From 276835bf69369ca664da98a41a9d867cddb09ac8 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 19 Aug 2025 12:27:49 -0600 Subject: [PATCH 001/134] fix aspiration name mistakes (carried over changes from apworld) --- Scripts/s4ap/enums/S4APLocalization.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Scripts/s4ap/enums/S4APLocalization.py b/Scripts/s4ap/enums/S4APLocalization.py index ba2aef6..6ec4ad5 100644 --- a/Scripts/s4ap/enums/S4APLocalization.py +++ b/Scripts/s4ap/enums/S4APLocalization.py @@ -242,7 +242,7 @@ def __init__(self): 2252361604: 'Competent Wordsmith (Bestselling Author 2)', 1903266201: 'Novelest Novelist (Bestselling Author 3)', 2893015914: 'Bestselling Author (Bestselling Author 4)', - 669436583: 'Tone Deaf (Musical Genius 1)', + 669436583: 'Tone-Deaf (Musical Genius 1)', 527786058: 'Fine Tuned (Musical Genius 2)', 3847573573: 'Harmonious (Musical Genius 3)', 3320148467: 'Musical Genius (Musical Genius 4)', @@ -276,11 +276,11 @@ def __init__(self): 3410479215: 'The Great Landscaper (Mansion Baron 2)', 1430851502: 'Home Renovator (Mansion Baron 3)', 3008497549: 'Mansion Baron (Mansion Baron 4)', - 1603920936: 'Prudent Student (Renaissance Sim / Nerd Brain 1', + 1603920936: 'Prudent Student (Renaissance Sim / Nerd Brain 1)', 3576085519: 'Jack of Some Trades (Renaissance Sim 2)', 3843569882: 'Pantologist (Renaissance Sim 3)', 517310505: 'Renaissance Sim (Renaissance Sim 4)', - 2769839652: 'With The Program (Computer Whiz 1)', + 2769839652: 'With the Program (Computer Whiz 1)', 1394699556: 'Technically Adept (Computer Whiz 2)', 1896269241: 'Computer Geek (Computer Whiz 3)', 2969693962: 'Computer Whiz (Computer Whiz 4)', @@ -311,7 +311,7 @@ def __init__(self): 2167317685: 'Funny (Joke Star 3)', 2867786966: 'Joke Star (Joke Star 4)', 2179132818: 'New in Town (Party Animal / Friend of the World 1)', - 6359719: 'Well liked (Friend of the World 2)', + 6359719: 'Well Liked (Friend of the World 2)', 3307311430: 'Super Friend (Friend of the World 3)', 3184496709: 'Friend of the World (Friend of the World 4)', 1596456398: 'Welcoming Host (Party Animal 2)', From 56108b1858793a0649755d021a75977848faf4b3 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 22 Aug 2025 16:16:41 -0600 Subject: [PATCH 002/134] push whatever this change is (probably made logging a bit better) --- Scripts/s4ap/events/career_event_dispatcher.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/s4ap/events/career_event_dispatcher.py b/Scripts/s4ap/events/career_event_dispatcher.py index 63da99f..8cb1a1d 100644 --- a/Scripts/s4ap/events/career_event_dispatcher.py +++ b/Scripts/s4ap/events/career_event_dispatcher.py @@ -30,7 +30,7 @@ def current_level(self): class OnCareerPromotionEvent(CommonService): def _on_promotion(self, career, user_level: int, *_, **__): - log.debug(f'here is the career: {career}') + log.debug(f'here is the career: {career} {user_level}') CommonEventRegistry.get().dispatch(CarrerPromotionEvent(career, user_level)) From cdd62a3cb7db1d132129c03d417fb5d956a942ee Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 22 Aug 2025 16:27:23 -0600 Subject: [PATCH 003/134] try doing some logging a bit better --- Scripts/s4ap/events/career_event_dispatcher.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Scripts/s4ap/events/career_event_dispatcher.py b/Scripts/s4ap/events/career_event_dispatcher.py index 8cb1a1d..f7f626a 100644 --- a/Scripts/s4ap/events/career_event_dispatcher.py +++ b/Scripts/s4ap/events/career_event_dispatcher.py @@ -30,7 +30,9 @@ def current_level(self): class OnCareerPromotionEvent(CommonService): def _on_promotion(self, career, user_level: int, *_, **__): - log.debug(f'here is the career: {career} {user_level}') + career_name = HashLookup().get_career_name(career, user_level) + log.debug(f'here is the career: {career} {user_level} ({career_name})') + log.debug(f'Promoted to {career_name}') CommonEventRegistry.get().dispatch(CarrerPromotionEvent(career, user_level)) From 34f27cc6900350ab6038cec7a508704cbe945fc1 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 22 Aug 2025 16:44:49 -0600 Subject: [PATCH 004/134] add generic function for looking up a sim's first name --- Scripts/s4ap/utils/s4ap_generic_utils.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Scripts/s4ap/utils/s4ap_generic_utils.py b/Scripts/s4ap/utils/s4ap_generic_utils.py index f7f007d..f6bfa23 100644 --- a/Scripts/s4ap/utils/s4ap_generic_utils.py +++ b/Scripts/s4ap/utils/s4ap_generic_utils.py @@ -1,6 +1,7 @@ import services from s4ap.modinfo import ModInfo from services.persistence_service import SaveGameData +from sims.sim_info import SimInfo from sims4communitylib.events.zone_spin.common_zone_spin_event_dispatcher import CommonZoneSpinEventDispatcher from sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification @@ -29,3 +30,9 @@ def trigger_autosave(*_) -> bool: CommonExceptionHandler.log_exception(ModInfo.get_identity(), 'An exception occurred while autosaving.', exception=ex) return False + + + def get_sim_first_name(sim_info: SimInfo): + if sim_info is None or not hasattr('first_name'): + return '' + return getattr(sim_info, 'first_name') \ No newline at end of file From ab5a8976ea7e49491da9a33ed736f4d08d3db858 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 22 Aug 2025 16:45:10 -0600 Subject: [PATCH 005/134] use our generic function to make the logging more verbose --- Scripts/s4ap/events/career_event_dispatcher.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Scripts/s4ap/events/career_event_dispatcher.py b/Scripts/s4ap/events/career_event_dispatcher.py index f7f626a..36f5dca 100644 --- a/Scripts/s4ap/events/career_event_dispatcher.py +++ b/Scripts/s4ap/events/career_event_dispatcher.py @@ -3,6 +3,7 @@ from s4ap.events.checks.send_check_event import SendLocationEvent from s4ap.logging.s4ap_logger import S4APLogger from s4ap.modinfo import ModInfo +from s4ap.utils.s4ap_generic_utils import S4APUtils from sims4communitylib.events.event_handling.common_event import CommonEvent from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry from sims4communitylib.services.common_service import CommonService @@ -29,10 +30,10 @@ def current_level(self): class OnCareerPromotionEvent(CommonService): - def _on_promotion(self, career, user_level: int, *_, **__): + def _on_promotion(self, career, user_level: int, name: str, *_, **__): career_name = HashLookup().get_career_name(career, user_level) log.debug(f'here is the career: {career} {user_level} ({career_name})') - log.debug(f'Promoted to {career_name}') + log.debug(f'{name} was promoted to {career_name}') CommonEventRegistry.get().dispatch(CarrerPromotionEvent(career, user_level)) @@ -44,7 +45,8 @@ def _on_milestone_complete(original, self, *args, **kwargs): level = self._user_level sim_info = self._sim_info if sim_info in CommonHouseholdUtils.get_sim_info_of_all_sims_in_active_household_generator(): - OnCareerPromotionEvent.get()._on_promotion(career, level) + sim_name = S4APUtils.get_sim_first_name(sim_info) + OnCareerPromotionEvent.get()._on_promotion(career, level, sim_name) return result From 66efdfdc4241f99ce82988a9b5c7b4adcedd0dfb Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 22 Aug 2025 16:52:18 -0600 Subject: [PATCH 006/134] use the s4ap generic function for this skill file name call --- Scripts/s4ap/utils/s4ap_skill_utils.py | 191 +++++++++++++------------ 1 file changed, 96 insertions(+), 95 deletions(-) diff --git a/Scripts/s4ap/utils/s4ap_skill_utils.py b/Scripts/s4ap/utils/s4ap_skill_utils.py index ba09d56..4774c4c 100644 --- a/Scripts/s4ap/utils/s4ap_skill_utils.py +++ b/Scripts/s4ap/utils/s4ap_skill_utils.py @@ -1,95 +1,96 @@ -import re - -from s4ap.enums.S4APLocalization import S4APTraitId -from s4ap.events.skill_event_dispatcher import SimSkillLeveledUpEvent -from s4ap.logging.s4ap_logger import S4APLogger -from s4ap.modinfo import ModInfo -from s4ap.persistance.ap_session_data_store import S4APSessionStoreUtils -from server_commands.argument_helpers import TunableInstanceParam -from sims4.resources import Types -from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils -from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils -from sims4communitylib.utils.sims.common_sim_skill_utils import CommonSimSkillUtils -from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils - -logger = S4APLogger.get_log() -logger.enable() - - -def lock_skills(skillcap: int, skill_name, from_level_up: bool): - try: - logger.debug(f"Skill cap is {skillcap}") - data_store = S4APSessionStoreUtils() - if skillcap < 2: - skillcap = 2 - if not skill_name.startswith("statistic_Skill_AdultMajor_") and not 'fitness' in skill_name.lower(): - skill_name = f"statistic_Skill_AdultMajor_{skill_name}" - logger.debug(f'{skill_name}') - skill_id = skill_name.replace("statistic_Skill_AdultMajor_", '') - skill_id = re.sub(r'(?<=[a-z])(?=[A-Z])', '_', skill_id) - if 'bartending' in skill_id.lower(): - skill_id = skill_id.lower().replace('bartending', 'mixology') - if from_level_up is True and data_store.get_items() is not None: - skill_id_lower = skill_id.replace("_", " ").strip().lower() - item_name = skill_id_lower - if 'fitness' in skill_id_lower: - item_name = skill_id_lower.replace('skill', '').strip() - elif 'homestyle' in skill_id_lower: - item_name = skill_id_lower.replace('homestyle', '').strip() - elif 'gourmet' in skill_id_lower: - item_name = skill_id_lower.replace("cooking", "").strip() - elif 'bartending' in skill_id_lower: - item_name = skill_id_lower.replace('bartending', 'mixology').strip() - logger.debug(f"item_name: {item_name}") - for item in data_store.get_items(): - if item_name in item.lower(): - skillcap = data_store.get_items().count(item) + 2 - logger.debug(f"new skillcap: {skillcap}") - break - else: - continue - trait = f"lock_{skill_id.lower().replace('skill_', '')}_skill" - if 'gourmet' in trait: - trait = "lock_gourmet_cooking_skill" - logger.debug(f"Skill Id: {skill_id}") - logger.debug(f"Trait: {trait}") - skill = TunableInstanceParam(Types.STATISTIC)(skill_name) - for sim_info in CommonHouseholdUtils.get_sim_info_of_all_sims_in_active_household_generator(): - current_level = CommonSimSkillUtils.get_current_skill_level(sim_info, skill, False) - logger.debug(f"{CommonSimNameUtils.get_first_name(sim_info)}'s Current level is {current_level}.") - if skillcap > current_level: - logger.debug('Skill cap is > than current level') - remove_lock_trait(sim_info, trait) - elif skillcap == current_level: - logger.debug('Skill cap is == as current level') - add_lock_trait(sim_info, trait) - elif skillcap < current_level: - logger.debug('Skill cap is < than current level') - CommonSimSkillUtils.set_current_skill_level(sim_info, skill, skillcap) - add_lock_trait(sim_info, trait) - except Exception as ex: - logger.debug(f"Exception occurred: {ex}") - -def add_lock_trait(sim_info, trait): - trait_upper = trait.upper() - if hasattr(S4APTraitId, trait_upper): - trait_id = getattr(S4APTraitId, trait_upper) - CommonTraitUtils.add_trait(sim_info, trait_id) - logger.debug(trait_id) - logger.debug(trait_upper) - - -def remove_lock_trait(sim_info, trait): - trait_upper = trait.upper() - if hasattr(S4APTraitId, trait_upper): - trait_id = getattr(S4APTraitId, trait_upper) - CommonTraitUtils.remove_trait(sim_info, trait_id) - logger.debug(trait_id) - logger.debug(trait_upper) - - -@CommonEventRegistry.handle_events(ModInfo.get_identity()) -def _lock_on_level_up(event_data: SimSkillLeveledUpEvent): - skill_name = event_data.skill.skill_type.__name__ - lock_skills(event_data.new_skill_level, skill_name, True) +import re + +from s4ap.enums.S4APLocalization import S4APTraitId +from s4ap.events.skill_event_dispatcher import SimSkillLeveledUpEvent +from s4ap.logging.s4ap_logger import S4APLogger +from s4ap.modinfo import ModInfo +from s4ap.persistance.ap_session_data_store import S4APSessionStoreUtils +from s4ap.utils.s4ap_generic_utils import S4APUtils +from server_commands.argument_helpers import TunableInstanceParam +from sims4.resources import Types +from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry +from sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils +from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils +from sims4communitylib.utils.sims.common_sim_skill_utils import CommonSimSkillUtils +from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils + +logger = S4APLogger.get_log() +logger.enable() + + +def lock_skills(skillcap: int, skill_name, from_level_up: bool): + try: + logger.debug(f"Skill cap is {skillcap}") + data_store = S4APSessionStoreUtils() + if skillcap < 2: + skillcap = 2 + if not skill_name.startswith("statistic_Skill_AdultMajor_") and not 'fitness' in skill_name.lower(): + skill_name = f"statistic_Skill_AdultMajor_{skill_name}" + logger.debug(f'{skill_name}') + skill_id = skill_name.replace("statistic_Skill_AdultMajor_", '') + skill_id = re.sub(r'(?<=[a-z])(?=[A-Z])', '_', skill_id) + if 'bartending' in skill_id.lower(): + skill_id = skill_id.lower().replace('bartending', 'mixology') + if from_level_up is True and data_store.get_items() is not None: + skill_id_lower = skill_id.replace("_", " ").strip().lower() + item_name = skill_id_lower + if 'fitness' in skill_id_lower: + item_name = skill_id_lower.replace('skill', '').strip() + elif 'homestyle' in skill_id_lower: + item_name = skill_id_lower.replace('homestyle', '').strip() + elif 'gourmet' in skill_id_lower: + item_name = skill_id_lower.replace("cooking", "").strip() + elif 'bartending' in skill_id_lower: + item_name = skill_id_lower.replace('bartending', 'mixology').strip() + logger.debug(f"item_name: {item_name}") + for item in data_store.get_items(): + if item_name in item.lower(): + skillcap = data_store.get_items().count(item) + 2 + logger.debug(f"new skillcap: {skillcap}") + break + else: + continue + trait = f"lock_{skill_id.lower().replace('skill_', '')}_skill" + if 'gourmet' in trait: + trait = "lock_gourmet_cooking_skill" + logger.debug(f"Skill Id: {skill_id}") + logger.debug(f"Trait: {trait}") + skill = TunableInstanceParam(Types.STATISTIC)(skill_name) + for sim_info in CommonHouseholdUtils.get_sim_info_of_all_sims_in_active_household_generator(): + current_level = CommonSimSkillUtils.get_current_skill_level(sim_info, skill, False) + logger.debug(f"{S4APUtils.get_sim_first_name(sim_info)}'s Current level is {current_level}.") + if skillcap > current_level: + logger.debug('Skill cap is > than current level') + remove_lock_trait(sim_info, trait) + elif skillcap == current_level: + logger.debug('Skill cap is == as current level') + add_lock_trait(sim_info, trait) + elif skillcap < current_level: + logger.debug('Skill cap is < than current level') + CommonSimSkillUtils.set_current_skill_level(sim_info, skill, skillcap) + add_lock_trait(sim_info, trait) + except Exception as ex: + logger.debug(f"Exception occurred: {ex}") + +def add_lock_trait(sim_info, trait): + trait_upper = trait.upper() + if hasattr(S4APTraitId, trait_upper): + trait_id = getattr(S4APTraitId, trait_upper) + CommonTraitUtils.add_trait(sim_info, trait_id) + logger.debug(trait_id) + logger.debug(trait_upper) + + +def remove_lock_trait(sim_info, trait): + trait_upper = trait.upper() + if hasattr(S4APTraitId, trait_upper): + trait_id = getattr(S4APTraitId, trait_upper) + CommonTraitUtils.remove_trait(sim_info, trait_id) + logger.debug(trait_id) + logger.debug(trait_upper) + + +@CommonEventRegistry.handle_events(ModInfo.get_identity()) +def _lock_on_level_up(event_data: SimSkillLeveledUpEvent): + skill_name = event_data.skill.skill_type.__name__ + lock_skills(event_data.new_skill_level, skill_name, True) From b372ad590c793fc242d5e64772e50c01f7f02966 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 22 Aug 2025 16:59:17 -0600 Subject: [PATCH 007/134] start working on changing the logging to be more verbose for the skills in the mod's log --- Scripts/s4ap/utils/s4ap_skill_utils.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Scripts/s4ap/utils/s4ap_skill_utils.py b/Scripts/s4ap/utils/s4ap_skill_utils.py index 4774c4c..1c9e53e 100644 --- a/Scripts/s4ap/utils/s4ap_skill_utils.py +++ b/Scripts/s4ap/utils/s4ap_skill_utils.py @@ -20,13 +20,13 @@ def lock_skills(skillcap: int, skill_name, from_level_up: bool): try: + logger.debug(f"Processing level up for {skill_name}") logger.debug(f"Skill cap is {skillcap}") data_store = S4APSessionStoreUtils() if skillcap < 2: skillcap = 2 if not skill_name.startswith("statistic_Skill_AdultMajor_") and not 'fitness' in skill_name.lower(): skill_name = f"statistic_Skill_AdultMajor_{skill_name}" - logger.debug(f'{skill_name}') skill_id = skill_name.replace("statistic_Skill_AdultMajor_", '') skill_id = re.sub(r'(?<=[a-z])(?=[A-Z])', '_', skill_id) if 'bartending' in skill_id.lower(): @@ -58,15 +58,15 @@ def lock_skills(skillcap: int, skill_name, from_level_up: bool): skill = TunableInstanceParam(Types.STATISTIC)(skill_name) for sim_info in CommonHouseholdUtils.get_sim_info_of_all_sims_in_active_household_generator(): current_level = CommonSimSkillUtils.get_current_skill_level(sim_info, skill, False) - logger.debug(f"{S4APUtils.get_sim_first_name(sim_info)}'s Current level is {current_level}.") + logger.debug(f"{S4APUtils.get_sim_first_name(sim_info)}'s Current {skill_id} level is {current_level}.") if skillcap > current_level: - logger.debug('Skill cap is > than current level') + logger.debug(f"{skill_id} skill cap is > than current level, unlocking skill.") remove_lock_trait(sim_info, trait) elif skillcap == current_level: - logger.debug('Skill cap is == as current level') + logger.debug(f"{skill_id} skill cap is the same as the current level, locking skill.") add_lock_trait(sim_info, trait) elif skillcap < current_level: - logger.debug('Skill cap is < than current level') + logger.debug(f"{skill_id} skill cap is < than current level, locking skill and setting skill level to {skillcap}") CommonSimSkillUtils.set_current_skill_level(sim_info, skill, skillcap) add_lock_trait(sim_info, trait) except Exception as ex: From f4570437166975868c418f1921a57f36df501814 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Wed, 3 Sep 2025 20:30:14 -0600 Subject: [PATCH 008/134] fix typo --- Scripts/s4ap/events/career_event_dispatcher.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Scripts/s4ap/events/career_event_dispatcher.py b/Scripts/s4ap/events/career_event_dispatcher.py index 36f5dca..8982b28 100644 --- a/Scripts/s4ap/events/career_event_dispatcher.py +++ b/Scripts/s4ap/events/career_event_dispatcher.py @@ -14,7 +14,7 @@ log.enable() -class CarrerPromotionEvent(CommonEvent): +class CareerPromotionEvent(CommonEvent): def __init__(self, career, current_level): self._career = career self._current_level = current_level @@ -34,7 +34,7 @@ def _on_promotion(self, career, user_level: int, name: str, *_, **__): career_name = HashLookup().get_career_name(career, user_level) log.debug(f'here is the career: {career} {user_level} ({career_name})') log.debug(f'{name} was promoted to {career_name}') - CommonEventRegistry.get().dispatch(CarrerPromotionEvent(career, user_level)) + CommonEventRegistry.get().dispatch(CareerPromotionEvent(career, user_level)) @CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), CareerBase, @@ -51,7 +51,7 @@ def _on_milestone_complete(original, self, *args, **kwargs): @CommonEventRegistry.handle_events(ModInfo.get_identity()) -def _send_notif_on_event_handle(event_data: CarrerPromotionEvent): +def _send_notif_on_event_handle(event_data: CareerPromotionEvent): lookup = HashLookup() CommonEventRegistry.get().dispatch( SendLocationEvent(f'{lookup.get_career_name(event_data.career, event_data.current_level)}')) From caacbc28056c182e0dc8e9e97c91c39c7230ecac Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Wed, 3 Sep 2025 20:32:35 -0600 Subject: [PATCH 009/134] replace thingy --- Scripts/s4ap/utils/s4ap_skill_utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Scripts/s4ap/utils/s4ap_skill_utils.py b/Scripts/s4ap/utils/s4ap_skill_utils.py index 1c9e53e..f7d01b6 100644 --- a/Scripts/s4ap/utils/s4ap_skill_utils.py +++ b/Scripts/s4ap/utils/s4ap_skill_utils.py @@ -60,13 +60,13 @@ def lock_skills(skillcap: int, skill_name, from_level_up: bool): current_level = CommonSimSkillUtils.get_current_skill_level(sim_info, skill, False) logger.debug(f"{S4APUtils.get_sim_first_name(sim_info)}'s Current {skill_id} level is {current_level}.") if skillcap > current_level: - logger.debug(f"{skill_id} skill cap is > than current level, unlocking skill.") + logger.debug(f"{skill_id} skill cap is greater than current level, unlocking skill.") remove_lock_trait(sim_info, trait) elif skillcap == current_level: logger.debug(f"{skill_id} skill cap is the same as the current level, locking skill.") add_lock_trait(sim_info, trait) elif skillcap < current_level: - logger.debug(f"{skill_id} skill cap is < than current level, locking skill and setting skill level to {skillcap}") + logger.debug(f"{skill_id} skill cap is less than current level, locking skill and setting skill level to {skillcap}") CommonSimSkillUtils.set_current_skill_level(sim_info, skill, skillcap) add_lock_trait(sim_info, trait) except Exception as ex: From 8f3e3c96e2cd9e49784752a80c839dfabc136fe2 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Thu, 4 Sep 2025 09:42:59 -0600 Subject: [PATCH 010/134] replace lots of s4cl calls with our own functions or base game equivalents that are simpler to use in the skill file --- Scripts/s4ap/utils/s4ap_household_utils.py | 19 ++++++++++++ Scripts/s4ap/utils/s4ap_skill_utils.py | 36 ++++++++++++++++------ 2 files changed, 46 insertions(+), 9 deletions(-) create mode 100644 Scripts/s4ap/utils/s4ap_household_utils.py diff --git a/Scripts/s4ap/utils/s4ap_household_utils.py b/Scripts/s4ap/utils/s4ap_household_utils.py new file mode 100644 index 0000000..857d2fa --- /dev/null +++ b/Scripts/s4ap/utils/s4ap_household_utils.py @@ -0,0 +1,19 @@ +import services +from services import active_household +from lib.typing import Iterator, Union +from sims.household import Household +from sims.sim_info import SimInfo + +class S4APHouseholdUtils: + + @classmethod + def get_active_household(cls) -> Union[Household, None]: + return services.active_household() + + @classmethod + def get_sim_info_of_all_sims_in_active_household_generator(cls) -> Iterator[SimInfo]: + household = active_household() + if household is not None: + for sim_info in household.sim_info_gen(): + if sim_info is not None: + yield sim_info \ No newline at end of file diff --git a/Scripts/s4ap/utils/s4ap_skill_utils.py b/Scripts/s4ap/utils/s4ap_skill_utils.py index f7d01b6..8fdc8e5 100644 --- a/Scripts/s4ap/utils/s4ap_skill_utils.py +++ b/Scripts/s4ap/utils/s4ap_skill_utils.py @@ -6,13 +6,12 @@ from s4ap.modinfo import ModInfo from s4ap.persistance.ap_session_data_store import S4APSessionStoreUtils from s4ap.utils.s4ap_generic_utils import S4APUtils +from s4ap.utils.s4ap_household_utils import S4APHouseholdUtils from server_commands.argument_helpers import TunableInstanceParam +from sims.sim_info import SimInfo from sims4.resources import Types from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils -from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils -from sims4communitylib.utils.sims.common_sim_skill_utils import CommonSimSkillUtils -from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils +from statistics.skill import Skill logger = S4APLogger.get_log() logger.enable() @@ -56,8 +55,8 @@ def lock_skills(skillcap: int, skill_name, from_level_up: bool): logger.debug(f"Skill Id: {skill_id}") logger.debug(f"Trait: {trait}") skill = TunableInstanceParam(Types.STATISTIC)(skill_name) - for sim_info in CommonHouseholdUtils.get_sim_info_of_all_sims_in_active_household_generator(): - current_level = CommonSimSkillUtils.get_current_skill_level(sim_info, skill, False) + for sim_info in S4APHouseholdUtils.get_sim_info_of_all_sims_in_active_household_generator(): + current_level = get_current_skill_level(sim_info, skill) logger.debug(f"{S4APUtils.get_sim_first_name(sim_info)}'s Current {skill_id} level is {current_level}.") if skillcap > current_level: logger.debug(f"{skill_id} skill cap is greater than current level, unlocking skill.") @@ -67,7 +66,7 @@ def lock_skills(skillcap: int, skill_name, from_level_up: bool): add_lock_trait(sim_info, trait) elif skillcap < current_level: logger.debug(f"{skill_id} skill cap is less than current level, locking skill and setting skill level to {skillcap}") - CommonSimSkillUtils.set_current_skill_level(sim_info, skill, skillcap) + set_current_skill_level(sim_info, skill, skillcap) add_lock_trait(sim_info, trait) except Exception as ex: logger.debug(f"Exception occurred: {ex}") @@ -76,7 +75,9 @@ def add_lock_trait(sim_info, trait): trait_upper = trait.upper() if hasattr(S4APTraitId, trait_upper): trait_id = getattr(S4APTraitId, trait_upper) - CommonTraitUtils.add_trait(sim_info, trait_id) + trait = TunableInstanceParam(Types.TRAIT)(trait_id) + if not sim_info.has_trait(trait): + sim_info.add_trait(trait) logger.debug(trait_id) logger.debug(trait_upper) @@ -85,7 +86,9 @@ def remove_lock_trait(sim_info, trait): trait_upper = trait.upper() if hasattr(S4APTraitId, trait_upper): trait_id = getattr(S4APTraitId, trait_upper) - CommonTraitUtils.remove_trait(sim_info, trait_id) + trait = trait = TunableInstanceParam(Types.TRAIT)(trait_id) + if sim_info.has_trait(trait): + sim_info.remove_trait(trait) logger.debug(trait_id) logger.debug(trait_upper) @@ -94,3 +97,18 @@ def remove_lock_trait(sim_info, trait): def _lock_on_level_up(event_data: SimSkillLeveledUpEvent): skill_name = event_data.skill.skill_type.__name__ lock_skills(event_data.new_skill_level, skill_name, True) + +def get_current_skill_level(sim_info: SimInfo, skill: TunableInstanceParam(Types.STATISTIC)) -> float: + skill_stat = sim_info.get_statistic(skill, add=False) + if skill_stat is None: + return 0.0 + skill_level: float = skill_stat.get_user_value() + return skill_level + +def set_current_skill_level(sim_info: SimInfo, skill: TunableInstanceParam(Types.STATISTIC), level: float) -> bool: + skill_stat = sim_info.get_statistic(skill, add=False) + if skill_stat is None: + return False + exp = skill_stat.convert_from_user_value(level) + skill_stat.set_value(exp) + return True From 1a03fd9ccc759d07ca618bec2834ff7bb9eec8ab Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Thu, 4 Sep 2025 09:43:34 -0600 Subject: [PATCH 011/134] remove unused import --- Scripts/s4ap/utils/s4ap_skill_utils.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Scripts/s4ap/utils/s4ap_skill_utils.py b/Scripts/s4ap/utils/s4ap_skill_utils.py index 8fdc8e5..1d4379e 100644 --- a/Scripts/s4ap/utils/s4ap_skill_utils.py +++ b/Scripts/s4ap/utils/s4ap_skill_utils.py @@ -11,7 +11,6 @@ from sims.sim_info import SimInfo from sims4.resources import Types from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from statistics.skill import Skill logger = S4APLogger.get_log() logger.enable() From fda51f0a81f235fc2fbb3c7a654795b9a4c99657 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Thu, 4 Sep 2025 10:13:14 -0600 Subject: [PATCH 012/134] replace more s4cl functions with our own or simpler EA methods to do the same thing --- Scripts/s4ap/utils/s4ap_generic_utils.py | 7 +- Scripts/s4ap/utils/s4ap_phone_utils.py | 24 ++++--- Scripts/s4ap/utils/s4ap_reset_utils.py | 19 +++--- Scripts/s4ap/utils/s4ap_skill_utils.py | 84 +++++++++++++++++------- 4 files changed, 93 insertions(+), 41 deletions(-) diff --git a/Scripts/s4ap/utils/s4ap_generic_utils.py b/Scripts/s4ap/utils/s4ap_generic_utils.py index f6bfa23..4489cf3 100644 --- a/Scripts/s4ap/utils/s4ap_generic_utils.py +++ b/Scripts/s4ap/utils/s4ap_generic_utils.py @@ -35,4 +35,9 @@ def trigger_autosave(*_) -> bool: def get_sim_first_name(sim_info: SimInfo): if sim_info is None or not hasattr('first_name'): return '' - return getattr(sim_info, 'first_name') \ No newline at end of file + return getattr(sim_info, 'first_name') + + @classmethod + def get_sim_instance(cls, sim_identifier: SimInfo): + if isinstance(sim_identifier, SimInfo): + return sim_identifier.get_sim_instance() \ No newline at end of file diff --git a/Scripts/s4ap/utils/s4ap_phone_utils.py b/Scripts/s4ap/utils/s4ap_phone_utils.py index 32f7bcd..b8ae68f 100644 --- a/Scripts/s4ap/utils/s4ap_phone_utils.py +++ b/Scripts/s4ap/utils/s4ap_phone_utils.py @@ -6,6 +6,8 @@ from s4ap.logging.s4ap_logger import S4APLogger from s4ap.modinfo import ModInfo from s4ap.persistance.ap_session_data_store import S4APSessionStoreUtils +from s4ap.utils.s4ap_household_utils import S4APHouseholdUtils +from s4ap.utils.s4ap_skill_utils import S4APSkillUtils from server_commands.argument_helpers import TunableInstanceParam from sims4.resources import Types from sims4communitylib.dialogs.choose_object_dialog import CommonChooseObjectDialog @@ -15,12 +17,8 @@ from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification from sims4communitylib.utils.common_icon_utils import CommonIconUtils from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.resources.common_skill_utils import CommonSkillUtils from sims4communitylib.utils.sims.common_career_utils import CommonCareerUtils -from sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils from sims4communitylib.utils.sims.common_sim_career_utils import CommonSimCareerUtils -from sims4communitylib.utils.sims.common_sim_skill_utils import CommonSimSkillUtils -from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils from ui.ui_dialog_picker import ObjectPickerRow logger = S4APLogger.get_log() @@ -30,7 +28,9 @@ @CommonEventRegistry.handle_events(ModInfo.get_identity()) def _handle_show_max_skills_phone(event_data: S4CLSimTraitAddedEvent): if event_data.trait_id == S4APTraitId.SHOW_RECEIVED_SKILLS: - CommonTraitUtils.remove_trait(event_data.sim_info, S4APTraitId.SHOW_RECEIVED_SKILLS) + received_skills_trait_instance = TunableInstanceParam(Types.TRAIT)(S4APTraitId.SHOW_RECEIVED_SKILLS) + if event_data.sim_info.has_trait(received_skills_trait_instance): + event_data.sim_info.remove_trait(received_skills_trait_instance) data_store = S4APSessionStoreUtils() options = [] skills_and_levels = {} @@ -87,14 +87,16 @@ def _on_chosen(_, outcome: CommonChoiceOutcome): @CommonEventRegistry.handle_events(ModInfo.get_identity()) def _resync_locations(event_data: S4CLSimTraitAddedEvent): if event_data.trait_id == S4APTraitId.RESYNC_LOCATIONS: - CommonTraitUtils.remove_trait(event_data.sim_info, S4APTraitId.RESYNC_LOCATIONS) + resync_trait_instance = TunableInstanceParam(Types.TRAIT)(S4APTraitId.RESYNC_LOCATIONS) + if event_data.sim_info.has_trait(resync_trait_instance): + event_data.sim_info.remove_trait(resync_trait_instance) lookup = HashLookup() locations = [] skill_dict = {} careers_dict = {} - for sim_info in CommonHouseholdUtils.get_sim_info_of_all_sims_in_active_household_generator(): - for skill in CommonSkillUtils.get_all_skills_gen(): - skill_level = CommonSimSkillUtils.get_current_skill_level(sim_info, skill, False) + for sim_info in S4APHouseholdUtils.get_sim_info_of_all_sims_in_active_household_generator(): + for skill in S4APSkillUtils.get_all_skills_gen(): + skill_level = S4APSkillUtils.get_current_skill_level(sim_info, skill) skill_name = skill.skill_type.__name__ if skill_name.startswith("statistic_Skill_AdultMajor_") or 'fitness' in skill_name.lower(): skill_name = skill_name.replace("statistic_Skill_AdultMajor_", "") @@ -157,7 +159,9 @@ def _resync_locations(event_data: S4CLSimTraitAddedEvent): @CommonEventRegistry.handle_events(ModInfo.get_identity()) def _show_aspiration_and_career(event_data: S4CLSimTraitAddedEvent): if event_data.trait_id == S4APTraitId.SHOW_YAML_OPTIONS: - CommonTraitUtils.remove_trait(event_data.sim_info, S4APTraitId.SHOW_YAML_OPTIONS) + yaml_options_trait_instance = TunableInstanceParam(Types.TRAIT)(S4APTraitId.SHOW_YAML_OPTIONS) + if event_data.sim_info.has_trait(yaml_options_trait_instance): + event_data.sim_info.remove_trait(yaml_options_trait_instance) data_store = S4APSessionStoreUtils() if data_store.get_goal() is not None: goal = data_store.get_goal() diff --git a/Scripts/s4ap/utils/s4ap_reset_utils.py b/Scripts/s4ap/utils/s4ap_reset_utils.py index e7eb089..bb2963c 100644 --- a/Scripts/s4ap/utils/s4ap_reset_utils.py +++ b/Scripts/s4ap/utils/s4ap_reset_utils.py @@ -1,19 +1,20 @@ from s4ap.enums.S4APLocalization import S4APTraitId from s4ap.logging.s4ap_logger import S4APLogger +from s4ap.utils.s4ap_household_utils import S4APHouseholdUtils +from s4ap.utils.s4ap_skill_utils import get_all_skills_available_for_sim_gen +from server_commands.argument_helpers import TunableInstanceParam +from sims4.resources import Types from sims4communitylib.enums.traits_enum import CommonTraitId from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification -from sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils -from sims4communitylib.utils.sims.common_sim_skill_utils import CommonSimSkillUtils -from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils logger = S4APLogger.get_log() logger.enable() class ResetSimData: def reset_all_skills(self): - for sim_info in CommonHouseholdUtils.get_sim_info_of_all_sims_in_active_household_generator(): - for skill in CommonSimSkillUtils.get_all_skills_available_for_sim_gen(sim_info): - CommonSimSkillUtils.remove_skill(sim_info, skill) + for sim_info in S4APHouseholdUtils.get_sim_info_of_all_sims_in_active_household_generator(): + for skill in get_all_skills_available_for_sim_gen(sim_info): + sim_info.remove_statistic(skill) def show_reset_notif(self): notif = CommonBasicNotification( @@ -29,5 +30,7 @@ def remove_all_s4ap_traits(self): # Check if the trait is not a built-in attribute and is unique to S4APTraitId if not trait.startswith("_") and trait not in common_trait_ids: logger.debug(f"Removing trait {trait}: {trait_value}") - for sim_info in CommonHouseholdUtils.get_sim_info_of_all_sims_in_active_household_generator(): - CommonTraitUtils.remove_trait(sim_info, trait_value) + trait_instance = TunableInstanceParam(Types.TRAIT)(trait_value) + for sim_info in S4APHouseholdUtils.get_sim_info_of_all_sims_in_active_household_generator(): + if sim_info.has_trait(trait_instance): + sim_info.remove_trait(trait_instance) diff --git a/Scripts/s4ap/utils/s4ap_skill_utils.py b/Scripts/s4ap/utils/s4ap_skill_utils.py index 1d4379e..54988cd 100644 --- a/Scripts/s4ap/utils/s4ap_skill_utils.py +++ b/Scripts/s4ap/utils/s4ap_skill_utils.py @@ -1,5 +1,7 @@ import re +import services +from lib.typing import Callable, Iterator, Union from s4ap.enums.S4APLocalization import S4APTraitId from s4ap.events.skill_event_dispatcher import SimSkillLeveledUpEvent from s4ap.logging.s4ap_logger import S4APLogger @@ -11,6 +13,7 @@ from sims.sim_info import SimInfo from sims4.resources import Types from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry +from statistics.skill import Skill logger = S4APLogger.get_log() logger.enable() @@ -55,7 +58,7 @@ def lock_skills(skillcap: int, skill_name, from_level_up: bool): logger.debug(f"Trait: {trait}") skill = TunableInstanceParam(Types.STATISTIC)(skill_name) for sim_info in S4APHouseholdUtils.get_sim_info_of_all_sims_in_active_household_generator(): - current_level = get_current_skill_level(sim_info, skill) + current_level = S4APSkillUtils.get_current_skill_level(sim_info, skill) logger.debug(f"{S4APUtils.get_sim_first_name(sim_info)}'s Current {skill_id} level is {current_level}.") if skillcap > current_level: logger.debug(f"{skill_id} skill cap is greater than current level, unlocking skill.") @@ -65,7 +68,7 @@ def lock_skills(skillcap: int, skill_name, from_level_up: bool): add_lock_trait(sim_info, trait) elif skillcap < current_level: logger.debug(f"{skill_id} skill cap is less than current level, locking skill and setting skill level to {skillcap}") - set_current_skill_level(sim_info, skill, skillcap) + S4APSkillUtils.set_current_skill_level(sim_info, skill, skillcap) add_lock_trait(sim_info, trait) except Exception as ex: logger.debug(f"Exception occurred: {ex}") @@ -74,9 +77,9 @@ def add_lock_trait(sim_info, trait): trait_upper = trait.upper() if hasattr(S4APTraitId, trait_upper): trait_id = getattr(S4APTraitId, trait_upper) - trait = TunableInstanceParam(Types.TRAIT)(trait_id) - if not sim_info.has_trait(trait): - sim_info.add_trait(trait) + trait_instance = TunableInstanceParam(Types.TRAIT)(trait_id) + if not sim_info.has_trait(trait_instance): + sim_info.add_trait(trait_instance) logger.debug(trait_id) logger.debug(trait_upper) @@ -85,9 +88,9 @@ def remove_lock_trait(sim_info, trait): trait_upper = trait.upper() if hasattr(S4APTraitId, trait_upper): trait_id = getattr(S4APTraitId, trait_upper) - trait = trait = TunableInstanceParam(Types.TRAIT)(trait_id) - if sim_info.has_trait(trait): - sim_info.remove_trait(trait) + trait_instance = TunableInstanceParam(Types.TRAIT)(trait_id) + if sim_info.has_trait(trait_instance): + sim_info.remove_trait(trait_instance) logger.debug(trait_id) logger.debug(trait_upper) @@ -97,17 +100,54 @@ def _lock_on_level_up(event_data: SimSkillLeveledUpEvent): skill_name = event_data.skill.skill_type.__name__ lock_skills(event_data.new_skill_level, skill_name, True) -def get_current_skill_level(sim_info: SimInfo, skill: TunableInstanceParam(Types.STATISTIC)) -> float: - skill_stat = sim_info.get_statistic(skill, add=False) - if skill_stat is None: - return 0.0 - skill_level: float = skill_stat.get_user_value() - return skill_level - -def set_current_skill_level(sim_info: SimInfo, skill: TunableInstanceParam(Types.STATISTIC), level: float) -> bool: - skill_stat = sim_info.get_statistic(skill, add=False) - if skill_stat is None: - return False - exp = skill_stat.convert_from_user_value(level) - skill_stat.set_value(exp) - return True +class S4APSkillUtils: + + def get_current_skill_level(sim_info: SimInfo, skill: TunableInstanceParam(Types.STATISTIC)) -> float: + skill_stat = sim_info.get_statistic(skill, add=False) + if skill_stat is None: + return 0.0 + skill_level: float = skill_stat.get_user_value() + return skill_level + + def set_current_skill_level(sim_info: SimInfo, skill: TunableInstanceParam(Types.STATISTIC), level: float) -> bool: + skill_stat = sim_info.get_statistic(skill, add=False) + if skill_stat is None: + return False + exp = skill_stat.convert_from_user_value(level) + skill_stat.set_value(exp) + return True + + def get_all_skills_available_for_sim_gen(sim_info: SimInfo) -> Iterator[Skill]: + sim = S4APUtils.get_sim_instance(sim_info) + if sim is None: + return tuple() + + def _is_skill_available_for_sim(skill: Skill) -> bool: + return skill.can_add(sim) + + yield from get_all_skills_gen(include_skill_callback=_is_skill_available_for_sim) + + def get_all_skills_gen(include_skill_callback: Callable[[Skill], bool] = None) -> Iterator[Skill]: + statistic_manager = services.get_instance_manager(Types.STATISTIC) + for skill in statistic_manager.get_ordered_types(only_subclasses_of=Skill): + skill: Skill = skill + skill_id = get_skill_id(skill) + if skill_id is None: + continue + if include_skill_callback is not None and not include_skill_callback(skill): + continue + yield skill + + def get_skill_id(skill_identifier: Union[int, Skill]) -> Union[int, None]: + """get_skill_id(skill_identifier) + + Retrieve the decimal identifier of a Skill. + + :param skill_identifier: The identifier or instance of a Skill. + :type skill_identifier: Union[int, Skill] + :return: The decimal identifier of the Skill or None if the Skill does not have an id. + :rtype: Union[int, None] + """ + if isinstance(skill_identifier, int): + return skill_identifier + return getattr(skill_identifier, 'guid64', None) \ No newline at end of file From cdaa75a8a17b3b3565f87058feed7f98e2c9da84 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Thu, 4 Sep 2025 12:06:37 -0600 Subject: [PATCH 013/134] static methods --- Scripts/s4ap/utils/s4ap_skill_utils.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Scripts/s4ap/utils/s4ap_skill_utils.py b/Scripts/s4ap/utils/s4ap_skill_utils.py index 54988cd..4ace7fc 100644 --- a/Scripts/s4ap/utils/s4ap_skill_utils.py +++ b/Scripts/s4ap/utils/s4ap_skill_utils.py @@ -102,14 +102,16 @@ def _lock_on_level_up(event_data: SimSkillLeveledUpEvent): class S4APSkillUtils: - def get_current_skill_level(sim_info: SimInfo, skill: TunableInstanceParam(Types.STATISTIC)) -> float: + @staticmethod + def get_current_skill_level(self, sim_info: SimInfo, skill: TunableInstanceParam(Types.STATISTIC)) -> float: skill_stat = sim_info.get_statistic(skill, add=False) if skill_stat is None: return 0.0 skill_level: float = skill_stat.get_user_value() return skill_level - def set_current_skill_level(sim_info: SimInfo, skill: TunableInstanceParam(Types.STATISTIC), level: float) -> bool: + @staticmethod + def set_current_skill_level(self, sim_info: SimInfo, skill: TunableInstanceParam(Types.STATISTIC), level: float) -> bool: skill_stat = sim_info.get_statistic(skill, add=False) if skill_stat is None: return False @@ -117,6 +119,7 @@ def set_current_skill_level(sim_info: SimInfo, skill: TunableInstanceParam(Types skill_stat.set_value(exp) return True + @staticmethod def get_all_skills_available_for_sim_gen(sim_info: SimInfo) -> Iterator[Skill]: sim = S4APUtils.get_sim_instance(sim_info) if sim is None: @@ -125,19 +128,21 @@ def get_all_skills_available_for_sim_gen(sim_info: SimInfo) -> Iterator[Skill]: def _is_skill_available_for_sim(skill: Skill) -> bool: return skill.can_add(sim) - yield from get_all_skills_gen(include_skill_callback=_is_skill_available_for_sim) + yield from S4APSkillUtils.get_all_skills_gen(include_skill_callback=_is_skill_available_for_sim) + @staticmethod def get_all_skills_gen(include_skill_callback: Callable[[Skill], bool] = None) -> Iterator[Skill]: statistic_manager = services.get_instance_manager(Types.STATISTIC) for skill in statistic_manager.get_ordered_types(only_subclasses_of=Skill): skill: Skill = skill - skill_id = get_skill_id(skill) + skill_id = S4APSkillUtils.get_skill_id(skill) if skill_id is None: continue if include_skill_callback is not None and not include_skill_callback(skill): continue yield skill + @staticmethod def get_skill_id(skill_identifier: Union[int, Skill]) -> Union[int, None]: """get_skill_id(skill_identifier) From fb3981b1d6427d7df63927cf69da4ee590ce5ab5 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Thu, 4 Sep 2025 12:09:14 -0600 Subject: [PATCH 014/134] move sim functions to new file + class --- Scripts/s4ap/events/career_event_dispatcher.py | 3 ++- Scripts/s4ap/utils/s4ap_generic_utils.py | 13 +------------ Scripts/s4ap/utils/s4ap_sim_utils.py | 13 +++++++++++++ Scripts/s4ap/utils/s4ap_skill_utils.py | 5 +++-- 4 files changed, 19 insertions(+), 15 deletions(-) create mode 100644 Scripts/s4ap/utils/s4ap_sim_utils.py diff --git a/Scripts/s4ap/events/career_event_dispatcher.py b/Scripts/s4ap/events/career_event_dispatcher.py index 8982b28..6b4c8c4 100644 --- a/Scripts/s4ap/events/career_event_dispatcher.py +++ b/Scripts/s4ap/events/career_event_dispatcher.py @@ -4,6 +4,7 @@ from s4ap.logging.s4ap_logger import S4APLogger from s4ap.modinfo import ModInfo from s4ap.utils.s4ap_generic_utils import S4APUtils +from s4ap.utils.s4ap_sim_utils import S4APSimUtils from sims4communitylib.events.event_handling.common_event import CommonEvent from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry from sims4communitylib.services.common_service import CommonService @@ -45,7 +46,7 @@ def _on_milestone_complete(original, self, *args, **kwargs): level = self._user_level sim_info = self._sim_info if sim_info in CommonHouseholdUtils.get_sim_info_of_all_sims_in_active_household_generator(): - sim_name = S4APUtils.get_sim_first_name(sim_info) + sim_name = S4APSimUtils.get_sim_first_name(sim_info) OnCareerPromotionEvent.get()._on_promotion(career, level, sim_name) return result diff --git a/Scripts/s4ap/utils/s4ap_generic_utils.py b/Scripts/s4ap/utils/s4ap_generic_utils.py index 4489cf3..8dc2f18 100644 --- a/Scripts/s4ap/utils/s4ap_generic_utils.py +++ b/Scripts/s4ap/utils/s4ap_generic_utils.py @@ -29,15 +29,4 @@ def trigger_autosave(*_) -> bool: ).show() CommonExceptionHandler.log_exception(ModInfo.get_identity(), 'An exception occurred while autosaving.', exception=ex) - return False - - - def get_sim_first_name(sim_info: SimInfo): - if sim_info is None or not hasattr('first_name'): - return '' - return getattr(sim_info, 'first_name') - - @classmethod - def get_sim_instance(cls, sim_identifier: SimInfo): - if isinstance(sim_identifier, SimInfo): - return sim_identifier.get_sim_instance() \ No newline at end of file + return False \ No newline at end of file diff --git a/Scripts/s4ap/utils/s4ap_sim_utils.py b/Scripts/s4ap/utils/s4ap_sim_utils.py new file mode 100644 index 0000000..bde60fc --- /dev/null +++ b/Scripts/s4ap/utils/s4ap_sim_utils.py @@ -0,0 +1,13 @@ + +class S4APSimUtils: + + @staticmethod + def get_sim_first_name(sim_info: SimInfo): + if sim_info is None or not hasattr('first_name'): + return '' + return getattr(sim_info, 'first_name') + + @classmethod + def get_sim_instance(cls, sim_identifier: SimInfo): + if isinstance(sim_identifier, SimInfo): + return sim_identifier.get_sim_instance() \ No newline at end of file diff --git a/Scripts/s4ap/utils/s4ap_skill_utils.py b/Scripts/s4ap/utils/s4ap_skill_utils.py index 4ace7fc..bedc08a 100644 --- a/Scripts/s4ap/utils/s4ap_skill_utils.py +++ b/Scripts/s4ap/utils/s4ap_skill_utils.py @@ -9,6 +9,7 @@ from s4ap.persistance.ap_session_data_store import S4APSessionStoreUtils from s4ap.utils.s4ap_generic_utils import S4APUtils from s4ap.utils.s4ap_household_utils import S4APHouseholdUtils +from s4ap.utils.s4ap_sim_utils import S4APSimUtils from server_commands.argument_helpers import TunableInstanceParam from sims.sim_info import SimInfo from sims4.resources import Types @@ -59,7 +60,7 @@ def lock_skills(skillcap: int, skill_name, from_level_up: bool): skill = TunableInstanceParam(Types.STATISTIC)(skill_name) for sim_info in S4APHouseholdUtils.get_sim_info_of_all_sims_in_active_household_generator(): current_level = S4APSkillUtils.get_current_skill_level(sim_info, skill) - logger.debug(f"{S4APUtils.get_sim_first_name(sim_info)}'s Current {skill_id} level is {current_level}.") + logger.debug(f"{S4APSimUtils.get_sim_first_name(sim_info)}'s Current {skill_id} level is {current_level}.") if skillcap > current_level: logger.debug(f"{skill_id} skill cap is greater than current level, unlocking skill.") remove_lock_trait(sim_info, trait) @@ -121,7 +122,7 @@ def set_current_skill_level(self, sim_info: SimInfo, skill: TunableInstanceParam @staticmethod def get_all_skills_available_for_sim_gen(sim_info: SimInfo) -> Iterator[Skill]: - sim = S4APUtils.get_sim_instance(sim_info) + sim = S4APSimUtils.get_sim_instance(sim_info) if sim is None: return tuple() From 68ec23ae8656ce1299b3bd13dc601c3407f90b53 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Thu, 4 Sep 2025 12:11:02 -0600 Subject: [PATCH 015/134] fix unused import --- Scripts/s4ap/events/career_event_dispatcher.py | 1 - Scripts/s4ap/utils/s4ap_generic_utils.py | 1 - 2 files changed, 2 deletions(-) diff --git a/Scripts/s4ap/events/career_event_dispatcher.py b/Scripts/s4ap/events/career_event_dispatcher.py index 6b4c8c4..197de74 100644 --- a/Scripts/s4ap/events/career_event_dispatcher.py +++ b/Scripts/s4ap/events/career_event_dispatcher.py @@ -3,7 +3,6 @@ from s4ap.events.checks.send_check_event import SendLocationEvent from s4ap.logging.s4ap_logger import S4APLogger from s4ap.modinfo import ModInfo -from s4ap.utils.s4ap_generic_utils import S4APUtils from s4ap.utils.s4ap_sim_utils import S4APSimUtils from sims4communitylib.events.event_handling.common_event import CommonEvent from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry diff --git a/Scripts/s4ap/utils/s4ap_generic_utils.py b/Scripts/s4ap/utils/s4ap_generic_utils.py index 8dc2f18..b0dc8e6 100644 --- a/Scripts/s4ap/utils/s4ap_generic_utils.py +++ b/Scripts/s4ap/utils/s4ap_generic_utils.py @@ -1,7 +1,6 @@ import services from s4ap.modinfo import ModInfo from services.persistence_service import SaveGameData -from sims.sim_info import SimInfo from sims4communitylib.events.zone_spin.common_zone_spin_event_dispatcher import CommonZoneSpinEventDispatcher from sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification From ec0e9805bba7b97704dda8cd9e144d68a8e4c701 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Thu, 4 Sep 2025 12:35:17 -0600 Subject: [PATCH 016/134] add career helpers to avoid using lots of s4cl functions --- Scripts/s4ap/utils/s4ap_career_utils.py | 149 ++++++++++++++++++++++++ Scripts/s4ap/utils/s4ap_phone_utils.py | 11 +- 2 files changed, 154 insertions(+), 6 deletions(-) create mode 100644 Scripts/s4ap/utils/s4ap_career_utils.py diff --git a/Scripts/s4ap/utils/s4ap_career_utils.py b/Scripts/s4ap/utils/s4ap_career_utils.py new file mode 100644 index 0000000..96f2cef --- /dev/null +++ b/Scripts/s4ap/utils/s4ap_career_utils.py @@ -0,0 +1,149 @@ +from careers.career_tuning import Career, CareerLevel, TunableCareerTrack +from lib.random import random +from lib.typing import Callable, Iterator, Tuple, Union +from services import get_instance_manager +from sims.sim_info import SimInfo +from sims4.resources import Types + +class S4APCareerUtils: + + @classmethod + def get_career_guid(cls, career: Career) -> Union[int, None]: + if career is None: + return None + return getattr(career, 'guid64', None) + + @staticmethod + def load_career_by_guid(career: Union[int, Career]) -> Union[Career, None]: + if career is None: + return None + if isinstance(career, Career): + return career + try: + career_guid = int(career) + except Exception: + return None # invalid ID + + # Use the game's instance manager for careers + career_manager = get_instance_manager(Types.CAREER) + if career_manager is None: + return None + return career_manager.get(career_guid) + + @classmethod + def get_all_careers_for_sim_gen(cls, sim_info: SimInfo, include_career_callback: Callable[[Career], bool]=None) -> Iterator[Career]: + if sim_info is None: + return tuple() + career_tracker = sim_info.career_tracker + if career_tracker is None: + return tuple() + + for career in career_tracker.careers.values(): + if include_career_callback is not None and not include_career_callback(career): + continue + yield career + + @staticmethod + def determine_entry_level_into_career_from_user_level(career: Career, desired_user_level: int) -> Tuple[ + Union[int, None], Union[int, None], Union[TunableCareerTrack, None]]: + if career is None: + return None, None, None + track = S4APCareerUtils.get_starting_career_track(career) + + @classmethod + def get_starting_career_track(cls, career: Career) -> Union[TunableCareerTrack, None]: + """get_starting_career_track(career) + + Retrieve the starting Career Track of a Career. + + :param career: A career. + :type career: Career + :return: The starting Career Track of the Career or None if not found. + :rtype: Union[TunableCareerTrack, None] + """ + if career is None: + return None + return career.start_track + + @classmethod + def determine_entry_level_into_career_track_by_user_level(cls, career_track: TunableCareerTrack, + desired_user_level: int) -> Tuple[ + Union[int, None], Union[int, None], Union[TunableCareerTrack, None]]: + if career_track is None: + return None, None, None + track = career_track + track_start_level = 1 + + while True: + track_length = len(cls.get_career_levels(track)) + level = desired_user_level - track_start_level + if level < track_length: + user_level = track_start_level + level + return level, user_level, track + + branches = cls.get_branches(track) + if not branches: + # The exit path. When we run out of branches to check we'll just return the last info found. + level = track_length - 1 + user_level = track_start_level + level + return level, user_level, track + + track_start_level += track_length + track = random.choice(branches) + + @classmethod + def get_career_levels(cls, career_track: TunableCareerTrack, include_branches: bool = False) -> Tuple[CareerLevel]: + if career_track is None: + return tuple() + if include_branches: + if career_track is None: + return tuple() + if include_branches: + # noinspection PyUnresolvedReferences + if hasattr(career_track, 'career_levels') and career_track.career_levels is not None: + career_levels: List[CareerLevel] = list(career_track.career_levels) + branches = cls.get_branches(career_track) + for branch_career_track in branches: + sub_career_levels = cls.get_career_levels(branch_career_track, + include_branches=include_branches) + if not sub_career_levels: + continue + career_levels.extend(sub_career_levels) + return tuple(career_levels) + else: + # noinspection PyUnresolvedReferences + if hasattr(career_track, 'career_levels') and career_track.career_levels is not None: + return tuple(career_track.career_levels) + return tuple() + + @classmethod + def get_branches(cls, career_track: TunableCareerTrack, include_sub_branches: bool = False) -> Tuple[ + TunableCareerTrack]: + """get_branches(career_track, include_sub_branches=True) + + Retrieve a collection of all Career Tracks that branch off of a Career Track and if specified, the branches those branches branch off to. + + :param career_track: A Career Track. + :type career_track: TunableCareerTrack + :param include_sub_branches: If True, all branches will be checked for their own branches and those branches will be included recursively. If False, only the top level branches will be included. Default is False. + :type include_sub_branches: bool, optional + :return: A collection of all Career Tracks that branch off from the specified Career Track. + :rtype: Tuple[TunableCareerTrack] + """ + if career_track is None: + return tuple() + if include_sub_branches: + # noinspection PyUnresolvedReferences + if hasattr(career_track, 'branches') and career_track.branches is not None: + career_track_branches: List[TunableCareerTrack] = list(career_track.branches) + for sub_career_track in career_track_branches: + sub_branches = cls.get_branches(sub_career_track, include_sub_branches=include_sub_branches) + if not sub_branches: + continue + career_track_branches.extend(sub_branches) + return tuple(career_track_branches) + else: + # noinspection PyUnresolvedReferences + if hasattr(career_track, 'branches') and career_track.branches is not None: + return tuple(career_track.branches) + return tuple() \ No newline at end of file diff --git a/Scripts/s4ap/utils/s4ap_phone_utils.py b/Scripts/s4ap/utils/s4ap_phone_utils.py index b8ae68f..e534c40 100644 --- a/Scripts/s4ap/utils/s4ap_phone_utils.py +++ b/Scripts/s4ap/utils/s4ap_phone_utils.py @@ -6,6 +6,7 @@ from s4ap.logging.s4ap_logger import S4APLogger from s4ap.modinfo import ModInfo from s4ap.persistance.ap_session_data_store import S4APSessionStoreUtils +from s4ap.utils.s4ap_career_utils import S4APCareerUtils from s4ap.utils.s4ap_household_utils import S4APHouseholdUtils from s4ap.utils.s4ap_skill_utils import S4APSkillUtils from server_commands.argument_helpers import TunableInstanceParam @@ -17,8 +18,6 @@ from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification from sims4communitylib.utils.common_icon_utils import CommonIconUtils from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.sims.common_career_utils import CommonCareerUtils -from sims4communitylib.utils.sims.common_sim_career_utils import CommonSimCareerUtils from ui.ui_dialog_picker import ObjectPickerRow logger = S4APLogger.get_log() @@ -124,8 +123,8 @@ def _resync_locations(event_data: S4CLSimTraitAddedEvent): for level in range(2, int(skill_level) + 1): location_name = f'{skill_new_name.title()} Skill {level}' locations.append(location_name) - for career in CommonSimCareerUtils.get_all_careers_for_sim_gen(sim_info): - career_id = CommonCareerUtils.get_career_guid(career) + for career in S4APCareerUtils.get_all_careers_for_sim_gen(sim_info): + career_id = S4APCareerUtils.get_career_guid(career) career_level = career.user_level if careers_dict.get(career_id) is not None: if career_level > careers_dict.get(career_id): @@ -133,9 +132,9 @@ def _resync_locations(event_data: S4CLSimTraitAddedEvent): else: careers_dict[career_id] = career_level for career_guid, level in careers_dict.items(): - career = CommonCareerUtils.load_career_by_guid(career_guid) + career = S4APCareerUtils.load_career_by_guid(career_guid) for i in range(1, level + 1): - (_, _, career_track) = CommonCareerUtils.determine_entry_level_into_career_from_user_level(career, i) + (_, _, career_track) = S4APCareerUtils.determine_entry_level_into_career_from_user_level(career, i) career_hash = career_track.get_career_name(sim_info).hash career_name = lookup.get_career_name(career_hash, i) if career_name is not None: From d7750174ca6b73f2d6d464e2a4332b414b581974 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Thu, 4 Sep 2025 16:29:54 -0600 Subject: [PATCH 017/134] this could work for localization stuff, but it's not likely to be super great --- Scripts/s4ap/utils/s4ap_localization_utils.py | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 Scripts/s4ap/utils/s4ap_localization_utils.py diff --git a/Scripts/s4ap/utils/s4ap_localization_utils.py b/Scripts/s4ap/utils/s4ap_localization_utils.py new file mode 100644 index 0000000..efa276b --- /dev/null +++ b/Scripts/s4ap/utils/s4ap_localization_utils.py @@ -0,0 +1,31 @@ +from protocolbuffers.Localization_pb2 import LocalizedString +from sims4.localization import LocalizationHelperTuning, _create_localized_string, create_tokens + +class S4APLocalizationUtils: + + @staticmethod + def localize(string_object, tokens=()): + tokens = S4APLocalizationUtils._localize_tokens(tokens) + if isinstance(string_object, str): + string_object = LocalizationHelperTuning.get_raw_text(string_object) + else: + if isinstance(string_object, int): + return _create_localized_string(string_object, tokens) + if hasattr(string_object, 'populate_localization_token'): + return string_object + if isinstance(string_object, LocalizedString): + create_tokens(string_object.tokens, tokens) + return string_object + elif isinstance(string_object, LocalizedString): + create_tokens(string_object.tokens, tokens) + return string_object + if isinstance(string_object, LocalizedString): + create_tokens(string_object.tokens, tokens) + return string_object + + @staticmethod + def _localize_tokens(tokens_unlocalized): + tokens = list() + for token in tokens_unlocalized: + tokens.append(S4APLocalizationUtils.localize(token)) + return tokens \ No newline at end of file From 237492b288c2d3f6d92de930ceec7b9030b064bd Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Thu, 4 Sep 2025 16:30:12 -0600 Subject: [PATCH 018/134] maybe we needed a skill id enum... probably not though --- Scripts/s4ap/enums/S4APLocalization.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Scripts/s4ap/enums/S4APLocalization.py b/Scripts/s4ap/enums/S4APLocalization.py index 6ec4ad5..fcd086f 100644 --- a/Scripts/s4ap/enums/S4APLocalization.py +++ b/Scripts/s4ap/enums/S4APLocalization.py @@ -396,3 +396,9 @@ def get_career_name(self, hash_value, level): for career_location in careers_list: if career in career_location: return career_location + +class SkillID(int): + ADULT_MAJOR_ACTING = 194727 + ADULT_MAJOR_ARCHAEOLOGY = 174237 + ADULT_MAJOR_BAKING = None + ADULT_MAJOR_BARTENDING = None \ No newline at end of file From 9e6f9d80ac001b748e57664889f0c4c463312089 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Thu, 4 Sep 2025 16:34:25 -0600 Subject: [PATCH 019/134] update gitignore file to include more of the folders that are in the project --- .gitignore | 9 +- EA/README.md | 15 + Utilities/__init__.py | 0 Utilities/compile_utils.py | 87 + Utilities/decompilation_method.py | 4 + Utilities/py37_decompiler.py | 714 +++++++ Utilities/py37_execute_decompile.exe | Bin 0 -> 4238336 bytes Utilities/unpyc3.py | 2659 ++++++++++++++++++++++++ Utilities/unpyc3_compiler.py | 115 + Utilities/unpyc3_decompiler.py | 87 + custom_scripts_for_decompile/README.md | 10 + decompile_scripts.py | 47 + 12 files changed, 3741 insertions(+), 6 deletions(-) create mode 100644 EA/README.md create mode 100644 Utilities/__init__.py create mode 100644 Utilities/compile_utils.py create mode 100644 Utilities/decompilation_method.py create mode 100644 Utilities/py37_decompiler.py create mode 100644 Utilities/py37_execute_decompile.exe create mode 100644 Utilities/unpyc3.py create mode 100644 Utilities/unpyc3_compiler.py create mode 100644 Utilities/unpyc3_decompiler.py create mode 100644 custom_scripts_for_decompile/README.md create mode 100644 decompile_scripts.py diff --git a/.gitignore b/.gitignore index ed419d3..2f93c4d 100644 --- a/.gitignore +++ b/.gitignore @@ -2,10 +2,11 @@ .idea # EA Scripts -EA +EA/* +!EA/README.md # Libraries -Libraries/**/* +Libraries/** # Additional non mod related items Scripts/compile @@ -33,7 +34,6 @@ Utilities/*.pyc **/*.pyc */*.pyc */*.pyo -custom_scripts_for_decompile custom_scripts_for_decompile/*.py custom_scripts_for_decompile/*.pyc custom_scripts_for_decompile/*.pyo @@ -52,10 +52,7 @@ custom_scripts_for_decompile/**/*.py **/*.lnk **/*.xml___jb_old___ Tunings/Temp -Utilities -decompile_scripts.py settings.py Pipfile .DS_Store # Project exclude paths -/Release/ diff --git a/EA/README.md b/EA/README.md new file mode 100644 index 0000000..4b7562e --- /dev/null +++ b/EA/README.md @@ -0,0 +1,15 @@ +This folder will be where the decompiled EA python scripts will be placed when running `decompile_scripts.py` with `should_decompile_ea_scripts` set to `True` + +# Decompile EA Python Scripts. + +1. Inside `/settings.py`, change `should_decompile_ea_scripts` to `True` +2. If it does not exist, create a folder in your project with the name `EA`. i.e. /EA +3. Run the `decompile_scripts.py` script +4. The script will decompile the EA python scripts and put them inside of this folder: `/EA/...` +5. After the script finishes running, look inside of the `/EA` folder, you should see four folders (`base`, `core`, `generated`, `simulation`) and four zip files (`base.zip`, `core.zip`, `generated.zip`, `simulation.zip`) +6. In PyCharm, highlight all four folders (Not Zip files) (`base`, `core`, `generated`, `simulation`) and Right Click them -> `Mark Directory as...` -> `Sources Root` +- root\EA\base +- root\EA\core +- root\EA\generated +- root\EA\simulation +7. The folders should now be `BLUE` in color, if they are not `BLUE`, repeat step the previous step. \ No newline at end of file diff --git a/Utilities/__init__.py b/Utilities/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Utilities/compile_utils.py b/Utilities/compile_utils.py new file mode 100644 index 0000000..388d693 --- /dev/null +++ b/Utilities/compile_utils.py @@ -0,0 +1,87 @@ +import os + + +def _remove_files_conflicting_with_decompile(decompile_ea_scripts: bool=False): + ea_folder = os.path.realpath(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'EA')) + if not os.path.exists(ea_folder): + os.mkdir(ea_folder) + + if decompile_ea_scripts: + # print('Removing EA decompiled files before decompiling it again.') + to_remove_before_compile = ( + 'base', + 'base.zip', + 'core', + 'core.zip', + 'generated', + 'generated.zip', + 'simulation', + 'simulation.zip', + ) + + def _remove_directory_recursive(directory_path: str): + for _file_in_dir in os.listdir(directory_path): + _to_remove_path = os.path.join(directory_path, _file_in_dir) + if os.path.isdir(_to_remove_path): + # noinspection PyBroadException + try: + os.rmdir(_to_remove_path) + except: + _remove_directory_recursive(_to_remove_path) + os.rmdir(_to_remove_path) + else: + os.remove(_to_remove_path) + + for to_remove in to_remove_before_compile: + to_remove_path = os.path.join(ea_folder, to_remove) + if not os.path.exists(to_remove_path): + # print(f'Did not exist \'{to_remove_path}\'') + continue + if os.path.isdir(to_remove_path): + # noinspection PyBroadException + try: + os.rmdir(to_remove_path) + except: + _remove_directory_recursive(to_remove_path) + os.rmdir(to_remove_path) + else: + os.remove(to_remove_path) + else: + # print('Renaming enum.py to enum.py_renamed') + to_fix_before_decompile = ( + os.path.join('core', 'enum.py'), + os.path.join('core', 'enum.pyc'), + ) + + for to_fix in to_fix_before_decompile: + to_fix_path = os.path.join(ea_folder, to_fix) + if not os.path.exists(to_fix_path): + # print(f'Did not exist \'{to_fix_path}\'') + continue + if os.path.isdir(to_fix_path): + os.rename(to_fix_path, to_fix_path + '_renamed') + else: + os.rename(to_fix_path, to_fix_path + '_renamed') + + +def _replace_renamed_files(decompile_ea_scripts: bool=False): + if decompile_ea_scripts: + return + + # print('Renaming enum.py_renamed to enum.py') + + ea_folder = os.path.realpath(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'EA')) + to_fix_after_decompile = ( + os.path.join('core', 'enum.py_renamed'), + os.path.join('core', 'enum.pyc_renamed'), + ) + + for to_fix in to_fix_after_decompile: + to_remove_path = os.path.join('.', ea_folder, to_fix) + if not os.path.exists(to_remove_path): + # print(f'Did not exist \'{to_remove_path}\'') + continue + if os.path.isdir(to_remove_path): + os.rename(to_remove_path, to_remove_path.rstrip('_renamed')) + else: + os.rename(to_remove_path, to_remove_path.rstrip('_renamed')) \ No newline at end of file diff --git a/Utilities/decompilation_method.py b/Utilities/decompilation_method.py new file mode 100644 index 0000000..8d9fb17 --- /dev/null +++ b/Utilities/decompilation_method.py @@ -0,0 +1,4 @@ +class S4PyDecompilationMethod: + """Method to use when compiling/decompiling python code.""" + UNPYC3 = 'unpyc3' + PY37DEC = 'py37dec' diff --git a/Utilities/py37_decompiler.py b/Utilities/py37_decompiler.py new file mode 100644 index 0000000..b1a4fce --- /dev/null +++ b/Utilities/py37_decompiler.py @@ -0,0 +1,714 @@ +# TS4 Python decompiler front-end +# Original code by Scumbumbo @ Mod The Sims and Andrew @ Sims 4 Studio +# Modified code by ColonolNutty +# +# May be freely modified for personal use +# +# May be redistributed AS-IS or in modified form, providing: +# - All comments and code authorship attributions remain unmodified except as required for clarity +# - This redistribution notice must remain intact +# - The hosted site is free and community-friendly: +# - Host site may be advertising supported to offset costs +# - Host site may not restrict downloads in any way, particularly but not limited to +# - Paid registration requirements (free registrations are okay) +# - Forced download waits due to ad-block detection +# +from typing import List, Any + +from decompilation_method import S4PyDecompilationMethod +from settings import decompile_method_name, game_folder +import os + +# These defaults can be edited here and/or overridden on command line +# +# Location of the game's zipped binary scripts (base.zip, core.zip and simulation.zip) +GAME_ZIP_FOLDER = game_folder + +# Default destination folder to put decompiled scripts into. +# Will be created if not found. +DEFAULT_PY_DESTINATION_FOLDER = './ts4_scripts' + +# You may want to turn this down to 2 or 4 if you don't have a quad-core CPU +DEFAULT_MAX_THREADS = 1 + +# Set to either S4PyDecompilationMethod.UNPYC3 or S4PyDecompilationMethod.PY37DEC +DEFAULT_DECOMPILER = decompile_method_name + +""" Command line help: + +decompiler.py - For decompiling The Sims 4 Python modules + +Requires: + - Python version 3.7.0 + - py37_execute_decompile.exe executable must be available on the system path or in current folder, + or unpyc3 (with 3.7.0 decompile support) module must be available for import + +usage: decompiler.py [-h] [-z ZIP_FOLDER] [-s SOURCE_FOLDER] [-d DEST_FOLDER] + [-S] [-p] [-t N] [-r [FILENAME]] [-L [N]] + [-c none|detail] [-U] [-P] [-T SEC] + +optional arguments: + -h, --help show this help message and exit + -z ZIP_FOLDER location of installed game Zip files + -s SOURCE_FOLDER get compiled scripts from folder instead of Zip files + -d DEST_FOLDER destination folder for decompilaed files + -S create subfolders of DEST_FOLDER by result + -p prefix output filenames with [RESULT] + -t N number of simultaneous decompile threads to use + -r [FILENAME] create CSV file containing results for decompiled files + -L [N] code objects with >N bytes will not be analyzed + -c none|detail prefix decompiled files with test results comment (default brief) + -U use unpyc3 for decompilation + -P use py37dec for decompilation + -T SEC py37dec only: override timeout in seconds (0=no limit, default 5) +""" + + +################################################################# +# DO NOT EDIT BELOW THIS LINE WITHOUT KNOWING WHAT YOU'RE DOING # +################################################################# +import subprocess +import time +import traceback +import dis +import marshal +import types +import difflib +import re +import sys +import argparse +import shutil +import zipfile + +if DEFAULT_DECOMPILER != S4PyDecompilationMethod.PY37DEC and DEFAULT_DECOMPILER != S4PyDecompilationMethod.UNPYC3: + print('Invalid setting for DEFAULT_DECOMPILER in source') + exit() +if os.path.isfile('./py37_execute_decompile.exe'): + PY37DEC_EXECUTABLE_LOCATION = './py37_execute_decompile.exe' +elif os.path.isfile('./py37_execute_decompile'): + PY37DEC_EXECUTABLE_LOCATION = './py37_execute_decompile' +else: + PY37DEC_EXECUTABLE_LOCATION = shutil.which('py37_execute_decompile') +PY37DEC_AVAILABLE = True if PY37DEC_EXECUTABLE_LOCATION is not None else False +UNPYC3_AVAILABLE = False +DECOMPILER = None + +try: + import unpyc3 + UNPYC3_AVAILABLE = True +except: + pass + + +# Quick 'n' dirty stopwatch timer +class _StopWatch: + def __init__(self) -> None: + self.start_time = time.perf_counter() + + @property + def elapsed_time(self) -> float: + return time.perf_counter() - self.start_time + + +# Values returned from a "thread" to indicate results. Since the Python VM doesn't really +# support true threads and shared data, the results are encapsulated in this and the Python +# "threading" library returns this information to the main thread via an OS dependent mechanism. +class _DecompileResultData: + def __init__(self, pyc_file_name: str): + self._pyc_file_name = pyc_file_name + self.py_file_name = '' + self.decompile_time = -1 + self.analyze_time = -1 + self.result = -1 + + @property + def pyc_file_name(self) -> str: + return self._pyc_file_name + + +class Py37PythonDecompiler: + """Handles decompilation of python files from pyc to py using py37dec.""" + # Code object comparison routines based on code written by Andrew from Sims 4 Studio + # + # Handle formatting dis() output of a code object in order to run through a diff process. + _CODE_OBJECT_REGEX = re.compile(r'(.*)\(\\)', re.RegexFlag.IGNORECASE) + + # Launch "threads" and summarize results + def decompile(self, src_folder, dest_folder, prefix_filenames=False, max_threads=DEFAULT_MAX_THREADS, results_file=None, test_large_codeobjects=False, large_codeobjects_threshold=10000, comment_style=0, py37dec_timeout=5, split_result_folders=False): + global total, DEFAULT_DECOMPILER + from shutil import copyfile + from Utilities.unpyc3_decompiler import Unpyc3PyDecompiler + + timer = _StopWatch() + if py37dec_timeout == 0: + py37dec_timeout = None + + # Create our "thread" pool + results = [] + + print('Decompiling all files in {} using {}, please wait'.format(src_folder, DEFAULT_DECOMPILER)) + + # Search the source folder for all .pyc files and add a call to decompile() + # to the "thread" pool. + source_folder = os.path.realpath(src_folder) + destination_folder = os.path.realpath(dest_folder) + if source_folder == destination_folder: + destination_folder = os.path.join(destination_folder, '_decompiled') + if not os.path.exists(destination_folder): + os.mkdir(destination_folder) + else: + def _remove_directory_recursive(directory_path: str): + for _file_in_dir in os.listdir(directory_path): + _to_remove_path = os.path.join(directory_path, _file_in_dir) + if os.path.isdir(_to_remove_path): + # noinspection PyBroadException + try: + os.rmdir(_to_remove_path) + except: + _remove_directory_recursive(_to_remove_path) + os.rmdir(_to_remove_path) + else: + os.remove(_to_remove_path) + + # noinspection PyBroadException + try: + os.rmdir(destination_folder) + except: + _remove_directory_recursive(destination_folder) + os.rmdir(destination_folder) + os.mkdir(destination_folder) + + for root, subFolders, files in os.walk(src_folder): + if root.startswith(destination_folder): + continue + files = [f for f in files if os.path.splitext(f)[1].lower() == '.pyc'] + for pycFile in files: + total += 1 + sub_folder = os.path.relpath(root, source_folder) + file_name = os.path.splitext(pycFile)[0] + py_file_name = file_name + '.py' + py_full_file_path = os.path.join(source_folder, sub_folder, py_file_name) + py_full_destination_file_path = os.path.join(destination_folder, sub_folder, py_file_name) + copied_file_path = os.path.join(source_folder, sub_folder, f'{pycFile}_copied') + pyc_full_file_path = os.path.join(source_folder, sub_folder, pycFile) + copyfile(pyc_full_file_path, copied_file_path) + the_file = os.path.join(src_folder, sub_folder, pycFile) + # print(f'Attempting to decompile file: {os.path.join(src_folder, sub_folder, pycFile)}') + result = self._decompile( + source_folder, + destination_folder, + sub_folder, + pycFile, + py_file_name, + prefix_filenames, + large_codeobjects_threshold, + comment_style, + DECOMPILER, + py37dec_timeout, + split_result_folders + ) + if not is_success(result): + print('Failed to decompile file, attempting to use alternative decompiler.') + copyfile(copied_file_path, pyc_full_file_path) + os.remove(copied_file_path) + print(pyc_full_file_path) + if not Unpyc3PyDecompiler.decompile_file(pyc_full_file_path, throw_on_error=False): + print(f'FAILED: {the_file}') + else: + print(f'SUCCESS: {the_file}') + # print(f'Removing {py_full_file_path}') + copyfile(py_full_file_path, py_full_destination_file_path) + os.remove(py_full_file_path) + result = _DecompileResultData(os.path.realpath(pyc_full_file_path)) + result.result = 1 + else: + print(f'SUCCESS: {the_file}') + os.remove(copied_file_path) + completed_callback(result) + results.append(result) + + # Print results summary and CSV results file if requested + print('\b\b\b\b\b\b') + if total == 0: + print(f' \nError, no compiled Python files found in source folder {source_folder}') + return + print('Completed') + + print('\nperfect\t= {} ({:0.1f}%)'.format(len(perfect), len(perfect)/total*100)) + print('good\t= {} ({:0.1f}%)'.format(len(good), len(good)/total*100)) + print('syntax\t= {} ({:0.1f}%)'.format(len(syntax), len(syntax)/total*100)) + print('failure\t= {} ({:0.1f}%)'.format(len(failed), len(failed)/total*100)) + if len(timeout) > 0: + print('timeout\t= {} ({:0.1f}%)'.format(len(timeout), len(timeout)/total*100)) + print('{:0.2f} seconds'.format(timer.elapsed_time)) + + if results_file: + with open(results_file, 'w', encoding='UTF-8') as fp: + fp.write(' ,Compiled,Decompiled,Decompile,Compare\nResult,Path,Path,Time,Time\n') + for decompile_result in perfect: + fp.write('PERFECT,{},{},{},{}\n'.format(os.path.relpath(decompile_result.pyc_file_name, src_folder), os.path.relpath(decompile_result.pyFilename, dest_folder), decompile_result.decompile_time, decompile_result.analyze_time)) + for decompile_result in good: + fp.write('GOOD,{},{},{},{}\n'.format(os.path.relpath(decompile_result.pyc_file_name, src_folder), os.path.relpath(decompile_result.pyFilename, dest_folder), decompile_result.decompile_time, decompile_result.analyze_time)) + for decompile_result in failed: + fp.write('FAILED,{},{},{},{}\n'.format(os.path.relpath(decompile_result.pyc_file_name, src_folder), os.path.relpath(decompile_result.pyFilename, dest_folder), decompile_result.decompile_time, decompile_result.analyze_time)) + for decompile_result in syntax: + fp.write('SYNTAX,{},{},{},{}\n'.format(os.path.relpath(decompile_result.pyc_file_name, src_folder), os.path.relpath(decompile_result.pyFilename, dest_folder), decompile_result.decompile_time, decompile_result.analyze_time)) + for decompile_result in timeout: + fp.write('TIMEOUT,{},{},{},{}\n'.format(os.path.relpath(decompile_result.pyc_file_name, src_folder), os.path.relpath(decompile_result.pyFilename, dest_folder), decompile_result.decompile_time, decompile_result.analyze_time)) + + # Decompile a .pyc file to produce a .py file + # Returns a _DecompileResultData encapsulation of the result information. + def _decompile(self, srcFolder: str, destination_folder: str, subFolder: str, pycFile: str, python_file_to_decompile, prefix_filenames, large_codeobjects_threshold, comment_style, decompiler, py37dec_timeout, split_result_folders): + global PY37DEC_EXECUTABLE_LOCATION + decompile_results = _DecompileResultData(os.path.realpath(os.path.join(srcFolder, subFolder, pycFile))) + timer = _StopWatch() + remove_pyc = True if srcFolder == destination_folder else False + pyc_full_file_path = os.path.join(srcFolder, subFolder, pycFile) + + # noinspection PyBroadException + try: + if decompiler == S4PyDecompilationMethod.UNPYC3: + # For unpyc3, just call the decompile() method from that module + src_code = '' + lines = unpyc3.decompile(pyc_full_file_path) + for line in lines: + src_code += str(line) + '\n' + else: + # For py37dec, run the executable (py37_execute_decompile.exe) in a subprocess. At least one file from TS4 still takes + # too long (and too much virtual memory) to process, so a timeout is specified. + subprocess_result = subprocess.run( + [ + PY37DEC_EXECUTABLE_LOCATION, + pyc_full_file_path.replace('\\', '/') + ], + capture_output=True, + encoding='utf-8', + timeout=py37dec_timeout + ) + decompile_results.decompile_time = timer.elapsed_time + if subprocess_result.returncode != 0: + # Non-zero return code from the py37dec executable (py37_execute_decompile.exe) indicates a crash failure + # in the executable. Summarize and build an empty .py file. + if prefix_filenames: + python_file_to_decompile = f'[FAILED] {python_file_to_decompile}' + if split_result_folders: + python_folder_to_decompile = os.path.join(destination_folder, 'decompile_failure', subFolder) + else: + python_folder_to_decompile = os.path.join(destination_folder, subFolder) + os.makedirs(python_folder_to_decompile, exist_ok=True) + decompile_results.py_file_name = os.path.realpath(os.path.join(python_folder_to_decompile, python_file_to_decompile)) + with open(decompile_results.py_file_name, 'w', encoding='UTF-8') as fp: + if comment_style == 1: + fp.write(f'# {decompiler}: Decompile failed\n') + elif comment_style == 2: + fp.write('"""\npy37dec: Decompilation failure\n\n') + fp.write(subprocess_result.stderr) + fp.write('"""\n') + decompile_results.result = 3 + if remove_pyc: + os.remove(pyc_full_file_path) + return decompile_results + # Rc = 0 from subprocess, so read the source code lines from the subprocess stdout + src_code = subprocess_result.stdout + except subprocess.TimeoutExpired: + # This exception will only occur if a py37dec subprocess is killed off due to a timeout. + decompile_results.decompile_time = timer.elapsed_time + if prefix_filenames: + python_file_to_decompile = f'[TIMEOUT] {python_file_to_decompile}' + if split_result_folders: + python_folder_to_decompile = os.path.join(destination_folder, 'timeout', subFolder) + else: + python_folder_to_decompile = os.path.join(destination_folder, subFolder) + os.makedirs(python_folder_to_decompile, exist_ok=True) + decompile_results.py_file_name = os.path.realpath(os.path.join(python_folder_to_decompile, python_file_to_decompile)) + decompile_results.result = 4 + with open(decompile_results.py_file_name, 'w', encoding='UTF-8') as fp: + if comment_style == 1: + fp.write('# py37dec: Timeout\n') + elif comment_style == 2: + fp.write(f'"""\npy37dec: Timeout of {py37dec_timeout} seconds exceeded\n"""\n') + if remove_pyc: + os.remove(pyc_full_file_path) + return decompile_results + except Exception as ex: + # A normal exception will occur if unpyc3 fails and throws an exception during the + # decompilation process. + if prefix_filenames: + python_file_to_decompile = f'[FAILED] {python_file_to_decompile}: {ex}' + if split_result_folders: + python_folder_to_decompile = os.path.join(destination_folder, 'decompile_failure', subFolder) + else: + python_folder_to_decompile = os.path.join(destination_folder, subFolder) + os.makedirs(python_folder_to_decompile, exist_ok=True) + decompile_results.py_file_name = os.path.realpath(os.path.join(python_folder_to_decompile, python_file_to_decompile)) + with open(decompile_results.py_file_name, 'w', encoding='UTF-8') as fp: + if comment_style == 1: + fp.write(f'# {decompiler}: Decompile failed\n') + elif comment_style == 2: + fp.write('"""\nunpyc3: Decompilation failure\n\n') + fp.write(traceback.format_exc()) + fp.write('"""\n') + decompile_results.result = 3 + if remove_pyc: + os.remove(pyc_full_file_path) + return decompile_results + + decompile_results.decompile_time = timer.elapsed_time + + syntax_error = None + # noinspection PyBroadException + try: + # Try compiling the generated source, a syntax error in the source code + # will throw an exception. + py_compiled_obj = compile(src_code, python_file_to_decompile, 'exec') + + # Get the code object from the .pyc file + pyc_compiled_obj = self._get_code_obj_from_pyc(decompile_results.pyc_file_name) + + # Compare the code objects recursively + issues = self._compare_code_objs(pyc_compiled_obj, py_compiled_obj, large_codeobjects_threshold) + decompile_results.analyze_time = timer.elapsed_time - decompile_results.decompile_time + + if not issues: + # There were no issues returned from the code object comparison, so this code + # is identical to the original sources. + if prefix_filenames: + python_file_to_decompile = '[PERFECT] ' + python_file_to_decompile + if split_result_folders: + python_folder_to_decompile = os.path.join(destination_folder, 'perfect', subFolder) + else: + python_folder_to_decompile = os.path.join(destination_folder, subFolder) + decompile_results.py_file_name = os.path.realpath(os.path.join(python_folder_to_decompile, python_file_to_decompile)) + decompile_results.result = 0 + else: + # There were comparison issues with the code objects, this source code differs + # from the original. It may function identically or improperly (or not at all) but + # only human inspection of the resulting code can determine how good the results are. + if prefix_filenames: + python_file_to_decompile = '[GOOD] ' + python_file_to_decompile + if split_result_folders: + python_folder_to_decompile = os.path.join(destination_folder, 'good', subFolder) + else: + python_folder_to_decompile = os.path.join(destination_folder, subFolder) + decompile_results.py_file_name = os.path.realpath(os.path.join(python_folder_to_decompile, python_file_to_decompile)) + decompile_results.result = 1 + except Exception as ex: + # An exception from the compile or comparison will end up here, this is generally + # due to a syntax error in the decompilation results. + if prefix_filenames: + python_file_to_decompile = f'[SYNTAX] {python_file_to_decompile}: {ex}' + if split_result_folders: + python_folder_to_decompile = os.path.join(destination_folder, 'syntax', subFolder) + else: + python_folder_to_decompile = os.path.join(destination_folder, subFolder) + decompile_results.py_file_name = os.path.realpath(os.path.join(python_folder_to_decompile, python_file_to_decompile)) + decompile_results.result = 2 + syntax_error = traceback.format_exc(1) + + # Create the destination folder for this .py file and write it, adding comments + # if requested (1 = brief, 2 = detailed). + os.makedirs(python_folder_to_decompile, exist_ok=True) + with open(decompile_results.py_file_name, 'w', encoding='UTF-8') as fp: + if comment_style == 1: + if syntax_error: + fp.write('# {}: Syntax error in decompiled file\n'.format(decompiler)) + elif issues: + fp.write('# {}: Decompiled file contains inaccuracies\n'.format(decompiler)) + else: + fp.write('# {}: 100% Accurate decompile result\n'.format(decompiler)) + elif comment_style == 2: + if syntax_error: + fp.write(f'"""\n{decompiler}:\n{syntax_error}"""\n') + elif issues: + fp.write(f'"""\n{decompiler}:\n{issues}"""\n') + else: + fp.write(f'# {decompiler}: 100% Accurate decompile result\n') + fp.write(src_code) + + if remove_pyc: + os.remove(pyc_full_file_path) + return decompile_results + + # Perform the actual code object comparisons + # Returns a string of errors found, or an empty string for a perfect comparison result + def _compare_code_objs(self, pyc_co, py_co, large_codeobjects_threshold): + # Large code objects can take a significant time to process with diff(), so skipped by default + if large_codeobjects_threshold and len(py_co.co_code) > large_codeobjects_threshold: + return '{0}\nSKIPPING COMPARISON OF LARGE CODE OBJECT\n\t{1}\n{0}\n'.format('='*80, pyc_co.co_name) + err_str = '' + flags_err_str = '' + names_err_str = '' + consts_err_str = '' + args_err_str = '' + locals_err_str = '' + if pyc_co.co_flags != py_co.co_flags: + flags_err_str = 'Differings flags: {} != {}\n'.format(pyc_co.co_flags, py_co.co_flags) + if (pyc_co.co_flags & 0x4) == 0x4 and (py_co.co_flags & 0x4) == 0: + flags_err_str += '\tMissing expected *args\n' + if (pyc_co.co_flags & 0x8) == 0x8 and (py_co.co_flags & 0x8) == 0: + flags_err_str += '\tMissing expected **kwargs\n' + if (pyc_co.co_flags & 0x20) != (py_co.co_flags & 0x20): + if pyc_co.co_flags & 0x20 == 0x20: + flags_err_str += '\tShould be generator function but is not\n' + else: + flags_err_str += '\tIs generator function but should not be\n' + if pyc_co.co_kwonlyargcount != py_co.co_kwonlyargcount: + args_err_str = 'Differing kwonlyargcount: {} != {}\n'.format(pyc_co.co_kwonlyargcount, py_co.co_kwonlyargcount) + if pyc_co.co_argcount != py_co.co_argcount: + args_err_str += 'Differing argcount: {} != {}\n'.format(pyc_co.co_argcount, py_co.co_argcount) + if len(py_co.co_names) != len(pyc_co.co_names): + names_err_str += 'Differing number of global names: {} != {}\n'.format(len(pyc_co.co_names), len(py_co.co_names)) + names_err_str += '\tExpected: {}\n\tActual: {}\n'.format(pyc_co.co_names, py_co.co_names) + else: + current_cell_index = 0 + # Compare all constant names to ensure equality + for name in pyc_co.co_names: + if len(py_co.co_names) < current_cell_index + 1: + names_err_str += 'Unable to compare global name {}. Does not exist in the decompiled version\n'.format(name) + elif name != py_co.co_names[current_cell_index]: + names_err_str += 'Global name: {} != {}\n'.format(name, py_co.co_names[current_cell_index]) + current_cell_index += 1 + if len(py_co.co_consts) != len(pyc_co.co_consts): + consts_err_str += 'Differing number of constants: {} != {}\n'.format(len(pyc_co.co_consts), len(py_co.co_consts)) + consts_err_str += '\tExpected: {}\n\tActual: {}\n'.format(pyc_co.co_consts, py_co.co_consts) + else: + current_cell_index = 0 + # Compare all constants to ensure equality + for constant in pyc_co.co_consts: + if len(py_co.co_consts) < current_cell_index + 1: + consts_err_str += 'Unable to compare constant {}. Does not exist in the decompiled version\n'.format(constant) + elif type(constant) is types.CodeType: + if type(py_co.co_consts[current_cell_index]) is types.CodeType: + err_str += self._compare_code_objs(constant, py_co.co_consts[current_cell_index], large_codeobjects_threshold) + else: + consts_err_str += 'Constants mismatched: unable to compare code object {} to non-code object {}\n'.format(constant, py_co.co_consts[current_cell_index]) + elif constant != py_co.co_consts[current_cell_index]: + consts_err_str += 'Constant: {} != {}\n'.format(constant, py_co.co_consts[current_cell_index]) + current_cell_index += 1 + if py_co.co_nlocals != pyc_co.co_nlocals: + locals_err_str += 'Differing number of locals: {} != {}\n'.format(pyc_co.co_nlocals, py_co.co_nlocals) + locals_err_str += '\tExpected: {}\n\tActual: {}\n'.format(pyc_co.co_varnames, py_co.co_varnames) + else: + current_cell_index = 0 + # Compare all local names to ensure equality + for name in pyc_co.co_varnames: + if py_co.co_nlocals < current_cell_index + 1: + locals_err_str += 'Unable to compare local var name {}. Does not exist in the decompiled version\n'.format(constant) + elif name != py_co.co_varnames[current_cell_index]: + locals_err_str += 'Local var name: {} != {}\n'.format(name, py_co.co_varnames[current_cell_index]) + current_cell_index += 1 + if len(py_co.co_cellvars) != len(pyc_co.co_cellvars): + locals_err_str += 'Differing number of cellvars: {} != {}\n'.format(len(pyc_co.co_cellvars), len(py_co.co_cellvars)) + locals_err_str += '\tExpected: {}\n\tActual: {}\n'.format(pyc_co.co_cellvars, py_co.co_cellvars) + else: + current_cell_index = 0 + # Compare all cellvar names to ensure equality + for name in pyc_co.co_cellvars: + if len(py_co.co_cellvars) < current_cell_index + 1: + locals_err_str += 'Unable to compare cellvar name {}. Does not exist in the decompiled version\n'.format(constant) + elif name != py_co.co_cellvars[current_cell_index]: + locals_err_str += 'Cellvar name: {} != {}\n'.format(name, py_co.co_cellvars[current_cell_index]) + current_cell_index += 1 + if flags_err_str or args_err_str or names_err_str or consts_err_str or locals_err_str: + err_str += '{0}\n{1}\n{0}\n'.format('='*80, pyc_co.co_name) + if flags_err_str: + err_str += flags_err_str + if args_err_str: + err_str += args_err_str + if names_err_str: + err_str += names_err_str + if consts_err_str: + err_str += consts_err_str + if locals_err_str: + err_str += locals_err_str + a = self._format_dis_lines(pyc_co) + b = self._format_dis_lines(py_co) + d = list(difflib.unified_diff(a, b)) + if any(d): + err_str += '{0}\n{1}\n{0}\nEXPECTED:\n\t{2}\n{0}\nACTUAL:\n\t{3}\n{0}\nDIFF:\n\t{4}\n{0}\n'.format('='*80, pyc_co.co_name, str.join('\n\t', a), str.join('\n\t', b), str.join('\n\t', d)) + return err_str + + def _format_dis_lines(self, co) -> List[Any]: + def _remove_line_number(s: str): + ix = s.index(' ', 5) + x = s[ix:].lstrip(' ') + return x + + def _clean_code_object_line(s: str): + # strip out any line numbers, file names, or offsets + b = Py37PythonDecompiler._CODE_OBJECT_REGEX.match(s) + if b: + return s.replace(b.group(0), f'{b.group(1)}<{b.group(2)}>') + return s + + return list( + map( + _clean_code_object_line, + map( + _remove_line_number, + filter( + None, + dis.Bytecode(co).dis().split('\n') + ) + ) + ) + ) + + # Reads the code object from a compiled Python (.pyc) file + def _get_code_obj_from_pyc(self, file_name: str) -> Any: + with open(file_name, 'rb') as file_data: + code_obj = marshal.loads(file_data.read()[16:]) + return code_obj + + +# +# The following all runs in the main "thread" +# +# Result buckets and counters for the _DecompileResultData from each thread +perfect = [] +good = [] +syntax = [] +failed = [] +timeout = [] +completed = 0 +total = 0 + +# A completed thread will issue this callback in the main thread, place the +# _DecompileResultData into a bucket depending on the returned result. +def completed_callback(result) -> bool: + global completed, total + completed += 1 + + # Write percentage complete to stdout + #print('\b\b\b\b{:3}%'.format(int(completed/total*100))) + #sys.stdout.flush() + + if result.result == 0: + perfect.append(result) + return True + elif result.result == 1: + good.append(result) + return True + elif result.result == 2: + print('syntax') + syntax.append(result) + return False + elif result.result == 3: + print('failed') + failed.append(result) + return False + else: + print('timeout') + timeout.append(result) + return False + + +def is_success(result) -> bool: + print('The result: ' + str(result.result)) + if result.result == 0: + return True + elif result.result == 1: + return True + elif result.result == 2: + return False + elif result.result == 3: + return False + else: + return False + +# Unzips the script files (.pyc) from the TS4 game executable folders into the destination folder. +def unzip_script_files(zip_folder, dest_folder): + print('Extracting Zip files from game, please wait.') + for file in ['base.zip', 'core.zip', 'simulation.zip']: + zip = zipfile.ZipFile(os.path.join(zip_folder, file)) + zip.extractall(os.path.join(dest_folder, os.path.splitext(file)[0])) + if os.name == 'posix': + # Mac location for generated.zip + generated_folder = os.path.realpath(os.path.join(zip_folder, os.path.join('..', '..' '..' '..', 'Python'))) + else: + # Windows location for generated.zip + generated_folder = os.path.realpath(os.path.join(zip_folder, '..', '..', '..', '..', 'Game', 'Bin', 'Python')) + zip = zipfile.ZipFile(os.path.join(generated_folder, 'generated.zip')) + zip.extractall(os.path.join(dest_folder, 'generated')) + + +# Setup and parse command line options, calling main() with all desired options +if __name__ == '__main__': + if sys.version_info[0] != 3 or sys.version_info[1] != 7 or sys.version_info[2] != 0: + print('Decompiler requires Python version 3.7.0 for proper results') + exit() + + # If the default decompiler is not available, override that and print a warning + if DEFAULT_DECOMPILER == S4PyDecompilationMethod.PY37DEC: + if not PY37DEC_AVAILABLE: + if UNPYC3_AVAILABLE: + print('py37dec unavailable, will use unpyc3 as default') + DECOMPILER = S4PyDecompilationMethod.UNPYC3 + else: + DECOMPILER = S4PyDecompilationMethod.PY37DEC + else: + if not UNPYC3_AVAILABLE: + if PY37DEC_AVAILABLE: + print('unpyc3 unavailable, will use py37dec as default') + DECOMPILER = S4PyDecompilationMethod.PY37DEC + else: + DECOMPILER = S4PyDecompilationMethod.UNPYC3 + if not DECOMPILER: + print('No decompiler is available, please install unpyc3 or py37dec') + exit() + + parser = argparse.ArgumentParser() + parser.add_argument('-z', nargs=1, metavar='ZIP_FOLDER', default=[GAME_ZIP_FOLDER], dest='zip_folder', help='location of installed game Zip files') + parser.add_argument('-s', nargs=1, metavar='SOURCE_FOLDER', default=[None], dest='src_folder', help='get compiled scripts from folder instead of Zip files') + parser.add_argument('-d', nargs=1, metavar='DEST_FOLDER', default=[DEFAULT_PY_DESTINATION_FOLDER], dest='dest_folder', help='destination folder for decompilaed files') + parser.add_argument('-S', action='store_true', dest='split_result_folders', help='create subfolders of DEST_FOLDER by result') + parser.add_argument('-p', action='store_true', dest='prefix_filenames', help='prefix output filenames with [RESULT]') + parser.add_argument('-r', nargs='?', metavar='FILENAME', default=argparse.SUPPRESS, dest='results_file', help='create CSV file containing results for decompiled files') + parser.add_argument('-L', nargs='?', type=int, metavar='N', default=argparse.SUPPRESS, dest='large_codeobjects_threshold', help='code objects with >N bytes will not be analyzed') + parser.add_argument('-c', nargs=1, metavar='none|detail', choices=['none', 'detail'], default=argparse.SUPPRESS, dest='comment_style', help='prefix decompiled files with test results comment (default brief)') + if UNPYC3_AVAILABLE: + parser.add_argument('-U', action='store_true', dest='use_unpyc3', help='use unpyc3 for decompilation') + if PY37DEC_AVAILABLE: + parser.add_argument('-P', action='store_true', dest='use_py37dec', help='use py37dec for decompilation') + parser.add_argument('-T', nargs=1, type=int, metavar='SEC', default=[5], dest='py37dec_timeout', help='py37dec only: override timeout in seconds (0=no limit, default 5)') + + args = parser.parse_args() + if hasattr(args, 'use_unpyc3') and hasattr(args, 'use_py37dec') and args.use_unpyc3 and args.use_py37dec: + parser.print_help() + print('\n-U and -P options conflict, please use only one') + exit() + if hasattr(args, 'use_unpyc3') and args.use_unpyc3: + DECOMPILER = S4PyDecompilationMethod.UNPYC3 + if hasattr(args, 'use_py37dec') and args.use_py37dec: + DECOMPILER = S4PyDecompilationMethod.PY37DEC + if hasattr(args, 'results_file'): + if args.results_file is None: + args.results_file = 'results.csv' + else: + args.results_file = None + if hasattr(args, 'large_codeobjects_threshold'): + if args.large_codeobjects_threshold is None: + args.large_codeobjects_threshold = 10000 + else: + args.large_codeobjects_threshold = None + comment_style = 1 + if hasattr(args, 'comment_style'): + if args.comment_style[0] == 'none': + comment_style = 0 + else: + comment_style = 2 + if not hasattr(args, 'py37dec_timeout'): + args.py37dec_timeout = [0] + if args.src_folder[0] is None: + unzip_script_files(args.zip_folder[0], args.dest_folder[0]) + args.src_folder[0] = args.dest_folder[0] + Py37PythonDecompiler().decompile( + args.src_folder[0], + args.dest_folder[0], + prefix_filenames=args.prefix_filenames, + results_file=args.results_file, + large_codeobjects_threshold=args.large_codeobjects_threshold, + comment_style=comment_style, + py37dec_timeout=args.py37dec_timeout[0], + split_result_folders=args.split_result_folders + ) diff --git a/Utilities/py37_execute_decompile.exe b/Utilities/py37_execute_decompile.exe new file mode 100644 index 0000000000000000000000000000000000000000..a593a6b50c0a118843f05d67d203f5fc37747779 GIT binary patch literal 4238336 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%0Arhbcl%+(if;ATYd%`p9b~g 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

tftRHqGz=;=n) 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 GeaIVl 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

VvZIJNf8tS-4d`YLSKO2!}0-GJ@B6_`@} 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%0ANh4>J3JVR@rLLCQL%~+X_ft8Cf1|{X(l1bHwu-q zY+c!YQkJSGDLeauG|$4JZ0tDKiH5QBE*MWhDsC=BDt3-g-!gs*jX^4&ifRI}t7wP- zLI-dbX+WGsdWJfq!F(2Jh%&L^c+e)clqSe)r^F^z80$IXf|%`LxBN^`!TnNrfb4*} z6^KGmMbd7d3(p4B_aykBkMFIogEF{upmBI&=R&!ib%xs7Fjg8ym$Ac3osn=Tk+3uO z(Iv0#@IKn~Z?Gejc4DKI0qA4_p_8%EG976ff~%3(s3mO(ciG--bRN+Mb`3^n_~@{M zx=CJ;>!W^K>8i$`rLXN7s94E{xdMK8&TpS4egm=T{8j|91@YTm|6=y)@VD&knzWVd z4r-T!Gm4>T!XV%p4wOrrNerP0<#HM+mpD%lS|*gswsw*C=g|m67%7@iE<3qF5G3U? z#+A!yWE|*7jp2|bg!1GUJ&W&zu0>82A)pj>BW5~R=cLD$O+Cxh7b5+x^?198`POfi zNnCT4GRejgfy^nu5@9mBFv+$4RpKroxjvI7xwbo{1@YULh|rIIf6sa4Bhufihl`Sx zl4+Ru+41bX8?{16)UacTx?7q=-R?~)XdayKGLyT_7iN{a29BoTw>wh& zpDt>j$}eH1z}AJbcG63dB}qyz9feC}6?3Vm^Ug6VflBPsidkyiC2aBTHOt#RvZeYH zEX1+ScP9x~v-6~KLMgK&b z#6n(0Y^T`N3L{>N&g)=c;_2%W<@X zowI^J?C+l9FHT#3Y|ZLR;TN4VQM>Rjj^jf8U*q+bIInj2tAs;1jSD^eQ-rNWs7?J% zqMg)G{7aAL3BmW=SOwL-TIt+$#UTL|$kq!=?8mUvSnLKJDsm=~ds5XDbav)bT`VWCE=s8;x0O%=Zj za!wolcIx4p8!vHb(HO%6U4q`Mahb9D5d>AvJ`zC4NZ8K+pj>gG{pa)cJB zuP=(AXZP{5H-7b6G4{q`3z)qTpTheutG*vI*&9PaCg^k78;YpUslDON_x(Kf#?YCZ zek?_$vNsfrJ&WZDK?O@Fu?s4cHS3K?o-TBP#olm-_^l%CjsA1dt;O3Lmt2yjEo|w2&Q4)(jGV#yBai+_5#UUP#B#ggddp6VgtcuRYFlaT4Sx}ITJ4RmsU>7j92J8wfrj9+O(2)WFmhRp zAeTiFxhzr$-k`6s9X@{rK1n;JT*F`H^AM6Fn55XceDA5D<+_f9F zA^n0PIg%7WyA~fnPg0VBIPSBzI=cXf5#`!)*TQyTaZrz1Z4ximWPSvT@HL~s-66wX6hfgxh9 zc58ND{{>`y#ORknm2(ZoUR(cd+GHQ37|)P9h&?*QFN~kDGkDt9vBQ1~-(f!wuqQ6~ z4*MmnmRr~so=~g_IV)cF#Jt!yh<+Ksf5u+VpP1ViQg`DyD-ir{+F?(Zh zowgGuA)-1lyMRY;SZrcFGIvw72$RwsM^eKW{T+Z3Fg*IBX(Mt5^3-=OHgul}9iTY67qO%hjBa;H==Qp>YS>8WV?Z~L z|LOSx?;jgEZOEdf;QJhM`p>(u1}8J*^pDIk%#^*xET@0L5>~h>1s#RUX+Kyi8zed_ zKJadl%q<1Rh}h5?C)5xnJ-gk(A@=_X_=aPwGwNn@GO}zl|_Q`rgRLLc67+tR7+cwSO<%d zi`~eBFwt&uZ{b^TtriTnUV zC**s-b$@!-4V_iI+jjftQFLqQ$Ltp0%Ri0pagRqF)~A^2`vtGh{R2~dU!F(`>#TT< zsL%UNPN&q1bbdtpX7l!?x~a|#e_7i?s%PZ*JnaN7KNEaS%-Rm&1$NHdCx0+>B+y#e z#z0C}7p)J=T`|}m!*|8Bh+Q#!?=@|SiLjZ;x5O~*h+8YzvmNNzvdir6W6l{iksEnj zXh4YB2l;%nZli|UV%>n6V;glGU#B^>MQfyd5?uMl=DDEyoHmK>INcx$YmBD{fHlU` z1B7LI0JM^)2cRwGytyp@;7sV2Mh<|pX&30ZY%Z}KjUh-9&_l~K+qci=z1V(ETfSuu z!RTTi)yaalv86i|RA10k%B8?}i^>pogc6$flGUrN=ce!P5Axk)GiKY9z@o+T(187F zoB(MEYAzzAFwRNexQ}k-8~4$zeB*vtZrsnoJlBfd`QV=u(`5Glu_4XeH!9g+vv$_I zCN@|`Z182=3B`U&8}i^d4J_S)4SCC0ME_)U+GOu(3tkz8nHE^El(Hm*AQNXzR)aj5 zgOKmb4VGj)3x0!4wC;)4DDj`Y>cr&Llt10b}Z+#pqbN(qSZO8{TX{9Jrs}bJv%dx}Ima%D@ET>gSU*!_wbcY;zJ5!5=PKxYC+4bT~o%H+2K{0M>y(ji6 zZTQkv`yyLPo3_~T^Vu7kW&m^{jRkNIun1UYK3J#C4fY@xM3r_d3_cOxK5!K0zY^n< z!>wdWI>je%+jz93r&iFj`}pCL*F0JbKDk#D!zUw0^8U+;55`RKki%`vz|MtF){6R^ z;*+j?-_L_j4jjShhqjV8FaML=(Q3%0Ki~!&24lb{IV=f$@)lnN6v)*4VVRnrgC!z0 ze-oIB6yYKJK+A6QF3l071eS(XN6pv zRO8wByBET#i=4>*pn5;0;-@m8%lipsq;eD7iV>DH8HFw?0KIIBQvv8@8}Q6lLND8T z$Z%uLRNH!~%$*%=eLyq&c|d0)P|da>pqUAvnZrOcfoe7a)tpJFCIQ9FhxI$=bYgn2 zyNZwB{tGkm!W(+<&(O6PCxL6$vQcBX?#;L+HNU0Zz%}W*5L}Z%e1@HZw=r0m&}I+r zTcFL6vvicwi>F$`xc1ZaAg;;r*1UkmfgQVCsXcXz{u1?ocDwOX16}{ZxMr1fSgz-Y zN)sJ=rGD)vmP*euUSgD;YPtR_uOv0XI7FW1Y~Z2C81>QnXoR=jWU5I(ti-f?P&oF0~x$(L7;BP0N@3QwwzEooCzV7ta6_TM564BiCla)1WJH z0)b7wbRUC8{VsRWbX%dTL3_H7vZK4H=)B|KXV9qM)o@s`{cWM!+dtoSLR~zWtV2y_8Q2TPqWP|mWf-j`E(h>7+qmO$C&0*@8!0v6{*iQpRfQ~ zCR6@A{)c+G^hldbbIdKxHJKKReE2Pg6g$4wJpSP;Y#SY|vzbp{fEo+B%^Cy zGF+6!>)5SN?R-8Zi<(cz@jU)sK}S*Z$xn+-?)>9@2k~}V^(q~I18#OZIsMH`&PnY2 zf?Rm;@Fmo_nRqZdY|MCYKU*3Z9!$kC9|6@DfuyzVkMCez zAAj6h@+C3Np<}lJu;&3M2K$=KE657#pXFH|+yoycv*A&oj8APsAJNmED(cNS8}2x3QICzIYK z6Wt>~hR*(qv(_g9IQ=ZjpCL0+E%a^jbce3_b! z(NEOnYlU!NXbQu;3QUyWLroo1utsjCzt2Zsu;KgfQJ33Ca})<>vG0(hRQoEW;1^kv zIp6;uOUmC?1%GI@{n-I^K0msli9%K2IxjSuqX532f3Csv8ELtBelFUqm2c2>);*V{ z^kSJP2co%yB!XlM59cYdp6d=(x&=$NX0`0EAHey zbr6F-xAB;U9oAEEO1%$-2K_beIlmna=39jFi6pg@?a*1;Zx$s|(zM?W$)#-k@e#MZ zz6-m}@TcxEPWYA&=p~udIR@9t(|5Ir~Yr7MxXT@|#>&r+M|Nlp? zA4n~cOT|v!>)%C&<|4$T=LTso$00s1uiV|}S$r`~0(0tbgzn{$yZ=Ov{IS`K{3N#w+ZItT@;Go? z+g8d|2vu&n=Cc!|ad;e2yt7#TOGQ|W2$W_mEx0QLd$OKzXyzX?485SXg7YVZnE+p8 z|L8AVTI@P4pYhM;INtBy!glMrTqTaDsp%#cm(zHfvxoF}nh~*|b@%a$r#bDWV&Z8Y z{yf7MY6QKG;%RDbWRAaF@iZgbKF7w^X*^Az_ID$|Wp#6<0 z#F6#0Sd^RLlqTqcZQrayE44%ZPmj#-()Ave>&>450tUBjGd^RN&-mR-@jfN~MSd~Y z%`zaxVLoHmhkU%ZSAMbX4|x67yh9+kN?+HC%x7GM#-d+qw0Dk6>p^scJAMnHiKcwU z(PPnzJ3gOr*H+#iW63X8d#j~w_Z&kQX-V@L4{s@)PHQ;Ju$9h<8FY?0zgX?q>GTf# zlIE`|zu1LGlWdJ(GP)9*c|Yu^{9;Yw`+4|9Mie>DXY3O7I>|2JXGC%dV9UfQCXPheM7enfrhH`!}(^;7RlljF4|HI{pBYWd;0M|lZ z=ZoKWiF!+HZ}j|zM4D53jOQ-pCKULl~C zQ2L;{3@dBAwvS8%pt3MQ5Jr!b0x0xQ0rB@Z7zPCd-`DrSI_ZaXG5`&E5P@AouwIb3 zh^GZJSuAm8vFw4d)h!l3`bzswm9B4-S3o=8a(xD_L5?eakFZ#xGpn^Tf0+K#k;Y5R z?Agz9y$i1-)y3K*W5vCC?yN08(9NEf)b9+lr-g#>D`i{^$YcL3`NiVyBeeE9_8|*Y!OqII1~xa>5fkaz8eM2GC?9)G-8*LXR@nLx9ccx6p;!7m+}N=h10; zoA+aElnY4NkLWhU#msDGUDvUKl5dH8%>E5mTO!Px@3QpC6^HNu;0Tc|$vq8S2vW`D z&V3+1sZkOC|5o92S~H?~@3zqSLZuCzvv|yIp>(ci0q`#O*y;2pK_~2`7VsD)c*FTG zpi`dz@+R*GPq-4Do5uGBemJ1VkB3^o_wD*lj3Y3}7=xjVNY_hk*+v}pwO~aAU(zaQ zUqZF`eja{FillVXUXs&i@b}cTHe>osJD8i+kmYS|k%?uVuK`EbU5Fe%qddn?7;^y^ zJQdyDpoRR)L{l(!I#SUs^~4^8pOhMg|KwblyD*Kp6r5caYxQlW-IpZ6;h`mIq8-OJ z0Js`9IO8vcj-y1rJ=CzlYLB=4!P2<72N8c+NZk$M-b!lvJjh0B1W~!YZxl|abskjy z(L(1l2inj%6-#$>4|r-V~$LG!KpionjvJXj$ihWB|{i5B0cj%RD#EtA&gB{$;q9`nYr36}xYY`37MA~ZTBl?lsa;vDZM-Yr z`|uOgLLtNZsTPtmc7B3;Sez=`&sUqTz6u_n+W=KWr-g!6czo{25_X%%=MI6Rq~0+6 zI&bGbl@rhAODci?G%v0 zYR*IQppo(fOIXd*!b#@`XQ?yJ_mUt=Q2b!Xf+yK#-I19vBIp*8XK9OeImK$r{7J~7 z8&KB%!*m3t253X%hwsOhv3Cv6ra?#P`q?usgvq_&>-r= zlynQd#q%biw|L$p$ozSD-Z8q%>~_pXWBu|{V?`7u>o;Q?C&wRi^c!S4sfyTvze<6A zg++9Yf?c(I?`x9hIpN`I+NY^K_hd)?a3XNoD0%`i>e5t_KfQiv{+`?w_+ z@&s8#mYgYQN>D{mW+J3MA3~Z6M0eA8^6q|+g}#sS$i539Yi6nQ8piTfLYq0SXa8s& zeRL=5h&~qCKF%F+3j65FA~~Y4L{g4f;tmRrkIi8xHa8&VrnLoX?@E@95(hU|n#s#i~Q^4 zo2GhA{^=p+pWX#`VI&-glq8_Ka>Qz-^I1>lFs@-z4EY}=lfo%J z@zuL^d?K+@sH_XpJp@T%CQ;}b222$}vr%$IsyG$+=0WBzB%oc(EM{+_M zDKH%Aex~F??dWZ~Wrj4wCLElr6@7&5$4L(&HFEYMxsXTz#BmUwX{hgMvb?c{n>oxn zThKG?1YAXBn`5cm0KgzZ1?*C*@1g=0<@z`k;N`3DrUHzx`W`AkeXsAOtwGdOl>6Wd z>_48un=ygN7b~ zzWe|jWs229f~yEs z=t!O()S`V1jyjIx#Q(;}-BJFD6tkj*7rWDf=J=nm?cKXakItn2!^1PEH|00c;imv} zU<>8bM82TJbH&na&2N&jr+ecz8@eC*M6q<=BJu@Qm5Off$O`IjwksdpOv8$~?A1;I z-B|DXpXL2?KqMpoR)ap@K0s%}?yAIm;}eZnBlBt9jjcI{m1of$^Nh-s zFX$1GFUY^95Wd7|wE>9=S@Q+OSJ^gt`Ugj2*ts+aKpF%H#@g@T4BAceDHq+l3A($6 zily5+pOiscx^LfVL-!j+=ids7d_hCcl!$I`?UT0iX~PyapPI#YZ03{Ue}0#MhwSqy zDiFM)=F@cewlSZEpDv)i+2&K#YTF@lp{dq+)KKs|y4}lo(G0127G36a9<{=^PIg@C zuLZO-Esvdb9wqD>yZ>ezetd#s_-5K2&Z9@*aw59@MbmAaNAag@2WfiBhVGG~^KR`X z=bjU>k6uj zYn?}aT5z(Wv9uhyYDN84ebmW&LtHfhBpzX+`lv>T{%lbZW$=?fHGEAC) z9WLp?8Z7cU_2#Qj;IYFrdXg3ckL?|1w>ci`!ufp?k8Q|XuV>*Ff>hAX7MN0^?zTmO zE^of~(at^?+;~6Lhn2;)opYhbi24Se%+qh8or4A~o=&5kH7}al*~8M)ay_|O)VtsC z01dCP|2eylTun)`^kqU{Fp;wEPv)*m+pYNd zwv3V|unt*qenF4{$2TcaOc#cvz#K>0l}vqSt8k8J>sfl1f)La6?s(Y z%>1Q+#Q3qZMadw=_=$8z%vq!-@QR?bC`T>n)09cZbLCyE^n_sehe?Z$5ByoCx?VooOJz z2Yq~Rr3^tbl;K<`eWgtX=7fYpi%e29Zhdr#Irq?x>7z}^K~h9=8`(vsgIAd_fx=f> zHad^!6A8d5c*a=*uul`e=?QDbK&;SVow58~$SnhVb>tCyy9P4FSjq07c9kHG25<#1 z7=BJ%*mO=DluLF_94VSmE=B$?cJ>K}Qz!sOcgT{`NtwXzgsufLjZ9!0G1FP-9w0le zy0fmZOnv@Dy9@b+ijhhEW|_n-5y?!@T+){)-_| zw|kQcng=Jm%;av%lB{yqu$DFac8AMd618t*v4E)U6S^Qvx|mPGN`b8lW$mPwBukQ% zPK$s($9ps#5e$aK3Bf%6x$Y7ciQH?Jw|!);_DkVLkqu8Y{$Kd4U}Adbn-!sTXie-g7DY~(aObrnihLD|BHx_{kq;w?JVnh$ z47r#-bc#a8^cl|vI-fp2SPN1;bk6ed-CT|%5|71h;t%^r`6eI^&+gRxiWR4Qo+Jj7q4f*t&rwb#-Z;|ydSdD>FIRSSAcuCG}$lsA`Y9u&Uo|(D6g+YFQ*v!e_`a$ ziZ^Ae7e~wD-Hum)(QK}0J@R4M2Px`wd4f$XtBd0^XCk|3Sfh_?4_e!v*NvdydTc} z!x4DVcDxQpBi;I#4ZmxQ*%EignEi|hjp1m-XvnYZ>SiSEil5;gcnYzwyH>Ihdksuy zA~VQGjK0K2?OGHmsBGln_`kp`{QPe)Jnn87VgG-X{r?~A|If4k(>{y-4XfGzpJ4xg zjQzhK{~y`#XZHW!kNFQY%-AcVlAAL_2G+sz*!?N&# zeDt&|tdNCAWZ_<3NNRVN8h?i-kC3d+$swf%SYdog|Ep%gDjlE3rX!% zS@?o{^ch(=N)`^4g?)J;skvog6q{LD+c(L=Te9#kS$L5blG?Mf@T7b+APY-m;g7QL zTV6Y z%185LVU8?(PZqwx3rVd>7S5KBCdZHuwFh|Cktz2VNezx=Y^#9fGqq$KKhL;+$;+}mj#s{|qrb?) za#?st7XHKwNv&5FZj+C$mxY)tER==Icp<6HmWA)iM`2kwUlz`ig?e5{YG0Ox6Xl~% z%fb=7(5F?(f`=D+vDtMtsOCfd!ozSDbBMYy|!asQ-sr^kBp5lcOZJ8`QC<}eE@H<{`Yrm9*>v*A0 zTPzD5ywIavDhog6g@o2D3m5XjkanIdgk+&k7Ea*>w|0UodzY!-2^7`7b z99vY=dlB{t6{jInA5$py(xi{o;@YI>r0Zk4RyDZE(5eEv5&1%&cI)&bTN3_d>eFox zrD=+{(fY|1u&`9X?jvfs0#+*(upZnq(IpfxrhIANBmD!aBEDC%5xY2QZe%JLU27Mu zWASrD3;iQ{=%3QDo{ST>ZWxR}dDbrY8+1&jZ~O0%<6yLd_Fn}SJVCz{I{(~dfmI8A zRcHe9;zaA)1L{IwHLmG?4gPXp&SKvYbWdIEs};}ure`OJXNq`6s)>B>bn&c7JPVti zohzO-i)SsSXQc4Z_u9p?2>z0z6HMTy`(5IG9Dn7vaKIzV#SnW(TqKlT8ymbSS^O zEhjIqS59sut|G&bI~QnBQekWoRHD~WLnu>>dVr5Uo_q}v$I(!GC{~AdQ*sl;Os&*5 zzrGtxM#F%uz_;TgzvAEBYciyW_^$M4RHo!QVdu}lHmdq2tQT#c(Pb91i|=}d?Bckn zH#(VBYa@3}evHb^hV-`aW1NA0u=iuUkfJAsALB7xn}l+9KgRALlF8MP9^U@!bb2~d zXae~$`iV?71lj!$ zckmBc$LDZbkMtF`=>ubo=3=+5WkEMBo4ViPKqATFw@BG8oAf2=w?G2M@D{mfQWnPJ zp97zADs!xtw2NE&>|f=2=@spZo@caAte5mlIi=Wo=>~s^^%Am@%W0CmmAKF4;bPw& zG#9ZxkesGx)uv~Mif1+AS*__A1sl+NB&+E?1%J7u;_DvCX}aHpzw%p@+koC7SxwKH zP0zkAo{_AkXYKfFtY1N2gxJ4}zCbJ2CG6MJd~v$l&Fi1$Q%Q{W(5>FeJBX#ZV8#Bh zMhNg}zJ3%Sz^C~JP=Ju1Mq>F|-gz>=pOc*N`Vf_79(}i&>`>@~DbPNCP?mR7;AvdWJA5!hc z5|Hj+u7W(SCVBjEl0RNiPp8;epQ-nnm8>2&p~@Fb9)-vZ7+Y1pq&pU`Rm4Y zR{4v;ul8>tyD-5KEXAn5xOX%T~TYpC}|>RM6(gFXcOhcFLd+T zgRyiCwaUcOZWBxY9V}g=U4N6rFWSXAZypz-+r-zW8+yi*B<}6_n$%rdlG^cQov&d; ztVn6EHXFSCkXhH*cMx(k6&L&kBZ>Y|zghVjhj$uGM%|NYxPiK-vD(Df4PZtn8C4d( zzV_vGzP@D@w@<@Aj@*fNE$tzFZ0ecV^UD^WGg?XI(q_MLx8fN5k z{u;Pmjz7&-&cCc5D7~~DE){3}kk1dYmE1MsrcDIIfKge{5a>PT* zf5cbxFT)Sgk8#w_LqdN(4z<^baWJ)mS_D4`{Zfj4rq?x~2}1fqR71zYHR()Y{FS=a zIdl)YRlV+*Z$WkP1!l3YSKKEdF26;1 z64B8wo|%0Xe-h6I#j_#&mEYo4bh_U{=!01C7N_|v__uQVEZ$|`y4FWJG4+)ff9YGW zG9%Q@7MBGl<62?A+q*4}q^fM(7FbYP=su~$^eIw>WqsTQknXmS&nOm}-Xpb`-Xm35 zKKrJ4Mrtu}Wu)mRY~_MiU>f->n5j%@}Tz@9rxJD`x?hHjjG5IWLqL_3ETc5@I zKO~<8jfboH=l1i#q)(Xq7C*}7xA=eTeF>ZsMfQIXgoww)lXw!CQKPOJbzS4J8ZHe2 zI^Lt8j=JLLx*CCz5s!@=G9#ezSRHj;$9p^(@rulfBOZ(wM!e!3!6Pjm@s6nQf3L2t z?ygF@!>k|p{D1TLC`qUL)wkYz^{rR0jy{&*~!|g6Azr-|*a1EKY8} zikAPfAJIs>xM)P7-p~0}&L2RYS@gR&|BwA{W5n9$jtB9yy~mmS#nm?Xg14kNwthX6 z{S2Vxwu9wOq158^txvqr!}iu}8u=z#S*5z>!gW3Yt_WU?BfH)p@o z7sCZ9|Nd2}eh1b+u(--~xK>&N;VywlR(AfL<@mU~44CZNB*VgE`94V?7+@~UQ zU@YKDZ$ysrDE~RhoHAe!5IJXf&aKVZK2z!A3B42EMka?2g)(_PXYw$9z|;niEMxJd zGK+6Q6v0@Wb~}W{kFJ@D4Vl>>$nX%;&VC1lLl;8Eg2d+}{)Wg-H^-F5kmE${~zLgkQBc)mGee0YMBw?pXdaBBocTgJNcx97QFl865B z3C3foODV2?cp3iqI1L(UsXX*?#0*hsd>DqY3XBgUw(;Sl*R12ii%7vSU;Qjvt}5@5 z+KBU|+>gMrHnOfRWXXF3nH+h1Z5ywc>*vA&lZ!m%J)VSJ3G$fg4)|{GFU0yeP%=sTF!gK!5I~KkAE+= z`t==;VS|eKnw#~0-LSEHzm73Evi`Jw?c20MzkdBgt6$HD?om}1gp^xZ* z#r+kmgU-ATs*vLTF8D5~!kTZARWbh|Xv3+tX;crc*Fgscm^M@7303Q$tKS8PwsAmT zxF*4Ljss+cPfs|F>QW#)&vq7Z*@|bR&IL$m~9${MgO=rBr=Rxara&_@e0hP`BO>MlRUoSNe z`zR^ixxv~$S^G_x|D8hZ?s~mc^B~hkF4s$KXm*=opI0HH>NX*fB(IlB4dk6BuAk}k zAowXuE0FvRes<(J$$F`kck})-cLA;6|E-t8WS@4uRA}X4;L?BSdMPxnM9R+fQV+eq z65dDIq_&@wUy=B@?0TtgC{*xq)VShc4Ie*wC*y^NzcXI+v|g(FSE5dNy;NZvLdN#> zQU^R~CF9|wV0cf=WLBk)KHaQe%~qRjUBSo0wd2qAUa|6V z;blu}*YoiR07=%bhRfnK`M9Zu>q9^Oq6Vhe0*NJYd${bHqOVjlbHT(>mOmA z!~d;cMT(~DSCgOq;e3q7Ey>51E&x7GO;FpfLO!m8LM1+48Po9bu5FAL;-}N{*Z0K7 z;bjg!P6CNSaBSz}`yaRR@guij!7*Pei_2B>ICWvpKPo;BS>|zSnH*R7?!r!H+x9e% zbJQX$|LzChCDO6-FV5rmpd>z{95${eEKKs1W#cU}k8{O;c>7KysC{~99w+b)8m`iL z9ITb((u#SUxhvWE8|iZ?ZrLujai5oYoG7&%-6uomaRwh~`nF{r=ZKquM{}pp^4Ik= zkCT3j__aKb698vaOr#R#IXRUr7gYQ~Dm&bh{+{E~#>mRiKdYopQkwcg+$9)Ytxw<$bkIG(+ao+*Y zSmTUp_%5l!9%po)P3!GC&PeWV+Q?;`as5JPoG}HiNwCy$M)R&F8`T->0r$Hc_w~Jz z^H83}?f*CKD>?21#b|C z?%j)*y6{qW+kL3D5s-I>9VJmE4o46E@p2WlpNe8>xMMAd9m)07qvMYDBsbv;O9Ksjfd0z@!?A_~SruAF#7x56bPG*7)Oc_)ZL7?!2)R zuVHqImBnesAN6~4z3@DTetm8JZ&bgI`s>!$HV_@STwfb=uCKjpzBT^%2Yi=QVUIuJ z4ByL3wDz&Cuk}Su8&%!kcmOB3M|3!{JT7a6%^99K}Uv?GuzlPJ8 z{?9b)$9TL{o&$JnI@z0myc-0+qYU~#*{2I6G+WU(%w~Oq=Y6`c5Y_WO-RL#6!^9v3 z7qh~0Q@T$VIs>{-w-!IR-KQJV??r%~i}Vn6Xk01&kQcJjeY!`Ch5n(PjmJjW>{ns@ z5raZS{1Gv>h&ba9GLRl|CF6xKD<9TklRxA~;y=l$+{$ea9>kDg7jg_$hewMaeBs>cQ}lh%eM#8f1ZB@ zZx3~>KkH-Pw+npV1|^o}`w-{*5I?`i&*Y6@3KIQ?ir=IAo7|zuqa3Q`_c@PR`F#?6 zm)OIZM~UxeGDp}roUnY7T9E!9apIq2-inz2;5l4hVb*^?FX_u}f6G2#5Td7dG}9d z+u?Z>;%w{92A+-`Ld%!qXD~0uD+T}eDnEm6UF_R2_seecxD;9u@%PRG+oVz_Qu!O; z!L0Bn{0`)24p7O5xnUun?+dD$F&&<@#zlt``4J|6ag>NRSfxt91obkYJ^WYb09(r^5E;Su% zJRqlLhF*?(4l}&3HtO^+X=|h-vGOZ;AmSx^h$q@M1zm?A>E7Hh-+OcML*$y}?9qC- zCP8$>2Cc9@BsG@WfAM~LTmn-n#xYgRI0_oF4Od^vJJ18!_ieq>!Iek%Z9M|tC1iwm z#J(+X?L-&Up6729#@j%^B^*;%~LmZ*<4XY{&Ud;A{{h!M;}ZOhS6*6ubt% zp`W6*l7V`{dJWhC!Y0Wv5KD~49g<_}@dNCu8B>QJ+TcS1Kfn%2N|6wXj3MC+?2epW zb0m>F8h1y|W_uvvdypR(WCcvYGQH+1`IGHhQ>k+v3^pAH$9?Pzl90vz|% ze~g|>4vk*2q6peFk5{_wGHjpCb$TAm4uOXq<2ScFIF!f_Gx-j_Qt)8&P+nen9?Tra z{M*j2Ivz}7Wmba+3-|M;OwVC{8@@|TSt25w~pYLJo4a`_i^P>9y}kuOUiTdU^mp>M>dALFdw zTFZlN!`65nM8lQj!RnR2K%JX3NkxY+nd9WEPvl=`&?{40dDG%NN z-=(Ik=fORbsOKQV>zW6{am4GI2YVqr8xMYRmj$Ad2a`uQ{ZY$&hgE9SvHiTogw?}i6kNAvQ^^I+E) zrbo9tn8M1e1`kfUjW=b=gJa>lD<0hWLez7B;dRY}kuk)wI9cLmT>Q+fP9D4qu1OG; zJlHha>5p0-Y(Jc1^2mdmB07>(pgg#u&4SFygITD($%9Y*(<2W)b^+(X)=|#-t+hPZ z)qjoWK{Q-R9^9*w@SyKdwOuOY!N6g}GdT~Q6SVPQY#IJe;=%dLtvq=7WNe>_kra=L z2Me|EaK${hGm#%)^4;)Y+Y!9H@;sQ1Gd;TH!B(uyYVhD+Zstvy^5C}cT_PEMJUIA# z)U%)AbLeDfx*Jj#Rrh3^tF zClBVJ_9hQLKE)#sJ~)Z*?bonN9S&^7{M;IvA4J2IM|{H8V@%$Ynm58gW>=Le@w!1md|@ThpOcnk=ymtsJ6|dC zgYC!i^2+mI$1smP*oKu^4IV6B&zmyk!H?j()Rgr+xD}ke5A(1LuWKHR9Y-wdHXb|# z;n~K;J6jbbpR6OV#3lCS!gIf{#K3-oJJlG-1E6;=N2YTee_7hMOZ2edT^TqS8=1rOM z;H~goYRY;Z+~jQ3bMdbfuWKHRk0X|K%Y*A7JR1*wd6fmCk_YPR=8HQ{Mom=CgBQ)=O_}oGY4F_@5B5I;^<0R0enSfMQc0{qTx#N;Cq`A9?VA6cBzmDqfjhl(>V_wys8G7 zi@pbvtRMUge<$(a)k~~AcmKI06JiU)&d!NV2v;5tNpes}jg*e%K{&x0wQTpbT~ zor#*LoCkf=cvGf4`1w>zQ`Ym~igBpt+-@Fuu>SAFvTozS!vT(cT)d|hqLK&W43{e& z%>IL8^2md?T*{S4dGIp$UXlm>XUjZzi@pc*616K4T1ziU&jI!owBw;EFoZ z{&#lIgBej?c^+)m$<^^-_c^GE%6V|%#k?s~9=r#>OHEnNgWny8ddTkNkp~+R#IkOA zaASmL%Mbo=kp-fX2V)GED;~^E;Fvt};30$ei(D;5?ZJXF^xvXe!N2@yLF9(kp~lvoO4`_i(jAY3LjvbX@#0e3y_pc`$UL%!8AmEAhmG=fJu5^jx0W?bPjUt>nQ>|23Wm(QqYs@Ygwn z2h-cA?NT8R)Ly!&jfJj#Pt!1t0o7*5JOcrJ7$o_KKlA)E)}TdLdJTFHa; zUyp_cxkj&}M#Gil!D(j`9_$#Pwo8RPSP#WYJhy8a7%<|%Mbo`h6SRM2SW^(D<1UCU_m95Z9}zP zD&)Zg6f5!IM(^8ru*>AZ6XsfZaOeH8eFhjF6%W?VSsfmHaX-@jH*n8`zAJcn<$179 zCs)UVMbd^V=fT5H;!T z98THWq*KyB-fmU8#c^-`GXK_A2AiU&hCaZDb0@Vq0r z@+c41!FNe{&Umo)2AKyBfv&_84<5K1=fRLq-QLzp9*oql@jQrzE6IbqJV$u2dF5{8 z0Cd^!@cfGkd9WFZm3Z){mu)=QX7b?BHY*Qq0`CKW{r|sHJSrY+_%{fzm^2mdGAv!5PxRn)|lLzbmBlF-v(3N=N!N2Up zc`&G`-&%X#OxLhAo(IuzC3*1S+X)XQe{uTVYVcqRij{cq>qRymjD3Z_lX!5yo2)$8 zAI|WH{r^Qh4<>Gfhb!j6dv_r1pUHQ_gQ44adF6R9s*|hZ!5~&{CQ+8x(;9z?^H&!RdFa!Go<( zti*$#Ewu4q&g8*8ue0*tI&g+R?En8>&x1{Of$)lX@U}su{WJM)crbi7FRwfgMs#v@ zJQ%{ttOgGThx4XPb)8x$+?;D=Azcrf`j{!Ze-ov*U;;EHXqedfN_^I-Bmc(`I7yphOH zGWl+JFmgXHuRITib#iq)7{^ z6T-9c;09KRN*>I8>GVe}560$lOdfggg1>U*Q68*^?~?MI@nGTsnFn`-uEY}$ZnqWZ zL7$?2Yb_5Zz8(b)a*bX`jfN}9gQE^2JlODs)9+S;2iu`oi3i_G+juba4gOAeaPVv^ z4}LcQ+h^9$^I&raJX|pkUQOgTG5KzIF!~TLuRITibaHh(7{SV{1`qywU*41{4^D&c zQd8FR;N@GOo)dYGJeWacxaYy;Q6~>BhHDZ;B@bplclx822jh=$Odfe~e?%wc2M1e` zIeD;Yp3H*-p)2vkgIjFQd9e7IvwmwW5Bip@@jQrzE6IbeZ%cTv{!_JGDx4?jfMO*c zT>P+&2fIuj+-jzk2fx?^+h^tzibpk1l6n+`SImQ#6Zr`y-whAO9^>Ve=fR*(u8s$z zSeez}!IS>Xn=<9W5%66i89fh9-5B-Uu#D>2^*l)ymEoQTAK1&ugDJQsK~(Z!W~tL3 zwLDn+1jpo&2Y=s_E04y5pTKtsnUe>TkIOtb0J;)SJh)MS^I+j)XZ_Y%9!x#D#`7Q= zt|SkR{cQ!Vo2kpG?NT8RrlDAg2cLh?#)I_*{GG&un@qLx;L;7TeRh9D@u+yPbv`^? zF%M29@*9|ZH#`{c@&dmcP@HzyAs1J@*oN*?U~!0C@#9;{oyF?r;{=XT}FqdYhlzDvlQJlOnSnFp(& zEAhmGeb?tan1A0{zqOVJLpQAPJcx!X$%D(@B|KRBp4u)I@?aMfEAilhdu%-D`xbvE zJlOwYD-XWw$M)IvF2$qb!M3O1;fi^13XxyWrZ#hr z-Vo->qdYhbzDvq;@?h#|nFsqpSK^5WSFX!>F!#2zerqicc3iZ^^B@|oBoF@m3BrT% zx72p2kO#Y=ScwN8yTitVZ6*({(g$ouJjqnxVSL4Or*iPFPP+aSh)r~&icJS{i z_>0dP5uUcJUwqoHy{e|C2jhhk{qU?m^F5aQ;mDTfi}8R%owdJ6#jJlwO``1 zj_Mch^zfSf2!j`7K8L!}-OrMh%j$AaorVjA8_nibb9uXYbGQFlAzT@=< z_&1w6%{Ow+>>Ajmvub3^?3x7otx5XrEb`mvnk1^bISo(1BtaNoTA9KttyIS7nijm& zhL_sw&Lm6`$15FhcMLzI;X?>NbYY28nAGl(b4J(Ph?g_)do7)v!}PS`q_Q(y`-N-Uy}Xo zwoQwOZp!yn%D8%Hdg|8)#s9sk2xmGr+I&gcH;W4L9ztOm~&&^7pbU8w(^ zb%W%8%+o^93m7*Pf#+IZq?$Cr4DtTqMKobPad#s`#?WW=ho7O3@-@9m zY8h|&Xh9#iG-l4En!GW5y*^;V7<{LHC=dVQ)0P#P-zQ&d@(o#ada*M}+d=@^LYw#) zpOxr0VvnET-heUS?Bc4<&?}^wz+F(NKMaLFwa2Sdpq7{wL6Jt`xn92TLRyc-K|d)E z%LO;ZAR{0D`EYxD-kEtGq_&JH&>(#Tswxiwdew~T9pS0!RL9d)-uk_1$0^Gz00vvU z-&yF^$h#0xRHp(=USA52^uzcI;>%^6@-j#cPJE36S5=eoLcWXQdm%=uE6Xdyh`h!K z>Sxxl0Wkh3!oOAUFNNJQA_CPd80oW$t6HC;a#%G@IU@e4n%)mo062?@*9gwOodp7p zD6NR2nypq<`x%}->p1bGD4w7mPmtgV1D+(q(;afi$!CA_V8`V<6TSPHymiq<;ZL?> zn%1XZeAcKch|WM!@0PP8sKJ+50-S{^z^Ze5G_i4~Lyr)b`r(22tj2)8{sCJ5GmGdC zg)qTY2bki3X$%-I2ID58ZX85b%{UpN8s-PBPg46$rPZ_4uVa-5eO>b>l!<1}WBmdz zg8!N25;NZie(YoA^>^Ai-~PIHKQ2B;@xKzF6+rt`!GEZSW*^a8SwAkEQCyYpq;d|i z>p}A4$En<6^bO|65v(LtEcfFglhbUM19<94{mQqidcf1l3n)HB2B7dE zLfpERxHTJ>F+VGZ2YR1rpF>(_Rj*0?J25|EoB;Z=q(s&QCWyEE9Di-qXh_nG>{T3t zL(?y}f~#am_B~05ybj+*s4@ly&1^_EuI5{#ABbdeNiI$Gq~N)HW<#f4wf)SnebBC{ z1}0C@ehYPPad{-4&bbMaN`ea-XEGj0KTdHuDoyZ*97k%g^D8F6z+@cZr z_5d&6Zjqi!B1*#W zdcbkh{tQR4192oYJmzQRsp5sEZ9J4$JsitRr5>gDRq;Y7>y%e6UMM_5<*DL@z&lQP zDMDqAct-S3-AtY;UPusp<$107RMJ1?o1y&94x-pNSQ83$c2pQlVO-#2CB|6r#+w0_zfHsN7E#^kBuf{a4HW$cCBRqMN;mW-(ud%xYdHI!RF zkJdvKCxk$Nn>fLDN^w>8A-z6Ycl4l-X`_ig>X|&1K5_)tFpqIkq5VD3N1=>9x;pgw zh=2e$`Y4=SToq+<9Q+6Tk=WUTK1RWQdd69ZKk$+|4r-pO*S{~~p}fDtAtB%w0VYqS z|N8fx@?7|1_yfQnA^1r%Rr+J%LB0MvNV(h5>K-nbp!RLiB z3c$z<=S65g@cxmg2IvPKpmL@=<0fAMDn!R!v_E8HqyPvCBHdgAdaUKo+v7KgW5oQ= zfMZA?=1Zf7>On*J^v&3l`r`L9eb}FedIa{gluu@m?De>xm=oR;&E)j!O9jc}j?9N# zj?}L{TY9_~X7c(+9P)hid)4|z&l(dSl75I-`@#Y7Sre;9&zjiJxY>upahP9fy^q%G zS!ccSNd=xRl%$GBv3mtQrx|}b+8Yiy>3FIil49T^s4I-Cazq{sM2W(VAp;%~0I>0K z(1pC^55j)MductGdzj-LGtSu=%Z*~4TCxCTBZ%_)La}n#R5jyIB-X@;C>b@KplZfA zob172kS~kKXW=M}jK2KnBR8OrBvFOwdo(zJZ#r_`?c2=c$?XR*`b!lXr+T zZo|@0_koX{@;VlwJTV~}#es)xe}4&lp&?Fr2_3%uPbTfINH>bRm4&SDi5PVHco(f;!GpD?A_Vt&*SAV8cUP6cO!l?vbYn#4(bX0&Z%;c&3 zui+dgzFHl=WtS0r>09*pYCm_%E2qCWlc&O$nCO%j(cv34i{Q)tM~|;i0lo$%Pld0k z$%!wZ!}su&1YhxHJ-$@lDX*OVnwdNmzU0MDd4;z${I~VB1YfWOzKG$JR}NqMziE9{ z_?o9W%K{kFE!JNuS17#`M(LiIwntrFM)^5Ti2U)meXJU zMm@gP*-m*W9loP(CHR_{JQcpca;Lm<`1~dCwO!?um(bzsyp!N-y+PkTIx4^yX7W`2 z*M6N7U#$*b^}PgNx>b*__DiR{a{7xic`AGzH#y}+bogdHNbqH^*W)WxfUkkcQ{hXu zIq?N__`aV<@D;Dq<4b+zlvhrF%}kyOU)P;Zd4)GM{5SS-f-hJCUjz^R@YsIa|3&Mo z!q<(*-`M13boid>B>19Co~r$3D!|u$tsY-yt`lE}4&N?a1YaGKr^1)`Mj@|U{CABW zUlzBE+w_;x;k)Kpg0G3mQ{f8~obt-~pT7jY+!IcD2_3#)y9vJ5tM%=pqXK+kCQs#m zdE8!Q(_gI)-)XN9eCez7_-em($}6Y8Fq5~)p5KDyhqz7=<}U+~OZLOL!zs8$te2km z8czF7ufg@Yd=`_g)1|8)XV>6(1lKlN*Xmx5m*`quzD$y=!R^2~#5A1&JsKA3!nbaI z!xQ*S1}|m#r5Ev14lm{TrFZcXT|db$eKE3S12UW1_C07uHJiEua-d{3^JrG1S>{n|Vdlg+j~e`KrDYy<)vqhH^Qiv>kt~1KdL^^J(_T?X z*sYp1_P13vAB1nckga3QUqSD;=f^}&_l55O2PDe^KR_ld1eq|**9{W+x^DiwGyhdg z?~nf0=r`xd(VcOg5~jUj+5^(dn5Q!oS<#~gLd`&&W0tOJ#)+?Ds{s7PI=~NUM_Bj)@6N&36O##3o+xj;p5^nBEWaS< zUwgsA3CzDmek7$@=4)b@8#ME8JpU@@2NO)5oFC@vFlx#EhQ_kJrD(gdaaYi1Vp zUl}i$9GcFsRnwY&gH0)4zDdz$5p7Gh(}(Ncq{S)Qq5^$9&!WQHh0BI5eyqmZHJsv2 z5xuDK7B8oGhuHlbbLymd!d99ss-`t$p%OJ8G__qw=NaNGZ-X}FZ3IPZ1pkrwpgAM5 zqxUUNI1e4Q>t{%8w|pOOX~eaGWP{8==HGrMN3JJ+hR5=uBC#j7s(qkU9Rz?5fh|0A zKBf_t^x-taF`ztHwla+@>uU_d8p9M@cSz<#+F8D3I9p(g^D`)a^sG_+M$Z}nZTVto z{EflUvl>Ip34`!2E~X2C(4f)T@B{9PZ(wo;u=>G2c zucQ4)`DwqXx8L^9mq0TwOr5NIaKVaaXam3#UYk{a+#LxN~e=HWaSmAD;(= zo;ASN*LH(r39`mmpjbph%{sE6mHN*~`tN4>Dy~b@4<-G71pRr+`X}oj>x+8CzxbRHMYR7Gpu=JpD<3*lq~Tq_ z_O(mcqToH?12~p{)#=K0#I(QfJ?ZVvUh<8;a^<4m6+3>T^`_-k&A0`CLD_zYRmp+9w{XG+&!kggAru5T%Q{#Lr@0_pP+=4YZT_#f&U|FD0U75gnd zt+>I2_2bjJepprWobR>^eVsd*&tShAVfi-tl+U+0d_dcQ-buULH$Lr4|L7J2=3?Pf zXpgS^Z8ueeqMr@JMy*K$NvnLl5j&jXkOfPi0I)&9IC!T`Q8R^A)ftvAb1#3WUj7?g z{%2t>KjB&a(i^q--{$f!6Y>L|_d6vJ9UjCnGgnXQ*EOH(dT_+jIO0&+?aEuf_ipmw%a%AMh-Hs$PEI+ZjLXAmn$je$Ksq2J7Yb z=klMg;rgldEPvs3TK#Om<&PKg3oJkB9{;I&`5STheTDp#XZh>st z9W0;fUO$8N^0(pgpC82aQ|np&!fUkp8OY_27xD`%-|8O!se1W?x%|FDe#*1_b@cLU zxcs|9Tt5-d@^8CZtDhaX{DX!349m~D*UwPB{4kgQ*+7mz;aUFDtF-w4#N}Tm(j|H65 zrjKRJj~(X6l=(4XeylY=M$C@^^J4+$ikMvUV~6=MWqwSUA8XBz5%Xif{8+#oHj`_9 z>@Yv3%#R84W3BiI`GGc;m*#%M#(yx}BXK=M^ARu>oV#nguYCNz^h&M${dchb`Lb=f ze+4|tpQ@MNpUdAt$j_v9BUM!SSFb+4e%!yv_%FSl>|c$T|M0y-eJjP}$ohikd$V!h zgl!=0)Mvu_of*?iIpJaO+dA-@wCz(?{l|HLtVp+CiE&68BkmI}rpFBOBQLj@5x=Y+5>DKQumrf07+Vo@NQj&4d9zJ*{J0%?d&f z06WCp*AX58!#?KXJd{4Z(k|^x@mstv*IP?phyVclxL;uaBmHH+^Kp z{T1pXu!&oJ?ERQ)eZ<}AqprL@n!#LN{39psck06x|73+ebp7M5kGkfc21yUj{;{4_ zU)4XR0EUi#u$Sg@=h(kVdHEcf-AQ1#HA`&(I7)lFaB+$TWO80}?w4r%)+1S>9#Mdy ztB0#Np~&i?juW2la1|%`e>LM+5kEFF*eO>yk^`td)j0Nbha;@Qk@AGYA1sCAp}DT~ z5m(`8^@Jl;630&Na5SiJv~e7++H1p><^23+IB?%3?=%A*K5ljLPCEl;=P%^v5WuL^ z&riYeT8`C2?O*RaP|mJ6uTI8n{@>8o@g&i4aPSDGbfAOjV9<#kT={!qt5SY8vMe4t zek54%v_}a`n%mbEj$%n1Pv2ioF9b(kg`>+8j^x&*^s%oy9RA-;9uni}ZjQs1zt?S3 z&fg!n&$YjY0guDqzXzuw`H2hzrt3>Y?^`<6c*GjZ6B3bpzDbvs|C9 z{Ht!;Qg%JX9gb!RhiG#-PdIWVal8YE<+~UUx2tgEJ>h8Bu9QBGaEGH?g`?mJN1-H+ z7usFvBfQdVZ^AA`j>FY>I1u9Ptz3R!Z@@(O)t;Ah=11dzi?_QH`2pX%G*Mh4KhQjo zw?h%3DcewV8Zb^SmzX+A^iwMA2ZNKQQ;dOE27mwcV z+As1_z1;XkxU66J0V=JpJHKcU_q+3pR&jrYev#Uq>r&?zjkme>3;!yUzny*&Dd87! zfT8mXSN!YWf!0IKzYpE&ihsj^pU>-velf~myW`&+!y&C_x6PAn4_HWlXy;95z9(K% zpRp49Yy}uPeY)a{_8rUl#ffl8zsq_wl&nX*L_O*OhOQp2;*@ll*P~pVGUpanpYm}^ zvs9lFaY`+#Scy0#0`O@4M0+n8r!MTgzg+1v$?BozoqeGWF7%mK>9c|B)0LmM?ZWk0&d=}s zw`)K5`;KxGk0;9ec@W@v@$-bZ-|6SB_^aVhTpv3Bx)~1TcgbI2Ne@o{YAWGhA%LOt zuM+j3`%Nx@9s+V;h1hN=1o!Olx>U`W48Mtam;lbhymBL}4}2kis`U$G9;T?u56DY7 zrh=&PsZ#yZYnVSOgke0($7@0_JWrCc^C;d4)$vDn#p*l{+lPSjVEqc@CyX$hkta`d z`v3v|Q`O^jn$wfU(>!k^OPLSn-j6TY{zyHF$~;(-w?DfcNIhEKnf5X4!uqB6gahIK zeI^94W(BnNtciX2o1~5e3c)016V`av#C7rdtYI6%OcgFFD;j&^@6&!+hd!OAclG5@ zZ$_W?`_TNbXNh0`4JPq$zX#_hj&D7tu+c3)ku6S-{Ek~~%injuOL>1|^0-|$VdcU4 z8nVCSPzYeeLYY0$aSN~Ec9Iiu3t|9v=mm+^)t`r@^*1(NB1`24gBUmb z>MykpNz1RTdqQ<={Mrpw!F9XH2fRITUbXO9uStZ-YEj0liGqvpEPQ0LEWJ*+i0{h= zCR_e@Sm#=fk7|B##Yf8rvUs^f|Ck}`6)uGr<)QuRhhbk|7}@d@zW0Q#Rwx*6eq19{ zit)fTuKP#T{F~ITKqJBU02mO{9G=d=(T|B5Jt9)tAP#*7v<8)LB5_s7Iz+qD;W=wb)kj!QtJU^MGr!G zyx&sUovt%Y5Msh*!tj1R7CpuPBDoX~pYEv>ZbjDQJe>mh)0tyQ@Eg1Gty z^Ic+La>%hBCk)f2tX)F5K>oN~Xo9{XqJn^q?3HghF=QMEouRD3-2oAMzLa0QOybH0 z7kUf<2IHM8)p``~Eh6>I$0d3C@wz>4%r&0dhx;4k@JmpKdKR29l&~l>RxWyDrMirA$G=``IL}-6f0Co#TqwUTy6ofB9 z@4+s@I0EiLhHfQlDe*cRveBL|btR@v&@r3&Qg(TgoT`}xLR7HWjgP^=%ivUr6aDxC z#oyvUMzMIyOYvEwYhuQQxGQI%ShL65o5W*PGk;|AoMSN%90I{)e1*c{j15`%b|73m zpP|Om=Mc#|N{(Q_O%Yzrf$nq`(dCX`LZ0*Zui5|TTzrP3H zS=<3%&2@*DK8ru|rH9}m^gXQ!2xOtOFuuPP&w7G0p@8}LJ6W5rJsn<#I-9)F6|d5> zo_r+OgtxK6gM=OF;ZF2scyBB6WEc8IH{07mwsd6hr8e{Nw=8~wgQEBgSpC#f3BMNb zw-+o-i(5b(6>wtA%Wwlaa}FC_%kv{!7DFHlN1cxd z8gKq2w3mRpj0Y}f@z1)9fF*xQaAlGFKx+<$L{w9&Q*+Qt?%NHgKoAB^)Mdr7E`h)D zx)>YV>R_}0-`jZ%{7c{`eBWA2@e?hh<%m(rS&o=DgJ81+H5iAOFel?DU8Tlww2O>6 z+A9Je=Z{HtyP4T7BkIcR7BIH`QP?epcKflJ*=;%t7$m#JEOz5QXs?ON5alX@hUh*} z7^3+H0g7}B^#F?hNqEHYpT@1KeFzpdxEsWZz}Zg*;^dSwf89Z(XftqLbhwCcNSF7~ zOwo^)k0-iIjiW4pwjhA$ON!9$#T+DG_|a=Q85DMwdjhD=W|k-FJfb(ezl*IA+E@C# zhxBGev+YxH+t z(ebW37v6Frgiv(@;a>=w#arp}#_6oA6urNS z+)v+|V2q@{73xSFz{4nl4Iy8UY9}~L(XRN zCrFzBB9FP=< z@6ldn9CRY&&Cs~l3?TYR6&XC-`Byb#Pr$IM`U#{h2p*Qd1Gg1IFes+)u86DNAlSGi zqE4dz?C}adogIQtn@1AinK82<_BD@>!#KELM4(f#w?CqPem+>Qs;R@E8;9EY;f$~V z>>4eb*ZVEsBYCS1j;FL*BF*%wot(Pb!@=yavuJ#VtJW>0X{m!Dtru@vs=a z762JLLT!KuYdNxI$aLvAL*>1^MSW^$v^K6rRb2X?HR4P+(N9=;f3ghc8Lp^wn(!yQ zs1i6CV2!h=VO$NUVH`WPm8t=z!w6~f*b($W^GSSLH`780wJ-=^L9rrDL9~!p2(nd= zY!6SdfWzSr*#8k1!~PGrn(l`Z{h#B0s~$-I*L^VZzN7!U3Px?T|MSJsht2+PE|5Fx z{}l4|{a=5O$aS49g1hn2SiWrkN2*w||D)qtN56#q8p3zHEkEM%^@M zbYLl-ql1s~emOcn%jXa3Mxjou^RwT;1EO7%ka^dOSvy8q_{aSb96`j*bbhwn{K3+T z{+IIy*+a29*7@0H=mR@jnd52lcreb9<0&$akV09~JVFfQ02LO4s4_OEDa|7oA^4r^ z+&;g!Epn(ir8p4|=A1|lu{FMc9tgW~YIlso(DvN^_Ic6&vi^$S$NkoiMuEREEfC<6 z7i_^1mlLau17L32%{=PxT#xiSwWAgNVE0h({oo@X^$4Dv3Qx2GJT*OoCox8$pY|c% z^>giqR6lP0;LnhFko};X-}Lc#{~I9Ci~Ku0-apCX{dg{}7d)GJy#Etu=qTTNdtb3k zZtsfcY23whmBD0R87u4Sa1{Ufy4CESpl}n@`*UBDtpHP+5yf7UCGc(eD|N??OG` zACDg}Q;XwkGcP>p3CTaJW)`7gidZXrBpUpf5JvW;W385VjfoK42}H#@3!=t_ES}+Y zmhgmZcseb3zJwB8pkL0CSm0XF4q!&^{$$FFcggQhioPh(v8WZu`cHNw0Y12$`dS?Pr$g6 zw*xL$(#>QtZ=aRd{Xt{40VmmZG7@}G299GF4E;KeAs`%+l-rZ;c(@`Tg>faIkKlv0 zxU}$rr~y%U_jyX568a{2=^UNQvcU$nVguNvGHm2&G66aTF%&3xu`VWID?je4d^-1~ zE&pRj`A~A=SfVzu3h<}*NhIyh5}RVC4&R7OUQ=g6}wg z)(_dlKs>lq{FnA@3txL{I-fxj;%_ z0^~E)0O;En0v2Qo1r6hweJnwq@!q)vKSgiBFUC^@e^Ir*T1I;{2pX@Nw-tIIexJ{f z&eB{aK|LMt0(%j>!JLE_I{BbcWnw0Q#g0%EE1Jw>3?Ow#VjZRfP2-=`?t;93rRyTJ z>)dhbNv_b-=cwn&M1APGh$hlc)9EqPKU9P29}GeD-wvEF^grw`R{f8KQow)spM=|{ z|8~Xtb{Xy_AjpmW;}kDxsfgF9|N7%iyhQ(3?kzBf0H|^IKM->gF_-dtqVIe&-B;kj z@8cl8yx#|DJ&3y1ejhx+tcUT^pG6&r&n!Ee=)IJ`5Wg=p==Md}{pBiSb!GMKJJG~%EZ;+5C!Kh2 zg5B4b9Z)6lis;9Qf9LG`HARD>#K1c!JWncWW5`?16#9Ym4*8SH5q?j3AWZ8+x+nB| z=$0g1F5IZaf3qqo2Z%`(0sw+V6+R7+?fg8$?4HQEvYjw}0!&l0R>~yD$>9KNRDN zKN`SJ953I0%Ct%ZeK8)iEM<$ALC{AR9Ty>=%43jb7#B&KD}u(X-2|QxD*tv619%j1 zzNj~i`{LAZNNd7+6SWHm;u9MzY!Ujy8!=W6o`N{6dF0p<;Wwm4L4d;lr1mG;1@VJo zSg)5DR%prTXve8c5SIh<&^%vrJZLS(ed{@%uj%d}S!kNC$)Zhj=u&x}ujwZC#!JO+ zT>S<^F?bE1d4v#|jky();@Bii*CG`=2q3XIqg4F}zZBc0eM~C5fA=@6Unx1nPm9e8 zIh|>iwFi?Fa(_cYp<9XQo2($(X0KP92GjYsX2_tz7lyD8_YlEq0%OiRvbfaO4xtsl zb^*OsXgIyJyd$W*VyopozTTr~?7@ET*8ILP!;^yUj+g!WLv*ogQS;0P@E$#=YrYxi z%UV}(;bE|D1$KCtbx%{^0&7F_Ksp9xx69{7k+hZv^*;Ar3R;hX9=4*nr7b z-Jet3|NdNxM|FQK^wW0v_p|%${WIz@MEXF?Ea9AL1a)a##O}BE8+d;+_SixA| z6XyimPh+c?UL)(9m|YY&<#|2pI;MUyPM;T?MRY=rlcp?A_!8aEvW_WV!0Lz@Tk`%) zT+dXXQ?|r+^QdNXJ(I$Yg*qBZ;k*38tj(G%z}hZoqhQ?flJHMOzZL*11mS&yt7aVu z?*0Q>y&73yd~Da4JLLCsyU_Vb zNcc<~K;|d^ZP0lv3<$Z;!$&#)Oy@(U!$km>%bW?|$U7JFmi+T+P^dgCzwjgkEXwEY zTF&FpIH3#COXETsC%}~;iAm@JEV4YqShYPYne1X+63t`s`f>TFzZgOk`h#Wy`s)LS z$sy0E?r($pO`wqV|w{jp5+&v^5c5>17!IeH@;^A|M))MeI4(Ko3g9+Jrl;=>^&22 zT{f7^XRWHH(&+o=O3NLrm-{uBdr1XyU;L96?+;w=4i(6qpqKj_m%Dg|cRg&Sm)pCY z>G%8!LJ4AZd8HX6ZCTT=5imK>Rk`(=;iLq<(?$uM)ur| zP!I1nIS(N(W0sn~2ZX$TCYrGDKE8h@@*Cy-!X8u(e;)fKTnlD@|4abx#|R1@E&R$q zviHwq#D&fd@sY(>%}l=PT$kM`PBQO|?_nzB0Vk|2WAExE??=Y>InxC6$ttv3VNaD~AS80X;?e1i_Xlhq<%9MA7$l?fP!z!g@X zT!iXNRUhoD*?xQW{^Rp_>;Vy+_5H)OtWK>=o}8b+y7BiPkA(L;;}Gc$SbB){uV?pT zo%u8Hk@WZExt5>dNQ@y1j(~pAxP?5F#NVSXpF0(B8N2@|>Z>XT<+1*=YU%+{D%vhQ zk=NBcx8-iQ5$uQWAtt_ay7PP>YO`LG-tC(T8$$^}o7hL3>_xtPR4(D>mS0H!ZU@hKSE_b5}0Itf70A7JkX8?8ak+gfkb9(F?nEy4!71MLup*?zJB7E&L^<*vNIJKjU}a$C6EyDE_T-9W7#Qe5s~70A6&FZU)c_opWBdKjvgdpno=p9nf1DbX%<+p5<~66mmzy+BcZbgZ$OS zkjEltK41(IHn!dg7fkx1JJL9g=U1@b#rR3i_v``5GkACu2pJn9lO>7A8)4=Nrbuv? z?8rG6!9gM|9}ZanOXz&Yku$}qZXx(iS91C?JM?rpUtFdtr$JK=&vW3UkeKiqf&rVk zxxjrTL4yV3OecWxsr>e|o;)YV^~uY>1j-kaQsdR-9~A;chf&epzKd{*4^|noCA56` zSOYGh#W||XcCgnT=BQxW3g@UUs`)P7@)orO0r~6kwh69|t%6j^MZYrRkdtq9Q^s3&OLz9B#}t5r2~2@HPVc`{|3 zi|C%u^5;*3=V_ZwLd|@EYHB||zD91qKipr#>`3=TJq{PZj`{RIF>=jfiIC_g8E4Gf zlM~iR&VE;6ycj%UtRE-&=8nO%9EbhP`CObU5l!d6;2(XVkd08o-6`TQbl)B{6`a!* z3sgl@$!%+CD&wH3fWlx37phyt75wZg88?M&cyL`lt1lU+kC${j`7nzEOXnWuc;WdB z77oA)h__e=O2Sr47oE0z$lnQ5FzyFyv2;B8wpa(B8f4WE;z3)$rX`@}i9trbZ(fS5 z4(+?%-Tim+`y;yh**T9mg(y*_TqvlmV2lGn2sR&bws(S)$!P?=Mfs#WzWhWIYUSTd z^it~UDqC{e%Sg1hSfagGl7jYd!3iRx9n^{U zDOEGCgbStWm5(QBy$A`wow?jpY%(vQLqI=jZco`ow3HCk!T5MMtix&^NcD?4#Xk$r z@p(nyxH<3}IY;Uc3EbokXfcH2@*yY_{ZTMcUeH^>IC(umZ-ijafRbf@2YMSN=q;CI zb^>Oz(j{XynEy>6v%z^%`%7S|W)75?E$?SiWI&A60>)xLAvIIUpGc&Z&&mo#s)o8S zJ_{Jv;G^`7#UaoMZBURu+s@gZr1o7kbuKCp+%q|y_eG>1;z^yx-Gp&saHlbR7@eoe zZ|lN7y(ZOxA_SK`4(c?ytd>~@c#Q0tadi1zDjwrIi%4p(tNJ4B3UTp}=h~q)zT!5{`Vx8A?{a_aHAy!7taqE5X zJZ-Z{@E2cQkm^;%cg&8~xHWM(cEaxC)}#JP;@08-js0B3t#RToJsGz)*zojh+!_ES zd5c@KTUhm@iMO_$%;K$fclUpFKD)n3cfZTH^$rk(ZWCd0bo}cfZY|8BzFJA#x;emM z(TX*0O>OQ;l(zl*wrfX{f`+PtaL513tXTx!Ox(JOghR5EUz9i?$=gvl*wpOSH_AG`r6THED& zh+8-M8;@I4o6!2Icw8B`hErJYl5uP6J~h4=lPlNPecYP6!s&$~ZXNX7rf4o(+`2wo zg}9=7V_F}%T_Og_OFYIeOV1OOVLFPhzQ@a%qAaHvP}k>w5V!u4a8z`Bs)?1~Lvd^3 zsxnSoE^a;A1Q`>}7UI@Sm0C}g+x?4k9qIu8YEYEJ_(31HHeAEG!d2W__vaeuWoUhR zB5rNHnkwBv#3F88TohzT;?}qJDiyaDm=Vjwt@oTUw1-+5D_2=D6#jOQqCkH2qxb@W&%Ezru zOo|*xi@5b91f-2ymBy`2Om0d0 zl#E-um}Pn*ZawyR9=B%u(fX=*Tp73KZp3<*j9YVms_`{5xpIBo$E~fPT+tMm7mB#` z%x_h3>rrqO;tF0~0BnkXoL>fFj@+C=pBNajU>KdyEEw@Rx@rQ~Yi9a7?JwzJ0!~wi z4a~b+h2p#reUDh7_9m=ApBmg8T_6)r51SKaxEF@|TfL?{$*U*tOy`)X=zJ>?ZJiMr z0aYFSgB|J!Mh1Wk1pjO;gp7I?v_=5?taWqy>) zJxVTje`mSUB8~>RY*Z*rKD|VAdN-WNZJRR*Xv&4+c*<__UiNh&xg0CPK~+biV#CJ@ z#qzn%RC}M&^&2Y}IIL9ta&v3ZDG6P%sA&X64J{30c252`wr-TwT7oek0dq zVqmlWsOTJ5^kr~rF;g@Lz~jK)R1Z2Fe*+w1xxwgiII^+-P+h1);!}8wz3ymX5sb5G zV@kp&ZTm+*7wy*J=Q!D2;B(-`B$)%pWh#?uzLR(&WR}XCaH?&cp5cpI?0hlJe1i=y z4EZUdDG#d0XB};P(M?1v_~MA8gc3ubIaK2KRHm1+KC)lAMzo!NizGwyQ_JD3};jd~qzC`KacLL>U|&`66+fE4~f6 zdhv*-SQ5{dKFIxY{zdMDG1)iK<+b*gUqXNHP5a1_N9kLPFuPDMQ7tJUCp=SEu-n7 zmk?{>LE`Y0p8h8&GR5ZhyXd+WSfgYfG0_CDI*TitU>k2^7EV5dUgYBZ=oWYnYs(m1 zmXHOeDU!0ff$f!L0lF@z8Fch8rH)!N?l^2Pgm*Dt;&*BGHKfsSM0rDg3 zlW=Ki)r{xiCb2H77DO2LZ%a}swY;g)S5HLmq0JIjpCBUxKbs7~n`IgY$~Jn=u+`Qk zjSN|k-kPnv-DxRA2j*KYs%B1t^=&9S-PPW6#kKO{=6`G}Ze3nnya$VG;>C@!7k3>Q zcthUeSQ=WMmxkr!9jgT+O8asRLvmxhB>iS2TC^<3?OyttJg(NxR$RPje^ zd&l)Z#P2QZ*5TNZX6PAk{?K+m_S1Mj9123RB*shRh2*|A&3$q=j)$U{sTI*z@?jc= z_}>{9THonPJ0e&=sgRFx6OX%Hj%WN2Q0>ZD$X2?_9`YX_if}swqOs^y^AA*C@^}Vw zQ&2B4PV>0_>u8a>=B0q1Lp@&3e#&yv->d7x_1J^!{+>9>QPJ_KC@WviGoU_s`5yPH zbUaAysZFMG1_kC-?pN8&1Q`PuBJN3jr`A*DcE9&XhdRLSVMRGCPpzLnZSUYYYghB9 z!2vbCu5X>~Ud$_aT=$oqOO@_Obcy-XE8Y_=34>hYx-Cl0pGKHGb+Sn8S2=TN`T5g0 z^9KhsF@O5~yM*X@PR+LNFUR=7@jRPv2pSK=^VCa{P%~eBf$EjV6FhIN-LKLx4{YaQ z{&ei-Wd790%Hi>fShwkF{xn7$rYGl56W>_j`> z>u`7fkB71Qle+s|&Y#{7g3xWEOpd)j;r!=e{xttEZHB6`9;ZDv)+5{WZyb+%-V9~BIZxGLqKLk zQZ>`E?yp(#sF*)p_NJ&y2y_p<))06vde_XVxD#h;<#&_1a@Uk!*Y zsy-hsIP)>myjS)y1j@E5p+DEB(Vw3|g4683!Yqh!N)`BXx8cU0Cp3}0SNi}kku-Y* zhZE*x2w?=CAd}ALS@t?{9sXF=%nR7CPWz}h$fq4172B*#0nu^-#ECy=*vtN%4Z5^t zi=%=5gpb;{SwX%km8bgR{W0$^aeQ9|b_5Oau7C3GFdiYVv_MVeGT^-EPtZ)q)fC6H z{F(2<-2?NMU+ydNV=NV4B8IG1ct3Kif(`Qug91q%C*8A%1 z)AfOpyv05FPkYP{3RpPrckO=g(D(WBTVrsFk@$0>L|IqY_+WsORvOY9dXrHy3`(!$Bl@IAu zuQw?yQ{m_(+P}+uNN|D0=42~tn&(5hUvY43s!3U{$vgIa+Yk%j8Xcrx!Y6kOqa+ex za?o$^4`Yi<;XlS-Ra2+I7f_a%^Z2`(!*K1xL{Q||2$FcF!0MAz%zs#7;xRB?2J;Va zQo!5s7CADW_=%YEJGUBCFsO@M&30Is+*eb00hX z;ZiuMPWa_m>X&KFeV+Xi{hW2cX15gc)hXro<#wIm(l0x@oPL?*ei?bm>6f`2t-l<% z$-LZyd99CQ4k{dvt^k$8xI-d0wPi+dI!7k|!H2QKCPX&pAdNQ60+wjnMiqx0H&#M%xCb!P)Psw>;bf~)iOCcKJt*~$vj6Lv}~Woj$@L0v%LY1GSAcT zo~EAGeA$ot^ZXaP-&!AHCps?P9z0eek*b;N*&8@**q9s$VP}|+v3ik=22eq+X%V_~ z**wokAB>9&?^67{omkqvc@Bi-G?Mwe&F9n4Q)z@64BgqK_<#UAFQPZjE8m+L&p%bbR0s#`3DTYbsQn-QBn*|h&8{GXBDd`eulUTf)x=zKe#iGpQ8+ywcf;a#Il<)@;sqAQBE@$jyZBNVxA+G z+K^NyKO62Z`wI6*=BA_9Bz*F9WS#zxT+7GLF5{HQ3rk{ z^kHzY|3&>Fgk{a&UjMh9^~b))YyDqz)}Li1q5e-R>aQpl>(9$YUKEN@oY!Puf92gN z2u*Lhk3%sm|NR!#ig&J)BTX@6izi2b=M=slM;bo`)2KhLndx6t`n^?KB ze^mJ--u@N5+0qYw1Q#rUuDu_O0;^l{!^y?i50=UgqfZz^eyN6Z=j&7t*oN>A`#~H_ zllYhSgRo!hQM?B4X`X-%A{@8_dPH(QSElI|y|eN~qA*~k?7?C=06MlCUrZ9H5g zy`(r~%5r8`cY^6z+nMk(*m#B>mM30|e7FREc2fpnpYUAO5pff73Ctga9%At z{@I<4f0!JuFXSXyj+gPz5BS<{{R$9JLX^RQ9I@s#)|Fu?4JZsiydQSaC+RIl6=!jEY>4_H=;?V zg7KGa?c~DGedu_J>P_cY<=XlCyHF2lSWP+CGC85ulrx&i$-cOH_3Fdqq?jD5-xrVv zY5sB%v_eZ*2l>lbmWC0p-~9mk`6XL#rg`NXy~Sw~O+&!pe-R{b;=`N=%GoUg6BwBPg~&)y0F2IDf5XG4En`GZvD zw=MeP>c69^{(oHggH+|WJx}ZJsl7+u_tf4~%d34+Ru1RgO51zDi#Cm28;Kq1_=(|Djh~`86*hDO3#u*SS{ls zv*bhm{4JlMj!{g-@u{RjU)bhFzrL}eUk~Oywe$ARt9?OM4!1A1b5f4IU+*=^(wjd{ zdPuq?i?-~mqC)}>p6y59TvDxJj-cKMzGnWpmEOz<@ay-nJ5P|HmMji_CjdpY`ks%R@*X7)!3wL z(D?oiN>BXUqxsZNczlAsjDOnwTj4y|&cpt#n?9<>bvH3qj>CSg*4_As!}R33n~o=F zy*VC?Kbhb5z`C36&%q3Hyu5EHq`*UX#kwBl^ex$XltS8xUvdB5{QfT8{Vw-!eF;N# z?A4l>9E|1g4|OKK@mu=yB5}&uT z`{nvDKd5y7RvKD}SVxZ2Q?<*n$&_8!bKd(fpBZF$cssZMOYMsjsL&LZ1;Srr^t$%Ym+nvMepu@VL?5d^UQ_Q+N-4^fd9t!| zgVZ8C{KVu3>@V zD{=uAnx^RtuXA=BIzV=Ci(_8$X6SDjf7h~BOUKuB3_te^dtT^&em+%olhCQTF z0m|*gxr%y#2l4Tr2Yw5GM{Q6^{P6*Bl`{UQWB7FS?7?}I<4p_@&Cr}fD*IrM=_l}g z<@$MYBaMEdW$<~(JEs^vhaY~){cxXEgSeG=-Z}jM)sMqI);Rn34Ox8HthpchDY5K; zoqywQsey4Dh-R+C%?9J6kh&aPFGcz(m+Sd*KTw-lqAb3iuXvpZ`$EiNQtkJ<(#KaD zFnu&>?yp=QSA%G$J_71;0v`2I_|d74AROsP7JTIY<Q~RuE_ZPM1zDe}!W99RBk;mKG zeb(JYZ~2K|7nA%%+dWphmG86eT7f1hxzE}Mvv%!FF83>8cg!pD@pj2^T%J{@ zqH&yUpY>(MLG1mp0fx)oPl^4kY@c=hF00>iKau%ob@o{|tL4W$@=o$si_OVC>pIRm z^(iOs#96tzJo_$kh&p=KsKDr1!=RoQhHU%M?znr^D$EHK?=<}fnl{Z_fpAujs;M*K zA}B4+$3^G(+>(Qq71YKFGdxQpH-Md6KYt)&|qE%XUL@$Q) ze&#gLAbisj-yr(WF$H{lFs{oIG-g!fHFod+zQK22^YD*882>Itab2t7?MV@!QsUy#% zl&F~BlAWRdw#R?;f&S6H)|D4IP{6sXotw#ix$b?>TRWVsr>7J>TDOjo`$`cg{*e8m zkEtGy*(zYCPQ(s_Fm^GJy3s0)A6}7lw>W`CdcK7p9LRFcASn1n%X~U?0=y090PK3( zytUvgCn?s0$bSMjfBfk9Luoo(K~o^VtBI#aAqAbwm1)$cl#s_?*Fug1Y35`95B=@2 zvX^zq`&@F4gLBkzyiC6zc-~~w3XPMQH|ZTH&5sJt_3oVn6%woQp0xs%hk^~3`LVeh zvr0yXyryNO1|r9m9sL3?8iy*jCB?(MHH4Cp&5)O!|^B%XJeMR%O5x82n-NU?9!9%2{n<-evd#XlT z5sFe&Fh&;@+-+z@j-w*YIESNFNK362=2~k-lk-gn%Vk^@v%)<(t|GT+MFo~h10p@o zpybD;1uZ;5tOcd)TSTRP(}9wlV#ciYOM#L(R!;Gv(BuSE1y@FSw(pNZOhlV8>-BCI z3V+6l%PuaYoq(!9VTcnj{wNgHfg0xv6jb3~q^FbBg%o{Rg!SVn(($nd2@HXy|E?OP zB+y-3vz3yJwQ_=U5yhqYb%$6Oh#jI^#*7}?xP5I|ttj`KTS`hRgH~5;6w+Y>s zQU1tfcx9mkax$A7vo6>Kx>X@VJQ_~ELTD_VJ*r389mWV7;HO#~zW8}ZSl4~P z`B5$?Jog114)aKVcq4PBSxyroJwMi>BOA2_=N&DZL5K||o+HHCW)IP|B``gw0!57f zpBVCubG3$(2fir!vv7!eaK7%4uPh9USs#B%%eR^2J5^Aj4z^ph8R1V;Jpr&8hz-6cW8_b^L{lS7~tQi9v^Za zQOtTJ&*(L&$>D`2YJ}8K{&As(5OkZNi?*!vaWS6Yh2wm^4qR_c z1v623I8)ANs;exLV^AejFw;9qT;ifi3gf_RJ5m@I)-hpywo|*U79eh&JmPY$iMNHp zW^D-LJUu=1P3PLdN1;{AZpboQV37Jv2bROihTn7vyAeBRc~WcavIt=|+<%8q3BgI? zqG_2zzoDnP6TDzg(tVl8X5Fw%2i**9u+3tm=R`LG!#^p7K+Df+L4f#^yV>!kgFpR> zKO6qf}1141GB_qGEZ^Pt2PA!k(d#@a7Jhts(h_nxb(P7(8_` zwsFue!|Im@)i3?(mtU)2I@B-M>t7V*SE^r{)GwFNFAvTyHcY`BLY}#bed?6_De^rk z@4tyD2QPtkZl#(mBv%qi(_K@dX@Q&0LbS4ZR%UR6823kGgwTh^J-TZn>U>B z9xk#N#V(8$nZh?j`<>9vJ>P-ppnM+ZAx@yVP62bBMSXAJ&MR}S)4nVE9g=WVUXtT? zz{G2zhN!}QIdZ4-!@#$FpUtyIVv^mIr)ZV$n|PDyT7*+dk-`JbYv4v#O{zDvJ>e?`he?Fjsf1&O~< z&vxQllf->k!l8HRqvSvLjsqXN2-v$Z4_h;V`HD=dd{6OC<*Csx^R4Xqe?jDN6B3Tn zVUh>aE#XwN{y#l9r;wGkEz*s7>Q|n5Rl8!9RuK87-i+XL5S{g0|F?0VR3K%6R%F7m z|2ps|x_#~ZxzoO((#fBeuM7SJ;aAQ2zr?RVZnUV%3Q-UyPaZ2+hdrmm-h|{({%Zm9 zaim(U|Ne`H+cBZga6o%_-k6F8t6cvFXjiHdd6D5O{P42R0jzZWe+MBm%??yqCWRX+ zSjDgCz$z};kx9ya{qkUwLSfq1B+gyz!YCu#8r{(^57s_o^DO39;c`KT)4qca<(K-N z?)p0{>pPPo>%R^pz(kY6r$16_Mrw%Jpo1$%gd*7yv#fT_4$@KUwIRo( zH+WVqfsY&0YTwYsf7aH@W~aoYNUCql>iDZx-xML(2n0tm+KF`Hw@^~@+t05{zr=o> z{bF_}<(C|Oo$UL71Y3}Cg|c7DzNg)O@p;S`NpEF)Kfh@EBX}|Emv~`CroW>0b2t8y z{MU@*wf|~x;idhDbKK5OOq?Ms&5xNThL9k(2ZRadvuAM=h|S>jx2Ct{_Sh$$J2Q~el&g6+fNPr7~I**4_Pfz&v;^G%IbDjP(A@Nh=Q;!3wZ*`0>-nK7G zx8sY!p1Sd;b=TVYv)snb$)9i;{HlmA3KBn0d?EKe6s$i#sSUJ>FM2Qa>c7vpycTIi z9+yo4?Q0*GN81@oB{taU@r%89)i5qoyL-oFOvM-dU-pj6UfHi-d?EW6@x`^!Xo@dd z_b3@(BqTgDzF;`+_yYR?kD!nR`v4>B{34AhMx-&wWa)Up*PA;sS}Mn$jXK|SL>iJY zG3%1^G-F6xt)4;uNMlO`K-(Dk;mmHtZD*+9i<^I>k!1tqd>shd`G2X%$p8OQD{_hu z{O66ch;x%Y*APT{4gt4aaavUN<7eoCQ(2V8>0mRj`R?GJH1{!U?z!Ne9VSM4ZjlET z8UhSC0r@h?Uw|#_dHqq49yn%g{L=QJk*toqFfSOFe!rr)E4^o6+?A6+Gp;xyFz%A~ zjW)^l<>RjJB4LDkCo5_{cjN06cilK&$6Z6xpO^3FcRA{3yrTAVH%<>-7_yGC`$^09 z{PGiIKkwr7Lf=~yNj9UWxNJ|)=o7_%Y-gn(oK1O{!sG2oh%7Ji%g8F37jf(gAms36 zek9xJwT~vebD@EH`|nZ{xTp=2=kj*Uq!H^WQ4sF_R9cBMkLjRIPn00CzV@7U_jd6_ zC!U6q5-&HME|RQ8fI#`7mP-U3{(KB~$~;eG-NV#3ay|K3LN{fu=Ky`3GdU0Ind_;% z2>KqAa0w^+2>ryo&aRI=+VojCYkc0+1vCzu(SfSWDCpT}*!p6NHi~fov{s@kK!~eZ zHP#&M+o|$n%-Cb>c|In#a-tNrj(-eE-4h%n2^M`9N%_$R`4zRe}Zr2+W+Gj z(S9JHy^1%>>fbd0WawX`gclUoRj7Z(*){3kwm?SaBwYG8Ed6aczC8R_!I!c2VEto1 zE%JROMq13--372$_KBRvPPw5~0eHVU%PnfdOp^4ZNJCD!!E#&rc zXrgq_VJmmGQxo$8UQJ}zO!}NpGZd#LN=F*D?tgesLSgdCLyf@@>Dd>k>H#svG7_aq z7!cCWg{_kb4LhwA>3M_w+&nHKDfBzvlCCLi&B9wF14{QZ;k5yF%sDUI{Vyag@?&fK z+Z%|e^Fe}2{G6qI);&*aT{7a&R=<8ykXLo{ogcq^%8wt-e*JV-&5vxt%Z~xYkMNmZe&jFo=SS`I{bAgXzT5@g ze&qPCrv7qhUoU+PGx)Hlf|dBZm%jee{YKW^Kt=+wL4H48tioas-?O6^YCf(VAcyLI z{hp|=O-Q)P4r=@3+$Z2X%ZlP;vKiSJIy2V2%ZI0Q@;B)(Un3C}1V^pI&e&e9=fpd_ z{3YBVM;)dF+#?}Mz&+<`mAXgbl_#}~UH&1}>cyi5Id|+|Le8mXubhkLm+UvP?q5>Q z*^gEv=QqDA@Ab}i=+I;&dF#$teV9?&p{;`1CrsV&z7StoG#Ct$`rp`k}s9sKh_}$G1n1Bm0cM+%`1)a|DnI^KPUlqsOwbx7oI21MYN(yg zEraMxuM~7n0rm8u`S2ETrZda?&h`=Ute$hi$7GuhWZMJT(s{^Bus@0Kg~q0v#kq9f ziF7}7mWl&h_d~aQdsb*%`WwX$@;BU{%5!ZvF_!Low(Fl*OM8D(+fs}hRn52hS7bEC z(#(cqXwJzpU+RCuBISeZy7?h->S5e^_!Q{04KvcS3|5`tHnSR42{)tQwgE25yCD6B znx`r{!;(()t^HV1%mnE^NqMh8UecB)+K`_$4g|ry0?+&u2ZGGGTc@<7%i?UqwWpFcGDKCykYL%_GXeY7poKi5GI1|T70F67)td*mYldT?H#y%y(P z`JIatJyhATlK0vVT{$b%E8#2s((-r4$tCVxYxsm9OW7??GHrDCiWQd z=O%7nPGCdqJ|DKf41FjHqmnl3y@M#Vi#%b4?H`uyQ?h-4-bU7~2OGddRl&XbT$*I5 z1S}YeiI#mg*y!kCBxKqW12$*X4eU8G=dOEz)wG1O_nh^l;P>vu6ajPY^oWD?#jlr<0bC)q}ai3`KZSc4}VNO*Xn=pOXp ziCP5=*Y*uLCbf=zGF#eDHUylE@3qNBV1jj3*pJF~>-c>SQ z3H9Ng*wY04X1v1Vtm1g32}~#BR*!h)(py!$(jxKlk-r#k8(t2l_3I*G49 zS@Sl({*vKWG|!7tr*)m@ z4f^;?lkXGrm;J!EI)54S@s}n(Rp>$Q(PCi8TRcj^fNdLaFWssFP7V7pnISCQQu z>%u)g57&@z$-8}9W%5KJ_zaaZVACYI#`Cd;!)9Nqz+s!2ippCO%`X#ct zz~T-}V3q{st@W8b59i{PI z(*UQJq*>K)<``lyPgRx@a&6?I*3J$lfn9)^{?!K*eR^0QuwxthPC_{@@t;P2;6wa& z;D0TC0RC#873ujZekex+_7NfJw=6|;45j7^I!3A99>%|oh*>*(d@-DEDPk}UGl|i~ zHhcb7OF~V!R%BXEa{4VL56VXpJs?3(ZI=kYMfu1j*s!*01{Ra|0lEhex}%{_3%v%C zcIh1sydsK-8zcM##|0N^XVy5^xfsZ+U4Zg0NcphOtqRQjHnosriYuYXM zx&`K%t73CEYUVz?Si}OI%LE)Ve!+eco$suojyn4p!O&n?%dsa55zKSqKk*w)q#AW% z-J(O{XY$vivyOGtcP!E-S_KL#GR>#djX%Tb+WGU5I|BGKdU9#}s;Hw*E)e)Z`JMZ; z?u7DlEcx}H=mC(xc%xWy+_(Sw=gW6nsD%@kU2`2sqwHVBvC7W{=F3wHtBa$$)^Z$G zkoHsQq4uK{#ZgVi);o@BcHu*DvpFs%7DwfPZ*_50R@!B!9jQqVvXBr39KLbX4hsVG zK=!ZXWAGz5j!G@AD30p9XjZ5o?Yz=2E&qz=pUsN|S#a+DYr9qC%ctI;;;7LR{l-7L za-Aoa>+^P6H?I=8VDZ+NE^??Uk9@O!daE`y_DBmg)xDpiefuda^`}RzzmdJyg!$Yf zT^W&V&F=n{hfwT)mi?RS$L6@I^4_Sy?MKEpBERK#Z`42|kE;su+vG;9`081qvBjbvHGWlo%d;P~f_tN~ z#|x%=9GTwe@$EUf5`-3=t?z$@%X#!lHl3rSD@n%_5*|WBUd0Z$H|m1xsHXIt$tzP3 zLP8(vG9Bzf(8&d6xs=og4{CZB#k)uFg1-I!ALK3y3R-jHuvlapJ@4x+5F>cs$jc8c z5`6XZk5Z1#JVWyd)%nLW+eMy1_T!OXMgB3#3RBO#{P;qrKDqNs6Z4NDFsVBK7;E(6 z!*<14clEJf$hxci@fEfI@6ToX;h^@iZnxZg;8p-4wP}@bg8XwP}IChh$G5hn-XBSi{C$foG-ejT&2OAR!MtmF6vK-F~Px zZ){-ix`54_vMH{6qY@I7$EL_?`Ka}sYss>`J$dCE2d8EjmMuRdr7fd2J~>(%wWzf> zA!Ivl*S%4lKCeo97PU5gLemllPgMT8DP2ac(}i4B@n@vxE#hd2weD<=12q5GOy%CQ zl&c__cb-Htzn6@_>sY>}rP~}W-P-$dQs~c`-%8dI`QFTDDv%(@< zO;L)e`uNc`khoS^mtKrq!{>d*C4OeyBgYBn;j4^$vY#XMwDT&S;t<79&#b)^9i$Kj2frV?BlGBLOL90eH&$`UcXvT&ZWsjAzdgV`#0^S z!LK^xr;Z>hJo%|nY3EG4OZ2NazKXoMFgH zP0Ol_d%koo$35fH4k`ZXd0|CyPwOe@w65zbX%{})Kgu{@VsTFq_*NJ93`@IG2R+C` zLfY@jNvqa__n`Aq3*%5TZ7-6ter|6^QUvXZb z14~0hR`qtBh;$nBSH7k40)ukgJNaHyUbn~yR^S(9UiSeb&Aj|a+Bi7lxRA>(D*2Et zrTjDOq7GLMFxQ`R1qeq@feb5%?czC;aulLH1v<9c*r{&JLb=4%@-(JSTtkIH<@DcAQ>sJD76eV~l%_ zXC`I`Lts*Mc5vuu!Jj(lL4i6~^AEQjeDmM{J&^r7^`G@H*bX*-z9Ku=d^YNH<_h|1 zw}YK$)Xxt7Go$QagTyOH|BYG6YP+5|1j3oci~A1YavIbV-%RG^3IKMx8Cg%9O*!@7 zt#1>zFaGt!O|suQ=vB!$>w5?K>s9tBL3a>;5$`$UtkJWovoBkm$@ZmH_M`N-I{Pwy zX1(o8?o*}ZJu&;z3?@})Um7JobE+74q>dDHJNa(M6;{GitJ!<*{o2Dgs=2V%fI6JW?qt24?FmOJ<1Ly4-<4d`CgM9YymfFwS)iq zR)8JM9O@jOYW$S9gU#m#*ufu=9b9{-^jKK}YY`UxkW zm7WIL!R(i-vx9Fmu^nud{V4wGaZu5GGk;#a?O^thz;Ry(JJ<>)Rc8lN5}!KgLG$?~ z?BM#n0`%bEKz;<|pPK&he@6r1c1ychl=nC)n!|Vn6>_%LM`@@XUYjhl*2O%Q|Fbt`!KcB3Z09c_2$pmQI} zA7=#Uf$ZNo4$I^RJHJwqy-t00R%qyBg1*}A^?)R+9`^cywaQ*cC0;@L@1GxxgK&3# z@VgWao(I6b`N5%&I`!YJZy!{CFe&@}pzX`r-Tn1yXn#R>5Pv=S!CXgm_T~BG*uFH% zew6-JXJ3k|>up~~_bV;$iP@JLW_ zYAA;`vd+kQ@l72_r184-+(H@yo%qUo0OM)Oc=$UJ)v3ka*L5Smx`<_+Dd_=7!uR7{a{U10ZYV1(*!zWrX>-X0uT2W1b^|v(YD#zo3ev|Lq zzjHq5I1dtMU(0hpbCPU7)l#gNswGZ8A=Vp3Pu6na0P6Hq#C0AdPmAo++w^&m+iv6L zD5@1YK~yLy=~4Woc!B8A^P=lf7LIvQBA}g#OhxmeC4gs8BnoI!q1=qR=+*coUcG8n z^P=$9ZY~ruowG#0PP+k(k#$VLQ);V<0IWPJx2z3VTVt!oo8DFFe+JF0Gj{6|}H%z%vH<1M4>^_XTi7RPdbRqyd*(>WN`hDz+(!LbCtFte^pUd_oDf_9-zC@|hy4I%-?(X#`ro1O+ zU;2S>b@nAD@u`Cz^j=!RzMP5+T%7|z*q8p@0{Ia)_9eWlKi#k^dKX^6x#%L8Dm^ceQvkK6^~no$a6|k3L~zqd{D|%3 z#lwhOD?Nuh)9aAEGj2|7;f-&yJBofyy_5Y4xi>&!hLMf*?0_Fi&5!c^EGW5kA1!n7 z%gAK#9utrWSAbFk5#|U@rBh|*;43@qO28}sKiIvVNX0S*EvD~ z?M&uW6we2&a}4iL7kwYx;MMnxiszFdk5n>#27xUWp=ts2Mfb+Rhz>{4G7wEGz=_AS`c=g1=&`x&lSrEzoaXGoU8uZnY6 zMkRg)n$_t<3^q8({g?%7+F3f9mc@64VIRGinEqY2Qj=9y%)&mT(n3 zijO>g5BqU{jo*1cuEPV~f*$zJs%$zFtW@PPNGZU!b_Ft~Q^FAh3-u8MW6hFZfkBw+ z!!gOHEEVtDHLtsg^c2O30^-V>F=+|>MuP(CO?}x(+ept(i~|a?d1*MS0!J=V`t8AO zg?^diT*_CRH!&F&7JQ28^A-Ln1s-&Ub#aVEvo&qo9Z!9eLZYW+RP;8YqMUi~@`29G zV$UHuuO8pdsrRHOWP|+9rx>K)ai8f*lkKZ-pcH$_BeY${hY!w-zQ>nl#jNLx7!)Sk zmrxW_3&?`-(=jUpkbGdp5(nUSI1^X{u2}{6FgLC@)(Ub+f&9mRv`xT_T1N1+A9!ma z7iAZe|5f>CP!_O{Z15Xm#KO!v>zjKiVezBW+$L7+BTLKvR6i|8=h)0qw&+pv8;ZRy?@tzm@#1^ql{@|)>;3a zu429>!u#9?##^tgokPBc7&w|-Pq<3n-ECml&kuAzXj@PVZpDgt*ZZ>e$h_>AKY(#i zM+--KXidN&%x0{h1Pe2X>~ZzNB$f?vI$x9GU|FjgvIo8imf6dXk)9MRmS$5NOYXjG z>f{F+cJ*vp@GRJ5o@9B9W{aUxQLfY~sZw!N9o5F4eg>{-aPX&5@n^d?m_N4o{(&2S z9pVe4Of^`1t^8DXQaz)>PcWlw1kQ9L5W;?eU<6wD=>!nCgf2fZHDr(f8X6M9rY&C$ zY32tL=y%$fi|{YL>*9R>X{87cVY_PeieXs6J?>=$nzhwi=dgNfa9XK2{b8{4WP!*K zSw5J*wTAioiD6ud+-?FqS#>8+62~|+lY!f?zat)v^mJ+zmqobaqsZKijV} z)!HM7_H5H<2>H@0_E~eqzJZpFSr6!N_6F-X`@oP^qG?Cagy;5%e7xvV%veh3gTTt| zp8NUf1hinw>s%x9^0$o?&I2`hY2a>O32^A2zOYpS3mb_hXEN)xM8zX2MOXK zm!L3Uh?`7+1N(oIG0`E{!kG2m%hOey!E@9p3DyXW z4yJ_;bTS{S6`jm}jyE0X$SWjc)_H`EIqPVaKHT6)a$g6a3jGjqWFX;q(}9A#9XDpZ zw8@3SGwjYCTu3+pRe?fgpI{U^#YLJi>l~mkGA{3K#^Ez_H-?lGUxY{eOHMUDLjBUL zeo4?T56;hze~&DVGDAydK$JUS_KEoX#3E**n2X(?#~D(Q?xWz2HqYYq_~K@4IK<~@ z{?~P07*^&GFKpg$!h4%%|0$1Y%Zf~Dvap9cp}m?z)2mp13QdY*Y9RJwuiS$WN?s@K z^mfh>+GlN^HIkRq7AJYEtYh&4>i;FarQ6Tl_zv)~Zog08tJ@^|QS(0PgFZ|r{?CPJvZvhZKn=gS@uBwM zM-lU;mD_z_ELX{2$IxTv1xKyB$m{)IkW&x7oDC$()o^7!xgn&U7` z`^YaJ(cfi0qeQ=AU;Jw-U-cs;3!Sc7vw0SsuE`(OufFGKO8ZAJMVhh*G62d^>tLXa zFJXlb<$jP4S2TOx-y*X9Qb49xHvN8uw;yxe2l=l*aoe}2th@k>3JnpXkopp-6zFi6 z_4ahAt<+n0zmi{(^-X93#feJ9W7b7bQ-aw727sb1@c^1NZySt=sI^=?EEc#!kq}Gw zJ&pVg1`U*HF%e(n&S!Gxf&7{r>HZrVj#X1N&o%=~&X1iy2;>-nWm6qQwQnSXQl7d> zEr&^w?mhu`nudEL!3D(RkC{zW5X2ZWo7(Tg@amAdl_{Ygwq9ll4(a6sh>u4)|0jAm zPwM5+4b|!8q&Ct^o5$A>oGSEkQe^%ARjQYh+UPc&P#P#g8=ZoSbbmo=V<*6Q#(~yH z;m{0ye2IDo)FMM&MN%bwjIcgFA|4id`QbuNn*``1o!bvd4{B+3;$6-esmKkYiH&A+eg;7fSsGZ;eKB}-yyO-jpx?+ z_@@+{k3`nTsoiJFw2MX7Q}a(aaily z@jG+#m~|hTuPD=ga%BAs)&8mq+QX>7ip3g?H)O0TXg?*g{w~%2kP6yw8Cm~z)qY9^ z?Wac8pRU^f5w>eZM(MuIAJ!uv{*Y)GwQfSgGJFBvQA9XQ=URqan(qLg+flY(R6%?2 zeMq(6t%CM2TAix>%SfUG(h0=h5DlZ&y=ds;cbOkx^nX6W2#2j}s9g{CRnW)g+kBJ( z7tO09jB~_X{lvBIu0*jcnx?EU^}*w;RQv9u zRr_(uuh5H+;fr{$!P8Gd_k+8qMLz>*F8e9bzI#8_zE$;ej{0&McbE!MoJb#=f6Qkn z=r6>}3F}}q&2-BPW$bqIaSWi%=kA}vV}q20H3iLAWV)q7>-K6tBP4y5YWmbWM0F?i zUl#tc>ZKpyCGO}Ne93gv%lLTufolIwy>dYn{rnxChru6-mrBq*{w-)K`Lrd%SqHrv=1V;UW3N;%bP{aVr{MNr&>5(Ucz5Yi>yC*8)kgWx|dQMUH8YW->5IQ;ESX`;Qer9{SI5p_q))# zyq(-zn30&Z6wS-|8}RBaF=k`d>O%n z>l!o!pBk)h;L9|aIfq_!J&zjpEjFayOV62~jI2Kj1p#QBw9ZCj%zvguUF|o_Z_sw; zEY&zkxUe3TYTtc`Y9H3^rJCB~Qpowkk@ag(YR2OI%Ug_p)cOOy1kk%xWc_WpnhWjW z|5W?yg4=H$SszyI*QoX@gWGQtS$_&F8^d3SWu+sOJU!XAdLStZ&<;K#7^33y@a z-G2wei$>P}UA23nM7!+}=)goXyqnODzg&kem&yRy9!K+IT7DlEbKVB411*L8O11BP znr4%vNomnVgLM?Xu-vC&R5|oY+Z*WYJCGW`7uEfgYTx}k)js#8RNX(TFOT92#lZo3 zGd;5YGXlxDbv>G9<_fgj`n6-*h0LN$7~C=5eSb18-l=UCw>ydYe{g;{`V-77FnNaD zc+$KL2--Xg6E=JDy7HOnJpUR070;?%lh+%m_55&p&b(=nt41TYji&F;ZIRy4AK$Z+ zSi}`4m^=;ny&UQO6nX;yAd(++B62Da6i-H7Pj=By23${a$RKT=CFDL;GF0n{^1~3{ zMTk^+p2$e8!IA3i4Rbg4VXkBSdNG}T4*pHWXm!ayfoXf!-;m~cds5r(^#1s*%n^H@ z*#I84e~Zx$#Rz!cz0B3S5HiX;=aOu~DJCI!Mx0SJTdU@GWn2UAam z@-kE3JQi0oK#e+CCy*33Q%#ZXYZ0+A*ie&ygQdDbgMWjqbc3*egL@Doi7p!NBUZaI zCfB^mdS1-kLJv!3Oei{2RP(;#aT6<{!I%yf~J52NdiL>tk z9tH3h*5m(zKbnSVqhtKq@fXk-B{ViHk3qGQtk%mBLkQ(a{YGKf{(Jr<->A8=1eHFk zBzDh%I3Nb(P_$&{cnP^k_xBkb`A=_rtm1+#Rvv`R{FIfa@kWF3EF!!k2x~Te-Bn928KQHNd*OqSoOZht$2VfoK z4k$m@0k@M78X1bQ4nkfk()}M;9qIqO#cqg7Kyu)pC^a+~7tR6H;UWWjxnQz?Gea<&*N1VWL-_Uqc&a zIs;wKpb*c6G5w~G#>1fFB{3L7jb1u-*K{1>dVd4*QA!^r9j$kjpd)V3aR53L;vJ$_ zM4TkzxgIK*#m5iNXE#aGZlZpe-$}{u_M;WQ4|Bb5t{+Znqqr^{8+GG}(HbV6U&&a7 zhp7W&cCr&X7Wg*Ns{&sU*A)s3jC~t<4#akgVY?8h2?L1WhH5) z2kJe)fvx5F|9wTpcOHN9;QT_7<)+-Litqf*(dCMiLh^3nLNMY)pEu6idakfr8J2-3 z&buEY6z@rEM^hUR5VxL8sr{B7{GmsF_WP%b&sf&XEAEdQzg{nXwe7c%8QZbb#iAyi;{JNF;wb*~J5_Ax??K_iI>72Cjrq$`|sJvmrBF*5+Ij|e6vi7YBNa?U9xy+E)e-huJ* z7s(#-;+HsJ0&aK#f(#6s*8ANn%8~9Dzyg99x)j+_`Y1c3{pCAkgvh8+@QMVVfVb)A z5|1g8fu8riOMXwhN3$(V>In~P6==YpDb(&jcdWC-pKQ>#&CVkOH=$;S^A9vFR=gzof)R~YkhZy!99 z{%K2h9>mOJQ4ealmP!%9Z@={j&GSLD-}ETsM>x^P!`~y(25cJNbOZj)Z5ojB@WhLT z-@B0bg&-vNAn6zTlZ5mqdmSnLiRXR9n{L0?@&N0nosXe#MEUO=v`qQ$|8OY6ba=)Y zSUSjXDzoElz@6r4f$KiVH(f3BO~VkCi@y1D6n&-QOzGFt%pW5UV$v5Sq-A{a8JoV+ z@|TG95@6v?d!*iY*0&9L&7#-5`J4-nKt88iI#{I_JUs0942)lNmj_` zn5712oJb0~(1NIqbbpg`X};@nT2B))G1f>ONuJOE_p6_RyhF@ax4e;t($feU_+lFI zSMGi!2aig-)JoOsh;e$09H-fbz2o%s3dd=J#;L3&t7M$!Dj27{O^(ND$?@F15t;z% z$E`KsAHL+QmH3kJj7LL1K1(ezo`-(#(f1RRO5cU~(Dnm*;u+7$-_iS~o*3h~_aR%h zkJcZn_<&eay*Yqy>BAG zdORx&PX#$%|6|B)4<6Sd*%M}-t${7Yt|u8khOKWOs^Z5o#-^oPfJA4lqd9_|E#u-+z2REXH@fg7GctHDv`@Vf+#A z`0jy{OM5ESUF*BFRnB@*FruKwxj2DK#{kNns`th*V4~nbv<3Y_NSM=$y3c#>olbt- zW4{qG#vdhprE#DFQ1F1$Q>tpRJq`mLoov*(!jkYu^-pXcpf25c-G!oGN(ai2gWoga z7UI{+832$UAVm6*(t96MtHL62lwaNo1H?#7_ufeW-2E&1w{zrtAH4@}%EDV>+=^0m znejLocobrfxnr9Rl7lxp97ifZ2^`bb&F*>d?7dZtSOXuBbbTTC~eENWQ55cz`yL)3})N z4C)7U4l_hM=s&e9UB3w#UkMHYt+4eYG%r`jg!X5s_H7ll?>8b+k5P)Z+^A^ zNphy5N@QpF5s}>{qS|5w7`wo3Wz#1k3%)LUi zMi=F|eGkm2jKAD?Yk&7^tY$l6zhi-jPkpu0$1Nh=>*y6kF8$-wvuj7uR(Kr`!(;r= zwTecZAoRjC@w^$VHg~c-{wUs5D`?TAAj?iZ*<|HlCiz{vsOnqvE=BL+Ejy)ZzxA|u z3wWmpHK`=zOV zFIq2*ThBkj^7g!ke4>`O%u^MgVhP)<;5py5LQ`7_s3c}H?1PlI+fQkEv#|v-4Nnu$ zm<-i7(K2Or3x^{>>wIj=-+g)InaGnGBG$5b7UyI-c8@n<>4 z0f)-6;?}C)`_pgmtwUI_P=n|nb$ncDLexjPMV*BgUmyMr@cTv{hWRJgeftgmt>#J^ z=AYX>$@pyhNcRq?j{sH0oQEr3yZUA5ztH96GsMFZqq&{rsn-FuT29$ZsAVhbjz=x8 zl?5^(cif@J*M4Y$&AV8HXpd@jPgpn4CdKvErRw*n%9n(fXT)XQ$;O8S?eS-cni3=P zTcTkh&1hFNGJnctHg3Lae6B^!pW1}1>4;hXm?h|NzbEAtjdY(yFM^OE8)sVeB`u6v z{~8kn<@sSL@%)?&S;{lt*ZBPxl?*=k9a9>=NTmBddJ*_FKBswVQLl^ZExK8*q zs)eL}$F*K0t%vs%__^!0wY+Yk_ki9QW59KOF}Wy}!MpDHnSO7rd@uAjBCEZDi){{l z<`n`~Nb--`(xLbcw^%sqvf?nA1*`o5?meG-f}p7JQBh6YEH>hFZ9 zVV@hxrAYf6C*ab*oeo`;@x*1ACDTX6H(EYllf$W#fi7oIh$k*P#o6B2&%OR7sj2xt z5FQRXx@Ral#$E6G#6{ufOVBY)z$G0AphFQYrRf#^mFlcjJ%_aZX=^IF7xSN9WUc6< z=r!?wKuWyR#$VM(-M@#z|5?}j6auI?UexPE$2|B$S1EFr^*Yf;L4*7?(!CjL{(_G1 zKQtYvXTiJyn|b)7@YVA9k3@Ey<-LsZ1V+@#Ad4D!Vun#ifuw??AB@6c z2SaI(VQ8jYqmQa2sop0=fs6I(Jrsj<5&)mLrO?lM?Os=k8|#KVm^mCd5@aze@`)EJ zqXGUNd~*9O&8MGn9fPVr-dDu-G3(9Ugk5vLC&&MXF#cuP-~i*nw#fD;-8W6=;*xQG zSZ4g&{zR9bx1)PD>a1#>aO455dLn!6SwGbEqmx8kbM|qiF_G@W_%(t%VEpWYX}+#wzH+fYMXwFkOQUQO3n3;+nc|WqvbPJ&%o>^>2`Hgf zBEVZi^KY)#Qfoi7QU_|oX+bT}pb2QC`$kdKg(q>>le75=^u?2hGUDa;Q61%&!A5{o zP(H^w{&~Mk_C?0sp4aiTSj;oRV_BA$#&wM-#e&Sjc_kfG{`Ae~mj;AcDAG$_Zk#XP zHTieeT`Yyrfd3mWi0Uo#jf3PH9sX}@5N{BdU6{}1Cjt2rttTHtE0MhO)HA`cF6w)O ztLfp($v)b3T^{)mpY8gen^pY}nR7MQBKxD((Qx=uT%KdLdIlXjmd_VY2rb6>R|Pr* ztGJ-=NZfaJ>TC-tWZW+?(jixHg4UM+H>Tk3LU0S=w*_2)JcL2MW`m?vzL8D^lKeQ0 zXGNO}->8E75rSJxFkAuh9UCP1>ycgw66+Wh!%G|R-gd#uXn2*=Jy?$JL6h#v;f|Gq zJ7mJGoc??X`iC|BmFrXZol5j+R6?#CZlWT%V^zaVR|Ge!mr2Qlz#_b;(c4rZhFTwyvqG$n&Fj;>#`DZ<#K5$f#02=)G_<#YOt+R&Vy-ixszbH#V+pK`|OopPTrZ_Td}yxoJO4`!MG7e%O%z`|`QT zU(-GuvQgj{WFO9v&&~Hu`!L}1zG)x+3|esO zh0CUlIM&oC8;S-oRCLR*xQ^Bwn9 zgh$4}L(8~T;ZaV$UncpEOFRtup6`_J$AAmVSB+C+9N6+Dz7&R7w(}udET$~z6AaR_ z?U0DM;gDQ2Km&CFq!`9JoTwkDh>n3N9zAu@arV6x(~21??wb7go$e?c}#sDZYL8HGnha_yK}POewnU9nsn zfDaXrI`orlKii)E5^`+-8bNZch>p~>a&+83S}`4sest(@Hc*0&VhK8e@?Y==;-2@* zVU00ZbD6NBC6A-e)F#Os*8#kUHrjrW|F`~im!wPial?M-^`}R9{i)TUD^DxfB&Y(u z#2gZP0TPRow-}U^%6%5(EbvkA$*yF&A!LH-I$J9u=|kxqxW6 zRQqP#UfV6*z9PM7`jFyf5mfPtyvuI=Y-7cGkumtE?eAMkzlTcbMHFZR>32o;A}i_e z_p8>O71^yJ;IHfjZ)_qV4@u3XBvKA12$4J0Re-P(2sQQ3EkbaJ51%FvBb4o2qQRA$r9Ma$~ z*cTB8K7}q5M8l}0f&HkvAJV(l4=eu1p?AC~p;PIdU;A<0UhB2iJHPf}up~&Yr?}`Q ze3I0j%a&}1e7meqDxue6-}yV>FMt&Kw^njcx*h3$44t9ChDuB3%-cHRb1pA!lE(8W zo=<6el9X3%&!vzWbwu~L@l|z1Q`#P+=9?Z9_F!&MJ8Zl9I-a3zc+>SOyyq4xc-U?= zDBD>bDCnxB9tr!3uHtua|IlJEp%?=bP(?EZwM1J7T)#30ur*J%^y3NnClX7Ffi2q- z<&U)aL0x7f?h}$sof-&$HUupsFf9U%vsxTr_b!z4{Gj*ueweM<5lR%xYUzy#H%Me@fdYWpGEcx|C;CC^dBS9ewpCeIJD$4a?(f}&Ezi7i^)ZfAYiLEDeY-s|0 z0XEgcaSg7jN~M}yI&(RW|5L?$g5|aWx(mH3VJF4;J3l5v0Xv!8&O`e`>}R4eLm!2g z9EZ+xIZRy-vQG%v`q2gB&ew`o&9Bgw=DMAWUr_M`$Vh~U3>WX{usgvz(Y;_HZ(xzE zBNh_t;+syA_yY!bPIsAz5@PV5Y;|JOp~9{YLG_3)$A;-&=SS6U)2~K+!1qS2TaWD9 zqB-rM_S1lFet37%TiiM>ql3PSsh2!Q2n*0sjFQ;S)QXRkpx0^Ks*g)9*qaN4NXwMJ zBG(V*#M#rWzgawuZptyk$h-X=t)rW=lI}|>If;*g3xC~}!rpC15GqSM+Q4J9!+ zCE``p&wH={rTUpH`}w127ue5Xs-K(Ca7D(Ax5no!)o~ZMo95=DeeUy|`3am-Ae!Tv z5z+rN>7*2$ph(}_(7l`3`X96QA=n(hN$_4dVSnlzu{A$t75S8gPNJvO}ElF#78e;jC1RT3j29e$SP)S z#@=9l^DTT~eg*b}?eec;62`5^xOFEXRFYqptA4&C`bk+|6JOF+H-kupwqYpt_<%ec zaL$L8>H68~jV1W9B2%t?_nWloxa{#@gQ~r0GIwei84;ab1$0-ztT9 zP;?TvHu9ULp0=p_n-qr*t!59 z$oKU#*B1i&CBS}_#NOvTdt#+uY%-*M9P<8`fY_)Q;mc zS?n9;VR{7VJ}R0N#~6UmyvdgCub`iZlLGPChV)nRBjJnB84{nwE{xBX4t%y@d_E=d zX%_gP$ud0f)wU6_(HGlk~JG660 z$oh?Zw_m(#AITuzU4wn`&{c}Tal;fmxbvt=m?Zufdav$yZ2uj!A>2QmbVbeKBHjD* zUUJgJ^sYn)QUK6DQeoT&3qLFqX9hfo**;g}ee@>I)mTg4z>WfS;GP4=F?}VVk?!re zKkqp&5S zw|N08ITZSdQHHpWWFv|DJlt}%<0imMvhFR1q~{A7eylJEwQ?j)C&kcx8GiSIK-Q!m zI7YbP?lqy21nm5xzV>nKL&~``baZs7@K5FDPhHc2@JNH4nvkJVfj1pQTH@Rl`01~) zj^3Z&^f0}*=>f89Dp#TPTE#<%Q=U-mzvpxRv}%XA>2Ux7#GG{jI4VHo}@~vwt%~%8Rk~tb=2C1At4^{(-S@JrmVaeTDRrOW1)4$)E)$f z%=&3H!?-vu8^jL%Wd z#~&pEwL)|sFE;c{5Ir`V1kW?W&87oGuYjbfLMXuZAF<#t! z)AMPJ(;ta>M|cxw+BV%=Zv4M2#&vkp)#xg*>6`esVbc{dj*dFVH`vwSm~ZSz!sOvU)4?1!cUc5Gi7Jrt|IFWw1T|Hc=AS0MdU+fKzhVLrr> zMr@HSfDy!t5xX9c$ltr+NPTI`s057`M$C#n2VnqY?<^XR9JoVm=274twdNtl!NX#T zANmCDws~qq*J}O4Gaq)}Gc`VwO$VEqUog^y!l3ahokYpnmJgG*`Nr+=Q7U1`aeEv* z%9A}&aeLr79u|*7WEgd{hgXx(i}B0xdWJ`VJ6^y08D?ibEI3v^ zUMCI`(vj{b<#6}J7AN6LeV-7gK{LLdx70l zA7yXUc%Q&|y>`C^)$gGQA4gj1(XYanY6Izmbp@_pJ3QU>a(GdnMG;Wf%kcw8^IvSm z5fEMXCDPraZ8N}y!sru7E#sgYhy?rtKMK|Z55?*D{KDp00$M0k9`5vDxVI^|U)FF* zPv}3Yg`|&M590|#q3}3iw7dxH@(ug)0L1uQh4X!oeI^X^)>(75SNrF=0B_0&49*|rX zvpb>P^qsq3gx;piCQ^zZWx*9|XTOddi9yQMM>t72{QLfO0=mwO*Wn9+bjaFGVhfQZ z{GboNSwBtyP5QusBS;-I^9_3Pt%SN=(AG9PKX>C@N~#G+)i}$b6d%3vjqdL&-}Q$( znKJv@|NrGX4pMyNdq>hq%E{mR|4+V+gt|+<4=DMjADn=E3m^5B?~e|1GUb?S>LXu7 z)Y`XE%%<|4urFkPBkS%K<2WgcS|U9^#t#UF;FXp|XzXVDfiZ31%aN7HJBM?24-Drk zPMw{l3LT7=V)kQN=D3JKnx~?5|DjIu&i<~fUqWa6@v~1{|5bKeC-FXpn9L8TxRh$n z>9c6VDz-w_R){#@FWt`#6SkTbbW515#aFb=e%-nkQKQSEke!Ww<)hr637>3?@;epU zmDI<*dN%}r$X;k*`E-w6$+U}p$#2M14dX%UoD?HVKN49t8<>&NZ8-q?M=PB2ic&Za z3Rh;x`EgppJDQ=0yg0$-=^oB;hu`e_JJuiHK}|~<1mYXc%KZgefRl|{i8z(AVF{-Q zNMnYRq!)clXOEH+jgiXSfkn)%)*itsHo#;r@>Q`6d5kNdhpK>z{1ep!@tbkyo7}GJ zzC5oSNXEsib57NaYXqj&`QMpI=qjCGy^<%fHaZDt{DQt(&>7y(@umYEX+L7PH$vMF zQeG?f?U}?!VCj%Vc_q-)~`syTiE89mBEv#w!3#Yj%}l3(c@ zH)IER+~{@wRnRufWe>)@1ml-J^qlsb&?hiXYC331=&l1Fy9k=Q3Nr*9D9t%&do_qS zQ2NWa$Px))_}9-4Wl7V5?GXES0#FfNg#f&+KhTNSy#Fy?y$AdAYbzICH(gaXevz%D zy*>2N{)jH9#n@CumXV%o>8W9u#~XlY30E|(Tv5{@XeYu;(-j@j;AHgE-<*lOFyTNS zKlwjiTK>`-G~jJJzAT!h_Qm{7un+jbS-KeZ&-JJ zL;A}>2^T-|hw$Zbr}AO2%U$@5DnwQ;1S54YI|L?bdz>F*Ccl4{a8983#Yi-6&05*xGAjoKTp&a*p}lO?YoAzZY`8CoNFe z`q!PXKm}4AKB zOTj&^2Dsl1hFer{-x^kY2&${I{(@bT@QbZq68c5DL?231^LUf_l-*#vj4AS}D25;h zt4mG@u{ku>GwHpu`HkoizVoB?`#G)l?5~kQOaY?!_}T3V-NMG z8UtfM7GzGt#7b>!Xx~pe@dRG8ikHm{<*bvJp(xJECq; zd39oDt`nk{drTJDjy#9FrHI<2)|Zdhjyz5nd<7T)o{kCN$d|Dr&o@fJnDK!0=27dU z+sK=ve1W{Ve)$HPoDd@U;ll+Y=F8HhN3C7(GR@C z;JAK*rkTPDC*OS9eU;jc$#$fp^r1X}oCk~jYIorWht0x5ZSSW@cJoM0X@^%H28^r1 zZTZFUmX++A8ESFiLGokxru-(geH@I^;nIi*dC-XwDh(lXf_|db?-oNwM(ZoM_4p?p ztuw0i_t2WOGL9vozKW8xPNEF_tAUSgscm1)zi^9sNpe?>GXk5V;s^29hfpZ*!WMXYwlW#TqrsNH> z0>5Y9bQIQ>TnXC7fPT@P9(@N3e%f8+^0JEpWec?SV+1CNvGHGN#?ts_`toP`(^tBm z=9FNgryt^_)w@vhQTNj+`%&w}%tuUf6(2uuc1ZOhh7%{HAtIN=F(49bYQ`9WMRfk> zQbp+6**PB5hhva3TSJjo6($CE{TNJ*3wpx{Kz+#=Er#^A}3bDk8FCL z;719hw4j!!wV)JYf-j8*UgYZyIf;E~58+1xw@A;=@Iz_*)-*t7Ns?K1ED*;dc_}P3 zA2cA;$zmx?M9_Kb${E`$8M6C1uv3Lvut^(hK1Q&ATxLv{ zl47Wnf>m~5Z0^P;QjBeWt`#E%{;{v&`scCJoOqDEAbi63Z;PXt^%|dJfe)4^oSVFe z&0|f(MueAcT;%zKbm&0aY~YfnxZ<;)*1C{FFTkaU`#mKd)Hi*i_>aDWAKIU@U#0%+ z1n--Nf67kPxDvN(Q5&uZ|ia(Xd zKVzRJ+0Y(nP8Hel&oN+=!Cevmv^ZPa@ef)PCv&Iz(+NmAKy}4GAkw|0C*q%*v`)sg zoH~8rlTA>5q{8)_XxiJUHb&WbT0vCDnXzSpu6o2jX5Y^E2iGLI|~KPhaVNnimK*dioLZ&(WHXx}Q$jk2~&A@~bxfVFa9Uh&TS3>J$H* zEa-LP0eZ{DKgSB1OT|Bfn!(D;_XhN*=&m;YDT##EW~lh*q|*GTCH`3?_)!8WEvV&3X+bH(Wc*{` zMYg@(@lPO*GX6OZG`QoR9k+MJKNo!v@z3XMd6;xVA9TD?CjMD0*zb-x_@)F;{PSb2 z7%6bsj(@Tz`rv`MM~&OBm(Mca4HiiFv@2t?|IhB<41FVO{kJ7A*9b4ScoA4H9T znC--@tb%6T{ zW!1sQbTT%DSFA6!Q$jqHJ;9$YT~9x$?NoE<{T4K02j8-7SxaKf$i*OQ5zRUL^V&IC zzyf_2CjhAe7LZ$1+bW^O&DjbvYriy=t@S+2LlRE6*@ z7J)C-()^uK>3fzG`)wZgH``@RDu!ZwhCVC!QanKDF7e9*YoWC0UtKXzl2yMyihuP zuhnSlZcKDi$P|zB(o6U&e_G-EEvpDqjvRHqL>P~msE4>hrbG5yf`2;BJVNm=+weKT zzZ^M2SBa(afmv-nY^Ne)IOHutvfsdQdJhrr@&mmmRW(kNtusUYi=BK``fcik;RozZ zZ>%T6A6yK7fLo+!rx0KN*7x{=zA^R&FxZ^_>YGovh6i74XLE(bJ@$1h!1dX}LmY#= zki^4}&%XYlqY1QD;U5;B&;DU>kw3ka`G+_&xSswY=E6sfW2M&<^A9mFsXG7AyHN0_ zD!mJxQkC9~o;NcTm;F@eA6$ADKAAeKQSTndMc!KPGRF#fOX!``Z{(QPl71t1?#xh1 z!mZtJ^n=EF`HdC*%5MxVaO%I(H@DyDknQ~VLNS|ZA8fzTvCQi?#>sE|x*@=C!~*cC zm){spd+8s_-84`oMT zSH!xEoX6T}9n_`7&tQ5vK=-dpNx?K(11n~RLK1%M{v!)oYxW-q+{}5$-rrFEqh($V z_9g!Ls^mOyHt3iAxW}96cRrxF^cLJ2ujSl&bd~lcdM0SCA};;aS!`dTvL83SmD!hJ zR;+s3m(ID)ac1au9r6}KP>Aa6OCeQ*-u0hVmEI-JoEhqs{kY{&ncfYM@N11r563O@ zTJJ)^^a}ej9hLz|sURZK^A<%l=7i8yKb0MYwUul7o*YEhweK&NJ)6|{UJ?@Kk184G>ms_DW`C<>c9Ay1sNpobrN$pAz_~ zcudKcs!$1M;HA@W2hcnoc?#YxnTvxHgja!5!a5;>ny^_^0I@Z|%l>7attj$-vOm?2 zd;Cz{n@)`Q)V-BUl5pVp8SH_SovTF2=qH_YDtV|ptD!Qh?R-UUg`lzaxU*6ATb=)J zscL-oo(}(iq@YjnwL1Slp}6zv7me}RB=J!C}yVA zzfhdxPj6*@A$txnxSoEY#f6VsuP2tT7=uDo=NHD05d5i1?}olumEJ{{&kVK7ernUZ zVG@3=eqqlS486-A?$if^|G{x*|CgBFa&c$kRQNv$U+J?NUzO*((_n6GcAT7_Gw%F( zkBU1B$r|L`e{NNBPAmicvY*=IJR$pX`16LGi-!q%E4DAa=YiHL?8}@}*uM13e%$m{ zW?veZ!S%E+VHZAze%B%HOn^z%*_Vz(YtXys`BmxNP}9s%RQBVR1N^n$daNrS8v8PJ zSYtl)?wp}_y`KoAx7N5b3F}jF+?j4AH7*->UVM^_JI4!j+K1N$DRF9BHy@kXNo(o0(if;bL?Qj57m!*{CrSxXIl2F=v4A39d|Ze zAZV;T?kpbUl)tL)Rry^$0m?q|$2dBmU?mW-iwRdMl#y_%iX)0Es~YEHOJ{}>vL7WM zh!LojXJE+znt;3p?3)v9)^7ij$fO; z!t|DlUt2yqGc@*br#(<~Rvy2G!Q9&Xfj54AWvz-|8zf#;$+>BDRdQ}=1pObIh@2;6 zUoIRsfV_(5fst=|Q)sYjfD!%G~fOSH* z*+2hmZvq`_x~L4Yf}z;@Mb%M!LYvwGdEM1|3qT48h`=p0lo0rlouLomHw*s(KOye~ zumz54b4H|RYy1$5r@c9Hd=R3fc}w28FB0$O3Tw5LQTA$Q#}Cvssg#ek{(LM+xf5SQ zVTq?HXBv|(zjPQ-)oI~dsm99Qlg6x(8?LY?ZAfh)KRJT(1N*f|&xM>8F7awcy}Adz z>fBZ;@on74<}2Z>OAo8(ihQ}+zqf1#;hjx`N2HfIlZQqI9eYc6pqb3? z+VxCEmA@fhKfbr-`#Jze+!< zna4Ems)j=fb7zLavLD4) zrT6~>zjDVz#`x~oqcopAekI%kTC4CYBPsSPG1-rs-pc&SP&YBSo_?iwcR{zp$F0{B z^DBc;i0b@GaW{caReG1{txE42j>1M%*^i>TI=$;B;n(U{=00fXT}a~L7k?W5J+e;i zV`}ZAu1nUVH+~BFzg-0%mAz2(Rqjs`U~0|&r087Neew&+pTs0yitkF_-1X@BU4qBs zo``!)`(W3jhc6R2>#`ke_Zg;o^t~qQiBBAF!{f<)Oue!nH$H%`=VcSw$CU7aPx!02 zt-^Zrenps3k4}VfSx|bCo47(|aObl8)AKpoZxm%W6Ih>#iGJyvdc{+G<#Thdn4#&8 ztlJhNoWg~MuS1{tJacvI9_~%VGt8`wsm1Y7`ANJ5DGvP?n{~1G(c-hUccur$jt%sH zj))O^B56k*KS(lB?gzXFIS$OMJ?9|8FtQrUQKrWCkJ8&?QH1g|qaCNea!u@5DSSaM z$XU>)VSM|Wfkz59+Ji^eeFcb0pu|0=sOKAx;GP@R#_RLZv*S7->T@`aMG;C#jL~1& z!HX3>*lLy|3>cSTjSH@~$GPl+Cj&fBb&>ADrIB#iRp6qF;&4chxTllpE?}8f&g*?h z9_MAfa@|loW!-u>ldQYJ35E;#h9B;xgX_{b1>@6AGpd_Pan{zCNYAd=QwW_A=No3Q zhez|r)R{c*zi=TAE*A%RV~gv734esISz0ExPc~t1sW1E?-WTWsL-1R9U!wEDNC$S8 zlV#%g_9J2(%>~owL-zZ598_rAZ``}sjEGg{Z$@Q%%G;35H}U{fm$vd?Gc;d>edCMx zyu>xwpSh|*9?rR8UP30f^49l8g_BZanCvutw4L7KQZY}K{Ra6ja}e8hdI*D_e2ZzP z`^ipU{N8pdK@~@Dww-q4QImb{)>8>pKA9QbLGamxPyDOWJ|{DhAj3WrL2RD~-*pp( z{X(+e5`6Qq&;7ES+U@i3_JUrbkv`Sro$^Qq(p-`B)8rSy(R#57r<@_5*DU)fL7&bW z*?KW{rB^S~q!(wu<7Q#NeId2zMG`2>tfqQm^bSS-OngE<$1CAO0lYXi3SVg{pl8)rFa>7Z%?7DL6aNNi@ z*c;JVDEog^D}$MDQ1VcEPk9FVK;N`4bJme3t`eg6}lJkyzpLk5gPT{DaiCwQEPx)S4A#-Ca4 zW`3cBeD!kIJaeDGSp3^UzBo7J)Y+v59xrWCl=!;6@jnICA?KD!Y+L)dYXY;>xXW!* zJDjKiCy4(a__+Jk#lHGbLM{R0Zs0os<8Bg-yG6^~q8Ix&KG1RZ=e3$PLM5KP?VEl!4qF-xmSU#pn(E!&D_K%+6% zUYuJ+e~mZuUvi2!N+(#2^XzU9dRmA9B{Dw61$|rdwD&b|SxtKjNmdWvr#u5q15<0S zk3usIWN133FPRw~_@>Y>flQwN3PNUp&7p61Ky{Rzq0dusT7DedF%3LT_xW7=TrWq2 zax$1RrnU`?jdKP?Tqzd$4fg{knP;E}?N9dwWx_)KrrhYe$&5DVI`^s>z-k|sQnQ@D zAbjA1qn1*TK_|b6gaG82?z%XvX5lf$NSqx-r!^@N6>|*6{lJz^&wevQBfWA~$Orgu zJ<=zlM}h&h3}wD2(t&(E@KIRbmiNF7P80OeJW$y-eC0gMBvNU04m|1h@U`lmFO`GQ z_sO+LI1mtjbRH3X7x9{45v~^Ro6pzV?t{C*`i*&PLcVYEnP6cGx)Y|L5pjR+s(o;8 zJFZ%uH-q4SMPX~#U-ErngHub;0m>8|yAU0{-}lf#_zW8OG)s6MdeA@SFmzWL?n}Uq zU^%buEYbg0L5HLN@DF_ZA2#|=R?`0^xL8>BpW9N{!(zkA9*>~3pm4x@z2Wk8|I=ZsD4-6`6|Q4|w5^2gBc~YWSh+J^1H> z;YX^5-|U5-4~7q$RylvpAT1wr!pFFgvqs7mS+C9VKgTtyBAP$Ig0P<~4)Wd9wu7Vd zG)D>&Ro0_2@`|jxpM(sYnt$ZrDeSt$DNZ;o2TlwRfAB}^hq_k}F<2L#z`yIf(?;Mq zh5UJ5;7L`v59)2oH{cIOUf2`(68T_L(^|nE?9x{qdg9 z2RfNKd+)W@UiZEB-Xsa~WfRijbpTH~#4mU05bL@J-v?>&rTs$Y$F46=U3!{}#`O_g#@R3q*ZZ8H2)*FO=zOiz^OmjE5e zFO#Q3po@-4)4&mxFn;O1qL^Renrvo0#I)o2!F(_=R$uKZQlI-HkL^`w|Gw^LYN+yt zns-s$wrTt+ z)ndHs9XPl6T?*da7S2*~SKMF9>8}v)UfW-o-w=-Xz(jcWxp-IJ??_?4|MZa;diJ~h zR*rwp!M~860~Y_v`-}g{=c7Wt9JKvaj(3gp=kU=h1$d`jyesdwzOdgy{v3AuC50(V z=5gfG=JjTf?=#K1Uj*0YR+{tYk=L^4Y&EHRQe&_c*1D<2x_o@8-=lXXO$D6q}AN(Xw;eEwNCp%t@ z&g=1#J&)m2;*fOq(rf~~-&vjPO1B&c4=$H}5cvQc0Ds%gyPXtN-W0W+*!zVKRA!&lQdL31>Xs;bq5L`-$CQ?boKvP~PKaDEM8u zS0_8p#^-&!g5#Vo|8~B2Fy5nxZ@=BIOHAj7xlfS+o0S( za6F4nKpnfMe#7kHs#_%Sr|%zFfUE76)gTb(Jp?1ko`u*VH9wQ=Y2|$c!{Wq$44v2@ zg-X@CdRIE&b&=UxiCO=D)ogS-A0_h(6UkMr=$h60qcb})+s^68Pl~1u+Gs{ z@Fu5Wa5>OFS92BDe5aDm`QhspL~eU|*HaP8sT-@l*am)DOk(G~drwvOmllrS@f^bC zH!#lU!0jluiKC}T96e!^pP;fx;*r!j+W`wa4%~owK44x5m|H=PGvm6i*8h^C9V95m zuG2AV16rcvXySTwj32z#xQ<5(;Sms4Eq426eiZeU|4Q~eob1_%!=*ru1`~To95|`9TaK8DQYu93%AYq(>$2yYLS9@WL`^cu%MZUY3ak;oZEE@cP$x)Bs-I z8QQZs*@IK<-X81H&ep*ws>c`@T?o8==CbvP*K)E3kL zQS?CHi^`wqr18bW`4syL1D2uz6Zc?MYn5sYjT3{FRW>Y&jv91(no-RX>_*o4xV8=d zN9|Ah41NVf`99cgo<;~80()lH`Kok3(is0E9O4g}{3-O`R_uaXUgl0)liCy6%MG)$ zdAb5Uys2j)Y?1($b^A?^Dg5YP@Ui$g{oaJ{sji@VXxs4b0K>zX@3nw()xs(oxe=;2en0_%zgw9r%usGN_nUTezX{lp zp%lF+ESR{7I8JeL4f|dk7w@1|Bnx^g`+~yT%n8Fjem4Fn*Qcycg@wmB5YLT$O_lS& zKDh0Os%f`JSUd0Suc*s$mZa+SxMBRjJ!9xc&Z+G9Bt{tO(>S?w-gyVoIj;NBY$@|5 z?cKTt@Wk`z)2025q+&V;nvlB6(Wo9Gg=WY3jdMB5>RD66$jrbUW=f`Rxk$xC)a*D%GuJU+Ow1#-=^%lxCaH3CmHlt!9Nq zB%=E@bg=MPK8$s4qx#IYu}`Hp8K|(^RjimO(wecZZ@HE^2^_sQqT&ao{-)^GNoK;s z@i?|Cd$K_!Jq+feAFX7si7RkQzM$-a+d(0dP=uWP4O3^3(Ru#HV^XOIWUImQOHx&O z+^HH-j=K~7L)(P)S4XtJT6Y_X*9t*j?;Yx2>QsyOy+aiq!+%wHtiX4C96V}G45K!> z)Kf?_gc%|fR2?Y20pv{B%c&toP^&1Y8)jEU)1>)&l$B7kR(Zd}ehr7Cz29w1verdh zI0%m`HuqDPNzJf13QMZe~(-ojdh-aX(d!C3stp1wPOKP zI|3?|&v56N9lLPdR~{}-90rS2->zn3=336Jcj=n}3h<3Syy3k*h5EimejK@wejGXcJNE(s-S{2k3H0lWx5y!*9b_DO zW+$X?9;Y(CKN~bi1IGQWf6{eTQ9WLf+~f5TBj>gpD%SNPG#~2{MxIspo}<{r(L-=m zj+`Bjt-g;?(pe`=h_%7Jb9$Zv7`b79AqPme+VZTF$$O=AzhU~6B!NDa`k=3)qkJC~ zCGE}yuLpR+yI`u}I}M(|$ItHEE556iHGP!wnZ+_z9nwAyjaWlg7s))M@HKQQ^nb$b z#ButnrX{If-9F5oE>L)}&P6TilStKfkx1}EVV$9=yav5M7>IE}vAA?jZDA9sojWi0aT>^GAM;_v8%D8P+&-zoZuGt4fwK}n9- z|Nc_#z+X9Oqx}Kz*dum{q*7t^s~jKmuFikqUP{uZYCQ*h1(|)rM6s@4;l*HDZr82$ z3rzWQj;dJ(MbK(tHVhxnLoX&XL`iuoE!# zNib<08DiBe{EKd*!hV`Z4EMGE6h&nzK*x|S#6E@TQ;u)^>r>EkuI}z4#r%UH+kJL? zI@k{JoOulVF5hhuekiS1do`HkU!zY=KlDrhN;EG>!rze+)~NR;><-@_ctYtRGd|a0 z*oVR6h@y3oJ?~F|NNOEMPSZ8(Ff-R~yHOYN|L7RAB+{V!*XGwpU1lCiA6KUpvB?ndbKOEA3BI>Hb_lNZ@e%mv7@o_BG7D=)VNP>JXITW&giepC7-=HPFaZ3S>j$n3z0d!^qiI3xEfHo%IiGIj#!6@C~XRNWnbx`Yz%&xnYm3d)O! z@eEgEuOp|8L4i)7F<7QOs(x6@Gv_ZxVDnXZi&iLDE4=ldf(1YVMxaIhu zg{a%4{3^li9Z=}HU+rf3^WyYdqx#KNiK2Gm=z!-P>#9RAWALmk)i3buGw|88U8{|2 zBW2p6OUCi&Oq@vqm_)a^23#kqvG@>z?P0c&7WPI zVqJ8Utj{bN&+}fH9!bsA2vWZIh@WfxtEo$ypr-744{Ea)NlkLPU*{%N22uSrOCQ}+ ztuvvxtekcg=KOYk3NHIRV=O#N{*`gvvh~vMI-|u_)`Pn-qLgv}8%8wiOB@~d!t2M< z0VJ$`Nc0o@+C{rV0E~Yc>v{xihp;B2=T7|p5no>x@*8;r{3iRQrekh$wGVS{UPBsX z=GtfIP?%)OF~32EBWt@wJkzNAb@c`N*M=L$f{BePZ`P|S4yh^iKJ>r{Sb{Fw%(a_k z(8W=&>x+7wJAc1|-@r~f$T*-w1mH?=`KW3pgz%0HSnyjJw(=Y}axI z^fKB&7=E>p!q85dC3U+ZzP97FF!;`of-vw!isB~t14C7SUewh7CJPXMloGKHUq)%| zuY;QA%c`|!`17ax^DU6_9=NlRJT z!eSA68t#4^u^_&9nIVysEY2UrDqjZ0fmx7l*n0#HoDPX3L>hmQ(MCH!jX?FuWArgV zHF4XhzSAGu5R1VmeH%sC z{E%k}9-2X)s$Fy}!=qpAL~P8Vqzd5zo{{up9RS>>5u1zA80v+y2UIf^fe=Pj`A>|~Si=IH1Xc3#$FUd()q zdSCEER`C#iFlOiDC^a3{4{|KEnvZl!>fdo%pP7^(^|8n@IqEZ#aaIyl21{yZ35rY4 zdf-z)&sf(YnSfOCZbi>9|4i#CRk!nyV*h;N>7d{A9KN@HQ!PgJzVZV6ru=ZY{DLla zeRU%_Ya}hRt@6*A;)M>izG{>GI;5jhqLG)G_^YSm@OC{eVdq0S079~a_0!gK+;o&& zX#_#B_ADH0p(Q2+k~C+?Uv|)tFgxu`gSQBfV9(vurQdS6aQTyRUZ z!5#(dLrG(MBtKlYLCu>Cs>c;RF!lf^hwKg3!MM|w?o9-mo}@NjwjD6s$|7)=3O%#^ zo-}|f9JJlg@2jpf-%lF(lSpy#Ow+mzh zGo=s)F<_BGxKFqo^J4Hae93sl=!4-a5gj#!)1_`*X?~o7q`Qgtr7o=QImk!{*5{YJ z49RTMJqlkWbw8YYK7@lXnFZwkf##z8r0)pMH{%q(hjC;*CM5p3F@ZrtxV6W9uk*Fz3Rtt_C4@-6x~CW z#OUH~K;QkAP{9B8N#lP*N&Gii{0}zxH%_|$jn|j#f2VtN9Qa||e`M1ApHjO2<4phS z4>Itl(;@VkD)T3Kfa17qJE#AmxGncr#%<@SakAc5cTjQXl2k*%IKr`wU(CZw=B( z=*n?O*VFdVbiLpfL)Rw#ewaR-a)-btbyrHSds?rbh~@2}G7<6U5A$O5Z2j&U{Nc@bLiycCaZo&F-r+OZHEOAg()-A9)G0mMEHf1* zW>YEjuuO#$E6Zp%J&rYU@n>q*sCj@%kVohTeBE*HB9C&k(IhAZ?nCm#lmU0EZ;)jX z?=9Xt23o?E9u*l)aZAer`enu~9=llw)q>nKAgAW5UH21&2mL_*G{3~zS)|VE`3(kUHY~i4bwwm~;=;G&Q7%|-*(%m~JLoW!Q`1lj zJvMT)!n+7wmwr>1&H}%g_%gO~3Ips_i{wnGJokr@yIAD-I?){bJE^Pd$kej*YYJIF z(7M&wCE>_?a!EXz8sPWqn9(C|r0AH7HmuOrU%PtA;EtJQL>;B3*d) zo$SSgz?V}Tx}%~v&Y025zxonneWV#sopOTS?aNahhAAv6*JUbM`c$rKHM-y@r=Xq( zLNFDA3KNxQG!-u0HMMtTHi$>knAB1(cAprc(WY?NdTY=AUgkxzDWASLCN8U#4QI*iUIwufHdL zO0)nk@)>Dm{HSn01|3TdzM<@d9*pgkXLdR6e%_IyzSx;z6j z!9|Ht(SU~o1Z%(R(S!HRhm`$B*Ya@Q`GBM9jnZJ=Ozf!ad8Op1$@RknYNY~sj9CRs z689@bftSS4Q!_aGUbUr%?e*6rXz7W0Asm#=hF2(2E+53YP6qdoZ=0`EbaLAXozX6X zcJz-jIF2BMFIV*lU};AAIX%=7=j2soMm=I`6+Z)ik~1uq2qO$LJer|3{8pf|l{=L0qt zQ!|^(gDjAWbv*>c?I6wggM=IYC-(_$ru}Nu{RZ?Z=}SGR>=)PrjU zkWL;&(NEqR$jM*ar4OT3WU5Z4F{7&q+uQ3qePYMJti`5^OJd^Rjs8jD9fS{f7r={T+yOk|&qz)Jy)t5mC!_9f)v5FGA;`Q!W*W*$FXwP>w@)H{0wnH{2VK)ZU>+gx(82O``2LoSa zcH?t!&z0S%((MgjRAe{$UKe~PV>dpssbt(Yq1}ipy8-=QXg4-iVmDxKitWZxnlZ>1 ze5iI(Tgd6O8(4DE+j@=NsJ&Xz*=JGC}nFmB6=LdR~kOqUeWNjrc=1x_y=$bj_`4ez~kg&o%aFRp%FEf*p1$+6upA_ zGqMBem4Ab5CUIWt=Yu^yd5^I~8vx-@&i0rr)gS9pOdJax{JlcG%0h+kP(h~dEuySr zF}2~Fr&9nZ*OQK_K0-nWdoqqOaRYBcG4Bp6^t`6745fq8r^?PDX2w=$$Ie|%UEQ07 zHla~dcCH#c%xZqvxt90R&gJ?;;R8(84hwv)om*6B=RU1$mx^~MuyZ?>w{t@SmSG(q zh*K2>cY3$pP0G%SL~1qMM!#u3-ivTMbGIBP7s1Xag_g?hwLx%<-SckUU&m$HD-<0H z`rAk7VEJolFfRKkY{`Un?^L|xKoncqpjwr*dpT?O^zsJnUNRiMy?nbD>r9ihuzmd^ zUq!WEv97Z)vaZ9)Uml9@ULv2MG*Y_E{PY=rbJ)DE6^EraW+o}B=(U+^ujJg(l~}SL zYA0o$Qo5a1hblf?5&4`8H$!&9T~`Y3|B@I{`Ww{!8U0mg7sJm(@%M){>-J%KcKQnF zX>-oaOMsX_4NN(~S=Wzs9WCl1Rb%L(5hFdMy^ zOLxZqzt!5HcB3S`1F&xbtcZg-rYbG%-G!?P@Xm>Nliy!xzW<~8{^)jUy&IlZdH0da)OdmSKn%)B65Z23h#(Qt zANC&k3GX%Q_xj-QngcDv;O7{CU+Nb+#_-2b!pw+X%a%%V^cde7h~ZQSis-JCXakofn|L(|dqw0bB(Ko6su-+miKZ<}nPlVEtQ$L~<>gXNdOQ|1| z{1J!I$5u4rle?x0&h3#>v91QZV))3&yMf>K^NiRN z+t1idfCSmF@3MQ9kKP8|k6oheaT&UkZ(c3&ir2f#CR1AT%s-xaA6+qk4^oi5vP_`*~o z`(!bk{(LXJM&|l{-Q(75aJ8K$>Qg?N50{4Lr*^y8tb>)IC)dGZ9T!4ahLS;gauDz3 z+ey#Dd9`q2P2vPJbu8!d+kv0E}FkR(Kg#BT7X_GuKbR@DE2bqnD$eBF5^ z-q-ShtS44JWO(LiW&AL@>G3yHmWDBi9$$o%n&L9+YgYqy?}urz81|U#=Y+rDE@kS$ zU5vogf?Pj|y_&_X4#mltu5`>$omp96XEImW_Aj}eb?eSvFr957ACklbnq0kV87|E} zdONFKzD{=u7NT0nwrqR+_(A-b$G-}PJ#V;=t$Lh%+!ckea3SMj+`AW zRVPu=xXs&>rtj&v{lD?)M_F>{r`E+6fC?@R@i|?!gTMhg&ILWqdC;fV!qs8sW*BQ2 zs7Gkk^$2IuD5j~{us&U@$J>So;~{-WXJ_7HD`l;OyTegfawbFW+|buPENY>K8tBN` zRcC%#;>8*egbE5kMY;v3)~GDxA-bvdx_8|pMM$532v!5a z8ZQARl5Phvzoy%a>Nf6odkDHsHBX}7VFatL)$3a`T{w>QBGtN|ch0}3p!Z4g@8J92 zb3Uqwe`|Jp&&SR7z61UpRdBo${%zCay*K=u!$cTHOU6hXmw$(M-Z>K0<5j}Hjo@+N z-!`Y)KGm(mzduB`sexZrE*DYhS59UXk1%ty&%aH&pLfo`S3xR${?%eC_taBfjUK0n zTRnbT4bSR_0@sJ+(z6)*pgCo?o$X5X6YeL!biVPEQx_<@a5sR#iTyd}(hSNuWYh60 zV9NAm4j3M+SeX@Jng}8GVRxp}yzWARkgkr3mF% z9XN;oNpynZ6!vA-`TFK;=$yfzvI+7ur{^a#7zobk`Na%|mvee3P{Qs*BAc^U7z%c(?H_vc%!)3c4wa)gfUPpV&tz`wqVuV z4xABp88@sDj9f&6@tht~s&mwMuj=tsJW%@!MgNr;mJjJK^KSgYsY`3YR{7qYPKewl zS5iPF*t4MhSpLnboz3(%p$l)`4M@nV`K!kKVJ^?CLOoGJMcFIx3b?4r%p5E2B(K@m zFBbF!uD`ahn240dTnuv&MimqVFlM1qDU307KE`zg6u$cUFbX$`q2gMPx$yvU=y(z|eTL(yw3}?~`3U}|y&XJX(VsNuQ$+tMa$b+w*0?-yCQEJv&M`-& zGD={EK;^hT2D6c8_Vz5!+fe7E-Eo|7n|7Ox|HAy8_?a~tjxGg;g~O5c*vf-NZg|k` z+}+`4NzNjp^7g#Efs7|hA0=nv8_G>>y`h1$Pk>Qsk!D~x||J^@-u z#-ku|nFWonJ0$)2K&s_D7=J$qgPh|0h>3@;0{r>02aEF(z@rMF&`ov=kuK5s0Am;I zxJK@#w46g4G^)1PGUOLA@%*czcELD{JMU~LP*coi{Q?X{&`_xO4qht9iCK~x@ddr68Xb99jsid>T8}R1# zETU7aYp&QVS$7Y-&wROKm$rZ@h;#Su(no+^$X^uiHxAG%*7txa+FI;SOo<#?vy-&C=F^SvKGQQqA)KiR#R= z$|p?(SC^!bfZKqA%jMlz*K*+%k}J9g!NxJehQ%zot|5chi7g4t8ye+FV_T19TEx1V zB>(Sf$+g#*d|V;FLoZpKsLq9@$)nVY#WUwJ)7VjP%g_JRSl5x92hPog*;Rvr)Uq9z zGv)SOrJbt02sD%N!7SfmM4NkiO)*gwb@NXBVg}hWJGN3Z_VSH=H zx=2<7C4H1f!)RMzp6z)}vq^kB4!jB2WrP}7XF77hwz1Ad?5JmWY>n7~iQhk1zkjYf zQM>+8`;q15Nu4tpm?u-Szvv$C+=eDeC#ApdRs9?5Eo+X3LN4tprg_vM+~&Xdgu2 za3Bz#Kb}Ai3+I<~s*_Q9RH&J`sP}tw{%|3E#10!hKegpHF(t%Y%k`atZ2({2E=-Me z-XqIAa<7nDTSeAbpV0asZ?9T44~MiK@z|MM|Bd$vWZW&ll8)96QH94PzOR8*r37mhM0_BNG*{`?0R?h>}Ycz3LD`u?^96N!=-oyQdzt|TaLr3tJT^kTR zpH1pBws4E2bBU-&v@kV8gT{dg%A1oPmi?CDarbdxKZ*TQ27jJ2!Uu6b&%;=H7Vxlf zKR##j2@(b8$?{r@p4rSTX1rN{jh+Jqe^=gN5@VK%6B2X!s{cZD{#<1{S*TeKDy`0sdee|K+&PJo*Ye^8q#LJ z%R!qI+wd{-Zr9sz?!>d`7;)pYr6+vn4SF%1!1TeK9+f)a z;O+50;MTv@7wJ61$um;?wzp620z6q4VyP<&a2gMP8%}5db$Gd2;&Wz9@CkW`!l3p( zi%h#gh8B|y?~?M7-`OBjNV@@lm#{lQy&CJh3aqQUT>OEko_)4c^Fa}?svC$(C^nv_j{m$ckR8Chj+Wu{a$JMU1IxfJ6q*bTzb&fg3huoSiBGZ zs--?XiuP;QfA|FK*M3-yll9)dN5PMC;R?nfzsoq>uYJdd)S9vPx6{pjZKE3t^=h~s z`tTEP>;1w5?FyeT{i^XAka+x8s6;0_ch>~j`7(TuIJ8aoGe;AK@De8I0p#Xz?-|b} z?L0*^Ej%PhY4t%AruE*QPqJXFSZ5(Q3OQ@hc^}cZcq@NCPY#24L1j&qt8rd4MJe@+ z!|tA;05JLia#m*)@9_X8319%wLL`1$6B1d<1vXsuEf0hY*>Pu9yka?tpW|umScgHq zTQ0%*RE6VPJ2R!_0Ak&K0CmrzX_9pMFN|s(VM*h)q7Q&<)8CSq%}|>Yc2PT|C_m)z zp@tvw_>eHv_$xF9^CAR}<3*|!m2Y@l*Ny#H&9~WCVCRYN3Ty@bn6qY#l3759YSGpB0O}aaEh=>N$upkfSD+lTzIzEDy{i0gCy^^Q?z!L6#zlJ1 zRCMbu#$Pr94<5oHokWH4gJWISB9p}+y`4?#OZ8*@^H}H6D)kk~94LK~S6U6-;=29R zLO4L98on=ikE)`*#lMqjB#WoppmPj$)c#o!E)XSc2nM2*Bp8TUM6jW((n#2utR+IY z`HG9If6#D-qTe(PxaB*Gck3FL@x?zdj4y1SRcx*pzsfK^tfNu`WPH-R7L1Si%AT&q z`$7SoFhI5YPkk6uEU#vdvU`1 z)Weo9CI9vLNkU*aMa@n->C>qlDC0MfUNs-5tJ7K~45aR-=GTM#8aLK@83ey=%N0MF zc;4zY=;Qv6Qi&9w^N^AiC@olY*t{SAirb4&soZrt{=_85jgErF)3v4DzW^tKhHAA# zo!S8P1O^+5V)+A+GAgkm*&iu*h!Y>eqx?p_4{@8Nhceb(wg{+XBcC8D%MgXyV-!sd zqkoLz7F=4!;3>A^E8rD0%jH1f5tkuaJvE~CZTMw*vl&r@X2!UU2+*fin>5A_3?FUkJGJ+ zULkhE$Y*Tji%2Jtg?&f%mrO8q+&Kb1j`Ga=NVD#TwB}>!4*l8$PZvvA;2DaYuU`9b zc6g0$7v_KSJH!=|-;(?7+A&=i5$ETjrREg#uE>mw$+GrV?kCHnP-#KMtLzZecy55T7tpf0s6n5N zV)73vZ>QCSpGN}UbrUSR-XzISd(Xq9@Jk<75q|YQ|IgyrM6liq{Q5pw5q{0*|7Y<_ z60FMcll(3hMt$Byeimw!PE*d?6YibxirD>-`JbTuW4I{u-L${(UA8~}-gh_t@$a(z z&J(p)=SGL=he&Nj{1s2VGyWP0)erx~taAytw0`LS)TH>UG=7=N@T>XRe-^)Pf>pWv zl*TW8L`Cyg|I`00eoX|c1b$)n`O(h7KBgsa7Kw@-%d{QMPIx6jwy19Mi;_bVec}2c z><4zsu20p$Tp?!F$+WKLw#Uz~TiLjfZ8p*!PBI8V7<3W~pb*J}MV-7x0{wd1uahkqRNgfH-mv=2GFJu7MJxl`LLk+w&!p4(?chOI5yqy3{-dz6e z5J#epY&}IyUq^uKj*2=!ia1CSHKfo1Vt#nG!HL_U6i!dvt$fLWPm7aZM1o(q4JahJ4yKD$W!BnNzK#t2HyBPfp>ert3wEpr#HI8=4nJc zHg&zngz}U-*5KsN(@!8R&>xY==VV^0z0>s<)pPYkUAm6)6rzU`t{$2VM~X>Hh!xXZ zsKMCCbg;ViQ4)15HHE~hH&!jI#aoH7r?!Qz;A7$d=y7|V{c>z}QY{u!tx5~k@7U!< zJ^ezhKZd|rZF5JjAUcrjh708F7}8sSkW=(~VSC$_=Zav^L@|=yZfIPNk532y%j6sG z25mh^csU2(-3S?^4W+zccA?|Wj7!QwTk-TcHm_6&KZXv~Ly0+t7koX`erI_+W`*Gq z>-s9tS9Y!$uGJy&l2j2tqHP^)O;P@1>pZg*#qT@(y8_7uj-7yQ7Q^h+@*w{q{1!G| zE^NG`Cm!!H${@x|O=i4+KhYxfq-kmI)C@_;tm{eJVU*p>I}0aOB~gSPR4`5Cp9A9N zT`2DXzT76(wS$5^TMfO7PEdO>7g?_bxIknPGF|g?s24{mu{Z%)$@hIn#x15l@XsDu z1W2sw4P=BSn6IxRDNFi|C`1CaSLNob7dEZ{aTJtJJYQ=xf7HPzsF*)O=BruSmzb|O z46Zw0AH<+)z6R8=ZfS4X`SR=PFkdg~`5I*RmCTo}<1W%qj=bE*L?$f+?FZ(eTCo~4 zNbQm?q-9Br{e}6;BDrz;`2p)n=!)}gT!NxMVS{yDq;Pzz->+~6A3M9q-r4t3&U@a8 zRDD#=7|EN1KSKF2_1O^q*kxjVJVo_+|O> zpUC37e3?`tC1$Y&(2K5AJeDb^Cs$5_FD*~r?+jj!F9)6XLin;wUdFE%9-%OEJ>@uT zC~_Ue%g-pYo?`Pc71ayZ+0~GC`Xy%lpt3rxALI34Ua_)v$JlnzLh`VFnh)|)qhWQ% z+3xuig3}YI{5QGmtamt0CU)ua)6?H8x)3YcOQ=-2zA=}V#IKVDF_2O;s##0$7g{*s7y^nh1wd@ybu(6K4&?%~e+0-of zUJFfBR2|HU;1npr+JknMOLVh9N0kAa;$T%ZY|4R6ad4WE)37NHRvS$dD34;mBio0E z`6lCt zRe?2&Wz)$0aJaM?&eR+aCAHA_)w`wU2Qb*R@?F_~p6B{-dzP$_`><1Rh8k=fR(XHi zZC{SLs_uIKJ)=^5Cn@T%V_7l()1bf?0X{045Hea!w= z^lR5gXRu!>wPC+m7GXkY&X|#(Z`i^gfptMc?RJEc`!tH-X7x+}?$`WY1@3O!E9B{d zGY+sYLul;2zvTEjG+UB-NdL~?_)xF#bFyRIR(K(`>zU=-AFqEe)&BgD-#G^Q-Cb;UVV=~|^fK4$V{=zX^4m#8t_9_ntryBG)H0ttA*tkU0<;O|TD{JUw_{6ct za<1HppQ3Zv34d)E4qELAG-m$Yp!->)L4dvXWzz|gJjSlMbdh?6(dxI3ht}ri1CS&8 zrLENk%DL(YiWcxqzJ=d_E{_{+`VZJBDsP%vYd4GPEH1{d1@LAX782f~I*VA>Ie0k; z`<+W^@an8z69&J!Uy1O;tBg|ZXZ-ro^6;C5)#Cl=u={zEHMlO6S&9uUccm??7@1!Nj5+IWHrI_Oe&7bLUsQv(R zf+{{}wkY8z**r%J&kM|tDpnA5bbgF}59lNX#g;Bba?qvd8<2y#FPD-7nh~$9IaCg; zT~c*B**BFOC~v~D&v!KY<6sEoySVIM_FMbJ&i|&Mh z7Z_M7UKq`R**NDKcB(Xg;v6=Rs=fg;Y3KQqHaU6^G?b-x6v&vz@HJqsjNV^=kLca- zm2&j{*7x5Py&FM*is_v<^nP?=dN2J^fzHe(P72c6zyFzr*1PC?N>7H++xl~&Cv*L; zEB?;&Zt|_FsnnGu8(l7boY6;)+(}(g_9EvnHC0O3kMN1jIM>T184sEOeMq&z}xT zQIRDUyL=Yw>cIEblr?aQwtQzoJs;~l8*f5J8jP-A>+1S}KHx}XfDz6VnnU$3WxK#Z zqAL}D4bzh2s|Si%6WWVGk)sM6i%?G}7XV5CP;USbi!e9>DPq&$n1lSP(lJBqhT|!E zkDnsrT4q&M-qtJo3K_Ma3(;cD_yN;}+T?bCZy%#?Y+O90h5OR;=|vPHr7{EdW|^`# zW#(Jy@jeW}js^nr?ZoL~)87wlgntY`A@DH1b#1z@$JL}xg0{|l3Q>kNQHHL>hk!jU zg&$zCq%ZJSH=~bI{(V*tRPtP-GX35T4PUC?oaxulZ{oP&(jyY3;)Z{kxZ&;dP25m< zzsHvD_g|*p%ilr2FV~iY_bt=!aqpnt3rqL=vCTSudhNW))8VMn{Wh3>FSh;Wj!|)$ zOJ|8!OYUQR_ESDRiuSQqeU1BAd(=3{8|rbEq`C{np`6J$+{b$SL3$tSJ~Pce)<*q) zm>e+IZ2fm$O-VVg{(4ZaUytvtUKgKj`jP@48u~?DyW0IWO)bL_+MZ7zXhJG&mmU>m ztYQ}5r=&t&l1k53^fPwY;ut zS$HpD>m@itqZgejmFmY`mH7cX4jDfnjJ^cO<~wzLZ9X5MucJqWws(DVVm(^MA8tnH zByvUma7Lp&bh{=hCgPpwwOh*QwX7ava(;HzH-o;P?;lBA)Ax<(YO?WvV`rdu3;k^R zedI$4?Gfnb_*cG~JPK#Q#x>?(a`Aym$Mt&t-1sY#_?9qL9PtPi+tpbjOkx-8pU8bZ z)SnB1*TnP45tfD5gz+Kg>LZRHCi#MKyxl)hhEIcWeA|+s9w?6E_W)XUUd=pI9>+HW zN~J992EfYW_}_l5KnHPdM~A;rhW!hiDUxs~d9aS-55$Ln-(VQb;^pfTiR1g!)K5N+ z{}q)&K|U+`e@gMYI9CIWq5N)rDTxP0vYOvV4ZkZboFu=4IJwOmnZ%eiW3y;s`j+w{ zf+2Gj4<(>vJaa`c+?m>@Q2vi~F==OwhT!nxe<^+K>UYxE^$8_j6FiI@AO&L*bQR)Z zB%^Q~kUTO%G6&_N-Q>4uL-|lX_&{%ST`#ucPy8b|U!zUmHhA;=a*_Q^;NI1>XjFjz zR~7z-zJ{+Rz#oK&Dz}D_OnsEewPM6@1WpCN8$~qmDwYEXoDKK+;KvW5S>F0E9ai5{`{DgJa6;r~<9xbSw7! zpC^ausX^#g!{VW)x}aClRlP=6o$BbSV*Tsusg)#uRVW zOkYU+XwOeDa#oqYbmFy>_Lr)^>+(;bzx2yR@5*2519qI>&`Br^GDpn>+~Q9_io_!g zb`mOz-jH)^P6P2=Um=?Z9=FMbTiDn(`w*UOmGv(E*G`5DtI&b>IiM4sM+R@&cvbB? zm23~xBUTaB;wSI-GC8eO!>5%$%{4JIM+A}UlV8Js+Am!?)9v^`F%*4(lznpg2fqgb zVFP{+m%gcBB<~$@&b}_tL+u|i?(?ijBzr_K4kBMo=Xi`yPQsf6();mYJ83*~`hCL4 z|8~*;>bOL%s`BaR*HYxXgdnXnW%`4P1sFfHEGH}4b~8vd+IA}&axovGFBXG&|QJ;>dJVZrD`5+x^Q zN6=R21ax-bW>e}92kuztx?fGR%pdoKX1zU8!{ILNocrYx^JnS3nR7Rq+`=HWq+6ka z)KczID)}izZ)2~R_tkK#eRvn(ivrot)c-I*f7xg4odgB!!oTrE!f*K3;lB|0jq%73 zqhhx}j}RNKdrSa+CBAi${9!&`q$~BGrmONl^`SDp4%{$1 zlU-KKPqK)(9<40_6ZpexIYIfI_$-gZS7xe~i{G6!auE!ZJ)_-Bn5^^8bsFwcdV>YH z@g(82`XlaLa($8h$RDckpXtCS_(Om6p?R_XxZ^tNk3rq86klSpYNml$`rD3Ob>tLpg_Ub3WhFp#VT5eXX2?*`uh>%jh6w z#QWrN*7y-Wyq9TL?V{oeiPm?P`@~DqC@>0{GCVr@C@S)T#7VB z)HLEx@mGLd{t&U5JD{L!923&U zxE$WIkZKRxWN`m!$6e~Wmo(a2>DAMh&#^sAD|;3~(FsxW-jC)LPG7W6-jm?{;U^8Pl*zNghmbmUa_CyW;LUYcKqAE_&-Q$qN$0fc{-{HW^u z;rcG*MQ}z7$5x&SA_Upy2+>QLZ36FZfr3hQrDH#v&PJlOhm$>T-UM;Pc2v?5Zu`kND4hqzBWgKeM%~y?gUBi+%)qgQO89Q?JAzB3Q+4m+ zfqo%5)ET^k0O1?^P9}REWXJe-76%%Zli9ty#HlSKjKkig@`@a?rg_(gvQpoR9J>P(RV02?^ZDAx59UbY-h4)spPNYvxzG4qBQuzrKeM-IR1 zyeh|uYkXGd0Xd%dIXcb~f2r{d(!s=AaqkCL75PiU2bK1hM$o+2UpoIv`b#O@j_kw# z96wX?6%r?o1nFm;a>R-Cx_v45199Tb7_uNvjF*8sg<*@~eypExj~=M-rS9WX6mNy) zrAL2Uf)5y+1^M6vXfDo=7Awp5;e24+f_I*mj%s||@q`Z$hcyvwKMwO6At|HP3V*)C zhkl2=Z~Tlu;fn$}7>&0Z{3Sn)xq+|L1540x*JyE^Ao4ITspw$nTwWe59cbQ_f({Kt zgAVFM`RV4f4E}^zu5@TO`R0)Wf_z}*2Xq^??Vy@wN4;w7C+*em8$XS-Bh8(-RpqH$ z@h#|=&7LhZnq;SlYEdH)tjuLK%j*ndG(=nm)pf$RmB0h$G%1ZN5xKUQGp_Ljxzh4Rd2mPDSu9*IJ z{I}#kbh`=l+ceA$^;>(F&^|=JwH|C)w+D^0@9Ybh)*%eEIO+K3+zCWnZ7Jvy?cd_uK&gxboYr+q?2B?X|uS z$nW1Tg8cS=&Ry?H>h`YuN_)s}1BMm(jk)VxJEIfaKjOemIiUPHaEGsVC03P@-wQwU zuH@I015F^m4SOkiyYj2yF1_AW_mcqq!{zs}Bj2_B7T{2+{ANhj67t*l!P4@p@vcOE ztH25Y`HifuNPh47w3gq@o<5(GUnsvae#P?J4J_ZW{C*a2z^oU@?}%VkXv8IGk=-@2 z+XMw=W}jThdRNrJt3ZBBuXm09w3wfYoO*Ski+b?__P>-7XRru$S$Nqo#NF4t+C@L{OwjzfWBGP)|GfhU@8J=}7xo&-(ez z8Z`D^KKwtSrw4XZ^l|mHhP$+$&Yl;TH>Ia}; zjA=_xCs~)!P4G(S>A_t~%Y(+d5*-nzhf5zBzhXUI11#UM zp8n-wVS2g^{Kzifg`d^<0YzWp#s3&5X}Xry(}TY#<|on9Z=+E zv6Xw7H{0RX76KUP^JP(;KqZX`vFw|}=FMuPWy-#Jv3WCzbY{_;Dm5#1=G>YvRS?DQ zevJZ_dGd@~*qcsibErO)Yw#CUb7xJd@V`D2fYI2TdS=kB@kSfG-r3{lUD!J4I7#h(fu0zMGt?cB#q3fK_uREV# z_PKB9LbbI@-hbBl{DS{E*|BAxrMuz(`^GxH1Xde5R+Sek9^bO}(jA5_416;s)^Q-; zdo1wnQL&C)@NKf=_L1=!_q9E6I=mUw}qs2g38|}-4A0B+5_`YU+DFyJkLSny~FuYtt&dznO^&2k6lJn zuv+(H+EcHxKdg)I4nK^gxl!*dxf8yf??m`SYRWsu^$5vd3 zFEDnt{WsLBIi$pKaN(jDmg#axiObrPcmHV+X-CAb_y~<=JG(OUARK&Lf9zhC+_E!r zwVeOM3X2l?Qk(?IZ2Hsf{q6N1)%(=W$9YK<5$GQk-xxk1U-RL$Ib(Y+vGwQb+ra(a zBBwlWBj5hp0Pc`e&222q@QyeL>j0*`oqr$S&tMKsJ)uN<+Ju;z^v{D%6cDz(sGgv-Z=*%))Kxegd4Eh_+Onf z8Px|pCQohnh(4~?ugcH=GybBUYUmT3Le`IB zUALi;MXjEwy>)<=8`H0W2lHTkhfS{B4|W4eqo-tDXvC^7ipL1`F>W0d_owPoN4}4PBj8TswBC+=dQf$fD6}6 zF!UNO62jZD99%XS61ejHgiC7~Q&cZB5_qb%3ED5ir`!AV9ufQX7eEdev-Ouzhll$Q zKa<1c+R-#JJaq!TU$sD7hP8C&9Hx)0{4KsncD;61E56NQ#AxI148sVIL#ybbQO(|a zd^i$GHR$nXb8tM4oF#OQCPsmFgvA0OqE21#^VO|-sYTk@Gk1i>hyjav2K%i=I zlXtvt0BEyFkTeLQZiFIS3u!L1-t2v?C)I}cyv6&M)=zCl?gIKLHT>U1d)ACTg48e7 z?2zshzZ&3IgGMc-8^J0@V~0v9+FiwV!Te0P7E_)Wob2*^fyuFTixc`&5s--E%W1LY z{i)PeYFt-N_*v%%O8MV2CX)Li`HEle$o+{pY}}QvYo?cx`vUpOmX$9T51?W7P!T+R zEAF@uJ(2oCe_{Pec)UV~M%gURfcY)u$^vB?3*S=;NuOd9fXXAa}I+hZY{BCar zm!Yczm$m-_S1t;;40ndbw{Vw{A1UkyU`473N^sqw&(v#8)fA!M%t!0N*osT>2bifz z8;{sZp6wby5*xx0<-_VNNPzIwv>AOhm<48`lm$^n6wf1WdQ6AvquO2VCE*Yp4d6R zum-KY$X?TJyyVPJjj^k;-)c0e&t=S*Ny<`)DPB2Zp6}PE`XMo?H$c-*(4mgKU)_OU z2V!vLae$yYOKEFUuvx-TcB_n~Y#p#xl(l#}{I2}9 zTfk`naIj~m>Ka2=$f19JP^{}?c-iuOEopl7o>1+MjaT)(-DYosR6+po%;r1V!1arf z?Fpnd4KY!W?Guw5xC|eddBPmP7kjkh8N@(awr=@}GiGch_lS@@BgNz1t;WUtRW>e3 z(fCI#XLEH5347txE^)QIz!Ug`RJeQ(;|CPUtvV;{eJz(e5HDX>23mpC@LrJR0#q{5 zwaP0PdKL2B58PqD9GGa!cZ(7N&cM}*=Q4^`F1u+-4r8~UKWW*G458SqE|Sd$?VHh0 zQM{w`T`3hW;1)`NHQGJk_zw#}_+`688|{m5F9UBmt2}4PKaP4|T!O0!c>T?)#dQeH zxpo%myOz*1!p%y!DEUfw+8yw+_uUf;Mfn>I8ZN@Yhx|o&KqjN7V=Lc>S@gw?N{sAB z7B!>F9?`LtYp4d-$}T9Rtr~ANAY>E>1Y52gqvKx%P%_>x_8=&Ak&%D-^l{f zo*(5bu7<7!>FNaP>g}oZl$=%T{<{xj?|%Q7w;CVrSm$>kkb|i`Pa|(f>aHVUrMK4I z6#m^G@Z0kf=x*<;{42USKg~!C>@S+S&{V3S;5MqWDJ4utbLlO8s1PEkFaE zItEdI&w|3F-^)$_RVQ_Dv?1#XuY{~2zg7u!kt>w8JYS5)4(O0sx zb*wW1JcwVq0KYE?e&n$F8?@+JlT~XN?nW!ZLV-7SCIuqp@R#ZMPvifYLj2`?&G*GR z_cq8I6c;05JiE?L@=-n!Zj|Zg>R8&yYun38&qTGNH2Q$d&WqMr?F3(DcNoeFI#Ov7`qJnNdKYWD%YNe z-W9@>?G>1cF0wRw1$PBoc=*B9D-XiZ0Up{Hrcm*(hUbbUsnrgBg6&%NA%i7vJ|VJ} zrwU<>1BwX;mVzGMj(fb#8^maUtA_Cgcljzmw8}g8yQ~i^>KA>D00olqH?T)MzLJlT zLu)^VptaF84B@)5jZ0GJs@Lp$_zC)MejRdk)v~vE)tR+(dPZkLiOxX*My&HyG$7#F z5WwT!!m78i+Au2;De4zZn$g6-=gtp7u<%V$@PUZ{pVo^>J!bXb2@&sYj9!xMFZ<>57f=+&DO8yrPFrnNibe>LEmsJh4Kl=mzRR zwYRzl>HW9IeoqQitBI+`aY^->NN zO_$m=VRU(YSD{NCX_5iuG)>kjyFV$ouF^6vcD-h>dSK!m@qVm-P6O6_jNE{S>W$rf zfNV0zIF{T-E=l7WGQR;jE${BPo)*0b7y0Uh) z$XW_n6^a>TO*XoQp2A~f?E_ZU=nfUgnk#v~(laJ*^Gc`!1V&ueinP-gMBF0OIR^P# z?GKMBK6m*Jv(FhceA@DTwvUJ}NimCct+aPc){xP#k59ht!+nfG!+es)LLA-2NlXbT zM!z}M^~){t3KtiVylhr%N_xt#mzWMB1Jnh_%0xFz_-fhsT#os%#yn`~G{R z;eP;$sl}+3QKk!P6!`ChFDN>|bjrhiC0;}fkYPk9Ps_S-n{LN8FYvibggZJ1y=X0HBzA z8NEZFlKIf;$<5J%@ z$hN1Qd_-aW6HZ+Vg#M8<-VS6Rc(e`EMiTaCz273F6T39}yn@5f$B`T8D5Ns{edWJ( zlnKWBqkk(;f5>O8v0oFe6Q%)@8V%z@Z|g|V zm&RIP$C3SW3$>cE>uN>yJNes1xp0Lh>wW)myRMcX$<}XU;%-eg*X|b7?{stBfqt4C zWrGiSDdc%C>UVN?gv)$E{Z192HTsAA!3XrUaH?~~0&v32z;Soxukc*4!v1KA`T&lV z`y(F{xzGJY%`@|mV76h9 zXlFQK{-s35!wz5hb}joKx7P4PG~PvWNfWE@bAA`~JMHU?ekoJGQw!y$fulL{;sDM( z4xMbQ5vptl!-i|6v`Ab%C)J z4`If^bor(Y)XU~x-dNWdzPI{~Qts`sl`Kiv<-q5l&ZcmJ^VLE{r7c*mO>i~AYS{AW zDbms|2(jf>FtFRP^=Lxukx_efLM~a~!f#dw1$(VyuRW?)t6te_!Og$Wo@q%z(gVd< znLbG+i|26yJr6w&_*X&yj2WlH?uCr4JOmCE`ko4icMyoX^^&=Y8|!6+k`TK+JG+Jhq7Sl?JkqV-Gy0%1e``mGsq(iPOSccN!>$^pzVg?nbsct9 z2)u;JVs)shZw&K4h#>f!E}vn+Ggcf1QFdQ?Vx%%!vGD6igBfU@Isk?kLhSLv5yN`Gvyz z>$WEqzJ?zvlZ)>oD_$}V5&wN}(8jNiaL+wI_x8AID|9h-(1~LvXn$;={lF8!`7-`8 z<2mAl`AUntBry_T%GBQL$P3pG7wrxYJd5-#JaJh!%y_%w*vO#YKC+1u;H(;2znxjA zthX3(sNhqr;W2R~=UL!j9+`Qi3Hxhiwm5%ikj|kltr8+eGP(-`hwWXrZH>AdHg^nq(r7_Ms)O&gHNUgyngAehF;jXs9N;~OG{lv$>3l@vCfyGpQ3)4M2AxVrgWJOc$ zYbbm_bDw!1DG|wswc2}1Ts~qu(%8wHd{tBsm=kMyvJMFTLLyP>M)hI47{2w_Odhqf zeIb1bZ;c(_hqqJU<*zCBuJW}HjPKvcPVl(+*2(y)#2W~x?sElX3o%Y2z!%P4a#%K2^v$8oaY?C`8Ku$6UoJfEfN03rjsRBBX>zdOD#GKG(_ zPn7!CwIiS4m?QmQ4S%@!{Txnqft;a+13xP+c7|gdIn=F{tmuJ+9(Qtj)!+AJ?4D^) zSov7{uanF9?#-NheJ8|MXIq0Wp8etfO6dJ0M$ejg1K!rZm%8qBldi=X9z!XNZ)}Y8 z-%g@aRH8vqF~TEL5m;?ytyA%N{l2|Bl)T$LLhy_3wTpEv68>>xsBgcP;B-|PH6|rQ zvdUqgl0!Up#x$6P4%WV?JiVe`fN%2=A)V!0qfcX9UzV|je@e{*0I~j3*?TbRfFQZl z8s+eNFdF|HloJCl{EaZIHb+&h79!KkSoF5r235UGiB8{hrBZskfD#IU9dq-X%Z3 zC+0oZ_^=vJozW_#0$;$G!xn`))7;uwD^G8%m+=NSEBp+98n~zmF+{W$Lnwz;ZE^v( zu?9__Fq88Rdj-KWo_Vs)k85(U?u8s3bzs69N3YsnNa=CRK534}|5%1XdkVZ%-R+b7 zW7W~`=Q-m)d5C}9g8%WUOZME6oW3#H^?=e+0B^MZ5#ju8^it2}=iq~9;5%gJ^|Znd zm$Pd}y^o(qpRk>sRB1RmwIOrxRr&B$3lkXOtlj4Hj3j&RPp)nrS4SsQdxrqtQLHzOp?# zpQ_RQxprFm!8#V^1vsLd1+^I7DmZ5Flk@jaF#f7V+jz^N3^o0-NGlLNL%%`Yp5IXi zn1}Psk|)foTIU!B6i@~x=^k5oHNSvJj*NiCWDP92`j{!n&5%r54*ZhMVs@z$9`sF1 z6G*_X#*}H9HRBDkLHna1OwSu2N(Mwh5Y`IfsNzkUnd8UzuhMW%bLyT1K3Jrx$Azp= zfl}(D)+DdTOrTyQvq{lsDv5}P{37j)ok8ixEh;3;B?StsS;!3+)6{~DgjXV(zkpd? zJ&0bx4*5B^=eL`4b~-YOq~xrgSwD=Q{rotFNS?hRf*mgNK#3(s^_(%2%LBE^j`ds3 z!Pd5(r?D$+PR}OqeVC6qXXnW+XI`zE%X{PN1F!J}rX?HD_ggS(=%(Q3b@*BPMYLw1 zV?6yB>3Al>ht?W2iF>e8< z4=z#uQr~@weuiI2Kax`P%PP6gf|V3N?tYe=UQ_^3AE(9zs547Zu8SmfzsD5Lr|2Q6 zyI`G84eKr_r}KMmpLzB(kvy(!J9`VM9_yR|D$ZMd+?07oY>ch`BZ=YT7hB27jan)a(B7tvrSvm_tj4yMzSIS784!u+MFW7coMl86(X;Bn@#| z%cyuhZhpvmCt!!|P|g}o)hYh(&%<+hnG0Q)o874JGcWRV;xFqMPLx|)i4k|)A?5TR_1LEDK zkNi3M8bcVj!x}cQEB}b#)ZU1YS2LYYff9P6}O@z{4xG`B(nT_ z$<_5!VmF_>ATBdYi=6C8!(Tus$8R#xD85+;+(+>-Z&fmM@O| zuYW^)D_jW=QK6S*Hvn<{ld$+>jHiP`kh!w_IrpFJMue6o$@}?V5;Eahj+*ZB<&|`I z^s}-%uaJg?I{L&Lt&Wa${+Vw;kr+MA*&cZAgviXbeOL=5vw1Ha6*G3R5pR1t0*LTD z5hk_K$m@NIU;O-JfBcqjK*K(k-26I=z6L0egQR7e)9H(C8+c8q9yqxysizH-MMIBi zlN_5&;FTr=Lvv3@g368jn7p$jeM;D`Pv2l^Q)s^~RrJVtPtALX{eSX9 z5&i#Keil3vke}*1O7ce;`PuC{%Om0PllvRx=l4c_uK9dWel}(Pt@1PYm-kG5D(3IZ z^Z$>(|Np?>%bp7Gck;G(!rzDgX#)Np@yOp-82;Y$nIM0^^yI&lzk9)J?~#27i9HhD z0q~-HEn?gPzY2Y1t~!k_N6LYP*^UK|K~I3oOj=S_ub8I znihV~zxzCC_wt@|X6DSynVBV zuD7JAgeUmyEK!mdA{`e>U`}EdrPenA=qVENI~M-SAj5mr!RqLW>W=bMgl{Dyd~2() zNY}?Jk1=6BSfB4lmdxP&f2-Il&LNUhxETy7wbla^v5h6@xAIl-uUZ~f^z(}QY5Gym z&XKrZ$v;JhHeH{uEO6H_hW(->|5Vx(HVfFGguX!IaGxkgjJYPm&LU{+6_-S z(DnwXV0+UcP{jJ*8r##8&;P>b0P}d-A5!$&rkzxC@T6kcggvz8Vngh14tzD7oJ>q zgN(MSqP7+|nRr`m9`Uwhufj7+ysh7X@4SQZjknd&o5Ovf(E+>6Is`O8^Kdh1-uh_R zdhG?9WAuFZV+qbjMGbha7SG^Z*wvU*FmYI-sBpX@@DIP0@(*jNbCrJ>SbQr-0Q=Wf zcAPSya@y)ZM-?^~0RNz42IeiL=t(?RUHvW8e@u%3r=ZTV5F(2WKA`9_3jMKDh^Z5e zIIzytCK-In*1Pbz_gUiO1n~yM*xevLI68<&14QM2m5c$-Ytnr3O8OoK**xWS3kW%;AyK%zK8%7d z#&f!UpBH{9c~!^!hQYMyp)-|I$8}WnXGHg#RevH~;kOh6sJ__0K_6}@Voie_iQW@^ zeGKqc#eb0x_{iy7$=7kLP$qsge4m26ho{B52*!IJ|S@MCc^~~_WH=k3I-BBu;M7fi!4~lU8@K- z(XmjjjV%B8Gm!<4$<|eQwDFYSg4fj6)kvALTbr>xzjokgUSi#T<g8MFfjrq-5wZ!#N@H;I10j`IY)@51*C?9-yG3gA7U)|4 zz#)8DddW`f;uNiuy+Z3W!oF`^#a_ow*z`^{6=8&8imZbKV7aF{8~Pe>oGvMAG)O(? zM8|RvSp1;$q4Ve+2w)YNfv`E0HCW+^s_1%{!)}@h5ceYWg*2|hmDr;{y?{@5EKqE= zJhJ?KaM*I;u<6mNIl;Yz!L}fORbs~uw4L!y;jbZycXpuO0=zuT1tKoM0!W;fl7(1RJ=0m3h@baoDQj*E%0!lu?~%0 z*nCF*AxHicQsf03vG>VPWEMxJg$+$K1{RT!_?TD(N&(IWnEnN@3lcnpQNSgXwE^V6 zM8JQ%1HLZsz>K4U0Fj|~u&;#LUqz^WxlH5)U*vGbNQWp!nlUGhhYJPJW~5y3l>k1j z!$tR~bERLPlNH25opf4*^sPW^n=@kfa>)av%My&(JJ z8E5c=2Xe$2A|Qq<&M=_A8izPTe9}zVisKe%`03*z6BP)7N>&>_i=7<0%UkYK`}u)I zCeF|TnCv*i={u#z84gU1KtImf)Ajjt_)Mdnu5h%@Z85_4*M5}P#6P=7~W^v@Y*=$hcd=a?15XI$e9{kInmr^|o$M<%-9ylJ@` z&JB(;6m2-1!4lC~j=11^{kFXJ-j-EfH%XkKOpl+pyyh8a82+Wg%WXH=`qL3-NPaBK zXRbIy&u1{zUU7zIJx)GxhA_t&CC*Ti2izvk&`ti^9B0@ZXYdH%Y>qRe`DmNt44W$Q zvN_K1|74t@=NI1Vz^3f|U^D$qcNA|0iVdn{kd_3_v8fEWb69P8A)Dbb6 zGtf5I&&>h7Q&dDxXy=DfC*S*j3h&484PUZPpyK$6=51wtwM&v+g&~2qJJ0~}d~EH3 zO!2Lrtb=L1)n$=MegWZ1^&QT3 zKwZ$JBJA=8mNwu!Mt?O}EFDMA0Y_p~cm29+L5pxd2rVUE_&#hs^GEQ9f>OcB_mNgp zPoQVC6JJ_SJ!tZS>Tl5Wcbs?4_($b}NBE>kC0$XuYEd!o2aq^8w%jYDi;78i!q}oh z;Y*7z2?9X>f~2l{0f*$&UiP!=`j!8!iQ8Ys{em9Z>z)nW&m$c z-&R#Th&M==;WLodS_ypJGZNyjUhtcugi0VpMiqiX8>=l`6Jl z(B)B~+?0Pac-aDceYMwn)5EsICo~?>O9Dxr(LByvAKT#-X1I9wHJsA6Gx-C!HAzuG z_=U+u6{Xhpr-f(%2O=Z=>y|l1?C@S4M;Yo=;~&kE5xi_ULxONw(8!fa>CKRD*0`kW zjDI|!`)$$v`adh(ruy}e-ywS(BflkDeoH_ubOT*>UGh7yLr(d0Mt-}0rumhL=XeRf;QvwN7qYR@znUr4<i{CWri%WXSJ(Yi#-L{HZrR#wfqN7}}QK66?5` z4*Bi#?XPM-xbG3t!qUQ*%(oiH7e)hYnfRe$95%p7V;qd`Y1X(!vtgD7va|)%e6o*YnLO&!|Y-+370;PLGorZ;ktN14tllh zlt!l;S?(kI#o=v#lxqj!d?00_eKEmuP(eP&7Z`6D%dDSgDi^9s4S3Ue=g}+nZ3IDs# zQ_y+U-TL{gt4ZfkYVB*#JNPrURQ130w`Ewh9^-9VzyB618;dWUQRG~xT#J>L9xrG~ z0LYAoGj3z+$0A zo`+-*`ey_lXgn)ex!_|tC}H7gU_g9exhZl)IGAJtBGIpM+S`GSH83p*82-#w&%6bs zh&~=dCvziFOmT>0bk|sK%lQc{OB6lY_eZ~Y*?M2QOp`?ZKj74U_+V7g;WGp2^W~WQz~Uo#jF!s(2k)X2 zlmAc46;C2}s<8b3TI&(`ZM5fW^!TIjOTy0o&vTzI*{<;NACQih)9zkO7Z-|WkaFg+ z|5gUHO`dPJ?$0gfc7ND6`~!w!e=+a{GO&N;BYOERlDZF!zO=FD%rCDZPX^qY+#gUV!vv~$}JB}RO=c}SGTDKsh9NdU1h<@=Pxgo{fIZDeJtu1E#J z&L~FSsKodn4NO-)gGs|EDgvBUNc*e7%|}(yRh58?E1>m0JVokG$r)wn4JY(8o{;wt z%)B0DgzGrMCyL{a8y&~rNq#iK>0_M7)|JSoGzDT~o5)gv&@mUMD>TkSam{1Q>#Xj$ zk$Ih!I6|Rv!aJ26zvDDV%xoXa*-oGAQQ*j9w(mr4w4B3BJJ9@PoJVn&QYP`5Vo@e( z=TW2|_#)>~9HrEptham%A+^uVJ5hoHhgJCHEQ%rLSrlB>hn1Z4Gcc4o@d5fCabSIJ z#H$Puk&RR5M#zd?f{`ri7E_5kgXeItOw4s|oWmcgZB=@Coc*ELUZhgK{?J=TrPjZN z3Z6~q552nWSp1>WVc)^tEYk31^+%lkQ0&XXJGuO!!37HceEp$L{e0H(NAZVhb$jwC z{jPEFhy0lP9R5%QL~!{-1Ny5m`a{iM1zE@L4?TEO$mDi1Q_s57_4#^yrWrASVZ8jI zt9jax_J`_93iO8(m#g{SSpHCp?%!=E0pOIMHAa7^1<1l;D7CJ-F^z)s84~-rZ1H_> z02M!Zf2iRyMekAU+noMT=T}^~9e=&s&)8spXkdQfaJv1W@V+iM@91>HxxxNWXv5(Q zhD3fH{?N#E_Il8NsiMOtR{nS6@k6A zH!A$|^@rN^^I69q#UG03_T%Ue6=Cjk_(QcIg3BKo(qE0yA8MZlvX0#!y7QVeYu>uv z^*M^q^oNEpjF&&OU^wLuH5^=^KQuf?&G*LghZ=PMZaZl_{Gk|-6@TdRtJ5e*f5>;J z%NGA)$EU&{s=H9pdldUNr$5x~#_hd5zxD%ee!!*&o{M579ux%f1ibE`C6gX2TJpOg_c_(Bth6f2d_hox?wa zfq$a#9i@l)elq{jFZx4UOiWGyzP*wkb>Zg)-ywe(7G4k;!5+tn4M_&lgJ_zTfkZM5 z9?7*>*ZxFj(Qb-cTP?EJIWz8V`i;Xrn|B{~$#gmpb|86-CG3-fWJAoH!@W|sGwoHn z1nNwU=5M6hhvEg!KTL_ z>Cw1Srib95HUm=_RM+WLMxTeDRYZQW`nqlSxr>Ab$yPir@owlFOl$8bukj&1g1Hw z@J8-dSgjsDj1RZ2n#eA`fTx*8|9Xg@$i*^lNvVwG0HFR?|iS2td1B(Z7 zMl0|yVZGHe2+V*}CdhSdOYe|hz%{saf>m_a;WLS$i-S&9RdlL??q`_W5QmIV&y29@jD7; zo&&>_T1TMZO~GA%j)FUFUWl(<2hw;{s@{!^;92k1!yh0kVKsBA-i?b{(%NN@5KvJy zZ|35sQjUPflcE{0>P4{{@Zs&|Lo=jhT_(fFh|r~;*=K?MjHrtV_-sz0z2fJd!haXW z%M|{djPNtZFpKc}BOKjR_${=u>pDVb7bvF`a89*LPEXfzilj)9(};2ArXeM# zZ)CTRyybN5Wkyb$&r)<8Cpq=+y&-Z+ta8ff6)&54=|5A!oi;CEz%j~cT-aLIr7Ag{ zvs-pK?GhPu$mw|(*)nKW`Q$fUa=IWT%Oan2V^;{!}z~daY zg}F$juyhjN;N*wpABT8b#`2L6kAL`a7XXg5jlhoulb82GevrPsyn6TL=KT}ZyRWE@ z4ps&3T~!&lcYW1_$B=c4r!Eg%^%VZE4&3`pWcll%stM1_aT1SGR(P(&?bJqp)Z_?b z&#-d$WHkV3>);QoDu(?h5nf!a`i@vf)hJP_KzJBOenjWv2h``bK00juvj{UNT+D=-Ye>2SW@J&nFR7GUbkERprQsS@Pv9_wfoc6$dM1+I}i!n z`(711Fhh!!cpfBr!AXjT@LlA+wbs8db|HPu^XTgby04psyqL~@jlz34?*Bc`CXzC6 zw=GZ@xvW-D*b7a}uqzxWAilAlC}1`}sG9I}WC5|nZ2Is#zI!{e{Ebj#!h2+jrSGwz zqM|H-NeFW4v?uEtC_Q8Ng|U9~kU73L+@uAN&^7=0mt zsqD#Uli#}TVtZXm%v5*|9GKC62^S2Mp&)M66r4JuLlGT^bFMIr6P~G_HgKsQA%JS! zyYY8cmh7{l{KU%W6A@hGT^U`?g2s+8uKIZjLdDBkBhf|0Ef{8Me^vC_;&!~NivC}5 z4FAVxzM^suq&Ji?;T|A*?RBjDs9m?XZxG7bBhWZ(-&+vYcyRw8W`O;Y_$59eekt|l zCxRM@qLZoNao4w;KO~n(oAU;Ix*yINUpBo##9B0y6#mqG)=hikPRwBdrvM52`cGE$ zELY9#_Ek%!<37wwaAtaM2{D|4S>`LbS9 zCx81h+e>{q@4fY?2UwMV{dCDm3a@d_kLjODlIEKq^T!=*zU?|u!LteTV}A43vE;|> zJC88?;wLD0v*xEb^JDr?5k||EAJe7#GrUedW&B0+7s|&ZmQ`fw`sw=7#vdg=rbM?V ze{viw@}k%L`ZMH9)la{M-2-U2RQ>cSd;zJ+te-B!+~>%TX$BEo`7ufTRa$;v8 zSacXMN7SeG4C-jyGbIJpP=gi9lCAlJ-FFCGSS9IWp=q$}G(zr33Ha-G)%abX)%7hQ?z!;|iMQLpl1`@*$ai)(s`9yiZCfLkyM*U3l=5HZ^) zQZW7nhLXZSTfIm>zMvPSUVQL4g`da10(GaeUOfMMqF5{LeNR+r7YWT!Vc+-dNztCZ zzvo+AE@p*MXCEPa)~VkKVM1p~JvV9`QKdHI^98)>xly-R*>M!=xt9kzRzq$`4#yPD z`>Cw`43So6tCc8vm= zgYBf^Y5p<5>CV^jQC^(%e&c*Moc{;C=cZ*IaDKstv#zRedKx&x;L~izh+p@+^*Q8b z550i;mz5n?fGluuS32vHkBOd9dv#DE4!m3XBN(OgLwmZM3m=<5-^xtgm%eE^lP4OE8wYv1UwDEf>O!%T(VamCVyo$vmT6Ur>`) z$h@*r-34zhs5yq*0M<+AhMe#e!VN)yqxbV#j#2u}t%o3nsrtXm3BKA`g^e&X@OwGA(is=m#*4^#$pS|?`zQTY(jr&!P8^$mp+7T1%Ih`hN53y{!-#x z;hkLmQiJXaif7YgYuzofnclb-co~6cb z(Bp4ve<@k6@E*l(M_dql?oY0>{iPltQi#9QrN`M+{?Z@`O@C=goqH1e!{@u~_r1^9 zA^q1P}U3i>zy4w%gV1H@o$im??eu(i;ODQi-f9Zj5x#8Skf2ni>;0!}p zv-wLyM=1Q=c8a~v@9>urR7<)2rQi=J|C{}#&HfTEmCW?bHv3CsaE){NCk462pI(2d z=Ih>i=u_)24O7#}A=5}Ji>{IFtWVc@RHxMz;4cl7Df*AIzZ7a9mGbqM&Pq-({!&=O zvkCpB6IP7HUwRU@75t_4Llyn<@|Qvv3h(6dm%_TgeElW=XycFKFAW@`;D@O&Uj9<& z4|DoULtqV;zf=pl@T)@orLH-&I>zKL9W*n|e71`5nf_A$!HORF_)EP%^7fY!x7dA$ zKvrwuWc#!6mpbPXa)-ZkX^k2`tjFKf{?fof3hzSwrC}gah`-dJ$Jtc=lCKejroVLh zN$yGT2b)~>`+LW2a(}7jz`W?5(_iX!(&B12oEz*f z`8EK~FoZRmztlZd;h&Gc6rynF_Lst!Q2sajOPl?r&HfU%5!DXf=KUpaZgA``g}&yk zhd#CbQt(nyhM(g7rG1Wd_)DRo^!n`XeHFd2G$Z)xf45;Id z@1yAGg?}^g7#08TW#W%83o+;${e$R`%Y9nrx$Rq zMm8Qce_TaiWZKLc&Qtj;c)BBq$plCq1>C;iLV~VqIDtU5x;B)TM4003VgR9ww`UM4Z3sH zZpV7Qtoq$DP0mffv;5Zcx-YL<&;eMvS!>FkK*QOw8q>c+{V^B=8L(4<1=tD(`E_0kDMLXU2OaeITwN+L5`gN?=F73rs znmW)@>y>X(c3Qv~_RHv5?>f-uA#5rSqhT*iKPP_Z1@qym*Je5vpvRr1re3>K!bR#B z`TOp) z?RxFrVsE$|^WwOlbhLVHUqVDf*MWwtAN(CT^sf6!OF1#ZW@6e5Ss7}>7t3|X%aXP3h=;dU*DFCS*hnOUft z+u4;~sQ;IeQ<1~x@Of-C*gwalWQu3fi05zAoOy|7shpaUvHU)Z7O=CX6d;#8roclk zzpLdktmP85*Rh!HH>+G8oI@__k$aa_F82|+EH(W**N<#+IdEl8xja3qTz0bF+98+i z9`)8~>*Ek;omwCNIK4o*y#H_`mo>YMT`tQ`9cQ^DRypPJ$9BDS=dRvxk5MjzYUb2= zCL!y%m$S>|pvaw;%Zjp8oi&VOQ)kV$y3RUfGKU}tSYYErOFZ0zj}GM&hVh7c8T$ry zipg7@w^8e?ef?LFd1r;K3js=DHP#=1u?s9_eilvKHP&Lqu*UjU8V+7H)>rZel>F7l z2QK1I=!@w~ez`a={yjIqZ0_pF<6m2Cey)m^?d*5{&0 z-lfsyYRt6KXkNfqaE*1+qsICzXN|SQZyI)1`YR*uAm`}dzyL&-XpQ^9>8!CnpB66S zOl7*=z^*Ah0sofv5thaD8tX3-C7QPxHP*Mq5=CnKfx}(>tf~liLP1qbeO!lq;J!BD z%Iu~PhM-eW2GGi^hrcBS*8X;A4O3uEsqs#dV3e%B04bRGSt2$S^GBUCA^WN-Ckx)fRA5+XONfB zzmuXb-FBD@_KSHQ%!^K|%kH_FD}rZTc8l(ZbIcdl1(|Q~Mgq-LDvYc~64_&2b_htB zy6muSUoNdv?LF(V?@iTZd*=C1+1qFAf6w0?bpVMS75?L#*OI)3DCe8kviLbWuccnY zvjvHd7wIVTAm>w7gBNufNZY%Y?<_X~yb$TQkls1Xb^7Mt1ldpFIfzo_KRESS9`A@E zsOpaLAf$zb{;0~C+K+o_tD>mmk6(1tSn^ulnMOmv*Yo)l|6tLRIVap(8@Qcy)5)I* zBjn0!sn`7(UQFRHb@@Se-E`?_fo28WEg=`Z6~7&)oB>CfN`aCK(g zbOYu-M;$;9h~Ua=DZN&Gm66v1Rr#TJ-EvI`CW0+*g4U8|(MXU^=q*)=cVOnuGUTF*3>-ypTpF+PnFPt8wemJ&+qI(|s9f8G{ zVq$pTG!g~u4GI&y;>4+QIdESo1VG<69n$@~_u(COYGCnOu$Zt~V8tltzUg7$Dx$Xk z)HDKuR{omns3K=!;&d(YlV1f9Q}?T3g(~d6=`b%5miwlk*bXWnIHw_4=4{EFr zu)5BU1wX6kJxbmV^G75!J)=0Bao=>(joVxM0ymuUn}YEeB_+dv(;NXhFID&JzHi!w z@f5-+c0+xza5&xhBVC=YIXET*&gGDEH!bsk^B%iCxj(SMa0XjMd>zSMH+{wSkLz^* zIrF=Yq}}Ire!$r8oBk6bZS?Pkx6cbd>@rGS%ndsD8iq7xOO28FZP)$g%A0Ga6$-r* z{u$L9bk6BGngM_f7jqZ?AltalCK(JVq|ZR;|slX1n@Z zS8Km7b<@yKSojLMZ~7p@v1BawP2Y+-QYwy7?wh_;Dx2@engZivquw_i(f3Uw%>6Ns zPQ#HyVe5a+a^^;cz{Yynv}gA>vinVP)3oRCQ#LMk{j4j-z0PBuy8`Z1^F%K!W!Z&X zFnt_nc&rypd&2NALYJ^#Y4g!fF@M?XpKlc9@hQ$viIzC>Q%3W9l76M%$Jy^m+(atn z>-StWVEa7{8lFw)_bj+(EPl_2u;;)xy;~{z(Qh_B1KxW3J&7*iom_rTgYGY1zo%@p z@kjA{l3ObH2{UED;IILHPd(;7hu_l;BDnmXlAFio_YB?+dXC-isoN{fY`1D$pTqb} z`y+IRx8GAX7wxs*(|b!{eoyBXitZcB?bDSoi0ab1%Oq3BK6u_jH)^ zp$6bj@HAAMks8H@+M-{?{GKil!R7aa?irik zGw?gmbL@UkJe%VUKt9it_jr`#slh@9=vD zT=mFBZz+9FI~R#R_Dk~mCN`JkTaR4(5Owl~)FX$`Lq?V9@3-d4H^T-?^4$2zVXtkJ zdSw5<6(f|7BkG*iW*`sSu{_p{+Ql}__{OUys%sfR&!~yo4=qed^6mg4 zqa=CT)R&`|B){?*^pIAP9QHN8=_QYN&Z{1IDf0CgjdRsOZja;ucRg}Q_nWoeYK`v8 zs}8ajx<6~Z)t}LDcC6o0aBrDUy;WI1shhPP`R^=z5Z-d%AKfRvr0%8t73&v30B1e2 zx{^%SBS-!SQ7ye*?o%waj>ig7P#xsaP&O(LZ#eFOpVB+7I!I?dvGe}u8O69idWOC~ zx(*Q!peUu0Fz{7rhlaep+ztN2PvlvAhv;~SJX<9-K7BeBX-Z>8>!KH9EFF3AG7 z?H^2NETj&y1tT+&@|oADxUIE!WUsdhiwNm@tLG*{`qS%?8HOyk3AD7Eq7esr$_;hq>yJ>kxa+Du=2bxyLp>kXYrE z!^d7WdAwbJ_lA3na_CnxXXNmdUuKuX0g*E;ht(rf+;ZrD)FFr8pOh|#75KcV>yi5f zpbYU;^~kla6(E-d)Fbhno5%bk$nTi{FZS;84=hxxDtxu8 za>}J$kDMWwKW9C%tp?6PPyD)Y|9qtLHlLwYwz0Ipy+@KO4F9XMx)>FNLg+T^QN1J}&FZE|+z}=2|X)|KSw--sgPl zk?RLM+=C0y(I;DvT=OTA0QJbPegNbPy7PIw>ydAvrSDab9OVzFM@|Z?qtzoPZ`@pu zjOy;q^~m|$`Minik%#}P^lnDn!Bvmk2~Ky`BX{d|8(NQCXZrD|M=qg)%Dn5Do~$WH z{@QM;9JvVKrI#b$>QiwJ)Bh)1k9^*Fx$BWjHzrXX+NCMw6oL;zQ)5PgQ(4(`t-%z^A7SxR{R$kL0RBq ztTM(b5`LO1-a82D@@cuAyL)6$HD3Q3MK_McS04BeWW|5tUoPS33G4nN4gRWE)i2*0 ze#oTj!tDLdF#WFGeK$?l{QLb%_I|%<`n_Td{XV-YD;+K|{q8r0elO16@9n1F=R<}L z{-MnIgYiH*bAMz`c?SRP;^_Y*vWL0n9Pi`9&&>3dFB?+h#H}Cbac0N5UPvE@@+sp) z*Oo7PcB%xh{MIRh0SQrreGRVX$ydzZ$qv`T$5QmnfUEgg!nMtF!e4Rg`6&wj*)hLs z9Kt2z5Uzy>Xtl+5HBW$=DT;mWf8HaEkaG-|k z%Qjp_?=d#bm!Z>-I75kNnrN~nIYaFj5iV2^au(-;`Q`MZGY|StR{OfB`moz-F=z9h zmQYB^|4xLfjo|DFlP-dHNVn^Z;&;$3?~BGU4++`tF}iC91(q$pyQaalWG)VHom(Wb z|Lidzjoo^p z7)2*R2LIT2rS$%@Bv0L6WDOK_V4YCSs^Z!Y5#AozGd3!nUnH^6QQ7n9bp8pxx9J?l z2W$O$4>|*RbCkloXNmlP|3mN(ZV(<6Qq*fw;vQd+SOtR-C+2U768?ra$+I6LJ!TZY z$Uw1^FtcMASY96Zf0bYlfIZau=PEAdp^8}liVo70eLqE6`kABBWfyQ12k3esoi48d zoOHUZN#sSBl1)XIJqh+OrZX2^P6J)EOndI%I^qbc(VwpdWT41UwfqEhZPs+nMn|Vm zd_BbpnC;)D5ki3sUIhFy#wD%0hCpjMqaz5B4oaB&0%7Ob znR?FF2Z2R*02|JI(HhUWZ@M)d@7@0myhXV1Pj0+9fdgtia0|A=n-9cAt>Mimg3WbA z)HAlEI|-^Ba3TBh3+#OiH(U;W6uFNm95eOaI?;Q5aU=JSI~hF>xqn;}vFxREzG=nx zHvL5Rzxq#axwjVs;hQ1RfY67-g(|<%ONsIy?zUvFT6;qF8Izfev_DUJgF0OOu~&(g7rp^NM>6E!0M%A<+OA zfx9S3sl@|N%5I}$lab6e3Xg@rV`+AZfy=>12NJzuOtYt+JWL3v*ZMl(X03ly)_NN) zS?dj20%H#$>osD~FKFQ#B{`m`$?4C9p+>ba+f#2e|5fvX?G6XpwjEV(H11D2)V%CT zho(Ey=lWk(4jKqD1=4^N8y3w1`lvl*el^PU(hO7fQHI^exBzhx{mJv=s8~{TP+XeQ zcMg6iAsuSL?jHO=I`nlKVYUEk;e7{m0fab?wQHER=l-@nGJ`8UP^QN>^rya; z@gX3Fc3%^YMQc^vssTs7^@OwU~i5j$4;TuiY z*kcNRj%jFsx1tZ$b1ChpNRkdmgAS&Ef8Kt?IUWbjw1?qn9>g@6WZi2-90qdvvLC1j zLeg3qw5c9Kw|%vTsD(YG$K_aj5$_39ITBC6LtON&=a&Vvz6|T<4V}oRd=L2OchA|~ zIW>Qzh(_SVS4@2u{Uod{r+lP*_*nAMOnzrS&S_5ZQH&UgZzp`zM?QKeU}I#a66bMr z>3$6j$wwMK;iEI1103xHmP~8&(U2Yx4-EJGeWp)g5?u>K(pbtmXt$4$0n*lvDM~>B z|H9D6wi|E{4a24g0a$}~1bkhOWS{Q|U&=Y(rGO`GzH9zr&-c&GeE;9}Hg!TEL0{3K zYQ9VLxcE+9GT(kZ-*21we*Iy4zV-8reHonCkn0pbFKdK1W}S(AG$lvD(VqVvpWn}Z zet4y#L)QM!;qxEc=fd@j_WWsl{we$UPW`->TpbDc!M8)SS6i1NJG!r4Q^_%-*4JO1 z0(%LM%FE2BlZ~Dc)idzEj(d?J&X|w*E2}C(Ew58!%Z)aE@IlBLxGmuGYxovvhL!oi zNVZ)uxpAf9n-VJq*JNmgqSqn^JX%kMw4MqqJRdVdT@_e(H@kvKGt99i^RVf*G!1B- zjwAgcH|FJqpBM)T8$ZsV7k+hbxbTbrGT$yHc?EOf z>DM^tJ)UW3)1&Pc-E#_ zExNM$ajLzR#4tbiq&~~_i{Kbi_L`LD<){t0r0{G#_ZYPGS@Q!=xAm7XKYzag?5j2E*YQ zW0d;{hRbX=j5aI^3lBNmC-Ym9zbUgDDYydRjN&yKOzs0(Cj)=zkFsTo?z!pL_}w(x zP0>J)C+!5NKeA&dd2R#a3V94-y$Z2eSd`Bw?&nVfhH?&H2t@f)wh2TNp-yTNHFC55K zzYXah*|R-cd$cN|w5ItzP4>QSjc$k4(j_NGzV73xovd(yZ~+E?t@Oq-XeC5?F#x_Co^;e@fc| zFxRhF@rcysf1vGY{AR20GPJUq1WfdA@ORi3_I}z^oQ}bMOab+v$eRIJ#rP!<23Z{B zZ}xuL+rWXrEM*U9_?_dBHtfjO-xHMnreyRBndfd#O^f4E8RxNzM3svzUrOM6UzlRs zybieS`0Q%JJ;eP^1MV=tiAy+&9A@BtDFbfFr+{!YCuaJVNgxAokYlce9^m>~@}S}` zCq6O{cD%lE@4g14c#sIz5B`cY$`Z|=T-nm{Hh^vk#!(9}S9HB6Ff2Mp*;Bo}>GDW? zUE|#Wx+RmUBjk&?0>)~;ELNxc@!})qtbmVHeE3$)M`iD1^3kbIK9Z^Uy_}2>KH{A6 z0D*)B2;|as}XO7GEqSsF!X}#p5$xQsp%R7Ez4}J*MjE0 z7TvGc{O-*Db)4cH5~k!o&X{G>Tw6C#pIWE=#e4tAR@1Wop(44omZ+=E<}Q7zzK9K4 z*q8Xd!j~}eMgG_tf3_brp>aomO?Rvfz6To)mn)@N0u_a1?wQK(p6lJAPHZZ18vqk|wOr zee0hR!qRd!^xGVG`+N;K@U8)_2JfQxY`pg|c(3^=9q*E_JMga8H(nqlqSQz*_Os!qMKnor`gG*E7Ho@1pCp`x01)( zB}<1^D)O`zfSQI)guFePyyS#_PTrEa6U&#~iEpi6U5niTd>#BizMiDNz7}8i-8@mr zGiT`f)O)Xb7q#Av6hB%6H3Glf>-_I^2h5K3g6GIjlZ}DF5BfFPyutsD{m21{lQv?0 z`+5O!w(A`f|2oh2Vs~Py99B^jSb85m^{wAdEG}-dlWfWMYw;%f4O!nm0D;To2QkIT z(BoaqfctRv!yu(^@iVN%$i^Tk<~=(P8TT7oE`YwDGmuLFEO}voelN z)C(>{nt$HZ1>YREV&l$%<#cM35jHVmEHcQ=rQeS1d4(G;b*)SZu5Bn~@E6yb`!Od$ zaF3D4z+$P_n>G|!lz>H!UlOE1WCW=(gSfz{GWsqoM2tGzqh&4H6puvbC#s?VMD1$@ z+I}v^d@SGb6}`T=D)7CWJ%^5O7C4JMY1S03OivSM7Qt8d)mx@Bo9#C*c{QxFOPUJm%$T{VQr5FiBJU`tEFT#mYz%>BvV2$*gI$~si|;WGxBB0$uOq~E#yh&pAsp)q z|7hKB6}>}uDSM48lbe633bDTSQqL_s9G@!5TrUBP!SIAr00x$ALV_;m4@39>QFQ_o zqYw@X)ow=*wmnjU57u8+D0^hGo@g`A;Gq(e-z4_PaQ9cfg}GMwO>tvxB&avJguDv% z0}7ro0QKXGbvHpJ`V#n0v}fpsQ!y`!y|I)_@kWV?vz6Vc?b9s*4PG3d(};dSwd#_{ zw1L3Vohe-4p>|+dzO4B;tTteWj?>^Z;3=?=HEXWcyKX$t%-8Qbh3ia+a>yN0#Y+-r zu!@^e47sYJsAv)i_)cWWg?@PgwTHN?oTnfFhUolK+>=#?(ZUo?D=?3vwE#?CbGL%u z&oBU9HvDOF(mfHqJN11V9u<9GrrSH$3&9_H-zTk{yAlK^2{5S9rJkiz^ggt<*85>L z@zVQ)cPKd9-EguV4Oe|Z|CfpWxAjWouvx*tBF10(hG1O`Vqf>WuN zTv{BKkiu%K35reYl3HMA-SP#Ur1=G2NLR354*OL3v3r4&Di=J`jwiGn1Qu_J?=YG8 zo8^B{q(Az0W%P+EEL^MKj6|QoI##**Z}Ll36dvG{>A$>IJ?+K7qQ}r9Wu#>os;n}4 zX>qI?Oww72%$qKL-%YvTn;wh?v%jjirLyDX;_gVt#lfnMqe4~FRs|M@FnU$=aV%6a z#9OUz1muk@TGKubbZmnM*vUW`b3pkUl7zf!sV(W?E>-lXqR6U=N(d(!AxxAA_nwR> z+14*sM?WuyGy~-HPPNvcX0k5mhqJTbk!EEz_?oxED6NlS@x&Frs06Bt&SY*v!umDz z68(#EG~&x4H+KB{4gxx4&>j}TQe=QSR*w^cxRA6cGVSd-dqq}FZ~xtS_Ke<6fuZT7E(YTjfE8Cj=mvfoMJU^g7%mXg9f1x>VIevh{1yehK89goUAzD>7TC|;`fc4I%I@d^!P!RznFFuRo7H;3_j+mOTk*Ge zgbnmxkN8`=ZVgc5qk!skXRlnwb>R^Wv}4|EfBTt~w<=uYQg#0Y0ZPC&G_PT%3~`As z-I`O-556s5_8Ne({vs!A*m+OZ=P{~=LhPQ&_#9bs32i!naxQs@1NA zNd<^h7IzDqX0!)VK7in~RcgK`fq<^6Y0CrGt_7(dC-ook4OlgPwDPW07SwKfw@51UheFlpTQ-+WI&d)(1$T4UZ_6`Rq0ar@_AscoUs6 zh^3sDHvkZ=zZpJXA$VH5QY%K`y*%c(&cu7o&~<9QeP!F8;GF02(FX787P6p zw?HZQc2!G`-LVpEv#0~>RTb_vrw#YMTq+`-sU*<|I~Q3e@W#Y6r!bsA&rrb;PP+B# zLx`7AneyeBA1da4@Q;Zb%zKDLOV$g~l`j1VkJO|Xm0SY~g}b+NbiWYY&yGbem+sU1 zS1tus$#7&F1Wy)VJIUv3T#7Mm-EkYo)T<2!HvvQ{aSogn?sWiGv_%NxTFZWK{NL!l z>2NsZL-M#pJ|IOAF-GyGjBjY0l}e(o*w?eD3&6iKvG_E?R*N>im|7Vsd^NxyGg7$^ zmZeMJ)W9L+HQCl;2)y<)23W9*mrZX3d4|x8GLY`qgtUK%n? z%~jE*#VzPI{x@t>$hiees)}nOXt`uYac$M^DxNsJhk9}I9B9>?e6NL5EU zH9p^mB}#yu%&0@>f0VR^B!p3{`yLS8Z0k-b3edU}Il&palM5K_m$DnwI_uQSvc9JD zGI*y6lln^Q8;CWHAl9@i^W$1a5NrB6MYYxT)B}rm#uqrQbDPMt!N8)I1V-pBqvYb0 zTKY@Fk&X!TTLa9W^>YsLa@D~%$*#{D#T7-6qg5B)a<1TYMt6?1F88l{Nb~2GS|Ql{ z>GXe-HBf;N+fu`t5{%dfiES#S$cKT*7`#Lr(F$Qmi3^F3dmrOM!Rxco3F~AyX!r_b z(wTq{i;A5c8|qZ;9;JTAi|~=Y4xJHLyqfoXnh3eFRFw#a`jpYgIKUGT9P4Gw@yP1e zs9Jy%R(QGXz61m+rF6q`U$0CNEy$}XhUx`D#%6}ymYk5{5KuzJLrOKgUUnT#CfHq! zU(N|pum^U40-&MCP)`&7pHJg(*t+WX{~YN{YWG&zcW5fFwE2PYVxNa`ouU)R;ET^G z+%XYY#JVt4Wpp`C@50IpoK3cPk@fa}nV;CM+e>5oLv$Vaa%dr;b4jp3{gw2^hXJ4d@7-R?Ki?m@PjY1%d9XcyP* z?v!?wfYaL5v@6TeF7$Z?=grb?Yqt9b+);tkm!n;+Zg;)3JDct9Hthy}nw>5&-R^2> zx19Jf*dyb`aoQV9l z@oTf=*Pz>7DD9#g&(3q{$3WaqCVgY_KzJW`x9*+c1Yhzs#RgrARb@EGh-NQ z7ne#Obb@*ShhJq*c(LPAt*U!_9QZ*Drv$q&S=gfsFn%JVA>$h)?S6y7e^zkN#HuJ- zcciu_4P6Y}TkC!S=2rCMn5$`M#-GgZz$AQ6TbS{>$B@i4HH*gQKMP!#Go8h(m$ zdo3~cThNj3bNDkh7C)PK9fr02=3UrlvYD_k{TpGtjx&lsuyzN_IQ;Uy`okRgR)!wz zlP^cV_B?-{^w<+44Pwh)l1fupl3)57bdMb0RkaLM9eJvR&lI)mLv3cj@Ev&yo1E*G z(yuY|C%`!1vG+~x#ms^Ok}Xrn*NkAPbA7nqf^&U1w|p6X6+Qx2KExk@fsRQ{y-<%13-EI!(3Hh&al67CR<`2mT zFJH!~z}SB4IbJU1rSIZ~1rD*3|x5IO*(T898(Es7HP+^^fj zixdO25} z&!!9#**#od9S=u>R;#~ zb&t}s8vm|6lpb={i@e}Ow-z6)KSO|Jz3E?oS z6=gE1h_BBZTBGKm8sx?HfKkmM$dQpZFS>#RCO#2ZcrhqLzAD|*P1mN+VSb$RDDA)i zoqK^QlILUOJJ42zZfuT|ottk$6KUCtpr!S7e4ZV1>qpSuKA=PL4Enp(`Bp_FB9>@( zVr}8)TXFX$bDgs1Kd^}GL)w-Vi#WM!QiKki3%+c<1v<2VWX#1tc?ZOAR*`jNeIO0x zV{WzWI@LPW-ii00$W($i-;DS9R$|sQ6Se4Lb|K17&kq1}n5IA@Ni<9@ib^G3s};P; zPe{XC;+?84xA70a!ek!>7LSOs#e$|PSknt;&M5vH=Tg#HrA`T^(%b7=`Z_iLXYiRl zKaI$k!h02>-bK}MNgvr$4m)~KDlno?u6urVtY=ZCUf~$HGDyk4sUKoM z6dlJ)_Lj*<1sBf$dkF(^q`B|hmM#7R491;bdjJ4?Tj$&iH zY<&sZ_o5xLvX)HWTXt8~Bv=baxNjZS?VS3?(3>`e7d#j z#`I(Rt;zU4oDWnKx593^9Y@MJb@ydA8oSB#WAva?kBQyXZ}RU4RKC1>A_~{vw5)Bv z)jdA>IZV)b&dl;PaM|xVk95;$I`wt3AJ2(N3^KubnGVNX^YD%TK^w6bI45Qd{!e|u zms75%qOD}<5A|T?)De%liN~gr?$fuF`yZHb;jsUB4w7w; zh~oVIb=n?r+GV7Nb3GJ$q<>(e_%lNnDf}ku#ftNw?Ghvl49%Y+p5dwre@!Wcji;H= z_p~l}7lwc9qX}c4NP0i^iQ094PJFa|;;SWT#NR{wSL!;NU@oflvL<`GRx681HY`Y&-Ou&hJ6;e~<_R9ioXNm3a6p-hBs^^7s!I$Ar?|B(_e=8PlR`Zg9 z7yTxbW_4T+*Gd9{up8q-SUop5&ka@x?V0`q$cnRq@I9KQ=r~(^p6YjnLQC*6^HY!K zopcUb|9(gAw@A*84d`}kMppT({@>Vv%`m-^+lH!Od24woNit z*Es5WqT;kKgL43W+&7IA=e?dRb_zlm)UkHGI&c5BMCz^G%lTOS+t^%%SBBo#{_U55 zOR!5QmWm$j4fBiaXBH8x2K>10EyMwIe@AiB@go1}bqPX{;_okk;N*ecLrEr48JujS zY*Xv)&N*pe`^20q`V_KJgtkt-CooxW|Jx42h0%ev;wtEv41W;vV8;z4?l_Q(u7xl? z3$zgj&jzE#0ius)U5!xo zQuJ&F6^K{S*U4+?>uOB*y8^iLW%DbZ??*T3^!(XB&AM8n+vSLNrQ4T@!#KFNKFG8$ zx9j+X?aSsLDteDr}4LpcZ?PF75pgLd7ommCbB8z-HE){iYC2NB)QOAcsj z+IFIe`!*lJ!Ff_zW}H1U?z_d6d9RC+agF;nUy#Xnf{!!q+e<<^;=TcprLXe{XWX|` z_v7S4=?CjqDM%r7m24Xmi##As{-r&_zXIcfvtAxO-k|nVkC-URK3P=G`OtCSd!A2^ zH(b$f_#IEn%VAHt_+9VYiCI1_`*z$f&D^&G|CSv|vYUACL&qC>5kLc9YQH(PzgH9% z)^q!jvcKoXk8;w3adiAiHu!?pkJj3@g@gfSFE;d1)Jcu+^f#40AboOJ*Bf?!O#-M1 zsN6xIpZ}+qc_e(;fR&;P@Tw&pZ2Db%9O-8swCM-_93q`{%9#n3i%p>HX-2Z`{ROrs zzvhmYcZ1_y@tg#{$|Ig*`lsyhW&GC=Cd&3-0c@~)LSwM+w||ynVG`gVrdafe%ZOD8 zpS4}dJ_zsV{Y@O_{w9xefBwAst2tlkGoz;`lK^=6@i(Dm66rZ8=T&ThUqI8L`sp(H zNHjPW0&~(Apd)qz(0UWr8G*IOseI-L_at&Ta9D-CqGI5ww>9y3#Ms%%2!P# z`EaGM)FW^b^fvCg*WkZ~G`#d3_+me%-o`$=@J#%Qj{Nb6bVSCN&H~aIhv-pQFju7n zEL?)0n;y0u<{&z?ZfQlvR8rj#Sz=ufwKbspx`@Aat9u$ttm9I@HnZ(){Hpx<7B9T< z2yj*BMYr9GPtXd@ChPG5{3My2F?DDWYrtUybj6d<6CE>(uVK`p+k`KA@J3XtDu?9p zQ1~XKk|gl-&3u=B;;_BbCIJ#hb|^;ij(@P&sjpUDP*-A|4dox}K2Oglg#|B}PyCL*9UcaVLxI@6Ez;^>FG-q290w-m*IRJWW41;?G41|XP9&~XxM76`^99wZ-tVCg>e8O0!&BoZRP!I>Dv z93!z%PxEaLekXl^M~mPw1VB>p4Ra4t#G~CLwzK)=3Z_$}vP}bv&l3-4y6}uX=n7|P zGyVm1KHz}0N0V^+pw%U#wF~eUgRh$^a)Z3Lfzy_(ekKtZhk8xajJ}qy@r${C)n&{|OaI;6= z4#~#90`1=Okjlc9-nK_H`R#mjZ7&2CUXRW}w`BJ>NqlYh-v6Yn^~3nx`tf|D*G)gh zE&`|6aSpNT2IAxBchIC#>j|Kcml>BJmjYz({m`|mVZ)6ff1wL2u*)8c-$9|K#2ulV4^0zV0evc2B==3R>EVK8zl$?JoU<{Jxem6<)1?f-hO`03MfL z?yE_@PtUQ`PpNq5PA|dlYd+HH_m$~>oPM9s1@l+}QsDj{){f6oF^eN!H1p@n-ps!-rn-&0j z-DkWFA>q;*hr@x~M<|J)b?P(rJyazcF0c0MmO+1H{~b5izjXN*sM{K-ZK;(GR8wUrP9Foi&vr>=a%6u7eUrD{7lHX?cb*5rEUWMw&*yU zwrj0PgEG%fek5O}>@VBD^(E2Hv7SgIeJ4GiTr2sq^@*BCe~fK}m0^a-H2SUP!_z6$ z(mX{qcC>fWN6x+4X!)yB);xGTQDZSP-Pc+1^_OC@&W_c8OYxJFZtQ~Xk_s4@)oZOYp3$}sUi1mh5lpU*Qq$Vun8x=NRnCz|KqBUiV|zb=QZBV zrz!Zh(18nS5An5asq<+|QE5Ri71cu4)3>q;u7%^3>Gn>(nm`r7IIQzr_d!7{>$&cZ z#9L^#Ae9S`gHU;OG$-yM1BQJAwF=%eeW=DWbpiLKcz4aZ-*72}e)C#i2*16aOa3n6 ziQPEM{$u_CFxpQ{uT{DU-}5L0XzaN-6AGH@e}i^mNC|$le$kX=y#Wa^3m*B-^JJ@Z zSY7tw&UOAfJqbJ483W7x05WnbMh0HyWy_;&A0powD1?AQiXJvO18pkbS=hUL*+a;l zMz4PBYv`2}!;zQe@|*QVH4b@}e+Al8J3g-Msew~8pXq+I7>Qja^3b8{Gpg{3fcKtE zz_ndLdKp#SVV?+v_P8BqJn zh;C}L`(~Am4L+%vspt@@uE#3Pm0ngI8? z?7}bx%fl`lRbICT2Vh3G?8af{Zvp@!Qg>>)ysiR->Gt6NF3cjIfZw*qb^iAzz2Cln zW)?YBeq7&Yk(EseMX-RFmY(9owCOkLSnecPwty=3Tp9h~#8c`;1|pjX&%mNXm0O(=cm~Q%?Tpr-xQ*VuRzvKIl6zcbN)ym*1&wUvV zTyt)1|LliGUm003csS{={J#2eqQ{Z~yKix53+vDUqwVssee)3&UYQDv8($|y7(vgwG@d_U2eDi(p z33@#lJPi#q*OOk|&U5_S>&evbZ~XP7o#=Y4Cq4}~P?VQ*Jt;yXZ$7(hrQx&Qh*({1u^hj~&l(&p#|WgOf^s#pL1U&Ohw7pSRhxM}zJyY@dRQ_R7ezor#%rpPc&sH`Y>I>4;eyO+; zu=P60sVUjaFaI!aIf$I?1Rzg2xUqf=a`1`e;fBsK^Om0+^w`gjT@HrXM?D>Vt zfu`rCmxG2nLr*U`@R6ZX?3$+>1leb9Ip|97c!T9Y<+aSlY6K%QK6s8308cp>gr2tz zaLMQR*?C3|%zERn|Ll06%IBz8bsd`^9#}$DMDH8^4YXY#CU<7sQk0DCPdDPo>TvKNWkn7JvJn=9rE;w6g-=rtGxft*=J+KV1XD`6%D( zKe+b6oF{=?dBo7LUe}pjVFr@q2%v7x5to%7E-Ss}KFxl0P{SEGLl|Kib) zlhHoR%N)70it|lPcxM0{%kJcC2V4M|I@^Jj1KN>j0EAZcx!PZiRVezn;J?WU{}&Ye z4F>-E4g8($I%lYhx`88i6OkT+NG3+t7l=_m)}s6{y5t0J0 zgUB%-Ha@+X_;AhN82I$UTkyt**<^Z#B(dXHXA3@w=?b56g-!||?2GdfsMh54z{2|& zsFVY&lXK?G!FP>wO7U+~p!MtUyMSuYOx-UyKgk+_g69sY)1)aacz*7juQ;9!EdD;^ zL!KXogQw0ZNZyKKXv+#QlFF<)#^{m=?hWO;LABjVBPg=-L za^hGg-^pR(JvN8I>Q_48Z(g+PUIp;mxM=Z7@fook+~Lq@5=)68Molhe$TwaB~9 z`DDO68A0_%#*=BZ3M}r?glG720MP8$r>bS5@oU( zNTmcZusCR*Y-i6r5gpUDNA4|v?gl<3lFBr(AwV(1loy!-ldG3hm+BJ{TK;n zsN=L9ljZvS)heRc{B8bTV*k#)GwVV8*jI}9D-9LXQ_*avnG`83hf}q7GMX-`DEPJPIik8WX{rS+7p)? zg*BXYx*xXX%Z|@r&mX&23|soGJ8)@6Ouf9$pJqFIf9wi=z+PnN`zrFBIyZ~sI`=uQ z|JKHhOZC-g97(Tia9h(cABZ0qf0wxMMLP0j==dYjF`;p4Rh5t_e2Va-_4sMPM;hTD zW5=iLl*VsB4vWmf&0Qujkf{muUC}i3^u?y;vd+F1jYHqrc*Ds6+Y_H`@LI>_#>WYR zoF^$`Ggg+mruy(Zt!!{<{+P21d877+8N6{Mc(ThL zD9kS9Wz$h@@%gR8&J;T;(@&5*5q}xFmRxfh*xHS>=5@18i|$hX)7K^#zMV5I;~esd z``G8qN~x!P26_3i@C$OqbHX}v;jWVKJ+i0id-Q(qD#_aK(Wc)m$I$PI+54Sm`n_jC z;qZR2cUE|RVfsDA?ziOYN-sI-q4g2{)$O3 z{@JnqY3bvTPh=d{8Qh|dLh@VBmj)!k2>Mb#Prl(F_Y*W+teczjJ&x==>o7D2j3jrp zrJZ%ybf(HLsL}m7{SxU<=WW4rHu+jb*7?6rozGOHPA&}U_D(-Q+C$9@18Had6XiZ> zU3nj3;<3Rpg}0YJlYC9HKYjxc1Wxf@;32tJ_B{YBj&IuE*2QIb(AsV$B?R)_tot`I zZs-cVQRdWLavsrO43IJnmR{hnvRrL-2J3B5tSl~t#%`rvqi56?#}sj$4CcUx^JML- z^x5E{>GMrF+np#Xd_DN;sJ&8ro55GTbIDh47{2=1WrnZnUE>gc8Hao|N0nOnt;_Z^ zd==5p6IT9_ucY2e-2<4(SIvz%`6_vc!qdrD(w`S!1%8*R|I&QbtJ{|Y4!#J#vMs7OZVsGE9uXRuO8@0<(F!{ zs?+Vu(HmccU)qDOVn8}QzjW=rX8*1vdpqAC+F_4W<(JOgQS#;z2WFqQ1rzLfN%3JP z@E%>ieXU0GVW;lj$%n+ln-9YR;aK!rC#IBqSeFAIpkwo4;sAv=zLJ;lAw!s1_1ih2 z9DLZ>oW_UuUu5{O-8GKzA;%#f?xD_R^jkOXWB9OMKTlZsM?RFiy=;6~dyyv}nsu{C z_vhq8>CcM~_rC{xs1JV7Qi|m&2 zK^W>_Ai5d{%rly}-sKAn=;348`Zaz)*5B7^M^gVsp5lu!Qob+`a^9r(IYGDE`ZQbr zPP}#!yh4{S7vP{`rbH&JFO^P6b8dz;LWRMx+o*5=5AnZwY`aZpxW91rx-~##*~p~; zj(~}YclrM5z{NFi@K4Q)^2(RayKUUo)SA*UGpgaxM_ls?P;awXDYe-{Yfj_$8!rxRf`a&fd1u>FK!y&5peMf2qhIi?d%MC3mQq!TZs;r;*E`xf}P zs%rh|3q}McsKBUD28l3$$W#PVDlnyuPH2n4wh(FIM$sCt_i6}@L|QN;DNP8)@dZ&) zBff%HG(Nzx*SZnJU1_~HKJq>NP==P<@bg~V~TcKeKT_p))u z%sBPZa+3$r!?gJ(qZb}1MTppLK3m&3A3opkRpv1NaY|gF^_&Mi`!O~%&cua25j7@HYqtjA}Z?<})B&1Rf6(UapWLC7@e zxu+dxu*x_Ws&Pu5W`$cm-zoChg0bmw=AylNoD@-Ptx{BPSk=SHb{;&GbKX^E&|3AV z)vP{F=Vdm)bDuTE$FtV{if)n|kyQZ7+`7H5le`-TorL&~{yo8ymtI6ear)QSf`&Y3gd1J)cK=-dy|hucBQK*8co~ zm={WB53U)W2l@P1?azM(Gik~8+MmA)XNe^nYJdI|p65lJ@v4oFuEi_xy7S1ty;+Uh z%iiuldzchXF?V0cU|}!-oWG5h0O^T*MEth z()@HWKV_OW_0@AdKX0a=nd!dz)AbD|r~B$p(l_wp`s$CB8#P6JQ_+zlMpE5c z29zJxUGFcCq>an?JAuPz1ibK#$0S69lu(Iu^WN_{oY5fum7o8p`)fHLXT*}kZyf(5&K{K~FU6CpUDL1Ot5>Pl03R0CowMuYRt=wNxBNMm{GJUYPQ%a6 zZ&X~M>IlO9>Q4FDb$hNZ^Rw@18c^hMMRww6XEk{=oKxWGy~I=Dlo|g1w#K&^uSSQ( zBVFRJ&p9vPd~R>?+x?z1bTjWWFT%^jiIwvD%scrrncmySW2P^`nAX@sZBcOPyNpJHQF4#EB{dz&>*NJ;oHg=)dx_U1#|$ zZeSC!09tHAM6ZMC*6+FPiOeV1y0x{Z)8QPySkg1PHjn4|V5UOO^MPSf)0(ocPRs`m zv=L}P8=Ip5nadlUAMFy7iOE#@4YCPRoilXe0fBr(jo!c$4w931FS#;!83<1a^d3xab~r;`Mc3;{LIVfL8ljm3>d%P?@XOdM=xjRDt_UN zGty@EVt<4=F@UwETS0f{^qXfQpEowe^OJWez1**#^U`O89duH4yjSC9jHgNiBe~2b zV1%cRbJ9%tvgE8c>^LZ{+jGmAz{mV$u?{vuyv8miUe{p@3N;m|)|Em&ZkmbKQR#2I zJK!<5zZ$yHKoy&y3n{~UrXonZ&SkdDVeH0btG~(PkK2zl-_4981rJgtS zvul~!3rq-Z&e;b#`XF9edp9$Jh==^TRkg?`&)JP_0E89G?J4Xz7e z&SO`5GS&i&8}zT!&l472)K`Kx-EXD7`asY}UoG7HF4&_~Y!|gBowKm-0Fp-OtC2VQ z<5ST|W6k+4ZZR*YpEq)D#$)(O`!~*d{J?moq3n6X&s;~vcb6hugw>!=d*y!7F<@Z$@k&eq8zuY8>W0G%XkP#s2sQzOeP#9}pin4WjX6R#lrF_>A(C z#`)C*A4tdaSDE7Ztl_$khTy?P5ik?#wmJJ}6%^FUF zH}amFpTtA4bq6@BapC46yf21^c8`Q3Uh}V?a=bRptn!b+&ssTXV%`ywkh=9?cw8UZ zU>BiM+om#Zcw2Noe)QJ*vV(dg7yq2mBiJoMEqPd0qA*XfetA&0Yv^m`VSsw1PK!g> zS$~7lBbl%oZ{_n=kMO9=Kpj9JXQ*;2wIP>t8r7rdawZMroYZdJo)^E&!2Fk6kEnBY z$2IJYV~Hq1Qvy$bHI=c9r#yA<0E~I|~1RKU;tQQHs-0^z%yIR0P_B zJI1P`6fPBp_Uo@uC1TE9PH1_9RGLlkNJfg_cdg)I&4CiUM~i~j4iHko#m3c%`}!r| z-(p?l#21wFs2$(Kp~J(vjnZ^m9L=kXe9NntXDvzK`S$Dlx=G?3FaL(^8MyWWQx}>q zgIob9XO~-M22xQwEa($+mBX>S8{pC$cQ@b3?XCF7tAFz6vVofxj?sy94#No>Ym(zr zJa7D~;VGVTR&AWcd717ho-=V?>lDv9uYPPM+lx=}oM|sI#dFT`C#Ai>6wjIVjQ%kC z{8dCQF3?ZyXSxcK1{!9&zhrbHeJq(tRz8+>{?9%d^`f)2qh#m_A3l;;&=_9-DlkCQ zS%zn1CCK37n|QEhp?!$W>izSCN$9J+-s;&oSPR3;)gJfH3I@N3_h5ACKr(vVfn9=F z+PnHwboJw6lgi%1IoLda{h{8+PzC(L>`+f128~a1I^GX$JBuFdU_3bQmjo*!V4+MI zd-34pcAP$fC0~e9S-19f#57*x46A{yj1UlR_}9$W2bb12Pks;EHO%JmBZI4gn9-mA z@cI+^8y(FBXb$vWtQDGToNO6#fauJ2TWX0@MH&P|^j`2?nH*qiTmIuHlJK-eBR$)dydX~!rymCH zvUQnD2N!|B>tbNPXkt_Q3>bbihWbo|<&#I#SS6Vs<@@B-@{4h$`PwD76S803rT8&1 ze|zYXuiyj3)%oQ->n1heE9c3>iO*fi5ko z<3ofW3iuFJCEsgVEJ@KMAsd`6>ka@Aomof|0<-hs14|T|CHb2M7w5^x6KVDW_SLc? z%Pi9f`PC!kBHk=IXP*ucj-hw#c1s6yzt;af!LkH==S2zsTsk`@N##%^jrJq4h zfN!OSPnK4usf>_6BACUzC>wUkX%sN4bBAVk#1p;G&*|XqptG77kgkKcD?E^>G3N}5 zAjVhrBjq#ZWYI3(pVjd?iLlR^qtO?0E;wRwL41w^q{$L3+OkyX>e)2PGX!1P*jR_>5Ju-NmPSR zSa}tD+eEMdh1T$BlFeT@bP;ScUIAlEhaxF{_kiK(n%~U zXLtAtbtls;KcO!x(=AW&6Q)}h*Z+;5vLsS2MxgK&Rsu8XWKtvkHNuJQmnnKkYQWOo z;xrdkZ3{RcHD*<9QNHoLT=dg<89(!bwA$mtCH`-5JqtCr^Zdac>sj1(;Fr{Qi5=qt z;m9s1>Cuik7qdw{Qd&b)Jl9Qtz<(}ysOLjHmlHVX`j)R#sXYUBhMiLhUBD%hD(SL1 zrN4|Gcj=X&ORs!P^vZjvSLWTGSg<5`{?E{OaDj0#PJ z9IJCN6$!PFEyZHqmD(rN(+G8omr6AdUYcz8l&jO#`g*q=gvo=6TNeeYBiiKEO}=eS zGC75vGvhIM2Hj$YKVL&Vax}h4+bpeCBr&{}%3`#B+C*#*>79vPsTjIKiOAlA8RsBq zZun{c!sE=4{`j$%`Dw;UV{hMBu9cO4m0#|<@tQp$DH?<{lQJQ zVwc+SwaX|W?)5R<-(;Qda#L@9*D_P@5HIV8d`+2AOCWJB=k`5O6}~3vMIYx8Jm|{* zyZI6NgZ1a3o?bjdXl(9kYhxzzEhb~&n+>jugJByq!$$BK4&M^^ZL1JaG{S2@DAc

iA&-AH)GndrzchFK5BiF4$s_vUsbx^*IuM+3k;8mvwi&2P>;|JK5B48;F+F}8rrZPlr3EX zwOd4dMnqPl_zl|8`t|g%=a9bX5gGh4(08d>??iu|zp0)3K{xpEDm_KI#XvVY!!n|igG_#xw6B`0(pD8%2nQgu8TG_w&Nf#xu5(%WgO-ga!nqi z=hvnwcW%6j9g5)_`m<`baM}*-D9B%nLwl>J>A1H&dIgSqduEo3?l?Qjd5Vw`B;GX9sX6PVrcZL~b61IlI*V#M*pU>9Pcd~!Pxj-^G*dTzdz@C&pB}D~JD|kfCFVWD^t`q{wUK@Qx8RkX5iZE+` zI@I$W+<=w4Y~|M=zkp&$_CqZ*5E$a!aQr*!ZiF8G=c)EbiIF?W#A8jHme&7<%0+zY zi2#YbX+`~&O#>^SSMYkKAaq}$BZcI5$py3=cpE|7?ow1d@;!blvlb49QgHUg@U>)h z0jgBE(Im*iJpfr^CgB~Tzo9;9>{iwt|lL2>+Qis`vQ1wWiG*l^D%4| zC_HED{|vv;FH*^uIwy?X=?Xv@5i;#OQn^3jTzr6yOU0eI^7TG>Bu z@T_tp=ue0nL4N`s#OivaH<(A_8eH&5u0_2iUI;h?wu!tpYU~nuq9%VL{C%KtTKT1- zKT#8%;y(~NfkxPN-c6_5K!K_0)V`($KjG6LB6uPl9u?g-JwKtd&FZ-b+HwA{ukjJC zz%9hx*5p_pAs3KADIY;&UvKI_#2bfz_~B*vk3OLFduMliX$pUUTm1lI<^F&&_Ty-m z@n@Cn*VS|xboR@E^7fSDe`a3R?I)Dxy^aOA({>ZaL46UBDe_)h#7)3Fo2P&DPs~&M zY=EI=)Re{|yrR<+a-MMBINsmRX)dPKvegcqknLG)KO*Y@e zbkF8r;(upvYJSR zTK(6UPzzrn%35513B6%NS&QrMoX}PE;ajnnFv|2GZdqr|S~>R| z`1n`zM?goVKfjDIi~ad7KG6Pr=`|&M<@{)OpLoaS*R1_Xw_Y#yr%pr;CMC=d$dCHX zn`=WODifw9N_s+1LnTsej&y{kv@sLGl(sRd;G~90^o82CklNP1_~a?oJbL1Wa@)eQ zjsG|2(U&m+;ukOEFb?SbSsnXpe1>U)5R}aUDrp+R&KYNi{7nNNi8()Vg%p?7f#&}b zev^?ullS-cqaTBHowj`l|ExBB_{UeCefZ^`JAser=GyS_TVo%LA71X?>iSpkY{(hK z!{#~4953Uqmu|uv+SrfZsH(dIP$kM9;BII_-wpG(ksM^6zllw_qPk7!CWWC^r2bUd zgrp48*o5efd|-8bH+7Y`zr1rTuOmpQxV8#jdffRZ{Y18g{+r&Zs`Lfu}?C2GgFT3tluc)|ZH-I~ByOsy_Yl(Yaf%&o*cHIel1h&+Mk6Q9& zY02AsgNDkTFWbm3pnOMzP$Sg4W4s$5f_U(*Bwx0=9))Ab`*Xesg=3tI#Px)fP|kEw=R}+ma&knDg8m+Bc zalq2{r2|h(dFm>-#yZXT20$Tm72@xjb_{;p^Gf5`EY9>t9P%=LjOp*);0Zf!zJ2LZkAq^77?_F=wcDvZ2I?PE&;0>144^5}uL=NM{ z?2oP^`rygn9bHG1n^nvc8v1#~3&#kXfh6fLfTDktrDW!qaqz1F!6dg!`4;(P^f84e zj^FscL`B)Wa>pV!KO8RnFpAFgel&%lpOZ8HDzo9_3)Y+zoXd+T3E_n<%L{?H?pLE- z z9S2p^haoR3>u&nd5*NEFUJE)mG=cBTP6led3ba=z7Ub}taU|8z6IOY%zE`p;9|1mW zb&M;Y?c=|7d=iQwoxf9LW}0)ID_9R`_`e)ac72%?w{ifWrwmG}a#2yF=4(x!-Mn8m zuNn8vPpf+WBdX;o#zA7qQ!sfL8O0!hSyS{Mao(R0XA@<&Tr>$?QCfD3*$iUX>A(C)aID{MiLNl?|IEv;J8Qbs%_lAlSD(Y{>kvS(eF~9D@!<0f8bn;r&Zp{ zOD}`{$`1W;{JrXOIY`nAe$_)V!jp4#s3Hc`dy=hL+N zy~ggJd7#nf>0g)jQ*QVFc8`C(@k`PBJzb!vXv$|XY^y0rZTu}yYBh88Ed(WD$;)sH5Jw*Zfy)o zW|hk$xvUC{@337SXV!ww9dFy;cnVTdx9-`wj1R0Y__zhk4HWBmtkoL+rLtPc^NO3# zWA~~WuGj21sJyNjFb1*$FOukk=fgH311wAJV521cAZzSn&N^u7D)!dMkB^-S^{gb_ zV5_?B+X-70+VB>>0AdoN1P{Or8K_$nObN}&xB?#)WZ;w1e!ocuy2S#^g`gMOnP&lxEk&752mog zoWDa4<@H6%f;NzJtS@?lhmn;Mq{)^N*8qOY%joaPI*Fqo^XuPb<-L;ba%z*Q=?go3 zuz!B+Y6K|P_AB5Oj@aN52vBh+i^+?9{DqzKS9c2jTS1U1;g8<$3qSob%7%%%g80nK z`0uLz_W`#ouG**e`rkbFqWS05|NhA%pRkAI9mtLm=OVh5%oIc$U}p<+`>6A%6ncgf7XrSDJeUwrq*D*i?DgY+-1 zF#g5%u<j;9$<1_s(%rG zi17X|`4^erxOLj{eE|K`bMIdM#gmi&Z2uw+{A)V<_!n;~rSUre^3*i0^e>`&Wh_Af@D{)_%aE0jd7 z{>3o(vCO|{1&NFPMPBa8{fpqEQ}`FzqJNRUqtrhzcH7gx_>ZUHUyK|7;uPH3d?Z6W zUdCUoT0b{z>gNt#_R6cDJDo~f9lzOt0XrSPr`;)!)1lTq>gR?*8RRICx4>E;e0YiV zb0^hMKbLq6T~5O(2yK{t{apX!ZoN^X4S!kpp?S&mb4}B#pF7n7&0k^lb5}w~yZF{G zSVaKl+K;B?cT^={R;sLutt5*3(Yyld=RW(yPT-^M_qE~UA74Kghbkdal1!8h1tI0U z8|K|e6!OTsTI%PdW%Yr@fse}G3^tMYL zobNtTyB=?Q;^oxiqhFtTt<6MT?jNtmo1Is>9{HTn>G8;uwdt)_pdSDEqdS3**ko<^uzDORb-7%AuB>PGUMF+rSIjyYue>B1f`8a< z>U%pyg{PrYiYh!0aj#W{_mjA#Dtt)BXHs5N@Buu_dc23i) z^vBKY-Zl&@ikY8O;9XN}#{~>!((G{H77t;~$kfnEnHqA{k9gog@O>8X9r-g`E7^nX z!*;SQOkDgn!+@M~QlG;ukPtRVunXb!xLh^y91_b%Qb7!f;oeVL`se&T zY7i3Wx^dp^jq}DatB|B~R>(ze_EV=YWXyfLH_w%~?9!4=8q>!t<{C72B2Zao;-bmpzF6tOq+$H*tOp_-inA zhVum11FK&^f%DAd2$t9NZiy#$Y{hglwq94Kk0l1~=Vs2ZpTCy*N(8Y0;+AC_ z#zU7}3NVNjIqrak0$X>gxo1Xkulf&vH&r*q!wXB|M&WQlBCWfki|jE<-0! zIWY1UnI{U*L*4enjo1gA`}j)vN!Yoe4+dy((M)!N?QOTSZhU+MJsELooM80}3}OZ% z1<^8V_C>U~NdWUhYm%)$^`R&F&w$HR?I!z$S!xVAe=F|hLlpY7pHbEg{z&0k)xOau z)DgVQxeZ!BgnDL@#kb;2jlW_HnlE7p>4{*k0j&~pV$2J8-!i-q^5lC=oRQT1x%WpW zYJn$9PpN&$7oZVHSXP&jknmBktp-#@<~a^~SrEEHFi%av0R1@<*f~n+M~;D)rB|6g z(&V(i8#%y19jw4MrWZ{X+$VKdyiHuA@MiGEe%K}eMJ51Pe4I2vH*y8yP)s@R== zaMi05g9#8#X;+Y4ZST%H)4bDo{@lQ3YB10jwH|6e$!6{%#&xjjtT9w;6$BNiF*SuY zd^_m;b$?T7%A*{yEI}P(q?>sanyFcTVlj$b>7S_a@+OFX27lI$3^roy%Yunb*!^Pu z3!&akRGZ%1E!?LDMS;{3A499ooA0KyfiK&1f4%GwmkYnZna1y&bFL#k*8UjWW4)14 zaVMz4_#vx_5~gHwIZ7t6>6E&}rnAF|`P({9NNk-U%1*v(uS?9ISlf^ogw30YU#vcf zilSP|m4^GtvGep4MVD-yDSD&#=HTT2@Wi&nz(iu;p2Wbmg=54LzKUS)?|I|7)yG9} zhh0(!o}T>X(t(L(8*UF>lEfp1yXbg|R&0~b!1D}g{(_N#Gf02-w2mwaC73o7ZMwO8R}aMvMd=~d>hr`MEpg(rxvbIgRTM=RYALl zW}I;T6N?9y4cyVx`^=7|2R__%&!gCErD5s7$~bV;0E-0^wUi`4urX0$y5>)WF8QSB z{pVr7yTnLMG;tr~O}kP|F!135bD(~j{f<8clr(D%S} zK=KBb1)VqIJ{i?;dBxqc04Mm#&dVgo9qIhjDtZQU!wu(G**d5d@x{r4`fMqDUuXb& z_|>E0c?`hd!4*JhljflYw4WNYu~Rp0?fwJ&%!_^~FB3mYJeU6)&|Wp3+vARx63A&N-bWL$g^6%B-m{)#0m#GO4L))w4VVd!rk{)&bo?DJ8&zXH} zs947)r?{DYxfgD}M%Az7o#VId#{iB;@1Zf{%dlNfIUNd|HieviXzNRn)8M;bj=an5 zPyJg?LBUiVu<4O-%hHE!;z}~=`b@)&)BdmLU24KZd}eh#XgM{0Z+RYEB+TwLFXtpO z3j?1d?~EZNp_DN`H!@bfKJip{0CYTkkz!-q%zRat)XK+ZoraJZPAJae*{U{VqCrOd zrB^WC*A_AkH6t(8E&S>7ei2u|KUr1h+<~p&5Z?x_QvQsI1I;*%e-H3%UgBWJe*`C& z6L8=eFuTrE9CHgd=b#py#{NAG7!d`AK5wTS4)?GRN4v$LO4^xTNB92c$(Xr*bQ@ic zFhF*>tsG-AF{0piw=b^0&eOlwJ%D5V@SAI&P5h!$bLx>EkkGMxWBH)+$%*ewi8t$S z9c%EGPU~*6%F7~U?QoMEE@+xI>78xG7>OPh#dl4zS@+9&X8LvJqTbeio{fl(BCRs* zpq1)wU_A=5(L*NDyM4C{4&|?f<~baA#ab-}WvPf(%kp4YKrcS1_g9(tw!(wg`f(YR0OT@p(1~+YQZe0Ew{FkSvl##JY%Y5~ZPWb|E@cez5x8j;|Ks7XZ9 zZdW>G)8hK;jgYxcTDl3u^w2{+zY(m z_rh1zcu8Ac)IEZCbzZCN&scN?w_@*vJx*g%7!x=&MN8nsEsuf80dQjmX`n1-6}Xp0 z+S!KGEv=h^H>vw6$1C6qtAlm9;Ug9S%e)&C={K+8IlFZjI^mk5UySQ^~Km-z=&=AxPvKSh= zmnl$DyZ8`QS{E7wHxcL;AZl40nYjc8ic}$Yv}kVHw4SckJxv1>O#|CuhA@`{mRUM~ zE6;R&#`zy??*=+G`@ls$9NLqRaH+cpiz29Uy%KxC$5+#zeMV4VV=TMPfT6I5$zD5rH`Q@`8 zB)>%Tdq#hm{h(d^F(&&eOcixs1qAzJZ`>{d8hOkDOHuP z;+C(dVACLb12`$+bYnL;dgt^qh@k-8B4PYev>c?Wh*g>I9Ml!qp z#m@ZD<$3NoB29*Nxl2&}CJ}6ZiJd8uo#)kTN|#|16=~Ew>BM zYZd<45L&D5pPhMTxqp`Xf`Z$l{SyC7Hlix=&+;YyS-*zU#MdScF?9_%Umc;ZnHqQg zC}AZ0;THX#@$<{yQ!j-iVh%sIV@IT{AL5=D%?wMAz&AFITuzdX<$x9P2H3*rg~-0@ zs|>$VF=YSMm<|Rnz%S7;BqB%VrMAwle-s%u7Ce-Pkb#6rpT`5k8jpVCu=Gy@Naeh& z3SCDogM!Y+!}L~)hpVlGt1g8p;;O$9essd0P8EDGjMl32!Kte&_~7%k^1=NH>@OLo zZ#B5OKJFX`g|CcoH%1m1(d`&L&$y4DjXm*>r@#7UQ@`wfkL^`|@8mz2c+vPjZvNr> zZhs>#7Itve9^{L3yCwW}fP@2h2Q`YOSXEuk(G|-D283eka{U_}6wK~V zz;Re17>V)dH4=}u>3+yZyo!96>CNKV!i=>yW7yGt8MbV0%J{hR0KN@-8`bZtw~KJn zzzWOWvUpF%-vN*D2!4@hPbicgBG9oKrguw0B9?Pu3)F^F$>gO9ABIk*KkCKD@eepC z(~CjjN}6b^7lS}SQ7<;*u138W2Xd*Qkx$WZ7``pb_k?Ezf3+da>D-q*z!j^#T>rN4;Z>c;ls#-3-1}o zXGgnRFj~9_faF9392OOM>=%^LGa~?M7U+Jwm63hb;6a@Nijz5@*kxum|ZFHt-rZ0rmT) z!s|p{;}sr;oM63zyBC`itdoF&IE6&&+%_@byl>nhHV()Ye|g~(KWYv3c)_eo@P7_d zVn_CeOg^LTVnrttPn7Vh8ZY@M)blrX0!A1*NN9ze^b*t*yY>Re4$dI$SZPRNH}&3$@pOcA0qsqoVzR@ zCKgBdl?pb3fR$f8$gkA=%h=Uw4ol_{7;JFoX0G=FAj5`><92RB zteOn#_Y5EMec~DVLiE{xyAiz7jRXW8b!y^ZRYVYi#oQO>ei@B*6Dtx zfwuw9`(`fkhmWy}8*K*)dL|C`g6~P^$-_%fkVLb5u^`H|U&v-LBvB z;)4am^M$vL@%07YYC)5sjaT!#t$p>)7py6|^Y zo>^PpO>NOn7cEI@4Q2KB&~DuS0pE}D`|(&*Q4zKSDSLjO5$Z?Cb`d!SJR{>_i-bagJF9(qtwgMd(?Nj)|*K(1kG~LyCsN5K~BIY~h<2F_e_3gv9{Ei>&<<>rYrVXuCIht6`UNt3MshNeY zPTwv?M39^2qmTfXkOZDt>>X8pd=SMGRR;8OOn zxSnnN2<215M+?DMM^;$8G8VUlHhdotsC>z-0*&GqestsQ3=Fm|v0%}zor~}(h)@k7M70u%u5BID7|6@OZ01ohZaxI)g zEye^WL!uJOIIsNmBY~y0;2{&Mj)y7g(!J+59zN6LFTM06`5W@Zb8|vHSMmm~|Ipjq zdeURvZ|7>RS2q5kkq?uH;L)vEo7h+3KNFp{+nB|Wf7N6v*_sWP;jD;+4eJe17cJ2A>W3 zeS-(;FZcVWz;M`l;`!9p#UP+GF3X3HqJqVm=YfaG^6-o90FLrb)9-9dMD0n)*CgHf z7d>v$uVWqhvxQS?vE4mb+&^#zvdE^tVqPn)rk%KbH}Wq^vq!o83l`48X|}1ZlEnv4 z>l9bk`77AURo6wxs_>WK^P_I~mYa!4niLI-*?Ui{jDlq~Vd1_lm<#<8++DR8LXI1w zMI}6v8*@Hf0Z+kA7mX*0m(Oz3Wl2@Kw7p%$%Y|a`w+fU|mt^{930}rIZKcJBp_IXg zp;wSV;L>q>sOJIRz(>y>ZRBl92&qRzSgQ`;wir?m<(WgOx3y0#Xv2BvGxYmRKSmxg zOk3X~=UUV6A#O(}z;5)$N#=1bU*$Hd2$w(!*&T=vW%DxjrC>(AX%LVwyB@O5!$ay! z2|U1qs{>Mu;zLBF{La%wLJGlim3$dI7&$ld@>cJpi3h#UfSs4l97982ZC-lx6RLef zXX_Vv)F(8&gM_?Emp^*dk8VD$Jn!A?-+nQcfhKDjs6Ou$ENjQ5C#>9Bhs#H9RsJT^ z4Wy`CUYX45gr3L=j}YR_F(N~1U^ky;ofB4BKBb#RxozuIc+}gch#y9rmhdTp_$0ow zLHrmW@KkA3F|1i#hlS9KPyn|oZUXrk_Xm^+H2yOf;o+7OIiFq8E>{&4}I-e05jw`;6xm2j~Gt%fi zr$+@&zw_A5ArqXfv!zn_}rhf+mWDHNtFy9C7QGm#gG5UkN)k)lfsdj{MVrc)&193z8@d02@k{X ztd0lm#}_`XA>-KB0uS009x_v$Km~#7?|Ck!T zNBh&VuOnscl-t+;aOv!G-|cO*lzq)-k5l#)ig0%p3`vFpd&ewn-9_W*Bp z;_e;BL8FC{8Wr)&B?BxAl&w#Wa#HP+-}_#RrwAHWCL(V4v-9Xz>ZF#t>9xS!Z$2E? z^eOf$i!otj^Ty9%Jdks?Hrc-QhzmwejGr9jU~vJ@(r*{~jhp%FR@HCOA?LU!h6TUa zSxC+$kemg-&nFFBjGo}Dka-w5`2crV5x6)2P>2a+KC0xwYaSK6F$3VW8SqxH+u;T*XF#?D!&6(u~xu)UYzO z+j*KQtjaW;C~i?$d>83jeCCscYNFL$b#O`}@pIo^M738JVGkvGQ7 zB*$&ylJPb*F86o*EOiE0+6u629g(bq&&C!j`JjUfIN;#ogHU_vz+I$u78URkvu1y3 z0bnPoW@YHTymq~zp1;2LmW#R98~OzFIHpIR=L&{C;~!Rdcp2!^+~}rHQtrIya}zf8 zbCoqH`ouIGUiu1S3xXb2oi3ofO{CEQ^;L%IC`)yu7(+HhfHs2WWDtT}52rL4KDjnT zh?6d@RxQN?V{3MX&%ggygGV?1(e@PbaVCxfSL1f$-TmG)>~!6`z3ue-(iYE^cDmed zx%pk2=TdW(O-MH@7$Do(TA9U_ojsqz27H>RL?i}>2yQXfMSMu%)kp7g=Tl496NIjr zcWJuvE<281i}uEf9_=#-tY*L-h17AzSoa@C|EYFETih7m03SuZ`Pb+#Ns%-(O%*?G zx!|S5kKG2Cq8>JRHR_NW=YbCW=D*`dP%hQ4)G6{YTn&Cc%(J+NS@K-dpxK`&1DgKd zo(D?Sgoo@&)$uUJJW#dy5BL5=UGLu+{rRzNMt?^2`(FAVIx-GfhT#(68Y2~>3iBduy2MlZYa zz(qOL`v`QQ+449Qm4V!UdeNR}Kj>V0NO_!^(Cr(YWZE}d9Tc*F8}Hgls*6+|L0vVt zp#Bmtc5&HA7>k)EuXWki)R5Ia(8o39(-J37r4O(9<`q0}SzwHE*M>BZ=Bj22#;$`*MmArvY8a)Lvrst{P z095XWy|eS;-(BdM7ytdbD)ZuPB_I@4&dWJ3-nwdM?82!}8M_eC?;Cww9zRaQPmaBp z>bi1XeBKu8x)%LpcYiMW)if`z@_)s7=<+#n_dK+kU-Ow4e*|o$HF*PoV8l>`zy9&_ z;_s<|=jE6e?_N&2*a;)z!e?Imgkvl|45bV{%HtWxTUzGXPJ(;D76Ydmc`L>>Rp-S+ z8=`pC&W)1*&gKr|C$L{$F1r=REI6hsSHc!Q-1`TtLfbxLZ5vz_TSjpW-4y>)2{&65 z%M&8*Y1b$sorp7WoJB)3Kyadf3jH*jeBR^iXDlo1zL;T>6k)6|8N3w=-OOV|HQryx zsd(-;6E-t-@UAh#hbU_dAJ}c!S-3z=#Y1+Y7)#oP|xjO?!Wc> zw?D0UhIm;!F1o!~kE-fTKHFB@!@gri@E9UWY zzzZb4j+~Ol2gzK&jPv;4h*_wqn^WV~$M42%Afe$ma?kI0>3nM-bvyRxLk=f8)pJ*= z=ltRrsend1>E()kW*v#K=Rx$T^^Da0zez8Y8bCI8-QFlR*#k?vuziuF6bjDXYC#Lu zJH9;a{r$I+_$wp}?^W=bag@X7v3{!wn?xkj`n{Jpu05X6a3rS>$JtK;j%NKHX-!*D z4nO2W{E2twD^>tg<-X!2+o}%F;wR7qX zrk$>r)XpF7H0=y6Q{yuHrm&#o7DjysOh6DeT&tkaMr`H=Q_@!-fZ&XtP6har`XD}Y zJyxCky`etLzj!8szkyZinW%myrk`oh&&2V!SwEA|&ot|2TJ$rm_}j0aY17ZN>t}de z2m9*A-;92yUq6%7&kX5jhVi#}`^INl^fO%l zHlm-AwQp!gmBX#C@1}3qAN&9pk@V@6a;$^H4V$KQ7~&0K;mt6gAGrt0oF7IXBwbZ?J~0ul_`RgH&B#{XzN$OGEnV zXUUDq_YV|v{p7t=L7SSS>oRid=2w1(UJ|{(51idXwv|@-8F;tc_n{N}6Q$~wsq!=P zp7n3_4i@NI{NI||kH5d7{cw%#8-L5dK|9II=+!p>{`?5qFROdQ{urr;95H#)!ufzQ~YgkXj@#JG?nej*+IeE(9)z}aBc-r{5$9Uqd@k~h%XXbyhUfYiz zhF=7}^z`5he$X4f#B|`(`1OO&@XJ*4^dZXY5CC$?EB1ZYQA-`D?i_d){A5jj%fIlC z>x_Ra=h!9&<3Xyj!iXGCt27EXhUN@nsznb?_QfF0%J-ps6X{&K^kNkPe>QWnJGG-Na}{WBWnE&&%?$4KUTCQ7$F?hz!)uaLzE}Q|(?*j3#OAV~ zlFSjabO}SujbMl@kjNo1!Xh%+!-C5Sv7n?E5U&imC zXP*Yr(7{E)bC)3;izF5_)~(-zYGr!F{1=K*C8Ja|aX?qbw^N zJR_XgF%Cr@an_95RAvPII(xPPW9=4Wi;K82aESf^O&}FyEieT2n2ZIqx>tsx4hmEI zU3~sSOen_#<>O&!sd*}b0n|a)ay|;Xz-pfQj+$SaYF|?N&qNjJ%FF1l!w8p=JFEqW za7_S!k0v&?&pI?+M)e}!~m|JU#9e18?b75lrMJe&WB7tiuM z4Yyvs9b#8ukHM&=dR264fDK}GzFOflo*3*3@{|a5&gS2!XqPK8jiA24~riysay;|DadE(#n*G(RX__#}Bj{59%;ozMf{`aq5Rfac{gdLH<( z^_BLV>me~-+(by@w+-*4x`7Not{_&2+y0aE<~F||`j}qEvL0SGeoT+bkCOc}YpP8J z6!?ZrvPqW3C_~2*D8Yv(-v116^ghgfct5lf@07u=8Hnp6c2}HlqamVxjh7rsezRnM z9kiKk|1Yx6A|=QAR3bW1`>1`L7YcUWcC5@VbzXq3Ta#pb#Yg?*RySkqaT%Tdy8dW< z13Jmx|D|;5pNdY|k5-{m6yqZik)_497bKlJx(C#$MkkYBDTf<+QSiw9y|SbKO*!WJ z7bt;ZL5$n~Gyn?-wtx~ zDL&^W(5JQ$Qpl_MO1)LeS6=VASKuR*9rm;Q z@1^iQ(lOCi599X6_V4`Eb2Ee zxSX>fR*19x^q+zIqlA0p6PB-?FJpTtca(9~DU4jqu&w=f+k>qzb_ zgFmbAj+6nlXv_9jcZpT6FgO_QapoIY%n#Ohy*k##OI@$|V z1WxwJX9Evic#n8U0S{B!#;j z9Cjff%*SPhtL1<;$-@OT*cEXn={E#0v>mbXX!5K*xrz|Q{I2IeSb*C;$q&(b$+e*t@{HPHm`#ivbeMAl{q~JDeq5-*BtN$<|?K|@8lO? zuv`q7ro$!a5~99;9Z{dxDM{|54t7>4JLfOhNXV_0?p#Vnj#u!Bn~(1H= zw~X^lPJnoG`57XY^h5K_7Z^O)`K%9@()Q}6m!{_vhQ8%?ljaW~1nU5T=xj(9=4hM` zKF1+enSWeR^hXSh+~afG<2d;)%h^ED69j=lRyMJz1?NyE!io8Jbi{mhC;}ZVlJo&m zEqWwN2aZbg-V&VLJcZwMP7zKsc0V{5)d1&FzHriautXD3+sZ&q!ETwjpD^$;`~ZB# z%>3EOgd=0{l_h$KuZ+f5g!no>G0=`&gv_zl22u>oq}t0s8YK+82p2ENr|{()$(Lpx zVBzLd)rlr~=X+~(y>oi+jhXjm>-XA@ASsHMYrkLRCoq9o zvET2z_I2$KyM|8y8}9vnCobeUFEQ0y&bh38Kf|PH^yO@CH1*55x0LozeIf#I;jMhq zko;!WrLZtWW=ruoj?c&A0e;W=6Z1W5P!ec>-?I+Ie9u}G?t9DcIYZdm4SB|A)}su` zXOyF)^@pL{TD7ZkzbZXJ-3OoJjnsm&0p5(VBBV**j5Te#r2c(!gAK^|vy`9A*FUSo zN)UJ<_vR*a513BTIh8N+ldKc|;Q=TKP@CpGDaz*K2dHHo@Q=q1SNQU>FT~sCE^x4O z!HXsz)UTiS(!~ADZJ{+ujcAcmdTNVm&bEgpkc!9dil(N0urrz%SbGm#%Nf)F06W~>OWmAlIy9Zw zblwa(_7GH~L(KnsSe?4$|5JFS1>@q8hTe(0YdFFOxMS$2l$ zToN`N>p1U`&brxA_%KB$qx%hCQ&6JlccBnUc{?re?jKC-z=U*hk6UL}o`46^hpKkG z=tp`x3sgR5*!5hwJtePbI){4RiML4W{)@b6y{LlLhaL~VsT!S8&rp@l#>c0<+!^|| zZSbe>Z=Ug|Zv%!n9r})QCn&`k#`{Z~T+cIeUm|$IJdPHw^k^ zByN-a*TF;${f2(VCkkzNM+NQv`<+@&$t%1J|4&Cwg?@JNi2Gfx39Y(D8tOXokgJ}%CoN}_OL5f0g-cqj+bmwKpvQ_O&Wmb8%(xM3At zwFUHs2NwSoT7Os3`a5oOc)9`h3#<2+8@ikDxV5 z9>h*+9fC|`{auXUdtf6{xe__(I>=uRGH9t%4%|Yp#xZj2B?prop7ZVEH&0Qw_OpeW z|LJcLXGY%`{PC|BKN>&gc(;5U48{yyatU4`#&U)^WeUr|gYa@(%o)LRe$1KNpasCv zk0#H3_QT-$@Jm+T4-VZ$IJ9?53^i?Pnl3SLzdEVfITOP&jGh|;D_R~0L!{d-p-z8V z%PP(eXN_70>IckUGNqn&?&~Lm#seb<`t$#R7!dGM#{ZYr#Q(?sZ}9&nZ~mWO6aN<| z$Zq~eYd-w{2u{vP6-xO(QicD~(iHsv2gCpS0LQcOj~7{FH~A!Zm-wl-7hiBP+O1u7 zG(i8lCYT==fmZBUoc*A8T;X?#t2OXo@1saVJU?UYb&3a<^N21?fEVkEDffvTHzfw{ z#*Xvc%oi?S7Nlq8kCX=5w0Y?&S^4P9Vv~ z@)}R%RLNZCos)jQKg4ZA|14Du;k*We^*oQo&abO|oTt{K?pAMjhvI)NmewC}qxEh< zYd;xY9Mr~O3xI~}KJYM7IaH4<1q(XORFA>;lN0|sv$QYW7goRI*=XX`wK32obTJW!|GbB~LkSs#HS2PU8DoR5po-%S9`bBxM( zX?gD`tB=AdVS49eGJ>vN$vVf(F5fSJF!KtkKWtC=of&+AcQa$3q5eQpehF%CmUFIW zU*J>NifU>l3_dGQr4)m+_MLCG)-8@EoLR?^a8_n4eh2J%o1LIx+ywr&LR;btx>b9U zmJ{kcl4TLPHHe(Cx4I~H_4OH8Q^;M_VGm{T?AFF$e49jwb#IcLw_pMQSeUNK1U|4n zH0ZomZJkws^BTq%QRmnN*z!;?y=`a&?D%>)}@~5U^`Yx z6uj>3N=`9uxom$f^@n*27SUCyhnE^YnSaT>LCKr(0SuhMEsW@P%=?5(-gnE{u1KS3f4*Hm&p6!h20n^@BrNDx@N*6bX$x&uk%(h0;116F zOt4}Slrl$mwFs@&qoM{+6#{^jq{?c4E?4&j^~D%yCmzf5_&~jpa}GeaS{XK@?^M(( z5UaZ_o@Kw+0PDR(2}-&GVH)_s>DsXeEatL^hYuH>{DjKK5GVXM%{b;+sAm!_$#q|N zJ+MV1x)4_M<9DnF(qG&4jKJf#*qICQ3vg*-ozTV);ftm7{~Efa7atPy|GM^I{G6pa z3tw*SwX$xy@GR$SewemMyMA=Fd|W?a)rCjE?=bLK{JHp4`Q0?rL?!8D=8Cz(LE$T+ z$G59qAYJ4u2;kr{L}x1_(B&u*J|A1jH#V5_MdnHHJh1u!8{+hCi6?g41|M?S01kI6 zBnJLkbR!>!gn|?JfXA;}@au_0FfKC=V*#5l69pkgQ07LV$t8oO)Wep?tnrTEZ3qtB z&rT?_^Kra0JOBm(y<23rNC@pr!EGxTmHS;m^S+ZxXncr$V9!{*vJHN36Hd>if3R#~ z>A=dg@@OlX9Cv17Yr8ec%s&41bOsy~@Q3necOe%*7lpqFa+Jk$A^cXVhBh7fzu?ct zhCKb*z0h|usK>R4M8ReF0z7Q}AXztG7za8*EgRQ$p;bsJlznF2j$&lD9drmgzd$)? zs=eLw^VID{s>eOEI?9@ zv-R7~wfx13Smy}n4zW)Q1*)Rlfxfm37x{2y*YnZCPKTL>)^{tCZJ;O>Nh+d8$@tEU z&&o0U(4=S}U3abvBQDqe=v3ob$MKAPxnew@vg3(xJZHSce>_GdpDW{m?U(acatS@A zym%$m$JGk3lq()A{gU@%T!q*bYFxc)9c@`X+Q8wE zLros57v1tF>+*!B+hid9 z#W&9y^fp)kz4>MW=qblz0E%iR1i;j0Fz6 zn^jO@req+l$KvI0v3=lK{H?iwE7$y0+JN#kZ=H(}TP1WmhE_(7)b={CeAJ>F&m|SQ z*>3rBXg&}{^AdYWZJXjvXSuxNTW4j~lU9L$Lj0Ug^vE$pzUDcG_h1aJCBn&zG-Ay- zh&;R=OyYG_Qx?OJg3eDq!68-F3(51$TMaza`xv6h7iNcgUPPPtG$+*a9by)F*m=KB z3?_n@M?b#@D=}Heg`ztFP%XyemKkuV)x4Lu{eV;S-xeYfmkU1lJir>$ggFD{c(@LqO@P9wE;qh}==hKII=qbEF~6c# z=S$D*2fE)HO>7unE32kVozB9|;}5MPOXQvBma3|yVqN#t?Vjl0?n9>CuiAFwyBFhr z!pruFd%(^5lTgnEVuYRwE*(I!3THGw6`41ldw83LJ=E9AC*Xw`_{ZWnk|OmGutIss zf1C0m2cl)6L_!-LL+d*Zns~M9*R2PbE7Ecj>U)+zNbXOj>mc~T7fJn|;Un_5%)=M+ zl&6!|N7=1TQ7TqG)6DFvbDB8**-bat{(Em`cAv1h&o@ zIT*d`_qF*Kc`t+KF2d7V0S|ILqT86;BRruE4N&zv4pN?gctA1dddLIwH5`36h6+%i z49nI-PoAgpqQnVl$II|t?d#%?F3Ag3TOZ4@n)wvSm(7pLI_4O@K|%qW=D5lVnO^mq z!fP^HvZvd>L-)WO%&F2ssxJGTa>x*JbhkMNp?B!X|I2vj8krgolXI0FHF}aX=jF0n zYF^0fBQkas?1rS_Y^+?2!z4a}=X`_iSnu<*I*xR88rrxBqEfwMIr(}a zUNU)+&_*Ub(d91EWk$HotIH^-CHt4F6bT(Iurh=cl{RW09m<)Jcgi|16ZdevbuRKh zO8E%Bi;D;7L+z{em|K6z`_MPd>NTX?Rpw7W54kK<__MH>yNZva7ORAv!T+KoXyIa- zhnK8~hW>&dhEc7Nbv#Dr@^=@%sJQ1*{0gL*B9hR?E&KvB%4WZ-45wO+)CFL5Vli9y z1M2v^>TBQ`q2J>A$EfycL*eEV31<+AS?2=+2m9t_{1dD9zYEOpIpZhMWhC+^{{(eD zOHeboDwtT%5)AciLId&}E8U`r1&dz278VN6-kjV;J9DOeOpWzs5my!Fti4wr`5OKY zPJU57e@?%?cc^bA2+QxB_23oY)3=>jYkw}!iGPl!WB~!KM*M0bX52m1jXK}^8NtQ+WzAR>`sQ zRJHm^GzznZ0kp|L&zYkcH|E^`5mRqm4eqZ{1)#49Ke#_Ea8pZ!HrxvK;={4;bC63I zFYWCKSmza#XCn)h_*#1;n;Dn!;kX8w$9LgsQu;LByLj_k8^aL+QKc`$rq=@;&wkXp zv%m=SpFfCra6kVUt%>P(rIK2^*}U7- ze&v%n>+_ZStB)JM@?9rR-(UT#f4lqsTKmC&S~&f7kM(c&P}A;ZJJIfAPx#_tk!kmM z+pe+CM&Fyb2lhhETmMW6Qg-x*B9tzt4 z2TpNsmG{L?MI`1{b}iyOBAY~Ya|oFohsa30;%`pX0Z(HRhot9-T{6kn(8ize3)rQ6 z9lCL^-^(^} zku&am`~=3Z-2$lo&*%#)pAP|pz~{I@Y(m+sLYdvt>AUl(9VhQylgw^c~U z6zx^0XEjs^M7aU#?A3|+6X(1~UcOBDU|7GuvFv@#522oKE4UgAUx=ofe@Cb<%U*i7 zG)(>;ZHD?zWhcD7U;aT>hE{$WY>WdFdlTxOOZf%CZ#T`pPLIQRH9vq0 zvp-Sxc;N1N&*=?f2F_@3)?F+1y;b+WQFUMJA8)q*m?C+81M6sLmxC9~48-*F74*XM zqv#273Fec}Zz$<2Bz<+Wi~Qfzcy|e^4h??ncwwiR2&L_bN&gP7mw$APjQZ z_UI6~>@^O=6?+}IhGX)u*WANj+3T~>IP5iaN2uqm%9;k!0!n9GTkZyDKWuzO>;^Dq z_@XrFh)Wmk0rM1tfW@5`-!J}XK*LvoFXNA4yvxjZr7e%~{#nM0?(%il3iz<<%h44r zyWTMnX=Fyzn7~KggqrfJL{L1?{i4FR+n*_suNlhDw+mi8`u;J1L(=ieyF^`z^yo}n z=0|{q(ZQC8nEIztmBLQDNr<3dzv|^ck^@nDoP;)f+=cN8v{GWX?@^TaX7T$7yPUjE z$^Q##d_sKuXXtPB(ro$-Ak>Jcw2PtAoZ(~l3$*#X2ZS!%{Mi-A-O#7KRB|40tNK2r zXcTQnGiuOLVtL5eqi{{_9gp_38$yMj8be3Qeq^5ap%Xw4qE8*ibVlIqMx41%8-H4> z8TbB9QqSyt4$t;RPnkAYqhelh z7;csg)5joSN2iLC$3YFvC28` z^c5^nLaB@a3h&aF@%3k}#*g5)Z2R?;R8=GB@6WUt{_*x_W~{CBUasUWpEb=Vj4BXz z+JA}3`yT$w0RTbEc{zQG@%DLtqJ8tiKQL7EYvw~UxtJ!jaesb6#>omnWJfrYmCgYo zePl!?vzd};y_}|j?X2xV1hy>84{&i%=!m1Lp=B6&XB_8`m|tVxyr?I5Sv~Or4Fn!D zsEt*LyT5=J@oe2>W!$~1RqEQ)B-YvF9#_hJ}gctpm#NT)GJNO6% zfyu+3m&f16E@_4}@LBqwtrUD9CdlYS5gaDa2G58)Z#!LC`k|i@>Jm#2&!{ox?1cxC z75H+E`wZ1|AtA7O*w{m4+$w%wuRM-?Ub z<`-e#^(>s&cg(U435g_*SH}H5m{HGubR6F<(x~=GWE{V-Ob#rbN4(?sew|3Hpv%3* z=atdK|b{^h%A-9}TG}d0s(R%ohUt7R`B^^ct7qz*Xco*vT)p> zw}S5{TA{#vYv0?F)!JWa=@YV`E z-HF4u+<1x`Jk`Wc#8U}Er)ht`dW?~u>EUUOeJ|tqlNVILf)6l={IYjA*3o*}cp$aK@cH*s&Nou0M!S9lbaCFap- z`eSR3-Z{Lz)xI~J^T*o^5Cd}Phqu7(ZoD<%PV-l;?&nkB?M&>!=jOK7BHmocmc1W^iS`-IdI?Py_V^{_pEs@I=%OP zkF1~cm-)lA#&yw|=T<73ac_hSr~^$XI;#d?FkgOE5Et`2{6 zsw}keIDUtHpSVYO0&K@~;kfq&&o~S6FMi{hW8M0LKge~aSpnEoxMe`7rr-;3jK zUjLTRzcuUMTJSe|hw86Y|JJ5|W4TDH{;f-XTU*~vRntEt->${EXwWx9{Azeye>KXl z#`x8Eo30@oW(^@WomyOfF+Zi7HucqaNPF;+d2_nHLE;8yoaq~sPW06urf;x5uCM+z z`UXcf^wqyWuW~?DB;EucNsA$onrhc#IBkF6_`{4I@{5C@cFh!=&KvgsLMaTDH>@xE zGi)N&twHf?Z}R(UJ`-Te<%(ZLUzMJVxV16YeitWMux`2+CF6G;Y2ekbTR&3mSs!%% z>rhVJ#eM60E5{Q<2ULJ+JS(0e4@q)X#*@_Ji9fF7(bQcV_~}FQbLl?tm%=Kmae6&Z z*h`;Z14^ssGmoi$m=7|2@OjD+^*Z3U^>=Y{T{Lo-x48as zTh)56;UQO5YXjO&4Ot%Q#;q^@oTK2FfzO!x=0*L>3-*Td+a2=|2itYYLbt8@^lqNz z!S&cYlSS2sW}J_`ZI<@iP5!IAy><-P)Fz$V;%*!bAz{URc9utwr^1SXRWU(99w^{= z^GyRQ)F!Xo^h1L|Y-9zF0n7{||LHtAZ7LdvJgpZo=eU}{STGY24De&t_`TSOT`Gc^ET{+Sy|uWMxWZ>L9Y|brqk?5 z9VCTP`DIw>s85uVRNz)sYHsjVhtx7Na6#w#n2f2Q_?2ld@~Mk%s;+D=Sdf4_k;nco{#;=7sfqUQjh%o@4F& zltmIXjk5=Kh674WiQu_v#}95!$T>J88$AAvD*(XMdNIF%%IR(7 z0ei}y-z4h;>k=RN_2*^;W+aXRzoMuI>>0-pa8MkMSNnlhI1xhl(Z9&PRtgp2#)qlc9FE9&B4wxJ1RFbK)3$E*;IBjaiSSP=_FV~@*2M}cNR{u$^PBVt9TnRi#4JaEB$#ChQ|x4%$dY}1xj4>@VkuxYdvENi>9$V@O z?D}+Y$|Jo`ppJ3JoQ@^n0i*jv8;=CL0ohWBM}nja;0LO`Eaf;y-3JA@o(d3KQb2Gi z$&j*VoKC*kyJObc5WmJZiGj2uzL2|p&P||wS$`z$$DuE3YJYFE?^|~YyLaRGC$TlA z-Y?PUMQ97TOudv^BocxJ*>&;`$f1{?&lk$#gWnrJ-#o8ct(M1(->)p@1RXiGJ7}B! z3aB)ev~JJUVo8hZL$Dcu_xg~mn~yx~n#@<9>o60gflXL3_BbR=5W|&>>gq>*+Q2!BjrWG7nlO5PeI}--K)zrS&89)EP zSp@q9y`kNx8tZ-@ezWn{{n~|4m&LpUDzOWmnz(yTO%8<#ftpW!P#A6=0bXFtaF5?5xOm-eqhJ;&l( z*oR!?5%PYfa*0c5Lky2_9owqeEWF2R4Q$6e|Kar~Dzn7x^VU?HcMFXIPnhQ%tVE$Q z%DiNaH=+#J^5{wIs<(a{m!0M#50feKvXXo|%8O*(0oRf*143j=t-Qkxz||`6-(eui zF>`^ls0a@D!sC1~KX~GLnR$G2%)&ET13cG(0}=eedchy;0Z61qN@?-rYH8FVt)@;08w_%PecRY>p!A@ z=7~Z*Tv$WC3_hx4qI5IG(1u?8Zeu@6pR*U?T8K})3?1C^jOr%6FHF__J@i;vyWso` z8&IaA8fdS)H`=%J$2e(7wO@K>f=oJaW1&qeurzs72hN%}4`(NA?>Heba1w%snQDLa znR$IMg+89^b+Xai2uPrIzj8YX2ZK)_kppuRy|)D?e*k{>TtE4?HUE#iYk_aGD*G9` zMY$xRK)44O67NMpI|09xt(dx2>j%@qHY}pEikC7rR~W;xZmgjcE8d3JB8XK`Dxwst zqwHG7En|uS6awReyi6e*0%0Kg{{QEk^X4RZlcrn8Me_S?P1-l-@|@@SpZ|HzbDq;P zfCnj$HT(~+-h}c$@x856#?J-$C+O$-psiSk<>hzPH#qSOXHh1iQino&s&u`}2ts&q zeE8P2lP;VvB2J7lziY>uOkG!fh9HuNJxWz!DlCH_bUDmS!R>&>qI*wj!g(5qsQF5z za%;Kg)sb8FZdLE@lw14e3gvb)Mr@RF<5-(lp}z6=&^P5zYR3m#=USNT`e;ECm9Vu) z-=g@2bI4}$FJ!c~6k*u+f1Jw@I*F9x^gPYPw8l(md1^op)PiakLg+B@cq*k3-Zx1T zISW^!?q&ylL$rO&Ns^;!*j@uAHQAZ1uYFVbc;I2-f*p%e_;SQ20AGc=djW2<1yyz3 z7f#t4i(j|_nyml=XE~7AMJCC=$vnwOdFOVaK~dlEo%w!cZDw}9Kl*P2OD>(DaJA)0 zneWkL>x@i5BPQ{-$^j+SzW8_M378%Rg(z z(<4_dfW{YmT!XU6X&jz*&j}Qk%f}OVoXYk?SDMo2vr;3?qh>zIws_>pvcRK?geUkk zrU;$R?6&nfyKPJ-{leZHp5!0Jx5frCvl?lbma!Pa&ye$SZqKUX{=0S{{&=y2h%P$I z>CX6-c%t4aRCJ<25^3g=I-i8k!Y?z!Y8PZ<}Q zM9|qQ%Vkuw$PaGmM_@VkGs}%*$g#)q1wfK(4~6pKIHvHp9!Hly2X+6nxx0Gm`el(n z>i{xmocNx1JW9#5!K&OWi|V{G594Xr*EdPTXL4gP;~aV^bOelc2pZ>pX+o?^T?u0) z?r@%oi#F|{D(OU1-RIR=POnPH;xocu~153G9tykmb<*($FV##^oK{9^* zn7p`OSr-=)|AJG4SOd$r2di8<3Vf`Tzx1tB?V!3A&cjrx-NpN=b-lZjzeN98A%A%S z+BHi4(z^E5k(*D~yF2C9_OA-%b^|nIlyakOGEXUhE^yf6C{InD0o zeYriFLf)5XwS34ohMfI=-8-eQG{1?{_3i%A?Z@l%33lMSRgL4w zd@r#@#xalYMPTgSeD7^z!T0>n*yA`N-%H@}LcSMXsrpwr-)n(Yxm0WulMN@_+E5p_};*uR69`R zE6Vp`y58N%TdJO`khk13dcM~_`0B_lsO#OGa%*|MLb-kaHO2R2wSC+@9(*sIC8ycl ze9z!}V7cLYvZi-Qomtc4C$_tGj?+CUZam`tElU4J3W_- zm`~j0&Sy0Q2)vA+#d|*MGz8Z4m9x0Xhi=bb-6+}qyjW^Nzee`sRdFyaUYFTkl8@Xl zM!YWhf<2Fo$m>?1MfrS0c-@tEjv24}IEu2x_Yr(nye{(xr57Xfx-8JqmSgoxCFS_O zG2(UM7fZ@fX;)6a#Q%fG^W_-EW6mee}9B=zjo}VrXt8ppSNW5*q*A;K;go?Od^5ktZ_@v9*s?b#T z`H^^A5MM3y({=t%^~;O5ac{Jkx3vL0^89pX75M2IZQf?q=R^#?;QuI-*XG*q?ycj> zJ-)|y@(S;rTj`c#<`eoH`Lf~!)xJ;?zl3ont9(srKH158=epL5y5xVB9;mikRx=iR5_mh4D~v`W^Uy!8T5wh3C-MT8%-G_J!YJoDYB2$Dd=2t#eJc^79Yt=gs)A|9lSpS9(xk|9K{3R)oDy zB%m=$2G~?d)9aN1p!)f@Y@c)+akTj-G#D|S68Y%5u^V9(MEP714C_Db!i;cp|p0A}hVcI#O-A5+un%#eU^=r%SuU=YU_Zx=C(C%Bu z8=a@!59v=HcHcU21iN4T`JJ-+?Ddt|{q=EW_X+*{7~1_XG^Ui@_e!@bvHMwOTr4g687fOnIEk`GTFg{O>TA|G8^Anb@($u};x(8fcv7tlVm`xY=ttmd0;Dyl>izhHHEU?5;{Yy0a3-IE+1JIWIn-b~blUt?b^az4_3~x1QTAbo#YiYMu~+)3~L!AoqaBK!6YYxcC^UVYrbcDtvG1m;ld+= zdsf0De)*@0c|=*i3BjbN>KFO)H@HH(%aiN-vEpLylWZf2WTpK4J+AL3iZY!ogJN$( z*Q$EWI8r~PJ`=ZW;xWznG{j%rg=gfXS{{S{8BTf1vW{vz9DK7DcvAFexH6R{T*RXjxuYcJwe%@CsZ4E4Eawk9xqK3|MqlP4$j}U`S$@x2TXe^}X z{VdPm6?6*0d+Ky#u2Ze5$~_9IJX5Ni;iB4bLP)b1#A!V4$LdhKl3_czu19r5^a2@< zLv_?KT;D(u^gSVWbcaoVigOkI-qU}L(gSmj9m19u&kax)Aslxp^dSynB8o*0DXd!Z zv_KvC35Z3>L&U&gnkuqa&Yt2pC&E>y2a>dYuw5^TscU>${I<+`_9X zmfe4QL4n=>@s=^P`}Tc}&SQ#5C-f%|yKjHn2zLLwPwkZ5r+-|T-T&wUW%on+`7yNn zBs8X!-SEUT!LydaiTyY_WtPIEhC%1f#Y$2JCyaiSTnD!tP=FIVxeh+Hf9%)6VUhDL zu7l4w*98u>4!)T4hLOt{tb^NSWXw7^i#C^A2M>ij0VKB$p7*~lfJC8tia3@(Ju9;g&d39mtb->lazP{~gLX8pvUPCipi20| zRlly7Ka9K%j;zR+zs<|@ z^ga~|YrUT}$vwB1hD>pG4>!egC-IRRh|k)9jNcEj65-ehwV?~&gl8hopYaT0&v8V3 z`fc_VN|w8QjrxFp(E{Q=l4Oz(f%$MCG$aUS(acDJKjx-2yqut z;Y{}vc0y=UrR|C8_C&Y*$s{qzwjEwsdsaXv=_pb;2-M-nMeu%|Hw4tTXQ7t|0^BbKVWd$`n?dV1T{utWP*(h!o?WpR=%Jep8M|~Le(sq>i z)vnpmP=)RBvZM3%wr%JS|IXRahtaBB9Exo}?V>~Z_OsWh?WZ3@?qNUA6xdH+zWsQf zCwv9(BQKo)?D_UBNSbjWuZ`w?O7QX<~y}7{VtNL z^|dKqgtY)vgf~i7NZu!gC`8R0xi|j~cdw9ht8?p5iRJBh>&4^1u_V6}Ci#at9!Cz# zm$64UglF+?;=F2mM*kJ69WS$bCpxP(h|m;uIsAQ`*k2OH^Io8w^}WFIucD)3!DIw& zqO6cKPO^8k$;I;4cOT`&N*yonF>g*@3GY@Vs5|0Y#QaN@(1UPj#e-fRKkuek{BPU@ zMD*N5Qc@DKgAF>3{v;@xH|4DoC4n%tWiM z_EZkYJ@2Rtfc_$Y9DPmW@mR>C_nno=V~qgvt1k~?1LtfjopwPD-aXT8Jhw(;$S*3c7 zAoa6$%A3>JE<Ws_*CTWy`u(5D6&6lpMS$aU{%6G`(A4Ho@8xs2S=MSoU5G)KNFT zEjnH(FO~0XzQXDBiuWj-X4+mCoSBekK`tM-fb)?*;C#ll4qq;RH1QkO`dU({aeaN9 zg^UY-$Hlf_atNKVF!gSO$04T(j~5A=s?dw9A0twL<<@tJ$F}Qg-jx8)j_ul7Xf@OYt2Ke2rFB3lEVhVi+*&Dyx*(YK_YK4{b~za54SA9>1F3R~dfY^ajE6)~d?n zam{NT&wmU{5Im>Psu0f`@jK^R-}T1x#ymWy%?z|3ODvxQET4^_FQkL!n*`o~Nh64p zo+DYM;Z2xtR2mHdZiCqaqsHvW`zylik15PXj|{dJ%x?;>n>1d>K2RZE&->0;;dL6) z^Tz9s7xL#kyiSTPmIA{)a-QiBhjZ1pHC}VY?Z!$AUULjHxzQLIlmBgF@~}Wesb-wx ziOKGH3$#pLCVy@*9%nJk1$g|?0z4jiLV4- z0}phL)jZIQ&UnuQ<^3p)7?IKdTujBhn{FW7uI3(v4*RWE%c*LKEYA_}7&dK$) zLp+3ppTmuZT>!I~7J=6d3(=yx42PU64&TRwVo9LX&o1%O8+6M(FSC)|&^aO1{W>Xx zlVGjOC@pshg*VyuLoX1QWP)mN>#_HsDeAr*$r0>)=$-qRI7YpFW#7lA{H<4^pQzj% zlng9iR@m{pGl;xTaZwfgWYuiRP;ZnfD2FIc;tGNTGx15ltDLHxviZY|te zay4p7!wfB?-#OvnJPUDVEb$yS%d{8D&c;yVbXKl#1w*571$8hJJ~R_=!ex*KCR~g( z5$CR>71H#S#F=X$2TO4R%P%byOunJ!;mkl9jb^KcD+e1WQ-xrYInWg)O@JdR_J;TN zc$UVQ$VX*7gE=*m`%5dunI5E)EVMU>sszqtM0u2rK~2UOXG}XRJy!7mx2xew1!H-A z#V|=;0)zzc8i?F2v~PDebp=+gN6yO<@o0zxxWD5O!~wi8ZvK}n6X3%iJX{HDNR7oo5r&Ss5Tpp(@>8xmSlVayZ;TxLR06!v zE_d%~DhyHIhj^+aFW^*|?1vI4!@+zA072#el?{SdFvst6u9)TqOjn^mXc_M>G``}( z`_)fHg|74TgggKdJDDZ7t*XU4yDCfo3eQL+OrwlD$T*Dm(ECYr%~G*V{|vt}@xrLi zAHQRYtbJbOD-^ui$^Bk9Kodn}% z>*MQTa@5bQ&Y8K%iv&?!uI6f=eot^Lxs;-_rp3FimRgXoLZ6WbcOe( zOnlW-FTX%_?5(a>{p+LN_48K)&H7iEBS+RnZe)*)erJ);t zU)hV?3sje9oCCsn&^efeFiM%GmP16h=OEN?I0>6%@)JNV+>e`g803;pe4MVvJ5VHW zU@=caNZR%W=fwLb_k0)0cHYMf2wN41ZS1<3O~9 z?J+OPmvai_t9ZjD`~WPBHd4l`b6AL*Ryx)S7UI52YnE~@UI@Qbt1iD#-gdt?n0YGG zi@sx>fPLXZrpSl@YXF?=enyaUF*Yd&W4h1eA*1W}-2v0@#96A}rN+~4UtS)!%nAsA z)~!ZdEz>j3W4UM-j*DUiu&)+fj~Cw3hi%uR@HU0=OX2NP`{j>*la|EXp0KXRYaB(t z<3kPc;aGhAmTs~8Otb30X_t{B$6P(nynz#(*8 zqujwZS4rCO@iiTHlONZ9NpmG7M;s$~v9g#l|Ci%*{h4o;~p?Rsw&=DB{_lZsp>&o#ol{5kJ$D!bLb1q@#*w zZ$@7Qf^q?dR!sT_!2^JBLHDM}ymxL%JbP5syi`2<3KL4x zq2k%^1ETM3V%gt?B!ecF{e}guTnvAtO!y*B^JTR`pU-Q>0C=1)DvW3Ee7)lE59a6D zS!Fof+*BFvybf{r((`sg9<8TWCXd%44qpJ=wcI4m6<@9#huhECMI8PLauAl%$ht0l zuqZO?6~N)9*`vqdFP!7z%~;`Z8WP=E98QXomO{}=aClhEzElZiaro*#=5Y9!-27BI z4rejS72t4BJ`NjyibD4s&JS+faDfj#3opLTXW^GwdE;FdAld$}P@wY_Ssq}WW5&_) zH*-I0-Un=d1>PrH&!p;`y}aUFxcl!oivCUGzi{`hc-}eZUw#`r8Iy9vB;?FSHY+u? zg`Ct^p+Qf|iWId=|M8C>Qm ze_H>kYCUD@rL6ek{7Kn>&t)kOZn_ydu<%n-$p9*s0bF039sUfh>G_pg_r5@UCfl*< z%{r6CtJRKTe2uyuzURyMFPPVr{(;#!?=)RUg9CclLnXdv?FTa7QOr(c0Eage_U zt*Kf0SNLn46R%Kyb)%Oa{7m-m=r7GQHnSJ-lRk$$kSG-g=)_~1aejaEp(3;%^L;bE zc3#?MBp5RFNGI{1;USQt)bmkWj_(sW22ravgq2(OQu2F|%@NP3X~AG_p)LX%&bJG@ zUbfLX*Ch2yp4jTM*uNKb#tq3ee~jz_6-nlGgXhK_$2q zK)GMgd^_mOL>4(Jnd>JVg*-Bl2hFuu7ErV+(QS-%#<>n8QBPwck3_yaO#AsazKs06 z{g9U*QQRMi29sJmqm#?`ZZLi) zgRAEIX5Yrh<&b*V4RWaz>Fw1URQejdelg{sP4Y7Kfqq6zT!Zv86+Bz@Od(pMe1crj z#gypU;J48w=MX5G7H0$n4yJTJjXe~$*RBV9htnofiBrr)uDs##3)Qw6t4QIrvD1Yl zZdL^&jhB&!hn@RASBaf(!i71uUZ?Z*+Q`q$TV{XI)H{U(5dJ(Zh>kGix0%K*!pW}w zZMjidrXCL?A1^%XL29=$a&*nWm18=IE{YtrBk)9l1tdp(#+in~MxpoUkNC%FZ|=M! ziHou^^v(+}(>jhJL*UT;O*~%pV>AE9*I`(&t1ONQ%>Pg?cm41Z6b_D+4KK}Uh_Xyc{_(-2zhz*5Ev5B(?6s1{7+poQ8WCQs6zShs|H&d!BsYo1a&F zpck#HS@|#Wfp=f3_<+H8Yu{V;P2WNLG1ul`q!??Ll8&g@ItIU_oS%Ht#Ag?lgRg{O zZ$al&q#A-B+1RVGvqIe5pY;v3P`75`9vDf5mDzHOf*Fr_xMMQ{6 zyC`jvgP=j3U!hdJ7)EzKIhNBGhcelW22hXEv|CLf`76v^*f_Lys?~vi&M2ydE?+g{ zXyLhA&s3=+gaQj_s_%!!B`J2>EnBuLzI;FR!UfM5ZZ1nXgdmQmT z9r+Sv*te6wQ)->W=KO44hneb+}95cS8 z>@0%=>v=xgUdP;ouKM~QQi%;fw*`Bd&5hSwkn6++;L^@{SJL2IJ23t9;#Drbr=JBxsNwx z^*IYk)T}(r=<{jIls>0x%j@&Mj~}Hz`@cFGeXc#@71HOwpFZ~b-1e0U^m+WZc2%Fl zsK)4X0@9VWPLV#}@zl=i^Y_oR^!ZYJz<&9(()z6Ta|`sj9||V=+>ADktk2>x@Nz-pO@F+t*b0)U-DspNiKRH|4TaiTPIP?vAdXZ%6nFkf}^Q zYa^$U>#4I<5s2Mur(C`KHvGMfPwx?YYHqdr*(;xzrSSROlFIqiKV7AhURIkqx8ypW z%FD>Enw7kg$k`7Ci2op5qx8+IeS&Lxf$yAso$R-dPL78iVB|OuRrMI&%)awQoE`_| zgB;wrumeP$`_82tj+2!M;vatH_Lw0BgXx_b*UR@e?TP62c=kJ--=4#zJ=OD6d&GUF z>2t=ZFKAa*x67-aXgBSvUwFtTAjw$QNBze>i1{)ZIgh*?=~16iUiZa1PF9=|N$0D8 zYsIHL^O2rV8@{k*P}6q?z}t-CjMHS_KwltOJii8(GPRk_Ic{Tr#W%@aOEWQ&cT@|B zzXj_W}X@{wk(4d_uX++Q9f7rgqra%c!*GS;UU};Yex11FwvZiWkUFm}44p5QTM)NZ%5b4jfXY4+DtgrMsC$MA%{=jud=Rz_GtU2;x z2m{N$jlbuwIj(9%d|RRZ*>;NjRVJu_j-&b{EX&u^$Ma^s41UNUhJU~tWcAVz0_4&` z!$S|MbWT7mgDtwZ#p{W>i`Vcm{h7cJXm*Y1V1stt$2JMEWH)xJ+B%+qxc!c z&lrBj@Usy=8}YLVKb!Eg89$rxvjsm}@Us;^Tan$lEfznyjZ2>pqzz>9OSY^b3>9(& z%e+T?@ER{?Ms7Tf&k2v(`vcUUz>`Cj9>;2Zg4`PYw^;M?|i!e2k?@ic45 zB0b3)x4`mMGDLJEyl%!W-DZv5Uu5iT#a+?>#ck7y>)MIsCzAb?Lor6Kp9q_JA@LP) zA$mpnWhUp+=LJWYF9J($!gyn_3}6P9ui!5Tn$ZgsVN(I@P>GfcsS+9bNYb*6gXOlK zUYy5%;QIDxHO`;vsTff=j@{s-trzz|FJLuHI$p7zkCk2oUwby~TO@iB6q_#Ai!aS^ zB^-u?2ipy{iQO042|=Ps3QUS;0r!?#<<9MC{a|T+Jef9S;^_3b(zO4gCSUEbx7Q3@ zIqQ7it+$|Z&Q&YhE?cy0&WHDS5YS(@^0AZ88D4ed(^FA-vWMo zuwLed`xjHR4^eX;z+4e_{;xXd8(eXwp;b{|i>`kO>g3DR&)oHDk2vJ?<4e&J?WDY` zPz&aNfc~6_GkC>b^g9Lh^Y-|#UldJ}&vV-f)KQMeELKNkB=7wk(!rE7Uy6zP62~d| zaFI}m?<~*Yd!K#|zmk{b#~BiQ-wRKp@*H-+utVP{8e4Z@%ZzHr+N87B8F{0Ll9Mec zttiGOK8N%->0CHn;eu(Og$wRD-{6ijBMRWbx{!`x3C(p6mCcrc^kdRj^IokMiYX7H zkBJvPz#P>IqXCG{geLwCp}ic``06do36&V9wht)z8h@LSG55D*yv%(PcjFiAWq-RK zJlYH+!QdyPxluKD7Z*_$D;~eX$(# z+yNy!cVkB$$uT>&d2qlr+vz^v@Ug1hrQ`SS+0udbrK-w4w+Ha9SL|bNu%o)J8nu2M zZeK#+!1|SosRXPP`Id07gM%#RJq6Q-oojR0OuvQmy&89&Q#{_TpX)B^KJU&pBMH?} zz?P9g?w&p65h!pNmvIbNz=36MjHr0v?E6%ICt2%b(POcThN{@q;lO3Lqpi^8;4pew zv$E~u#PnpW`*dEt5y9vNokO=Bg3*PXClvGpU-S9!HN?Y*aZoP)Q0=kL@yp0bh%X17 z$DZRCqrO(%4nMITFITTjJGy38^Qem6R|+ic!$T-M6j@5iKNIUZ*DpmsEEjcvE5sWB zu#2m3))s8KHi~A3obNq*2xQ0wwO+if=+NVqw|F~f$5E;GD!EK1kmBXG2YT+um-PBA zHR3w{;Q3s~;b?x>;xL53cEn;kR@KFCkHJWz_3@$lF8qu^onvsV#Jc8Bi3#Rxa<0y0 z3~WLZoStci`X(007xvO*7AKpiC;b`32pIJkG72+{UIP`7fPz5BH|qEYl}a#zmekL8 zatc&y)AT!_P2<&yYJ9OI1d04i~S5353@ZKSpH9T)c9~tXoy_+6^>B0a7jwA zwe^hc!`C7hswy7fc6FYqL8DR*`(H7vtbV5RH zw*3+>O%Iv%pl$zBKfdC_S1Q)?51f0jp=(0yH%G;{&%xlJuvO964jf_{it!v192dMT z#rY=IHF{MOL%q)R_!{w`5J%9Ln9=ilC`ElYePMnE{wb9QmDKE^o!4yO~eY} z`|@(0Ig9bJ&hY88lJ0qC-)C}s(yXz~JYUZ_Ghc_p&Zp(9S3AeW>s*m@EB>H)1Ir_R zlh5&G?CfOdK#t2XQAXDcD40@?WM3y03Yj#zW`%fHlBC^+EzV>Zf!HAYS!6)&I@7cl zZN<0FgYC)L>yWdjc-DOpxEfgh8va-CB6rd-<}>@N7+;sy9a%s1xeKEl$)r!bHy5h& z>i6RzG|D=F&dI_9HBxA57AyqUrq9?@%88+a3g?(~fFw~?tJDox_w?ssB9jH@cC2&G zrE4b{QTXqL8<4NxmvhWBYI>~eYVr$wASsD}+Tt|uBLnN?CUC-e>d8Yi zA8ph1*!r&LUycU&BF_1oin|yvc}~4g-M&F{ZtHfZVt|&^wK_HqA(OShElhA7pj@4( z1#iN18}C>ZLmG%!EWRDrSMev%_O>n8_hgSz{T#OD6o{izho$2yw|G7YDlOYvI=r-^;IDx8tZD9_QuDYB%bTbq36?j@Peo zIX87fp!+Lm9>kSk^_gC&9p55gaOi3T=Hu732v%()AZD5#|GS9otVq!>?bxx=ip zL>ksO!L||@1GLni&sRf6E1ar-9^xCCqU@&7Ztb?9{{VB3_OMGn+65VusOa8cDXs~~ z{CV|M*NsCAa=wkv;4v{>??g>zCUH-IC8I(nBbct{$1Fw!OF)TD@vk6Kkt)R> zJ{GZ;3nFaBv(PfX^L0eys&#VeDDVEU=>r%IX*JL9V|w&k^I4m2pBHXw-Y4_q87L?f z{w8g$RNfC+PgLph?0Hh~3GHa+*JZwRFTz`ZIPt-d)t-#*N8$H9=heXSRS9oEBt ze7W&(z+~s)lQbhY1M>v?8(4BVKcLT@J*D~_SoTdkldlCo{t#=L?(;=T z^uyLSY!0e8x$Fv&3{94)orXv#xO@JBo~6UiNiSf_C}PQJ_((P0g>vF}N7&>7IWO1y zTQo;Am*cI?t7V_*izp!L{}u{>|41Daz{XDpf-Lu)w?`gfybSxf)UV9f0fUO1oxR{+Ju|?9EcdpyMFuv&Q zEA2a(h2Uki&$z@FN1mVOQJ*AQQ=KQ3DZMXQT%GJkzP{t8vi_Fc(hLEE_c z$Gcj8eS9XU3^-0)ZkQzr3oQFCraKoIqtthNxB0vL?)~*~>?#y~S5x2x@7MTw$1J7j zu6-#c)oADmArg}!I4)dAmr*GyS*;HmB+ZXuLf`w)yvSpavshj91Raa2ZbGx z6s7p9v=75Xo`l?HZ(~GgwhA332IDTTt$Jtd;aHdO9+VEYn%DKkWX4(N@r$vD#+Q43 zXiKS{F{^N%6-nvS5NeT>I=`o-w24y6|E`wOCysS-rG%WCO3Ud1$O+?Y$q5VmJUN|X zgOxlbn8?KBWnc$%gpGhWG;_<6W+o9sgL@ zZ1&ls0cC1`3d^E;u2Mf9pKS|^2OM|Y=G?S;T;|N<&#+Vg`5gF@8h~jtkuH#+&coZav~)Td1IxZH%Sqb%I!!Dsdxz~|Yea<< zhG8d|>oWC6k*mH?_dG7`+um@*2JGP19{V8t%XL$?2bMod8x+HdXX}qh#Fh;OmU2&s zn-}WivNP~V{So)YmOU3(`U%L84Q>RKbFYVUyJv$VZiDAQgNP`;5%3tcy%<>H>Q4?& zv|Wd1#Ahdhbvh1=?u9(NUX3JO4VZxA_tnK$Ddao|HP>x?RDIZ6h9B#P)Z6s>SHYX` zV{$z7%ae!)J{J!+!uVR;| zV@(9bXPSQGy7suE$ek(7Tp&2`135R{r}oRrth>lN14~TW;Pg*84>I14TunK|mZNbl zPY`dz@$b+)sm5wI-`bPH-O_S)WXCZ5K(QlkV<(OsO0WEiYCb2ztT}0I7H2^&cUrU} zQ-*xG`UrV;qKWRh12l;8tYCeq`gt=76RG{Qu%8Rw3O`&?eSm(MdoG5;`g{vMODy3s zXVFV9n~ezZw;UCrM0_6daQ!R^Hkw_|MD#XV)?Vr{w>9P92_K9qYnLtv&D;vjeHc4PK>kXsPQe+4R`@J!E&fW0il)b;{0$#rwIfW`I&s zHn$EMd)jvoQwA5`y5*XBfWord1DDbJFnI3Sa&n&|Cu7@U#+L5Qf1_tGMkA`ZJ*)8* zzKlNO@2-9vhd~Hw|6iMucHroICeEnX{$t* zCt)mHY$Sj}Ub-{v{7Tk&chq$}g9+fFx{Z%OtEw?GMbWrw_@EJ?Tu%oyST3MfXE6lk z)iJW*e1b0$S_dv`!*quy@L`WY_hkH)#Db1%UFeu*w8o35eoGj&}b_v=s#$-u@HGFHSaJq;7i z$fN+??p&R~MsMzZYv-J!1h>MvUi-WR>$dS+{KVO)$XI!(ps-;yB0P*n2n84d9)+;Z zAay35XYtpd$TbetCT@NkI7*oBu4omiSTf&&lTd zVZ^VWQ5%%45IXChIGO)rF|@amKi@MH-;~dA7wLzIUpxb&1K}8FUSRo02$)mv30yWC zZ-De~uES$1N5{XA7Wi+2Jyud^)>Tz!aVF#&9v5i?_t#E+yi^oa;m{+ zzKoo#su$j=CPQ^Ev-T%ql98Mp_5?#;B4LU=uWB#V&q+G)p5;paWWIBc5ri?GSPwDu z@%|csHf?V{&Q~+Z-|X#1@3rM(XC}{J<9EXjoxj0Q)dOCCy+zD;bpt5kWmljLl#D>C zpz|aH;pt96RUYC7ag&{+f8kL=tKhCIWCa7yJ4E!k9L{1Mc5zk!RuztNZE10bL*|I7 z4+oZVk5>;`s`nQ;bOqnav#*ph?Jg27-!uvnFEd^kZC@B)a;5{6wONMo zwX!pB*R(y@?6e=+qYf~}kyVsHe60Yn_7v#7&C*ERiL^rDH!D2=D9iZ6A0RKo5w!n1 zuw-wlE=YRMFAe!ZP-54t1K^Akx@e+Zun%cg6wlo3Qr$gd=DP-~mxBLn2XwInQz6oKsaCk1E|72X(Ksi!Vig z&+XIhBWmtGk5bcSvZr1U#1LQXSN$+@GyM=1GdyPk4qFmc}T5MXw=&s86ZIGD9( ztSg2oQz5o;>;bunmRaZ74Ttzv5}^==KY_CvyOzaf40+Q$kOe3*#K7PfbC-Gp94WCy zdj-t7Z&WMFZ4Y{n-MJ zde2*2xvo~-cX^`KHS+q=^3(;2r*d#pu^V$JTFg^_xT+*i9saH0s3%YT5x`eZ>cZ&W zy&oW(gcP!<>#Bd54uPR0YBq!htTa9|QG(A7(RFtS)_Og?JKipmDAEV;=3#27%K0`~ zT=}w{>36c9b9eFBmJ)R&Nz{6(b@_(pYT7CBq);Fe=Mh-)KUAmnh&{Q9l`^=Nae~-1 zhD+3q$mFs2z_Kbln$K?!dz<06iI-J>M&`F^V2>xi^`ix)`Ry}UM`N8~UhX=><*U|e z!nx$Frd><)7u@G_eD_3*p;^u@ybXO9lalo$$t9PQYW0QI290XF@hRF3W-=`${-gSD z|KqOdaGDL0w z&DswY3r&X482*r;bMt2nRX(YRDuT41XBb zX#7mMbr{c%q0oPPK`0;IjD#4Fe+$^~6$&c6ER+=A2ZXrdh)W5qs`ElnT zh?SN2cbm2={d}$QSqxjQmGBF9VQX||DF8!hDokmcOyS;`Ew3Mi}~@Qn@jTJ^q&MrJ^As4 z0AHIQ@AYO6ew;k~JwTk$0-%j)6sBR}QdN=ap zLj}3OkCR)KT>e}5@oDp42mE-UPx0gEYS&ae`0-W0Ey0fmRtc_q^5bj%P?{gd*5G>; z^W!UaqyME&TYLJ%k@ebiE_< z?v1IuqT{P;b1gPC2&FC2^#T>o(& zKG^=_{&gfWCF2(Y<6Is$*8I5bpQ@jg@?&!j8L4*zfK23A^@-xkL=9QLv~r=N6Ge@5oF5!#R!zxAU9 zrTOg#DvNJGZ{%gxrN#~r+yE&mXEE+pV6cG+ZZIxfiPH$`epJp=`)+sDY-FCg->*D) zY6v0s65ntPIFPCimrL`)RhH(+<~3usVkmP?c|{CMxMGr5C?Lp()Inf@YL(S_&VUJ z_b{y#wqMhCxu)X5Q(w5Y1W#?o*APeM$x~mtt~5{0+)b)fsULTD^3=vViFuXq)Skzb zJ-pUjKV4VAPlsK8>Qx_c5OLpfj^aGwDfe;ivd;uASm*}6h!^E( zK?d;28h#lsv)(|v-CRpLU;B*7u}$fYlw^(aKKz%|%|m=k;ra#5@vT5}l*+4xAcKg$ zKXQHNx0fj2tDmiCVqrhcImc4*A&VU_zO=^P2NYR3|N_-SBA&&jG-dz{^Qax{5u5S)cH$ZyWZu>8r8>T)GSh@}+ z(m2|~&_3qk?qQn66+BAN%is5zBcT1%Wgh)(uj@W-N?)w|f?$33$>I8`>jO)|sJ))4 zaqp2Tp6+-eAa9=PcsvlB`f{LqPdvcVhTAa)jL1qdjxELb&@@-~h)z5i$0+3Z9)6hf zM*7I;X~@U&CL}C*n*HE_ngHq*wCVruec?o;MD8UCC;|y4u;Ax;`l+a4xDR+a00Q8^?u3p zAfiZ!z&%Cbp6D8#D5xESY2aBoADrN5DcmYLw=7c1|F49eN?u^*hf5Cq!(ck#EC0x{ z1Z;jE<>`6i6kW6#2M%5jzOL~$i~$UDUilD?U1vt@Sk!k4l@u>ip3W}}NR{*1VH{4P zB1D|4mEUfXdfa`U^+$8{!$qwxRyZ4)g>&g+EjMSiC?ts++J-RW5zdjXrJ3W^nNU21 z?+r)gdvX-E6u6=8d-)G>BX@`>u>2AHLMBROpt1N?H9=|sQRwk>EdGN0`q9|bL}2Ot zD3xzIj$>(g)|@F zR=Ik>Bfat{c-1qq&di%uAD=dozNAX(%jZO3_3<}}z^=2VhH_9ix5u2j<6!Yc`{7HH zT|Xa_c;$)CwbdqGCUKXtJDzhMkAG$wCnjpUYnO8&4`5`VQA3G6PDf$bESWJ834!4` zpSB+q?ogbgkSlf?F!3=gA6eBk*+Y9VWl7c#hUEvAogbzt;7f>`z9+V6OUGtJ7}Y<- z2!DU-KY+?Oj``uri*2~|qP}|`<~+UViHKwVOK8^Io*s=C6KSt_QEw(5EA#=F!_4}U z?iG~t;f^PeA9u&Zz>@bK#J^)bW~$w?+`AS1J9I1V0h%C1Kz;YQg{^o@&%6D1D*4&% z5V;BVdADQ9!G-NW=B}JU9Qzpjvv=%JBj{xhNZG6PwB!NfW;r^7lqQ>D|JW`82FM*E z>zq4&F7f@tcc^yHXs7g){B*k!`zQI{qsaf!2>eFADwTJvF8)AG$D=r_y&b|#9SVlj zb?TlCQxo&Qi_u38o;qaZ;lN=*w@zIhfB|cEYOw8M_wSRN$Ebf@r$Pm1?M++E4nIN~ zCfUt=EsybilF8kX=HD$ie+1Cr^g)^CFTpZeH(!>dS3K(S zYWchbpDWE5+9IdT6`y*E+KgdRI6S27aDp~mOP_ge3Ath*d4JwRq%XUG=vIKh|{`^GMVt!;e!c$jq%xt1f<@vMg}P6pR&_ zoR~_H+39A&260rX18E&zlH(vzUs$*A_Q}+iJbSCw`Vxb_Kxc~c)FG9{Iy7MtXA%?| zsoS_2X{VT2ZO2f3eCd>Sl-CeX)OUSH-iiXfTpxefIRZV4ZG6Hx5I?OUKyO0+CupK` z!YD7~{O#|U^*Uad5Lhx#Ol#T%=3Kdjl2DmeRwL8O&yIFe8-?5d&-Kw5aEYR%u=9^@ zJx}OiaOWfO#B{7pV~Y?PWArGn{PS$0M~*tQFk%U{s0T*+#B>r@}~nv*H3^=SJhmcqKJ?&QSxme zahaWOYa5RKQKPW7X~xxACg0Xc_+2jF*3y5VE~L)8A9_~5LG)}znj^EFARAxDoeApM z>?v))cou~0Axws7=i#cw^F-_Ect~XrOFBzob(Blr28C01d{eq*_Y3+adEuddZl1kH z@J{5Fu=4v!^RZ1)kmfEgAD85QMkd4jlw8fu^JEdvucDCVPf@*$Pk#oz6cUJJU6Q6x za=3;#!^rjN6Bn zdhzXAp+Vv|xEX|C&*}9?x~d%8HuxP4y(Aj<|@v4M=12psXdsb=v zu4+S7M!%~>zfTeUMo)Z=qzPTKtZ7po_z(DrYXCxnr~QKl;Jb4N*@x0w{4Iv`0C#*(=DpT6N}uY*iYU`iYJZ-$PPw{GpD=!Bt*H3ZPr@3}nz~?i#s~v)q8rg^v!+o`Tw^ z^U^6S;+gI<#Rse;E!}vWPvnV;r|KvwdpchAAoZb~{B!G&l6=D|v>7dTzJfy0{ASbq z&1_v?pH5-b&sGocS3_oXA@>?U7|m3uU(z)(6ze`0%Z&4}0DF1fC-|`3r=m{3p~L!u zpm+^Pwo2BO%gm*(wo!B-yG5(1Xy8#$Xr|sj3^S>J%TKAR&3pjNmNYV}bjf zYn48izz+q$jTak^*i?J$y>gEa;QrX5x~VS) zmcI+?j_YivG-B~wf5iPUq$XR+{4;QjnU4=+uz~#BNHgvu{3m*zB7}isAlnx58{*!F z*;87XV7OTlMlyL9jt~poP|0vXJAf3^@sPU2E8%p)c>1-S-g&qp_||;Z2zzNpzYO0% z{;b+2;C_`S?yC-9RzO0=q?M4dDz@u+ zISHVzDAK(-LbwdBH5pQ0SR<1_Jw#FX%qsVpUYP_ot1o=JcoGO_tV!UdO-fICSF3Th z_vdB3gLAf8M^9In#%J%rpL)>{IGw`p%dBe)~ zxNa#hLh!57d4u=vl;A~Gt*9!0-k4O#i=av2jL1PQb_+YlAx|9bWv#_Op?l~dwai>PgMZIQuAPH%dHkhvNcs(IV!p}*CP96S$U-F`Rn%t zubdCZqz|Caf^87FuBFopFT?);g&4=RnZo%vivcJh*I+LMX5`9bpn+u%LA&UfjQW~y zQ~I-CvDaW(d;Jv+rpR9D-z#OW*+P5ur|gzIhb(Ai?Ujk*U4LU4du1EM zUY8%9-!B_(m~Ru?_Qm)AKthp5w96Q2M2ytI(B=u!nS8eryB}gVp#*1QB=3*yV1O!d z2-Fr10gQ$7&To*vEw}QWuw{ZD#6^{J5_XMT=kfUuV2;*%QnkLwv*bO)b?<<$dlBx? zL@r_`a(9v)hxks>8+PuvK??@(JZz}o{!A3Bw8H7d_bk+OS~ecywJ+t$d6UcQBPO>g zC1-ej!M2#tru|T)$iL@L%I+sl%8i4k|4;HtCu?v?7E&dG!?)x48ojYTYfoN(xoHa| zi_L+$O(_~oU3U`zZDS0CN9IcS4sf#oZ!K#x&WiM>_R~g0mO$KUiXE|0_)#qe6BbK< zN3B2eJgwnw?Rw{M`JL;YM4n1h|9%DaJBy$S(!UNp(Hi+%`W0CIq*MYO#n70*=55Be!z1%-$k_y&gFMz0$wTnU z54;MO8m(g1obP)Wk3aW~A2sW+dzVUn^o-N4)84fIhgI85=Oo&lv__C0Q*UxaSnWQgzg;QP7hvAc=a48z_U z!pWj$qW@UF_a z_5ZB83$bp?67teDFid-V^KeelDsCcUQ8O~m`Jw;<(N)pYi#5izvwVA;`5Da)wzAnW z-uen#Yo7`CO)VnM?Z8UvljsJ!S&hx9nw7r;PC5HMdypEJ)<2AlQ@)=IPWk#DWqp=U zOkr^yiqD__--qm+CGr?s@=^JDJ*kpEr$)W#tn&~IROx3S-Xq3@PZ&SVhPw4jr?j9w z$}h8Y3iB8Xxx>6)*L|7%O){lR+ySP!u8+jxAC7fh1oOK9mU9sdR-|X9;G;dB?!I2pR8lye`=F>d z>UcI|q`byc$s_q2J#H4RU?9Ng^gXE)0!w2U|C*Ka72l|GZr^7wNxGY3DA659Rq1m4 zRDQfTUQ!P6!p$=lSi&@jU_&65lN`~cbcWghs@`?#co;i2o5`tFs&vGIsQX}5Oi0h8 zR1wu~f2nr!{_R|SOK-w{9IKDqJSx+#>hF9D zTchNs=c}CjAhp`Z^p}2KA5U!QMM>iWOMd*UG%A&bH(!Yo8@*1=uY_*J{|gr9vf=P_`KpxuA+P{kYf)^mt2r2FG_Pu;|= zlNqZwjBdK2j6vuHu{4VI$VDW0AH(~Z;FtV;qxJhHyx$*R=I@)W-xG)5seex#PS2k! z&oC%(#i{4x{q!mA1Nu#8l5e_~PN~6P=_K!|>;BP{Ps)ec41b)C@JIalEdA#`e!G8I zio{kyV6)UWNCY?f}ebeI9K*S&OzOmTBrR z<%=G^F5=0CC!MabZsd5f?Z~t?=J8}dXZkiPo-B$6dBl?)2DDW;Rzo4b~{|ZLvBAS&+iZ$MLbzIDiK~@uAWyuo~&weDSa91 zc(OVKX?4w-=-e4#Du$>p`zwXFCXP%mQ{=3%vbSY~EeR!i9?AjC9jJZ>=bWS+N`~Fl zLs9P02sKjSWJ7@YVQdj0q^toUW$NM)E2L~d)Zy}Q>5#J66xLEUr0g?jnZ}uF-48pS zOV3+ivsi|B#Fc%dD6VXYnyLz;+d^;GO(`8$_7_YzlxP1hl{`n&jw>Yi#g1>wiz~bT z&)}cs_IX|YIr2Vx>P^If+Zb9V3qQ5T{x+xclsosmDJ1KM$>R zpZ)lP*s^DlCQa7|Y@3;8j0SYy{AW?%T%n@`8=hg*b_=)W6gHuvk8 z5Vf+i8>j#C; zO}|j%visu9I`;wwjXKWk?>f$G;9Awb*GimO>)tfkIbkrukn=SrYZ@ue?87?_!b58! z(2_`c&(kdr5|;tce8%=H_=46`!+XqpDgKC#(Z!kdqL%y>QE{Bv-)~`s(X#qeNt{{e z=W2XP#2dh#;dOmQ;>>&jj?AvcnSD;jnMJQr{d!}>nKcGQt5uxYmA@m$n^r-b*=JsI zRXY^fr%<&Qhp`;PVpUW;Ve`o zvj<_jSeM?lLv1J+djl@JywJtZ((_*{9BYLC6a-ilXBK6g+1XgBas7Lh(x(PFfta`c zt-}1*2s>$porFE-ze?lGTAkx_ab_{tw)5=oHLf%~r6h0qsr>NbgKvgQqA<=ZW*mSL zXExM-Ga_}n=2UY*S2o0Ki0i>DLCfsgF~p2gvNr-hBduyD_>_~s`v*)h+#^F}6&am#J02_=G8R1OAYoHNffe(g%<^Uw zyf)&@!UqiX)4Yvto!u_j5AA#M(Q}TFaMHDpbFy5KCsQT`E)E) zWb<&{TXAM{&p@g0!iNs!cww1Ti%QDHnfVVEn^h4hAz)XbA5Por?vFEz*)6#o$u7&< z>nj&$HgHhRNK3_;{qz?~?5&5mYybn7KQW9LXO^MGd&Zf~BPN(QvxuK$r7+H{3eI8irwHRNj5BL2j5EtZOf@SH z{D+P+`{X9<^Y?#8jqfsRzUN$P$C*VtWS>9lKhmQOcygpTvw_1oJUY(ooIYySs~2aM zwHxyg0H7>hy>fA8Eohg~olOq^LX?2SWdAe&d5Ss$JU4wZ~E>&N%# z3}`xndf^>s7P&&{mmPm3`entLWl>L#65DZRA3rr8>GnsqIW=Bm9B20DpKH9U{+4R* zs}N^4?#Ue3dB>SWkD?(J$C>@~6^=9O!+?vf3hs;;XO$iM#iZX7pZt8KQ?Fbd}4~EPc4cwTYt4{PqZn%tohU3S8)9@ zp8E=VChoY<&oY@u~XV!K!$94zf%r@SM`KRjgk;irDLN%^E zGOh)2W-K^A&TK0(S&mVh*|jL@jXIvg7%8vuRPqR3rpFDD4}8&XjGrWh^LSY|&g?D| zXLeS4&w@BJM8XeusdC;FW+_%VBgUCEVh2(MM~xI`)@j9=HR<}66}H=s3q#vYoLSW| zsupq7sC7hMoSDCp@~k+sbYXca&J0msOIPQ|nMJGV+DE+|Yoox~5^-jomn!+ik18X- zk>bo6;h5dYI5WSl-;NX1``l5lII}jp|G7o38)w!ZSN-vfGy83Tab_v>)QvMc4rGFH zWAuZyO(4Jd)08T_=kKcV)5M-J4$Z`#F%HfAo^fa<_Kb08=J$+4GqGokLo=~wj6+kg zXG^Crpu>cpwVUv>srV%~1v(jiRwo~3BNh$6S;6qL)AgTw>F4h=;b;9O{OpVR&+2fv z2|pW7vS$cCdywTM_|;?#8}bZ4OELT`&C1@PE0b8XU%9bpcNN8=wdP{cD9gd1jzy!N z+~iNf?p%#N08~ z`OWr2p`bS7vAj=!dS?>vW*kaUezX07ZVIP8`~qVWkJgBqa~!ZtJlbb}Ksglpr)>Yk z7{sIf=St1r%hi*Mdl@nAO-#(>W=L_aU|;Q=copS08!D+UyBd#1JK{PjXP+-RiJu(e zYh9}B%*3JD`OE~DyK7ZGvn80Zp+Q5jPZ0Z)b`TmAY&7}IjtG|yK5P0IOD`LIrt+B$ zb*OfaCf@5lOcH48$ob47^|}?M*nRP4+4qz6j5e>?zjeG>OtCdYlZ`OJ|M`l;!%`Sx5Q7(zas$Xx6c(b7oidL(5 zvv(lJUS;uSPyf|b?cj>z3RSxxui23wAzYF8dhChy;*zsm+P5k4c zyk_V02!57}Lw51Abi7lGjyG%k5M9w;dCi`|8VfkxzDVhlN4zy+bKH3AuxGs4FCaCP zUO`^7nFyJYeX;tNlxe#-V$Ro%o4*io62Py`Of}r%x~3%A+ou3%ikFv@OYWR>$$64; zvE#u0b9t#aFb2MH)!2_WNM*yUXjncL=N&_%o0xVCF=3}M_t-q-9>c*^uiRs^-P~g* zBllQgig%rROofTJRNJeB1F%Bnsg-?lxyK@WplnQ76Sj_;Axh*1TxrLIO|LljSZ_g0 zSONxUUS|AkTz2sH>ek5?PKs1(=B#e=1%7UH^RJXp&~l!J~3`xCNd zQVy?LJXoLIn)fnyr{Hf1dAus|U?DWo%$J4nVCnfve_k8$U{(K93=*S^2OCuJU_srl zH()$iMl@2#gUv?Hr;6gij>2x2J{FU1`bd$@=f{J6>Nu3TzBU_~#__5k9xPNNHml;n z{J^e4KiDf457uP2iuJ&5rzt8Mux^};(IEc9iiU*+P#{P=#(i)Y7!edIm)NH+<&_|$k6>W{s@ zlv_{d?faM$Tg1CaZappD-(Mqzn&4gJ9M#@eAs%e&>Kxd4$AdN2QFn{u!47!54A$+2 zyki3xFwxb@;=$5_8>QmGE_fetj`3i>)bU{b=w{8z&odtE$9*~;Ec?ZgajLUP#SOK; zkNRkxkyIr8s-k$Xn-{zGq^D2UPi*@KDvt-7ivpE?zVYJ0{Mh<409G6ib}I880V_IZ zaBQ16wzpl2`6t{m^0@YYO2_$OGYs=Ye%>(_>^j}VmLEYPyPk66>E?a#^!M2DecwY- zZ`AQjVx+vrQ^~_OSC1R_%JCxalzm6z7j@&o-mdsYmGj9}h4Em>J2vonRgOnIk>8Cc z0ygCGj?HyMlhVV~hKllzWvqCxn69tVc(7=Ls-;vsSoU)z|?&<7ed^>$Lk1+%L>K)~n02dPw^na)D?axU_VQX35G$gjCQ$O)EL8l+LFo=Q4)=fzCdH5_Pm+@>2Uc@!GUA&hJTfoeK z!;3zWP6$IV7}Y`*{@AX+AHet6H(iY6d6ROKoaW6!$5JUah_N`cCei$Okz7L>Dg^hXXsHpEI$IrhMk}y)8j9A9>vOwxH%R7Fg{Ht=fxb3Pk-z* zg(Yf#uuXqL#-{l?;|mbC9rt?~n`%!_0TTHA^cex2$SHrGxD* z-t?ZSoNW);&qzgDhWSqlqg@a2jIQKQ`a*Vvm z_-ws6*;d4N+J%BS;yN6(xOFCRbv~L7BWCfbe3fKPJ;^z$y+;0~-IOPPhiY8^+L0_a zGk{{XzO(cUN*`SF_6vN@mABUv7)k-i65@FE@jw84wXz>9jp3pkQ< z!1_rS2YtF+qi3$(3tr&L6Typ+bA49fMPjz2wR{Rz+vR3U%G9UI3EA%q*3=cRZ2R(pJ;Ez?&Ad2VaA>d-WKaxG+yCc#K|Ha1Kmy!Zrxje zwa^LH_vJ%ezT(Q&tmnqfUt`C~D3!gHupPw*p*m;<(i-z}FtlR71(#zyLcv*p zU5Whg@zyyE2IbFN=g^^Pd*f%=nfs%Ie1i$w&dcaqmh;A2IMgW=Ed%>?FuK8{{e6f; zUZy|l^00C9_ZqzME)jws%^lph!F{j&t6t|(SP=AF=Bp!6Z>D87b$kd{sY&uq&}G~v zOWS@5wmq1#+hK6Tv;(vcSG3^V)VTS~^9)77Rh2thp_g6Ic7E7~4|996pHg__C5Mwh zM09%sOAbH{)&K>Tzlhe#AgLoR6QFwEq_%d)4j_qTL#DTk&=0 zdtWmCk2c*7yB{a9hK@C@2A9^dx)rKA0Mv=P0e$K$4Jd~?NQ00hbBbn&r)ZP{O~(a~ z_T0db5kIlf+8!+oWDWdzv^u5q^xnY|8 zU@+~Dgs*?5l4oH*Jjdf}UsDe5DoCtmVi3;GtOe>A1OtQAM>- zg_-yj((VzJGH*S^H+)onyP-4LY81n>0r~gKMCALNE(b!c7zji7iZ6B+)ohc~Jy-9W z)LQu@SOfY8c;}q^fIXzL*wEY1^8`p!m$BbVrdKx{wxv@35Fhlr}= zUh=A%TWDzw@m0Lz6Bl1^da^#gQ7->_L|y(>2OrXgdaNdJp%=IbE(GQMU-#9+vDCs# zz*>1J4sHUwY)U%{O4tALAmH4Zh`Rg6z6tCcdQ+4d*7K5*T7Q<^z}>0cr+`g8R1Z>v zO~OXGbPb%0q7a<&J0FGc0B{g1L2fY^6! zp<$4Cn-sk5!Y|R-97kVYn~Z%Gp7{$snSG=c7}2H;pXUIeRoZ`e(L(bk|WRvAr3exx>YS~Q zZ<2nkWL0REGp8AYc=4M5=k8tL+pOyU@eJ4q*9HU(8?XRHf}mu0%S16_tE8;e!k84s zw2F+XKfcs$b!BW&=;m5WHTv~Z6}5u;tyijo7K$S<#tJAzrVzz11W?Gsyo8GyE?@S4 zzdz@alk`cOu}yvbpVw>4lk|Dc`JB)B+|TEHPM4ORy%(bw_%>i7FgA>2swJwVZ^K0p zJw6X_@pAYlX7s5XXPY(S&Jn>BcN{i$Xr6_{^^b>>bDv#)98N~6fV4u#h;Pz26aHOr z8@#vK$(}7i?=A`dV9bMHqbj(7JbN{`AeBre*p{W-_yq@M>8DqXD}byvMdw2 zX|EGqyUKU~g(_v9Cd<31VZR?;PDs=}NldxkcHkS6_ymMy9{aF8Dbv*RFhlt(xPucKG9 zHM(xYJ-{V!v|n=WJ$38O2iXdQhUW5|8uCRhInV-n>kxX2RXOuC*!@usjJ9PTDiFiD zXJq;~?u1aJw{cl2oz!}qlZeacap*b1jWO^Xq%90lk12wuEd|+edvfd3h&xEc0V_j~ zh`&fjL@Cpl_Y-9G>#2*PVef$pDDT%vFD3p$`@oghXE1q!b)Vl<_p^tQ*gCCly*4Lk zGlEggDV8ysAc?>X0)xx&DcS+7&9G%@XqM_Me@R3lmJ#M=9CK>@borS>Q>uU4*EOhO zogEKQwSBF6DfQ#nQ?;K1Cq~G}NdF)TOoR8x5@WB;*Bv_9x);a zC-nNC6URaftQV0SU|27WHsZ;?(~|vNzy{8U>+iy>;f%QcE=&;4i0ki);1d|@0t#?O zTz^*#pTJ%hUc(u2{ap!sCh(cWXA+++_-w&vD?VHC*@n+He757W9iJWe?7#_*UCF+8 z=LR9TZx~)Ac}2JD!~gJ5Xr4e?fg>+n6hHW}#cyZIj8H4E*E0 zMJ-j`H|2!5+AuJ0^LdbKJ%07G!AG#lE~p^psmy;7keVAxEA%21k(d7zXyO7=^A6@V5O|0$cAl<)Xq%25ZwEB>FFLew?gJ~oMYxOMWtihF4e`XKj0lZ4_x;+4 zUhLq9^o5?_8Oa2)h@L>QIVCq=ED0qzMDA3iJYC%{J4Bt7Ne6 z;La~jab-~A6vd&Bm*NyWJGy^4g5vK-kb+_0h9HO;gbcZhBWr=%qIbrg7XESU`g7q2 z=@fJ5ZeqM5f~F|3ie3=ix}qe5igS0UX6!t=^H)QDJY6$~fW5V7QtYAi+5ofkPrXfr zy6$$YtdV+Yknj(7@v=G;k(D18`#QZc;~sH}>IZaE1ih z<(%9mh;_sTuC4Dzn@xS6ucxt_Kk3V*_yAPbJx!48ZB0ktkz5borXV2#Pyl|t1A3|< zlmK#YtPtW8O#^4ZJ-{OP%KBszoSpV2W)wH`G|3APguoYc`!G(#0-3<%=vxeFM6&}Y z_Tq;)CLZzg=dI}z0WjV}EGOv%=ANL`6U9WI3W`YbpOV0GV6dr!oeY` zb;#xOF}h6j6BHElafl|=7f5R%R++G}20vxV^kz8cB(9}dOiT{CG>=Is01rh>OvXD2 z$#@Jsg>-+~Oc(hf{eYv*S`u1ytmH}y<^QnMme1B z#0>Mle~+0C&iMyI9%~xQMw5!`_7^zv+srG*fvMw4GL|UeHgGISJ(eVvgZtM!%dr## zT~vFZ8PrLG1m)qhjROgun$AJtHF5rmUKBGAJVX563ZwxfWP3S~y|)Z9t+xkHRpYM} zzJ!J^vF!&IzM&f7>jl0@>wpoq3e0~MwOqyq_HPU>yivFjRik= znUt1XmTK4i8+l;lk|Ph4{JWN@hr}CPEi&QAN|^wS2$}F~bKiZC1sTj;783=@u@tgl zu`3(Kz0jlEw-@KCanI1}dk&vPKngvNfyZ8$w(#)Ri`!&m-*2~GT zM8+gJiY57ziz~eBF8R}~+kdt4C$fganOgpYO+S_Lf%=#znMD4OpMbAP<6Aa2%wI22UYEo41l3slD~SV?UJqst@|tfT6Vz^fffzN z40OZGu_q#qJ#m)nzl~AZQyk{hxrohSI%@@(#Rv&WEcXax>E7N9IhmVaX!N7_k{FX# zzQDM_dPhv*qh|S%>DeLq(yrS#a@QFr{gR#bdxER0&L9Yw&gyX4Ez8`b!0h0jmE46d&YzS`u=*}is1;SCB-KfB`~@YzJW zqa6%R`QmGLbb;DywL9Xj-O;Y$Fm^{(IggI&9e(UTwcU$iCjPFy&;Ks zUBdh4sdoLy^hbHb3vp1!^wPkWU0=CTT))cY!-3?vQ%aMv9!M> zz%(SpWVmb@NnVB8%YnekYtW}%GyFFDEY)KY35R7?=2EfaYU`HiZMW!Us0d*4?t80Q zr<^Pw`B&^~SL7onFn+&vzAycGmRWD~%P$_sYZKS&q7ozso-&np8s9> zx4&FlT3<`>WY^Xt5_i|%UAOKQMw!d}@Q@$@^x8&&-FhIx(bmo(%`;&KCArT>Y z+=HrV|K>d1q0}Vs?ok2n%zr<;EuWnP-m~9Pj^B?`7VYvp=>PmY-IQ?I?#|OKfOM+l zrtVCh?oB8%=j7?e{u{mg$LHxLs^bFE{9m7^n}p)2%+t*tRkC|#K>TR)dSae#CnCg9 ze(8>{X<@r?57^ZEa)q#lJl$WRV6dC&@+XvJlX&!Gd2>6OryKh`sKU+D&GHBTJl%8t z{EFo1=8jb3e^q(9m%}6;Nyn~WzQfMv>F$9b zyq-FV*1diX<>!3R3NOcAg?f`b%OExma1q@#S0swRIRcAOuNzNzA9_56VV3lG$V)#m ztL8l3y=kK}|I5we?YvBE+aAf}bnH>kaj5M}=#0rY%VQkRzdUdB36zuD^?9QMXcctW zW|op9lW3TEpTGptRsNNEqgi0MJi}`?mh64Bj)4?;{~nAS5|=$|*5 zhFwrYz9<%~B{3`JEkiDxrV~1B-f3^NV#_#iLtiG5Y6tGE`1_>$MAI&ml5ad=o2rlh z*7_Bvj|Wg&aw`8Vv77z315YsH?3*M{v&?_nnLNz^#_#99Jp_TE<%eIsWiMWv=)XlU zTPojj5U+#vi=nTU{I^=tJllRZD=5p0Mp|!$qlO2+gG$2Jnq0N0fhj~U1A`OL}UBXEn^nv25l8NN ze|^1(C%XfAcP2VUG7u{&(UB*U>9kGm)Ip*n_U>#gB{?=T$uZ)E0Bz>bD)s>MQ`;BJ ze8nj-B){=Dc!%poEeEUj{Ni4edN#i?4Y>j$%!a>C*;J?{zcF}Gd4A(CxG}2XG;wr^ zV?zfzMu?N&*ny}MMKQ8GO@3oLY$GV_Qhwu8%x}am5kMCi1axr8C!{(?ylpTC##-(A zAx0yYwF7Kky^@PV8cq}UH_x*^5v(W1)ztph=kdkVW6OoVK}@qATOP^R1z?-mj#6gq zD7C+*MYqc~c**$j34Sv5DwdMh+t^b7`~$gEXaoUwIn8D>3$TaM507jI^F54rRUC0X zYH(e?H{$s$U>5RD76yT_VY3cX=|j}~?^PL}Hu;Q{6R5kOjzXcfLs>RvJdd>-TnaoL zx*b1!(X{i&S8`}7d_{D-Q{gMcmL|bh_BDE(fQ6UEJMfjoyT16^&QNh#t+rIkw6nwb z>MFxmi*ARJHNy*pi}b~qYE$19ZyeJV)z6uAmNGvF&q>~`Dlg{^;`xH+XX2dgR6gIt zJY8J}Esphtw0_>Sk5}X(91K~3FI$XJCYy0aTfV8{-f8CdsG1_(`X{~g#%O5o4^=rc zBy%GU%TV|&yel@Mp2*GbyG*#+sbva zU`>T@kvduZODGO9!`G3%u;E-bm?O=wXLE*JRLZAIAEfBQ^keCwf*%WPX%hPC((RbJ zwC#Yt;@4N9uWv9(v7EkQrk%;@3xXU9OwwGD#qWi{kVpzBEKB7>YCLBC&A3dSlq+Z7 zfB```EQF9)@><5Qa|w)6O&IeKSS^f2Uvl1z<<_30FQsxRyKxs7)cqOysiZfoD=Ctb z3W(k>uG?Sv&!PRx;he$7a1qWjy)#|S^LXpGWdbz3i(U&Vo(fymm>ZYVd@*v`Yb3kA{)+Fs|1PF9$K^f`ll#5(IEjImZR%JVgUc1Z-;~zd!Tj z>Hr6f0vOnmzVAB^Fd-Gr0m&Brq@h>xI4_;{3+$rW7}OPP711-*pF=UoNB26w*x4bC zCqtKpFCF?)`v9~Y$rQdL^o2~~g;2VS4nxOBA(2(lRY`z=ra)WN>LN%`zEi=~yN{X| zgICfI@d|XBx^i_JK8qidJ(usj@0F{GxuHR!X+=IGhI~eGBgB$c#IgXz0yIIXlgeX& zl%z5w#Kwm5t@@|m@h6pOIr_t8@{~t%qYcH{VKJ_`_1rmV=t{n;LQd^~&6^RCLXe=d zLQsuoCVnketUxtrF|T*TCR@3Xgtt zsP$Qq<2n}mWiXVZFqFes(G?{i!MQa3NNYv!8t8UPfVghY&@~ zO7mS9Fc}zeD|B-LJ^`NHuW%wk$hHCmAG#q3S%u=>k69GQ(8SodMR6h!pM=kM1ivT2 z79xH#nveb9Z&dJG^uA6|*zvup@IUSyH(Z9Mv8)C?HKhA7ICAJ**`zi9nZGmvr9kAS_6Ex zLq2b%MGbOZ? zfaz7TdSG4shomnW$M_PHFG^%TMscmga~9(o%Ui+^bnLCNm`7sur20N9TsGpe?$_W9IgcSn8%Wjd+dovi4`+RMg{nYL2=;C8k& ziQOI0?HGEp?a&6oyS{$i@i=p@!tNfOuEsruA6(V$?$GZW`mVHtt^fNRCK7Xzi;NIO zS(qCzX_wT&lvnkJVYb?Bk_;Twt@rSTHCwyz#rpsX#_4!sz`%{)d71G;&UP8U?M`Lq zFR3FXraDwEV1yEX$V5_x`KOW59}?Nkuwt9))3|{d(gYU|6ss(c=!}(OQ;hH@=tUco z(Z7rNAr-4r#_C|g4U0rjri{(GU#wX!rzH0(r!xb$V{d1GregaIzVlzVeiry-`?0C^ zfNICcJ;M)(vrTwu#( z4>mDpp4&eV*8S=3O7pBM)bwCQXi)1g`p@}2G<+lqTn0X~r}i-P8OVVKH_})_bSUh7 z^Pg}y^b~Q*M6U#OzXrdif7%?p2VIL@b`09fhkqiIHA5NA#!!|c2@tm;38c~*F2f%N zE|t$>>&1t?H{HA+AP5Y~=Hy=MGeR^f&5i@xR@+E|3(blyfWnpobB>iRiU zd;$jG>vZ!yBPUFI#3wIPFZ&PA&{0lI`P|9_>GC839n;i&vt3?}J|KK`S6_`Efh_C5 ze$)lH+%|N4y9{QOe4Zm}^O2ttOBVp4_(>ry$)6-n&{Xen#{z0H@z7*O3OVcxUf;AK#U8#0;1%0%gaB8C{?S+w^#`mqMf`i`qTr^HgB&z2(i1NX)vmHh9gdAtC};NkLgdK`)djh*m49AM~8wUY(w` zACffm{0{b&?f{0_4UjI$?Q2*@4wF&ZR5zl#PWyD7MAu`%52@|E=--czi7$h9QM%ci zs5s$$5b2+S^wBdYNPqkwuIup~UViwNdW^3U--iCL*%rzjbK=oPRIXG%~x6fP%gli*jZP)JautRJe3qMM1e|4BPrn| zl`@V{jwM>D?s#qes-2Fw1vC)|YdHPn&Hk}nQ?&O$U{g>U;lPLRHkzncr0vb zsTu`z{rcLf4}&X*c}Wdt%3od<$t$+-mE{lb|9Z`?0cq}VU^1dg?ouIT`Q)0bMba6 zuHQ3qvFdvW2-olx=QR?Vb`nD7W-6QhA%6hn@E9+spuYrS$--q)0_hJ4HYiW%x+!h&A zQw`TZ^wJvbydIPE!W=by>G zM-u3p@&?kxtV8w^oB?gvD-k^+Fd5y(Kf;buCjPb(?X{w(u~sX6Adiz89y4#X)88%U zxbzp)?YML_HT_+2rJ=vb-)pC%_D4}S<$3kIna7==qn6uz>F7n2X4CWM&{4}X<#c4` zkaProXC6sf{E&8x9^^Yde7pFHnw}OxEH60{>v(d|M`;}orR(y@rZBFgTE}Zc6AXyJ zgz5r}@Tr3$W{h*qRkoO#Wl|oTY6N?tV1l@J2?`I2TnIj=;GIDt!=?SuJwRtRzPpfX zHPcpp5x->tawwl>{?(6hOaY+_Cu|X$`-E-oj6_9qVP#joZE{BveEr!65(+{K_9B zq;wd&l6tcpf18L0fn!TUF`}l3ORP8#tAV2~%IoLq*TE;|eLueCQ;5&z0Hf7Q3?EW2 zMe#RvlF2#=dESAC_J%Rfp_3w<`s&h`(N&HqFb)sUp>a-IT$K`=1jR>Qjfae?g zR83j7%XscS=iqPnjWJz5Lj!<>(@j$9H3y)i)Bz~#>KpZ+l`iBVD12@>y-~@XQOcb( ze;N;xQwH!iwx;5}MPZ&brT`QE_$eimaR;@jB+wHj2}C4~wOa{?gwi zBA<G(_T; zN_O1e)rZYTB>#`zzaOCNq{57NfB7Y&HJ}Frk7)<57Kh6~uyoY)>h~Eu#Vg=P)QrpAJMJpfRf-`o`9DxC;&CT-X?X&v~;; zu*CrbEeL}TgHLCECEoNg7rsTr2Vju^uZBgc&2!)@ zs4TD7E#7yh1vCLTl-J&kJ4;UnZt5XknBR=(A)cd()-#2>41X{W#^jYOIo@yWpLz&I z^?KCWf4vRLx1%lZo&e(_rawdfKux=`pX59hGfhK7cd}y@W5?qE;wZ-rp(6g#1v;~8 z9C(8A3aJs=cuHqq~(dDAmI^{O;gI z;<(EIunl;OC+wH^et^TNwbc*< zwlGs*Kk$9w&&T0w=}ZX6UQzQjgg-hk)ooaZAJ9(~ek6@u&ZK}ik^>SzcCrx+kc|P^ z3WxZXAKb!k)+m(f2bfwDw**xro>jQqh5^V)SsV$BSga9X_Pzfq?Jd!xF>&26oI?O8 zxpVvs>hZb1@t%Gg>sVNN{1d;R=Z?GS;{&Uxc*w-H2`9E>yvP=dOQF1$S7rr+zja7yc6c%?@;OEikxR7Iz6FY7efii|bu};+-;h!+^K%g?P7SzL` zRtGS_+Ghy~5U}4@Utp{YT5j@fuAmE}2k5WyGJ3$@?|Nk1 z*vsTUzFSRhQjbIoLy8_T44GFl963wsluXL%f|1o&mD74;1-jCN96>*dkV|p;z3>~a zO1|nszg9-JDS2%K&XU=jf$^?;6mMbG*c>XUWTKmyp=7o&8Bt4_D4a%_NXeA*qs4gy8wVWf02O>Ir0!MUXzYWTk!XbJGNi{`Kv{2Rplogh+a4(b7n8@(~Q=-c?&2Wf5C%F9 zs}90{v6UJacv=kh?*L-uF=a?nKpFU))T5Up$u5q}9#y#x`?;9`J{V>EUFVh}|8OZ!fh6#%X#T}r_ z==Xd{Y{i1D+u+Crq2HAixXKR+u4M5|tlZaG5csNhgn*D>*K(Qu0k~Z^LLnTORol}t zo8qi!yZr?qRxckJxjzYiDLd)6=ms!mTke;^!S7vyy2el|q*btSv-WevzQ}UOCHtZS z?|L6C&Vqem$$CLqk~{qeh^oIqlW z%mZ|4@RV@WprHvymAFhyCR&zCA-G9I8vPUclj3vtH{Mh4-Hw0YbD6h~0^wHfoXtLS znO_0|c3uD|WcU(`)Bo7g5FE__hmbu=OJ7hA6fT7nynt)wON*N2^WHd07iqGi5E>ht zQt>1LsXvzB#yci1K)RiSP+WZ$ZH+mMZx#sx|s(o&^9K=+oP-wOKQ z3v{|aXCo8-wIU2y0Lc5G8bF6S$&n@f?)g=NTv*uhENz$4huNzwz&+ z4>=%5$7g-$BS1h%A49k?^Z|LMR6z6vWw|{MGEjsAx_BIP0jakXQc})3R#D#JZRPYa zTmyY@z6{PP=2fLB>-7kOUp~Xj__M&TH3JgFFGn(Ne4i}Q3Iro=AR}zoi8bI)upiTD ziD{Hrf6iNRy2W$??HfB}@G*r~Km9rlfP?QCA6WiD0AlT+Ms}9ZKA`Yg3~VJ{v8f8q zszK+=K&PawJ&hZheF4EQq_xf%$$95JZP6J4L}Q~?!@{1c$}iU|ewmIph^tC`f&BLN z&M4`NYI4?Pn^Vfn7lm8bQ33iSCN1^pH+kokXjXFvj3z-`=VHGhih*>Q=2m0DI zY5GiPel+82dsK}Vqp~ub_ri}56c}o&(K8~ZN76C`8-EAQ!f=JAAV<=$P+9~xVrnSE zqU*O9D26a%ln6CxsALzlqQ|lEDcKP8WX4GtNi)VCL+X(i{^u-f?^e>2J7ut+=1-UD zF#K0?X0`l$&fD)@md^}zFm4okMB&Sq&mho@eq-TJ%V%@hS-$N-&1c=X(R`*=*@F6) z$X-N|C;Zg|gMQjmc9tU;=~%WVzPcQirDL}mndQWh%HxFLtTDQnjJONqgr_67)W!)n zk4_RN%sk|R014A0@#cSRobbPIv7QTMxRI+SUgGF$k)yT53714T@1?k$ik;vm9V2w( za-|riPn__d$cc08Xu$UGjT2rx0iInQCv5*6CF4%V3Ewzk5tmStYV39+NBGGLtScAz zcU~Q-^zA~ z5o?!8J%;KbXP2BxVcw_-WiTWj18YUS;h$Tqv=OQxph7=wM$W4u9ODoSG(Sc;4`~J| z$Az2=m>QT=a2uH(NL>clqr8D#C=u^N7@B0_x$JTihZ23uHn(97M8tc|O)500^^%zf zi;pc>hkDqco}$Uhg}U|kLy77A(8ew>eCo`j_!(2gHHUw%28n@4PL^vfOd8kx%?~XO zW5A&j7tl}PtkMq#4#$4jm2u5hnH-a!*#R2eskr7Bb5_;p(HK5y$N3f*pS2BQ52^9F zzwut|1$fxtA2rTD;YadM@{uXyn#rG7T(;vaugjYi$ULa}F?I^+f;t^^YUAoEuGuTv zV?tar@V_J;fsK6{eM3 zq!W${coRSH^=d)4ezft4gSvddjtZq=ZXZ$#yaf@7;!+GjUW5MAF zoLPoo+#x&ytAEA*2pHgilEnxd+v&=CuhYfbm!%TA{arL)OL5Mb;GwW}*WlqDSm9uU zBf7omnm%1SlJx54F@?W@+GLte@KI)$k3EAZC=C7fiuT;+*xuMdSir|~$*G>3qn;ao zK#kYTk0WP=kEY&7cmAU?QoT>DZKvBi`(d}ely1-9t@b>k)nC@RWU@|{{^Q&U*$h52`q`{Jb7Or@K5wnhci(s$*vNqmm$XItc%8|z!;^Va${ zeDc|Le#f&N_>4ZLVCa%(ZmjQ?&s*zz@yTaX{ElY_@!74P9g=5mtRI%oTkA*g$!ACT z9nYrmnbFUV%QH9DXY}8)_$=aYd@hgs$m8n1i2J0z55j_J$35pKED0w!)<@*?R>_fJ zU$P|-Z7?@xR6omn7~-ZyKii5=KHJ9cc(xs%!6)>1<(ZZB-L%_!gIu2&P)|_BrTB$S z^UEN=5GH;Z;+GdV7@Jo~alI53U z^p_mJyd=Z}E0SLx&|lyQudDyQ{(|uHy80gZqS9yjN`V8?{#emE#)+!&rfPMx3->Ah zB2UpKr!3;dxE*au=;cxI2QGo6p*@rJ#3bufZhZYtgQ!@R~8eZ^+qo zkSgc$hEO0as0&=zt-lhDG&&0u*K?|4;%kL{1E>d+k`>nR%QKe7yLIfI8^0~_iz+&F{IB3QCJqSNPO0fB0jy7 zAGY|7@cV3h*M7ug^}5T>V;{>Fz)50h7F`?C_gvmUp7!>5;|ba1 zz~$4_Va`l(eJZ62ZpT0)^EP(9=Q3EJH5A+)>7NzwtMA=~ZYI`;iyBwR>q2+Vta=I5 zi`%RXW;1{8ywz|XuTvO8F#VVRC1w`{0-1XipSbn8g+Dlz3Rl1xGcMOg0ds8L&7>rp zKZ~PoVZ=6WeY&ad*K!E%W9ksxMo5=?a4>EY%53-iInvm7$DDL?--Au?D%)A)rh|v! z;vC#->bucU{-k4OA}(|%LU&E5f8*BY?gx34*XIsxVaSPn5Du9-t}$) zGw%9&)jI_5$Yk(73t6YRM&RA|-w$uwUnart=@syv|NGs6U)qA0y}%Y@Q1gqvOe}*O zZQ||PU#+|P4VW1kq4=9MLJ!1mAZ+|=4(h|OpOqu8OL8E&^>HmBaON{uy2+6dO;V(B z>*GyxaklkcXqf7*dq}u?ch>_CU@E8(u$&>8l#B`uEI?*d-x)}UeKj?(V;F$fb;DS^#SqhlSqa>XfJH)J?%6j12L>qPE&w-52 zw`-taz!lwmoVvmP6zOg}P}_0CV#i$s3dR(ScD)3ilR6B0BBf?OwEvn$QyV-D2YwvK z(_(2GQgLD`-l+G(KUg6`gUZ|dpw^SSvOajCK(U}ASD?bC`p2Nn^8h|l#9w?1g-5&- z;mtt4NA6Vk2p*!)LjC6G>j)E1p|4@Vz)>{?Vz) z)TpQvel{Hj@MbQBV_A5U=d_Vua>;>~P;#IH^{t;>9;;&Og<77)FvQlw8Sb$6LQH=- zjun?@CVTD(Zrh0U*iC92Zk=$B1Nsfwo>a{&;kpHpm%Yc>x!58+NB;KYRxDZ5zE|2ciUV&7H)%f)a40JUV_7xF)0!vo_ORF*CSH$p%S-&EV&p194_)Oq4iO(cH zTkzR}&sKc4;lQiwP0s0Ilpnq&o-{^(ghoGUa2x0^QJOa4>c2f;{ff!> z`j=QwmihpNUKB1jEdvPE^54-i6Q(plv~j>+K+6EXV#!6<~PtWwkUOYb zx#U3QY&Z5jAkOv+Rh(^Rca%BX*p_=veLMYZINRqq&h~8wYiApIs;;ZeAShjJU{DoW zkEUKE=4&am4#tIu=v$niH1sa{2Y2uzuE4ZOUJiX2iBY#<4~QWULWq7u4gPm1_(F+R zX-m|tAJ9Jdgnlrefhd4i&6oS%A@8&+>`X=gocH7}iS`oZ$_lw?6sA65-CN3d9AXto z65@U`I~Nm&MIs!Aj`aN(l3Ta+Jb^t(OO|+4fj|%YWg#L0=lIh zNCR(%Uslz8-eT|-r;}sQ$yDcc?C$dx-@n=DyUF6WW#@J5O#F5PNcPhg$6s#o?H7-Y z18o!Kf3zh3SF7-E8qe)O`1i-1mI_2|TsA&y_n)^I_?e>Te^)&Bg8i$-b0?m+*cG5v zJw-hCa!3^Ty$wEb)&yBm@XI~ETP?J)_wpQ|tizenEw z_rjZ=4Bp2f|6KgOc<1hb_dh?r8UPV8i7Z8vW{@V$5Z#(#6WbY~XHHL`o62@LIdEC1 zX<%NYY3`P~tB;0yk_FNG5yw^bjNJUS=gGR{+(+sL_QwNkZM+RrL1Ns+@zsV+n8Z?i zb!ad2@*f{x9TANC;^N;EUwvqc)qj=o)$toj_7B&|X|wSP;ver}C#v{r1Ac*>I68VD zWQ4?5aqi-xec`4YyaVyoW3zNlRcJ%zkq3IN3e(}}T8KhDq!*7!F z(I2&iEhFB&t0lgg{*l7RtBS9_NkStpOs~88O;A@b;dWDeb!2Z0100LmoYms1#UE-r z0P2&MvB!5lzWQ`UeD%89C|BpJZmhot|=k$pyrZ9g~#TCExm%}kI z#uXoc9&)`NdzKYVrQz|akg4coGK@hXW@njizPFa}=Y&12`c&9^U&aV)HH?edlHoOE&VmE8=H>3mHU+ zpEYjvuyk2>W`EN-18C7!h?6PKQH+5$!1>K87?}XHh3{0+=b)QBtbxk-*&&b?jGv9@ z_x$2#+;eB+XLlI5X_0VaIz38A#8cQ8V?V__XiOJP)U*|=22d5Xi| zR(Pd|b5l#0zpU*>6<^#B9)dYfG20#@k~XQO_s%>|^umm>#E4W#n7RGfR^6^?ll?PB zhIumQDSiawD2|{da8%Xv6hpcl7oXA&<~?{2<;p@FO2R5zYabNA

(Qm17PuBoi_*6I>HV*_13pgPg@XlI< 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 (suwppo<&+jUvXlt= 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

$75ZoN$M>uh5!Y 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 z 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 Mwf=$o6qIawQ2{U0Z zaFFLT9OOHH%PQOeDGJTDIg5-iCmH||MVDMrdn7)Ccn}gE*XNnn)=XjnZnX->Z z^Oc}yBAODqq>s;ypC@dV6&z9NG#`w!NU;BqUh$D%56CMzmjY*4?&09!nxM<#4pd}0bh}NTi?%> zZ)f<+;mc((&y9$rpg&>P&H1K=zSJhXOg{@!P>w!>pH9`2Y4TKg>&}rU1%=BGhkb}+ zxDQVIBRR`RlXdioJo>#CbO)f)k zx18>X9;+o78G7tDCEKOPnveD#Q<@(0VNB-o8qXN?*eN&f96eSH$UXGfZ71v`Jr)I; z)Ad-w=&`Q#HkSr~m+jJHF%DpR^;k%Yh3K(-0oB%sDSC_`TQ9F0tsX1+Y*sy1y{q(C z0)4vuy)=1R0Vjoe#av$eHyU|Le;?}9*N3jt_1Gn!AFCd#MJp~nCMf^rLpFzq9;?~u zdh8`Z$Xdw|L7p{ehu zx1hbTAfThb*WRwiW&Cp55&kg?)(VFK<70ke!E_8I+BZ$~ECMBNOg0-q>RcSIgX3hm z=VuH#J$M~F-d3{LQARxhv%j2A_p?G9RrbpE)%nDTyE>25d5I6K-1se=dbp4pMrzw&JEDxh)&A;}VSR3U*}Rf4~2B#%phD&g!%H5i9xXh`-% zAbUrZ(V(y0HH$xTn*q!V$Ub?PlBVOUQj|Jkt5u9XlrOZbEDFiKn`~5-pQ%>NUZ^Aw z8$c-vop^kD8IUubQ@HsKFFlN3dXYoje4VCS_0JTYHXS^iGJXuV1gLI(8Q$&|%$ZzF z8R?KrOZ)L+0Ve5mMN-lg{{VrRH}dKBp2$-Pcf(g`PoqrGRRcMwMQ*Vk`ltct<^^$X zUI2eQLNkOvgr3ajca#Ia$c+J!A<2ks5I*8TcR1K?O=TVqp~IPXn1kV(oLZizSHpZ6 z{;#dfTMty27|6eJ6Gsr9#{61!88#eQRn&tKS9E>>ece#hi_bVZuQI$s9eJu3@bCy! zc`Tf)#2a0BinsW*p6m(X4We!uCV*}zisDmc_?Ds={*MRW9|zU-5ZGi@Q8#XMd_2^; zbuWM0m4L*5Pk|Z>HKLvhGCNSDPX)zl!Mb`Ls2g^Kyx&pD4G$k>)9q*)5)ijDqTxBz zm@#XJJMzugF!OYo)T+s=2p@?1!BFQ{AU>;#n&mxCU_rNqI&P60m1ww$`w}$pyuy0x zKADig{>?vCeDdT;JwgH(T|vt#pngt$sN?t2X2%~0Qe{UQ(N)>e$+7FR5kcGerJyfp z-U$9uG;R{+5E^s-io`{8Ad8T+5lRt|fMEh$ONBR?EX9G4c%i8x{A}6sm({G+7B#E2 z2eT~tpuN*^%HzD#F(L0HuvU=`v8FjVJ{Y6-vLaP%38u6OWLe#$t*`Dc%Ih6#Af~FslXh z0gsq=0Q%Ti0nvvSkkXVnH$3rVD7=+;#C|0>lJYs6n=bQPZ(?%G#RI>`mSVvkMgNU^ z*8?6$Pl9ylP1GQP1_+rz%jv}>pnNf)t;HW`tSAqvA_J=_4>~K#17byani$;8!m8H6 zfGc(SE#6*23lYVn4J0BV$1t1CFu!vh(r4H;rVO)ikeVJ0!iaLH<1~0DI2jMD4LjqD zPZv9*=H_s44B7!Vf)P86b|}XXs)}j(FR*h+0k(*oW8_4>U4=hPyoMWrcBr*5R2<&G zfRdJvkf<`i5Z4LmH@vX?;OJvBq5}L^ZHegr>biF0kfh*sXqZK zC(1a1(dydA=OGNP3g`c=_z{+}RCP?I;u&fvR$&dy)Ok8b!{eY5RWwmm;VDc;7S
  • &S1VQBPlRfE-bHZ#h|t0sP=#&!Lk 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
    XVq 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 z�Prm=eDO-!ZBKIL+>}Y(E+-1}ng#UP3QZ zU|dIq{R@2am=i;xn-ZbB5Q(IwMc4O54vDFd63juHn^_VIx-mO}6{6~nnT50rnP(Sb z7YVW9!RJ-Rs6;<2x$Umymi%_1+(KQqq6K?gm7TS_8`S4~6OGa|)1fA>{3Ay2-4 zk~jZ?aa0MpZjzVooswJ+pj?~L1h-t9m0TgWK|U!Zw~loHfgvL^jH5V~F@4Fln|wO# zS;onivpX{1agR$wUFv>unrm8_tDSki37cel=T+vdbfH9G>vnqL0Kq9}K>Kg;bIRjx z%m^59o~Xn%rYX&8kzTv({=04pleOmyY){K~-R&v7hxi;+TvQ)8HA^9u7mTxI-Q1>> zJ3YfD52vk|k?)y|ulI?Z^ZEJ!`YNM|uy6SBz`Ysys<|>02;E+6T4V`&Xg-slLv!w% z*pS+JUlm3JaxA1B$JdQ~WV*@sH17QQ2Ic;AKVj&eZ|PDu`Tu=2<7OQFRmdy1R2rFu z+V4~KS0YGUR#7*?W8h&{X=ed;Xt^A*^X7->SZg)4oIKtAtM54yMUC!$ho%p9bz_9i zOeuxTeoB5u#XoNP)CUu9oPmlgve4_~l)_bMI!^JawMb0T$z4BLm=?M;<23!X%;-o& zR~>KG^?L2klK9KyOI{~4(7*TqLAm&RpEvLvemSh^ZN#7auwU2?uy6KWh1T7IAE+Yi zpP_D1=<~1~cX4IHB!R~`2CDCEsJsWu58t!uXi=n$G!8rYxB^-2;v0HUm%8 zVs)V_er(GxDeuYn1v;k16LDt$#fqm13_5cT1~AvWp!{ylr}O)V?UMYUjU(Il<$kle zkqVSR-4)LBSkg+g8~On)mg#A~kTulxXJ`dIGpH(g@h%m9d~qQ9!;1p<%I(*3GnEB` zQ-|{{W#S+Lfg*-t&I7l^C{+ZH~P)TLW9oFo-YdwN43hy{7K@I ziZAlQkB8pfIIL9;i(}$_`hBlBQShYaEleHMjhur@oP&|A(D{hADVF;p%RL7j)8)MC zA)i`rLu-D>KLA%%KPikydC!K#mJH%*WtR=0deaYTM;yZVMj#o2^iH)Tr~zR}7KG^xP;L8dcn~x(7l&uj zIS;qL#2+V|=$s7_4hJWmRr<3*Rqs)MXzl*6Z7FuA|9TO~OXa02&=Sfk@zX+ig}UxV zC2D=LgvI7`eV89oG23#-?c)a<#9aarGn)i2b|$2`>GFguuZ@3<>d$@vVH{75^)_?~A8o zD11k;+)Ip`a`mJyBMTxDCg3?moF*hy&$el@BSFOs9xmW42oXFFfQvD@3r+8KUWl{ySl5$(UsX#!v^ zOPQ9^hFA6%P&6`$0qV2c( z&SE{f6wkE%GR13q0sh&eA7HV_1N1!I`2zZ2Ygzlef<8#J|0>tsTpy@w@Qhg8`qTP8 z=>yx3a7>WG5!m$Bl~{dr^zcpS*VUYXN)OLOtF_rrUWYFEq1>Aifw~V?FQTPl)O=oP ze(Av};z6j3=dlA5sthKGzx2nO_I_iZQ^JFw?#G&66!+sDQ1*NUUI~;{{Uuk(V=v&G z@ztNE{vK2y6}>{u_7AZ;PZ?N9j+&fcSE#t&cuLkp{hNWez2Z!_?^f&K*}%N@;Dzh9!`Pw5J`_A# zdn$u!^&x$;-`T9|yTkRI{Yzb!e%9+cO%|{Cvj@Z`5K;FvG&;?t8eqjq^ z1+~SV%MRmaKgcBdy7WBynYLeBU3HGy*S06j_ME!6U!KJ73y}7x-Mjiy7#_I9o*%B# z-23hafP7`%@Jqy;=x`q9I6s(Wd6A*hy)(#*$bo&xkCB60kJNc91K4e8Kdy(V7zcC&<5Gp>DthGp*dF)Q<5<+wtkCwLYjB6%U|qC-YE+Cxb&#NE~~atkCggzLS5{#NwYhtUCO%VwB|#vYj#38 zUc@dB6JBCuq@*0#nG&-{!4snd(QkKVT4dR*nWNt*q(}Sg13NBx(#-k{-c5$%D?uQg zx!33gPK~%+9e95XaNCXJX9h*SYec$vcACR+)1Gvzt3AMSm9&SFD5IT#)CJ31Y{NWp zycKL|eGel67iPn*)AQ1W{)BQ!@O?Sg9>Za^ynD#Vf&GFtk@i!R*WnpkAd;#XHL^gi z%$}{1a*hD*YkA073n%U&^61nZ;?g&JDBrk|N2=Q;4-VsG5`%)N$m{XHKrl=|47X~* zEQxn&jtzabb49|+1^dJj9QkvoP3=bX zid} z1T-l8$UeGxe(h#CcvSKtaw?MR2IkQSHQHhv#PFB9#>Y1+=qTjr-I4`}C`=C$#2e=BLod zW2g)C@}a*3Q;+x{K*x zoWsr;mnSBx-?0Jd&pwNdG1^<|eLix4jGH}d_7a>n$M|DFmvj4HjThM=LXhCAnZPcT zS4YIOvqjT!`zu4I26XH>Y0SFA#$aDgx^Y$@qRV;VB6Sw{n~#g#k5bsBaItyJg^O!Z z2iuu=ufKc-A1c=423@Y(ubj~@jf>+RG=iWJ)#VHAPt4A&CoICnIGRuz7c={L+coLt z3HE{6X~KYrJlpzwUl`7Q|pGSJclrJ-JFxWFt~v z5^tUC{b@^OJTRc@oSNUelzuM>%gv1k0)Fi=d`(+=B*y|t)H9jSYmu?QaOWddmP_LO z@9~kBp%4Feg^uTIpP(+e{a>i7U5_uCC!+)ZcZjCbUqpxV9~>8?6Z%jV;2W-lLp z(Z4MoHoO2Q*0FzwbU9D|M@X8Y|7+89JpCW&c=|t_s#dMbdEq2=&f?_J8Yc&n6m}_` zZ2P?nCoe%AZ0Go%{_+|4gNOd>a(#Z~j2>v59P^-&sht&Q*5!-rryyT4-{9nI_V)mq z;ER(SQ<=fPLBDE|3bP=gE}|m`%`u2CkPP~?TjOAwHF@Bm86WqRC{G+*QR+Exu(`x@ zFC45Y@xH~uv&0RJ#l1u6zgvVsf~6=eF{t8x3#{Je3cevq3oCr|A@p zn_yQJC{T!-Zy&Gpt;MJQ!uY>M(U=+z{^wyuIGEktr+?`n-((LYj$-1ygF^CHcY(Er+?98}#I>T+H<8F^OZ>e?vf zpJ$F}I$k*054OE*2z_)nKBl(WXg zrJP9$nz=|Bej}C)t@$NG89mdM1ywgrK99rL;!!_-7=L*5`A<-Y`WE)#rw}Lm6^*Ik zd#tT&I>1_grq6Pli97R9bPy& z2DZI$vKc%K>2hB2#<<_;auL6BMh`Vk z)_Txb0UD_-{{8D8Pe%Si$(O>(f_QS^ZuSFr^Wcn?iem8of^N(YS#?)}~ANv>KWK7pn)W5c#98NZ)fm0oK zS4~FOg_8-=^})&1zkK@N@aMwG3Q^*`@w>&zK24{ve?4)sMOlLzCu=lLHu>>`{!GCZ z3iBwx{J84R3SG_%C))@~Q^d*fe=2!+;baDEd*Ng?c!=wAUN~8&aB@J-Gddlb0H>I4 z{X09Q7$?``xthlbJ1(4j^kb@>)w&+D?%%Gff_$Pci+r$VkbM-vx{3lvXMvd#v$sAmRh zRl`%SP&5iG-$aLUzM#gBf36EcjM2@SEKYLSn7W3<aPh16;&#GKS>M3iVU1Is&Hfo0P~K45mEhRo|e za$p?d(f12bhIl!o%N6nkUCUd)l~FXRsp9I|I=Szf>$j+oS=b@(!KNOhoqK2H@DhE` zdYb(B<2_EfamyOn+s%GQ8}l&}>Mv`!ayp>Si&FW)%xgaFH|+p!UZms83~7rknPs@S z`I>>r=m0n0uk)2nqR+HRLnpUirA5;zlB?Q(ZP)IseTq3t93Kj+>QnY%Oz9d7$DC{%yxWZpiH*j*uD8QV>$i%5IdjHt?3o{JuHl^ z20g)1$`*$Y&}zv|O&ji*W0R02;2N|Yy_c9(h%JZ&xU+zU@@O1y9JG%3Q?c=|OQH;MRHmn)RB z8&8Q8MR*F3EyUCQOg^60poadx`^b^@hW8P#!02iFgue=BI?7P*T6MWXz6$ZQR?(Om zo?g0l5uOJ8_>=hF>Y2sUB5Ho{WwQPy37L5t3_HC{o%e<`GJ%#rV;rg+GslWe~zvBJa)Zf4CWxU@! z_4mK<54<0q`un5L;r*mD<@SEzX}sUB-*>N9<9GNa+285CUhT`9ckGa}rsB=IJjY9h z2ENLAyLS*n<6h=*{Ao|q+KNATH**bgYE96e#-3kR*5W&V<7w?N{acg%jWN%l{*CKa z_+BgiP3hlwHYtBwfq%nqs+D{(u8Zrg)qlnLS6`d{tDk=j^y$Bb_*bG;ukst{zBl=O-p_#Ep2?Y_2y*&5lO%zfCIy!*qPT7q<6V}xH&x3NWTU7hSxz9ImzxW$D7G>#Tg(fQd#ioAW zliGia<8lnMh5OJWyGB>-hjq~{yhp0aP1oQJ`-mU2kFQt`!EFU{DCD==O?T@3RV8#) ze-+->RHI4m%>7}}LOu)IU+d=r_|{NG1fEn_78ZrztCQrb^B+{pl#%2YcMye@54GyKj%AqX2fBh zFVW9UIr?>e$5|F~U)FW{x$*au9lx9Vr0#K*XF2L4KZgE`9?#wM_ugCa@22lA|7rc) z&7b@Ed9LTCemDIt*K^Z0H~&9%J*R9~mj9xC)6vWEKe(Qo^11rslkK|>t%;Es28ZFd z5zOS>$L%_=Sa#9yR*^m6dzpL}TM)?Q!6DPs11hqDp6Yd+ayLe$nG9I1xr?~6z z!}er^S`>9&e0U}X0#?tMPvghN|7Gn<(56~*7v+5j$}zKiDlRZR^L=QS95gf5b~h{; zBMh2el1)m9D~qqXP@0QY$~jTo4BuWk#)D@a&Q8<#ogW=AOC52jcKAh{!^a`l68_Sj z7bgBPvjPpz`JtZeJihle=TFFaxYyCQX^HyLg*?@H<$FV;m^A9!PI=~yV$TD-5^J+3KhKOHi(xcM8%4>CLxGF)b5m{!7Suzp|89}bLx4GIk> zdvgyYhKCEo&T<@OD5Gnf>bmVQ=|7_%w*N3LsE{UboP#M8+14KFQunSei5I=k{3*{9 z>bxK0#K&>e9x8O+fE0&UXwiuuXIuH1{2Z$rZu8xLFuteWhy3d6A@+S{$DxYqROlY< zPxnnj_m*9t`$C^DzX$K7`8|FY=w9tl_gF*srPp>|4xjX=yU@_Rb{FVAeXFk=<{G-6 z*#)|5{OO)%=sue?h_pLSj(5Oli0(GKPf(p{+juShMu=zLv4O<_-I&vBG_G71-yu0fK4M!JLM>z<0Ih1$4D3q z)Z7Y6zwVjMWzQ zBclBJo?|Ofd@M7~^kYxsctg+pBy=DJ6vfG(_m4TB|G4c}a_ThRM>L%m2n;^0Z60DFihtiJGgN|3Y6BXq4o?kzQwg zrrxmTgTEEV!IYtm1NKmUE0vrMed*bV@D`rG1D;>bSrN~Fg!TMUlysa8@UugkRXg41 ziwIrg57sY)Kd|SnUV`>VO)PLHx&eM{B`)PY(fYAOEdpLH{dKQ7~b9P&!`M{6z@x_m0)(L)8==TflR>v<(i|``_ zK0NVb17??Ud?fy;2|zhB6Q+djPUqZ=J$)fxhs-kJKMjy z4w4hr33NFMXSe^+ndPGZ;SF=*vDg8-3~4 z?|bp->hERe4fpG6j6j*2Hw&66Y$dl^kNU;Va`yW$4!l1oaK+t}H+p;@j;x_b188av z2s<8A>p*B*^l|26@{ihXLu=&j80d8MKB~Cu4sxCwZTgRR$&VYWPGi^zRofru&vwkj z6U3%w$~?@)H0n%viF}mGEnpZWStHRlb?&yw8fkAJu({o9zKQ6I8I9pK00Cy&w3 zP29nE_^`C{;$DlpxT*a{i=nV?aRkUYR z2L5FZ&aD+*-SnV&fea)_QYycbe_y?*c}mGo7G0`HyBZE!_JOM<+gAtb8Rm#xxdBF~kzC0zunz`NEb{FF9wM$X4F^OQh5C?_7zQ{hO1tGqmRW zV47`RF{?3shol z+LapvRrqK0#l50s8>79Q#0QCkRDB$OqCVn>yFLw541k>RU(EE>pCCk1THc|qHznK~ zPH36i{5|N($K^j5uZ7m=bKkRV`zd*A8{S{b*_1Q=4mlgU4Xx|NQ^Qc`?uKRvc#8=5 z{cLbH7{uu}J<3U#6KL^<$hE{9J2pa`prypwdz-g7HFXv680uPz0y|gV2^TbG{SIffY=jTep)Ij}{Fw0!6GcW* zm&@hEuKa66>(=^Hk%?VY5#8}f=lDMWiu#QGqGXT$- zPwTJT&bLCH@4+8Kd>y0b&@~^$x9BiS;Zqy!8I2yY8AF^<*GxWm5O;QdfEd3qy6HuX z29PqD&oD9Vgd1lTozIU4SriFYABZC86am${L08-92B{<$7r9}lRmNAxk;ThDu%ze2 zFuNu@xV8m0LA;+=xdmKI^aG6oT+}`q9o@25^vY4H$&#K^!yn#(7ULmI8l`7>mUb?H zKD*uCjX$0l7@}mI3{*W{SHK_Fz09BeFTfrSh>*#Cf>8?uGF*KdAYREL<5d0}>d<0) zE)d(`-!Bw=Lr>qg!|n$L;iYgCu_vOC?c$`Ahx#AtT|A9Tkf zp)U4ko)2b6w#rNF!Vb8;^Vmaa=L`SiJ>D?(x%}5I6M;X@Q(j|vg?=4fi993bzwI3L zV@w2~`@TOMvtq(}=20alEp~~QDIahfs3Nzx*v)wy0@3qeHTr!oxv-q`qP*)les(TE zKWjS4gsPWzOLwWy=67QAcS76h7#ZtE5X_PmX@&ilR5IyAKXx9^=t`zp+$ZBhW?MGX1aB@2~Gc5B@RQdl>*w?w{+tzuH*?M$h6>fZkIv?i!!{L<2tA*N@=z7_-`5>u6IbDPg2Vss!MB$xd z;9M{-+IO##AN@DwN7?bivtqRTWPEup)o$=$aWuQh3KyKota2{Qx7z$)lcvXh;K#Nf zdXQGdIo=LKhGAWfJjE+?xizX-t{n76_WV%?;isJ=lwPDpCgFSiqTQSmfDyW1x-siQ z(q^4ozb?<;sDu2l?R(+>y4}hyH{mJ3Ef<9R3O_)RrqP(js-P!y@8dM4WVHAEGJq?8 zP?1I}T1@Z$2!F~5kVPWurwJ4LZVTNtqefsl38BdpVg?l&s|~ID3Vz1@NbR^T3c-tY zphAso8$z=5t@FMVdMX<|1i;q)V~JfQfb<*JK&EuK@uA-;d7A!bzwx_3IRMl70%S>y z7Q}uyI=U5zy+IKB#GVBwg|B>GKpQUrwd;GE%9hmiG@OMiof75I&IhMCa`$QP+2x_T z_QUvlL#(0qKgv!*%Y*fuqp|wY=Xb9!+XV6v)-wA1jE1s@IHm#%mtVc)#GZze!u2~6 zLg+Dq>aOxp?p(*>y=RvhK0vBg)wz3=9H=^Pch_0&oV)9F?s(8SP)aMp_v8rUN%^kR z?R;>$vyuDMde5F_+5(xD7s=G!*3lOr*oV>Nuxj$GT$4k+%kW!{JJRPqI9I3yy~?yg zudJ`E`Ci_#EIdzDRPydx?sR}{!nEKcHYaXy4x`;vJ2*GgaA^XEC71-`6rtblF8F3x)xK&~@K+bNe8Lku%HXKNoA9l-u@ggdm*rywm*NP{8ks4||BV<96Zq zAI1D$2QlpezxQob{C3~7v+^zEx8frn{NDdfsEkp7+5(Y|OiiSRfW>%vXlMDmSlKI3MoE+ZT@2aU1v~S|c(UyW9g^@$(T4~+w*c$y3?RfYe|BQ_juDcU z^(gcV??6ej&b3>trB&nUaK9ao;4k?QkNMF%rE!Mg=*xFagAU7UggV8{S$}S@_-8q~F?1`Yp7E0~DQUTmFUm-m}V(QEQUnN22dA zx2I+q>d>Mg!Ow~c~_3(z_%GeESL5A=^$#h zLw@?7^e~yrC9NVTHaw(_a_Hwu9?V*ip80Sdg?}6T_#E*g@o~C(j0cfvdw>pYBBq_K z07%={7@4V$7k)e`Xd(EBVUpc{#yb;bB6Q3GMXj&D`F}W3fD_$EdYa(B&EG}6>F;)1W=#xhcXBh+n0HrTAzAGo`w-90Kj_k&z75fQ&7L}<>#5harOiGw&1aopJi9z57KQkiM&GEK4}gOxrgQUvgyV;I+cyslC(H zGrov~C0|M474!V8GaKe?=s0NN5S{Nrjs-c6xwy}Jw7h=K_>!Kw?d`k$Ys0jTm+E`l z-l^}weJl?}=e)jbk$%5!eR+N7hUv)01m}hBN`~(G(~|i;=Va@8HX@O8&epooiSTH; zVoBYVFYXBN$=mgFUdNNV?Mv^E_KZj08jqG`qN8afdlF?}aWvYy-x}20{$3A8IwlsK zzfrV3*S@;5>&~iMShrx|*=L;@U0>d~zM^6MC6%r9J&!i@?pMd8W?SQ&&2{U~3#<<| z^dv)9T?w&7dq4jBKkknK>jR@N?moZgIpjnZe=tzj z`L`41?YV7k?=|lyB82X0*qiTnZN~dp^nl`_t6swQ9!%Q3L0OEZ_geDt+A6ei?%O@d zC76|1^6@|=|J)8|S3l>q`R~@AQHXie2`@oHEx=zO=xtKx zvc2loPy1mEpY{!Pp}XEQ4_u;|I1@;k^5ixo#Z0>n+1T|^`+<;C=aw0vwPzu-gEl$! z_}A1Ak_WIA($w=#hLzlj}`(n;$wC6E)Lqks@bX5#8iuNA2=qU>RoVRB`^jjtQ z_En9&EtGnoPQ-pc#6EqGy3W6zFn`YpNWDyPHzP!$-v=UfM(X4EV_r|Pu_sk1cKn(r z_lBNSq_KC(i`jNB#Y&nn3{Z(R=$Cpe1mm86Ks&kcSfi#Ctv(w<@!z=t_px?t%XOAzuou{TRMB%z1d((V@G`8+zxKFX_y#4qf#}NOH+>JN8&! z-Ls)Hbppg$zGU>}-8;u(oewAKy65hw>po+9L(c}3T>3ym&rGqy7zzb?2Lo6txa7+1 zJEnd4sGbcdISnOebUvIyk#~feq4dHDq}2IvOcQf>hsnIq-E+%7&U~=+VQMef{q(uL zQ1(jnbWfsgG(D@Xb1XBzd+yun&lz>#5I@E6(>wTye~qTet2`jH>fv^0UsO=nT@J=U zyv%u?i9?X=2HI>0){mx-$RmE*?)(C8FNyy!fTNgEqT?fYhee`Y zNjxq?Rvkhjv(8WXqOlKFgkQ^@Tk$JsM)1e(_;DKPI&1J_9(>1#e$Plbw`O&^`~^#q z{pIoa*d)&}$rJHdD_Z3|i4hOR@y4&9+i6DulP5tOuHu>v_z^xh-7<%<4EG9iVLVRO zdIKX2gyuM4t5cT7cU0QZPZP>G=Uxk67+-_0{J7%tCbQpYlO6Z0KNGsRNX8RG1FtiP zK@i7~Z;V5qaST#0WyP(?Os|+1(tIHkEqk5sWTS__p(ZTaEAL?l^1RG0a%SiK&te+d zte0!~e!f3toB3f(b1?pI$9+fO3ESO#jBdATFfx3m!J)3h@Q$9huF!N(Br$y0Udk4J z-?TTh?oRxGK^v3EnD{*N;OLx(S6zrrR~Y=Qw42Jc0I;2kXC6QRTycVyx*IR2BCKNL zWd;b1e^_!MXt!>>tUif2AN(^@>GLXwg6KY%RD0)D{u-=-`sTW!Um$k4_j>$iWDWkK zPL{&#EM@mA=z|V$q*J@DnHd-v415)|)b?e*H1sDU;Mzd&drH30F8NRnB3EfP_Of?9 zbj1i`x~8KcS1hywqq4>d+f5MR$#Q@(Sb@nyhB1OAq4|2S*#BKcpT9A7G#`#1SL6R^ zlwGEz*1!f(Q6pB(HDYc5R_7+Xs2ju(ez=7#?&-k%Yex!`3z&b!{tcznNh(d>CS`xR zda)7KY3z?Yu&t)Oc0WHBqN8n2`_r5btrfc>jiUE@=O<(y`DmqYsqy1P-}Z(*@Pbs;4bU^63@5qk}YdGSM_BBu9$41prgwuu-C5ag7{Q_(Wa)jx&qs&#trK~0^n zfZ$_XZ_$GtnRqY5$>eCy1G5w9OSa6y3z$SE`Rtn{54}~Z%F!W?BLA2Wi*8oRnoi<9 z@LnYbP6Gf3Y9SA=fUnI@EjX|B81^h7ueEV1Bhn9YU7}0jT^qIj%JB^*g#tNg)rvFX9(G&(%aiD;? z{}%GhU#Exi)W#+8jcgP?w!EyPz&`)=3jryM4#qy7=;*68wcWGTx9ZyN%Mfeu$0~d+ zS6?IeI!%48z}M;OYZzalb9^_5ue*1jgEJJLYUsTT>~Jw##5oPtsNzmy8}%8=C?Db{ zKNdebls>0pCx~o7R~&{5KRdXeqEH^tha6rWLK>1ATNDx$YhzCWJgFE7Zc!ujD8Bsi zDrlR{D;-EtX5#1|)Bl;_6o@)^KVc`}C36$cvFXQO-n`rhXVT1OKe6@batxmJqj&w%U zMq=Al>L@u_8e;#)MQs@tyaFW(Ixi!}(U>0r!QuWK_z|IXy&M%7UBXwXmrFBYKeBK8 zOJF?P9mQ%nA}R=HoeO_wb%fgJ%vp{2GOFp320um)Zu5JX{Ab2$sP>G7vE3;JrtGvg z1Uo#ax%3_He;xW=Fy3c>^G~S_x$Pja^L|C zypy1t<@ic&KvsBv-eqp4tY&++=vm%{aX zK2SgUVnySgZ`6;z5NX`=X{-vYYTR>E{b;JXanG^n=-+A@_I!}TlH3TJdEusIdhFR1u|bN$%>nmzVbH>3H&O0gW;Lc zo6wpvND`fIgcn-(S3Irn%mzc(FinRH?eycLy%&_>%Yg?)u`&-|X6(b|dib*6`x<)B zo_@0Wa=~u+a^OJ?7|+!<^e#tFwnJvfEZ0(=pNaM^hxAradaEjH@ylne^dPoi{ht4V z*uqL|klxc#NUvefC$NgLD!S(;?8mE)?)gY`G*uJbGfCm(OE0RW$0P-XiTu41VSR6H zfe0IV9&tJzwYEXM8csl+OAX6~)hx`b5&fU5nd8bdC!;g=yhslFpD)aD)QxNs1H%3B zfO0B#)_EAQbUdCMRpWi5&-9P{ZuTSNt9&LuFYR*;zUOX5_R;5$jeOsnk0rq${u8@V z=?T?_^%_2Cr^1KE7w&t`RyV2z@WTIIaBt>XUQTZ-oE2vAA7htv3j^Wyr`$X388@1b zeGj;s0`dcQ_h1b1po$^lUhf6L2H$xEeT~0r-Nx;xkTM!N&AkRG)b%8O2cH}94?niO zW*mLYse5$b1P~zgjc_?%xS-Di3t)_sBaxtXIF6jkBrDCaRqq zS!elzvcma5DTMz_uD{=@_toDPqrcm~Q>eeef_88mqxH7LxhN0d6-H}I;)%Gw{%f36 zsFyov80L#TWL63UbU-xc6xsf&akC}Y` z&@khB+70Dp^uYRO?sIu-o}HiXyUyRvR-?Q-{`n}|mF`Eo6g1N6`p`0Cbq*V|#kuTc zYjhD%7;dpfXTS;nwz%pwJmO`yA5(F}6?h7{WQNY5{UM$fn9Vrk2k9u zi64Lw?l)JG3dW;-esoYSA>|bQ{Xpj{TK(S7t2eZ^QOB-9G+)QA9X|%{R86sbnJ!<0 z^0fVrb&z4)FV^eRZt%N8)g^d+2k@oMqXUh+UHJuxS2<|RR-Gx#+7#CT0{R#@*RqS{ z!+zq&b$-$;k8x)Dnw))@Hj{5xo=WZ4|0x@Tw%06h`-zTE*f_TdFF3u+be!9# z>5>*dln3d9eUrCbj+qgkd;u(Ps0~8S4W*)gM7BzzCj>Gn4xWZ|eoys+cY=~_spe~k_DUZ@Ca zt`O((}vJwnfUUWN15IiwDIt@0>G%w)M3%E^Af=O6{T6Y!J0+Q(iB?3D>Q&`1w~ zhRkho{hBVZoFDoU{@>(Jb|RlK2F+uiBP?bz>oKA+my~9l zZ=D6jQs?bNK$}g9xay_6Ouuv9iMWsYm4CdEf1p8CXI~r`DMK&Sjl4#Sp=zpzg)}Co zo#k~F`6YYttu|_V3={%GJxYG29_okon>LSeAN@30!Q5d7X1B77(cmKk>fS9F&|dwKlKEnyPbY~Tu!-y zkMudp7xjP1R?aAkkDBqwsr};2K)0c*J0@R#IOxZfRvf0hG70F7RezJyP~r9?6G*H+ zGJ)xrMBStPnYgzYcZ%Sm%kZD(+8t-{wn0Yd7LmHev{kFuof8 zQ}AX;m)Fg4*Ov*%`-FNmZ-+Ejev}{T;@S^VvU*N^^tgGJ8nlUl~`y5&% z_PK{jq#L*7^1m&3(b@YF?SES}eRqHGJM^l>j6dvCFnjC1*E(#qob=?KwJ*j+|G7p|@Qc!2MNzbbtp5DU%=n zXV*-v-XCgA37((B6vqEUQ!M{&UA_k8CI0^cgxB*x-AGK?d&HS_a|q)_PxKaUdE znp8VD7ZmFHFF_hw{)rXB>KN#Dz?H3(gdkd2PN@edy%m;C|8F7F2#*kKKtV92cd1vBj(aGP( z-EpkedxqMG6tsk}e71;4HArHBvfm)fuYKh%8-d|XA@_m+z+*Ifi5%58xl z@ydc+!qwC!x`h_QO{26LL~C9Z2yJ33Pz+5%6Ki$7NA$&rqES==A_P{-mP;Eza4TK{ z_~PPqk5S$Qd~p$_-~a#2JacAmNecLW-*yq&gwwV(?V2 zzmO|ulO!l+(BBS7F|WVFuD|UcujX6I4$qH$H7Y2MNd@&_>K&q6Z4@BfAjrwW<<<3y z9KzVGGQ3ZJJT|x=)=i^u))(H0r`TbfLp<)~$JULSkvxkIA4hC z1^N5V?)U`uLaX-oBNcdg0d_|on#!{~(rR}EO*QO}q19#_)b3Ec*7f(B-anJS|DWeu zd!yObtM!pzh*RkCIr{sZK=O<7_lrKsOk7q@Z6HGnimL|j9Z5uJ|ImQnoGst zz6;#&ajM7q=~I`Qei0U>S={<@#hk=5w%{SaDm8x)q1g?eJ@gVxdKk(m1@C;9n?*|E zv*1_fiC2_V!%)1UsS-w>@%1GJ>zAg11Wr5;fL-%s$_6)RA@N+o;O7Pko|NzD<4Xh48}$ zfMxv2QCpsHlJ2{42 z#CT>_$(>n2rVh8bGC1ZvApWE!eqW13EZoEeFNNFF*Ex2(fYxi+DA2ct1}9e|D~8M-jQ$Pu8WgLi?j7iNDuqhcQ1HI%n_4 z2HuTsqq#_m&6UTDzVkl#I};x*=NGmo^`OkSlqvUjhU$GE%A>v5Udfb|d^6a80v3AR z_uK{f^dapCs$``+e3gXhMVZm;QOKDL>g;zrSMw9ONU9 zVKduwkC_>dW$E+`+Qp6tu790`458 zMT2Gd0eic&!t|q7yC|RZ%fCs=bALCPw_px_dcu}hdEnr7^c)+ASsp54Jg93$r#&Rj z2*43PqjUl3+WA!*ouAP$hx-3&XtmVBN~-;<*x)T?ZFO8&*4B?i4;Po$8BebtS=-L4 zdhM(&YbRT)ogv$fFW-c2D)^7vSb=bg6M`7p9JPHqI%{HEl$v@3yI3XTEdnCJ(8r7o zegzgP{K%+nUx-ZU48TA!X}V}^Z4_JrL`oo*I;l{AGBgSZQ!317EI`)c8{|+zymxdH zp;*bn6$vnbR%3Sh9Ju>fa?x)#@;HMY?mbP&v)al`vliJAdI|rwB83VoD4B3J{X-j- z6Ql6M@1(~N>A2X8i$9;Xkwoc@%UM)8vXqW{i9L&%guj@P!dAmF)PjKJ!n|G+4PMW6I-x%pTRVSFARG%2tiFxRt)J6h_U4O&UqKLLI@Pt@Mt|&@L+kou zHYi#Qp1-WpA5*%X-QRml{ra=&?_K>O>i_K_b>Yuz{ijsbU;MD4C(1JAJ@$!lB#GS-2gjF@l9#$-(drB;+F0Gf1;PUE?tF9k>HO&i-uvtr#fE@(me)?MI zfrKqT!+HksGx{F^;F+SMr(&1s5B(EfY?t?(gQ%dV)FmE0H8zCw)O;y>rABmYZ~{#z zJ*92^KD|o)HR!43V>15M;FLg?u^~NrYO(bx&p3EJdRj;LiEUHg?DPcu6+US2PyA;2 zyK>dV97mms!>}W?X;)FBJe6V-GcBN{VFiQ89z?ebMRZ$c;oT{-1+f_(7DBUnsI;tZ ze?xkESx9dN3AClPsp-#&{b=jqm|B*=osqK=kFfC>n8%>I2&56iqljPIa{f3{Rx7O! zY{2*A(-MeFq!@WK`2H(w{#Z+m@@!v4LlmDAKMlcl#`qD*H&I5Zy`SBBXz>Gin*l+z@3IgARv8Tr7byDp{e&&=_oFr(mw;53rTgsn{Dzln&(UwsYe~B;Xw<}f zYx`eIL=X}|4XZ79^CgxMd}42$;g?R-Xve`NA6i)#4<6@&iNgC09t>19;bJ7YG)}l` z`MM_xKz``YQYc7P&hbkDPLd@IISSox!722vTJ%F$Z2UI1<~IHS0ArV^s*M=iXtZ^9D6)i2kD z0Uh>x?KjO8-fR53_I%RSNsXT;W+^}0`JlP?)rZ>awS%PgR{sT5MQR2`D1LQ*RSd zSux3z`nZVzn5ihU2GXA3O(P%S=?ckdtTiEqQPkLC;X(^?ahwF6kl#-CY2gmz(4V`9 zNZqKk4tI#!qz^`7C(S9ei%0`Pz{z_gtrd=mD63-d;C1uL=TOtx^9){m`5^6=(PM02 zJFpMMm1UL$8Vi{vHpn#eGKR6;nZtbZHT%}JpW`vRe(Cw{O8dXb!tJ-?)6*&3Eo9Mf zz=(>OI61*&DYi4^eMIy635B$(JAd9*h;j(MH)M}R zc^kM#tC9SGycm3MmokB9W}+Yuhu&-O>%%8;9=k8W2fzf5^%mD^cWPYPMO03pkO?A& z49)}MJywLcL~@fEjAF3k&JG+hIl&3@Kol0P`$hCyE`Z_usFOYv*}CG0t(@(Yna>!` zOWzmExDT>}7rjviubJ?anv%;bR+cnAD>GbTl~E4T;_&@I@?Wj?PTsoWxEUM#(hYNO z(ArsSix>SoUKr;Ing9MSdS8a-&21CiYel(w)AK73oVYZJemBFBXn~x`!X=vI5_Zh^ zP9fx($3{ntt4xTA_ffD89j}%MS7PyUddbPV*uXq|g{C7BY0k#Q??(Y}|F{e_=ehXMi{z5?ooFZnYLS_-~UX z1jP%#?Yh$8H3_^XEnX!awuuCb%m02f{2pd_TNA&(#roM*<1KMBOa-Hz9LsU5H~P~F zmbyV^_7XTP2pQSGCcV7XG*{MMDjawC{x&yn8s;?Uggnd3hp)wuFX;sSl9`B8_~Pdp z`9tzx*OV{Fhx`pXar4;k2A$w!rPHu?)>&A$a_Iq}|HHudZvYP*LuSv8fPOeuIcBNA z2H?g(NCn1{VGJaf5|>n*!q;tF^&%Ihg6;wM*$$IzDz_tN$gvcq>~-9 z+Bass&jKTyi{qc9je|UWMkF#vvlqJTCH+`j2Xqq8gNc*&jJ%~1&MWTbJ0&^NQFL8H zYJF;lb$hN`xI=1v_ipP>S@+Q$7OijDyKP;xZC%R_t?SzNZ(Y}sXkFKha;*q_Kfz5o{umNMS>U;m@u3 zDc)VdJ22Zocw2%l7aCgQ?u-v~6NHzPujb@R9@HCV^{vS z>M_;FDyNk`P~MF9_gLBHw%ll1WF~a-Y0$}MVWvU$wS*07G7vHRMGQZOJqKAD8^nYI z3`(nb2v!hp-ZOGfg&hQW>g@f8IDT7u8@6&IRqm{M4g&IRO?16T6&TeG*LnsxSsQ!x zf-7hca(Ny{(kO(;Jq(=SQn`&TM8-ZXU7&pe5^JL+6dSx0Yzupa(=3(W$4!^{JqEno z-fFAyeM|Vg+Dpzp+p)&?-Qo99)GwL+YA>~%Y3NbMMR}6r!)F*D`opm`H{l16sEd(e zYe)FDY~eC?lkC4s)?VjZfC3}SAW(}gs~6ZQb$`ZAf^l8;@31c0uu3Vo0k)n$j0=yg zy?gTwBo(K}GyDPF-TYar7l{cF zqmAxAl9AuTiy?o`0U?U~$p;_!l~a{$G+2L(l}Cm45WjdKbi(#LRIc2_e&q8qN=6PB zAPyjhA^s_@cmqQdi+wk@#m4~G{0&bLY1kni1o=3C;9Oih7<#>KCuHmtZI6HX0p(A- zg-7|(l8daT6}X0ZHtmi9GfdRpVfnf7`xmE`-wSUy{nmDTeDj%=8?iNc`~Wi4*om#Z zn{UN1KX-Q`rZ@?Lu?El467ZS$92LP`)Sj4;kP+ZMk&MrH10U>sH0YKww`% z+a7ViwiGYiH-yii_}KgDwKlGx@8>xFfgAtDreC$@2_=8g#DijM3T(9B#e`yOf5Hbq z_f$k=2)C{#@;g7z?qVl44*Qg~QHqmakO&>0J?WD|vYZs2KT_w@J1kt331nI=}1lSBHLAsanHQR%PNeJ3YV4uOA>r8VI6jpfC=wwk+BUtezI~m+}_tVZTWO zo+%gnrvV9zTCapEG9%Jy%kP74RX5_+j~AQyZZ7W6BrU|SzqQ>8J5}-03m)sXs_l1W`=~03 zs>CKS^WBy}6R0Kl#T)H-cH8pX6G^yOKj{YJ>ih@MTLlJ0Q{py&OUbG-oJMb%8I5tY zC%bi#O#{w6aHmYzx?a{r@F;dSOr5y2DR$)^FqA+ou*GPKW5QWx!J(3is7G8?4kSDQ z9B~Yuhaz?p(D~rkKaH1dVTCW{nw_71`+R80OY}kK6%b}tembS2lAk&khV*4oCG9DF zZHOS#EjaxPI)7%tnZta_nf2jGD?C4VXC*vyum7ok)$Q-7)_?kosQ(6TaPrRcN z{-%_{r{a=QhWA!JEwAloeCs$}uaQw(KShIp*f@uZJYuwl zc~rYS7v+%U4++)$=yjGq`fNK2C;3C*)b(7qgHzO~S@~n~MX~EElvlLyj4M$TQ{c6S zi@$E`qxHiptgkHrW{6{VIUH^-LX`W=y#k;ovR`F=h?VyvljvzkVq;x21;2VVJhr0B zBC#`aZ#8%^wR`mg1##9R`%iO=7n+I&6-jYf%sfikmRFn-KHAcNqu42MxP2{Z?Ozug zWO6-ZbE-x?6k!x`5ex;yUeK{-yGWu2y!N|dibE!+U@S0u(wNP5ioq@LepHd#zuMnQ z{_ph_)KUuJvPs5Y{3B$J)7eKA1|qIEZ)9h1OJDIr7zp$w_vUlo4*MWY#0oxfVUjBp?8(#Z5^Ces5c55ehJ`o|$XG+n}r}#t+H!cP;bIgR1;J zJc%=O?h4QE!snPJo#A(GV}6&N`OyF{hEuk3v0Luln2*b&R{WmiK~Fp^%f6pnhV!@l z-)OHtA43IwET7tX*zvm^z@$L)J$^qME&u)Hoy&jUiubOUz)HvbTWMMx`Lh(%V`@HD z3qV-VT#Vo^y~)U}439HZn%Me^6H%K48bNa%ccoSSkh*w5PBOl`To$LhDc#L&g~-=! zJ_{#_F*=1HSnchzZc2xCgv~(VI7Wjz@TKi<<#*)UsZq)gPJdwgt>Aqit!3%aw-`F3 zydaFEWuY^Tm*0a2WGoNH{0LyQ8z+kVUAH0uXb}%v09(O?&x1Gp+?mwvs3JHNvJNAz zc%WS31@>OTF*U#5_uv`$nE|vlYHVWP)6V)&%g!3v5e?SEEW?d;)v7l z=9C@P19^H`dVGF$f633Px6T1T8ar8ea#_dOJ6R`vZh|1>lfZ&)P9~Vlrsa7wR}5~) zf+f$#m9|B`H`(?n=Ri#EqFkZe^qW6enn_%v`^bn_CG%L=cPqFm;Zh4pe3_)>UqiBm z7Sm5QK%8^lM&z=kJ37+N@LyQjPc|&(AypuE+I@EZ#CZo{pUgAR$c8u;XT#V!7;Z8M z*5+Ong4g`s^;u=;vUG=qgY8%L*ZP;j2X6;FP7TYB#l`41%uE&=Y4|2d7eRKjMIh}G zF7G)%Yo%r(c=YWt#W*d1Op8T_<%i;%4L;W39WT@_FgEg&qV0b!V-(|eHSJKK6#mX~YSn}25mqSrNebsxACb>@rGYqOw< zfh=9n)CMtbW~kixGm2Z~E7aGY$K+XQUTk0h?ZTc(h*g3hDhlHsOMxX9S(ZT|K7(!O zF|9Mb*4PpLIw!(Sdr0(-E*C+-7t!x`?L0%K{rx6cFM%4R|>VxK*0?c0! zO_7#s$;nG4X8`-PWV-Dz;bc3LuVekf&Qr{I&4B-+#5?aLaF9=v-y;51ixz{24yNzr z#;z7#R!hIIL5WN14(ETXzwbGa;f3&9-`srb!L`zQn|KU7Imx7_hX$q21QH?5gqx|X zSG^Wg+ow$2b+YNd(q1*)^q53Y2Rkc^YGo%MU7?}19#8)ee|7BiADrUiLnqBT4rZS6 zGiDr0@i7cAEYslK;G|{M`|*^=^Y%B%lMTU1XwhOciJF4H9aJm(FaB*Ka!sgd_Uyk* zTJecG<#OW+k{Lp6CUul~D6qt21BInw`rbuwtE>f3Jkj8R`cZ9bR;d1?lLu?TiKNHz z?-_aEpO14m-dVYzHl%~cE3!|DxghD!7F2?S4o7yGl*4KGzWjY$t$Y8@UeZX`qBl zCKv+X0b+^Z=-<2X6o;(wK&t;1XFI!ov!5=$8yh$egzBpTvzK6)T!!(a_>d?&MfdO~ z&B#pz+22W72uhudBP8F&)9U@Syf$KM#mAI&6dL>b$9c<_VKc}}K6*X=pT9hb|KI)5 zZ;+Y8yx{Wyi^Mmjxe$!w3C5hhjNwbE|7g}9yYkKOR_0dn7r&ir8`sH~;fjQ>><|AF zq9XoX64hPeOaC`m74gD;tjObVZ*Gf@d`I4rV&sc+oKxbiqI5;>vgmg+80 z`v|Jmtp@G%HYl>1g54^>`{#a!PC!s{IXZFt(Q^XXtK&KXhzZa->yh7&9=Q;xNR(?( zGoVeXwfQ@OIi-}9=V+4Y!f6C6UJwT0w9fk0MkF+tfPgN`Af~bcNVwSLENNKr*j$0f z?<47-xmFAYh^|and7$#y^|xG3iX}QKa)5`|Sk;XwV5D$ij#ZAg1MT+PgSdWx6n-ez zQ7io<-k^K@8iAHPuD(38cB1iTPXT1;XJP95L^$Kj(6KVD%T*-3A7^jaGK9g~C=7b$ ziz)Y6E63fkb_V`3{YPSX2%?h}xzQ4ev?q1W64m@*ho0RZ+DM2uY;(Gcu|bHR=PTs{^FT&I}Fa5#7*uPgO6G4o8@n2hZ5J9*_LO)MjEl@eY%l;Na&fA z5D%Kcw3)1J-0F!=TaGy8MS2rFhWvE^n=GIY@abS<$cD*ArGF4q<*(@QI@Dn6)$!qe zECP?sC+1?2(1%=iDF&TqopIB4Qf<(BoUu42kFJjwOP9v(-VQAh(2nsk++1Y&X~@>& z+p(5j5=w8e{&9fl>#m$y1RpTu-u!^NcCRzSeJ3b2-B|?q> zN^LtHV!+T$Wb`v$vow9lj1UG1Sd{4qWw!(oN}`Xt~lT+9A*1SAaD_% z0uTD7e8}Kwq!~k@%WQ(jK7#BX$D9B(le6UQlO^qpA+5i%zo@d|23O@{!8%k4csgeI zJ_-;dZX)Y(Ub~!elP3MX5`NS_hWbHcG0~i_1O6dI@Hk2;Fs@H*u*am$Iu0rwY4Bme z_2V!m@8&5;3e=L1|B$tWp$KOf!t7ZL(Toi*tZ%qK<=tpSy&j%DxfvUnMn8nt=@Wvj zI@ydTJP)#b)o$za=~Konq@z6m0PIY2r1bQSq!QE^O-``JP*GlmDz+XPvGw%}6?k;u z>Wd8=LRPo+$!WBYpuS@KCe{ZP_>h^OlEo$TZ6(J*;T=te@}!K;y!yA`h2i_Idg?^cN{<9QdVi zp{m`}m3vj*Kcil%Ad{xDr9bB=2 zANu0~$cBEzCd@hj#e0+1GsC!k&BN35%|`we-&m)8cGcPmvHmky((^y&!oHc0IC;-3-^jnu0L z<+=cjXGh8Rx!2dhhu1&G@YwFSDew0$k4Mg$8;3LBXX~rtL;9tT-X4J24l}pR=e?EB z&`OI?KX*}%4gM0(fXLy8r~hE>t%R+=N?tG@qQA5>*54}Yk?9bWmaMoN|HGe7@)>IR z8Ux4D@2S_Bek+__oW5K?ByT0s=Byw3D(ZD|i2e8c@=E>C$7X8ihor5qicj45AZ`Ul zak9!=yl3 zt{)1oDIf1@xGMF-IPq6oKlDihp?>&uSEwIW{kR_G=!dZkn<&>0 zQLV?Iy(Zpk>4#jCr3XlSUJft+m-R!lg{zA0XVDK4Th8>x>yM*vqaRWnrgHso1LSi$ zd$_?zRe8!kDO0W=()GS~?ZpOEKNL-QUw$TT5B0;vyBPhD=kQkQho(8SqxvCH-M3#r zzKPt+zq)?^h5$^Zei*O!z1Kh04>?ob?_UH=1A(_SOHm8+Jwg8`51*n2Ou`c9aFa+I%@0n<-62t!oA)Y%I@{+&M~1Z8`u85 zG3y#6^uA?!J?wv5pHB~m5g(L4PG9!C2Plq?vcutCc@O^yajzUA*m#t?m{fyjQ*3TzFQ0XRH-XG6;{XB;L1p3(|^=Lo8Yv?jMw6U_E1U*&u zG&X4By_nxW#Pr{XTl(+u|EEm%BP~MlY!62{2k*unPs`HX^~!@~B50HI#Ci;8H;Agm zem|FfE+!wMpY3J+yz>tjPwU8a3q)!I_1?Di(EP#Gd|}5kj=D+_DPh<03PTI=?=Hj- zzh!iW^3&MpL?#B9KS01zAhh6;9hm3VRihkLE+7>;MI_y&N!-dvdVUK2DI-2buEDk0 z7xsK}%9C9&Q44tDv(!8NEh7&KiRym)?FU?^b6Xq(hX6ouA%2*0!McfWie z?16DxelGNQriCNz!|^7-!TKZjl(F3%8vm(LzoW+r`Nb0m+0QYlO8M+55W=!_v|c@+ z=`6bD^I6o&hfdaGEL@(mTS2^0^dh)@p3VClJ8)+D@#*(wq2CFK`PQZ1(>4kHw$D=U z^tY5Kr@u;hoS5Z%*$g?8w^7Vx>EZ#^a9?EcI3daoc-(@|gYQlfk6HUYK9P%h^W*pj zyce@n@#_}EB$FG-g>*Tsh74Ns;aUa;A<0|3U{lHkdqMJYcph~ax8K}W=-bRn8M|jR z6c$7w7?6={fUVU0fFJ*l4W0&}jQJ5?|4BI)FXz$*Oz)nJ|1Vj|xsFKJ{Ur4%Grw-; zJCA|>fYpMz-`JYZPz`f_cJ1Z7LxJ(?0*kx?Sy$luwm|$RRV`d91uPAZvS+9`I|&-z z@(-lO?||356n{qUVnz8CcaP$+2IKGG+G;MEPGVTNw%RS09{p}FV(#W8#d4ZRA4&2l zewoG4I{7)V1w+Y@{RrP>`Q@a%!|=#5=o|Um9LFxhhEMO~Bgwhz)yq&={N*8=o?ZFSnOV8b_|?uEMVFik*Rx0#U>yy zfajcFsLf|~KKHvAeH;l_UiVI}?x?MM`kGnl*}!^&kC7mF!_5KYhVzl-m1h|^V@k@v zM!Cb+Z^1{i)Sr>sUa8f_^~R$+U!MYJpa7;iT+D(xUJUo*cXaxROwq~ns&W-^wQmv! z5U~+(KKuu`vzW6s8>iEsk*&*(KXZc2>2n;0C{3{P8ym}}8}ho|=JG=;*V{m=$^59c+efblnNFwK?cG2y8F^h zJ`;DeQ49WXUz+9{FiR@?((w2MIf;A|sXVwKW702XvbzkNSAc6tYt29RX$|KR;W;cO zW;QuhQd$!0e&)twoi6 zu|fKk66Y!vYk%+|`M~PkEQcN>GX66deEDL$R$e3!Df^7j=HvHj^I?(NKw}EEwS(0b z4u7?5Kb<_Et^caL=R4|3eowp5n1r8i8CPLF`dX!nfrk!Kge3YwrTm!>`B z+l1JKiqB`T39T7AvmIrQf;M>E5;OoN#p;$|m$F~~q>i*0-x555UzwIlx#Y&ti}Rdl zbZaRAB!_aGOIi_TgJ#7R8yI7=hVGv*7iiA_&vMnOZvjmTP(a}!zrIlaVP99OKDk~R z{nxRr`mc^0*Z5KnO#7ns-!HaB|D95;|LzL)U-`bEoHjQ>P7F&ic=%>-Azo9=_{F~5 z=RH?RO&@}Bv+rx^NxD*MSFE{?KRAfLWH+9fzu`Q_kU$2(mWAbN>f$HihmG%1-Y)4v z>Z3&w#(TM(#w}mrz7%G^*eT%3ZU_^nuYw*OZ(yDV=n%FWqAt6ZZ^&JYLa(#REl|5bB4QXig4G}`?~?= zf0y2GlBS*B{}|}X>6lshi(=df_6DC%P-3h!9axZpLGio z*ePzSS?njcElwXG@fzBrS_jKx>P#+Y-(ZIg@?C!NVIfWo4IG_^g+`eY*#@4FtYX=C zFI?BKy&Z6+E0JW5?_vWZs1~%QF@TjT%>oB5Px!~Y-d9t@*-!@67Bmv};$iTj|88g= z2HHgpVd6@@OcFR~UFyRrew{Zf3u*tEfCxj|s9;h99876s6}~^+{MWcyNy`Q*@|bN{ zNBkcmNb&q(K;%->c{;a`ba){=pVh28oJxZ_%xSEE(!^a>0d6K(0_Oc2g;7P)n1e=& z!AdAX3t$p$a=`LC8@V=vyfk?wXW|QhQ%e1=+}?Y7CyBGMJTEss@QWA320B@aQ*5xI zP&(3;7vUG2{1--YTFsjD%5ta220rPPo8AODSF8SWVgo<%zq^_(U1It%8&{f&8hrTi43eI+3%P|~V)}YliLodL<>{A~rAKBfPwAZq zK0?DrtYLB+9yJ6!83gMjZF!{+;?r+Gwq}&juz-ZitVtT{e=RW~H74W^A24hYou$6z zw@Y2Wrinzg!ej6#4|6*iJXFDfamD$6Z_+ltp#`rpH__lTypbF!nEh+^Wk*3a&A&G6 zZr3jLTXXALd~B@cRkc63TRyNvTVmHS#`*t(wS40r;?M*BIN>dcEg@rL_T{6^%u;GI zBg8+@$hb}dI)!#|0{47IWKQwf`kUnaLTp0WY~Quuud$hbEZ;30{;}+1$#QfMMjkPB zb@6+Y6I&bK(AK6n=`$ju6^1qfu`EH6Vgj-93g3)g0rP_rWewl?=J(mg{Jx6Mx7GY6 zYeKA9SA&kr^6u`yiWAn+ z?AP%@!#y^rH3r%08TGd_k{6k+-Vd63OI?o=wi+?PH{k>N^DuKaV>VEvtDBg{e$lr7 zv$eAo`y!))(rCSQwl8a^>xH)SCELzqy>{-x2O@DI6TZYT>C|5oAVmIcXXGDk8D35f zd*gb)#a$HQsNAo_(1~BkG;-rtezL54Ex#=rs_$++v~v#aecra$V%oC@z<8GZdoB2_ zn7_02S+l7o{EKaUBmmaGk7pqsEvoOmCV>iU>ek_$BzdqJnAXH?x{V$ zn3u}R<`Vn$=HhS68J_XqvvYO*h`WFH@AD(NrD^9!9CRln1^wdwkOD ze~Kgsu~(b^=-aEkhr6(EA3g}a@HmGJ{GylYBVT?~F+o4|;g9MkS&lrE29451Fq=&$ zFih0oqM^pAxF)9Lk;K%Nz*oSdTr+S*#gjL4jCf=`3KSH-MBIuA->r~feAem-UERQk z3^2XO_|l5DOu^O+s|k8sSBENnRpXR5}fXG8(8kAHwx|#=PNF5>~NdDhUUg?v{}S!Qc$e>N!U)3e}y2#l}e~ z6X>)5kN)#jAQP|<{wWXfH~nHhQ+fAJz*UF_;LYJ8!cXvj=Wj4sOiLLRDgnoZ;P3my zK%IRk7HPNjuHg?{p+4dkgN$D`1nqY-B5I+s~#v zg$L7z318%%GyQ?R@8%ZRKKldDPx}+=e+WM^?Y42$6HTLYrsC-I!|AlG$EPdaBd%lN zj|b_ywr=gR-{F;9gjd>ede@wT*6?SmYq-0JAWk+h@iuL^?G-V%7Knpq^1`CFejguF zKMWj~7kM&F1Y(rngM22?lWPA=%ivn_#hB)9qh~AAbNkwP z=qkI?tM}tlFV~IBl6U;AvtCbJtz2G6#+dzi^$iLX%9Rqh#!}S*b_$ouLxgGEO4wtV z1aL^tRU+T%(4q1KWxUChF{@r%8-Io}d1IhAg^{9WR2uB@sN0UZfxn-B1iw8?M)oKW zC>8F~!U`a{wUwv0Jvd!F`V9uo_qi^kGK9Fet3gF&-Wde~&xL>|({0JmS3wxaNa`E#_B`<|D)VFemY_Z5nDU<8$>(FR5lde13$hM!WlgMqyJ^3qCim_m!cr$0@JcXJQ#78c%J-9xR#(5PyQO z`djbzj?Gm*@cg_|78Q8%VL!AtYN0mJdhqsNilm9Fv$31Asg3#VQ|m?&2lo*qYY=oi zWB6IiF%N;fsqw{Xy?d2+B0`1UZJ8%iA~?V9D>?-e-RAmFs9*nlt$&ZJwEnUGG4R*Y zpJn>yMszBZKm}C63x~Jx3@|K=!M<@TOrj(AMnpjCx~SN*9kyQLf)~eM^q`X`J?wm` zvq)mD@`GtNW+Db$kOT5oZGB36u0ER=4Ow(hYVc>VK^_bOKpNb(xWzb|C?l8HpgF%7 z{5$ctndLETg@7v*)aa;t{#-vgXypO>SsBlNBRcE!1I|!_@LZ6@p)X&>-=@_1Rqy9q z4|GNXuotI~XQ){81?P-WU8IebR$SDDdR6dYY|RMXctSI__A+@;dVlQGSDROp1S$U{ zkyBcPy>!-hY+W=Daik~F=hVE%Qd=h%&ciO5&=XW+A2#Fak0;v>Em*_v_21i&6yp^}4=vap@-Ejad zc*CPaslu!0uS`5u&CmQ!?MUphQju45-?gC~EfWZuR|FUf$)|Z5L3~d+-?0!JxOESi z1;Bciigp}5bKdP|+nG$D;APi~vUkwe_dhIru{Agnmv%#;8Y-~_y$^mydV$zb?>I-ZJg#c9Lv7{0Ro&sXD07BaVM-P<{S3QpUAE4dc7QF_IJ)3&Xld0n;KfV~F zy#u*G`0c5M!&&@*`L*##9GCWB;r^Czg>5g#E=^oPR#qsAo$tRCu7)Ec4SDZux zPrz^?h87dRbOnaRtQUIX7B5LiA>vH*(D+{soOhF0acTWfWjGELvcl}=3Ad*=A#H(C z@poTTOjU>W+7h6>ce=IPT=|h7v>88}Yhf{<1UiNbA?Ch3pHV3WfKqj%h z$n9nrqoaQ@_)@)1e93r*_RkR*o6^{`GB%a5<=%^2+)O0((g(#saUxh86cM-TQxw!w zDdGm6G`tMlfG^F~X^#W>N$^9|!ln3eaII@gLT)xmF8Vsq2hU&F6Uc;|#tSCIVUv?} zt2v0tg~RtQ90tu`YigVX1{)!Vu1v+*6;4F;=Am&4I1m+)mc=kFo(&D@vS1Z{cGD5W7Cxas{aQ1+9jP$_^ z?@%AgmS;76d~t2y8X%UhIKC_~PNa7K4~XpFjsJg5lS-27nzG&W^3$YiiY`#t%a*8cL1m?Q#fjU4v$V6GvD03ASr&xQ!eTLdYEyBL37I{3_ z0p0NlDFQa1NkX{c0^dlB7&4slMS066K&2s1a@ag^m`)cAebtkP8s`!}HvO+MKbCQ> zIAEjDZnyQAQ3~ZX-8HxwSf+!yhu?r=%NkFon<~oDpS5%?ajt5A_P(n^`?tcMjqjlT zEQCIw!ruP5Kbih%y$T=s$NHO+@7(`Q%HkH=8xct)!Ys~UVPqXygMm!jrb6TdSnu-bzqIIVvWOh1>1dy_Nv0Kd;q)_ES~__ zW$6WIhL^tg_+;hR9a&N?P=HMtjscy(PVz|<4p1d^l7=up4p62)Rm1LsZiy38vYOpV zQFOeRfTiFg7!l69rv7Ng!_W6J;|-n79PsTMs0u!L2?RHxw6VX0v#o)WLN^d+PM$Qz z1aKhI{-R20pLY1-`17hCCs{sHm#(^vKZQ8Slg6J4Rm#X8On)reWnCrjwVeY2uk*t< zjK6^5J|8s51~>!vQT0MLvK7h2&ieFo@K z@SUgjP{I;BvD*^4w449EfuFeHMY=I`4ZrXj!%xxRiBVWjr_y(0MXM+f_jLn-}mU z`&IXo0x}VFgi>l*dcM33`2&8Q?u#h#p{eaY0IgXaANn}pK5vuJkr1H-$+!~G`x{g1 zFWq+`^vJriVyW%-rHU1euo)WR^+&4;L5OJHZ+M*B@bkn?5)GB(CN^l!f0A+W<&5-4 zc|qe&mr&KZ{>xuP{da!8 zF8u9U|A8-}{`b|de_ZR|@YffPpY7_`U)1{FQ&s<5{Soy85|4-cP1&NC@(uU|z6k8c z4sadlaw@kY>GFQq8+q_;frk;mc4It;7B&3@q0e02)Z0p7fh*)&@y}p-t%mvDix49w zFU^8<$nqNg*@@VC6>*8a8ub}DU1PvGFBvf;bhFiSIbG1s4jmTJoRxRr$X+kr3a>$c}!jW>~igQ#Yfi-^e$9 z%ZvTyr9#V2AEXn%G2^DO81q%x{I$$$ioMr|b~bb-Me3D;TPIQ7xNRx_SV&i_L&qN; z+WZZBnj+C)k88_>HM%)jQEvA6i$~IR`FzipS$pr7f7;&Kd#kp&{!8lDKd-v}p`A_q zj(w({vgGg1(;k`SJ;#@NQ+4OAxaWoO6}_3DZYV`LzD4Lf_0vsE{7<{?~{BKR7%6ti*IIl(iub8UFuIR|(iy>)hYVmCT?h)*A{ z>hr2TUxUR$5@bs5B7y+H#?xRRAhW|dmo$ijP1|EHV`EFF@O|*9+hIG4+)}(N-e69p zH0kF7np4>nIt$Aau2U=1|G6^)9#3`O!X=fu|1ln$oZE4HO}luCP8P;4k^@}a_Wn*- z7Igfc1z_=D^-X4}K=nMj9XCjcn(z@4R2v;fwGvaMTaB29M4Y3+FLt&2pv-9;+jp%! zj-N&?6d#})r5DAIqpQ6pW*^7R*Sm2fm(+^0U>wc*(&y0~W}?#v zg-$0RB<9}FL?xZB0^Y0X^cNx-UPM1TIGl|Am(%GRc6R+tkRe}zer6I7uZHYeoE%lW zf-e)wmzci+6JXN*vIFt|cB@at%RHH)$f2gSjo89NTj4GbK6=?3h@8R{y9)+J5X7cH z;094j69@@VA`yJ~d!pW@rYQ`M)-;TooI(b$!V`=e@=`fn``pWy1v=kW`c-{BD|U^| zAFAQcb?$+YvHn~`jO1zjxieQYDpm>}{(ZSWmvm^vxDDBM4YZ+NHfs%|!OyWzpX(fM zx+=b(T_2x1Tvs2D8W4+^cig%aBa8S;dEX=~*=(L^7{c;9- zUYz<7mHK+rJmnQJHSre)pW(Kd`EO%H_&- z**@qfw6pSPw<15J&$i2Nc`09*Bu2^NM2=!OKdbUW?TLlM&muC((;U~W*d2z%j=?8N z+arENxlH<-{rmfZZT$Yv{J!%SW}IrZLp)T&_1bBc(|AHPT(%Q?pc5|(2LHOf(UXj1 za7-(|SG*pKh87KH9S(Lw@g1OwX-JiVQ~o0MBH{rruAVEO(0b+wf7^ds_*;H%@TBzN z_k(ycBPXHLU>qH-g-?7|1E1HR%553vtKcbNf3b%QJPHT%4GD+JyZZTtCm@VUUN`nt zr>#fvK^S?F-`_py;iix*6xi4xz4H+zE^Zl3ci~fyXc2;ot5}w*kk~Io9(+k z`)sqy9EAD+IL)w#&=2kt{H!e_MKVLbyH)?zH7(d#9js# zv$E_av#$ei#`S3J_T4IekBRC&s=uM=`=~bjO~LSkCl*mBj_}Qi_Qxo{AKUXySe%BN z@q_Kn#8JG#cL&?=vi!mA8jM+tAAghHw{nHmKqJ=|@(oPhfyO)Sk34@|XMbP|v4O_V z*&jvzxYYhA@yGe{!>H$B7*p2zBdui8Ru)okHE%I=O4{VbyaJz2YwP7N?!29$(R3+S z&Ufm+(a*5;n0Uy`@r(9pa$lNRI+=YgCzxTYE{0Tc%a~(>bV?W)X^Gr}J6Cx`)C)>#re$-XIe1!lI+0%e!o3xiu<^k zqz|cY?575gDwm|w_>X+fc@@9kM@b(`uK=i$lYt%=TF|DQSmYV5>q$qpUqLwhoCwK` zdc*JhCyqNWl}|Dgq-WR8->`fWx?ooG6oavUiSva7x6sa{eB!0$&j7$Ku6{fQ-UaP3 z_=sGE>#~bQPz1A#+{QXQ#tIp07sGC}WJ|3gGBN#1+)>8sMf~tWb2?SK^0mZIKH1_?Qg@5jCsWs*QFm16L7ghw+uTP^U^Ve8Xzc6{vZC(`wm?IXz= z--+LW5Jd?nlsH`{7(F-vUt?ZzhVK&ui*elHrO{vk08(PZ-~9dc<$$!e-mL%QJXm20 z6;;pM$$E*r?c#{7Pwf!x9|E?AoAh5BQ^wRs@HKcVHjbtEsHFSa`rzsw<PQHcS&H6KL- zOn9MBdb`SNzyGWUMN8>25Zc5WWK8}mo?O=cC_Y@=&&C(a&tGPTgkPJms)6EIRtj)q zII}dSNN6dXpR}ek&fD#!!RF4Hgxo;bsHWT?{+3_rD}wXUiyCq@lp8rl*~n&jlhsL4 zLeMxp4gH||P0O;Kybl}Z!0*Wi$Az#_b5N!!J`|toAF15uejH9gpQQs#oLE?vFdrCM zFb+)&>H!w!RbW*G*ZI`N)we-r7FQM?_+aMp z!Nt_7zksTcW}{<8d`tyj`mk$XHIm{(<)If}HFEY>hS;V?4^n#9bJ`_|&(M7yZNUmU zN2lLqYN*krkaeJr;8kPHSI~Amx!a*}oh?4P$A=DJgNx%F<}5cJARQn8i;*C9NR5C+?V z9ijVohhBRH+n=DJMgS*C6M*Y73s*C+MNkWbsmSMI(@cm>gVe{(Z3Qz#y)b)(ktfMk1q|j9gXxkzUBtO1BpQPN%@Q*l&w^bJXSGuFE|5?A3m{Z~5>sQQC%e#6j* zH14$zz~jo+X7iD)S;5JeY)@`Hs%L>%PLvvA?_(WG=QZ?)q4QthBfvN{DR5C-oQrd1 zF-e28mo|*nVkD-9^vo`YakBPY8R-ZD8kG6I%S`*chN=C~TF6Sx5dLxhqL zAU<{eY7)p7T4%3|lM*1Hzb?eSUbX}`NZ|JDoV2DWLf-zJ_3b;Z&4WBDQO~z|yuMOm z@Wn1*#Ml%zn4Lci;nlD2e2L6EJdI{b!2^&Po;8sfvJ8|S-)P!J6LKkkBaCPEF<5Xa zZNG@>vnqRs^PCrb+tFjaaRk`T4?D_;`*U|Eit*1%11pt74CpnT*ULRov#PW06r7_~5x_~ja0G`yJ&K2E9pbntc1px0hz z#NtZ)@e$ju(rIPI9U@e6Jh$91Hc zF*`v1;!=g1!ityb^NRSzAwTtSTKG%opHFNs{a5>?(k^(X&xda=6P}fEjPWM+YB%Sj z&)*;;Df4O2{~>jgmW@bk!2$`>zVZ|Mz>D;K9{!;}l6SY}TK?D!zv(p`*XN87l#rP$ z_&CCiEqN#S>wl6{VfW;2H}xwWyYXe{%9n_kcu)}1xB$fU*1S_Tqk;oSSSQQVUz3v1@9ebUA%?c>fei&c4kyl4jwn9Ve?jw3KOYPF-T}?*#%6MzuQh@m z#EL|7$`UkaBT8%ymc-M+7yj&8qUILaCHPPL*x+B=W#4&meCL69m0rvJNMVTr8umpO zcD~rK#!CCYkrKuAHB&I~Be6`}m;94Xn)R{0$xJyNY^yx`J%*3?8`}1I%H-KsZ9Pd_ zPc3=27vQyciD`aHaq{(~`?5vjp*-tAiQw6*AkXr*nSQEVaP;ovSx+~{+WAZyd|5W0 ze;sMv#Hz9!?@1wnCbT`Pyc(~PS5tG7SK`-mouISJppL4t5G==2^?fBj)TT=y3)ZFy>=}^_9GQb?#BX--ji+F&nH(#u{Zt+#50EqH zZ_LoH*r^mq4QjBRSk`Xo4Td4TcC9nGRGdMLtrUVkom$jPB*EES4V>x;RNz3R>XV1bnE1UV~4IKa>=~s_vo=()Zr+TWIu44lOXv(MU zA8C6e;_-2yO|4pww!7cR$7W^A)WY>=Lw!rU2t^77yt6JXY*}%;qZ$(c=y3Mdw>DxE zM2WmbgH`V~1?ebBjy?X@=0`R4wE9^=mbTxDo#!u`4arA9& zF?R!w4Q@syHoth%*6Xhm={I2tJ0b-uN_=JX*w9A~^gjuImZF5WM*d&aX%)oOsTQ zbbc59dFu*J1(*!|HcU#_sp=c(2ky^!aomz14)=c$-P%Xe=k+Jtn}^61J>il?Hc~r3_I>kM5z&{kOwbe{QJFVz{S76 zZ0$gWhxp(H5K8GX5ZeAP#lPQEC8NoID(5I)d0G6;DgJHZx?#MTBCKA#IgHKMihqZ& zH3NpZ=*xd^{2OFu#hr!cC5e9@WA*9m@$a);`zo@O-c?pbWwd0x%)I}pMovwQ9jEj@ z$M|<_un9$-Tf+_q`+P?AA=~BU=-Dh)P0&+;8_@qpaQpM~db%KZoL&DT%Ch=XBDJR> z68^LZ;&c#pi6ssV?EoR@ON)SOS93)ccTWr*ZP1FCkxaInts!@d?jpokll7fyzzQb z@p?3EoOu|8#y=9^MOVxeuWvoG441|{1f0bm7(J+TRq2;+YrI|tL*w-Y&?2D)pmpQ* z{YB?b(X>#zpxwfycq9$-5`QisbU$mn9%5JH_2b9S60iULI~;yeXeQYEQxxdfZ~Xh^ z_#quo&w<`69QOvwYVz z+jr;UxMj3EYkj|ie~$0sv(>lj6Y^ccepeSSyUK|Gk%{X}f9v++{@;}47ep%BCr)^A zUR&r#_J!aMo6K>2uo1b8CXQ6m&dlYWKy{|vs4b^-P+88jv{UfS0~mhB`qgb}2Rm8X zcG_(@tsgI>KkCQUw%fjiFbFvtcB3t?^riJEUKVqogA%sPFaYlm+>a;)#xwuja{O18 z^9uo=7$$?430qFTpBudIKw6K1ca<$a8(v#)W`b->q~is(_iAh_WZFx-pz`}5p~RFg ze8=Ev+xq+bkIXu>W$BbHul*&>@*@9l{Wzr16?b=`ZmWW0Yj462=D{*|wRj>0?oEx% zU*$9At~Q-yp85H!o%WgJui`uAucqxY=CHCX^H;O>8FN?pjCrfklTCeo?rMvD7Kcy4 z@0h#VZJ$ZbDxM|rY{EWc-YUOi&T8I1Yq!sstC~2)w81=8e%Fn^o${=wv5&Tm%TwhW zD!BB*_2B^uBm80VVR3!}zaQI(geBgL-@qHZKGGJP;M43i_9+2pb(8#r8}ai;jz4(B z7=IvgU~t19dH&$R82ll5sA87%= z^;9~r`2S8m(zh|J<^E4`hVhkn&%f0l+qVjym%<;Lc*|V&&ye*m~JK`*;Joh4^EfHg~pOK2pm9_WcFqBVD#gIR4+2 zk2EQ8QJQU|fAjt}H$)&73MH@;{F~f0Mjw)Xd3pYg@tfD;A&hw!6uk(8<|YVCjFCCi z<#S?FV-O((F;Dqjn8X+hHth_VrnluC)Sv_-}C> z96O4gk2q#^;%Filw;?}2{Wgx9jbTgfyvfhs@>3VZRq2EEU$(#MkNA3*F$YH{DbNY! zP=2Avp)k+qIYS7V=Oa_xX7jmr6hVwv_$T`{gIDzhz43R`$SXLSE}ngy#IqNZCh|FS zNhdup)Jrk=%s&-71oOudjA0V`6TqYkYft%M?WW+GpGeeaD$@rm32f68v=2Ch$RvE% z%{kw1?5g^D^NJRchqTLkDt!rm~CDh``Ow)^`Ts_$H#OYfHI7i z(rGwP7#qOi@yc_E%2L;cOpdQvku(C66vn{WJkNWHf1n`jlOaAbF0tmYO={-)l{X+LU_K zmGk2f5DHsHezIWA*qyx9as9XCVSRgZnPQ}EqIP5@eL&8*`I_=Ptisz30|L+W^RRZm z$FxV!WRu3+s0Q1{#E(PFXxZjOnD8ZyFz z4Z9w3^bF#p=6b|avCpR0cMdkH==PUN8#K3|`o z$$LH=hM&98e#pS3M&TihuyzP5IUUtA~ z_6pCXi=Q+7_vwwWLCy%DUE(+RzS-z4pFNB8cD9|yFUYU5)oZe1i;`B9B5$y>D%QSG zBc>T+G)wF(fJKpigr_FHHfJ5aBDNnYuTVrT+PyaayhZJd<0vjB+s`&52O%uE?UylW zl%Y?&EEVyRz)h-zem1m#TTo>tX-72s*%u-wo++rDm{tEyp*8B?62Esh_Ru4p&$vUbn%x#f9oIMGC1mZc}sFN6-Bz@#JvuhH{_ zrBctTzAw)^)`TPu!W{EE_X4Qp;{L_vcTT;NybfmJB)M6SStq}9r=zOdwtZE(6D9I- zp}!_RwIi?ry3aMgOX;2`W}Ss|P|iIN>(G&647q_|)M5mq&Ou5Yx9gM`M2>EG1s_~_ zq4I&+Q?=~SFQR>)7jCb`3r!5vkrxt_a~?0WcM#B}uuYkuf&@*FyUQi9%O?@TFb)k= zm1b(XaFt6XxfeY%;i?CrG07wheLzGegD_y2}pUXP*mn;wOdJL%Q7dzIejIPX&{5ARd|QCIH$FXrKm9PQB14m1R%E*PTT za&wc17q@7IyeZ4WYhG&54cWPEd3bw5>ri-#d{TV-{G5D`qWFJ34=-ywRiL(j^D^gk z^FMxV87^J_nubEV2{?YK=BY*@@(5y{Dx}a2ntUPiRJT0k412nO8++I^{9c|4T7X^$R#ao|MmYT3zdQpy?Rjhv;(a^Hl%pd1(5c-|(I4hsyU_PW9ck zzE^un>!~cS_39YU^?fb7hJE28zBEn*Sv6?JOWURW&U>|&x$lk(jcn+~iUwJ%)sNMN z=e@>|pvZ+LTaU_Rw!w>ZX!j{9G45MqztZUWG@69|N|U&k4WH(3$m)KjuSu8hSDN6(4XR8$63d>)_YT_Iqy&3 zbKH1oJz8Gr)w5^BUg!iv>YVk;lt0KY*5e2iVRFgXGsZ8XGygbH#Ly5=u*8BlY}CFH zPjvC=TYluiBC4d}hbmoHv>#iu2EYOa7fkq2Z5Ybu`zQ17H-)DXrk zgmFEEiOk>v&~hlhijB0bKxhF36rn=D$|s8ds=TS&@ijoqcP|rVr||=`js<=bqoHm` zKhJLxO?~=#YCq_BsQ&cj;sd@rI??$7He}qKNlhfl;iiGA0|;Q^Sv3M~5Ck9(pjMC| z+^-b9k&FDv%O{7!1f_9w)I{XSn>=!LGtLU(3gD-LQ$S~BVs#f2XHTbFt}y(l_*8mi zd`{?AGfH0;Jd0G#bc6j~^;hNhRe7j)-NXdXNU?8bxmDX=Ivv$>$d{$ZZF!9kR<^4d z!QVqhCi4oq?Dw_g$3X^vZvL&C_#5f`puyiLe~qQ>FSA)d*8VaoFWP0kG(Kd1KcSv{;bd9NkDtDQ2DqIR+p6o?|+WbEeOci#rb$iOF(7yHN7Prw=rF58AFjKKu}J z+4!~h^T+14!sv&KzTfAGKFoz7@&k=)Uu=})q7F!91`7O%-IO7BrP*=r+_#r}_ zE|kZ!)>Iz3@54NbDKuD$vcc-}hGK)@~(GgvUJ9pdms6Q2_xOH{_=*8hx_AV`q0iTpJHeihY z5N`qL8%vsYiG3|R%e*gfaG#h5*qeG&a77N}XTsbGw2(=MR26D`ob?HMS`CfXi}Rqc z$r%?keGpi+{Gs?&`cr(=*zaWiu|$gO90YxSota}&ylOqFH_%TvueZRbpKzI;2^5uS zuX$*~?hj}3k8s57rl14?V>{Z6j)E~uReYmxSF9uVj5h!QEZB9rGGmLTOMM4Wr|&P^ z3Y~8Dk+=n0uX*B~l0e6@LXR)!x+K@pI{S#7o1kFGO?<@Y?pj)_X2&sB#o#$mT6yOs z&ua#}JCmXe?~_dzu=!SMPWWLpke?dG0XeOS>8|C_gb%_N$W4nQoiG3MqXKz$~k0KPRV+` z>hsM1(G=R@iz&sN9lp7(5a~wh!G@x7B?`gmYxI1D;;Qm?D9_lAk;T#AF9>?jR?pe* zl-?9BjxTuvd?$X5oIlWw)@Ts+-&11noabBSR4CPHFU;TQ;VywML)mEX_a)d?W*jBu zSAbt`{B+zZ<&~V5r~4OU+ZY^dj6F5LK+^}1eck@}KK#4~{IcIp|6}-($y;bWh6_IX z4(cs!SLHrDcSsW)z&!j&|8J3i_m6q8fzO}{UmV=Z4hhYV12NWM)uqWIfxwAk&Ey=* z0c1I1RO!aG7wWx(srQ;L2CA{6ztMfjBOGp%ICAjZH-J04fe3d|VukkHW6;J3idF2Y za&4JQrtPXfrE--=Dc+k=T)@gHi@hs7`btyurV#BZ@2zezj`jyk8dU4SD?+&q44 z0LN|+w=O3Jb1DY6Q}N{nx1J-UXoaW?vv6cfDT^3xQfKTd!pN%zo_|I>521F0W6-9> zu~<{*ihTj>B2u%7Uq)7x5&z8wtxaDy@<#I;6~8JEX26^9)lybHiK@|3Dfng2uBr?; zK*1hot6wFZ@cIE<#dR+B0n%V;Og8GHTIHciU^Cz#6WLWA7t3Mw;1Ra|U8#&#Sfr+X z@m}=O+82b2edgRbFQum=eR>kr++TWs?30i3lasjtS#14XyzkF`b!+22*}X3lza_I} zFA)kw!hXfx;r+qh{l(t>eDD5ouk1$e{xjY;H+av_@SgAK-OuyxpY*;z&wKuL@BYZ} zKGk1(-RdXs|Gdiz=vHK(%M?#TupQCg$N>Mt)wLp&&#FuK+>0mW$X9C~#6#e6s`yco zUzJ{*3SNGgGiJK+ZE)uqn!-V*RG>JwLL&sr&q5@P;w?{=CL* zdHUg%<81XS^JilH%$LfvSaw~O?z82zjN(D}%RZh%C)2&y&yuk_0+AZN^T=#!_?I{g zxX}M$15JNvhn_PGx|)L1A=Iop!!0ZkXK1kP5EfqA4iS`H$-#e2yiQL8eGIz*LB2G} zHtbwTk#AbXLE#>DFxlK@p84Rt*aya-(fvQsZSYCl@gMgF6FeF{z5D_Ys!Lot2bDXe zhQv4=zFZQ4Hy7CJu$@EOjTzu^kHHvKsGZZ)K}RsNbfWb{PB!Ub^T za(G}E@H2Zz@n~=gikt6?7lr)G0`7a{btl>I@MA&bd)r5{_B*wwOzmZSF5|!EJ9v{C zd?xnkDWD^h2EZ5~4^*O}<5J@J94uRI!(Z7Fy%>CVq2qscDY$d7`<>wL8}WNty2Zjl zT=Pm?!9zn&{^0XD4FCH8C5UP&da^H}XsRvTA-=jP^Vtq&aBDFK*$o!{^3N z!sd=&_CRs-ef}f$`K6N$gI{tGn&b96%DqZ?Yv)-^Tx+!rc`{W~+iwcE|;=u$ASA@-Bu{q)D?F{ zehpjYmPbhtek)7Zill-qF>4h}n4B=BHkNit?HHM2xhw(jd?3IC0R=0I(A}p3TKCqq zJlh2X1UI}59%Ek_twA!2`ftH|b1D8jfBok~dmcT5TF`TLsYU7g#|C*+m4|zmsO;~2jqxeE#PLLoQ_TeDjr#nWj7ker9mOW^^souBhl;<~1v6UrsE)A*NH z)cm1eB6&{70j_-e6`-Yc3-&RG$n9Z{5{9dN8ZriPZo|5BUk&k~!S#HQz22N+=dZt1 z_z-tRC<1#unILf@xa&(IFO)7T@lv&4`y^mNi-Hwu%Zl||e`}iqUZ}Sr0X_5>qg&lT z!=-&hMfV4dT;M!~+LnB-_KA&`EN8NBr#hG)V9jHl7(r&BOz>B>gkKEvA)2TsJuu*x zCpnIVw7Lr2BXI)llJv>f#H_dpI0M+Iyx_mSzrB(}C!onhcC&u#$mflJt>dV8oz1__ z%sWmjsCxcx=5b?TDZLN}yod*0z=QbbJd&l<)$hw5#=U&fJ);#?t|?{YEbo1~{Tat+ z9r_3A9TLN}e0VZR?QL4(SZa&29uFRw*X|}?wGSA0%!F)_WV5myrrQ^gY+4aaXC=6l zUVXT5t`nRp$i{U$G}Hu6OuZHhoYCWof2|MTz^Nq(bL&I#62$1kxdoz67*C(6Kc})k z+3No6YuBmPYOhqIy@TLawp&QarB^EI zS!#JH`uG-pjLXNz2tK#%#X;e5jt}AM^x(VG6bs8K{xH!tyu+>vBx8j#j%o|}?R19i zFg{4U#|AHjShl$50L(_;???YisVirq?~CWpg}$xLQ!<`e1%Y=v0-uc@E+#!B*DAhg zqt&AC|7zJ5`i|XV3A_?GA@DvoEZ~<~^p*#DlzuFpc`nD?>3g)gKQqzy6h5zPkMxsv zfYzt)WfcToEABwjE2HnRA;tHc=zA4DuSMUZ9(*&=_p&MiZ*jK1Pv0$JJ2TR^jv4#q z$xD&nGH;O>E~D@LfXi_UE6eb5?b1~256=&-r$1CbNd0})^=IqXe-LOo8axdNZTWLn z`195E=jzvQ*8P6Y)K7j>*};A)eh}{sy79@J`q%l1D*WZ^x4*CSZ?BpA7d(2MM9AjU ze!jZ>$nM5KV4rw-<7fN-mbv4%WnESO;`Qq{sWdH752lPC(T8^ih?#V z{tDrmu%L=Os)tYLeU}b*AnTHpG8%9$XhH|oTVPBJF_ZM`W&=t~v(3-NVd>MsoWuN_ z%pa}!BATP@pZcWAA}9Mpd~t?2c>Dz5OL-<7cYi*qhs%E5y!4&^y3kxZ8lZier`P2< zR1!a0-wJoHa#E?qB0-!!5e;!#Cw&0M@m3{1D$j#<_y~ANaOkgSeirNErTpo`Z_bD9 zTyN*qX@mQ4a|p}e7OzxJASAvrDGR>X5lSCAj+)N_d1m4&Uqca$Lw?n#Amo{EbedgC z^N6GZ>aliWw{utW-ou>bnLyEC!SUk%sLkibC!F7GMc-V^@op#*$u%TR7P_(iiIE8t z%(HvcU|M05bFW@MY?kQa0bQmG%7sz1Kc_X3pdS_ z|IYJ3Pv)Gn_qwmO*WP<=Gmk?ulf+Pg%A5kE-{us?s`Q}6(!`&BR(S%Ta;f~5`Nxq= zm3?isZRvMTPH-Bhw++Uupu;BT#Nzq@w(#y`Bwv|r2rs=oC~ zWyC4l+M23yq@C}H_tnAT(Vk{m;T$(+WDxV~|C5%IhsIHK@xFiYFGL#KZ;#AdVBD4m zS~iZWM_emK_kU%_T`KpEFHYX#eV>8_qg$){f_yLP%dN&#$-xy&ol-SriO8_lcbdUo zAILSTb46%&|qh{}a;cwEnY99@@WHC2#qe}uKIZ9IwBa|Jp zuuso~CY=eTYzz}p@F6A45A>S+2=$Pc(pmE(`ds;`W8KQru6=7emF??y zgoF3#UbDV`R`w(Rr7C(SECtvvFDIuGzazf>V$-zrF5_qFKdahLPTT$*#|Ijw zlLORtKTPw=jfA)q?007Qewc1cDv4hv-yJ=VWM;VQf|sMhu_&_r--vxbO3pku<30TZ z8b+x3%Vn~Fakuo_TB~1AZ{H%u^w=FZhkpHjq+zM94u|I1a8i@8pmdQD4F`e0hoSOQ ziMuo+RiCl=3I@ef4Zei6lFs})7<%_SAK|F?@LDXm?{XP$joJ31@-Wh#eNSmPY~N=a zytwX}?}5LPk35=d56boporJw+vcv+DS5n1B*DEgC@+Z4eCiwl)$V@_vb{vwj?UO%h zqi`#7WblK8asI7>4t&PT?Ypq>B&iqmmx^QBHQU+*KVfI`7_085CxJU!s{A8|k5njg zm@P7&7hJYc^klTToc`1Hn|TrXJ;e0eWc$_rX!fy8nshho1r~!^l-JT%iL1;Xn2DK} zLImLa;NKhZ2$B{wVHkkF>r-;lieU?F~ETrhQt!S5y#6Bp@09>aMic%*H-e}8tw zMDa0;`Ip zQ-R+<=4A9KQ=!|ICi8xu*F@W~%KnP)GWaPS3774!&cs&poaS+ikn5+ob>g#1m@TApE4xabNX4*>-%7Xs-l~rO24rY#kP)BiGsx(T?Z? zIv)@@$NGUDKy2Sb7jm&b`(AMh?;$OL{uc8*74&na^b;I`)tgp+$Cev9MA@SY(U$Kg z_ZL4o0iMvEE!y(9;`#nDys=8^aD_&t_~zd(9*B~it;|2vG_PR0xD|*2)JyrO@uB3;Cq~L*F6QSOZR`47 z=ueJz{)Ao3s{Q0Qs@hN0XkXV??vedK*irV>@LmI>x!^Za-GB46{m);!NA{CppD0

      x>WY;b$0+4hwwoM_sK%3n}beLa+Y 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

      qVM&a*{!na1@AC1C49ff~B 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

      HyHYw4p% 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 literal 0 HcmV?d00001 diff --git a/Utilities/unpyc3.py b/Utilities/unpyc3.py new file mode 100644 index 0000000..27d3122 --- /dev/null +++ b/Utilities/unpyc3.py @@ -0,0 +1,2659 @@ +""" +Decompiler for Python3.7. +Decompile a module or a function using the decompile() function + +>>> from unpyc3 import decompile +>>> def foo(x, y, z=3, *args): +... global g +... for i, j in zip(x, y): +... if z == i + j or args[i] == j: +... g = i, j +... return +... +>>> print(decompile(foo)) + +def foo(x, y, z=3, *args): + global g + for i, j in zip(x, y): + if z == i + j or args[i] == j: + g = i, j + return +>>> +""" +from __future__ import annotations + +from typing import Union + +__all__ = ['decompile'] + + +def set_trace(trace_function): + global current_trace + current_trace = trace_function if trace_function else _trace + + +def get_trace(): + global current_trace + return None if current_trace == _trace else current_trace + + +def trace(*args): + global current_trace + if current_trace: + current_trace(*args) + + +def _trace(*args): + pass + + +current_trace = _trace + +# TODO: +# - Support for keyword-only arguments +# - Handle assert statements better +# - (Partly done) Nice spacing between function/class declarations + +import dis +from array import array +from opcode import opname, opmap, HAVE_ARGUMENT, cmp_op +import inspect + +import struct +import sys + +# Masks for code object's co_flag attribute +VARARGS = 4 +VARKEYWORDS = 8 + +# Put opcode names in the global namespace +for name, val in opmap.items(): + globals()[name] = val + +# These opcodes will generate a statement. This is used in the first +# pass (in Code.find_else) to find which POP_JUMP_IF_* instructions +# are jumps to the else clause of an if statement +stmt_opcodes = { + SETUP_LOOP, BREAK_LOOP, CONTINUE_LOOP, + SETUP_FINALLY, END_FINALLY, + SETUP_EXCEPT, POP_EXCEPT, + SETUP_WITH, + POP_BLOCK, + STORE_FAST, DELETE_FAST, + STORE_DEREF, DELETE_DEREF, + STORE_GLOBAL, DELETE_GLOBAL, + STORE_NAME, DELETE_NAME, + STORE_ATTR, DELETE_ATTR, + IMPORT_NAME, IMPORT_FROM, + RETURN_VALUE, YIELD_VALUE, + RAISE_VARARGS, + POP_TOP, +} + +# Conditional branching opcode that make up if statements and and/or +# expressions +pop_jump_if_opcodes = (POP_JUMP_IF_TRUE, POP_JUMP_IF_FALSE) + +# These opcodes indicate that a pop_jump_if_x to the address just +# after them is an else-jump +else_jump_opcodes = ( + JUMP_FORWARD, RETURN_VALUE, JUMP_ABSOLUTE, + SETUP_LOOP, RAISE_VARARGS, POP_TOP +) + +# These opcodes indicate for loop rather than while loop +for_jump_opcodes = ( + GET_ITER, FOR_ITER, GET_ANEXT +) + + +def read_code(stream): + # This helper is needed in order for the PEP 302 emulation to + # correctly handle compiled files + # Note: stream must be opened in "rb" mode + import marshal + + if sys.version_info < (3, 4): + import imp + runtime_magic = imp.get_magic() + else: + import importlib.util + runtime_magic = importlib.util.MAGIC_NUMBER + + magic = stream.read(4) + if magic != runtime_magic: + print("*** Warning: file has wrong magic number ***") + + flags = 0 + if sys.version_info >= (3, 7): + flags = struct.unpack('i', stream.read(4))[0] + + if flags & 1: + stream.read(4) + stream.read(4) + else: + stream.read(4) # Skip timestamp + if sys.version_info >= (3, 3): + stream.read(4) # Skip rawsize + return marshal.load(stream) + + +def dec_module(path): + if path.endswith(".py"): + if sys.version_info < (3, 6): + import imp + path = imp.cache_from_source(path) + else: + import importlib.util + path = importlib.util.cache_from_source(path) + elif not path.endswith(".pyc") and not path.endswith(".pyo"): + raise ValueError("path must point to a .py or .pyc file") + with open(path, "rb") as stream: + code_obj = read_code(stream) + code = Code(code_obj) + return code.get_suite(include_declarations=False, look_for_docstring=True) + + +def decompile(obj): + """ + Decompile obj if it is a module object, a function or a + code object. If obj is a string, it is assumed to be the path + to a python module. + """ + if isinstance(obj, str): + return dec_module(obj) + if inspect.iscode(obj): + code = Code(obj) + return code.get_suite() + if inspect.isfunction(obj): + code = Code(obj.__code__) + defaults = obj.__defaults__ + kwdefaults = obj.__kwdefaults__ + return DefStatement(code, defaults, kwdefaults, obj.__closure__) + elif inspect.ismodule(obj): + return dec_module(obj.__file__) + else: + msg = "Object must be string, module, function or code object" + raise TypeError(msg) + + +class Indent: + def __init__(self, indent_level=0, indent_step=4): + self.level = indent_level + self.step = indent_step + + def write(self, pattern, *args, **kwargs): + if args or kwargs: + pattern = pattern.format(*args, **kwargs) + return self.indent(pattern) + + def __add__(self, indent_increase): + return type(self)(self.level + indent_increase, self.step) + + +class IndentPrint(Indent): + def indent(self, string): + print(" " * self.step * self.level + string) + + +class IndentString(Indent): + def __init__(self, indent_level=0, indent_step=4, lines=None): + Indent.__init__(self, indent_level, indent_step) + if lines is None: + self.lines = [] + else: + self.lines = lines + + def __add__(self, indent_increase): + return type(self)(self.level + indent_increase, self.step, self.lines) + + def sep(self): + if not self.lines or self.lines[-1]: + self.lines.append("") + + def indent(self, string): + self.lines.append(" " * self.step * self.level + string) + + def __str__(self): + return "\n".join(self.lines) + + +class Stack: + def __init__(self): + self._stack = [] + self._counts = {} + + def __bool__(self): + return bool(self._stack) + + def __len__(self): + return len(self._stack) + + def __contains__(self, val): + return self.get_count(val) > 0 + + def get_count(self, obj): + return self._counts.get(id(obj), 0) + + def set_count(self, obj, val): + if val: + self._counts[id(obj)] = val + else: + del self._counts[id(obj)] + + def pop1(self): + val = None + if self._stack: + val = self._stack.pop() + else: + raise Exception('Empty stack popped!') + self.set_count(val, self.get_count(val) - 1) + return val + + def pop(self, count=None): + if count is None: + val = self.pop1() + return val + else: + vals = [self.pop1() for i in range(count)] + vals.reverse() + return vals + + def push(self, *args): + for val in args: + self.set_count(val, self.get_count(val) + 1) + self._stack.append(val) + + def peek(self, count=None): + if count is None: + return self._stack[-1] + else: + return self._stack[-count:] + + +def code_walker(code): + l = len(code) + code = array('B', code) + oparg = 0 + i = 0 + extended_arg = 0 + + while i < l: + op = code[i] + offset = 1 + if sys.version_info >= (3, 6): + oparg = code[i + offset] + offset += 1 + elif op >= HAVE_ARGUMENT: + oparg = code[i + offset] + code[i + offset + 1] * 256 + extended_arg + extended_arg = 0 + offset += 2 + if op == EXTENDED_ARG: + if sys.version_info >= (3, 6): + op = code[i + offset] + offset += 1 + oparg <<= 8 + oparg |= code[i + offset] + offset += 1 + else: + extended_arg = oparg * 65536 + yield i, (op, oparg) + i += offset + + +class CodeFlags(object): + def __init__(self, cf): + self.flags = cf + + @property + def optimized(self): + return self.flags & 0x1 + + @property + def new_local(self): + return self.flags & 0x2 + + @property + def varargs(self): + return self.flags & 0x4 + + @property + def varkwargs(self): + return self.flags & 0x8 + @property + def nested(self): + return self.flags & 0x10 + + @property + def generator(self): + return self.flags & 0x20 + + @property + def no_free(self): + return self.flags & 0x40 + + @property + def coroutine(self): + return self.flags & 0x80 + + @property + def iterable_coroutine(self): + return self.flags & 0x100 + + @property + def async_generator(self): + return self.flags & 0x200 + + +class Code: + def __init__(self, code_obj, parent=None): + self.code_obj = code_obj + self.parent = parent + self.derefnames = [PyName(v) + for v in code_obj.co_cellvars + code_obj.co_freevars] + self.consts = list(map(PyConst, code_obj.co_consts)) + self.names = list(map(PyName, code_obj.co_names)) + self.varnames = list(map(PyName, code_obj.co_varnames)) + self.instr_seq = list(code_walker(code_obj.co_code)) + self.instr_map = {addr: i for i, (addr, _) in enumerate(self.instr_seq)} + self.name = code_obj.co_name + self.globals = [] + self.nonlocals = [] + self.jump_targets = [] + self.find_else() + self.find_jumps() + trace('================================================') + trace(self.code_obj) + trace('================================================') + for addr in self: + trace(str(addr)) + if addr.opcode in stmt_opcodes or addr.opcode in pop_jump_if_opcodes: + trace(' ') + trace('================================================') + self.flags: CodeFlags = CodeFlags(code_obj.co_flags) + + def __getitem__(self, instr_index): + if 0 <= instr_index < len(self.instr_seq): + return Address(self, instr_index) + + def __iter__(self): + for i in range(len(self.instr_seq)): + yield Address(self, i) + + def show(self): + for addr in self: + print(addr) + + def address(self, addr): + return self[self.instr_map[addr]] + + def iscellvar(self, i): + return i < len(self.code_obj.co_cellvars) + + def find_jumps(self): + for addr in self: + opcode, arg = addr + jt = addr.jump() + if jt: + self.jump_targets.append(jt) + + def find_else(self): + jumps = {} + last_jump = None + for addr in self: + opcode, arg = addr + if opcode in pop_jump_if_opcodes: + jump_addr = self.address(arg) + if (jump_addr[-1].opcode in else_jump_opcodes + or jump_addr.opcode == FOR_ITER): + last_jump = addr + jumps[jump_addr] = addr + elif opcode == JUMP_ABSOLUTE: + # This case is to deal with some nested ifs such as: + # if a: + # if b: + # f() + # elif c: + # g() + jump_addr = self.address(arg) + if jump_addr in jumps: + jumps[addr] = jumps[jump_addr] + elif opcode == JUMP_FORWARD: + jump_addr = addr[1] + arg + if jump_addr in jumps: + jumps[addr] = jumps[jump_addr] + elif opcode in stmt_opcodes and last_jump is not None: + # This opcode will generate a statement, so it means + # that the last POP_JUMP_IF_x was an else-jump + jumps[addr] = last_jump + self.else_jumps = set(jumps.values()) + + def get_suite(self, include_declarations=True, look_for_docstring=False) -> Suite: + dec = SuiteDecompiler(self[0]) + dec.run() + first_stmt = dec.suite and dec.suite[0] + # Change __doc__ = "docstring" to "docstring" + if look_for_docstring and isinstance(first_stmt, AssignStatement): + chain = first_stmt.chain + if len(chain) == 2 and str(chain[0]) == "__doc__": + dec.suite[0] = DocString(first_stmt.chain[1].val) + if include_declarations and (self.globals or self.nonlocals): + suite = Suite() + if self.globals: + stmt = "global " + ", ".join(map(str, self.globals)) + suite.add_statement(SimpleStatement(stmt)) + if self.nonlocals: + stmt = "nonlocal " + ", ".join(map(str, self.nonlocals)) + suite.add_statement(SimpleStatement(stmt)) + for stmt in dec.suite: + suite.add_statement(stmt) + return suite + else: + return dec.suite + + def declare_global(self, name): + """ + Declare name as a global. Called by STORE_GLOBAL and + DELETE_GLOBAL + """ + if name not in self.globals: + self.globals.append(name) + + def ensure_global(self, name): + """ + Declare name as global only if it is also a local variable + name in one of the surrounding code objects. This is called + by LOAD_GLOBAL + """ + parent = self.parent + while parent: + if name in parent.varnames: + return self.declare_global(name) + parent = parent.parent + + def declare_nonlocal(self, name): + """ + Declare name as nonlocal. Called by STORE_DEREF and + DELETE_DEREF (but only when the name denotes a free variable, + not a cell one). + """ + if name not in self.nonlocals: + self.nonlocals.append(name) + + + +class Address: + def __init__(self, code, instr_index): + self.code = code + self.index = instr_index + self.addr, (self.opcode, self.arg) = code.instr_seq[instr_index] + + def __eq__(self, other): + return (isinstance(other, type(self)) + and self.code == other.code and self.index == other.index) + + def __lt__(self, other): + return other is None or (isinstance(other, type(self)) + and self.code == other.code and self.index < other.index) + + def __str__(self): + mark = "* " if self in self.code.else_jumps else " " + jump = self.jump() + jt = '>>' if self.is_jump_target() else ' ' + arg = self.arg or " " + jdest = '\t(to {})'.format(jump.addr) if jump and jump.addr != self.arg else '' + val = '' + op = opname[self.opcode].ljust(18, ' ') + try: + + val = self.code.globals[self.arg] and self.arg + 1 < len(self.code.globals) if 'GLOBAL' in op else \ + self.code.names[self.arg] if 'ATTR' in op else \ + self.code.names[self.arg] if 'NAME' in op else \ + self.code.names[self.arg] if 'LOAD_METHOD' in op else \ + self.code.consts[self.arg] if 'CONST' in op else \ + self.code.varnames[self.arg] if 'FAST' in op else \ + self.code.derefnames[self.arg] if 'DEREF' in op else \ + cmp_op[self.arg] if 'COMPARE' in op else '' + if val != '': + val = '\t({})'.format(val) + except: + pass + + return "{}{}\t{}\t{}\t{}{}{}".format( + jt, + mark, + self.addr, + op, + arg, + jdest, + val + ) + + def __add__(self, delta): + return self.code.address(self.addr + delta) + + def __getitem__(self, index): + return self.code[self.index + index] + + def __iter__(self): + yield self.opcode + yield self.arg + + def __hash__(self): + return hash((self.code, self.index)) + + def is_else_jump(self): + return self in self.code.else_jumps + + def is_jump_target(self): + return self in self.code.jump_targets + + def change_instr(self, opcode, arg=None): + self.code.instr_seq[self.index] = (self.addr, (opcode, arg)) + + def jump(self) -> Address: + opcode = self.opcode + if opcode in dis.hasjrel: + return self[1] + self.arg + elif opcode in dis.hasjabs: + return self.code.address(self.arg) + + def seek(self, opcode: tuple, increment: int, end: Address = None) -> Address: + if not isinstance(opcode, tuple): + opcode = (opcode,) + a = self[increment] + while a and a != end: + if a.opcode in opcode: + return a + a = a[increment] + + def seek_back(self, opcode: Union[tuple,int], end: Address = None) -> Address: + return self.seek(opcode, -1, end) + + def seek_forward(self, opcode: Union[tuple,int], end: Address = None) -> Address: + return self.seek(opcode, 1, end) + + +class AsyncMixin: + def __init__(self): + self.is_async = False + + @property + def async_prefix(self): + return 'async ' if self.is_async else '' + + +class AwaitableMixin: + + def __init__(self): + self.is_awaited = False + + @property + def await_prefix(self): + return 'await ' if self.is_awaited else '' + + +class PyExpr: + def wrap(self, condition=True): + if condition: + return "({})".format(self) + else: + return str(self) + + def store(self, dec, dest): + chain = dec.assignment_chain + chain.append(dest) + if self not in dec.stack: + chain.append(self) + dec.suite.add_statement(AssignStatement(chain)) + dec.assignment_chain = [] + + def on_pop(self, dec): + dec.write(str(self)) + + +class PyConst(PyExpr): + precedence = 100 + + def __init__(self, val): + self.val = val + + def __str__(self): + return repr(self.val) + + def __iter__(self): + return iter(self.val) + + def __eq__(self, other): + return isinstance(other, PyConst) and self.val == other.val + + +class PyFormatValue(PyConst): + def __str__(self): + return f'{{{self.val}}}' + + +class PyFormatString(PyExpr): + precedence = 100 + + def __init__(self, params): + super().__init__() + self.params = params + + def __str__(self): + return "f'{}'".format(''.join([str(p) if isinstance(p, PyFormatValue) else str(p.val) for p in self.params])) + + +class PyTuple(PyExpr): + precedence = 0 + + def __init__(self, values): + self.values = values + + def __str__(self): + if not self.values: + return "()" + valstr = [val.wrap(val.precedence <= self.precedence) + for val in self.values] + if len(valstr) == 1: + return '(' + valstr[0] + "," + ')' + else: + return '(' + ", ".join(valstr) + ')' + + def __iter__(self): + return iter(self.values) + + def wrap(self, condition=True): + return str(self) + + +class PyList(PyExpr): + precedence = 16 + + def __init__(self, values): + self.values = values + + def __str__(self): + valstr = ", ".join(val.wrap(val.precedence <= 0) + for val in self.values) + return "[{}]".format(valstr) + + def __iter__(self): + return iter(self.values) + + +class PySet(PyExpr): + precedence = 16 + + def __init__(self, values): + self.values = values + + def __str__(self): + valstr = ", ".join(val.wrap(val.precedence <= 0) + for val in self.values) + return "{{{}}}".format(valstr) + + def __iter__(self): + return iter(self.values) + + +class PyDict(PyExpr): + precedence = 16 + + def __init__(self): + self.items = [] + + def set_item(self, key, val): + self.items.append((key, val)) + + def __str__(self): + itemstr = ", ".join("{}: {}".format(*kv) for kv in self.items) + return "{{{}}}".format(itemstr) + + +class PyName(PyExpr): + precedence = 100 + + def __init__(self, name): + self.name = name + + def __str__(self): + return self.name + + def __eq__(self, other): + return isinstance(other, type(self)) and self.name == other.name + + +class PyUnaryOp(PyExpr): + def __init__(self, operand): + self.operand = operand + + def __str__(self): + opstr = self.operand.wrap(self.operand.precedence < self.precedence) + return self.pattern.format(opstr) + + @classmethod + def instr(cls, stack): + stack.push(cls(stack.pop())) + + +class PyBinaryOp(PyExpr): + def __init__(self, left, right): + self.left = left + self.right = right + + def wrap_left(self): + return self.left.wrap(self.left.precedence < self.precedence) + + def wrap_right(self): + return self.right.wrap(self.right.precedence <= self.precedence) + + def __str__(self): + return self.pattern.format(self.wrap_left(), self.wrap_right()) + + @classmethod + def instr(cls, stack): + right = stack.pop() + left = stack.pop() + stack.push(cls(left, right)) + + +class PySubscript(PyBinaryOp): + precedence = 15 + pattern = "{}[{}]" + + def wrap_right(self): + return str(self.right) + + +class PySlice(PyExpr): + precedence = 1 + + def __init__(self, args): + assert len(args) in (2, 3) + if len(args) == 2: + self.start, self.stop = args + self.step = None + else: + self.start, self.stop, self.step = args + if self.start == PyConst(None): + self.start = "" + if self.stop == PyConst(None): + self.stop = "" + + def __str__(self): + if self.step is None: + return "{}:{}".format(self.start, self.stop) + else: + return "{}:{}:{}".format(self.start, self.stop, self.step) + + +class PyCompare(PyExpr): + precedence = 6 + + def __init__(self, complist): + self.complist = complist + + def __str__(self): + return " ".join(x if i % 2 else x.wrap(x.precedence <= 0) + for i, x in enumerate(self.complist)) + + def extends(self, other): + if not isinstance(other, PyCompare): + return False + else: + return self.complist[0] == other.complist[-1] + + def chain(self, other): + return PyCompare(self.complist + other.complist[1:]) + + +class PyBooleanAnd(PyBinaryOp): + precedence = 4 + pattern = "{} and {}" + + +class PyBooleanOr(PyBinaryOp): + precedence = 3 + pattern = "{} or {}" + + +class PyIfElse(PyExpr): + precedence = 2 + + def __init__(self, cond, true_expr, false_expr): + self.cond = cond + self.true_expr = true_expr + self.false_expr = false_expr + + def __str__(self): + p = self.precedence + cond_str = self.cond.wrap(self.cond.precedence <= p) + true_str = self.true_expr.wrap(self.cond.precedence <= p) + false_str = self.false_expr.wrap(self.cond.precedence < p) + return "{} if {} else {}".format(true_str, cond_str, false_str) + + +class PyAttribute(PyExpr): + precedence = 15 + + def __init__(self, expr, attrname): + self.expr = expr + self.attrname = attrname + + def __str__(self): + expr_str = self.expr.wrap(self.expr.precedence < self.precedence) + return "{}.{}".format(expr_str, self.attrname) + + +class PyCallFunction(PyExpr, AwaitableMixin): + precedence = 15 + + def __init__(self, func: PyAttribute, args: list, kwargs: list, varargs=None, varkw=None): + AwaitableMixin.__init__(self) + self.func = func + self.args = args + self.kwargs = kwargs + self.varargs = varargs + self.varkw = varkw + + def __str__(self): + funcstr = self.func.wrap(self.func.precedence < self.precedence) + if hasattr(self.args, '__iter__') and len(self.args) == 1 and not (self.kwargs or self.varargs + or self.varkw): + arg = self.args[0] + if isinstance(arg, PyGenExpr): + # Only one pair of brackets arount a single arg genexpr + return "{}{}".format(funcstr, arg) + args = [x.wrap(x.precedence <= 0) for x in self.args] + if self.varargs is not None: + args.append("*{}".format(self.varargs)) + args.extend("{}={}".format(str(k).replace('\'', ''), v.wrap(v.precedence <= 0)) + for k, v in self.kwargs) + if self.varkw is not None: + args.append("**{}".format(self.varkw)) + return "{}{}({})".format(self.await_prefix, funcstr, ", ".join(args)) + + +class FunctionDefinition: + def __init__(self, code: Code, defaults, kwdefaults, closure, paramobjs=None, annotations=None): + self.code = code + self.defaults = defaults + self.kwdefaults = kwdefaults + self.closure = closure + self.paramobjs = paramobjs if paramobjs else {} + self.annotations = annotations if annotations else [] + + def is_coroutine(self): + return self.code.code_obj.co_flags & 0x100 + + def getparams(self): + code_obj = self.code.code_obj + l = code_obj.co_argcount + params = [] + for name in code_obj.co_varnames[:l]: + if name in self.paramobjs: + params.append('{}:{}'.format(name, str(self.paramobjs[name]))) + else: + params.append(name) + if self.defaults: + for i, arg in enumerate(reversed(self.defaults)): + name = params[-i - 1] + if name in self.paramobjs: + params[-i - 1] = "{}:{}={}".format(name, str(self.paramobjs[name]), arg) + else: + params[-i - 1] = "{}={}".format(name, arg) + kwcount = code_obj.co_kwonlyargcount + kwparams = [] + if kwcount: + for i in range(kwcount): + name = code_obj.co_varnames[l + i] + if name in self.kwdefaults and name in self.paramobjs: + kwparams.append("{}:{}={}".format(name, self.paramobjs[name], self.kwdefaults[name])) + elif name in self.kwdefaults: + kwparams.append("{}={}".format(name, self.kwdefaults[name])) + else: + kwparams.append(name) + l += kwcount + if code_obj.co_flags & VARARGS: + params.append("*" + code_obj.co_varnames[l]) + l += 1 + elif kwparams: + params.append("*") + params.extend(kwparams) + if code_obj.co_flags & VARKEYWORDS: + params.append("**" + code_obj.co_varnames[l]) + + return params + + def getreturn(self): + if self.paramobjs and 'return' in self.paramobjs: + return self.paramobjs['return'] + return None + + +class PyLambda(PyExpr, FunctionDefinition): + precedence = 1 + + def __str__(self): + suite = self.code.get_suite() + params = ", ".join(self.getparams()) + if len(suite.statements) > 0: + def strip_return(val): + return val[len("return "):] if val.startswith('return') else val + + if isinstance(suite[0], IfStatement): + end = suite[1] if len(suite) > 1 else PyConst(None) + expr = "{} if {} else {}".format( + strip_return(str(suite[0].true_suite)), + str(suite[0].cond), + strip_return(str(end)) + ) + else: + expr = strip_return(str(suite[0])) + else: + expr = "None" + return "lambda {}: {}".format(params, expr) + + +class PyComp(PyExpr): + """ + Abstraction for list, set, dict comprehensions and generator expressions + """ + precedence = 16 + + def __init__(self, code, defaults, kwdefaults, closure, paramobjs={}, annotations=[]): + assert not defaults and not kwdefaults + self.code = code + code[0].change_instr(NOP) + last_i = len(code.instr_seq) - 1 + code[last_i].change_instr(NOP) + self.annotations = annotations + + def set_iterable(self, iterable): + self.code.varnames[0] = iterable + + def __str__(self): + suite = self.code.get_suite() + return self.pattern.format(suite.gen_display()) + + +class PyListComp(PyComp): + pattern = "[{}]" + + +class PySetComp(PyComp): + pattern = "{{{}}}" + + +class PyKeyValue(PyBinaryOp): + """This is only to create dict comprehensions""" + precedence = 1 + pattern = "{}: {}" + + +class PyDictComp(PyComp): + pattern = "{{{}}}" + + +class PyGenExpr(PyComp): + precedence = 16 + pattern = "({})" + + def __init__(self, code, defaults, kwdefaults, closure, paramobjs={}, annotations=[]): + self.code = code + + +class PyYield(PyExpr): + precedence = 1 + + def __init__(self, value): + self.value = value + + def __str__(self): + return "yield {}".format(self.value) + + +class PyYieldFrom(PyExpr): + precedence = 1 + + def __init__(self, value): + self.value = value + + def __str__(self): + return "yield from {}".format(self.value) + + +class PyStarred(PyExpr): + """Used in unpacking assigments""" + precedence = 15 + + def __init__(self, expr): + self.expr = expr + + def __str__(self): + es = self.expr.wrap(self.expr.precedence < self.precedence) + return "*{}".format(es) + + +code_map = { + '': PyLambda, + '': PyListComp, + '': PySetComp, + '': PyDictComp, + '': PyGenExpr, +} + +unary_ops = [ + ('UNARY_POSITIVE', 'Positive', '+{}', 13), + ('UNARY_NEGATIVE', 'Negative', '-{}', 13), + ('UNARY_NOT', 'Not', 'not {}', 5), + ('UNARY_INVERT', 'Invert', '~{}', 13), +] + +binary_ops = [ + ('POWER', 'Power', '{}**{}', 14, '{} **= {}'), + ('MULTIPLY', 'Multiply', '{}*{}', 12, '{} *= {}'), + ('FLOOR_DIVIDE', 'FloorDivide', '{}//{}', 12, '{} //= {}'), + ('TRUE_DIVIDE', 'TrueDivide', '{}/{}', 12, '{} /= {}'), + ('MODULO', 'Modulo', '{} % {}', 12, '{} %= {}'), + ('ADD', 'Add', '{} + {}', 11, '{} += {}'), + ('SUBTRACT', 'Subtract', '{} - {}', 11, '{} -= {}'), + ('SUBSCR', 'Subscript', '{}[{}]', 15, None), + ('LSHIFT', 'LeftShift', '{} << {}', 10, '{} <<= {}'), + ('RSHIFT', 'RightShift', '{} >> {}', 10, '{} >>= {}'), + ('AND', 'And', '{} & {}', 9, '{} &= {}'), + ('XOR', 'Xor', '{} ^ {}', 8, '{} ^= {}'), + ('OR', 'Or', '{} | {}', 7, '{} |= {}'), + ('MATRIX_MULTIPLY', 'MatrixMultiply', '{} @ {}', 12, '{} @= {}'), +] + + +class PyStatement(object): + def __str__(self): + istr = IndentString() + self.display(istr) + return str(istr) + + def wrap(self, condition=True): + if condition: + assert not condition + return "({})".format(self) + else: + return str(self) + + def on_pop(self, dec): + # dec.write("#ERROR: Unexpected context 'on_pop': pop on statement: ") + pass + + +class DocString(PyStatement): + def __init__(self, string): + self.string = string + + def display(self, indent): + if '\n' not in self.string: + indent.write(repr(self.string)) + else: + if "'''" not in self.string: + fence = "'''" + elif '"""' not in self.string: + fence = '"""' + else: + raise NotImplemented + lines = self.string.split('\n') + text = '\n'.join(l.encode('unicode_escape').decode() + for l in lines) + docstring = "{0}{1}{0}".format(fence, text) + indent.write(docstring) + + +class AssignStatement(PyStatement): + def __init__(self, chain): + self.chain = chain + + def display(self, indent): + indent.write(" = ".join(map(str, self.chain))) + + +class InPlaceOp(PyStatement): + def __init__(self, left, right): + self.right = right + self.left = left + + def store(self, dec, dest): + # assert dest is self.left + dec.suite.add_statement(self) + + def display(self, indent): + indent.write(self.pattern, self.left, self.right) + + @classmethod + def instr(cls, stack): + right = stack.pop() + left = stack.pop() + stack.push(cls(left, right)) + + +class Unpack: + precedence = 50 + + def __init__(self, val, length, star_index=None): + self.val = val + self.length = length + self.star_index = star_index + self.dests = [] + + def store(self, dec, dest): + if len(self.dests) == self.star_index: + dest = PyStarred(dest) + self.dests.append(dest) + if len(self.dests) == self.length: + dec.stack.push(self.val) + dec.store(PyTuple(self.dests)) + + +class ImportStatement(PyStatement): + alias = "" + precedence = 100 + + def __init__(self, name, level, fromlist): + self.name = name + self.alias = name + self.level = level + self.fromlist = fromlist + self.aslist = [] + + def store(self, dec: SuiteDecompiler, dest): + self.alias = dest + dec.suite.add_statement(self) + + def on_pop(self, dec): + dec.suite.add_statement(self) + + def display(self, indent): + if self.fromlist == PyConst(None): + name = self.name.name + alias = self.alias.name + if name == alias or name.startswith(alias + "."): + indent.write("import {}", name) + else: + indent.write("import {} as {}", name, alias) + elif self.fromlist == PyConst(('*',)): + indent.write("from {} import *", self.name.name) + else: + names = [] + for name, alias in zip(self.fromlist, self.aslist): + if name == alias: + names.append(name) + else: + names.append("{} as {}".format(name, alias)) + indent.write("from {} import {}", self.name, ", ".join(names)) + + +class ImportFrom: + def __init__(self, name): + self.name = name + + def store(self, dec, dest): + imp = dec.stack.peek() + assert isinstance(imp, ImportStatement) + + if imp.fromlist != PyConst(None): + + imp.aslist.append(dest.name) + else: + imp.alias = dest + + +class SimpleStatement(PyStatement): + def __init__(self, val): + assert val is not None + self.val = val + + def display(self, indent): + indent.write(self.val) + + def gen_display(self, seq=()): + return " ".join((self.val,) + seq) + + +class IfStatement(PyStatement): + def __init__(self, cond, true_suite, false_suite): + self.cond = cond + self.true_suite = true_suite + self.false_suite = false_suite + + def display(self, indent, is_elif=False): + ptn = "elif {}:" if is_elif else "if {}:" + indent.write(ptn, self.cond) + self.true_suite.display(indent + 1) + if not self.false_suite: + return + if len(self.false_suite) == 1: + stmt = self.false_suite[0] + if isinstance(stmt, IfStatement): + stmt.display(indent, is_elif=True) + return + indent.write("else:") + self.false_suite.display(indent + 1) + + def gen_display(self, seq=()): + s = "if {}".format(self.cond) + return self.true_suite.gen_display(seq + (s,)) + + +class ForStatement(PyStatement, AsyncMixin): + def __init__(self, iterable): + AsyncMixin.__init__(self) + self.iterable = iterable + + def store(self, dec, dest): + self.dest = dest + + def display(self, indent): + indent.write("{}for {} in {}:", self.async_prefix, self.dest, self.iterable) + self.body.display(indent + 1) + + def gen_display(self, seq=()): + s = "{}for {} in {}".format(self.async_prefix, self.dest, self.iterable.wrap() if isinstance(self.iterable, PyIfElse) else self.iterable) + return self.body.gen_display(seq + (s,)) + + +class WhileStatement(PyStatement): + def __init__(self, cond, body): + self.cond = cond + self.body = body + + def display(self, indent): + indent.write("while {}:", self.cond) + self.body.display(indent + 1) + + +class DecorableStatement(PyStatement): + def __init__(self): + self.decorators = [] + + def display(self, indent): + indent.sep() + for f in reversed(self.decorators): + indent.write("@{}", f) + self.display_undecorated(indent) + indent.sep() + + def decorate(self, f): + self.decorators.append(f) + + +class DefStatement(FunctionDefinition, DecorableStatement, AsyncMixin): + def __init__(self, code: Code, defaults, kwdefaults, closure, paramobjs=None, annotations=None): + FunctionDefinition.__init__(self, code, defaults, kwdefaults, closure, paramobjs, annotations) + DecorableStatement.__init__(self) + AsyncMixin.__init__(self) + self.is_async = code.flags.coroutine + + def display_undecorated(self, indent): + paramlist = ", ".join(self.getparams()) + result = self.getreturn() + if result: + indent.write("{}def {}({}) -> {}:", self.async_prefix, self.code.name, paramlist, result) + else: + indent.write("{}def {}({}):", self.async_prefix, self.code.name, paramlist) + # Assume that co_consts starts with None unless the function + # has a docstring, in which case it starts with the docstring + if self.code.consts[0] != PyConst(None): + docstring = self.code.consts[0].val + DocString(docstring).display(indent + 1) + self.code.get_suite().display(indent + 1) + + def store(self, dec, dest): + self.name = dest + dec.suite.add_statement(self) + + +class TryStatement(PyStatement): + def __init__(self, try_suite): + self.try_suite = try_suite + self.except_clauses = [] + + def add_except_clause(self, type, suite): + self.except_clauses.append([type, None, suite]) + + def store(self, dec, dest): + self.except_clauses[-1][1] = dest + + def display(self, indent): + indent.write("try:") + self.try_suite.display(indent + 1) + for type, name, suite in self.except_clauses: + if type is None: + indent.write("except:") + elif name is None: + indent.write("except {}:", type) + else: + indent.write("except {} as {}:", type, name) + suite.display(indent + 1) + + +class FinallyStatement(PyStatement): + def __init__(self, try_suite, finally_suite): + self.try_suite = try_suite + self.finally_suite = finally_suite + + def display(self, indent): + # Wrap the try suite in a TryStatement if necessary + try_stmt = None + if len(self.try_suite) == 1: + try_stmt = self.try_suite[0] + if not isinstance(try_stmt, TryStatement): + try_stmt = None + if try_stmt is None: + try_stmt = TryStatement(self.try_suite) + try_stmt.display(indent) + indent.write("finally:") + self.finally_suite.display(indent + 1) + + +class WithStatement(PyStatement): + def __init__(self, with_expr): + self.with_expr = with_expr + self.with_name = None + self.is_async = False + + @property + def async_prefix(self): + return 'async ' if self.is_async else '' + + def store(self, dec, dest): + self.with_name = dest + + def display(self, indent, args=None): + # args to take care of nested withs: + # with x as t: + # with y as u: + # + # ---> + # with x as t, y as u: + # + if args is None: + args = [] + if self.with_name is None: + args.append(str(self.with_expr)) + else: + args.append("{} as {}".format(self.with_expr, self.with_name)) + if len(self.suite) == 1 and isinstance(self.suite[0], WithStatement): + self.suite[0].display(indent, args) + else: + indent.write(self.async_prefix + "with {}:", ", ".join(args)) + self.suite.display(indent + 1) + + +class ClassStatement(DecorableStatement): + def __init__(self, func, name, parents, kwargs): + DecorableStatement.__init__(self) + self.func = func + self.parents = parents + self.kwargs = kwargs + + def store(self, dec, dest): + self.name = dest + dec.suite.add_statement(self) + + def display_undecorated(self, indent): + if self.parents or self.kwargs: + args = [str(x) for x in self.parents] + kwargs = ["{}={}".format(str(k).replace('\'', ''), v) for k, v in self.kwargs] + all_args = ", ".join(args + kwargs) + indent.write("class {}({}):", self.name, all_args) + else: + indent.write("class {}:", self.name) + suite = self.func.code.get_suite(look_for_docstring=True) + if suite: + # TODO: find out why sometimes the class suite ends with + # "return __class__" + last_stmt = suite[-1] + if isinstance(last_stmt, SimpleStatement): + if last_stmt.val.startswith("return "): + suite.statements.pop() + clean_vars = ['__module__', '__qualname__'] + for clean_var in clean_vars: + for i in range(len(suite.statements)): + stmt = suite.statements[i] + if isinstance(stmt, AssignStatement) and str(stmt).startswith(clean_var): + suite.statements.pop(i) + break + + suite.display(indent + 1) + + +class Suite: + def __init__(self): + self.statements = [] + + def __bool__(self): + return bool(self.statements) + + def __len__(self): + return len(self.statements) + + def __getitem__(self, i): + return self.statements[i] + + def __setitem__(self, i, val): + self.statements[i] = val + + def __str__(self): + istr = IndentString() + self.display(istr) + return str(istr) + + def display(self, indent): + if self.statements: + for stmt in self.statements: + stmt.display(indent) + else: + indent.write("pass") + + def gen_display(self, seq=()): + completed = ' '.join(seq) + # This is to fix a line in dataclasses.py + if completed == 'for f in fields.values() if f._field_type is _FIELD': + return '[f for f in fields.values() if f._field_type is _FIELD]' + if len(self) < 1: + # This is to fix a line in dataclasses.py + if completed == 'for f in fields if f.hash is None': + return 'f for f in fields if f.hash is None' + return ' '.join(seq) + return self[0].gen_display(seq) + + def add_statement(self, stmt): + self.statements.append(stmt) + + +class SuiteDecompiler: + # An instruction handler can return this to indicate to the run() + # function that it should return immediately + END_NOW = object() + + # This is put on the stack by LOAD_BUILD_CLASS + BUILD_CLASS = object() + + def __init__(self, start_addr, end_addr=None, stack=None): + self.start_addr = start_addr + self.end_addr = end_addr + self.code: Code = start_addr.code + self.stack = Stack() if stack is None else stack + self.suite = Suite() + self.assignment_chain = [] + self.popjump_stack = [] + + def push_popjump(self, jtruthiness, jaddr, jcond): + stack = self.popjump_stack + if jaddr and jaddr[-1].is_else_jump(): + # Increase jaddr to the 'else' address if it jumps to the 'then' + jaddr = jaddr[-1].jump() + while stack: + truthiness, addr, cond = stack[-1] + # if jaddr == None: + # raise Exception("#ERROR: jaddr is None") + # jaddr == None \ + if jaddr and jaddr < addr or jaddr == addr: + break + stack.pop() + obj_maker = PyBooleanOr if truthiness else PyBooleanAnd + if isinstance(jcond, obj_maker): + # Use associativity of 'and' and 'or' to minimise the + # number of parentheses + jcond = obj_maker(obj_maker(cond, jcond.left), jcond.right) + else: + jcond = obj_maker(cond, jcond) + stack.append((jtruthiness, jaddr, jcond)) + + def pop_popjump(self): + truthiness, addr, cond = self.popjump_stack.pop() + return cond + + def run(self): + addr, end_addr = self.start_addr, self.end_addr + while addr and addr < end_addr: + try: + opcode, arg = addr + method = getattr(self, opname[opcode]) + if opcode < HAVE_ARGUMENT: + new_addr = method(addr) + else: + new_addr = method(addr, arg) + if new_addr is self.END_NOW: + break + elif new_addr is None: + new_addr = addr[1] + addr = new_addr + except: + addr = addr[1] + continue + return addr + + def write(self, template, *args): + def fmt(x): + if isinstance(x, int): + return self.stack.getval(x) + else: + return x + + if args: + line = template.format(*map(fmt, args)) + else: + line = template + self.suite.add_statement(SimpleStatement(line)) + + def store(self, dest): + val = self.stack.pop() + val.store(self, dest) + + def is_for_loop(self, addr, end_addr): + i = 0 + while 1: + cur_addr = addr[i] + if cur_addr == end_addr: + break + elif cur_addr.opcode in else_jump_opcodes: + cur_addr = cur_addr.jump() + if cur_addr and cur_addr.opcode in for_jump_opcodes: + return True + break + elif cur_addr.opcode in for_jump_opcodes: + return True + i = i + 1 + return False + + def scan_to_first_jump_if(self, addr: Address, end_addr: Address) -> Union[Address,None]: + i = 0 + while 1: + cur_addr = addr[i] + if cur_addr == end_addr: + break + elif cur_addr.opcode in pop_jump_if_opcodes: + return cur_addr + elif cur_addr.opcode in else_jump_opcodes: + break + elif cur_addr.opcode in for_jump_opcodes: + break + i = i + 1 + return None + + def scan_for_final_jump(self, start_addr, end_addr): + i = 0 + end = None + while 1: + cur_addr = end_addr[i] + if cur_addr == start_addr: + break + elif cur_addr.opcode == JUMP_ABSOLUTE: + end = cur_addr + return end + elif cur_addr.opcode in else_jump_opcodes: + break + elif cur_addr.opcode in pop_jump_if_opcodes: + break + i = i - 1 + return end + + # + # All opcode methods in CAPS below. + # + + def SETUP_LOOP(self, addr: Address, delta): + jump_addr = addr[1] + delta + end_addr = jump_addr[-1] + if end_addr.opcode == POP_BLOCK: # assume conditional + # scan to first jump + end_cond = self.scan_to_first_jump_if(addr[1], end_addr) + if end_cond and end_cond[1].opcode == BREAK_LOOP: + end_cond = None + if end_cond and end_cond.arg == addr.arg: + # scan for conditional + d_cond = SuiteDecompiler(addr[1], end_cond) + # + d_cond.run() + cond = d_cond.stack.pop() + if end_cond.opcode == POP_JUMP_IF_TRUE: + cond = PyNot(cond) + d_body = SuiteDecompiler(end_cond[1], end_addr) + while_stmt = WhileStatement(cond, d_body.suite) + d_body.stack.push(while_stmt) + d_body.run() + while_stmt.body = d_body.suite + self.suite.add_statement(while_stmt) + return jump_addr + elif (not end_cond or not end_cond.jump()[1] == addr.jump()) and not self.is_for_loop(addr[1], end_addr): + d_body = SuiteDecompiler(addr[1], end_addr) + while_stmt = WhileStatement(PyConst(True), d_body.suite) + d_body.stack.push(while_stmt) + d_body.run() + while_stmt.body = d_body.suite + self.suite.add_statement(while_stmt) + return jump_addr + return None + + def BREAK_LOOP(self, addr): + self.write("break") + + def CONTINUE_LOOP(self, addr, *argv): + self.write("continue") + + def SETUP_FINALLY(self, addr, delta): + start_finally = addr.jump() + d_try = SuiteDecompiler(addr[1], start_finally) + d_try.run() + d_finally = SuiteDecompiler(start_finally) + end_finally = d_finally.run() + self.suite.add_statement(FinallyStatement(d_try.suite, d_finally.suite)) + return end_finally[1] + + def END_FINALLY(self, addr): + return self.END_NOW + + def SETUP_EXCEPT(self, addr, delta): + start_except = addr.jump() + start_try = addr[1] + end_try = start_except + if sys.version_info < (3, 7): + if end_try.opcode == JUMP_FORWARD: + end_try = end_try[1] + end_try.arg + elif end_try.opcode == JUMP_ABSOLUTE: + end_try = end_try[-1] + else: + end_try = end_try[1] + d_try = SuiteDecompiler(start_try, end_try) + d_try.run() + + stmt = TryStatement(d_try.suite) + while start_except.opcode != END_FINALLY: + if start_except.opcode == DUP_TOP: + # There's a new except clause + d_except = SuiteDecompiler(start_except[1]) + d_except.stack.push(stmt) + d_except.run() + start_except = stmt.next_start_except + elif start_except.opcode == POP_TOP: + # It's a bare except clause - it starts: + # POP_TOP + # POP_TOP + # POP_TOP + # + # POP_EXCEPT + start_except = start_except[3] + end_except = start_except + + while end_except and end_except[-1].opcode != RETURN_VALUE: + if end_except.opcode == POP_EXCEPT: + break + end_except = end_except[1] + # Handle edge case where there is a return in the except + if end_except[-1].opcode == RETURN_VALUE: + d_except = SuiteDecompiler(start_except, end_except) + end_except = d_except.run() + stmt.add_except_clause(None, d_except.suite) + self.suite.add_statement(stmt) + return end_except + + d_except = SuiteDecompiler(start_except, end_except) + end_except = d_except.run() + stmt.add_except_clause(None, d_except.suite) + start_except = end_except[2] + assert start_except.opcode == END_FINALLY + self.suite.add_statement(stmt) + return start_except[1] + + def SETUP_WITH(self, addr, delta): + end_with = addr.jump() + with_stmt = WithStatement(self.stack.pop()) + d_with = SuiteDecompiler(addr[1], end_with) + d_with.stack.push(with_stmt) + d_with.run() + with_stmt.suite = d_with.suite + self.suite.add_statement(with_stmt) + if sys.version_info <= (3, 4): + assert end_with.opcode == WITH_CLEANUP + assert end_with[1].opcode == END_FINALLY + return end_with[2] + else: + assert end_with.opcode == WITH_CLEANUP_START + assert end_with[1].opcode == WITH_CLEANUP_FINISH + return end_with[3] + + def POP_BLOCK(self, addr): + pass + + def POP_EXCEPT(self, addr): + return self.END_NOW + + def NOP(self, addr): + return + + def COMPARE_OP(self, addr, compare_opname): + left, right = self.stack.pop(2) + if compare_opname != 10: # 10 is exception match + self.stack.push(PyCompare([left, cmp_op[compare_opname], right])) + else: + # It's an exception match + # left is a TryStatement + # right is the exception type to be matched + # It goes: + # COMPARE_OP 10 + # POP_JUMP_IF_FALSE + # POP_TOP + # POP_TOP or STORE_FAST (if the match is named) + # POP_TOP + # SETUP_FINALLY if the match was named + assert addr[1].opcode == POP_JUMP_IF_FALSE + left.next_start_except = addr[1].jump() + assert addr[2].opcode == POP_TOP + assert addr[4].opcode == POP_TOP + if addr[5].opcode == SETUP_FINALLY: + except_start = addr[6] + except_end = addr[5].jump() + else: + except_start = addr[5] + except_end = left.next_start_except + d_body = SuiteDecompiler(except_start, except_end) + d_body.run() + left.add_except_clause(right, d_body.suite) + if addr[3].opcode != POP_TOP: + # The exception is named + d_exc_name = SuiteDecompiler(addr[3], addr[4]) + d_exc_name.stack.push(left) + # This will store the name in left: + d_exc_name.run() + # We're done with this except clause + return self.END_NOW + + # + # Stack manipulation + # + + def POP_TOP(self, addr): + self.stack.pop().on_pop(self) + + def ROT_TWO(self, addr): + # special case: x, y = z, t + if addr[2] and addr[1].opcode == STORE_NAME and addr[2].opcode == STORE_NAME: + val = PyTuple(self.stack.pop(2)) + unpack = Unpack(val, 2) + self.stack.push(unpack) + self.stack.push(unpack) + else: + tos1, tos = self.stack.pop(2) + self.stack.push(tos, tos1) + + def ROT_THREE(self, addr): + tos2, tos1, tos = self.stack.pop(3) + self.stack.push(tos, tos2, tos1) + + def DUP_TOP(self, addr): + self.stack.push(self.stack.peek()) + + def DUP_TOP_TWO(self, addr): + self.stack.push(*self.stack.peek(2)) + + # + # LOAD / STORE / DELETE + # + + # FAST + + def LOAD_FAST(self, addr, var_num): + name = self.code.varnames[var_num] + self.stack.push(name) + + def STORE_FAST(self, addr, var_num): + name = self.code.varnames[var_num] + self.store(name) + + def DELETE_FAST(self, addr, var_num): + name = self.code.varnames[var_num] + self.write("del {}", name) + + # DEREF + + def LOAD_DEREF(self, addr, i): + name = self.code.derefnames[i] + self.stack.push(name) + + def LOAD_CLASSDEREF(self, addr, i): + name = self.code.derefnames[i] + self.stack.push(name) + + def STORE_DEREF(self, addr, i): + name = self.code.derefnames[i] + if not self.code.iscellvar(i): + self.code.declare_nonlocal(name) + self.store(name) + + def DELETE_DEREF(self, addr, i): + name = self.code.derefnames[i] + if not self.code.iscellvar(i): + self.code.declare_nonlocal(name) + self.write("del {}", name) + + # GLOBAL + + def LOAD_GLOBAL(self, addr, namei): + name = self.code.names[namei] + self.code.ensure_global(name) + self.stack.push(name) + + def STORE_GLOBAL(self, addr, namei): + name = self.code.names[namei] + self.code.declare_global(name) + self.store(name) + + def DELETE_GLOBAL(self, addr, namei): + name = self.code.names[namei] + self.declare_global(name) + self.write("del {}", name) + + # NAME + + def LOAD_NAME(self, addr, namei): + name = self.code.names[namei] + self.stack.push(name) + + def STORE_NAME(self, addr, namei): + name = self.code.names[namei] + self.store(name) + + def DELETE_NAME(self, addr, namei): + name = self.code.names[namei] + self.write("del {}", name) + + # METHOD + def LOAD_METHOD(self, addr, namei): + expr = self.stack.pop() + attrname = self.code.names[namei] + self.stack.push(PyAttribute(expr, attrname)) + + def CALL_METHOD(self, addr, argc, have_var=False, have_kw=False): + kw_argc = argc >> 8 + pos_argc = argc + varkw = self.stack.pop() if have_kw else None + varargs = self.stack.pop() if have_var else None + kwargs_iter = iter(self.stack.pop(2 * kw_argc)) + kwargs = list(zip(kwargs_iter, kwargs_iter)) + posargs = self.stack.pop(pos_argc) + func = self.stack.pop() + if func is self.BUILD_CLASS: + # It's a class construction + # TODO: check the assert statement below is correct + assert not (have_var or have_kw) + func, name, *parents = posargs + self.stack.push(ClassStatement(func, name, parents, kwargs)) + elif isinstance(func, PyComp): + # It's a list/set/dict comprehension or generator expression + assert not (have_var or have_kw) + assert len(posargs) == 1 and not kwargs + func.set_iterable(posargs[0]) + self.stack.push(func) + elif posargs and isinstance(posargs[0], DecorableStatement): + # It's a decorator for a def/class statement + assert len(posargs) == 1 and not kwargs + defn = posargs[0] + defn.decorate(func) + self.stack.push(defn) + else: + # It's none of the above, so it must be a normal function call + func_call = PyCallFunction(func, posargs, kwargs, varargs, varkw) + self.stack.push(func_call) + + # ATTR + + def LOAD_ATTR(self, addr, namei): + expr = self.stack.pop() + attrname = self.code.names[namei] + self.stack.push(PyAttribute(expr, attrname)) + + def STORE_ATTR(self, addr, namei): + expr = self.stack.pop() + attrname = self.code.names[namei] + self.store(PyAttribute(expr, attrname)) + + def DELETE_ATTR(self, addr, namei): + expr = self.stack.pop() + attrname = self.code.names[namei] + self.write("del {}.{}", expr, attrname) + + # SUBSCR + + def STORE_SUBSCR(self, addr): + expr, sub = self.stack.pop(2) + self.store(PySubscript(expr, sub)) + + def DELETE_SUBSCR(self, addr): + expr, sub = self.stack.pop(2) + self.write("del {}[{}]", expr, sub) + + # CONST + CONST_LITERALS = { + Ellipsis: PyName('...') + } + def LOAD_CONST(self, addr, consti): + const = self.code.consts[consti] + if const.val in self.CONST_LITERALS: + const = self.CONST_LITERALS[const.val] + self.stack.push(const) + + # + # Import statements + # + + def IMPORT_NAME(self, addr, namei): + name = self.code.names[namei] + level, fromlist = self.stack.pop(2) + self.stack.push(ImportStatement(name, level, fromlist)) + # special case check for import x.y.z as w syntax which uses + # attributes and assignments and is difficult to workaround + i = 1 + while addr[i].opcode == LOAD_ATTR: i = i + 1 + if i > 1 and addr[i].opcode in (STORE_FAST, STORE_NAME): + return addr[i] + return None + + def IMPORT_FROM(self, addr, namei): + name = self.code.names[namei] + self.stack.push(ImportFrom(name)) + if addr[1].opcode == ROT_TWO: + return addr[4] + + + def IMPORT_STAR(self, addr): + self.POP_TOP(addr) + + # + # Function call + # + + def STORE_LOCALS(self, addr): + self.stack.pop() + return addr[3] + + def LOAD_BUILD_CLASS(self, addr): + self.stack.push(self.BUILD_CLASS) + + def RETURN_VALUE(self, addr): + value = self.stack.pop() + if isinstance(value, PyConst) and value.val is None: + if addr[1] is not None: + self.write("return") + return + if self.code.flags.coroutine or self.code.flags.iterable_coroutine: + self.write("yield {}", value) + else: + self.write("return {}", value) + + def GET_YIELD_FROM_ITER(self, addr): + pass + + def YIELD_VALUE(self, addr): + if self.code.name == '': + return + value = self.stack.pop() + self.stack.push(PyYield(value)) + + def YIELD_FROM(self, addr): + value = self.stack.pop() # TODO: from statement ? + value = self.stack.pop() + self.stack.push(PyYieldFrom(value)) + + def CALL_FUNCTION_CORE(self, func, posargs, kwargs, varargs, varkw): + if func is self.BUILD_CLASS: + # It's a class construction + # TODO: check the assert statement below is correct + # assert not (have_var or have_kw) + func, name, *parents = posargs + self.stack.push(ClassStatement(func, name, parents, kwargs)) + elif isinstance(func, PyComp): + # It's a list/set/dict comprehension or generator expression + # assert not (have_var or have_kw) + assert len(posargs) == 1 and not kwargs + func.set_iterable(posargs[0]) + self.stack.push(func) + elif posargs and isinstance(posargs, list) and isinstance(posargs[0], DecorableStatement): + # It's a decorator for a def/class statement + assert len(posargs) == 1 and not kwargs + defn = posargs[0] + defn.decorate(func) + self.stack.push(defn) + else: + # It's none of the above, so it must be a normal function call + func_call = PyCallFunction(func, posargs, kwargs, varargs, varkw) + self.stack.push(func_call) + + def CALL_FUNCTION(self, addr, argc, have_var=False, have_kw=False): + if sys.version_info >= (3, 6): + pos_argc = argc + posargs = self.stack.pop(pos_argc) + func = self.stack.pop() + self.CALL_FUNCTION_CORE(func, posargs, [], None, None) + else: + kw_argc = argc >> 8 + pos_argc = argc & 0xFF + varkw = self.stack.pop() if have_kw else None + varargs = self.stack.pop() if have_var else None + kwargs_iter = iter(self.stack.pop(2 * kw_argc)) + kwargs = list(zip(kwargs_iter, kwargs_iter)) + posargs = self.stack.pop(pos_argc) + func = self.stack.pop() + self.CALL_FUNCTION_CORE(func, posargs, kwargs, varargs, varkw) + + def CALL_FUNCTION_VAR(self, addr, argc): + self.CALL_FUNCTION(addr, argc, have_var=True) + + def CALL_FUNCTION_KW(self, addr, argc): + if sys.version_info >= (3, 6): + keys = self.stack.pop() + kwargc = len(keys.val) + kwarg_values = self.stack.pop(kwargc) + posargs = self.stack.pop(argc - kwargc) + func = self.stack.pop() + kwarg_dict = list(zip([PyName(k) for k in keys], kwarg_values)) + self.CALL_FUNCTION_CORE(func, posargs, kwarg_dict, None, None) + else: + self.CALL_FUNCTION(addr, argc, have_kw=True) + + def CALL_FUNCTION_EX(self, addr, flags): + kwarg_dict = PyDict() + if flags & 1: + kwarg_dict = self.stack.pop() + posargs = self.stack.pop() + func = self.stack.pop() + kwvar = None + posvar = None + + if not isinstance(posargs, PyTuple): + posvar = posargs + posargs = PyTuple([]) + + if not isinstance(kwarg_dict, PyDict): + kwvar = kwarg_dict + kwarg_dict = PyDict() + + if not posargs: + posargs = PyTuple([]) + + assert isinstance(kwarg_dict, PyDict) + for i in range(len(kwarg_dict.items)): + k, v = kwarg_dict.items[i] + if isinstance(v, PyConst) and v.val == '**KWARG**': + kwarg_dict.items.pop(i) + kwvar = k.val + break + elif not isinstance(k, PyConst): + kwvar = kwarg_dict + kwarg_dict = PyDict() + break + + assert isinstance(posargs, PyTuple) + posvals = posargs.values + assert isinstance(posvals, list) + for i in range(len(posvals)): + posarg = posvals[i] + if isinstance(posarg, PyName) and posarg.name == 'args': + posvals.pop(i) + posvar = posarg + break + + self.CALL_FUNCTION_CORE(func, list(posargs.values), list(kwarg_dict.items), posvar, kwvar) + + def CALL_FUNCTION_VAR_KW(self, addr, argc): + self.CALL_FUNCTION(addr, argc, have_var=True, have_kw=True) + + # a, b, ... = ... + + def UNPACK_SEQUENCE(self, addr, count): + unpack = Unpack(self.stack.pop(), count) + for i in range(count): + self.stack.push(unpack) + + def UNPACK_EX(self, addr, counts): + rcount = counts >> 8 + lcount = counts & 0xFF + count = lcount + rcount + 1 + unpack = Unpack(self.stack.pop(), count, lcount) + for i in range(count): + self.stack.push(unpack) + + # Build operations + + def BUILD_SLICE(self, addr, argc): + assert argc in (2, 3) + self.stack.push(PySlice(self.stack.pop(argc))) + + def BUILD_TUPLE(self, addr, count): + values = [self.stack.pop() for i in range(count)] + values.reverse() + self.stack.push(PyTuple(values)) + + def BUILD_TUPLE_UNPACK_WITH_CALL(self, addr, count): + values = [] + for o in self.stack.pop(count): + if isinstance(o, PyTuple): + values.extend(o.values) + else: + values.append(o) + + self.stack.push(PyTuple(values)) + + def BUILD_LIST(self, addr, count): + values = [self.stack.pop() for i in range(count)] + values.reverse() + self.stack.push(PyList(values)) + + def BUILD_SET(self, addr, count): + values = [self.stack.pop() for i in range(count)] + values.reverse() + self.stack.push(PySet(values)) + + def BUILD_MAP(self, addr, count): + d = PyDict() + if sys.version_info >= (3, 5): + for i in range(count): + d.items.append(tuple(self.stack.pop(2))) + self.stack.push(d) + + def BUILD_MAP_UNPACK_WITH_CALL(self, addr, count): + d = PyDict() + for i in range(count): + o = self.stack.pop() + if isinstance(o, PyDict): + for item in o.items: + k, v = item + d.set_item(PyConst(k.val), v) + else: + d.set_item(PyConst(o), PyConst('**KWARG**')) + self.stack.push(d) + + def BUILD_CONST_KEY_MAP(self, addr, count): + keys = self.stack.pop() + vals = self.stack.pop(count) + dict = PyDict() + for i in range(count): + dict.set_item(PyConst(keys.val[i]), vals[i]) + self.stack.push(dict) + + def STORE_MAP(self, addr): + v, k = self.stack.pop(2) + d = self.stack.peek() + d.set_item(k, v) + + # Comprehension operations - just create an expression statement + + def LIST_APPEND(self, addr, i): + self.POP_TOP(addr) + + def SET_ADD(self, addr, i): + self.POP_TOP(addr) + + def MAP_ADD(self, addr, i): + value, key = self.stack.pop(2) + self.stack.push(PyKeyValue(key, value)) + self.POP_TOP(addr) + + # and operator + + def JUMP_IF_FALSE_OR_POP(self, addr, target): + end_addr = addr.jump() + self.push_popjump(True, end_addr, self.stack.pop()) + left = self.pop_popjump() + if end_addr.opcode == ROT_TWO: + opc, arg = end_addr[-1] + if opc == JUMP_FORWARD and arg == 2: + end_addr = end_addr[2] + elif opc == RETURN_VALUE or opc == JUMP_FORWARD: + end_addr = end_addr[-1] + d = SuiteDecompiler(addr[1], end_addr, self.stack) + d.run() + right = self.stack.pop() + if isinstance(right, PyCompare) and right.extends(left): + py_and = left.chain(right) + else: + py_and = PyBooleanAnd(left, right) + self.stack.push(py_and) + return end_addr[3] + + d = SuiteDecompiler(addr[1], end_addr, self.stack) + d.run() + # if end_addr.opcode == RETURN_VALUE: + # return end_addr[2] + right = self.stack.pop() + if isinstance(right, PyCompare) and right.extends(left): + py_and = left.chain(right) + else: + py_and = PyBooleanAnd(left, right) + self.stack.push(py_and) + return end_addr + + # This appears when there are chained comparisons, e.g. 1 <= x < 10 + + def JUMP_FORWARD(self, addr, delta): + ## if delta == 2 and addr[1].opcode == ROT_TWO and addr[2].opcode == POP_TOP: + ## # We're in the special case of chained comparisons + ## return addr[3] + ## else: + ## # I'm hoping its an unused JUMP in an if-else statement + ## return addr[1] + return addr.jump() + + # or operator + + def JUMP_IF_TRUE_OR_POP(self, addr, target): + end_addr = addr.jump() + self.push_popjump(True, end_addr, self.stack.pop()) + left = self.pop_popjump() + d = SuiteDecompiler(addr[1], end_addr, self.stack) + d.run() + right = self.stack.pop() + self.stack.push(PyBooleanOr(left, right)) + return end_addr + + # + # If-else statements/expressions and related structures + # + + def POP_JUMP_IF(self, addr: Address, target: int, truthiness: bool) -> Union[Address, None]: + jump_addr = addr.jump() + end_of_loop = jump_addr.opcode == FOR_ITER or jump_addr[-1].opcode == SETUP_LOOP + if jump_addr.opcode == FOR_ITER: + # We are in a for-loop with nothing after the if-suite + # But take care: for-loops in generator expression do + # not end in POP_BLOCK, hence the test below. + jump_addr = jump_addr.jump() + elif end_of_loop: + # We are in a while-loop with nothing after the if-suite + jump_addr = jump_addr[-1].jump()[-1] + cond = self.stack.pop() + if not addr.is_else_jump(): + + + # Handle generator expressions with or clause + for_iter = addr.seek_back(FOR_ITER) + if for_iter: + end_of_for = for_iter.jump() + if end_of_for.addr > addr.addr: + gen = jump_addr.seek_forward((YIELD_VALUE, LIST_APPEND), end_of_for) + if gen: + if not truthiness: + truthiness = not truthiness + if truthiness: + cond = PyNot(cond) + self.push_popjump(truthiness, jump_addr, cond) + return None + + self.push_popjump(truthiness, jump_addr, cond) + # Dictionary comprehension + if jump_addr.seek_forward(MAP_ADD): + return None + + # Generator + if jump_addr.seek_forward(YIELD_VALUE): + return None + + # Generator + if jump_addr.opcode != END_FINALLY and jump_addr[1] and jump_addr[1].opcode == JUMP_ABSOLUTE: + return None + + a = addr[1] + while a and a < jump_addr: + if a.opcode in stmt_opcodes: + break + if a.opcode in pop_jump_if_opcodes and a.arg >= addr.arg: + return None + a = a[1] + # if there are no nested conditionals and no else clause, write the true portion and jump ahead to the end of the conditional + cond = self.pop_popjump() + end_true = jump_addr + if truthiness: + cond = PyNot(cond) + d_true = SuiteDecompiler(addr[1], end_true) + d_true.run() + stmt = IfStatement(cond, d_true.suite, None) + self.suite.add_statement(stmt) + return end_true + # Increase jump_addr to pop all previous jumps + self.push_popjump(truthiness, jump_addr[1], cond) + cond = self.pop_popjump() + end_true = jump_addr[-1] + if truthiness: + last_pj = addr.seek_back(pop_jump_if_opcodes) + if last_pj and last_pj.arg == addr.arg and isinstance(cond, PyBooleanAnd) or isinstance(cond, PyBooleanOr): + cond.right = PyNot(cond.right) + else: + cond = PyNot(cond) + + if end_true.opcode == RETURN_VALUE: + end_false = jump_addr.seek_forward(RETURN_VALUE) + if end_false and end_false[2] and end_false[2].opcode == RETURN_VALUE: + d_true = SuiteDecompiler(addr[1], end_true[1]) + d_true.run() + d_false = SuiteDecompiler(jump_addr,end_false[1]) + d_false.run() + self.suite.add_statement(IfStatement(cond, d_true.suite, d_false.suite)) + + return end_false[1] + + # - If the true clause ends in return, make sure it's included + # - If the true clause ends in RAISE_VARARGS, then it's an + # assert statement. For now I just write it as a raise within + # an if (see below) + if end_true.opcode in (RETURN_VALUE, RAISE_VARARGS, POP_TOP): + # TODO: change + # if cond: raise AssertionError(x) + # to + # assert cond, x + d_true = SuiteDecompiler(addr[1], end_true[1]) + d_true.run() + self.suite.add_statement(IfStatement(cond, d_true.suite, Suite())) + return jump_addr + d_true = SuiteDecompiler(addr[1], end_true) + d_true.run() + if jump_addr.opcode == POP_BLOCK and not end_of_loop: + # It's a while loop + stmt = WhileStatement(cond, d_true.suite) + self.suite.add_statement(stmt) + return jump_addr[1] + # It's an if-else (expression or statement) + if end_true.opcode == JUMP_FORWARD: + end_false = end_true.jump() + elif end_true.opcode == JUMP_ABSOLUTE: + end_false = end_true.jump() + if end_false.opcode == FOR_ITER: + # We are in a for-loop with nothing after the else-suite + end_false = end_false.jump()[-1] + elif end_false[-1].opcode == SETUP_LOOP: + # We are in a while-loop with nothing after the else-suite + end_false = end_false[-1].jump()[-1] + if end_false.opcode == RETURN_VALUE: + end_false = end_false[1] + elif end_true.opcode == RETURN_VALUE: + # find the next RETURN_VALUE + end_false = jump_addr + while end_false.opcode != RETURN_VALUE: + end_false = end_false[1] + end_false = end_false[1] + elif end_true.opcode == BREAK_LOOP: + # likely in a loop in a try/except + end_false = jump_addr + else: + end_false = jump_addr + # # normal statement + # raise Exception("#ERROR: Unexpected statement: {} | {}\n".format(end_true, jump_addr, jump_addr[-1])) + # # raise Unknown + # jump_addr = end_true[-2] + # stmt = IfStatement(cond, d_true.suite, None) + # self.suite.add_statement(stmt) + # return jump_addr or self.END_NOW + d_false = SuiteDecompiler(jump_addr, end_false) + d_false.run() + if d_true.stack and d_false.stack: + assert len(d_true.stack) == len(d_false.stack) == 1 + # self.write("#ERROR: Unbalanced stacks {} != {}".format(len(d_true.stack),len(d_false.stack))) + assert not (d_true.suite or d_false.suite) + # this happens in specific if else conditions with assigments + true_expr = d_true.stack.pop() + false_expr = d_false.stack.pop() + self.stack.push(PyIfElse(cond, true_expr, false_expr)) + else: + stmt = IfStatement(cond, d_true.suite, d_false.suite) + self.suite.add_statement(stmt) + return end_false or self.END_NOW + + def POP_JUMP_IF_FALSE(self, addr, target): + return self.POP_JUMP_IF(addr, target, truthiness=False) + + def POP_JUMP_IF_TRUE(self, addr, target): + return self.POP_JUMP_IF(addr, target, truthiness=True) + + def JUMP_ABSOLUTE(self, addr, target): + # print("*** JUMP ABSOLUTE ***", addr) + # return addr.jump() + + # TODO: print out continue if not final jump + jump_addr = addr.jump() + if jump_addr[-1].opcode == SETUP_LOOP: + end_addr = jump_addr + jump_addr[-1].arg + last_jump = self.scan_for_final_jump(jump_addr, end_addr[-1]) + if last_jump != addr: + pass + pass + + # + # For loops + # + + def GET_ITER(self, addr): + pass + + def FOR_ITER(self, addr: Address, delta): + if addr[-1] and addr[-1].opcode == RETURN_VALUE: + # Dead code + return self.END_NOW + iterable = self.stack.pop() + jump_addr = addr.jump() + end_body = jump_addr + if end_body.opcode != POP_BLOCK: + end_body = end_body[-1] + d_body = SuiteDecompiler(addr[1], end_body) + for_stmt = ForStatement(iterable) + d_body.stack.push(for_stmt) + d_body.run() + for_stmt.body = d_body.suite + self.suite.add_statement(for_stmt) + return jump_addr + + # Function creation + + def MAKE_FUNCTION_OLD(self, addr, argc, is_closure=False): + testType = self.stack.pop().val + if isinstance(testType, str): + code = Code(self.stack.pop().val, self.code) + else: + code = Code(testType, self.code) + closure = self.stack.pop() if is_closure else None + # parameter annotation objects + paramobjs = {} + paramcount = (argc >> 16) & 0x7FFF + if paramcount: + paramobjs = dict(zip(self.stack.pop().val, self.stack.pop(paramcount - 1))) + # default argument objects in positional order + defaults = self.stack.pop(argc & 0xFF) + # pairs of name and default argument, with the name just below the object on the stack, for keyword-only parameters + kwdefaults = {} + for i in range((argc >> 8) & 0xFF): + k, v = self.stack.pop(2) + if hasattr(k, 'name'): + kwdefaults[k.name] = v + elif hasattr(k, 'val'): + kwdefaults[k.val] = v + else: + kwdefaults[str(k)] = v + func_maker = code_map.get(code.name, DefStatement) + self.stack.push(func_maker(code, defaults, kwdefaults, closure, paramobjs)) + + def MAKE_FUNCTION_NEW(self, addr, argc, is_closure=False): + testType = self.stack.pop().val + if isinstance(testType, str): + code = Code(self.stack.pop().val, self.code) + else: + code = Code(testType, self.code) + closure = self.stack.pop() if is_closure else None + annotations = {} + kwdefaults = {} + defaults = {} + if argc & 8: + annotations = list(self.stack.pop()) + if argc & 4: + annotations = self.stack.pop() + if isinstance(annotations, PyDict): + annotations = {str(k[0].val).replace('\'', ''): str(k[1]) for k in annotations.items} + if argc & 2: + kwdefaults = self.stack.pop() + if isinstance(kwdefaults, PyDict): + kwdefaults = {str(k[0].val): str(k[1] if isinstance(k[1], PyExpr) else PyConst(k[1])) for k in + kwdefaults.items} + if not kwdefaults: + kwdefaults = {} + if argc & 1: + defaults = list(map(lambda x: str(x if isinstance(x, PyExpr) else PyConst(x)), self.stack.pop())) + func_maker = code_map.get(code.name, DefStatement) + self.stack.push(func_maker(code, defaults, kwdefaults, closure, annotations, annotations)) + + def MAKE_FUNCTION(self, addr, argc, is_closure=False): + if sys.version_info < (3, 6): + self.MAKE_FUNCTION_OLD(addr, argc, is_closure) + else: + self.MAKE_FUNCTION_NEW(addr, argc, is_closure) + + def LOAD_CLOSURE(self, addr, i): + # Push the varname. It doesn't matter as it is not used for now. + self.stack.push(self.code.derefnames[i]) + + def MAKE_CLOSURE(self, addr, argc): + self.MAKE_FUNCTION(addr, argc, is_closure=True) + + # + # Raising exceptions + # + + def RAISE_VARARGS(self, addr, argc): + # TODO: find out when argc is 2 or 3 + # Answer: In Python 3, only 0, 1, or 2 argument (see PEP 3109) + if argc == 0: + self.write("raise") + elif argc == 1: + exception = self.stack.pop() + self.write("raise {}", exception) + elif argc == 2: + from_exc, exc = self.stack.pop(), self.stack.pop() + self.write("raise {} from {}".format(exc, from_exc)) + else: + raise Unknown + + def EXTENDED_ARG(self, addr, ext): + # self.write("# ERROR: {} : {}".format(addr, ext) ) + pass + + def WITH_CLEANUP(self, addr, *args, **kwargs): + # self.write("# ERROR: {} : {}".format(addr, args)) + pass + + def WITH_CLEANUP_START(self, addr, *args, **kwargs): + pass + + def WITH_CLEANUP_FINISH(self, addr, *args, **kwargs): + jaddr = addr.jump() + return jaddr + + # Formatted string literals + def FORMAT_VALUE(self, addr, flags): + val = self.stack.pop() + self.stack.push(PyFormatValue(val)) + + def BUILD_STRING(self, addr, c): + params = self.stack.pop(c) + self.stack.push(PyFormatString(params)) + + # Coroutines + def GET_AWAITABLE(self, addr: Address): + func: AwaitableMixin = self.stack.pop() + func.is_awaited = True + self.stack.push(func) + yield_op = addr.seek_forward(YIELD_FROM) + return yield_op[1] + + def BEFORE_ASYNC_WITH(self, addr: Address): + with_addr = addr.seek_forward(SETUP_ASYNC_WITH) + end_with = with_addr.jump() + with_stmt = WithStatement(self.stack.pop()) + with_stmt.is_async = True + d_with = SuiteDecompiler(addr[1], end_with) + d_with.stack.push(with_stmt) + d_with.run() + with_stmt.suite = d_with.suite + self.suite.add_statement(with_stmt) + if sys.version_info <= (3, 4): + assert end_with.opcode == WITH_CLEANUP + assert end_with[1].opcode == END_FINALLY + return end_with[2] + else: + assert end_with.opcode == WITH_CLEANUP_START + assert end_with[1].opcode == GET_AWAITABLE + assert end_with[4].opcode == WITH_CLEANUP_FINISH + return end_with[5] + + def SETUP_ASYNC_WITH(self, addr: Address, arg): + pass + + def GET_AITER(self, addr: Address): + return addr[2] + + def GET_ANEXT(self, addr: Address): + iterable = self.stack.pop() + for_stmt = ForStatement(iterable) + for_stmt.is_async = True + jump_addr = addr[-1].jump() + d_body = SuiteDecompiler(addr[3], jump_addr[-1]) + d_body.stack.push(for_stmt) + d_body.run() + jump_addr = jump_addr[-1].jump() + new_start = jump_addr + new_end = jump_addr[-2].jump()[-1] + d_body.start_addr = new_start + + d_body.end_addr = new_end + + d_body.run() + + for_stmt.body = d_body.suite + self.suite.add_statement(for_stmt) + new_end = new_end.seek_forward(POP_BLOCK) + return new_end + + +def make_dynamic_instr(cls): + def method(self, addr): + cls.instr(self.stack) + + return method + + +# Create unary operators types and opcode handlers +for op, name, ptn, prec in unary_ops: + name = 'Py' + name + tp = type(name, (PyUnaryOp,), dict(pattern=ptn, precedence=prec)) + globals()[name] = tp + setattr(SuiteDecompiler, op, make_dynamic_instr(tp)) + +# Create binary operators types and opcode handlers +for op, name, ptn, prec, inplace_ptn in binary_ops: + # Create the binary operator + tp_name = 'Py' + name + tp = globals().get(tp_name, None) + if tp is None: + tp = type(tp_name, (PyBinaryOp,), dict(pattern=ptn, precedence=prec)) + globals()[tp_name] = tp + + setattr(SuiteDecompiler, 'BINARY_' + op, make_dynamic_instr(tp)) + # Create the in-place operation + if inplace_ptn is not None: + inplace_op = "INPLACE_" + op + tp_name = 'InPlace' + name + tp = type(tp_name, (InPlaceOp,), dict(pattern=inplace_ptn)) + globals()[tp_name] = tp + setattr(SuiteDecompiler, inplace_op, make_dynamic_instr(tp)) + +if __name__ == "__main__": + import sys + + if len(sys.argv) == 1: + print('USAGE: {} '.format(sys.argv[0])) + else: + print(decompile(sys.argv[1])) diff --git a/Utilities/unpyc3_compiler.py b/Utilities/unpyc3_compiler.py new file mode 100644 index 0000000..e12a294 --- /dev/null +++ b/Utilities/unpyc3_compiler.py @@ -0,0 +1,115 @@ +from compile_utils import _remove_files_conflicting_with_decompile, _replace_renamed_files + +_remove_files_conflicting_with_decompile(decompile_ea_scripts=False) + +import traceback +from typing import Iterator +from zipfile import PyZipFile + +from settings import * + + +class Unpyc3PythonCompiler: + """Handles compilation of python files into ts4script files using unpyc3.""" + @classmethod + def compile_mod( + cls, + names_of_modules_include: Iterator[str], + folder_path_to_output_ts4script_to: str, + output_ts4script_name: str, + names_of_modules_to_exclude: str=None, + mod_creator_name: str=None, + folder_path_to_gather_script_modules_from: str='..' + ): + """compile_mod(\ + names_of_modules_include,\ + folder_path_to_output_ts4script_to,\ + output_ts4script_name,\ + names_of_modules_to_exclude=None,\ + mod_creator_name=None,\ + folder_path_to_gather_script_packages_from=None\ + ) + + Compile a mod using unpyc3. + + """ + os.makedirs(folder_path_to_output_ts4script_to, exist_ok=True) + from compile_utils import _remove_files_conflicting_with_decompile, _replace_renamed_files + _remove_files_conflicting_with_decompile(decompile_ea_scripts=False) + names_of_modules_include = tuple(names_of_modules_include) + if not mod_creator_name: + mod_creator_name = creator_name + if not output_ts4script_name: + output_ts4script_name = os.path.join('..', '..', os.path.basename(os.path.normpath(os.path.dirname(os.path.realpath('__file__'))))) + print('No mod name found, setting the path name to \'{}\'.'.format(output_ts4script_name)) + print(f'The current working directory {os.getcwd()}.') + + if mod_creator_name: + print('Mod creator name found, appending mod creator name to file name.') + output_ts4script_name = '{}_{}'.format(mod_creator_name, output_ts4script_name) + output_script_zip_name = '{}.ts4script'.format(output_ts4script_name) + if not folder_path_to_output_ts4script_to: + ts4script = output_script_zip_name + else: + ts4script = os.path.join(folder_path_to_output_ts4script_to, output_script_zip_name) + + # noinspection PyBroadException + try: + if os.path.exists(ts4script): + print('Script archive found, removing found archive.') + os.remove(ts4script) + print('Script archive removed.') + + output_zip = PyZipFile(ts4script, mode='w', allowZip64=True, optimize=2) + previous_working_directory = os.getcwd() + + if folder_path_to_gather_script_modules_from is not None: + print(f'Changing the working directory to \'{folder_path_to_gather_script_modules_from}\'') + os.chdir(folder_path_to_gather_script_modules_from) + else: + folder_path_to_gather_script_modules_from = '..' + os.chdir(folder_path_to_gather_script_modules_from) + print(f'Changed the current working directory \'{os.getcwd()}\'.') + # print('Found child directories {}'.format(pformat(tuple(child_directories)))) + for folder_path in cls._child_directories_gen(os.getcwd()): + # print(f'Attempting to compile {folder_path}') + if names_of_modules_to_exclude is not None and os.path.basename(folder_path) in names_of_modules_to_exclude: + # print(f'Folder is set to be ignored {folder_path}. Continuing to the next folder.') + continue + if names_of_modules_include is not None and os.path.basename(folder_path) not in names_of_modules_include: + # print(f'Folder is not set to be included {folder_path}. Continuing to the next folder.') + continue + # noinspection PyBroadException + try: + print(f'Compiling folder \'{folder_path}\'') + output_zip.writepy(folder_path) + print(f'\'{folder_path}\' compiled successfully.') + except Exception as ex: + print(f'Failed to write {folder_path}. {ex}') + traceback.print_exc() + continue + + print('Done compiling modules.') + output_zip.close() + print('Changing working directory to previous working directory.') + os.chdir(previous_working_directory) + print(f'Changed the current working directory to \'{os.getcwd()}\'') + except Exception as ex: + print(f'Failed to create {ts4script}. {ex}') + return + finally: + _replace_renamed_files(decompile_ea_scripts=False) + + # This code is meant to copy the file to the Mods folder, but in most cases, we probably do not want this to happen! + # ts4script_mods = os.path.join(os.path.join(mods_folder), script_zip_name) + # shutil.copyfile(ts4script, ts4script_mods) + + @classmethod + def _child_directories_gen(cls, directory_path) -> Iterator[str]: + for folder_path in os.listdir(directory_path): + if not os.path.isdir(os.path.join(directory_path, folder_path)): + continue + yield folder_path + + +_replace_renamed_files(decompile_ea_scripts=False) diff --git a/Utilities/unpyc3_decompiler.py b/Utilities/unpyc3_decompiler.py new file mode 100644 index 0000000..343f6a5 --- /dev/null +++ b/Utilities/unpyc3_decompiler.py @@ -0,0 +1,87 @@ +import shutil +import os +import io +import fnmatch +import traceback +from zipfile import PyZipFile +from Utilities.unpyc3 import decompile + + +class Unpyc3PyDecompiler: + """A handler that can both compile and decompile scripts using unpyc3.""" + _script_package_types = ['*.zip', '*.ts4script'] + + @classmethod + def decompile_file(cls, path_to_file_for_decompile: str, throw_on_error: bool=False) -> bool: + """Decompile a python file using unpyc3.""" + _replace_characters = () + # print('Decompiling \'{}\''.format(path_to_file_for_decompile)) + decompiled_py = decompile(path_to_file_for_decompile) + with io.open(path_to_file_for_decompile.replace('.pyc', '.py').replace('.pyo', '.py'), 'w', encoding="utf-8") as output_py: + success = True + for statement in decompiled_py.statements: + try: + statement_str = str(statement) + for replace_char in _replace_characters: + statement_str = statement_str.replace(replace_char, '-----') + output_py.write(statement_str + '\r') + except Exception as ex: + try: + statement_for_display = statement.gen_display() if hasattr(statement, 'gen_display') else statement + print(f'Failed to parse statement. {statement_for_display} {ex}') + traceback.print_exc() + if throw_on_error: + raise ex + success = False + except Exception as ex2: + print(f'Another error occurred! {ex} {ex2}') + if throw_on_error: + raise ex2 + success = False + continue + return success + + @classmethod + def decompile_folder(cls, folder_path: str, throw_on_error: bool=False) -> None: + """Decompile python files within a folder using unpyc3.""" + pattern = '*.pyc' + successful_decompiles = 0 + failed_decompiles = 0 + for root, dirs, files in os.walk(folder_path): + for file_name in fnmatch.filter(files, pattern): + path_to_file_for_decompile = str(os.path.join(root, file_name)) + try: + if cls.decompile_file(path_to_file_for_decompile, throw_on_error=True): + print(f'SUCCESS: {path_to_file_for_decompile}') + successful_decompiles += 1 + else: + print(f'FAILED: {path_to_file_for_decompile}') + failed_decompiles += 1 + except Exception as ex: + print("FAILED to decompile %s" % path_to_file_for_decompile) + failed_decompiles += 1 + traceback.print_exc() + if throw_on_error: + raise ex + + @classmethod + def _extract_sub_folder(cls, root: str, filename: str, ea_folder: str, decompile_files: bool=True): + src = os.path.join(root, filename) + dst = os.path.join(ea_folder, filename) + if src != dst: + shutil.copyfile(src, dst) + py_zip = PyZipFile(dst) + out_folder = os.path.join(ea_folder, os.path.splitext(filename)[0]) + py_zip.extractall(out_folder) + if decompile_files: + cls.decompile_folder(out_folder) + pass + + @classmethod + def extract_folder(cls, ea_folder: str, gameplay_folder: str, decompile_files: bool=True): + """Extract a folder.""" + for root, dirs, files in os.walk(gameplay_folder): + for ext_filter in Unpyc3PyDecompiler._script_package_types: + for filename in fnmatch.filter(files, ext_filter): + cls._extract_sub_folder(root, filename, ea_folder, decompile_files=decompile_files) + diff --git a/custom_scripts_for_decompile/README.md b/custom_scripts_for_decompile/README.md new file mode 100644 index 0000000..bacb9ee --- /dev/null +++ b/custom_scripts_for_decompile/README.md @@ -0,0 +1,10 @@ +This folder is where you place `.pyc` files to be decompiled when running `decompile_scripts.py` + +## Decompile Scripts From Other Mods. + +1. Inside `/settings.py`, change `should_decompile_ea_scripts` to `False` +2. Inside `/settings.py`, change `should_decompile_custom_scripts` to `True` +3. If it does not exist, create a folder in your project with the name `custom_scripts_for_decompile`. i.e. `/custom_scripts_for_decompile` +4. Put the script files (.pyc) of the mod you wish to decompile, inside of the `custom_scripts_for_decompile` folder. (Every ts4script file is a zip file and can be opened and extracted like one!) +5. Run the `decompile_scripts.py` script +6. It will decompile the custom scripts and put them inside of the folder: `/custom_scripts_for_decompile/_decompiled/...` \ No newline at end of file diff --git a/decompile_scripts.py b/decompile_scripts.py new file mode 100644 index 0000000..d2827fc --- /dev/null +++ b/decompile_scripts.py @@ -0,0 +1,47 @@ +import os + +from compile_utils import _remove_files_conflicting_with_decompile, _replace_renamed_files +from decompilation_method import S4PyDecompilationMethod +from settings import custom_scripts_for_decompile_source, game_folder, decompile_method_name, custom_scripts_for_decompile_destination, should_decompile_ea_scripts, should_decompile_custom_scripts + + +def _decompile_using_unpyc3(decompile_ea_scripts: bool=False, decompile_custom_scripts: bool=False): + output_folder = 'EA' + if not os.path.exists(output_folder): + os.mkdir(output_folder) + + _remove_files_conflicting_with_decompile(decompile_ea_scripts=decompile_ea_scripts) + + from Utilities.unpyc3_decompiler import Unpyc3PyDecompiler + + if decompile_custom_scripts: + Unpyc3PyDecompiler.decompile_folder(custom_scripts_for_decompile_source) + + if decompile_ea_scripts: + gameplay_folder_data = os.path.join(game_folder, 'Data', 'Simulation', 'Gameplay') + if os.name != 'nt': + gameplay_folder_game = os.path.join(game_folder, 'Python') + else: + gameplay_folder_game = os.path.join(game_folder, 'Game', 'Bin', 'Python') + + Unpyc3PyDecompiler.extract_folder(output_folder, gameplay_folder_data) + Unpyc3PyDecompiler.extract_folder(output_folder, gameplay_folder_game) + + _replace_renamed_files(decompile_ea_scripts=should_decompile_ea_scripts) + + +def _decompile_using_py37dec() -> None: + _remove_files_conflicting_with_decompile(decompile_ea_scripts=should_decompile_ea_scripts) + + from py37_decompiler import Py37PythonDecompiler + Py37PythonDecompiler().decompile( + custom_scripts_for_decompile_source, + custom_scripts_for_decompile_destination + ) + _replace_renamed_files(decompile_ea_scripts=should_decompile_ea_scripts) + + +if decompile_method_name == S4PyDecompilationMethod.UNPYC3: + _decompile_using_unpyc3(decompile_ea_scripts=should_decompile_ea_scripts, decompile_custom_scripts=should_decompile_custom_scripts) +elif decompile_method_name == S4PyDecompilationMethod.PY37DEC: + _decompile_using_py37dec() From 2ef1230b1d8ba8f2adcc38e32dcaac9735d27bc4 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Thu, 4 Sep 2025 16:38:28 -0600 Subject: [PATCH 020/134] add more stuff/edit gitignore more --- .gitignore | 3 +-- Libraries/.gitkeep | 0 Release/.gitkeep | 0 Scripts/compile/__init__.py | 0 Scripts/compile/compile.py | 12 ++++++++++++ 5 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 Libraries/.gitkeep create mode 100644 Release/.gitkeep create mode 100644 Scripts/compile/__init__.py create mode 100644 Scripts/compile/compile.py diff --git a/.gitignore b/.gitignore index 2f93c4d..68b295e 100644 --- a/.gitignore +++ b/.gitignore @@ -6,10 +6,9 @@ EA/* !EA/README.md # Libraries -Libraries/** +Libraries/*/ # Additional non mod related items -Scripts/compile Scripts/rel Scripts/randomizer Scripts/s4cl_sample_mod_scripts diff --git a/Libraries/.gitkeep b/Libraries/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Release/.gitkeep b/Release/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Scripts/compile/__init__.py b/Scripts/compile/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Scripts/compile/compile.py b/Scripts/compile/compile.py new file mode 100644 index 0000000..7ab0ed7 --- /dev/null +++ b/Scripts/compile/compile.py @@ -0,0 +1,12 @@ +import os +from Utilities.unpyc3_compiler import Unpyc3PythonCompiler + + +release_dir = os.path.join('..', '..', 'Release', 's4ap') + +# This function invocation will compile the files found within Scripts/s4cl_sample_mod_scripts, put them inside of a file named s4cl_sample_mod.ts4script, and it will finally place that ts4script file within /Release/S4CLSampleMod. +Unpyc3PythonCompiler.compile_mod( + folder_path_to_output_ts4script_to=release_dir, + names_of_modules_include=('s4ap',), + output_ts4script_name='s4ap' +) From 504e1c9d6330fd6780fbcf3899574bcad7473584 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Thu, 4 Sep 2025 16:42:28 -0600 Subject: [PATCH 021/134] add lot51's core library as a submodule --- .gitmodules | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .gitmodules diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..147b91c --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "Libraries/core-library"] + path = Libraries/lot51_core + url = https://github.com/lot51/core-library.git From e9e38d4f6de6e3a24bcbd3d29725d4577f00d469 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Thu, 4 Sep 2025 16:48:42 -0600 Subject: [PATCH 022/134] fix the submodule so it works properly in pycharm --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 147b91c..d280225 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "Libraries/core-library"] - path = Libraries/lot51_core + path = Libraries/core-library/lot51_core url = https://github.com/lot51/core-library.git From 0244c605e13555c39b23b9714b8bb9bc5e2081e6 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Thu, 4 Sep 2025 16:59:11 -0600 Subject: [PATCH 023/134] remove unused import --- Scripts/s4ap/utils/s4ap_skill_utils.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Scripts/s4ap/utils/s4ap_skill_utils.py b/Scripts/s4ap/utils/s4ap_skill_utils.py index bedc08a..8d7a7a0 100644 --- a/Scripts/s4ap/utils/s4ap_skill_utils.py +++ b/Scripts/s4ap/utils/s4ap_skill_utils.py @@ -7,7 +7,6 @@ from s4ap.logging.s4ap_logger import S4APLogger from s4ap.modinfo import ModInfo from s4ap.persistance.ap_session_data_store import S4APSessionStoreUtils -from s4ap.utils.s4ap_generic_utils import S4APUtils from s4ap.utils.s4ap_household_utils import S4APHouseholdUtils from s4ap.utils.s4ap_sim_utils import S4APSimUtils from server_commands.argument_helpers import TunableInstanceParam From 69e3d0982226844c4771f02d7524838637d5dc2e Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Thu, 4 Sep 2025 20:10:50 -0600 Subject: [PATCH 024/134] make sure the new career option doesn't crash the mod? --- Scripts/s4ap/persistance/ap_session_data_store.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Scripts/s4ap/persistance/ap_session_data_store.py b/Scripts/s4ap/persistance/ap_session_data_store.py index 95cf00a..1de820a 100644 --- a/Scripts/s4ap/persistance/ap_session_data_store.py +++ b/Scripts/s4ap/persistance/ap_session_data_store.py @@ -133,7 +133,7 @@ def save_item_info(self, items: str, item_ids: str, locations: str, senders: str self._set_value(S4APSettings.SENDERS, senders) S4APUtils.trigger_autosave() - def save_goal_and_career(self, goal: str, career: str): + def save_goal_and_career(self, goal: str, career: set): self._set_value(S4APSettings.GOAL, goal) self._set_value(S4APSettings.CAREER, career) S4APUtils.trigger_autosave() @@ -156,7 +156,7 @@ def get_seed_name(self) -> str: def get_goal(self) -> str: return self._get_value(S4APSettings.GOAL) - def get_career(self) -> str: + def get_career(self) -> set: return self._get_value(S4APSettings.CAREER) def _get_value(self, key: str) -> Any: From b0c788903d4179fbf38c399f37d011174c067117 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Thu, 4 Sep 2025 20:11:18 -0600 Subject: [PATCH 025/134] new version --- Scripts/s4ap/modinfo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/s4ap/modinfo.py b/Scripts/s4ap/modinfo.py index adfeb76..725e34d 100644 --- a/Scripts/s4ap/modinfo.py +++ b/Scripts/s4ap/modinfo.py @@ -14,7 +14,7 @@ def _name(self) -> str: @property def _version(self) -> str: # Mod version - return '0.2.1' + return '0.3.0-rc1' @property def _author(self) -> str: From 4d73491d66538d599ef14961833f25dce90b28ee Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 09:49:20 -0600 Subject: [PATCH 026/134] adjust this file to use the game's functools --- Scripts/s4ap/ModConstructor/Cactus_S4AP.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/s4ap/ModConstructor/Cactus_S4AP.py b/Scripts/s4ap/ModConstructor/Cactus_S4AP.py index e97ec39..5721f28 100644 --- a/Scripts/s4ap/ModConstructor/Cactus_S4AP.py +++ b/Scripts/s4ap/ModConstructor/Cactus_S4AP.py @@ -1,4 +1,4 @@ -from functools import wraps +from lib.functools import wraps import services import sims4.resources from sims4.tuning.instance_manager import InstanceManager From 0bfe9d4e3832084f893e332a62049366048c367e Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 10:09:32 -0600 Subject: [PATCH 027/134] make a few more tweaks to our utils files --- Scripts/s4ap/utils/s4ap_generic_utils.py | 5 ++--- Scripts/s4ap/utils/s4ap_reset_utils.py | 4 ++-- Scripts/s4ap/utils/s4ap_save_utils.py | 25 ++++++++++++++++++++++++ Scripts/s4ap/utils/s4ap_sim_utils.py | 1 + 4 files changed, 30 insertions(+), 5 deletions(-) create mode 100644 Scripts/s4ap/utils/s4ap_save_utils.py diff --git a/Scripts/s4ap/utils/s4ap_generic_utils.py b/Scripts/s4ap/utils/s4ap_generic_utils.py index b0dc8e6..7ee534f 100644 --- a/Scripts/s4ap/utils/s4ap_generic_utils.py +++ b/Scripts/s4ap/utils/s4ap_generic_utils.py @@ -4,8 +4,7 @@ from sims4communitylib.events.zone_spin.common_zone_spin_event_dispatcher import CommonZoneSpinEventDispatcher from sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification -from sims4communitylib.utils.save_load.common_save_utils import CommonSaveUtils - +from s4ap.utils.s4ap_save_utils import S4APSaveUtils class S4APUtils: @@ -15,7 +14,7 @@ def trigger_autosave(*_) -> bool: if CommonZoneSpinEventDispatcher().game_loading or not CommonZoneSpinEventDispatcher().game_loaded: return False import sims4.commands - save_game_data = SaveGameData(CommonSaveUtils.get_save_slot_id(), 'S4APAutosave', True, + save_game_data = SaveGameData(S4APSaveUtils.get_save_slot_id(), 'S4APAutosave', True, 5000002) persistence_service = services.get_persistence_service() persistence_service.save_using(persistence_service.save_game_gen, save_game_data, send_save_message=True, diff --git a/Scripts/s4ap/utils/s4ap_reset_utils.py b/Scripts/s4ap/utils/s4ap_reset_utils.py index bb2963c..42923e7 100644 --- a/Scripts/s4ap/utils/s4ap_reset_utils.py +++ b/Scripts/s4ap/utils/s4ap_reset_utils.py @@ -1,7 +1,7 @@ from s4ap.enums.S4APLocalization import S4APTraitId from s4ap.logging.s4ap_logger import S4APLogger from s4ap.utils.s4ap_household_utils import S4APHouseholdUtils -from s4ap.utils.s4ap_skill_utils import get_all_skills_available_for_sim_gen +from s4ap.utils.s4ap_skill_utils import S4APSkillUtils from server_commands.argument_helpers import TunableInstanceParam from sims4.resources import Types from sims4communitylib.enums.traits_enum import CommonTraitId @@ -13,7 +13,7 @@ class ResetSimData: def reset_all_skills(self): for sim_info in S4APHouseholdUtils.get_sim_info_of_all_sims_in_active_household_generator(): - for skill in get_all_skills_available_for_sim_gen(sim_info): + for skill in S4APSkillUtils.get_all_skills_available_for_sim_gen(sim_info): sim_info.remove_statistic(skill) def show_reset_notif(self): diff --git a/Scripts/s4ap/utils/s4ap_save_utils.py b/Scripts/s4ap/utils/s4ap_save_utils.py new file mode 100644 index 0000000..3c68133 --- /dev/null +++ b/Scripts/s4ap/utils/s4ap_save_utils.py @@ -0,0 +1,25 @@ +import services + +class S4APSaveUtils: + + @staticmethod + def get_save_slot() -> Any: + """get_save_slot() + + Retrieve the current save slot. + + :return: The current save slot. + :return: Any + """ + return services.get_persistence_service().get_save_slot_proto_buff() + + @staticmethod + def get_save_slot_id() -> int: + """get_save_slot_id() + + Retrieve the identifier for the current save slot. + + :return: The identifier for the current save slot. + :return: int + """ + return S4APSaveUtils.get_save_slot().slot_id \ No newline at end of file diff --git a/Scripts/s4ap/utils/s4ap_sim_utils.py b/Scripts/s4ap/utils/s4ap_sim_utils.py index bde60fc..b8d1027 100644 --- a/Scripts/s4ap/utils/s4ap_sim_utils.py +++ b/Scripts/s4ap/utils/s4ap_sim_utils.py @@ -1,3 +1,4 @@ +from sims.sim_info import SimInfo class S4APSimUtils: From 2ce00478a0c694ee6a5d1b038a24e19469327952 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 10:13:31 -0600 Subject: [PATCH 028/134] make a few tweaks to the skill event file to remove a few more s4cl imports that are easy to purge/replace --- Scripts/s4ap/events/skill_event_dispatcher.py | 8 ++-- Scripts/s4ap/utils/s4ap_sim_utils.py | 42 ++++++++++++++++++- 2 files changed, 45 insertions(+), 5 deletions(-) diff --git a/Scripts/s4ap/events/skill_event_dispatcher.py b/Scripts/s4ap/events/skill_event_dispatcher.py index 06d7783..f10bdd2 100644 --- a/Scripts/s4ap/events/skill_event_dispatcher.py +++ b/Scripts/s4ap/events/skill_event_dispatcher.py @@ -3,13 +3,13 @@ from s4ap.events.checks.send_check_event import SendLocationEvent from s4ap.logging.s4ap_logger import S4APLogger from s4ap.modinfo import ModInfo +from s4ap.utils.s4ap_sim_utils import S4APSimUtils +from s4ap.utils.s4ap_skill_utils import S4APSkillUtils from sims.sim_info import SimInfo from sims4communitylib.events.event_handling.common_event import CommonEvent from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry from sims4communitylib.services.common_service import CommonService from sims4communitylib.utils.common_injection_utils import CommonInjectionUtils -from sims4communitylib.utils.resources.common_skill_utils import CommonSkillUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils from statistics.skill import Skill logger = S4APLogger.get_log() @@ -40,7 +40,7 @@ def skill(self) -> Skill: @property def skill_id(self) -> int: """The decimal identifier of the Skill.""" - return CommonSkillUtils.get_skill_id(self.skill) + return S4APSkillUtils.get_skill_id(self.skill) class HandleSkillLevelUp(CommonService): @@ -48,7 +48,7 @@ def _on_skill_updated(self, skill: Skill, new_skill_level: int) -> None: if skill.tracker is None or skill.tracker._owner is None: return if not skill.tracker._owner.is_npc: - sim_info = CommonSimUtils.get_sim_info(skill.tracker._owner) + sim_info = S4APSimUtils.get_sim_info(skill.tracker._owner) CommonEventRegistry.get().dispatch(SimSkillLeveledUpEvent(sim_info, skill, new_skill_level)) diff --git a/Scripts/s4ap/utils/s4ap_sim_utils.py b/Scripts/s4ap/utils/s4ap_sim_utils.py index b8d1027..4e5a64e 100644 --- a/Scripts/s4ap/utils/s4ap_sim_utils.py +++ b/Scripts/s4ap/utils/s4ap_sim_utils.py @@ -1,4 +1,9 @@ +import services +from lib.typing import Union +from sims.sim import Sim from sims.sim_info import SimInfo +from sims.sim_info_base_wrapper import SimInfoBaseWrapper +from sims.sim_info_manager import SimInfoManager class S4APSimUtils: @@ -11,4 +16,39 @@ def get_sim_first_name(sim_info: SimInfo): @classmethod def get_sim_instance(cls, sim_identifier: SimInfo): if isinstance(sim_identifier, SimInfo): - return sim_identifier.get_sim_instance() \ No newline at end of file + return sim_identifier.get_sim_instance() + + @classmethod + def get_sim_info( + cls, + sim_identifier: Union[int, Sim, SimInfo, SimInfoBaseWrapper] + ) -> Union[SimInfo, SimInfoBaseWrapper, None]: + """get_sim_info(sim_identifier) + + Retrieve a SimInfo instance from a Sim identifier. + + :param sim_identifier: The identifier or instance of a Sim to use. + :type sim_identifier: Union[int, Sim, SimInfo, SimInfoBaseWrapper] + :return: The SimInfo of the specified Sim instance or None if SimInfo is not found. + :rtype: Union[SimInfo, SimInfoBaseWrapper, None] + """ + if sim_identifier is None or isinstance(sim_identifier, SimInfo): + return sim_identifier + if isinstance(sim_identifier, SimInfoBaseWrapper): + return sim_identifier.get_sim_info() + if isinstance(sim_identifier, Sim): + return sim_identifier.sim_info + if isinstance(sim_identifier, int): + return cls.get_sim_info_manager().get(sim_identifier) + return sim_identifier + + @classmethod + def get_sim_info_manager(cls) -> SimInfoManager: + """get_sim_info_manager() + + Retrieve the manager that manages the Sim Info of all Sims in a game world. + + :return: The manager that manages the Sim Info of all Sims in a game world. + :rtype: SimInfoManager + """ + return services.sim_info_manager() \ No newline at end of file From 7a1f5330701c859319cb258449f57ff43cdf3f16 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 10:14:10 -0600 Subject: [PATCH 029/134] purge another s4cl import in the career event file --- Scripts/s4ap/events/career_event_dispatcher.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Scripts/s4ap/events/career_event_dispatcher.py b/Scripts/s4ap/events/career_event_dispatcher.py index 197de74..c21d36e 100644 --- a/Scripts/s4ap/events/career_event_dispatcher.py +++ b/Scripts/s4ap/events/career_event_dispatcher.py @@ -3,12 +3,12 @@ from s4ap.events.checks.send_check_event import SendLocationEvent from s4ap.logging.s4ap_logger import S4APLogger from s4ap.modinfo import ModInfo +from s4ap.utils.s4ap_household_utils import S4APHouseholdUtils from s4ap.utils.s4ap_sim_utils import S4APSimUtils from sims4communitylib.events.event_handling.common_event import CommonEvent from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry from sims4communitylib.services.common_service import CommonService from sims4communitylib.utils.common_injection_utils import CommonInjectionUtils -from sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils log = S4APLogger.get_log() log.enable() @@ -44,7 +44,7 @@ def _on_milestone_complete(original, self, *args, **kwargs): career = self._current_track.get_career_name(self._sim_info).hash level = self._user_level sim_info = self._sim_info - if sim_info in CommonHouseholdUtils.get_sim_info_of_all_sims_in_active_household_generator(): + if sim_info in S4APHouseholdUtils.get_sim_info_of_all_sims_in_active_household_generator(): sim_name = S4APSimUtils.get_sim_first_name(sim_info) OnCareerPromotionEvent.get()._on_promotion(career, level, sim_name) return result From e6c241883b0591f43e0c3009887cdd22dfa291c6 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 10:16:34 -0600 Subject: [PATCH 030/134] replace another s4cl import in the aspiration file --- .../events/aspiration_event_dispatcher.py | 6 ++-- Scripts/s4ap/utils/s4ap_game_client_utils.py | 29 +++++++++++++++++++ Scripts/s4ap/utils/s4ap_sim_utils.py | 18 +++++++++++- 3 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 Scripts/s4ap/utils/s4ap_game_client_utils.py diff --git a/Scripts/s4ap/events/aspiration_event_dispatcher.py b/Scripts/s4ap/events/aspiration_event_dispatcher.py index 026f54f..5415511 100644 --- a/Scripts/s4ap/events/aspiration_event_dispatcher.py +++ b/Scripts/s4ap/events/aspiration_event_dispatcher.py @@ -3,11 +3,11 @@ from s4ap.enums.S4APLocalization import HashLookup from s4ap.events.checks.send_check_event import SendLocationEvent from s4ap.modinfo import ModInfo +from s4ap.utils.s4ap_sim_utils import S4APSimUtils from sims4communitylib.events.event_handling.common_event import CommonEvent from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry from sims4communitylib.services.common_service import CommonService from sims4communitylib.utils.common_injection_utils import CommonInjectionUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils class MilestoneCompletion(CommonEvent): @@ -42,9 +42,9 @@ class OnMilestoneCompletionEvent(CommonService): def _on_milestone_completion(self, aspiration, *_, **__): if aspiration.aspiration_type == AspriationType.FULL_ASPIRATION: - if aspiration.is_valid_for_sim(CommonSimUtils.get_active_sim_info()): + if aspiration.is_valid_for_sim(S4APSimUtils.get_active_sim_info()): aspiration_display_name = aspiration.display_name - track = CommonSimUtils.get_active_sim_info().primary_aspiration + track = S4APSimUtils.get_active_sim_info().primary_aspiration track_display_text = track.display_text # this takes the primary aspiration name as a LocalizedString object return CommonEventRegistry.get().dispatch( MilestoneCompletion(track_display_text, aspiration_display_name, aspiration)) diff --git a/Scripts/s4ap/utils/s4ap_game_client_utils.py b/Scripts/s4ap/utils/s4ap_game_client_utils.py new file mode 100644 index 0000000..9f993d3 --- /dev/null +++ b/Scripts/s4ap/utils/s4ap_game_client_utils.py @@ -0,0 +1,29 @@ +import services +from server.clientmanager import ClientManager + +class S4APGameClientUtils: + + @staticmethod + def get_first_game_client() -> Union[Client, None]: + """get_first_game_client() + + Retrieve an instance of the first available Game Client. + + :return: An instance of the first available Game Client or None if not found. + :rtype: Union[Client, None] + """ + client_manager = S4APGameClientUtils.get_game_client_manager() + if client_manager is None: + return None + return client_manager.get_first_client() + + @staticmethod + def get_game_client_manager() -> ClientManager: + """get_game_client_manager() + + Retrieve the manager that manages the Game Clients for the game. + + :return: The manager that manages the Game Clients for the game. + :rtype: ClientManager + """ + return services.client_manager() \ No newline at end of file diff --git a/Scripts/s4ap/utils/s4ap_sim_utils.py b/Scripts/s4ap/utils/s4ap_sim_utils.py index 4e5a64e..181d363 100644 --- a/Scripts/s4ap/utils/s4ap_sim_utils.py +++ b/Scripts/s4ap/utils/s4ap_sim_utils.py @@ -1,5 +1,6 @@ import services from lib.typing import Union +from s4ap.utils.s4ap_game_client_utils import S4APGameClientUtils from sims.sim import Sim from sims.sim_info import SimInfo from sims.sim_info_base_wrapper import SimInfoBaseWrapper @@ -51,4 +52,19 @@ def get_sim_info_manager(cls) -> SimInfoManager: :return: The manager that manages the Sim Info of all Sims in a game world. :rtype: SimInfoManager """ - return services.sim_info_manager() \ No newline at end of file + return services.sim_info_manager() + + @classmethod + def get_active_sim_info(cls) -> Union[SimInfo, None]: + """get_active_sim_info() + + Retrieve a SimInfo object of the Currently Active Sim. + + :return: The SimInfo of the Active Sim or None if not found. + :rtype: Union[SimInfo, None] + """ + client = S4APGameClientUtils.get_first_game_client() + if client is None: + return None + # noinspection PyPropertyAccess + return client.active_sim_info \ No newline at end of file From 3bac0edfc8b910cea3ef8f6f56a3bad53dc233a6 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 11:36:40 -0600 Subject: [PATCH 031/134] replace s4cl imports that are easy to replace in the item receiving file --- .../s4ap/events/items/receive_item_event.py | 34 ++++++++------- Scripts/s4ap/utils/s4ap_career_utils.py | 17 +++++++- Scripts/s4ap/utils/s4ap_generic_utils.py | 9 +++- Scripts/s4ap/utils/s4ap_sim_currency_utils.py | 24 +++++++++++ Scripts/s4ap/utils/s4ap_trait_utils.py | 41 +++++++++++++++++++ 5 files changed, 108 insertions(+), 17 deletions(-) create mode 100644 Scripts/s4ap/utils/s4ap_sim_currency_utils.py create mode 100644 Scripts/s4ap/utils/s4ap_trait_utils.py diff --git a/Scripts/s4ap/events/items/receive_item_event.py b/Scripts/s4ap/events/items/receive_item_event.py index f4fe904..7022034 100644 --- a/Scripts/s4ap/events/items/receive_item_event.py +++ b/Scripts/s4ap/events/items/receive_item_event.py @@ -1,20 +1,22 @@ import time +from protocolbuffers import Consts_pb2 + from s4ap.enums.S4APLocalization import S4APTraitId from s4ap.logging.s4ap_logger import S4APLogger from s4ap.modinfo import ModInfo from s4ap.persistance.ap_session_data_store import S4APSessionStoreUtils +from s4ap.utils.s4ap_career_utils import S4APCareerUtils +from s4ap.utils.s4ap_generic_utils import S4APUtils +from s4ap.utils.s4ap_household_utils import S4APHouseholdUtils +from s4ap.utils.s4ap_sim_currency_utils import S4APSimCurrencyUtils +from s4ap.utils.s4ap_sim_utils import S4APSimUtils from s4ap.utils.s4ap_skill_utils import lock_skills -from sims4communitylib.enums.common_currency_modify_reasons import CommonCurrencyModifyReason +from s4ap.utils.s4ap_trait_utils import S4APTraitUtils +from sims4.resources import Types from sims4communitylib.events.event_handling.common_event import CommonEvent from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification -from sims4communitylib.utils.sims.common_career_utils import CommonCareerUtils -from sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils -from sims4communitylib.utils.sims.common_sim_career_utils import CommonSimCareerUtils -from sims4communitylib.utils.sims.common_sim_currency_utils import CommonSimCurrencyUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils from collections import Counter log = S4APLogger.get_log() log.enable() @@ -129,16 +131,16 @@ def handle_items(self, items): log.debug(f'Processing {item}') if 'Simoleons' in item: # Simoleon items are either '5000 Simoleons' or '2000 Simoleons' number = item.split()[0] - CommonSimCurrencyUtils.add_simoleons_to_household(CommonSimUtils.get_active_sim_info(), int(number), - CommonCurrencyModifyReason.CHEAT) + S4APSimCurrencyUtils.add_simoleons_to_household(S4APSimUtils.get_active_sim_info(), int(number), + Consts_pb2.TELEMETRY_MONEY_CHEAT) time.sleep(0.2) elif 'boost' in item.lower(): if 'career' in item.lower(): - for sim_info in CommonHouseholdUtils.get_sim_info_of_all_sims_in_active_household_generator(): - for career in CommonSimCareerUtils.get_all_careers_for_sim_gen(sim_info): + for sim_info in S4APHouseholdUtils.get_sim_info_of_all_sims_in_active_household_generator(): + for career in S4APCareerUtils.get_all_careers_for_sim_gen(sim_info): if career is None: break - old_work_performance = CommonCareerUtils.get_work_performance(career) + old_work_performance = S4APCareerUtils.get_work_performance(career) work_performance_left_to_add = 100 - old_work_performance career.add_work_performance(work_performance_left_to_add) career.resend_career_data() @@ -157,10 +159,12 @@ def handle_items(self, items): rem_traits = (S4APTraitId.SKILL_GAIN_BOOST_2_5X, S4APTraitId.SKILL_GAIN_BOOST_3X, S4APTraitId.SKILL_GAIN_BOOST_3_5X) add_trait = S4APTraitId.SKILL_GAIN_BOOST_4X - for sim_info in CommonHouseholdUtils.get_sim_info_of_all_sims_in_active_household_generator(): + for sim_info in S4APHouseholdUtils.get_sim_info_of_all_sims_in_active_household_generator(): if rem_traits is not None: - CommonTraitUtils.remove_traits(sim_info, rem_traits) - CommonTraitUtils.add_trait(sim_info, add_trait) + S4APTraitUtils.remove_traits(sim_info, rem_traits) + trait_obj = S4APUtils.load_instance(Types.TRAIT, add_trait) + if trait_obj and not sim_info.has_trait(trait_obj): + sim_info.add_trait(trait_obj) elif 'skill' in item.lower(): count = data_store.get_items().count(item) count += 2 diff --git a/Scripts/s4ap/utils/s4ap_career_utils.py b/Scripts/s4ap/utils/s4ap_career_utils.py index 96f2cef..6aed926 100644 --- a/Scripts/s4ap/utils/s4ap_career_utils.py +++ b/Scripts/s4ap/utils/s4ap_career_utils.py @@ -146,4 +146,19 @@ def get_branches(cls, career_track: TunableCareerTrack, include_sub_branches: bo # noinspection PyUnresolvedReferences if hasattr(career_track, 'branches') and career_track.branches is not None: return tuple(career_track.branches) - return tuple() \ No newline at end of file + return tuple() + + @staticmethod + def get_work_performance(career: Career) -> float: + """get_work_performance(career) + + Add an amount to the work performance of a career. + + :param career: The career to modify. + :type career: Career + :return: The amount of work performance acquired in the specified Career. + :rtype: float + """ + if career is None: + return 0.0 + return career.work_performance \ No newline at end of file diff --git a/Scripts/s4ap/utils/s4ap_generic_utils.py b/Scripts/s4ap/utils/s4ap_generic_utils.py index 7ee534f..b4ed556 100644 --- a/Scripts/s4ap/utils/s4ap_generic_utils.py +++ b/Scripts/s4ap/utils/s4ap_generic_utils.py @@ -27,4 +27,11 @@ def trigger_autosave(*_) -> bool: ).show() CommonExceptionHandler.log_exception(ModInfo.get_identity(), 'An exception occurred while autosaving.', exception=ex) - return False \ No newline at end of file + return False + + def load_instance(self, instance_type: Types, instance_id: int): + """Load a resource instance (Trait, Buff, Mood, etc.) directly from the game.""" + instance_manager = services.get_instance_manager(instance_type) + if instance_manager is None: + return None + return instance_manager.get(instance_id) \ No newline at end of file diff --git a/Scripts/s4ap/utils/s4ap_sim_currency_utils.py b/Scripts/s4ap/utils/s4ap_sim_currency_utils.py new file mode 100644 index 0000000..e1aea1e --- /dev/null +++ b/Scripts/s4ap/utils/s4ap_sim_currency_utils.py @@ -0,0 +1,24 @@ +from sims.sim_info import SimInfo +from protocolbuffers import Consts_pb2 + +class S4APSimCurrencyUtils: + + @classmethod + def add_simoleons_to_household(cls, sim_info: SimInfo, amount: int, reason: int, **kwargs) -> bool: + """ + Add an amount of simoleons to the Household of a Sim. + + :param sim_info: The Sim whose household to modify. + :param amount: The number of simoleons to add (negative values will subtract). + :param reason: A string reason for the funds change (for notifications/logs). + :return: True if successful, False otherwise. + """ + if sim_info is None or sim_info.household is None: + return False + + funds = sim_info.household.funds + if funds is None: + return False + + funds.add(amount, reason, **kwargs) + return True diff --git a/Scripts/s4ap/utils/s4ap_trait_utils.py b/Scripts/s4ap/utils/s4ap_trait_utils.py new file mode 100644 index 0000000..7f5257d --- /dev/null +++ b/Scripts/s4ap/utils/s4ap_trait_utils.py @@ -0,0 +1,41 @@ +from lib.typing import Iterator, Optional +from s4ap.utils.s4ap_generic_utils import S4APUtils +from sims.sim_info import SimInfo +from sims4.resources import Types +from traits.traits import Trait + +class S4APTraitUtils: + + @classmethod + def remove_traits(cls, sim_info: SimInfo, traits: Iterator[Union[int, Trait]]) -> bool: + """Remove traits from a Sim using only vanilla TS4 API. + + :param sim_info: The Sim to remove the traits from. + :param traits: An iterator of Trait instances or trait IDs. + :return: True if all traits were successfully removed, False otherwise. + """ + all_removed = True + + for trait_item in traits: + trait = cls.load_trait_by_id(trait_item) + if trait is None: + all_removed = False + continue + + if sim_info.has_trait(trait): + if not sim_info.remove_trait(trait): + all_removed = False + + return all_removed + + @classmethod + def load_trait_by_id(cls, trait) -> Optional['Trait']: + if isinstance(trait, Trait): + return trait + + try: + trait_id = int(trait) + except Exception: + return None + + return S4APUtils.load_instance(Types.TRAIT, trait_id) \ No newline at end of file From f3b061f57c8dc704b4f4a8e17b6c81ac6d14658f Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 11:41:35 -0600 Subject: [PATCH 032/134] replace s4cl imports in localization file --- Scripts/s4ap/enums/S4APLocalization.py | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/Scripts/s4ap/enums/S4APLocalization.py b/Scripts/s4ap/enums/S4APLocalization.py index fcd086f..5a45870 100644 --- a/Scripts/s4ap/enums/S4APLocalization.py +++ b/Scripts/s4ap/enums/S4APLocalization.py @@ -1,9 +1,6 @@ -from sims4communitylib.enums.icons_enum import CommonIconId -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.enums.traits_enum import CommonTraitId +from enum import Int - -class S4APTraitId(CommonTraitId): +class S4APTraitId(Int): LOCK_MIXOLOGY_SKILL: 'S4APTraitId' = 3494693146 LOCK_MISCHIEF_SKILL: 'S4APTraitId' = 3494693147 LOCK_HANDINESS_SKILL: 'S4APTraitId' = 3494693148 @@ -31,7 +28,7 @@ class S4APTraitId(CommonTraitId): SHOW_RECEIVED_SKILLS: 'S4APTraitId' = 3511470836 RESYNC_LOCATIONS: 'S4APTraitId' = 2224316686 SHOW_YAML_OPTIONS: 'S4APTraitId' = 2241086516 -class S4APStringId(CommonStringId): +class S4APStringId(Int): # ap_client CONNECTION_REFUSED: 'S4APStringId' = 0x964EABE6 CONNECTION_ERROR: 'S4APStringId' = 0xC50BC4AF @@ -55,7 +52,7 @@ class S4APStringId(CommonStringId): CONFLICTING_CONNECTION_DATA_DESC: 'S4APStringId' = 0x3E4E79D3 -class S4APIconId(CommonIconId): +class S4APIconId(Int): AP_LOGO_BLUE: 'S4APIconId' = 0xBD85B76B1017163F class S4APBaseGameSkills: @@ -396,9 +393,3 @@ def get_career_name(self, hash_value, level): for career_location in careers_list: if career in career_location: return career_location - -class SkillID(int): - ADULT_MAJOR_ACTING = 194727 - ADULT_MAJOR_ARCHAEOLOGY = 174237 - ADULT_MAJOR_BAKING = None - ADULT_MAJOR_BARTENDING = None \ No newline at end of file From 160a15c7b678b1d5b102e4fd9cbfeb737642d51a Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 11:42:37 -0600 Subject: [PATCH 033/134] fix missing typing import --- Scripts/s4ap/utils/s4ap_trait_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/s4ap/utils/s4ap_trait_utils.py b/Scripts/s4ap/utils/s4ap_trait_utils.py index 7f5257d..cf5d54f 100644 --- a/Scripts/s4ap/utils/s4ap_trait_utils.py +++ b/Scripts/s4ap/utils/s4ap_trait_utils.py @@ -1,4 +1,4 @@ -from lib.typing import Iterator, Optional +from lib.typing import Iterator, Optional, Union from s4ap.utils.s4ap_generic_utils import S4APUtils from sims.sim_info import SimInfo from sims4.resources import Types From 9bed3ca20f026ca68b7bf0c676f07efe8615184a Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 11:43:17 -0600 Subject: [PATCH 034/134] use lib's collections --- Scripts/s4ap/events/items/receive_item_event.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/s4ap/events/items/receive_item_event.py b/Scripts/s4ap/events/items/receive_item_event.py index 7022034..1a519c2 100644 --- a/Scripts/s4ap/events/items/receive_item_event.py +++ b/Scripts/s4ap/events/items/receive_item_event.py @@ -17,7 +17,7 @@ from sims4communitylib.events.event_handling.common_event import CommonEvent from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification -from collections import Counter +from lib.collections import Counter log = S4APLogger.get_log() log.enable() From af361dfb3817159c2daf0f0d4a0b8f8aeff4f305 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 11:57:01 -0600 Subject: [PATCH 035/134] replace s4cl injection calls with core library injection --- Scripts/s4ap/events/aspiration_event_dispatcher.py | 6 ++---- Scripts/s4ap/events/career_event_dispatcher.py | 6 ++---- Scripts/s4ap/events/skill_event_dispatcher.py | 5 ++--- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/Scripts/s4ap/events/aspiration_event_dispatcher.py b/Scripts/s4ap/events/aspiration_event_dispatcher.py index 5415511..8cb0f07 100644 --- a/Scripts/s4ap/events/aspiration_event_dispatcher.py +++ b/Scripts/s4ap/events/aspiration_event_dispatcher.py @@ -7,7 +7,7 @@ from sims4communitylib.events.event_handling.common_event import CommonEvent from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry from sims4communitylib.services.common_service import CommonService -from sims4communitylib.utils.common_injection_utils import CommonInjectionUtils +from lot51_core.utils.injection import inject_to class MilestoneCompletion(CommonEvent): @@ -29,9 +29,7 @@ def milestone_display_name(self): def milestone_count(self): return self._milestone_count - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), AspirationTracker, - AspirationTracker.complete_milestone.__name__, handle_exceptions=True) +@inject_to(AspirationTracker, AspirationTracker.complete_milestone.__name__) def _on_milestone_complete(original, self, *args, **kwargs): result = original(self, *args, **kwargs) OnMilestoneCompletionEvent.get()._on_milestone_completion(*args, **kwargs) diff --git a/Scripts/s4ap/events/career_event_dispatcher.py b/Scripts/s4ap/events/career_event_dispatcher.py index c21d36e..640dbee 100644 --- a/Scripts/s4ap/events/career_event_dispatcher.py +++ b/Scripts/s4ap/events/career_event_dispatcher.py @@ -8,7 +8,7 @@ from sims4communitylib.events.event_handling.common_event import CommonEvent from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry from sims4communitylib.services.common_service import CommonService -from sims4communitylib.utils.common_injection_utils import CommonInjectionUtils +from lot51_core.utils.injection import inject_to log = S4APLogger.get_log() log.enable() @@ -36,9 +36,7 @@ def _on_promotion(self, career, user_level: int, name: str, *_, **__): log.debug(f'{name} was promoted to {career_name}') CommonEventRegistry.get().dispatch(CareerPromotionEvent(career, user_level)) - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), CareerBase, - CareerBase._handle_promotion.__name__, handle_exceptions=True) +@inject_to(CareerBase, CareerBase._handle_promotion.__name__) def _on_milestone_complete(original, self, *args, **kwargs): result = original(self, *args, **kwargs) career = self._current_track.get_career_name(self._sim_info).hash diff --git a/Scripts/s4ap/events/skill_event_dispatcher.py b/Scripts/s4ap/events/skill_event_dispatcher.py index f10bdd2..1312520 100644 --- a/Scripts/s4ap/events/skill_event_dispatcher.py +++ b/Scripts/s4ap/events/skill_event_dispatcher.py @@ -9,7 +9,7 @@ from sims4communitylib.events.event_handling.common_event import CommonEvent from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry from sims4communitylib.services.common_service import CommonService -from sims4communitylib.utils.common_injection_utils import CommonInjectionUtils +from lot51_core.utils.injection import inject_to from statistics.skill import Skill logger = S4APLogger.get_log() @@ -51,8 +51,7 @@ def _on_skill_updated(self, skill: Skill, new_skill_level: int) -> None: sim_info = S4APSimUtils.get_sim_info(skill.tracker._owner) CommonEventRegistry.get().dispatch(SimSkillLeveledUpEvent(sim_info, skill, new_skill_level)) - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), Skill, Skill._handle_skill_up.__name__) +@inject_to(Skill, Skill._handle_skill_up.__name__) def _common_on_sim_skill_level_up(original, self, *args, **kwargs): result = original(self, *args, **kwargs) HandleSkillLevelUp.get()._on_skill_updated(self, *args, **kwargs) From fa08ca556f358c288cedd0d2467a2947be124692 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 11:57:11 -0600 Subject: [PATCH 036/134] use lib.Typing --- Scripts/s4ap/persistance/ap_data_manager.py | 2 +- Scripts/s4ap/persistance/ap_data_store.py | 2 +- Scripts/s4ap/persistance/ap_data_utils.py | 2 +- Scripts/s4ap/persistance/ap_session_data_store.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Scripts/s4ap/persistance/ap_data_manager.py b/Scripts/s4ap/persistance/ap_data_manager.py index be7a3bd..2361b9b 100644 --- a/Scripts/s4ap/persistance/ap_data_manager.py +++ b/Scripts/s4ap/persistance/ap_data_manager.py @@ -1,4 +1,4 @@ -from typing import Tuple +from lib.typing import Tuple from s4ap.modinfo import ModInfo from sims4communitylib.mod_support.mod_identity import CommonModIdentity diff --git a/Scripts/s4ap/persistance/ap_data_store.py b/Scripts/s4ap/persistance/ap_data_store.py index 9a5f6c5..a04bc63 100644 --- a/Scripts/s4ap/persistance/ap_data_store.py +++ b/Scripts/s4ap/persistance/ap_data_store.py @@ -1,4 +1,4 @@ -from typing import Any, Dict +from lib.typing import Any, Dict from sims4communitylib.persistence.data_stores.common_data_store import CommonDataStore diff --git a/Scripts/s4ap/persistance/ap_data_utils.py b/Scripts/s4ap/persistance/ap_data_utils.py index 4c59ceb..22d5e97 100644 --- a/Scripts/s4ap/persistance/ap_data_utils.py +++ b/Scripts/s4ap/persistance/ap_data_utils.py @@ -1,4 +1,4 @@ -from typing import Type, Union, Dict, Any +from lib.typing import Type, Union, Dict, Any from s4ap.modinfo import ModInfo from s4ap.persistance.ap_data_manager import S4APDataManager diff --git a/Scripts/s4ap/persistance/ap_session_data_store.py b/Scripts/s4ap/persistance/ap_session_data_store.py index 1de820a..5364f1b 100644 --- a/Scripts/s4ap/persistance/ap_session_data_store.py +++ b/Scripts/s4ap/persistance/ap_session_data_store.py @@ -1,4 +1,4 @@ -from typing import Any +from lib.typing import Any from s4ap.jsonio.s4ap_json import print_json from s4ap.events.Utils.allow_read_items import AllowReceiveItems from s4ap.logging.s4ap_logger import S4APLogger From 2a7f1d9b507e5d84810d575bf9f37427778a458e Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 12:05:40 -0600 Subject: [PATCH 037/134] replace another s4cl function with a vanilla equivalent helper --- Scripts/s4ap/utils/s4ap_generic_utils.py | 7 ++++++- Scripts/s4ap/utils/s4ap_phone_utils.py | 8 ++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Scripts/s4ap/utils/s4ap_generic_utils.py b/Scripts/s4ap/utils/s4ap_generic_utils.py index b4ed556..1c2f63c 100644 --- a/Scripts/s4ap/utils/s4ap_generic_utils.py +++ b/Scripts/s4ap/utils/s4ap_generic_utils.py @@ -1,6 +1,7 @@ import services from s4ap.modinfo import ModInfo from services.persistence_service import SaveGameData +from sims4.resources import Types from sims4communitylib.events.zone_spin.common_zone_spin_event_dispatcher import CommonZoneSpinEventDispatcher from sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification @@ -34,4 +35,8 @@ def load_instance(self, instance_type: Types, instance_id: int): instance_manager = services.get_instance_manager(instance_type) if instance_manager is None: return None - return instance_manager.get(instance_id) \ No newline at end of file + return instance_manager.get(instance_id) + + def load_icon_by_id(icon_id: int): + manager = services.get_instance_manager(Types.PNG) + return manager.get(icon_id) # Returns vanilla ResourceKey / instance \ No newline at end of file diff --git a/Scripts/s4ap/utils/s4ap_phone_utils.py b/Scripts/s4ap/utils/s4ap_phone_utils.py index e534c40..f6b0948 100644 --- a/Scripts/s4ap/utils/s4ap_phone_utils.py +++ b/Scripts/s4ap/utils/s4ap_phone_utils.py @@ -7,6 +7,7 @@ from s4ap.modinfo import ModInfo from s4ap.persistance.ap_session_data_store import S4APSessionStoreUtils from s4ap.utils.s4ap_career_utils import S4APCareerUtils +from s4ap.utils.s4ap_generic_utils import S4APUtils from s4ap.utils.s4ap_household_utils import S4APHouseholdUtils from s4ap.utils.s4ap_skill_utils import S4APSkillUtils from server_commands.argument_helpers import TunableInstanceParam @@ -16,7 +17,6 @@ from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry from sims4communitylib.events.sim.events.sim_trait_added import S4CLSimTraitAddedEvent from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification -from sims4communitylib.utils.common_icon_utils import CommonIconUtils from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils from ui.ui_dialog_picker import ObjectPickerRow @@ -195,17 +195,17 @@ def _on_chosen(_, outcome: CommonChoiceOutcome): ObjectPickerRow( option_id=1, name= CommonLocalizationUtils.create_localized_string(goal.replace("_", " ").title()), - icon= CommonIconUtils.load_icon_by_id(1903793975082081275) + icon= S4APUtils.load_icon_by_id(1903793975082081275) ), ObjectPickerRow( option_id=2, name= CommonLocalizationUtils.create_localized_string(career.replace("_", " ").title()), - icon= CommonIconUtils.load_icon_by_id(12028399282094277793) + icon= S4APUtils.load_icon_by_id(12028399282094277793) ), ObjectPickerRow( option_id=3, name= CommonLocalizationUtils.create_localized_string(display), - icon= CommonIconUtils.load_icon_by_id(5906963266871873908) + icon= S4APUtils.load_icon_by_id(5906963266871873908) ) ] From 2bc4b27a52ebb7d9406b6061b7fb8de1bd3943f2 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 12:14:46 -0600 Subject: [PATCH 038/134] make a vanilla compatible replacement for this dialog stuff for showing the aspiration/career --- Scripts/s4ap/utils/s4ap_phone_utils.py | 49 +++++++++++++------------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/Scripts/s4ap/utils/s4ap_phone_utils.py b/Scripts/s4ap/utils/s4ap_phone_utils.py index f6b0948..782d38a 100644 --- a/Scripts/s4ap/utils/s4ap_phone_utils.py +++ b/Scripts/s4ap/utils/s4ap_phone_utils.py @@ -11,6 +11,8 @@ from s4ap.utils.s4ap_household_utils import S4APHouseholdUtils from s4ap.utils.s4ap_skill_utils import S4APSkillUtils from server_commands.argument_helpers import TunableInstanceParam +from services import get_instance_manager +from sims4.localization import LocalizationHelperTuning, TunableLocalizedStringFactory from sims4.resources import Types from sims4communitylib.dialogs.choose_object_dialog import CommonChooseObjectDialog from sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome @@ -18,7 +20,7 @@ from sims4communitylib.events.sim.events.sim_trait_added import S4CLSimTraitAddedEvent from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from ui.ui_dialog_picker import ObjectPickerRow +from ui.ui_dialog_picker import ObjectPickerRow, UiObjectPicker logger = S4APLogger.get_log() logger.enable() @@ -188,30 +190,27 @@ def _show_aspiration_and_career(event_data: S4CLSimTraitAddedEvent): display = 'No Skill Multiplier' else: display = 'No Skill Multiplier' - def _on_chosen(_, outcome: CommonChoiceOutcome): - if outcome == CommonChoiceOutcome.CHOICE_MADE: - dialog.show(on_chosen=_on_chosen) + # Build rows as tuples: (id, name, icon) options = [ - ObjectPickerRow( - option_id=1, - name= CommonLocalizationUtils.create_localized_string(goal.replace("_", " ").title()), - icon= S4APUtils.load_icon_by_id(1903793975082081275) - ), - ObjectPickerRow( - option_id=2, - name= CommonLocalizationUtils.create_localized_string(career.replace("_", " ").title()), - icon= S4APUtils.load_icon_by_id(12028399282094277793) - ), - ObjectPickerRow( - option_id=3, - name= CommonLocalizationUtils.create_localized_string(display), - icon= S4APUtils.load_icon_by_id(5906963266871873908) - ) + (1, LocalizationHelperTuning.get_raw_text(goal.replace("_", " ").title()), 1903793975082081275), + (2, LocalizationHelperTuning.get_raw_text(career.replace("_", " ").title()), 12028399282094277793), + (3, LocalizationHelperTuning.get_raw_text(display), 5906963266871873908) ] - dialog = CommonChooseObjectDialog( - 'Your Yaml Options Plus Skill Multiplier', - 'Options + Skill Multiplier', - choices=options - ) - dialog.show(on_chosen=_on_chosen) + # Create the picker + picker = UiObjectPicker.TunableFactory().default + + # Set title and description + picker.title = LocalizationHelperTuning.get_raw_text('Your Yaml Options Plus Skill Multiplier') + picker.text = LocalizationHelperTuning.get_raw_text('Options + Skill Multiplier') + + # Add the rows + for opt_id, name, icon_id in options: + icon = get_instance_manager(Types.PNG).get(icon_id) + picker.add_row(opt_id, name, icon_resource_key=icon) + + # Show dialog + def _on_chosen(dialog, option_id): + pass # player chose something, no need to do anything about it + + picker.show(_on_chosen) From d1571b2057ff294989ee485d4cf5654dcb6b3878 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 12:27:56 -0600 Subject: [PATCH 039/134] replace notification and choice things from s4cl with equivalent vanilla functionality --- Scripts/s4ap/utils/s4ap_phone_utils.py | 41 +++++++++++++------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/Scripts/s4ap/utils/s4ap_phone_utils.py b/Scripts/s4ap/utils/s4ap_phone_utils.py index 782d38a..5d2a2de 100644 --- a/Scripts/s4ap/utils/s4ap_phone_utils.py +++ b/Scripts/s4ap/utils/s4ap_phone_utils.py @@ -7,19 +7,15 @@ from s4ap.modinfo import ModInfo from s4ap.persistance.ap_session_data_store import S4APSessionStoreUtils from s4ap.utils.s4ap_career_utils import S4APCareerUtils -from s4ap.utils.s4ap_generic_utils import S4APUtils from s4ap.utils.s4ap_household_utils import S4APHouseholdUtils from s4ap.utils.s4ap_skill_utils import S4APSkillUtils from server_commands.argument_helpers import TunableInstanceParam from services import get_instance_manager -from sims4.localization import LocalizationHelperTuning, TunableLocalizedStringFactory +from sims4.localization import LocalizationHelperTuning from sims4.resources import Types -from sims4communitylib.dialogs.choose_object_dialog import CommonChooseObjectDialog -from sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry from sims4communitylib.events.sim.events.sim_trait_added import S4CLSimTraitAddedEvent -from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from ui.ui_dialog_notification import UiDialogNotification from ui.ui_dialog_picker import ObjectPickerRow, UiObjectPicker logger = S4APLogger.get_log() @@ -68,22 +64,23 @@ def _handle_show_max_skills_phone(event_data: S4CLSimTraitAddedEvent): for item, item_info in sorted(skills.items()): options.append(ObjectPickerRow( option_id=option, - name=CommonLocalizationUtils.create_localized_string( - f'{item} Max is {item_info[0] or 2}'), + name = LocalizationHelperTuning.get_raw_text(f'{item} Max is {item_info[0] or 2}'), icon=item_info[1] )) option += 1 - def _on_chosen(_, outcome: CommonChoiceOutcome): - if outcome == CommonChoiceOutcome.CHOICE_MADE: - dialog.show(on_chosen=_on_chosen) + picker = UiObjectPicker.TunableFactory().default + picker.title = LocalizationHelperTuning.get_raw_text('Max Possible Skills') + picker.text = LocalizationHelperTuning.get_raw_text('The highest you can level your skills to.') - dialog = CommonChooseObjectDialog( - 'Max Possible Skills', - 'The highest you can level your skills to.', - choices=options - ) - dialog.show(on_chosen=_on_chosen) + # Add the ObjectPickerRow objects directly + for row in options: + picker.add_row(row.option_id, row.name, icon_resource_key=row.icon) + + def _on_chosen(dialog, option_id): + pass # no action needed + + picker.show(_on_chosen) @CommonEventRegistry.handle_events(ModInfo.get_identity()) def _resync_locations(event_data: S4CLSimTraitAddedEvent): @@ -151,11 +148,13 @@ def _resync_locations(event_data: S4CLSimTraitAddedEvent): locations.append(milestone_display_name) print_json(locations, 'locations_cached.json') print_json(True, 'sync.json') - notif = CommonBasicNotification( - 'Locations Resynced', - '' + title = LocalizationHelperTuning.get_raw_text('Locations Resynced') + description = LocalizationHelperTuning.get_raw_text('') + dialog = UiDialogNotification.TunableFactory().default( + title=title, + text=description ) - notif.show() + dialog.show_dialog() @CommonEventRegistry.handle_events(ModInfo.get_identity()) def _show_aspiration_and_career(event_data: S4CLSimTraitAddedEvent): From cced4b111cef1645badef86986c5fb90dea7c495 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 12:30:33 -0600 Subject: [PATCH 040/134] replace notification from s4cl with vanilla equivalent --- Scripts/s4ap/utils/s4ap_reset_utils.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Scripts/s4ap/utils/s4ap_reset_utils.py b/Scripts/s4ap/utils/s4ap_reset_utils.py index 42923e7..6af49f6 100644 --- a/Scripts/s4ap/utils/s4ap_reset_utils.py +++ b/Scripts/s4ap/utils/s4ap_reset_utils.py @@ -3,9 +3,10 @@ from s4ap.utils.s4ap_household_utils import S4APHouseholdUtils from s4ap.utils.s4ap_skill_utils import S4APSkillUtils from server_commands.argument_helpers import TunableInstanceParam +from sims4.localization import LocalizationHelperTuning from sims4.resources import Types from sims4communitylib.enums.traits_enum import CommonTraitId -from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification +from ui.ui_dialog_notification import UiDialogNotification logger = S4APLogger.get_log() logger.enable() @@ -17,11 +18,13 @@ def reset_all_skills(self): sim_info.remove_statistic(skill) def show_reset_notif(self): - notif = CommonBasicNotification( - 'Progress Reset Completed', - "Your Sim's skills have been successfully reset. Please switch to a different sim or leave the lot and revisit to ensure the changes are visible in the UI." + title = LocalizationHelperTuning.get_raw_text('Progress Reset Completed') + description = LocalizationHelperTuning.get_raw_text("Your Sim's skills have been successfully reset. Please switch to a different sim or leave the lot and revisit to ensure the changes are visible in the UI.") + dialog = UiDialogNotification.TunableFactory().default( + title=title, + text=description ) - notif.show() + dialog.show_dialog() def remove_all_s4ap_traits(self): # Get all traits from the base class CommonTraitId From a8f3ee787a907a1a10a2f7fa21aed077841a3111 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 12:35:44 -0600 Subject: [PATCH 041/134] replace notification function from s4cl with our own helper function --- Scripts/s4ap/utils/s4ap_generic_utils.py | 24 +++++++++++++++++++----- Scripts/s4ap/utils/s4ap_phone_utils.py | 10 ++++------ Scripts/s4ap/utils/s4ap_reset_utils.py | 10 ++++------ 3 files changed, 27 insertions(+), 17 deletions(-) diff --git a/Scripts/s4ap/utils/s4ap_generic_utils.py b/Scripts/s4ap/utils/s4ap_generic_utils.py index 1c2f63c..a9e02a3 100644 --- a/Scripts/s4ap/utils/s4ap_generic_utils.py +++ b/Scripts/s4ap/utils/s4ap_generic_utils.py @@ -1,11 +1,14 @@ import services +from lib.typing import Union from s4ap.modinfo import ModInfo from services.persistence_service import SaveGameData from sims4.resources import Types from sims4communitylib.events.zone_spin.common_zone_spin_event_dispatcher import CommonZoneSpinEventDispatcher from sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler -from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification from s4ap.utils.s4ap_save_utils import S4APSaveUtils +from sims4.localization import LocalizationHelperTuning +from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification +from ui.ui_dialog_notification import UiDialogNotification class S4APUtils: @@ -22,10 +25,10 @@ def trigger_autosave(*_) -> bool: check_cooldown=False) return True except Exception as ex: - CommonBasicNotification( + S4APUtils.show_basic_notification( 'A problem occured while saving S4AP Data', 0 - ).show() + ) CommonExceptionHandler.log_exception(ModInfo.get_identity(), 'An exception occurred while autosaving.', exception=ex) return False @@ -37,6 +40,17 @@ def load_instance(self, instance_type: Types, instance_id: int): return None return instance_manager.get(instance_id) - def load_icon_by_id(icon_id: int): + def load_icon_by_id(self, icon_id: int): manager = services.get_instance_manager(Types.PNG) - return manager.get(icon_id) # Returns vanilla ResourceKey / instance \ No newline at end of file + return manager.get(icon_id) # Returns vanilla ResourceKey / instance + + def show_basic_notification(self, title_text: Union[int, str], description_text: Union[int, str]): + """Show a simple vanilla notification to the player.""" + title = LocalizationHelperTuning.get_raw_text(title_text) + description = LocalizationHelperTuning.get_raw_text(description_text) + + dialog = UiDialogNotification.TunableFactory().default( + title=title, + text=description + ) + dialog.show_dialog() \ No newline at end of file diff --git a/Scripts/s4ap/utils/s4ap_phone_utils.py b/Scripts/s4ap/utils/s4ap_phone_utils.py index 5d2a2de..9179fde 100644 --- a/Scripts/s4ap/utils/s4ap_phone_utils.py +++ b/Scripts/s4ap/utils/s4ap_phone_utils.py @@ -7,6 +7,7 @@ from s4ap.modinfo import ModInfo from s4ap.persistance.ap_session_data_store import S4APSessionStoreUtils from s4ap.utils.s4ap_career_utils import S4APCareerUtils +from s4ap.utils.s4ap_generic_utils import S4APUtils from s4ap.utils.s4ap_household_utils import S4APHouseholdUtils from s4ap.utils.s4ap_skill_utils import S4APSkillUtils from server_commands.argument_helpers import TunableInstanceParam @@ -148,13 +149,10 @@ def _resync_locations(event_data: S4CLSimTraitAddedEvent): locations.append(milestone_display_name) print_json(locations, 'locations_cached.json') print_json(True, 'sync.json') - title = LocalizationHelperTuning.get_raw_text('Locations Resynced') - description = LocalizationHelperTuning.get_raw_text('') - dialog = UiDialogNotification.TunableFactory().default( - title=title, - text=description + S4APUtils.show_basic_notification( + 'Locations Resynced', + '' ) - dialog.show_dialog() @CommonEventRegistry.handle_events(ModInfo.get_identity()) def _show_aspiration_and_career(event_data: S4CLSimTraitAddedEvent): diff --git a/Scripts/s4ap/utils/s4ap_reset_utils.py b/Scripts/s4ap/utils/s4ap_reset_utils.py index 6af49f6..a3057c4 100644 --- a/Scripts/s4ap/utils/s4ap_reset_utils.py +++ b/Scripts/s4ap/utils/s4ap_reset_utils.py @@ -1,5 +1,6 @@ from s4ap.enums.S4APLocalization import S4APTraitId from s4ap.logging.s4ap_logger import S4APLogger +from s4ap.utils.s4ap_generic_utils import S4APUtils from s4ap.utils.s4ap_household_utils import S4APHouseholdUtils from s4ap.utils.s4ap_skill_utils import S4APSkillUtils from server_commands.argument_helpers import TunableInstanceParam @@ -18,13 +19,10 @@ def reset_all_skills(self): sim_info.remove_statistic(skill) def show_reset_notif(self): - title = LocalizationHelperTuning.get_raw_text('Progress Reset Completed') - description = LocalizationHelperTuning.get_raw_text("Your Sim's skills have been successfully reset. Please switch to a different sim or leave the lot and revisit to ensure the changes are visible in the UI.") - dialog = UiDialogNotification.TunableFactory().default( - title=title, - text=description + S4APUtils.show_basic_notification( + 'Progress Reset Completed', + "Your Sim's skills have been successfully reset. Please switch to a different sim or leave the lot and revisit to ensure the changes are visible in the UI." ) - dialog.show_dialog() def remove_all_s4ap_traits(self): # Get all traits from the base class CommonTraitId From d6aa742b2fa311eb421da89679eeec5cff679f35 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 12:39:05 -0600 Subject: [PATCH 042/134] static methods --- Scripts/s4ap/utils/s4ap_generic_utils.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Scripts/s4ap/utils/s4ap_generic_utils.py b/Scripts/s4ap/utils/s4ap_generic_utils.py index a9e02a3..c6bd3db 100644 --- a/Scripts/s4ap/utils/s4ap_generic_utils.py +++ b/Scripts/s4ap/utils/s4ap_generic_utils.py @@ -7,7 +7,6 @@ from sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler from s4ap.utils.s4ap_save_utils import S4APSaveUtils from sims4.localization import LocalizationHelperTuning -from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification from ui.ui_dialog_notification import UiDialogNotification class S4APUtils: @@ -33,6 +32,7 @@ def trigger_autosave(*_) -> bool: exception=ex) return False + @staticmethod def load_instance(self, instance_type: Types, instance_id: int): """Load a resource instance (Trait, Buff, Mood, etc.) directly from the game.""" instance_manager = services.get_instance_manager(instance_type) @@ -40,11 +40,13 @@ def load_instance(self, instance_type: Types, instance_id: int): return None return instance_manager.get(instance_id) - def load_icon_by_id(self, icon_id: int): + @staticmethod + def load_icon_by_id(icon_id: int): manager = services.get_instance_manager(Types.PNG) return manager.get(icon_id) # Returns vanilla ResourceKey / instance - def show_basic_notification(self, title_text: Union[int, str], description_text: Union[int, str]): + @staticmethod + def show_basic_notification(title_text: Union[int, str], description_text: Union[int, str]): """Show a simple vanilla notification to the player.""" title = LocalizationHelperTuning.get_raw_text(title_text) description = LocalizationHelperTuning.get_raw_text(description_text) From e4805e0dff06dccb6583713619d4043fddc0ed9c Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 12:47:18 -0600 Subject: [PATCH 043/134] start removing more s4cl notification functions --- Scripts/s4ap/events/checks/send_check_event.py | 8 +++----- Scripts/s4ap/events/items/receive_item_event.py | 11 +++++------ Scripts/s4ap/logging/s4ap_logger.py | 4 ++-- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/Scripts/s4ap/events/checks/send_check_event.py b/Scripts/s4ap/events/checks/send_check_event.py index 4cc5ac9..3ec4fb6 100644 --- a/Scripts/s4ap/events/checks/send_check_event.py +++ b/Scripts/s4ap/events/checks/send_check_event.py @@ -4,7 +4,6 @@ from s4ap.modinfo import ModInfo from s4ap.utils.s4ap_generic_utils import S4APUtils from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification logger = S4APLogger.get_log() logger.enable() @@ -36,9 +35,8 @@ def _handle_send_check_event(event_data: SendLocationEvent): if event_data.location_name not in json_list["Locations"]: json_list["Locations"].append(event_data.location_name) print_json(json_list, 'locations_cached.json') - notif = CommonBasicNotification( - title_identifier='Saving on check', - description_identifier=event_data.location_name + S4APUtils.show_basic_notification( + 'Saving on check', + event_data.location_name ) - notif.show() S4APUtils.trigger_autosave() diff --git a/Scripts/s4ap/events/items/receive_item_event.py b/Scripts/s4ap/events/items/receive_item_event.py index 1a519c2..6fc51f4 100644 --- a/Scripts/s4ap/events/items/receive_item_event.py +++ b/Scripts/s4ap/events/items/receive_item_event.py @@ -16,7 +16,6 @@ from sims4.resources import Types from sims4communitylib.events.event_handling.common_event import CommonEvent from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification from lib.collections import Counter log = S4APLogger.get_log() log.enable() @@ -179,9 +178,9 @@ def handle_items(self, items): skill = skill.lower().replace('mixology', 'bartending') lock_skills(count, skill, False) - def show_received_notification(self, items, players, locations): - notif = CommonBasicNotification( - title_identifier='Received Items', - description_identifier='\n'.join( + @staticmethod + def show_received_notification(items, players, locations): + S4APUtils.show_basic_notification( + 'Received Items', + '\n'.join( [f'{item} from {player} ({location})' for item, player, location in zip(items, players, locations)])) - notif.show() diff --git a/Scripts/s4ap/logging/s4ap_logger.py b/Scripts/s4ap/logging/s4ap_logger.py index 6bb441b..cdad625 100644 --- a/Scripts/s4ap/logging/s4ap_logger.py +++ b/Scripts/s4ap/logging/s4ap_logger.py @@ -1,5 +1,6 @@ from s4ap.enums.S4APLocalization import S4APStringId from s4ap.modinfo import ModInfo +from s4ap.utils.s4ap_generic_utils import S4APUtils from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry from sims4communitylib.events.zone_spin.events.zone_late_load import S4CLZoneLateLoadEvent from sims4communitylib.logging.has_class_log import HasClassLog @@ -20,11 +21,10 @@ def get_log_identifier(cls) -> str: @staticmethod def show_loaded_notification() -> None: """ Show that the mod has loaded. """ - notification = CommonBasicNotification( + S4APUtils.show_basic_notification( CommonLocalizationUtils.create_localized_string(S4APStringId.S4AP_LOADED), 'Loaded Sims 4 Archipelago Mod (' + ModInfo.get_identity().version + ')' ) - notification.show() @staticmethod @CommonEventRegistry.handle_events('s4ap_loaded') From 527a463d1b445df5bfd19b392487c0689765089b Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 14:02:15 -0600 Subject: [PATCH 044/134] remove unused import --- Scripts/s4ap/logging/s4ap_logger.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Scripts/s4ap/logging/s4ap_logger.py b/Scripts/s4ap/logging/s4ap_logger.py index cdad625..0ac6ade 100644 --- a/Scripts/s4ap/logging/s4ap_logger.py +++ b/Scripts/s4ap/logging/s4ap_logger.py @@ -5,7 +5,6 @@ from sims4communitylib.events.zone_spin.events.zone_late_load import S4CLZoneLateLoadEvent from sims4communitylib.logging.has_class_log import HasClassLog from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils From 88a852a1ab034d7a2273bfb2068338c38af4a030 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 14:02:38 -0600 Subject: [PATCH 045/134] start trying to replace the okdialog... from s4cl with some vanilla/hybrid code --- .../s4ap/persistance/ap_session_data_store.py | 47 ++++++++++++++----- Scripts/s4ap/utils/s4ap_localization_utils.py | 32 ++++++++++++- 2 files changed, 67 insertions(+), 12 deletions(-) diff --git a/Scripts/s4ap/persistance/ap_session_data_store.py b/Scripts/s4ap/persistance/ap_session_data_store.py index 5364f1b..a32462a 100644 --- a/Scripts/s4ap/persistance/ap_session_data_store.py +++ b/Scripts/s4ap/persistance/ap_session_data_store.py @@ -5,6 +5,7 @@ from s4ap.persistance.ap_data_store import S4APGenericDataStore, S4APSettings from s4ap.persistance.ap_data_utils import S4APDataManagerUtils from s4ap.utils.s4ap_generic_utils import S4APUtils +from s4ap.utils.s4ap_localization_utils import S4APLocalizationUtils from s4ap.utils.s4ap_reset_utils import ResetSimData from sims4communitylib.dialogs.ok_cancel_dialog import CommonOkCancelDialog from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry @@ -52,13 +53,28 @@ def _ok_chosen(_: UiDialogOkCancel): return False # if okay is chosen then save seed values and resync items # Prompt the user to either overwrite the previous session_data, or stop parsing the data packet and wait for the connection_status.json to update - dialog = CommonOkCancelDialog( - CommonLocalizationUtils.create_localized_string('Warning!', + dialog = UiDialogOkCancel.TunableFactory().default( + title=CommonLocalizationUtils.create_localized_string('Warning!', text_color=CommonLocalizedStringColor.RED), - description_identifier="There's a mismatch with your AP session data. If you press 'Overwrite,' all previous items will be resynced, and your Sims' skill levels will reset. If you'd rather keep your current progress, select 'Cancel' and switch to a different save file so you can come back to this session later.", - ok_text_identifier='Overwrite' + description=S4APLocalizationUtils.create_from_string("There's a mismatch with your AP session data. If you press 'Overwrite,' all previous items will be resynced, and your Sims' skill levels will reset. If you'd rather keep your current progress, select 'Cancel' and switch to a different save file so you can come back to this session later."), + ok_text=S4APLocalizationUtils.create_from_string('Overwrite'), + cancel_text=S4APLocalizationUtils.create_from_string('Cancel'), ) - dialog.show(on_ok_selected=_ok_chosen, on_cancel_selected=_cancel_chosen) + # dialog = CommonOkCancelDialog( + # CommonLocalizationUtils.create_localized_string('Warning!', + # text_color=CommonLocalizedStringColor.RED), + # description_identifier="There's a mismatch with your AP session data. If you press 'Overwrite,' all previous items will be resynced, and your Sims' skill levels will reset. If you'd rather keep your current progress, select 'Cancel' and switch to a different save file so you can come back to this session later.", + # ok_text_identifier='Overwrite' + # ) + # Wrap the callbacks manually + def on_option_selected(dialog_instance: UiDialogOkCancel): + if dialog_instance.accepted: + _ok_chosen(dialog_instance) + else: + _cancel_chosen(dialog_instance) + + dialog.add_listener(on_option_selected) + dialog.show_dialog() return True else: # Settings exist and match logger.debug("AP session data matched") @@ -83,13 +99,22 @@ def _cancel_chosen(_: UiDialogOkCancel): return True # Prompt the user to either overwrite the previous session_data, or stop parsing the data packet and wait for the connection_status.json to update - dialog = CommonOkCancelDialog( - CommonLocalizationUtils.create_localized_string('Warning!', - text_color=CommonLocalizedStringColor.RED), - description_identifier="Pressing 'Connect' will reset your Sims' skill levels and will sync the game to the client. If you don't want to use this save, click 'Cancel' and switch to a different one.", - ok_text_identifier='Connect' + dialog = UiDialogOkCancel.TunableFactory().default( + title=CommonLocalizationUtils.create_localized_string('Warning!', + text_color=CommonLocalizedStringColor.RED), + description=S4APLocalizationUtils.create_from_string("Pressing 'Connect' will reset your Sims' skill levels and will sync the game to the client. If you don't want to use this save, click 'Cancel' and switch to a different one."), + ok_text=S4APLocalizationUtils.create_from_string('Connect'), + cancel_text=S4APLocalizationUtils.create_from_string('Cancel'), ) - dialog.show(on_ok_selected=_ok_chosen, on_cancel_selected=_cancel_chosen) + + def on_option_selected(dialog_instance: UiDialogOkCancel): + if dialog_instance.accepted: + _ok_chosen(dialog_instance) + else: + _cancel_chosen(dialog_instance) + + dialog.add_listener(on_option_selected) + dialog.show_dialog() return True def check_index_value(self, index: str) -> bool: diff --git a/Scripts/s4ap/utils/s4ap_localization_utils.py b/Scripts/s4ap/utils/s4ap_localization_utils.py index efa276b..1d035bb 100644 --- a/Scripts/s4ap/utils/s4ap_localization_utils.py +++ b/Scripts/s4ap/utils/s4ap_localization_utils.py @@ -1,4 +1,6 @@ from protocolbuffers.Localization_pb2 import LocalizedString + +from lib.typing import Any from sims4.localization import LocalizationHelperTuning, _create_localized_string, create_tokens class S4APLocalizationUtils: @@ -28,4 +30,32 @@ def _localize_tokens(tokens_unlocalized): tokens = list() for token in tokens_unlocalized: tokens.append(S4APLocalizationUtils.localize(token)) - return tokens \ No newline at end of file + return tokens + + @staticmethod + def create_from_string(string_text: str) -> LocalizedString: + """create_from_string(string_text) + + Create a LocalizedString from a string. + + :param string_text: The string to localize. The resulting LocalizedString will be '{0.String}' + :type string_text: str + :return: A LocalizedString created from the specified string. + :rtype: LocalizedString + """ + return LocalizationHelperTuning.get_raw_text(string_text) + + @staticmethod + def create_from_int(identifier: int, *tokens: Any) -> LocalizedString: + """create_from_int(identifier, *tokens) + + Locate a LocalizedString by an identifier and format tokens into it. + + :param identifier: A decimal number that identifies an existing LocalizedString. + :type identifier: int + :param tokens: A collection of objects to format into the LocalizedString. (Example types: LocalizedString, str, int, etc.) + :type tokens: Iterator[Any] + :return: A LocalizedString with the specified tokens formatted into it. + :rtype: LocalizedString + """ + return _create_localized_string(identifier, *tokens) \ No newline at end of file From 4ac4c1bff3778bd4d2c9e0a0493d11db28cfa94c Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 14:06:00 -0600 Subject: [PATCH 046/134] use our own borrowed localize function for this (maybe it might work) --- Scripts/s4ap/logging/s4ap_logger.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Scripts/s4ap/logging/s4ap_logger.py b/Scripts/s4ap/logging/s4ap_logger.py index 0ac6ade..a84a8b0 100644 --- a/Scripts/s4ap/logging/s4ap_logger.py +++ b/Scripts/s4ap/logging/s4ap_logger.py @@ -1,6 +1,7 @@ from s4ap.enums.S4APLocalization import S4APStringId from s4ap.modinfo import ModInfo from s4ap.utils.s4ap_generic_utils import S4APUtils +from s4ap.utils.s4ap_localization_utils import S4APLocalizationUtils from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry from sims4communitylib.events.zone_spin.events.zone_late_load import S4CLZoneLateLoadEvent from sims4communitylib.logging.has_class_log import HasClassLog @@ -21,7 +22,7 @@ def get_log_identifier(cls) -> str: def show_loaded_notification() -> None: """ Show that the mod has loaded. """ S4APUtils.show_basic_notification( - CommonLocalizationUtils.create_localized_string(S4APStringId.S4AP_LOADED), + S4APLocalizationUtils.localize(S4APStringId.S4AP_LOADED), 'Loaded Sims 4 Archipelago Mod (' + ModInfo.get_identity().version + ')' ) From 89b636a6f15601c33ef8f3067aa22e604374e5b2 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 14:08:27 -0600 Subject: [PATCH 047/134] remove commented code --- Scripts/s4ap/persistance/ap_session_data_store.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Scripts/s4ap/persistance/ap_session_data_store.py b/Scripts/s4ap/persistance/ap_session_data_store.py index a32462a..067bc46 100644 --- a/Scripts/s4ap/persistance/ap_session_data_store.py +++ b/Scripts/s4ap/persistance/ap_session_data_store.py @@ -60,12 +60,6 @@ def _ok_chosen(_: UiDialogOkCancel): ok_text=S4APLocalizationUtils.create_from_string('Overwrite'), cancel_text=S4APLocalizationUtils.create_from_string('Cancel'), ) - # dialog = CommonOkCancelDialog( - # CommonLocalizationUtils.create_localized_string('Warning!', - # text_color=CommonLocalizedStringColor.RED), - # description_identifier="There's a mismatch with your AP session data. If you press 'Overwrite,' all previous items will be resynced, and your Sims' skill levels will reset. If you'd rather keep your current progress, select 'Cancel' and switch to a different save file so you can come back to this session later.", - # ok_text_identifier='Overwrite' - # ) # Wrap the callbacks manually def on_option_selected(dialog_instance: UiDialogOkCancel): if dialog_instance.accepted: From fb5a55df976bda3f1b2835e8fcd0e42e0ed889eb Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 14:15:11 -0600 Subject: [PATCH 048/134] replace the last localization calls and string colour things to actually fully replace the strings that need coloured text --- Scripts/s4ap/persistance/ap_session_data_store.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Scripts/s4ap/persistance/ap_session_data_store.py b/Scripts/s4ap/persistance/ap_session_data_store.py index 067bc46..844d4af 100644 --- a/Scripts/s4ap/persistance/ap_session_data_store.py +++ b/Scripts/s4ap/persistance/ap_session_data_store.py @@ -9,8 +9,6 @@ from s4ap.utils.s4ap_reset_utils import ResetSimData from sims4communitylib.dialogs.ok_cancel_dialog import CommonOkCancelDialog from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor from ui.ui_dialog import UiDialogOkCancel logger = S4APLogger.get_log() @@ -54,8 +52,7 @@ def _ok_chosen(_: UiDialogOkCancel): # Prompt the user to either overwrite the previous session_data, or stop parsing the data packet and wait for the connection_status.json to update dialog = UiDialogOkCancel.TunableFactory().default( - title=CommonLocalizationUtils.create_localized_string('Warning!', - text_color=CommonLocalizedStringColor.RED), + title = S4APLocalizationUtils.create_from_string("Warning!"), description=S4APLocalizationUtils.create_from_string("There's a mismatch with your AP session data. If you press 'Overwrite,' all previous items will be resynced, and your Sims' skill levels will reset. If you'd rather keep your current progress, select 'Cancel' and switch to a different save file so you can come back to this session later."), ok_text=S4APLocalizationUtils.create_from_string('Overwrite'), cancel_text=S4APLocalizationUtils.create_from_string('Cancel'), @@ -94,8 +91,7 @@ def _cancel_chosen(_: UiDialogOkCancel): # Prompt the user to either overwrite the previous session_data, or stop parsing the data packet and wait for the connection_status.json to update dialog = UiDialogOkCancel.TunableFactory().default( - title=CommonLocalizationUtils.create_localized_string('Warning!', - text_color=CommonLocalizedStringColor.RED), + title = S4APLocalizationUtils.create_from_string("Warning!"), description=S4APLocalizationUtils.create_from_string("Pressing 'Connect' will reset your Sims' skill levels and will sync the game to the client. If you don't want to use this save, click 'Cancel' and switch to a different one."), ok_text=S4APLocalizationUtils.create_from_string('Connect'), cancel_text=S4APLocalizationUtils.create_from_string('Cancel'), From dee2c933a0af92d248273efc4a4785023149fd48 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 14:21:43 -0600 Subject: [PATCH 049/134] try making a command manually --- Scripts/s4ap/s4ap_commands.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Scripts/s4ap/s4ap_commands.py b/Scripts/s4ap/s4ap_commands.py index 0ccd28c..d585804 100644 --- a/Scripts/s4ap/s4ap_commands.py +++ b/Scripts/s4ap/s4ap_commands.py @@ -1,5 +1,6 @@ from s4ap.logging.s4ap_logger import S4APLogger from s4ap.modinfo import ModInfo +from sims4.commands import Command, CommandType, Output from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput @@ -7,6 +8,11 @@ log.enable() +@Command('s4ap.version', command_type=CommandType.Live) +def show_mod_version(_connection=None): + output = Output(_connection) + output(f"The Sims 4 Archipelago, Current Mod Version: {ModInfo.get_identity().version}") + @CommonConsoleCommand(ModInfo.get_identity(), 's4ap.version', 'Prints the mod version to the console') def _show_mod_version(output: CommonConsoleCommandOutput): output(f"The Sims 4 Archipelago, Current Mod Version: {ModInfo.get_identity().version}") From a62024e1d4b1458a1c12dff128bd84c033a73ad8 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 14:31:02 -0600 Subject: [PATCH 050/134] comment out the old command approach (not deleting it *yet*) --- Scripts/s4ap/s4ap_commands.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Scripts/s4ap/s4ap_commands.py b/Scripts/s4ap/s4ap_commands.py index d585804..4944ab4 100644 --- a/Scripts/s4ap/s4ap_commands.py +++ b/Scripts/s4ap/s4ap_commands.py @@ -1,8 +1,8 @@ from s4ap.logging.s4ap_logger import S4APLogger from s4ap.modinfo import ModInfo from sims4.commands import Command, CommandType, Output -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +# from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +# from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput log = S4APLogger.get_log() log.enable() @@ -13,6 +13,6 @@ def show_mod_version(_connection=None): output = Output(_connection) output(f"The Sims 4 Archipelago, Current Mod Version: {ModInfo.get_identity().version}") -@CommonConsoleCommand(ModInfo.get_identity(), 's4ap.version', 'Prints the mod version to the console') -def _show_mod_version(output: CommonConsoleCommandOutput): - output(f"The Sims 4 Archipelago, Current Mod Version: {ModInfo.get_identity().version}") +# @CommonConsoleCommand(ModInfo.get_identity(), 's4ap.version', 'Prints the mod version to the console') +# def _show_mod_version(output: CommonConsoleCommandOutput): +# output(f"The Sims 4 Archipelago, Current Mod Version: {ModInfo.get_identity().version}") From e55b7935242750c57d9bccb0f0a3cfb85ad8f31d Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 14:32:47 -0600 Subject: [PATCH 051/134] change version --- Scripts/s4ap/modinfo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/s4ap/modinfo.py b/Scripts/s4ap/modinfo.py index 725e34d..09ebe7c 100644 --- a/Scripts/s4ap/modinfo.py +++ b/Scripts/s4ap/modinfo.py @@ -14,7 +14,7 @@ def _name(self) -> str: @property def _version(self) -> str: # Mod version - return '0.3.0-rc1' + return '0.3.0-rc2' @property def _author(self) -> str: From a17b1dae32c2c70dbae40790d8eaf523b1df2fe4 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 14:44:37 -0600 Subject: [PATCH 052/134] hmmm how about bundling the s4cl code we need into the mod itself? --- Release/S4CLSampleMod/s4cl_sample_mod.package | Bin 0 -> 3228 bytes Scripts/s4ap/events/Utils/allow_read_items.py | 2 +- .../s4ap/events/Utils/send_location_event.py | 2 +- .../events/aspiration_event_dispatcher.py | 6 +- .../s4ap/events/career_event_dispatcher.py | 6 +- .../s4ap/events/checks/send_check_event.py | 2 +- .../s4ap/events/items/receive_item_event.py | 4 +- Scripts/s4ap/events/skill_event_dispatcher.py | 6 +- Scripts/s4ap/jsonio/auto_parse_json.py | 8 +- Scripts/s4ap/jsonio/s4ap_json.py | 4 +- Scripts/s4ap/logging/s4ap_logger.py | 10 +- Scripts/s4ap/modinfo.py | 2 +- Scripts/s4ap/persistance/ap_data_manager.py | 8 +- Scripts/s4ap/persistance/ap_data_store.py | 2 +- Scripts/s4ap/persistance/ap_data_utils.py | 6 +- .../s4ap/persistance/ap_session_data_store.py | 4 +- Scripts/s4ap/sims4communitylib/__init__.py | 7 + .../sims4communitylib/classes/__init__.py | 7 + .../classes/appearance_modifiers/__init__.py | 7 + ...on_attach_cas_parts_appearance_modifier.py | 359 + .../classes/buffs/__init__.py | 7 + .../classes/buffs/common_buff.py | 99 + .../classes/calculations/__init__.py | 7 + .../calculations/common_available_for_sim.py | 174 + .../classes/commodities/__init__.py | 7 + .../classes/commodities/common_commodity.py | 28 + .../classes/common_resource_key.py | 133 + .../classes/effects/__init__.py | 7 + .../classes/effects/common_visual_effect.py | 217 + .../classes/enums/__init__.py | 7 + .../common_versioned_enum_value_collection.py | 81 + ...rsioned_sim_demographic_type_collection.py | 39 + .../classes/filters/__init__.py | 7 + ...common_match_all_non_sims_object_filter.py | 19 + .../common_match_all_sims_object_filter.py | 16 + .../filters/common_match_object_filter.py | 36 + .../classes/interactions/__init__.py | 7 + .../_common_interaction_custom_mixin.py | 81 + .../_common_interaction_hooks_mixin.py | 325 + .../common_immediate_super_interaction.py | 427 + .../interactions/common_interaction.py | 462 + .../common_interaction_override_name.py | 89 + .../interactions/common_mixer_interaction.py | 460 + .../interactions/common_object_interaction.py | 77 + .../common_social_mixer_interaction.py | 466 + .../common_social_super_interaction.py | 518 + .../interactions/common_super_interaction.py | 894 + .../common_terrain_interaction.py | 108 + .../classes/math/__init__.py | 7 + .../classes/math/common_comparison.py | 55 + .../classes/math/common_float_range.py | 69 + .../classes/math/common_integer_range.py | 69 + .../classes/math/common_location.py | 112 + .../classes/math/common_polygon.py | 101 + .../classes/math/common_quaternion.py | 415 + .../classes/math/common_routing_location.py | 110 + .../classes/math/common_surface_identifier.py | 94 + .../classes/math/common_transform.py | 102 + .../classes/math/common_vector3.py | 298 + .../classes/math/common_weighted_value.py | 56 + .../math/common_weighted_value_tally.py | 38 + .../classes/mixins/__init__.py | 7 + .../mixins/common_affordance_lists_mixin.py | 21 + .../mixins/common_interactions_mixin.py | 40 + .../s4ap/sims4communitylib/classes/options.py | 117 + .../classes/resolvers/__init__.py | 7 + .../resolvers/common_double_sim_resolver.py | 99 + .../classes/runnables/__init__.py | 7 + .../classes/runnables/common_runnable.py | 433 + .../runnables/common_runnable_with_sims.py | 187 + .../classes/runnables/contexts/__init__.py | 7 + .../contexts/common_runnable_context.py | 250 + .../common_runnable_context_with_sims.py | 279 + .../common_runnable_object_context.py | 133 + .../contexts/common_runnable_sim_context.py | 140 + .../classes/serialization/__init__.py | 7 + .../serialization/common_serializable.py | 34 + .../common_serializable_location.py | 98 + .../classes/test_based_scores/__init__.py | 7 + .../common_sim_to_sim_test_based_score.py | 73 + .../common_single_sim_test_based_score.py | 69 + .../common_test_based_score.py | 60 + .../classes/testing/__init__.py | 7 + .../classes/testing/common_enqueue_result.py | 201 + .../testing/common_execution_result.py | 197 + .../classes/testing/common_test_result.py | 149 + .../classes/time/__init__.py | 7 + .../classes/time/common_alarm_handle.py | 81 + .../classes/time/common_stop_watch.py | 82 + .../conditionals/__init__.py | 7 + .../conditionals/common_conditional_action.py | 66 + .../s4ap/sims4communitylib/debug/__init__.py | 7 + .../debug/dialogs/__init__.py | 7 + .../common_change_object_state_dialog.py | 114 + .../debug/interactions/__init__.py | 7 + .../interactions/_register_interactions.py | 163 + .../interactions/change_object_states.py | 70 + .../debug/interactions/induce_labor.py | 62 + .../debug/interactions/log_all_game_tags.py | 69 + .../interactions/log_all_interactions.py | 134 + .../debug/interactions/object_break.py | 51 + .../debug/interactions/object_fix.py | 51 + .../debug/interactions/object_make_clean.py | 51 + .../debug/interactions/object_make_dirty.py | 51 + .../debug/interactions/show_active_buffs.py | 74 + .../show_running_and_queued_interactions.py | 86 + .../interactions/show_running_situations.py | 90 + .../debug/interactions/show_traits.py | 75 + .../debug/traits/__init__.py | 7 + .../debug/traits/_auto_apply_traits.py | 442 + .../sims4communitylib/dialogs/__init__.py | 7 + ...on_ui_dialog_multi_text_input_ok_cancel.py | 66 + .../_common_ui_dialog_text_input_ok_cancel.py | 50 + .../dialogs/choose_item_dialog.py | 199 + .../dialogs/choose_object_dialog.py | 519 + .../dialogs/choose_objects_dialog.py | 434 + .../dialogs/common_choice_outcome.py | 32 + .../dialogs/common_choose_dialog.py | 102 + .../dialogs/common_choose_outfit_dialog.py | 372 + .../dialogs/common_choose_response_dialog.py | 513 + .../dialogs/common_choose_sim_dialog.py | 318 + .../dialogs/common_choose_sims_dialog.py | 309 + .../dialogs/common_dialog.py | 92 + .../common_dialog_navigation_button_tag.py | 13 + .../dialogs/common_input_float_dialog.py | 216 + .../dialogs/common_input_integer_dialog.py | 216 + .../dialogs/common_input_multi_text_dialog.py | 209 + .../dialogs/common_input_text_dialog.py | 196 + .../dialogs/common_input_text_field.py | 94 + .../common_multi_pane_choose_dialog.py | 431 + .../dialogs/common_ok_dialog.py | 174 + .../dialogs/common_purchase_objects_dialog.py | 393 + .../common_targeted_question_dialog.py | 223 + .../dialogs/common_ui_dialog_response.py | 38 + .../dialogs/common_ui_response_dialog.py | 157 + .../dialogs/custom_dialogs/__init__.py | 7 + .../custom_dialogs/picker_dialogs/__init__.py | 7 + .../picker_dialogs/common_ui_multi_picker.py | 48 + .../common_ui_object_category_picker.py | 51 + .../dialogs/ok_cancel_dialog.py | 199 + .../dialogs/option_dialogs/__init__.py | 7 + .../common_choose_button_option_dialog.py | 349 + .../common_choose_object_option_dialog.py | 357 + .../common_choose_objects_option_dialog.py | 414 + .../common_choose_option_dialog.py | 129 + .../common_choose_options_dialog.py | 160 + .../common_choose_response_option_dialog.py | 140 + .../common_choose_sim_option_dialog.py | 275 + .../common_choose_sims_option_dialog.py | 306 + .../common_multi_pane_choose_option_dialog.py | 468 + .../option_dialogs/common_option_dialog.py | 95 + .../option_dialogs/options/__init__.py | 7 + .../options/common_dialog_option.py | 146 + .../options/common_dialog_option_context.py | 144 + .../options/objects/__init__.py | 7 + .../objects/common_dialog_action_option.py | 43 + .../objects/common_dialog_branch_option.py | 50 + .../common_dialog_input_integer_option.py | 107 + .../common_dialog_input_multi_text_option.py | 98 + .../objects/common_dialog_input_option.py | 101 + .../common_dialog_input_text_option.py | 97 + .../objects/common_dialog_object_option.py | 102 + .../objects/common_dialog_option_category.py | 32 + .../objects/common_dialog_select_option.py | 50 + .../objects/common_dialog_toggle_option.py | 78 + .../options/response/__init__.py | 7 + .../response/common_dialog_button_option.py | 77 + .../response/common_dialog_response_option.py | 94 + .../common_dialog_response_option_context.py | 67 + .../option_dialogs/options/sims/__init__.py | 7 + .../options/sims/common_dialog_sim_option.py | 71 + .../sims/common_dialog_sim_option_context.py | 31 + .../dialogs/premade_dialogs/__init__.py | 7 + ...mon_choose_sim_demographic_types_dialog.py | 251 + ...common_premade_choose_sim_option_dialog.py | 187 + ...ommon_premade_choose_sims_option_dialog.py | 186 + .../dialogs/utils/__init__.py | 7 + .../dialogs/utils/common_dialog_utils.py | 58 + .../s4ap/sims4communitylib/dtos/__init__.py | 7 + .../sims4communitylib/dtos/common_cas_part.py | 47 + .../dtos/common_object_containment_slot.py | 37 + .../sims4communitylib/dtos/common_outfit.py | 274 + .../s4ap/sims4communitylib/enums/__init__.py | 7 + .../enums/affordance_list_ids.py | 21 + .../enums/animation_state_machines_enum.py | 16 + .../sims4communitylib/enums/buffs_enum.py | 14677 ++++++++++++++++ .../sims4communitylib/enums/clubs_enum.py | 108 + .../sims4communitylib/enums/common_age.py | 184 + .../common_appearance_modifier_priority.py | 121 + .../enums/common_appearance_modifier_type.py | 18 + .../enums/common_body_frame.py | 78 + .../enums/common_body_slot.py | 728 + .../enums/common_bucks_types.py | 203 + .../enums/common_business_advertising_type.py | 141 + ...mmon_business_customer_star_rating_type.py | 148 + .../enums/common_business_employee_type.py | 122 + .../enums/common_business_quality_type.py | 111 + .../enums/common_career_ids.py | 145 + .../enums/common_character_restrictions.py | 16 + .../enums/common_civic_policy_status_type.py | 16 + .../enums/common_civic_policy_type.py | 14 + .../enums/common_cloud_type.py | 116 + .../enums/common_combined_species.py | 96 + .../enums/common_currency_modify_reasons.py | 54 + .../enums/common_death_types.py | 213 + .../sims4communitylib/enums/common_enum.py | 90 + .../enums/common_fund_types.py | 13 + .../enums/common_funds_sources.py | 63 + .../enums/common_game_tag_category.py | 431 + .../sims4communitylib/enums/common_gender.py | 148 + .../enums/common_gender_preference_type.py | 67 + .../enums/common_ground_cover_type.py | 78 + .../sims4communitylib/enums/common_key.py | 230 + .../enums/common_object_delivery_method.py | 109 + .../enums/common_object_filter_type.py | 15 + .../enums/common_object_preference_tag.py | 23 + .../enums/common_object_quality.py | 55 + .../enums/common_object_slot_name_ids.py | 13 + .../enums/common_object_state_ids.py | 14 + .../enums/common_object_state_value_ids.py | 33 + .../enums/common_occult_type.py | 175 + .../enums/common_posture_id.py | 186 + .../enums/common_precipitation_type.py | 78 + .../enums/common_pregnancy_origin.py | 21 + .../enums/common_puddle_liquid.py | 82 + .../enums/common_puddle_size.py | 61 + .../enums/common_region_id.py | 53 + .../enums/common_runnable_state.py | 17 + .../enums/common_runnable_state_type.py | 17 + .../sims4communitylib/enums/common_side.py | 108 + .../enums/common_sim_demographic_types.py | 172 + .../enums/common_sim_name_type.py | 236 + .../enums/common_skill_effectiveness.py | 107 + .../enums/common_slot_type.py | 116 + .../sims4communitylib/enums/common_species.py | 189 + .../enums/common_statistic_category.py | 75 + .../enums/common_street_civic_policy_ids.py | 37 + .../enums/common_temperature.py | 98 + .../enums/common_venue_civic_policy_ids.py | 16 + .../enums/common_voice_actor_type.py | 102 + .../enums/common_weather_effect_type.py | 124 + .../enums/common_weather_event_ids.py | 58 + .../enums/common_weather_type.py | 280 + .../enums/enumtypes/__init__.py | 7 + .../enums/enumtypes/common_int.py | 130 + .../enums/enumtypes/common_int_flags.py | 160 + .../enums/enumtypes/common_versioned_int.py | 55 + .../enumtypes/common_versioned_int_flags.py | 55 + .../common_versioned_values_mixin.py | 52 + .../enums/enumtypes/float_enum.py | 87 + .../enums/enumtypes/int_enum.py | 90 + .../enums/enumtypes/object_enum.py | 87 + .../enums/enumtypes/string_enum.py | 87 + .../enums/furniture_objects_enum.py | 16 + .../sims4communitylib/enums/icons_enum.py | 31 + .../enums/interactions_enum.py | 145 + .../enums/long_term_sentiments_enum.py | 38 + .../enums/lot_traits_enum.py | 67 + .../sims4communitylib/enums/moods_enum.py | 35 + .../sims4communitylib/enums/motives_enum.py | 53 + .../relationship_bit_collection_uids_enum.py | 38 + .../relationship_bit_collections_enum.py | 34 + .../enums/relationship_bits_enum.py | 514 + .../enums/relationship_tracks_enum.py | 23 + .../enums/relationship_types_enum.py | 21 + .../short_term_relationship_tracks_enum.py | 30 + .../enums/short_term_sentiments_enum.py | 107 + .../s4ap/sims4communitylib/enums/sim_type.py | 629 + .../enums/situation_jobs_enum.py | 1083 ++ .../enums/situations_enum.py | 1217 ++ .../sims4communitylib/enums/skills_enum.py | 154 + .../enums/statistics_enum.py | 1698 ++ .../sims4communitylib/enums/strings_enum.py | 269 + .../s4ap/sims4communitylib/enums/tags_enum.py | 4867 +++++ .../sims4communitylib/enums/traits_enum.py | 2715 +++ .../sims4communitylib/enums/types/__init__.py | 7 + .../enums/types/component_types.py | 94 + .../sims4communitylib/enums/venues_enum.py | 56 + .../sims4communitylib/enums/whims_enum.py | 242 + .../enums/world_types_enum.py | 84 + .../s4ap/sims4communitylib/events/__init__.py | 7 + .../events/build_buy/__init__.py | 7 + .../common_build_buy_event_dispatcher.py | 65 + .../events/build_buy/events/__init__.py | 7 + .../build_buy/events/build_buy_enter.py | 51 + .../events/build_buy/events/build_buy_exit.py | 51 + .../events/event_handling/__init__.py | 7 + .../events/event_handling/common_event.py | 25 + .../event_handling/common_event_handler.py | 100 + .../event_handling/common_event_registry.py | 78 + .../events/game_object/__init__.py | 7 + .../common_game_object_event_dispatcher.py | 131 + .../events/game_object/events/__init__.py | 7 + ...e_object_added_to_game_object_inventory.py | 83 + .../events/game_object_added_to_inventory.py | 51 + .../events/game_object_initialized.py | 51 + .../game_object/events/game_object_loaded.py | 51 + .../events/game_object_pre_deleted.py | 51 + .../events/game_object_pre_despawned.py | 51 + ..._pre_removed_from_game_object_inventory.py | 83 + .../game_object_pre_removed_from_inventory.py | 51 + .../game_object/events/game_object_spawned.py | 51 + .../events/interaction/__init__.py | 7 + .../common_interaction_event_dispatcher.py | 497 + .../events/interaction/events/__init__.py | 7 + .../events/interaction_cancelled.py | 102 + .../interaction/events/interaction_outcome.py | 94 + .../events/interaction_post_queued.py | 80 + .../interaction/events/interaction_pre_run.py | 91 + .../interaction/events/interaction_queued.py | 84 + .../interaction/events/interaction_run.py | 79 + .../interaction/events/interaction_started.py | 71 + .../events/mixer_interaction_cancelled.py | 90 + .../events/super_interaction_cancelled.py | 90 + .../events/interval/__init__.py | 7 + .../interval/common_interval_event_service.py | 241 + .../sims4communitylib/events/save/__init__.py | 7 + .../save/common_save_event_dispatcher.py | 66 + .../events/save/events/__init__.py | 7 + .../events/save/events/save_loaded.py | 37 + .../events/save/events/save_saved.py | 61 + .../sims4communitylib/events/sim/__init__.py | 7 + .../events/sim/common_sim_event_dispatcher.py | 385 + .../events/sim/events/__init__.py | 7 + .../game_object_added_to_sim_inventory.py | 83 + ...e_object_pre_removed_from_sim_inventory.py | 84 + .../sim/events/sim_added_occult_type.py | 77 + .../events/sim_after_set_current_outfit.py | 66 + .../events/sim/events/sim_buff_added.py | 74 + .../events/sim/events/sim_buff_removed.py | 74 + .../events/sim/events/sim_changed_age.py | 66 + .../events/sim/events/sim_changed_gender.py | 64 + .../sim_changed_gender_options_body_frame.py | 51 + .../sim_changed_gender_options_breasts.py | 51 + ...anged_gender_options_can_be_impregnated.py | 51 + ...m_changed_gender_options_can_impregnate.py | 51 + ...im_changed_gender_options_can_reproduce.py | 51 + ...nged_gender_options_clothing_preference.py | 51 + ...sim_changed_gender_options_toilet_usage.py | 51 + .../sim/events/sim_changed_occult_type.py | 79 + .../sim/events/sim_changing_occult_type.py | 79 + .../events/sim/events/sim_died.py | 68 + .../events/sim/events/sim_initialized.py | 51 + .../events/sim/events/sim_loaded.py | 51 + .../events/sim/events/sim_pre_despawned.py | 51 + .../sim/events/sim_relationship_bit_added.py | 86 + .../events/sim_relationship_bit_removed.py | 86 + .../sim/events/sim_removed_occult_type.py | 77 + .../events/sim/events/sim_revived.py | 56 + .../sim/events/sim_set_current_outfit.py | 66 + .../events/sim/events/sim_skill_leveled_up.py | 78 + .../events/sim/events/sim_spawned.py | 51 + .../events/sim/events/sim_trait_added.py | 87 + .../events/sim/events/sim_trait_removed.py | 87 + .../events/zone_spin/__init__.py | 7 + .../common_zone_spin_event_dispatcher.py | 114 + .../events/zone_spin/events/__init__.py | 7 + .../zone_spin/events/zone_early_load.py | 77 + .../events/zone_spin/events/zone_late_load.py | 101 + .../events/zone_manager_start_event.py | 51 + .../events/zone_spin/events/zone_post_load.py | 75 + .../events/zone_spin/events/zone_save.py | 93 + .../events/zone_spin/events/zone_teardown.py | 92 + .../events/zone_update/__init__.py | 7 + .../common_zone_update_event_dispatcher.py | 81 + .../events/zone_update/events/__init__.py | 7 + .../zone_update/events/zone_update_event.py | 77 + .../sims4communitylib/examples/__init__.py | 7 + .../common_example_apply_bare_feet_buff.py | 140 + .../sims4communitylib/exceptions/__init__.py | 7 + .../exceptions/common_exceptions_handler.py | 102 + .../exceptions/common_stacktrace_utils.py | 73 + .../exceptions/generic_error_handling.py | 34 + .../sims4communitylib/logging/__init__.py | 7 + .../logging/_has_s4cl_class_log.py | 28 + .../logging/_has_s4cl_log.py | 28 + .../logging/_logging_commands.py | 156 + .../logging/has_class_log.py | 132 + .../s4ap/sims4communitylib/logging/has_log.py | 93 + .../logging/vanilla_logging.py | 211 + .../sims4communitylib/mod_support/__init__.py | 7 + .../mod_support/common_mod_info.py | 85 + .../mod_support/has_class_mod_identity.py | 33 + .../mod_support/has_mod_identity.py | 26 + .../mod_support/mod_identity.py | 108 + Scripts/s4ap/sims4communitylib/modinfo.py | 35 + .../notifications/__init__.py | 7 + .../common_basic_notification.py | 177 + .../sims4communitylib/persistence/__init__.py | 7 + .../common_game_object_data_storage.py | 230 + ...mmon_persisted_game_object_data_storage.py | 156 + .../common_persisted_sim_data_storage.py | 157 + .../persistence/common_sim_data_storage.py | 234 + .../persistence/data_management/__init__.py | 7 + .../data_management/common_data_manager.py | 232 + .../common_data_manager_registry.py | 189 + .../persistence/data_stores/__init__.py | 7 + .../data_stores/common_data_store.py | 223 + .../common_game_object_data_store.py | 30 + .../data_stores/common_sim_data_store.py | 30 + .../persistence_services/__init__.py | 7 + .../common_file_persistence_service.py | 120 + .../common_folder_persistence_service.py | 152 + ...on_hidden_household_persistence_service.py | 118 + ...n_individual_folder_persistence_service.py | 114 + .../common_persistence_service.py | 85 + .../s4ap/sims4communitylib/s4cl_commands.py | 87 + .../sims4communitylib/s4cl_configuration.py | 130 + .../sims4communitylib/services/__init__.py | 7 + .../services/commands/__init__.py | 7 + .../commands/common_console_command.py | 664 + .../commands/common_console_command_output.py | 60 + .../common_console_command_parameters.py | 151 + .../services/common_service.py | 52 + .../services/interactions/__init__.py | 7 + .../interaction_registration_service.py | 337 + .../services/resources/__init__.py | 7 + ..._instance_manager_modification_registry.py | 75 + .../common_posture_constraint_service.py | 80 + .../modification_handlers/__init__.py | 7 + ...nteractions_to_affordance_lists_handler.py | 54 + ...n_instance_manager_modification_handler.py | 50 + .../services/sim/__init__.py | 7 + .../services/sim/cas/__init__.py | 7 + .../services/sim/cas/common_sim_outfit_io.py | 396 + ...mmon_temporary_sim_clone_in_cas_service.py | 283 + .../sims4communitylib/systems/__init__.py | 7 + .../systems/caching/__init__.py | 7 + .../common_serializable_object_cache.py | 69 + ...ommon_serializable_object_cache_service.py | 104 + .../systems/item_query/__init__.py | 7 + .../common_loaded_item_query_registry.py | 545 + .../item_query/common_loaded_item_registry.py | 269 + .../systems/item_query/dtos/__init__.py | 7 + .../item_query/dtos/common_loaded_item.py | 198 + .../systems/item_query/enums/__init__.py | 7 + .../enums/common_query_method_type.py | 16 + .../item_query/item_loaders/__init__.py | 7 + .../item_loaders/common_base_item_loader.py | 106 + .../systems/item_query/item_tests/__init__.py | 7 + .../common_loaded_item_is_available_test.py | 32 + ...ommon_loaded_item_is_not_available_test.py | 32 + .../item_tests/common_loaded_item_test.py | 34 + .../item_query/persistence/__init__.py | 7 + .../persistence/common_loaded_item_cache.py | 18 + .../common_loaded_item_cache_service.py | 45 + .../systems/item_query/query/__init__.py | 7 + .../query/common_loaded_item_filter.py | 93 + .../common_loaded_item_filter_request.py | 131 + .../query/common_loaded_item_key.py | 42 + .../query/common_loaded_item_organizer.py | 35 + .../query/common_loaded_item_query_utils.py | 160 + .../systems/settings/__init__.py | 7 + .../systems/settings/common_setting_utils.py | 112 + .../settings/common_settings_data_manager.py | 41 + .../common_settings_data_manager_utils.py | 61 + .../settings/common_settings_data_store.py | 35 + .../sims4communitylib/testing/__init__.py | 7 + .../testing/common_assertion_utils.py | 282 + .../testing/common_test_service.py | 345 + .../s4ap/sims4communitylib/utils/__init__.py | 7 + .../sims4communitylib/utils/cas/__init__.py | 7 + .../utils/cas/common_cas_utils.py | 975 + .../utils/cas/common_outfit_utils.py | 1466 ++ .../utils/common_collection_utils.py | 260 + .../utils/common_component_utils.py | 79 + .../utils/common_date_utils.py | 37 + .../utils/common_function_utils.py | 245 + .../utils/common_icon_utils.py | 189 + .../utils/common_injection_utils.py | 417 + .../utils/common_io_utils.py | 119 + .../utils/common_json_io_utils.py | 155 + .../utils/common_keyboard_utils.py | 161 + .../utils/common_log_registry.py | 818 + .../utils/common_log_utils.py | 206 + .../utils/common_math_utils.py | 97 + .../utils/common_resource_utils.py | 437 + .../utils/common_time_utils.py | 592 + .../utils/common_type_utils.py | 271 + .../utils/common_weather_utils.py | 308 + .../utils/effects/__init__.py | 7 + .../effects/common_visual_effect_commands.py | 192 + .../utils/environment/__init__.py | 7 + .../environment/common_business_utils.py | 80 + .../environment/common_civic_policy_utils.py | 455 + .../utils/localization/__init__.py | 7 + .../localization/common_localization_utils.py | 245 + .../common_localized_string_colors.py | 23 + .../common_localized_string_separators.py | 65 + .../utils/location/__init__.py | 7 + .../utils/location/common_location_utils.py | 979 ++ .../utils/location/common_terrain_utils.py | 14 + .../utils/location/common_travel_utils.py | 80 + .../sims4communitylib/utils/math/__init__.py | 7 + .../utils/math/common_bitwise_utils.py | 110 + .../sims4communitylib/utils/misc/__init__.py | 7 + .../utils/misc/common_camera_utils.py | 141 + .../utils/misc/common_fire_utils.py | 134 + .../utils/misc/common_game_client_utils.py | 104 + .../utils/misc/common_mod_identity_utils.py | 37 + .../utils/misc/common_text_utils.py | 70 + .../utils/objects/__init__.py | 7 + .../objects/common_object_household_utils.py | 47 + .../common_object_interaction_utils.py | 326 + .../objects/common_object_inventory_utils.py | 214 + .../objects/common_object_location_utils.py | 389 + .../utils/objects/common_object_lock_utils.py | 198 + .../objects/common_object_ownership_utils.py | 141 + .../common_object_reservation_utils.py | 190 + .../utils/objects/common_object_slot_utils.py | 197 + .../objects/common_object_spawn_utils.py | 462 + .../objects/common_object_state_utils.py | 734 + .../utils/objects/common_object_tag_utils.py | 167 + .../utils/objects/common_object_type_utils.py | 482 + .../utils/objects/common_object_utils.py | 314 + .../objects/common_object_visibility_utils.py | 82 + .../utils/resources/__init__.py | 7 + .../utils/resources/common_club_utils.py | 78 + .../utils/resources/common_game_pack_utils.py | 68 + .../resources/common_interaction_utils.py | 434 + .../resources/common_loot_action_utils.py | 105 + .../utils/resources/common_recipe_utils.py | 128 + .../utils/resources/common_situation_utils.py | 329 + .../utils/resources/common_skill_utils.py | 121 + .../utils/resources/common_statistic_utils.py | 131 + .../utils/save_load/__init__.py | 7 + .../utils/save_load/common_save_utils.py | 56 + .../sims4communitylib/utils/sims/__init__.py | 7 + .../utils/sims/common_age_species_utils.py | 446 + .../utils/sims/common_age_utils.py | 1103 ++ .../utils/sims/common_buff_utils.py | 592 + .../utils/sims/common_career_level_utils.py | 50 + .../utils/sims/common_career_track_utils.py | 199 + .../utils/sims/common_career_utils.py | 252 + .../utils/sims/common_gender_utils.py | 240 + .../utils/sims/common_household_utils.py | 747 + .../utils/sims/common_mood_utils.py | 277 + .../utils/sims/common_occult_utils.py | 1876 ++ .../utils/sims/common_phone_utils.py | 77 + .../utils/sims/common_rabbit_hole_utils.py | 61 + .../utils/sims/common_relationship_utils.py | 1128 ++ .../common_sim_appearance_modifier_utils.py | 219 + .../utils/sims/common_sim_autonomy_utils.py | 143 + .../utils/sims/common_sim_body_utils.py | 190 + .../utils/sims/common_sim_bucks_utils.py | 785 + .../utils/sims/common_sim_career_utils.py | 965 + .../utils/sims/common_sim_club_utils.py | 126 + .../utils/sims/common_sim_crafting_utils.py | 104 + .../utils/sims/common_sim_currency_utils.py | 140 + .../utils/sims/common_sim_death_utils.py | 472 + .../sims/common_sim_demographic_type_utils.py | 407 + .../sims/common_sim_gender_option_utils.py | 879 + .../common_sim_gender_preference_utils.py | 485 + .../utils/sims/common_sim_genealogy_utils.py | 572 + .../sims/common_sim_interaction_utils.py | 1419 ++ .../utils/sims/common_sim_inventory_utils.py | 396 + .../utils/sims/common_sim_location_utils.py | 770 + .../sims/common_sim_loot_action_utils.py | 124 + .../utils/sims/common_sim_motive_utils.py | 646 + .../utils/sims/common_sim_name_utils.py | 284 + .../sims/common_sim_occult_type_utils.py | 265 + .../utils/sims/common_sim_plumbob_utils.py | 143 + .../utils/sims/common_sim_posture_utils.py | 266 + .../utils/sims/common_sim_pregnancy_utils.py | 622 + .../sims/common_sim_rabbit_hole_utils.py | 102 + ...mmon_sim_relationship_expectation_utils.py | 223 + .../utils/sims/common_sim_routing_utils.py | 123 + .../utils/sims/common_sim_situation_utils.py | 607 + .../utils/sims/common_sim_skill_utils.py | 409 + .../utils/sims/common_sim_spawn_utils.py | 3082 ++++ .../utils/sims/common_sim_spell_utils.py | 302 + .../utils/sims/common_sim_state_utils.py | 104 + .../utils/sims/common_sim_statistic_utils.py | 621 + .../utils/sims/common_sim_type_utils.py | 2603 +++ .../utils/sims/common_sim_unlock_utils.py | 28 + .../utils/sims/common_sim_utils.py | 362 + .../utils/sims/common_sim_voice_utils.py | 462 + .../utils/sims/common_sim_walkstyle_utils.py | 62 + .../utils/sims/common_species_utils.py | 336 + .../utils/sims/common_trait_utils.py | 1655 ++ .../utils/sims/common_whim_utils.py | 36 + .../utils/terrain/__init__.py | 7 + .../common_terrain_interaction_utils.py | 58 + .../terrain/common_terrain_location_utils.py | 68 + .../utils/terrain/common_terrain_utils.py | 12 + .../sims4communitylib/utils/time/__init__.py | 7 + .../utils/time/common_alarm_utils.py | 181 + .../sims4communitylib/utils/whims/__init__.py | 7 + .../common_satisfaction_reward_store_item.py | 35 + .../common_satisfaction_reward_store_utils.py | 172 + Scripts/s4ap/utils/s4ap_generic_utils.py | 4 +- Scripts/s4ap/utils/s4ap_phone_utils.py | 4 +- Scripts/s4ap/utils/s4ap_reset_utils.py | 2 +- Scripts/s4ap/utils/s4ap_skill_utils.py | 2 +- custom_scripts_for_decompile/generated/key | Bin 0 -> 256 bytes 595 files changed, 117396 insertions(+), 43 deletions(-) create mode 100644 Release/S4CLSampleMod/s4cl_sample_mod.package create mode 100644 Scripts/s4ap/sims4communitylib/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/appearance_modifiers/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/appearance_modifiers/common_attach_cas_parts_appearance_modifier.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/buffs/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/buffs/common_buff.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/calculations/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/calculations/common_available_for_sim.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/commodities/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/commodities/common_commodity.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/common_resource_key.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/effects/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/effects/common_visual_effect.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/enums/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/enums/common_versioned_enum_value_collection.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/enums/common_versioned_sim_demographic_type_collection.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/filters/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/filters/common_match_all_non_sims_object_filter.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/filters/common_match_all_sims_object_filter.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/filters/common_match_object_filter.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/interactions/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/interactions/_common_interaction_custom_mixin.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/interactions/_common_interaction_hooks_mixin.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/interactions/common_immediate_super_interaction.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/interactions/common_interaction.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/interactions/common_interaction_override_name.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/interactions/common_mixer_interaction.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/interactions/common_object_interaction.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/interactions/common_social_mixer_interaction.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/interactions/common_social_super_interaction.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/interactions/common_super_interaction.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/interactions/common_terrain_interaction.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/math/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/math/common_comparison.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/math/common_float_range.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/math/common_integer_range.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/math/common_location.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/math/common_polygon.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/math/common_quaternion.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/math/common_routing_location.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/math/common_surface_identifier.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/math/common_transform.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/math/common_vector3.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/math/common_weighted_value.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/math/common_weighted_value_tally.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/mixins/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/mixins/common_affordance_lists_mixin.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/mixins/common_interactions_mixin.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/options.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/resolvers/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/resolvers/common_double_sim_resolver.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/runnables/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/runnables/common_runnable.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/runnables/common_runnable_with_sims.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/runnables/contexts/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_context.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_context_with_sims.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_object_context.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_sim_context.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/serialization/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/serialization/common_serializable.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/serialization/common_serializable_location.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/test_based_scores/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/test_based_scores/common_sim_to_sim_test_based_score.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/test_based_scores/common_single_sim_test_based_score.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/test_based_scores/common_test_based_score.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/testing/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/testing/common_enqueue_result.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/testing/common_execution_result.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/testing/common_test_result.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/time/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/time/common_alarm_handle.py create mode 100644 Scripts/s4ap/sims4communitylib/classes/time/common_stop_watch.py create mode 100644 Scripts/s4ap/sims4communitylib/conditionals/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/conditionals/common_conditional_action.py create mode 100644 Scripts/s4ap/sims4communitylib/debug/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/debug/dialogs/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/debug/dialogs/common_change_object_state_dialog.py create mode 100644 Scripts/s4ap/sims4communitylib/debug/interactions/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/debug/interactions/_register_interactions.py create mode 100644 Scripts/s4ap/sims4communitylib/debug/interactions/change_object_states.py create mode 100644 Scripts/s4ap/sims4communitylib/debug/interactions/induce_labor.py create mode 100644 Scripts/s4ap/sims4communitylib/debug/interactions/log_all_game_tags.py create mode 100644 Scripts/s4ap/sims4communitylib/debug/interactions/log_all_interactions.py create mode 100644 Scripts/s4ap/sims4communitylib/debug/interactions/object_break.py create mode 100644 Scripts/s4ap/sims4communitylib/debug/interactions/object_fix.py create mode 100644 Scripts/s4ap/sims4communitylib/debug/interactions/object_make_clean.py create mode 100644 Scripts/s4ap/sims4communitylib/debug/interactions/object_make_dirty.py create mode 100644 Scripts/s4ap/sims4communitylib/debug/interactions/show_active_buffs.py create mode 100644 Scripts/s4ap/sims4communitylib/debug/interactions/show_running_and_queued_interactions.py create mode 100644 Scripts/s4ap/sims4communitylib/debug/interactions/show_running_situations.py create mode 100644 Scripts/s4ap/sims4communitylib/debug/interactions/show_traits.py create mode 100644 Scripts/s4ap/sims4communitylib/debug/traits/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/debug/traits/_auto_apply_traits.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/_common_ui_dialog_multi_text_input_ok_cancel.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/_common_ui_dialog_text_input_ok_cancel.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/choose_item_dialog.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/choose_object_dialog.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/choose_objects_dialog.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/common_choice_outcome.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/common_choose_dialog.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/common_choose_outfit_dialog.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/common_choose_response_dialog.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/common_choose_sim_dialog.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/common_choose_sims_dialog.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/common_dialog.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/common_dialog_navigation_button_tag.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/common_input_float_dialog.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/common_input_integer_dialog.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/common_input_multi_text_dialog.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/common_input_text_dialog.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/common_input_text_field.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/common_multi_pane_choose_dialog.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/common_ok_dialog.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/common_purchase_objects_dialog.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/common_targeted_question_dialog.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/common_ui_dialog_response.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/common_ui_response_dialog.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/custom_dialogs/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/custom_dialogs/picker_dialogs/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/custom_dialogs/picker_dialogs/common_ui_multi_picker.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/custom_dialogs/picker_dialogs/common_ui_object_category_picker.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/ok_cancel_dialog.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_button_option_dialog.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_object_option_dialog.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_objects_option_dialog.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_option_dialog.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_options_dialog.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_response_option_dialog.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_sim_option_dialog.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_sims_option_dialog.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_multi_pane_choose_option_dialog.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_option_dialog.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/common_dialog_option.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/common_dialog_option_context.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_action_option.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_branch_option.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_integer_option.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_multi_text_option.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_option.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_text_option.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_object_option.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_option_category.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_select_option.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_toggle_option.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/response/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/response/common_dialog_button_option.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/response/common_dialog_response_option.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/response/common_dialog_response_option_context.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/sims/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/sims/common_dialog_sim_option.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/sims/common_dialog_sim_option_context.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/premade_dialogs/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/premade_dialogs/common_choose_sim_demographic_types_dialog.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/premade_dialogs/common_premade_choose_sim_option_dialog.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/premade_dialogs/common_premade_choose_sims_option_dialog.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/utils/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/dialogs/utils/common_dialog_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/dtos/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/dtos/common_cas_part.py create mode 100644 Scripts/s4ap/sims4communitylib/dtos/common_object_containment_slot.py create mode 100644 Scripts/s4ap/sims4communitylib/dtos/common_outfit.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/affordance_list_ids.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/animation_state_machines_enum.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/buffs_enum.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/clubs_enum.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_age.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_appearance_modifier_priority.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_appearance_modifier_type.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_body_frame.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_body_slot.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_bucks_types.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_business_advertising_type.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_business_customer_star_rating_type.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_business_employee_type.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_business_quality_type.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_career_ids.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_character_restrictions.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_civic_policy_status_type.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_civic_policy_type.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_cloud_type.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_combined_species.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_currency_modify_reasons.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_death_types.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_enum.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_fund_types.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_funds_sources.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_game_tag_category.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_gender.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_gender_preference_type.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_ground_cover_type.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_key.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_object_delivery_method.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_object_filter_type.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_object_preference_tag.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_object_quality.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_object_slot_name_ids.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_object_state_ids.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_object_state_value_ids.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_occult_type.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_posture_id.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_precipitation_type.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_pregnancy_origin.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_puddle_liquid.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_puddle_size.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_region_id.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_runnable_state.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_runnable_state_type.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_side.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_sim_demographic_types.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_sim_name_type.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_skill_effectiveness.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_slot_type.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_species.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_statistic_category.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_street_civic_policy_ids.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_temperature.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_venue_civic_policy_ids.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_voice_actor_type.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_weather_effect_type.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_weather_event_ids.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/common_weather_type.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/enumtypes/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/enumtypes/common_int.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/enumtypes/common_int_flags.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/enumtypes/common_versioned_int.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/enumtypes/common_versioned_int_flags.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/enumtypes/common_versioned_values_mixin.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/enumtypes/float_enum.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/enumtypes/int_enum.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/enumtypes/object_enum.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/enumtypes/string_enum.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/furniture_objects_enum.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/icons_enum.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/interactions_enum.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/long_term_sentiments_enum.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/lot_traits_enum.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/moods_enum.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/motives_enum.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/relationship_bit_collection_uids_enum.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/relationship_bit_collections_enum.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/relationship_bits_enum.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/relationship_tracks_enum.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/relationship_types_enum.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/short_term_relationship_tracks_enum.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/short_term_sentiments_enum.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/sim_type.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/situation_jobs_enum.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/situations_enum.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/skills_enum.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/statistics_enum.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/strings_enum.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/tags_enum.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/traits_enum.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/types/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/types/component_types.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/venues_enum.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/whims_enum.py create mode 100644 Scripts/s4ap/sims4communitylib/enums/world_types_enum.py create mode 100644 Scripts/s4ap/sims4communitylib/events/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/events/build_buy/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/events/build_buy/common_build_buy_event_dispatcher.py create mode 100644 Scripts/s4ap/sims4communitylib/events/build_buy/events/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/events/build_buy/events/build_buy_enter.py create mode 100644 Scripts/s4ap/sims4communitylib/events/build_buy/events/build_buy_exit.py create mode 100644 Scripts/s4ap/sims4communitylib/events/event_handling/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/events/event_handling/common_event.py create mode 100644 Scripts/s4ap/sims4communitylib/events/event_handling/common_event_handler.py create mode 100644 Scripts/s4ap/sims4communitylib/events/event_handling/common_event_registry.py create mode 100644 Scripts/s4ap/sims4communitylib/events/game_object/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/events/game_object/common_game_object_event_dispatcher.py create mode 100644 Scripts/s4ap/sims4communitylib/events/game_object/events/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_added_to_game_object_inventory.py create mode 100644 Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_added_to_inventory.py create mode 100644 Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_initialized.py create mode 100644 Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_loaded.py create mode 100644 Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_deleted.py create mode 100644 Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_despawned.py create mode 100644 Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_removed_from_game_object_inventory.py create mode 100644 Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_removed_from_inventory.py create mode 100644 Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_spawned.py create mode 100644 Scripts/s4ap/sims4communitylib/events/interaction/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/events/interaction/common_interaction_event_dispatcher.py create mode 100644 Scripts/s4ap/sims4communitylib/events/interaction/events/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_cancelled.py create mode 100644 Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_outcome.py create mode 100644 Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_post_queued.py create mode 100644 Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_pre_run.py create mode 100644 Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_queued.py create mode 100644 Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_run.py create mode 100644 Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_started.py create mode 100644 Scripts/s4ap/sims4communitylib/events/interaction/events/mixer_interaction_cancelled.py create mode 100644 Scripts/s4ap/sims4communitylib/events/interaction/events/super_interaction_cancelled.py create mode 100644 Scripts/s4ap/sims4communitylib/events/interval/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/events/interval/common_interval_event_service.py create mode 100644 Scripts/s4ap/sims4communitylib/events/save/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/events/save/common_save_event_dispatcher.py create mode 100644 Scripts/s4ap/sims4communitylib/events/save/events/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/events/save/events/save_loaded.py create mode 100644 Scripts/s4ap/sims4communitylib/events/save/events/save_saved.py create mode 100644 Scripts/s4ap/sims4communitylib/events/sim/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/events/sim/common_sim_event_dispatcher.py create mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/game_object_added_to_sim_inventory.py create mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/game_object_pre_removed_from_sim_inventory.py create mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_added_occult_type.py create mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_after_set_current_outfit.py create mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_buff_added.py create mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_buff_removed.py create mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_age.py create mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender.py create mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_body_frame.py create mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_breasts.py create mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_can_be_impregnated.py create mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_can_impregnate.py create mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_can_reproduce.py create mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_clothing_preference.py create mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_toilet_usage.py create mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_occult_type.py create mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_changing_occult_type.py create mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_died.py create mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_initialized.py create mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_loaded.py create mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_pre_despawned.py create mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_relationship_bit_added.py create mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_relationship_bit_removed.py create mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_removed_occult_type.py create mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_revived.py create mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_set_current_outfit.py create mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_skill_leveled_up.py create mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_spawned.py create mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_trait_added.py create mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_trait_removed.py create mode 100644 Scripts/s4ap/sims4communitylib/events/zone_spin/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/events/zone_spin/common_zone_spin_event_dispatcher.py create mode 100644 Scripts/s4ap/sims4communitylib/events/zone_spin/events/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_early_load.py create mode 100644 Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_late_load.py create mode 100644 Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_manager_start_event.py create mode 100644 Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_post_load.py create mode 100644 Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_save.py create mode 100644 Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_teardown.py create mode 100644 Scripts/s4ap/sims4communitylib/events/zone_update/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/events/zone_update/common_zone_update_event_dispatcher.py create mode 100644 Scripts/s4ap/sims4communitylib/events/zone_update/events/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/events/zone_update/events/zone_update_event.py create mode 100644 Scripts/s4ap/sims4communitylib/examples/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/examples/common_example_apply_bare_feet_buff.py create mode 100644 Scripts/s4ap/sims4communitylib/exceptions/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/exceptions/common_exceptions_handler.py create mode 100644 Scripts/s4ap/sims4communitylib/exceptions/common_stacktrace_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/exceptions/generic_error_handling.py create mode 100644 Scripts/s4ap/sims4communitylib/logging/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/logging/_has_s4cl_class_log.py create mode 100644 Scripts/s4ap/sims4communitylib/logging/_has_s4cl_log.py create mode 100644 Scripts/s4ap/sims4communitylib/logging/_logging_commands.py create mode 100644 Scripts/s4ap/sims4communitylib/logging/has_class_log.py create mode 100644 Scripts/s4ap/sims4communitylib/logging/has_log.py create mode 100644 Scripts/s4ap/sims4communitylib/logging/vanilla_logging.py create mode 100644 Scripts/s4ap/sims4communitylib/mod_support/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/mod_support/common_mod_info.py create mode 100644 Scripts/s4ap/sims4communitylib/mod_support/has_class_mod_identity.py create mode 100644 Scripts/s4ap/sims4communitylib/mod_support/has_mod_identity.py create mode 100644 Scripts/s4ap/sims4communitylib/mod_support/mod_identity.py create mode 100644 Scripts/s4ap/sims4communitylib/modinfo.py create mode 100644 Scripts/s4ap/sims4communitylib/notifications/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/notifications/common_basic_notification.py create mode 100644 Scripts/s4ap/sims4communitylib/persistence/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/persistence/common_game_object_data_storage.py create mode 100644 Scripts/s4ap/sims4communitylib/persistence/common_persisted_game_object_data_storage.py create mode 100644 Scripts/s4ap/sims4communitylib/persistence/common_persisted_sim_data_storage.py create mode 100644 Scripts/s4ap/sims4communitylib/persistence/common_sim_data_storage.py create mode 100644 Scripts/s4ap/sims4communitylib/persistence/data_management/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/persistence/data_management/common_data_manager.py create mode 100644 Scripts/s4ap/sims4communitylib/persistence/data_management/common_data_manager_registry.py create mode 100644 Scripts/s4ap/sims4communitylib/persistence/data_stores/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/persistence/data_stores/common_data_store.py create mode 100644 Scripts/s4ap/sims4communitylib/persistence/data_stores/common_game_object_data_store.py create mode 100644 Scripts/s4ap/sims4communitylib/persistence/data_stores/common_sim_data_store.py create mode 100644 Scripts/s4ap/sims4communitylib/persistence/persistence_services/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_file_persistence_service.py create mode 100644 Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_folder_persistence_service.py create mode 100644 Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_hidden_household_persistence_service.py create mode 100644 Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_individual_folder_persistence_service.py create mode 100644 Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_persistence_service.py create mode 100644 Scripts/s4ap/sims4communitylib/s4cl_commands.py create mode 100644 Scripts/s4ap/sims4communitylib/s4cl_configuration.py create mode 100644 Scripts/s4ap/sims4communitylib/services/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/services/commands/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/services/commands/common_console_command.py create mode 100644 Scripts/s4ap/sims4communitylib/services/commands/common_console_command_output.py create mode 100644 Scripts/s4ap/sims4communitylib/services/commands/common_console_command_parameters.py create mode 100644 Scripts/s4ap/sims4communitylib/services/common_service.py create mode 100644 Scripts/s4ap/sims4communitylib/services/interactions/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/services/interactions/interaction_registration_service.py create mode 100644 Scripts/s4ap/sims4communitylib/services/resources/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/services/resources/common_instance_manager_modification_registry.py create mode 100644 Scripts/s4ap/sims4communitylib/services/resources/common_posture_constraint_service.py create mode 100644 Scripts/s4ap/sims4communitylib/services/resources/modification_handlers/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/services/resources/modification_handlers/common_add_interactions_to_affordance_lists_handler.py create mode 100644 Scripts/s4ap/sims4communitylib/services/resources/modification_handlers/common_instance_manager_modification_handler.py create mode 100644 Scripts/s4ap/sims4communitylib/services/sim/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/services/sim/cas/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/services/sim/cas/common_sim_outfit_io.py create mode 100644 Scripts/s4ap/sims4communitylib/services/sim/cas/common_temporary_sim_clone_in_cas_service.py create mode 100644 Scripts/s4ap/sims4communitylib/systems/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/systems/caching/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/systems/caching/common_serializable_object_cache.py create mode 100644 Scripts/s4ap/sims4communitylib/systems/caching/common_serializable_object_cache_service.py create mode 100644 Scripts/s4ap/sims4communitylib/systems/item_query/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/systems/item_query/common_loaded_item_query_registry.py create mode 100644 Scripts/s4ap/sims4communitylib/systems/item_query/common_loaded_item_registry.py create mode 100644 Scripts/s4ap/sims4communitylib/systems/item_query/dtos/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/systems/item_query/dtos/common_loaded_item.py create mode 100644 Scripts/s4ap/sims4communitylib/systems/item_query/enums/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/systems/item_query/enums/common_query_method_type.py create mode 100644 Scripts/s4ap/sims4communitylib/systems/item_query/item_loaders/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/systems/item_query/item_loaders/common_base_item_loader.py create mode 100644 Scripts/s4ap/sims4communitylib/systems/item_query/item_tests/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/systems/item_query/item_tests/common_loaded_item_is_available_test.py create mode 100644 Scripts/s4ap/sims4communitylib/systems/item_query/item_tests/common_loaded_item_is_not_available_test.py create mode 100644 Scripts/s4ap/sims4communitylib/systems/item_query/item_tests/common_loaded_item_test.py create mode 100644 Scripts/s4ap/sims4communitylib/systems/item_query/persistence/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/systems/item_query/persistence/common_loaded_item_cache.py create mode 100644 Scripts/s4ap/sims4communitylib/systems/item_query/persistence/common_loaded_item_cache_service.py create mode 100644 Scripts/s4ap/sims4communitylib/systems/item_query/query/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_filter.py create mode 100644 Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_filter_request.py create mode 100644 Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_key.py create mode 100644 Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_organizer.py create mode 100644 Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_query_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/systems/settings/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/systems/settings/common_setting_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/systems/settings/common_settings_data_manager.py create mode 100644 Scripts/s4ap/sims4communitylib/systems/settings/common_settings_data_manager_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/systems/settings/common_settings_data_store.py create mode 100644 Scripts/s4ap/sims4communitylib/testing/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/testing/common_assertion_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/testing/common_test_service.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/cas/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/cas/common_cas_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/cas/common_outfit_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/common_collection_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/common_component_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/common_date_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/common_function_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/common_icon_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/common_injection_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/common_io_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/common_json_io_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/common_keyboard_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/common_log_registry.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/common_log_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/common_math_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/common_resource_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/common_time_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/common_type_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/common_weather_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/effects/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/effects/common_visual_effect_commands.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/environment/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/environment/common_business_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/environment/common_civic_policy_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/localization/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/localization/common_localization_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/localization/common_localized_string_colors.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/localization/common_localized_string_separators.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/location/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/location/common_location_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/location/common_terrain_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/location/common_travel_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/math/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/math/common_bitwise_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/misc/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/misc/common_camera_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/misc/common_fire_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/misc/common_game_client_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/misc/common_mod_identity_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/misc/common_text_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/objects/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/objects/common_object_household_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/objects/common_object_interaction_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/objects/common_object_inventory_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/objects/common_object_location_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/objects/common_object_lock_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/objects/common_object_ownership_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/objects/common_object_reservation_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/objects/common_object_slot_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/objects/common_object_spawn_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/objects/common_object_state_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/objects/common_object_tag_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/objects/common_object_type_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/objects/common_object_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/objects/common_object_visibility_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/resources/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/resources/common_club_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/resources/common_game_pack_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/resources/common_interaction_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/resources/common_loot_action_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/resources/common_recipe_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/resources/common_situation_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/resources/common_skill_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/resources/common_statistic_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/save_load/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/save_load/common_save_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_age_species_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_age_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_buff_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_career_level_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_career_track_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_career_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_gender_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_household_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_mood_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_occult_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_phone_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_rabbit_hole_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_relationship_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_appearance_modifier_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_autonomy_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_body_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_bucks_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_career_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_club_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_crafting_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_currency_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_death_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_demographic_type_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_gender_option_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_gender_preference_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_genealogy_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_interaction_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_inventory_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_location_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_loot_action_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_motive_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_name_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_occult_type_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_plumbob_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_posture_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_pregnancy_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_rabbit_hole_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_relationship_expectation_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_routing_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_situation_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_skill_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_spawn_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_spell_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_state_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_statistic_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_type_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_unlock_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_voice_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_walkstyle_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_species_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_trait_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_whim_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/terrain/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/terrain/common_terrain_interaction_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/terrain/common_terrain_location_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/terrain/common_terrain_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/time/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/time/common_alarm_utils.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/whims/__init__.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/whims/common_satisfaction_reward_store_item.py create mode 100644 Scripts/s4ap/sims4communitylib/utils/whims/common_satisfaction_reward_store_utils.py create mode 100644 custom_scripts_for_decompile/generated/key diff --git a/Release/S4CLSampleMod/s4cl_sample_mod.package b/Release/S4CLSampleMod/s4cl_sample_mod.package new file mode 100644 index 0000000000000000000000000000000000000000..307462cea06c3676ee61341e234e69c024d73cb3 GIT binary patch literal 3228 zcmZ>93UFg$U|?VbVq8EFDxm^Why<8{>lE%ikl)qn zI7`vOaJzzf=s|OP*MrI%BMxesn))A9w>MNZb=Ch{dCII!iS4{e>#09Mt&gsRv`*?d zlhk_W%A-d|zJ$oOo)J>8He4^EF=v%P&Z9Sr8&V?JE^K)6=T6g^IafqlA6X>=_IU4I6;8Qxqdiz5yuD1d{)OTb>yt zKLOZ?#i5@CB(DK%zv7T*1<4=4Ezbs$j{r7!ap-3U$$!8t&jFI}V8N-M8zis5ic_8k zB)K6scKR}ZQ E0E?zaVE_OC literal 0 HcmV?d00001 diff --git a/Scripts/s4ap/events/Utils/allow_read_items.py b/Scripts/s4ap/events/Utils/allow_read_items.py index cb5461d..c667011 100644 --- a/Scripts/s4ap/events/Utils/allow_read_items.py +++ b/Scripts/s4ap/events/Utils/allow_read_items.py @@ -1,4 +1,4 @@ -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent class AllowReceiveItems(CommonEvent): diff --git a/Scripts/s4ap/events/Utils/send_location_event.py b/Scripts/s4ap/events/Utils/send_location_event.py index 9ef0861..fff2115 100644 --- a/Scripts/s4ap/events/Utils/send_location_event.py +++ b/Scripts/s4ap/events/Utils/send_location_event.py @@ -1,4 +1,4 @@ -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent class SendLocationEvent(CommonEvent): diff --git a/Scripts/s4ap/events/aspiration_event_dispatcher.py b/Scripts/s4ap/events/aspiration_event_dispatcher.py index 8cb0f07..0a6591e 100644 --- a/Scripts/s4ap/events/aspiration_event_dispatcher.py +++ b/Scripts/s4ap/events/aspiration_event_dispatcher.py @@ -4,9 +4,9 @@ from s4ap.events.checks.send_check_event import SendLocationEvent from s4ap.modinfo import ModInfo from s4ap.utils.s4ap_sim_utils import S4APSimUtils -from sims4communitylib.events.event_handling.common_event import CommonEvent -from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from sims4communitylib.services.common_service import CommonService +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry +from s4ap.sims4communitylib.services.common_service import CommonService from lot51_core.utils.injection import inject_to diff --git a/Scripts/s4ap/events/career_event_dispatcher.py b/Scripts/s4ap/events/career_event_dispatcher.py index 640dbee..c9ccca9 100644 --- a/Scripts/s4ap/events/career_event_dispatcher.py +++ b/Scripts/s4ap/events/career_event_dispatcher.py @@ -5,9 +5,9 @@ from s4ap.modinfo import ModInfo from s4ap.utils.s4ap_household_utils import S4APHouseholdUtils from s4ap.utils.s4ap_sim_utils import S4APSimUtils -from sims4communitylib.events.event_handling.common_event import CommonEvent -from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from sims4communitylib.services.common_service import CommonService +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry +from s4ap.sims4communitylib.services.common_service import CommonService from lot51_core.utils.injection import inject_to log = S4APLogger.get_log() diff --git a/Scripts/s4ap/events/checks/send_check_event.py b/Scripts/s4ap/events/checks/send_check_event.py index 3ec4fb6..568d20d 100644 --- a/Scripts/s4ap/events/checks/send_check_event.py +++ b/Scripts/s4ap/events/checks/send_check_event.py @@ -3,7 +3,7 @@ from s4ap.logging.s4ap_logger import S4APLogger from s4ap.modinfo import ModInfo from s4ap.utils.s4ap_generic_utils import S4APUtils -from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry +from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry logger = S4APLogger.get_log() logger.enable() diff --git a/Scripts/s4ap/events/items/receive_item_event.py b/Scripts/s4ap/events/items/receive_item_event.py index 6fc51f4..2f47cb0 100644 --- a/Scripts/s4ap/events/items/receive_item_event.py +++ b/Scripts/s4ap/events/items/receive_item_event.py @@ -14,8 +14,8 @@ from s4ap.utils.s4ap_skill_utils import lock_skills from s4ap.utils.s4ap_trait_utils import S4APTraitUtils from sims4.resources import Types -from sims4communitylib.events.event_handling.common_event import CommonEvent -from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry from lib.collections import Counter log = S4APLogger.get_log() log.enable() diff --git a/Scripts/s4ap/events/skill_event_dispatcher.py b/Scripts/s4ap/events/skill_event_dispatcher.py index 1312520..7f453e0 100644 --- a/Scripts/s4ap/events/skill_event_dispatcher.py +++ b/Scripts/s4ap/events/skill_event_dispatcher.py @@ -6,9 +6,9 @@ from s4ap.utils.s4ap_sim_utils import S4APSimUtils from s4ap.utils.s4ap_skill_utils import S4APSkillUtils from sims.sim_info import SimInfo -from sims4communitylib.events.event_handling.common_event import CommonEvent -from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from sims4communitylib.services.common_service import CommonService +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry +from s4ap.sims4communitylib.services.common_service import CommonService from lot51_core.utils.injection import inject_to from statistics.skill import Skill diff --git a/Scripts/s4ap/jsonio/auto_parse_json.py b/Scripts/s4ap/jsonio/auto_parse_json.py index e610c45..5e6a39f 100644 --- a/Scripts/s4ap/jsonio/auto_parse_json.py +++ b/Scripts/s4ap/jsonio/auto_parse_json.py @@ -7,10 +7,10 @@ from s4ap.logging.s4ap_logger import S4APLogger from s4ap.modinfo import ModInfo from s4ap.persistance.ap_session_data_store import S4APSessionStoreUtils -from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from sims4communitylib.events.interval.common_interval_event_service import CommonIntervalEventRegistry -from sims4communitylib.events.save.events.save_loaded import S4CLSaveLoadedEvent -from sims4communitylib.utils.common_log_utils import CommonLogUtils +from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry +from s4ap.sims4communitylib.events.interval.common_interval_event_service import CommonIntervalEventRegistry +from s4ap.sims4communitylib.events.save.events.save_loaded import S4CLSaveLoadedEvent +from s4ap.sims4communitylib.utils.common_log_utils import CommonLogUtils logger = S4APLogger.get_log() logger.enable() diff --git a/Scripts/s4ap/jsonio/s4ap_json.py b/Scripts/s4ap/jsonio/s4ap_json.py index 2043197..b5fc5ef 100644 --- a/Scripts/s4ap/jsonio/s4ap_json.py +++ b/Scripts/s4ap/jsonio/s4ap_json.py @@ -1,8 +1,8 @@ import os from s4ap.logging.s4ap_logger import S4APLogger -from sims4communitylib.utils.common_json_io_utils import CommonJSONIOUtils -from sims4communitylib.utils.common_log_utils import CommonLogUtils +from s4ap.sims4communitylib.utils.common_json_io_utils import CommonJSONIOUtils +from s4ap.sims4communitylib.utils.common_log_utils import CommonLogUtils log = S4APLogger.get_log() log.enable() diff --git a/Scripts/s4ap/logging/s4ap_logger.py b/Scripts/s4ap/logging/s4ap_logger.py index a84a8b0..c480a99 100644 --- a/Scripts/s4ap/logging/s4ap_logger.py +++ b/Scripts/s4ap/logging/s4ap_logger.py @@ -2,12 +2,10 @@ from s4ap.modinfo import ModInfo from s4ap.utils.s4ap_generic_utils import S4APUtils from s4ap.utils.s4ap_localization_utils import S4APLocalizationUtils -from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from sims4communitylib.events.zone_spin.events.zone_late_load import S4CLZoneLateLoadEvent -from sims4communitylib.logging.has_class_log import HasClassLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils - +from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry +from s4ap.sims4communitylib.events.zone_spin.events.zone_late_load import S4CLZoneLateLoadEvent +from s4ap.sims4communitylib.logging.has_class_log import HasClassLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity class S4APLogger(HasClassLog): @classmethod diff --git a/Scripts/s4ap/modinfo.py b/Scripts/s4ap/modinfo.py index 09ebe7c..f632f05 100644 --- a/Scripts/s4ap/modinfo.py +++ b/Scripts/s4ap/modinfo.py @@ -1,4 +1,4 @@ -from sims4communitylib.mod_support.common_mod_info import CommonModInfo +from s4ap.sims4communitylib.mod_support.common_mod_info import CommonModInfo class ModInfo(CommonModInfo): diff --git a/Scripts/s4ap/persistance/ap_data_manager.py b/Scripts/s4ap/persistance/ap_data_manager.py index 2361b9b..523260e 100644 --- a/Scripts/s4ap/persistance/ap_data_manager.py +++ b/Scripts/s4ap/persistance/ap_data_manager.py @@ -1,10 +1,10 @@ from lib.typing import Tuple from s4ap.modinfo import ModInfo -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.persistence.data_management.common_data_manager import CommonDataManager -from sims4communitylib.persistence.data_management.common_data_manager_registry import CommonDataManagerRegistry -from sims4communitylib.persistence.persistence_services.common_persistence_service import CommonPersistenceService +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.persistence.data_management.common_data_manager import CommonDataManager +from s4ap.sims4communitylib.persistence.data_management.common_data_manager_registry import CommonDataManagerRegistry +from s4ap.sims4communitylib.persistence.persistence_services.common_persistence_service import CommonPersistenceService @CommonDataManagerRegistry.common_data_manager() diff --git a/Scripts/s4ap/persistance/ap_data_store.py b/Scripts/s4ap/persistance/ap_data_store.py index a04bc63..e17d3cb 100644 --- a/Scripts/s4ap/persistance/ap_data_store.py +++ b/Scripts/s4ap/persistance/ap_data_store.py @@ -1,6 +1,6 @@ from lib.typing import Any, Dict -from sims4communitylib.persistence.data_stores.common_data_store import CommonDataStore +from s4ap.sims4communitylib.persistence.data_stores.common_data_store import CommonDataStore class S4APSettings: diff --git a/Scripts/s4ap/persistance/ap_data_utils.py b/Scripts/s4ap/persistance/ap_data_utils.py index 22d5e97..ecce855 100644 --- a/Scripts/s4ap/persistance/ap_data_utils.py +++ b/Scripts/s4ap/persistance/ap_data_utils.py @@ -3,9 +3,9 @@ from s4ap.modinfo import ModInfo from s4ap.persistance.ap_data_manager import S4APDataManager from s4ap.persistance.ap_data_store import S4APGenericDataStore -from sims4communitylib.persistence.data_management.common_data_manager_registry import CommonDataManagerRegistry -from sims4communitylib.persistence.data_stores.common_data_store import CommonDataStore -from sims4communitylib.services.common_service import CommonService +from s4ap.sims4communitylib.persistence.data_management.common_data_manager_registry import CommonDataManagerRegistry +from s4ap.sims4communitylib.persistence.data_stores.common_data_store import CommonDataStore +from s4ap.sims4communitylib.services.common_service import CommonService class S4APDataManagerUtils(CommonService): diff --git a/Scripts/s4ap/persistance/ap_session_data_store.py b/Scripts/s4ap/persistance/ap_session_data_store.py index 844d4af..99f5820 100644 --- a/Scripts/s4ap/persistance/ap_session_data_store.py +++ b/Scripts/s4ap/persistance/ap_session_data_store.py @@ -7,8 +7,8 @@ from s4ap.utils.s4ap_generic_utils import S4APUtils from s4ap.utils.s4ap_localization_utils import S4APLocalizationUtils from s4ap.utils.s4ap_reset_utils import ResetSimData -from sims4communitylib.dialogs.ok_cancel_dialog import CommonOkCancelDialog -from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry +from s4ap.sims4communitylib.dialogs.ok_cancel_dialog import CommonOkCancelDialog +from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry from ui.ui_dialog import UiDialogOkCancel logger = S4APLogger.get_log() diff --git a/Scripts/s4ap/sims4communitylib/__init__.py b/Scripts/s4ap/sims4communitylib/__init__.py new file mode 100644 index 0000000..3251898 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" \ No newline at end of file diff --git a/Scripts/s4ap/sims4communitylib/classes/__init__.py b/Scripts/s4ap/sims4communitylib/classes/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/classes/appearance_modifiers/__init__.py b/Scripts/s4ap/sims4communitylib/classes/appearance_modifiers/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/appearance_modifiers/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/classes/appearance_modifiers/common_attach_cas_parts_appearance_modifier.py b/Scripts/s4ap/sims4communitylib/classes/appearance_modifiers/common_attach_cas_parts_appearance_modifier.py new file mode 100644 index 0000000..eed56c5 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/appearance_modifiers/common_attach_cas_parts_appearance_modifier.py @@ -0,0 +1,359 @@ +""" +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 +""" +import os +from typing import Any, Tuple, Union, List + +from sims.outfits.outfit_enums import OutfitCategory, BodyTypeFlag, BodyType +from sims.sim_info import SimInfo +from sims4communitylib.dtos.common_cas_part import CommonCASPart +from sims4communitylib.enums.buffs_enum import CommonBuffId +from sims4communitylib.enums.common_appearance_modifier_type import CommonAppearanceModifierType +from sims4communitylib.enums.common_body_slot import CommonBodySlot +from sims4communitylib.logging.has_log import HasLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + CommonConsoleCommandArgument +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput + +ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' + +# If on Read The Docs, create fake versions of extended objects to fix the error of inheriting from multiple MockObjects. +if ON_RTD: + # noinspection PyMissingOrEmptyDocstring + class AppearanceModifier: + # noinspection PyMissingOrEmptyDocstring + class BaseAppearanceModification: + # noinspection PyPep8Naming + @classmethod + def TunableFactory(cls) -> Any: + pass + +if not ON_RTD: + from buffs.appearance_modifier.appearance_modifier import AppearanceModifier + + +class CommonAttachCASPartsAppearanceModifier(AppearanceModifier.BaseAppearanceModification, HasLog): + """CommonAttachCASPartsAppearanceModifier() + + Attach CAS Parts to a Sim by utilizing Appearance Modifiers. + + .. note:: Appearance Modifiers will apply to any outfit a Sim wears, when switching outfits ALL of their outfits will APPEAR to have the attached CAS Part. However, appearance modifiers are only temporary. + + .. note:: To see an example of this appearance modifier in action, run the command `s4clib_testing.toggle_example_appearance_modifier_buff` in the console. (The Sim will have bare feet) + + :Example usage: + + .. highlight:: python + .. code-block:: python + + class CommonExampleApplyBareFeetAppearanceModifier(AppearanceModifier): + + class CommonAttachBareFeetModifier(CommonAttachCASPartsAppearanceModifier): + # noinspection PyMissingOrEmptyDocstring + @property + def mod_identity(self) -> CommonModIdentity: + return ModInfo.get_identity() + + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + return 'common_example_apply_bare_feet' + + def _get_cas_parts( + self, + source_sim_info: SimInfo, + modified_sim_info: SimInfo, + original_unmodified_sim_info: SimInfo, + random_seed: int + ) -> Tuple[CommonCASPart]: + # Human + # yfShoes_Nude + adult_human_female_bare_feet_id = 6543 + # ymShoes_Nude + adult_human_male_bare_feet_id = 6563 + # cuShoes_Nude + child_human_bare_feet_id = 22018 + # puShoes_Nude + toddler_human_bare_feet_id = 132818 + + # Dog + # adShoes_Nude + adult_large_dog_bare_feet_id = 125251 + # alShoes_Nude + adult_small_dog_bare_feet_id = 148839 + # cdShoes_Nude + child_dog_bare_feet_id = 158046 + + # Cat + # acShoes_Nude + adult_cat_bare_feet_id = 150367 + # ccShoes_Nude + child_cat_bare_feet_id = 164111 + + # Fox + adult_fox_bare_feet_id = 277492 + + bare_feet_cas_part_id = None + if CommonAgeUtils.is_teen_adult_or_elder(original_unmodified_sim_info): + if CommonSpeciesUtils.is_human(original_unmodified_sim_info): + if CommonGenderUtils.is_female(original_unmodified_sim_info): + bare_feet_cas_part_id = adult_human_female_bare_feet_id + elif CommonGenderUtils.is_male(original_unmodified_sim_info): + bare_feet_cas_part_id = adult_human_male_bare_feet_id + elif CommonSpeciesUtils.is_large_dog(original_unmodified_sim_info): + bare_feet_cas_part_id = adult_large_dog_bare_feet_id + elif CommonSpeciesUtils.is_small_dog(original_unmodified_sim_info): + bare_feet_cas_part_id = adult_small_dog_bare_feet_id + elif CommonSpeciesUtils.is_cat(original_unmodified_sim_info): + bare_feet_cas_part_id = adult_cat_bare_feet_id + elif CommonSpeciesUtils.is_fox(original_unmodified_sim_info): + bare_feet_cas_part_id = adult_fox_bare_feet_id + elif CommonAgeUtils.is_child(original_unmodified_sim_info): + if CommonSpeciesUtils.is_human(original_unmodified_sim_info): + bare_feet_cas_part_id = child_human_bare_feet_id + elif CommonSpeciesUtils.is_large_dog(original_unmodified_sim_info) or CommonSpeciesUtils.is_small_dog(original_unmodified_sim_info): + bare_feet_cas_part_id = child_dog_bare_feet_id + elif CommonSpeciesUtils.is_cat(original_unmodified_sim_info): + bare_feet_cas_part_id = child_cat_bare_feet_id + elif CommonAgeUtils.is_toddler(original_unmodified_sim_info): + bare_feet_cas_part_id = toddler_human_bare_feet_id + + if bare_feet_cas_part_id is None: + return tuple() + + return CommonCASPart(bare_feet_cas_part_id, CommonCASUtils.get_body_type_of_cas_part(bare_feet_cas_part_id)), + + # We override the original "appearance_modifiers" to so we can insert our custom appearance modifier. + FACTORY_TUNABLES = { + 'appearance_modifiers': TunableList( + description=' The specific appearance modifiers to use for this buff. ', + tunable=TunableList( + description=' A tunable list of weighted modifiers. When applying modifiers one of the modifiers in this list will be applied. The weight will be used to run a weighted random selection. ', + tunable=TunableTuple( + description=' A Modifier to apply and weight for the weighted random selection. ', + modifier=TunableVariant( + custom_bare_feet_modifier=CommonAttachBareFeetModifier.TunableFactory(), + ), + weight=TunableMultiplier.TunableFactory( + description=' A weight with testable multipliers that is used to determine how likely this entry is to be picked when selecting randomly. ' + ) + ) + ) + ) + } + + + # We use this buff in a Buff tuning and then apply the buff to the Sim. + class CommonExampleApplyBareFeetBuff(Buff): + + # We override the original "appearance_modifier" to so we can insert our custom appearance modifier. + INSTANCE_TUNABLES = { + 'appearance_modifier': OptionalTunable(CommonExampleApplyBareFeetAppearanceModifier.TunableFactory()), + } + + + :Example Tuning: + + Buff Tuning: + + .. highlight:: xml + .. code-block:: xml + + + + + + + + + + + + + + + + + 39b2aa4a:00000000:8af8b916cf64c646 + 39b2aa4a:00000000:3bf33216a25546ea + 2f7d0004:00000000:30f0846c783606f9 + False + + + Sim Data: + + .. highlight:: xml + .. code-block:: xml + + + + + + FD04E3BE-001407EC-8AF8B916CF64C646 + FD04E3BE-001407EC-3BF33216A25546EA + 0x00000000 + 0x00000000 + 00B2D882-00000000-30F0846C783606F9 + 0 + 0 + 0x00000000 + 0x00000000 + 1 + + + + + + + + + + + + + + + + + + + + + """ + + # noinspection PyMissingOrEmptyDocstring + @property + def mod_identity(self) -> CommonModIdentity: + raise NotImplementedError() + + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + raise NotImplementedError() + + # noinspection PyMissingOrEmptyDocstring + def modify_sim_info(self, source_sim_info: SimInfo, modified_sim_info: SimInfo, random_seed: int) -> Tuple[BodyTypeFlag, Union[List[int], None]]: + try: + if not hasattr(modified_sim_info, 'original_unmodified_sim_info'): + self.log.format_with_message('No Based On Sim Info found, using current source Sim!', original_unmodified_sim=source_sim_info) + original_unmodified_sim_info = source_sim_info + else: + original_unmodified_sim_info = getattr(modified_sim_info, 'original_unmodified_sim_info') + self.log.format_with_message('Based On Sim Info found, using Based On Sim Info!', original_unmodified_sim=original_unmodified_sim_info) + + self.log.format_with_message('Copying the base attributes of Sim to the modified Sim.', sim=source_sim_info, original_unmodified_sim=original_unmodified_sim_info, modified_sim=modified_sim_info) + if source_sim_info is not modified_sim_info: + from sims.sim_info_base_wrapper import SimInfoBaseWrapper + SimInfoBaseWrapper.copy_base_attributes(modified_sim_info, source_sim_info) + SimInfoBaseWrapper.copy_physical_attributes(modified_sim_info, source_sim_info) + modified_sim_info.skin_tone = source_sim_info._base.skin_tone + modified_sim_info.skin_tone_val_shift = source_sim_info._base.skin_tone_val_shift + modified_sim_info.load_outfits(source_sim_info.save_outfits()) + + cas_parts = self._get_cas_parts(source_sim_info, modified_sim_info, original_unmodified_sim_info, random_seed) + body_types = self._apply_cas_parts(cas_parts, source_sim_info, modified_sim_info, original_unmodified_sim_info, random_seed) + + if not body_types: + self.log.format_with_message('No body types were returned. Assuming BodyTypeFlag is NONE', sim=original_unmodified_sim_info, cas_part_ids_and_body_types=cas_parts) + return BodyTypeFlag.NONE, None + body_types = [CommonBodySlot.convert_to_vanilla(body_type) for body_type in body_types] + body_type_flags = BodyTypeFlag.make_body_type_flag(*body_types) + self.log.format_with_message('Done applying CAS Parts!', sim=original_unmodified_sim_info, cas_part_ids_and_body_types=cas_parts, body_type_flags=body_type_flags, body_types=body_types) + return body_type_flags, None + except Exception as ex: + self.log.error('An error occurred while applying selected part.', exception=ex) + return BodyTypeFlag.NONE, None + + def _get_cas_parts(self, source_sim_info: SimInfo, modified_sim_info: SimInfo, original_unmodified_sim_info: SimInfo, random_seed: int) -> Tuple[CommonCASPart]: + """_get_cas_parts(source_sim_info, modified_sim_info, original_unmodified_sim_info, random_seed) + + Retrieve a collection of CAS Parts being applied to the Sim. + + :param source_sim_info: The Sim the parts are being applied to. (This Sim is replaced with "modified_sim_info" after the first appearance modifier modification) + :type source_sim_info: SimInfo + :param modified_sim_info: A cloned instance of "source_sim_info" that the parts are applied to. (The value of this property replaces "source_sim_info" after the first appearance modifier modification) + :type modified_sim_info: SimInfo + :param original_unmodified_sim_info: The original unmodified Sim, from before any modifications were made to them. This value will never be replaced and keeps the original information about the Sim, especially their Sim Id. + :type original_unmodified_sim_info: SimInfo + :param random_seed: The seed used to assign the appearance modifier. + :type random_seed: int + :return: A collection of CAS Parts that will be applied to the Sim. + :rtype: Tuple[CommonCASPart] + """ + raise NotImplementedError() + + # noinspection PyUnusedLocal + def _apply_cas_parts(self, cas_parts: Tuple[CommonCASPart], source_sim_info: SimInfo, modified_sim_info: SimInfo, original_unmodified_sim_info: SimInfo, random_seed: int) -> Tuple[Union[CommonBodySlot, BodyType, int]]: + if not cas_parts: + self.log.format_with_message('No CAS Parts were found to apply.', sim=original_unmodified_sim_info) + return tuple() + + self.log.format_with_message('Applying CAS Parts with ids', sim=original_unmodified_sim_info, cas_part_ids_and_body_types=cas_parts) + + from sims4communitylib.utils.cas.common_cas_utils import CommonCASUtils + CommonCASUtils.attach_cas_parts_to_all_outfits_of_sim(modified_sim_info, cas_parts) + + body_types: Tuple[Union[CommonBodySlot, BodyType, int], ...] = tuple([cas_part.body_type for cas_part in cas_parts]) + return body_types + + @property + def modifier_type(self) -> CommonAppearanceModifierType: + """The type of modifier being applied.""" + return CommonAppearanceModifierType.CUSTOM + + @property + def is_permanent_modification(self) -> bool: + """Whether the modification is permanent or not.""" + return False + + @property + def combinable_sorting_key(self) -> str: + """A key used to combine this appearance modifiers with other appearance modifiers.""" + return self.__class__.__name__ + + # noinspection PyUnusedLocal + def is_compatible_with_outfit(self, outfit_category: OutfitCategory) -> bool: + """is_compatible_with_outfit(outfit_category) + + Whether or not the appearance modifier is compatible with the specified outfit category. + + .. note:: If the appearance modifier is not compatible, then the buff that applies it will be removed. + + :param outfit_category: The outfit category being checked. + :type outfit_category: OutfitCategory + :return: True, if the appearance modifier is compatible with the specified outfit category. False, if not. + :rtype: bool + """ + return True + + def __repr__(self) -> str: + return self.__class__.__name__ + + +if not ON_RTD: + @CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_testing.toggle_example_appearance_modifier_buff', + 'Apply an example S4CL buff that will make the feet of the Sims with it bare.', + command_arguments=( + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of a Sim to attach the buff to.', is_optional=True, default_value='Active Sim'), + ) + ) + def _s4cl_testing_apply_example_bare_feet_buff(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): + if sim_info is None: + return False + output(f'Toggling bare feet example buff on Sim {sim_info}.') + from sims4communitylib.utils.sims.common_buff_utils import CommonBuffUtils + if CommonBuffUtils.has_buff(sim_info, CommonBuffId.S4CL_EXAMPLE_APPLY_BARE_FEET): + output(f'Removing bare feet example buff from Sim {sim_info}') + CommonBuffUtils.remove_buff(sim_info, CommonBuffId.S4CL_EXAMPLE_APPLY_BARE_FEET) + else: + output(f'Adding bare feet example buff on Sim {sim_info}') + CommonBuffUtils.add_buff(sim_info, CommonBuffId.S4CL_EXAMPLE_APPLY_BARE_FEET) + output(f'Done toggling bare feet example buff on Sim {sim_info}') diff --git a/Scripts/s4ap/sims4communitylib/classes/buffs/__init__.py b/Scripts/s4ap/sims4communitylib/classes/buffs/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/buffs/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/classes/buffs/common_buff.py b/Scripts/s4ap/sims4communitylib/classes/buffs/common_buff.py new file mode 100644 index 0000000..a462016 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/buffs/common_buff.py @@ -0,0 +1,99 @@ +""" +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 +""" +from typing import Union +from buffs.buff import Buff +from sims.sim import Sim +from sims4communitylib.logging.has_class_log import HasClassLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + + +class CommonBuff(Buff, HasClassLog): + """CommonBuff(...) + + An inheritable class that provides a way to create Custom Buffs. + + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 'common_buff' + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + raise NotImplementedError('Missing \'{}\'.'.format(cls.get_mod_identity.__name__)) + + @property + def sim(self) -> Union[Sim, None]: + """Retrieve the Sim that owns the Buff. + + :return: An instance of the Sim that owns the Buff + :rtype: Sim + """ + return CommonSimUtils.get_sim_instance(self._owner) + + # noinspection PyMissingOrEmptyDocstring + def on_add(self, from_load: bool=False, apply_buff_loot: bool=True): + """on_add(from_load=False, apply_buff_loot=True) + + A function that occurs upon a Buff being added to a Sim. + + :param from_load: True, if the Buff is being added from a load. Default is False. + :type from_load: bool, optional + :param apply_buff_loot: If True, Loot will be applied when the Buff is added. Default is True. + :type apply_buff_loot: bool, optional + """ + super().on_add(from_load=from_load, apply_buff_loot=apply_buff_loot) + try: + self.on_added(self.sim, from_load=from_load, apply_buff_loot=apply_buff_loot) + except Exception as ex: + self.log.error('Error occurred while running buff \'{}\' on_added.'.format(self.__class__.__name__), exception=ex) + + def on_remove(self, apply_loot_on_remove: bool=True): + """on_remove(apply_loot_on_remove=True) + + A function that occurs upon a Buff being removed from a Sim. + + :param apply_loot_on_remove: If True, Loot will be applied after the Buff is removed. If False, it won't. Default is True. + :type apply_loot_on_remove: bool, optional + """ + super().on_remove(apply_loot_on_remove=apply_loot_on_remove) + try: + self.on_removed(self.sim, apply_loot_on_remove=apply_loot_on_remove) + except Exception as ex: + self.log.error('Error occurred while running buff \'{}\' on_removed.'.format(self.__class__.__name__), exception=ex) + + # The following functions are hooks into various parts of a buff, override them in your own buff to provide custom functionality. + + def on_added(self, owner: Sim, from_load: bool=False, apply_buff_loot: bool=True): + """on_added(owner, from_load=False, apply_buff_loot=True) + + A hook that occurs upon the Buff being added to the Sim. + + :param owner: The Sim that owns the Buff. + :type owner: Sim + :param from_load: True, if the Buff was added from a load. Default is False. + :type from_load: bool, optional + :param apply_buff_loot: If True, Loot was applied when the Buff was added. Default is True. + :type apply_buff_loot: bool, optional + """ + pass + + def on_removed(self, owner: Sim, apply_loot_on_remove: bool=True): + """on_removed(owner, apply_loot_on_remove=True) + + A hook that occurs upon the Buff being removed from the Sim. + + :param owner: The Sim that owns the Buff. + :type owner: Sim + :param apply_loot_on_remove: If True, Loot will be applied after the Buff is removed. If False, it won't. Default is True. + :type apply_loot_on_remove: bool, optional + """ + pass diff --git a/Scripts/s4ap/sims4communitylib/classes/calculations/__init__.py b/Scripts/s4ap/sims4communitylib/classes/calculations/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/calculations/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/classes/calculations/common_available_for_sim.py b/Scripts/s4ap/sims4communitylib/classes/calculations/common_available_for_sim.py new file mode 100644 index 0000000..949829b --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/calculations/common_available_for_sim.py @@ -0,0 +1,174 @@ +""" +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 +""" +from pprint import pformat +from typing import Tuple, Iterator + +from sims.sim_info import SimInfo +from sims4communitylib.enums.common_age import CommonAge +from sims4communitylib.enums.common_gender import CommonGender +from sims4communitylib.enums.common_occult_type import CommonOccultType +from sims4communitylib.enums.common_species import CommonSpecies + + +class CommonAvailableForSim: + """CommonAvailableForSim(\ + genders=(),\ + ages=(),\ + species=(),\ + occult_types=()\ + ) + + Holds information for what types of Sims this is available for. + + .. note:: At least one argument must be supplied with values. + + :param genders: An iterator of CommonGender. Default is an empty collection. + :type genders: Iterator[CommonGender], optional + :param ages: An iterator of CommonAge. Default is an empty collection. + :type ages: Iterator[CommonAge], optional + :param species: An iterator of CommonSpecies. Default is an empty collection. + :type species: Iterator[CommonSpecies], optional + :param occult_types: An iterator of CommonOccultType. Default is an empty collection. + :type occult_types: Iterator[CommonOccultType], optional + """ + def __init__( + self, + genders: Iterator[CommonGender]=(), + ages: Iterator[CommonAge]=(), + species: Iterator[CommonSpecies]=(), + occult_types: Iterator[CommonOccultType]=() + ): + self._genders = tuple(genders) + self._ages = tuple(ages) + self._species = tuple(species) + self._occult_types = tuple(occult_types) + if not self._genders and not self._ages and not self._species and not self._occult_types: + raise AssertionError('No Genders, Ages, Species, nor Occult Types were specified!') + + @property + def genders(self) -> Tuple[CommonGender]: + """Genders this is available for.""" + return self._genders + + @property + def ages(self) -> Tuple[CommonAge]: + """Ages this is available for.""" + return self._ages + + @property + def species(self) -> Tuple[CommonSpecies]: + """Species this is available for.""" + return self._species + + @property + def occult_types(self) -> Tuple[CommonOccultType]: + """Occult Types this is available for.""" + return self._occult_types + + def is_available_for(self, sim_info: SimInfo) -> bool: + """is_available_for(sim_info) + + Determine if available for a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: True, if is available for the specified Sim. False, if not. + :rtype: bool + """ + age = CommonAge.get_age(sim_info) + if self.ages and age not in self.ages: + return False + gender = CommonGender.get_gender(sim_info) + if self.genders and gender not in self.genders: + return False + common_species = CommonSpecies.get_species(sim_info) + if self.species and common_species not in self.species: + return False + common_occult_type = CommonOccultType.determine_occult_type(sim_info) + if self.occult_types and common_occult_type not in self.occult_types: + return False + return True + + def is_valid(self) -> Tuple[bool, str]: + """is_valid() + + Determine if the Available For is valid. + + :return: If the Available For is valid, the return will be True and a Success message. If the Available For is not valid, the return will be False and an error message. + :rtype: Tuple[bool, str] + """ + if len(self.genders) == 0 and len(self.ages) == 0 and len(self.species) == 0 and len(self.occult_types) == 0: + return False, 'No Genders, Ages, Species, nor Occult Types were specified!' + return True, 'Success' + + def clone(self) -> 'CommonAvailableForSim': + """Clone the available for.""" + return CommonAvailableForSim( + genders=tuple(self.genders), + ages=tuple(self.ages), + species=tuple(self.species), + occult_types=tuple(self.occult_types) + ) + + @staticmethod + def generate_for_sim(sim_info: SimInfo) -> 'CommonAvailableForSim': + """generate_for_sim(sim_info) + + Generate an available for, for a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: An available for matching the specified Sim. + :rtype: CommonAvailableForSim + """ + from sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils + gender = CommonGender.get_gender(sim_info) + if gender == CommonGender.INVALID: + genders = tuple() + else: + genders = (gender,) + age = CommonAge.get_age(sim_info) + if age == CommonAge.INVALID: + ages = tuple() + elif CommonAgeUtils.is_teen_adult_or_elder_age(age): + ages = (CommonAge.TEEN, CommonAge.YOUNGADULT, CommonAge.ADULT, CommonAge.ELDER) + else: + ages = (age,) + sim_species = CommonSpecies.get_species(sim_info) + if sim_species == CommonSpecies.INVALID: + species = tuple() + else: + species = (sim_species,) + occult_type = CommonOccultType.determine_occult_type(sim_info) + if occult_type == CommonOccultType.NON_OCCULT: + occult_types = (occult_type,) + else: + occult_types = (CommonOccultType.NON_OCCULT, occult_type) + return CommonAvailableForSim( + genders=genders, + ages=ages, + species=species, + occult_types=occult_types + ) + + @staticmethod + def everything() -> 'CommonAvailableForSim': + """ Create an Available For instance that applies to everything. """ + return CommonAvailableForSim( + genders=CommonGender.get_all(), + ages=CommonAge.get_all(), + species=CommonSpecies.get_all(), + occult_types=CommonOccultType.get_all() + ) + + def __repr__(self) -> str: + return ''\ + .format(pformat(self.genders), pformat(self.ages), pformat(self.species), pformat(self.occult_types)) + + def __str__(self) -> str: + return self.__repr__() diff --git a/Scripts/s4ap/sims4communitylib/classes/commodities/__init__.py b/Scripts/s4ap/sims4communitylib/classes/commodities/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/commodities/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/classes/commodities/common_commodity.py b/Scripts/s4ap/sims4communitylib/classes/commodities/common_commodity.py new file mode 100644 index 0000000..7c013c4 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/commodities/common_commodity.py @@ -0,0 +1,28 @@ +""" +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 +""" +from sims4communitylib.logging.has_class_log import HasClassLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from statistics.commodity import Commodity + + +class CommonCommodity(Commodity, HasClassLog): + """CommonCommodity() + + A commodity override with additional functionality. + + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + raise NotImplementedError() + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + raise NotImplementedError() diff --git a/Scripts/s4ap/sims4communitylib/classes/common_resource_key.py b/Scripts/s4ap/sims4communitylib/classes/common_resource_key.py new file mode 100644 index 0000000..e5abb81 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/common_resource_key.py @@ -0,0 +1,133 @@ +""" +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 +""" +import os +from typing import Union +from sims4communitylib.enums.enumtypes.common_int import CommonInt + +ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' + +if ON_RTD: + # noinspection PyMissingOrEmptyDocstring + class Types(CommonInt): + pass + + # noinspection PyMissingOrEmptyDocstring + class Groups(CommonInt): + pass + + # noinspection PyMissingOrEmptyDocstring + class Key: + # noinspection PyPropertyDefinition + @property + def type(self) -> str: + pass + + # noinspection PyPropertyDefinition + @property + def instance(self) -> str: + pass + + # noinspection PyPropertyDefinition + @property + def group(self) -> str: + pass + + # noinspection PyUnusedLocal + def __init__(self, res_type: int, res_instance: int, *args, **kwargs): + pass + +if not ON_RTD: + try: + # noinspection PyUnresolvedReferences + from _resourceman import Key + from sims4.resources import Types, Groups + except: + class Key: + pass + + class Types: + pass + + class Groups: + pass + + +class CommonResourceKey: + """CommonResourceKey(resource_key_type, resource_key_instance, resource_key_group) + + A wrapper for a resource key. + + :param resource_key_type: An identifier that indicates the tuning type of the resource. + :type resource_key_type: Union[int, str, Types] + :param resource_key_instance: An identifier that indicates what tuning instance the resource key is for. + :type resource_key_instance: Union[int, str] + :param resource_key_group: An identifier that indicates what tuning group the resource key is for. In most cases a group of "0" is sufficient. + :type resource_key_group: Union[int, str, Group] + """ + + @property + def type(self) -> Union[int, str, Types]: + """ The type identifier of the resource. """ + return self._resource_key_type + + @property + def instance(self) -> Union[int, str]: + """ The instance identifier of the resource. """ + return self._resource_key_instance + + @property + def group(self) -> Union[int, str, Groups]: + """ The group identifier of the resource. """ + return self._resource_key_group + + def __init__(self, resource_key_type: Union[int, str, Types], resource_key_instance: Union[int, str], resource_key_group: Union[int, str, Groups]): + self._resource_key_type = resource_key_type + self._resource_key_instance = resource_key_instance + self._resource_key_group = resource_key_group + + def __new__(cls, resource_key_type: Union[int, str, Types], resource_key_instance: Union[int, str], resource_key_group: Union[int, str, Groups]) -> 'CommonResourceKey': + # noinspection PyTypeChecker + return Key(resource_key_type, resource_key_instance, resource_key_group) + + @staticmethod + def empty() -> 'CommonResourceKey': + """empty() + + Create an empty resource key. + + :return: An empty resource key. + :rtype: CommonResourceKey + """ + return CommonResourceKey(0, 0, 0) + + @staticmethod + def from_resource_key(resource_key: Union[Key, 'CommonResourceKey']) -> Union['CommonResourceKey', None]: + """from_resource_key(resource_key) + + Convert a vanilla Key object into a CommonResourceKey. + + :param resource_key: An instance of a Resource Key. + :type resource_key: Union[Key, CommonResourceKey] + :return: An instance of a CommonResourceKey or None if the object failed to convert. + :rtype: Union[CommonResourceKey, None] + """ + if resource_key is None: + return None + if isinstance(resource_key, CommonResourceKey): + return resource_key + if not isinstance(resource_key, Key): + raise Exception('Failed to convert {} with type {}, it was not of type {}.'.format(resource_key, type(resource_key), type(Key))) + return CommonResourceKey(resource_key.type, resource_key.instance, resource_key.group) + + def __repr__(self) -> str: + if not self.group or self.group == 0: + return '{}!{}'.format(self.type, self.instance) + return '{}!{}!{}'.format(self.type, self.instance, self.group) + + def __str__(self) -> str: + return self.__repr__() diff --git a/Scripts/s4ap/sims4communitylib/classes/effects/__init__.py b/Scripts/s4ap/sims4communitylib/classes/effects/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/effects/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/classes/effects/common_visual_effect.py b/Scripts/s4ap/sims4communitylib/classes/effects/common_visual_effect.py new file mode 100644 index 0000000..780a72c --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/effects/common_visual_effect.py @@ -0,0 +1,217 @@ +""" +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 +""" +from typing import Callable, Union + +import alarms +from date_and_time import TimeSpan +from sims.sim import Sim +from sims4communitylib.logging.has_log import HasLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from vfx import PlayEffect +from objects.game_object import GameObject + + +class CommonVisualEffect(HasLog): + """CommonVisualEffect(\ + mod_identity,\ + target,\ + effect_name,\ + joint_bone_name='b__Root__',\ + target_actor_id=0,\ + target_joint_bone_name=None,\ + **kwargs\ + ) + + A visual effect that will play while attached to an object or Sim. + + :param mod_identity: The identity of the mod that owns this visual effect. + :type mod_identity: CommonModIdentity + :param source: An instance of an object or Sim. They will be the source of the effect. + :type source: Union[GameObject, Sim] + :param effect_name: The name of the effect to play. + :type effect_name: str + :param joint_bone_name: The name of the joint to play the effect attached to. Default is the root bone 'b__Root__'. + :type joint_bone_name: str, optional + :param target_actor_id: The id of the target actor. Default will be the id of the target. + :type target_actor_id: int, optional + :param target_joint_bone_name: The name of the joint to play the effect attached to on the target. Default is the value of joint_bone_name. + :type target_joint_bone_name: str, optional + """ + + # noinspection PyMissingOrEmptyDocstring + @property + def mod_identity(self) -> CommonModIdentity: + return self._mod_identity + + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + return 'common_game_object_effect' + + def __init__( + self, + mod_identity: CommonModIdentity, + source: Union[GameObject, Sim], + effect_name: str, + joint_bone_name: str = 'b__Root__', + target_actor_id: int = 0, + target_joint_bone_name: str = None, + **kwargs + ): + from sims4.hash_util import hash32 + super().__init__() + self._source = source + self._mod_identity = mod_identity + self._effect_name = effect_name + self._joint_bone_name = joint_bone_name + self._target_actor_id = target_actor_id + self._target_joint_bone_name = target_joint_bone_name + if joint_bone_name is None: + joint_bone_hash = 0 + else: + joint_bone_hash = hash32(joint_bone_name) + if target_joint_bone_name is None: + target_joint_bone_hash = 0 + else: + target_joint_bone_hash = hash32(target_joint_bone_name) + self._effect_instance = PlayEffect( + source, + effect_name=effect_name, + joint_name=joint_bone_hash, + target_actor_id=target_actor_id, + target_joint_name_hash=target_joint_bone_hash, + **kwargs + ) + self._alarm_handle = None + + def start(self, time_span: TimeSpan = None, on_end: Callable[['CommonVisualEffect'], None] = None) -> bool: + """start(time_span=None, on_end=None) + + Start the effect. + + :param time_span: A span of time indicating how long to run the effect for. Default is however long the vfx itself runs. + :type time_span: TimeSpan, optional + :param on_end: A callback invoked when the effect ends. This is only used when sim_minutes_until_end is specified. Default is None. + :type on_end: Callable[['CommonVisualEffect'], None], optional + :return: True, if the effect was started successfully. False, if not. + :rtype: bool + """ + try: + self.log.format_with_message('Running effect.', source=self._source, effect_name=self._effect_name, time_span=time_span) + self._effect_instance.start() + if time_span is not None: + self._create_stop_alarm(time_span, on_end=on_end) + return True + except Exception as ex: + self.log.format_error_with_message( + 'Error occurred while trying to start visual effect.', + effect_instance=self._effect_instance, + source=self._source, + effect_name=self._effect_name, + joint_bone_name=self._joint_bone_name, + target_actor_id=self._target_actor_id, + target_joint_bone_name=self._target_joint_bone_name, + exception=ex + ) + return False + + def start_run_once(self, time_span: TimeSpan = None, on_end: Callable[['CommonVisualEffect'], None] = None) -> bool: + """start_run_once(time_span=None, on_end=None) + + Start the effect and have it run only once. + + :param time_span: A span of time indicating how long to run the effect for. Default is however long the vfx itself runs. + :type time_span: TimeSpan, optional + :param on_end: A callback invoked when the effect ends. This is only used when sim_minutes_until_end is specified. Default is None. + :type on_end: Callable[['CommonVisualEffect'], None], optional + :return: True, if the effect was started successfully. False, if not. + :rtype: bool + """ + try: + self.log.format_with_message('Running effect once.', source=self._source, effect_name=self._effect_name, time_span=time_span) + self._effect_instance.start_one_shot() + if time_span is not None: + self._create_stop_alarm(time_span, on_end=on_end) + return True + except Exception as ex: + self.log.format_error_with_message( + 'Error occurred while trying to start visual effect via one shot.', + effect_instance=self._effect_instance, + source=self._source, + effect_name=self._effect_name, + joint_bone_name=self._joint_bone_name, + target_actor_id=self._target_actor_id, + target_joint_bone_name=self._target_joint_bone_name, + exception=ex + ) + return False + + def _create_stop_alarm(self, time_span: TimeSpan, on_end: Callable[['CommonVisualEffect'], None] = None) -> None: + def _on_end(_) -> None: + if on_end is not None: + on_end(self) + self.stop() + + self._alarm_handle = alarms.add_alarm(self, time_span, _on_end, repeating=False, use_sleep_time=False) + + def _destroy_stop_alarm(self) -> None: + if self._alarm_handle is not None: + alarms.cancel_alarm(self._alarm_handle) + self._alarm_handle = None + + def stop(self) -> bool: + """stop() + + Stop the effect. + + :return: True, if the effect was stopped successfully. False, if not. + :rtype: bool + """ + try: + self.log.format_with_message('Stopping effect.', source=self._source, effect_name=self._effect_name) + self._destroy_stop_alarm() + self._effect_instance.stop() + return True + except Exception as ex: + self.log.format_error_with_message( + 'Error occurred while trying to stop visual effect.', + effect_instance=self._effect_instance, + source=self._source, + effect_name=self._effect_name, + joint_bone_name=self._joint_bone_name, + target_actor_id=self._target_actor_id, + target_joint_bone_name=self._target_joint_bone_name, + exception=ex + ) + return False + + def stop_immediate(self) -> bool: + """stop_immediate() + + Kill the effect. + + :return: True, if the effect was stopped successfully. False, if not. + :rtype: bool + """ + try: + self.log.format_with_message('Stopping effect immediate.', source=self._source, effect_name=self._effect_name) + self._destroy_stop_alarm() + self._effect_instance.stop(immediate=True) + return True + except Exception as ex: + self.log.format_error_with_message( + 'Error occurred while trying to stop visual effect immediately.', + effect_instance=self._effect_instance, + source=self._source, + effect_name=self._effect_name, + joint_bone_name=self._joint_bone_name, + target_actor_id=self._target_actor_id, + target_joint_bone_name=self._target_joint_bone_name, + exception=ex + ) + return False diff --git a/Scripts/s4ap/sims4communitylib/classes/enums/__init__.py b/Scripts/s4ap/sims4communitylib/classes/enums/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/enums/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/classes/enums/common_versioned_enum_value_collection.py b/Scripts/s4ap/sims4communitylib/classes/enums/common_versioned_enum_value_collection.py new file mode 100644 index 0000000..6e69a1b --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/enums/common_versioned_enum_value_collection.py @@ -0,0 +1,81 @@ +""" +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 +""" +from typing import Tuple, Union, Dict, Any, Iterator, TypeVar, Generic, Type + +from sims4communitylib.enums.enumtypes.common_versioned_int import CommonVersionedInt +from sims4communitylib.enums.enumtypes.common_versioned_int_flags import CommonVersionedIntFlags +from sims4communitylib.classes.serialization.common_serializable import CommonSerializable +from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + +CommonEnumType = TypeVar('CommonEnumType', CommonVersionedIntFlags, CommonVersionedInt) + +CommonVersionedEnumValueCollectionType = TypeVar('CommonVersionedEnumValueCollectionType', bound="CommonVersionedEnumValueCollection") + + +class CommonVersionedEnumValueCollection(CommonSerializable, Generic[CommonEnumType]): + """CommonVersionedEnumValueCollection(\ + enum_values,\ + version=None\ + ) + + A collection of enum values with a version. + + :param enum_values: A collection of enum values. + :type enum_values: Iterator[CommonEnumType] + :param version: The version of the data. Default is the version of the enum. + :type version: str, optional + """ + + def __init__(self: CommonVersionedEnumValueCollectionType, enum_values: Iterator[CommonEnumType], version: str = None): + self._enum_values = tuple(enum_values) + self._version = version or self.get_enum_type().get_version() + + @property + def enum_values(self: CommonVersionedEnumValueCollectionType) -> Tuple[CommonEnumType]: + """A collection of enum values.""" + # noinspection PyTypeChecker + return self._enum_values + + @property + def version(self: CommonVersionedEnumValueCollectionType) -> str: + """The version of the enum values.""" + return self._version + + @classmethod + def get_enum_type(cls: Type[CommonVersionedEnumValueCollectionType]) -> Type[CommonEnumType]: + """The type of enum.""" + raise NotImplementedError() + + # noinspection PyMissingOrEmptyDocstring + def serialize(self: CommonVersionedEnumValueCollectionType) -> Union[str, Dict[str, Any]]: + data = dict() + data['enum_values'] = [enum_value.name for enum_value in self.enum_values] + data['version'] = self.version + return data + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def deserialize(cls: Type[CommonVersionedEnumValueCollectionType], data: Union[str, Dict[str, Any]]) -> Union[CommonVersionedEnumValueCollectionType, None]: + if not hasattr(data, 'get'): + return None + enum_value_names = data.get('enum_values', None) + if enum_value_names is None: + return None + + enum_values = list() + for enum_value_name in enum_value_names: + enum_value = CommonResourceUtils.get_enum_by_name(enum_value_name, cls.get_enum_type(), default_value=None) + if enum_value is None: + continue + enum_value = cls.get_enum_type().convert_obsolete_value(enum_value) + enum_values.append(enum_value) + + version = data.get('version', None) + if version is None or version != cls.get_enum_type().get_version(): + return None + return cls(enum_values, version=version) diff --git a/Scripts/s4ap/sims4communitylib/classes/enums/common_versioned_sim_demographic_type_collection.py b/Scripts/s4ap/sims4communitylib/classes/enums/common_versioned_sim_demographic_type_collection.py new file mode 100644 index 0000000..d3bbcf3 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/enums/common_versioned_sim_demographic_type_collection.py @@ -0,0 +1,39 @@ +""" +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 +""" +from typing import Tuple, Type, Iterator + +from sims4communitylib.classes.enums.common_versioned_enum_value_collection import CommonVersionedEnumValueCollection +from sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType + + +class CommonVersionedSimDemographicTypeCollection(CommonVersionedEnumValueCollection[CommonSimDemographicType]): + """CommonVersionedSimDemographicTypeCollection(\ + demographic_types,\ + version=None\ + ) + + A collection of demographic types with a version. + + :param demographic_types: A collection of demographic types. + :type demographic_types: Iterator[CommonSimDemographicType] + :param version: The version of the data. Default is the version of CommonSimDemographicType. + :type version: str, optional + """ + + def __init__(self, demographic_types: Iterator[CommonSimDemographicType], version: str = None): + super().__init__(demographic_types, version=version) + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_enum_type(cls) -> Type[CommonSimDemographicType]: + return CommonSimDemographicType + + @property + def demographic_types(self) -> Tuple[CommonSimDemographicType]: + """Types of demographics.""" + return self.enum_values diff --git a/Scripts/s4ap/sims4communitylib/classes/filters/__init__.py b/Scripts/s4ap/sims4communitylib/classes/filters/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/filters/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/classes/filters/common_match_all_non_sims_object_filter.py b/Scripts/s4ap/sims4communitylib/classes/filters/common_match_all_non_sims_object_filter.py new file mode 100644 index 0000000..16504f5 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/filters/common_match_all_non_sims_object_filter.py @@ -0,0 +1,19 @@ +""" +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 +""" +from objects.proxy import ProxyObject +from objects.script_object import ScriptObject +from sims4communitylib.classes.filters.common_match_object_filter import CommonMatchObjectFilterBase +from sims4communitylib.utils.common_type_utils import CommonTypeUtils + + +class CommonMatchAllNonSimsObjectFilter(CommonMatchObjectFilterBase): + """An object filter that will match on all non-Sim objects.""" + + # noinspection PyMissingOrEmptyDocstring + def matches(self, obj: ScriptObject) -> bool: + return not CommonTypeUtils.is_sim_or_sim_info(obj) and CommonTypeUtils.is_game_object(obj) and not isinstance(obj, ProxyObject) diff --git a/Scripts/s4ap/sims4communitylib/classes/filters/common_match_all_sims_object_filter.py b/Scripts/s4ap/sims4communitylib/classes/filters/common_match_all_sims_object_filter.py new file mode 100644 index 0000000..224bc92 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/filters/common_match_all_sims_object_filter.py @@ -0,0 +1,16 @@ +""" +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 +""" +from sims4communitylib.classes.filters.common_match_object_filter import CommonMatchObjectFilterBase +from sims4communitylib.utils.common_type_utils import CommonTypeUtils + + +class CommonMatchAllSimsObjectFilter(CommonMatchObjectFilterBase): + """A filter that will match on all Sims.""" + # noinspection PyMissingOrEmptyDocstring + def matches(self, obj) -> bool: + return CommonTypeUtils.is_sim_or_sim_info(obj) diff --git a/Scripts/s4ap/sims4communitylib/classes/filters/common_match_object_filter.py b/Scripts/s4ap/sims4communitylib/classes/filters/common_match_object_filter.py new file mode 100644 index 0000000..037558b --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/filters/common_match_object_filter.py @@ -0,0 +1,36 @@ +""" +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 +""" +from interactions.utils.object_definition_or_tags import TunableObjectFilter +from objects.script_object import ScriptObject +from sims4communitylib.enums.common_object_filter_type import CommonObjectFilterType + + +class CommonMatchObjectFilterBase(TunableObjectFilter): + """A filter that will match on objects.""" + + def get_filter_type(self) -> CommonObjectFilterType: + """Indicates the type of filter.""" + return CommonObjectFilterType.CUSTOM + + def _intersect_dissimilar(self, other) -> TunableObjectFilter: + return self + + def _intersect_similar(self, other) -> TunableObjectFilter: + return self + + def matches(self, obj: ScriptObject) -> bool: + """matches(obj) + + Whether or not the specified object matches this filter. + + :param obj: An instance of an object. + :type obj: ScriptObject + :return: True, if the object matches the filter. False, if not. + :rtype: bool + """ + raise NotImplementedError() diff --git a/Scripts/s4ap/sims4communitylib/classes/interactions/__init__.py b/Scripts/s4ap/sims4communitylib/classes/interactions/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/interactions/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/classes/interactions/_common_interaction_custom_mixin.py b/Scripts/s4ap/sims4communitylib/classes/interactions/_common_interaction_custom_mixin.py new file mode 100644 index 0000000..10f4edd --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/interactions/_common_interaction_custom_mixin.py @@ -0,0 +1,81 @@ +""" +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 +""" +from typing import Union, Any, Iterator, Tuple, List, Set + +from interactions.base.interaction import Interaction +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils + + +class _CommonInteractionCustomMixin: + """Custom functionality for interactions.""" + + @classmethod + def create_test_result( + cls, + result: bool, + reason: str=None, + text_tokens: Union[Tuple[Any], List[Any], Set[Any]]=(), + tooltip: Union[int, str, CommonLocalizationUtils.LocalizedTooltip]=None, + tooltip_tokens: Iterator[Any]=(), + icon=None, + influence_by_active_mood: bool=False + ) -> CommonTestResult: + """create_test_result(\ + result,\ + reason=None,\ + text_tokens=(),\ + tooltip=None,\ + tooltip_tokens=(),\ + icon=None,\ + influence_by_active_mood=False\ + ) + + Create a CommonTestResult with the specified information. + + .. note:: CommonTestResult 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 tooltip_tokens: A collection of objects to format into the localized tooltip. (They can be anything. LocalizedString, str, int, SimInfo, just to name a few) Default is an empty collection. + :type tooltip_tokens: Iterator[Any], optional + :param icon: The icon of the outcome. + :type icon: CommonResourceKey, 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`. + :rtype: CommonTestResult + """ + return CommonTestResult( + result, + reason=reason.format(*text_tokens) if reason is not None else reason, + tooltip_text=tooltip, + tooltip_tokens=tooltip_tokens, + icon=icon, + influenced_by_active_mood=influence_by_active_mood + ) + + def set_current_progress_bar(self: Interaction, 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 + """ + self._send_progress_bar_update_msg(percent, rate_change, start_msg=start_message) diff --git a/Scripts/s4ap/sims4communitylib/classes/interactions/_common_interaction_hooks_mixin.py b/Scripts/s4ap/sims4communitylib/classes/interactions/_common_interaction_hooks_mixin.py new file mode 100644 index 0000000..09e4006 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/interactions/_common_interaction_hooks_mixin.py @@ -0,0 +1,325 @@ +""" +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 +""" +from typing import Union, Any, Iterator, Tuple + +from interactions import ParticipantType +from interactions.base.interaction import Interaction +from interactions.constraints import Constraint +from interactions.context import InteractionContext +from interactions.interaction_finisher import FinishingType +from native.animation import NativeAsm +from postures.posture_state import PostureState +from protocolbuffers.Localization_pb2 import LocalizedString +from scheduling import Timeline +from sims.sim import Sim +from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from singletons import DEFAULT + + +class _CommonInteractionHooksMixin: + """Hooks that are called from the various custom interactions.""" + + # The following functions are hooks into various parts of an interaction override them in your own interaction to provide custom functionality. + + # noinspection PyUnusedLocal + @classmethod + def on_replacement_constraints_gen(cls, inst_or_cls: 'Interaction', sim: Sim, target: Any) -> Union[Iterator[Constraint], None]: + """on_replacement_constraints_gen(inst_or_cls, sim, target) + + A hook that occurs before the normal constraints of an interaction, these constraints will replace the normal constraints of the interaction. + + .. note:: If None is returned, the normal constraints will be used. (Plus any additional constraints from on_constraint_gen) + + :param inst_or_cls: An instance or the class of the interaction. + :type inst_or_cls: Interaction + :param sim: The source Sim of the interaction. + :type sim: Sim + :param target: The target Object of the interaction. + :type target: Any + :return: An iterator of constraints to replace the normal constraints of the interaction or None if replacement constraints are not wanted. + :rtype: Union[Iterator[Constraint], None] + """ + return None + + # noinspection PyUnusedLocal + @classmethod + def on_constraint_gen(cls, inst_or_cls: 'Interaction', sim: Sim, target: Any) -> Union[Iterator[Constraint], Constraint, None]: + """on_constraint_gen(inst_or_cls, sim, target) + + A hook that occurs after generating the constraints of an interaction, this constraint will be returned in addition to the normal constraints of the interaction. + + .. note:: Return None from this function to exclude any custom constraints. + + :param inst_or_cls: An instance or the class of the interaction. + :type inst_or_cls: Interaction + :param sim: The source Sim of the interaction. + :type sim: Sim + :param target: The target Object of the interaction. + :type target: Any + :return: A constraint or an iterator of constraints to return in addition to the normal constraints or None if no additional constraints should be added. + :rtype: Union[Iterator[Constraint], Constraint, None] + """ + return None + + # noinspection PyUnusedLocal + @classmethod + def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, *args, **kwargs) -> CommonTestResult: + """on_test(interaction_sim, interaction_target, interaction_context, *args, **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: CommonTestResult + """ + return CommonTestResult.TRUE + + # noinspection PyUnusedLocal + @classmethod + def on_post_super_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, *args, **kwargs) -> CommonTestResult: + """on_post_super_test(interaction_sim, interaction_target, interaction_context, *args, **kwargs) + + A hook that occurs after the interaction being tested for availability by on_test and the super _test functions. + + .. note:: This will only run if both on_test and _test returns CommonTestResult.TRUE or similar. + + :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: CommonTestResult + """ + return CommonTestResult.TRUE + + # noinspection PyUnusedLocal + def on_started(self, interaction_sim: Sim, interaction_target: Any) -> CommonExecutionResult: + """on_started(interaction_sim, interaction_target) + + A hook that occurs upon the interaction being started. + + .. note:: If CommonExecutionResult.FALSE, CommonExecutionResult.NONE, or False is returned from here, then the interaction will be cancelled instead of starting. + + :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: The result of running the start function. True, if the interaction hook was executed successfully. False, if the interaction hook was not executed successfully. + :rtype: CommonExecutionResult + """ + return CommonExecutionResult.TRUE + + # noinspection PyUnusedLocal + def on_killed(self, interaction_sim: Sim, interaction_target: Any) -> None: + """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 + """ + pass + + def on_cancelled(self, interaction_sim: Sim, interaction_target: Any, finishing_type: FinishingType, cancel_reason_msg: str, *args, **kwargs) -> None: + """on_cancelled(interaction_sim, interaction_target, finishing_type, cancel_reason_msg, *args, **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 + + # noinspection PyUnusedLocal + @classmethod + def get_custom_replacement_participants(cls, participant_type: ParticipantType, sim: Union[Sim, None], target: Union[Sim, None], carry_target: Union[Any, None], interaction: 'Interaction'=None, **kwargs) -> Union[Tuple[Any], None]: + """get_custom_replacement_participants(participant_type, sim=None, target=None, carry_target=None, interaction=None, **kwargs) + + A hook used to replace the result of the get_participants function with custom participants. + + :param participant_type: The type of participant being searched for. + :type participant_type: ParticipantType + :param sim: The Source of the interaction. + :type sim: Union[Sim, None] + :param target: The Target of the interaction. + :type sim: Union[Sim, None] + :param carry_target: The target being carried while the interaction is being run. + :type carry_target: Union[Any, None] + :param interaction: An instance of the interaction, if get_participants was invoked using an instance or None if get_participants was invoked using the class. Default is None. + :type interaction: Interaction, optional + :return: A collection of custom participants to use as replacements for the normal result of get_participants. Return None to keep the original participants. Default return is None. + :rtype: Union[Tuple[Any], None] + """ + return None + + # noinspection PyUnusedLocal + @classmethod + def get_custom_participants(cls, participant_type: ParticipantType, sim: Union[Sim, None], target: Union[Sim, None], carry_target: Union[Any, None], interaction: 'Interaction'=None, **kwargs) -> Tuple[Any]: + """get_custom_participants(participant_type, sim=None, target=None, carry_target=None, interaction=None, **kwargs) + + A hook used to add custom participants to the result of the get_participants function. + + :param participant_type: The type of participant being searched for. + :type participant_type: ParticipantType + :param sim: The Source of the interaction. + :type sim: Union[Sim, None] + :param target: The Target of the interaction. + :type sim: Union[Sim, None] + :param carry_target: The target being carried while the interaction is being run. + :type carry_target: Union[Any, None] + :param interaction: An instance of the interaction, if get_participants was invoked using an instance or None if get_participants was invoked using the class. Default is None. + :type interaction: Interaction, optional + :return: A collection of custom participants to add to the normal result of get_participants. + :rtype: Tuple[Any] + """ + return tuple() + + 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 + + @classmethod + def _create_override_display_name( + cls, + interaction_sim: Sim, + interaction_target: Any, + interaction: 'Interaction'=None, + interaction_context: InteractionContext=None, + **interaction_parameters + ) -> Union[LocalizedString, None]: + """_create_override_display_name(\ + interaction_sim,\ + interaction_target,\ + interaction=None,\ + interaction_context=None,\ + **interaction_parameters\ + ) + + If overridden you may supply a custom name for the interaction to display. + + .. 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: The interaction being performed or None. + :type interaction: Interaction + :param interaction_context: The context of the interaction being performed or None. + :type interaction_context: InteractionContext + :param interaction_parameters: Parameters for the interaction. + :type interaction_parameters: Iterator[Any] + :return: The name to use in place of the original name of the interaction or None if you want the original name to be used. + :rtype: Union[LocalizedString, None] + """ + pass + + # 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 + + # noinspection PyUnusedLocal + def on_run(self, interaction_sim: Sim, interaction_target: Any, timeline: Timeline): + """on_run(interaction_sim, interaction_target, timeline) + + A hook that occurs upon the interaction being run. + + :param interaction_sim: The sim performing the interaction. + :type interaction_sim: Sim + :param interaction_target: The target of the interaction. + :type interaction_target: Any + :param timeline: The timeline the interaction is running on. + :type timeline: Timeline + """ + pass diff --git a/Scripts/s4ap/sims4communitylib/classes/interactions/common_immediate_super_interaction.py b/Scripts/s4ap/sims4communitylib/classes/interactions/common_immediate_super_interaction.py new file mode 100644 index 0000000..5966cb6 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/interactions/common_immediate_super_interaction.py @@ -0,0 +1,427 @@ +""" +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 +""" +import inspect +from typing import Union, Any, Set + +from event_testing.tests import TestList +from interactions import ParticipantType +from interactions.base.interaction import Interaction +from interactions.constraints import Constraint +from interactions.context import InteractionContext +from interactions.interaction_finisher import FinishingType +from native.animation import NativeAsm +from postures.posture_state import PostureState +from protocolbuffers.Localization_pb2 import LocalizedString +from scheduling import Timeline +from sims.sim import Sim +from sims4.utils import flexmethod +from sims4communitylib.classes.interactions._common_interaction_custom_mixin import _CommonInteractionCustomMixin +from sims4communitylib.classes.interactions._common_interaction_hooks_mixin import _CommonInteractionHooksMixin +from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult + +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.logging.has_class_log import HasClassLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from sims4communitylib.utils.misc.common_text_utils import CommonTextUtils +from singletons import DEFAULT +from interactions.base.immediate_interaction import ImmediateSuperInteraction + + +class CommonImmediateSuperInteraction(ImmediateSuperInteraction, HasClassLog, _CommonInteractionHooksMixin, _CommonInteractionCustomMixin): + """CommonImmediateSuperInteraction(*_, **__) + + An inheritable class that provides a way to create Custom Immediate Super Interactions. + + .. note:: + + The main use for this class is to create interactions that do something upon starting the interaction, without the Sim needing to queue the interaction. + One example would be the `Replace` interaction to replace objects that were destroyed in a fire. + + .. 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) -> Union[CommonModIdentity, None]: + return None + + def __init__(self, *_: Any, **__: Any): + super().__init__(*_, **__) + HasClassLog.__init__(self) + + @classmethod + def _test(cls, target: Any, context: InteractionContext, super_interaction: 'Interaction'=None, skip_safe_tests: bool=False, **kwargs) -> CommonTestResult: + from event_testing.results import TestResult + from sims4communitylib.classes.time.common_stop_watch import CommonStopWatch + log = cls.get_log() + verbose_log = cls.get_verbose_log() + stop_watch = CommonStopWatch() + if verbose_log.enabled: + stop_watch.start() + try: + try: + verbose_log.format_with_message( + 'Running on_test.', + class_name=cls.__name__, + interaction_sim=context.sim, + interaction_target=target, + interaction_context=context, + super_interaction=super_interaction, + skip_safe_tests=skip_safe_tests, + kwargles=kwargs + ) + test_result = cls.on_test(context.sim, target, context, super_interaction=super_interaction, skip_safe_tests=skip_safe_tests, **kwargs) + verbose_log.format_with_message('Test Result (CommonImmediateSuperInteraction)', test_result=test_result) + except Exception as ex: + log.error('Error occurred while running CommonImmediateSuperInteraction \'{}\' on_test.'.format(cls.__name__), exception=ex) + return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') + + if test_result is not None: + if isinstance(test_result, CommonTestResult): + if test_result.is_success is False: + return test_result + elif isinstance(test_result, TestResult) and 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, icon=test_result.icon, influence_by_active_mood=test_result.influence_by_active_mood) + + try: + verbose_log.format_with_message( + 'Running super()._test.', + class_name=cls.__name__, + interaction_sim=context.sim, + interaction_target=target, + interaction_context=context, + super_interaction=super_interaction, + skip_safe_tests=skip_safe_tests, + kwargles=kwargs + ) + super_test_result: TestResult = super()._test(target, context, super_interaction=super_interaction, skip_safe_tests=skip_safe_tests, **kwargs) + if verbose_log.enabled: + search_for_tooltip = context.source == context.SOURCE_PIE_MENU + resolver = cls.get_resolver(target=target, context=context, super_interaction=super_interaction, search_for_tooltip=search_for_tooltip, **kwargs) + global_result = cls.test_globals.run_tests(resolver, skip_safe_tests, search_for_tooltip=search_for_tooltip) + local_result = cls.tests.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=search_for_tooltip) + if cls._additional_tests: + additional_tests = TestList(cls._additional_tests) + additional_local_result = additional_tests.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=search_for_tooltip) + else: + additional_local_result = None + if cls.test_autonomous: + autonomous_result = cls.test_autonomous.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=False) + else: + autonomous_result = None + if target is not None: + tests = target.get_affordance_tests(cls) + if tests is not None: + target_result = tests.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=search_for_tooltip) + else: + target_result = None + else: + target_result = None + verbose_log.format_with_message('Super Test Result (CommonImmediateSuperInteraction)', super_test_result=super_test_result, global_result=global_result, local_result=local_result, additional_local_result=additional_local_result, autonomous_result=autonomous_result, target_result=target_result) + except Exception as ex: + log.error('Error occurred while running CommonImmediateSuperInteraction \'{}\' super()._test.'.format(cls.__name__), exception=ex) + return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') + + if super_test_result is not None and isinstance(test_result, TestResult) and not super_test_result.result: + return CommonTestResult.convert_from_vanilla(test_result) + + try: + verbose_log.format_with_message( + 'Running on_post_super_test.', + class_name=cls.__name__, + interaction_sim=context.sim, + interaction_target=target, + interaction_context=context, + super_interaction=super_interaction, + skip_safe_tests=skip_safe_tests, + kwargles=kwargs + ) + post_super_test_result = cls.on_post_super_test(context.sim, target, context, super_interaction=super_interaction, skip_safe_tests=skip_safe_tests, **kwargs) + verbose_log.format_with_message('Post Test Result (CommonImmediateSuperInteraction)', post_super_test_result=post_super_test_result) + except Exception as ex: + log.error('Error occurred while running CommonImmediateSuperInteraction \'{}\' on_post_super_test.'.format(cls.__name__), exception=ex) + return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') + + if post_super_test_result is not None: + if isinstance(post_super_test_result, CommonTestResult): + if post_super_test_result.is_success is False: + return post_super_test_result + elif isinstance(post_super_test_result, TestResult) and post_super_test_result.result is False: + if post_super_test_result.tooltip is not None: + post_super_test_result_tooltip = CommonLocalizationUtils.create_localized_tooltip(post_super_test_result.tooltip) + elif post_super_test_result.reason is not None: + post_super_test_result_tooltip = CommonLocalizationUtils.create_localized_tooltip(post_super_test_result.reason) + else: + post_super_test_result_tooltip = None + return cls.create_test_result(post_super_test_result.result, post_super_test_result.reason, tooltip=post_super_test_result_tooltip, icon=post_super_test_result.icon, influence_by_active_mood=post_super_test_result.influence_by_active_mood) + + return cls.create_test_result(True) + except Exception as ex: + log.error('Error occurred while running _test of CommonImmediateSuperInteraction \'{}\''.format(cls.__name__), exception=ex) + return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') + finally: + if verbose_log.enabled: + time_taken = CommonTextUtils.to_truncated_decimal(stop_watch.stop_milliseconds()) + verbose_log.format_with_message(f'Took {time_taken}ms to return result from CommonImmediateSuperInteraction.', class_name=cls.__name__) + else: + stop_watch.stop() + + # noinspection PyMissingOrEmptyDocstring,PyMethodParameters + @flexmethod + def get_participants(cls, inst, participant_type: ParticipantType, sim=DEFAULT, target=DEFAULT, carry_target=DEFAULT, **kwargs): + inst_or_cls = inst or cls + log = cls.get_log() + try: + custom_participants = cls.get_custom_replacement_participants(participant_type, sim, target, carry_target, interaction=inst, **kwargs) + if custom_participants is not None: + return tuple(custom_participants) + except Exception as ex: + log.error('Error occurred while running CommonImmediateSuperInteraction \'{}\' get_custom_replacement_participants.'.format(cls.__name__), exception=ex) + + result: Set[Any] = super(CommonImmediateSuperInteraction, inst_or_cls).get_participants(participant_type, sim=sim, target=target, carry_target=carry_target, **kwargs) + + result = set(result) + try: + custom_participants = cls.get_custom_participants(participant_type, sim, target, carry_target, interaction=inst, **kwargs) + result.update(custom_participants) + except Exception as ex: + log.error('Error occurred while running CommonImmediateSuperInteraction \'{}\' get_custom_participants.'.format(cls.__name__), exception=ex) + return tuple(result) + + # noinspection PyMethodParameters,PyMissingOrEmptyDocstring + @flexmethod + def get_name(cls, inst: 'CommonImmediateSuperInteraction', target: Any=DEFAULT, context: InteractionContext=DEFAULT, **interaction_parameters) -> LocalizedString: + inst_or_cls = inst or cls + try: + context_inst_or_cls = context or inst_or_cls + interaction_sim = context_inst_or_cls.sim + interaction_target = target or context_inst_or_cls.target + + cls.get_verbose_log().format_with_message( + 'Running get_name.', + class_name=cls.__name__, + interaction_sim=interaction_sim, + interaction_target=interaction_target, + interaction=inst, + interaction_context=context + ) + override_name = cls._create_override_display_name( + interaction_sim, + interaction_target, + interaction=inst, + interaction_context=context, + **interaction_parameters + ) + if override_name is not None: + return override_name + except Exception as ex: + cls.get_log().error('An error occurred while running get_name of CommonImmediateSuperInteraction {}'.format(cls.__name__), exception=ex) + result = super(CommonImmediateSuperInteraction, inst_or_cls).get_name(target=target, context=context, **interaction_parameters) + if result is None: + cls.get_log().error(f'Missing a name for interaction {cls.__name__}', throw=True) + return result + + def _trigger_interaction_start_event(self: 'CommonImmediateSuperInteraction'): + try: + self.verbose_log.format_with_message( + 'Running on_started.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target + ) + result = self.on_started(self.sim, self.target) + if result is not None and ((isinstance(result, CommonExecutionResult) and not result.is_success) or (isinstance(result, bool) and not result)): + self.cancel(FinishingType.CONDITIONAL_EXIT, str(result)) + return False + return super()._trigger_interaction_start_event() + except Exception as ex: + self.log.error('Error occurred while running CommonImmediateSuperInteraction \'{}\' 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: + self.verbose_log.format_with_message( + 'Running modify_posture_state.', + class_name=self.__class__.__name__, + posture_state=posture_state, + participant_type=participant_type, + sim=sim + ) + (new_posture_state, new_participant_type, new_sim) = self.modify_posture_state(posture_state, participant_type=participant_type, sim=sim) + except Exception as ex: + self.log.error('Error occurred while running CommonImmediateSuperInteraction \'{}\' 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.verbose_log.format_with_message( + 'Running on_killed.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target + ) + self.on_killed(self.sim, self.target) + except Exception as ex: + self.log.error('Error occurred while running CommonImmediateSuperInteraction \'{}\' 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.verbose_log.format_with_message( + 'Running on_cancelled.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target, + finishing_type=finishing_type, + cancel_reason_msg=cancel_reason_msg, + kwargles=kwargs + ) + self.on_cancelled(self.sim, self.target, finishing_type, cancel_reason_msg, **kwargs) + except Exception as ex: + self.log.error('Error occurred while running CommonImmediateSuperInteraction \'{}\' _cancel.'.format(self.__class__.__name__), exception=ex) + return super()._cancel(finishing_type, cancel_reason_msg, **kwargs) + + def on_reset(self: 'CommonImmediateSuperInteraction'): + """on_reset() + + A function that occurs upon an interaction being reset. + + """ + try: + self.verbose_log.format_with_message( + 'Running on_reset.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target + ) + self._on_reset(self.sim, self.target) + except Exception as ex: + self.log.error('Error occurred while running CommonImmediateSuperInteraction \'{}\' on_reset.'.format(self.__class__.__name__), exception=ex) + return super().on_reset() + + def _post_perform(self: 'CommonImmediateSuperInteraction'): + super_result = super()._post_perform() + try: + self.verbose_log.format_with_message( + 'Running on_performed.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target + ) + self.on_performed(self.sim, self.target) + except Exception as ex: + self.log.error('Error occurred while running CommonImmediateSuperInteraction \'{}\' _post_perform.'.format(self.__class__.__name__), exception=ex) + return super_result + + def send_current_progress(self, *args: Any, **kwargs: Any): + """send_current_progress(*args, **kwargs) + + A function that occurs upon a progress bar update. + + """ + try: + self.verbose_log.format_with_message( + 'Running _send_current_progress.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target, + argles=args, + kwargles=kwargs + ) + result = self._send_current_progress(self.sim, self.target, *args, **kwargs) + if result is not None: + return result + except Exception as ex: + self.log.error('Error occurred while running CommonImmediateSuperInteraction \'{}\' 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: + self.verbose_log.format_with_message( + 'Running _setup_asm_default.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target, + asm=asm, + argles=args, + kwargles=kwargs + ) + result = self._setup_asm_default(self.sim, self.target, asm, *args, **kwargs) + if result is not None: + return result + except Exception as ex: + self.log.error('Error occurred while running CommonImmediateSuperInteraction \'{}\' setup_asm_default.'.format(self.__class__.__name__), exception=ex) + return super().setup_asm_default(asm, *args, **kwargs) + + def _run_interaction_gen(self, timeline: Timeline): + try: + self.verbose_log.format_with_message( + 'Running on_run.', + class_name=self.__class__.__name__, + interaction_sim=self.sim, + interaction_target=self.target, + timeline=timeline + ) + self.on_run(self.sim, self.target, timeline) + except Exception as ex: + self.log.error('Error occurred while running CommonImmediateSuperInteraction \'{}\' on_run.'.format(self.__class__.__name__), exception=ex) + yield from super()._run_interaction_gen(timeline) + + # noinspection PyMethodParameters + @flexmethod + def _constraint_gen(cls, inst: 'CommonImmediateSuperInteraction', sim: Sim, target: Any, participant_type: ParticipantType=ParticipantType.Actor, **kwargs) -> Constraint: + inst_or_cls = inst if inst is not None else cls + try: + replacement_results = cls.on_replacement_constraints_gen(inst_or_cls, sim or inst_or_cls.sim, inst_or_cls.get_constraint_target(target) or target or inst_or_cls.target) + if replacement_results is not None: + yield from replacement_results + else: + yield from super(CommonImmediateSuperInteraction, inst_or_cls)._constraint_gen(sim, target, participant_type=participant_type, **kwargs) + result = cls.on_constraint_gen(inst_or_cls, sim or inst_or_cls.sim, inst_or_cls.get_constraint_target(target) or target or inst_or_cls.target) + if result is not None: + if inspect.isgenerator(result): + yield from result + else: + yield result + except Exception as ex: + cls.get_log().error('Error occurred while running CommonImmediateSuperInteraction \'{}\' _on_constraint_gen.'.format(cls.__name__), exception=ex) diff --git a/Scripts/s4ap/sims4communitylib/classes/interactions/common_interaction.py b/Scripts/s4ap/sims4communitylib/classes/interactions/common_interaction.py new file mode 100644 index 0000000..c0b1d75 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/interactions/common_interaction.py @@ -0,0 +1,462 @@ +""" +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 +""" +import inspect +from typing import Any, Union, Set + +from event_testing.tests import TestList +from interactions import ParticipantType +from interactions.constraints import Constraint +from interactions.context import InteractionContext +from interactions.interaction_finisher import FinishingType +from native.animation import NativeAsm +from postures.posture_state import PostureState +from protocolbuffers.Localization_pb2 import LocalizedString +from scheduling import Timeline +from sims.sim import Sim +from sims4.utils import flexmethod +from sims4communitylib.classes.interactions._common_interaction_custom_mixin import _CommonInteractionCustomMixin +from sims4communitylib.classes.interactions._common_interaction_hooks_mixin import _CommonInteractionHooksMixin +from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.logging.has_class_log import HasClassLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from sims4communitylib.utils.misc.common_text_utils import CommonTextUtils +from singletons import DEFAULT +from interactions.base.interaction import Interaction + + +class CommonInteraction(Interaction, HasClassLog, _CommonInteractionHooksMixin, _CommonInteractionCustomMixin): + """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:`CommonInteraction` + * :class:`CommonSocialMixerInteraction` + * :class:`CommonSocialSuperInteraction` + * :class:`CommonSuperInteraction` + * :class:`CommonObjectInteraction` + * :class:`CommonTerrainInteraction` + + .. warning:: Due to an issue with how Read The Docs functions, the base classes of this class will have different namespaces in the docs than they do in the source code! + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> Union[CommonModIdentity, None]: + return None + + def __init__(self, *_: Any, **__: Any): + super().__init__(*_, **__) + HasClassLog.__init__(self) + + @classmethod + def _test(cls, inst, target: Any=DEFAULT, context: InteractionContext=DEFAULT, super_interaction: 'Interaction'=None, skip_safe_tests: bool=False, **kwargs) -> CommonTestResult: + from event_testing.results import TestResult + from sims4communitylib.classes.time.common_stop_watch import CommonStopWatch + log = cls.get_log() + verbose_log = cls.get_verbose_log() + stop_watch = CommonStopWatch() + if verbose_log.enabled: + stop_watch.start() + try: + inst_or_cls = inst if inst is not None else cls + try: + verbose_log.format_with_message( + 'Running on_test.', + class_name=cls.__name__, + interaction_sim=context.sim, + interaction_target=target, + interaction_context=context, + super_interaction=super_interaction, + skip_safe_tests=skip_safe_tests, + kwargles=kwargs + ) + test_result = cls.on_test(context.sim, target, context, super_interaction=super_interaction, skip_safe_tests=skip_safe_tests, **kwargs) + verbose_log.format_with_message('Test Result (CommonInteraction)', test_result=test_result) + except Exception as ex: + log.error('Error occurred while running CommonInteraction \'{}\' on_test.'.format(cls.__name__), exception=ex) + return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') + + if test_result is not None: + if isinstance(test_result, CommonTestResult): + if test_result.is_success is False: + return test_result + elif isinstance(test_result, TestResult) and 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, icon=test_result.icon, influence_by_active_mood=test_result.influence_by_active_mood) + + try: + verbose_log.format_with_message( + 'Running super()._test.', + class_name=cls.__name__, + interaction_sim=context.sim, + interaction_target=target, + interaction_context=context, + super_interaction=super_interaction, + skip_safe_tests=skip_safe_tests, + kwargles=kwargs + ) + super_test_result: TestResult = super()._test(target, context, super_interaction=super_interaction, skip_safe_tests=skip_safe_tests, **kwargs) + + if verbose_log.enabled: + search_for_tooltip = context.source == context.SOURCE_PIE_MENU + resolver = inst_or_cls.get_resolver(target=target, context=context, super_interaction=super_interaction, search_for_tooltip=search_for_tooltip, **kwargs) + global_result = cls.test_globals.run_tests(resolver, skip_safe_tests, search_for_tooltip=search_for_tooltip) + local_result = cls.tests.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=search_for_tooltip) + if inst_or_cls._additional_tests: + additional_tests = TestList(inst_or_cls._additional_tests) + additional_local_result = additional_tests.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=search_for_tooltip) + else: + additional_local_result = None + if inst_or_cls.test_autonomous: + autonomous_result = cls.test_autonomous.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=False) + else: + autonomous_result = None + if target is not None: + tests = target.get_affordance_tests(inst_or_cls) + if tests is not None: + target_result = tests.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=search_for_tooltip) + else: + target_result = None + else: + target_result = None + verbose_log.format_with_message('Super Test Result (CommonInteraction)', super_test_result=super_test_result, global_result=global_result, local_result=local_result, additional_local_result=additional_local_result, autonomous_result=autonomous_result, target_result=target_result) + + if super_test_result is not None and (isinstance(test_result, TestResult) and not super_test_result.result): + return CommonTestResult.convert_from_vanilla(super_test_result) + except Exception as ex: + log.error('Error occurred while running CommonInteraction \'{}\' super()._test.'.format(cls.__name__), exception=ex) + return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') + + try: + verbose_log.format_with_message( + 'Running on_post_super_test.', + class_name=cls.__name__, + interaction_sim=context.sim, + interaction_target=target, + interaction_context=context, + super_interaction=super_interaction, + skip_safe_tests=skip_safe_tests, + kwargles=kwargs + ) + post_super_test_result = cls.on_post_super_test(context.sim, target, context, super_interaction=super_interaction, skip_safe_tests=skip_safe_tests, **kwargs) + verbose_log.format_with_message('Post Test Result (CommonInteraction)', post_super_test_result=post_super_test_result) + except Exception as ex: + log.error('Error occurred while running CommonInteraction \'{}\' on_post_super_test.'.format(cls.__name__), exception=ex) + return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') + + if post_super_test_result is not None: + if isinstance(post_super_test_result, CommonTestResult): + if post_super_test_result.is_success is False: + return post_super_test_result + elif isinstance(post_super_test_result, TestResult) and post_super_test_result.result is False: + if post_super_test_result.tooltip is not None: + post_super_test_result_tooltip = CommonLocalizationUtils.create_localized_tooltip(post_super_test_result.tooltip) + elif post_super_test_result.reason is not None: + post_super_test_result_tooltip = CommonLocalizationUtils.create_localized_tooltip(post_super_test_result.reason) + else: + post_super_test_result_tooltip = None + return cls.create_test_result(post_super_test_result.result, post_super_test_result.reason, tooltip=post_super_test_result_tooltip, icon=post_super_test_result.icon, influence_by_active_mood=post_super_test_result.influence_by_active_mood) + + return cls.create_test_result(True) + except Exception as ex: + log.error('Error occurred while running _test of CommonInteraction \'{}\''.format(cls.__name__), exception=ex) + return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') + finally: + if verbose_log.enabled: + time_taken = CommonTextUtils.to_truncated_decimal(stop_watch.stop_milliseconds()) + verbose_log.format_with_message(f'Took {time_taken}ms to return result from CommonInteraction.', class_name=cls.__name__) + else: + stop_watch.stop() + + # noinspection PyMissingOrEmptyDocstring,PyMethodParameters + @flexmethod + def get_participants(cls, inst, participant_type: ParticipantType, sim: Sim=DEFAULT, target: Any=DEFAULT, carry_target: Any=DEFAULT, **kwargs): + inst_or_cls = inst or cls + log = cls.get_log() + try: + custom_participants = cls.get_custom_replacement_participants(participant_type, sim, target, carry_target, interaction=inst, **kwargs) + if custom_participants is not None: + return tuple(custom_participants) + except Exception as ex: + log.error('Error occurred while running CommonInteraction \'{}\' get_custom_replacement_participants.'.format(cls.__name__), exception=ex) + + result: Set[Any] = super(CommonInteraction, inst_or_cls).get_participants(participant_type, sim=sim, target=target, carry_target=carry_target, **kwargs) + + result = set(result) + try: + custom_participants = cls.get_custom_participants(participant_type, sim, target, carry_target, interaction=inst, **kwargs) + result.update(custom_participants) + except Exception as ex: + log.error('Error occurred while running CommonInteraction \'{}\' get_custom_participants.'.format(cls.__name__), exception=ex) + return tuple(result) + + # noinspection PyMethodParameters,PyMissingOrEmptyDocstring + @flexmethod + def get_name(cls, inst: 'CommonInteraction', target: Any=DEFAULT, context: InteractionContext=DEFAULT, **interaction_parameters) -> LocalizedString: + inst_or_cls = inst or cls + try: + context_inst_or_cls = context or inst_or_cls + interaction_sim = context_inst_or_cls.sim + interaction_target = target or context_inst_or_cls.target + + cls.get_verbose_log().format_with_message( + 'Running get_name.', + class_name=cls.__name__, + interaction_sim=interaction_sim, + interaction_target=interaction_target, + interaction=inst, + interaction_context=context + ) + override_name = cls._create_override_display_name( + interaction_sim, + interaction_target, + interaction=inst, + interaction_context=context, + **interaction_parameters + ) + if override_name is not None: + return override_name + except Exception as ex: + cls.get_log().error('An error occurred while running get_name of CommonInteraction {}'.format(cls.__name__), exception=ex) + result = super(CommonInteraction, inst_or_cls).get_name(target=target, context=context, **interaction_parameters) + if result is None: + cls.get_log().error(f'Missing a name for interaction {cls.__name__}', throw=True) + return result + + def _trigger_interaction_start_event(self: 'CommonInteraction'): + try: + self.verbose_log.format_with_message( + 'Running on_started.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target + ) + result = self.on_started(self.sim, self.target) + if result is not None and ((isinstance(result, CommonExecutionResult) and not result.is_success) or (isinstance(result, bool) and not result)): + self.cancel(FinishingType.CONDITIONAL_EXIT, str(result)) + return False + return super()._trigger_interaction_start_event() + except Exception as ex: + self.log.error('Error occurred while running CommonInteraction \'{}\' 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: + self.verbose_log.format_with_message( + 'Running modify_posture_state.', + class_name=self.__class__.__name__, + posture_state=posture_state, + participant_type=participant_type, + sim=sim + ) + (new_posture_state, new_participant_type, new_sim) = self.modify_posture_state(posture_state, participant_type=participant_type, sim=sim) + except Exception as ex: + self.log.error('Error occurred while running CommonInteraction \'{}\' 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.verbose_log.format_with_message( + 'Running on_killed.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target + ) + self.on_killed(self.sim, self.target) + except Exception as ex: + self.log.error('Error occurred while running CommonInteraction \'{}\' 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.verbose_log.format_with_message( + 'Running on_cancelled.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target, + finishing_type=finishing_type, + cancel_reason_msg=cancel_reason_msg, + kwargles=kwargs + ) + self.on_cancelled(self.sim, self.target, finishing_type, cancel_reason_msg, **kwargs) + except Exception as ex: + self.log.error('Error occurred while running CommonInteraction \'{}\' cancel.'.format(self.__class__.__name__), exception=ex) + return super().cancel(finishing_type, cancel_reason_msg, **kwargs) + + def on_reset(self: 'CommonInteraction'): + """on_reset() + + A function that occurs upon an interaction being reset. + + """ + try: + self.verbose_log.format_with_message( + 'Running on_reset.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target + ) + self._on_reset(self.sim, self.target) + except Exception as ex: + self.log.error('Error occurred while running CommonInteraction \'{}\' on_reset.'.format(self.__class__.__name__), exception=ex) + return super().on_reset() + + def _post_perform(self: 'CommonInteraction'): + super_result = super()._post_perform() + try: + self.verbose_log.format_with_message( + 'Running on_performed.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target + ) + self.on_performed(self.sim, self.target) + except Exception as ex: + self.log.error('Error occurred while running CommonInteraction \'{}\' _post_perform.'.format(self.__class__.__name__), exception=ex) + return super_result + + def send_current_progress(self, *args: Any, **kwargs: Any): + """send_current_progress(*args, **kwargs) + + A function that occurs upon a progress bar update. + + """ + try: + self.verbose_log.format_with_message( + 'Running _send_current_progress.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target, + argles=args, + kwargles=kwargs + ) + result = self._send_current_progress(self.sim, self.target, *args, **kwargs) + if result is not None: + return result + except Exception as ex: + self.log.error('Error occurred while running CommonInteraction \'{}\' 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: + self.verbose_log.format_with_message( + 'Running _setup_asm_default.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target, + asm=asm, + argles=args, + kwargles=kwargs + ) + result = self._setup_asm_default(self.sim, self.target, asm, *args, **kwargs) + if result is not None: + return result + except Exception as ex: + self.log.error('Error occurred while running CommonInteraction \'{}\' setup_asm_default.'.format(self.__class__.__name__), exception=ex) + return super().setup_asm_default(asm, *args, **kwargs) + + def _run_interaction_gen(self, timeline: Timeline): + try: + self.verbose_log.format_with_message( + 'Running on_run.', + class_name=self.__class__.__name__, + interaction_sim=self.sim, + interaction_target=self.target, + timeline=timeline + ) + self.on_run(self.sim, self.target, timeline) + except Exception as ex: + self.log.error('Error occurred while running CommonInteraction \'{}\' on_run.'.format(self.__class__.__name__), exception=ex) + yield from super()._run_interaction_gen(timeline) + + @classmethod + def _constraint_gen(cls, sim: Sim, target: Any, participant_type: ParticipantType=ParticipantType.Actor, interaction: 'CommonInteraction'=None) -> Constraint: + inst_or_cls = interaction if interaction is not None else cls + try: + replacement_results = cls.on_replacement_constraints_gen(inst_or_cls, sim or inst_or_cls.sim, inst_or_cls.get_constraint_target(target) or target or inst_or_cls.target) + if replacement_results is not None: + if inspect.isgenerator(replacement_results): + yield from replacement_results + else: + yield replacement_results + else: + yield from super()._constraint_gen(sim, target, participant_type=participant_type, interaction=interaction) + result = cls.on_constraint_gen(inst_or_cls, sim or inst_or_cls.sim, inst_or_cls.get_constraint_target(target) or target or inst_or_cls.target) + if result is not None: + if inspect.isgenerator(result): + yield from result + else: + yield result + except Exception as ex: + cls.get_log().error('Error occurred while running CommonInteraction \'{}\' _on_constraint_gen.'.format(cls.__name__), exception=ex) + + +# The following is an example interaction that varies when it will display, when it will be hidden, and when it will be disabled with a tooltip. +class _ExampleInteraction(CommonInteraction): + # noinspection PyMissingOrEmptyDocstring + @classmethod + def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, *args, **kwargs) -> CommonTestResult: + result = 1 + 1 + if result == 2: + # Interaction will be displayed, but disabled, it will also have a tooltip that displays on hover with the text "Test Tooltip" + return cls.create_test_result(False, reason="Test Tooltip") + # Alternative way to specify a tooltip with the text "Test Tooltip" + # return cls.create_test_result(False, reason="No Reason", tooltip=CommonLocalizationUtils.create_localized_tooltip("Test Tooltip")) + if result == 3: + # Interaction will be hidden completely. + return CommonTestResult.NONE + # Interaction will display and be enabled. + return CommonTestResult.TRUE + + # noinspection PyMissingOrEmptyDocstring + def on_started(self, interaction_sim: Sim, interaction_target: Any) -> CommonExecutionResult: + result = True + if not result: + return CommonExecutionResult.FALSE + # Put here what you want the interaction to do as soon as the player clicks it while it is enabled. + return CommonExecutionResult.TRUE diff --git a/Scripts/s4ap/sims4communitylib/classes/interactions/common_interaction_override_name.py b/Scripts/s4ap/sims4communitylib/classes/interactions/common_interaction_override_name.py new file mode 100644 index 0000000..3ac174c --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/interactions/common_interaction_override_name.py @@ -0,0 +1,89 @@ +""" +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 +""" +from typing import Any, Union + +from interactions.base.interaction import Interaction +from interactions.context import InteractionContext +from protocolbuffers.Localization_pb2 import LocalizedString +from sims.sim import Sim +from sims4.utils import flexmethod +from sims4communitylib.logging.has_class_log import HasClassLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity + + +class CommonInteractionOverrideName(HasClassLog): + """CommonInteractionOverrideName() + + An inheritable class that provides a way to override the :func:`~get_name` function of :class:`.CommonInteraction`. + + .. warning:: This class is obsolete. All interaction types come with their own :func:`~get_name` function. This class is to be used in conjunction with :class:`.CommonInteraction`. Inheriting from this class will do nothing for class that does not also inherit from :class:`.CommonInteraction`. + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> Union[CommonModIdentity, None]: + return None + + def __init__(self) -> None: + super().__init__() + HasClassLog.__init__(self) + + # noinspection PyMethodParameters,PyMissingOrEmptyDocstring + @flexmethod + def get_name(cls, inst: Interaction, target: Any=None, context: InteractionContext=None, **interaction_parameters) -> LocalizedString: + inst_or_cls = inst or cls + try: + context_inst_or_cls = context or inst_or_cls + interaction_sim = context_inst_or_cls.sim + interaction_target = target or context_inst_or_cls.target + + cls.get_verbose_log().format_with_message( + 'Creating display name.', + class_name=cls.__name__, + interaction_sim=interaction_sim, + interaction_target=interaction_target, + interaction=inst, + interaction_context=context + ) + override_name = cls._create_display_name( + interaction_sim, + interaction_target, + interaction=inst, + interaction_context=context, + **interaction_parameters + ) + if override_name is not None: + return override_name + except Exception as ex: + cls.get_log().error('An error occurred while running get_name of CommonInteractionOverrideName {}'.format(cls.__name__), exception=ex) + result = super(Interaction, inst_or_cls).get_name(target=target, context=context, **interaction_parameters) + if result is None: + cls.get_log().error(f'Missing a name for interaction {cls.__name__}', throw=True) + return result + + # noinspection PyUnusedLocal + @classmethod + def _create_display_name(cls, interaction_sim: Sim, interaction_target: Any, interaction: Union[Interaction, None]=None, interaction_context: Union[InteractionContext, None]=None, **interaction_parameters) -> Union[LocalizedString, None]: + """_create_display_name(interaction_sim, interaction_target, interaction=None, interaction_context=None, **interaction_parameters) + + A hook that allows using a custom display name for an Interaction. + + :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: An instance of an interaction or None if no instance of the interaction is available. Default is None. + :type interaction: Union[Interaction, None], optional + :param interaction_context: The context of the interaction or None if no interaction context is available. Default is None. + :type interaction_context: Union[InteractionContext, None], optional + :param interaction_parameters: Extra interaction parameters. + :type interaction_parameters: Any + :return: A Localized String to display for the interaction or None if the original display name should be used. + :rtype: Union[LocalizedString, None] + """ + raise NotImplementedError() diff --git a/Scripts/s4ap/sims4communitylib/classes/interactions/common_mixer_interaction.py b/Scripts/s4ap/sims4communitylib/classes/interactions/common_mixer_interaction.py new file mode 100644 index 0000000..07bac74 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/interactions/common_mixer_interaction.py @@ -0,0 +1,460 @@ +""" +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 +""" +import inspect +from typing import Union, Any, Set + +from event_testing.tests import TestList +from interactions import ParticipantType +from interactions.base.interaction import Interaction +from interactions.constraints import Constraint +from interactions.context import InteractionContext +from interactions.interaction_finisher import FinishingType +from native.animation import NativeAsm +from postures.posture_state import PostureState +from protocolbuffers.Localization_pb2 import LocalizedString +from scheduling import Timeline +from sims.sim import Sim +from sims4.utils import flexmethod +from sims4communitylib.classes.interactions._common_interaction_custom_mixin import _CommonInteractionCustomMixin +from sims4communitylib.classes.interactions._common_interaction_hooks_mixin import _CommonInteractionHooksMixin +from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.logging.has_class_log import HasClassLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from sims4communitylib.utils.misc.common_text_utils import CommonTextUtils +from singletons import DEFAULT +from interactions.base.mixer_interaction import MixerInteraction + + +class CommonMixerInteraction(MixerInteraction, HasClassLog, _CommonInteractionHooksMixin, _CommonInteractionCustomMixin): + """CommonMixerInteraction(*_, **__) + + An inheritable class that provides a way to create Custom Mixer Interactions. + + .. 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! + + :Example: + + .. highlight:: python + .. code-block:: python + + # The following is an example interaction that varies when it will display, when it will be hidden, and when it will be disabled with a tooltip. + class _ExampleInteraction(CommonMixerInteraction): + @classmethod + def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, **kwargs) -> CommonTestResult: + result = 1 + 1 + if result == 2: + # Interaction will be displayed, but disabled, it will also have a tooltip that displays on hover with the text "Test Tooltip" + return cls.create_test_result(False, reason="Test Tooltip") + # Alternative way to specify a tooltip with the text "Test Tooltip" + # return cls.create_test_result(False, reason="No Reason", tooltip=CommonLocalizationUtils.create_localized_tooltip("Test Tooltip")) + if result == 3: + # Interaction will be hidden completely. + return CommonTestResult.NONE + # Interaction will display and be enabled. + return CommonTestResult.TRUE + + def on_started(self, interaction_sim: Sim, interaction_target: Any) -> CommonExecutionResult: + result = True + if not result: + return CommonExecutionResult.FALSE + # Put here what you want the interaction to do as soon as the player clicks it while it is enabled. + return CommonExecutionResult.TRUE + + def on_cancelled(self, interaction_sim: Sim, interaction_target: Any, finishing_type: FinishingType, cancel_reason_msg: str, **kwargs): + result = True + if not result: + return False + # Put here what you want the interaction to do as soon as the player clicks it while it is enabled. + return True + + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> Union[CommonModIdentity, None]: + return None + + def __init__(self, *_: Any, **__: Any): + super().__init__(*_, **__) + HasClassLog.__init__(self) + + @classmethod + def _test(cls, target: Any, context: InteractionContext, super_interaction: 'Interaction'=None, skip_safe_tests: bool=False, **kwargs) -> CommonTestResult: + from event_testing.results import TestResult + from sims4communitylib.classes.time.common_stop_watch import CommonStopWatch + log = cls.get_log() + verbose_log = cls.get_verbose_log() + stop_watch = CommonStopWatch() + if verbose_log.enabled: + stop_watch.start() + try: + try: + verbose_log.format_with_message( + 'Running on_test.', + class_name=cls.__name__, + interaction_sim=context.sim, + interaction_target=target, + interaction_context=context, + super_interaction=super_interaction, + skip_safe_tests=skip_safe_tests, + kwargles=kwargs + ) + test_result = cls.on_test(context.sim, target, context, super_interaction=super_interaction, skip_safe_tests=skip_safe_tests, **kwargs) + verbose_log.format_with_message('Test Result (CommonMixerInteraction)', test_result=test_result) + except Exception as ex: + log.error('Error occurred while running CommonMixerInteraction \'{}\' on_test.'.format(cls.__name__), exception=ex) + return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') + + if test_result is not None: + if isinstance(test_result, CommonTestResult): + if test_result.is_success is False: + return test_result + elif isinstance(test_result, TestResult) and 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, icon=test_result.icon, influence_by_active_mood=test_result.influence_by_active_mood) + + try: + verbose_log.format_with_message( + 'Running super()._test.', + class_name=cls.__name__, + interaction_sim=context.sim, + interaction_target=target, + interaction_context=context, + super_interaction=super_interaction, + skip_safe_tests=skip_safe_tests, + kwargles=kwargs + ) + super_test_result: TestResult = super()._test(target, context, super_interaction=super_interaction, skip_safe_tests=skip_safe_tests, **kwargs) + + if verbose_log.enabled: + search_for_tooltip = context.source == context.SOURCE_PIE_MENU + resolver = cls.get_resolver(target=target, context=context, super_interaction=super_interaction, search_for_tooltip=search_for_tooltip, **kwargs) + global_result = cls.test_globals.run_tests(resolver, skip_safe_tests, search_for_tooltip=search_for_tooltip) + local_result = cls.tests.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=search_for_tooltip) + if cls._additional_tests: + additional_tests = TestList(cls._additional_tests) + additional_local_result = additional_tests.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=search_for_tooltip) + else: + additional_local_result = None + if cls.test_autonomous: + autonomous_result = cls.test_autonomous.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=False) + else: + autonomous_result = None + if target is not None: + tests = target.get_affordance_tests(cls) + if tests is not None: + target_result = tests.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=search_for_tooltip) + else: + target_result = None + else: + target_result = None + verbose_log.format_with_message('Super Test Result (CommonMixerInteraction)', super_test_result=super_test_result, global_result=global_result, local_result=local_result, additional_local_result=additional_local_result, autonomous_result=autonomous_result, target_result=target_result) + + if super_test_result is not None and (isinstance(test_result, TestResult) and not super_test_result.result): + return CommonTestResult.convert_from_vanilla(super_test_result) + except Exception as ex: + log.error('Error occurred while running CommonMixerInteraction \'{}\' super()._test.'.format(cls.__name__), exception=ex) + return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') + + try: + verbose_log.format_with_message( + 'Running on_post_super_test.', + class_name=cls.__name__, + interaction_sim=context.sim, + interaction_target=target, + interaction_context=context, + super_interaction=super_interaction, + skip_safe_tests=skip_safe_tests, + kwargles=kwargs + ) + post_super_test_result = cls.on_post_super_test(context.sim, target, context, super_interaction=super_interaction, skip_safe_tests=skip_safe_tests, **kwargs) + verbose_log.format_with_message('Post Test Result (CommonMixerInteraction)', post_super_test_result=post_super_test_result) + except Exception as ex: + log.error('Error occurred while running CommonMixerInteraction \'{}\' on_post_super_test.'.format(cls.__name__), exception=ex) + return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') + + if post_super_test_result is not None: + if isinstance(post_super_test_result, CommonTestResult): + if post_super_test_result.is_success is False: + return post_super_test_result + elif isinstance(post_super_test_result, TestResult) and post_super_test_result.result is False: + if post_super_test_result.tooltip is not None: + post_super_test_result_tooltip = CommonLocalizationUtils.create_localized_tooltip(post_super_test_result.tooltip) + elif post_super_test_result.reason is not None: + post_super_test_result_tooltip = CommonLocalizationUtils.create_localized_tooltip(post_super_test_result.reason) + else: + post_super_test_result_tooltip = None + return cls.create_test_result(post_super_test_result.result, post_super_test_result.reason, tooltip=post_super_test_result_tooltip, icon=post_super_test_result.icon, influence_by_active_mood=post_super_test_result.influence_by_active_mood) + + return cls.create_test_result(True) + except Exception as ex: + log.error('Error occurred while running _test of CommonMixerInteraction \'{}\''.format(cls.__name__), exception=ex) + return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') + finally: + if verbose_log.enabled: + time_taken = CommonTextUtils.to_truncated_decimal(stop_watch.stop_milliseconds()) + verbose_log.format_with_message(f'Took {time_taken}ms to return result from CommonMixerInteraction.', class_name=cls.__name__) + else: + stop_watch.stop() + + # noinspection PyMissingOrEmptyDocstring,PyMethodParameters + @flexmethod + def get_participants(cls, inst, participant_type:ParticipantType, sim=DEFAULT, target=DEFAULT, carry_target=DEFAULT, **kwargs): + inst_or_cls = inst or cls + log = cls.get_log() + try: + custom_participants = cls.get_custom_replacement_participants(participant_type, sim, target, carry_target, interaction=inst, **kwargs) + if custom_participants is not None: + return tuple(custom_participants) + except Exception as ex: + log.error('Error occurred while running CommonMixerInteraction \'{}\' get_custom_replacement_participants.'.format(cls.__name__), exception=ex) + + result: Set[Any] = super(CommonMixerInteraction, inst_or_cls).get_participants(participant_type, sim=sim, target=target, carry_target=carry_target, **kwargs) + + result = set(result) + try: + custom_participants = cls.get_custom_participants(participant_type, sim, target, carry_target, interaction=inst, **kwargs) + result.update(custom_participants) + except Exception as ex: + log.error('Error occurred while running CommonMixerInteraction \'{}\' get_custom_participants.'.format(cls.__name__), exception=ex) + return tuple(result) + + # noinspection PyMethodParameters,PyMissingOrEmptyDocstring + @flexmethod + def get_name(cls, inst: 'CommonMixerInteraction', target: Any=DEFAULT, context: InteractionContext=DEFAULT, **interaction_parameters) -> LocalizedString: + inst_or_cls = inst or cls + try: + context_inst_or_cls = context or inst_or_cls + interaction_sim = context_inst_or_cls.sim + interaction_target = target or context_inst_or_cls.target + + cls.get_verbose_log().format_with_message( + 'Running get_name.', + class_name=cls.__name__, + interaction_sim=interaction_sim, + interaction_target=interaction_target, + interaction=inst, + interaction_context=context + ) + override_name = cls._create_override_display_name( + interaction_sim, + interaction_target, + interaction=inst, + interaction_context=context, + **interaction_parameters + ) + if override_name is not None: + return override_name + except Exception as ex: + cls.get_log().error('An error occurred while running get_name of CommonMixerInteraction {}'.format(cls.__name__), exception=ex) + result = super(CommonMixerInteraction, inst_or_cls).get_name(target=target, context=context, **interaction_parameters) + if result is None: + cls.get_log().error(f'Missing a name for interaction {cls.__name__}', throw=True) + return result + + def _trigger_interaction_start_event(self: 'CommonMixerInteraction'): + try: + self.verbose_log.format_with_message( + 'Running on_started.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target + ) + result = self.on_started(self.sim, self.target) + if result is not None and ((isinstance(result, CommonExecutionResult) and not result.is_success) or (isinstance(result, bool) and not result)): + self.cancel(FinishingType.CONDITIONAL_EXIT, str(result)) + return False + return super()._trigger_interaction_start_event() + except Exception as ex: + self.log.error('Error occurred while running CommonMixerInteraction \'{}\' 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: + self.verbose_log.format_with_message( + 'Running modify_posture_state.', + class_name=self.__class__.__name__, + posture_state=posture_state, + participant_type=participant_type, + sim=sim + ) + (new_posture_state, new_participant_type, new_sim) = self.modify_posture_state(posture_state, participant_type=participant_type, sim=sim) + except Exception as ex: + self.log.error('Error occurred while running CommonMixerInteraction \'{}\' 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.verbose_log.format_with_message( + 'Running on_killed.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target + ) + self.on_killed(self.sim, self.target) + except Exception as ex: + self.log.error('Error occurred while running CommonMixerInteraction \'{}\' 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.verbose_log.format_with_message( + 'Running on_cancelled.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target, + finishing_type=finishing_type, + cancel_reason_msg=cancel_reason_msg, + kwargles=kwargs + ) + self.on_cancelled(self.sim, self.target, finishing_type, cancel_reason_msg, **kwargs) + except Exception as ex: + self.log.error('Error occurred while running CommonMixerInteraction \'{}\' cancel.'.format(self.__class__.__name__), exception=ex) + return super().cancel(finishing_type, cancel_reason_msg, **kwargs) + + def on_reset(self: 'CommonMixerInteraction'): + """on_reset() + + A function that occurs upon an interaction being reset. + + """ + try: + self.verbose_log.format_with_message( + 'Running on_reset.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target + ) + self._on_reset(self.sim, self.target) + except Exception as ex: + self.log.error('Error occurred while running CommonMixerInteraction \'{}\' on_reset.'.format(self.__class__.__name__), exception=ex) + return super().on_reset() + + def _post_perform(self: 'CommonMixerInteraction'): + super_result = super()._post_perform() + try: + self.verbose_log.format_with_message( + 'Running on_performed.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target + ) + self.on_performed(self.sim, self.target) + except Exception as ex: + self.log.error('Error occurred while running CommonMixerInteraction \'{}\' _post_perform.'.format(self.__class__.__name__), exception=ex) + return super_result + + def send_current_progress(self, *args: Any, **kwargs: Any): + """send_current_progress(*args, **kwargs) + + A function that occurs upon a progress bar update. + + """ + try: + self.verbose_log.format_with_message( + 'Running _send_current_progress.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target, + argles=args, + kwargles=kwargs + ) + result = self._send_current_progress(self.sim, self.target, *args, **kwargs) + if result is not None: + return result + except Exception as ex: + self.log.error('Error occurred while running CommonMixerInteraction \'{}\' 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: + self.verbose_log.format_with_message( + 'Running _setup_asm_default.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target, + asm=asm, + argles=args, + kwargles=kwargs + ) + result = self._setup_asm_default(self.sim, self.target, asm, *args, **kwargs) + if result is not None: + return result + except Exception as ex: + self.log.error('Error occurred while running CommonMixerInteraction \'{}\' setup_asm_default.'.format(self.__class__.__name__), exception=ex) + return super().setup_asm_default(asm, *args, **kwargs) + + def _run_interaction_gen(self, timeline: Timeline): + try: + self.verbose_log.format_with_message( + 'Running on_run.', + class_name=self.__class__.__name__, + interaction_sim=self.sim, + interaction_target=self.target, + timeline=timeline + ) + self.on_run(self.sim, self.target, timeline) + except Exception as ex: + self.log.error('Error occurred while running CommonMixerInteraction \'{}\' on_run.'.format(self.__class__.__name__), exception=ex) + yield from super()._run_interaction_gen(timeline) + + @classmethod + def _constraint_gen(cls, sim: Sim, target: Any, participant_type: ParticipantType=ParticipantType.Actor, interaction: 'CommonMixerInteraction'=None) -> Constraint: + inst_or_cls = interaction if interaction is not None else cls + try: + replacement_results = cls.on_replacement_constraints_gen(inst_or_cls, sim or inst_or_cls.sim, inst_or_cls.get_constraint_target(target) or target or inst_or_cls.target) + if replacement_results is not None: + if inspect.isgenerator(replacement_results): + yield from replacement_results + else: + yield replacement_results + else: + yield from super()._constraint_gen(sim, target, participant_type=participant_type, interaction=interaction) + result = cls.on_constraint_gen(inst_or_cls, sim or inst_or_cls.sim, inst_or_cls.get_constraint_target(target) or target or inst_or_cls.target) + if result is not None: + if inspect.isgenerator(result): + yield from result + else: + yield result + except Exception as ex: + cls.get_log().error('Error occurred while running CommonMixerInteraction \'{}\' _on_constraint_gen.'.format(cls.__name__), exception=ex) diff --git a/Scripts/s4ap/sims4communitylib/classes/interactions/common_object_interaction.py b/Scripts/s4ap/sims4communitylib/classes/interactions/common_object_interaction.py new file mode 100644 index 0000000..22dfcab --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/interactions/common_object_interaction.py @@ -0,0 +1,77 @@ +""" +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 +""" +from typing import Any + +from interactions.context import InteractionContext +from sims.sim import Sim +from sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction +from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from sims4communitylib.classes.testing.common_test_result import CommonTestResult + + +class CommonObjectInteraction(CommonImmediateSuperInteraction): + """CommonObjectInteraction(*_, **__) + + An inheritable class that provides a way to create custom Object Interactions. + + .. 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! + + :Example: + + .. highlight:: python + .. code-block:: python + + class _ExampleObjectInteraction(CommonObjectInteraction): + @classmethod + def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, **kwargs) -> CommonTestResult: + result = 1 + 1 + if result == 2: + # Interaction will be displayed, but disabled, it will also have a tooltip that displays on hover with the text "Test Tooltip" + return cls.create_test_result(False, reason="Test Tooltip") + # Alternative way to specify a tooltip with the text "Test Tooltip" + # return cls.create_test_result(False, reason="No Reason", tooltip=CommonLocalizationUtils.create_localized_tooltip("Test Tooltip")) + if result == 3: + # Interaction will be hidden completely. + return CommonTestResult.NONE + # Interaction will display and be enabled. + return CommonTestResult.TRUE + + def on_started(self, interaction_sim: Sim, interaction_target: Any) -> CommonExecutionResult: + result = True + if not result: + return CommonExecutionResult.FALSE + # Put here what you want the interaction to do as soon as the player clicks it while it is enabled. + return CommonExecutionResult.TRUE + """ + pass + + +# The following is an example interaction that varies when it will display, when it will be hidden, and when it will be disabled with a tooltip. +class _ExampleObjectInteraction(CommonObjectInteraction): + # noinspection PyMissingOrEmptyDocstring + @classmethod + def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, **kwargs) -> CommonTestResult: + result = 1 + 1 + if result == 2: + # Interaction will be displayed, but disabled, it will also have a tooltip that displays on hover with the text "Test Tooltip" + return cls.create_test_result(False, reason="Test Tooltip") + # Alternative way to specify a tooltip with the text "Test Tooltip" + # return cls.create_test_result(False, reason="No Reason", tooltip=CommonLocalizationUtils.create_localized_tooltip("Test Tooltip")) + if result == 3: + # Interaction will be hidden completely. + return CommonTestResult.NONE + # Interaction will display and be enabled. + return CommonTestResult.TRUE + + # noinspection PyMissingOrEmptyDocstring + def on_started(self, interaction_sim: Sim, interaction_target: Any) -> CommonExecutionResult: + result = True + if not result: + return CommonExecutionResult.FALSE + # Put here what you want the interaction to do as soon as the player clicks it while it is enabled. + return CommonExecutionResult.TRUE diff --git a/Scripts/s4ap/sims4communitylib/classes/interactions/common_social_mixer_interaction.py b/Scripts/s4ap/sims4communitylib/classes/interactions/common_social_mixer_interaction.py new file mode 100644 index 0000000..f329184 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/interactions/common_social_mixer_interaction.py @@ -0,0 +1,466 @@ +""" +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 +""" +import inspect + +from event_testing.tests import TestList +from interactions.base.interaction import Interaction +from postures.posture_state import PostureState +from sims4communitylib.classes.interactions._common_interaction_custom_mixin import _CommonInteractionCustomMixin +from sims4communitylib.classes.interactions._common_interaction_hooks_mixin import _CommonInteractionHooksMixin +from sims4communitylib.utils.misc.common_text_utils import CommonTextUtils +from singletons import DEFAULT +from typing import Any, Union, Tuple, Set + +from interactions import ParticipantType +from interactions.constraints import Constraint +from interactions.context import InteractionContext +from interactions.interaction_finisher import FinishingType +from native.animation import NativeAsm +from protocolbuffers.Localization_pb2 import LocalizedString +from scheduling import Timeline +from sims.sim import Sim +from sims4.utils import flexmethod +from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.logging.has_class_log import HasClassLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from interactions.social.social_mixer_interaction import SocialMixerInteraction + + +class CommonSocialMixerInteraction(SocialMixerInteraction, HasClassLog, _CommonInteractionHooksMixin, _CommonInteractionCustomMixin): + """CommonSocialMixerInteraction(*_, **__) + + An inheritable class that provides a way to create Custom Social Mixer Interactions. + + .. note:: The main use for this class is to create interactions that involve two or more Sims interacting with each other. + + .. 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! + + :Example: + + .. highlight:: python + .. code-block:: python + + # The following is an example interaction that varies when it will display, when it will be hidden, and when it will be disabled with a tooltip. + class _ExampleInteraction(CommonSocialMixerInteraction): + @classmethod + def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, *args, **kwargs) -> TestResult: + result = 1 + 1 + if result == 2: + # Interaction will be displayed, but disabled, it will also have a tooltip that displays on hover with the text "Test Tooltip" + return cls.create_test_result(False, reason="Test Tooltip") + # Alternative way to specify a tooltip with the text "Test Tooltip" + # return cls.create_test_result(False, reason="No Reason", tooltip=CommonLocalizationUtils.create_localized_tooltip("Test Tooltip")) + if result == 3: + # Interaction will be hidden completely. + return CommonTestResult.NONE + # Interaction will display and be enabled. + return CommonTestResult.TRUE + + def on_started(self, interaction_sim: Sim, interaction_target: Any) -> CommonExecutionResult: + result = True + if not result: + return CommonExecutionResult.FALSE + # Put here what you want the interaction to do as soon as the player clicks it while it is enabled. + return CommonExecutionResult.TRUE + + def on_cancelled(self, interaction_sim: Sim, interaction_target: Any, finishing_type: FinishingType, cancel_reason_msg: str, **kwargs): + result = True + if not result: + return False + # Put here what you want the interaction to do as soon as the player clicks it while it is enabled. + return True + + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> Union[CommonModIdentity, None]: + return None + + def __init__(self, *_: Any, **__: Any): + super().__init__(*_, **__) + HasClassLog.__init__(self) + + # SocialMixerInteraction has a different signature for its _test function, so we override it in here. + @classmethod + def _test(cls, target: Any, context: InteractionContext, *args, super_interaction: 'Interaction'=None, skip_safe_tests: bool=False, **kwargs) -> CommonTestResult: + from event_testing.results import TestResult + from sims4communitylib.classes.time.common_stop_watch import CommonStopWatch + log = cls.get_log() + verbose_log = cls.get_verbose_log() + stop_watch = CommonStopWatch() + stop_watch.start() + try: + try: + verbose_log.format_with_message( + 'Running on_test.', + class_name=cls.__name__, + interaction_sim=context.sim, + interaction_target=target, + interaction_context=context, + super_interaction=super_interaction, + skip_safe_tests=skip_safe_tests, + argles=args, + kwargles=kwargs + ) + test_result = cls.on_test(context.sim, target, context, *args, super_interaction=super_interaction, skip_safe_tests=skip_safe_tests, **kwargs) + verbose_log.format_with_message('Test Result (CommonSocialMixerInteraction)', test_result=test_result) + except Exception as ex: + log.error('Error occurred while running CommonSocialMixerInteraction \'{}\' on_test.'.format(cls.__name__), exception=ex) + return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') + + if test_result is not None: + if isinstance(test_result, CommonTestResult): + if test_result.is_success is False: + return test_result + elif isinstance(test_result, TestResult) and 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, icon=test_result.icon, influence_by_active_mood=test_result.influence_by_active_mood) + + try: + verbose_log.format_with_message( + 'Running super()._test.', + class_name=cls.__name__, + interaction_sim=context.sim, + interaction_target=target, + interaction_context=context, + super_interaction=super_interaction, + skip_safe_tests=skip_safe_tests, + argles=args, + kwargles=kwargs + ) + super_test_result: TestResult = super()._test(target, context, *args, super_interaction=super_interaction, skip_safe_tests=skip_safe_tests, **kwargs) + + if verbose_log.enabled: + search_for_tooltip = context.source == context.SOURCE_PIE_MENU + resolver = cls.get_resolver(target=target, context=context, super_interaction=super_interaction, search_for_tooltip=search_for_tooltip, **kwargs) + global_result = cls.test_globals.run_tests(resolver, skip_safe_tests, search_for_tooltip=search_for_tooltip) + local_result = cls.tests.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=search_for_tooltip) + if cls._additional_tests: + additional_tests = TestList(cls._additional_tests) + additional_local_result = additional_tests.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=search_for_tooltip) + else: + additional_local_result = None + if cls.test_autonomous: + autonomous_result = cls.test_autonomous.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=False) + else: + autonomous_result = None + if target is not None: + tests = target.get_affordance_tests(cls) + if tests is not None: + target_result = tests.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=search_for_tooltip) + else: + target_result = None + else: + target_result = None + verbose_log.format_with_message('Super Test Result (CommonSocialMixerInteraction)', super_test_result=super_test_result, global_result=global_result, local_result=local_result, additional_local_result=additional_local_result, autonomous_result=autonomous_result, target_result=target_result) + + if super_test_result is not None and (isinstance(test_result, TestResult) and not super_test_result.result): + return CommonTestResult.convert_from_vanilla(super_test_result) + except Exception as ex: + log.error('Error occurred while running CommonSocialMixerInteraction \'{}\' super()._test.'.format(cls.__name__), exception=ex) + return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') + + try: + verbose_log.format_with_message( + 'Running on_post_super_test.', + class_name=cls.__name__, + interaction_sim=context.sim, + interaction_target=target, + interaction_context=context, + super_interaction=super_interaction, + skip_safe_tests=skip_safe_tests, + argles=args, + kwargles=kwargs + ) + post_super_test_result = cls.on_post_super_test(context.sim, target, context, *args, super_interaction=super_interaction, skip_safe_tests=skip_safe_tests, **kwargs) + verbose_log.format_with_message('Post Test Result (CommonSocialMixerInteraction)', post_super_test_result=post_super_test_result) + except Exception as ex: + log.error('Error occurred while running CommonSocialMixerInteraction \'{}\' on_post_super_test.'.format(cls.__name__), exception=ex) + return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') + + if post_super_test_result is not None: + if isinstance(post_super_test_result, CommonTestResult): + if post_super_test_result.is_success is False: + return post_super_test_result + elif isinstance(post_super_test_result, TestResult) and post_super_test_result.result is False: + if post_super_test_result.tooltip is not None: + post_super_test_result_tooltip = CommonLocalizationUtils.create_localized_tooltip(post_super_test_result.tooltip) + elif post_super_test_result.reason is not None: + post_super_test_result_tooltip = CommonLocalizationUtils.create_localized_tooltip(post_super_test_result.reason) + else: + post_super_test_result_tooltip = None + return cls.create_test_result(post_super_test_result.result, post_super_test_result.reason, tooltip=post_super_test_result_tooltip, icon=post_super_test_result.icon, influence_by_active_mood=post_super_test_result.influence_by_active_mood) + + return cls.create_test_result(True) + except Exception as ex: + log.error('Error occurred while running _test of CommonSocialMixerInteraction \'{}\''.format(cls.__name__), exception=ex) + return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') + finally: + if verbose_log.enabled: + time_taken = CommonTextUtils.to_truncated_decimal(stop_watch.stop_milliseconds()) + verbose_log.format_with_message(f'Took {time_taken}ms to return result from CommonSocialMixerInteraction.', class_name=cls.__name__) + else: + stop_watch.stop() + + # noinspection PyMissingOrEmptyDocstring,PyMethodParameters + @flexmethod + def get_participants(cls, inst, participant_type: ParticipantType, sim=DEFAULT, target=DEFAULT, carry_target=DEFAULT, **kwargs) -> Union[Tuple[Any], Set[Any]]: + inst_or_cls = inst or cls + log = cls.get_log() + try: + custom_participants = cls.get_custom_replacement_participants(participant_type, sim, target, carry_target, interaction=inst, **kwargs) + if custom_participants is not None: + return tuple(custom_participants) + except Exception as ex: + log.error('Error occurred while running CommonSocialMixerInteraction \'{}\' get_custom_replacement_participants.'.format(cls.__name__), exception=ex) + + result: Set[Any] = super(CommonSocialMixerInteraction, inst_or_cls).get_participants(participant_type, sim=sim, target=target, carry_target=carry_target, **kwargs) + + result = set(result) + try: + custom_participants = cls.get_custom_participants(participant_type, sim, target, carry_target, interaction=inst, **kwargs) + result.update(custom_participants) + except Exception as ex: + log.error('Error occurred while running CommonSocialMixerInteraction \'{}\' get_custom_participants.'.format(cls.__name__), exception=ex) + return tuple(result) + + # noinspection PyMethodParameters,PyMissingOrEmptyDocstring + @flexmethod + def get_name(cls, inst: 'CommonSocialMixerInteraction', target: Any=DEFAULT, context: InteractionContext=DEFAULT, **interaction_parameters) -> LocalizedString: + inst_or_cls = inst or cls + try: + context_inst_or_cls = context or inst_or_cls + interaction_sim = context_inst_or_cls.sim + interaction_target = target or context_inst_or_cls.target + + cls.get_verbose_log().format_with_message( + 'Running get_name.', + class_name=cls.__name__, + interaction_sim=interaction_sim, + interaction_target=interaction_target, + interaction=inst, + interaction_context=context + ) + override_name = cls._create_override_display_name( + interaction_sim, + interaction_target, + interaction=inst, + interaction_context=context, + **interaction_parameters + ) + if override_name is not None: + return override_name + except Exception as ex: + cls.get_log().error('An error occurred while running get_name of CommonSocialMixerInteraction {}'.format(cls.__name__), exception=ex) + result = super(CommonSocialMixerInteraction, inst_or_cls).get_name(target=target, context=context, **interaction_parameters) + if result is None: + cls.get_log().error(f'Missing a name for interaction {cls.__name__}', throw=True) + return result + + def _trigger_interaction_start_event(self: 'CommonSocialMixerInteraction'): + try: + self.verbose_log.format_with_message( + 'Running on_started.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target + ) + result = self.on_started(self.sim, self.target) + if result is not None and ((isinstance(result, CommonExecutionResult) and not result.is_success) or (isinstance(result, bool) and not result)): + self.cancel(FinishingType.CONDITIONAL_EXIT, str(result)) + return False + return super()._trigger_interaction_start_event() + except Exception as ex: + self.log.error('Error occurred while running CommonSocialMixerInteraction \'{}\' 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: + self.verbose_log.format_with_message( + 'Running modify_posture_state.', + class_name=self.__class__.__name__, + posture_state=posture_state, + participant_type=participant_type, + sim=sim + ) + (new_posture_state, new_participant_type, new_sim) = self.modify_posture_state(posture_state, participant_type=participant_type, sim=sim) + except Exception as ex: + self.log.error('Error occurred while running CommonSocialMixerInteraction \'{}\' 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.verbose_log.format_with_message( + 'Running on_killed.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target + ) + self.on_killed(self.sim, self.target) + except Exception as ex: + self.log.error('Error occurred while running CommonSocialMixerInteraction \'{}\' 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.verbose_log.format_with_message( + 'Running on_cancelled.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target, + finishing_type=finishing_type, + cancel_reason_msg=cancel_reason_msg, + kwargles=kwargs + ) + self.on_cancelled(self.sim, self.target, finishing_type, cancel_reason_msg, **kwargs) + except Exception as ex: + self.log.error('Error occurred while running CommonSocialMixerInteraction \'{}\' cancel.'.format(self.__class__.__name__), exception=ex) + return super().cancel(finishing_type, cancel_reason_msg, **kwargs) + + def on_reset(self: 'CommonSocialMixerInteraction'): + """on_reset() + + A function that occurs upon an interaction being reset. + + """ + try: + self.verbose_log.format_with_message( + 'Running on_reset.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target + ) + self._on_reset(self.sim, self.target) + except Exception as ex: + self.log.error('Error occurred while running CommonSocialMixerInteraction \'{}\' on_reset.'.format(self.__class__.__name__), exception=ex) + return super().on_reset() + + def _post_perform(self: 'CommonSocialMixerInteraction'): + super_result = super()._post_perform() + try: + self.verbose_log.format_with_message( + 'Running on_performed.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target + ) + self.on_performed(self.sim, self.target) + except Exception as ex: + self.log.error('Error occurred while running CommonSocialMixerInteraction \'{}\' _post_perform.'.format(self.__class__.__name__), exception=ex) + return super_result + + def send_current_progress(self, *args: Any, **kwargs: Any): + """send_current_progress(*args, **kwargs) + + A function that occurs upon a progress bar update. + + """ + try: + self.verbose_log.format_with_message( + 'Running _send_current_progress.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target, + argles=args, + kwargles=kwargs + ) + result = self._send_current_progress(self.sim, self.target, *args, **kwargs) + if result is not None: + return result + except Exception as ex: + self.log.error('Error occurred while running CommonSocialMixerInteraction \'{}\' 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: + self.verbose_log.format_with_message( + 'Running _setup_asm_default.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target, + asm=asm, + argles=args, + kwargles=kwargs + ) + result = self._setup_asm_default(self.sim, self.target, asm, *args, **kwargs) + if result is not None: + return result + except Exception as ex: + self.log.error('Error occurred while running CommonSocialMixerInteraction \'{}\' setup_asm_default.'.format(self.__class__.__name__), exception=ex) + return super().setup_asm_default(asm, *args, **kwargs) + + def _run_interaction_gen(self, timeline: Timeline): + try: + self.verbose_log.format_with_message( + 'Running on_run.', + class_name=self.__class__.__name__, + interaction_sim=self.sim, + interaction_target=self.target, + timeline=timeline + ) + self.on_run(self.sim, self.target, timeline) + except Exception as ex: + self.log.error('Error occurred while running CommonSocialMixerInteraction \'{}\' on_run.'.format(self.__class__.__name__), exception=ex) + yield from super()._run_interaction_gen(timeline) + + @classmethod + def _constraint_gen(cls, sim: Sim, target: Any, participant_type: ParticipantType=ParticipantType.Actor, interaction: 'CommonSocialMixerInteraction'=None) -> Constraint: + inst_or_cls = interaction if interaction is not None else cls + try: + replacement_results = cls.on_replacement_constraints_gen(inst_or_cls, sim or inst_or_cls.sim, inst_or_cls.get_constraint_target(target) or target or inst_or_cls.target) + if replacement_results is not None: + if inspect.isgenerator(replacement_results): + yield from replacement_results + else: + yield replacement_results + else: + yield from super()._constraint_gen(sim, target, participant_type=participant_type, interaction=interaction) + result = cls.on_constraint_gen(inst_or_cls, sim or inst_or_cls.sim, inst_or_cls.get_constraint_target(target) or target or inst_or_cls.target) + if result is not None: + if inspect.isgenerator(result): + yield from result + else: + yield result + except Exception as ex: + cls.get_log().error('Error occurred while running CommonSocialMixerInteraction \'{}\' _on_constraint_gen.'.format(cls.__name__), exception=ex) diff --git a/Scripts/s4ap/sims4communitylib/classes/interactions/common_social_super_interaction.py b/Scripts/s4ap/sims4communitylib/classes/interactions/common_social_super_interaction.py new file mode 100644 index 0000000..921b3f8 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/interactions/common_social_super_interaction.py @@ -0,0 +1,518 @@ +""" +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 +""" +import inspect +from typing import Any, Union, Set + +from event_testing.tests import TestList +from interactions.base.interaction import Interaction +from sims4communitylib.classes.interactions._common_interaction_custom_mixin import _CommonInteractionCustomMixin +from sims4communitylib.classes.interactions._common_interaction_hooks_mixin import _CommonInteractionHooksMixin +from sims4communitylib.utils.misc.common_text_utils import CommonTextUtils +from singletons import DEFAULT + +from interactions import ParticipantType +from interactions.constraints import Constraint +from interactions.interaction_finisher import FinishingType +from postures.posture_state import PostureState +from protocolbuffers.Localization_pb2 import LocalizedString +from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.logging.has_class_log import HasClassLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from interactions.social.social_super_interaction import SocialSuperInteraction +from interactions.context import InteractionContext +from native.animation import NativeAsm +from scheduling import Timeline +from sims.sim import Sim +from sims4.utils import flexmethod + + +# If on Read The Docs, create fake versions of extended objects to fix the error of inheriting from multiple MockObjects. +class CommonSocialSuperInteraction(SocialSuperInteraction, HasClassLog, _CommonInteractionHooksMixin, _CommonInteractionCustomMixin): + """CommonSocialSuperInteraction(*_, **__) + + An inheritable class that provides a way to create Custom Social Super Interactions. + + .. note:: + + The main use for this class is to create interactions that wrap sub interactions. + + .. 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! + + :Example: + + .. highlight:: python + .. code-block:: python + + # The following is an example interaction that varies when it will display, when it will be hidden, and when it will be disabled with a tooltip. + class _ExampleInteraction(CommonSocialSuperInteraction): + @classmethod + def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, interaction=None, **kwargs) -> TestResult: + result = 1 + 1 + if result == 2: + # Interaction will be displayed, but disabled, it will also have a tooltip that displays on hover with the text "Test Tooltip" + return cls.create_test_result(False, reason="Test Tooltip") + # Alternative way to specify a tooltip with the text "Test Tooltip" + # return cls.create_test_result(False, reason="No Reason", tooltip=CommonLocalizationUtils.create_localized_tooltip("Test Tooltip")) + if result == 3: + # Interaction will be hidden completely. + return CommonTestResult.NONE + # Interaction will display and be enabled. + return CommonTestResult.TRUE + + # Instead of on_started, SocialSuperInteractions use on_run. + def on_run(self, interaction_sim: Sim, interaction_target: Any, timeline: Timeline) -> bool: + result = True + if not result: + return False + # Put here what you want the interaction to do as soon as the player clicks it while it is enabled. + return True + + def on_cancelled(self, interaction_sim: Sim, interaction_target: Any, finishing_type: FinishingType, cancel_reason_msg: str, **kwargs): + result = True + if not result: + return False + # Put here what you want the interaction to do as soon as the player clicks it while it is enabled. + return True + + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> Union[CommonModIdentity, None]: + return None + + def __init__(self, *_: Any, **__: Any): + super().__init__(*_, **__) + HasClassLog.__init__(self) + + # noinspection PyMethodParameters + @flexmethod + def _test(cls, inst: 'CommonSocialSuperInteraction', target: Any, context: InteractionContext, super_interaction: 'Interaction'=None, skip_safe_tests: bool=False, **kwargs): + from event_testing.results import TestResult + from sims4communitylib.classes.time.common_stop_watch import CommonStopWatch + inst_or_cls = inst or cls + log = cls.get_log() + verbose_log = cls.get_verbose_log() + stop_watch = CommonStopWatch() + if verbose_log.enabled: + stop_watch.start() + try: + try: + verbose_log.format_with_message( + 'Running on_test.', + class_name=cls.__name__, + inst=inst, + interaction_sim=context.sim, + interaction_target=target, + interaction_context=context, + super_interaction=super_interaction, + skip_safe_tests=skip_safe_tests, + kwargles=kwargs + ) + test_result = cls.on_test(context.sim, target, context, interaction=inst, super_interaction=super_interaction, skip_safe_tests=skip_safe_tests, **kwargs) + verbose_log.format_with_message('Test Result (CommonSocialSuperInteraction)', test_result=test_result) + except Exception as ex: + log.error('Error occurred while running CommonSocialSuperInteraction \'{}\' on_test.'.format(cls.__name__), exception=ex) + return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') + + if test_result is not None: + if isinstance(test_result, CommonTestResult): + if test_result.is_success is False: + return test_result + elif isinstance(test_result, TestResult) and 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, icon=test_result.icon, influence_by_active_mood=test_result.influence_by_active_mood) + + try: + verbose_log.format_with_message( + 'Running super()._test.', + class_name=cls.__name__, + inst=inst, + interaction_sim=context.sim, + interaction_target=target, + interaction_context=context, + super_interaction=super_interaction, + skip_safe_tests=skip_safe_tests, + kwargles=kwargs + ) + super_test_result: TestResult = super(CommonSocialSuperInteraction, inst_or_cls)._test(target, context, super_interaction=super_interaction, skip_safe_tests=skip_safe_tests, **kwargs) + + if verbose_log.enabled: + search_for_tooltip = context.source == context.SOURCE_PIE_MENU + resolver = inst_or_cls.get_resolver(target=target, context=context, super_interaction=super_interaction, search_for_tooltip=search_for_tooltip, **kwargs) + global_result = cls.test_globals.run_tests(resolver, skip_safe_tests, search_for_tooltip=search_for_tooltip) + local_result = cls.tests.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=search_for_tooltip) + if inst_or_cls._additional_tests: + additional_tests = TestList(inst_or_cls._additional_tests) + additional_local_result = additional_tests.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=search_for_tooltip) + else: + additional_local_result = None + if inst_or_cls.test_autonomous: + autonomous_result = cls.test_autonomous.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=False) + else: + autonomous_result = None + if target is not None: + tests = target.get_affordance_tests(inst_or_cls) + if tests is not None: + target_result = tests.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=search_for_tooltip) + else: + target_result = None + else: + target_result = None + verbose_log.format_with_message('Super Test Result (CommonSocialSuperInteraction)', super_test_result=super_test_result, global_result=global_result, local_result=local_result, additional_local_result=additional_local_result, autonomous_result=autonomous_result, target_result=target_result) + + if super_test_result is not None and (isinstance(test_result, TestResult) and not super_test_result.result): + return CommonTestResult.convert_from_vanilla(super_test_result) + except Exception as ex: + log.error('Error occurred while running CommonSocialSuperInteraction \'{}\' super()._test.'.format(cls.__name__), exception=ex) + return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') + + try: + verbose_log.format_with_message( + 'Running on_post_super_test.', + class_name=cls.__name__, + inst=inst, + interaction_sim=context.sim, + interaction_target=target, + interaction_context=context, + super_interaction=super_interaction, + skip_safe_tests=skip_safe_tests, + kwargles=kwargs + ) + post_super_test_result = cls.on_post_super_test(context.sim, target, context, interaction=inst, super_interaction=super_interaction, skip_safe_tests=skip_safe_tests, **kwargs) + verbose_log.format_with_message('Post Test Result (CommonSocialSuperInteraction)', post_super_test_result=post_super_test_result) + except Exception as ex: + log.error('Error occurred while running CommonSocialSuperInteraction \'{}\' on_post_super_test.'.format(cls.__name__), exception=ex) + return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') + + if post_super_test_result is not None: + if isinstance(post_super_test_result, CommonTestResult): + if post_super_test_result.is_success is False: + return post_super_test_result + elif isinstance(post_super_test_result, TestResult) and post_super_test_result.result is False: + if post_super_test_result.tooltip is not None: + post_super_test_result_tooltip = CommonLocalizationUtils.create_localized_tooltip(post_super_test_result.tooltip) + elif post_super_test_result.reason is not None: + post_super_test_result_tooltip = CommonLocalizationUtils.create_localized_tooltip(post_super_test_result.reason) + else: + post_super_test_result_tooltip = None + return cls.create_test_result(post_super_test_result.result, post_super_test_result.reason, tooltip=post_super_test_result_tooltip, icon=post_super_test_result.icon, influence_by_active_mood=post_super_test_result.influence_by_active_mood) + + return cls.create_test_result(True) + except Exception as ex: + log.error('Error occurred while running _test of CommonSocialSuperInteraction \'{}\''.format(cls.__name__), exception=ex) + return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') + finally: + if verbose_log.enabled: + time_taken = CommonTextUtils.to_truncated_decimal(stop_watch.stop_milliseconds()) + verbose_log.format_with_message(f'Took {time_taken}ms to return result from CommonSocialSuperInteraction.', class_name=cls.__name__) + else: + stop_watch.stop() + + # noinspection PyMissingOrEmptyDocstring,PyMethodParameters + @flexmethod + def get_participants(cls, inst, participant_type: ParticipantType, sim=DEFAULT, target=DEFAULT, carry_target=DEFAULT, **kwargs): + inst_or_cls = inst or cls + log = cls.get_log() + try: + custom_participants = cls.get_custom_replacement_participants(participant_type, sim, target, carry_target, interaction=inst, **kwargs) + if custom_participants is not None: + return tuple(custom_participants) + except Exception as ex: + log.error('Error occurred while running CommonSocialSuperInteraction \'{}\' get_custom_replacement_participants.'.format(cls.__name__), exception=ex) + + result: Set[Any] = super(CommonSocialSuperInteraction, inst_or_cls).get_participants(participant_type, sim=sim, target=target, carry_target=carry_target, **kwargs) + + result = set(result) + try: + custom_participants = cls.get_custom_participants(participant_type, sim, target, carry_target, interaction=inst, **kwargs) + result.update(custom_participants) + except Exception as ex: + log.error('Error occurred while running CommonSocialSuperInteraction \'{}\' get_custom_participants.'.format(cls.__name__), exception=ex) + return tuple(result) + + # noinspection PyMethodParameters,PyMissingOrEmptyDocstring + @flexmethod + def get_name(cls, inst: 'CommonSocialSuperInteraction', target: Any=DEFAULT, context: InteractionContext=DEFAULT, **interaction_parameters) -> LocalizedString: + inst_or_cls = inst or cls + try: + context_inst_or_cls = context or inst_or_cls + interaction_sim = context_inst_or_cls.sim + interaction_target = target or context_inst_or_cls.target + + cls.get_verbose_log().format_with_message( + 'Running get_name.', + class_name=cls.__name__, + interaction_sim=interaction_sim, + interaction_target=interaction_target, + interaction=inst, + interaction_context=context + ) + override_name = cls._create_override_display_name( + interaction_sim, + interaction_target, + interaction=inst, + interaction_context=context, + **interaction_parameters + ) + if override_name is not None: + return override_name + except Exception as ex: + cls.get_log().error('An error occurred while running get_name of CommonSocialSuperInteraction {}'.format(cls.__name__), exception=ex) + result = super(CommonSocialSuperInteraction, inst_or_cls).get_name(target=target, context=context, **interaction_parameters) + if result is None: + cls.get_log().error(f'Missing a name for interaction {cls.__name__}', throw=True) + return result + + def _trigger_interaction_start_event(self: 'CommonSocialSuperInteraction'): + try: + self.verbose_log.format_with_message( + 'Running on_started.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target + ) + result = self.on_started(self.sim, self.target) + if result is not None and ((isinstance(result, CommonExecutionResult) and not result.is_success) or (isinstance(result, bool) and not result)): + self.cancel(FinishingType.CONDITIONAL_EXIT, str(result)) + return False + return super()._trigger_interaction_start_event() + except Exception as ex: + self.log.error('Error occurred while running CommonSocialSuperInteraction \'{}\' 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: + self.verbose_log.format_with_message( + 'Running modify_posture_state.', + class_name=self.__class__.__name__, + posture_state=posture_state, + participant_type=participant_type, + sim=sim + ) + (new_posture_state, new_participant_type, new_sim) = self.modify_posture_state(posture_state, participant_type=participant_type, sim=sim) + except Exception as ex: + self.log.error('Error occurred while running CommonSocialSuperInteraction \'{}\' 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.verbose_log.format_with_message( + 'Running on_killed.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target + ) + self.on_killed(self.sim, self.target) + except Exception as ex: + self.log.error('Error occurred while running CommonSocialSuperInteraction \'{}\' on_killed.'.format(self.__class__.__name__), exception=ex) + return super().kill() + + # noinspection PyMethodOverriding + 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.verbose_log.format_with_message( + 'Running on_cancelled.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target, + finishing_type=finishing_type, + cancel_reason_msg=cancel_reason_msg, + kwargles=kwargs + ) + self.on_cancelled(self.sim, self.target, finishing_type, cancel_reason_msg, **kwargs) + except Exception as ex: + self.log.error('Error occurred while running CommonSocialSuperInteraction \'{}\' cancel.'.format(self.__class__.__name__), exception=ex) + return super()._cancel(finishing_type, cancel_reason_msg, **kwargs) + + def on_reset(self: 'CommonSocialSuperInteraction'): + """on_reset() + + A function that occurs upon an interaction being reset. + + """ + try: + self.verbose_log.format_with_message( + 'Running on_reset.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target + ) + self._on_reset(self.sim, self.target) + except Exception as ex: + self.log.error('Error occurred while running CommonSocialSuperInteraction \'{}\' on_reset.'.format(self.__class__.__name__), exception=ex) + return super().on_reset() + + def _post_perform(self: 'CommonSocialSuperInteraction'): + super_result = super()._post_perform() + try: + self.verbose_log.format_with_message( + 'Running on_performed.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target + ) + self.on_performed(self.sim, self.target) + except Exception as ex: + self.log.error('Error occurred while running CommonSocialSuperInteraction \'{}\' _post_perform.'.format(self.__class__.__name__), exception=ex) + return super_result + + def send_current_progress(self, *args: Any, **kwargs: Any): + """send_current_progress(*args, **kwargs) + + A function that occurs upon a progress bar update. + + """ + try: + self.verbose_log.format_with_message( + 'Running _send_current_progress.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target, + argles=args, + kwargles=kwargs + ) + result = self._send_current_progress(self.sim, self.target, *args, **kwargs) + if result is not None: + return result + except Exception as ex: + self.log.error('Error occurred while running CommonSocialSuperInteraction \'{}\' 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: + self.verbose_log.format_with_message( + 'Running _setup_asm_default.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target, + asm=asm, + argles=args, + kwargles=kwargs + ) + result = self._setup_asm_default(self.sim, self.target, asm, *args, **kwargs) + if result is not None: + return result + except Exception as ex: + self.log.error('Error occurred while running CommonSocialSuperInteraction \'{}\' setup_asm_default.'.format(self.__class__.__name__), exception=ex) + return super().setup_asm_default(asm, *args, **kwargs) + + def _run_interaction_gen(self, timeline: Timeline): + try: + self.verbose_log.format_with_message( + 'Running on_run.', + class_name=self.__class__.__name__, + interaction_sim=self.sim, + interaction_target=self.target, + timeline=timeline + ) + self.on_run(self.sim, self.target, timeline) + except Exception as ex: + self.log.error('Error occurred while running CommonSocialSuperInteraction \'{}\' on_run.'.format(self.__class__.__name__), exception=ex) + yield from super()._run_interaction_gen(timeline) + + # noinspection PyMethodParameters + @flexmethod + def _constraint_gen(cls, inst: 'CommonSocialSuperInteraction', sim: Sim, target: Any, participant_type: ParticipantType=ParticipantType.Actor, **kwargs) -> Constraint: + inst_or_cls = inst if inst is not None else cls + try: + replacement_results = cls.on_replacement_constraints_gen(inst_or_cls, sim or inst_or_cls.sim, inst_or_cls.get_constraint_target(target) or target or inst_or_cls.target) + if replacement_results is not None: + if inspect.isgenerator(replacement_results): + yield from replacement_results + else: + yield replacement_results + else: + yield from super(CommonSocialSuperInteraction, inst_or_cls)._constraint_gen(sim, target, participant_type=participant_type, **kwargs) + result = cls.on_constraint_gen(inst_or_cls, sim or inst_or_cls.sim, inst_or_cls.get_constraint_target(target) or target or inst_or_cls.target) + if result is not None: + if inspect.isgenerator(result): + yield from result + else: + yield result + except Exception as ex: + cls.get_log().error('Error occurred while running CommonSocialSuperInteraction \'{}\' _on_constraint_gen.'.format(cls.__name__), exception=ex) + + # The following functions are hooks into various parts of an interaction override them in your own interaction to provide custom functionality. + + # noinspection PyUnusedLocal + @classmethod + def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, *args, interaction: 'Interaction'=None, **kwargs) -> CommonTestResult: + """on_test(interaction_sim, interaction_target, interaction_context, *args, interaction=None, **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 + :param interaction: The interaction being tested or None. Default is None. + :type interaction: Interaction, optional + :return: The outcome of testing the availability of the interaction + :rtype: CommonTestResult + """ + return super().on_test(interaction_sim, interaction_target, interaction_context, *args, interaction=interaction, **kwargs) + + # noinspection PyUnusedLocal + @classmethod + def on_post_super_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, *args, interaction: 'Interaction'=None, **kwargs) -> CommonTestResult: + """on_post_super_test(interaction_sim, interaction_target, interaction_context, *args, interaction=None, **kwargs) + + A hook that occurs after the interaction being tested for availability by on_test and the super _test functions. + + .. note:: This will only run if both on_test and _test returns CommonTestResult.TRUE or similar. + + :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 + :param interaction: The interaction being tested or None. Default is None. + :type interaction: Interaction, optional + :return: The outcome of testing the availability of the interaction + :rtype: CommonTestResult + """ + return super().on_post_super_test(interaction_sim, interaction_target, interaction_context, *args, interaction=interaction, **kwargs) diff --git a/Scripts/s4ap/sims4communitylib/classes/interactions/common_super_interaction.py b/Scripts/s4ap/sims4communitylib/classes/interactions/common_super_interaction.py new file mode 100644 index 0000000..f6548af --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/interactions/common_super_interaction.py @@ -0,0 +1,894 @@ +""" +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 +""" +import inspect +from typing import Any, Union, Set + +from event_testing.tests import TestList +from interactions import ParticipantType +from interactions.base.interaction import Interaction +from interactions.constraints import Constraint +from interactions.context import InteractionContext +from interactions.interaction_finisher import FinishingType +from native.animation import NativeAsm +from postures.posture_state import PostureState +from protocolbuffers.Localization_pb2 import LocalizedString +from sims4communitylib.classes.interactions._common_interaction_custom_mixin import _CommonInteractionCustomMixin +from sims4communitylib.classes.interactions._common_interaction_hooks_mixin import _CommonInteractionHooksMixin +from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.logging.has_class_log import HasClassLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from sims4communitylib.utils.misc.common_text_utils import CommonTextUtils +from singletons import DEFAULT +from interactions.base.super_interaction import SuperInteraction +from scheduling import Timeline +from sims4.utils import flexmethod +from sims.sim import Sim + + +class CommonBaseSuperInteraction(SuperInteraction, HasClassLog, _CommonInteractionHooksMixin, _CommonInteractionCustomMixin): + """CommonBaseSuperInteraction(*_, **__) + + An inheritable class that provides a way to create custom Super Interactions. + + .. note:: Use this Base class when you don't wish _run_interaction_gen to be overridden. + + .. note:: + + The main use for this class is to create interactions that wrap sub interactions. + One example Super interaction is the `sim-chat` interaction, where other interactions (Such as the `Get To Know` interaction), run as sub interactions of `sim-chat` + + .. 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! + + :Example: + + .. highlight:: python + .. code-block:: python + + # The following is an example interaction that varies when it will display, when it will be hidden, and when it will be disabled with a tooltip. + class _ExampleInteraction(CommonBaseSuperInteraction): + @classmethod + def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, **kwargs) -> CommonTestResult: + result = 1 + 1 + if result == 2: + # Interaction will be displayed, but disabled, it will also have a tooltip that displays on hover with the text "Test Tooltip" + return cls.create_test_result(False, reason="Test Tooltip") + # Alternative way to specify a tooltip with the text "Test Tooltip" + # return cls.create_test_result(False, reason="No Reason", tooltip=CommonLocalizationUtils.create_localized_tooltip("Test Tooltip")) + if result == 3: + # Interaction will be hidden completely. + return CommonTestResult.NONE + # Interaction will display and be enabled. + return CommonTestResult.TRUE + + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> Union[CommonModIdentity, None]: + return None + + def __init__(self, *_: Any, **__: Any): + super().__init__(*_, **__) + HasClassLog.__init__(self) + + +class CommonSuperInteraction(CommonBaseSuperInteraction): + """CommonSuperInteraction(*_, **__) + + An inheritable class that provides a way to create custom Super Interactions. + + .. note:: + + The main use for this class is to create interactions that wrap sub interactions. + One example Super interaction is the `sim-chat` interaction, where other interactions (Such as the `Get To Know` interaction), run as sub interactions of `sim-chat` + + .. 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! + + :Example: + + .. highlight:: python + .. code-block:: python + + # The following is an example interaction that varies when it will display, when it will be hidden, and when it will be disabled with a tooltip. + class _ExampleInteraction(CommonSuperInteraction): + @classmethod + def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, **kwargs) -> CommonTestResult: + result = 1 + 1 + if result == 2: + # Interaction will be displayed, but disabled, it will also have a tooltip that displays on hover with the text "Test Tooltip" + return cls.create_test_result(False, reason="Test Tooltip") + # Alternative way to specify a tooltip with the text "Test Tooltip" + # return cls.create_test_result(False, reason="No Reason", tooltip=CommonLocalizationUtils.create_localized_tooltip("Test Tooltip")) + if result == 3: + # Interaction will be hidden completely. + return CommonTestResult.NONE + # Interaction will display and be enabled. + return CommonTestResult.TRUE + + # Instead of on_started, SuperInteractions use on_run. + def on_run(self, interaction_sim: Sim, interaction_target: Any: timeline: Timeline) -> bool: + result = True + if not result: + return False + # Put here what you want the interaction to do as soon as the player clicks it while it is enabled. + return True + """ + + @classmethod + def _test(cls, target: Any, context: InteractionContext, super_interaction: 'Interaction'=None, skip_safe_tests: bool=False, **kwargs) -> CommonTestResult: + from event_testing.results import TestResult + from sims4communitylib.classes.time.common_stop_watch import CommonStopWatch + log = cls.get_log() + verbose_log = cls.get_verbose_log() + stop_watch = CommonStopWatch() + if verbose_log.enabled: + stop_watch.start() + try: + try: + verbose_log.format_with_message( + 'Running on_test.', + class_name=cls.__name__, + interaction_sim=context.sim, + interaction_target=target, + interaction_context=context, + super_interaction=super_interaction, + skip_safe_tests=skip_safe_tests, + kwargles=kwargs + ) + test_result = cls.on_test(context.sim, target, context, super_interaction=super_interaction, skip_safe_tests=skip_safe_tests, **kwargs) + verbose_log.format_with_message('Test Result (CommonSuperInteraction)', test_result=test_result) + except Exception as ex: + log.error('Error occurred while running CommonSuperInteraction \'{}\' on_test.'.format(cls.__name__), exception=ex) + return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') + + if test_result is not None: + if isinstance(test_result, CommonTestResult): + if test_result.is_success is False: + return test_result + elif isinstance(test_result, TestResult) and 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, icon=test_result.icon, influence_by_active_mood=test_result.influence_by_active_mood) + + try: + verbose_log.format_with_message( + 'Running super()._test.', + class_name=cls.__name__, + interaction_sim=context.sim, + interaction_target=target, + interaction_context=context, + super_interaction=super_interaction, + skip_safe_tests=skip_safe_tests, + kwargles=kwargs + ) + super_test_result: TestResult = super()._test(target, context, super_interaction=super_interaction, skip_safe_tests=skip_safe_tests, **kwargs) + + if verbose_log.enabled: + search_for_tooltip = context.source == context.SOURCE_PIE_MENU + resolver = cls.get_resolver(target=target, context=context, super_interaction=super_interaction, search_for_tooltip=search_for_tooltip, **kwargs) + global_result = cls.test_globals.run_tests(resolver, skip_safe_tests, search_for_tooltip=search_for_tooltip) + local_result = cls.tests.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=search_for_tooltip) + if cls._additional_tests: + additional_tests = TestList(cls._additional_tests) + additional_local_result = additional_tests.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=search_for_tooltip) + else: + additional_local_result = None + if cls.test_autonomous: + autonomous_result = cls.test_autonomous.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=False) + else: + autonomous_result = None + if target is not None: + tests = target.get_affordance_tests(cls) + if tests is not None: + target_result = tests.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=search_for_tooltip) + else: + target_result = None + else: + target_result = None + verbose_log.format_with_message('Super Test Result (CommonSuperInteraction)', super_test_result=super_test_result, global_result=global_result, local_result=local_result, additional_local_result=additional_local_result, autonomous_result=autonomous_result, target_result=target_result) + + if super_test_result is not None and (isinstance(test_result, TestResult) and not super_test_result.result): + return CommonTestResult.convert_from_vanilla(super_test_result) + except Exception as ex: + log.error('Error occurred while running CommonSuperInteraction \'{}\' super()._test.'.format(cls.__name__), exception=ex) + return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') + + try: + verbose_log.format_with_message( + 'Running on_post_super_test.', + class_name=cls.__name__, + interaction_sim=context.sim, + interaction_target=target, + interaction_context=context, + super_interaction=super_interaction, + skip_safe_tests=skip_safe_tests, + kwargles=kwargs + ) + post_super_test_result = cls.on_post_super_test(context.sim, target, context, super_interaction=super_interaction, skip_safe_tests=skip_safe_tests, **kwargs) + verbose_log.format_with_message('Post Test Result (CommonSuperInteraction)', post_super_test_result=post_super_test_result) + except Exception as ex: + log.error('Error occurred while running CommonSuperInteraction \'{}\' on_post_super_test.'.format(cls.__name__), exception=ex) + return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') + + if post_super_test_result is not None: + if isinstance(post_super_test_result, CommonTestResult): + if post_super_test_result.is_success is False: + return post_super_test_result + elif isinstance(post_super_test_result, TestResult) and post_super_test_result.result is False: + if post_super_test_result.tooltip is not None: + post_super_test_result_tooltip = CommonLocalizationUtils.create_localized_tooltip(post_super_test_result.tooltip) + elif post_super_test_result.reason is not None: + post_super_test_result_tooltip = CommonLocalizationUtils.create_localized_tooltip(post_super_test_result.reason) + else: + post_super_test_result_tooltip = None + return cls.create_test_result(post_super_test_result.result, post_super_test_result.reason, tooltip=post_super_test_result_tooltip, icon=post_super_test_result.icon, influence_by_active_mood=post_super_test_result.influence_by_active_mood) + + return cls.create_test_result(True) + except Exception as ex: + log.error('Error occurred while running _test of CommonSuperInteraction \'{}\''.format(cls.__name__), exception=ex) + return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') + finally: + if verbose_log.enabled: + time_taken = CommonTextUtils.to_truncated_decimal(stop_watch.stop_milliseconds()) + verbose_log.format_with_message(f'Took {time_taken}ms to return result from CommonSuperInteraction.', class_name=cls.__name__) + else: + stop_watch.stop() + + # noinspection PyMissingOrEmptyDocstring,PyMethodParameters + @flexmethod + def get_participants(cls, inst, participant_type: ParticipantType, sim=DEFAULT, target=DEFAULT, carry_target=DEFAULT, **kwargs): + inst_or_cls = inst or cls + log = cls.get_log() + try: + custom_participants = cls.get_custom_replacement_participants(participant_type, sim, target, carry_target, interaction=inst, **kwargs) + if custom_participants is not None: + return tuple(custom_participants) + except Exception as ex: + log.error('Error occurred while running CommonSuperInteraction \'{}\' get_custom_replacement_participants.'.format(cls.__name__), exception=ex) + + result: Set[Any] = super(CommonSuperInteraction, inst_or_cls).get_participants(participant_type, sim=sim, target=target, carry_target=carry_target, **kwargs) + + result = set(result) + try: + custom_participants = cls.get_custom_participants(participant_type, sim, target, carry_target, interaction=inst, **kwargs) + result.update(custom_participants) + except Exception as ex: + log.error('Error occurred while running CommonSuperInteraction \'{}\' get_custom_participants.'.format(cls.__name__), exception=ex) + return tuple(result) + + # noinspection PyMethodParameters,PyMissingOrEmptyDocstring + @flexmethod + def get_name(cls, inst: 'CommonSuperInteraction', target: Any=DEFAULT, context: InteractionContext=DEFAULT, **interaction_parameters) -> LocalizedString: + inst_or_cls = inst or cls + try: + context_inst_or_cls = context or inst_or_cls + interaction_sim = context_inst_or_cls.sim + interaction_target = target or context_inst_or_cls.target + + cls.get_verbose_log().format_with_message( + 'Running get_name.', + class_name=cls.__name__, + interaction_sim=interaction_sim, + interaction_target=interaction_target, + interaction=inst, + interaction_context=context + ) + override_name = cls._create_override_display_name( + interaction_sim, + interaction_target, + interaction=inst, + interaction_context=context, + **interaction_parameters + ) + if override_name is not None: + return override_name + except Exception as ex: + cls.get_log().error('An error occurred while running get_name of CommonSuperInteraction {}'.format(cls.__name__), exception=ex) + result = super(CommonSuperInteraction, inst_or_cls).get_name(target=target, context=context, **interaction_parameters) + if result is None: + cls.get_log().error(f'Missing a name for interaction {cls.__name__}', throw=True) + return result + + def _trigger_interaction_start_event(self: 'CommonSuperInteraction'): + try: + self.verbose_log.format_with_message( + 'Running on_started.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target + ) + result = self.on_started(self.sim, self.target) + if result is not None and ((isinstance(result, CommonExecutionResult) and not result.is_success) or (isinstance(result, bool) and not result)): + self.cancel(FinishingType.CONDITIONAL_EXIT, str(result)) + return False + return super()._trigger_interaction_start_event() + except Exception as ex: + self.log.error('Error occurred while running CommonSuperInteraction \'{}\' 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: + self.verbose_log.format_with_message( + 'Running modify_posture_state.', + class_name=self.__class__.__name__, + posture_state=posture_state, + participant_type=participant_type, + sim=sim + ) + (new_posture_state, new_participant_type, new_sim) = self.modify_posture_state(posture_state, participant_type=participant_type, sim=sim) + except Exception as ex: + self.log.error('Error occurred while running CommonSuperInteraction \'{}\' 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.verbose_log.format_with_message( + 'Running on_killed.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target + ) + self.on_killed(self.sim, self.target) + except Exception as ex: + self.log.error('Error occurred while running CommonSuperInteraction \'{}\' 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.verbose_log.format_with_message( + 'Running on_cancelled.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target, + finishing_type=finishing_type, + cancel_reason_msg=cancel_reason_msg, + kwargles=kwargs + ) + self.on_cancelled(self.sim, self.target, finishing_type, cancel_reason_msg, **kwargs) + except Exception as ex: + self.log.error('Error occurred while running CommonSuperInteraction \'{}\' _cancel.'.format(self.__class__.__name__), exception=ex) + return super()._cancel(finishing_type, cancel_reason_msg, **kwargs) + + def on_reset(self: 'CommonSuperInteraction'): + """on_reset() + + A function that occurs upon an interaction being reset. + + """ + try: + self.verbose_log.format_with_message( + 'Running on_reset.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target + ) + self._on_reset(self.sim, self.target) + except Exception as ex: + self.log.error('Error occurred while running CommonSuperInteraction \'{}\' on_reset.'.format(self.__class__.__name__), exception=ex) + return super().on_reset() + + def _post_perform(self: 'CommonSuperInteraction'): + super_result = super()._post_perform() + try: + self.verbose_log.format_with_message( + 'Running on_performed.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target + ) + self.on_performed(self.sim, self.target) + except Exception as ex: + self.log.error('Error occurred while running CommonSuperInteraction \'{}\' _post_perform.'.format(self.__class__.__name__), exception=ex) + return super_result + + def send_current_progress(self, *args: Any, **kwargs: Any): + """send_current_progress(*args, **kwargs) + + A function that occurs upon a progress bar update. + + """ + try: + self.verbose_log.format_with_message( + 'Running _send_current_progress.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target, + argles=args, + kwargles=kwargs + ) + result = self._send_current_progress(self.sim, self.target, *args, **kwargs) + if result is not None: + return result + except Exception as ex: + self.log.error('Error occurred while running CommonSuperInteraction \'{}\' 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: + self.verbose_log.format_with_message( + 'Running _setup_asm_default.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target, + asm=asm, + argles=args, + kwargles=kwargs + ) + result = self._setup_asm_default(self.sim, self.target, asm, *args, **kwargs) + if result is not None: + return result + except Exception as ex: + self.log.error('Error occurred while running CommonSuperInteraction \'{}\' setup_asm_default.'.format(self.__class__.__name__), exception=ex) + return super().setup_asm_default(asm, *args, **kwargs) + + def _run_interaction_gen(self, timeline: Timeline): + try: + self.verbose_log.format_with_message( + 'Running on_run.', + class_name=self.__class__.__name__, + interaction_sim=self.sim, + interaction_target=self.target, + timeline=timeline + ) + self.on_run(self.sim, self.target, timeline) + except Exception as ex: + self.log.error('Error occurred while running CommonSuperInteraction \'{}\' on_run.'.format(self.__class__.__name__), exception=ex) + yield from super()._run_interaction_gen(timeline) + + @classmethod + def _tuning_loaded_callback(cls) -> Any: + if isinstance(cls.basic_content, str): + from interactions.base.basic import NoContent + cls.basic_content = NoContent(allow_holster=None, allow_with_unholsterable_object=False, route_to_location=None) + return super()._tuning_loaded_callback() + + # noinspection PyMethodParameters + @flexmethod + def _constraint_gen(cls, inst: 'CommonSuperInteraction', sim: Sim, target: Any, participant_type: ParticipantType=ParticipantType.Actor, **kwargs) -> Constraint: + inst_or_cls = inst if inst is not None else cls + try: + replacement_results = cls.on_replacement_constraints_gen(inst_or_cls, sim or inst_or_cls.sim, inst_or_cls.get_constraint_target(target) or target or inst_or_cls.target) + if replacement_results is not None: + if inspect.isgenerator(replacement_results): + yield from replacement_results + else: + yield replacement_results + else: + yield from super(CommonSuperInteraction, inst_or_cls)._constraint_gen(sim, target, participant_type=participant_type, **kwargs) + result = cls.on_constraint_gen(inst_or_cls, sim or inst_or_cls.sim, inst_or_cls.get_constraint_target(target) or target or inst_or_cls.target) + if result is not None: + if inspect.isgenerator(result): + yield from result + else: + yield result + except Exception as ex: + cls.get_log().error('Error occurred while running CommonSuperInteraction \'{}\' _on_constraint_gen.'.format(cls.__name__), exception=ex) + + +class CommonConstrainedSuperInteraction(SuperInteraction, HasClassLog): + """An inheritable class that provides a way to create custom Super Interactions that provide custom constraints. + + .. warning:: This class is obsolete. All interaction types come with their own :func:`~on_replacement_constraints_gen` and :func:`~on_constraint_gen` functions. 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) -> Union[CommonModIdentity, None]: + return None + + def __init__(self, *_: Any, **__: Any): + super().__init__(*_, **__) + HasClassLog.__init__(self) + + @classmethod + def _test(cls, target: Any, context: InteractionContext, super_interaction: 'Interaction'=None, skip_safe_tests: bool=False, **kwargs) -> CommonTestResult: + from event_testing.results import TestResult + from sims4communitylib.classes.time.common_stop_watch import CommonStopWatch + log = cls.get_log() + verbose_log = cls.get_verbose_log() + stop_watch = CommonStopWatch() + stop_watch.start() + try: + try: + verbose_log.format_with_message( + 'Running on_test.', + class_name=cls.__name__, + interaction_sim=context.sim, + interaction_target=target, + interaction_context=context, + super_interaction=super_interaction, + skip_safe_tests=skip_safe_tests, + kwargles=kwargs + ) + test_result = cls.on_test(context.sim, target, context, super_interaction=super_interaction, skip_safe_tests=skip_safe_tests, **kwargs) + verbose_log.format_with_message('Test Result (CommonConstrainedSuperInteraction)', test_result=test_result) + except Exception as ex: + log.error('Error occurred while running CommonConstrainedSuperInteraction \'{}\' on_test.'.format(cls.__name__), exception=ex) + return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') + + if test_result is not None: + if isinstance(test_result, CommonTestResult): + if test_result.is_success is False: + return test_result + elif isinstance(test_result, TestResult) and 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, icon=test_result.icon, influence_by_active_mood=test_result.influence_by_active_mood) + + try: + verbose_log.format_with_message( + 'Running super()._test.', + class_name=cls.__name__, + interaction_sim=context.sim, + interaction_target=target, + interaction_context=context, + super_interaction=super_interaction, + skip_safe_tests=skip_safe_tests, + kwargles=kwargs + ) + super_test_result: TestResult = super()._test(target, context, super_interaction=super_interaction, skip_safe_tests=skip_safe_tests, **kwargs) + if verbose_log.enabled: + search_for_tooltip = context.source == context.SOURCE_PIE_MENU + resolver = cls.get_resolver(target=target, context=context, super_interaction=super_interaction, search_for_tooltip=search_for_tooltip, **kwargs) + global_result = cls.test_globals.run_tests(resolver, skip_safe_tests, search_for_tooltip=search_for_tooltip) + local_result = cls.tests.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=search_for_tooltip) + if cls._additional_tests: + additional_tests = TestList(cls._additional_tests) + additional_local_result = additional_tests.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=search_for_tooltip) + else: + additional_local_result = None + if cls.test_autonomous: + autonomous_result = cls.test_autonomous.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=False) + else: + autonomous_result = None + if target is not None: + tests = target.get_affordance_tests(cls) + if tests is not None: + target_result = tests.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=search_for_tooltip) + else: + target_result = None + else: + target_result = None + verbose_log.format_with_message('Super Test Result (CommonConstrainedSuperInteraction)', super_test_result=super_test_result, global_result=global_result, local_result=local_result, additional_local_result=additional_local_result, autonomous_result=autonomous_result, target_result=target_result) + + if super_test_result is not None and (isinstance(test_result, TestResult) and not super_test_result.result): + return CommonTestResult.convert_from_vanilla(super_test_result) + except Exception as ex: + log.error('Error occurred while running CommonConstrainedSuperInteraction \'{}\' super()._test.'.format(cls.__name__), exception=ex) + return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') + + try: + verbose_log.format_with_message( + 'Running on_post_super_test.', + class_name=cls.__name__, + interaction_sim=context.sim, + interaction_target=target, + interaction_context=context, + super_interaction=super_interaction, + skip_safe_tests=skip_safe_tests, + kwargles=kwargs + ) + post_super_test_result = cls.on_post_super_test(context.sim, target, context, super_interaction=super_interaction, skip_safe_tests=skip_safe_tests, **kwargs) + verbose_log.format_with_message('Post Test Result (CommonConstrainedSuperInteraction)', post_super_test_result=post_super_test_result) + except Exception as ex: + log.error('Error occurred while running CommonConstrainedSuperInteraction \'{}\' on_post_super_test.'.format(cls.__name__), exception=ex) + return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') + + if post_super_test_result is not None: + if isinstance(post_super_test_result, CommonTestResult): + if post_super_test_result.is_success is False: + return post_super_test_result + elif isinstance(post_super_test_result, TestResult) and post_super_test_result.result is False: + if post_super_test_result.tooltip is not None: + post_super_test_result_tooltip = CommonLocalizationUtils.create_localized_tooltip(post_super_test_result.tooltip) + elif post_super_test_result.reason is not None: + post_super_test_result_tooltip = CommonLocalizationUtils.create_localized_tooltip(post_super_test_result.reason) + else: + post_super_test_result_tooltip = None + return cls.create_test_result(post_super_test_result.result, post_super_test_result.reason, tooltip=post_super_test_result_tooltip, icon=post_super_test_result.icon, influence_by_active_mood=post_super_test_result.influence_by_active_mood) + + return cls.create_test_result(True) + except Exception as ex: + log.error('Error occurred while running _test of CommonConstrainedSuperInteraction \'{}\''.format(cls.__name__), exception=ex) + return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') + finally: + if verbose_log.enabled: + time_taken = CommonTextUtils.to_truncated_decimal(stop_watch.stop_milliseconds()) + verbose_log.format_with_message(f'Took {time_taken}ms to return result from CommonConstrainedSuperInteraction.', class_name=cls.__name__) + else: + stop_watch.stop() + + # noinspection PyMissingOrEmptyDocstring,PyMethodParameters + @flexmethod + def get_participants(cls, inst, participant_type: ParticipantType, sim=DEFAULT, target=DEFAULT, carry_target=DEFAULT, **kwargs): + inst_or_cls = inst or cls + log = cls.get_log() + try: + custom_participants = cls.get_custom_replacement_participants(participant_type, sim, target, carry_target, interaction=inst, **kwargs) + if custom_participants is not None: + return tuple(custom_participants) + except Exception as ex: + log.error('Error occurred while running CommonConstrainedSuperInteraction \'{}\' get_custom_replacement_participants.'.format(cls.__name__), exception=ex) + + result: Set[Any] = super(CommonConstrainedSuperInteraction, inst_or_cls).get_participants(participant_type, sim=sim, target=target, carry_target=carry_target, **kwargs) + + result = set(result) + try: + custom_participants = cls.get_custom_participants(participant_type, sim, target, carry_target, interaction=inst, **kwargs) + result.update(custom_participants) + except Exception as ex: + log.error('Error occurred while running CommonConstrainedSuperInteraction \'{}\' get_custom_participants.'.format(cls.__name__), exception=ex) + return tuple(result) + + # noinspection PyMethodParameters,PyMissingOrEmptyDocstring + @flexmethod + def get_name(cls, inst: 'CommonConstrainedSuperInteraction', target: Any=DEFAULT, context: InteractionContext=DEFAULT, **interaction_parameters) -> LocalizedString: + inst_or_cls = inst or cls + try: + context_inst_or_cls = context or inst_or_cls + interaction_sim = context_inst_or_cls.sim + interaction_target = target or context_inst_or_cls.target + + cls.get_verbose_log().format_with_message( + 'Running get_name.', + class_name=cls.__name__, + interaction_sim=interaction_sim, + interaction_target=interaction_target, + interaction=inst, + interaction_context=context + ) + override_name = cls._create_override_display_name( + interaction_sim, + interaction_target, + interaction=inst, + interaction_context=context, + **interaction_parameters + ) + if override_name is not None: + return override_name + except Exception as ex: + cls.get_log().error('An error occurred while running get_name of CommonConstrainedSuperInteraction {}'.format(cls.__name__), exception=ex) + result = super(CommonConstrainedSuperInteraction, inst_or_cls).get_name(target=target, context=context, **interaction_parameters) + if result is None: + cls.get_log().error(f'Missing a name for interaction {cls.__name__}', throw=True) + return result + + def _trigger_interaction_start_event(self: 'CommonConstrainedSuperInteraction'): + try: + self.verbose_log.format_with_message( + 'Running on_started.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target + ) + result = self.on_started(self.sim, self.target) + if result is not None and ((isinstance(result, CommonExecutionResult) and not result.is_success) or (isinstance(result, bool) and not result)): + self.cancel(FinishingType.CONDITIONAL_EXIT, str(result)) + return False + return super()._trigger_interaction_start_event() + except Exception as ex: + self.log.error('Error occurred while running CommonConstrainedSuperInteraction \'{}\' 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: + self.verbose_log.format_with_message( + 'Running modify_posture_state.', + class_name=self.__class__.__name__, + posture_state=posture_state, + participant_type=participant_type, + sim=sim + ) + (new_posture_state, new_participant_type, new_sim) = self.modify_posture_state(posture_state, participant_type=participant_type, sim=sim) + except Exception as ex: + self.log.error('Error occurred while running CommonConstrainedSuperInteraction \'{}\' 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.verbose_log.format_with_message( + 'Running on_killed.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target + ) + self.on_killed(self.sim, self.target) + except Exception as ex: + self.log.error('Error occurred while running CommonConstrainedSuperInteraction \'{}\' 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.verbose_log.format_with_message( + 'Running on_cancelled.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target, + finishing_type=finishing_type, + cancel_reason_msg=cancel_reason_msg, + kwargles=kwargs + ) + self.on_cancelled(self.sim, self.target, finishing_type, cancel_reason_msg, **kwargs) + except Exception as ex: + self.log.error('Error occurred while running CommonConstrainedSuperInteraction \'{}\' _cancel.'.format(self.__class__.__name__), exception=ex) + return super()._cancel(finishing_type, cancel_reason_msg, **kwargs) + + def on_reset(self: 'CommonConstrainedSuperInteraction'): + """on_reset() + + A function that occurs upon an interaction being reset. + + """ + try: + self.verbose_log.format_with_message( + 'Running on_reset.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target + ) + self._on_reset(self.sim, self.target) + except Exception as ex: + self.log.error('Error occurred while running CommonConstrainedSuperInteraction \'{}\' on_reset.'.format(self.__class__.__name__), exception=ex) + return super().on_reset() + + def _post_perform(self: 'CommonConstrainedSuperInteraction'): + super_result = super()._post_perform() + try: + self.verbose_log.format_with_message( + 'Running on_performed.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target + ) + self.on_performed(self.sim, self.target) + except Exception as ex: + self.log.error('Error occurred while running CommonConstrainedSuperInteraction \'{}\' _post_perform.'.format(self.__class__.__name__), exception=ex) + return super_result + + def send_current_progress(self, *args: Any, **kwargs: Any): + """send_current_progress(*args, **kwargs) + + A function that occurs upon a progress bar update. + + """ + try: + self.verbose_log.format_with_message( + 'Running _send_current_progress.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target, + argles=args, + kwargles=kwargs + ) + result = self._send_current_progress(self.sim, self.target, *args, **kwargs) + if result is not None: + return result + except Exception as ex: + self.log.error('Error occurred while running CommonConstrainedSuperInteraction \'{}\' 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: + self.verbose_log.format_with_message( + 'Running _setup_asm_default.', + class_name=self.__class__.__name__, + sim=self.sim, + target=self.target, + asm=asm, + argles=args, + kwargles=kwargs + ) + result = self._setup_asm_default(self.sim, self.target, asm, *args, **kwargs) + if result is not None: + return result + except Exception as ex: + self.log.error('Error occurred while running CommonConstrainedSuperInteraction \'{}\' setup_asm_default.'.format(self.__class__.__name__), exception=ex) + return super().setup_asm_default(asm, *args, **kwargs) + + def _run_interaction_gen(self, timeline: Timeline): + try: + self.verbose_log.format_with_message( + 'Running on_run.', + class_name=self.__class__.__name__, + interaction_sim=self.sim, + interaction_target=self.target, + timeline=timeline + ) + self.on_run(self.sim, self.target, timeline) + except Exception as ex: + self.log.error('Error occurred while running CommonConstrainedSuperInteraction \'{}\' on_run.'.format(self.__class__.__name__), exception=ex) + yield from super()._run_interaction_gen(timeline) + + # noinspection PyMethodParameters + @flexmethod + def _constraint_gen(cls, inst: 'CommonConstrainedSuperInteraction', sim: Sim, target: Any, participant_type: ParticipantType=ParticipantType.Actor, **kwargs) -> Constraint: + inst_or_cls = inst if inst is not None else cls + try: + replacement_results = cls.on_replacement_constraints_gen(inst_or_cls, sim or inst_or_cls.sim, inst_or_cls.get_constraint_target(target) or target or inst_or_cls.target) + if replacement_results is not None: + if inspect.isgenerator(replacement_results): + yield from replacement_results + else: + yield replacement_results + else: + yield from super(CommonConstrainedSuperInteraction, inst_or_cls)._constraint_gen(sim, target, participant_type=participant_type, **kwargs) + result = cls.on_constraint_gen(inst_or_cls, sim or inst_or_cls.sim, inst_or_cls.get_constraint_target(target) or target or inst_or_cls.target) + if result is not None: + if inspect.isgenerator(result): + yield from result + else: + yield result + except Exception as ex: + cls.get_log().error('Error occurred while running CommonConstrainedSuperInteraction \'{}\' _on_constraint_gen.'.format(cls.__name__), exception=ex) diff --git a/Scripts/s4ap/sims4communitylib/classes/interactions/common_terrain_interaction.py b/Scripts/s4ap/sims4communitylib/classes/interactions/common_terrain_interaction.py new file mode 100644 index 0000000..d8a0567 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/interactions/common_terrain_interaction.py @@ -0,0 +1,108 @@ +""" +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 +""" +import os +from typing import Any + +from interactions.context import InteractionContext +from sims.sim import Sim +from sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction +from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from sims4communitylib.classes.testing.common_test_result import CommonTestResult + +ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' + +# If on Read The Docs, create fake versions of extended objects to fix the error of inheriting from multiple MockObjects. +if ON_RTD: + # noinspection PyMissingOrEmptyDocstring + class MockClass(object): + # noinspection PyMissingTypeHints,PyUnusedLocal + def __init__(self, *args, **kwargs): + super(MockClass, self).__init__() + + # noinspection PyMissingTypeHints + def __call__(self, *args, **kwargs): + return None + + # noinspection PyMissingOrEmptyDocstring + class TravelMixin(MockClass): + pass + + # noinspection PyMissingOrEmptyDocstring + class TerrainInteractionMixin(MockClass): + pass + +if not ON_RTD: + from objects.terrain import TravelMixin, TerrainInteractionMixin + + +class CommonTerrainInteraction(TravelMixin, TerrainInteractionMixin, CommonImmediateSuperInteraction): + """CommonTerrainInteraction(*_, **__) + + An inheritable class that provides a way to create custom Terrain Interactions. + + .. note:: + + The main use for this class is to create interactions that appear when clicking on the ground.\ + It CAN be used for interactions that appear when clicking on Sims and Objects, but it is not recommended. + + .. 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! + + :Example: + + .. highlight:: python + .. code-block:: python + + class _ExampleTerrainInteraction(CommonTerrainInteraction): + @classmethod + def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, **kwargs) -> CommonTestResult: + result = 1 + 1 + if result == 2: + # Interaction will be displayed, but disabled, it will also have a tooltip that displays on hover with the text "Test Tooltip" + return cls.create_test_result(False, reason="Test Tooltip") + # Alternative way to specify a tooltip with the text "Test Tooltip" + # return cls.create_test_result(False, reason="No Reason", tooltip=CommonLocalizationUtils.create_localized_tooltip("Test Tooltip")) + if result == 3: + # Interaction will be hidden completely. + return CommonTestResult.NONE + # Interaction will display and be enabled. + return CommonTestResult.TRUE + + def on_started(self, interaction_sim: Sim, interaction_target: Any) -> CommonExecutionResult: + result = True + if not result: + return CommonExecutionResult.FALSE + # Put here what you want the interaction to do as soon as the player clicks it while it is enabled. + return CommonExecutionResult.TRUE + """ + pass + + +# The following is an example interaction that varies when it will display, when it will be hidden, and when it will be disabled with a tooltip. +class _ExampleTerrainInteraction(CommonTerrainInteraction): + # noinspection PyMissingOrEmptyDocstring + @classmethod + def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, **kwargs) -> CommonTestResult: + result = 1 + 1 + if result == 2: + # Interaction will be displayed, but disabled, it will also have a tooltip that displays on hover with the text "Test Tooltip" + return cls.create_test_result(False, reason="Test Tooltip") + # Alternative way to specify a tooltip with the text "Test Tooltip" + # return cls.create_test_result(False, reason="No Reason", tooltip=CommonLocalizationUtils.create_localized_tooltip("Test Tooltip")) + if result == 3: + # Interaction will be hidden completely. + return CommonTestResult.NONE + # Interaction will display and be enabled. + return CommonTestResult.TRUE + + # noinspection PyMissingOrEmptyDocstring + def on_started(self, interaction_sim: Sim, interaction_target: Any) -> CommonExecutionResult: + result = True + if not result: + return CommonExecutionResult.FALSE + # Put here what you want the interaction to do as soon as the player clicks it while it is enabled. + return CommonExecutionResult.TRUE diff --git a/Scripts/s4ap/sims4communitylib/classes/math/__init__.py b/Scripts/s4ap/sims4communitylib/classes/math/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/math/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/classes/math/common_comparison.py b/Scripts/s4ap/sims4communitylib/classes/math/common_comparison.py new file mode 100644 index 0000000..d910023 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/math/common_comparison.py @@ -0,0 +1,55 @@ +""" +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 +""" +from typing import Any + + +class CommonComparison: + """A comparison that may be used in functions that require a CommonComparison object.""" + def compare(self, value_a: Any, value_b: Any) -> bool: + """Compare two values.""" + raise NotImplementedError() + + +class CommonComparisonEqualTo(CommonComparison): + """Check if A is equal to B.""" + + # noinspection PyMissingOrEmptyDocstring + def compare(self, value_a: Any, value_b: Any) -> bool: + return value_a == value_b + + +class CommonComparisonGreaterThan(CommonComparison): + """Check if A is greater than B.""" + + # noinspection PyMissingOrEmptyDocstring + def compare(self, value_a: Any, value_b: Any) -> bool: + return value_a > value_b + + +class CommonComparisonLessThan(CommonComparison): + """Check if A is less than B.""" + + # noinspection PyMissingOrEmptyDocstring + def compare(self, value_a: Any, value_b: Any) -> bool: + return value_a < value_b + + +class CommonComparisonGreaterThanOrEqualTo(CommonComparison): + """Check if A is greater than or equal to B.""" + + # noinspection PyMissingOrEmptyDocstring + def compare(self, value_a: Any, value_b: Any) -> bool: + return value_a >= value_b + + +class CommonComparisonLessThanOrEqualTo(CommonComparison): + """Check if A is less than or equal to B.""" + + # noinspection PyMissingOrEmptyDocstring + def compare(self, value_a: Any, value_b: Any) -> bool: + return value_a <= value_b diff --git a/Scripts/s4ap/sims4communitylib/classes/math/common_float_range.py b/Scripts/s4ap/sims4communitylib/classes/math/common_float_range.py new file mode 100644 index 0000000..80e79b1 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/math/common_float_range.py @@ -0,0 +1,69 @@ +""" +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 +""" +from typing import Union + + +class CommonFloatRange: + """CommonFloatRange(min_value=None, max_value=None) + + A range with a minimum and maximum for use in calculations. + + :param min_value: The minimum threshold. Set to None if there is no minimum. Default is None. + :type min_value: float, optional + :param max_value: The maximum threshold. Set to None if there is no maximum. Default is None. + :type max_value: float, optional + """ + def __init__(self, min_value: float=None, max_value: float=None): + self._min_value = min_value + self._max_value = max_value + + @property + def min_value(self) -> Union[float, None]: + """The minimum threshold of this range. + + :return: The minimum threshold of this range. + :rtype: Union[float, None] + """ + return self._min_value + + @property + def max_value(self) -> Union[float, None]: + """The maximum threshold of this range. + + :return: The maximum threshold of this range. + :rtype: Union[float, None] + """ + return self._max_value + + def in_range(self, value: float, or_equal: bool=True) -> bool: + """in_range(value, or_equal=True) + + If a Minimum and Maximum value are specified, determine if the specified value is between or equal to the Minimum and Maximum values. + If a Maximum value is not specified, determine if the specified value is greater than or equal to the Minimum value. + If a Minimum value is not specified, determine if the specified value is less than or equal to the Maximum value. + + :param value: The value to check. + :type value: float + :param or_equal: If True, the value may equal the minimum or maximum values to pass. Default is True. + :type or_equal: bool, optional + :return: True, if the value is within range of the Minimum and Maximum values. False, it not. + :rtype: bool + """ + if self.min_value is None and self.max_value is None: + return False + if self.min_value is None: + if or_equal: + return value <= self.max_value + return value < self.max_value + if self.max_value is None: + if or_equal: + return value >= self.min_value + return value > self.min_value + if or_equal: + return self.min_value <= value <= self.max_value + return self.min_value < value < self.max_value diff --git a/Scripts/s4ap/sims4communitylib/classes/math/common_integer_range.py b/Scripts/s4ap/sims4communitylib/classes/math/common_integer_range.py new file mode 100644 index 0000000..9accf6f --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/math/common_integer_range.py @@ -0,0 +1,69 @@ +""" +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 +""" +from typing import Union + + +class CommonIntegerRange: + """CommonIntegerRange(min_value=None, max_value=None) + + A range with a minimum and maximum for use in calculations. + + :param min_value: The minimum threshold. Set to None if there is no minimum. Default is None. + :type min_value: int, optional + :param max_value: The maximum threshold. Set to None if there is no maximum. Default is None. + :type max_value: int, optional + """ + def __init__(self, min_value: int=None, max_value: int=None): + self._min_value = min_value + self._max_value = max_value + + @property + def min_value(self) -> Union[int, None]: + """The minimum threshold of this range. + + :return: The minimum threshold of this range. + :rtype: Union[int, None] + """ + return self._min_value + + @property + def max_value(self) -> Union[int, None]: + """The maximum threshold of this range. + + :return: The maximum threshold of this range. + :rtype: Union[int, None] + """ + return self._max_value + + def in_range(self, value: int, or_equal: bool=True) -> bool: + """in_range(value, or_equal=True) + + If a Minimum and Maximum value are specified, determine if the specified value is between or equal to the Minimum and Maximum values. + If a Maximum value is not specified, determine if the specified value is greater than or equal to the Minimum value. + If a Minimum value is not specified, determine if the specified value is less than or equal to the Maximum value. + + :param value: The value to check. + :type value: int + :param or_equal: If True, the value may equal the minimum or maximum values to pass. Default is True. + :type or_equal: bool, optional + :return: True, if the value is within range of the Minimum and Maximum values. False, it not. + :rtype: bool + """ + if self.min_value is None and self.max_value is None: + return False + if self.min_value is None: + if or_equal: + return value <= self.max_value + return value < self.max_value + if self.max_value is None: + if or_equal: + return value >= self.min_value + return value > self.min_value + if or_equal: + return self.min_value <= value <= self.max_value + return self.min_value < value < self.max_value diff --git a/Scripts/s4ap/sims4communitylib/classes/math/common_location.py b/Scripts/s4ap/sims4communitylib/classes/math/common_location.py new file mode 100644 index 0000000..9b7ef73 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/math/common_location.py @@ -0,0 +1,112 @@ +""" +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 +""" +from typing import Any, Union +from sims4.math import Location +from sims4communitylib.classes.math.common_surface_identifier import CommonSurfaceIdentifier +from sims4communitylib.classes.math.common_transform import CommonTransform + + +class CommonLocation: + """ A class that contains locational data. """ + + def __init__(self, transform: CommonTransform, routing_surface: CommonSurfaceIdentifier, parent_ref: Any=None, joint_name_or_hash: Any=None, slot_hash: int=0): + self._transform = transform + self._routing_surface = routing_surface + self._parent_ref = parent_ref + self._joint_name_or_hash = joint_name_or_hash + self._slot_hash = slot_hash + + @property + def transform(self) -> CommonTransform: + """ The translation and orientation of the location. + + :return: The translation and orientation of the location. + :rtype: CommonTransform + """ + return self._transform + + @property + def routing_surface(self) -> CommonSurfaceIdentifier: + """ The routing surface the location is located on. + + :return: The routing surface the location is located on. + :rtype: CommonSurfaceIdentifier + """ + return self._routing_surface + + @property + def parent_ref(self) -> Any: + """ The parent reference of the location. + + :return: The parent reference of the location. + :rtype: Any + """ + return self._parent_ref + + @property + def joint_name_or_hash(self) -> Union[str, int]: + """ The name or hash identifier of the joint the location is located at. + + :return: The name or hash identifier of the joint the location is located at. + :rtype: Union[str, int] + """ + return self._joint_name_or_hash + + @property + def slot_hash(self) -> int: + """ The hash identifier of the Slot the location is located at. + + :return: The hash identifier of the Slot the location is located at. + :rtype: int + """ + return self._slot_hash + + def __new__(cls, transform: CommonTransform, routing_surface: CommonSurfaceIdentifier, parent_ref: Any=None, joint_name_or_hash: Any=None, slot_hash: int=0) -> 'CommonLocation': + # noinspection PyTypeChecker, PyArgumentList + return Location(transform, routing_surface, parent_ref, joint_name_or_hash, slot_hash) + + @staticmethod + def empty() -> 'CommonLocation': + """empty() + + Create an empty location. + + :return: An empty location. + :rtype: CommonLocation + """ + return CommonLocation(CommonTransform.empty(), CommonSurfaceIdentifier.empty()) + + @staticmethod + def from_location(location: Union[Location, 'CommonLocation']) -> Union['CommonLocation', None]: + """from_location(location) + + Convert a vanilla Location object into a CommonLocation. + + :param location: An instance of a Location. + :type location: Union[Location, CommonLocation] + :return: An instance of a CommonLocation or None if the object failed to convert. + :rtype: Union[CommonLocation, None] + """ + if location is None: + return None + if isinstance(location, CommonLocation): + return location + if not isinstance(location, Location): + raise Exception('Failed to convert {} with type {} was not of type {}.'.format(location, type(location), type(Location))) + routing_surface = location.routing_surface if location.routing_surface is not None else CommonSurfaceIdentifier.empty( + secondary_id=location.level) + parent_ref = None + if location.parent_ref is not None and hasattr(location.parent_ref, 'provided_routing_surface'): + parent_ref = location.parent_ref + return CommonLocation( + CommonTransform.from_transform(location.transform), + CommonSurfaceIdentifier.from_surface_identifier(routing_surface), + parent_ref=parent_ref, + joint_name_or_hash=location.joint_name_or_hash, + slot_hash=location.slot_hash + ) diff --git a/Scripts/s4ap/sims4communitylib/classes/math/common_polygon.py b/Scripts/s4ap/sims4communitylib/classes/math/common_polygon.py new file mode 100644 index 0000000..6749f5a --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/math/common_polygon.py @@ -0,0 +1,101 @@ +""" +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 +""" +from typing import Tuple, Iterator, List, Union + +from interactions.constraints import Constraint +from sims4.geometry import Polygon +from sims4communitylib.classes.math.common_vector3 import CommonVector3 + + +class CommonPolygon: + """ A class that contains polygonal data. """ + + def __init__(self, polygon_vertices: Tuple[CommonVector3]): + self._polygon_vertices = polygon_vertices + + def __new__(cls, corners: Tuple[CommonVector3]) -> 'CommonPolygon': + return Polygon(corners) + + def __iter__(self) -> Iterator[CommonVector3]: + pass + + def __len__(self) -> int: + pass + + def __getitem__(self, item: int) -> CommonVector3: + pass + + # noinspection PyMissingOrEmptyDocstring + def normalize(self) -> None: + pass + + # noinspection PyMissingOrEmptyDocstring + def centroid(self) -> 'CommonVector3': + pass + + # noinspection PyMissingOrEmptyDocstring + def radius(self) -> float: + pass + + # noinspection PyMissingOrEmptyDocstring + def area(self) -> float: + pass + + # noinspection PyMissingOrEmptyDocstring + def bounds(self) -> Tuple[CommonVector3, CommonVector3]: + pass + + # noinspection PyMissingOrEmptyDocstring + def contains(self, point: CommonVector3) -> bool: + pass + + # noinspection PyMissingOrEmptyDocstring + def intersect(self, polygon: 'CommonPolygon') -> Constraint: + pass + + # noinspection PyMissingOrEmptyDocstring + def union(self, polygon: 'CommonPolygon') -> Constraint: + pass + + # noinspection PyMissingOrEmptyDocstring + def subtract(self, polygon: 'CommonPolygon') -> List[CommonVector3]: + pass + + # noinspection PyMissingOrEmptyDocstring + def get_convex_hull(self) -> 'CommonPolygon': + pass + + @staticmethod + def empty() -> 'CommonPolygon': + """empty() + + Create an empty Polygon. + + :return: An empty Polygon. + :rtype: CommonPolygon + """ + return CommonPolygon(tuple()) + + @staticmethod + def from_polygon(polygon: Union[Polygon, 'CommonPolygon']) -> Union['CommonPolygon', None]: + """from_polygon(polygon) + + Convert a vanilla Polygon object into a CommonPolygon. + + :param polygon: An instance of a Polygon + :type polygon: Union[Polygon, CommonPolygon] + :return: An instance of a CommonPolygon or None if the object failed to convert. + :rtype: Union[CommonLocation, None] + """ + if polygon is None: + return None + if isinstance(polygon, CommonPolygon): + return polygon + if not isinstance(polygon, Polygon): + raise Exception('Failed to convert {} with type {} was not of type {}.'.format(polygon, type(polygon), type(Polygon))) + return CommonPolygon(tuple(polygon)) diff --git a/Scripts/s4ap/sims4communitylib/classes/math/common_quaternion.py b/Scripts/s4ap/sims4communitylib/classes/math/common_quaternion.py new file mode 100644 index 0000000..42f2138 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/math/common_quaternion.py @@ -0,0 +1,415 @@ +""" +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 +""" +from typing import Union, Any, TYPE_CHECKING, Dict, Type +from protocolbuffers.Math_pb2 import Quaternion as MathPb2Quaternion + +if TYPE_CHECKING: + from sims4communitylib.classes.math.common_vector3 import CommonVector3 + +# noinspection PyBroadException +try: + # noinspection PyUnresolvedReferences + from sims4.math import Quaternion, QuaternionImmutable +except: + # noinspection PyMissingOrEmptyDocstring + class QuaternionImmutable: + # noinspection PyUnusedLocal + def __init__(self, x: float, y: float, z: float, w: float): + pass + + # noinspection PyPropertyDefinition + @property + def x(self) -> float: + pass + + # noinspection PyPropertyDefinition + @property + def y(self) -> float: + pass + + # noinspection PyPropertyDefinition + @property + def z(self) -> float: + pass + + # noinspection PyPropertyDefinition + @property + def w(self) -> float: + pass + + # noinspection PyMissingOrEmptyDocstring + def transform_vector(self, vector: 'CommonVector3') -> 'CommonVector3': + pass + + # noinspection PyMissingOrEmptyDocstring + class Quaternion: + # noinspection PyUnusedLocal + def __init__(self, x: float, y: float, z: float, w: float): + pass + + # noinspection PyPropertyDefinition + @property + def x(self) -> float: + pass + + @x.setter + def x(self, value: float): + pass + + # noinspection PyPropertyDefinition + @property + def y(self) -> float: + pass + + @y.setter + def y(self, value: float): + pass + + # noinspection PyPropertyDefinition + @property + def z(self) -> float: + pass + + @z.setter + def z(self, value: float): + pass + + # noinspection PyPropertyDefinition + @property + def w(self) -> float: + pass + + @w.setter + def w(self, value: float): + pass + + # noinspection PyMissingOrEmptyDocstring + def transform_vector(self, vector: 'CommonVector3') -> 'CommonVector3': + pass + + +class CommonQuaternion: + """ A class that contains orientation data. """ + + def __init__(self, x: float, y: float, z: float, w: float) -> None: + if x is None: + x = 0.0 + if y is None: + y = 0.0 + if z is None: + z = 0.0 + if w is None: + w = 1.0 + self._x = x + self._y = y + self._z = z + self._w = w + + @property + def x(self) -> float: + """ The x position. + + :return: The x position. + :rtype: float + """ + return self._x + + @x.setter + def x(self, value: float): + self._x = value + + @property + def y(self) -> float: + """ The y position. + + :return: The y position. + :rtype: float + """ + return self._y + + @y.setter + def y(self, value: float): + self._y = value + + @property + def z(self) -> float: + """ The z position. + + :return: The z position. + :rtype: float + """ + return self._z + + @property + def w(self) -> Any: + """ The rotation. + + :return: The rotation. + :rtype: Any + """ + return self._w + + @w.setter + def w(self, value: float): + self._w = value + + def __new__(cls, x: float, y: float, z: float, w: float) -> 'CommonQuaternion': + if x is None: + x = 0.0 + if y is None: + y = 0.0 + if z is None: + z = 0.0 + if w is None: + w = 1.0 + # noinspection PyTypeChecker + return Quaternion(x, y, z, w) + + @staticmethod + def empty() -> 'CommonQuaternion': + """empty() + + Deprecated, use "identity" instead. + + Create an empty quaternion. + + :return: An empty quaternion. + :rtype: CommonQuaternion + """ + return CommonQuaternion.identity() + + @staticmethod + def identity() -> 'CommonQuaternion': + """identity() + + Create an identity quaternion. + + :return: An identity quaternion. + :rtype: CommonQuaternion + """ + return CommonQuaternion(0.0, 0.0, 0.0, 1.0) + + @staticmethod + def is_empty(quaternion: Union[Quaternion, MathPb2Quaternion, 'CommonQuaternion']) -> bool: + """is_empty(quaternion) + + Determine if a quaternion is empty or not. + + :param quaternion: The quaternion to check. + :type quaternion: Union[Quaternion, MathPb2Quaternion, CommonQuaternion] + :return: True, if the quaternion is empty. False, if not. + :rtype: bool + """ + quaternion_identity = CommonQuaternion.empty() + return quaternion.x == quaternion_identity.x and quaternion.y == quaternion_identity.y and quaternion.z == quaternion_identity.z and quaternion.w == quaternion_identity.w + + @staticmethod + def from_quaternion(quaternion: Union[Quaternion, MathPb2Quaternion, 'CommonQuaternion']) -> Union['CommonQuaternion', None]: + """from_quaternion(quaternion) + + Convert a Quaternion into a CommonQuaternion. + + :param quaternion: An instance of a Quaternion. + :type quaternion: Union[Quaternion, MathPb2Quaternion, CommonQuaternion] + :return: An instance of a CommonQuaternion or None if the object failed to convert. + :rtype: Union[CommonQuaternion, None] + """ + if quaternion is None: + return None + if isinstance(quaternion, CommonQuaternion): + return quaternion + if not isinstance(quaternion, Quaternion) and not isinstance(quaternion, QuaternionImmutable): + raise Exception('Failed to convert {} with type {} was not of type {}.'.format(quaternion, type(quaternion), type(Quaternion))) + # noinspection PyUnresolvedReferences + return CommonQuaternion(quaternion.x, quaternion.y, quaternion.z, quaternion.w) + + @staticmethod + def from_radian(radian: float) -> 'CommonQuaternion': + """from_radian(radian) + + Convert a radian value into a CommonQuaternion. + + :param radian: An angle in radians + :type radian: float + :return: An instance of a CommonQuaternion. + :rtype: CommonQuaternion + """ + from sims4.math import angle_to_yaw_quaternion + return CommonQuaternion.from_quaternion(angle_to_yaw_quaternion(radian)) + + @staticmethod + def from_degrees(degrees: float) -> 'CommonQuaternion': + """from_degrees(degrees) + + Convert an angle in degrees into a CommonQuaternion. + + :param degrees: An angle in degrees + :type degrees: float + :return: An instance of a CommonQuaternion. + :rtype: CommonQuaternion + """ + from sims4communitylib.utils.common_math_utils import CommonMathUtils + return CommonQuaternion.from_radian(CommonMathUtils.degrees_to_radian(degrees)) + + @staticmethod + def to_radian(quaternion: Union[Quaternion, MathPb2Quaternion, 'CommonQuaternion']) -> float: + """to_radian(quaternion) + + Convert a Quaternion into radians. + + :param quaternion: An instance of a Quaternion. + :type quaternion: Union[Quaternion, MathPb2Quaternion, CommonQuaternion] + :return: The quaternion represented in radians. + :rtype: float + """ + if quaternion is None: + return 0.0 + from sims4.math import yaw_quaternion_to_angle + return yaw_quaternion_to_angle(quaternion) + + @staticmethod + def to_degrees(quaternion: Union[Quaternion, MathPb2Quaternion, 'CommonQuaternion']) -> float: + """to_degrees(quaternion) + + Convert a Quaternion into degrees. + + :param quaternion: An instance of a Quaternion. + :type quaternion: Union[Quaternion, MathPb2Quaternion, CommonQuaternion] + :return: The quaternion represented in degrees. + :rtype: float + """ + if quaternion is None: + return 0.0 + from sims4communitylib.utils.common_math_utils import CommonMathUtils + return CommonMathUtils.radian_to_degrees(CommonQuaternion.to_radian(quaternion)) + + def __add__(self, other: Union[Quaternion, MathPb2Quaternion, 'CommonQuaternion', float]) -> 'CommonQuaternion': + # The functionality lies inside Quaternion + pass + + def __sub__(self, other: Union[Quaternion, MathPb2Quaternion, 'CommonQuaternion', float]) -> 'CommonQuaternion': + # The functionality lies inside Quaternion + pass + + @staticmethod + def rotate_vector(quaternion: Union[Quaternion, MathPb2Quaternion, 'CommonQuaternion'], vector: 'CommonVector3') -> Any: + """rotate_vector(quaternion, vector) + + Rotate a vector with a quaternion. + + :param quaternion: The quaternion to use for rotation. + :type quaternion: Union[Quaternion, MathPb2Quaternion, CommonQuaternion] + :param vector: The vector to rotate. + :type vector: CommonVector3 + :return: A normalized Quaternion. + :rtype: CommonQuaternion + """ + from sims4communitylib.classes.math.common_vector3 import CommonVector3 + q = CommonQuaternion.multiply(CommonQuaternion.multiply(quaternion, CommonQuaternion(vector.x, vector.y, vector.z, 0.0)), CommonQuaternion.conjugate(quaternion)) # q.w will be zero. + return CommonVector3(q.x, q.y, q.z) + + @staticmethod + def normalize(quaternion: Union[Quaternion, MathPb2Quaternion, 'CommonQuaternion'], tolerance: float = 0.00001) -> 'CommonQuaternion': + """normalize(quaternion, tolerance=0.00001) + + Normalize a quaternion. + + :param quaternion: The quaternion to normalize. + :type quaternion: Union[Quaternion, MathPb2Quaternion, CommonQuaternion] + :param tolerance: The tolerance level for normalization. Default is 0.00001. + :type tolerance: float, optional + :return: A normalized Quaternion. + :rtype: CommonQuaternion + """ + import math + mag2 = (quaternion.x * quaternion.x) + (quaternion.y * quaternion.y) + (quaternion.z * quaternion.z) + (quaternion.w * quaternion.w) + if mag2 == 0: + return quaternion + mag3 = abs(1 - mag2) + if mag3 > tolerance: + mag = math.sqrt(mag2) + new_x = (quaternion.x / mag) + new_y = (quaternion.y / mag) + new_z = (quaternion.z / mag) + new_w = (quaternion.w / mag) + return CommonQuaternion(new_x, new_y, new_z, new_w) + return quaternion + + @staticmethod + def conjugate(quaternion: Union[Quaternion, MathPb2Quaternion, 'CommonQuaternion']) -> 'CommonQuaternion': + """conjugate(quaternion) + + Conjugate a quaternion. + + :param quaternion: The quaternion to conjugate. + :type quaternion: Union[Quaternion, MathPb2Quaternion, CommonQuaternion] + :return: A conjugated Quaternion. + :rtype: CommonQuaternion + """ + return CommonQuaternion(-quaternion.x, -quaternion.y, -quaternion.z, quaternion.w) + + @staticmethod + def __truediv__(quaternion: Union[Quaternion, MathPb2Quaternion, 'CommonQuaternion'], quaternion_other: Union[Quaternion, MathPb2Quaternion, 'CommonQuaternion']) -> 'CommonQuaternion': + return CommonQuaternion.normalize(CommonQuaternion.divide(quaternion, quaternion_other)) + + @staticmethod + def __mul__(quaternion: Union[Quaternion, MathPb2Quaternion, 'CommonQuaternion'], quaternion_other: Union[Quaternion, MathPb2Quaternion, 'CommonQuaternion']) -> 'CommonQuaternion': + return CommonQuaternion.normalize(CommonQuaternion.multiply(quaternion, quaternion_other)) + + @staticmethod + def divide(quaternion: Union[Quaternion, MathPb2Quaternion, 'CommonQuaternion'], quaternion_other: Union[Quaternion, MathPb2Quaternion, 'CommonQuaternion']): + """divide(quaternion, quaternion_other) + + Divides two quaternions without normalizing the result. Use `q = q1 / q2` for a normalized result. + + :param quaternion: The quaternion to be divided. + :type quaternion: Union[Quaternion, MathPb2Quaternion, CommonQuaternion] + :param quaternion_other: The quaternion to divide with. + :type quaternion_other: Union[Quaternion, MathPb2Quaternion, CommonQuaternion] + :return: A divided Quaternion. + :rtype: CommonQuaternion + """ + return CommonQuaternion.multiply(quaternion, CommonQuaternion.conjugate(quaternion_other)) + + @staticmethod + def multiply(quaternion: Union[Quaternion, MathPb2Quaternion, 'CommonQuaternion'], quaternion_other: Union[Quaternion, MathPb2Quaternion, 'CommonQuaternion']) -> 'CommonQuaternion': + """multiply(quaternion, quaternion_other) + + Multiplies two quaternions without normalizing the result. Use `q = q1 * q2` for a normalized result. + + :param quaternion: The quaternion to be multiplied. + :type quaternion: Union[Quaternion, MathPb2Quaternion, CommonQuaternion] + :param quaternion_other: The quaternion to multiply with. + :type quaternion_other: Union[Quaternion, MathPb2Quaternion, CommonQuaternion] + :return: A divided Quaternion. + :rtype: CommonQuaternion + """ + x = (quaternion.w * quaternion_other.x) + (quaternion.x * quaternion_other.w) + (quaternion.y * quaternion_other.z) - (quaternion.z * quaternion_other.y) + y = (quaternion.w * quaternion_other.y) - (quaternion.x * quaternion_other.z) + (quaternion.y * quaternion_other.w) + (quaternion.z * quaternion_other.x) + z = (quaternion.w * quaternion_other.z) + (quaternion.x * quaternion_other.y) - (quaternion.y * quaternion_other.x) + (quaternion.z * quaternion_other.w) + w = (quaternion.w * quaternion_other.w) - (quaternion.x * quaternion_other.x) - (quaternion.y * quaternion_other.y) - (quaternion.z * quaternion_other.z) + return CommonQuaternion(x, y, z, w) + + # noinspection PyMissingOrEmptyDocstring + @staticmethod + def serialize(quaternion: Union[Quaternion, MathPb2Quaternion, 'CommonQuaternion']) -> Union[str, Dict[str, Any]]: + data = dict() + data['x'] = quaternion.x + data['y'] = quaternion.y + data['z'] = quaternion.z + data['w'] = quaternion.w + return data + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def deserialize(cls: Type['CommonQuaternion'], data: Union[str, Dict[str, Any]]) -> Union['CommonQuaternion', None]: + x = data.get('x', 0.0) + y = data.get('y', 0.0) + z = data.get('z', 0.0) + w = data.get('w', 1.0) + return CommonQuaternion(x, y, z, w) diff --git a/Scripts/s4ap/sims4communitylib/classes/math/common_routing_location.py b/Scripts/s4ap/sims4communitylib/classes/math/common_routing_location.py new file mode 100644 index 0000000..e7fc160 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/math/common_routing_location.py @@ -0,0 +1,110 @@ +""" +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 +""" +from typing import Union, TYPE_CHECKING +from sims4.math import Location as Math_Location +from routing import Location +from sims4communitylib.classes.math.common_quaternion import CommonQuaternion +from sims4communitylib.classes.math.common_surface_identifier import CommonSurfaceIdentifier +from sims4communitylib.classes.math.common_vector3 import CommonVector3 + +if TYPE_CHECKING: + from sims4communitylib.classes.math.common_location import CommonLocation + + +class CommonRoutingLocation: + """CommonRoutingLocation(position, orientation=None, routing_surface=None) + + A Location used for routing. + + :param position: The position of the location. + :type position: CommonVector3 + :param orientation: The orientation of the location. Default is None. + :type orientation: CommonQuaternion, optional + :param routing_surface: The routing surface of the location. Default is None. + :type routing_surface: CommonSurfaceIdentifier, optional + """ + def __init__(self, position: CommonVector3, orientation: CommonQuaternion=None, routing_surface: CommonSurfaceIdentifier=None): + super().__init__(position, orientation, routing_surface) + self._position = position + self._orientation = orientation + self._routing_surface = routing_surface + + @property + def position(self) -> CommonVector3: + """The translation and orientation of the location. + + :return: The translation and orientation of the location. + :rtype: CommonTransform + """ + return self._position + + @property + def orientation(self) -> CommonQuaternion: + """The orientation of the location. + + :return: The orientation of the Location. + :rtype: CommonQuaternion + """ + return self._orientation + + @property + def routing_surface(self) -> CommonSurfaceIdentifier: + """The routing surface the location is located on. + + :return: The routing surface the location is located on. + :rtype: CommonSurfaceIdentifier + """ + return self._routing_surface + + def __new__(cls, position: CommonVector3, orientation: CommonQuaternion=None, routing_surface: CommonSurfaceIdentifier=None) -> 'CommonRoutingLocation': + # noinspection PyTypeChecker + return Location(position, orientation, routing_surface) + + @staticmethod + def empty() -> 'CommonRoutingLocation': + """empty() + + Create an empty location. + + :return: An empty location. + :rtype: CommonRoutingLocation + """ + return CommonRoutingLocation(CommonVector3.empty(), orientation=CommonQuaternion.empty(), routing_surface=CommonSurfaceIdentifier.empty()) + + @staticmethod + def from_location(location: Union[Location, Math_Location, 'CommonLocation', 'CommonRoutingLocation']) -> Union['CommonRoutingLocation', None]: + """from_location(location) + + Convert a vanilla Location object into a CommonRoutingLocation. + + :param location: An instance of a Location. + :type location: Union[routing.Location, sims4.math.Location, CommonLocation, CommonRoutingLocation] + :return: An instance of a CommonRoutingLocation or None if the object failed to convert. + :rtype: Union[CommonRoutingLocation, None] + """ + from sims4communitylib.classes.math.common_location import CommonLocation + if location is None: + return None + if isinstance(location, CommonRoutingLocation): + return location + if isinstance(location, Location): + return CommonRoutingLocation(location.position, location.orientation, location.routing_surface) + if not isinstance(location, Math_Location) and not isinstance(location, CommonLocation): + raise Exception('Failed to convert {} with type {} was not of type {}.'.format(location, type(location), type(Math_Location))) + routing_surface = location.routing_surface if location.routing_surface is not None else CommonSurfaceIdentifier.empty() + return CommonRoutingLocation(CommonVector3.from_vector3(location.transform.translation), orientation=CommonQuaternion.from_quaternion(location.transform.orientation), routing_surface=CommonSurfaceIdentifier.from_surface_identifier(routing_surface)) + + def get_world_surface_location(self) -> 'CommonRoutingLocation': + """get_world_surface_location(self) + + Retrieve the Location as a world surface location. + + :return: A world surface location. + :rtype: CommonRoutingLocation + """ + pass diff --git a/Scripts/s4ap/sims4communitylib/classes/math/common_surface_identifier.py b/Scripts/s4ap/sims4communitylib/classes/math/common_surface_identifier.py new file mode 100644 index 0000000..eac34e8 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/math/common_surface_identifier.py @@ -0,0 +1,94 @@ +""" +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 +""" +from typing import Union +from routing import SurfaceType, SurfaceIdentifier + + +class CommonSurfaceIdentifier: + """ A class that contains surface data. """ + + def __init__(self, primary_id: int, secondary_id: int=None, surface_type: SurfaceType=SurfaceType.SURFACETYPE_WORLD): + self._primary_id = primary_id + self._secondary_id = secondary_id + self._surface_type = surface_type + + @property + def primary_id(self) -> int: + """ The primary identifier for the surface. This value is usually the identifier of a Zone. + + :return: The primary identifier. + :rtype: int + """ + return self._primary_id + + @primary_id.setter + def primary_id(self, value: int): + self._primary_id = value + + @property + def secondary_id(self) -> Union[int, None]: + """ The secondary identifier for the surface. This value is usually the level at which the surface is. + + :return: The secondary identifier. + :rtype: Union[int, None] + """ + return self._secondary_id + + @secondary_id.setter + def secondary_id(self, value: Union[int, None]): + self._secondary_id = value + + @property + def type(self) -> Union[SurfaceType, None]: + """ The type of surface. + + :return: The type of surface. + :rtype: Union[SurfaceType, None] + """ + return self._surface_type + + @type.setter + def type(self, value: Union[SurfaceType, None]): + self._surface_type = value + + def __new__(cls, primary_id: int, secondary_id: int=None, surface_type: SurfaceType=SurfaceType.SURFACETYPE_WORLD) -> 'CommonSurfaceIdentifier': + # noinspection PyTypeChecker + return SurfaceIdentifier(primary_id, secondary_id, surface_type) + + @staticmethod + def empty(secondary_id: int=0) -> 'CommonSurfaceIdentifier': + """empty(secondary_id=0) + + Create an empty surface identifier for the current zone. + + :param secondary_id: The secondary id to give to the surface identifier. Default is 0. + :type secondary_id: int, optional + :return: An empty surface identifier. + :rtype: CommonSurfaceIdentifier + """ + from sims4communitylib.utils.location.common_location_utils import CommonLocationUtils + return CommonSurfaceIdentifier(CommonLocationUtils.get_current_zone_id(), secondary_id=secondary_id) + + @staticmethod + def from_surface_identifier(surface_identifier: Union[SurfaceIdentifier, 'CommonSurfaceIdentifier']) -> Union['CommonSurfaceIdentifier', None]: + """from_surface_identifier(surface_identifier) + + Convert a SurfaceIdentifier into a CommonSurfaceIdentifier. + + :param surface_identifier: An instance of a surface identifier. + :type surface_identifier: Union[SurfaceIdentifier, CommonSurfaceIdentifier] + :return: An instance of a CommonSurfaceIdentifier or None if it failed to convert. + :rtype: Union[CommonSurfaceIdentifier, None] + """ + if surface_identifier is None: + return None + if isinstance(surface_identifier, CommonSurfaceIdentifier): + return surface_identifier + if not isinstance(surface_identifier, SurfaceIdentifier): + raise Exception('Failed to convert {} with type {} was not of type {}.'.format(surface_identifier, type(surface_identifier), type(SurfaceIdentifier))) + return CommonSurfaceIdentifier(surface_identifier.primary_id, secondary_id=surface_identifier.secondary_id, surface_type=surface_identifier.type) diff --git a/Scripts/s4ap/sims4communitylib/classes/math/common_transform.py b/Scripts/s4ap/sims4communitylib/classes/math/common_transform.py new file mode 100644 index 0000000..4357aae --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/math/common_transform.py @@ -0,0 +1,102 @@ +""" +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 +""" +from typing import Union, Any +from protocolbuffers.Math_pb2 import Transform as MathPb2Transform + +from sims4communitylib.classes.math.common_quaternion import CommonQuaternion +from sims4communitylib.classes.math.common_vector3 import CommonVector3 + +# noinspection PyBroadException +try: + # noinspection PyUnresolvedReferences + from sims4.math import Transform +except: + # noinspection PyMissingOrEmptyDocstring + class Transform: + # noinspection PyUnusedLocal + def __init__(self, translation: Any, orientation: Any): + pass + + # noinspection PyPropertyDefinition + @property + def translation(self) -> Any: + pass + + # noinspection PyPropertyDefinition + @property + def orientation(self) -> Any: + pass + + +class CommonTransform: + """ A class that contains transformational data. """ + + def __init__(self, translation: CommonVector3, orientation: CommonQuaternion): + self._translation = translation + self._orientation = orientation + + @property + def translation(self) -> CommonVector3: + """ The translation. + + :return: The translation. + :rtype: CommonVector3 + """ + return self._translation + + @translation.setter + def translation(self, value: CommonVector3): + self._translation = value + + @property + def orientation(self) -> CommonQuaternion: + """ The orientation. + + :return: The orientation. + :rtype: CommonQuaternion + """ + return self._orientation + + @orientation.setter + def orientation(self, value: CommonQuaternion): + self._orientation = value + + def __new__(cls, translation: CommonVector3, orientation: CommonQuaternion) -> 'CommonTransform': + # noinspection PyTypeChecker + return Transform(translation, orientation) + + @staticmethod + def empty() -> 'CommonTransform': + """empty() + + Create an empty transform. + + :return: An empty transform. + :rtype: CommonTransform + """ + return CommonTransform(CommonVector3.empty(), CommonQuaternion.empty()) + + @staticmethod + def from_transform(transform: Union[Transform, MathPb2Transform, 'CommonTransform']) -> Union['CommonTransform', None]: + """from_transform(transform) + + Convert a Transform into a CommonTransform. + + :param transform: An instance of a transform. + :type transform: Union[Transform, MathPb2Transform, CommonTransform] + :return: An instance of a CommonTransform or None if it failed to convert. + :rtype: Union[CommonTransform, None] + """ + if transform is None: + return None + if isinstance(transform, CommonTransform): + return transform + if not isinstance(transform, Transform) and not isinstance(transform, MathPb2Transform): + raise Exception('Failed to convert {} with type {} was not of type {}.'.format(transform, type(transform), type(Transform))) + # noinspection PyUnresolvedReferences + return CommonTransform(CommonVector3.from_vector3(transform.translation), CommonQuaternion.from_quaternion(transform.orientation)) diff --git a/Scripts/s4ap/sims4communitylib/classes/math/common_vector3.py b/Scripts/s4ap/sims4communitylib/classes/math/common_vector3.py new file mode 100644 index 0000000..91de528 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/math/common_vector3.py @@ -0,0 +1,298 @@ +""" +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 +""" +from typing import Union, Type, Dict, Any +from protocolbuffers.Math_pb2 import Vector3 as MathPb2Vector3 + +# noinspection PyBroadException +try: + # noinspection PyUnresolvedReferences + from sims4.math import Vector3, Vector3Immutable +except: + # noinspection PyMissingOrEmptyDocstring + class Vector3Immutable: + # noinspection PyUnusedLocal + def __init__(self, x: float, y: float, z: float): + pass + + # noinspection PyPropertyDefinition + @property + def x(self) -> float: + pass + + # noinspection PyPropertyDefinition + @property + def y(self) -> float: + pass + + # noinspection PyPropertyDefinition + @property + def z(self) -> float: + pass + + # noinspection PyMissingOrEmptyDocstring + class Vector3: + # noinspection PyUnusedLocal + def __init__(self, x: float, y: float, z: float): + pass + + # noinspection PyPropertyDefinition + @property + def x(self) -> float: + pass + + @x.setter + def x(self, value: float): + pass + + # noinspection PyPropertyDefinition + @property + def y(self) -> float: + pass + + @y.setter + def y(self, value: float): + pass + + # noinspection PyPropertyDefinition + @property + def z(self) -> float: + pass + + @z.setter + def z(self, value: float): + pass + + +class CommonVector3: + """ A class that contains positional data with three coordinates. """ + def __init__(self, x: float, y: float, z: float): + if x is None: + x = 0.0 + if y is None: + y = 0.0 + if z is None: + z = 0.0 + self._x = x + self._y = y + self._z = z + + @property + def x(self) -> float: + """ The x position. + + :return: The x position. + :rtype: float + """ + return self._x + + @x.setter + def x(self, value: float): + self._x = value + + @property + def y(self) -> float: + """ The y position. + + :return: The y position. + :rtype: float + """ + return self._y + + @y.setter + def y(self, value: float): + self._y = value + + @property + def z(self) -> float: + """ The z position. + + :return: The z position. + :rtype: float + """ + return self._z + + @z.setter + def z(self, value: float): + self._z = value + + def __new__(cls, x: float, y: float, z: float) -> 'CommonVector3': + if x is None: + x = 0.0 + if y is None: + y = 0.0 + if z is None: + z = 0.0 + # noinspection PyTypeChecker + return Vector3(x, y, z) + + @staticmethod + def empty() -> 'CommonVector3': + """empty() + + Create an empty vector. + + :return: An empty vector. + :rtype: CommonVector3 + """ + return CommonVector3(0.0, 0.0, 0.0) + + @staticmethod + def is_empty(vector: Union[Vector3, Vector3Immutable, MathPb2Vector3, 'CommonVector3']) -> bool: + """is_empty(vector) + + Determine if a vector is empty or not. + + :param vector: The vector to check. + :type vector: Union[Vector3, Vector3Immutable, MathPb2Vector3, CommonVector3] + :return: True, if the vector is empty. False, if not. + :rtype: bool + """ + empty_vector = CommonVector3.empty() + return vector.x == empty_vector.x and vector.y == empty_vector.y and vector.z == empty_vector.z + + @staticmethod + def from_vector3(vector: Union[Vector3, Vector3Immutable, MathPb2Vector3, 'CommonVector3']) -> Union['CommonVector3', None]: + """from_vector3(vector) + + Convert a Vector into a CommonVector3. + + :param vector: An instance of a vector. + :type vector: Union[Vector3, Vector3Immutable, MathPb2Vector3, CommonVector3] + :return: An instance of a CommonVector3 or None if it failed to convert. + :rtype: Union[CommonVector3, None] + """ + if vector is None: + raise ValueError('Cannot convert {} to {}.'.format(vector, CommonVector3.__name__)) + if isinstance(vector, CommonVector3): + return vector + if not isinstance(vector, Vector3) and not isinstance(vector, Vector3Immutable) and not isinstance(vector, MathPb2Vector3): + raise Exception('Failed to convert {} with type {} was not of type {}.'.format(vector, type(vector), type(Vector3))) + # noinspection PyUnresolvedReferences + return CommonVector3(vector.x, vector.y, vector.z) + + @staticmethod + def flatten(vector: Union[Vector3, Vector3Immutable, MathPb2Vector3, 'CommonVector3']) -> 'CommonVector3': + """flatten(vector) + + Flatten a Vector. + + :param vector: An instance of a vector. + :type vector: Union[Vector3, Vector3Immutable, MathPb2Vector3, CommonVector3] + :return: An instance of a flattened CommonVector3. + :rtype: CommonVector3 + """ + if vector is None: + raise AttributeError('{} was called with vector as None!'.format(CommonVector3.flatten.__name__)) + from sims4.math import vector_flatten + return CommonVector3.from_vector3(vector_flatten(vector)) + + @staticmethod + def normalize(vector: 'CommonVector3') -> float: + """normalize(vector) + + Normalize a Vector. + + :param vector: An instance of a vector. + :type vector: Union[Vector3, Vector3Immutable, MathPb2Vector3, CommonVector3] + :return: An instance of a normalized CommonVector3. + :rtype: float + """ + from sims4.math import vector_normalize + return vector_normalize(vector) + + @staticmethod + def distance_between( + position_one: Union[Vector3, Vector3Immutable, MathPb2Vector3, 'CommonVector3'], + position_two: Union[Vector3, Vector3Immutable, MathPb2Vector3, 'CommonVector3'] + ) -> float: + """distance_between(position_one, position_two) + + Calculate the distance between two vectors. + + :param position_one: An instance of a Vector. + :type position_one: CommonVector3 + :param position_two: An instance of a Vector. + :type position_two: CommonVector3 + :return: The distance between the two specified vectors. + :rtype: float + """ + if position_one is None: + raise AttributeError('{} was called with position_one as None!'.format(CommonVector3.distance_between.__name__)) + if position_two is None: + raise AttributeError('{} was called with position_two as None!'.format(CommonVector3.distance_between.__name__)) + from math import sqrt + return sqrt((position_one - position_two).magnitude_squared()) + + # noinspection PyMissingOrEmptyDocstring + def magnitude_squared(self) -> float: + # The functionality lies inside Vector3 + pass + + def __add__(self, other: Union[Vector3, Vector3Immutable, MathPb2Vector3, 'CommonVector3', float]) -> 'CommonVector3': + # The functionality lies inside Vector3 + pass + + def __sub__(self, other: Union[Vector3, Vector3Immutable, MathPb2Vector3, 'CommonVector3', float]) -> 'CommonVector3': + # The functionality lies inside Vector3 + pass + + def __mul__(self, other: Union[Vector3, Vector3Immutable, MathPb2Vector3, 'CommonVector3', float]) -> 'CommonVector3': + # The functionality lies inside Vector3 + pass + + def __le__(self, other: Union[Vector3, Vector3Immutable, MathPb2Vector3, 'CommonVector3']) -> bool: + # The functionality lies inside Vector3 + pass + + def __lt__(self, other: Union[Vector3, Vector3Immutable, MathPb2Vector3, 'CommonVector3']) -> bool: + # The functionality lies inside Vector3 + pass + + def __ge__(self, other: Union[Vector3, Vector3Immutable, MathPb2Vector3, 'CommonVector3']) -> bool: + # The functionality lies inside Vector3 + pass + + def __gt__(self, other: Union[Vector3, Vector3Immutable, MathPb2Vector3, 'CommonVector3']) -> bool: + # The functionality lies inside Vector3 + pass + + def __hash__(self) -> int: + # The functionality lies inside Vector3 + pass + + def __ne__(self, other: Union[Vector3, Vector3Immutable, MathPb2Vector3, 'CommonVector3']) -> bool: + # The functionality lies inside Vector3 + pass + + def __eq__(self, other: Union[Vector3, Vector3Immutable, MathPb2Vector3, 'CommonVector3']) -> bool: + # The functionality lies inside Vector3 + pass + + def __repr__(self) -> str: + # The functionality lies inside Vector3 + pass + + def __str__(self) -> str: + pass + + # noinspection PyMissingOrEmptyDocstring + @staticmethod + def serialize(vector: Union[Vector3, Vector3Immutable, MathPb2Vector3, 'CommonVector3']) -> Union[str, Dict[str, Any]]: + data = dict() + data['x'] = vector.x + data['y'] = vector.y + data['z'] = vector.z + return data + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def deserialize(cls: Type['CommonVector3'], data: Union[str, Dict[str, Any]]) -> Union['CommonVector3', None]: + x = data.get('x', 0.0) + y = data.get('y', 0.0) + z = data.get('z', 0.0) + return CommonVector3(x, y, z) diff --git a/Scripts/s4ap/sims4communitylib/classes/math/common_weighted_value.py b/Scripts/s4ap/sims4communitylib/classes/math/common_weighted_value.py new file mode 100644 index 0000000..8cddd8c --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/math/common_weighted_value.py @@ -0,0 +1,56 @@ +""" +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 +""" + + +class CommonWeightedValue: + """ A value with a weight. To be used in conjunction with other CommonWeightedValueTally. """ + def __init__(self, value: float=0.0, weight: float=1.0): + if value is None: + raise AssertionError('Value is None') + if weight is None: + raise AssertionError('Weight is None') + self._value = value + self._weight = weight + + @property + def value(self) -> float: + """ The value. """ + return self._value + + @property + def weight(self) -> float: + """ The weight. """ + return self._weight + + def __add__(self, other: 'CommonWeightedValue') -> 'CommonWeightedValue': + return CommonWeightedValue(value=self.value + other.value, weight=self.weight + other.weight) + + def __sub__(self, other: 'CommonWeightedValue') -> 'CommonWeightedValue': + return CommonWeightedValue(value=self.value - other.value, weight=self.weight - other.weight) + + def __mul__(self, other: 'CommonWeightedValue') -> 'CommonWeightedValue': + return CommonWeightedValue(value=self.value * other.value, weight=self.weight * other.weight) + + def has_value(self) -> bool: + """ Determine if this weighted value has a value. """ + return self.value != 0.0 + + def has_weight(self) -> bool: + """ Determine if this weighted value has a weight. """ + return self.weight > 0.0 + + @staticmethod + def create_empty() -> 'CommonWeightedValue': + """ Create an empty CommonWeightedValue. """ + return CommonWeightedValue(value=0.0, weight=1.0) + + def __str__(self) -> str: + return 'Weighted Value:\n Value: {}\n Weight: {}'.format(self.value, self.weight) + + def __repr__(self) -> str: + return 'value_{}_weight_{}'.format(repr(self.value), repr(self.weight)) diff --git a/Scripts/s4ap/sims4communitylib/classes/math/common_weighted_value_tally.py b/Scripts/s4ap/sims4communitylib/classes/math/common_weighted_value_tally.py new file mode 100644 index 0000000..215d860 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/math/common_weighted_value_tally.py @@ -0,0 +1,38 @@ +""" +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 +""" +from sims4communitylib.classes.math.common_weighted_value import CommonWeightedValue + + +class CommonWeightedValueTally: + """ A tally that keeps track of weighted values. """ + def __init__(self) -> None: + self._value: CommonWeightedValue = CommonWeightedValue(value=0.0, weight=0.0) + self._value_count: int = 0 + self._weight_count: int = 0 + + def add_value(self, common_weighted_value: CommonWeightedValue): + """ Add to the tally. """ + if common_weighted_value is None: + return + if common_weighted_value.has_value(): + self._value_count += 1 + if common_weighted_value.has_weight(): + self._weight_count += 1 + self._value += common_weighted_value + + def get_total_value(self) -> float: + """ Tally up all weighted values and calculate the total. """ + total_value = self._value.value / max(1, self._value_count) + total_weight = self._value.weight / max(1, self._weight_count) + return total_value * total_weight + + def __str__(self) -> str: + return 'Tally:\n Value: {}\n Weight: {}\n Value Count: {}\n Weight Count: {}'.format(self._value.value, self._value.weight, self._value_count, self._weight_count) + + def __repr__(self) -> str: + return 'tally_{}_value_count_{}_weight_count_{}'.format(repr(self._value), self._value_count, self._weight_count) diff --git a/Scripts/s4ap/sims4communitylib/classes/mixins/__init__.py b/Scripts/s4ap/sims4communitylib/classes/mixins/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/mixins/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/classes/mixins/common_affordance_lists_mixin.py b/Scripts/s4ap/sims4communitylib/classes/mixins/common_affordance_lists_mixin.py new file mode 100644 index 0000000..73c17b2 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/mixins/common_affordance_lists_mixin.py @@ -0,0 +1,21 @@ +""" +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 +""" +from typing import Tuple + + +class CommonAffordanceListsMixin: + """A mixin that will do something with affordance lists.""" + + @property + def affordance_list_ids(self) -> Tuple[int]: + """A collection of identifiers for affordance lists. + + :return: A collection of identifiers for affordance lists. + :rtype: Tuple[int] + """ + raise NotImplementedError() diff --git a/Scripts/s4ap/sims4communitylib/classes/mixins/common_interactions_mixin.py b/Scripts/s4ap/sims4communitylib/classes/mixins/common_interactions_mixin.py new file mode 100644 index 0000000..a29a45c --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/mixins/common_interactions_mixin.py @@ -0,0 +1,40 @@ +""" +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 +""" +from typing import Tuple, Iterator + +from interactions.base.interaction import Interaction + + +class CommonInteractionsMixin: + """A mixin that will do something with interactions.""" + + def __init__(self) -> None: + self._cached_interactions = None + + @property + def interaction_ids(self) -> Tuple[int]: + """A collection of interaction identifiers. + + :return: A collection of interaction identifiers. + :rtype: Tuple[int] + """ + raise NotImplementedError() + + def _interaction_instances_gen(self) -> Iterator[Interaction]: + if self._cached_interactions is not None: + yield from self._cached_interactions + else: + cached_interactions = list() + from sims4communitylib.utils.resources.common_interaction_utils import CommonInteractionUtils + for interaction_id in self.interaction_ids: + interaction = CommonInteractionUtils.load_interaction_by_id(interaction_id) + if interaction is None: + continue + yield interaction + cached_interactions.append(interaction) + self._cached_interactions = cached_interactions diff --git a/Scripts/s4ap/sims4communitylib/classes/options.py b/Scripts/s4ap/sims4communitylib/classes/options.py new file mode 100644 index 0000000..dde1ffb --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/options.py @@ -0,0 +1,117 @@ +""" +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 +""" +from typing import Dict, Any + + +class CommonOption: + """CommonOption(name) + + Useful for giving a type to arguments when str just won't cut it. + + :param name: The name of the option. It is also considered as the value of the option. + :type name: str + """ + def __init__(self, name: str): + self._name = name + + @property + def name(self) -> str: + """The name and string value of the option. + + :return: The name of the option. + :rtype: str + """ + return self._name + + def __hash__(self) -> int: + return hash((self.name,)) + + def __eq__(self, other) -> bool: + return self.name == other.name + + def __ne__(self, other) -> bool: + return not(self == other) + + def __repr__(self) -> str: + return self._name + + def __str__(self) -> str: + return self.__repr__() + + +class HasCommonOptions: + """HasCommonOptions(options) + + An inheritable class that provides a dictionary of custom options. + + :param options: The options contained within the class. + :type options: Dict[CommonOption, Any] + """ + def __init__(self, options: Dict[CommonOption, Any]): + self._options = dict() + if options is not None: + for key, val in options.items(): + self.set_option(key, val) + + @property + def options(self) -> Dict[str, Any]: + """Retrieve all options. + + :return: A dictionary of options. + :rtype: Dict[str, Any] + """ + if self._options is None: + self._options = dict() + return self._options + + @options.setter + def options(self, options: Dict[str, Any]): + self._options = options + + def set_option(self, option: CommonOption, value: Any): + """set_option(option, value) + + Set an option to have the specified value. + + :param option: The option to set the value of. + :type option: CommonOption + :param value: The value to set an option to. + :type value: Any + """ + self._options[str(option)] = value + + def remove_option(self, option: CommonOption): + """remove_option(option) + + Remove an option. + + :param option: The option to delete. + :type option: CommonOption + """ + del self._options[str(option)] + + def get_option(self, option: CommonOption, default_value: Any=None) -> Any: + """get_option(option, default_value=None) + + Retrieve the value of an option. + + :param option: The option to retrieve. + :type option: CommonOption + :param default_value: A default value to return when an option does not exist. Default is None. + :type default_value: Any + :return: An option or the default value if not found. + :rtype: Any + """ + if str(option) not in self.options and default_value is not None: + self.set_option(option, default_value) + return self.options[str(option)] + + +class _DefaultCommonOption(CommonOption): + def __init__(self, name: str): + super().__init__(name or 'Default') diff --git a/Scripts/s4ap/sims4communitylib/classes/resolvers/__init__.py b/Scripts/s4ap/sims4communitylib/classes/resolvers/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/resolvers/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/classes/resolvers/common_double_sim_resolver.py b/Scripts/s4ap/sims4communitylib/classes/resolvers/common_double_sim_resolver.py new file mode 100644 index 0000000..bd3e30c --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/resolvers/common_double_sim_resolver.py @@ -0,0 +1,99 @@ +""" +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 +""" +from typing import Any + +from event_testing.resolver import DoubleSimResolver +from interactions import ParticipantType, ParticipantTypeSituationSims +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + + +class CommonDoubleSimResolver(DoubleSimResolver): + """A double Sim resolver that is able to handle many more participant types.""" + + # noinspection PyMissingOrEmptyDocstring + def get_participants(self, participant_type, **kwargs) -> Any: + from event_testing.test_constants import SIM_INSTANCE, FROM_DATA_OBJECT, OBJECTIVE_GUID64, FROM_EVENT_DATA + if participant_type == SIM_INSTANCE: + participant_type = ParticipantType.Actor + + if participant_type in ( + # Participants Shared + ParticipantType.Lot, + ParticipantType.LotOwners, + ParticipantType.LotOwnersOrRenters, + ParticipantType.LotOwnerSingleAndInstanced, + ParticipantType.ActiveHousehold, + ParticipantType.AllInstancedActiveHouseholdSims, + ParticipantType.CareerEventSim, + ParticipantType.AllInstancedSims, + ParticipantType.Street, + ParticipantType.VenuePolicyProvider, + ParticipantType.CurrentRegion, + # Single Sim Resolver + ParticipantType.Actor, + ParticipantType.CustomSim, + ParticipantType.SignificantOtherActor, + ParticipantType.PregnancyPartnerActor, + ParticipantType.AllRelationships, + ParticipantType.ActorFeudTarget, + ParticipantType.InteractionContext, + ParticipantType.Affordance, + ParticipantType.Familiar, + ParticipantType.PickedZoneId, + ParticipantType.ActorLot, + ParticipantType.RoutingSlaves, + ParticipantType.StoredCASPartsOnObject, + ParticipantType.ActorLotLevel, + # Double Sim Resolver + ParticipantType.TargetSim, + ParticipantType.TargetHouseholdMembers, + ParticipantType.SignificantOtherTargetSim, + ParticipantType.FamiliarOfTarget + ): + return super().get_participants(participant_type, **kwargs) + + sim = CommonSimUtils.get_sim_instance(self.sim_info_to_test) + target_sim = CommonSimUtils.get_sim_instance(self.target_sim_info) + if participant_type == ParticipantType.Object: + return (self.target_sim_info,) + elif participant_type == ParticipantType.ObjectIngredients: + if target_sim is not None and hasattr(target_sim, 'crafting_component') and target_sim.crafting_component and hasattr(target_sim, 'get_crafting_process'): + target_crafting_process = target_sim.get_crafting_process() + if target_crafting_process is not None: + return tuple(target_crafting_process.get_ingredients_object_definitions()) + return () + + if participant_type == ParticipantType.ActorPostureTarget: + return (self.target_sim_info, ) + elif participant_type == ParticipantType.AssociatedClub or participant_type == ParticipantType.AssociatedClubLeader or participant_type == ParticipantType.AssociatedClubMembers: + return () + if participant_type == ParticipantType.ObjectCrafter: + return (self.sim_info_to_test, ) + if participant_type in ParticipantTypeSituationSims: + return self.sim_info_to_test, self.target_sim_info + else: + if participant_type == ParticipantType.ObjectLotLevel: + return self._get_lot_level_from_object(target_sim) + if participant_type == ParticipantType.ActorLotLevel: + return self._get_lot_level_from_object(sim) + if participant_type == 0: + return () + result = self._get_participants_base(participant_type, **kwargs) + if result is not None: + return result + if participant_type == FROM_DATA_OBJECT: + return () + if participant_type == OBJECTIVE_GUID64: + return () + if participant_type == FROM_EVENT_DATA: + return () + if participant_type == ParticipantType.PickedItemId: + return (self.target_sim_info, ) + if participant_type == ParticipantType.Listeners: + return (self.target_sim_info, ) + return self.sim_info_to_test, self.target_sim_info diff --git a/Scripts/s4ap/sims4communitylib/classes/runnables/__init__.py b/Scripts/s4ap/sims4communitylib/classes/runnables/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/runnables/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/classes/runnables/common_runnable.py b/Scripts/s4ap/sims4communitylib/classes/runnables/common_runnable.py new file mode 100644 index 0000000..b9166ba --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/runnables/common_runnable.py @@ -0,0 +1,433 @@ +""" +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 +""" + +from typing import Union, Any, TypeVar, Generic + +from sims4communitylib.classes.runnables.contexts.common_runnable_context import CommonRunnableContext +from sims4communitylib.enums.common_runnable_state_type import CommonRunnableStateType +from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from sims4communitylib.classes.time.common_alarm_handle import CommonAlarmHandle +from sims4communitylib.enums.enumtypes.common_int import CommonInt +from sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags +from sims4communitylib.events.interval.common_interval_event_service import CommonIntervalEventRegistry, \ + CommonIntervalDispatcher +from sims4communitylib.logging.has_class_log import HasClassLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.utils.common_time_utils import CommonTimeUtils +from sims4communitylib.utils.time.common_alarm_utils import CommonAlarmUtils + +CommonRunnableContextType = TypeVar('CommonRunnableContextType', bound=CommonRunnableContext) + + +class CommonRunnable(HasClassLog, Generic[CommonRunnableContextType]): + """CommonRunnable() + + This class is used when you want to have something reoccurring again and again. + + :param context: A context containing information about the runnable as well as actions the runnable should perform. + :type context: CommonRunnableContext + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + raise NotImplementedError() + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + raise NotImplementedError() + + def __init__(self, context: CommonRunnableContextType) -> None: + self._update_alarm: Union[CommonAlarmHandle, None] = None + self._update_dispatcher: Union[CommonIntervalDispatcher, None] = None + self._context = context + self._has_initial_started = False + self._change_state(CommonRunnableStateType.STOPPED) + self.milliseconds_per_update = 1000 + # This is used when we are expecting a reset to happen, and we don't want to cancel the runnable. + self._expect_reset = False + self._is_ended = False + self._await_stop = False + self._await_stop_reason = self.unknown_stop_reason + self._updating = False + super().__init__() + + @property + def context(self) -> CommonRunnableContextType: + """A context containing information about the runnable as well as actions the runnable should perform.""" + return self._context + + @context.setter + def context(self, value: CommonRunnableContextType): + self._context = value + + @property + def is_running(self) -> bool: + """The runnable is running.""" + return self._current_state == CommonRunnableStateType.RUNNING + + @property + def is_starting(self) -> bool: + """The runnable is starting.""" + return self._current_state == CommonRunnableStateType.STARTING + + @property + def is_waiting_for_start(self) -> bool: + """The runnable is waiting to start.""" + return self._current_state == CommonRunnableStateType.WAITING_TO_START + + @property + def is_stopping(self) -> bool: + """The runnable is stopping.""" + return self._current_state == CommonRunnableStateType.STOPPING + + @property + def is_stopped(self) -> bool: + """The runnable is stopped.""" + return self._current_state == CommonRunnableStateType.STOPPED + + def _start_updater(self, milliseconds_per_update: int) -> None: + self._stop_updater() + self._updating = False + + def _start_update(_: Any) -> None: + if self._updating: + return + self._updating = True + + def _run_update() -> None: + try: + self.update(milliseconds_per_update) + finally: + self._updating = False + + _run_update() + + if self.context.should_run_on_game_time: + sim_minutes = int(CommonTimeUtils.convert_milliseconds_to_seconds(milliseconds_per_update)) + time_until_update = CommonTimeUtils.create_interval_from_sim_minutes(sim_minutes) + self._update_alarm = CommonAlarmUtils.schedule_alarm( + self, + time_until_update, + _start_update, + should_repeat=True, + time_until_repeat=time_until_update + ) + else: + self._update_dispatcher = CommonIntervalEventRegistry()._add_tracker( + self.mod_identity, + milliseconds_per_update, + lambda *_, **__: _start_update(None) + ) + + def _stop_updater(self) -> None: + if self._update_dispatcher is not None: + if self._update_dispatcher in CommonIntervalEventRegistry()._registered_interval_trackers: + self.log.format_with_message('Removing update dispatcher from interval trackers.') + CommonIntervalEventRegistry()._registered_interval_trackers.remove(self._update_dispatcher) + self._update_dispatcher = None + + if self._update_alarm is not None: + CommonAlarmUtils.cancel_alarm(self._update_alarm) + self._update_alarm = None + + @property + def milliseconds_per_update(self) -> int: + """The number of milliseconds between updates.""" + return self._milliseconds_per_update + + @milliseconds_per_update.setter + def milliseconds_per_update(self, value: int): + self._milliseconds_per_update = value + self._start_updater(value) + + def _change_state(self, new_state: CommonRunnableStateType): + self._current_state = new_state + + def start(self, *_, **__) -> CommonExecutionResult: + """start(*_, **__) + + Start the runnable. + + :return: True, if the runnable has successfully been started. False, if not. + :rtype: CommonExecutionResult + """ + try: + self._is_ended = False + if self.is_starting: + self.log.debug('Failed to start runnable, Already starting!') + return CommonExecutionResult(True, reason='Runnable Is Already starting') + + on_initialize_result = self._on_initialize(*_, **__) + if not on_initialize_result: + self.log.format_error_with_message('On Initialize Failed.', runnable=self, result=on_initialize_result) + self.stop(self.invalid_stop_reason, force_stop=True) + return on_initialize_result + + self.log.debug('Attempting to start runnable.') + if self.is_running: + self.log.debug('Success, runnable has already been started.') + return CommonExecutionResult.TRUE + + is_waiting_to_start = self.is_waiting_for_start + self._change_state(CommonRunnableStateType.STARTING) + + on_setup_result = self._on_setup(*_, is_waiting_to_start=is_waiting_to_start, **__) + if not on_setup_result: + self.log.format_error_with_message('On Setup Failed', runnable=self, context=self.context, result=on_setup_result) + self.stop(self.invalid_stop_reason, force_stop=True) + return on_setup_result + + if self.is_waiting_for_start: + self.log.format_with_message('Runnable is waiting to start.') + return CommonExecutionResult.TRUE + + self._start_updater(self.milliseconds_per_update) + + if not self._has_initial_started: + on_initial_start_result = self._on_initial_start(*_, **__) + if not on_initial_start_result: + self.log.format_error_with_message('On Initial Start Failed.', result=on_initial_start_result) + self.stop(self.invalid_stop_reason, force_stop=True) + return on_initial_start_result + + on_start_result = self._on_start() + if not on_start_result: + self.log.format_error_with_message('On Start Failed.', result=on_start_result) + return on_start_result + + self.log.debug('Finished starting runnable.') + self._change_state(CommonRunnableStateType.RUNNING) + self._has_initial_started = True + return CommonExecutionResult.TRUE + except Exception as ex: + self.log.error('Error occurred while starting runnable.', exception=ex) + self._expect_reset = False + self.stop(self.invalid_stop_reason, force_stop=True) + return CommonExecutionResult(False, reason=f'An error occurred while starting {ex}.') + + # noinspection PyUnusedLocal + def should_update(self, milliseconds_since_last_update: int) -> CommonExecutionResult: + """should_update(milliseconds_since_last_update) + + Determine if the runnable should update. + + :param milliseconds_since_last_update: The number of milliseconds since the last update. + :type milliseconds_since_last_update: int + :return: True, if the update should continue. False, if not. + :rtype: CommonExecutionResult + """ + return CommonExecutionResult.TRUE + + def update(self, milliseconds_since_last_update: int, *_, **__) -> CommonExecutionResult: + """update(milliseconds_since_last_update, *_, **__) + + Update the runnable. + + .. note:: This function is invoked automatically by the runnable itself. + + :param milliseconds_since_last_update: The number of milliseconds since the last update. + :type milliseconds_since_last_update: int + :return: True, if the update is successful. False, if not. + :rtype: CommonExecutionResult + """ + try: + if self._is_ended: + self.verbose_log.debug('Failed to update runnable, it has already ended.') + return CommonExecutionResult(False, reason='Has already ended.') + + if self._await_stop: + self.verbose_log.debug('Failed to update runnable, it is awaiting a stop.') + self.stop(self._await_stop_reason) + return CommonExecutionResult(False, reason='Runnable is waiting to stop.') + + if self.is_waiting_for_start: + if self._has_finished_waiting_to_start(milliseconds_since_last_update, *_, **__): + self.log.format_with_message('Finished waiting to start. Attempting to start runnable now.') + self.restart(self.start_after_wait_reason) + return CommonExecutionResult(True, reason='Finished Waiting for runnable to begin. We still do not want to update.') + + on_continue_waiting_result = self._on_continue_waiting_to_start() + if not on_continue_waiting_result: + self.log.format_error_with_message('On Continue Waiting To Start Failed.', result=on_continue_waiting_result) + self.stop(self.invalid_stop_reason, force_stop=True) + return on_continue_waiting_result + + self.log.format_with_message('Waiting for runnable to start.') + return CommonExecutionResult(True, reason='Waiting for runnable to start.') + + if not self.is_running or self.is_stopping or self.is_stopped: + self.verbose_log.format_with_message('Failed to update runnable, it is either not running, it is stopping, or it is stopped.', running=self.is_running, stopping=self.is_stopping) + return CommonExecutionResult(False, reason='Runnable is not running.') + + self.verbose_log.format_with_message( + 'Updating Runnable', + class_name=self.__class__.__name__, + milliseconds_since_last_update=milliseconds_since_last_update + ) + should_update_result = self.should_update(milliseconds_since_last_update) + if not should_update_result: + self.verbose_log.format_with_message('Skipping update due to request to skip update.', result=should_update_result) + return CommonExecutionResult.TRUE + + on_update_result = self._on_update(milliseconds_since_last_update) + if not on_update_result: + self.log.format_error_with_message('On Update Failed', result=on_update_result) + self.stop(self.invalid_stop_reason, force_stop=True) + + return on_update_result + except Exception as ex: + self.log.error('Error occurred while updating runnable.', exception=ex) + self._expect_reset = False + self.stop(self.invalid_stop_reason, force_stop=True) + return CommonExecutionResult(False, reason=f'An error occurred while updating {ex}.') + + def stop(self, stop_reason: Union[int, CommonInt, CommonIntFlags], *_, force_stop: bool = False, **__) -> CommonExecutionResult: + """stop(stop_reason, force_stop=False) + + Stop the runnable. + + :param stop_reason: The reason the runnable is being stopped for. + :type stop_reason: Union[int, CommonInt, CommonIntFlags] + :param force_stop: If True, the is_stopping state will not be checked and the runner will be forced to stop. Default is False. + :type force_stop: bool, optional + :return: True, if the runnable has been stopped successfully. False, if not. + :rtype: CommonExecutionResult + """ + try: + if not force_stop and self.is_stopping: + self.log.format_with_message('Failed to stop, runnable is already stopping.', stop_reason=stop_reason) + return CommonExecutionResult(True, reason='Already stopping.') + + if self._expect_reset: + self.log.format_with_message('Failed to stop, runnable is expected to be restarting.', stop_reason=stop_reason) + return CommonExecutionResult.TRUE + + if stop_reason == self.invalid_stop_reason and not self._has_initial_started: + stop_reason = self.cancel_stop_reason + + self._change_state(CommonRunnableStateType.STOPPING) + self.log.format_with_message('Stopping runnable', stop_reason=stop_reason) + + on_stop_result = self._on_stop(stop_reason, *_, force_stop=force_stop, **__) + if not on_stop_result: + self.log.format_error_with_message('On Stop Failed.', result=on_stop_result) + return on_stop_result + + if self._is_restart_stop_reason(stop_reason): + self.log.format_with_message('Stopping due to a restart.', stop_reason=stop_reason) + on_restart_result = self._on_restart(stop_reason) + if not on_restart_result: + self.log.format_error_with_message('On Restart Failed.', result=on_restart_result) + return CommonExecutionResult.TRUE + + self._stop_updater() + + self._is_ended = True + + on_end_result = self._on_end(stop_reason, *_, force_stop=force_stop, **__) + if not on_end_result: + self.log.format_with_message('On End Failed.', result=on_end_result) + return on_end_result + + self.log.format_with_message('Done ending runnable.', stop_reason=stop_reason) + return on_end_result + except Exception as ex: + self.log.error('Error occurred while stopping runnable.', exception=ex) + self._expect_reset = False + if stop_reason != self.invalid_stop_reason: + self.stop(self.invalid_stop_reason, force_stop=True) + return CommonExecutionResult(False, reason=f'An error occurred while stopping {ex}.') + finally: + self._change_state(CommonRunnableStateType.STOPPED) + self._expect_reset = False + + def restart(self, restart_reason: Union[int, CommonInt, CommonIntFlags], *_, **__) -> CommonExecutionResult: + """restart(restart_reason, *_, **__) + + Restart the runnable. + + :param restart_reason: The reason for the restart. + :type restart_reason: Union[int, CommonInt, CommonIntFlags] + :return: True, if the runnable has been restarted successfully. False, if not. + :rtype: CommonExecutionResult + """ + self.log.format_with_message('Restarting runnable', restart_reason=restart_reason) + self.stop(restart_reason) + return self.start() + + @property + def invalid_stop_reason(self) -> Union[int, CommonInt, CommonIntFlags]: + """A reason for the runnable to be stopped for invalid reasons.""" + raise NotImplementedError() + + @property + def unknown_stop_reason(self) -> Union[int, CommonInt, CommonIntFlags]: + """A reason for the runnable to be stopped for unknown reasons.""" + raise NotImplementedError() + + @property + def cancel_stop_reason(self) -> Union[int, CommonInt, CommonIntFlags]: + """A reason for the runnable to be stopped for a cancel reasons.""" + raise NotImplementedError() + + @property + def start_after_wait_reason(self) -> Union[int, CommonInt, CommonIntFlags]: + """A reason for the runnable to be stopped after waiting for it to start.""" + raise NotImplementedError() + + def _is_restart_stop_reason(self, stop_reason: Union[int, CommonInt, CommonIntFlags]) -> bool: + raise NotImplementedError() + + def _is_end_stop_reason(self, stop_reason: Union[int, CommonInt, CommonIntFlags]) -> bool: + raise NotImplementedError() + + def _on_start(self, *_, **__) -> CommonExecutionResult: + return CommonExecutionResult.TRUE + + def _on_update(self, milliseconds_since_last_update: int, *_, **__) -> CommonExecutionResult: + return self.context.update(milliseconds_since_last_update, *_, **__) + + # noinspection PyUnusedLocal + def _on_restart(self, restart_reason: Union[int, CommonInt, CommonIntFlags], *_, **__) -> CommonExecutionResult: + return self.context.restart(restart_reason, *_, **__) + + # noinspection PyUnusedLocal + def _on_stop(self, stop_reason: Union[int, CommonInt, CommonIntFlags], *_, force_stop: bool = False, **__) -> CommonExecutionResult: + return CommonExecutionResult.TRUE + + def _on_end(self, stop_reason: Union[int, CommonInt, CommonIntFlags], *_, force_stop: bool = False, **__) -> CommonExecutionResult: + return self.context.teardown(stop_reason, *_, force_stop, **__) + + # noinspection PyUnusedLocal + def _has_finished_waiting_to_start(self, milliseconds_since_last_update: int, *_, **__) -> bool: + return True + + def _on_continue_waiting_to_start(self, *_, **__) -> CommonExecutionResult: + return CommonExecutionResult.TRUE + + def _on_initialize(self, *_, **__) -> CommonExecutionResult: + return self.context.initialize(*_, **__) + + def _on_initial_start(self, *_, **__) -> CommonExecutionResult: + return CommonExecutionResult.TRUE + + def _on_setup(self, *_, is_waiting_to_start: bool = False, **__) -> CommonExecutionResult: + return self.context.setup(*_, is_waiting_to_start=is_waiting_to_start, **__) + + def __eq__(self, other: 'CommonRunnable') -> bool: + if not isinstance(other, CommonRunnable): + return False + return self.context.__eq__(other.context) + + def __repr__(self) -> str: + return repr(self.context) + + def __str__(self) -> str: + return str(self.context) diff --git a/Scripts/s4ap/sims4communitylib/classes/runnables/common_runnable_with_sims.py b/Scripts/s4ap/sims4communitylib/classes/runnables/common_runnable_with_sims.py new file mode 100644 index 0000000..da59534 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/runnables/common_runnable_with_sims.py @@ -0,0 +1,187 @@ +""" +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 +""" + +from typing import Union, List, Tuple, TypeVar, Generic + +from sims.sim import Sim +from sims4communitylib.classes.runnables.common_runnable import CommonRunnable +from sims4communitylib.classes.runnables.contexts.common_runnable_context_with_sims import CommonRunnableContextWithSims +from sims4communitylib.classes.runnables.contexts.common_runnable_sim_context import CommonRunnableSimContext +from sims.sim_info import SimInfo +from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from sims4communitylib.enums.enumtypes.common_int import CommonInt +from sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags +from sims4communitylib.mod_support.mod_identity import CommonModIdentity + +CommonRunnableContextWithSimsType = TypeVar('CommonRunnableContextWithSimsType', bound=CommonRunnableContextWithSims) +CommonRunnableSimContextType = TypeVar('CommonRunnableSimContextType', bound=CommonRunnableSimContext) + + +class CommonRunnableWithSims(CommonRunnable[CommonRunnableContextWithSimsType], Generic[CommonRunnableContextWithSimsType, CommonRunnableSimContextType]): + """CommonRunnableWithSims() + + This class is used when you want to have something reoccurring again and again. Specifically when it involves something reoccurring for Sims again and again. + + :param context: A context containing information about the runnable as well as actions the runnable should perform, including which Sims to perform the actions with. + :type context: CommonRunnableContextWithSims + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + raise NotImplementedError() + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + raise NotImplementedError() + + # noinspection PyMissingOrEmptyDocstring + @property + def invalid_stop_reason(self) -> Union[int, CommonInt, CommonIntFlags]: + raise NotImplementedError() + + # noinspection PyMissingOrEmptyDocstring + @property + def unknown_stop_reason(self) -> Union[int, CommonInt, CommonIntFlags]: + raise NotImplementedError() + + # noinspection PyMissingOrEmptyDocstring + @property + def cancel_stop_reason(self) -> Union[int, CommonInt, CommonIntFlags]: + raise NotImplementedError() + + # noinspection PyMissingOrEmptyDocstring + @property + def start_after_wait_reason(self) -> Union[int, CommonInt, CommonIntFlags]: + raise NotImplementedError() + + def _is_restart_stop_reason(self, stop_reason: Union[int, CommonInt, CommonIntFlags]) -> bool: + raise NotImplementedError() + + def _is_end_stop_reason(self, stop_reason: Union[int, CommonInt, CommonIntFlags]) -> bool: + raise NotImplementedError() + + def __init__(self, context: CommonRunnableContextWithSimsType) -> None: + super().__init__(context) + + # noinspection PyMissingOrEmptyDocstring + @property + def context(self) -> CommonRunnableContextWithSimsType: + return self._context + + @context.setter + def context(self, value: CommonRunnableContextWithSimsType): + self._context = value + + @property + def sim_contexts(self) -> List[CommonRunnableSimContextType]: + """A collection of Sim Contexts within the context.""" + return self.context.sim_contexts + + @property + def sims_as_sim_id(self) -> Tuple[int]: + """Retrieves a collection of decimal identifiers for the Sims.""" + return self.context.sims_as_sim_id + + @property + def sims_as_sim_info(self) -> Tuple[SimInfo]: + """Retrieves a collection of Sim Info for the Sims.""" + return self.context.sims_as_sim_info + + @property + def sims_as_sim(self) -> Tuple[Sim]: + """Retrieves a collection of Sim Instances for the Sims.""" + return self.context.sims_as_sim + + def has_sim_context(self, sim_info: SimInfo) -> bool: + """has_sim_context(sim_info) + + Determine if a Sim Context exists for a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: True, if a Sim Context exists for the Sim. False, if not. + :rtype: bool + """ + return self.context.has_sim_context(sim_info) + + def get_sim_context(self, sim_info: SimInfo) -> Union[CommonRunnableSimContextType, None]: + """get_sim_context(sim_info) + + Retrieve the Sim Context for a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The Sim Context matching the Sim or None if no context matches. + :rtype: Union[CommonRunnableSimContext, None] + """ + return self.context.get_sim_context(sim_info) + + def add_sim_context(self, sim_context: CommonRunnableSimContextType, add_reason: Union[int, CommonInt, CommonIntFlags], restart_after_add: bool = True) -> CommonExecutionResult: + """add_sim_context(sim_context, add_reason, restart_after_add=True) + + Add a Sim Context to the context. + + :param sim_context: A Sim Context. + :type sim_context: CommonRunnableSimContextType + :param add_reason: The reason the Sim Context is being added. + :type add_reason: Union[int, CommonInt, CommonIntFlags] + :param restart_after_add: If True, the Runnable will be restarted after the Sim is added. If False, the Runnable will not be restarted after add. Default is True. + :type restart_after_add: bool, optional + :return: True, if the context was added successfully. False, if not. + :rtype: CommonExecutionResult + """ + if self.has_sim_context(sim_context.sim_info): + return CommonExecutionResult(False, reason=f'Sim {sim_context.sim_info} is already a part of the runnable.') + add_result = self.context.add_sim_context(sim_context) + if not add_result: + return add_result + if restart_after_add: + return self.restart(add_reason) + return CommonExecutionResult.TRUE + + def remove_sim_context(self, sim_context: CommonRunnableSimContextType, remove_reason: Union[int, CommonInt, CommonIntFlags], *_, restart_after_remove: bool = True, **__) -> CommonExecutionResult: + """remove_sim_context(sim_context, remove_reason, restart_after_remove=True) + + Remove a Sim Context from the context. + + :param sim_context: A Sim Context. + :type sim_context: CommonRunnableSimContextType + :param remove_reason: The reason the context is being removed. + :type remove_reason: Union[int, CommonInt, CommonIntFlags] + :param restart_after_remove: If True, the Runnable will be restarted after the Sim is removed. If False, the Runnable will not be restarted after remove. Default is True. + :type restart_after_remove: bool, optional + :return: True, if the Sim Context was removed from the context successfully. False, if not. + :rtype: CommonExecutionResult + """ + remove_result = self.context.remove_sim_context(sim_context, remove_reason, *_, restart_after_remove=restart_after_remove, **__) + if not remove_result: + return remove_result + if restart_after_remove: + return self.restart(remove_reason) + return CommonExecutionResult.TRUE + + def remove_sim(self, sim_info: SimInfo, remove_reason: Union[int, CommonInt, CommonIntFlags], *_, restart_after_remove: bool = False, **__) -> CommonExecutionResult: + """remove_sim(sim_info, remove_reason) + + Remove a Sim from the context. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param remove_reason: The reason the Sim is being removed. + :type remove_reason: Union[int, CommonInt, CommonIntFlags] + :param restart_after_remove: If True, the Runnable will be restarted after the Sim is removed. If False, the Runnable will not be restarted after remove. Default is True. + :type restart_after_remove: bool, optional + :return: True, if the sim was removed from the context successfully. False, if not. + :rtype: CommonExecutionResult + """ + sim_context = self.get_sim_context(sim_info) + if sim_context is None: + return CommonExecutionResult(False, reason=f'Sim {sim_info} did not have a Sim context!') + return self.remove_sim_context(sim_context, remove_reason, *_, restart_after_remove=restart_after_remove, **__) diff --git a/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/__init__.py b/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/__init__.py new file mode 100644 index 0000000..3251898 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" \ No newline at end of file diff --git a/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_context.py b/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_context.py new file mode 100644 index 0000000..0ecf3c6 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_context.py @@ -0,0 +1,250 @@ +""" +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 +""" + +from typing import Union, Dict, Any, Tuple, TypeVar, Type + +from sims4communitylib.classes.serialization.common_serializable import CommonSerializable +from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from sims4communitylib.enums.enumtypes.common_int import CommonInt +from sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags +from sims4communitylib.logging.has_class_log import HasClassLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity + +CommonRunnableContextType = TypeVar('CommonRunnableContextType', bound="CommonRunnableContext") + + +class CommonRunnableContext(CommonSerializable, HasClassLog): + """CommonRunnableContext() + + A context used by a runnable. + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + raise NotImplementedError() + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + raise NotImplementedError() + + def __init__(self: CommonRunnableContextType) -> None: + super().__init__() + self._initialized = False + self._total_milliseconds = 0 + + @property + def should_run_on_game_time(self) -> bool: + """Determine if the context should be run using game time or if it should be run using real time.""" + return True + + @property + def should_track_total_time(self) -> bool: + """Determine if the total time in milliseconds should be tracked. Default is False.""" + return False + + @property + def total_milliseconds(self) -> int: + """A counter for the total number of milliseconds the context has been running for.""" + return self._total_milliseconds + + def clear_total_milliseconds(self) -> None: + """clear_time_since_setup() + + Clear the total time passed since the context was set up. + """ + self._total_milliseconds = 0 + + def initialize(self, *_, **__) -> CommonExecutionResult: + """initialize(*_, **__) + + Initialize the context. + + :return: True, if successful. False, if not. + :rtype: CommonExecutionResult + """ + self.log.format_with_message('Attempting to initialize runnable context.') + if self._initialized: + self.log.format_with_message('Failed to initialize context. It was already initialized.') + return CommonExecutionResult.TRUE + initialize_result = self._initialize(*_, **__) + if not initialize_result: + self.log.format_with_message('Failed to initialize context.') + return initialize_result + self._initialized = True + self.log.debug('Finished initializing context.') + return CommonExecutionResult.TRUE + + def setup(self, *_, **__) -> CommonExecutionResult: + """setup(*_, **__) + + Setup the context. + + :return: True, if successful. False, if not. + :rtype: CommonExecutionResult + """ + self.log.format_with_message('Setting up context.') + self.clear_total_milliseconds() + return self._setup(*_, **__) + + # noinspection PyUnusedLocal + def should_update(self, milliseconds_since_last_update: int, *_, **__) -> CommonExecutionResult: + """should_update(milliseconds_since_last_update, *_, **__) + + Determine if the context should update. + + :param milliseconds_since_last_update: The number of milliseconds since the last update. + :type milliseconds_since_last_update: int + :return: True, if the context should update. False, if not. + :rtype: CommonExecutionResult + """ + return CommonExecutionResult.TRUE + + def update(self, milliseconds_since_last_update: int, *_, **__) -> CommonExecutionResult: + """update(milliseconds_since_last_update, *_, **__) + + Update the context. + + :param milliseconds_since_last_update: The number of milliseconds since the last update. + :type milliseconds_since_last_update: int + :return: True, if successful. False, if not. + :rtype: CommonExecutionResult + """ + should_update_result = self.should_update(milliseconds_since_last_update, *_, **__) + if not should_update_result: + return should_update_result.reverse_result() + pre_update_result = self._pre_update(milliseconds_since_last_update, *_, **__) + if not pre_update_result: + return pre_update_result + if self.should_track_total_time: + self._total_milliseconds += milliseconds_since_last_update + update_result = self._update(milliseconds_since_last_update, *_, **__) + if not update_result: + return update_result + return self._post_update(milliseconds_since_last_update, *_, **__) + + def restart(self, restart_reason: Union[int, CommonInt, CommonIntFlags], *_, **__) -> CommonExecutionResult: + """restart(restart_reason, *_, **__) + + Restart the context. + + :param restart_reason: The reason the context to be restarted. + :type restart_reason: Union[int, CommonInt, CommonIntFlags] + :return: True, if successful. False, if not. + :rtype: CommonExecutionResult + """ + self.log.format_with_message('Restarting context.', reason=restart_reason) + return self._restart(restart_reason, *_, **__) + + def teardown(self, teardown_reason: Union[int, CommonInt, CommonIntFlags], *_, **__) -> CommonExecutionResult: + """teardown(teardown_reason, *_, **__) + + Teardown the context. + + :param teardown_reason: The reason the context to be torn down. + :type teardown_reason: Union[int, CommonInt, CommonIntFlags] + :return: True, if successful. False, if not. + :rtype: CommonExecutionResult + """ + self.log.format_with_message('Tearing down context.', reason=teardown_reason) + return self._teardown(teardown_reason, *_, **__) + + # -------------------------Hooks Start------------------------- + + def _initialize(self, *_, **__) -> CommonExecutionResult: + raise NotImplementedError() + + def _setup(self, *_, **__) -> CommonExecutionResult: + raise NotImplementedError() + + # noinspection PyUnusedLocal + def _pre_update(self, milliseconds_since_last_update: int, *_, **__) -> CommonExecutionResult: + return CommonExecutionResult.TRUE + + def _update(self, milliseconds_since_last_update: int, *_, **__) -> CommonExecutionResult: + raise NotImplementedError() + + # noinspection PyUnusedLocal + def _post_update(self, milliseconds_since_last_update: int, *_, **__) -> CommonExecutionResult: + return CommonExecutionResult.TRUE + + def _restart(self, restart_reason: Union[int, CommonInt, CommonIntFlags], *_, **__) -> CommonExecutionResult: + return CommonExecutionResult.TRUE + + def _teardown(self, teardown_reason: Union[int, CommonInt, CommonIntFlags], *_, **__) -> CommonExecutionResult: + raise NotImplementedError() + + # -------------------------Hooks End------------------------- + + def clone(self: CommonRunnableContextType, *_, **__) -> CommonRunnableContextType: + """clone(*_, **__) + + Create a clone of the context. + + :return: A cloned version of this context. + :rtype: CommonRunnableContext + """ + clone_args = self._clone_args(*_, **__) + clone_kwargs = self._clone_kwargs(*_, **__) + + # noinspection PyArgumentList + return self.__class__( + *clone_args, + **clone_kwargs + ) + + def _clone_args(self, *_, **__) -> Tuple[Any]: + return tuple() + + def _clone_kwargs(self, *_, **__) -> Dict[str, Any]: + return dict() + + # noinspection PyMissingOrEmptyDocstring + def serialize(self) -> Union[str, Dict[str, Any]]: + data = dict() + self._serialize_data(data) + return data + + def _serialize_data(self, data: Dict[str, Any]): + pass + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def deserialize(cls: Type[CommonRunnableContextType], data: Union[str, Dict[str, Any]]) -> Union[CommonRunnableContextType, None]: + deserialized_args = cls._deserialize_args(data) + if deserialized_args is None: + return None + deserialized_kwargs = cls._deserialize_kwargs(data) + if deserialized_kwargs is None: + return None + + # noinspection PyArgumentList + return cls( + *deserialized_args, + **deserialized_kwargs + ) + + @classmethod + def _deserialize_args(cls, data: Union[str, Dict[str, Any]]) -> Union[Tuple[Any], None]: + return tuple() + + # noinspection PyUnusedLocal + @classmethod + def _deserialize_kwargs(cls, data: Union[str, Dict[str, Any]]) -> Union[Dict[str, Any], None]: + return dict() + + def __repr__(self) -> str: + return self.__str__() + + def __str__(self) -> str: + str_extras = self._get_str() + return f'<[CRC] {str_extras}>' + + def _get_str(self) -> str: + return '' diff --git a/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_context_with_sims.py b/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_context_with_sims.py new file mode 100644 index 0000000..f114217 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_context_with_sims.py @@ -0,0 +1,279 @@ +""" +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 +""" + +from typing import Union, Iterator, List, Tuple, Any, Dict, Type, TypeVar, Generic + +from sims.sim import Sim +from sims4communitylib.classes.runnables.contexts.common_runnable_context import CommonRunnableContext +from sims4communitylib.classes.runnables.contexts.common_runnable_sim_context import CommonRunnableSimContext +from sims.sim_info import SimInfo +from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from sims4communitylib.enums.enumtypes.common_int import CommonInt +from sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags +from sims4communitylib.mod_support.mod_identity import CommonModIdentity + +CommonRunnableSimContextType = TypeVar('CommonRunnableSimContextType', bound=CommonRunnableSimContext) + + +class CommonRunnableContextWithSims(CommonRunnableContext, Generic[CommonRunnableSimContextType]): + """CommonRunnableContextWithSims() + + A context used by a runnable. + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + raise NotImplementedError() + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + raise NotImplementedError() + + def __init__(self, sim_contexts: Iterator[CommonRunnableSimContextType]) -> None: + super().__init__() + self._sim_contexts = list(sim_contexts) + + @property + def sim_contexts(self) -> List[CommonRunnableSimContextType]: + """A collection of Sim Contexts within the context.""" + return self._sim_contexts + + @classmethod + def sim_context_type(cls) -> Type['CommonRunnableSimContextType']: + """The context type for Sim info.""" + raise NotImplementedError() + + @property + def sims_as_sim_id(self) -> Tuple[int]: + """Retrieves a collection of decimal identifiers for the Sims.""" + result: Tuple[int, ...] = tuple([context.sim_id for context in self.sim_contexts]) + return result + + @property + def sims_as_sim_info(self) -> Tuple[SimInfo]: + """Retrieves a collection of Sim Info for the Sims.""" + result: Tuple[SimInfo, ...] = tuple([context.sim_info for context in self.sim_contexts]) + return result + + @property + def sims_as_sim(self) -> Tuple[Sim]: + """Retrieves a collection of Sim Instances for the Sims.""" + result: Tuple[Sim, ...] = tuple([context.sim for context in self.sim_contexts]) + return result + + def has_sim_context(self, sim_info: SimInfo) -> bool: + """has_sim_context(sim_info) + + Determine if a Sim Context exists for a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: True, if a Sim Context exists for the Sim. False, if not. + :rtype: bool + """ + return self.get_sim_context(sim_info) is not None + + def get_sim_context(self, sim_info: SimInfo) -> Union[CommonRunnableSimContextType, None]: + """get_sim_context(sim_info) + + Retrieve the Sim Context for a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The Sim Context matching the Sim or None if no context matches. + :rtype: Union[CommonRunnableSimContextType, None] + """ + self.verbose_log.format_with_message('Retrieving Sim Context.', sim=sim_info) + for sim_context in self.sim_contexts: + if sim_context.sim_info is sim_info: + self.verbose_log.format_with_message('Found Sim Context.', sim=sim_info) + return sim_context + self.verbose_log.format_with_message('Failed to locate Sim Context.', sim=sim_info) + return None + + def add_sim_context(self, sim_context: CommonRunnableSimContextType, *_, **__) -> CommonExecutionResult: + """add_sim_context(sim_context, *_, **__) + + Add a Sim Context to the context. + + :param sim_context: A Sim Context. + :type sim_context: CommonRunnableSimContextType + :return: True, if the context was added successfully. False, if not. + :rtype: CommonExecutionResult + """ + self.log.format_with_message('Adding Sim Context.', sim_context=sim_context) + if self.has_sim_context(sim_context.sim_info): + self.log.format_with_message('Failed, the Sim was already a part of the context.', sim_context=sim_context) + return CommonExecutionResult.TRUE + + result = sim_context.initialize(self, *_, **__) + if not result: + self.log.format_error_with_message('Failed to initialize Sim Context', context=sim_context, result=result) + return result + + if sim_context not in self._sim_contexts: + self._sim_contexts.append(sim_context) + self.log.format_with_message('Finished adding Sim Context.', sim=sim_context) + return CommonExecutionResult.TRUE + + def remove_sim_context(self, sim_context: CommonRunnableSimContextType, remove_reason: Union[int, CommonInt, CommonIntFlags], *_, **__) -> CommonExecutionResult: + """remove_sim_context(sim_context, remove_reason, *_, **__) + + Remove a Sim Context from the context. + + :param sim_context: A Sim Context. + :type sim_context: CommonRunnableSimContextType + :param remove_reason: The reason the context is being removed. + :type remove_reason: Union[int, CommonInt, CommonIntFlags] + :return: True, if the Sim Context was removed from the context successfully. False, if not. + :rtype: CommonExecutionResult + """ + if sim_context is None: + self.log.format_with_message('Sim Context was None.', sim_context=sim_context) + return CommonExecutionResult.FALSE + self.log.format_with_message('Removing Sim Context.', sim_context=sim_context) + result = sim_context.teardown(remove_reason, self, *_, **__) + if not result: + self.log.format_error_with_message('Failed to tear down Sim Context', context=sim_context, result=result) + return result + if sim_context in self._sim_contexts: + self.log.format_with_message('Found Sim Context, removing it now.', sim_context=sim_context) + self._sim_contexts.remove(sim_context) + self.log.format_with_message('Removed Sim Context.', sim_context=sim_context) + return CommonExecutionResult.TRUE + + def remove_sim(self, sim_info: SimInfo, remove_reason: Union[int, CommonInt, CommonIntFlags], *_, **__) -> CommonExecutionResult: + """remove_sim(sim_info, remove_reason, *_, **__) + + Remove a Sim from the context. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param remove_reason: The reason the Sim is being removed. + :type remove_reason: Union[int, CommonInt, CommonIntFlags] + :return: True, if the sim was removed from the context successfully. False, if not. + :rtype: CommonExecutionResult + """ + sim_context = self.get_sim_context(sim_info) + if sim_context is None: + self.log.format_with_message('No Sim Context found for Sim.', sim=sim_info) + return CommonExecutionResult.FALSE + remove_result = self.remove_sim_context(sim_context, remove_reason, *_, **__) + if not remove_result: + self.log.format_with_message('Failed to remove Sim Context.', sim=sim_info, result=remove_result) + return remove_result + return CommonExecutionResult.TRUE + + def _initialize(self, *_, **__) -> CommonExecutionResult: + self.log.format_with_message('Initializing Sim Contexts.') + for sim_context in self.sim_contexts: + result = sim_context.initialize(self, *_, **__) + if not result: + self.log.format_error_with_message('Failed to initialize Sim Context.', sim_context=sim_context, result=result) + return result + self.log.format_with_message('Finished initializing Sim Context.') + return CommonExecutionResult.TRUE + + def _setup(self, *_, **__) -> CommonExecutionResult: + self.log.format_with_message('Setting Up Sim Contexts.') + for sim_context in self.sim_contexts: + result = sim_context.setup(self, *_, **__) + if not result: + self.log.format_error_with_message('Failed to setup Sim Context', sim_context=sim_context, result=result) + return result + self.log.format_with_message('Finished setting up Sim Contexts.') + return CommonExecutionResult.TRUE + + def _update(self, milliseconds_since_last_update: int, *_, **__) -> CommonExecutionResult: + self.log.format_with_message('Updating Sim Contexts.') + for sim_context in self.sim_contexts: + result = sim_context.update(milliseconds_since_last_update, self, *_, **__) + if not result: + self.log.format_error_with_message('Failed to update Sim Context.', sim_context=sim_context, result=result) + return result + self.log.format_with_message('Finished updating Sim Contexts.') + return CommonExecutionResult.TRUE + + def _restart(self, restart_reason: Union[int, CommonInt, CommonIntFlags], *_, **__) -> CommonExecutionResult: + self.log.format_with_message('Restarting Sim Contexts.', restart_reason=restart_reason) + for sim_context in self.sim_contexts: + result = sim_context.restart(restart_reason, self, *_, **__) + if not result: + self.log.format_error_with_message('Failed to restart Sim Context.', sim_context=sim_context, result=result) + return result + self.log.format_with_message('Finished restarting Sim Contexts.', restart_reason=restart_reason) + return CommonExecutionResult.TRUE + + def _teardown(self, teardown_reason: Union[int, CommonInt, CommonIntFlags], *_, **__) -> CommonExecutionResult: + self.log.format_with_message('Tearing Down Sim Contexts.', teardown_reason=teardown_reason) + for sim_context in self.sim_contexts: + try: + result = sim_context.teardown(teardown_reason, self, *_, **__) + if not result: + self.log.format_error_with_message('Failed to tear down Sim Context.', sim_context=sim_context, result=result) + return result + except Exception as ex: + self.log.format_error_with_message('An error occurred while tearing down Sim Context.', sim_context=sim_context, exception=ex) + continue + self.log.format_with_message('Finished Tearing Down Sim Contexts.') + return CommonExecutionResult.TRUE + + def _clone_args(self, *_, **__) -> Tuple[Any]: + sim_context_clones = [sim_context.clone(*_, **__) for sim_context in self.sim_contexts] + result: Tuple[Any, ...] = ( + sim_context_clones, + *super()._clone_args(*_, **__) + ) + return result + + def _serialize_data(self, data: Dict[str, Any]): + super()._serialize_data(data) + data['sim_contexts'] = [sim_context.serialize() for sim_context in self.sim_contexts] + + @classmethod + def _deserialize_args(cls, data: Union[str, Dict[str, Any]]) -> Union[Tuple[Any], None]: + sim_contexts_data = data.get('sim_contexts', None) + if sim_contexts_data is None: + return None + + sim_contexts: List[CommonRunnableSimContextType] = list() + for sim_context_data in sim_contexts_data: + sim_context = cls.sim_context_type().deserialize(sim_context_data) + if sim_context is None: + return None + sim_contexts.append(sim_context) + if not sim_contexts: + return None + + deserialized_args = super()._deserialize_args(data) + if deserialized_args is None: + return None + + result: Tuple[Any, ...] = ( + sim_contexts, + *deserialized_args + ) + return result + + def __eq__(self, other: 'CommonRunnableContextWithSims') -> bool: + if not isinstance(other, CommonRunnableContextWithSims): + return False + if len(self.sim_contexts) != len(other.sim_contexts): + return False + for (self_sim_context, other_sim_context) in zip(self.sim_contexts, other.sim_contexts): + if not self_sim_context.__eq__(other_sim_context): + return False + return True + + def __repr__(self) -> str: + return 'Runnable Context:\n'\ + 'Sims: [{}]\n'.format( + self.sim_contexts, + ) diff --git a/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_object_context.py b/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_object_context.py new file mode 100644 index 0000000..ef0dd90 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_object_context.py @@ -0,0 +1,133 @@ +""" +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 +""" + +from typing import Union, Tuple, Any, Dict + +from sims4communitylib.classes.runnables.contexts.common_runnable_context import CommonRunnableContext +from objects.game_object import GameObject +from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from sims4communitylib.enums.enumtypes.common_int import CommonInt +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.utils.common_type_utils import CommonTypeUtils +from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils + + +class CommonRunnableObjectContext(CommonRunnableContext): + """CommonRunnableObjectContext(game_object) + + A context used by a runnable that contains information about an Object. + + :param game_object: The game object the context is for. + :type game_object: Union[GameObject, None] + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + raise NotImplementedError() + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + raise NotImplementedError() + + def __init__( + self, + game_object: Union[GameObject, None] + ): + super().__init__() + + if game_object is not None and CommonTypeUtils.is_game_object(game_object): + self._game_object = game_object + else: + self._game_object = None + + self._game_object_id = -1 + if self._game_object is not None: + self._game_object_id = CommonObjectUtils.get_object_id(self._game_object) + + @property + def game_object(self) -> Union[GameObject, None]: + """The Game Object this context is for.""" + return self._game_object + + @property + def game_object_id(self) -> int: + """The decimal identifier of the Game Object this context is for.""" + return self._game_object_id + + def _initialize(self, *_, **__) -> CommonExecutionResult: + return CommonExecutionResult.TRUE + + def _setup(self, *_, **__) -> CommonExecutionResult: + raise NotImplementedError() + + def _update(self, milliseconds_since_last_update: int, *_, **__) -> CommonExecutionResult: + raise NotImplementedError() + + def _teardown(self, teardown_reason: Union[int, CommonInt], *_, **__) -> CommonExecutionResult: + raise NotImplementedError() + + def _clone_args(self, *_, **__) -> Tuple[Any]: + result: Tuple[Any, ...] = ( + self.game_object, + *super()._clone_args(*_, **__) + ) + return result + + def _serialize_data(self, data: Dict[str, Any]): + super()._serialize_data(data) + if self.game_object_id != -1: + data['object_id'] = self.game_object_id + + @classmethod + def _deserialize_args(cls, data: Union[str, Dict[str, Any]]) -> Union[Tuple[Any], None]: + object_id = data.get('object_id', None) + if object_id is None: + return None + + game_object = CommonObjectUtils.get_game_object(object_id) + if game_object is None: + return None + + deserialized_args = super()._deserialize_args(data) + if deserialized_args is None: + return None + + result: Tuple[Any, ...] = ( + game_object, + *deserialized_args + ) + return result + + def __gt__(self, other: 'CommonRunnableObjectContext') -> bool: + if self.game_object is None: + return False + return self.game_object_id > other.game_object_id + + def __lt__(self, other: 'CommonRunnableObjectContext') -> bool: + if self.game_object is None: + return False + return self.game_object_id < other.game_object_id + + def __eq__(self, other: 'CommonRunnableObjectContext') -> bool: + if self.game_object is None: + return False + return self.game_object is other.game_object + + def __hash__(self) -> int: + if self.game_object is None: + return 0 + return self.game_object_id + + def __repr__(self) -> str: + return self.__str__() + + def __str__(self) -> str: + extra_str = self._get_str() + return f'<[CROC] {self.game_object} ({self.game_object_id}) {extra_str}>' diff --git a/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_sim_context.py b/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_sim_context.py new file mode 100644 index 0000000..e076529 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_sim_context.py @@ -0,0 +1,140 @@ +""" +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 +""" + +from typing import Union, Dict, Any, Tuple + +from sims4communitylib.classes.runnables.contexts.common_runnable_context import CommonRunnableContext +from sims.sim import Sim +from sims.sim_info import SimInfo +from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from sims4communitylib.enums.enumtypes.common_int import CommonInt +from sims4communitylib.enums.sim_type import CommonSimType +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils +from sims4communitylib.utils.sims.common_sim_type_utils import CommonSimTypeUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + + +class CommonRunnableSimContext(CommonRunnableContext): + """CommonRunnableSimContext(sim_info) + + A context used by a runnable that contains information about a Sim. + + :param sim_info: The Sim the context is for. + :type sim_info: SimInfo + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + raise NotImplementedError() + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + raise NotImplementedError() + + def __init__(self, sim_info: SimInfo): + super().__init__() + self._sim_info = sim_info + self._sim_full_name = CommonSimNameUtils.get_full_name(self._sim_info) + self._sim_type = CommonSimTypeUtils.determine_sim_type(self._sim_info) + + @property + def sim_info(self) -> SimInfo: + """The Sim this context is for.""" + return self._sim_info + + @property + def sim_full_name(self) -> str: + """The full name of the Sim this context is for.""" + return self._sim_full_name + + @property + def sim_id(self) -> int: + """The decimal identifier of the Sim this context is for.""" + return CommonSimUtils.get_sim_id(self._sim_info) + + @property + def sim(self) -> Sim: + """The instance of the Sim this context is for.""" + return CommonSimUtils.get_sim_instance(self._sim_info) + + @property + def sim_type(self) -> CommonSimType: + """The type of Sim.""" + return self._sim_type + + def _initialize(self, *_, **__) -> CommonExecutionResult: + raise NotImplementedError() + + def _setup(self, *_, **__) -> CommonExecutionResult: + raise NotImplementedError() + + def _update(self, milliseconds_since_last_update: int, *_, **__) -> CommonExecutionResult: + raise NotImplementedError() + + def _teardown(self, teardown_reason: Union[int, CommonInt], *_, **__) -> CommonExecutionResult: + raise NotImplementedError() + + def _clone_args(self, *_, **__) -> Tuple[Any]: + result: Tuple[Any, ...] = ( + self.sim_info, + *super()._clone_args(*_, **__) + ) + return result + + def _serialize_data(self, data: Dict[str, Any]): + super()._serialize_data(data) + data['sim_id'] = self.sim_id + + @classmethod + def _deserialize_args(cls, data: Union[str, Dict[str, Any]]) -> Union[Tuple[Any], None]: + sim_id = data.get('sim_id', None) + if sim_id is None: + return None + + deserialized_args = super()._deserialize_args(data) + if deserialized_args is None: + return None + + sim_info = CommonSimUtils.get_sim_info(sim_id) + if sim_info is None: + return None + + result: Tuple[Any, ...] = ( + sim_info, + *deserialized_args, + ) + return result + + def __gt__(self, other: 'CommonRunnableSimContext') -> bool: + if not isinstance(other, self.__class__): + return False + return self.sim_id > other.sim_id + + def __lt__(self, other: 'CommonRunnableSimContext') -> bool: + if not isinstance(other, self.__class__): + return False + return self.sim_id < other.sim_id + + def __eq__(self, other: 'CommonRunnableSimContext') -> bool: + if not isinstance(other, self.__class__): + return False + return self.sim_info is other.sim_info + + def __hash__(self) -> int: + return self.sim_id + + def __repr__(self) -> str: + return self.__str__() + + def __str__(self) -> str: + sim_type_name = self.sim_type.name + str_extras = self._get_str() + return f'<[CRSC] {self.sim_info} ST: {sim_type_name} {str_extras}>' diff --git a/Scripts/s4ap/sims4communitylib/classes/serialization/__init__.py b/Scripts/s4ap/sims4communitylib/classes/serialization/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/serialization/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/classes/serialization/common_serializable.py b/Scripts/s4ap/sims4communitylib/classes/serialization/common_serializable.py new file mode 100644 index 0000000..c0e6db6 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/serialization/common_serializable.py @@ -0,0 +1,34 @@ +""" +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 +""" +from typing import Union, Any, Dict, TypeVar, Type + +CommonSerializableType = TypeVar('CommonSerializableType', bound="CommonSerializable") + + +class CommonSerializable: + """Indicates an object can be serialized and deserialized.""" + def serialize(self: CommonSerializableType) -> Union[str, Dict[str, Any]]: + """serialize() + + Serialize the object into a JSON Serializable form. + + :return: A serializable representation of the object. + :rtype: Union[str, Dict[str, Any]] + """ + raise NotImplementedError() + + @classmethod + def deserialize(cls: Type[CommonSerializableType], data: Union[str, Dict[str, Any]]) -> Union[CommonSerializableType, None]: + """deserialize(data) + + Deserialize the object from a JSON Serializable form. + + :return: The deserialized form of the object or None if it fails to deserialize. + :rtype: Union[CommonSerializableType, None] + """ + raise NotImplementedError() diff --git a/Scripts/s4ap/sims4communitylib/classes/serialization/common_serializable_location.py b/Scripts/s4ap/sims4communitylib/classes/serialization/common_serializable_location.py new file mode 100644 index 0000000..254b7f4 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/serialization/common_serializable_location.py @@ -0,0 +1,98 @@ +""" +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 +""" +from typing import Dict, Any, Union + +from sims4communitylib.classes.math.common_location import CommonLocation +from sims4communitylib.classes.math.common_quaternion import CommonQuaternion +from sims4communitylib.classes.math.common_surface_identifier import CommonSurfaceIdentifier +from sims4communitylib.classes.math.common_transform import CommonTransform +from sims4communitylib.classes.math.common_vector3 import CommonVector3 +from sims4communitylib.classes.serialization.common_serializable import CommonSerializable + + +class CommonSerializableLocation(CommonSerializable): + """A wrapper to serialize/deserialize a CommonLocation.""" + def __init__(self, location: CommonLocation): + self.location = location + if isinstance(location, CommonSerializableLocation): + self.location = location.location + + # noinspection PyMissingOrEmptyDocstring + def serialize(self) -> Union[str, Dict[str, Any]]: + if self.location is None: + return dict() + transform = self.location.transform + translation = transform.translation + x = translation.x + y = translation.y + z = translation.z + orientation = transform.orientation + or_x = orientation.x + or_y = orientation.y + or_z = orientation.z + or_w = orientation.w + routing_surface = self.location.routing_surface + primary_id = routing_surface.primary_id + secondary_id = routing_surface.secondary_id + joint_name_or_hash = self.location.joint_name_or_hash + slot_hash = self.location.slot_hash + parent_ref = self.location.parent_ref + + return { + 'transform': { + 'translation': { + 'x': x, + 'y': y, + 'z': z + }, + 'orientation': { + 'x': or_x, + 'y': or_y, + 'z': or_z, + 'w': or_w + } + }, + 'routing_surface': { + 'primary_id': primary_id, + 'secondary_id': secondary_id + }, + 'joint_name_or_hash': joint_name_or_hash, + 'slot_hash': slot_hash, + 'parent_ref': parent_ref + } + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def deserialize(cls, data: Union[str, Dict[str, Any]]) -> Union['CommonSerializableLocation', None]: + if not data: + return None + if isinstance(data, CommonSerializableLocation): + return data + data: Dict[str, Any] = data + transform_data = data['transform'] + translation_data = transform_data['translation'] + x = translation_data['x'] + y = translation_data['y'] + z = translation_data['z'] + orientation_data = transform_data['orientation'] + or_x = orientation_data['x'] + or_y = orientation_data['y'] + or_z = orientation_data['z'] + or_w = orientation_data['w'] + routing_surface = data['routing_surface'] + primary_id = routing_surface['primary_id'] + secondary_id = routing_surface['secondary_id'] + joint_name_or_hash = data['joint_name_or_hash'] + slot_hash = data['slot_hash'] + parent_ref = data['parent_ref'] + + translation = CommonVector3(x, y, z) + orientation = CommonQuaternion(or_x, or_y, or_z, or_w) + transform = CommonTransform(translation, orientation) + routing_surface = CommonSurfaceIdentifier(primary_id, secondary_id=secondary_id) + return cls(CommonLocation(transform, routing_surface, parent_ref=parent_ref, joint_name_or_hash=joint_name_or_hash, slot_hash=slot_hash)) diff --git a/Scripts/s4ap/sims4communitylib/classes/test_based_scores/__init__.py b/Scripts/s4ap/sims4communitylib/classes/test_based_scores/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/test_based_scores/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/classes/test_based_scores/common_sim_to_sim_test_based_score.py b/Scripts/s4ap/sims4communitylib/classes/test_based_scores/common_sim_to_sim_test_based_score.py new file mode 100644 index 0000000..01d4ccb --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/test_based_scores/common_sim_to_sim_test_based_score.py @@ -0,0 +1,73 @@ +""" +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 +""" +from event_testing.resolver import Resolver +from interactions import ParticipantType +from interactions.base.interaction import Interaction +from sims.sim_info import SimInfo +from sims4.sim_irq_service import yield_to_irq +from sims4communitylib.classes.test_based_scores.common_test_based_score import CommonTestBasedScore +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.utils.common_type_utils import CommonTypeUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + + +class CommonSimToSimTestBasedScore(CommonTestBasedScore): + """ A test based score used when testing a resolver involving two Sims. """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + raise NotImplementedError() + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + raise NotImplementedError() + + @classmethod + def get_score(cls, resolver: Resolver) -> int: + """get_score(resolver) + + Calculate the score. + """ + try: + yield_to_irq() + cls.get_verbose_log().format_with_message('Retrieving score.', class_name=cls.__name__) + source_sim = resolver.get_participant(ParticipantType.Actor) + target_sim = resolver.get_participant(ParticipantType.TargetSim) or resolver.get_participant(ParticipantType.Listeners) + if source_sim is None or target_sim is None or not CommonTypeUtils.is_sim_or_sim_info(source_sim) or not CommonTypeUtils.is_sim_or_sim_info(target_sim): + cls.get_verbose_log().format_with_message('Failed, the Source or the Target were not Sims.', source=source_sim, target=target_sim) + return cls.get_default_score() + source_sim_info = CommonSimUtils.get_sim_info(source_sim) + target_sim_info = CommonSimUtils.get_sim_info(target_sim) + interaction_instance = resolver.interaction or getattr(resolver, 'affordance', None) + score = cls.calculate_score(resolver, source_sim_info, target_sim_info, interaction_instance) + cls.get_verbose_log().format_with_message('Retrieved score for Sims.', source_sim=source_sim_info, target_sim=target_sim_info, score=score) + return score + except Exception as ex: + cls.get_verbose_log().error('Error occurred while retrieving score.', exception=ex) + return cls.get_default_score() + + @classmethod + def calculate_score(cls, resolver: Resolver, source_sim_info: SimInfo, target_sim_info: SimInfo, interaction: Interaction) -> int: + """calculate_score(resolver, source_sim_info, target_sim_info, interaction) + + Calculate a score involving two Sims. + + :param resolver: A resolver containing information about what is being tested. + :type resolver: Resolver + :param source_sim_info: The Source or Actor Sim of the test, also known as Sim A. + :type source_sim_info: SimInfo + :param target_sim_info: The Target or Listener Sim of the test, also known as Sim B. + :type target_sim_info: SimInfo + :param interaction: The interaction or affordance, if available, that Sim A is attempting to perform with the Sim B. If no interaction or affordance is present, this value will be None. + :type interaction: Interaction + :return: The calculated Score. + :rtype: int + """ + raise NotImplementedError() diff --git a/Scripts/s4ap/sims4communitylib/classes/test_based_scores/common_single_sim_test_based_score.py b/Scripts/s4ap/sims4communitylib/classes/test_based_scores/common_single_sim_test_based_score.py new file mode 100644 index 0000000..cf32680 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/test_based_scores/common_single_sim_test_based_score.py @@ -0,0 +1,69 @@ +""" +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 +""" +from event_testing.resolver import Resolver +from interactions import ParticipantType +from interactions.base.interaction import Interaction +from sims.sim_info import SimInfo +from sims4.sim_irq_service import yield_to_irq +from sims4communitylib.classes.test_based_scores.common_test_based_score import CommonTestBasedScore +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.utils.common_type_utils import CommonTypeUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + + +class CommonSingleSimTestBasedScore(CommonTestBasedScore): + """ A test based score used when testing a resolver involving one Sim. """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + raise NotImplementedError() + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + raise NotImplementedError() + + @classmethod + def get_score(cls, resolver: Resolver) -> int: + """get_score(resolver) + + Calculate the score. + """ + try: + yield_to_irq() + cls.get_verbose_log().format_with_message('Retrieving score.', class_name=cls.__name__) + source_sim = resolver.get_participant(ParticipantType.Actor) + if source_sim is None or not CommonTypeUtils.is_sim_or_sim_info(source_sim): + cls.get_verbose_log().format_with_message('Failed, the Source was not a Sim.', source=source_sim) + return cls.get_default_score() + source_sim_info = CommonSimUtils.get_sim_info(source_sim) + interaction_instance = resolver.interaction or getattr(resolver, 'affordance', None) + score = cls.calculate_score(resolver, source_sim_info, interaction_instance) + cls.get_verbose_log().format_with_message('Retrieved score for Sim.', source_sim=source_sim_info, score=score) + return score + except Exception as ex: + cls.get_verbose_log().error('Error occurred while retrieving score.', exception=ex) + return cls.get_default_score() + + @classmethod + def calculate_score(cls, resolver: Resolver, source_sim_info: SimInfo, interaction: Interaction) -> int: + """calculate_score(resolver, source_sim_info, interaction) + + Calculate a score involving one Sim. + + :param resolver: A resolver containing information about what is being tested. + :type resolver: Resolver + :param source_sim_info: The Source or Actor Sim of the test. + :type source_sim_info: SimInfo + :param interaction: The interaction or affordance, if available, that the Source Sim is attempting to perform. If no interaction or affordance is present, this value will be None. + :type interaction: Interaction + :return: The calculated Score. + :rtype: int + """ + raise NotImplementedError() diff --git a/Scripts/s4ap/sims4communitylib/classes/test_based_scores/common_test_based_score.py b/Scripts/s4ap/sims4communitylib/classes/test_based_scores/common_test_based_score.py new file mode 100644 index 0000000..ca3a98a --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/test_based_scores/common_test_based_score.py @@ -0,0 +1,60 @@ +""" +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 +""" +from event_testing.resolver import Resolver +from event_testing.test_based_score import TestBasedScore +from sims4.math import Threshold +from sims4communitylib.logging.has_class_log import HasClassLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity + + +class CommonTestBasedScore(TestBasedScore, HasClassLog): + """ A test based score used when testing a resolver. """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + raise NotImplementedError() + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + raise NotImplementedError() + + def __init__(self, *_, **__) -> None: + super().__init__(*_, **__) + HasClassLog.__init__(self) + + @classmethod + def get_default_score(cls) -> int: + """The default score used when no other score is found or when an error occurs.""" + return 0 + + @classmethod + def passes_threshold(cls, resolver: Resolver, threshold: Threshold) -> bool: + """ True if the threshold is passed. """ + if resolver is not None: + cls.get_verbose_log().format( + resolver_type=type(resolver), + resolver_class=resolver.__class__, + resolver_class_name=resolver.__class__.__name__ + ) + if threshold is not None: + cls.get_verbose_log().format( + threshold_type=type(threshold), + threshold_class=threshold.__class__ + ) + return threshold.compare(cls.get_score(resolver)) + + @classmethod + def _verify_tuning_callback(cls) -> None: + pass + + @classmethod + def _tuning_loaded_callback(cls) -> None: + pass + diff --git a/Scripts/s4ap/sims4communitylib/classes/testing/__init__.py b/Scripts/s4ap/sims4communitylib/classes/testing/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/testing/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/classes/testing/common_enqueue_result.py b/Scripts/s4ap/sims4communitylib/classes/testing/common_enqueue_result.py new file mode 100644 index 0000000..7797c51 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/testing/common_enqueue_result.py @@ -0,0 +1,201 @@ +""" +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 +""" +from event_testing.results import TestResult, EnqueueResult +from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from sims4communitylib.classes.testing.common_test_result import CommonTestResult + + +class CommonEnqueueResult(EnqueueResult): + """CommonEnqueueResult(\ + test_result,\ + execute_result,\ + ) + + The result of enqueuing an interaction. + """ + TRUE = None + FALSE = None + NONE = None + test_result: CommonTestResult + execute_result: CommonExecutionResult + + def __new__(cls, test_result: CommonTestResult, execute_result: CommonExecutionResult): + return super(CommonEnqueueResult, cls).__new__(cls, test_result, execute_result) + + def reverse_result(self) -> 'CommonExecutionResult': + """reverse_result() + + Create a CommonExecutionResult that has a reversed result of this one, but with the same reason and tooltip information. + + .. note:: This function works best when the result value has an opposite, such as a boolean. + + :return: This CommonExecutionResult, but with a reversed result value. + :rtype: CommonExecutionResult + """ + return CommonEnqueueResult( + self.test_result.reverse_result(), + self.execute_result.reverse_result() + ) + + @property + def is_success(self) -> bool: + """True, if the result of enqueue is successful. False, if not.""" + return bool(self) + + @property + def is_failure(self) -> bool: + """False, if the result of enqueue is a failure. False, if not.""" + return not self.is_success + + def __repr__(self) -> str: + return f'<{self.__class__.__name__}: {repr(self.test_result)} {repr(self.execute_result)}>' + + def __str__(self) -> str: + return f'<{self.__class__.__name__}: {str(self.test_result)} {str(self.execute_result)}>' + + def __eq__(self, other) -> bool: + if isinstance(other, bool): + return self.is_success is other + if isinstance(other, CommonEnqueueResult): + return self.test_result == other.test_result and self.execute_result == other.execute_result + if isinstance(other, CommonExecutionResult): + return self.execute_result == other + if isinstance(other, CommonTestResult): + return self.test_result == other + if isinstance(other, TestResult): + return self.is_success == other.result + if isinstance(other, EnqueueResult): + return self.test_result == other.test_result and self.execute_result == other.execute_result + return self.test_result == other and self.execute_result == other + + def __ne__(self, other) -> bool: + return not self == other + + def __bool__(self) -> bool: + return bool(self.test_result) and bool(self.execute_result) + + def __or__(self, other) -> 'CommonExecutionResult': + if isinstance(other, CommonEnqueueResult): + test_result = self.test_result or other.test_result + execute_result = self.execute_result or other.execute_result + elif isinstance(other, EnqueueResult): + test_result = self.test_result or other.test_result + execute_result = self.execute_result or other.execute_result + elif isinstance(other, CommonExecutionResult): + test_result = self.test_result or CommonTestResult( + other.result, + reason=other.reason, + tooltip_text=other._tooltip_text, + tooltip_tokens=other._tooltip_tokens, + icon=other.icon, + influenced_by_active_mood=other.influence_by_active_mood, + hide_tooltip=other._hide_tooltip + ) + execute_result = self.execute_result or other + elif isinstance(other, CommonTestResult): + test_result = self.test_result or other + execute_result = self.execute_result or CommonExecutionResult( + other.result, + success_override=other._success_override, + reason=other.reason, + tooltip_text=other._tooltip_text, + tooltip_tokens=other._tooltip_tokens, + icon=other.icon, + influenced_by_active_mood=other.influence_by_active_mood, + hide_tooltip=other._hide_tooltip + ) + elif isinstance(other, bool): + test_result = self.test_result or CommonTestResult( + other, + reason=self.test_result.reason, + tooltip_text=self.test_result._tooltip_text, + tooltip_tokens=self.test_result._tooltip_tokens, + icon=self.test_result.icon, + influenced_by_active_mood=self.test_result.influence_by_active_mood, + hide_tooltip=self.test_result._hide_tooltip + ) + execute_result = self.execute_result or CommonExecutionResult( + other, + success_override=other, + reason=self.execute_result.reason, + tooltip_text=self.execute_result._tooltip_text, + tooltip_tokens=self.execute_result._tooltip_tokens, + icon=self.execute_result.icon, + influenced_by_active_mood=self.execute_result.influence_by_active_mood, + hide_tooltip=self.execute_result._hide_tooltip + ) + else: + return self + + return CommonEnqueueResult( + test_result, + execute_result + ) + + def __and__(self, other: 'CommonExecutionResult') -> 'CommonExecutionResult': + if isinstance(other, CommonEnqueueResult): + test_result = self.test_result and other.test_result + execute_result = self.execute_result and other.execute_result + elif isinstance(other, EnqueueResult): + test_result = self.test_result and other.test_result + execute_result = self.execute_result and other.execute_result + elif isinstance(other, CommonExecutionResult): + test_result = self.test_result and CommonTestResult( + other.result, + reason=other.reason, + tooltip_text=other._tooltip_text, + tooltip_tokens=other._tooltip_tokens, + icon=other.icon, + influenced_by_active_mood=other.influence_by_active_mood, + hide_tooltip=other._hide_tooltip + ) + execute_result = self.execute_result and other + elif isinstance(other, CommonTestResult): + test_result = self.test_result and other + execute_result = self.execute_result and CommonExecutionResult( + other.result, + success_override=other._success_override, + reason=other.reason, + tooltip_text=other._tooltip_text, + tooltip_tokens=other._tooltip_tokens, + icon=other.icon, + influenced_by_active_mood=other.influence_by_active_mood, + hide_tooltip=other._hide_tooltip + ) + elif isinstance(other, bool): + test_result = self.test_result and CommonTestResult( + other, + reason=self.test_result.reason, + tooltip_text=self.test_result._tooltip_text, + tooltip_tokens=self.test_result._tooltip_tokens, + icon=self.test_result.icon, + influenced_by_active_mood=self.test_result.influence_by_active_mood, + hide_tooltip=self.test_result._hide_tooltip + ) + execute_result = self.execute_result and CommonExecutionResult( + other, + success_override=other, + reason=self.execute_result.reason, + tooltip_text=self.execute_result._tooltip_text, + tooltip_tokens=self.execute_result._tooltip_tokens, + icon=self.execute_result.icon, + influenced_by_active_mood=self.execute_result.influence_by_active_mood, + hide_tooltip=self.execute_result._hide_tooltip + ) + else: + return self + + return CommonEnqueueResult( + test_result, + execute_result + ) + + +CommonEnqueueResult.TRUE = CommonEnqueueResult(CommonTestResult.TRUE, CommonExecutionResult.TRUE) +CommonEnqueueResult.FALSE = CommonEnqueueResult(CommonTestResult.FALSE, CommonExecutionResult.FALSE) +CommonEnqueueResult.NONE = CommonEnqueueResult(CommonTestResult.NONE, CommonExecutionResult.NONE) diff --git a/Scripts/s4ap/sims4communitylib/classes/testing/common_execution_result.py b/Scripts/s4ap/sims4communitylib/classes/testing/common_execution_result.py new file mode 100644 index 0000000..1c24919 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/testing/common_execution_result.py @@ -0,0 +1,197 @@ +""" +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 +""" +from typing import Any, Union, Iterator + +from event_testing.results import TestResult +from protocolbuffers.Localization_pb2 import LocalizedString +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from sims4communitylib.utils.localization.common_localized_string_separators import CommonLocalizedStringSeparator + + +class CommonExecutionResult(TestResult): + """CommonExecutionResult(\ + result,\ + reason=None,\ + success_override=None,\ + tooltip_text=None,\ + tooltip_tokens=(),\ + icon=None,\ + influenced_by_active_mood=False,\ + hide_tooltip=False,\ + ) + + The result of executing something. + + .. note:: This class can be used in place of TestResult + + :param result: The result of execution. This value can be any type. + :type result: Any + :param reason: The reason for the success or failure of the execution result. Default is None. + :type reason: Union[str, None], optional + :param success_override: If True, the execution will be indicated as being a success. If False, the execution will be indicated as being a failure. If None, the execution success will be indicated by whether result is set or not, if result is a bool, success is True and failure is False. Default is None. + :type success_override: bool + :param tooltip_text: The text that will be displayed. If not specified, then no tooltip will be displayed. Default is None. + :type tooltip_text: Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator], optional + :param tooltip_tokens: A collection of objects to format into the localized tooltip. (They can be anything. LocalizedString, str, int, SimInfo, just to name a few). Default is an empty collection. + :type tooltip_tokens: Iterator[Any], optional + :param icon: The icon to display. Default is None. + :type icon: Any, optional + :param influenced_by_active_mood: Indicate whether or not the result was influenced by a Sims active mood. Default is False. + :type influenced_by_active_mood: bool, optional + :param hide_tooltip: If True, no tooltip will be shown to the Player, even if a tooltip is specified. If False, a tooltip will be shown to the Player and if not specified, will be created from the reason (Assuming a reason is specified). Default is False. + :type hide_tooltip: bool, optional + """ + TRUE = None + FALSE = None + NONE = None + + def __init__( + self, + result: Any, + reason: Union[str, None] = None, + success_override: bool = None, + tooltip_text: Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator, CommonLocalizationUtils.LocalizedTooltip] = None, + tooltip_tokens: Iterator[Any] = (), + icon: Any = None, + influenced_by_active_mood: bool = False, + hide_tooltip: bool = False + ) -> None: + self._tooltip_text = None + self._tooltip_tokens = None + self._hide_tooltip = hide_tooltip + tooltip = None + if not hide_tooltip: + self._tooltip_text = tooltip_text + self._tooltip_tokens = tooltip_tokens + if tooltip_text is not None: + tooltip = CommonLocalizationUtils.create_localized_tooltip(tooltip_text, tooltip_tokens=tooltip_tokens) + elif reason is not None: + tooltip = CommonLocalizationUtils.create_localized_tooltip(reason, tooltip_tokens=tooltip_tokens) + super().__init__(result, reason, tooltip=tooltip, icon=icon, influence_by_active_mood=influenced_by_active_mood) + self._success_override = success_override + if success_override is None: + if result: + success_override = True + else: + success_override = False + self._success = success_override + + @property + def tooltip_text(self) -> Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator, CommonLocalizationUtils.LocalizedTooltip]: + """The text of the tooltip.""" + return self._tooltip_text + + @property + def tooltip_tokens(self) -> Iterator[Any]: + """The tokens of the tooltip.""" + return self._tooltip_tokens + + def reverse_result(self) -> 'CommonExecutionResult': + """reverse_result() + + Create a CommonExecutionResult that has a reversed result of this one, but with the same reason and tooltip information. + + .. note:: This function works best when the result value has an opposite, such as a boolean. + + :return: This CommonExecutionResult, but with a reversed result value. + :rtype: CommonExecutionResult + """ + return CommonExecutionResult(not self.result, reason=self.reason, success_override=self._success, tooltip_text=self._tooltip_text, tooltip_tokens=self._tooltip_tokens, icon=self.icon, influenced_by_active_mood=self.influence_by_active_mood, hide_tooltip=self._hide_tooltip) + + @property + def is_success(self) -> bool: + """True, if the result of execution is successful. False, if not.""" + return self._success + + @property + def is_failure(self) -> bool: + """False, if the result of execution is a failure. False, if not.""" + return not self.is_success + + def __repr__(self) -> str: + if self.reason: + return f'<{self.__class__.__name__}: {bool(self.result)} ({self.reason})>' + return f'<{self.__class__.__name__}: {bool(self.result)}>' + + def __str__(self) -> str: + if self.reason: + return self.reason + return str(self.result) + + def __eq__(self, other) -> bool: + if isinstance(other, bool): + return self.is_success is other + if isinstance(other, CommonExecutionResult): + return self.result == other.result and self.is_success == other.is_success + if isinstance(other, TestResult): + return self.is_success == other.result + return self.result == other + + def __ne__(self, other) -> bool: + return not self == other + + def __bool__(self) -> bool: + return self._success + + def __or__(self, other) -> 'CommonExecutionResult': + if isinstance(other, CommonExecutionResult): + is_success = self.is_success or other.is_success + result = self.result or other.result + tooltip_text = self._tooltip_text or other._tooltip_text + tooltip_tokens = self._tooltip_tokens or other._tooltip_tokens + elif isinstance(other, TestResult): + is_success = self.is_success or other.result + result = self.result or other.result + if self._tooltip_text: + tooltip_text = self._tooltip_text + tooltip_tokens = self._tooltip_tokens + else: + tooltip_text = other.tooltip + tooltip_tokens = tuple() + else: + return self + + if self._reason: + reason = self._reason + else: + reason = other._reason + icon = self.icon or other.icon + influence_by_active_mood = self.influence_by_active_mood or other.influence_by_active_mood + return CommonExecutionResult(result, reason=reason, success_override=is_success, tooltip_text=tooltip_text, tooltip_tokens=tooltip_tokens, icon=icon, influenced_by_active_mood=influence_by_active_mood) + + def __and__(self, other: 'CommonExecutionResult') -> 'CommonExecutionResult': + if isinstance(other, CommonExecutionResult): + is_success = self.is_success and other.is_success + result = self.result or other.result + tooltip_text = self._tooltip_text or other._tooltip_text + tooltip_tokens = self._tooltip_tokens or other._tooltip_tokens + elif isinstance(other, TestResult): + is_success = self.is_success and other.result + result = self.result or other.result + if self._tooltip_text: + tooltip_text = self._tooltip_text + tooltip_tokens = self._tooltip_tokens + else: + tooltip_text = other.tooltip + tooltip_tokens = tuple() + else: + return self + + if self._reason: + reason = self._reason + else: + reason = other._reason + icon = self.icon or other.icon + influence_by_active_mood = self.influence_by_active_mood or other.influence_by_active_mood + return CommonExecutionResult(result, reason=reason, success_override=is_success, tooltip_text=tooltip_text, tooltip_tokens=tooltip_tokens, icon=icon, influenced_by_active_mood=influence_by_active_mood) + + +CommonExecutionResult.TRUE = CommonExecutionResult(True, hide_tooltip=True) +CommonExecutionResult.FALSE = CommonExecutionResult(False, reason='Failure Unknown', hide_tooltip=True) +CommonExecutionResult.NONE = CommonExecutionResult(False, hide_tooltip=True) diff --git a/Scripts/s4ap/sims4communitylib/classes/testing/common_test_result.py b/Scripts/s4ap/sims4communitylib/classes/testing/common_test_result.py new file mode 100644 index 0000000..f5bc333 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/testing/common_test_result.py @@ -0,0 +1,149 @@ +""" +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 +""" +from typing import Any, Union, Iterator + +from event_testing.results import TestResult +from protocolbuffers.Localization_pb2 import LocalizedString +from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from sims4communitylib.utils.localization.common_localized_string_separators import CommonLocalizedStringSeparator + + +class CommonTestResult(CommonExecutionResult): + """CommonTestResult(\ + result,\ + reason=None,\ + tooltip_text=None,\ + tooltip_tokens=(),\ + icon=None,\ + influenced_by_active_mood=False,\ + hide_tooltip=False,\ + ) + + The result of testing something. + + .. note:: This class can be used in place of TestResult and CommonExecutionResult + + :param result: A value that indicates whether the test was successful or not. If True, the test was successful. If False, the test was not successful. + :type result: bool + :param reason: The reason for the success or failure of the test result. Default is None. + :type reason: Union[str, None], optional + :param tooltip_text: The text that will be displayed. If not specified, then no tooltip will be displayed. Default is None. + :type tooltip_text: Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator], optional + :param tooltip_tokens: A collection of objects to format into the localized tooltip. (They can be anything. LocalizedString, str, int, SimInfo, just to name a few). Default is an empty collection. + :type tooltip_tokens: Iterator[Any], optional + :param icon: The icon to display. Default is None. + :type icon: Any, optional + :param influenced_by_active_mood: Indicate whether or not the result was influenced by a Sims active mood. Default is False. + :type influenced_by_active_mood: bool, optional + :param hide_tooltip: If True, no tooltip will be shown to the Player, even if a tooltip is specified. If False, a tooltip will be shown to the Player and if not specified, will be created from the reason (Assuming a reason is specified). Default is False. + :type hide_tooltip: bool, optional + """ + TRUE = None + FALSE = None + NONE = None + + def __init__( + self, + result: bool, + reason: Union[str, None] = None, + tooltip_text: Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator, CommonLocalizationUtils.LocalizedTooltip] = None, + tooltip_tokens: Iterator[Any] = (), + icon: Any = None, + influenced_by_active_mood: bool = False, + hide_tooltip: bool = False + ) -> None: + super().__init__(result, reason=reason, success_override=result, tooltip_text=tooltip_text, tooltip_tokens=tooltip_tokens, icon=icon, influenced_by_active_mood=influenced_by_active_mood, hide_tooltip=hide_tooltip) + + @classmethod + def convert_from_vanilla(cls, test_result: TestResult) -> 'CommonTestResult': + """convert_from_vanilla(test_result) + + Convert a vanilla TestResult into a CommonTestResult. + + :param test_result: An instance of TestResult + :type test_result: TestResult + :return: The specified TestResult translated to CommonTestResult. + :rtype: CommonTestResult + """ + return CommonTestResult(test_result.result, reason=test_result.reason, tooltip_text=test_result.tooltip, icon=test_result.icon, influenced_by_active_mood=test_result.influence_by_active_mood) + + def reverse_result(self) -> 'CommonTestResult': + """reverse_result() + + Create a CommonTestResult that has a reversed result of this one, but with the same reason and tooltip information. + + .. note:: This function works best when the result value has an opposite, such as a boolean. + + :return: This CommonTestResult, but with a reversed result value. + :rtype: CommonTestResult + """ + return self.__class__(not self.result, self.reason, tooltip_text=self._tooltip_text, tooltip_tokens=self._tooltip_tokens) + + def __eq__(self, other) -> bool: + if isinstance(other, bool): + return self.is_success is other + if isinstance(other, CommonTestResult): + return self.result == other.result and self.is_success == other.is_success + if isinstance(other, TestResult): + return self.is_success == other.result + return self.result == other + + def __or__(self, other) -> 'CommonTestResult': + if isinstance(other, CommonTestResult): + result = self.result or other.result + tooltip_text = self._tooltip_text or other._tooltip_text + tooltip_tokens = self._tooltip_tokens or other._tooltip_tokens + elif isinstance(other, TestResult): + result = self.result or other.result + if self._tooltip_text: + tooltip_text = self._tooltip_text + tooltip_tokens = self._tooltip_tokens + else: + tooltip_text = other.tooltip + tooltip_tokens = tuple() + else: + return self + + if self._reason: + reason = self._reason + else: + reason = other._reason + icon = self.icon or other.icon + influence_by_active_mood = self.influence_by_active_mood or other.influence_by_active_mood + return self.__class__(result, reason, tooltip_text=tooltip_text, tooltip_tokens=tooltip_tokens, icon=icon, influenced_by_active_mood=influence_by_active_mood) + + def __and__(self, other: 'CommonTestResult') -> 'CommonTestResult': + if isinstance(other, CommonTestResult): + result = self.result and other.result + tooltip_text = self._tooltip_text or other._tooltip_text + tooltip_tokens = self._tooltip_tokens or other._tooltip_tokens + elif isinstance(other, TestResult): + result = self.result and other.result + if self._tooltip_text: + tooltip_text = self._tooltip_text + tooltip_tokens = self._tooltip_tokens + else: + tooltip_text = other.tooltip + tooltip_tokens = tuple() + else: + return self + + if self._reason: + reason = self._reason + else: + reason = other._reason + icon = self.icon or other.icon + influence_by_active_mood = self.influence_by_active_mood or other.influence_by_active_mood + return self.__class__(result, reason, tooltip_text=tooltip_text, tooltip_tokens=tooltip_tokens, icon=icon, influenced_by_active_mood=influence_by_active_mood) + + +CommonTestResult.TRUE = CommonTestResult(True, hide_tooltip=True) +CommonTestResult.FALSE = CommonTestResult(False, reason='Failure Unknown', hide_tooltip=True) +CommonTestResult.NONE = CommonTestResult(False, hide_tooltip=True) diff --git a/Scripts/s4ap/sims4communitylib/classes/time/__init__.py b/Scripts/s4ap/sims4communitylib/classes/time/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/time/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/classes/time/common_alarm_handle.py b/Scripts/s4ap/sims4communitylib/classes/time/common_alarm_handle.py new file mode 100644 index 0000000..eb94c21 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/time/common_alarm_handle.py @@ -0,0 +1,81 @@ +""" +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 +""" +import os +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.common_time_utils import CommonTimeUtils +from typing import Any, Callable + + +ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' + +if ON_RTD: + # noinspection PyMissingOrEmptyDocstring + class AlarmHandle: + def cancel(self) -> Any: + pass + + # noinspection PyMissingOrEmptyDocstring + class DateAndTime: + pass + + # noinspection PyMissingOrEmptyDocstring + class TimeSpan: + pass + + # noinspection PyMissingOrEmptyDocstring + class Timeline: + pass + +if not ON_RTD: + from scheduling import Timeline, ElementHandle + from alarms import AlarmHandle + from date_and_time import DateAndTime, TimeSpan + + +class CommonAlarmHandle(AlarmHandle): + """A custom alarm handle that keeps track of when it is slated to trigger for the first time.""" + def __init__( + self, + owner: Any, + on_alarm_triggered_callback: Callable[['CommonAlarmHandle'], None], + timeline: Timeline, + when: DateAndTime, + should_repeat: bool=False, + time_until_repeat: TimeSpan=None, + accurate_repeat: bool=True, + persist_across_zone_loads: bool=False + ): + self.started_at_date_and_time = when + super().__init__( + owner, + on_alarm_triggered_callback, + timeline, + when, + repeating=should_repeat, + repeat_interval=time_until_repeat, + accurate_repeat=accurate_repeat, + cross_zone=persist_across_zone_loads + ) + + @property + def is_active(self) -> bool: + """True, if the Alarm Handle is currently active and scheduled. False, if not.""" + if self._element_handle is None: + return False + element_handle: ElementHandle = self._element_handle + # noinspection PyPropertyAccess + return element_handle.is_active and element_handle.is_scheduled + + +@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.print_current_time', 'Prints the current time.') +def _s4clib_print_current_time(output: CommonConsoleCommandOutput): + output('Current time') + output('Hour {} Minute {}'.format(CommonTimeUtils.get_current_date_and_time().hour(), CommonTimeUtils.get_current_date_and_time().minute())) + output('Abs Hour {} Abs Minute {}'.format(CommonTimeUtils.get_current_date_and_time().absolute_hours(), CommonTimeUtils.get_current_date_and_time().absolute_minutes())) diff --git a/Scripts/s4ap/sims4communitylib/classes/time/common_stop_watch.py b/Scripts/s4ap/sims4communitylib/classes/time/common_stop_watch.py new file mode 100644 index 0000000..1c1201b --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/classes/time/common_stop_watch.py @@ -0,0 +1,82 @@ +""" +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 +""" +from time import perf_counter + + +class CommonStopWatch: + """CommonStopWatch() + + A class used to see how long things take. + + """ + def __init__(self) -> None: + self._start_time = None + self._started: bool = False + + def start(self) -> None: + """start() + + Start the stop watch. + """ + if self._started: + return + self._start_time = perf_counter() + self._started = True + + def interval(self) -> float: + """interval() + + Retrieve a time stamp for how long the watch has been running for without ending it. + + :return: The number of seconds that occurred since the stop watch was started. + :rtype: float + """ + if not self._started or self._start_time is None: + return -1.0 + interval_time = perf_counter() + fractional_seconds = (interval_time - self._start_time) + return fractional_seconds + + def interval_milliseconds(self) -> float: + """interval_milliseconds() + + Retrieve a time stamp for how long the watch has been running for without ending it, but in milliseconds. + + :return: The number of milliseconds that occurred since the stop watch was started. + :rtype: float + """ + from sims4communitylib.utils.common_time_utils import CommonTimeUtils + return CommonTimeUtils.convert_seconds_to_milliseconds(self.interval()) + + def stop(self) -> float: + """stop() + + Stop the stop watch. + + .. warning:: This will also reset the start time of the stop watch. It will also stop the stop watch. + + :return: The number of seconds that occurred since starting the stop watch. + :rtype: float + """ + stopped_time = self.interval() + self._start_time = None + self._started = False + return stopped_time + + def stop_milliseconds(self) -> float: + """stop_milliseconds() + + Stop the stop watch, but return milliseconds rather than seconds. + + .. warning:: This will also reset the start time of the stop watch. It will also stop the stop watch. + + :return: The number of milliseconds that occurred since starting the stop watch. + :rtype: float + """ + from sims4communitylib.utils.common_time_utils import CommonTimeUtils + return CommonTimeUtils.convert_seconds_to_milliseconds(self.stop()) diff --git a/Scripts/s4ap/sims4communitylib/conditionals/__init__.py b/Scripts/s4ap/sims4communitylib/conditionals/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/conditionals/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/conditionals/common_conditional_action.py b/Scripts/s4ap/sims4communitylib/conditionals/common_conditional_action.py new file mode 100644 index 0000000..e902348 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/conditionals/common_conditional_action.py @@ -0,0 +1,66 @@ +""" +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 +""" +from typing import Union + +from sims4communitylib.logging.has_log import HasLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity + + +class CommonConditionalAction(HasLog): + """CommonConditionalAction() + + An inheritable class that Performs an action when a condition is met. + + .. note:: A common usage would be in a factory pattern with a collection of :class:`CommonConditionalAction` objects. + + """ + # noinspection PyMissingOrEmptyDocstring + @property + def mod_identity(self) -> Union[CommonModIdentity, None]: + return None + + def _should_apply(self, *_, **__) -> bool: + """_should_apply(*_, **__) + + Determine if the action should apply based on the given arguments. + + .. warning:: The arguments must match the :func:`~try_apply` method. + + :return: True, if the action should be applied. False, if not. + :rtype: bool + """ + return True + + def try_apply(self, *_, **__) -> bool: + """try_apply(*_, **__) + + Attempt to apply the action. + + .. note:: Override this method with any arguments you want to. + + :return: True, if the action was applied. False, if not. + :rtype: bool + """ + if self._should_apply(*_, **__): + self.log.debug('Applying action \'{}\'.'.format(self.__class__.__name__)) + return self._apply(*_, **__) + else: + self.log.debug('Skipping action \'{}\'.'.format(self.__class__.__name__)) + return False + + def _apply(self, *_, **__) -> bool: + """_apply(*_, **__) + + Apply the action. + + .. warning:: The arguments must match the :func:`~try_apply` arguments. + + :return: True, if the action was applied. False, if not. + :rtype: bool + """ + raise NotImplementedError('\'{}\' not implemented'.format(self.__class__._apply.__name__)) diff --git a/Scripts/s4ap/sims4communitylib/debug/__init__.py b/Scripts/s4ap/sims4communitylib/debug/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/debug/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/debug/dialogs/__init__.py b/Scripts/s4ap/sims4communitylib/debug/dialogs/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/debug/dialogs/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/debug/dialogs/common_change_object_state_dialog.py b/Scripts/s4ap/sims4communitylib/debug/dialogs/common_change_object_state_dialog.py new file mode 100644 index 0000000..e42607b --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/debug/dialogs/common_change_object_state_dialog.py @@ -0,0 +1,114 @@ +""" +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 +""" +from typing import Callable + +from objects.components.state import ObjectState +from objects.game_object import GameObject +from sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext +from sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_select_option import \ + CommonDialogSelectOption +from sims4communitylib.dialogs.option_dialogs.common_choose_object_option_dialog import CommonChooseObjectOptionDialog +from sims4communitylib.logging._has_s4cl_log import _HasS4CLLog +from sims4communitylib.utils.common_icon_utils import CommonIconUtils +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from sims4communitylib.utils.objects.common_object_state_utils import CommonObjectStateUtils +from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils + + +class CommonChangeObjectStateDialog(_HasS4CLLog): + """ Open a dialog that allows changing the states of objects. """ + + def __init__(self, game_object: GameObject, on_close: Callable[[], None] = None): + super().__init__() + self._game_object = game_object + self._on_close = on_close + + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + return 'common_change_object_state_dialog' + + def open(self) -> None: + """ Open Dialog. """ + def _reopen() -> None: + self.open() + + def _on_close() -> None: + if self._on_close is not None: + self._on_close() + + option_dialog = CommonChooseObjectOptionDialog( + CommonObjectUtils.get_catalog_name(self._game_object), + 0, + on_close=_on_close, + mod_identity=self.mod_identity, + per_page=500 + ) + + def _on_state_chosen(_: str, _chosen_state: ObjectState): + if _chosen_state is None: + _on_close() + return + self._modify_object_state_dialog(_chosen_state, on_close=_reopen) + + for (object_state, object_state_value) in CommonObjectStateUtils.get_object_state_items(self._game_object).items(): + display_name = CommonLocalizationUtils.create_localized_string(f'{object_state}: {object_state_value}') + option_dialog.add_option( + CommonDialogSelectOption( + str(object_state), + object_state, + CommonDialogOptionContext( + display_name, + 0, + icon=CommonIconUtils.load_arrow_right_icon() + ), + on_chosen=_on_state_chosen + ) + ) + + option_dialog.show(sort_options=True) + + def _modify_object_state_dialog(self, object_state: ObjectState, on_close: Callable[[], None]): + def _on_close() -> None: + on_close() + + option_dialog = CommonChooseObjectOptionDialog( + CommonObjectUtils.get_catalog_name(self._game_object), + 0, + on_close=_on_close, + mod_identity=self.mod_identity, + per_page=500 + ) + + def _on_state_chosen(_: str, _chosen_state: ObjectState): + if _chosen_state is None: + _on_close() + return + CommonObjectStateUtils.set_object_state(self._game_object, _chosen_state) + _on_close() + + current_object_state_value = CommonObjectStateUtils.get_current_object_state(self._game_object, object_state) + for object_state_value in object_state.values: + display_name = CommonLocalizationUtils.create_localized_string(str(object_state_value)) + icon = CommonIconUtils.load_unfilled_circle_icon() + if object_state_value == current_object_state_value: + icon = CommonIconUtils.load_filled_circle_icon() + option_dialog.add_option( + CommonDialogSelectOption( + str(object_state_value), + object_state_value, + CommonDialogOptionContext( + display_name, + 0, + icon=icon + ), + on_chosen=_on_state_chosen + ) + ) + + option_dialog.show(sort_options=True) diff --git a/Scripts/s4ap/sims4communitylib/debug/interactions/__init__.py b/Scripts/s4ap/sims4communitylib/debug/interactions/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/debug/interactions/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/debug/interactions/_register_interactions.py b/Scripts/s4ap/sims4communitylib/debug/interactions/_register_interactions.py new file mode 100644 index 0000000..f8c5364 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/debug/interactions/_register_interactions.py @@ -0,0 +1,163 @@ +""" +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 +""" +from typing import Tuple + +from objects.game_object import GameObject +from objects.script_object import ScriptObject +from sims.sim import Sim +from sims4communitylib.enums.affordance_list_ids import CommonAffordanceListId +from sims4communitylib.enums.enumtypes.common_int import CommonInt +from sims4communitylib.enums.interactions_enum import CommonInteractionId +from sims4communitylib.services.interactions.interaction_registration_service import CommonInteractionRegistry, \ + CommonInteractionType, CommonScriptObjectInteractionHandler, CommonInteractionHandler +from sims4communitylib.services.resources.common_instance_manager_modification_registry import \ + CommonInstanceManagerModificationRegistry +from sims4communitylib.services.resources.modification_handlers.common_add_interactions_to_affordance_lists_handler import \ + CommonAddInteractionsToAffordanceListsModificationHandler +from sims4communitylib.utils.common_type_utils import CommonTypeUtils +from sims4communitylib.utils.objects.common_object_state_utils import CommonObjectStateUtils + + +@CommonInteractionRegistry.register_interaction_handler(CommonInteractionType.ON_SCRIPT_OBJECT_LOAD) +class _S4CLObjectBrokennessDebugInteractionHandler(CommonScriptObjectInteractionHandler): + # noinspection PyMissingOrEmptyDocstring + @property + def interactions_to_add(self) -> Tuple[CommonInt]: + result: Tuple[CommonInt, ...] = ( + CommonInteractionId.S4CL_DEBUG_OBJECT_BREAK, + CommonInteractionId.S4CL_DEBUG_OBJECT_FIX + ) + return result + + # noinspection PyMissingOrEmptyDocstring + def should_add(self, script_object: ScriptObject, *args, **kwargs) -> bool: + if not isinstance(script_object, GameObject): + return False + script_object: GameObject = script_object + return CommonObjectStateUtils.can_become_broken(script_object) + + +@CommonInteractionRegistry.register_interaction_handler(CommonInteractionType.ON_SCRIPT_OBJECT_LOAD) +class _S4CLObjectDirtinessDebugInteractionHandler(CommonScriptObjectInteractionHandler): + # noinspection PyMissingOrEmptyDocstring + @property + def interactions_to_add(self) -> Tuple[CommonInt]: + result: Tuple[CommonInt, ...] = ( + CommonInteractionId.S4CL_DEBUG_OBJECT_MAKE_DIRTY, + CommonInteractionId.S4CL_DEBUG_OBJECT_MAKE_CLEAN + ) + return result + + # noinspection PyMissingOrEmptyDocstring + def should_add(self, script_object: ScriptObject, *args, **kwargs) -> bool: + if not isinstance(script_object, GameObject): + return False + script_object: GameObject = script_object + return CommonObjectStateUtils.can_become_dirty(script_object) + + +@CommonInteractionRegistry.register_interaction_handler(CommonInteractionType.ON_SCRIPT_OBJECT_LOAD) +class _S4CLDebugEverywhereObjectInteractionHandler(CommonScriptObjectInteractionHandler): + # noinspection PyMissingOrEmptyDocstring + @property + def interactions_to_add(self) -> Tuple[CommonInt]: + result: Tuple[CommonInt, ...] = ( + CommonInteractionId.S4CL_DEBUG_LOG_ALL_INTERACTIONS, + CommonInteractionId.S4CL_DEBUG_LOG_ALL_GAME_TAGS, + CommonInteractionId.S4CL_DEBUG_CHANGE_OBJECT_STATES, + ) + return result + + # noinspection PyMissingOrEmptyDocstring + def should_add(self, script_object: ScriptObject, *args, **kwargs) -> bool: + return not CommonTypeUtils.is_sim_or_sim_info(script_object) + + +@CommonInteractionRegistry.register_interaction_handler(CommonInteractionType.ON_TERRAIN_LOAD) +class _S4CLDebugEverywhereTerrainInteractionHandler(CommonInteractionHandler): + # noinspection PyMissingOrEmptyDocstring + @property + def interactions_to_add(self) -> Tuple[CommonInt]: + result: Tuple[CommonInt, ...] = ( + CommonInteractionId.S4CL_DEBUG_LOG_ALL_INTERACTIONS, + ) + return result + + +@CommonInteractionRegistry.register_interaction_handler(CommonInteractionType.ON_OCEAN_LOAD) +class _S4CLDebugEverywhereOceanInteractionHandler(CommonInteractionHandler): + # noinspection PyMissingOrEmptyDocstring + @property + def interactions_to_add(self) -> Tuple[CommonInt]: + result: Tuple[CommonInt, ...] = ( + CommonInteractionId.S4CL_DEBUG_LOG_ALL_INTERACTIONS, + CommonInteractionId.S4CL_DEBUG_LOG_ALL_GAME_TAGS, + CommonInteractionId.S4CL_DEBUG_CHANGE_OBJECT_STATES, + ) + return result + + +@CommonInteractionRegistry.register_interaction_handler(CommonInteractionType.ADD_TO_SIM_RELATIONSHIP_PANEL_INTERACTIONS) +class _S4CLDebugSimRelationshipPanelInteractionHandler(CommonScriptObjectInteractionHandler): + # noinspection PyMissingOrEmptyDocstring + @property + def interactions_to_add(self) -> Tuple[CommonInt]: + result: Tuple[CommonInt, ...] = ( + CommonInteractionId.S4CL_DEBUG_LOG_ALL_INTERACTIONS, + ) + return result + + # noinspection PyMissingOrEmptyDocstring + def should_add(self, script_object: Sim, *args, **kwargs) -> bool: + return CommonTypeUtils.is_sim_or_sim_info(script_object) + + +@CommonInteractionRegistry.register_interaction_handler(CommonInteractionType.ADD_TO_SIM_PHONE_INTERACTIONS) +class _S4CLDebugSimPhoneInteractionHandler(CommonScriptObjectInteractionHandler): + # noinspection PyMissingOrEmptyDocstring + @property + def interactions_to_add(self) -> Tuple[CommonInt]: + result: Tuple[CommonInt, ...] = ( + CommonInteractionId.S4CL_DEBUG_LOG_ALL_INTERACTIONS_PHONE, + ) + return result + + # noinspection PyMissingOrEmptyDocstring + def should_add(self, script_object: ScriptObject, *args, **kwargs) -> bool: + return CommonTypeUtils.is_sim_or_sim_info(script_object) + + +@CommonInstanceManagerModificationRegistry.register_modification_handler() +class _S4CLAddDebugInteractionsToAffordanceWhitelist(CommonAddInteractionsToAffordanceListsModificationHandler): + # noinspection PyMissingOrEmptyDocstring + @property + def interaction_ids(self) -> Tuple[CommonInt]: + result: Tuple[CommonInt, ...] = ( + CommonInteractionId.S4CL_DEBUG_SHOW_RUNNING_AND_QUEUED_INTERACTIONS, + CommonInteractionId.S4CL_DEBUG_SHOW_ACTIVE_BUFFS, + CommonInteractionId.S4CL_DEBUG_SHOW_TRAITS, + CommonInteractionId.S4CL_DEBUG_SHOW_RUNNING_SITUATIONS, + CommonInteractionId.S4CL_DEBUG_LOG_ALL_INTERACTIONS, + CommonInteractionId.S4CL_DEBUG_LOG_ALL_INTERACTIONS_PHONE, + CommonInteractionId.S4CL_DEBUG_INDUCE_LABOR, + CommonInteractionId.S4CL_DEBUG_OBJECT_BREAK, + CommonInteractionId.S4CL_DEBUG_OBJECT_FIX, + CommonInteractionId.S4CL_DEBUG_OBJECT_MAKE_DIRTY, + CommonInteractionId.S4CL_DEBUG_OBJECT_MAKE_CLEAN, + CommonInteractionId.S4CL_DEBUG_LOG_ALL_GAME_TAGS, + CommonInteractionId.S4CL_DEBUG_CHANGE_OBJECT_STATES, + ) + return result + + # noinspection PyMissingOrEmptyDocstring + @property + def affordance_list_ids(self) -> Tuple[int]: + result: Tuple[int, ...] = ( + CommonAffordanceListId.DEBUG_AFFORDANCES, + ) + return result diff --git a/Scripts/s4ap/sims4communitylib/debug/interactions/change_object_states.py b/Scripts/s4ap/sims4communitylib/debug/interactions/change_object_states.py new file mode 100644 index 0000000..3d13dff --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/debug/interactions/change_object_states.py @@ -0,0 +1,70 @@ +""" +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 +""" +from typing import Any, Tuple + +from interactions import ParticipantType +from interactions.context import InteractionContext +from sims.sim import Sim +from sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction +from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + + +class S4CLDebugChangeObjectStatesInteraction(CommonImmediateSuperInteraction): + """ Change States of an Object. """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + return ModInfo.get_identity() + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 's4cl_debug_change_object_states' + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, picked_item_ids: Tuple[int] = (), **kwargs) -> CommonTestResult: + if interaction_target is None and not picked_item_ids: + cls.get_log().debug('Failed, Target is not valid.') + return CommonTestResult.NONE + cls.get_log().debug('Success, can show active Buffs.') + return CommonTestResult.TRUE + + # noinspection PyMissingOrEmptyDocstring + def on_started(self, interaction_sim: Sim, interaction_target: Any) -> CommonExecutionResult: + picked_item_id = self.get_participant(ParticipantType.PickedItemId) + self.log.format_with_message('Got picked item ids', picked_item_id=picked_item_id) + if picked_item_id is not None: + new_target = CommonSimUtils.get_sim_info(picked_item_id) + if new_target is None: + self.log.format_with_message('No Sim with the identifier found.', picked_item_id=picked_item_id) + new_target = CommonObjectUtils.get_game_object(picked_item_id) + if new_target is None: + self.log.format_with_message('No object with the identifier found.', picked_item_id=picked_item_id) + return CommonExecutionResult(False, reason=f'Picked Item {picked_item_id} was not found.') + else: + self.log.format_with_message('Found object target using picked item id.', new_target=new_target) + interaction_target = new_target + else: + self.log.format_with_message('Found Sim target using picked item id.', new_target=new_target) + new_target = CommonSimUtils.get_sim_instance(new_target) + if new_target is None: + self.log.format_with_message('Had Sim Info, but did not have Sim instance.', new_target=new_target) + else: + self.log.format_with_message('Had Sim Instance.', new_target=new_target) + interaction_target = new_target + + from sims4communitylib.debug.dialogs.common_change_object_state_dialog import CommonChangeObjectStateDialog + CommonChangeObjectStateDialog(interaction_target).open() + return CommonExecutionResult.TRUE diff --git a/Scripts/s4ap/sims4communitylib/debug/interactions/induce_labor.py b/Scripts/s4ap/sims4communitylib/debug/interactions/induce_labor.py new file mode 100644 index 0000000..bb931aa --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/debug/interactions/induce_labor.py @@ -0,0 +1,62 @@ +""" +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 +""" +from typing import Any + +from interactions.context import InteractionContext +from sims.sim import Sim +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils +from sims4communitylib.utils.sims.common_sim_pregnancy_utils import CommonSimPregnancyUtils +from sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from sims4communitylib.utils.common_type_utils import CommonTypeUtils + + +class S4CLDebugInduceLaborInteraction(CommonImmediateSuperInteraction): + """ Handle the interaction to Induce Labor. """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + return ModInfo.get_identity() + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 's4cl_debug_induce_labor' + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, **kwargs) -> CommonTestResult: + if interaction_target is None or not CommonTypeUtils.is_sim_or_sim_info(interaction_target): + cls.get_log().debug('Target is not a Sim.') + return CommonTestResult.NONE + target_sim_info = CommonSimUtils.get_sim_info(interaction_target) + if not CommonSimPregnancyUtils.can_be_impregnated(target_sim_info): + cls.get_log().format_with_message('Sim cannot be impregnated and thus cannot be pregnant.', target_sim=target_sim_info) + return CommonTestResult.NONE + if not hasattr(target_sim_info, 'pregnancy_tracker'): + cls.get_log().format_with_message('Target does not have a pregnancy tracker.', target_sim=target_sim_info) + return CommonTestResult.NONE + cls.get_log().format_with_message('Checking if Sim is pregnant.', target_sim=target_sim_info) + if not CommonSimPregnancyUtils.is_pregnant(target_sim_info): + cls.get_log().format_with_message('Sim is not pregnant.', sim=target_sim_info) + return cls.create_test_result(False, reason='\'{}\' is not pregnant.'.format(CommonSimNameUtils.get_full_name(target_sim_info)), tooltip=CommonLocalizationUtils.create_localized_tooltip(CommonStringId.S4CL_SIM_IS_NOT_PREGNANT, tooltip_tokens=(target_sim_info, ))) + cls.get_log().debug('Success.') + return CommonTestResult.TRUE + + # noinspection PyMissingOrEmptyDocstring + def on_started(self, interaction_sim: Sim, interaction_target: Sim) -> bool: + target_sim_info = CommonSimUtils.get_sim_info(interaction_target) + self.log.format_with_message('The baby wants out now! Labor induced in Sim.', target_sim=target_sim_info) + CommonSimPregnancyUtils.induce_labor_in_sim(target_sim_info) + return True diff --git a/Scripts/s4ap/sims4communitylib/debug/interactions/log_all_game_tags.py b/Scripts/s4ap/sims4communitylib/debug/interactions/log_all_game_tags.py new file mode 100644 index 0000000..24c55db --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/debug/interactions/log_all_game_tags.py @@ -0,0 +1,69 @@ +""" +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 +""" +from typing import Any, Tuple + +from interactions import ParticipantType +from interactions.context import InteractionContext +from sims.sim import Sim +from sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction +from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.utils.objects.common_object_tag_utils import CommonObjectTagUtils +from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + + +class S4CLDebugLogAllGameTagsInteraction(CommonImmediateSuperInteraction): + """ Log All Game Tags of a Target. """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + return ModInfo.get_identity() + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 's4cl_debug_log_all_game_tags' + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, picked_item_ids: Tuple[int] = (), **kwargs) -> CommonTestResult: + if interaction_target is None and not picked_item_ids: + cls.get_log().debug('Failed, Target is not valid.') + return CommonTestResult.NONE + cls.get_log().debug('Success, can show active Buffs.') + return CommonTestResult.TRUE + + # noinspection PyMissingOrEmptyDocstring + def on_started(self, interaction_sim: Sim, interaction_target: Any) -> CommonExecutionResult: + picked_item_id = self.get_participant(ParticipantType.PickedItemId) + self.log.format_with_message('Got picked item ids', picked_item_id=picked_item_id) + if picked_item_id is not None: + new_target = CommonSimUtils.get_sim_info(picked_item_id) + if new_target is None: + self.log.format_with_message('No Sim with the identifier found.', picked_item_id=picked_item_id) + new_target = CommonObjectUtils.get_game_object(picked_item_id) + if new_target is None: + self.log.format_with_message('No object with the identifier found.', picked_item_id=picked_item_id) + return CommonExecutionResult(False, reason=f'Picked Item {picked_item_id} was not found.') + else: + self.log.format_with_message('Found object target using picked item id.', new_target=new_target) + interaction_target = new_target + else: + self.log.format_with_message('Found Sim target using picked item id.', new_target=new_target) + new_target = CommonSimUtils.get_sim_instance(new_target) + if new_target is None: + self.log.format_with_message('Had Sim Info, but did not have Sim instance.', new_target=new_target) + else: + self.log.format_with_message('Had Sim Instance.', new_target=new_target) + interaction_target = new_target + CommonObjectTagUtils._print_game_tags(interaction_target) + return CommonExecutionResult.TRUE diff --git a/Scripts/s4ap/sims4communitylib/debug/interactions/log_all_interactions.py b/Scripts/s4ap/sims4communitylib/debug/interactions/log_all_interactions.py new file mode 100644 index 0000000..4e0f581 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/debug/interactions/log_all_interactions.py @@ -0,0 +1,134 @@ +""" +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 +""" +from pprint import pformat +from typing import Any, List, Tuple +from interactions import ParticipantType +from interactions.base.interaction import Interaction +from interactions.context import InteractionContext +from objects.game_object import GameObject +from sims.sim import Sim +from sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction +from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification +from sims4communitylib.utils.common_log_utils import CommonLogUtils +from sims4communitylib.utils.common_type_utils import CommonTypeUtils +from sims4communitylib.utils.objects.common_object_interaction_utils import CommonObjectInteractionUtils +from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils +from sims4communitylib.utils.resources.common_interaction_utils import CommonInteractionUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + + +class S4CLDebugLogAllInteractionsInteraction(CommonImmediateSuperInteraction): + """ Log All Interactions of an object. """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + return ModInfo.get_identity() + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 's4cl_debug_log_all_interactions' + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, picked_item_ids: Tuple[int] = (), **kwargs) -> CommonTestResult: + if interaction_target is None and not picked_item_ids: + cls.get_log().debug('Failed, No Target was found.') + return cls.create_test_result(False) + cls.get_log().format_with_message( + 'Success, can show Log All Interactions interaction.', + interaction_sim=interaction_sim, + interaction_target=interaction_target, + picked_item_ids=picked_item_ids + ) + return cls.create_test_result(True) + + # noinspection PyMissingOrEmptyDocstring + def on_started(self, interaction_sim: Sim, interaction_target: Any) -> CommonExecutionResult: + self.log.enable() + # noinspection PyUnresolvedReferences + picked_item_id = self.get_participant(ParticipantType.PickedItemId) + self.log.format_with_message('Got picked item ids', picked_item_id=picked_item_id) + if picked_item_id is not None: + new_target = CommonSimUtils.get_sim_info(picked_item_id) + if new_target is None: + self.log.format_with_message('No Sim with the identifier found.', picked_item_id=picked_item_id) + new_target = CommonObjectUtils.get_game_object(picked_item_id) + if new_target is None: + self.log.format_with_message('No object with the identifier found.', picked_item_id=picked_item_id) + return CommonExecutionResult(False, reason=f'Picked Item {picked_item_id} was not found.') + else: + self.log.format_with_message('Found object target using picked item id.', new_target=new_target) + interaction_target = new_target + else: + self.log.format_with_message('Found Sim target using picked item id.', new_target=new_target) + new_target = CommonSimUtils.get_sim_instance(new_target) + if new_target is None: + self.log.format_with_message('Had Sim Info, but did not have Sim instance.', new_target=new_target) + else: + self.log.format_with_message('Had Sim Instance.', new_target=new_target) + interaction_target = new_target + object_id = CommonObjectUtils.get_object_id(interaction_target) if interaction_target is not None else -1 + object_tuning_name = None + definition_id = -1 + if CommonTypeUtils.is_sim_or_sim_info(interaction_target): + target_sim_info = CommonSimUtils.get_sim_info(interaction_target) + object_id = CommonSimUtils.get_sim_id(interaction_target) + target_sim = CommonSimUtils.get_sim_instance(interaction_target) + object_tuning_name = target_sim.__name__ if hasattr(target_sim, '__name__') else target_sim.__class__.__name__ + rig_hash64 = target_sim.rig.hash64 + rig_instance = target_sim.rig.instance + self.log.format_with_message('All things on rig', rig64=rig_hash64, rig_instance=rig_instance, target_rig_key=target_sim_info.rig_key) + definition = CommonObjectUtils.get_game_object_definition(target_sim) + if definition is not None: + definition_id = definition.id + elif CommonTypeUtils.is_game_object(interaction_target): + object_tuning_name = interaction_target.__name__ if hasattr(interaction_target, '__name__') else interaction_target.__class__.__name__ + rig_hash64 = interaction_target.rig.hash64 + rig_instance = interaction_target.rig.instance + self.log.format_with_message('All things on rig', rig64=rig_hash64, rig_instance=rig_instance) + definition = CommonObjectUtils.get_game_object_definition(interaction_target) + if definition is not None: + definition_id = definition.id + self.log.debug(f'Interactions that can be performed on \'{interaction_target}\' id:{object_id} def_id:{definition_id} tuning_name:{object_tuning_name}:') + interactions = CommonObjectInteractionUtils.get_all_interactions_registered_to_object_gen(interaction_target) + interaction_target: GameObject = interaction_target + interaction_short_names: List[str] = list() + for interaction in interactions: + interaction: Interaction = interaction + try: + interaction_short_names.append('{} ({})'.format(CommonInteractionUtils.get_interaction_short_name(interaction), CommonInteractionUtils.get_interaction_id(interaction))) + except Exception as ex: + self.log.error('Problem while attempting to handle interaction {}'.format(pformat(interaction)), exception=ex) + continue + for component in interaction_target.components: + if not hasattr(component, 'component_super_affordances_gen'): + continue + for affordance in component.component_super_affordances_gen(): + try: + interaction_short_names.append('{} ({})'.format(CommonInteractionUtils.get_interaction_short_name(affordance), CommonInteractionUtils.get_interaction_id(affordance))) + except Exception as ex: + self.log.error('Problem while attempting to handle affordance {}'.format(pformat(affordance)), exception=ex) + continue + + sorted_short_names = sorted(interaction_short_names, key=lambda x: x) + self.log.format(interactions=sorted_short_names) + self.log.debug('Done Logging Available Interactions.') + self.log.disable() + CommonBasicNotification( + CommonStringId.S4CL_LOG_ALL_INTERACTIONS, + CommonStringId.S4CL_DONE_LOGGING_ALL_INTERACTIONS, + description_tokens=(CommonLogUtils.get_message_file_path(self.mod_identity), ) + ).show() + return CommonExecutionResult.TRUE diff --git a/Scripts/s4ap/sims4communitylib/debug/interactions/object_break.py b/Scripts/s4ap/sims4communitylib/debug/interactions/object_break.py new file mode 100644 index 0000000..906c33f --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/debug/interactions/object_break.py @@ -0,0 +1,51 @@ +""" +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 +""" +from typing import Any +from interactions.context import InteractionContext +from objects.game_object import GameObject +from sims.sim import Sim +from sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.utils.common_type_utils import CommonTypeUtils +from sims4communitylib.utils.objects.common_object_state_utils import CommonObjectStateUtils + + +class S4CLDebugObjectBreakInteraction(CommonImmediateSuperInteraction): + """S4CLDebugObjectBreakInteraction(*_, **__) + + Set the target Object to a broken state. + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + return ModInfo.get_identity() + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 's4cl_debug_break_object' + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, **kwargs) -> CommonTestResult: + if interaction_target is None or CommonTypeUtils.is_sim_or_sim_info(interaction_target): + cls.get_log().debug('Failed, Target is None.') + return CommonTestResult.NONE + interaction_target: GameObject = interaction_target + if CommonObjectStateUtils.is_broken(interaction_target): + cls.get_log().debug('Failed, the Object is already broken.') + return CommonTestResult.NONE + cls.get_log().debug('Success, can break object.') + return CommonTestResult.TRUE + + # noinspection PyMissingOrEmptyDocstring + def on_started(self, interaction_sim: Sim, interaction_target: GameObject) -> bool: + return CommonObjectStateUtils.break_object(interaction_target) diff --git a/Scripts/s4ap/sims4communitylib/debug/interactions/object_fix.py b/Scripts/s4ap/sims4communitylib/debug/interactions/object_fix.py new file mode 100644 index 0000000..b675fb1 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/debug/interactions/object_fix.py @@ -0,0 +1,51 @@ +""" +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 +""" +from typing import Any +from interactions.context import InteractionContext +from objects.game_object import GameObject +from sims.sim import Sim +from sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.utils.common_type_utils import CommonTypeUtils +from sims4communitylib.utils.objects.common_object_state_utils import CommonObjectStateUtils + + +class S4CLDebugObjectFixInteraction(CommonImmediateSuperInteraction): + """S4CLDebugObjectFixInteraction(*_, **__) + + Set the target Object to a fixed state. + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + return ModInfo.get_identity() + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 's4cl_debug_fix_object' + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, **kwargs) -> CommonTestResult: + if interaction_target is None or CommonTypeUtils.is_sim_or_sim_info(interaction_target): + cls.get_log().debug('Failed, Target is None.') + return CommonTestResult.NONE + interaction_target: GameObject = interaction_target + if not CommonObjectStateUtils.is_broken(interaction_target): + cls.get_log().debug('Failed, the Object is not broken.') + return CommonTestResult.NONE + cls.get_log().debug('Success, can fix object.') + return CommonTestResult.TRUE + + # noinspection PyMissingOrEmptyDocstring + def on_started(self, interaction_sim: Sim, interaction_target: GameObject) -> bool: + return CommonObjectStateUtils.fix_object(interaction_target) diff --git a/Scripts/s4ap/sims4communitylib/debug/interactions/object_make_clean.py b/Scripts/s4ap/sims4communitylib/debug/interactions/object_make_clean.py new file mode 100644 index 0000000..af3bccf --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/debug/interactions/object_make_clean.py @@ -0,0 +1,51 @@ +""" +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 +""" +from typing import Any +from interactions.context import InteractionContext +from objects.game_object import GameObject +from sims.sim import Sim +from sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.utils.common_type_utils import CommonTypeUtils +from sims4communitylib.utils.objects.common_object_state_utils import CommonObjectStateUtils + + +class S4CLDebugObjectMakeCleanInteraction(CommonImmediateSuperInteraction): + """S4CLDebugObjectMakeCleanInteraction(*_, **__) + + Set the target Object to a clean state. + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + return ModInfo.get_identity() + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 's4cl_debug_make_object_clean' + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, **kwargs) -> CommonTestResult: + if interaction_target is None or CommonTypeUtils.is_sim_or_sim_info(interaction_target): + cls.get_log().debug('Failed, Target is None.') + return CommonTestResult.NONE + interaction_target: GameObject = interaction_target + if not CommonObjectStateUtils.is_dirty(interaction_target): + cls.get_log().debug('Failed, the Object is not dirty.') + return CommonTestResult.NONE + cls.get_log().debug('Success, can make object clean.') + return CommonTestResult.TRUE + + # noinspection PyMissingOrEmptyDocstring + def on_started(self, interaction_sim: Sim, interaction_target: GameObject) -> bool: + return CommonObjectStateUtils.make_clean(interaction_target) diff --git a/Scripts/s4ap/sims4communitylib/debug/interactions/object_make_dirty.py b/Scripts/s4ap/sims4communitylib/debug/interactions/object_make_dirty.py new file mode 100644 index 0000000..ed24d56 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/debug/interactions/object_make_dirty.py @@ -0,0 +1,51 @@ +""" +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 +""" +from typing import Any +from interactions.context import InteractionContext +from objects.game_object import GameObject +from sims.sim import Sim +from sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.utils.common_type_utils import CommonTypeUtils +from sims4communitylib.utils.objects.common_object_state_utils import CommonObjectStateUtils + + +class S4CLDebugObjectMakeDirtyInteraction(CommonImmediateSuperInteraction): + """S4CLDebugObjectMakeDirtyInteraction(*_, **__) + + Set the target Object to a dirty state. + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + return ModInfo.get_identity() + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 's4cl_debug_make_object_dirty' + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, **kwargs) -> CommonTestResult: + if interaction_target is None or CommonTypeUtils.is_sim_or_sim_info(interaction_target): + cls.get_log().debug('Failed, Target is None.') + return CommonTestResult.NONE + interaction_target: GameObject = interaction_target + if CommonObjectStateUtils.is_dirty(interaction_target): + cls.get_log().debug('Failed, the Object is already dirty.') + return CommonTestResult.NONE + cls.get_log().debug('Success, can make object dirty.') + return CommonTestResult.TRUE + + # noinspection PyMissingOrEmptyDocstring + def on_started(self, interaction_sim: Sim, interaction_target: GameObject) -> bool: + return CommonObjectStateUtils.make_dirty(interaction_target) diff --git a/Scripts/s4ap/sims4communitylib/debug/interactions/show_active_buffs.py b/Scripts/s4ap/sims4communitylib/debug/interactions/show_active_buffs.py new file mode 100644 index 0000000..52baf57 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/debug/interactions/show_active_buffs.py @@ -0,0 +1,74 @@ +""" +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 +""" +from typing import Any, List + +from distributor.shared_messages import IconInfoData +from interactions.context import InteractionContext +from sims.sim import Sim +from sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification +from sims4communitylib.utils.common_type_utils import CommonTypeUtils +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from sims4communitylib.utils.sims.common_buff_utils import CommonBuffUtils +from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + + +class S4CLDebugShowActiveBuffsInteraction(CommonImmediateSuperInteraction): + """S4CLDebugShowActiveBuffsInteraction(*_, **__) + + Show the currently active Buffs of a Sim. + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + return ModInfo.get_identity() + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 's4cl_debug_show_active_buffs' + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, **kwargs) -> CommonTestResult: + if interaction_target is None or not CommonTypeUtils.is_sim_or_sim_info(interaction_target): + cls.get_log().debug('Failed, Target is not a Sim.') + return CommonTestResult.NONE + cls.get_log().debug('Success, can show active Buffs.') + return CommonTestResult.TRUE + + # noinspection PyMissingOrEmptyDocstring + def on_started(self, interaction_sim: Sim, interaction_target: Sim) -> bool: + target_sim_info = CommonSimUtils.get_sim_info(interaction_target) + target_sim_name = CommonSimNameUtils.get_full_name(target_sim_info) + sim_buff_strings: List[str] = list() + for buff in CommonBuffUtils.get_buffs(target_sim_info): + buff_name = CommonBuffUtils.get_buff_name(buff) + buff_id = CommonBuffUtils.get_buff_id(buff) + sim_buff_strings.append('{} ({})'.format(buff_name, buff_id)) + sim_buff_strings = sorted(sim_buff_strings, key=lambda x: x) + sim_buffs = ', '.join(sim_buff_strings) + text = '' + text += 'Active Buffs:\n{}\n\n'.format(sim_buffs) + self.log.enable() + sim_buffs_for_log = ',\n'.join(sim_buff_strings) + for_log_text = 'Active Buffs:\n{}\n\n'.format(sim_buffs_for_log) + self.log.debug(f'{target_sim_name} ({CommonSimUtils.get_sim_id(target_sim_info)}): {for_log_text}') + self.log.disable() + CommonBasicNotification( + CommonLocalizationUtils.create_localized_string('{} Active Buffs ({})'.format(target_sim_name, CommonSimUtils.get_sim_id(target_sim_info))), + CommonLocalizationUtils.create_localized_string(text) + ).show( + icon=IconInfoData(obj_instance=interaction_target) + ) + return True diff --git a/Scripts/s4ap/sims4communitylib/debug/interactions/show_running_and_queued_interactions.py b/Scripts/s4ap/sims4communitylib/debug/interactions/show_running_and_queued_interactions.py new file mode 100644 index 0000000..65ed00d --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/debug/interactions/show_running_and_queued_interactions.py @@ -0,0 +1,86 @@ +""" +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 +""" +from typing import Any, List + +from distributor.shared_messages import IconInfoData +from interactions.context import InteractionContext +from sims.sim import Sim +from sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification +from sims4communitylib.utils.common_type_utils import CommonTypeUtils +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + + +class S4CLDebugShowRunningAndQueuedInteractionsInteraction(CommonImmediateSuperInteraction): + """S4CLDebugShowRunningAndQueuedInteractionsInteraction(*_, **__) + + Show the currently running and queued interactions of a Sim. + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + return ModInfo.get_identity() + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 's4cl_debug_show_running_and_queued_interactions' + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, **kwargs) -> CommonTestResult: + if interaction_target is None or not CommonTypeUtils.is_sim_or_sim_info(interaction_target): + cls.get_log().debug('Failed, Target is not a Sim.') + return CommonTestResult.NONE + cls.get_log().debug('Success, can show running and queued interactions.') + return CommonTestResult.TRUE + + # noinspection PyMissingOrEmptyDocstring + def on_started(self, interaction_sim: Sim, interaction_target: Sim) -> bool: + target_sim_info = CommonSimUtils.get_sim_info(interaction_target) + target_sim_name = CommonSimNameUtils.get_full_name(target_sim_info) + from sims4communitylib.utils.sims.common_sim_interaction_utils import CommonSimInteractionUtils + from sims4communitylib.utils.resources.common_interaction_utils import CommonInteractionUtils + running_interaction_strings: List[str] = list() + for interaction in CommonSimInteractionUtils.get_running_interactions_gen(target_sim_info): + interaction_name = CommonInteractionUtils.get_interaction_short_name(interaction) + interaction_id = CommonInteractionUtils.get_interaction_id(interaction) + running_interaction_strings.append('{} ({})'.format(interaction_name, interaction_id)) + running_interaction_strings = sorted(running_interaction_strings, key=lambda x: x) + running_interaction_names = ', '.join(running_interaction_strings) + + queued_interaction_strings: List[str] = list() + for interaction in CommonSimInteractionUtils.get_queued_interactions_gen(target_sim_info): + interaction_name = CommonInteractionUtils.get_interaction_short_name(interaction) + interaction_id = CommonInteractionUtils.get_interaction_id(interaction) + queued_interaction_strings.append('{} ({})'.format(interaction_name, interaction_id)) + queued_interaction_strings = sorted(queued_interaction_strings, key=lambda x: x) + queued_interaction_names = ', '.join(queued_interaction_strings) + text = '' + text += 'Running Interactions:\n{}\n\n'.format(running_interaction_names) + text += 'Queued Interactions:\n{}\n\n'.format(queued_interaction_names) + self.log.enable() + sim_running_interactions_for_log = ',\n'.join(running_interaction_strings) + for_log_text = 'Running Interactions:\n{}\n\n'.format(sim_running_interactions_for_log) + sim_queued_interactions_for_log = ',\n'.join(queued_interaction_strings) + for_log_text += 'Queued Interactions:\n{}\n\n'.format(sim_queued_interactions_for_log) + self.log.debug(f'{target_sim_name} ({CommonSimUtils.get_sim_id(target_sim_info)}): {for_log_text}') + self.log.disable() + CommonBasicNotification( + CommonLocalizationUtils.create_localized_string('{} Running and Queued Interactions ({})'.format(target_sim_name, CommonSimUtils.get_sim_id(target_sim_info))), + CommonLocalizationUtils.create_localized_string(text) + ).show( + icon=IconInfoData(obj_instance=interaction_target) + ) + return True diff --git a/Scripts/s4ap/sims4communitylib/debug/interactions/show_running_situations.py b/Scripts/s4ap/sims4communitylib/debug/interactions/show_running_situations.py new file mode 100644 index 0000000..d111895 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/debug/interactions/show_running_situations.py @@ -0,0 +1,90 @@ +""" +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 +""" +from typing import Any, List + +from distributor.shared_messages import IconInfoData +from interactions.context import InteractionContext +from sims.sim import Sim +from sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification +from sims4communitylib.utils.common_type_utils import CommonTypeUtils +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from sims4communitylib.utils.resources.common_situation_utils import CommonSituationUtils +from sims4communitylib.utils.sims.common_sim_situation_utils import CommonSimSituationUtils + + +class S4CLDebugShowRunningSituationsInteraction(CommonImmediateSuperInteraction): + """S4CLDebugShowRunningSituationsInteraction(*_, **__) + + Show the currently running Situations of a Sim. + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + return ModInfo.get_identity() + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 's4cl_debug_show_running_situations' + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, **kwargs) -> CommonTestResult: + if interaction_target is None or not CommonTypeUtils.is_sim_or_sim_info(interaction_target): + cls.get_log().debug('Failed, Target is not a Sim.') + return CommonTestResult.NONE + cls.get_log().debug('Success, can show active Buffs.') + return CommonTestResult.TRUE + + # noinspection PyMissingOrEmptyDocstring + def on_started(self, interaction_sim: Sim, interaction_target: Sim) -> bool: + target_sim_info = CommonSimUtils.get_sim_info(interaction_target) + target_sim_name = CommonSimNameUtils.get_full_name(target_sim_info) + situation_strings: List[str] = list() + for situation in CommonSimSituationUtils.get_situations(target_sim_info): + from situations.situation import Situation + situation: Situation = situation + situation_name = CommonSituationUtils.get_situation_name(situation) + situation_id = CommonSituationUtils.get_situation_id(situation) + current_job = situation.get_current_job_for_sim(interaction_target) + # noinspection PyBroadException + try: + job_name = current_job.__name__ or 'No Job' + except: + job_name = 'No Job' + current_role = situation.get_current_role_state_for_sim(interaction_target) + # noinspection PyBroadException + try: + role_name = current_role.__name__ or 'No Role' + except: + role_name = 'No Role' + situation_strings.append('S:{} ({})\n Job: {}\n Role: {}'.format(situation_name, situation_id, job_name, role_name)) + + situation_strings = sorted(situation_strings, key=lambda x: x) + sim_situations = '\n\n'.join(situation_strings) + text = '' + text += 'Running Situations:\n{}'.format(sim_situations) + self.log.enable() + sim_buffs_for_log = '\n\n'.join(situation_strings) + for_log_text = 'Running Situations:\n{}\n\n'.format(sim_buffs_for_log) + self.log.debug(f'{target_sim_name} ({CommonSimUtils.get_sim_id(target_sim_info)}): {for_log_text}') + self.log.disable() + CommonBasicNotification( + CommonLocalizationUtils.create_localized_string('{} Running Situations ({})'.format(target_sim_name, CommonSimUtils.get_sim_id(target_sim_info))), + CommonLocalizationUtils.create_localized_string(text) + ).show( + icon=IconInfoData(obj_instance=interaction_target) + ) + return True diff --git a/Scripts/s4ap/sims4communitylib/debug/interactions/show_traits.py b/Scripts/s4ap/sims4communitylib/debug/interactions/show_traits.py new file mode 100644 index 0000000..c6199c8 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/debug/interactions/show_traits.py @@ -0,0 +1,75 @@ +""" +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 +""" +from typing import Any, List + +from distributor.shared_messages import IconInfoData +from interactions.context import InteractionContext +from sims.sim import Sim +from sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification +from sims4communitylib.utils.common_type_utils import CommonTypeUtils +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils + + +class S4CLDebugShowTraitsInteraction(CommonImmediateSuperInteraction): + """S4CLDebugShowTraitsInteraction(*_, **__) + + Show the current Traits of a Sim. + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + return ModInfo.get_identity() + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 's4cl_debug_show_traits' + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, **kwargs) -> CommonTestResult: + if interaction_target is None or not CommonTypeUtils.is_sim_or_sim_info(interaction_target): + cls.get_log().debug('Failed, Target is not a Sim.') + return CommonTestResult.NONE + cls.get_log().debug('Success, can show active Buffs.') + return CommonTestResult.TRUE + + # noinspection PyMissingOrEmptyDocstring + def on_started(self, interaction_sim: Sim, interaction_target: Sim) -> bool: + target_sim_info = CommonSimUtils.get_sim_info(interaction_target) + target_sim_name = CommonSimNameUtils.get_full_name(target_sim_info) + trait_strings: List[str] = list() + for trait in CommonTraitUtils.get_traits(target_sim_info): + trait_name = CommonTraitUtils.get_trait_name(trait) + trait_id = CommonTraitUtils.get_trait_id(trait) + trait_strings.append('{} ({})'.format(trait_name, trait_id)) + + trait_strings = sorted(trait_strings, key=lambda x: x) + sim_traits = ', '.join(trait_strings) + text = '' + text += 'Traits:\n{}\n\n'.format(sim_traits) + self.log.enable() + sim_traits_for_log = ',\n'.join(trait_strings) + for_log_text = 'Traits:\n{}\n\n'.format(sim_traits_for_log) + self.log.debug(f'{target_sim_name} ({CommonSimUtils.get_sim_id(target_sim_info)}): {for_log_text}') + self.log.disable() + CommonBasicNotification( + CommonLocalizationUtils.create_localized_string('{} Traits ({})'.format(target_sim_name, CommonSimUtils.get_sim_id(target_sim_info))), + CommonLocalizationUtils.create_localized_string(text) + ).show( + icon=IconInfoData(obj_instance=interaction_target) + ) + return True diff --git a/Scripts/s4ap/sims4communitylib/debug/traits/__init__.py b/Scripts/s4ap/sims4communitylib/debug/traits/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/debug/traits/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/debug/traits/_auto_apply_traits.py b/Scripts/s4ap/sims4communitylib/debug/traits/_auto_apply_traits.py new file mode 100644 index 0000000..a0fb3e1 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/debug/traits/_auto_apply_traits.py @@ -0,0 +1,442 @@ +""" +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 +""" +from sims.sim_info import SimInfo +from sims4communitylib.enums.traits_enum import CommonTraitId +from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry +from sims4communitylib.events.sim.events.sim_spawned import S4CLSimSpawnedEvent +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils +from sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils +from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils + + +class _S4CLAutoApplyTraits: + """ Auto apply the S4CL main traits. """ + + def _try_apply_traits(self, sim_info: SimInfo): + # Main Trait + if not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_MAIN_TRAIT): + CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_MAIN_TRAIT) + + if CommonSpeciesUtils.is_human(sim_info): + # Main Trait + CommonTraitUtils.remove_trait( + sim_info, + CommonTraitId.S4CL_MAIN_TRAIT_LARGE_DOG, + CommonTraitId.S4CL_MAIN_TRAIT_SMALL_DOG, + CommonTraitId.S4CL_MAIN_TRAIT_CAT, + CommonTraitId.S4CL_MAIN_TRAIT_FOX, + CommonTraitId.S4CL_MAIN_TRAIT_HORSE, + ) + if not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_MAIN_TRAIT_HUMAN): + CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_MAIN_TRAIT_HUMAN) + elif CommonSpeciesUtils.is_large_dog(sim_info): + # Main Trait + CommonTraitUtils.remove_trait( + sim_info, + CommonTraitId.S4CL_MAIN_TRAIT_HUMAN, + CommonTraitId.S4CL_MAIN_TRAIT_SMALL_DOG, + CommonTraitId.S4CL_MAIN_TRAIT_CAT, + CommonTraitId.S4CL_MAIN_TRAIT_FOX, + CommonTraitId.S4CL_MAIN_TRAIT_HORSE, + ) + if not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_MAIN_TRAIT_LARGE_DOG): + CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_MAIN_TRAIT_LARGE_DOG) + # Toilet Standing/Sitting/Unknown + if not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_LARGE_DOG)\ + and not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_LARGE_DOG)\ + and not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_UNKNOWN): + CommonTraitUtils.remove_trait( + sim_info, + CommonTraitId.GENDER_OPTIONS_TOILET_STANDING, + CommonTraitId.GENDER_OPTIONS_TOILET_SITTING, + CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_SMALL_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_SMALL_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_CAT, + CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_CAT, + CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_FOX, + CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_FOX, + CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_HORSE, + CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_HORSE, + ) + if CommonGenderUtils.is_male(sim_info): + CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_LARGE_DOG) + else: + CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_LARGE_DOG) + + # Can Impregnate + CommonTraitUtils.remove_trait( + sim_info, + CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE, + CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_SMALL_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_SMALL_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_CAT, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_CAT, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_FOX, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_FOX, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_HORSE, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_HORSE, + ) + if not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_LARGE_DOG)\ + and not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_LARGE_DOG): + if CommonGenderUtils.is_male(sim_info): + if CommonTraitUtils.has_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_REPRODUCE): + CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_LARGE_DOG) + else: + CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_LARGE_DOG) + else: + CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_LARGE_DOG) + # Can Be Impregnated + CommonTraitUtils.remove_trait( + sim_info, + CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED, + CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_SMALL_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_SMALL_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_CAT, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_CAT, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_FOX, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_FOX, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_HORSE, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_HORSE, + ) + if not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_LARGE_DOG)\ + and not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_LARGE_DOG): + if CommonGenderUtils.is_male(sim_info): + CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_LARGE_DOG) + else: + if CommonTraitUtils.has_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_REPRODUCE): + CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_LARGE_DOG) + else: + CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_LARGE_DOG) + elif CommonSpeciesUtils.is_small_dog(sim_info): + # Main Trait + CommonTraitUtils.remove_trait( + sim_info, + CommonTraitId.S4CL_MAIN_TRAIT_HUMAN, + CommonTraitId.S4CL_MAIN_TRAIT_LARGE_DOG, + CommonTraitId.S4CL_MAIN_TRAIT_CAT, + CommonTraitId.S4CL_MAIN_TRAIT_FOX, + CommonTraitId.S4CL_MAIN_TRAIT_HORSE, + ) + if not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_MAIN_TRAIT_SMALL_DOG): + CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_MAIN_TRAIT_SMALL_DOG) + # Toilet Standing/Sitting/Unknown + CommonTraitUtils.remove_trait( + sim_info, + CommonTraitId.GENDER_OPTIONS_TOILET_STANDING, + CommonTraitId.GENDER_OPTIONS_TOILET_SITTING, + CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_LARGE_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_LARGE_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_CAT, + CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_CAT, + CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_FOX, + CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_FOX, + CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_HORSE, + CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_HORSE, + ) + if not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_SMALL_DOG)\ + and not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_SMALL_DOG)\ + and not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_UNKNOWN): + if CommonGenderUtils.is_male(sim_info): + CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_SMALL_DOG) + else: + CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_SMALL_DOG) + # Can Impregnate + CommonTraitUtils.remove_trait( + sim_info, + CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE, + CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_LARGE_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_LARGE_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_CAT, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_CAT, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_FOX, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_FOX, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_HORSE, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_HORSE, + ) + if not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_SMALL_DOG)\ + and not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_SMALL_DOG): + if CommonGenderUtils.is_male(sim_info): + if CommonTraitUtils.has_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_REPRODUCE): + CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_SMALL_DOG) + else: + CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_SMALL_DOG) + else: + CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_SMALL_DOG) + # Can Be Impregnated + CommonTraitUtils.remove_trait( + sim_info, + CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED, + CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_LARGE_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_LARGE_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_CAT, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_CAT, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_FOX, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_FOX, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_HORSE, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_HORSE, + ) + if not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_SMALL_DOG)\ + and not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_SMALL_DOG): + if CommonGenderUtils.is_male(sim_info): + CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_SMALL_DOG) + else: + if CommonTraitUtils.has_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_REPRODUCE): + CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_SMALL_DOG) + else: + CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_SMALL_DOG) + elif CommonSpeciesUtils.is_cat(sim_info): + # Main Trait + CommonTraitUtils.remove_trait( + sim_info, + CommonTraitId.S4CL_MAIN_TRAIT_HUMAN, + CommonTraitId.S4CL_MAIN_TRAIT_LARGE_DOG, + CommonTraitId.S4CL_MAIN_TRAIT_SMALL_DOG, + CommonTraitId.S4CL_MAIN_TRAIT_FOX, + CommonTraitId.S4CL_MAIN_TRAIT_HORSE, + ) + if not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_MAIN_TRAIT_CAT): + CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_MAIN_TRAIT_CAT) + # Toilet Standing/Sitting/Unknown + CommonTraitUtils.remove_trait( + sim_info, + CommonTraitId.GENDER_OPTIONS_TOILET_STANDING, + CommonTraitId.GENDER_OPTIONS_TOILET_SITTING, + CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_LARGE_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_LARGE_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_SMALL_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_SMALL_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_FOX, + CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_FOX, + CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_HORSE, + CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_HORSE, + ) + if not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_CAT)\ + and not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_CAT)\ + and not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_UNKNOWN): + if CommonGenderUtils.is_male(sim_info): + CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_CAT) + else: + CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_CAT) + # Can Impregnate + CommonTraitUtils.remove_trait( + sim_info, + CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE, + CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_LARGE_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_LARGE_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_SMALL_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_SMALL_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_FOX, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_FOX, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_HORSE, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_HORSE, + ) + if not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_CAT)\ + and not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_CAT): + if CommonGenderUtils.is_male(sim_info): + if CommonTraitUtils.has_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_REPRODUCE): + CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_CAT) + else: + CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_CAT) + else: + CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_CAT) + # Can Be Impregnated + CommonTraitUtils.remove_trait( + sim_info, + CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED, + CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_LARGE_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_LARGE_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_SMALL_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_SMALL_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_FOX, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_FOX, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_HORSE, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_HORSE, + ) + if not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_CAT)\ + and not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_CAT): + if CommonGenderUtils.is_male(sim_info): + CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_CAT) + else: + if CommonTraitUtils.has_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_REPRODUCE): + CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_CAT) + else: + CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_CAT) + elif CommonSpeciesUtils.is_fox(sim_info): + # Main Trait + CommonTraitUtils.remove_trait( + sim_info, + CommonTraitId.S4CL_MAIN_TRAIT_HUMAN, + CommonTraitId.S4CL_MAIN_TRAIT_LARGE_DOG, + CommonTraitId.S4CL_MAIN_TRAIT_SMALL_DOG, + CommonTraitId.S4CL_MAIN_TRAIT_CAT, + CommonTraitId.S4CL_MAIN_TRAIT_HORSE, + ) + if not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_MAIN_TRAIT_FOX): + CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_MAIN_TRAIT_FOX) + # Toilet Standing/Sitting/Unknown + CommonTraitUtils.remove_trait( + sim_info, + CommonTraitId.GENDER_OPTIONS_TOILET_STANDING, + CommonTraitId.GENDER_OPTIONS_TOILET_SITTING, + CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_LARGE_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_LARGE_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_SMALL_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_SMALL_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_CAT, + CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_CAT, + CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_HORSE, + CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_HORSE, + ) + if not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_FOX)\ + and not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_FOX)\ + and not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_UNKNOWN): + if CommonGenderUtils.is_male(sim_info): + CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_FOX) + else: + CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_FOX) + # Can Impregnate + CommonTraitUtils.remove_trait( + sim_info, + CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE, + CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_LARGE_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_LARGE_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_SMALL_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_SMALL_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_CAT, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_CAT, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_HORSE, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_HORSE, + ) + if not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_FOX)\ + and not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_FOX): + if CommonGenderUtils.is_male(sim_info): + if CommonTraitUtils.has_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_REPRODUCE): + CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_FOX) + else: + CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_FOX) + else: + CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_FOX) + # Can Be Impregnated + CommonTraitUtils.remove_trait( + sim_info, + CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED, + CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_LARGE_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_LARGE_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_SMALL_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_SMALL_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_CAT, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_CAT, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_HORSE, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_HORSE, + ) + if not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_FOX)\ + and not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_FOX): + if CommonGenderUtils.is_male(sim_info): + CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_FOX) + else: + if CommonTraitUtils.has_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_REPRODUCE): + CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_FOX) + else: + CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_FOX) + elif CommonSpeciesUtils.is_horse(sim_info): + # Main Trait + CommonTraitUtils.remove_trait( + sim_info, + CommonTraitId.S4CL_MAIN_TRAIT_HUMAN, + CommonTraitId.S4CL_MAIN_TRAIT_LARGE_DOG, + CommonTraitId.S4CL_MAIN_TRAIT_SMALL_DOG, + CommonTraitId.S4CL_MAIN_TRAIT_CAT, + CommonTraitId.S4CL_MAIN_TRAIT_FOX, + ) + if not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_MAIN_TRAIT_HORSE): + CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_MAIN_TRAIT_HORSE) + # Toilet Standing/Sitting/Unknown + CommonTraitUtils.remove_trait( + sim_info, + CommonTraitId.GENDER_OPTIONS_TOILET_STANDING, + CommonTraitId.GENDER_OPTIONS_TOILET_SITTING, + CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_LARGE_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_LARGE_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_SMALL_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_SMALL_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_CAT, + CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_CAT, + CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_FOX, + CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_FOX, + ) + if not CommonTraitUtils.has_trait(sim_info, + CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_HORSE) \ + and not CommonTraitUtils.has_trait(sim_info, + CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_HORSE) \ + and not CommonTraitUtils.has_trait(sim_info, + CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_UNKNOWN): + if CommonGenderUtils.is_male(sim_info): + CommonTraitUtils.add_trait(sim_info, + CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_HORSE) + else: + CommonTraitUtils.add_trait(sim_info, + CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_HORSE) + # Can Impregnate + CommonTraitUtils.remove_trait( + sim_info, + CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE, + CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_LARGE_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_LARGE_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_SMALL_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_SMALL_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_CAT, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_CAT, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_FOX, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_FOX, + ) + if not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_HORSE) \ + and not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_HORSE): + if CommonGenderUtils.is_male(sim_info): + CommonTraitUtils.add_trait(sim_info, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_HORSE) + else: + CommonTraitUtils.add_trait(sim_info, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_HORSE) + # Can Be Impregnated + CommonTraitUtils.remove_trait( + sim_info, + CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED, + CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_LARGE_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_LARGE_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_SMALL_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_SMALL_DOG, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_CAT, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_CAT, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_FOX, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_FOX, + ) + if not CommonTraitUtils.has_trait(sim_info, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_HORSE) \ + and not CommonTraitUtils.has_trait(sim_info, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_HORSE): + if CommonGenderUtils.is_male(sim_info): + CommonTraitUtils.add_trait(sim_info, + CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_HORSE) + else: + CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_HORSE) + + +@CommonEventRegistry.handle_events(ModInfo.get_identity()) +def _common_auto_apply_traits_on_sim_spawned(event_data: S4CLSimSpawnedEvent): + _S4CLAutoApplyTraits()._try_apply_traits(event_data.sim_info) diff --git a/Scripts/s4ap/sims4communitylib/dialogs/__init__.py b/Scripts/s4ap/sims4communitylib/dialogs/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/dialogs/_common_ui_dialog_multi_text_input_ok_cancel.py b/Scripts/s4ap/sims4communitylib/dialogs/_common_ui_dialog_multi_text_input_ok_cancel.py new file mode 100644 index 0000000..70ba055 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/_common_ui_dialog_multi_text_input_ok_cancel.py @@ -0,0 +1,66 @@ +""" +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 +""" +from typing import Tuple, Any, Callable, Iterator +from protocolbuffers.Localization_pb2 import LocalizedString +from sims.sim_info import SimInfo +from sims4communitylib.dialogs.common_input_text_field import CommonInputTextField +from sims4communitylib.enums.common_character_restrictions import CommonCharacterRestriction +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from ui.ui_dialog_generic import UiDialogTextInputOkCancel + + +class _CommonUiDialogMultiTextInputOkCancel(UiDialogTextInputOkCancel): + def __init__( + self, + sim_info: SimInfo, + input_fields: Iterator[CommonInputTextField], + *args, + title: Callable[..., LocalizedString] = None, + text: Callable[..., LocalizedString] = None, + **kwargs + ): + super().__init__( + sim_info, + *args, + title=title, + text=text, + **kwargs + ) + self.input_fields = input_fields + self.text_input_responses = {} + + def on_text_input(self, text_input_name: str = '', text_input: str = '') -> bool: + """A callback that occurs upon text being entered. + + """ + self.text_input_responses[text_input_name] = text_input + return False + + def build_msg(self, text_input_overrides=None, additional_tokens: Tuple[Any] = (), **kwargs): + """Build the message. + + """ + msg = super().build_msg(additional_tokens=(), **kwargs) + for input_field in self.input_fields: + if input_field.initial_value is not None: + self.text_input_responses[input_field.identifier] = str(input_field.initial_value) + text_input_msg = msg.text_input.add() + text_input_msg.text_input_name = input_field.identifier + if input_field.default_text is not None: + text_input_msg.default_text = CommonLocalizationUtils.create_localized_string(input_field.default_text) + if input_field.initial_value is not None: + text_input_msg.initial_value = CommonLocalizationUtils.create_localized_string(str(input_field.initial_value)) + if input_field.title is not None: + text_input_msg.title = CommonLocalizationUtils.create_localized_string(input_field.title) + if input_field.character_restriction is not None and input_field.character_restriction != CommonCharacterRestriction.NONE: + character_restriction_mapping = { + CommonCharacterRestriction.NUMBERS_ONLY: CommonStringId.ZERO_THROUGH_NINE, + } + text_input_msg.restricted_characters = CommonLocalizationUtils.create_localized_string(character_restriction_mapping.get(input_field.character_restriction)) + return msg diff --git a/Scripts/s4ap/sims4communitylib/dialogs/_common_ui_dialog_text_input_ok_cancel.py b/Scripts/s4ap/sims4communitylib/dialogs/_common_ui_dialog_text_input_ok_cancel.py new file mode 100644 index 0000000..afecd18 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/_common_ui_dialog_text_input_ok_cancel.py @@ -0,0 +1,50 @@ +""" +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 +""" +from typing import Tuple, Any, Callable +from protocolbuffers.Localization_pb2 import LocalizedString +from sims.sim_info import SimInfo +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from ui.ui_dialog_generic import UiDialogTextInputOkCancel + + +class _CommonUiDialogTextInputOkCancel(UiDialogTextInputOkCancel): + def __init__( + self, + sim_info: SimInfo, + *args, + title: Callable[..., LocalizedString]=None, + text: Callable[..., LocalizedString]=None, + **kwargs + ): + super().__init__( + sim_info, + *args, + title=title, + text=text, + **kwargs + ) + self.text_input_responses = {} + + def on_text_input(self, text_input_name: str='', text_input: str='') -> bool: + """A callback that occurs upon text being entered. + + """ + self.text_input_responses[text_input_name] = text_input + return False + + def build_msg(self, text_input_overrides=None, additional_tokens: Tuple[Any]=(), **kwargs): + """Build the message. + + """ + from sims4communitylib.dialogs.utils.common_dialog_utils import CommonDialogUtils + msg = super().build_msg(additional_tokens=(), **kwargs) + text_input_msg = msg.text_input.add() + text_input_msg.text_input_name = CommonDialogUtils.TEXT_INPUT_NAME + if additional_tokens and additional_tokens[0] is not None: + text_input_msg.initial_value = CommonLocalizationUtils.create_localized_string(str(additional_tokens[0])) + return msg diff --git a/Scripts/s4ap/sims4communitylib/dialogs/choose_item_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/choose_item_dialog.py new file mode 100644 index 0000000..15f8fd5 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/choose_item_dialog.py @@ -0,0 +1,199 @@ +""" +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 +""" +from typing import Tuple, Any, Callable, Union + +from pprint import pformat +from protocolbuffers.Localization_pb2 import LocalizedString +from sims4communitylib.dialogs.utils.common_dialog_utils import CommonDialogUtils +from sims4communitylib.enums.enumtypes.common_int import CommonInt +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from ui.ui_dialog_picker import UiObjectPicker, ObjectPickerRow + + +class CommonChooseItemResult(CommonInt): + """Different outcomes upon the player choosing or not choosing items in the dialog. + + """ + DIALOG_CANCELLED: 'CommonChooseItemResult' = 0 + ITEM_CHOSEN: 'CommonChooseItemResult' = 1 + ITEM_CHOSEN_WITH_ERROR: 'CommonChooseItemResult' = 2 + + @staticmethod + def is_error(result: 'CommonChooseItemResult') -> bool: + """is_error(result) + + Determine if a result is an error or cancel. + + :param result: The result to check + :type result: CommonChooseItemResult + :return: True, if the result is an error or cancelled. False, if not. + :rtype: bool + """ + return result == CommonChooseItemResult.DIALOG_CANCELLED or result == CommonChooseItemResult.ITEM_CHOSEN_WITH_ERROR + + +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, str, LocalizedString, CommonStringId] + :param description_identifier: A decimal identifier of the description text. + :type description_identifier: Union[int, str, LocalizedString, CommonStringId] + :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, str, LocalizedString, CommonStringId], + description_identifier: Union[int, str, LocalizedString, CommonStringId], + 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 + + 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,) + + 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.DIALOG_CANCELLED) + chosen_item = CommonDialogUtils.get_chosen_item(dialog) + return on_item_chosen(chosen_item, CommonChooseItemResult.ITEM_CHOSEN) + + for list_item in self.list_items: + _dialog.add_row(list_item) + + _dialog.add_listener(_on_item_chosen) + _dialog.show_dialog() + + 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) + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_testing.show_choose_item_dialog', + 'Show an example of CommonChooseItemDialog.', + show_with_help_command=False +) +def _common_testing_show_choose_item_dialog(output: CommonConsoleCommandOutput): + output('Showing test choose item dialog.') + + def _item_chosen(chosen_item: str, result: CommonChooseItemResult): + output('Item chosen {} with result: {}.'.format(pformat(chosen_item), pformat(result))) + + # 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) + output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/choose_object_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/choose_object_dialog.py new file mode 100644 index 0000000..0697779 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/choose_object_dialog.py @@ -0,0 +1,519 @@ +""" +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 +""" +import math + +from typing import Tuple, Any, Callable, Union, Iterator + +from pprint import pformat + +from distributor.shared_messages import IconInfoData +from protocolbuffers.Localization_pb2 import LocalizedString +from sims.sim_info import SimInfo +from sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome +from sims4communitylib.dialogs.common_choose_dialog import CommonChooseDialog +from sims4communitylib.dialogs.common_dialog_navigation_button_tag import CommonDialogNavigationButtonTag +from sims4communitylib.dialogs.custom_dialogs.picker_dialogs.common_ui_object_category_picker import \ + CommonUiObjectCategoryPicker + +from sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_option_category import \ + CommonDialogObjectOptionCategory +from sims4communitylib.dialogs.utils.common_dialog_utils import CommonDialogUtils +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from sims4communitylib.utils.common_icon_utils import CommonIconUtils +from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from ui.ui_dialog_picker import UiObjectPicker, ObjectPickerRow + + +class CommonChooseObjectDialog(CommonChooseDialog): + """CommonChooseObjectDialog(\ + title_identifier,\ + description_identifier,\ + choices,\ + title_tokens=(),\ + description_tokens=(),\ + per_page=25,\ + mod_identity=None,\ + required_tooltip=None,\ + required_tooltip_tokens=()\ + ) + + Create a dialog that prompts the player to choose an object. + + .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_choose_object_dialog` in the in-game console. + + .. highlight:: python + .. code-block:: python + + def _common_testing_show_choose_object_dialog(): + + def _on_chosen(choice: str, outcome: CommonChoiceOutcome): + 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' + ), + 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) + + :param title_identifier: The title to display in the dialog. + :type title_identifier: Union[int, str, LocalizedString, CommonStringId] + :param description_identifier: The description to display in the dialog. + :type description_identifier: Union[int, str, LocalizedString, CommonStringId] + :param choices: The choices that can be chosen. + :type choices: Iterator[ObjectPickerRow] + :param title_tokens: Tokens to format into the title. + :type title_tokens: Iterator[Any], optional + :param description_tokens: Tokens to format into the description. + :type description_tokens: Iterator[Any], optional + :param per_page: The number of rows to display per page. If the number of rows (including rows added after creation) exceeds this value, pagination will be added. + :type per_page: int + :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. + :type mod_identity: CommonModIdentity, optional + :param required_tooltip: If provided, this text will display when the dialog requires at least one choice and a choice has not been made. Default is None. + :type required_tooltip: Union[int, str, LocalizedString, CommonStringId], optional + :param required_tooltip_tokens: Tokens to format into the required tooltip. Default is an empty collection. + :type required_tooltip_tokens: Iterator[Any], optional + """ + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + return 's4cl_choose_object_dialog' + + def __init__( + self, + title_identifier: Union[int, str, LocalizedString, CommonStringId], + description_identifier: Union[int, str, LocalizedString, CommonStringId], + choices: Iterator[ObjectPickerRow], + title_tokens: Iterator[Any]=(), + description_tokens: Iterator[Any]=(), + per_page: int=25, + mod_identity: CommonModIdentity=None, + required_tooltip: Union[int, str, LocalizedString, CommonStringId]=None, + required_tooltip_tokens: Iterator[Any]=() + ): + super().__init__( + title_identifier, + description_identifier, + choices, + title_tokens=title_tokens, + description_tokens=description_tokens, + mod_identity=mod_identity, + required_tooltip=required_tooltip, + required_tooltip_tokens=required_tooltip_tokens + ) + if per_page <= 0: + raise AssertionError('\'per_page\' must be greater than zero.') + self._per_page = per_page + self._always_visible_rows = tuple() + self._current_page = 1 + + @property + def current_page(self) -> int: + """Retrieve the current page. + + :return: A number indicating the current page. + :rtype: int + """ + return self._current_page + + # noinspection PyMissingOrEmptyDocstring + @property + def rows(self) -> Tuple[ObjectPickerRow]: + result: Tuple[ObjectPickerRow] = super().rows + return result + + @property + def always_visible_rows(self) -> Tuple[ObjectPickerRow]: + """A collection of rows that will always appear in the dialog no matter which page. + + .. note:: These rows are added to the dialog before the normal rows are added to the dialog. + + :return: A collection of rows added to the dialog that will always appear. + :rtype: Tuple[ObjectPickerRow] + """ + return self._always_visible_rows + + # noinspection PyMissingOrEmptyDocstring + def add_row(self, choice: ObjectPickerRow, *_, always_visible: bool=False, **__): + """add_row(row, *_, always_on_visible=False, **__) + + Add a row to the dialog. + + :param choice: The row to add. + :type choice: ObjectPickerRow + :param always_visible: If set to True, the row will always appear in the dialog no matter which page. If False, the row will act as normal. Default is False. + :type always_visible: bool, optional + """ + if not always_visible: + super().add_row(choice, *_, **__) + return + try: + self._always_visible_rows += (choice,) + except Exception as ex: + self.log.error('An error occurred while running \'{}\''.format(CommonChooseObjectDialog.add_row.__name__), exception=ex) + + def show( + self, + on_chosen: Callable[[Any, CommonChoiceOutcome], Any]=CommonFunctionUtils.noop, + picker_type: UiObjectPicker.UiObjectPickerObjectPickerType=UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT, + page: int=1, + sim_info: SimInfo=None, + categories: Iterator[CommonDialogObjectOptionCategory]=(), + include_pagination: bool=True, + sort_rows: bool=False + ): + """show(\ + on_chosen=CommonFunctionUtils.noop,\ + picker_type=UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT,\ + page=1,\ + sim_info=None,\ + categories=(),\ + include_pagination=True,\ + sort_rows=True\ + ) + + Show the dialog and invoke the callbacks upon the player making a choice. + + :param on_chosen: A callback invoked upon the player choosing something from the list. Default is CommonFunctionUtils.noop. + :type on_chosen: Callable[[Any, CommonChoiceOutcome], optional + :param picker_type: The layout of the dialog. Default is UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT. + :type picker_type: UiObjectPicker.UiObjectPickerObjectPickerType, optional + :param page: The page to display. Ignored if there is only one page of choices. Default is 1. + :type page: int, optional + :param sim_info: The Sim that will appear in the dialog image. The default Sim is the Active Sim. Default is None. + :type sim_info: SimInfo, optional + :param categories: A collection of categories to display in the dialog. They will appear in a drop down above the rows. Default is an empty collection. + :type categories: Iterator[CommonDialogObjectOptionCategory], optional + :param include_pagination: If True, pagination will be applied. If False, no pagination will be applied. Default is True. + :type include_pagination: bool, optional + :param sort_rows: If True, rows will be sorted by display name, with the selected rows on top. If False, rows will not be sorted. Default is False. + :type sort_rows: bool, optional + """ + self._current_page = page + try: + return self._show( + on_chosen=on_chosen, + picker_type=picker_type, + page=page, + sim_info=sim_info, + categories=categories, + include_pagination=include_pagination, + sort_rows=sort_rows + ) + except Exception as ex: + self.log.error('An error occurred while running \'{}\''.format(CommonChooseObjectDialog.show.__name__), exception=ex) + + def _show( + self, + on_chosen: Callable[[Any, CommonChoiceOutcome], bool]=CommonFunctionUtils.noop, + picker_type: UiObjectPicker.UiObjectPickerObjectPickerType=UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT, + page: int=1, + sim_info: SimInfo=None, + categories: Iterator[CommonDialogObjectOptionCategory]=(), + include_pagination: bool=True, + sort_rows: bool=False + ): + def _on_chosen(choice: Any, outcome: CommonChoiceOutcome) -> bool: + try: + self.log.debug('Choice made.') + if choice == CommonDialogNavigationButtonTag.NEXT: + self.log.debug('Next chosen.') + self.show(on_chosen=on_chosen, picker_type=picker_type, page=page + 1, sim_info=sim_info, categories=categories, sort_rows=sort_rows) + return True + elif choice == CommonDialogNavigationButtonTag.PREVIOUS: + self.log.debug('Previous chosen.') + self.show(on_chosen=on_chosen, picker_type=picker_type, page=page - 1, sim_info=sim_info, categories=categories, sort_rows=sort_rows) + return True + self.log.format_with_message('Choose Object Choice made.', choice=choice) + result = on_chosen(choice, outcome) + self.log.format_with_message('Finished handling choose object _show.', result=result) + return result + except Exception as ex: + self.log.error('Error occurred on choosing a value.', exception=ex) + return False + + _dialog = self.build_dialog( + on_chosen=_on_chosen, + picker_type=picker_type, + page=page, + sim_info=sim_info, + categories=categories, + include_pagination=include_pagination, + sort_rows=sort_rows + ) + self.log.debug('Showing dialog.') + _dialog.show_dialog() + + # noinspection PyMissingOrEmptyDocstring + def build_dialog( + self, + on_chosen: Callable[[Any, CommonChoiceOutcome], bool]=CommonFunctionUtils.noop, + picker_type: UiObjectPicker.UiObjectPickerObjectPickerType=UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT, + page: int=1, + sim_info: SimInfo=None, + categories: Iterator[CommonDialogObjectOptionCategory]=(), + include_pagination: bool=True, + sort_rows: bool=False + ) -> Union[UiObjectPicker, None]: + self.log.format_with_message('Attempting to build dialog.', page=page, categories=categories) + + _dialog = self._create_dialog( + picker_type=picker_type, + categories=categories, + sim_info=sim_info, + sort_rows=sort_rows + ) + if _dialog is None: + self.log.error('_dialog was None for some reason.') + return + + if on_chosen is None: + raise ValueError('on_chosen was None.') + + if len(self.always_visible_rows) == 0 and len(self.rows) == 0: + raise AssertionError('No rows have been provided. Add rows to the dialog before attempting to display it.') + + def _on_chosen(dialog: UiObjectPicker) -> bool: + try: + self.log.debug('Choice made.') + if not dialog.accepted: + self.log.debug('Dialog cancelled.') + return on_chosen(None, CommonChoiceOutcome.CANCEL) + self.log.debug('Choice not made.') + choice = CommonDialogUtils.get_chosen_item(dialog) + self.log.format_with_message('Choose Object Choice made.', choice=pformat(choice)) + result = on_chosen(choice, CommonChoiceOutcome.CHOICE_MADE) + self.log.format_with_message('Finished handling choose object _on_chosen.', result=result) + return result + except Exception as ex: + self.log.error('Error occurred on choosing a value.', exception=ex) + return False + + if include_pagination: + self._setup_dialog_rows( + _dialog, + page=page, + categories=categories + ) + else: + self.log.debug('Adding always visible rows.') + for always_visible_rows in self.always_visible_rows: + _dialog.add_row(always_visible_rows) + self.log.debug('Adding rows.') + for row in self.rows: + _dialog.add_row(row) + + self.log.debug('Adding listener.') + _dialog.add_listener(_on_chosen) + return _dialog + + def _setup_dialog_rows( + self, + _dialog: UiObjectPicker, + page: int=1, + categories: Iterator[CommonDialogObjectOptionCategory]=() + ): + if page < 0: + raise AssertionError('page cannot be less than zero.') + + number_of_rows = len(self.rows) + self.log.format(number_of_rows=number_of_rows, per_page=self._per_page) + if number_of_rows > self._per_page: + number_of_pages = math.ceil(number_of_rows / self._per_page) + + if page > number_of_pages: + raise AssertionError('page was out of range. Number of Pages: {}, Requested Page: {}'.format(str(number_of_pages), str(page))) + # Add the rows that are always visible. + for always_visible_row in self.always_visible_rows: + _dialog.add_row(always_visible_row) + + # Add the rows that should show on the current page. + start_index = (page - 1) * self._per_page + end_index = page * self._per_page + self.log.format(start_index=start_index, end_index=end_index) + current_choices = self.rows[start_index:end_index] + self.log.format(current_rows=current_choices) + for row in current_choices: + _dialog.add_row(row) + + tag_list = [(abs(hash(category.object_category)) % (10 ** 8)) for category in categories] + self.log.format_with_message('Found tags.', tag_list=tag_list) + + if page > 1: + self.log.format_with_message('Adding Previous row.', page=page, number_of_pages=number_of_pages) + previous_choice = ObjectPickerRow( + option_id=len(self.rows) + 2, + name=CommonLocalizationUtils.create_localized_string(CommonStringId.S4CL_EXCLAMATION_EXCLAMATION_STRING, tokens=(CommonStringId.PREVIOUS,)), + row_description=None, + row_tooltip=CommonLocalizationUtils.create_localized_tooltip(CommonStringId.PREVIOUS), + icon=CommonIconUtils.load_arrow_left_icon(), + tag_list=tag_list, + tag=CommonDialogNavigationButtonTag.PREVIOUS + ) + _dialog.add_row(previous_choice) + else: + self.log.format_with_message('Not adding Previous row.', page=page) + if page < number_of_pages: + self.log.format_with_message('Adding Next row.', page=page, number_of_pages=number_of_pages) + next_choice = ObjectPickerRow( + option_id=len(self.rows) + 1, + name=CommonLocalizationUtils.create_localized_string(CommonStringId.S4CL_EXCLAMATION_EXCLAMATION_STRING, tokens=(CommonStringId.NEXT,)), + row_description=None, + row_tooltip=CommonLocalizationUtils.create_localized_tooltip(CommonStringId.NEXT), + icon=CommonIconUtils.load_arrow_right_icon(), + tag_list=tag_list, + tag=CommonDialogNavigationButtonTag.NEXT + ) + _dialog.add_row(next_choice) + else: + self.log.format_with_message('Not adding Next.', page=page, number_of_pages=number_of_pages) + else: + self.log.debug('Adding always visible rows.') + for always_visible_row in self.always_visible_rows: + _dialog.add_row(always_visible_row) + self.log.debug('Adding rows.') + for row in self.rows: + _dialog.add_row(row) + + def _create_dialog( + self, + picker_type: UiObjectPicker.UiObjectPickerObjectPickerType=UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT, + sim_info: SimInfo=None, + categories: Iterator[CommonDialogObjectOptionCategory]=(), + min_selectable: int=1, + max_selectable: int=1, + sort_rows: bool=False + ) -> Union[UiObjectPicker, None]: + try: + from collections import namedtuple + object_category_type = namedtuple('object_category_type', ('object_category', 'icon', 'category_name')) + object_categories = list() + for category in tuple(categories): + object_categories.append(object_category_type(category.object_category, lambda *_, **__: IconInfoData(icon_resource=CommonIconUtils._load_icon(category.icon)), CommonLocalizationUtils.create_localized_string(category.category_name))) + + if len(object_categories) > 0: + self.log.debug('Building dialog with categories.') + return CommonUiObjectCategoryPicker.TunableFactory().default( + sim_info or CommonSimUtils.get_active_sim_info(), + text=lambda *_, **__: self.description, + title=lambda *_, **__: self.title, + picker_type=picker_type, + use_dropdown_filter=True, + is_sortable=sort_rows, + object_categories=tuple(object_categories), + min_selectable=min_selectable, + max_selectable=max_selectable + ) + else: + self.log.debug('Building dialog without categories.') + return UiObjectPicker.TunableFactory().default( + sim_info or CommonSimUtils.get_active_sim_info(), + text=lambda *_, **__: self.description, + title=lambda *_, **__: self.title, + picker_type=picker_type, + is_sortable=sort_rows, + min_selectable=min_selectable, + max_selectable=max_selectable + ) + except Exception as ex: + self.log.error('_create_dialog', exception=ex) + return None + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_testing.show_choose_object_dialog', + 'Show an example of CommonChooseObjectDialog.' +) +def _common_testing_show_choose_object_dialog(output: CommonConsoleCommandOutput): + output('Showing test choose object dialog.') + + def _on_chosen(choice: str, outcome: CommonChoiceOutcome): + output('Chose {} with result: {}.'.format(pformat(choice), pformat(outcome))) + + # 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) + output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/choose_objects_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/choose_objects_dialog.py new file mode 100644 index 0000000..41a17f9 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/choose_objects_dialog.py @@ -0,0 +1,434 @@ +""" +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 +""" +from typing import Tuple, Any, Callable, Union, Iterator + +from pprint import pformat +from protocolbuffers.Localization_pb2 import LocalizedString +from sims.sim_info import SimInfo +from sims4communitylib.dialogs.choose_object_dialog import CommonChooseObjectDialog +from sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome +from sims4communitylib.dialogs.common_dialog_navigation_button_tag import CommonDialogNavigationButtonTag +from sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_option_category import \ + CommonDialogObjectOptionCategory +from sims4communitylib.dialogs.utils.common_dialog_utils import CommonDialogUtils +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from ui.ui_dialog_picker import UiObjectPicker, ObjectPickerRow + + +class CommonChooseObjectsDialog(CommonChooseObjectDialog): + """CommonChooseObjectsDialog(\ + title_identifier,\ + description_identifier,\ + choices,\ + title_tokens=(),\ + description_tokens=(),\ + per_page=25,\ + mod_identity=None,\ + required_tooltip=None,\ + required_tooltip_tokens=()\ + ) + + Create a dialog that prompts the player to choose multiple objects. + + .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_choose_objects_dialog` in the in-game console. + + .. highlight:: python + .. code-block:: python + + def _common_testing_show_choose_objects_dialog(): + + def _on_chosen(choices: Tuple[str], outcome: CommonChoiceOutcome): + 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' + ), + 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 = CommonChooseObjectsDialog( + 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, min_selectable=1, max_selectable=2) + + :param title_identifier: The title to display in the dialog. + :type title_identifier: Union[int, str, LocalizedString, CommonStringId] + :param description_identifier: The description to display in the dialog. + :type description_identifier: Union[int, str, LocalizedString, CommonStringId] + :param choices: The choices that can be chosen. + :type choices: Iterator[ObjectPickerRow] + :param title_tokens: Tokens to format into the title. + :type title_tokens: Iterator[Any], optional + :param description_tokens: Tokens to format into the description. + :type description_tokens: Iterator[Any], optional + :param per_page: The number of rows to display per page. If the number of rows (including rows added after creation) exceeds this value, pagination will be added. + :type per_page: int + :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. + :type mod_identity: CommonModIdentity, optional + :param required_tooltip: If provided, this text will display when the dialog requires at least one choice and a choice has not been made. Default is None. + :type required_tooltip: Union[int, str, LocalizedString, CommonStringId], optional + :param required_tooltip_tokens: Tokens to format into the required tooltip. Default is an empty collection. + :type required_tooltip_tokens: Iterator[Any], optional + """ + def __init__( + self, + title_identifier: Union[int, str, LocalizedString, CommonStringId], + description_identifier: Union[int, str, LocalizedString, CommonStringId], + choices: Iterator[ObjectPickerRow], + title_tokens: Iterator[Any]=(), + description_tokens: Iterator[Any]=(), + per_page: int=25, + mod_identity: CommonModIdentity=None, + required_tooltip: Union[int, str, LocalizedString, CommonStringId]=None, + required_tooltip_tokens: Iterator[Any]=() + ): + super().__init__( + title_identifier, + description_identifier, + choices, + title_tokens=title_tokens, + description_tokens=description_tokens, + mod_identity=mod_identity, + required_tooltip=required_tooltip, + required_tooltip_tokens=required_tooltip_tokens + ) + if per_page <= 0: + raise AssertionError('\'per_page\' must be greater than zero.') + self._per_page = per_page + self._always_visible_rows = tuple() + self._current_page = 1 + + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + return 's4cl_choose_object_dialog' + + @property + def current_page(self) -> int: + """Retrieve the current page. + + :return: A number indicating the current page. + :rtype: int + """ + return self._current_page + + # noinspection PyMissingOrEmptyDocstring + @property + def rows(self) -> Tuple[ObjectPickerRow]: + result: Tuple[ObjectPickerRow] = super().rows + return result + + @property + def always_visible_rows(self) -> Tuple[ObjectPickerRow]: + """A collection of rows that will always appear in the dialog no matter which page. + + .. note:: These rows are added to the dialog before the normal rows are added to the dialog. + + :return: A collection of rows added to the dialog that will always appear. + :rtype: Tuple[ObjectPickerRow] + """ + return self._always_visible_rows + + # noinspection PyMissingOrEmptyDocstring + def add_row(self, choice: ObjectPickerRow, *_, always_visible: bool=False, **__): + """add_row(row, *_, always_on_visible=False, **__) + + Add a row to the dialog. + + :param choice: The row to add. + :type choice: ObjectPickerRow + :param always_visible: If set to True, the row will always appear in the dialog no matter which page. If False, the row will act as normal. + :type always_visible: bool, optional + """ + if not always_visible: + super().add_row(choice, *_, **__) + return + try: + self._always_visible_rows += (choice,) + except Exception as ex: + self.log.error('An error occurred while running \'{}\''.format(CommonChooseObjectsDialog.add_row.__name__), exception=ex) + + def show( + self, + on_chosen: Callable[[Tuple[Any], CommonChoiceOutcome], Any]=CommonFunctionUtils.noop, + picker_type: UiObjectPicker.UiObjectPickerObjectPickerType=UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT, + page: int=1, + sim_info: SimInfo=None, + categories: Iterator[CommonDialogObjectOptionCategory]=(), + include_pagination: bool=True, + min_selectable: int=1, + max_selectable: int=1, + sort_rows: bool=False + ): + """show(\ + on_chosen=CommonFunctionUtils.noop,\ + picker_type=UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT,\ + page=1,\ + sim_info=None,\ + categories=(),\ + min_selectable=1,\ + max_selectable=1,\ + sort_rows=True\ + ) + + Show the dialog and invoke the callbacks upon the player choosing objects. + + :param on_chosen: A callback invoked upon the player choosing something from the list. Default is CommonFunctionUtils.noop. + :type on_chosen: Callable[[Tuple[Any], CommonChoiceOutcome], optional + :param picker_type: The layout of the dialog. Default is UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT. + :type picker_type: UiObjectPicker.UiObjectPickerObjectPickerType, optional + :param page: The page to display. Ignored if there is only one page of choices. Default is 1. + :type page: int, optional + :param sim_info: The Sim that will appear in the dialog image. The default Sim is the Active Sim. Default is None. + :type sim_info: SimInfo, optional + :param categories: A collection of categories to display in the dialog. They will appear in a drop down above the rows. Default is an empty collection. + :type categories: Iterator[CommonDialogObjectOptionCategory], optional + :param include_pagination: If True, pagination will be applied. If False, no pagination will be applied. Default is True. + :type include_pagination: bool, optional + :param min_selectable: The minimum number of items required to be selected. Default is 1. + :type min_selectable: int, optional + :param max_selectable: The maximum number of items allowed to be selected. Default is 1. + :type max_selectable: int, optional + :param sort_rows: If True, rows will be sorted by display name, with the selected rows on top. If False, rows will not be sorted. Default is False. + :type sort_rows: bool, optional + """ + self._current_page = page + try: + return self._show( + on_chosen=on_chosen, + picker_type=picker_type, + page=page, + sim_info=sim_info, + categories=categories, + include_pagination=include_pagination, + min_selectable=min_selectable, + max_selectable=max_selectable, + sort_rows=sort_rows + ) + except Exception as ex: + self.log.error('An error occurred while running \'{}\''.format(CommonChooseObjectsDialog.show.__name__), exception=ex) + + def _show( + self, + on_chosen: Callable[[Tuple[Any], CommonChoiceOutcome], bool]=CommonFunctionUtils.noop, + picker_type: UiObjectPicker.UiObjectPickerObjectPickerType=UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT, + page: int=1, + sim_info: SimInfo=None, + categories: Iterator[CommonDialogObjectOptionCategory]=(), + include_pagination: bool=True, + min_selectable: int=1, + max_selectable: int=1, + sort_rows: bool=False + ): + def _on_chosen(choices: Tuple[Any], outcome: CommonChoiceOutcome) -> bool: + try: + self.log.debug('Choices made {}.'.format(pformat(choices))) + if CommonDialogNavigationButtonTag.NEXT in choices: + self.log.debug('Next chosen.') + self.show( + on_chosen=on_chosen, + picker_type=picker_type, + page=page + 1, + sim_info=sim_info, + categories=categories, + min_selectable=min_selectable, + max_selectable=max_selectable + ) + return True + elif CommonDialogNavigationButtonTag.PREVIOUS in choices: + self.log.debug('Previous chosen.') + self.show( + on_chosen=on_chosen, + picker_type=picker_type, + page=page - 1, + sim_info=sim_info, + categories=categories, + min_selectable=min_selectable, + max_selectable=max_selectable + ) + return True + self.log.format_with_message('Choose Objects Choices made.', choices=pformat(choices)) + result = on_chosen(choices, outcome) + self.log.format_with_message('Finished handling choose objects _show._on_chosen.', result=result) + return result + except Exception as ex: + self.log.error('Error occurred on choosing a value.', exception=ex) + return False + + _dialog = self.build_dialog( + on_chosen=_on_chosen, + picker_type=picker_type, + page=page, + sim_info=sim_info, + categories=categories, + min_selectable=min_selectable, + max_selectable=max_selectable, + sort_rows=sort_rows + ) + self.log.debug('Showing dialog.') + _dialog.show_dialog() + + # noinspection PyMissingOrEmptyDocstring + def build_dialog( + self, + on_chosen: Callable[[Tuple[Any], CommonChoiceOutcome], bool]=CommonFunctionUtils.noop, + picker_type: UiObjectPicker.UiObjectPickerObjectPickerType=UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT, + page: int=1, + sim_info: SimInfo=None, + categories: Iterator[CommonDialogObjectOptionCategory]=(), + include_pagination: bool=True, + min_selectable: int=1, + max_selectable: int=1, + sort_rows: bool=False + ) -> Union[UiObjectPicker, None]: + self.log.format_with_message('Attempting to build dialog.', page=page, categories=categories) + + _dialog = self._create_dialog( + picker_type=picker_type, + categories=categories, + sim_info=sim_info, + min_selectable=min_selectable, + max_selectable=max_selectable, + sort_rows=sort_rows + ) + if _dialog is None: + self.log.error('_dialog was None for some reason.') + return + + if on_chosen is None: + raise ValueError('on_chosen was None.') + + if len(self.always_visible_rows) == 0 and len(self.rows) == 0: + raise AssertionError('No rows have been provided. Add rows to the dialog before attempting to display it.') + + def _on_chosen(dialog: UiObjectPicker) -> bool: + try: + if not dialog.accepted: + self.log.debug('Dialog cancelled.') + return on_chosen(tuple(), CommonChoiceOutcome.CANCEL) + self.log.debug('Choices not made.') + choices = CommonDialogUtils.get_chosen_items(dialog) + self.log.format_with_message('Choose Object Choice made.', choice=pformat(choices)) + result = on_chosen(choices, CommonChoiceOutcome.CHOICE_MADE) + self.log.format_with_message('Finished handling choose objects _build_dialog._on_chosen.', result=result) + return result + except Exception as ex: + self.log.error('Error occurred on choosing a value.', exception=ex) + return False + + if include_pagination: + self._setup_dialog_rows( + _dialog, + page=page, + categories=categories + ) + else: + self.log.debug('Adding always visible rows.') + for always_visible_rows in self.always_visible_rows: + _dialog.add_row(always_visible_rows) + self.log.debug('Adding rows.') + for row in self.rows: + _dialog.add_row(row) + + self.log.debug('Adding listener.') + _dialog.add_listener(_on_chosen) + return _dialog + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_testing.show_choose_objects_dialog', + 'Show an example of CommonChooseObjectsDialog.' +) +def _common_testing_show_choose_objects_dialog(output: CommonConsoleCommandOutput): + output('Showing test choose objects dialog.') + + def _on_chosen(choices: Tuple[str], outcome: CommonChoiceOutcome): + output('Chose {} with result: {}.'.format(pformat(choices), pformat(outcome))) + + # 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 = CommonChooseObjectsDialog( + 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, + min_selectable=1, + max_selectable=2 + ) + output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_choice_outcome.py b/Scripts/s4ap/sims4communitylib/dialogs/common_choice_outcome.py new file mode 100644 index 0000000..36410bf --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/common_choice_outcome.py @@ -0,0 +1,32 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonChoiceOutcome(CommonInt): + """The outcome of the player being given a choice. + + """ + CANCEL = 0 + CHOICE_MADE = 1 + ERROR = 2 + NEXT = 3 + PREVIOUS = 4 + + @staticmethod + def is_error_or_cancel(result: 'CommonChoiceOutcome') -> bool: + """is_error_or_cancel(result) + + Determine if an outcome is either :py:attr:`~ERROR` or :py:attr:`~CANCEL`. + + :param result: The result to check. + :type result: CommonChoiceOutcome + :return: True, if result is either an Error or Cancel. False, if not. + :rtype: bool + """ + return result == CommonChoiceOutcome.ERROR or result == CommonChoiceOutcome.CANCEL diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_choose_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/common_choose_dialog.py new file mode 100644 index 0000000..896ed4a --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/common_choose_dialog.py @@ -0,0 +1,102 @@ +""" +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 +""" +from abc import ABC +from typing import Tuple, Any, Union, Iterator +from protocolbuffers.Localization_pb2 import LocalizedString +from sims4communitylib.dialogs.common_dialog import CommonDialog +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from ui.ui_dialog_picker import BasePickerRow + + +class CommonChooseDialog(CommonDialog, ABC): + """CommonChooseDialog(\ + title_identifier,\ + description_identifier,\ + rows,\ + title_tokens=(),\ + description_tokens=(),\ + mod_identity=None,\ + required_tooltip=None,\ + required_tooltip_tokens=()\ + ) + + A dialog that prompts the player to choose something. + + :param title_identifier: The title to display in the dialog. + :type title_identifier: Union[int, str, LocalizedString, CommonStringId] + :param description_identifier: The description to display in the dialog. + :type description_identifier: Union[int, str, LocalizedString, CommonStringId] + :param rows: The rows to display in the dialog. + :type rows: Iterator[BasePickerRow] + :param title_tokens: Tokens to format into the title. Default is an empty collection. + :type title_tokens: Iterator[Any], optional + :param description_tokens: Tokens to format into the description. Default is an empty collection. + :type description_tokens: Iterator[Any], optional + :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. Default is None. + :type mod_identity: CommonModIdentity, optional + :param required_tooltip: If provided, this text will display when the dialog requires at least one choice and a choice has not been made. Default is None. + :type required_tooltip: Union[int, str, LocalizedString, CommonStringId], optional + :param required_tooltip_tokens: Tokens to format into the required tooltip. Default is an empty collection. + :type required_tooltip_tokens: Iterator[Any], optional + """ + def __init__( + self, + title_identifier: Union[int, str, LocalizedString, CommonStringId], + description_identifier: Union[int, str, LocalizedString, CommonStringId], + rows: Iterator[BasePickerRow], + title_tokens: Iterator[Any]=(), + description_tokens: Iterator[Any]=(), + mod_identity: CommonModIdentity=None, + required_tooltip: Union[int, str, LocalizedString, CommonStringId]=None, + required_tooltip_tokens: Iterator[Any]=() + ): + super().__init__( + title_identifier, + description_identifier, + title_tokens=title_tokens, + description_tokens=description_tokens, + mod_identity=mod_identity + ) + self._rows = tuple(rows) + if required_tooltip is None: + self._required_tooltip = None + else: + self._required_tooltip = CommonLocalizationUtils.create_localized_string(required_tooltip, tokens=tuple(required_tooltip_tokens)) + + @property + def required_tooltip(self) -> Union[LocalizedString, None]: + """A tooltip that will display when the dialog requires at least one choice and a choice has not been made. + + :return: A localized string or None if no value provided. + :rtype: Union[LocalizedString, None] + """ + return self._required_tooltip + + @property + def rows(self) -> Tuple[BasePickerRow]: + """The rows to display in the dialog. + + :return: A collection of rows added to the dialog. + :rtype: Tuple[BasePickerRow] + """ + return self._rows + + def add_row(self, row: BasePickerRow, *_, **__): + """add_row(row, *_, **__) + + Add a row to the dialog. + + :param row: The row to add. + :type row: BasePickerRow + """ + try: + self._rows += (row,) + except Exception as ex: + self.log.error('add_row', exception=ex) diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_choose_outfit_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/common_choose_outfit_dialog.py new file mode 100644 index 0000000..63ae20d --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/common_choose_outfit_dialog.py @@ -0,0 +1,372 @@ +""" +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 +""" +from typing import Tuple, Any, Callable, Union, Iterator, List + +from pprint import pformat + +from protocolbuffers.Localization_pb2 import LocalizedString +from sims.outfits.outfit_enums import OutfitCategory, HIDDEN_OUTFIT_CATEGORIES +from sims.sim_info import SimInfo +from sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome +from sims4communitylib.dialogs.common_choose_dialog import CommonChooseDialog +from sims4communitylib.dialogs.utils.common_dialog_utils import CommonDialogUtils +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from ui.ui_dialog_picker import OutfitPickerRow, UiOutfitPicker + + +class CommonChooseOutfitDialog(CommonChooseDialog): + """CommonChooseOutfitDialog(\ + mod_identity,\ + title_identifier,\ + description_identifier,\ + title_tokens=(),\ + description_tokens=(),\ + required_tooltip=None,\ + required_tooltip_tokens=()\ + ) + + Create a dialog that allows the player to choose an outfit from a Sims currently available outfits. + + .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_choose_outfit_dialog` in the in-game console. + + .. highlight:: python + .. code-block:: python + + def _common_testing_show_choose_outfit_dialog(): + def _on_chosen(choice: Tuple[OutfitCategory, int], outcome: CommonChoiceOutcome): + output('Chose {} with result: {}.'.format(pformat(choice), pformat(outcome))) + + try: + sim_info = CommonSimUtils.get_active_sim_info() + # 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=(sim_info,), text_color=CommonLocalizedStringColor.BLUE),) + from sims4communitylib.utils.common_icon_utils import CommonIconUtils + dialog = CommonChooseOutfitDialog( + ModInfo.get_identity(), + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + title_tokens=title_tokens, + description_tokens=description_tokens + ) + outfit_list = (OutfitCategory.EVERYDAY, 0) + dialog.show(sim_info, outfit_list=outfit_list, on_chosen=_on_chosen) + 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.') + + :param title_identifier: The title to display in the dialog. + :type title_identifier: Union[int, str, LocalizedString, CommonStringId] + :param description_identifier: The description to display in the dialog. + :type description_identifier: Union[int, str, LocalizedString, CommonStringId] + :param title_tokens: Tokens to format into the title. + :type title_tokens: Iterator[Any], optional + :param description_tokens: Tokens to format into the description. + :type description_tokens: Iterator[Any], optional + :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. + :type mod_identity: CommonModIdentity, optional + :param required_tooltip: If provided, this text will display when the dialog requires at least one choice and a choice has not been made. Default is None. + :type required_tooltip: Union[int, str, LocalizedString, CommonStringId], optional + :param required_tooltip_tokens: Tokens to format into the required tooltip. Default is an empty collection. + :type required_tooltip_tokens: Iterator[Any], optional + """ + + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + return 'common_choose_outfit_dialog' + + def __init__( + self, + mod_identity: CommonModIdentity, + title_identifier: Union[int, str, LocalizedString, CommonStringId], + description_identifier: Union[int, str, LocalizedString, CommonStringId], + title_tokens: Iterator[Any]=(), + description_tokens: Iterator[Any]=(), + required_tooltip: Union[int, str, LocalizedString, CommonStringId]=None, + required_tooltip_tokens: Iterator[Any]=() + ): + super().__init__( + title_identifier, + description_identifier, + tuple(), + title_tokens=title_tokens, + description_tokens=description_tokens, + mod_identity=mod_identity, + required_tooltip=required_tooltip, + required_tooltip_tokens=required_tooltip_tokens + ) + + # noinspection PyMissingOrEmptyDocstring + @property + def rows(self) -> Tuple[OutfitPickerRow]: + result: Tuple[OutfitPickerRow] = super().rows + return result + + # noinspection PyMissingOrEmptyDocstring + def add_row(self, choice: OutfitPickerRow, *_, **__): + """add_row(row, *_, **__) + + Add a row to the dialog. + + :param choice: The row to add. + :type choice: OutfitPickerRow + """ + super().add_row(choice, *_, **__) + + def show( + self, + sim_info: SimInfo, + outfit_list: Iterator[Tuple[OutfitCategory, int]]=(), + thumbnail_type: UiOutfitPicker._OutftiPickerThumbnailType=UiOutfitPicker._OutftiPickerThumbnailType.SIM_INFO, + on_chosen: Callable[[Union[Tuple[OutfitCategory, int], None], CommonChoiceOutcome], None]=CommonFunctionUtils.noop, + exclude_outfit_categories: Tuple[OutfitCategory]=(OutfitCategory.CURRENT_OUTFIT, OutfitCategory.BATHING, *HIDDEN_OUTFIT_CATEGORIES), + show_filter: bool=True, + allow_choose_current_outfit: bool=False + ): + """show(\ + sim_info, + outfit_list=(),\ + thumbnail_type=UiOutfitPicker._OutftiPickerThumbnailType.SIM_INFO,\ + on_chosen=CommonFunctionUtils.noop,\ + exclude_outfit_categories=(OutfitCategory.CURRENT_OUTFIT, OutfitCategory.BATHING, OutfitCategory.SPECIAL, OutfitCategory.CAREER, OutfitCategory.SITUATION, OutfitCategory.BATUU),\ + show_filter=True,\ + allow_choose_current_outfit=False\ + ) + + Show the dialog and invoke the callbacks upon the player making a choice. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param outfit_list: A collection of outfits. Default is all Outfits. + :type outfit_list: Iterator[Tuple[OutfitCategory, int]], optional + :param thumbnail_type: Determines how the thumbnails of the outfits should be displayed. Default is UiOutfitPicker._OutftiPickerThumbnailType.SIM_INFO + :type thumbnail_type: UiObjectPicker._OutftiPickerThumbnailType, optional + :param on_chosen: A callback invoked upon the player choosing something from the list. Default is CommonFunctionUtils.noop. + :type on_chosen: Callable[[Union[Tuple[OutfitCategory, int], None], CommonChoiceOutcome], None], optional + :param exclude_outfit_categories: A collection of Outfit Categories to exclude from display. Default is CURRENT_OUTFIT, BATHING, SPECIAL, CAREER, SITUATION, BATUU + :type exclude_outfit_categories: Tuple[OutfitCategory], optional + :param show_filter: Whether or not to show the Outfit Category filters in the dialogue. Default is True. + :type show_filter: bool, optional + :param allow_choose_current_outfit: If True, then the Outfit that is currently being worn will be allowed to be chosen. If False, the current outfit cannot be chosen. Default is False. + :type allow_choose_current_outfit: bool, optional + """ + try: + outfit_list = self._setup_outfit_list(outfit_list, exclude_outfit_categories) + return self._show( + sim_info, + outfit_list=outfit_list, + thumbnail_type=thumbnail_type, + on_chosen=on_chosen, + show_filter=show_filter, + allow_choose_current_outfit=allow_choose_current_outfit, + ) + except Exception as ex: + self.log.error('An error occurred while running \'{}\''.format(self.show.__name__), exception=ex) + + def _setup_outfit_list( + self, + outfit_list: Iterator[Tuple[OutfitCategory, int]], + exclude_outfit_categories: Tuple[OutfitCategory] + ) -> Tuple[Tuple[OutfitCategory, int]]: + if outfit_list: + return tuple(outfit_list) + outfit_list: List[Tuple[OutfitCategory, int]] = list() + for outfit_category in OutfitCategory.values: + if outfit_category in exclude_outfit_categories: + continue + outfit_index = 0 + while outfit_index < CommonOutfitUtils.get_maximum_number_of_outfits_for_category(outfit_category): + outfit_list.append((outfit_category, outfit_index)) + outfit_index += 1 + return tuple(outfit_list) + + def _show( + self, + sim_info: SimInfo, + outfit_list: Iterator[Tuple[OutfitCategory, int]]=(), + thumbnail_type: UiOutfitPicker._OutftiPickerThumbnailType=UiOutfitPicker._OutftiPickerThumbnailType.SIM_INFO, + on_chosen: Callable[[Union[Tuple[OutfitCategory, int], None], CommonChoiceOutcome], None]=CommonFunctionUtils.noop, + show_filter: bool=True, + allow_choose_current_outfit: bool=False + ): + def _on_chosen(choice: Tuple[OutfitCategory, int], outcome: CommonChoiceOutcome) -> None: + try: + self.log.format_with_message('Choose Outfit Choice made.', choice=choice) + on_chosen(choice, outcome) + self.log.debug('Finished handling choose object _show.') + return + except Exception as ex: + self.log.error('Error occurred on choosing a value.', exception=ex) + + _dialog = self.build_dialog( + sim_info, + outfit_list=outfit_list, + thumbnail_type=thumbnail_type, + on_chosen=_on_chosen, + show_filter=show_filter, + allow_choose_current_outfit=allow_choose_current_outfit + ) + self.log.debug('Showing dialog.') + _dialog.show_dialog() + + # noinspection PyMissingOrEmptyDocstring + def build_dialog( + self, + sim_info: SimInfo, + outfit_list: Iterator[Tuple[OutfitCategory, int]]=(), + thumbnail_type: UiOutfitPicker._OutftiPickerThumbnailType=UiOutfitPicker._OutftiPickerThumbnailType.SIM_INFO, + on_chosen: Callable[[Union[Tuple[OutfitCategory, int], None], CommonChoiceOutcome], None]=CommonFunctionUtils.noop, + show_filter: bool=True, + allow_choose_current_outfit: bool=False + ) -> Union[UiOutfitPicker, None]: + self.log.format_with_message( + 'Attempting to build dialog.', + sim=sim_info, + outfit_list=outfit_list, + thumbnail_type=thumbnail_type + ) + + _dialog = self._create_dialog( + sim_info, + outfit_list=outfit_list, + thumbnail_type=thumbnail_type, + show_filter=show_filter + ) + if _dialog is None: + self.log.error('_dialog was None for some reason.') + return + + if on_chosen is None: + raise ValueError('on_chosen was None.') + + def _on_chosen(dialog: UiOutfitPicker) -> None: + try: + self.log.format_with_message('Choice made.', picked_results=dialog.picked_results) + if not dialog.accepted: + self.log.debug('Dialog cancelled.') + on_chosen(None, CommonChoiceOutcome.CANCEL) + return + self.log.format_with_message('Dialog accepted, checking if choices were made.') + choice = CommonDialogUtils.get_chosen_item(dialog) + self.log.format_with_message('Outfit choice made.', choice=choice) + on_chosen(choice, CommonChoiceOutcome.CHOICE_MADE) + self.log.debug('Finished handling outfit items _on_chosen.') + return + except Exception as ex: + self.log.error('Error occurred on choosing a value.', exception=ex) + + self._setup_dialog_rows( + sim_info, + _dialog, + outfit_list=outfit_list, + allow_choose_current_outfit=allow_choose_current_outfit + ) + + self.log.debug('Adding listener.') + _dialog.add_listener(_on_chosen) + return _dialog + + def _setup_dialog_rows( + self, + sim_info: SimInfo, + _dialog: UiOutfitPicker, + outfit_list: Iterator[Tuple[OutfitCategory, int]]=(), + allow_choose_current_outfit: bool=False + ): + self.log.debug('Adding rows.') + sim_id = CommonSimUtils.get_sim_id(sim_info) + added_rows = False + current_outfit = CommonOutfitUtils.get_current_outfit(sim_info) + for (outfit_category, outfit_index) in outfit_list: + # noinspection PyTypeChecker + if not CommonOutfitUtils.has_outfit(sim_info, (outfit_category, outfit_index)) and not CommonOutfitUtils.has_outfit(sim_info, (int(outfit_category), outfit_index)): + self.log.format_with_message('Sim does not have outfit.', sim=sim_info, outfit_category_and_index=(outfit_category, outfit_index)) + continue + added_rows = True + _dialog.add_row( + OutfitPickerRow( + sim_id, + outfit_category, + outfit_index, + # For some reason the Outfit Picker uses "is_enable" to determine which outfit is currently selected, instead of the expected "is_selected". + is_enable=(outfit_category, outfit_index) != current_outfit if not allow_choose_current_outfit else True, + tag=(outfit_category, outfit_index) + ) + ) + + for row in self.rows: + _dialog.add_row(row) + + if not added_rows and len(self.rows) == 0: + raise AssertionError('No rows have been provided. Add rows to the dialog before attempting to display it.') + + def _create_dialog( + self, + target_sim_info: SimInfo, + outfit_list: Iterator[Tuple[OutfitCategory, int]], + thumbnail_type: UiOutfitPicker._OutftiPickerThumbnailType=UiOutfitPicker._OutftiPickerThumbnailType.SIM_INFO, + show_filter: bool=True + ) -> Union[UiOutfitPicker, None]: + try: + outfit_categories: List[OutfitCategory] = list() + for (outfit_category, outfit_index) in outfit_list: + if outfit_category not in outfit_categories: + outfit_categories.append(outfit_category) + + dialog = UiOutfitPicker.TunableFactory()\ + .default( + target_sim_info or CommonSimUtils.get_active_sim_info(), + text=lambda *_, **__: self.description, + title=lambda *_, **__: self.title, + outfit_categories=set([outfit[0] for outfit in outfit_list]), + thumbnail_type=thumbnail_type, + show_filter=show_filter + ) + dialog.outfit_category_filters = outfit_categories + return dialog + except Exception as ex: + self.log.error('_create_dialog', exception=ex) + return None + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_testing.show_choose_outfit_dialog', + 'Show an example of CommonChooseResponseDialog.' +) +def _common_testing_show_choose_outfit_dialog(output: CommonConsoleCommandOutput): + output('Showing test choose outfit dialog.') + + def _on_chosen(choice: Tuple[OutfitCategory, int], outcome: CommonChoiceOutcome): + output('Chose {} with result: {}.'.format(pformat(choice), pformat(outcome))) + + sim_info = CommonSimUtils.get_active_sim_info() + # 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=(sim_info,), text_color=CommonLocalizedStringColor.BLUE),) + dialog = CommonChooseOutfitDialog( + ModInfo.get_identity(), + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + title_tokens=title_tokens, + description_tokens=description_tokens + ) + outfit_list = ((OutfitCategory.EVERYDAY, 0),) + dialog.show(sim_info, outfit_list=outfit_list, on_chosen=_on_chosen) + output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_choose_response_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/common_choose_response_dialog.py new file mode 100644 index 0000000..b512352 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/common_choose_response_dialog.py @@ -0,0 +1,513 @@ +""" +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 +""" +import math +import os + +from typing import Tuple, Any, Callable, Union, Iterator + +from pprint import pformat + +from event_testing.resolver import DoubleSimResolver +from protocolbuffers.Localization_pb2 import LocalizedString +from sims.sim_info import SimInfo +from sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome +from sims4communitylib.dialogs.common_dialog import CommonDialog +from sims4communitylib.dialogs.common_dialog_navigation_button_tag import CommonDialogNavigationButtonTag +from sims4communitylib.dialogs.common_ui_dialog_response import CommonUiDialogResponse +from sims4communitylib.dialogs.common_ui_response_dialog import CommonUiResponseDialog +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from ui.ui_dialog import UiDialogOption, ButtonType + +ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' + + +class CommonChooseResponseDialog(CommonDialog): + """CommonChooseResponseDialog(\ + mod_identity,\ + title_identifier,\ + description_identifier,\ + responses,\ + title_tokens=(),\ + description_tokens=(),\ + next_button_text=CommonStringId.NEXT,\ + previous_button_text=CommonStringId.PREVIOUS,\ + ) + + Create a dialog that prompts the player to choose a response. + + .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_choose_response_dialog` in the in-game console. + + .. highlight:: python + .. code-block:: python + + def _common_testing_show_choose_response_dialog(): + + def _on_chosen(choice: str, outcome: CommonChoiceOutcome): + pass + + responses: Tuple[CommonUiDialogResponse] = ( + CommonUiDialogResponse( + 1, + 'Value 1', + text=CommonLocalizationUtils.create_localized_string(CommonStringId.TESTING_TEST_BUTTON_ONE) + ), + CommonUiDialogResponse( + 2, + 'Value 2', + text=CommonLocalizationUtils.create_localized_string(CommonStringId.TESTING_TEST_BUTTON_TWO) + ), + CommonUiDialogResponse( + 3, + 'Value 3', + text=CommonLocalizationUtils.create_localized_string('Test Button 3') + ) + ) + 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),) + + active_sim_info = CommonSimUtils.get_active_sim_info() + dialog = CommonChooseResponseDialog( + ModInfo.get_identity(), + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + responses, + title_tokens=title_tokens, + description_tokens=description_tokens, + per_page=2 + ) + dialog.show( + on_chosen=_on_chosen, + sim_info=active_sim_info, + include_previous_button=False + ) + + :param title_identifier: The title to display in the dialog. + :type title_identifier: Union[int, str, LocalizedString, CommonStringId] + :param description_identifier: The description to display in the dialog. + :type description_identifier: Union[int, str, LocalizedString, CommonStringId] + :param responses: The choices that can be chosen. + :type responses: Iterator[CommonUiDialogResponse] + :param title_tokens: Tokens to format into the title. Default is no tokens. + :type title_tokens: Iterator[Any], optional + :param description_tokens: Tokens to format into the description. Default is no tokens. + :type description_tokens: Iterator[Any], optional + :param next_button_text: The text the Next button will display, if the Next button is added. Default is Next. + :type next_button_text: Union[int, str, LocalizedString, CommonStringId], optional + :param previous_button_text: The text the Previous button will display, if the Previous button is added. Default is Previous. + :type previous_button_text: Union[int, str, LocalizedString, CommonStringId], optional + :param per_page: The number of responses to display per page of the dialog. Default is 10. + :type per_page: int, optional + :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. + :type mod_identity: CommonModIdentity, optional + """ + # If on Read The Docs, create fake versions of extended objects to fix the error of inheriting from multiple MockObjects. + if ON_RTD: + _NEXT_BUTTON_ID = 10001 + _PREVIOUS_BUTTON_ID = 10002 + + if not ON_RTD: + _NEXT_BUTTON_ID: int = int(ButtonType.DIALOG_RESPONSE_OK) + _PREVIOUS_BUTTON_ID: int = int(ButtonType.DIALOG_RESPONSE_CANCEL) + + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + return 's4cl_choose_response_dialog' + + def __init__( + self, + mod_identity: CommonModIdentity, + title_identifier: Union[int, str, LocalizedString, CommonStringId], + description_identifier: Union[int, str, LocalizedString, CommonStringId], + responses: Iterator[CommonUiDialogResponse], + title_tokens: Iterator[Any]=(), + description_tokens: Iterator[Any]=(), + next_button_text: Union[int, str, LocalizedString, CommonStringId]=CommonStringId.NEXT, + previous_button_text: Union[int, str, LocalizedString, CommonStringId]=CommonStringId.PREVIOUS, + per_page: int=10 + ): + super().__init__( + title_identifier, + description_identifier, + title_tokens=title_tokens, + description_tokens=description_tokens, + mod_identity=mod_identity + ) + if per_page <= 0: + raise AssertionError('\'per_page\' must be greater than zero.') + self._responses = tuple(responses) + self._per_page = per_page + self._current_page = 1 + self._next_button_text = CommonLocalizationUtils.create_localized_string(next_button_text) + self._previous_button_text = CommonLocalizationUtils.create_localized_string(previous_button_text) + self._always_visible_responses = tuple() + + @property + def current_page(self) -> int: + """The current page shown of the dialog.""" + return self._current_page + + @property + def responses(self) -> Tuple[CommonUiDialogResponse]: + """The responses to display in the dialog.""" + return self._responses + + @property + def always_visible_responses(self) -> Tuple[CommonUiDialogResponse]: + """A collection of responses that will always appear in the dialog no matter which page. + + .. note:: These responses are added to the dialog before the normal responses are added to the dialog. + + :return: A collection of responses added to the dialog that will always appear. + :rtype: Tuple[CommonUiDialogResponse] + """ + return self._always_visible_responses + + def add_response(self, response: CommonUiDialogResponse, *_, always_visible: bool=False, **__): + """add_response(response, *_, always_visible=False, **__) + + Add a response to the dialog. + + :param response: The response to add. + :type response: CommonUiDialogResponse + :param always_visible: If set to True, the response will always appear in the dialog no matter which page. If False, the response will act as normal. Default is False. + :type always_visible: bool, optional + """ + if not always_visible: + self._responses += (response,) + return + try: + self._always_visible_responses += (response,) + except Exception as ex: + self.log.error('An error occurred while running \'{}\''.format(self.add_response.__name__), exception=ex) + + def show( + self, + sim_info: SimInfo=None, + target_sim_info: SimInfo=None, + on_chosen: Callable[[Any, CommonChoiceOutcome], None]=CommonFunctionUtils.noop, + on_previous: Callable[[], None]=CommonFunctionUtils.noop, + dialog_options: UiDialogOption=0, + include_previous_button: bool=True, + include_pagination: bool=True, + page: int=1 + ): + """show(\ + sim_info=None,\ + target_sim_info=None,\ + on_chosen=CommonFunctionUtils.noop,\ + on_previous=CommonFunctionUtils.noop,\ + dialog_options=0,\ + include_previous_button=True,\ + include_pagination=True,\ + page=1\ + ) + + Show the dialog and invoke the callbacks upon the player making a choice. + + :param sim_info: The Sim that will appear in the dialog image. The default Sim is the Active Sim. Default is None. + :type sim_info: SimInfo, optional + :param target_sim_info: If provided, the dialog will appear as if it were a conversation instead of the normal view. Default is None. + :type target_sim_info: SimInfo, optional + :param on_chosen: A callback invoked upon the player choosing something from the list. Default is CommonFunctionUtils.noop. + :type on_chosen: Callable[[Any, CommonChoiceOutcome], optional + :param on_previous: A callback performed when the previous response is chosen. Default is no operation. + :type on_previous: Callable[[], None], optional + :param dialog_options: Options to apply to the dialog, such as removing the close button. Default is no options. + :type dialog_options: UiDialogOption, optional + :param include_previous_button: If True, the Previous button will be appended to the end of the dialog, if False, the Previous button will not be shown unless the current page is greater than 1. Default is True. + :type include_previous_button: bool, optional + :param include_pagination: If True, pagination will be applied. If False, no pagination will be applied. Default is True. The `include_previous_button` argument will override this setting! + :type include_pagination: bool, optional + :param page: The page to show the dialog on. Default is the first page. + :type page: int, optional + """ + self._current_page = page + try: + return self._show( + sim_info=sim_info, + target_sim_info=target_sim_info, + on_chosen=on_chosen, + on_previous=on_previous, + dialog_options=dialog_options, + include_previous_button=include_previous_button, + include_pagination=include_pagination, + page=page + ) + except Exception as ex: + self.log.error('An error occurred while running \'{}\''.format(self.__class__.show.__name__), exception=ex) + + def _show( + self, + sim_info: SimInfo=None, + target_sim_info: SimInfo=None, + on_chosen: Callable[[Any, CommonChoiceOutcome], None]=CommonFunctionUtils.noop, + on_previous: Callable[[], None]=CommonFunctionUtils.noop, + dialog_options: UiDialogOption=0, + include_previous_button: bool=True, + include_pagination: bool=True, + page: int=1 + ): + def _on_chosen(choice: Any, outcome: CommonChoiceOutcome) -> None: + try: + self.log.debug('Choice made.') + if choice == CommonDialogNavigationButtonTag.NEXT: + self.log.debug('Next chosen.') + self.show(on_chosen=on_chosen, on_previous=on_previous, dialog_options=dialog_options, include_previous_button=include_previous_button, sim_info=sim_info, target_sim_info=target_sim_info, page=page + 1) + return + elif choice == CommonDialogNavigationButtonTag.PREVIOUS: + self.log.debug('Previous chosen.') + if page == 1: + on_previous() + else: + self.show(on_chosen=on_chosen, on_previous=on_previous, dialog_options=dialog_options, include_previous_button=include_previous_button, sim_info=sim_info, target_sim_info=target_sim_info, page=page - 1) + return + self.log.format_with_message('Choice made.', choice=choice) + on_chosen(choice, outcome) + self.log.debug('Finished handling _show.') + except Exception as ex: + self.log.error('Error occurred on choosing a value.', exception=ex) + + _dialog = self.build_dialog( + sim_info=sim_info, + target_sim_info=target_sim_info, + on_chosen=_on_chosen, + on_previous=on_previous, + dialog_options=dialog_options, + include_previous_button=include_previous_button, + include_pagination=include_pagination, + page=page + ) + if _dialog is None: + self.log.error('An error occurred when building the dialog!') + return + self.log.debug('Showing dialog.') + _dialog.show_dialog() + + def build_dialog( + self, + sim_info: SimInfo=None, + target_sim_info: SimInfo=None, + on_chosen: Callable[[Any, CommonChoiceOutcome], None]=CommonFunctionUtils.noop, + on_previous: Callable[[], None]=CommonFunctionUtils.noop, + dialog_options: Union[UiDialogOption, int]=0, + include_previous_button: bool=True, + include_pagination: bool=True, + page: int=1 + ) -> Union[CommonUiResponseDialog, None]: + """build_dialog(\ + sim_info=None,\ + target_sim_info=None,\ + on_chosen=CommonFunctionUtils.noop,\ + on_previous=CommonFunctionUtils.noop,\ + dialog_options=0,\ + include_previous_button=True,\ + include_pagination=True,\ + page=1\ + ) + + Build the dialog. + + :param sim_info: A Sim that will appear in the top left image when the dialog is shown. If set to None, the active Sim will be used. Default is None. + :type sim_info: SimInfo, optional + :param target_sim_info: If provided, the dialog will appear as if it were a conversation instead of the normal view. Default is None. + :type target_sim_info: SimInfo, optional + :param on_chosen: A callback performed when a choice is made. Default is no operation. + :type on_chosen: Callable[[Any, CommonChoiceOutcome], None], optional + :param on_previous: A callback performed when the Previous response is chosen. Default is no operation. + :type on_previous: Callable[[], None], optional + :param dialog_options: Display options for the dialog, such as hiding the close button. Default is no display options. + :type dialog_options: UiDialogOption, optional + :param include_previous_button: If True, the Previous button will be appended to the end of the dialog. Default is True. + :type include_previous_button: bool, optional + :param include_pagination: If True, pagination will be applied. If False, no pagination will be applied. Default is True. The `include_previous_button` argument will override this setting! + :type include_pagination: bool, optional + :param page: The page to build the dialog on. Default is the first page. + :type page: int, optional + :return: The built dialog or None if a problem occurs. + :rtype: Union[CommonUiResponseDialog, None] + """ + self.log.format_with_message('Attempting to build dialog.', dialog_options=dialog_options) + + _dialog = self._create_dialog( + dialog_options=dialog_options, + sim_info=sim_info, + target_sim_info=target_sim_info + ) + if _dialog is None: + self.log.error('_dialog was None for some reason.') + return + + if on_chosen is None: + raise ValueError('on_chosen was None.') + + if len(self.always_visible_responses) == 0 and len(self.responses) == 0: + raise AssertionError('No responses have been provided. Add responses to the dialog before attempting to display it.') + + def _on_chosen(dialog: CommonUiResponseDialog) -> None: + try: + if dialog.cancelled: + self.log.debug('Dialog cancelled.') + on_chosen(None, CommonChoiceOutcome.CANCEL) + return + choice = dialog.get_response_value() + self.log.format_with_message('Choice made.', choice=choice) + on_chosen(choice, CommonChoiceOutcome.CHOICE_MADE) + self.log.debug('Finished handling _on_chosen.') + except Exception as ex: + self.log.error('Error occurred on choosing a value.', exception=ex) + + if include_pagination: + self._setup_responses( + _dialog, + include_previous_button=include_previous_button, + page=page + ) + else: + self.log.debug('Adding always visible responses.') + for always_visible_response in self.always_visible_responses: + _dialog.add_response(always_visible_response) + self.log.debug('Adding responses.') + for response in self.responses: + _dialog.add_response(response) + + self.log.debug('Adding listener.') + _dialog.add_listener(_on_chosen) + return _dialog + + def _setup_responses( + self, + _dialog: CommonUiResponseDialog, + include_previous_button: bool=True, + page: int=1 + ): + if page < 0: + raise AssertionError('page cannot be less than zero.') + + added_previous_button = False + number_of_responses = len(self.responses) + self.log.format(number_of_responses=number_of_responses, per_page=self._per_page) + if number_of_responses > self._per_page: + number_of_pages = math.ceil(number_of_responses / self._per_page) + + if page > number_of_pages: + raise AssertionError('page was out of range. Number of Pages: {}, Requested Page: {}'.format(str(number_of_pages), str(page))) + # Add the responses that are always visible. + for always_visible_response in self.always_visible_responses: + _dialog.add_response(always_visible_response) + + # Add the responses that should show on the current page. + start_index = (page - 1) * self._per_page + end_index = page * self._per_page + self.log.format(start_index=start_index, end_index=end_index) + current_choices = self.responses[start_index:end_index] + self.log.format(current_responses=current_choices) + for response in current_choices: + _dialog.add_response(response) + + if page < number_of_pages: + self.log.format_with_message('Adding Next response.', page=page, number_of_pages=number_of_pages) + _dialog.add_response(CommonUiDialogResponse(len(self.responses) + 1, CommonDialogNavigationButtonTag.NEXT, text=self._next_button_text)) + else: + self.log.format_with_message('Not adding Next.', page=page, number_of_pages=number_of_pages) + + if page > 1: + self.log.format_with_message('Adding Previous response.', page=page, number_of_pages=number_of_pages) + added_previous_button = True + _dialog.add_response(CommonUiDialogResponse(len(self.responses) + 2, CommonDialogNavigationButtonTag.PREVIOUS, text=self._previous_button_text)) + else: + self.log.format_with_message('Not adding Previous response.', page=page) + else: + self.log.debug('Adding always visible responses.') + for always_visible_response in self.always_visible_responses: + _dialog.add_response(always_visible_response) + self.log.debug('Adding responses.') + for response in self.responses: + _dialog.add_response(response) + + if not added_previous_button and include_previous_button: + self.log.format_with_message('Adding Previous response.', page=page) + _dialog.add_response(CommonUiDialogResponse(len(self.responses) + 2, CommonDialogNavigationButtonTag.PREVIOUS, text=self._previous_button_text)) + + def _create_dialog( + self, + dialog_options: UiDialogOption=0, + sim_info: SimInfo=None, + target_sim_info: SimInfo=None + ) -> Union[CommonUiResponseDialog, None]: + try: + self.log.debug('Creating dialog.') + return CommonUiResponseDialog.TunableFactory().default( + sim_info or CommonSimUtils.get_active_sim_info(), + tuple(), + dialog_options=dialog_options, + text=lambda *_, **__: self.description, + title=lambda *_, **__: self.title, + target_sim_id=CommonSimUtils.get_sim_id(target_sim_info) if target_sim_info is not None else None, + resolver=DoubleSimResolver(sim_info, target_sim_info) if sim_info is not None and target_sim_info is not None else None + ) + except Exception as ex: + self.log.error('_create_dialog', exception=ex) + return None + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_testing.show_choose_response_dialog', + 'Show an example of CommonChooseResponseDialog.' +) +def _common_testing_show_choose_response_dialog(output: CommonConsoleCommandOutput): + output('Showing test choose response dialog.') + + def _on_chosen(choice: str, outcome: CommonChoiceOutcome): + output('Chose {} with result: {}.'.format(pformat(choice), pformat(outcome))) + + responses: Tuple[CommonUiDialogResponse] = ( + CommonUiDialogResponse( + 1, + 'Value 1', + text=CommonLocalizationUtils.create_localized_string(CommonStringId.TESTING_TEST_BUTTON_ONE) + ), + CommonUiDialogResponse( + 2, + 'Value 2', + text=CommonLocalizationUtils.create_localized_string(CommonStringId.TESTING_TEST_BUTTON_TWO) + ), + CommonUiDialogResponse( + 3, + 'Value 3', + text=CommonLocalizationUtils.create_localized_string('Test Button 3') + ) + ) + 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),) + + active_sim_info = CommonSimUtils.get_active_sim_info() + dialog = CommonChooseResponseDialog( + ModInfo.get_identity(), + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + responses, + title_tokens=title_tokens, + description_tokens=description_tokens, + per_page=2 + ) + dialog.show( + sim_info=active_sim_info, + on_chosen=_on_chosen, + include_previous_button=False + ) + output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_choose_sim_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/common_choose_sim_dialog.py new file mode 100644 index 0000000..c280c31 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/common_choose_sim_dialog.py @@ -0,0 +1,318 @@ +""" +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 +""" +from typing import Any, Callable, Union, Iterator, Tuple + +from pprint import pformat + +import random +from protocolbuffers.Localization_pb2 import LocalizedString +from sims.sim_info import SimInfo +from sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome +from sims4communitylib.dialogs.common_choose_dialog import CommonChooseDialog +from sims4communitylib.dialogs.utils.common_dialog_utils import CommonDialogUtils +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from ui.ui_dialog_picker import UiSimPicker, SimPickerRow + + +class CommonChooseSimDialog(CommonChooseDialog): + """CommonChooseSimDialog(\ + title_identifier,\ + description_identifier,\ + choices,\ + title_tokens=(),\ + description_tokens=(),\ + mod_identity=None,\ + required_tooltip=None,\ + required_tooltip_tokens=()\ + ) + + Create a dialog to display a list of Sims to choose. + + .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_choose_sim_dialog` in the in-game console. + + .. highlight:: python + .. code-block:: python + + def _common_testing_show_choose_sim_dialog(): + + def _on_chosen(choice: Union[SimInfo, None], outcome: CommonChoiceOutcome): + 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 + current_count = 0 + count = 25 + options = [] + for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): + if current_count >= count: + break + sim_id = CommonSimUtils.get_sim_id(sim_info) + should_select = random.choice((True, False)) + is_enabled = random.choice((True, False)) + options.append( + SimPickerRow( + sim_id, + select_default=should_select, + tag=sim_info, + is_enable=is_enabled + ) + ) + current_count += 1 + + dialog = CommonChooseSimDialog( + 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_chosen=_on_chosen, column_count=5) + + :param title_identifier: A decimal identifier of the title text. + :type title_identifier: Union[int, str, LocalizedString, CommonStringId] + :param description_identifier: A decimal identifier of the description text. + :type description_identifier: Union[int, str, LocalizedString, CommonStringId] + :param choices: The choices to display in the dialog. + :type choices: Iterator[SimPickerRow] + :param title_tokens: Tokens to format into the title. + :type title_tokens: Iterator[Any], optional + :param description_tokens: Tokens to format into the description. + :type description_tokens: Iterator[Any], optional + :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. + :type mod_identity: CommonModIdentity, optional + :param required_tooltip: If provided, this text will display when the dialog requires at least one choice and a choice has not been made. Default is None. + :type required_tooltip: Union[int, str, LocalizedString, CommonStringId], optional + :param required_tooltip_tokens: Tokens to format into the required tooltip. Default is an empty collection. + :type required_tooltip_tokens: Iterator[Any], optional + """ + def __init__( + self, + title_identifier: Union[int, str, LocalizedString, CommonStringId], + description_identifier: Union[int, str, LocalizedString, CommonStringId], + choices: Iterator[SimPickerRow], + title_tokens: Iterator[Any]=(), + description_tokens: Iterator[Any]=(), + mod_identity: CommonModIdentity=None, + required_tooltip: Union[int, str, LocalizedString, CommonStringId]=None, + required_tooltip_tokens: Iterator[Any]=() + ): + super().__init__( + title_identifier, + description_identifier, + choices, + title_tokens=title_tokens, + description_tokens=description_tokens, + mod_identity=mod_identity, + required_tooltip=required_tooltip, + required_tooltip_tokens=required_tooltip_tokens + ) + + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + return 's4cl_choose_sim_dialog' + + # noinspection PyMissingOrEmptyDocstring + @property + def rows(self) -> Tuple[SimPickerRow]: + result: Tuple[SimPickerRow] = super().rows + return result + + # noinspection PyMissingOrEmptyDocstring + def add_row(self, choice: SimPickerRow, *_, **__): + return super().add_row(choice, *_, **__) + + def show( + self, + on_chosen: Callable[[Any, CommonChoiceOutcome], Any]=CommonFunctionUtils.noop, + sim_info: SimInfo=None, + should_show_names: bool=True, + hide_row_descriptions: bool=False, + column_count: int=3 + ): + """show(\ + on_chosen=CommonFunctionUtils.noop,\ + sim_info=None,\ + should_show_names=True,\ + hide_row_descriptions=False,\ + column_count=3\ + ) + + Show the dialog and invoke the callbacks upon the player making a choice. + + :param on_chosen: A callback invoked upon the player choosing a Sim from the list. Cannot be None. + :type on_chosen: Callable[[Any, CommonChoiceOutcome], Any], optional + :param sim_info: The SimInfo of the Sim that will appear in the dialog image. The default Sim is the active Sim. + :type sim_info: SimInfo, optional + :param should_show_names: If True, then the names of the Sims will display in the dialog. + :type should_show_names: bool, optional + :param hide_row_descriptions: A flag to hide the row descriptions. + :type hide_row_descriptions: bool, optional + :param column_count: The number of columns to display Sims in. Minimum: 3, Maximum: 8 + :type column_count: int, optional + :exception AssertionError: when something is wrong with the arguments or no rows were added to the dialog. + """ + try: + self._rows = tuple(sorted(self._rows, key=lambda row: CommonSimNameUtils.get_full_name(CommonSimUtils.get_sim_info(row.sim_id)))) + return self._show( + on_chosen=on_chosen, + sim_info=sim_info, + should_show_names=should_show_names, + hide_row_descriptions=hide_row_descriptions, + column_count=column_count + ) + except Exception as ex: + self.log.error('show', exception=ex) + + def _show( + self, + on_chosen: Callable[[Any, CommonChoiceOutcome], Any]=CommonFunctionUtils.noop, + sim_info: SimInfo=None, + should_show_names: bool=True, + hide_row_descriptions: bool=False, + column_count: int=3 + ): + _dialog = self.build_dialog( + on_chosen=on_chosen, + sim_info=sim_info, + should_show_names=should_show_names, + hide_row_descriptions=hide_row_descriptions, + column_count=column_count + ) + self.log.debug('Showing dialog.') + _dialog.show_dialog() + + # noinspection PyMissingOrEmptyDocstring + def build_dialog( + self, + on_chosen: Callable[[Any, CommonChoiceOutcome], bool]=CommonFunctionUtils.noop, + sim_info: SimInfo=None, + should_show_names: bool=True, + hide_row_descriptions: bool=False, + column_count: int=3 + ) -> Union[UiSimPicker, None]: + self.log.format_with_message('Attempting to display choices.') + _dialog = self._create_dialog( + sim_info=sim_info, + should_show_names=should_show_names, + hide_row_descriptions=hide_row_descriptions, + column_count=column_count + ) + if _dialog is None: + self.log.error('_dialog was None for some reason.') + return + + if on_chosen is None: + raise AssertionError('\'on_chosen\' was None.') + + if len(self.rows) == 0: + raise AssertionError('No rows have been provided. Add rows to the dialog before attempting to display it.') + + def _on_chosen(dialog: UiSimPicker) -> bool: + try: + if not dialog.accepted: + self.log.debug('Dialog cancelled.') + return on_chosen(None, CommonChoiceOutcome.CANCEL) + choice = CommonDialogUtils.get_chosen_item(dialog) + self.log.format_with_message('Choice made.', choice=choice) + result = on_chosen(choice, CommonChoiceOutcome.CHOICE_MADE) + self.log.format_with_message('Finished handling choice.', result=result) + return result + except Exception as ex: + self.log.error('Error occurred on choosing a value.', exception=ex) + return False + + self.log.debug('Adding all choices') + for row in self.rows: + _dialog.add_row(row) + + _dialog.add_listener(_on_chosen) + return _dialog + + def _create_dialog( + self, + sim_info: SimInfo=None, + should_show_names: bool=True, + hide_row_descriptions: bool=False, + column_count: int=3, + min_selectable: int=1, + max_selectable: int=1 + ) -> Union[UiSimPicker, None]: + if column_count < 3: + raise AttributeError('\'column_count\' must be at least 3 columns.') + if column_count > 8: + raise AttributeError('\'column_count\' can be no more than 8 columns.') + try: + return UiSimPicker.TunableFactory().default( + sim_info or CommonSimUtils.get_active_sim_info(), + title=lambda *_, **__: self.title, + text=lambda *_, **__: self.description, + min_selectable=min_selectable, + max_selectable=max_selectable, + should_show_names=should_show_names, + hide_row_description=hide_row_descriptions, + column_count=column_count + ) + except Exception as ex: + self.log.error('_create_dialog', exception=ex) + return None + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_testing.show_choose_sim_dialog', + 'Show an example of CommonChooseSimDialog.' +) +def _common_testing_show_choose_sim_dialog(output: CommonConsoleCommandOutput): + output('Showing test choose sim dialog.') + + def _on_chosen(choice: Union[SimInfo, None], outcome: CommonChoiceOutcome): + output('Chose {} with result: {}.'.format(CommonSimNameUtils.get_full_name(choice), pformat(outcome))) + + # 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),) + current_count = 0 + count = 25 + options = [] + for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): + if current_count >= count: + break + sim_id = CommonSimUtils.get_sim_id(sim_info) + should_select = random.choice((True, False)) + is_enabled = random.choice((True, False)) + options.append( + SimPickerRow( + sim_id, + select_default=should_select, + tag=sim_info, + is_enable=is_enabled + ) + ) + current_count += 1 + + dialog = CommonChooseSimDialog( + 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_chosen=_on_chosen, column_count=5) + output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_choose_sims_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/common_choose_sims_dialog.py new file mode 100644 index 0000000..e5d1c1d --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/common_choose_sims_dialog.py @@ -0,0 +1,309 @@ +""" +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 +""" +from typing import Any, Callable, Union, Tuple, Iterator + +from pprint import pformat + +import random + +from protocolbuffers.Localization_pb2 import LocalizedString +from sims.sim_info import SimInfo +from sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome +from sims4communitylib.dialogs.common_choose_sim_dialog import CommonChooseSimDialog +from sims4communitylib.dialogs.option_dialogs.options.sims.common_dialog_sim_option import CommonDialogSimOption +from sims4communitylib.dialogs.utils.common_dialog_utils import CommonDialogUtils +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from ui.ui_dialog_picker import UiSimPicker, SimPickerRow + + +class CommonChooseSimsDialog(CommonChooseSimDialog): + """CommonChooseSimsDialog(\ + title_identifier,\ + description_identifier,\ + choices,\ + title_tokens=(),\ + description_tokens=(),\ + mod_identity=None,\ + required_tooltip=None,\ + required_tooltip_tokens=()\ + ) + + Create a dialog that prompts the player to choose a number of Sims. + + .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_choose_sims_dialog` in the in-game console. + + .. highlight:: python + .. code-block:: python + + def _common_testing_show_choose_sims_dialog(): + + def _on_chosen(choice: Union[Tuple[SimInfo], None], outcome: CommonChoiceOutcome): + 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 + current_count = 0 + count = 25 + options = [] + for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): + if current_count >= count: + break + sim_id = CommonSimUtils.get_sim_id(sim_info) + is_enabled = random.choice((True, False)) + options.append( + SimPickerRow( + sim_id, + select_default=False, + tag=sim_info, + is_enable=is_enabled + ) + ) + current_count += 1 + + dialog = CommonChooseSimsDialog( + 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_chosen=_on_chosen, + column_count=5, + min_selectable=2, + max_selectable=6 + ) + + :param title_identifier: A decimal identifier of the title text. + :type title_identifier: Union[int, str, LocalizedString, CommonStringId] + :param description_identifier: A decimal identifier of the description text. + :type description_identifier: Union[int, str, LocalizedString, CommonStringId] + :param choices: The choices to display in the dialog. + :type choices: Iterator[SimPickerRow] + :param title_tokens: Tokens to format into the title. + :type title_tokens: Iterator[Any], optional + :param description_tokens: Tokens to format into the description. + :type description_tokens: Iterator[Any], optional + :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. + :type mod_identity: CommonModIdentity, optional + :param required_tooltip: If provided, this text will display when the dialog requires at least one choice and a choice has not been made. Default is None. + :type required_tooltip: Union[int, str, LocalizedString, CommonStringId], optional + :param required_tooltip_tokens: Tokens to format into the required tooltip. Default is an empty collection. + :type required_tooltip_tokens: Iterator[Any], optional + """ + def __init__( + self, + title_identifier: Union[int, str, LocalizedString, CommonStringId], + description_identifier: Union[int, str, LocalizedString, CommonStringId], + choices: Iterator[SimPickerRow], + title_tokens: Iterator[Any]=(), + description_tokens: Iterator[Any]=(), + mod_identity: CommonModIdentity=None, + required_tooltip: Union[int, str, LocalizedString, CommonStringId]=None, + required_tooltip_tokens: Iterator[Any]=() + ): + super().__init__( + title_identifier, + description_identifier, + choices, + title_tokens=title_tokens, + description_tokens=description_tokens, + mod_identity=mod_identity, + required_tooltip=required_tooltip, + required_tooltip_tokens=required_tooltip_tokens + ) + + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + return 's4cl_choose_sims_dialog' + + def show( + self, + on_chosen: Callable[[Union[Tuple[Any], None], CommonChoiceOutcome], Any]=CommonFunctionUtils.noop, + sim_info: SimInfo=None, + should_show_names: bool=True, + hide_row_descriptions: bool=False, + column_count: int=3, + min_selectable: int=1, + max_selectable: int=1 + ): + """show(\ + on_chosen=CommonFunctionUtils.noop,\ + sim_info=None,\ + should_show_names=True,\ + hide_row_descriptions=False,\ + column_count=3,\ + min_selectable=1,\ + max_selectable=1\ + ) + + Show the dialog and invoke the callbacks upon the player submitting their selection. + + :param on_chosen: A callback invoked upon the player submitting their chosen Sims from the list. Default is CommonFunctionUtils.noop. + :type on_chosen: Callable[[Union[Tuple[Any], None], CommonChoiceOutcome], Any], optional + :param sim_info: The SimInfo of the Sim that will appear in the dialog image. The default Sim is the active Sim. Default is None. + :type sim_info: SimInfo, optional + :param should_show_names: If True, then the names of the Sims will display in the dialog. Default is True. + :type should_show_names: bool, optional + :param hide_row_descriptions: A flag to hide the row descriptions. Default is False. + :type hide_row_descriptions: bool, optional + :param column_count: The number of columns to display Sims in. Default is 3. + :type column_count: int, optional + :param min_selectable: The minimum number of Sims that must be chosen. Default is 1. + :type min_selectable: int, optional + :param max_selectable: The maximum number of Sims that can be chosen. Default is 1. + :type max_selectable: int, optional + :exception AssertionError: When something is wrong with the arguments or no rows were added to the dialog. + :exception AttributeError: When Min or Max Selectable are invalid. + """ + try: + self._rows = tuple(sorted(self._rows, key=lambda row: CommonSimNameUtils.get_full_name(CommonSimUtils.get_sim_info(row.sim_id)))) + return self._show( + on_chosen=on_chosen, + sim_info=sim_info, + should_show_names=should_show_names, + hide_row_descriptions=hide_row_descriptions, + column_count=column_count, + min_selectable=min_selectable, + max_selectable=max_selectable + ) + except Exception as ex: + self.log.error('show', exception=ex) + + def _show( + self, + on_chosen: Callable[[Union[Tuple[CommonDialogSimOption], None], CommonChoiceOutcome], Any]=CommonFunctionUtils.noop, + sim_info: SimInfo=None, + should_show_names: bool=True, + hide_row_descriptions: bool=False, + column_count: int=3, + min_selectable: int=1, + max_selectable: int=1 + ): + _dialog = self.build_dialog( + on_chosen=on_chosen, + sim_info=sim_info, + should_show_names=should_show_names, + hide_row_descriptions=hide_row_descriptions, + column_count=column_count, + min_selectable=min_selectable, + max_selectable=max_selectable + ) + self.log.debug('Showing dialog.') + _dialog.show_dialog() + + # noinspection PyMissingOrEmptyDocstring + def build_dialog( + self, + on_chosen: Callable[[Union[Tuple[CommonDialogSimOption], None], CommonChoiceOutcome], Any]=CommonFunctionUtils.noop, + sim_info: SimInfo=None, + should_show_names: bool=True, + hide_row_descriptions: bool=False, + column_count: int=3, + min_selectable: int=1, + max_selectable: int=1 + ): + if min_selectable < 1: + raise AttributeError('\'min_selectable\' must be at least 1.') + if max_selectable < min_selectable: + raise AttributeError('\'max_selectable\' must be greater than \'min_selectable\'.') + self.log.format_with_message('Attempting to display Sims choices.') + _dialog = self._create_dialog( + sim_info=sim_info, + should_show_names=should_show_names, + hide_row_descriptions=hide_row_descriptions, + column_count=column_count, + min_selectable=min_selectable, + max_selectable=max_selectable + ) + if _dialog is None: + self.log.error('_dialog was None for some reason.') + return + + if on_chosen is None: + raise AssertionError('on_chosen was None.') + + if len(self.rows) == 0: + raise AssertionError('No rows have been provided. Add rows to the dialog before attempting to display it.') + + def _on_chosen(dialog: UiSimPicker): + if not dialog.accepted: + self.log.debug('Dialog cancelled.') + return on_chosen(None, CommonChoiceOutcome.CANCEL) + choices = tuple(CommonDialogUtils.get_chosen_items(dialog)) + self.log.format_with_message('Choice made.', choice=choices) + result = on_chosen(choices, CommonChoiceOutcome.CHOICE_MADE) + self.log.format_with_message('Finished handling choice.', result=result) + return result + + self.log.debug('Adding all choices') + for row in self.rows: + _dialog.add_row(row) + + _dialog.add_listener(_on_chosen) + return _dialog + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_testing.show_choose_sims_dialog', + 'Show an example of CommonChooseSimsDialog.' +) +def _common_testing_show_choose_sims_dialog(output: CommonConsoleCommandOutput): + output('Showing test choose sims dialog.') + + def _on_chosen(choice: Union[Tuple[SimInfo], None], outcome: CommonChoiceOutcome): + output('Chose {} with result: {}.'.format(CommonSimNameUtils.get_full_names(choice), pformat(outcome))) + + # 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),) + current_count = 0 + count = 25 + options = [] + for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): + if current_count >= count: + break + sim_id = CommonSimUtils.get_sim_id(sim_info) + is_enabled = random.choice((True, False)) + options.append( + SimPickerRow( + sim_id, + select_default=False, + tag=sim_info, + is_enable=is_enabled + ) + ) + current_count += 1 + + dialog = CommonChooseSimsDialog( + 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_chosen=_on_chosen, + column_count=5, + min_selectable=2, + max_selectable=6 + ) + output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/common_dialog.py new file mode 100644 index 0000000..c53d266 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/common_dialog.py @@ -0,0 +1,92 @@ +""" +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 +""" +from typing import Any, Union, Iterator +from protocolbuffers.Localization_pb2 import LocalizedString +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.logging.has_log import HasLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from ui.ui_dialog import UiDialogBase + + +class CommonDialog(HasLog): + """CommonDialog(\ + title_identifier,\ + description_identifier,\ + title_tokens=(),\ + description_tokens=(),\ + mod_identity=None\ + ) + + An inheritable class for creating a dialog. + + .. note:: It is recommended to utilize one of the ready made dialogs, instead of creating a custom :class:`CommonDialog` + + :param title_identifier: The title to display in the dialog. + :type title_identifier: Union[int, str, LocalizedString, CommonStringId] + :param description_identifier: The description to display in the dialog. + :type description_identifier: Union[int, str, LocalizedString, CommonStringId] + :param title_tokens: Tokens to format into the title. Default is an empty collection. + :type title_tokens: Iterator[Any], optional + :param description_tokens: Tokens to format into the description. Default is an empty collection. + :type description_tokens: Iterator[Any], optional + :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. Default is None. + :type mod_identity: CommonModIdentity, optional + """ + + def __init__( + self, + title_identifier: Union[int, str, LocalizedString, CommonStringId], + description_identifier: Union[int, str, LocalizedString, CommonStringId], + title_tokens: Iterator[Any]=(), + description_tokens: Iterator[Any]=(), + mod_identity: CommonModIdentity=None + ): + super().__init__() + self.title = CommonLocalizationUtils.create_localized_string(title_identifier, tokens=tuple(title_tokens)) + self.description = CommonLocalizationUtils.create_localized_string(description_identifier, tokens=tuple(description_tokens)) + self._mod_identity = mod_identity + + # noinspection PyMissingOrEmptyDocstring + @property + def mod_identity(self) -> CommonModIdentity: + return self._mod_identity + + def show(self, *_: Any, **__: Any): + """show(*_, **__) + + Display the dialog to the player. + + .. note:: Override this method with any arguments you want to. + + """ + raise NotImplementedError('\'{}\' not implemented.'.format(self.__class__.show.__name__)) + + def build_dialog(self, *_: Any, **__: Any) -> Union[UiDialogBase, None]: + """build_dialog(*_, **__) + + Build the dialog. + + .. note:: Override this method with any arguments you want to. + + :return: The built dialog or None if a problem occurs. + :rtype: Union[UiDialogBase, None] + """ + return self._create_dialog(*_, **__) + + def _create_dialog(self, *_: Any, **__: Any) -> Union[UiDialogBase, None]: + """_create_dialog(*_, **__) + + Create a dialog for use in :func:``show`. + + .. note:: Override this method with any arguments you want to. + + :return: An instance of the dialog being shown or None if a problem occurs. + :rtype: Union[UiDialogBase, None] + """ + raise NotImplementedError('\'{}\' not implemented.'.format(self.__class__._create_dialog.__name__)) diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_dialog_navigation_button_tag.py b/Scripts/s4ap/sims4communitylib/dialogs/common_dialog_navigation_button_tag.py new file mode 100644 index 0000000..cbdc265 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/common_dialog_navigation_button_tag.py @@ -0,0 +1,13 @@ +""" +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 +""" + + +class CommonDialogNavigationButtonTag: + """ Tags applied to the navigation buttons of a dialog. """ + PREVIOUS = 'S4CL_PREVIOUS' + NEXT = 'S4CL_NEXT' diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_input_float_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/common_input_float_dialog.py new file mode 100644 index 0000000..6eb458a --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/common_input_float_dialog.py @@ -0,0 +1,216 @@ +""" +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 +""" +from typing import Any, Callable, Union, Iterator + +from pprint import pformat +from protocolbuffers.Localization_pb2 import LocalizedString +from sims.sim_info import SimInfo +from sims4communitylib.dialogs._common_ui_dialog_text_input_ok_cancel import _CommonUiDialogTextInputOkCancel +from sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome +from sims4communitylib.dialogs.common_dialog import CommonDialog +from sims4communitylib.dialogs.utils.common_dialog_utils import CommonDialogUtils +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from ui.ui_dialog_generic import UiDialogTextInput +from sims4communitylib.modinfo import ModInfo + + +class CommonInputFloatDialog(CommonDialog): + """CommonInputFloatDialog(\ + title_identifier,\ + description_identifier,\ + initial_value,\ + min_value=0.0,\ + max_value=2147483647.0,\ + title_tokens=(),\ + description_tokens=(),\ + mod_identity=None\ + ) + + Create a dialog that prompts the player to enter a float value. + + .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_input_float_dialog` in the in-game console. + + .. highlight:: python + .. code-block:: python + + def _common_testing_show_input_float_dialog(): + + def _on_submit(input_value: float, outcome: CommonChoiceOutcome): + 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 + dialog = CommonInputFloatDialog( + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + 2.0, + title_tokens=title_tokens, + description_tokens=description_tokens + ) + dialog.show(on_submit=_on_submit) + + :param title_identifier: A decimal identifier of the title text. + :type title_identifier: Union[int, str, LocalizedString, CommonStringId] + :param description_identifier: A decimal identifier of the description text. + :type description_identifier: Union[int, str, LocalizedString, CommonStringId] + :param initial_value: The initial value that will appear in the input box. + :type initial_value: float + :param min_value: The minimum value allowed to be entered by the player. Default is 0.0 + :type min_value: float, optional + :param max_value: The maximum value allowed to be entered by the player. Default is Max Int. + :type max_value: float, optional + :param title_tokens: Tokens to format into the title. + :type title_tokens: Iterator[Any], optional + :param description_tokens: Tokens to format into the description. + :type description_tokens: Iterator[Any], optional + :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. + :type mod_identity: CommonModIdentity, optional + """ + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + return 's4cl_input_float_dialog' + + def __init__( + self, + title_identifier: Union[int, str, LocalizedString, CommonStringId], + description_identifier: Union[int, str, LocalizedString, CommonStringId], + initial_value: float, + min_value: float=0.0, + max_value: float=2147483647.0, + title_tokens: Iterator[Any]=(), + description_tokens: Iterator[Any]=(), + mod_identity: CommonModIdentity=None + ): + super().__init__( + title_identifier, + description_identifier, + title_tokens=title_tokens, + description_tokens=description_tokens, + mod_identity=mod_identity + ) + self.initial_value = initial_value + self.min_value = min_value + self.max_value = max_value + + def show( + self, + sim_info: SimInfo=None, + on_submit: Callable[[Union[float, None], CommonChoiceOutcome], Any]=CommonFunctionUtils.noop + ): + """show(\ + sim_info=None,\ + on_submit=CommonFunctionUtils.noop\ + ) + + Show the dialog and invoke the callbacks upon the player submitting a value. + + :param sim_info: The Sim that owns the dialog. Set to None to use the Active Sim. Default is None. + :type sim_info: SimInfo, optional + :param on_submit: A callback invoked upon the player submitting a value. Default is CommonFunctionUtils.noop. + :type on_submit: Callable[[Union[float, None], CommonChoiceOutcome], Any], optional + """ + try: + return self._show( + sim_info=sim_info, + on_submit=on_submit + ) + except Exception as ex: + self.log.error('show', exception=ex) + + def _show( + self, + sim_info: SimInfo=None, + on_submit: Callable[[Union[float, None], CommonChoiceOutcome], bool]=CommonFunctionUtils.noop + ): + self.log.debug('Attempting to display input float dialog.') + + if on_submit is None: + raise ValueError('\'on_submit\' was None.') + + _dialog = self._create_dialog(sim_info=sim_info) + if _dialog is None: + self.log.error('_dialog was None for some reason.') + return + + # noinspection PyBroadException + def _on_submit(dialog: UiDialogTextInput) -> bool: + try: + input_value = CommonDialogUtils.get_input_value(dialog) + if not input_value or not dialog.accepted: + self.log.debug('Dialog cancelled.') + return on_submit(None, CommonChoiceOutcome.CANCEL) + self.log.format_with_message('Value entered, attempting to convert it to a float.', value=input_value) + + try: + input_value = float(input_value) + self.log.debug('Conversion successful.') + input_value = max(self.min_value, input_value) + input_value = min(self.max_value, input_value) + except: + self.log.format_with_message('Failed to convert value', value=input_value) + return on_submit(None, CommonChoiceOutcome.ERROR) + + self.log.format_with_message('Value entered.', input_value=input_value) + result = on_submit(input_value, CommonChoiceOutcome.CHOICE_MADE) + self.log.format_with_message('Finished handling input.', result=result) + return result + except Exception as ex: + self.log.error('Error occurred on submitting a value.', exception=ex) + return False + + _dialog.add_listener(_on_submit) + if self.initial_value is not None: + _dialog.show_dialog(additional_tokens=(self.initial_value,)) + else: + _dialog.show_dialog() + + def _create_dialog(self, sim_info: SimInfo=None) -> Union[_CommonUiDialogTextInputOkCancel, None]: + try: + return _CommonUiDialogTextInputOkCancel.TunableFactory().default( + sim_info or CommonSimUtils.get_active_sim_info(), + text=lambda *_, **__: self.description, + title=lambda *_, **__: self.title + ) + except Exception as ex: + self.log.error('_create_dialog', exception=ex) + return None + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_testing.show_input_float_dialog', + 'Show an example of CommonInputFloatDialog.' +) +def _common_testing_show_input_float_dialog(output: CommonConsoleCommandOutput): + output('Showing test input float dialog.') + + def _on_submit(input_value: float, outcome: CommonChoiceOutcome): + output('Input {} with result: {}.'.format(pformat(input_value), pformat(outcome))) + + # 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),) + dialog = CommonInputFloatDialog( + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + 2.0, + title_tokens=title_tokens, + description_tokens=description_tokens + ) + dialog.show(on_submit=_on_submit) + output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_input_integer_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/common_input_integer_dialog.py new file mode 100644 index 0000000..419eeea --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/common_input_integer_dialog.py @@ -0,0 +1,216 @@ +""" +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 +""" +from typing import Any, Callable, Union, Iterator + +from pprint import pformat +from protocolbuffers.Localization_pb2 import LocalizedString +from sims.sim_info import SimInfo +from sims4communitylib.dialogs._common_ui_dialog_text_input_ok_cancel import _CommonUiDialogTextInputOkCancel +from sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome +from sims4communitylib.dialogs.common_dialog import CommonDialog +from sims4communitylib.dialogs.utils.common_dialog_utils import CommonDialogUtils +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from ui.ui_dialog_generic import UiDialogTextInput +from sims4communitylib.modinfo import ModInfo + + +class CommonInputIntegerDialog(CommonDialog): + """CommonInputIntegerDialog(\ + title_identifier,\ + description_identifier,\ + initial_value,\ + min_value=0,\ + max_value=2147483647,\ + title_tokens=(),\ + description_tokens=(),\ + mod_identity=None\ + ) + + Create a dialog that prompts the player to enter an integer value. + + .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_input_integer_dialog` in the in-game console. + + .. highlight:: python + .. code-block:: python + + def _common_testing_show_input_integer_dialog(): + + def _on_submit(input_value: integer, outcome: CommonChoiceOutcome): + 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 + dialog = CommonInputIntegerDialog( + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + 2, + title_tokens=title_tokens, + description_tokens=description_tokens + ) + dialog.show(on_submit=_on_submit) + + :param title_identifier: A decimal identifier of the title text. + :type title_identifier: Union[int, str, LocalizedString, CommonStringId] + :param description_identifier: A decimal identifier of the description text. + :type description_identifier: Union[int, str, LocalizedString, CommonStringId] + :param initial_value: The initial value that will appear in the input box. + :type initial_value: int + :param min_value: The minimum value allowed to be entered by the player. Default is 0.0 + :type min_value: int, optional + :param max_value: The maximum value allowed to be entered by the player. Default is Max Int. + :type max_value: int, optional + :param title_tokens: Tokens to format into the title. + :type title_tokens: Iterator[Any], optional + :param description_tokens: Tokens to format into the description. + :type description_tokens: Iterator[Any], optional + :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. + :type mod_identity: CommonModIdentity, optional + """ + def __init__( + self, + title_identifier: Union[int, str, LocalizedString, CommonStringId], + description_identifier: Union[int, str, LocalizedString, CommonStringId], + initial_value: int, + min_value: int=0, + max_value: int=2147483647, + title_tokens: Iterator[Any]=(), + description_tokens: Iterator[Any]=(), + mod_identity: CommonModIdentity=None + ): + super().__init__( + title_identifier, + description_identifier, + title_tokens=title_tokens, + description_tokens=description_tokens, + mod_identity=mod_identity + ) + self.initial_value = initial_value + self.min_value = min_value + self.max_value = max_value + + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + return 's4cl_input_integer_dialog' + + def show( + self, + sim_info: SimInfo=None, + on_submit: Callable[[Union[int, None], CommonChoiceOutcome], Any]=CommonFunctionUtils.noop + ): + """show(\ + sim_info=None,\ + on_submit=CommonFunctionUtils.noop\ + ) + + Show the dialog and invoke the callbacks upon the player submitting a value. + + :param sim_info: The Sim that owns the dialog. Set to None to use the Active Sim. Default is None. + :type sim_info: SimInfo, optional + :param on_submit: A callback invoked upon the player submitting a value. Default is CommonFunctionUtils.noop. + :type on_submit: Callable[[Union[int, None], CommonChoiceOutcome], Any], optional + """ + try: + return self._show( + sim_info=sim_info, + on_submit=on_submit + ) + except Exception as ex: + self.log.error('show', exception=ex) + + def _show( + self, + sim_info: SimInfo=None, + on_submit: Callable[[Union[int, None], CommonChoiceOutcome], bool]=CommonFunctionUtils.noop + ): + self.log.debug('Attempting to display input integer dialog.') + + if on_submit is None: + raise ValueError('\'on_submit\' was None.') + + _dialog = self._create_dialog(sim_info=sim_info) + if _dialog is None: + self.log.error('_dialog was None for some reason.') + return + + # noinspection PyBroadException + def _on_submit(dialog: UiDialogTextInput) -> bool: + try: + input_value = CommonDialogUtils.get_input_value(dialog) + if not input_value or not dialog.accepted: + self.log.debug('Dialog cancelled.') + return on_submit(None, CommonChoiceOutcome.CANCEL) + self.log.format_with_message('Value entered, attempting to convert it to an integer.', value=input_value) + + try: + input_value = int(input_value) + self.log.debug('Conversion successful.') + input_value = max(self.min_value, input_value) + input_value = min(self.max_value, input_value) + except: + self.log.format_with_message('Failed to convert value', value=input_value) + return on_submit(None, CommonChoiceOutcome.ERROR) + + self.log.format_with_message('Value entered.', input_value=input_value) + result = on_submit(input_value, CommonChoiceOutcome.CHOICE_MADE) + self.log.format_with_message('Finished handling input.', result=result) + return result + except Exception as ex: + self.log.error('Error occurred on submitting a value.', exception=ex) + return False + + _dialog.add_listener(_on_submit) + if self.initial_value is not None: + _dialog.show_dialog(additional_tokens=(self.initial_value,)) + else: + _dialog.show_dialog() + + def _create_dialog(self, sim_info: SimInfo=None) -> Union[_CommonUiDialogTextInputOkCancel, None]: + try: + return _CommonUiDialogTextInputOkCancel.TunableFactory().default( + sim_info or CommonSimUtils.get_active_sim_info(), + text=lambda *_, **__: self.description, + title=lambda *_, **__: self.title + ) + except Exception as ex: + self.log.error('_create_dialog', exception=ex) + return None + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_testing.show_input_integer_dialog', + 'Show an example of CommonInputIntegerDialog.' +) +def _common_testing_show_input_integer_dialog(output: CommonConsoleCommandOutput): + output('Showing test input integer dialog.') + + def _on_submit(input_value: int, outcome: CommonChoiceOutcome): + output('Input {} with result: {}.'.format(pformat(input_value), pformat(outcome))) + + # 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),) + dialog = CommonInputIntegerDialog( + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + 2, + title_tokens=title_tokens, + description_tokens=description_tokens + ) + dialog.show(on_submit=_on_submit) + output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_input_multi_text_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/common_input_multi_text_dialog.py new file mode 100644 index 0000000..f3000be --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/common_input_multi_text_dialog.py @@ -0,0 +1,209 @@ +""" +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 +""" +from typing import Any, Callable, Union, Iterator, Dict + +from pprint import pformat +from protocolbuffers.Localization_pb2 import LocalizedString +from sims.sim_info import SimInfo +from sims4communitylib.dialogs._common_ui_dialog_multi_text_input_ok_cancel import _CommonUiDialogMultiTextInputOkCancel +from sims4communitylib.dialogs._common_ui_dialog_text_input_ok_cancel import _CommonUiDialogTextInputOkCancel +from sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome +from sims4communitylib.dialogs.common_dialog import CommonDialog +from sims4communitylib.dialogs.common_input_text_field import CommonInputTextField +from sims4communitylib.enums.common_character_restrictions import CommonCharacterRestriction +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from ui.ui_dialog_generic import UiDialogTextInput + + +class CommonInputMultiTextDialog(CommonDialog): + """CommonInputMultiTextDialog(\ + mod_identity,\ + title_identifier,\ + description_identifier,\ + input_fields,\ + title_tokens=(),\ + description_tokens=()\ + ) + + Create a dialog that prompts the player to enter a text value. + + .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_input_multi_text_dialog` in the in-game console. + + .. highlight:: python + .. code-block:: python + + def _common_testing_show_input_text_dialog(): + + def _on_submit(input_value: str, outcome: CommonChoiceOutcome): + 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 + dialog = CommonInputMultiTextDialog( + ModInfo.get_identity(), + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + ( + CommonInputTextField('first_input_field', 'initial_text', title='First Input', default_text='default text stuff'), + CommonInputTextField('input_box_two', 'initial_text_two', default_text=CommonStringId.TESTING_TEST_TEXT_NO_TOKENS), + CommonInputTextField('input_box_three', 'initial_text_three', title='Numbers Only', character_restriction=CommonCharacterRestriction.NUMBERS_ONLY) + ), + title_tokens=title_tokens, + description_tokens=description_tokens + ) + dialog.show(on_submit=_on_submit) + + :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. + :type mod_identity: CommonModIdentity + :param title_identifier: A decimal identifier of the title text. + :type title_identifier: Union[int, str, LocalizedString, CommonStringId] + :param description_identifier: A decimal identifier of the description text. + :type description_identifier: Union[int, str, LocalizedString, CommonStringId] + :param input_fields: An iterator of input fields to display in the dialog. + :type input_fields: Iterator[CommonInputTextField] + :param title_tokens: Tokens to format into the title. + :type title_tokens: Iterator[Any], optional + :param description_tokens: Tokens to format into the description. + :type description_tokens: Iterator[Any], optional + """ + def __init__( + self, + mod_identity: CommonModIdentity, + title_identifier: Union[int, str, LocalizedString, CommonStringId], + description_identifier: Union[int, str, LocalizedString, CommonStringId], + input_fields: Iterator[CommonInputTextField], + title_tokens: Iterator[Any] = (), + description_tokens: Iterator[Any] = () + ): + super().__init__( + title_identifier, + description_identifier, + title_tokens=title_tokens, + description_tokens=description_tokens, + mod_identity=mod_identity + ) + self.input_fields = input_fields + + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + return 's4cl_input_text_dialog' + + def show( + self, + sim_info: SimInfo = None, + on_submit: Callable[[Dict[str, str], CommonChoiceOutcome], Any] = CommonFunctionUtils.noop + ) -> None: + """show(\ + sim_info=None,\ + on_submit=CommonFunctionUtils.noop\ + ) + + Show the dialog and invoke the callbacks upon the player submitting a value. + + :param sim_info: The Sim that owns the dialog. Set to None to use the Active Sim. Default is None. + :type sim_info: SimInfo, optional + :param on_submit: A callback invoked upon the player submitting a value. Default is CommonFunctionUtils.noop. + :type on_submit: Callable[[Union[str, None], CommonChoiceOutcome], Any], optional + """ + try: + return self._show( + sim_info=sim_info, + on_submit=on_submit + ) + except Exception as ex: + self.log.error('show', exception=ex) + + def _show( + self, + sim_info: SimInfo = None, + on_submit: Callable[[Dict[str, str], CommonChoiceOutcome], bool] = CommonFunctionUtils.noop + ) -> None: + self.log.debug('Attempting to display input text dialog.') + + if on_submit is None: + raise ValueError('\'on_submit\' was None.') + + _dialog = self._create_dialog(sim_info=sim_info) + if _dialog is None: + self.log.error('_dialog was None for some reason.') + return + + # noinspection PyBroadException + def _on_submit(dialog: UiDialogTextInput) -> None: + try: + input_values = dict(dialog.text_input_responses) + if not input_values or not dialog.accepted: + self.log.debug('Dialog cancelled.') + on_submit(dict(), CommonChoiceOutcome.CANCEL) + return + self.log.format_with_message('Values entered.', input_values=input_values) + result = on_submit(input_values, CommonChoiceOutcome.CHOICE_MADE) + self.log.format_with_message('Finished handling input.', result=result) + except Exception as ex: + self.log.error('Error occurred on submitting values.', exception=ex) + + _dialog.add_listener(_on_submit) + if self.input_fields is not None: + _dialog.show_dialog(additional_tokens=tuple([input_field.initial_value for input_field in self.input_fields])) + else: + _dialog.show_dialog() + + def _create_dialog(self, sim_info: SimInfo = None) -> Union[_CommonUiDialogTextInputOkCancel, None]: + try: + return _CommonUiDialogMultiTextInputOkCancel.TunableFactory().default( + sim_info or CommonSimUtils.get_active_sim_info(), + self.input_fields, + text=lambda *_, **__: self.description, + title=lambda *_, **__: self.title + ) + except Exception as ex: + self.log.error('_create_dialog', exception=ex) + return None + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_testing.show_input_multi_text_dialog', + 'Show an example of CommonInputMultiTextDialog.' +) +def _common_testing_show_input_multi_text_dialog(output: CommonConsoleCommandOutput): + output('Showing test input multi text dialog.') + + def _on_chosen(input_values: Dict[str, str], outcome: CommonChoiceOutcome): + for (input_name, input_value) in input_values.items(): + output('Input {} Value {} with result: {}.'.format(pformat(input_name), pformat(input_value), pformat(outcome))) + output('Done printing inputs.') + + # 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),) + dialog = CommonInputMultiTextDialog( + ModInfo.get_identity(), + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + ( + CommonInputTextField('first_input_field', 'initial_text', title='First Input', default_text='default text stuff'), + CommonInputTextField('input_box_two', 'initial_text_two', default_text=CommonStringId.TESTING_TEST_TEXT_NO_TOKENS), + CommonInputTextField('input_box_three', 'initial_text_three', title='Numbers Only', character_restriction=CommonCharacterRestriction.NUMBERS_ONLY) + ), + title_tokens=title_tokens, + description_tokens=description_tokens + ) + dialog.show(on_submit=_on_chosen) + output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_input_text_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/common_input_text_dialog.py new file mode 100644 index 0000000..81645fb --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/common_input_text_dialog.py @@ -0,0 +1,196 @@ +""" +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 +""" +from typing import Any, Callable, Union, Iterator + +from pprint import pformat +from protocolbuffers.Localization_pb2 import LocalizedString +from sims.sim_info import SimInfo +from sims4communitylib.dialogs._common_ui_dialog_text_input_ok_cancel import _CommonUiDialogTextInputOkCancel +from sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome +from sims4communitylib.dialogs.common_dialog import CommonDialog +from sims4communitylib.dialogs.utils.common_dialog_utils import CommonDialogUtils +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from ui.ui_dialog_generic import UiDialogTextInput + + +class CommonInputTextDialog(CommonDialog): + """CommonInputTextDialog(\ + mod_identity,\ + title_identifier,\ + description_identifier,\ + initial_value,\ + title_tokens=(),\ + description_tokens=()\ + ) + + Create a dialog that prompts the player to enter a text value. + + .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_input_text_dialog` in the in-game console. + + .. highlight:: python + .. code-block:: python + + def _common_testing_show_input_text_dialog(): + + def _on_submit(input_value: str, outcome: CommonChoiceOutcome): + 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 + dialog = CommonInputTextDialog( + ModInfo.get_identity(), + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + 'default_text', + title_tokens=title_tokens, + description_tokens=description_tokens + ) + dialog.show(on_submit=_on_submit) + + :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. + :type mod_identity: CommonModIdentity + :param title_identifier: A decimal identifier of the title text. + :type title_identifier: Union[int, str, LocalizedString, CommonStringId] + :param description_identifier: A decimal identifier of the description text. + :type description_identifier: Union[int, str, LocalizedString, CommonStringId] + :param initial_value: The initial value that will appear in the input box. + :type initial_value: str + :param title_tokens: Tokens to format into the title. + :type title_tokens: Iterator[Any], optional + :param description_tokens: Tokens to format into the description. + :type description_tokens: Iterator[Any], optional + """ + def __init__( + self, + mod_identity: CommonModIdentity, + title_identifier: Union[int, str, LocalizedString, CommonStringId], + description_identifier: Union[int, str, LocalizedString, CommonStringId], + initial_value: str, + title_tokens: Iterator[Any]=(), + description_tokens: Iterator[Any]=() + ): + super().__init__( + title_identifier, + description_identifier, + title_tokens=title_tokens, + description_tokens=description_tokens, + mod_identity=mod_identity + ) + self.initial_value = initial_value + + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + return 's4cl_input_text_dialog' + + def show( + self, + sim_info: SimInfo=None, + on_submit: Callable[[Union[str, None], CommonChoiceOutcome], Any]=CommonFunctionUtils.noop + ) -> None: + """show(\ + sim_info=None,\ + on_submit=CommonFunctionUtils.noop\ + ) + + Show the dialog and invoke the callbacks upon the player submitting a value. + + :param sim_info: The Sim that owns the dialog. Set to None to use the Active Sim. Default is None. + :type sim_info: SimInfo, optional + :param on_submit: A callback invoked upon the player submitting a value. Default is CommonFunctionUtils.noop. + :type on_submit: Callable[[Union[str, None], CommonChoiceOutcome], Any], optional + """ + try: + return self._show( + sim_info=sim_info, + on_submit=on_submit + ) + except Exception as ex: + self.log.error('show', exception=ex) + + def _show( + self, + sim_info: SimInfo=None, + on_submit: Callable[[Union[str, None], CommonChoiceOutcome], bool]=CommonFunctionUtils.noop + ) -> None: + self.log.debug('Attempting to display input text dialog.') + + if on_submit is None: + raise ValueError('\'on_submit\' was None.') + + _dialog = self._create_dialog(sim_info=sim_info) + if _dialog is None: + self.log.error('_dialog was None for some reason.') + return + + # noinspection PyBroadException + def _on_submit(dialog: UiDialogTextInput) -> None: + try: + input_value = CommonDialogUtils.get_input_value(dialog) + if not input_value or not dialog.accepted: + self.log.debug('Dialog cancelled.') + on_submit(None, CommonChoiceOutcome.CANCEL) + return + self.log.format_with_message('Value entered.', input_value=input_value) + result = on_submit(input_value, CommonChoiceOutcome.CHOICE_MADE) + self.log.format_with_message('Finished handling input.', result=result) + except Exception as ex: + self.log.error('Error occurred on submitting a value.', exception=ex) + + _dialog.add_listener(_on_submit) + if self.initial_value is not None: + _dialog.show_dialog(additional_tokens=(self.initial_value,)) + else: + _dialog.show_dialog() + + def _create_dialog(self, sim_info: SimInfo=None) -> Union[_CommonUiDialogTextInputOkCancel, None]: + try: + return _CommonUiDialogTextInputOkCancel.TunableFactory().default( + sim_info or CommonSimUtils.get_active_sim_info(), + text=lambda *_, **__: self.description, + title=lambda *_, **__: self.title + ) + except Exception as ex: + self.log.error('_create_dialog', exception=ex) + return None + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_testing.show_input_text_dialog', + 'Show an example of CommonInputTextDialog.' +) +def _common_testing_show_input_text_dialog(output: CommonConsoleCommandOutput): + output('Showing test input text dialog.') + + def _on_chosen(input_value: str, outcome: CommonChoiceOutcome): + output('Input {} with result: {}.'.format(pformat(input_value), pformat(outcome))) + + # 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),) + dialog = CommonInputTextDialog( + ModInfo.get_identity(), + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + 'default_text', + title_tokens=title_tokens, + description_tokens=description_tokens + ) + dialog.show(on_submit=_on_chosen) + output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_input_text_field.py b/Scripts/s4ap/sims4communitylib/dialogs/common_input_text_field.py new file mode 100644 index 0000000..83add6e --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/common_input_text_field.py @@ -0,0 +1,94 @@ +""" +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 +""" +from typing import Union + +from protocolbuffers.Localization_pb2 import LocalizedString +from sims4communitylib.enums.common_character_restrictions import CommonCharacterRestriction +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.utils.localization.common_localized_string_separators import CommonLocalizedStringSeparator + + +class CommonInputTextField: + """CommonInputTextField(\ + identifier,\ + initial_value,\ + title=None,\ + character_restriction=CommonCharacterRestriction.NONE,\ + default_text=None\ + ) + + A field intended for use with an input text dialog. It allows entering of text. + + :param identifier: The identifier of the input. + :type identifier: str + :param initial_value: The initial value of the text input. + :type initial_value: str + :param title: A title to display above the input. Default is None. + :type title: Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator], optional + :param character_restriction: A character restriction to enforce what can be entered or not. Default is NONE. + :type character_restriction: CommonCharacterRestriction, optional + :param default_text: The default text shown when nothing is entered into the field. Default is None. + :type default_text: Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator], optional + """ + def __init__( + self, + identifier: str, + initial_value: str, + title: Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator, None] = None, + character_restriction: CommonCharacterRestriction = CommonCharacterRestriction.NONE, + default_text: Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator, None] = None + ): + self._identifier = identifier + self._initial_value = initial_value + self._title = title + self._character_restriction = character_restriction + self._default_text = default_text + + # 'default_text', + # 'height', + # 'initial_value', + # 'input_invalid_max_tooltip', + # 'input_invalid_min_tooltip', + # 'input_too_short_tooltip', + # 'max_length', + # 'max_value', + # 'message_descriptor', + # 'min_length', + # 'min_value', + # 'restricted_characters', + # 'text_input_name', + # 'title' + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + return 's4cl_input_text_dialog' + + @property + def identifier(self) -> str: + """The identifier of the input.""" + return self._identifier + + @property + def initial_value(self) -> str: + """The initial value the field will have entered.""" + return self._initial_value + + @property + def default_text(self) -> Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator, None]: + """The default text that will show in the field when nothing is entered.""" + return self._default_text + + @property + def title(self) -> Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator, None]: + """The title to display above the text field.""" + return self._title + + @property + def character_restriction(self) -> CommonCharacterRestriction: + """A character restriction to enforce what can be entered or not.""" + return self._character_restriction diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_multi_pane_choose_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/common_multi_pane_choose_dialog.py new file mode 100644 index 0000000..1f2b499 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/common_multi_pane_choose_dialog.py @@ -0,0 +1,431 @@ +""" +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 +""" +from pprint import pformat + +from typing import Tuple, Any, Callable, Union, Iterator, List, Dict +from protocolbuffers.Localization_pb2 import LocalizedString +from sims.sim_info import SimInfo +from sims4communitylib.dialogs.choose_object_dialog import CommonChooseObjectDialog +from sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome +from sims4communitylib.dialogs.common_choose_dialog import CommonChooseDialog +from sims4communitylib.dialogs.common_dialog import CommonDialog +from sims4communitylib.dialogs.custom_dialogs.picker_dialogs.common_ui_multi_picker import CommonUiMultiPicker +from sims4communitylib.dialogs.utils.common_dialog_utils import CommonDialogUtils +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from ui.ui_dialog import UiDialogBase +from ui.ui_dialog_picker import ObjectPickerRow + + +class CommonMultiPaneChooseDialog(CommonDialog): + """CommonMultiPaneChooseDialog(\ + mod_identity,\ + title_identifier,\ + description_identifier,\ + title_tokens=(),\ + description_tokens=()\ + ) + + Create a multi-pane dialog that prompts the player to choose from multiple dialogs and submit their choices. + + .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_multi_pane_choose_dialog` in the in-game console. + + .. warning:: This dialog does not currently work with `CommonChooseSimDialog` or `CommonChooseSimsDialog`. + + .. highlight:: python + .. code-block:: python + + def _common_testing_show_multi_pane_choose_dialog(): + + def _on_submit(choices_made: Tuple[Any], outcome: CommonChoiceOutcome) -> None: + pass + + def _on_sub_dialog_one_chosen(choice: Any, outcome: CommonChoiceOutcome) -> None: + pass + + def _on_sub_dialog_two_chosen(choice: Any, outcome: CommonChoiceOutcome) -> None: + 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 + # Create the dialog. + dialog = CommonMultiPaneChooseDialog( + ModInfo.get_identity(), + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + title_tokens=title_tokens, + description_tokens=description_tokens + ) + + sub_dialog_one_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' + ) + ] + + # Add sub dialog one. + sub_dialog_one = CommonChooseObjectDialog( + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + tuple(sub_dialog_one_options), + title_tokens=title_tokens, + description_tokens=description_tokens + ) + dialog.add_sub_dialog(sub_dialog_one, on_chosen=_on_sub_dialog_one_chosen) + + # Add sub dialog two. + sub_dialog_two_options = [ + ObjectPickerRow( + option_id=4, + name=CommonLocalizationUtils.create_localized_string('Value 4'), + row_description=CommonLocalizationUtils.create_localized_string(CommonStringId.TESTING_TEST_BUTTON_ONE), + row_tooltip=None, + icon=CommonIconUtils.load_checked_square_icon(), + tag='Value 4' + ), + ObjectPickerRow( + option_id=5, + name=CommonLocalizationUtils.create_localized_string('Value 5'), + row_description=CommonLocalizationUtils.create_localized_string(CommonStringId.TESTING_TEST_BUTTON_TWO), + row_tooltip=None, + icon=CommonIconUtils.load_arrow_navigate_into_icon(), + tag='Value 5' + ), + ObjectPickerRow( + option_id=6, + name=CommonLocalizationUtils.create_localized_string('Value 6'), + row_description=CommonLocalizationUtils.create_localized_string(CommonStringId.TESTING_TEST_BUTTON_TWO), + row_tooltip=None, + icon=CommonIconUtils.load_arrow_navigate_into_icon(), + tag='Value 6' + ) + ] + + sub_dialog_two = CommonChooseObjectDialog( + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + tuple(sub_dialog_two_options), + title_tokens=title_tokens, + description_tokens=description_tokens + ) + + dialog.add_sub_dialog(sub_dialog_two, on_chosen=_on_sub_dialog_two_chosen) + + # Show the dialog. + dialog.show(on_submit=_on_submit) + + :param title_identifier: The title to display in the dialog. + :type title_identifier: Union[int, str, LocalizedString, CommonStringId] + :param description_identifier: The description to display in the dialog. + :type description_identifier: Union[int, str, LocalizedString, CommonStringId] + :param title_tokens: Tokens to format into the title. + :type title_tokens: Iterator[Any], optional + :param description_tokens: Tokens to format into the description. + :type description_tokens: Iterator[Any], optional + :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. + :type mod_identity: CommonModIdentity, optional + """ + def __init__( + self, + mod_identity: CommonModIdentity, + title_identifier: Union[int, str, LocalizedString, CommonStringId], + description_identifier: Union[int, str, LocalizedString, CommonStringId], + title_tokens: Iterator[Any]=(), + description_tokens: Iterator[Any]=(), + ): + super().__init__( + title_identifier, + description_identifier, + title_tokens=title_tokens, + description_tokens=description_tokens, + mod_identity=mod_identity + ) + self._sub_dialogs: Tuple[Tuple[CommonChooseDialog, Tuple[Any], Dict[str, Any]]] = tuple() + + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + return 's4cl_multi_pane_choose_dialog' + + def add_sub_dialog(self, sub_dialog: CommonChooseDialog, *dialog_arguments: Any, **dialog_keyword_arguments: Any): + """add_sub_dialog(sub_dialog, *dialog_arguments, **dialog_keyword_arguments) + + Add a sub dialog to the dialog. + + :param sub_dialog: An instance of a choose dialog. + :type sub_dialog: CommonChooseDialog + :param dialog_arguments: Arguments to pass to the sub dialog when building it. + :type dialog_arguments: Any + :param dialog_keyword_arguments: Keyword arguments to pass to the sub dialog when building it. + :type dialog_keyword_arguments: Any + """ + self._sub_dialogs += ((sub_dialog, dialog_arguments, dialog_keyword_arguments), ) + + def show( + self, + on_submit: Callable[[Dict[int, Tuple[Any]], CommonChoiceOutcome], Any]=CommonFunctionUtils.noop, + sim_info: SimInfo=None + ): + """show(\ + on_submit=CommonFunctionUtils.noop,\ + sim_info=None\ + ) + + Show the dialog and invoke the callbacks upon the player making a choice. + + :param on_submit: A callback invoked upon the player submitting the dialog and the choices within it.\ + Default is CommonFunctionUtils.noop. Each choice is mapped as follows The key is the dialog index starting at 0. The value is the choice made within that sub dialog. + :type on_submit: Callable[[Dict[int, Tuple[Any]], CommonChoiceOutcome], Any], optional + :param sim_info: The Sim that will appear in the dialog image. The default Sim is the Active Sim. Default is None. + :type sim_info: SimInfo, optional + """ + try: + return self._show( + on_submit=on_submit, + sim_info=sim_info + ) + except Exception as ex: + self.log.error('An error occurred while running \'{}\''.format(CommonMultiPaneChooseDialog.show.__name__), exception=ex) + + def _show( + self, + on_submit: Callable[[Dict[int, Tuple[Any]], CommonChoiceOutcome], Any]=CommonFunctionUtils.noop, + sim_info: SimInfo=None + ): + self.log.debug('Attempting to display multi choose dialog.') + dialog = self.build_dialog( + on_submit=on_submit, + sim_info=sim_info + ) + dialog.show_dialog() + + # noinspection PyMissingOrEmptyDocstring + def build_dialog( + self, + on_submit: Callable[[Dict[int, Tuple[Any]], CommonChoiceOutcome], bool]=CommonFunctionUtils.noop, + sim_info: SimInfo=None + ): + dialog = self._create_dialog(sim_info=sim_info) + if dialog is None: + self.log.error('dialog was None for some reason.') + return + + if on_submit is None: + raise AssertionError('on_submit was None.') + + if len(self._sub_dialogs) == 0: + raise AssertionError('No dialogs have been added to the container. Add dialogs before attempting to display the multi pane dialog.') + + def _on_submit(_dialog: CommonUiMultiPicker) -> bool: + try: + if not _dialog.accepted: + self.log.debug('Dialog cancelled.') + return on_submit(dict(), CommonChoiceOutcome.CANCEL) + self.log.debug('Choices made, combining choices.') + index = 0 + dialog_choices: Dict[int, Tuple[Any]] = dict() + for _sub_dialog_submit_id in _dialog._picker_dialogs: + _sub_dialog_submit = _dialog._picker_dialogs[_sub_dialog_submit_id] + sub_dialog_choices: List[Any] = list() + for choice in CommonDialogUtils.get_chosen_items(_sub_dialog_submit): + sub_dialog_choices.append(choice) + dialog_choices[index] = tuple(sub_dialog_choices) + index += 1 + if not dialog_choices: + self.log.debug('No choices made. Cancelling dialog.') + return on_submit(dict(), CommonChoiceOutcome.CANCEL) + + self.log.format_with_message('Choices were made, submitting.', choice=dialog_choices) + result = on_submit(dialog_choices, CommonChoiceOutcome.CHOICE_MADE) + self.log.format_with_message('Finished handling choice.', result=result) + return result + except Exception as ex: + self.log.error('Error occurred on submitting a value.', exception=ex) + return False + + for (sub_dialog, sub_dialog_arguments, sub_dialog_keyword_arguments) in self._sub_dialogs: + sub_dialog: CommonChooseDialog = sub_dialog + # noinspection PyBroadException + try: + # Delete to prevent duplicate keyword arguments. + if 'include_pagination' in sub_dialog_keyword_arguments: + del sub_dialog_keyword_arguments['include_pagination'] + + _sub_dialog: UiDialogBase = sub_dialog.build_dialog( + *sub_dialog_arguments, + include_pagination=False, + **sub_dialog_keyword_arguments + ) + except: + _sub_dialog: UiDialogBase = sub_dialog.build_dialog( + *sub_dialog_arguments, + **sub_dialog_keyword_arguments + ) + if _sub_dialog is None: + continue + dialog.required_tooltips[_sub_dialog.dialog_id] = sub_dialog.required_tooltip + dialog._picker_dialogs[_sub_dialog.dialog_id] = _sub_dialog + + self.log.debug('Showing dialog.') + dialog.add_listener(_on_submit) + return dialog + + def _create_dialog(self, sim_info: SimInfo=None) -> Union[CommonUiMultiPicker, None]: + try: + return CommonUiMultiPicker.TunableFactory().default( + sim_info or CommonSimUtils.get_active_sim_info(), + text=lambda *args, **kwargs: self.description, + title=lambda *args, **kwargs: self.title, + text_input=None, + pickers=() + ) + except Exception as ex: + self.log.error('multi_pane_choose._create_dialog', exception=ex) + return None + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_testing.show_multi_pane_choose_dialog', + 'Show an example of CommonMultiPaneChooseDialog.' +) +def _common_testing_show_multi_pane_choose_dialog(output: CommonConsoleCommandOutput): + output('Showing test multi-pane choose dialog.') + + def _on_submit(choices_made: Dict[int, Any], outcome: CommonChoiceOutcome) -> None: + output('On Submit choices_made: {} and outcome: {}'.format(pformat(choices_made), pformat(outcome))) + + def _on_sub_dialog_one_chosen(choice: Any, outcome: CommonChoiceOutcome) -> None: + output('Sub Dialog one choice made: {} outcome: {}'.format(pformat(choice), pformat(outcome))) + + def _on_sub_dialog_two_chosen(choice: Any, outcome: CommonChoiceOutcome) -> None: + output('Sub Dialog two choice made: {} outcome: {}'.format(pformat(choice), pformat(outcome))) + + sim_info = CommonSimUtils.get_active_sim_info() + + # 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 + # Create the dialog. + dialog = CommonMultiPaneChooseDialog( + ModInfo.get_identity(), + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + title_tokens=title_tokens, + description_tokens=description_tokens + ) + + sub_dialog_one_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' + ) + ] + + # Add sub dialog one. + sub_dialog_one = CommonChooseObjectDialog( + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + tuple(sub_dialog_one_options), + title_tokens=title_tokens, + description_tokens=description_tokens + ) + dialog.add_sub_dialog(sub_dialog_one, on_chosen=_on_sub_dialog_one_chosen, sim_info=sim_info) + + # Add sub dialog two. + sub_dialog_two_options = [ + ObjectPickerRow( + option_id=4, + name=CommonLocalizationUtils.create_localized_string('Value 4'), + row_description=CommonLocalizationUtils.create_localized_string(CommonStringId.TESTING_TEST_BUTTON_ONE), + row_tooltip=None, + icon=CommonIconUtils.load_checked_square_icon(), + tag='Value 4' + ), + ObjectPickerRow( + option_id=5, + name=CommonLocalizationUtils.create_localized_string('Value 5'), + row_description=CommonLocalizationUtils.create_localized_string(CommonStringId.TESTING_TEST_BUTTON_TWO), + row_tooltip=None, + icon=CommonIconUtils.load_arrow_navigate_into_icon(), + tag='Value 5' + ), + ObjectPickerRow( + option_id=6, + name=CommonLocalizationUtils.create_localized_string('Value 6'), + row_description=CommonLocalizationUtils.create_localized_string(CommonStringId.TESTING_TEST_BUTTON_TWO), + row_tooltip=None, + icon=CommonIconUtils.load_arrow_navigate_into_icon(), + tag='Value 6' + ) + ] + + sub_dialog_two = CommonChooseObjectDialog( + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + tuple(sub_dialog_two_options), + title_tokens=title_tokens, + description_tokens=description_tokens + ) + + dialog.add_sub_dialog(sub_dialog_two, on_chosen=_on_sub_dialog_two_chosen, include_pagination=True) + + # Show the dialog. + dialog.show(on_submit=_on_submit) + output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_ok_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/common_ok_dialog.py new file mode 100644 index 0000000..eca8a6c --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/common_ok_dialog.py @@ -0,0 +1,174 @@ +""" +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 +""" +from typing import Any, Callable, Union, Iterator + +from protocolbuffers.Localization_pb2 import LocalizedString +from sims4communitylib.dialogs.common_dialog import CommonDialog +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from ui.ui_dialog import UiDialogOk + + +class CommonOkDialog(CommonDialog): + """CommonOkDialog(\ + title_identifier,\ + description_identifier,\ + title_tokens=(),\ + description_tokens=(),\ + ok_text_identifier=CommonStringId.OK,\ + ok_text_tokens=(), + mod_identity=None\ + ) + + Use to create an acknowledgement dialog. + + .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_ok_dialog` in the in-game console. + + .. highlight:: python + .. code-block:: python + + def _common_testing_show_ok_dialog(): + + def _on_acknowledged(_dialog: UiDialogOk): + if _dialog.accepted: + pass + else: + 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),) + dialog = CommonOkDialog( + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + title_tokens=title_tokens, + description_tokens=description_tokens, + ok_text_identifier=CommonLocalizationUtils.create_localized_string(CommonStringId.TESTING_TEST_BUTTON_ONE, text_color=CommonLocalizedStringColor.RED) + ) + dialog.show(on_acknowledged=_on_acknowledged) + + + :param title_identifier: A decimal identifier of the title text. + :type title_identifier: Union[int, str, LocalizedString, CommonStringId] + :param description_identifier: A decimal identifier of the description text. + :type description_identifier: Union[int, str, LocalizedString, CommonStringId] + :param title_tokens: Tokens to format into the title. + :type title_tokens: Iterator[Any], optional + :param description_tokens: Tokens to format into the description. + :type description_tokens: Iterator[Any], optional + :param ok_text_identifier: A decimal identifier for the Ok button text. + :type ok_text_identifier: Union[int, str, LocalizedString, CommonStringId], optional + :param ok_text_tokens: Tokens to format into the Ok button text. + :type ok_text_tokens: Iterator[Any], optional + :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. + :type mod_identity: CommonModIdentity, optional + """ + def __init__( + self, + title_identifier: Union[int, str, LocalizedString, CommonStringId], + description_identifier: Union[int, str, LocalizedString, CommonStringId], + title_tokens: Iterator[Any]=(), + description_tokens: Iterator[Any]=(), + ok_text_identifier: Union[int, str, LocalizedString, CommonStringId]=CommonStringId.OK, + ok_text_tokens: Iterator[Any]=(), + mod_identity: CommonModIdentity=None + ): + super().__init__( + title_identifier, + description_identifier, + title_tokens=title_tokens, + description_tokens=description_tokens, + mod_identity=mod_identity + ) + self.ok_text = CommonLocalizationUtils.create_localized_string(ok_text_identifier, tokens=tuple(ok_text_tokens)) + + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + return 's4cl_ok_dialog' + + def show( + self, + on_acknowledged: Callable[[UiDialogOk], Any]=CommonFunctionUtils.noop + ): + """show(\ + on_acknowledged=CommonFunctionUtils.noop\ + ) + + Show the dialog and invoke the callback upon the player acknowledging the dialog. + + :param on_acknowledged: Invoked upon the player acknowledging (Hitting Ok) or closing the dialog. + :type on_acknowledged: Callable[[UiDialogOk], Any], optional + """ + try: + return self._show( + on_acknowledged=on_acknowledged + ) + except Exception as ex: + self.log.error('show', exception=ex) + + def _show( + self, + on_acknowledged: Callable[[UiDialogOk], Any]=CommonFunctionUtils.noop + ): + self.log.format_with_message('Attempting to display dialog.') + _dialog = self._create_dialog() + if _dialog is None: + self.log.debug('Failed to create dialog.') + return + + _dialog.add_listener(on_acknowledged) + self.log.debug('Displaying dialog.') + _dialog.show_dialog() + + def _create_dialog(self) -> Union[UiDialogOk, None]: + try: + return UiDialogOk.TunableFactory().default( + CommonSimUtils.get_active_sim_info(), + text=lambda *_, **__: self.description, + title=lambda *_, **__: self.title, + text_ok=lambda *_, **__: self.ok_text + ) + except Exception as ex: + self.log.error('_create_dialog', exception=ex) + return None + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_testing.show_ok_dialog', + 'Show an example of CommonPurchaseObjectsDialog.' +) +def _common_testing_show_ok_dialog(output: CommonConsoleCommandOutput): + output('Showing test ok dialog.') + + def _on_acknowledged(_dialog: UiDialogOk): + if _dialog.accepted: + output('Ok option chosen.') + else: + output('Dialog closed.') + + # 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),) + dialog = CommonOkDialog( + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + title_tokens=title_tokens, + description_tokens=description_tokens, + ok_text_identifier=CommonLocalizationUtils.create_localized_string(CommonStringId.TESTING_TEST_BUTTON_ONE, text_color=CommonLocalizedStringColor.RED) + ) + dialog.show(on_acknowledged=_on_acknowledged) + output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_purchase_objects_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/common_purchase_objects_dialog.py new file mode 100644 index 0000000..f8d625e --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/common_purchase_objects_dialog.py @@ -0,0 +1,393 @@ +""" +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 +""" +from collections import namedtuple + +from typing import Tuple, Any, Callable, Union, Iterator, List + +from pprint import pformat + +from interactions.base.picker_interaction import PurchasePickerData +from protocolbuffers.Localization_pb2 import LocalizedString +from sims.sim_info import SimInfo +from sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome +from sims4communitylib.dialogs.common_choose_dialog import CommonChooseDialog +from sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_option_category import \ + CommonDialogObjectOptionCategory +from sims4communitylib.enums.common_object_delivery_method import CommonObjectDeliveryMethod +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.enums.tags_enum import CommonGameTag +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from sims4communitylib.utils.common_icon_utils import CommonIconUtils +from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils +from sims4communitylib.utils.sims.common_sim_inventory_utils import CommonSimInventoryUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from ui.ui_dialog_picker import UiObjectPicker, UiPurchasePicker, PurchasePickerRow, UiDialogObjectPicker + + +class CommonPurchaseObjectsDialog(CommonChooseDialog): + """CommonPurchaseObjectsDialog(\ + mod_identity,\ + title_identifier,\ + description_identifier,\ + purchasable_object_rows,\ + title_tokens=(),\ + description_tokens=(),\ + required_tooltip=None,\ + required_tooltip_tokens=()\ + ) + + Create a dialog that allows the player to purchase some objects. + + .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_purchase_objects_dialog` in the in-game console. + + .. highlight:: python + .. code-block:: python + + def _common_testing_show_purchase_objects_dialog(): + def _on_chosen(choices: Any, outcome: CommonChoiceOutcome): + output('Chose {} with result: {}.'.format(pformat(choices), pformat(outcome))) + + # 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),) + show_discount = True + from sims4communitylib.utils.common_icon_utils import CommonIconUtils + active_sim_info = CommonSimUtils.get_active_sim_info() + obj_id = 20359 + obj_definition = CommonObjectUtils.get_object_definition(obj_id) + tags = obj_definition.build_buy_tags + options = [ + PurchasePickerRow( + def_id=obj_definition.id, + num_owned=CommonSimInventoryUtils.get_count_of_object_in_inventory(active_sim_info, obj_id), + tags=obj_definition.build_buy_tags, + num_available=2000, + custom_price=50, + objects=tuple(), + show_discount=show_discount, + icon_info_data_override=None, # Should be an instance of IconInfoData + is_enable=True, + row_tooltip=None, + row_description=None + ), + ] + categories = list() + for tag in tags: + tag_name = CommonGameTag.value_to_name.get(tag, None) + if tag_name is None: + continue + categories.append(CommonDialogObjectOptionCategory(tag, obj_definition.icon, category_name=tag_name)) + dialog = CommonPurchaseObjectsDialog( + ModInfo.get_identity(), + 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_chosen=_on_chosen, categories=categories) + + :param title_identifier: The title to display in the dialog. + :type title_identifier: Union[int, str, LocalizedString, CommonStringId] + :param description_identifier: The description to display in the dialog. + :type description_identifier: Union[int, str, LocalizedString, CommonStringId] + :param purchasable_objects: The objects that may be purchased + :type purchasable_objects: Iterator[PurchasePickerRow] + :param title_tokens: Tokens to format into the title. + :type title_tokens: Iterator[Any], optional + :param description_tokens: Tokens to format into the description. + :type description_tokens: Iterator[Any], optional + :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. + :type mod_identity: CommonModIdentity, optional + :param required_tooltip: If provided, this text will display when the dialog requires at least one choice and a choice has not been made. Default is None. + :type required_tooltip: Union[int, str, LocalizedString, CommonStringId], optional + :param required_tooltip_tokens: Tokens to format into the required tooltip. Default is an empty collection. + :type required_tooltip_tokens: Iterator[Any], optional + """ + def __init__( + self, + mod_identity: CommonModIdentity, + title_identifier: Union[int, str, LocalizedString, CommonStringId], + description_identifier: Union[int, str, LocalizedString, CommonStringId], + purchasable_objects: Iterator[PurchasePickerRow], + title_tokens: Iterator[Any] = (), + description_tokens: Iterator[Any] = (), + required_tooltip: Union[int, str, LocalizedString, CommonStringId] = None, + required_tooltip_tokens: Iterator[Any] = () + ): + super().__init__( + title_identifier, + description_identifier, + purchasable_objects, + title_tokens=title_tokens, + description_tokens=description_tokens, + mod_identity=mod_identity, + required_tooltip=required_tooltip, + required_tooltip_tokens=required_tooltip_tokens + ) + + # noinspection PyMissingOrEmptyDocstring + @property + def rows(self) -> Tuple[PurchasePickerRow]: + # noinspection PyTypeChecker + result: Tuple[PurchasePickerRow] = super().rows + return result + + # noinspection PyMissingOrEmptyDocstring + def add_row(self, choice: PurchasePickerRow, *_, **__): + """add_row(row, *_, **__) + + Add a row to the dialog. + + :param choice: The row to add. + :type choice: PurchasePickerRow + """ + super().add_row(choice, *_, **__) + + def show( + self, + on_chosen: Callable[[Any, CommonChoiceOutcome], Any] = CommonFunctionUtils.noop, + target_sim_info_to_receive_objects: SimInfo = None, + categories: Iterator[CommonDialogObjectOptionCategory] = (), + object_delivery_method: CommonObjectDeliveryMethod = CommonObjectDeliveryMethod.INVENTORY + ): + """show(\ + on_chosen=CommonFunctionUtils.noop,\ + target_sim_info_to_receive_objects=None,\ + categories=(),\ + object_delivery_method=CommonObjectDeliveryMethod.INVENTORY,\ + ) + + Show the dialog and invoke the callbacks upon the player making a choice. + + :param on_chosen: A callback invoked upon the player choosing something from the list. Default is CommonFunctionUtils.noop. + :type on_chosen: Callable[[Any, CommonChoiceOutcome], optional + :param target_sim_info_to_receive_objects: The Sim that will appear in the dialog image. They will also be the receiver of purchased objects if object_delivery_method is set to INVENTORY. The default Sim is the Active Sim. Default is None. + :type target_sim_info_to_receive_objects: SimInfo, optional + :param categories: A collection of categories to display in the dialog. They will appear in a drop down above the rows. Default is an empty collection. + :type categories: Iterator[CommonDialogObjectOptionCategory], optional + :param object_delivery_method: The method of delivery for purchased objects. If set to INVENTORY, objects that are purchased will be immediately available within the inventory of the specified Sim or the Active Sim if no Sim is specified.\ + If set to MAIL, objects that are purchased will be delivered via the Mail Man. They may also appear within the Household Inventory upon the mail being delivered. Default is INVENTORY. + :type object_delivery_method: CommonObjectDeliveryMethod, optional + """ + try: + if object_delivery_method is CommonObjectDeliveryMethod.NONE: + raise AssertionError('object_delivery_method was set to NONE.') + return self._show( + on_chosen=on_chosen, + target_sim_info_to_receive_objects=target_sim_info_to_receive_objects, + categories=categories, + object_delivery_method=object_delivery_method + ) + except Exception as ex: + self.log.error('An error occurred while running \'{}\''.format(CommonPurchaseObjectsDialog.show.__name__), exception=ex) + + def _show( + self, + on_chosen: Callable[[Any, CommonChoiceOutcome], bool] = CommonFunctionUtils.noop, + target_sim_info_to_receive_objects: SimInfo = None, + categories: Iterator[CommonDialogObjectOptionCategory] = (), + object_delivery_method: CommonObjectDeliveryMethod = CommonObjectDeliveryMethod.INVENTORY + ): + def _on_chosen(choice: Any, outcome: CommonChoiceOutcome) -> bool: + try: + self.log.debug('Choice made.') + self.log.format_with_message('Choose Object Choice made.', choice=choice) + result = on_chosen(choice, outcome) + self.log.format_with_message('Finished handling choose object _show.', result=result) + return result + except Exception as ex: + self.log.error('Error occurred on choosing a value.', exception=ex) + return False + + _dialog = self.build_dialog( + on_chosen=_on_chosen, + target_sim_info_to_receive_objects=target_sim_info_to_receive_objects, + categories=categories, + object_delivery_method=object_delivery_method + ) + if not _dialog: + raise AssertionError('Failed to create the purchase objects dialog.') + self.log.debug('Showing dialog.') + _dialog.show_dialog() + + # noinspection PyMissingOrEmptyDocstring + def build_dialog( + self, + on_chosen: Callable[[Any, CommonChoiceOutcome], bool] = CommonFunctionUtils.noop, + target_sim_info_to_receive_objects: SimInfo = None, + categories: Iterator[CommonDialogObjectOptionCategory] = (), + object_delivery_method: CommonObjectDeliveryMethod = CommonObjectDeliveryMethod.INVENTORY + ) -> Union[UiPurchasePicker, None]: + self.log.format_with_message('Attempting to build dialog.', categories=categories) + + _dialog = self._create_dialog( + categories=categories, + target_sim_info_to_receive_objects=target_sim_info_to_receive_objects, + object_delivery_method=object_delivery_method + ) + if _dialog is None: + self.log.error('_dialog was None for some reason.') + return + + if on_chosen is None: + raise ValueError('on_chosen was None.') + + if len(self.rows) == 0: + raise AssertionError('No rows have been provided. Add rows to the dialog before attempting to display it.') + + def _on_chosen(dialog: UiPurchasePicker) -> bool: + try: + self.log.format_with_message('Choice made.', picked_results=dialog.picked_results) + if not dialog.accepted: + self.log.debug('Dialog cancelled.') + return on_chosen(None, CommonChoiceOutcome.CANCEL) + self.log.debug('Dialog accepted, checking if choices were made.') + choices = dialog.get_result_definitions_and_counts() + zipped_choices = zip(choices[0], choices[1]) + self.log.format_with_message('Purchase Objects choice made.', choice=zipped_choices) + outcome = CommonChoiceOutcome.CHOICE_MADE + if not choices: + outcome = CommonChoiceOutcome.CANCEL + result = on_chosen(zipped_choices, outcome) + self.log.format_with_message('Finished handling purchase objects _on_chosen.', result=result) + return result + except Exception as ex: + self.log.error('Error occurred on choosing a value.', exception=ex) + return False + + self._setup_dialog_rows( + _dialog + ) + + self.log.debug('Adding listener.') + _dialog.add_listener(_on_chosen) + return _dialog + + def _setup_dialog_rows( + self, + _dialog: UiPurchasePicker + ): + self.log.debug('Adding rows.') + for row in self.rows: + _dialog.add_row(row) + + def _create_dialog( + self, + picker_type: UiObjectPicker.UiObjectPickerObjectPickerType = UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT, + target_sim_info_to_receive_objects: SimInfo = None, + categories: Iterator[CommonDialogObjectOptionCategory] = (), + object_delivery_method: CommonObjectDeliveryMethod = CommonObjectDeliveryMethod.INVENTORY + ) -> Union[UiPurchasePicker, None]: + try: + category_type = namedtuple('category_type', ('tag', 'icon', 'tooltip')) + dialog_categories = list() + for category in tuple(categories): + dialog_categories.append( + category_type( + category.object_category, + CommonIconUtils._load_icon(category.icon), + CommonLocalizationUtils.create_localized_string(category.category_name) + ) + ) + + target_to_receive_sim_info = target_sim_info_to_receive_objects or CommonSimUtils.get_active_sim_info() + inventory_target_id = CommonSimUtils.get_sim_id(target_to_receive_sim_info) + purchase_objects: List[int] = list() + dialog = UiPurchasePicker.TunableFactory().default( + target_to_receive_sim_info, + text=lambda *_, **__: self.description, + title=lambda *_, **__: self.title, + categories=dialog_categories, + max_selectable=UiDialogObjectPicker._MaxSelectableUnlimited() + ) + purchase_picker_data = PurchasePickerData() + if object_delivery_method == CommonObjectDeliveryMethod.INVENTORY: + purchase_picker_data.inventory_owner_id_to_purchase_to = inventory_target_id + if object_delivery_method == CommonObjectDeliveryMethod.MAIL: + purchase_picker_data.delivery_method = CommonObjectDeliveryMethod.convert_to_vanilla(object_delivery_method) + if object_delivery_method == CommonObjectDeliveryMethod.DELIVERY_SERVICE: + purchase_picker_data.delivery_method = CommonObjectDeliveryMethod.convert_to_vanilla(object_delivery_method) + for purchase_object in purchase_objects: + purchase_picker_data.add_definition_to_purchase(purchase_object) + dialog.set_target_sim(CommonSimUtils.get_sim_instance(target_to_receive_sim_info)) + dialog.object_id = purchase_picker_data.inventory_owner_id_to_purchase_to + dialog.inventory_object_id = purchase_picker_data.inventory_owner_id_to_purchase_from + dialog.purchase_by_object_ids = purchase_picker_data.use_obj_ids_in_response + dialog.delivery_method = purchase_picker_data.delivery_method + dialog.show_description = 1 + dialog.show_description_tooltip = 1 + dialog.use_dialog_pick_response = True + dialog.max_selectable_num = len(self.rows) + dialog.use_dropdown_filter = len(dialog_categories) > 0 + right_custom_text = None + if right_custom_text is not None: + dialog.right_custom_text = right_custom_text + return dialog + except Exception as ex: + self.log.error('_create_dialog', exception=ex) + return None + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_testing.show_purchase_objects_dialog', + 'Show an example of CommonPurchaseObjectsDialog.' +) +def _common_testing_show_purchase_objects_dialog(output: CommonConsoleCommandOutput): + output('Showing test purchase object dialog.') + + def _on_chosen(choices: str, outcome: CommonChoiceOutcome): + output('Chose {} with result: {}.'.format(pformat(choices), pformat(outcome))) + + # 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),) + show_discount = True + active_sim_info = CommonSimUtils.get_active_sim_info() + obj_id = 20359 + obj_definition = CommonObjectUtils.get_object_definition(obj_id) + tags = obj_definition.build_buy_tags + options = [ + PurchasePickerRow( + def_id=obj_definition.id, + num_owned=CommonSimInventoryUtils.get_count_of_object_in_inventory(active_sim_info, obj_id), + tags=obj_definition.build_buy_tags, + num_available=2000, + custom_price=50, + objects=tuple(), + show_discount=show_discount, + icon_info_data_override=None, # Should be an instance of IconInfoData + is_enable=True, + row_tooltip=None, + row_description=None + ), + ] + categories = list() + for tag in tags: + tag_name = CommonGameTag.value_to_name.get(tag, None) + if tag_name is None: + continue + categories.append(CommonDialogObjectOptionCategory(tag, obj_definition.icon, category_name=tag_name)) + dialog = CommonPurchaseObjectsDialog( + ModInfo.get_identity(), + 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.log.enable() + dialog.show(on_chosen=_on_chosen, categories=categories) + output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_targeted_question_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/common_targeted_question_dialog.py new file mode 100644 index 0000000..6d44f6f --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/common_targeted_question_dialog.py @@ -0,0 +1,223 @@ +""" +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 +""" +from typing import Any, Callable, Union, Iterator + +from event_testing.resolver import DoubleSimResolver +from protocolbuffers.Localization_pb2 import LocalizedString +from sims.sim_info import SimInfo +from sims4communitylib.dialogs.common_dialog import CommonDialog +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from ui.ui_dialog import UiDialogOkCancel + + +class CommonTargetedQuestionDialog(CommonDialog): + """CommonTargetedQuestionDialog(\ + question_text,\ + question_tokens=(),\ + ok_text_identifier=CommonStringId.OK,\ + ok_text_tokens=(),\ + cancel_text_identifier=CommonStringId.CANCEL,\ + cancel_text_tokens=(),\ + mod_identity=None\ + ) + + A Sim to Sim question dialog. + + .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_targeted_question_dialog` in the in-game console. + + .. highlight:: python + .. code-block:: python + + def _common_testing_show_targeted_question_dialog(): + + def _ok_chosen(_: UiDialogOkCancel): + pass + + def _cancel_chosen(_: UiDialogOkCancel): + pass + + # LocalizedStrings within other LocalizedStrings + 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),) + dialog = CommonTargetedQuestionDialog( + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + question_tokens=description_tokens, + ok_text_identifier=CommonLocalizationUtils.create_localized_string(CommonStringId.TESTING_TEST_BUTTON_ONE, text_color=CommonLocalizedStringColor.RED), + cancel_text_identifier=CommonStringId.TESTING_TEST_BUTTON_TWO + ) + dialog.show( + CommonSimUtils.get_active_sim_info(), + tuple(CommonSimUtils.get_sim_info_for_all_sims_generator())[0], + on_ok_selected=_ok_chosen, + on_cancel_selected=_cancel_chosen + ) + + + :param question_text: A decimal identifier of the question text. + :type question_text: Union[int, str, LocalizedString, CommonStringId] + :param question_tokens: Tokens to format into the question text. + :type question_tokens: Iterator[Any], optional + :param ok_text_identifier: A decimal identifier for the Ok text. + :type ok_text_identifier: Union[int, str, LocalizedString, CommonStringId], optional + :param ok_text_tokens: Tokens to format into the Ok text. + :type ok_text_tokens: Iterator[Any], optional + :param cancel_text_identifier: A decimal identifier for the Cancel text. + :type cancel_text_identifier: Union[int, str, LocalizedString, CommonStringId], optional + :param cancel_text_tokens: Tokens to format into the Cancel text. + :type cancel_text_tokens: Iterator[Any], optional + :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. + :type mod_identity: CommonModIdentity, optional + """ + def __init__( + self, + question_text: Union[int, str, LocalizedString, CommonStringId], + question_tokens: Iterator[Any]=(), + ok_text_identifier: Union[int, str, LocalizedString, CommonStringId]=CommonStringId.OK, + ok_text_tokens: Iterator[Any]=(), + cancel_text_identifier: Union[int, str, LocalizedString, CommonStringId]=CommonStringId.CANCEL, + cancel_text_tokens: Iterator[Any]=(), + mod_identity: CommonModIdentity=None + ): + super().__init__( + 0, + question_text, + description_tokens=question_tokens, + mod_identity=mod_identity + ) + self.ok_text = CommonLocalizationUtils.create_localized_string(ok_text_identifier, tokens=tuple(ok_text_tokens)) + self.cancel_text = CommonLocalizationUtils.create_localized_string(cancel_text_identifier, tokens=tuple(cancel_text_tokens)) + + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + return 's4cl_targeted_question_dialog' + + def show( + self, + sim_info: SimInfo, + target_sim_info: SimInfo, + on_ok_selected: Callable[[UiDialogOkCancel], Any]=CommonFunctionUtils.noop, + on_cancel_selected: Callable[[UiDialogOkCancel], Any]=CommonFunctionUtils.noop + ): + """show(\ + sim_info,\ + target_sim_info,\ + on_ok_selected=CommonFunctionUtils.noop,\ + on_cancel_selected=CommonFunctionUtils.noop\ + ) + + Show the dialog and invoke the callbacks upon the player making a choice. + + :param sim_info: The Sim that is the source of the question. + :type sim_info: SimInfo + :param target_sim_info: The Sim that is the target of the question. + :type target_sim_info: SimInfo + :param on_ok_selected: Invoked upon the player clicking the Ok button in the dialog. + :type on_ok_selected: Callable[[UiDialogOkCancel], Any], optional + :param on_cancel_selected: Invoked upon the player clicking the Cancel button in the dialog. + :type on_cancel_selected: Callable[[UiDialogOkCancel], Any], optional + """ + try: + return self._show( + sim_info, + target_sim_info, + on_ok_selected=on_ok_selected, + on_cancel_selected=on_cancel_selected + ) + except Exception as ex: + self.log.error('show', exception=ex) + + def _show( + self, + sim_info: SimInfo, + target_sim_info: SimInfo, + on_ok_selected: Callable[[UiDialogOkCancel], bool]=CommonFunctionUtils.noop, + on_cancel_selected: Callable[[UiDialogOkCancel], bool]=CommonFunctionUtils.noop + ): + self.log.format_with_message( + 'Attempting to display dialog.', + sim=CommonSimNameUtils.get_full_name(sim_info), + target=CommonSimNameUtils.get_full_name(target_sim_info) + ) + _dialog = self._create_dialog(sim_info, target_sim_info) + if _dialog is None: + self.log.debug('Failed to create dialog.') + return + + def _on_option_selected(dialog: UiDialogOkCancel) -> bool: + try: + self.log.debug('Option selected.') + if dialog.accepted: + self.log.debug('Ok chosen.') + return on_ok_selected(dialog) + self.log.debug('Cancel chosen.') + return on_cancel_selected(dialog) + except Exception as ex: + self.log.error('Error occurred on choosing an option.', exception=ex) + return False + + _dialog.add_listener(_on_option_selected) + self.log.debug('Displaying dialog.') + _dialog.show_dialog() + + def _create_dialog( + self, + sim_info: SimInfo, + target_sim_info: SimInfo + ) -> Union[UiDialogOkCancel, None]: + try: + return UiDialogOkCancel.TunableFactory().default( + sim_info, + text=lambda *_, **__: self.description, + text_ok=lambda *_, **__: self.ok_text, + text_cancel=lambda *_, **__: self.cancel_text, + target_sim_id=CommonSimUtils.get_sim_id(target_sim_info), + resolver=DoubleSimResolver(sim_info, target_sim_info) + ) + except Exception as ex: + self.log.error('_create_dialog', exception=ex) + return None + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_testing.show_targeted_question_dialog', + 'Show an example of CommonTargetedQuestionDialog.' +) +def _common_testing_show_targeted_question_dialog(output: CommonConsoleCommandOutput): + output('Showing test targeted question dialog.') + + def _ok_chosen(_: UiDialogOkCancel): + output('Ok option chosen.') + + def _cancel_chosen(_: UiDialogOkCancel): + output('Cancel option chosen.') + + # LocalizedStrings within other LocalizedStrings + 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),) + dialog = CommonTargetedQuestionDialog( + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + question_tokens=description_tokens, + ok_text_identifier=CommonLocalizationUtils.create_localized_string(CommonStringId.TESTING_TEST_BUTTON_ONE, text_color=CommonLocalizedStringColor.RED), + cancel_text_identifier=CommonStringId.TESTING_TEST_BUTTON_TWO + ) + dialog.show( + CommonSimUtils.get_active_sim_info(), + tuple(CommonSimUtils.get_sim_info_for_all_sims_generator())[0], + on_ok_selected=_ok_chosen, + on_cancel_selected=_cancel_chosen + ) + output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_ui_dialog_response.py b/Scripts/s4ap/sims4communitylib/dialogs/common_ui_dialog_response.py new file mode 100644 index 0000000..7bfb7d9 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/common_ui_dialog_response.py @@ -0,0 +1,38 @@ +""" +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 +""" +from typing import Any, Union +from protocolbuffers.Localization_pb2 import LocalizedString +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from ui.ui_dialog import UiDialogResponse + + +class CommonUiDialogResponse(UiDialogResponse): + """ A dialog response. """ + def __init__( + self, + dialog_response_id: int, + value: Any, + sort_order: int=0, + text: Union[int, str, LocalizedString, CommonStringId]=None, + subtext: Union[int, str, LocalizedString, CommonStringId]=None, + ui_request: UiDialogResponse.UiDialogUiRequest=UiDialogResponse.UiDialogUiRequest.NO_REQUEST, + response_command: Any=None, + disabled_text: Union[int, str, LocalizedString, CommonStringId]=None + ): + super().__init__( + sort_order=sort_order, + dialog_response_id=dialog_response_id, + text=lambda *_, **__: CommonLocalizationUtils.create_localized_string(text) if text is not None else None, + subtext=CommonLocalizationUtils.create_localized_string(subtext) if subtext is not None else None, + ui_request=ui_request, + response_command=response_command, + disabled_text=CommonLocalizationUtils.create_localized_string(disabled_text) if disabled_text is not None else None + ) + self.response_id = int(dialog_response_id) + self.value = value diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_ui_response_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/common_ui_response_dialog.py new file mode 100644 index 0000000..c4b08b5 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/common_ui_response_dialog.py @@ -0,0 +1,157 @@ +""" +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 +""" +from sims4communitylib.dialogs.common_ui_dialog_response import CommonUiDialogResponse +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from ui.ui_dialog import UiDialog, UiDialogOption +from typing import Tuple, Any, Iterator + +from event_testing.resolver import Resolver +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.logging.has_class_log import HasClassLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + + +class CommonUiResponseDialog(UiDialog, HasClassLog): + """CommonUiResponseDialog(owner, responses, *args, resolver=None, target_sim_id=None, dialog_options=UiDialogOption.DISABLE_CLOSE_BUTTON, **kwargs) + + A dialog that displays various responses for the player to choose from. + + :param owner: The owner of the dialog. + :type owner: Any + :param responses: An iteration of responses the player may choose. + :type responses: Iterator[CommonUiDialogResponse] + :param resolver: A resolver used to determine the display name of responses. Default is None. + :type resolver: Resolver, optional + :param target_sim_id: The Sim Id of the Target the response is directed at. Default is None. + :type target_sim_id: int, optional + :param dialog_options: Flags used to change how the dialog appears or functions. Default is UiDialogOption.DISABLE_CLOSE_BUTTON. + :type dialog_options: UiDialogOption, optional + """ + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + return ModInfo.get_identity() + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 'common_ui_response_dialog' + + def __init__( + self, + owner: Any, + responses: Iterator[CommonUiDialogResponse], + *args, + resolver: Resolver=None, + target_sim_id: int=None, + dialog_options: UiDialogOption=UiDialogOption.DISABLE_CLOSE_BUTTON, + **kwargs + ): + super().__init__( + owner, + *args, + resolver=resolver, + target_sim_id=target_sim_id, + dialog_options=dialog_options, + **kwargs + ) + HasClassLog.__init__(self) + self._response_value = None + self._responses = tuple(responses) + + @property + def accepted(self) -> bool: + """Whether or not a response was chosen.""" + return self.response != CommonUiResponseDialog._PREVIOUS_BUTTON_ID and self.response != CommonUiResponseDialog._NEXT_BUTTON_ID + + @property + def cancelled(self) -> bool: + """Whether not the dialog was cancelled.""" + return self.response < 0 + + def add_response(self, response: CommonUiDialogResponse): + """add_response(response) + + Add a response to the dialog. + + :param response: The response to add. + :type response: CommonUiDialogResponse + """ + self._responses += (response,) + + def get_response(self) -> Any: + """Retrieve the chosen response. If there is one.""" + return self.response + + def get_response_value(self) -> Any: + """Retrieve the chosen response value. If there is one.""" + return self._response_value + + def respond(self, chosen_response: int) -> bool: + """When the player makes a choice, this function is invoked.""" + try: + self.log.format_with_message('Chosen response', response=chosen_response) + self.response = chosen_response + if chosen_response < 0: + self._response_value = None + else: + self._response_value = None + for response in self._get_responses_gen(): + if response.response_id == chosen_response: + self._response_value = response.value + self._listeners(self) + return True + except Exception as ex: + self.log.error('Error occurred while attempting to respond.', exception=ex) + return False + finally: + self.on_response_received() + + def _get_responses_gen(self) -> Iterator[CommonUiDialogResponse]: + yield from super()._get_responses_gen() + + @property + def responses(self) -> Tuple[CommonUiDialogResponse]: + """The responses of the dialog.""" + result: Tuple[CommonUiDialogResponse] = ( + *self._responses, + ) + return result + + +@CommonConsoleCommand(ModInfo.get_identity(), 's4clib_testing.show_ui_response_dialog', 'Show an example of UI Response Dialog.', show_with_help_command=False) +def _common_testing_show_ui_response_dialog(output: CommonConsoleCommandOutput): + output('Showing test ui response dialog.') + + def _on_chosen(_: CommonUiResponseDialog): + response_value = _.get_response_value() + output('Chosen value {}'.format(response_value if response_value is not None else 'No value chosen.')) + + responses: Tuple[CommonUiDialogResponse] = ( + CommonUiDialogResponse(0, 'one', text='Button one'), + CommonUiDialogResponse(1, 'two', text='Button two') + ) + title = CommonLocalizationUtils.create_localized_string(CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, tokens=(CommonLocalizationUtils.create_localized_string(CommonStringId.TESTING_SOME_TEXT_FOR_TESTING, text_color=CommonLocalizedStringColor.GREEN), )) + description = CommonLocalizationUtils.create_localized_string(CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, 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), )) + + active_sim_info = CommonSimUtils.get_active_sim_info() + dialog = CommonUiResponseDialog.TunableFactory().default( + active_sim_info, + responses, + # Having a value of 0 means that we want to display the Close button with no other dialog options. + dialog_options=0, + text=lambda *_, **__: description, + title=lambda *_, **__: title + ) + dialog.add_listener(_on_chosen) + dialog.show_dialog() diff --git a/Scripts/s4ap/sims4communitylib/dialogs/custom_dialogs/__init__.py b/Scripts/s4ap/sims4communitylib/dialogs/custom_dialogs/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/custom_dialogs/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/dialogs/custom_dialogs/picker_dialogs/__init__.py b/Scripts/s4ap/sims4communitylib/dialogs/custom_dialogs/picker_dialogs/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/custom_dialogs/picker_dialogs/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/dialogs/custom_dialogs/picker_dialogs/common_ui_multi_picker.py b/Scripts/s4ap/sims4communitylib/dialogs/custom_dialogs/picker_dialogs/common_ui_multi_picker.py new file mode 100644 index 0000000..b9a7b79 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/custom_dialogs/picker_dialogs/common_ui_multi_picker.py @@ -0,0 +1,48 @@ +""" +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 +""" +from typing import Any, Dict +from protocolbuffers.Localization_pb2 import LocalizedString +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from protocolbuffers.Dialog_pb2 import UiDialogMessage, UiDialogMultiPicker +from ui.ui_dialog_multi_picker import UiMultiPicker + + +class CommonUiMultiPicker(UiMultiPicker): + """CommonUiMultiPicker(\ + *args,\ + **kwargs\ + ) + + A custom multi picker dialog that enables programmatic creation. + + """ + def __init__(self, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + self.required_tooltips: Dict[Any, LocalizedString] = dict() + + def build_msg(self, **kwargs) -> Any: + """build_msg(**kwargs) + + Build the message for display. + + :return: Unknown. + :rtype: Any + """ + message = super().build_msg(**kwargs) + # noinspection PyUnresolvedReferences + message.dialog_type = UiDialogMessage.MULTI_PICKER + multi_picker_msg = UiDialogMultiPicker() + for dialog in self._picker_dialogs.values(): + new_message = dialog.build_msg() + # noinspection PyUnresolvedReferences + multi_picker_item = multi_picker_msg.multi_picker_items.add() + multi_picker_item.picker_data = new_message.picker_data + multi_picker_item.picker_id = new_message.dialog_id + multi_picker_item.disabled_tooltip = self.required_tooltips.get(new_message.dialog_id, None) or CommonLocalizationUtils.create_localized_string('') + message.multi_picker_data = multi_picker_msg + return message diff --git a/Scripts/s4ap/sims4communitylib/dialogs/custom_dialogs/picker_dialogs/common_ui_object_category_picker.py b/Scripts/s4ap/sims4communitylib/dialogs/custom_dialogs/picker_dialogs/common_ui_object_category_picker.py new file mode 100644 index 0000000..406e9c5 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/custom_dialogs/picker_dialogs/common_ui_object_category_picker.py @@ -0,0 +1,51 @@ +""" +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 +""" +from distributor.rollback import ProtocolBufferRollback +from interactions.utils.tunable_icon import TunableIconFactory +from sims4.localization import TunableLocalizedString +from sims4.tuning.tunable import TunableTuple, TunableList, Tunable +from ui.ui_dialog_picker import UiObjectPicker +from distributor.shared_messages import build_icon_info_msg + + +class CommonUiObjectCategoryPicker(UiObjectPicker): + """An ObjectPicker with categories listed in a drop down. + + """ + FACTORY_TUNABLES = { + 'object_categories': TunableList( + description='\n The categories to display in the drop down for this picker.\n ', + tunable=TunableTuple( + object_category=Tunable( + tunable_type=str, + default='ALL' + ), + icon=TunableIconFactory(), + category_name=TunableLocalizedString() + ) + ) + } + + def _build_customize_picker(self, picker_data) -> None: + # noinspection PyBroadException + try: + with ProtocolBufferRollback(picker_data.filter_data) as filter_data_list: + for category in self.object_categories: + with ProtocolBufferRollback(filter_data_list.filter_data) as category_data: + category_data.tag_type = abs(hash(category.object_category)) % (10 ** 8) + build_icon_info_msg(category.icon(None), None, category_data.icon_info) + category_data.description = category.category_name + filter_data_list.use_dropdown_filter = self.use_dropdown_filter + super()._build_customize_picker(picker_data) + except: + with ProtocolBufferRollback(picker_data.filter_data) as category_data: + for category in self.object_categories: + category_data.tag_type = abs(hash(category.object_category)) % (10 ** 8) + build_icon_info_msg(category.icon(None), None, category_data.icon_info) + category_data.description = category.category_name + super()._build_customize_picker(picker_data) diff --git a/Scripts/s4ap/sims4communitylib/dialogs/ok_cancel_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/ok_cancel_dialog.py new file mode 100644 index 0000000..cd34a2e --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/ok_cancel_dialog.py @@ -0,0 +1,199 @@ +""" +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 +""" +from typing import Any, Callable, Union, Iterator + +from protocolbuffers.Localization_pb2 import LocalizedString +from sims4communitylib.dialogs.common_dialog import CommonDialog +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from ui.ui_dialog import UiDialogOkCancel + + +class CommonOkCancelDialog(CommonDialog): + """CommonOkCancelDialog(\ + title_identifier,\ + description_identifier,\ + title_tokens=(),\ + description_tokens=(),\ + ok_text_identifier=CommonStringId.OK,\ + ok_text_tokens=(),\ + cancel_text_identifier=CommonStringId.CANCEL,\ + cancel_text_tokens=(),\ + mod_identity=None\ + ) + + Use to create a prompt dialog. + + .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_ok_cancel_dialog` in the in-game console. + + .. highlight:: python + .. code-block:: python + + def _common_testing_show_ok_cancel_dialog(): + + def _ok_chosen(_: UiDialogOkCancel): + pass + + def _cancel_chosen(_: UiDialogOkCancel): + 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),) + dialog = CommonOkCancelDialog( + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + title_tokens=title_tokens, + description_tokens=description_tokens, + ok_text_identifier=CommonLocalizationUtils.create_localized_string(CommonStringId.TESTING_TEST_BUTTON_ONE, text_color=CommonLocalizedStringColor.RED), + cancel_text_identifier=CommonStringId.TESTING_TEST_BUTTON_TWO + ) + dialog.show(on_ok_selected=_ok_chosen, on_cancel_selected=_cancel_chosen) + + :param title_identifier: A decimal identifier of the title text. + :type title_identifier: Union[int, str, LocalizedString, CommonStringId] + :param description_identifier: A decimal identifier of the description text. + :type description_identifier: Union[int, str, LocalizedString, CommonStringId] + :param title_tokens: Tokens to format into the title. + :type title_tokens: Iterator[Any], optional + :param description_tokens: Tokens to format into the description. + :type description_tokens: Iterator[Any], optional + :param ok_text_identifier: A decimal identifier for the Ok text. + :type ok_text_identifier: Union[int, str, LocalizedString, CommonStringId], optional + :param ok_text_tokens: Tokens to format into the Ok text. + :type ok_text_tokens: Iterator[Any], optional + :param cancel_text_identifier: A decimal identifier for the Cancel text. + :type cancel_text_identifier: Union[int, str, LocalizedString, CommonStringId], optional + :param cancel_text_tokens: Tokens to format into the Cancel text. + :type cancel_text_tokens: Iterator[Any], optional + :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. + :type mod_identity: CommonModIdentity, optional + """ + def __init__( + self, + title_identifier: Union[int, str, LocalizedString, CommonStringId], + description_identifier: Union[int, str, LocalizedString, CommonStringId], + title_tokens: Iterator[Any]=(), + description_tokens: Iterator[Any]=(), + ok_text_identifier: Union[int, str, LocalizedString, CommonStringId]=CommonStringId.OK, + ok_text_tokens: Iterator[Any]=(), + cancel_text_identifier: Union[int, str, LocalizedString, CommonStringId]=CommonStringId.CANCEL, + cancel_text_tokens: Iterator[Any]=(), + mod_identity: CommonModIdentity=None + ): + super().__init__( + title_identifier, + description_identifier, + title_tokens=title_tokens, + description_tokens=description_tokens, + mod_identity=mod_identity + ) + self.ok_text = CommonLocalizationUtils.create_localized_string(ok_text_identifier, tokens=tuple(ok_text_tokens)) + self.cancel_text = CommonLocalizationUtils.create_localized_string(cancel_text_identifier, tokens=tuple(cancel_text_tokens)) + + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + return 's4cl_ok_cancel_dialog' + + def show( + self, + on_ok_selected: Callable[[UiDialogOkCancel], Any]=CommonFunctionUtils.noop, + on_cancel_selected: Callable[[UiDialogOkCancel], Any]=CommonFunctionUtils.noop + ): + """show(\ + on_ok_selected=CommonFunctionUtils.noop,\ + on_cancel_selected=CommonFunctionUtils.noop\ + ) + + Show the dialog and invoke the callbacks upon the player selecting an option. + + :param on_ok_selected: Invoked upon the player selecting Ok in the dialog. + :type on_ok_selected: Callable[[UiDialogOkCancel], Any], optional + :param on_cancel_selected: Invoked upon the player selecting Cancel in the dialog. + :type on_cancel_selected: Callable[[UiDialogOkCancel], Any], optional + """ + try: + return self._show( + on_ok_selected=on_ok_selected, + on_cancel_selected=on_cancel_selected + ) + except Exception as ex: + self.log.error('show', exception=ex) + + def _show( + self, + on_ok_selected: Callable[[UiDialogOkCancel], Any]=CommonFunctionUtils.noop, + on_cancel_selected: Callable[[UiDialogOkCancel], Any]=CommonFunctionUtils.noop + ): + self.log.format_with_message('Attempting to display dialog.') + _dialog = self._create_dialog() + if _dialog is None: + self.log.debug('Failed to create dialog.') + return + + def _on_option_selected(dialog: UiDialogOkCancel): + self.log.debug('Option selected.') + if dialog.accepted: + self.log.debug('Ok chosen.') + return on_ok_selected(dialog) + self.log.debug('Cancel chosen.') + return on_cancel_selected(dialog) + + _dialog.add_listener(_on_option_selected) + self.log.debug('Displaying dialog.') + _dialog.show_dialog() + + def _create_dialog(self) -> Union[UiDialogOkCancel, None]: + try: + return UiDialogOkCancel.TunableFactory().default( + CommonSimUtils.get_active_sim_info(), + text=lambda *_, **__: self.description, + title=lambda *_, **__: self.title, + text_ok=lambda *_, **__: self.ok_text, + text_cancel=lambda *_, **__: self.cancel_text + ) + except Exception as ex: + self.log.error('_create_dialog', exception=ex) + return None + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_testing.show_ok_cancel_dialog', + 'Show an example of CommonOkCancelDialog.' +) +def _common_testing_show_ok_cancel_dialog(output: CommonConsoleCommandOutput): + output('Showing test ok cancel dialog.') + + def _ok_chosen(_: UiDialogOkCancel): + output('Ok option chosen.') + + def _cancel_chosen(_: UiDialogOkCancel): + output('Cancel option chosen.') + + # 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),) + dialog = CommonOkCancelDialog( + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + title_tokens=title_tokens, + description_tokens=description_tokens, + ok_text_identifier=CommonLocalizationUtils.create_localized_string(CommonStringId.TESTING_TEST_BUTTON_ONE, text_color=CommonLocalizedStringColor.RED), + cancel_text_identifier=CommonStringId.TESTING_TEST_BUTTON_TWO + ) + dialog.show(on_ok_selected=_ok_chosen, on_cancel_selected=_cancel_chosen) + output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/__init__.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_button_option_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_button_option_dialog.py new file mode 100644 index 0000000..299df27 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_button_option_dialog.py @@ -0,0 +1,349 @@ +""" +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 +""" +from pprint import pformat + +from typing import Any, Union, Callable, Iterator + +from protocolbuffers.Localization_pb2 import LocalizedString +from sims.sim_info import SimInfo +from sims4communitylib.dialogs.common_choose_response_dialog import CommonChooseResponseDialog +from sims4communitylib.dialogs.option_dialogs.common_choose_response_option_dialog import \ + CommonChooseResponseOptionDialog +from sims4communitylib.dialogs.option_dialogs.options.response.common_dialog_button_option import \ + CommonDialogButtonOption +from sims4communitylib.dialogs.option_dialogs.options.response.common_dialog_response_option_context import \ + CommonDialogResponseOptionContext +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + CommonConsoleCommandArgument +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.services.commands.common_console_command_parameters import \ + CommonOptionalSimInfoConsoleCommandParameter +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from ui.ui_dialog import UiDialogBase, UiDialogOption + + +class CommonChooseButtonOptionDialog(CommonChooseResponseOptionDialog): + """CommonChooseButtonOptionDialog(\ + mod_identity,\ + title_identifier,\ + description_identifier,\ + title_tokens=(),\ + description_tokens=(),\ + include_previous_button=True,\ + on_previous=CommonFunctionUtils.noop,\ + on_close=CommonFunctionUtils.noop\ + ) + + A dialog that displays a list of options. + + .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_choose_button_option_dialog` in the in-game console. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + def _on_option_chosen(option_identifier: DialogOptionIdentifierType, choice: DialogOptionValueType): + pass + + def _on_previous_chosen() -> None: + pass + + def _on_close() -> None: + 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 + ), + ) + option_dialog = CommonChooseButtonOptionDialog( + ModInfo.get_identity(), + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + title_tokens=title_tokens, + description_tokens=description_tokens, + on_previous=_on_previous_chosen, + on_close=_on_close + ) + + # We add the options, in this case we have three options. + option_dialog.add_option( + CommonDialogButtonOption( + 'Option 1', + 'Value 1', + CommonDialogResponseOptionContext( + CommonStringId.TESTING_SOME_TEXT_FOR_TESTING, + subtext_identifier=CommonStringId.TESTING_TEST_BUTTON_ONE + ), + on_chosen=_on_option_chosen + ) + ) + + option_dialog.add_option( + CommonDialogButtonOption( + 'Option 2', + 'Value 2', + CommonDialogResponseOptionContext( + CommonStringId.TESTING_SOME_TEXT_FOR_TESTING, + subtext_identifier=CommonStringId.TESTING_TEST_BUTTON_TWO, + ), + on_chosen=_on_option_chosen + ) + ) + + option_dialog.add_option( + CommonDialogButtonOption( + 'Option 3', + 'Value 3', + CommonDialogResponseOptionContext( + CommonLocalizationUtils.create_localized_string('Value 3'), + subtext_identifier=CommonStringId.TESTING_TEST_BUTTON_TWO + ), + on_chosen=_on_option_chosen + ) + ) + + option_dialog.show( + sim_info=CommonSimUtils.get_active_sim_info() + ) + + :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. + :type mod_identity: CommonModIdentity + :param title_identifier: A decimal identifier of the title text. + :type title_identifier: Union[int, str, LocalizedString, CommonStringId] + :param description_identifier: A decimal identifier of the description text. + :type description_identifier: Union[int, str, LocalizedString, CommonStringId] + :param title_tokens: An iterator of Tokens to format into the title. Default is an empty collection. + :type title_tokens: Iterator[Any], optional + :param description_tokens: An iterator of Tokens to format into the description. Default is an empty collection. + :type description_tokens: Iterator[Any], optional + :param include_previous_button: If True, the Previous button will be appended to the end of the dialog. Default is True. + :type include_previous_button: bool, optional + :param on_previous: A callback invoked upon the the Previous option being chosen. Default is CommonFunctionUtils.noop. + :type on_previous: Callable[[], None], optional + :param on_close: A callback invoked upon the dialog closing. Default is CommonFunctionUtils.noop. + :type on_close: Callable[[], None], optional + """ + + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + return 's4cl_choose_button_option_dialog' + + def __init__( + self, + mod_identity: CommonModIdentity, + title_identifier: Union[int, str, LocalizedString, CommonStringId], + description_identifier: Union[int, str, LocalizedString, CommonStringId], + title_tokens: Iterator[Any]=(), + description_tokens: Iterator[Any]=(), + include_previous_button: bool=True, + next_button_text: Union[int, str, LocalizedString, CommonStringId]=CommonStringId.NEXT, + previous_button_text: Union[int, str, LocalizedString, CommonStringId]=CommonStringId.PREVIOUS, + on_previous: Callable[[], None]=CommonFunctionUtils.noop, + on_close: Callable[[], None]=CommonFunctionUtils.noop, + per_page: int=10 + ): + super().__init__( + CommonChooseResponseDialog( + mod_identity, + title_identifier, + description_identifier, + tuple(), + next_button_text=next_button_text, + previous_button_text=previous_button_text, + title_tokens=title_tokens, + description_tokens=description_tokens, + per_page=per_page + ), + include_previous_button=include_previous_button, + on_previous=on_previous, + on_close=on_close + ) + + def add_option(self, option: CommonDialogButtonOption): + """add_option(option) + + Add an option to the dialog. + + :param option: The option to add. + :type option: CommonDialogObjectOption + """ + return super().add_option(option) + + def _add_response(self, option: CommonDialogButtonOption): + self._internal_dialog.add_response(option.as_response(len(self._options))) + + def show( + self, + dialog_options: UiDialogOption=0, + sim_info: SimInfo=None, + target_sim_info: SimInfo=None, + page: int=1 + ): + """show(\ + dialog_options=0,\ + sim_info=None,\ + target_sim_info=None,\ + page=1\ + ) + + Show the dialog and invoke the callbacks upon the player making a choice. + + :param dialog_options: Options to apply to the dialog, such as removing the close button. Default is no options. + :type dialog_options: UiDialogOption, optional + :param sim_info: The SimInfo of the Sim that will appear in the dialog image. The default Sim is the active Sim. Default is None. + :type sim_info: SimInfo, optional + :param target_sim_info: If provided, the dialog will appear as if it were a conversation instead of the normal view. Default is None. + :type target_sim_info: SimInfo, optional + :param page: The page to show the dialog on. Default is the first page. + :type page: int, optional + """ + return super().show( + dialog_options=dialog_options, + sim_info=sim_info, + target_sim_info=target_sim_info, + page=page + ) + + def build_dialog( + self, + dialog_options: UiDialogOption=0, + sim_info: SimInfo=None, + target_sim_info: SimInfo=None, + page: int=1 + ) -> Union[UiDialogBase, None]: + """build_dialog(\ + dialog_options=0,\ + sim_info=None,\ + target_sim_info=None,\ + page=1\ + ) + + Build the dialog and invoke the callbacks upon the player making a choice. + + :param dialog_options: Options to apply to the dialog, such as removing the close button. Default is no options. + :type dialog_options: UiDialogOption, optional + :param sim_info: The SimInfo of the Sim that will appear in the dialog image. The default Sim is the active Sim. Default is None. + :type sim_info: SimInfo, optional + :param target_sim_info: If provided, the dialog will appear as if it were a conversation instead of the normal view. Default is None. + :type target_sim_info: SimInfo, optional + :param page: The page to build the dialog on. Default is the first page. + :type page: int, optional + :return: The built dialog or None if a problem occurs. + :rtype: Union[UiDialogBase, None] + """ + return super().build_dialog( + dialog_options=dialog_options, + sim_info=sim_info, + page=page + ) + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_testing.show_choose_button_option_dialog', + 'Show an example of CommonChooseButtonOptionDialog.', + command_arguments=( + CommonConsoleCommandArgument('target_sim_info', 'Sim Id or Name', 'The name or instance id of a Sim that will be the target of the dialog.', is_optional=True, default_value='No Sim'), + ) +) +def _common_testing_show_choose_button_option_dialog(output: CommonConsoleCommandOutput, target_sim_info: CommonOptionalSimInfoConsoleCommandParameter=None): + output('Showing test choose button option dialog.') + + def _on_option_chosen(option_identifier: str, choice: str): + output('Chose option {} with value: {}.'.format(pformat(option_identifier), pformat(choice))) + + def _on_previous_chosen() -> None: + output('Chose previous option.') + + def _on_close() -> None: + output('Closed dialog.') + + # 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 = CommonChooseButtonOptionDialog( + ModInfo.get_identity(), + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + title_tokens=title_tokens, + description_tokens=description_tokens, + on_previous=_on_previous_chosen, + on_close=_on_close, + per_page=2 + ) + + option_dialog.add_option( + CommonDialogButtonOption( + 'Option 1', + 'Value 1', + CommonDialogResponseOptionContext( + CommonStringId.TESTING_SOME_TEXT_FOR_TESTING, + subtext_identifier=CommonStringId.TESTING_TEST_BUTTON_ONE + ), + on_chosen=_on_option_chosen + ) + ) + + option_dialog.add_option( + CommonDialogButtonOption( + 'Option 2', + 'Value 2', + CommonDialogResponseOptionContext( + CommonStringId.TESTING_SOME_TEXT_FOR_TESTING, + subtext_identifier=CommonStringId.TESTING_TEST_BUTTON_TWO, + ), + on_chosen=_on_option_chosen + ) + ) + + option_dialog.add_option( + CommonDialogButtonOption( + 'Option 3', + 'Value 3', + CommonDialogResponseOptionContext( + CommonLocalizationUtils.create_localized_string('Value 3'), + subtext_identifier=CommonStringId.TESTING_TEST_BUTTON_TWO + ), + on_chosen=_on_option_chosen + ) + ) + + option_dialog.show( + sim_info=CommonSimUtils.get_active_sim_info(), + target_sim_info=target_sim_info if target_sim_info is not CommonSimUtils.get_active_sim_info() else None + ) + output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_object_option_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_object_option_dialog.py new file mode 100644 index 0000000..b5ecd69 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_object_option_dialog.py @@ -0,0 +1,357 @@ +""" +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 +""" +from pprint import pformat + +from typing import Any, Union, Callable, Iterator + +from protocolbuffers.Localization_pb2 import LocalizedString +from sims.sim_info import SimInfo +from sims4communitylib.dialogs.choose_object_dialog import CommonChooseObjectDialog +from sims4communitylib.dialogs.option_dialogs.common_choose_option_dialog import CommonChooseOptionDialog +from sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext +from sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_option_category import \ + CommonDialogObjectOptionCategory +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_object_option import CommonDialogObjectOption +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from ui.ui_dialog import UiDialogBase +from ui.ui_dialog_picker import UiObjectPicker + + +class CommonChooseObjectOptionDialog(CommonChooseOptionDialog): + """CommonChooseObjectOptionDialog(\ + title_identifier,\ + description_identifier,\ + title_tokens=(),\ + description_tokens=(),\ + on_close=CommonFunctionUtils.noop,\ + mod_identity=None,\ + per_page=25,\ + required_tooltip=None,\ + required_tooltip_tokens=()\ + ) + + A dialog that displays a list of options. + + .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_choose_object_option_dialog` in the in-game console. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + def _on_option_chosen(option_identifier: DialogOptionIdentifierType, choice: DialogOptionValueType): + 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 + ), + ) + + # Create the dialog and only showing 2 options per page. + 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 + + # We add the options, in this case we have three options. + 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() + ) + + + :param title_identifier: A decimal identifier of the title text. + :type title_identifier: Union[int, str, LocalizedString, CommonStringId] + :param description_identifier: A decimal identifier of the description text. + :type description_identifier: Union[int, str, LocalizedString, CommonStringId] + :param title_tokens: An iterator of Tokens to format into the title. Default is an empty collection. + :type title_tokens: Iterator[Any], optional + :param description_tokens: An iterator of Tokens to format into the description. Default is an empty collection. + :type description_tokens: Iterator[Any], optional + :param on_close: A callback invoked upon the dialog closing. Default is CommonFunctionUtils.noop. + :type on_close: Callable[[], None], optional + :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. Default is None. + :type mod_identity: CommonModIdentity, optional + :param per_page: The number of rows to display per page. If the number of rows (including rows added after creation) exceeds this value, pagination will be added. Default is 25. + :type per_page: int, optional + :param required_tooltip: If provided, this text will display when the dialog requires at least one choice and a choice has not been made. Default is None. + :type required_tooltip: Union[int, str, LocalizedString, CommonStringId], optional + :param required_tooltip_tokens: Tokens to format into the required tooltip. Default is an empty collection. + :type required_tooltip_tokens: Iterator[Any], optional + """ + + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + return 's4cl_choose_object_option_dialog' + + def __init__( + self, + title_identifier: Union[int, str, LocalizedString, CommonStringId], + description_identifier: Union[int, str, LocalizedString, CommonStringId], + title_tokens: Iterator[Any]=(), + description_tokens: Iterator[Any]=(), + on_close: Callable[[], None]=CommonFunctionUtils.noop, + mod_identity: CommonModIdentity=None, + per_page: int=25, + required_tooltip: Union[int, str, LocalizedString, CommonStringId]=None, + required_tooltip_tokens: Iterator[Any]=() + ): + super().__init__( + CommonChooseObjectDialog( + title_identifier, + description_identifier, + tuple(), + title_tokens=title_tokens, + description_tokens=description_tokens, + per_page=per_page, + mod_identity=mod_identity, + required_tooltip=required_tooltip, + required_tooltip_tokens=required_tooltip_tokens + ), + on_close=on_close + ) + + @property + def current_page(self) -> int: + """Retrieve the current page. + + :return: A number indicating the current page. + :rtype: int + """ + dialog: CommonChooseObjectDialog = self._internal_dialog + return dialog.current_page + + def add_option(self, option: CommonDialogObjectOption): + """add_option(option) + + Add an option to the dialog. + + :param option: The option to add. + :type option: CommonDialogObjectOption + """ + return super().add_option(option) + + def _add_row(self, option: CommonDialogObjectOption): + self._internal_dialog.add_row(option.as_row(len(self._options)), always_visible=option.always_visible) + + def show( + self, + picker_type: UiObjectPicker.UiObjectPickerObjectPickerType=UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT, + page: int=1, + sim_info: SimInfo=None, + categories: Iterator[CommonDialogObjectOptionCategory]=(), + sort_options: bool=False + ): + """show(\ + picker_type=UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT,\ + page=1,\ + sim_info=None,\ + categories=()\ + ) + + Show the dialog and invoke the callbacks upon the player making a choice. + + :param picker_type: The layout of the dialog. Default is UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT. + :type picker_type: UiObjectPicker.UiObjectPickerObjectPickerType, optional + :param page: The page to display. Ignored if there is only one page of choices. Default is 1. + :type page: int, optional + :param sim_info: The SimInfo of the Sim that will appear in the dialog image. The default Sim is the active Sim. Default is None. + :type sim_info: SimInfo, optional + :param categories: A collection of categories do display in the dialog. Default is an empty collection. + :type categories: Iterator[CommonDialogObjectOptionCategory], optional + :param sort_options: If True, options will be sorted by display name, with the selected options on top. If False, options will not be sorted. Default is False. + :type sort_options: bool, optional + """ + return super().show( + picker_type=picker_type, + page=page, + sim_info=sim_info, + categories=categories, + sort_rows=sort_options + ) + + def build_dialog( + self, + picker_type: UiObjectPicker.UiObjectPickerObjectPickerType=UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT, + page: int=1, + sim_info: SimInfo=None, + categories: Iterator[CommonDialogObjectOptionCategory]=(), + sort_options: bool=False + ) -> Union[UiDialogBase, None]: + """build_dialog(\ + picker_type=UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT,\ + page=1,\ + sim_info=None,\ + categories=(),\ + sort_options=False\ + ) + + Build the dialog and invoke the callbacks upon the player making a choice. + + :param picker_type: The layout of the dialog. Default is UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT. + :type picker_type: UiObjectPicker.UiObjectPickerObjectPickerType, optional + :param page: The page to display. Ignored if there is only one page of choices. Default is 1. + :type page: int, optional + :param sim_info: The SimInfo of the Sim that will appear in the dialog image. The default Sim is the active Sim. Default is None. + :type sim_info: SimInfo, optional + :param categories: A collection of categories do display in the dialog. Default is an empty collection. + :type categories: Iterator[CommonDialogObjectOptionCategory], optional + :param sort_options: If True, options will be sorted by display name, with the selected options on top. If False, options will not be sorted. Default is False. + :type sort_options: bool, optional + :return: The built dialog or None if a problem occurs. + :rtype: Union[UiDialogBase, None] + """ + return super().build_dialog( + picker_type=picker_type, + page=page, + sim_info=sim_info, + categories=categories, + sort_rows=sort_options + ) + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_testing.show_choose_object_option_dialog', + 'Show an example of CommonChooseObjectOptionDialog.' +) +def _common_testing_show_choose_object_option_dialog(output: CommonConsoleCommandOutput): + 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))) + + # 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() + ) + output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_objects_option_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_objects_option_dialog.py new file mode 100644 index 0000000..8c4a341 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_objects_option_dialog.py @@ -0,0 +1,414 @@ +""" +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 +""" +from pprint import pformat + +from typing import Any, Union, Callable, Iterator, Tuple + +from protocolbuffers.Localization_pb2 import LocalizedString +from sims.sim_info import SimInfo +from sims4communitylib.dialogs.choose_objects_dialog import CommonChooseObjectsDialog +from sims4communitylib.dialogs.option_dialogs.common_choose_options_dialog import CommonChooseOptionsDialog +from sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext, \ + DialogOptionValueType +from sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_option_category import \ + CommonDialogObjectOptionCategory +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_object_option import CommonDialogObjectOption +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from ui.ui_dialog import UiDialogBase +from ui.ui_dialog_picker import UiObjectPicker + + +class CommonChooseObjectsOptionDialog(CommonChooseOptionsDialog): + """CommonChooseObjectsOptionDialog(\ + mod_identity,\ + title_identifier,\ + description_identifier,\ + title_tokens=(),\ + description_tokens=(),\ + on_close=CommonFunctionUtils.noop,\ + per_page=25,\ + required_tooltip=None,\ + required_tooltip_tokens=()\ + ) + + A dialog that displays a list of options and prompts to select multiple options. + + .. note:: This dialog allows selection of multiple Options. + + .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_choose_objects_option_dialog` in the in-game console. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + def _on_option_chosen(option_identifier: str, choice: str): + pass + + def _on_submit(choices: Tuple[str]): + 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 + ), + ) + + # Create the dialog and only showing 2 options per page. + option_dialog = CommonChooseObjectsOptionDialog( + 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 + + # We add the options, in this case we have three options. + 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( + on_submit=_on_submit, + sim_info=CommonSimUtils.get_active_sim_info() + ) + + + :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. + :type mod_identity: CommonModIdentity + :param title_identifier: A decimal identifier of the title text. + :type title_identifier: Union[int, str, LocalizedString, CommonStringId] + :param description_identifier: A decimal identifier of the description text. + :type description_identifier: Union[int, str, LocalizedString, CommonStringId] + :param title_tokens: An iterator of Tokens to format into the title. Default is an empty collection. + :type title_tokens: Iterator[Any], optional + :param description_tokens: An iterator of Tokens to format into the description. Default is an empty collection. + :type description_tokens: Iterator[Any], optional + :param on_close: A callback invoked upon the dialog closing. Default is CommonFunctionUtils.noop. + :type on_close: Callable[[], None], optional + :param per_page: The number of rows to display per page. If the number of rows (including rows added after creation) exceeds this value, pagination will be added. Default is 25. + :type per_page: int, optional + :param required_tooltip: If provided, this text will display when the dialog requires at least one choice and a choice has not been made. Default is None. + :type required_tooltip: Union[int, str, LocalizedString, CommonStringId], optional + :param required_tooltip_tokens: Tokens to format into the required tooltip. Default is an empty collection. + :type required_tooltip_tokens: Iterator[Any], optional + """ + + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + return 's4cl_choose_objects_option_dialog' + + def __init__( + self, + title_identifier: Union[int, str, LocalizedString, CommonStringId], + description_identifier: Union[int, str, LocalizedString, CommonStringId], + title_tokens: Iterator[Any]=(), + description_tokens: Iterator[Any]=(), + on_close: Callable[[], None]=CommonFunctionUtils.noop, + mod_identity: CommonModIdentity=None, + per_page: int=25, + required_tooltip: Union[int, str, LocalizedString, CommonStringId]=None, + required_tooltip_tokens: Iterator[Any]=() + ): + super().__init__( + CommonChooseObjectsDialog( + title_identifier, + description_identifier, + tuple(), + title_tokens=title_tokens, + description_tokens=description_tokens, + per_page=per_page, + mod_identity=mod_identity, + required_tooltip=required_tooltip, + required_tooltip_tokens=required_tooltip_tokens + ), + on_close=on_close + ) + + @property + def current_page(self) -> int: + """Retrieve the current page. + + :return: A number indicating the current page. + :rtype: int + """ + return self._internal_dialog.current_page + + @property + def _internal_dialog(self) -> CommonChooseObjectsDialog: + result: CommonChooseObjectsDialog = super()._internal_dialog + return result + + def add_option(self, option: CommonDialogObjectOption): + """add_option(option) + + Add an option to the dialog. + + :param option: The option to add. + :type option: CommonDialogObjectOption + """ + return super().add_option(option) + + def _add_row(self, option: CommonDialogObjectOption): + self._internal_dialog.add_row(option.as_row(len(self._options)), always_visible=option.always_visible) + + def show( + self, + on_submit: Callable[[Tuple[DialogOptionValueType]], Any]=CommonFunctionUtils.noop, + picker_type: UiObjectPicker.UiObjectPickerObjectPickerType=UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT, + page: int=1, + sim_info: SimInfo=None, + categories: Iterator[CommonDialogObjectOptionCategory]=(), + min_selectable: int=1, + max_selectable: int=1, + sort_options: bool=False, + allow_no_selection: bool=False + ): + """show(\ + on_submit=CommonFunctionUtils.noop,\ + picker_type=UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT,\ + page=1,\ + sim_info=None,\ + categories=(),\ + min_selectable=1,\ + max_selectable=1,\ + allow_no_selection=False\ + ) + + Show the dialog and invoke the callbacks upon the player submitting their selection. + + :param on_submit: When the dialog is submitted, this callback will be invoked with the chosen options. + :type on_submit: Callable[[Tuple[DialogOptionValueType]], Any], optional + :param picker_type: The layout of the dialog. Default is UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT. + :type picker_type: UiObjectPicker.UiObjectPickerObjectPickerType, optional + :param page: The page to display. Ignored if there is only one page of choices. Default is 1. + :type page: int, optional + :param sim_info: The SimInfo of the Sim that will appear in the dialog image. If None, it will be the active Sim. Default is None. + :type sim_info: SimInfo, optional + :param categories: A collection of categories do display in the dialog. Default is an empty collection. + :type categories: Iterator[CommonDialogObjectOptionCategory], optional + :param min_selectable: The minimum number of options that can be chosen. + :type min_selectable: int, optional + :param max_selectable: The maximum number of options that can be chosen. + :type max_selectable: int, optional + :param sort_options: If True, options will be sorted by display name, with the selected options on top. If False, options will not be sorted. Default is False. + :type sort_options: bool, optional + :param allow_no_selection: If True, the player may select no options. If False, the dialog will close with no options selected. Default is False. + :type allow_no_selection: bool, optional + """ + return super().show( + picker_type=picker_type, + page=page, + sim_info=sim_info, + categories=categories, + on_submit=on_submit, + min_selectable=min_selectable, + max_selectable=max_selectable, + sort_rows=sort_options, + allow_no_selection=allow_no_selection + ) + + def build_dialog( + self, + on_submit: Callable[[Tuple[DialogOptionValueType]], Any]=CommonFunctionUtils.noop, + picker_type: UiObjectPicker.UiObjectPickerObjectPickerType=UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT, + page: int=1, + sim_info: SimInfo=None, + categories: Iterator[CommonDialogObjectOptionCategory]=(), + min_selectable: int=1, + max_selectable: int=1, + sort_options: bool=False, + allow_no_selection: bool=False + ) -> Union[UiDialogBase, None]: + """build_dialog(\ + on_submit=CommonFunctionUtils.noop,\ + picker_type=UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT,\ + page=1,\ + sim_info=None,\ + categories=(),\ + min_selectable=1,\ + max_selectable=1,\ + sort_options=False,\ + allow_no_selection=False\ + ) + + Build the dialog and invoke the callbacks upon the player submitting their selection. + + :param on_submit: When the dialog is submitted, this callback will be invoked with the chosen options. + :type on_submit: Callable[[Tuple[DialogOptionValueType]], Any], optional + :param picker_type: The layout of the dialog. Default is UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT. + :type picker_type: UiObjectPicker.UiObjectPickerObjectPickerType, optional + :param page: The page to display. Ignored if there is only one page of choices. Default is 1. + :type page: int, optional + :param sim_info: The SimInfo of the Sim that will appear in the dialog image. If None, it will be the active Sim. Default is None. + :type sim_info: SimInfo, optional + :param categories: A collection of categories do display in the dialog. Default is an empty collection. + :type categories: Iterator[CommonDialogObjectOptionCategory], optional + :param min_selectable: The minimum number of options that can be chosen. + :type min_selectable: int, optional + :param max_selectable: The maximum number of options that can be chosen. + :type max_selectable: int, optional + :param sort_options: If True, options will be sorted by display name, with the selected options on top. If False, options will not be sorted. Default is False. + :type sort_options: bool, optional + :param allow_no_selection: If True, the player may select no options. If False, the dialog will close with no options selected. Default is False. + :type allow_no_selection: bool, optional + :return: The built dialog or None if a problem occurs. + :rtype: Union[UiDialogBase, None] + """ + return super().build_dialog( + picker_type=picker_type, + page=page, + sim_info=sim_info, + categories=categories, + on_submit=on_submit, + min_selectable=min_selectable, + max_selectable=max_selectable, + sort_rows=sort_options, + allow_no_selection=allow_no_selection + ) + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_testing.show_choose_objects_option_dialog', + 'Show an example of CommonChooseObjectsOptionDialog.' +) +def _common_testing_show_choose_objects_option_dialog(output: CommonConsoleCommandOutput): + output('Showing test choose objects option dialog.') + + def _on_option_chosen(option_identifier: str, choice: str): + output('Chose option {} with value: {}.'.format(pformat(option_identifier), pformat(choice))) + + def _on_submit(choices: Tuple[str]): + output('Chose options {}.'.format(pformat(choices))) + + # 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 = CommonChooseObjectsOptionDialog( + 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( + on_submit=_on_submit, + sim_info=CommonSimUtils.get_active_sim_info(), + min_selectable=1, + max_selectable=2 + ) + output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_option_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_option_dialog.py new file mode 100644 index 0000000..b5c68c7 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_option_dialog.py @@ -0,0 +1,129 @@ +""" +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 +""" +from typing import Any, Callable, Union +from sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome +from sims4communitylib.dialogs.common_choose_dialog import CommonChooseDialog +from sims4communitylib.dialogs.option_dialogs.common_option_dialog import CommonOptionDialog +from sims4communitylib.dialogs.option_dialogs.options.common_dialog_option import CommonDialogOption +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from ui.ui_dialog import UiDialogBase + + +class CommonChooseOptionDialog(CommonOptionDialog): + """CommonChooseOptionDialog(\ + internal_dialog,\ + on_close=CommonFunctionUtils.noop\ + ) + + A dialog that displays a list of options. + + .. warning:: Unless you know what you are doing, do not create an instance of this class directly! + + :param internal_dialog: The dialog this option dialog wraps. + :type internal_dialog: CommonChooseDialog + :param on_close: A callback invoked upon the dialog closing. + :type on_close: Callable[[], None], optional + """ + def __init__( + self, + internal_dialog: CommonChooseDialog, + on_close: Callable[[], None]=CommonFunctionUtils.noop + ): + super().__init__( + internal_dialog, + on_close=on_close + ) + self._options = [] + + @property + def option_count(self) -> int: + """The number of options within the dialog. + + :return: The number of options within the dialog. + :rtype: int + """ + return len(self._options) + + @property + def _internal_dialog(self) -> CommonChooseDialog: + result: CommonChooseDialog = super()._internal_dialog + return result + + def has_options(self) -> bool: + """has_options() + + Determine if the dialog has selectable options. + + :return: True, if the dialog has any options in it. False, if not. + :rtype: bool + """ + try: + return self.option_count > 0 + except Exception as ex: + self.log.error('has_options', exception=ex) + return False + + def add_option(self, option: CommonDialogOption): + """add_option(option) + + Add an option to the dialog. + + :param option: The option to add. + :type option: CommonDialogOption + """ + try: + if self._internal_dialog is None or not hasattr(self._internal_dialog, 'add_row'): + return + self._options.append(option) + self._add_row(option) + except Exception as ex: + self.log.error('add_option', exception=ex) + + def _add_row(self, option: CommonDialogOption): + self._internal_dialog.add_row(option.as_row(len(self._options))) + + def show(self, *_: Any, **__: Any): + """show(*_, **__) + + Show the dialog. + + .. note:: Override this function to provide your own arguments. + + """ + try: + return self._internal_dialog.show(*_, on_chosen=self._on_chosen(), **__) + except Exception as ex: + self.log.error('choose_option.show', exception=ex) + + def build_dialog(self, *_: Any, **__: Any) -> Union[UiDialogBase, None]: + """build_dialog(*_, **__) + + Build the dialog. + + .. note:: Override this function to provide your own arguments. + + :return: The built dialog or None if a problem occurs. + :rtype: Union[UiDialogBase, None] + """ + try: + return self._internal_dialog.build_dialog(*_, on_chosen=self._on_chosen(), **__) + except Exception as ex: + self.log.error('choose_option.build_dialog', exception=ex) + return None + + def _on_chosen(self) -> Callable[[CommonDialogOption, CommonChoiceOutcome], bool]: + def _on_chosen(chosen_option: CommonDialogOption, outcome: CommonChoiceOutcome) -> bool: + try: + if chosen_option is None or CommonChoiceOutcome.is_error_or_cancel(outcome): + self.close() + return False + return chosen_option.choose() + except Exception as ex: + self.log.error('Error occurred on choosing a value.', exception=ex) + return False + return _on_chosen diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_options_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_options_dialog.py new file mode 100644 index 0000000..6857237 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_options_dialog.py @@ -0,0 +1,160 @@ +""" +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 +""" +from typing import Union, Tuple, Any, Callable, List + +from sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome +from sims4communitylib.dialogs.common_choose_dialog import CommonChooseDialog +from sims4communitylib.dialogs.option_dialogs.common_choose_option_dialog import CommonChooseOptionDialog +from sims4communitylib.dialogs.option_dialogs.options.common_dialog_option import CommonDialogOption +from sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import DialogOptionValueType +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils + + +# noinspection PyMissingOrEmptyDocstring +from ui.ui_dialog import UiDialogBase + + +class CommonChooseOptionsDialog(CommonChooseOptionDialog): + """CommonChooseOptionsDialog(\ + internal_dialog,\ + on_close=CommonFunctionUtils.noop\ + ) + + A dialog that displays a list of options and prompts to select multiple items. + + .. warning:: Unless you know what you are doing, do not create an instance of this class directly! + + :param internal_dialog: The dialog this option dialog wraps. + :type internal_dialog: CommonChooseDialog + :param on_close: A callback invoked upon the dialog closing. + :type on_close: Callable[[], None], optional + """ + def __init__( + self, + internal_dialog: CommonChooseDialog, + on_close: Callable[[], None]=CommonFunctionUtils.noop + ): + super().__init__( + internal_dialog, + on_close=on_close + ) + + def show( + self, + *_, + on_submit: Callable[[Tuple[DialogOptionValueType]], Any]=CommonFunctionUtils.noop, + min_selectable: int=1, + max_selectable: int=1, + allow_no_selection: bool=False, + **__ + ): + """show(\ + *_,\ + on_submit=CommonFunctionUtils.noop,\ + min_selectable=1,\ + max_selectable=1,\ + allow_no_selection=False,\ + **__\ + ) + + Show the dialog. + + .. note:: Override this function to provide your own arguments. + + :param on_submit: When the dialog is submitted, this callback will be invoked with the chosen options. + :type on_submit: Callable[[Tuple[DialogOptionValueType]], Any], optional + :param min_selectable: The minimum number of options that can be chosen. + :type min_selectable: int, optional + :param max_selectable: The maximum number of options that can be chosen. + :type max_selectable: int, optional + :param allow_no_selection: If True, the player may select no options. If False, the dialog will close with no options selected. Default is False. + :type allow_no_selection: bool, optional + """ + try: + return self._internal_dialog.show( + *_, + on_chosen=self._on_submit(on_submit, allow_no_selection=allow_no_selection), + min_selectable=min_selectable, + max_selectable=max_selectable, + **__ + ) + except Exception as ex: + self.log.error('choose_options.show', exception=ex) + + def build_dialog( + self, + *_: Any, + on_submit: Callable[[Tuple[DialogOptionValueType]], Any]=CommonFunctionUtils.noop, + min_selectable: int=1, + max_selectable: int=1, + allow_no_selection: bool=False, + **__: Any + ) -> Union[UiDialogBase, None]: + """build_dialog(\ + *_,\ + on_submit=CommonFunctionUtils.noop,\ + min_selectable=1,\ + max_selectable=1,\ + allow_no_selection=False,\ + **__\ + ) + + Build the dialog. + + .. note:: Override this function to provide your own arguments. + + :param on_submit: When the dialog is submitted, this callback will be invoked with the chosen options. + :type on_submit: Callable[[Tuple[DialogOptionValueType]], Any], optional + :param min_selectable: The minimum number of options that can be chosen. + :type min_selectable: int, optional + :param max_selectable: The maximum number of options that can be chosen. + :type max_selectable: int, optional + :param allow_no_selection: If True, the player may select no options. If False, the dialog will close with no options selected. Default is False. + :type allow_no_selection: bool, optional + :return: The built dialog or None if a problem occurs. + :rtype: Union[UiDialogBase, None] + """ + try: + + return self._internal_dialog.build_dialog( + *_, + on_chosen=self._on_submit(on_submit, allow_no_selection=allow_no_selection), + min_selectable=min_selectable, + max_selectable=max_selectable, + **__ + ) + except Exception as ex: + self.log.error('choose_options.build_dialog', exception=ex) + return None + + def _on_chosen(self) -> Callable[[Union[Tuple[CommonDialogOption], None], CommonChoiceOutcome], bool]: + return self._on_submit() + + def _on_submit( + self, + on_submit: Callable[[Tuple[DialogOptionValueType]], Any]=CommonFunctionUtils.noop, + allow_no_selection: bool=False + ) -> Callable[[Union[Tuple[CommonDialogOption], None], CommonChoiceOutcome], bool]: + def _on_submit(chosen_options: Union[Tuple[CommonDialogOption], None], outcome: CommonChoiceOutcome) -> bool: + try: + if chosen_options is None or CommonChoiceOutcome.is_error_or_cancel(outcome): + self.close() + return True + if not allow_no_selection: + if len(chosen_options) == 0: + self.close() + return True + chosen_values: List[DialogOptionValueType] = list() + for chosen_option in chosen_options: + chosen_values.append(chosen_option.value) + chosen_option.choose() + return on_submit(tuple(chosen_values)) + except Exception as ex: + self.log.error('Error occurred on submitting a value.', exception=ex) + return False + return _on_submit diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_response_option_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_response_option_dialog.py new file mode 100644 index 0000000..2a7ff3d --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_response_option_dialog.py @@ -0,0 +1,140 @@ +""" +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 +""" +from typing import Any, Callable, Union +from sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome +from sims4communitylib.dialogs.common_choose_response_dialog import CommonChooseResponseDialog +from sims4communitylib.dialogs.common_ui_response_dialog import CommonUiResponseDialog +from sims4communitylib.dialogs.option_dialogs.common_option_dialog import CommonOptionDialog +from sims4communitylib.dialogs.option_dialogs.options.response.common_dialog_response_option import \ + CommonDialogResponseOption +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils + + +class CommonChooseResponseOptionDialog(CommonOptionDialog): + """CommonChooseResponseOptionDialog(\ + internal_dialog,\ + include_previous_button=True,\ + on_previous=CommonFunctionUtils.noop\ + on_close=CommonFunctionUtils.noop\ + ) + + A dialog that displays a list of options. + + .. warning:: Unless you know what you are doing, do not create an instance of this class directly! + + :param internal_dialog: The dialog this option dialog wraps. + :type internal_dialog: CommonChooseResponseDialog + :param include_previous_button: If True, the Previous button will be appended to the end of the dialog. Default is True. + :type include_previous_button: bool, optional + :param on_previous: A callback invoked upon the Previous response being chosen. Default is no operation. + :type on_previous: Callable[[], None], optional + :param on_close: A callback invoked upon the dialog closing. + :type on_close: Callable[[], None], optional + """ + def __init__( + self, + internal_dialog: CommonChooseResponseDialog, + include_previous_button: bool=True, + on_previous: Callable[[], None]=CommonFunctionUtils.noop, + on_close: Callable[[], None]=CommonFunctionUtils.noop + ): + super().__init__( + internal_dialog, + on_close=on_close + ) + self._include_previous_button = include_previous_button + self._on_previous = on_previous + self._options = [] + + @property + def option_count(self) -> int: + """The number of options within the dialog. + + :return: The number of options within the dialog. + :rtype: int + """ + return len(self._options) + + @property + def _internal_dialog(self) -> CommonChooseResponseDialog: + result: CommonChooseResponseDialog = super()._internal_dialog + return result + + def has_options(self) -> bool: + """has_options() + + Determine if the dialog has selectable options. + + :return: True, if the dialog has any options in it. False, if not. + :rtype: bool + """ + try: + return self.option_count > 0 + except Exception as ex: + self.log.error('has_options', exception=ex) + return False + + def add_option(self, option: CommonDialogResponseOption): + """add_option(option) + + Add an option to the dialog. + + :param option: The option to add. + :type option: CommonDialogResponseOption + """ + try: + if self._internal_dialog is None or not hasattr(self._internal_dialog, 'add_response'): + return + self._options.append(option) + self._add_response(option) + except Exception as ex: + self.log.error('add_option', exception=ex) + + def _add_response(self, option: CommonDialogResponseOption): + self._internal_dialog.add_response(option.as_response(len(self._options))) + + def show(self, *_: Any, **__: Any): + """show(*_, **__) + + Show the dialog. + + .. note:: Override this function to provide your own arguments. + + """ + try: + return self._internal_dialog.show(*_, on_chosen=self._on_chosen(), include_previous_button=self._include_previous_button, on_previous=self._on_previous, **__) + except Exception as ex: + self.log.error('choose_response_option.show', exception=ex) + + def build_dialog(self, *_: Any, **__: Any) -> Union[CommonUiResponseDialog, None]: + """build_dialog(*_, **__) + + Build the dialog. + + .. note:: Override this function to provide your own arguments. + + :return: The built dialog or None if a problem occurs. + :rtype: Union[CommonUiResponseDialog, None] + """ + try: + return self._internal_dialog.build_dialog(*_, on_chosen=self._on_chosen(), include_previous_button=self._include_previous_button, on_previous=self._on_previous, **__) + except Exception as ex: + self.log.error('choose_response_option.build_dialog', exception=ex) + return None + + def _on_chosen(self) -> Callable[[CommonDialogResponseOption, CommonChoiceOutcome], None]: + def _on_chosen(chosen_option: CommonDialogResponseOption, outcome: CommonChoiceOutcome) -> None: + try: + if chosen_option is None or CommonChoiceOutcome.is_error_or_cancel(outcome): + self.close() + return + chosen_option.choose() + return + except Exception as ex: + self.log.error('Error occurred on choosing a value.', exception=ex) + return _on_chosen diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_sim_option_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_sim_option_dialog.py new file mode 100644 index 0000000..f4bdc77 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_sim_option_dialog.py @@ -0,0 +1,275 @@ +""" +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 +""" +import random +from typing import Any, Union, Callable, Iterator + +from protocolbuffers.Localization_pb2 import LocalizedString +from sims.sim_info import SimInfo +from sims4communitylib.dialogs.common_choose_sim_dialog import CommonChooseSimDialog +from sims4communitylib.dialogs.option_dialogs.common_choose_option_dialog import CommonChooseOptionDialog +from sims4communitylib.dialogs.option_dialogs.options.sims.common_dialog_sim_option_context import \ + CommonDialogSimOptionContext +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from sims4communitylib.dialogs.option_dialogs.options.sims.common_dialog_sim_option import CommonDialogSimOption +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from ui.ui_dialog import UiDialogBase + + +class CommonChooseSimOptionDialog(CommonChooseOptionDialog): + """CommonChooseSimOptionDialog(\ + title_identifier,\ + description_identifier,\ + title_tokens=(),\ + description_tokens=(),\ + on_close=CommonFunctionUtils.noop,\ + mod_identity=None,\ + required_tooltip=None,\ + required_tooltip_tokens=()\ + ) + + A dialog that displays a list of Sims for selection. + + .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_choose_sim_option_dialog` in the in-game console. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + def _on_chosen(_sim_info: SimInfo): + 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 + ), + ) + + # Create the dialog and show a number of Sims in 4 columns. + option_dialog = CommonChooseSimOptionDialog( + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + title_tokens=title_tokens, + description_tokens=description_tokens, + mod_identity=ModInfo.get_identity() + ) + + current_count = 0 + count = 25 + + for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): + if current_count >= count: + break + should_select = random.choice((True, False)) + is_enabled = random.choice((True, False)) + option_dialog.add_option( + CommonDialogSimOption( + sim_info, + CommonDialogSimOptionContext( + is_enabled=is_enabled, + is_selected=should_select + ), + on_chosen=_on_chosen + ) + ) + + option_dialog.show( + sim_info=CommonSimUtils.get_active_sim_info(), + column_count=4 + ) + + :param title_identifier: A decimal identifier of the title text. + :type title_identifier: Union[int, str, LocalizedString, CommonStringId] + :param description_identifier: A decimal identifier of the description text. + :type description_identifier: Union[int, str, LocalizedString, CommonStringId] + :param title_tokens: An iterator of Tokens to format into the title. + :type title_tokens: Iterator[Any], optional + :param description_tokens: An iterator of Tokens to format into the description. + :type description_tokens: Iterator[Any], optional + :param on_close: A callback invoked upon the dialog closing. + :type on_close: Callable[[], None], optional + :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. + :type mod_identity: CommonModIdentity, optional + :param required_tooltip: If provided, this text will display when the dialog requires at least one choice and a choice has not been made. Default is None. + :type required_tooltip: Union[int, str, LocalizedString, CommonStringId], optional + :param required_tooltip_tokens: Tokens to format into the required tooltip. Default is an empty collection. + :type required_tooltip_tokens: Iterator[Any], optional + """ + def __init__( + self, + title_identifier: Union[int, str, LocalizedString, CommonStringId], + description_identifier: Union[int, str, LocalizedString, CommonStringId], + title_tokens: Iterator[Any]=(), + description_tokens: Iterator[Any]=(), + on_close: Callable[[], None]=CommonFunctionUtils.noop, + mod_identity: CommonModIdentity=None, + required_tooltip: Union[int, str, LocalizedString, CommonStringId]=None, + required_tooltip_tokens: Iterator[Any]=() + ): + super().__init__( + CommonChooseSimDialog( + title_identifier, + description_identifier, + tuple(), + title_tokens=title_tokens, + description_tokens=description_tokens, + mod_identity=mod_identity, + required_tooltip=required_tooltip, + required_tooltip_tokens=required_tooltip_tokens + ), + on_close=on_close + ) + + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + return 's4cl_choose_sim_option_dialog' + + def add_option(self, option: CommonDialogSimOption): + """add_option(option) + + Add an option to the dialog. + + :param option: The option to add. + :type option: CommonDialogSimOption + """ + return super().add_option(option) + + def show( + self, + sim_info: SimInfo=None, + should_show_names: bool=True, + hide_row_descriptions: bool=False, + column_count: int=3 + ): + """show(sim_info=None, should_show_names=True, hide_row_descriptions=False, column_count=3) + + Show the dialog. + + :param sim_info: The SimInfo of the Sim that will appear in the dialog image. The default Sim is the active Sim. + :type sim_info: SimInfo, optional + :param should_show_names: If True, then the names of the Sims will display in the dialog. + :type should_show_names: bool, optional + :param hide_row_descriptions: A flag to hide the row descriptions. + :type hide_row_descriptions: bool, optional + :param column_count: The number of columns to display Sims in. + :type column_count: int, optional + """ + return super().show( + sim_info=sim_info, + should_show_names=should_show_names, + hide_row_descriptions=hide_row_descriptions, + column_count=column_count + ) + + def build_dialog( + self, + sim_info: SimInfo=None, + should_show_names: bool=True, + hide_row_descriptions: bool=False, + column_count: int=3 + ) -> Union[UiDialogBase, None]: + """build_dialog(sim_info=None, should_show_names=True, hide_row_descriptions=False, column_count=3) + + Build the dialog. + + :param sim_info: The SimInfo of the Sim that will appear in the dialog image. The default Sim is the active Sim. Default is None. + :type sim_info: SimInfo, optional + :param should_show_names: If True, then the names of the Sims will display in the dialog. Default is True. + :type should_show_names: bool, optional + :param hide_row_descriptions: A flag to hide the row descriptions. Default is False. + :type hide_row_descriptions: bool, optional + :param column_count: The number of columns to display Sims in. Default is 3. + :type column_count: int, optional + :return: The built dialog or None if a problem occurs. + :rtype: Union[UiDialogBase, None] + """ + return super().build_dialog( + sim_info=sim_info, + should_show_names=should_show_names, + hide_row_descriptions=hide_row_descriptions, + column_count=column_count + ) + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_testing.show_choose_sim_option_dialog', + 'Show an example of CommonChooseSimOptionDialog.' +) +def _common_testing_show_choose_sim_option_dialog(output: CommonConsoleCommandOutput): + output('Showing test choose sim option dialog.') + + def _on_chosen(_sim_info: SimInfo): + output('Chose Sim with name \'{}\''.format(CommonSimNameUtils.get_full_name(_sim_info))) + + # 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 + ), + ) + + # Create the dialog and show a number of Sims in 4 columns. + option_dialog = CommonChooseSimOptionDialog( + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + title_tokens=title_tokens, + description_tokens=description_tokens, + mod_identity=ModInfo.get_identity() + ) + + current_count = 0 + count = 25 + + for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): + if current_count >= count: + break + should_select = random.choice((True, False)) + is_enabled = random.choice((True, False)) + option_dialog.add_option( + CommonDialogSimOption( + sim_info, + CommonDialogSimOptionContext( + is_enabled=is_enabled, + is_selected=should_select + ), + on_chosen=_on_chosen + ) + ) + + option_dialog.show( + sim_info=CommonSimUtils.get_active_sim_info(), + column_count=4 + ) + output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_sims_option_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_sims_option_dialog.py new file mode 100644 index 0000000..d6f2e1c --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_sims_option_dialog.py @@ -0,0 +1,306 @@ +""" +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 +""" +import random +from typing import Any, Tuple, Union, Callable, Iterator + +from protocolbuffers.Localization_pb2 import LocalizedString +from sims.sim_info import SimInfo +from sims4communitylib.dialogs.common_choose_sims_dialog import CommonChooseSimsDialog +from sims4communitylib.dialogs.option_dialogs.common_choose_options_dialog import CommonChooseOptionsDialog +from sims4communitylib.dialogs.option_dialogs.options.sims.common_dialog_sim_option_context import \ + CommonDialogSimOptionContext +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from sims4communitylib.dialogs.option_dialogs.options.sims.common_dialog_sim_option import CommonDialogSimOption +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from ui.ui_dialog import UiDialogBase + + +class CommonChooseSimsOptionDialog(CommonChooseOptionsDialog): + """CommonChooseSimsOptionDialog(\ + title_identifier,\ + description_identifier,\ + title_tokens=(),\ + description_tokens=(),\ + on_close=CommonFunctionUtils.noop,\ + mod_identity=None,\ + required_tooltip=None,\ + required_tooltip_tokens=()\ + ) + + A dialog that displays a list of Sims for selection and prompts to select multiple Sims. + + .. note:: This dialog allows selection of multiple Sims. + + .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_choose_sims_option_dialog` in the in-game console. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + def _on_submit(sim_info_list: Tuple[SimInfo]): + 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 + ), + ) + + # Create the dialog and show a number of Sims in 4 columns and being able to select up to 5 Sims. + option_dialog = CommonChooseSimsOptionDialog( + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + title_tokens=title_tokens, + description_tokens=description_tokens, + mod_identity=ModInfo.get_identity() + ) + + current_count = 0 + count = 25 + + for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): + if current_count >= count: + break + should_select = random.choice((True, False)) + is_enabled = random.choice((True, False)) + option_dialog.add_option( + CommonDialogSimOption( + sim_info, + CommonDialogSimOptionContext( + is_enabled=is_enabled, + is_selected=should_select + ) + ) + ) + + option_dialog.show( + sim_info=CommonSimUtils.get_active_sim_info(), + column_count=4, + max_selectable=5, + on_submit=_on_submit + ) + + :param title_identifier: A decimal identifier of the title text. + :type title_identifier: Union[int, str, LocalizedString, CommonStringId] + :param description_identifier: A decimal identifier of the description text. + :type description_identifier: Union[int, str, LocalizedString, CommonStringId] + :param title_tokens: An iterator of Tokens to format into the title. + :type title_tokens: Iterator[Any], optional + :param description_tokens: An iterator of Tokens to format into the description. + :type description_tokens: Iterator[Any], optional + :param on_close: A callback invoked upon the dialog closing. + :type on_close: Callable[[], None], optional + :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. + :type mod_identity: CommonModIdentity, optional + :param required_tooltip: If provided, this text will display when the dialog requires at least one choice and a choice has not been made. Default is None. + :type required_tooltip: Union[int, str, LocalizedString, CommonStringId], optional + :param required_tooltip_tokens: Tokens to format into the required tooltip. Default is an empty collection. + :type required_tooltip_tokens: Iterator[Any], optional + """ + def __init__( + self, + title_identifier: Union[int, str, LocalizedString, CommonStringId], + description_identifier: Union[int, str, LocalizedString, CommonStringId], + title_tokens: Iterator[Any]=(), + description_tokens: Iterator[Any]=(), + on_close: Callable[[], None]=CommonFunctionUtils.noop, + mod_identity: CommonModIdentity=None, + required_tooltip: Union[int, str, LocalizedString, CommonStringId]=None, + required_tooltip_tokens: Iterator[Any]=() + ): + super().__init__( + CommonChooseSimsDialog( + title_identifier, + description_identifier, + tuple(), + title_tokens=title_tokens, + description_tokens=description_tokens, + mod_identity=mod_identity, + required_tooltip=required_tooltip, + required_tooltip_tokens=required_tooltip_tokens + ), + on_close=on_close + ) + + # noinspection PyMissingOrEmptyDocstring + def add_option(self, option: CommonDialogSimOption): + return super().add_option(option) + + def show( + self, + on_submit: Callable[[Tuple[SimInfo]], Any]=CommonFunctionUtils.noop, + sim_info: SimInfo=None, + should_show_names: bool=True, + hide_row_descriptions: bool=False, + column_count: int=3, + min_selectable: int=1, + max_selectable: int=1 + ): + """show(\ + on_submit=CommonFunctionUtils.noop,\ + sim_info=None,\ + should_show_names=True,\ + hide_row_descriptions=False,\ + column_count=3,\ + min_selectable=1,\ + max_selectable=1,\ + ) + + Show the dialog and invoke the callbacks upon the player submitting their selection. + + :param on_submit: A callback invoked upon the player choosing Sims. Default is CommonFunctionUtils.noop. + :type on_submit: Callable[[Tuple[SimInfo]], Any], optional + :param sim_info: The SimInfo of the Sim that will appear in the dialog image. If None, it will be the active Sim. Default is None. + :type sim_info: SimInfo, optional + :param should_show_names: If True, then the names of the Sims will display in the dialog. Default is True. + :type should_show_names: bool, optional + :param hide_row_descriptions: A flag to hide the row descriptions. Default is False. + :type hide_row_descriptions: bool, optional + :param column_count: The number of columns to display Sims in. Default is 3. + :type column_count: int, optional + :param min_selectable: The minimum number of Sims that must be chosen. Default is 1. + :type min_selectable: int, optional + :param max_selectable: The maximum number of Sims that can be chosen. Default is 1. + :type max_selectable: int, optional + """ + return super().show( + on_submit=on_submit, + sim_info=sim_info, + should_show_names=should_show_names, + hide_row_descriptions=hide_row_descriptions, + column_count=column_count, + min_selectable=min_selectable, + max_selectable=max_selectable + ) + + def build_dialog( + self, + on_submit: Callable[[Tuple[SimInfo]], Any]=CommonFunctionUtils.noop, + sim_info: SimInfo=None, + should_show_names: bool=True, + hide_row_descriptions: bool=False, + column_count: int=3, + min_selectable: int=1, + max_selectable: int=1 + ) -> Union[UiDialogBase, None]: + """build_dialog(\ + on_submit=CommonFunctionUtils.noop,\ + sim_info=None,\ + should_show_names=True,\ + hide_row_descriptions=False,\ + column_count=3,\ + min_selectable=1,\ + max_selectable=1,\ + ) + + Show the dialog and invoke the callbacks upon the player submitting their selection. + + :param on_submit: A callback invoked upon the player choosing Sims. Default is CommonFunctionUtils.noop. + :type on_submit: Callable[[Tuple[SimInfo]], Any], optional + :param sim_info: The SimInfo of the Sim that will appear in the dialog image. If None, it will be the active Sim. Default is None. + :type sim_info: SimInfo, optional + :param should_show_names: If True, then the names of the Sims will display in the dialog. Default is True. + :type should_show_names: bool, optional + :param hide_row_descriptions: A flag to hide the row descriptions. Default is False. + :type hide_row_descriptions: bool, optional + :param column_count: The number of columns to display Sims in. Default is 3. + :type column_count: int, optional + :param min_selectable: The minimum number of Sims that must be chosen. Default is 1. + :type min_selectable: int, optional + :param max_selectable: The maximum number of Sims that can be chosen. Default is 1. + :type max_selectable: int, optional + :return: The built dialog or None if a problem occurs. + :rtype: Union[UiDialogBase, None] + """ + return super().build_dialog( + on_submit=on_submit, + sim_info=sim_info, + should_show_names=should_show_names, + hide_row_descriptions=hide_row_descriptions, + column_count=column_count, + min_selectable=min_selectable, + max_selectable=max_selectable + ) + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_testing.show_choose_sims_option_dialog', + 'Show an example of CommonChooseSimsOptionDialog.' +) +def _common_testing_show_choose_sims_option_dialog(output: CommonConsoleCommandOutput): + output('Showing test choose sims option dialog.') + + def _on_submit(sim_info_list: Tuple[SimInfo]): + output('Chose Sims with names {}'.format(CommonSimNameUtils.get_full_names(sim_info_list))) + + # 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 + ), + ) + + # Create the dialog and show a number of Sims in 4 columns and being able to select up to 5 Sims. + option_dialog = CommonChooseSimsOptionDialog( + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + title_tokens=title_tokens, + description_tokens=description_tokens, + mod_identity=ModInfo.get_identity() + ) + + current_count = 0 + count = 25 + + for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): + if current_count >= count: + break + is_enabled = random.choice((True, False)) + option_dialog.add_option( + CommonDialogSimOption( + sim_info, + CommonDialogSimOptionContext( + is_enabled=is_enabled + ) + ) + ) + + option_dialog.show( + sim_info=CommonSimUtils.get_active_sim_info(), + column_count=4, + max_selectable=5, + on_submit=_on_submit + ) + output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_multi_pane_choose_option_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_multi_pane_choose_option_dialog.py new file mode 100644 index 0000000..61ded52 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_multi_pane_choose_option_dialog.py @@ -0,0 +1,468 @@ +""" +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 +""" +from pprint import pformat + +from typing import Any, Union, Callable, Iterator, Dict, Tuple, List + +from protocolbuffers.Localization_pb2 import LocalizedString +from sims.sim_info import SimInfo +from sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome +from sims4communitylib.dialogs.common_multi_pane_choose_dialog import CommonMultiPaneChooseDialog +from sims4communitylib.dialogs.option_dialogs.common_choose_object_option_dialog import CommonChooseObjectOptionDialog +from sims4communitylib.dialogs.option_dialogs.common_choose_option_dialog import CommonChooseOptionDialog +from sims4communitylib.dialogs.option_dialogs.common_option_dialog import CommonOptionDialog +from sims4communitylib.dialogs.option_dialogs.options.common_dialog_option import CommonDialogOption +from sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext, \ + DialogOptionValueType +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_object_option import CommonDialogObjectOption +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from sims4communitylib.utils.common_icon_utils import CommonIconUtils +from ui.ui_dialog import UiDialogBase + + +class CommonMultiPaneChooseOptionDialog(CommonOptionDialog): + """CommonMultiPaneChooseOptionDialog(\ + mod_identity,\ + title_identifier,\ + description_identifier,\ + title_tokens=(),\ + description_tokens=(),\ + on_close=CommonFunctionUtils.noop\ + ) + + A container for multiple choose option dialogs. + + .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_multi_pane_choose_option_dialog` in the in-game console. + + .. warning:: This dialog does not currently work with `CommonChooseSimOptionDialog` or `CommonChooseSimsOptionDialog`. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + def _on_option_chosen_in_dialog_one(option_identifier: str, choice: str): + pass + + def _on_option_chosen_in_dialog_two(option_identifier: str, choice: str): + pass + + def _on_submit(chosen_options: Dict[int, Any]): + 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 + ), + ) + + sub_dialog_one = 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 + ) + + sub_dialog_one.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_in_dialog_one + ) + ) + + sub_dialog_one.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_in_dialog_one + ) + ) + + sub_dialog_one.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_in_dialog_one + ) + ) + + sub_dialog_two = 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 + ) + + sub_dialog_two.add_option( + CommonDialogObjectOption( + 'Option 4', + 'Value 4', + CommonDialogOptionContext( + CommonStringId.TESTING_SOME_TEXT_FOR_TESTING, + CommonStringId.TESTING_TEST_BUTTON_ONE, + icon=CommonIconUtils.load_checked_square_icon() + ), + on_chosen=_on_option_chosen_in_dialog_two + ) + ) + + sub_dialog_two.add_option( + CommonDialogObjectOption( + 'Option 5', + 'Value 5', + CommonDialogOptionContext( + CommonStringId.TESTING_SOME_TEXT_FOR_TESTING, + CommonStringId.TESTING_TEST_BUTTON_TWO, + icon=CommonIconUtils.load_arrow_navigate_into_icon() + ), + on_chosen=_on_option_chosen_in_dialog_two + ) + ) + + sub_dialog_two.add_option( + CommonDialogObjectOption( + 'Option 6', + 'Value 6', + CommonDialogOptionContext( + CommonLocalizationUtils.create_localized_string('Value 3'), + CommonStringId.TESTING_TEST_BUTTON_TWO, + icon=CommonIconUtils.load_arrow_navigate_into_icon() + ), + on_chosen=_on_option_chosen_in_dialog_two + ) + ) + + option_dialog = CommonMultiPaneChooseOptionDialog( + ModInfo.get_identity(), + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + title_tokens=title_tokens, + description_tokens=description_tokens + ) + + option_dialog.add_sub_dialog(sub_dialog_one) + option_dialog.add_sub_dialog(sub_dialog_two) + + option_dialog.show( + on_submit=_on_submit, + sim_info=CommonSimUtils.get_active_sim_info() + ) + + + :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. + :type mod_identity: CommonModIdentity + :param title_identifier: A decimal identifier of the title text. + :type title_identifier: Union[int, str, LocalizedString, CommonStringId] + :param description_identifier: A decimal identifier of the description text. + :type description_identifier: Union[int, str, LocalizedString, CommonStringId] + :param title_tokens: An iterator of Tokens to format into the title. Default is an empty collection. + :type title_tokens: Iterator[Any], optional + :param description_tokens: An iterator of Tokens to format into the description. Default is an empty collection. + :type description_tokens: Iterator[Any], optional + :param on_close: A callback invoked upon the dialog closing. Default is CommonFunctionUtils.noop. + :type on_close: Callable[[], None], optional + """ + def __init__( + self, + mod_identity: CommonModIdentity, + title_identifier: Union[int, str, LocalizedString, CommonStringId], + description_identifier: Union[int, str, LocalizedString, CommonStringId], + title_tokens: Iterator[Any]=(), + description_tokens: Iterator[Any]=(), + on_close: Callable[[], None]=CommonFunctionUtils.noop + ): + super().__init__( + CommonMultiPaneChooseDialog( + mod_identity, + title_identifier, + description_identifier, + title_tokens=title_tokens, + description_tokens=description_tokens + ), + on_close=on_close + ) + + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + return 's4cl_multi_pane_choose_option_dialog' + + @property + def _internal_dialog(self) -> CommonMultiPaneChooseDialog: + result: CommonMultiPaneChooseDialog = super()._internal_dialog + return result + + def add_sub_dialog(self, sub_dialog: CommonChooseOptionDialog, *dialog_arguments: Any, **dialog_keyword_arguments: Any): + """add_sub_dialog(sub_dialog, *dialog_arguments, **dialog_keyword_arguments) + + Add a sub dialog. + + :param sub_dialog: An instance of a choose option dialog. + :type sub_dialog: CommonChooseOptionDialog + :param dialog_arguments: Arguments to pass to the sub dialog when building it. + :type dialog_arguments: Any, optional + :param dialog_keyword_arguments: Keyword arguments to pass to the sub dialog when building it. + :type dialog_keyword_arguments: Any, optional + """ + self._internal_dialog.add_sub_dialog(sub_dialog._internal_dialog, *dialog_arguments, **dialog_keyword_arguments) + + def show( + self, + on_submit: Callable[[Dict[int, Tuple[Any]]], Any]=CommonFunctionUtils.noop, + sim_info: SimInfo=None + ): + """show(\ + on_submit=CommonFunctionUtils.noop,\ + sim_info=None\ + ) + + Show the dialog and invoke the callbacks upon the player submitting their selections. + + :param on_submit: A callback invoked upon the player submitting the dialog and the choices within it.\ + Each choice is mapped as follows: The key is the index of the dialog a value belongs to, starting at 0. The value is the choice made within that dialog. Default is CommonFunctionUtils.noop. + :type on_submit: Callable[[Dict[int, Tuple[Any]]], Any], optional + :param sim_info: The SimInfo of the Sim that will appear in the dialog image. The default Sim is the active Sim. Default is None. + :type sim_info: SimInfo, optional + """ + try: + return self._internal_dialog.show(on_submit=self._on_submit(on_submit=on_submit), sim_info=sim_info) + except Exception as ex: + self.log.error('multi_pane_choose_option.show', exception=ex) + + def build_dialog( + self, + on_submit: Callable[[Dict[int, Tuple[Any]]], bool]=CommonFunctionUtils.noop, + sim_info: SimInfo=None + ) -> Union[UiDialogBase, None]: + """build_dialog(\ + on_submit=CommonFunctionUtils.noop,\ + sim_info=None\ + ) + + Build the dialog and invoke the callbacks upon the player submitting their selections. + + :param on_submit: A callback invoked upon the player submitting the dialog and the choices within it.\ + Default is CommonFunctionUtils.noop. Each choice is mapped as follows The key is the dialog index starting at 0. The value is the choice made within that sub dialog. Default is CommonFunctionUtils.noop. + :type on_submit: Callable[[Dict[int, Tuple[Any]]], Any], optional + :param sim_info: The SimInfo of the Sim that will appear in the dialog image. The default Sim is the active Sim. Default is None. + :type sim_info: SimInfo, optional + """ + try: + return self._internal_dialog.build_dialog(on_submit=self._on_submit(on_submit=on_submit), sim_info=sim_info) + except Exception as ex: + self.log.error('multi_pane_choose_option.build_dialog', exception=ex) + return None + + def _on_submit( + self, + on_submit: Callable[[Dict[int, Tuple[Any]]], Any]=CommonFunctionUtils.noop + ) -> Callable[[Dict[int, Tuple[CommonDialogOption]], CommonChoiceOutcome], bool]: + def _on_submit(chosen_options: Dict[int, Tuple[CommonDialogOption]], outcome: CommonChoiceOutcome) -> bool: + try: + if chosen_options is None or not chosen_options or CommonChoiceOutcome.is_error_or_cancel(outcome): + self.log.debug('No options chosen.') + self.close() + return False + + self.log.debug('Chose options: {} with outcome: {}'.format(pformat(chosen_options), pformat(outcome))) + chosen_values: Dict[int, DialogOptionValueType] = dict() + for chosen_option_index in chosen_options: + self.log.debug('Chosen option index: {}'.format(chosen_option_index)) + chosen_option_options = chosen_options[chosen_option_index] + chosen_option_values: List[Any] = list() + for chosen_option_option in chosen_option_options: + chosen_option_values.append(chosen_option_option.value) + self.log.debug('Chose value for option: {}'.format(chosen_option_option.value)) + chosen_option_option.choose() + chosen_values[chosen_option_index] = tuple(chosen_option_values) + + self.log.debug('Submitting choices: {}'.format(pformat(chosen_values))) + return on_submit(chosen_values) + except Exception as ex: + self.log.error('Error occurred on submitting a value.', exception=ex) + return False + return _on_submit + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_testing.show_multi_pane_choose_option_dialog', + 'Show an example of CommonMultiPaneChooseOptionDialog.' +) +def _common_testing_show_multi_pane_choose_option_dialog(output: CommonConsoleCommandOutput): + output('Showing test multi pane choose option dialog.') + + def _on_option_chosen_in_dialog_one(option_identifier: str, choice: str): + output('Chose option in dialog one {} with value: {}.'.format(pformat(option_identifier), pformat(choice))) + + def _on_option_chosen_in_dialog_two(option_identifier: str, choice: str): + output('Chose option in dialog two {} with value: {}.'.format(pformat(option_identifier), pformat(choice))) + + def _on_submit(chosen_options: Dict[int, Any]): + output('Chosen options from all dialogs {}.'.format(pformat(chosen_options))) + + # 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 + ), + ) + + sub_dialog_one = 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 + ) + + sub_dialog_one.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_in_dialog_one + ) + ) + + sub_dialog_one.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_in_dialog_one + ) + ) + + sub_dialog_one.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_in_dialog_one + ) + ) + + sub_dialog_two = 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 + ) + + sub_dialog_two.add_option( + CommonDialogObjectOption( + 'Option 4', + 'Value 4', + CommonDialogOptionContext( + CommonStringId.TESTING_SOME_TEXT_FOR_TESTING, + CommonStringId.TESTING_TEST_BUTTON_ONE, + icon=CommonIconUtils.load_checked_square_icon() + ), + on_chosen=_on_option_chosen_in_dialog_two + ) + ) + + sub_dialog_two.add_option( + CommonDialogObjectOption( + 'Option 5', + 'Value 5', + CommonDialogOptionContext( + CommonStringId.TESTING_SOME_TEXT_FOR_TESTING, + CommonStringId.TESTING_TEST_BUTTON_TWO, + icon=CommonIconUtils.load_arrow_navigate_into_icon() + ), + on_chosen=_on_option_chosen_in_dialog_two + ) + ) + + sub_dialog_two.add_option( + CommonDialogObjectOption( + 'Option 6', + 'Value 6', + CommonDialogOptionContext( + CommonLocalizationUtils.create_localized_string('Value 3'), + CommonStringId.TESTING_TEST_BUTTON_TWO, + icon=CommonIconUtils.load_arrow_navigate_into_icon() + ), + on_chosen=_on_option_chosen_in_dialog_two + ) + ) + + option_dialog = CommonMultiPaneChooseOptionDialog( + ModInfo.get_identity(), + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + title_tokens=title_tokens, + description_tokens=description_tokens + ) + + option_dialog.add_sub_dialog(sub_dialog_one) + option_dialog.add_sub_dialog(sub_dialog_two) + + option_dialog.show( + on_submit=_on_submit, + sim_info=CommonSimUtils.get_active_sim_info() + ) + output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_option_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_option_dialog.py new file mode 100644 index 0000000..d421539 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_option_dialog.py @@ -0,0 +1,95 @@ +""" +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 +""" +from typing import Any, Callable, Union +from protocolbuffers.Localization_pb2 import LocalizedString +from sims4communitylib.dialogs.common_dialog import CommonDialog +from sims4communitylib.logging.has_log import HasLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from ui.ui_dialog import UiDialogBase + + +class CommonOptionDialog(HasLog): + """CommonOptionDialog(\ + internal_dialog,\ + on_close=CommonFunctionUtils.noop\ + ) + + A dialog that displays that displays options. + + .. warning:: Unless you know what you are doing, do not create an instance of this class directly! + + :param internal_dialog: The dialog this option dialog wraps. + :type internal_dialog: CommonDialog + :param on_close: A callback invoked upon the dialog closing. Default is CommonFunctionUtils.noop. + :type on_close: Callable[[], None], optional + """ + def __init__( + self, + internal_dialog: CommonDialog, + on_close: Callable[[], None]=CommonFunctionUtils.noop + ): + super().__init__() + self._on_close = on_close + self.__internal_dialog = internal_dialog + + # noinspection PyMissingOrEmptyDocstring + @property + def mod_identity(self) -> CommonModIdentity: + return self._internal_dialog.mod_identity + + @property + def title(self) -> LocalizedString: + """The title of the dialog. + + :return: The title of the dialog. + :rtype: LocalizedString + """ + return self._internal_dialog.title + + @property + def description(self) -> LocalizedString: + """The description of the dialog. + + :return: The description of the dialog. + :rtype: LocalizedString + """ + return self._internal_dialog.description + + @property + def _internal_dialog(self) -> CommonDialog: + return self.__internal_dialog + + def show(self, *_: Any, **__: Any): + """show(*_, **__) + + Show the dialog. + + .. note:: Override this function to provide your own arguments. + + """ + raise NotImplementedError('\'{}\' not implemented.'.format(self.__class__.show.__name__)) + + def build_dialog(self, *_: Any, **__: Any) -> Union[UiDialogBase, None]: + """build_dialog(*_, **__) + + Build the dialog. + + .. note:: Override this function to provide your own arguments. + + :return: The built dialog or None if a problem occurs. + :rtype: Union[UiDialogBase, None] + """ + raise NotImplementedError('\'{}\' not implemented.'.format(self.__class__.build_dialog.__name__)) + + def close(self) -> None: + """close() + + Close the dialog. + """ + return self._on_close() diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/__init__.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/common_dialog_option.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/common_dialog_option.py new file mode 100644 index 0000000..9673631 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/common_dialog_option.py @@ -0,0 +1,146 @@ +""" +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 +""" +from typing import Any, Callable, Union, Tuple + +from protocolbuffers.Localization_pb2 import LocalizedString +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from ui.ui_dialog_picker import BasePickerRow +from sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext, \ + DialogOptionValueType + + +class CommonDialogOption: + """CommonDialogOption(value, context, on_chosen=CommonFunctionUtils.noop) + + An option the player can choose within a dialog. + + :param value: The value of the option. + :type value: DialogOptionValueType + :param context: A context to customize the dialog option. + :type context: CommonDialogOptionContext + :param on_chosen: A callback invoked when the dialog option is chosen. + :type on_chosen: Callable[[DialogOptionValueType], Any], optional + """ + def __init__( + self, + value: DialogOptionValueType, + context: CommonDialogOptionContext, + on_chosen: Callable[[DialogOptionValueType], Any]=CommonFunctionUtils.noop + ): + if context is None: + raise AttributeError('Missing required argument \'context\'') + + self._value = value + self._option_context = context + self._on_chosen = on_chosen + + @property + def title(self) -> LocalizedString: + """The title of the option. + + :return: The title of the option. + :rtype: LocalizedString + """ + return self.context.title + + @property + def description(self) -> LocalizedString: + """The description of the option. + + :return: The description of the option. + :rtype: LocalizedString + """ + return self.context.description + + @property + def tooltip(self) -> Union[CommonLocalizationUtils.LocalizedTooltip, None]: + """The tooltip displayed to the player on hover. + + :return: The tooltip displayed when hovering the option or None if no tooltip specified. + :rtype: Union[CommonLocalizationUtils.LocalizedTooltip, None] + """ + return self.context.tooltip + + @property + def icon(self) -> Any: + """The icon of the option. + + :return: The icon of the option. + :rtype: Any + """ + return self.context.icon + + @property + def tag_list(self) -> Tuple[str]: + """A collection of tags used to filter the option. + + :return: A collection of tags used to filter the option. + :rtype: Tuple[str] + """ + return self.context.tag_list + + @property + def hashed_tag_list(self) -> Tuple[int]: + """Same as tag_list, but the values are hashed. + + :return: Same as tag_list, but the values are hashed. + :rtype: Tuple[str] + """ + return self.context.hashed_tag_list + + @property + def context(self) -> CommonDialogOptionContext: + """The context of the option. + + :return: The context of the option. + :rtype: CommonDialogOptionContext + """ + return self._option_context + + @property + def value(self) -> DialogOptionValueType: + """The value of the option. + + :return: The value of the option. + :rtype: DialogOptionValueType + """ + return self._value + + @property + def on_chosen(self) -> Callable[[DialogOptionValueType], Any]: + """The action to perform upon choosing this option. + + :return: The action to perform upon choosing this option. + :rtype: Callable[[DialogOptionValueType], Any] + """ + return self._on_chosen + + def choose(self) -> Any: + """choose() + + Choose the option. + + :return: The result of choosing the option. + :rtype: Any + """ + if self.on_chosen is None: + return None + return self.on_chosen(self.value) + + def as_row(self, option_id: int) -> BasePickerRow: + """as_row(option_id) + + Convert the option into a picker row. + + :param option_id: The index of the option. + :type option_id: int + :return: The option as a Picker Row + :rtype: BasePickerRow + """ + raise NotImplementedError('\'{}\' not implemented.'.format(self.__class__.as_row.__name__)) diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/common_dialog_option_context.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/common_dialog_option_context.py new file mode 100644 index 0000000..bb6e497 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/common_dialog_option_context.py @@ -0,0 +1,144 @@ +""" +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 +""" +from typing import Union, Any, TypeVar, Iterator, Tuple, List +from protocolbuffers.Localization_pb2 import LocalizedString +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils + +DialogOptionValueType = TypeVar('DialogOptionValueType') + + +class CommonDialogOptionContext: + """CommonDialogOptionContext(\ + title_identifier,\ + description_identifier,\ + description_tokens=(),\ + tooltip_text_identifier=None,\ + tooltip_tokens=(),\ + icon=None,\ + is_enabled=True,\ + is_selected=False,\ + tag_list=()\ + ) + + A context used by :class:`.CommonDialogOption` that provides customization of options. + + :param title_identifier: The title of the option. + :type title_identifier: Union[int, str, LocalizedString, CommonStringId] + :param description_identifier: The description of the option. + :type description_identifier: Union[int, str, LocalizedString, CommonStringId] + :param title_tokens: An iterator of Tokens that will be formatted into the title. + :type title_tokens: Iterator[Any], optional + :param description_tokens: An iterator of Tokens that will be formatted into the description. + :type description_tokens: Iterator[Any], optional + :param tooltip_text_identifier: Text that will be displayed upon hovering the option. + :type tooltip_text_identifier: Union[int, str, LocalizedString, CommonStringId], optional + :param tooltip_tokens: An iterator of Tokens that will be formatted into the tooltip text. + :type tooltip_tokens: Tuple[Any], optional + :param icon: The icon to display for the option. + :type icon: Any, optional + :param is_enabled: If True, the dialog option will be selectable in the dialog. If False, the dialog option will be disabled in the dialog. + :type is_enabled: bool, optional + :param is_selected: If True, the dialog option will already be selected in the dialog. If False, the dialog option will not be selected in the dialog. + :type is_selected: bool, optional + """ + def __init__( + self, + title_identifier: Union[int, str, LocalizedString, CommonStringId], + description_identifier: Union[int, str, LocalizedString, CommonStringId], + title_tokens: Iterator[Any]=(), + description_tokens: Iterator[Any]=(), + tooltip_text_identifier: Union[int, str, LocalizedString, CommonStringId]=None, + tooltip_tokens: Iterator[Any]=(), + icon: Any=None, + is_enabled: bool=True, + is_selected: bool=False, + tag_list: Iterator[str]=() + ): + self._title = CommonLocalizationUtils.create_localized_string(title_identifier, tokens=tuple(title_tokens)) + self._description = CommonLocalizationUtils.create_localized_string(description_identifier, tokens=tuple(description_tokens)) + self._tooltip = CommonLocalizationUtils.create_localized_tooltip(tooltip_text_identifier, tooltip_tokens=tuple(tooltip_tokens)) + self._icon = icon + self._is_enabled = is_enabled + self._is_selected = is_selected + self._tag_list = tuple(tag_list) + + @property + def is_enabled(self) -> bool: + """Determine if the dialog option is enabled. + + :return: True, if the dialog option is enabled. False, if not. + :rtype: bool + """ + return self._is_enabled + + @property + def is_selected(self) -> bool: + """Determine if the dialog option is selected. + + :return: True, if the dialog option is selected. False, if not. + :rtype: bool + """ + return self._is_selected + + @property + def title(self) -> LocalizedString: + """The title of the dialog option. + + :return: The title of the dialog option. + :rtype: LocalizedString + """ + return self._title + + @property + def description(self) -> LocalizedString: + """A description of what the dialog option does. + + :return: A description of what the dialog option does. + :rtype: LocalizedString + """ + return self._description + + @property + def tooltip(self) -> Union[CommonLocalizationUtils.LocalizedTooltip, None]: + """The tooltip displayed to the player on hover. + + :return: The tooltip displayed to the player on hover or None if no tooltip was specified. + :rtype: Union[CommonLocalizationUtils.LocalizedTooltip, None] + """ + return self._tooltip + + @property + def tag_list(self) -> Tuple[str]: + """A collection of tags used to filter the option. + + :return: A collection of tags used to filter the option. + :rtype: Tuple[str] + """ + return self._tag_list + + @property + def hashed_tag_list(self) -> Tuple[int]: + """Same as tag_list, but the values are hashed. + + :return: Same as :py:attr:`~tag_list`, but the values are hashed. + :rtype: Tuple[str] + """ + hashed_tag_list: List[int] = list() + for tag in self.tag_list: + hashed_tag_list.append((abs(hash(tag)) % (10 ** 8))) + return tuple(hashed_tag_list) + + @property + def icon(self) -> Any: + """The icon displayed for this dialog option. + + :return: The icon displayed for this dialog option. + :rtype: Any + """ + return self._icon diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/__init__.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_action_option.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_action_option.py new file mode 100644 index 0000000..85f4894 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_action_option.py @@ -0,0 +1,43 @@ +""" +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 +""" +from typing import Any, Callable + +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext +from sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_select_option import CommonDialogSelectOption + + +class CommonDialogActionOption(CommonDialogSelectOption): + """CommonDialogActionOption(context, on_chosen=CommonFunctionUtils.noop, always_visible=False) + + An option that invokes a callback upon being chosen. + + :param context: A context to customize the dialog option. + :type context: CommonDialogOptionContext + :param on_chosen: A callback invoked when the dialog option is chosen. + :type on_chosen: Callable[..., Any], optional + :param always_visible: If set to True, the option will always appear in the dialog no matter which page.\ + If False, the option will act as normal. Default is False. + :type always_visible: bool, optional + """ + def __init__( + self, + context: CommonDialogOptionContext, + on_chosen: Callable[..., Any]=CommonFunctionUtils.noop, + always_visible: bool=False + ): + def _on_chosen(_, __) -> None: + on_chosen() + + super().__init__( + 'Dialog Action', + None, + context, + on_chosen=_on_chosen, + always_visible=always_visible + ) diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_branch_option.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_branch_option.py new file mode 100644 index 0000000..9b884ed --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_branch_option.py @@ -0,0 +1,50 @@ +""" +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 +""" +from typing import Any, Callable +from sims4communitylib.dialogs.option_dialogs.common_option_dialog import CommonOptionDialog +from sims4communitylib.utils.common_icon_utils import CommonIconUtils +from sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_object_option import CommonDialogObjectOption +from sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext + + +class CommonDialogOpenDialogOption(CommonDialogObjectOption): + """CommonDialogOpenDialogOption(create_dialog_callback, context, always_visible=False) + + An option that branches into other options. + + :param create_dialog_callback: A callback invoked when the dialog option is chosen. It should open a dialog. + :type create_dialog_callback: Callable[..., CommonOptionDialog] + :param context: A context to customize the dialog option. + :type context: CommonDialogOptionContext + :param always_visible: If set to True, the option will always appear in the dialog no matter which page.\ + If False, the option will act as normal. Default is False. + :type always_visible: bool, optional + """ + def __init__( + self, + create_dialog_callback: Callable[..., CommonOptionDialog], + context: CommonDialogOptionContext, + always_visible: bool=False + ): + def _on_chosen(_, __) -> None: + create_dialog_callback().show() + + super().__init__( + 'Dialog Branch', + None, + context, + on_chosen=_on_chosen, + always_visible=always_visible + ) + + # noinspection PyMissingOrEmptyDocstring + @property + def icon(self) -> Any: + if super().icon is not None: + return super().icon + return CommonIconUtils.load_arrow_navigate_into_icon() diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_integer_option.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_integer_option.py new file mode 100644 index 0000000..ea9af84 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_integer_option.py @@ -0,0 +1,107 @@ +""" +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 +""" +from typing import Any, Callable, Union, Iterator + +from protocolbuffers.Localization_pb2 import LocalizedString +from sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome +from sims4communitylib.dialogs.common_input_integer_dialog import CommonInputIntegerDialog +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from sims4communitylib.utils.common_icon_utils import CommonIconUtils +from sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_object_option import \ + CommonDialogObjectOption, DialogOptionIdentifierType +from sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils + + +class CommonDialogInputIntegerOption(CommonDialogObjectOption): + """CommonDialogInputIntegerOption(\ + mod_identity,\ + option_identifier,\ + initial_value,\ + context,\ + min_value=0,\ + max_value=2147483647,\ + on_chosen=CommonFunctionUtils.noop,\ + always_visible=False,\ + dialog_description_identifier=None,\ + dialog_description_tokens=()\ + ) + + An option to open a dialog to input an integer value. + + :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. + :type mod_identity: CommonModIdentity + :param option_identifier: A string that identifies the option from other options. + :type option_identifier: DialogOptionIdentifierType + :param initial_value: The value the option will have initially + :type initial_value: int + :param context: A context to customize the dialog option. + :type context: CommonDialogOptionContext + :param min_value: The minimum value allowed to be entered. + :type min_value: int, optional + :param max_value: The maximum value allowed to be entered. + :type max_value: int, optional + :param on_chosen: A callback invoked when the dialog option is chosen. args: (option_identifier, entered value, outcome) + :type on_chosen: Callable[[DialogOptionIdentifierType, int, CommonChoiceOutcome], None], optional + :param always_visible: If set to True, the option will always appear in the dialog no matter which page.\ + If False, the option will act as normal. Default is False. + :type always_visible: bool, optional + :param dialog_description_identifier: The description that will display in the input dialog separately from the option.\ + If not provided the description from the provided context will be used instead. + :type dialog_description_identifier: Union[int, str, LocalizedString, CommonStringId], optional + :param dialog_description_tokens: An iterator of Tokens that will be formatted into the dialog description. + :type dialog_description_tokens: Iterator[Any], optional + """ + def __init__( + self, + mod_identity: CommonModIdentity, + option_identifier: DialogOptionIdentifierType, + initial_value: int, + context: CommonDialogOptionContext, + min_value: int=0, + max_value: int=2147483647, + on_chosen: Callable[[DialogOptionIdentifierType, int, CommonChoiceOutcome], None]=CommonFunctionUtils.noop, + always_visible: bool=False, + dialog_description_identifier: Union[int, str, LocalizedString, CommonStringId]=None, + dialog_description_tokens: Iterator[Any]=() + ): + if dialog_description_identifier is not None: + dialog_description = CommonLocalizationUtils.create_localized_string(dialog_description_identifier, tokens=tuple(dialog_description_tokens)) + else: + dialog_description = context.description + self._dialog = CommonInputIntegerDialog( + context.title, + dialog_description, + initial_value, + min_value=min_value, + max_value=max_value, + mod_identity=mod_identity + ) + + def _on_submit(_: int, __: CommonChoiceOutcome): + on_chosen(self.option_identifier, _, __) + + def _on_chosen(_, __) -> None: + self._dialog.show(on_submit=_on_submit) + + super().__init__( + option_identifier, + None, + context, + on_chosen=_on_chosen, + always_visible=always_visible + ) + + # noinspection PyMissingOrEmptyDocstring + @property + def icon(self) -> Any: + if super().icon is not None: + return super().icon + return CommonIconUtils.load_arrow_right_icon() diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_multi_text_option.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_multi_text_option.py new file mode 100644 index 0000000..890d1bf --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_multi_text_option.py @@ -0,0 +1,98 @@ +""" +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 +""" +from typing import Any, Callable, Union, Iterator, Dict + +from protocolbuffers.Localization_pb2 import LocalizedString +from sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome +from sims4communitylib.dialogs.common_input_multi_text_dialog import CommonInputMultiTextDialog +from sims4communitylib.dialogs.common_input_text_field import CommonInputTextField +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from sims4communitylib.utils.common_icon_utils import CommonIconUtils +from sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_object_option import \ + CommonDialogObjectOption, DialogOptionIdentifierType +from sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils + + +class CommonDialogInputMultiTextOption(CommonDialogObjectOption): + """CommonDialogInputMultiTextOption(\ + mod_identity,\ + option_identifier,\ + input_fields,\ + context,\ + on_chosen=CommonFunctionUtils.noop,\ + always_visible=False,\ + dialog_description_identifier=None,\ + dialog_description_tokens=()\ + ) + + An option to open a dialog to input a text value. + + :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. + :type mod_identity: CommonModIdentity + :param option_identifier: A string that identifies the option from other options. + :type option_identifier: DialogOptionIdentifierType + :param input_fields: An iterator of input fields to display in the dialog when the option is chosen. + :type input_fields: Iterator[CommonInputTextField] + :param context: A context to customize the dialog option. + :type context: CommonDialogOptionContext + :param on_chosen: A callback invoked when the dialog option is chosen. args: (option_identifier, entered value, outcome) + :type on_chosen: Callable[[DialogOptionIdentifierType, int, CommonChoiceOutcome], None], optional + :param always_visible: If set to True, the option will always appear in the dialog no matter which page.\ + If False, the option will act as normal. Default is False. + :type always_visible: bool, optional + :param dialog_description_identifier: The description that will display in the input dialog separately from the option.\ + If not provided the description from the provided context will be used instead. + :type dialog_description_identifier: Union[int, str, LocalizedString, CommonStringId], optional + :param dialog_description_tokens: An iterator of Tokens that will be formatted into the dialog description. + :type dialog_description_tokens: Iterator[Any], optional + """ + def __init__( + self, + mod_identity: CommonModIdentity, + option_identifier: DialogOptionIdentifierType, + input_fields: Iterator[CommonInputTextField], + context: CommonDialogOptionContext, + on_chosen: Callable[[DialogOptionIdentifierType, Dict[str, str], CommonChoiceOutcome], None]=CommonFunctionUtils.noop, + always_visible: bool=False, + dialog_description_identifier: Union[int, str, LocalizedString, CommonStringId]=None, + dialog_description_tokens: Iterator[Any]=() + ): + if dialog_description_identifier is not None: + dialog_description = CommonLocalizationUtils.create_localized_string(dialog_description_identifier, tokens=tuple(dialog_description_tokens)) + else: + dialog_description = context.description + self._dialog = CommonInputMultiTextDialog( + mod_identity, + context.title, + dialog_description, + input_fields + ) + + def _on_submit(_: Dict[str, str], __: CommonChoiceOutcome): + on_chosen(self.option_identifier, _, __) + + def _on_chosen(_, __) -> None: + self._dialog.show(on_submit=_on_submit) + + super().__init__( + option_identifier, + None, + context, + on_chosen=_on_chosen, + always_visible=always_visible + ) + + # noinspection PyMissingOrEmptyDocstring + @property + def icon(self) -> Any: + if super().icon is not None: + return super().icon + return CommonIconUtils.load_arrow_right_icon() diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_option.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_option.py new file mode 100644 index 0000000..55a2cc0 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_option.py @@ -0,0 +1,101 @@ +""" +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 +""" +from typing import Any, Callable, Union, Iterator + +from protocolbuffers.Localization_pb2 import LocalizedString +from sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from sims4communitylib.utils.common_icon_utils import CommonIconUtils +from sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_object_option import \ + CommonDialogObjectOption, DialogOptionIdentifierType +from sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext +from sims4communitylib.dialogs.common_input_float_dialog import CommonInputFloatDialog +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils + + +class CommonDialogInputFloatOption(CommonDialogObjectOption): + """CommonDialogInputFloatOption(\ + option_identifier,\ + initial_value,\ + context,\ + min_value=0.0,\ + max_value=2147483647.0,\ + on_chosen=CommonFunctionUtils.noop,\ + always_visible=False,\ + dialog_description_identifier=None,\ + dialog_description_tokens=()\ + ) + + An option to open a dialog to input a float value. + + :param option_identifier: A string that identifies the option from other options. + :type option_identifier: DialogOptionIdentifierType + :param initial_value: The value the option will have initially + :type initial_value: float + :param context: A context to customize the dialog option. + :type context: CommonDialogOptionContext + :param min_value: The minimum value allowed to be entered. + :type min_value: float, optional + :param max_value: The maximum value allowed to be entered. + :type max_value: float, optional + :param on_chosen: A callback invoked when the dialog option is chosen. args: (option_identifier, entered value, outcome) + :type on_chosen: Callable[[DialogOptionIdentifierType, float, CommonChoiceOutcome], None], optional + :param always_visible: If set to True, the option will always appear in the dialog no matter which page.\ + If False, the option will act as normal. Default is False. + :type always_visible: bool, optional + :param dialog_description_identifier: The description that will display in the input dialog separately from the option.\ + If not provided the description from the provided context will be used instead. + :type dialog_description_identifier: Union[int, str, LocalizedString, CommonStringId], optional + :param dialog_description_tokens: An iterator of Tokens that will be formatted into the dialog description. + :type dialog_description_tokens: Iterator[Any], optional + """ + def __init__( + self, + option_identifier: DialogOptionIdentifierType, + initial_value: float, + context: CommonDialogOptionContext, + min_value: float=0.0, + max_value: float=2147483647.0, + on_chosen: Callable[[DialogOptionIdentifierType, float, CommonChoiceOutcome], None]=CommonFunctionUtils.noop, + always_visible: bool=False, + dialog_description_identifier: Union[int, str, LocalizedString, CommonStringId]=None, + dialog_description_tokens: Iterator[Any]=() + ): + if dialog_description_identifier is not None: + dialog_description = CommonLocalizationUtils.create_localized_string(dialog_description_identifier, tokens=tuple(dialog_description_tokens)) + else: + dialog_description = context.description + self._dialog = CommonInputFloatDialog( + context.title, + dialog_description, + initial_value, + min_value=min_value, + max_value=max_value + ) + + def _on_submit(_: float, __: CommonChoiceOutcome): + on_chosen(self.option_identifier, _, __) + + def _on_chosen(_, __) -> None: + self._dialog.show(on_submit=_on_submit) + + super().__init__( + option_identifier, + None, + context, + on_chosen=_on_chosen, + always_visible=always_visible + ) + + # noinspection PyMissingOrEmptyDocstring + @property + def icon(self) -> Any: + if super().icon is not None: + return super().icon + return CommonIconUtils.load_arrow_right_icon() diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_text_option.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_text_option.py new file mode 100644 index 0000000..6ed167e --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_text_option.py @@ -0,0 +1,97 @@ +""" +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 +""" +from typing import Any, Callable, Union, Iterator + +from protocolbuffers.Localization_pb2 import LocalizedString +from sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome +from sims4communitylib.dialogs.common_input_text_dialog import CommonInputTextDialog +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from sims4communitylib.utils.common_icon_utils import CommonIconUtils +from sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_object_option import \ + CommonDialogObjectOption, DialogOptionIdentifierType +from sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils + + +class CommonDialogInputTextOption(CommonDialogObjectOption): + """CommonDialogInputTextOption(\ + mod_identity,\ + option_identifier,\ + initial_value,\ + context,\ + on_chosen=CommonFunctionUtils.noop,\ + always_visible=False,\ + dialog_description_identifier=None,\ + dialog_description_tokens=()\ + ) + + An option to open a dialog to input a text value. + + :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. + :type mod_identity: CommonModIdentity + :param option_identifier: A string that identifies the option from other options. + :type option_identifier: DialogOptionIdentifierType + :param initial_value: The value the option will have initially + :type initial_value: str + :param context: A context to customize the dialog option. + :type context: CommonDialogOptionContext + :param on_chosen: A callback invoked when the dialog option is chosen. args: (option_identifier, entered value, outcome) + :type on_chosen: Callable[[DialogOptionIdentifierType, int, CommonChoiceOutcome], None], optional + :param always_visible: If set to True, the option will always appear in the dialog no matter which page.\ + If False, the option will act as normal. Default is False. + :type always_visible: bool, optional + :param dialog_description_identifier: The description that will display in the input dialog separately from the option.\ + If not provided the description from the provided context will be used instead. + :type dialog_description_identifier: Union[int, str, LocalizedString, CommonStringId], optional + :param dialog_description_tokens: An iterator of Tokens that will be formatted into the dialog description. + :type dialog_description_tokens: Iterator[Any], optional + """ + def __init__( + self, + mod_identity: CommonModIdentity, + option_identifier: DialogOptionIdentifierType, + initial_value: str, + context: CommonDialogOptionContext, + on_chosen: Callable[[DialogOptionIdentifierType, str, CommonChoiceOutcome], None]=CommonFunctionUtils.noop, + always_visible: bool=False, + dialog_description_identifier: Union[int, str, LocalizedString, CommonStringId]=None, + dialog_description_tokens: Iterator[Any]=() + ): + if dialog_description_identifier is not None: + dialog_description = CommonLocalizationUtils.create_localized_string(dialog_description_identifier, tokens=tuple(dialog_description_tokens)) + else: + dialog_description = context.description + self._dialog = CommonInputTextDialog( + mod_identity, + context.title, + dialog_description, + initial_value + ) + + def _on_submit(_: str, __: CommonChoiceOutcome): + on_chosen(self.option_identifier, _, __) + + def _on_chosen(_, __) -> None: + self._dialog.show(on_submit=_on_submit) + + super().__init__( + option_identifier, + None, + context, + on_chosen=_on_chosen, + always_visible=always_visible + ) + + # noinspection PyMissingOrEmptyDocstring + @property + def icon(self) -> Any: + if super().icon is not None: + return super().icon + return CommonIconUtils.load_arrow_right_icon() diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_object_option.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_object_option.py new file mode 100644 index 0000000..963d975 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_object_option.py @@ -0,0 +1,102 @@ +""" +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 +""" +from typing import Any, Callable, TypeVar +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from ui.ui_dialog_picker import ObjectPickerRow +from sims4communitylib.dialogs.option_dialogs.options.common_dialog_option import CommonDialogOption +from sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext, \ + DialogOptionValueType + +DialogOptionIdentifierType = TypeVar('DialogOptionIdentifierType') + + +class CommonDialogObjectOption(CommonDialogOption): + """CommonDialogObjectOption(option_identifier, value, context, on_chosen=CommonFunctionUtils.noop) + + An option the player can choose within a dialog. + + :param option_identifier: A string that identifies the option from other options. + :type option_identifier: DialogOptionIdentifierType + :param value: The value of the option. + :type value: DialogOptionValueType + :param context: A context to customize the dialog option. + :type context: CommonDialogOptionContext + :param on_chosen: A callback invoked when the dialog option is chosen. The values are as follows: (option_identifier, value) + :type on_chosen: Callable[[DialogOptionIdentifierType, DialogOptionValueType], None], optional + :param always_visible: If set to True, the option will always appear in the dialog no matter which page.\ + If False, the option will act as normal. Default is False. + :type always_visible: bool, optional + """ + def __init__( + self, + option_identifier: DialogOptionIdentifierType, + value: DialogOptionValueType, + context: CommonDialogOptionContext, + on_chosen: Callable[[DialogOptionIdentifierType, DialogOptionValueType], None]=CommonFunctionUtils.noop, + always_visible: bool=False + ): + if option_identifier is None: + raise AttributeError('Missing required argument \'option_identifier\'') + + self._option_identifier = option_identifier + self._always_visible = always_visible + + def _on_chosen(val: DialogOptionValueType) -> Any: + return on_chosen(self.option_identifier, val) + + super().__init__(value, context, on_chosen=_on_chosen) + + @property + def option_identifier(self) -> DialogOptionIdentifierType: + """Used to identify the option. + + :return: The identity of the option. + :rtype: str + """ + return self._option_identifier + + @property + def value(self) -> DialogOptionValueType: + """The value of the option. + + :return: The value of the option. + :rtype: DialogOptionValueType + """ + return self._value + + @property + def always_visible(self) -> bool: + """Determine if the option will always be visible. + + :return: If set to True, the option will always appear in the dialog no matter which page.\ + If False, the option will act as normal. + :rtype: bool + """ + return self._always_visible + + def as_row(self, option_id: int) -> ObjectPickerRow: + """as_row(option_id) + + Convert the option into a picker row. + + :param option_id: The index of the option. + :type option_id: int + :return: The option as a Picker Row + :rtype: ObjectPickerRow + """ + return ObjectPickerRow( + option_id=option_id, + name=self.title, + row_description=self.description, + row_tooltip=self.tooltip, + icon=self.icon, + is_enable=self.context.is_enabled, + is_selected=self.context.is_selected, + tag_list=self.hashed_tag_list, + tag=self + ) diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_option_category.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_option_category.py new file mode 100644 index 0000000..c653647 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_option_category.py @@ -0,0 +1,32 @@ +""" +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 +""" +from typing import Union + +from protocolbuffers.Localization_pb2 import LocalizedString +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils + + +class CommonDialogObjectOptionCategory: + """CommonDialogObjectOptionCategory(object_category, icon, category_name=None) + + An option category. + + :param object_category: The category of the option. + :type object_category: str + :param icon: The decimal identifier of the icon for the category. + :type icon: int + :param category_name: The name of the category. Default is the object_category value. + :type category_name: LocalizedString + """ + def __init__(self, object_category: str, icon: int, category_name: Union[int, str, LocalizedString, CommonStringId, None] = None): + self.object_category = object_category + self.icon = icon + if category_name is None: + category_name = object_category + self.category_name = CommonLocalizationUtils.create_localized_string(category_name) diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_select_option.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_select_option.py new file mode 100644 index 0000000..f2ba2cb --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_select_option.py @@ -0,0 +1,50 @@ +""" +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 +""" +from typing import Any, Callable + +from sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import DialogOptionValueType, \ + CommonDialogOptionContext +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from sims4communitylib.utils.common_icon_utils import CommonIconUtils +from sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_object_option import \ + CommonDialogObjectOption, DialogOptionIdentifierType + + +class CommonDialogSelectOption(CommonDialogObjectOption): + """CommonDialogSelectOption(option_identifier, value, context, on_chosen=CommonFunctionUtils.noop, always_visible=False) + + An option that invokes a callback, passing in its value. + + :param option_identifier: A string that identifies the option from other options. + :type option_identifier: DialogOptionIdentifierType + :param value: The value of the option. + :type value: DialogOptionValueType + :param context: A context to customize the dialog option. + :type context: CommonDialogOptionContext + :param on_chosen: A callback invoked when the dialog option is chosen. + :type on_chosen: Callable[[DialogOptionIdentifierType, DialogOptionValueType], None], optional + :param always_visible: If set to True, the option will always appear in the dialog no matter which page.\ + If False, the option will act as normal. Default is False. + :type always_visible: bool, optional + """ + def __init__( + self, + option_identifier: DialogOptionIdentifierType, + value: DialogOptionValueType, + context: CommonDialogOptionContext, + on_chosen: Callable[[DialogOptionIdentifierType, DialogOptionValueType], None]=CommonFunctionUtils.noop, + always_visible: bool=False + ): + super().__init__(option_identifier, value, context, on_chosen=on_chosen, always_visible=always_visible) + + # noinspection PyMissingOrEmptyDocstring + @property + def icon(self) -> Any: + if super().icon is not None: + return super().icon + return CommonIconUtils.load_arrow_right_icon() diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_toggle_option.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_toggle_option.py new file mode 100644 index 0000000..77b402d --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_toggle_option.py @@ -0,0 +1,78 @@ +""" +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 +""" +from typing import Any, Callable, Union + +from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from sims4communitylib.utils.common_icon_utils import CommonIconUtils +from sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_object_option import \ + CommonDialogObjectOption, DialogOptionIdentifierType + + +class CommonDialogToggleOption(CommonDialogObjectOption): + """CommonDialogObjectOption(option_identifier, value, context, on_chosen=CommonFunctionUtils.noop, always_visible=False) + + An option with two states, on or off. + + :param option_identifier: A string that identifies the option from other options. + :type option_identifier: DialogOptionIdentifierType + :param value: The value of the option. + :type value: bool + :param context: A context to customize the dialog option. + :type context: CommonDialogOptionContext + :param on_chosen: A callback invoked when the dialog option is chosen. The values are as follows: (option_identifier, not value) + :type on_chosen: Callable[[DialogOptionIdentifierType, bool], None], optional + :param always_visible: If set to True, the option will always appear in the dialog no matter which page.\ + If False, the option will act as normal. Default is False. + :type always_visible: bool, optional + """ + def __init__( + self, + option_identifier: DialogOptionIdentifierType, + value: Union[bool, CommonExecutionResult], + context: CommonDialogOptionContext, + on_chosen: Callable[[DialogOptionIdentifierType, bool], None]=CommonFunctionUtils.noop, + always_visible: bool=False + ): + if isinstance(value, CommonExecutionResult): + value = bool(value.result) + super().__init__(option_identifier, value, context, on_chosen=on_chosen, always_visible=always_visible) + + # noinspection PyMissingOrEmptyDocstring + @property + def icon(self) -> Any: + if super().icon is not None: + return super().icon + if self.value: + return CommonIconUtils.load_checked_square_icon() + return CommonIconUtils.load_unchecked_square_icon() + + @property + def value(self) -> bool: + """The value of the option. + + :return: The value of the option. + :rtype: bool + """ + return self._value + + @property + def on_chosen(self) -> Callable[[bool], Any]: + """The action to perform upon choosing this option. + + :return: The action to perform upon choosing this option. + :rtype: Callable[[bool], Any] + """ + return super().on_chosen + + # noinspection PyMissingOrEmptyDocstring + def choose(self) -> None: + if self.on_chosen is None: + return None + return self.on_chosen(not bool(self.value)) diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/response/__init__.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/response/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/response/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/response/common_dialog_button_option.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/response/common_dialog_button_option.py new file mode 100644 index 0000000..738d044 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/response/common_dialog_button_option.py @@ -0,0 +1,77 @@ +""" +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 +""" +from typing import Any, Callable, TypeVar + +from sims4communitylib.dialogs.common_ui_dialog_response import CommonUiDialogResponse +from sims4communitylib.dialogs.option_dialogs.options.response.common_dialog_response_option import \ + CommonDialogResponseOption +from sims4communitylib.dialogs.option_dialogs.options.response.common_dialog_response_option_context import \ + DialogResponseOptionValueType, CommonDialogResponseOptionContext +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils + +DialogResponseOptionIdentifierType = TypeVar('DialogResponseOptionIdentifierType') + + +class CommonDialogButtonOption(CommonDialogResponseOption): + """CommonDialogButtonOption(option_identifier, value, context, on_chosen=CommonFunctionUtils.noop) + + An option the player can choose within a dialog. + + :param option_identifier: A string that identifies the option from other options. + :type option_identifier: DialogOptionIdentifierType + :param value: The value of the option. + :type value: DialogResponseOptionValueType + :param context: A context to customize the dialog option. + :type context: CommonDialogOptionContext + :param on_chosen: A callback invoked when the dialog option is chosen. The values are as follows: (option_identifier, value) + :type on_chosen: Callable[[DialogOptionIdentifierType, DialogResponseOptionValueType], None], optional + """ + def __init__( + self, + option_identifier: DialogResponseOptionIdentifierType, + value: DialogResponseOptionValueType, + context: CommonDialogResponseOptionContext, + on_chosen: Callable[[DialogResponseOptionIdentifierType, DialogResponseOptionValueType], None]=CommonFunctionUtils.noop + ): + if option_identifier is None: + raise AttributeError('Missing required argument \'option_identifier\'') + + self._option_identifier = option_identifier + + def _on_chosen(val: DialogResponseOptionValueType) -> Any: + return on_chosen(self.option_identifier, val) + + super().__init__(value, context, on_chosen=_on_chosen) + + @property + def option_identifier(self) -> DialogResponseOptionIdentifierType: + """Used to identify the option.""" + return self._option_identifier + + @property + def value(self) -> DialogResponseOptionValueType: + """The value of the option.""" + return self._value + + def as_response(self, option_id: int) -> CommonUiDialogResponse: + """as_response(option_id) + + Convert the option into a response. + + :param option_id: The index of the option. + :type option_id: int + :return: The option as a Response + :rtype: CommonUiDialogResponse + """ + return CommonUiDialogResponse( + option_id, + self, + text=self.context.text, + subtext=self.context.subtext, + disabled_text=self.context.disabled_text + ) diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/response/common_dialog_response_option.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/response/common_dialog_response_option.py new file mode 100644 index 0000000..1efc5df --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/response/common_dialog_response_option.py @@ -0,0 +1,94 @@ +""" +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 +""" +from typing import Any, Callable, Union + +from protocolbuffers.Localization_pb2 import LocalizedString +from sims4communitylib.dialogs.common_ui_dialog_response import CommonUiDialogResponse +from sims4communitylib.dialogs.option_dialogs.options.response.common_dialog_response_option_context import \ + DialogResponseOptionValueType, CommonDialogResponseOptionContext +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils + + +class CommonDialogResponseOption: + """CommonDialogResponseOption(value, context, on_chosen=CommonFunctionUtils.noop) + + An option the player can choose within a dialog. + + :param value: The value of the option. + :type value: DialogOptionValueType + :param context: A context to customize the dialog option. + :type context: CommonDialogResponseOptionContext + :param on_chosen: A callback invoked when the dialog option is chosen. + :type on_chosen: Callable[[DialogOptionValueType], Any], optional + """ + def __init__( + self, + value: DialogResponseOptionValueType, + context: CommonDialogResponseOptionContext, + on_chosen: Callable[[DialogResponseOptionValueType], Any]=CommonFunctionUtils.noop + ): + if context is None: + raise AttributeError('Missing required argument \'context\'') + + self._value = value + self._option_context = context + self._on_chosen = on_chosen + + @property + def text(self) -> LocalizedString: + """The text of the dialog option.""" + return self.context.text + + @property + def subtext(self) -> Union[LocalizedString, None]: + """The subtext that displays under the option.""" + return self.context.subtext + + @property + def disabled_text(self) -> Union[LocalizedString, None]: + """The text that displays on the option as a tooltip. If provided, the option will also be disabled.""" + return self.context.disabled_text + + @property + def context(self) -> CommonDialogResponseOptionContext: + """The context of the option.""" + return self._option_context + + @property + def value(self) -> DialogResponseOptionValueType: + """The value of the option.""" + return self._value + + @property + def on_chosen(self) -> Callable[[DialogResponseOptionValueType], Any]: + """The action to perform upon choosing this option.""" + return self._on_chosen + + def choose(self) -> Any: + """choose() + + Choose the option. + + :return: The result of choosing the option. + :rtype: Any + """ + if self.on_chosen is None: + return None + return self.on_chosen(self.value) + + def as_response(self, option_id: int) -> CommonUiDialogResponse: + """as_response(option_id) + + Convert the option into a response. + + :param option_id: The index of the option. + :type option_id: int + :return: The option as a Response + :rtype: CommonUiDialogResponse + """ + raise NotImplementedError('\'{}\' not implemented.'.format(self.__class__.as_response.__name__)) diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/response/common_dialog_response_option_context.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/response/common_dialog_response_option_context.py new file mode 100644 index 0000000..b7f5783 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/response/common_dialog_response_option_context.py @@ -0,0 +1,67 @@ +""" +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 +""" +from typing import Union, Any, TypeVar, Iterator +from protocolbuffers.Localization_pb2 import LocalizedString +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils + +DialogResponseOptionValueType = TypeVar('DialogResponseOptionValueType') + + +class CommonDialogResponseOptionContext: + """CommonDialogResponseOptionContext(\ + text_identifier,\ + text_tokens=(),\ + subtext_identifier=None,\ + subtext_tokens=(),\ + disabled_text_identifier=None,\ + disabled_text_tokens=(),\ + ) + + A context used by :class:`.CommonDialogResponseOption` that provides customization of options. + + :param text_identifier: The text of the option. + :type text_identifier: Union[int, str, LocalizedString, CommonStringId] + :param text_tokens: An iterator of Tokens that will be formatted into the text. + :type text_tokens: Iterator[Any], optional + :param subtext_identifier: The subtext of the option. Default is None. + :type subtext_identifier: Union[int, str, LocalizedString, CommonStringId], optional + :param subtext_tokens: An iterator of Tokens that will be formatted into the description. + :type subtext_tokens: Iterator[Any], optional + :param disabled_text_identifier: The text that displays on the option as a tooltip. Setting this value will also disable the option. Default is None. + :type disabled_text_identifier: Union[int, str, LocalizedString, CommonStringId], optional + :param disabled_text_tokens: An iterator of Tokens that will be formatted into the description. + :type disabled_text_tokens: Iterator[Any], optional + """ + def __init__( + self, + text_identifier: Union[int, str, LocalizedString, CommonStringId], + text_tokens: Iterator[Any]=(), + subtext_identifier: Union[int, str, LocalizedString, CommonStringId]=None, + subtext_tokens: Iterator[Any]=(), + disabled_text_identifier: Union[int, str, LocalizedString, CommonStringId]=None, + disabled_text_tokens: Iterator[Any]=() + ): + self._text = CommonLocalizationUtils.create_localized_string(text_identifier, tokens=tuple(text_tokens)) + self._subtext = CommonLocalizationUtils.create_localized_string(subtext_identifier, tokens=tuple(subtext_tokens)) if subtext_identifier is not None else None + self._disabled_text = CommonLocalizationUtils.create_localized_string(disabled_text_identifier, tokens=tuple(disabled_text_tokens)) if disabled_text_identifier is not None else None + + @property + def text(self) -> LocalizedString: + """The text of the dialog option.""" + return self._text + + @property + def subtext(self) -> Union[LocalizedString, None]: + """The subtext that displays under the option.""" + return self._subtext + + @property + def disabled_text(self) -> Union[LocalizedString, None]: + """The text that displays on the option as a tooltip. If provided, the option will also be disabled.""" + return self._disabled_text diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/sims/__init__.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/sims/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/sims/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/sims/common_dialog_sim_option.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/sims/common_dialog_sim_option.py new file mode 100644 index 0000000..ef0674e --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/sims/common_dialog_sim_option.py @@ -0,0 +1,71 @@ +""" +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 +""" +from typing import Any, Callable +from sims.sim_info import SimInfo +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from ui.ui_dialog_picker import SimPickerRow +from sims4communitylib.dialogs.option_dialogs.options.common_dialog_option import CommonDialogOption +from sims4communitylib.dialogs.option_dialogs.options.sims.common_dialog_sim_option_context import CommonDialogSimOptionContext + + +class CommonDialogSimOption(CommonDialogOption): + """CommonDialogSimOption(sim_info, context, on_chosen=CommonFunctionUtils.noop) + + An option the player can choose within a dialog. + + :param sim_info: The Sim that will be chosen when the option is chosen. + :type sim_info: SimInfo + :param context: A context to customize the dialog option. + :type context: CommonDialogOptionContext + :param on_chosen: A callback invoked when the dialog option is chosen. args: (sim_info) + :type on_chosen: Callable[[SimInfo], Any], optional + """ + + def __init__( + self, + sim_info: SimInfo, + context: CommonDialogSimOptionContext, + on_chosen: Callable[[SimInfo], Any]=CommonFunctionUtils.noop + ): + super().__init__( + sim_info, + context, + on_chosen=on_chosen + ) + + # noinspection PyMissingOrEmptyDocstring + @property + def value(self) -> SimInfo: + return self._value + + @property + def sim_id(self) -> int: + """The id of the Sim in this option. + + :return: The id of the Sim within the option. + :rtype: int + """ + return CommonSimUtils.get_sim_id(self.value) + + def as_row(self, option_id: int) -> SimPickerRow: + """as_row(option_id) + + Convert the option into a picker row. + + :param option_id: The index of the option. + :type option_id: int + :return: The option as a Picker Row + :rtype: SimPickerRow + """ + return SimPickerRow( + self.sim_id, + select_default=self.context.is_selected, + is_enable=self.context.is_enabled, + tag=self + ) diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/sims/common_dialog_sim_option_context.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/sims/common_dialog_sim_option_context.py new file mode 100644 index 0000000..0ff3351 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/sims/common_dialog_sim_option_context.py @@ -0,0 +1,31 @@ +""" +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 +""" +from sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext + + +class CommonDialogSimOptionContext(CommonDialogOptionContext): + """CommonDialogSimOptionContext(is_enabled=True, is_selected=False) + + A context used by CommonDialogSimOption that contains customization of the option. + + :param is_enabled: If True, the Sim will be selectable in the dialog. If False, the Sim will be disabled in the dialog. + :type is_enabled: bool, optional + :param is_selected: If True, the Sim will already be selected in the dialog. If False, the Sim will not be selected in the dialog. + :type is_selected: bool, optional + """ + def __init__( + self, + is_enabled: bool=True, + is_selected: bool=False + ): + super().__init__( + 0, + 0, + is_enabled=is_enabled, + is_selected=is_selected + ) diff --git a/Scripts/s4ap/sims4communitylib/dialogs/premade_dialogs/__init__.py b/Scripts/s4ap/sims4communitylib/dialogs/premade_dialogs/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/premade_dialogs/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/dialogs/premade_dialogs/common_choose_sim_demographic_types_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/premade_dialogs/common_choose_sim_demographic_types_dialog.py new file mode 100644 index 0000000..33d8e5a --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/premade_dialogs/common_choose_sim_demographic_types_dialog.py @@ -0,0 +1,251 @@ +""" +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 +""" +from typing import Callable, Tuple, Union, Iterator + +from protocolbuffers.Localization_pb2 import LocalizedString +from sims4communitylib.dialogs.option_dialogs.common_choose_objects_option_dialog import CommonChooseObjectsOptionDialog +from sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext +from sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_action_option import \ + CommonDialogActionOption +from sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_select_option import \ + CommonDialogSelectOption +from sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.logging._has_s4cl_log import _HasS4CLLog +from sims4communitylib.utils.common_collection_utils import CommonCollectionUtils +from sims4communitylib.utils.common_icon_utils import CommonIconUtils +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor + + +class CommonChooseSimDemographicTypesDialog(_HasS4CLLog): + """CommonChooseSimDemographicTypesDialog(\ + on_close,\ + available_values=None,\ + exclude_values=None\ + ) + + Open a dialog that prompts the player to choose from Sim Demographic Types. + + :param on_close: A callback invoked upon the dialog closing. + :type on_close: Callable[[], None] + :param available_values: The available values shown in the dialog. Default is all Values. + :type available_values: Iterator[CommonSimDemographicType], optional + :param exclude_values: The demographics to not display in the dialog. Default is all Values will be available. + :type exclude_values: Iterator[CommonSimDemographicType], optional + """ + def __init__( + self, + on_close: Callable[[], None], + available_values: Iterator[CommonSimDemographicType] = None, + exclude_values: Iterator[CommonSimDemographicType] = None + ): + super().__init__() + self._on_close = on_close + self._exclude_values = tuple(exclude_values) if exclude_values else None + self._available_values = tuple(available_values or CommonSimDemographicType.get_all(exclude_values=self._exclude_values)) + + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + return 'common_choose_sim_demographic_types_dialog' + + def open( + self, + title: Union[int, CommonStringId, LocalizedString], + description: Union[int, CommonStringId, LocalizedString], + current_selections: Tuple[CommonSimDemographicType], + on_submit: Callable[[Tuple[CommonSimDemographicType]], None], + include_all_choice: bool = True, + include_none_choice: bool = True, + reopen_on_submit: bool = True + ) -> None: + """open(\ + title,\ + description,\ + current_selections,\ + on_submit,\ + include_all_choice=True,\ + include_none_choice=True,\ + reopen_on_submit=True\ + ) + + Open the dialog. + + :param title: The title to show at the top of the dialog. + :type title: Union[int, CommonStringId, LocalizedString] + :param description: The description to show at the top of the dialog. + :type description: Union[int, CommonStringId, LocalizedString] + :param current_selections: The currently selected options in the dialog. + :type current_selections: Tuple[CommonSimDemographicType] + :param on_submit: A callback invoked upon submitting the dialog. + :type on_submit: Callable[[Tuple[CommonSimDemographicType]], None] + :param include_all_choice: If True, the "All Sims" choice will be shown to players. If False, the "All Sims" choice will not be shown. Default is True. + :type include_all_choice: bool, optional + :param include_none_choice: If True, the "No Sims" choice will be shown to players. If False, the "No Sims" choice will not be shown. Default is True. + :type include_none_choice: bool, optional + :param reopen_on_submit: If True, the dialog will reopen on submit. If False, the dialog will not reopen on submit. Default is True. + :type reopen_on_submit: bool, optional + """ + def _on_close() -> None: + if self._on_close is not None: + self._on_close() + + def _reopen(_current_selections: Tuple[CommonSimDemographicType] = None) -> None: + if _current_selections is None: + _current_selections = current_selections + self.open( + title, + description, + _current_selections, + on_submit, + include_all_choice=include_all_choice, + include_none_choice=include_none_choice, + reopen_on_submit=reopen_on_submit + ) + + self.log.format_with_message('Choosing Sim demographic types.', current_selections=current_selections) + + if not current_selections: + current_val_localized_string = CommonStringId.S4CL_NO_SIMS + else: + current_val_localized_string = None + for current_value in current_selections: + _display_name = CommonSimDemographicType.to_display_name(current_value) + if current_val_localized_string is None: + current_val_localized_string = _display_name + continue + current_val_localized_string = CommonLocalizationUtils.create_localized_string(CommonStringId.STRING_COMMA_SPACE_STRING, tokens=( + current_val_localized_string, + _display_name + )) + + option_dialog = CommonChooseObjectsOptionDialog( + title, + description, + title_tokens=( + CommonLocalizationUtils.colorize(current_val_localized_string, text_color=CommonLocalizedStringColor.GREEN), + ), + on_close=_on_close, + mod_identity=self.mod_identity, + per_page=500 + ) + + def _on_submit(_types: Tuple[CommonSimDemographicType]): + if _types is None: + _on_close() + return + if CommonStringId.S4CL_ALL_SIMS.name in _types: + on_submit(self._available_values) + if reopen_on_submit: + _reopen(_current_selections=self._available_values) + return + if CommonStringId.S4CL_NO_SIMS.name in _types: + on_submit(tuple()) + if reopen_on_submit: + _reopen(_current_selections=tuple()) + return + on_submit(_types) + if reopen_on_submit: + _reopen(_current_selections=_types) + + if include_all_choice: + option_dialog.add_option( + CommonDialogSelectOption( + 'ChooseAllSims', + CommonStringId.S4CL_ALL_SIMS.name, + CommonDialogOptionContext( + CommonStringId.S4CL_ALL_SIMS, + CommonStringId.S4CL_ALL_OPTIONS_WILL_BE_INCLUDED, + icon=CommonIconUtils.load_arrow_right_icon() + ) + ) + ) + + if include_none_choice: + option_dialog.add_option( + CommonDialogSelectOption( + 'ChooseNoSims', + CommonStringId.S4CL_NO_SIMS.name, + CommonDialogOptionContext( + CommonStringId.S4CL_NO_SIMS, + CommonStringId.S4CL_NO_OPTIONS_WILL_BE_INCLUDED, + icon=CommonIconUtils.load_arrow_right_icon() + ) + ) + ) + + for setting_type in self._available_values: + display_name = CommonLocalizationUtils.create_localized_string(CommonSimDemographicType.to_display_name(setting_type)) + icon = CommonIconUtils.load_unchecked_square_icon() + is_selected = setting_type in current_selections + if is_selected: + icon = CommonIconUtils.load_checked_square_icon() + option_dialog.add_option( + CommonDialogSelectOption( + setting_type.name, + setting_type, + CommonDialogOptionContext( + display_name, + CommonSimDemographicType.to_display_description(setting_type), + icon=icon, + is_selected=is_selected + ) + ) + ) + + if not option_dialog.has_options(): + _on_close() + return + + option_dialog.show( + min_selectable=0, + max_selectable=option_dialog.option_count, + allow_no_selection=True, + on_submit=_on_submit + ) + + def create_dialog_option( + self, + option_id: str, + title: Union[int, CommonStringId, LocalizedString], + description: Union[int, CommonStringId, LocalizedString], + current_values: Tuple[CommonSimDemographicType], + on_chosen: Callable[[str, Tuple[CommonSimDemographicType]], None] + ): + """Create a dialog option.""" + def _open_choose_sim_demographics_dialog() -> None: + self.open(title, description, current_values, lambda val: on_chosen(option_id, val)) + + if not current_values: + current_val_localized_string = CommonStringId.S4CL_NO_SIMS + else: + if CommonCollectionUtils.lists_are_equal(sorted(current_values), sorted(self._available_values)): + current_val_localized_string = CommonStringId.S4CL_ALL_SIMS + else: + current_val_localized_string = None + for current_value in current_values: + display_name = CommonSimDemographicType.to_display_name(current_value) + if current_val_localized_string is None: + current_val_localized_string = display_name + continue + current_val_localized_string = CommonLocalizationUtils.create_localized_string(CommonStringId.STRING_COMMA_SPACE_STRING, tokens=( + current_val_localized_string, + display_name + )) + + return CommonDialogActionOption( + CommonDialogOptionContext( + title, + description, + title_tokens=( + CommonLocalizationUtils.colorize(CommonLocalizationUtils.create_localized_string(current_val_localized_string), text_color=CommonLocalizedStringColor.GREEN), + ) + ), + on_chosen=_open_choose_sim_demographics_dialog + ) diff --git a/Scripts/s4ap/sims4communitylib/dialogs/premade_dialogs/common_premade_choose_sim_option_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/premade_dialogs/common_premade_choose_sim_option_dialog.py new file mode 100644 index 0000000..d182c6a --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/premade_dialogs/common_premade_choose_sim_option_dialog.py @@ -0,0 +1,187 @@ +""" +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 +""" +from typing import Union, Any, Iterator, Callable +from protocolbuffers.Localization_pb2 import LocalizedString +from sims.sim_info import SimInfo +from sims4communitylib.dialogs.option_dialogs.common_choose_sim_option_dialog import CommonChooseSimOptionDialog +from sims4communitylib.dialogs.option_dialogs.options.sims.common_dialog_sim_option import CommonDialogSimOption +from sims4communitylib.dialogs.option_dialogs.options.sims.common_dialog_sim_option_context import \ + CommonDialogSimOptionContext +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils +from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + + +class CommonPremadeChooseSimOptionDialog(CommonChooseSimOptionDialog): + """CommonPremadeChooseSimOptionDialog(\ + title_identifier,\ + description_identifier,\ + title_tokens=(),\ + description_tokens=(),\ + on_close=CommonFunctionUtils.noop,\ + mod_identity=None,\ + include_sim_callback=None,\ + instanced_sims_only=True,\ + on_sim_chosen=CommonFunctionUtils.noop\ + ) + + A premade dialog that will display a list of Sims based on a filter and will prompt the player to choose a single Sim. + + .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_premade_choose_sim_option_dialog` in the in-game console. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + def _on_chosen(_sim_info: SimInfo): + 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 + ), + ) + + # Create the dialog that will only show adult Sims in the current area. + option_dialog = CommonPremadeChooseSimOptionDialog( + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + title_tokens=title_tokens, + description_tokens=description_tokens, + mod_identity=ModInfo.get_identity(), + include_sim_callback=CommonAgeUtils.is_adult, + instanced_sims_only=True, + on_sim_chosen=_on_chosen + ) + + option_dialog.show( + sim_info=CommonSimUtils.get_active_sim_info(), + column_count=4 + ) + + :param title_identifier: A decimal identifier of the title text. + :type title_identifier: Union[int, str, LocalizedString, CommonStringId] + :param description_identifier: A decimal identifier of the description text. + :type description_identifier: Union[int, str, LocalizedString, CommonStringId] + :param title_tokens: An iterator of Tokens to format into the title. + :type title_tokens: Iterator[Any], optional + :param description_tokens: An iterator of Tokens to format into the description. + :type description_tokens: Iterator[Any], optional + :param on_close: A callback invoked upon the dialog closing. + :type on_close: Callable[[], None], optional + :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. + :type mod_identity: CommonModIdentity, optional + :param include_sim_callback: If the result of this callback is True, the sim will be included in the results. If set to None, All sims will be included. + :type include_sim_callback: Callable[[SimInfo], bool], optional + :param instanced_sims_only: If True, only Sims that are currently spawned will be shown. If False, all Sims will be shown. Default is True. + :type instanced_sims_only: bool, optional + :param on_sim_chosen: Called upon a Sim being chosen. Default is :func:`~CommonFunctionUtils.noop`. + :type on_sim_chosen: Callable[[SimInfo], Any], optional + """ + def __init__( + self, + title_identifier: Union[int, str, LocalizedString, CommonStringId], + description_identifier: Union[int, str, LocalizedString, CommonStringId], + title_tokens: Iterator[Any]=(), + description_tokens: Iterator[Any]=(), + on_close: Callable[[], None]=CommonFunctionUtils.noop, + mod_identity: CommonModIdentity=None, + include_sim_callback: Callable[[SimInfo], bool]=None, + instanced_sims_only: bool=True, + on_sim_chosen: Callable[[SimInfo], Any]=CommonFunctionUtils.noop + ): + super().__init__( + title_identifier, + description_identifier, + title_tokens=title_tokens, + description_tokens=description_tokens, + on_close=on_close, + mod_identity=mod_identity + ) + + if instanced_sims_only: + _sim_info_list = CommonSimUtils.get_instanced_sim_info_for_all_sims_generator(include_sim_callback=include_sim_callback) + else: + _sim_info_list = CommonSimUtils.get_sim_info_for_all_sims_generator(include_sim_callback=include_sim_callback) + + for _sim_info in _sim_info_list: + self.add_option( + CommonDialogSimOption( + _sim_info, + CommonDialogSimOptionContext(), + on_chosen=on_sim_chosen + ) + ) + + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + return 's4cl_premade_choose_sim_option_dialog' + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_testing.show_premade_choose_sim_option_dialog', + 'Show an example of CommonPremadeChooseSimOptionDialog.' +) +def _common_testing_show_premade_choose_sim_option_dialog(output: CommonConsoleCommandOutput): + output('Showing test premade choose sim option dialog.') + + def _on_chosen(_sim_info: SimInfo): + output('Chose Sim with name \'{}\''.format(CommonSimNameUtils.get_full_name(_sim_info))) + + # 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 + ), + ) + + # Create the dialog that will only show adult Sims in the current area. + option_dialog = CommonPremadeChooseSimOptionDialog( + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + title_tokens=title_tokens, + description_tokens=description_tokens, + mod_identity=ModInfo.get_identity(), + include_sim_callback=CommonAgeUtils.is_adult, + instanced_sims_only=True, + on_sim_chosen=_on_chosen + ) + + option_dialog.show( + sim_info=CommonSimUtils.get_active_sim_info(), + column_count=4 + ) + output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/premade_dialogs/common_premade_choose_sims_option_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/premade_dialogs/common_premade_choose_sims_option_dialog.py new file mode 100644 index 0000000..bbe6b1d --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/premade_dialogs/common_premade_choose_sims_option_dialog.py @@ -0,0 +1,186 @@ +""" +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 +""" +from pprint import pformat + +from typing import Union, Any, Iterator, Callable, Tuple +from protocolbuffers.Localization_pb2 import LocalizedString +from sims.sim_info import SimInfo +from sims4communitylib.dialogs.option_dialogs.common_choose_sims_option_dialog import CommonChooseSimsOptionDialog +from sims4communitylib.dialogs.option_dialogs.options.sims.common_dialog_sim_option import CommonDialogSimOption +from sims4communitylib.dialogs.option_dialogs.options.sims.common_dialog_sim_option_context import \ + CommonDialogSimOptionContext +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils +from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + + +class CommonPremadeChooseSimsOptionDialog(CommonChooseSimsOptionDialog): + """CommonPremadeChooseSimsOptionDialog(\ + title_identifier,\ + description_identifier,\ + title_tokens=(),\ + description_tokens=(),\ + on_close=CommonFunctionUtils.noop,\ + mod_identity=None,\ + include_sim_callback=None,\ + instanced_sims_only=True\ + ) + + A premade dialog that will display a list of Sims based on a filter and will prompt the player to choose one or more Sims. + + .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_premade_choose_sims_option_dialog` in the in-game console. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + def _on_submit(_chosen_sim_info_list: Tuple[SimInfo]): + 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 + ), + ) + + # Create the dialog that will only show adult (include_sim_callback=CommonAgeUtils.is_adult) Sims in the current area (instanced_sims_only=True). + option_dialog = CommonPremadeChooseSimsOptionDialog( + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + title_tokens=title_tokens, + description_tokens=description_tokens, + mod_identity=ModInfo.get_identity(), + include_sim_callback=CommonAgeUtils.is_adult, + instanced_sims_only=True + ) + + option_dialog.show( + sim_info=CommonSimUtils.get_active_sim_info(), + column_count=4, + max_selectable=5, + on_submit=_on_submit + ) + + :param title_identifier: A decimal identifier of the title text. + :type title_identifier: Union[int, str, LocalizedString, CommonStringId] + :param description_identifier: A decimal identifier of the description text. + :type description_identifier: Union[int, str, LocalizedString, CommonStringId] + :param title_tokens: An iterator of Tokens to format into the title. + :type title_tokens: Iterator[Any], optional + :param description_tokens: An iterator of Tokens to format into the description. + :type description_tokens: Iterator[Any], optional + :param on_close: A callback invoked upon the dialog closing. + :type on_close: Callable[[], None], optional + :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. + :type mod_identity: CommonModIdentity, optional + :param include_sim_callback: If the result of this callback is True, the sim will be included in the results. If set to None, All sims will be included. + :type include_sim_callback: Callable[[SimInfo], bool], optional + :param instanced_sims_only: If True, only Sims that are currently spawned will be shown. If False, all Sims will be shown. Default is True. + :type instanced_sims_only: bool, optional + """ + def __init__( + self, + title_identifier: Union[int, str, LocalizedString, CommonStringId], + description_identifier: Union[int, str, LocalizedString, CommonStringId], + title_tokens: Iterator[Any]=(), + description_tokens: Iterator[Any]=(), + on_close: Callable[[], None]=CommonFunctionUtils.noop, + mod_identity: CommonModIdentity=None, + include_sim_callback: Callable[[SimInfo], bool]=None, + instanced_sims_only: bool=True + ): + super().__init__( + title_identifier, + description_identifier, + title_tokens=title_tokens, + description_tokens=description_tokens, + on_close=on_close, + mod_identity=mod_identity + ) + + if instanced_sims_only: + sim_info_list = CommonSimUtils.get_instanced_sim_info_for_all_sims_generator(include_sim_callback=include_sim_callback) + else: + sim_info_list = CommonSimUtils.get_sim_info_for_all_sims_generator(include_sim_callback=include_sim_callback) + + for sim_info in sim_info_list: + self.add_option( + CommonDialogSimOption( + sim_info, + CommonDialogSimOptionContext() + ) + ) + + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + return 's4cl_premade_choose_sims_option_dialog' + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_testing.show_premade_choose_sims_option_dialog', + 'Show an example of CommonPremadeChooseSimsOptionDialog.' +) +def _common_testing_show_premade_choose_sims_option_dialog(output: CommonConsoleCommandOutput): + output('Showing test premade choose Sims option dialog.') + + def _on_submit(_chosen_sim_info_list: Tuple[SimInfo]): + output('Chose Sims with names \'{}\''.format(pformat(CommonSimNameUtils.get_full_names(_chosen_sim_info_list)))) + + # 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 + ), + ) + + # Create the dialog that will only show adult (include_sim_callback=CommonAgeUtils.is_adult) Sims in the current area (instanced_sims_only=True). + option_dialog = CommonPremadeChooseSimsOptionDialog( + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + title_tokens=title_tokens, + description_tokens=description_tokens, + mod_identity=ModInfo.get_identity(), + include_sim_callback=CommonAgeUtils.is_adult, + instanced_sims_only=True + ) + + option_dialog.show( + sim_info=CommonSimUtils.get_active_sim_info(), + column_count=4, + max_selectable=5, + on_submit=_on_submit + ) + output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/utils/__init__.py b/Scripts/s4ap/sims4communitylib/dialogs/utils/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/utils/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/dialogs/utils/common_dialog_utils.py b/Scripts/s4ap/sims4communitylib/dialogs/utils/common_dialog_utils.py new file mode 100644 index 0000000..c19e7f5 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dialogs/utils/common_dialog_utils.py @@ -0,0 +1,58 @@ +""" +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 +""" +from typing import Any, Union, Tuple + +from ui.ui_dialog_generic import UiDialogTextInput +from ui.ui_dialog_multi_picker import UiMultiPicker +from ui.ui_dialog_picker import UiDialogObjectPicker + + +class CommonDialogUtils: + """Utilities for use with dialogs. + + """ + TEXT_INPUT_NAME = 'text_input' + + @staticmethod + def get_chosen_item(dialog: Union[UiDialogObjectPicker, UiMultiPicker]) -> Any: + """get_chosen_item(dialog) + + Retrieves the item chosen by the player from a dialog. + + :param dialog: The dialog to get the chosen item of. + :type dialog: Union[UiDialogObjectPicker, UiMultiPicker] + :return: The value of the chosen item. + :rtype: Any + """ + return dialog.get_result_tags()[-1] or dialog.get_result_tags()[0] + + @staticmethod + def get_chosen_items(dialog: Union[UiDialogObjectPicker, UiMultiPicker]) -> Tuple[Any]: + """get_chosen_items(dialog) + + Retrieves the items chosen by the player from a dialog. + + :param dialog: The dialog to get the chosen items of. + :type dialog: Union[UiDialogObjectPicker, UiMultiPicker] + :return: A collection of chosen items. + :rtype: Tuple[Any] + """ + return dialog.get_result_tags() + + @staticmethod + def get_input_value(dialog: UiDialogTextInput) -> Union[str, None]: + """get_input_value(dialog) + + Retrieve the value entered by the player from an input dialog. + + :param dialog: The dialog to get the chosen items of. + :type dialog: UiDialogTextInput + :return: The value of the entered input. + :rtype: Union[str, None] + """ + return str(dialog.text_input_responses.get(CommonDialogUtils.TEXT_INPUT_NAME)) diff --git a/Scripts/s4ap/sims4communitylib/dtos/__init__.py b/Scripts/s4ap/sims4communitylib/dtos/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dtos/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/dtos/common_cas_part.py b/Scripts/s4ap/sims4communitylib/dtos/common_cas_part.py new file mode 100644 index 0000000..39e2514 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dtos/common_cas_part.py @@ -0,0 +1,47 @@ +""" +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 +""" +from typing import Union + +from sims.outfits.outfit_enums import BodyType +from sims4communitylib.enums.common_body_slot import CommonBodySlot + + +class CommonCASPart: + """CommonCASPart(\ + cas_part_id,\ + body_type=None,\ + ) + + A class that contains information about a CAS Part. + + :param cas_part_id: The decimal identifier of a CAS Part. + :type cas_part_id: int + :param body_type: The place on a Sims person the CAS Part gets applied to. If not specified, then the Body Type of the CAS Part itself will be used. Default is None. + :type body_type: Union[CommonBodySlot, BodyType, int, None], optional + """ + + def __init__(self, cas_part_id: int, body_type: Union[CommonBodySlot, BodyType, int, None] = None) -> None: + self._cas_part_id = cas_part_id + from sims4communitylib.utils.cas.common_cas_utils import CommonCASUtils + self._body_type = body_type or CommonCASUtils.get_body_type_of_cas_part(cas_part_id) + + @property + def cas_part_id(self) -> int: + """The decimal identifier of a CAS Part.""" + return self._cas_part_id + + @property + def body_type(self) -> Union[CommonBodySlot, BodyType, int]: + """The place on a Sims person the CAS Part gets applied to.""" + return self._body_type + + def __repr__(self) -> str: + return self.__str__() + + def __str__(self) -> str: + return f'' diff --git a/Scripts/s4ap/sims4communitylib/dtos/common_object_containment_slot.py b/Scripts/s4ap/sims4communitylib/dtos/common_object_containment_slot.py new file mode 100644 index 0000000..ad51724 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dtos/common_object_containment_slot.py @@ -0,0 +1,37 @@ +""" +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 +""" +from typing import Tuple + +from objects.slots import SlotType + + +class CommonObjectContainmentSlot: + """CommonObjectContainmentSlot(slot_name_hash, slot_types) + + A slot used for containing other objects within an object. + + .. note:: A place that other objects can be placed at on an object. + + :param slot_name_hash: The hashed name of the slot. + :type slot_name_hash: int + :param slot_types: A collection of slot types within this containment slot. + :type slot_types: Tuple[SlotType] + """ + def __init__(self, slot_name_hash: int, slot_types: Tuple[SlotType]): + self._slot_name_hash = slot_name_hash + self._slot_types = slot_types + + @property + def slot_name_hash(self) -> int: + """The hashed name of the slot.""" + return self._slot_name_hash + + @property + def slot_types(self) -> Tuple[SlotType]: + """The types of slots.""" + return self._slot_types diff --git a/Scripts/s4ap/sims4communitylib/dtos/common_outfit.py b/Scripts/s4ap/sims4communitylib/dtos/common_outfit.py new file mode 100644 index 0000000..4b30b78 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/dtos/common_outfit.py @@ -0,0 +1,274 @@ +""" +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 +""" +from typing import Union, Dict, Any, List, Tuple + +from sims.outfits.outfit_enums import BodyType, OutfitCategory +from sims.sim_info import SimInfo +from sims4communitylib.classes.serialization.common_serializable import CommonSerializable +from sims4communitylib.enums.common_body_slot import CommonBodySlot +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.services.sim.cas.common_sim_outfit_io import CommonSimOutfitIO +from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + + +class CommonOutfit(CommonSerializable): + """CommonOutfit(outfit_parts) + + Contains information on the CAS Parts that make up an outfit. + + :param outfit_parts: A mapping of CAS Parts organized by Body Slot. + :type outfit_parts: Dict[Union[CommonBodySlot, BodyType, int], int] + """ + + def __init__(self, outfit_parts: Dict[Union[CommonBodySlot, BodyType, int], int]): + self._outfit_parts = outfit_parts + + @property + def outfit_parts(self) -> Dict[Union[CommonBodySlot, BodyType, int], int]: + """A library of Body Slots to CAS Part Ids""" + return self._outfit_parts + + def has_body_slot(self, body_slot: Union[CommonBodySlot, BodyType, int]) -> bool: + """has_body_slot(body_slot) + + Determine if the Outfit has a Body Slot. + + :param body_slot: A body slot. + :type body_slot: Union[CommonBodySlot, BodyType, int] + :return: True, if the outfit has the specified body slot. False, if not. + :rtype: bool + """ + return body_slot in self.outfit_parts + + def has_cas_part(self, cas_part: int) -> bool: + """has_cas_part(cas_part) + + Determine if the Outfit has a CAS Part. + + :param cas_part: The decimal identifier of a CAS Part. + :type cas_part: int + :return: True, if the outfit contains the specified CAS Part. False, if not. + :rtype: bool + """ + return any(self.get_all_by_cas_part(cas_part)) + + def set_outfit_part(self, body_slot: Union[CommonBodySlot, BodyType, int], cas_part: int): + """set_outfit_part(body_slot, cas_part) + + Set the CAS Part id at a Body Slot. + + :param body_slot: A body slot. + :type body_slot: Union[CommonBodySlot, BodyType, int] + :param cas_part: The decimal identifier of a CAS Part. + :type cas_part: int + """ + self.outfit_parts[body_slot] = cas_part + + def get_by_body_slot(self, body_slot: Union[CommonBodySlot, BodyType, int]) -> int: + """get_by_body_slot(body_slot) + + Retrieve the CAS Part ID at a Body Slot. + + :param body_slot: A body slot. + :type body_slot: Union[CommonBodySlot, BodyType, int] + :return: The decimal identifier of the CAS Part located at the body slot on the outfit or -1 if the body slot is not found. + :rtype: int + """ + return self.outfit_parts.get(body_slot, -1) + + def get_all_by_cas_part(self, cas_part: int) -> Tuple[Union[CommonBodySlot, BodyType, int]]: + """get_all_by_cas_part(cas_part) + + Retrieve the Body Slots a CAS Part is attached to. + + :param cas_part: The CAS Part to look for. + :type cas_part: Union[CommonBodySlot, BodyType, int] + :return: A collection of body slots the CAS Part is attached to or an empty collection if the CAS Part is not attached to the outfit. + :rtype: Tuple[Union[CommonBodySlot, BodyType, int]] + """ + body_slots: List[Union[CommonBodySlot, BodyType, int]] = list() + for (body_slot, _cas_part) in self.outfit_parts.items(): + if _cas_part == cas_part: + body_slots.append(body_slot) + return tuple(body_slots) + + def remove_by_body_slot(self, body_slot: Union[CommonBodySlot, BodyType, int]): + """remove_by_body_slot(body_slot) + + Remove a CAS Part by a Body Slot. + + :param body_slot: A body slot. + :type body_slot: Union[CommonBodySlot, BodyType, int] + """ + if body_slot not in self.outfit_parts: + return + del self.outfit_parts[body_slot] + + def remove_by_cas_part(self, cas_part: int): + """remove_by_cas_part(cas_part) + + Remove all Body Slots containing a CAS Part. + + :param cas_part: The decimal identifier of a CAS Part. + :type cas_part: int + """ + body_slots = self.get_all_by_cas_part(cas_part) + for body_slot in body_slots: + self.remove_by_body_slot(body_slot) + + def clone(self) -> 'CommonOutfit': + """clone() + + Create a clone of the outfit. + + :return: A clone of the outfit. + :rtype: CommonOutfit + """ + return CommonOutfit(dict(self.outfit_parts)) + + # noinspection PyMissingOrEmptyDocstring + def serialize(self) -> Union[str, Dict[str, Any]]: + data = dict() + if not self.outfit_parts: + return data + outfit_parts_list = list() + for (body_slot, cas_part) in self.outfit_parts.items(): + outfit_parts_list.append((body_slot.name if hasattr(body_slot, 'name') else str(int(body_slot)), cas_part)) + if outfit_parts_list: + data['outfit_parts'] = outfit_parts_list + return data + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def deserialize(cls, data: Union[str, Dict[str, Any]]) -> 'CommonOutfit': + if not data: + return CommonOutfit(dict()) + if isinstance(data, CommonOutfit): + return data + outfit_parts_list: List[Union[CommonBodySlot, BodyType, int], int] = data.get('outfit_parts', None) + outfit_parts = dict() + for (body_slot_str, cas_part) in outfit_parts_list: + if isinstance(body_slot_str, int): + body_slot = CommonResourceUtils.get_enum_by_int_value(int(body_slot_str), CommonBodySlot, default_value=CommonBodySlot.NONE) + if body_slot == CommonBodySlot.NONE: + body_slot = CommonResourceUtils.get_enum_by_int_value(int(body_slot_str), BodyType, default_value=BodyType.NONE) + if body_slot == BodyType.NONE: + body_slot = body_slot_str + else: + body_slot = CommonBodySlot.convert_from_vanilla(body_slot) + elif isinstance(body_slot_str, str) and body_slot_str.isnumeric(): + body_slot = CommonResourceUtils.get_enum_by_int_value(int(body_slot_str), CommonBodySlot, default_value=CommonBodySlot.NONE) + if body_slot == CommonBodySlot.NONE: + body_slot = CommonResourceUtils.get_enum_by_int_value(int(body_slot_str), BodyType, default_value=BodyType.NONE) + if body_slot == BodyType.NONE: + body_slot = body_slot_str + else: + body_slot = CommonBodySlot.convert_from_vanilla(body_slot) + else: + body_slot = CommonResourceUtils.get_enum_by_name(body_slot_str, CommonBodySlot, default_value=CommonBodySlot.NONE) + if body_slot == CommonBodySlot.NONE: + body_slot = CommonResourceUtils.get_enum_by_name(body_slot_str, BodyType, default_value=BodyType.NONE) + if body_slot == BodyType.NONE: + continue + body_slot = CommonBodySlot.convert_from_vanilla(body_slot) + outfit_parts[body_slot] = cas_part + return CommonOutfit(outfit_parts) + + @classmethod + def from_sim(cls, mod_identity: CommonModIdentity, sim_info: SimInfo, outfit_category_and_index: Union[Tuple[OutfitCategory, int], None] = None, include_body_slots: Tuple[Union[CommonBodySlot, BodyType, int]] = None) -> 'CommonOutfit': + """from_sim(mod_identity, sim_info, outfit_category_and_index, include_body_slots=None) + + Create an outfit from the outfit of a Sim. + + :param mod_identity: The identity of the mod making the change. + :type mod_identity: CommonModIdentity + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param outfit_category_and_index: The Category and Index of the outfit to copy from. Default is the current outfit of the Sim. + :type outfit_category_and_index: Union[Tuple[OutfitCategory, int], None], optional + :param include_body_slots: A collection of body slots to include. If set to None, all body slots will be included. Default is None. + :type include_body_slots: Tuple[Union[CommonBodySlot, BodyType, int]], optional + :return: An Outfit created from the Sim. + :rtype: CommonOutfit + """ + if include_body_slots is not None: + include_body_slots = tuple([int(body_type) for body_type in include_body_slots]) + outfit_io = CommonSimOutfitIO(sim_info, outfit_category_and_index=outfit_category_and_index, mod_identity=mod_identity) + return cls.from_outfit_io(outfit_io, include_body_slots=include_body_slots) + + def apply_to_sim(self, mod_identity: CommonModIdentity, sim_info: SimInfo, outfit_category_and_index: Union[Tuple[OutfitCategory, int], None] = None, override_all: bool = False) -> None: + """apply_to_sim(mod_identity, sim_info, outfit_category_and_index=None, override_all=False) + + Apply the outfit parts to the outfit of a Sim. + + :param mod_identity: The identity of the mod making the change. + :type mod_identity: CommonModIdentity + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param outfit_category_and_index: The Category and Index of the outfit to copy to. Default is the current outfit of the Sim. + :type outfit_category_and_index: Union[Tuple[OutfitCategory, int], None], optional + :param override_all: If True, then all outfit parts on the outfit of th Sim will be removed before applying the parts from this outfit. If False, no parts will be removed. Default is True. + :type override_all: bool, optional + """ + outfit_io = CommonSimOutfitIO(sim_info, outfit_category_and_index=outfit_category_and_index, mod_identity=mod_identity) + self.apply_to_outfit_io(outfit_io, override_all=override_all) + outfit_io.apply(apply_to_outfit_category_and_index=outfit_category_and_index) + + @classmethod + def from_outfit_io(cls, outfit_io: CommonSimOutfitIO, include_body_slots: Tuple[Union[CommonBodySlot, BodyType, int]] = None) -> 'CommonOutfit': + """from_outfit_io(outfit_io, include_body_slots=None) + + Create an outfit from an Outfit IO. + + :param outfit_io: An instance of an Outfit IO. + :type outfit_io: CommonSimOutfitIO + :param include_body_slots: A collection of body slots to include. If set to None, all body slots will be included. Default is None. + :type include_body_slots: Tuple[Union[CommonBodySlot, BodyType, int]], optional + :return: An Outfit created from the outfit io. + :rtype: CommonOutfit + """ + if include_body_slots is not None: + include_body_slots = tuple([int(body_slot) for body_slot in include_body_slots]) + outfit_parts: Dict[Union[CommonBodySlot, BodyType, int], int] = dict() + for (body_slot_val, cas_part) in zip(outfit_io.body_types, outfit_io.cas_part_ids): + if include_body_slots is not None and int(body_slot_val) not in include_body_slots: + continue + if isinstance(body_slot_val, int): + body_slot = CommonResourceUtils.get_enum_by_int_value(body_slot_val, CommonBodySlot, default_value=CommonBodySlot.NONE) + if body_slot == CommonBodySlot.NONE: + body_slot = body_slot_val + elif isinstance(body_slot_val, BodyType) or isinstance(body_slot_val, CommonBodySlot): + body_slot = CommonBodySlot.convert_from_vanilla(body_slot_val) + else: + body_slot = CommonResourceUtils.get_enum_by_name(body_slot_val, CommonBodySlot, default_value=CommonBodySlot.NONE) + + outfit_parts[body_slot] = cas_part + return cls(outfit_parts) + + def apply_to_outfit_io(self, outfit_io: CommonSimOutfitIO, override_all: bool = False) -> None: + """apply_to_outfit_io(outfit_io, override_all=False) + + Apply the outfit parts of this outfit to an outfit io. + + :param outfit_io: An instance of an Outfit IO. + :type outfit_io: CommonSimOutfitIO + :param override_all: If True, then all outfit parts on the outfit io will be removed before applying the parts from this outfit. If False, no parts will be removed. Default is True. + :type override_all: bool, optional + """ + if override_all: + for body_slot in tuple(outfit_io.body_types): + outfit_io.detach_body_type(body_slot) + for (body_slot_val, cas_part) in self.outfit_parts.items(): + outfit_io.attach_cas_part(cas_part, body_type=CommonBodySlot.convert_to_vanilla(body_slot_val)) + + def __repr__(self) -> str: + return self.__str__() + + def __str__(self) -> str: + result = ', '.join(['{} ({}): {}'.format(body_slot.name if hasattr(body_slot, 'name') else body_slot, int(body_slot), cas_part) for (body_slot, cas_part) in self.outfit_parts.items()]) + return result diff --git a/Scripts/s4ap/sims4communitylib/enums/__init__.py b/Scripts/s4ap/sims4communitylib/enums/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/enums/affordance_list_ids.py b/Scripts/s4ap/sims4communitylib/enums/affordance_list_ids.py new file mode 100644 index 0000000..36723f6 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/affordance_list_ids.py @@ -0,0 +1,21 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonAffordanceListId(CommonInt): + """Identifiers for affordance lists. + + """ + INVALID: 'CommonAffordanceListId' = 0 + DEBUG_AFFORDANCES = 26870 # debug_affordances + SOCIAL_MIXERS_FRIENDLY_NON_TOUCHING = 24508 # social_Mixers_Friendly_NonTouching + SOCIAL_MIXERS_FRIENDLY_NON_TOUCHING_FOR_REFERENCE = 163702 # social_Mixers_Friendly_NonTouching_ForReference + SOCIAL_MIXERS_ROMANCE_NON_TOUCHING = 24510 # social_Mixers_Romance_NonTouching + SOCIAL_MIXERS_ROMANCE_NON_TOUCHING_FOR_REFERENCE = 163713 # social_Mixers_Romance_NonTouching_ForReference + SOCIAL_MIXERS_MISCHIEF_NON_TOUCHING_FOR_REFERENCE = 163708 # social_Mixers_Mischief_NonTouching_ForReference diff --git a/Scripts/s4ap/sims4communitylib/enums/animation_state_machines_enum.py b/Scripts/s4ap/sims4communitylib/enums/animation_state_machines_enum.py new file mode 100644 index 0000000..2385a8a --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/animation_state_machines_enum.py @@ -0,0 +1,16 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonAnimationStateMachineId(CommonInt): + """Identifiers for vanilla animation state machines (ASM). + + """ + INVALID: 'CommonAnimationStateMachineId' = 0 + STAND_POSTURE: 'CommonAnimationStateMachineId' = 15425961973529743787 diff --git a/Scripts/s4ap/sims4communitylib/enums/buffs_enum.py b/Scripts/s4ap/sims4communitylib/enums/buffs_enum.py new file mode 100644 index 0000000..01a6f3a --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/buffs_enum.py @@ -0,0 +1,14677 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonBuffId(CommonInt): + """Identifiers for vanilla buffs + + """ + # APM = Apartment Problem + # CDG = Core Dating Gameplay + S4CL_EXAMPLE_APPLY_BARE_FEET: 'CommonBuffId' = 16461769487103204847 + + INVALID: 'CommonBuffId' = 0 + ACTING_SKILL_MOOD_ENERGIZED_ACTION: 'CommonBuffId' = 195825 + ACTING_SKILL_MOOD_ENERGIZED_HORROR: 'CommonBuffId' = 195827 + ACTING_SKILL_MOOD_ENERGIZED_SCI_FI: 'CommonBuffId' = 195826 + ACTING_SKILL_MOOD_FLIRTY: 'CommonBuffId' = 195811 + ACTING_SKILL_MOOD_HAPPY: 'CommonBuffId' = 195824 + ACTING_SKILL_MOOD_INSPIRED: 'CommonBuffId' = 195823 + ACTING_SKILL_MOOD_INSPIRED_DRAMATIC_MONOLOGUE: 'CommonBuffId' = 199388 + ACTING_SKILL_MOOD_PLAYFUL: 'CommonBuffId' = 195822 + ACTING_SKILL_PERFORMING_ROUTINE: 'CommonBuffId' = 195118 + ACTING_SKILL_PERFORMING_ROUTINE_FOR_TIPS: 'CommonBuffId' = 195550 + ACTING_SKILL_SKILL_FROM_CAS_REWARD: 'CommonBuffId' = 197822 + ACTING_SKILL_SUCCESSFUL_ROUTINE_ENERGIZED_ACTION: 'CommonBuffId' = 195855 + ACTING_SKILL_SUCCESSFUL_ROUTINE_ENERGIZED_HORROR: 'CommonBuffId' = 195856 + ACTING_SKILL_SUCCESSFUL_ROUTINE_ENERGIZED_SCI_FI: 'CommonBuffId' = 195857 + ACTING_SKILL_SUCCESSFUL_ROUTINE_FLIRTY: 'CommonBuffId' = 195858 + ACTING_SKILL_SUCCESSFUL_ROUTINE_HAPPY: 'CommonBuffId' = 195859 + ACTING_SKILL_SUCCESSFUL_ROUTINE_INSPIRED: 'CommonBuffId' = 195551 + ACTING_SKILL_SUCCESSFUL_ROUTINE_INSPIRED_DRAMATIC_MONOLOGUE: 'CommonBuffId' = 199383 + ACTING_SKILL_SUCCESSFUL_ROUTINE_PLAYFUL: 'CommonBuffId' = 195860 + ACTING_SKILL_THESPIAN_TRAINING: 'CommonBuffId' = 199560 + ACTIVITY_TABLE_HOLIDAY_CRAFT: 'CommonBuffId' = 186344 + ACTIVITY_TABLE_SEASONAL_CRAFT: 'CommonBuffId' = 186345 + ACTOR_CAREER_AGENCY_WELL_SUITED_AMATEUR_FAIL: 'CommonBuffId' = 199369 + ACTOR_CAREER_GOT_INTO_COSTUME: 'CommonBuffId' = 189356 + ACTOR_CAREER_GOT_INTO_HAIR_MAKE_UP: 'CommonBuffId' = 189354 + ACTOR_CAREER_HAIR_COMMERCIAL_HOSPITAL: 'CommonBuffId' = 197526 + ACTOR_CAREER_HAIR_COMMERCIAL_HOUSE_NICE: 'CommonBuffId' = 197516 + ACTOR_CAREER_HAIR_COMMERCIAL_KIDS: 'CommonBuffId' = 197519 + ACTOR_CAREER_HAIR_COMMERCIAL_PIRATE: 'CommonBuffId' = 197514 + ACTOR_CAREER_HAIR_COMMERCIAL_WESTERN: 'CommonBuffId' = 197530 + ACTOR_CAREER_HAIR_FAIL: 'CommonBuffId' = 197855 + ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR1_COMMERCIAL_HOSPITAL: 'CommonBuffId' = 201797 + ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR1_COMMERCIAL_HOUSE_NICE: 'CommonBuffId' = 201798 + ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR1_MOVIE_CITY: 'CommonBuffId' = 201821 + ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR1_MOVIE_MEDIEVAL: 'CommonBuffId' = 201817 + ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR1_MOVIE_PIRATE: 'CommonBuffId' = 201816 + ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR1_MOVIE_SUPERHERO: 'CommonBuffId' = 201820 + ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR1_MOVIE_VICTORIAN: 'CommonBuffId' = 201819 + ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR1_MOVIE_WESTERN: 'CommonBuffId' = 201818 + ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR1_TV_HIGH_APOCALYPSE: 'CommonBuffId' = 201804 + ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR1_TV_HIGH_HOSPITAL: 'CommonBuffId' = 201805 + ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR1_TV_HIGH_POLICE: 'CommonBuffId' = 201808 + ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR1_TV_HIGH_VICTORIAN: 'CommonBuffId' = 201807 + ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR1_TV_HIGH_WESTERN: 'CommonBuffId' = 201806 + ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR1_TV_LOW_HOUSE_LOW: 'CommonBuffId' = 201802 + ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR1_TV_LOW_HOUSE_NICE: 'CommonBuffId' = 201800 + ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR1_TV_LOW_PIRATE: 'CommonBuffId' = 201799 + ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR1_TV_LOW_WESTERN: 'CommonBuffId' = 201801 + ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR2_MOVIE_CITY: 'CommonBuffId' = 201832 + ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR2_MOVIE_MEDIEVAL: 'CommonBuffId' = 201828 + ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR2_MOVIE_PIRATE: 'CommonBuffId' = 201827 + ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR2_MOVIE_SUPERHERO: 'CommonBuffId' = 201831 + ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR2_MOVIE_VICTORIAN: 'CommonBuffId' = 201830 + ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR2_MOVIE_WESTERN: 'CommonBuffId' = 201829 + ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR2_TV_HIGH_APOCALYPSE: 'CommonBuffId' = 201809 + ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR2_TV_HIGH_HOSPITAL: 'CommonBuffId' = 201811 + ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR2_TV_HIGH_POLICE: 'CommonBuffId' = 201812 + ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR2_TV_HIGH_VICTORIAN: 'CommonBuffId' = 201810 + ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR2_TV_LOW_PIRATE: 'CommonBuffId' = 201803 + ACTOR_CAREER_HAIR_MOVIE_CITY: 'CommonBuffId' = 197523 + ACTOR_CAREER_HAIR_MOVIE_MEDIEVAL: 'CommonBuffId' = 197529 + ACTOR_CAREER_HAIR_MOVIE_PIRATE: 'CommonBuffId' = 197525 + ACTOR_CAREER_HAIR_MOVIE_SUPERHERO: 'CommonBuffId' = 197522 + ACTOR_CAREER_HAIR_MOVIE_VICTORIAN: 'CommonBuffId' = 197518 + ACTOR_CAREER_HAIR_MOVIE_WESTERN: 'CommonBuffId' = 197533 + ACTOR_CAREER_HAIR_TV_HIGH_APOCALYPSE: 'CommonBuffId' = 197524 + ACTOR_CAREER_HAIR_TV_HIGH_HOSPITAL: 'CommonBuffId' = 197528 + ACTOR_CAREER_HAIR_TV_HIGH_POLICE: 'CommonBuffId' = 197521 + ACTOR_CAREER_HAIR_TV_HIGH_VICTORIAN: 'CommonBuffId' = 197517 + ACTOR_CAREER_HAIR_TV_HIGH_WESTERN: 'CommonBuffId' = 197532 + ACTOR_CAREER_HAIR_TV_LOW_HOUSE_LOW: 'CommonBuffId' = 197534 + ACTOR_CAREER_HAIR_TV_LOW_HOUSE_NICE: 'CommonBuffId' = 197527 + ACTOR_CAREER_HAIR_TV_LOW_KIDS: 'CommonBuffId' = 197520 + ACTOR_CAREER_HAIR_TV_LOW_PIRATE: 'CommonBuffId' = 197515 + ACTOR_CAREER_HAIR_TV_LOW_WESTERN: 'CommonBuffId' = 197531 + ACTOR_CAREER_MAIN_GOAL: 'CommonBuffId' = 197926 + ACTOR_CAREER_MAKEUP_COMMERCIAL_HOSPITAL: 'CommonBuffId' = 197494 + ACTOR_CAREER_MAKEUP_COMMERCIAL_HOUSE_NICE: 'CommonBuffId' = 197484 + ACTOR_CAREER_MAKEUP_COMMERCIAL_KIDS: 'CommonBuffId' = 197487 + ACTOR_CAREER_MAKEUP_COMMERCIAL_PIRATE: 'CommonBuffId' = 197482 + ACTOR_CAREER_MAKEUP_COMMERCIAL_WESTERN: 'CommonBuffId' = 197498 + ACTOR_CAREER_MAKEUP_GENDER_FAIL_0: 'CommonBuffId' = 202357 + ACTOR_CAREER_MAKEUP_GENDER_FAIL_1: 'CommonBuffId' = 202358 + ACTOR_CAREER_MAKEUP_GENDER_FAIL_2: 'CommonBuffId' = 202359 + ACTOR_CAREER_MAKEUP_GENDER_FAIL_3: 'CommonBuffId' = 202360 + ACTOR_CAREER_MAKEUP_GENDER_FAIL_4: 'CommonBuffId' = 202361 + ACTOR_CAREER_MAKEUP_MOVIE_CITY: 'CommonBuffId' = 197489 + ACTOR_CAREER_MAKEUP_MOVIE_MEDIEVAL: 'CommonBuffId' = 197497 + ACTOR_CAREER_MAKEUP_MOVIE_PIRATE: 'CommonBuffId' = 197493 + ACTOR_CAREER_MAKEUP_MOVIE_SUPERHERO: 'CommonBuffId' = 197490 + ACTOR_CAREER_MAKEUP_MOVIE_VICTORIAN: 'CommonBuffId' = 197486 + ACTOR_CAREER_MAKEUP_MOVIE_WESTERN: 'CommonBuffId' = 197501 + ACTOR_CAREER_MAKEUP_TV_HIGH_APOCALYPSE: 'CommonBuffId' = 197492 + ACTOR_CAREER_MAKEUP_TV_HIGH_HOSPITAL: 'CommonBuffId' = 197496 + ACTOR_CAREER_MAKEUP_TV_HIGH_POLICE: 'CommonBuffId' = 197491 + ACTOR_CAREER_MAKEUP_TV_HIGH_VICTORIAN: 'CommonBuffId' = 197485 + ACTOR_CAREER_MAKEUP_TV_HIGH_WESTERN: 'CommonBuffId' = 197500 + ACTOR_CAREER_MAKEUP_TV_LOW_HOUSE_LOW: 'CommonBuffId' = 197502 + ACTOR_CAREER_MAKEUP_TV_LOW_HOUSE_NICE: 'CommonBuffId' = 197495 + ACTOR_CAREER_MAKEUP_TV_LOW_KIDS: 'CommonBuffId' = 197488 + ACTOR_CAREER_MAKEUP_TV_LOW_PIRATE: 'CommonBuffId' = 197483 + ACTOR_CAREER_MAKEUP_TV_LOW_WESTERN: 'CommonBuffId' = 197499 + ACTOR_CAREER_MAKEUP_UNISEX_FAIL_0: 'CommonBuffId' = 202363 + ACTOR_CAREER_MAKEUP_UNISEX_FAIL_1: 'CommonBuffId' = 202364 + ACTOR_CAREER_MAKEUP_UNISEX_FAIL_2: 'CommonBuffId' = 202365 + ACTOR_CAREER_PRACTICED_SCENE: 'CommonBuffId' = 189338 + ACTOR_CAREER_PREP_TASKS_RESEARCH_MOOD_ANGRY: 'CommonBuffId' = 200801 + ACTOR_CAREER_PREP_TASKS_RESEARCH_MOOD_FLIRTY: 'CommonBuffId' = 200800 + ACTOR_CAREER_PREP_TASKS_RESEARCH_MOOD_PLAY_FUL: 'CommonBuffId' = 200802 + ACTOR_CAREER_READY_TO_PERFORM: 'CommonBuffId' = 191351 + ACTOR_CAREER_ROLE_GO_TO_MARK_BACKGROUND_PRODUCER: 'CommonBuffId' = 191196 + ACTOR_CAREER_ROLE_GO_TO_MARK_COSTAR2: 'CommonBuffId' = 190125 + ACTOR_CAREER_ROLE_GO_TO_MARK_CO_STAR1: 'CommonBuffId' = 189282 + ACTOR_CAREER_ROLE_GO_TO_MARK_DIRECTOR: 'CommonBuffId' = 190126 + ACTOR_CAREER_ROLE_GO_TO_MARK_DOLLY_CAMERA_OPERATOR: 'CommonBuffId' = 190530 + ACTOR_CAREER_ROLE_GO_TO_MARK_SPECIAL_EFFECTS_OPERATOR: 'CommonBuffId' = 192119 + ACTOR_CAREER_ROLE_GO_TO_MARK_STATIONARY_CAMERA_OPERATOR: 'CommonBuffId' = 191276 + ACTOR_CAREER_ROLE_PLAYER: 'CommonBuffId' = 197344 + ACTOR_CAREER_ROLE_PRE_PERFORMANCE_BACKGROUND_ACTOR: 'CommonBuffId' = 193211 + ACTOR_CAREER_ROLE_PRE_PERFORMANCE_BACKGROUND_PRODUCER: 'CommonBuffId' = 192799 + ACTOR_CAREER_ROLE_PRE_PERFORMANCE_DIRECTOR: 'CommonBuffId' = 191096 + ACTOR_CAREER_ROLE_PRE_PERFORMANCE_DOLLY_CAMERA_OPERATOR: 'CommonBuffId' = 191075 + ACTOR_CAREER_ROLE_PRE_PERFORMANCE_SPECIAL_EFFECTS: 'CommonBuffId' = 199288 + ACTOR_CAREER_ROLE_PRE_PERFORMANCE_STATIONARY_CAMERA_OPERATOR: 'CommonBuffId' = 191279 + ADOPTION: 'CommonBuffId' = 40069 + ADULT_MOOD_SWING_ANGRY: 'CommonBuffId' = 164632 + ADULT_MOOD_SWING_EMBARRASSED: 'CommonBuffId' = 164634 + ADULT_MOOD_SWING_SAD: 'CommonBuffId' = 164636 + ADULT_MOOD_SWING_STRESSED: 'CommonBuffId' = 164638 + ADVENTUROUS_ATE_QUICK_MEAL: 'CommonBuffId' = 252229 + ADVENTUROUS_DID_WOOHOO: 'CommonBuffId' = 252180 + ADVENTUROUS_DID_WOOHOO_FLAG_BAT: 'CommonBuffId' = 252252 + ADVENTUROUS_DID_WOOHOO_FLAG_BUSH: 'CommonBuffId' = 252253 + ADVENTUROUS_DID_WOOHOO_FLAG_CLOSET: 'CommonBuffId' = 252262 + ADVENTUROUS_DID_WOOHOO_FLAG_COFFIN: 'CommonBuffId' = 252263 + ADVENTUROUS_DID_WOOHOO_FLAG_DUMPSTER: 'CommonBuffId' = 252264 + ADVENTUROUS_DID_WOOHOO_FLAG_DWELLING: 'CommonBuffId' = 252265 + ADVENTUROUS_DID_WOOHOO_FLAG_HOT_SPRINGS: 'CommonBuffId' = 252266 + ADVENTUROUS_DID_WOOHOO_FLAG_HOT_TUB: 'CommonBuffId' = 252254 + ADVENTUROUS_DID_WOOHOO_FLAG_ISLAND_WATERFALL: 'CommonBuffId' = 252255 + ADVENTUROUS_DID_WOOHOO_FLAG_LEAF_PILE: 'CommonBuffId' = 252256 + ADVENTUROUS_DID_WOOHOO_FLAG_LIGHTHOUSE: 'CommonBuffId' = 252257 + ADVENTUROUS_DID_WOOHOO_FLAG_LIVESTOCK_PEN: 'CommonBuffId' = 257640 + ADVENTUROUS_DID_WOOHOO_FLAG_ROCKET_SHIP: 'CommonBuffId' = 252258 + ADVENTUROUS_DID_WOOHOO_FLAG_ROMANTIC_BLANKET: 'CommonBuffId' = 359659 + ADVENTUROUS_DID_WOOHOO_FLAG_SLEEPING_POD: 'CommonBuffId' = 252259 + ADVENTUROUS_DID_WOOHOO_FLAG_STEAM_ROOM: 'CommonBuffId' = 252260 + ADVENTUROUS_DID_WOOHOO_FLAG_TELESCOPE: 'CommonBuffId' = 252261 + ADVENTUROUS_DID_WOOHOO_FLAG_TENT: 'CommonBuffId' = 252267 + ADVENTUROUS_DID_WOOHOO_FLAG_TREEHOUSE: 'CommonBuffId' = 310670 + ADVENTUROUS_DID_WOOHOO_FLAG_WALK_IN_SAFE: 'CommonBuffId' = 252268 + ADVENTUROUS_HIGH_SKILL_BORED: 'CommonBuffId' = 252512 + ADVENTUROUS_HIGH_SKILL_BORED_GAIN: 'CommonBuffId' = 252510 + ADVENTUROUS_INSPIRED_MEAL: 'CommonBuffId' = 252306 + ADVENTUROUS_LOW_SKILL_BONUS_SKILL: 'CommonBuffId' = 252507 + ADVENTUROUS_ON_AN_ADVENTURE: 'CommonBuffId' = 252221 + ADVENTUROUS_TALE: 'CommonBuffId' = 103144 + ADVENTUROUS_TALE_GREAT_STORY: 'CommonBuffId' = 109730 + ALIEN_ABDUCTION_HIGH: 'CommonBuffId' = 102868 + ALIEN_ABDUCTION_HIGH_SATELLITE_CALLED: 'CommonBuffId' = 107162 + ALIEN_ABDUCTION_LOW: 'CommonBuffId' = 115180 + ALIEN_ABDUCTION_MEDIUM: 'CommonBuffId' = 115181 + ALIEN_ABDUCTION_NO_CHANCE: 'CommonBuffId' = 107158 + ALIEN_ABDUCTION_VERY_HIGH: 'CommonBuffId' = 115182 + ALIEN_ABDUCTION_VERY_LOW: 'CommonBuffId' = 115179 + ALIEN_ALIEN_CONTACT_FROM_SATELLITE: 'CommonBuffId' = 107166 + ALIEN_DETECT_AURA: 'CommonBuffId' = 108874 + ALIEN_DISCOVERY_ANGRY_REACTION: 'CommonBuffId' = 111529 + ALIEN_DISCOVERY_CONFIDENT_REACTION: 'CommonBuffId' = 111530 + ALIEN_DISCOVERY_EMBARRASSED_ALIEN: 'CommonBuffId' = 111528 + ALIEN_DISCOVERY_SUBJECT_OF_ALIEN_BRAINPOWER_INTERACTION: 'CommonBuffId' = 116577 + ALIEN_EMPATHY_COOLDOWN_TIMER: 'CommonBuffId' = 103559 + ALIEN_EMPATHY_EMOTION_ANGRY: 'CommonBuffId' = 103474 + ALIEN_EMPATHY_EMOTION_BORED: 'CommonBuffId' = 103475 + ALIEN_EMPATHY_EMOTION_CONFIDENT: 'CommonBuffId' = 103487 + ALIEN_EMPATHY_EMOTION_DAZED: 'CommonBuffId' = 103486 + ALIEN_EMPATHY_EMOTION_EMBARRASSED: 'CommonBuffId' = 103485 + ALIEN_EMPATHY_EMOTION_ENERGIZED: 'CommonBuffId' = 103484 + ALIEN_EMPATHY_EMOTION_FLIRTY: 'CommonBuffId' = 103483 + ALIEN_EMPATHY_EMOTION_FOCUSED: 'CommonBuffId' = 103482 + ALIEN_EMPATHY_EMOTION_HAPPY: 'CommonBuffId' = 103481 + ALIEN_EMPATHY_EMOTION_INSPIRED: 'CommonBuffId' = 103480 + ALIEN_EMPATHY_EMOTION_PLAYFUL: 'CommonBuffId' = 103479 + ALIEN_EMPATHY_EMOTION_SAD: 'CommonBuffId' = 103478 + ALIEN_EMPATHY_EMOTION_STRESSED: 'CommonBuffId' = 103477 + ALIEN_EMPATHY_EMOTION_UNCOMFORTABLE: 'CommonBuffId' = 103476 + ALIEN_HOMESICK: 'CommonBuffId' = 103361 + ALIEN_IS_ALIEN: 'CommonBuffId' = 103358 + ALIEN_LOW_BRAIN_POWER: 'CommonBuffId' = 103333 + ALIEN_MEMORY_ERASE: 'CommonBuffId' = 103576 + ALIEN_MOOD_AURA_ANGRY: 'CommonBuffId' = 108933 + ALIEN_MOOD_AURA_BORED: 'CommonBuffId' = 108943 + ALIEN_MOOD_AURA_CHILD_ANGRY: 'CommonBuffId' = 114644 + ALIEN_MOOD_AURA_CHILD_BORED: 'CommonBuffId' = 114645 + ALIEN_MOOD_AURA_CHILD_CONFIDENT: 'CommonBuffId' = 114654 + ALIEN_MOOD_AURA_CHILD_EMBARRASSED: 'CommonBuffId' = 114646 + ALIEN_MOOD_AURA_CHILD_ENERGISED: 'CommonBuffId' = 114647 + ALIEN_MOOD_AURA_CHILD_FOCUSED: 'CommonBuffId' = 114649 + ALIEN_MOOD_AURA_CHILD_HAPPY: 'CommonBuffId' = 114648 + ALIEN_MOOD_AURA_CHILD_INSPIRED: 'CommonBuffId' = 114650 + ALIEN_MOOD_AURA_CHILD_PLAYFUL: 'CommonBuffId' = 114651 + ALIEN_MOOD_AURA_CHILD_SAD: 'CommonBuffId' = 114652 + ALIEN_MOOD_AURA_CHILD_STRESSED: 'CommonBuffId' = 114653 + ALIEN_MOOD_AURA_CHILD_UNCOMFORTABLE: 'CommonBuffId' = 114655 + ALIEN_MOOD_AURA_CONFIDENT: 'CommonBuffId' = 108944 + ALIEN_MOOD_AURA_DAZED: 'CommonBuffId' = 108945 + ALIEN_MOOD_AURA_EMBARRASSED: 'CommonBuffId' = 108935 + ALIEN_MOOD_AURA_ENERGISED: 'CommonBuffId' = 108936 + ALIEN_MOOD_AURA_FLIRTY: 'CommonBuffId' = 108937 + ALIEN_MOOD_AURA_FOCUSED: 'CommonBuffId' = 108938 + ALIEN_MOOD_AURA_HAPPY: 'CommonBuffId' = 108939 + ALIEN_MOOD_AURA_INSPIRED: 'CommonBuffId' = 108940 + ALIEN_MOOD_AURA_PLAYFUL: 'CommonBuffId' = 108941 + ALIEN_MOOD_AURA_REMOVED_MOOD_AURA_BUFFS: 'CommonBuffId' = 114656 + ALIEN_MOOD_AURA_SAD: 'CommonBuffId' = 108934 + ALIEN_MOOD_AURA_STRESSED: 'CommonBuffId' = 108942 + ALIEN_MOOD_AURA_UNCOMFORTABLE: 'CommonBuffId' = 108946 + ALIEN_REMINDED_OF_HOME: 'CommonBuffId' = 103362 + ALIEN_SATELLITE_DETECT_ALIENS_COOL_DOWN: 'CommonBuffId' = 115021 + ALIEN_SATELLITE_DISH_HIVE_MIND_ANGRY: 'CommonBuffId' = 107525 + ALIEN_SATELLITE_DISH_HIVE_MIND_DANCE: 'CommonBuffId' = 107524 + ALIEN_SATELLITE_DISH_HIVE_MIND_HAPPY: 'CommonBuffId' = 107526 + ALIEN_SATELLITE_DISH_HIVE_MIND_KNOCKED_OUT: 'CommonBuffId' = 107533 + ALIEN_SATELLITE_DISH_HIVE_MIND_KNOCKOUT_DAZED: 'CommonBuffId' = 107534 + ALIEN_SCARE_WITH_PROBE: 'CommonBuffId' = 115015 + ALIEN_VISIT_ALIEN: 'CommonBuffId' = 113541 + ALLOW_SLEEP_DESIRE: 'CommonBuffId' = 36123 + ALMOST_ALWAYS_RUN: 'CommonBuffId' = 207314 + ANGRY_ABOUT_VICIOUS_RUMOR: 'CommonBuffId' = 35130 + ANIMAL_OBJECTS_BIRD_HOME_SINGING_SKILL_EXISTS: 'CommonBuffId' = 269176 + ANIMAL_OBJECTS_CHEATS_FORCE_OUTCOME_SOCIAL_FAIL: 'CommonBuffId' = 257699 + ANIMAL_OBJECTS_CHEATS_FORCE_OUTCOME_SOCIAL_SUCCESS: 'CommonBuffId' = 257698 + ANIMAL_OBJECTS_CHICKEN_GRIM_DEFEATED: 'CommonBuffId' = 268695 + ANIMAL_OBJECTS_COWS_COWBELL_COOLDOWN: 'CommonBuffId' = 268471 + ANIMAL_OBJECTS_GOAT_SHEEP_SAW_TRICK_HIDDEN: 'CommonBuffId' = 331883 + ANIMAL_OBJECTS_MOODLETS_DEATH_RABBIT: 'CommonBuffId' = 257724 + ANIMAL_OBJECTS_MOODLETS_EGG_DARK_CHICKEN: 'CommonBuffId' = 267396 + ANIMAL_OBJECTS_MOODLETS_EGG_GOLDEN_CHICKEN: 'CommonBuffId' = 267395 + ANIMAL_OBJECTS_MOODLETS_EGG_MMM_CHOCOLATE: 'CommonBuffId' = 267386 + ANIMAL_OBJECTS_MOODLETS_GHOST_KILLER_CHICKEN_ANGRY: 'CommonBuffId' = 268000 + ANIMAL_OBJECTS_MOODLETS_GHOST_KILLER_CHICKEN_SCARED: 'CommonBuffId' = 268001 + ANIMAL_OBJECTS_MOODLETS_GHOST_KILLER_CHICKEN_TENSE: 'CommonBuffId' = 268002 + ANIMAL_OBJECTS_MOODLETS_GHOST_KILLER_RABBIT_ANGRY: 'CommonBuffId' = 260124 + ANIMAL_OBJECTS_MOODLETS_GHOST_KILLER_RABBIT_SCARED: 'CommonBuffId' = 260122 + ANIMAL_OBJECTS_MOODLETS_GHOST_KILLER_RABBIT_TENSE: 'CommonBuffId' = 260123 + ANIMAL_OBJECTS_MOODLETS_GOAT_SHEEP_IMPROVE_MOOD_COOLDOWN: 'CommonBuffId' = 327758 + ANIMAL_OBJECTS_MOODLETS_GOAT_SHEEP_PLACE_DOWN_COOLDOWN: 'CommonBuffId' = 351539 + ANIMAL_OBJECTS_MOODLETS_NEW_FRIEND_BIRD_HOME: 'CommonBuffId' = 257727 + ANIMAL_OBJECTS_MOODLETS_NEW_FRIEND_RABBIT: 'CommonBuffId' = 257726 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_ANGRY_BIRD_HOME_SHOW_AFFECTION: 'CommonBuffId' = 268821 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_ANGRY_BIRD_HOME_TALK: 'CommonBuffId' = 257766 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_CONFIDENT_BIRD_HOME_SCARE: 'CommonBuffId' = 257776 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_CONFIDENT_CHICKEN_ATTACKED: 'CommonBuffId' = 268039 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_CONFIDENT_RABBIT_ATTACKED: 'CommonBuffId' = 257751 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_DAZED_CHICKEN_ATTACKED: 'CommonBuffId' = 268040 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_DAZED_RABBIT_ATTACKED: 'CommonBuffId' = 257753 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_EMBARRASSED_BIRD_HOME_QUESTION: 'CommonBuffId' = 257769 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_EMBARRASSED_BIRD_HOME_SING: 'CommonBuffId' = 257780 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_EMBARRASSED_GOAT_JOKE: 'CommonBuffId' = 326070 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_EMBARRASSED_LIVESTOCK_PEN_SCARE_ANIMAL_ENTHUSIAST: 'CommonBuffId' = 263700 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_EMBARRASSED_RABBIT_JOKE: 'CommonBuffId' = 257738 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_EMBARRASSED_SHEEP_JOKE: 'CommonBuffId' = 326071 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_ENERGIZED_BIRD_HOME_WATCH: 'CommonBuffId' = 257756 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_ENERGIZED_COWBELL: 'CommonBuffId' = 268477 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_ENERGIZED_SHEEP_COUNT: 'CommonBuffId' = 325648 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_HAPPY_BIRD_HOME_QUESTION: 'CommonBuffId' = 257767 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_HAPPY_BIRD_HOME_SCARE: 'CommonBuffId' = 257772 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_HAPPY_BIRD_HOME_SHOW_AFFECTION: 'CommonBuffId' = 268820 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_HAPPY_BIRD_HOME_TALK: 'CommonBuffId' = 257761 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_HAPPY_CHICKEN_HUG: 'CommonBuffId' = 261286 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_HAPPY_COW_HUG: 'CommonBuffId' = 263671 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_HAPPY_COW_HUG_ANIMAL_ENTHUSIAST: 'CommonBuffId' = 263672 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_HAPPY_GOAT_HUG: 'CommonBuffId' = 326075 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_HAPPY_GOAT_PET: 'CommonBuffId' = 326077 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_HAPPY_GOAT_TALK: 'CommonBuffId' = 326072 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_HAPPY_LLAMA_HUG: 'CommonBuffId' = 263673 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_HAPPY_LLAMA_HUG_ANIMAL_ENTHUSIAST: 'CommonBuffId' = 263674 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_HAPPY_RABBIT_HUG: 'CommonBuffId' = 257747 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_HAPPY_RABBIT_JOKE: 'CommonBuffId' = 257733 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_HAPPY_RABBIT_TALK: 'CommonBuffId' = 257729 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_HAPPY_ROOSTER_HUG: 'CommonBuffId' = 271329 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_HAPPY_SHEEP_HUG: 'CommonBuffId' = 326074 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_HAPPY_SHEEP_PET: 'CommonBuffId' = 326076 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_HAPPY_SHEEP_TALK: 'CommonBuffId' = 326073 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_INSPIRED_BIRD_HOME_QUESTION: 'CommonBuffId' = 257768 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_INSPIRED_BIRD_HOME_SING: 'CommonBuffId' = 257778 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_INSPIRED_BIRD_HOME_TALK: 'CommonBuffId' = 257762 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_INSPIRED_BIRD_HOME_WATCH: 'CommonBuffId' = 257757 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_INSPIRED_RABBIT_QUESTION: 'CommonBuffId' = 257732 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_PLAYFUL_GOAT_BE_MEAN: 'CommonBuffId' = 326078 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_PLAYFUL_GOAT_JOKE: 'CommonBuffId' = 326092 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_PLAYFUL_GOAT_PLAY_WITH: 'CommonBuffId' = 326094 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_PLAYFUL_GOAT_SCARE: 'CommonBuffId' = 326091 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_PLAYFUL_RABBIT_BE_MEAN: 'CommonBuffId' = 257742 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_PLAYFUL_RABBIT_JOKE: 'CommonBuffId' = 257735 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_PLAYFUL_RABBIT_SCARE: 'CommonBuffId' = 257741 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_PLAYFUL_SHEEP_BE_MEAN: 'CommonBuffId' = 326079 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_PLAYFUL_SHEEP_JOKE: 'CommonBuffId' = 326093 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_PLAYFUL_SHEEP_PLAY_WITH: 'CommonBuffId' = 326095 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_PLAYFUL_SHEEP_SCARE: 'CommonBuffId' = 326090 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_PLAYFUL_SHEEP_TRICK: 'CommonBuffId' = 325223 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_BIRD_HOME_QUESTION: 'CommonBuffId' = 257770 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_BIRD_HOME_SHOW_AFFECTION: 'CommonBuffId' = 268825 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_BIRD_HOME_SING: 'CommonBuffId' = 257779 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_CHICKEN_DEATH: 'CommonBuffId' = 261284 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_CHICKEN_MISSING: 'CommonBuffId' = 261285 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_CHICKEN_SOLD: 'CommonBuffId' = 261287 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_COWBELL: 'CommonBuffId' = 268484 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_COW_DEATH: 'CommonBuffId' = 263656 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_COW_HUG: 'CommonBuffId' = 263713 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_COW_HUG_ANIMAL_ENTHUSIAST: 'CommonBuffId' = 263714 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_COW_SOLD: 'CommonBuffId' = 263676 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_GOAT_DEATH: 'CommonBuffId' = 330927 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_GOAT_MISSING: 'CommonBuffId' = 336493 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_GOAT_TALK: 'CommonBuffId' = 326096 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_LIVESTOCK_PEN_GO_MISSING: 'CommonBuffId' = 268063 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_LLAMA_DEATH: 'CommonBuffId' = 263657 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_LLAMA_SOLD: 'CommonBuffId' = 263677 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_PET_TODDLER: 'CommonBuffId' = 339929 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_RABBIT_HUG: 'CommonBuffId' = 257749 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_SHEEP_DEATH: 'CommonBuffId' = 330928 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_SHEEP_HUG: 'CommonBuffId' = 326098 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_SHEEP_MISSING: 'CommonBuffId' = 336494 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_SHEEP_PET: 'CommonBuffId' = 326099 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_SHEEP_PLAY_WITH: 'CommonBuffId' = 326100 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_SHEEP_TALK: 'CommonBuffId' = 326097 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_SCARED_CHICKEN_PECKED_AT: 'CommonBuffId' = 261271 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_SCARED_CHICKEN_PECKED_AT_TODDLERS: 'CommonBuffId' = 264978 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_SCARED_LLAMA_HUG: 'CommonBuffId' = 263716 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_SCARED_RABBIT_ATTACKED: 'CommonBuffId' = 257754 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_SCARED_RABBIT_PET: 'CommonBuffId' = 257744 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_SCARED_ROOSTER_PECKED_AT: 'CommonBuffId' = 271331 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_SCARED_ROOSTER_PECKED_AT_TODDLERS: 'CommonBuffId' = 271332 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_TENSE_COW_MILK_FAIL: 'CommonBuffId' = 263084 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_TENSE_COW_MILK_FAIL_ANIMAL_ENTHUSIAST: 'CommonBuffId' = 267015 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_TENSE_LIVESTOCK_PEN_BE_MEAN_ANIMAL_ENTHUSIAST: 'CommonBuffId' = 263699 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_TENSE_LLAMA_SHEAR_FAIL: 'CommonBuffId' = 263085 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_TENSE_LLAMA_SHEAR_FAIL_ANIMAL_ENTHUSIAST: 'CommonBuffId' = 267016 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_TENSE_RABBIT_JOKE: 'CommonBuffId' = 257745 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_TENSE_RABBIT_PET: 'CommonBuffId' = 257746 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_UNCOMFORTABLE_BIRD_HOME_SING: 'CommonBuffId' = 257781 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_UNCOMFORTABLE_BIRD_HOME_TALK: 'CommonBuffId' = 257764 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_UNCOMFORTABLE_GOAT_HEADBUTT: 'CommonBuffId' = 326101 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_UNCOMFORTABLE_GOAT_YELLING: 'CommonBuffId' = 325100 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_UNCOMFORTABLE_LIVESTOCK_PEN_SMELLY: 'CommonBuffId' = 263698 + ANIMAL_OBJECTS_MOODLETS_SOCIALS_UNCOMFORTABLE_LLAMA_HUG: 'CommonBuffId' = 263715 + ANIMAL_OBJECTS_MOODLETS_TRAIT_SQUEAMISH_BIRD_HOME_GARDENING_HELP: 'CommonBuffId' = 257785 + ANIMAL_OBJECTS_MOODLETS_TRAIT_SQUEAMISH_BIRD_HOME_POOPED_ON: 'CommonBuffId' = 257784 + ANIMAL_OBJECTS_RABBIT_SIM_ABOUT_TO_DIE: 'CommonBuffId' = 264515 + ANIMAL_OBJECTS_SOLD_MY_FRIEND_TRACKER: 'CommonBuffId' = 339253 + APM_ANNOYING_FREELOADERS: 'CommonBuffId' = 347766 + APM_CONTRACT_BROKEN: 'CommonBuffId' = 347767 + APM_DELIVER_FINE_COOLDOWN: 'CommonBuffId' = 359216 + APM_DELIVER_RENT_COOLDOWN: 'CommonBuffId' = 359214 + APM_GETTING_AWAY_WITH_IT: 'CommonBuffId' = 347764 + APM_POST_COOLDOWN: 'CommonBuffId' = 357722 + APM_POST_FINE_COOLDOWN: 'CommonBuffId' = 359215 + APM_POST_RENT_COOLDOWN: 'CommonBuffId' = 359213 + APM_POWER_OUTAGE_ANGRY_WAIT_COOLDOWN: 'CommonBuffId' = 358727 + APM_POWER_OUTAGE_AT_OWNED_RENTABLE_RESIDENTIAL: 'CommonBuffId' = 351431 + APM_PROSECUTE_FINE_COOLDOWN: 'CommonBuffId' = 359461 + APM_RELIABLE_SUPPORT: 'CommonBuffId' = 347761 + APM_SHODDY_SUPPORT: 'CommonBuffId' = 347762 + APM_SITUATION_ARRIVAL: 'CommonBuffId' = 355966 + APM_TAKING_THE_HIT: 'CommonBuffId' = 347763 + APM_TREACHEROUS_TENANTS: 'CommonBuffId' = 347765 + APPLY_FROZEN_ADULT: 'CommonBuffId' = 116188 + APPLY_FROZEN_CHILD: 'CommonBuffId' = 116189 + ARCADE_MACHINE_GAME_WIN: 'CommonBuffId' = 129185 + ARCADE_MACHINE_LEVEL_WIN: 'CommonBuffId' = 129184 + ARCADE_MACHINE_LOSE_GAME_HIDDEN: 'CommonBuffId' = 127480 + ARCADE_MACHINE_PLAYER_1: 'CommonBuffId' = 128521 + ARCADE_MACHINE_PLAYER_2: 'CommonBuffId' = 128522 + ARCADE_MACHINE_PLAYER_3: 'CommonBuffId' = 128523 + ARCADE_MACHINE_PLAYER_4: 'CommonBuffId' = 128520 + ARCADE_MACHINE_WIN_GAME_HIDDEN: 'CommonBuffId' = 129284 + ARCADE_MACHINE_WIN_GAME_WALK_AWAY_HIDDEN: 'CommonBuffId' = 129550 + ARCHAEOLOGY_SKILL_GIVE_ARCHAEOLOGY_LECTURE_ACTOR_FAILURE: 'CommonBuffId' = 174886 + ARCHAEOLOGY_SKILL_GIVE_ARCHAEOLOGY_LECTURE_ACTOR_SUCCESS: 'CommonBuffId' = 174855 + ARCHAEOLOGY_SKILL_GIVE_ARCHAEOLOGY_LECTURE_LISTENERS_SUCCESS: 'CommonBuffId' = 174889 + ARCHAEOLOGY_SKILL_STUDY_FOR_HISTORICAL_INSIGHTS_FOCUSED: 'CommonBuffId' = 174307 + ARCHAEOLOGY_TABLE_ANALYZE_COLLECTIBLE_FOCUSED: 'CommonBuffId' = 175740 + ARCHAEOLOGY_TABLE_AUTHENTICATE_ARTIFACT_FOCUSED: 'CommonBuffId' = 176077 + ARCHAEOLOGY_TABLE_UNCOVER_ARTIFACT_FOCUSED: 'CommonBuffId' = 176078 + ASKED_TO_STAY_NIGHT_INVISIBLE: 'CommonBuffId' = 101209 + ASK_FOR_RECYCLING_MATERIALS_COOLDOWN: 'CommonBuffId' = 234365 + ASK_SIM_TO_PURSUE_DREAM_JOB_AMATEUR_CAREER_CONSULTANT: 'CommonBuffId' = 274864 + ASK_SIM_TO_PURSUE_DREAM_JOB_EXPERT_CAREER_CONSULTANT: 'CommonBuffId' = 274862 + ASK_SIM_TO_PURSUE_DREAM_JOB_HIDDEN_COOLDOWN_FAILURE: 'CommonBuffId' = 274796 + ASK_SIM_TO_PURSUE_DREAM_JOB_HIDDEN_COOLDOWN_SUCCESS: 'CommonBuffId' = 274821 + ASK_SIM_TO_PURSUE_DREAM_JOB_ONLY_TRYING_TO_HELP: 'CommonBuffId' = 274822 + ASK_SIM_TO_PURSUE_DREAM_JOB_SERIOUS_LIFE_CHANGES: 'CommonBuffId' = 274863 + ASPIRATION_COMPLETE_INVISIBLE: 'CommonBuffId' = 325690 + ASPIRATION_MIND_AND_BODY_NO_BAD_MOOD: 'CommonBuffId' = 313715 + ASPIRATION_MIND_AND_BODY_NO_BAD_MOOD_COMPLETE: 'CommonBuffId' = 313716 + ASPIRATION_SUPER_PARENT_IN_LIFE_SKILL_RANGE: 'CommonBuffId' = 167467 + ATMOSPHERIC_CONDENSER_WATER_PRESSURE_UNCOMFORTABLE: 'CommonBuffId' = 233300 + ATTRACTION_CAN_LEARN_ATTRACTION_REQUIRED_STUFF: 'CommonBuffId' = 380149 + ATTRACTION_CONVERSATION_EMBARRASSED: 'CommonBuffId' = 362281 + ATTRACTION_CONVERSATION_HAPPY: 'CommonBuffId' = 362282 + ATTRACTION_FOUND_ATTRACTIVE: 'CommonBuffId' = 365137 + ATTRACTION_HAS_TURN_OFF: 'CommonBuffId' = 365341 + ATTRACTION_HAS_TURN_ON: 'CommonBuffId' = 365340 + ATTRACTION_LEARN_ABOUT_IDLE_CHAT_COOLDOWN: 'CommonBuffId' = 364915 + ATTRACTOR_POINT_BEACH_COOLDOWN: 'CommonBuffId' = 209673 + AT_MAGIC_HQ: 'CommonBuffId' = 216284 + AUTONOMOUS_GRILL_COOLDOWN: 'CommonBuffId' = 351701 + AUTONOMY_MOD_ACTIVITY_TABLE: 'CommonBuffId' = 143507 + AUTONOMY_MOD_ADD_CANDLES_TO_CAKE: 'CommonBuffId' = 39354 + AUTONOMY_MOD_APM_ANGRY_VISIBLE: 'CommonBuffId' = 357312 + AUTONOMY_MOD_APM_CHECK_RULES_FOR_VISIT_COOLDOWN: 'CommonBuffId' = 359443 + AUTONOMY_MOD_APM_DELIVER_FINE: 'CommonBuffId' = 358859 + AUTONOMY_MOD_APM_DOMAIN_TENANCE: 'CommonBuffId' = 358084 + AUTONOMY_MOD_APM_PRIMARY_REMEDY: 'CommonBuffId' = 345513 + AUTONOMY_MOD_APM_SECONDARY_REMEDY: 'CommonBuffId' = 345675 + AUTONOMY_MOD_APM_TRIGGER_EVICTION: 'CommonBuffId' = 351126 + AUTONOMY_MOD_ARTS_CENTER_ORDER_DRINK: 'CommonBuffId' = 154445 + AUTONOMY_MOD_BABY_SHOWER_BARTENDER: 'CommonBuffId' = 309657 + AUTONOMY_MOD_BAKE_ONE_CAKE: 'CommonBuffId' = 31036 + AUTONOMY_MOD_BARTENDER: 'CommonBuffId' = 128325 + AUTONOMY_MOD_BEAR: 'CommonBuffId' = 104743 + AUTONOMY_MOD_BEHAVIOR_BOMB_ENERGY: 'CommonBuffId' = 224372 + AUTONOMY_MOD_BEHAVIOR_BOMB_PARTY: 'CommonBuffId' = 218932 + AUTONOMY_MOD_BEHAVIOR_BOMB_STUDY: 'CommonBuffId' = 219266 + AUTONOMY_MOD_BEHAVIOR_BOMB_TIDY: 'CommonBuffId' = 219250 + AUTONOMY_MOD_BIRTHDAY_BLOW_OUT_CANDLES: 'CommonBuffId' = 117435 + AUTONOMY_MOD_BIRTHDAY_GUEST_CELEBRATE: 'CommonBuffId' = 32209 + AUTONOMY_MOD_BREAK_THINGS: 'CommonBuffId' = 12617 + AUTONOMY_MOD_BROWSE_BOOKS: 'CommonBuffId' = 96922 + AUTONOMY_MOD_CAFE_BARISTA_ACTIVE: 'CommonBuffId' = 124621 + AUTONOMY_MOD_CAFE_BUSINESS_PARTNER: 'CommonBuffId' = 125186 + AUTONOMY_MOD_CAFE_CUSTOMER: 'CommonBuffId' = 122234 + AUTONOMY_MOD_CAFE_FRIENDS: 'CommonBuffId' = 125048 + AUTONOMY_MOD_CAFE_MEDIA_USER: 'CommonBuffId' = 122744 + AUTONOMY_MOD_CAFE_ORDER_DRINK: 'CommonBuffId' = 122674 + AUTONOMY_MOD_CAFE_ORDER_DRINK_TO_GO: 'CommonBuffId' = 124308 + AUTONOMY_MOD_CAFE_ORDER_FOOD: 'CommonBuffId' = 130063 + AUTONOMY_MOD_CAREER_ACTIVIST_ATTRACT_TO_PROTEST_HIDDEN: 'CommonBuffId' = 149923 + AUTONOMY_MOD_CAREER_ACTIVIST_ATTRACT_TO_PROTEST_PLAYER_HIDDEN: 'CommonBuffId' = 155277 + AUTONOMY_MOD_CARVE_PUMPKINS: 'CommonBuffId' = 127118 + AUTONOMY_MOD_CELEBRITY_AT_VENUE: 'CommonBuffId' = 196537 + AUTONOMY_MOD_CELEBRITY_HANG_OUT_BAR: 'CommonBuffId' = 191731 + AUTONOMY_MOD_CELEBRITY_HANG_OUT_GYM: 'CommonBuffId' = 191732 + AUTONOMY_MOD_CELEBRITY_HANG_OUT_LIBRARY: 'CommonBuffId' = 191729 + AUTONOMY_MOD_CELEBRITY_HANG_OUT_MUSEUM: 'CommonBuffId' = 191727 + AUTONOMY_MOD_CELEBRITY_HANG_OUT_PARK: 'CommonBuffId' = 191730 + AUTONOMY_MOD_CELEBRITY_HANG_OUT_POOL: 'CommonBuffId' = 191728 + AUTONOMY_MOD_CELEBRITY_NEARBY_SIMS: 'CommonBuffId' = 196650 + AUTONOMY_MOD_CELEBRITY_NEARBY_SIMS_ARRIVE_AT_VENUE: 'CommonBuffId' = 262049 + AUTONOMY_MOD_CHALET_GARDENS_WANDER_MAZE: 'CommonBuffId' = 126240 + AUTONOMY_MOD_CHALET_GHOST_GARDEN: 'CommonBuffId' = 127075 + AUTONOMY_MOD_CHALET_GHOST_PAINTER: 'CommonBuffId' = 126030 + AUTONOMY_MOD_CHALET_GHOST_THINGS: 'CommonBuffId' = 127062 + AUTONOMY_MOD_CITY_LIFE_BASKET_BALLER: 'CommonBuffId' = 149964 + AUTONOMY_MOD_CITY_LIFE_BUSKER_WATCH_BROADCAST: 'CommonBuffId' = 151112 + AUTONOMY_MOD_CITY_LIFE_CITY_REPAIR: 'CommonBuffId' = 144299 + AUTONOMY_MOD_CITY_LIFE_LIVES_ON_STREET_ADULT: 'CommonBuffId' = 151046 + AUTONOMY_MOD_CITY_LIFE_LIVES_ON_STREET_CHILD: 'CommonBuffId' = 153512 + AUTONOMY_MOD_CITY_LIFE_LIVING_STATUE_BUSKER: 'CommonBuffId' = 134322 + AUTONOMY_MOD_CITY_LIFE_MURAL_PAINTER: 'CommonBuffId' = 149974 + AUTONOMY_MOD_CITY_LIFE_MYSHUNO_MEADOWS_TOURIST_BARFLY: 'CommonBuffId' = 152983 + AUTONOMY_MOD_CITY_LIFE_PHONE_CHATTER_COOLDOWN: 'CommonBuffId' = 155329 + AUTONOMY_MOD_CITY_LIFE_PROTESTERS: 'CommonBuffId' = 153087 + AUTONOMY_MOD_CITY_LIFE_READ_GUIDE_COOLDOWN: 'CommonBuffId' = 155331 + AUTONOMY_MOD_CITY_LIFE_TOURIST: 'CommonBuffId' = 134323 + AUTONOMY_MOD_CITY_LIFE_VIEW_COOLDOWN: 'CommonBuffId' = 155708 + AUTONOMY_MOD_CITY_LIFE_WEIRDO: 'CommonBuffId' = 134321 + AUTONOMY_MOD_CITY_LIFE_WEIRDO_BATHROBE_ELDER: 'CommonBuffId' = 145016 + AUTONOMY_MOD_CITY_LIFE_WEIRDO_RACCOON: 'CommonBuffId' = 145018 + AUTONOMY_MOD_CITY_LIFE_WEIRDO_TALK_TO_SELF_COOLDOWN: 'CommonBuffId' = 155649 + AUTONOMY_MOD_CITY_LIFE_WEIRDO_TOWELS: 'CommonBuffId' = 145019 + AUTONOMY_MOD_CLEAN_BAR: 'CommonBuffId' = 27058 + AUTONOMY_MOD_CLEAN_GLASSES: 'CommonBuffId' = 27370 + AUTONOMY_MOD_CLEAN_PLATES: 'CommonBuffId' = 27371 + AUTONOMY_MOD_CLEAR_EASEL: 'CommonBuffId' = 145080 + AUTONOMY_MOD_CLEAR_MURAL: 'CommonBuffId' = 148096 + AUTONOMY_MOD_CLUB_DANCER: 'CommonBuffId' = 123144 + AUTONOMY_MOD_CLUB_DJ: 'CommonBuffId' = 122822 + AUTONOMY_MOD_CLUB_DJ_AUDIENCE: 'CommonBuffId' = 123011 + AUTONOMY_MOD_CLUB_GO_DANCING_PARTY_GOER: 'CommonBuffId' = 123413 + AUTONOMY_MOD_CLUB_GO_DANCING_PARTY_POOPER: 'CommonBuffId' = 126289 + AUTONOMY_MOD_COMPLIMENT_MORE: 'CommonBuffId' = 34849 + AUTONOMY_MOD_CONGRATULATE_MORE: 'CommonBuffId' = 34963 + AUTONOMY_MOD_CONSERVATIONIST: 'CommonBuffId' = 211667 + AUTONOMY_MOD_CRIME_SCENE_DETECTIVE_NPC: 'CommonBuffId' = 115759 + AUTONOMY_MOD_DANCE_FLOOR_GROUP_DANCE_NO_SOCIAL: 'CommonBuffId' = 129081 + AUTONOMY_MOD_DANCE_STEREO: 'CommonBuffId' = 26276 + AUTONOMY_MOD_DEBTOR_REPO: 'CommonBuffId' = 228339 + AUTONOMY_MOD_DEBTOR_REPO_BILLS: 'CommonBuffId' = 241175 + AUTONOMY_MOD_DJ_BOOTH_AUDIENCE_0_COOLDOWN: 'CommonBuffId' = 125705 + AUTONOMY_MOD_DJ_BOOTH_AUDIENCE_1_WATCH: 'CommonBuffId' = 124603 + AUTONOMY_MOD_DJ_BOOTH_AUDIENCE_2_DANCE: 'CommonBuffId' = 124602 + AUTONOMY_MOD_DJ_BOOTH_AUDIENCE_DANCE_DECAY_HIGH: 'CommonBuffId' = 128031 + AUTONOMY_MOD_DJ_BOOTH_AUDIENCE_DANCE_DECAY_LOW: 'CommonBuffId' = 128030 + AUTONOMY_MOD_DJ_BOOTH_AUDIENCE_POSITIVE_BUFF: 'CommonBuffId' = 128378 + AUTONOMY_MOD_DJ_BOOTH_AUDIENCE_WATCH_DECAY_HIGH: 'CommonBuffId' = 128033 + AUTONOMY_MOD_DJ_BOOTH_AUDIENCE_WATCH_DECAY_LOW: 'CommonBuffId' = 128029 + AUTONOMY_MOD_DJ_BOOTH_AUDIENCE_X_ANTI: 'CommonBuffId' = 125704 + AUTONOMY_MOD_DOCTOR_CAREER_AUTONOMOUS_COOLDOWN: 'CommonBuffId' = 116628 + AUTONOMY_MOD_DOCTOR_CAREER_PATIENT_ADMITTED_EXAM_BED: 'CommonBuffId' = 113884 + AUTONOMY_MOD_DOCTOR_CAREER_PATIENT_ADMITTED_EXAM_BED_RECLINE: 'CommonBuffId' = 115264 + AUTONOMY_MOD_DOCTOR_CAREER_PATIENT_ARRIVAL_WAIT_TO_CHECK_IN: 'CommonBuffId' = 113885 + AUTONOMY_MOD_DO_BULLETIN_BOARD_INTERACTIONS: 'CommonBuffId' = 145899 + AUTONOMY_MOD_DO_WOODWORKING: 'CommonBuffId' = 144775 + AUTONOMY_MOD_DUMPSTER_WOOHOO: 'CommonBuffId' = 231207 + AUTONOMY_MOD_EASEL_MENTOR: 'CommonBuffId' = 28374 + AUTONOMY_MOD_EASEL_PAINT: 'CommonBuffId' = 28373 + AUTONOMY_MOD_EAT_ONE_SLICE_OF_CAKE: 'CommonBuffId' = 34440 + AUTONOMY_MOD_EP14_WORLD_NPC_HORSE_TRAINER_ADVERTISE_EQUESTRIAN_CENTER_SITUATION: 'CommonBuffId' = 329804 + AUTONOMY_MOD_EP14_WORLD_NPC_MYSTERIOUS_RANCHER_SELL_NECTAR_SITUATION: 'CommonBuffId' = 327886 + AUTONOMY_MOD_EP16_NPC_VENUE_DATE: 'CommonBuffId' = 369786 + AUTONOMY_MOD_EP16_WORLD_SHELL_VISITORS_FLOWER_SHOP: 'CommonBuffId' = 376280 + AUTONOMY_MOD_EP16_WORLD_SHELL_VISITORS_MOTEL: 'CommonBuffId' = 376279 + AUTONOMY_MOD_ESPRESSO_WAIT_FOR_WORK: 'CommonBuffId' = 129328 + AUTONOMY_MOD_EUROPE_WALK_BYS_BRAWL: 'CommonBuffId' = 123436 + AUTONOMY_MOD_EXERCISE: 'CommonBuffId' = 27527 + AUTONOMY_MOD_EXTRA_HOMEWORK_PRANK: 'CommonBuffId' = 36133 + AUTONOMY_MOD_FAN_STAN_CAN_TARGET_CELEBRITIES: 'CommonBuffId' = 194436 + AUTONOMY_MOD_FITNESS_MENTOR: 'CommonBuffId' = 40333 + AUTONOMY_MOD_FOREST_GHOST: 'CommonBuffId' = 108335 + AUTONOMY_MOD_FOREST_GHOST_GLOOMY: 'CommonBuffId' = 108322 + AUTONOMY_MOD_FOREST_GHOST_GOOFY: 'CommonBuffId' = 108323 + AUTONOMY_MOD_FOREST_GHOST_MEAN: 'CommonBuffId' = 108324 + AUTONOMY_MOD_FOREST_RANGER: 'CommonBuffId' = 108777 + AUTONOMY_MOD_FOREST_RANGER_VACATION_ARRIVAL: 'CommonBuffId' = 109032 + AUTONOMY_MOD_FREEGAN_ACTIVE_CAREER: 'CommonBuffId' = 238020 + AUTONOMY_MOD_FRIENDLY_SOCIALS_MORE: 'CommonBuffId' = 136764 + AUTONOMY_MOD_FUN_INCREASE: 'CommonBuffId' = 33299 + AUTONOMY_MOD_GHOST_HAUNT: 'CommonBuffId' = 102777 + AUTONOMY_MOD_GRAB_COFFEE_TEA: 'CommonBuffId' = 26249 + AUTONOMY_MOD_GRAB_COOLER_DRINK: 'CommonBuffId' = 105831 + AUTONOMY_MOD_GRAB_DESSERT: 'CommonBuffId' = 26252 + AUTONOMY_MOD_GRAB_DRINK: 'CommonBuffId' = 26247 + AUTONOMY_MOD_GRAB_FOOD: 'CommonBuffId' = 26286 + AUTONOMY_MOD_GRILL_MEALS: 'CommonBuffId' = 105828 + AUTONOMY_MOD_GYM_RELAXER: 'CommonBuffId' = 120594 + AUTONOMY_MOD_HANG_OUT_BAR: 'CommonBuffId' = 225524 + AUTONOMY_MOD_HANG_OUT_GYM: 'CommonBuffId' = 225527 + AUTONOMY_MOD_HANG_OUT_LIBRARY: 'CommonBuffId' = 225530 + AUTONOMY_MOD_HANG_OUT_MUSEUM: 'CommonBuffId' = 225532 + AUTONOMY_MOD_HANG_OUT_PARK: 'CommonBuffId' = 225534 + AUTONOMY_MOD_HANG_OUT_POOL: 'CommonBuffId' = 225535 + AUTONOMY_MOD_HIGH_SCHOOL_FILL_FOUNTAIN_PUNCH: 'CommonBuffId' = 287395 + AUTONOMY_MOD_HIGH_SCHOOL_SERVE_FOOD: 'CommonBuffId' = 290312 + AUTONOMY_MOD_HIGH_SCHOOL_TEAM_VICTORY_DANCE_CHAIN: 'CommonBuffId' = 279073 + AUTONOMY_MOD_IN_ROMANTIC_STC: 'CommonBuffId' = 101235 + AUTONOMY_MOD_ISLAND_CANOE_WALK_BY: 'CommonBuffId' = 214038 + AUTONOMY_MOD_IS_HERMIT: 'CommonBuffId' = 104054 + AUTONOMY_MOD_KEG_PARTY_FOOD: 'CommonBuffId' = 222496 + AUTONOMY_MOD_LAMPOON_HOST: 'CommonBuffId' = 202599 + AUTONOMY_MOD_LAMPOON_PARTY_GUEST_OF_HONOR: 'CommonBuffId' = 200817 + AUTONOMY_MOD_LANDLORD_FIX_THINGS: 'CommonBuffId' = 135330 + AUTONOMY_MOD_LEAVE: 'CommonBuffId' = 156116 + AUTONOMY_MOD_LESS_FUN: 'CommonBuffId' = 96800 + AUTONOMY_MOD_LISTEN_TO_MUSIC: 'CommonBuffId' = 34445 + AUTONOMY_MOD_LISTEN_TO_SPOOKY: 'CommonBuffId' = 126270 + AUTONOMY_MOD_LOCKED_MOTIVES: 'CommonBuffId' = 228865 + AUTONOMY_MOD_LOUNGE_EVENT_ACCEPT_AWARD: 'CommonBuffId' = 192739 + AUTONOMY_MOD_LOUNGE_EVENT_AWARD_ATTENDEE_WATCH: 'CommonBuffId' = 200984 + AUTONOMY_MOD_LOUNGE_EVENT_AWARD_DRINKS: 'CommonBuffId' = 193066 + AUTONOMY_MOD_LOUNGE_EVENT_AWARD_HOST: 'CommonBuffId' = 192696 + AUTONOMY_MOD_LOUNGE_EVENT_NO_MORE_AWARD: 'CommonBuffId' = 192746 + AUTONOMY_MOD_LOUNGE_EVENT_OPEN_MIC: 'CommonBuffId' = 192697 + AUTONOMY_MOD_LOUNGE_EVENT_OPEN_MIC_PLAYER: 'CommonBuffId' = 197905 + AUTONOMY_MOD_LOUNGE_EVENT_OPEN_MIC_PLAYER_EVENT: 'CommonBuffId' = 197909 + AUTONOMY_MOD_LOUNGE_EVENT_OPEN_MIC_TURN: 'CommonBuffId' = 193096 + AUTONOMY_MOD_LOUNGE_EVENT_OPEN_MIC_WATCH: 'CommonBuffId' = 201425 + AUTONOMY_MOD_LOWER_FAT_GAIN: 'CommonBuffId' = 137029 + AUTONOMY_MOD_MAGIC_DUELIST_CHALLENGE: 'CommonBuffId' = 218445 + AUTONOMY_MOD_MAGIC_DUELIST_DUEL: 'CommonBuffId' = 216813 + AUTONOMY_MOD_MAGIC_DUELIST_GO_TO_DUEL: 'CommonBuffId' = 216882 + AUTONOMY_MOD_MAKE_BIRTHDAY_CAKE: 'CommonBuffId' = 32210 + AUTONOMY_MOD_MAKE_BLACK_AND_WHITE_PARTY_DRINKS: 'CommonBuffId' = 37400 + AUTONOMY_MOD_MAKE_BLACK_AND_WHITE_PARTY_FOOD: 'CommonBuffId' = 37402 + AUTONOMY_MOD_MAKE_COFFEE_TEA: 'CommonBuffId' = 26289 + AUTONOMY_MOD_MAKE_COSTUME_PARTY_DRINKS: 'CommonBuffId' = 37399 + AUTONOMY_MOD_MAKE_COSTUME_PARTY_FOOD: 'CommonBuffId' = 37401 + AUTONOMY_MOD_MAKE_DESSERT: 'CommonBuffId' = 26287 + AUTONOMY_MOD_MAKE_DRINK: 'CommonBuffId' = 26278 + AUTONOMY_MOD_MAKE_GROUP_MEAL: 'CommonBuffId' = 26280 + AUTONOMY_MOD_MAKE_GROUP_MEAL_VEGETARIAN: 'CommonBuffId' = 152515 + AUTONOMY_MOD_MAKE_ONE_DESSERT: 'CommonBuffId' = 34116 + AUTONOMY_MOD_MAKE_ONE_GROUP_MEAL: 'CommonBuffId' = 34125 + AUTONOMY_MOD_MAKE_SPOOKY_FOOD: 'CommonBuffId' = 126094 + AUTONOMY_MOD_MARKET_STALLS_CUSTOMER: 'CommonBuffId' = 181131 + AUTONOMY_MOD_MARKET_STALLS_STOP_SOCIAL: 'CommonBuffId' = 143393 + AUTONOMY_MOD_MARKET_STALLS_TEND_STALL: 'CommonBuffId' = 132895 + AUTONOMY_MOD_MARKET_STALL_BROWSE: 'CommonBuffId' = 132958 + AUTONOMY_MOD_MARKET_STALL_HIRED_NPC_OPEN: 'CommonBuffId' = 151767 + AUTONOMY_MOD_MARKET_STALL_MAGIC_ADD_SPECTRAL_LOOK: 'CommonBuffId' = 217028 + AUTONOMY_MOD_MARKET_STALL_VENDOR_NPC: 'CommonBuffId' = 136193 + AUTONOMY_MOD_MARKET_STALL_VENDOR_NPC_COFFEE_CART: 'CommonBuffId' = 226097 + AUTONOMY_MOD_MEAN_SOCIALS_MORE: 'CommonBuffId' = 137512 + AUTONOMY_MOD_MICROPHONE_PERFORM_STAND_UP: 'CommonBuffId' = 32464 + AUTONOMY_MOD_MIRROR: 'CommonBuffId' = 128308 + AUTONOMY_MOD_MOLD_CLAY_BOB: 'CommonBuffId' = 148099 + AUTONOMY_MOD_MOVE_IN: 'CommonBuffId' = 310404 + AUTONOMY_MOD_MURAL_PAINT: 'CommonBuffId' = 146653 + AUTONOMY_MOD_NIGHTCLUB_DANCER: 'CommonBuffId' = 123546 + AUTONOMY_MOD_NO_AUTONOMOUS_CELL_PHONE: 'CommonBuffId' = 276966 + AUTONOMY_MOD_NO_CLEANING_DESKS: 'CommonBuffId' = 304086 + AUTONOMY_MOD_NO_CLEAN_FLOOR_BASIC: 'CommonBuffId' = 172992 + AUTONOMY_MOD_NO_CLEAN_FLOOR_EXTENSIVE: 'CommonBuffId' = 172998 + AUTONOMY_MOD_NO_SWIMMING: 'CommonBuffId' = 215379 + AUTONOMY_MOD_NO_TOILET_PRANK: 'CommonBuffId' = 304291 + AUTONOMY_MOD_OCEAN_ACTIVITY_COOLDOWN: 'CommonBuffId' = 215134 + AUTONOMY_MOD_OPEN_PRESENTS: 'CommonBuffId' = 190997 + AUTONOMY_MOD_OPEN_STREET_WORKOUT: 'CommonBuffId' = 40384 + AUTONOMY_MOD_OPEN_STREET_WORKOUT_DONE: 'CommonBuffId' = 40406 + AUTONOMY_MOD_ORDER_DRINK: 'CommonBuffId' = 27030 + AUTONOMY_MOD_ORDER_DRINK_SMALL: 'CommonBuffId' = 115739 + AUTONOMY_MOD_ORDER_FAVORITE_DRINK: 'CommonBuffId' = 123905 + AUTONOMY_MOD_PAIRED_DANCING_STEREO: 'CommonBuffId' = 303076 + AUTONOMY_MOD_PATIENT_AWAY_EVENT_COLLAPSED: 'CommonBuffId' = 114329 + AUTONOMY_MOD_PATIENT_COLLAPSE: 'CommonBuffId' = 113742 + AUTONOMY_MOD_PATIENT_PREGNANT_WAITING: 'CommonBuffId' = 114357 + AUTONOMY_MOD_PATIENT_PREGNANT_WALK_IN: 'CommonBuffId' = 114318 + AUTONOMY_MOD_PATIENT_WALK_INSIDE: 'CommonBuffId' = 113509 + AUTONOMY_MOD_PET_ADOPTION_ARRIVAL: 'CommonBuffId' = 170282 + AUTONOMY_MOD_PET_ADOPTION_OFFICER_DESTROY_CRATE: 'CommonBuffId' = 169596 + AUTONOMY_MOD_PET_ADOPTION_PETS_DESPAWN: 'CommonBuffId' = 169557 + AUTONOMY_MOD_PET_WALK: 'CommonBuffId' = 168030 + AUTONOMY_MOD_PET_WORLD_CAT_FISHER: 'CommonBuffId' = 164413 + AUTONOMY_MOD_PET_WORLD_CAT_GHOST: 'CommonBuffId' = 164414 + AUTONOMY_MOD_PET_WORLD_CAT_IN_HEAT: 'CommonBuffId' = 164393 + AUTONOMY_MOD_PET_WORLD_CAT_WANDERER: 'CommonBuffId' = 164412 + AUTONOMY_MOD_PET_WORLD_DOG_DOG_WALKER: 'CommonBuffId' = 168314 + AUTONOMY_MOD_PET_WORLD_DOG_GHOST: 'CommonBuffId' = 164415 + AUTONOMY_MOD_PET_WORLD_DOG_IN_HEAT: 'CommonBuffId' = 164411 + AUTONOMY_MOD_PET_WORLD_DOG_WANDERER: 'CommonBuffId' = 164392 + AUTONOMY_MOD_PET_WORLD_SIM_DOG_WALKER: 'CommonBuffId' = 168182 + AUTONOMY_MOD_PLAY_CHESS: 'CommonBuffId' = 27472 + AUTONOMY_MOD_PLAY_CHILDREN_INDOOR_OBJECTS: 'CommonBuffId' = 27511 + AUTONOMY_MOD_PLAY_CHILDREN_OUTDOOR_OBJECTS: 'CommonBuffId' = 27509 + AUTONOMY_MOD_PLAY_GAMES: 'CommonBuffId' = 34450 + AUTONOMY_MOD_PLAY_GAMING_RIG: 'CommonBuffId' = 27528 + AUTONOMY_MOD_PLAY_GUITAR: 'CommonBuffId' = 123630 + AUTONOMY_MOD_PLAY_MUSICAL_INSTRUMENTS: 'CommonBuffId' = 32463 + AUTONOMY_MOD_PLAY_ORGAN: 'CommonBuffId' = 155977 + AUTONOMY_MOD_PLAY_PIANO: 'CommonBuffId' = 303754 + AUTONOMY_MOD_PLAY_PIANO_BW_PARTY: 'CommonBuffId' = 37259 + AUTONOMY_MOD_PLAY_VIOLIN: 'CommonBuffId' = 123677 + AUTONOMY_MOD_POSTURE_BE_CARRIED: 'CommonBuffId' = 313136 + AUTONOMY_MOD_POSTURE_BE_CARRIED_BACK: 'CommonBuffId' = 313137 + AUTONOMY_MOD_POSTURE_CRIB: 'CommonBuffId' = 280281 + AUTONOMY_MOD_POSTURE_HIGH_CHAIR: 'CommonBuffId' = 280280 + AUTONOMY_MOD_POSTURE_LAY_ON_BACK: 'CommonBuffId' = 313135 + AUTONOMY_MOD_POSTURE_PLAY_MAT: 'CommonBuffId' = 280282 + AUTONOMY_MOD_PRACTICE_SPELLCASTING_COOLDOWN: 'CommonBuffId' = 220137 + AUTONOMY_MOD_PUT_AWAY_BOOKS: 'CommonBuffId' = 40090 + AUTONOMY_MOD_QUICK_SOCIAL_LESS: 'CommonBuffId' = 300711 + AUTONOMY_MOD_RANCH_WORLD_HORSE_AND_RIDER_HORSE: 'CommonBuffId' = 328816 + AUTONOMY_MOD_RANCH_WORLD_HORSE_AND_RIDER_SIM: 'CommonBuffId' = 328755 + AUTONOMY_MOD_RANGER_STATION: 'CommonBuffId' = 106122 + AUTONOMY_MOD_READ_BOOKS: 'CommonBuffId' = 27575 + AUTONOMY_MOD_RECREATION_TABLE_CLEANUP: 'CommonBuffId' = 317529 + AUTONOMY_MOD_RECREATION_TABLE_PLAY_SIMBLES: 'CommonBuffId' = 317528 + AUTONOMY_MOD_REPO_IDLE: 'CommonBuffId' = 229923 + AUTONOMY_MOD_RETAIL_BROWSE: 'CommonBuffId' = 109453 + AUTONOMY_MOD_RETAIL_BUY: 'CommonBuffId' = 109789 + AUTONOMY_MOD_RETAIL_EMPLOYEE_CLEAN: 'CommonBuffId' = 109776 + AUTONOMY_MOD_RETAIL_EMPLOYEE_CLOCK_IN: 'CommonBuffId' = 109787 + AUTONOMY_MOD_RETAIL_EMPLOYEE_ONLY_SCORE_STATIC_COMMODITIES: 'CommonBuffId' = 118378 + AUTONOMY_MOD_RETAIL_EMPLOYEE_RESTOCK: 'CommonBuffId' = 109779 + AUTONOMY_MOD_RETAIL_EMPLOYEE_RING_UP_CUSTOMERS: 'CommonBuffId' = 114894 + AUTONOMY_MOD_RETAIL_EMPLOYEE_SLACK_OFF: 'CommonBuffId' = 112297 + AUTONOMY_MOD_RETAIL_EMPLOYEE_SOCIALIZE: 'CommonBuffId' = 109780 + AUTONOMY_MOD_RETAIL_EMPLOYEE_SOCIALIZE_BACKUP: 'CommonBuffId' = 116088 + AUTONOMY_MOD_RETAIL_EMPLOYEE_STAND_NEAR_REGISTER: 'CommonBuffId' = 118376 + AUTONOMY_MOD_RETAIL_LOITER: 'CommonBuffId' = 116064 + AUTONOMY_MOD_ROMANCE_SOCIALS_MORE: 'CommonBuffId' = 136717 + AUTONOMY_MOD_SCARECROW: 'CommonBuffId' = 190059 + AUTONOMY_MOD_SCARECROW_ALWAYS_CONSIDER_SCARECROW_OBJECT: 'CommonBuffId' = 191325 + AUTONOMY_MOD_SCARE_SPOOKY: 'CommonBuffId' = 128311 + AUTONOMY_MOD_SCRAP_DRAWING: 'CommonBuffId' = 144974 + AUTONOMY_MOD_SCRAP_PAINTING: 'CommonBuffId' = 208152 + AUTONOMY_MOD_SCRAP_WOODWORK: 'CommonBuffId' = 145090 + AUTONOMY_MOD_SEASONAL_LEAVES: 'CommonBuffId' = 181071 + AUTONOMY_MOD_SEASONAL_SKATER: 'CommonBuffId' = 181070 + AUTONOMY_MOD_SEASONAL_SNOW: 'CommonBuffId' = 181491 + AUTONOMY_MOD_SECRET_LAB_VENUE: 'CommonBuffId' = 203426 + AUTONOMY_MOD_SHOWER: 'CommonBuffId' = 120583 + AUTONOMY_MOD_SIT: 'CommonBuffId' = 76180 + AUTONOMY_MOD_SKATING_RINK_ROUTINE_WATCH: 'CommonBuffId' = 180438 + AUTONOMY_MOD_SOCIALIZE_AS_BACKUP: 'CommonBuffId' = 96801 + AUTONOMY_MOD_SOCIALIZE_GREETINGS: 'CommonBuffId' = 115572 + AUTONOMY_MOD_SOCIALIZE_NOW: 'CommonBuffId' = 180880 + AUTONOMY_MOD_SOCIAL_LESS: 'CommonBuffId' = 123148 + AUTONOMY_MOD_SOCIAL_MORE: 'CommonBuffId' = 33931 + AUTONOMY_MOD_SOCIAL_MORE_ANNOYING: 'CommonBuffId' = 122338 + AUTONOMY_MOD_SOCIAL_MORE_DATE: 'CommonBuffId' = 118567 + AUTONOMY_MOD_SOCIAL_NONE: 'CommonBuffId' = 240036 + AUTONOMY_MOD_SPA_DO_STUFF: 'CommonBuffId' = 119014 + AUTONOMY_MOD_SPA_GUEST_ALL: 'CommonBuffId' = 273418 + AUTONOMY_MOD_SPA_GUEST_ARRIVAL: 'CommonBuffId' = 119688 + AUTONOMY_MOD_SPA_GUEST_DELAY_CHANGE_INTO_ROBE: 'CommonBuffId' = 273424 + AUTONOMY_MOD_SPA_GUEST_DELAY_CHANGE_INTO_ROBE_TIMED: 'CommonBuffId' = 273405 + AUTONOMY_MOD_SPA_GUEST_LEAVE_VENUE: 'CommonBuffId' = 119689 + AUTONOMY_MOD_SPA_MASSAGE_THERAPIST_ACTIVE: 'CommonBuffId' = 119015 + AUTONOMY_MOD_SPA_MASSAGE_THERAPIST_BORED: 'CommonBuffId' = 119019 + AUTONOMY_MOD_SPA_REFLEXOLOGIST_ACTIVE: 'CommonBuffId' = 119016 + AUTONOMY_MOD_SPA_REFLEXOLOGIST_BORED: 'CommonBuffId' = 119017 + AUTONOMY_MOD_SPA_YOGA_INSTRUCTOR_ARRIVAL: 'CommonBuffId' = 120241 + AUTONOMY_MOD_SPA_YOGA_INSTRUCTOR_BORED: 'CommonBuffId' = 119018 + AUTONOMY_MOD_SPLASH_PAD: 'CommonBuffId' = 303708 + AUTONOMY_MOD_STRANGER_VILLE_CONSPIRACIST: 'CommonBuffId' = 203333 + AUTONOMY_MOD_STRANGER_VILLE_OGA: 'CommonBuffId' = 203332 + AUTONOMY_MOD_STUDENT_COMMONS_EXAM_CRAM_PLAYER: 'CommonBuffId' = 222197 + AUTONOMY_MOD_STUDENT_COMMONS_GET_REFRESHMENTS: 'CommonBuffId' = 230207 + AUTONOMY_MOD_STUDENT_COMMONS_SLACKING: 'CommonBuffId' = 222359 + AUTONOMY_MOD_STUDENT_COMMONS_SLEEP_MORE: 'CommonBuffId' = 230208 + AUTONOMY_MOD_STUDENT_COMMONS_SOCIAL: 'CommonBuffId' = 222358 + AUTONOMY_MOD_STUDENT_COMMONS_STUDYING: 'CommonBuffId' = 222185 + AUTONOMY_MOD_STUDY_HOMEWORK: 'CommonBuffId' = 27682 + AUTONOMY_MOD_SUMMIT_BUNNY_SLOPE: 'CommonBuffId' = 247314 + AUTONOMY_MOD_SUMMIT_CLIMBER: 'CommonBuffId' = 247358 + AUTONOMY_MOD_SUMMIT_SLOPE: 'CommonBuffId' = 247313 + AUTONOMY_MOD_SUMMIT_SOLO_HIKER: 'CommonBuffId' = 247360 + AUTONOMY_MOD_SUMMIT_SOLO_SLEDDER: 'CommonBuffId' = 247359 + AUTONOMY_MOD_SUMMIT_TOURIST: 'CommonBuffId' = 253863 + AUTONOMY_MOD_SUMMONED_GHOST: 'CommonBuffId' = 108712 + AUTONOMY_MOD_SUMMON_GHOST_FAIL: 'CommonBuffId' = 215673 + AUTONOMY_MOD_SUPPRESS_PRE_ROLL_AUTONOMY: 'CommonBuffId' = 115876 + AUTONOMY_MOD_SWIMMER: 'CommonBuffId' = 124810 + AUTONOMY_MOD_TEND_BAR: 'CommonBuffId' = 27056 + AUTONOMY_MOD_TEND_BAR_CASUAL: 'CommonBuffId' = 203483 + AUTONOMY_MOD_THANK_HOST_FOR_INVITE: 'CommonBuffId' = 26284 + AUTONOMY_MOD_THRIFT_STORE_BROWSING: 'CommonBuffId' = 280735 + AUTONOMY_MOD_THRIFT_STORE_BUBBLE_TEA_DRINKING: 'CommonBuffId' = 280819 + AUTONOMY_MOD_THRIFT_STORE_COMEDY_PERFORMING: 'CommonBuffId' = 280900 + AUTONOMY_MOD_THRIFT_STORE_COMEDY_WAITING: 'CommonBuffId' = 280899 + AUTONOMY_MOD_THRIFT_STORE_FASHION_SHOW_OFF: 'CommonBuffId' = 280998 + AUTONOMY_MOD_THRIFT_STORE_ORDER_FOOD: 'CommonBuffId' = 294686 + AUTONOMY_MOD_THRIFT_STORE_PLAYER: 'CommonBuffId' = 280787 + AUTONOMY_MOD_THRIFT_STORE_POETRY_PERFORMING: 'CommonBuffId' = 280901 + AUTONOMY_MOD_THRIFT_STORE_POETRY_WAITING: 'CommonBuffId' = 280902 + AUTONOMY_MOD_TIDY: 'CommonBuffId' = 304708 + AUTONOMY_MOD_TOP_CAKE: 'CommonBuffId' = 31037 + AUTONOMY_MOD_TOWN_VISITOR: 'CommonBuffId' = 210422 + AUTONOMY_MOD_TRAIT_MELT_MASTER_EAT_GRILLED_CHEESE: 'CommonBuffId' = 132358 + AUTONOMY_MOD_TRAIT_VEGETARIAN_EAT_VEGETARIAN_FOOD: 'CommonBuffId' = 133129 + AUTONOMY_MOD_TRASH_CHUTE_THROW_AWAY: 'CommonBuffId' = 151163 + AUTONOMY_MOD_TRIGGER_HOUSE_CALL: 'CommonBuffId' = 114195 + AUTONOMY_MOD_TRIGGER_OUTBREAK: 'CommonBuffId' = 114270 + AUTONOMY_MOD_TUTOR: 'CommonBuffId' = 27653 + AUTONOMY_MOD_UNICORN_HORN: 'CommonBuffId' = 333940 + AUTONOMY_MOD_UNICORN_HORN_C: 'CommonBuffId' = 334258 + AUTONOMY_MOD_UNIVERSITY_WORLD_CONSTRAIN_TO_ATTRACTOR: 'CommonBuffId' = 222941 + AUTONOMY_MOD_UNIVERSITY_WORLD_STUDENT: 'CommonBuffId' = 222940 + AUTONOMY_MOD_USE_BONFIRE: 'CommonBuffId' = 126414 + AUTONOMY_MOD_USE_CAMPFIRE: 'CommonBuffId' = 105897 + AUTONOMY_MOD_USE_COMPUTER: 'CommonBuffId' = 27766 + AUTONOMY_MOD_USE_OUTDOOR_OBJECTS_BUSH: 'CommonBuffId' = 126337 + AUTONOMY_MOD_USE_OUTDOOR_OBJECTS_FISHING_LOCATION: 'CommonBuffId' = 76557 + AUTONOMY_MOD_USE_OUTDOOR_OBJECTS_GARDEN: 'CommonBuffId' = 38934 + AUTONOMY_MOD_USE_OUTDOOR_OBJECTS_HERBALIST: 'CommonBuffId' = 101858 + AUTONOMY_MOD_USE_OUTDOOR_OBJECTS_RESTROOM: 'CommonBuffId' = 40784 + AUTONOMY_MOD_USE_OUTDOOR_OBJECTS_RESTROOM_SHOWER: 'CommonBuffId' = 107843 + AUTONOMY_MOD_USE_PORTABLE_COMPUTER: 'CommonBuffId' = 225754 + AUTONOMY_MOD_USE_TABLET: 'CommonBuffId' = 27578 + AUTONOMY_MOD_VENUE_BEACH_BEACH_COMBER: 'CommonBuffId' = 207806 + AUTONOMY_MOD_VENUE_BEACH_LIFE_GUARD: 'CommonBuffId' = 207807 + AUTONOMY_MOD_VENUE_BEACH_MERFOLK: 'CommonBuffId' = 207808 + AUTONOMY_MOD_VENUE_BEACH_MERFOLK_UNDISCOVERED: 'CommonBuffId' = 209204 + AUTONOMY_MOD_VENUE_BEACH_SAND_ARTIST: 'CommonBuffId' = 207810 + AUTONOMY_MOD_VENUE_BEACH_SWIMMER: 'CommonBuffId' = 205388 + AUTONOMY_MOD_VENUE_BEACH_TANNER: 'CommonBuffId' = 207811 + AUTONOMY_MOD_VENUE_BEACH_WATER_ENTHUSIAST: 'CommonBuffId' = 207815 + AUTONOMY_MOD_VIEW_PAINTING: 'CommonBuffId' = 28372 + AUTONOMY_MOD_VIP_ROPE_ATTEMPT_TO_ENTER: 'CommonBuffId' = 199880 + AUTONOMY_MOD_VIP_ROPE_BOUNCER_ARRIVAL: 'CommonBuffId' = 191978 + AUTONOMY_MOD_VIP_ROPE_BOUNCER_IDLE: 'CommonBuffId' = 195307 + AUTONOMY_MOD_WAITING_FOR_CLASS: 'CommonBuffId' = 229426 + AUTONOMY_MOD_WATCH_CEREMONY: 'CommonBuffId' = 31019 + AUTONOMY_MOD_WATCH_KARAOKE: 'CommonBuffId' = 154186 + AUTONOMY_MOD_WATCH_STAND_UP: 'CommonBuffId' = 34443 + AUTONOMY_MOD_WATCH_TV: 'CommonBuffId' = 27033 + AUTONOMY_MOD_WATER_SCOOTER_WALK_BY: 'CommonBuffId' = 209526 + AUTONOMY_MOD_WELLNESS_ACTIVITY_PROMOTED: 'CommonBuffId' = 272558 + AUTONOMY_MOD_WELLNESS_ACTIVITY_PROMOTED_TIMED: 'CommonBuffId' = 272569 + AUTONOMY_MOD_WORKOUT: 'CommonBuffId' = 97595 + AUTO_SMOKE: 'CommonBuffId' = 97496 + AXOLOTL_BREED_COOLDOWN_HIDDEN: 'CommonBuffId' = 378235 + AXOLOTL_RELEASE_INSPIRED: 'CommonBuffId' = 380475 + A_GREAT_SCARE: 'CommonBuffId' = 103141 + A_GREAT_SCARE_GREAT_STORYTELLER: 'CommonBuffId' = 109738 + A_NEW_BEGINNING: 'CommonBuffId' = 100146 + A_SILLY_SCARE: 'CommonBuffId' = 108023 + A_SILLY_SCARE_GREAT_STORYTELLER: 'CommonBuffId' = 109740 + BABY_BIRTH_PARTNER: 'CommonBuffId' = 115502 + BABY_FEED_PREFERENCE_BODY: 'CommonBuffId' = 334605 + BABY_FEED_PREFERENCE_BOTTLE: 'CommonBuffId' = 334604 + BABY_SHOWER_ATTEND_SHOWER: 'CommonBuffId' = 305762 + BABY_SHOWER_BAD_BABY_NAME: 'CommonBuffId' = 305696 + BABY_SHOWER_GIFT_COOLDOWN: 'CommonBuffId' = 310458 + BABY_SHOWER_GOOD_BABY_NAME: 'CommonBuffId' = 305695 + BABY_SHOWER_TOO_MUCH_BABY: 'CommonBuffId' = 305763 + BABY_SHOWER_UNWANTED_ADVICE: 'CommonBuffId' = 305764 + BAD_MANNERS_VISITING: 'CommonBuffId' = 164675 + BAIT_CRYSTAL: 'CommonBuffId' = 98249 + BAIT_ELEMENT: 'CommonBuffId' = 98248 + BAIT_FRESH_FLOWER: 'CommonBuffId' = 76073 + BAIT_FRESH_FRUIT: 'CommonBuffId' = 76072 + BAIT_FROG: 'CommonBuffId' = 75548 + BAIT_GROUP_ORGANIC: 'CommonBuffId' = 75549 + BAIT_GROUP_TRASH: 'CommonBuffId' = 76076 + BAIT_MEDIUM_FISH: 'CommonBuffId' = 76071 + BAIT_METAL: 'CommonBuffId' = 98250 + BAIT_PLASMA_FRUIT: 'CommonBuffId' = 155037 + BAIT_ROTTEN_FRUIT: 'CommonBuffId' = 76075 + BAIT_SMALL_FISH: 'CommonBuffId' = 75556 + BATTLE_MONSTERS_HIDDEN_ATTACK_MISS: 'CommonBuffId' = 135448 + BATTLE_MONSTERS_HIDDEN_CHALLENGER: 'CommonBuffId' = 138030 + BATTLE_MONSTERS_HIDDEN_ELEMENTS_EARTH: 'CommonBuffId' = 135617 + BATTLE_MONSTERS_HIDDEN_ELEMENTS_FIRE: 'CommonBuffId' = 135614 + BATTLE_MONSTERS_HIDDEN_ELEMENTS_VOID: 'CommonBuffId' = 135616 + BATTLE_MONSTERS_HIDDEN_ELEMENTS_WATER: 'CommonBuffId' = 135615 + BATTLE_MONSTERS_HIDDEN_ELEMENTS_WIND: 'CommonBuffId' = 135618 + BATTLE_MONSTERS_HIDDEN_LEVEL_1: 'CommonBuffId' = 135605 + BATTLE_MONSTERS_HIDDEN_LEVEL_10: 'CommonBuffId' = 135604 + BATTLE_MONSTERS_HIDDEN_LEVEL_2: 'CommonBuffId' = 135606 + BATTLE_MONSTERS_HIDDEN_LEVEL_3: 'CommonBuffId' = 135607 + BATTLE_MONSTERS_HIDDEN_LEVEL_4: 'CommonBuffId' = 135608 + BATTLE_MONSTERS_HIDDEN_LEVEL_5: 'CommonBuffId' = 135609 + BATTLE_MONSTERS_HIDDEN_LEVEL_6: 'CommonBuffId' = 135610 + BATTLE_MONSTERS_HIDDEN_LEVEL_7: 'CommonBuffId' = 135611 + BATTLE_MONSTERS_HIDDEN_LEVEL_8: 'CommonBuffId' = 135612 + BATTLE_MONSTERS_HIDDEN_LEVEL_9: 'CommonBuffId' = 135613 + BATTLE_MONSTERS_HIDDEN_REACTIONS_CHEER: 'CommonBuffId' = 137733 + BATTLE_MONSTERS_HIDDEN_REACTIONS_VICTORY_CHEER: 'CommonBuffId' = 139217 + BATTLE_MONSTERS_HIDDEN_TRASH_CAN_COOLDOWN: 'CommonBuffId' = 134201 + BATUU_AGNON_FIRST_ORDER_AUTHORITY: 'CommonBuffId' = 238996 + BATUU_AGNON_IDENTIFIER: 'CommonBuffId' = 238987 + BATUU_ARREST_BUSTED: 'CommonBuffId' = 242891 + BATUU_ARREST_BUSTED_ANGRY: 'CommonBuffId' = 242997 + BATUU_ARREST_NOT_BUSTED: 'CommonBuffId' = 242892 + BATUU_ARREST_ROLE_DESPAWN_PRISONER: 'CommonBuffId' = 245251 + BATUU_ARREST_ROLE_ESCORT_ESCORTER: 'CommonBuffId' = 245248 + BATUU_ASPIRATIONS_BOUGHT_DROID_CHECK: 'CommonBuffId' = 245341 + BATUU_ASPIRATIONS_EXTOL_MIGHT_FAILURE: 'CommonBuffId' = 245470 + BATUU_ASPIRATIONS_EXTOL_MIGHT_OF_FIRST_ORDER: 'CommonBuffId' = 238933 + BATUU_ASPIRATIONS_HEROIC_PRESENCE_ACTOR: 'CommonBuffId' = 238938 + BATUU_ASPIRATIONS_HEROIC_PRESENCE_TARGET: 'CommonBuffId' = 238658 + BATUU_ASPIRATIONS_PREPARED_VOYAGER: 'CommonBuffId' = 238660 + BATUU_ASPIRATIONS_SLEIGHT_OF_HAND: 'CommonBuffId' = 238661 + BATUU_BATUUAN_MISSION_GIVER: 'CommonBuffId' = 242819 + BATUU_BATUUAN_MISSION_SCOUNDREL: 'CommonBuffId' = 244393 + BATUU_CHECK_ID_BYSTANDER_CANCEL_FOR_BRIBE: 'CommonBuffId' = 242478 + BATUU_CHECK_ID_BYSTANDER_CANCEL_FOR_CONVINCE: 'CommonBuffId' = 242479 + BATUU_CHECK_ID_CANCEL_FOR_BRIBE: 'CommonBuffId' = 242429 + BATUU_CHECK_ID_CANCEL_FOR_CONVINCE: 'CommonBuffId' = 242470 + BATUU_CHECK_ID_ORIGINAL_TARGET: 'CommonBuffId' = 242520 + BATUU_CHECK_ID_TARGET_COOLDOWN_HIDDEN: 'CommonBuffId' = 231390 + BATUU_CHECK_ID_TARGET_COOLDOWN_HIDDEN_NPC_ACTOR: 'CommonBuffId' = 250150 + BATUU_CHECK_POINT_DOOR_FIRST_ORDER: 'CommonBuffId' = 231456 + BATUU_CHECK_POINT_DOOR_RESISTANCE: 'CommonBuffId' = 231457 + BATUU_CONTROL_PANEL_ALARM_RAISED_FIRST_ORDER: 'CommonBuffId' = 249772 + BATUU_CONTROL_PANEL_ALARM_RAISED_RESISTANCE: 'CommonBuffId' = 249780 + BATUU_CONTROL_PANEL_ROOKIE_MISTAKE_FIRST_ORDER_SYSTEM: 'CommonBuffId' = 237376 + BATUU_CONTROL_PANEL_ROOKIE_MISTAKE_FIRST_ORDER_SYSTEM_ANGRY: 'CommonBuffId' = 237377 + BATUU_CONTROL_PANEL_ROOKIE_MISTAKE_RESISTANCE_SYSTEM_FIRST_ORDER: 'CommonBuffId' = 237381 + BATUU_CONTROL_PANEL_ROOKIE_MISTAKE_RESISTANCE_SYSTEM_FIRST_ORDER_ANGRY: 'CommonBuffId' = 237382 + BATUU_CONTROL_PANEL_ROOKIE_MISTAKE_RESISTANCE_SYSTEM_SCOUNDREL: 'CommonBuffId' = 237383 + BATUU_CONTROL_PANEL_ROOKIE_MISTAKE_RESISTANCE_SYSTEM_SCOUNDREL_ANGRY: 'CommonBuffId' = 237384 + BATUU_CONTROL_PANEL_UNDER_WATCH_FIRST_ORDER: 'CommonBuffId' = 231386 + BATUU_CONTROL_PANEL_UNDER_WATCH_RESISTANCE: 'CommonBuffId' = 231387 + BATUU_DROID_AURAL_SENSOR: 'CommonBuffId' = 245252 + BATUU_DROID_CANCEL_FOLLOW: 'CommonBuffId' = 237495 + BATUU_DROID_CANCEL_GET_ZAPPED: 'CommonBuffId' = 245114 + BATUU_DROID_DISCUSSED_SCHEMATICS: 'CommonBuffId' = 242906 + BATUU_DROID_DISTRACTED: 'CommonBuffId' = 246006 + BATUU_DROID_DISTRACTED_SWIPE_COOLDOWN: 'CommonBuffId' = 248822 + BATUU_DROID_DISTRACTED_SWIPE_FAIL: 'CommonBuffId' = 242348 + BATUU_DROID_DISTRACTED_SWIPE_SUCCESS: 'CommonBuffId' = 242347 + BATUU_DROID_SHOCK_DAZED: 'CommonBuffId' = 242971 + BATUU_FIRST_ORDER_MISSION_GIVER: 'CommonBuffId' = 233163 + BATUU_FIRST_ORDER_STORMTROOPER_HIGH_ALERT: 'CommonBuffId' = 231374 + BATUU_FIRST_ORDER_STORMTROOPER_HIGH_ALERT_RS6: 'CommonBuffId' = 244423 + BATUU_FIRST_ORDER_STORMTROOPER_HIGH_ALERT_TIMED: 'CommonBuffId' = 242911 + BATUU_HOLOCRON_JEDI: 'CommonBuffId' = 233179 + BATUU_HOLOCRON_SITH: 'CommonBuffId' = 233180 + BATUU_HONDO_GOOD_BUSINESS: 'CommonBuffId' = 238787 + BATUU_HONDO_IDENTIFIER: 'CommonBuffId' = 233796 + BATUU_HONDO_STEAL_CAN_ASK: 'CommonBuffId' = 233800 + BATUU_HONDO_STEAL_COOLDOWN: 'CommonBuffId' = 233798 + BATUU_INSPECTION_CLOSE_SHAVE: 'CommonBuffId' = 242890 + BATUU_INSPECTION_IN_FIGHT: 'CommonBuffId' = 250826 + BATUU_INSPECTION_ROLE_FIGHT_INSPECTOR: 'CommonBuffId' = 245311 + BATUU_INVITED_NPC: 'CommonBuffId' = 251642 + BATUU_KYLO_FEAR_THE_DARK_SIDE: 'CommonBuffId' = 238995 + BATUU_KYLO_FIRST_ORDER_MIGHT_NEGATIVE: 'CommonBuffId' = 238994 + BATUU_KYLO_FIRST_ORDER_MIGHT_POSITIVE: 'CommonBuffId' = 238993 + BATUU_KYLO_IDENTIFIER: 'CommonBuffId' = 238988 + BATUU_LIGHTSABER_REFINED_WEAPON: 'CommonBuffId' = 232333 + BATUU_LUCK_OF_BATUU: 'CommonBuffId' = 247412 + BATUU_MISSIONS_ASPIRATIONS_MISSION_COMPLETE: 'CommonBuffId' = 243193 + BATUU_MISSIONS_CONVINCE_TO_BET_VALUABLE_FAIL_SR9: 'CommonBuffId' = 246514 + BATUU_MISSIONS_DEFECTOR_WRONG_PERSON: 'CommonBuffId' = 243579 + BATUU_MISSIONS_DELIVERED_SPY_SUCCESS: 'CommonBuffId' = 242241 + BATUU_MISSIONS_EXIT_WAIT: 'CommonBuffId' = 242406 + BATUU_MISSIONS_FR13_INTIMIDATE_COOLDOWN: 'CommonBuffId' = 251739 + BATUU_MISSIONS_FR13_PATROL_END: 'CommonBuffId' = 245515 + BATUU_MISSIONS_FS1_RECENTLY_HEARD_PROPAGANDA: 'CommonBuffId' = 248364 + BATUU_MISSIONS_FS4_ASK_ABOUT_CRIMINAL_COOLDOWN: 'CommonBuffId' = 245754 + BATUU_MISSIONS_FS6_CHARM_COOLDOWN: 'CommonBuffId' = 245587 + BATUU_MISSIONS_FS6_INTIMIDATE_COOLDOWN: 'CommonBuffId' = 246641 + BATUU_MISSIONS_FS8_RECENTLY_EAVESDROPPED: 'CommonBuffId' = 249194 + BATUU_MISSIONS_FS8_RECENTLY_RECRUITED_OR_PAID: 'CommonBuffId' = 249193 + BATUU_MISSIONS_FS8_REY_STOP_AND_GO_MIND_ERASE: 'CommonBuffId' = 250516 + BATUU_MISSIONS_FS_7_FOUND_SPY: 'CommonBuffId' = 242013 + BATUU_MISSIONS_FS_7_IS_SPY: 'CommonBuffId' = 242003 + BATUU_MISSIONS_FS_7_SHARE_FAKE_INFO_ANTI_FO_SENTIMENTS: 'CommonBuffId' = 241716 + BATUU_MISSIONS_FS_7_SHARE_FAKE_INFO_HOLOTABLE_SECURITY_FLAW: 'CommonBuffId' = 241713 + BATUU_MISSIONS_FS_7_SHARE_FAKE_INFO_RUMOR: 'CommonBuffId' = 241712 + BATUU_MISSIONS_FS_7_SPY_DELIVERED_FALSE: 'CommonBuffId' = 248959 + BATUU_MISSIONS_FS_7_SPY_DELIVERED_TRUE: 'CommonBuffId' = 248958 + BATUU_MISSIONS_GO_TO_KYLO: 'CommonBuffId' = 241808 + BATUU_MISSIONS_HAS_INFO_ON_CRIMINAL_WHEREABOUTS: 'CommonBuffId' = 241273 + BATUU_MISSIONS_NR2_LIGHTSABER_CHALLENGE_COMPLETE: 'CommonBuffId' = 243948 + BATUU_MISSIONS_NR2_LIGHTSABER_NPC: 'CommonBuffId' = 243895 + BATUU_MISSIONS_PLAYED_SABACC_TOURNAMENT_1ST_OPPONENT_R8: 'CommonBuffId' = 244411 + BATUU_MISSIONS_PLAYED_SABACC_TOURNAMENT_2ND_OPPONENT_SR8: 'CommonBuffId' = 244412 + BATUU_MISSIONS_PLAYED_SABACC_TOURNAMENT_FINAL_OPPONENT_SR8: 'CommonBuffId' = 244413 + BATUU_MISSIONS_RECENTLY_TARGETED_FOR_MISSION_SOCIAL: 'CommonBuffId' = 244345 + BATUU_MISSIONS_RECRUIT_HEIST_FAIL: 'CommonBuffId' = 251796 + BATUU_MISSIONS_RESISTANCE_CONTACT: 'CommonBuffId' = 245246 + BATUU_MISSIONS_RESISTANCE_SAD: 'CommonBuffId' = 244480 + BATUU_MISSIONS_REY_ERASE_MIND: 'CommonBuffId' = 242128 + BATUU_MISSIONS_RICH_SCOUNDREL: 'CommonBuffId' = 245703 + BATUU_MISSIONS_RR15_CAN_ACCESS_DATA_WAITING: 'CommonBuffId' = 245980 + BATUU_MISSIONS_RS2_DATA_SPIKE_COOLDOWN: 'CommonBuffId' = 249564 + BATUU_MISSIONS_RS8_RESCUED_PRISONER: 'CommonBuffId' = 244752 + BATUU_MISSIONS_RS8_RESCUING_WITH_DROID: 'CommonBuffId' = 244699 + BATUU_MISSIONS_SCOUNDREL_CONTACT: 'CommonBuffId' = 245556 + BATUU_MISSIONS_SCOUNDREL_REPEATABLE_04_REVEAL_PASSCODE_COOLDOWN: 'CommonBuffId' = 244597 + BATUU_MISSIONS_SR3_CONTROL_PANEL_COOLDOWN_1: 'CommonBuffId' = 246216 + BATUU_MISSIONS_SR3_CONTROL_PANEL_COOLDOWN_2: 'CommonBuffId' = 246217 + BATUU_MISSIONS_SR3_CONTROL_PANEL_COOLDOWN_3: 'CommonBuffId' = 246218 + BATUU_MISSIONS_SR3_CONTROL_PANEL_COOLDOWN_4: 'CommonBuffId' = 246219 + BATUU_MISSIONS_SR3_CONTROL_PANEL_COOLDOWN_5: 'CommonBuffId' = 246220 + BATUU_MISSIONS_SR3_CONTROL_PANEL_COOLDOWN_6: 'CommonBuffId' = 246221 + BATUU_MISSIONS_SR3_CONTROL_PANEL_COOLDOWN_7: 'CommonBuffId' = 246222 + BATUU_MISSIONS_SR3_CONTROL_PANEL_COOLDOWN_8: 'CommonBuffId' = 246215 + BATUU_MISSIONS_SS10_CELEBRATED_SCOUNDREL: 'CommonBuffId' = 244159 + BATUU_MISSIONS_SS10_CELEBRATION_OVER: 'CommonBuffId' = 245851 + BATUU_MISSIONS_STARSHIP_BLAME_FAIL: 'CommonBuffId' = 244619 + BATUU_MISSIONS_STARSHIP_BLAME_SUCCESS: 'CommonBuffId' = 244618 + BATUU_MISSIONS_STARSHIP_DISPARAGE_FO_RR5: 'CommonBuffId' = 245052 + BATUU_MISSIONS_STARSHIP_INVESTIGATE_BLASTER: 'CommonBuffId' = 244629 + BATUU_MISSIONS_STARSHIP_SR9_ORDER_RECRUIT: 'CommonBuffId' = 244611 + BATUU_MISSIONS_STARSHIP_SS6_SCOUTED_MANUALLY: 'CommonBuffId' = 245622 + BATUU_MISSIONS_STARSHIP_TRY_FIX_FAIL: 'CommonBuffId' = 244615 + BATUU_MISSIONS_STARSHIP_TRY_FIX_SUCCESS: 'CommonBuffId' = 244614 + BATUU_MISSIONS_WEARING_FIRST_ORDER_UNIFORM: 'CommonBuffId' = 243461 + BATUU_MISSIONS_WEARING_RESISTANCE_DISGUISE: 'CommonBuffId' = 242103 + BATUU_MISSION_COMPLETE_FIRST_ORDER: 'CommonBuffId' = 244691 + BATUU_MISSION_COMPLETE_RESISTANCE: 'CommonBuffId' = 244693 + BATUU_MISSION_COMPLETE_SMUGGLER: 'CommonBuffId' = 244694 + BATUU_MISSION_SABACC_TOURNAMENT_1ST_OPPONENT: 'CommonBuffId' = 244448 + BATUU_MISSION_SABACC_TOURNAMENT_2ND_OPPONENT: 'CommonBuffId' = 244450 + BATUU_MISSION_SABACC_TOURNAMENT_FINAL_OPPONENT: 'CommonBuffId' = 244451 + BATUU_NPC_BRIBE_COOLDOWN: 'CommonBuffId' = 245620 + BATUU_NPC_CITIZEN_IDENTIFIER: 'CommonBuffId' = 241637 + BATUU_NPC_FIRST_ORDER_OFFICER_IDENTIFIER: 'CommonBuffId' = 241692 + BATUU_NPC_HONDO_OHNAKA: 'CommonBuffId' = 239650 + BATUU_NPC_LIGHTSABER_TRAIT: 'CommonBuffId' = 243755 + BATUU_NPC_LT_AGNON: 'CommonBuffId' = 239648 + BATUU_NPC_MOVE_TO_POSITION_COOLDOWN: 'CommonBuffId' = 240683 + BATUU_NPC_RESISTANCE_IDENTIFIER: 'CommonBuffId' = 245216 + BATUU_NPC_RESTRICTED_PATROL_COOLDOWN: 'CommonBuffId' = 246062 + BATUU_NPC_SCAN_COOLDOWN: 'CommonBuffId' = 240695 + BATUU_NPC_VENUE_OGAS_CANTINA_BARFLY: 'CommonBuffId' = 237867 + BATUU_NPC_VENUE_OGAS_CANTINA_BARTENDER: 'CommonBuffId' = 237866 + BATUU_NPC_VENUE_RESTRICTED_AREA_BEING_INVESTIGATED: 'CommonBuffId' = 243483 + BATUU_NPC_VENUE_RESTRICTED_AREA_FIRST_ORDER: 'CommonBuffId' = 240493 + BATUU_NPC_VENUE_RESTRICTED_AREA_RESISTANCE: 'CommonBuffId' = 240492 + BATUU_NPC_VENUE_RESTRICTED_AREA_SPOTTED: 'CommonBuffId' = 240666 + BATUU_NPC_VI_MORADI: 'CommonBuffId' = 239649 + BATUU_NPC_WALK_BY_CITIZEN: 'CommonBuffId' = 235807 + BATUU_NPC_WALK_BY_CITIZEN_RESISTANCE_SYMPATHIZER: 'CommonBuffId' = 243523 + BATUU_NPC_WALK_BY_CITIZEN_SCIENTIST: 'CommonBuffId' = 241556 + BATUU_NPC_WALK_BY_CITIZEN_SCIENTIST_DO_WORK: 'CommonBuffId' = 247415 + BATUU_NPC_WALK_BY_CITIZEN_SCIENTIST_JOINED_FO: 'CommonBuffId' = 241569 + BATUU_NPC_WALK_BY_CITIZEN_SUSPICIOUS: 'CommonBuffId' = 241612 + BATUU_NPC_WALK_BY_COOLDOWN: 'CommonBuffId' = 239701 + BATUU_NPC_WALK_BY_FIRST_ORDER_FS7_POTENTIAL_SPY_VFX_BUFF: 'CommonBuffId' = 248937 + BATUU_NPC_WALK_BY_FIRST_ORDER_OFFICER: 'CommonBuffId' = 232306 + BATUU_NPC_WALK_BY_FIRST_ORDER_OFFICER_RESISTANCE_SPY: 'CommonBuffId' = 242007 + BATUU_NPC_WALK_BY_FIRST_ORDER_STORMTROOPER: 'CommonBuffId' = 232307 + BATUU_NPC_WALK_BY_FIRST_ORDER_STORMTROOPER_PATROL: 'CommonBuffId' = 233328 + BATUU_NPC_WALK_BY_RESISTANCE_MEMBER: 'CommonBuffId' = 232309 + BATUU_NPC_WALK_BY_RESISTANCE_MEMBER_PATROL: 'CommonBuffId' = 233329 + BATUU_NPC_WALK_BY_RESISTANCE_MEMBER_PATROL_2: 'CommonBuffId' = 242493 + BATUU_NPC_WALK_BY_ROLE_STATES_SCOUNDREL_MEMBER: 'CommonBuffId' = 235897 + BATUU_PATROL_COOLDOWN: 'CommonBuffId' = 246383 + BATUU_PICKPOCKET_COOLDOWN: 'CommonBuffId' = 244759 + BATUU_REPUTATION_ENTHUSE_DONT_JOIN: 'CommonBuffId' = 243119 + BATUU_REPUTATION_ENTHUSE_FIRST_ORDER_FAN: 'CommonBuffId' = 243115 + BATUU_REPUTATION_ENTHUSE_FRIEND_OF_THE_RESISTANCE: 'CommonBuffId' = 243113 + BATUU_REPUTATION_FIRST_ORDER_NEGATIVE_INTERACTION_MODIFIER_LEVEL_1: 'CommonBuffId' = 243034 + BATUU_REPUTATION_FIRST_ORDER_NEGATIVE_INTERACTION_MODIFIER_LEVEL_2: 'CommonBuffId' = 243035 + BATUU_REPUTATION_FIRST_ORDER_NEGATIVE_INTERACTION_MODIFIER_LEVEL_3: 'CommonBuffId' = 243036 + BATUU_REPUTATION_FIRST_ORDER_NEGATIVE_INTERACTION_MODIFIER_LEVEL_4: 'CommonBuffId' = 243033 + BATUU_REPUTATION_FIRST_ORDER_NEGATIVE_INTERACTION_MODIFIER_LEVEL_5: 'CommonBuffId' = 243010 + BATUU_REPUTATION_RECRUIT_COOLDOWN: 'CommonBuffId' = 243104 + BATUU_REPUTATION_RESISTANCE_NEGATIVE_INTERACTION_MODIFIER_LEVEL_1: 'CommonBuffId' = 243044 + BATUU_REPUTATION_RESISTANCE_NEGATIVE_INTERACTION_MODIFIER_LEVEL_2: 'CommonBuffId' = 243045 + BATUU_REPUTATION_RESISTANCE_NEGATIVE_INTERACTION_MODIFIER_LEVEL_3: 'CommonBuffId' = 243046 + BATUU_REPUTATION_RESISTANCE_NEGATIVE_INTERACTION_MODIFIER_LEVEL_4: 'CommonBuffId' = 243043 + BATUU_REPUTATION_RESISTANCE_NEGATIVE_INTERACTION_MODIFIER_LEVEL_5: 'CommonBuffId' = 243004 + BATUU_REPUTATION_SCOUNDREL_NEGATIVE_INTERACTION_MODIFIER_LEVEL_1: 'CommonBuffId' = 243049 + BATUU_REPUTATION_SCOUNDREL_NEGATIVE_INTERACTION_MODIFIER_LEVEL_2: 'CommonBuffId' = 243050 + BATUU_REPUTATION_SCOUNDREL_NEGATIVE_INTERACTION_MODIFIER_LEVEL_3: 'CommonBuffId' = 243051 + BATUU_REPUTATION_SCOUNDREL_NEGATIVE_INTERACTION_MODIFIER_LEVEL_4: 'CommonBuffId' = 243048 + BATUU_REPUTATION_SCOUNDREL_NEGATIVE_INTERACTION_MODIFIER_LEVEL_5: 'CommonBuffId' = 243011 + BATUU_REPUTATION_TELLTALES_FIRST_ORDER_BRINGING_ORDER: 'CommonBuffId' = 243130 + BATUU_REPUTATION_TELLTALES_FIRST_ORDER_CRUSHING_THE_RESISTANCE: 'CommonBuffId' = 243131 + BATUU_REPUTATION_TELLTALES_FIRST_ORDER_THEY_DONT_WANT_ORDER: 'CommonBuffId' = 243132 + BATUU_REPUTATION_TELLTALES_RESISTANCE_DESPERATE_TIMES: 'CommonBuffId' = 243128 + BATUU_REPUTATION_TELLTALES_RESISTANCE_LIGHTING_THE_FIRE: 'CommonBuffId' = 243127 + BATUU_REPUTATION_TELLTALES_RESISTANCE_SNUFFED_FLAME: 'CommonBuffId' = 243129 + BATUU_REPUTATION_TELLTALES_RESISTANCE_WE_ARE_THE_SPARK: 'CommonBuffId' = 243126 + BATUU_REPUTATION_TELLTALES_SCOUNDREL_ANYTHING_FOR_A_PRICE: 'CommonBuffId' = 243134 + BATUU_REPUTATION_TELLTALES_SCOUNDREL_NOTHING_BUT_LIES: 'CommonBuffId' = 243137 + BATUU_REPUTATION_TELLTALES_SCOUNDREL_SPICE_WONT_SMUGGLE_ITSELF: 'CommonBuffId' = 243135 + BATUU_REPUTATION_TELLTALES_SCOUNDREL_THE_SCORE_WAS_THIS_BIG: 'CommonBuffId' = 243136 + BATUU_REPUTATION_THERE_IS_HOPE: 'CommonBuffId' = 243100 + BATUU_RESISTANCE_CAVE_COOLDOWN_LONG: 'CommonBuffId' = 245133 + BATUU_RESISTANCE_CAVE_COOLDOWN_SHORT: 'CommonBuffId' = 245132 + BATUU_RESISTANCE_CAVE_NEGATIVE_BUFF_1: 'CommonBuffId' = 245130 + BATUU_RESISTANCE_CAVE_NEGATIVE_BUFF_2: 'CommonBuffId' = 245131 + BATUU_RESISTANCE_CAVE_NEGATIVE_BUFF_3: 'CommonBuffId' = 245129 + BATUU_RESISTANCE_CAVE_POSITIVE_BUFF_1: 'CommonBuffId' = 243238 + BATUU_RESISTANCE_CAVE_POSITIVE_BUFF_2: 'CommonBuffId' = 243237 + BATUU_RESISTANCE_CAVE_POSITIVE_BUFF_3: 'CommonBuffId' = 245128 + BATUU_RESISTANCE_MISSION_GIVER: 'CommonBuffId' = 233177 + BATUU_REY_IDENTIFIER: 'CommonBuffId' = 238985 + BATUU_REY_IGNITE_THE_SPARK: 'CommonBuffId' = 238990 + BATUU_REY_NOTHING_TO_REPORT: 'CommonBuffId' = 238989 + BATUU_RR3_HAS_RECEIVED_FOOD: 'CommonBuffId' = 243939 + BATUU_SPECIAL_NPC_GET_INTO_POSITION_COOLDOWN: 'CommonBuffId' = 249788 + BATUU_SPECIAL_NPC_INCREASE_RELATIONSHIP_GAIN: 'CommonBuffId' = 243287 + BATUU_SPECIAL_NPC_KYLO_ROLE: 'CommonBuffId' = 249774 + BATUU_SPECIAL_NPC_REY_ROLE: 'CommonBuffId' = 250080 + BATUU_STARSHIP_BREAK: 'CommonBuffId' = 248735 + BATUU_STARSHIP_EXPLORE_COOLDOWN: 'CommonBuffId' = 245068 + BATUU_STARSHIP_EXPLORE_COOLDOWN_INTERSTELLAR_UPGRADE: 'CommonBuffId' = 248621 + BATUU_STARSHIP_EXPLORE_FIRST_ORDER_NEGATIVE: 'CommonBuffId' = 245073 + BATUU_STARSHIP_EXPLORE_FIRST_ORDER_POSITIVE: 'CommonBuffId' = 245069 + BATUU_STARSHIP_EXPLORE_RESISTANCE_NEGATIVE: 'CommonBuffId' = 245075 + BATUU_STARSHIP_EXPLORE_RESISTANCE_POSITIVE: 'CommonBuffId' = 245070 + BATUU_STARSHIP_EXPLORE_SCOUNDREL_NEGATIVE: 'CommonBuffId' = 245074 + BATUU_STARSHIP_EXPLORE_SCOUNDREL_POSITIVE: 'CommonBuffId' = 245072 + BATUU_STARSHIP_EXPLORE_WITH_GO_TO_SPACE: 'CommonBuffId' = 239378 + BATUU_STARSHIP_MISSION_CREW_ROLE: 'CommonBuffId' = 244885 + BATUU_STARSHIP_REPAIR_ROLE: 'CommonBuffId' = 239182 + BATUU_SUPPLY_CRATE_SLICE_FAIL: 'CommonBuffId' = 237335 + BATUU_SUPPLY_CRATE_SLICE_SUCCESS: 'CommonBuffId' = 237334 + BATUU_SWINDLE_COOLDOWN: 'CommonBuffId' = 238439 + BATUU_SYSTEM_OVERLOADED: 'CommonBuffId' = 239899 + BATUU_TIL_THE_SPIRE_COOLDOWN: 'CommonBuffId' = 247417 + BATUU_VENDOR_CANCEL_HIDDEN: 'CommonBuffId' = 245746 + BATUU_VI_DUPED: 'CommonBuffId' = 238991 + BATUU_VI_IDENTIFIER: 'CommonBuffId' = 238986 + BATUU_VI_STAND_TOGETHER: 'CommonBuffId' = 238992 + BATUU_VI_WALK_BY: 'CommonBuffId' = 245750 + BATUU_WHITELIST_NPC_GENERIC: 'CommonBuffId' = 240749 + BATUU_WHITELIST_SPECIAL_NPC_AGNON: 'CommonBuffId' = 241027 + BATUU_WHITELIST_SPECIAL_NPC_HONDO: 'CommonBuffId' = 239782 + BATUU_WHITELIST_SPECIAL_NPC_KYLO: 'CommonBuffId' = 240751 + BATUU_WHITELIST_SPECIAL_NPC_REY: 'CommonBuffId' = 240750 + BATUU_WHITELIST_SPECIAL_NPC_VI: 'CommonBuffId' = 241026 + BEACH_CAVE_ANCIENT_WRECK_OUTCOME_1_HIDDEN: 'CommonBuffId' = 210479 + BEACH_CAVE_ANCIENT_WRECK_OUTCOME_2_HIDDEN: 'CommonBuffId' = 210480 + BEACH_CAVE_BAT_COLONY_BAT_BITES: 'CommonBuffId' = 209184 + BEACH_CAVE_BAT_COLONY_NATURAL_HABITAT: 'CommonBuffId' = 209182 + BEACH_CAVE_BAT_COLONY_OUTCOME_1_HIDDEN: 'CommonBuffId' = 210484 + BEACH_CAVE_BAT_COLONY_OUTCOME_2_HIDDEN: 'CommonBuffId' = 210485 + BEACH_CAVE_CAVE_GRAFFITI_GOOD_DEED: 'CommonBuffId' = 209094 + BEACH_CAVE_CAVE_GRAFFITI_OUTCOME_1_HIDDEN: 'CommonBuffId' = 210462 + BEACH_CAVE_CAVE_GRAFFITI_OUTCOME_2_HIDDEN: 'CommonBuffId' = 210463 + BEACH_CAVE_CAVE_GRAFFITI_URBAN_ARTWORK: 'CommonBuffId' = 209097 + BEACH_CAVE_COLLECTION_OF_SHELLS_OUTCOME_1_HIDDEN: 'CommonBuffId' = 210486 + BEACH_CAVE_COLLECTION_OF_SHELLS_OUTCOME_2_HIDDEN: 'CommonBuffId' = 210487 + BEACH_CAVE_COLLECTION_OF_SHELLS_PINCHED_DURING_PILFERING: 'CommonBuffId' = 209185 + BEACH_CAVE_ENCHANTED_SONG_OUTCOME_1_HIDDEN: 'CommonBuffId' = 210460 + BEACH_CAVE_ENCHANTED_SONG_OUTCOME_2_HIDDEN: 'CommonBuffId' = 210461 + BEACH_CAVE_GLINT_OUT_OF_REACH_OUTCOME_1_HIDDEN: 'CommonBuffId' = 210477 + BEACH_CAVE_GLINT_OUT_OF_REACH_OUTCOME_2_HIDDEN: 'CommonBuffId' = 210478 + BEACH_CAVE_GLOW_WORMS_OUTCOME_1_HIDDEN: 'CommonBuffId' = 210490 + BEACH_CAVE_GLOW_WORMS_OUTCOME_2_HIDDEN: 'CommonBuffId' = 210491 + BEACH_CAVE_GLOW_WORMS_STARTLED_BY_LAVA: 'CommonBuffId' = 209188 + BEACH_CAVE_GLOW_WORMS_STRANGE_LIGHTS: 'CommonBuffId' = 209187 + BEACH_CAVE_LAVA_TUBES_OUTCOME_1_HIDDEN: 'CommonBuffId' = 210474 + BEACH_CAVE_LAVA_TUBES_OUTCOME_2_HIDDEN: 'CommonBuffId' = 210475 + BEACH_CAVE_LAVA_TUBES_RAN_FROM_KRAKEN: 'CommonBuffId' = 209160 + BEACH_CAVE_LIGHT_IN_THE_DARK_HIDDEN_LOCH: 'CommonBuffId' = 209106 + BEACH_CAVE_LIGHT_IN_THE_DARK_OUTCOME_1_HIDDEN: 'CommonBuffId' = 210464 + BEACH_CAVE_LIGHT_IN_THE_DARK_OUTCOME_2_HIDDEN: 'CommonBuffId' = 210465 + BEACH_CAVE_LIGHT_IN_THE_DARK_UNEXPECTED_TRIP: 'CommonBuffId' = 209110 + BEACH_CAVE_PLAYFUL_DOLPHINS_OUTCOME_1_HIDDEN: 'CommonBuffId' = 210488 + BEACH_CAVE_PLAYFUL_DOLPHINS_OUTCOME_2_HIDDEN: 'CommonBuffId' = 210489 + BEACH_CAVE_PLAYFUL_DOLPHINS_PLAYTIME_INTERRUPTED: 'CommonBuffId' = 209186 + BEACH_CAVE_STRANGE_NOISE_IN_THE_DARK_OF_THE_CAVE: 'CommonBuffId' = 209102 + BEACH_CAVE_STRANGE_NOISE_OUTCOME_1_HIDDEN: 'CommonBuffId' = 210466 + BEACH_CAVE_STRANGE_NOISE_OUTCOME_2_HIDDEN: 'CommonBuffId' = 210467 + BEACH_CAVE_STRANGE_NOISE_SPLENDOR: 'CommonBuffId' = 209100 + BEACH_CAVE_UNDERGROUND_POOLS_OUTCOME_1_HIDDEN: 'CommonBuffId' = 210472 + BEACH_CAVE_UNDERGROUND_POOLS_OUTCOME_2_HIDDEN: 'CommonBuffId' = 210473 + BEACH_COMBING_COMB_SEASHELLS: 'CommonBuffId' = 206640 + BEACH_COMBING_COMB_TRASH: 'CommonBuffId' = 206641 + BEACH_COMBING_COOLDOWN: 'CommonBuffId' = 210723 + BEACH_COMBING_FAIL_REACTIONS_CUTE_BABY_TURTLE: 'CommonBuffId' = 206736 + BEACH_COMBING_FAIL_REACTIONS_ESCAPED_YOUR_GRASP: 'CommonBuffId' = 206755 + BEACH_COMBING_FAIL_REACTIONS_MADE_CRAB_FRIEND: 'CommonBuffId' = 206735 + BEACH_COMBING_FAIL_REACTIONS_PINCHED_BY_CRAB: 'CommonBuffId' = 206733 + BEACH_COMBING_FAIL_REACTIONS_POOPED_ON: 'CommonBuffId' = 206752 + BEACH_COMBING_FAIL_REACTIONS_SNATCHED_BY_SEAGULL: 'CommonBuffId' = 206751 + BEACH_COMBING_FAIL_REACTIONS_TOUCHED_SOMETHING_GROSS: 'CommonBuffId' = 206756 + BEACH_COMBING_FAIL_REACTIONS_TOUCHED_SOMETHING_PAINFUL: 'CommonBuffId' = 206757 + BEACH_COMBING_FAIL_REACTIONS_WHAT_WAS_THAT: 'CommonBuffId' = 206753 + BEACH_COMBING_SURVEYING: 'CommonBuffId' = 206489 + BEAR_NEARBY: 'CommonBuffId' = 108234 + BEAR_ROARED_AT: 'CommonBuffId' = 108102 + BED_NAP_SLOSHED: 'CommonBuffId' = 10367 + BED_PERFECT_FIRMNESS: 'CommonBuffId' = 231308 + BED_UPDATES_LOW_QUALITY_KNEEL: 'CommonBuffId' = 293649 + BED_UPDATES_LOW_QUALITY_SIT: 'CommonBuffId' = 293648 + BED_UPDATES_PILLOW_FIGHT_LOSE: 'CommonBuffId' = 282996 + BED_UPDATES_PILLOW_FIGHT_WIN: 'CommonBuffId' = 282995 + BED_UPDATES_STAY_IN_SIT_ON_BED_FROM_CHAT: 'CommonBuffId' = 302672 + BED_UPDATES_STAY_IN_SIT_ON_BED_FROM_SIT: 'CommonBuffId' = 302674 + BED_UPDATES_STAY_IN_SIT_ON_GROUND: 'CommonBuffId' = 302784 + BEE_BOX_BEE_SWARM_CHEERED_UP: 'CommonBuffId' = 186570 + BEE_BOX_DISTURB_BOX_PLAYFUL: 'CommonBuffId' = 186204 + BEE_BOX_HONEY: 'CommonBuffId' = 186384 + BEE_BOX_HONEY_BEAR: 'CommonBuffId' = 189014 + BEE_BOX_HONEY_BEE_FOOD_DRINK: 'CommonBuffId' = 188942 + BEE_BOX_STUNG: 'CommonBuffId' = 186173 + BEE_BOX_WEARING_BEE_SUIT: 'CommonBuffId' = 186176 + BEGUILED: 'CommonBuffId' = 35120 + BEG_HOST_OLD_AGE_HORSE: 'CommonBuffId' = 324643 + BEING_INAPPROPRIATE: 'CommonBuffId' = 24336 + BEST_HUG_EVER: 'CommonBuffId' = 332288 + BE_GHOST_ANGER: 'CommonBuffId' = 102367 + BE_GHOST_ANIMAL_OBJECTS_KILLER_CHICKEN: 'CommonBuffId' = 267994 + BE_GHOST_ANIMAL_OBJECTS_KILLER_RABBIT: 'CommonBuffId' = 257787 + BE_GHOST_BROKEN_HEART: 'CommonBuffId' = 382009 + BE_GHOST_CLIMBING_ROUTE: 'CommonBuffId' = 250227 + BE_GHOST_COW_PLANT: 'CommonBuffId' = 102855 + BE_GHOST_DROWN: 'CommonBuffId' = 103659 + BE_GHOST_DROWN_CHILD: 'CommonBuffId' = 105677 + BE_GHOST_ELECTROCUTION: 'CommonBuffId' = 102368 + BE_GHOST_EMBARRASSMENT: 'CommonBuffId' = 102526 + BE_GHOST_FIRE: 'CommonBuffId' = 102369 + BE_GHOST_FIRE_CHILD: 'CommonBuffId' = 103607 + BE_GHOST_FLIES_TRASH_UPDATE: 'CommonBuffId' = 234849 + BE_GHOST_FROZEN: 'CommonBuffId' = 182186 + BE_GHOST_FROZEN_CHILD: 'CommonBuffId' = 182193 + BE_GHOST_GENERIC: 'CommonBuffId' = 102288 + BE_GHOST_GUIDRY: 'CommonBuffId' = 252854 + BE_GHOST_HAUNTED_HOUSE_TEMPERANCE: 'CommonBuffId' = 256361 + BE_GHOST_HUNGRY: 'CommonBuffId' = 102797 + BE_GHOST_METEORITE: 'CommonBuffId' = 295360 + BE_GHOST_MOLD_SYSTEM: 'CommonBuffId' = 343870 + BE_GHOST_MOTHER_PLANT: 'CommonBuffId' = 204160 + BE_GHOST_MURPHY_BED: 'CommonBuffId' = 229439 + BE_GHOST_OLD_AGE: 'CommonBuffId' = 102636 + BE_GHOST_OLD_AGE_PET_IDLE_YOWL: 'CommonBuffId' = 166676 + BE_GHOST_OVERHEATED: 'CommonBuffId' = 184952 + BE_GHOST_OVER_EXERTION: 'CommonBuffId' = 102696 + BE_GHOST_PLAYFUL: 'CommonBuffId' = 102503 + BE_GHOST_POISON: 'CommonBuffId' = 176265 + BE_GHOST_PUFFER_FISH: 'CommonBuffId' = 137464 + BE_GHOST_RODENTT_DISEASE: 'CommonBuffId' = 181921 + BE_GHOST_RODENT_DISEASE: 'CommonBuffId' = 181919 + BE_GHOST_RODENT_DISEASE_RODENT_COSTUME: 'CommonBuffId' = 185711 + BE_GHOST_STEAM: 'CommonBuffId' = 119953 + BE_GHOST_STEAM_CHILD: 'CommonBuffId' = 119954 + BE_GHOST_STINK_BOMB: 'CommonBuffId' = 284381 + BE_GHOST_URBAN_MYTH: 'CommonBuffId' = 284382 + BE_GHOST_VAMPIRE_SUN: 'CommonBuffId' = 151545 + BE_GHOST_VENDING_MACHINE: 'CommonBuffId' = 252088 + BE_GHOST_WITCH_OVERLOAD: 'CommonBuffId' = 216980 + BIRD_FLOCK_ATTACKED_FLOCK: 'CommonBuffId' = 172693 + BIRD_FLOCK_CHASED_FLOCK: 'CommonBuffId' = 172694 + BLESSINGS_ANCIENT_JOY: 'CommonBuffId' = 175088 + BLESSINGS_APPLY_BLESSINGS_ANCIENT_JOY: 'CommonBuffId' = 178958 + BLESSINGS_APPLY_BLESSINGS_ANCIENT_JOY_2: 'CommonBuffId' = 183534 + BLESSINGS_APPLY_BLESSINGS_GLORIOUS_TASTES: 'CommonBuffId' = 183533 + BLESSINGS_APPLY_BLESSINGS_IM_A_SKELETON_COMMON: 'CommonBuffId' = 176391 + BLESSINGS_APPLY_BLESSINGS_IM_A_SKELETON_RARE: 'CommonBuffId' = 176393 + BLESSINGS_APPLY_BLESSINGS_IM_A_SKELETON_UNCOMMON: 'CommonBuffId' = 176392 + BLESSINGS_APPLY_BLESSINGS_ITS_ALL_GOOD: 'CommonBuffId' = 183532 + BLESSINGS_APPLY_BLESSINGS_MONEY_COMMON: 'CommonBuffId' = 175323 + BLESSINGS_APPLY_BLESSINGS_MONEY_RARE: 'CommonBuffId' = 175324 + BLESSINGS_APPLY_BLESSINGS_MONEY_UNCOMMON: 'CommonBuffId' = 175325 + BLESSINGS_APPLY_BLESSINGS_PERSONAL_SUN: 'CommonBuffId' = 183531 + BLESSINGS_APPLY_BLESSINGS_RELATIONSHIPS_COMMON: 'CommonBuffId' = 175347 + BLESSINGS_APPLY_BLESSINGS_RELATIONSHIPS_RARE: 'CommonBuffId' = 175348 + BLESSINGS_APPLY_BLESSINGS_RELATIONSHIPS_UNCOMMON: 'CommonBuffId' = 175349 + BLESSINGS_APPLY_BLESSINGS_SERVICE_SKELETON_COMMON: 'CommonBuffId' = 177656 + BLESSINGS_APPLY_BLESSINGS_SERVICE_SKELETON_RARE: 'CommonBuffId' = 177658 + BLESSINGS_APPLY_BLESSINGS_SERVICE_SKELETON_UNCOMMON: 'CommonBuffId' = 177657 + BLESSINGS_EFFECTS_GLORIOUS_TASTES_GREAT_MEAL: 'CommonBuffId' = 175299 + BLESSINGS_EFFECTS_IM_A_SKELETON_COMMON: 'CommonBuffId' = 176399 + BLESSINGS_EFFECTS_IM_A_SKELETON_RARE: 'CommonBuffId' = 176401 + BLESSINGS_EFFECTS_IM_A_SKELETON_UNCOMMON: 'CommonBuffId' = 176400 + BLESSINGS_GLORIOUS_TASTES: 'CommonBuffId' = 175284 + BLESSINGS_ITS_ALL_GOOD: 'CommonBuffId' = 175207 + BLESSINGS_PERSONAL_SUN: 'CommonBuffId' = 175014 + BLOCK_CONSTRUCTION_TABLE_BONDING_TIME: 'CommonBuffId' = 165602 + BLOCK_CONSTRUCTION_TABLE_CONSTRUCTION_COLLABORATION: 'CommonBuffId' = 165365 + BODY_SPRAY: 'CommonBuffId' = 12387 + BOOK_READ_TOO_EASY_VAMPIRE_BOOK: 'CommonBuffId' = 149625 + BOOK_READ_TOO_HARD_VAMPIRE_BOOK: 'CommonBuffId' = 149627 + BOUQUET_STOP_HOLDING: 'CommonBuffId' = 282710 + BREATH_SPRAY: 'CommonBuffId' = 12388 + BROKEN_UP_OR_DIVORCED_HIDDEN: 'CommonBuffId' = 28121 + BUFFS_CORE_SOCIALS_BUFFS_PEEVED_CHILD: 'CommonBuffId' = 40595 + BUFFS_CORE_SOCIAL_BUFFS_AWKWARD_TURTLE: 'CommonBuffId' = 37659 + BUFFS_CORE_SOCIAL_BUFFS_DULL_HUMOR: 'CommonBuffId' = 37656 + BUFFS_CORE_SOCIAL_BUFFS_ENOUGH_IS_ENOUGH: 'CommonBuffId' = 37654 + BUFFS_CORE_SOCIAL_BUFFS_FLATTERED: 'CommonBuffId' = 37684 + BUFFS_CORE_SOCIAL_BUFFS_HOT_N_HEAVY: 'CommonBuffId' = 37657 + BUFFS_CORE_SOCIAL_BUFFS_MADE_A_DEEP_CONNECTION: 'CommonBuffId' = 37658 + BUFFS_CORE_SOCIAL_BUFFS_ON_A_ROLL: 'CommonBuffId' = 37664 + BUFFS_MAKE_A_MESS_COOLDOWN: 'CommonBuffId' = 168756 + BUFFS_MAKE_A_MESS_INSPIRED: 'CommonBuffId' = 163601 + BUFFS_MAKE_A_MESS_PLAYFUL: 'CommonBuffId' = 163602 + BUFFS_MENTOREE_BASKETBALL: 'CommonBuffId' = 147863 + BUFFS_MENTOREE_BY_MENTOR_PRO_FABRICATION: 'CommonBuffId' = 237524 + BUFFS_MENTOREE_BY_MENTOR_PRO_MURAL: 'CommonBuffId' = 152534 + BUFFS_MENTOREE_FABRICATION: 'CommonBuffId' = 237523 + BUFFS_MENTOREE_FISHING: 'CommonBuffId' = 207780 + BUFFS_MENTOREE_KNITTING: 'CommonBuffId' = 245597 + BUFFS_MENTOREE_MURAL: 'CommonBuffId' = 152533 + BUFFS_MENTOREE_ROBOTICS: 'CommonBuffId' = 227897 + BUFFS_MENTOREE_TODDLER_DANCING: 'CommonBuffId' = 150130 + BUFFS_MENTOREE_TODDLER_DANCING_CLINGY: 'CommonBuffId' = 154565 + BUFFS_MENTOREE_TODDLER_DANCING_INDEPENDENT: 'CommonBuffId' = 157434 + BUFFS_MENTOREE_TODDLER_FAILURE: 'CommonBuffId' = 156538 + BUFFS_MENTOREE_TODDLER_INTERACTING: 'CommonBuffId' = 254901 + BUFFS_MENTOREE_TODDLER_NESTING_BLOCKS: 'CommonBuffId' = 148197 + BUFFS_MENTOREE_TODDLER_NESTING_BLOCKS_CLINGY: 'CommonBuffId' = 154570 + BUFFS_MENTOREE_TODDLER_PROUD: 'CommonBuffId' = 156449 + BUFFS_PORTABLE_KEYBOARD_BUSKER_TIPPED_HIGH: 'CommonBuffId' = 147273 + BUFFS_PORTABLE_KEYBOARD_BUSKER_TIPPED_LOW: 'CommonBuffId' = 147274 + BUFFS_PORTABLE_KEYBOARD_BUSKER_TIPPED_MED: 'CommonBuffId' = 147275 + BUILD_LADDERS_SLIDE: 'CommonBuffId' = 236254 + BUILD_LADDERS_SLIDE_HAPPY: 'CommonBuffId' = 236653 + BUILD_UP_PARTNER: 'CommonBuffId' = 372344 + BURNOUT_BURNED_OUT: 'CommonBuffId' = 306680 + BURNOUT_CLEAR_MIND_FINE: 'CommonBuffId' = 306861 + BURNOUT_CLEAR_MIND_HAPPY: 'CommonBuffId' = 306747 + BURNOUT_FOG_CREATIVE: 'CommonBuffId' = 304277 + BURNOUT_FOG_MENTAL: 'CommonBuffId' = 306746 + BURNOUT_HIDDEN_CREATIVE_TRACKER: 'CommonBuffId' = 306676 + BURNOUT_HIDDEN_CREATIVE_TRACKER_DECREASE_LARGE: 'CommonBuffId' = 306714 + BURNOUT_HIDDEN_CREATIVE_TRACKER_DECREASE_SMALL: 'CommonBuffId' = 306715 + BURNOUT_HIDDEN_CREATIVE_TRACKER_INCREASE_LARGE: 'CommonBuffId' = 304276 + BURNOUT_HIDDEN_CREATIVE_TRACKER_INCREASE_SMALL: 'CommonBuffId' = 306713 + BURNOUT_HIDDEN_DECREASE_LARGE_FOG_BURNED_OUT_MENTAL_BLOCK: 'CommonBuffId' = 324909 + BURNOUT_HIDDEN_DECREASE_SMALL_FOG_BURNED_OUT_MENTAL_BLOCK: 'CommonBuffId' = 324908 + BURNOUT_HIDDEN_INCREASE_LARGE_FOG_BURNED_OUT: 'CommonBuffId' = 324906 + BURNOUT_HIDDEN_INCREASE_SMALL_FOG_BURNED_OUT: 'CommonBuffId' = 324907 + BURNOUT_HIDDEN_MENTAL_TRACKER: 'CommonBuffId' = 306750 + BURNOUT_HIDDEN_MENTAL_TRACKER_DECREASE_LARGE: 'CommonBuffId' = 306779 + BURNOUT_HIDDEN_MENTAL_TRACKER_DECREASE_SMALL: 'CommonBuffId' = 306780 + BURNOUT_HIDDEN_MENTAL_TRACKER_INCREASE_LARGE: 'CommonBuffId' = 306781 + BURNOUT_HIDDEN_MENTAL_TRACKER_INCREASE_SMALL: 'CommonBuffId' = 306802 + BURNOUT_HIDDEN_ON_VACATION: 'CommonBuffId' = 308561 + BURNOUT_HIDDEN_TIMER_BURNED_OUT: 'CommonBuffId' = 306803 + BURNOUT_HIDDEN_TIMER_FOG_CREATIVE: 'CommonBuffId' = 306678 + BURNOUT_HIDDEN_TIMER_FOG_MENTAL: 'CommonBuffId' = 306753 + BURNOUT_MENTAL_BLOCK: 'CommonBuffId' = 306776 + BUSH_PET_BIRD: 'CommonBuffId' = 171930 + BUSH_PET_DIRTY: 'CommonBuffId' = 176262 + BUSH_PET_FIND_ITEM: 'CommonBuffId' = 171931 + BUSH_PET_PLAY: 'CommonBuffId' = 171932 + BUSH_PET_SKUNKED: 'CommonBuffId' = 171906 + BUSH_PET_SQUIRREL_FAIL: 'CommonBuffId' = 171929 + BUSH_PET_SQUIRREL_SUCCESS: 'CommonBuffId' = 171910 + CAFETERIA_STATION_FAILED_PRANK: 'CommonBuffId' = 217688 + CAFETERIA_STATION_SERVER_BREAKFAST: 'CommonBuffId' = 229048 + CAFETERIA_STATION_SERVER_DINNER: 'CommonBuffId' = 229050 + CAFETERIA_STATION_SERVER_LUNCH: 'CommonBuffId' = 229049 + CAFETERIA_STATION_SERVER_PRANKED: 'CommonBuffId' = 218062 + CAFETERIA_STATION_TOO_SPICY: 'CommonBuffId' = 218816 + CAMPING_FOREST_HOME_SICK: 'CommonBuffId' = 105348 + CAMPING_FOREST_LOVES_OUTDOORS_REJUVENATED: 'CommonBuffId' = 107826 + CAMPING_FOREST_MOSQUITOES: 'CommonBuffId' = 110271 + CAMPING_FOREST_NEAT_HYGIENE_DECAY: 'CommonBuffId' = 107875 + CAMPING_FOREST_REFRESHED: 'CommonBuffId' = 104851 + CANNING_COWBERRY_JAM: 'CommonBuffId' = 257629 + CANNING_EXCELLENT_QUALITY: 'CommonBuffId' = 257630 + CANNING_JAMS: 'CommonBuffId' = 267680 + CANNING_MAYO_HATES: 'CommonBuffId' = 267681 + CANNING_MAYO_LIKES: 'CommonBuffId' = 267682 + CAREER_10_FAR_BEHIND: 'CommonBuffId' = 39475 + CAREER_10_FLUFFY_MISSING: 'CommonBuffId' = 75611 + CAREER_10_FLUFFY_RECOVERED: 'CommonBuffId' = 75608 + CAREER_10_HATERS_APPEASED: 'CommonBuffId' = 38547 + CAREER_10_LOST_GERBIL_HANDLING_RIGHT: 'CommonBuffId' = 75610 + CAREER_10_NEW_RECIPE: 'CommonBuffId' = 38531 + CAREER_10_PEER_STUDY: 'CommonBuffId' = 39471 + CAREER_10_RECAPTURED_FLUFFY: 'CommonBuffId' = 75609 + CAREER_10_SCAMMED: 'CommonBuffId' = 38532 + CAREER_10_UNCOMFORTABLE: 'CommonBuffId' = 106897 + CAREER_10_WROTE_FOR_TV: 'CommonBuffId' = 38583 + CAREER_11_EMPTY_CROWD: 'CommonBuffId' = 38203 + CAREER_11_EX_ON_HOLD: 'CommonBuffId' = 39531 + CAREER_11_FIERY_EX: 'CommonBuffId' = 39530 + CAREER_11_HOMEWORK_COMPLETE: 'CommonBuffId' = 39477 + CAREER_11_MOUNTAIN_OF_HOMEWORK: 'CommonBuffId' = 39480 + CAREER_11_PREFORMED_FOR_FRIENDS: 'CommonBuffId' = 38202 + CAREER_11_SENT_INTO_THE_HALL: 'CommonBuffId' = 75614 + CAREER_11_SOMEONE_ELSE_IN_TROUBLE: 'CommonBuffId' = 75612 + CAREER_12_CAUGHT_NAPPING: 'CommonBuffId' = 75616 + CAREER_12_DELAYED_POSTING: 'CommonBuffId' = 37960 + CAREER_12_NO_NEW_GOOD_NEWS: 'CommonBuffId' = 37958 + CAREER_12_PERFECT_C_STUDENT: 'CommonBuffId' = 39482 + CAREER_12_PE_NAP: 'CommonBuffId' = 75615 + CAREER_12_SMELLY_TIRADE: 'CommonBuffId' = 39532 + CAREER_13_A_PLUS_PROJECT: 'CommonBuffId' = 39488 + CAREER_13_CLASS_GOSSIP: 'CommonBuffId' = 75618 + CAREER_13_FLUBBED_ATTEMPT: 'CommonBuffId' = 38205 + CAREER_13_HECKLER_SHUTDOWN: 'CommonBuffId' = 38204 + CAREER_13_HUMOROUS_BOSS: 'CommonBuffId' = 38148 + CAREER_13_LOWER_GRADE: 'CommonBuffId' = 39490 + CAREER_13_MISSED_DEADLINE: 'CommonBuffId' = 39534 + CAREER_13_NOT_FULLY_PAID: 'CommonBuffId' = 37962 + CAREER_13_SECRET_ADMIRER: 'CommonBuffId' = 75617 + CAREER_13_SELF_LEARNING: 'CommonBuffId' = 39533 + CAREER_13_SLACKING_CLASSMATES: 'CommonBuffId' = 39489 + CAREER_14_ASSIGNMENT_EXTENSION: 'CommonBuffId' = 75620 + CAREER_14_COPIED_A_CLASSMATE: 'CommonBuffId' = 75619 + CAREER_14_FINDERS_KEEPERS: 'CommonBuffId' = 39491 + CAREER_14_HENCHMEN_CHAT: 'CommonBuffId' = 38655 + CAREER_14_MISSING_FINGERNAILS: 'CommonBuffId' = 38653 + CAREER_14_NO_LUNCH: 'CommonBuffId' = 75621 + CAREER_14_PRINCIPALS_SPEECH: 'CommonBuffId' = 39492 + CAREER_14_UNDERCOVER_STORIES: 'CommonBuffId' = 38652 + CAREER_15_BRANCHING_OUT: 'CommonBuffId' = 37964 + CAREER_15_DEMO_SCRAMBLE: 'CommonBuffId' = 39537 + CAREER_15_DIFFICULT_REPORT: 'CommonBuffId' = 39493 + CAREER_15_FAN_BACKLASH: 'CommonBuffId' = 37965 + CAREER_15_MENTOR_DISCOVERED: 'CommonBuffId' = 38428 + CAREER_15_NUMBED_MIND: 'CommonBuffId' = 39494 + CAREER_15_ONE_LESS_FRIEND: 'CommonBuffId' = 75622 + CAREER_15_PAGER_WORRIES: 'CommonBuffId' = 38149 + CAREER_15_RESTED_AND_RECOVERED: 'CommonBuffId' = 38052 + CAREER_15_SPEAK_UP: 'CommonBuffId' = 38150 + CAREER_15_SPY_INSTINCTS: 'CommonBuffId' = 38650 + CAREER_15_TASKS_CLEARED_OUT: 'CommonBuffId' = 39538 + CAREER_15_THE_FUMES: 'CommonBuffId' = 38053 + CAREER_15_TV_BIRTHDAY: 'CommonBuffId' = 75623 + CAREER_16_BABY_CRANKS: 'CommonBuffId' = 38051 + CAREER_16_DISSUADED_BULLIES: 'CommonBuffId' = 39495 + CAREER_16_DOCTORED_UP_BOSS: 'CommonBuffId' = 39541 + CAREER_16_EPIC_WEDGIE: 'CommonBuffId' = 39496 + CAREER_16_EXTRA_HOMEWORK: 'CommonBuffId' = 75630 + CAREER_16_IMPROVING_CAMARADERIE: 'CommonBuffId' = 39540 + CAREER_16_RIOT_STORIES: 'CommonBuffId' = 37993 + CAREER_16_TEST_RETAKEN: 'CommonBuffId' = 75629 + CAREER_16_WORKED_ALL_NIGHT: 'CommonBuffId' = 99454 + CAREER_16_WRITING_PRAISED: 'CommonBuffId' = 37967 + CAREER_16_YELLOW_JOURNALISM: 'CommonBuffId' = 37968 + CAREER_17_ANGRY_FRIEND: 'CommonBuffId' = 39500 + CAREER_17_CANCELED_PROJECT: 'CommonBuffId' = 39544 + CAREER_17_CHASED_OFF_STAGE: 'CommonBuffId' = 38209 + CAREER_17_HORRIBLE_HOST: 'CommonBuffId' = 37974 + CAREER_17_INCOMPETENT_AGENT: 'CommonBuffId' = 38158 + CAREER_17_MORE_PAPERWORK: 'CommonBuffId' = 38153 + CAREER_17_NO_COMPETITION: 'CommonBuffId' = 39542 + CAREER_17_PROJECT_THROWN_OUT: 'CommonBuffId' = 75631 + CAREER_17_RUSHED_PROJECT: 'CommonBuffId' = 39543 + CAREER_17_SIMPLE_MINDED_FRIEND: 'CommonBuffId' = 39499 + CAREER_17_SPLOTCH_PAINT_JOB: 'CommonBuffId' = 38058 + CAREER_17_STUNNING_BALLAD: 'CommonBuffId' = 38208 + CAREER_18_ACADEMIC_FAME: 'CommonBuffId' = 75634 + CAREER_18_BARGAIN_BIN_BOMB: 'CommonBuffId' = 37976 + CAREER_18_BORROWED_TUX: 'CommonBuffId' = 38211 + CAREER_18_CONFUSING_SEQUEL: 'CommonBuffId' = 37975 + CAREER_18_GREEN_LIT_IDEA: 'CommonBuffId' = 39545 + CAREER_18_LOST_HONESTLY: 'CommonBuffId' = 75633 + CAREER_18_RUINED_PIECES: 'CommonBuffId' = 38059 + CAREER_18_SURPRISE_WINNER: 'CommonBuffId' = 75635 + CAREER_18_THAT_AWKWARD_SOUND: 'CommonBuffId' = 38217 + CAREER_18_TRICKED_INTO_FAILURE: 'CommonBuffId' = 75632 + CAREER_18_TURNCOAT_MENTOR: 'CommonBuffId' = 38160 + CAREER_19_AIRPLANE_INNOVATION: 'CommonBuffId' = 75636 + CAREER_19_BENT_AIRPLANE: 'CommonBuffId' = 75638 + CAREER_19_BORING_CASE: 'CommonBuffId' = 38161 + CAREER_19_CATCHY_TUNE: 'CommonBuffId' = 38219 + CAREER_19_MASCOT_BEAT_DOWN: 'CommonBuffId' = 39548 + CAREER_19_OUTDATED_ARTIST: 'CommonBuffId' = 38061 + CAREER_19_PERSONAL_MASCOT: 'CommonBuffId' = 39549 + CAREER_19_PIDDLE_PIDDLE: 'CommonBuffId' = 38220 + CAREER_19_RAUCOUS_JEERS: 'CommonBuffId' = 39547 + CAREER_19_SHARED_DESIGN: 'CommonBuffId' = 75637 + CAREER_19_SOUND_DEBATE: 'CommonBuffId' = 38054 + CAREER_19_THREW_OFF_CURVE: 'CommonBuffId' = 39501 + CAREER_19_UNNEEDED_QUESTIONING: 'CommonBuffId' = 37994 + CAREER_1_ANOTHER_LECTURE: 'CommonBuffId' = 39443 + CAREER_1_ASLEEP_IN_CLASS: 'CommonBuffId' = 39445 + CAREER_1_QUICK_SNACK: 'CommonBuffId' = 75580 + CAREER_1_SENT_TO_PRINCIPAL: 'CommonBuffId' = 75579 + CAREER_1_SPITBALL_MARKSMAN: 'CommonBuffId' = 39439 + CAREER_20_ABSTRACT_MEMORY: 'CommonBuffId' = 38063 + CAREER_20_ANOTHERS_EMBARRASSMENT: 'CommonBuffId' = 75639 + CAREER_20_DISASTROUS_MATCH: 'CommonBuffId' = 39551 + CAREER_20_KITTEN_SAVIOR: 'CommonBuffId' = 37995 + CAREER_20_LIFE_LESSON: 'CommonBuffId' = 39502 + CAREER_20_NO_ONES_WORKING: 'CommonBuffId' = 38162 + CAREER_20_OFFICE_DOWNTIME: 'CommonBuffId' = 38163 + CAREER_20_PAINTERS_EYE: 'CommonBuffId' = 38062 + CAREER_20_UNIFIED_TEAM: 'CommonBuffId' = 39550 + CAREER_21_CAUGHT_WITH_A_BIB: 'CommonBuffId' = 75641 + CAREER_21_DEALING_WITH_PAIN: 'CommonBuffId' = 38065 + CAREER_21_ELECTRONIC_FUTURE: 'CommonBuffId' = 37977 + CAREER_21_FEARLESS_HIPSTERS: 'CommonBuffId' = 37996 + CAREER_21_FUTURE_BLACKMAIL: 'CommonBuffId' = 38164 + CAREER_21_FUTURE_FOCUSED: 'CommonBuffId' = 39504 + CAREER_21_INFORMATION_OVERLOAD: 'CommonBuffId' = 39505 + CAREER_21_LESS_CHORES: 'CommonBuffId' = 38064 + CAREER_21_LOST_SOME_FANS: 'CommonBuffId' = 38221 + CAREER_21_RACKET_ANGUISH: 'CommonBuffId' = 37997 + CAREER_21_SHARED_BISCUITS: 'CommonBuffId' = 75640 + CAREER_21_STUDY_BREAK: 'CommonBuffId' = 39503 + CAREER_22_CHARITABLE_ACTION: 'CommonBuffId' = 37979 + CAREER_22_CHEESY_SPEECH: 'CommonBuffId' = 38165 + CAREER_22_COLA_RUSH: 'CommonBuffId' = 39506 + CAREER_22_CULPRIT_CAUGHT: 'CommonBuffId' = 75643 + CAREER_22_DROPPED_WEAK_LINK: 'CommonBuffId' = 39552 + CAREER_22_MANUSCRIPT_SPOILERS: 'CommonBuffId' = 37978 + CAREER_22_ONGOING_SUGAR_RUSH: 'CommonBuffId' = 39508 + CAREER_22_OVERSLEPT: 'CommonBuffId' = 39507 + CAREER_22_PAINTING_RESTORER: 'CommonBuffId' = 38092 + CAREER_22_SEAT_TAKEN: 'CommonBuffId' = 38222 + CAREER_22_SIGN_TRANSFERRED: 'CommonBuffId' = 75644 + CAREER_22_THOROUGH_THRASHING: 'CommonBuffId' = 37999 + CAREER_23_ANGRY: 'CommonBuffId' = 106898 + CAREER_23_CAR_STUNT_REALITY: 'CommonBuffId' = 38003 + CAREER_23_DUKES_MOMENT: 'CommonBuffId' = 38001 + CAREER_23_FAILED_RUSE: 'CommonBuffId' = 75645 + CAREER_23_FEIGNED_ILLNESS: 'CommonBuffId' = 75646 + CAREER_23_HAPPY_WITH_RESULTS: 'CommonBuffId' = 39515 + CAREER_23_IN_THE_GAMER_ZONE: 'CommonBuffId' = 39553 + CAREER_23_LACKED_MOMENTUM: 'CommonBuffId' = 38095 + CAREER_23_LOWER_SDT_SCORE: 'CommonBuffId' = 39513 + CAREER_23_MOVEMENT_INSPIRATION: 'CommonBuffId' = 38094 + CAREER_23_OVER_PARTIED: 'CommonBuffId' = 39554 + CAREER_23_OVER_THE_TOP: 'CommonBuffId' = 37982 + CAREER_23_TERMINALLY_HOT: 'CommonBuffId' = 38166 + CAREER_23_TOTAL_PERFECTION: 'CommonBuffId' = 39514 + CAREER_23_UNORTHODOX_REPORT: 'CommonBuffId' = 37980 + CAREER_24_AHEAD_OF_RIVAL: 'CommonBuffId' = 39522 + CAREER_24_ANOTHER_LOST_MEAL: 'CommonBuffId' = 75649 + CAREER_24_CLEANED_THE_IVORIES: 'CommonBuffId' = 38227 + CAREER_24_CRITICALLY_ACCLAIMED: 'CommonBuffId' = 38096 + CAREER_24_FALSE_CLAIM: 'CommonBuffId' = 38097 + CAREER_24_FROSTBIT_FINGERS: 'CommonBuffId' = 38006 + CAREER_24_LAXATIVE_LACED_BROWNIE: 'CommonBuffId' = 75648 + CAREER_24_LEFT_EM_BEWILDERED: 'CommonBuffId' = 38005 + CAREER_24_MEMOIRS_CANCELED: 'CommonBuffId' = 38173 + CAREER_24_NEW_NICKNAME: 'CommonBuffId' = 38004 + CAREER_24_NOTEBOOK_RETURNED: 'CommonBuffId' = 39521 + CAREER_24_REWARDED_INSPIRATION: 'CommonBuffId' = 38099 + CAREER_24_SHAMED_BULLY: 'CommonBuffId' = 75647 + CAREER_24_SPY_GAMES: 'CommonBuffId' = 38167 + CAREER_24_STICKY_KEYS: 'CommonBuffId' = 38228 + CAREER_24_TRAP_GIVEN_TO_PRINCIPAL: 'CommonBuffId' = 75650 + CAREER_24_TUTORING_RIVAL: 'CommonBuffId' = 39525 + CAREER_24_UNCOMFORTABLE: 'CommonBuffId' = 106899 + CAREER_24_UNGRATEFUL_RIVAL: 'CommonBuffId' = 39523 + CAREER_25_ANYTHING_FOR_EXPOSURE: 'CommonBuffId' = 38100 + CAREER_25_APPEASED_THE_BRIDE: 'CommonBuffId' = 38229 + CAREER_25_BRIDEZILLA: 'CommonBuffId' = 38230 + CAREER_25_CONFIDENT: 'CommonBuffId' = 106900 + CAREER_25_EMBARRASSED: 'CommonBuffId' = 106964 + CAREER_25_HELPING_THE_COOL_KIDS: 'CommonBuffId' = 75652 + CAREER_25_PASSED_THE_BLAME: 'CommonBuffId' = 38325 + CAREER_25_QUIZASTER: 'CommonBuffId' = 39527 + CAREER_25_SLY_CHEATER: 'CommonBuffId' = 75653 + CAREER_25_STRAIGHT_ARROW_PARTNER: 'CommonBuffId' = 38174 + CAREER_25_TARNISHED_REPUTATION: 'CommonBuffId' = 38101 + CAREER_25_TRUTH_OR_DODGE_BALL: 'CommonBuffId' = 39528 + CAREER_25_UNLUCKY_NUMBER7: 'CommonBuffId' = 38007 + CAREER_25_UNRULY_CLASSMATES: 'CommonBuffId' = 39526 + CAREER_25_VENGEFUL_MODERATOR: 'CommonBuffId' = 39555 + CAREER_26_APPEALING_COMPOSITION: 'CommonBuffId' = 38231 + CAREER_26_BAD_ANSWERS: 'CommonBuffId' = 75584 + CAREER_26_CLASS_COMEDIAN: 'CommonBuffId' = 75592 + CAREER_26_COMPOSITION_IGNORED: 'CommonBuffId' = 38557 + CAREER_26_ENJOYABLE_INTERVIEW: 'CommonBuffId' = 75655 + CAREER_26_GOT_SPOOKED: 'CommonBuffId' = 37983 + CAREER_26_JOB_INSECURITY: 'CommonBuffId' = 38103 + CAREER_26_JOB_SECURITY: 'CommonBuffId' = 38102 + CAREER_26_LONG_INTERVIEW: 'CommonBuffId' = 75654 + CAREER_26_REEVALUATING_KEY_UNDERLINGS: 'CommonBuffId' = 38008 + CAREER_26_TASTE_OF_FAILURE: 'CommonBuffId' = 38177 + CAREER_26_TASTY_SECRETS: 'CommonBuffId' = 38175 + CAREER_27_CONFIDENT: 'CommonBuffId' = 106912 + CAREER_27_DISPERSED_THE_CROWD: 'CommonBuffId' = 38105 + CAREER_27_DREW_A_CROWD: 'CommonBuffId' = 38104 + CAREER_27_EMBARRASSED: 'CommonBuffId' = 106913 + CAREER_27_ENJOYABLE_VACATION: 'CommonBuffId' = 39556 + CAREER_28_ART_IN_THE_DARK: 'CommonBuffId' = 38108 + CAREER_28_BEATEN_BY_SLOB: 'CommonBuffId' = 38233 + CAREER_28_COLLECTION_BONANZA: 'CommonBuffId' = 38106 + CAREER_28_COMPANY_RECOVERING: 'CommonBuffId' = 39558 + CAREER_28_DESPICABLE_CFO: 'CommonBuffId' = 39557 + CAREER_28_HONORARY_WING: 'CommonBuffId' = 38107 + CAREER_28_IN_THE_CLEAR: 'CommonBuffId' = 38178 + CAREER_28_UNDER_SUSPICION: 'CommonBuffId' = 38179 + CAREER_29_COUNTRY_ROCKED: 'CommonBuffId' = 38328 + CAREER_29_ENERGIZED: 'CommonBuffId' = 106914 + CAREER_2_ANGRY: 'CommonBuffId' = 106882 + CAREER_2_FAILED_CALL_OUT: 'CommonBuffId' = 38563 + CAREER_2_GOOD_LAUGH: 'CommonBuffId' = 75583 + CAREER_2_LAUGHING_STOCK: 'CommonBuffId' = 75585 + CAREER_2_ROASTING_A_HACK: 'CommonBuffId' = 38564 + CAREER_2_SILVER_TOUNGED_SLACKER: 'CommonBuffId' = 38550 + CAREER_2_WET_PANTS: 'CommonBuffId' = 75586 + CAREER_30_EMBARRASSED: 'CommonBuffId' = 107442 + CAREER_30_ENERGIZED: 'CommonBuffId' = 107441 + CAREER_30_FAKE_DOCUMENTS: 'CommonBuffId' = 38424 + CAREER_30_KNOWLEDGE_LEAKER: 'CommonBuffId' = 38027 + CAREER_30_NO_CREDIT: 'CommonBuffId' = 38236 + CAREER_31_LOCKED_OUT: 'CommonBuffId' = 38026 + CAREER_31_OVERSTEPPED_FRIENDSHIP: 'CommonBuffId' = 38238 + CAREER_31_SECURITY_CRACKER: 'CommonBuffId' = 38021 + CAREER_32_COVERED_IN_SPITBALLS: 'CommonBuffId' = 38239 + CAREER_32_HAPPY: 'CommonBuffId' = 107440 + CAREER_32_INTERNET_AFLAME: 'CommonBuffId' = 38028 + CAREER_32_SAD: 'CommonBuffId' = 107439 + CAREER_32_SNEAK_PEEK: 'CommonBuffId' = 38030 + CAREER_32_UNBELIEVABLE_SPOILERS: 'CommonBuffId' = 38024 + CAREER_3_A_LITTLE_CHEATING: 'CommonBuffId' = 75587 + CAREER_3_STRESS_FREE_ANSWERING: 'CommonBuffId' = 39711 + CAREER_3_TATTLED_ON: 'CommonBuffId' = 75588 + CAREER_3_UNDER_PREPARED: 'CommonBuffId' = 39448 + CAREER_4_BALLISTIC_WATERMELON_GUM: 'CommonBuffId' = 75593 + CAREER_4_CHEWED_ANOTHERS_GUM: 'CommonBuffId' = 75590 + CAREER_4_DISSECTION_THEFT: 'CommonBuffId' = 39451 + CAREER_4_GENEROUS_FRIENDS: 'CommonBuffId' = 39455 + CAREER_4_ILL_GOTTEN_CHOW: 'CommonBuffId' = 39454 + CAREER_4_SHARED_USED_GUM: 'CommonBuffId' = 75594 + CAREER_4_SOUND_FAILURE: 'CommonBuffId' = 38567 + CAREER_4_WRONGLY_ACCUSED: 'CommonBuffId' = 75591 + CAREER_5_BULLYING_NERD: 'CommonBuffId' = 75595 + CAREER_5_FIRE_ALARM_EXTENSION: 'CommonBuffId' = 39458 + CAREER_5_HAPPY: 'CommonBuffId' = 106884 + CAREER_5_NEW_FRIEND: 'CommonBuffId' = 75597 + CAREER_5_SHORTED: 'CommonBuffId' = 38570 + CAREER_5_TURNED_AWAY_BY_FRIENDS: 'CommonBuffId' = 75596 + CAREER_5_UNCOMFORTABLE: 'CommonBuffId' = 106883 + CAREER_6_FIELD_TRIP: 'CommonBuffId' = 75599 + CAREER_6_FORGED_SIGNATURE: 'CommonBuffId' = 75598 + CAREER_6_FORGED_WRONG_NAME: 'CommonBuffId' = 75600 + CAREER_6_HYSTERICAL_CAULIFLOWER: 'CommonBuffId' = 38574 + CAREER_6_MISSED_FIELD_TRIP: 'CommonBuffId' = 75601 + CAREER_6_TESTING_ANGST: 'CommonBuffId' = 39461 + CAREER_6_UNGUARDED_ANSWERS: 'CommonBuffId' = 39459 + CAREER_7_CHOCOLATE_CHIP_COOKIE: 'CommonBuffId' = 75602 + CAREER_7_FALSELY_ACCUSED: 'CommonBuffId' = 75603 + CAREER_7_STILL_CONFUSED: 'CommonBuffId' = 39462 + CAREER_8_DISCUSSING_FEELINGS: 'CommonBuffId' = 39463 + CAREER_8_FEEBLE_MANAGER: 'CommonBuffId' = 38434 + CAREER_8_HELPED_ANOTHER: 'CommonBuffId' = 75604 + CAREER_8_HYPER_STRESS: 'CommonBuffId' = 39465 + CAREER_8_JUST_TRYING_TO_HELP: 'CommonBuffId' = 75605 + CAREER_8_PARENT_COUNSELOR_MEETING: 'CommonBuffId' = 39464 + CAREER_8_PLAYED_OFF: 'CommonBuffId' = 38579 + CAREER_8_WRONG_COMPANY: 'CommonBuffId' = 38578 + CAREER_9_NO_TIME_FOR_DOODLES: 'CommonBuffId' = 75606 + CAREER_9_REDONE_TEST: 'CommonBuffId' = 75607 + CAREER_9_THIRD_PERIOD_NAP: 'CommonBuffId' = 39469 + CAREER_9_UNCOMFORTABLE: 'CommonBuffId' = 106896 + CAREER_ABANDON_SHIP: 'CommonBuffId' = 37759 + CAREER_ACTIVIST_BREAK_WATCH_PROTEST_HIDDEN: 'CommonBuffId' = 136094 + CAREER_ACTIVIST_CAUSE_SUCCESSFUL_ECONOMY: 'CommonBuffId' = 136398 + CAREER_ACTIVIST_CAUSE_SUCCESSFUL_ENVIRONMENT: 'CommonBuffId' = 136395 + CAREER_ACTIVIST_CAUSE_SUCCESSFUL_JUSTICE: 'CommonBuffId' = 136397 + CAREER_ACTIVIST_CAUSE_SUCCESSFUL_PEACE: 'CommonBuffId' = 136396 + CAREER_ACTIVIST_CAUSE_SUCCESSFUL_TAX: 'CommonBuffId' = 136394 + CAREER_ACTIVIST_CONVINCED_TO_LEAVE_HIDDEN: 'CommonBuffId' = 142143 + CAREER_ACTIVIST_FLIP_FLOP_POLITICS: 'CommonBuffId' = 136613 + CAREER_ACTIVIST_JOB_PERFORMANCE_LUCKY_BREAK: 'CommonBuffId' = 141450 + CAREER_ACTIVIST_JOB_PERFORMANCE_MISTAKE_MADE: 'CommonBuffId' = 141411 + CAREER_ACTIVIST_JOB_PERFORMANCE_REVEAL_TRUTH: 'CommonBuffId' = 141451 + CAREER_ACTIVIST_POLITICAL_PARTISANS: 'CommonBuffId' = 136615 + CAREER_ACTIVIST_POLITICAL_PARTNERS: 'CommonBuffId' = 136614 + CAREER_ACTIVIST_POLITICIAN_APPROVAL: 'CommonBuffId' = 135696 + CAREER_ACTIVIST_POLITICIAN_APPROVAL_FROM_KISS_BABY: 'CommonBuffId' = 135825 + CAREER_ACTIVIST_POLITICIAN_GAMES: 'CommonBuffId' = 135697 + CAREER_ACTIVIST_PROMPT_CHOOSE_CAUSE: 'CommonBuffId' = 141181 + CAREER_ACTIVIST_PROMPT_CHOOSE_CAUSE_TIMER_HIDDEN: 'CommonBuffId' = 141173 + CAREER_ACTIVIST_PROTESTING_HIDDEN: 'CommonBuffId' = 135895 + CAREER_ACTIVIST_PROTEST_JOINED_OR_WATCHED_HIDDEN: 'CommonBuffId' = 147859 + CAREER_ACTIVIST_QUIT_JOB_HIDDEN: 'CommonBuffId' = 154532 + CAREER_ACTIVIST_UNETHICAL_BRIBE: 'CommonBuffId' = 135868 + CAREER_ACTIVIST_WATCH_PROTEST_COOLDOWN: 'CommonBuffId' = 155609 + CAREER_ADVICE_FAIL: 'CommonBuffId' = 32554 + CAREER_ADVICE_FIXED: 'CommonBuffId' = 32553 + CAREER_AGENCY_HERO: 'CommonBuffId' = 32120 + CAREER_ALIEN_CONTACT: 'CommonBuffId' = 37774 + CAREER_ANGRY_EMPLOYEES: 'CommonBuffId' = 33991 + CAREER_ATHLETE_COMPETITIVE_EDGE: 'CommonBuffId' = 107183 + CAREER_ATHLETE_OVER_AWED_BY_OPPONENTS: 'CommonBuffId' = 107182 + CAREER_ATHLETE_PUMPED: 'CommonBuffId' = 107181 + CAREER_ATHLETE_STATISTICAL_FERVOR: 'CommonBuffId' = 107179 + CAREER_ATHLETE_STATISTICAL_RAGE: 'CommonBuffId' = 107180 + CAREER_ATTENDANCE_CLASSES: 'CommonBuffId' = 34038 + CAREER_A_CAUSE_FOR_APPLAUSE: 'CommonBuffId' = 31364 + CAREER_BAD_MATH: 'CommonBuffId' = 38112 + CAREER_BAG_OF_POO: 'CommonBuffId' = 33024 + CAREER_BLOG_DEBUNKED: 'CommonBuffId' = 32533 + CAREER_BLOG_PLAGIARIST: 'CommonBuffId' = 32549 + CAREER_BLUFFING_BLUNDER: 'CommonBuffId' = 32170 + CAREER_BROWSE_INTELLIGENCE_DB_BORED: 'CommonBuffId' = 34150 + CAREER_BROWSE_INTELLIGENCE_DB_EMBARRASSED: 'CommonBuffId' = 34149 + CAREER_BROWSE_INTELLIGENCE_DB_WORK_PERF: 'CommonBuffId' = 34148 + CAREER_BUSINESS_21_CONFIDENT: 'CommonBuffId' = 108001 + CAREER_BUSINESS_22_HAPPY: 'CommonBuffId' = 108002 + CAREER_BUSINESS_23_CONFIDENT: 'CommonBuffId' = 108003 + CAREER_BUSINESS_27_PASS_THE_BLAME_EVIL: 'CommonBuffId' = 108006 + CAREER_BUSINESS_27_PASS_THE_BLAME_NORMAL: 'CommonBuffId' = 108005 + CAREER_BUSINESS_8_CLOSE_BRANCH_EVIL: 'CommonBuffId' = 107722 + CAREER_BUSINESS_8_CLOSE_BRANCH_NORMAL: 'CommonBuffId' = 107723 + CAREER_BUSINESS_8_CUT_BONUSES_EVIL: 'CommonBuffId' = 107721 + CAREER_BUSINESS_8_CUT_BONUSES_NORMAL: 'CommonBuffId' = 107720 + CAREER_BUSINESS_AGGRAVATED_BY_BLOWHARD: 'CommonBuffId' = 109063 + CAREER_BUSINESS_BLEW_THE_DEAL: 'CommonBuffId' = 108532 + CAREER_BUSINESS_FEELING_IMPORTANT: 'CommonBuffId' = 109061 + CAREER_BUSINESS_HIDDEN_INVESTED: 'CommonBuffId' = 110140 + CAREER_BUSINESS_HIDDEN_INVESTMENT_LOSE_A_BIT_1000: 'CommonBuffId' = 110104 + CAREER_BUSINESS_HIDDEN_INVESTMENT_LOSE_A_BIT_2000: 'CommonBuffId' = 110105 + CAREER_BUSINESS_HIDDEN_INVESTMENT_LOSE_A_BIT_5000: 'CommonBuffId' = 110114 + CAREER_BUSINESS_HIDDEN_INVESTMENT_LOSE_BIG_1000: 'CommonBuffId' = 110115 + CAREER_BUSINESS_HIDDEN_INVESTMENT_LOSE_BIG_2000: 'CommonBuffId' = 110116 + CAREER_BUSINESS_HIDDEN_INVESTMENT_LOSE_BIG_5000: 'CommonBuffId' = 110117 + CAREER_BUSINESS_HIDDEN_INVESTMENT_STAY_EVEN_1000: 'CommonBuffId' = 110118 + CAREER_BUSINESS_HIDDEN_INVESTMENT_STAY_EVEN_2000: 'CommonBuffId' = 110106 + CAREER_BUSINESS_HIDDEN_INVESTMENT_STAY_EVEN_5000: 'CommonBuffId' = 110107 + CAREER_BUSINESS_HIDDEN_INVESTMENT_WIN_A_BIT_1000: 'CommonBuffId' = 110108 + CAREER_BUSINESS_HIDDEN_INVESTMENT_WIN_A_BIT_2000: 'CommonBuffId' = 110109 + CAREER_BUSINESS_HIDDEN_INVESTMENT_WIN_A_BIT_5000: 'CommonBuffId' = 110110 + CAREER_BUSINESS_HIDDEN_INVESTMENT_WIN_BIG_1000: 'CommonBuffId' = 110111 + CAREER_BUSINESS_HIDDEN_INVESTMENT_WIN_BIG_2000: 'CommonBuffId' = 110112 + CAREER_BUSINESS_HIDDEN_INVESTMENT_WIN_BIG_5000: 'CommonBuffId' = 110113 + CAREER_BUSINESS_MADE_THE_SALE: 'CommonBuffId' = 108531 + CAREER_BUSINESS_NUMBERS: 'CommonBuffId' = 108530 + CAREER_BUSINESS_ON_TOP_OF_THE_MARKET: 'CommonBuffId' = 108543 + CAREER_BUSINESS_PAPERWORK_DRUDGERY: 'CommonBuffId' = 108529 + CAREER_BUSINESS_SHOT_DOWN: 'CommonBuffId' = 109062 + CAREER_CALCULATED_OUT: 'CommonBuffId' = 27935 + CAREER_CANT_GET_ME_DOWN: 'CommonBuffId' = 36048 + CAREER_CAPSULE_PLAYFUL: 'CommonBuffId' = 37738 + CAREER_CAPSULE_SICKNESS: 'CommonBuffId' = 28102 + CAREER_CARGO_DUMPED: 'CommonBuffId' = 37767 + CAREER_CAUGHT_GOUGING: 'CommonBuffId' = 100442 + CAREER_CELEBRITY_SLIGHTING: 'CommonBuffId' = 31239 + CAREER_CHEESE_LOVE: 'CommonBuffId' = 28536 + CAREER_CHEWED_OUT: 'CommonBuffId' = 37772 + CAREER_CIVIL_DESIGNER_CONCEPT_GAVE_FEEDBACK: 'CommonBuffId' = 237393 + CAREER_CIVIL_DESIGNER_CONCEPT_SOLID_DESIGNS: 'CommonBuffId' = 237394 + CAREER_CIVIL_DESIGNER_CONCEPT_SUBMIT_FAIL: 'CommonBuffId' = 234319 + CAREER_CIVIL_DESIGNER_CONCEPT_SUBMIT_SUCCESS: 'CommonBuffId' = 234320 + CAREER_CIVIL_DESIGNER_CONCEPT_SUBMIT_TED_ECO_INVENTION: 'CommonBuffId' = 234334 + CAREER_CIVIL_DESIGNER_CONCEPT_SUBMIT_TED_GREAT: 'CommonBuffId' = 234279 + CAREER_CIVIL_DESIGNER_CONCEPT_SUBMIT_TED_OKAY: 'CommonBuffId' = 234270 + CAREER_CIVIL_DESIGNER_CONCEPT_SUBMIT_TED_OUTSTANDING: 'CommonBuffId' = 234289 + CAREER_CIVIL_DESIGNER_CONCEPT_SUBMIT_TED_PERFECT: 'CommonBuffId' = 234290 + CAREER_CIVIL_DESIGNER_CONCEPT_SUBMIT_TED_POOR: 'CommonBuffId' = 234269 + CAREER_CIVIL_DESIGNER_COOLDOWN_RALLY: 'CommonBuffId' = 239193 + CAREER_CIVIL_DESIGNER_INTERVIEW_COOLDOWN_CIVIC_POLICIES: 'CommonBuffId' = 237481 + CAREER_CIVIL_DESIGNER_INTERVIEW_COOLDOWN_UTILITIES: 'CommonBuffId' = 239096 + CAREER_CIVIL_DESIGNER_RALLY_FAILED_TO_RALLY: 'CommonBuffId' = 237395 + CAREER_CIVIL_DESIGNER_SMOG_VACUUM_THERE_GOES_THE_NEIGHBORHOOD: 'CommonBuffId' = 234702 + CAREER_CIVIL_DESIGNER_TRAIT_CHAMPION_OF_THE_PEOPLE: 'CommonBuffId' = 234581 + CAREER_CIVIL_DESIGNER_TRAIT_ECO_ENGINEER: 'CommonBuffId' = 234584 + CAREER_CIVIL_DESIGNER_UNLOCK_FOOD_REWARD_RECIPES: 'CommonBuffId' = 235569 + CAREER_CIVIL_DESIGNER_VOTE_TRACKING_COMMUNITY_SPACE: 'CommonBuffId' = 240332 + CAREER_CIVIL_DESIGNER_VOTE_TRACKING_NEIGHBORHOOD_RENOVATION: 'CommonBuffId' = 240333 + CAREER_CIVIL_DESIGNER_WATCHING_RALLY: 'CommonBuffId' = 233519 + CAREER_CLEAN_VICTORY: 'CommonBuffId' = 31507 + CAREER_CONFRONTED_BY_COWORKER: 'CommonBuffId' = 33986 + CAREER_CONSERVATIONIST_AWAY_ACTIONS_BORED: 'CommonBuffId' = 209830 + CAREER_CONSERVATIONIST_AWAY_ACTIONS_PLAYFUL: 'CommonBuffId' = 209832 + CAREER_CONSERVATIONIST_AWAY_ACTIONS_UNCOMFORTABLE: 'CommonBuffId' = 209833 + CAREER_CONSERVATIONIST_CONSERVATION_AWARENESS_BORING_CONVERSATION: 'CommonBuffId' = 205160 + CAREER_CONSERVATIONIST_CONSERVATION_AWARENESS_CONSERVATION_KNOWLEDGE: 'CommonBuffId' = 205159 + CAREER_CONSERVATIONIST_CONSERVATION_AWARENESS_NOONE_LISTENING: 'CommonBuffId' = 205166 + CAREER_CONSERVATIONIST_CONSERVATION_AWARENESS_SPREADING_AWARENESS: 'CommonBuffId' = 205165 + CAREER_CONSERVATIONIST_CONSULT_REGULATION_COOLDOWN: 'CommonBuffId' = 211688 + CAREER_CONSERVATIONIST_CONSULT_REGULATION_GENERAL_ACCUSED_OF_WRONGDOING: 'CommonBuffId' = 206384 + CAREER_CONSERVATIONIST_CONSULT_REGULATION_LITTERING_ACCUSE_OF_LITTERING_COOLDOWN: 'CommonBuffId' = 212325 + CAREER_CONSERVATIONIST_CONSULT_REGULATION_ORGANIC_PRODUCE_EATING_ORGANIC: 'CommonBuffId' = 209822 + CAREER_CONSERVATIONIST_CONSULT_REGULATION_OVERFISHING_CAUGHT_FISHING_ILLEGALLY: 'CommonBuffId' = 209825 + CAREER_CONSERVATIONIST_CONSULT_REGULATION_OVERFISHING_ENFORCED_POLICY: 'CommonBuffId' = 206307 + CAREER_CONSERVATIONIST_CONSULT_REGULATION_OVERFISHING_FINED_FOR_FISHING: 'CommonBuffId' = 207055 + CAREER_CONSERVATIONIST_CONSULT_REGULATION_OVERFISHING_FISHING_ALLOWED: 'CommonBuffId' = 206308 + CAREER_CONSERVATIONIST_CONSULT_REGULATION_OVERFISHING_STOP_FISHING: 'CommonBuffId' = 206305 + CAREER_CONSERVATIONIST_CONSULT_REGULATION_REGULATION_COMPLETE: 'CommonBuffId' = 206280 + CAREER_CONSERVATIONIST_DISCOVERED_NEW_SPECIES: 'CommonBuffId' = 209924 + CAREER_CONSERVATIONIST_SPRAY_INVASIVE_SPECIES_INVASIVE_SPECIES_EXTERMINATOR: 'CommonBuffId' = 209823 + CAREER_CONSERVATIONIST_SUBMIT_GRANT_APPLICATION_FLUBBED_ATTEMPT: 'CommonBuffId' = 205741 + CAREER_CONSERVATIONIST_TAKE_SAMPLE_COOLDOWN_HIDDEN: 'CommonBuffId' = 210720 + CAREER_CONSERVATIONIST_TRAIT_FRIEND_OF_THE_SEA: 'CommonBuffId' = 207855 + CAREER_CORPORATE_WORKER_BRAIN_FRIED: 'CommonBuffId' = 248612 + CAREER_CORPORATE_WORKER_COMPANY_AMBASSADOR: 'CommonBuffId' = 248610 + CAREER_CORPORATE_WORKER_FAILED_ATTEMPT: 'CommonBuffId' = 248846 + CAREER_CORPORATE_WORKER_FIRED_UP_FOR_SUCCESS: 'CommonBuffId' = 248608 + CAREER_CORPORATE_WORKER_INSPIRATION_AND_PERSPIRATION: 'CommonBuffId' = 248609 + CAREER_CORPORATE_WORKER_JUICED: 'CommonBuffId' = 248845 + CAREER_CORPORATE_WORKER_LUCKY_ESCAPE: 'CommonBuffId' = 253824 + CAREER_CORPORATE_WORKER_ONE_OF_US: 'CommonBuffId' = 248611 + CAREER_CORPORATE_WORKER_OUT_LATE_SHAME: 'CommonBuffId' = 248811 + CAREER_CORPORATE_WORKER_OUT_LATE_TIMER: 'CommonBuffId' = 254397 + CAREER_CORPORATE_WORKER_TRAIT_CHARISMATIC_CROONER: 'CommonBuffId' = 249170 + CAREER_CORPORATE_WORKER_TRAIT_LEGENDARY_STAMINA: 'CommonBuffId' = 249175 + CAREER_CORPORATE_WORKER_UNLOCK_AMAZAKE: 'CommonBuffId' = 248994 + CAREER_CORPORATE_WORKER_UNLOCK_CHICKEN_YAKITORI: 'CommonBuffId' = 249015 + CAREER_CORPORATE_WORKER_UNLOCK_ENERGY_CRUSH: 'CommonBuffId' = 249014 + CAREER_CORPORATE_WORKER_WORKING_OVERTIME: 'CommonBuffId' = 248802 + CAREER_COUNTER_OPINION_DEBATE: 'CommonBuffId' = 33835 + CAREER_COUNTER_OPINION_DISMISSED: 'CommonBuffId' = 33833 + CAREER_CREATIVELY_DRAINED: 'CommonBuffId' = 31224 + CAREER_CRIMINAL_BANK_BLUEPRINT_INSIDE_SCOOP: 'CommonBuffId' = 33953 + CAREER_CRIMINAL_HACK_MAINFRAME_PATCHED_IN: 'CommonBuffId' = 33971 + CAREER_CRITIC_ENTHUSIASTIC_ABOUT_FOOD: 'CommonBuffId' = 137456 + CAREER_CRITIC_ENTHUSIASTIC_ABOUT_FOOD_HIDDEN: 'CommonBuffId' = 137468 + CAREER_CRITIC_HAS_BEEN_TO_FESTIVAL: 'CommonBuffId' = 138309 + CAREER_CRITIC_INSPIRED_GAIN_COOLDOWN: 'CommonBuffId' = 137763 + CAREER_CRITIC_PRAISED: 'CommonBuffId' = 139910 + CAREER_CRITIC_REVIEWED_BAD_DRINK: 'CommonBuffId' = 153063 + CAREER_CRITIC_REVIEWED_BAD_FOOD: 'CommonBuffId' = 137799 + CAREER_CRITIC_REVIEWED_BAD_PERFORMANCE: 'CommonBuffId' = 137907 + CAREER_CRITIC_REVIEWED_GOOD_DRINK: 'CommonBuffId' = 153062 + CAREER_CRITIC_REVIEWED_GOOD_FOOD: 'CommonBuffId' = 137798 + CAREER_CRITIC_REVIEWED_GOOD_PERFORMANCE: 'CommonBuffId' = 137908 + CAREER_CRITIC_REVIEWING_FOOD: 'CommonBuffId' = 137795 + CAREER_CRITIC_SNUBBED: 'CommonBuffId' = 137649 + CAREER_CRITIC_STUDIED_ART: 'CommonBuffId' = 137722 + CAREER_CRITIC_THAT_FOOD_MUST_BE_AWFUL: 'CommonBuffId' = 137560 + CAREER_CRITIC_WRITE_COLUMN_BOOST: 'CommonBuffId' = 152336 + CAREER_DAILY_TASK_COMPLETE_HIDDEN: 'CommonBuffId' = 288788 + CAREER_DEBRIS_COVERED_PATROLLER: 'CommonBuffId' = 37787 + CAREER_DECIMAL_FIXED: 'CommonBuffId' = 33089 + CAREER_DETECTIVE_APB_SUSPECT: 'CommonBuffId' = 111874 + CAREER_DETECTIVE_CAN_GET_CITATION: 'CommonBuffId' = 109484 + CAREER_DETECTIVE_CRACKING_THE_CASE: 'CommonBuffId' = 116203 + CAREER_DETECTIVE_DAY02_ALLOW_APB: 'CommonBuffId' = 116738 + CAREER_DETECTIVE_DUNCE_DUCTION: 'CommonBuffId' = 116206 + CAREER_DETECTIVE_FINISHED_INTERROGATION: 'CommonBuffId' = 113758 + CAREER_DETECTIVE_INTERROGATING_GUILTY_SUSPECT: 'CommonBuffId' = 113855 + CAREER_DETECTIVE_INTERROGATING_INNOCENT_SUSPECT: 'CommonBuffId' = 113854 + CAREER_DETECTIVE_NPC_REPORT_TAKEN: 'CommonBuffId' = 114579 + CAREER_DETECTIVE_ROLE_STATIC_COMMODITY_BUFFS_POLICE_STATION_CHIEF: 'CommonBuffId' = 116694 + CAREER_DETECTIVE_ROLE_STATIC_COMMODITY_BUFFS_POLICE_STATION_CIVILIAN: 'CommonBuffId' = 116347 + CAREER_DETECTIVE_ROLE_STATIC_COMMODITY_BUFFS_POLICE_STATION_LAB_TECH: 'CommonBuffId' = 115815 + CAREER_DETECTIVE_ROLE_STATIC_COMMODITY_BUFFS_POLICE_STATION_RECEPTIONIST: 'CommonBuffId' = 114826 + CAREER_DETECTIVE_SOLVED_CASE_RECENTLY: 'CommonBuffId' = 113109 + CAREER_DETECTIVE_UNCOMFORTABLE_SEARCH: 'CommonBuffId' = 110639 + CAREER_DETECTIVE_USED_CHEMICAL_ANALYZER: 'CommonBuffId' = 112552 + CAREER_DETECTIVE_WENT_TO_CRIME_SCENE: 'CommonBuffId' = 112551 + CAREER_DIABOLIC_PRESENTER: 'CommonBuffId' = 32367 + CAREER_DISAPPOINTING_ENCOUNTER: 'CommonBuffId' = 31377 + CAREER_DONATE_EARLY_WORK_ACCEPTED: 'CommonBuffId' = 34014 + CAREER_DONATE_EARLY_WORK_REJECTED: 'CommonBuffId' = 34016 + CAREER_DONATE_RECENT_WORK: 'CommonBuffId' = 34015 + CAREER_DOUBLE_ARREST: 'CommonBuffId' = 37828 + CAREER_DREADFUL_DISPLAY: 'CommonBuffId' = 32371 + CAREER_DREW_A_BLANK: 'CommonBuffId' = 31412 + CAREER_EARNED_PROMOTION: 'CommonBuffId' = 125702 + CAREER_EDGY_PIECE_ACCEPTED: 'CommonBuffId' = 33830 + CAREER_EDGY_PIECE_REJECTED: 'CommonBuffId' = 33831 + CAREER_EDIT_PAINTING_BETTER: 'CommonBuffId' = 33843 + CAREER_EDIT_PAINTING_WORSE: 'CommonBuffId' = 33845 + CAREER_EDUCATION_DONATION_ASK_COOLDOWN: 'CommonBuffId' = 221061 + CAREER_EDUCATION_FINISHED_TUTORING: 'CommonBuffId' = 220221 + CAREER_EDUCATION_VISIBLE_ALL_PLANNED_OUT: 'CommonBuffId' = 220294 + CAREER_EDUCATION_VISIBLE_BUDGETED: 'CommonBuffId' = 220295 + CAREER_EDUCATION_VISIBLE_EVERYTHINGS_ADDING_UP: 'CommonBuffId' = 220292 + CAREER_EDUCATION_VISIBLE_FEELING_PREPARED: 'CommonBuffId' = 220302 + CAREER_EDUCATION_VISIBLE_MADE_THE_GRADE: 'CommonBuffId' = 224612 + CAREER_EDUCATION_VISIBLE_MANY_HANDS: 'CommonBuffId' = 220994 + CAREER_EDUCATION_VISIBLE_PREPARED_TO_TEACH: 'CommonBuffId' = 220290 + CAREER_EDUCATION_VISIBLE_TEACHEM: 'CommonBuffId' = 227628 + CAREER_EDUCATION_VOLUNTEER_ASK_COOLDOWN: 'CommonBuffId' = 221062 + CAREER_EMPTY_HANDED: 'CommonBuffId' = 37809 + CAREER_ENGINEER_COMPUTER_DESIGNER: 'CommonBuffId' = 221157 + CAREER_ENGINEER_ENGINEERING_EDUCATION: 'CommonBuffId' = 221158 + CAREER_ENGINEER_EXHILARATED_ENGINEER: 'CommonBuffId' = 228427 + CAREER_ENGINEER_FOCUS_TESTED: 'CommonBuffId' = 221155 + CAREER_ENGINEER_OBJECT_REWARD_1: 'CommonBuffId' = 221170 + CAREER_ENGINEER_OBJECT_REWARD_2: 'CommonBuffId' = 221184 + CAREER_ENGINEER_TECH_TINKERER: 'CommonBuffId' = 222424 + CAREER_ENGINEER_TRIPLE_CHECKED: 'CommonBuffId' = 221163 + CAREER_ENTERTAINER_SOME_INSPIRATION: 'CommonBuffId' = 35995 + CAREER_EXAMINE_FAILED: 'CommonBuffId' = 37747 + CAREER_EXCELLENT_XXULYPS: 'CommonBuffId' = 37781 + CAREER_EXOTIC_JUICE_SUCCESS: 'CommonBuffId' = 33496 + CAREER_EXPERIMENTAL_ACCEPTED: 'CommonBuffId' = 34010 + CAREER_EXPERIMENTAL_REJECTED: 'CommonBuffId' = 34009 + CAREER_E_SPORTS_ASSEMBLE_THE_TEAM_COOLDOWN: 'CommonBuffId' = 227369 + CAREER_E_SPORTS_MATCH_SOON: 'CommonBuffId' = 227179 + CAREER_E_SPORTS_NOT_ENROLLED: 'CommonBuffId' = 230302 + CAREER_E_SPORTS_PLAYED_WITH_TEAM: 'CommonBuffId' = 226931 + CAREER_E_SPORTS_RECIEVED_DRAMA_NODE_FRI: 'CommonBuffId' = 228246 + CAREER_E_SPORTS_RECIEVED_DRAMA_NODE_SAT: 'CommonBuffId' = 228248 + CAREER_E_SPORTS_TEAMMATE_AUTONOMY: 'CommonBuffId' = 227364 + CAREER_E_SPORTS_VISIBLE_ALWAYS_NEXT_TIME: 'CommonBuffId' = 226601 + CAREER_E_SPORTS_VISIBLE_E_LEGEND: 'CommonBuffId' = 226606 + CAREER_E_SPORTS_VISIBLE_E_SUCCESS: 'CommonBuffId' = 226604 + CAREER_E_SPORTS_VISIBLE_E_VICTORY: 'CommonBuffId' = 226605 + CAREER_E_SPORTS_VISIBLE_POWER_DIPPING: 'CommonBuffId' = 226607 + CAREER_E_SPORTS_VISIBLE_POWER_SIPPING: 'CommonBuffId' = 226596 + CAREER_E_SPORTS_VISIBLE_POWER_SIPPING_INFERNO: 'CommonBuffId' = 226599 + CAREER_E_SPORTS_VISIBLE_POWER_SITTING: 'CommonBuffId' = 226597 + CAREER_E_SPORTS_VISIBLE_READY_TO_SCUFFLE: 'CommonBuffId' = 226598 + CAREER_E_SPORTS_VISIBLE_TEAM_PLAYER: 'CommonBuffId' = 226595 + CAREER_FAN_KICK_OUT_FAILURE: 'CommonBuffId' = 33477 + CAREER_FAN_KICK_OUT_SUCCESS: 'CommonBuffId' = 33478 + CAREER_FIRED: 'CommonBuffId' = 97449 + CAREER_FIRED_AMBITIOUS: 'CommonBuffId' = 97450 + CAREER_FIRED_INTERIOR_DECORATOR_INTERVIEW_BY_ENEMY: 'CommonBuffId' = 257719 + CAREER_FISHERMAN_AWAY_ACTIONS_HAPPY: 'CommonBuffId' = 210267 + CAREER_FISHERMAN_AWAY_ACTIONS_TENSE: 'CommonBuffId' = 211689 + CAREER_FORMULA_DISCOVERY: 'CommonBuffId' = 37735 + CAREER_FORTUNATE_OUTCOME: 'CommonBuffId' = 37786 + CAREER_FORUM_ENCRYPTED: 'CommonBuffId' = 33078 + CAREER_FORUM_POST_PICS: 'CommonBuffId' = 33077 + CAREER_FREELANCER_ARTIST_STELLAR_STUDENTS: 'CommonBuffId' = 208709 + CAREER_FREELANCER_ARTIST_UNRULY_CLASS: 'CommonBuffId' = 208708 + CAREER_FREELANCER_CLEAR_GOALS: 'CommonBuffId' = 208706 + CAREER_FREELANCER_GREAT_SESSION: 'CommonBuffId' = 208239 + CAREER_FREELANCER_HIDDEN_MET_WITH_CLIENT_CLASS: 'CommonBuffId' = 211962 + CAREER_FREELANCER_INSTRUCTIONS_UNCLEAR: 'CommonBuffId' = 208705 + CAREER_FREELANCER_OVERCLOCKED_PC: 'CommonBuffId' = 208696 + CAREER_FREELANCER_PROGRAMMER_RUDE_CLIENT: 'CommonBuffId' = 208228 + CAREER_FREELANCER_PROGRAMMER_SHARED_VISION: 'CommonBuffId' = 208229 + CAREER_FREELANCER_TERRIBLE_SESSION: 'CommonBuffId' = 208238 + CAREER_GARDENER_ACADEMIC_FAME_HAPPY: 'CommonBuffId' = 187041 + CAREER_GARDENER_BACK_TO_ROOTS_HAPPY: 'CommonBuffId' = 187038 + CAREER_GARDENER_DESIGN_CLASS_INSPIRED: 'CommonBuffId' = 187044 + CAREER_GARDENER_FLORAL_FIGHT_ANGRY: 'CommonBuffId' = 191624 + CAREER_GARDENER_FLORIST_CLIENTELE_FOCUSED: 'CommonBuffId' = 187040 + CAREER_GARDENER_HANDS_ON_APPROACH_ENERGIZED: 'CommonBuffId' = 187043 + CAREER_GARDENER_NATURE_WALK_ENERGIZED: 'CommonBuffId' = 187039 + CAREER_GARDENER_POOR_PROPOSAL_EMBARRASSED: 'CommonBuffId' = 187042 + CAREER_GARDENER_READ_ANGRY_LOW: 'CommonBuffId' = 191191 + CAREER_GARDENER_WRITING_PRAISED: 'CommonBuffId' = 191192 + CAREER_GLORZAK_BUST: 'CommonBuffId' = 37776 + CAREER_GOOD_INSTINCTS: 'CommonBuffId' = 37770 + CAREER_GOT_NEW_JOB: 'CommonBuffId' = 125723 + CAREER_GUARD_CLOSE_CALL: 'CommonBuffId' = 33043 + CAREER_GUARD_KO: 'CommonBuffId' = 33042 + CAREER_GUARD_SPOTTED: 'CommonBuffId' = 33045 + CAREER_HANDY_PERSON_ATTEND_LOCAL_ISSUE_COOLDOWN_HIDDEN: 'CommonBuffId' = 354675 + CAREER_HANDY_PERSON_BAD_COMPLAIN: 'CommonBuffId' = 353754 + CAREER_HANDY_PERSON_BODGE_JOB: 'CommonBuffId' = 353753 + CAREER_HANDY_PERSON_CLOSE_CALL: 'CommonBuffId' = 354269 + CAREER_HANDY_PERSON_CLOSE_ONE: 'CommonBuffId' = 354262 + CAREER_HANDY_PERSON_COMPLAIN_DONE_HIDDEN: 'CommonBuffId' = 354270 + CAREER_HANDY_PERSON_COMPLAIN_READY_HIDDEN: 'CommonBuffId' = 354261 + CAREER_HANDY_PERSON_DISHONEST: 'CommonBuffId' = 354265 + CAREER_HANDY_PERSON_HANDY_INJURY: 'CommonBuffId' = 354264 + CAREER_HANDY_PERSON_HAPPY_RESIDENT: 'CommonBuffId' = 353752 + CAREER_HANDY_PERSON_HONEST: 'CommonBuffId' = 354263 + CAREER_HANDY_PERSON_MASTER_HANDER: 'CommonBuffId' = 354268 + CAREER_HANDY_PERSON_NOT_SO_ACCURATE: 'CommonBuffId' = 354267 + CAREER_HANDY_PERSON_RESEARCH_REPAIR: 'CommonBuffId' = 353751 + CAREER_HANDY_PERSON_TRAINED_HANDY: 'CommonBuffId' = 354266 + CAREER_HARSH_REVIEW_ACCEPTED: 'CommonBuffId' = 34030 + CAREER_HARSH_REVIEW_REJECTED: 'CommonBuffId' = 34032 + CAREER_HECKLED_ON_STAGE: 'CommonBuffId' = 31189 + CAREER_HEIST_NEWBIE_SLEEPS: 'CommonBuffId' = 33063 + CAREER_HEIST_NOT_ENOUGH_SIMS: 'CommonBuffId' = 33067 + CAREER_HEIST_SUCCESS: 'CommonBuffId' = 33065 + CAREER_HIGH_SCHOOL_EXPELLED: 'CommonBuffId' = 298687 + CAREER_HIGH_SCHOOL_TEAM_BIG_WIN: 'CommonBuffId' = 277198 + CAREER_HIGH_SCHOOL_TEAM_HYPED: 'CommonBuffId' = 277196 + CAREER_HIGH_SCHOOL_TEAM_MAJOR_LOSS: 'CommonBuffId' = 277197 + CAREER_HIGH_STAKES_FAILURE: 'CommonBuffId' = 37755 + CAREER_HIGH_STAKES_SUCCESS: 'CommonBuffId' = 37752 + CAREER_HOW_IS_IT: 'CommonBuffId' = 37799 + CAREER_IDEA_THIEF: 'CommonBuffId' = 32555 + CAREER_IMPRESSIVE_INTERROGATION: 'CommonBuffId' = 32165 + CAREER_IMPRESSIVE_ROUTINE: 'CommonBuffId' = 31407 + CAREER_INFORMATION_FREE: 'CommonBuffId' = 33079 + CAREER_INFORMATION_SECURE: 'CommonBuffId' = 33080 + CAREER_INKED_BY_SPACE_SQUID: 'CommonBuffId' = 28112 + CAREER_INTERIOR_DECORATOR_BAD_BEHAVIOR_TRACKER: 'CommonBuffId' = 257432 + CAREER_INTERIOR_DECORATOR_COMMERICAL_GIG_COMPLETE: 'CommonBuffId' = 267264 + CAREER_INTERIOR_DECORATOR_FOLLOW_UP_CLIENT_CALL_DO_SOMETHING_DEBUG: 'CommonBuffId' = 261306 + CAREER_INTERIOR_DECORATOR_FOLLOW_UP_CLIENT_CALL_NOTE_LETTER_PENDING: 'CommonBuffId' = 255193 + CAREER_INTERIOR_DECORATOR_FOLLOW_UP_CLIENT_CALL_NOTE_RECENT_CALL_OR_LETTER: 'CommonBuffId' = 269324 + CAREER_INTERIOR_DECORATOR_FOLLOW_UP_COMMERCIAL_VENUE: 'CommonBuffId' = 255194 + CAREER_INTERIOR_DECORATOR_FOLLOW_UP_COMMERCIAL_VENUE_NEGATIVE: 'CommonBuffId' = 258311 + CAREER_INTERIOR_DECORATOR_FOLLOW_UP_COMMERCIAL_VENUE_POSITIVE: 'CommonBuffId' = 255195 + CAREER_INTERIOR_DECORATOR_FOLLOW_UP_SPONSORSHIP_COOLDOWN: 'CommonBuffId' = 258049 + CAREER_INTERIOR_DECORATOR_FOLLOW_UP_SPONSORSHIP_PACKAGE_PENDING: 'CommonBuffId' = 257995 + CAREER_INTERIOR_DECORATOR_FOLLOW_UP_TV_COOLDOWN: 'CommonBuffId' = 258075 + CAREER_INTERIOR_DECORATOR_FOLLOW_UP_TV_EXIT_TO_WATCH_SHOW: 'CommonBuffId' = 259498 + CAREER_INTERIOR_DECORATOR_FOLLOW_UP_TV_HOME_DECORATING_CHANNEL_NEGATIVE: 'CommonBuffId' = 258500 + CAREER_INTERIOR_DECORATOR_FOLLOW_UP_TV_HOME_DECORATING_CHANNEL_POSITIVE: 'CommonBuffId' = 258499 + CAREER_INTERIOR_DECORATOR_FOLLOW_UP_TV_TO_BE_FEATURED_NEGATIVE: 'CommonBuffId' = 258341 + CAREER_INTERIOR_DECORATOR_FOLLOW_UP_TV_TO_BE_FEATURED_POSITIVE: 'CommonBuffId' = 258051 + CAREER_INTERIOR_DECORATOR_FOLLOW_UP_TV_WAS_NOTIFIED: 'CommonBuffId' = 259632 + CAREER_INTERIOR_DECORATOR_GIG_COMPLETE: 'CommonBuffId' = 267263 + CAREER_INTERIOR_DECORATOR_HIDE_CLIENTS: 'CommonBuffId' = 263614 + CAREER_INTERIOR_DECORATOR_HIDE_CLIENTS_ROLE: 'CommonBuffId' = 261335 + CAREER_INTERIOR_DECORATOR_HIDE_CLIENTS_SITUATION: 'CommonBuffId' = 261867 + CAREER_INTERIOR_DECORATOR_HIDE_CLIENTS_SITUATION_NO_HOUSEHOLD: 'CommonBuffId' = 264520 + CAREER_INTERIOR_DECORATOR_INTERVIEW_BAD_BEHAVIOR_FIRE_ME: 'CommonBuffId' = 257376 + CAREER_INTERIOR_DECORATOR_INTERVIEW_GIG_CANCELLED: 'CommonBuffId' = 257713 + CAREER_INTERIOR_DECORATOR_INTERVIEW_LEARNED_INFO_1: 'CommonBuffId' = 260037 + CAREER_INTERIOR_DECORATOR_INTERVIEW_LEARNED_INFO_2: 'CommonBuffId' = 260038 + CAREER_INTERIOR_DECORATOR_INTERVIEW_LEARNED_INFO_GUARANTEED_SUCCESS_COOLDOWN: 'CommonBuffId' = 265106 + CAREER_INTERIOR_DECORATOR_INTERVIEW_ROLE_CLIENT: 'CommonBuffId' = 256879 + CAREER_INTERIOR_DECORATOR_INTERVIEW_ROLE_HOST: 'CommonBuffId' = 256878 + CAREER_INTERIOR_DECORATOR_REVEAL_CLIENT_MOOD_ANGRY: 'CommonBuffId' = 262902 + CAREER_INTERIOR_DECORATOR_REVEAL_CLIENT_MOOD_DEFAULT: 'CommonBuffId' = 262906 + CAREER_INTERIOR_DECORATOR_REVEAL_CLIENT_MOOD_HAPPY: 'CommonBuffId' = 262904 + CAREER_INTERIOR_DECORATOR_REVEAL_CLIENT_MOOD_SAD: 'CommonBuffId' = 262903 + CAREER_INTERIOR_DECORATOR_REVEAL_CLIENT_MOOD_VERY_HAPPY: 'CommonBuffId' = 262905 + CAREER_INTERIOR_DECORATOR_REVEAL_CLIENT_SHARED_FINAL_VERDICT_FALSE: 'CommonBuffId' = 268877 + CAREER_INTERIOR_DECORATOR_REVEAL_CLIENT_SHARED_FINAL_VERDICT_TRUE: 'CommonBuffId' = 258876 + CAREER_INTERIOR_DECORATOR_REVEAL_CLIENT_SOCIAL_COOLDOWN: 'CommonBuffId' = 259940 + CAREER_INTERIOR_DECORATOR_REVEAL_FINAL_VERDICT_GOAL_COMPLETE: 'CommonBuffId' = 265023 + CAREER_INTERIOR_DECORATOR_REVEAL_FINISHED: 'CommonBuffId' = 263755 + CAREER_INTERIOR_DECORATOR_REVEAL_GIG_SCORE_BIG_FAILURE: 'CommonBuffId' = 267060 + CAREER_INTERIOR_DECORATOR_REVEAL_GIG_SCORE_BIG_SUCCESS: 'CommonBuffId' = 267061 + CAREER_INTERIOR_DECORATOR_REVEAL_GIG_SCORE_FAILURE: 'CommonBuffId' = 267063 + CAREER_INTERIOR_DECORATOR_REVEAL_GIG_SCORE_SUCCESS: 'CommonBuffId' = 267062 + CAREER_INTERIOR_DECORATOR_REVEAL_JUST_KICKED_OUT: 'CommonBuffId' = 268874 + CAREER_INTERIOR_DECORATOR_REVEAL_PUSH_KICK_OFF_DELAYED: 'CommonBuffId' = 269286 + CAREER_INTERIOR_DECORATOR_REVEAL_READING_THE_ROOM_NEGATIVE_1: 'CommonBuffId' = 258583 + CAREER_INTERIOR_DECORATOR_REVEAL_READING_THE_ROOM_NEGATIVE_2: 'CommonBuffId' = 258584 + CAREER_INTERIOR_DECORATOR_REVEAL_READING_THE_ROOM_NEUTRAL: 'CommonBuffId' = 269245 + CAREER_INTERIOR_DECORATOR_REVEAL_READING_THE_ROOM_POSITIVE_1: 'CommonBuffId' = 258581 + CAREER_INTERIOR_DECORATOR_REVEAL_READING_THE_ROOM_POSITIVE_2: 'CommonBuffId' = 258582 + CAREER_INTERIOR_DECORATOR_REVEAL_ROLE_CLIENT_EXPLORE: 'CommonBuffId' = 257626 + CAREER_INTERIOR_DECORATOR_REVEAL_ROLE_CLIENT_EXPLORE_FINAL_REACTION: 'CommonBuffId' = 258676 + CAREER_INTERIOR_DECORATOR_REVEAL_ROLE_CLIENT_EXPLORE_NORMAL: 'CommonBuffId' = 258677 + CAREER_INTERIOR_DECORATOR_REVEAL_ROLE_CLIENT_ROUTE: 'CommonBuffId' = 263301 + CAREER_INTERIOR_DECORATOR_REVEAL_ROLE_CLIENT_WAIT: 'CommonBuffId' = 258911 + CAREER_INTERIOR_DECORATOR_REVEAL_ROLE_HOST_EXPLORE: 'CommonBuffId' = 258852 + CAREER_INTERIOR_DECORATOR_REVEAL_ROLE_HOST_GET_IN_GROUP: 'CommonBuffId' = 267870 + CAREER_INTERIOR_DECORATOR_REVEAL_ROLE_HOST_WAIT: 'CommonBuffId' = 267105 + CAREER_INTERIOR_DECORATOR_REVEAL_ROLE_NON_MEMBER: 'CommonBuffId' = 267774 + CAREER_INTERIOR_DECORATOR_REWARDS_REPUTATION_GAIN: 'CommonBuffId' = 267357 + CAREER_INVESTIGATIVE_FAILURE: 'CommonBuffId' = 32559 + CAREER_INVESTIGATIVE_PRO: 'CommonBuffId' = 32558 + CAREER_JUICE_LOVED_BY_ALL: 'CommonBuffId' = 33484 + CAREER_JUICE_SUPPORTED: 'CommonBuffId' = 33488 + CAREER_LAUNCH_CANCELED: 'CommonBuffId' = 28106 + CAREER_LAUNCH_SUCCESSFUL: 'CommonBuffId' = 28108 + CAREER_LEAF_ON_THE_WIND: 'CommonBuffId' = 37741 + CAREER_LIFEGUARD_AWAY_ACTIONS_CONFIDENT: 'CommonBuffId' = 210254 + CAREER_LIFEGUARD_AWAY_ACTIONS_TENSE: 'CommonBuffId' = 210257 + CAREER_LIFEGUARD_FLEX_CONFIDENT: 'CommonBuffId' = 212597 + CAREER_LIFEGUARD_STAND_WATCH_FOCUSED: 'CommonBuffId' = 212598 + CAREER_LOST_GAMER_CRED: 'CommonBuffId' = 34166 + CAREER_LOST_PROFITS: 'CommonBuffId' = 100441 + CAREER_MAD_GAMER_CRED: 'CommonBuffId' = 34169 + CAREER_MILITARY_ORDERED_TO_CLEAN: 'CommonBuffId' = 204179 + CAREER_MISSED_OPPORTUNITY: 'CommonBuffId' = 37811 + CAREER_MOON_ROCK: 'CommonBuffId' = 37929 + CAREER_MOVIE_BOMB: 'CommonBuffId' = 32556 + CAREER_MOVIE_VISION: 'CommonBuffId' = 32557 + CAREER_MOVING_UP: 'CommonBuffId' = 36045 + CAREER_MUSICAL_MASTER: 'CommonBuffId' = 31373 + CAREER_NOT_PROMOTED_RECENTLY: 'CommonBuffId' = 217058 + CAREER_NOT_SO_SMOOTH_MOVE: 'CommonBuffId' = 32307 + CAREER_OUT_OF_PRACTICE: 'CommonBuffId' = 32290 + CAREER_PAINTER_RESEARCH_ART_REF_FAIL: 'CommonBuffId' = 34065 + CAREER_PAINTER_RESEARCH_ART_REF_SUCCESS: 'CommonBuffId' = 34046 + CAREER_PATROLMEN_LAUGHING: 'CommonBuffId' = 37801 + CAREER_PATROL_FALLOUT: 'CommonBuffId' = 37778 + CAREER_PERSUASIVE: 'CommonBuffId' = 33993 + CAREER_PICK_POCKET_SUCCESS: 'CommonBuffId' = 98522 + CAREER_PLAYED_HOOKY: 'CommonBuffId' = 30731 + CAREER_POLITICAL_PARIAH: 'CommonBuffId' = 32567 + CAREER_POLITICAL_TRUTH_SAYER: 'CommonBuffId' = 32563 + CAREER_POOR_PERFORMANCE: 'CommonBuffId' = 77832 + CAREER_PRACTICE_MAKES_PERFECT: 'CommonBuffId' = 31221 + CAREER_PREGNANT_SPOUSE_HIDDEN: 'CommonBuffId' = 111037 + CAREER_PROMOTED_RECENTLY: 'CommonBuffId' = 113108 + CAREER_PROMOTION_AMBITIOUS: 'CommonBuffId' = 36047 + CAREER_PROMOTION_TIMER: 'CommonBuffId' = 217059 + CAREER_PROTEST_FAILURE: 'CommonBuffId' = 154313 + CAREER_PROTEST_SUCCESS: 'CommonBuffId' = 154311 + CAREER_REALLY_BUGGED: 'CommonBuffId' = 33967 + CAREER_REGRETTABLE_INACTION: 'CommonBuffId' = 37783 + CAREER_REJECTED_REPLACED: 'CommonBuffId' = 33799 + CAREER_RESPECTED_GAMER: 'CommonBuffId' = 34017 + CAREER_RETHINKING_OPTIONS: 'CommonBuffId' = 36046 + CAREER_ROMANCE_CONSULTANT_BAD_CALL: 'CommonBuffId' = 366984 + CAREER_ROMANCE_CONSULTANT_EYE_FOR_LOVE: 'CommonBuffId' = 366954 + CAREER_ROMANCE_CONSULTANT_HAPPY_COUPLE: 'CommonBuffId' = 366957 + CAREER_ROMANCE_CONSULTANT_HEART_TO_HEART_TRAIT: 'CommonBuffId' = 368495 + CAREER_ROMANCE_CONSULTANT_JUST_LISTEN: 'CommonBuffId' = 366958 + CAREER_ROMANCE_CONSULTANT_LOVE_BUZZ: 'CommonBuffId' = 366959 + CAREER_ROMANCE_CONSULTANT_LOVE_IS_DEAD: 'CommonBuffId' = 366956 + CAREER_ROMANCE_CONSULTANT_LOVE_IS_FLEETING: 'CommonBuffId' = 366953 + CAREER_ROMANCE_CONSULTANT_LOVE_IS_IN_THE_AIR: 'CommonBuffId' = 366952 + CAREER_ROMANCE_CONSULTANT_MATCHMAKING_FAILURE: 'CommonBuffId' = 366955 + CAREER_ROMANCE_CONSULTANT_NEW_POINT_OF_VIEW: 'CommonBuffId' = 366951 + CAREER_ROMANCE_CONSULTANT_RELATIONSHIP_SATISFACTION_TIPS_DECREASE_HIDDEN: 'CommonBuffId' = 370013 + CAREER_ROMANCE_CONSULTANT_RELATIONSHIP_SATISFACTION_TIPS_INCREASE_HIDDEN: 'CommonBuffId' = 370012 + CAREER_ROMANCE_CONSULTANT_SUCCESSFUL_THERAPY: 'CommonBuffId' = 366983 + CAREER_ROMANCE_CONSULTANT_SYMPATHY_FOR_SADNESS: 'CommonBuffId' = 366982 + CAREER_ROMANCE_CONSULTANT_WONDERFUL_SIGHT: 'CommonBuffId' = 366985 + CAREER_SAFE_CODES_OBTAINED: 'CommonBuffId' = 33053 + CAREER_SAFE_DRILL_FAILURE: 'CommonBuffId' = 33052 + CAREER_SAFE_DRILL_SUCCESS: 'CommonBuffId' = 33050 + CAREER_SCHOOL_DAY_ANGRY: 'CommonBuffId' = 34880 + CAREER_SCHOOL_DAY_BORED: 'CommonBuffId' = 34881 + CAREER_SCHOOL_DAY_CONFIDENT: 'CommonBuffId' = 34885 + CAREER_SCHOOL_DAY_EMBARRASSED: 'CommonBuffId' = 34882 + CAREER_SCHOOL_DAY_ENERGIZED: 'CommonBuffId' = 34886 + CAREER_SCHOOL_DAY_FLIRTY: 'CommonBuffId' = 34887 + CAREER_SCHOOL_DAY_FOCUSED: 'CommonBuffId' = 34888 + CAREER_SCHOOL_DAY_HAPPY: 'CommonBuffId' = 34889 + CAREER_SCHOOL_DAY_INSPIRED: 'CommonBuffId' = 34890 + CAREER_SCHOOL_DAY_PLAYFUL: 'CommonBuffId' = 34891 + CAREER_SCHOOL_DAY_SAD: 'CommonBuffId' = 34883 + CAREER_SCHOOL_DAY_STRESSED: 'CommonBuffId' = 34884 + CAREER_SCHOOL_GOOD_GRADES: 'CommonBuffId' = 100332 + CAREER_SCIENTIST_ALIEN_WORLD_START_GIVE_PORTAL: 'CommonBuffId' = 116475 + CAREER_SCIENTIST_BREAKTHROUGH_BUFF: 'CommonBuffId' = 109414 + CAREER_SCIENTIST_BREAKTHROUGH_MULTI_STAGE0: 'CommonBuffId' = 114447 + CAREER_SCIENTIST_BREAKTHROUGH_MULTI_STAGE1: 'CommonBuffId' = 114448 + CAREER_SCIENTIST_BREAKTHROUGH_MULTI_STAGE2: 'CommonBuffId' = 115570 + CAREER_SCIENTIST_BREAKTHROUGH_MULTI_STAGE3: 'CommonBuffId' = 114449 + CAREER_SCIENTIST_BREAKTHROUGH_MULTI_STAGE4: 'CommonBuffId' = 114450 + CAREER_SCIENTIST_BREAKTHROUGH_MULTI_STAGE5: 'CommonBuffId' = 114451 + CAREER_SCIENTIST_BREAKTHROUGH_MULTI_STAGE6: 'CommonBuffId' = 114452 + CAREER_SCIENTIST_BREAKTHROUGH_RECENTLY: 'CommonBuffId' = 113501 + CAREER_SCIENTIST_EXPERT_REPAIR: 'CommonBuffId' = 109673 + CAREER_SCIENTIST_ORDER_COWORKERS_ALIENS: 'CommonBuffId' = 113651 + CAREER_SCIENTIST_ORDER_COWORKERS_CRYSTALS: 'CommonBuffId' = 113646 + CAREER_SCIENTIST_ORDER_COWORKERS_EXPERIMENT: 'CommonBuffId' = 113648 + CAREER_SCIENTIST_ORDER_COWORKERS_FLORA: 'CommonBuffId' = 113647 + CAREER_SCIENTIST_ORDER_COWORKERS_GARDEN: 'CommonBuffId' = 113466 + CAREER_SCIENTIST_ORDER_COWORKERS_INVENT: 'CommonBuffId' = 113649 + CAREER_SCIENTIST_ORDER_COWORKERS_METALS: 'CommonBuffId' = 113629 + CAREER_SCIENTIST_ORDER_COWORKERS_ROCKET: 'CommonBuffId' = 113650 + CAREER_SCOUTING_CONFIDENT: 'CommonBuffId' = 188459 + CAREER_SCOUTING_EMBARRASSED: 'CommonBuffId' = 188457 + CAREER_SCOUTING_ENERGIZED: 'CommonBuffId' = 188461 + CAREER_SCOUTING_HAPPY: 'CommonBuffId' = 188436 + CAREER_SCOUTING_IS_WALK_BY: 'CommonBuffId' = 188555 + CAREER_SCOUTING_SAD: 'CommonBuffId' = 188463 + CAREER_SCOUTING_STRESSED: 'CommonBuffId' = 188462 + CAREER_SCOUTING_UNIFORM_WORN: 'CommonBuffId' = 190776 + CAREER_SIDE_HUSTLE_NAILED_IT: 'CommonBuffId' = 278872 + CAREER_SIDE_HUSTLE_RECENT_FOLLOWER: 'CommonBuffId' = 278483 + CAREER_SIDE_HUSTLE_SEALED_THE_DEAL: 'CommonBuffId' = 278873 + CAREER_SIMSFLUENCER_SIDE_HUSTLE_CURSED_CONCLUSION: 'CommonBuffId' = 276842 + CAREER_SIMSFLUENCER_SIDE_HUSTLE_DEMONITIZED: 'CommonBuffId' = 276841 + CAREER_SIMSFLUENCER_SIDE_HUSTLE_PRIME_PRODUCT: 'CommonBuffId' = 276843 + CAREER_SIMSFLUENCER_SIDE_HUSTLE_REVIEW_BUFF: 'CommonBuffId' = 278425 + CAREER_SOCCER_TEAM_CHANCE_CARD_BLEW_IT: 'CommonBuffId' = 221638 + CAREER_SOCCER_TEAM_CHANCE_CARD_GOAL: 'CommonBuffId' = 221637 + CAREER_SOCCER_TEAM_CHANCE_CARD_INJURY: 'CommonBuffId' = 221635 + CAREER_SOCCER_TEAM_CHANCE_CARD_RED_CARD: 'CommonBuffId' = 221639 + CAREER_SOCCER_TEAM_CHANCE_CARD_TOO_MUCH_ENERGY_DRINK: 'CommonBuffId' = 221636 + CAREER_SOCCER_TEAM_CHANCE_CARD_YELLOW_CARD: 'CommonBuffId' = 221640 + CAREER_SOCCER_TEAM_GAME_LOST_ARTS: 'CommonBuffId' = 228144 + CAREER_SOCCER_TEAM_GAME_LOST_SCIENCE: 'CommonBuffId' = 228162 + CAREER_SOCCER_TEAM_GAME_WON_ARTS: 'CommonBuffId' = 228143 + CAREER_SOCCER_TEAM_GAME_WON_SCIENCE: 'CommonBuffId' = 228160 + CAREER_SOCIAL_MEDIA_HAS_CHECKED_IN_AT_VENUE_HIDDEN: 'CommonBuffId' = 136910 + CAREER_SOCIAL_MEDIA_HIDDEN_COOLDOWN_CHARITY_STREAM: 'CommonBuffId' = 151263 + CAREER_SOCIAL_MEDIA_HIDDEN_COOLDOWN_PERSUADED_TO: 'CommonBuffId' = 153036 + CAREER_SOCIAL_MEDIA_HIDDEN_COOLDOWN_PICKED_SIM_REPRESENTED: 'CommonBuffId' = 141731 + CAREER_SOCIAL_MEDIA_HIDDEN_COOLDOWN_PRANK_STREAMERS: 'CommonBuffId' = 143908 + CAREER_SOCIAL_MEDIA_HIDDEN_COOLDOWN_RECORD_RANT: 'CommonBuffId' = 137775 + CAREER_SOCIAL_MEDIA_HIDDEN_COOLDOWN_SHARE_FUNNY_MEME: 'CommonBuffId' = 143907 + CAREER_SOCIAL_MEDIA_HIDDEN_COOLDOWN_SHARE_IMAGE_PROMOTE_IMAGE: 'CommonBuffId' = 137771 + CAREER_SOCIAL_MEDIA_HIDDEN_COOLDOWN_UPLOAD_VIRAL_VIDEO: 'CommonBuffId' = 137770 + CAREER_SOCIAL_MEDIA_INTERNET_PERSONALITY_ANGRY_FANS: 'CommonBuffId' = 137075 + CAREER_SOCIAL_MEDIA_INTERNET_PERSONALITY_MEME_FAIL: 'CommonBuffId' = 137072 + CAREER_SOCIAL_MEDIA_INTERNET_PERSONALITY_MEME_SUCCESS: 'CommonBuffId' = 137071 + CAREER_SOCIAL_MEDIA_INTERNET_PERSONALITY_PRANK_STREAMERS_FAIL: 'CommonBuffId' = 137073 + CAREER_SOCIAL_MEDIA_INTERNET_PERSONALITY_PRANK_STREAMERS_SUCCESS: 'CommonBuffId' = 137074 + CAREER_SOCIAL_MEDIA_INTERNET_PERSONALITY_PRE_STREAMING_MARATHON_HIDDEN: 'CommonBuffId' = 153949 + CAREER_SOCIAL_MEDIA_INTERNET_PERSONALITY_SHARE_JOKE_FAIL: 'CommonBuffId' = 141660 + CAREER_SOCIAL_MEDIA_INTERNET_PERSONALITY_SHARE_JOKE_SUCCESS: 'CommonBuffId' = 153486 + CAREER_SOCIAL_MEDIA_INTERNET_PERSONALITY_STREAMING_MARATHON: 'CommonBuffId' = 137040 + CAREER_SOCIAL_MEDIA_INTERNET_PERSONALITY_TRENDING: 'CommonBuffId' = 137039 + CAREER_SOCIAL_MEDIA_PERSUADED_TO_COOK: 'CommonBuffId' = 136649 + CAREER_SOCIAL_MEDIA_PERSUADED_TO_DO_COMEDY: 'CommonBuffId' = 136654 + CAREER_SOCIAL_MEDIA_PERSUADED_TO_FLIRT: 'CommonBuffId' = 136651 + CAREER_SOCIAL_MEDIA_PERSUADED_TO_GOOF_OFF: 'CommonBuffId' = 136655 + CAREER_SOCIAL_MEDIA_PERSUADED_TO_PLAY_GAMES: 'CommonBuffId' = 136656 + CAREER_SOCIAL_MEDIA_PERSUADED_TO_PLAY_MUSIC: 'CommonBuffId' = 136657 + CAREER_SOCIAL_MEDIA_PERSUADED_TO_RACCOON: 'CommonBuffId' = 150999 + CAREER_SOCIAL_MEDIA_PERSUADED_TO_RANT: 'CommonBuffId' = 136652 + CAREER_SOCIAL_MEDIA_PERSUADED_TO_SING: 'CommonBuffId' = 136796 + CAREER_SOCIAL_MEDIA_PERSUADED_TO_SMILE: 'CommonBuffId' = 136650 + CAREER_SOCIAL_MEDIA_PERSUADED_TO_WORK_OUT: 'CommonBuffId' = 136653 + CAREER_SOCIAL_MEDIA_PUBLIC_RELATIONS_DEVELOP_NETWORK_FAIL: 'CommonBuffId' = 137080 + CAREER_SOCIAL_MEDIA_PUBLIC_RELATIONS_DEVELOP_NETWORK_SUCCESS: 'CommonBuffId' = 137079 + CAREER_SOCIAL_MEDIA_PUBLIC_RELATIONS_REPRESENTED_FRIEND_FAIL: 'CommonBuffId' = 137081 + CAREER_SOCIAL_MEDIA_PUBLIC_RELATIONS_REPRESENTED_FRIEND_SUCCESS: 'CommonBuffId' = 137083 + CAREER_SOCIAL_MEDIA_PUBLIC_RELATIONS_REPRESENT_CLIENT_FAIL: 'CommonBuffId' = 137082 + CAREER_SOCIAL_MEDIA_PUBLIC_RELATIONS_REPRESENT_CLIENT_SUCCESS: 'CommonBuffId' = 137084 + CAREER_SOCIAL_MEDIA_PUBLIC_RELATIONS_TRENDING: 'CommonBuffId' = 137103 + CAREER_SO_MANY_ERRORS: 'CommonBuffId' = 31921 + CAREER_SPACE_DUPED: 'CommonBuffId' = 33444 + CAREER_SPACE_ROUTINE: 'CommonBuffId' = 33453 + CAREER_SPEAKER_POWER: 'CommonBuffId' = 32568 + CAREER_SPONSOR_ARTIST_FAILURE: 'CommonBuffId' = 34041 + CAREER_SPONSOR_ARTIST_SUCCESS: 'CommonBuffId' = 34040 + CAREER_SPY_SWAGGER: 'CommonBuffId' = 32304 + CAREER_STREAMER_SIDE_HUSTLE_BANNED: 'CommonBuffId' = 276733 + CAREER_STREAMER_SIDE_HUSTLE_BEATEN_AT_OWN_GAME: 'CommonBuffId' = 276738 + CAREER_STREAMER_SIDE_HUSTLE_BEHIND_THE_MASK: 'CommonBuffId' = 276736 + CAREER_STREAMER_SIDE_HUSTLE_TIP_COOLDOWN: 'CommonBuffId' = 297082 + CAREER_STUNK_IT_UP: 'CommonBuffId' = 31541 + CAREER_STYLE_INFLUENCER_ARTICLE_SUBMIT_FAILURE: 'CommonBuffId' = 198664 + CAREER_STYLE_INFLUENCER_FAKE_NEWS_ANGRY: 'CommonBuffId' = 197551 + CAREER_STYLE_INFLUENCER_FAKE_NEWS_EMBARRASSED: 'CommonBuffId' = 197552 + CAREER_STYLE_INFLUENCER_FAKE_NEWS_SAD: 'CommonBuffId' = 197550 + CAREER_STYLE_INFLUENCER_FASHION_FANATIC: 'CommonBuffId' = 197561 + CAREER_STYLE_INFLUENCER_IMPRESSION: 'CommonBuffId' = 197115 + CAREER_STYLE_INFLUENCER_INTERVIEW_HIDDEN_COOLDOWN: 'CommonBuffId' = 201602 + CAREER_STYLE_INFLUENCER_MODELING_LOOK: 'CommonBuffId' = 198915 + CAREER_STYLE_INFLUENCER_MODEL_LOOK: 'CommonBuffId' = 198813 + CAREER_STYLE_INFLUENCER_MODEL_LOOK_COOLDOWN: 'CommonBuffId' = 198814 + CAREER_STYLE_INFLUENCER_PROLIFIC_PERSONA: 'CommonBuffId' = 197560 + CAREER_STYLE_INFLUENCER_SCOOP: 'CommonBuffId' = 197553 + CAREER_STYLE_INFLUENCER_SELL_OUT: 'CommonBuffId' = 197555 + CAREER_STYLE_INFLUENCER_STANDBY_CONVICTIONS: 'CommonBuffId' = 197554 + CAREER_STYLE_INFLUENCER_UNHAPPY_CUSTOMER_ANGRY: 'CommonBuffId' = 197558 + CAREER_STYLE_INFLUENCER_UNHAPPY_CUSTOMER_SAD: 'CommonBuffId' = 197559 + CAREER_STYLE_INFLUENCER_WORKING_IT: 'CommonBuffId' = 197556 + CAREER_SUDDEN_INSPIRATION: 'CommonBuffId' = 31230 + CAREER_SUSPECT_ESCAPED: 'CommonBuffId' = 37940 + CAREER_TALK_TO_THE_HENCHMEN: 'CommonBuffId' = 32337 + CAREER_TAXES_EVADED: 'CommonBuffId' = 37805 + CAREER_TEACH_HANDS_ON_FAIL: 'CommonBuffId' = 34020 + CAREER_TEACH_HANDS_ON_SUCCESS: 'CommonBuffId' = 34022 + CAREER_TEACH_THEORY: 'CommonBuffId' = 34023 + CAREER_TEEN_BABYSITTER_01_COOKIE_BEFORE_DINNER: 'CommonBuffId' = 74391 + CAREER_TEEN_BABYSITTER_01_COOKIE_TANTRUM: 'CommonBuffId' = 74392 + CAREER_TEEN_BABYSITTER_02_BROWN_PAINT_EVERYWHERE: 'CommonBuffId' = 74394 + CAREER_TEEN_BABYSITTER_02_CLEANED_UP_MESS: 'CommonBuffId' = 74393 + CAREER_TEEN_BABYSITTER_02_LEFT_THE_MESS: 'CommonBuffId' = 74395 + CAREER_TEEN_BABYSITTER_03_LIFE_LESSONS: 'CommonBuffId' = 74396 + CAREER_TEEN_BARISTA_03_BREWED_MASTERPIECE: 'CommonBuffId' = 74430 + CAREER_TEEN_BARISTA_03_MORE_PRACTISE: 'CommonBuffId' = 74432 + CAREER_TEEN_FAST_FOOD_01_BREAK_TIME: 'CommonBuffId' = 74411 + CAREER_TEEN_FAST_FOOD_01_CLEANING_SHOW: 'CommonBuffId' = 74412 + CAREER_TEEN_FAST_FOOD_02_FIVE_SECOND_RULE: 'CommonBuffId' = 74413 + CAREER_TEEN_FAST_FOOD_02_HAIR_BURGER: 'CommonBuffId' = 74414 + CAREER_TEEN_FAST_FOOD_03_PROACTIVE_THINKING: 'CommonBuffId' = 74415 + CAREER_TEEN_MANUAL_LABOR_01_RECORD_SPEED: 'CommonBuffId' = 74433 + CAREER_TEEN_MANUAL_LABOR_02_DOUBLE_THE_WORK: 'CommonBuffId' = 74435 + CAREER_TEEN_MANUAL_LABOR_02_MINIMALISTIC_DESIGN: 'CommonBuffId' = 74434 + CAREER_TEEN_MANUAL_LABOR_03_BACKHOE_MASTER: 'CommonBuffId' = 74436 + CAREER_TEEN_MANUAL_LABOR_03_FLIPPED_BACKHOE: 'CommonBuffId' = 74437 + CAREER_TEEN_RETAIL_01_BURIED_CUSTOMER: 'CommonBuffId' = 74420 + CAREER_TEEN_RETAIL_01_SOLD_OUT_DISPLAY: 'CommonBuffId' = 74417 + CAREER_TEEN_RETAIL_02_CUSTOMER_PRAISE: 'CommonBuffId' = 74421 + CAREER_TEEN_RETAIL_03_CUSTOMER_TURNED_AWAY: 'CommonBuffId' = 74419 + CAREER_TEEN_RETAIL_03_GRATEFUL_CUSTOMER: 'CommonBuffId' = 74418 + CAREER_THE_BEST_AROUND: 'CommonBuffId' = 32184 + CAREER_TIRE_FAIL: 'CommonBuffId' = 33049 + CAREER_TIRE_FIXED: 'CommonBuffId' = 33048 + CAREER_TONE_BORED: 'CommonBuffId' = 154576 + CAREER_TONE_BORED_ACTIVIST_POLITICS: 'CommonBuffId' = 137300 + CAREER_TONE_CONFIDENT: 'CommonBuffId' = 145074 + CAREER_TONE_CONFIDENT_AGENT_AGENT: 'CommonBuffId' = 76864 + CAREER_TONE_CONFIDENT_AGENT_MAIN: 'CommonBuffId' = 76863 + CAREER_TONE_CONFIDENT_AGENT_VILLAIN: 'CommonBuffId' = 76866 + CAREER_TONE_CONFIDENT_BIG_BREAK: 'CommonBuffId' = 76839 + CAREER_TONE_CONFIDENT_CRIMINAL_BOSS: 'CommonBuffId' = 76807 + CAREER_TONE_EMBARRASSED: 'CommonBuffId' = 145062 + CAREER_TONE_EMBARRASSED_CONFIDENT: 'CommonBuffId' = 101215 + CAREER_TONE_ENERGIZED_ACTIVIST_MAIN: 'CommonBuffId' = 137297 + CAREER_TONE_FOCUSED_ASTRONAUT_MAIN: 'CommonBuffId' = 100970 + CAREER_TONE_FOCUSED_ASTRONAUT_RANGER: 'CommonBuffId' = 100973 + CAREER_TONE_HAPPY: 'CommonBuffId' = 145073 + CAREER_TONE_HAPPY_SLACK_OFF: 'CommonBuffId' = 100536 + CAREER_TONE_HAPPY_TAKE_IT_EASY: 'CommonBuffId' = 76774 + CAREER_TONE_HAPPY_TECH_GAMING: 'CommonBuffId' = 76870 + CAREER_TONE_HAPPY_TECH_MAIN: 'CommonBuffId' = 76868 + CAREER_TONE_INSPIRED_CULINARY_BARTENDER: 'CommonBuffId' = 76828 + CAREER_TONE_INSPIRED_CULINARY_MAIN: 'CommonBuffId' = 76818 + CAREER_TONE_INSPIRED_ENTERTAINER_MUSIC: 'CommonBuffId' = 76842 + CAREER_TONE_INSPIRED_PAINTER_ARTIST: 'CommonBuffId' = 76850 + CAREER_TONE_INSPIRED_PAINTER_MAIN: 'CommonBuffId' = 76847 + CAREER_TONE_INSPIRED_TECH_STARTUP: 'CommonBuffId' = 76873 + CAREER_TONE_INSPIRED_WRITER_AUTHOR: 'CommonBuffId' = 76879 + CAREER_TONE_INSPIRED_WRITER_MAIN: 'CommonBuffId' = 76876 + CAREER_TONE_PLAYFUL_ENTERTAINER_COMEDY: 'CommonBuffId' = 76845 + CAREER_TONE_SAD_FAILED_MISSION: 'CommonBuffId' = 76861 + CAREER_TONE_SCHOOL_TENSE: 'CommonBuffId' = 98354 + CAREER_TONE_STRESS: 'CommonBuffId' = 145075 + CAREER_TONE_STRESS_ASTRONAUT_SMUGGLER: 'CommonBuffId' = 76792 + CAREER_TONE_STRESS_PAINTER_CRITIC: 'CommonBuffId' = 76858 + CAREER_TONE_STRESS_WORKING_HARD: 'CommonBuffId' = 76770 + CAREER_TONE_STYLE_INFLUENCER_MAIN_RESEARCH: 'CommonBuffId' = 196952 + CAREER_TONE_STYLE_INFLUENCER_STYLIST_NETWORK: 'CommonBuffId' = 196951 + CAREER_TONE_STYLE_INFLUENCER_STYLIST_PAMPER: 'CommonBuffId' = 196953 + CAREER_TONE_STYLE_INFLUENCER_TREND_SETTER_PROMOTE_BAND: 'CommonBuffId' = 196954 + CAREER_TONE_STYLE_INFLUENCER_TREND_SETTER_SHOP: 'CommonBuffId' = 196955 + CAREER_TRIANGLE_SILENT: 'CommonBuffId' = 33090 + CAREER_TUTORING_FAILED: 'CommonBuffId' = 34013 + CAREER_TUTORING_WORTHWHILE: 'CommonBuffId' = 34011 + CAREER_UNCOMFORTABLE_IRRESPONSIBLE: 'CommonBuffId' = 163929 + CAREER_UNDEFENDED_GALAXY: 'CommonBuffId' = 37797 + CAREER_UNDER_PRICED_CORRECT: 'CommonBuffId' = 34036 + CAREER_UNDER_PRICED_OUT_BID: 'CommonBuffId' = 34035 + CAREER_UNDER_PRICED_PURCHASE: 'CommonBuffId' = 34037 + CAREER_UNGRATEFUL_PILOTS: 'CommonBuffId' = 37749 + CAREER_USELESS_MISSION: 'CommonBuffId' = 37758 + CAREER_VIRAL_CHASE: 'CommonBuffId' = 37942 + CAREER_VIRUS_CRIPPLES_COMPUTER: 'CommonBuffId' = 33072 + CAREER_VIRUS_INVESTIGATE_NOTHING: 'CommonBuffId' = 33071 + CAREER_VIRUS_INVESTIGATE_SUCCESS: 'CommonBuffId' = 33070 + CAREER_WORMHOLE_BACKLASH: 'CommonBuffId' = 37746 + CAREER_WORMHOLE_TRAVELER: 'CommonBuffId' = 37765 + CAREER_WORTHWHILE_LACERATIONS: 'CommonBuffId' = 37807 + CAREER_YELLED_AT_BY_COWORKER: 'CommonBuffId' = 27188 + CARRIED_PET: 'CommonBuffId' = 176876 + CATCH_SNOOPING: 'CommonBuffId' = 160255 + CATCH_SNOOPING_VISIBLE_ANGRY: 'CommonBuffId' = 164039 + CAT_ACTIVE_ROUGHHOUSE_PLAY_DECAY: 'CommonBuffId' = 173488 + CAT_BLOCK_ROUTABLE_SURFACE_MISBEHAVIOR: 'CommonBuffId' = 171975 + CAT_MAD_NIP_ATTACK_COOLDOWN: 'CommonBuffId' = 173594 + CAT_ON_ROUTABLE_SURFACE_MISBEHAVIOR: 'CommonBuffId' = 171915 + CAUGHT_IN_CURRENT_ROUTE_EVENT: 'CommonBuffId' = 212889 + CAULDRON_POTION_BFF_FAILURE: 'CommonBuffId' = 214263 + CAULDRON_POTION_BFF_SUCCESS: 'CommonBuffId' = 214261 + CAULDRON_POTION_BFF_SUCCESS_POTENT: 'CommonBuffId' = 214262 + CAULDRON_POTION_DEATH_PROOF_FAILURE: 'CommonBuffId' = 215772 + CAULDRON_POTION_DEATH_PROOF_FAILURE_POTENT: 'CommonBuffId' = 215776 + CAULDRON_POTION_DEATH_PROOF_SUCCESS: 'CommonBuffId' = 215771 + CAULDRON_POTION_DEATH_PROOF_SUCCESS_POTENT: 'CommonBuffId' = 215775 + CAULDRON_POTION_FAIL_POTION: 'CommonBuffId' = 218968 + CAULDRON_POTION_HATE_FAILURE: 'CommonBuffId' = 214250 + CAULDRON_POTION_HATE_SUCCESS: 'CommonBuffId' = 214251 + CAULDRON_POTION_HATE_SUCCESS_POTENT: 'CommonBuffId' = 214252 + CAULDRON_POTION_IMMORTALITY_FAILURE_TENSE: 'CommonBuffId' = 214403 + CAULDRON_POTION_IMMORTALITY_SUCCESS: 'CommonBuffId' = 219899 + CAULDRON_POTION_IMMORTALITY_SUCCESS_VFX: 'CommonBuffId' = 214393 + CAULDRON_POTION_LEARNED_POTION_COOLDOWN: 'CommonBuffId' = 216168 + CAULDRON_POTION_LOVE_FAILURE: 'CommonBuffId' = 214097 + CAULDRON_POTION_LOVE_SUCCESS: 'CommonBuffId' = 214098 + CAULDRON_POTION_LOVE_SUCCESS_POTENT: 'CommonBuffId' = 214099 + CAULDRON_POTION_LUCK: 'CommonBuffId' = 215690 + CAULDRON_POTION_LUCK_CHEAT_ALWAYS_MONEY: 'CommonBuffId' = 216800 + CAULDRON_POTION_LUCK_CHEAT_ALWAYS_OBJECTS: 'CommonBuffId' = 216799 + CAULDRON_POTION_LUCK_FAIL_TIMER: 'CommonBuffId' = 215780 + CAULDRON_POTION_LUCK_POTENT: 'CommonBuffId' = 215698 + CAULDRON_POTION_MAKE_GLOWY_FAILURE: 'CommonBuffId' = 214531 + CAULDRON_POTION_MAKE_GLOWY_FAILURE_POTENT: 'CommonBuffId' = 214536 + CAULDRON_POTION_MAKE_GLOWY_FAILURE_VFX_1: 'CommonBuffId' = 217447 + CAULDRON_POTION_MAKE_GLOWY_FAILURE_VFX_2: 'CommonBuffId' = 217448 + CAULDRON_POTION_MAKE_GLOWY_FAILURE_VFX_3: 'CommonBuffId' = 217451 + CAULDRON_POTION_MAKE_GLOWY_FAILURE_VFX_4: 'CommonBuffId' = 217452 + CAULDRON_POTION_MAKE_GLOWY_SUCCESS: 'CommonBuffId' = 214529 + CAULDRON_POTION_MAKE_GLOWY_SUCCESS_POTENT: 'CommonBuffId' = 214537 + CAULDRON_POTION_NULLIFY_FAILURE_1: 'CommonBuffId' = 214483 + CAULDRON_POTION_NULLIFY_FAILURE_11: 'CommonBuffId' = 214493 + CAULDRON_POTION_NULLIFY_FAILURE_12: 'CommonBuffId' = 214489 + CAULDRON_POTION_NULLIFY_FAILURE_13: 'CommonBuffId' = 214492 + CAULDRON_POTION_NULLIFY_FAILURE_14: 'CommonBuffId' = 214487 + CAULDRON_POTION_NULLIFY_FAILURE_15: 'CommonBuffId' = 214488 + CAULDRON_POTION_NULLIFY_FAILURE_15_POTENT: 'CommonBuffId' = 214500 + CAULDRON_POTION_NULLIFY_FAILURE_2: 'CommonBuffId' = 214490 + CAULDRON_POTION_NULLIFY_FAILURE_3: 'CommonBuffId' = 214498 + CAULDRON_POTION_NULLIFY_FAILURE_4: 'CommonBuffId' = 214495 + CAULDRON_POTION_NULLIFY_FAILURE_5: 'CommonBuffId' = 214485 + CAULDRON_POTION_NULLIFY_FAILURE_6: 'CommonBuffId' = 214491 + CAULDRON_POTION_NULLIFY_FAILURE_7: 'CommonBuffId' = 214494 + CAULDRON_POTION_NULLIFY_FAILURE_8: 'CommonBuffId' = 214497 + CAULDRON_POTION_NULLIFY_FAILURE_9: 'CommonBuffId' = 214496 + CAULDRON_POTION_NULLIFY_SUCCESS: 'CommonBuffId' = 217405 + CAULDRON_POTION_NULLIFY_SUCCESS_POTENT: 'CommonBuffId' = 217407 + CAULDRON_POTION_PHEROMONE_FAILURE: 'CommonBuffId' = 214940 + CAULDRON_POTION_PHEROMONE_SUCCESS: 'CommonBuffId' = 214941 + CAULDRON_POTION_PHEROMONE_SUCCESS_POTENT: 'CommonBuffId' = 214944 + CAULDRON_POTION_POISON: 'CommonBuffId' = 213624 + CAULDRON_POTION_POISON_FAIL_FORVAMPIRE: 'CommonBuffId' = 219207 + CAULDRON_POTION_POISON_POTENT: 'CommonBuffId' = 213687 + CAULDRON_POTION_RESET_WITCH_PERKS_FAIL: 'CommonBuffId' = 219285 + CAULDRON_POTION_SKILL_INCREASE: 'CommonBuffId' = 214466 + CAULDRON_POTION_SKILL_INCREASE_FAIL: 'CommonBuffId' = 219258 + CAULDRON_POTION_SKILL_INCREASE_POTENT: 'CommonBuffId' = 214467 + CAULDRON_STIR: 'CommonBuffId' = 220394 + CAULDRON_USAGE_CANCEL: 'CommonBuffId' = 220498 + CAVE_INSPIRED: 'CommonBuffId' = 345651 + CAVE_UNCOMFORTABLE: 'CommonBuffId' = 345652 + CELEBRATION_CANNON_BABY_BUST: 'CommonBuffId' = 321239 + CELEBRATION_CANNON_CELEBRATION_CATASTROPHE: 'CommonBuffId' = 322451 + CELEBRATION_CANNON_CONFETTI_TIME: 'CommonBuffId' = 322452 + CELEBRATION_CANNON_COOLDOWN: 'CommonBuffId' = 321084 + CELEBRATION_CANNON_ITS_A_SIM: 'CommonBuffId' = 321238 + CELEBRITY_ACQUAINTANCE: 'CommonBuffId' = 192633 + CELEBRITY_FAINT_COOLDOWN: 'CommonBuffId' = 198718 + CELEBRITY_FANS: 'CommonBuffId' = 196088 + CELEBRITY_FANS_FAN_TRAITS_NERVOUS: 'CommonBuffId' = 196909 + CELEBRITY_FANS_FAN_TRAITS_SOCIAL: 'CommonBuffId' = 196911 + CELEBRITY_FANS_FAN_TRAITS_TOUCHY: 'CommonBuffId' = 196910 + CELEBRITY_FAN_SOCIAL_COOLDOWN: 'CommonBuffId' = 198717 + CELEBRITY_FAN_WHIMS: 'CommonBuffId' = 193469 + CELEBRITY_MEET_AND_GREET_CELEBRITY: 'CommonBuffId' = 199597 + CELEBRITY_MEET_AND_GREET_FAME_AND_REP_BRONZE: 'CommonBuffId' = 199827 + CELEBRITY_MEET_AND_GREET_FAME_AND_REP_BRONZE_BAD_REP: 'CommonBuffId' = 202817 + CELEBRITY_MEET_AND_GREET_FAME_AND_REP_GOLD: 'CommonBuffId' = 199828 + CELEBRITY_MEET_AND_GREET_FAME_AND_REP_GOLD_BAD_REP: 'CommonBuffId' = 202818 + CELEBRITY_MEET_AND_GREET_FAME_AND_REP_SILVER: 'CommonBuffId' = 199829 + CELEBRITY_MEET_AND_GREET_FAME_AND_REP_SILVER_BAD_REP: 'CommonBuffId' = 202819 + CELEBRITY_MEET_AND_GREET_FAN: 'CommonBuffId' = 199598 + CELEBRITY_MEET_AND_GREET_POSE_FOR_PICTURES: 'CommonBuffId' = 201444 + CELEBRITY_NEAR_CELEBRITY: 'CommonBuffId' = 192980 + CELEBRITY_POSE_CELEBRITY: 'CommonBuffId' = 193799 + CELEBRITY_POSE_FAN: 'CommonBuffId' = 193800 + CELEBRITY_SOCIALS_AUTOGRAPH_FAILURE: 'CommonBuffId' = 194599 + CELEBRITY_SOCIALS_AUTOGRAPH_SUCCESS: 'CommonBuffId' = 194598 + CELEBRITY_SOCIALS_CELEB_HUG_FAILURE: 'CommonBuffId' = 198636 + CELEBRITY_SOCIALS_CELEB_SELFIE_FAILURE: 'CommonBuffId' = 198684 + CELEBRITY_SOCIALS_HUG_FAILURE: 'CommonBuffId' = 194594 + CELEBRITY_SOCIALS_HUG_SUCCESS: 'CommonBuffId' = 194589 + CELEBRITY_SOCIALS_SELFIE_FAILURE: 'CommonBuffId' = 194597 + CELEBRITY_SOCIALS_SELFIE_SUCCESS: 'CommonBuffId' = 194595 + CELEBRITY_STANS: 'CommonBuffId' = 196846 + CELEBRITY_TAKE_PICTURE_SUCCESS: 'CommonBuffId' = 194509 + CELEBRITY_TILE_HIDDEN_TILE_ACHIEVED_DEFACED_TILE: 'CommonBuffId' = 201078 + CELEBRITY_TILE_MOOD_DEFACE_PLAYFUL: 'CommonBuffId' = 198719 + CELEBRITY_TILE_PLACEMENT_CEREMONY_CROWD_MEMBER_GATHER: 'CommonBuffId' = 195851 + CELEBRITY_TILE_PLACEMENT_CEREMONY_CROWD_MEMBER_GATHER_IMPATIENT: 'CommonBuffId' = 195852 + CELEBRITY_TILE_PLACEMENT_CEREMONY_CROWD_MEMBER_START_CEREMONY: 'CommonBuffId' = 195853 + CELEBRITY_TILE_PLACEMENT_CEREMONY_HONOREE_GATHER: 'CommonBuffId' = 195846 + CELEBRITY_TILE_PLACEMENT_CEREMONY_HONOREE_GATHER_IMPATIENT: 'CommonBuffId' = 195848 + CELEBRITY_TILE_PLACEMENT_CEREMONY_HONOREE_START_CEREMONY: 'CommonBuffId' = 195850 + CELEBRITY_TILE_PLACE_TILE_CONFIDENT: 'CommonBuffId' = 198691 + CELEBRITY_TILE_TILE_EARNED_HAPPY: 'CommonBuffId' = 198692 + CELEBRITY_TILE_VIEW_CELEBRITY_NEGATIVE: 'CommonBuffId' = 196543 + CELEBRITY_TILE_VIEW_CELEBRITY_POSITIVE: 'CommonBuffId' = 196542 + CHARITY_BENEFIT_PARTY_GOLD: 'CommonBuffId' = 197821 + CHARITY_BENEFIT_PARTY_SILVER: 'CommonBuffId' = 197820 + CHEATING_INTENSITY_ANGRY: 'CommonBuffId' = 12783 + CHEATING_INTENSITY_BORED: 'CommonBuffId' = 12784 + CHEATING_INTENSITY_BUFF_PETS_HORSE_ANGRY: 'CommonBuffId' = 322156 + CHEATING_INTENSITY_BUFF_PETS_HORSE_CONFIDENT: 'CommonBuffId' = 322155 + CHEATING_INTENSITY_BUFF_PETS_HORSE_DAZED: 'CommonBuffId' = 322159 + CHEATING_INTENSITY_BUFF_PETS_HORSE_HAPPY: 'CommonBuffId' = 322154 + CHEATING_INTENSITY_BUFF_PETS_HORSE_SAD: 'CommonBuffId' = 322160 + CHEATING_INTENSITY_BUFF_PETS_HORSE_SCARED: 'CommonBuffId' = 322161 + CHEATING_INTENSITY_BUFF_PETS_HORSE_TENSE: 'CommonBuffId' = 322158 + CHEATING_INTENSITY_BUFF_PETS_HORSE_UNCOMFORTABLE: 'CommonBuffId' = 322157 + CHEATING_INTENSITY_BUFF_PETS_HORSE_VERY_ANGRY: 'CommonBuffId' = 322163 + CHEATING_INTENSITY_BUFF_PETS_HORSE_VERY_CONFIDENT: 'CommonBuffId' = 322164 + CHEATING_INTENSITY_BUFF_PETS_HORSE_VERY_DAZED: 'CommonBuffId' = 322165 + CHEATING_INTENSITY_BUFF_PETS_HORSE_VERY_HAPPY: 'CommonBuffId' = 322166 + CHEATING_INTENSITY_BUFF_PETS_HORSE_VERY_SAD: 'CommonBuffId' = 322167 + CHEATING_INTENSITY_BUFF_PETS_HORSE_VERY_SCARED: 'CommonBuffId' = 322168 + CHEATING_INTENSITY_BUFF_PETS_HORSE_VERY_TENSE: 'CommonBuffId' = 322169 + CHEATING_INTENSITY_BUFF_PETS_HORSE_VERY_UNCOMFORTABLE: 'CommonBuffId' = 322170 + CHEATING_INTENSITY_BUFF_SCARED: 'CommonBuffId' = 251737 + CHEATING_INTENSITY_BUFF_TERRIFIED: 'CommonBuffId' = 251738 + CHEATING_INTENSITY_CONFIDENT: 'CommonBuffId' = 12785 + CHEATING_INTENSITY_DEPRESSED: 'CommonBuffId' = 12787 + CHEATING_INTENSITY_ELATED: 'CommonBuffId' = 12788 + CHEATING_INTENSITY_EMBARRASSED: 'CommonBuffId' = 12789 + CHEATING_INTENSITY_ENERGIZED: 'CommonBuffId' = 12790 + CHEATING_INTENSITY_ENRAGED: 'CommonBuffId' = 12786 + CHEATING_INTENSITY_FEARLESS: 'CommonBuffId' = 12791 + CHEATING_INTENSITY_FLIRTY: 'CommonBuffId' = 12792 + CHEATING_INTENSITY_FOCUSED: 'CommonBuffId' = 12793 + CHEATING_INTENSITY_FURIOUS: 'CommonBuffId' = 12794 + CHEATING_INTENSITY_HAPPY: 'CommonBuffId' = 12795 + CHEATING_INTENSITY_HUMILIATED: 'CommonBuffId' = 12796 + CHEATING_INTENSITY_HYSTERICAL: 'CommonBuffId' = 12797 + CHEATING_INTENSITY_IMAGINATIVE: 'CommonBuffId' = 12798 + CHEATING_INTENSITY_INSPIRED: 'CommonBuffId' = 12799 + CHEATING_INTENSITY_IN_THE_ZONE: 'CommonBuffId' = 12800 + CHEATING_INTENSITY_MISERABLE: 'CommonBuffId' = 12801 + CHEATING_INTENSITY_MORTIFIED: 'CommonBuffId' = 12802 + CHEATING_INTENSITY_PASSIONATE: 'CommonBuffId' = 12803 + CHEATING_INTENSITY_PETS_DOG_ANGRY: 'CommonBuffId' = 158257 + CHEATING_INTENSITY_PETS_DOG_ANXIOUS: 'CommonBuffId' = 158262 + CHEATING_INTENSITY_PETS_DOG_ASHAMED: 'CommonBuffId' = 158260 + CHEATING_INTENSITY_PETS_DOG_EXCITED: 'CommonBuffId' = 158258 + CHEATING_INTENSITY_PETS_DOG_FLIRTY: 'CommonBuffId' = 158263 + CHEATING_INTENSITY_PETS_DOG_HAPPY: 'CommonBuffId' = 158265 + CHEATING_INTENSITY_PETS_DOG_MOPEY: 'CommonBuffId' = 158261 + CHEATING_INTENSITY_PETS_DOG_SAD: 'CommonBuffId' = 158259 + CHEATING_INTENSITY_PETS_DOG_SCARED: 'CommonBuffId' = 158264 + CHEATING_INTENSITY_PLAYFUL: 'CommonBuffId' = 12804 + CHEATING_INTENSITY_POSSESSED: 'CommonBuffId' = 201535 + CHEATING_INTENSITY_PUMPED: 'CommonBuffId' = 12805 + CHEATING_INTENSITY_SAD: 'CommonBuffId' = 12806 + CHEATING_INTENSITY_SILLY: 'CommonBuffId' = 12807 + CHEATING_INTENSITY_SLOSHED: 'CommonBuffId' = 12808 + CHEATING_INTENSITY_STRESSED: 'CommonBuffId' = 12809 + CHEATING_INTENSITY_TENSE: 'CommonBuffId' = 12810 + CHEATING_INTENSITY_UNCOMFORTABLE: 'CommonBuffId' = 12811 + CHEATING_OKAY: 'CommonBuffId' = 12778 + CHEATING_PETS_CAT_ANGRY: 'CommonBuffId' = 158444 + CHEATING_PETS_CAT_ANXIOUS: 'CommonBuffId' = 158195 + CHEATING_PETS_CAT_DROWSY: 'CommonBuffId' = 158149 + CHEATING_PETS_CAT_FLIRTY: 'CommonBuffId' = 158446 + CHEATING_PETS_CAT_HAPPY: 'CommonBuffId' = 158448 + CHEATING_PETS_CAT_SCARED: 'CommonBuffId' = 158447 + CHEATING_PETS_HYPER: 'CommonBuffId' = 157910 + CHECK_FRESHNESS_COOLDOWN: 'CommonBuffId' = 237002 + CHEERED_UP: 'CommonBuffId' = 24494 + CHEERFUL_SCENT: 'CommonBuffId' = 118502 + CHEER_MAT_CANT_STOP_THIS: 'CommonBuffId' = 292165 + CHEER_MAT_IN_GROUP_CHEER: 'CommonBuffId' = 300895 + CHEER_MAT_TEAM_SPIRIT: 'CommonBuffId' = 292166 + CHEER_MAT_TOO_MUCH_SPIRIT: 'CommonBuffId' = 292164 + CHEF_BEGIN_STATE: 'CommonBuffId' = 133753 + CHEF_HAS_ORDER: 'CommonBuffId' = 131588 + CHEMICAL_ANALYZER_INSPIRED: 'CommonBuffId' = 107960 + CHILDHOOD_FRIENDS_SCENARIO_REWARD_INVSIBLE: 'CommonBuffId' = 299508 + CHILDHOOD_PHASE_BEAR: 'CommonBuffId' = 164893 + CHILDHOOD_PHASE_BEAR_IN_COSTUME_ADULT: 'CommonBuffId' = 165769 + CHILDHOOD_PHASE_BEAR_IN_COSTUME_CHILD: 'CommonBuffId' = 165768 + CHILDHOOD_PHASE_BEAR_NOT_IN_COSTUME: 'CommonBuffId' = 165770 + CHILDHOOD_PHASE_BEAR_NOT_IN_COSTUME_IGNORE: 'CommonBuffId' = 166821 + CHILDHOOD_PHASE_CLINGY: 'CommonBuffId' = 164894 + CHILDHOOD_PHASE_CLINGY_SOCIAL_HAPPY: 'CommonBuffId' = 165607 + CHILDHOOD_PHASE_CLINGY_SOCIAL_STRESSED: 'CommonBuffId' = 165608 + CHILDHOOD_PHASE_DISTANT: 'CommonBuffId' = 164895 + CHILDHOOD_PHASE_DISTANT_PROXIMITY: 'CommonBuffId' = 165495 + CHILDHOOD_PHASE_LOUD: 'CommonBuffId' = 164897 + CHILDHOOD_PHASE_MEAN_STREAK: 'CommonBuffId' = 164898 + CHILDHOOD_PHASE_MEAN_STREAK_MEAN_SOCIAL: 'CommonBuffId' = 165685 + CHILDHOOD_PHASE_PICKY_EATER_A: 'CommonBuffId' = 164896 + CHILDHOOD_PHASE_PICKY_EATER_B: 'CommonBuffId' = 165204 + CHILDHOOD_PHASE_PICKY_EATER_C: 'CommonBuffId' = 165205 + CHILDHOOD_PHASE_PICKY_EATER_CONSUMED_FOOD_BAD: 'CommonBuffId' = 165184 + CHILDHOOD_PHASE_PICKY_EATER_CONSUMED_FOOD_GOOD: 'CommonBuffId' = 165183 + CHILDHOOD_PHASE_PICKY_EATER_D: 'CommonBuffId' = 165206 + CHILDHOOD_PHASE_PICKY_EATER_E: 'CommonBuffId' = 165207 + CHILDHOOD_PHASE_REBELLIOUS: 'CommonBuffId' = 164899 + CHILDREN_HIDDEN_GREET_RETURNING_CAREGIVER: 'CommonBuffId' = 168221 + CHILDREN_STORIES_NEIGHBOR_ADOPTED_A_BABY: 'CommonBuffId' = 279286 + CHILDREN_STORIES_NEIGHBOR_ADOPTED_A_CAT: 'CommonBuffId' = 279975 + CHILDREN_STORIES_NEIGHBOR_ADOPTED_A_CHILD: 'CommonBuffId' = 279288 + CHILDREN_STORIES_NEIGHBOR_ADOPTED_A_DOG: 'CommonBuffId' = 279977 + CHILDREN_STORIES_NEIGHBOR_ADOPTED_A_HORSE: 'CommonBuffId' = 337813 + CHILDREN_STORIES_NEIGHBOR_ADOPTED_A_TODDLER: 'CommonBuffId' = 279287 + CHILD_CONFIDENCE_HIDDEN_AFFORDANCE_CREATIVITY: 'CommonBuffId' = 307432 + CHILD_CONFIDENCE_HIDDEN_AFFORDANCE_HOMEWORK: 'CommonBuffId' = 307431 + CHILD_CONFIDENCE_HIDDEN_AFFORDANCE_MENTAL: 'CommonBuffId' = 307433 + CHILD_CONFIDENCE_HIDDEN_AFFORDANCE_MOTOR: 'CommonBuffId' = 307434 + CHILD_CONFIDENCE_HIDDEN_AFFORDANCE_SCHOOL: 'CommonBuffId' = 307430 + CHILD_CONFIDENCE_HIDDEN_AFFORDANCE_SOCIAL: 'CommonBuffId' = 307435 + CHILD_DIVORCE: 'CommonBuffId' = 97679 + CHILD_FIGHT: 'CommonBuffId' = 97588 + CHILD_HIDDEN_MET_NEW_SIBLING: 'CommonBuffId' = 97690 + CHILD_MET_NEW_SIBLING_ANGRY: 'CommonBuffId' = 97694 + CHILD_MET_NEW_SIBLING_HAPPY: 'CommonBuffId' = 97695 + CHILD_MET_NEW_SIBLING_SAD: 'CommonBuffId' = 97692 + CHOPSTICKS_OPTIONAL_PREFER_CHOPSTICKS: 'CommonBuffId' = 247897 + CHOPSTICKS_OPTIONAL_PREFER_FORKS: 'CommonBuffId' = 247909 + CINNAMON_BUN_AIR: 'CommonBuffId' = 118501 + CITY_LIFE_LIVING_STATUE_BUSKER_TIPPED_HIGH: 'CommonBuffId' = 143332 + CITY_LIFE_LIVING_STATUE_BUSKER_TIPPED_LOW: 'CommonBuffId' = 143331 + CITY_LIFE_LIVING_STATUE_BUSKER_TIPPED_MED: 'CommonBuffId' = 143333 + CIVIC_POLICY_GIVE_INFLUENCE_EXTRA_LARGE: 'CommonBuffId' = 234099 + CIVIC_POLICY_GIVE_INFLUENCE_LARGE: 'CommonBuffId' = 234097 + CIVIC_POLICY_GIVE_INFLUENCE_MEDIUM: 'CommonBuffId' = 234096 + CIVIC_POLICY_GIVE_INFLUENCE_SMALL: 'CommonBuffId' = 234093 + CIVIC_POLICY_GIVE_INFLUENCE_SMALL_FUN_COMMUNITY: 'CommonBuffId' = 234654 + CIVIC_POLICY_NPC_AUTONOMY_AGGRESSION: 'CommonBuffId' = 237929 + CIVIC_POLICY_NPC_AUTONOMY_BAG_NEIGHBORHOOD: 'CommonBuffId' = 237919 + CIVIC_POLICY_NPC_AUTONOMY_COMMUNAL_OWNERSHIP: 'CommonBuffId' = 237951 + CIVIC_POLICY_NPC_AUTONOMY_CREATIVE_ARTS: 'CommonBuffId' = 232215 + CIVIC_POLICY_NPC_AUTONOMY_FREE_LOVE: 'CommonBuffId' = 237930 + CIVIC_POLICY_NPC_AUTONOMY_FUN_COMMUNITY: 'CommonBuffId' = 232216 + CIVIC_POLICY_NPC_AUTONOMY_HOME_COOKING: 'CommonBuffId' = 232217 + CIVIC_POLICY_NPC_AUTONOMY_JUICED_COMMUNITY: 'CommonBuffId' = 232218 + CIVIC_POLICY_NPC_AUTONOMY_JUICED_COMMUNITY_DAZED: 'CommonBuffId' = 238039 + CIVIC_POLICY_NPC_AUTONOMY_MUSIC_ARTS: 'CommonBuffId' = 232219 + CIVIC_POLICY_NPC_AUTONOMY_OLD_DAYS: 'CommonBuffId' = 237931 + CIVIC_POLICY_NPC_AUTONOMY_SELF_CARE: 'CommonBuffId' = 232220 + CIVIC_POLICY_NPC_AUTONOMY_SELF_SUFFICIENT: 'CommonBuffId' = 232221 + CIVIC_POLICY_NPC_AUTONOMY_TECHNOLOGICAL_PROGRESS: 'CommonBuffId' = 232222 + CIVIC_POLICY_NPC_VOTE_COOLDOWN: 'CommonBuffId' = 237019 + CIVIC_POLICY_PLAYER_TRACKING_AGGRESSION: 'CommonBuffId' = 237926 + CIVIC_POLICY_PLAYER_TRACKING_COMMUNAL_OWNERSHIP: 'CommonBuffId' = 237953 + CIVIC_POLICY_PLAYER_TRACKING_CREATIVE_ARTS: 'CommonBuffId' = 232157 + CIVIC_POLICY_PLAYER_TRACKING_ECO_FRIENDLY_APPLIANCES: 'CommonBuffId' = 232601 + CIVIC_POLICY_PLAYER_TRACKING_FREE_LOVE: 'CommonBuffId' = 237928 + CIVIC_POLICY_PLAYER_TRACKING_FUN_COMMUNITY: 'CommonBuffId' = 232158 + CIVIC_POLICY_PLAYER_TRACKING_HOME_COOKING: 'CommonBuffId' = 232159 + CIVIC_POLICY_PLAYER_TRACKING_JUICED_COMMUNITY: 'CommonBuffId' = 232160 + CIVIC_POLICY_PLAYER_TRACKING_MUSIC_ARTS: 'CommonBuffId' = 232161 + CIVIC_POLICY_PLAYER_TRACKING_OBJECT_BASED_GREEN_GARDENING: 'CommonBuffId' = 234851 + CIVIC_POLICY_PLAYER_TRACKING_OLD_DAYS: 'CommonBuffId' = 237927 + CIVIC_POLICY_PLAYER_TRACKING_SELF_CARE: 'CommonBuffId' = 232162 + CIVIC_POLICY_PLAYER_TRACKING_SELF_SUFFICIENT: 'CommonBuffId' = 232163 + CIVIC_POLICY_PLAYER_TRACKING_TECHNOLOGICAL_PROGRESS: 'CommonBuffId' = 232164 + CIVIC_POLICY_PLAYER_TRACKING_UPCYCLING_INITIATIVE: 'CommonBuffId' = 233506 + CIVIC_POLICY_SOCIAL_BUFF_CONVINCE_TO_INSTALL_FAIL_ACTOR: 'CommonBuffId' = 233753 + CIVIC_POLICY_SOCIAL_BUFF_CONVINCE_TO_INSTALL_FAIL_TARGET: 'CommonBuffId' = 233754 + CIVIC_POLICY_SOCIAL_BUFF_CONVINCE_TO_INSTALL_SUCCESS_TARGET: 'CommonBuffId' = 233756 + CIVIC_POLICY_SOCIAL_BUFF_CONVINCE_TO_INSTALL_SUCCESS_TARGET_REPLACEMENT: 'CommonBuffId' = 233755 + CIVIC_POLICY_SOCIAL_BUFF_CONVINCE_TO_INSTALL_SUPER_FAIL_ACTOR: 'CommonBuffId' = 233751 + CIVIC_POLICY_SOCIAL_BUFF_CONVINCE_TO_INSTALL_SUPER_FAIL_TARGET: 'CommonBuffId' = 233752 + CIVIC_POLICY_SOCIAL_BUFF_CONVINCE_TO_REPEAL_TARGET_ANGRY: 'CommonBuffId' = 239017 + CIVIC_POLICY_SOCIAL_BUFF_CONVINCE_TO_REPEAL_TARGET_BORED: 'CommonBuffId' = 239018 + CIVIC_POLICY_SOCIAL_BUFF_CONVINCE_TO_SUPPORT_FAIL_ACTOR: 'CommonBuffId' = 233758 + CIVIC_POLICY_SOCIAL_BUFF_CONVINCE_TO_SUPPORT_FAIL_TARGET: 'CommonBuffId' = 233757 + CIVIC_POLICY_SOCIAL_BUFF_CONVINCE_TO_SUPPORT_SUCCESS_ACTOR: 'CommonBuffId' = 233750 + CIVIC_POLICY_SOCIAL_BUFF_CONVINCE_TO_SUPPORT_SUCCESS_TARGET: 'CommonBuffId' = 233759 + CLAIM_CRIMINAL_MASTERMIND_TARGET: 'CommonBuffId' = 26681 + CLEANED_TOILET_ENERGIZED: 'CommonBuffId' = 10454 + CLEANING_HAPPY: 'CommonBuffId' = 24003 + CLEANING_SAD: 'CommonBuffId' = 24004 + CLIMBING_ROUTE_BEST_VIEWS_HARDEST_CLIMBS: 'CommonBuffId' = 246137 + CLIMBING_ROUTE_BREAKING_POINT_REACHED: 'CommonBuffId' = 246127 + CLIMBING_ROUTE_BREAKING_POINT_REACHED_AVERAGE: 'CommonBuffId' = 247173 + CLIMBING_ROUTE_BREAKING_POINT_REACHED_AVERAGE_TRACKER: 'CommonBuffId' = 250558 + CLIMBING_ROUTE_BREAKING_POINT_REACHED_MASTER: 'CommonBuffId' = 247172 + CLIMBING_ROUTE_BREAKING_POINT_REACHED_MASTER_TRACKER: 'CommonBuffId' = 250559 + CLIMBING_ROUTE_BREAKING_POINT_REACHED_NOVICE_TRACKER: 'CommonBuffId' = 250560 + CLIMBING_ROUTE_CANCEL_CLIMB: 'CommonBuffId' = 247205 + CLIMBING_ROUTE_CLIMB_TRACKING_AVERAGE_ATTEMPT: 'CommonBuffId' = 247166 + CLIMBING_ROUTE_CLIMB_TRACKING_AVERAGE_BREAKING_POINT: 'CommonBuffId' = 245479 + CLIMBING_ROUTE_CLIMB_TRACKING_AVERAGE_CAUTIOUSLY: 'CommonBuffId' = 247167 + CLIMBING_ROUTE_CLIMB_TRACKING_AVERAGE_COURAGEOUSLY: 'CommonBuffId' = 247168 + CLIMBING_ROUTE_CLIMB_TRACKING_AVERAGE_METICULOUS_SESSION: 'CommonBuffId' = 245480 + CLIMBING_ROUTE_CLIMB_TRACKING_AVERAGE_NORMALLY: 'CommonBuffId' = 247169 + CLIMBING_ROUTE_CLIMB_TRACKING_AVERAGE_PRACTICE: 'CommonBuffId' = 245477 + CLIMBING_ROUTE_CLIMB_TRACKING_MASTER_ATTEMPT: 'CommonBuffId' = 247170 + CLIMBING_ROUTE_CLIMB_TRACKING_MASTER_BREAKING_POINT: 'CommonBuffId' = 245481 + CLIMBING_ROUTE_CLIMB_TRACKING_MASTER_CAUTIOUSLY: 'CommonBuffId' = 247177 + CLIMBING_ROUTE_CLIMB_TRACKING_MASTER_COURAGEOUSLY: 'CommonBuffId' = 247179 + CLIMBING_ROUTE_CLIMB_TRACKING_MASTER_METICULOUS_SESSION: 'CommonBuffId' = 245483 + CLIMBING_ROUTE_CLIMB_TRACKING_MASTER_NORMALLY: 'CommonBuffId' = 247178 + CLIMBING_ROUTE_CLIMB_TRACKING_MASTER_PRACTICE: 'CommonBuffId' = 245484 + CLIMBING_ROUTE_CLIMB_TRACKING_NOVICE_BREAKING_POINT: 'CommonBuffId' = 245485 + CLIMBING_ROUTE_CLIMB_TRACKING_NOVICE_CAUTIOUSLY: 'CommonBuffId' = 247163 + CLIMBING_ROUTE_CLIMB_TRACKING_NOVICE_COURAGEOUSLY: 'CommonBuffId' = 247165 + CLIMBING_ROUTE_CLIMB_TRACKING_NOVICE_METICULOUS_SESSION: 'CommonBuffId' = 245486 + CLIMBING_ROUTE_CLIMB_TRACKING_NOVICE_NORMALLY: 'CommonBuffId' = 247164 + CLIMBING_ROUTE_CLIMB_TRACKING_NOVICE_PRACTICE: 'CommonBuffId' = 245487 + CLIMBING_ROUTE_DID_RECENT_CLIMB: 'CommonBuffId' = 252875 + CLIMBING_ROUTE_EXCELS_AT_ELEVATING: 'CommonBuffId' = 246123 + CLIMBING_ROUTE_EXCELS_AT_ELEVATING_TRACKER: 'CommonBuffId' = 250575 + CLIMBING_ROUTE_FAILED_GRIP_SLIP: 'CommonBuffId' = 246119 + CLIMBING_ROUTE_FAILED_SLIP_GRIP_TRACKER: 'CommonBuffId' = 250573 + CLIMBING_ROUTE_FIGHTING_GRAVITY: 'CommonBuffId' = 246135 + CLIMBING_ROUTE_LESS_TALK_MORE_CHALK: 'CommonBuffId' = 246118 + CLIMBING_ROUTE_LESS_TALK_MORE_CHALK_TRACKER: 'CommonBuffId' = 250572 + CLIMBING_ROUTE_LIFE_ON_THE_ROCKS: 'CommonBuffId' = 246126 + CLIMBING_ROUTE_MORE_STRUGGLE_MORE_PROGRESS: 'CommonBuffId' = 246136 + CLIMBING_ROUTE_MOVING_UP: 'CommonBuffId' = 246121 + CLIMBING_ROUTE_NATURAL_BORN_CLIMBER: 'CommonBuffId' = 246134 + CLIMBING_ROUTE_NEVER_LOOK_DOWN: 'CommonBuffId' = 246132 + CLIMBING_ROUTE_NOT_READY_YET: 'CommonBuffId' = 246129 + CLIMBING_ROUTE_NOT_READY_YET_TRACKER: 'CommonBuffId' = 250570 + CLIMBING_ROUTE_OUTCOME_TRACKING_FAILURE: 'CommonBuffId' = 250494 + CLIMBING_ROUTE_OUTCOME_TRACKING_LARGE_FAILURE: 'CommonBuffId' = 250495 + CLIMBING_ROUTE_OUTCOME_TRACKING_LARGE_SUCCESS: 'CommonBuffId' = 250493 + CLIMBING_ROUTE_OUTCOME_TRACKING_SUCCESS: 'CommonBuffId' = 250492 + CLIMBING_ROUTE_PEAK_FAILURE: 'CommonBuffId' = 246125 + CLIMBING_ROUTE_PEAK_FAILURE_TRACKER: 'CommonBuffId' = 250577 + CLIMBING_ROUTE_PEAK_TRAINING: 'CommonBuffId' = 246122 + CLIMBING_ROUTE_PEAK_TRAINING_AVERAGE: 'CommonBuffId' = 247193 + CLIMBING_ROUTE_PEAK_TRAINING_AVERAGE_TRACKER: 'CommonBuffId' = 250561 + CLIMBING_ROUTE_PEAK_TRAINING_MASTER: 'CommonBuffId' = 247194 + CLIMBING_ROUTE_PEAK_TRAINING_MASTER_TRACKER: 'CommonBuffId' = 250562 + CLIMBING_ROUTE_PEAK_TRAINING_NOVICE_TRACKER: 'CommonBuffId' = 250563 + CLIMBING_ROUTE_PRACTICE_NOT_MAKE_PERFECT: 'CommonBuffId' = 246124 + CLIMBING_ROUTE_PRACTICE_NOT_MAKE_PERFECT_TRACKER: 'CommonBuffId' = 250576 + CLIMBING_ROUTE_REACHING_NEW_HEIGHTS: 'CommonBuffId' = 246131 + CLIMBING_ROUTE_REACHING_ROCK_BOTTOM: 'CommonBuffId' = 246120 + CLIMBING_ROUTE_REACHING_ROCK_BOTTOM_TRACKER: 'CommonBuffId' = 250574 + CLIMBING_ROUTE_RECENT_EXTREME_SUCCESS: 'CommonBuffId' = 252873 + CLIMBING_ROUTE_ROCKSTAR: 'CommonBuffId' = 246138 + CLIMBING_ROUTE_SKILL_GAIN_LARGE: 'CommonBuffId' = 246114 + CLIMBING_ROUTE_SKILL_GAIN_SMALL: 'CommonBuffId' = 245998 + CLIMBING_ROUTE_SLOW_AND_STEADY: 'CommonBuffId' = 246117 + CLIMBING_ROUTE_SLOW_AND_STEADY_AVERAGE: 'CommonBuffId' = 247198 + CLIMBING_ROUTE_SLOW_AND_STEADY_AVERAGE_TRACKER: 'CommonBuffId' = 250564 + CLIMBING_ROUTE_SLOW_AND_STEADY_MASTER: 'CommonBuffId' = 247199 + CLIMBING_ROUTE_SLOW_AND_STEADY_MASTER_TRACKER: 'CommonBuffId' = 250565 + CLIMBING_ROUTE_SLOW_AND_STEADY_NOVICE_TRACKER: 'CommonBuffId' = 250566 + CLIMBING_ROUTE_SPECTACULAR_CLIMBING: 'CommonBuffId' = 246128 + CLIMBING_ROUTE_SPECTACULAR_CLIMBING_TRACKER: 'CommonBuffId' = 250568 + CLIMBING_ROUTE_SUMMITOR_PLUMMET: 'CommonBuffId' = 246130 + CLIMBING_ROUTE_SUMMITOR_PLUMMET_TRACKER: 'CommonBuffId' = 250571 + CLIMBING_ROUTE_TIME_TO_ROCK: 'CommonBuffId' = 246133 + CLONING_MACHINE_FAILURE_GOATEE: 'CommonBuffId' = 115351 + CLOTHING_ANGRY_LION: 'CommonBuffId' = 33344 + CLOTHING_CATEGORY_TEMPERATURE_COLD_CLOTHING: 'CommonBuffId' = 182695 + CLOTHING_CATEGORY_TEMPERATURE_HOT_CLOTHING: 'CommonBuffId' = 182696 + CLOTHING_CATEGORY_TEMPERATURE_IMMUNE: 'CommonBuffId' = 182697 + CLOTHING_CATEGORY_TEMPERATURE_MODIFIER: 'CommonBuffId' = 190002 + CLOTHING_DAZED_BEAR: 'CommonBuffId' = 33347 + CLOTHING_ENERGIZED_OWL: 'CommonBuffId' = 33348 + CLOTHING_FLIRTY_COW: 'CommonBuffId' = 33342 + CLOTHING_HAT_OF_SHAME: 'CommonBuffId' = 40360 + CLOTHING_HYSTERICAL_TIGER: 'CommonBuffId' = 33346 + CLOTHING_INSPIRED_CHICKEN: 'CommonBuffId' = 33343 + CLOTHING_NUDE: 'CommonBuffId' = 128807 + CLOTHING_NUDE_TODDLER: 'CommonBuffId' = 157429 + CLOTHING_SAD_PANDA: 'CommonBuffId' = 33345 + CLOTHING_STAR_SPANGLED_GLASSES: 'CommonBuffId' = 100126 + CLOTHING_SUIT_OF_LOVE: 'CommonBuffId' = 40352 + CLOTHING_TICKLE_ME_PINK: 'CommonBuffId' = 40356 + CLOTHING_TRAGIC_CLOWN_MISERY_LOVES_COMPANY: 'CommonBuffId' = 139614 + CLOTHING_TRAGIC_CLOWN_TEARS_OF_A_CLOWN: 'CommonBuffId' = 139611 + CLUBS_BAD_CLUB_MEMBER: 'CommonBuffId' = 123823 + CLUBS_BROKE_A_RULE: 'CommonBuffId' = 123790 + CLUBS_BROKE_A_RULE_APPLIED_AFTER_INTERACTION_COMPLETES: 'CommonBuffId' = 130470 + CLUBS_FAILED_GAMBIT: 'CommonBuffId' = 123821 + CLUBS_INSECURE_THRONE: 'CommonBuffId' = 123822 + CLUBS_PASSED_THE_TORCH: 'CommonBuffId' = 123820 + CLUBS_PERKS_SOCIAL_BONUS_FRIENDLY: 'CommonBuffId' = 126042 + CLUBS_PERKS_SOCIAL_BONUS_FUNNY: 'CommonBuffId' = 126045 + CLUBS_PERKS_SOCIAL_BONUS_MEAN: 'CommonBuffId' = 126046 + CLUBS_PERKS_SOCIAL_BONUS_MISCHIEF: 'CommonBuffId' = 126044 + CLUBS_PERKS_SOCIAL_BONUS_ROMANTIC: 'CommonBuffId' = 126043 + CLUBS_REJECTED: 'CommonBuffId' = 123824 + CLUBS_TORCH_PASSED: 'CommonBuffId' = 123819 + CLUB_GATHERING_ADD_NPC_INVITE_COOLDOWN: 'CommonBuffId' = 130394 + CLUB_GATHERING_NPC_INVITE_COOLDOWN: 'CommonBuffId' = 130392 + CLUB_GATHERING_PROVIDED_AFFORDANCE: 'CommonBuffId' = 193128 + CLUB_PERKS_INFAMOUS_CLUB_INTIMIDATED_BY_CLUB_MEMBER: 'CommonBuffId' = 126311 + CLUB_PERKS_POPULAR_CLUB_AWED_BY_CLUB_MEMBER: 'CommonBuffId' = 126125 + CLUB_PERKS_SET_VIBE_AMONG_COMRADES_1: 'CommonBuffId' = 126064 + CLUB_PERKS_SET_VIBE_AMONG_COMRADES_2: 'CommonBuffId' = 126065 + CLUB_PERKS_SET_VIBE_AMONG_COMRADES_3: 'CommonBuffId' = 126066 + CLUB_PERKS_SET_VIBE_ANGRY_1: 'CommonBuffId' = 126053 + CLUB_PERKS_SET_VIBE_ANGRY_2: 'CommonBuffId' = 126054 + CLUB_PERKS_SET_VIBE_ANGRY_3: 'CommonBuffId' = 126052 + CLUB_PERKS_SET_VIBE_CONFIDENT_1: 'CommonBuffId' = 126056 + CLUB_PERKS_SET_VIBE_CONFIDENT_2: 'CommonBuffId' = 126057 + CLUB_PERKS_SET_VIBE_CONFIDENT_3: 'CommonBuffId' = 126058 + CLUB_PERKS_SET_VIBE_ENERGIZED_1: 'CommonBuffId' = 126060 + CLUB_PERKS_SET_VIBE_ENERGIZED_2: 'CommonBuffId' = 126061 + CLUB_PERKS_SET_VIBE_ENERGIZED_3: 'CommonBuffId' = 126062 + CLUB_PERKS_SET_VIBE_FLIRTY_1: 'CommonBuffId' = 126068 + CLUB_PERKS_SET_VIBE_FLIRTY_2: 'CommonBuffId' = 126069 + CLUB_PERKS_SET_VIBE_FLIRTY_3: 'CommonBuffId' = 126070 + CLUB_PERKS_SET_VIBE_FOCUSED_1: 'CommonBuffId' = 126072 + CLUB_PERKS_SET_VIBE_FOCUSED_2: 'CommonBuffId' = 126073 + CLUB_PERKS_SET_VIBE_FOCUSED_3: 'CommonBuffId' = 126074 + CLUB_PERKS_SET_VIBE_INSPIRED_1: 'CommonBuffId' = 126076 + CLUB_PERKS_SET_VIBE_INSPIRED_2: 'CommonBuffId' = 126077 + CLUB_PERKS_SET_VIBE_INSPIRED_3: 'CommonBuffId' = 126078 + CLUB_PERKS_SET_VIBE_PLAYFUL_1: 'CommonBuffId' = 126080 + CLUB_PERKS_SET_VIBE_PLAYFUL_2: 'CommonBuffId' = 126081 + CLUB_PERKS_SET_VIBE_PLAYFUL_3: 'CommonBuffId' = 126082 + CLUB_PERKS_SET_VIBE_SAD_1: 'CommonBuffId' = 126084 + CLUB_PERKS_SET_VIBE_SAD_2: 'CommonBuffId' = 126085 + CLUB_PERKS_SET_VIBE_SAD_3: 'CommonBuffId' = 126086 + CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_ACTING: 'CommonBuffId' = 201034 + CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_ARCHAEOLOGY: 'CommonBuffId' = 174280 + CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_BAKING: 'CommonBuffId' = 126252 + CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_BARTENDING: 'CommonBuffId' = 125834 + CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_CHARISMA: 'CommonBuffId' = 125872 + CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_COMEDY: 'CommonBuffId' = 125880 + CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_DJ: 'CommonBuffId' = 125881 + CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_DOG_TRAINING: 'CommonBuffId' = 170916 + CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_EQUESTRIAN_SKILL: 'CommonBuffId' = 332925 + CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_FABRICATION: 'CommonBuffId' = 231943 + CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_FISHING: 'CommonBuffId' = 125882 + CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_FITNESS: 'CommonBuffId' = 125883 + CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_FLOWER_ARRANGING: 'CommonBuffId' = 190030 + CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_GARDENING: 'CommonBuffId' = 125884 + CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_GOURMET_COOKING: 'CommonBuffId' = 125885 + CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_GUITAR: 'CommonBuffId' = 125886 + CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_HANDINESS: 'CommonBuffId' = 125888 + CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_HERBALISM: 'CommonBuffId' = 126267 + CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_HOME_STYLE_COOKING: 'CommonBuffId' = 125889 + CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_KNITTING: 'CommonBuffId' = 242249 + CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_LOGIC: 'CommonBuffId' = 125891 + CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_MISCHIEF: 'CommonBuffId' = 125892 + CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_PAINTING: 'CommonBuffId' = 125894 + CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_PARENTING: 'CommonBuffId' = 165915 + CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_PIANO: 'CommonBuffId' = 125896 + CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_PROGRAMMING: 'CommonBuffId' = 125897 + CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_RESEARCH_DEBATE: 'CommonBuffId' = 229649 + CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_ROBOTICS: 'CommonBuffId' = 219168 + CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_ROCKET_SCIENCE: 'CommonBuffId' = 125899 + CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_ROCK_CLIMBING: 'CommonBuffId' = 253671 + CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_ROMANCE: 'CommonBuffId' = 393392 + CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_SINGING: 'CommonBuffId' = 151916 + CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_SKIING: 'CommonBuffId' = 246489 + CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_SNOWBOARD: 'CommonBuffId' = 246796 + CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_VETERINARIAN: 'CommonBuffId' = 170915 + CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_VIDEO_GAMING: 'CommonBuffId' = 125900 + CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_VIOLIN: 'CommonBuffId' = 125902 + CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_WELLNESS: 'CommonBuffId' = 128403 + CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_WRITING: 'CommonBuffId' = 125906 + CLUB_PERKS_SKILL_BOOST_ADULT_MINOR_BOWLING: 'CommonBuffId' = 163340 + CLUB_PERKS_SKILL_BOOST_ADULT_MINOR_CROSS_STITCH: 'CommonBuffId' = 263767 + CLUB_PERKS_SKILL_BOOST_ADULT_MINOR_DANCING: 'CommonBuffId' = 128399 + CLUB_PERKS_SKILL_BOOST_ADULT_MINOR_JUICE_FIZZING: 'CommonBuffId' = 239068 + CLUB_PERKS_SKILL_BOOST_ADULT_MINOR_LOCAL_CULTURE: 'CommonBuffId' = 182983 + CLUB_PERKS_SKILL_BOOST_ADULT_MINOR_MEDIA_PRODUCTION: 'CommonBuffId' = 201031 + CLUB_PERKS_SKILL_BOOST_ADULT_MINOR_PHOTOGRAPHY: 'CommonBuffId' = 126250 + CLUB_PERKS_SKILL_BOOST_CHILD_CREATIVITY: 'CommonBuffId' = 125912 + CLUB_PERKS_SKILL_BOOST_CHILD_MENTAL: 'CommonBuffId' = 125915 + CLUB_PERKS_SKILL_BOOST_CHILD_MOTOR: 'CommonBuffId' = 125916 + CLUB_PERKS_SKILL_BOOST_CHILD_SOCIAL: 'CommonBuffId' = 125920 + COFFEE_UPGRADED: 'CommonBuffId' = 23830 + COFFIN_HUMAN_NIGHTMARE: 'CommonBuffId' = 154766 + COFFIN_VAMPIRE_DAY_MARE: 'CommonBuffId' = 154767 + COFFIN_VAMPIRE_GOOD_DREAM: 'CommonBuffId' = 154768 + COLLECTION_CASE_VIEW_FOCUSED: 'CommonBuffId' = 180428 + COLLEGE_ORGANIZATION_ART_SOCIETY_RANK_3: 'CommonBuffId' = 223666 + COLLEGE_ORGANIZATION_DEBATE_DECLARE_WINNER: 'CommonBuffId' = 225667 + COLLEGE_ORGANIZATION_DEBATE_EXTRA_CREDIT_COOLDOWN: 'CommonBuffId' = 229377 + COLLEGE_ORGANIZATION_EVENTS_SOCIAL_COUNTER: 'CommonBuffId' = 223955 + COLLEGE_ORGANIZATION_EVENTS_SOCIAL_COUNTER_ADD_ORG_PROGRESS: 'CommonBuffId' = 223964 + COLLEGE_ORGANIZATION_HONOR_SOCIETY_EXTRA_CREDIT_COOLDOWN: 'CommonBuffId' = 229573 + COLLEGE_ORGANIZATION_HONOR_SOCIETY_RANK3: 'CommonBuffId' = 226892 + COLLEGE_ORGANIZATION_ROBOTICS_RANK3: 'CommonBuffId' = 223083 + COLLEGE_ORGANIZATION_SCHOOL_SPIRIT_PARTY_STREAK_COOLDOWN: 'CommonBuffId' = 225224 + COLLEGE_ORGANIZATION_SECRET_SOCIETY_ATTACK_COOLDOWN: 'CommonBuffId' = 227357 + COLLEGE_ORGANIZATION_SECRET_SOCIETY_FEELING_GUILTY: 'CommonBuffId' = 219080 + COLLEGE_ORGANIZATION_SECRET_SOCIETY_FEELING_GUILTY_HIDDEN: 'CommonBuffId' = 219296 + COLLEGE_ORGANIZATION_SECRET_SOCIETY_FEELING_GUILTY_IN_NEGATIVE: 'CommonBuffId' = 221761 + COLLEGE_ORGANIZATION_SECRET_SOCIETY_JOIN_VISIT_MARKED: 'CommonBuffId' = 222708 + COLLEGE_ORGANIZATION_SECRET_SOCIETY_NPC_OFFERING_COOLDOWN: 'CommonBuffId' = 222671 + COLLEGE_ORGANIZATION_SECRET_SOCIETY_NPC_RANDOM_LOOT: 'CommonBuffId' = 221525 + COLLEGE_ORGANIZATION_SECRET_SOCIETY_RITUAL_IN_ROBE: 'CommonBuffId' = 230284 + COLLEGE_ORGANIZATION_SECRET_SOCIETY_SPRITE_ENERGETIC: 'CommonBuffId' = 219240 + COLLEGE_ORGANIZATION_SECRET_SOCIETY_SPRITE_FLIRTY: 'CommonBuffId' = 219239 + COLLEGE_ORGANIZATION_SECRET_SOCIETY_SPRITE_FOCUSED: 'CommonBuffId' = 219082 + COLLEGE_ORGANIZATION_SECRET_SOCIETY_SPRITE_HAPPY: 'CommonBuffId' = 219081 + COLLEGE_ORGANIZATION_SECRET_SOCIETY_SPRITE_INSPIRED: 'CommonBuffId' = 219083 + COLLEGE_ORGANIZATION_SECRET_SOCIETY_SPRITE_TENSE: 'CommonBuffId' = 219079 + COLLEGE_ORGANIZATION_SECRET_SOCIETY_SPRITE_TENSE_NONMEMBER: 'CommonBuffId' = 227439 + COLLEGE_ORGANIZATION_SECRET_SOCIETY_SPRITE_VISITOR: 'CommonBuffId' = 226734 + COLLEGE_ORGANIZATION_SECRET_SOCIETY_SPRITE_VISITOR_COOLDOWN: 'CommonBuffId' = 226819 + COLLEGE_ORGANIZATION_SECRET_SOCIETY_SUMMON_COOLDOWN: 'CommonBuffId' = 220517 + COMMUNAL_EVENTS_ANIMAL_DAY_ROLE_GUESTS: 'CommonBuffId' = 331504 + COMMUNAL_EVENTS_ANIMAL_DAY_ROLE_HOST: 'CommonBuffId' = 331503 + COMMUNAL_EVENTS_ANIMAL_DAY_ROLE_RANCH_HELPER: 'CommonBuffId' = 331505 + COMMUNAL_EVENTS_GUESTS_HAVE_MET_HOST: 'CommonBuffId' = 331489 + COMMUNAL_EVENTS_RANCH_GATHERING_ROLE_GRILL_MASTER: 'CommonBuffId' = 338333 + COMMUNAL_EVENTS_RANCH_GATHERING_ROLE_GUESTS: 'CommonBuffId' = 338331 + COMMUNAL_EVENTS_RANCH_GATHERING_ROLE_HOST: 'CommonBuffId' = 338332 + COMMUNITY_BOARD_HORSE_REMOVE_RIDER_BEFORE_RABBITHOLE: 'CommonBuffId' = 348308 + COMMUNITY_CLOSENESS_CIVIC_POLICY_CALL_NOT_VOTING_SHAME: 'CommonBuffId' = 238048 + COMMUNITY_CLOSENESS_COMPLAIN_SHUNNED: 'CommonBuffId' = 238147 + COMMUNITY_CLOSENESS_GOGREEN_RECYCLING_TIME: 'CommonBuffId' = 232980 + COMMUNITY_CLOSENESS_IN_HERITENCE_MARRIED_FOR_MONEY: 'CommonBuffId' = 233023 + COMMUNITY_CLOSENESS_LANDGRAB_POWER_CURSE_YOU_LANDGRAB: 'CommonBuffId' = 233034 + COMMUNITY_CLOSENESS_LANDGRAB_POWER_HIDDEN_DISCOUNT: 'CommonBuffId' = 233066 + COMMUNITY_CLOSENESS_PARENTAL_CHECK_IN_HIDDEN_VISIT_CHECK: 'CommonBuffId' = 238044 + COMMUNITY_CLOSENESS_PARENTAL_CHECK_IN_MISSED_PARENTS: 'CommonBuffId' = 238043 + COMMUNITY_CLOSENESS_PRANK_CALL_PRANK_CALLED: 'CommonBuffId' = 233030 + COMMUNITY_CLOSENESS_SIM_TOCK_WEIRD_MEMES: 'CommonBuffId' = 238042 + COMMUNITY_CLOSENESS_TELEMARKETER_HAPPY_SIM: 'CommonBuffId' = 233031 + COMMUNITY_CLOSENESS_THE_MOTIVE_GAMES_LOSER: 'CommonBuffId' = 235127 + COMMUNITY_CLOSENESS_THE_MOTIVE_GAMES_WINNER: 'CommonBuffId' = 233035 + COMMUNITY_CLOSENESS_THE_SIMULATION_ONLY_A_SIM: 'CommonBuffId' = 233032 + COMMUNITY_CLOSENESS_THE_SIMULATION_WOAH: 'CommonBuffId' = 233033 + COMPASSIONATE_DID_MEAN_SOCIAL: 'CommonBuffId' = 162036 + COMPASSIONATE_EMOTIONS_CALMED: 'CommonBuffId' = 160910 + COMPASSIONATE_SHARE_ANGRY: 'CommonBuffId' = 160916 + COMPASSIONATE_SHARE_EMBARRASSED: 'CommonBuffId' = 160918 + COMPASSIONATE_SHARE_SAD: 'CommonBuffId' = 160917 + COMPASSIONATE_SHARE_STRESSED: 'CommonBuffId' = 160919 + COMPUTER_GLASSES_APPEARANCE_WEARING_BLUE: 'CommonBuffId' = 225099 + COMPUTER_GLASSES_APPEARANCE_WEARING_GREEN: 'CommonBuffId' = 225100 + COMPUTER_GLASSES_APPEARANCE_WEARING_ORANGE: 'CommonBuffId' = 225149 + COMPUTER_GLASSES_APPEARANCE_WEARING_PINK: 'CommonBuffId' = 225098 + COMPUTER_GLASSES_APPEARANCE_WEARING_RED: 'CommonBuffId' = 224990 + COMPUTER_GLASSES_APPEARANCE_WEARING_YELLOW: 'CommonBuffId' = 225153 + CONFIDENCE_BELIEF_BREEDS_CONFIDENCE: 'CommonBuffId' = 307444 + CONFIDENCE_FEELING_DISCOURAGED: 'CommonBuffId' = 307441 + CONFIDENCE_FEELING_ENCOURAGED: 'CommonBuffId' = 307443 + CONFIDENCE_HIGH_CONFIDENCE_BOOST: 'CommonBuffId' = 306787 + CONFIDENCE_HIGH_IVE_GOT_THIS: 'CommonBuffId' = 306784 + CONFIDENCE_HIGH_I_BELIEVE_IN_ME: 'CommonBuffId' = 306785 + CONFIDENCE_HIGH_LEARNING_FROM_MISTAKES: 'CommonBuffId' = 306786 + CONFIDENCE_LOW_CRUSHED: 'CommonBuffId' = 306793 + CONFIDENCE_LOW_ILL_NEVER: 'CommonBuffId' = 306792 + CONFIDENCE_NEUTRAL_I_CAN: 'CommonBuffId' = 306791 + CONFIDENCE_NEUTRAL_I_CANNOT: 'CommonBuffId' = 306790 + CONFIDENCE_SUPPORTED_DRIVE: 'CommonBuffId' = 307445 + CONFIDENCE_UNFAIR_CRITICISM: 'CommonBuffId' = 307442 + CONFIDENT_BRAG_ABOUT_STARTUP: 'CommonBuffId' = 37296 + CONFIDENT_BY_POTION: 'CommonBuffId' = 26332 + CONFIDENT_DISCUSS_CONQUESTS: 'CommonBuffId' = 37010 + CONFIDENT_MAD_SKILLZ: 'CommonBuffId' = 31550 + CONFIDENT_SO_SNEAKY: 'CommonBuffId' = 36392 + CONSTELLATION_FORMATIONS: 'CommonBuffId' = 107388 + COOLDOWN_REPUTATION_DONATION: 'CommonBuffId' = 201973 + CORE_SOCIAL_ANGRY: 'CommonBuffId' = 10647 + CORE_SOCIAL_BORED: 'CommonBuffId' = 10653 + CORE_SOCIAL_EMBARRASSING: 'CommonBuffId' = 10651 + CORE_SOCIAL_FLIRTY: 'CommonBuffId' = 10658 + CORE_SOCIAL_HAPPY: 'CommonBuffId' = 10655 + CORE_SOCIAL_HAPPY_OUTGOING: 'CommonBuffId' = 29578 + CORE_SOCIAL_PLAYFUL: 'CommonBuffId' = 10649 + COSTUME_BOX_COSTUME_AAYLA_SECURA: 'CommonBuffId' = 361437 + COSTUME_BOX_COSTUME_ALIEN: 'CommonBuffId' = 364648 + COSTUME_BOX_COSTUME_APRON: 'CommonBuffId' = 361394 + COSTUME_BOX_COSTUME_ASTRONAUT: 'CommonBuffId' = 361424 + COSTUME_BOX_COSTUME_BEAR: 'CommonBuffId' = 365429 + COSTUME_BOX_COSTUME_BOBA_FETT: 'CommonBuffId' = 361432 + COSTUME_BOX_COSTUME_BUNNY: 'CommonBuffId' = 365092 + COSTUME_BOX_COSTUME_BUTLER: 'CommonBuffId' = 365482 + COSTUME_BOX_COSTUME_BUTLER_FLIRTY: 'CommonBuffId' = 371452 + COSTUME_BOX_COSTUME_CATFISH: 'CommonBuffId' = 381081 + COSTUME_BOX_COSTUME_CHEERLEADER: 'CommonBuffId' = 361428 + COSTUME_BOX_COSTUME_CLOWN: 'CommonBuffId' = 361418 + COSTUME_BOX_COSTUME_CUPID: 'CommonBuffId' = 361395 + COSTUME_BOX_COSTUME_DARTH_MAUL: 'CommonBuffId' = 361431 + COSTUME_BOX_COSTUME_DARTH_VADER: 'CommonBuffId' = 361430 + COSTUME_BOX_COSTUME_DOCTOR: 'CommonBuffId' = 364649 + COSTUME_BOX_COSTUME_EGGPLANT: 'CommonBuffId' = 361425 + COSTUME_BOX_COSTUME_FAIRY: 'CommonBuffId' = 365108 + COSTUME_BOX_COSTUME_FATHER_WINTER: 'CommonBuffId' = 365091 + COSTUME_BOX_COSTUME_FIREFIGHTER: 'CommonBuffId' = 361419 + COSTUME_BOX_COSTUME_FIREFIGHTER_FLIRTY: 'CommonBuffId' = 370426 + COSTUME_BOX_COSTUME_GNOME: 'CommonBuffId' = 365093 + COSTUME_BOX_COSTUME_GRIM_REAPER: 'CommonBuffId' = 361421 + COSTUME_BOX_COSTUME_HOT_DOG: 'CommonBuffId' = 361417 + COSTUME_BOX_COSTUME_KNIGHT: 'CommonBuffId' = 365156 + COSTUME_BOX_COSTUME_LUCHADOR: 'CommonBuffId' = 361427 + COSTUME_BOX_COSTUME_LUKE_SKYWALKER: 'CommonBuffId' = 361435 + COSTUME_BOX_COSTUME_MAID: 'CommonBuffId' = 361422 + COSTUME_BOX_COSTUME_MAID_FLIRTY: 'CommonBuffId' = 370425 + COSTUME_BOX_COSTUME_MAILMAN: 'CommonBuffId' = 361423 + COSTUME_BOX_COSTUME_MASCOT: 'CommonBuffId' = 365433 + COSTUME_BOX_COSTUME_MASCOT_2: 'CommonBuffId' = 394379 + COSTUME_BOX_COSTUME_MASK: 'CommonBuffId' = 372334 + COSTUME_BOX_COSTUME_NINJA: 'CommonBuffId' = 365106 + COSTUME_BOX_COSTUME_PANDA: 'CommonBuffId' = 364500 + COSTUME_BOX_COSTUME_PARK_RANGER: 'CommonBuffId' = 370424 + COSTUME_BOX_COSTUME_PEACH: 'CommonBuffId' = 361426 + COSTUME_BOX_COSTUME_PIRATE: 'CommonBuffId' = 365104 + COSTUME_BOX_COSTUME_PIZZA_DELIVERY: 'CommonBuffId' = 361429 + COSTUME_BOX_COSTUME_POLICE: 'CommonBuffId' = 364650 + COSTUME_BOX_COSTUME_PRINCESS_LEIA: 'CommonBuffId' = 361438 + COSTUME_BOX_COSTUME_RACOON: 'CommonBuffId' = 364501 + COSTUME_BOX_COSTUME_RANCH_HAND: 'CommonBuffId' = 363131 + COSTUME_BOX_COSTUME_ROBOT: 'CommonBuffId' = 361420 + COSTUME_BOX_COSTUME_SKELETON: 'CommonBuffId' = 365161 + COSTUME_BOX_COSTUME_SMUGGLER: 'CommonBuffId' = 361434 + COSTUME_BOX_COSTUME_SPACE_RANGER: 'CommonBuffId' = 361433 + COSTUME_BOX_COSTUME_SPARTAN: 'CommonBuffId' = 365105 + COSTUME_BOX_COSTUME_VICTORIAN: 'CommonBuffId' = 364634 + COSTUME_BOX_COSTUME_VILLAIN: 'CommonBuffId' = 361439 + COSTUME_BOX_COSTUME_WITCH: 'CommonBuffId' = 365109 + COSTUME_BOX_TIMER_CONFIDENT: 'CommonBuffId' = 361932 + COSTUME_BOX_TIMER_FLIRTY: 'CommonBuffId' = 363012 + COSTUME_BOX_TIMER_PLAYFUL: 'CommonBuffId' = 363011 + COTTAGE_WORLD_GOSSIPER_GO_TO_SQUARE_COOLDOWN: 'CommonBuffId' = 264562 + COTTAGE_WORLD_MUSIC_IN_THE_WOODS: 'CommonBuffId' = 267048 + COTTAGE_WORLD_NPC_FREE_DRINK_COOLDOWN: 'CommonBuffId' = 266868 + COTTAGE_WORLD_NPC_MYSTERY_BOX_COOLDOWN_GARDEN: 'CommonBuffId' = 267082 + COTTAGE_WORLD_NPC_MYSTERY_BOX_COOLDOWN_GROCERY: 'CommonBuffId' = 267083 + COTTAGE_WORLD_NPC_OFFER_FAVOR_COOLDOWN: 'CommonBuffId' = 265102 + COTTAGE_WORLD_NPC_RECEIVE_FAVOR_COOLDOWN: 'CommonBuffId' = 265103 + COTTAGE_WORLD_PROXIMITY_RUINS_CONFIDENT: 'CommonBuffId' = 268099 + COTTAGE_WORLD_PROXIMITY_RUINS_HIDDEN: 'CommonBuffId' = 268541 + COTTAGE_WORLD_PROXIMITY_WATERFULL_INSPIRED: 'CommonBuffId' = 268101 + COTTAGE_WORLD_SNAIL_AUTONOMOUS_COOLDOWN: 'CommonBuffId' = 268424 + COW_PLANT_ESSENCE_ANGRY: 'CommonBuffId' = 8666 + COW_PLANT_ESSENCE_BORED: 'CommonBuffId' = 8667 + COW_PLANT_ESSENCE_CONFIDENT: 'CommonBuffId' = 8668 + COW_PLANT_ESSENCE_EMBARRASSED: 'CommonBuffId' = 8669 + COW_PLANT_ESSENCE_ENERGIZED: 'CommonBuffId' = 8671 + COW_PLANT_ESSENCE_FLIRTY: 'CommonBuffId' = 8672 + COW_PLANT_ESSENCE_FOCUSED: 'CommonBuffId' = 8673 + COW_PLANT_ESSENCE_HAPPY: 'CommonBuffId' = 8674 + COW_PLANT_ESSENCE_INSPIRED: 'CommonBuffId' = 8675 + COW_PLANT_ESSENCE_LIFE: 'CommonBuffId' = 29987 + COW_PLANT_ESSENCE_PLAYFUL: 'CommonBuffId' = 8676 + COW_PLANT_ESSENCE_SAD: 'CommonBuffId' = 8677 + COW_PLANT_ESSENCE_SLOSHED: 'CommonBuffId' = 8678 + COW_PLANT_ESSENCE_STRESSED: 'CommonBuffId' = 8679 + COW_PLANT_ESSENCE_UNCOMFORTABLE: 'CommonBuffId' = 8680 + CRISP_AIR: 'CommonBuffId' = 108250 + CRISP_AIR_LOVES_OUTDOORS: 'CommonBuffId' = 108256 + CROSS_AGE_INTERACTIONS_CALL_THEM_SOMETHING_MEAN: 'CommonBuffId' = 316220 + CROSS_AGE_INTERACTIONS_CLAIM_ARE_ALIEN: 'CommonBuffId' = 316175 + CROSS_AGE_INTERACTIONS_CLAIM_ARE_HUMAN: 'CommonBuffId' = 316176 + CROSS_AGE_INTERACTIONS_CLAIM_ARE_PLANT_SIM: 'CommonBuffId' = 316174 + CROSS_AGE_INTERACTIONS_CLAIM_FAILED: 'CommonBuffId' = 316177 + CROSS_AGE_INTERACTIONS_DISAPPROVE_LACK_OF_CHILD_DISCIPLINE: 'CommonBuffId' = 312466 + CROSS_AGE_INTERACTIONS_DISAPPROVE_OF_CHILD_DISCIPLINING: 'CommonBuffId' = 312464 + CROSS_AGE_INTERACTIONS_ENTHUSE_ABOUT_NEW_SIBLING: 'CommonBuffId' = 316442 + CROSS_AGE_INTERACTIONS_FAMILY_KISS_LOCKOUT: 'CommonBuffId' = 329904 + CROSS_AGE_INTERACTIONS_FOUND_PARENT: 'CommonBuffId' = 312923 + CROSS_AGE_INTERACTIONS_GOOD_TIMES: 'CommonBuffId' = 314197 + CROSS_AGE_INTERACTIONS_MAKE_SCARY_FACE: 'CommonBuffId' = 316221 + CROSS_AGE_INTERACTIONS_MOAN_ABOUT_NEW_SIBLING: 'CommonBuffId' = 316441 + CROSS_AGE_INTERACTIONS_NOT_PICKED_UP: 'CommonBuffId' = 316714 + CROSS_AGE_INTERACTIONS_NOT_THE_FAVORITE: 'CommonBuffId' = 314029 + CROSS_AGE_INTERACTIONS_PICKED_UP: 'CommonBuffId' = 316713 + CROSS_AGE_INTERACTIONS_SAGE_ADVICE_BORED: 'CommonBuffId' = 313657 + CROSS_AGE_INTERACTIONS_SAGE_ADVICE_FAMILY: 'CommonBuffId' = 313249 + CROSS_AGE_INTERACTIONS_SAGE_ADVICE_FRIENDSHIP: 'CommonBuffId' = 313248 + CROSS_AGE_INTERACTIONS_SAGE_ADVICE_HARD_WORK: 'CommonBuffId' = 313252 + CROSS_AGE_INTERACTIONS_SAGE_ADVICE_LOVE: 'CommonBuffId' = 313247 + CROSS_AGE_INTERACTIONS_SAGE_ADVICE_MONEY: 'CommonBuffId' = 313250 + CROSS_AGE_INTERACTIONS_SAGE_ADVICE_RESPONSIBILITY: 'CommonBuffId' = 313251 + CROSS_AGE_INTERACTIONS_STRANGER_DANGER: 'CommonBuffId' = 313057 + CROSS_AGE_INTERACTIONS_SWEET_TREAT: 'CommonBuffId' = 313052 + CROSS_AGE_INTERACTIONS_THE_FAVORITE: 'CommonBuffId' = 314030 + CROSS_STITCH_COMPLETED: 'CommonBuffId' = 358615 + CROSS_STITCH_EXPERT_STITCHER: 'CommonBuffId' = 261191 + CROSS_STITCH_HOMESTYLE_STITCHING: 'CommonBuffId' = 261196 + CROSS_STITCH_NIFTY_STITCHING: 'CommonBuffId' = 261188 + CROSS_STITCH_ONE_POKE_TOO_MANY: 'CommonBuffId' = 261190 + CRUMPLE_BOTTOMED: 'CommonBuffId' = 264407 + CRY_OVER_DOLLHOUSE: 'CommonBuffId' = 12393 + CUDDLE_NEW_BABY: 'CommonBuffId' = 98944 + CUDDLE_ON_BED_ALLOW_SLEEP: 'CommonBuffId' = 366133 + CUDDLE_ON_BED_FORCE_LEAVE_SLEEP: 'CommonBuffId' = 361012 + CUDDLE_ON_BED_GO_TO_SLEEP: 'CommonBuffId' = 360647 + CUDDLE_ON_BED_IN_AWAKE_CUDDLE: 'CommonBuffId' = 360735 + CUDDLE_ON_BED_STAY_ASLEEP: 'CommonBuffId' = 361178 + CULLING_GHOST: 'CommonBuffId' = 161431 + CUP_OF_COZY: 'CommonBuffId' = 170014 + CURFEW_HIGH_RESPONSIBILITY: 'CommonBuffId' = 168811 + CURFEW_MID_RESPONSIBILITY: 'CommonBuffId' = 168812 + CURSES_ANCIENT_SICKNESS_COMMON: 'CommonBuffId' = 175022 + CURSES_ANCIENT_SICKNESS_RARE: 'CommonBuffId' = 175023 + CURSES_ANCIENT_SICKNESS_UNCOMMON: 'CommonBuffId' = 175024 + CURSES_APPLY_CURSE_ANCIENT_SICKNESS_COMMON: 'CommonBuffId' = 175035 + CURSES_APPLY_CURSE_ANCIENT_SICKNESS_RARE: 'CommonBuffId' = 175036 + CURSES_APPLY_CURSE_ANCIENT_SICKNESS_UNCOMMON: 'CommonBuffId' = 175034 + CURSES_APPLY_CURSE_GREEDY_NEEDS_COMMON: 'CommonBuffId' = 175181 + CURSES_APPLY_CURSE_GREEDY_NEEDS_RARE: 'CommonBuffId' = 175182 + CURSES_APPLY_CURSE_GREEDY_NEEDS_UNCOMMON: 'CommonBuffId' = 175183 + CURSES_APPLY_CURSE_MARKED_FOR_DEATH_RARE: 'CommonBuffId' = 175219 + CURSES_APPLY_CURSE_MARKED_FOR_DEATH_UNCOMMON: 'CommonBuffId' = 175220 + CURSES_APPLY_CURSE_PERSONAL_RAIN_CLOUD_COMMON: 'CommonBuffId' = 174901 + CURSES_APPLY_CURSE_PERSONAL_RAIN_CLOUD_RARE: 'CommonBuffId' = 174904 + CURSES_APPLY_CURSE_PERSONAL_RAIN_CLOUD_UNCOMMON: 'CommonBuffId' = 174903 + CURSES_APPLY_CURSE_SEEING_THINGS_COMMON: 'CommonBuffId' = 175263 + CURSES_APPLY_CURSE_SEEING_THINGS_RARE: 'CommonBuffId' = 175265 + CURSES_APPLY_CURSE_SEEING_THINGS_UNCOMMON: 'CommonBuffId' = 175264 + CURSES_APPLY_MARKED_FOR_DEATH_COMMON: 'CommonBuffId' = 180621 + CURSES_EFFECTS_GREEDY_NEEDS_DISPEL_AT_HIGH_MOTIVES: 'CommonBuffId' = 175209 + CURSES_EFFECTS_PERSONAL_RAIN_CLOUD_ANGRY: 'CommonBuffId' = 174936 + CURSES_EFFECTS_PERSONAL_RAIN_CLOUD_BORED: 'CommonBuffId' = 174939 + CURSES_EFFECTS_PERSONAL_RAIN_CLOUD_CONFIDENT: 'CommonBuffId' = 174940 + CURSES_EFFECTS_PERSONAL_RAIN_CLOUD_DAZED: 'CommonBuffId' = 174937 + CURSES_EFFECTS_PERSONAL_RAIN_CLOUD_EMBARRASSED: 'CommonBuffId' = 174938 + CURSES_EFFECTS_PERSONAL_RAIN_CLOUD_ENERGIZED: 'CommonBuffId' = 174941 + CURSES_EFFECTS_PERSONAL_RAIN_CLOUD_FLIRTY: 'CommonBuffId' = 174942 + CURSES_EFFECTS_PERSONAL_RAIN_CLOUD_FOCUSED: 'CommonBuffId' = 174943 + CURSES_EFFECTS_PERSONAL_RAIN_CLOUD_HAPPY: 'CommonBuffId' = 174944 + CURSES_EFFECTS_PERSONAL_RAIN_CLOUD_INSPIRED: 'CommonBuffId' = 174945 + CURSES_EFFECTS_PERSONAL_RAIN_CLOUD_PLAYFUL: 'CommonBuffId' = 174946 + CURSES_EFFECTS_PERSONAL_RAIN_CLOUD_SAD: 'CommonBuffId' = 174935 + CURSES_EFFECTS_PERSONAL_RAIN_CLOUD_STRESSED: 'CommonBuffId' = 174933 + CURSES_EFFECTS_PERSONAL_RAIN_CLOUD_STRESSED_SHORT: 'CommonBuffId' = 180189 + CURSES_EFFECTS_PERSONAL_RAIN_CLOUD_UNCOMFORTABLE: 'CommonBuffId' = 174948 + CURSES_FOUNTAIN_OF_MAGIC_TRAIT_HIDDEN: 'CommonBuffId' = 215755 + CURSES_GREEDY_NEEDS_COMMON: 'CommonBuffId' = 175188 + CURSES_GREEDY_NEEDS_RARE: 'CommonBuffId' = 175190 + CURSES_GREEDY_NEEDS_UNCOMMON: 'CommonBuffId' = 175189 + CURSES_HEX_OF_DUELIST_PUSH_OPPONENT: 'CommonBuffId' = 218332 + CURSES_INFECTIOUS_LAUGHTER_TEMP_IMMUNITY: 'CommonBuffId' = 215941 + CURSES_MARKED_FOR_DEATH_COMMON: 'CommonBuffId' = 180774 + CURSES_MARKED_FOR_DEATH_RARE: 'CommonBuffId' = 175223 + CURSES_MARKED_FOR_DEATH_UNCOMMON: 'CommonBuffId' = 175224 + CURSES_NIGHT_STALKER_BEING_CHASED: 'CommonBuffId' = 216417 + CURSES_NIGHT_STALKER_HIDDEN_STALKER_ROLE_IDLE: 'CommonBuffId' = 216312 + CURSES_NIGHT_STALKER_HIDDEN_STALKER_ROLE_LEAVE: 'CommonBuffId' = 216541 + CURSES_NIGHT_STALKER_HIDDEN_STALKER_ROLE_SCREAM: 'CommonBuffId' = 216313 + CURSES_NIGHT_STALKER_HIDDEN_TRAIT: 'CommonBuffId' = 215608 + CURSES_NIGHT_STALKER_HIDDEN_TRAIT_STALKER: 'CommonBuffId' = 216516 + CURSES_PERSONAL_RAIN_CLOUD_COMMON: 'CommonBuffId' = 174906 + CURSES_PERSONAL_RAIN_CLOUD_RARE: 'CommonBuffId' = 174907 + CURSES_PERSONAL_RAIN_CLOUD_UNCOMMON: 'CommonBuffId' = 174908 + CURSES_PUNCHABLEFACE_HIDDEN_BROADCASTER: 'CommonBuffId' = 215330 + CURSES_PUNCHABLE_FACE_HIDDEN_TRAIT: 'CommonBuffId' = 215276 + CURSES_REPULSIVENESS: 'CommonBuffId' = 215053 + CURSES_REPULSIVENESS_HIDDEN_REMOVEBUFF: 'CommonBuffId' = 215072 + CURSES_SEEING_THINGS_COMMON: 'CommonBuffId' = 175267 + CURSES_SEEING_THINGS_RARE: 'CommonBuffId' = 175269 + CURSES_SEEING_THINGS_UNCOMMON: 'CommonBuffId' = 175268 + CURSES_SWEATYSTENCH_HIDDEN_TRAIT: 'CommonBuffId' = 215514 + CURSES_TEMP_IMMUNITY: 'CommonBuffId' = 215741 + CURSES_TOUCHY_FEELY_HIDDEN_TRAIT: 'CommonBuffId' = 215496 + CUSTOM_STATE_WEDDING_BLISSFUL_MARRIAGE: 'CommonBuffId' = 279277 + CUSTOM_STATE_WEDDING_CONFIDENT_DELIVERY: 'CommonBuffId' = 279270 + CUSTOM_STATE_WEDDING_GOOD_SPEECH: 'CommonBuffId' = 279271 + CUSTOM_STATE_WEDDING_HONEYMOON_IS_OVER: 'CommonBuffId' = 279267 + CUSTOM_STATE_WEDDING_IS_WEAR: 'CommonBuffId' = 279274 + CUSTOM_STATE_WEDDING_OFFICIANT_SPEECH: 'CommonBuffId' = 279275 + CUSTOM_STATE_WEDDING_QUESTIONABLE_REFERENCES: 'CommonBuffId' = 279653 + CUSTOM_STATE_WEDDING_RUNAWAY: 'CommonBuffId' = 279269 + CUSTOM_STATE_WEDDING_SOMETHING_BLUE_SOMETHING: 'CommonBuffId' = 279268 + CUSTOM_STATE_WEDDING_STOP_SITTING: 'CommonBuffId' = 292134 + CUSTOM_STATE_WEDDING_THOSE_VOWS: 'CommonBuffId' = 279273 + CUSTOM_STATE_WEDDING_VOWS_OVER: 'CommonBuffId' = 291178 + CUSTOM_STATE_WEDDING_WEDDING_BUBBLES: 'CommonBuffId' = 279265 + CUSTOM_STATE_WEDDING_WEDDING_DAY_INSPIRATION: 'CommonBuffId' = 279279 + CUSTOM_STATE_WEDDING_WEDDING_DAY_NOT_TO_DOS: 'CommonBuffId' = 279280 + CUSTOM_STATE_WEDDING_WEDDING_KISS: 'CommonBuffId' = 279276 + CUSTOM_STATE_WEDDING_WEDDING_RICE: 'CommonBuffId' = 279266 + CUSTOM_STATE_WEDDING_WHAT_DID_THEY_SAY: 'CommonBuffId' = 279654 + CUSTOM_STATE_WEDDING_WISHING_AND_HOPING: 'CommonBuffId' = 279278 + CUSTOM_STATE_WEDDING_WITH_THIS_RING: 'CommonBuffId' = 279272 + DANCING_COUNTRY_DANCING: 'CommonBuffId' = 326349 + DANCING_COUNTRY_DANCING_IS_DANCING_GROUP: 'CommonBuffId' = 326432 + DANCING_COUNTRY_DANCING_WATCHER: 'CommonBuffId' = 326433 + DANCING_PAIRED_DANCING_SENTIMENTAL_SWAYING: 'CommonBuffId' = 278788 + DANCING_PAIRED_DANCING_THATS_MY_FOOT: 'CommonBuffId' = 278932 + DATE_DEBRIEF_AMAZING_RECOVERY: 'CommonBuffId' = 375123 + DATE_DEBRIEF_AMAZING_REGULAR: 'CommonBuffId' = 375124 + DATE_DEBRIEF_FINE_RECOVERY: 'CommonBuffId' = 375121 + DATE_DEBRIEF_FINE_REGULAR: 'CommonBuffId' = 375122 + DATE_DEBRIEF_POST_DATE_VALIDATION: 'CommonBuffId' = 376891 + DATE_DEBRIEF_TERRIBLE_RECOVERY: 'CommonBuffId' = 375119 + DATE_DEBRIEF_TERRIBLE_REGULAR: 'CommonBuffId' = 375120 + DEATH_BROKEN_HEART_DEPRESSED_FOOD_SHARING: 'CommonBuffId' = 381333 + DEATH_BROKEN_HEART_HEART_ACHE: 'CommonBuffId' = 377369 + DEATH_BROKEN_HEART_MISERY: 'CommonBuffId' = 377367 + DEATH_BROKEN_HEART_SORROW: 'CommonBuffId' = 377366 + DEATH_BROKEN_HEART_TOTAL_DESPAIR: 'CommonBuffId' = 377368 + DEATH_ELDER_EXHAUSTION_WARNING: 'CommonBuffId' = 9448 + DEATH_ELECTROCUTION_WARNING: 'CommonBuffId' = 8686 + DEATH_METEORITE_WARNING: 'CommonBuffId' = 294213 + DEATH_OF_SIM_ACQUAINTANCE: 'CommonBuffId' = 190991 + DEATH_OF_SIM_BFF: 'CommonBuffId' = 185333 + DEATH_OF_SIM_CHILD: 'CommonBuffId' = 185335 + DEATH_OF_SIM_CHILD_DISLIKED: 'CommonBuffId' = 185336 + DEATH_OF_SIM_DIVORCED: 'CommonBuffId' = 185338 + DEATH_OF_SIM_DIVORCED_DISLIKED: 'CommonBuffId' = 185339 + DEATH_OF_SIM_FRIEND: 'CommonBuffId' = 185340 + DEATH_OF_SIM_GOOD_FRIEND: 'CommonBuffId' = 185341 + DEATH_OF_SIM_GRANDPARENT: 'CommonBuffId' = 185343 + DEATH_OF_SIM_GRANDPARENT_DISLIKED: 'CommonBuffId' = 185344 + DEATH_OF_SIM_HORSE_FRIEND: 'CommonBuffId' = 324697 + DEATH_OF_SIM_HORSE_NEUTRAL: 'CommonBuffId' = 324696 + DEATH_OF_SIM_NEMESIS: 'CommonBuffId' = 190761 + DEATH_OF_SIM_NIBLING: 'CommonBuffId' = 185346 + DEATH_OF_SIM_NIBLING_DISLIKED: 'CommonBuffId' = 185347 + DEATH_OF_SIM_PARENT: 'CommonBuffId' = 185349 + DEATH_OF_SIM_PARENT_DISLIKED: 'CommonBuffId' = 185350 + DEATH_OF_SIM_PET_FRIEND: 'CommonBuffId' = 190774 + DEATH_OF_SIM_PET_NEUTRAL: 'CommonBuffId' = 190775 + DEATH_OF_SIM_PIBLING: 'CommonBuffId' = 185352 + DEATH_OF_SIM_PIBLING_DISLIKED: 'CommonBuffId' = 185353 + DEATH_OF_SIM_ROMANTIC: 'CommonBuffId' = 185354 + DEATH_OF_SIM_SIBLING: 'CommonBuffId' = 185356 + DEATH_OF_SIM_SIBLING_DISLIKED: 'CommonBuffId' = 185357 + DEATH_OF_SIM_SPOUSE: 'CommonBuffId' = 185359 + DEATH_OF_SIM_SPOUSE_DISLIKED: 'CommonBuffId' = 185360 + DEATH_PUFFER_FISH_CANCEL_PUT_DOWN: 'CommonBuffId' = 134978 + DEATH_URBAN_MYTH_SAW_MIRROR_EP12: 'CommonBuffId' = 295883 + DEATH_WONT_DO_DEATH_INTERACTIONS: 'CommonBuffId' = 360603 + DEATH_WONT_DO_DEATH_SOLO_INTERACTIONS: 'CommonBuffId' = 117010 + DEBATE_SKILL_CONVINCE_BATHE: 'CommonBuffId' = 228449 + DEBATE_SKILL_CONVINCE_CLEAN: 'CommonBuffId' = 223453 + DEBATE_SKILL_CONVINCE_COOK: 'CommonBuffId' = 228421 + DEBATE_SKILL_DEGRADED: 'CommonBuffId' = 227701 + DEBATE_SKILL_GOING_SOLO: 'CommonBuffId' = 227704 + DEBATE_SKILL_HOMEWORK_HELP_COOLDOWN_CLASS_A: 'CommonBuffId' = 227753 + DEBATE_SKILL_HOMEWORK_HELP_COOLDOWN_CLASS_B: 'CommonBuffId' = 227754 + DEBATE_SKILL_HOMEWORK_HELP_COOLDOWN_CLASS_C: 'CommonBuffId' = 227755 + DEBATE_SKILL_HOMEWORK_HELP_COOLDOWN_CLASS_D: 'CommonBuffId' = 227756 + DEBATE_SKILL_INEFFICIENT_STUDIER: 'CommonBuffId' = 227703 + DEBATE_SKILL_INSIDER_STUDY: 'CommonBuffId' = 227702 + DEBATE_SKILL_OVERBEARING: 'CommonBuffId' = 223542 + DEBATE_SKILL_PREPARED: 'CommonBuffId' = 225145 + DEBATE_SKILL_STUDY_TIPS_COOLDOWN: 'CommonBuffId' = 228199 + DEBT_COMMODITY: 'CommonBuffId' = 226841 + DEBT_POST_HUMOUS_POVERTY_MAD: 'CommonBuffId' = 228591 + DEBT_POST_HUMOUS_POVERTY_SAD: 'CommonBuffId' = 228590 + DEBUG_INTERACTIONS: 'CommonBuffId' = 161518 + DEBUG_INTERACTION_FAIL: 'CommonBuffId' = 290825 + DEBUG_PET_WANDERLUST_CARRY: 'CommonBuffId' = 163956 + DEBUG_PET_WANDERLUST_MISSING: 'CommonBuffId' = 173608 + DEBUG_PET_WANDERLUST_NOTHING: 'CommonBuffId' = 163958 + DEBUG_PET_WANDERLUST_PREGNANT: 'CommonBuffId' = 163957 + DEBUG_PET_WANDERLUST_SICK: 'CommonBuffId' = 163955 + DELIVERIES_ASK_FOR_TIP_COOLDOWN: 'CommonBuffId' = 262352 + DELIVERIES_COUPON_REDEEMED: 'CommonBuffId' = 267620 + DELIVERIES_FOOD_DELIVERY_EAT_AT_HOME: 'CommonBuffId' = 267132 + DENIZEN_POND_AGITATED_BITES: 'CommonBuffId' = 192260 + DENIZEN_POND_CALMING_DENIZENS: 'CommonBuffId' = 192257 + DENIZEN_POND_DENIZENS_DENIED: 'CommonBuffId' = 199409 + DENIZEN_POND_FERVENT_PREDATORS: 'CommonBuffId' = 192258 + DENIZEN_POND_MISCHIEVOUS_SPRITES: 'CommonBuffId' = 192261 + DENIZEN_POND_PLAYFUL_DENIZENS: 'CommonBuffId' = 192259 + DENIZEN_POND_SOPPING: 'CommonBuffId' = 199407 + DIPLOMA_ASPIRING_TO_KNOWLEDGE: 'CommonBuffId' = 224283 + DIPLOMA_GRADUATE_GAFFE: 'CommonBuffId' = 224285 + DIPLOMA_KIND_OF_BIG_DEAL: 'CommonBuffId' = 224284 + DIPLOMA_NOT_WORTH_PAPER_WRITTEN_ON: 'CommonBuffId' = 224280 + DIPLOMA_STUCK_IN_RUT: 'CommonBuffId' = 224281 + DIPLOMA_THAT_PLACE_SUCKS: 'CommonBuffId' = 224282 + DIPLOMA_TIME_WELL_SPENT: 'CommonBuffId' = 224277 + DISCERNING_DWELLER_PIECE_OF_CAKE: 'CommonBuffId' = 354202 + DISCERNING_DWELLER_WHAT_RULES: 'CommonBuffId' = 354203 + DISCIPLINE_BAD_GRADES: 'CommonBuffId' = 163548 + DISCIPLINE_BEING_DISCIPLINED: 'CommonBuffId' = 168536 + DISCIPLINE_BROKE_CURFEW: 'CommonBuffId' = 163288 + DISCIPLINE_GOOD_GRADES: 'CommonBuffId' = 163547 + DISCIPLINE_QUIT_JOB: 'CommonBuffId' = 163621 + DISCIPLINE_TEEN_JOB_PERFORMANCE_GOOD: 'CommonBuffId' = 163593 + DISCIPLINE_TIME_OUT_BORED: 'CommonBuffId' = 163231 + DISCIPLINE_TIME_OUT_BROKE: 'CommonBuffId' = 167841 + DISCIPLINE_TIME_OUT_FOCUSED: 'CommonBuffId' = 163233 + DISCIPLINE_TIME_OUT_SAD: 'CommonBuffId' = 163232 + DISCUSS_EXPANDING_THE_FAMILY_BABY_JOY: 'CommonBuffId' = 274751 + DISCUSS_EXPANDING_THE_FAMILY_COOLDOWN_HIDDEN: 'CommonBuffId' = 274120 + DISCUSS_EXPANDING_THE_FAMILY_FRIEND_EXPECTING: 'CommonBuffId' = 274523 + DISCUSS_EXPANDING_THE_FAMILY_HIDDEN_COOLDOWN_PREGNANCY_SUCCESS: 'CommonBuffId' = 275715 + DOCTOR_AWAY_EVENT_PATIENT: 'CommonBuffId' = 114016 + DOCTOR_PATIENT: 'CommonBuffId' = 115002 + DOCTOR_PATIENT_NO_VFX_WALK_STYLE: 'CommonBuffId' = 116260 + DOCTOR_PATIENT_VFX_BLUE: 'CommonBuffId' = 115646 + DOCTOR_PLAY_SET_ADULT_BECAME_DOCTOR: 'CommonBuffId' = 168521 + DOCTOR_PLAY_SET_ADULT_BECAME_VET: 'CommonBuffId' = 175695 + DOCTOR_PLAY_SET_CONFIDENT: 'CommonBuffId' = 161481 + DOCTOR_PLAY_SET_PLAYFUL: 'CommonBuffId' = 161479 + DOCTOR_PLAY_SET_SAD: 'CommonBuffId' = 161480 + DOG_ACTIVE_ROUGHHOUSE_PLAY_DECAY: 'CommonBuffId' = 173490 + DOG_CONDITIONING_SHORT_TERM_BARK: 'CommonBuffId' = 148253 + DOG_CONDITIONING_SHORT_TERM_BEG_FOR_FOOD: 'CommonBuffId' = 148254 + DOG_HEEL: 'CommonBuffId' = 167006 + DOG_ON_LEASH_HIDDEN: 'CommonBuffId' = 164919 + DOG_TO_DOG_PLAY_SOCIAL: 'CommonBuffId' = 176980 + DOG_TRAINING_BORED_PROTECTION: 'CommonBuffId' = 167211 + DOG_TRAINING_COOL_TRICK: 'CommonBuffId' = 164387 + DOG_TRAINING_FETCH_BORED_PROTECTION: 'CommonBuffId' = 168613 + DOG_TRAINING_PARTICIPANT: 'CommonBuffId' = 170274 + DOG_TRAINING_QUALITY_TIME: 'CommonBuffId' = 164372 + DOG_TRAINING_SHOW_OFF_DOG: 'CommonBuffId' = 165920 + DOG_TRAINING_SHOW_OFF_HUMAN: 'CommonBuffId' = 165750 + DOG_TRAINING_SHOW_OFF_TRICKS: 'CommonBuffId' = 170017 + DOG_TRAINING_TENSE: 'CommonBuffId' = 164386 + DOG_TRAINING_TRICK_LEARNED_EXIT_CONDITION_FETCH: 'CommonBuffId' = 167731 + DOG_TRAINING_TRICK_LEARNED_EXIT_CONDITION_HIDDEN: 'CommonBuffId' = 162553 + DOG_WALKING_GO_FOR_JOG_DOG_JOG_BEHAVIOR: 'CommonBuffId' = 177662 + DOG_WALKING_SIM_GOOD_WALK: 'CommonBuffId' = 165223 + DOLPHIN_DOLPHIN_FRIEND_1: 'CommonBuffId' = 206476 + DOLPHIN_DOLPHIN_FRIEND_2: 'CommonBuffId' = 206477 + DOLPHIN_DOLPHIN_FRIEND_3: 'CommonBuffId' = 206475 + DOLPHIN_FEED_COOLDOWN: 'CommonBuffId' = 211583 + DOLPHIN_FEED_RELATIONSHIP_MODIFIER: 'CommonBuffId' = 208348 + DOLPHIN_FIRST_ATTEMPT_DANCE: 'CommonBuffId' = 211536 + DOLPHIN_FIRST_ATTEMPT_FETCH: 'CommonBuffId' = 211537 + DOLPHIN_FIRST_ATTEMPT_JUMP: 'CommonBuffId' = 211611 + DOLPHIN_FIRST_ATTEMPT_KISS: 'CommonBuffId' = 211539 + DOLPHIN_FIRST_ATTEMPT_RUB_BELLY: 'CommonBuffId' = 211538 + DOLPHIN_MEAN_SPLASH_RELATIONSHIP_MAXIMIZER: 'CommonBuffId' = 212490 + DOLPHIN_NO_DOLPHIN: 'CommonBuffId' = 207032 + DOLPHIN_PET_RELATIONSHIP_MINIMIZER: 'CommonBuffId' = 211581 + DOLPHIN_RUB_BELLY_RELATIONSHIP_COOLDOWN: 'CommonBuffId' = 208355 + DOLPHIN_SPOUTING_OFF: 'CommonBuffId' = 206547 + DOLPHIN_SPOUTING_OFF_ANGRY: 'CommonBuffId' = 211224 + DOLPHIN_SPOUTING_OFF_SAD: 'CommonBuffId' = 211225 + DOLPHIN_SQUIRT_SILLINESS: 'CommonBuffId' = 206546 + DOLPHIN_SUMMON_COOLDOWN: 'CommonBuffId' = 211414 + DOLPHIN_TALK_RELATIONSHIP_MINIMIZER: 'CommonBuffId' = 211107 + DOLPHIN_TRICK_COOLDOWN_DANCE: 'CommonBuffId' = 206550 + DOLPHIN_TRICK_COOLDOWN_FETCH: 'CommonBuffId' = 206551 + DOLPHIN_TRICK_COOLDOWN_JUMP: 'CommonBuffId' = 211609 + DOLPHIN_TRICK_COOLDOWN_KISS: 'CommonBuffId' = 206552 + DOLPHIN_TRICK_COOLDOWN_RUB_BELLY: 'CommonBuffId' = 206549 + DRAINED: 'CommonBuffId' = 12396 + DRAMA_CLUB_ARRIVAL: 'CommonBuffId' = 200523 + DRAMA_CLUB_CRY_ON_DEMAND: 'CommonBuffId' = 199902 + DRAMA_CLUB_FRIDAY_SHOW: 'CommonBuffId' = 200344 + DRAMA_CLUB_HAPPY: 'CommonBuffId' = 200498 + DRAMA_CLUB_HOUSEHOLD_ATTENDING: 'CommonBuffId' = 200520 + DRAMA_CLUB_INSPIRED: 'CommonBuffId' = 200500 + DRAMA_CLUB_PRACTICE_ACTING_CONFIDENT: 'CommonBuffId' = 199901 + DRAMA_CLUB_PROMOTION: 'CommonBuffId' = 201014 + DRAMA_CLUB_SAD: 'CommonBuffId' = 200499 + DRINK_BEETLE_JUICE_3_INVISIBLE: 'CommonBuffId' = 235951 + DRINK_COFFEE_TEA_COOLDOWN: 'CommonBuffId' = 355197 + DRINK_MICROWAVE_HOT_WATER_NEGATIVE: 'CommonBuffId' = 352193 + DRINK_MILK_LIVESTOCK_BLACK: 'CommonBuffId' = 263350 + DRINK_MILK_LIVESTOCK_BROWN: 'CommonBuffId' = 262989 + DRINK_MILK_LIVESTOCK_ENRICHED: 'CommonBuffId' = 262979 + DRINK_MILK_LIVESTOCK_GOLD: 'CommonBuffId' = 263352 + DRINK_MILK_LIVESTOCK_GREEN: 'CommonBuffId' = 262997 + DRINK_MILK_LIVESTOCK_ORANGE: 'CommonBuffId' = 262995 + DRINK_MILK_LIVESTOCK_PINK: 'CommonBuffId' = 262994 + DRINK_MILK_LIVESTOCK_PINK_CHILD: 'CommonBuffId' = 268614 + DRINK_MILK_LIVESTOCK_RAINBOW: 'CommonBuffId' = 262990 + DRINK_MILK_LIVESTOCK_RED: 'CommonBuffId' = 262991 + DRINK_MOON_PETAL_CALM: 'CommonBuffId' = 289745 + DRINK_MOON_PETAL_STILLNESS: 'CommonBuffId' = 289746 + DRINK_NECTAR_ASTONISHING_AROMA_HIGH: 'CommonBuffId' = 132087 + DRINK_NECTAR_ASTONISHING_AROMA_HIGH_GREAT_PAIRING: 'CommonBuffId' = 132102 + DRINK_NECTAR_ASTONISHING_AROMA_NORMAL: 'CommonBuffId' = 132077 + DRINK_NECTAR_ASTONISHING_AROMA_NORMAL_GREAT_PAIRING: 'CommonBuffId' = 132105 + DRINK_NECTAR_BREATHTAKING_BALANCE_HIGH: 'CommonBuffId' = 132089 + DRINK_NECTAR_BREATHTAKING_BALANCE_HIGH_GREAT_PAIRING: 'CommonBuffId' = 132107 + DRINK_NECTAR_BREATHTAKING_BALANCE_NORMAL: 'CommonBuffId' = 132078 + DRINK_NECTAR_BREATHTAKING_BALANCE_NORMAL_GREAT_PAIRING: 'CommonBuffId' = 132109 + DRINK_NECTAR_COMMANDING_COMPLEXITY_HIGH: 'CommonBuffId' = 132091 + DRINK_NECTAR_COMMANDING_COMPLEXITY_HIGH_GREAT_PAIRING: 'CommonBuffId' = 132111 + DRINK_NECTAR_COMMANDING_COMPLEXITY_NORMAL: 'CommonBuffId' = 132079 + DRINK_NECTAR_COMMANDING_COMPLEXITY_NORMAL_GREAT_PAIRING: 'CommonBuffId' = 132113 + DRINK_NECTAR_FABULOUS_FINISH_HIGH: 'CommonBuffId' = 132093 + DRINK_NECTAR_FABULOUS_FINISH_HIGH_GREAT_PAIRING: 'CommonBuffId' = 132115 + DRINK_NECTAR_FABULOUS_FINISH_NORMAL: 'CommonBuffId' = 132076 + DRINK_NECTAR_FABULOUS_FINISH_NORMAL_GREAT_PAIRING: 'CommonBuffId' = 132117 + DRINK_NECTAR_LUSCIOUS_LIBATION: 'CommonBuffId' = 132085 + DRINK_NECTAR_LUSCIOUS_LIBATION_GREAT_PAIRING: 'CommonBuffId' = 133743 + DRINK_NECTAR_RED_PAIRING: 'CommonBuffId' = 132057 + DRINK_NECTAR_TANTALIZING_TANNINS_HIGH: 'CommonBuffId' = 132095 + DRINK_NECTAR_TANTALIZING_TANNINS_HIGH_GREAT_PAIRING: 'CommonBuffId' = 132119 + DRINK_NECTAR_TANTALIZING_TANNINS_NORMAL: 'CommonBuffId' = 132080 + DRINK_NECTAR_TANTALIZING_TANNINS_NORMAL_GREAT_PAIRING: 'CommonBuffId' = 132121 + DRINK_NECTAR_WHITE_PAIRING: 'CommonBuffId' = 132058 + DRINK_POWER_SIP_MIDNIGHT: 'CommonBuffId' = 289744 + DRINK_TEA_APPLE_CIDER: 'CommonBuffId' = 280353 + DRINK_TEA_BUILDERS_TEA_NOT_SWEET: 'CommonBuffId' = 356848 + DRINK_TEA_BUILDERS_TEA_TOO_SWEET: 'CommonBuffId' = 356851 + DRINK_TEA_CHAMOMILE_TEA: 'CommonBuffId' = 358715 + DRINK_TEA_COCOA: 'CommonBuffId' = 346704 + DRINK_TEA_COCOA_WITH_MARSHMALLOWS: 'CommonBuffId' = 346705 + DRINK_TEA_TEA_SET_BLACK_DRAGON: 'CommonBuffId' = 274312 + DRINK_TEA_TEA_SET_ORANGE_BLOSSOM: 'CommonBuffId' = 274313 + DRINK_TEA_UNICORN_GALAXY: 'CommonBuffId' = 346703 + DUMPSTER_DIRTY_FLIRTY: 'CommonBuffId' = 233597 + DUMPSTER_DIVE_FOR_COOLDOWN: 'CommonBuffId' = 240839 + DUMPSTER_DUMPSTER_DOVE: 'CommonBuffId' = 233595 + DUMPSTER_GROSSED_OUT_BY_DUMPSTERS: 'CommonBuffId' = 233596 + DUMPSTER_NAP_NOT_SLOB: 'CommonBuffId' = 238697 + DUMPSTER_NAP_SLOB: 'CommonBuffId' = 238696 + DUST_ASK_CLEAN_COOLDOWN: 'CommonBuffId' = 303735 + DUST_CLEAN_FRESH_N_FRISKY: 'CommonBuffId' = 254485 + DUST_CLEAN_PERFECTIONIST_ZEAL_1: 'CommonBuffId' = 254489 + DUST_CLEAN_PERFECTIONIST_ZEAL_2: 'CommonBuffId' = 254490 + DUST_CLEAN_PERFECTIONIST_ZEAL_3: 'CommonBuffId' = 254491 + DUST_CLEAN_PERFECTIONIST_ZEAL_4: 'CommonBuffId' = 254492 + DUST_DIRTY_MESSINESS_KILLS_THE_MOOD: 'CommonBuffId' = 254495 + DUST_DIRTY_MESSINESS_KILLS_THE_MOOD_FILTHY: 'CommonBuffId' = 257324 + DUST_DIRTY_NOT_USUALLY_LIKE_THIS: 'CommonBuffId' = 254494 + DUST_DUSTY_CHORE_GALORE: 'CommonBuffId' = 254493 + DUST_ENABLED: 'CommonBuffId' = 256481 + DUST_FILTHY_RAGE_CLEANING_1: 'CommonBuffId' = 254497 + DUST_FILTHY_RAGE_CLEANING_2: 'CommonBuffId' = 254498 + DUST_FILTHY_RAGE_CLEANING_3: 'CommonBuffId' = 254499 + DUST_FRIENDS_BUNNY_BFF: 'CommonBuffId' = 255315 + DUST_FRIENDS_BUNNY_CARE: 'CommonBuffId' = 255314 + DUST_FRIENDS_BUNNY_SAD: 'CommonBuffId' = 255316 + DUST_FRIENDS_FIEND_SCARED: 'CommonBuffId' = 255318 + DUST_FRIENDS_FIEND_SLAYER: 'CommonBuffId' = 255317 + DUST_INTERACTIONS_CHORE_SHAMED: 'CommonBuffId' = 254501 + DUST_INTERACTIONS_NOT_YOUR_HOUSEKEEPER: 'CommonBuffId' = 254502 + DUST_REACTION_COOLDOWN: 'CommonBuffId' = 318706 + DUST_STATE_CLEAN: 'CommonBuffId' = 254476 + DUST_STATE_DIRTY: 'CommonBuffId' = 254478 + DUST_STATE_DUSTY: 'CommonBuffId' = 254477 + DUST_STATE_FILTHY: 'CommonBuffId' = 254479 + DUST_STATE_NPC_DIRTY_FILTHY: 'CommonBuffId' = 257298 + DUST_STATE_SLOB_DIRTY: 'CommonBuffId' = 270224 + DUST_STATE_SLOB_FILTHY: 'CommonBuffId' = 270223 + DWELLING_HIDDEN_SUPPRESS_DECAY_OVERRIDE: 'CommonBuffId' = 237400 + DWELLING_MESS_AROUND_OUTERWORLD_FLING: 'CommonBuffId' = 245625 + DWELLING_WELL_RESTED: 'CommonBuffId' = 237379 + DWELLING_WOOHOO_TWO_FOR_BATUU: 'CommonBuffId' = 237406 + DYNAMIC_SIGN_VIEW_BUFF: 'CommonBuffId' = 133333 + ECO_FOOTPRINT_ACID_PUDDLE_HIDDEN: 'CommonBuffId' = 235221 + ECO_FOOTPRINT_BASK_IN_THE_LIGHT_BURNT: 'CommonBuffId' = 232109 + ECO_FOOTPRINT_BASK_IN_THE_LIGHT_PRAISED: 'CommonBuffId' = 232107 + ECO_FOOTPRINT_GREEN_BREATHE_DEEPLY: 'CommonBuffId' = 232134 + ECO_FOOTPRINT_HIDDEN_ACID_RAIN: 'CommonBuffId' = 239632 + ECO_FOOTPRINT_HIDDEN_BASK_IN_LIGHT_SUPRESSSUN: 'CommonBuffId' = 240794 + ECO_FOOTPRINT_HIDDEN_GREEN: 'CommonBuffId' = 232485 + ECO_FOOTPRINT_HIDDEN_INDUSTRIAL: 'CommonBuffId' = 232484 + ECO_FOOTPRINT_INDUSTRIAL_STRUGGLE_TO_BREATHE: 'CommonBuffId' = 232135 + ECO_INSPECTOR: 'CommonBuffId' = 239376 + ECO_LIVING: 'CommonBuffId' = 237050 + EMBARRASSED_GOT_LOST: 'CommonBuffId' = 75523 + EMBARRASSED_LONER: 'CommonBuffId' = 29532 + EMBARRASSING_CONVERSATION: 'CommonBuffId' = 12399 + EMOTIONAL_BUFFS_GENERAL_PETS_CAT_ANGRY_CATNIP: 'CommonBuffId' = 171119 + EMOTIONAL_BUFFS_GENERAL_PETS_CAT_ANGRY_LEVEL1: 'CommonBuffId' = 158476 + EMOTIONAL_BUFFS_GENERAL_PETS_CAT_ANGRY_LEVEL1_NOT_TIMED: 'CommonBuffId' = 168659 + EMOTIONAL_BUFFS_GENERAL_PETS_CAT_ANGRY_LEVEL2: 'CommonBuffId' = 158477 + EMOTIONAL_BUFFS_GENERAL_PETS_CAT_ANGRY_WALK_BY: 'CommonBuffId' = 171702 + EMOTIONAL_BUFFS_GENERAL_PETS_CAT_ANXIOUS_E_P05_THERMOSTAT: 'CommonBuffId' = 190956 + EMOTIONAL_BUFFS_GENERAL_PETS_CAT_ANXIOUS_LEVEL1: 'CommonBuffId' = 158478 + EMOTIONAL_BUFFS_GENERAL_PETS_CAT_ANXIOUS_LEVEL2: 'CommonBuffId' = 158479 + EMOTIONAL_BUFFS_GENERAL_PETS_CAT_DROWSY_CATNIP: 'CommonBuffId' = 171120 + EMOTIONAL_BUFFS_GENERAL_PETS_CAT_DROWSY_LEVEL1: 'CommonBuffId' = 158480 + EMOTIONAL_BUFFS_GENERAL_PETS_CAT_DROWSY_LEVEL2: 'CommonBuffId' = 158481 + EMOTIONAL_BUFFS_GENERAL_PETS_CAT_DROWSY_WALK_BY: 'CommonBuffId' = 178595 + EMOTIONAL_BUFFS_GENERAL_PETS_CAT_FINE_WALK_BY: 'CommonBuffId' = 171708 + EMOTIONAL_BUFFS_GENERAL_PETS_CAT_FLIRTY_CATNIP: 'CommonBuffId' = 171121 + EMOTIONAL_BUFFS_GENERAL_PETS_CAT_FLIRTY_LEVEL1: 'CommonBuffId' = 158482 + EMOTIONAL_BUFFS_GENERAL_PETS_CAT_FLIRTY_LEVEL2: 'CommonBuffId' = 158483 + EMOTIONAL_BUFFS_GENERAL_PETS_CAT_HAPPY_LEVEL1: 'CommonBuffId' = 158484 + EMOTIONAL_BUFFS_GENERAL_PETS_CAT_HAPPY_LEVEL2: 'CommonBuffId' = 158485 + EMOTIONAL_BUFFS_GENERAL_PETS_CAT_HAPPY_WALK_BY: 'CommonBuffId' = 171703 + EMOTIONAL_BUFFS_GENERAL_PETS_CAT_HYPER_CATNIP: 'CommonBuffId' = 171122 + EMOTIONAL_BUFFS_GENERAL_PETS_CAT_HYPER_LEVEL1: 'CommonBuffId' = 158486 + EMOTIONAL_BUFFS_GENERAL_PETS_CAT_HYPER_LEVEL2: 'CommonBuffId' = 158487 + EMOTIONAL_BUFFS_GENERAL_PETS_CAT_HYPER_WALK_BY: 'CommonBuffId' = 178593 + EMOTIONAL_BUFFS_GENERAL_PETS_CAT_SCARED_LEVEL1: 'CommonBuffId' = 158488 + EMOTIONAL_BUFFS_GENERAL_PETS_CAT_SCARED_LEVEL1_NOT_TIMED: 'CommonBuffId' = 168662 + EMOTIONAL_BUFFS_GENERAL_PETS_CAT_SCARED_LEVEL2: 'CommonBuffId' = 158489 + EMOTIONAL_BUFFS_GENERAL_PETS_CAT_VENGEFUL: 'CommonBuffId' = 165613 + EMOTIONAL_BUFFS_GENERAL_PETS_DOG_ANGRY_LEVEL1: 'CommonBuffId' = 158289 + EMOTIONAL_BUFFS_GENERAL_PETS_DOG_ANGRY_LEVEL1_NOT_TIMED: 'CommonBuffId' = 168661 + EMOTIONAL_BUFFS_GENERAL_PETS_DOG_ANGRY_LEVEL2: 'CommonBuffId' = 158311 + EMOTIONAL_BUFFS_GENERAL_PETS_DOG_ANGRY_WALK_BY: 'CommonBuffId' = 171704 + EMOTIONAL_BUFFS_GENERAL_PETS_DOG_ANXIOUS_E_P05_THERMOSTAT: 'CommonBuffId' = 190957 + EMOTIONAL_BUFFS_GENERAL_PETS_DOG_ANXIOUS_LEVEL1: 'CommonBuffId' = 158290 + EMOTIONAL_BUFFS_GENERAL_PETS_DOG_ANXIOUS_LEVEL2: 'CommonBuffId' = 158312 + EMOTIONAL_BUFFS_GENERAL_PETS_DOG_ASHAMED_LEVEL1: 'CommonBuffId' = 158291 + EMOTIONAL_BUFFS_GENERAL_PETS_DOG_ASHAMED_LEVEL2: 'CommonBuffId' = 158313 + EMOTIONAL_BUFFS_GENERAL_PETS_DOG_EXCITED_LEVEL1: 'CommonBuffId' = 158293 + EMOTIONAL_BUFFS_GENERAL_PETS_DOG_EXCITED_LEVEL2: 'CommonBuffId' = 158314 + EMOTIONAL_BUFFS_GENERAL_PETS_DOG_EXCITED_WALK_BY: 'CommonBuffId' = 178591 + EMOTIONAL_BUFFS_GENERAL_PETS_DOG_FINE_WALK_BY: 'CommonBuffId' = 171706 + EMOTIONAL_BUFFS_GENERAL_PETS_DOG_FLIRTY_LEVEL1: 'CommonBuffId' = 158292 + EMOTIONAL_BUFFS_GENERAL_PETS_DOG_FLIRTY_LEVEL2: 'CommonBuffId' = 158315 + EMOTIONAL_BUFFS_GENERAL_PETS_DOG_HAPPY_LEVEL1: 'CommonBuffId' = 158297 + EMOTIONAL_BUFFS_GENERAL_PETS_DOG_HAPPY_LEVEL2: 'CommonBuffId' = 158316 + EMOTIONAL_BUFFS_GENERAL_PETS_DOG_HAPPY_WALK_BY: 'CommonBuffId' = 171705 + EMOTIONAL_BUFFS_GENERAL_PETS_DOG_MOPEY_LEVEL1: 'CommonBuffId' = 158295 + EMOTIONAL_BUFFS_GENERAL_PETS_DOG_MOPEY_LEVEL2: 'CommonBuffId' = 158317 + EMOTIONAL_BUFFS_GENERAL_PETS_DOG_MOPEY_WALK_BY: 'CommonBuffId' = 178592 + EMOTIONAL_BUFFS_GENERAL_PETS_DOG_SAD_LEVEL1: 'CommonBuffId' = 158294 + EMOTIONAL_BUFFS_GENERAL_PETS_DOG_SAD_LEVEL2: 'CommonBuffId' = 158318 + EMOTIONAL_BUFFS_GENERAL_PETS_DOG_SCARED_LEVEL1: 'CommonBuffId' = 158296 + EMOTIONAL_BUFFS_GENERAL_PETS_DOG_SCARED_LEVEL1_NOT_TIMED: 'CommonBuffId' = 168660 + EMOTIONAL_BUFFS_GENERAL_PETS_DOG_SCARED_LEVEL2: 'CommonBuffId' = 158319 + EMOTIONAL_BUFFS_GENERAL_PETS_DOG_VENGEFUL: 'CommonBuffId' = 165615 + EMOTIONAL_BUFFS_SICKNESS_PETS_CAT_ANXIOUS: 'CommonBuffId' = 169698 + EMOTIONAL_BUFFS_SICKNESS_PETS_CAT_DROWSY: 'CommonBuffId' = 169697 + EMOTIONAL_BUFFS_SICKNESS_PETS_DOG_ANXIOUS: 'CommonBuffId' = 169695 + EMOTIONAL_BUFFS_SICKNESS_PETS_DOG_DROWSY: 'CommonBuffId' = 169696 + EMOTIONAL_BUFFS_WRITE_BOOK_CONFIDENT_HIGH: 'CommonBuffId' = 74803 + EMOTIONAL_BUFFS_WRITE_BOOK_CONFIDENT_LOW: 'CommonBuffId' = 74802 + EMOTIONAL_BUFFS_WRITE_BOOK_ENERGIZED_HIGH: 'CommonBuffId' = 74805 + EMOTIONAL_BUFFS_WRITE_BOOK_ENERGIZED_LOW: 'CommonBuffId' = 74804 + EMOTIONAL_BUFFS_WRITE_BOOK_FLIRTY_HIGH: 'CommonBuffId' = 74807 + EMOTIONAL_BUFFS_WRITE_BOOK_FLIRTY_LOW: 'CommonBuffId' = 74806 + EMOTIONAL_BUFFS_WRITE_BOOK_FOCUSED_HIGH: 'CommonBuffId' = 98157 + EMOTIONAL_BUFFS_WRITE_BOOK_FOCUSED_LOW: 'CommonBuffId' = 98156 + EMOTIONAL_BUFFS_WRITE_BOOK_INSPIRED_HIGH: 'CommonBuffId' = 98158 + EMOTIONAL_BUFFS_WRITE_BOOK_INSPIRED_LOW: 'CommonBuffId' = 98155 + EMOTIONAL_BUFFS_WRITE_BOOK_PLAYFUL_HIGH: 'CommonBuffId' = 74809 + EMOTIONAL_BUFFS_WRITE_BOOK_PLAYFUL_LOW: 'CommonBuffId' = 74808 + EMOTIONAL_BUFFS_WRITE_BOOK_SAD_HIGH: 'CommonBuffId' = 74811 + EMOTIONAL_BUFFS_WRITE_BOOK_SAD_LOW: 'CommonBuffId' = 74810 + EMOTIONAL_MELTDOWNS_EMBARRASSED: 'CommonBuffId' = 159502 + EMOTIONAL_MELTDOWNS_TENSE_NON_PARENT: 'CommonBuffId' = 159501 + EMOTIONAL_MELTDOWNS_TENSE_PARENT: 'CommonBuffId' = 160239 + EMOTIONAL_SUPPORT: 'CommonBuffId' = 99789 + ENCHANTED_CHARISMA: 'CommonBuffId' = 37497 + ENERGIZED_BY_POTION: 'CommonBuffId' = 26330 + ENERGIZING_SCENT: 'CommonBuffId' = 118500 + ENERGY_JUICE_ENERGIZED: 'CommonBuffId' = 99465 + ENERGY_JUICE_HIDDEN: 'CommonBuffId' = 99462 + ENLIGHTENED_AND_INSPIRED: 'CommonBuffId' = 118672 + ENLIGHTENED_CONFIDENCE: 'CommonBuffId' = 118514 + ENVIRONMENT_ANGRY_AMBIENCE_LARGE: 'CommonBuffId' = 12401 + ENVIRONMENT_ANGRY_AMBIENCE_MEDIUM: 'CommonBuffId' = 12402 + ENVIRONMENT_ANGRY_AMBIENCE_SMALL: 'CommonBuffId' = 12403 + ENVIRONMENT_BB_GAMEPLAY_EFFECTS_BAD_ENVIRONMENT_LARGE: 'CommonBuffId' = 238500 + ENVIRONMENT_BB_GAMEPLAY_EFFECTS_BAD_ENVIRONMENT_MEDIUM: 'CommonBuffId' = 238499 + ENVIRONMENT_BB_GAMEPLAY_EFFECTS_BAD_ENVIRONMENT_SMALL: 'CommonBuffId' = 238498 + ENVIRONMENT_BB_GAMEPLAY_EFFECTS_GOOD_ENVIRONMENT_LARGE: 'CommonBuffId' = 240250 + ENVIRONMENT_BB_GAMEPLAY_EFFECTS_GOOD_ENVIRONMENT_MEDIUM: 'CommonBuffId' = 240249 + ENVIRONMENT_BB_GAMEPLAY_EFFECTS_GOOD_ENVIRONMENT_SMALL: 'CommonBuffId' = 240248 + ENVIRONMENT_BB_GAMEPLAY_EFFECTS_SLOB_LARGE: 'CommonBuffId' = 238493 + ENVIRONMENT_BB_GAMEPLAY_EFFECTS_SLOB_LARGE_CHOOSER: 'CommonBuffId' = 239282 + ENVIRONMENT_BB_GAMEPLAY_EFFECTS_SLOB_MEDIUM: 'CommonBuffId' = 238495 + ENVIRONMENT_BB_GAMEPLAY_EFFECTS_SLOB_MEDIUM_CHOOSER: 'CommonBuffId' = 239281 + ENVIRONMENT_BB_GAMEPLAY_EFFECTS_SLOB_SMALL: 'CommonBuffId' = 238494 + ENVIRONMENT_BB_GAMEPLAY_EFFECTS_SLOB_SMALL_CHOOSER: 'CommonBuffId' = 239280 + ENVIRONMENT_BB_GAMEPLAY_EFFECTS_SNOB_LARGE: 'CommonBuffId' = 238492 + ENVIRONMENT_BB_GAMEPLAY_EFFECTS_SNOB_MEDIUM: 'CommonBuffId' = 238491 + ENVIRONMENT_BB_GAMEPLAY_EFFECTS_SNOB_SMALL: 'CommonBuffId' = 238490 + ENVIRONMENT_BORED_AMBIENCE_LARGE: 'CommonBuffId' = 12404 + ENVIRONMENT_BORED_AMBIENCE_MEDIUM: 'CommonBuffId' = 12405 + ENVIRONMENT_BORED_AMBIENCE_SMALL: 'CommonBuffId' = 12406 + ENVIRONMENT_CONFIDENT_AMBIENCE_LARGE: 'CommonBuffId' = 12407 + ENVIRONMENT_CONFIDENT_AMBIENCE_MEDIUM: 'CommonBuffId' = 12408 + ENVIRONMENT_CONFIDENT_AMBIENCE_SMALL: 'CommonBuffId' = 12409 + ENVIRONMENT_EMBARRASSED_AMBIENCE_LARGE: 'CommonBuffId' = 12410 + ENVIRONMENT_EMBARRASSED_AMBIENCE_MEDIUM: 'CommonBuffId' = 12411 + ENVIRONMENT_EMBARRASSED_AMBIENCE_SMALL: 'CommonBuffId' = 12412 + ENVIRONMENT_ENERGIZED_AMBIENCE_LARGE: 'CommonBuffId' = 12413 + ENVIRONMENT_ENERGIZED_AMBIENCE_MEDIUM: 'CommonBuffId' = 12414 + ENVIRONMENT_ENERGIZED_AMBIENCE_SMALL: 'CommonBuffId' = 12415 + ENVIRONMENT_FLIRTY_AMBIENCE_LARGE: 'CommonBuffId' = 12416 + ENVIRONMENT_FLIRTY_AMBIENCE_MEDIUM: 'CommonBuffId' = 12417 + ENVIRONMENT_FLIRTY_AMBIENCE_SMALL: 'CommonBuffId' = 12418 + ENVIRONMENT_FOCUSED_AMBIENCE_LARGE: 'CommonBuffId' = 12419 + ENVIRONMENT_FOCUSED_AMBIENCE_MEDIUM: 'CommonBuffId' = 12420 + ENVIRONMENT_FOCUSED_AMBIENCE_SMALL: 'CommonBuffId' = 12421 + ENVIRONMENT_HAPPY_AMBIENCE_LARGE: 'CommonBuffId' = 12422 + ENVIRONMENT_HAPPY_AMBIENCE_MEDIUM: 'CommonBuffId' = 12423 + ENVIRONMENT_HAPPY_AMBIENCE_SMALL: 'CommonBuffId' = 12424 + ENVIRONMENT_HAPPY_PEACE_AND_QUIET: 'CommonBuffId' = 179558 + ENVIRONMENT_HIDDEN_NEGATIVE: 'CommonBuffId' = 240236 + ENVIRONMENT_HIDDEN_NEGATIVE_SNOB: 'CommonBuffId' = 268126 + ENVIRONMENT_HIDDEN_POSITIVE: 'CommonBuffId' = 240234 + ENVIRONMENT_IMAGINATIVE_AMBIENCE_LARGE: 'CommonBuffId' = 12425 + ENVIRONMENT_IMAGINATIVE_AMBIENCE_MEDIUM: 'CommonBuffId' = 12426 + ENVIRONMENT_IMAGINATIVE_AMBIENCE_SMALL: 'CommonBuffId' = 12427 + ENVIRONMENT_NEGATIVE_BAD_SURROUNDINGS: 'CommonBuffId' = 12428 + ENVIRONMENT_NEGATIVE_ICKY_SURROUNDINGS: 'CommonBuffId' = 102939 + ENVIRONMENT_NEGATIVE_LITTER_BOX: 'CommonBuffId' = 172775 + ENVIRONMENT_NEGATIVE_UNPLEASANT_SURROUNDINGS: 'CommonBuffId' = 12429 + ENVIRONMENT_NEGATIVE_WRETCHED_SURROUNDINGS: 'CommonBuffId' = 12430 + ENVIRONMENT_PEACE_AND_QUIET_DISTRESS: 'CommonBuffId' = 179572 + ENVIRONMENT_PLAYFUL_AMBIENCE_LARGE: 'CommonBuffId' = 12431 + ENVIRONMENT_PLAYFUL_AMBIENCE_MEDIUM: 'CommonBuffId' = 12432 + ENVIRONMENT_PLAYFUL_AMBIENCE_SMALL: 'CommonBuffId' = 12433 + ENVIRONMENT_SAD_AMBIENCE_LARGE: 'CommonBuffId' = 12434 + ENVIRONMENT_SAD_AMBIENCE_MEDIUM: 'CommonBuffId' = 12435 + ENVIRONMENT_SAD_AMBIENCE_SMALL: 'CommonBuffId' = 12436 + ENVIRONMENT_SCARED_AMBIENCE_LARGE: 'CommonBuffId' = 251728 + ENVIRONMENT_SCARED_AMBIENCE_MEDIUM: 'CommonBuffId' = 251727 + ENVIRONMENT_SCARED_AMBIENCE_SMALL: 'CommonBuffId' = 251725 + ENVIRONMENT_TENSE_AMBIENCE_LARGE: 'CommonBuffId' = 12437 + ENVIRONMENT_TENSE_AMBIENCE_MEDIUM: 'CommonBuffId' = 12438 + ENVIRONMENT_TENSE_AMBIENCE_SMALL: 'CommonBuffId' = 12439 + EP10_FESTIVALS_AUTONOMY_BLESSING: 'CommonBuffId' = 252289 + EP10_FESTIVALS_AUTONOMY_HIKE: 'CommonBuffId' = 252281 + EP10_FESTIVALS_AUTONOMY_SELFIE: 'CommonBuffId' = 252290 + EP10_FESTIVALS_AUTONOMY_SNOW_FIGHT: 'CommonBuffId' = 253133 + EP10_FESTIVALS_AUTONOMY_VOID_CRITTER_HUNT: 'CommonBuffId' = 252288 + EP10_FESTIVALS_AUTONOMY_WISH: 'CommonBuffId' = 252282 + EP10_FESTIVALS_BLESSED_CHECK: 'CommonBuffId' = 267478 + EP10_FESTIVALS_GIVE_BLESSING: 'CommonBuffId' = 250932 + EP10_FESTIVALS_GOOD_WEATHER: 'CommonBuffId' = 254917 + EP10_FESTIVALS_GOOD_WEATHER_SNOW_FESTIVAL: 'CommonBuffId' = 254920 + EP10_FESTIVALS_MAKE_A_WISH: 'CommonBuffId' = 246877 + EP10_FESTIVALS_MAKE_A_WISH_TOGETHER: 'CommonBuffId' = 246878 + EP10_FESTIVALS_UNBLESSED_CHECK: 'CommonBuffId' = 253271 + EP10_FESTIVALS_VOID_CRITTER_HUNT_AVAILABLE: 'CommonBuffId' = 252725 + EP10_FESTIVALS_VOID_CRITTER_HUNT_AVAILABLE_NPC: 'CommonBuffId' = 252908 + EP10_FESTIVALS_VOID_CRITTER_HUNT_RECEIVED_PRIZE: 'CommonBuffId' = 252726 + EP10_FESTIVALS_VOID_CRITTER_HUNT_REMOVE_COUNT_AFTER_FESTIVAL: 'CommonBuffId' = 253423 + EP13_WORLD_FEELING_ANCHORED: 'CommonBuffId' = 320494 + EP13_WORLD_FISHERMANS_LUCK: 'CommonBuffId' = 320491 + EP13_WORLD_FOREST_FOR_THE_TREES: 'CommonBuffId' = 320495 + EP13_WORLD_STREET_PIANO_TUNES: 'CommonBuffId' = 320493 + EP13_WORLD_TOPIARYTASTIC: 'CommonBuffId' = 320516 + EP13_WORLD_WATCHOUT_FOR_WHITE_CLAW: 'CommonBuffId' = 320517 + EP13_WORLD_WHALEY_HAPPY: 'CommonBuffId' = 320518 + EP14_WORLD_CAVE_EXIT: 'CommonBuffId' = 325772 + EP14_WORLD_CAVE_FAILURE_EXIT: 'CommonBuffId' = 325025 + EP14_WORLD_CAVE_SELF_AWARE: 'CommonBuffId' = 325664 + EP14_WORLD_CAVE_SURVIVED_THE_CAVE: 'CommonBuffId' = 325665 + EP14_WORLD_CAVE_SURVIVED_THE_CAVE_DAZED: 'CommonBuffId' = 325666 + EP14_WORLD_HORSE_GRAVE: 'CommonBuffId' = 335440 + EP14_WORLD_NPC_ASK_FOR_LIFE_NECTAR_INGREDIENTS_MYSTERIOUS_RANCHER_COOLDOWN: 'CommonBuffId' = 322426 + EP14_WORLD_NPC_BONDING_TIME: 'CommonBuffId' = 322243 + EP14_WORLD_NPC_HIDDEN_READY_TO_RIDE_COOLDOWN: 'CommonBuffId' = 329418 + EP14_WORLD_NPC_NECTAR_KNOWLEDGE: 'CommonBuffId' = 322245 + EP14_WORLD_NPC_READY_TO_RANCH: 'CommonBuffId' = 322244 + EP14_WORLD_NPC_READY_TO_RIDE: 'CommonBuffId' = 322246 + EP14_WORLD_PROXIMITY_HORSE_ROCK: 'CommonBuffId' = 337346 + EP15_ADOPT_TIGER_ENERGIZED: 'CommonBuffId' = 353581 + EP15_ADOPT_TIGER_HAPPY: 'CommonBuffId' = 353582 + EP15_ADOPT_TIGER_HAPPY_PAT: 'CommonBuffId' = 353585 + EP15_ADOPT_TIGER_SAD: 'CommonBuffId' = 353583 + EP15_ADOPT_TIGER_SPECIAL_HAPPY: 'CommonBuffId' = 353584 + EP15_TRAIT_LOCAL: 'CommonBuffId' = 343328 + EP16_SPECIAL_NPC_SAD_BEAR: 'CommonBuffId' = 370490 + EP16_WORLD_FOUNTAIN_OF_DREAMS_STEAL_COOLDOWN_HIDDEN: 'CommonBuffId' = 369421 + EP16_WORLD_FOUNTAIN_OF_DREAMS_WISH_FOR_HAPPINESS: 'CommonBuffId' = 369265 + EP16_WORLD_FOUNTAIN_OF_DREAMS_WISH_FOR_LOVE: 'CommonBuffId' = 369264 + EP16_WORLD_FOUNTAIN_OF_DREAMS_WISH_FOR_OTHERS_HAPPINESS: 'CommonBuffId' = 369266 + EP16_WORLD_FOUNTAIN_OF_DREAMS_WISH_FOR_OTHERS_UNHAPPINESS: 'CommonBuffId' = 369297 + EP16_WORLD_REGION: 'CommonBuffId' = 388993 + EP16_WORLD_ROMANTIC_BLANKET_SPOT: 'CommonBuffId' = 370503 + EP16_WORLD_ROMANTIC_DATE_SPOT: 'CommonBuffId' = 370504 + EP16_WORLD_ROMANTIC_SUNSET_SPOT: 'CommonBuffId' = 370502 + EP16_WORLD_ROMANTIC_WALK: 'CommonBuffId' = 370508 + EP16_WORLD_WALL_OF_LOVE_CHANGE_LOVE_DECLARATIONS: 'CommonBuffId' = 369301 + EP16_WORLD_WALL_OF_LOVE_SYMBOL_OF_LOVE_ATTACHED: 'CommonBuffId' = 369299 + EP16_WORLD_WALL_OF_LOVE_SYMBOL_OF_LOVE_ERASED: 'CommonBuffId' = 369300 + EQUESTRIAN_CENTER_WATCHED_COMPETITIONS: 'CommonBuffId' = 333397 + EVENT_CONFIDENT: 'CommonBuffId' = 29685 + EVENT_ENERGIZED: 'CommonBuffId' = 29686 + EVENT_MARK: 'CommonBuffId' = 25287 + EVENT_NPC_HORSE_TRAINER_ADVERTISE_COOLDOWN: 'CommonBuffId' = 349073 + EVENT_NPC_IDLE: 'CommonBuffId' = 154886 + EVENT_NPC_VISITED_MAILBOX_COOLDOWN: 'CommonBuffId' = 154883 + EVENT_PLAYFUL: 'CommonBuffId' = 29683 + EVENT_STRESSED: 'CommonBuffId' = 29684 + EVENT_UNCOMFORTABLE: 'CommonBuffId' = 118871 + EVICTION_SYSTEM_JUST_EVICTED: 'CommonBuffId' = 355065 + EVICTION_SYSTEM_KICKED_OUT: 'CommonBuffId' = 346420 + EVICTION_SYSTEM_STAY_SUCCESS_CONFIDENT: 'CommonBuffId' = 346418 + EVICTION_SYSTEM_STAY_SUCCESS_HAPPY: 'CommonBuffId' = 346417 + EVICTION_SYSTEM_TENANT_ANGRY: 'CommonBuffId' = 355127 + EVICTION_SYSTEM_TENANT_ROLE: 'CommonBuffId' = 346412 + EXCURSION_MOUNTAIN_ACT_01_TIN_EMBARRASSED_LEADER: 'CommonBuffId' = 249367 + EXCURSION_MOUNTAIN_ACT_1_GOLD_HAPPY: 'CommonBuffId' = 241132 + EXCURSION_MOUNTAIN_ACT_1_SILVER_HAPPY: 'CommonBuffId' = 249411 + EXCURSION_MOUNTAIN_ACT_2_BRONZE_ANGRY: 'CommonBuffId' = 241126 + EXCURSION_MOUNTAIN_ACT_2_BRONZE_TENSE: 'CommonBuffId' = 241120 + EXCURSION_MOUNTAIN_ACT_2_GOLD_HAPPY: 'CommonBuffId' = 241130 + EXCURSION_MOUNTAIN_ACT_2_SILVER_HAPPY: 'CommonBuffId' = 249431 + EXCURSION_MOUNTAIN_ACT_2_TIN_SAD: 'CommonBuffId' = 249423 + EXCURSION_MOUNTAIN_ACT_3_AGAINST_ALL_ODDS: 'CommonBuffId' = 249539 + EXCURSION_MOUNTAIN_ACT_3_BRONZE: 'CommonBuffId' = 242018 + EXCURSION_MOUNTAIN_ACT_3_BRONZE_EMBARRASSED: 'CommonBuffId' = 241121 + EXCURSION_MOUNTAIN_ACT_3_DEFYING_GRAVITY: 'CommonBuffId' = 249540 + EXCURSION_MOUNTAIN_ACT_3_FEET_SHORT: 'CommonBuffId' = 249536 + EXCURSION_MOUNTAIN_ACT_3_GOLD_CONFIDENT: 'CommonBuffId' = 241125 + EXCURSION_MOUNTAIN_ACT_3_GOLD_INSPIRED: 'CommonBuffId' = 241119 + EXCURSION_MOUNTAIN_ACT_3_SILVER_CONFIDENT: 'CommonBuffId' = 241122 + EXCURSION_MOUNTAIN_ACT_3_SILVER_INSPIRED: 'CommonBuffId' = 241124 + EXCURSION_MOUNTAIN_ACT_3_TOP_OF_WORLD: 'CommonBuffId' = 249538 + EXCURSION_MOUNTAIN_BONKED_HEAD: 'CommonBuffId' = 249366 + EXCURSION_MOUNTAIN_CAVE_DRINK: 'CommonBuffId' = 253527 + EXCURSION_MOUNTAIN_CAVE_SLEEP: 'CommonBuffId' = 253528 + EXCURSION_MOUNTAIN_CAVE_WOOHOO: 'CommonBuffId' = 253625 + EXCURSION_MOUNTAIN_CLIMBING_MAP_NEAR: 'CommonBuffId' = 248013 + EXCURSION_MOUNTAIN_CLIMBING_PLAQUE_RANK_01: 'CommonBuffId' = 250091 + EXCURSION_MOUNTAIN_CLIMBING_PLAQUE_RANK_02: 'CommonBuffId' = 250094 + EXCURSION_MOUNTAIN_CLIMBING_PLAQUE_RANK_03: 'CommonBuffId' = 250095 + EXCURSION_MOUNTAIN_CLIMB_TAKE_PHOTO_COOLDOWN: 'CommonBuffId' = 250978 + EXCURSION_MOUNTAIN_CLIMB_TAKE_SELFIE_COOLDOWN: 'CommonBuffId' = 250891 + EXCURSION_MOUNTAIN_DIDNT_REACH_THE_PEAK: 'CommonBuffId' = 252879 + EXCURSION_MOUNTAIN_FIGHT_COOLDOWN: 'CommonBuffId' = 241768 + EXCURSION_MOUNTAIN_GROUP_MEMBER: 'CommonBuffId' = 241760 + EXCURSION_MOUNTAIN_HIDDEN_REACTION: 'CommonBuffId' = 241983 + EXCURSION_MOUNTAIN_INSPECT_CLIMB_COOLDOWN: 'CommonBuffId' = 241773 + EXCURSION_MOUNTAIN_MOTIVE_ADJUST: 'CommonBuffId' = 254801 + EXCURSION_MOUNTAIN_STUBBED_TOE: 'CommonBuffId' = 249365 + EXCURSION_MOUNTAIN_TIN_SAD: 'CommonBuffId' = 241227 + EXCURSION_MOUNTAIN_TIN_SAD_CLIMBER: 'CommonBuffId' = 249433 + EXPERIMENTAL_CURE_TESTED_ON_SELF: 'CommonBuffId' = 207406 + FACIAL_MASK_APPLIED_ANTI_AGING: 'CommonBuffId' = 271590 + FACIAL_MASK_APPLIED_ANTI_AGING_READY_TO_REMOVE: 'CommonBuffId' = 271591 + FACIAL_MASK_APPLIED_BASIC: 'CommonBuffId' = 271343 + FACIAL_MASK_APPLIED_BASIC_READY_TO_REMOVE: 'CommonBuffId' = 271348 + FACIAL_MASK_APPLIED_FAMILY_CTYAE: 'CommonBuffId' = 271528 + FACIAL_MASK_APPLIED_FAMILY_CTYAE_READY_TO_REMOVE: 'CommonBuffId' = 271531 + FACIAL_MASK_APPLIED_FAMILY_HATES_CHILDREN: 'CommonBuffId' = 271530 + FACIAL_MASK_APPLIED_FAMILY_HATES_CHILDREN_READY_TO_REMOVE: 'CommonBuffId' = 271534 + FACIAL_MASK_APPLIED_FAMILY_TODDLER: 'CommonBuffId' = 271529 + FACIAL_MASK_APPLIED_FAMILY_TODDLER_READY_TO_REMOVE: 'CommonBuffId' = 271533 + FACIAL_MASK_APPLIED_GOLD: 'CommonBuffId' = 271567 + FACIAL_MASK_APPLIED_GOLD_FREEGAN: 'CommonBuffId' = 271568 + FACIAL_MASK_APPLIED_GOLD_FREEGAN_READY_TO_REMOVE: 'CommonBuffId' = 271572 + FACIAL_MASK_APPLIED_GOLD_READY_TO_REMOVE: 'CommonBuffId' = 271573 + FACIAL_MASK_APPLIED_GOLD_SPECIAL: 'CommonBuffId' = 271569 + FACIAL_MASK_APPLIED_GOLD_SPECIAL_READY_TO_REMOVE: 'CommonBuffId' = 271574 + FACIAL_MASK_APPLIED_HYDRATING: 'CommonBuffId' = 271585 + FACIAL_MASK_APPLIED_HYDRATING_MERMAID: 'CommonBuffId' = 271604 + FACIAL_MASK_APPLIED_HYDRATING_MERMAID_READY_TO_REMOVE: 'CommonBuffId' = 271605 + FACIAL_MASK_APPLIED_HYDRATING_READY_TO_REMOVE: 'CommonBuffId' = 271586 + FACIAL_MASK_APPLIED_RANCID: 'CommonBuffId' = 272295 + FACIAL_MASK_APPLIED_RANCID_READY_TO_REMOVE: 'CommonBuffId' = 272300 + FACIAL_MASK_APPLIED_RANCID_VEGETARIAN: 'CommonBuffId' = 272296 + FACIAL_MASK_APPLIED_RANCID_VEGETARIAN_READY_TO_REMOVE: 'CommonBuffId' = 272302 + FACIAL_MASK_APPLIED_TOO_LONG_ANTIAGING: 'CommonBuffId' = 271583 + FACIAL_MASK_APPLIED_TOO_LONG_BASIC: 'CommonBuffId' = 271351 + FACIAL_MASK_APPLIED_TOO_LONG_FAMILY_TODDLER: 'CommonBuffId' = 271535 + FACIAL_MASK_APPLIED_TOO_LONG_GOLD: 'CommonBuffId' = 271580 + FACIAL_MASK_APPLIED_TOO_LONG_HYDRATING: 'CommonBuffId' = 271582 + FACIAL_MASK_APPLIED_TOO_LONG_RANCID: 'CommonBuffId' = 272298 + FACIAL_MASK_APPLIED_TOO_LONG_UV: 'CommonBuffId' = 271581 + FACIAL_MASK_APPLIED_UV: 'CommonBuffId' = 271593 + FACIAL_MASK_APPLIED_UV_READY_TO_REMOVE: 'CommonBuffId' = 271592 + FACIAL_MASK_BONUS_ANTI_AGING: 'CommonBuffId' = 271559 + FACIAL_MASK_BONUS_ANTI_AGING_BASIC: 'CommonBuffId' = 271560 + FACIAL_MASK_BONUS_BASIC: 'CommonBuffId' = 271462 + FACIAL_MASK_BONUS_FAMILY: 'CommonBuffId' = 271537 + FACIAL_MASK_BONUS_FAMILY_HATES_CHILDREN: 'CommonBuffId' = 271538 + FACIAL_MASK_BONUS_GOLD: 'CommonBuffId' = 271565 + FACIAL_MASK_BONUS_GOLD_FREEGAN: 'CommonBuffId' = 271566 + FACIAL_MASK_BONUS_GOLD_SPECIAL: 'CommonBuffId' = 271564 + FACIAL_MASK_BONUS_HYDRATING: 'CommonBuffId' = 271561 + FACIAL_MASK_BONUS_HYDRATING_MERMAID: 'CommonBuffId' = 271606 + FACIAL_MASK_BONUS_UV: 'CommonBuffId' = 271563 + FACIAL_MASK_BONUS_UV_VAMPIRE: 'CommonBuffId' = 271562 + FACIAL_MASK_COLD_BONUS: 'CommonBuffId' = 271634 + FACIAL_MASK_IRRITATED_SKIN: 'CommonBuffId' = 272291 + FACIAL_MASK_MASTER_ANTI_AGING: 'CommonBuffId' = 271551 + FACIAL_MASK_MASTER_FAMILY_CTYAE: 'CommonBuffId' = 271539 + FACIAL_MASK_MASTER_FAMILY_TODDLER: 'CommonBuffId' = 271541 + FACIAL_MASK_MASTER_GOLD: 'CommonBuffId' = 271557 + FACIAL_MASK_MASTER_HYDRATING: 'CommonBuffId' = 271558 + FACIAL_MASK_MASTER_RANCID: 'CommonBuffId' = 272293 + FACIAL_MASK_MASTER_RELAXING: 'CommonBuffId' = 271366 + FACIAL_MASK_MASTER_UV: 'CommonBuffId' = 271556 + FALL_CHALLENGE_DO_TD_CELEBRANT_ROLE: 'CommonBuffId' = 155506 + FALL_CHALLENGE_DO_TD_CELEBRANT_ROLE_ALWAYS: 'CommonBuffId' = 155504 + FALL_CHALLENGE_DO_TD_CELEBRATE_BUFF: 'CommonBuffId' = 153306 + FALL_CHALLENGE_DO_TD_CELEBRATE_CHILD: 'CommonBuffId' = 154600 + FALL_CHALLENGE_DO_TD_CELEBRATE_COSTUME_VFX_REMOVE_CHILD: 'CommonBuffId' = 154629 + FALL_CHALLENGE_DO_TD_CELEBRATE_COSTUME_VFX_REMOVE_CHILD_F: 'CommonBuffId' = 155143 + FALL_CHALLENGE_DO_TD_CELEBRATE_COSTUME_VFX_REMOVE_F_PREF: 'CommonBuffId' = 154628 + FALL_CHALLENGE_DO_TD_CELEBRATE_F_CHILD: 'CommonBuffId' = 155142 + FALL_CHALLENGE_DO_TD_CELEBRATE_F_PREF: 'CommonBuffId' = 153404 + FALL_CHALLENGE_DO_TD_CELEBRATE_M_PREF_VFX_REMOVE: 'CommonBuffId' = 154722 + FALL_CHALLENGE_DO_TD_HAS_BEEN_ASKED_FOR_SKULL: 'CommonBuffId' = 153215 + FALL_CHALLENGE_DO_TD_URN_STONE_COOLDOWN: 'CommonBuffId' = 154654 + FAME_FAME_OPPORTUNITY_ACTIVIST_BASE: 'CommonBuffId' = 192882 + FAME_FAME_OPPORTUNITY_ACTIVIST_POLITICIAN: 'CommonBuffId' = 192917 + FAME_FAME_OPPORTUNITY_ENTERTAINER_MUSIC: 'CommonBuffId' = 192961 + FAME_FAME_OPPORTUNITY_GARDENER_BASE: 'CommonBuffId' = 195695 + FAME_FAME_OPPORTUNITY_GARDENER_FLORIST: 'CommonBuffId' = 192962 + FAME_FAME_OPPORTUNITY_PAINTER_BASE: 'CommonBuffId' = 192963 + FAME_FAME_OPPORTUNITY_QUIT: 'CommonBuffId' = 202220 + FAME_FAME_OPPORTUNITY_SECRET_AGENT_VILLAIN: 'CommonBuffId' = 192965 + FAME_FAME_OPPORTUNITY_SOCIAL_MEDIA_BASE: 'CommonBuffId' = 192966 + FAME_FAME_OPPORTUNITY_STYLE_INFLUENCER_STYLIST: 'CommonBuffId' = 194321 + FAME_FAME_OPPORTUNITY_TECH_GURU_BASE: 'CommonBuffId' = 192967 + FAME_FAME_OPPORTUNITY_WRITER_BASE: 'CommonBuffId' = 192968 + FAME_LEVEL_1: 'CommonBuffId' = 191809 + FAME_LEVEL_2: 'CommonBuffId' = 191813 + FAME_LEVEL_3: 'CommonBuffId' = 191814 + FAME_LEVEL_4: 'CommonBuffId' = 191811 + FAME_LEVEL_5: 'CommonBuffId' = 191812 + FAME_LOCK_STAT: 'CommonBuffId' = 192950 + FAME_PERK_BAD_REPUTATION_PLAY_THE_VILLAIN: 'CommonBuffId' = 193788 + FAME_PERK_BRAND_ALL_NIGHTER: 'CommonBuffId' = 195943 + FAME_PERK_BRAND_ALL_NIGHTER_ACTIVE: 'CommonBuffId' = 195945 + FAME_PERK_BRAND_ALL_NIGHTER_CHARITY_STREAM: 'CommonBuffId' = 196061 + FAME_PERK_BRAND_ALL_NIGHTER_ENERGY_DRAIN: 'CommonBuffId' = 195949 + FAME_PERK_BRAND_CORPORATE_PARTNERSHIP: 'CommonBuffId' = 197602 + FAME_PERK_BRAND_LIFESTYLE_BRAND: 'CommonBuffId' = 197601 + FAME_PERK_BRAND_TRAILBLAZER: 'CommonBuffId' = 197600 + FAME_PERK_CAREER_HOPPER_PERK_BUFF: 'CommonBuffId' = 196005 + FAME_PERK_CELEBRITY_CLEANSE_FOCUSED: 'CommonBuffId' = 197596 + FAME_PERK_CELEBU_SERUM_DRANK_CONFIDENT: 'CommonBuffId' = 194891 + FAME_PERK_CELEBU_SERUM_DRANK_ENERGY: 'CommonBuffId' = 194892 + FAME_PERK_CELEBU_SERUM_DRANK_FLIRTY: 'CommonBuffId' = 194893 + FAME_PERK_CELEBU_SERUM_DRANK_FOCUS: 'CommonBuffId' = 194894 + FAME_PERK_CELEBU_SERUM_DRANK_FUN: 'CommonBuffId' = 194889 + FAME_PERK_CELEBU_SERUM_DRANK_HAPPY: 'CommonBuffId' = 194895 + FAME_PERK_CELEBU_SERUM_DRANK_HYGIENE: 'CommonBuffId' = 194890 + FAME_PERK_CELEBU_SERUM_DRANK_INSPIRED: 'CommonBuffId' = 194896 + FAME_PERK_CELEBU_SERUM_DRANK_SLEEP: 'CommonBuffId' = 194920 + FAME_PERK_CELEBU_SERUM_MAILBOX_TIMER: 'CommonBuffId' = 194603 + FAME_PERK_CELEBU_SERUM_WITHDRAWAL_TIMER: 'CommonBuffId' = 194990 + FAME_PERK_CORPORATE_PARTNERSHIP_DIALOG_COOLDOWN: 'CommonBuffId' = 194046 + FAME_PERK_CORPORATE_PARTNERSHIP_ROYALTY_BONUS: 'CommonBuffId' = 193596 + FAME_PERK_CORPORATE_PARTNERSHIP_ROYALTY_BONUS_TREND1: 'CommonBuffId' = 194059 + FAME_PERK_CORPORATE_PARTNERSHIP_ROYALTY_BONUS_TREND2: 'CommonBuffId' = 194063 + FAME_PERK_CORPORATE_PARTNERSHIP_ROYALTY_BONUS_TREND3: 'CommonBuffId' = 194062 + FAME_PERK_CORPORATE_PARTNERSHIP_ROYALTY_BONUS_TREND4: 'CommonBuffId' = 194061 + FAME_PERK_CORPORATE_PARTNERSHIP_ROYALTY_BONUS_TREND5: 'CommonBuffId' = 194060 + FAME_PERK_EASY_STREET_CAREER: 'CommonBuffId' = 196719 + FAME_PERK_EASY_STREET_LEAVE_WORK_CONFIDENT: 'CommonBuffId' = 196740 + FAME_PERK_EASY_STREET_LEAVE_WORK_ENERGIZED: 'CommonBuffId' = 196741 + FAME_PERK_EASY_STREET_LEAVE_WORK_FLIRTY: 'CommonBuffId' = 196742 + FAME_PERK_EASY_STREET_LEAVE_WORK_FOCUSED: 'CommonBuffId' = 196743 + FAME_PERK_EASY_STREET_LEAVE_WORK_HAPPY: 'CommonBuffId' = 196744 + FAME_PERK_EASY_STREET_LEAVE_WORK_INSPIRED: 'CommonBuffId' = 196745 + FAME_PERK_EASY_STREET_LEAVE_WORK_PLAYFUL: 'CommonBuffId' = 196746 + FAME_PERK_FAN_FAVORITE_CONFIDENT: 'CommonBuffId' = 196264 + FAME_PERK_FAN_FAVORITE_DAZED: 'CommonBuffId' = 196263 + FAME_PERK_FAN_FAVORITE_FAN_COOLDOWN: 'CommonBuffId' = 201204 + FAME_PERK_FAN_FAVORITE_HAS_PERK: 'CommonBuffId' = 196153 + FAME_PERK_FEUD_BRINGER_COMMENT_BACKLASH: 'CommonBuffId' = 193883 + FAME_PERK_FEUD_BRINGER_DISCUSSED_FEUD: 'CommonBuffId' = 193882 + FAME_PERK_FEUD_BRINGER_ENCOURAGING_CHIRPS: 'CommonBuffId' = 193885 + FAME_PERK_FEUD_BRINGER_HIDDEN_END_FEUD: 'CommonBuffId' = 193874 + FAME_PERK_FEUD_BRINGER_HIDDEN_FEUD_CHECK: 'CommonBuffId' = 193851 + FAME_PERK_FEUD_BRINGER_HIDDEN_PERK_BUFF: 'CommonBuffId' = 193978 + FAME_PERK_FEUD_BRINGER_INFURIATING_COMMENTS: 'CommonBuffId' = 193884 + FAME_PERK_FEUD_BRINGER_LOSING_FEUD: 'CommonBuffId' = 193886 + FAME_PERK_FEUD_BRINGER_LOST_FEUD: 'CommonBuffId' = 200325 + FAME_PERK_FEUD_BRINGER_WINNING_FEUD: 'CommonBuffId' = 193887 + FAME_PERK_GOOD_REPUTATION_GIVING_BACK: 'CommonBuffId' = 193789 + FAME_PERK_GOOD_REPUTATION_STAR_TREATMENT: 'CommonBuffId' = 193791 + FAME_PERK_GOOD_REPUTATION_STAR_TREATMENT_BROADCASTER_DELAY: 'CommonBuffId' = 196894 + FAME_PERK_GOOD_REPUTATION_STAR_TREATMENT_HIDDEN_REACT_COOLDOWN: 'CommonBuffId' = 202214 + FAME_PERK_HAS_PERK_RALLY: 'CommonBuffId' = 196071 + FAME_PERK_INFLUENCER: 'CommonBuffId' = 196259 + FAME_PERK_INFLUENCER_GIFT_RECIPIENT: 'CommonBuffId' = 194097 + FAME_PERK_INFLUENCER_LETTER_BUFFS_CONFIDENT: 'CommonBuffId' = 194852 + FAME_PERK_INFLUENCER_LETTER_BUFFS_ENERGIZED: 'CommonBuffId' = 194851 + FAME_PERK_INFLUENCER_LETTER_BUFFS_HAPPY: 'CommonBuffId' = 194848 + FAME_PERK_INFLUENCER_LETTER_BUFFS_INSPIRED: 'CommonBuffId' = 194849 + FAME_PERK_INFLUENCER_LETTER_BUFFS_PLAYFUL: 'CommonBuffId' = 194850 + FAME_PERK_INFLUENCER_NOT_GIFT_RECIPIENT: 'CommonBuffId' = 194098 + FAME_PERK_INSTANT_BESTIES: 'CommonBuffId' = 195135 + FAME_PERK_RALLY_AUDIENCE_EFFECTS: 'CommonBuffId' = 196223 + FAME_PERK_RALLY_AUTONOMOUS_WATCH: 'CommonBuffId' = 196030 + FAME_PERK_RALLY_COOLDOWN: 'CommonBuffId' = 198882 + FAME_PERK_RALLY_RALLYER_EFFECTS: 'CommonBuffId' = 196326 + FAME_PERK_RALLY_RALLYING: 'CommonBuffId' = 196064 + FAME_PERK_RELATIONSHIP_GAME_NETWORKING: 'CommonBuffId' = 193581 + FAME_PERK_RELATIONSHIP_GAME_PR_PERSON: 'CommonBuffId' = 195109 + FAME_PERK_RELATIONSHIP_GAME_PR_PERSON_COOLDOWN: 'CommonBuffId' = 195315 + FAME_PERK_RELATIONSHIP_GAME_PR_PERSON_DAZED: 'CommonBuffId' = 195319 + FAME_PERK_RELATIONSHIP_GAME_PR_PERSON_PLAYFUL: 'CommonBuffId' = 195482 + FAME_PERK_SKILL_CAREER_CELEBU_SERUM: 'CommonBuffId' = 197597 + FAME_PERK_SKILL_CAREER_ESTABLISHED_NAME: 'CommonBuffId' = 197599 + FAME_PERK_SKILL_CAREER_NOTICEABLE: 'CommonBuffId' = 197598 + FAME_PERK_SQUAD_COOLDOWN: 'CommonBuffId' = 196267 + FAME_PERK_SQUAD_OWNER: 'CommonBuffId' = 194260 + FAME_PERK_SQUAD_PERK_BUFF: 'CommonBuffId' = 196113 + FAME_PERK_SQUAD_ROLE: 'CommonBuffId' = 194255 + FAME_PERK_WHOS_BAD_HAS_PERK_REPUTATION_DECREASE: 'CommonBuffId' = 196175 + FAME_PROGRESSION_RANK_DOWN_0: 'CommonBuffId' = 189452 + FAME_PROGRESSION_RANK_DOWN_1: 'CommonBuffId' = 189448 + FAME_PROGRESSION_RANK_DOWN_2: 'CommonBuffId' = 189449 + FAME_PROGRESSION_RANK_DOWN_3: 'CommonBuffId' = 189450 + FAME_PROGRESSION_RANK_DOWN_4: 'CommonBuffId' = 189451 + FAME_PROGRESSION_RANK_DOWN_AMBITIOUS_0: 'CommonBuffId' = 189458 + FAME_PROGRESSION_RANK_DOWN_AMBITIOUS_1: 'CommonBuffId' = 189459 + FAME_PROGRESSION_RANK_DOWN_AMBITIOUS_2: 'CommonBuffId' = 189460 + FAME_PROGRESSION_RANK_DOWN_AMBITIOUS_3: 'CommonBuffId' = 189461 + FAME_PROGRESSION_RANK_DOWN_AMBITIOUS_4: 'CommonBuffId' = 189462 + FAME_PROGRESSION_RANK_UP_1: 'CommonBuffId' = 189443 + FAME_PROGRESSION_RANK_UP_2: 'CommonBuffId' = 189444 + FAME_PROGRESSION_RANK_UP_3: 'CommonBuffId' = 189445 + FAME_PROGRESSION_RANK_UP_4: 'CommonBuffId' = 189446 + FAME_PROGRESSION_RANK_UP_5: 'CommonBuffId' = 189442 + FAME_PROGRESSION_RANK_UP_AMBITIOUS_1: 'CommonBuffId' = 189465 + FAME_PROGRESSION_RANK_UP_AMBITIOUS_2: 'CommonBuffId' = 189466 + FAME_PROGRESSION_RANK_UP_AMBITIOUS_3: 'CommonBuffId' = 189467 + FAME_PROGRESSION_RANK_UP_AMBITIOUS_4: 'CommonBuffId' = 189468 + FAME_PROGRESSION_RANK_UP_AMBITIOUS_5: 'CommonBuffId' = 189464 + FAME_QUIRK_A_SERIOUS_ACTOR: 'CommonBuffId' = 192853 + FAME_QUIRK_A_SERIOUS_ACTOR_ANGRY: 'CommonBuffId' = 195908 + FAME_QUIRK_A_SERIOUS_ACTOR_INSPIRED: 'CommonBuffId' = 195909 + FAME_QUIRK_BE_GONE_COOLDOWN: 'CommonBuffId' = 195873 + FAME_QUIRK_BRUSHES_WITH_FAME: 'CommonBuffId' = 192852 + FAME_QUIRK_BRUSHES_WITH_FAME_ENERGIZED: 'CommonBuffId' = 194083 + FAME_QUIRK_BRUSHES_WITH_FAME_SAD: 'CommonBuffId' = 194082 + FAME_QUIRK_EMOTION_BOMB: 'CommonBuffId' = 192854 + FAME_QUIRK_EMOTION_BOMB_EXTRA_ANGER: 'CommonBuffId' = 196436 + FAME_QUIRK_EMOTION_BOMB_EXTRA_SADNESS: 'CommonBuffId' = 196438 + FAME_QUIRK_FAN_MAIL: 'CommonBuffId' = 192851 + FAME_QUIRK_JUICE_ENTHUSIAST: 'CommonBuffId' = 192860 + FAME_QUIRK_JUICE_ENTHUSIAST_ANGRY_CHILD: 'CommonBuffId' = 196077 + FAME_QUIRK_JUICE_ENTHUSIAST_ANGRY_TYAE: 'CommonBuffId' = 196050 + FAME_QUIRK_JUICE_ENTHUSIAST_CHILD: 'CommonBuffId' = 196276 + FAME_QUIRK_JUICE_ENTHUSIAST_ENERGIZED_CHILD: 'CommonBuffId' = 196079 + FAME_QUIRK_JUICE_ENTHUSIAST_ENERGIZED_TYAE: 'CommonBuffId' = 196048 + FAME_QUIRK_JUICE_ENTHUSIAST_SAD_CHILD: 'CommonBuffId' = 196081 + FAME_QUIRK_JUICE_ENTHUSIAST_SAD_TYAE: 'CommonBuffId' = 196049 + FAME_QUIRK_NO_TOUCHING: 'CommonBuffId' = 192856 + FAME_QUIRK_NO_TOUCHING_CONFIDENT: 'CommonBuffId' = 194079 + FAME_QUIRK_NO_TOUCHING_STRESSED: 'CommonBuffId' = 194078 + FAME_QUIRK_PAPARAZZI_DARLING: 'CommonBuffId' = 192859 + FAME_QUIRK_PAPARAZZI_DARLING_SHUTTER_LOVE: 'CommonBuffId' = 196144 + FAME_QUIRK_PHONE_FANATIC: 'CommonBuffId' = 191666 + FAME_QUIRK_PHONE_FANATIC_STRESSED: 'CommonBuffId' = 191707 + FAME_QUIRK_PUBLIC_NUMBER: 'CommonBuffId' = 192858 + FAME_QUIRK_PUBLIC_NUMBER_ANGRY: 'CommonBuffId' = 195406 + FAME_QUIRK_PUBLIC_NUMBER_EMBARRASSED: 'CommonBuffId' = 195405 + FAME_QUIRK_PUBLIC_NUMBER_FLIRTY: 'CommonBuffId' = 195407 + FAME_QUIRK_PUBLIC_NUMBER_HAPPY: 'CommonBuffId' = 195403 + FAME_QUIRK_PUBLIC_NUMBER_HIDDEN_COOLDOWN: 'CommonBuffId' = 198690 + FAME_QUIRK_PUBLIC_NUMBER_INSPIRED: 'CommonBuffId' = 195409 + FAME_QUIRK_PUBLIC_NUMBER_SAD: 'CommonBuffId' = 195404 + FAME_QUIRK_PUBLIC_NUMBER_STRESSED: 'CommonBuffId' = 195408 + FAME_QUIRK_REFINED_PALATE: 'CommonBuffId' = 192857 + FAME_QUIRK_STAN: 'CommonBuffId' = 192850 + FAME_QUIRK_VAIN_STREET: 'CommonBuffId' = 192855 + FAME_QUIRK_VAIN_STREET_CONFIDENT: 'CommonBuffId' = 195992 + FAME_QUIRK_VAIN_STREET_STRESSED: 'CommonBuffId' = 195991 + FAME_SHINE_RANK4: 'CommonBuffId' = 199150 + FAME_SHINE_RANK5: 'CommonBuffId' = 199151 + FAME_SOCIAL_EVENT_GOLD: 'CommonBuffId' = 200706 + FAMILIAR_ACTIVE: 'CommonBuffId' = 222233 + FAMILIAR_PET_ACTIVE_ADULT_CAT_SMALL_DOG: 'CommonBuffId' = 222231 + FAMILIAR_PET_ACTIVE_ADULT_LARGE_DOG: 'CommonBuffId' = 222230 + FAMILIAR_PET_ACTIVE_CHILD: 'CommonBuffId' = 222232 + FAMILIAR_RESURRECT: 'CommonBuffId' = 215224 + FAMILIAR_RESURRECT_COOLDOWN: 'CommonBuffId' = 215225 + FAMILIAR_TNS_COOLDOWN: 'CommonBuffId' = 215227 + FAMILIES_ARGUMENTS_LOSER: 'CommonBuffId' = 159389 + FAMILIES_ARGUMENTS_NO_WINNER: 'CommonBuffId' = 160084 + FAMILIES_ARGUMENTS_TYPE_ARGUMENTS: 'CommonBuffId' = 160061 + FAMILIES_ARGUMENTS_TYPE_CAREER: 'CommonBuffId' = 160050 + FAMILIES_ARGUMENTS_TYPE_CHILDREN: 'CommonBuffId' = 160052 + FAMILIES_ARGUMENTS_TYPE_CLEANLINESS: 'CommonBuffId' = 160057 + FAMILIES_ARGUMENTS_TYPE_CURFEW: 'CommonBuffId' = 168136 + FAMILIES_ARGUMENTS_TYPE_EXERCISING: 'CommonBuffId' = 160067 + FAMILIES_ARGUMENTS_TYPE_FOOD: 'CommonBuffId' = 160070 + FAMILIES_ARGUMENTS_TYPE_HOUSE_RULES: 'CommonBuffId' = 160065 + FAMILIES_ARGUMENTS_TYPE_HUMOR: 'CommonBuffId' = 160054 + FAMILIES_ARGUMENTS_TYPE_JOB: 'CommonBuffId' = 160063 + FAMILIES_ARGUMENTS_TYPE_KINDNESS: 'CommonBuffId' = 160053 + FAMILIES_ARGUMENTS_TYPE_LIFE_GOALS: 'CommonBuffId' = 160068 + FAMILIES_ARGUMENTS_TYPE_LIFE_OUTLOOK: 'CommonBuffId' = 160069 + FAMILIES_ARGUMENTS_TYPE_MORALS: 'CommonBuffId' = 160071 + FAMILIES_ARGUMENTS_TYPE_MUSIC: 'CommonBuffId' = 160060 + FAMILIES_ARGUMENTS_TYPE_NATURE_WONDERS: 'CommonBuffId' = 160056 + FAMILIES_ARGUMENTS_TYPE_PARENTING: 'CommonBuffId' = 160064 + FAMILIES_ARGUMENTS_TYPE_POLITICS: 'CommonBuffId' = 159364 + FAMILIES_ARGUMENTS_TYPE_ROMANCE: 'CommonBuffId' = 160058 + FAMILIES_ARGUMENTS_TYPE_SCHOOL: 'CommonBuffId' = 160062 + FAMILIES_ARGUMENTS_TYPE_SHARING: 'CommonBuffId' = 160051 + FAMILIES_ARGUMENTS_TYPE_SOCIAL_ANXIETY: 'CommonBuffId' = 160055 + FAMILIES_ARGUMENTS_TYPE_WHOS_BETTER: 'CommonBuffId' = 160066 + FAMILIES_ARGUMENTS_WINNER: 'CommonBuffId' = 159388 + FAMILIES_JUST_SHOVED: 'CommonBuffId' = 159939 + FAMILY_BULLETIN_BOARD_HAS_NOTE_DRAWING: 'CommonBuffId' = 163112 + FAMILY_BULLETIN_BOARD_HAS_NOTE_NEGATIVE: 'CommonBuffId' = 163109 + FAMILY_BULLETIN_BOARD_HAS_NOTE_POSITIVE: 'CommonBuffId' = 163108 + FAMILY_BULLETIN_BOARD_LOOK_AT_DRAWING: 'CommonBuffId' = 162728 + FAMILY_BULLETIN_BOARD_READ_NOTE: 'CommonBuffId' = 162458 + FAMILY_BULLETIN_BOARD_READ_NOTE_ANGRY: 'CommonBuffId' = 162705 + FAMILY_DYNAMICS_ADOPTION: 'CommonBuffId' = 317586 + FAMILY_DYNAMICS_BIRTHDAY_GIFT_CALL: 'CommonBuffId' = 322807 + FAMILY_DYNAMICS_CALMING_DOWN: 'CommonBuffId' = 312729 + FAMILY_DYNAMICS_CHATTY_CALL_CONFIDENT: 'CommonBuffId' = 319532 + FAMILY_DYNAMICS_CHATTY_CALL_HAPPY: 'CommonBuffId' = 319531 + FAMILY_DYNAMICS_CHATTY_CALL_PLAYFUL: 'CommonBuffId' = 319534 + FAMILY_DYNAMICS_CONTAGIOUS_ANGER: 'CommonBuffId' = 312728 + FAMILY_DYNAMICS_CONTAGIOUS_EMBARRASSMENT: 'CommonBuffId' = 312733 + FAMILY_DYNAMICS_CONTAGIOUS_FEAR: 'CommonBuffId' = 312731 + FAMILY_DYNAMICS_CONTAGIOUS_SADNESS: 'CommonBuffId' = 312734 + FAMILY_DYNAMICS_CONTAGIOUS_STRESS: 'CommonBuffId' = 312732 + FAMILY_DYNAMICS_FAMILY_TROPE_ADVENTURE_COOLDOWN: 'CommonBuffId' = 306626 + FAMILY_DYNAMICS_HIDDEN_CLOSE: 'CommonBuffId' = 317770 + FAMILY_DYNAMICS_HIDDEN_COMPLIANT: 'CommonBuffId' = 318080 + FAMILY_DYNAMICS_HIDDEN_DIFFICULT: 'CommonBuffId' = 318083 + FAMILY_DYNAMICS_HIDDEN_DISTANT: 'CommonBuffId' = 318078 + FAMILY_DYNAMICS_HIDDEN_JOKESTERS: 'CommonBuffId' = 318085 + FAMILY_DYNAMICS_HIDDEN_LOVING: 'CommonBuffId' = 320330 + FAMILY_DYNAMICS_HIDDEN_PERMISSIVE: 'CommonBuffId' = 320331 + FAMILY_DYNAMICS_PRAISE_MESS_ACTOR: 'CommonBuffId' = 320811 + FAMILY_DYNAMICS_PRAISE_MESS_HIDDEN: 'CommonBuffId' = 320808 + FAMILY_DYNAMICS_PRAISE_MESS_TARGET: 'CommonBuffId' = 320812 + FAMILY_DYNAMICS_SOCIAL_CLOSE: 'CommonBuffId' = 318077 + FAMILY_DYNAMICS_SOCIAL_COMPLIANT_AUTHORITY: 'CommonBuffId' = 320335 + FAMILY_DYNAMICS_SOCIAL_COMPLIANT_SUBORDINATE: 'CommonBuffId' = 318082 + FAMILY_DYNAMICS_SOCIAL_DIFFICULT: 'CommonBuffId' = 318084 + FAMILY_DYNAMICS_SOCIAL_DISTANT: 'CommonBuffId' = 318079 + FAMILY_DYNAMICS_SOCIAL_JOKESTERS: 'CommonBuffId' = 320332 + FAMILY_DYNAMICS_SOCIAL_LOVING: 'CommonBuffId' = 320333 + FAMILY_DYNAMICS_SOCIAL_PERMISSIVE_AUTHORITY: 'CommonBuffId' = 320334 + FAMILY_DYNAMICS_SOCIAL_PERMISSIVE_SUBORDINATE: 'CommonBuffId' = 320625 + FAMILY_GOSSIP: 'CommonBuffId' = 164737 + FAMILY_PORTRAIT_APPRECIATE_FAMILY: 'CommonBuffId' = 181414 + FAMILY_REL_BIT_ACQUIRED_PROXIMITY_HIGH: 'CommonBuffId' = 162438 + FAMILY_REL_BIT_ACQUIRED_PROXIMITY_LOW: 'CommonBuffId' = 162440 + FAMILY_REL_BIT_ACQUIRED_PROXIMITY_NEUTRAL: 'CommonBuffId' = 162439 + FASHION_MARKETPLACE_DIDNT_READ_THE_ROOM: 'CommonBuffId' = 287585 + FASHION_MARKETPLACE_FASHION_EMPIRE_GROWING: 'CommonBuffId' = 287589 + FASHION_MARKETPLACE_FASHION_FIRESTARTER: 'CommonBuffId' = 287594 + FASHION_MARKETPLACE_STYLE_REJECTION: 'CommonBuffId' = 287593 + FASHION_MARKETPLACE_WEARING_OUTFIT: 'CommonBuffId' = 286292 + FEARFUL_PET_RUN_AWAY: 'CommonBuffId' = 178105 + FEAR_BEING_ALONE_EFFECTS_ALONE: 'CommonBuffId' = 366274 + FEAR_BEING_ALONE_EFFECTS_BURDENED_FEELINGS: 'CommonBuffId' = 364232 + FEAR_BEING_ALONE_EFFECTS_SEEKING_SOLACE: 'CommonBuffId' = 364577 + FEAR_BEING_ALONE_EFFECTS_SIM_PROXIMITY: 'CommonBuffId' = 366273 + FEAR_BEING_ALONE_EFFECTS_SOLITUDE: 'CommonBuffId' = 364578 + FEAR_BEING_ALONE_TRAIT_EFFECTS: 'CommonBuffId' = 364231 + FEAR_BEING_CHEATED_ON_CONFRONTATION_PROGRESS: 'CommonBuffId' = 278550 + FEAR_BEING_CHEATED_ON_EFFECTS_CATCH_CHEATING: 'CommonBuffId' = 278341 + FEAR_BEING_CHEATED_ON_EFFECTS_SUSPICIOUS_ANGRY: 'CommonBuffId' = 278330 + FEAR_BEING_CHEATED_ON_EFFECTS_SUSPICIOUS_SAD: 'CommonBuffId' = 278340 + FEAR_BEING_CHEATED_ON_EFFECTS_TALK_RELATIONSHIP_FEARS_FAIL_ACTOR: 'CommonBuffId' = 278538 + FEAR_BEING_CHEATED_ON_EFFECTS_TALK_RELATIONSHIP_FEARS_FAIL_TARGET: 'CommonBuffId' = 278537 + FEAR_BEING_CHEATED_ON_EFFECTS_TALK_RELATIONSHIP_FEARS_SUCCESS: 'CommonBuffId' = 278539 + FEAR_BEING_CHEATED_ON_TRAIT_EFFECTS: 'CommonBuffId' = 278338 + FEAR_BEING_JUDGED_FIGURE_OUT_DIFFERENCES_FAIL: 'CommonBuffId' = 288469 + FEAR_BEING_JUDGED_FIGURE_OUT_DIFFERENCES_SUCCESS: 'CommonBuffId' = 288466 + FEAR_BEING_JUDGED_JUDGING_EYES: 'CommonBuffId' = 288468 + FEAR_BEING_JUDGED_JUDGING_EYES_LEVEL2: 'CommonBuffId' = 288467 + FEAR_BEING_JUDGED_TRACKER: 'CommonBuffId' = 288479 + FEAR_BEING_JUDGED_TRAIT_EFFECTS: 'CommonBuffId' = 288474 + FEAR_CONFRONTATION_PROGRESS_GAINED: 'CommonBuffId' = 295484 + FEAR_CONFRONTED_RECENTLY: 'CommonBuffId' = 277638 + FEAR_CONFRONT_FEAR_SUCCESS_CONFIDENCE_GAIN: 'CommonBuffId' = 308140 + FEAR_COW_PLANT_EFFECTS_COW_PLANT_PROXIMITY: 'CommonBuffId' = 277209 + FEAR_COW_PLANT_TRAIT_EFFECTS: 'CommonBuffId' = 277208 + FEAR_CROWDED_PLACES_EFFECTS_LEVEL_1: 'CommonBuffId' = 287761 + FEAR_CROWDED_PLACES_EFFECTS_LEVEL_2: 'CommonBuffId' = 287760 + FEAR_DARK_EFFECTS_SCARED_OUTSIDE: 'CommonBuffId' = 278014 + FEAR_DARK_EFFECTS_STARTLED_WAKE_UP: 'CommonBuffId' = 278154 + FEAR_DARK_TRAIT_EFFECTS: 'CommonBuffId' = 278005 + FEAR_DEAD_END_JOB_EFFECTS_PASSION_RETURN_FLAG: 'CommonBuffId' = 289790 + FEAR_DEAD_END_JOB_EFFECTS_PASSION_RETURN_TRACKER: 'CommonBuffId' = 277848 + FEAR_DEAD_END_JOB_EFFECTS_REGAIN_PASSION_FAIL: 'CommonBuffId' = 277853 + FEAR_DEAD_END_JOB_EFFECTS_REGAIN_PASSION_FOCUSED: 'CommonBuffId' = 277854 + FEAR_DEAD_END_JOB_EFFECTS_REGAIN_PASSION_INSPIRED: 'CommonBuffId' = 277855 + FEAR_DEAD_END_JOB_EFFECTS_SAD_RETURN: 'CommonBuffId' = 277847 + FEAR_DEAD_END_JOB_TRIGGER_PROGRESS: 'CommonBuffId' = 277972 + FEAR_DEATH_DISCUSS_FEARS_SUCCESS: 'CommonBuffId' = 296120 + FEAR_DEATH_EFFECTS_NEAR_REAPER: 'CommonBuffId' = 283721 + FEAR_DEATH_TRAIT_EFFECTS: 'CommonBuffId' = 283708 + FEAR_DISAPPOINTING_PARENTS_CONFRONTATION_PROGRESS: 'CommonBuffId' = 283667 + FEAR_DISAPPOINTING_PARENTS_EFFECTS_NEAR_PARENTS: 'CommonBuffId' = 284098 + FEAR_DISAPPOINTING_PARENTS_EFFECTS_WAKE_UP_TENSE: 'CommonBuffId' = 284099 + FEAR_DISAPPOINTING_PARENTS_SET_EXPECTATIONS_FAILURE: 'CommonBuffId' = 284102 + FEAR_DISAPPOINTING_PARENTS_SET_EXPECTATIONS_SUCCESS: 'CommonBuffId' = 284103 + FEAR_DISAPPOINTING_PARENTS_TRAIT_EFFECTS: 'CommonBuffId' = 283709 + FEAR_EVICTION_CONFRONTATION_PROGRESS: 'CommonBuffId' = 355835 + FEAR_EVICTION_EFFECTS_PHONE_PANIC_IDLE: 'CommonBuffId' = 342758 + FEAR_FAILING_AFTER_SCHOOL_CONFRONTATION_TRACKER: 'CommonBuffId' = 288077 + FEAR_FAILING_AFTER_SCHOOL_EFFECTS_LOST_EVENT: 'CommonBuffId' = 288120 + FEAR_FAILING_AFTER_SCHOOL_EFFECTS_WAKE_UP: 'CommonBuffId' = 288125 + FEAR_FAILING_AFTER_SCHOOL_TRIGGER_PROGRESS: 'CommonBuffId' = 288079 + FEAR_FAILING_CLASS_EFFECTS_GRADE_DROP: 'CommonBuffId' = 288114 + FEAR_FAILING_CLASS_EFFECTS_SCHOOL_ARRIVAL: 'CommonBuffId' = 287938 + FEAR_FAILING_CLASS_EXTRA_CREDIT_AVAILABLE: 'CommonBuffId' = 288094 + FEAR_FAILING_CLASS_TRIGGER_PROGRESS: 'CommonBuffId' = 288078 + FEAR_FAILING_TESTS_EFFECTS_MUST_BE_PREPARED: 'CommonBuffId' = 287710 + FEAR_FAILING_TESTS_EFFECTS_PREPARED_FAIL: 'CommonBuffId' = 290929 + FEAR_FAILING_TESTS_EFFECTS_TEST_DAY: 'CommonBuffId' = 287713 + FEAR_FAILING_TEST_CONFRONTATION_PROGRESS: 'CommonBuffId' = 287860 + FEAR_FAILURE_EFFECTS_PERFORMANCE_REVIEW_FAIL: 'CommonBuffId' = 283826 + FEAR_FAILURE_EFFECTS_PERFORMANCE_REVIEW_SUCCESS: 'CommonBuffId' = 283825 + FEAR_FAILURE_EFFECTS_SAD_CRAFTING: 'CommonBuffId' = 283796 + FEAR_FAILURE_EFFECTS_SAD_WAKE_UP: 'CommonBuffId' = 283797 + FEAR_FAILURE_EFFECTS_SHOW_OFF_COOLDOWN: 'CommonBuffId' = 283895 + FEAR_FAILURE_EFFECTS_SHOW_OFF_FAIL: 'CommonBuffId' = 283844 + FEAR_FAILURE_EFFECTS_SHOW_OFF_WAITING: 'CommonBuffId' = 283896 + FEAR_FAILURE_TRIGGER_PROGRESS: 'CommonBuffId' = 283789 + FEAR_FIRE_TRAIT_EFFECTS: 'CommonBuffId' = 277317 + FEAR_GAINED_ANXIETY: 'CommonBuffId' = 284204 + FEAR_GAINED_SCARED: 'CommonBuffId' = 284203 + FEAR_GHOSTS_EFFECTS_GHOST_PROXIMITY: 'CommonBuffId' = 277559 + FEAR_GHOSTS_EFFECTS_SCARED: 'CommonBuffId' = 277620 + FEAR_GHOSTS_TRAIT_EFFECTS_NEAR_GHOST_TRACKER: 'CommonBuffId' = 277558 + FEAR_HOMEWORK_CONFRONTATION_PROGRESS: 'CommonBuffId' = 286298 + FEAR_HOMEWORK_EFFECTS_NOTHING_ABSORBED: 'CommonBuffId' = 286711 + FEAR_HOMEWORK_EFFECTS_SHOULD_FINISH_HOMEWORK: 'CommonBuffId' = 286653 + FEAR_HORSES_GET_ADVICE_SUCCESS: 'CommonBuffId' = 323772 + FEAR_HORSES_TRAIT_EFFECTS: 'CommonBuffId' = 323759 + FEAR_HORSES_TRAIT_FEAR_REACT_TO_HORSES: 'CommonBuffId' = 339408 + FEAR_IMMUNITY_RESOLVED_RECENTLY: 'CommonBuffId' = 277115 + FEAR_INFERIOR_EFFECTS_BRILLIANCE_PROXIMITY: 'CommonBuffId' = 307978 + FEAR_INFERIOR_EFFECTS_SAD_WAKE_UP: 'CommonBuffId' = 307979 + FEAR_INTIMACY_EFFECTS_EMBRACING_VULNERABILITY: 'CommonBuffId' = 362863 + FEAR_INTIMACY_EFFECTS_EMOTIONAL_WALLS: 'CommonBuffId' = 362861 + FEAR_INTIMACY_EFFECTS_GROUNDED_BELIEFS: 'CommonBuffId' = 374375 + FEAR_INTIMACY_EFFECTS_TOUCH_SENSITIVITY: 'CommonBuffId' = 362862 + FEAR_INTIMACY_TRAIT_EFFECTS: 'CommonBuffId' = 362853 + FEAR_OF_EVICTION_DOOR_PANIC: 'CommonBuffId' = 351565 + FEAR_OF_EVICTION_EFFECTS: 'CommonBuffId' = 352133 + FEAR_SWIMMING_EFFECTS_SCARED_IN_WATER: 'CommonBuffId' = 277695 + FEAR_SWIMMING_TRAIT_EFFECTS: 'CommonBuffId' = 277688 + FEAR_TESTS_EFFECTS_PREPARED_SUCCESS: 'CommonBuffId' = 294552 + FESTIVAL_APPROPRIATENESS_NO_SINGING: 'CommonBuffId' = 154237 + FESTIVAL_AUTONOMY_BUY_T_SHIRT: 'CommonBuffId' = 143635 + FESTIVAL_AUTONOMY_WATCH: 'CommonBuffId' = 136206 + FESTIVAL_BLOSSOM_5_STAGES_OF_PETALS_1_HIDDEN: 'CommonBuffId' = 153016 + FESTIVAL_BLOSSOM_5_STAGES_OF_PETALS_2_HAPPY: 'CommonBuffId' = 153022 + FESTIVAL_BLOSSOM_5_STAGES_OF_PETALS_3_DENIAL: 'CommonBuffId' = 153019 + FESTIVAL_BLOSSOM_5_STAGES_OF_PETALS_4_ANGER: 'CommonBuffId' = 153020 + FESTIVAL_BLOSSOM_5_STAGES_OF_PETALS_5_BARGAIN: 'CommonBuffId' = 153021 + FESTIVAL_BLOSSOM_5_STAGES_OF_PETALS_6_DEPRESSION: 'CommonBuffId' = 153018 + FESTIVAL_BLOSSOM_5_STAGES_OF_PETALS_7_ACCEPTANCE: 'CommonBuffId' = 153017 + FESTIVAL_BLOSSOM_ALLOW_THROW_PETALS: 'CommonBuffId' = 143102 + FESTIVAL_BLOSSOM_AUTONOMY_ARTIST: 'CommonBuffId' = 136203 + FESTIVAL_BLOSSOM_AUTONOMY_DRINK_SAKURA_TEA: 'CommonBuffId' = 150875 + FESTIVAL_BLOSSOM_AUTONOMY_ROMANCE_INTERACTIONS: 'CommonBuffId' = 146792 + FESTIVAL_BLOSSOM_AUTONOMY_THROW_PETALS: 'CommonBuffId' = 135703 + FESTIVAL_BLOSSOM_AUTONOMY_VIEWERS: 'CommonBuffId' = 143729 + FESTIVAL_BLOSSOM_HAS_BEEN_SLEAZED: 'CommonBuffId' = 155131 + FESTIVAL_BLOSSOM_INSPIRATION: 'CommonBuffId' = 135699 + FESTIVAL_BLOSSOM_PLAYER_BUFF: 'CommonBuffId' = 143101 + FESTIVAL_BLOSSOM_PLAYER_TEST_ADD: 'CommonBuffId' = 144001 + FESTIVAL_BLOSSOM_PLAYER_TIMER: 'CommonBuffId' = 144002 + FESTIVAL_BLOSSOM_SAKURA_TEA_CHILD_BUFF: 'CommonBuffId' = 153901 + FESTIVAL_BLOSSOM_SAKURA_TEA_GURU_ONLY: 'CommonBuffId' = 150918 + FESTIVAL_BLOSSOM_SLEAZE_ANGRY: 'CommonBuffId' = 136256 + FESTIVAL_BLOSSOM_SLEAZE_FLIRTY: 'CommonBuffId' = 136216 + FESTIVAL_BLOSSOM_TEA_GLOW_SAKURA: 'CommonBuffId' = 147112 + FESTIVAL_BLOSSOM_TEA_GLOW_SAKURA_CHILD: 'CommonBuffId' = 147113 + FESTIVAL_BLOSSOM_THROW_PETALS_COOLDOWN: 'CommonBuffId' = 135704 + FESTIVAL_CONTESTS_HACKATHON_WINNER_BRONZE: 'CommonBuffId' = 144195 + FESTIVAL_CONTESTS_HACKATHON_WINNER_GOLD: 'CommonBuffId' = 144189 + FESTIVAL_CONTESTS_HACKATHON_WINNER_SILVER: 'CommonBuffId' = 144194 + FESTIVAL_CONTESTS_UGT_WINNER: 'CommonBuffId' = 144192 + FESTIVAL_DARK_TEA_DRINK: 'CommonBuffId' = 135532 + FESTIVAL_FLEA_MARKET_AUTONOMY_HAGGLER: 'CommonBuffId' = 142223 + FESTIVAL_FLEA_MARKET_HAGGLE_SUCCEED: 'CommonBuffId' = 142219 + FESTIVAL_FLEA_MARKET_PLAYER_BUFF: 'CommonBuffId' = 140386 + FESTIVAL_FLEA_MARKET_PLAYER_TEST_ADD: 'CommonBuffId' = 143999 + FESTIVAL_FLEA_MARKET_PLAYER_TIMER: 'CommonBuffId' = 144000 + FESTIVAL_FLEA_MARKET_TRADE_CD: 'CommonBuffId' = 144401 + FESTIVAL_FLEA_MARKET_TRADE_FAIL_CD: 'CommonBuffId' = 152786 + FESTIVAL_FLEA_MARKET_VENDOR: 'CommonBuffId' = 139949 + FESTIVAL_FOOD_AUTONOMY_BUBBLE_BLOWER: 'CommonBuffId' = 140094 + FESTIVAL_FOOD_AUTONOMY_CURRY_CONTEST_PARTICIPANT: 'CommonBuffId' = 146550 + FESTIVAL_FOOD_AUTONOMY_OVEREAT: 'CommonBuffId' = 136418 + FESTIVAL_FOOD_AUTONOMY_SAMPLE: 'CommonBuffId' = 141204 + FESTIVAL_FOOD_AUTONOMY_VOMIT: 'CommonBuffId' = 136590 + FESTIVAL_FOOD_CURRY_CONTEST_BURNT_TONGUE: 'CommonBuffId' = 146420 + FESTIVAL_FOOD_CURRY_CONTEST_COOLDOWN: 'CommonBuffId' = 146145 + FESTIVAL_FOOD_CURRY_CONTEST_FAILED: 'CommonBuffId' = 153580 + FESTIVAL_FOOD_CURRY_CONTEST_T_SHIRT: 'CommonBuffId' = 152354 + FESTIVAL_FOOD_CURRY_CONTEST_WON_CONTEST: 'CommonBuffId' = 153563 + FESTIVAL_FOOD_EAT_FASTER: 'CommonBuffId' = 142708 + FESTIVAL_FOOD_PLAYER_BUFF: 'CommonBuffId' = 139945 + FESTIVAL_FOOD_PLAYER_TEST_ADD: 'CommonBuffId' = 143997 + FESTIVAL_FOOD_PLAYER_TIMER: 'CommonBuffId' = 143998 + FESTIVAL_FOOD_SAMPLE_COOLDOWN: 'CommonBuffId' = 137152 + FESTIVAL_GENERAL_DRINK: 'CommonBuffId' = 134832 + FESTIVAL_GENERAL_EAT: 'CommonBuffId' = 134831 + FESTIVAL_LAMP_AUTONOMY_DARK_CONTESTANT: 'CommonBuffId' = 146920 + FESTIVAL_LAMP_AUTONOMY_LIGHT_CONTESTANT: 'CommonBuffId' = 146921 + FESTIVAL_LAMP_AUTONOMY_LIGHT_FIREWORKS: 'CommonBuffId' = 140096 + FESTIVAL_LAMP_CREATE_FIREWORKS_CD: 'CommonBuffId' = 152792 + FESTIVAL_LAMP_CREATE_VOODOO_CD: 'CommonBuffId' = 153427 + FESTIVAL_LAMP_DARK_TEA: 'CommonBuffId' = 134573 + FESTIVAL_LAMP_DAZED_BUFF: 'CommonBuffId' = 135540 + FESTIVAL_LAMP_LIGHT_TEA: 'CommonBuffId' = 134572 + FESTIVAL_LAMP_PLAYER_BUFF: 'CommonBuffId' = 140384 + FESTIVAL_LAMP_PLAYER_TEST_ADD: 'CommonBuffId' = 143996 + FESTIVAL_LAMP_PLAYER_TIMER: 'CommonBuffId' = 143995 + FESTIVAL_LAMP_TEA_GLOW_DARK: 'CommonBuffId' = 147116 + FESTIVAL_LAMP_TEA_GLOW_DARK_CHILD: 'CommonBuffId' = 147119 + FESTIVAL_LAMP_TEA_GLOW_LIGHT: 'CommonBuffId' = 147118 + FESTIVAL_LAMP_TEA_GLOW_LIGHT_CHILD: 'CommonBuffId' = 147117 + FESTIVAL_LIGHT_TEA_DRINK: 'CommonBuffId' = 135533 + FESTIVAL_LOGIC_AUTONOMY_HACK_THE_PLANET: 'CommonBuffId' = 141127 + FESTIVAL_LOGIC_AUTONOMY_ROCKET_SHIP_BUILDER: 'CommonBuffId' = 137242 + FESTIVAL_LOGIC_AUTONOMY_ROCKET_SHIP_USER: 'CommonBuffId' = 140945 + FESTIVAL_LOGIC_AUTONOMY_ROCKET_SHIP_WOOHOO: 'CommonBuffId' = 137328 + FESTIVAL_LOGIC_AUTONOMY_UGT: 'CommonBuffId' = 141199 + FESTIVAL_LOGIC_COSPLAY_SELFIE_FAIL: 'CommonBuffId' = 144353 + FESTIVAL_LOGIC_COSPLAY_SELFIE_SUCCESS: 'CommonBuffId' = 144352 + FESTIVAL_LOGIC_COSPLAY_SELFIE_TARGET_CD: 'CommonBuffId' = 144367 + FESTIVAL_LOGIC_EVENT_HACK_THE_PLANET: 'CommonBuffId' = 141168 + FESTIVAL_LOGIC_EVENT_UGT: 'CommonBuffId' = 141169 + FESTIVAL_LOGIC_HACK_THE_PLANET_CD: 'CommonBuffId' = 141092 + FESTIVAL_LOGIC_PLAYER_BUFF: 'CommonBuffId' = 140385 + FESTIVAL_LOGIC_PLAYER_TEST_ADD: 'CommonBuffId' = 143787 + FESTIVAL_LOGIC_PLAYER_TIMER: 'CommonBuffId' = 143796 + FESTIVAL_LOGIC_ROCKET_SHIP_USE_CD: 'CommonBuffId' = 153373 + FESTIVAL_LOGIC_ROCKET_SHIP_WOOHOO_CD: 'CommonBuffId' = 140980 + FESTIVAL_PLAYER_IGNORE_VENUES: 'CommonBuffId' = 154328 + FESTIVAL_TRAVEL_NP_CS_BEHAVIOR: 'CommonBuffId' = 149279 + FESTIVAL_TRAVEL_NP_CS_TEST_ADD: 'CommonBuffId' = 149280 + FESTIVAL_TRAVEL_NP_CS_TIMER: 'CommonBuffId' = 149278 + FIGHT_WITNESSED_BORED: 'CommonBuffId' = 99270 + FIGHT_WITNESSED_ENERGIZED: 'CommonBuffId' = 99267 + FIGHT_WITNESSED_HAPPY: 'CommonBuffId' = 99263 + FIGHT_WITNESSED_INSPIRING: 'CommonBuffId' = 99268 + FIGHT_WITNESSED_SAD: 'CommonBuffId' = 99266 + FIGHT_WITNESSED_STRESSED: 'CommonBuffId' = 99265 + FIGHT_WITNESSED_UNCOMFORTABLE: 'CommonBuffId' = 99269 + FILTHY_FABULOUS_TOILET_BUFFS_DIDNT_WASH_HANDS: 'CommonBuffId' = 257336 + FILTHY_FABULOUS_TOILET_BUFFS_USED_TOILET: 'CommonBuffId' = 257335 + FILTHY_FABULOUS_TOILET_BUFFS_WASHED_HANDS: 'CommonBuffId' = 257337 + FINISHED_BOOK: 'CommonBuffId' = 36577 + FIREWORKS_LIGHTING_HIDDEN: 'CommonBuffId' = 135817 + FIREWORKS_SINGED: 'CommonBuffId' = 134991 + FIREWORKS_WATCHING_HIDDEN: 'CommonBuffId' = 135816 + FIRE_CALLED_FIRE_FIGHTERS: 'CommonBuffId' = 237762 + FIRE_EXCITED_ADRENALINE_SEEKER: 'CommonBuffId' = 254553 + FIRE_EXTINGUISHED: 'CommonBuffId' = 98326 + FIRE_EXTINGUISHED_SIM: 'CommonBuffId' = 98328 + FIRE_EXTINGUISHER: 'CommonBuffId' = 97139 + FIRE_FINISHED_STRESSED: 'CommonBuffId' = 77651 + FIRE_FLIRTY_FIRE_FIGHTERS: 'CommonBuffId' = 237794 + FIRE_GRIM_REAPER_REACTED: 'CommonBuffId' = 100087 + FIRE_ON_FIRE: 'CommonBuffId' = 98786 + FIRE_ON_FIRE_PET_CAT: 'CommonBuffId' = 172014 + FIRE_ON_FIRE_PET_DOG: 'CommonBuffId' = 172015 + FIRE_RECENTLY_EXTINGUISHED: 'CommonBuffId' = 101043 + FIRE_RECENT_FIRE: 'CommonBuffId' = 100849 + FIRE_SIM_SINGED: 'CommonBuffId' = 98815 + FIRE_SIM_SINGED_PET_CAT: 'CommonBuffId' = 172020 + FIRE_SIM_SINGED_PET_DOG: 'CommonBuffId' = 172021 + FIRE_STRESSED: 'CommonBuffId' = 77649 + FIRE_STRESSED_PET_CAT: 'CommonBuffId' = 171899 + FIRE_STRESSED_PET_DOG: 'CommonBuffId' = 171900 + FIRE_TODDLER: 'CommonBuffId' = 157024 + FIRE_WEARING_FIRE_FIGHTER_OUTFIT: 'CommonBuffId' = 237760 + FIRST_KISS: 'CommonBuffId' = 29350 + FITNESS_SKILL_HIGH_STAMINA: 'CommonBuffId' = 212215 + FITNESS_SKILL_MEDIUM_STAMINA: 'CommonBuffId' = 212214 + FITNESS_SKILL_SWIM_STYLE_CHILD_MEDIUM: 'CommonBuffId' = 211073 + FITNESS_SKILL_SWIM_STYLE_TYAE_HIGH: 'CommonBuffId' = 211076 + FITNESS_SKILL_SWIM_STYLE_TYAE_MEDIUM: 'CommonBuffId' = 211075 + FLAVOR_INSPIRATION: 'CommonBuffId' = 130728 + FLIRTATIOUS_SCENT: 'CommonBuffId' = 118494 + FLIRTY_BY_POTION: 'CommonBuffId' = 26303 + FLIRTY_DEDICATED_SONG: 'CommonBuffId' = 30892 + FLOAT_AVAILABLE_HIDDEN: 'CommonBuffId' = 119067 + FOCUSED_BY_POTION: 'CommonBuffId' = 26329 + FOCUSED_ENLIGHTENMENT: 'CommonBuffId' = 118513 + FOCUSED_FEELING_FLEXY: 'CommonBuffId' = 118660 + FOCUSING_SCENT: 'CommonBuffId' = 118504 + FOOD_AMBROSIA_HAPPY_HIGH: 'CommonBuffId' = 102098 + FOOD_AMBROSIA_HAPPY_PET_CAT: 'CommonBuffId' = 175236 + FOOD_AMBROSIA_HAPPY_PET_DOG: 'CommonBuffId' = 175237 + FOOD_CHOPSTICKS_FAIL: 'CommonBuffId' = 148694 + FOOD_CHOPSTICKS_SUCCEED: 'CommonBuffId' = 148693 + FOOD_COOKING_0: 'CommonBuffId' = 10591 + FOOD_COOKING_0_FOODIE: 'CommonBuffId' = 27388 + FOOD_COOKING_1: 'CommonBuffId' = 10592 + FOOD_COOKING_1_FOODIE: 'CommonBuffId' = 27387 + FOOD_COOKING_2: 'CommonBuffId' = 10593 + FOOD_COOKING_2_FOODIE: 'CommonBuffId' = 27386 + FOOD_COOKING_2_GRILL_MASTER: 'CommonBuffId' = 105023 + FOOD_COOKING_3: 'CommonBuffId' = 10597 + FOOD_COOKING_3_GRILL_MASTER: 'CommonBuffId' = 105024 + FOOD_COOKING_4: 'CommonBuffId' = 10601 + FOOD_COOKING_4_FOODIE: 'CommonBuffId' = 27383 + FOOD_COOKING_4_GRILL_MASTER: 'CommonBuffId' = 105025 + FOOD_COOKING_5: 'CommonBuffId' = 10602 + FOOD_COOKING_5_BATUU: 'CommonBuffId' = 237774 + FOOD_COOKING_5_FOODIE: 'CommonBuffId' = 27384 + FOOD_COOKING_5_GRILL_MASTER: 'CommonBuffId' = 105026 + FOOD_COOKING_INGREDIENTS_BAD: 'CommonBuffId' = 76399 + FOOD_COOKING_INGREDIENTS_BAD_FOODIE: 'CommonBuffId' = 76415 + FOOD_COOKING_INGREDIENTS_GOOD: 'CommonBuffId' = 76392 + FOOD_COOKING_INGREDIENTS_GOOD_FOODIE: 'CommonBuffId' = 76416 + FOOD_COOKING_INGREDIENTS_GOOD_GRILL_MASTER: 'CommonBuffId' = 105027 + FOOD_COOKING_TODDLER_ANGRY: 'CommonBuffId' = 144669 + FOOD_COOKING_TODDLER_BAD: 'CommonBuffId' = 144667 + FOOD_COOKING_TODDLER_ENERGIZED: 'CommonBuffId' = 144668 + FOOD_COOKING_TODDLER_GOOD: 'CommonBuffId' = 144666 + FOOD_ECO_BUG_FOOD_SQUEAMISH: 'CommonBuffId' = 235697 + FOOD_EMOTION_ANGRY_HIGH: 'CommonBuffId' = 40894 + FOOD_EMOTION_ANGRY_LOW: 'CommonBuffId' = 40893 + FOOD_EMOTION_ENERGIZED_HIGH: 'CommonBuffId' = 40890 + FOOD_EMOTION_ENERGIZED_LOW: 'CommonBuffId' = 40886 + FOOD_EMOTION_FLIRTY_HIGH: 'CommonBuffId' = 40883 + FOOD_EMOTION_FLIRTY_LOW: 'CommonBuffId' = 40882 + FOOD_EMOTION_HAPPY: 'CommonBuffId' = 118436 + FOOD_EMOTION_PLAYFUL_HIGH: 'CommonBuffId' = 40885 + FOOD_EMOTION_PLAYFUL_LOW: 'CommonBuffId' = 40884 + FOOD_EXPERIMENTAL_0: 'CommonBuffId' = 130527 + FOOD_EXPERIMENTAL_2: 'CommonBuffId' = 130526 + FOOD_EXPERIMENTAL_3: 'CommonBuffId' = 130717 + FOOD_EXPERIMENTAL_4: 'CommonBuffId' = 130718 + FOOD_EXPERIMENTAL_5: 'CommonBuffId' = 130525 + FOOD_EXPERIMENTAL_FOODIE_0: 'CommonBuffId' = 131493 + FOOD_EXPERIMENTAL_FOODIE_2: 'CommonBuffId' = 131495 + FOOD_EXPERIMENTAL_FOODIE_3: 'CommonBuffId' = 131496 + FOOD_EXPERIMENTAL_FOODIE_4: 'CommonBuffId' = 131497 + FOOD_EXPERIMENTAL_FOODIE_5: 'CommonBuffId' = 131498 + FOOD_FAME_QUIRKS_REFINED_PALATE_HAPPY: 'CommonBuffId' = 193505 + FOOD_FAME_QUIRKS_REFINED_PALATE_HEAVY_UNCOMFORTABLE: 'CommonBuffId' = 193507 + FOOD_FAME_QUIRKS_REFINED_PALATE_UNCOMFORTABLE: 'CommonBuffId' = 193506 + FOOD_FOOD_FAILS_NINJA_FINGERS: 'CommonBuffId' = 149399 + FOOD_FOOD_FAILS_SPICY_SATISFACTION: 'CommonBuffId' = 149400 + FOOD_FRANKS_AND_BEANS_HIDDEN: 'CommonBuffId' = 102555 + FOOD_FRESH_CATCH: 'CommonBuffId' = 212555 + FOOD_HAS_EATEN_RECENTLY: 'CommonBuffId' = 132413 + FOOD_HAS_EATEN_RECENTLY_GROSS_MANNERS: 'CommonBuffId' = 164370 + FOOD_HAS_EATEN_RECENTLY_INCLUDING_CANCEL: 'CommonBuffId' = 137573 + FOOD_HAS_EATEN_TODAY_HIDDEN: 'CommonBuffId' = 155562 + FOOD_HAS_EATEN_WITHIN_HOUR: 'CommonBuffId' = 212237 + FOOD_HIDDEN_EATING_EXPERIMENTAL_FOOD: 'CommonBuffId' = 131557 + FOOD_LIFESTYLES_HEALTH_NUT_1: 'CommonBuffId' = 248272 + FOOD_LIFESTYLES_HEALTH_NUT_2: 'CommonBuffId' = 248271 + FOOD_LIFESTYLES_HEALTH_NUT_3: 'CommonBuffId' = 248270 + FOOD_LIFESTYLES_HEALTH_NUT_4: 'CommonBuffId' = 248304 + FOOD_LIFESTYLES_HEALTH_NUT_5: 'CommonBuffId' = 248303 + FOOD_LIFESTYLES_HEALTH_NUT_HEALTHY_MEAL: 'CommonBuffId' = 248356 + FOOD_LIFESTYLES_HEALTH_NUT_SAD: 'CommonBuffId' = 248344 + FOOD_LIFESTYLES_HEALTH_NUT_SUGAR_FOOD: 'CommonBuffId' = 248357 + FOOD_LIFESTYLES_JUNK_FOOD_1: 'CommonBuffId' = 248265 + FOOD_LIFESTYLES_JUNK_FOOD_2: 'CommonBuffId' = 248266 + FOOD_LIFESTYLES_JUNK_FOOD_3: 'CommonBuffId' = 248267 + FOOD_LIFESTYLES_JUNK_FOOD_4: 'CommonBuffId' = 248268 + FOOD_LIFESTYLES_JUNK_FOOD_5: 'CommonBuffId' = 248269 + FOOD_LIFESTYLES_JUNK_FOOD_BORED: 'CommonBuffId' = 248343 + FOOD_LIFESTYLES_JUNK_FOOD_HEALTHY_MEAL: 'CommonBuffId' = 248355 + FOOD_LIFESTYLES_JUNK_FOOD_SUGAR_FOOD: 'CommonBuffId' = 248354 + FOOD_LIFESTYLES_JUNK_FOOD_SUGAR_RUSH: 'CommonBuffId' = 250604 + FOOD_LIFESTYLES_JUNK_FOOD_SUGAR_RUSH_CRASH: 'CommonBuffId' = 250605 + FOOD_LUNA_FISH: 'CommonBuffId' = 289743 + FOOD_POISONING_ACTIVE: 'CommonBuffId' = 131881 + FOOD_POISONING_INFECTED: 'CommonBuffId' = 131877 + FOOD_POISONING_RECENTLY_PUKED: 'CommonBuffId' = 135000 + FOOD_POISONING_RECOVERY: 'CommonBuffId' = 131908 + FOOD_POISONING_REPORTED: 'CommonBuffId' = 131916 + FOOD_SHARING_EAT_TOGETHER_REJECTION_ALLOW_SAD_EAT: 'CommonBuffId' = 370635 + FOOD_SPICY_FAIL: 'CommonBuffId' = 148691 + FOOD_SPICY_SUCCEED: 'CommonBuffId' = 148692 + FOOD_SUPPRESS_EAT_IDLE_MIXER: 'CommonBuffId' = 152795 + FOOD_SUPPRESS_STANDARD_EAT_MIXER: 'CommonBuffId' = 142689 + FOOD_SURVIVED_PUFFER_FISH: 'CommonBuffId' = 153808 + FOOD_TODDLER_MESSY_QUIT: 'CommonBuffId' = 143923 + FOOD_UNBALANCED_MEALS: 'CommonBuffId' = 217241 + FOOD_VAMPIRE_GARLIC_NOODLES: 'CommonBuffId' = 156006 + FOOD_VILLAGER_HELP_MUSHROOM_MASH: 'CommonBuffId' = 267517 + FOOD_WALLEYE_SURPRISE_INSPIRED: 'CommonBuffId' = 102553 + FORGOTTEN_BIRTHDAY: 'CommonBuffId' = 12442 + FOUNTAIN_A_COIN_FOR_GOOD_LUCK: 'CommonBuffId' = 131818 + FOUNTAIN_ENTRANCED_BY_SUDS: 'CommonBuffId' = 132019 + FOUNTAIN_HIDDEN_ADDED_SOAP: 'CommonBuffId' = 132572 + FOUNTAIN_OF_LOCAL_KNOWLEDGE_PRESSURE_COOKER_TRACKER: 'CommonBuffId' = 351249 + FOUNTAIN_OF_LOCAL_KNOWLEDGE_REGIONAL_FOOD_TRACKER: 'CommonBuffId' = 359589 + FOUNTAIN_OF_LOCAL_KNOWLEDGE_TRAIT_HIDDEN: 'CommonBuffId' = 348277 + FOX_ANIMAL_CLOTHING_GRANDMA_1: 'CommonBuffId' = 268769 + FOX_ANIMAL_CLOTHING_GRANDMA_2: 'CommonBuffId' = 270056 + FOX_ANIMAL_CLOTHING_GRANDMA_3: 'CommonBuffId' = 270057 + FOX_ANIMAL_CLOTHING_GRANDMA_4: 'CommonBuffId' = 270058 + FOX_ANIMAL_CLOTHING_GRANDMA_5: 'CommonBuffId' = 270055 + FOX_ANIMAL_CLOTHING_GRANDMA_6: 'CommonBuffId' = 270054 + FOX_ANIMAL_CLOTHING_ROBBER_1: 'CommonBuffId' = 268770 + FOX_ANIMAL_CLOTHING_ROBBER_2: 'CommonBuffId' = 270062 + FOX_ANIMAL_CLOTHING_ROBBER_3: 'CommonBuffId' = 270063 + FOX_ANIMAL_CLOTHING_ROBBER_4: 'CommonBuffId' = 270064 + FOX_ANIMAL_CLOTHING_ROBBER_5: 'CommonBuffId' = 270065 + FOX_ANIMAL_CLOTHING_ROBBER_6: 'CommonBuffId' = 270061 + FOX_ANIMAL_CLOTHING_ROBBER_7: 'CommonBuffId' = 270060 + FOX_ANIMAL_CLOTHING_ROBIN_HOOD_1: 'CommonBuffId' = 268771 + FOX_ANIMAL_CLOTHING_ROBIN_HOOD_2: 'CommonBuffId' = 270070 + FOX_ANIMAL_CLOTHING_ROBIN_HOOD_3: 'CommonBuffId' = 270071 + FOX_ANIMAL_CLOTHING_ROBIN_HOOD_4: 'CommonBuffId' = 270072 + FOX_ANIMAL_CLOTHING_ROBIN_HOOD_5: 'CommonBuffId' = 270069 + FOX_ANIMAL_CLOTHING_ROBIN_HOOD_6: 'CommonBuffId' = 270068 + FOX_CHEATS: 'CommonBuffId' = 270789 + FOX_DANGEROUS_WILDS: 'CommonBuffId' = 268621 + FOX_DISCORDANT_ARIA: 'CommonBuffId' = 269564 + FOX_HIDDEN_CANCEL_STALK: 'CommonBuffId' = 265099 + FOX_HIDDEN_CANT_PLEAD: 'CommonBuffId' = 270272 + FOX_HIDDEN_EVIL_CHICKEN_SCARE: 'CommonBuffId' = 268567 + FOX_HIDDEN_LEAVE: 'CommonBuffId' = 271068 + FOX_HIDDEN_RELATIONSHIP_WITH_POUNCE_TARGET: 'CommonBuffId' = 268933 + FOX_HIDDEN_ROOSTER_SCARES_FOX: 'CommonBuffId' = 269365 + FOX_HIDDEN_STALK: 'CommonBuffId' = 263653 + FOX_HIDDEN_STOLE_EGG: 'CommonBuffId' = 269635 + FOX_HIDDEN_WAKE_UP: 'CommonBuffId' = 270484 + FOX_IS_SLEEPING: 'CommonBuffId' = 260308 + FOX_SITUATION_LEAVE: 'CommonBuffId' = 270639 + FOX_SITUATION_ON_LOT: 'CommonBuffId' = 268741 + FOX_SITUATION_OPEN_STREET: 'CommonBuffId' = 267984 + FOX_SITUATION_STEAL: 'CommonBuffId' = 261652 + FOX_SITUATION_STEAL_EGG_FOCUS: 'CommonBuffId' = 266380 + FOX_SITUATION_STEAL_STALK_FOCUS: 'CommonBuffId' = 266381 + FOX_WATCH_TARGET: 'CommonBuffId' = 260022 + FREE_DIVING_WETSUIT: 'CommonBuffId' = 206587 + FREE_FROM_TOXINS: 'CommonBuffId' = 118511 + FREE_LANCER_CAREER_FASHION_PHOTOGRAPHER_COMPLETED_STYLE_INFLUENCER_MEETING: 'CommonBuffId' = 220467 + FREE_LANCER_CAREER_FASHION_PHOTOGRAPHER_COVER_PHOTO: 'CommonBuffId' = 218676 + FREE_LANCER_CAREER_FASHION_PHOTOGRAPHER_FASHION_SIMSTAGRAM: 'CommonBuffId' = 218681 + FREE_LANCER_CAREER_FASHION_PHOTOGRAPHER_FASHION_STUDIO_NEAR_BACKDROP: 'CommonBuffId' = 221113 + FREE_LANCER_CAREER_FASHION_PHOTOGRAPHER_FASHION_STUDIO_NEAR_LIGHT: 'CommonBuffId' = 221140 + FREE_LANCER_CAREER_FASHION_PHOTOGRAPHER_FREELANCE_PHOTOS: 'CommonBuffId' = 218679 + FREE_LANCER_CAREER_FASHION_PHOTOGRAPHER_INFLUENCED_FASHION_PHOTOS: 'CommonBuffId' = 218680 + FREE_LANCER_CAREER_FASHION_PHOTOGRAPHER_INFLUENCED_PHOTOS: 'CommonBuffId' = 218687 + FREE_LANCER_CAREER_FASHION_PHOTOGRAPHER_INFLUENCER_STYLE: 'CommonBuffId' = 218685 + FREE_LANCER_CAREER_FASHION_PHOTOGRAPHER_PHOTO_EDITOR: 'CommonBuffId' = 218683 + FREE_LANCER_CAREER_FASHION_PHOTOGRAPHER_SAD_FASHION_SIMSTAGRAM: 'CommonBuffId' = 218682 + FREE_LANCER_CAREER_FASHION_PHOTOGRAPHER_STEADY_EYE: 'CommonBuffId' = 220228 + FRESH_CLEAN_SCENT: 'CommonBuffId' = 118497 + FRIDGE_BAD_FRIDGE: 'CommonBuffId' = 10245 + FRIDGE_GOOD_FRIDGE: 'CommonBuffId' = 10244 + FRIENDSHIP_BRACELET_APPLIED_1: 'CommonBuffId' = 320048 + FRIENDSHIP_BRACELET_APPLIED_2: 'CommonBuffId' = 320049 + FRIENDSHIP_BRACELET_APPLIED_3: 'CommonBuffId' = 320050 + FRIENDSHIP_BRACELET_APPLIED_4: 'CommonBuffId' = 320047 + FRIENDSHIP_BRACELET_APPLIED_5: 'CommonBuffId' = 319947 + FRIENDSHIP_BRACELET_AWKWARD: 'CommonBuffId' = 320181 + FRIENDSHIP_BRACELET_BRACELETLESS: 'CommonBuffId' = 320182 + FRIENDSHIP_BRACELET_NEEDS_CLEANUP: 'CommonBuffId' = 329149 + FTUE_AUTONOMY_MOD_DAY1_NO_SLEEP: 'CommonBuffId' = 201480 + FTUE_AUTONOMY_MOD_DAY1_SLEEP_MOTIVES: 'CommonBuffId' = 201256 + FTUE_AUTONOMY_MOD_DAY1_START_SUPPRESS_AUTONOMY_PLAYER_SIM: 'CommonBuffId' = 201242 + FTUE_AUTONOMY_MOD_DAY1_START_SUPPRESS_AUTONOMY_ROOMMATE_SIM: 'CommonBuffId' = 201459 + FTUE_AUTONOMY_MOD_DAY2_FREEZE_BLADDER_DECAY: 'CommonBuffId' = 204699 + FTUE_GIVE_GIFT: 'CommonBuffId' = 198669 + FTUE_ROLE_PLAYER_SIM: 'CommonBuffId' = 201457 + FTUE_ROLE_ROOMMATE_COOK: 'CommonBuffId' = 198046 + FTUE_ROOMMATE_GAVE_GIFT: 'CommonBuffId' = 201554 + FTUE_ROOMMATE_GIFT: 'CommonBuffId' = 199659 + FTUE_ROOMMATE_SLEEP: 'CommonBuffId' = 201000 + FTUE_ROOMMATE_WAVE: 'CommonBuffId' = 199414 + FTUE_WAVE_COOLDOWN: 'CommonBuffId' = 200005 + FUNNIEST_JOKE_PLAYFUL: 'CommonBuffId' = 98772 + FUNNY_CONVERSATION: 'CommonBuffId' = 12443 + FUSE_BOX_FLICKER_REACTION: 'CommonBuffId' = 354212 + FUSE_BOX_FLICKER_REACTION_IP: 'CommonBuffId' = 354225 + FUTURE_CUBE_BRIGHT: 'CommonBuffId' = 10298 + FUTURE_CUBE_BRIGHT_LOVE_LIFE: 'CommonBuffId' = 39895 + FUTURE_CUBE_FUTURE_LOOKS_BRIGHT: 'CommonBuffId' = 237787 + FUTURE_CUBE_GRIM: 'CommonBuffId' = 10299 + FUTURE_CUBE_GRIM_LOVE_LIFE: 'CommonBuffId' = 39896 + FUTURE_CUBE_INSPIRED: 'CommonBuffId' = 39912 + FUTURE_CUBE_READY_TO_STUDY: 'CommonBuffId' = 39902 + FUTURE_CUBE_UNSMART: 'CommonBuffId' = 39906 + FUTURE_CUBE_UN_CREATIVE: 'CommonBuffId' = 39913 + GAME_CHALLENGED_DONT_WAKE_LLAMA: 'CommonBuffId' = 127880 + GARDENER_LOVE_TO_GARDEN: 'CommonBuffId' = 131914 + GARLIC_BRAID_GARLIC_SICKNESS_LEVEL1: 'CommonBuffId' = 151175 + GARLIC_BRAID_GARLIC_SICKNESS_LEVEL2: 'CommonBuffId' = 151178 + GARLIC_BRAID_GARLIC_SICKNESS_LEVEL3: 'CommonBuffId' = 151177 + GARLIC_BRAID_IN_ONE_GARLIC: 'CommonBuffId' = 151190 + GARLIC_BRAID_IN_THREE_GARLIC: 'CommonBuffId' = 151201 + GARLIC_BRAID_IN_TWO_GARLIC: 'CommonBuffId' = 151200 + GENERIC_CANCEL_INTERACTION: 'CommonBuffId' = 226416 + GENERIC_EXIT_INTERACTION: 'CommonBuffId' = 226414 + GENERIC_INJURY_BUFFS_LEVEL_1: 'CommonBuffId' = 247128 + GENERIC_INJURY_BUFFS_LEVEL_1_CHILD: 'CommonBuffId' = 247200 + GENERIC_INJURY_BUFFS_LEVEL_2: 'CommonBuffId' = 247129 + GENERIC_INJURY_BUFFS_LEVEL_2_CHILD: 'CommonBuffId' = 247201 + GENERIC_REACTION_BEEN_SHOCKED: 'CommonBuffId' = 128925 + GETTING_MARRIED: 'CommonBuffId' = 99711 + GHOST_ANGRY: 'CommonBuffId' = 102467 + GHOST_DROWN_FEAR_WATER: 'CommonBuffId' = 103681 + GHOST_EMBARRASSMENT: 'CommonBuffId' = 102527 + GHOST_PLAYFUL: 'CommonBuffId' = 102504 + GHOST_SCARED_HORSE_NEIGH_FROM_BEYOND: 'CommonBuffId' = 324642 + GHOST_SIM_ANGRY: 'CommonBuffId' = 102488 + GHOST_SIM_PLAYFUL: 'CommonBuffId' = 102509 + GIANT_CROPS_PLANT_CRY_COOLDOWN: 'CommonBuffId' = 261508 + GIVE_GIFT_BRO_ACTOR: 'CommonBuffId' = 183064 + GIVE_GIFT_BRO_TARGET: 'CommonBuffId' = 183065 + GIVE_GIFT_HAPPY_GIVING_SPIRIT: 'CommonBuffId' = 181236 + GIVE_GIFT_HAPPY_LOVELY_SURPRISE: 'CommonBuffId' = 181237 + GIVE_GIFT_HIDDEN: 'CommonBuffId' = 190705 + GIVE_GIFT_PLAYFUL_GOTCHA_GAG_GIFT: 'CommonBuffId' = 181234 + GIVE_GIFT_ROMANTIC_ACTOR: 'CommonBuffId' = 183297 + GIVE_GIFT_ROMANTIC_TARGET: 'CommonBuffId' = 183298 + GIVE_GIFT_SAD_USELESS_GIFT: 'CommonBuffId' = 181239 + GLIMMERSTONE_COOLDOWN: 'CommonBuffId' = 219828 + GLOBAL_TEMPERATURE_BURNING: 'CommonBuffId' = 185971 + GLOBAL_TEMPERATURE_COLD: 'CommonBuffId' = 186056 + GLOBAL_TEMPERATURE_FREEZING: 'CommonBuffId' = 185970 + GLOBAL_TEMPERATURE_HOT: 'CommonBuffId' = 185978 + GLOBAL_TEMPERATURE_VEHICLE_EXIT_DELAY: 'CommonBuffId' = 222948 + GOING_OUT_SOCIALS_BREAK_UP_REJECTED_ANGRY: 'CommonBuffId' = 128795 + GOING_OUT_SOCIALS_BREAK_UP_SIMS_COOLDOWN: 'CommonBuffId' = 129863 + GOING_OUT_SOCIALS_BREAK_UP_SIMS_MEAN_OR_EVIL: 'CommonBuffId' = 275612 + GOING_OUT_SOCIALS_EXCHANGE_NUMBERS_CONFIDENT: 'CommonBuffId' = 125734 + GOING_OUT_SOCIALS_MATCHMAKE_COOLDOWN: 'CommonBuffId' = 125443 + GOING_OUT_SOCIALS_MATCH_MAKE_FEELING_THE_LOVE: 'CommonBuffId' = 274402 + GOING_OUT_SOCIALS_MATCH_MAKE_HOOK_UP_DISASTER: 'CommonBuffId' = 274403 + GOING_OUT_SOCIALS_MATCH_MAKE_HOOK_UP_MISHAP: 'CommonBuffId' = 274396 + GOING_OUT_SOCIALS_MATCH_MAKE_LOVE_DOCTOR: 'CommonBuffId' = 274401 + GOING_OUT_SOCIALS_MATCH_MAKE_TWO_SEPARATE_SOULS: 'CommonBuffId' = 274398 + GOING_OUT_SOCIALS_TALK_UP_SIM_COOLDOWN: 'CommonBuffId' = 129865 + GOING_OUT_SOCIALS_TALK_UP_SIM_FRIENDLY_CATASTROPHE: 'CommonBuffId' = 275567 + GOING_OUT_SOCIALS_TALK_UP_SIM_MADE_A_FRIEND: 'CommonBuffId' = 275569 + GOING_OUT_SOCIALS_TALK_UP_SIM_NOT_VERY_INTERESTING: 'CommonBuffId' = 275568 + GOING_OUT_SOCIALS_TALK_UP_SIM_REACTION: 'CommonBuffId' = 129402 + GOING_OUT_SOCIALS_TALK_UP_SIM_REACTION_HIDDEN: 'CommonBuffId' = 129391 + GOING_OUT_SOCIALS_TRASH_SIM_COOLDOWN: 'CommonBuffId' = 129864 + GOING_OUT_SOCIALS_TRASH_SIM_FALTERED_PLAN: 'CommonBuffId' = 275627 + GOING_OUT_SOCIALS_TRASH_SIM_MALICIOUS_INTENTIONS: 'CommonBuffId' = 275628 + GOING_OUT_SOCIALS_TRASH_SIM_REACTION: 'CommonBuffId' = 129419 + GOING_OUT_SOCIALS_TRASH_SIM_REACTION_HIDDEN: 'CommonBuffId' = 129392 + GOING_OUT_SOCIALS_TRASH_SIM_SIDE_SHAVE_BEENC_HOSEN: 'CommonBuffId' = 275626 + GOOD_MANNERS_FORBIDDEN_WORD_EMBARRASSMENT: 'CommonBuffId' = 164055 + GOOD_MANNERS_GROSS_MANNER_EMBARRASSMENT: 'CommonBuffId' = 160893 + GOOD_VICTORY: 'CommonBuffId' = 108025 + GOOD_VICTORY_GREAT_STORY: 'CommonBuffId' = 109732 + GOOD_VS_EVIL_ANGRY: 'CommonBuffId' = 26787 + GOOD_VS_EVIL_SAD: 'CommonBuffId' = 77298 + GOT_FIT: 'CommonBuffId' = 12447 + GO_FOR_WALK_DOG_IDLE_BEHAVIOR: 'CommonBuffId' = 165199 + GO_FOR_WALK_DOG_WALK_BEHAVIOR: 'CommonBuffId' = 166305 + GO_FOR_WALK_SIM_IDLE_BEHAVIOR: 'CommonBuffId' = 166239 + GO_FOR_WALK_SIM_WALK_BEHAVIOR: 'CommonBuffId' = 166114 + GO_ON_ADVENTURE_LIGHTHOUSE_CASE_CLOSED: 'CommonBuffId' = 175674 + GO_ON_ADVENTURE_LIGHTHOUSE_GHOST_DOG_HAPPY: 'CommonBuffId' = 175675 + GO_ON_ADVENTURE_LIGHTHOUSE_GHOST_DOG_SAD: 'CommonBuffId' = 175676 + GO_ON_ADVENTURE_LIGHTHOUSE_SAW_GHOST: 'CommonBuffId' = 175671 + GO_ON_ADVENTURE_LIGHTHOUSE_SUSPICIOUS: 'CommonBuffId' = 175673 + GO_ON_ADVENTURE_TOWN_SQUARE_A_B1: 'CommonBuffId' = 178248 + GO_ON_ADVENTURE_TOWN_SQUARE_DIRTY_AND_HAPPY: 'CommonBuffId' = 175955 + GO_ON_ADVENTURE_WHISKERMANS_WHARF_SAVED_DOG: 'CommonBuffId' = 175956 + GO_TO_FLOAT_HIDDEN: 'CommonBuffId' = 119068 + GRAND_MEAL_BIG_MEAL: 'CommonBuffId' = 182679 + GRAND_MEAL_FOOD_COMA: 'CommonBuffId' = 182678 + GRAND_MEAL_HIDDEN_ENJOY_COMPANY: 'CommonBuffId' = 191091 + GRIM_REAPER_ALWAYS_ON: 'CommonBuffId' = 76684 + GRIM_REAPER_DEMAND_SUCCESS: 'CommonBuffId' = 73900 + GRIM_REAPER_PLEAD_SUCCESS: 'CommonBuffId' = 73897 + GRIM_REAPER_ROLE: 'CommonBuffId' = 12450 + GRIM_REAPER_SEDUCED_DEATH: 'CommonBuffId' = 73899 + GRIM_REAPER_SPARED: 'CommonBuffId' = 12451 + GROSS_MANNERS_EMBARRASSED_GAMBLED_AND_LOST: 'CommonBuffId' = 161735 + GROSS_MANNERS_EMBARRASSED_REACTED: 'CommonBuffId' = 161734 + GROUNDED_BREAKING: 'CommonBuffId' = 163474 + GROUNDED_BREAK_REWARD_PLAYFUL: 'CommonBuffId' = 163473 + GROUNDED_BREAK_REWARD_STRESSED: 'CommonBuffId' = 163472 + GROUNDED_BROKE_FLAG: 'CommonBuffId' = 163470 + GROUNDED_CAUGHT_BREAKING: 'CommonBuffId' = 163476 + GROUNDED_CONTROLLERS_NO_COMPUTER: 'CommonBuffId' = 161725 + GROUNDED_CONTROLLERS_NO_FRIENDS: 'CommonBuffId' = 161746 + GROUNDED_CONTROLLERS_NO_MUSIC: 'CommonBuffId' = 161764 + GROUNDED_CONTROLLERS_NO_OFF_LOT: 'CommonBuffId' = 161737 + GROUNDED_CONTROLLERS_NO_PHONE: 'CommonBuffId' = 161757 + GROUNDED_CONTROLLERS_NO_TOYS: 'CommonBuffId' = 161789 + GROUNDED_CONTROLLERS_NO_TV: 'CommonBuffId' = 161676 + GROUNDED_NO_COMPUTER_HIGH_RESPONSIBILITY: 'CommonBuffId' = 161719 + GROUNDED_NO_COMPUTER_LOW_RESPONSIBILITY: 'CommonBuffId' = 161717 + GROUNDED_NO_COMPUTER_MED_RESPONSIBILITY: 'CommonBuffId' = 161720 + GROUNDED_NO_FRIENDS_HIGH_RESPONSIBILITY: 'CommonBuffId' = 161742 + GROUNDED_NO_FRIENDS_LOW_RESPONSIBILITY: 'CommonBuffId' = 161740 + GROUNDED_NO_FRIENDS_MED_RESPONSIBILITY: 'CommonBuffId' = 161743 + GROUNDED_NO_MUSIC_HIGH_RESPONSIBILITY: 'CommonBuffId' = 161761 + GROUNDED_NO_MUSIC_LOW_RESPONSIBILITY: 'CommonBuffId' = 161759 + GROUNDED_NO_MUSIC_MED_RESPONSIBILITY: 'CommonBuffId' = 161762 + GROUNDED_NO_OFF_LOT_HIGH_RESPONSIBILITY: 'CommonBuffId' = 161729 + GROUNDED_NO_OFF_LOT_LOW_RESPONSIBILITY: 'CommonBuffId' = 161727 + GROUNDED_NO_OFF_LOT_MED_RESPONSIBILITY: 'CommonBuffId' = 161730 + GROUNDED_NO_PHONE_HIGH_RESPONSIBILITY: 'CommonBuffId' = 161754 + GROUNDED_NO_PHONE_LOW_RESPONSIBILITY: 'CommonBuffId' = 161752 + GROUNDED_NO_PHONE_MED_RESPONSIBILITY: 'CommonBuffId' = 161755 + GROUNDED_NO_TOYS_HIGH_RESPONSIBILITY: 'CommonBuffId' = 161768 + GROUNDED_NO_TOYS_LOW_RESPONSIBILITY: 'CommonBuffId' = 161766 + GROUNDED_NO_TOYS_MED_RESPONSIBILITY: 'CommonBuffId' = 161769 + GROUNDED_NO_TV_HIGH_RESPONSIBILITY: 'CommonBuffId' = 161670 + GROUNDED_NO_TV_LOW_RESPONSIBILITY: 'CommonBuffId' = 161673 + GROUNDED_NO_TV_MED_RESPONSIBILITY: 'CommonBuffId' = 161672 + GROUNDED_STRESSOR: 'CommonBuffId' = 161674 + GROUNDED_WHINED_RECENTLY: 'CommonBuffId' = 168477 + GROUP_STORY_READY_TO_TELL: 'CommonBuffId' = 342622 + GROUP_WALKING_TRAIL_PREVENT_IMMEDIATE_SCORING: 'CommonBuffId' = 311561 + GROUP_WALKING_TRAIL_ROUTE_EVENT_JOG: 'CommonBuffId' = 318569 + GROUP_WALKING_TRAIL_ROUTE_EVENT_POWER_WALK: 'CommonBuffId' = 311537 + GROUP_WALKING_TRAIL_ROUTE_EVENT_REFLECTIVE_WALK: 'CommonBuffId' = 314802 + GROUP_WALKING_TRAIL_ROUTE_EVENT_WALK: 'CommonBuffId' = 311536 + GROUP_WALKING_TRAIL_SOLO_WALK_REWARDS_BRONZE: 'CommonBuffId' = 311966 + GROUP_WALKING_TRAIL_SOLO_WALK_REWARDS_SILVER_GOLD: 'CommonBuffId' = 311967 + GROUP_WALKING_TRAIL_SOLO_WALK_REWARDS_TIN: 'CommonBuffId' = 311965 + GROUP_WALKING_TRAIL_WALK_AROUND_WITH_LEADER_REWARDS_BRONZE: 'CommonBuffId' = 311963 + GROUP_WALKING_TRAIL_WALK_AROUND_WITH_LEADER_REWARDS_SILVER_GOLD: 'CommonBuffId' = 311964 + GROUP_WALKING_TRAIL_WALK_AROUND_WITH_LEADER_REWARDS_TIN: 'CommonBuffId' = 311962 + GROUP_WALKING_TRAIL_WALK_AROUND_WITH_MEMBER_REWARDS_BRONZE: 'CommonBuffId' = 311960 + GROUP_WALKING_TRAIL_WALK_AROUND_WITH_MEMBER_REWARDS_SILVER_GOLD: 'CommonBuffId' = 311961 + GROUP_WALKING_TRAIL_WALK_AROUND_WITH_MEMBER_REWARDS_TIN: 'CommonBuffId' = 311959 + GUIDED_MEDITATION_DEBUG_FEEDBACK_NEGATIVE: 'CommonBuffId' = 272732 + GUIDED_MEDITATION_DEBUG_FEEDBACK_NO_PAY: 'CommonBuffId' = 272731 + GUIDED_MEDITATION_DEBUG_FEEDBACK_POSITIVE: 'CommonBuffId' = 272733 + GUIDED_MEDITATION_DEBUG_FEEDBACK_TIP: 'CommonBuffId' = 272734 + GUIDED_MEDITATION_IN_CLASS: 'CommonBuffId' = 272143 + GUIDED_MEDITATION_IS_OUTSIDE: 'CommonBuffId' = 272316 + GUIDED_MEDITATION_POST_CLASS: 'CommonBuffId' = 272268 + GUIDED_MEDITATION_PRE_CLASS_CLASS_MEMBER: 'CommonBuffId' = 272231 + GUIDED_MEDITATION_PRE_CLASS_INSTRUCTOR: 'CommonBuffId' = 272156 + GUIDED_MEDITATION_SELF_DISCOVERY: 'CommonBuffId' = 272265 + GUIDED_MEDITATION_SELF_DISCOVERY_INCENSE: 'CommonBuffId' = 272266 + HAD_BABY: 'CommonBuffId' = 97243 + HAD_BABY_MALE: 'CommonBuffId' = 102462 + HAD_BABY_PET: 'CommonBuffId' = 169228 + HAD_SELF_DISCOVERY_HIDDEN: 'CommonBuffId' = 119066 + HAD_WOO_HOO_HIDDEN: 'CommonBuffId' = 75626 + HAIR_MAKE_UP_CHAIR_NEW_HAIR_CONFIDENT: 'CommonBuffId' = 197883 + HAIR_MAKE_UP_CHAIR_NEW_MAKE_UP_CONFIDENT: 'CommonBuffId' = 197884 + HAIR_MAKE_UP_CHAIR_REMOVE_HAT: 'CommonBuffId' = 200039 + HAIR_MAKE_UP_CHAIR_REMOVE_HAT_GIG: 'CommonBuffId' = 200999 + HAIR_MAKE_UP_CHAIR_STYLE_HAIR: 'CommonBuffId' = 196092 + HAIR_MAKE_UP_CHAIR_STYLIST_ARRIVAL: 'CommonBuffId' = 189724 + HAIR_MAKE_UP_CHAIR_STYLIST_BORED: 'CommonBuffId' = 189723 + HAIR_MAKE_UP_CHAIR_STYLIST_NEW_HAIR_INSPIRED: 'CommonBuffId' = 197882 + HAIR_MAKE_UP_CHAIR_STYLIST_NEW_MAKE_UP_INSPIRED: 'CommonBuffId' = 197888 + HAIR_MAKE_UP_CHAIR_STYLIST_WORKING: 'CommonBuffId' = 189722 + HAIR_MAKE_UP_CHAIR_WARDROBE_PEDESTAL_ALLOW_SIT: 'CommonBuffId' = 191942 + HAIR_MAKE_UP_CHAIR_WARDROBE_PEDESTAL_GIG_FAILED: 'CommonBuffId' = 189996 + HAIR_MAKE_UP_CHAIR_WARDROBE_PEDESTAL_KEEP_STYLE: 'CommonBuffId' = 189987 + HAPPILY_EVER_AFTER: 'CommonBuffId' = 103143 + HAPPILY_EVER_AFTER_GREAT_STORY: 'CommonBuffId' = 109734 + HAPPY_BY_POTION: 'CommonBuffId' = 26328 + HAPPY_HOUR: 'CommonBuffId' = 122665 + HAPPY_MEAN_MISCHIEF: 'CommonBuffId' = 37334 + HARVESTABLE_EMOTIONAL_BERRY_CONFIDENT: 'CommonBuffId' = 174575 + HARVESTABLE_EMOTIONAL_BERRY_ENERGIZED: 'CommonBuffId' = 174576 + HARVESTABLE_EMOTIONAL_BERRY_FLIRTY: 'CommonBuffId' = 174577 + HARVESTABLE_EMOTIONAL_BERRY_FOCUSED: 'CommonBuffId' = 174578 + HARVESTABLE_EMOTIONAL_BERRY_HAPPY: 'CommonBuffId' = 174574 + HARVESTABLE_EMOTIONAL_BERRY_INSPIRED: 'CommonBuffId' = 174579 + HARVESTABLE_EMOTIONAL_BERRY_PLAYFUL: 'CommonBuffId' = 174580 + HARVESTABLE_LEVEL0: 'CommonBuffId' = 103198 + HARVESTABLE_LEVEL1: 'CommonBuffId' = 103199 + HARVESTABLE_LEVEL2: 'CommonBuffId' = 103200 + HARVESTABLE_MUSHROOM_WILD_CHARMING: 'CommonBuffId' = 265137 + HARVESTABLE_MUSHROOM_WILD_CHARMING_STRONGER: 'CommonBuffId' = 266705 + HARVESTABLE_MUSHROOM_WILD_CHARMING_TODDLER: 'CommonBuffId' = 265649 + HARVESTABLE_MUSHROOM_WILD_CHARMING_TODDLER_STRONGER: 'CommonBuffId' = 266708 + HARVESTABLE_MUSHROOM_WILD_LOVELY: 'CommonBuffId' = 265138 + HARVESTABLE_MUSHROOM_WILD_LOVELY_PC: 'CommonBuffId' = 265651 + HARVESTABLE_MUSHROOM_WILD_LOVELY_PC_STRONGER: 'CommonBuffId' = 266712 + HARVESTABLE_MUSHROOM_WILD_LOVELY_STRONGER: 'CommonBuffId' = 266710 + HARVESTABLE_MUSHROOM_WILD_MYSTERIOUS: 'CommonBuffId' = 266742 + HARVESTABLE_MUSHROOM_WILD_NIGHTLY: 'CommonBuffId' = 265135 + HARVESTABLE_MUSHROOM_WILD_NIGHTLY_STRONGER: 'CommonBuffId' = 266714 + HARVESTABLE_MUSHROOM_WILD_SPICY: 'CommonBuffId' = 266253 + HARVESTABLE_MUSHROOM_WILD_SPICY_FAIL: 'CommonBuffId' = 266254 + HARVESTABLE_MUSHROOM_WILD_SPICY_FAIL_STRONGER: 'CommonBuffId' = 266718 + HARVESTABLE_MUSHROOM_WILD_SPICY_STRONGER: 'CommonBuffId' = 266716 + HARVESTABLE_MUSHROOM_WILD_VERDANT: 'CommonBuffId' = 265136 + HARVESTABLE_MUSHROOM_WILD_VERDANT_STRONGER: 'CommonBuffId' = 266720 + HARVESTABLE_MUSHROOM_WILD_VERDANT_TODDLER: 'CommonBuffId' = 265650 + HARVESTABLE_MUSHROOM_WILD_VERDANT_TODDLER_STRONGER: 'CommonBuffId' = 266722 + HARVESTABLE_VAMPIRE_EATS_GARLIC: 'CommonBuffId' = 155835 + HARVESTABLE_WEREWOLF_ATE_WOLFSBANE: 'CommonBuffId' = 298015 + HARVEST_FEST_GNOME_BAD_BUFF: 'CommonBuffId' = 180287 + HARVEST_FEST_GNOME_GOOD_BUFF: 'CommonBuffId' = 180286 + HAS_BEEN_WET: 'CommonBuffId' = 178758 + HAS_COMMITTED_TO_MAKING_IT_WORK_SENTIMENT_HIDDEN: 'CommonBuffId' = 378805 + HAS_SATISFIED_OR_VERY_SATISFIED_RELATIONSHIP_HIDDEN: 'CommonBuffId' = 378806 + HATES_CHILDREN_FLED_CHILD: 'CommonBuffId' = 259795 + HAUNTED_HOUSE_ACCURSED_REACTION_COOLDOWN: 'CommonBuffId' = 255061 + HAUNTED_HOUSE_BONEHILDA_NANNY_COOLDOWN: 'CommonBuffId' = 256679 + HAUNTED_HOUSE_DOLL_CREATE_COOLDOWN: 'CommonBuffId' = 256554 + HAUNTED_HOUSE_FIRST_TIME: 'CommonBuffId' = 252984 + HAUNTED_HOUSE_FORBIDDEN_CANDY_COOLDOWN: 'CommonBuffId' = 253677 + HAUNTED_HOUSE_GUIDRY_COOLDOWNS_DRINK: 'CommonBuffId' = 256462 + HAUNTED_HOUSE_GUIDRY_COOLDOWNS_HELP: 'CommonBuffId' = 256463 + HAUNTED_HOUSE_GUIDRY_COOLDOWNS_HUNGRY: 'CommonBuffId' = 256464 + HAUNTED_HOUSE_GUIDRY_COOLDOWNS_SLEEP: 'CommonBuffId' = 256465 + HAUNTED_HOUSE_GUIDRY_COOLDOWNS_SOUL: 'CommonBuffId' = 256582 + HAUNTED_HOUSE_GUIDRY_COOLDOWNS_TOO_SCARED: 'CommonBuffId' = 256466 + HAUNTED_HOUSE_GUIDRY_GIG: 'CommonBuffId' = 257092 + HAUNTED_HOUSE_GUIDRY_GOODBYE: 'CommonBuffId' = 255331 + HAUNTED_HOUSE_HEROIC_MODE_COOLDOWN: 'CommonBuffId' = 256332 + HAUNTED_HOUSE_PARANORMAL_INVESTIGATOR: 'CommonBuffId' = 254962 + HAUNTED_HOUSE_PARANORMAL_INVESTIGATOR_LEAVE_NOW: 'CommonBuffId' = 256781 + HAUNTED_HOUSE_PARANORMAL_INVESTIGATOR_OVER_MAX: 'CommonBuffId' = 257099 + HAUNTED_HOUSE_PARANORMAL_INVESTIGATOR_REACTION_COOLDOWN: 'CommonBuffId' = 256363 + HAUNTED_HOUSE_SOUL_SCRAP: 'CommonBuffId' = 256920 + HAUNTED_HOUSE_SPECTER_REACTION_COOLDOWN: 'CommonBuffId' = 255025 + HAUNTED_HOUSE_SPECTER_REACTION_IMMUNE: 'CommonBuffId' = 254147 + HAUNTED_HOUSE_SPECTER_SUMMON_COOLDOWN: 'CommonBuffId' = 256646 + HAUNTED_HOUSE_TEMPERANCE_BREAK_COOLDOWN: 'CommonBuffId' = 256678 + HAUNTED_HOUSE_TEMPERANCE_SCARED: 'CommonBuffId' = 256842 + HAUNTED_HOUSE_VISIBLE_ADRENALINE_SEEKER: 'CommonBuffId' = 256929 + HAUNTED_HOUSE_VISIBLE_AWKWARD_AURA: 'CommonBuffId' = 254789 + HAUNTED_HOUSE_VISIBLE_BONEHILDA_FORM: 'CommonBuffId' = 255370 + HAUNTED_HOUSE_VISIBLE_BUST_IN_FEEL_BAD: 'CommonBuffId' = 255073 + HAUNTED_HOUSE_VISIBLE_BUST_IN_FEEL_GOOD: 'CommonBuffId' = 255072 + HAUNTED_HOUSE_VISIBLE_FEAR_1: 'CommonBuffId' = 253117 + HAUNTED_HOUSE_VISIBLE_FEAR_3: 'CommonBuffId' = 253119 + HAUNTED_HOUSE_VISIBLE_FORBIDDEN_CANDY_BAD: 'CommonBuffId' = 253676 + HAUNTED_HOUSE_VISIBLE_FORBIDDEN_CANDY_GOOD: 'CommonBuffId' = 253675 + HAUNTED_HOUSE_VISIBLE_GHOST_FORM: 'CommonBuffId' = 255359 + HAUNTED_HOUSE_VISIBLE_MENACE: 'CommonBuffId' = 256773 + HAUNTED_HOUSE_VISIBLE_NEAR_TEMPERANCE: 'CommonBuffId' = 256373 + HAUNTED_HOUSE_VISIBLE_NOPE: 'CommonBuffId' = 254003 + HAUNTED_HOUSE_VISIBLE_OFFER_SOUL: 'CommonBuffId' = 254224 + HAUNTED_HOUSE_VISIBLE_PANIC: 'CommonBuffId' = 255345 + HAUNTED_HOUSE_VISIBLE_PARANORMAL_INVESTIGATOR_CHILD: 'CommonBuffId' = 255265 + HAUNTED_HOUSE_VISIBLE_READY_FOR_ANYTHING: 'CommonBuffId' = 253498 + HAUNTED_HOUSE_VISIBLE_SACRED_PROTECTION: 'CommonBuffId' = 253585 + HAUNTED_HOUSE_VISIBLE_SECOND_GUESSING: 'CommonBuffId' = 253499 + HAUNTED_HOUSE_VISIBLE_SOMETHING_AINT_RIGHT: 'CommonBuffId' = 253530 + HAUNTED_HOUSE_VISIBLE_SOUL_STUFFED: 'CommonBuffId' = 253679 + HAUNTED_HOUSE_VISIBLE_SPECTER_SLOSHED: 'CommonBuffId' = 253692 + HAUNTED_HOUSE_VISIBLE_SPECTRAL_SPRINKLES: 'CommonBuffId' = 254001 + HAUNTED_HOUSE_VISIBLE_WHAT_WAS_THAT: 'CommonBuffId' = 255353 + HEART_BED_NAUSEOUS_BUILD_UP: 'CommonBuffId' = 361617 + HIDDEN_BEING_MENTORED: 'CommonBuffId' = 38050 + HIDDEN_CHEF_COOKING: 'CommonBuffId' = 131282 + HIDDEN_CHEF_GIVE_COMPLIMENT: 'CommonBuffId' = 138534 + HIDDEN_CHEF_GIVE_INSULT: 'CommonBuffId' = 138535 + HIDDEN_CHILD_SKILL_IDEA_PERSON: 'CommonBuffId' = 308738 + HIDDEN_CONFIDENCE_CHILD_HIGH: 'CommonBuffId' = 306794 + HIDDEN_ENGAGED: 'CommonBuffId' = 281040 + HIDDEN_FIGHTING: 'CommonBuffId' = 120163 + HIDDEN_FIGHTING_VAMPIRES: 'CommonBuffId' = 156024 + HIDDEN_HOME_CHEF_COOKING_TIMER: 'CommonBuffId' = 140403 + HIDDEN_HOME_CHEF_GET_OUT: 'CommonBuffId' = 140405 + HIDDEN_HORSE_COMPETITION_ENTER_MASTER_COMPETITION: 'CommonBuffId' = 335588 + HIDDEN_HORSE_COMPETITION_WINNER_HORSE_REACTION: 'CommonBuffId' = 348347 + HIDDEN_HORSE_COMPETITION_WIN_COMPETITION: 'CommonBuffId' = 335589 + HIDDEN_HORSE_COMPETITION_WIN_MASTER_OR_ULTIMATE_COMPETITION: 'CommonBuffId' = 340311 + HIDDEN_HORSE_TRAINING_CANCEL: 'CommonBuffId' = 349192 + HIDDEN_INTERRUPT_INAPPROPRIATE_BEHAVIOR: 'CommonBuffId' = 129629 + HIDDEN_MARRIED: 'CommonBuffId' = 287888 + HIDDEN_MARRIED_NEWLY_WED: 'CommonBuffId' = 275285 + HIDDEN_MOOD_REPLACEMENT: 'CommonBuffId' = 26440 + HIDDEN_MOVE_AWAY_FROM_EQUESTRIAN_CENTER: 'CommonBuffId' = 349402 + HIDDEN_MOVE_AWAY_FROM_EQUESTRIAN_CENTER_FROM_SPECTATE: 'CommonBuffId' = 349403 + HIDDEN_OBJECT_TREAD_MILL_ROCK_CLIMBING_WALL_DEFEAT_FINAL_CLIMB_LEVEL: 'CommonBuffId' = 167902 + HIDDEN_PET_OWNER_EXIT_WATCH: 'CommonBuffId' = 170875 + HIDDEN_PET_STUBBORN_SCOLDED: 'CommonBuffId' = 166494 + HIDDEN_REMOVE_FOOTWEAR_FEMALE: 'CommonBuffId' = 119095 + HIDDEN_REMOVE_FOOTWEAR_FEMALE_SHOES: 'CommonBuffId' = 273533 + HIDDEN_REMOVE_FOOTWEAR_FEMALE_TIMEOUT: 'CommonBuffId' = 121071 + HIDDEN_REMOVE_FOOTWEAR_MALE: 'CommonBuffId' = 119094 + HIDDEN_REMOVE_FOOTWEAR_MALE_SHOES: 'CommonBuffId' = 273576 + HIDDEN_REMOVE_FOOTWEAR_MALE_TIMEOUT: 'CommonBuffId' = 121068 + HIDDEN_REMOVE_FOOTWEAR_TODDLER: 'CommonBuffId' = 273493 + HIDDEN_SCENARIO_3_INVITE_KICK_GOAL_ACTIVE: 'CommonBuffId' = 299785 + HIDDEN_SCENARIO_INHERITANCE_PHASE_1_DONATED_MONEY: 'CommonBuffId' = 338976 + HIDDEN_SCENARIO_INHERITANCE_PHASE_1_DRAMA_NODE_RECEIVED: 'CommonBuffId' = 339519 + HIDDEN_SCENARIO_INHERITANCE_PHASE_1_SENTIMENT_DECAY: 'CommonBuffId' = 347915 + HIDDEN_SCENARIO_INHERITANCE_PHASE_2_BURN_MONEY: 'CommonBuffId' = 338980 + HIDDEN_SCENARIO_INHERITANCE_PHASE_3_DONATE_INHERITANCE: 'CommonBuffId' = 338981 + HIDDEN_SCENARIO_INVITED_RIVAL: 'CommonBuffId' = 298066 + HIDDEN_SCENARIO_KICKED_OUT_RIVAL: 'CommonBuffId' = 298067 + HIDDEN_SCENARIO_STUCK_IN_THEIR_SHADOW_3_IMPROVE_WORSEN_ACTIVE: 'CommonBuffId' = 309102 + HIDDEN_SCENARIO_STUCK_IN_THEIR_SHADOW_3_RIVAL_ARRIVED: 'CommonBuffId' = 300430 + HIDDEN_SCENARIO_STUCK_IN_THEIR_SHADOW_ACCEPTED_PROPOSAL: 'CommonBuffId' = 297849 + HIDDEN_SCENARIO_STUCK_IN_THEIR_SHADOW_ASKED_ABOUT_CAREER: 'CommonBuffId' = 302136 + HIDDEN_SCENARIO_STUCK_IN_THEIR_SHADOW_ASTRONAUT_NO: 'CommonBuffId' = 302255 + HIDDEN_SCENARIO_STUCK_IN_THEIR_SHADOW_ASTRONAUT_YES: 'CommonBuffId' = 301599 + HIDDEN_SCENARIO_STUCK_IN_THEIR_SHADOW_CAN_QUIT: 'CommonBuffId' = 300348 + HIDDEN_SCENARIO_STUCK_IN_THEIR_SHADOW_GOAL_1_COMPLETE: 'CommonBuffId' = 299553 + HIDDEN_SCENARIO_STUCK_IN_THEIR_SHADOW_GOAL_2_COMPLETE: 'CommonBuffId' = 299554 + HIDDEN_SCENARIO_STUCK_IN_THEIR_SHADOW_HIGH_MOTIVES: 'CommonBuffId' = 302534 + HIDDEN_SCENARIO_STUCK_IN_THEIR_SHADOW_IMPROVE_WORSEN_COMPLETE: 'CommonBuffId' = 300059 + HIDDEN_SCENARIO_STUCK_IN_THEIR_SHADOW_PHASE_1_ANSWER_PHONE_GOAL_ACTIVE: 'CommonBuffId' = 323788 + HIDDEN_SCENARIO_STUCK_IN_THEIR_SHADOW_PHASE_3_ANSWER_PHONE_GOAL_ACTIVE: 'CommonBuffId' = 323840 + HIDDEN_SCENARIO_STUCK_IN_THEIR_SHADOW_REJECTED_PROPOSAL: 'CommonBuffId' = 297850 + HIDDEN_SCENARIO_STUCK_IN_THEIR_SHADOW_RIVAL_PURCHASES: 'CommonBuffId' = 299411 + HIDDEN_SCENARIO_STUCK_IN_THEIR_SHADOW_SCHMOOZED: 'CommonBuffId' = 300227 + HIDDEN_SCENARIO_STUCK_IN_THEIR_SHADOW_START: 'CommonBuffId' = 297026 + HIDDEN_SCENARIO_STUCK_IN_THEIR_SHADOW_VOODOO_OWNER: 'CommonBuffId' = 302339 + HIDDEN_SCENARIO_STUCK_IN_THEIR_SHADOW_WORKED_HARD: 'CommonBuffId' = 300139 + HIDDEN_SLEEPING_POD_WOOHOOING: 'CommonBuffId' = 200583 + HIDDEN_WITNESSED_DEATH_BODY: 'CommonBuffId' = 127005 + HIDDEN_WITNESSED_DEATH_MOURN: 'CommonBuffId' = 126962 + HIDDEN_WITNESSED_DEATH_REAPING: 'CommonBuffId' = 126992 + HIDDEN_YOGA_INSTRUCTOR_CLASS_STARTING: 'CommonBuffId' = 118679 + HIDDEN_YOGA_INSTRUCTOR_IN_CLASS: 'CommonBuffId' = 121795 + HIGH_SCHOOL_ACTIVE_ALL_IN_THE_BRANDING: 'CommonBuffId' = 284970 + HIGH_SCHOOL_ACTIVE_ASK_CAREER_DETAILS_COOLDOWN: 'CommonBuffId' = 282516 + HIGH_SCHOOL_ACTIVE_ASK_CAREER_DETAILS_NEGATIVE: 'CommonBuffId' = 290051 + HIGH_SCHOOL_ACTIVE_ASK_CAREER_DETAILS_POSITIVE: 'CommonBuffId' = 290050 + HIGH_SCHOOL_ACTIVE_ATTENDING_CLASS: 'CommonBuffId' = 287711 + HIGH_SCHOOL_ACTIVE_AVOIDED_CONSEQUENCES: 'CommonBuffId' = 277054 + HIGH_SCHOOL_ACTIVE_BRAND_RECOGNITION: 'CommonBuffId' = 284967 + HIGH_SCHOOL_ACTIVE_CAREER_DAY_CAN_ASK_CAREER_DETAILS: 'CommonBuffId' = 294255 + HIGH_SCHOOL_ACTIVE_CAREER_DAY_CLEAR_FUTURE: 'CommonBuffId' = 284357 + HIGH_SCHOOL_ACTIVE_CAREER_DAY_FUTURE_UNCERTAIN: 'CommonBuffId' = 284358 + HIGH_SCHOOL_ACTIVE_CAREER_DAY_WATCHED_1: 'CommonBuffId' = 289100 + HIGH_SCHOOL_ACTIVE_CAREER_DAY_WATCHED_2: 'CommonBuffId' = 289101 + HIGH_SCHOOL_ACTIVE_CAREER_DAY_WATCHED_3: 'CommonBuffId' = 289099 + HIGH_SCHOOL_ACTIVE_CAUGHT_FOR_TRUANCY: 'CommonBuffId' = 277057 + HIGH_SCHOOL_ACTIVE_CLAIMED_LOCKER: 'CommonBuffId' = 300256 + HIGH_SCHOOL_ACTIVE_CLASSICALLY_STUDIED: 'CommonBuffId' = 284939 + HIGH_SCHOOL_ACTIVE_CLUMPY_CLOTHING: 'CommonBuffId' = 291516 + HIGH_SCHOOL_ACTIVE_COMPLETED_T_POSE_CHALLENGE: 'CommonBuffId' = 293436 + HIGH_SCHOOL_ACTIVE_CRICKETS: 'CommonBuffId' = 284960 + HIGH_SCHOOL_ACTIVE_DEBUG_FORCE_CHANCE_CARD: 'CommonBuffId' = 297343 + HIGH_SCHOOL_ACTIVE_EXAM_FAIL: 'CommonBuffId' = 292772 + HIGH_SCHOOL_ACTIVE_EXAM_HIGH: 'CommonBuffId' = 292770 + HIGH_SCHOOL_ACTIVE_EXAM_MAX: 'CommonBuffId' = 292768 + HIGH_SCHOOL_ACTIVE_EXAM_POOR: 'CommonBuffId' = 292771 + HIGH_SCHOOL_ACTIVE_EXPERIMENT_GONE_WRONG: 'CommonBuffId' = 284933 + HIGH_SCHOOL_ACTIVE_FRIENDLY_GAME_OF_TELEPHONE: 'CommonBuffId' = 284894 + HIGH_SCHOOL_ACTIVE_GOAL_COUNT_1: 'CommonBuffId' = 300540 + HIGH_SCHOOL_ACTIVE_GOAL_COUNT_2: 'CommonBuffId' = 300541 + HIGH_SCHOOL_ACTIVE_GOT_AWAY_WITH_IT: 'CommonBuffId' = 284941 + HIGH_SCHOOL_ACTIVE_GOT_CLASS_LIST: 'CommonBuffId' = 282582 + HIGH_SCHOOL_ACTIVE_GOT_DETENTION_HIDDEN: 'CommonBuffId' = 276713 + HIGH_SCHOOL_ACTIVE_GRADE_TRICKLING_DOWNWARD: 'CommonBuffId' = 284964 + HIGH_SCHOOL_ACTIVE_HOOKY_AT_SCHOOL: 'CommonBuffId' = 285682 + HIGH_SCHOOL_ACTIVE_HOOKY_AT_SCHOOL_CAUGHT: 'CommonBuffId' = 304704 + HIGH_SCHOOL_ACTIVE_HOW_TO_CLIMB_THE_CORPORATE_LADDER: 'CommonBuffId' = 284962 + HIGH_SCHOOL_ACTIVE_IDEA_THEFT: 'CommonBuffId' = 291515 + HIGH_SCHOOL_ACTIVE_LAUGHING_STOCK: 'CommonBuffId' = 291512 + HIGH_SCHOOL_ACTIVE_MADE_TO_STAY_LATE: 'CommonBuffId' = 304698 + HIGH_SCHOOL_ACTIVE_MATH_WHIZ: 'CommonBuffId' = 291514 + HIGH_SCHOOL_ACTIVE_MORNING_JAMZ: 'CommonBuffId' = 291510 + HIGH_SCHOOL_ACTIVE_MOUTHED_OFF_WARNING: 'CommonBuffId' = 294896 + HIGH_SCHOOL_ACTIVE_MOUTHING_OFF: 'CommonBuffId' = 294893 + HIGH_SCHOOL_ACTIVE_NPC_JANITOR_CLEAN_BATHROOM_COOLDOWN: 'CommonBuffId' = 297004 + HIGH_SCHOOL_ACTIVE_NPC_JANITOR_CLEAN_PUDDLE_COOLDOWN: 'CommonBuffId' = 297005 + HIGH_SCHOOL_ACTIVE_NPC_JANITOR_CLEAN_TABLE_COOLDOWN: 'CommonBuffId' = 297007 + HIGH_SCHOOL_ACTIVE_NPC_MONITOR_DETENTION: 'CommonBuffId' = 297585 + HIGH_SCHOOL_ACTIVE_ONE_OF_THE_COOL_KIDS: 'CommonBuffId' = 284896 + HIGH_SCHOOL_ACTIVE_PATROL_COOLDOWN_BATHROOM: 'CommonBuffId' = 303587 + HIGH_SCHOOL_ACTIVE_PATROL_COOLDOWN_CAFETERIA: 'CommonBuffId' = 303588 + HIGH_SCHOOL_ACTIVE_PATROL_COOLDOWN_HALLWAY: 'CommonBuffId' = 303589 + HIGH_SCHOOL_ACTIVE_PATROL_COOLDOWN_MISC: 'CommonBuffId' = 303590 + HIGH_SCHOOL_ACTIVE_PA_BOREDOM: 'CommonBuffId' = 291511 + HIGH_SCHOOL_ACTIVE_PHYSICS_TO_THE_FACE: 'CommonBuffId' = 284935 + HIGH_SCHOOL_ACTIVE_READY_TO_TEST: 'CommonBuffId' = 284955 + HIGH_SCHOOL_ACTIVE_SENT_BACK_TO_SCHOOL: 'CommonBuffId' = 285639 + HIGH_SCHOOL_ACTIVE_SKIPPED_CLASS: 'CommonBuffId' = 287712 + HIGH_SCHOOL_ACTIVE_SPAGHETTI_ARCHITECT: 'CommonBuffId' = 291517 + HIGH_SCHOOL_ACTIVE_STOPPING_THE_SPREAD: 'CommonBuffId' = 284854 + HIGH_SCHOOL_ACTIVE_STUCK: 'CommonBuffId' = 284898 + HIGH_SCHOOL_ACTIVE_TONGUE_TIED: 'CommonBuffId' = 291513 + HIGH_SCHOOL_ACTIVE_TOOK_THE_BLAME: 'CommonBuffId' = 284893 + HIGH_SCHOOL_DAY_ROLE_DURING_CLASS: 'CommonBuffId' = 272760 + HIGH_SCHOOL_FESTIVAL_ALL_DO_MISCHIEF: 'CommonBuffId' = 282185 + HIGH_SCHOOL_FESTIVAL_ALL_DO_PHOTO_OP_ACTIVITY: 'CommonBuffId' = 282193 + HIGH_SCHOOL_FESTIVAL_ALL_ENTER_FESTIVAL: 'CommonBuffId' = 282496 + HIGH_SCHOOL_FESTIVAL_ALL_JUDGE_COMPETITION: 'CommonBuffId' = 282191 + HIGH_SCHOOL_FESTIVAL_ALL_SUBMIT_SCORE: 'CommonBuffId' = 282163 + HIGH_SCHOOL_FESTIVAL_ALL_WATCH_COMPETITION: 'CommonBuffId' = 282160 + HIGH_SCHOOL_FESTIVAL_ALL_WATCH_RESULT: 'CommonBuffId' = 282271 + HIGH_SCHOOL_FESTIVAL_ANNOUNCED_RESULTS: 'CommonBuffId' = 285562 + HIGH_SCHOOL_FESTIVAL_BIG_LEAGUE: 'CommonBuffId' = 291265 + HIGH_SCHOOL_FESTIVAL_BRANIAC_JAMMING: 'CommonBuffId' = 291267 + HIGH_SCHOOL_FESTIVAL_CHESS_BATTLE_NO_LAW: 'CommonBuffId' = 291266 + HIGH_SCHOOL_FESTIVAL_ENTERED_FESTIVAL: 'CommonBuffId' = 282498 + HIGH_SCHOOL_FESTIVAL_HYPED: 'CommonBuffId' = 291264 + HIGH_SCHOOL_FESTIVAL_SCIENCE_FAIR_DO_GAME_JAM: 'CommonBuffId' = 282096 + HIGH_SCHOOL_FESTIVAL_SCIENCE_FAIR_PLAY_CHESS: 'CommonBuffId' = 282180 + HIGH_SCHOOL_FESTIVAL_SCIENCE_FAIR_PLAY_CHESS_PUZZLE: 'CommonBuffId' = 282094 + HIGH_SCHOOL_FESTIVAL_SCIENCE_FAIR_PLAY_WITH_TABLET: 'CommonBuffId' = 282178 + HIGH_SCHOOL_FESTIVAL_SPORTS_DAY_DO_COMPETITIVE_CHEER: 'CommonBuffId' = 282267 + HIGH_SCHOOL_FESTIVAL_SPORTS_DAY_DO_SOLO_CHEER: 'CommonBuffId' = 282157 + HIGH_SCHOOL_FESTIVAL_SPORTS_DAY_PLAY_FOOTBALL: 'CommonBuffId' = 282186 + HIGH_SCHOOL_FESTIVAL_SUBMITTED_TO_COMPETITION: 'CommonBuffId' = 284989 + HIGH_SCHOOL_GRADUATION_BAD_VALEDICTORIAN_SPEECH: 'CommonBuffId' = 289387 + HIGH_SCHOOL_GRADUATION_GAVE_SPEECH: 'CommonBuffId' = 291680 + HIGH_SCHOOL_GRADUATION_GOOD_VALEDICTORIAN_SPEECH: 'CommonBuffId' = 289386 + HIGH_SCHOOL_GRADUATION_GOT_DIPLOMA: 'CommonBuffId' = 287699 + HIGH_SCHOOL_GRADUATION_GOT_DIPLOMA_VISIBLE: 'CommonBuffId' = 289384 + HIGH_SCHOOL_GRADUATION_GRADUATION_CAP_OFF: 'CommonBuffId' = 288616 + HIGH_SCHOOL_GRADUATION_GRADUATION_OUTFIT_BLACK: 'CommonBuffId' = 296480 + HIGH_SCHOOL_GRADUATION_GRADUATION_OUTFIT_BROWN: 'CommonBuffId' = 296585 + HIGH_SCHOOL_GRADUATION_GRADUATION_OUTFIT_CORAL: 'CommonBuffId' = 296587 + HIGH_SCHOOL_GRADUATION_GRADUATION_OUTFIT_GRAY: 'CommonBuffId' = 296586 + HIGH_SCHOOL_GRADUATION_GRADUATION_OUTFIT_GREEN_YELLOW: 'CommonBuffId' = 296588 + HIGH_SCHOOL_GRADUATION_GRADUATION_OUTFIT_HAT_BLACK: 'CommonBuffId' = 304543 + HIGH_SCHOOL_GRADUATION_GRADUATION_OUTFIT_HAT_BROWN: 'CommonBuffId' = 304544 + HIGH_SCHOOL_GRADUATION_GRADUATION_OUTFIT_HAT_CORAL: 'CommonBuffId' = 304545 + HIGH_SCHOOL_GRADUATION_GRADUATION_OUTFIT_HAT_GRAY: 'CommonBuffId' = 304546 + HIGH_SCHOOL_GRADUATION_GRADUATION_OUTFIT_HAT_GREEN_YELLOW: 'CommonBuffId' = 304547 + HIGH_SCHOOL_GRADUATION_GRADUATION_OUTFIT_HAT_NAVY_RED: 'CommonBuffId' = 304548 + HIGH_SCHOOL_GRADUATION_GRADUATION_OUTFIT_HAT_ORANGE: 'CommonBuffId' = 304549 + HIGH_SCHOOL_GRADUATION_GRADUATION_OUTFIT_HAT_PURPLE: 'CommonBuffId' = 304550 + HIGH_SCHOOL_GRADUATION_GRADUATION_OUTFIT_HAT_RED: 'CommonBuffId' = 304581 + HIGH_SCHOOL_GRADUATION_GRADUATION_OUTFIT_HAT_WHITE: 'CommonBuffId' = 304582 + HIGH_SCHOOL_GRADUATION_GRADUATION_OUTFIT_HAT_WHITE_BLUE: 'CommonBuffId' = 304583 + HIGH_SCHOOL_GRADUATION_GRADUATION_OUTFIT_NAVY_RED: 'CommonBuffId' = 296590 + HIGH_SCHOOL_GRADUATION_GRADUATION_OUTFIT_ORANGE: 'CommonBuffId' = 296591 + HIGH_SCHOOL_GRADUATION_GRADUATION_OUTFIT_PURPLE: 'CommonBuffId' = 296584 + HIGH_SCHOOL_GRADUATION_GRADUATION_OUTFIT_RED: 'CommonBuffId' = 296488 + HIGH_SCHOOL_GRADUATION_GRADUATION_OUTFIT_WHITE: 'CommonBuffId' = 296486 + HIGH_SCHOOL_GRADUATION_GRADUATION_OUTFIT_WHITE_BLUE: 'CommonBuffId' = 296589 + HIGH_SCHOOL_GRADUATION_HEARD_BAD_SPEECH: 'CommonBuffId' = 289389 + HIGH_SCHOOL_GRADUATION_HEARD_GOOD_SPEECH: 'CommonBuffId' = 289388 + HIGH_SCHOOL_GRADUATION_SHARED_SCHOOL_MEMORIES: 'CommonBuffId' = 289385 + HIGH_SCHOOL_GRADUATION_WAITING_FOR_GIVE_DIPLOMA: 'CommonBuffId' = 302812 + HIGH_SCHOOL_PROM_CELEBRITY_DATE: 'CommonBuffId' = 280982 + HIGH_SCHOOL_PROM_CROWN_AUTONOMY: 'CommonBuffId' = 303165 + HIGH_SCHOOL_PROM_CROWN_SPIN_JESTER: 'CommonBuffId' = 283491 + HIGH_SCHOOL_PROM_CROWN_SPIN_ROYALTY: 'CommonBuffId' = 283492 + HIGH_SCHOOL_PROM_GOT_PROM_TNS: 'CommonBuffId' = 303561 + HIGH_SCHOOL_PROM_HIDDEN_GOT_PROM_TNS: 'CommonBuffId' = 289892 + HIGH_SCHOOL_PROM_NOSTALGIA: 'CommonBuffId' = 291997 + HIGH_SCHOOL_PROM_PRESENTER_ROUTE_TO_PODIUM: 'CommonBuffId' = 291274 + HIGH_SCHOOL_PROM_PRESENTER_WAITING: 'CommonBuffId' = 291933 + HIGH_SCHOOL_PROM_PRESENTING: 'CommonBuffId' = 285055 + HIGH_SCHOOL_PROM_REJECTED_PROM_POSAL: 'CommonBuffId' = 280985 + HIGH_SCHOOL_PROM_ROLE_TEEN_GENERIC: 'CommonBuffId' = 289410 + HIGH_SCHOOL_PROM_ROLE_TEEN_PRE_VOTE: 'CommonBuffId' = 284077 + HIGH_SCHOOL_PROM_SELECT_SIGN_1: 'CommonBuffId' = 301957 + HIGH_SCHOOL_PROM_SELECT_SIGN_2: 'CommonBuffId' = 301958 + HIGH_SCHOOL_PROM_SELECT_SIGN_3: 'CommonBuffId' = 301959 + HIGH_SCHOOL_PROM_SELECT_SIGN_4: 'CommonBuffId' = 301960 + HIGH_SCHOOL_PROM_SELECT_SIGN_5: 'CommonBuffId' = 301961 + HIGH_SCHOOL_PROM_SO_SHINY: 'CommonBuffId' = 280983 + HIGH_SCHOOL_PROM_SUCCESSFUL_PROMPOSAL: 'CommonBuffId' = 280984 + HIGH_SCHOOL_PROM_TEEN_GATHERING: 'CommonBuffId' = 285056 + HIGH_SCHOOL_PROM_TEEN_POST_VOTE: 'CommonBuffId' = 294531 + HIGH_SCHOOL_PROM_VOTED_JESTER: 'CommonBuffId' = 284628 + HIGH_SCHOOL_PROM_VOTED_ROYALTY: 'CommonBuffId' = 284629 + HIGH_SCHOOL_PROM_WATCH_AWARDS: 'CommonBuffId' = 301076 + HIGH_SCHOOL_PROM_WEARING_CROWN: 'CommonBuffId' = 284110 + HIGH_SCHOOL_TEAMS_CRUSH_CONFIDENT: 'CommonBuffId' = 296242 + HIGH_SCHOOL_TEAMS_CRUSH_EMBARRASSED: 'CommonBuffId' = 296241 + HIKING_TRAIL_HIKE_AROUND_WITH_BRONZE: 'CommonBuffId' = 240590 + HIKING_TRAIL_HIKE_AROUND_WITH_GOLD: 'CommonBuffId' = 240592 + HIKING_TRAIL_HIKE_AROUND_WITH_GOLD_ALL_SIMS: 'CommonBuffId' = 249653 + HIKING_TRAIL_HIKE_AROUND_WITH_LEADER_SILVER: 'CommonBuffId' = 249505 + HIKING_TRAIL_HIKE_AROUND_WITH_LEADER_TIN: 'CommonBuffId' = 249504 + HIKING_TRAIL_HIKE_AROUND_WITH_SILVER: 'CommonBuffId' = 240591 + HIKING_TRAIL_HIKE_AROUND_WITH_TIN: 'CommonBuffId' = 240589 + HIKING_TRAIL_POI_ENVIRONMENT_BAMBOO: 'CommonBuffId' = 249881 + HIKING_TRAIL_POI_ENVIRONMENT_NATURE_COVE: 'CommonBuffId' = 249882 + HIKING_TRAIL_POI_OFFERING_HIGH_VALUE: 'CommonBuffId' = 249884 + HIKING_TRAIL_POI_OFFERING_NORMAL_VALUE: 'CommonBuffId' = 249885 + HIKING_TRAIL_POI_OFFERING_POOR_ITEM: 'CommonBuffId' = 249887 + HIKING_TRAIL_POI_OFFERING_VERY_POOR_VALUE: 'CommonBuffId' = 249886 + HIKING_TRAIL_POI_SELFIE_CEMETERY: 'CommonBuffId' = 253842 + HIKING_TRAIL_POI_SELFIE_HAPPY: 'CommonBuffId' = 249883 + HIKING_TRAIL_POI_WISH_HAPPY: 'CommonBuffId' = 249889 + HIKING_TRAIL_POI_WISH_SAD: 'CommonBuffId' = 249888 + HIKING_TRAIL_PREVENT_IMMEDIATE_SCORING: 'CommonBuffId' = 253843 + HIKING_TRAIL_ROUTE_EVENT_JOG: 'CommonBuffId' = 251094 + HIKING_TRAIL_ROUTE_EVENT_MEDITATIVE_WALK: 'CommonBuffId' = 251095 + HIKING_TRAIL_ROUTE_EVENT_MINDFUL_WALK: 'CommonBuffId' = 253845 + HIKING_TRAIL_ROUTE_EVENT_WALK: 'CommonBuffId' = 251096 + HIKING_TRAIL_SOLO_HIKE_BRONZE: 'CommonBuffId' = 249502 + HIKING_TRAIL_SOLO_HIKE_SILVER: 'CommonBuffId' = 249503 + HIKING_TRAIL_SOLO_HIKE_TIN: 'CommonBuffId' = 249501 + HOLIDAYS_FASTING_COMPLETE: 'CommonBuffId' = 185462 + HOLIDAYS_FASTING_CONTROLLER: 'CommonBuffId' = 185756 + HOLIDAYS_FASTING_FAILED: 'CommonBuffId' = 185760 + HOLIDAYS_FASTING_PROGRESS: 'CommonBuffId' = 185464 + HOLIDAYS_GO_STREAKING: 'CommonBuffId' = 190712 + HOLIDAYS_HIDDEN_BASE_SOCIALS: 'CommonBuffId' = 181954 + HOLIDAYS_SABOTAGE_DISCIPLINE_INTERACTIONS: 'CommonBuffId' = 190702 + HOLIDAYS_TRADITION_VISIBLE_ALMOST_MISSED_THE_BALL_DROP: 'CommonBuffId' = 187765 + HOLIDAYS_VISIBLE_EXCELLENT: 'CommonBuffId' = 184169 + HOLIDAYS_VISIBLE_FAILURE: 'CommonBuffId' = 184170 + HOLIDAYS_VISIBLE_GREAT: 'CommonBuffId' = 184171 + HOLIDAY_BASE_ACTIVE: 'CommonBuffId' = 190549 + HOLIDAY_BASE_SINGING_TERRAIN: 'CommonBuffId' = 190554 + HOLIDAY_CANDLES_FEELING_FESTIVE_KINARA: 'CommonBuffId' = 348580 + HOLIDAY_CANDLES_FEELING_FESTIVE_MENORAH: 'CommonBuffId' = 348377 + HOLIDAY_CRACKER_CANDY_BUFFS_DAZED: 'CommonBuffId' = 155089 + HOLIDAY_CRACKER_CANDY_BUFFS_ENERGIZED: 'CommonBuffId' = 155102 + HOLIDAY_CRACKER_CANDY_BUFFS_FLIRTY: 'CommonBuffId' = 155065 + HOLIDAY_CRACKER_CANDY_BUFFS_HAPPY: 'CommonBuffId' = 155103 + HOLIDAY_CRACKER_CANDY_BUFFS_PLAYFUL: 'CommonBuffId' = 155104 + HOLIDAY_CRACKER_CANDY_BUFFS_UNCOMFORTABLE: 'CommonBuffId' = 155107 + HOLIDAY_CRACKER_CHILD_ANGER_BUFF: 'CommonBuffId' = 154618 + HOLIDAY_CRACKER_FESTIVE_BUFF: 'CommonBuffId' = 154617 + HOLIDAY_CRACKER_PLAYFUL_BUFF: 'CommonBuffId' = 154615 + HOLIDAY_CRACKER_SAD_BUFF: 'CommonBuffId' = 154619 + HOLIDAY_CRACKER_STRESSED: 'CommonBuffId' = 156177 + HOLIDAY_CRACKER_STRESSED_ELDERS: 'CommonBuffId' = 154614 + HOLIDAY_DECORATIONS_NEARBY: 'CommonBuffId' = 182227 + HOLIDAY_HIDDEN_GETTING_FORGED_BREAKUP_LETTER: 'CommonBuffId' = 191193 + HOLIDAY_TRADITIONS_HIDDEN_ADMIRE_GHOSTS: 'CommonBuffId' = 185903 + HOLIDAY_TRADITIONS_HIDDEN_ADORE_OBJECT: 'CommonBuffId' = 185570 + HOLIDAY_TRADITIONS_HIDDEN_BE_FESTIVE: 'CommonBuffId' = 185824 + HOLIDAY_TRADITIONS_HIDDEN_BE_THANKFUL: 'CommonBuffId' = 185845 + HOLIDAY_TRADITIONS_HIDDEN_EGG_HUNT: 'CommonBuffId' = 185569 + HOLIDAY_TRADITIONS_HIDDEN_FATHER_WINTER: 'CommonBuffId' = 185904 + HOLIDAY_TRADITIONS_HIDDEN_FESTIVE_LIGHTING: 'CommonBuffId' = 192434 + HOLIDAY_TRADITIONS_HIDDEN_GIVEN_PRESENT: 'CommonBuffId' = 188738 + HOLIDAY_TRADITIONS_HIDDEN_GIVE_GIFTS_ACTIVE: 'CommonBuffId' = 183253 + HOLIDAY_TRADITIONS_HIDDEN_GIVING_FLOWER: 'CommonBuffId' = 190740 + HOLIDAY_TRADITIONS_HIDDEN_GNOMES: 'CommonBuffId' = 185039 + HOLIDAY_TRADITIONS_HIDDEN_GO_TO_SERVICES: 'CommonBuffId' = 182195 + HOLIDAY_TRADITIONS_HIDDEN_NPC_GIVE_GIFTS_AUTONOMY: 'CommonBuffId' = 186034 + HOLIDAY_TRADITIONS_HIDDEN_ON_VACATION: 'CommonBuffId' = 191349 + HOLIDAY_TRADITIONS_HIDDEN_PARTY_INTERACTIONS: 'CommonBuffId' = 186063 + HOLIDAY_TRADITIONS_HIDDEN_SING_BOX_OF_DECORATIONS: 'CommonBuffId' = 189822 + HOLIDAY_TRADITIONS_HIDDEN_SING_FIREWORKS: 'CommonBuffId' = 190543 + HOLIDAY_TRADITIONS_HIDDEN_SING_GNOME: 'CommonBuffId' = 189821 + HOLIDAY_TRADITIONS_HIDDEN_SING_GRAND_MEAL: 'CommonBuffId' = 189826 + HOLIDAY_TRADITIONS_HIDDEN_SING_HOLIDAY_TREE: 'CommonBuffId' = 189839 + HOLIDAY_TRADITIONS_HIDDEN_SING_LIGHTING_CANDLES: 'CommonBuffId' = 189837 + HOLIDAY_TRADITIONS_HIDDEN_SING_PRESENT_PILE: 'CommonBuffId' = 189824 + HOLIDAY_TRADITIONS_HIDDEN_THROW_CONFETTI: 'CommonBuffId' = 186062 + HOLIDAY_TRADITIONS_HIDDEN_WATCH_COUNTDOWN: 'CommonBuffId' = 184001 + HOLIDAY_TRADITIONS_HIDDEN_WEAR_COSTUMES: 'CommonBuffId' = 187795 + HOLIDAY_TRADITIONS_HIDDEN_WEAR_COSTUME_COSTUME_ON: 'CommonBuffId' = 188498 + HOLIDAY_TRADITIONS_VISIBLE_BACK_TO_THE_FLOWER_GARDEN: 'CommonBuffId' = 187719 + HOLIDAY_TRADITIONS_VISIBLE_BACK_TO_THE_NORTH_POLE: 'CommonBuffId' = 187712 + HOLIDAY_TRADITIONS_VISIBLE_COUNTDOWN_TO_HILARITY: 'CommonBuffId' = 187767 + HOLIDAY_TRADITIONS_VISIBLE_DECORATE_THIS: 'CommonBuffId' = 187770 + HOLIDAY_TRADITIONS_VISIBLE_DECORATION_DESTRUCTION: 'CommonBuffId' = 187771 + HOLIDAY_TRADITIONS_VISIBLE_EVIL_LITTLE_LETTER: 'CommonBuffId' = 188794 + HOLIDAY_TRADITIONS_VISIBLE_FAMILY_TIME_TOMORROW: 'CommonBuffId' = 182184 + HOLIDAY_TRADITIONS_VISIBLE_FATHER_WINTERS_GOT_GAME: 'CommonBuffId' = 187720 + HOLIDAY_TRADITIONS_VISIBLE_FEAST_TOMORROW: 'CommonBuffId' = 182182 + HOLIDAY_TRADITIONS_VISIBLE_FLOWER_BUNNYS_GOT_GAME: 'CommonBuffId' = 187718 + HOLIDAY_TRADITIONS_VISIBLE_FORGERY_FAILURE: 'CommonBuffId' = 188793 + HOLIDAY_TRADITIONS_VISIBLE_GAME_OVER_FATHER_WINTER: 'CommonBuffId' = 187725 + HOLIDAY_TRADITIONS_VISIBLE_GAME_OVER_FLOWER_BUNNY: 'CommonBuffId' = 187724 + HOLIDAY_TRADITIONS_VISIBLE_GIFT_GIFTS_CHANCE_CARD_FAILURE: 'CommonBuffId' = 190337 + HOLIDAY_TRADITIONS_VISIBLE_GIFT_GIFTS_CHANCE_CARD_SUCCESS_CHILD: 'CommonBuffId' = 190339 + HOLIDAY_TRADITIONS_VISIBLE_GIFT_GIFTS_CHANCE_CARD_SUCCESS_TEEN: 'CommonBuffId' = 190336 + HOLIDAY_TRADITIONS_VISIBLE_LEAVE_FATHER_WINTER_ALONE: 'CommonBuffId' = 187722 + HOLIDAY_TRADITIONS_VISIBLE_LEAVE_FLOWER_BUNNY_ALONE: 'CommonBuffId' = 187721 + HOLIDAY_TRADITIONS_VISIBLE_MADE_IT_TO_MIDNIGHT: 'CommonBuffId' = 185846 + HOLIDAY_TRADITIONS_VISIBLE_MEAL_IN_AND_DEAL_IN: 'CommonBuffId' = 187768 + HOLIDAY_TRADITIONS_VISIBLE_PRESENTS_TOMORROW: 'CommonBuffId' = 182183 + HOLIDAY_TRADITIONS_VISIBLE_ROMANTIC_DAY_TOMORROW: 'CommonBuffId' = 182180 + HOLIDAY_TRADITIONS_VISIBLE_WHAT_A_THING: 'CommonBuffId' = 190453 + HOLIDAY_TRADITIONS_VISIBLE_WONDERFUL_SERVICE: 'CommonBuffId' = 182198 + HOLIDAY_TRADITIONS_WEAR_COSTUMES_WALK_BY: 'CommonBuffId' = 188579 + HOLIDAY_TREE_DECORATION_FAIL_ANGRY: 'CommonBuffId' = 180641 + HOLIDAY_TREE_DECORATION_FAIL_EMBARRASSED: 'CommonBuffId' = 180643 + HOLIDAY_TREE_DECORATION_SUCCESS: 'CommonBuffId' = 180636 + HOLIDAY_TREE_FEELING_FESTIVE: 'CommonBuffId' = 180611 + HOLIDAY_TREE_HIDDEN_EXIT: 'CommonBuffId' = 191241 + HOLIDAY_TREE_HIDDEN_WATCH: 'CommonBuffId' = 191242 + HOLIDAY_TREE_SABOTAGE_HAPPY: 'CommonBuffId' = 183606 + HOLOTABLE_ALARM_FIRST_ORDER_BROADCASTER: 'CommonBuffId' = 245027 + HOLOTABLE_ALARM_RESISTANCE_BROADCASTER: 'CommonBuffId' = 245028 + HOLOTABLE_ALARM_TRIGGERED: 'CommonBuffId' = 251008 + HOLOTABLE_ARCHIVES_ARE_COMPLETE: 'CommonBuffId' = 243144 + HOP_SCOTCH_HOPPED_TO_TOP: 'CommonBuffId' = 340937 + HOP_SCOTCH_HOPPING_MAD: 'CommonBuffId' = 340938 + HOP_SCOTCH_IN_GAME: 'CommonBuffId' = 342594 + HOP_SCOTCH_JUST_FAILED_HOP: 'CommonBuffId' = 340641 + HOP_SCOTCH_MORTIFYING_MISSTEP: 'CommonBuffId' = 340939 + HORRIFYING_JOKE_EMBARRASSED: 'CommonBuffId' = 98774 + HORSE_ADD_SENTIMENT_WITNESS_FOAL_BIRTH: 'CommonBuffId' = 338491 + HORSE_BREEDING_BUFFS_SIM_FOAL_DELIVERY: 'CommonBuffId' = 324233 + HORSE_BREEDING_BUFFS_SIM_HEART_FOAL_OF_LOVE: 'CommonBuffId' = 324087 + HORSE_BREEDING_BUFFS_WOOHOO_COOLDOWN: 'CommonBuffId' = 323056 + HORSE_CARE_OBJECTS_HORSE_TOY_PLAYFUL: 'CommonBuffId' = 328979 + HORSE_CARE_OBJECTS_HORSE_TOY_SAD: 'CommonBuffId' = 328980 + HORSE_DRINK_WATER_COOLDOWN_AUTONOMOUS: 'CommonBuffId' = 348067 + HORSE_FATIGUE_REACTION_COOLDOWN: 'CommonBuffId' = 349441 + HORSE_FOAL_MENTOREE_BY_MENTOR_PRO_TEMPERAMENT_SKILL: 'CommonBuffId' = 329482 + HORSE_HIDDEN_BASK_IN_HORSE_BRAVERY_COOLDOWN: 'CommonBuffId' = 340981 + HORSE_HIDDEN_BE_WOKEN_UP: 'CommonBuffId' = 328400 + HORSE_HIDDEN_MEAN_ACTOR_COOLDOWN_HORSE: 'CommonBuffId' = 346921 + HORSE_HIDDEN_MEAN_ACTOR_COOLDOWN_SIM: 'CommonBuffId' = 346922 + HORSE_HIDDEN_TEACH_TO_CANTER_COOLDOWN: 'CommonBuffId' = 330837 + HORSE_HIDDEN_WILL_NOT_BUCK: 'CommonBuffId' = 340914 + HORSE_HORSE_COMPETITION_CHAMPIONSHIP_HORSE: 'CommonBuffId' = 333538 + HORSE_HORSE_COMPETITION_ENTERED_A_COMPETITION: 'CommonBuffId' = 335314 + HORSE_INTELLECTUAL_CHAT_PICKER_COOLDOWN: 'CommonBuffId' = 348388 + HORSE_IS_SLEEPING: 'CommonBuffId' = 325741 + HORSE_IS_SLEEPING_SS3: 'CommonBuffId' = 328034 + HORSE_IS_SOCIALIZING: 'CommonBuffId' = 328033 + HORSE_MOODLETS_ANGRY_DEFIANT_FAILED_ASK_FOR_COOPERATION: 'CommonBuffId' = 340907 + HORSE_MOODLETS_CONFIDENT_EP14_WORLD_NPC_HORSE_TRAINER: 'CommonBuffId' = 329635 + HORSE_MOODLETS_CONFIDENT_EQUESTRIAN_SKILL: 'CommonBuffId' = 324382 + HORSE_MOODLETS_CONFIDENT_HORSE_OBSTACLES_SUCCESS: 'CommonBuffId' = 332050 + HORSE_MOODLETS_CONFIDENT_HORSE_TRAINING_ENCOURAGEMENT: 'CommonBuffId' = 332051 + HORSE_MOODLETS_CONFIDENT_MASTER_TRAINER_DURING_TRAINING: 'CommonBuffId' = 328997 + HORSE_MOODLETS_CONFIDENT_MASTER_TRAINER_POST_RIDE: 'CommonBuffId' = 328998 + HORSE_MOODLETS_DAZED_MELLOW_TRAINING_DAZE: 'CommonBuffId' = 340908 + HORSE_MOODLETS_DAZED_NEW_FOAL: 'CommonBuffId' = 330839 + HORSE_MOODLETS_HAPPY_ALL_MOTIVES_HIGH: 'CommonBuffId' = 335959 + HORSE_MOODLETS_HAPPY_CRADLED_WELL: 'CommonBuffId' = 330141 + HORSE_MOODLETS_HAPPY_EATING_FOOD_QUALITY_EXCELLENT: 'CommonBuffId' = 324246 + HORSE_MOODLETS_HAPPY_EATING_FOOD_QUALITY_MAGNIFICENT: 'CommonBuffId' = 324247 + HORSE_MOODLETS_HAPPY_EATING_FOOD_QUALITY_NICE: 'CommonBuffId' = 324245 + HORSE_MOODLETS_HAPPY_EATING_FOOD_QUALITY_PERFECT: 'CommonBuffId' = 324248 + HORSE_MOODLETS_HAPPY_ENERGETIC_GOT_EXERCISE: 'CommonBuffId' = 340772 + HORSE_MOODLETS_HAPPY_EQUESTRIAN_SKILL: 'CommonBuffId' = 326892 + HORSE_MOODLETS_HAPPY_GENTLY_TOUCHED: 'CommonBuffId' = 330139 + HORSE_MOODLETS_HAPPY_TALK_TO_GOAT: 'CommonBuffId' = 331361 + HORSE_MOODLETS_HAPPY_TALK_TO_SHEEP: 'CommonBuffId' = 331364 + HORSE_MOODLETS_HAPPY_WEAN_TO_HAY: 'CommonBuffId' = 330047 + HORSE_MOODLETS_HAPPY_WHATS_THAT: 'CommonBuffId' = 331853 + HORSE_MOODLETS_SAD_HORSE_OBSTACLES_FAILURE: 'CommonBuffId' = 332052 + HORSE_MOODLETS_SAD_LOST_COMPETITION: 'CommonBuffId' = 324471 + HORSE_MOODLETS_SAD_NEEDY_NEEDS_HAND_FEED: 'CommonBuffId' = 340725 + HORSE_MOODLETS_SAD_STUCK_INSIDE: 'CommonBuffId' = 326341 + HORSE_MOODLETS_SAD_TALK_TO_GOAT: 'CommonBuffId' = 331362 + HORSE_MOODLETS_SAD_TALK_TO_SHEEP: 'CommonBuffId' = 331363 + HORSE_MOODLETS_SAD_WEAN_TO_HAY: 'CommonBuffId' = 330048 + HORSE_MOODLETS_SAD_WITNESSED_DEATH: 'CommonBuffId' = 347528 + HORSE_MOODLETS_SCARED_FIRE: 'CommonBuffId' = 331744 + HORSE_MOODLETS_SCARED_LIGHTNING_NEARBY: 'CommonBuffId' = 335304 + HORSE_MOODLETS_SCARED_ROUGHLY_TOUCHED: 'CommonBuffId' = 330140 + HORSE_MOODLETS_SCARED_SPOOKED: 'CommonBuffId' = 324470 + HORSE_MOODLETS_SCARED_WHATS_THAT: 'CommonBuffId' = 331854 + HORSE_MOODLETS_TENSE_DEFIANT_STRESSED_FROM_MOUNTING: 'CommonBuffId' = 340906 + HORSE_MOODLETS_TENSE_EQUESTRIAN_SKILL_RIDING_IRRITATION: 'CommonBuffId' = 324384 + HORSE_MOODLETS_TENSE_EQUESTRIAN_SKIL_FEELING_RIDER_STRESS: 'CommonBuffId' = 324385 + HORSE_MOODLETS_UNCOMFORTABLE_DESOLATE: 'CommonBuffId' = 322224 + HORSE_MOODLETS_UNCOMFORTABLE_DESPERATE_FOR_FUN: 'CommonBuffId' = 322222 + HORSE_MOODLETS_UNCOMFORTABLE_DIRTY: 'CommonBuffId' = 322225 + HORSE_MOODLETS_UNCOMFORTABLE_EXHAUSTED: 'CommonBuffId' = 322220 + HORSE_MOODLETS_UNCOMFORTABLE_FAMISHED: 'CommonBuffId' = 322218 + HORSE_MOODLETS_UNCOMFORTABLE_HUNGRY: 'CommonBuffId' = 322217 + HORSE_MOODLETS_UNCOMFORTABLE_LONELY: 'CommonBuffId' = 322223 + HORSE_MOODLETS_UNCOMFORTABLE_NEEDS_AMUSMENT: 'CommonBuffId' = 322221 + HORSE_MOODLETS_UNCOMFORTABLE_ROUGHLY_CRADLED: 'CommonBuffId' = 330142 + HORSE_MOODLETS_UNCOMFORTABLE_TIRED: 'CommonBuffId' = 322219 + HORSE_MOTIVE_HYGIENE_ALLOW_CARE: 'CommonBuffId' = 348616 + HORSE_OBSTACLES_SIM_FAILURE: 'CommonBuffId' = 332055 + HORSE_OBSTACLES_SIM_SUCCESS: 'CommonBuffId' = 332054 + HORSE_RIDING_ALWAYS_THROW_RIDER: 'CommonBuffId' = 332120 + HORSE_RIDING_APPEARANCE_MODIFIER_REINS: 'CommonBuffId' = 332274 + HORSE_RIDING_APPEARANCE_MODIFIER_SADDLE: 'CommonBuffId' = 332141 + HORSE_RIDING_AUTONOMOUS_SOCIAL_WITH_RIDDEN_HORSE: 'CommonBuffId' = 347618 + HORSE_RIDING_HAPPY_REIN_IN_THE_SCENERY: 'CommonBuffId' = 326887 + HORSE_RIDING_HORSE_CARRYING_SIM: 'CommonBuffId' = 339267 + HORSE_RIDING_HORSE_LOVER: 'CommonBuffId' = 349411 + HORSE_RIDING_HORSE_MOUNTED: 'CommonBuffId' = 317538 + HORSE_RIDING_NEVER_THROW_RIDER: 'CommonBuffId' = 332089 + HORSE_RIDING_REAR_UP_UNBUCKABLE: 'CommonBuffId' = 340123 + HORSE_RIDING_REAR_UP_UNEXPECTED_REARING: 'CommonBuffId' = 340124 + HORSE_RIDING_REINS_DOWN: 'CommonBuffId' = 342330 + HORSE_RIDING_SIM_BUCKED_EMBARRASSED: 'CommonBuffId' = 339401 + HORSE_RIDING_SIM_BUCKED_UNCOMFORTABLE: 'CommonBuffId' = 339400 + HORSE_RIDING_SIM_MOUNTED: 'CommonBuffId' = 317537 + HORSE_RIDING_THROW_RIDER: 'CommonBuffId' = 332086 + HORSE_RIDING_WALKSTYLE_CANTER: 'CommonBuffId' = 326965 + HORSE_RIDING_WALKSTYLE_CANTER_LOW_SKILL: 'CommonBuffId' = 331991 + HORSE_RIDING_WALKSTYLE_CANTER_LOW_SKILL_BUCK_WILD: 'CommonBuffId' = 331996 + HORSE_RIDING_WALKSTYLE_GHOST_CANTER: 'CommonBuffId' = 345117 + HORSE_RIDING_WALKSTYLE_GHOST_CANTER_LOW_SKILL: 'CommonBuffId' = 345118 + HORSE_RIDING_WALKSTYLE_GHOST_TROT: 'CommonBuffId' = 345115 + HORSE_RIDING_WALKSTYLE_GHOST_TROT_LOW_SKILL: 'CommonBuffId' = 345116 + HORSE_RIDING_WALKSTYLE_GHOST_WALK: 'CommonBuffId' = 345113 + HORSE_RIDING_WALKSTYLE_GHOST_WALK_LOW_SKILL: 'CommonBuffId' = 345114 + HORSE_RIDING_WALKSTYLE_TROT: 'CommonBuffId' = 326967 + HORSE_RIDING_WALKSTYLE_TROT_LOW_SKILL: 'CommonBuffId' = 331993 + HORSE_RIDING_WALKSTYLE_TROT_LOW_SKILL_BUCK_WILD: 'CommonBuffId' = 331997 + HORSE_RIDING_WALKSTYLE_WALK: 'CommonBuffId' = 326966 + HORSE_RIDING_WALKSTYLE_WALK_LOW_SKILL: 'CommonBuffId' = 331995 + HORSE_RUN_AROUND_COOLDOWN: 'CommonBuffId' = 348068 + HORSE_RUN_AROUND_FROLIC_COOLDOWN: 'CommonBuffId' = 352692 + HORSE_RUN_AROUND_PORTAL_DISABLE: 'CommonBuffId' = 353335 + HORSE_SEASON_WEATHER_WET_VFX: 'CommonBuffId' = 335391 + HORSE_SEASON_WEATHER_WET_VFX_FOAL: 'CommonBuffId' = 349449 + HORSE_TRAINING_ENDURANCE_FATIGUE_DECAY: 'CommonBuffId' = 337154 + HORSE_TRAINING_FATIGUE: 'CommonBuffId' = 327961 + HORSE_TRAINING_SOCIALS_CHARISMA: 'CommonBuffId' = 330480 + HORSE_TRAINING_SOCIALS_DANCE: 'CommonBuffId' = 330481 + HORSE_TRAINING_SOCIALS_FITNESS: 'CommonBuffId' = 330478 + HORSE_TRAINING_SOCIALS_GAME_JUMPING: 'CommonBuffId' = 330479 + HORSE_TRANSACTION_ASK_ABOUT_HORSES_HIDDEN: 'CommonBuffId' = 332748 + HORSE_TRANSACTION_RECENTLY_INTERACTED_HIDDEN: 'CommonBuffId' = 332749 + HORSE_WEATHER_AUTONOMY_HIDDEN_IN_THE_RAIN: 'CommonBuffId' = 335400 + HOT_POT_ALL_PARTICIPANTS: 'CommonBuffId' = 254214 + HOT_POT_ATE_WITH_OTHERS: 'CommonBuffId' = 250906 + HOT_POT_ROLE_EAT: 'CommonBuffId' = 249676 + HOT_POT_ROLE_GATHER: 'CommonBuffId' = 249673 + HOT_POT_ROLE_START_COOKING: 'CommonBuffId' = 249674 + HOT_POT_ROLE_WAIT_TO_EAT: 'CommonBuffId' = 249675 + HOT_POT_STARTED_EATING: 'CommonBuffId' = 250893 + HOT_POT_WARM_SIM: 'CommonBuffId' = 250886 + HOVER_LAMP_FOCUSED: 'CommonBuffId' = 109868 + HUMANOID_ROBOTS_BEHAVIOR_MODULES_CHILD_CARE: 'CommonBuffId' = 218995 + HUMANOID_ROBOTS_BEHAVIOR_MODULES_CLEANING: 'CommonBuffId' = 218996 + HUMANOID_ROBOTS_BEHAVIOR_MODULES_FIGHTER: 'CommonBuffId' = 218997 + HUMANOID_ROBOTS_BEHAVIOR_MODULES_GARDENING: 'CommonBuffId' = 218999 + HUMANOID_ROBOTS_BEHAVIOR_MODULES_PARTY: 'CommonBuffId' = 219712 + HUMANOID_ROBOTS_BEHAVIOR_MODULES_REPAIR: 'CommonBuffId' = 218998 + HUMANOID_ROBOTS_BEHAVIOR_MODULES_SECURITY: 'CommonBuffId' = 218994 + HUMANOID_ROBOTS_CREATION_CREATOR_MARKER: 'CommonBuffId' = 221905 + HUMANOID_ROBOTS_ELECTROCUTION_HYPER_CHARGED: 'CommonBuffId' = 223943 + HUMANOID_ROBOTS_ELECTROCUTION_SUPER_CHARGED: 'CommonBuffId' = 223942 + HUMANOID_ROBOTS_ENHANCEMENT_LEVEL_1: 'CommonBuffId' = 219924 + HUMANOID_ROBOTS_ENHANCEMENT_LEVEL_10: 'CommonBuffId' = 219923 + HUMANOID_ROBOTS_ENHANCEMENT_LEVEL_2: 'CommonBuffId' = 219925 + HUMANOID_ROBOTS_ENHANCEMENT_LEVEL_3: 'CommonBuffId' = 219926 + HUMANOID_ROBOTS_ENHANCEMENT_LEVEL_4: 'CommonBuffId' = 219927 + HUMANOID_ROBOTS_ENHANCEMENT_LEVEL_5: 'CommonBuffId' = 219928 + HUMANOID_ROBOTS_ENHANCEMENT_LEVEL_6: 'CommonBuffId' = 219929 + HUMANOID_ROBOTS_ENHANCEMENT_LEVEL_7: 'CommonBuffId' = 219930 + HUMANOID_ROBOTS_ENHANCEMENT_LEVEL_8: 'CommonBuffId' = 219931 + HUMANOID_ROBOTS_ENHANCEMENT_LEVEL_9: 'CommonBuffId' = 219932 + HUMANOID_ROBOTS_FLIRT_WITH_OBJECT: 'CommonBuffId' = 223394 + HUMANOID_ROBOTS_HOVER_MODE_WALK_STYLE: 'CommonBuffId' = 223735 + HUMANOID_ROBOTS_MAIN_BUFF: 'CommonBuffId' = 219638 + HUMANOID_ROBOTS_MOOD_VFX_ANGRY: 'CommonBuffId' = 221879 + HUMANOID_ROBOTS_MOOD_VFX_BORED: 'CommonBuffId' = 221881 + HUMANOID_ROBOTS_MOOD_VFX_CONFIDENT: 'CommonBuffId' = 221882 + HUMANOID_ROBOTS_MOOD_VFX_DAZED: 'CommonBuffId' = 227718 + HUMANOID_ROBOTS_MOOD_VFX_EMBARRASSED: 'CommonBuffId' = 221814 + HUMANOID_ROBOTS_MOOD_VFX_ENERGIZED: 'CommonBuffId' = 221818 + HUMANOID_ROBOTS_MOOD_VFX_FINE: 'CommonBuffId' = 221819 + HUMANOID_ROBOTS_MOOD_VFX_FLIRTY: 'CommonBuffId' = 221883 + HUMANOID_ROBOTS_MOOD_VFX_FOCUSED: 'CommonBuffId' = 221820 + HUMANOID_ROBOTS_MOOD_VFX_HAPPY: 'CommonBuffId' = 220400 + HUMANOID_ROBOTS_MOOD_VFX_INSPIRED: 'CommonBuffId' = 221821 + HUMANOID_ROBOTS_MOOD_VFX_ONTRAVEL: 'CommonBuffId' = 230601 + HUMANOID_ROBOTS_MOOD_VFX_PLAYFUL: 'CommonBuffId' = 221816 + HUMANOID_ROBOTS_MOOD_VFX_SAD: 'CommonBuffId' = 221813 + HUMANOID_ROBOTS_MOOD_VFX_STRESSED: 'CommonBuffId' = 221884 + HUMANOID_ROBOTS_MOOD_VFX_UNCOMFORTABLE: 'CommonBuffId' = 221885 + HUMANOID_ROBOTS_MOTIVES_ALL_MOTIVES_HIGH: 'CommonBuffId' = 230065 + HUMANOID_ROBOTS_MOTIVES_ALL_MOTIVES_PRETTY_HIGH: 'CommonBuffId' = 230067 + HUMANOID_ROBOTS_OUTFIT: 'CommonBuffId' = 218341 + HUMANOID_ROBOTS_OUTFIT_BEIGE_WHITE: 'CommonBuffId' = 227829 + HUMANOID_ROBOTS_OUTFIT_BLACK_BLUE: 'CommonBuffId' = 227830 + HUMANOID_ROBOTS_OUTFIT_GRAY_BROWN: 'CommonBuffId' = 227831 + HUMANOID_ROBOTS_OUTFIT_GREEN_BROWN: 'CommonBuffId' = 227832 + HUMANOID_ROBOTS_OUTFIT_RED_GREEN: 'CommonBuffId' = 227833 + HUMANOID_ROBOTS_OUTFIT_WHITE_COPPER: 'CommonBuffId' = 227834 + HUMANOID_ROBOTS_STOP_ENHANCEMENT: 'CommonBuffId' = 229860 + HUMANOID_ROBOTS_THEY_ARE_PLANNING_SOMETHING: 'CommonBuffId' = 227141 + HUMANOID_ROBOTS_VFX_MINI_BOT_SOCIAL: 'CommonBuffId' = 229243 + ICE_CREAM_CREPE_YOUTH: 'CommonBuffId' = 251499 + ILLUMINATED_BY_STARS: 'CommonBuffId' = 105318 + IMMEDIATELY_PREPARED_FOOD_HIDDEN: 'CommonBuffId' = 170451 + INCREDIBLE_STORYTELLER: 'CommonBuffId' = 108018 + INFANTS_CARRY_BACK_HIDDEN: 'CommonBuffId' = 272014 + INFANTS_PERSONALITY_GASSY_GAS_TROUBLE: 'CommonBuffId' = 286118 + INFANTS_PERSONALITY_GIVE_QUIRKS: 'CommonBuffId' = 336049 + INFANTS_PERSONALITY_GOOD_APPETITE_FULL: 'CommonBuffId' = 334030 + INFANTS_PERSONALITY_HICCUPS_IDLE: 'CommonBuffId' = 286117 + INFANTS_PERSONALITY_OBSESSED_WITH_SOUND: 'CommonBuffId' = 286125 + INFANTS_PERSONALITY_ONLY_SLEEPS_WHEN_HELD: 'CommonBuffId' = 333686 + INFANTS_PERSONALITY_REVEAL_DELAY: 'CommonBuffId' = 333666 + INFANTS_PERSONALITY_SELF_SOOTHED: 'CommonBuffId' = 334066 + INFANTS_PERSONALITY_SELF_SOOTHER: 'CommonBuffId' = 286120 + INFANTS_PERSONALITY_SNEEZE_TRAIT: 'CommonBuffId' = 286119 + INFANTS_PERSONALITY_TALKER_TRAIT: 'CommonBuffId' = 286121 + INFANTS_TYAE_CARRY_BACK_HIDDEN: 'CommonBuffId' = 271983 + INFANT_ANTICIPATION_MOMENTS_WATCH_END: 'CommonBuffId' = 319240 + INFANT_ATTACHMENT_CARED_FOR_GOOD: 'CommonBuffId' = 275644 + INFANT_ATTACHMENT_CARED_FOR_GREAT: 'CommonBuffId' = 319192 + INFANT_ATTACHMENT_IS_ANYONE_THERE: 'CommonBuffId' = 275648 + INFANT_ATTACHMENT_IS_ANYONE_THERE_NEGLECTED: 'CommonBuffId' = 319339 + INFANT_ATTACHMENT_LOVED_GOOD: 'CommonBuffId' = 275646 + INFANT_ATTACHMENT_LOVED_GREAT: 'CommonBuffId' = 319196 + INFANT_ATTACHMENT_LOVE_SHOWN_FINE: 'CommonBuffId' = 275645 + INFANT_ATTACHMENT_LOVE_SHOWN_NEGLECTED: 'CommonBuffId' = 319194 + INFANT_ATTACHMENT_MOTIVE_DISTRESS: 'CommonBuffId' = 275468 + INFANT_ATTACHMENT_NEEDS_HELP_FINE: 'CommonBuffId' = 275647 + INFANT_ATTACHMENT_NEEDS_HELP_NEGLECTED: 'CommonBuffId' = 319200 + INFANT_ATTACHMENT_NEEDS_MET_FINE: 'CommonBuffId' = 275643 + INFANT_ATTACHMENT_NEEDS_MET_NEGLECTED: 'CommonBuffId' = 319190 + INFANT_AUTO_AGE_UP_TEST: 'CommonBuffId' = 322790 + INFANT_AWAKE_TIME: 'CommonBuffId' = 327515 + INFANT_BABY_BOP: 'CommonBuffId' = 317598 + INFANT_BABY_FEED_CRAVING_NEW_FLAVOR: 'CommonBuffId' = 305360 + INFANT_BEING_BREAST_FED: 'CommonBuffId' = 333766 + INFANT_BEING_LET_OUT: 'CommonBuffId' = 326995 + INFANT_BGO_MESMERIZED: 'CommonBuffId' = 277355 + INFANT_CANT_BE_CONTAINED: 'CommonBuffId' = 282585 + INFANT_CANT_REACH_ANGRY: 'CommonBuffId' = 321037 + INFANT_CANT_REACH_SAD: 'CommonBuffId' = 321043 + INFANT_CAREGIVER_ACTIVE: 'CommonBuffId' = 281020 + INFANT_CAREGIVER_PASSIVE: 'CommonBuffId' = 281019 + INFANT_CAREGIVER_TIME_ALONE_SHOW_CONCERN: 'CommonBuffId' = 282866 + INFANT_CARRY_COOLDOWN: 'CommonBuffId' = 276020 + INFANT_CARRY_GIVE_CARRIED_SIM_HIDDEN_TARGET: 'CommonBuffId' = 335678 + INFANT_CARRY_PROTECT_CARRY: 'CommonBuffId' = 333166 + INFANT_CARRY_RESPONSE_ANGRY_CARRY: 'CommonBuffId' = 275847 + INFANT_CARRY_RESPONSE_ANGRY_CARRY_BACK: 'CommonBuffId' = 275848 + INFANT_CARRY_RESPONSE_ANGRY_PUT_DOWN: 'CommonBuffId' = 275841 + INFANT_CARRY_RESPONSE_HAPPY_CARRY: 'CommonBuffId' = 275840 + INFANT_CARRY_RESPONSE_HAPPY_CARRY_BACK: 'CommonBuffId' = 275849 + INFANT_CARRY_RESPONSE_HAPPY_PUT_DOWN: 'CommonBuffId' = 275850 + INFANT_CARRY_RESPONSE_SAD_CARRY: 'CommonBuffId' = 275839 + INFANT_CARRY_RESPONSE_SAD_CARRY_BACK: 'CommonBuffId' = 275853 + INFANT_CARRY_RESPONSE_SAD_PUT_DOWN: 'CommonBuffId' = 275851 + INFANT_CARRY_RIGHT_HIDDEN: 'CommonBuffId' = 276004 + INFANT_CHECK_ON_CLASH_PREVENTION: 'CommonBuffId' = 335346 + INFANT_CHECK_ON_NOT_CHECKED_SHOW_CONCERN: 'CommonBuffId' = 283485 + INFANT_CHOMP_COOLDOWN: 'CommonBuffId' = 339336 + INFANT_CRAWLING_LEVEL_ONE: 'CommonBuffId' = 309450 + INFANT_CRAWLING_LEVEL_TWO: 'CommonBuffId' = 309449 + INFANT_CRAWLING_ON_THE_MOVE: 'CommonBuffId' = 280971 + INFANT_CRAWLING_ROUTE_EVENT_REACT_SHOCKED: 'CommonBuffId' = 310631 + INFANT_CRAWLING_ROUTE_EVENT_TIMER: 'CommonBuffId' = 323346 + INFANT_CRYING_BABY: 'CommonBuffId' = 316000 + INFANT_CRYING_BABY_HATES_CHILDREN: 'CommonBuffId' = 316002 + INFANT_CRYING_INFANT: 'CommonBuffId' = 276062 + INFANT_CRY_REACTION: 'CommonBuffId' = 324066 + INFANT_CRY_REACTION_COOLDOWN: 'CommonBuffId' = 324067 + INFANT_DIAPER_RASH: 'CommonBuffId' = 275886 + INFANT_FRESHLY_DIAPERED: 'CommonBuffId' = 311691 + INFANT_HIDDEN_DIAPER_OVER_FULL: 'CommonBuffId' = 329250 + INFANT_HIDDEN_DIAPER_PARTIAL_FULL: 'CommonBuffId' = 329248 + INFANT_HIDDEN_STINKY_DIAPER_ACTOR: 'CommonBuffId' = 309713 + INFANT_HIGH_CHAIR_ALREADY_FED_FIRST_BITE: 'CommonBuffId' = 334560 + INFANT_HIGH_CHAIR_BETRAYED: 'CommonBuffId' = 283945 + INFANT_HIGH_CHAIR_FOOD_BOREDOM: 'CommonBuffId' = 283944 + INFANT_HIGH_CHAIR_LAST_FOOD_EATEN_APPLESAUCE: 'CommonBuffId' = 307631 + INFANT_HIGH_CHAIR_LAST_FOOD_EATEN_BANANA_SLICES: 'CommonBuffId' = 307639 + INFANT_HIGH_CHAIR_LAST_FOOD_EATEN_CRUSHED_CARROTS: 'CommonBuffId' = 307632 + INFANT_HIGH_CHAIR_LAST_FOOD_EATEN_HOMEMADE_HUMMUS: 'CommonBuffId' = 307643 + INFANT_HIGH_CHAIR_LAST_FOOD_EATEN_ICE_CREAM: 'CommonBuffId' = 307635 + INFANT_HIGH_CHAIR_LAST_FOOD_EATEN_MASHED_MANGO: 'CommonBuffId' = 307644 + INFANT_HIGH_CHAIR_LAST_FOOD_EATEN_MASHED_PEAS: 'CommonBuffId' = 307647 + INFANT_HIGH_CHAIR_LAST_FOOD_EATEN_OATMEAL_CEREAL: 'CommonBuffId' = 307641 + INFANT_HIGH_CHAIR_LAST_FOOD_EATEN_OATY_OS: 'CommonBuffId' = 307636 + INFANT_HIGH_CHAIR_LAST_FOOD_EATEN_PAPAYA_PASTE: 'CommonBuffId' = 307646 + INFANT_HIGH_CHAIR_LAST_FOOD_EATEN_PEANUT_BUTTER_PUFFS: 'CommonBuffId' = 307638 + INFANT_HIGH_CHAIR_LAST_FOOD_EATEN_PUMPKIN_PUREE: 'CommonBuffId' = 307633 + INFANT_HIGH_CHAIR_LAST_FOOD_EATEN_RICE_PORRIDGE: 'CommonBuffId' = 307640 + INFANT_HIGH_CHAIR_LAST_FOOD_EATEN_SMASHED_AVOCADO: 'CommonBuffId' = 307645 + INFANT_HIGH_CHAIR_LAST_FOOD_EATEN_SMASHED_LEMON: 'CommonBuffId' = 307634 + INFANT_HIGH_CHAIR_LAST_FOOD_EATEN_SWEET_POTATO_PUREE: 'CommonBuffId' = 307642 + INFANT_HIGH_CHAIR_LAST_FOOD_EATEN_YOGURT: 'CommonBuffId' = 307630 + INFANT_HIGH_CHAIR_LAST_FOOD_EATEN_YOGURT_MELTS: 'CommonBuffId' = 307637 + INFANT_HIGH_CHAIR_YUMMY: 'CommonBuffId' = 283943 + INFANT_INVITED_OVER: 'CommonBuffId' = 320281 + INFANT_IN_SPECIAL_MULTI_SIM: 'CommonBuffId' = 335989 + INFANT_IS_BEING_CARED_FOR: 'CommonBuffId' = 335779 + INFANT_LOUD_NOISE_NOISY_NEIGHBOR_HIDDEN: 'CommonBuffId' = 321698 + INFANT_LOUSY_LOCKPICKER: 'CommonBuffId' = 282608 + INFANT_MILESTONE_ANTICIPATION_MOMENT_ALLOW_SIT: 'CommonBuffId' = 332429 + INFANT_MILESTONE_ANTICIPATION_MOMENT_BIG: 'CommonBuffId' = 327859 + INFANT_MILESTONE_ANTICIPATION_MOMENT_JUST_GRABBED: 'CommonBuffId' = 327168 + INFANT_MILESTONE_ANTICIPATION_MOMENT_JUST_REACHED: 'CommonBuffId' = 327169 + INFANT_MILESTONE_ANTICIPATION_MOMENT_SMALL: 'CommonBuffId' = 327858 + INFANT_MILESTONE_BLOCK_ANTICIPATION_PUSHER: 'CommonBuffId' = 335142 + INFANT_MILESTONE_CAN_CRAWL: 'CommonBuffId' = 322738 + INFANT_MILESTONE_CELEBRATE_MY_PRIDE_AND_JOY: 'CommonBuffId' = 319246 + INFANT_MILESTONE_CELEBRATE_OUTSHINED: 'CommonBuffId' = 319247 + INFANT_MILESTONE_CELEBRATE_PUSH_BRAG_COOLDOWN: 'CommonBuffId' = 324374 + INFANT_MILESTONE_MAIN: 'CommonBuffId' = 287573 + INFANT_MILESTONE_NOT_SITTING_UP: 'CommonBuffId' = 288538 + INFANT_MILESTONE_RECENT_UNLOCK: 'CommonBuffId' = 328806 + INFANT_MILESTONE_SIT_UP: 'CommonBuffId' = 287574 + INFANT_MILESTONE_SLEPT_THROUGH_NIGHT: 'CommonBuffId' = 331333 + INFANT_MILESTONE_UNLOCK_TRIGGER: 'CommonBuffId' = 320410 + INFANT_MOTIVE_OVERRIDE_ENERGY_ANGRY: 'CommonBuffId' = 279868 + INFANT_MOTIVE_OVERRIDE_ENERGY_SAD: 'CommonBuffId' = 275519 + INFANT_MOTIVE_OVERRIDE_ENERGY_VERY_ANGRY: 'CommonBuffId' = 279869 + INFANT_MOTIVE_OVERRIDE_ENERGY_VERY_SAD: 'CommonBuffId' = 275520 + INFANT_MOTIVE_OVERRIDE_FUN_ANGRY: 'CommonBuffId' = 275522 + INFANT_MOTIVE_OVERRIDE_FUN_SAD: 'CommonBuffId' = 279865 + INFANT_MOTIVE_OVERRIDE_FUN_VERY_ANGRY: 'CommonBuffId' = 275523 + INFANT_MOTIVE_OVERRIDE_FUN_VERY_SAD: 'CommonBuffId' = 279866 + INFANT_MOTIVE_OVERRIDE_HUNGER_ANGRY: 'CommonBuffId' = 275489 + INFANT_MOTIVE_OVERRIDE_HUNGER_SAD: 'CommonBuffId' = 279863 + INFANT_MOTIVE_OVERRIDE_HUNGER_VERY_ANGRY: 'CommonBuffId' = 275491 + INFANT_MOTIVE_OVERRIDE_HUNGER_VERY_SAD: 'CommonBuffId' = 279864 + INFANT_MOTIVE_OVERRIDE_HYGIENE_ANGRY: 'CommonBuffId' = 317664 + INFANT_MOTIVE_OVERRIDE_HYGIENE_SAD: 'CommonBuffId' = 279861 + INFANT_MOTIVE_OVERRIDE_HYGIENE_VERY_ANGRY: 'CommonBuffId' = 317665 + INFANT_MOTIVE_OVERRIDE_HYGIENE_VERY_SAD: 'CommonBuffId' = 279862 + INFANT_NANNY_CHECK_ON_COOLDOWN: 'CommonBuffId' = 330803 + INFANT_PEEKABOO_AUTONOMOUS_COOLDOWN: 'CommonBuffId' = 333241 + INFANT_PLAY_BABY_LAUGH: 'CommonBuffId' = 279257 + INFANT_PLAY_MAT_HIDDEN_PLAY_WITH_TRACKER: 'CommonBuffId' = 334481 + INFANT_PLAY_MAT_JUST_STOPPED_INTERACTION: 'CommonBuffId' = 332297 + INFANT_PLAY_SQUISHY_AND_COLD: 'CommonBuffId' = 322089 + INFANT_PLAY_THAT_WAS_CUTE: 'CommonBuffId' = 279256 + INFANT_PLAY_WATER_BABY: 'CommonBuffId' = 322399 + INFANT_PLAY_WIBBLE_WOBBLE: 'CommonBuffId' = 279258 + INFANT_PRE_SLEEP_HIDDEN_BED_TIME_STORY: 'CommonBuffId' = 279904 + INFANT_PRE_SLEEP_HIDDEN_LULLED_TO_SLEEP: 'CommonBuffId' = 279905 + INFANT_PRE_SLEEP_HIDDEN_SOOTHED_TO_SLEEP: 'CommonBuffId' = 279906 + INFANT_REACTION_ANGRY: 'CommonBuffId' = 334370 + INFANT_REACTION_COOLDOWN: 'CommonBuffId' = 333196 + INFANT_REACTION_HAPPY: 'CommonBuffId' = 334371 + INFANT_REACTION_SAD: 'CommonBuffId' = 334372 + INFANT_REWARD_TRAIT_HAPPY: 'CommonBuffId' = 320153 + INFANT_REWARD_TRAIT_TOP_NOTCH: 'CommonBuffId' = 320150 + INFANT_REWARD_TRAIT_UNHAPPY: 'CommonBuffId' = 320154 + INFANT_RILED_UP: 'CommonBuffId' = 287903 + INFANT_RUDE_AWAKENING: 'CommonBuffId' = 276334 + INFANT_SIM_SOCIAL_BABYLESS_BLISS: 'CommonBuffId' = 286217 + INFANT_SIM_SOCIAL_BABY_WORRY: 'CommonBuffId' = 286216 + INFANT_SIM_SOCIAL_CUTE_BABY: 'CommonBuffId' = 274949 + INFANT_SIM_SOCIAL_JEALOUS: 'CommonBuffId' = 286345 + INFANT_SIM_SOCIAL_PARENTAL_PRESSURE: 'CommonBuffId' = 286218 + INFANT_SIM_SOCIAL_PROUD: 'CommonBuffId' = 286343 + INFANT_SIM_SOCIAL_SWEET_SIBLINGS: 'CommonBuffId' = 286414 + INFANT_SIM_SOCIAL_UGH_BABIES: 'CommonBuffId' = 274950 + INFANT_SLEEP_AWAKE_ANGRY: 'CommonBuffId' = 275451 + INFANT_SLEEP_AWAKE_HAPPY: 'CommonBuffId' = 275452 + INFANT_SLEEP_AWAKE_SAD: 'CommonBuffId' = 275450 + INFANT_SLEEP_BED_TIME_STORY: 'CommonBuffId' = 275453 + INFANT_SLEEP_HIDDEN_AWAKE_BUFFS_ALLOWED: 'CommonBuffId' = 329251 + INFANT_SLEEP_HIDDEN_MOTIVE_ADJUST: 'CommonBuffId' = 331278 + INFANT_SLEEP_HIDDEN_SLEEP_TIME_DONE: 'CommonBuffId' = 275624 + INFANT_SLEEP_LULLED_TO_SLEEP: 'CommonBuffId' = 275518 + INFANT_SLEEP_SOOTHED: 'CommonBuffId' = 334368 + INFANT_SLEEP_SOOTHED_TO_SLEEP: 'CommonBuffId' = 275445 + INFANT_SOCIAL_BOUNCE: 'CommonBuffId' = 283572 + INFANT_SOCIAL_OUCH: 'CommonBuffId' = 282668 + INFANT_SOCIAL_WERE_THOSE_FANGS: 'CommonBuffId' = 282669 + INFANT_STINKY_DIAPER_TARGET: 'CommonBuffId' = 305678 + INFANT_STOP_CRY: 'CommonBuffId' = 332110 + INFANT_STUCK_ANGRY: 'CommonBuffId' = 321036 + INFANT_STUCK_SAD: 'CommonBuffId' = 321041 + INFANT_TINY_DANCER: 'CommonBuffId' = 317597 + INFANT_TOP_NOTCH: 'CommonBuffId' = 275659 + INFANT_TRAIT_CALM: 'CommonBuffId' = 277619 + INFANT_TRAIT_CALM_BOREDOM_EXIT: 'CommonBuffId' = 334661 + INFANT_TRAIT_CALM_MOVE_COOLDOWN: 'CommonBuffId' = 335335 + INFANT_TRAIT_CAUTIOUS: 'CommonBuffId' = 284563 + INFANT_TRAIT_CAUTIOUS_CAREGIVER_PROXIMITY: 'CommonBuffId' = 334601 + INFANT_TRAIT_CAUTIOUS_FAMILIAR_SPACE: 'CommonBuffId' = 284558 + INFANT_TRAIT_CAUTIOUS_NEED_FAMILIAR_FACE: 'CommonBuffId' = 284556 + INFANT_TRAIT_CAUTIOUS_PROXIMITY_BROADCASTER: 'CommonBuffId' = 334608 + INFANT_TRAIT_CAUTIOUS_PUT_DOWN: 'CommonBuffId' = 284698 + INFANT_TRAIT_CAUTIOUS_SAFE: 'CommonBuffId' = 284582 + INFANT_TRAIT_CAUTIOUS_STRANGE_PLACE: 'CommonBuffId' = 284557 + INFANT_TRAIT_CAUTIOUS_STRANGE_PLACE_HIDDEN: 'CommonBuffId' = 334606 + INFANT_TRAIT_GASSY_RELEASED: 'CommonBuffId' = 288901 + INFANT_TRAIT_HOME_CHECK: 'CommonBuffId' = 284572 + INFANT_TRAIT_INTENSE: 'CommonBuffId' = 287895 + INFANT_TRAIT_INTENSE_REFUSE_EATING: 'CommonBuffId' = 287901 + INFANT_TRAIT_SENSITIVE_OVERSTIMULATED: 'CommonBuffId' = 275857 + INFANT_TRAIT_SUNNY: 'CommonBuffId' = 277824 + INFANT_TRAIT_WIGGLY: 'CommonBuffId' = 275837 + INFANT_TRAIT_WIGGLY_TIME_FOR_WIGGLES: 'CommonBuffId' = 275843 + INFANT_TUMMY_TIME_SOMEONE_JOINED: 'CommonBuffId' = 319754 + INFANT_UGH_INFANTS: 'CommonBuffId' = 333378 + INFANT_WIGGLE_TO_MUSIC_COOLDOWN: 'CommonBuffId' = 335336 + INFANT_WONT_STOP_CRYING: 'CommonBuffId' = 276064 + INFATUATING_SCENT: 'CommonBuffId' = 118495 + INFECTED_PLANT_ATTACKS_BOTANOPHOBIA: 'CommonBuffId' = 203660 + INFECTED_PLANT_ATTACKS_HIDDEN_ATTACK_COOLDOWN: 'CommonBuffId' = 206540 + INFECTED_PLANT_ATTACKS_HIDDEN_REACT_COOLDOWN: 'CommonBuffId' = 207455 + INFECTED_PLANT_ATTACKS_RECENTLY_MOCKED_PLANT: 'CommonBuffId' = 202514 + INFECTION_CURE_TEMP_INFECTION_IMMUNITY: 'CommonBuffId' = 204249 + INFECTION_SCANNER_FIGHT_SCANNING_SIM: 'CommonBuffId' = 207198 + INFECTION_SCANNER_TRIGGERED_POSSESSION: 'CommonBuffId' = 207194 + INFLUENTIAL_INDIVIDUAL_CHEER: 'CommonBuffId' = 232560 + INFLUENTIAL_INDIVIDUAL_SHUN: 'CommonBuffId' = 232481 + INSECTS_BUG_BITE: 'CommonBuffId' = 102983 + INSECTS_ICKY_BUG: 'CommonBuffId' = 102986 + INSECTS_STINK_BUG: 'CommonBuffId' = 102984 + INSECT_FARM_BEETLE_BURNS: 'CommonBuffId' = 237703 + INSIGHTFUL_MEDITATION: 'CommonBuffId' = 119058 + INSIGHTFUL_MEDITATION_INCENSE: 'CommonBuffId' = 120175 + INSPIRATIONAL_MORAL: 'CommonBuffId' = 108024 + INSPIRATIONAL_MORAL_GREAT_STORYTELLER: 'CommonBuffId' = 109743 + INSPIRATIONAL_SCENT: 'CommonBuffId' = 118496 + INSPIRED_BY_NATURE: 'CommonBuffId' = 108251 + INSPIRED_BY_NATURE_LOVES_OUTDOORS: 'CommonBuffId' = 108258 + INSPIRED_BY_POTION: 'CommonBuffId' = 26334 + INSPIRED_SAW_SOME_STARS: 'CommonBuffId' = 31630 + INSPIRED_STARRY_NIGHT: 'CommonBuffId' = 31632 + INSPIRED_WRITING_ENTHUSED: 'CommonBuffId' = 26700 + INSPIRING_CHILD_STORY: 'CommonBuffId' = 31122 + INSTILLED_CONFIDENCE: 'CommonBuffId' = 26690 + INSTRUMENT_PLAYING_BADLY: 'CommonBuffId' = 38906 + INTENSE_WEATHER_SLIPPING_ON_THIN_ICE: 'CommonBuffId' = 247636 + INTERACTABLE_CAVE_BEASTLY_LAUGHTER: 'CommonBuffId' = 249444 + INTERACTABLE_CAVE_GREAT_RANTINGS: 'CommonBuffId' = 249450 + INTERACTABLE_CAVE_IM_GROWLIN_HERE: 'CommonBuffId' = 249445 + INTERACTABLE_CAVE_LUCKY_SIMOLEON: 'CommonBuffId' = 249453 + INTERACTABLE_CAVE_MAD_RANTINGS: 'CommonBuffId' = 249449 + INTERACTABLE_CAVE_MONSTROUS_LOGIC: 'CommonBuffId' = 249446 + INTERACTABLE_CAVE_SERIOUSLY: 'CommonBuffId' = 249448 + INTERACTABLE_CAVE_SPIRIT_DANCE: 'CommonBuffId' = 249447 + INTERACTABLE_CAVE_THAT_WONT_BE_ME: 'CommonBuffId' = 249451 + INTERACTABLE_CAVE_THOSE_WHO_CAME_BEFORE: 'CommonBuffId' = 249452 + INTERACTABLE_STATUE_LASER_FOCUS: 'CommonBuffId' = 224542 + INTERACTABLE_STATUE_NPC_OFFERING_COOLDOWN: 'CommonBuffId' = 224637 + INTERACTABLE_STATUE_PLACEBO: 'CommonBuffId' = 224541 + INTERACTABLE_STATUE_SURREAL_FOCUS: 'CommonBuffId' = 224523 + INTERROGATION_TABLE_MOOD_CONTROL_CALM: 'CommonBuffId' = 104575 + INTERROGATION_TABLE_MOOD_CONTROL_DEFENSIVE: 'CommonBuffId' = 104576 + INTERROGATION_TABLE_MOOD_CONTROL_FRIENDLY: 'CommonBuffId' = 104583 + INTERROGATION_TABLE_MOOD_CONTROL_FURIOUS: 'CommonBuffId' = 104577 + INTERROGATION_TABLE_MOOD_CONTROL_SHY: 'CommonBuffId' = 104578 + INTERROGATION_TABLE_MOOD_CONTROL_SMUG: 'CommonBuffId' = 104579 + INTERROGATION_TABLE_MOOD_CONTROL_SUSPICIOUS: 'CommonBuffId' = 104580 + INTERROGATION_TABLE_MOOD_CONTROL_TENSE: 'CommonBuffId' = 104598 + INTERROGATION_TABLE_MOOD_CONTROL_TERRIFIED: 'CommonBuffId' = 104582 + INTERROGATION_TABLE_MOOD_CONTROL_WORRIED: 'CommonBuffId' = 104581 + INTERROGATION_TABLE_RESULTS_INTERROGATION_FAILURE: 'CommonBuffId' = 106733 + INTERROGATION_TABLE_RESULTS_INTERROGATION_SUCCESS: 'CommonBuffId' = 106732 + INVALID: 'CommonBuffId' = 0 + INVESTIGATION_SYSTEM_ARCHIVE_EVIDENCE_COOLDOWN: 'CommonBuffId' = 205555 + INVESTIGATION_SYSTEM_CRAFT_SPORE_FILTER_COOLDOWN: 'CommonBuffId' = 207381 + INVESTIGATION_SYSTEM_KEY_CARD_MILITARY_REQUISITION_COOLDOWN: 'CommonBuffId' = 207586 + INVESTIGATION_SYSTEM_MILITARY_WALK_BY_WALK_STYLE_OVERRIDE_NORMAL: 'CommonBuffId' = 207068 + INVESTIGATION_SYSTEM_MILITARY_WALK_BY_WALK_STYLE_OVERRIDE_TOUGH: 'CommonBuffId' = 207069 + INVESTIGATION_SYSTEM_STOP_IMPRESS_WITH_PHYSICAL_PROWESS_SUCCESS: 'CommonBuffId' = 204066 + INVESTIGATION_SYSTEM_STOP_IMPRESS_W_ITH_PHYSICAL_PROWESS_FAILURE: 'CommonBuffId' = 204085 + INVIGORATED_BY_NATURE: 'CommonBuffId' = 108252 + INVIGORATED_BY_NATURE_LOVES_OUTDOORS: 'CommonBuffId' = 108260 + IN_DEBT: 'CommonBuffId' = 226857 + IN_REGION_BATUU: 'CommonBuffId' = 237013 + IN_REGION_BATUU_PLAYER: 'CommonBuffId' = 245146 + IN_RELATIONSHIP: 'CommonBuffId' = 374159 + IRRESPONSIBLE_IGNORE_BILLS: 'CommonBuffId' = 163657 + ISLANDER_CULTURE_EXTRA_FOOD_COMPLETE_OBJECTIVE: 'CommonBuffId' = 209313 + ISLANDER_CULTURE_FIRE_BRIGADE_NEIGHBOR_SAVED_ME: 'CommonBuffId' = 209214 + ISLANDER_CULTURE_NEIGHBORS_HELPED_THROUGH_THE_LOSS: 'CommonBuffId' = 208671 + ISLANDER_CULTURE_ROLE_NEED_SOMETHING_FIXED_REPAIR: 'CommonBuffId' = 210643 + ISLANDER_CULTURE_ROLE_NEED_SOMETHING_FIXED_WAITING: 'CommonBuffId' = 210662 + ISLANDER_CULTURE_ROLE_VISITOR_DEATH_COMFORT: 'CommonBuffId' = 208638 + ISLANDER_CULTURE_TRAIT_ISLANDER: 'CommonBuffId' = 209324 + ISLAND_CANOE_FLOWER_SAIL: 'CommonBuffId' = 209114 + ISLAND_CANOE_SAIL_AWAY: 'CommonBuffId' = 209108 + ISLAND_CONSERVATION_AUTONOMY_BUFFS_NPC_ANTI_ENVIRONMENTALIST: 'CommonBuffId' = 208869 + ISLAND_CONSERVATION_AUTONOMY_BUFFS_NPC_LITTERING_SIM: 'CommonBuffId' = 208868 + ISLAND_CONSERVATION_AUTONOMY_BUFFS_NPC_POACHING_SIM: 'CommonBuffId' = 208867 + ISLAND_CONSERVATION_AUTONOMY_MOD_TURTLE_HATCHING_GENERAL: 'CommonBuffId' = 205466 + ISLAND_CONSERVATION_BUFFS_DIDNT_LISTEN: 'CommonBuffId' = 209458 + ISLAND_CONSERVATION_BUFFS_MAKING_A_DIFFERENCE: 'CommonBuffId' = 209475 + ISLAND_CONSERVATION_BUFFS_MAKING_A_DIFFERENCE_VFX: 'CommonBuffId' = 212655 + ISLAND_CONSERVATION_BUFFS_OUCH: 'CommonBuffId' = 210469 + ISLAND_CONSERVATION_BUFFS_STINKY_PILE: 'CommonBuffId' = 210493 + ISLAND_CONSERVATION_BUFFS_TAMING_VOLCANO: 'CommonBuffId' = 210470 + ISLAND_EVENTS_AUTONOMY_MOD_TURTLE_HATCHING_CONSERVATIONIST: 'CommonBuffId' = 210347 + ISLAND_EVENTS_BEACH_BONFIRE_AUTONOMY_MOD: 'CommonBuffId' = 211686 + ISLAND_EVENTS_FAMILY_FUN_AUTONOMY_MOD_CHILD: 'CommonBuffId' = 209542 + ISLAND_EVENTS_FAMILY_FUN_AUTONOMY_MOD_PARENT: 'CommonBuffId' = 209535 + ISLAND_EVENTS_FAMILY_FUN_AUTONOMY_MOD_VENDOR: 'CommonBuffId' = 209543 + ISLAND_EVENTS_FISHING_COMPETITION_AUTONOMY_MOD_ANNOUNCE_WINNER: 'CommonBuffId' = 208367 + ISLAND_EVENTS_FISHING_COMPETITION_AUTONOMY_MOD_VENDOR: 'CommonBuffId' = 208366 + ISLAND_EVENTS_FISHING_COMPETITION_DONE_FISHING: 'CommonBuffId' = 208336 + ISLAND_EVENTS_ISLAND_CELEBRATION_AUTONOMY_MOD_BONFIRE_FIRE_DANCE: 'CommonBuffId' = 208294 + ISLAND_EVENTS_ISLAND_CELEBRATION_AUTONOMY_MOD_CREATE_OBJECTON_TABLE: 'CommonBuffId' = 208289 + ISLAND_EVENTS_ISLAND_CELEBRATION_AUTONOMY_MOD_VENDOR: 'CommonBuffId' = 211343 + ISLAND_EVENTS_ISLAND_CELEBRATION_CONSTRAINED: 'CommonBuffId' = 212365 + ISLAND_EVENTS_PART_OF_THE_COMMUNITY: 'CommonBuffId' = 210659 + ISLAND_EVENTS_POTLUCK_AUTONOMY_MOD: 'CommonBuffId' = 209537 + ISLAND_EVENTS_TOWN_BBQ_AUTONOMY_MOD_GRAB_KAVA: 'CommonBuffId' = 212080 + ISLAND_EVENTS_TOWN_BBQ_AUTONOMY_MOD_HANG_OUT_PIT_BBQ: 'CommonBuffId' = 212467 + ISLAND_EVENTS_TOWN_BBQ_AUTONOMY_MOD_MAKE_KAVA: 'CommonBuffId' = 212077 + ISLAND_EVENTS_TOWN_BBQ_AUTONOMY_MOD_USE_PIT_BBQ: 'CommonBuffId' = 212055 + ISLAND_EVENTS_TURTLE_HATCHING_ENTHUSE_ABOUT_BABY_TURTLES: 'CommonBuffId' = 215934 + ISLAND_WATERFALL_ALL_NATURAL_SHOWER: 'CommonBuffId' = 207412 + ISLAND_WATERFALL_ATTRACT_FROGS_HIDDEN: 'CommonBuffId' = 207427 + ISLAND_WATERFALL_CATCH_FROGS_COOLDOWN_HIDDEN: 'CommonBuffId' = 207426 + ISLAND_WATERFALL_EYES_WATCHING: 'CommonBuffId' = 207411 + ISLAND_WATERFALL_SPOTTED_IN_THE_OPEN: 'CommonBuffId' = 207414 + ISLAND_WATERFALL_WATERFALL_ESCAPADES: 'CommonBuffId' = 207410 + ISLAND_WATERFALL_WATERFALL_FROLIC: 'CommonBuffId' = 207418 + IS_BEAR_BG: 'CommonBuffId' = 153741 + IS_DANCING: 'CommonBuffId' = 156894 + IS_FLOATING_HIDDEN: 'CommonBuffId' = 119069 + IS_KNIGHT: 'CommonBuffId' = 129890 + IS_OWNED_PET: 'CommonBuffId' = 221056 + IS_RUNNING_MICROPHONE_SUPER_NOT_VISIBLE: 'CommonBuffId' = 39717 + IS_WADING: 'CommonBuffId' = 207673 + IS_WEARING_TOWEL: 'CommonBuffId' = 119404 + JEALOUSY_CAUGHT_CHEATING: 'CommonBuffId' = 76385 + JEALOUSY_CAUGHT_CHEATING_FIANCE: 'CommonBuffId' = 394371 + JEALOUSY_CAUGHT_WITH_ANOTHER: 'CommonBuffId' = 76384 + JEALOUSY_CHEATER: 'CommonBuffId' = 129283 + JEALOUSY_CHEATING_DISCOVERED: 'CommonBuffId' = 76387 + JEALOUSY_COMPERSION: 'CommonBuffId' = 362338 + JEALOUSY_DOOMED_RELATIONSHIP: 'CommonBuffId' = 76388 + JEALOUSY_DRIFTING_LOVE: 'CommonBuffId' = 76375 + JEALOUSY_ENEMY_WITH_BENEFITS: 'CommonBuffId' = 76378 + JEALOUSY_EVEN_MORE_AWKWARD: 'CommonBuffId' = 76567 + JEALOUSY_FLIRTY_FIANCE: 'CommonBuffId' = 394372 + JEALOUSY_FLIRTY_SPOUSE: 'CommonBuffId' = 76376 + JEALOUSY_FREEZE_MISSING_SO_TIMER: 'CommonBuffId' = 259618 + JEALOUSY_HIDDEN_WITNESSED_CHEATING: 'CommonBuffId' = 129281 + JEALOUSY_LOVE_INTEREST: 'CommonBuffId' = 76374 + JEALOUSY_TRUE_ENEMY: 'CommonBuffId' = 76559 + JEALOUSY_UNFAITHFUL_LOVE: 'CommonBuffId' = 76574 + JEALOUSY_UNINTERESTED_SOUL_MATE: 'CommonBuffId' = 76377 + JEALOUSY_UPDATES_EVERYTHING_IS_FINE: 'CommonBuffId' = 368349 + JEALOUSY_UPDATES_FILLED_WITH_REGRET: 'CommonBuffId' = 368919 + JEALOUSY_UPDATES_STILL_FEELS_WRONG: 'CommonBuffId' = 368231 + JEALOUSY_UPDATES_THAT_FELT_GOOD: 'CommonBuffId' = 368918 + JEALOUSY_WOO_HOO_INTERRUPTURE: 'CommonBuffId' = 125709 + JEALOUS_LOVED_ONE: 'CommonBuffId' = 12456 + JEALOUS_LOVED_ONE_GLOOMY: 'CommonBuffId' = 36956 + JOB_LOSS_CONSOLE_COOLDOWN: 'CommonBuffId' = 308844 + JOB_LOSS_LAY_OFF_ASSURED_OF_NEW_JOB: 'CommonBuffId' = 311100 + JOB_LOSS_LAY_OFF_BETWEEN_JOBS: 'CommonBuffId' = 307297 + JOB_LOSS_LAY_OFF_CHANCE: 'CommonBuffId' = 306067 + JOB_LOSS_LAY_OFF_COOLDOWN: 'CommonBuffId' = 306066 + JOB_LOSS_LAY_OFF_DEVASTATING: 'CommonBuffId' = 307295 + JOB_LOSS_LAY_OFF_EXPIRED: 'CommonBuffId' = 315653 + JOB_LOSS_LAY_OFF_LOOMING: 'CommonBuffId' = 306346 + JOB_LOSS_LAY_OFF_NEVER_NEEDED_THIS_JOB: 'CommonBuffId' = 307296 + JOB_LOSS_LAY_OFF_PITY_PIZZA: 'CommonBuffId' = 308584 + JOB_LOSS_LAY_OFF_PROMISING_PIZZA: 'CommonBuffId' = 308585 + JOB_LOSS_LAY_OFF_SLACK_OFF_BOOST: 'CommonBuffId' = 306500 + JOB_LOSS_LAY_OFF_WORK_HARDER_BOOST: 'CommonBuffId' = 306501 + JOB_LOSS_LOOKING_FOR_WORK_POST_COOLDOWN: 'CommonBuffId' = 308845 + JOB_LOSS_RECENTLY_LOST_JOB: 'CommonBuffId' = 307761 + JOURNAL_ANGRY: 'CommonBuffId' = 160146 + JOURNAL_ANGRY_ENTRY: 'CommonBuffId' = 160176 + JOURNAL_CONFIDENT: 'CommonBuffId' = 160149 + JOURNAL_EMBARRASSED: 'CommonBuffId' = 160151 + JOURNAL_EMBARRASSED_ENTRY: 'CommonBuffId' = 160174 + JOURNAL_HAPPY: 'CommonBuffId' = 160150 + JOURNAL_INSPIRED: 'CommonBuffId' = 160148 + JOURNAL_JOURNAL_BEING_SNOOPED: 'CommonBuffId' = 167847 + JOURNAL_NORMAL_ENTRY: 'CommonBuffId' = 160169 + JOURNAL_SAD: 'CommonBuffId' = 160152 + JOURNAL_SAD_ENTRY: 'CommonBuffId' = 160175 + JOURNAL_SNOOPING_CONFIDENT: 'CommonBuffId' = 160258 + JOURNAL_SNOOPING_EMBARRASSED: 'CommonBuffId' = 160257 + JOURNAL_STRESSED_ENTRY: 'CommonBuffId' = 160172 + JUICE_FIZZER_DRINK_EFFECTS_JUICE_AND_SELTZER_CONFIDENT_1: 'CommonBuffId' = 236417 + JUICE_FIZZER_DRINK_EFFECTS_JUICE_AND_SELTZER_CONFIDENT_3: 'CommonBuffId' = 236418 + JUICE_FIZZER_DRINK_EFFECTS_JUICE_AND_SELTZER_CONFIDENT_6: 'CommonBuffId' = 236419 + JUICE_FIZZER_DRINK_EFFECTS_JUICE_AND_SELTZER_ENERGIZED_1: 'CommonBuffId' = 236414 + JUICE_FIZZER_DRINK_EFFECTS_JUICE_AND_SELTZER_ENERGIZED_3: 'CommonBuffId' = 236415 + JUICE_FIZZER_DRINK_EFFECTS_JUICE_AND_SELTZER_ENERGIZED_6: 'CommonBuffId' = 236416 + JUICE_FIZZER_DRINK_EFFECTS_JUICE_AND_SELTZER_FLIRTY_1: 'CommonBuffId' = 236421 + JUICE_FIZZER_DRINK_EFFECTS_JUICE_AND_SELTZER_FLIRTY_3: 'CommonBuffId' = 236422 + JUICE_FIZZER_DRINK_EFFECTS_JUICE_AND_SELTZER_FLIRTY_6: 'CommonBuffId' = 236423 + JUICE_FIZZER_DRINK_EFFECTS_JUICE_AND_SELTZER_FOCUSED_1: 'CommonBuffId' = 236433 + JUICE_FIZZER_DRINK_EFFECTS_JUICE_AND_SELTZER_FOCUSED_3: 'CommonBuffId' = 236434 + JUICE_FIZZER_DRINK_EFFECTS_JUICE_AND_SELTZER_FOCUSED_6: 'CommonBuffId' = 236435 + JUICE_FIZZER_DRINK_EFFECTS_JUICE_AND_SELTZER_HAPPY_1: 'CommonBuffId' = 236372 + JUICE_FIZZER_DRINK_EFFECTS_JUICE_AND_SELTZER_HAPPY_3: 'CommonBuffId' = 236375 + JUICE_FIZZER_DRINK_EFFECTS_JUICE_AND_SELTZER_HAPPY_6: 'CommonBuffId' = 236377 + JUICE_FIZZER_DRINK_EFFECTS_JUICE_AND_SELTZER_INSPIRED_1: 'CommonBuffId' = 236429 + JUICE_FIZZER_DRINK_EFFECTS_JUICE_AND_SELTZER_INSPIRED_3: 'CommonBuffId' = 236430 + JUICE_FIZZER_DRINK_EFFECTS_JUICE_AND_SELTZER_INSPIRED_6: 'CommonBuffId' = 236431 + JUICE_FIZZER_DRINK_EFFECTS_JUICE_AND_SELTZER_PASSED_OUT: 'CommonBuffId' = 236561 + JUICE_FIZZER_DRINK_EFFECTS_JUICE_AND_SELTZER_PLAYFUL_1: 'CommonBuffId' = 236437 + JUICE_FIZZER_DRINK_EFFECTS_JUICE_AND_SELTZER_PLAYFUL_3: 'CommonBuffId' = 236438 + JUICE_FIZZER_DRINK_EFFECTS_JUICE_AND_SELTZER_PLAYFUL_6: 'CommonBuffId' = 236439 + JUICE_FIZZER_DRINK_EFFECTS_KOMBUCHA_DAZED_FIZZY_HEAD: 'CommonBuffId' = 236985 + JUICE_FIZZER_DRINK_EFFECTS_KOMBUCHA_DAZED_FROM_ENERGIZED: 'CommonBuffId' = 236607 + JUICE_FIZZER_DRINK_EFFECTS_KOMBUCHA_DAZED_FROM_FOCUSED: 'CommonBuffId' = 240188 + JUICE_FIZZER_DRINK_EFFECTS_KOMBUCHA_ENERGIZED_1: 'CommonBuffId' = 236570 + JUICE_FIZZER_DRINK_EFFECTS_KOMBUCHA_ENERGIZED_2: 'CommonBuffId' = 236571 + JUICE_FIZZER_DRINK_EFFECTS_KOMBUCHA_ENERGIZED_4: 'CommonBuffId' = 236572 + JUICE_FIZZER_DRINK_EFFECTS_KOMBUCHA_FOCUSED_1: 'CommonBuffId' = 236573 + JUICE_FIZZER_DRINK_EFFECTS_KOMBUCHA_FOCUSED_2: 'CommonBuffId' = 236574 + JUICE_FIZZER_DRINK_EFFECTS_KOMBUCHA_FOCUSED_4: 'CommonBuffId' = 236575 + JUICE_FIZZER_DRINK_EFFECTS_KOMBUCHA_GRIMBUCHA_1: 'CommonBuffId' = 236604 + JUICE_FIZZER_DRINK_EFFECTS_KOMBUCHA_GRIMBUCHA_2: 'CommonBuffId' = 236605 + JUICE_FIZZER_DRINK_EFFECTS_KOMBUCHA_GRIMBUCHA_4: 'CommonBuffId' = 236606 + JUICE_FIZZER_DRINK_EFFECTS_KOMBUCHA_GRIMBUCHA_DAZED: 'CommonBuffId' = 236614 + JUICE_FIZZER_DRINK_EFFECTS_SUSPICIOUS_DANGEROUSLY_FIZZY: 'CommonBuffId' = 236624 + JUICE_FIZZER_DRINK_EFFECTS_SUSPICIOUS_HORRIBLY_FIZZY: 'CommonBuffId' = 236623 + JUICE_FIZZER_DRINK_EFFECTS_SUSPICIOUS_WEIRDLY_FIZZY: 'CommonBuffId' = 236622 + JUICE_FIZZER_KOMBUCHA_ENERGIZED: 'CommonBuffId' = 236593 + JUICE_FIZZER_KOMBUCHA_FOCUSED: 'CommonBuffId' = 236594 + JUICE_FIZZER_KOMBUCHA_GRIMBUCHA: 'CommonBuffId' = 236595 + JUICE_FIZZER_TRAIT_FIZZER_FOCUS: 'CommonBuffId' = 236953 + JUICE_FIZZER_TRAIT_FIZZY_HEAD: 'CommonBuffId' = 236951 + JUICE_FIZZING_FLAT_FIZZ_FACTS: 'CommonBuffId' = 235751 + JUICE_FIZZING_JUICY_FIZZ_KNOWELDGE: 'CommonBuffId' = 235750 + JUICE_FIZZING_KNOWLEDGE_FIZZLED_OUT: 'CommonBuffId' = 235752 + JUICE_FIZZING_SEND_FOR_EVALUATION_AVERAGE: 'CommonBuffId' = 236826 + JUICE_FIZZING_SEND_FOR_EVALUATION_AWFUL: 'CommonBuffId' = 236827 + JUICE_FIZZING_SEND_FOR_EVALUATION_OUTSTANDING: 'CommonBuffId' = 236828 + JUICE_FIZZING_SEND_FOR_EVALUATION_VERY_GOOD: 'CommonBuffId' = 236829 + JUICE_FIZZING_SEND_FOR_EVALUATION_WORLD_CLASS: 'CommonBuffId' = 236830 + JUICE_KEG_BLUE_RASPBERRY_CONFIDENT_1: 'CommonBuffId' = 208584 + JUICE_KEG_BLUE_RASPBERRY_CONFIDENT_2: 'CommonBuffId' = 208585 + JUICE_KEG_BLUE_RASPBERRY_CONFIDENT_3: 'CommonBuffId' = 208586 + JUICE_KEG_DRAGON_FRUIT_PLAYFUL_1: 'CommonBuffId' = 208587 + JUICE_KEG_DRAGON_FRUIT_PLAYFUL_2: 'CommonBuffId' = 208588 + JUICE_KEG_DRAGON_FRUIT_PLAYFUL_3: 'CommonBuffId' = 208589 + JUICE_KEG_FINISHED_KEG: 'CommonBuffId' = 222674 + JUICE_KEG_FLAT_JUICE_DEBUFF: 'CommonBuffId' = 210446 + JUICE_KEG_KEG_PARTY_SNACKS: 'CommonBuffId' = 222683 + JUICE_KEG_KEG_STAND_FAIL: 'CommonBuffId' = 209601 + JUICE_KEG_KEG_STAND_SUCCESS: 'CommonBuffId' = 209600 + JUICE_KEG_PASSION_FRUIT_FLIRTY_1: 'CommonBuffId' = 208590 + JUICE_KEG_PASSION_FRUIT_FLIRTY_2: 'CommonBuffId' = 208591 + JUICE_KEG_PASSION_FRUIT_FLIRTY_3: 'CommonBuffId' = 208592 + JUICE_KEG_PINEAPPLE_HAPPY_1: 'CommonBuffId' = 208593 + JUICE_KEG_PINEAPPLE_HAPPY_2: 'CommonBuffId' = 208594 + JUICE_KEG_PINEAPPLE_HAPPY_3: 'CommonBuffId' = 208595 + JUICE_KEG_TAPPER_FAILED: 'CommonBuffId' = 209599 + JUICE_KEG_TAPPER_SUCCESS: 'CommonBuffId' = 209598 + JUNGLE_REGION_ON_JUNGLE_VACATION: 'CommonBuffId' = 178668 + JUNGLE_REGION_WELCOME_PACKAGE: 'CommonBuffId' = 183105 + JUNGLE_WELCOME_PACKAGE_RECEIVED: 'CommonBuffId' = 183130 + KARAOKE_MACHINE_COOLDOWN: 'CommonBuffId' = 154416 + KARAOKE_MACHINE_END_GOOD_SINGING: 'CommonBuffId' = 141672 + KARAOKE_MACHINE_END_GOOD_SINGING_ACTIVATED: 'CommonBuffId' = 152435 + KARAOKE_MACHINE_END_GOOD_SINGING_BALLAD: 'CommonBuffId' = 154200 + KARAOKE_MACHINE_END_POOR_SINGING: 'CommonBuffId' = 141671 + KARAOKE_MACHINE_GOOD_SINGING_ACTOR_GENERAL: 'CommonBuffId' = 148245 + KARAOKE_MACHINE_GOOD_SINGING_ACTOR_TRAITS_BUFF: 'CommonBuffId' = 148243 + KARAOKE_MACHINE_GREAT_SINGING_ACTOR_GENERAL: 'CommonBuffId' = 148244 + KARAOKE_MACHINE_GREAT_SINGING_ACTOR_TRAITS_BUFF: 'CommonBuffId' = 148242 + KARAOKE_MACHINE_HIDDEN_BALLAD_WITH_CHILD: 'CommonBuffId' = 155691 + KARAOKE_MACHINE_HIDDEN_CURRENTLY_SINGING: 'CommonBuffId' = 152415 + KARAOKE_MACHINE_HIDDEN_CURRENTLY_SINGING_CONTEST: 'CommonBuffId' = 153655 + KARAOKE_MACHINE_HIDDEN_CURRENTLY_SINGING_Y_SIM: 'CommonBuffId' = 152419 + KARAOKE_MACHINE_HIDDEN_WATCHING_BALLAD: 'CommonBuffId' = 154274 + KARAOKE_MACHINE_POOR_SINGING_ACTOR_GENERAL: 'CommonBuffId' = 148246 + KARAOKE_MACHINE_POOR_SINGING_ACTOR_TRAITS_BUFF: 'CommonBuffId' = 148241 + KAVA_BOWL_DRINK_BUFFS_LEVEL_1: 'CommonBuffId' = 205923 + KAVA_BOWL_DRINK_BUFFS_LEVEL_2: 'CommonBuffId' = 205924 + KAVA_BOWL_DRINK_BUFFS_LEVEL_3: 'CommonBuffId' = 205925 + KAVA_BOWL_DRINK_BUFFS_WELL_RESTED: 'CommonBuffId' = 206153 + KAVA_PARTY_INCLUDED: 'CommonBuffId' = 206775 + KAVA_PARTY_PHASE_2: 'CommonBuffId' = 206767 + KEEPSAKE_BOX_ADULT_VFX: 'CommonBuffId' = 324062 + KEEPSAKE_BOX_CHILD_VFX: 'CommonBuffId' = 328017 + KEEPSAKE_BOX_FAMILY_ENTRUSTED: 'CommonBuffId' = 320392 + KEEPSAKE_BOX_PASSING_TORCH: 'CommonBuffId' = 320391 + KEEPSAKE_BOX_PONDER_MEANING_BEING_TOGETHER: 'CommonBuffId' = 320700 + KEEPSAKE_BOX_PONDER_MEANING_COOLDOWN: 'CommonBuffId' = 320564 + KEEPSAKE_BOX_PONDER_MEANING_ISNT_EVERYTHING: 'CommonBuffId' = 320704 + KEEPSAKE_BOX_PONDER_MEANING_NOBODY_KNOWS: 'CommonBuffId' = 320705 + KEEPSAKE_BOX_PONDER_MEANING_OBEDIENCE: 'CommonBuffId' = 322837 + KEEPSAKE_BOX_PONDER_MEANING_PATIENCE: 'CommonBuffId' = 320706 + KEEPSAKE_BOX_PONDER_MEANING_TOLERANCE: 'CommonBuffId' = 320707 + KEEPSAKE_BOX_PONDER_MEANING_UNCONDITIONAL: 'CommonBuffId' = 320708 + KEEPSAKE_BOX_PONDER_MEANING_WEIRD: 'CommonBuffId' = 320709 + KEEPSAKE_BOX_WANT_COOL_BOX: 'CommonBuffId' = 320393 + KIDDIE_POOL_ADULT_COOL_POOL: 'CommonBuffId' = 189635 + KIDDIE_POOL_ADULT_ERRATIC_SPLASHING: 'CommonBuffId' = 189630 + KIDDIE_POOL_ADULT_SPLASHY_FUN: 'CommonBuffId' = 189629 + KIDDIE_POOL_TODDLER_POOL_TIME_PLAYFUL: 'CommonBuffId' = 189626 + KISS_COOLDOWN_QUICK_SOCIAL_NOT_VISIBLE: 'CommonBuffId' = 39865 + KNITTING_AUTONOMOUS_COOLDOWN: 'CommonBuffId' = 250694 + KNITTING_DONATE_BEANIES: 'CommonBuffId' = 241076 + KNITTING_DONATE_CHILD_TOY: 'CommonBuffId' = 241085 + KNITTING_DONATE_DECORATIONS: 'CommonBuffId' = 241082 + KNITTING_DONATE_FURNISHINGS: 'CommonBuffId' = 241078 + KNITTING_DONATE_ONESIES: 'CommonBuffId' = 241083 + KNITTING_DONATE_POUFFES: 'CommonBuffId' = 241081 + KNITTING_DONATE_RUGS: 'CommonBuffId' = 241079 + KNITTING_DONATE_SOCKS: 'CommonBuffId' = 241077 + KNITTING_DONATE_SWEATERS: 'CommonBuffId' = 241080 + KNITTING_DONATE_SWEATER_SCARF: 'CommonBuffId' = 241084 + KNITTING_IS_KNITTING: 'CommonBuffId' = 245464 + KNITTING_VISIBLE_BRUTAL_KNITS: 'CommonBuffId' = 241317 + KNITTING_VISIBLE_FRESH_START: 'CommonBuffId' = 243734 + KNITTING_VISIBLE_GREAT_KNITS: 'CommonBuffId' = 239824 + KNITTING_VISIBLE_INTERNAL_SCREAMING: 'CommonBuffId' = 239822 + KNITTING_VISIBLE_INTERWOVEN_FATES: 'CommonBuffId' = 239812 + KNITTING_VISIBLE_ITCHY_KNITS: 'CommonBuffId' = 239811 + KNITTING_VISIBLE_KNEAT_KNITS: 'CommonBuffId' = 239807 + KNITTING_VISIBLE_KNITTABLE_CONTRIBUTE: 'CommonBuffId' = 239809 + KNITTING_VISIBLE_MADE_THAT: 'CommonBuffId' = 239870 + KNITTING_VISIBLE_NO_MORE_KNITTING: 'CommonBuffId' = 239808 + KNITTING_VISIBLE_READY_SET_KNIT: 'CommonBuffId' = 239810 + KNITTING_VISIBLE_SWEATER_CURSE: 'CommonBuffId' = 239813 + KNITTING_VISIBLE_UNFORTUKNITS: 'CommonBuffId' = 239823 + KNITTING_WEARING_KNITTED_CLOTHING: 'CommonBuffId' = 240782 + KNITTING_YELL_AT_COOLDOWN: 'CommonBuffId' = 244399 + KOTATSU_COSY: 'CommonBuffId' = 248530 + KOTATSU_COSY_UPGRADED: 'CommonBuffId' = 248536 + KOTATSU_DAZED: 'CommonBuffId' = 248531 + KOTATSU_DAZED_STRONGER: 'CommonBuffId' = 252298 + KOTATSU_FUNNY_BURNING_SMELL: 'CommonBuffId' = 248529 + KOTATSU_HIDDEN_TEMPERATURE_COLD: 'CommonBuffId' = 248532 + KOTATSU_HIDDEN_TEMPERATURE_COOL: 'CommonBuffId' = 248533 + KOTATSU_HIDDEN_TEMPERATURE_HOT: 'CommonBuffId' = 248534 + KOTATSU_HIDDEN_TEMPERATURE_WARM: 'CommonBuffId' = 248535 + LAMPOON_PARTY_GOLD: 'CommonBuffId' = 202959 + LANDLORD_TENANT_ANGRY_TENANT: 'CommonBuffId' = 355689 + LANDLORD_TENANT_ASKED_ABOUT_CONDITIONS_HIDDEN: 'CommonBuffId' = 353764 + LANDLORD_TENANT_ASK_ABOUT_RENTAL_NEGATIVE: 'CommonBuffId' = 355703 + LANDLORD_TENANT_ASK_ABOUT_RENTAL_POSITIVE: 'CommonBuffId' = 355690 + LANDLORD_TENANT_BLAME_TENANTS: 'CommonBuffId' = 355683 + LANDLORD_TENANT_COMMEND_TENANTS: 'CommonBuffId' = 355684 + LANDLORD_TENANT_COMPLAIN_ABOUT_RENTAL_CONDITIONS: 'CommonBuffId' = 355681 + LANDLORD_TENANT_COMPLIMENT_RENTAL_CONDTIONS: 'CommonBuffId' = 355682 + LANDLORD_TENANT_COUPON: 'CommonBuffId' = 345820 + LANDLORD_TENANT_CRITICIZE_NEIGHBORS: 'CommonBuffId' = 355685 + LANDLORD_TENANT_DO_INSPECTION_MAINTENANCE_AUTONOMOUS_PLAYER_COOLDOWN_HIDDEN: 'CommonBuffId' = 360443 + LANDLORD_TENANT_EMERGENCY_SUCCESS_HIDDEN: 'CommonBuffId' = 351013 + LANDLORD_TENANT_EVERY_LITTLE_BIT_COUNTS: 'CommonBuffId' = 345359 + LANDLORD_TENANT_FOR_RENT_SIGN_RUMINATE: 'CommonBuffId' = 353654 + LANDLORD_TENANT_GOLD_EVENTS_HIDDEN: 'CommonBuffId' = 350268 + LANDLORD_TENANT_GOLD_SOCIAL_EVENT_COMPLETE: 'CommonBuffId' = 354135 + LANDLORD_TENANT_HANDINESS_MODIFIER_HIDDEN: 'CommonBuffId' = 359529 + LANDLORD_TENANT_INCITE_TENANT_REVOLT: 'CommonBuffId' = 355686 + LANDLORD_TENANT_JUNK_MAIL_FAIL: 'CommonBuffId' = 357042 + LANDLORD_TENANT_LANDLORD_HIDDEN: 'CommonBuffId' = 345358 + LANDLORD_TENANT_MAINTENANCE_SUCCESS_HIDDEN: 'CommonBuffId' = 350497 + LANDLORD_TENANT_MOVE_HOUSEHOLD_OWES_FEE_HIDDEN: 'CommonBuffId' = 359178 + LANDLORD_TENANT_NEIGHBOR_CHAT_COOLDOWN_HIDDEN: 'CommonBuffId' = 354024 + LANDLORD_TENANT_NOTORIOUS_NEGOTIATOR: 'CommonBuffId' = 345360 + LANDLORD_TENANT_PRAISE_HAVING_GREAT_NEIGHBORS: 'CommonBuffId' = 355687 + LANDLORD_TENANT_REPO_ANGRY: 'CommonBuffId' = 354535 + LANDLORD_TENANT_RULE_BROKEN_HIDDEN: 'CommonBuffId' = 350269 + LANDLORD_TENANT_SORT_JUNK_MAIL_KIDS: 'CommonBuffId' = 357258 + LANDLORD_TENANT_SUGGEST_HOSTING_CHARITY_EVENT: 'CommonBuffId' = 355688 + LANDLORD_TENANT_TENANT_HIDDEN: 'CommonBuffId' = 358087 + LANDLORD_TENANT_WORTH_A_TRY: 'CommonBuffId' = 345361 + LARGE_SLEEP_DESIRE: 'CommonBuffId' = 8904 + LAUNDRY_CLEAN: 'CommonBuffId' = 176286 + LAUNDRY_DAMP: 'CommonBuffId' = 176291 + LAUNDRY_DIZZY: 'CommonBuffId' = 178389 + LAUNDRY_DRY: 'CommonBuffId' = 176290 + LAUNDRY_FILTHY: 'CommonBuffId' = 176293 + LAUNDRY_FRAGRANT: 'CommonBuffId' = 178523 + LAUNDRY_GRUNGY: 'CommonBuffId' = 176292 + LAUNDRY_PRISTINE: 'CommonBuffId' = 176287 + LAUNDRY_RANK: 'CommonBuffId' = 178525 + LAUNDRY_SOAKED: 'CommonBuffId' = 178524 + LAUNDRY_TODDLER_DAMP_DIRTY: 'CommonBuffId' = 178410 + LAUNDRY_USED: 'CommonBuffId' = 176289 + LAUNDRY_WARM: 'CommonBuffId' = 178522 + LAUNDRY_WASH_TUB_WASHED_OUT_ARMS: 'CommonBuffId' = 178412 + LAW_BLABBERMOUTH: 'CommonBuffId' = 228579 + LAW_IMPARTER_OF_KNOWLEDGE: 'CommonBuffId' = 228581 + LAW_JUDGE_HAS_SPOKEN: 'CommonBuffId' = 228584 + LAW_REPRESENT: 'CommonBuffId' = 228173 + LAW_UNAPPOINTED: 'CommonBuffId' = 228175 + LEAVE_POOL: 'CommonBuffId' = 106168 + LEAVE_WORK_BORED: 'CommonBuffId' = 23879 + LEAVE_WORK_EMBARRASSED: 'CommonBuffId' = 23880 + LEAVE_WORK_STRESSED: 'CommonBuffId' = 23905 + LEAVE_WORK_UNCOMFORTABLE: 'CommonBuffId' = 23910 + LECTURE_GRADES_EMBARRASSED: 'CommonBuffId' = 98975 + LECTURE_RESPONSIBILITIES_ANGRY: 'CommonBuffId' = 99231 + LIFESTYLES_ADRENALINE_SEEKER_AT_DANGEROUS_CAREER: 'CommonBuffId' = 249874 + LIFESTYLES_ADRENALINE_SEEKER_AT_EXCITING_VENUE: 'CommonBuffId' = 253510 + LIFESTYLES_ADRENALINE_SEEKER_AT_MUNDANE_CAREER: 'CommonBuffId' = 250383 + LIFESTYLES_ADRENALINE_SEEKER_AT_MUNDANE_VENUE: 'CommonBuffId' = 253140 + LIFESTYLES_ADRENALINE_SEEKER_BORED: 'CommonBuffId' = 250387 + LIFESTYLES_ADRENALINE_SEEKER_CONFIDENT: 'CommonBuffId' = 250385 + LIFESTYLES_ADRENALINE_SEEKER_DANGEROUS_WEATHER_COOLDOWN: 'CommonBuffId' = 253343 + LIFESTYLES_ADRENALINE_SEEKER_EXCITED_AT_FIRE: 'CommonBuffId' = 253200 + LIFESTYLES_ADRENALINE_SEEKER_FUN_GAIN: 'CommonBuffId' = 250384 + LIFESTYLES_ADRENALINE_SEEKER_MUNDANE_INTERACTIONS_FUN_LOSS: 'CommonBuffId' = 254080 + LIFESTYLES_ADRENALINE_SEEKER_THRILL_SEEKING_INTERACTIONS_FUN_GAIN: 'CommonBuffId' = 254079 + LIFESTYLES_CAN_UNLOCK_LIFESTYLES: 'CommonBuffId' = 246488 + LIFESTYLES_CLOSE_KNIT_LOST_A_FRIEND: 'CommonBuffId' = 248776 + LIFESTYLES_CLOSE_KNIT_NEW_FRIEND_TOO_MANY_FRIENDS: 'CommonBuffId' = 248647 + LIFESTYLES_COFFEE_FANATIC_DRANK_COFFEE: 'CommonBuffId' = 246571 + LIFESTYLES_COFFEE_FANATIC_NEED_MORE_COFFEE: 'CommonBuffId' = 246521 + LIFESTYLES_COFFEE_FANATIC_WAKES_UP: 'CommonBuffId' = 246560 + LIFESTYLES_DISLIKED_ENERGETIC: 'CommonBuffId' = 248176 + LIFESTYLES_DISLIKED_ENERGETIC_CONFLICT_OVERRIDE: 'CommonBuffId' = 248219 + LIFESTYLES_DISLIKED_SEDENTARY: 'CommonBuffId' = 248295 + LIFESTYLES_DISLIKED_SEDENTARY_CONFLICT_OVERRIDE: 'CommonBuffId' = 248301 + LIFESTYLES_DISLIKED_TECHNOPHOBE: 'CommonBuffId' = 249090 + LIFESTYLES_DISLIKED_TECHNOPHOBE_CONFLICT_OVERRIDE: 'CommonBuffId' = 249425 + LIFESTYLES_ENERGETIC_AT_ENERGETIC_CAREER: 'CommonBuffId' = 248756 + LIFESTYLES_ENERGETIC_AT_SEDENTARY_CAREER: 'CommonBuffId' = 248757 + LIFESTYLES_ENERGETIC_ENERGETIC_INTERACTIONS_FUN_GAIN: 'CommonBuffId' = 249913 + LIFESTYLES_ENERGETIC_NEGLECT_LIFESTYLE_00: 'CommonBuffId' = 250606 + LIFESTYLES_ENERGETIC_SEDENTARY_INTERACTIONS_FUN_LOSS: 'CommonBuffId' = 249914 + LIFESTYLES_ENERGETIC_SEDENTARY_POSTURE_FUN_LOSS: 'CommonBuffId' = 250612 + LIFESTYLES_FREQUENT_TRAVELER_CAN_ASK_ABOUT_HOME_REGION: 'CommonBuffId' = 254335 + LIFESTYLES_FREQUENT_TRAVELER_MET_LOCAL: 'CommonBuffId' = 246621 + LIFESTYLES_FREQUENT_TRAVELER_POST_VACATION_CONFIDENT: 'CommonBuffId' = 246393 + LIFESTYLES_FREQUENT_TRAVELER_POST_VACATION_ENERGIZED: 'CommonBuffId' = 246398 + LIFESTYLES_FREQUENT_TRAVELER_POST_VACATION_HAPPY: 'CommonBuffId' = 246397 + LIFESTYLES_FREQUENT_TRAVELER_POST_VACATION_INSPIRED: 'CommonBuffId' = 246396 + LIFESTYLES_FREQUENT_TRAVELER_REGION_TOURIST_NO_VACATION: 'CommonBuffId' = 246350 + LIFESTYLES_FREQUENT_TRAVELER_REGION_TOURIST_VACATION: 'CommonBuffId' = 246391 + LIFESTYLES_FREQUENT_TRAVELER_SHARE_TRAVEL_STORIES_ACTOR: 'CommonBuffId' = 252893 + LIFESTYLES_FREQUENT_TRAVELER_SHARE_TRAVEL_STORIES_LISTENER: 'CommonBuffId' = 252894 + LIFESTYLES_FREQUENT_TRAVELER_VACATION_PROGRESS_COOLDOWN: 'CommonBuffId' = 250138 + LIFESTYLES_FREQUENT_TRAVELER_VISIT_PROGRESS_REGION: 'CommonBuffId' = 246414 + LIFESTYLES_FREQUENT_TRAVELER_VISIT_PROGRESS_REGION_CAFE: 'CommonBuffId' = 246626 + LIFESTYLES_FREQUENT_TRAVELER_VISIT_REGION_COOLDOWN: 'CommonBuffId' = 254070 + LIFESTYLES_HAS_LIFESTYLE_ADRENALINE_SEEKER: 'CommonBuffId' = 248834 + LIFESTYLES_HAS_LIFESTYLE_ENERGETIC: 'CommonBuffId' = 248159 + LIFESTYLES_HAS_LIFESTYLE_FREQUENT_TRAVELER: 'CommonBuffId' = 246593 + LIFESTYLES_HAS_LIFESTYLE_HEALTH_FOOD_NUT: 'CommonBuffId' = 247606 + LIFESTYLES_HAS_LIFESTYLE_INDOORSY: 'CommonBuffId' = 248835 + LIFESTYLES_HAS_LIFESTYLE_JUNK_FOOD_DEVOURER: 'CommonBuffId' = 247607 + LIFESTYLES_HAS_LIFESTYLE_OUTDOORSY: 'CommonBuffId' = 248836 + LIFESTYLES_HAS_LIFESTYLE_SEDENTARY: 'CommonBuffId' = 248135 + LIFESTYLES_HAS_LIFESTYLE_WORKAHOLIC: 'CommonBuffId' = 245844 + LIFESTYLES_HAS_TRAIT_CLOSE_KNIT: 'CommonBuffId' = 253960 + LIFESTYLES_HAS_TRAIT_COFFEE_FANATIC: 'CommonBuffId' = 246516 + LIFESTYLES_HAS_TRAIT_HUNGRY_FOR_LOVE: 'CommonBuffId' = 253963 + LIFESTYLES_HAS_TRAIT_NETWORKER: 'CommonBuffId' = 253961 + LIFESTYLES_HAS_TRAIT_SINGLE_AND_LOVING_IT: 'CommonBuffId' = 253962 + LIFESTYLES_HAS_TRAIT_TECHIE: 'CommonBuffId' = 253956 + LIFESTYLES_HAS_TRAIT_TECHNOPHOBE: 'CommonBuffId' = 253957 + LIFESTYLES_HUNGRY_FOR_LOVE_CONSUMING_ROMANTIC_MEDIA: 'CommonBuffId' = 251020 + LIFESTYLES_HUNGRY_FOR_LOVE_FLIRTY_CONVERSATION: 'CommonBuffId' = 250756 + LIFESTYLES_HUNGRY_FOR_LOVE_IN_A_RELATIONSHIP: 'CommonBuffId' = 250757 + LIFESTYLES_HUNGRY_FOR_LOVE_NEAR_PARTNER: 'CommonBuffId' = 254104 + LIFESTYLES_HUNGRY_FOR_LOVE_NEAR_PARTNER_COOLDOWN: 'CommonBuffId' = 254110 + LIFESTYLES_HUNGRY_FOR_LOVE_NO_RELATIONSHIP: 'CommonBuffId' = 251261 + LIFESTYLES_HUNGRY_FOR_LOVE_ROMANTIC_MEDIA: 'CommonBuffId' = 251004 + LIFESTYLES_HUNGRY_FOR_LOVE_WAKE_UP_HAS_RELATIONSHIP: 'CommonBuffId' = 251075 + LIFESTYLES_INDOORSY_ANGRY_DOG_WALK: 'CommonBuffId' = 251967 + LIFESTYLES_INDOORSY_AT_OUTDOOR_CAREER: 'CommonBuffId' = 253609 + LIFESTYLES_INDOORSY_BORED: 'CommonBuffId' = 251319 + LIFESTYLES_INDOORSY_FINE: 'CommonBuffId' = 253142 + LIFESTYLES_INDOORSY_HAPPY: 'CommonBuffId' = 251318 + LIFESTYLES_INDOORSY_IM_INDOORS: 'CommonBuffId' = 251872 + LIFESTYLES_INDOORSY_IM_OUTDOORS: 'CommonBuffId' = 251873 + LIFESTYLES_INDOORSY_INDOORS_INTERACTIONS_FUN_GAIN: 'CommonBuffId' = 251874 + LIFESTYLES_INDOORSY_OUTDOORS_INTERACTIONS_FUN_LOSS: 'CommonBuffId' = 251875 + LIFESTYLES_LIKED_ENERGETIC: 'CommonBuffId' = 248318 + LIFESTYLES_LIKED_ENERGETIC_CONFLICT_OVERRIDE: 'CommonBuffId' = 248326 + LIFESTYLES_LIKED_INDOORSY_CONFLICT_OVERRIDE: 'CommonBuffId' = 253524 + LIFESTYLES_LIKED_TECHIE: 'CommonBuffId' = 249080 + LIFESTYLES_NEGLECT_ADRENALINE_SEEKER_LEVEL_1: 'CommonBuffId' = 250858 + LIFESTYLES_NEGLECT_ADRENALINE_SEEKER_LEVEL_2: 'CommonBuffId' = 250859 + LIFESTYLES_NEGLECT_CLOSE_KNIT_LEVEL_1: 'CommonBuffId' = 250547 + LIFESTYLES_NEGLECT_CLOSE_KNIT_LEVEL_2: 'CommonBuffId' = 250548 + LIFESTYLES_NEGLECT_COFFEE_FANATIC_LEVEL_1: 'CommonBuffId' = 246549 + LIFESTYLES_NEGLECT_COFFEE_FANATIC_LEVEL_2: 'CommonBuffId' = 247639 + LIFESTYLES_NEGLECT_ENERGETIC_CONFLICT_OVERRIDE: 'CommonBuffId' = 249151 + LIFESTYLES_NEGLECT_ENERGETIC_LEVEL_1: 'CommonBuffId' = 248573 + LIFESTYLES_NEGLECT_ENERGETIC_LEVEL_2: 'CommonBuffId' = 250601 + LIFESTYLES_NEGLECT_FOOD_HEALTH_NUT_LEVEL_1: 'CommonBuffId' = 250482 + LIFESTYLES_NEGLECT_FOOD_HEALTH_NUT_LEVEL_2: 'CommonBuffId' = 250483 + LIFESTYLES_NEGLECT_FOOD_JUNK_FOOD_LEVEL_1: 'CommonBuffId' = 250485 + LIFESTYLES_NEGLECT_FOOD_JUNK_FOOD_LEVEL_2: 'CommonBuffId' = 250484 + LIFESTYLES_NEGLECT_FREQUENT_TRAVELER_LEVEL_1: 'CommonBuffId' = 250352 + LIFESTYLES_NEGLECT_FREQUENT_TRAVELER_LEVEL_2: 'CommonBuffId' = 250356 + LIFESTYLES_NEGLECT_HUNGRY_FOR_LOVE_LEVEL_1: 'CommonBuffId' = 250670 + LIFESTYLES_NEGLECT_HUNGRY_FOR_LOVE_LEVEL_2: 'CommonBuffId' = 250669 + LIFESTYLES_NEGLECT_INDOORSY_LEVEL_1: 'CommonBuffId' = 250853 + LIFESTYLES_NEGLECT_INDOORSY_LEVEL_1_FINE_OVERRIDE: 'CommonBuffId' = 253639 + LIFESTYLES_NEGLECT_INDOORSY_LEVEL_2: 'CommonBuffId' = 250854 + LIFESTYLES_NEGLECT_INDOORSY_LEVEL_2_FINE_OVERRIDE: 'CommonBuffId' = 253640 + LIFESTYLES_NEGLECT_LEVEL_0_ADRENALINE_SEEKER: 'CommonBuffId' = 250841 + LIFESTYLES_NEGLECT_LEVEL_0_CLOSE_KNIT: 'CommonBuffId' = 250538 + LIFESTYLES_NEGLECT_LEVEL_0_COFFEE_FANATIC: 'CommonBuffId' = 252168 + LIFESTYLES_NEGLECT_LEVEL_0_FOOD_HEALTH_NUT: 'CommonBuffId' = 250480 + LIFESTYLES_NEGLECT_LEVEL_0_FOOD_JUNK_FOOD: 'CommonBuffId' = 250481 + LIFESTYLES_NEGLECT_LEVEL_0_FREQUENT_TRAVELER: 'CommonBuffId' = 250348 + LIFESTYLES_NEGLECT_LEVEL_0_HUNGRY_FOR_LOVE: 'CommonBuffId' = 250664 + LIFESTYLES_NEGLECT_LEVEL_0_INDOORSY: 'CommonBuffId' = 250842 + LIFESTYLES_NEGLECT_LEVEL_0_NETWORKER: 'CommonBuffId' = 250537 + LIFESTYLES_NEGLECT_LEVEL_0_NO_NEED_FOR_ROMANCE: 'CommonBuffId' = 250663 + LIFESTYLES_NEGLECT_LEVEL_0_OUTDOORSY: 'CommonBuffId' = 250843 + LIFESTYLES_NEGLECT_LEVEL_0_TECHIE: 'CommonBuffId' = 250535 + LIFESTYLES_NEGLECT_LEVEL_0_TECHNOPHOBE: 'CommonBuffId' = 250536 + LIFESTYLES_NEGLECT_LEVEL_0_WORKAHOLIC: 'CommonBuffId' = 250330 + LIFESTYLES_NEGLECT_NETWORKER_CONFLICT_OVERRIDE: 'CommonBuffId' = 250555 + LIFESTYLES_NEGLECT_NETWORKER_LEVEL_1: 'CommonBuffId' = 250550 + LIFESTYLES_NEGLECT_NETWORKER_LEVEL_2: 'CommonBuffId' = 250551 + LIFESTYLES_NEGLECT_NO_NEED_FOR_ROMANCE_CONFLICT_OVERRIDE: 'CommonBuffId' = 253861 + LIFESTYLES_NEGLECT_NO_NEED_FOR_ROMANCE_LEVEL_1: 'CommonBuffId' = 250666 + LIFESTYLES_NEGLECT_NO_NEED_FOR_ROMANCE_LEVEL_2: 'CommonBuffId' = 250667 + LIFESTYLES_NEGLECT_OUTDOORSY_LEVEL_1: 'CommonBuffId' = 250849 + LIFESTYLES_NEGLECT_OUTDOORSY_LEVEL_2: 'CommonBuffId' = 250852 + LIFESTYLES_NEGLECT_SEDENTARY_CONFLICT_OVERRIDE: 'CommonBuffId' = 249148 + LIFESTYLES_NEGLECT_SEDENTARY_LEVEL_1: 'CommonBuffId' = 248568 + LIFESTYLES_NEGLECT_SEDENTARY_LEVEL_2: 'CommonBuffId' = 250591 + LIFESTYLES_NEGLECT_TECHIE_LEVEL_1: 'CommonBuffId' = 250541 + LIFESTYLES_NEGLECT_TECHIE_LEVEL_2: 'CommonBuffId' = 250540 + LIFESTYLES_NEGLECT_TECHNOPHOBE_CONFLICT_OVERRIDE: 'CommonBuffId' = 250543 + LIFESTYLES_NEGLECT_TECHNOPHOBE_LEVEL_1: 'CommonBuffId' = 250544 + LIFESTYLES_NEGLECT_TECHNOPHOBE_LEVEL_2: 'CommonBuffId' = 250545 + LIFESTYLES_NEGLECT_WORKAHOLIC_LEVEL_1: 'CommonBuffId' = 250061 + LIFESTYLES_NEGLECT_WORKAHOLIC_LEVEL_2: 'CommonBuffId' = 250062 + LIFESTYLES_NEGLECT_WORKAHOLIC_OVERRIDE: 'CommonBuffId' = 250069 + LIFESTYLES_NETWORKER_AMONG_FRIENDS: 'CommonBuffId' = 248622 + LIFESTYLES_NETWORKER_AMONG_FRIENDS_OVERRIDE: 'CommonBuffId' = 248638 + LIFESTYLES_NETWORKER_DESOLATE_OVERRIDE: 'CommonBuffId' = 248670 + LIFESTYLES_NETWORKER_LONELY_OVERRIDE: 'CommonBuffId' = 248669 + LIFESTYLES_NETWORKER_LOST_A_FRIEND: 'CommonBuffId' = 248777 + LIFESTYLES_NETWORKER_NEW_FRIEND: 'CommonBuffId' = 248660 + LIFESTYLES_NO_NEED_FOR_ROMANCE_CONSUMING_ROMANTIC_MEDIA: 'CommonBuffId' = 251263 + LIFESTYLES_NO_NEED_FOR_ROMANCE_FLIRTY_CONVERSATION: 'CommonBuffId' = 251456 + LIFESTYLES_NO_NEED_FOR_ROMANCE_HAS_RELATIONSHIP: 'CommonBuffId' = 251260 + LIFESTYLES_NO_NEED_FOR_ROMANCE_NO_RELATIONSHIP: 'CommonBuffId' = 251258 + LIFESTYLES_NO_NEED_FOR_ROMANCE_ROMANTIC_MEDIA: 'CommonBuffId' = 251005 + LIFESTYLES_NO_NEED_FOR_ROMANCE_WAKEUP_NO_RELATIONSHIP: 'CommonBuffId' = 251195 + LIFESTYLES_NO_NEED_FOR_ROMANCE_WAKEUP_NO_RELATIONSHIP_CONFLICT_OVERRIDE: 'CommonBuffId' = 251199 + LIFESTYLES_OUTDOORSY_AT_OUTDOORSY_CAREER: 'CommonBuffId' = 252963 + LIFESTYLES_OUTDOORSY_BORED: 'CommonBuffId' = 251323 + LIFESTYLES_OUTDOORSY_ENERGIZED_DOG_WALK: 'CommonBuffId' = 251907 + LIFESTYLES_OUTDOORSY_HAPPY: 'CommonBuffId' = 251322 + LIFESTYLES_OUTDOORSY_HAPPY_DOG_TRICKS: 'CommonBuffId' = 251908 + LIFESTYLES_OUTDOORSY_IM_INDOORS: 'CommonBuffId' = 251864 + LIFESTYLES_OUTDOORSY_IM_OUTDOORS: 'CommonBuffId' = 251863 + LIFESTYLES_OUTDOORSY_INDOORS_INTERACTIONS_FUN_LOSS: 'CommonBuffId' = 251871 + LIFESTYLES_OUTDOORSY_OUTDOORS_INTERACTIONS_FUN_GAIN: 'CommonBuffId' = 251870 + LIFESTYLES_OUTDOORSY_STRESSED_INDOOR_WORK: 'CommonBuffId' = 251909 + LIFESTYLES_OUTDOORSY_STRESSED_INDOOR_WORK_COOLDOWN: 'CommonBuffId' = 253637 + LIFESTYLES_ROMANCE_PERFORMED_ROMANTIC_INTERACTION: 'CommonBuffId' = 251257 + LIFESTYLES_ROMANCE_ROMANTIC_MEDIA_TIMER: 'CommonBuffId' = 250973 + LIFESTYLES_ROMANCE_WAKE_UP_COOLDOWN: 'CommonBuffId' = 254177 + LIFESTYLES_SEDENTARY_AT_ENERGETIC_CAREER: 'CommonBuffId' = 248755 + LIFESTYLES_SEDENTARY_AT_SEDENTARY_CAREER: 'CommonBuffId' = 248754 + LIFESTYLES_SEDENTARY_ENERGETIC_INTERACTIONS_FUN_LOSS: 'CommonBuffId' = 249916 + LIFESTYLES_SEDENTARY_NEGLECT_LIFESTYLE_00: 'CommonBuffId' = 250599 + LIFESTYLES_SEDENTARY_SEATED: 'CommonBuffId' = 248558 + LIFESTYLES_SEDENTARY_SEATED_CONFLICT_OVERRIDE: 'CommonBuffId' = 249147 + LIFESTYLES_SEDENTARY_SEDENTARY_INTERACTIONS_FUNGAIN: 'CommonBuffId' = 249915 + LIFESTYLES_SEDENTARY_SEDENTARY_POSTURE_FUNGAIN: 'CommonBuffId' = 250617 + LIFESTYLES_SHARE_LIFESTYLE_TIPS_NEGATIVE: 'CommonBuffId' = 249196 + LIFESTYLES_SHARE_LIFESTYLE_TIPS_NEGATIVE_TARGET: 'CommonBuffId' = 253756 + LIFESTYLES_SHARE_LIFESTYLE_TIPS_POSITIVE: 'CommonBuffId' = 249195 + LIFESTYLES_SHARE_LIFESTYLE_TIPS_POSITIVE_TARGET: 'CommonBuffId' = 253754 + LIFESTYLES_SINGLE_AND_LOVING_IT_GOT_ENGAGED: 'CommonBuffId' = 254098 + LIFESTYLES_SINGLE_AND_LOVING_IT_GOT_ENGAGED_CONFLICT: 'CommonBuffId' = 254100 + LIFESTYLES_SINGLE_AND_LOVING_IT_HA_DWEDDING: 'CommonBuffId' = 254099 + LIFESTYLES_SINGLE_AND_LOVING_IT_HA_DWEDDING_CONFLICT: 'CommonBuffId' = 254101 + LIFESTYLES_SINGLE_AND_LOVING_IT_NEW_PARTNER: 'CommonBuffId' = 254097 + LIFESTYLES_SINGLE_AND_LOVING_IT_NEW_PARTNER_CONFLICT: 'CommonBuffId' = 254102 + LIFESTYLES_SLEEP_TIMER: 'CommonBuffId' = 251073 + LIFESTYLES_TECHIE_AT_TECH_CAREER: 'CommonBuffId' = 247925 + LIFESTYLES_TECHIE_CONVERSATION_TARGET_SIM_BOT: 'CommonBuffId' = 247899 + LIFESTYLES_TECHIE_LAUNDRY: 'CommonBuffId' = 254125 + LIFESTYLES_TECHIE_NO_POWER_LOT: 'CommonBuffId' = 251701 + LIFESTYLES_TECHIE_ON_OFF_THE_GRID_LOT: 'CommonBuffId' = 249563 + LIFESTYLES_TECHIE_OVERCLOCKED_COMPUTER: 'CommonBuffId' = 249560 + LIFESTYLES_TECHIE_OVERCLOCKED_VIDEO_GAME: 'CommonBuffId' = 249559 + LIFESTYLES_TECHIE_REPAIRING_ELECTRONICS: 'CommonBuffId' = 247726 + LIFESTYLES_TECHIE_SAW_BROKEN_ELECTRONICS: 'CommonBuffId' = 246957 + LIFESTYLES_TECHIE_SIM_BOT: 'CommonBuffId' = 247810 + LIFESTYLES_TECHIE_USING_ELECTRONICS: 'CommonBuffId' = 249421 + LIFESTYLES_TECHNOPHOBE_AT_TECH_CAREER: 'CommonBuffId' = 247926 + LIFESTYLES_TECHNOPHOBE_CONVERSATION_TARGET_SIM_BOT: 'CommonBuffId' = 247900 + LIFESTYLES_TECHNOPHOBE_LAUNDRY: 'CommonBuffId' = 254123 + LIFESTYLES_TECHNOPHOBE_NEED_TO_GAME_OVERRIDE: 'CommonBuffId' = 247910 + LIFESTYLES_TECHNOPHOBE_NO_POWER_LOT: 'CommonBuffId' = 251702 + LIFESTYLES_TECHNOPHOBE_OFF_THE_GRID_VISIT_COOLDOWN: 'CommonBuffId' = 249349 + LIFESTYLES_TECHNOPHOBE_ON_OFF_THE_GRID_LOT: 'CommonBuffId' = 248882 + LIFESTYLES_TECHNOPHOBE_REPAIRING_ELECTRONICS: 'CommonBuffId' = 247727 + LIFESTYLES_TECHNOPHOBE_SAW_BROKEN_ELECTRONICS: 'CommonBuffId' = 246955 + LIFESTYLES_TECHNOPHOBE_SIM_BOT: 'CommonBuffId' = 247811 + LIFESTYLES_TECHNOPHOBE_USING_ELECTRONICS: 'CommonBuffId' = 249422 + LIFESTYLES_WORKAHOLIC_AT_WORK: 'CommonBuffId' = 245827 + LIFESTYLES_WORKAHOLIC_AT_WORK_CONFLICT_OVERRIDE: 'CommonBuffId' = 246110 + LIFESTYLES_WORKAHOLIC_DEMAND_PROMOTION_COOLDOWN: 'CommonBuffId' = 250244 + LIFESTYLES_WORKAHOLIC_DEMAND_PROMOTION_FAIL: 'CommonBuffId' = 252176 + LIFESTYLES_WORKAHOLIC_LOST_JOB: 'CommonBuffId' = 246069 + LIFESTYLES_WORKAHOLIC_LOST_JOB_CONFLICT_OVERRIDE: 'CommonBuffId' = 246073 + LIFESTYLES_WORKAHOLIC_WORK_OFF_HOURS_LAZY: 'CommonBuffId' = 250085 + LIFESTYLES_WORKAHOLIC_WORK_OFF_HOURS_LAZY_POST_WORK: 'CommonBuffId' = 250153 + LIFE_MILESTONE_ABDUCTED_BY_ALIENS_HERE_ENERGIZED: 'CommonBuffId' = 306142 + LIFE_MILESTONE_ABDUCTED_BY_ALIENS_HERE_SCARED: 'CommonBuffId' = 306143 + LIFE_MILESTONE_BABY_KEEPSAKE_BIG_KID: 'CommonBuffId' = 306156 + LIFE_MILESTONE_BABY_KEEPSAKE_HAPPY: 'CommonBuffId' = 311463 + LIFE_MILESTONE_BABY_KEEPSAKE_MY_BABY: 'CommonBuffId' = 306157 + LIFE_MILESTONE_BABY_KEEPSAKE_SAD: 'CommonBuffId' = 311461 + LIFE_MILESTONE_BABY_KEEPSAKE_WHY_DID_I_KEEP_THIS: 'CommonBuffId' = 306158 + LIFE_MILESTONE_CAUGHT_CHEATER_HERE_ANGRY: 'CommonBuffId' = 306140 + LIFE_MILESTONE_CAUGHT_CHEATER_HERE_SAD: 'CommonBuffId' = 306139 + LIFE_MILESTONE_CHILD_DRAWINGS_CRINGE_KEEPSAKE: 'CommonBuffId' = 306150 + LIFE_MILESTONE_CHILD_DRAWINGS_OK_I_GUESS: 'CommonBuffId' = 306149 + LIFE_MILESTONE_CHILD_DRAWINGS_TERRIBLE_REMINDER: 'CommonBuffId' = 306151 + LIFE_MILESTONE_CHILD_DRAWINGS_WHAT_IMAGINATION_INSPIRED: 'CommonBuffId' = 306153 + LIFE_MILESTONE_CHILD_DRAWINGS_WHAT_IMAGINATION_PARENT: 'CommonBuffId' = 306152 + LIFE_MILESTONE_CHILD_DRAWINGS_WHAT_IMAGINATION_PLAYFUL: 'CommonBuffId' = 306154 + LIFE_MILESTONE_CHILD_DRAWINGS_WORK_ON_DISPLAY: 'CommonBuffId' = 306378 + LIFE_MILESTONE_ENGAGMENT_REJECTED_HERE: 'CommonBuffId' = 306138 + LIFE_MILESTONE_FIRST_BLADDER_FAILHERE: 'CommonBuffId' = 306144 + LIFE_MILESTONE_FIRST_FIRE_HERE: 'CommonBuffId' = 306145 + LIFE_MILESTONE_FIRST_FIRE_HERE_FIRE_OBJECT: 'CommonBuffId' = 315259 + LIFE_MILESTONE_FIRST_PROMOTION: 'CommonBuffId' = 306147 + LIFE_MILESTONE_GOT_MARRIED_HERE_POSITIVE: 'CommonBuffId' = 306146 + LIFE_MILESTONE_HIDDEN_CAN_GET_LOT_BASED_BUFF: 'CommonBuffId' = 315076 + LIFE_MILESTONE_HIDDEN_CAREER_MAX_LEVEL: 'CommonBuffId' = 311611 + LIFE_MILESTONE_HIDDEN_CAREER_MAX_LEVEL_AFTER_SCHOOL_ACTIVITY: 'CommonBuffId' = 311612 + LIFE_MILESTONE_HIDDEN_JUST_BECAME_NON_OCCULT: 'CommonBuffId' = 333236 + LIFE_MILESTONE_HIDDEN_JUST_HAD_BIRTHDAY: 'CommonBuffId' = 332971 + LIFE_MILESTONE_HIDDEN_JUST_HAD_SELF_DISCOVERY: 'CommonBuffId' = 313002 + LIFE_MILESTONE_HIDDEN_JUST_RESURRECTED_NO_BIT: 'CommonBuffId' = 329409 + LIFE_MILESTONE_HIDDEN_JUST_SURVIVED_HAUNTED_HOUSE: 'CommonBuffId' = 313485 + LIFE_MILESTONE_HIDDEN_JUST_WON_VILLAGE_FAIR: 'CommonBuffId' = 313486 + LIFE_MILESTONE_HIDDEN_RECENT_FIRST_FIRE: 'CommonBuffId' = 315083 + LIFE_MILESTONE_HIDDEN_RECENT_FIRST_PROMOTION: 'CommonBuffId' = 318750 + LIFE_MILESTONE_HIDDEN_RECENT_STRUCK_BY_LIGHTNING: 'CommonBuffId' = 315084 + LIFE_MILESTONE_HIDDEN_REFLECTION_COOLDOWN: 'CommonBuffId' = 311914 + LIFE_MILESTONE_LET_ME_FORGET: 'CommonBuffId' = 311913 + LIFE_MILESTONE_MANY_ENEMIES_NEGATIVE: 'CommonBuffId' = 311893 + LIFE_MILESTONE_MANY_ENEMIES_POSITIVE: 'CommonBuffId' = 311892 + LIFE_MILESTONE_MANY_FRIENDS: 'CommonBuffId' = 311894 + LIFE_MILESTONE_MARRIAGE_CERTIFICATE_HAPPY: 'CommonBuffId' = 306160 + LIFE_MILESTONE_MARRIAGE_CERTIFICATE_MARRIAGE_OF_MISTAKES: 'CommonBuffId' = 306163 + LIFE_MILESTONE_MARRIAGE_CERTIFICATE_NOT_MEANT_FOR_MARRIAGE: 'CommonBuffId' = 306162 + LIFE_MILESTONE_MARRIAGE_CERTIFICATE_TENSE: 'CommonBuffId' = 306161 + LIFE_MILESTONE_MEMORABILIA_OF_DEAD_SIM: 'CommonBuffId' = 335427 + LIFE_MILESTONE_NEXT_ADVENTURE: 'CommonBuffId' = 311896 + LIFE_MILESTONE_PRO_PROFESSIONAL: 'CommonBuffId' = 311910 + LIFE_MILESTONE_RESILIENT: 'CommonBuffId' = 311911 + LIFE_MILESTONE_REVIVED: 'CommonBuffId' = 311895 + LIFE_MILESTONE_SMOOTH_SAILING: 'CommonBuffId' = 311891 + LIFE_MILESTONE_STRUCK_BY_LIGHTNING_HERE: 'CommonBuffId' = 306141 + LIFE_MILESTONE_TOOTH_CERTIFICATE_ANGRY: 'CommonBuffId' = 312234 + LIFE_MILESTONE_TOOTH_CERTIFICATE_PLAYFUL: 'CommonBuffId' = 312177 + LIFE_MILESTONE_UNDER_ACHIEVING: 'CommonBuffId' = 311912 + LIFE_MILESTONE_UPS_AND_DOWNS: 'CommonBuffId' = 311889 + LIFE_SKILLS_AUTONOMY_CONFLICT_RESOLUTION_NEGATIVE: 'CommonBuffId' = 163773 + LIFE_SKILLS_AUTONOMY_CONFLICT_RESOLUTION_POSITIVE: 'CommonBuffId' = 163774 + LIFE_SKILLS_AUTONOMY_CONFLICT_RESOLUTION_VERY_NEGATIVE: 'CommonBuffId' = 168261 + LIFE_SKILLS_AUTONOMY_CONFLICT_RESOLUTION_VERY_POSITIVE: 'CommonBuffId' = 168262 + LIFE_SKILLS_AUTONOMY_EMOTIONAL_CONTROL_NEGATIVE: 'CommonBuffId' = 163776 + LIFE_SKILLS_AUTONOMY_EMOTIONAL_CONTROL_POSITIVE: 'CommonBuffId' = 163775 + LIFE_SKILLS_AUTONOMY_EMOTIONAL_CONTROL_VERY_NEGATIVE: 'CommonBuffId' = 168263 + LIFE_SKILLS_AUTONOMY_EMOTIONAL_CONTROL_VERY_POSITIVE: 'CommonBuffId' = 168264 + LIFE_SKILLS_AUTONOMY_EMPATHY_NEGATIVE: 'CommonBuffId' = 163778 + LIFE_SKILLS_AUTONOMY_EMPATHY_POSITIVE: 'CommonBuffId' = 163777 + LIFE_SKILLS_AUTONOMY_EMPATHY_VERY_NEGATIVE: 'CommonBuffId' = 168265 + LIFE_SKILLS_AUTONOMY_EMPATHY_VERY_POSITIVE: 'CommonBuffId' = 168266 + LIFE_SKILLS_AUTONOMY_MANNERS_NEGATIVE: 'CommonBuffId' = 163780 + LIFE_SKILLS_AUTONOMY_MANNERS_POSITIVE: 'CommonBuffId' = 163779 + LIFE_SKILLS_AUTONOMY_MANNERS_VERY_NEGATIVE: 'CommonBuffId' = 168267 + LIFE_SKILLS_AUTONOMY_MANNERS_VERY_POSITIVE: 'CommonBuffId' = 168268 + LIFE_SKILLS_AUTONOMY_RESPONSIBILITY_NEGATIVE: 'CommonBuffId' = 163782 + LIFE_SKILLS_AUTONOMY_RESPONSIBILITY_POSITIVE: 'CommonBuffId' = 163781 + LIFE_SKILLS_AUTONOMY_RESPONSIBILITY_VERY_NEGATIVE: 'CommonBuffId' = 168270 + LIFE_SKILLS_AUTONOMY_RESPONSIBILITY_VERY_POSITIVE: 'CommonBuffId' = 168271 + LIGHTHOUSE_CONCEIVED_HERE_HAPPY: 'CommonBuffId' = 172432 + LIGHTHOUSE_HAPPY: 'CommonBuffId' = 176176 + LISTENING_DEVICE_BUGGED: 'CommonBuffId' = 202322 + LIVESTOCK_PEN_WOOHOO_EMBARRASSED: 'CommonBuffId' = 263151 + LIVESTOCK_PEN_WOOHOO_UNCOMFORTABLE: 'CommonBuffId' = 263159 + LIVING_STATUE_BUSKER_AT_PO_COOLDOWN: 'CommonBuffId' = 155689 + LIVING_STATUE_BUSKER_CAN_BUSK_HIDDEN_BODY: 'CommonBuffId' = 144139 + LIVING_STATUE_BUSKER_CAN_BUSK_HIDDEN_HEAD: 'CommonBuffId' = 144171 + LIVING_VICARIOUSLY_SKILL_ADULT_BARTENDING: 'CommonBuffId' = 30183 + LIVING_VICARIOUSLY_SKILL_ADULT_BODYBUILDING: 'CommonBuffId' = 30184 + LIVING_VICARIOUSLY_SKILL_ADULT_CHARISMA: 'CommonBuffId' = 30182 + LIVING_VICARIOUSLY_SKILL_ADULT_COMEDY: 'CommonBuffId' = 30185 + LIVING_VICARIOUSLY_SKILL_ADULT_GARDENING: 'CommonBuffId' = 30186 + LIVING_VICARIOUSLY_SKILL_ADULT_GOURMET_COOKING: 'CommonBuffId' = 30187 + LIVING_VICARIOUSLY_SKILL_ADULT_GUITAR: 'CommonBuffId' = 30188 + LIVING_VICARIOUSLY_SKILL_ADULT_HACKING: 'CommonBuffId' = 30189 + LIVING_VICARIOUSLY_SKILL_ADULT_HANDINESS: 'CommonBuffId' = 30190 + LIVING_VICARIOUSLY_SKILL_ADULT_HOME_STYLE_COOKING: 'CommonBuffId' = 30191 + LIVING_VICARIOUSLY_SKILL_ADULT_LOGIC: 'CommonBuffId' = 30192 + LIVING_VICARIOUSLY_SKILL_ADULT_MISCHIEF: 'CommonBuffId' = 30193 + LIVING_VICARIOUSLY_SKILL_ADULT_PAINTING: 'CommonBuffId' = 30194 + LIVING_VICARIOUSLY_SKILL_ADULT_PIANO: 'CommonBuffId' = 30195 + LIVING_VICARIOUSLY_SKILL_ADULT_ROCKET_SCIENCE: 'CommonBuffId' = 30197 + LIVING_VICARIOUSLY_SKILL_ADULT_VIDEO_GAMING: 'CommonBuffId' = 30199 + LIVING_VICARIOUSLY_SKILL_ADULT_VIOLIN: 'CommonBuffId' = 30200 + LIVING_VICARIOUSLY_SKILL_ADULT_WRITING: 'CommonBuffId' = 30201 + LIVING_VICARIOUSLY_SKILL_CHILD_CREATIVITY: 'CommonBuffId' = 29852 + LIVING_VICARIOUSLY_SKILL_CHILD_LOGIC: 'CommonBuffId' = 29858 + LIVING_VICARIOUSLY_SKILL_CHILD_MOTOR: 'CommonBuffId' = 29859 + LIVING_VICARIOUSLY_SKILL_CHILD_SOCIAL: 'CommonBuffId' = 29860 + LOCAL_CULTURE_SKILL_FOOD_TOLERANCE: 'CommonBuffId' = 176930 + LOOT_CHARITY_DRAMA_NODE: 'CommonBuffId' = 198064 + LORE_RING_EP16_RING_CONFIDENT: 'CommonBuffId' = 366261 + LORE_RING_EP16_RING_HAZE: 'CommonBuffId' = 366262 + LOSE_TEETH_CURRENTLY_AGING_UP: 'CommonBuffId' = 340261 + LOSE_TEETH_FIX_TOOTH_COOLDOWN: 'CommonBuffId' = 332335 + LOSE_TEETH_MISADVENTURE_DELAY: 'CommonBuffId' = 315029 + LOSE_TEETH_MISSING_TOOTH_APPEARANCE_MODIFIER: 'CommonBuffId' = 312134 + LOSE_TEETH_MISSING_TOOTH_BED_SWIPE: 'CommonBuffId' = 327987 + LOSE_TEETH_TIMER: 'CommonBuffId' = 312133 + LOSE_TEETH_TOOTHTASTROPHE: 'CommonBuffId' = 314781 + LOSE_TEETH_TOOTH_FAIRY: 'CommonBuffId' = 314778 + LOSE_TEETH_TOOTH_FAIRY_COOLDOWN: 'CommonBuffId' = 314866 + LOSE_TEETH_TOOTH_FAIRY_LOCKOUT: 'CommonBuffId' = 334268 + LOSE_TEETH_TOOTH_YOINKED: 'CommonBuffId' = 314782 + LOSE_TEETH_WIGGLE_TOOTH: 'CommonBuffId' = 314783 + LOST_A_GAME: 'CommonBuffId' = 273092 + LOST_FIGHT: 'CommonBuffId' = 12464 + LOST_FIGHT_BEAR: 'CommonBuffId' = 108103 + LOST_FIGHT_VILLAIN: 'CommonBuffId' = 99535 + LOTUS_ENERGIZED: 'CommonBuffId' = 346129 + LOT_MODS_APARTMENT_PRO_CHEFS_KITCHEN: 'CommonBuffId' = 140092 + LOT_MODS_APARTMENT_PRO_GREAT_ATMOSPHERE: 'CommonBuffId' = 135662 + LOT_MODS_APARTMENT_PRO_GREAT_ATMOSPHERE_VISIBLE: 'CommonBuffId' = 141963 + LOT_MODS_APARTMENT_PRO_GREAT_VIEW: 'CommonBuffId' = 135667 + LOT_MODS_APARTMENT_PRO_HISTORICAL: 'CommonBuffId' = 135668 + LOT_MODS_APARTMENT_PRO_HOME_STUDIO: 'CommonBuffId' = 135661 + LOT_MODS_APARTMENT_PRO_NEAR_GOOD_SCHOOLS_VISIBLE: 'CommonBuffId' = 141965 + LOT_MODS_BASE_GAME_BRACING_BREEZES_HIDDEN: 'CommonBuffId' = 145503 + LOT_MODS_BASE_GAME_BRACING_BREEZES_VISIBLE: 'CommonBuffId' = 145530 + LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_BIRTHDAY_SUIT_VISIBLE: 'CommonBuffId' = 206402 + LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_BURNT_BITS_VISIBLE: 'CommonBuffId' = 206521 + LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_CHILD_HOUSEHOLD_HIDDEN: 'CommonBuffId' = 207151 + LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_DARING_DINER_CONFIDENT_VISIBLE: 'CommonBuffId' = 212028 + LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_DARING_DINER_ENERGIZED_VISIBLE: 'CommonBuffId' = 212029 + LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_DARING_DINER_FLIRTY_VISIBLE: 'CommonBuffId' = 212026 + LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_DARING_DINER_PLAYFUL_VISIBLE: 'CommonBuffId' = 212030 + LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_EH_WHY_NOT_VISIBLE: 'CommonBuffId' = 211965 + LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_EWWWWW_1_VISIBLE: 'CommonBuffId' = 207628 + LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_EWWWWW_2_VISIBLE: 'CommonBuffId' = 211920 + LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_GETTING_BUFF_VISIBLE: 'CommonBuffId' = 212081 + LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_GET_NUDE_HIDDEN: 'CommonBuffId' = 206158 + LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_HAVE_SOME_DECENCY_1_VISIBLE: 'CommonBuffId' = 207623 + LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_HAVE_SOME_DECENCY_2_VISIBLE: 'CommonBuffId' = 211925 + LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_IN_MY_ELEMENT_VISIBLE: 'CommonBuffId' = 212116 + LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_IN_THE_BUFF_1_VISIBLE: 'CommonBuffId' = 206401 + LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_IN_THE_BUFF_2_VISIBLE: 'CommonBuffId' = 211931 + LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_IS_NUDE_HIDDEN: 'CommonBuffId' = 212086 + LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_LOT_HANG_OUT_VISIBLE: 'CommonBuffId' = 206561 + LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_NATURAL_FORM_VISIBLE: 'CommonBuffId' = 212238 + LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_NEVER_NUDE_HIDDEN: 'CommonBuffId' = 206639 + LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_NOT_A_CARE_IN_THE_WORLD_VISIBLE: 'CommonBuffId' = 212084 + LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_OH_NATURAL_VISIBLE: 'CommonBuffId' = 212085 + LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_PERFECT_TAN_VISIBLE: 'CommonBuffId' = 212236 + LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_RISKY_BUSINESS_VISIBLE: 'CommonBuffId' = 206493 + LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_SAND_EVERYWHERE_2_VISIBLE: 'CommonBuffId' = 212271 + LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_SAND_EVERYWHERE_VISIBLE: 'CommonBuffId' = 212261 + LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_SKINNY_DIP_VISIBLE: 'CommonBuffId' = 212172 + LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_UPDATER_HIDDEN: 'CommonBuffId' = 211867 + LOT_MODS_BASE_GAME_CONVIVIAL_HIDDEN: 'CommonBuffId' = 145501 + LOT_MODS_BASE_GAME_CONVIVIAL_HIDDEN_VFX: 'CommonBuffId' = 191074 + LOT_MODS_BASE_GAME_CONVIVIAL_VISIBLE: 'CommonBuffId' = 145525 + LOT_MODS_BASE_GAME_GREAT_ACOUSTICS_HIDDEN: 'CommonBuffId' = 145499 + LOT_MODS_BASE_GAME_GREAT_ACOUSTICS_VISIBLE: 'CommonBuffId' = 145522 + LOT_MODS_BASE_GAME_GRODY_RESTAURANTS_HIDDEN: 'CommonBuffId' = 152195 + LOT_MODS_BASE_GAME_HIGH_SPEED_INTERNET_HIDDEN: 'CommonBuffId' = 145498 + LOT_MODS_BASE_GAME_HIGH_SPEED_INTERNET_VISIBLE: 'CommonBuffId' = 145519 + LOT_MODS_BASE_GAME_HOMEY_HIDDEN: 'CommonBuffId' = 145493 + LOT_MODS_BASE_GAME_HOMEY_INVISIBLE_VFX: 'CommonBuffId' = 157154 + LOT_MODS_BASE_GAME_HOMEY_VISIBLE: 'CommonBuffId' = 145494 + LOT_MODS_BASE_GAME_NATURAL_LIGHT_HANDINESS_HIDDEN: 'CommonBuffId' = 146577 + LOT_MODS_BASE_GAME_NATURAL_LIGHT_HIDDEN: 'CommonBuffId' = 145502 + LOT_MODS_BASE_GAME_NATURAL_LIGHT_VISIBLE: 'CommonBuffId' = 145528 + LOT_MODS_BASE_GAME_SCIENCE_LAIR_HIDDEN: 'CommonBuffId' = 145500 + LOT_MODS_BASE_GAME_SCIENCE_LAIR_VISIBLE: 'CommonBuffId' = 145524 + LOT_MODS_ISLAND_SPIRITS_BENEVOLENT_ADULT_HIDDEN: 'CommonBuffId' = 210152 + LOT_MODS_ISLAND_SPIRITS_BENEVOLENT_CHILD_HIDDEN: 'CommonBuffId' = 210131 + LOT_MODS_ISLAND_SPIRITS_ISLAND_ABUNDANCE_VISIBLE: 'CommonBuffId' = 208762 + LOT_MODS_ISLAND_SPIRITS_ISLAND_CURSE_ADULT_VISIBLE: 'CommonBuffId' = 208772 + LOT_MODS_ISLAND_SPIRITS_ISLAND_CURSE_CHILD_VISIBLE: 'CommonBuffId' = 208816 + LOT_MODS_ISLAND_SPIRITS_ISLAND_ENERGY_VISIBLE: 'CommonBuffId' = 208763 + LOT_MODS_ISLAND_SPIRITS_ISLAND_FEAR_VISIBLE: 'CommonBuffId' = 208774 + LOT_MODS_ISLAND_SPIRITS_ISLAND_IMPATIENCE_VISIBLE: 'CommonBuffId' = 208775 + LOT_MODS_ISLAND_SPIRITS_ISLAND_LUCK_VISIBLE: 'CommonBuffId' = 208718 + LOT_MODS_ISLAND_SPIRITS_MALICIOUS_ADULT_HIDDEN: 'CommonBuffId' = 210154 + LOT_MODS_ISLAND_SPIRITS_MALICIOUS_CHILD_HIDDEN: 'CommonBuffId' = 210155 + LOT_MODS_OCEANIC_PARADISE_MERFOLK_HIDDEN: 'CommonBuffId' = 209688 + LOT_MODS_OCEANIC_PARADISE_NOT_SWIMMING_HIDDEN: 'CommonBuffId' = 209445 + LOT_MODS_OCEANIC_PARADISE_NOT_WADING_HIDDEN: 'CommonBuffId' = 209430 + LOT_MODS_OCEANIC_PARADISE_OCEANIC_SPLENDOR_VISIBLE: 'CommonBuffId' = 209490 + LOT_MODS_OCEANIC_PARADISE_SWIMMING_HIDDEN: 'CommonBuffId' = 209444 + LOT_MODS_OCEANIC_PARADISE_WADING_HIDDEN: 'CommonBuffId' = 209429 + LOUNGE_CHAIR_DOZE_OFF: 'CommonBuffId' = 207020 + LOUNGE_CHAIR_LUXORIOUS_LOUNGING: 'CommonBuffId' = 206848 + LOUNGE_EVENT_AWARD_CEREMONY_BOOK: 'CommonBuffId' = 197459 + LOUNGE_EVENT_AWARD_CEREMONY_CAREER_GIG: 'CommonBuffId' = 197460 + LOUNGE_EVENT_AWARD_CEREMONY_PAINTING: 'CommonBuffId' = 197461 + LOUNGE_EVENT_AWARD_CEREMONY_SONG: 'CommonBuffId' = 197463 + LOUNGE_EVENT_AWARD_CEREMONY_VIDEO: 'CommonBuffId' = 197462 + LOVE_GURU_ROMANTIC_DESTINY: 'CommonBuffId' = 146662 + LOVE_GURU_ROMANTIC_DOOM: 'CommonBuffId' = 146663 + LUNAR_CYCLE_MERMAID_4_FULLMOON: 'CommonBuffId' = 295512 + LUNAR_CYCLE_MERMAID_4_FULLMOON_TELEGRAPH: 'CommonBuffId' = 295513 + LUNAR_CYCLE_VAMPIRE_0_NEW_MOON: 'CommonBuffId' = 295399 + LUNAR_CYCLE_VAMPIRE_0_NEW_MOON_TELEGRAPH: 'CommonBuffId' = 295404 + LUNAR_CYCLE_WELL_RESTED: 'CommonBuffId' = 289361 + LUNAR_CYCLE_WEREWOLVES_0_NEW_MOON: 'CommonBuffId' = 288669 + LUNAR_CYCLE_WEREWOLVES_0_NEW_MOON_BLESSED: 'CommonBuffId' = 296542 + LUNAR_CYCLE_WEREWOLVES_0_NEW_MOON_TELEGRAPH: 'CommonBuffId' = 291593 + LUNAR_CYCLE_WEREWOLVES_1_WAXING_CRESCENT: 'CommonBuffId' = 288670 + LUNAR_CYCLE_WEREWOLVES_1_WAXING_CRESCENT_BLESSED: 'CommonBuffId' = 296544 + LUNAR_CYCLE_WEREWOLVES_1_WAXING_CRESCENT_TELEGRAPH: 'CommonBuffId' = 291594 + LUNAR_CYCLE_WEREWOLVES_2_FIRST_QUARTER: 'CommonBuffId' = 288671 + LUNAR_CYCLE_WEREWOLVES_2_FIRST_QUARTER_BLESSED: 'CommonBuffId' = 296546 + LUNAR_CYCLE_WEREWOLVES_2_FIRST_QUARTER_BLESSED_NEGATIVE: 'CommonBuffId' = 296818 + LUNAR_CYCLE_WEREWOLVES_2_FIRST_QUARTER_NEGATIVE: 'CommonBuffId' = 296817 + LUNAR_CYCLE_WEREWOLVES_2_FIRST_QUARTER_TELEGRAPH: 'CommonBuffId' = 291595 + LUNAR_CYCLE_WEREWOLVES_2_FIRST_QUARTER_TELEGRAPH_NEGATIVE: 'CommonBuffId' = 296824 + LUNAR_CYCLE_WEREWOLVES_3_WAXING_GIBBOUS: 'CommonBuffId' = 288672 + LUNAR_CYCLE_WEREWOLVES_3_WAXING_GIBBOUS_BLESSED: 'CommonBuffId' = 296548 + LUNAR_CYCLE_WEREWOLVES_3_WAXING_GIBBOUS_TELEGRAPH: 'CommonBuffId' = 291596 + LUNAR_CYCLE_WEREWOLVES_4_FULL_MOON: 'CommonBuffId' = 288673 + LUNAR_CYCLE_WEREWOLVES_4_FULL_MOON_FORMER_LYCAN: 'CommonBuffId' = 297732 + LUNAR_CYCLE_WEREWOLVES_4_FULL_MOON_FORMER_LYCAN_TELEGRAPH: 'CommonBuffId' = 297733 + LUNAR_CYCLE_WEREWOLVES_4_FULL_MOON_FURY_RATE: 'CommonBuffId' = 289862 + LUNAR_CYCLE_WEREWOLVES_4_FULL_MOON_FURY_RATE_COOLDOWN: 'CommonBuffId' = 292722 + LUNAR_CYCLE_WEREWOLVES_4_FULL_MOON_FURY_RATE_RESISTANCE: 'CommonBuffId' = 295870 + LUNAR_CYCLE_WEREWOLVES_4_FULL_MOON_INSATIABLE_HUNGER_SPEED_UP: 'CommonBuffId' = 293927 + LUNAR_CYCLE_WEREWOLVES_4_FULL_MOON_PRE_PHASE: 'CommonBuffId' = 289429 + LUNAR_CYCLE_WEREWOLVES_4_FULL_MOON_PRE_PHASE_NEGATIVE: 'CommonBuffId' = 289428 + LUNAR_CYCLE_WEREWOLVES_4_FULL_MOON_TELEGRAPH: 'CommonBuffId' = 291597 + LUNAR_CYCLE_WEREWOLVES_5_WANING_GIBBOUS: 'CommonBuffId' = 288674 + LUNAR_CYCLE_WEREWOLVES_5_WANING_GIBBOUS_BLESSED: 'CommonBuffId' = 296550 + LUNAR_CYCLE_WEREWOLVES_5_WANING_GIBBOUS_TELEGRAPH: 'CommonBuffId' = 291660 + LUNAR_CYCLE_WEREWOLVES_6_THIRD_QUARTER: 'CommonBuffId' = 288675 + LUNAR_CYCLE_WEREWOLVES_6_THIRD_QUARTER_BLESSED: 'CommonBuffId' = 296552 + LUNAR_CYCLE_WEREWOLVES_6_THIRD_QUARTER_BLESSED_NEGATIVE: 'CommonBuffId' = 296820 + LUNAR_CYCLE_WEREWOLVES_6_THIRD_QUARTER_NEGATIVE: 'CommonBuffId' = 296819 + LUNAR_CYCLE_WEREWOLVES_6_THIRD_QUARTER_TELEGRAPH: 'CommonBuffId' = 291661 + LUNAR_CYCLE_WEREWOLVES_6_THIRD_QUARTER_TELEGRAPH_NEGATIVE: 'CommonBuffId' = 296825 + LUNAR_CYCLE_WEREWOLVES_7_WANING_CRESCENT: 'CommonBuffId' = 288676 + LUNAR_CYCLE_WEREWOLVES_7_WANING_CRESCENT_BLESSED: 'CommonBuffId' = 296554 + LUNAR_CYCLE_WEREWOLVES_7_WANING_CRESCENT_TELEGRAPH: 'CommonBuffId' = 291662 + LUNAR_CYCLE_WEREWOLVES_LUNAR_BLESSING: 'CommonBuffId' = 296555 + LUNAR_CYCLE_WEREWOLVES_MOON_BATH_DREAMS_0_NEW_MOON: 'CommonBuffId' = 290180 + LUNAR_CYCLE_WEREWOLVES_MOON_BATH_DREAMS_1_WAXING_CRESCENT: 'CommonBuffId' = 290186 + LUNAR_CYCLE_WEREWOLVES_MOON_BATH_DREAMS_2_FIRST_QUARTER: 'CommonBuffId' = 290187 + LUNAR_CYCLE_WEREWOLVES_MOON_BATH_DREAMS_3_WAXING_GIBBOUS: 'CommonBuffId' = 290218 + LUNAR_CYCLE_WEREWOLVES_MOON_BATH_DREAMS_4_FULLMOON: 'CommonBuffId' = 290294 + LUNAR_CYCLE_WEREWOLVES_MOON_BATH_DREAMS_5_WANING_GIBBOUS: 'CommonBuffId' = 290295 + LUNAR_CYCLE_WEREWOLVES_MOON_BATH_DREAMS_6_THIRD_QUARTER: 'CommonBuffId' = 290296 + LUNAR_CYCLE_WEREWOLVES_MOON_BATH_DREAMS_7_WANING_CRESCENT: 'CommonBuffId' = 290297 + LUNAR_CYCLE_WEREWOLVES_MOON_BATH_DREAMS_PUT_TO_BED: 'CommonBuffId' = 290331 + LUNAR_CYCLE_WITCH_4_FULLMOON: 'CommonBuffId' = 295529 + LUNAR_CYCLE_WITCH_4_FULLMOON_TELEGRAPH: 'CommonBuffId' = 295530 + MAGIC_DUEL_COOLDOWN: 'CommonBuffId' = 223063 + MAGIC_DUEL_LOSE: 'CommonBuffId' = 217338 + MAGIC_DUEL_WIN: 'CommonBuffId' = 217334 + MAGIC_HQ_BROWSE_BOOKS_COOLDOWN: 'CommonBuffId' = 222436 + MAGIC_IS_REAL: 'CommonBuffId' = 108016 + MAGIC_IS_REAL_GREAT_STORYTELLER: 'CommonBuffId' = 109745 + MAGIC_SAGE_MISCHIEF: 'CommonBuffId' = 212864 + MAGIC_SAGE_PRACTICAL: 'CommonBuffId' = 212866 + MAGIC_SAGE_UNTAMED: 'CommonBuffId' = 212869 + MAGIC_VENUE_NPC_EXPERIMENT_COOLDOWN: 'CommonBuffId' = 223356 + MAGIC_VENUE_NPC_INTERMEDIATE: 'CommonBuffId' = 213055 + MAGIC_VENUE_NPC_NOVICE: 'CommonBuffId' = 213039 + MAILBOX_GET_GIFT_COOLDOWN: 'CommonBuffId' = 185510 + MAKER_MENTOR_SHARE_IDEAS_COOLDOWN: 'CommonBuffId' = 238695 + MAM_BORING_CONVERSATION: 'CommonBuffId' = 12465 + MAM_SOCIAL_REBUFF: 'CommonBuffId' = 12466 + MARBLES_ANOTHER_FOR_THE_COLLECTION: 'CommonBuffId' = 348852 + MARBLES_ANTED_PLAYER_DURING_GAME_HIDDEN: 'CommonBuffId' = 348866 + MARBLES_ANTED_PLAYER_PRE_GAME_HIDDEN: 'CommonBuffId' = 348864 + MARBLES_FINDERS_KEEPERS: 'CommonBuffId' = 346977 + MARBLES_GUARANTEE_SUCCESS_TURN_HIDDEN: 'CommonBuffId' = 354796 + MARBLES_LOST_MY_MARBLES: 'CommonBuffId' = 348853 + MARBLES_MARBLE_MASTER: 'CommonBuffId' = 347884 + MARBLES_RUMMAGE_COOLDOWN: 'CommonBuffId' = 359584 + MARBLES_SORE_THUMB: 'CommonBuffId' = 347885 + MARBLES_TRADE_MARBLE_COOLDOWN: 'CommonBuffId' = 359583 + MASCOT_LOSE_MASK: 'CommonBuffId' = 226767 + MASCOT_OUTFIT_ARTS: 'CommonBuffId' = 225125 + MASCOT_OUTFIT_TECH: 'CommonBuffId' = 225126 + MASCOT_PUMPED_UP: 'CommonBuffId' = 224911 + MASCOT_PUMP_UP_COOLDOWN: 'CommonBuffId' = 228796 + MASCOT_WHATS_THAT_SMELL: 'CommonBuffId' = 224912 + MASTER_TRAINER_PRACTICE_MAKES_PERFECT: 'CommonBuffId' = 327405 + MASTER_TRAINER_TOP_RIDER_TIPS: 'CommonBuffId' = 321406 + MATCHMAKING_BLIND_DATE_CATFISH: 'CommonBuffId' = 376224 + MATCHMAKING_USED_APP: 'CommonBuffId' = 374480 + MAX_FAT: 'CommonBuffId' = 38111 + MAX_FIT: 'CommonBuffId' = 38060 + MECHANICAL_SUIT_BODY_BEIGE_WHITE: 'CommonBuffId' = 226719 + MECHANICAL_SUIT_BODY_BLACK_BLUE: 'CommonBuffId' = 226294 + MECHANICAL_SUIT_BODY_BLUE_RED: 'CommonBuffId' = 226720 + MECHANICAL_SUIT_BODY_GRAY_BROWN: 'CommonBuffId' = 226721 + MECHANICAL_SUIT_BODY_GREEN_BROWN: 'CommonBuffId' = 226722 + MECHANICAL_SUIT_BODY_RED_GREEN: 'CommonBuffId' = 226723 + MECHANICAL_SUIT_BODY_WHITE_COPPER: 'CommonBuffId' = 226724 + MECHANICAL_SUIT_HELMET_BLACK_BLUE: 'CommonBuffId' = 226293 + MECHANICAL_SUIT_HELMET_BLACK_COPPER: 'CommonBuffId' = 226725 + MECHANICAL_SUIT_HELMET_BLACK_GOLD: 'CommonBuffId' = 226726 + MECHANICAL_SUIT_HELMET_BLACK_GRAY: 'CommonBuffId' = 226727 + MECHANICAL_SUIT_HELMET_BLUE_GRAY: 'CommonBuffId' = 226728 + MECHANICAL_SUIT_HELMET_GRAY_BLACK: 'CommonBuffId' = 226729 + MECHANICAL_SUIT_HELMET_GREEN_BLACK: 'CommonBuffId' = 226730 + MECHANICAL_SUIT_HOVER_MODE: 'CommonBuffId' = 226295 + MEDITATION_BOREDOM: 'CommonBuffId' = 119050 + MEDITATION_MOTIVE_AND_DECAY_HIGH_SKILL: 'CommonBuffId' = 121345 + MEDITATION_MOTIVE_AND_DECAY_LEVEL10: 'CommonBuffId' = 121346 + MEDITATION_MOTIVE_AND_DECAY_LOW_SKILL: 'CommonBuffId' = 121343 + MEDITATION_MOTIVE_AND_DECAY_MED_SKILL: 'CommonBuffId' = 121344 + MEDITATION_MOTIVE_DECAY_MASSAGE_CHAIR_FOOT_SOAK: 'CommonBuffId' = 273380 + MEDITATION_SELF_DISCOVERY_HOMEWORK_EPIPHANY: 'CommonBuffId' = 271218 + MEMORY_ANGRY: 'CommonBuffId' = 37548 + MEMORY_CONFIDENT: 'CommonBuffId' = 37547 + MEMORY_EMBARRASSED: 'CommonBuffId' = 37551 + MEMORY_FLIRTY: 'CommonBuffId' = 37545 + MEMORY_HAPPY: 'CommonBuffId' = 37541 + MEMORY_INSPIRED: 'CommonBuffId' = 37550 + MEMORY_SAD: 'CommonBuffId' = 37549 + MEMORY_SCARED: 'CommonBuffId' = 254532 + MENTALLY_RELAXED: 'CommonBuffId' = 118512 + MENTOREE_ACTIVITY_TABLE: 'CommonBuffId' = 30026 + MENTOREE_BY_MENTOR_PRO_ACTIVITY_TABLE: 'CommonBuffId' = 40516 + MENTOREE_BY_MENTOR_PRO_CHESS: 'CommonBuffId' = 40517 + MENTOREE_BY_MENTOR_PRO_CHILD_HOMEWORK: 'CommonBuffId' = 40518 + MENTOREE_BY_MENTOR_PRO_COMEDY: 'CommonBuffId' = 290396 + MENTOREE_BY_MENTOR_PRO_EASEL: 'CommonBuffId' = 40519 + MENTOREE_BY_MENTOR_PRO_EQUESTRIAN: 'CommonBuffId' = 332040 + MENTOREE_BY_MENTOR_PRO_FISHING: 'CommonBuffId' = 207777 + MENTOREE_BY_MENTOR_PRO_GUITAR: 'CommonBuffId' = 40527 + MENTOREE_BY_MENTOR_PRO_HANDINESS: 'CommonBuffId' = 40520 + MENTOREE_BY_MENTOR_PRO_PIANO: 'CommonBuffId' = 40528 + MENTOREE_BY_MENTOR_PRO_PIPE_ORGAN: 'CommonBuffId' = 151304 + MENTOREE_BY_MENTOR_PRO_PROGRAMMING: 'CommonBuffId' = 290394 + MENTOREE_BY_MENTOR_PRO_PUNCHING_BAG: 'CommonBuffId' = 40521 + MENTOREE_BY_MENTOR_PRO_ROCKET_SCIENCE: 'CommonBuffId' = 290395 + MENTOREE_BY_MENTOR_PRO_TEEN_HOMEWORK: 'CommonBuffId' = 40522 + MENTOREE_BY_MENTOR_PRO_TREADMILL: 'CommonBuffId' = 40523 + MENTOREE_BY_MENTOR_PRO_VIOLIN: 'CommonBuffId' = 40529 + MENTOREE_BY_MENTOR_PRO_WORKOUT_MACHINE: 'CommonBuffId' = 40524 + MENTOREE_BY_MENTOR_PRO_WRITING: 'CommonBuffId' = 40525 + MENTOREE_CHESS: 'CommonBuffId' = 30695 + MENTOREE_CHILD_HOMEWORK: 'CommonBuffId' = 29295 + MENTOREE_COMEDY: 'CommonBuffId' = 290391 + MENTOREE_EASEL: 'CommonBuffId' = 30024 + MENTOREE_EQUESTRIAN_SKILL: 'CommonBuffId' = 329328 + MENTOREE_GUITAR: 'CommonBuffId' = 38157 + MENTOREE_HANDINESS: 'CommonBuffId' = 38432 + MENTOREE_PIANO: 'CommonBuffId' = 40486 + MENTOREE_PIPE_ORGAN: 'CommonBuffId' = 151303 + MENTOREE_PROGRAMMING: 'CommonBuffId' = 290390 + MENTOREE_PUNCHING_BAG: 'CommonBuffId' = 9171 + MENTOREE_ROCKET_SCIENCE: 'CommonBuffId' = 290392 + MENTOREE_TEEN_HOMEWORK: 'CommonBuffId' = 29154 + MENTOREE_TREADMILL: 'CommonBuffId' = 9167 + MENTOREE_VIOLIN: 'CommonBuffId' = 40487 + MENTOREE_WORKOUT_MACHINE: 'CommonBuffId' = 9163 + MENTOREE_WRITING: 'CommonBuffId' = 38056 + MENTORER: 'CommonBuffId' = 12467 + MERMAID_AQUATIC_LURE_EFFECTIVE_SKILL: 'CommonBuffId' = 210725 + MERMAID_BURNING_WEATHER: 'CommonBuffId' = 213441 + MERMAID_DISCOVERY_CHECK: 'CommonBuffId' = 215253 + MERMAID_DREAMING: 'CommonBuffId' = 215417 + MERMAID_HEIGHTENED_SENSATIONS: 'CommonBuffId' = 206216 + MERMAID_HYDRATION_DEHYDRATED: 'CommonBuffId' = 208501 + MERMAID_HYDRATION_DRIED_SCALES: 'CommonBuffId' = 208500 + MERMAID_HYPNOTIZE: 'CommonBuffId' = 213447 + MERMAID_INTENSE_TINGLING: 'CommonBuffId' = 206275 + MERMAID_IS_WADING: 'CommonBuffId' = 212613 + MERMAID_OCEAN_THREAT: 'CommonBuffId' = 207173 + MERMAID_OF_AGE: 'CommonBuffId' = 215478 + MERMAID_OUTSIDE_IN_RAIN: 'CommonBuffId' = 208387 + MERMAID_OUTSIDE_IN_RAIN_HEAV_YRAIN: 'CommonBuffId' = 209373 + MERMAID_OUTSIDE_IN_RAIN_NO_MODIFER: 'CommonBuffId' = 209379 + MERMAID_POWER_CHARMER: 'CommonBuffId' = 206027 + MERMAID_POWER_COOLDOWN_AQUATIC_LURE: 'CommonBuffId' = 205864 + MERMAID_POWER_COOLDOWN_CALL_STORM: 'CommonBuffId' = 205865 + MERMAID_POWER_COOLDOWN_CHARMER: 'CommonBuffId' = 205848 + MERMAID_POWER_COOLDOWN_INSPIRING: 'CommonBuffId' = 205849 + MERMAID_POWER_COOLDOWN_MERFOLK_KISS: 'CommonBuffId' = 205866 + MERMAID_POWER_COOLDOWN_QUESTION: 'CommonBuffId' = 205850 + MERMAID_POWER_COOLDOWN_REQUIEM: 'CommonBuffId' = 205851 + MERMAID_POWER_COOLDOWN_SIRENS_CALL: 'CommonBuffId' = 205867 + MERMAID_POWER_COOLDOWN_SUMMON_OCEAN_THREAT: 'CommonBuffId' = 205869 + MERMAID_POWER_INSPIRING: 'CommonBuffId' = 206025 + MERMAID_POWER_MERFOLK_KISS: 'CommonBuffId' = 206040 + MERMAID_POWER_QUESTION: 'CommonBuffId' = 206031 + MERMAID_POWER_REQUIEM: 'CommonBuffId' = 206037 + MERMAID_SHALLOW_WATER_CHECK: 'CommonBuffId' = 212420 + MERMAID_SHALLOW_WATER_VFX: 'CommonBuffId' = 212376 + MERMAID_SIREN_CALLED: 'CommonBuffId' = 213444 + MERMAID_STRANGE_REACTION: 'CommonBuffId' = 206172 + MERMAID_STRANGE_SENSATIONS: 'CommonBuffId' = 205931 + MERMAID_SWIM_WALK_STYLE: 'CommonBuffId' = 199046 + MERMAID_SWIM_WALK_STYLE_OCEAN: 'CommonBuffId' = 210128 + MERMAID_TEMPORARY_DISCOVERY: 'CommonBuffId' = 215412 + MERMAID_TRAIT: 'CommonBuffId' = 205407 + MESSED_UP_ENDING: 'CommonBuffId' = 103137 + MIDLIFE_CRISIS_DESIRE_FOR_EXCITEMENT: 'CommonBuffId' = 313567 + MIDLIFE_CRISIS_HIDDEN_BEFRIEND_A_STRAY: 'CommonBuffId' = 332556 + MIDLIFE_CRISIS_HIDDEN_CREATIVE_QUALITY_INCREASE: 'CommonBuffId' = 317909 + MIDLIFE_CRISIS_HIDDEN_GOLDEN_DATE: 'CommonBuffId' = 323622 + MIDLIFE_CRISIS_HIDDEN_MAX_A_SKILL: 'CommonBuffId' = 334199 + MIDLIFE_CRISIS_HIDDEN_SMART_HUB: 'CommonBuffId' = 323724 + MIDLIFE_CRISIS_HIDDEN_STRESS_ABOUT_LOST_TIME_COOLDOWN: 'CommonBuffId' = 318050 + MIDLIFE_CRISIS_MARCH_OF_TIME: 'CommonBuffId' = 313568 + MIDLIFE_CRISIS_RANDOM_MOOD_ANGRY: 'CommonBuffId' = 321214 + MIDLIFE_CRISIS_RANDOM_MOOD_CONFIDENT: 'CommonBuffId' = 321215 + MIDLIFE_CRISIS_RANDOM_MOOD_DAZED: 'CommonBuffId' = 321216 + MIDLIFE_CRISIS_RANDOM_MOOD_ENERGIZED: 'CommonBuffId' = 321217 + MIDLIFE_CRISIS_RANDOM_MOOD_FLIRTY: 'CommonBuffId' = 321218 + MIDLIFE_CRISIS_RANDOM_MOOD_FOCUSED: 'CommonBuffId' = 321219 + MIDLIFE_CRISIS_RANDOM_MOOD_INSPIRED: 'CommonBuffId' = 321220 + MIDLIFE_CRISIS_RANDOM_MOOD_SAD: 'CommonBuffId' = 321221 + MIDLIFE_CRISIS_RANDOM_MOOD_SCARED: 'CommonBuffId' = 321222 + MIDLIFE_CRISIS_RESOLUTION_ADVENTURE: 'CommonBuffId' = 314166 + MIDLIFE_CRISIS_RESOLUTION_CREATE: 'CommonBuffId' = 314167 + MIDLIFE_CRISIS_RESOLUTION_RELATIONSHIP: 'CommonBuffId' = 314169 + MIDLIFE_CRISIS_RESOLUTION_SUCCESS: 'CommonBuffId' = 314168 + MIDLIFE_CRISIS_TYPE_ADVENTURE: 'CommonBuffId' = 313922 + MIDLIFE_CRISIS_TYPE_CREATE: 'CommonBuffId' = 313923 + MIDLIFE_CRISIS_TYPE_RELATIONSHIP: 'CommonBuffId' = 313924 + MIDLIFE_CRISIS_TYPE_SUCCESS: 'CommonBuffId' = 313925 + MILITARY_CAREER_ADMIRE_MEDALS_HIGH: 'CommonBuffId' = 206624 + MILITARY_CAREER_ADMIRE_MEDALS_LOW: 'CommonBuffId' = 206622 + MILITARY_CAREER_ADMIRE_MEDALS_MEDIUM: 'CommonBuffId' = 206623 + MILITARY_CAREER_PORE_OVER_CASE_FILES: 'CommonBuffId' = 204695 + MILITARY_CAREER_RUN_DRILLS: 'CommonBuffId' = 204696 + MIND_CONTROL_SIT_COOLDOWN: 'CommonBuffId' = 115201 + MIND_POWERS_ALLURING_VISAGE_SELF: 'CommonBuffId' = 150023 + MIND_POWERS_ALLURING_VISAGE_SELF_2: 'CommonBuffId' = 150036 + MIND_POWERS_ALLURING_VISAGE_SELF_3: 'CommonBuffId' = 150037 + MIND_POWERS_ALLURING_VISAGE_TARGET: 'CommonBuffId' = 150029 + MIND_POWERS_ALLURING_VISAGE_TARGET_2: 'CommonBuffId' = 150052 + MIND_POWERS_ALLURING_VISAGE_TARGET_3: 'CommonBuffId' = 150053 + MIND_POWERS_COMMAND_BE_MEAN: 'CommonBuffId' = 150407 + MIND_POWERS_COMMAND_CLEAN: 'CommonBuffId' = 150147 + MIND_POWERS_COMMAND_REPAIR: 'CommonBuffId' = 150228 + MIND_POWERS_COMMAND_SIT: 'CommonBuffId' = 150156 + MIND_POWERS_COMMAND_WAKE_UP: 'CommonBuffId' = 150295 + MIND_POWERS_COMMAND_WORKOUT: 'CommonBuffId' = 150240 + MIND_POWERS_IRRESISTIBLE_SLUMBER: 'CommonBuffId' = 150475 + MIND_POWERS_MESMERIZE: 'CommonBuffId' = 150429 + MIND_POWERS_MESMERIZE_NIGHTTIME: 'CommonBuffId' = 155908 + MIN_FAT: 'CommonBuffId' = 77836 + MIN_FIT: 'CommonBuffId' = 77837 + MIRROR_MADE_SILLY_FACE: 'CommonBuffId' = 24193 + MIRROR_PSYCHED_UP: 'CommonBuffId' = 39888 + MISCHIEF_PRANKS_COOLDOWN_FAKE_ALIEN_CONTACT: 'CommonBuffId' = 98334 + MISCHIEF_PRANKS_COOLDOWN_FILL_BOSS_OFFICE_WITH_BALLOONS: 'CommonBuffId' = 98335 + MISCHIEF_PRANKS_COOLDOWN_FREE_THE_FROGS: 'CommonBuffId' = 98336 + MISCHIEF_PRANKS_COOLDOWN_GENERIC: 'CommonBuffId' = 98337 + MISCHIEF_PRANKS_COOLDOWN_HACK_INTO_COWORKERS_EMAIL: 'CommonBuffId' = 98338 + MISCHIEF_PRANKS_COOLDOWN_LURE_LLAMA_TO_THE_OFFICE: 'CommonBuffId' = 98339 + MISCHIEF_PRANKS_COOLDOWN_MAKE_ALL_INVISIBLE_INK_VISIBLE: 'CommonBuffId' = 98340 + MISCHIEF_PRANKS_COOLDOWN_MUSTACHES_FOR_ART: 'CommonBuffId' = 98341 + MISCHIEF_PRANKS_COOLDOWN_REARRANGE_KEYS_ON_THE_KEYBOARD: 'CommonBuffId' = 98342 + MISCHIEF_PRANKS_COOLDOWN_SELL_TEST_ANSWERS: 'CommonBuffId' = 98343 + MISCHIEF_PRANKS_COOLDOWN_SILLY_PUTTY_IN_THE_MIC: 'CommonBuffId' = 98344 + MISCHIEF_PRANKS_COOLDOWN_START_A_FOOD_FIGHT: 'CommonBuffId' = 98345 + MISCHIEF_PRANKS_COOLDOWN_STUFF_GEEKS_IN_LOCKER: 'CommonBuffId' = 98346 + MISCHIEF_PRANKS_COOLDOWN_STUFF_JOCKS_IN_LOCKER: 'CommonBuffId' = 98347 + MISCHIEF_PRANKS_COOLDOWN_UNLEASH_THE_GERBILS: 'CommonBuffId' = 98348 + MISCHIEF_PRANKS_COOLDOWN_WATER_CUP_PRANK: 'CommonBuffId' = 98349 + MISCHIEF_PRANKS_COOLDOWN_WRAP_BACON_AROUND_EVERYTHING: 'CommonBuffId' = 98350 + MISCHIEF_PRANKS_FAKE_ALIEN_CONTACT: 'CommonBuffId' = 36014 + MISCHIEF_PRANKS_FILL_BOSS_OFFICE_WITH_BALLOONS: 'CommonBuffId' = 36015 + MISCHIEF_PRANKS_FREE_THE_FROGS: 'CommonBuffId' = 36016 + MISCHIEF_PRANKS_GENERIC: 'CommonBuffId' = 26965 + MISCHIEF_PRANKS_HACK_INTO_COWORKERS_EMAIL: 'CommonBuffId' = 36020 + MISCHIEF_PRANKS_LURE_LLAMA_TO_THE_OFFICE: 'CommonBuffId' = 36013 + MISCHIEF_PRANKS_MAKE_ALL_INVISIBLE_INK_VISIBLE: 'CommonBuffId' = 36019 + MISCHIEF_PRANKS_MUSTACHES_FOR_ART: 'CommonBuffId' = 36018 + MISCHIEF_PRANKS_REARRANGE_KEYS_ON_THE_KEYBOARD: 'CommonBuffId' = 36021 + MISCHIEF_PRANKS_SELL_TEST_ANSWERS: 'CommonBuffId' = 35983 + MISCHIEF_PRANKS_SILLY_PUTTY_IN_THE_MIC: 'CommonBuffId' = 36017 + MISCHIEF_PRANKS_START_A_FOOD_FIGHT: 'CommonBuffId' = 35986 + MISCHIEF_PRANKS_STUFF_GEEKS_IN_LOCKER: 'CommonBuffId' = 35984 + MISCHIEF_PRANKS_STUFF_JOCKS_IN_LOCKER: 'CommonBuffId' = 35985 + MISCHIEF_PRANKS_SUCCESSFUL: 'CommonBuffId' = 35729 + MISCHIEF_PRANKS_SUCCESSFUL_OBJECT: 'CommonBuffId' = 98380 + MISCHIEF_PRANKS_UNLEASH_THE_GERBILS: 'CommonBuffId' = 35987 + MISCHIEF_PRANKS_UNSUCCESSFUL: 'CommonBuffId' = 35732 + MISCHIEF_PRANKS_WATER_CUP_PRANK: 'CommonBuffId' = 35889 + MISCHIEF_PRANKS_WRAP_BACON_AROUND_EVERYTHING: 'CommonBuffId' = 35672 + MISCHIEF_TEEN_PRANKS_CAUGHT: 'CommonBuffId' = 284916 + MISCHIEF_TEEN_PRANKS_NO_CATCHING: 'CommonBuffId' = 284914 + MISCHIEF_TEEN_PRANKS_PASSWORD_FAIL: 'CommonBuffId' = 285101 + MISCHIEF_TEEN_PRANKS_PASSWORD_SUCCESS: 'CommonBuffId' = 285102 + MISCHIEF_TEEN_PRANKS_PA_SPEAKER_FAIL: 'CommonBuffId' = 285104 + MISCHIEF_TEEN_PRANKS_PA_SPEAKER_SUCCESS: 'CommonBuffId' = 285105 + MISCHIEF_TEEN_PRANKS_STINK_CAPSULE_FAIL: 'CommonBuffId' = 285106 + MISCHIEF_TEEN_PRANKS_STINK_CAPSULE_TARGET: 'CommonBuffId' = 285107 + MISCHIEF_TEEN_PRANKS_SYSTEM_DARED_HIDDEN: 'CommonBuffId' = 285680 + MISCHIEF_TEEN_PRANKS_SYSTEM_FRAMED_HIDDEN: 'CommonBuffId' = 285700 + MISCHIEF_TEEN_PRANKS_SYSTEM_PRANKED_HIDDEN: 'CommonBuffId' = 285709 + MISCHIEF_TEEN_PRANKS_SYSTEM_RECENT_PRANK_HIDDEN: 'CommonBuffId' = 285500 + MISCHIEF_TEEN_PRANKS_URBAN_MYTH_EFFECT: 'CommonBuffId' = 285103 + MISCHIEF_TEEN_PRANKS_URBAN_MYTH_VAMPIRE: 'CommonBuffId' = 285100 + MISCHIEF_TEEN_PRANKS_WHITEBOARD_SUCCESS: 'CommonBuffId' = 285108 + MISSING_PETS_COMFORTED: 'CommonBuffId' = 173655 + MISSING_PETS_MISSING_MY_FURRY_FRIEND: 'CommonBuffId' = 173548 + MISSING_PETS_PROVIDE_WELCOME_BACK: 'CommonBuffId' = 176246 + MISSING_PETS_WELCOME_BACK: 'CommonBuffId' = 173838 + MISSING_PETS_WELCOME_BACK_AUTONOMY: 'CommonBuffId' = 174547 + MISSING_PETS_WOULDNT_SAY_IM_MISSING_IT: 'CommonBuffId' = 173560 + MOLD_SYSTEM_AFRAID_OF_THE_MOLD: 'CommonBuffId' = 345605 + MOLD_SYSTEM_BLOW_SPORES_AUTONOMOUS_COOLDOWN: 'CommonBuffId' = 356558 + MOLD_SYSTEM_BURN_MOLD_PILE_DONT_EXTINGUISH: 'CommonBuffId' = 353285 + MOLD_SYSTEM_FREEZE_SICKNESS_COMMODITIES: 'CommonBuffId' = 355805 + MOLD_SYSTEM_FUNGAL_OVERGROWTH_AUTONOMOUS_COOLDOWN: 'CommonBuffId' = 356556 + MOLD_SYSTEM_MOLD_FREE: 'CommonBuffId' = 342352 + MOLD_SYSTEM_MUSHROOM_RAGE: 'CommonBuffId' = 342351 + MOLD_SYSTEM_MUSHROOM_RAGE_EAT: 'CommonBuffId' = 356187 + MOLD_SYSTEM_PET_BLOCK_SICKNESS: 'CommonBuffId' = 357356 + MOLD_SYSTEM_PET_SICKNESS: 'CommonBuffId' = 357354 + MOLD_SYSTEM_SPOIL_FOOD_AUTONOMOUS_COOLDOWN: 'CommonBuffId' = 356557 + MOLD_SYSTEM_SPORE_SICKNESS: 'CommonBuffId' = 342350 + MOLD_SYSTEM_SPREAD_SPORES_AUTONOMOUS_COOLDOWN: 'CommonBuffId' = 356537 + MOLD_SYSTEM_TOXIC_CHILDREN: 'CommonBuffId' = 345833 + MOLD_SYSTEM_TOXIC_TIER_1_MILD: 'CommonBuffId' = 342347 + MOLD_SYSTEM_TOXIC_TIER_2_SEVERE: 'CommonBuffId' = 342348 + MOLD_SYSTEM_TOXIC_TIER_3_DEADLY: 'CommonBuffId' = 342349 + MOOD_BUFFS_HIDDEN_SCARED_TRACK_SCARED: 'CommonBuffId' = 251722 + MOOD_BUFFS_HIDDEN_SCARED_TRACK_TERRIFIED: 'CommonBuffId' = 251723 + MOOD_BUFFS_HORSES_HIDDEN_ANGRY: 'CommonBuffId' = 319703 + MOOD_BUFFS_HORSES_HIDDEN_ASLEEP: 'CommonBuffId' = 321110 + MOOD_BUFFS_HORSES_HIDDEN_CONFIDENT: 'CommonBuffId' = 319704 + MOOD_BUFFS_HORSES_HIDDEN_DAZED: 'CommonBuffId' = 319711 + MOOD_BUFFS_HORSES_HIDDEN_FINE: 'CommonBuffId' = 319708 + MOOD_BUFFS_HORSES_HIDDEN_HAPPY: 'CommonBuffId' = 319705 + MOOD_BUFFS_HORSES_HIDDEN_SAD: 'CommonBuffId' = 319712 + MOOD_BUFFS_HORSES_HIDDEN_SCARED: 'CommonBuffId' = 319710 + MOOD_BUFFS_HORSES_HIDDEN_TENSE: 'CommonBuffId' = 319707 + MOOD_BUFFS_HORSES_HIDDEN_UNCOMFORTABLE: 'CommonBuffId' = 319706 + MOOD_BUFFS_HORSES_HIDDEN_VERY_ANGRY: 'CommonBuffId' = 321118 + MOOD_BUFFS_HORSES_HIDDEN_VERY_CONFIDENT: 'CommonBuffId' = 321119 + MOOD_BUFFS_HORSES_HIDDEN_VERY_DAZED: 'CommonBuffId' = 321120 + MOOD_BUFFS_HORSES_HIDDEN_VERY_HAPPY: 'CommonBuffId' = 321121 + MOOD_BUFFS_HORSES_HIDDEN_VERY_SAD: 'CommonBuffId' = 321122 + MOOD_BUFFS_HORSES_HIDDEN_VERY_SCARED: 'CommonBuffId' = 321123 + MOOD_BUFFS_HORSES_HIDDEN_VERY_TENSE: 'CommonBuffId' = 321124 + MOOD_BUFFS_HORSES_HIDDEN_VERY_UNCOMFORTABLE: 'CommonBuffId' = 321125 + MOOD_BUFFS_LUNAR_CYCLE_MOON_BATHE_ALIEN_NOSTALGIA: 'CommonBuffId' = 300237 + MOOD_BUFFS_LUNAR_CYCLE_MOON_BATHE_ANTI_SPACED: 'CommonBuffId' = 295994 + MOOD_BUFFS_LUNAR_CYCLE_MOON_BATHE_ANTI_SPACED_WEREWOLF: 'CommonBuffId' = 295995 + MOOD_BUFFS_LUNAR_CYCLE_MOON_BATHE_CELESTIAL_REFRESH: 'CommonBuffId' = 289026 + MOOD_BUFFS_LUNAR_CYCLE_MOON_BATHE_CELESTIAL_REFRESH_WEREWOLF: 'CommonBuffId' = 295871 + MOOD_BUFFS_LUNAR_CYCLE_MOON_BATHE_FRISKY_MOON: 'CommonBuffId' = 295898 + MOOD_BUFFS_LUNAR_CYCLE_MOON_BATHE_FRISKY_MOON_WEREWOLF: 'CommonBuffId' = 295899 + MOOD_BUFFS_LUNAR_CYCLE_MOON_BATHE_JOYFUL_MOON: 'CommonBuffId' = 295997 + MOOD_BUFFS_LUNAR_CYCLE_MOON_BATHE_LUNAR_GLEE_FIRST_QUARTER: 'CommonBuffId' = 295893 + MOOD_BUFFS_LUNAR_CYCLE_MOON_BATHE_LUNAR_GLEE_FIRST_QUARTER_WEREWOLF: 'CommonBuffId' = 295894 + MOOD_BUFFS_LUNAR_CYCLE_MOON_BATHE_LUNAR_GLEE_THIRD_QUARTER: 'CommonBuffId' = 295992 + MOOD_BUFFS_LUNAR_CYCLE_MOON_BATHE_LUNAR_GLEE_THIRD_QUARTER_WEREWOLF: 'CommonBuffId' = 295993 + MOOD_BUFFS_LUNAR_CYCLE_MOON_BATHE_LUNAR_REASSURANCE: 'CommonBuffId' = 295990 + MOOD_BUFFS_LUNAR_CYCLE_MOON_BATHE_LUNAR_REASSURANCE_WEREWOLF: 'CommonBuffId' = 295991 + MOOD_BUFFS_LUNAR_CYCLE_MOON_BATHE_MOODY_MOON: 'CommonBuffId' = 289024 + MOOD_BUFFS_LUNAR_CYCLE_MOON_BATHE_NORMIE_SHINE: 'CommonBuffId' = 295872 + MOOD_BUFFS_LUNAR_CYCLE_MOON_BATHE_RECENT_MOON_BATHE: 'CommonBuffId' = 289022 + MOOD_BUFFS_LUNAR_CYCLE_MOON_BATHE_SPACE_ROCK_AMUSEMENT: 'CommonBuffId' = 295895 + MOOD_BUFFS_LUNAR_CYCLE_MOON_BATHE_SPACE_ROCK_AMUSEMENT_WEREWOLF: 'CommonBuffId' = 295896 + MOOD_BUFFS_LUNAR_CYCLE_MOON_BATHE_SPACE_ROCK_STRESS: 'CommonBuffId' = 295897 + MOOD_BUFFS_LUNAR_CYCLE_MOON_BATHE_WOLF_SHINE: 'CommonBuffId' = 289023 + MOOD_BUFFS_PETS_CATS_HIDDEN_ANXIOUS: 'CommonBuffId' = 158194 + MOOD_BUFFS_PETS_CAT_HIDDEN_ANGRY: 'CommonBuffId' = 158401 + MOOD_BUFFS_PETS_CAT_HIDDEN_ASLEEP: 'CommonBuffId' = 158559 + MOOD_BUFFS_PETS_CAT_HIDDEN_DROWSY: 'CommonBuffId' = 158140 + MOOD_BUFFS_PETS_CAT_HIDDEN_FINE: 'CommonBuffId' = 158402 + MOOD_BUFFS_PETS_CAT_HIDDEN_FLIRTY: 'CommonBuffId' = 158403 + MOOD_BUFFS_PETS_CAT_HIDDEN_HAPPY: 'CommonBuffId' = 158405 + MOOD_BUFFS_PETS_CAT_HIDDEN_SCARED: 'CommonBuffId' = 158404 + MOOD_BUFFS_PETS_DOG_HIDDEN_ANGRY: 'CommonBuffId' = 158280 + MOOD_BUFFS_PETS_DOG_HIDDEN_ANXIOUS: 'CommonBuffId' = 158279 + MOOD_BUFFS_PETS_DOG_HIDDEN_ASHAMED: 'CommonBuffId' = 158286 + MOOD_BUFFS_PETS_DOG_HIDDEN_ASLEEP: 'CommonBuffId' = 158285 + MOOD_BUFFS_PETS_DOG_HIDDEN_EXCITED: 'CommonBuffId' = 158276 + MOOD_BUFFS_PETS_DOG_HIDDEN_FINE: 'CommonBuffId' = 158284 + MOOD_BUFFS_PETS_DOG_HIDDEN_FLIRTY: 'CommonBuffId' = 158281 + MOOD_BUFFS_PETS_DOG_HIDDEN_HAPPY: 'CommonBuffId' = 158283 + MOOD_BUFFS_PETS_DOG_HIDDEN_MOPEY: 'CommonBuffId' = 158278 + MOOD_BUFFS_PETS_DOG_HIDDEN_SAD: 'CommonBuffId' = 158277 + MOOD_BUFFS_PETS_DOG_HIDDEN_SCARED: 'CommonBuffId' = 158282 + MOOD_BUFFS_SOCIALS_ANTI_ECO_DRAMA_DID_IT_JUST_MOVE: 'CommonBuffId' = 238413 + MOOD_BUFFS_SOCIALS_ANTI_ECO_DRAMA_FINE_VINTAGE: 'CommonBuffId' = 238419 + MOOD_BUFFS_SOCIALS_ANTI_ECO_DRAMA_FORCED_TO_RECYCLE: 'CommonBuffId' = 238409 + MOOD_BUFFS_SOCIALS_ANTI_ECO_DRAMA_HANDS_ON: 'CommonBuffId' = 238420 + MOOD_BUFFS_SOCIALS_ANTI_ECO_DRAMA_HOW_PEDESTRIAN: 'CommonBuffId' = 238410 + MOOD_BUFFS_SOCIALS_ANTI_ECO_DRAMA_SAVING_THE_WORLD: 'CommonBuffId' = 238418 + MOOD_BUFFS_SOCIALS_ANTI_ECO_DRAMA_SUPERB: 'CommonBuffId' = 238412 + MOOD_BUFFS_SOCIALS_ANTI_ECO_DRAMA_THIS_IS_EXACTLY_WHAT_THEY_WANT: 'CommonBuffId' = 238414 + MOOD_BUFFS_SOCIALS_ANTI_ECO_DRAMA_WATCH_THE_WORLD_BURN: 'CommonBuffId' = 238076 + MOOD_BUFFS_SOCIALS_ANTI_ECO_DRAMA_WHY_ARENT_WE_TALKING_ABOUT_ME: 'CommonBuffId' = 238408 + MOOD_BUFFS_SOCIALS_FEELING_IMPORTANT: 'CommonBuffId' = 107469 + MOOD_BUFFS_SOCIALS_FOLK_TALE_SUCCESS_LISTENERS: 'CommonBuffId' = 174856 + MOOD_BUFFS_SOCIALS_FOOLED_ME_ONCE: 'CommonBuffId' = 107461 + MOOD_BUFFS_SOCIALS_GREAT_INVESTMENT_TIPS: 'CommonBuffId' = 107459 + MOOD_BUFFS_SOCIALS_JUICY_OFFICE_GOSSIP: 'CommonBuffId' = 107236 + MOOD_HIDDEN_ANGRY: 'CommonBuffId' = 12831 + MOOD_HIDDEN_ASLEEP: 'CommonBuffId' = 27147 + MOOD_HIDDEN_BORED: 'CommonBuffId' = 12829 + MOOD_HIDDEN_CONFIDENT: 'CommonBuffId' = 12830 + MOOD_HIDDEN_DEPRESSED: 'CommonBuffId' = 12832 + MOOD_HIDDEN_ELATED: 'CommonBuffId' = 12834 + MOOD_HIDDEN_EMBARRASSED: 'CommonBuffId' = 12835 + MOOD_HIDDEN_ENERGIZED: 'CommonBuffId' = 12836 + MOOD_HIDDEN_ENRAGED: 'CommonBuffId' = 12840 + MOOD_HIDDEN_FEARLESS: 'CommonBuffId' = 12814 + MOOD_HIDDEN_FINE_DEFAULT: 'CommonBuffId' = 12837 + MOOD_HIDDEN_FLIRTY: 'CommonBuffId' = 12838 + MOOD_HIDDEN_FOCUSED: 'CommonBuffId' = 12839 + MOOD_HIDDEN_FURIOUS: 'CommonBuffId' = 12827 + MOOD_HIDDEN_GLOOMIER: 'CommonBuffId' = 27155 + MOOD_HIDDEN_GLOOMY: 'CommonBuffId' = 27154 + MOOD_HIDDEN_HAPPY: 'CommonBuffId' = 12841 + MOOD_HIDDEN_HOT_HEAD1: 'CommonBuffId' = 27321 + MOOD_HIDDEN_HOT_HEAD2: 'CommonBuffId' = 27323 + MOOD_HIDDEN_HOT_HEAD3: 'CommonBuffId' = 27320 + MOOD_HIDDEN_HUMILIATED: 'CommonBuffId' = 12842 + MOOD_HIDDEN_HYSTERICAL: 'CommonBuffId' = 12843 + MOOD_HIDDEN_IMAGINATIVE: 'CommonBuffId' = 12844 + MOOD_HIDDEN_INSPIRED: 'CommonBuffId' = 12845 + MOOD_HIDDEN_IN_THE_ZONE: 'CommonBuffId' = 12846 + MOOD_HIDDEN_MISERABLE: 'CommonBuffId' = 12847 + MOOD_HIDDEN_MORTIFIED: 'CommonBuffId' = 12848 + MOOD_HIDDEN_MUSERER_TRAIT_REPLACEMENT: 'CommonBuffId' = 37939 + MOOD_HIDDEN_MUSER_TRAIT_REPLACEMENT: 'CommonBuffId' = 27107 + MOOD_HIDDEN_NEUTRAL: 'CommonBuffId' = 12849 + MOOD_HIDDEN_PASSIONATE: 'CommonBuffId' = 12850 + MOOD_HIDDEN_PLAYFUL: 'CommonBuffId' = 12851 + MOOD_HIDDEN_POSSESSED: 'CommonBuffId' = 201540 + MOOD_HIDDEN_PUMPED: 'CommonBuffId' = 12852 + MOOD_HIDDEN_SAD: 'CommonBuffId' = 12853 + MOOD_HIDDEN_SILLY: 'CommonBuffId' = 12854 + MOOD_HIDDEN_SLOSHED: 'CommonBuffId' = 12855 + MOOD_HIDDEN_STRESSED: 'CommonBuffId' = 12856 + MOOD_HIDDEN_TENSE: 'CommonBuffId' = 12857 + MOOD_HIDDEN_UNCOMFORTABLE: 'CommonBuffId' = 12858 + MOOD_PETS_HIDDEN_HYPER: 'CommonBuffId' = 157880 + MOOD_REPLACEMENT_LOW_SOCIAL_HIDDEN: 'CommonBuffId' = 389884 + MOTHER_PLANT_ENERGIZED: 'CommonBuffId' = 204364 + MOTHER_PLANT_HOSTILE_REASON_WITH_INFECTED_SOCIALIZATION_BAD: 'CommonBuffId' = 204372 + MOTHER_PLANT_KNOCKED_OUT: 'CommonBuffId' = 204119 + MOTHER_PLANT_MADE_REQUEST: 'CommonBuffId' = 204363 + MOTHER_PLANT_RECENTLY_COMMANDED_FIGHT: 'CommonBuffId' = 207294 + MOTHER_PLANT_RECENTLY_FOUGHT: 'CommonBuffId' = 204374 + MOTHER_PLANT_RECENTLY_FOUGHT_BIG_FIGHT: 'CommonBuffId' = 206575 + MOTHER_PLANT_REVIVE: 'CommonBuffId' = 204114 + MOTHER_PLANT_SUCCESS: 'CommonBuffId' = 205007 + MOTIVES_ALL_MOTIVES_HIGH: 'CommonBuffId' = 26886 + MOTIVES_ALL_MOTIVES_PRETTY_HIGH: 'CommonBuffId' = 27116 + MOTIVES_BLADDER_HAS_TO_PEE: 'CommonBuffId' = 27109 + MOTIVES_BLADDER_REALLY_HAS_TO_PEE: 'CommonBuffId' = 27108 + MOTIVES_ENERGY_EXHAUSTED: 'CommonBuffId' = 12818 + MOTIVES_ENERGY_TIRED: 'CommonBuffId' = 12816 + MOTIVES_ENERGY_TRANQUILIZED: 'CommonBuffId' = 31566 + MOTIVES_FUN_DESPERATE_FOR_FUN: 'CommonBuffId' = 12819 + MOTIVES_FUN_HIGH: 'CommonBuffId' = 256947 + MOTIVES_FUN_NEEDS_AMUSEMENT: 'CommonBuffId' = 27113 + MOTIVES_HIDDEN_BLADDER_FILL_BLADDER: 'CommonBuffId' = 137304 + MOTIVES_HORSE_SUPPRESS_ALL: 'CommonBuffId' = 330660 + MOTIVES_HUMANOID_ROBOTS_DEPLETED_CHARGE: 'CommonBuffId' = 223435 + MOTIVES_HUMANOID_ROBOTS_DURABILITY_BREAKING_VFX: 'CommonBuffId' = 222670 + MOTIVES_HUMANOID_ROBOTS_DURABILITY_BROKEN_STATE: 'CommonBuffId' = 218479 + MOTIVES_HUMANOID_ROBOTS_DURABILITY_BROKEN_STATE_RUSTING: 'CommonBuffId' = 223429 + MOTIVES_HUMANOID_ROBOTS_DURABILITY_BROKEN_STATE_TRACKER: 'CommonBuffId' = 224389 + MOTIVES_HUMANOID_ROBOTS_DURABILITY_DILAPITATED: 'CommonBuffId' = 223431 + MOTIVES_HUMANOID_ROBOTS_DURABILITY_LOSS_FROM_WATER_HIGH: 'CommonBuffId' = 229576 + MOTIVES_HUMANOID_ROBOTS_DURABILITY_LOSS_FROM_WATER_LOW: 'CommonBuffId' = 229867 + MOTIVES_HUMANOID_ROBOTS_DURABILITY_ON_THE_FRITZ: 'CommonBuffId' = 223428 + MOTIVES_HUMANOID_ROBOTS_DURABILITY_STOP_LOSS: 'CommonBuffId' = 229903 + MOTIVES_HUMANOID_ROBOTS_DURABILITY_STOP_LOSS_TEMPORARY: 'CommonBuffId' = 230399 + MOTIVES_HUMANOID_ROBOTS_DURABILITY_WAKE_UP: 'CommonBuffId' = 218696 + MOTIVES_HUMANOID_ROBOTS_LOW_CHARGE: 'CommonBuffId' = 223434 + MOTIVES_HUMANOID_ROBOTS_RECHARGING: 'CommonBuffId' = 223742 + MOTIVES_HUNGER_HUNGRY: 'CommonBuffId' = 12820 + MOTIVES_HUNGER_HUNGRY_GLUTTON: 'CommonBuffId' = 30331 + MOTIVES_HUNGER_HUNGRY_PLANT_SIMS: 'CommonBuffId' = 164179 + MOTIVES_HUNGER_STARVING: 'CommonBuffId' = 12821 + MOTIVES_HUNGER_STARVING_GHOST: 'CommonBuffId' = 103387 + MOTIVES_HUNGER_STARVING_PLANT_SIMS: 'CommonBuffId' = 164180 + MOTIVES_HUNGER_STARVING_WEREWOLF: 'CommonBuffId' = 294060 + MOTIVES_HUNGER_WEREWOLF: 'CommonBuffId' = 294059 + MOTIVES_HYGIENE_CAMPING_TRAIT_REPLACEMENT: 'CommonBuffId' = 102274 + MOTIVES_HYGIENE_FILTHY: 'CommonBuffId' = 12823 + MOTIVES_HYGIENE_GRUNGY: 'CommonBuffId' = 27114 + MOTIVES_INFANT_ATTENTION_ANGRY: 'CommonBuffId' = 317667 + MOTIVES_INFANT_ATTENTION_ANGRY_VERY: 'CommonBuffId' = 317668 + MOTIVES_INFANT_ATTENTION_SAD: 'CommonBuffId' = 290177 + MOTIVES_INFANT_ATTENTION_SAD_VERY: 'CommonBuffId' = 290178 + MOTIVES_INVIS_DECAY_MODS_BLADDER_YELLOW: 'CommonBuffId' = 27132 + MOTIVES_INVIS_DECAY_MODS_ENERGY_YELLOW: 'CommonBuffId' = 27139 + MOTIVES_INVIS_DECAY_MODS_FUN_YELLOW: 'CommonBuffId' = 27141 + MOTIVES_INVIS_DECAY_MODS_HUNGER_YELLOW: 'CommonBuffId' = 27142 + MOTIVES_INVIS_DECAY_MODS_HYGIENE_YELLOW: 'CommonBuffId' = 27138 + MOTIVES_INVIS_DECAY_MODS_SOCIAL_YELLOW: 'CommonBuffId' = 27140 + MOTIVES_INVIS_DECAY_MODS_TODDLER_ATTENTION_YELLOW: 'CommonBuffId' = 317356 + MOTIVES_PEED_SELF: 'CommonBuffId' = 12815 + MOTIVES_PET_CAT_AFFECTION_DISTRESS: 'CommonBuffId' = 159597 + MOTIVES_PET_CAT_COMPLAIN: 'CommonBuffId' = 158396 + MOTIVES_PET_CAT_DROWSY_ENERGY: 'CommonBuffId' = 161155 + MOTIVES_PET_CAT_DROWSY_ENERGY_LAZY: 'CommonBuffId' = 174965 + MOTIVES_PET_CAT_FILTHY: 'CommonBuffId' = 175246 + MOTIVES_PET_CAT_HUNGER_COOLDOWN: 'CommonBuffId' = 177668 + MOTIVES_PET_CAT_HUNGRY: 'CommonBuffId' = 158695 + MOTIVES_PET_CAT_IN_HEAT: 'CommonBuffId' = 160629 + MOTIVES_PET_CAT_IN_S_S3_MODE: 'CommonBuffId' = 167047 + MOTIVES_PET_CAT_KITTEN_HYPER: 'CommonBuffId' = 164491 + MOTIVES_PET_CAT_LOW_BLADDER: 'CommonBuffId' = 167242 + MOTIVES_PET_CAT_LOW_BOWEL: 'CommonBuffId' = 167243 + MOTIVES_PET_CAT_PLAY_COOLDOWN: 'CommonBuffId' = 161291 + MOTIVES_PET_CAT_PLAY_DISTRESS: 'CommonBuffId' = 157738 + MOTIVES_PET_CAT_STARVING: 'CommonBuffId' = 158720 + MOTIVES_PET_CAT_SUPPRESS_ALL: 'CommonBuffId' = 176465 + MOTIVES_PET_DOG_AFFECTION_DISTRESS: 'CommonBuffId' = 163242 + MOTIVES_PET_DOG_DIRTY: 'CommonBuffId' = 173851 + MOTIVES_PET_DOG_DROWSY_ELDER: 'CommonBuffId' = 161086 + MOTIVES_PET_DOG_FILTHY: 'CommonBuffId' = 175250 + MOTIVES_PET_DOG_HUNGRY: 'CommonBuffId' = 160302 + MOTIVES_PET_DOG_IN_HEAT: 'CommonBuffId' = 160627 + MOTIVES_PET_DOG_IN_S_S3_MODE: 'CommonBuffId' = 167048 + MOTIVES_PET_DOG_LOW_BLADDER: 'CommonBuffId' = 167202 + MOTIVES_PET_DOG_LOW_BOWEL: 'CommonBuffId' = 167215 + MOTIVES_PET_DOG_MOPEY_ENERGY: 'CommonBuffId' = 159911 + MOTIVES_PET_DOG_MOPEY_ENERGY_LAZY: 'CommonBuffId' = 174966 + MOTIVES_PET_DOG_PLAY_DISTRESS: 'CommonBuffId' = 158752 + MOTIVES_PET_DOG_PLAY_LOW: 'CommonBuffId' = 174625 + MOTIVES_PET_DOG_PUPPY_EXCITEMENT: 'CommonBuffId' = 164476 + MOTIVES_PET_DOG_SPIN_BLADDER: 'CommonBuffId' = 171081 + MOTIVES_PET_DOG_SPIN_BOWEL: 'CommonBuffId' = 171055 + MOTIVES_PET_DOG_STARVING: 'CommonBuffId' = 158736 + MOTIVES_PET_DOG_SUPPRESS_ALL: 'CommonBuffId' = 176464 + MOTIVES_PET_KITTEN_FILTHY: 'CommonBuffId' = 175247 + MOTIVES_PET_PUPPY_FILTHY: 'CommonBuffId' = 175251 + MOTIVES_PET_SMALL_DOG_FILTHY: 'CommonBuffId' = 175249 + MOTIVES_PLANT_SIM_WATER_INVISIBLE: 'CommonBuffId' = 162899 + MOTIVES_PLANT_SIM_WATER_PARCHED: 'CommonBuffId' = 162703 + MOTIVES_PLANT_SIM_WATER_THIRSTY: 'CommonBuffId' = 162702 + MOTIVES_SOCIAL_DESOLATE: 'CommonBuffId' = 12826 + MOTIVES_SOCIAL_DESOLATE_OUTGOING: 'CommonBuffId' = 29574 + MOTIVES_SOCIAL_LONELY: 'CommonBuffId' = 12825 + MOTIVES_SOCIAL_LONELY_OUTGOING: 'CommonBuffId' = 29575 + MOTIVES_TODDLER_ALL_MOTIVES_OKAY_CHECK_TODDLER: 'CommonBuffId' = 157834 + MOTIVES_TODDLER_ATTENTION_ANGRY: 'CommonBuffId' = 142131 + MOTIVES_TODDLER_ATTENTION_ANGRY_VERY: 'CommonBuffId' = 142132 + MOTIVES_TODDLER_ATTENTION_SAD: 'CommonBuffId' = 142133 + MOTIVES_TODDLER_ATTENTION_SAD_VERY: 'CommonBuffId' = 142134 + MOTIVES_TODDLER_BLADDER_ANGRY: 'CommonBuffId' = 154170 + MOTIVES_TODDLER_BLADDER_ANGRY_VERY: 'CommonBuffId' = 154171 + MOTIVES_TODDLER_BLADDER_HIDDEN: 'CommonBuffId' = 154253 + MOTIVES_TODDLER_BLADDER_HIDDEN_VERY: 'CommonBuffId' = 154255 + MOTIVES_TODDLER_BLADDER_SAD: 'CommonBuffId' = 154172 + MOTIVES_TODDLER_BLADDER_SAD_VERY: 'CommonBuffId' = 154173 + MOTIVES_TODDLER_ENERGY_ANGRY: 'CommonBuffId' = 142045 + MOTIVES_TODDLER_ENERGY_ANGRY_VERY: 'CommonBuffId' = 142094 + MOTIVES_TODDLER_ENERGY_FAIL_WHAT_HAPPENED: 'CommonBuffId' = 156757 + MOTIVES_TODDLER_ENERGY_SAD: 'CommonBuffId' = 142095 + MOTIVES_TODDLER_ENERGY_SAD_VERY: 'CommonBuffId' = 142096 + MOTIVES_TODDLER_FUN_ANGRY: 'CommonBuffId' = 142117 + MOTIVES_TODDLER_FUN_ANGRY_VERY: 'CommonBuffId' = 142118 + MOTIVES_TODDLER_FUN_SAD: 'CommonBuffId' = 142119 + MOTIVES_TODDLER_FUN_SAD_VERY: 'CommonBuffId' = 142120 + MOTIVES_TODDLER_HUNGER_ANGRY: 'CommonBuffId' = 142101 + MOTIVES_TODDLER_HUNGER_ANGRY_VERY: 'CommonBuffId' = 142102 + MOTIVES_TODDLER_HUNGER_SAD: 'CommonBuffId' = 142127 + MOTIVES_TODDLER_HUNGER_SAD_VERY: 'CommonBuffId' = 142128 + MOTIVES_TODDLER_HYGIENE_ANGRY: 'CommonBuffId' = 142240 + MOTIVES_TODDLER_HYGIENE_ANGRY_VERY: 'CommonBuffId' = 142241 + MOTIVES_TODDLER_HYGIENE_SAD: 'CommonBuffId' = 142242 + MOTIVES_TODDLER_HYGIENE_SAD_VERY: 'CommonBuffId' = 142243 + MOTIVES_VAMPIRE_POWER_EMPTY: 'CommonBuffId' = 155954 + MOTIVES_VAMPIRE_POWER_LOW: 'CommonBuffId' = 150259 + MOTIVES_VAMPIRE_THIRST_IRRESISTIBLE_THIRST: 'CommonBuffId' = 149567 + MOTIVES_VAMPIRE_THIRST_NEED_TO_FEED: 'CommonBuffId' = 149566 + MOTIVES_VAMPIRE_THIRST_PARCHED: 'CommonBuffId' = 149568 + MOTIVE_PEED_SELF_POOL: 'CommonBuffId' = 105772 + MOVE_HOUSEHOLD_PRE_MOVE: 'CommonBuffId' = 359179 + MOVE_HOUSEHOLD_RECENT_MOVE: 'CommonBuffId' = 359176 + MOVE_IN_ASK_COOLDOWN: 'CommonBuffId' = 310049 + MOVE_IN_RECENT: 'CommonBuffId' = 310401 + MOVE_IN_STORY_PROGRESSION_KLEPTOMANIAC: 'CommonBuffId' = 280272 + MOVE_IN_STORY_PROGRESSION_LONER: 'CommonBuffId' = 280270 + MOVE_IN_STORY_PROGRESSION_OUTGOING: 'CommonBuffId' = 280269 + MOVE_IN_STORY_PROGRESSION_PARANOID: 'CommonBuffId' = 280274 + MOVIE_THEATER_BANNED: 'CommonBuffId' = 305952 + MOVIE_THEATER_CHANCE_CARD_ENJOYMENT_DOWN: 'CommonBuffId' = 305957 + MOVIE_THEATER_CHANCE_CARD_ENJOYMENT_UP: 'CommonBuffId' = 305956 + MOVIE_THEATER_IN_THEATER: 'CommonBuffId' = 333127 + MOVIE_THEATER_LETS_GO_OUT_TO_THE_LOBBY_SAD: 'CommonBuffId' = 305953 + MOVIE_THEATER_SHUSH_SHAMER_CONFIDENT: 'CommonBuffId' = 305929 + MOVIE_THEATER_SHUSH_SHAMER_EMBARRASSED: 'CommonBuffId' = 305950 + MOVIE_THEATER_TALLTASTROPHE_HAPPY: 'CommonBuffId' = 305954 + MOVIE_THEATER_TALLTASTROPHE_UNCOMFORTABLE: 'CommonBuffId' = 305955 + MOVIE_THEATER_WATCHED_ACTION_DISLIKED: 'CommonBuffId' = 305729 + MOVIE_THEATER_WATCHED_ACTION_LIKED: 'CommonBuffId' = 305572 + MOVIE_THEATER_WATCHED_COMEDY_DISLIKED: 'CommonBuffId' = 305772 + MOVIE_THEATER_WATCHED_COMEDY_LIKED: 'CommonBuffId' = 305731 + MOVIE_THEATER_WATCHED_DRAMA_DISLIKED: 'CommonBuffId' = 305774 + MOVIE_THEATER_WATCHED_DRAMA_LIKED: 'CommonBuffId' = 305773 + MOVIE_THEATER_WATCHED_HORROR_DISLIKED: 'CommonBuffId' = 305778 + MOVIE_THEATER_WATCHED_HORROR_LIKED: 'CommonBuffId' = 305777 + MOVIE_THEATER_WATCHED_KIDS_DISLIKED: 'CommonBuffId' = 305776 + MOVIE_THEATER_WATCHED_KIDS_LIKED: 'CommonBuffId' = 305775 + MOVIE_THEATER_WATCHED_ROMANCE_DISLIKED: 'CommonBuffId' = 305779 + MOVIE_THEATER_WATCHED_ROMANCE_LIKED: 'CommonBuffId' = 305730 + MOVIE_THEATER_WATCHED_ROMANCE_LIKED_CHILD: 'CommonBuffId' = 305828 + MUD_PUDDLE_ACID_MUD_PUDDLE: 'CommonBuffId' = 240861 + MUD_PUDDLE_MUDDY_GOOD_TIME: 'CommonBuffId' = 185172 + MUD_PUDDLE_SLIP_IMMUNITY: 'CommonBuffId' = 182091 + MUD_PUDDLE_SUPER_MUDDY: 'CommonBuffId' = 190282 + MULTI_UNIT_EVENT_ALGAE_YUCKY: 'CommonBuffId' = 344305 + MULTI_UNIT_EVENT_CHARITY_DRIVE_FEELS_GOOD: 'CommonBuffId' = 345530 + MULTI_UNIT_EVENT_CHEMICAL_BROADCASTER: 'CommonBuffId' = 345145 + MULTI_UNIT_EVENT_COMPLETED_COMMUNITY: 'CommonBuffId' = 358889 + MULTI_UNIT_EVENT_COMPLETED_PRIMARY: 'CommonBuffId' = 343477 + MULTI_UNIT_EVENT_COMPLETED_SECONDARY: 'CommonBuffId' = 352303 + MULTI_UNIT_EVENT_CURSED_AFTER_DESTROY: 'CommonBuffId' = 345177 + MULTI_UNIT_EVENT_ELECTRICAL_POWERLESS_PROVOCATION: 'CommonBuffId' = 344834 + MULTI_UNIT_EVENT_EXPLOSION_SHREDDED_NERVES: 'CommonBuffId' = 342828 + MULTI_UNIT_EVENT_HIDDEN_BLIGHT_UPROOT_COMPLETE: 'CommonBuffId' = 360299 + MULTI_UNIT_EVENT_HIDDEN_BLIGHT_UPROOT_DELAY_CHECK: 'CommonBuffId' = 360301 + MULTI_UNIT_EVENT_HIDDEN_CHARITY_DRIVE_COOLDOWN: 'CommonBuffId' = 345543 + MULTI_UNIT_EVENT_HIDDEN_HAUNTING_CANCEL_POSSESS: 'CommonBuffId' = 344754 + MULTI_UNIT_EVENT_HIDDEN_HAUNTING_CONFRONT_COOLDOWN: 'CommonBuffId' = 344716 + MULTI_UNIT_EVENT_HIDDEN_HAUNTING_POSSESS_COOLDOWN: 'CommonBuffId' = 344695 + MULTI_UNIT_EVENT_HIDDEN_NUISANCE_NOTE_COOLDOWN: 'CommonBuffId' = 349615 + MULTI_UNIT_EVENT_HIDDEN_SEWAGE_LEAK_FLUSH_COOLDOWN: 'CommonBuffId' = 356923 + MULTI_UNIT_EVENT_HIDDEN_TENANT_DID_FIX: 'CommonBuffId' = 353150 + MULTI_UNIT_EVENT_INFESTATION_FAIL_STOMP: 'CommonBuffId' = 357311 + MULTI_UNIT_EVENT_INFESTATION_UNCOMFORTABLE: 'CommonBuffId' = 345007 + MULTI_UNIT_EVENT_MAINTENANCE_DAY_AUTONOMY: 'CommonBuffId' = 343856 + MULTI_UNIT_EVENT_MAINTENANCE_DAY_COMMUNITY_SPIRIT: 'CommonBuffId' = 344267 + MULTI_UNIT_EVENT_NUISANCE_ANNOYING_NOISE: 'CommonBuffId' = 349597 + MULTI_UNIT_EVENT_NUISANCE_BAD_SMELL: 'CommonBuffId' = 349598 + MULTI_UNIT_EVENT_PET_DAY_WARM_AND_FUZZY: 'CommonBuffId' = 344833 + MULTI_UNIT_EVENT_SEWAGE_LEAK_SULK: 'CommonBuffId' = 344677 + MULTI_UNIT_EVENT_TENANT_REVOLT_AUTONOMY: 'CommonBuffId' = 358006 + MULTI_UNIT_EVENT_TENANT_REVOLT_MOB_RULES: 'CommonBuffId' = 352350 + MULTI_UNIT_EVENT_TRASH_OVERLOAD_END_TRASH_DRIVE: 'CommonBuffId' = 350681 + MULTI_UNIT_EVENT_TRASH_OVERLOAD_START_TRASH_DRIVE: 'CommonBuffId' = 350680 + MULTI_UNIT_EVENT_WATER_LEAK_ATTEMPT: 'CommonBuffId' = 356234 + MUSHROOM_HUNT_GROSSED_OUT_BY_FUNGUS: 'CommonBuffId' = 268560 + MUSIC_FESTIVAL_ARTIST_PERFORMER_END: 'CommonBuffId' = 269372 + MUSIC_FESTIVAL_ARTIST_PERFORMER_REACT: 'CommonBuffId' = 269373 + MUSIC_FESTIVAL_ARTIST_PERFORMER_SI_COMPATIBILITY: 'CommonBuffId' = 269751 + MUSIC_FESTIVAL_ARTIST_PERFORMER_START: 'CommonBuffId' = 269371 + MUSIC_FESTIVAL_AUTONOMY_MOD_ARTIST_ENTER: 'CommonBuffId' = 270408 + MUSIC_FESTIVAL_AUTONOMY_MOD_ARTIST_MAIN_ARTIST: 'CommonBuffId' = 269945 + MUSIC_FESTIVAL_AUTONOMY_MOD_ARTIST_OPENER_1: 'CommonBuffId' = 269943 + MUSIC_FESTIVAL_AUTONOMY_MOD_ARTIST_OPENER_2: 'CommonBuffId' = 269944 + MUSIC_FESTIVAL_AUTONOMY_MOD_FESTIVAL_GOER: 'CommonBuffId' = 269764 + MUSIC_FESTIVAL_AUTONOMY_MOD_FESTIVAL_GOER_ENDING: 'CommonBuffId' = 270743 + MUSIC_FESTIVAL_AUTONOMY_MOD_FESTIVAL_GOER_MAIN_ARTIST: 'CommonBuffId' = 269768 + MUSIC_FESTIVAL_AUTONOMY_MOD_FESTIVAL_GOER_NPC: 'CommonBuffId' = 270784 + MUSIC_FESTIVAL_AUTONOMY_MOD_FESTIVAL_GOER_OPENER_1: 'CommonBuffId' = 269766 + MUSIC_FESTIVAL_AUTONOMY_MOD_FESTIVAL_GOER_OPENER_2: 'CommonBuffId' = 269767 + MUSIC_FESTIVAL_AUTONOMY_MOD_FESTIVAL_GOER_POST_PERFORMANCE: 'CommonBuffId' = 269765 + MUSIC_FESTIVAL_AUTONOMY_MOD_FESTIVAL_GOER_STAGE_PERMISSIONS: 'CommonBuffId' = 269976 + MUSIC_FESTIVAL_COOLDOWNS_GET_HYPED_AUTONOMOUS: 'CommonBuffId' = 270809 + MUSIC_FESTIVAL_HIDDEN_MAIN_ARTIST: 'CommonBuffId' = 270112 + MUSIC_FESTIVAL_HIDDEN_WATCHING_PERFORMANCE_OPENER_1: 'CommonBuffId' = 270110 + MUSIC_FESTIVAL_HIDDEN_WATCHING_PERFORMANCE_OPENER_2: 'CommonBuffId' = 270111 + MUSIC_FESTIVAL_NPC_PURCHASE_COOLDOWN: 'CommonBuffId' = 270780 + MUSIC_FESTIVAL_VISIBLE_ENERGETIC_MAIN_ARTIST: 'CommonBuffId' = 270446 + MUSIC_FESTIVAL_VISIBLE_ENERGETIC_OPENER: 'CommonBuffId' = 270447 + MUSIC_FESTIVAL_VISIBLE_HAPPY_MAIN_ARTIST: 'CommonBuffId' = 270445 + MUSIC_FESTIVAL_VISIBLE_HAPPY_OPENER: 'CommonBuffId' = 270444 + MUSIC_FESTIVAL_VISIBLE_INSPIRED_POST_PERFORMANCE: 'CommonBuffId' = 270448 + MUSIC_FESTIVAL_WATCHING_END: 'CommonBuffId' = 270342 + MUSIC_FESTIVAL_WATCHING_REACT: 'CommonBuffId' = 270343 + MUSIC_FESTIVAL_WATCHING_START: 'CommonBuffId' = 270344 + MUSIC_PRODUCTION_STATION_LISTEN_BUFFS_LISTEN_ANGER: 'CommonBuffId' = 195378 + MUSIC_PRODUCTION_STATION_LISTEN_BUFFS_LISTEN_CONFIDENT: 'CommonBuffId' = 195377 + MUSIC_PRODUCTION_STATION_LISTEN_BUFFS_LISTEN_FLIRTY: 'CommonBuffId' = 195374 + MUSIC_PRODUCTION_STATION_LISTEN_BUFFS_LISTEN_FOCUSED: 'CommonBuffId' = 195375 + MUSIC_PRODUCTION_STATION_LISTEN_BUFFS_LISTEN_HAPPY: 'CommonBuffId' = 195373 + MUSIC_PRODUCTION_STATION_LISTEN_BUFFS_LISTEN_PLAYFUL: 'CommonBuffId' = 195376 + MUSIC_PRODUCTION_STATION_LISTEN_BUFFS_LISTEN_SAD: 'CommonBuffId' = 195372 + MUSIC_PRODUCTION_STATION_LISTEN_BUFFS_THATS_MY_SONG: 'CommonBuffId' = 195370 + MUSIC_PRODUCTION_STATION_REJECTION_LETTER_OFF_LOT: 'CommonBuffId' = 203301 + MUSIC_PRODUCTION_STATION_RELEASED_TRACK: 'CommonBuffId' = 194956 + MYSTICAL_RELIC_ANCIENT_JOY_CANT_CATCH: 'CommonBuffId' = 180262 + MYSTICAL_RELIC_ANCIENT_SICKNESS_CANT_CATCH: 'CommonBuffId' = 180261 + MYSTICAL_RELIC_CURSES_MARKED_FOR_DEATH_ELECTROCUTION_COOLDOWN: 'CommonBuffId' = 181087 + NAP: 'CommonBuffId' = 10362 + NATURAL_DANGERS_BEES_FAIL: 'CommonBuffId' = 177125 + NATURAL_DANGERS_BLOCK_ATTACK: 'CommonBuffId' = 181653 + NATURAL_DANGERS_BLOOD_BATS_FAIL: 'CommonBuffId' = 177128 + NATURAL_DANGERS_COOLDOWN: 'CommonBuffId' = 179883 + NATURAL_DANGERS_FIRE_FLIES_FAIL: 'CommonBuffId' = 177126 + NATURAL_DANGERS_FITNESS_SUCCESS: 'CommonBuffId' = 177169 + NATURAL_DANGERS_GEAR_SUCCESS: 'CommonBuffId' = 177136 + NATURAL_DANGERS_INSECTS_REPELLED: 'CommonBuffId' = 179463 + NATURAL_DANGERS_LIGHTNING_BUGS_FAIL: 'CommonBuffId' = 177127 + NATURAL_DANGERS_LOCAL_CULTURE_SKILL_SUCCESS: 'CommonBuffId' = 177171 + NATURAL_DANGERS_LOGIC_SKILL_SUCCESS: 'CommonBuffId' = 177170 + NATURAL_DANGERS_ROUTE_EVENT: 'CommonBuffId' = 180802 + NATURAL_DANGERS_SPIDER_FAIL: 'CommonBuffId' = 177129 + NATURAL_EARTHY_SCENT: 'CommonBuffId' = 118503 + NATURAL_FOCUS: 'CommonBuffId' = 108253 + NATURAL_FOCUS_LOVES_OUTDOORS: 'CommonBuffId' = 108263 + NAUSEOUS: 'CommonBuffId' = 9912 + NEARBY_PET_SKUNK: 'CommonBuffId' = 171963 + NEAR_FRIENDLY: 'CommonBuffId' = 32807 + NEAR_HOUSEHOLD_TODDLER: 'CommonBuffId' = 169547 + NEAR_MY_BABY: 'CommonBuffId' = 97289 + NEAR_MY_CHILD: 'CommonBuffId' = 32943 + NEAR_NEW_SIBLING: 'CommonBuffId' = 97686 + NEAR_PARTNER: 'CommonBuffId' = 32815 + NEAR_ROMANCE: 'CommonBuffId' = 32813 + NEAR_SOLAR_PANEL_ON: 'CommonBuffId' = 238802 + NEAR_UNFRIENDLY: 'CommonBuffId' = 32818 + NEIGHBOR_RELATIONSHIP_PHONE_CALL_FRIENDLY_BROUGHT_FRIENDS_TOGETHER: 'CommonBuffId' = 274065 + NEIGHBOR_RELATIONSHIP_PHONE_CALL_ROMANTIC_JUST_CALL_ME_CUPID: 'CommonBuffId' = 279203 + NEIGHBOR_TRAIT_BLIC_BLOCK_DANCE_COOLDOWN_HIDDEN: 'CommonBuffId' = 354232 + NEIGHBOR_TRAIT_CONTRIBUTE_FUNDS_COOLDOWN_FAMILY_HIDDEN: 'CommonBuffId' = 359364 + NEIGHBOR_TRAIT_CONTRIBUTE_FUNDS_COOLDOWN_HIDDEN: 'CommonBuffId' = 348263 + NEIGHBOR_TRAIT_CRINGE_AM_I_CRINGE: 'CommonBuffId' = 346655 + NEIGHBOR_TRAIT_CRINGE_BLIC_BLOCK_DANCE_NEGATIVE: 'CommonBuffId' = 346653 + NEIGHBOR_TRAIT_CRINGE_BLIC_BLOCK_DANCE_POSITIVE: 'CommonBuffId' = 346652 + NEIGHBOR_TRAIT_CRINGE_BLIC_BLOCK_DANCE_SELF: 'CommonBuffId' = 346651 + NEIGHBOR_TRAIT_CRINGE_BLIC_BLOCK_DANCE_SELF_TEMP: 'CommonBuffId' = 347689 + NEIGHBOR_TRAIT_CRINGE_COOLDOWN_HIDDEN: 'CommonBuffId' = 347014 + NEIGHBOR_TRAIT_CRINGE_CRUSTY_MEMES: 'CommonBuffId' = 346649 + NEIGHBOR_TRAIT_CRINGE_EMBRACE_YOUR_TRUTH: 'CommonBuffId' = 346656 + NEIGHBOR_TRAIT_CRINGE_IM_TOO_OLD_FOR_THIS: 'CommonBuffId' = 346650 + NEIGHBOR_TRAIT_CRINGE_IM_WAY_TOO_OLD_FOR_THIS: 'CommonBuffId' = 346654 + NEIGHBOR_TRAIT_CRINGE_STILL_GOT_IT: 'CommonBuffId' = 347876 + NEIGHBOR_TRAIT_CRINGE_WELL_MEMED_MY_FRIEND: 'CommonBuffId' = 346648 + NEIGHBOR_TRAIT_CRINGE_WORST_PUNS_NEGATIVE: 'CommonBuffId' = 355956 + NEIGHBOR_TRAIT_CRINGE_WORST_PUNS_POSITIVE: 'CommonBuffId' = 355955 + NEIGHBOR_TRAIT_GENEROUS_COOLDOWN_HIDDEN: 'CommonBuffId' = 348265 + NEIGHBOR_TRAIT_GENEROUS_FEELING_HEARD: 'CommonBuffId' = 346659 + NEIGHBOR_TRAIT_GENEROUS_FULL_OF_EMPATHY: 'CommonBuffId' = 346661 + NEIGHBOR_TRAIT_GENEROUS_GIFT: 'CommonBuffId' = 357005 + NEIGHBOR_TRAIT_GENEROUS_GIFT_OF_GIVING: 'CommonBuffId' = 346657 + NEIGHBOR_TRAIT_GENEROUS_GIFT_OF_GIVING_FAMILY: 'CommonBuffId' = 357006 + NEIGHBOR_TRAIT_GENEROUS_ICKY_FEELING: 'CommonBuffId' = 346675 + NEIGHBOR_TRAIT_GENEROUS_KIND_WORDS_RECIEVED: 'CommonBuffId' = 346660 + NEIGHBOR_TRAIT_GENEROUS_NEIGHBOR: 'CommonBuffId' = 356608 + NEIGHBOR_TRAIT_GENEROUS_SPREAD_THE_LOVE: 'CommonBuffId' = 346658 + NEIGHBOR_TRAIT_GENEROUS_UNPLEASANT_AURA: 'CommonBuffId' = 346672 + NEIGHBOR_TRAIT_LEARN_A_SECRET_HIDDEN: 'CommonBuffId' = 349861 + NEIGHBOR_TRAIT_NOSY_ADVICE_ACTOR: 'CommonBuffId' = 356496 + NEIGHBOR_TRAIT_NOSY_ADVICE_NEGATIVE_TARGET: 'CommonBuffId' = 356498 + NEIGHBOR_TRAIT_NOSY_ADVICE_POSITIVE_TARGET: 'CommonBuffId' = 356499 + NEIGHBOR_TRAIT_NOSY_ANIMAL_SPY: 'CommonBuffId' = 354536 + NEIGHBOR_TRAIT_NOSY_COOLDOWN_HIDDEN: 'CommonBuffId' = 348920 + NEIGHBOR_TRAIT_NOSY_DONT_BE_SUSPICIOUS: 'CommonBuffId' = 346644 + NEIGHBOR_TRAIT_NOSY_HOT_GOSSIP: 'CommonBuffId' = 346676 + NEIGHBOR_TRAIT_NOSY_JOURNAL_SNOOP: 'CommonBuffId' = 357564 + NEIGHBOR_TRAIT_NOSY_NEIGHBORHOOD_TELESCOPE: 'CommonBuffId' = 358014 + NEIGHBOR_TRAIT_NOSY_NOSY_NUISANCE: 'CommonBuffId' = 348922 + NEIGHBOR_TRAIT_NOSY_TEA_DEPRIVED: 'CommonBuffId' = 346677 + NEIGHBOR_TRAIT_NOSY_YOU_KNOW_YOU_LOVE_ME: 'CommonBuffId' = 346678 + NEIGHBOR_TRAIT_SPREAD_THE_CRINGE_HIDDEN: 'CommonBuffId' = 354726 + NEIGHBOR_TRAIT_SPREAD_THE_JOY_HIDDEN: 'CommonBuffId' = 354727 + NEIGHBOR_TRAIT_TEA_DEPRIVED_COUNTDOWN_HIDDEN: 'CommonBuffId' = 349565 + NEIGHBOR_TRAIT_WISE_COOLDOWN_HIDDEN: 'CommonBuffId' = 348264 + NEIGHBOR_TRAIT_WISE_ENERGIZED: 'CommonBuffId' = 348929 + NEIGHBOR_TRAIT_WISE_IMPORTANT_LESSON: 'CommonBuffId' = 356501 + NEIGHBOR_TRAIT_WISE_INSPIRATION_FOR_LIFE: 'CommonBuffId' = 346683 + NEIGHBOR_TRAIT_WISE_I_WAS_WRONGED_THAT_DAY: 'CommonBuffId' = 346689 + NEIGHBOR_TRAIT_WISE_LESSON_WELL_LEARNED: 'CommonBuffId' = 346684 + NEIGHBOR_TRAIT_WISE_MENTOR: 'CommonBuffId' = 356609 + NEIGHBOR_TRAIT_WISE_PASSING_IT_DOWN: 'CommonBuffId' = 346679 + NEIGHBOR_TRAIT_WISE_READY_FOR_LIFE: 'CommonBuffId' = 346680 + NEIGHBOR_TRAIT_WISE_SCARED: 'CommonBuffId' = 348927 + NEIGHBOR_TRAIT_WISE_SHARE_LIFE_EXPERIENCE: 'CommonBuffId' = 356500 + NEIGHBOR_TRAIT_WISE_THOSE_WERE_THE_DAYS: 'CommonBuffId' = 346686 + NEIGHBOR_TRAIT_WISE_THOSE_WERE_THE_DAYS_FLIRTY: 'CommonBuffId' = 346687 + NEIGHBOR_TRAIT_WISE_UGH_SPARE_ME: 'CommonBuffId' = 346681 + NEIGHBOR_TRAIT_WISE_WHERE_DID_THE_DAYS_GO: 'CommonBuffId' = 346688 + NEIGHBOR_TRAIT_WISE_WHERE_WAS_THIS_STORY_GOING: 'CommonBuffId' = 346682 + NEIGHBOR_TRAIT_WISE_WHO_ASKED: 'CommonBuffId' = 346685 + NEIGHBOR_TRAIT_WISE_WHY_OH_WHY: 'CommonBuffId' = 346690 + NEUTRAL_OVER48_HOURS: 'CommonBuffId' = 77767 + NEW_FRIEND_DRAMA_NODE_COOLDOWN: 'CommonBuffId' = 202751 + NEW_GOOD_FRIEND: 'CommonBuffId' = 12472 + NIGHTLIGHT: 'CommonBuffId' = 165358 + NO_GREETINGS: 'CommonBuffId' = 123741 + NO_SLEEP_24_HOURS: 'CommonBuffId' = 38133 + NO_SOCIAL_24_HOURS: 'CommonBuffId' = 38134 + NPC_ANGRY: 'CommonBuffId' = 29680 + NPC_BORED: 'CommonBuffId' = 29688 + NPC_CHEF_ANGRY: 'CommonBuffId' = 131377 + NPC_CHEF_CONFIDENT: 'CommonBuffId' = 131380 + NPC_CHEF_INSPIRED: 'CommonBuffId' = 131375 + NPC_CHEF_STRESSED: 'CommonBuffId' = 139951 + NPC_CHEF_VERY_ANGRY: 'CommonBuffId' = 131383 + NPC_CHEF_VERY_INSPIRED: 'CommonBuffId' = 131382 + NPC_DAZED: 'CommonBuffId' = 29744 + NPC_DISCOURAGE_SIT: 'CommonBuffId' = 136466 + NPC_DO_NOTHING: 'CommonBuffId' = 39236 + NPC_EMBARRASSED: 'CommonBuffId' = 29745 + NPC_FLIRTY: 'CommonBuffId' = 29678 + NPC_FOCUSED: 'CommonBuffId' = 29687 + NPC_HAPPY: 'CommonBuffId' = 29681 + NPC_INSPIRED: 'CommonBuffId' = 29682 + NPC_PET_SUPPRESS_ALL_MOTIVE_DECAY: 'CommonBuffId' = 168168 + NPC_RELATIONSHIP_AUTONOMY_GENERIC_COMMITMENT: 'CommonBuffId' = 280578 + NPC_RELATIONSHIP_AUTONOMY_HIDDEN_TARGET_BEST_FRIEND: 'CommonBuffId' = 310218 + NPC_RELATIONSHIP_AUTONOMY_HIDDEN_TARGET_BOYFRIEND_GIRLFRIEND: 'CommonBuffId' = 310223 + NPC_RELATIONSHIP_AUTONOMY_HIDDEN_TARGET_BREAK_UP: 'CommonBuffId' = 310221 + NPC_RELATIONSHIP_AUTONOMY_HIDDEN_TARGET_PROM: 'CommonBuffId' = 310220 + NPC_RELATIONSHIP_AUTONOMY_HIDDEN_TARGET_PROM_FRIENDS: 'CommonBuffId' = 310219 + NPC_RELATIONSHIP_AUTONOMY_HIDDEN_TARGET_PROPOSE: 'CommonBuffId' = 310222 + NPC_RELATIONSHIP_AUTONOMY_TALK_ABOUT_MARRIAGE: 'CommonBuffId' = 280633 + NPC_SAD: 'CommonBuffId' = 29679 + NPC_SUPPRESS_ALL_MOTIVES_EXCEPT_BLADDER: 'CommonBuffId' = 143413 + NPC_SUPPRESS_ALL_MOTIVE_DECAY: 'CommonBuffId' = 121359 + NPC_SUPPRESS_ALL_MOTIVE_DECAY_SS3: 'CommonBuffId' = 230218 + NPC_VERY_ANGRY: 'CommonBuffId' = 127091 + NPC_VILLAGERS_CONSPIRE_WITH_GNOMES_WHIMSICAL_EMBARRASSED: 'CommonBuffId' = 266411 + NPC_VILLAGERS_CONSPIRE_WITH_GNOMES_WHIMSICAL_ENERGIZED: 'CommonBuffId' = 266413 + NPC_VILLAGERS_CONSPIRE_WITH_GNOMES_WHIMSICAL_INSPIRED: 'CommonBuffId' = 266414 + NPC_VILLAGERS_CONSPIRE_WITH_GNOMES_WHIMSICAL_PLAYFUL: 'CommonBuffId' = 266412 + NPC_VILLAGERS_CONSPIRE_WITH_GNOMES_WHIMSICAL_STRESSED: 'CommonBuffId' = 266415 + OBJECT_AIR_CON_EFFECTS: 'CommonBuffId' = 357736 + OBJECT_AIR_CON_NEGATIVE: 'CommonBuffId' = 357735 + OBJECT_AIR_CON_POSITIVE: 'CommonBuffId' = 357734 + OBJECT_ALIEN_PORTAL_CALIBRATED: 'CommonBuffId' = 110526 + OBJECT_ALIEN_PORTAL_CONTACT: 'CommonBuffId' = 110658 + OBJECT_APARTMENT_BULLETIN_BOARD_ANGRY_FROM_PASSIVE_AGGRESSIVE_NOTE: 'CommonBuffId' = 145620 + OBJECT_APARTMENT_BULLETIN_BOARD_HAPPY_FROM_AFFIRMING_NOTE: 'CommonBuffId' = 145619 + OBJECT_APARTMENT_PROBLEM_ELECTRICAL_PROBLEM_OMINOUS_SPARKING: 'CommonBuffId' = 133097 + OBJECT_APARTMENT_PROBLEM_GOO_PUDDLE_GOO_GROSS_OUT: 'CommonBuffId' = 133094 + OBJECT_APARTMENT_PROBLEM_HANDY_HERO: 'CommonBuffId' = 143679 + OBJECT_APARTMENT_PROBLEM_LEAKY_PIPE_RISING_TIDE: 'CommonBuffId' = 133091 + OBJECT_APARTMENT_PROBLEM_MADE_IT_WORSE: 'CommonBuffId' = 143680 + OBJECT_APARTMENT_PROBLEM_MICE_MICE: 'CommonBuffId' = 144349 + OBJECT_APARTMENT_PROBLEM_MICE_RUDE_AWAKENING: 'CommonBuffId' = 151394 + OBJECT_APARTMENT_PROBLEM_MICE_SUSPICIOUS_SQUEAKING: 'CommonBuffId' = 144348 + OBJECT_APARTMENT_PROBLEM_NPC_COMPLAIN_TO_LANDLORD: 'CommonBuffId' = 150483 + OBJECT_APARTMENT_PROBLEM_RANDOM_SMELL_NOXIOUS_ODOR: 'CommonBuffId' = 133096 + OBJECT_APARTMENT_PROBLEM_RANDOM_SMELL_UNSETTLED_BY_ODOR: 'CommonBuffId' = 133095 + OBJECT_APARTMENT_PROBLEM_ROACH_HOLE_BUGGING_OUT: 'CommonBuffId' = 133093 + OBJECT_APARTMENT_PROBLEM_ROACH_HOLE_WAS_THAT: 'CommonBuffId' = 133092 + OBJECT_ARCADE_MACHINE_CONTINUE_GAME_HIDDEN: 'CommonBuffId' = 129531 + OBJECT_BABY_MOURN: 'CommonBuffId' = 100188 + OBJECT_BAR_GLOBE_CONTEMPLATED_WORLD_DOMINATION: 'CommonBuffId' = 145046 + OBJECT_BAR_GLOBE_FOUND_MY_CITY: 'CommonBuffId' = 145049 + OBJECT_BAR_GLOBE_STRIVING_FOR_GREATNESS: 'CommonBuffId' = 145048 + OBJECT_BAR_GLOBE_THE_VAST_WORLD: 'CommonBuffId' = 145047 + OBJECT_BASKETBALL_COACH_TIMER: 'CommonBuffId' = 154716 + OBJECT_BASKETBALL_DREAM_BIG: 'CommonBuffId' = 145875 + OBJECT_BASKETBALL_DREAM_BIG_SHOT_TAKEN_2_POINT: 'CommonBuffId' = 154209 + OBJECT_BASKETBALL_DREAM_BIG_SHOT_TAKEN_3_POINT: 'CommonBuffId' = 153704 + OBJECT_BASKETBALL_DREAM_BIG_SHOT_TAKEN_DOUBLE_CLUTCH: 'CommonBuffId' = 153705 + OBJECT_BASKETBALL_DREAM_BIG_SHOT_TAKEN_FLYING: 'CommonBuffId' = 153706 + OBJECT_BASKETBALL_DUNK_COMPETITION: 'CommonBuffId' = 147236 + OBJECT_BASKETBALL_RECENT_CURRY: 'CommonBuffId' = 147475 + OBJECT_BASKETBALL_SHOT_COMPETITION: 'CommonBuffId' = 147235 + OBJECT_BASKETBALL_SHOT_RESULT_MADE: 'CommonBuffId' = 146545 + OBJECT_BASKETBALL_SHOT_RESULT_MISSED: 'CommonBuffId' = 146546 + OBJECT_BASKETBALL_STOP_COACHING: 'CommonBuffId' = 155002 + OBJECT_BASKETBALL_TAKE_SHOT_2_POINT: 'CommonBuffId' = 145908 + OBJECT_BASKETBALL_TAKE_SHOT_3_POINT: 'CommonBuffId' = 145909 + OBJECT_BASKETBALL_TAKE_SHOT_ANY: 'CommonBuffId' = 145910 + OBJECT_BASKETBALL_TAKE_SHOT_CLOSE_SHOT: 'CommonBuffId' = 145906 + OBJECT_BASKETBALL_TAKE_SHOT_FREE_THROW: 'CommonBuffId' = 145907 + OBJECT_BASKETBALL_TAKE_SHOT_LONG_THREE: 'CommonBuffId' = 153823 + OBJECT_BASKETBALL_TAKING_A_SHOT: 'CommonBuffId' = 144051 + OBJECT_BASKETBALL_TAUNT: 'CommonBuffId' = 144054 + OBJECT_BASKETBALL_VISIBLE_CAUGHT_PRETENDING: 'CommonBuffId' = 146877 + OBJECT_BASKETBALL_VISIBLE_COURT_LOSS: 'CommonBuffId' = 146876 + OBJECT_BASKETBALL_VISIBLE_COURT_ROYALTY: 'CommonBuffId' = 146889 + OBJECT_BASKETBALL_VISIBLE_DUNKED_ON: 'CommonBuffId' = 146886 + OBJECT_BASKETBALL_VISIBLE_DUNK_MASTER: 'CommonBuffId' = 146885 + OBJECT_BASKETBALL_VISIBLE_GOOD_GAME: 'CommonBuffId' = 146887 + OBJECT_BASKETBALL_VISIBLE_HOT_LIKE_CURRY: 'CommonBuffId' = 146874 + OBJECT_BASKETBALL_VISIBLE_HOW_COULD_I_LOSE: 'CommonBuffId' = 146888 + OBJECT_BASKETBALL_VISIBLE_IN_THE_ZONE: 'CommonBuffId' = 146875 + OBJECT_BASKETBALL_VISIBLE_MASSIVE_DUNK: 'CommonBuffId' = 146880 + OBJECT_BASKETBALL_VISIBLE_ON_FIRE: 'CommonBuffId' = 146884 + OBJECT_BASKETBALL_VISIBLE_SPRAINED_ANKLE: 'CommonBuffId' = 146881 + OBJECT_BATHTUB_BABY_SOFT_SKIN: 'CommonBuffId' = 120480 + OBJECT_BATHTUB_BABY_SOFT_SKIN_INCENSE: 'CommonBuffId' = 120493 + OBJECT_BATHTUB_BUBBLES: 'CommonBuffId' = 12474 + OBJECT_BATHTUB_CLEAN_COAT: 'CommonBuffId' = 99511 + OBJECT_BATHTUB_FACE_MASK_HIDDEN: 'CommonBuffId' = 120486 + OBJECT_BATHTUB_FACE_MASK_HIDDEN_CHILD: 'CommonBuffId' = 146845 + OBJECT_BATHTUB_INFANT_BATH_BABY_BATH: 'CommonBuffId' = 273904 + OBJECT_BATHTUB_INFANT_BATH_BUBBLES: 'CommonBuffId' = 273908 + OBJECT_BATHTUB_INFANT_BATH_BUBBLES_VFX: 'CommonBuffId' = 283706 + OBJECT_BATHTUB_INFANT_BATH_BUBBLE_WATER_BABY: 'CommonBuffId' = 326409 + OBJECT_BATHTUB_INFANT_BATH_SOAKING_WET: 'CommonBuffId' = 273905 + OBJECT_BATHTUB_INFANT_BATH_WATER_BABY: 'CommonBuffId' = 273906 + OBJECT_BATHTUB_LIME_AND_SHINE: 'CommonBuffId' = 120482 + OBJECT_BATHTUB_LIME_AND_SHINE_INCENSE: 'CommonBuffId' = 120494 + OBJECT_BATHTUB_LOW_QUALITY: 'CommonBuffId' = 39241 + OBJECT_BATHTUB_PLAY: 'CommonBuffId' = 8231 + OBJECT_BATHTUB_RELAX: 'CommonBuffId' = 12476 + OBJECT_BATHTUB_RELAXING_LAVENDER: 'CommonBuffId' = 120481 + OBJECT_BATHTUB_RELAXING_LAVENDER_INCENSE: 'CommonBuffId' = 120495 + OBJECT_BATHTUB_RESTORATIVE_SOAK: 'CommonBuffId' = 120483 + OBJECT_BATHTUB_RESTORATIVE_SOAK_INCENSE: 'CommonBuffId' = 120496 + OBJECT_BATHTUB_ROSE_SCENTED_GARDEN: 'CommonBuffId' = 120484 + OBJECT_BATHTUB_ROSE_SCENTED_GARDEN_INCENSE: 'CommonBuffId' = 120497 + OBJECT_BATHTUB_SMELLS_LIKE_FLOWERS: 'CommonBuffId' = 120485 + OBJECT_BATHTUB_SMELLS_LIKE_FLOWERS_INCENSE: 'CommonBuffId' = 120498 + OBJECT_BATHTUB_TODDLER_BATH_BATH_TIME: 'CommonBuffId' = 150535 + OBJECT_BATHTUB_TODDLER_BATH_BUBBLE_FUN: 'CommonBuffId' = 150809 + OBJECT_BATHTUB_TODDLER_BATH_SPLASHY_SPLASHY: 'CommonBuffId' = 150537 + OBJECT_BATHTUB_TODDLER_BATH_TODDLER_SOAKING: 'CommonBuffId' = 150538 + OBJECT_BATHTUB_TODDLER_BATH_WATER_FUN: 'CommonBuffId' = 150536 + OBJECT_BATHTUB_WATER_HEATER_COLD: 'CommonBuffId' = 353062 + OBJECT_BATHTUB_WATER_HEATER_COLD_IP: 'CommonBuffId' = 353558 + OBJECT_BATHTUB_WATER_HEATER_COLD_IP_TIMED: 'CommonBuffId' = 354746 + OBJECT_BATHTUB_WATER_HEATER_COLD_TIMED: 'CommonBuffId' = 354745 + OBJECT_BATHTUB_WHIRLPOOL_RELAX: 'CommonBuffId' = 77316 + OBJECT_BATTLE_STATION_CANT_WIN_THEM_ALL: 'CommonBuffId' = 135135 + OBJECT_BATTLE_STATION_CLOSE_BATTLE: 'CommonBuffId' = 135134 + OBJECT_BATTLE_STATION_LOST_A_BATTLE: 'CommonBuffId' = 135137 + OBJECT_BATTLE_STATION_SHOULD_HAVE_WON: 'CommonBuffId' = 135136 + OBJECT_BATTLE_STATION_VICTOR: 'CommonBuffId' = 135133 + OBJECT_BED_MONSTER_UNDER_ENERGIZED_MONSTER_FRIEND: 'CommonBuffId' = 136465 + OBJECT_BED_MONSTER_UNDER_INTERRUPT_SLEEP: 'CommonBuffId' = 138779 + OBJECT_BED_MONSTER_UNDER_NEED_A_HUG: 'CommonBuffId' = 139152 + OBJECT_BED_MONSTER_UNDER_SPRAYING_FOR_MONSTER: 'CommonBuffId' = 136899 + OBJECT_BED_MONSTER_UNDER_SPRAY_FOR_MONSTER: 'CommonBuffId' = 139102 + OBJECT_BED_SCARED: 'CommonBuffId' = 133589 + OBJECT_BED_WOOHOO_COOLDOWN: 'CommonBuffId' = 12482 + OBJECT_BILLS_ANGRY: 'CommonBuffId' = 24344 + OBJECT_BILLS_SAD: 'CommonBuffId' = 24345 + OBJECT_BIRD_FEEDER_BIRDS: 'CommonBuffId' = 140759 + OBJECT_BIRD_FEEDER_BIRD_WATCHING: 'CommonBuffId' = 140735 + OBJECT_BIRTHDAY_CAKE_BAKED_ONE_CAKE: 'CommonBuffId' = 34706 + OBJECT_BIRTHDAY_CAKE_CANDLES_LIT: 'CommonBuffId' = 100394 + OBJECT_BIRTHDAY_CAKE_CELEBRATE: 'CommonBuffId' = 28561 + OBJECT_BONFIRE_BURNING_SENSATION: 'CommonBuffId' = 124696 + OBJECT_BONFIRE_BURNT_ARM: 'CommonBuffId' = 124682 + OBJECT_BONFIRE_COZY_BONFIRE: 'CommonBuffId' = 121835 + OBJECT_BONFIRE_COZY_FLIRTY_BUFF: 'CommonBuffId' = 126901 + OBJECT_BONFIRE_DIED_A_LITTLE_ART: 'CommonBuffId' = 124551 + OBJECT_BONFIRE_DIED_A_LITTLE_BOOK: 'CommonBuffId' = 123670 + OBJECT_BONFIRE_DIED_A_LITTLE_FOOD: 'CommonBuffId' = 124548 + OBJECT_BONFIRE_DIED_A_LITTLE_MUSIC: 'CommonBuffId' = 124649 + OBJECT_BONFIRE_FEELING_CONFIDENT: 'CommonBuffId' = 124707 + OBJECT_BONFIRE_FEELING_PLAYFUL: 'CommonBuffId' = 124658 + OBJECT_BONFIRE_FIRE_DECAY_STOP: 'CommonBuffId' = 126588 + OBJECT_BONFIRE_HAPPY_TOY: 'CommonBuffId' = 124657 + OBJECT_BONFIRE_HOMEWORK_HAPPY: 'CommonBuffId' = 124736 + OBJECT_BONFIRE_NOT_HOT_ENOUGH: 'CommonBuffId' = 125597 + OBJECT_BONFIRE_SAD_TOY: 'CommonBuffId' = 124656 + OBJECT_BONFIRE_WHATS_THAT_SMELL: 'CommonBuffId' = 124636 + OBJECT_BONSAI_ONE_WITH_PLANT: 'CommonBuffId' = 24596 + OBJECT_BONSAI_VIEW_ANGRY: 'CommonBuffId' = 37481 + OBJECT_BONSAI_VIEW_BOTCHED: 'CommonBuffId' = 37482 + OBJECT_BONSAI_VIEW_FLIRTY: 'CommonBuffId' = 37476 + OBJECT_BONSAI_VIEW_GENERIC: 'CommonBuffId' = 37483 + OBJECT_BONSAI_VIEW_INSPIRED: 'CommonBuffId' = 37480 + OBJECT_BONSAI_VIEW_PLAYFUL: 'CommonBuffId' = 37477 + OBJECT_BOOK_BROWSE_BOOKS: 'CommonBuffId' = 76994 + OBJECT_BOOK_STIMULATING_READ: 'CommonBuffId' = 75802 + OBJECT_BOWLING_LANE_BOWLING_KING: 'CommonBuffId' = 159005 + OBJECT_BOWLING_LANE_GLOVE_SHOES: 'CommonBuffId' = 161855 + OBJECT_BOWLING_LANE_HIDDEN_CHEATS_ALWAYS_TRICK: 'CommonBuffId' = 158907 + OBJECT_BOWLING_LANE_HIDDEN_CHEATS_NEVER_FAIL: 'CommonBuffId' = 158903 + OBJECT_BOWLING_LANE_HIDDEN_PICKED_UP_BALL: 'CommonBuffId' = 158386 + OBJECT_BOWLING_LANE_HIDDEN_SHOT_FAILED: 'CommonBuffId' = 158834 + OBJECT_BOWLING_LANE_HIDDEN_TURN_TAKEN: 'CommonBuffId' = 163786 + OBJECT_BOWLING_LANE_HIGH_SKILL_ON_FIRE: 'CommonBuffId' = 160622 + OBJECT_BOWLING_LANE_MOONLIGHT_BOWLING: 'CommonBuffId' = 161270 + OBJECT_BOWLING_LANE_OVER_BOWLED: 'CommonBuffId' = 159004 + OBJECT_BOWLING_LANE_SHOES: 'CommonBuffId' = 161421 + OBJECT_BOWLING_LANE_SORE_ARMS: 'CommonBuffId' = 159003 + OBJECT_BOWLING_LANE_THEY_CHEATED: 'CommonBuffId' = 159006 + OBJECT_BOWLING_LANE_WATCH_BOWLING_MATCH: 'CommonBuffId' = 159002 + OBJECT_BOX_OF_KINDNESS_SEARCH_COOLDOWN: 'CommonBuffId' = 199167 + OBJECT_BRAMBLE_PATCH_FREAKED_OUT: 'CommonBuffId' = 107011 + OBJECT_BRAMBLE_PATCH_MAULED_BY_BEAR: 'CommonBuffId' = 107012 + OBJECT_BRAMBLE_PATCH_TICKS: 'CommonBuffId' = 107010 + OBJECT_BUBBLE_BLOWER_AUTONOMOUS_USE_COOLDOWN_HIDDEN: 'CommonBuffId' = 135246 + OBJECT_BUBBLE_BLOWER_FAMILIARITY_REACTION_COOLDOWN: 'CommonBuffId' = 134857 + OBJECT_BUBBLE_BLOWER_USE_1_DEFAULT_FAIL1: 'CommonBuffId' = 135241 + OBJECT_BUBBLE_BLOWER_USE_1_DEFAULT_FAIL2: 'CommonBuffId' = 135991 + OBJECT_BUBBLE_BLOWER_USE_1_DEFAULT_SUCCESS1: 'CommonBuffId' = 135238 + OBJECT_BUBBLE_BLOWER_USE_1_DEFAULT_SUCCESS2: 'CommonBuffId' = 135992 + OBJECT_BUBBLE_BLOWER_USE_2_WHITE_FAIL1: 'CommonBuffId' = 135239 + OBJECT_BUBBLE_BLOWER_USE_2_WHITE_FAIL2: 'CommonBuffId' = 138273 + OBJECT_BUBBLE_BLOWER_USE_2_WHITE_SUCCESS1: 'CommonBuffId' = 135240 + OBJECT_BUBBLE_BLOWER_USE_2_WHITE_SUCCESS2: 'CommonBuffId' = 138274 + OBJECT_BUBBLE_BLOWER_USE_3_BLUE_FAIL1: 'CommonBuffId' = 135309 + OBJECT_BUBBLE_BLOWER_USE_3_BLUE_FAIL2: 'CommonBuffId' = 136023 + OBJECT_BUBBLE_BLOWER_USE_3_BLUE_SUCCESS1: 'CommonBuffId' = 135306 + OBJECT_BUBBLE_BLOWER_USE_3_BLUE_SUCCESS2: 'CommonBuffId' = 136022 + OBJECT_BUBBLE_BLOWER_USE_4_RED_FAIL1: 'CommonBuffId' = 135308 + OBJECT_BUBBLE_BLOWER_USE_4_RED_FAIL2: 'CommonBuffId' = 138290 + OBJECT_BUBBLE_BLOWER_USE_4_RED_SUCCESS1: 'CommonBuffId' = 135310 + OBJECT_BUBBLE_BLOWER_USE_4_RED_SUCCESS2: 'CommonBuffId' = 138289 + OBJECT_BUBBLE_BLOWER_USE_5_GREEN_FAIL1: 'CommonBuffId' = 135324 + OBJECT_BUBBLE_BLOWER_USE_5_GREEN_FAIL2: 'CommonBuffId' = 136298 + OBJECT_BUBBLE_BLOWER_USE_5_GREEN_SUCCESS1: 'CommonBuffId' = 135311 + OBJECT_BUBBLE_BLOWER_USE_5_GREEN_SUCCESS2: 'CommonBuffId' = 136299 + OBJECT_BUBBLE_BLOWER_USE_6_PURPLE_FAIL1: 'CommonBuffId' = 135307 + OBJECT_BUBBLE_BLOWER_USE_6_PURPLE_FAIL2: 'CommonBuffId' = 138277 + OBJECT_BUBBLE_BLOWER_USE_6_PURPLE_SUCCESS1: 'CommonBuffId' = 135325 + OBJECT_BUBBLE_BLOWER_USE_6_PURPLE_SUCCESS2: 'CommonBuffId' = 138278 + OBJECT_BUBBLE_BLOWER_USE_7_DENSE_FAIL1: 'CommonBuffId' = 135326 + OBJECT_BUBBLE_BLOWER_USE_7_DENSE_FAIL2: 'CommonBuffId' = 138291 + OBJECT_BUBBLE_BLOWER_USE_7_DENSE_SUCCESS1: 'CommonBuffId' = 135327 + OBJECT_BUBBLE_BLOWER_USE_7_DENSE_SUCCESS2: 'CommonBuffId' = 138292 + OBJECT_BUBBLE_BLOWER_USE_8_NEON_FAIL: 'CommonBuffId' = 135410 + OBJECT_BUBBLE_BLOWER_USE_8_NEON_FAIL2: 'CommonBuffId' = 135990 + OBJECT_BUBBLE_BLOWER_USE_8_NEON_SUCCESS: 'CommonBuffId' = 135409 + OBJECT_BUBBLE_BLOWER_USE_8_NEON_SUCCESS2: 'CommonBuffId' = 135993 + OBJECT_BUBBLE_BLOWER_USE_9_YELLOW_FAIL1: 'CommonBuffId' = 135904 + OBJECT_BUBBLE_BLOWER_USE_9_YELLOW_FAIL2: 'CommonBuffId' = 138276 + OBJECT_BUBBLE_BLOWER_USE_9_YELLOW_SUCCESS1: 'CommonBuffId' = 135903 + OBJECT_BUBBLE_BLOWER_USE_9_YELLOW_SUCCESS2: 'CommonBuffId' = 138275 + OBJECT_BUBBLE_BLOWER_USING_HIDDEN: 'CommonBuffId' = 143874 + OBJECT_BUBBLE_BOTTLE_ANNOYED_BY_BUBBLES: 'CommonBuffId' = 145888 + OBJECT_BUBBLE_BOTTLE_AUTONOMOUS_COOLDOWN_HIDDEN: 'CommonBuffId' = 145889 + OBJECT_BUBBLE_BOTTLE_BUBBLES: 'CommonBuffId' = 145884 + OBJECT_BUBBLE_BOTTLE_BUBBLES_HOW_INTERESTING: 'CommonBuffId' = 145886 + OBJECT_BUBBLE_BOTTLE_WHEE_BUBBLES: 'CommonBuffId' = 145885 + OBJECT_BUBBLE_BOTTLE_WOAH_BUBBLES: 'CommonBuffId' = 145887 + OBJECT_CAMPFIRE_BURNT_ARM: 'CommonBuffId' = 101942 + OBJECT_CAMPFIRE_COZY_FIRE: 'CommonBuffId' = 102665 + OBJECT_CAMPFIRE_MMMM_MARSHMALLOW: 'CommonBuffId' = 105236 + OBJECT_CAMPFIRE_SMORE: 'CommonBuffId' = 105238 + OBJECT_CAMPING_BATHROOM_BUGGED: 'CommonBuffId' = 104846 + OBJECT_CANDLE_MAKING_STATION_CANDLE_AURA_ENERGIZED_1: 'CommonBuffId' = 236742 + OBJECT_CANDLE_MAKING_STATION_CANDLE_AURA_ENERGIZED_2: 'CommonBuffId' = 236743 + OBJECT_CANDLE_MAKING_STATION_CANDLE_AURA_FLIRTY_1: 'CommonBuffId' = 236738 + OBJECT_CANDLE_MAKING_STATION_CANDLE_AURA_FLIRTY_2: 'CommonBuffId' = 236739 + OBJECT_CANDLE_MAKING_STATION_CANDLE_AURA_FOCUSED_1: 'CommonBuffId' = 236740 + OBJECT_CANDLE_MAKING_STATION_CANDLE_AURA_FOCUSED_2: 'CommonBuffId' = 236741 + OBJECT_CANDLE_MAKING_STATION_CANDLE_AURA_HAPPY_1: 'CommonBuffId' = 236735 + OBJECT_CANDLE_MAKING_STATION_CANDLE_AURA_HAPPY_2: 'CommonBuffId' = 236736 + OBJECT_CANDLE_MAKING_STATION_CANDLE_AURA_PLAYFUL_1: 'CommonBuffId' = 236744 + OBJECT_CANDLE_MAKING_STATION_CANDLE_AURA_SAD_1: 'CommonBuffId' = 236745 + OBJECT_CANDLE_MAKING_STATION_CANDLE_AURA_SAD_2: 'CommonBuffId' = 236737 + OBJECT_CANDY_BOWL_BOWL_OF_FRIGHTS_HAPPY: 'CommonBuffId' = 124902 + OBJECT_CANDY_BOWL_BOWL_OF_FRIGHTS_STRESSFUL: 'CommonBuffId' = 124903 + OBJECT_CARD_GAME_FOCUSED: 'CommonBuffId' = 9513 + OBJECT_CARD_GAME_LOSE1: 'CommonBuffId' = 9580 + OBJECT_CARD_GAME_LOSE2: 'CommonBuffId' = 9581 + OBJECT_CARD_GAME_LOSE3: 'CommonBuffId' = 9582 + OBJECT_CARD_GAME_WIN1: 'CommonBuffId' = 9576 + OBJECT_CARD_GAME_WIN2: 'CommonBuffId' = 9583 + OBJECT_CEILING_FAN_COOLING: 'CommonBuffId' = 210313 + OBJECT_CEILING_FAN_DRYING: 'CommonBuffId' = 210312 + OBJECT_CHAIR_IS_SITTING: 'CommonBuffId' = 12490 + OBJECT_CHEMISTRY_LAB_INTERESTING_RESULTS: 'CommonBuffId' = 105415 + OBJECT_CHEMISTRY_LAB_TOXIC_FUMES: 'CommonBuffId' = 105417 + OBJECT_CHEMISTRY_LAB_WHY_WONT_IT_WORK: 'CommonBuffId' = 105416 + OBJECT_CHESS_TABLE_PONDER: 'CommonBuffId' = 39970 + OBJECT_CHESS_TABLE_WIN: 'CommonBuffId' = 28209 + OBJECT_CHESS_TABLE_WIN_HIGH_LOGIC: 'CommonBuffId' = 28210 + OBJECT_CLAY_BLOB_INSPIRED: 'CommonBuffId' = 39930 + OBJECT_CLOSET_BREAKING_THROUGH: 'CommonBuffId' = 125375 + OBJECT_CLOSET_CLOSET_CHAOS: 'CommonBuffId' = 129060 + OBJECT_CLOSET_CONSOLE_COOLDOWN_HIDDEN: 'CommonBuffId' = 130145 + OBJECT_CLOSET_FASHION_RECOGNIZED: 'CommonBuffId' = 125382 + OBJECT_CLOSET_FASHION_SCORN: 'CommonBuffId' = 125392 + OBJECT_CLOSET_HUNG_UP: 'CommonBuffId' = 125393 + OBJECT_CLOSET_LEAVE_CLOSET_AFTER_CONSOLE: 'CommonBuffId' = 130315 + OBJECT_CLOSET_LOVE_STRANGE_PLACES: 'CommonBuffId' = 125377 + OBJECT_CLOSET_OUTFIT_TRACKER_BUFFS_ATHLETIC: 'CommonBuffId' = 121916 + OBJECT_CLOSET_OUTFIT_TRACKER_BUFFS_COLD_WEATHER: 'CommonBuffId' = 192477 + OBJECT_CLOSET_OUTFIT_TRACKER_BUFFS_EVERYDAY: 'CommonBuffId' = 121914 + OBJECT_CLOSET_OUTFIT_TRACKER_BUFFS_FAIL: 'CommonBuffId' = 121920 + OBJECT_CLOSET_OUTFIT_TRACKER_BUFFS_FORMAL: 'CommonBuffId' = 121915 + OBJECT_CLOSET_OUTFIT_TRACKER_BUFFS_HOT_WEATHER: 'CommonBuffId' = 192476 + OBJECT_CLOSET_OUTFIT_TRACKER_BUFFS_PARTY: 'CommonBuffId' = 121918 + OBJECT_CLOSET_OUTFIT_TRACKER_BUFFS_SLEEPWEAR: 'CommonBuffId' = 121917 + OBJECT_CLOSET_OUTFIT_TRACKER_BUFFS_SWIM: 'CommonBuffId' = 121919 + OBJECT_CLOSET_SEE_OUTFIT_COOLDOWN_ATHLETIC: 'CommonBuffId' = 129001 + OBJECT_CLOSET_SEE_OUTFIT_COOLDOWN_COLD_WEATHER: 'CommonBuffId' = 186304 + OBJECT_CLOSET_SEE_OUTFIT_COOLDOWN_EVERYDAY: 'CommonBuffId' = 129002 + OBJECT_CLOSET_SEE_OUTFIT_COOLDOWN_FORMAL: 'CommonBuffId' = 129003 + OBJECT_CLOSET_SEE_OUTFIT_COOLDOWN_HOT_WEATHER: 'CommonBuffId' = 186305 + OBJECT_CLOSET_SEE_OUTFIT_COOLDOWN_PARTY: 'CommonBuffId' = 129004 + OBJECT_CLOSET_SEE_OUTFIT_COOLDOWN_SLEEP: 'CommonBuffId' = 129005 + OBJECT_CLOSET_SEE_OUTFIT_COOLDOWN_SWIM: 'CommonBuffId' = 129006 + OBJECT_CLOSET_TRY_NEW_OUTFIT_KEEP_OUTFIT: 'CommonBuffId' = 121122 + OBJECT_CLOSET_VENUE_WOOHOO_EXHILERATING: 'CommonBuffId' = 377110 + OBJECT_COFFEE_CAFFEINE0: 'CommonBuffId' = 100835 + OBJECT_COFFEE_CAFFEINE1: 'CommonBuffId' = 12492 + OBJECT_COFFEE_CAFFEINE2: 'CommonBuffId' = 99749 + OBJECT_COFFEE_CART_LINGERING_FLAVOR_CONFIDENT: 'CommonBuffId' = 225265 + OBJECT_COFFEE_CART_LINGERING_FLAVOR_FOCUSED: 'CommonBuffId' = 225266 + OBJECT_COFFEE_CART_LINGERING_FLAVOR_INSPIRED: 'CommonBuffId' = 225268 + OBJECT_COFFEE_CART_LINGERING_FLAVOR_PLAYFUL: 'CommonBuffId' = 225267 + OBJECT_COFFEE_OVERLOAD: 'CommonBuffId' = 99783 + OBJECT_COFFIN_HIBERNATE: 'CommonBuffId' = 149961 + OBJECT_COFFIN_NON_VAMPIRE: 'CommonBuffId' = 149984 + OBJECT_COLLECTIBLES_FASCINATING_SPECIMEN: 'CommonBuffId' = 40109 + OBJECT_COMPUTER_BRAIN_FRIED: 'CommonBuffId' = 36129 + OBJECT_COMPUTER_EPIC_GAME: 'CommonBuffId' = 33114 + OBJECT_COMPUTER_EXCUSE_NOTE_COOLDOWN: 'CommonBuffId' = 100437 + OBJECT_COMPUTER_FOCUSED_RESEARCH_SIMPEDIA: 'CommonBuffId' = 31038 + OBJECT_COMPUTER_HIGH_SCORE: 'CommonBuffId' = 30991 + OBJECT_COMPUTER_INSPIRING_ART: 'CommonBuffId' = 40075 + OBJECT_COMPUTER_MAKE_CONNECTIONS_COOLDOWN: 'CommonBuffId' = 99637 + OBJECT_COMPUTER_PICK_UP_LINES: 'CommonBuffId' = 40080 + OBJECT_COMPUTER_PROGRAMMING_SKILL_ACCOMPLISHED: 'CommonBuffId' = 31591 + OBJECT_COMPUTER_PROGRAMMING_SKILL_FEELING_DEVIOUS: 'CommonBuffId' = 33268 + OBJECT_COMPUTER_PROGRAMMING_SKILL_JOB_WELL_DONE: 'CommonBuffId' = 33241 + OBJECT_COMPUTER_RESEARCH_IDIOMS_BORED: 'CommonBuffId' = 37238 + OBJECT_COMPUTER_RESEARCH_IDIOMS_INSPIRED: 'CommonBuffId' = 37236 + OBJECT_COMPUTER_RESPOND_TO_MAIL_NEGATIVE_CRITICISM: 'CommonBuffId' = 136551 + OBJECT_COMPUTER_RESPOND_TO_MAIL_POSITIVE_FEEDBACK: 'CommonBuffId' = 136550 + OBJECT_COMPUTER_RESPOND_TO_MAIL_TROLLED: 'CommonBuffId' = 136552 + OBJECT_COMPUTER_WATCH_SIM_TUBE_PLAYFUL: 'CommonBuffId' = 37223 + OBJECT_COOLER_REFRESHINGLY_COOL: 'CommonBuffId' = 102142 + OBJECT_COZY_FIRE: 'CommonBuffId' = 75075 + OBJECT_CRAFT_SALES_TABLE_AUTONOMY_MOD_BROWSE: 'CommonBuffId' = 145279 + OBJECT_CRAFT_SALES_TABLE_AUTONOMY_MOD_BROWSE_ONLY_SCORED: 'CommonBuffId' = 256565 + OBJECT_CRAFT_SALES_TABLE_AUTONOMY_MOD_CLOSE: 'CommonBuffId' = 147530 + OBJECT_CRAFT_SALES_TABLE_AUTONOMY_MOD_CREATE_ITEMS: 'CommonBuffId' = 148007 + OBJECT_CRAFT_SALES_TABLE_AUTONOMY_MOD_STOCK: 'CommonBuffId' = 146946 + OBJECT_CRAFT_SALES_TABLE_AUTONOMY_MOD_STOCK_PAINTINGS: 'CommonBuffId' = 154454 + OBJECT_CRAFT_SALES_TABLE_AUTONOMY_MOD_STOCK_PAINTINGS_STAFFED_ONLY: 'CommonBuffId' = 238446 + OBJECT_CRAFT_SALES_TABLE_AUTONOMY_MOD_STOCK_STAFFED_ONLY: 'CommonBuffId' = 238445 + OBJECT_CRAFT_SALES_TABLE_AUTONOMY_MOD_TEND: 'CommonBuffId' = 145287 + OBJECT_CRAFT_SALES_TABLE_HAGGLE_SUCCEED: 'CommonBuffId' = 145222 + OBJECT_CRAFT_SALES_TABLE_HIGHER_BUY_CHANCE: 'CommonBuffId' = 145274 + OBJECT_CRYSTAL_HELMET_DEBUFFS_ANGRY: 'CommonBuffId' = 194329 + OBJECT_CRYSTAL_HELMET_DEBUFFS_BORED: 'CommonBuffId' = 194305 + OBJECT_CRYSTAL_HELMET_DEBUFFS_EMBARRASSED: 'CommonBuffId' = 194306 + OBJECT_CRYSTAL_HELMET_DEBUFFS_SAD: 'CommonBuffId' = 194307 + OBJECT_CRYSTAL_HELMET_DEBUFFS_STRESSED: 'CommonBuffId' = 194304 + OBJECT_CRYSTAL_HELMET_DEBUFFS_UNCOMFORTABLE: 'CommonBuffId' = 194308 + OBJECT_CRYSTAL_HELMET_DESTROY_CRYSTAL: 'CommonBuffId' = 193352 + OBJECT_CRYSTAL_HELMET_EMBARRASSED_BY_VIEWER: 'CommonBuffId' = 198603 + OBJECT_CRYSTAL_HELMET_HAPPY_FROM_PROXIMITY_RAINBORZ: 'CommonBuffId' = 194859 + OBJECT_CRYSTAL_HELMET_MOTIVE_TANK_BLADDER: 'CommonBuffId' = 196663 + OBJECT_CRYSTAL_HELMET_MOTIVE_TANK_FUN: 'CommonBuffId' = 196664 + OBJECT_CRYSTAL_HELMET_MOTIVE_TANK_HUNGER: 'CommonBuffId' = 193558 + OBJECT_CRYSTAL_HELMET_MOTIVE_TANK_HYGIENE: 'CommonBuffId' = 196665 + OBJECT_CRYSTAL_HELMET_MOTIVE_TANK_PLANT_SIM_WATER: 'CommonBuffId' = 196666 + OBJECT_CRYSTAL_HELMET_MOTIVE_TANK_SOCIAL: 'CommonBuffId' = 196667 + OBJECT_CRYSTAL_HELMET_MOTIVE_TANK_VAMPIRE_POWER: 'CommonBuffId' = 196668 + OBJECT_CRYSTAL_HELMET_MOTIVE_TANK_VAMPIRE_THIRST: 'CommonBuffId' = 196669 + OBJECT_CRYSTAL_HELMET_REMOVE_QUIRK: 'CommonBuffId' = 200842 + OBJECT_CRYSTAL_HELMET_TRAITS_ALABASTER: 'CommonBuffId' = 193945 + OBJECT_CRYSTAL_HELMET_TRAITS_ALEXANDRITE_EP: 'CommonBuffId' = 193955 + OBJECT_CRYSTAL_HELMET_TRAITS_AMAZONITE_EP: 'CommonBuffId' = 193956 + OBJECT_CRYSTAL_HELMET_TRAITS_AMETHYST: 'CommonBuffId' = 193553 + OBJECT_CRYSTAL_HELMET_TRAITS_CITRINE: 'CommonBuffId' = 193957 + OBJECT_CRYSTAL_HELMET_TRAITS_CRANDESTINE_EP: 'CommonBuffId' = 193958 + OBJECT_CRYSTAL_HELMET_TRAITS_DIAMOND: 'CommonBuffId' = 193959 + OBJECT_CRYSTAL_HELMET_TRAITS_EMERALD: 'CommonBuffId' = 193960 + OBJECT_CRYSTAL_HELMET_TRAITS_FIRE_OPAL: 'CommonBuffId' = 193961 + OBJECT_CRYSTAL_HELMET_TRAITS_HEMATITE: 'CommonBuffId' = 193962 + OBJECT_CRYSTAL_HELMET_TRAITS_JET: 'CommonBuffId' = 193963 + OBJECT_CRYSTAL_HELMET_TRAITS_JONQUILYST: 'CommonBuffId' = 193964 + OBJECT_CRYSTAL_HELMET_TRAITS_NITELITE_EP: 'CommonBuffId' = 193965 + OBJECT_CRYSTAL_HELMET_TRAITS_ORANGE_TOPAZ: 'CommonBuffId' = 193966 + OBJECT_CRYSTAL_HELMET_TRAITS_PEACH: 'CommonBuffId' = 193967 + OBJECT_CRYSTAL_HELMET_TRAITS_PLUMBITE: 'CommonBuffId' = 193968 + OBJECT_CRYSTAL_HELMET_TRAITS_QUARTZ: 'CommonBuffId' = 193969 + OBJECT_CRYSTAL_HELMET_TRAITS_RAINBORZ: 'CommonBuffId' = 193970 + OBJECT_CRYSTAL_HELMET_TRAITS_ROSE: 'CommonBuffId' = 193971 + OBJECT_CRYSTAL_HELMET_TRAITS_RUBY: 'CommonBuffId' = 193972 + OBJECT_CRYSTAL_HELMET_TRAITS_SAPPHIRE: 'CommonBuffId' = 193973 + OBJECT_CRYSTAL_HELMET_TRAITS_SHINALITE: 'CommonBuffId' = 193974 + OBJECT_CRYSTAL_HELMET_TRAITS_SIMANITE: 'CommonBuffId' = 193975 + OBJECT_CRYSTAL_HELMET_TRAITS_TURQUOISE: 'CommonBuffId' = 193976 + OBJECT_CRYSTAL_HELMET_VFX_ADULT_ALABASTER: 'CommonBuffId' = 196573 + OBJECT_CRYSTAL_HELMET_VFX_ADULT_ALEXANDRITE_EP: 'CommonBuffId' = 196566 + OBJECT_CRYSTAL_HELMET_VFX_ADULT_AMAZONITE_EP: 'CommonBuffId' = 196580 + OBJECT_CRYSTAL_HELMET_VFX_ADULT_AMETHYST: 'CommonBuffId' = 196581 + OBJECT_CRYSTAL_HELMET_VFX_ADULT_CITRINE: 'CommonBuffId' = 196574 + OBJECT_CRYSTAL_HELMET_VFX_ADULT_CRANDESTINE_EP: 'CommonBuffId' = 196567 + OBJECT_CRYSTAL_HELMET_VFX_ADULT_DIAMOND: 'CommonBuffId' = 196582 + OBJECT_CRYSTAL_HELMET_VFX_ADULT_EMERALD: 'CommonBuffId' = 196575 + OBJECT_CRYSTAL_HELMET_VFX_ADULT_FIRE_OPAL: 'CommonBuffId' = 196583 + OBJECT_CRYSTAL_HELMET_VFX_ADULT_HEMATITE: 'CommonBuffId' = 196584 + OBJECT_CRYSTAL_HELMET_VFX_ADULT_JET: 'CommonBuffId' = 196568 + OBJECT_CRYSTAL_HELMET_VFX_ADULT_JONQUILYST: 'CommonBuffId' = 196569 + OBJECT_CRYSTAL_HELMET_VFX_ADULT_NITELITE_EP: 'CommonBuffId' = 196570 + OBJECT_CRYSTAL_HELMET_VFX_ADULT_ORANGE_TOPAZ: 'CommonBuffId' = 196576 + OBJECT_CRYSTAL_HELMET_VFX_ADULT_PEACH: 'CommonBuffId' = 196585 + OBJECT_CRYSTAL_HELMET_VFX_ADULT_PLUMBITE: 'CommonBuffId' = 196571 + OBJECT_CRYSTAL_HELMET_VFX_ADULT_QUARTZ: 'CommonBuffId' = 196577 + OBJECT_CRYSTAL_HELMET_VFX_ADULT_RAINBORZ: 'CommonBuffId' = 196572 + OBJECT_CRYSTAL_HELMET_VFX_ADULT_ROSE: 'CommonBuffId' = 196578 + OBJECT_CRYSTAL_HELMET_VFX_ADULT_RUBY: 'CommonBuffId' = 196586 + OBJECT_CRYSTAL_HELMET_VFX_ADULT_SAPPHIRE: 'CommonBuffId' = 196587 + OBJECT_CRYSTAL_HELMET_VFX_ADULT_SHINALITE: 'CommonBuffId' = 196588 + OBJECT_CRYSTAL_HELMET_VFX_ADULT_SIMANITE: 'CommonBuffId' = 196589 + OBJECT_CRYSTAL_HELMET_VFX_ADULT_TURQUOISE: 'CommonBuffId' = 196579 + OBJECT_CRYSTAL_HELMET_VFX_CHILD_ALABASTER: 'CommonBuffId' = 196590 + OBJECT_CRYSTAL_HELMET_VFX_CHILD_ALEXANDRITE_EP: 'CommonBuffId' = 196591 + OBJECT_CRYSTAL_HELMET_VFX_CHILD_AMAZONITE_EP: 'CommonBuffId' = 196592 + OBJECT_CRYSTAL_HELMET_VFX_CHILD_AMETHYST: 'CommonBuffId' = 196593 + OBJECT_CRYSTAL_HELMET_VFX_CHILD_CITRINE: 'CommonBuffId' = 196594 + OBJECT_CRYSTAL_HELMET_VFX_CHILD_CRANDESTINE_EP: 'CommonBuffId' = 196595 + OBJECT_CRYSTAL_HELMET_VFX_CHILD_DIAMOND: 'CommonBuffId' = 196596 + OBJECT_CRYSTAL_HELMET_VFX_CHILD_EMERALD: 'CommonBuffId' = 196597 + OBJECT_CRYSTAL_HELMET_VFX_CHILD_FIRE_OPAL: 'CommonBuffId' = 196598 + OBJECT_CRYSTAL_HELMET_VFX_CHILD_HEMATITE: 'CommonBuffId' = 196599 + OBJECT_CRYSTAL_HELMET_VFX_CHILD_JET: 'CommonBuffId' = 196600 + OBJECT_CRYSTAL_HELMET_VFX_CHILD_JONQUILYST: 'CommonBuffId' = 196601 + OBJECT_CRYSTAL_HELMET_VFX_CHILD_NITELITE_EP: 'CommonBuffId' = 196602 + OBJECT_CRYSTAL_HELMET_VFX_CHILD_ORANGE_TOPAZ: 'CommonBuffId' = 196603 + OBJECT_CRYSTAL_HELMET_VFX_CHILD_PEACH: 'CommonBuffId' = 196604 + OBJECT_CRYSTAL_HELMET_VFX_CHILD_PLUMBITE: 'CommonBuffId' = 196605 + OBJECT_CRYSTAL_HELMET_VFX_CHILD_QUARTZ: 'CommonBuffId' = 196606 + OBJECT_CRYSTAL_HELMET_VFX_CHILD_RAINBORZ: 'CommonBuffId' = 196607 + OBJECT_CRYSTAL_HELMET_VFX_CHILD_ROSE: 'CommonBuffId' = 196608 + OBJECT_CRYSTAL_HELMET_VFX_CHILD_RUBY: 'CommonBuffId' = 196609 + OBJECT_CRYSTAL_HELMET_VFX_CHILD_SAPPHIRE: 'CommonBuffId' = 196610 + OBJECT_CRYSTAL_HELMET_VFX_CHILD_SHINALITE: 'CommonBuffId' = 196611 + OBJECT_CRYSTAL_HELMET_VFX_CHILD_SIMANITE: 'CommonBuffId' = 196612 + OBJECT_CRYSTAL_HELMET_VFX_CHILD_TURQUOISE: 'CommonBuffId' = 196613 + OBJECT_CRYSTAL_HELMET_WEARING: 'CommonBuffId' = 192776 + OBJECT_CRYSTAL_HELMET_WEARING_INCOMPATIBLE_OUTFIT_BG: 'CommonBuffId' = 198617 + OBJECT_DANCE_FLOOR_DANCE_BATTLE_COMPLETE: 'CommonBuffId' = 129315 + OBJECT_DANCE_FLOOR_GROUP_DANCE_POSITIVE: 'CommonBuffId' = 128898 + OBJECT_DANCE_FLOOR_SHOW_OFF_MOVES_NEGATIVE: 'CommonBuffId' = 125319 + OBJECT_DANCE_FLOOR_SHOW_OFF_MOVES_NEUTRAL: 'CommonBuffId' = 128293 + OBJECT_DANCE_FLOOR_SHOW_OFF_MOVES_PERFORMER: 'CommonBuffId' = 125498 + OBJECT_DANCE_FLOOR_SHOW_OFF_MOVES_POSITIVE: 'CommonBuffId' = 125318 + OBJECT_DANCE_FLOOR_SHOW_OFF_MOVES_WATCHER: 'CommonBuffId' = 125499 + OBJECT_DARTBOARD_BULLS_EYE: 'CommonBuffId' = 128291 + OBJECT_DARTBOARD_DART_VICTORY: 'CommonBuffId' = 128481 + OBJECT_DARTBOARD_OFF_TARGET: 'CommonBuffId' = 128292 + OBJECT_DARTBOARD_SORE_LOSER: 'CommonBuffId' = 128480 + OBJECT_DARTBOARD_TAKING_A_TURN: 'CommonBuffId' = 127951 + OBJECT_DARTBOARD_WAITING_FOR_TURN: 'CommonBuffId' = 130245 + OBJECT_DJ_BOOTH_BUMP_IN_BEATS: 'CommonBuffId' = 122759 + OBJECT_DJ_BOOTH_FEEL_THE_CROWD_CONFIDENT: 'CommonBuffId' = 122749 + OBJECT_DJ_BOOTH_FEEL_THE_CROWD_DAZED: 'CommonBuffId' = 122747 + OBJECT_DJ_BOOTH_FEEL_THE_CROWD_ENERGIZED: 'CommonBuffId' = 122712 + OBJECT_DJ_BOOTH_FEEL_THE_CROWD_FLIRTY: 'CommonBuffId' = 122748 + OBJECT_DJ_BOOTH_FEEL_THE_CROWD_VFX: 'CommonBuffId' = 128367 + OBJECT_DJ_BOOTH_HIDDEN_CROWD_MEMBER: 'CommonBuffId' = 122968 + OBJECT_DJ_BOOTH_HIDDEN_DJ_PERFORMING: 'CommonBuffId' = 122685 + OBJECT_DJ_BOOTH_HIDDEN_DJ_PRACTICING: 'CommonBuffId' = 123910 + OBJECT_DJ_BOOTH_HIDDEN_FEEL_THE_CROWD_COOLDOWN: 'CommonBuffId' = 122756 + OBJECT_DJ_BOOTH_HIDDEN_GET_HYPED_COOLDOWN: 'CommonBuffId' = 122842 + OBJECT_DJ_BOOTH_HIDDEN_JUST_TIPPED: 'CommonBuffId' = 130613 + OBJECT_DJ_BOOTH_HIDDEN_TIPS_COLLECTED: 'CommonBuffId' = 128097 + OBJECT_DJ_BOOTH_IM_ADJ: 'CommonBuffId' = 122760 + OBJECT_DJ_BOOTH_MIX_MASTER: 'CommonBuffId' = 126112 + OBJECT_DJ_BOOTH_SERIOUS_SONIC_SKILLS: 'CommonBuffId' = 122758 + OBJECT_DJ_BOOTH_TERRIBLE_TURNTABLISM: 'CommonBuffId' = 122762 + OBJECT_DJ_BOOTH_UNCE_UNCE_UGH: 'CommonBuffId' = 122761 + OBJECT_DOLLHOUSE_ACT_OF_KINDNESS: 'CommonBuffId' = 32287 + OBJECT_DOLLHOUSE_DESTRUCTIVE_TODDLER_HAPPY: 'CommonBuffId' = 333447 + OBJECT_DOLLHOUSE_INSPIRED: 'CommonBuffId' = 30897 + OBJECT_DOLLHOUSE_INSPIRED_STAT_MOD: 'CommonBuffId' = 75731 + OBJECT_DOLLHOUSE_PLAYED_WITH: 'CommonBuffId' = 38797 + OBJECT_DOLLHOUSE_WICKED_ACT: 'CommonBuffId' = 30929 + OBJECT_DONE_PONDERING_HIDDEN: 'CommonBuffId' = 40570 + OBJECT_DONT_WAKE_LLAMA_KEEP_PLAYING: 'CommonBuffId' = 130259 + OBJECT_DONT_WAKE_LLAMA_LEFT_CHALLENGE: 'CommonBuffId' = 129595 + OBJECT_DONT_WAKE_LLAMA_LLAMA_ALMOST_FELL: 'CommonBuffId' = 127830 + OBJECT_DONT_WAKE_LLAMA_LLAMA_CRIES_SAD: 'CommonBuffId' = 127832 + OBJECT_DONT_WAKE_LLAMA_LLAMA_SLEEPS_HAPPY: 'CommonBuffId' = 127831 + OBJECT_DONT_WAKE_LLAMA_LOSE_CHALLENGE: 'CommonBuffId' = 129585 + OBJECT_DONT_WAKE_LLAMA_STOP_PLAYING: 'CommonBuffId' = 130067 + OBJECT_DRESSER_TRY_ON_OUTFITS: 'CommonBuffId' = 40131 + OBJECT_DRINK_ALIEN_JUICE_ENERGIZED: 'CommonBuffId' = 33746 + OBJECT_DRINK_ALIEN_JUICE_SOCIAL_MOTIVE: 'CommonBuffId' = 33747 + OBJECT_DRINK_ALIEN_JUICE_SOCIAL_SUCCESS: 'CommonBuffId' = 33748 + OBJECT_DRINK_BARTENDING_0: 'CommonBuffId' = 10402 + OBJECT_DRINK_BARTENDING_0_FOODIE: 'CommonBuffId' = 27401 + OBJECT_DRINK_BARTENDING_2: 'CommonBuffId' = 10404 + OBJECT_DRINK_BARTENDING_2_FLAMING: 'CommonBuffId' = 35019 + OBJECT_DRINK_BARTENDING_2_FOODIE: 'CommonBuffId' = 27402 + OBJECT_DRINK_BARTENDING_3: 'CommonBuffId' = 10405 + OBJECT_DRINK_BARTENDING_3_FLAMING: 'CommonBuffId' = 35068 + OBJECT_DRINK_BARTENDING_3_FOODIE: 'CommonBuffId' = 27403 + OBJECT_DRINK_BARTENDING_4: 'CommonBuffId' = 10406 + OBJECT_DRINK_BARTENDING_4_FLAMING: 'CommonBuffId' = 35069 + OBJECT_DRINK_BARTENDING_4_FOODIE: 'CommonBuffId' = 27404 + OBJECT_DRINK_BATUU_DAGOBAH_SLUG_SLINGER: 'CommonBuffId' = 237756 + OBJECT_DRINK_BATUU_FUZZY_TAUN_TAUN: 'CommonBuffId' = 237755 + OBJECT_DRINK_BATUU_JET_JUICE_BAD: 'CommonBuffId' = 237758 + OBJECT_DRINK_BATUU_JET_JUICE_GOOD: 'CommonBuffId' = 237757 + OBJECT_DRINK_BEETLE_JUICE_1_INVISIBLE: 'CommonBuffId' = 235883 + OBJECT_DRINK_BEETLE_JUICE_2_VISIBLE: 'CommonBuffId' = 235884 + OBJECT_DRINK_BEETLE_JUICE_4_VISIBLE: 'CommonBuffId' = 237484 + OBJECT_DRINK_BOILER_ROOM_ANGRY_HIGH: 'CommonBuffId' = 73913 + OBJECT_DRINK_BOILER_ROOM_ANGRY_LOW: 'CommonBuffId' = 73912 + OBJECT_DRINK_CREATIVE: 'CommonBuffId' = 26346 + OBJECT_DRINK_CUPID_JUICE_FLIRTY_HIGH: 'CommonBuffId' = 73915 + OBJECT_DRINK_CUPID_JUICE_FLIRTY_LOW: 'CommonBuffId' = 73914 + OBJECT_DRINK_DYED_COCKTAIL_EMBARRASSED: 'CommonBuffId' = 235886 + OBJECT_DRINK_DYED_COCKTAIL_HAPPY: 'CommonBuffId' = 235885 + OBJECT_DRINK_FIZZY_DRINK_HAPPY: 'CommonBuffId' = 118861 + OBJECT_DRINK_FLIRTY: 'CommonBuffId' = 26351 + OBJECT_DRINK_INTELLECTUAL: 'CommonBuffId' = 26347 + OBJECT_DRINK_PHYSICAL: 'CommonBuffId' = 26350 + OBJECT_DRINK_SCIENCE_TABLE_BORED: 'CommonBuffId' = 31738 + OBJECT_DRINK_SCIENCE_TABLE_CONFIDENT: 'CommonBuffId' = 31721 + OBJECT_DRINK_SCIENCE_TABLE_HAPPY: 'CommonBuffId' = 31737 + OBJECT_DRINK_SCIENCE_TABLE_UNCOMFORTABLE: 'CommonBuffId' = 31739 + OBJECT_DRINK_SNAGGLE_FLUSTER: 'CommonBuffId' = 76714 + OBJECT_DRINK_TEA_BLACK: 'CommonBuffId' = 8257 + OBJECT_DRINK_TEA_EARL: 'CommonBuffId' = 8440 + OBJECT_DRINK_TEA_GINSENG: 'CommonBuffId' = 8436 + OBJECT_DRINK_TEA_GREEN: 'CommonBuffId' = 8305 + OBJECT_DRINK_TEA_LEMON_HONEY_GINGER: 'CommonBuffId' = 118393 + OBJECT_DRINK_TEA_LEMON_HONEY_GINGER_NO_LOOT: 'CommonBuffId' = 272782 + OBJECT_DRINK_TEA_OOLONG: 'CommonBuffId' = 8432 + OBJECT_DRINK_TEA_YERBA_MATE: 'CommonBuffId' = 176983 + OBJECT_DRINK_TODDLER_HAPPY: 'CommonBuffId' = 144670 + OBJECT_DRINK_VILLAGER_HELP_FOCUSED: 'CommonBuffId' = 267494 + OBJECT_DRINK_VILLAGER_HELP_FOCUSED_SAMPLER: 'CommonBuffId' = 267495 + OBJECT_DRINK_VILLAGER_HELP_PLAYFUL: 'CommonBuffId' = 267492 + OBJECT_DRINK_VILLAGER_HELP_PLAYFUL_SAMPLER: 'CommonBuffId' = 267493 + OBJECT_EAR_BUDS_HIDDEN_COLOR_CHILD_BLACK: 'CommonBuffId' = 169300 + OBJECT_EAR_BUDS_HIDDEN_COLOR_CHILD_BLUE: 'CommonBuffId' = 169301 + OBJECT_EAR_BUDS_HIDDEN_COLOR_CHILD_GOLD: 'CommonBuffId' = 169302 + OBJECT_EAR_BUDS_HIDDEN_COLOR_CHILD_GREEN: 'CommonBuffId' = 169303 + OBJECT_EAR_BUDS_HIDDEN_COLOR_CHILD_ORANGE: 'CommonBuffId' = 169304 + OBJECT_EAR_BUDS_HIDDEN_COLOR_CHILD_PINK: 'CommonBuffId' = 169305 + OBJECT_EAR_BUDS_HIDDEN_COLOR_CHILD_RED: 'CommonBuffId' = 169306 + OBJECT_EAR_BUDS_HIDDEN_COLOR_CHILD_TEAL: 'CommonBuffId' = 169307 + OBJECT_EAR_BUDS_HIDDEN_COLOR_CHILD_WHITE: 'CommonBuffId' = 169308 + OBJECT_EAR_BUDS_HIDDEN_EAR_BUDS_COLOR_BLACK: 'CommonBuffId' = 168734 + OBJECT_EAR_BUDS_HIDDEN_EAR_BUDS_COLOR_BLUE: 'CommonBuffId' = 168733 + OBJECT_EAR_BUDS_HIDDEN_EAR_BUDS_COLOR_GOLD: 'CommonBuffId' = 168736 + OBJECT_EAR_BUDS_HIDDEN_EAR_BUDS_COLOR_GREEN: 'CommonBuffId' = 168737 + OBJECT_EAR_BUDS_HIDDEN_EAR_BUDS_COLOR_ORANGE: 'CommonBuffId' = 168735 + OBJECT_EAR_BUDS_HIDDEN_EAR_BUDS_COLOR_PINK: 'CommonBuffId' = 168738 + OBJECT_EAR_BUDS_HIDDEN_EAR_BUDS_COLOR_RED: 'CommonBuffId' = 168739 + OBJECT_EAR_BUDS_HIDDEN_EAR_BUDS_COLOR_TEAL: 'CommonBuffId' = 168740 + OBJECT_EAR_BUDS_HIDDEN_EAR_BUDS_COLOR_WHITE: 'CommonBuffId' = 168741 + OBJECT_EAR_BUDS_HIDDEN_LISTENING_TO_MUSIC: 'CommonBuffId' = 164760 + OBJECT_EAR_BUDS_HIDDEN_REACT_INTERRUPT_SLEEP: 'CommonBuffId' = 168545 + OBJECT_EASEL_CANVAS_CREATED: 'CommonBuffId' = 10678 + OBJECT_EASEL_PRACTICE_PAINTING: 'CommonBuffId' = 40762 + OBJECT_EAT_TOXIC_PLANTS_CHAMOMILE: 'CommonBuffId' = 107485 + OBJECT_EAT_TOXIC_PLANTS_ELDERBERRY: 'CommonBuffId' = 107483 + OBJECT_EAT_TOXIC_PLANTS_FIRE_LEAF: 'CommonBuffId' = 107484 + OBJECT_EAT_TOXIC_PLANTS_HUCKLEBERRY: 'CommonBuffId' = 107482 + OBJECT_EAT_TOXIC_PLANTS_MOREL: 'CommonBuffId' = 107486 + OBJECT_ESPRESSO_BRIGHT_EYED: 'CommonBuffId' = 122957 + OBJECT_ESPRESSO_CAFFEINATED: 'CommonBuffId' = 122949 + OBJECT_ESPRESSO_FREEDOM: 'CommonBuffId' = 122955 + OBJECT_ESPRESSO_FUN_EMPLOYED: 'CommonBuffId' = 122965 + OBJECT_ESPRESSO_MARKED_FOR_FUN: 'CommonBuffId' = 122952 + OBJECT_ESPRESSO_MMMM_CHOCOLATE: 'CommonBuffId' = 122954 + OBJECT_ESPRESSO_MMMM_PHENETHYLAMINE: 'CommonBuffId' = 122953 + OBJECT_ESPRESSO_NEW_DISCOVERY: 'CommonBuffId' = 122956 + OBJECT_ESPRESSO_SCALDED_MILK: 'CommonBuffId' = 124347 + OBJECT_ESPRESSO_SOPHISTICATED: 'CommonBuffId' = 122951 + OBJECT_ESPRESSO_WARM_COMFORT: 'CommonBuffId' = 122950 + OBJECT_EXAM_BED_DOCTOR_SOCIAL_RECLINED: 'CommonBuffId' = 114026 + OBJECT_EXAM_BED_DOCTOR_SOCIAL_SEATED: 'CommonBuffId' = 114025 + OBJECT_EXAM_BED_PATIENT_DISCHARGE: 'CommonBuffId' = 110882 + OBJECT_EXPERIMENTAL_FOOD_PHOTO_PHOTO_HIPSTER: 'CommonBuffId' = 131891 + OBJECT_EXPERIMENTAL_FOOD_PHOTO_WELL_CURATED_COLLECTION: 'CommonBuffId' = 131890 + OBJECT_FITNESS_FATIGUED: 'CommonBuffId' = 12543 + OBJECT_FITNESS_FATIGUED_LAZY: 'CommonBuffId' = 28907 + OBJECT_FITNESS_GOOD_WORKOUT: 'CommonBuffId' = 31361 + OBJECT_FITNESS_POTENTIALLY_SORE: 'CommonBuffId' = 23986 + OBJECT_FITNESS_SORE: 'CommonBuffId' = 23987 + OBJECT_FITNESS_VERY_FATIGUED: 'CommonBuffId' = 31362 + OBJECT_FLOWER_ARRANGEMENT_ANGRY_DISRESPECT: 'CommonBuffId' = 187612 + OBJECT_FLOWER_ARRANGEMENT_CONFIDENT_FRIENDSHIP_GIVER: 'CommonBuffId' = 187661 + OBJECT_FLOWER_ARRANGEMENT_CONFIDENT_MAGNIFICENCE: 'CommonBuffId' = 187616 + OBJECT_FLOWER_ARRANGEMENT_CONFIDENT_MAGNIFICENCE_GIVER: 'CommonBuffId' = 187662 + OBJECT_FLOWER_ARRANGEMENT_DAZED_CURSED: 'CommonBuffId' = 187615 + OBJECT_FLOWER_ARRANGEMENT_FAITHFUL_RECEIVER: 'CommonBuffId' = 187703 + OBJECT_FLOWER_ARRANGEMENT_FLIRTY_ROMANCE: 'CommonBuffId' = 187611 + OBJECT_FLOWER_ARRANGEMENT_FLIRTY_ROMANCE_GIVER: 'CommonBuffId' = 187664 + OBJECT_FLOWER_ARRANGEMENT_HAPPY_FAITHFUL: 'CommonBuffId' = 188219 + OBJECT_FLOWER_ARRANGEMENT_HAPPY_FRIENDSHIP: 'CommonBuffId' = 187606 + OBJECT_FLOWER_ARRANGEMENT_HAPPY_JOY: 'CommonBuffId' = 187608 + OBJECT_FLOWER_ARRANGEMENT_HAPPY_JOY_GIVER: 'CommonBuffId' = 187665 + OBJECT_FLOWER_ARRANGEMENT_HIDDEN_CHRISTMAS_ROSE_ASLEEP: 'CommonBuffId' = 188764 + OBJECT_FLOWER_ARRANGEMENT_HIDDEN_CHRISTMAS_ROSE_SLEEP_DESIRE: 'CommonBuffId' = 188763 + OBJECT_FLOWER_ARRANGEMENT_HIDDEN_CHRISTMAS_ROSE_WOKE_UP: 'CommonBuffId' = 188765 + OBJECT_FLOWER_ARRANGEMENT_HIDDEN_COOLDOWN: 'CommonBuffId' = 188848 + OBJECT_FLOWER_ARRANGEMENT_HIDDEN_CURSED_EFFECTS: 'CommonBuffId' = 188702 + OBJECT_FLOWER_ARRANGEMENT_HIDDEN_SNAPDRAGON_DISRESPECT: 'CommonBuffId' = 191507 + OBJECT_FLOWER_ARRANGEMENT_HIDDEN_SNAPDRAGON_DISRESPECT_TURN_ONE: 'CommonBuffId' = 188184 + OBJECT_FLOWER_ARRANGEMENT_HIDDEN_SNAPDRAGON_DISRESPECT_TURN_TWO: 'CommonBuffId' = 188185 + OBJECT_FLOWER_ARRANGEMENT_INSPIRED_CREATIVITY: 'CommonBuffId' = 187613 + OBJECT_FLOWER_ARRANGEMENT_INSPIRED_SEASONS: 'CommonBuffId' = 187614 + OBJECT_FLOWER_ARRANGEMENT_SAD_MOURNING: 'CommonBuffId' = 187610 + OBJECT_FOOSBALL_CHEERED: 'CommonBuffId' = 122868 + OBJECT_FOOSBALL_EMBARRASSED_CHALLENGE: 'CommonBuffId' = 127115 + OBJECT_FOOSBALL_HECKLED: 'CommonBuffId' = 122869 + OBJECT_FOOSBALL_LEFT_CHALLENGE: 'CommonBuffId' = 130262 + OBJECT_FOOSBALL_LOSE: 'CommonBuffId' = 124476 + OBJECT_FOOSBALL_TABLE_CHALLENGED: 'CommonBuffId' = 124814 + OBJECT_FOOSBALL_TABLE_CLUB_CHALLENGE: 'CommonBuffId' = 126310 + OBJECT_FOOSBALL_TABLE_PLAY_SIDE_A: 'CommonBuffId' = 123137 + OBJECT_FOOSBALL_TABLE_PLAY_SIDE_B: 'CommonBuffId' = 123138 + OBJECT_FOOSBALL_WIN: 'CommonBuffId' = 124475 + OBJECT_FRONT_DESK_BADGED_IN: 'CommonBuffId' = 112447 + OBJECT_FRONT_DESK_BE_CHECKED_IN: 'CommonBuffId' = 111910 + OBJECT_FRONT_DESK_STAFFED: 'CommonBuffId' = 110676 + OBJECT_FRUITCAKE_HATES: 'CommonBuffId' = 119331 + OBJECT_FRUITCAKE_LIKES: 'CommonBuffId' = 119335 + OBJECT_FRUIT_PUNCH_FOUNTAIN_CARAMEL: 'CommonBuffId' = 116947 + OBJECT_FRUIT_PUNCH_FOUNTAIN_CHEESE: 'CommonBuffId' = 116948 + OBJECT_FRUIT_PUNCH_FOUNTAIN_CIDER: 'CommonBuffId' = 116949 + OBJECT_FRUIT_PUNCH_FOUNTAIN_FUTURISTIC: 'CommonBuffId' = 116950 + OBJECT_FRUIT_PUNCH_FOUNTAIN_HIDDEN_DIP_FINGER_TIME_OUT: 'CommonBuffId' = 116976 + OBJECT_FRUIT_PUNCH_FOUNTAIN_HIDDEN_OBJECT_CHECK: 'CommonBuffId' = 117187 + OBJECT_FRUIT_PUNCH_FOUNTAIN_HIDDEN_SABOTAGED_FOUNTAIN: 'CommonBuffId' = 116964 + OBJECT_FRUIT_PUNCH_FOUNTAIN_IMPROVED_DRINK: 'CommonBuffId' = 116945 + OBJECT_FRUIT_PUNCH_FOUNTAIN_IMPROVED_FOOD_BALL: 'CommonBuffId' = 116953 + OBJECT_FRUIT_PUNCH_FOUNTAIN_PARTY_BONUS: 'CommonBuffId' = 117185 + OBJECT_FRUIT_PUNCH_FOUNTAIN_PARTY_EXTENDER: 'CommonBuffId' = 116951 + OBJECT_FRUIT_PUNCH_FOUNTAIN_SABOTAGE_PLAYFUL: 'CommonBuffId' = 116946 + OBJECT_FRUIT_PUNCH_FOUNTAIN_SABOTAGE_UNCOMFORTABLE: 'CommonBuffId' = 116952 + OBJECT_GARDENING_PLANT_CHILD_HELPED_CARE: 'CommonBuffId' = 260097 + OBJECT_GARDENING_PLANT_CHILD_TALK_TO_PLANT: 'CommonBuffId' = 260101 + OBJECT_GUITAR_PRACTICE: 'CommonBuffId' = 39949 + OBJECT_GUITAR_REAPER_BEING_PLAYED: 'CommonBuffId' = 150078 + OBJECT_GUITAR_RIGHTEOUS_RIFFS: 'CommonBuffId' = 36973 + OBJECT_GUITAR_ROCKING_RIFFS: 'CommonBuffId' = 34548 + OBJECT_HEART_BED_PLAYFUL: 'CommonBuffId' = 368804 + OBJECT_HEART_BED_TENSE: 'CommonBuffId' = 368806 + OBJECT_HEART_BED_UNCOMFORTABLE: 'CommonBuffId' = 368805 + OBJECT_HEAT_LAMP_HEATED_SURROUNDINGS: 'CommonBuffId' = 131770 + OBJECT_HEAT_LAMP_WARMED_BY_HEAT_LAMP: 'CommonBuffId' = 131781 + OBJECT_HERBALIST_POTION_CLEAR_MIND: 'CommonBuffId' = 108791 + OBJECT_HERBALIST_POTION_CLEAR_MIND_MASTERWORK: 'CommonBuffId' = 111692 + OBJECT_HERBALIST_POTION_CLEAR_MIND_NORMAL: 'CommonBuffId' = 111691 + OBJECT_HERBALIST_POTION_CLEAR_MIND_OUTSTANDING: 'CommonBuffId' = 111689 + OBJECT_HERBALIST_POTION_DEODORANT: 'CommonBuffId' = 104584 + OBJECT_HERBALIST_POTION_DEODORANT_MASTERWORK: 'CommonBuffId' = 111695 + OBJECT_HERBALIST_POTION_DEODORANT_OUTSTANDING: 'CommonBuffId' = 111694 + OBJECT_HERBALIST_POTION_DISGUSTING_APPLICATION: 'CommonBuffId' = 110751 + OBJECT_HERBALIST_POTION_DISGUSTING_LIQUID: 'CommonBuffId' = 104651 + OBJECT_HERBALIST_POTION_ENERGIZER: 'CommonBuffId' = 104585 + OBJECT_HERBALIST_POTION_ENERGIZER_MASTERWORK: 'CommonBuffId' = 111698 + OBJECT_HERBALIST_POTION_ENERGIZER_OUTSTANDING: 'CommonBuffId' = 111697 + OBJECT_HERBALIST_POTION_FERTILITY_POTION: 'CommonBuffId' = 104587 + OBJECT_HERBALIST_POTION_FERTILITY_POTION_MASTERWORK: 'CommonBuffId' = 105210 + OBJECT_HERBALIST_POTION_FERTILITY_POTION_NORMAL: 'CommonBuffId' = 105208 + OBJECT_HERBALIST_POTION_FERTILITY_POTION_OUTSTANDING: 'CommonBuffId' = 105209 + OBJECT_HERBALIST_POTION_INSECT_REPELLENT: 'CommonBuffId' = 104543 + OBJECT_HERBALIST_POTION_SKIN_BALM_HIDDEN: 'CommonBuffId' = 104570 + OBJECT_HERBALIST_POTION_TUMMY_FIXER: 'CommonBuffId' = 104586 + OBJECT_HIDDEN_PINGPONG_JUICE_PONG_PLAYING_AGAINST_RIVAL: 'CommonBuffId' = 230422 + OBJECT_HIDDEN_PINGPONG_WINNER: 'CommonBuffId' = 224875 + OBJECT_HOLDING_CELL_BEING_PUT_IN_CELL: 'CommonBuffId' = 112619 + OBJECT_HOLDING_CELL_FINGERPRINT_NEXT: 'CommonBuffId' = 112607 + OBJECT_HOLDING_CELL_INTERROGATE_NEXT: 'CommonBuffId' = 112609 + OBJECT_HOLDING_CELL_IN_CELL: 'CommonBuffId' = 104873 + OBJECT_HOLDING_CELL_MUGSHOT_NEXT: 'CommonBuffId' = 112608 + OBJECT_HOLDING_CELL_OUT_OF_CELL_TIMER: 'CommonBuffId' = 106109 + OBJECT_HOLDING_CELL_PUT_ME_BACK_IN_CELL: 'CommonBuffId' = 106110 + OBJECT_HOLDING_CELL_SEARCH_NEXT: 'CommonBuffId' = 112610 + OBJECT_HOLIDAY_CANDLE_FULLY_LIT: 'CommonBuffId' = 110530 + OBJECT_HOLIDAY_CANDLE_LIT: 'CommonBuffId' = 110493 + OBJECT_HOMEWORK_COMPLETE: 'CommonBuffId' = 31589 + OBJECT_HOMEWORK_HAS_ANSWER_KEY: 'CommonBuffId' = 33803 + OBJECT_HORSE_BED_HAPPY: 'CommonBuffId' = 329134 + OBJECT_HORSE_BED_UNCOMFORTABLE: 'CommonBuffId' = 329135 + OBJECT_HORSE_OBSTACLES_CHEATS_FAILURE: 'CommonBuffId' = 332059 + OBJECT_HORSE_OBSTACLES_CHEATS_SUCCESS: 'CommonBuffId' = 332058 + OBJECT_HORSE_OBSTACLES_IS_TRAINING: 'CommonBuffId' = 348970 + OBJECT_HORSE_OBSTACLES_SKILL_GAIN_HORSE_LARGE: 'CommonBuffId' = 333981 + OBJECT_HORSE_OBSTACLES_SKILL_GAIN_HORSE_SMALL: 'CommonBuffId' = 333387 + OBJECT_HORSE_OBSTACLES_SKILL_GAIN_HORSE_STANDARD: 'CommonBuffId' = 333980 + OBJECT_HORSE_OBSTACLES_SKILL_GAIN_SIM_LARGE: 'CommonBuffId' = 333985 + OBJECT_HORSE_OBSTACLES_SKILL_GAIN_SIM_SMALL: 'CommonBuffId' = 333982 + OBJECT_HORSE_OBSTACLES_SKILL_GAIN_SIM_STANDARD: 'CommonBuffId' = 333984 + OBJECT_HORSE_OBSTACLES_STOP_TRAINING: 'CommonBuffId' = 338877 + OBJECT_HORSE_SHOES_EMBARRASSING_SHOWING: 'CommonBuffId' = 109922 + OBJECT_HORSE_SHOES_LOSE: 'CommonBuffId' = 105891 + OBJECT_HORSE_SHOES_PLAYING: 'CommonBuffId' = 109968 + OBJECT_HORSE_SHOES_PRACTICE: 'CommonBuffId' = 106087 + OBJECT_HORSE_SHOES_SORE_LOSER: 'CommonBuffId' = 105089 + OBJECT_HORSE_SHOES_UNSOPHISTICATED: 'CommonBuffId' = 109921 + OBJECT_HORSE_SHOES_WIN: 'CommonBuffId' = 105086 + OBJECT_HORSE_TRAINING_SKILL_GAIN_TEMPERAMENT_SMALL: 'CommonBuffId' = 334179 + OBJECT_HORSE_TRAINING_SKILL_GAIN_TEMPERAMENT_STANDARD: 'CommonBuffId' = 334180 + OBJECT_HOT_SPRINGS_1_WARM_FEELINGS: 'CommonBuffId' = 248902 + OBJECT_HOT_SPRINGS_2_LOST_IN_WARMTH: 'CommonBuffId' = 248903 + OBJECT_HOT_SPRINGS_3_COMPLETE_RELAXATION: 'CommonBuffId' = 248904 + OBJECT_HOT_SPRINGS_BUFF_TRACKER: 'CommonBuffId' = 254617 + OBJECT_HOT_SPRINGS_HIDDEN_CLEAN: 'CommonBuffId' = 249179 + OBJECT_HOT_SPRINGS_ON_ENTER_DIRTY_HOT_SPRINGS: 'CommonBuffId' = 249459 + OBJECT_HOT_SPRINGS_ON_ENTER_GOOD_SIM: 'CommonBuffId' = 249295 + OBJECT_HOT_SPRINGS_ON_ENTER_SEEN_UNCLEAN: 'CommonBuffId' = 249296 + OBJECT_HOT_SPRINGS_SOAKED_TOO_LONG: 'CommonBuffId' = 248905 + OBJECT_HOT_SPRINGS_TIME_INSIDE_TRACKER: 'CommonBuffId' = 248956 + OBJECT_HOT_TUB_ANNOYED_BY_SPLASHER: 'CommonBuffId' = 119414 + OBJECT_HOT_TUB_AROMATHERAPY_JASMINE: 'CommonBuffId' = 118704 + OBJECT_HOT_TUB_AROMATHERAPY_LEMON: 'CommonBuffId' = 118703 + OBJECT_HOT_TUB_AROMATHERAPY_PEPPERMINT: 'CommonBuffId' = 118706 + OBJECT_HOT_TUB_AROMATHERAPY_SAGE: 'CommonBuffId' = 118705 + OBJECT_HOT_TUB_BORED_OF_SPLASHING: 'CommonBuffId' = 120477 + OBJECT_HOT_TUB_BROKEN: 'CommonBuffId' = 120649 + OBJECT_HOT_TUB_IN_HOT_TUB: 'CommonBuffId' = 120612 + OBJECT_HOT_TUB_MESSED_AROUND_HOT_TUB: 'CommonBuffId' = 119138 + OBJECT_HOT_TUB_MISTAKEN_SPLASH: 'CommonBuffId' = 119139 + OBJECT_HOT_TUB_NUDE: 'CommonBuffId' = 120584 + OBJECT_HOT_TUB_SPLASHED_HOT_WATER: 'CommonBuffId' = 119140 + OBJECT_HOT_TUB_SPLASHING: 'CommonBuffId' = 119141 + OBJECT_HOT_TUB_THIOACETONE_USED_HIDDEN: 'CommonBuffId' = 119144 + OBJECT_HOT_TUB_UNIMAGINABLE_ODOR: 'CommonBuffId' = 119142 + OBJECT_HOT_TUB_WOOHOO_IN_HOT_TUB: 'CommonBuffId' = 119143 + OBJECT_ICE_CREAM_CHILLED_TO_THE_BONE: 'CommonBuffId' = 121033 + OBJECT_ICE_CREAM_CHILLING_TOUCH_USED: 'CommonBuffId' = 121441 + OBJECT_ICE_CREAM_DRAGONS_FURY_CONFIDENT: 'CommonBuffId' = 121025 + OBJECT_ICE_CREAM_DRAGONS_FURY_UNCOMFORTABLE: 'CommonBuffId' = 121026 + OBJECT_ICE_CREAM_GREEN_LIFE: 'CommonBuffId' = 121031 + OBJECT_ICE_CREAM_HAUNTED: 'CommonBuffId' = 121040 + OBJECT_ICE_CREAM_HAUNTED_BROADCASTER: 'CommonBuffId' = 121041 + OBJECT_ICE_CREAM_HAUNTINGLY_TASTY_INSPIRED: 'CommonBuffId' = 121038 + OBJECT_ICE_CREAM_HAUNTINGLY_TASTY_SAD: 'CommonBuffId' = 121039 + OBJECT_ICE_CREAM_ICE_TREAT: 'CommonBuffId' = 121032 + OBJECT_ICE_CREAM_JUST_NUTS: 'CommonBuffId' = 121609 + OBJECT_ICE_CREAM_MIND_ASKEW_ANGRY: 'CommonBuffId' = 121043 + OBJECT_ICE_CREAM_MIND_ASKEW_BORED: 'CommonBuffId' = 121047 + OBJECT_ICE_CREAM_MIND_ASKEW_CONFIDENT: 'CommonBuffId' = 121045 + OBJECT_ICE_CREAM_MIND_ASKEW_DAZED: 'CommonBuffId' = 121054 + OBJECT_ICE_CREAM_MIND_ASKEW_EMBARRASSED: 'CommonBuffId' = 121048 + OBJECT_ICE_CREAM_MIND_ASKEW_ENERGIZED: 'CommonBuffId' = 121044 + OBJECT_ICE_CREAM_MIND_ASKEW_FLIRTY: 'CommonBuffId' = 121049 + OBJECT_ICE_CREAM_MIND_ASKEW_FOCUSED: 'CommonBuffId' = 121055 + OBJECT_ICE_CREAM_MIND_ASKEW_HAPPY: 'CommonBuffId' = 121050 + OBJECT_ICE_CREAM_MIND_ASKEW_HIDDEN: 'CommonBuffId' = 121028 + OBJECT_ICE_CREAM_MIND_ASKEW_INSPIRED: 'CommonBuffId' = 121056 + OBJECT_ICE_CREAM_MIND_ASKEW_PLAYFUL: 'CommonBuffId' = 121046 + OBJECT_ICE_CREAM_MIND_ASKEW_SAD: 'CommonBuffId' = 121053 + OBJECT_ICE_CREAM_MIND_ASKEW_STRESSED: 'CommonBuffId' = 121051 + OBJECT_ICE_CREAM_MIND_ASKEW_UNCOMFORTABLE: 'CommonBuffId' = 121052 + OBJECT_ICE_CREAM_PERFECT_TOPPINGS: 'CommonBuffId' = 121596 + OBJECT_ICE_CREAM_PURE_PERFECTION: 'CommonBuffId' = 121035 + OBJECT_ICE_CREAM_RUB_TUMMY: 'CommonBuffId' = 121425 + OBJECT_ICE_CREAM_SUGARY_GOODNESS: 'CommonBuffId' = 121036 + OBJECT_ICE_CREAM_TASTE_OF_DIET: 'CommonBuffId' = 121037 + OBJECT_ICE_CREAM_TASTE_OF_ROSES_ADULT: 'CommonBuffId' = 121030 + OBJECT_ICE_CREAM_TASTE_OF_ROSES_CHILD: 'CommonBuffId' = 121065 + OBJECT_INCENSE: 'CommonBuffId' = 118851 + OBJECT_INSECT_FARM_FEED_COMPOST: 'CommonBuffId' = 239042 + OBJECT_INSECT_FARM_WHY_BUGS: 'CommonBuffId' = 238847 + OBJECT_INTERACTIVE_BUSH_EWW: 'CommonBuffId' = 124869 + OBJECT_INTERACTIVE_BUSH_UNCOMFORTABLE_NAP: 'CommonBuffId' = 126307 + OBJECT_INVENTION_CONSTRUCTOR_INSPIRED: 'CommonBuffId' = 110195 + OBJECT_IN_WARMING_OBJECT: 'CommonBuffId' = 187519 + OBJECT_IS_PLAYING: 'CommonBuffId' = 151823 + OBJECT_IS_PLAYING_01: 'CommonBuffId' = 157657 + OBJECT_IS_PLAYING_02: 'CommonBuffId' = 157016 + OBJECT_IS_PLAYING_03: 'CommonBuffId' = 157017 + OBJECT_IS_PLAYING_04: 'CommonBuffId' = 157018 + OBJECT_IS_PLAYING_05: 'CommonBuffId' = 157019 + OBJECT_IS_PLAYING_NON_TODDLER: 'CommonBuffId' = 156821 + OBJECT_IS_PLAYING_SAND_ACTIVITIES_1: 'CommonBuffId' = 214541 + OBJECT_IS_PLAYING_SAND_ACTIVITIES_2: 'CommonBuffId' = 214543 + OBJECT_IS_PLAYING_SAND_ACTIVITIES_3: 'CommonBuffId' = 214544 + OBJECT_IS_PLAYING_SAND_ACTIVITIES_4: 'CommonBuffId' = 214545 + OBJECT_IS_PLAYING_SAND_ACTIVITIES_5: 'CommonBuffId' = 214546 + OBJECT_IS_SLEEPING_TODDLER: 'CommonBuffId' = 155008 + OBJECT_JUMP_STAND_DIVE_DISASTER: 'CommonBuffId' = 128655 + OBJECT_JUMP_STAND_DIVE_MASTER: 'CommonBuffId' = 128654 + OBJECT_JUMP_STAND_FREE_FLYING: 'CommonBuffId' = 128658 + OBJECT_JUMP_STAND_SPLASHED: 'CommonBuffId' = 128657 + OBJECT_JUMP_STAND_SWIMSUIT_MALFUNCTION: 'CommonBuffId' = 128656 + OBJECT_JUNGLE_GYM_BOAT_PLAYFUL: 'CommonBuffId' = 8596 + OBJECT_JUNGLE_GYM_ROCKET_SHIP_PLAYFUL: 'CommonBuffId' = 8615 + OBJECT_KIDS_TENT_IM_ANGRY_TODDLER: 'CommonBuffId' = 268551 + OBJECT_KIDS_TENT_IM_A_MONSTER: 'CommonBuffId' = 257391 + OBJECT_KIDS_TENT_IM_SCARED: 'CommonBuffId' = 257456 + OBJECT_KIDS_TENT_IS_PLAYING: 'CommonBuffId' = 268371 + OBJECT_KIDS_TENT_IS_PLAYING_1: 'CommonBuffId' = 267803 + OBJECT_KIDS_TENT_IS_PLAYING_2: 'CommonBuffId' = 267804 + OBJECT_KIDS_TENT_IS_PLAYING_3: 'CommonBuffId' = 267805 + OBJECT_KIDS_TENT_IS_PLAYING_4: 'CommonBuffId' = 267806 + OBJECT_KIDS_TENT_IS_PLAYING_5: 'CommonBuffId' = 267807 + OBJECT_KIDS_TENT_MAKE_BELIEVE: 'CommonBuffId' = 257390 + OBJECT_KIDS_TENT_SHABBY_TENT: 'CommonBuffId' = 257392 + OBJECT_LASER_LIGHT_SHOW: 'CommonBuffId' = 35451 + OBJECT_LASER_POINTER_PLAYFUL: 'CommonBuffId' = 158125 + OBJECT_LEAF_PILE_COZY_FIRE: 'CommonBuffId' = 182976 + OBJECT_LEAF_PILE_GROSS_PLAY_IN: 'CommonBuffId' = 186342 + OBJECT_LEAF_PILE_GROSS_WOOHOO: 'CommonBuffId' = 190668 + OBJECT_LEAF_PILE_RAKE_DISCIPLINE: 'CommonBuffId' = 190872 + OBJECT_MAILBOX_WALL_BROWSING: 'CommonBuffId' = 133185 + OBJECT_MARKET_STALLS_CAS_CHANGE_BLOSSOM_SHIRT: 'CommonBuffId' = 139598 + OBJECT_MARKET_STALLS_CAS_CHANGE_FOOD_SHIRT: 'CommonBuffId' = 132817 + OBJECT_MARKET_STALLS_CAS_CHANGE_LAMP_SHIRT: 'CommonBuffId' = 139596 + OBJECT_MARKET_STALLS_CAS_CHANGE_LOGIC_SHIRT: 'CommonBuffId' = 139597 + OBJECT_MARKET_STALLS_CURIO_SHOP_QUESTION_COOLDOWN: 'CommonBuffId' = 203216 + OBJECT_MARKET_STALLS_HAGGLE: 'CommonBuffId' = 132805 + OBJECT_MARKET_STALLS_HAGGLE_BATUU: 'CommonBuffId' = 250410 + OBJECT_MARKET_STALLS_HAGGLE_FAIL: 'CommonBuffId' = 132806 + OBJECT_MARKET_STALLS_IN_THE_KNOW: 'CommonBuffId' = 148137 + OBJECT_MARKET_STALLS_SHOW_OFF_PREVENTION: 'CommonBuffId' = 141666 + OBJECT_MASSAGE_CHAIR_ACHING_ARCHES: 'CommonBuffId' = 119782 + OBJECT_MASSAGE_CHAIR_FABULOUS_FEET: 'CommonBuffId' = 119783 + OBJECT_MASSAGE_CHAIR_FIRST_HAND_COMPLETE: 'CommonBuffId' = 119583 + OBJECT_MASSAGE_CHAIR_GETTING_MANICURE: 'CommonBuffId' = 273062 + OBJECT_MASSAGE_CHAIR_HAND_TABULOUS_MASSAGE: 'CommonBuffId' = 119947 + OBJECT_MASSAGE_CHAIR_HAPPY_HANDS: 'CommonBuffId' = 119780 + OBJECT_MASSAGE_CHAIR_HURT_HANDS: 'CommonBuffId' = 119781 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ALMOND_BEIGE: 'CommonBuffId' = 271702 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ALMOND_BLACK: 'CommonBuffId' = 271703 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ALMOND_BLUE: 'CommonBuffId' = 271704 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ALMOND_BLUE_LT: 'CommonBuffId' = 271705 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ALMOND_CREAM: 'CommonBuffId' = 271706 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ALMOND_GREEN: 'CommonBuffId' = 271707 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ALMOND_LILAC: 'CommonBuffId' = 271708 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ALMOND_PINK: 'CommonBuffId' = 271709 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ALMOND_PURPLE: 'CommonBuffId' = 271710 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ALMOND_RED: 'CommonBuffId' = 271711 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ALMOND_SILVER: 'CommonBuffId' = 271712 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ALMOND_WHITE: 'CommonBuffId' = 271713 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ALMOND_YELLOW: 'CommonBuffId' = 271714 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_ART_1: 'CommonBuffId' = 271779 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_ART_2: 'CommonBuffId' = 271780 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_ART_3: 'CommonBuffId' = 271781 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_ART_4: 'CommonBuffId' = 271782 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_ART_5: 'CommonBuffId' = 271783 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_ART_6: 'CommonBuffId' = 271778 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_BEIGE: 'CommonBuffId' = 271255 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_BLACK: 'CommonBuffId' = 271256 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_BLUE: 'CommonBuffId' = 271257 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_BLUE_LT: 'CommonBuffId' = 271355 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_CREAM: 'CommonBuffId' = 271991 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_GREEN: 'CommonBuffId' = 271363 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_LILAC: 'CommonBuffId' = 271370 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_MATTE_BEIGE: 'CommonBuffId' = 271745 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_MATTE_BLACK: 'CommonBuffId' = 271746 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_MATTE_BLUE: 'CommonBuffId' = 271747 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_MATTE_BLUE_LT: 'CommonBuffId' = 271748 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_MATTE_CREAM: 'CommonBuffId' = 271992 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_MATTE_GREEN: 'CommonBuffId' = 271749 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_MATTE_LILAC: 'CommonBuffId' = 271750 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_MATTE_PINK: 'CommonBuffId' = 271751 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_MATTE_PURPLE: 'CommonBuffId' = 271752 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_MATTE_RED: 'CommonBuffId' = 271753 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_MATTE_SILVER: 'CommonBuffId' = 271754 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_MATTE_WHITE: 'CommonBuffId' = 271755 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_MATTE_YELLOW: 'CommonBuffId' = 271756 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_PINK: 'CommonBuffId' = 271376 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_PURPLE: 'CommonBuffId' = 271382 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_RED: 'CommonBuffId' = 271388 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_SILVER: 'CommonBuffId' = 271394 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_SWIRL_BLACK: 'CommonBuffId' = 271787 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_SWIRL_BLUE: 'CommonBuffId' = 271788 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_SWIRL_CREAM: 'CommonBuffId' = 271789 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_SWIRL_PINK: 'CommonBuffId' = 271790 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_SWIRL_PURPLE: 'CommonBuffId' = 271791 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_SWIRL_SPACE: 'CommonBuffId' = 272825 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_SWIRL_TEAL: 'CommonBuffId' = 272824 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_SWIRL_WHITE: 'CommonBuffId' = 271792 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_WHITE: 'CommonBuffId' = 271400 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_YELLOW: 'CommonBuffId' = 271406 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COMMUNITY_BLACK: 'CommonBuffId' = 272691 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COMMUNITY_BLUE: 'CommonBuffId' = 272142 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COMMUNITY_FUCHSIA: 'CommonBuffId' = 272692 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COMMUNITY_GREEN: 'CommonBuffId' = 272693 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COMMUNITY_MINT: 'CommonBuffId' = 272694 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COMMUNITY_ORANGE: 'CommonBuffId' = 272695 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COMMUNITY_PINK: 'CommonBuffId' = 272696 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COMMUNITY_PLUM: 'CommonBuffId' = 272697 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COMMUNITY_PURPLE: 'CommonBuffId' = 272698 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COMMUNITY_RED: 'CommonBuffId' = 272699 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COMMUNITY_YELLOW: 'CommonBuffId' = 272700 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_BEIGE: 'CommonBuffId' = 271251 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_BLACK: 'CommonBuffId' = 271252 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_BLUE: 'CommonBuffId' = 271253 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_BLUE_LT: 'CommonBuffId' = 271356 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_ASEX: 'CommonBuffId' = 271886 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_BI: 'CommonBuffId' = 271887 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_BLACKPINK: 'CommonBuffId' = 272810 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_BLUE: 'CommonBuffId' = 271888 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_BLUE_YELLOW: 'CommonBuffId' = 272811 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_GRAYS: 'CommonBuffId' = 271889 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_LEATHER: 'CommonBuffId' = 271890 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_NON: 'CommonBuffId' = 271891 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_ORANGE: 'CommonBuffId' = 271892 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_PAN: 'CommonBuffId' = 271893 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_PASTEL: 'CommonBuffId' = 271894 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_PINKS: 'CommonBuffId' = 271895 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_PINK_WHITE: 'CommonBuffId' = 272812 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_PRIDE: 'CommonBuffId' = 271896 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_PURPLE_MUAVE: 'CommonBuffId' = 272813 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_SHORT_ASEX: 'CommonBuffId' = 271914 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_SHORT_BI: 'CommonBuffId' = 271915 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_SHORT_BLACK_PINK: 'CommonBuffId' = 272814 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_SHORT_BLUE: 'CommonBuffId' = 271916 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_SHORT_BLUE_YELLOW: 'CommonBuffId' = 272815 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_SHORT_GRAYS: 'CommonBuffId' = 271917 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_SHORT_LEATHER: 'CommonBuffId' = 271918 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_SHORT_NON: 'CommonBuffId' = 271919 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_SHORT_ORANGE: 'CommonBuffId' = 271920 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_SHORT_PAN: 'CommonBuffId' = 271921 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_SHORT_PASTEL: 'CommonBuffId' = 271922 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_SHORT_PINKS: 'CommonBuffId' = 271923 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_SHORT_PINK_WHITE: 'CommonBuffId' = 272816 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_SHORT_PRIDE: 'CommonBuffId' = 271924 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_SHORT_PURPLE_MUAVE: 'CommonBuffId' = 272817 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_SHORT_TRANS: 'CommonBuffId' = 271925 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_TRANS: 'CommonBuffId' = 271897 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_GREEN: 'CommonBuffId' = 271364 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_LILAC: 'CommonBuffId' = 271371 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_PINK: 'CommonBuffId' = 271377 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_PURPLE: 'CommonBuffId' = 271383 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_RED: 'CommonBuffId' = 271389 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_SHORT_BEIGE: 'CommonBuffId' = 271940 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_SHORT_BLACK: 'CommonBuffId' = 271942 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_SHORT_BLUE: 'CommonBuffId' = 271941 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_SHORT_BLUE_LT: 'CommonBuffId' = 271943 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_SHORT_BUFFED_PINK: 'CommonBuffId' = 271807 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_SHORT_BUFFED_WHITE: 'CommonBuffId' = 271811 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_SHORT_CHOCOLATE: 'CommonBuffId' = 272818 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_SHORT_GREEN: 'CommonBuffId' = 271944 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_SHORT_LILAC: 'CommonBuffId' = 271945 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_SHORT_MUAVE: 'CommonBuffId' = 272819 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_SHORT_PINK: 'CommonBuffId' = 271946 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_SHORT_PINK_DUSTY: 'CommonBuffId' = 272820 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_SHORT_PURPLE: 'CommonBuffId' = 271947 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_SHORT_RED: 'CommonBuffId' = 271948 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_SHORT_SILVER: 'CommonBuffId' = 271949 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_SHORT_WHITE: 'CommonBuffId' = 271950 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_SHORT_YELLOW: 'CommonBuffId' = 271997 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_SILVER: 'CommonBuffId' = 271395 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_WHITE: 'CommonBuffId' = 271401 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_YELLOW: 'CommonBuffId' = 271407 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_GRADIENT_BEIGE: 'CommonBuffId' = 271828 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_GRADIENT_BLACK: 'CommonBuffId' = 271829 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_GRADIENT_BLUE: 'CommonBuffId' = 271830 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_GRADIENT_BLUE_LT: 'CommonBuffId' = 271831 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_GRADIENT_CREAM: 'CommonBuffId' = 272010 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_GRADIENT_GREEN: 'CommonBuffId' = 271832 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_GRADIENT_LILAC: 'CommonBuffId' = 271834 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_GRADIENT_PINK: 'CommonBuffId' = 271835 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_GRADIENT_PURPLE: 'CommonBuffId' = 271836 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_GRADIENT_RED: 'CommonBuffId' = 271837 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_GRADIENT_SILVER: 'CommonBuffId' = 271838 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_GRADIENT_WHITE: 'CommonBuffId' = 271839 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_GRADIENT_YELLOW: 'CommonBuffId' = 271840 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_SPLIT_BEIGE: 'CommonBuffId' = 271856 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_SPLIT_BLACK: 'CommonBuffId' = 271858 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_SPLIT_BLUE: 'CommonBuffId' = 271860 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_SPLIT_BLUE_LT: 'CommonBuffId' = 271863 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_SPLIT_CREAM: 'CommonBuffId' = 272012 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_SPLIT_GREEN: 'CommonBuffId' = 271864 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_SPLIT_LILAC: 'CommonBuffId' = 271866 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_SPLIT_PINK: 'CommonBuffId' = 271868 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_SPLIT_PURPLE: 'CommonBuffId' = 271870 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_SPLIT_RED: 'CommonBuffId' = 271873 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_SPLIT_SILVER: 'CommonBuffId' = 271876 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_SPLIT_WHITE: 'CommonBuffId' = 271878 + OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_SPLIT_YELLOW: 'CommonBuffId' = 271879 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ALMOND_BEIGE: 'CommonBuffId' = 271716 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ALMOND_BLACK: 'CommonBuffId' = 271717 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ALMOND_BLUE: 'CommonBuffId' = 271718 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ALMOND_BLUE_LT: 'CommonBuffId' = 271719 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ALMOND_CREAM: 'CommonBuffId' = 271721 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ALMOND_GREEN: 'CommonBuffId' = 271722 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ALMOND_LILAC: 'CommonBuffId' = 271723 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ALMOND_PINK: 'CommonBuffId' = 271724 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ALMOND_PURPLE: 'CommonBuffId' = 271725 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ALMOND_RED: 'CommonBuffId' = 271726 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ALMOND_SILVER: 'CommonBuffId' = 271727 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ALMOND_WHITE: 'CommonBuffId' = 271728 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ALMOND_YELLOW: 'CommonBuffId' = 271729 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_ART_1: 'CommonBuffId' = 271772 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_ART_2: 'CommonBuffId' = 271773 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_ART_3: 'CommonBuffId' = 271774 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_ART_4: 'CommonBuffId' = 271775 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_ART_5: 'CommonBuffId' = 271776 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_ART_6: 'CommonBuffId' = 271771 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_BEIGE: 'CommonBuffId' = 271267 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_BLACK: 'CommonBuffId' = 271268 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_BLUE: 'CommonBuffId' = 271269 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_BLUE_LT: 'CommonBuffId' = 271360 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_CREAM: 'CommonBuffId' = 271993 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_GREEN: 'CommonBuffId' = 271367 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_LILAC: 'CommonBuffId' = 271373 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_MATTE_BEIGE: 'CommonBuffId' = 271758 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_MATTE_BLACK: 'CommonBuffId' = 271759 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_MATTE_BLUE: 'CommonBuffId' = 271760 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_MATTE_BLUE_LT: 'CommonBuffId' = 271761 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_MATTE_CREAM: 'CommonBuffId' = 271994 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_MATTE_GREEN: 'CommonBuffId' = 271762 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_MATTE_LILAC: 'CommonBuffId' = 271763 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_MATTE_PINK: 'CommonBuffId' = 271764 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_MATTE_PURPLE: 'CommonBuffId' = 271765 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_MATTE_RED: 'CommonBuffId' = 271766 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_MATTE_SILVER: 'CommonBuffId' = 271767 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_MATTE_WHITE: 'CommonBuffId' = 271768 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_MATTE_YELLOW: 'CommonBuffId' = 271769 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_PINK: 'CommonBuffId' = 271379 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_PURPLE: 'CommonBuffId' = 271385 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_RED: 'CommonBuffId' = 271391 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_SILVER: 'CommonBuffId' = 271397 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_SWIRL_BLACK: 'CommonBuffId' = 271793 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_SWIRL_BLUE: 'CommonBuffId' = 271794 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_SWIRL_CREAM: 'CommonBuffId' = 271795 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_SWIRL_PINK: 'CommonBuffId' = 271796 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_SWIRL_PURPLE: 'CommonBuffId' = 271797 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_SWIRL_SPACE: 'CommonBuffId' = 272826 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_SWIRL_TEAL: 'CommonBuffId' = 272827 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_SWIRL_WHITE: 'CommonBuffId' = 271798 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_WHITE: 'CommonBuffId' = 271403 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_YELLOW: 'CommonBuffId' = 271409 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COMMUNITY_BLACK: 'CommonBuffId' = 272701 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COMMUNITY_BLUE: 'CommonBuffId' = 272140 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COMMUNITY_FUCHSIA: 'CommonBuffId' = 272702 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COMMUNITY_GREEN: 'CommonBuffId' = 272703 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COMMUNITY_MINT: 'CommonBuffId' = 272704 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COMMUNITY_ORANGE: 'CommonBuffId' = 272705 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COMMUNITY_PINK: 'CommonBuffId' = 272706 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COMMUNITY_PLUM: 'CommonBuffId' = 272707 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COMMUNITY_PURPLE: 'CommonBuffId' = 272708 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COMMUNITY_RED: 'CommonBuffId' = 272709 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COMMUNITY_YELLOW: 'CommonBuffId' = 272710 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_BEIGE: 'CommonBuffId' = 271270 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_BLACK: 'CommonBuffId' = 271271 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_BLUE: 'CommonBuffId' = 271272 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_BLUE_LT: 'CommonBuffId' = 271361 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_ASEX: 'CommonBuffId' = 271898 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_BI: 'CommonBuffId' = 271899 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_BLACKPINK: 'CommonBuffId' = 272803 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_BLUE: 'CommonBuffId' = 271900 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_BLUE_YELLOW: 'CommonBuffId' = 272802 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_GRAYS: 'CommonBuffId' = 271901 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_LEATHER: 'CommonBuffId' = 271902 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_NON: 'CommonBuffId' = 271903 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_ORANGE: 'CommonBuffId' = 271904 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_PAN: 'CommonBuffId' = 271905 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_PASTEL: 'CommonBuffId' = 271906 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_PINKS: 'CommonBuffId' = 271907 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_PINK_WHITE: 'CommonBuffId' = 272804 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_PRIDE: 'CommonBuffId' = 271908 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_PURPLE_MUAVE: 'CommonBuffId' = 272805 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_SHORT_ASEX: 'CommonBuffId' = 271926 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_SHORT_BI: 'CommonBuffId' = 271927 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_SHORT_BLACKPINK: 'CommonBuffId' = 272806 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_SHORT_BLUE: 'CommonBuffId' = 271928 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_SHORT_BLUE_YELLOW: 'CommonBuffId' = 272807 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_SHORT_GRAYS: 'CommonBuffId' = 271929 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_SHORT_LEATHER: 'CommonBuffId' = 271930 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_SHORT_NON: 'CommonBuffId' = 271931 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_SHORT_ORANGE: 'CommonBuffId' = 271932 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_SHORT_PAN: 'CommonBuffId' = 271933 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_SHORT_PASTEL: 'CommonBuffId' = 271934 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_SHORT_PINKS: 'CommonBuffId' = 271935 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_SHORT_PINK_WHITE: 'CommonBuffId' = 272808 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_SHORT_PRIDE: 'CommonBuffId' = 271936 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_SHORT_PURPLE_MUAVE: 'CommonBuffId' = 272809 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_SHORT_TRANS: 'CommonBuffId' = 271937 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_TRANS: 'CommonBuffId' = 271909 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_GREEN: 'CommonBuffId' = 271368 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_LILAC: 'CommonBuffId' = 271374 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_PINK: 'CommonBuffId' = 271380 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_PURPLE: 'CommonBuffId' = 271386 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_RED: 'CommonBuffId' = 271392 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_SHORT_BEIGE: 'CommonBuffId' = 271998 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_SHORT_BLACK: 'CommonBuffId' = 271999 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_SHORT_BLUE: 'CommonBuffId' = 272000 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_SHORT_BLUE_LT: 'CommonBuffId' = 272001 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_SHORT_BUFFED_PINK: 'CommonBuffId' = 271819 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_SHORT_BUFFED_WHITE: 'CommonBuffId' = 271824 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_SHORT_CHOCOLATE: 'CommonBuffId' = 272822 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_SHORT_GREEN: 'CommonBuffId' = 272002 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_SHORT_LILAC: 'CommonBuffId' = 272003 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_SHORT_MUAVE: 'CommonBuffId' = 272821 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_SHORT_PINK: 'CommonBuffId' = 272004 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_SHORT_PINK_DUSTY: 'CommonBuffId' = 272823 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_SHORT_PURPLE: 'CommonBuffId' = 272005 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_SHORT_RED: 'CommonBuffId' = 272006 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_SHORT_SILVER: 'CommonBuffId' = 272007 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_SHORT_WHITE: 'CommonBuffId' = 272008 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_SHORT_YELLOW: 'CommonBuffId' = 272009 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_SILVER: 'CommonBuffId' = 271398 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_WHITE: 'CommonBuffId' = 271404 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_YELLOW: 'CommonBuffId' = 271410 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_GRADIENT_BEIGE: 'CommonBuffId' = 271841 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_GRADIENT_BLACK: 'CommonBuffId' = 271842 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_GRADIENT_BLUE: 'CommonBuffId' = 271843 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_GRADIENT_BLUE_LT: 'CommonBuffId' = 271844 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_GRADIENT_CREAM: 'CommonBuffId' = 272011 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_GRADIENT_GREEN: 'CommonBuffId' = 271845 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_GRADIENT_LILAC: 'CommonBuffId' = 271846 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_GRADIENT_PINK: 'CommonBuffId' = 271847 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_GRADIENT_PURPLE: 'CommonBuffId' = 271848 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_GRADIENT_RED: 'CommonBuffId' = 271849 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_GRADIENT_SILVER: 'CommonBuffId' = 271851 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_GRADIENT_WHITE: 'CommonBuffId' = 271852 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_GRADIENT_YELLOW: 'CommonBuffId' = 271853 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_SPLIT_BEIGE: 'CommonBuffId' = 271857 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_SPLIT_BLACK: 'CommonBuffId' = 271859 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_SPLIT_BLUE: 'CommonBuffId' = 271861 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_SPLIT_BLUE_LT: 'CommonBuffId' = 271862 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_SPLIT_CREAM: 'CommonBuffId' = 272013 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_SPLIT_GREEN: 'CommonBuffId' = 271865 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_SPLIT_LILAC: 'CommonBuffId' = 271867 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_SPLIT_PINK: 'CommonBuffId' = 271869 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_SPLIT_PURPLE: 'CommonBuffId' = 271874 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_SPLIT_RED: 'CommonBuffId' = 271875 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_SPLIT_SILVER: 'CommonBuffId' = 271877 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_SPLIT_WHITE: 'CommonBuffId' = 271880 + OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_SPLIT_YELLOW: 'CommonBuffId' = 271881 + OBJECT_MASSAGE_CHAIR_MANICURE_READY: 'CommonBuffId' = 273058 + OBJECT_MASSAGE_CHAIR_MANICURE_VFX_ALMOND: 'CommonBuffId' = 273045 + OBJECT_MASSAGE_CHAIR_MANICURE_VFX_COFFIN: 'CommonBuffId' = 273043 + OBJECT_MASSAGE_CHAIR_MANICURE_VFX_COMMUNITY: 'CommonBuffId' = 273046 + OBJECT_MASSAGE_CHAIR_MANICURE_VFX_ROUND: 'CommonBuffId' = 273047 + OBJECT_MASSAGE_CHAIR_MANICURE_VFX_STILETTO: 'CommonBuffId' = 273048 + OBJECT_MASSAGE_CHAIR_MANICURE_VISIBLE_BRO: 'CommonBuffId' = 271283 + OBJECT_MASSAGE_CHAIR_MANICURE_VISIBLE_CONFIDENT: 'CommonBuffId' = 271281 + OBJECT_MASSAGE_CHAIR_MANICURE_VISIBLE_FLIRTY: 'CommonBuffId' = 271280 + OBJECT_MASSAGE_CHAIR_MANICURE_VISIBLE_HAPPY: 'CommonBuffId' = 271279 + OBJECT_MASSAGE_CHAIR_MANICURE_VISIBLE_HATE_COLOR: 'CommonBuffId' = 272240 + OBJECT_MASSAGE_CHAIR_MANICURE_VISIBLE_LOVE_COLOR: 'CommonBuffId' = 272239 + OBJECT_MASSAGE_CHAIR_MANICURE_VISIBLE_PLAYFUL: 'CommonBuffId' = 271282 + OBJECT_MASSAGE_CHAIR_MANICURE_VISIBLE_WORN_AWAY: 'CommonBuffId' = 271647 + OBJECT_MASSAGE_CHAIR_MANIPEDI_BRO: 'CommonBuffId' = 271432 + OBJECT_MASSAGE_CHAIR_MANIPEDI_CONFIDENT: 'CommonBuffId' = 271433 + OBJECT_MASSAGE_CHAIR_MANIPEDI_FLIRTY: 'CommonBuffId' = 271434 + OBJECT_MASSAGE_CHAIR_MANIPEDI_HAPPY: 'CommonBuffId' = 271435 + OBJECT_MASSAGE_CHAIR_MANIPEDI_PLAYFUL: 'CommonBuffId' = 271436 + OBJECT_MASSAGE_CHAIR_OFFER_FOOT_MASSAGE: 'CommonBuffId' = 272210 + OBJECT_MASSAGE_CHAIR_OFFER_HAND_MASSAGE: 'CommonBuffId' = 272211 + OBJECT_MASSAGE_CHAIR_OFFER_MANICURE: 'CommonBuffId' = 272212 + OBJECT_MASSAGE_CHAIR_OFFER_PEDICURE: 'CommonBuffId' = 272213 + OBJECT_MASSAGE_CHAIR_ONE_DONE: 'CommonBuffId' = 271516 + OBJECT_MASSAGE_CHAIR_PAMPERED_PAWS: 'CommonBuffId' = 119946 + OBJECT_MASSAGE_CHAIR_PEDICURE_NAIL_BEIGE: 'CommonBuffId' = 271954 + OBJECT_MASSAGE_CHAIR_PEDICURE_NAIL_BLACK: 'CommonBuffId' = 271955 + OBJECT_MASSAGE_CHAIR_PEDICURE_NAIL_BLUE: 'CommonBuffId' = 271956 + OBJECT_MASSAGE_CHAIR_PEDICURE_NAIL_BLUE_LT: 'CommonBuffId' = 271957 + OBJECT_MASSAGE_CHAIR_PEDICURE_NAIL_CREAM: 'CommonBuffId' = 271975 + OBJECT_MASSAGE_CHAIR_PEDICURE_NAIL_GREEN: 'CommonBuffId' = 271958 + OBJECT_MASSAGE_CHAIR_PEDICURE_NAIL_LILAC: 'CommonBuffId' = 271959 + OBJECT_MASSAGE_CHAIR_PEDICURE_NAIL_PINK: 'CommonBuffId' = 271960 + OBJECT_MASSAGE_CHAIR_PEDICURE_NAIL_PURPLE: 'CommonBuffId' = 271961 + OBJECT_MASSAGE_CHAIR_PEDICURE_NAIL_RED: 'CommonBuffId' = 271621 + OBJECT_MASSAGE_CHAIR_PEDICURE_NAIL_SILVER: 'CommonBuffId' = 271962 + OBJECT_MASSAGE_CHAIR_PEDICURE_NAIL_WHITE: 'CommonBuffId' = 271963 + OBJECT_MASSAGE_CHAIR_PEDICURE_NAIL_YELLOW: 'CommonBuffId' = 271964 + OBJECT_MASSAGE_CHAIR_PEDICURE_PICKER_BEIGE: 'CommonBuffId' = 271965 + OBJECT_MASSAGE_CHAIR_PEDICURE_PICKER_BLACK: 'CommonBuffId' = 271977 + OBJECT_MASSAGE_CHAIR_PEDICURE_PICKER_BLUE: 'CommonBuffId' = 271966 + OBJECT_MASSAGE_CHAIR_PEDICURE_PICKER_BLUE_LT: 'CommonBuffId' = 271967 + OBJECT_MASSAGE_CHAIR_PEDICURE_PICKER_CREAM: 'CommonBuffId' = 271976 + OBJECT_MASSAGE_CHAIR_PEDICURE_PICKER_GREEN: 'CommonBuffId' = 271968 + OBJECT_MASSAGE_CHAIR_PEDICURE_PICKER_LILAC: 'CommonBuffId' = 271969 + OBJECT_MASSAGE_CHAIR_PEDICURE_PICKER_PINK: 'CommonBuffId' = 271970 + OBJECT_MASSAGE_CHAIR_PEDICURE_PICKER_PURPLE: 'CommonBuffId' = 271971 + OBJECT_MASSAGE_CHAIR_PEDICURE_PICKER_RED: 'CommonBuffId' = 271622 + OBJECT_MASSAGE_CHAIR_PEDICURE_PICKER_SILVER: 'CommonBuffId' = 271972 + OBJECT_MASSAGE_CHAIR_PEDICURE_PICKER_WHITE: 'CommonBuffId' = 271973 + OBJECT_MASSAGE_CHAIR_PEDICURE_PICKER_YELLOW: 'CommonBuffId' = 271974 + OBJECT_MASSAGE_CHAIR_PEDICURE_VISIBLE_BRO: 'CommonBuffId' = 271426 + OBJECT_MASSAGE_CHAIR_PEDICURE_VISIBLE_CONFIDENT: 'CommonBuffId' = 271427 + OBJECT_MASSAGE_CHAIR_PEDICURE_VISIBLE_FLIRTY: 'CommonBuffId' = 271428 + OBJECT_MASSAGE_CHAIR_PEDICURE_VISIBLE_HAPPY: 'CommonBuffId' = 271429 + OBJECT_MASSAGE_CHAIR_PEDICURE_VISIBLE_PLAYFUL: 'CommonBuffId' = 271430 + OBJECT_MASSAGE_CHAIR_PEDICURE_VISIBLE_WORN_AWAY: 'CommonBuffId' = 271648 + OBJECT_MASSAGE_CHAIR_REFRESHED_FLANGIES: 'CommonBuffId' = 119943 + OBJECT_MASSAGE_CHAIR_REMOVE_VISIBLE_NAIL_BUFF: 'CommonBuffId' = 273088 + OBJECT_MASSAGE_CHAIR_SOLEFUL_RUB: 'CommonBuffId' = 119944 + OBJECT_MASSAGE_CHAIR_TENDING: 'CommonBuffId' = 272164 + OBJECT_MASSAGE_CHAIR_WORN_OUT_NAILS: 'CommonBuffId' = 271649 + OBJECT_MASSAGE_TABLE_CONFIDENT_AROMA: 'CommonBuffId' = 117592 + OBJECT_MASSAGE_TABLE_CONFIDENT_AROMA_INCENSE: 'CommonBuffId' = 118898 + OBJECT_MASSAGE_TABLE_DEEPLY_RELAXED: 'CommonBuffId' = 117589 + OBJECT_MASSAGE_TABLE_DEEPLY_RELAXED_INCENSE: 'CommonBuffId' = 118899 + OBJECT_MASSAGE_TABLE_ENERGIZING_AROMA: 'CommonBuffId' = 117598 + OBJECT_MASSAGE_TABLE_ENERGIZING_AROMA_INCENSE: 'CommonBuffId' = 118900 + OBJECT_MASSAGE_TABLE_FERTILITY_BOOST: 'CommonBuffId' = 117594 + OBJECT_MASSAGE_TABLE_FERTILITY_BOOST_INCENSE: 'CommonBuffId' = 118901 + OBJECT_MASSAGE_TABLE_FOCUSING_AROMA: 'CommonBuffId' = 117600 + OBJECT_MASSAGE_TABLE_FOCUSING_AROMA_INCENSE: 'CommonBuffId' = 118902 + OBJECT_MASSAGE_TABLE_HIDDEN_JUST_GOT_MASSAGE_AROMATHERAPY: 'CommonBuffId' = 272445 + OBJECT_MASSAGE_TABLE_HIDDEN_JUST_GOT_MASSAGE_DEEPTISSUE: 'CommonBuffId' = 272446 + OBJECT_MASSAGE_TABLE_HIDDEN_JUST_GOT_MASSAGE_FERTILITY: 'CommonBuffId' = 272447 + OBJECT_MASSAGE_TABLE_HIDDEN_JUST_GOT_MASSAGE_SPORTS: 'CommonBuffId' = 272448 + OBJECT_MASSAGE_TABLE_HIDDEN_JUST_GOT_MASSAGE_STONE: 'CommonBuffId' = 272449 + OBJECT_MASSAGE_TABLE_HIDDEN_JUST_GOT_MASSAGE_SWEDISH: 'CommonBuffId' = 272450 + OBJECT_MASSAGE_TABLE_HOT_AND_HAPPY: 'CommonBuffId' = 117593 + OBJECT_MASSAGE_TABLE_HOT_AND_HAPPY_INCENSE: 'CommonBuffId' = 118903 + OBJECT_MASSAGE_TABLE_INSPIRATIONAL_AROMA: 'CommonBuffId' = 117599 + OBJECT_MASSAGE_TABLE_INSPIRATIONAL_AROMA_INCENSE: 'CommonBuffId' = 118904 + OBJECT_MASSAGE_TABLE_PASSED_GAS_HIDDEN: 'CommonBuffId' = 117597 + OBJECT_MASSAGE_TABLE_PREPPED_FOR_FITNESS: 'CommonBuffId' = 117591 + OBJECT_MASSAGE_TABLE_PREPPED_FOR_FITNESS_INCENSE: 'CommonBuffId' = 118906 + OBJECT_MASSAGE_TABLE_RELAXING_MASSAGE: 'CommonBuffId' = 117588 + OBJECT_MASSAGE_TABLE_RELAXING_MASSAGE_INCENSE: 'CommonBuffId' = 118907 + OBJECT_MASSAGE_TABLE_TENDING: 'CommonBuffId' = 272384 + OBJECT_MASSAGE_TABLE_UNCOMFORTABLE_MASSAGE: 'CommonBuffId' = 117596 + OBJECT_MASSAGE_TABLE_WORST_MASSAGE_EVER: 'CommonBuffId' = 117590 + OBJECT_MEDITATION_STOOL_CHILD_VFX: 'CommonBuffId' = 272117 + OBJECT_MICROSCOPE_INSPIRED: 'CommonBuffId' = 29927 + OBJECT_MICROWAVE_COLD: 'CommonBuffId' = 23985 + OBJECT_MICROWAVE_UPGRADED: 'CommonBuffId' = 28944 + OBJECT_MIRROR_ADMIRE_SELF_EMBARRASSED: 'CommonBuffId' = 97774 + OBJECT_MIRROR_ADMIRE_SELF_HAPPY: 'CommonBuffId' = 97771 + OBJECT_MIRROR_FEELING_FRUMPY: 'CommonBuffId' = 12440 + OBJECT_MIRROR_GUSSY_UP: 'CommonBuffId' = 12452 + OBJECT_MONKEY_BARS_PLAY: 'CommonBuffId' = 31649 + OBJECT_MOTION_GAMING_RIG_ADVENTURE: 'CommonBuffId' = 29392 + OBJECT_MOTION_GAMING_RIG_FAMILY: 'CommonBuffId' = 29399 + OBJECT_MOTION_GAMING_RIG_PUZZLE: 'CommonBuffId' = 39915 + OBJECT_MOTION_GAMING_RIG_SPORTS: 'CommonBuffId' = 29400 + OBJECT_MOVIE_AUTONOMY: 'CommonBuffId' = 191128 + OBJECT_MOVIE_BIG_SCREEN_LET_DOWN: 'CommonBuffId' = 129018 + OBJECT_MOVIE_BORING_MOVIE: 'CommonBuffId' = 129016 + OBJECT_MOVIE_CINEMA_SIN: 'CommonBuffId' = 129017 + OBJECT_MOVIE_GENRE_STAPLE: 'CommonBuffId' = 129020 + OBJECT_MOVIE_HIDDEN_CUDDLE_DONT_REACT: 'CommonBuffId' = 130510 + OBJECT_MOVIE_HIDDEN_FALL_ASLEEP: 'CommonBuffId' = 129462 + OBJECT_MOVIE_HIDDEN_SHUSH_TARGET: 'CommonBuffId' = 129286 + OBJECT_MOVIE_HIDDEN_WATCHED_ACTION: 'CommonBuffId' = 128976 + OBJECT_MOVIE_HIDDEN_WATCHED_COMEDY: 'CommonBuffId' = 128977 + OBJECT_MOVIE_HIDDEN_WATCHED_FAMILY: 'CommonBuffId' = 128979 + OBJECT_MOVIE_HIDDEN_WATCHED_HORROR: 'CommonBuffId' = 128978 + OBJECT_MOVIE_HIDDEN_WATCHED_ROMANCE: 'CommonBuffId' = 128980 + OBJECT_MOVIE_INTERESTING_FLICK: 'CommonBuffId' = 129019 + OBJECT_MOVIE_SILVER_SCREEN_MASTERPIECE: 'CommonBuffId' = 129021 + OBJECT_MUD_BATH_DECAY_MOD_FREEZE_FUN: 'CommonBuffId' = 121807 + OBJECT_MUD_BATH_MUCKY_MUD: 'CommonBuffId' = 120372 + OBJECT_MUD_BATH_MUD_IS_MAGIC: 'CommonBuffId' = 120371 + OBJECT_MUD_BATH_MUD_IS_MAGIC_INCENSE: 'CommonBuffId' = 120500 + OBJECT_MURAL_CAUGHT_DEFACING: 'CommonBuffId' = 150177 + OBJECT_MURAL_EP08_FLOOR_SCOOT_COOLDOWN: 'CommonBuffId' = 220779 + OBJECT_MURAL_FINISHED_A_MURAL: 'CommonBuffId' = 153091 + OBJECT_MURAL_IMPROVED_ART: 'CommonBuffId' = 149454 + OBJECT_MURAL_KICK_OFF: 'CommonBuffId' = 147462 + OBJECT_MURAL_KICK_OFF_NOW: 'CommonBuffId' = 154444 + OBJECT_MURAL_MARRED: 'CommonBuffId' = 149451 + OBJECT_MURAL_POLITICAL_MURAL: 'CommonBuffId' = 153267 + OBJECT_MURAL_SCOOT_COOLDOWN: 'CommonBuffId' = 147243 + OBJECT_MURAL_STATIC_COMMODITY_SCOLD: 'CommonBuffId' = 149995 + OBJECT_MURPHY_BED_REMOTE_TECH: 'CommonBuffId' = 230315 + OBJECT_MURPHY_BED_STUCK_UNDER_BED: 'CommonBuffId' = 230314 + OBJECT_MURPHY_BED_SWALLOWED_BY_BED: 'CommonBuffId' = 230318 + OBJECT_OCEAN_UNCOMFORTABLY_WARM: 'CommonBuffId' = 212979 + OBJECT_OFF_THE_GRID_BAD_RECEPTION: 'CommonBuffId' = 214402 + OBJECT_OFF_THE_GRID_CONSUME_AMPHIBIAN_AGILITY: 'CommonBuffId' = 235238 + OBJECT_OFF_THE_GRID_CONSUME_CRITTER: 'CommonBuffId' = 235234 + OBJECT_OFF_THE_GRID_CONSUME_FEASTED_LIKE_A_KING: 'CommonBuffId' = 235235 + OBJECT_OFF_THE_GRID_CONSUME_FORAGER_DELIGHT: 'CommonBuffId' = 235239 + OBJECT_OFF_THE_GRID_CONSUME_FRESH_CATCH: 'CommonBuffId' = 235237 + OBJECT_OFF_THE_GRID_CONSUME_LIVING_OFF_THE_LAND: 'CommonBuffId' = 235233 + OBJECT_OFF_THE_GRID_CONSUME_NATURES_REVENGE: 'CommonBuffId' = 235232 + OBJECT_OFF_THE_GRID_CONSUME_OMEGA_BRAIN_BOOST: 'CommonBuffId' = 235236 + OBJECT_OFF_THE_GRID_COOLDOWN_GATHER_SNOW: 'CommonBuffId' = 237053 + OBJECT_OFF_THE_GRID_COOLDOWN_GATHER_WATER: 'CommonBuffId' = 237051 + OBJECT_OFF_THE_GRID_FRIGIDLY_FRESH: 'CommonBuffId' = 212298 + OBJECT_OFF_THE_GRID_FUMES: 'CommonBuffId' = 212306 + OBJECT_OFF_THE_GRID_NEGATIVE_SORE_FROM_CHORES: 'CommonBuffId' = 237206 + OBJECT_OFF_THE_GRID_POSITIVE_CHAR: 'CommonBuffId' = 235225 + OBJECT_OFF_THE_GRID_POSITIVE_DROPPED_CALL: 'CommonBuffId' = 235223 + OBJECT_OFF_THE_GRID_POSITIVE_LOCAL_WATER: 'CommonBuffId' = 235226 + OBJECT_OFF_THE_GRID_POSITIVE_SPIT_SHINED: 'CommonBuffId' = 235224 + OBJECT_OVER_GLOATED: 'CommonBuffId' = 34086 + OBJECT_PAINTING_VIEW_INSPIRED: 'CommonBuffId' = 33647 + OBJECT_PAINTING_VIEW_TRAGIC_CLOWN_SAD: 'CommonBuffId' = 132564 + OBJECT_PET_BREAK_HIDING: 'CommonBuffId' = 163827 + OBJECT_PET_MINOR_CAGE_FED_RODENT: 'CommonBuffId' = 184003 + OBJECT_PET_MINOR_CAGE_FREEZE_RODENT_DISEASE: 'CommonBuffId' = 185938 + OBJECT_PET_MINOR_CAGE_HIDDEN_RODENT_DISEASE_CURED: 'CommonBuffId' = 185841 + OBJECT_PET_MINOR_CAGE_NEW_RODENT: 'CommonBuffId' = 184004 + OBJECT_PET_MINOR_CAGE_OBSERVE_HIDE_AND_SEEK: 'CommonBuffId' = 181475 + OBJECT_PET_MINOR_CAGE_OBSERVE_PIPE_SIZE_EXERCISE: 'CommonBuffId' = 181474 + OBJECT_PET_MINOR_CAGE_OBSERVE_RESTED_RODENT: 'CommonBuffId' = 181476 + OBJECT_PET_MINOR_CAGE_OBSERVE_RODENT_PEACE: 'CommonBuffId' = 181473 + OBJECT_PET_MINOR_CAGE_PLAYFUL_RODENT_PLAY_TIME: 'CommonBuffId' = 183684 + OBJECT_PET_MINOR_CAGE_RODENT_BITE: 'CommonBuffId' = 185508 + OBJECT_PET_MINOR_CAGE_RODENT_DEATH: 'CommonBuffId' = 188565 + OBJECT_PET_MINOR_CAGE_RODENT_DISEASE_1: 'CommonBuffId' = 181672 + OBJECT_PET_MINOR_CAGE_RODENT_DISEASE_2: 'CommonBuffId' = 181673 + OBJECT_PET_MINOR_CAGE_RODENT_DISEASE_3: 'CommonBuffId' = 181674 + OBJECT_PET_MINOR_CAGE_RODENT_FREEDOM: 'CommonBuffId' = 184005 + OBJECT_PET_RECIPE_ATE_PET_FOOD: 'CommonBuffId' = 169582 + OBJECT_PET_RECIPE_ATE_PET_FOOD_TODDLER: 'CommonBuffId' = 174911 + OBJECT_PET_RECIPE_DRANK_PET_FOOD: 'CommonBuffId' = 179771 + OBJECT_PET_RECIPE_DRANK_PET_FOOD_GLUTTON: 'CommonBuffId' = 179833 + OBJECT_PET_RECIPE_GLUTTON: 'CommonBuffId' = 169583 + OBJECT_PET_RECIPE_KISSED_BY_MINTY_BREATH: 'CommonBuffId' = 169580 + OBJECT_PET_RECIPE_MINTY_BREATH: 'CommonBuffId' = 169581 + OBJECT_PHONE_CHAT_SUCCESS: 'CommonBuffId' = 24064 + OBJECT_PHONE_HIGH_SCORE: 'CommonBuffId' = 97941 + OBJECT_PHONE_PRANK_FAIL: 'CommonBuffId' = 30831 + OBJECT_PHONE_PRANK_SUCCESS: 'CommonBuffId' = 30832 + OBJECT_PHONE_RESPOND_TO_MAIL_NEGATIVE_CRITICISM: 'CommonBuffId' = 136682 + OBJECT_PHONE_RESPOND_TO_MAIL_POSITIVE_FEEDBACK: 'CommonBuffId' = 136683 + OBJECT_PHONE_RESPOND_TO_MAIL_TROLLED: 'CommonBuffId' = 136679 + OBJECT_PHONE_SAD_HOTLINE: 'CommonBuffId' = 24365 + OBJECT_PHONE_SEND_SELFIE_FAILURE: 'CommonBuffId' = 377576 + OBJECT_PHONE_SEND_TEXT_SUCCESS: 'CommonBuffId' = 24011 + OBJECT_PIANO_COOL_KEY_CHORDS: 'CommonBuffId' = 34519 + OBJECT_PIANO_JAZZED_UP: 'CommonBuffId' = 24615 + OBJECT_PIANO_KILLER_KEY_CHORDS: 'CommonBuffId' = 36972 + OBJECT_PING_PONG_BETTER_SCHOOL_WINS: 'CommonBuffId' = 212748 + OBJECT_PIPE_ORGAN_PALLIATIVE_PIPES: 'CommonBuffId' = 151298 + OBJECT_PLASTIC_FLOWER_AROUND_AND_AROUND: 'CommonBuffId' = 143488 + OBJECT_PLASTIC_FLOWER_MESMERIZED: 'CommonBuffId' = 140845 + OBJECT_PLUMBING_USE_DIRTY: 'CommonBuffId' = 10165 + OBJECT_PODIUM_BRILLIANT_ORATOR: 'CommonBuffId' = 137263 + OBJECT_PODIUM_EVENT_RECEIVED_HIDDEN: 'CommonBuffId' = 136959 + OBJECT_PODIUM_FEEL_THE_CALL: 'CommonBuffId' = 136949 + OBJECT_PODIUM_FEEL_THE_CALL_ANGRY: 'CommonBuffId' = 136952 + OBJECT_PODIUM_FEEL_THE_CALL_CONFIDENT: 'CommonBuffId' = 136953 + OBJECT_PODIUM_FEEL_THE_CALL_ENERGIZED: 'CommonBuffId' = 136954 + OBJECT_PODIUM_FEEL_THE_CALL_HIDDEN: 'CommonBuffId' = 155448 + OBJECT_PODIUM_FEEL_THE_CALL_INSPIRED: 'CommonBuffId' = 136955 + OBJECT_PODIUM_GIVE_EULOGY: 'CommonBuffId' = 152738 + OBJECT_PODIUM_LAME_DRIVEL: 'CommonBuffId' = 136950 + OBJECT_PODIUM_LAME_DRIVEL_HIDDEN: 'CommonBuffId' = 155449 + OBJECT_PODIUM_WATCHING_SPEECH_ANGRY_HIDDEN: 'CommonBuffId' = 136939 + OBJECT_PODIUM_WATCHING_SPEECH_CONFIDENT_HIDDEN: 'CommonBuffId' = 136940 + OBJECT_PODIUM_WATCHING_SPEECH_ENERGIZED_HIDDEN: 'CommonBuffId' = 136941 + OBJECT_PODIUM_WATCHING_SPEECH_HIDDEN: 'CommonBuffId' = 136824 + OBJECT_PODIUM_WATCHING_SPEECH_INSPIRED_HIDDEN: 'CommonBuffId' = 136942 + OBJECT_POOL_UNCOMFORTABLY_WARM: 'CommonBuffId' = 107550 + OBJECT_POTTY_ACCIDENT: 'CommonBuffId' = 144960 + OBJECT_POTTY_BEING_MENTORED_HIDDEN: 'CommonBuffId' = 145219 + OBJECT_POTTY_BEING_MENTORED_HIDDEN_CLINGY: 'CommonBuffId' = 154563 + OBJECT_PREVENT_FREEZING: 'CommonBuffId' = 184873 + OBJECT_PUBLIC_BATHROOM_SO_GROSS: 'CommonBuffId' = 38544 + OBJECT_PUMPKIN_CARVED_ART: 'CommonBuffId' = 126865 + OBJECT_PUMPKIN_CARVE_PUMPKIN: 'CommonBuffId' = 125551 + OBJECT_PUMPKIN_INTERESTING_CARVING: 'CommonBuffId' = 125061 + OBJECT_PUMPKIN_PUMPKIN_HEAD: 'CommonBuffId' = 125058 + OBJECT_PUMPKIN_SMASHING_PUMPKINS: 'CommonBuffId' = 125060 + OBJECT_RANCH_NECTAR_AFTER_GLOW_CONFIDENT: 'CommonBuffId' = 323637 + OBJECT_RANCH_NECTAR_AFTER_GLOW_ENERGIZED: 'CommonBuffId' = 323638 + OBJECT_RANCH_NECTAR_AFTER_GLOW_FLIRTY: 'CommonBuffId' = 323639 + OBJECT_RANCH_NECTAR_AFTER_GLOW_HAPPY: 'CommonBuffId' = 323662 + OBJECT_RANCH_NECTAR_AFTER_GLOW_INSPIRED: 'CommonBuffId' = 323640 + OBJECT_RANCH_NECTAR_AFTER_GLOW_UNCOMFORTABLE: 'CommonBuffId' = 323663 + OBJECT_RANCH_NECTAR_MAKER_ENERGIZED: 'CommonBuffId' = 333569 + OBJECT_RANCH_NECTAR_MAKER_PLAYFUL: 'CommonBuffId' = 333567 + OBJECT_RANCH_NECTAR_MAKER_UNCOMFORTABLE: 'CommonBuffId' = 333566 + OBJECT_RANCH_NECTAR_MOOD_EFFECTS_CONFIDENT_1: 'CommonBuffId' = 315780 + OBJECT_RANCH_NECTAR_MOOD_EFFECTS_CONFIDENT_3: 'CommonBuffId' = 315781 + OBJECT_RANCH_NECTAR_MOOD_EFFECTS_CONFIDENT_6: 'CommonBuffId' = 315782 + OBJECT_RANCH_NECTAR_MOOD_EFFECTS_ENERGIZED_1: 'CommonBuffId' = 315784 + OBJECT_RANCH_NECTAR_MOOD_EFFECTS_ENERGIZED_3: 'CommonBuffId' = 315785 + OBJECT_RANCH_NECTAR_MOOD_EFFECTS_ENERGIZED_6: 'CommonBuffId' = 315786 + OBJECT_RANCH_NECTAR_MOOD_EFFECTS_FLIRTY_1: 'CommonBuffId' = 315788 + OBJECT_RANCH_NECTAR_MOOD_EFFECTS_FLIRTY_3: 'CommonBuffId' = 315789 + OBJECT_RANCH_NECTAR_MOOD_EFFECTS_FLIRTY_6: 'CommonBuffId' = 315790 + OBJECT_RANCH_NECTAR_MOOD_EFFECTS_HAPPY_1: 'CommonBuffId' = 315792 + OBJECT_RANCH_NECTAR_MOOD_EFFECTS_HAPPY_2: 'CommonBuffId' = 323632 + OBJECT_RANCH_NECTAR_MOOD_EFFECTS_HAPPY_3: 'CommonBuffId' = 315793 + OBJECT_RANCH_NECTAR_MOOD_EFFECTS_HAPPY_4: 'CommonBuffId' = 323633 + OBJECT_RANCH_NECTAR_MOOD_EFFECTS_HAPPY_6: 'CommonBuffId' = 315794 + OBJECT_RANCH_NECTAR_MOOD_EFFECTS_HIDDEN_AGED: 'CommonBuffId' = 323636 + OBJECT_RANCH_NECTAR_MOOD_EFFECTS_HIDDEN_POTATO: 'CommonBuffId' = 323635 + OBJECT_RANCH_NECTAR_MOOD_EFFECTS_INSPIRED_1: 'CommonBuffId' = 315796 + OBJECT_RANCH_NECTAR_MOOD_EFFECTS_INSPIRED_3: 'CommonBuffId' = 315797 + OBJECT_RANCH_NECTAR_MOOD_EFFECTS_INSPIRED_6: 'CommonBuffId' = 315798 + OBJECT_RANCH_NECTAR_PASSED_OUT: 'CommonBuffId' = 323417 + OBJECT_RANCH_NECTAR_TRAIT_BAD: 'CommonBuffId' = 338174 + OBJECT_RANCH_NECTAR_TRAIT_GOOD: 'CommonBuffId' = 338172 + OBJECT_RANCH_NECTAR_TRASH: 'CommonBuffId' = 323866 + OBJECT_RANCH_NECTAR_WILDGRASS: 'CommonBuffId' = 323665 + OBJECT_RANCH_NECTAR_WILDGRASS_AGED: 'CommonBuffId' = 323666 + OBJECT_READ_MAGAZINE_COOLDOWN_HIDDEN: 'CommonBuffId' = 120289 + OBJECT_ROCKET_SHIP_BITTEN_BY_ALIEN: 'CommonBuffId' = 39051 + OBJECT_ROCKET_SHIP_BUSTED_BY_SPACE_POLICE: 'CommonBuffId' = 39046 + OBJECT_ROCKET_SHIP_ESCAPED_CRASH: 'CommonBuffId' = 8580 + OBJECT_ROCKET_SHIP_EXPLORED_SPACE: 'CommonBuffId' = 8581 + OBJECT_ROCKET_SHIP_FIFTY_MILE_HIGH_CLUB: 'CommonBuffId' = 8584 + OBJECT_ROCKET_SHIP_FIFTY_MILE_HIGH_CLUB_TEEN: 'CommonBuffId' = 100785 + OBJECT_ROCKET_SHIP_JOINED_THE_FIFTY_MILE_HIGH_CLUB: 'CommonBuffId' = 8583 + OBJECT_ROCKET_SHIP_JOINED_THE_FIFTY_MILE_HIGH_CLUB_TEEN: 'CommonBuffId' = 100784 + OBJECT_ROCKET_SHIP_OPPRESSED_COLONISTS: 'CommonBuffId' = 39044 + OBJECT_ROCKET_SHIP_ORBITED_MOON: 'CommonBuffId' = 38471 + OBJECT_ROCKET_SHIP_SPACE_BATTLE_WIN: 'CommonBuffId' = 38737 + OBJECT_ROCKET_SHIP_SPACE_CHEESE: 'CommonBuffId' = 132354 + OBJECT_ROCKING_CHAIR_ELDER: 'CommonBuffId' = 242372 + OBJECT_ROCKING_CHAIR_REMINISCE_ANGRY: 'CommonBuffId' = 240871 + OBJECT_ROCKING_CHAIR_REMINISCE_EMBARRASSED: 'CommonBuffId' = 240872 + OBJECT_ROCKING_CHAIR_REMINISCE_HAPPY: 'CommonBuffId' = 240851 + OBJECT_ROCKING_CHAIR_REMINISCE_SAD: 'CommonBuffId' = 240869 + OBJECT_ROCKING_CHAIR_ROCK: 'CommonBuffId' = 242370 + OBJECT_SACK_LUNCH_HOMEMADE_MEAL: 'CommonBuffId' = 165119 + OBJECT_SACK_LUNCH_HOMEMADE_MEAL_HIGH: 'CommonBuffId' = 168705 + OBJECT_SCHOOL_LOCKER_DECORATION_COOLDOWN: 'CommonBuffId' = 290922 + OBJECT_SCHOOL_LOCKER_SNACK_COOLDOWN: 'CommonBuffId' = 298488 + OBJECT_SCHOOL_LOCKER_SOMETHING_ROTTEN: 'CommonBuffId' = 277069 + OBJECT_SEATING_COZY_LAZY: 'CommonBuffId' = 75859 + OBJECT_SEATING_HAPPY: 'CommonBuffId' = 25003 + OBJECT_SEATING_UNCOMFORTABLE: 'CommonBuffId' = 24999 + OBJECT_SERENADED: 'CommonBuffId' = 24621 + OBJECT_SERENADER: 'CommonBuffId' = 24623 + OBJECT_SHOWER_BRISK: 'CommonBuffId' = 39963 + OBJECT_SHOWER_CLEAN_VOCAL_SKILLS: 'CommonBuffId' = 141950 + OBJECT_SHOWER_DO_NOT_DISTURB: 'CommonBuffId' = 28592 + OBJECT_SHOWER_INSPIRATION: 'CommonBuffId' = 39849 + OBJECT_SHOWER_MESS_AROUND: 'CommonBuffId' = 227533 + OBJECT_SHOWER_NON_SINGING_HIDDEN: 'CommonBuffId' = 141946 + OBJECT_SHOWER_STEAMY: 'CommonBuffId' = 39863 + OBJECT_SHOWER_TAKE_SHOWER_HIGH_QUALITY: 'CommonBuffId' = 9966 + OBJECT_SHOWER_TAKE_SHOWER_HIGH_QUALITY_UPGRADE: 'CommonBuffId' = 10135 + OBJECT_SHOWER_TAKE_SHOWER_LOW_QUALITY: 'CommonBuffId' = 9967 + OBJECT_SHOWER_TAKE_SHOWER_UPGRADE: 'CommonBuffId' = 10134 + OBJECT_SINK_BRUSH_TEETH: 'CommonBuffId' = 12523 + OBJECT_SINK_IS_WASHING_DIRTY_DISHES: 'CommonBuffId' = 76836 + OBJECT_SINK_SOAP_UPGRADE: 'CommonBuffId' = 28529 + OBJECT_SKATING_RINK_BACKWARDS_REMOVE_TIMER: 'CommonBuffId' = 191015 + OBJECT_SKATING_RINK_BACKWARDS_WALK_STYLE_ICE: 'CommonBuffId' = 180434 + OBJECT_SKATING_RINK_BACKWARDS_WALK_STYLE_ROLLER: 'CommonBuffId' = 183908 + OBJECT_SKATING_RINK_ICE_SKILL_HIGH: 'CommonBuffId' = 183869 + OBJECT_SKATING_RINK_ICE_SKILL_LOW: 'CommonBuffId' = 180342 + OBJECT_SKATING_RINK_ICE_SKILL_MED: 'CommonBuffId' = 185397 + OBJECT_SKATING_RINK_PRACTICE_TRICKS: 'CommonBuffId' = 173346 + OBJECT_SKATING_RINK_PRACTICE_TRICKS_NO_VFX: 'CommonBuffId' = 189879 + OBJECT_SKATING_RINK_ROLLER_SKILL_HIGH: 'CommonBuffId' = 183901 + OBJECT_SKATING_RINK_ROLLER_SKILL_LOW: 'CommonBuffId' = 183902 + OBJECT_SKATING_RINK_ROLLER_SKILL_MED: 'CommonBuffId' = 185398 + OBJECT_SKATING_RINK_ROUTINE: 'CommonBuffId' = 185103 + OBJECT_SKATING_RINK_ROUTINE_NO_VFX: 'CommonBuffId' = 189878 + OBJECT_SKATING_RINK_ROUTINE_REACTIONS_FAILURE: 'CommonBuffId' = 190819 + OBJECT_SKATING_RINK_ROUTINE_REACTIONS_SUCCESS: 'CommonBuffId' = 190818 + OBJECT_SKATING_RINK_ROUTINE_SKATER_ADEQUATE: 'CommonBuffId' = 180131 + OBJECT_SKATING_RINK_ROUTINE_SKATER_AMAZING: 'CommonBuffId' = 180128 + OBJECT_SKATING_RINK_ROUTINE_SKATER_EMBARRASSING_NEG: 'CommonBuffId' = 180129 + OBJECT_SKATING_RINK_ROUTINE_SKATER_MESSED_UP_NEG: 'CommonBuffId' = 180130 + OBJECT_SKATING_RINK_ROUTINE_SKATER_PERFECT: 'CommonBuffId' = 180127 + OBJECT_SKATING_RINK_ROUTINE_WATCHER_ADEQUATE: 'CommonBuffId' = 180124 + OBJECT_SKATING_RINK_ROUTINE_WATCHER_PERFECT: 'CommonBuffId' = 180125 + OBJECT_SKATING_RINK_ROUTINE_WATCHER_TERRIBLE: 'CommonBuffId' = 180126 + OBJECT_SLIPPY_SLIDE_BACKYARD_WATER_PACK: 'CommonBuffId' = 140355 + OBJECT_SLIPPY_SLIDE_FOAMY_SLIDE: 'CommonBuffId' = 143346 + OBJECT_SLIPPY_SLIDE_HIDDEN_BROADCASTER_FAIL: 'CommonBuffId' = 140878 + OBJECT_SLIPPY_SLIDE_HIDDEN_BROADCASTER_SUCCESS: 'CommonBuffId' = 140879 + OBJECT_SLIPPY_SLIDE_HIDDEN_BROADCASTER_TRICK_FAIL: 'CommonBuffId' = 141457 + OBJECT_SLIPPY_SLIDE_HIDDEN_BROADCASTER_TRICK_SUCCESS: 'CommonBuffId' = 141458 + OBJECT_SLIPPY_SLIDE_HIDDEN_SLIDE_FAIL: 'CommonBuffId' = 140352 + OBJECT_SLIPPY_SLIDE_HIDDEN_SLIDING: 'CommonBuffId' = 142638 + OBJECT_SLIPPY_SLIDE_HIDDEN_SOAP_SUDS: 'CommonBuffId' = 141922 + OBJECT_SLIPPY_SLIDE_HIDDEN_SOAP_SUDS_CHILDREN: 'CommonBuffId' = 143421 + OBJECT_SLIPPY_SLIDE_TOO_SLIPPERY: 'CommonBuffId' = 140353 + OBJECT_SLIPPY_SLIDE_TRICKTASTROPHE: 'CommonBuffId' = 140354 + OBJECT_SLIPPY_SLIDE_TRICK_SLIDE_MASTER: 'CommonBuffId' = 140356 + OBJECT_SLIPPY_SLIDE_WATCH_BRO_SLIDE: 'CommonBuffId' = 141306 + OBJECT_SLIPPY_SLIDE_WATCH_GREAT_TRICKS: 'CommonBuffId' = 141307 + OBJECT_SLIPPY_SLIDE_WATCH_LOOKS_LIKE_FUN: 'CommonBuffId' = 141305 + OBJECT_SLIPPY_SLIDE_WATCH_SHOWOFF: 'CommonBuffId' = 141310 + OBJECT_SLIPPY_SLIDE_WATCH_SLIDE_FAIL: 'CommonBuffId' = 141309 + OBJECT_SLIPPY_SLIDE_WATCH_THAT_HAD_TO_HURT: 'CommonBuffId' = 141308 + OBJECT_SMART_HUB_BEEN_COMPLIMENTED: 'CommonBuffId' = 204332 + OBJECT_SMART_HUB_BEEN_INSULTED: 'CommonBuffId' = 204328 + OBJECT_SMART_HUB_GOT_AFFIRMATION: 'CommonBuffId' = 204003 + OBJECT_SMART_HUB_GOT_JOKE: 'CommonBuffId' = 204004 + OBJECT_SMART_HUB_GOT_NEWS: 'CommonBuffId' = 203963 + OBJECT_SMART_HUB_MISBEHAVIOR_ANGRY: 'CommonBuffId' = 204546 + OBJECT_SMART_HUB_MISBEHAVIOR_SAD: 'CommonBuffId' = 204547 + OBJECT_SMART_HUB_SERVICE_PROVIDED_PIZZA: 'CommonBuffId' = 204929 + OBJECT_SPACE_HEATER_HEATED_SURROUNDINGS: 'CommonBuffId' = 252945 + OBJECT_SPACE_HEATER_WARMED_BY_SPACE_HEATER: 'CommonBuffId' = 252944 + OBJECT_SQUAT_TOILET_PRANKED: 'CommonBuffId' = 347302 + OBJECT_STEAM_ROOM_HIDDEN_DEATH_BY_STEAM: 'CommonBuffId' = 119830 + OBJECT_STEAM_ROOM_HIDDEN_GET_OUT: 'CommonBuffId' = 122213 + OBJECT_STEAM_ROOM_HIDDEN_RELAXING: 'CommonBuffId' = 119633 + OBJECT_STEAM_ROOM_HOT_N_STEAMY: 'CommonBuffId' = 119397 + OBJECT_STEAM_ROOM_ROTTEN_EGGS: 'CommonBuffId' = 119398 + OBJECT_STEAM_ROOM_SATISFACTORY_STEAMING: 'CommonBuffId' = 119393 + OBJECT_STEAM_ROOM_STUPENDOUS_STEAMING: 'CommonBuffId' = 119394 + OBJECT_STEAM_ROOM_SUPERFLUOUS_STEAMING: 'CommonBuffId' = 119396 + OBJECT_STEAM_ROOM_SUPREME_STEAMING: 'CommonBuffId' = 119395 + OBJECT_STEREO_CLASSICAL_HIDDEN: 'CommonBuffId' = 354086 + OBJECT_STEREO_MUSIC: 'CommonBuffId' = 96812 + OBJECT_STEREO_MUSIC_FOCUS: 'CommonBuffId' = 240288 + OBJECT_STEREO_MUSIC_METAL: 'CommonBuffId' = 240287 + OBJECT_STEREO_MUSIC_ROMANCE: 'CommonBuffId' = 370714 + OBJECT_STEREO_MUSIC_TODDLER: 'CommonBuffId' = 147776 + OBJECT_STEREO_NEW_AGE_BORED: 'CommonBuffId' = 118102 + OBJECT_STEREO_NEW_AGE_FOCUSED: 'CommonBuffId' = 118101 + OBJECT_STEREO_NEW_AGE_HIDDEN: 'CommonBuffId' = 354087 + OBJECT_STEREO_SUMMER_STRUT: 'CommonBuffId' = 179825 + OBJECT_STEREO_WINTER_HOLIDAY: 'CommonBuffId' = 179922 + OBJECT_STOVE_HEAT_SENSOR: 'CommonBuffId' = 28861 + OBJECT_STUFFED_ANIMAL_HAPPY: 'CommonBuffId' = 33305 + OBJECT_STUFFED_ANIMAL_HUG_COOLDOWN: 'CommonBuffId' = 157859 + OBJECT_STUFFED_ANIMAL_PLAYFUL: 'CommonBuffId' = 31778 + OBJECT_SURFACE_USE_DIRTY: 'CommonBuffId' = 36389 + OBJECT_SWING_SET_EXIT_SWING: 'CommonBuffId' = 190191 + OBJECT_TELESCOPE_INSPIRED: 'CommonBuffId' = 29876 + OBJECT_TELESCOPE_LOGIC_FESTIVAL_CAUGHT_SPYING: 'CommonBuffId' = 144282 + OBJECT_TELESCOPE_LOGIC_FESTIVAL_WITNESSED_APARTMENT: 'CommonBuffId' = 144283 + OBJECT_TELESCOPE_NEIGHBORS_BORED: 'CommonBuffId' = 38838 + OBJECT_TELESCOPE_NEIGHBORS_EMBARRASSED: 'CommonBuffId' = 38840 + OBJECT_TELESCOPE_NEIGHBORS_FLIRTY: 'CommonBuffId' = 29910 + OBJECT_TELESCOPE_NEIGHBORS_PLAYFUL: 'CommonBuffId' = 38839 + OBJECT_TEMPERATURE_MODIFIER_EXERCISING: 'CommonBuffId' = 189969 + OBJECT_TEMPERATURE_MODIFIER_FIRE_CLIMBING: 'CommonBuffId' = 189818 + OBJECT_TEMPERATURE_MODIFIER_KIDDIE_POOL: 'CommonBuffId' = 189728 + OBJECT_TENT_GREAT_SCARE: 'CommonBuffId' = 105338 + OBJECT_TENT_HIDDEN_IN_TENT: 'CommonBuffId' = 185156 + OBJECT_TENT_REACTED_TO_WOO_HOO_HIDDEN: 'CommonBuffId' = 107517 + OBJECT_TENT_SCARED_BLADDERLESS: 'CommonBuffId' = 105337 + OBJECT_TENT_SMOKEY: 'CommonBuffId' = 105004 + OBJECT_TENT_WOOHOOED_IN_THE_WILD: 'CommonBuffId' = 105985 + OBJECT_TODDLER_JUNGLE_GYM_MAKE_BELIEVE_PIRATE: 'CommonBuffId' = 172892 + OBJECT_TODDLER_JUNGLE_GYM_MAKE_BELIEVE_PLAY_WITH_PIRATE: 'CommonBuffId' = 173516 + OBJECT_TODDLER_JUNGLE_GYM_MAKE_BELIEVE_PLAY_WITH_ROCKET: 'CommonBuffId' = 173517 + OBJECT_TODDLER_JUNGLE_GYM_MAKE_BELIEVE_ROCKET: 'CommonBuffId' = 172891 + OBJECT_TODDLER_JUNGLE_GYM_MAKE_BELIEVE_SHARED_WORLD_IMAGINATION: 'CommonBuffId' = 172960 + OBJECT_TODDLER_JUNGLE_GYM_SLIDE_FUN_SLIDE: 'CommonBuffId' = 171990 + OBJECT_TODDLER_JUNGLE_GYM_SLIDE_SCARY_SLIDE: 'CommonBuffId' = 172004 + OBJECT_TODDLER_JUNGLE_GYM_TUNNELS_A_MY_TUNNEL: 'CommonBuffId' = 171003 + OBJECT_TODDLER_JUNGLE_GYM_TUNNELS_H_TUNNEL_FUN: 'CommonBuffId' = 171002 + OBJECT_TODDLER_JUNGLE_GYM_TUNNELS_P_TUNNEL_ADVENTURE: 'CommonBuffId' = 171000 + OBJECT_TODDLER_JUNGLE_GYM_TUNNELS_S_SCRAPED_KNEE: 'CommonBuffId' = 171001 + OBJECT_TOILET_BATHROOM_BUDDY: 'CommonBuffId' = 214242 + OBJECT_TOILET_BIDET: 'CommonBuffId' = 96968 + OBJECT_TOILET_JUST_CRIED: 'CommonBuffId' = 214241 + OBJECT_TOILET_LOW_QUALITY: 'CommonBuffId' = 10450 + OBJECT_TOILET_NO_TABLET: 'CommonBuffId' = 100122 + OBJECT_TOILET_PRANKED: 'CommonBuffId' = 227118 + OBJECT_TOILET_TALKING_FAMILIARITY_REACTION_COOLDOWN: 'CommonBuffId' = 134855 + OBJECT_TOILET_TALKING_HIDDEN_NEGATIVE_STC: 'CommonBuffId' = 138089 + OBJECT_TOILET_TALKING_MASSAGE_ENERGIZED: 'CommonBuffId' = 134537 + OBJECT_TOILET_TALKING_WATCH_FOCUSED: 'CommonBuffId' = 142802 + OBJECT_TOILET_TALKING_WATCH_PLAYFUL: 'CommonBuffId' = 142803 + OBJECT_TOXIC_FIRE_LEAF_EXTREME_ITCH: 'CommonBuffId' = 102123 + OBJECT_TOXIC_FIRE_LEAF_EXTREME_ITCH_BASE_GAME: 'CommonBuffId' = 120040 + OBJECT_TOXIC_FIRE_LEAF_IRKSOME_ITCH: 'CommonBuffId' = 102101 + OBJECT_TOXIC_FIRE_LEAF_IRKSOME_ITCH_BASE_GAME: 'CommonBuffId' = 120041 + OBJECT_TOXIC_FIRE_LEAF_UNRELENTING_ITCH: 'CommonBuffId' = 102122 + OBJECT_TOXIC_FIRE_LEAF_UNRELENTING_ITCH_BASE_GAME: 'CommonBuffId' = 120042 + OBJECT_TOY_BALL_PET_PET_PLAYING: 'CommonBuffId' = 164418 + OBJECT_TOY_BOX_AWESOME_TOY: 'CommonBuffId' = 12530 + OBJECT_TOY_CLEAN_UP_HIDDEN_COOLDOWN: 'CommonBuffId' = 157507 + OBJECT_TOY_EMOTION_TALKING_DOLL_ANGRY: 'CommonBuffId' = 32949 + OBJECT_TOY_EMOTION_TALKING_DOLL_BORED: 'CommonBuffId' = 32950 + OBJECT_TOY_EMOTION_TALKING_DOLL_EMBARRASSED: 'CommonBuffId' = 32959 + OBJECT_TOY_EMOTION_TALKING_DOLL_HAPPY: 'CommonBuffId' = 32947 + OBJECT_TOY_EMOTION_TALKING_DOLL_PLAYFUL: 'CommonBuffId' = 32948 + OBJECT_TOY_EMOTION_TALKING_DOLL_SAD: 'CommonBuffId' = 32951 + OBJECT_TOY_EMOTION_TALKING_DOLL_STRESSED: 'CommonBuffId' = 32958 + OBJECT_TOY_SECRET_WORLD: 'CommonBuffId' = 147876 + OBJECT_TOY_TOYING_AROUND: 'CommonBuffId' = 24582 + OBJECT_TRASH_CHUTE_STRESSED: 'CommonBuffId' = 148387 + OBJECT_TREAD_MILL_ROCK_CLIMBING_WALL_DEFEATED_CLIMBING_HIGH_SCORE: 'CommonBuffId' = 165809 + OBJECT_TREAD_MILL_ROCK_CLIMBING_WALL_DEFEAT_CLIMB_LEVEL_1: 'CommonBuffId' = 165811 + OBJECT_TREAD_MILL_ROCK_CLIMBING_WALL_DEFEAT_CLIMB_LEVEL_2: 'CommonBuffId' = 165812 + OBJECT_TREAD_MILL_ROCK_CLIMBING_WALL_DEFEAT_CLIMB_LEVEL_3: 'CommonBuffId' = 165813 + OBJECT_TREAD_MILL_ROCK_CLIMBING_WALL_DEFEAT_CLIMB_LEVEL_4: 'CommonBuffId' = 165814 + OBJECT_TREAD_MILL_ROCK_CLIMBING_WALL_DEFEAT_CLIMB_LEVEL_5: 'CommonBuffId' = 165815 + OBJECT_TREAD_MILL_ROCK_CLIMBING_WALL_DEFEAT_CLIMB_LEVEL_CHAMPION: 'CommonBuffId' = 165816 + OBJECT_TREAD_MILL_ROCK_CLIMBING_WALL_HIDDEN_IS_CLIMBING: 'CommonBuffId' = 165282 + OBJECT_TREAD_MILL_ROCK_CLIMBING_WALL_SURVIVED_ROCK_WALL_MALFUNCTION: 'CommonBuffId' = 165817 + OBJECT_TV_CHILD_LEARNING_ADULTS: 'CommonBuffId' = 318272 + OBJECT_TV_CHILD_LEARNING_KIDS: 'CommonBuffId' = 338847 + OBJECT_TV_CTYAE_WATCHING_WITH_CT: 'CommonBuffId' = 229043 + OBJECT_TV_FIREPLACE_WINTER: 'CommonBuffId' = 179867 + OBJECT_TV_HOME_DECORATING_CHANNEL_DECORATOR_CREATIVE: 'CommonBuffId' = 257804 + OBJECT_TV_HOME_DECORATING_CHANNEL_DECORATOR_NOT_CREATIVE: 'CommonBuffId' = 257805 + OBJECT_TV_HOME_DECORATING_CHANNEL_NORMAL_CREATIVE: 'CommonBuffId' = 257807 + OBJECT_TV_HOME_DECORATING_CHANNEL_NORMAL_NOT_CREATIVE: 'CommonBuffId' = 257806 + OBJECT_TV_MINU_S06_COMEDY_CHANNEL: 'CommonBuffId' = 12536 + OBJECT_TV_MINU_S10_ROMANCE_CHANNEL_FLIRTY: 'CommonBuffId' = 10491 + OBJECT_TV_MINU_S16_KIDS_CHANNEL_KIDS: 'CommonBuffId' = 23734 + OBJECT_TV_MINU_S17_KIDS_CHANNEL_ADULTS: 'CommonBuffId' = 23736 + OBJECT_TV_PUBLIC_ACCESS: 'CommonBuffId' = 146008 + OBJECT_TV_SCARY_BRAVE: 'CommonBuffId' = 318280 + OBJECT_TV_SCARY_EXTRA_BRAVE: 'CommonBuffId' = 318281 + OBJECT_TV_SCARY_EXTRA_SCARED: 'CommonBuffId' = 318279 + OBJECT_TV_SCARY_RUN_AWAY: 'CommonBuffId' = 318282 + OBJECT_TV_SCARY_SCARED: 'CommonBuffId' = 318278 + OBJECT_TV_SCARY_TODDLER_NIGHTMARE: 'CommonBuffId' = 318283 + OBJECT_TV_SCARY_TODDLER_SAD: 'CommonBuffId' = 318365 + OBJECT_TV_SILENT_WESTERN_HORSE_LOVER: 'CommonBuffId' = 338475 + OBJECT_TV_SITCOM_PLAYFUL: 'CommonBuffId' = 321869 + OBJECT_TV_SITCOM_PLAYFUL_TOGETHER: 'CommonBuffId' = 321870 + OBJECT_TV_TEEN_EQUESTRIANS_HORSE_LOVER: 'CommonBuffId' = 338474 + OBJECT_TV_TEEN_EQUESTRIANS_KIDS: 'CommonBuffId' = 338473 + OBJECT_TV_TRAIT_LOVE_BUG: 'CommonBuffId' = 378229 + OBJECT_TV_TRAIT_SNOB: 'CommonBuffId' = 37111 + OBJECT_TV_TRAIT_SNOB_NEWS: 'CommonBuffId' = 98110 + OBJECT_TV_WEATHER_TV_CLIMATE_CHANGE: 'CommonBuffId' = 179839 + OBJECT_URN_STONE_MOURN_ENEMY: 'CommonBuffId' = 12540 + OBJECT_URN_STONE_MOURN_FRIEND: 'CommonBuffId' = 12541 + OBJECT_URN_STONE_MOURN_FRIEND_DOG: 'CommonBuffId' = 174950 + OBJECT_URN_STONE_MOURN_LOVED_ONE: 'CommonBuffId' = 103190 + OBJECT_URN_STONE_MOURN_NEUTRAL: 'CommonBuffId' = 12542 + OBJECT_URN_STONE_MOURN_NEUTRAL_PET: 'CommonBuffId' = 178053 + OBJECT_URN_STONE_RELEASE_SPIRIT_NEGATIVE: 'CommonBuffId' = 98917 + OBJECT_URN_STONE_RELEASE_SPIRIT_POSITIVE: 'CommonBuffId' = 98951 + OBJECT_VANITY_APPLIED_MAKE_UP: 'CommonBuffId' = 145345 + OBJECT_VANITY_APPLIED_MAKE_UP_BLUE: 'CommonBuffId' = 152383 + OBJECT_VANITY_APPLIED_MAKE_UP_GREEN: 'CommonBuffId' = 152384 + OBJECT_VANITY_APPLIED_MAKE_UP_PINK: 'CommonBuffId' = 152386 + OBJECT_VANITY_APPLIED_MAKE_UP_PURPLE: 'CommonBuffId' = 152385 + OBJECT_VANITY_MAKEUP_CLEAR_EYE_SHADOW: 'CommonBuffId' = 152603 + OBJECT_VANITY_MAKEUP_CLEAR_LIP_STICK: 'CommonBuffId' = 152604 + OBJECT_VANITY_MAKE_UP_APPLIED_BEIGE_EYES_DARK_RED_LIPS: 'CommonBuffId' = 151970 + OBJECT_VANITY_MAKE_UP_APPLIED_BEIGE_EYES_RED_LIPS: 'CommonBuffId' = 151971 + OBJECT_VANITY_MAKE_UP_APPLIED_BLACK_CAT_EYES: 'CommonBuffId' = 151981 + OBJECT_VANITY_MAKE_UP_APPLIED_BLACK_EYELINER_CORAL_LIPS: 'CommonBuffId' = 151987 + OBJECT_VANITY_MAKE_UP_APPLIED_BLACK_EYELINER_SATIN_PINK_LIPS: 'CommonBuffId' = 151984 + OBJECT_VANITY_MAKE_UP_APPLIED_BLACK_EYES: 'CommonBuffId' = 151983 + OBJECT_VANITY_MAKE_UP_APPLIED_BLACK_EYES_GLOSSY_ORANGE_LIPS: 'CommonBuffId' = 152010 + OBJECT_VANITY_MAKE_UP_APPLIED_BLACK_EYES_PINK_LIPS: 'CommonBuffId' = 152011 + OBJECT_VANITY_MAKE_UP_APPLIED_BLACK_EYES_SATIN_BLACK_LIPS: 'CommonBuffId' = 151982 + OBJECT_VANITY_MAKE_UP_APPLIED_BLUE_BLUE_EYES_PINK_LIPS: 'CommonBuffId' = 151994 + OBJECT_VANITY_MAKE_UP_APPLIED_BLUE_EYES_GLOSSY_BLUE_LIPS: 'CommonBuffId' = 151993 + OBJECT_VANITY_MAKE_UP_APPLIED_BLUE_EYES_GLOSSY_PINK_LIPS: 'CommonBuffId' = 151996 + OBJECT_VANITY_MAKE_UP_APPLIED_BLUE_EYES_GLOSSY_VIOLET_LIPS: 'CommonBuffId' = 151997 + OBJECT_VANITY_MAKE_UP_APPLIED_BLUE_EYES_PINK_LIPS: 'CommonBuffId' = 151992 + OBJECT_VANITY_MAKE_UP_APPLIED_BLUE_EYES_RED_LIPS: 'CommonBuffId' = 151995 + OBJECT_VANITY_MAKE_UP_APPLIED_BLUE_EYES_ROSE_LIPS: 'CommonBuffId' = 151999 + OBJECT_VANITY_MAKE_UP_APPLIED_BLUE_EYES_SATIN_BRONZE_LIPS: 'CommonBuffId' = 151998 + OBJECT_VANITY_MAKE_UP_APPLIED_BRONZE_EYES_GLOSSY_RED_LIPS: 'CommonBuffId' = 151973 + OBJECT_VANITY_MAKE_UP_APPLIED_BROWN_EYES: 'CommonBuffId' = 152003 + OBJECT_VANITY_MAKE_UP_APPLIED_BROWN_EYES_CORAL_LIPS: 'CommonBuffId' = 152006 + OBJECT_VANITY_MAKE_UP_APPLIED_BROWN_EYES_PINK_LIPS: 'CommonBuffId' = 152005 + OBJECT_VANITY_MAKE_UP_APPLIED_BROWN_EYES_ROSE_LIPS: 'CommonBuffId' = 152007 + OBJECT_VANITY_MAKE_UP_APPLIED_BROWN_EYES_SATIN_RED_LIPS: 'CommonBuffId' = 152008 + OBJECT_VANITY_MAKE_UP_APPLIED_GOLD_EYES_GLOSSY_RED_LIPS: 'CommonBuffId' = 152009 + OBJECT_VANITY_MAKE_UP_APPLIED_GOTH_BLACK_EYES_SATIN_BLACK_LIPS: 'CommonBuffId' = 151986 + OBJECT_VANITY_MAKE_UP_APPLIED_GOTH_BLACK_EYES_SATIN_RED_LIPS: 'CommonBuffId' = 151988 + OBJECT_VANITY_MAKE_UP_APPLIED_GRAY_BROWN_EYES_CORAL_LIPS: 'CommonBuffId' = 152004 + OBJECT_VANITY_MAKE_UP_APPLIED_GRAY_EYES_CORAL_LIPS: 'CommonBuffId' = 151974 + OBJECT_VANITY_MAKE_UP_APPLIED_GRAY_EYES_RED_LIPS: 'CommonBuffId' = 152012 + OBJECT_VANITY_MAKE_UP_APPLIED_GREEN_EYES_BRONZE_LIPS: 'CommonBuffId' = 152016 + OBJECT_VANITY_MAKE_UP_APPLIED_GREEN_EYES_GLOSSY_RED_LIPS: 'CommonBuffId' = 152014 + OBJECT_VANITY_MAKE_UP_APPLIED_GREEN_EYES_RED_LIPS: 'CommonBuffId' = 152015 + OBJECT_VANITY_MAKE_UP_APPLIED_GREEN_EYES_SATIN_CORAL_LIPS: 'CommonBuffId' = 152018 + OBJECT_VANITY_MAKE_UP_APPLIED_GREEN_EYES_SATIN_PINK_LIPS: 'CommonBuffId' = 152017 + OBJECT_VANITY_MAKE_UP_APPLIED_GREY_EYES_GLOSSY_RED_LIPS: 'CommonBuffId' = 151985 + OBJECT_VANITY_MAKE_UP_APPLIED_MAGENTA_EYES_RED_LIPS: 'CommonBuffId' = 152019 + OBJECT_VANITY_MAKE_UP_APPLIED_MAUVE_EYES_CORAL_LIPS: 'CommonBuffId' = 151975 + OBJECT_VANITY_MAKE_UP_APPLIED_MAUVE_EYES_GLOSSY_CORAL_LIPS: 'CommonBuffId' = 152020 + OBJECT_VANITY_MAKE_UP_APPLIED_PINK_EYES_GLOSSY_CORAL_LIPS: 'CommonBuffId' = 152022 + OBJECT_VANITY_MAKE_UP_APPLIED_PLUM_EYES_SATIN_RED_LIPS: 'CommonBuffId' = 152023 + OBJECT_VANITY_MAKE_UP_APPLIED_PURPLE_EYES_SATIN_VIOLET_LIPS: 'CommonBuffId' = 152021 + OBJECT_VANITY_MAKE_UP_APPLIED_RED_EYES: 'CommonBuffId' = 152024 + OBJECT_VANITY_MAKE_UP_APPLIED_SILVER_BLUE_ROSE_LIPS: 'CommonBuffId' = 151990 + OBJECT_VANITY_MAKE_UP_APPLIED_SILVER_BLUE_SATIN_BLUE_LIPS: 'CommonBuffId' = 151989 + OBJECT_VANITY_MAKE_UP_APPLIED_SILVER_BLUE_SATIN_RED_LIPS: 'CommonBuffId' = 151972 + OBJECT_VANITY_MAKE_UP_APPLIED_SILVER_BROWN_SATIN_BEIGE_LIPS: 'CommonBuffId' = 152000 + OBJECT_VANITY_MAKE_UP_APPLIED_SILVER_BROWN_SATIN_RED_LIPS: 'CommonBuffId' = 152002 + OBJECT_VANITY_MAKE_UP_APPLIED_SILVER_GREEN_SATIN_CORAL_LIPS: 'CommonBuffId' = 152013 + OBJECT_VANITY_MAKE_UP_APPLIED_SILVER_SATIN_BRONZE_LIPS: 'CommonBuffId' = 151980 + OBJECT_VANITY_MAKE_UP_APPLIED_SLIVER_PINK_PINK_LIPS: 'CommonBuffId' = 152001 + OBJECT_VANITY_MAKE_UP_APPLIED_THICK_BLACK_EYELINER: 'CommonBuffId' = 151976 + OBJECT_VANITY_MAKE_UP_APPLIED_TURQUOISE_EYES_CORAL_LIPS: 'CommonBuffId' = 151977 + OBJECT_VANITY_MAKE_UP_APPLIED_TURQUOISE_EYES_ROSE_LIPS: 'CommonBuffId' = 151978 + OBJECT_VANITY_MAKE_UP_APPLIED_TURQUOISE_EYES_SATIN_RED_LIPS: 'CommonBuffId' = 151991 + OBJECT_VANITY_MAKE_UP_APPLIED_VIOLET_EYES_RED_LIPS: 'CommonBuffId' = 151979 + OBJECT_VANITY_MAKE_UP_CLEAR_BLUSH: 'CommonBuffId' = 152600 + OBJECT_VANITY_MAKE_UP_CLEAR_EYELINER: 'CommonBuffId' = 152601 + OBJECT_VANITY_OOPS: 'CommonBuffId' = 145346 + OBJECT_VANITY_OOPS_BLUE: 'CommonBuffId' = 152377 + OBJECT_VANITY_OOPS_PINK: 'CommonBuffId' = 152378 + OBJECT_VANITY_OOPS_PURPLE: 'CommonBuffId' = 152379 + OBJECT_VANITY_OOPS_RED: 'CommonBuffId' = 152380 + OBJECT_VERTICAL_GARDEN_MEAT_WALL_SQUEAMISH: 'CommonBuffId' = 237753 + OBJECT_VERTICAL_GARDEN_MEAT_WALL_VEGETARIAN: 'CommonBuffId' = 237754 + OBJECT_VET_MEDICINE_STATION_CALMING_AGENT: 'CommonBuffId' = 171734 + OBJECT_VET_MEDICINE_STATION_RELAXATION_SERUM: 'CommonBuffId' = 171575 + OBJECT_VET_MEDICINE_STATION_REQUEST_CRAFTING_AGE_DOWN_TREAT: 'CommonBuffId' = 172311 + OBJECT_VET_MEDICINE_STATION_REQUEST_CRAFTING_AGE_UP_TREAT: 'CommonBuffId' = 172312 + OBJECT_VET_MEDICINE_STATION_REQUEST_CRAFTING_AMBROSIA_TREAT: 'CommonBuffId' = 172350 + OBJECT_VET_MEDICINE_STATION_REQUEST_CRAFTING_CALMING_AGENT: 'CommonBuffId' = 172304 + OBJECT_VET_MEDICINE_STATION_REQUEST_CRAFTING_RELAXATION_SERUM: 'CommonBuffId' = 172136 + OBJECT_VET_MEDICINE_STATION_REQUEST_CRAFTING_SICKNESS_TREAT_1: 'CommonBuffId' = 172306 + OBJECT_VET_MEDICINE_STATION_REQUEST_CRAFTING_SICKNESS_TREAT_2: 'CommonBuffId' = 172307 + OBJECT_VET_MEDICINE_STATION_REQUEST_CRAFTING_SICKNESS_TREAT_3: 'CommonBuffId' = 172308 + OBJECT_VET_MEDICINE_STATION_REQUEST_CRAFTING_SICKNESS_TREAT_4: 'CommonBuffId' = 172309 + OBJECT_VET_MEDICINE_STATION_REQUEST_CRAFTING_SICKNESS_TREAT_5: 'CommonBuffId' = 172310 + OBJECT_VET_MEDICINE_STATION_REQUEST_CRAFTING_SIMULATION_GEL: 'CommonBuffId' = 172303 + OBJECT_VET_MEDICINE_STATION_REQUEST_CRAFTING_WELLNESS_TREAT: 'CommonBuffId' = 172305 + OBJECT_VET_MEDICINE_STATION_SIMULATION_GEL: 'CommonBuffId' = 171749 + OBJECT_VIDEO_STATION_POST_UPDATE_COOLDOWN: 'CommonBuffId' = 192565 + OBJECT_VIDEO_STATION_POST_UPDATE_HYPE: 'CommonBuffId' = 192571 + OBJECT_VIDEO_STATION_STUDY_TRENDS: 'CommonBuffId' = 192549 + OBJECT_VIDEO_STATION_STUDY_TRENDS_COOLDOWN: 'CommonBuffId' = 199057 + OBJECT_VIOLIN_SCINTILLATING_STRINGS: 'CommonBuffId' = 36971 + OBJECT_VIOLIN_SOOTHING_STRINGS: 'CommonBuffId' = 34550 + OBJECT_WATER_SCOOTER_TRICKS: 'CommonBuffId' = 204840 + OBJECT_WILD_GRASS_CUTS: 'CommonBuffId' = 326663 + OBJECT_WILD_GRASS_HARVEST_BAD: 'CommonBuffId' = 326661 + OBJECT_WILD_GRASS_HARVEST_GOOD: 'CommonBuffId' = 326662 + OBJECT_WIND_CHIMES_SOUNDS_OF_THE_WINDS: 'CommonBuffId' = 141182 + OBJECT_WIND_CHIME_ANNOYING_CHIMES: 'CommonBuffId' = 143521 + OBJECT_WIND_CHIME_SOOTHING_CHIMES: 'CommonBuffId' = 143520 + OBJECT_WIND_CHIME_WOKEN_UP: 'CommonBuffId' = 190422 + OBJECT_WOOHOO_IN_PROGRESS_HIDDEN: 'CommonBuffId' = 156207 + OBJECT_XRAY_MACHINE_LASER_PRECISION: 'CommonBuffId' = 105798 + OBJECT_YOGA_MAT_CENTERED_AND_FOCUSED: 'CommonBuffId' = 117439 + OBJECT_YOGA_MAT_CENTERED_AND_FOCUSED_INCENSE: 'CommonBuffId' = 118925 + OBJECT_YOGA_MAT_CENTERED_AND_FOCUSED_YOGA_CLASS: 'CommonBuffId' = 118665 + OBJECT_YOGA_MAT_CHILD_FRIENDLY_CHILD: 'CommonBuffId' = 271117 + OBJECT_YOGA_MAT_CHILD_FRIENDLY_CHILD_INCENSE: 'CommonBuffId' = 271118 + OBJECT_YOGA_MAT_CHILD_FRIENDLY_CHILD_YOGA_CLASS: 'CommonBuffId' = 271119 + OBJECT_YOGA_MAT_CHILD_FRIENDLY_TYAE: 'CommonBuffId' = 271122 + OBJECT_YOGA_MAT_CHILD_FRIENDLY_TYAE_INCENSE: 'CommonBuffId' = 271123 + OBJECT_YOGA_MAT_CHILD_FRIENDLY_TYAE_YOGA_CLASS: 'CommonBuffId' = 271124 + OBJECT_YOGA_MAT_CHILD_POSE_BOAT: 'CommonBuffId' = 271327 + OBJECT_YOGA_MAT_CHILD_POSE_DOWNWARD_DOG: 'CommonBuffId' = 271189 + OBJECT_YOGA_MAT_CHILD_POSE_HALF_MOON: 'CommonBuffId' = 271200 + OBJECT_YOGA_MAT_CHILD_POSE_TREE: 'CommonBuffId' = 271190 + OBJECT_YOGA_MAT_IMPROVED_POSING: 'CommonBuffId' = 117441 + OBJECT_YOGA_MAT_IMPROVED_POSING_INCENSE: 'CommonBuffId' = 118929 + OBJECT_YOGA_MAT_SENSES_BOOSTED: 'CommonBuffId' = 117437 + OBJECT_YOGA_MAT_SENSES_BOOSTED_INCENSE: 'CommonBuffId' = 118924 + OBJECT_YOGA_MAT_SENSES_BOOSTED_YOGA_CLASS: 'CommonBuffId' = 118667 + OBJECT_YOGA_MAT_YOGA_BLISS: 'CommonBuffId' = 117440 + OBJECT_YOGA_MAT_YOGA_BLISS_INCENSE: 'CommonBuffId' = 118928 + OBJECT_YOGA_MAT_YOGIC_INSPIRATION: 'CommonBuffId' = 117438 + OBJECT_YOGA_MAT_YOGIC_INSPIRATION_INCENSE: 'CommonBuffId' = 118923 + OBJECT_YOGA_MAT_YOGIC_INSPIRATION_YOGA_CLASS: 'CommonBuffId' = 118669 + OCEAN_LADDER_CANNONBALL: 'CommonBuffId' = 211982 + OCEAN_LADDER_CLIMB: 'CommonBuffId' = 213431 + OCEAN_LADDER_JUMP: 'CommonBuffId' = 211984 + OCEAN_LADDER_SWAN_DIVE: 'CommonBuffId' = 211983 + OCEAN_SWIMMING_BASE_GAME_REACTIONS_LOST_YOUR_SUIT: 'CommonBuffId' = 211409 + OCEAN_SWIMMING_BASE_GAME_REACTIONS_SPLASHED: 'CommonBuffId' = 211352 + OCEAN_SWIMMING_BASE_GAME_REACTIONS_SUDDEN_CHILL: 'CommonBuffId' = 206442 + OCEAN_SWIMMING_BASE_GAME_REACTIONS_SUDDEN_CHILL_BLUE_TONE: 'CommonBuffId' = 211904 + OCEAN_SWIMMING_BASE_GAME_REACTIONS_SWIMMING_CRAMP: 'CommonBuffId' = 206439 + OCEAN_SWIMMING_BASE_GAME_REACTIONS_SWIMMING_CRAMP_JUST_ATE: 'CommonBuffId' = 212335 + OCEAN_SWIMMING_BASE_GAME_REACTIONS_THALASSOPHOBIA: 'CommonBuffId' = 206441 + OCEAN_SWIMMING_BASE_GAME_REACTION_SPLASHY_FUN: 'CommonBuffId' = 214463 + OCEAN_SWIMMING_BASE_GAME_REACTION_THALASSOPHOBIA: 'CommonBuffId' = 212330 + OCEAN_SWIMMING_BASE_GAME_REACTION_TRIGGER_COOLDOWN_NEGATIVE_BUFFS: 'CommonBuffId' = 212333 + OCEAN_SWIMMING_BASE_GAME_REACTION_TRIGGER_LOST_YOUR_SUIT: 'CommonBuffId' = 211346 + OCEAN_SWIMMING_BASE_GAME_REACTION_TRIGGER_SPLASHED: 'CommonBuffId' = 211350 + OCEAN_SWIMMING_BASE_GAME_REACTION_TRIGGER_SUDDEN_CHILL: 'CommonBuffId' = 211348 + OCEAN_SWIMMING_BASE_GAME_REACTION_TRIGGER_SUDDEN_CHILL_WADE: 'CommonBuffId' = 212692 + OCEAN_SWIMMING_BASE_GAME_REACTION_TRIGGER_SWIMMING_CRAMP: 'CommonBuffId' = 211345 + OCEAN_SWIMMING_BASE_GAME_REACTION_TRIGGER_THALASSOPHOBIA: 'CommonBuffId' = 211347 + OCEAN_SWIMMING_BASE_GAME_REACTION_TRIGGER_THALASSOPHOBIA_WADE: 'CommonBuffId' = 212344 + OCEAN_SWIMMING_BASE_GAME_REACTION_WAVE_TAG: 'CommonBuffId' = 212460 + OCEAN_SWIMMING_BASE_GAME_WAVE_TAG_AUTONOMY: 'CommonBuffId' = 215262 + OCEAN_SWIMMING_REACTIONS_CAUGHT_IN_CURRENT: 'CommonBuffId' = 205894 + OCEAN_SWIMMING_REACTIONS_PULLED_UNDER: 'CommonBuffId' = 205875 + OCEAN_SWIMMING_REACTIONS_SHARK_SIGHTING: 'CommonBuffId' = 205874 + OCEAN_SWIMMING_REACTIONS_SHARK_SIGHTING_POSITIVE: 'CommonBuffId' = 212310 + OCEAN_SWIMMING_REACTIONS_SLIMED: 'CommonBuffId' = 205900 + OCEAN_SWIMMING_REACTIONS_STUNG_BY_SOMETHING: 'CommonBuffId' = 205842 + OCEAN_SWIMMING_REACTIONS_STUNNING_VIEW: 'CommonBuffId' = 205898 + OCEAN_SWIMMING_REACTIONS_SWALLOWED_WATER: 'CommonBuffId' = 211393 + OCEAN_SWIMMING_REACTIONS_TICKLED_BY_OCEAN: 'CommonBuffId' = 205899 + OCEAN_SWIMMING_REACTION_TRIGGER_SHARK_SIGHTING: 'CommonBuffId' = 211245 + OCEAN_SWIMMING_REACTION_TRIGGER_SLIMED: 'CommonBuffId' = 211246 + OCEAN_SWIMMING_REACTION_TRIGGER_SLIMED_TRASH: 'CommonBuffId' = 215083 + OCEAN_SWIMMING_REACTION_TRIGGER_STUNG_BY_SOMETHING: 'CommonBuffId' = 211219 + OCEAN_SWIMMING_REACTION_TRIGGER_STUNNING_VIEW: 'CommonBuffId' = 211248 + OCEAN_SWIMMING_REACTION_TRIGGER_SWALLOWED_WATER: 'CommonBuffId' = 211252 + OCEAN_SWIMMING_REACTION_TRIGGER_TICKLED_BY_OCEAN: 'CommonBuffId' = 211249 + OCEAN_SWIMMING_SPLASHED_BROADCASTER: 'CommonBuffId' = 212503 + OFFER_GRATITUDE_MINDED_MY_MANNERS: 'CommonBuffId' = 160892 + OFFER_GRATITUDE_SUCH_GOOD_MANNERS: 'CommonBuffId' = 160890 + OFF_LOT_AUTONOMY_MOD_ALL: 'CommonBuffId' = 40411 + OFF_LOT_AUTONOMY_MOD_DEFAULT: 'CommonBuffId' = 130248 + OFF_LOT_AUTONOMY_MOD_OFF_LOT_ONLY: 'CommonBuffId' = 38293 + OFF_LOT_AUTONOMY_MOD_OFF_LOT_ONLY_CAMPFIRE: 'CommonBuffId' = 112081 + OFF_LOT_AUTONOMY_MOD_OFF_LOT_ONLY_GO_DANCING: 'CommonBuffId' = 126871 + OFF_LOT_AUTONOMY_MOD_ON_LOT_ONLY: 'CommonBuffId' = 38292 + OFF_LOT_AUTONOMY_MOD_ON_LOT_ONLY_ANCHORED_SPA: 'CommonBuffId' = 122390 + OFF_LOT_AUTONOMY_MOD_ON_LOT_ONLY_DJ_NPC: 'CommonBuffId' = 127027 + OFF_LOT_AUTONOMY_MOD_ON_LOT_ONLY_GO_DANCING: 'CommonBuffId' = 126872 + OFF_LOT_AUTONOMY_MOD_ON_LOT_ONLY_GRILL_MASTER: 'CommonBuffId' = 105939 + OFF_LOT_AUTONOMY_MOD_RESTRICTED: 'CommonBuffId' = 135730 + OFF_LOT_AUTONOMY_MOD_SHARED_SPACE_ONLY: 'CommonBuffId' = 349229 + OFF_THE_GRID_BRACKISH_WATER: 'CommonBuffId' = 212112 + ONIBI_STRONG_BUFFS_COLLECT_BLUE: 'CommonBuffId' = 251350 + ONIBI_STRONG_BUFFS_COLLECT_GREEN: 'CommonBuffId' = 251351 + ONIBI_STRONG_BUFFS_COLLECT_RED_ORANGE: 'CommonBuffId' = 251352 + ONIBI_STRONG_BUFFS_COLLECT_WHITE: 'CommonBuffId' = 251353 + ONIBI_STRONG_BUFFS_COLLECT_YELLOW: 'CommonBuffId' = 251354 + ONIBI_STRONG_BUFFS_WISH_BLUE: 'CommonBuffId' = 251338 + ONIBI_STRONG_BUFFS_WISH_GREEN: 'CommonBuffId' = 251339 + ONIBI_STRONG_BUFFS_WISH_RED_ORANGE: 'CommonBuffId' = 251340 + ONIBI_STRONG_BUFFS_WISH_WHITE: 'CommonBuffId' = 251341 + ONIBI_STRONG_BUFFS_WISH_YELLOW: 'CommonBuffId' = 251342 + ONIBI_WEAK_BUFFS_COLLECT_BLUE: 'CommonBuffId' = 251333 + ONIBI_WEAK_BUFFS_COLLECT_GREEN: 'CommonBuffId' = 251337 + ONIBI_WEAK_BUFFS_COLLECT_RED_ORANGE: 'CommonBuffId' = 251335 + ONIBI_WEAK_BUFFS_COLLECT_WHITE: 'CommonBuffId' = 251334 + ONIBI_WEAK_BUFFS_COLLECT_YELLOW: 'CommonBuffId' = 251336 + ONIBI_WEAK_BUFFS_WISH_BLUE: 'CommonBuffId' = 251343 + ONIBI_WEAK_BUFFS_WISH_GREEN: 'CommonBuffId' = 251344 + ONIBI_WEAK_BUFFS_WISH_RED_ORANGE: 'CommonBuffId' = 251345 + ONIBI_WEAK_BUFFS_WISH_WHITE: 'CommonBuffId' = 251346 + ONIBI_WEAK_BUFFS_WISH_YELLOW: 'CommonBuffId' = 251347 + ON_FOREIGN_LOT: 'CommonBuffId' = 12554 + OPENABLE_WINDOW_ACCEPTED_EVENT_COLLEGE_PARTY: 'CommonBuffId' = 282992 + OPENABLE_WINDOW_ACCEPTED_EVENT_HANGOUT: 'CommonBuffId' = 283416 + OPENABLE_WINDOW_ACCEPTED_EVENT_LOITERING: 'CommonBuffId' = 283415 + OPENABLE_WINDOW_ACCEPTED_EVENT_POP_CONCERT: 'CommonBuffId' = 283414 + OPENABLE_WINDOW_ACCEPTED_EVENT_R_MOVIE: 'CommonBuffId' = 283413 + OPENABLE_WINDOW_ACCEPTED_EVENT_SCHOOL_GAME: 'CommonBuffId' = 283412 + OPENABLE_WINDOW_ACCEPTED_EVENT_SLEEPOVER: 'CommonBuffId' = 283411 + OPENABLE_WINDOW_CAUGHT: 'CommonBuffId' = 283442 + OPENABLE_WINDOW_CLEARED_TO_GO: 'CommonBuffId' = 283017 + OPENABLE_WINDOW_CLEARED_TO_GO_AT_EVENT_HIDDEN: 'CommonBuffId' = 290386 + OPENABLE_WINDOW_COLLEGE_PARTY_NO_PARTY_COOLDOWN: 'CommonBuffId' = 373590 + OPENABLE_WINDOW_COLLEGE_PARTY_TRIGGER_COOLDOWN: 'CommonBuffId' = 373479 + OPENABLE_WINDOW_EVENT_OUTCOME_COLLEGE_PARTY_FAIL: 'CommonBuffId' = 283053 + OPENABLE_WINDOW_EVENT_OUTCOME_COLLEGE_PARTY_SUCCESS: 'CommonBuffId' = 283052 + OPENABLE_WINDOW_EVENT_OUTCOME_HANG_OUT_FAIL: 'CommonBuffId' = 283208 + OPENABLE_WINDOW_EVENT_OUTCOME_LOITERING_FAIL: 'CommonBuffId' = 283207 + OPENABLE_WINDOW_EVENT_OUTCOME_POP_CONCERT_FAIL: 'CommonBuffId' = 283204 + OPENABLE_WINDOW_EVENT_OUTCOME_POP_CONCERT_SUCCESS: 'CommonBuffId' = 283205 + OPENABLE_WINDOW_EVENT_OUTCOME_R_MOVIE_FAIL: 'CommonBuffId' = 283202 + OPENABLE_WINDOW_EVENT_OUTCOME_R_MOVIE_SUCCESS: 'CommonBuffId' = 283203 + OPENABLE_WINDOW_EVENT_OUTCOME_SCHOOL_GAME_FAIL: 'CommonBuffId' = 283210 + OPENABLE_WINDOW_EVENT_OUTCOME_SCHOOL_GAME_SUCCESS: 'CommonBuffId' = 283211 + OPENABLE_WINDOW_EVENT_OUTCOME_SLEEPOVER_FAIL: 'CommonBuffId' = 283206 + OPENABLE_WINDOW_EVENT_OUTCOME_WITH_FRIENDS_SUCCESS: 'CommonBuffId' = 283209 + OPENABLE_WINDOW_ROUTING_TO_EVENT_NOT_SNEAKING: 'CommonBuffId' = 283016 + OPENABLE_WINDOW_ROUTING_TO_EVENT_SNEAKING: 'CommonBuffId' = 283015 + OPENABLE_WINDOW_SNEAKING_BACK_IN_HIDDEN: 'CommonBuffId' = 290380 + OPENABLE_WINDOW_SNEAK_SUCCESSFUL: 'CommonBuffId' = 283441 + OPENABLE_WINDOW_TEMPORARY_WINDOW_ACCESS: 'CommonBuffId' = 283859 + OPEN_STREET_COTTAGE_WORLD_PICNICKER_CREATE_FOOD_COOLDOWN: 'CommonBuffId' = 265785 + OPEN_STREET_COTTAGE_WORLD_WANDERER_ATTRACTED_BEHAVIOR_WOODS: 'CommonBuffId' = 264536 + OPEN_STREET_COTTAGE_WORLD_WANDERER_FISH: 'CommonBuffId' = 263666 + OPEN_STREET_COTTAGE_WORLD_WANDERER_GARDEN: 'CommonBuffId' = 263667 + OPEN_STREET_COTTAGE_WORLD_WANDERER_SOCIALIZE: 'CommonBuffId' = 263764 + OPEN_STREET_COTTAGE_WORLD_WANDERER_SWIM: 'CommonBuffId' = 263663 + ORGANIZATIONS_ACTIVATE_CHEATS: 'CommonBuffId' = 225545 + ORRERY_FOCUSED: 'CommonBuffId' = 109869 + OUTSIDE_CHECK: 'CommonBuffId' = 76778 + OUTSIDE_CHECK_CURRENTLY_INSIDE: 'CommonBuffId' = 76781 + OUTSIDE_CHECK_CURRENTLY_OUTSIDE: 'CommonBuffId' = 76780 + OWNABLE_BUSINESS_CUSTOMER_ENVIRONMENT_ALREADY_APPLIED_LOOT: 'CommonBuffId' = 143387 + OWNABLE_BUSINESS_CUSTOMER_ENVIRONMENT_BAD_INSTRUMENT_PLAYING: 'CommonBuffId' = 143309 + OWNABLE_BUSINESS_CUSTOMER_ENVIRONMENT_BAD_SURROUNDINGS: 'CommonBuffId' = 143313 + OWNABLE_BUSINESS_CUSTOMER_ENVIRONMENT_BEAUTIFULLY_DECORATED: 'CommonBuffId' = 143312 + OWNABLE_BUSINESS_CUSTOMER_ENVIRONMENT_DECORATED: 'CommonBuffId' = 143311 + OWNABLE_BUSINESS_CUSTOMER_ENVIRONMENT_GOOD_MUSIC: 'CommonBuffId' = 143307 + OWNABLE_BUSINESS_CUSTOMER_ENVIRONMENT_NEAR_HEAT_SOURCE: 'CommonBuffId' = 143308 + OWNABLE_BUSINESS_CUSTOMER_ENVIRONMENT_NICELY_DECORATED: 'CommonBuffId' = 143310 + OWNABLE_BUSINESS_CUSTOMER_ENVIRONMENT_STEREO_MUSIC: 'CommonBuffId' = 143316 + OWNABLE_BUSINESS_CUSTOMER_ENVIRONMENT_UNPLEASANT_SURROUNDINGS: 'CommonBuffId' = 143314 + OWNABLE_BUSINESS_CUSTOMER_ENVIRONMENT_WRETCHED_SURROUNDINGS: 'CommonBuffId' = 143315 + OWNABLE_BUSINESS_EMPLOYEE_CHECK_UP_ON: 'CommonBuffId' = 137599 + OWNABLE_BUSINESS_EMPLOYEE_CRITICIZED: 'CommonBuffId' = 136969 + OWNABLE_BUSINESS_EMPLOYEE_EXHAUSTED: 'CommonBuffId' = 137104 + OWNABLE_BUSINESS_EMPLOYEE_EXHAUSTED_QUIT: 'CommonBuffId' = 142993 + OWNABLE_BUSINESS_EMPLOYEE_FIRED: 'CommonBuffId' = 136963 + OWNABLE_BUSINESS_EMPLOYEE_INSPIRED: 'CommonBuffId' = 136968 + OWNABLE_BUSINESS_EMPLOYEE_PRAISED: 'CommonBuffId' = 136967 + OWNABLE_BUSINESS_EMPLOYEE_QUIT_COOLDOWN: 'CommonBuffId' = 174471 + OWNABLE_BUSINESS_EMPLOYEE_SATISFACTION_MODIFIERS_PAY_0_PAID_ADEQUATELY: 'CommonBuffId' = 137167 + OWNABLE_BUSINESS_EMPLOYEE_SATISFACTION_MODIFIERS_PAY_MINU_S1_UNDERPAID: 'CommonBuffId' = 137158 + OWNABLE_BUSINESS_EMPLOYEE_SATISFACTION_MODIFIERS_PAY_MINU_S2_VERY_UNDERPAID: 'CommonBuffId' = 137159 + OWNABLE_BUSINESS_EMPLOYEE_SATISFACTION_MODIFIERS_PAY_MINU_S3_SEVERELY_UNDERPAID: 'CommonBuffId' = 137160 + OWNABLE_BUSINESS_EMPLOYEE_SATISFACTION_MODIFIERS_PAY_MINU_S4_GROSSLY_UNDERPAID: 'CommonBuffId' = 137161 + OWNABLE_BUSINESS_EMPLOYEE_SATISFACTION_MODIFIERS_PAY_PLU_S1_OVERPAID: 'CommonBuffId' = 137163 + OWNABLE_BUSINESS_EMPLOYEE_SATISFACTION_MODIFIERS_PAY_PLU_S2_VERY_OVERPAID: 'CommonBuffId' = 137164 + OWNABLE_BUSINESS_EMPLOYEE_SATISFACTION_MODIFIERS_PAY_PLU_S3_SEVERELY_OVERPAID: 'CommonBuffId' = 137165 + OWNABLE_BUSINESS_EMPLOYEE_SATISFACTION_MODIFIERS_PAY_PLU_S4_GROSSLY_OVERPAID: 'CommonBuffId' = 137166 + OWNABLE_BUSINESS_EMPLOYEE_SATISFACTION_STATES_NEUTRAL: 'CommonBuffId' = 137171 + OWNABLE_BUSINESS_EMPLOYEE_SATISFACTION_STATES_SATISFIED: 'CommonBuffId' = 137172 + OWNABLE_BUSINESS_EMPLOYEE_SATISFACTION_STATES_UNSATISFIED: 'CommonBuffId' = 137173 + OWNABLE_BUSINESS_EMPLOYEE_SATISFACTION_STATES_VERY_SATISFIED: 'CommonBuffId' = 137174 + OWNABLE_BUSINESS_EMPLOYEE_SATISFACTION_STATES_VERY_UNSATISFIED: 'CommonBuffId' = 137175 + OWNABLE_BUSINESS_EMPLOYEE_TRAINING_BRIEF: 'CommonBuffId' = 138007 + OWNABLE_BUSINESS_EMPLOYEE_TRAINING_EXTENSIVE: 'CommonBuffId' = 138008 + OWNABLE_BUSINESS_EMPLOYEE_TRAINING_STANDARD: 'CommonBuffId' = 138009 + OWNABLE_BUSINESS_EMPLOYEE_TRAINING_SUPPRESS_BACKUP: 'CommonBuffId' = 143662 + OWNABLE_BUSINESS_RESTAURANT_ALLOW_EATING: 'CommonBuffId' = 144204 + OWNABLE_RESTAURANT_DRINK_QUALITY_AMAZING: 'CommonBuffId' = 143109 + OWNABLE_RESTAURANT_DRINK_QUALITY_GOOD: 'CommonBuffId' = 143110 + OWNABLE_RESTAURANT_DRINK_QUALITY_GREAT: 'CommonBuffId' = 143111 + OWNABLE_RESTAURANT_DRINK_QUALITY_POOR: 'CommonBuffId' = 143112 + OWNABLE_RESTAURANT_DRINK_QUALITY_TERRIBLE: 'CommonBuffId' = 143113 + OWNABLE_RESTAURANT_DRINK_VALUE_AMAZING: 'CommonBuffId' = 143115 + OWNABLE_RESTAURANT_DRINK_VALUE_GOOD: 'CommonBuffId' = 143116 + OWNABLE_RESTAURANT_DRINK_VALUE_GREAT: 'CommonBuffId' = 143117 + OWNABLE_RESTAURANT_DRINK_VALUE_POOR: 'CommonBuffId' = 143118 + OWNABLE_RESTAURANT_DRINK_VALUE_TERRIBLE: 'CommonBuffId' = 143119 + OWNABLE_RESTAURANT_EMPLOYEE_CHEF_COOK_STYLE_CAREFUL: 'CommonBuffId' = 137888 + OWNABLE_RESTAURANT_EMPLOYEE_CHEF_COOK_STYLE_NORMAL: 'CommonBuffId' = 137887 + OWNABLE_RESTAURANT_EMPLOYEE_CHEF_COOK_STYLE_QUICK: 'CommonBuffId' = 137889 + OWNABLE_RESTAURANT_EMPLOYEE_SKILL_GAIN_HIGH_BARTENDING: 'CommonBuffId' = 143428 + OWNABLE_RESTAURANT_EMPLOYEE_SKILL_GAIN_HIGH_CHARISMA: 'CommonBuffId' = 143432 + OWNABLE_RESTAURANT_EMPLOYEE_SKILL_GAIN_HIGH_COMEDY: 'CommonBuffId' = 143433 + OWNABLE_RESTAURANT_EMPLOYEE_SKILL_GAIN_HIGH_FITNESS: 'CommonBuffId' = 143431 + OWNABLE_RESTAURANT_EMPLOYEE_SKILL_GAIN_HIGH_GOURMET: 'CommonBuffId' = 143429 + OWNABLE_RESTAURANT_EMPLOYEE_SKILL_GAIN_LOW_BARTENDING: 'CommonBuffId' = 143441 + OWNABLE_RESTAURANT_EMPLOYEE_SKILL_GAIN_LOW_CHARISMA: 'CommonBuffId' = 143437 + OWNABLE_RESTAURANT_EMPLOYEE_SKILL_GAIN_LOW_COMEDY: 'CommonBuffId' = 143438 + OWNABLE_RESTAURANT_EMPLOYEE_SKILL_GAIN_LOW_FITNESS: 'CommonBuffId' = 143439 + OWNABLE_RESTAURANT_EMPLOYEE_SKILL_GAIN_LOW_GOURMET: 'CommonBuffId' = 143440 + OWNABLE_RESTAURANT_EMPLOYEE_WAITER_SPILLED_FOOD: 'CommonBuffId' = 136909 + OWNABLE_RESTAURANT_FOOD_QUALITY_AMAZING: 'CommonBuffId' = 141912 + OWNABLE_RESTAURANT_FOOD_QUALITY_GOOD: 'CommonBuffId' = 141913 + OWNABLE_RESTAURANT_FOOD_QUALITY_GREAT: 'CommonBuffId' = 141914 + OWNABLE_RESTAURANT_FOOD_QUALITY_POOR: 'CommonBuffId' = 141915 + OWNABLE_RESTAURANT_FOOD_QUALITY_TERRIBLE: 'CommonBuffId' = 141916 + OWNABLE_RESTAURANT_FOOD_VALUE_AMAZING: 'CommonBuffId' = 136744 + OWNABLE_RESTAURANT_FOOD_VALUE_GOOD: 'CommonBuffId' = 136742 + OWNABLE_RESTAURANT_FOOD_VALUE_GREAT: 'CommonBuffId' = 136743 + OWNABLE_RESTAURANT_FOOD_VALUE_POOR: 'CommonBuffId' = 136741 + OWNABLE_RESTAURANT_FOOD_VALUE_TERRIBLE: 'CommonBuffId' = 136740 + OWNABLE_RESTAURANT_HOSPITALITY_DELAY_PLACE_ORDER: 'CommonBuffId' = 143842 + OWNABLE_RESTAURANT_HOSPITALITY_DISH_RECOMMENDED: 'CommonBuffId' = 136769 + OWNABLE_RESTAURANT_HOSPITALITY_DISH_RECOMMENDED_RANDOM_CHANCE: 'CommonBuffId' = 142075 + OWNABLE_RESTAURANT_HOSPITALITY_FOOD_COMPED: 'CommonBuffId' = 136767 + OWNABLE_RESTAURANT_HOSPITALITY_FREE_DESSERT: 'CommonBuffId' = 136770 + OWNABLE_RESTAURANT_HOSPITALITY_FREE_DRINKS: 'CommonBuffId' = 136771 + OWNABLE_RESTAURANT_HOSPITALITY_GROUP_WELCOMED: 'CommonBuffId' = 143486 + OWNABLE_RESTAURANT_HOSPITALITY_HOST_GREETING_DELIGHTFUL: 'CommonBuffId' = 136884 + OWNABLE_RESTAURANT_HOSPITALITY_HOST_GREETING_PLEASANT: 'CommonBuffId' = 136883 + OWNABLE_RESTAURANT_HOSPITALITY_HOST_GREETING_RUDE: 'CommonBuffId' = 136882 + OWNABLE_RESTAURANT_HOSPITALITY_ORDER_PRIORITIZED: 'CommonBuffId' = 143137 + OWNABLE_RESTAURANT_HOSPITALITY_TABLE_CHECKED_ON: 'CommonBuffId' = 136768 + OWNABLE_RESTAURANT_HOSPITALITY_WAITER_SERVICE_BAD: 'CommonBuffId' = 136887 + OWNABLE_RESTAURANT_HOSPITALITY_WAITER_SERVICE_GOOD: 'CommonBuffId' = 136889 + OWNABLE_RESTAURANT_HOSPITALITY_WAITER_SERVICE_GREAT: 'CommonBuffId' = 136888 + OWNABLE_RESTAURANT_HOSPITALITY_WANTS_DISH_RECOMMENDED: 'CommonBuffId' = 142077 + OWNABLE_RESTAURANT_PERK_LONGER_WAIT_TIME: 'CommonBuffId' = 142019 + OWNABLE_RESTAURANT_WAIT_TIME_BAD: 'CommonBuffId' = 136759 + OWNABLE_RESTAURANT_WAIT_TIME_DISGRUNTLED: 'CommonBuffId' = 136758 + OWNABLE_RESTAURANT_WAIT_TIME_GOOD: 'CommonBuffId' = 136757 + OWNABLE_RESTAURANT_WAIT_TIME_START: 'CommonBuffId' = 141602 + OWNABLE_RESTAURANT_WAIT_TIME_STOP: 'CommonBuffId' = 141910 + OWNABLE_VET_CLINIC_BEDSIDE_MANNER_DISMISS_PATIENT: 'CommonBuffId' = 178333 + OWNABLE_VET_CLINIC_BEDSIDE_MANNER_FRIENDLY_GREETING: 'CommonBuffId' = 168405 + OWNABLE_VET_CLINIC_BEDSIDE_MANNER_FRIENDLY_OWNER_SOCIAL: 'CommonBuffId' = 168408 + OWNABLE_VET_CLINIC_BEDSIDE_MANNER_FRIENDLY_PET_SOCIAL: 'CommonBuffId' = 168407 + OWNABLE_VET_CLINIC_BEDSIDE_MANNER_MEAN_GREETING: 'CommonBuffId' = 168406 + OWNABLE_VET_CLINIC_BEDSIDE_MANNER_MEAN_OWNER_SOCIAL: 'CommonBuffId' = 168410 + OWNABLE_VET_CLINIC_BEDSIDE_MANNER_MEAN_PET_SOCIAL: 'CommonBuffId' = 168409 + OWNABLE_VET_CLINIC_BEDSIDE_MANNER_NEUTRAL_GREETING: 'CommonBuffId' = 179802 + OWNABLE_VET_CLINIC_EMPLOYEE_TRAINING_BRIEF: 'CommonBuffId' = 168005 + OWNABLE_VET_CLINIC_EMPLOYEE_TRAINING_EXTENSIVE: 'CommonBuffId' = 168006 + OWNABLE_VET_CLINIC_EMPLOYEE_TRAINING_STANDARD: 'CommonBuffId' = 168007 + OWNABLE_VET_CLINIC_EMPLOYEE_TRAINING_SUPPRESS_BACKUP: 'CommonBuffId' = 168008 + OWNABLE_VET_CLINIC_PERK_LONGER_WAIT_TIME: 'CommonBuffId' = 167883 + OWNABLE_VET_CLINIC_PET_STRESS_01_AMAZING: 'CommonBuffId' = 178678 + OWNABLE_VET_CLINIC_PET_STRESS_02_GREAT: 'CommonBuffId' = 178679 + OWNABLE_VET_CLINIC_PET_STRESS_03_GOOD: 'CommonBuffId' = 178683 + OWNABLE_VET_CLINIC_PET_STRESS_04_BAD: 'CommonBuffId' = 168218 + OWNABLE_VET_CLINIC_PET_STRESS_05_TERRIBLE: 'CommonBuffId' = 168217 + OWNABLE_VET_CLINIC_QUALITY_OF_SERVICE_CONE_OF_SHAME: 'CommonBuffId' = 168804 + OWNABLE_VET_CLINIC_QUALITY_OF_SERVICE_CORRECT_TREATMENT_0_WORST: 'CommonBuffId' = 178633 + OWNABLE_VET_CLINIC_QUALITY_OF_SERVICE_CORRECT_TREATMENT_1_2ND_WORST: 'CommonBuffId' = 178634 + OWNABLE_VET_CLINIC_QUALITY_OF_SERVICE_CORRECT_TREATMENT_2_3RD_WORST: 'CommonBuffId' = 178635 + OWNABLE_VET_CLINIC_QUALITY_OF_SERVICE_CORRECT_TREATMENT_3_4TH_BEST: 'CommonBuffId' = 178636 + OWNABLE_VET_CLINIC_QUALITY_OF_SERVICE_CORRECT_TREATMENT_4_3RD_BEST: 'CommonBuffId' = 178637 + OWNABLE_VET_CLINIC_QUALITY_OF_SERVICE_CORRECT_TREATMENT_5_2ND_BEST: 'CommonBuffId' = 178638 + OWNABLE_VET_CLINIC_QUALITY_OF_SERVICE_CORRECT_TREATMENT_6_BEST: 'CommonBuffId' = 178639 + OWNABLE_VET_CLINIC_QUALITY_OF_SERVICE_GREAT_SERVICE: 'CommonBuffId' = 168805 + OWNABLE_VET_CLINIC_QUALITY_OF_SERVICE_INCORRECT_TREATMENT: 'CommonBuffId' = 168552 + OWNABLE_VET_CLINIC_RATING_TIMERS_PET_STRESS_AMAZING: 'CommonBuffId' = 178769 + OWNABLE_VET_CLINIC_RATING_TIMERS_PET_STRESS_GOOD: 'CommonBuffId' = 178771 + OWNABLE_VET_CLINIC_RATING_TIMERS_PET_STRESS_GREAT: 'CommonBuffId' = 178770 + OWNABLE_VET_CLINIC_RATING_TIMERS_WAIT_TIME_GOOD: 'CommonBuffId' = 178764 + OWNABLE_VET_CLINIC_STATES_CLEAN: 'CommonBuffId' = 171547 + OWNABLE_VET_CLINIC_STATES_DONT_CLEAN: 'CommonBuffId' = 171548 + OWNABLE_VET_CLINIC_STATES_DONT_TREAT: 'CommonBuffId' = 171550 + OWNABLE_VET_CLINIC_STATES_TREAT: 'CommonBuffId' = 171549 + OWNABLE_VET_CLINIC_VALUE_OF_SERVICE_AMAZING: 'CommonBuffId' = 168496 + OWNABLE_VET_CLINIC_VALUE_OF_SERVICE_GOOD: 'CommonBuffId' = 168497 + OWNABLE_VET_CLINIC_VALUE_OF_SERVICE_GREAT: 'CommonBuffId' = 168498 + OWNABLE_VET_CLINIC_VALUE_OF_SERVICE_NEUTRAL: 'CommonBuffId' = 168499 + OWNABLE_VET_CLINIC_VALUE_OF_SERVICE_POOR: 'CommonBuffId' = 168500 + OWNABLE_VET_CLINIC_VALUE_OF_SERVICE_TERRIBLE: 'CommonBuffId' = 168501 + OWNABLE_VET_CLINIC_WAIT_TIME_BAD: 'CommonBuffId' = 167891 + OWNABLE_VET_CLINIC_WAIT_TIME_DISGRUNTLED: 'CommonBuffId' = 167892 + OWNABLE_VET_CLINIC_WAIT_TIME_GOOD: 'CommonBuffId' = 167897 + OWNABLE_VET_CLINIC_WAIT_TIME_START: 'CommonBuffId' = 167898 + OWNABLE_VET_CLINIC_WAIT_TIME_STOP: 'CommonBuffId' = 167899 + PAPARAZZI_EMBARRASSED: 'CommonBuffId' = 196748 + PAPARAZZI_IDLE: 'CommonBuffId' = 201576 + PAPARAZZI_LOCKED_OUT: 'CommonBuffId' = 202199 + PAPARAZZI_MELTDOWN_1: 'CommonBuffId' = 191958 + PAPARAZZI_MELTDOWN_2: 'CommonBuffId' = 191974 + PAPARAZZI_MELTDOWN_3: 'CommonBuffId' = 191975 + PAPARAZZI_PHOTO_OPPORTUNITY: 'CommonBuffId' = 197103 + PAPARAZZI_REACTION_COOLDOWN: 'CommonBuffId' = 191955 + PAPARAZZI_TRAIT: 'CommonBuffId' = 191785 + PARENTING_SKILL_ALLOW_GROUP_COOK: 'CommonBuffId' = 161554 + PARENTING_SKILL_ALLOW_INTERACTION: 'CommonBuffId' = 161871 + PARENTING_SKILL_ALLOW_NAP_SLEEP: 'CommonBuffId' = 161558 + PARENTING_SKILL_ALLOW_SCHOOL_PROJECT: 'CommonBuffId' = 168767 + PARENTING_SKILL_LEVEL_01: 'CommonBuffId' = 160505 + PARENTING_SKILL_LEVEL_02: 'CommonBuffId' = 160510 + PARENTING_SKILL_LEVEL_03: 'CommonBuffId' = 160511 + PARENTING_SKILL_LEVEL_04: 'CommonBuffId' = 160512 + PARENTING_SKILL_LEVEL_05: 'CommonBuffId' = 160513 + PARENTING_SKILL_LEVEL_06: 'CommonBuffId' = 160514 + PARENTING_SKILL_LEVEL_07: 'CommonBuffId' = 160515 + PARENTING_SKILL_LEVEL_08: 'CommonBuffId' = 160516 + PARENTING_SKILL_LEVEL_09: 'CommonBuffId' = 160509 + PARENTING_SKILL_LEVEL_10: 'CommonBuffId' = 160508 + PARENTING_SKILL_PARENTING_TIPS_ANGRY: 'CommonBuffId' = 163208 + PARENTING_SKILL_PARENTING_TIPS_CONFIDENT: 'CommonBuffId' = 163207 + PARENTING_SKILL_PARENTING_TIPS_EMBARRASSED: 'CommonBuffId' = 163209 + PARENTING_SKILL_PARENTING_TIPS_HAPPY: 'CommonBuffId' = 163191 + PARENTING_SKILL_RESEARCH_ANGRY: 'CommonBuffId' = 160653 + PARENTING_SKILL_RESEARCH_CONFIDENT: 'CommonBuffId' = 160652 + PARENTING_SKILL_RESEARCH_EMBARRASSED: 'CommonBuffId' = 160654 + PARENTING_SKILL_RESEARCH_INSPIRED: 'CommonBuffId' = 162632 + PARENTING_SKILL_RESEARCH_STRESSED: 'CommonBuffId' = 162631 + PARENTING_SKILL_SOLVE_BLADDER: 'CommonBuffId' = 160558 + PARENTING_SKILL_SOLVE_BLADDER_ADVANCED: 'CommonBuffId' = 160561 + PARENTING_SKILL_SOLVE_COOLDOWN: 'CommonBuffId' = 162725 + PARENTING_SKILL_SUPER_PARENT: 'CommonBuffId' = 160762 + PARENTING_SKILL_SUPER_SOLVE_INFANT_COOLDOWN: 'CommonBuffId' = 166894 + PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_B_1_SUCCESS: 'CommonBuffId' = 177951 + PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_B_2_FAILURE: 'CommonBuffId' = 177953 + PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_B_2_SUCCESS: 'CommonBuffId' = 177952 + PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_CAMPSITE_CHASED: 'CommonBuffId' = 177995 + PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_C_1_SUCCESS: 'CommonBuffId' = 177955 + PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_C_2_FAILURE: 'CommonBuffId' = 177957 + PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_D_1_SUCCESS: 'CommonBuffId' = 177963 + PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_EGG_2_OPTION_1_FAILURE: 'CommonBuffId' = 180329 + PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_EGG_2_OPTION_2_FAILURE: 'CommonBuffId' = 180328 + PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_E_1_SUCCESS: 'CommonBuffId' = 177972 + PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_FIND_ARTIFACT: 'CommonBuffId' = 177996 + PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_F_1_SUCCESS: 'CommonBuffId' = 177981 + PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_F_2_FAILURE: 'CommonBuffId' = 178010 + PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_G_1_SUCCESS: 'CommonBuffId' = 177987 + PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_H_1_SUCCESS: 'CommonBuffId' = 177991 + PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_PACK_FAILURE: 'CommonBuffId' = 178002 + PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_PACK_SUCCESS: 'CommonBuffId' = 178003 + PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_QUICKSAND_2_OPTION_2_FAILURE: 'CommonBuffId' = 180330 + PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_SLOTHS_2_OPTION_2_FAILURE: 'CommonBuffId' = 180325 + PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_SLOTH_2_OPTION_1_FAILURE: 'CommonBuffId' = 180326 + PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_SLOTH_WALK: 'CommonBuffId' = 180331 + PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_SLOTH_WINK: 'CommonBuffId' = 180332 + PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_VINES_2_OPTION_1_FAILURE: 'CommonBuffId' = 180259 + PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_VINES_2_OPTION_2_FAILURE: 'CommonBuffId' = 180260 + PATH_OBSTACLE_SORE_HANDS: 'CommonBuffId' = 175098 + PA_MATRIARCH_SKILL_UP: 'CommonBuffId' = 29863 + PERFECT_DATE: 'CommonBuffId' = 372997 + PERFORMANCE_SPACE_AUTONOMY_BUSK_GUITAR: 'CommonBuffId' = 142053 + PERFORMANCE_SPACE_AUTONOMY_BUSK_VIOLIN: 'CommonBuffId' = 142052 + PERFORMANCE_SPACE_PUSH_TIP: 'CommonBuffId' = 135155 + PERFORMANCE_SPACE_PUSH_WATCH: 'CommonBuffId' = 143496 + PERFORMANCE_SPACE_TIP_RECIPIENT: 'CommonBuffId' = 133704 + PERFORMANCE_SPACE_TIP_RECIPIENT_WHILE_PERFORMING: 'CommonBuffId' = 143817 + PERSONA_POWERS_EMOTIONAL_DAMPENING_LEVEL1: 'CommonBuffId' = 151084 + PERSONA_POWERS_EMOTIONAL_DAMPENING_LEVEL2: 'CommonBuffId' = 151085 + PERSONA_POWERS_EMOTIONAL_DAMPENING_LEVEL3: 'CommonBuffId' = 151083 + PERSONA_POWERS_GARLIC_IMMUNITY: 'CommonBuffId' = 153329 + PERSONA_POWERS_LOSE_HUMANITY_FUN: 'CommonBuffId' = 150381 + PERSONA_POWERS_LOSE_HUMANITY_HYGIENE: 'CommonBuffId' = 150379 + PERSONA_POWERS_LOSE_HUMANITY_SOCIAL: 'CommonBuffId' = 150380 + PERSONA_POWERS_NOCTURNAL_AFFINITY_LEVEL1: 'CommonBuffId' = 151057 + PERSONA_POWERS_NOCTURNAL_AFFINITY_LEVEL2: 'CommonBuffId' = 151058 + PERSONA_POWERS_NOCTURNAL_AFFINITY_LEVEL3: 'CommonBuffId' = 151056 + PERSONA_POWERS_VAMPIRIC_SLUMBER_LEVEL1: 'CommonBuffId' = 151515 + PERSONA_POWERS_VAMPIRIC_SLUMBER_LEVEL2: 'CommonBuffId' = 151516 + PERSONA_POWERS_VAMPIRIC_SLUMBER_LEVEL3: 'CommonBuffId' = 151517 + PERSONA_POWERS_VAMPIRIC_SLUMBER_LEVEL4: 'CommonBuffId' = 151518 + PERSONA_POWERS_VAMPIRIC_SLUMBER_LEVEL5: 'CommonBuffId' = 151514 + PETS_AGGRESSIVE_TRAIT_HIDDEN: 'CommonBuffId' = 177754 + PETS_CANCEL_LAY_DOWN: 'CommonBuffId' = 168048 + PETS_CAT_SCRATCH_FURNITURE_SIM: 'CommonBuffId' = 163376 + PETS_DOG_SPLASHED_SIM: 'CommonBuffId' = 163813 + PETS_DOG_TOILET_DRINK_HIDDEN: 'CommonBuffId' = 163381 + PETS_DOG_TOILET_DRINK_SIM: 'CommonBuffId' = 163382 + PETS_EAT_PREPARED_PET_RECIPE_FOOD_HIDDEN: 'CommonBuffId' = 170454 + PETS_FEEL_THE_LOVE_ACTOR_SIM: 'CommonBuffId' = 170841 + PETS_FEEL_THE_LOVE_ACTOR_SIM_CAT: 'CommonBuffId' = 172393 + PETS_FEEL_THE_LOVE_TARGET_PET_COOLDOWN: 'CommonBuffId' = 170839 + PETS_FINDING_THINGS_REACTION_BUFF: 'CommonBuffId' = 173842 + PETS_IMITATE_PET_FAILURE_HIDDEN: 'CommonBuffId' = 173301 + PETS_IMITATE_PET_SUCCESS: 'CommonBuffId' = 173312 + PETS_INITIATED_PET_PET_COOL_DOWN: 'CommonBuffId' = 205707 + PETS_MISBEHAVIOR_RECENTLY_DISCIPLINED: 'CommonBuffId' = 167845 + PETS_OBSESS_MIXER_COOLDOWN: 'CommonBuffId' = 170537 + PETS_OWNER_RETURNS_PET_HIDDEN: 'CommonBuffId' = 171078 + PETS_OWNER_RETURNS_SIM_HIDDEN: 'CommonBuffId' = 171148 + PETS_PAMPER_PET_CAT: 'CommonBuffId' = 173702 + PETS_PAMPER_PET_DOG: 'CommonBuffId' = 173703 + PETS_PLAYED_WITH: 'CommonBuffId' = 178350 + PETS_PLAY_WRESTLE_ACTOR_SIM_FAIL: 'CommonBuffId' = 173700 + PETS_PLAY_WRESTLE_ACTOR_SIM_SUCCESS: 'CommonBuffId' = 173698 + PETS_SIM_DIRTY_PET: 'CommonBuffId' = 169046 + PETS_SIM_PEED_ON: 'CommonBuffId' = 167007 + PETS_SLEEP_FX_LARGE_DOG_ZZZZ: 'CommonBuffId' = 178600 + PETS_SLEEP_FX_SMALL_PET_ZZZZ: 'CommonBuffId' = 178605 + PETS_TREAT_COOLDOWN: 'CommonBuffId' = 167244 + PETS_TRIED_TO_BREED: 'CommonBuffId' = 172584 + PETS_WAYPOINT_ROUTE_EVENTS_CAT_LITTERBOX: 'CommonBuffId' = 169985 + PETS_WAYPOINT_ROUTE_EVENTS_CHASE_CAT: 'CommonBuffId' = 170326 + PETS_WAYPOINT_ROUTE_EVENTS_CHASE_DOG: 'CommonBuffId' = 170327 + PETS_WAYPOINT_ROUTE_EVENTS_DOG_HUNGER: 'CommonBuffId' = 169987 + PETS_WAY_POINT_ROUTE_EVENTS_CAT_LOW_AFFECTION: 'CommonBuffId' = 175869 + PET_ACTIVE_GO_FOR_WALK_PLAY_DECAY: 'CommonBuffId' = 172769 + PET_AGGRESSIVE_CALM_DOWN: 'CommonBuffId' = 173138 + PET_AGGRESSIVE_STRANGERS: 'CommonBuffId' = 173147 + PET_AUTONOMY_MOD_NEED_TO_DISCIPLINE_PET: 'CommonBuffId' = 169565 + PET_BE_EXAMINED: 'CommonBuffId' = 167756 + PET_CAT_IS_SLEEPING: 'CommonBuffId' = 158606 + PET_CAT_WANDERLUST: 'CommonBuffId' = 159114 + PET_CURIOUS_SEARCHING: 'CommonBuffId' = 172164 + PET_DISCIPLINE_FREQUENCY_HIGH_CAT_JUMP_ON_COUNTERS: 'CommonBuffId' = 177200 + PET_DISCIPLINE_FREQUENCY_HIGH_CAT_SCRATCHING: 'CommonBuffId' = 177201 + PET_DISCIPLINE_FREQUENCY_HIGH_DOG_BARK: 'CommonBuffId' = 177202 + PET_DISCIPLINE_FREQUENCY_HIGH_DOG_EAT_POOP: 'CommonBuffId' = 177205 + PET_DISCIPLINE_FREQUENCY_HIGH_DOG_JUMP_ON_COUNTERS: 'CommonBuffId' = 177206 + PET_DISCIPLINE_FREQUENCY_HIGH_DOG_PUDDLES_PLAY: 'CommonBuffId' = 177207 + PET_DISCIPLINE_FREQUENCY_HIGH_DOG_TOILET: 'CommonBuffId' = 177208 + PET_DISCIPLINE_FREQUENCY_HIGH_PET_ATTACK: 'CommonBuffId' = 177209 + PET_DISCIPLINE_FREQUENCY_HIGH_PET_BAT_KNOCK_TRASH: 'CommonBuffId' = 177210 + PET_DISCIPLINE_FREQUENCY_HIGH_PET_BEG_EATING: 'CommonBuffId' = 177211 + PET_DISCIPLINE_FREQUENCY_HIGH_PET_EAT_PEOPLE_FOOD: 'CommonBuffId' = 177212 + PET_DISCIPLINE_FREQUENCY_HIGH_PET_POTTY_TRAINING: 'CommonBuffId' = 177213 + PET_DISCIPLINE_FREQUENCY_HIGH_PET_PUDDLES_DRINK: 'CommonBuffId' = 177214 + PET_DISCIPLINE_FREQUENCY_HIGH_PET_TRASH_EAT: 'CommonBuffId' = 177215 + PET_DISCIPLINE_FREQUENCY_HIGH_PET_TRASH_PLAY: 'CommonBuffId' = 177216 + PET_DISCIPLINE_FREQUENCY_HIGH_PET_TRASH_RUMMAGE: 'CommonBuffId' = 177217 + PET_DISCIPLINE_FREQUENCY_HIGH_PET_WAKE_UP_SIMS: 'CommonBuffId' = 177218 + PET_DISCIPLINE_FREQUENCY_MEDIUM_CAT_JUMP_ON_COUNTERS: 'CommonBuffId' = 177179 + PET_DISCIPLINE_FREQUENCY_MEDIUM_CAT_SCRATCHING: 'CommonBuffId' = 177180 + PET_DISCIPLINE_FREQUENCY_MEDIUM_DOG_BARK: 'CommonBuffId' = 177181 + PET_DISCIPLINE_FREQUENCY_MEDIUM_DOG_EAT_POOP: 'CommonBuffId' = 177184 + PET_DISCIPLINE_FREQUENCY_MEDIUM_DOG_JUMP_ON_COUNTERS: 'CommonBuffId' = 177185 + PET_DISCIPLINE_FREQUENCY_MEDIUM_DOG_PUDDLES_PLAY: 'CommonBuffId' = 177186 + PET_DISCIPLINE_FREQUENCY_MEDIUM_DOG_TOILET: 'CommonBuffId' = 177187 + PET_DISCIPLINE_FREQUENCY_MEDIUM_PET_ATTACK: 'CommonBuffId' = 177188 + PET_DISCIPLINE_FREQUENCY_MEDIUM_PET_BAT_KNOCK_TRASH: 'CommonBuffId' = 177189 + PET_DISCIPLINE_FREQUENCY_MEDIUM_PET_BEG_EATING: 'CommonBuffId' = 177190 + PET_DISCIPLINE_FREQUENCY_MEDIUM_PET_EAT_PEOPLE_FOOD: 'CommonBuffId' = 177191 + PET_DISCIPLINE_FREQUENCY_MEDIUM_PET_POTTY_TRAINING: 'CommonBuffId' = 177192 + PET_DISCIPLINE_FREQUENCY_MEDIUM_PET_PUDDLES_DRINK: 'CommonBuffId' = 177193 + PET_DISCIPLINE_FREQUENCY_MEDIUM_PET_TRASH_EAT: 'CommonBuffId' = 177194 + PET_DISCIPLINE_FREQUENCY_MEDIUM_PET_TRASH_PLAY: 'CommonBuffId' = 177195 + PET_DISCIPLINE_FREQUENCY_MEDIUM_PET_TRASH_RUMMAGE: 'CommonBuffId' = 177196 + PET_DISCIPLINE_FREQUENCY_MEDIUM_PET_WAKE_UP_SIMS: 'CommonBuffId' = 177197 + PET_DOG_IS_SLEEPING: 'CommonBuffId' = 158528 + PET_DO_NOT_DISTURB: 'CommonBuffId' = 163908 + PET_ENCOURAGED_TO_WOOHOO: 'CommonBuffId' = 174515 + PET_HAIRY_BRUSHED: 'CommonBuffId' = 172878 + PET_HAIRY_CLEANED_HAIR_PILE: 'CommonBuffId' = 168317 + PET_HUNTER_GO_OUTSIDE_COOLDOWN_BUSH: 'CommonBuffId' = 177356 + PET_HUNTER_GO_OUTSIDE_COOLDOWN_DIG: 'CommonBuffId' = 177357 + PET_HUNTER_GO_OUTSIDE_COOLDOWN_FISHING_LOCATION: 'CommonBuffId' = 169344 + PET_HUNTER_GO_OUTSIDE_COOLDOWN_RUMMAGE_PILE: 'CommonBuffId' = 177823 + PET_HUNTER_GO_OUTSIDE_COOLDOWN_SNIFF: 'CommonBuffId' = 169322 + PET_HUNTER_OPEN_STREET: 'CommonBuffId' = 168780 + PET_INDEPENDENT_LET_OUT: 'CommonBuffId' = 177470 + PET_IS_DYING: 'CommonBuffId' = 164921 + PET_LAZE_COOLDOWN: 'CommonBuffId' = 178001 + PET_LAZY_RELAX_COOLDOWN: 'CommonBuffId' = 177736 + PET_LECTURED_OR_SCOLDED: 'CommonBuffId' = 173671 + PET_LIGHTNING_SCARED: 'CommonBuffId' = 188520 + PET_LITTER_BOX_KISSED_BY_LITTER_BREATH: 'CommonBuffId' = 159314 + PET_LITTER_BOX_LITTER_BREATH_HIDDEN: 'CommonBuffId' = 159273 + PET_LITTER_BOX_SQUEAMISH_TENSE: 'CommonBuffId' = 168955 + PET_OBSTACLE_COURSE_HIDDEN_FAILED_JUMP_FIRE_TAIL: 'CommonBuffId' = 172563 + PET_OBSTACLE_COURSE_HIDDEN_FAILED_OBSTACLE: 'CommonBuffId' = 172552 + PET_OBSTACLE_COURSE_HIDDEN_PASSED_OBSTACLE: 'CommonBuffId' = 172551 + PET_OBSTACLE_COURSE_HIDDEN_PRACTICED_HOOP: 'CommonBuffId' = 172594 + PET_OBSTACLE_COURSE_HIDDEN_PRACTICED_PLATFORM: 'CommonBuffId' = 172598 + PET_OBSTACLE_COURSE_HIDDEN_PRACTICED_RAMP: 'CommonBuffId' = 172596 + PET_OBSTACLE_COURSE_HIDDEN_PRACTICED_TUNNEL: 'CommonBuffId' = 172595 + PET_OBSTACLE_COURSE_HIDDEN_PRACTICED_WEAVING_FLAGS: 'CommonBuffId' = 172597 + PET_OBSTACLE_COURSE_PET_OWNER_HAPPY: 'CommonBuffId' = 170922 + PET_OBSTACLE_COURSE_PET_OWNER_TENSE: 'CommonBuffId' = 170923 + PET_OBSTACLE_COURSE_ROLE_PET_OWNER_WATCHING: 'CommonBuffId' = 170994 + PET_OBSTACLE_COURSE_ROLE_PET_RUN_COURSE: 'CommonBuffId' = 171028 + PET_OVERLAY_PLAID: 'CommonBuffId' = 174660 + PET_OVERLAY_PLAID_CAT: 'CommonBuffId' = 174676 + PET_OVERLAY_PLAID_SMALL_DOG: 'CommonBuffId' = 174677 + PET_OVERLAY_POLKA_DOTS: 'CommonBuffId' = 174661 + PET_OVERLAY_POLKA_DOTS_CAT: 'CommonBuffId' = 174678 + PET_OVERLAY_POLKA_DOTS_SMALL_DOG: 'CommonBuffId' = 174679 + PET_OVERLAY_RAINBOW: 'CommonBuffId' = 174662 + PET_OVERLAY_RAINBOW_CAT: 'CommonBuffId' = 174680 + PET_OVERLAY_RAINBOW_SMALL_DOG: 'CommonBuffId' = 174681 + PET_OWNER_VOCAL_REQUEST_SONG_HAPPY: 'CommonBuffId' = 177691 + PET_OWNER_VOCAL_REQUEST_SONG_TENSE: 'CommonBuffId' = 177692 + PET_PLASMA_EXTRACTED: 'CommonBuffId' = 170695 + PET_POOP_CLEAN_UP: 'CommonBuffId' = 161118 + PET_POOP_CLEAN_UP_SQUEAMISH: 'CommonBuffId' = 176096 + PET_POOP_INTERACTING_WITH: 'CommonBuffId' = 162510 + PET_POOP_STEPPED_ON: 'CommonBuffId' = 162023 + PET_PREFERENCE_SET_INSIDE: 'CommonBuffId' = 159270 + PET_PREFERENCE_SET_OUTSIDE: 'CommonBuffId' = 159271 + PET_RECENTLY_SCOLDED: 'CommonBuffId' = 161684 + PET_SEASON_WEATHER_WET_VFX_LARGE: 'CommonBuffId' = 190863 + PET_SEASON_WEATHER_WET_VFX_SMALL: 'CommonBuffId' = 190862 + PET_SICKNESS_BARFING: 'CommonBuffId' = 163807 + PET_SICKNESS_CRITICAL_FAILURE_BARFING: 'CommonBuffId' = 166037 + PET_SICKNESS_CRITICAL_FAILURE_EXTREME_LETHARGY: 'CommonBuffId' = 166038 + PET_SICKNESS_CRITICAL_FAILURE_FLEAS: 'CommonBuffId' = 166039 + PET_SICKNESS_CRITICAL_FAILURE_GLOWING_NOSE: 'CommonBuffId' = 166040 + PET_SICKNESS_CRITICAL_FAILURE_GOLDEN_POOP: 'CommonBuffId' = 166041 + PET_SICKNESS_CRITICAL_FAILURE_HOT_FEET: 'CommonBuffId' = 166047 + PET_SICKNESS_CRITICAL_FAILURE_ICEY_FUR: 'CommonBuffId' = 166042 + PET_SICKNESS_CRITICAL_FAILURE_MOUTH_MOTHS: 'CommonBuffId' = 166043 + PET_SICKNESS_CRITICAL_FAILURE_RAINBOW_POOP: 'CommonBuffId' = 166044 + PET_SICKNESS_CRITICAL_FAILURE_STINKY_FUR: 'CommonBuffId' = 166045 + PET_SICKNESS_CRITICAL_FAILURE_TEMPORARY_BLOCK_CRITICAL_FAILURE: 'CommonBuffId' = 169620 + PET_SICKNESS_CRITICAL_FAILURE_UNCONTROLLABLE_DROOLING: 'CommonBuffId' = 166046 + PET_SICKNESS_EXTREME_LETHARGY: 'CommonBuffId' = 163808 + PET_SICKNESS_FAILURE_CONTROLLER_BARFING: 'CommonBuffId' = 166022 + PET_SICKNESS_FAILURE_CONTROLLER_EXTREME_LETHARGY: 'CommonBuffId' = 166023 + PET_SICKNESS_FAILURE_CONTROLLER_FLEAS: 'CommonBuffId' = 166024 + PET_SICKNESS_FAILURE_CONTROLLER_GLOWING_NOSE: 'CommonBuffId' = 166025 + PET_SICKNESS_FAILURE_CONTROLLER_GOLDEN_POOP: 'CommonBuffId' = 166026 + PET_SICKNESS_FAILURE_CONTROLLER_HOT_FEET: 'CommonBuffId' = 166032 + PET_SICKNESS_FAILURE_CONTROLLER_ICEY_FUR: 'CommonBuffId' = 166027 + PET_SICKNESS_FAILURE_CONTROLLER_MOUTH_MOTHS: 'CommonBuffId' = 166028 + PET_SICKNESS_FAILURE_CONTROLLER_RAINBOW_POOP: 'CommonBuffId' = 166029 + PET_SICKNESS_FAILURE_CONTROLLER_STINKY_FUR: 'CommonBuffId' = 166030 + PET_SICKNESS_FAILURE_CONTROLLER_UNCONTROLLABLE_DROOLING: 'CommonBuffId' = 166031 + PET_SICKNESS_FLEAS: 'CommonBuffId' = 163806 + PET_SICKNESS_GLOWING_NOSE: 'CommonBuffId' = 163810 + PET_SICKNESS_GOLDEN_POOP: 'CommonBuffId' = 163811 + PET_SICKNESS_HOT_FEET: 'CommonBuffId' = 163802 + PET_SICKNESS_ICEY_FUR: 'CommonBuffId' = 163801 + PET_SICKNESS_MOUTH_MOTHS: 'CommonBuffId' = 163805 + PET_SICKNESS_RAINBOW_POOP: 'CommonBuffId' = 163803 + PET_SICKNESS_STINKY_FUR: 'CommonBuffId' = 163809 + PET_SICKNESS_TEMPORARY_BLOCK_SICKNESS: 'CommonBuffId' = 169691 + PET_SICKNESS_UNCONTROLLABLE_DROOLING: 'CommonBuffId' = 163804 + PET_SICKNESS_WELLNESS_TREAT_BLOCK_SICKNESS: 'CommonBuffId' = 171998 + PET_SMART_TELL_STORY: 'CommonBuffId' = 172406 + PET_SOCIAL_PARENT_TO_CHILD_COOLDOWN: 'CommonBuffId' = 164115 + PET_STOP_EATING_PET_NEARBY: 'CommonBuffId' = 174684 + PET_TEMPERATURE_AUTONOMY_HIDDEN_CAT_HOT: 'CommonBuffId' = 184254 + PET_TEMPERATURE_AUTONOMY_HIDDEN_DOG_HOT: 'CommonBuffId' = 184257 + PET_VFX_EXTREME_LETHARGY_ALL: 'CommonBuffId' = 169440 + PET_VFX_EXTREME_LETHARGY_ALL_CRITICAL: 'CommonBuffId' = 169441 + PET_VFX_FLEAS_CAT_SMALL_DOG: 'CommonBuffId' = 173617 + PET_VFX_FLEAS_CAT_SMALL_DOG_CRITICAL: 'CommonBuffId' = 173619 + PET_VFX_FLEAS_LARGE_DOG: 'CommonBuffId' = 173618 + PET_VFX_FLEAS_LARGE_DOG_CRITICAL: 'CommonBuffId' = 173620 + PET_VFX_GLOWING_NOSE_CAT: 'CommonBuffId' = 167626 + PET_VFX_GLOWING_NOSE_CAT_CRITICAL: 'CommonBuffId' = 167627 + PET_VFX_GLOWING_NOSE_LARGE_DOG: 'CommonBuffId' = 167631 + PET_VFX_GLOWING_NOSE_LARGE_DOG_CRITICAL: 'CommonBuffId' = 167632 + PET_VFX_GLOWING_NOSE_SMALL_DOG: 'CommonBuffId' = 167629 + PET_VFX_GLOWING_NOSE_SMALL_DOG_CRITICAL: 'CommonBuffId' = 167630 + PET_VFX_HOT_FEET_ALL: 'CommonBuffId' = 169618 + PET_VFX_HOT_FEET_ALL_CRITICAL: 'CommonBuffId' = 169619 + PET_VFX_ICEY_FUR_CAT: 'CommonBuffId' = 172982 + PET_VFX_ICEY_FUR_CAT_SMALL_DOG_CRITICAL: 'CommonBuffId' = 169437 + PET_VFX_ICEY_FUR_LARGE_DOG: 'CommonBuffId' = 172983 + PET_VFX_ICEY_FUR_LARGE_DOG_CRITICAL: 'CommonBuffId' = 169436 + PET_VFX_ICEY_FUR_SMALL_DOG: 'CommonBuffId' = 173093 + PET_VFX_ICEY_FUR_SMALL_DOG_ONLY_CRITICAL: 'CommonBuffId' = 172976 + PET_VFX_MOTH_MOUTH_ALL: 'CommonBuffId' = 169447 + PET_VFX_MOTH_MOUTH_ALL_CRITICAL: 'CommonBuffId' = 169448 + PET_VFX_STINKY_FUR_CAT_SMALL_DOG: 'CommonBuffId' = 167674 + PET_VFX_STINKY_FUR_CAT_SMALL_DOG_CRITICAL: 'CommonBuffId' = 167675 + PET_VFX_STINKY_FUR_LARGE_DOG: 'CommonBuffId' = 167676 + PET_VFX_STINKY_FUR_LARGE_DOG_CRITICAL: 'CommonBuffId' = 167677 + PET_VFX_UNCONTROLLABLE_DROOL_CAT_SMALL_DOG: 'CommonBuffId' = 167667 + PET_VFX_UNCONTROLLABLE_DROOL_CAT_SMALL_DOG_LEVEL2: 'CommonBuffId' = 169500 + PET_VFX_UNCONTROLLABLE_DROOL_LARGE_DOG: 'CommonBuffId' = 167668 + PET_VFX_UNCONTROLLABLE_DROOL_LARGE_DOG_LEVEL2: 'CommonBuffId' = 169501 + PET_WANDERLUST_GO_ON_ADVENTURE: 'CommonBuffId' = 173514 + PET_WEATHER_AUTONOMY_HIDDEN_IN_THE_RAIN: 'CommonBuffId' = 186242 + PET_WEATHER_HIDDEN_SNOWING_DOG: 'CommonBuffId' = 183070 + PET_WOOHOO_FAILURE_SAD_CATS: 'CommonBuffId' = 174258 + PET_WOOHOO_FAILURE_SAD_DOGS: 'CommonBuffId' = 174252 + PET_WOOHOO_OUTCOME_HAPPY_CATS: 'CommonBuffId' = 174260 + PET_WOOHOO_OUTCOME_HAPPY_DOGS: 'CommonBuffId' = 174261 + PHONE_BLACK: 'CommonBuffId' = 149354 + PHONE_BLACK_STRIPES: 'CommonBuffId' = 149355 + PHONE_BLUE_POLKA: 'CommonBuffId' = 149356 + PHONE_BREAK_UP_ACTOR_CONFIDENT_AVOIDED_CONFRONTATION: 'CommonBuffId' = 375896 + PHONE_BREAK_UP_ACTOR_HIDDEN_SFX: 'CommonBuffId' = 393718 + PHONE_BREAK_UP_ACTOR_TENSE_GUILTY: 'CommonBuffId' = 375895 + PHONE_BROWN: 'CommonBuffId' = 149357 + PHONE_COLOR_ASTRO_BLACK: 'CommonBuffId' = 284056 + PHONE_COLOR_ASTRO_GRAY: 'CommonBuffId' = 284057 + PHONE_COLOR_ASTRO_MAROON: 'CommonBuffId' = 284058 + PHONE_COLOR_ASTRO_PEACH: 'CommonBuffId' = 284059 + PHONE_COLOR_ASTRO_PINK: 'CommonBuffId' = 284060 + PHONE_COLOR_ASTRO_PURPLE: 'CommonBuffId' = 284061 + PHONE_COLOR_CASSETTE_BLACK: 'CommonBuffId' = 284312 + PHONE_COLOR_CASSETTE_BLUE: 'CommonBuffId' = 284314 + PHONE_COLOR_CASSETTE_GREEN: 'CommonBuffId' = 284313 + PHONE_COLOR_CASSETTE_ORANGE: 'CommonBuffId' = 284316 + PHONE_COLOR_CASSETTE_PINK: 'CommonBuffId' = 284315 + PHONE_COLOR_CASSETTE_RED: 'CommonBuffId' = 284311 + PHONE_COLOR_DUO_BABY_BLUE: 'CommonBuffId' = 284340 + PHONE_COLOR_DUO_BLACK: 'CommonBuffId' = 284343 + PHONE_COLOR_DUO_GREEN: 'CommonBuffId' = 284342 + PHONE_COLOR_DUO_LAVENDER: 'CommonBuffId' = 284341 + PHONE_COLOR_DUO_SLATE: 'CommonBuffId' = 284338 + PHONE_COLOR_DUO_UMBER: 'CommonBuffId' = 284339 + PHONE_COLOR_FLORAL_GREEN_BLUE: 'CommonBuffId' = 284262 + PHONE_COLOR_FLORAL_MAUVE: 'CommonBuffId' = 284263 + PHONE_COLOR_FLORAL_PEACH: 'CommonBuffId' = 284264 + PHONE_COLOR_FLORAL_PINK: 'CommonBuffId' = 284265 + PHONE_COLOR_FLORAL_SLATE: 'CommonBuffId' = 284266 + PHONE_COLOR_FLORAL_YELLOW: 'CommonBuffId' = 284267 + PHONE_COLOR_GEO_BLUE: 'CommonBuffId' = 284287 + PHONE_COLOR_GEO_BROWN: 'CommonBuffId' = 284292 + PHONE_COLOR_GEO_GOLD: 'CommonBuffId' = 284291 + PHONE_COLOR_GEO_GREEN: 'CommonBuffId' = 284289 + PHONE_COLOR_GEO_RED: 'CommonBuffId' = 284288 + PHONE_COLOR_GEO_SILVER: 'CommonBuffId' = 284290 + PHONE_COLOR_PAINT_BLACK: 'CommonBuffId' = 284028 + PHONE_COLOR_PAINT_BLUE: 'CommonBuffId' = 284029 + PHONE_COLOR_PAINT_CANARY: 'CommonBuffId' = 284030 + PHONE_COLOR_PAINT_GREEN: 'CommonBuffId' = 284031 + PHONE_COLOR_PAINT_TEAL: 'CommonBuffId' = 284032 + PHONE_COLOR_PAINT_WHITE: 'CommonBuffId' = 284033 + PHONE_COLOR_ROSE_BLACK: 'CommonBuffId' = 284238 + PHONE_COLOR_ROSE_BLUE: 'CommonBuffId' = 284239 + PHONE_COLOR_ROSE_GREEN: 'CommonBuffId' = 284240 + PHONE_COLOR_ROSE_LAVENDER: 'CommonBuffId' = 284241 + PHONE_COLOR_ROSE_METAL_GOLD: 'CommonBuffId' = 284242 + PHONE_COLOR_ROSE_WHITE: 'CommonBuffId' = 284243 + PHONE_COLOR_SWIRL_BLUE: 'CommonBuffId' = 283987 + PHONE_COLOR_SWIRL_GRAY: 'CommonBuffId' = 283989 + PHONE_COLOR_SWIRL_GREEN: 'CommonBuffId' = 283990 + PHONE_COLOR_SWIRL_ORANGE: 'CommonBuffId' = 283991 + PHONE_COLOR_SWIRL_PINK: 'CommonBuffId' = 283992 + PHONE_COLOR_SWIRL_PURPLE: 'CommonBuffId' = 283993 + PHONE_DARK_BLUE: 'CommonBuffId' = 149358 + PHONE_DARK_GREEN: 'CommonBuffId' = 149359 + PHONE_GOLD: 'CommonBuffId' = 149360 + PHONE_HOT_PINK_POLKA: 'CommonBuffId' = 149361 + PHONE_IDLE_COOLDOWN: 'CommonBuffId' = 310164 + PHONE_LIGHT_PINK: 'CommonBuffId' = 149362 + PHONE_LIME: 'CommonBuffId' = 149346 + PHONE_MINT_GREEN_STRIPES: 'CommonBuffId' = 149347 + PHONE_ORANGE_POLKA: 'CommonBuffId' = 149348 + PHONE_PURPLE: 'CommonBuffId' = 149349 + PHONE_RED: 'CommonBuffId' = 149350 + PHONE_ROSE_GOLD: 'CommonBuffId' = 149351 + PHONE_SILVER: 'CommonBuffId' = 149352 + PHONE_TURQUOISE_STRIPES: 'CommonBuffId' = 149345 + PHONE_WHITE: 'CommonBuffId' = 149353 + PHOTO_BOOTH_TAKE_PHOTO_FINE: 'CommonBuffId' = 296344 + PHOTO_BOOTH_TAKE_PHOTO_WITH_FRIENDLY_FAIL: 'CommonBuffId' = 293020 + PHOTO_BOOTH_TAKE_PHOTO_WITH_FRIENDLY_SUCCESS: 'CommonBuffId' = 293019 + PHOTO_BOOTH_TAKE_PHOTO_WITH_FUNNY_FAIL: 'CommonBuffId' = 293023 + PHOTO_BOOTH_TAKE_PHOTO_WITH_FUNNY_SUCCESS: 'CommonBuffId' = 293024 + PHOTO_BOOTH_TAKE_PHOTO_WITH_MISCHIEF_FAIL: 'CommonBuffId' = 293026 + PHOTO_BOOTH_TAKE_PHOTO_WITH_MISCHIEF_SUCCESS: 'CommonBuffId' = 293025 + PHOTO_BOOTH_TAKE_PHOTO_WITH_ROMANTIC_FAIL: 'CommonBuffId' = 293021 + PHOTO_BOOTH_TAKE_PHOTO_WITH_ROMANTIC_SUCCESS: 'CommonBuffId' = 293022 + PHOTO_BOOTH_TRACK_INITIATING_SIM: 'CommonBuffId' = 302417 + PHOTO_BOOTH_WOOHOO_GREAT: 'CommonBuffId' = 295910 + PHOTO_OP_STAND_CAUGHT_IN_THE_ACT: 'CommonBuffId' = 291270 + PHOTO_OP_STAND_TRASHED_TRIUMPH: 'CommonBuffId' = 291269 + PHYSICALLY_GIFTED: 'CommonBuffId' = 29626 + PICNIC_BASKET_COLDWEATHER: 'CommonBuffId' = 257906 + PICNIC_BASKET_HAPPY: 'CommonBuffId' = 257907 + PICNIC_BASKET_HAPPY_LOVES_OUTDOORS: 'CommonBuffId' = 258482 + PICNIC_BASKET_HOTWEATHER: 'CommonBuffId' = 257905 + PICNIC_BASKET_RAIN: 'CommonBuffId' = 257904 + PIER_ATTRACTIONS_BANNED_FERRIS_WHEEL: 'CommonBuffId' = 291046 + PIER_ATTRACTIONS_BANNED_HAUNTED_HOUSE: 'CommonBuffId' = 291195 + PIER_ATTRACTIONS_BANNED_TUNNEL_OF_LOVE: 'CommonBuffId' = 291196 + PIER_ATTRACTIONS_FERRIS_WHEEL_MESS_AROUND_1_A_FLIRTY: 'CommonBuffId' = 291082 + PIER_ATTRACTIONS_FERRIS_WHEEL_MESS_AROUND_1_B_DAZED: 'CommonBuffId' = 291106 + PIER_ATTRACTIONS_FERRIS_WHEEL_MESS_AROUND_2_A_SAD: 'CommonBuffId' = 291110 + PIER_ATTRACTIONS_FERRIS_WHEEL_MESS_AROUND_2_B_EMBARRASSED: 'CommonBuffId' = 291112 + PIER_ATTRACTIONS_FERRIS_WHEEL_RIDE_1_A_SCARED: 'CommonBuffId' = 291018 + PIER_ATTRACTIONS_FERRIS_WHEEL_RIDE_1_B_EMBARRASSED: 'CommonBuffId' = 291022 + PIER_ATTRACTIONS_FERRIS_WHEEL_RIDE_2_B_CONFIDENT: 'CommonBuffId' = 291024 + PIER_ATTRACTIONS_FERRIS_WHEEL_RIDE_2_B_EMBARRASSED: 'CommonBuffId' = 291034 + PIER_ATTRACTIONS_FERRIS_WHEEL_RIDE_3_A_BORED: 'CommonBuffId' = 291039 + PIER_ATTRACTIONS_FERRIS_WHEEL_RIDE_3_A_INSPIRED: 'CommonBuffId' = 291037 + PIER_ATTRACTIONS_FERRIS_WHEEL_RIDE_3_B_PLAYFUL: 'CommonBuffId' = 291045 + PIER_ATTRACTIONS_FERRIS_WHEEL_RIDE_WITH_1_A_TENSE: 'CommonBuffId' = 291052 + PIER_ATTRACTIONS_FERRIS_WHEEL_RIDE_WITH_1_B_SCARED: 'CommonBuffId' = 291059 + PIER_ATTRACTIONS_FERRIS_WHEEL_RIDE_WITH_2_A_FLIRTY: 'CommonBuffId' = 291061 + PIER_ATTRACTIONS_FERRIS_WHEEL_RIDE_WITH_2_B_EMBARRASSED: 'CommonBuffId' = 291064 + PIER_ATTRACTIONS_FERRIS_WHEEL_RIDE_WITH_3_A_PLAYFUL: 'CommonBuffId' = 291074 + PIER_ATTRACTIONS_FERRIS_WHEEL_RIDE_WITH_3_B_TENSE: 'CommonBuffId' = 291079 + PIER_ATTRACTIONS_FERRIS_WHEEL_RIDE_WITH_4_B_SAD: 'CommonBuffId' = 291094 + PIER_ATTRACTIONS_FERRIS_WHEEL_WOOHOO_1_A_CONFIDENT: 'CommonBuffId' = 291521 + PIER_ATTRACTIONS_FERRIS_WHEEL_WOOHOO_1_B_UNCOMFORTABLE: 'CommonBuffId' = 291114 + PIER_ATTRACTIONS_HAUNTED_HOUSE_MESS_AROUND_1_A_EMBARRASSED: 'CommonBuffId' = 291165 + PIER_ATTRACTIONS_HAUNTED_HOUSE_MESS_AROUND_1_B_SCARED: 'CommonBuffId' = 291167 + PIER_ATTRACTIONS_HAUNTED_HOUSE_MESS_AROUND_2_A_SCARED: 'CommonBuffId' = 291185 + PIER_ATTRACTIONS_HAUNTED_HOUSE_RIDE_1_SCARED: 'CommonBuffId' = 291125 + PIER_ATTRACTIONS_HAUNTED_HOUSE_RIDE_WITH_1_A_CONFIDENT: 'CommonBuffId' = 291128 + PIER_ATTRACTIONS_HAUNTED_HOUSE_RIDE_WITH_1_A_EMBARRASSED: 'CommonBuffId' = 291131 + PIER_ATTRACTIONS_HAUNTED_HOUSE_RIDE_WITH_1_B_EMBARRASSED: 'CommonBuffId' = 291139 + PIER_ATTRACTIONS_HAUNTED_HOUSE_RIDE_WITH_2_B_HAPPY: 'CommonBuffId' = 291161 + PIER_ATTRACTIONS_HAUNTED_HOUSE_RIDE_WITH_2_B_TENSE: 'CommonBuffId' = 291162 + PIER_ATTRACTIONS_HAUNTED_HOUSE_WOOHOO_1_A_SCARED: 'CommonBuffId' = 291188 + PIER_ATTRACTIONS_TUNNEL_OF_LOVE_MESS_AROUND_1_A_FLIRTY: 'CommonBuffId' = 291279 + PIER_ATTRACTIONS_TUNNEL_OF_LOVE_MESS_AROUND_1_B_CONFIDENT: 'CommonBuffId' = 291281 + PIER_ATTRACTIONS_TUNNEL_OF_LOVE_MESS_AROUND_2_A_EMBARRASSED: 'CommonBuffId' = 291284 + PIER_ATTRACTIONS_TUNNEL_OF_LOVE_RIDE_1_A_FOCUSED: 'CommonBuffId' = 291203 + PIER_ATTRACTIONS_TUNNEL_OF_LOVE_RIDE_1_A_TENSE: 'CommonBuffId' = 291205 + PIER_ATTRACTIONS_TUNNEL_OF_LOVE_RIDE_1_B_TENSE: 'CommonBuffId' = 291208 + PIER_ATTRACTIONS_TUNNEL_OF_LOVE_RIDE_2_A_CONFIDENT: 'CommonBuffId' = 291221 + PIER_ATTRACTIONS_TUNNEL_OF_LOVE_RIDE_2_B_SCARED: 'CommonBuffId' = 291223 + PIER_ATTRACTIONS_TUNNEL_OF_LOVE_RIDE_WITH_1_B_FLIRTY: 'CommonBuffId' = 291236 + PIER_ATTRACTIONS_TUNNEL_OF_LOVE_RIDE_WITH_2_A_SAD: 'CommonBuffId' = 291238 + PIER_ATTRACTIONS_TUNNEL_OF_LOVE_RIDE_WITH_2_B_SAD: 'CommonBuffId' = 291241 + PIPE_ORGAN_OMINOUS_REFRAIN: 'CommonBuffId' = 151459 + PIPE_ORGAN_VAMPIRIC_MELODY: 'CommonBuffId' = 151421 + PIT_BBQ_SERVING_THE_COMMUNITY: 'CommonBuffId' = 210737 + PIVOTAL_MOMENT_ASPIRATION_GOAL_COMPLETE_HIDDEN: 'CommonBuffId' = 357713 + PIVOTAL_MOMENT_COOLDOWN_1_HIDDEN: 'CommonBuffId' = 355472 + PIVOTAL_MOMENT_COOLDOWN_2_HIDDEN: 'CommonBuffId' = 357601 + PIVOTAL_MOMENT_COOLDOWN_3_HIDDEN: 'CommonBuffId' = 357602 + PIVOTAL_MOMENT_COOLDOWN_4_HIDDEN: 'CommonBuffId' = 357603 + PIVOTAL_MOMENT_HAS_JOB_HIDDEN: 'CommonBuffId' = 357803 + PIVOTAL_MOMENT_PHOTO_TAKEN_HIDDEN: 'CommonBuffId' = 356336 + PIVOTAL_MOMENT_REWARD_PURCHASED_HIDDEN: 'CommonBuffId' = 355574 + PIVOTAL_MOMENT_TRIGGER_1_HIDDEN: 'CommonBuffId' = 357605 + PIVOTAL_MOMENT_TRIGGER_2_HIDDEN: 'CommonBuffId' = 357606 + PIVOTAL_MOMENT_TRIGGER_3_HIDDEN: 'CommonBuffId' = 357607 + PIVOTAL_MOMENT_TRIGGER_4_HIDDEN: 'CommonBuffId' = 357608 + PIVOTAL_MOMENT_WHIM_COMPLETE_HIDDEN: 'CommonBuffId' = 356697 + PLACEMAT_INSPIRED: 'CommonBuffId' = 134050 + PLANT_MOON_PETAL_FLOWER_EATEN: 'CommonBuffId' = 291945 + PLANT_SIMS_FORBIDDEN_FRUIT_COOLDOWN: 'CommonBuffId' = 163656 + PLANT_SIMS_MAIN_VISIBLE: 'CommonBuffId' = 162844 + PLANT_SIMS_MAIN_VISIBLE_NPC: 'CommonBuffId' = 163437 + PLANT_SIMS_MOOD_AURAS_ANGRY: 'CommonBuffId' = 162841 + PLANT_SIMS_MOOD_AURAS_CONFIDENT: 'CommonBuffId' = 162837 + PLANT_SIMS_MOOD_AURAS_FLIRTY: 'CommonBuffId' = 162842 + PLANT_SIMS_MOOD_AURAS_PLAYFUL: 'CommonBuffId' = 162838 + PLANT_SIMS_MOOD_AURAS_SAD: 'CommonBuffId' = 162840 + PLANT_SIMS_MOOD_AURAS_UNCOMFORTABLE: 'CommonBuffId' = 162839 + PLANT_SIMS_PHOTOSYNTHESIS: 'CommonBuffId' = 162730 + PLANT_SIMS_SCENARIO_NOT_PLANT_SIM_INVISIBLE: 'CommonBuffId' = 294922 + PLANT_SIMS_SCENARIO_NOT_PLANT_SIM_TNS_INVISIBLE: 'CommonBuffId' = 297142 + PLANT_SIMS_SCENARIO_NOT_PLANT_SIM_VISIBLE: 'CommonBuffId' = 294909 + PLANT_SIMS_SCENARIO_REWARD_INVISIBLE: 'CommonBuffId' = 293723 + PLAYFUL_SCENT: 'CommonBuffId' = 121611 + PLAY_CHESS_FOCUSED_LOW: 'CommonBuffId' = 28269 + PLAY_CHESS_FOCUSED_MED: 'CommonBuffId' = 28271 + PLOPSY_SHIPPED: 'CommonBuffId' = 241761 + PODIUM_PAIR_DEBATE_SHOWDOWN_UNIFORM: 'CommonBuffId' = 230306 + PODIUM_PAIR_DEBATE_SHOWDOWN_UNIFORM_SCIENCE: 'CommonBuffId' = 230435 + PODIUM_PAIR_DEBATING: 'CommonBuffId' = 219247 + PODIUM_PAIR_VISIBLE_DEFT: 'CommonBuffId' = 218954 + PODIUM_PAIR_VISIBLE_DISAPPOINTING: 'CommonBuffId' = 218955 + PODIUM_PAIR_VISIBLE_DUD: 'CommonBuffId' = 218953 + PODIUM_PAIR_VISIBLE_VICTORIOUS: 'CommonBuffId' = 218950 + PODIUM_PAIR_VISIBLE_WISE_WORDS: 'CommonBuffId' = 222273 + PODIUM_PAIR_WATCHING: 'CommonBuffId' = 229809 + PODIUM_STAND_NEARBY_COOLDOWN: 'CommonBuffId' = 169459 + POISON_DYING: 'CommonBuffId' = 179683 + POISON_FEELING_ICKY: 'CommonBuffId' = 176141 + POISON_FEELING_ICKY_ANCIENT_RELIC_CURSE: 'CommonBuffId' = 179739 + POISON_FEELING_ICKY_BIT_BY_SPIDER: 'CommonBuffId' = 179740 + POISON_FEELING_ICKY_GATE: 'CommonBuffId' = 180014 + POISON_FEELING_ICKY_GHOST_BELCH: 'CommonBuffId' = 179741 + POISON_FEELING_ICKY_POISON_DART: 'CommonBuffId' = 179742 + POISON_FEELING_ICKY_POISON_GAS: 'CommonBuffId' = 180334 + POISON_FEELING_ICKY_STUNG_BY_BEE: 'CommonBuffId' = 179743 + POISON_OVERCAME_POISONING: 'CommonBuffId' = 176188 + POISON_OVERWHELMINGLY_POISONED: 'CommonBuffId' = 176189 + POISON_OVERWHELMINGLY_POISONED_ANCIENT_RELIC_CURSE: 'CommonBuffId' = 179744 + POISON_OVERWHELMINGLY_POISONED_BIT_BY_SPIDER: 'CommonBuffId' = 179745 + POISON_OVERWHELMINGLY_POISONED_GATE: 'CommonBuffId' = 180015 + POISON_OVERWHELMINGLY_POISONED_GHOST_BELCH: 'CommonBuffId' = 179746 + POISON_OVERWHELMINGLY_POISONED_POISON_DART: 'CommonBuffId' = 179747 + POISON_OVERWHELMINGLY_POISONED_POISON_GAS: 'CommonBuffId' = 180335 + POISON_OVERWHELMINGLY_POISONED_STUNG_BY_BEE: 'CommonBuffId' = 179748 + POISON_POISONED: 'CommonBuffId' = 176187 + POISON_POISONED_ANCIENT_RELIC_CURSE: 'CommonBuffId' = 179749 + POISON_POISONED_BIT_BY_SPIDER: 'CommonBuffId' = 179750 + POISON_POISONED_GATE: 'CommonBuffId' = 180016 + POISON_POISONED_GHOST_BELCH: 'CommonBuffId' = 179751 + POISON_POISONED_POISON_DART: 'CommonBuffId' = 179752 + POISON_POISONED_POISON_GAS: 'CommonBuffId' = 180336 + POISON_POISONED_STUNG_BY_BEE: 'CommonBuffId' = 179753 + POLITE_INTRODUCTION_POLITE_IS_RIGHT: 'CommonBuffId' = 161842 + POLITE_INTRODUCTION_SO_POLITE: 'CommonBuffId' = 161843 + POOLS_HYGIENE: 'CommonBuffId' = 156408 + POOLS_PLANT_SIM_WATER: 'CommonBuffId' = 164852 + POOLS_SITTING_POOL_SIDE: 'CommonBuffId' = 343464 + POOLS_SPLASHY_FUN: 'CommonBuffId' = 106177 + POOL_HAPPY_RELAXING_SWIM: 'CommonBuffId' = 103891 + POOL_TEMPERATURE_POLAR_BEAR_CLUB: 'CommonBuffId' = 180225 + POOL_TEMPERATURE_WATERS_FINE: 'CommonBuffId' = 180226 + POSITIVITY_CHALLENGE_VIEW_POSITIVITY_POSTER_TIER_1_CONFIDENT: 'CommonBuffId' = 198954 + POSITIVITY_CHALLENGE_VIEW_POSITIVITY_POSTER_TIER_1_FOCUSED: 'CommonBuffId' = 198953 + POSITIVITY_CHALLENGE_VIEW_POSITIVITY_POSTER_TIER_1_INSPIRED: 'CommonBuffId' = 198952 + POSITIVITY_CHALLENGE_VIEW_POSITIVITY_POSTER_TIER_2_CONFIDENT: 'CommonBuffId' = 198928 + POSITIVITY_CHALLENGE_VIEW_POSITIVITY_POSTER_TIER_2_FOCUSED: 'CommonBuffId' = 198956 + POSITIVITY_CHALLENGE_VIEW_POSITIVITY_POSTER_TIER_2_INSPIRED: 'CommonBuffId' = 198955 + POSITIVITY_CHALLENGE_VIEW_POSITIVITY_POSTER_TIER_3_CONFIDENT: 'CommonBuffId' = 198929 + POSITIVITY_CHALLENGE_VIEW_POSITIVITY_POSTER_TIER_3_FOCUSED: 'CommonBuffId' = 198957 + POSITIVITY_CHALLENGE_VIEW_POSITIVITY_POSTER_TIER_3_INSPIRED: 'CommonBuffId' = 198958 + POSITIVITY_CHALLENGE_VIEW_POSITIVITY_POSTER_TIER_4_CONFIDENT: 'CommonBuffId' = 198930 + POSITIVITY_CHALLENGE_VIEW_POSITIVITY_POSTER_TIER_4_FOCUSED: 'CommonBuffId' = 198959 + POSITIVITY_CHALLENGE_VIEW_POSITIVITY_POSTER_TIER_4_INSPIRED: 'CommonBuffId' = 198960 + POSITIVITY_CHALLENGE_VIEW_POSTER: 'CommonBuffId' = 198962 + POSSESSED_BEHAVIOR_EATING_INFECTED_FRUIT: 'CommonBuffId' = 203158 + POSSESSED_BEHAVIOR_FROM_ALLURING_MOTHER_PLANT: 'CommonBuffId' = 204371 + POSSESSED_BEHAVIOR_FROM_INFECTION_SCANNER: 'CommonBuffId' = 203389 + POSSESSED_BEHAVIOR_FROM_INFECTION_TIME: 'CommonBuffId' = 203122 + POSSESSED_BEHAVIOR_FROM_MOTHER_PLANT_LOSE: 'CommonBuffId' = 205282 + POSSESSED_BEHAVIOR_FROM_SPORE_HALLWAY: 'CommonBuffId' = 203702 + POSSESSED_BEHAVIOR_INFECTED_ATTACK: 'CommonBuffId' = 204729 + POSSESSED_BEHAVIOR_WALK_BY: 'CommonBuffId' = 204018 + POSSESSED_BEHAVIOR_WELCOME_WAGON: 'CommonBuffId' = 204536 + POSSESSED_JUICE_FIZZER_EP09_ADD_WALK_STYLE: 'CommonBuffId' = 236683 + POSSESSED_PLANT_SPORE_COOLDOWN: 'CommonBuffId' = 202902 + POSSESSED_PRE_WELCOME_WAGON: 'CommonBuffId' = 204537 + POSSESSED_TEND_INFECTED_PLANT_COOLDOWN: 'CommonBuffId' = 205352 + POSSESSED_VISIBLE: 'CommonBuffId' = 205491 + POSSESSED_WELCOME_WAGON_TIMED: 'CommonBuffId' = 205505 + POUNCE_STALK: 'CommonBuffId' = 171570 + PRAISE_GRADES_CONFIDENT: 'CommonBuffId' = 98981 + PREGNANCY_FREEZE_PROGRESS: 'CommonBuffId' = 248750 + PREGNANCY_IN_HEAT_ATTRACTOR: 'CommonBuffId' = 169035 + PREGNANCY_IN_HEAT_COOLDOWN: 'CommonBuffId' = 169036 + PREGNANCY_IN_LABOR: 'CommonBuffId' = 75271 + PREGNANCY_IN_LABOR_MALE: 'CommonBuffId' = 102463 + PREGNANCY_IN_LABOR_PET_CAT: 'CommonBuffId' = 169229 + PREGNANCY_IN_LABOR_PET_DOG: 'CommonBuffId' = 169251 + PREGNANCY_IN_LABOR_PET_HORSE: 'CommonBuffId' = 323055 + PREGNANCY_LABOR_REACT: 'CommonBuffId' = 98878 + PREGNANCY_NOT_PREGNANT: 'CommonBuffId' = 104000 + PREGNANCY_NOT_PREGNANT_HATES_CHILDREN: 'CommonBuffId' = 132010 + PREGNANCY_NOT_SHOWING: 'CommonBuffId' = 12560 + PREGNANCY_NOT_SHOWING_MALE: 'CommonBuffId' = 113493 + PREGNANCY_NOT_SHOWING_PET_CAT: 'CommonBuffId' = 169230 + PREGNANCY_NOT_SHOWING_PET_DOG: 'CommonBuffId' = 169250 + PREGNANCY_NOT_SHOWING_PET_HORSE: 'CommonBuffId' = 323051 + PREGNANCY_POST_LABOR_WORK_PERFORMANCE_MOD: 'CommonBuffId' = 103279 + PREGNANCY_TODDLER_FAMILY_LEAVE: 'CommonBuffId' = 157206 + PREGNANCY_TRIMESTER1: 'CommonBuffId' = 12561 + PREGNANCY_TRIMESTER1_HATES_CHILDREN: 'CommonBuffId' = 97309 + PREGNANCY_TRIMESTER1_MALE: 'CommonBuffId' = 102464 + PREGNANCY_TRIMESTER1_PET_CAT: 'CommonBuffId' = 169232 + PREGNANCY_TRIMESTER1_PET_DOG: 'CommonBuffId' = 169249 + PREGNANCY_TRIMESTER1_PET_HORSE: 'CommonBuffId' = 323052 + PREGNANCY_TRIMESTER2: 'CommonBuffId' = 12562 + PREGNANCY_TRIMESTER2_HATES_CHILDREN: 'CommonBuffId' = 97310 + PREGNANCY_TRIMESTER2_MALE: 'CommonBuffId' = 102465 + PREGNANCY_TRIMESTER2_PET_CAT: 'CommonBuffId' = 169233 + PREGNANCY_TRIMESTER2_PET_DOG: 'CommonBuffId' = 169248 + PREGNANCY_TRIMESTER2_PET_HORSE: 'CommonBuffId' = 323053 + PREGNANCY_TRIMESTER3: 'CommonBuffId' = 12563 + PREGNANCY_TRIMESTER3_HATES_CHILDREN: 'CommonBuffId' = 97311 + PREGNANCY_TRIMESTER3_MALE: 'CommonBuffId' = 102466 + PREGNANCY_TRIMESTER3_PET_CAT: 'CommonBuffId' = 169234 + PREGNANCY_TRIMESTER3_PET_DOG: 'CommonBuffId' = 169247 + PREGNANCY_TRIMESTER3_PET_HORSE: 'CommonBuffId' = 323054 + PRESENT_PILE_BAD_PRESENT: 'CommonBuffId' = 180956 + PRESENT_PILE_CAUGHT_PRANKING: 'CommonBuffId' = 185925 + PRESENT_PILE_CAUGHT_STEALING: 'CommonBuffId' = 181000 + PRESENT_PILE_GET_EXCITED: 'CommonBuffId' = 181006 + PRESENT_PILE_OPEN_COOLDOWN: 'CommonBuffId' = 180903 + PRESENT_PILE_PERFECT_PRESENT: 'CommonBuffId' = 180961 + PRESENT_PILE_SNEAK_COOLDOWN: 'CommonBuffId' = 190976 + PRESSURE_COOKER_SIMMERING_SATISFACTION: 'CommonBuffId' = 344658 + PRESSURE_COOKER_TOILANDTROUBLE: 'CommonBuffId' = 344659 + PREVENT_BUCK_OFF_OR_PUT_DOWN_SIM: 'CommonBuffId' = 330347 + PREVENT_DISMOUNTING: 'CommonBuffId' = 328887 + PREVENT_RUNNING: 'CommonBuffId' = 74343 + PRIVACY_EMBARRASSED: 'CommonBuffId' = 10425 + PRIVACY_EMBARRASSED_SHOWER_WALL: 'CommonBuffId' = 229668 + PRIVACY_EMBARRASSED_TARGET: 'CommonBuffId' = 99779 + PRIVACY_IMMUNE: 'CommonBuffId' = 39303 + PROFESSOR_NPC_ASK_FOR_HIGHER_GRADE_0_EMBARRASSED: 'CommonBuffId' = 225289 + PROFESSOR_NPC_ASK_FOR_HIGHER_GRADE_0_TENSE: 'CommonBuffId' = 225290 + PROFESSOR_NPC_ASK_FOR_HIGHER_GRADE_1_CONFIDENT: 'CommonBuffId' = 225294 + PROFESSOR_NPC_ASK_FOR_HIGHER_GRADE_1_EMBARRASSED: 'CommonBuffId' = 225291 + PROFESSOR_NPC_ASK_FOR_HIGHER_GRADE_1_TENSE: 'CommonBuffId' = 225293 + PROFESSOR_NPC_ASK_FOR_HIGHER_GRADE_1_UNCOMFORTABLE: 'CommonBuffId' = 225292 + PROFESSOR_NPC_ASK_FOR_HIGHER_GRADE_2_CONFIDENT: 'CommonBuffId' = 225384 + PROFESSOR_NPC_ASK_FOR_HIGHER_GRADE_2_TENSE: 'CommonBuffId' = 225295 + PROFESSOR_NPC_ASK_FOR_HIGHER_GRADE_2_UNCOMFORTABLE: 'CommonBuffId' = 227869 + PROFESSOR_NPC_ASK_FOR_HIGHER_GRADE_COOLDOWN_A: 'CommonBuffId' = 225698 + PROFESSOR_NPC_ASK_FOR_HIGHER_GRADE_COOLDOWN_B: 'CommonBuffId' = 225699 + PROFESSOR_NPC_ASK_FOR_HIGHER_GRADE_COOLDOWN_C: 'CommonBuffId' = 225700 + PROFESSOR_NPC_ASK_FOR_HIGHER_GRADE_COOLDOWN_D: 'CommonBuffId' = 225701 + PROFESSOR_NPC_ASK_FOR_HIGHER_GRADE_HIDDEN_ANGRY: 'CommonBuffId' = 225299 + PROFESSOR_NPC_ASK_FOR_HIGHER_GRADE_HIDDEN_UNCOMFORTABLE: 'CommonBuffId' = 225300 + PROFESSOR_NPC_ASK_FOR_HIGHER_GRADE_TERM_COOLDOWN_A: 'CommonBuffId' = 225782 + PROFESSOR_NPC_ASK_FOR_HIGHER_GRADE_TERM_COOLDOWN_B: 'CommonBuffId' = 225783 + PROFESSOR_NPC_ASK_FOR_HIGHER_GRADE_TERM_COOLDOWN_C: 'CommonBuffId' = 225784 + PROFESSOR_NPC_ASK_FOR_HIGHER_GRADE_TERM_COOLDOWN_D: 'CommonBuffId' = 225785 + PROMISE_RINGS_REJECTED: 'CommonBuffId' = 99508 + PROMO_NIGHT_GENERAL: 'CommonBuffId' = 124256 + PROTEIN_SHAKE: 'CommonBuffId' = 38979 + PROXIMITY_EMBARRASSED_BY_POOR_PLAYING: 'CommonBuffId' = 38910 + PROXIMITY_HATES_CHILDREN: 'CommonBuffId' = 10605 + PROXIMITY_HATES_CHILDREN_TENSE: 'CommonBuffId' = 258976 + PROXIMITY_OBJECT_ROMANTIC_FIREPLACE: 'CommonBuffId' = 135671 + PROXIMITY_POOR_PLAYING: 'CommonBuffId' = 38898 + PROXIMITY_TRAIT_CHILD_SKILL_PACK_ANIMAL: 'CommonBuffId' = 308831 + PTO_IN_NEED_OF_A_BREAK: 'CommonBuffId' = 111110 + PTO_NEEDS_A_DAY_OFF: 'CommonBuffId' = 111111 + PTO_NEEDS_A_VACATION: 'CommonBuffId' = 111112 + PUBERTY_CHANGES_ACNE_REMOVED: 'CommonBuffId' = 286428 + PUBERTY_CHANGES_CLEANSER_HIDDEN: 'CommonBuffId' = 302584 + PUBERTY_CHANGES_CONCEALER_FAIL: 'CommonBuffId' = 286275 + PUBERTY_CHANGES_CONCEALER_SUCCESS_HIDDEN: 'CommonBuffId' = 286276 + PUBERTY_CHANGES_CURRENTLY_SHAVING_BG: 'CommonBuffId' = 305278 + PUBERTY_CHANGES_GROWTH_ACNE: 'CommonBuffId' = 286425 + PUBERTY_CHANGES_GROWTH_FIRST_TIME: 'CommonBuffId' = 286424 + PUBERTY_CHANGES_GROWTH_HAIR_HAPPY: 'CommonBuffId' = 286427 + PUBERTY_CHANGES_GROWTH_HAIR_NEGATIVE: 'CommonBuffId' = 286497 + PUBERTY_CHANGES_HAS_ACNE: 'CommonBuffId' = 303135 + PUBERTY_CHANGES_MOCKED_ACNE: 'CommonBuffId' = 286430 + PUBERTY_CHANGES_MOCKED_HAIR: 'CommonBuffId' = 286431 + PUBERTY_CHANGES_MOCKED_HIDDEN: 'CommonBuffId' = 286498 + PUBERTY_CHANGES_SHAVING_NICKS: 'CommonBuffId' = 286429 + PUBERTY_CHANGES_SUPPORT: 'CommonBuffId' = 286426 + PUBERTY_CHANGES_SUPPORTED_HIDDEN: 'CommonBuffId' = 286474 + PUMPED_UP: 'CommonBuffId' = 27703 + PUNCHING_BAG_FEELING_FEARLESS: 'CommonBuffId' = 26576 + PUNCHING_BAG_FLYING_FEET: 'CommonBuffId' = 39349 + PUPPET_THEATER_ANNOYING_PUPPETS: 'CommonBuffId' = 133838 + PUPPET_THEATER_ENJOYABLE_PUPPET_SHOW: 'CommonBuffId' = 133836 + PUPPET_THEATER_GOOD_EFFORT: 'CommonBuffId' = 133837 + PUPPET_THEATER_GREAT_PERFORMANCE: 'CommonBuffId' = 133834 + PUPPET_THEATER_HIDDEN_MAKE_A_MISTAKE: 'CommonBuffId' = 133877 + PUPPET_THEATER_MADE_MISTAKES: 'CommonBuffId' = 133835 + QUADCOPTER_PLAY: 'CommonBuffId' = 224438 + QUICK_SOCIAL_COOLDOWN_JUICE_KEG_PARTY_SOCIALS: 'CommonBuffId' = 228627 + QUIRK_COOLDOWNS_FEAR_COFFEE_MAKER: 'CommonBuffId' = 168373 + QUIRK_COOLDOWNS_FEAR_COMPUTER: 'CommonBuffId' = 168375 + QUIRK_COOLDOWNS_FEAR_DISHWASHER: 'CommonBuffId' = 168376 + QUIRK_COOLDOWNS_FEAR_DOORBELL: 'CommonBuffId' = 168400 + QUIRK_COOLDOWNS_FEAR_FIRE: 'CommonBuffId' = 168377 + QUIRK_COOLDOWNS_FEAR_FITNESS_EQUIPMENT: 'CommonBuffId' = 168378 + QUIRK_COOLDOWNS_FEAR_GAMING: 'CommonBuffId' = 168379 + QUIRK_COOLDOWNS_FEAR_INSTRUMENT: 'CommonBuffId' = 168380 + QUIRK_COOLDOWNS_FEAR_MICROWAVE: 'CommonBuffId' = 168381 + QUIRK_COOLDOWNS_FEAR_ROBOT_VACUUM: 'CommonBuffId' = 172030 + QUIRK_COOLDOWNS_FEAR_SHOWER: 'CommonBuffId' = 168382 + QUIRK_COOLDOWNS_FEAR_STEREO: 'CommonBuffId' = 168383 + QUIRK_COOLDOWNS_FEAR_STOVE: 'CommonBuffId' = 168384 + QUIRK_COOLDOWNS_FEAR_SWIMMING: 'CommonBuffId' = 168385 + QUIRK_COOLDOWNS_FEAR_TOILET: 'CommonBuffId' = 168386 + QUIRK_COOLDOWNS_FEAR_TV: 'CommonBuffId' = 168387 + QUIRK_COOLDOWNS_FEAR_VACUUM: 'CommonBuffId' = 257145 + RAIN_RUN_COOLDOWN: 'CommonBuffId' = 184967 + RAIN_RUN_COOLDOWN_PLAY_IN_RAIN: 'CommonBuffId' = 191266 + REACTION_BREAK_INVESTIGATION: 'CommonBuffId' = 159914 + REACTION_BREAK_SOCIAL_CHAT: 'CommonBuffId' = 126524 + REACTION_COOLDOWN_DISGUSTED_FROM_OBJECT: 'CommonBuffId' = 141678 + REACTION_COOLDOWN_SHOCKED_FROM_OBJECT: 'CommonBuffId' = 141677 + REACTION_EXIT_WATCH_TV: 'CommonBuffId' = 130305 + READ_ANGRY_LOW: 'CommonBuffId' = 12565 + READ_BORING_LOW: 'CommonBuffId' = 12566 + READ_CAMPING_HAPPY: 'CommonBuffId' = 109380 + READ_CONFIDENT_LOW: 'CommonBuffId' = 12567 + READ_FLIRTY_LOW: 'CommonBuffId' = 12568 + READ_FOCUSED_LOW: 'CommonBuffId' = 12569 + READ_HAPPY_LOW: 'CommonBuffId' = 12570 + READ_INSPIRED_LOW: 'CommonBuffId' = 12571 + READ_KIDS_BOOK_HATES_CHILDREN: 'CommonBuffId' = 100439 + READ_PLAYFUL_DIRTY: 'CommonBuffId' = 12572 + READ_PLAYFUL_LOW: 'CommonBuffId' = 12573 + READ_SAD_LOW: 'CommonBuffId' = 12574 + READ_SKILL_TOO_EASY: 'CommonBuffId' = 12575 + READ_SKILL_TOO_HARD: 'CommonBuffId' = 12576 + READ_TO_CHILDREN_HIDDEN: 'CommonBuffId' = 328766 + REAPER_PLEADED_TO: 'CommonBuffId' = 37235 + RECENTLY_PREPARED_FOOD_HIDDEN: 'CommonBuffId' = 149760 + RECENTLY_SURVEYED: 'CommonBuffId' = 177627 + RECENT_STARGAZE: 'CommonBuffId' = 181095 + RECREATION_TABLE_FINISHED_PUZZLE_MISSING_PIECE: 'CommonBuffId' = 317698 + RECREATION_TABLE_PUZZLES_BORED: 'CommonBuffId' = 308438 + RECREATION_TABLE_PUZZLES_FINISHED_PUZZLE: 'CommonBuffId' = 308437 + RECREATION_TABLE_PUZZLES_OTHER_SMASHED: 'CommonBuffId' = 308571 + RECREATION_TABLE_PUZZLES_PIECE_OUT: 'CommonBuffId' = 308439 + RECREATION_TABLE_PUZZLES_PILE_BACKUP: 'CommonBuffId' = 318759 + RECREATION_TABLE_PUZZLES_REPLACE_FINAL_PIECE: 'CommonBuffId' = 308440 + RECREATION_TABLE_PUZZLES_SMASHED: 'CommonBuffId' = 308572 + RECREATION_TABLE_PUZZLES_SMASHED_TIMEOUT_HIDDEN: 'CommonBuffId' = 332100 + RECREATION_TABLE_PUZZLES_STEAL_PIECE: 'CommonBuffId' = 318799 + RECREATION_TABLE_SIMBLES_DOMINOES_LOSE: 'CommonBuffId' = 309428 + RECREATION_TABLE_SIMBLES_DOMINOES_PRACTICE_TEXT_TEST: 'CommonBuffId' = 330697 + RECREATION_TABLE_SIMBLES_DOMINOES_TRAY_BACKUP: 'CommonBuffId' = 318760 + RECREATION_TABLE_SIMBLES_DOMINOES_WIN: 'CommonBuffId' = 309427 + REGIONAL_GREETING_REGIONALTRAIT: 'CommonBuffId' = 339032 + REGION_CAMPING_FOREST: 'CommonBuffId' = 104835 + REGION_GENERIC: 'CommonBuffId' = 251292 + REGION_GENERIC_ALIEN_WORLD: 'CommonBuffId' = 252278 + REGION_GENERIC_BAY_AREA: 'CommonBuffId' = 302933 + REGION_GENERIC_COTTAGE_WORLD: 'CommonBuffId' = 269827 + REGION_GENERIC_DESTINATION: 'CommonBuffId' = 252222 + REGION_GENERIC_WEDDING_WORLD: 'CommonBuffId' = 285873 + REGION_VACATION_HOMESICK: 'CommonBuffId' = 251305 + REGION_VENUE_AT_PARK: 'CommonBuffId' = 324092 + REJECTED_BY_LOVER: 'CommonBuffId' = 100140 + REJECTED_PROPOSAL: 'CommonBuffId' = 98081 + RELATIONSHIP_APPROPRIATENESS_FRIENDS: 'CommonBuffId' = 75272 + RELATIONSHIP_APPROPRIATENESS_LOVERS: 'CommonBuffId' = 75274 + RELATIONSHIP_BROKEN_UP_FRIENDS_HIDDEN: 'CommonBuffId' = 289781 + RELATIONSHIP_BROKE_UP_ANGRY: 'CommonBuffId' = 77253 + RELATIONSHIP_BROKE_UP_GLOOMY_TRAIT: 'CommonBuffId' = 77265 + RELATIONSHIP_BROKE_UP_SAD: 'CommonBuffId' = 77249 + RELATIONSHIP_COUNSELING_COOLDOWN_HIDDEN: 'CommonBuffId' = 375606 + RELATIONSHIP_COUNSELING_GOAL_OF_ATTRACTION: 'CommonBuffId' = 375216 + RELATIONSHIP_COUNSELING_GOAL_OF_PERFECT_DATES: 'CommonBuffId' = 375218 + RELATIONSHIP_COUNSELING_GOAL_OF_ROMANTIC_IMPROVEMENT: 'CommonBuffId' = 375217 + RELATIONSHIP_COUNSELING_GOAL_OF_TRYING_SOMETHING_NEW: 'CommonBuffId' = 375219 + RELATIONSHIP_COUNSELING_IN_RELATIONSHIP_COUNSELING_HIDDEN: 'CommonBuffId' = 375140 + RELATIONSHIP_COUNSELING_IN_THERAPY: 'CommonBuffId' = 375222 + RELATIONSHIP_COUNSELING_I_SAID_IM_OK: 'CommonBuffId' = 375215 + RELATIONSHIP_COUNSELING_NEEDS_MORE_THERAPY: 'CommonBuffId' = 375220 + RELATIONSHIP_COUNSELING_THERAPY_BLUES: 'CommonBuffId' = 375223 + RELATIONSHIP_COUNSELING_THERAPY_IS_A_SCAM: 'CommonBuffId' = 375221 + RELATIONSHIP_COUNSELING_THEY_THINK_IM_NUTS: 'CommonBuffId' = 375144 + RELATIONSHIP_COUNSELING_WE_NEED_THERAPY: 'CommonBuffId' = 375143 + RELATIONSHIP_COUNSELING_WINNING_AT_THERAPY: 'CommonBuffId' = 375214 + RELATIONSHIP_EXPECTATIONS_CHANGE_OUTLOOK_COOLDOWN_HIDDEN: 'CommonBuffId' = 364923 + RELATIONSHIP_GOT_DIVORCED: 'CommonBuffId' = 32616 + RELATIONSHIP_GOT_ENGAGED: 'CommonBuffId' = 32615 + RELATIONSHIP_GOT_WIDOW: 'CommonBuffId' = 102085 + RELATIONSHIP_GOT_WIDOWER: 'CommonBuffId' = 102921 + RELATIONSHIP_HAD_WEDDING: 'CommonBuffId' = 12587 + RELATIONSHIP_NEW_BFF: 'CommonBuffId' = 77196 + RELATIONSHIP_NEW_ENEMY: 'CommonBuffId' = 77194 + RELATIONSHIP_NEW_ENEMY_EVIL: 'CommonBuffId' = 97373 + RELATIONSHIP_NEW_FRIEND: 'CommonBuffId' = 97650 + RELATIONSHIP_NEW_PARTNER: 'CommonBuffId' = 98092 + RELATIONSHIP_PROMISED: 'CommonBuffId' = 99474 + RELATIONSHIP_RENEWED_VOWS: 'CommonBuffId' = 99618 + RELATIONSHIP_RENEW_VOWS_COOLDOWN: 'CommonBuffId' = 97281 + RELATIONSHIP_SATISFACTION_ITS_COMPLICATED: 'CommonBuffId' = 364561 + RELATIONSHIP_SATISFACTION_MUTUALLY_DISSATISFIED: 'CommonBuffId' = 364560 + RELATIONSHIP_SATISFACTION_MUTUALLY_SATISFIED: 'CommonBuffId' = 364559 + RELATIONSHIP_SATISFACTION_REL_BIT_1_VERY_UNSATISFIED: 'CommonBuffId' = 364007 + RELATIONSHIP_SATISFACTION_REL_BIT_2_UNSATISFIED: 'CommonBuffId' = 364008 + RELATIONSHIP_SATISFACTION_REL_BIT_4_SATISFIED: 'CommonBuffId' = 364009 + RELATIONSHIP_SATISFACTION_REL_BIT_5_VERY_SATISIFED: 'CommonBuffId' = 364010 + RELATIONSHIP_SATISFACTION_TOTO_TNS_INFO_DELAY_HIDDEN: 'CommonBuffId' = 377156 + RELATIONSHIP_TODDLER_CAREGIVER: 'CommonBuffId' = 146494 + RELATIONSHIP_TODDLER_CAREGIVER_AUTONOMY: 'CommonBuffId' = 333126 + RELATIONSHIP_VERY_APPROPRIATE: 'CommonBuffId' = 74424 + RELATIONSHIP_WATCHED_WEDDING_HAPPY: 'CommonBuffId' = 12604 + RELATIONSHIP_WEDDING_CHEER_FAIL: 'CommonBuffId' = 12606 + RELATIONSHIP_WEDDING_CHEER_SUCCESS: 'CommonBuffId' = 12607 + RELATIONSHIP_WEDDING_DODGED_A_BULLET: 'CommonBuffId' = 12608 + RELATIONSHIP_WEDDING_HECKLE_FAIL: 'CommonBuffId' = 12609 + RELATIONSHIP_WEDDING_HECKLE_SUCCESS: 'CommonBuffId' = 12610 + RELATIONSHIP_WEDDING_HECKLE_SUCCESS_TARGET: 'CommonBuffId' = 12611 + RELATIONSHIP_WEDDING_LEFT_AT_THE_ALTAR: 'CommonBuffId' = 12612 + RELAXED_IN_BED: 'CommonBuffId' = 12613 + REPOMAN_CANT_REPO_ME: 'CommonBuffId' = 235069 + REPOMAN_INCREASE_FAILURE_CHANCE: 'CommonBuffId' = 235077 + REPOMAN_LOCKOUT_ALWAYS_FAIL: 'CommonBuffId' = 235061 + REPOMAN_LOCKOUT_APPEAL_TO_HUMANITY: 'CommonBuffId' = 235075 + REPOMAN_LOCKOUT_BRIBE: 'CommonBuffId' = 235078 + REPOMAN_LOCKOUT_FIGHT_THE_MAN: 'CommonBuffId' = 235074 + REPOMAN_REPO_BEAT_DOWN: 'CommonBuffId' = 235071 + REPOMAN_STUFF_TAKEN: 'CommonBuffId' = 241177 + REPOMAN_TAKE_OBJECT_TNS_COOLDOWN: 'CommonBuffId' = 360523 + REPO_OCCURRED: 'CommonBuffId' = 228341 + REPUTATION_HAS_BEEN_RANK_0: 'CommonBuffId' = 202632 + REPUTATION_HAS_BEEN_RANK_1: 'CommonBuffId' = 202680 + REPUTATION_HAS_BEEN_RANK_2: 'CommonBuffId' = 202681 + REPUTATION_HAS_BEEN_RANK_3: 'CommonBuffId' = 202682 + REPUTATION_HAS_BEEN_RANK_4: 'CommonBuffId' = 202683 + REPUTATION_HAS_BEEN_RANK_5: 'CommonBuffId' = 202684 + REPUTATION_HAS_BEEN_RANK_6: 'CommonBuffId' = 202685 + REPUTATION_PRISTINE_FRIENDSHIP: 'CommonBuffId' = 196112 + REPUTATION_SEEN: 'CommonBuffId' = 197339 + REPUTATION_TERRIBLE_FRIENDSHIP: 'CommonBuffId' = 202783 + REQUIRED_INGREDIENTS_HIDDEN: 'CommonBuffId' = 258830 + REQUIRED_INGREDIENTS_SELF_SUSTAINING: 'CommonBuffId' = 263862 + RESEARCHED_COOKING_TECHNIQUE: 'CommonBuffId' = 28605 + RESEARCHED_GARDENING: 'CommonBuffId' = 35943 + RESEARCHED_GUITAR: 'CommonBuffId' = 34497 + RESEARCHED_PIANO: 'CommonBuffId' = 34499 + RESEARCHED_VIOLIN: 'CommonBuffId' = 34498 + RESEARCH_MACHINE_HIDDEN_RISKY: 'CommonBuffId' = 228202 + RESEARCH_MACHINE_MENTALLY_DRAINED: 'CommonBuffId' = 228197 + RESEARCH_MACHINE_WELL_RESEARCHED: 'CommonBuffId' = 227545 + RESOLUTIONS_BARELY_MADE_IT: 'CommonBuffId' = 187826 + RESOLUTIONS_COMPLETE_BETTER_STUDENT: 'CommonBuffId' = 187838 + RESOLUTIONS_COMPLETE_COMPLETE_ASPIRATION_MILESTONE: 'CommonBuffId' = 187830 + RESOLUTIONS_COMPLETE_GET_BOYFRIEND_GIRLFRIEND: 'CommonBuffId' = 187834 + RESOLUTIONS_COMPLETE_GET_FIT: 'CommonBuffId' = 187833 + RESOLUTIONS_COMPLETE_GET_MORE_FOLLOWERS: 'CommonBuffId' = 187835 + RESOLUTIONS_COMPLETE_GET_PROMOTED: 'CommonBuffId' = 187831 + RESOLUTIONS_COMPLETE_GET_PROMOTED_SCOUTS: 'CommonBuffId' = 187837 + RESOLUTIONS_COMPLETE_LOSE_WEIGHT: 'CommonBuffId' = 187832 + RESOLUTIONS_COMPLETE_RAISE_SKILL: 'CommonBuffId' = 187836 + RESOLUTIONS_COMPLETE_WRITE_BOOK: 'CommonBuffId' = 187839 + RESOLUTIONS_FAILED_RESOLUTION: 'CommonBuffId' = 187828 + RESOLUTIONS_HIDDEN_COOLDOWN: 'CommonBuffId' = 186707 + RESOLUTIONS_HIDDEN_HAS_RESOLUTION: 'CommonBuffId' = 188005 + RESOLUTIONS_RESOLUTIONS_DONT_MATTER: 'CommonBuffId' = 187827 + RESOLUTIONS_RESOLUTION_DUE: 'CommonBuffId' = 187825 + RESOLUTION_MADE: 'CommonBuffId' = 186704 + RESTAURANTS_DINER_BASIC_ARRIVAL: 'CommonBuffId' = 132493 + RESTAURANTS_DINER_BASIC_CHECK_IN: 'CommonBuffId' = 132578 + RESTAURANTS_DINER_BASIC_EAT_FOOD: 'CommonBuffId' = 139028 + RESTAURANTS_DINER_BASIC_EAT_FOOD_CRITIC: 'CommonBuffId' = 141470 + RESTAURANTS_DINER_BASIC_ORDER_FROM_CHEF: 'CommonBuffId' = 132624 + RESTAURANTS_DINER_BASIC_POST_PLACE_ORDER: 'CommonBuffId' = 133233 + RESTAURANTS_DINER_BASIC_PREPARE_TO_LEAVE: 'CommonBuffId' = 133350 + RESTAURANTS_DINER_BASIC_PREPARE_TO_LEAVE_CRITIC: 'CommonBuffId' = 143683 + RESTAURANTS_DINER_BASIC_PRE_PLACE_ORDER: 'CommonBuffId' = 132667 + RESTAURANTS_DINER_BASIC_PRE_ROLL_ORDER: 'CommonBuffId' = 132860 + RESTAURANTS_DINER_BASIC_WAIT_FOR_FOOD: 'CommonBuffId' = 133109 + RESTAURANTS_DINER_BASIC_WAIT_FOR_FOOD_FROM_WAIT_STAFF: 'CommonBuffId' = 134378 + RESTAURANTS_DINER_BASIC_WAIT_FOR_TABLE: 'CommonBuffId' = 132654 + RESTAURANTS_DINER_HAPPY_DATE_FLIRTY: 'CommonBuffId' = 132702 + RESTAURANTS_DINER_PLAYER_PRE_PLACE_ORDER: 'CommonBuffId' = 133218 + RESTAURANTS_DINER_PLAYER_WAIT_FOR_FOOD_FROM_WAIT_STAFF: 'CommonBuffId' = 134375 + RESTAURANTS_DINER_WAIT_FOR_FOOD_STOP_DOING_STUFF: 'CommonBuffId' = 133110 + RESTAURANTS_FLIRTY_BREAKFAST: 'CommonBuffId' = 133358 + RESTAURANTS_FLIRTY_DINNER: 'CommonBuffId' = 133360 + RESTAURANTS_FLIRTY_LUNCH: 'CommonBuffId' = 133359 + RESTAURANTS_HAPPY_BREAKFAST: 'CommonBuffId' = 133355 + RESTAURANTS_HAPPY_DINNER: 'CommonBuffId' = 133357 + RESTAURANTS_HAPPY_LUNCH: 'CommonBuffId' = 133356 + RESTAURANTS_HIDDEN_FLIRTY_BREAKFAST: 'CommonBuffId' = 133602 + RESTAURANTS_HIDDEN_FLIRTY_DINNER: 'CommonBuffId' = 133604 + RESTAURANTS_HIDDEN_FLIRTY_LUNCH: 'CommonBuffId' = 133603 + RESTAURANTS_HIDDEN_HAPPY_BREAKFAST: 'CommonBuffId' = 133361 + RESTAURANTS_HIDDEN_HAPPY_DINNER: 'CommonBuffId' = 133601 + RESTAURANTS_HIDDEN_HAPPY_LUNCH: 'CommonBuffId' = 133600 + RESTAURANTS_HOST_ARRIVAL: 'CommonBuffId' = 132468 + RESTAURANTS_HOST_IDLE_AT_STATION: 'CommonBuffId' = 132576 + RESTAURANTS_HOST_SHOW_TO_TABLE: 'CommonBuffId' = 135131 + RESTAURANTS_RESTAURANT_AT_WORK: 'CommonBuffId' = 144763 + RESTAURANTS_WAITSTAFF_CLEAN: 'CommonBuffId' = 135847 + RESTAURANTS_WAITSTAFF_IDLE: 'CommonBuffId' = 133363 + RESTAURANT_BANNED: 'CommonBuffId' = 132849 + RETAIL_ADD_REL_BIT_EMPLOYEES_WONT_TALK_TO_LOT_OWNERS: 'CommonBuffId' = 117021 + RETAIL_CHECKOUT_TIMER_FREEZE: 'CommonBuffId' = 112180 + RETAIL_CHECK_ON_EMPLOYEE_COOLDOWN: 'CommonBuffId' = 116664 + RETAIL_CUSTOMER_START_WAITING_FOR_CHECKOUT: 'CommonBuffId' = 112198 + RETAIL_EMPLOYEE_CHANCE_TO_SLACK: 'CommonBuffId' = 115969 + RETAIL_EMPLOYEE_LEAVING_DUE_TO_TIME: 'CommonBuffId' = 116599 + RETAIL_EMPLOYEE_SATISFACTION_MODIFIERS_PAY_0_PAID_ADEQUATELY: 'CommonBuffId' = 112026 + RETAIL_EMPLOYEE_SATISFACTION_MODIFIERS_PAY_MINU_S1_UNDERPAID: 'CommonBuffId' = 112022 + RETAIL_EMPLOYEE_SATISFACTION_MODIFIERS_PAY_MINU_S2_VERY_UNDERPAID: 'CommonBuffId' = 112023 + RETAIL_EMPLOYEE_SATISFACTION_MODIFIERS_PAY_MINU_S3_SEVERELY_UNDERPAID: 'CommonBuffId' = 112024 + RETAIL_EMPLOYEE_SATISFACTION_MODIFIERS_PAY_MINU_S4_GROSSLY_UNDERPAID: 'CommonBuffId' = 112025 + RETAIL_EMPLOYEE_SATISFACTION_MODIFIERS_PAY_PLU_S1_OVERPAID: 'CommonBuffId' = 112027 + RETAIL_EMPLOYEE_SATISFACTION_MODIFIERS_PAY_PLU_S2_VERY_OVERPAID: 'CommonBuffId' = 112028 + RETAIL_EMPLOYEE_SATISFACTION_MODIFIERS_PAY_PLU_S3_SEVERELY_OVERPAID: 'CommonBuffId' = 112021 + RETAIL_EMPLOYEE_SATISFACTION_MODIFIERS_PAY_PLU_S4_GROSSLY_OVERPAID: 'CommonBuffId' = 112020 + RETAIL_EMPLOYEE_SATISFACTION_STATES_NEUTRAL: 'CommonBuffId' = 112068 + RETAIL_EMPLOYEE_SATISFACTION_STATES_SATISFIED: 'CommonBuffId' = 112070 + RETAIL_EMPLOYEE_SATISFACTION_STATES_UNSATISFIED: 'CommonBuffId' = 112071 + RETAIL_EMPLOYEE_SATISFACTION_STATES_VERY_SATISFIED: 'CommonBuffId' = 112069 + RETAIL_EMPLOYEE_SATISFACTION_STATES_VERY_UNSATISFIED: 'CommonBuffId' = 112072 + RETAIL_EMPLOYEE_SUPPRESS_FRONT_PAGE: 'CommonBuffId' = 115932 + RETAIL_LAUGH_AT_BROKEN_SIGN_COOLDOWN: 'CommonBuffId' = 110969 + RETAIL_PRAISE_EMPLOYEE_COOLDOWN: 'CommonBuffId' = 115328 + RETAIL_RECENT_PURCHASE: 'CommonBuffId' = 112137 + RETAIL_SURE_SALE_COOLDOWN: 'CommonBuffId' = 112363 + RETAIL_TIRED_OF_WAITING: 'CommonBuffId' = 112135 + RETAIL_TREND_SETTER: 'CommonBuffId' = 114680 + RETAIL_WAIT_TO_PURCHASE: 'CommonBuffId' = 112134 + RETAIL_WHAT_DID_IT_SPELL: 'CommonBuffId' = 110971 + RETURNED_FROM_ABDUCTION_ANGRY: 'CommonBuffId' = 114922 + RETURNED_FROM_ABDUCTION_DAZED: 'CommonBuffId' = 114921 + RETURNED_FROM_ABDUCTION_FOCUSED: 'CommonBuffId' = 114923 + REVEALED_DEEP_SECRET: 'CommonBuffId' = 77069 + RICHLY_SCENTED: 'CommonBuffId' = 118505 + RILED_UP_HOTHEADED: 'CommonBuffId' = 27745 + RILED_UP_HOTHEADED_PRANK: 'CommonBuffId' = 258442 + RILED_UP_HOTHEADED_WORK: 'CommonBuffId' = 258443 + RILED_UP_TARGET: 'CommonBuffId' = 77297 + ROBOTICS_ARM_EQUIPPED_BEIGE_WHITE: 'CommonBuffId' = 222151 + ROBOTICS_ARM_EQUIPPED_BLACK_BLUE: 'CommonBuffId' = 228984 + ROBOTICS_ARM_EQUIPPED_BLUE_RED: 'CommonBuffId' = 228985 + ROBOTICS_ARM_EQUIPPED_GRAY_BROWN: 'CommonBuffId' = 228986 + ROBOTICS_ARM_EQUIPPED_GREEN_BROWN: 'CommonBuffId' = 228987 + ROBOTICS_ARM_EQUIPPED_RED_GREEN: 'CommonBuffId' = 228988 + ROBOTICS_ARM_EQUIPPED_WHITE_COPPER: 'CommonBuffId' = 228989 + ROBOTICS_TABLE_ITS_ALIVE: 'CommonBuffId' = 223733 + ROBOTICS_TABLE_SORE_THUMB: 'CommonBuffId' = 222028 + ROBOT_BUILDING_EXHIBITION_BUILD_BOTS_COOLDOWN: 'CommonBuffId' = 225728 + ROCKET_SHIP_ESCAPE_POD_CHEWED_CABLES: 'CommonBuffId' = 77258 + ROCKET_SHIP_GALACTIC_MOVERS_HELPED_MOVE: 'CommonBuffId' = 77261 + ROCKET_SHIP_GALACTIC_MOVERS_NOT_ENOUGH_SPACE: 'CommonBuffId' = 77262 + ROCKET_SHIP_LOST_TREASURE_ALIEN_REPAIRS: 'CommonBuffId' = 77308 + ROCKET_SHIP_LOST_TREASURE_LOST_TREASURE: 'CommonBuffId' = 77307 + ROCKET_SHIP_OVERLORD_FLASHLIGHT: 'CommonBuffId' = 77208 + ROCKET_SHIP_OVERLORD_LEARNED_NOTHING: 'CommonBuffId' = 77214 + ROCKET_SHIP_OVERLORD_OUSTED: 'CommonBuffId' = 77210 + ROCKET_SHIP_OVERLORD_PETTY_ALIENS: 'CommonBuffId' = 77215 + ROCKET_SHIP_OVERLORD_PROMISED_LAND: 'CommonBuffId' = 77209 + ROCKET_SHIP_OVERLORD_RAMIFICATIONS_OF_POWER: 'CommonBuffId' = 77207 + ROCKET_SHIP_OVERLORD_SMOOSHED_REBELLION: 'CommonBuffId' = 77212 + ROCKET_SHIP_OVERLORD_TURNED_BENEVOLENT: 'CommonBuffId' = 77213 + ROCKET_SHIP_POOKA_POO_CALLED_THE_RANGERS: 'CommonBuffId' = 77268 + ROCKET_SHIP_POOKA_POO_FAILED_RESCUE: 'CommonBuffId' = 77270 + ROCKET_SHIP_POOKA_POO_RESCUE_COMPLETE: 'CommonBuffId' = 77269 + ROCKET_SHIP_SPACE_CRAZY_FORGOTTEN_OBJECTIVE: 'CommonBuffId' = 77290 + ROCKET_SHIP_SPACE_CRAZY_IRRATIONAL_ACTIONS: 'CommonBuffId' = 77284 + ROCKET_SHIP_SPACE_CRAZY_MADNESS_CURE: 'CommonBuffId' = 77285 + ROCKET_SHIP_SPACE_CRAZY_RECOVERY_FROM_MADNESS: 'CommonBuffId' = 77283 + ROCKET_SHIP_SPACE_CRAZY_SPACE_JUNK: 'CommonBuffId' = 77286 + ROCKET_SHIP_SPACE_CRAZY_SPACE_MADNESS: 'CommonBuffId' = 77282 + ROCKET_SHIP_SPACE_CRAZY_WAINING_SPACE_MADNESS: 'CommonBuffId' = 77287 + ROCKET_SHIP_STOWAWAY_ALIEN_NAPPING: 'CommonBuffId' = 77303 + ROCKET_SHIP_STOWAWAY_CUFFED_BY_STOWAWAY: 'CommonBuffId' = 77305 + ROCK_CLIMBING_GEAR_REPAIR_COOLDOWN: 'CommonBuffId' = 252530 + ROCK_CLIMBING_GEAR_WEARING_GEAR: 'CommonBuffId' = 247332 + ROLE_ALIEN_VISIT_ALIEN: 'CommonBuffId' = 114182 + ROLE_APM_MAILBOX_VISIT: 'CommonBuffId' = 350976 + ROLE_APPROPRIATENESS_ALIEN_VISIT_ALIEN: 'CommonBuffId' = 114149 + ROLE_APPROPRIATENESS_ALLOW_BARTENDING: 'CommonBuffId' = 35465 + ROLE_APPROPRIATENESS_ALLOW_COOKING: 'CommonBuffId' = 35470 + ROLE_APPROPRIATENESS_ALLOW_SLEEPING: 'CommonBuffId' = 35478 + ROLE_APPROPRIATENESS_AVOID_SITTING: 'CommonBuffId' = 201512 + ROLE_APPROPRIATENESS_BABY_BIRTH_HOSPITAL_NO_LABOR: 'CommonBuffId' = 112186 + ROLE_APPROPRIATENESS_CELEBRITY: 'CommonBuffId' = 196754 + ROLE_APPROPRIATENESS_COWORKER: 'CommonBuffId' = 108788 + ROLE_APPROPRIATENESS_COWORKER_FRONT_DESK_BADGE_IN: 'CommonBuffId' = 115777 + ROLE_APPROPRIATENESS_COWORKER_LUNCH: 'CommonBuffId' = 108789 + ROLE_APPROPRIATENESS_COWORKER_SCIENTIST_ALLOW: 'CommonBuffId' = 108846 + ROLE_APPROPRIATENESS_DOCTOR_CAREER_AWAY_EVENT_PATIENT: 'CommonBuffId' = 115633 + ROLE_APPROPRIATENESS_DOCTOR_CAREER_PATIENT: 'CommonBuffId' = 111788 + ROLE_APPROPRIATENESS_DOCTOR_CAREER_PLAYER: 'CommonBuffId' = 115830 + ROLE_APPROPRIATENESS_NO_BARTENDING: 'CommonBuffId' = 134456 + ROLE_APPROPRIATENESS_NO_BATHING: 'CommonBuffId' = 35368 + ROLE_APPROPRIATENESS_NO_CAKE: 'CommonBuffId' = 35369 + ROLE_APPROPRIATENESS_NO_CALL_TO_MEAL: 'CommonBuffId' = 101052 + ROLE_APPROPRIATENESS_NO_CLEANING: 'CommonBuffId' = 35370 + ROLE_APPROPRIATENESS_NO_COMPUTER: 'CommonBuffId' = 134457 + ROLE_APPROPRIATENESS_NO_COOKING: 'CommonBuffId' = 35365 + ROLE_APPROPRIATENESS_NO_DANCING: 'CommonBuffId' = 129759 + ROLE_APPROPRIATENESS_NO_EATING: 'CommonBuffId' = 35372 + ROLE_APPROPRIATENESS_NO_GRAB_SNACK: 'CommonBuffId' = 134458 + ROLE_APPROPRIATENESS_NO_PERFORMANCE_TIPPING: 'CommonBuffId' = 198707 + ROLE_APPROPRIATENESS_NO_PHONE: 'CommonBuffId' = 142027 + ROLE_APPROPRIATENESS_NO_PLAYING: 'CommonBuffId' = 137592 + ROLE_APPROPRIATENESS_NO_PLAYING_INSTRUMENTS: 'CommonBuffId' = 198708 + ROLE_APPROPRIATENESS_NO_READING: 'CommonBuffId' = 137593 + ROLE_APPROPRIATENESS_NO_READ_BOOKS: 'CommonBuffId' = 108838 + ROLE_APPROPRIATENESS_NO_SLEEPING: 'CommonBuffId' = 35390 + ROLE_APPROPRIATENESS_NO_SNOW_SHOVELING: 'CommonBuffId' = 250734 + ROLE_APPROPRIATENESS_NO_STEREO: 'CommonBuffId' = 35391 + ROLE_APPROPRIATENESS_NO_TOUCHING: 'CommonBuffId' = 132840 + ROLE_APPROPRIATENESS_NO_TV: 'CommonBuffId' = 155063 + ROLE_APPROPRIATENESS_NO_TV: 'CommonBuffId' = 108749 + ROLE_APPROPRIATENESS_NO_WORKOUT_BG: 'CommonBuffId' = 133051 + ROLE_APPROPRIATENESS_PLAYING_TRIVIA_BOX: 'CommonBuffId' = 386635 + ROLE_APPROPRIATENESS_SCIENTIST_FRONT_DESK: 'CommonBuffId' = 115893 + ROLE_APPROPRIATENESS_VISITOR: 'CommonBuffId' = 130085 + ROLE_BABY_SHOWER_GUEST: 'CommonBuffId' = 301105 + ROLE_BABY_SHOWER_GUEST_NPC: 'CommonBuffId' = 308982 + ROLE_BABY_SHOWER_HOST: 'CommonBuffId' = 308220 + ROLE_BARTENDER: 'CommonBuffId' = 12616 + ROLE_BAR_DRINKER: 'CommonBuffId' = 101021 + ROLE_BATUU_CONTROL_PANEL_SURVEILLANCE_ALARM_RESPONDER: 'CommonBuffId' = 240004 + ROLE_BE_WOKEN_UP: 'CommonBuffId' = 203046 + ROLE_BOWLING_VENUE_BOWLER: 'CommonBuffId' = 160126 + ROLE_BOWLING_VENUE_GROUP_1: 'CommonBuffId' = 161079 + ROLE_BOWLING_VENUE_GROUP_2: 'CommonBuffId' = 161080 + ROLE_BOWLING_VENUE_GROUP_3: 'CommonBuffId' = 161110 + ROLE_BOWLING_VENUE_GROUP_4: 'CommonBuffId' = 161111 + ROLE_BUTLER_BACK_TO_WORK: 'CommonBuffId' = 148769 + ROLE_BUTLER_BEEN_PRAISED: 'CommonBuffId' = 146340 + ROLE_BUTLER_BEEN_REPRIMANDED: 'CommonBuffId' = 146339 + ROLE_BUTLER_CAUGHT_NOT_WORKING: 'CommonBuffId' = 147258 + ROLE_BUTLER_DEFAULT: 'CommonBuffId' = 150512 + ROLE_BUTLER_DONT_COOK: 'CommonBuffId' = 151548 + ROLE_BUTLER_GARDENER_ROLE_NPC: 'CommonBuffId' = 150072 + ROLE_BUTLER_GIVEN_ORDER: 'CommonBuffId' = 152371 + ROLE_BUTLER_INVITE_GUESTS_ALWAYS_INVITE: 'CommonBuffId' = 147314 + ROLE_BUTLER_INVITE_GUESTS_NEVER_INVITE: 'CommonBuffId' = 147315 + ROLE_BUTLER_MAID_ROLE_NPC: 'CommonBuffId' = 150073 + ROLE_BUTLER_NANNY_ROLE_NPC: 'CommonBuffId' = 150074 + ROLE_BUTLER_NO_QUIRKY_ACTIONS: 'CommonBuffId' = 148740 + ROLE_BUTLER_NPC: 'CommonBuffId' = 145405 + ROLE_BUTLER_ORDER_CHECK_ON_MINOR: 'CommonBuffId' = 152549 + ROLE_BUTLER_REPAIRMAN_ROLE_NPC: 'CommonBuffId' = 150075 + ROLE_BUTLER_SITUATION_REPRIMANDED_BUTLER: 'CommonBuffId' = 149581 + ROLE_BUTLER_STATES_CARE_FOR_CHILDREN: 'CommonBuffId' = 152301 + ROLE_BUTLER_STATES_CLEAN: 'CommonBuffId' = 152305 + ROLE_BUTLER_STATES_DONT_CARE_FOR_CHILDREN: 'CommonBuffId' = 152302 + ROLE_BUTLER_STATES_DONT_CLEAN: 'CommonBuffId' = 152306 + ROLE_BUTLER_STATES_DONT_GARDEN: 'CommonBuffId' = 152304 + ROLE_BUTLER_STATES_DONT_REPAIR: 'CommonBuffId' = 152300 + ROLE_BUTLER_STATES_GARDEN: 'CommonBuffId' = 152303 + ROLE_BUTLER_STATES_REPAIR: 'CommonBuffId' = 152299 + ROLE_CALL_TO_MEAL_POLITE_HUNGER: 'CommonBuffId' = 98867 + ROLE_CANDLE_CRAFTER: 'CommonBuffId' = 232826 + ROLE_CANDLE_CRAFTER_CRAFTING_TIMEOUT: 'CommonBuffId' = 237996 + ROLE_CELEBRITY_CHANCE_WEAR_CRYSTAL_HELMET: 'CommonBuffId' = 198661 + ROLE_CELEBRITY_PLAY_GUITAR: 'CommonBuffId' = 202301 + ROLE_CELEBRITY_WALK_STYLE_APPLY: 'CommonBuffId' = 204573 + ROLE_CELEBRITY_WEAR_CRYSTAL_HELMET: 'CommonBuffId' = 198657 + ROLE_CHEF_PAN: 'CommonBuffId' = 139839 + ROLE_CHEF_POT: 'CommonBuffId' = 139840 + ROLE_CHEF_PREP: 'CommonBuffId' = 139841 + ROLE_CHEF_SERVE: 'CommonBuffId' = 139842 + ROLE_CHILD_CREATOR: 'CommonBuffId' = 232834 + ROLE_COLLEGE_ORGANIZATION_BAR_NIGHT_ART_SOCIETY_MEET_UP_PARTICIPANT: 'CommonBuffId' = 226527 + ROLE_COLLEGE_ORGANIZATION_BAR_NIGHT_DEBATE: 'CommonBuffId' = 228921 + ROLE_COLLEGE_ORGANIZATION_BAR_NIGHT_GENERAL: 'CommonBuffId' = 228894 + ROLE_COLLEGE_ORGANIZATION_BAR_NIGHT_HONOR_SOCIETY_PARTICIPANT: 'CommonBuffId' = 226898 + ROLE_COLLEGE_ORGANIZATION_BAR_NIGHT_PARTY: 'CommonBuffId' = 228924 + ROLE_COLLEGE_ORGANIZATION_BAR_NIGHT_PRANK: 'CommonBuffId' = 228923 + ROLE_COLLEGE_ORGANIZATION_BAR_NIGHT_ROBOTICS: 'CommonBuffId' = 228922 + ROLE_COLLEGE_ORGANIZATION_DEBATE_AUDIENCE: 'CommonBuffId' = 224130 + ROLE_COLLEGE_ORGANIZATION_DEBATE_DEBATER: 'CommonBuffId' = 224144 + ROLE_COLLEGE_ORGANIZATION_DEBATE_DECLARE: 'CommonBuffId' = 225702 + ROLE_COLLEGE_ORGANIZATION_DEBATE_GATHER: 'CommonBuffId' = 224142 + ROLE_COLLEGE_ORGANIZATION_DEBATE_JUDGE: 'CommonBuffId' = 224128 + ROLE_COLLEGE_ORGANIZATION_DEBATE_PARTICIPANT: 'CommonBuffId' = 224129 + ROLE_COLLEGE_ORGANIZATION_DEBATE_PLAYER: 'CommonBuffId' = 227489 + ROLE_COLLEGE_ORGANIZATION_DEBATE_REFRESHMENTS: 'CommonBuffId' = 224131 + ROLE_COLLEGE_ORGANIZATION_EVENTS_DEBATE_PLAYER: 'CommonBuffId' = 227486 + ROLE_COLLEGE_ORGANIZATION_EVENTS_PAINTIN_IN_THE_PARK_MEMBER: 'CommonBuffId' = 223441 + ROLE_COLLEGE_ORGANIZATION_EVENTS_PAINTIN_IN_THE_PARK_MODEL: 'CommonBuffId' = 227366 + ROLE_COLLEGE_ORGANIZATION_EVENTS_PAINTIN_IN_THE_PARK_PLAYER: 'CommonBuffId' = 223362 + ROLE_COLLEGE_ORGANIZATION_EVENTS_ROBOTICS_EXHIBITION_GO_TO_EVENT: 'CommonBuffId' = 224463 + ROLE_COLLEGE_ORGANIZATION_EVENTS_ROBOTICS_EXHIBITION_HUMANOID_ROBOT: 'CommonBuffId' = 230053 + ROLE_COLLEGE_ORGANIZATION_EVENTS_ROBOTICS_EXHIBITION_JUDGE_POST_JUDGING: 'CommonBuffId' = 224049 + ROLE_COLLEGE_ORGANIZATION_EVENTS_ROBOTICS_EXHIBITION_JUDGE_PRE_JUDGING: 'CommonBuffId' = 224050 + ROLE_COLLEGE_ORGANIZATION_EVENTS_ROBOTICS_EXHIBITION_PARTICIPANT: 'CommonBuffId' = 224051 + ROLE_COLLEGE_ORGANIZATION_EVENTS_ROBOTICS_EXHIBITION_PLAYER: 'CommonBuffId' = 223153 + ROLE_COLLEGE_ORGANIZATION_EVENTS_ROBOT_BUILDING_SESSION_GO_TO_EVENT: 'CommonBuffId' = 225330 + ROLE_COLLEGE_ORGANIZATION_EVENTS_ROBOT_BUILDING_SESSION_PARTICIPANT: 'CommonBuffId' = 225329 + ROLE_COLLEGE_ORGANIZATION_EVENTS_ROBOT_BUILDING_SESSION_PLAYER: 'CommonBuffId' = 225331 + ROLE_COLLEGE_ORGANIZATION_EVENTS_SECRET_SOCIETY_JOIN_VISIT: 'CommonBuffId' = 222756 + ROLE_COLLEGE_ORGANIZATION_EVENTS_SI_ROBOTICS_SOCIETY: 'CommonBuffId' = 230663 + ROLE_COLLEGE_ORGANIZATION_SCHOOL_SPIRIT_MASCOT: 'CommonBuffId' = 210856 + ROLE_COLLEGE_ORGANIZATION_SECRET_SOCIETY_GO_TO_RITUAL: 'CommonBuffId' = 224430 + ROLE_COLLEGE_ORGANIZATION_SECRET_SOCIETY_RITUAL: 'CommonBuffId' = 221642 + ROLE_COLLEGE_ORGANIZATION_SECRET_SOCIETY_RITUAL_PLAYER_MEMBER: 'CommonBuffId' = 228552 + ROLE_COLLEGE_ORGANIZATION_SECRET_SOCIETY_RITUAL_PLAYER_NONMEMBER: 'CommonBuffId' = 228551 + ROLE_COLLEGE_ORGANIZATION_SECRET_SOCIETY_RITUAL_SOCIAL_MORE_MEMBER_ONLY: 'CommonBuffId' = 228550 + ROLE_COLLEGE_ORGANIZATION_STUDY_GROUP_MEMBER: 'CommonBuffId' = 210838 + ROLE_COLLEGE_ORGANIZATION_STUDY_GROUP_PLAYER: 'CommonBuffId' = 210859 + ROLE_COMMUNITY_BOARD_DEBATER: 'CommonBuffId' = 224292 + ROLE_COMMUNITY_CLOSENESS_COMPLAINT_ANGRY_SIM: 'CommonBuffId' = 233783 + ROLE_COMMUNITY_CLOSENESS_HANDY_NEIGHBOR_BE_HANDY: 'CommonBuffId' = 233782 + ROLE_COMMUNITY_CLOSENESS_HANGOUT: 'CommonBuffId' = 234294 + ROLE_COMMUNITY_CLOSENESS_INTRO_TO_CIVIC_POLICIES: 'CommonBuffId' = 238072 + ROLE_COMMUNITY_CLOSENESS_INTRO_TO_CIVIC_POLICIES_HANG_OUT: 'CommonBuffId' = 239729 + ROLE_COMMUNITY_CLOSENESS_KNOCK_TNS_SHOWN: 'CommonBuffId' = 239097 + ROLE_COMMUNITY_CLOSENESS_RANDOM_GIFT_GIVE_GIFT: 'CommonBuffId' = 233784 + ROLE_COMMUNITY_CLOSENESS_SPARE_RECYCLINGS_RECYCLE: 'CommonBuffId' = 233785 + ROLE_COMMUNITY_CLOSENESS_TRASH_HELPER_PICKUP_TRASH: 'CommonBuffId' = 233781 + ROLE_COMMUNITY_GARDEN: 'CommonBuffId' = 223963 + ROLE_COTTAGE_WORLD_NPC_CRITTER_TENDER_COOK: 'CommonBuffId' = 264768 + ROLE_COTTAGE_WORLD_NPC_CRITTER_TENDER_FORAGE: 'CommonBuffId' = 264767 + ROLE_COTTAGE_WORLD_NPC_CRITTER_TENDER_GARDEN: 'CommonBuffId' = 264766 + ROLE_COTTAGE_WORLD_NPC_CRITTER_TENDER_GO_HOME: 'CommonBuffId' = 269654 + ROLE_COTTAGE_WORLD_NPC_CRITTER_TENDER_INTERACT_WITH_CRITTERS: 'CommonBuffId' = 264769 + ROLE_COTTAGE_WORLD_NPC_CRITTER_TENDER_SIT: 'CommonBuffId' = 269643 + ROLE_COTTAGE_WORLD_NPC_GROCERY_DELIVERY: 'CommonBuffId' = 269815 + ROLE_COWORKER: 'CommonBuffId' = 108695 + ROLE_CRAFT_SALES_TABLE_VENDOR_JUNGLE: 'CommonBuffId' = 178017 + ROLE_CUSTOM_STATE_WEDDING_COUPLE_ARRIVAL: 'CommonBuffId' = 277825 + ROLE_CUSTOM_STATE_WEDDING_COUPLE_BOUQUET_GATHER: 'CommonBuffId' = 278015 + ROLE_CUSTOM_STATE_WEDDING_COUPLE_BOUQUET_TOSS: 'CommonBuffId' = 278016 + ROLE_CUSTOM_STATE_WEDDING_COUPLE_CAKE: 'CommonBuffId' = 277836 + ROLE_CUSTOM_STATE_WEDDING_COUPLE_CAKE_EAT: 'CommonBuffId' = 278017 + ROLE_CUSTOM_STATE_WEDDING_COUPLE_CAKE_GATHER: 'CommonBuffId' = 278018 + ROLE_CUSTOM_STATE_WEDDING_COUPLE_DANCE: 'CommonBuffId' = 278019 + ROLE_CUSTOM_STATE_WEDDING_COUPLE_DANCE_GATHER: 'CommonBuffId' = 278020 + ROLE_CUSTOM_STATE_WEDDING_COUPLE_DANCE_GATHER_DANCE_FLOOR: 'CommonBuffId' = 278021 + ROLE_CUSTOM_STATE_WEDDING_COUPLE_DESSERTS: 'CommonBuffId' = 285085 + ROLE_CUSTOM_STATE_WEDDING_COUPLE_MEAL: 'CommonBuffId' = 278022 + ROLE_CUSTOM_STATE_WEDDING_COUPLE_MINGLE: 'CommonBuffId' = 277813 + ROLE_CUSTOM_STATE_WEDDING_COUPLE_POST_CEREMONY: 'CommonBuffId' = 278023 + ROLE_CUSTOM_STATE_WEDDING_COUPLE_PROCESSIONAL: 'CommonBuffId' = 277837 + ROLE_CUSTOM_STATE_WEDDING_COUPLE_RECESSIONAL: 'CommonBuffId' = 277838 + ROLE_CUSTOM_STATE_WEDDING_COUPLE_RECESSIONAL_GATHER: 'CommonBuffId' = 278024 + ROLE_CUSTOM_STATE_WEDDING_COUPLE_SIT_DOWN: 'CommonBuffId' = 277833 + ROLE_CUSTOM_STATE_WEDDING_COUPLE_TOAST: 'CommonBuffId' = 278025 + ROLE_CUSTOM_STATE_WEDDING_COUPLE_TOAST_GATHER: 'CommonBuffId' = 278028 + ROLE_CUSTOM_STATE_WEDDING_COUPLE_VOWS: 'CommonBuffId' = 278027 + ROLE_CUSTOM_STATE_WEDDING_COUPLE_VOWS_SPEECH: 'CommonBuffId' = 278029 + ROLE_CUSTOM_STATE_WEDDING_COUPLE_VOWS_WITH_OFFICIANT: 'CommonBuffId' = 278030 + ROLE_CUSTOM_STATE_WEDDING_FLOWER_SPREADER_ARRIVAL: 'CommonBuffId' = 278031 + ROLE_CUSTOM_STATE_WEDDING_FLOWER_SPREADER_BOUQUET_GATHER: 'CommonBuffId' = 278032 + ROLE_CUSTOM_STATE_WEDDING_FLOWER_SPREADER_BOUQUET_TOSS: 'CommonBuffId' = 278041 + ROLE_CUSTOM_STATE_WEDDING_FLOWER_SPREADER_CAKE: 'CommonBuffId' = 278042 + ROLE_CUSTOM_STATE_WEDDING_FLOWER_SPREADER_CAKE_EAT: 'CommonBuffId' = 278043 + ROLE_CUSTOM_STATE_WEDDING_FLOWER_SPREADER_CAKE_GATHER: 'CommonBuffId' = 278044 + ROLE_CUSTOM_STATE_WEDDING_FLOWER_SPREADER_DANCE: 'CommonBuffId' = 278045 + ROLE_CUSTOM_STATE_WEDDING_FLOWER_SPREADER_DANCE_GATHER: 'CommonBuffId' = 278046 + ROLE_CUSTOM_STATE_WEDDING_FLOWER_SPREADER_DANCE_GATHER_DANCE_FLOOR: 'CommonBuffId' = 278047 + ROLE_CUSTOM_STATE_WEDDING_FLOWER_SPREADER_MEAL: 'CommonBuffId' = 278048 + ROLE_CUSTOM_STATE_WEDDING_FLOWER_SPREADER_MINGLE: 'CommonBuffId' = 277814 + ROLE_CUSTOM_STATE_WEDDING_FLOWER_SPREADER_POST_CEREMONY: 'CommonBuffId' = 278049 + ROLE_CUSTOM_STATE_WEDDING_FLOWER_SPREADER_PROCESSIONAL: 'CommonBuffId' = 278050 + ROLE_CUSTOM_STATE_WEDDING_FLOWER_SPREADER_RECESSIONAL: 'CommonBuffId' = 278033 + ROLE_CUSTOM_STATE_WEDDING_FLOWER_SPREADER_RECESSIONAL_GATHER: 'CommonBuffId' = 278034 + ROLE_CUSTOM_STATE_WEDDING_FLOWER_SPREADER_SIT_DOWN: 'CommonBuffId' = 278035 + ROLE_CUSTOM_STATE_WEDDING_FLOWER_SPREADER_TOAST: 'CommonBuffId' = 278036 + ROLE_CUSTOM_STATE_WEDDING_FLOWER_SPREADER_TOAST_GATHER: 'CommonBuffId' = 278037 + ROLE_CUSTOM_STATE_WEDDING_FLOWER_SPREADER_VOWS: 'CommonBuffId' = 278038 + ROLE_CUSTOM_STATE_WEDDING_FLOWER_SPREADER_VOWS_SPEECH: 'CommonBuffId' = 278039 + ROLE_CUSTOM_STATE_WEDDING_FLOWER_SPREADER_VOWS_WITH_OFFICIANT: 'CommonBuffId' = 278040 + ROLE_CUSTOM_STATE_WEDDING_GUEST_ARRIVAL: 'CommonBuffId' = 278051 + ROLE_CUSTOM_STATE_WEDDING_GUEST_BOUQUET_GATHER: 'CommonBuffId' = 278052 + ROLE_CUSTOM_STATE_WEDDING_GUEST_BOUQUET_TOSS: 'CommonBuffId' = 278062 + ROLE_CUSTOM_STATE_WEDDING_GUEST_CAKE: 'CommonBuffId' = 278061 + ROLE_CUSTOM_STATE_WEDDING_GUEST_CAKE_EAT: 'CommonBuffId' = 278063 + ROLE_CUSTOM_STATE_WEDDING_GUEST_CAKE_GATHER: 'CommonBuffId' = 278064 + ROLE_CUSTOM_STATE_WEDDING_GUEST_DANCE: 'CommonBuffId' = 278065 + ROLE_CUSTOM_STATE_WEDDING_GUEST_DANCE_GATHER: 'CommonBuffId' = 278066 + ROLE_CUSTOM_STATE_WEDDING_GUEST_DANCE_GATHER_DANCE_FLOOR: 'CommonBuffId' = 278067 + ROLE_CUSTOM_STATE_WEDDING_GUEST_DESSERTS: 'CommonBuffId' = 285086 + ROLE_CUSTOM_STATE_WEDDING_GUEST_MEAL: 'CommonBuffId' = 278068 + ROLE_CUSTOM_STATE_WEDDING_GUEST_MINGLE: 'CommonBuffId' = 277815 + ROLE_CUSTOM_STATE_WEDDING_GUEST_POST_CEREMONY: 'CommonBuffId' = 278069 + ROLE_CUSTOM_STATE_WEDDING_GUEST_PROCESSIONAL: 'CommonBuffId' = 278053 + ROLE_CUSTOM_STATE_WEDDING_GUEST_RECESSIONAL: 'CommonBuffId' = 278054 + ROLE_CUSTOM_STATE_WEDDING_GUEST_RECESSIONAL_GATHER: 'CommonBuffId' = 278055 + ROLE_CUSTOM_STATE_WEDDING_GUEST_SIT_DOWN: 'CommonBuffId' = 277904 + ROLE_CUSTOM_STATE_WEDDING_GUEST_TOAST: 'CommonBuffId' = 278056 + ROLE_CUSTOM_STATE_WEDDING_GUEST_TOAST_GATHER: 'CommonBuffId' = 278057 + ROLE_CUSTOM_STATE_WEDDING_GUEST_VOWS: 'CommonBuffId' = 278058 + ROLE_CUSTOM_STATE_WEDDING_GUEST_VOWS_SPEECH: 'CommonBuffId' = 278059 + ROLE_CUSTOM_STATE_WEDDING_GUEST_VOWS_WITH_OFFICIANT: 'CommonBuffId' = 278060 + ROLE_CUSTOM_STATE_WEDDING_HONOR_ATTENDANT_ARRIVAL: 'CommonBuffId' = 278070 + ROLE_CUSTOM_STATE_WEDDING_HONOR_ATTENDANT_BOUQUET_GATHER: 'CommonBuffId' = 278071 + ROLE_CUSTOM_STATE_WEDDING_HONOR_ATTENDANT_BOUQUET_TOSS: 'CommonBuffId' = 278080 + ROLE_CUSTOM_STATE_WEDDING_HONOR_ATTENDANT_CAKE: 'CommonBuffId' = 278081 + ROLE_CUSTOM_STATE_WEDDING_HONOR_ATTENDANT_CAKE_EAT: 'CommonBuffId' = 278082 + ROLE_CUSTOM_STATE_WEDDING_HONOR_ATTENDANT_CAKE_GATHER: 'CommonBuffId' = 278083 + ROLE_CUSTOM_STATE_WEDDING_HONOR_ATTENDANT_DANCE: 'CommonBuffId' = 278084 + ROLE_CUSTOM_STATE_WEDDING_HONOR_ATTENDANT_DANCE_GATHER: 'CommonBuffId' = 278085 + ROLE_CUSTOM_STATE_WEDDING_HONOR_ATTENDANT_DANCE_GATHER_DANCE_FLOOR: 'CommonBuffId' = 278086 + ROLE_CUSTOM_STATE_WEDDING_HONOR_ATTENDANT_MEAL: 'CommonBuffId' = 278087 + ROLE_CUSTOM_STATE_WEDDING_HONOR_ATTENDANT_MINGLE: 'CommonBuffId' = 277816 + ROLE_CUSTOM_STATE_WEDDING_HONOR_ATTENDANT_POST_CEREMONY: 'CommonBuffId' = 278088 + ROLE_CUSTOM_STATE_WEDDING_HONOR_ATTENDANT_PROCESSIONAL: 'CommonBuffId' = 278089 + ROLE_CUSTOM_STATE_WEDDING_HONOR_ATTENDANT_RECESSIONAL: 'CommonBuffId' = 278072 + ROLE_CUSTOM_STATE_WEDDING_HONOR_ATTENDANT_RECESSIONNAL_GATHER: 'CommonBuffId' = 278073 + ROLE_CUSTOM_STATE_WEDDING_HONOR_ATTENDANT_SIT_DOWN: 'CommonBuffId' = 278074 + ROLE_CUSTOM_STATE_WEDDING_HONOR_ATTENDANT_TOAST: 'CommonBuffId' = 278075 + ROLE_CUSTOM_STATE_WEDDING_HONOR_ATTENDANT_TOAST_GATHER: 'CommonBuffId' = 278076 + ROLE_CUSTOM_STATE_WEDDING_HONOR_ATTENDANT_VOWS: 'CommonBuffId' = 278077 + ROLE_CUSTOM_STATE_WEDDING_HONOR_ATTENDANT_VOWS_SPEECH: 'CommonBuffId' = 278078 + ROLE_CUSTOM_STATE_WEDDING_HONOR_ATTENDANT_VOWS_WITH_OFFICIANT: 'CommonBuffId' = 278079 + ROLE_CUSTOM_STATE_WEDDING_OFFICIANT_ARRIVAL: 'CommonBuffId' = 278090 + ROLE_CUSTOM_STATE_WEDDING_OFFICIANT_BOUQUET_GATHER: 'CommonBuffId' = 278091 + ROLE_CUSTOM_STATE_WEDDING_OFFICIANT_BOUQUET_TOSS: 'CommonBuffId' = 278100 + ROLE_CUSTOM_STATE_WEDDING_OFFICIANT_CAKE: 'CommonBuffId' = 278101 + ROLE_CUSTOM_STATE_WEDDING_OFFICIANT_CAKE_EAT: 'CommonBuffId' = 278102 + ROLE_CUSTOM_STATE_WEDDING_OFFICIANT_CAKE_GATHER: 'CommonBuffId' = 278103 + ROLE_CUSTOM_STATE_WEDDING_OFFICIANT_DANCE: 'CommonBuffId' = 278104 + ROLE_CUSTOM_STATE_WEDDING_OFFICIANT_DANCE_GATHER: 'CommonBuffId' = 278105 + ROLE_CUSTOM_STATE_WEDDING_OFFICIANT_DANCE_GATHER_DANCE_FLOOR: 'CommonBuffId' = 278106 + ROLE_CUSTOM_STATE_WEDDING_OFFICIANT_MEAL: 'CommonBuffId' = 278107 + ROLE_CUSTOM_STATE_WEDDING_OFFICIANT_MINGLE: 'CommonBuffId' = 277817 + ROLE_CUSTOM_STATE_WEDDING_OFFICIANT_POST_CEREMONY: 'CommonBuffId' = 278108 + ROLE_CUSTOM_STATE_WEDDING_OFFICIANT_PROCESSIONAL: 'CommonBuffId' = 278109 + ROLE_CUSTOM_STATE_WEDDING_OFFICIANT_RECESSIONAL: 'CommonBuffId' = 278092 + ROLE_CUSTOM_STATE_WEDDING_OFFICIANT_RECESSIONAL_GATHER: 'CommonBuffId' = 278093 + ROLE_CUSTOM_STATE_WEDDING_OFFICIANT_SIT_DOWN: 'CommonBuffId' = 278094 + ROLE_CUSTOM_STATE_WEDDING_OFFICIANT_TOAST: 'CommonBuffId' = 278095 + ROLE_CUSTOM_STATE_WEDDING_OFFICIANT_TOAST_GATHER: 'CommonBuffId' = 278096 + ROLE_CUSTOM_STATE_WEDDING_OFFICIANT_VOWS: 'CommonBuffId' = 278097 + ROLE_CUSTOM_STATE_WEDDING_OFFICIANT_VOWS_SPEECH: 'CommonBuffId' = 278098 + ROLE_CUSTOM_STATE_WEDDING_OFFICIANT_VOWS_WITH_OFFICIANT: 'CommonBuffId' = 278099 + ROLE_DANCE_BATTLE_DANCER: 'CommonBuffId' = 129622 + ROLE_DANCE_BATTLE_WATCHER: 'CommonBuffId' = 129621 + ROLE_DELIVERIES_DROP_BAG: 'CommonBuffId' = 262208 + ROLE_DELIVERIES_GENERIC: 'CommonBuffId' = 262223 + ROLE_DELIVERIES_WAIT_FOR_CUSTOMER: 'CommonBuffId' = 262216 + ROLE_DELIVERIES_WAIT_FOR_TIP: 'CommonBuffId' = 262303 + ROLE_DETECTIVE_NP_CS_STATION_ARRESTED: 'CommonBuffId' = 116489 + ROLE_DETECTIVE_NP_CS_STATION_CRIMINAL: 'CommonBuffId' = 112474 + ROLE_DINNER_PARTY_GUEST_PHASE1: 'CommonBuffId' = 12625 + ROLE_DINNER_PARTY_GUEST_PHASE2: 'CommonBuffId' = 12626 + ROLE_DINNER_PARTY_HOST_PHASE1: 'CommonBuffId' = 12627 + ROLE_DINNER_PARTY_HOST_PHASE2: 'CommonBuffId' = 12628 + ROLE_DOCTOR_CAREER_DOCTOR: 'CommonBuffId' = 115348 + ROLE_DOCTOR_CAREER_DOCTOR_DIAGNOSER: 'CommonBuffId' = 116256 + ROLE_DOCTOR_CAREER_EMERGENCY_SAMPLE_ANALYSIS: 'CommonBuffId' = 114139 + ROLE_DOCTOR_CAREER_IS_PATIENT_DIAGNOSED_BLOATY_HEAD: 'CommonBuffId' = 115284 + ROLE_DOCTOR_CAREER_IS_PATIENT_DIAGNOSED_GAS_AND_GIGGLES: 'CommonBuffId' = 115282 + ROLE_DOCTOR_CAREER_IS_PATIENT_DIAGNOSED_LLAMA_FLU: 'CommonBuffId' = 115281 + ROLE_DOCTOR_CAREER_IS_PATIENT_DIAGNOSED_STARRY_EYES: 'CommonBuffId' = 115283 + ROLE_DOCTOR_CAREER_IS_PATIENT_HIGH_LEVEL: 'CommonBuffId' = 113779 + ROLE_DOCTOR_CAREER_IS_PATIENT_LOW_LEVEL: 'CommonBuffId' = 113744 + ROLE_DOCTOR_CAREER_IS_PATIENT_LOW_LEVEL_ADMITTED: 'CommonBuffId' = 115269 + ROLE_DOCTOR_CAREER_IS_PATIENT_PREGNANT: 'CommonBuffId' = 114080 + ROLE_DOCTOR_CAREER_NURSE: 'CommonBuffId' = 112216 + ROLE_DOCTOR_CAREER_OBGYN: 'CommonBuffId' = 116173 + ROLE_DOCTOR_CAREER_ORDERLY: 'CommonBuffId' = 112247 + ROLE_DOCTOR_CAREER_PATIENT_STATE_ADMITTED: 'CommonBuffId' = 114414 + ROLE_DOCTOR_CAREER_PATIENT_STATE_ARRIVAL: 'CommonBuffId' = 116676 + ROLE_DOCTOR_CAREER_PATIENT_STATE_DIAGNOSED: 'CommonBuffId' = 115798 + ROLE_DOCTOR_CAREER_PATIENT_STATE_TREATED: 'CommonBuffId' = 114415 + ROLE_DOCTOR_CAREER_PLAYER_HAD_BABY: 'CommonBuffId' = 116656 + ROLE_DOCTOR_CAREER_RECEPTIONIST: 'CommonBuffId' = 111789 + ROLE_EMPLOYEE: 'CommonBuffId' = 179092 + ROLE_EP16_SPECIAL_NPC_THERING_BEAR_HANGOUT: 'CommonBuffId' = 369737 + ROLE_EVENT_NPC: 'CommonBuffId' = 136555 + ROLE_EVENT_NPC_POSITIVITY_CHALLENGE: 'CommonBuffId' = 199079 + ROLE_FABRICATOR_RECYCLER: 'CommonBuffId' = 232825 + ROLE_FAMILY_DINNER_CHEF: 'CommonBuffId' = 33920 + ROLE_FAMILY_DINNER_EAT: 'CommonBuffId' = 33922 + ROLE_FAMILY_DINNER_EATER_SUPPRESS_HUNGER: 'CommonBuffId' = 33921 + ROLE_FASHION_SUBJECT: 'CommonBuffId' = 215304 + ROLE_GO_TO_FRONT_DOOR: 'CommonBuffId' = 204302 + ROLE_GROUP_COOKING_COOK_HEAD_COOK: 'CommonBuffId' = 264474 + ROLE_GROUP_COOKING_COOK_JOINED_COOKS: 'CommonBuffId' = 263898 + ROLE_GROUP_COOKING_COOK_STOP_COOKING: 'CommonBuffId' = 269313 + ROLE_GROUP_COOKING_GATHER_HEAD_COOK: 'CommonBuffId' = 263915 + ROLE_GROUP_COOKING_GATHER_JOINED_COOKS: 'CommonBuffId' = 263896 + ROLE_GROUP_COOKING_MENTOREE: 'CommonBuffId' = 267639 + ROLE_GUEST_SUPPRESS_SOCIAL_AUTONOMY: 'CommonBuffId' = 170450 + ROLE_HIGH_SCHOOL_ACTIVE_BASE_FACULTY: 'CommonBuffId' = 302783 + ROLE_HIGH_SCHOOL_ACTIVE_NPC_ATTEND_CLASS_PRINCIPAL: 'CommonBuffId' = 277031 + ROLE_HIGH_SCHOOL_ACTIVE_NPC_ATTEND_CLASS_STUDENT: 'CommonBuffId' = 276312 + ROLE_HIGH_SCHOOL_ACTIVE_NPC_ATTEND_CLASS_TEACHER: 'CommonBuffId' = 276313 + ROLE_HIGH_SCHOOL_ACTIVE_NPC_ATTEND_EXAM_PREP: 'CommonBuffId' = 304066 + ROLE_HIGH_SCHOOL_ACTIVE_NPC_CAREER_DAY_DISALLOW_PRE_ROLL_WATCH: 'CommonBuffId' = 304431 + ROLE_HIGH_SCHOOL_ACTIVE_NPC_CAREER_DAY_PROFESSIONAL: 'CommonBuffId' = 289106 + ROLE_HIGH_SCHOOL_ACTIVE_NPC_CLEAN_JANITOR: 'CommonBuffId' = 290222 + ROLE_HIGH_SCHOOL_ACTIVE_NPC_DO_STUFF_BULLIES: 'CommonBuffId' = 276442 + ROLE_HIGH_SCHOOL_ACTIVE_NPC_DO_STUFF_CAREER_DAY: 'CommonBuffId' = 282142 + ROLE_HIGH_SCHOOL_ACTIVE_NPC_DO_STUFF_CAREER_DAY_2: 'CommonBuffId' = 304416 + ROLE_HIGH_SCHOOL_ACTIVE_NPC_DO_STUFF_CAREER_DAY_3: 'CommonBuffId' = 304417 + ROLE_HIGH_SCHOOL_ACTIVE_NPC_DO_STUFF_DO_MISCHIEF: 'CommonBuffId' = 287886 + ROLE_HIGH_SCHOOL_ACTIVE_NPC_DO_STUFF_FIRE_DRILL: 'CommonBuffId' = 280938 + ROLE_HIGH_SCHOOL_ACTIVE_NPC_DO_STUFF_HIGH_SCHOOL_TEAM_RECRUITER: 'CommonBuffId' = 276556 + ROLE_HIGH_SCHOOL_ACTIVE_NPC_DO_STUFF_SOCIAL_MEDIA_ENTHUSIASTS: 'CommonBuffId' = 276536 + ROLE_HIGH_SCHOOL_ACTIVE_NPC_DO_STUFF_STUDY_BUDDIES: 'CommonBuffId' = 275831 + ROLE_HIGH_SCHOOL_ACTIVE_NPC_DO_STUFF_THROW_FOOTBALL_LEADER: 'CommonBuffId' = 284015 + ROLE_HIGH_SCHOOL_ACTIVE_NPC_DO_STUFF_T_POSE_LEADER: 'CommonBuffId' = 280764 + ROLE_HIGH_SCHOOL_ACTIVE_NPC_DO_STUFF_USE_LOCKER: 'CommonBuffId' = 286443 + ROLE_HIGH_SCHOOL_ACTIVE_NPC_GET_LUNCH: 'CommonBuffId' = 278839 + ROLE_HIGH_SCHOOL_ACTIVE_NPC_GET_LUNCH_CREATE: 'CommonBuffId' = 298820 + ROLE_HIGH_SCHOOL_ACTIVE_NPC_GO_TO_CLASS_1: 'CommonBuffId' = 293776 + ROLE_HIGH_SCHOOL_ACTIVE_NPC_GO_TO_CLASS_2: 'CommonBuffId' = 293817 + ROLE_HIGH_SCHOOL_ACTIVE_NPC_GO_TO_CLASS_TEACHER: 'CommonBuffId' = 297777 + ROLE_HIGH_SCHOOL_ACTIVE_NPC_GO_TO_EXAM_PREP: 'CommonBuffId' = 304063 + ROLE_HIGH_SCHOOL_ACTIVE_NPC_GO_TO_WHITEBOARD: 'CommonBuffId' = 280121 + ROLE_HIGH_SCHOOL_ACTIVE_NPC_HANG_OUT_PRINCIPAL: 'CommonBuffId' = 289475 + ROLE_HIGH_SCHOOL_ACTIVE_NPC_PREPARE_FOR_CLASS: 'CommonBuffId' = 276282 + ROLE_HIGH_SCHOOL_ACTIVE_NPC_SCHOOL_FIGHT_START_FIGHT: 'CommonBuffId' = 282863 + ROLE_HIGH_SCHOOL_ACTIVE_NPC_STOP_INTERACTION: 'CommonBuffId' = 276642 + ROLE_HIGH_SCHOOL_ACTIVE_NPC_STUDENT_ATTEND_CLASS_2: 'CommonBuffId' = 304592 + ROLE_HIGH_SCHOOL_ACTIVE_NPC_TEACH_EXAM_PREP: 'CommonBuffId' = 304082 + ROLE_HIGH_SCHOOL_ACTIVE_PLAYER_AFTER_SCHOOL: 'CommonBuffId' = 288882 + ROLE_HIGH_SCHOOL_ACTIVE_PLAYER_ATTEND_CLASS: 'CommonBuffId' = 276710 + ROLE_HIGH_SCHOOL_ACTIVE_PLAYER_BASE: 'CommonBuffId' = 294894 + ROLE_HIGH_SCHOOL_ACTIVE_PLAYER_CAREER_DAY: 'CommonBuffId' = 282052 + ROLE_HIGH_SCHOOL_ACTIVE_PLAYER_CAREER_DAY_AT_AUDITORIUM: 'CommonBuffId' = 282138 + ROLE_HIGH_SCHOOL_ACTIVE_PLAYER_FIRE_DRILL: 'CommonBuffId' = 280937 + ROLE_HIGH_SCHOOL_ACTIVE_PLAYER_GET_READY_FOR_CLASS: 'CommonBuffId' = 285939 + ROLE_HIGH_SCHOOL_ACTIVE_PLAYER_IS_CAREER_DAY_TRUE: 'CommonBuffId' = 282476 + ROLE_HIGH_SCHOOL_ACTIVE_PLAYER_IS_EXAM_DAY_TRUE: 'CommonBuffId' = 295491 + ROLE_HIGH_SCHOOL_ACTIVE_PLAYER_IS_EXAM_PREP_TRUE: 'CommonBuffId' = 292250 + ROLE_HIGH_SCHOOL_ACTIVE_PLAYER_IS_FIRE_DRILL_TRUE: 'CommonBuffId' = 285120 + ROLE_HIGH_SCHOOL_ACTIVE_PLAYER_ORIENTATION: 'CommonBuffId' = 276707 + ROLE_HIGH_SCHOOL_ACTIVE_PLAYER_TRUANT: 'CommonBuffId' = 285599 + ROLE_HIGH_SCHOOL_ACTIVE_USE_VENDING_MACHINE: 'CommonBuffId' = 297488 + ROLE_HIGH_SCHOOL_GRADUATION_AFFORDANCES: 'CommonBuffId' = 288487 + ROLE_HIGH_SCHOOL_GRADUATION_CALL_OUT_DIPLOMAS: 'CommonBuffId' = 288271 + ROLE_HIGH_SCHOOL_GRADUATION_CLEAN_UP_OUTFITS: 'CommonBuffId' = 305318 + ROLE_HIGH_SCHOOL_GRADUATION_GET_DIPLOMA: 'CommonBuffId' = 288488 + ROLE_HIGH_SCHOOL_GRADUATION_GIVE_SPEECH: 'CommonBuffId' = 288489 + ROLE_HIGH_SCHOOL_GRADUATION_PLEASANTRIES: 'CommonBuffId' = 288491 + ROLE_HIGH_SCHOOL_GRADUATION_THROW_CAP: 'CommonBuffId' = 288503 + ROLE_HIGH_SCHOOL_GRADUATION_WATCH_SPEECH: 'CommonBuffId' = 288441 + ROLE_HIGH_SCHOOL_GRADUATION_WATCH_SPEECH_BACK: 'CommonBuffId' = 288688 + ROLE_HOLIDAY_TRADITION_FATHER_WINTER_ADD_PRESENT: 'CommonBuffId' = 181568 + ROLE_HOLIDAY_TRADITION_FATHER_WINTER_ARRIVAL: 'CommonBuffId' = 181509 + ROLE_HOLIDAY_TRADITION_FATHER_WINTER_HANG_OUT: 'CommonBuffId' = 181512 + ROLE_HOLIDAY_TRADITION_FATHER_WINTER_LEAVE_LOT: 'CommonBuffId' = 188851 + ROLE_HOLIDAY_TRADITION_FLOWER_BUNNY_EXIT: 'CommonBuffId' = 186943 + ROLE_HOLIDAY_TRADITION_FLOWER_BUNNY_HANG_OUT: 'CommonBuffId' = 186944 + ROLE_HOLIDAY_TRADITION_FLOWER_BUNNY_OUTFIT: 'CommonBuffId' = 189297 + ROLE_HOLIDAY_TRADITION_TRICK_OR_TREAT_ARRIVAL: 'CommonBuffId' = 187599 + ROLE_HOLIDAY_TRADITION_TRICK_OR_TREAT_DONE: 'CommonBuffId' = 187691 + ROLE_HOLIDAY_TRADITION_TRICK_OR_TREAT_WAIT: 'CommonBuffId' = 187680 + ROLE_IMPRISONED: 'CommonBuffId' = 101250 + ROLE_INFECT_HOUSE: 'CommonBuffId' = 203120 + ROLE_INSECT_FARMER: 'CommonBuffId' = 233428 + ROLE_ISLAND_WELCOME_WAGON_KAVA_BEARER_PUT_DOWN: 'CommonBuffId' = 211527 + ROLE_ISLAND_WELCOME_WAGON_NEIGHBOR: 'CommonBuffId' = 211525 + ROLE_JOGGER_EAR_BUDS: 'CommonBuffId' = 166526 + ROLE_KARAOKE_SING_KARAOKE: 'CommonBuffId' = 138062 + ROLE_KARAOKE_SING_KARAOKE_CONTEST: 'CommonBuffId' = 138145 + ROLE_KARAOKE_SING_KARAOKE_DUET: 'CommonBuffId' = 140810 + ROLE_LEAVE_LOT_NOW: 'CommonBuffId' = 24238 + ROLE_LEAVE_LOT_NOW_MUST_RUN: 'CommonBuffId' = 24312 + ROLE_LEAVE_LOT_SOON: 'CommonBuffId' = 28380 + ROLE_LOOK_BUSY_IN_PLACE: 'CommonBuffId' = 101249 + ROLE_MAKERSPACEMENTOR: 'CommonBuffId' = 232823 + ROLE_MINGLER: 'CommonBuffId' = 12632 + ROLE_MOTHER_PLANT_BATTLE_COOLDOWN: 'CommonBuffId' = 205259 + ROLE_MOTHER_PLANT_BATTLE_COOLDOWN_ATTACK: 'CommonBuffId' = 204435 + ROLE_MOTHER_PLANT_BATTLE_COOLDOWN_INSPIRE: 'CommonBuffId' = 204437 + ROLE_MOTHER_PLANT_BATTLE_COOLDOWN_MEGA_SPRAY: 'CommonBuffId' = 204438 + ROLE_MOTHER_PLANT_BATTLE_COOLDOWN_RALLY: 'CommonBuffId' = 204436 + ROLE_MOTHER_PLANT_BATTLE_COOLDOWN_THROW_CURE: 'CommonBuffId' = 204439 + ROLE_MOTHER_PLANT_BATTLE_COOLDOWN_WARBLING_WARCRY: 'CommonBuffId' = 204440 + ROLE_MOTHER_PLANT_BATTLE_HELPER_ATTACK: 'CommonBuffId' = 203656 + ROLE_MOTHER_PLANT_BATTLE_HELPER_ATTACK_LOCATION_1: 'CommonBuffId' = 204404 + ROLE_MOTHER_PLANT_BATTLE_HELPER_ATTACK_LOCATION_2: 'CommonBuffId' = 204405 + ROLE_MOTHER_PLANT_BATTLE_HELPER_ATTACK_LOCATION_3: 'CommonBuffId' = 204403 + ROLE_MOTHER_PLANT_BATTLE_HELPER_BASE: 'CommonBuffId' = 203655 + ROLE_MOTHER_PLANT_BATTLE_HELPER_INSPIRE: 'CommonBuffId' = 203657 + ROLE_MOTHER_PLANT_BATTLE_HELPER_RALLY: 'CommonBuffId' = 203658 + ROLE_MOTHER_PLANT_BATTLE_HELPER_START: 'CommonBuffId' = 204380 + ROLE_MOTHER_PLANT_BATTLE_HELPER_THROW_CURE_NEXT: 'CommonBuffId' = 204502 + ROLE_MOTHER_PLANT_BATTLE_HELPER_WARBLING_WARCRY: 'CommonBuffId' = 203659 + ROLE_MOTHER_PLANT_BATTLE_OTHER_SIMS: 'CommonBuffId' = 207185 + ROLE_MOTHER_PLANT_BATTLE_PLAYER_ATTACK: 'CommonBuffId' = 203670 + ROLE_MOTHER_PLANT_BATTLE_PLAYER_BASE: 'CommonBuffId' = 203669 + ROLE_MOTHER_PLANT_BATTLE_PLAYER_INSPIRE: 'CommonBuffId' = 203672 + ROLE_MOTHER_PLANT_BATTLE_PLAYER_RALLY: 'CommonBuffId' = 203671 + ROLE_MOTHER_PLANT_BATTLE_PLAYER_START: 'CommonBuffId' = 204385 + ROLE_MOTHER_PLANT_BATTLE_PLAYER_WARBLING_WARCRY: 'CommonBuffId' = 203673 + ROLE_MOTHER_PLANT_BATTLE_ZOMBIE_BASE: 'CommonBuffId' = 203690 + ROLE_MOTHER_PLANT_BATTLE_ZOMBIE_START: 'CommonBuffId' = 204381 + ROLE_MOTHER_PLANT_BATTLE_ZOMBIE_WARBLING_WARCRY: 'CommonBuffId' = 203691 + ROLE_MULTI_UNIT_COMMUNITY_COOK: 'CommonBuffId' = 344208 + ROLE_MULTI_UNIT_COMMUNITY_GARDEN_TEND_GARDEN: 'CommonBuffId' = 343298 + ROLE_MULTI_UNIT_COMMUNITY_MAILBOX_GET_MAIL: 'CommonBuffId' = 343426 + ROLE_MULTI_UNIT_COMMUNITY_NEIGHBOR_CHAT: 'CommonBuffId' = 354022 + ROLE_MULTI_UNIT_COMMUNITY_USE_OBJECTS: 'CommonBuffId' = 343454 + ROLE_MULTI_UNIT_COMMUNITY_USE_TOILET: 'CommonBuffId' = 343458 + ROLE_MULTI_UNIT_EVENT_CHARITY_DRIVE_NPC: 'CommonBuffId' = 345529 + ROLE_MULTI_UNIT_EVENT_CHARITY_DRIVE_PLAYER: 'CommonBuffId' = 345508 + ROLE_MULTI_UNIT_EVENT_CURSED: 'CommonBuffId' = 345176 + ROLE_MULTI_UNIT_EVENT_HAUNTING_GHOST: 'CommonBuffId' = 344694 + ROLE_MULTI_UNIT_EVENT_HAUNTING_TENANT: 'CommonBuffId' = 344757 + ROLE_MULTI_UNIT_EVENT_NUISANCE_PLAYER: 'CommonBuffId' = 349596 + ROLE_MULTI_UNIT_EVENT_NUISANCE_PO_KNOCK: 'CommonBuffId' = 351870 + ROLE_MULTI_UNIT_EVENT_PET_DAY: 'CommonBuffId' = 344803 + ROLE_MULTI_UNIT_EVENT_SEWAGE_LEAK: 'CommonBuffId' = 344640 + ROLE_MULTI_UNIT_EVENT_TRASH_OVERLOAD: 'CommonBuffId' = 344181 + ROLE_MULTI_UNIT_EVENT_TRASH_OVERLOAD_TRASH_DRIVE: 'CommonBuffId' = 344182 + ROLE_NANNY_KIDS: 'CommonBuffId' = 143713 + ROLE_NANNY_LEAVE_LOT_NOW: 'CommonBuffId' = 143677 + ROLE_NANNY_MENTORED_ART: 'CommonBuffId' = 143793 + ROLE_NANNY_MENTORED_HOMEWORK: 'CommonBuffId' = 143792 + ROLE_NANNY_MENTORED_MUSIC: 'CommonBuffId' = 143794 + ROLE_NANNY_MENTORED_SWIM: 'CommonBuffId' = 143791 + ROLE_NO_CAREER_TALK: 'CommonBuffId' = 39294 + ROLE_ONSEN_VENUE_BROWSEVENDINGMACHINE: 'CommonBuffId' = 248288 + ROLE_ONSEN_VENUE_NOSOCIALIZECOOLDOWN: 'CommonBuffId' = 250622 + ROLE_ONSEN_VENUE_PLAYER_HOTSPRINGCOOLDOWN: 'CommonBuffId' = 248508 + ROLE_ONSEN_VENUE_POWERSOAKER: 'CommonBuffId' = 249507 + ROLE_ONSEN_VENUE_SHOWERCOOLDOWN: 'CommonBuffId' = 250628 + ROLE_ONSEN_VENUE_SOAKER_CHANGEINBATHE: 'CommonBuffId' = 248278 + ROLE_ONSEN_VENUE_SOAKER_CHANGEOUTBATHE: 'CommonBuffId' = 248279 + ROLE_ONSEN_VENUE_SOAKER_HOTSPRINGSOAK: 'CommonBuffId' = 248287 + ROLE_OPEN_STREET_COTTAGE_WORLD_FORAGER: 'CommonBuffId' = 264734 + ROLE_OPEN_STREET_COTTAGE_WORLD_GOSSIPER: 'CommonBuffId' = 264549 + ROLE_OPEN_STREET_COTTAGE_WORLD_PICNICKER: 'CommonBuffId' = 263839 + ROLE_OPEN_STREET_EP14_WORLD_COMMUNITY_BOARD_VIEWER: 'CommonBuffId' = 339332 + ROLE_OPEN_STREET_EP14_WORLD_EQUESTRIAN_CENTER_VISITOR: 'CommonBuffId' = 335563 + ROLE_OWNER_BILL_OWNER: 'CommonBuffId' = 176024 + ROLE_OWNER_BILL_OWNER_VFX: 'CommonBuffId' = 177919 + ROLE_PAINTER: 'CommonBuffId' = 232832 + ROLE_PET_PREVENT_CRITICAL_DECAY: 'CommonBuffId' = 168445 + ROLE_PHOTO_TRIPOD_LOCK_AUTONOMY: 'CommonBuffId' = 221131 + ROLE_PHOTO_TRIPOD_PHOTOGRAPHER: 'CommonBuffId' = 217410 + ROLE_PHOTO_TRIPOD_PHOTOGRAPHER_PHOTO_MODE: 'CommonBuffId' = 218435 + ROLE_PHOTO_TRIPOD_PHOTOGRAPHER_TAKE_PHOTO: 'CommonBuffId' = 218426 + ROLE_PHOTO_TRIPOD_POSE_CANT_WAIT_SEE: 'CommonBuffId' = 218693 + ROLE_PHOTO_TRIPOD_POSE_NOT_MY_GOOD_SIDE: 'CommonBuffId' = 218694 + ROLE_PHOTO_TRIPOD_POSE_TAKE_THE_PICTURE: 'CommonBuffId' = 218691 + ROLE_PHOTO_TRIPOD_SUBJECT: 'CommonBuffId' = 217409 + ROLE_PICNIC_ROMANTIC_BLANKET_EAT: 'CommonBuffId' = 364383 + ROLE_POSSESSED: 'CommonBuffId' = 202278 + ROLE_RANCH_HAND_NPC: 'CommonBuffId' = 305070 + ROLE_RANCH_HAND_NPC_ANIMAL_CARE_ROLE: 'CommonBuffId' = 305073 + ROLE_RANCH_HAND_NPC_ARRIVE: 'CommonBuffId' = 339306 + ROLE_RANCH_HAND_NPC_END: 'CommonBuffId' = 339312 + ROLE_RANCH_HAND_NPC_GARDENER_ROLE: 'CommonBuffId' = 305071 + ROLE_RANCH_HAND_NPC_REPAIRMAN_ROLE: 'CommonBuffId' = 305072 + ROLE_RANCH_HAND_STATES_CARE_FOR_ANIMALS: 'CommonBuffId' = 304754 + ROLE_RANCH_HAND_STATES_DONT_CARE_FOR_ANIMALS: 'CommonBuffId' = 304755 + ROLE_RANCH_HAND_STATES_DONT_GARDEN: 'CommonBuffId' = 304757 + ROLE_RANCH_HAND_STATES_DONT_REPAIR: 'CommonBuffId' = 304727 + ROLE_RANCH_HAND_STATES_GARDEN: 'CommonBuffId' = 304756 + ROLE_RANCH_HAND_STATES_REPAIR: 'CommonBuffId' = 304725 + ROLE_RECYCLING_GURU: 'CommonBuffId' = 232824 + ROLE_RESTAURANT_BACKGROUND_SOCIAL_DESIRE: 'CommonBuffId' = 138106 + ROLE_RESTAURANT_CAN_DRAW_ON_PLACEMAT: 'CommonBuffId' = 141036 + ROLE_RESTAURANT_PLAYER_EAT_FOOD: 'CommonBuffId' = 134540 + ROLE_RESTAURANT_PLAYER_WAIT_FOR_FOOD: 'CommonBuffId' = 134550 + ROLE_RESTAURANT_PREFER_SOCIALIZE_WITH_PARTY: 'CommonBuffId' = 138095 + ROLE_RESTAURANT_STAFF_SUPPRESS_SOCIALIZE_AUTONOMOUSLY: 'CommonBuffId' = 138206 + ROLE_RESTAURANT_STAY_ON_LOT: 'CommonBuffId' = 138028 + ROLE_RESTAURANT_STICKY_SEATING: 'CommonBuffId' = 138029 + ROLE_RESTAURANT_SUPPRESS_TRAINING: 'CommonBuffId' = 143648 + ROLE_SCHOOL_SPIRIT_PARTY_GAME_DAY_PARTY_MEMBER_PARTYING: 'CommonBuffId' = 225009 + ROLE_SCHOOL_SPIRIT_PARTY_GAME_DAY_PARTY_PARTY_GOER: 'CommonBuffId' = 225011 + ROLE_SCHOOL_SPIRIT_PARTY_GAME_DAY_PARTY_PLAYER: 'CommonBuffId' = 228447 + ROLE_SCHOOL_SPIRIT_PARTY_SCHOOL_SPIRIT_DAY_MEMBER_PARTYING: 'CommonBuffId' = 210853 + ROLE_SCHOOL_SPIRIT_PARTY_SCHOOL_SPIRIT_DAY_PLAYER: 'CommonBuffId' = 228448 + ROLE_SCHOOL_SPIRIT_PARTY_SCHOOL_SPIRIT_DAY_STUDENT_PARTYING: 'CommonBuffId' = 210857 + ROLE_SCHOOL_SPIRIT_PRANK_CREATIVITY_CELEBRATION_PAINTING: 'CommonBuffId' = 223409 + ROLE_SCHOOL_SPIRIT_PRANK_CREATIVITY_CELEBRATION_PARTYING: 'CommonBuffId' = 223410 + ROLE_SCHOOL_SPIRIT_PRANK_CREATIVITY_CELEBRATION_PLAYER: 'CommonBuffId' = 223439 + ROLE_SCHOOL_SPIRIT_PRANK_GAMEDAY_PARTY_MEMBER_PARTYING: 'CommonBuffId' = 223558 + ROLE_SCHOOL_SPIRIT_PRANK_GAMEDAY_PARTY_PLAYER: 'CommonBuffId' = 228444 + ROLE_SCHOOL_SPIRIT_PRANK_GAMEDAY_PARTY_RIVAL_PARTYING: 'CommonBuffId' = 223557 + ROLE_SCHOOL_SPIRIT_SCHOOL_CHEER: 'CommonBuffId' = 225048 + ROLE_SCROUNGER: 'CommonBuffId' = 234690 + ROLE_SERVICE_NPC_ADOPTION_OFFICER_AND_PETS_NO_FAILURES: 'CommonBuffId' = 169336 + ROLE_SERVICE_NPC_ADOPTION_OFFICER_ARRIVAL: 'CommonBuffId' = 169077 + ROLE_SERVICE_NPC_ADOPTION_OFFICER_ARRIVAL_FIND_PET: 'CommonBuffId' = 171190 + ROLE_SERVICE_NPC_ARRIVE: 'CommonBuffId' = 12633 + ROLE_SERVICE_NPC_GARDENER_SERVICE: 'CommonBuffId' = 130531 + ROLE_SERVICE_NPC_MAID: 'CommonBuffId' = 12634 + ROLE_SERVICE_NPC_MAID_UNIVERSITY_HOUSING: 'CommonBuffId' = 227449 + ROLE_SERVICE_NPC_MAILMAN: 'CommonBuffId' = 12635 + ROLE_SERVICE_NPC_NANNY: 'CommonBuffId' = 141866 + ROLE_SERVICE_NPC_NANNY_ARRIVE: 'CommonBuffId' = 143493 + ROLE_SERVICE_NPC_NANNY_BABY_PLAYING_COOLDOWN: 'CommonBuffId' = 143104 + ROLE_SERVICE_NPC_NANNY_MAKE_FOOD_COOLDOWN: 'CommonBuffId' = 143105 + ROLE_SERVICE_NPC_NANNY_NO_MORE_WORK: 'CommonBuffId' = 143414 + ROLE_SERVICE_NPC_NANNY_OVERTIME_WORK_TIME: 'CommonBuffId' = 143840 + ROLE_SERVICE_NPC_NANNY_WORK_TIME: 'CommonBuffId' = 143398 + ROLE_SERVICE_NPC_ONSEN_VENUE_EMPLOYEE_ARRIVE: 'CommonBuffId' = 247860 + ROLE_SERVICE_NPC_ONSEN_VENUE_EMPLOYEE_WORKING: 'CommonBuffId' = 247876 + ROLE_SERVICE_NPC_PET_ARRIVAL: 'CommonBuffId' = 164880 + ROLE_SERVICE_NPC_PET_ARRIVAL_SELL_ADOPT: 'CommonBuffId' = 171268 + ROLE_SERVICE_NPC_PET_CARE_WORKER_ARRIVAL: 'CommonBuffId' = 164148 + ROLE_SERVICE_NPC_PET_CARE_WORKER_LEAVE: 'CommonBuffId' = 164149 + ROLE_SERVICE_NPC_PET_CARE_WORKER_PET_INACCESSIBLE: 'CommonBuffId' = 177870 + ROLE_SERVICE_NPC_PET_CARE_WORKER_PET_ROUTE_TO_CRATE_SELL: 'CommonBuffId' = 169825 + ROLE_SERVICE_NPC_PET_CARE_WORKER_ROUTE_TO_CRATE: 'CommonBuffId' = 164684 + ROLE_SERVICE_NPC_PET_ROUTE_TO_CRATE: 'CommonBuffId' = 164881 + ROLE_SERVICE_NPC_PIZZA_DELIVERY: 'CommonBuffId' = 9829 + ROLE_SERVICE_NPC_REPAIR: 'CommonBuffId' = 129473 + ROLE_SITUATION_APARTMENT_NEIGHBORS_ANSWER_DOOR_COMPLAINT: 'CommonBuffId' = 139260 + ROLE_SITUATION_APARTMENT_NEIGHBORS_CHECK_MAIL: 'CommonBuffId' = 137331 + ROLE_SITUATION_APARTMENT_NEIGHBORS_COMPLAINED_TO_HIDDEN: 'CommonBuffId' = 140717 + ROLE_SITUATION_APARTMENT_NEIGHBORS_FLIRTY_SHOWER_HAS_BATHED: 'CommonBuffId' = 154398 + ROLE_SITUATION_APARTMENT_NEIGHBORS_HANGOUT_BRAINSTORM: 'CommonBuffId' = 141227 + ROLE_SITUATION_APARTMENT_NEIGHBORS_HANGOUT_CHILDS_PLAY: 'CommonBuffId' = 141232 + ROLE_SITUATION_APARTMENT_NEIGHBORS_HANGOUT_CHILD_COMPLAINT: 'CommonBuffId' = 141231 + ROLE_SITUATION_APARTMENT_NEIGHBORS_HANGOUT_FLIRTY_SHOWER: 'CommonBuffId' = 141226 + ROLE_SITUATION_APARTMENT_NEIGHBORS_HANGOUT_GEEK_OUT: 'CommonBuffId' = 141229 + ROLE_SITUATION_APARTMENT_NEIGHBORS_HANGOUT_GENERIC_GREETED: 'CommonBuffId' = 148298 + ROLE_SITUATION_APARTMENT_NEIGHBORS_HANGOUT_GENERIC_NOT_GREETED: 'CommonBuffId' = 139315 + ROLE_SITUATION_APARTMENT_NEIGHBORS_HANGOUT_KEY_GROUP_GAME_TIME: 'CommonBuffId' = 142572 + ROLE_SITUATION_APARTMENT_NEIGHBORS_HANGOUT_KEY_GROUP_PRE_PARTY: 'CommonBuffId' = 142571 + ROLE_SITUATION_APARTMENT_NEIGHBORS_HANGOUT_MUNCHIES: 'CommonBuffId' = 141228 + ROLE_SITUATION_APARTMENT_NEIGHBORS_HANGOUT_UNINVITED_ARRIVAL: 'CommonBuffId' = 141937 + ROLE_SITUATION_APARTMENT_NEIGHBORS_HANGOUT_WORKOUT: 'CommonBuffId' = 141230 + ROLE_SITUATION_APARTMENT_NEIGHBORS_NPC_WAIT_FOR_OCCUPANT_HIDDEN: 'CommonBuffId' = 155140 + ROLE_SITUATION_APARTMENT_NEIGHBORS_PENTHOUSE_HANGOUT_DONE_GREETING: 'CommonBuffId' = 154720 + ROLE_SITUATION_APARTMENT_NEIGHBORS_PLAYER_COMPLAIN_READY_HIDDEN: 'CommonBuffId' = 154282 + ROLE_SITUATION_APARTMENT_NEIGHBORS_PLAYER_WAIT_FOR_OCCUPANT_HIDDEN: 'CommonBuffId' = 154595 + ROLE_SITUATION_APARTMENT_NEIGHBORS_REACT_TO_YOU_INTRIGUED_NOISE: 'CommonBuffId' = 147080 + ROLE_SITUATION_APARTMENT_NEIGHBORS_REACT_TO_YOU_INTRIGUED_SMELL: 'CommonBuffId' = 147082 + ROLE_SITUATION_APARTMENT_NEIGHBORS_REACT_TO_YOU_KNOCK_ON_DOOR_ANGRY: 'CommonBuffId' = 150824 + ROLE_SITUATION_APARTMENT_NEIGHBORS_REACT_TO_YOU_KNOCK_ON_DOOR_POLITE: 'CommonBuffId' = 150827 + ROLE_SITUATION_APARTMENT_NEIGHBORS_REACT_TO_YOU_NO_SOCIAL: 'CommonBuffId' = 155942 + ROLE_SITUATION_APARTMENT_NEIGHBORS_TAKE_OUT_TRASH: 'CommonBuffId' = 137101 + ROLE_SITUATION_APARTMENT_NEIGHBOR_PLAYER_KNOCKED_POLITELY: 'CommonBuffId' = 155817 + ROLE_SITUATION_DJ_DANCING_NPC_DJ: 'CommonBuffId' = 122816 + ROLE_SITUATION_PENTHOUSE_HANGOUT_KEY_HOLDER_ARRIVAL: 'CommonBuffId' = 153859 + ROLE_SITUATION_PENTHOUSE_HANGOUT_KEY_HOLDER_GREET: 'CommonBuffId' = 155019 + ROLE_SITUATION_PENTHOUSE_HANGOUT_NON_KEY_HOLDER_ARRIVAL: 'CommonBuffId' = 155025 + ROLE_SITUATION_PENTHOUSE_HANGOUT_NON_KEY_HOLDER_GREET: 'CommonBuffId' = 155024 + ROLE_SLEEPOVER_GUEST: 'CommonBuffId' = 313210 + ROLE_SLEEPOVER_HOST: 'CommonBuffId' = 313209 + ROLE_SLEEPOVER_SLEEP: 'CommonBuffId' = 313208 + ROLE_TAKE_CARE_OF_BABY: 'CommonBuffId' = 194622 + ROLE_TAKE_PHOTO: 'CommonBuffId' = 180548 + ROLE_TOURIST_PHOTO_COOLDOWN_HIDDEN: 'CommonBuffId' = 155578 + ROLE_TOURIST_TAKE_PHOTO_NO_ATTRACTOR: 'CommonBuffId' = 201137 + ROLE_TOURIST_VIEW_ATTRACTOR_POINT: 'CommonBuffId' = 197031 + ROLE_TOURIST_VIEW_CELEBRITY_TILE: 'CommonBuffId' = 197029 + ROLE_TRAGIC_CLOWN_NPC: 'CommonBuffId' = 139606 + ROLE_TRAGIC_CLOWN_NPC_F_HAIR: 'CommonBuffId' = 140373 + ROLE_TRAGIC_CLOWN_NPC_M_HAIR: 'CommonBuffId' = 140372 + ROLE_TRASH_DIVER: 'CommonBuffId' = 224214 + ROLE_UNIVERSITY_GRADUATION_CEREMONY: 'CommonBuffId' = 227923 + ROLE_UNIVERSITY_GRADUATION_GATHER: 'CommonBuffId' = 227700 + ROLE_VAMPIRE_VISIT_ARRIVE: 'CommonBuffId' = 153608 + ROLE_VAMPIRE_VISIT_BITE: 'CommonBuffId' = 153607 + ROLE_VAMPIRE_VISIT_BREAK_IN: 'CommonBuffId' = 153609 + ROLE_VAMPIRE_VISIT_STARTLED_LEAVE: 'CommonBuffId' = 156871 + ROLE_VET_BILL_OWNER: 'CommonBuffId' = 168504 + ROLE_VET_BILL_OWNER_PET: 'CommonBuffId' = 178622 + ROLE_VET_CHECK_UP: 'CommonBuffId' = 169865 + ROLE_VET_CUSTOMER_ARRIVAL: 'CommonBuffId' = 166919 + ROLE_VET_EMPLOYEE: 'CommonBuffId' = 171651 + ROLE_VET_EMPLOYEE_EXAM_PET: 'CommonBuffId' = 167023 + ROLE_VET_EMPLOYEE_RESPONSIBILITIES: 'CommonBuffId' = 170055 + ROLE_VET_EMPLOYEE_SUPPRESS_INTERACTIONS: 'CommonBuffId' = 178611 + ROLE_VET_GREETED: 'CommonBuffId' = 167208 + ROLE_VET_NEED_TO_GREET: 'CommonBuffId' = 167207 + ROLE_VET_NO_PHONE: 'CommonBuffId' = 175870 + ROLE_VET_OWNER_SOCIALS: 'CommonBuffId' = 168788 + ROLE_VET_PET: 'CommonBuffId' = 168209 + ROLE_VET_PET_OWNER_DURING_SERVICE: 'CommonBuffId' = 178604 + ROLE_VET_PET_OWNER_STAY_NEAR_PET: 'CommonBuffId' = 169044 + ROLE_VET_PET_OWNER_SUPPRESS_INTERACTIONS: 'CommonBuffId' = 178404 + ROLE_VET_STAY_NEAR_PODIUM: 'CommonBuffId' = 169462 + ROLE_VET_SUPPRESS_GET_COMFORTABLE: 'CommonBuffId' = 168956 + ROLE_VET_SUPPRESS_SOCIAL_AUTONOMY: 'CommonBuffId' = 167085 + ROLE_VET_SUPPRESS_TRAINING: 'CommonBuffId' = 167679 + ROLE_VET_USE_VENDING_MACHINE: 'CommonBuffId' = 173500 + ROLE_VET_USE_VENDING_MACHINE_ONLY: 'CommonBuffId' = 173387 + ROLE_WAITING_IN_LINE: 'CommonBuffId' = 247161 + ROLE_WAIT_FOR_INVITATION_INTERACTIONS_ONLY: 'CommonBuffId' = 238905 + ROLE_WAIT_FOR_INVITATION_INTERACTIONS_ONLY_ANGRY: 'CommonBuffId' = 358726 + ROLE_WANT_FEAR_PARTY_HOST: 'CommonBuffId' = 302072 + ROLE_WEDDING_VENUE_VISITOR: 'CommonBuffId' = 274767 + ROLE_WELCOME_WAGON_NEIGHBOR_FOLLOW_DOOR_KNOCKER: 'CommonBuffId' = 120209 + ROLE_WELCOME_WAGON_NEIGHBOR_UNGREETED: 'CommonBuffId' = 120201 + ROLE_WELCOME_WAGON_SECRET_AGENT: 'CommonBuffId' = 203522 + ROLE_WELCOME_WAGON_SECRET_AGENT_NOTHING_TO_SEE_HERE: 'CommonBuffId' = 204543 + ROLE_WEREWOLF_REPAIRMAN_BE_HANDY: 'CommonBuffId' = 298463 + ROLE_WEREWOLF_REPAIRMAN_HANG_OUT: 'CommonBuffId' = 298800 + ROLE_WOODWORKER: 'CommonBuffId' = 232830 + ROMANCE_DYNAMICS_BREAK_UP_STRESS: 'CommonBuffId' = 365203 + ROMANCE_DYNAMICS_COMFORTED_BY_PARTNER: 'CommonBuffId' = 365180 + ROMANCE_DYNAMICS_CUT_IT_OFF_WITH_TOXIC_EX: 'CommonBuffId' = 365201 + ROMANCE_DYNAMICS_DAY_DREAMING_OF_PARTNER: 'CommonBuffId' = 365197 + ROMANCE_DYNAMICS_DISTRAUGHT_OVER_BREAK_UP: 'CommonBuffId' = 365202 + ROMANCE_DYNAMICS_ITS_GETTING_HOT_IN_HERE: 'CommonBuffId' = 365183 + ROMANCE_DYNAMICS_I_HAVE_A_BAD_FEELING: 'CommonBuffId' = 365182 + ROMANCE_DYNAMICS_I_HOPE_THEYRE_OKAY: 'CommonBuffId' = 365181 + ROMANCE_DYNAMICS_LOST_LOVE: 'CommonBuffId' = 365198 + ROMANCE_DYNAMICS_LOST_STEAMY_LOVE: 'CommonBuffId' = 365199 + ROMANCE_DYNAMICS_LOVE_IS_ALL_YOU_NEED: 'CommonBuffId' = 365185 + ROMANCE_DYNAMICS_LOVE_IS_MAD: 'CommonBuffId' = 365196 + ROMANCE_DYNAMICS_PARTNER_THOUGHTS_HIDDEN: 'CommonBuffId' = 376898 + ROMANCE_DYNAMICS_PARTNER_THOUGHTS_STRAINED_ANGRY: 'CommonBuffId' = 376896 + ROMANCE_DYNAMICS_PARTNER_THOUGHTS_STRAINED_HAPPY: 'CommonBuffId' = 376897 + ROMANCE_DYNAMICS_PARTNER_THOUGHTS_UNPREDICTABLE_FLIRTY: 'CommonBuffId' = 376894 + ROMANCE_DYNAMICS_PARTNER_THOUGHTS_UNPREDICTABLE_TENSE: 'CommonBuffId' = 376895 + ROMANCE_DYNAMICS_PARTNER_THOUGHTS_WHOLESOME: 'CommonBuffId' = 376893 + ROMANCE_DYNAMICS_PEACE_OF_MIND: 'CommonBuffId' = 365204 + ROMANCE_DYNAMICS_ROMANCE_TROPE_ADVENTURE_COOLDOWN: 'CommonBuffId' = 363091 + ROMANCE_DYNAMICS_ROMANCE_TROPE_ADVENTURE_COOLDOWN_STRAINED: 'CommonBuffId' = 393263 + ROMANCE_DYNAMICS_SHARED_SILLIES: 'CommonBuffId' = 365184 + ROMANCE_DYNAMICS_STEAMY_HIDDEN: 'CommonBuffId' = 362485 + ROMANCE_DYNAMICS_STEAMY_REBOUND: 'CommonBuffId' = 365200 + ROMANCE_DYNAMICS_STRAINED_HIDDEN: 'CommonBuffId' = 362498 + ROMANCE_DYNAMICS_UNPREDICTABLE_HIDDEN: 'CommonBuffId' = 362497 + ROMANCE_DYNAMICS_WHOLESOME_HIDDEN: 'CommonBuffId' = 362486 + ROMANCE_DYNAMICS_WORKING_ON_ROMANCE_DYNAMIC: 'CommonBuffId' = 363120 + ROMANCE_SKILL_AURA_OF_FLIRTINESS: 'CommonBuffId' = 370021 + ROMANCE_SKILL_DELAY_TIMER_AURA_OF_FLIRTINESS: 'CommonBuffId' = 392932 + ROMANCE_SKILL_DELAY_TIMER_SCAN_THE_ROOM: 'CommonBuffId' = 392933 + ROMANCE_SKILL_INCREASED_CHANCE: 'CommonBuffId' = 369828 + ROMANCE_SKILL_INCREASED_CHANCE_WOOHOO: 'CommonBuffId' = 369829 + ROMANCE_SKILL_SCAN_THE_ROOM: 'CommonBuffId' = 369827 + ROMANTIC_PHONE_CALLS_7_DATES_0_OUT_OF_7_WILD_DATES: 'CommonBuffId' = 372693 + ROMANTIC_PHONE_CALLS_7_DATES_1_OUT_OF_7_WILD_DATES: 'CommonBuffId' = 372991 + ROMANTIC_PHONE_CALLS_7_DATES_2_OUT_OF_7_WILD_DATES: 'CommonBuffId' = 372992 + ROMANTIC_PHONE_CALLS_7_DATES_3_OUT_OF_7_WILD_DATES: 'CommonBuffId' = 372993 + ROMANTIC_PHONE_CALLS_7_DATES_4_OUT_OF_7_WILD_DATES: 'CommonBuffId' = 372994 + ROMANTIC_PHONE_CALLS_7_DATES_5_OUT_OF_7_WILD_DATES: 'CommonBuffId' = 372995 + ROMANTIC_PHONE_CALLS_7_DATES_6_OUT_OF_7_WILD_DATES: 'CommonBuffId' = 372996 + ROMANTIC_PHONE_CALLS_7_WILD_DATES_FREE_RELATIONSHIP_COUNSELING_HIDDEN: 'CommonBuffId' = 373486 + ROMANTIC_PHONE_CALLS_BABE_COME_OVER_HEART_BED_HURRY: 'CommonBuffId' = 372694 + ROMANTIC_PHONE_CALLS_LOVE_YOU_HEART_MY_PIZZA: 'CommonBuffId' = 373895 + ROMANTIC_PHONE_CALLS_LOVE_YOU_TACO_BOUT_LOVE: 'CommonBuffId' = 372698 + ROMANTIC_PHONE_CALLS_SECRET_ADMIRER_VISIBLE_BUFF: 'CommonBuffId' = 372697 + ROMANTIC_PHONE_CALLS_SECRET_ADMIRER_WHO_WAS_THAT: 'CommonBuffId' = 372696 + ROMANTIC_PHONE_CALLS_THE_WEALTHY_WEIRDO_BLOCKED_HIDDEN: 'CommonBuffId' = 372703 + ROMANTIC_PHONE_CALLS_THE_WEALTHY_WEIRDO_MEETING_WITH_A_WEALTHY_WEIRDO: 'CommonBuffId' = 372695 + ROMANTIC_PHONE_CALLS_THE_WEALTHY_WEIRDO_NO_SHOW_WEIRDO: 'CommonBuffId' = 373087 + ROMANTIC_PHONE_CALLS_THE_WEALTHY_WEIRDO_WEALTHY_WEIRDO_REJECTED: 'CommonBuffId' = 372691 + ROMANTIC_PHONE_CALLS_THE_WEALTHY_WEIRDO_WEIRD_DATE: 'CommonBuffId' = 372692 + ROMANTIC_PHONE_CALLS_WE_NEED_TO_TALK_CHOCOLATE_LOVE: 'CommonBuffId' = 372699 + ROMANTIC_PHONE_CALLS_WE_NEED_TO_TALK_WHEREAREWE: 'CommonBuffId' = 372700 + ROMANTIC_SAGE_SELF_SOOTHE: 'CommonBuffId' = 379089 + ROMANTIC_VENUES_BIRDS_AND_THE_BEES: 'CommonBuffId' = 369863 + ROMANTIC_VENUES_KISS_BEHIND_BOOKSHELF_CONFIDENT: 'CommonBuffId' = 365776 + ROMANTIC_VENUES_KISS_BEHIND_BOOKSHELF_EMBARRASSED: 'CommonBuffId' = 365774 + ROMANTIC_VENUES_SEDUCTIVE_DANCE_IS_DANCING_HIDDEN: 'CommonBuffId' = 392495 + ROMANTIC_VENUES_SHARING_THE_SUNSET: 'CommonBuffId' = 368838 + ROMANTIC_VENUES_SWING_AND_A_MISS: 'CommonBuffId' = 368839 + ROOMMATE_NPC_ARCHETYPE_BREAKER: 'CommonBuffId' = 220347 + ROOMMATE_NPC_ARCHETYPE_CHEERLEADER: 'CommonBuffId' = 211753 + ROOMMATE_NPC_ARCHETYPE_CLINGY_SOCIALITE: 'CommonBuffId' = 207922 + ROOMMATE_NPC_ARCHETYPE_COUCHPOTATO: 'CommonBuffId' = 207923 + ROOMMATE_NPC_ARCHETYPE_EMO_LONER: 'CommonBuffId' = 211750 + ROOMMATE_NPC_ARCHETYPE_FIXER: 'CommonBuffId' = 211754 + ROOMMATE_NPC_ARCHETYPE_LOUD_MUSIC: 'CommonBuffId' = 211752 + ROOMMATE_NPC_ARCHETYPE_MEALMAKER: 'CommonBuffId' = 207921 + ROOMMATE_NPC_ARCHETYPE_PARTY_PLANNER: 'CommonBuffId' = 211751 + ROOMMATE_NPC_ARCHETYPE_SUPER_NEAT: 'CommonBuffId' = 207920 + ROOMMATE_NPC_ARGUMENT_ANGER: 'CommonBuffId' = 223259 + ROOMMATE_NPC_ARGUMENT_SADNESS: 'CommonBuffId' = 223261 + ROOMMATE_NPC_CLEAN_UP_TIME: 'CommonBuffId' = 223504 + ROOMMATE_NPC_EVENTS_ARGUMENT: 'CommonBuffId' = 221659 + ROOMMATE_NPC_EVENTS_GET_HYPE: 'CommonBuffId' = 221657 + ROOMMATE_NPC_EVENTS_LOCKED_OUT: 'CommonBuffId' = 221656 + ROOMMATE_NPC_EVENTS_WHISPERS: 'CommonBuffId' = 221660 + ROOMMATE_NPC_EVENTS_WOOING: 'CommonBuffId' = 221658 + ROOMMATE_NPC_FOUND_A_NOTE: 'CommonBuffId' = 221632 + ROOMMATE_NPC_GETTING_HYPED: 'CommonBuffId' = 223271 + ROOMMATE_NPC_INTERESTS_ART: 'CommonBuffId' = 211756 + ROOMMATE_NPC_INTERESTS_BAKING: 'CommonBuffId' = 211755 + ROOMMATE_NPC_INTERESTS_COMPUTERS: 'CommonBuffId' = 207927 + ROOMMATE_NPC_INTERESTS_FITNESS: 'CommonBuffId' = 211757 + ROOMMATE_NPC_INTERESTS_MUSIC: 'CommonBuffId' = 207926 + ROOMMATE_NPC_KICKED_OUT: 'CommonBuffId' = 223354 + ROOMMATE_NPC_KICKED_OUT_ANGRY: 'CommonBuffId' = 229262 + ROOMMATE_NPC_LATE_ON_RENT_REFUSAL: 'CommonBuffId' = 223350 + ROOMMATE_NPC_LOUD_NOISES: 'CommonBuffId' = 223270 + ROOMMATE_NPC_PARTY_COOLDOWN: 'CommonBuffId' = 212082 + ROOMMATE_NPC_POTENTIAL: 'CommonBuffId' = 220988 + ROOMMATE_NPC_QUIRKS_ABSENT: 'CommonBuffId' = 211759 + ROOMMATE_NPC_QUIRKS_BATHROOM_HOG: 'CommonBuffId' = 207928 + ROOMMATE_NPC_QUIRKS_BIG_CLOSET: 'CommonBuffId' = 211760 + ROOMMATE_NPC_QUIRKS_LATE_ON_RENT: 'CommonBuffId' = 220346 + ROOMMATE_NPC_QUIRKS_PRANKSTER: 'CommonBuffId' = 211761 + ROOMMATE_NPC_QUIRKS_PUBLIC_AFFECTION_DISPLAYER: 'CommonBuffId' = 207929 + ROOMMATE_NPC_RECENT_INTERACTIONS_CLEANING: 'CommonBuffId' = 220403 + ROOMMATE_NPC_RECENT_INTERACTIONS_COMPLIMENT: 'CommonBuffId' = 220406 + ROOMMATE_NPC_RECENT_INTERACTIONS_FIXING: 'CommonBuffId' = 220404 + ROOMMATE_NPC_RECENT_INTERACTIONS_FOOD: 'CommonBuffId' = 220405 + ROOMMATE_NPC_RECENT_INTERACTIONS_NOTES: 'CommonBuffId' = 220422 + ROOMMATE_NPC_RECENT_INTERACTIONS_PUBLIC_AFFECTION: 'CommonBuffId' = 220423 + ROOMMATE_NPC_RECENT_INTERACTIONS_TRASH: 'CommonBuffId' = 220407 + ROOMMATE_NPC_ROOMMATE_DRAMA: 'CommonBuffId' = 221755 + ROOMMATE_NPC_STANDARD: 'CommonBuffId' = 208160 + ROOMMATE_NPC_UNEXPECTED_KINDNESS: 'CommonBuffId' = 221648 + ROOMMATE_NPC_WHISPER_ANGRY: 'CommonBuffId' = 223473 + ROOMMATE_NPC_WHISPER_FLIRTY: 'CommonBuffId' = 223474 + ROOMMATE_NPC_WHISPER_HAPPY: 'CommonBuffId' = 223477 + ROOMMATE_NPC_WHISPER_INSPIRED: 'CommonBuffId' = 223472 + ROOMMATE_NPC_WHISPER_SAD: 'CommonBuffId' = 223478 + ROOMMATE_NPC_WHISPER_SAD_WATCHING: 'CommonBuffId' = 223476 + ROOMMATE_NPC_WHISPER_STRESSED_WATCHING: 'CommonBuffId' = 223475 + ROOMMATE_NPC_WOOING_SPURNED: 'CommonBuffId' = 223471 + ROOT_BEER_FLOAT_GOOD_OLD_DAYS: 'CommonBuffId' = 124812 + ROUTE_USE_PHONE: 'CommonBuffId' = 273647 + ROUTE_USE_PHONE_PLAYER_ONLY: 'CommonBuffId' = 282929 + ROYALTY_TRENDING_VIDEO: 'CommonBuffId' = 196736 + S4CL_EXAMPLE_APPLY_BARE_FEET: 'CommonBuffId' = 16461769487103204847 + SABACC_TABLE_ACCUSE_OF_CHEATING_ACCUSED: 'CommonBuffId' = 241815 + SABACC_TABLE_ACCUSE_OF_CHEATING_ACCUSER: 'CommonBuffId' = 241791 + SABACC_TABLE_BETTING: 'CommonBuffId' = 251755 + SABACC_TABLE_BETWEEN_BETTING_PHASES: 'CommonBuffId' = 251712 + SABACC_TABLE_CANCELLED: 'CommonBuffId' = 251746 + SABACC_TABLE_CANT_CHEAT_ME: 'CommonBuffId' = 241923 + SABACC_TABLE_CAUGHT_SABACC_CHEAT: 'CommonBuffId' = 241922 + SABACC_TABLE_CHEATED: 'CommonBuffId' = 237259 + SABACC_TABLE_CHEAT_SLEIGHT_OF_HAND_ACCUSER_FAIL: 'CommonBuffId' = 241925 + SABACC_TABLE_CHEAT_SLEIGHT_OF_HAND_NOTHING_UP_MY_SLEEVE: 'CommonBuffId' = 241924 + SABACC_TABLE_END: 'CommonBuffId' = 250860 + SABACC_TABLE_EVERYONE_FOLDED_I_WIN: 'CommonBuffId' = 243664 + SABACC_TABLE_FOLDED: 'CommonBuffId' = 233815 + SABACC_TABLE_GRABBED_CARDS: 'CommonBuffId' = 234914 + SABACC_TABLE_IN_GAME: 'CommonBuffId' = 230955 + SABACC_TABLE_NPC_NOT_ALLOWED_TO_PLAY: 'CommonBuffId' = 247612 + SABACC_TABLE_PLAY: 'CommonBuffId' = 244249 + SABACC_TABLE_PLAY_STYLE_CONFIDENT: 'CommonBuffId' = 237241 + SABACC_TABLE_PLAY_STYLE_LOGICAL: 'CommonBuffId' = 237242 + SABACC_TABLE_SCORED: 'CommonBuffId' = 245562 + SABACC_TABLE_VISIBLE_CALCULATED_MOVE: 'CommonBuffId' = 237246 + SABACC_TABLE_VISIBLE_FISHING_FOR_A_BREAK: 'CommonBuffId' = 243382 + SABACC_TABLE_VISIBLE_IDIOTS_ARRAY: 'CommonBuffId' = 243379 + SABACC_TABLE_VISIBLE_KNACK_FOR_SABACC: 'CommonBuffId' = 243377 + SABACC_TABLE_VISIBLE_NOT_MY_CREDITS: 'CommonBuffId' = 243381 + SABACC_TABLE_VISIBLE_PAYDAY: 'CommonBuffId' = 243378 + SABACC_TABLE_VISIBLE_PURE_SABACC: 'CommonBuffId' = 243380 + SABACC_TABLE_VISIBLE_WHILE_NOONE_IS_WATCHING: 'CommonBuffId' = 243663 + SAD_MELANCHOLY_THOUGHTS: 'CommonBuffId' = 26764 + SAD_STARTLED_BY_GHOST: 'CommonBuffId' = 156627 + SAD_SUBTLY_DEBASE: 'CommonBuffId' = 35133 + SAMPLE_FOODS_COOKING_0: 'CommonBuffId' = 143582 + SAMPLE_FOODS_COOKING_2: 'CommonBuffId' = 143586 + SAMPLE_FOODS_COOKING_3: 'CommonBuffId' = 143588 + SAMPLE_FOODS_COOKING_4: 'CommonBuffId' = 143589 + SAMPLE_FOODS_COOKING_5: 'CommonBuffId' = 143591 + SAMPLE_FOODS_COOKING_INGREDIENTS_BAD: 'CommonBuffId' = 143593 + SAMPLE_FOODS_COOKING_INGREDIENTS_GOOD: 'CommonBuffId' = 143595 + SAMPLE_FOODS_NAUSEOUS_LITE: 'CommonBuffId' = 143627 + SANCTUARY_BANNED: 'CommonBuffId' = 345604 + SANCTUARY_COOLDOWN: 'CommonBuffId' = 356755 + SANCTUARY_DONATION: 'CommonBuffId' = 345649 + SANCTUARY_EMBARRASSED: 'CommonBuffId' = 345648 + SANCTUARY_HAPPY: 'CommonBuffId' = 345646 + SANCTUARY_HEIST: 'CommonBuffId' = 345650 + SANCTUARY_PLAYFUL: 'CommonBuffId' = 345647 + SAND_ACTIVITES_GOOD_TIMES: 'CommonBuffId' = 210227 + SAND_ACTIVITES_SAND_SCULPTURE_COOLDOWN: 'CommonBuffId' = 216237 + SAND_ACTIVITES_SAND_SCULPTURE_IS_BUILDING: 'CommonBuffId' = 212673 + SAND_ACTIVITES_SAND_SCULPTURE_MONSTER_STOMPER: 'CommonBuffId' = 210595 + SAND_ACTIVITES_SAND_SCULPTURE_RUINED: 'CommonBuffId' = 210597 + SAND_ACTIVITES_SAND_SCULPTURE_SCULPTOR: 'CommonBuffId' = 210584 + SAND_PLAY_BEACHY_MOOD: 'CommonBuffId' = 277483 + SAND_PLAY_ROMANCE_WRIT_LARGE: 'CommonBuffId' = 277487 + SAND_PLAY_SANDY_SENTIMENTALITY: 'CommonBuffId' = 277482 + SAND_PLAY_SMILES_FOR_MILES: 'CommonBuffId' = 277488 + SAND_PLAY_SNOWY_MOOD: 'CommonBuffId' = 277486 + SAND_PLAY_SNOWY_SENTIMENTALITY: 'CommonBuffId' = 277507 + SAND_PLAY_STARRY_SAND: 'CommonBuffId' = 277484 + SAND_PLAY_STARRY_SNOW: 'CommonBuffId' = 277485 + SCARECROW_ASK_FOR_GARDENING_TIPS: 'CommonBuffId' = 189830 + SCARECROW_CANT_CHECK_POCKETS: 'CommonBuffId' = 188657 + SCARECROW_HIDDEN_ASK_FOR_TIPS_COOLDOWN: 'CommonBuffId' = 191244 + SCARECROW_HIDDEN_JUST_BEFRIENDED: 'CommonBuffId' = 190220 + SCARECROW_REACT_CHILD_NEGATIVE: 'CommonBuffId' = 189324 + SCARECROW_REACT_CHILD_POSITIVE: 'CommonBuffId' = 189323 + SCARECROW_REACT_FOCUSED: 'CommonBuffId' = 189325 + SCARECROW_REACT_NEGATIVE: 'CommonBuffId' = 189321 + SCARECROW_REACT_POSITIVE: 'CommonBuffId' = 189322 + SCARECROW_SITUATION_IS_SCARECROW: 'CommonBuffId' = 190165 + SCARED_ENCOURAGEMENT: 'CommonBuffId' = 256498 + SCARED_SLEEPING_SCARED: 'CommonBuffId' = 253327 + SCENARIO_ALIEN_ABDUCTION_CANCEL_RABBIT_HOLE: 'CommonBuffId' = 305127 + SCENARIO_ALIEN_ABDUCTION_HIDDEN_OUTCOME_CANCEL_RABBIT_HOLE: 'CommonBuffId' = 305237 + SCENARIO_ALIEN_ABDUCTION_PARENTS: 'CommonBuffId' = 305125 + SCENARIO_CARNAVAL_DANCE: 'CommonBuffId' = 285818 + SCENARIO_EXPLORE_THE_NIGHT_NIGHT_TIME: 'CommonBuffId' = 302113 + SCENARIO_EXPLORE_THE_NIGHT_SLEEPING_OR_PASSED_OUT: 'CommonBuffId' = 302117 + SCENARIO_EXPLORE_THE_NIGHT_STAYED_UP: 'CommonBuffId' = 302059 + SCENARIO_EXPLORE_THE_NIGHT_STAY_UP: 'CommonBuffId' = 302114 + SCENARIO_GROUP_COOKED: 'CommonBuffId' = 281109 + SCENARIO_HONEYMOONERS_JUST_MARRIED_HIDDEN: 'CommonBuffId' = 280685 + SCENARIO_IN_THE_MOODLET_HIDDEN: 'CommonBuffId' = 296355 + SCENARIO_IN_THE_MOODLET_MOOD_ANGRY: 'CommonBuffId' = 296363 + SCENARIO_IN_THE_MOODLET_MOOD_EMBARRASSED: 'CommonBuffId' = 296362 + SCENARIO_IN_THE_MOODLET_MOOD_SAD: 'CommonBuffId' = 296364 + SCENARIO_IN_THE_MOODLET_MOOD_TENSE: 'CommonBuffId' = 296365 + SCENARIO_IN_THE_MOODLET_MOOD_UNCOMFORTABLE: 'CommonBuffId' = 296366 + SCENARIO_NO_SKILLS_NO_PROBLEM: 'CommonBuffId' = 282977 + SCENARIO_ON_BOARDING_NEW_IN_TOWN_EXPLORING_TOWN: 'CommonBuffId' = 297044 + SCENARIO_ON_BOARDING_NEW_IN_TOWN_GOALED_PARTY: 'CommonBuffId' = 297904 + SCENARIO_ON_BOARDING_NEW_IN_TOWN_PHASE_1_MET_NEW_PEOPLE: 'CommonBuffId' = 297685 + SCENARIO_ON_BOARDING_NEW_IN_TOWN_PHASE_3A_ATHLETIC_OUTFIT: 'CommonBuffId' = 295817 + SCENARIO_ON_BOARDING_NEW_IN_TOWN_PHASE_3B_PARTY_OUTFIT: 'CommonBuffId' = 295818 + SCENARIO_ON_BOARDING_NEW_IN_TOWN_PHASE_3X_DRANK_MOODLET_SOLVER_POTION: 'CommonBuffId' = 295819 + SCENARIO_ON_BOARDING_NEW_IN_TOWN_PHASE_4_BOUGHT_OBSERVANT_TRAIT: 'CommonBuffId' = 295821 + SCENARIO_ON_BOARDING_NEW_IN_TOWN_PHASE_4_CHOSE_DATE: 'CommonBuffId' = 300767 + SCENARIO_ON_BOARDING_NEW_IN_TOWN_PHASE_4_CHOSE_HANGOUT: 'CommonBuffId' = 300768 + SCENARIO_ON_BOARDING_NEW_IN_TOWN_PHASE_4_RELATIONSHIP_GAIN: 'CommonBuffId' = 297060 + SCENARIO_PARENTING_PREDICAMENTS_AGED_UP: 'CommonBuffId' = 307947 + SCENARIO_PARENTING_PREDICAMENTS_AGE_UP_IN_QUEUE: 'CommonBuffId' = 308323 + SCENARIO_PARENTING_PREDICAMENTS_BIRTHDAY_PARTY: 'CommonBuffId' = 298969 + SCENARIO_PARENTING_PREDICAMENTS_TEEN_DATE: 'CommonBuffId' = 298973 + SCENARIO_PROUD_PARENT_ADOPTED_BABY: 'CommonBuffId' = 300937 + SCENARIO_PROUD_PARENT_TEEN_TNS_GIVEN: 'CommonBuffId' = 301064 + SCENARIO_STUCK_IN_THEIR_SHADOW_1_INVITED_RIVAL: 'CommonBuffId' = 295446 + SCENIC_BROADCASTER_CLIFF_LOOKOUT: 'CommonBuffId' = 179592 + SCENIC_BROADCASTER_HIGH_POINT: 'CommonBuffId' = 179594 + SCENIC_BROADCASTER_NATURAL_POOL: 'CommonBuffId' = 179596 + SCENIC_BROADCASTER_SECRET_AREA: 'CommonBuffId' = 179595 + SCENIC_BROADCASTER_WATERFALL_VISTA: 'CommonBuffId' = 179593 + SCHOOL_PROJECT_BOX_DESTROYED_PROJECT_DESTROYER: 'CommonBuffId' = 165434 + SCHOOL_PROJECT_BOX_DESTROYED_PROJECT_OWNER_ANGRY: 'CommonBuffId' = 165460 + SCHOOL_PROJECT_BOX_DESTROYED_PROJECT_OWNER_SAD: 'CommonBuffId' = 165463 + SCHOOL_PROJECT_BOX_EXTRA_CREDIT_POTENTIAL: 'CommonBuffId' = 162792 + SCHOOL_PROJECT_BOX_FINISHED_PROJECT: 'CommonBuffId' = 163000 + SCHOOL_PROJECT_BOX_FINISHED_PROJECT_NORMAL_OR_HIGH_QUALITY: 'CommonBuffId' = 163634 + SCHOOL_PROJECT_BOX_FINISHED_PROJECT_POOR_QUALITY: 'CommonBuffId' = 163633 + SCHOOL_PROJECT_BOX_RECEIVE_PROGRESS_NEXT_SCHOOL_DAY: 'CommonBuffId' = 163467 + SCHOOL_PROJECT_BOX_WORKING_CAREFULLY: 'CommonBuffId' = 162991 + SCIENTIST_BREAKTHROUGH_ANIMATION: 'CommonBuffId' = 108411 + SCUBA_REBREATHER: 'CommonBuffId' = 206586 + SCUBA_WETSUIT: 'CommonBuffId' = 214157 + SEANCE_TABLE_AINT_AFRAID: 'CommonBuffId' = 251622 + SEANCE_TABLE_BONEHILDA: 'CommonBuffId' = 253381 + SEANCE_TABLE_BOTCHED_RITUAL: 'CommonBuffId' = 251623 + SEANCE_TABLE_GHOSTS_ARE_JERKS: 'CommonBuffId' = 251626 + SEANCE_TABLE_GHOST_FORM_HOUSEHOLD: 'CommonBuffId' = 255378 + SEANCE_TABLE_HAUNTING_MESSAGE: 'CommonBuffId' = 251628 + SEANCE_TABLE_MELANCHOLY_MALAISE: 'CommonBuffId' = 251629 + SEANCE_TABLE_NOT_VISIBLE_GHOST_FORM_CHECK: 'CommonBuffId' = 255364 + SEANCE_TABLE_NOT_VISIBLE_IN_SEANCE: 'CommonBuffId' = 255082 + SEANCE_TABLE_NOT_VISIBLE_SEANCE_EXIT: 'CommonBuffId' = 251973 + SEANCE_TABLE_NOT_VISIBLE_SUCCESFUL_CEREMONY: 'CommonBuffId' = 253105 + SEANCE_TABLE_OTHERWORLDLY_GUIDANCE: 'CommonBuffId' = 251624 + SEANCE_TABLE_SPECTRAL_SMALL_TALK: 'CommonBuffId' = 251627 + SEANCE_TABLE_SPELLCASTER: 'CommonBuffId' = 255933 + SEANCE_TABLE_UHH_WHAT: 'CommonBuffId' = 251625 + SEASONAL_THROWING_MUD_HAPPY: 'CommonBuffId' = 181562 + SEASONAL_THROWING_MUD_PLAYFUL: 'CommonBuffId' = 181565 + SEASONAL_THROWING_NAILED_MUD: 'CommonBuffId' = 181835 + SEASONAL_THROWING_NAILED_SNOWBALL: 'CommonBuffId' = 181560 + SEASONAL_THROWING_NAILED_WATER_BALLOON: 'CommonBuffId' = 181836 + SEASONAL_THROWING_SKILL_LEVEL_01: 'CommonBuffId' = 183320 + SEASONAL_THROWING_SKILL_LEVEL_02: 'CommonBuffId' = 183321 + SEASONAL_THROWING_SKILL_LEVEL_03: 'CommonBuffId' = 183322 + SEASONAL_THROWING_SKILL_LEVEL_04: 'CommonBuffId' = 183323 + SEASONAL_THROWING_SKILL_LEVEL_05: 'CommonBuffId' = 183319 + SEASONAL_THROWING_SNOWBALL_HAPPY: 'CommonBuffId' = 181566 + SEASONAL_THROWING_SNOWBALL_PLAYFUL: 'CommonBuffId' = 181563 + SEASONAL_THROWING_SNOWBALL_UNCOMFORTABLE: 'CommonBuffId' = 247475 + SEASONAL_THROWING_WATER_BALLOON_HAPPY: 'CommonBuffId' = 181564 + SEASONAL_THROWING_WATER_BALLOON_HIDDEN_WET: 'CommonBuffId' = 191359 + SEASONAL_THROWING_WATER_BALLOON_PLAYFUL: 'CommonBuffId' = 181561 + SEA_FOOD_COLORFUL_MEAL: 'CommonBuffId' = 352534 + SEA_FOOD_FILLING_ENTREE: 'CommonBuffId' = 352535 + SEA_FOOD_UNIQUE_BEVERAGE: 'CommonBuffId' = 352533 + SECRET_LAB_VENUE: 'CommonBuffId' = 203479 + SEEDS_OF_DOUBT: 'CommonBuffId' = 35125 + SELF_DISCOVERY_ANIMAL_CAT: 'CommonBuffId' = 335501 + SELF_DISCOVERY_ANIMAL_DOG: 'CommonBuffId' = 335500 + SELF_DISCOVERY_CAN_MAKE_PROGRESS: 'CommonBuffId' = 315849 + SELF_DISCOVERY_DISCOVERY_MOMENT: 'CommonBuffId' = 318056 + SELF_DISCOVERY_DISCOVERY_MOMENT_COOLDOWN: 'CommonBuffId' = 318344 + SELF_DISCOVERY_DISCOVERY_MOMENT_COOLDOWN_PARANOID: 'CommonBuffId' = 342234 + SELF_DISCOVERY_DISCOVERY_MOMENT_COOLDOWN_SQUEAMISH: 'CommonBuffId' = 342233 + SELF_DISCOVERY_HYGIENE_PAUSE: 'CommonBuffId' = 334984 + SELF_DISCOVERY_METABOLISM_DRANK_SPOILED_MILK: 'CommonBuffId' = 319212 + SELF_DISCOVERY_MOOD_CURRENT_SITUATION_ANGRY: 'CommonBuffId' = 334507 + SELF_DISCOVERY_MOOD_CURRENT_SITUATION_SAD: 'CommonBuffId' = 334508 + SELF_DISCOVERY_ROMANCE_REJECTED_SOCIALS: 'CommonBuffId' = 375926 + SELF_DISCOVERY_SCARED_ERRATIC: 'CommonBuffId' = 335008 + SELF_DISCOVERY_VIRTUES_ACT_PROPER: 'CommonBuffId' = 335005 + SENTIMENT_ADORING_CONFIDENT_CONSOLE_DEATH: 'CommonBuffId' = 273916 + SENTIMENT_ADORING_CONFIDENT_GENERIC: 'CommonBuffId' = 246891 + SENTIMENT_ADORING_CONFIDENT_IMPRESSED: 'CommonBuffId' = 246930 + SENTIMENT_ADORING_CONFIDENT_LIFESAVER: 'CommonBuffId' = 247280 + SENTIMENT_ADORING_HAPPY_CONTAGION_GENERIC: 'CommonBuffId' = 246886 + SENTIMENT_ADORING_HAPPY_PRIMARY_AMAZING_BEING: 'CommonBuffId' = 274240 + SENTIMENT_ADORING_HAPPY_PRIMARY_CONSOLE_DEATH: 'CommonBuffId' = 273917 + SENTIMENT_ADORING_HAPPY_PRIMARY_DECORATOR_GOOD_BUILD: 'CommonBuffId' = 268269 + SENTIMENT_ADORING_HAPPY_PRIMARY_GENERIC: 'CommonBuffId' = 246883 + SENTIMENT_ADORING_HAPPY_PRIMARY_GROWING_FAMILY: 'CommonBuffId' = 274149 + SENTIMENT_ADORING_HAPPY_PRIMARY_IMPRESSED: 'CommonBuffId' = 246948 + SENTIMENT_ADORING_HAPPY_PRIMARY_INFECTIOUS_JOY: 'CommonBuffId' = 274150 + SENTIMENT_ADORING_HAPPY_PRIMARY_LIFESAVER: 'CommonBuffId' = 247281 + SENTIMENT_ADORING_HAPPY_PRIMARY_TWIN_FLAMES: 'CommonBuffId' = 357662 + SENTIMENT_ADORING_HAPPY_PRIMARY_WITNESS_FOAL_BIRTH: 'CommonBuffId' = 338408 + SENTIMENT_ADORING_INSPIRED_CONSOLE_DEATH: 'CommonBuffId' = 273918 + SENTIMENT_ADORING_INSPIRED_GENERIC: 'CommonBuffId' = 246905 + SENTIMENT_ADORING_INSPIRED_IMPRESSED: 'CommonBuffId' = 246962 + SENTIMENT_ADORING_INSPIRED_LIFESAVER: 'CommonBuffId' = 247282 + SENTIMENT_ADORING_PLAYFUL_CONTAGION_INFECTIOUS_JOY: 'CommonBuffId' = 314926 + SENTIMENT_ADORING_PLAYFUL_WITNESS_FOAL_BIRTH: 'CommonBuffId' = 338411 + SENTIMENT_BITTER_ANGRY_BIT_AT_BY_HORSE: 'CommonBuffId' = 340340 + SENTIMENT_BITTER_ANGRY_BREAKUP: 'CommonBuffId' = 247302 + SENTIMENT_BITTER_ANGRY_CHEATING: 'CommonBuffId' = 247300 + SENTIMENT_BITTER_ANGRY_CRUMPLEBOTTOMED: 'CommonBuffId' = 264468 + SENTIMENT_BITTER_ANGRY_DIVORCE: 'CommonBuffId' = 247306 + SENTIMENT_BITTER_ANGRY_FIGHT: 'CommonBuffId' = 247316 + SENTIMENT_BITTER_ANGRY_GENERIC: 'CommonBuffId' = 241022 + SENTIMENT_BITTER_ANGRY_HIKING_TRAIL: 'CommonBuffId' = 250368 + SENTIMENT_BITTER_ANGRY_LIFESTYLE_WORKAHOLIC: 'CommonBuffId' = 252772 + SENTIMENT_BITTER_ANGRY_LIVESTOCK_SOLD: 'CommonBuffId' = 263678 + SENTIMENT_BITTER_ANGRY_MOUNTAIN_CLIMB: 'CommonBuffId' = 253627 + SENTIMENT_BITTER_ANGRY_MOUNTAIN_CLIMB_LT: 'CommonBuffId' = 254127 + SENTIMENT_BITTER_ANGRY_NOT_THAT_CUTE: 'CommonBuffId' = 274212 + SENTIMENT_BITTER_ANGRY_VILLAGE_FAIR_BRIBE_FAIL: 'CommonBuffId' = 268422 + SENTIMENT_BITTER_ANGRY_YOGA_CLASS: 'CommonBuffId' = 271981 + SENTIMENT_BITTER_CONTAGION_HAPPY_GENERIC: 'CommonBuffId' = 241018 + SENTIMENT_BITTER_CONTAGION_HAPPY_SIBLING_JEALOUSY: 'CommonBuffId' = 274221 + SENTIMENT_BITTER_TENSE_PRIMARY_BIT_AT_BY_HORSE: 'CommonBuffId' = 340339 + SENTIMENT_BITTER_TENSE_PRIMARY_BREAKUP: 'CommonBuffId' = 247304 + SENTIMENT_BITTER_TENSE_PRIMARY_CHEATING: 'CommonBuffId' = 247285 + SENTIMENT_BITTER_TENSE_PRIMARY_CRUMPLEBOTTOMED: 'CommonBuffId' = 264469 + SENTIMENT_BITTER_TENSE_PRIMARY_DIVORCE: 'CommonBuffId' = 247307 + SENTIMENT_BITTER_TENSE_PRIMARY_FIGHT: 'CommonBuffId' = 247317 + SENTIMENT_BITTER_TENSE_PRIMARY_GENERIC: 'CommonBuffId' = 241020 + SENTIMENT_BITTER_TENSE_PRIMARY_HIKING_TRAIL: 'CommonBuffId' = 251494 + SENTIMENT_BITTER_TENSE_PRIMARY_LIFESTYLE_WORKAHOLIC: 'CommonBuffId' = 252773 + SENTIMENT_BITTER_TENSE_PRIMARY_LIVESTOCK_SOLD: 'CommonBuffId' = 263701 + SENTIMENT_BITTER_TENSE_PRIMARY_MOUNTAIN_CLIMB: 'CommonBuffId' = 254128 + SENTIMENT_BITTER_TENSE_PRIMARY_MOUNTAIN_CLIMB_LT: 'CommonBuffId' = 254137 + SENTIMENT_BITTER_TENSE_PRIMARY_PHONE_BREAK_UP: 'CommonBuffId' = 375528 + SENTIMENT_BITTER_TENSE_PRIMARY_WHATS_SO_SPECIAL: 'CommonBuffId' = 274204 + SENTIMENT_BITTER_TENSE_PRIMARY_YOGA_CLASS: 'CommonBuffId' = 271980 + SENTIMENT_CLOSE_CONFIDENT_LOYAL_REGAINED_TRUST: 'CommonBuffId' = 312706 + SENTIMENT_CLOSE_CONFIDENT_STRONGER_TOGETHER: 'CommonBuffId' = 357664 + SENTIMENT_CLOSE_FLIRTY_GENERIC: 'CommonBuffId' = 240624 + SENTIMENT_CLOSE_HAPPY_CONTAGION_GENERIC: 'CommonBuffId' = 240622 + SENTIMENT_CLOSE_HAPPY_CONTAGION_NEAR_DEATH: 'CommonBuffId' = 247388 + SENTIMENT_CLOSE_HAPPY_PRIMARY_ADOPTION: 'CommonBuffId' = 247383 + SENTIMENT_CLOSE_HAPPY_PRIMARY_CANNING_RECEIVED_GIFT: 'CommonBuffId' = 262186 + SENTIMENT_CLOSE_HAPPY_PRIMARY_COTTAGE_WORLD_NPC_GOSSIP: 'CommonBuffId' = 264955 + SENTIMENT_CLOSE_HAPPY_PRIMARY_GENERIC: 'CommonBuffId' = 240626 + SENTIMENT_CLOSE_HAPPY_PRIMARY_GENERIC_LT: 'CommonBuffId' = 247337 + SENTIMENT_CLOSE_HAPPY_PRIMARY_GROUP_COOKING_COOKING_TOGETHER: 'CommonBuffId' = 262315 + SENTIMENT_CLOSE_HAPPY_PRIMARY_HAPPY_NEW_DYNAMIC: 'CommonBuffId' = 357663 + SENTIMENT_CLOSE_HAPPY_PRIMARY_HIKING_TRAIL: 'CommonBuffId' = 250367 + SENTIMENT_CLOSE_HAPPY_PRIMARY_HOTPOT: 'CommonBuffId' = 252799 + SENTIMENT_CLOSE_HAPPY_PRIMARY_LIFESTYLE_CLOSE_KNIT: 'CommonBuffId' = 252776 + SENTIMENT_CLOSE_HAPPY_PRIMARY_LIGHT_FESTIVAL_WISH: 'CommonBuffId' = 253249 + SENTIMENT_CLOSE_HAPPY_PRIMARY_LOYAL_REGAINED_TRUST: 'CommonBuffId' = 312702 + SENTIMENT_CLOSE_HAPPY_PRIMARY_LYCAN_BOND: 'CommonBuffId' = 288813 + SENTIMENT_CLOSE_HAPPY_PRIMARY_MOUNTAIN_CLIMB: 'CommonBuffId' = 254129 + SENTIMENT_CLOSE_HAPPY_PRIMARY_NEAR_DEATH: 'CommonBuffId' = 247387 + SENTIMENT_CLOSE_HAPPY_PRIMARY_ONSEN: 'CommonBuffId' = 252802 + SENTIMENT_CLOSE_HAPPY_PRIMARY_PARTY: 'CommonBuffId' = 247373 + SENTIMENT_CLOSE_HAPPY_PRIMARY_PICNIC_BASKET_PICNIC_BONDING: 'CommonBuffId' = 262187 + SENTIMENT_CLOSE_HAPPY_PRIMARY_QUALITY_TIME: 'CommonBuffId' = 247333 + SENTIMENT_CLOSE_HAPPY_PRIMARY_SNOW: 'CommonBuffId' = 252582 + SENTIMENT_CLOSE_HAPPY_PRIMARY_SNOW_FESTIVAL_PARTY: 'CommonBuffId' = 253205 + SENTIMENT_CLOSE_HAPPY_PRIMARY_SNOW_FESTIVAL_PLAY: 'CommonBuffId' = 253195 + SENTIMENT_CLOSE_HAPPY_PRIMARY_TEA_SET_TEA_PARTY: 'CommonBuffId' = 280850 + SENTIMENT_CLOSE_HAPPY_PRIMARY_TRUSTING: 'CommonBuffId' = 283864 + SENTIMENT_CLOSE_HAPPY_PRIMARY_VACATION_SNOWY: 'CommonBuffId' = 252437 + SENTIMENT_CLOSE_HAPPY_PRIMARY_VILLAGER_HELP_HELPED_OUT: 'CommonBuffId' = 266370 + SENTIMENT_CLOSE_HAPPY_PRIMARY_VILLAGE_FAIR_BRIBE_SUCCESS: 'CommonBuffId' = 268400 + SENTIMENT_CLOSE_HAPPY_PRIMARY_YOUTH_FESTIVAL_BLESSED: 'CommonBuffId' = 253250 + SENTIMENT_CLOSE_PLAYFUL_ADOPTION: 'CommonBuffId' = 247386 + SENTIMENT_CLOSE_PLAYFUL_CANNING_RECEIVED_GIFT: 'CommonBuffId' = 262189 + SENTIMENT_CLOSE_PLAYFUL_COTTAGE_WORLD_NPC_GOSSIP: 'CommonBuffId' = 264956 + SENTIMENT_CLOSE_PLAYFUL_GENERIC: 'CommonBuffId' = 240625 + SENTIMENT_CLOSE_PLAYFUL_GENERIC_LT: 'CommonBuffId' = 247350 + SENTIMENT_CLOSE_PLAYFUL_GROUP_COOKING_COOKING_TOGETHER: 'CommonBuffId' = 262320 + SENTIMENT_CLOSE_PLAYFUL_HIKING_TRAIL: 'CommonBuffId' = 254133 + SENTIMENT_CLOSE_PLAYFUL_HOTPOT: 'CommonBuffId' = 252801 + SENTIMENT_CLOSE_PLAYFUL_LIFESTYLE_CLOSE_KNIT: 'CommonBuffId' = 252778 + SENTIMENT_CLOSE_PLAYFUL_LIGHT_FESTIVAL_WISH: 'CommonBuffId' = 253252 + SENTIMENT_CLOSE_PLAYFUL_LYCAN_BOND: 'CommonBuffId' = 288814 + SENTIMENT_CLOSE_PLAYFUL_MOUNTAIN_CLIMB: 'CommonBuffId' = 254131 + SENTIMENT_CLOSE_PLAYFUL_NEAR_DEATH: 'CommonBuffId' = 247401 + SENTIMENT_CLOSE_PLAYFUL_ONSEN: 'CommonBuffId' = 252804 + SENTIMENT_CLOSE_PLAYFUL_PARTY: 'CommonBuffId' = 247375 + SENTIMENT_CLOSE_PLAYFUL_PICNIC_BASKET_PICNIC_BONDING: 'CommonBuffId' = 262188 + SENTIMENT_CLOSE_PLAYFUL_QUALITY_TIME: 'CommonBuffId' = 247335 + SENTIMENT_CLOSE_PLAYFUL_SNOW: 'CommonBuffId' = 252584 + SENTIMENT_CLOSE_PLAYFUL_SNOW_FESTIVAL_PARTY: 'CommonBuffId' = 253206 + SENTIMENT_CLOSE_PLAYFUL_SNOW_FESTIVAL_PLAY: 'CommonBuffId' = 253196 + SENTIMENT_CLOSE_PLAYFUL_TEA_SET_TEA_PARTY: 'CommonBuffId' = 280853 + SENTIMENT_CLOSE_PLAYFUL_VACATION_SNOWY: 'CommonBuffId' = 252438 + SENTIMENT_CLOSE_PLAYFUL_VILLAGER_HELP_HELPED_OUT: 'CommonBuffId' = 266371 + SENTIMENT_CLOSE_PLAYFUL_YOUTH_FESTIVAL_BLESSED: 'CommonBuffId' = 253251 + SENTIMENT_CLOSE_SAD_CONTAGION_GENERIC: 'CommonBuffId' = 240623 + SENTIMENT_CLOSE_SAD_CONTAGION_NEAR_DEATH: 'CommonBuffId' = 247389 + SENTIMENT_CLOSE_TENSE_LOYAL_REGAINED_TRUST: 'CommonBuffId' = 312707 + SENTIMENT_CRUSH_EMBARRASSED_GENERIC: 'CommonBuffId' = 273031 + SENTIMENT_CRUSH_FLIRTY_PRIMARY_GENERIC: 'CommonBuffId' = 272848 + SENTIMENT_CRUSH_HAPPY_GENERIC: 'CommonBuffId' = 273029 + SENTIMENT_CRUSH_SAD_GENERIC: 'CommonBuffId' = 273033 + SENTIMENT_CRUSH_TENSE_GENERIC: 'CommonBuffId' = 272849 + SENTIMENT_ENAMORED_DAZED_GENERIC: 'CommonBuffId' = 240997 + SENTIMENT_ENAMORED_EMBARRASSED_GENERIC: 'CommonBuffId' = 240994 + SENTIMENT_ENAMORED_EMBARRASSED_GENERIC_LT: 'CommonBuffId' = 247456 + SENTIMENT_ENAMORED_EMBARRASSED_LOYAL_SECOND_CHANCE: 'CommonBuffId' = 312679 + SENTIMENT_ENAMORED_FLIRTY_PRIMARY_CANNING_GIFTED_JAR: 'CommonBuffId' = 262185 + SENTIMENT_ENAMORED_FLIRTY_PRIMARY_COTTAG_EWORLD_RUINS: 'CommonBuffId' = 268487 + SENTIMENT_ENAMORED_FLIRTY_PRIMARY_FIRST_DANCE_TOGETHER: 'CommonBuffId' = 274230 + SENTIMENT_ENAMORED_FLIRTY_PRIMARY_FULL_MOON_FIRST_KISS: 'CommonBuffId' = 290600 + SENTIMENT_ENAMORED_FLIRTY_PRIMARY_GENERIC: 'CommonBuffId' = 240991 + SENTIMENT_ENAMORED_FLIRTY_PRIMARY_GENERIC_LT: 'CommonBuffId' = 247457 + SENTIMENT_ENAMORED_FLIRTY_PRIMARY_LIFESTYLES_SHARED: 'CommonBuffId' = 252446 + SENTIMENT_ENAMORED_FLIRTY_PRIMARY_LIGHT_FESTIVAL_KISS: 'CommonBuffId' = 253190 + SENTIMENT_ENAMORED_FLIRTY_PRIMARY_LOYAL_SECOND_CHANCE: 'CommonBuffId' = 312678 + SENTIMENT_ENAMORED_FLIRTY_PRIMARY_MOUNTAIN: 'CommonBuffId' = 252797 + SENTIMENT_ENAMORED_FLIRTY_PRIMARY_MOUNTAIN_CLIMB: 'CommonBuffId' = 252790 + SENTIMENT_ENAMORED_FLIRTY_PRIMARY_MOUNTAIN_NEIGHBORHOOD: 'CommonBuffId' = 252793 + SENTIMENT_ENAMORED_FLIRTY_PRIMARY_OPPOSITES: 'CommonBuffId' = 252443 + SENTIMENT_ENAMORED_FLIRTY_PRIMARY_PAIRED_DANCING_FIRST_DANCE: 'CommonBuffId' = 280854 + SENTIMENT_ENAMORED_FLIRTY_PRIMARY_SLEEP_CUDDLED: 'CommonBuffId' = 362536 + SENTIMENT_ENAMORED_HAPPY_CANNING_GIFTED_JAR: 'CommonBuffId' = 262180 + SENTIMENT_ENAMORED_HAPPY_COTTAGE_WORLD_RUINS: 'CommonBuffId' = 268486 + SENTIMENT_ENAMORED_HAPPY_FULL_MOON_FIRST_KISS: 'CommonBuffId' = 290601 + SENTIMENT_ENAMORED_HAPPY_GENERIC: 'CommonBuffId' = 240996 + SENTIMENT_ENAMORED_HAPPY_GENERIC_LT: 'CommonBuffId' = 247458 + SENTIMENT_ENAMORED_HAPPY_LIFESTYLES_SHARED: 'CommonBuffId' = 252447 + SENTIMENT_ENAMORED_HAPPY_LIGHT_FESTIVAL_KISS: 'CommonBuffId' = 253191 + SENTIMENT_ENAMORED_HAPPY_LOYAL_SECOND_CHANCE: 'CommonBuffId' = 312677 + SENTIMENT_ENAMORED_HAPPY_MOUNTAIN: 'CommonBuffId' = 252796 + SENTIMENT_ENAMORED_HAPPY_MOUNTAIN_CLIMB: 'CommonBuffId' = 252791 + SENTIMENT_ENAMORED_HAPPY_MOUNTAIN_NEIGHBORHOOD: 'CommonBuffId' = 252794 + SENTIMENT_ENAMORED_HAPPY_OPPOSITES: 'CommonBuffId' = 252444 + SENTIMENT_ENAMORED_HAPPY_PAIRED_DANCING_FIRST_DANCE: 'CommonBuffId' = 280855 + SENTIMENT_ENAMORED_HAPPY_SLEEP_CUDDLED: 'CommonBuffId' = 370704 + SENTIMENT_FURIOUS_ANGRY_PRIMARY_CHEATING: 'CommonBuffId' = 247462 + SENTIMENT_FURIOUS_ANGRY_PRIMARY_DECORATOR_BAD_BUILD: 'CommonBuffId' = 268261 + SENTIMENT_FURIOUS_ANGRY_PRIMARY_GENERIC: 'CommonBuffId' = 241005 + SENTIMENT_FURIOUS_ANGRY_PRIMARY_LIGHT_FESTIVAL_JEALOUS: 'CommonBuffId' = 253216 + SENTIMENT_FURIOUS_ANGRY_PRIMARY_WEDDING: 'CommonBuffId' = 247469 + SENTIMENT_FURIOUS_ANGRY_PRIMARY_WEDDING_PARTIES_EJECTED_GUEST: 'CommonBuffId' = 274214 + SENTIMENT_FURIOUS_ANGRY_PRIMARY_WHY_TODAY: 'CommonBuffId' = 357665 + SENTIMENT_FURIOUS_CONFIDENT_BETTER_OFF_NOW: 'CommonBuffId' = 357667 + SENTIMENT_FURIOUS_CONFIDENT_CHEATING: 'CommonBuffId' = 247463 + SENTIMENT_FURIOUS_CONFIDENT_GENERIC: 'CommonBuffId' = 241009 + SENTIMENT_FURIOUS_CONFIDENT_WEDDING: 'CommonBuffId' = 247471 + SENTIMENT_FURIOUS_CONTAGION_ANGRY_GENERIC: 'CommonBuffId' = 241003 + SENTIMENT_FURIOUS_CONTAGION_ANGRY_HAPPY_EX: 'CommonBuffId' = 357668 + SENTIMENT_FURIOUS_TENSE_CHEATING: 'CommonBuffId' = 247467 + SENTIMENT_FURIOUS_TENSE_GENERIC: 'CommonBuffId' = 241007 + SENTIMENT_FURIOUS_TENSE_LIGHT_FESTIVAL_JEALOUS: 'CommonBuffId' = 253217 + SENTIMENT_FURIOUS_TENSE_REMINDED_OF_PAIN: 'CommonBuffId' = 357666 + SENTIMENT_FURIOUS_TENSE_WEDDING: 'CommonBuffId' = 247472 + SENTIMENT_FURIOUS_TENSE_WEDDING_PARTIES_EJECTED_GUEST: 'CommonBuffId' = 280856 + SENTIMENT_GUILTY_BIG_SAD_WOLF: 'CommonBuffId' = 288506 + SENTIMENT_GUILTY_EMBARRASSED_AWKWARD_DATE: 'CommonBuffId' = 247561 + SENTIMENT_GUILTY_EMBARRASSED_BAD_PARTY: 'CommonBuffId' = 247570 + SENTIMENT_GUILTY_EMBARRASSED_GENERIC: 'CommonBuffId' = 247541 + SENTIMENT_GUILTY_EMBARRASSED_LIFESTYLE_CLOSE_KNIT: 'CommonBuffId' = 252786 + SENTIMENT_GUILTY_EMBARRASSED_MOUNTAIN_CLIMB: 'CommonBuffId' = 254134 + SENTIMENT_GUILTY_EMBARRASSED_VILLAGE_FAIR_BRIBE_FAIL: 'CommonBuffId' = 268430 + SENTIMENT_GUILTY_SAD_CONTAGION_GENERIC: 'CommonBuffId' = 247555 + SENTIMENT_GUILTY_SAD_PRIMARY_AWKWARD_DATE: 'CommonBuffId' = 247563 + SENTIMENT_GUILTY_SAD_PRIMARY_BAD_PARTY: 'CommonBuffId' = 247574 + SENTIMENT_GUILTY_SAD_PRIMARY_GENERIC: 'CommonBuffId' = 247540 + SENTIMENT_GUILTY_SAD_PRIMARY_LIFESTYLE_CLOSE_KNIT: 'CommonBuffId' = 252787 + SENTIMENT_GUILTY_SAD_PRIMARY_MOUNTAIN_CLIMB: 'CommonBuffId' = 254135 + SENTIMENT_GUILTY_TENSE_AWKWARD_DATE: 'CommonBuffId' = 247568 + SENTIMENT_GUILTY_TENSE_BAD_PARTY: 'CommonBuffId' = 247577 + SENTIMENT_GUILTY_TENSE_GENERIC: 'CommonBuffId' = 247544 + SENTIMENT_GUILTY_TENSE_LIFESTYLE_CLOSE_KNIT: 'CommonBuffId' = 252788 + SENTIMENT_GUILTY_TENSE_MOUNTAIN_CLIMB: 'CommonBuffId' = 254136 + SENTIMENT_HURT_ANGRY_GENERIC: 'CommonBuffId' = 247589 + SENTIMENT_HURT_ANGRY_GENERIC_LT: 'CommonBuffId' = 247591 + SENTIMENT_HURT_ANGRY_LIFESTYLE_NETWORKER: 'CommonBuffId' = 252774 + SENTIMENT_HURT_ANGRY_LIVESTOCK_SOLD: 'CommonBuffId' = 263702 + SENTIMENT_HURT_ANGRY_REJECTION: 'CommonBuffId' = 247592 + SENTIMENT_HURT_ANGRY_ROMANTIC: 'CommonBuffId' = 247593 + SENTIMENT_HURT_ANGRY_SADDENED: 'CommonBuffId' = 247594 + SENTIMENT_HURT_ANGRY_SOLD_MY_FRIEND: 'CommonBuffId' = 339249 + SENTIMENT_HURT_ANGRY_SUSPICIOUS: 'CommonBuffId' = 283867 + SENTIMENT_HURT_ANGRY_WHERES_MY_ATTENTION: 'CommonBuffId' = 274229 + SENTIMENT_HURT_ANGRY_YOUTH_FESTIVAL_UNBLESSED: 'CommonBuffId' = 253225 + SENTIMENT_HURT_SAD_PRIMARY_GENERIC: 'CommonBuffId' = 247583 + SENTIMENT_HURT_SAD_PRIMARY_GENERIC_LT: 'CommonBuffId' = 247584 + SENTIMENT_HURT_SAD_PRIMARY_LIFESTYLE_NETWORKER: 'CommonBuffId' = 252775 + SENTIMENT_HURT_SAD_PRIMARY_LIVESTOCK_SOLD: 'CommonBuffId' = 263703 + SENTIMENT_HURT_SAD_PRIMARY_NO_ATTENTION_LEFT: 'CommonBuffId' = 274228 + SENTIMENT_HURT_SAD_PRIMARY_REJECTION: 'CommonBuffId' = 247586 + SENTIMENT_HURT_SAD_PRIMARY_ROMANTIC: 'CommonBuffId' = 247585 + SENTIMENT_HURT_SAD_PRIMARY_SADDENED: 'CommonBuffId' = 247587 + SENTIMENT_HURT_SAD_PRIMARY_SOLD_MY_FRIEND: 'CommonBuffId' = 339248 + SENTIMENT_HURT_SAD_PRIMARY_SUSPICIOUS: 'CommonBuffId' = 283868 + SENTIMENT_HURT_SAD_PRIMARY_YOUTH_FESTIVAL_UNBLESSED: 'CommonBuffId' = 253226 + SENTIMENT_MOTIVATING_CONFIDENT_EPICALLY_INSPIRED: 'CommonBuffId' = 309532 + SENTIMENT_MOTIVATING_CONFIDENT_EXTREME_SPORTS: 'CommonBuffId' = 252865 + SENTIMENT_MOTIVATING_CONFIDENT_FRIENDLY_ADVICE: 'CommonBuffId' = 273841 + SENTIMENT_MOTIVATING_ENERGIZED_CHAMPION_PARTNER: 'CommonBuffId' = 338939 + SENTIMENT_MOTIVATING_ENERGIZED_PRIMARY_EPICALLY_INSPIRED: 'CommonBuffId' = 309533 + SENTIMENT_MOTIVATING_ENERGIZED_PRIMARY_EXTREME_SPORTS: 'CommonBuffId' = 252858 + SENTIMENT_MOTIVATING_ENERGIZED_PRIMARY_FRIENDLY_ADVICE: 'CommonBuffId' = 273843 + SENTIMENT_MOTIVATING_FOCUSED_EPICALLY_INSPIRED: 'CommonBuffId' = 309534 + SENTIMENT_MOTIVATING_FOCUSED_EXTREME_SPORTS: 'CommonBuffId' = 252867 + SENTIMENT_MOTIVATING_FOCUSED_FRIENDLY_ADVICE: 'CommonBuffId' = 273844 + SENTIMENT_MOTIVATING_INSPIRED_CHAMPION_PARTNER: 'CommonBuffId' = 338937 + SENT_TEXT_COOLDOWN: 'CommonBuffId' = 100672 + SERUMS_ALIEN_AURA: 'CommonBuffId' = 104809 + SERUMS_ALL_BY_MYSELF: 'CommonBuffId' = 104805 + SERUMS_ANGRY_REAPER: 'CommonBuffId' = 107032 + SERUMS_BAD_LUCK: 'CommonBuffId' = 104807 + SERUMS_BEST_WAY_TO_RECOVER: 'CommonBuffId' = 104788 + SERUMS_BRILLIANT: 'CommonBuffId' = 104798 + SERUMS_BURNING_LOVE: 'CommonBuffId' = 104793 + SERUMS_CANT_FIX_MY_HEART: 'CommonBuffId' = 104808 + SERUMS_DO_YOU_KNOW_WHO_I_AM: 'CommonBuffId' = 104800 + SERUMS_FEAR_THE_REAPER: 'CommonBuffId' = 104796 + SERUMS_FIXERS_LUCK: 'CommonBuffId' = 104806 + SERUMS_FIZZY_EXPLOSION: 'CommonBuffId' = 112562 + SERUMS_GHOSTLY: 'CommonBuffId' = 104795 + SERUMS_MAD_AS_AN_OX: 'CommonBuffId' = 104797 + SERUMS_NOT_FEELING_WELL: 'CommonBuffId' = 104801 + SERUMS_PLACEBO_EFFECT: 'CommonBuffId' = 104789 + SERUMS_RAVENOUS: 'CommonBuffId' = 104786 + SERUMS_REAPERS_FRIEND: 'CommonBuffId' = 104803 + SERUMS_REAPER_REVIVED_FRIEND: 'CommonBuffId' = 115941 + SERUMS_RED_HOT_SERUM: 'CommonBuffId' = 104787 + SERUMS_ROSE_PERFUME_SERUM: 'CommonBuffId' = 104792 + SERUMS_SELF_EXPERIMENTATION: 'CommonBuffId' = 105161 + SERUMS_SPARK_DRIVE: 'CommonBuffId' = 104802 + SERUMS_TEMPTED_FATE: 'CommonBuffId' = 104804 + SERUMS_THIS_IS_BELOW_ME: 'CommonBuffId' = 104799 + SERUMS_WANT_TO_HIDE: 'CommonBuffId' = 104794 + SERUMS_WEIGHT_DISPOSAL: 'CommonBuffId' = 104791 + SERUMS_YUM_SPICY: 'CommonBuffId' = 104790 + SERVICE_SKELETON_NEAR_SKELETON_COMMON: 'CommonBuffId' = 177833 + SERVICE_SKELETON_NEAR_SKELETON_RARE: 'CommonBuffId' = 177835 + SERVICE_SKELETON_OUTFIT: 'CommonBuffId' = 181546 + SEXUAL_ORIENTATION_BECAME_WOOHOO_PARTNERS: 'CommonBuffId' = 294525 + SEXUAL_ORIENTATION_REJECTED_WOOHOO_PARTNERS: 'CommonBuffId' = 294526 + SHARED_BIG_NEWS_HAPPY: 'CommonBuffId' = 97066 + SHARED_BIG_NEWS_TENSE: 'CommonBuffId' = 97067 + SHOE_REMOVAL_SIGN_APPEARANCE_MODIFIER_BARE_FOOT: 'CommonBuffId' = 248147 + SHOE_REMOVAL_SIGN_APPEARANCE_MODIFIER_SLIPPERS: 'CommonBuffId' = 248148 + SHOE_REMOVAL_SIGN_BREAKING_RULES: 'CommonBuffId' = 248809 + SHOE_REMOVAL_SIGN_CAUGHT_EMBARRASSED: 'CommonBuffId' = 246808 + SHOE_REMOVAL_SIGN_COMPLIANT: 'CommonBuffId' = 246502 + SHOE_REMOVAL_SIGN_EXEMPTION: 'CommonBuffId' = 255240 + SHOE_REMOVAL_SIGN_NON_COMPLIANT: 'CommonBuffId' = 246503 + SHOE_REMOVAL_SIGN_NOT_WEARING_SHOES_EXEMPTION: 'CommonBuffId' = 254337 + SHOE_REMOVAL_SIGN_SHOES_OFF: 'CommonBuffId' = 246486 + SHOE_REMOVAL_SIGN_SLIPPERS_ON: 'CommonBuffId' = 246487 + SHOWER_WOOHOO_EMBARRASSED: 'CommonBuffId' = 229217 + SHOWER_WOOHOO_GOOD: 'CommonBuffId' = 229219 + SHOWER_WOOHOO_SPECTACULAR: 'CommonBuffId' = 229218 + SHOWER_WOOHOO_UNCOMFORTABLE: 'CommonBuffId' = 229220 + SICKNESS_ATE_HUMAN_FOOD: 'CommonBuffId' = 169740 + SICKNESS_EXERCISED: 'CommonBuffId' = 169739 + SICKNESS_IMMUNITY_GENERAL: 'CommonBuffId' = 9971 + SICKNESS_IS_SICK: 'CommonBuffId' = 168173 + SICKNESS_NEED_TO_PUKE: 'CommonBuffId' = 98267 + SICKNESS_PET_ATE_SPOILED_FOOD: 'CommonBuffId' = 158936 + SICKNESS_SABOTAGED_FOOD_SPICY: 'CommonBuffId' = 187147 + SICKNESS_SABOTAGED_FOOD_STOMACH_MEDS: 'CommonBuffId' = 187150 + SICKNESS_SABOTAGED_FOOD_YUCK_FRUIT: 'CommonBuffId' = 187148 + SICKNESS_SYSTEM_DIAGNOSED_0_NONE: 'CommonBuffId' = 109669 + SICKNESS_SYSTEM_DIAGNOSED_0_NONE_DOCTOR: 'CommonBuffId' = 114226 + SICKNESS_SYSTEM_DIAGNOSED_1_NONE_CHANCE: 'CommonBuffId' = 109670 + SICKNESS_SYSTEM_DIAGNOSED_BLOATY_HEAD: 'CommonBuffId' = 108169 + SICKNESS_SYSTEM_DIAGNOSED_BURNING_TUMMY: 'CommonBuffId' = 108170 + SICKNESS_SYSTEM_DIAGNOSED_GAS_AND_GIGGLES: 'CommonBuffId' = 108171 + SICKNESS_SYSTEM_DIAGNOSED_ITCHY_PLUMBOB: 'CommonBuffId' = 108172 + SICKNESS_SYSTEM_DIAGNOSED_LLAMA_FLU: 'CommonBuffId' = 108173 + SICKNESS_SYSTEM_DIAGNOSED_STARRY_EYES: 'CommonBuffId' = 108174 + SICKNESS_SYSTEM_DIAGNOSED_SWEATY_SHIVERS: 'CommonBuffId' = 108176 + SICKNESS_SYSTEM_DIAGNOSED_TRIPLE_THREAT: 'CommonBuffId' = 108175 + SICKNESS_SYSTEM_DOCTOR_AWAY_EVENTS_PATIENT_COLLAPSED: 'CommonBuffId' = 113901 + SICKNESS_SYSTEM_DOCTOR_AWAY_EVENTS_PATIENT_EXAMINED: 'CommonBuffId' = 113898 + SICKNESS_SYSTEM_DOCTOR_BEDSIDE_MANNER_GOOD: 'CommonBuffId' = 109837 + SICKNESS_SYSTEM_DOCTOR_EXAM_RESULTS_BAD: 'CommonBuffId' = 109082 + SICKNESS_SYSTEM_FAKE_SICK_COOLDOWN: 'CommonBuffId' = 112152 + SICKNESS_SYSTEM_HYGIENIC_POD_CURED: 'CommonBuffId' = 115141 + SICKNESS_SYSTEM_ILLNESS_BLOATY_HEAD: 'CommonBuffId' = 105478 + SICKNESS_SYSTEM_ILLNESS_BURNING_TUMMY: 'CommonBuffId' = 105621 + SICKNESS_SYSTEM_ILLNESS_CRITICALITY_MILD: 'CommonBuffId' = 105605 + SICKNESS_SYSTEM_ILLNESS_CRITICALITY_SEVERE: 'CommonBuffId' = 105606 + SICKNESS_SYSTEM_ILLNESS_DURATION_COMMODITY_STATE_IMMUNE: 'CommonBuffId' = 106531 + SICKNESS_SYSTEM_ILLNESS_DURATION_COMMODITY_STATE_MILD: 'CommonBuffId' = 106528 + SICKNESS_SYSTEM_ILLNESS_DURATION_COMMODITY_STATE_REMISSION: 'CommonBuffId' = 106530 + SICKNESS_SYSTEM_ILLNESS_DURATION_COMMODITY_STATE_REMOVE: 'CommonBuffId' = 106532 + SICKNESS_SYSTEM_ILLNESS_DURATION_COMMODITY_STATE_SEVERE: 'CommonBuffId' = 106529 + SICKNESS_SYSTEM_ILLNESS_GAS_AND_GIGGLES: 'CommonBuffId' = 105620 + SICKNESS_SYSTEM_ILLNESS_HOME_REMEDY: 'CommonBuffId' = 108672 + SICKNESS_SYSTEM_ILLNESS_ITCHY_PLUMBOB: 'CommonBuffId' = 105619 + SICKNESS_SYSTEM_ILLNESS_LLAMA_FLU: 'CommonBuffId' = 105618 + SICKNESS_SYSTEM_ILLNESS_SEVERE_CONTRACTED: 'CommonBuffId' = 105573 + SICKNESS_SYSTEM_ILLNESS_STARRY_EYES: 'CommonBuffId' = 105617 + SICKNESS_SYSTEM_ILLNESS_SWEATY_SHIVERS: 'CommonBuffId' = 105616 + SICKNESS_SYSTEM_ILLNESS_TRIPLE_THREAT: 'CommonBuffId' = 105615 + SICKNESS_SYSTEM_ILLNESS_X_NONE_PATIENT: 'CommonBuffId' = 113783 + SICKNESS_SYSTEM_MAKE_SICK_TRIPLE_THREAT: 'CommonBuffId' = 114355 + SICKNESS_SYSTEM_PATIENT_COLLAPSED: 'CommonBuffId' = 113332 + SICKNESS_SYSTEM_PATIENT_DIAGNOSIS_COMMODITY_STATE_STAGE0: 'CommonBuffId' = 114827 + SICKNESS_SYSTEM_PATIENT_DIAGNOSIS_COMMODITY_STATE_STAGE0_DONE: 'CommonBuffId' = 114878 + SICKNESS_SYSTEM_PATIENT_DIAGNOSIS_COMMODITY_STATE_STAGE0_RECEIVED: 'CommonBuffId' = 114881 + SICKNESS_SYSTEM_PATIENT_DIAGNOSIS_COMMODITY_STATE_STAGE1: 'CommonBuffId' = 109564 + SICKNESS_SYSTEM_PATIENT_DIAGNOSIS_COMMODITY_STATE_STAGE2: 'CommonBuffId' = 109565 + SICKNESS_SYSTEM_PATIENT_DIAGNOSIS_COMMODITY_STATE_STAGE3: 'CommonBuffId' = 109566 + SICKNESS_SYSTEM_PATIENT_DIAGNOSIS_COMMODITY_STATE_STAGE4: 'CommonBuffId' = 109567 + SICKNESS_SYSTEM_PATIENT_EXAMINED_1: 'CommonBuffId' = 107990 + SICKNESS_SYSTEM_PATIENT_EXAMINED_2: 'CommonBuffId' = 107991 + SICKNESS_SYSTEM_PATIENT_EXAMINED_CHECK_EARS: 'CommonBuffId' = 112594 + SICKNESS_SYSTEM_PATIENT_EXAMINED_CHECK_EYES: 'CommonBuffId' = 112593 + SICKNESS_SYSTEM_PATIENT_EXAMINED_PROBE: 'CommonBuffId' = 112595 + SICKNESS_SYSTEM_PATIENT_EXAMINED_TAKE_TEMP: 'CommonBuffId' = 112592 + SICKNESS_SYSTEM_PATIENT_SAMPLE_TAKEN: 'CommonBuffId' = 111239 + SICKNESS_SYSTEM_SLEEP_SYMPTOM_SUPPRESSION: 'CommonBuffId' = 112148 + SICKNESS_SYSTEM_SYMPTOM_COUGH_SNEEZE_MILD: 'CommonBuffId' = 105746 + SICKNESS_SYSTEM_SYMPTOM_COUGH_SNEEZE_SEVERE: 'CommonBuffId' = 105761 + SICKNESS_SYSTEM_SYMPTOM_DIZZY_MILD: 'CommonBuffId' = 105747 + SICKNESS_SYSTEM_SYMPTOM_DIZZY_SEVERE: 'CommonBuffId' = 105762 + SICKNESS_SYSTEM_SYMPTOM_FEVER_MILD: 'CommonBuffId' = 105748 + SICKNESS_SYSTEM_SYMPTOM_FEVER_SEVERE: 'CommonBuffId' = 105763 + SICKNESS_SYSTEM_SYMPTOM_GIGGLY_MILD: 'CommonBuffId' = 105365 + SICKNESS_SYSTEM_SYMPTOM_GIGGLY_SEVERE: 'CommonBuffId' = 105769 + SICKNESS_SYSTEM_SYMPTOM_HEADACHE_MILD: 'CommonBuffId' = 105370 + SICKNESS_SYSTEM_SYMPTOM_HEADACHE_SEVERE: 'CommonBuffId' = 105764 + SICKNESS_SYSTEM_SYMPTOM_ITCHY_MILD: 'CommonBuffId' = 105354 + SICKNESS_SYSTEM_SYMPTOM_ITCHY_SEVERE: 'CommonBuffId' = 105765 + SICKNESS_SYSTEM_SYMPTOM_NAUSEA_MILD: 'CommonBuffId' = 105453 + SICKNESS_SYSTEM_SYMPTOM_NAUSEA_SEVERE: 'CommonBuffId' = 105766 + SICKNESS_SYSTEM_SYMPTOM_SEEING_THINGS_MILD: 'CommonBuffId' = 105436 + SICKNESS_SYSTEM_SYMPTOM_SEEING_THINGS_SEVERE: 'CommonBuffId' = 105767 + SICKNESS_SYSTEM_SYMPTOM_STEAMY_EARS_MILD: 'CommonBuffId' = 105749 + SICKNESS_SYSTEM_SYMPTOM_STEAMY_EARS_SEVERE: 'CommonBuffId' = 105768 + SICKNESS_SYSTEM_SYMPTOM_TRIGGER: 'CommonBuffId' = 105526 + SICKNESS_SYSTEM_TAKE_MEDICINE_CURED: 'CommonBuffId' = 108716 + SICKNESS_SYSTEM_TAKE_MEDICINE_DAZED: 'CommonBuffId' = 105661 + SIM_BASKED_IN_BRAVERY: 'CommonBuffId' = 340980 + SIM_BE_WOKEN_UP_HIDDEN: 'CommonBuffId' = 10314 + SIM_CELEBRITY_DISGUISE: 'CommonBuffId' = 201066 + SIM_CHANGE_DIAPER_DIAPER_DISASTER: 'CommonBuffId' = 311692 + SIM_CHANGE_DIAPER_DISASTER_COOLDOWN: 'CommonBuffId' = 315094 + SIM_CHAT_SHORTEN_DURATION: 'CommonBuffId' = 391582 + SIM_CHILLED_FROZEN_SPELL: 'CommonBuffId' = 220093 + SIM_CITY_LIFE_PHONE_CHATTER_ANGRY: 'CommonBuffId' = 143976 + SIM_CITY_LIFE_PHONE_CHATTER_HAPPY: 'CommonBuffId' = 143977 + SIM_CITY_LIFE_PHONE_CHATTER_SAD: 'CommonBuffId' = 143978 + SIM_CURIO_SHOP_TENDING_SHOP: 'CommonBuffId' = 206573 + SIM_CURRENTLY_MAKING_DRINK: 'CommonBuffId' = 100136 + SIM_DOCTOR_DELIVERED_BABY_RECENTLY: 'CommonBuffId' = 113111 + SIM_DOCTOR_RESEARCH_MEDICAL_INFO: 'CommonBuffId' = 112667 + SIM_DOCTOR_RESEARCH_MEDICAL_INFO_COOLDOWN: 'CommonBuffId' = 112668 + SIM_EQUINE_ENERGY: 'CommonBuffId' = 340731 + SIM_FEAR_GENIUS_WRONG: 'CommonBuffId' = 273098 + SIM_FIX_RELATIONSHIP_COOLDOWN: 'CommonBuffId' = 167101 + SIM_GARDENING_SKILLED_QUALITY_VFX: 'CommonBuffId' = 191601 + SIM_GARDENING_SKILLED_QUALITY_VFX_TIMED: 'CommonBuffId' = 191605 + SIM_HAS_BRAWLED_RECENTLY_HIDDEN: 'CommonBuffId' = 124816 + SIM_HAZMAT_SUIT: 'CommonBuffId' = 203478 + SIM_HELPING_A_HORSE_IN_NEED: 'CommonBuffId' = 340729 + SIM_HIDDEN_CHECK_TODDLER_COOLDOWN: 'CommonBuffId' = 155201 + SIM_HIDDEN_CHECK_TODDLER_FAILED_NO_OBJECT: 'CommonBuffId' = 157838 + SIM_HORSE_ALLY: 'CommonBuffId' = 340722 + SIM_IN_RESTAURANT: 'CommonBuffId' = 130714 + SIM_IN_SPORE_HALLWAY: 'CommonBuffId' = 207072 + SIM_IN_VET: 'CommonBuffId' = 158852 + SIM_IS_BAR_TENDING: 'CommonBuffId' = 29363 + SIM_IS_COOKING: 'CommonBuffId' = 10090 + SIM_IS_DRINKING: 'CommonBuffId' = 9272 + SIM_IS_DYING: 'CommonBuffId' = 26171 + SIM_IS_EATING: 'CommonBuffId' = 9273 + SIM_IS_IN_BATH: 'CommonBuffId' = 195626 + SIM_IS_PERFORMING: 'CommonBuffId' = 200372 + SIM_IS_SLEEPING: 'CommonBuffId' = 10094 + SIM_IS_SLEEPING_HIDDEN: 'CommonBuffId' = 275549 + SIM_IS_SWIMMING: 'CommonBuffId' = 206484 + SIM_IS_TALKING: 'CommonBuffId' = 8876 + SIM_LAMPOON: 'CommonBuffId' = 201402 + SIM_LAZY_WOKEN_UP: 'CommonBuffId' = 35850 + SIM_LEASHED_TO_DOG: 'CommonBuffId' = 165193 + SIM_LOVE_GURU_ROMANTIC_ASK_HIDDEN: 'CommonBuffId' = 153593 + SIM_LOVE_GURU_WISDOM_ASK_HIDDEN: 'CommonBuffId' = 153792 + SIM_MORNING_SICKNESS: 'CommonBuffId' = 39405 + SIM_MULTI_TO_CARRY_INFANT_PREVENT_IDLE: 'CommonBuffId' = 329298 + SIM_NEEDY_STEED: 'CommonBuffId' = 340728 + SIM_PETS_ALLOWED_TO_EAT_HUMAN_FOOD: 'CommonBuffId' = 172797 + SIM_PETS_ATTACKING_HIDDEN: 'CommonBuffId' = 167556 + SIM_PETS_BE_WOKEN_UP_HIDDEN: 'CommonBuffId' = 158663 + SIM_PETS_FEAR_QUIRK_RUN_AWAY_THOUGHT_BALLOON: 'CommonBuffId' = 168530 + SIM_PETS_MISBEHAVIOR_BARKING: 'CommonBuffId' = 178426 + SIM_PETS_MISBEHAVIOR_BEG_FOR_FOOD: 'CommonBuffId' = 172827 + SIM_PETS_MISBEHAVIOR_JUMP_ON_COUNTERS_DOGS: 'CommonBuffId' = 178490 + SIM_PETS_PET_BED_KICK_OUT_HIDDEN: 'CommonBuffId' = 166971 + SIM_PETS_RELAX_LARGE_DOG: 'CommonBuffId' = 178109 + SIM_PETS_RELAX_SMALL_PET: 'CommonBuffId' = 178110 + SIM_PETS_SOLD_FOR_ADOPTION: 'CommonBuffId' = 170541 + SIM_PET_DOG_NO_SHAKE_OFF_COOLDOWN: 'CommonBuffId' = 172179 + SIM_PREFERENCE_BAD_TIME_ANGRY: 'CommonBuffId' = 260012 + SIM_PREFERENCE_BAD_TIME_UNCOMFORTABLE: 'CommonBuffId' = 260011 + SIM_PREFERENCE_COLOR_HAS_DISLIKE: 'CommonBuffId' = 267923 + SIM_PREFERENCE_COLOR_HAS_LIKE: 'CommonBuffId' = 267922 + SIM_PREFERENCE_DECOR_REACTION_ART_DECO: 'CommonBuffId' = 325876 + SIM_PREFERENCE_DECOR_REACTION_BASICS: 'CommonBuffId' = 262128 + SIM_PREFERENCE_DECOR_REACTION_BOHO: 'CommonBuffId' = 262129 + SIM_PREFERENCE_DECOR_REACTION_CONTEMPORARY: 'CommonBuffId' = 262130 + SIM_PREFERENCE_DECOR_REACTION_COOLDOWN: 'CommonBuffId' = 263787 + SIM_PREFERENCE_DECOR_REACTION_COSMOLUX: 'CommonBuffId' = 262131 + SIM_PREFERENCE_DECOR_REACTION_CUTE: 'CommonBuffId' = 325877 + SIM_PREFERENCE_DECOR_REACTION_FRENCH_COUNTRY: 'CommonBuffId' = 262133 + SIM_PREFERENCE_DECOR_REACTION_GARDEN: 'CommonBuffId' = 262134 + SIM_PREFERENCE_DECOR_REACTION_GOTHIC_FARMHOUSE: 'CommonBuffId' = 262135 + SIM_PREFERENCE_DECOR_REACTION_INDUSTRIAL: 'CommonBuffId' = 325879 + SIM_PREFERENCE_DECOR_REACTION_ISLAND: 'CommonBuffId' = 262136 + SIM_PREFERENCE_DECOR_REACTION_LUXE: 'CommonBuffId' = 325878 + SIM_PREFERENCE_DECOR_REACTION_MISSION: 'CommonBuffId' = 262137 + SIM_PREFERENCE_DECOR_REACTION_MODERN: 'CommonBuffId' = 262138 + SIM_PREFERENCE_DECOR_REACTION_PATIO: 'CommonBuffId' = 262139 + SIM_PREFERENCE_DECOR_REACTION_QUEEN_ANNE: 'CommonBuffId' = 262140 + SIM_PREFERENCE_DECOR_REACTION_SCANDINAVIAN_CONTEMPORARY: 'CommonBuffId' = 262141 + SIM_PREFERENCE_DECOR_REACTION_SHABBY: 'CommonBuffId' = 326020 + SIM_PREFERENCE_DECOR_REACTION_SUBURBAN_CONTEMPORARY: 'CommonBuffId' = 262143 + SIM_PREFERENCE_DECOR_REACTION_TUDOR: 'CommonBuffId' = 262144 + SIM_PREFERENCE_DECOR_REACTION_VINTAGE: 'CommonBuffId' = 325880 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_ACTING: 'CommonBuffId' = 264113 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_BAKING: 'CommonBuffId' = 264114 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_BOWLING: 'CommonBuffId' = 264115 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_COMEDY: 'CommonBuffId' = 264117 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_COOKING: 'CommonBuffId' = 258397 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_CROSS_STITCH: 'CommonBuffId' = 274550 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_DANCING: 'CommonBuffId' = 264118 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_DEBATING: 'CommonBuffId' = 264126 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_DJ_MIXING: 'CommonBuffId' = 264134 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_EQUESTRIAN_SKILL: 'CommonBuffId' = 340003 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_FISHING: 'CommonBuffId' = 264119 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_FITNESS: 'CommonBuffId' = 258769 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_GARDENING: 'CommonBuffId' = 264120 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_GUITAR: 'CommonBuffId' = 264135 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_HANDINESS: 'CommonBuffId' = 264121 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_KNITTING: 'CommonBuffId' = 274541 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_MEDIA_PRODUCTION: 'CommonBuffId' = 264122 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_MISCHIEF: 'CommonBuffId' = 264123 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_MIXOLOGY: 'CommonBuffId' = 264124 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_NECTAR_MAKING: 'CommonBuffId' = 340004 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_PAINTING: 'CommonBuffId' = 258770 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_PHOTOGRAPHY: 'CommonBuffId' = 264125 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_PIANO: 'CommonBuffId' = 264136 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_PIPE_ORGAN: 'CommonBuffId' = 264137 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_PROGRAMMING: 'CommonBuffId' = 264781 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_ROBOTICS: 'CommonBuffId' = 264127 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_ROCKET_SCIENCE: 'CommonBuffId' = 264129 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_ROCK_CLIMBING: 'CommonBuffId' = 264128 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_SINGING: 'CommonBuffId' = 264138 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_SKIING: 'CommonBuffId' = 264130 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_SNOWBOARDING: 'CommonBuffId' = 264131 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_VIDEO_GAMING: 'CommonBuffId' = 258771 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_VIOLIN: 'CommonBuffId' = 258772 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_WELLNESS: 'CommonBuffId' = 264132 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_WRITING: 'CommonBuffId' = 264133 + SIM_PREFERENCE_DISLIKES_DECOR_ART_DECO: 'CommonBuffId' = 325865 + SIM_PREFERENCE_DISLIKES_DECOR_BASICS: 'CommonBuffId' = 263808 + SIM_PREFERENCE_DISLIKES_DECOR_BOHO: 'CommonBuffId' = 263809 + SIM_PREFERENCE_DISLIKES_DECOR_CONTEMPORARY: 'CommonBuffId' = 263810 + SIM_PREFERENCE_DISLIKES_DECOR_COSMOLUX: 'CommonBuffId' = 263811 + SIM_PREFERENCE_DISLIKES_DECOR_CUTE: 'CommonBuffId' = 325866 + SIM_PREFERENCE_DISLIKES_DECOR_FRENCH_COUNTRY: 'CommonBuffId' = 263815 + SIM_PREFERENCE_DISLIKES_DECOR_GARDEN: 'CommonBuffId' = 263816 + SIM_PREFERENCE_DISLIKES_DECOR_GOTHIC_FARMHOUSE: 'CommonBuffId' = 263818 + SIM_PREFERENCE_DISLIKES_DECOR_INDUSTRIAL: 'CommonBuffId' = 325867 + SIM_PREFERENCE_DISLIKES_DECOR_ISLAND: 'CommonBuffId' = 263819 + SIM_PREFERENCE_DISLIKES_DECOR_LUXE: 'CommonBuffId' = 325868 + SIM_PREFERENCE_DISLIKES_DECOR_MISSION: 'CommonBuffId' = 263820 + SIM_PREFERENCE_DISLIKES_DECOR_MODERN: 'CommonBuffId' = 263821 + SIM_PREFERENCE_DISLIKES_DECOR_PATIO: 'CommonBuffId' = 263822 + SIM_PREFERENCE_DISLIKES_DECOR_QUEEN_ANNE: 'CommonBuffId' = 263823 + SIM_PREFERENCE_DISLIKES_DECOR_SCANDINAVIAN_CONTEMPORARY: 'CommonBuffId' = 263824 + SIM_PREFERENCE_DISLIKES_DECOR_SHABBY: 'CommonBuffId' = 326016 + SIM_PREFERENCE_DISLIKES_DECOR_SUBURBAN_CONTEMPORARY: 'CommonBuffId' = 263826 + SIM_PREFERENCE_DISLIKES_DECOR_TUDOR: 'CommonBuffId' = 263827 + SIM_PREFERENCE_DISLIKES_DECOR_VINTAGE: 'CommonBuffId' = 325869 + SIM_PREFERENCE_DISLIKES_FASHION_BASICS: 'CommonBuffId' = 272724 + SIM_PREFERENCE_DISLIKES_FASHION_BOHO: 'CommonBuffId' = 283087 + SIM_PREFERENCE_DISLIKES_FASHION_COLOSSAL_FASHION_FAUX_PAX: 'CommonBuffId' = 284515 + SIM_PREFERENCE_DISLIKES_FASHION_COUNTRY: 'CommonBuffId' = 283090 + SIM_PREFERENCE_DISLIKES_FASHION_HIPSTER: 'CommonBuffId' = 283091 + SIM_PREFERENCE_DISLIKES_FASHION_OUTDOORSY: 'CommonBuffId' = 283092 + SIM_PREFERENCE_DISLIKES_FASHION_POLISHED: 'CommonBuffId' = 283093 + SIM_PREFERENCE_DISLIKES_FASHION_PREPPY: 'CommonBuffId' = 283094 + SIM_PREFERENCE_DISLIKES_FASHION_ROCKER: 'CommonBuffId' = 283095 + SIM_PREFERENCE_DISLIKES_FASHION_STREETWEAR: 'CommonBuffId' = 283096 + SIM_PREFERENCE_DISLIKES_MUSIC_ALTERNATIVE: 'CommonBuffId' = 258801 + SIM_PREFERENCE_DISLIKES_MUSIC_AMERICANA: 'CommonBuffId' = 265288 + SIM_PREFERENCE_DISLIKES_MUSIC_BACKYARD: 'CommonBuffId' = 265275 + SIM_PREFERENCE_DISLIKES_MUSIC_BAROQUE: 'CommonBuffId' = 265278 + SIM_PREFERENCE_DISLIKES_MUSIC_BATUU: 'CommonBuffId' = 346364 + SIM_PREFERENCE_DISLIKES_MUSIC_BLUES: 'CommonBuffId' = 258802 + SIM_PREFERENCE_DISLIKES_MUSIC_BRAZILIAN: 'CommonBuffId' = 346363 + SIM_PREFERENCE_DISLIKES_MUSIC_CLASSICAL: 'CommonBuffId' = 258803 + SIM_PREFERENCE_DISLIKES_MUSIC_COTTAGE_CORE: 'CommonBuffId' = 274581 + SIM_PREFERENCE_DISLIKES_MUSIC_DJ: 'CommonBuffId' = 267532 + SIM_PREFERENCE_DISLIKES_MUSIC_EASY_LISTENING: 'CommonBuffId' = 265274 + SIM_PREFERENCE_DISLIKES_MUSIC_ELECTRONICA: 'CommonBuffId' = 258804 + SIM_PREFERENCE_DISLIKES_MUSIC_FOCUS: 'CommonBuffId' = 265290 + SIM_PREFERENCE_DISLIKES_MUSIC_HIP_HOP: 'CommonBuffId' = 258805 + SIM_PREFERENCE_DISLIKES_MUSIC_ISLAND: 'CommonBuffId' = 265287 + SIM_PREFERENCE_DISLIKES_MUSIC_JAPANESE_FOLK: 'CommonBuffId' = 265289 + SIM_PREFERENCE_DISLIKES_MUSIC_JAZZ: 'CommonBuffId' = 265277 + SIM_PREFERENCE_DISLIKES_MUSIC_KIDS: 'CommonBuffId' = 258735 + SIM_PREFERENCE_DISLIKES_MUSIC_LATIN: 'CommonBuffId' = 265281 + SIM_PREFERENCE_DISLIKES_MUSIC_LATIN_POP: 'CommonBuffId' = 265282 + SIM_PREFERENCE_DISLIKES_MUSIC_LULLABIES: 'CommonBuffId' = 258806 + SIM_PREFERENCE_DISLIKES_MUSIC_METAL: 'CommonBuffId' = 265291 + SIM_PREFERENCE_DISLIKES_MUSIC_NEW_AGE: 'CommonBuffId' = 265276 + SIM_PREFERENCE_DISLIKES_MUSIC_NU_DISCO: 'CommonBuffId' = 265280 + SIM_PREFERENCE_DISLIKES_MUSIC_OLDIES: 'CommonBuffId' = 312261 + SIM_PREFERENCE_DISLIKES_MUSIC_POP: 'CommonBuffId' = 258701 + SIM_PREFERENCE_DISLIKES_MUSIC_RANCH: 'CommonBuffId' = 334860 + SIM_PREFERENCE_DISLIKES_MUSIC_RETRO: 'CommonBuffId' = 258807 + SIM_PREFERENCE_DISLIKES_MUSIC_RNB: 'CommonBuffId' = 343312 + SIM_PREFERENCE_DISLIKES_MUSIC_ROMANCE: 'CommonBuffId' = 258808 + SIM_PREFERENCE_DISLIKES_MUSIC_SINGER_SONGWRITER: 'CommonBuffId' = 265285 + SIM_PREFERENCE_DISLIKES_MUSIC_SPOOKY: 'CommonBuffId' = 258809 + SIM_PREFERENCE_DISLIKES_MUSIC_STRANGE_TUNES: 'CommonBuffId' = 265283 + SIM_PREFERENCE_DISLIKES_MUSIC_SUMMER_STRUT: 'CommonBuffId' = 265286 + SIM_PREFERENCE_DISLIKES_MUSIC_S_POP: 'CommonBuffId' = 258810 + SIM_PREFERENCE_DISLIKES_MUSIC_TWEEN_POP: 'CommonBuffId' = 265279 + SIM_PREFERENCE_DISLIKES_MUSIC_WINTER_HOLIDAY: 'CommonBuffId' = 258811 + SIM_PREFERENCE_DISLIKES_MUSIC_WORLD: 'CommonBuffId' = 265284 + SIM_PREFERENCE_FASHION_DISCOVERY_COOLDOWN: 'CommonBuffId' = 283299 + SIM_PREFERENCE_FASHION_RECOGNITION_COOLDOWN: 'CommonBuffId' = 272765 + SIM_PREFERENCE_GAIN_COOLDOWN: 'CommonBuffId' = 263631 + SIM_PREFERENCE_HAS_PREFERENCE_ACTIVITY: 'CommonBuffId' = 258402 + SIM_PREFERENCE_HAS_PREFERENCE_COLOR: 'CommonBuffId' = 258400 + SIM_PREFERENCE_HAS_PREFERENCE_DECOR: 'CommonBuffId' = 258404 + SIM_PREFERENCE_HAS_PREFERENCE_FASHION: 'CommonBuffId' = 272664 + SIM_PREFERENCE_HAS_PREFERENCE_MUSIC: 'CommonBuffId' = 258403 + SIM_PREFERENCE_IDLE_COOLDOWN: 'CommonBuffId' = 269253 + SIM_PREFERENCE_LIKES_ACTIVITIES_ACTING: 'CommonBuffId' = 264201 + SIM_PREFERENCE_LIKES_ACTIVITIES_BAKING: 'CommonBuffId' = 264202 + SIM_PREFERENCE_LIKES_ACTIVITIES_BOWLING: 'CommonBuffId' = 264203 + SIM_PREFERENCE_LIKES_ACTIVITIES_COMEDY: 'CommonBuffId' = 264204 + SIM_PREFERENCE_LIKES_ACTIVITIES_COOKING: 'CommonBuffId' = 258394 + SIM_PREFERENCE_LIKES_ACTIVITIES_CROSS_STITCH: 'CommonBuffId' = 274551 + SIM_PREFERENCE_LIKES_ACTIVITIES_DANCING: 'CommonBuffId' = 264205 + SIM_PREFERENCE_LIKES_ACTIVITIES_DEBATING: 'CommonBuffId' = 264206 + SIM_PREFERENCE_LIKES_ACTIVITIES_DJ_MIXING: 'CommonBuffId' = 264207 + SIM_PREFERENCE_LIKES_ACTIVITIES_EQUESTRIAN_SKILL: 'CommonBuffId' = 340005 + SIM_PREFERENCE_LIKES_ACTIVITIES_FISHING: 'CommonBuffId' = 264208 + SIM_PREFERENCE_LIKES_ACTIVITIES_FITNESS: 'CommonBuffId' = 258773 + SIM_PREFERENCE_LIKES_ACTIVITIES_GARDENING: 'CommonBuffId' = 264209 + SIM_PREFERENCE_LIKES_ACTIVITIES_GUITAR: 'CommonBuffId' = 264210 + SIM_PREFERENCE_LIKES_ACTIVITIES_HANDINESS: 'CommonBuffId' = 264212 + SIM_PREFERENCE_LIKES_ACTIVITIES_KNITTING: 'CommonBuffId' = 274542 + SIM_PREFERENCE_LIKES_ACTIVITIES_MEDIA_PRODUCTION: 'CommonBuffId' = 264211 + SIM_PREFERENCE_LIKES_ACTIVITIES_MISCHIEF: 'CommonBuffId' = 264213 + SIM_PREFERENCE_LIKES_ACTIVITIES_MIXOLOGY: 'CommonBuffId' = 264214 + SIM_PREFERENCE_LIKES_ACTIVITIES_NECTAR_MAKING: 'CommonBuffId' = 340006 + SIM_PREFERENCE_LIKES_ACTIVITIES_PAINTING: 'CommonBuffId' = 258774 + SIM_PREFERENCE_LIKES_ACTIVITIES_PHOTOGRAPHY: 'CommonBuffId' = 264215 + SIM_PREFERENCE_LIKES_ACTIVITIES_PIANO: 'CommonBuffId' = 264216 + SIM_PREFERENCE_LIKES_ACTIVITIES_PIPE_ORGAN: 'CommonBuffId' = 264217 + SIM_PREFERENCE_LIKES_ACTIVITIES_PROGRAMMING: 'CommonBuffId' = 264780 + SIM_PREFERENCE_LIKES_ACTIVITIES_ROBOTICS: 'CommonBuffId' = 264218 + SIM_PREFERENCE_LIKES_ACTIVITIES_ROCKET_SCIENCE: 'CommonBuffId' = 264220 + SIM_PREFERENCE_LIKES_ACTIVITIES_ROCK_CLIMBING: 'CommonBuffId' = 264219 + SIM_PREFERENCE_LIKES_ACTIVITIES_SINGING: 'CommonBuffId' = 264221 + SIM_PREFERENCE_LIKES_ACTIVITIES_SKIING: 'CommonBuffId' = 264222 + SIM_PREFERENCE_LIKES_ACTIVITIES_SNOWBOARDING: 'CommonBuffId' = 264223 + SIM_PREFERENCE_LIKES_ACTIVITIES_VIDEO_GAMING: 'CommonBuffId' = 258775 + SIM_PREFERENCE_LIKES_ACTIVITIES_VIOLIN: 'CommonBuffId' = 258776 + SIM_PREFERENCE_LIKES_ACTIVITIES_WELLNESS: 'CommonBuffId' = 264224 + SIM_PREFERENCE_LIKES_ACTIVITIES_WRITING: 'CommonBuffId' = 264225 + SIM_PREFERENCE_LIKES_DECOR_ART_DECO: 'CommonBuffId' = 325870 + SIM_PREFERENCE_LIKES_DECOR_BASICS: 'CommonBuffId' = 263790 + SIM_PREFERENCE_LIKES_DECOR_BOHO: 'CommonBuffId' = 263791 + SIM_PREFERENCE_LIKES_DECOR_CONTEMPORARY: 'CommonBuffId' = 263792 + SIM_PREFERENCE_LIKES_DECOR_COSMOLUX: 'CommonBuffId' = 263793 + SIM_PREFERENCE_LIKES_DECOR_CUTE: 'CommonBuffId' = 325871 + SIM_PREFERENCE_LIKES_DECOR_FRENCH_COUNTRY: 'CommonBuffId' = 263795 + SIM_PREFERENCE_LIKES_DECOR_GARDEN: 'CommonBuffId' = 263796 + SIM_PREFERENCE_LIKES_DECOR_GOTHIC_FARMHOUSE: 'CommonBuffId' = 263797 + SIM_PREFERENCE_LIKES_DECOR_INDUSTRIAL: 'CommonBuffId' = 325872 + SIM_PREFERENCE_LIKES_DECOR_ISLAND: 'CommonBuffId' = 263798 + SIM_PREFERENCE_LIKES_DECOR_LUXE: 'CommonBuffId' = 325873 + SIM_PREFERENCE_LIKES_DECOR_MISSION: 'CommonBuffId' = 263799 + SIM_PREFERENCE_LIKES_DECOR_MODERN: 'CommonBuffId' = 263800 + SIM_PREFERENCE_LIKES_DECOR_PATIO: 'CommonBuffId' = 263801 + SIM_PREFERENCE_LIKES_DECOR_QUEEN_ANNE: 'CommonBuffId' = 263802 + SIM_PREFERENCE_LIKES_DECOR_SCANDINAVIAN_CONTEMPORARY: 'CommonBuffId' = 263803 + SIM_PREFERENCE_LIKES_DECOR_SHABBY: 'CommonBuffId' = 326015 + SIM_PREFERENCE_LIKES_DECOR_SUBURBAN_CONTEMPORARY: 'CommonBuffId' = 263805 + SIM_PREFERENCE_LIKES_DECOR_TUDOR: 'CommonBuffId' = 263806 + SIM_PREFERENCE_LIKES_DECOR_VINTAGE: 'CommonBuffId' = 325874 + SIM_PREFERENCE_LIKES_FASHION_BASICS: 'CommonBuffId' = 272653 + SIM_PREFERENCE_LIKES_FASHION_BOHO: 'CommonBuffId' = 283098 + SIM_PREFERENCE_LIKES_FASHION_COUNTRY: 'CommonBuffId' = 283100 + SIM_PREFERENCE_LIKES_FASHION_DEDICATED_FOLLOWER_OF_FASHION: 'CommonBuffId' = 284514 + SIM_PREFERENCE_LIKES_FASHION_HIPSTER: 'CommonBuffId' = 283101 + SIM_PREFERENCE_LIKES_FASHION_OUTDOORSY: 'CommonBuffId' = 283102 + SIM_PREFERENCE_LIKES_FASHION_POLISHED: 'CommonBuffId' = 283103 + SIM_PREFERENCE_LIKES_FASHION_PREPPY: 'CommonBuffId' = 283104 + SIM_PREFERENCE_LIKES_FASHION_ROCKER: 'CommonBuffId' = 283105 + SIM_PREFERENCE_LIKES_FASHION_STREETWEAR: 'CommonBuffId' = 283107 + SIM_PREFERENCE_LIKES_MUSIC_ALTERNATIVE: 'CommonBuffId' = 258790 + SIM_PREFERENCE_LIKES_MUSIC_AMERICANA: 'CommonBuffId' = 265306 + SIM_PREFERENCE_LIKES_MUSIC_BACKYARD: 'CommonBuffId' = 265293 + SIM_PREFERENCE_LIKES_MUSIC_BAROQUE: 'CommonBuffId' = 265297 + SIM_PREFERENCE_LIKES_MUSIC_BATUU: 'CommonBuffId' = 346362 + SIM_PREFERENCE_LIKES_MUSIC_BLUES: 'CommonBuffId' = 258791 + SIM_PREFERENCE_LIKES_MUSIC_BRAZILIAN: 'CommonBuffId' = 346361 + SIM_PREFERENCE_LIKES_MUSIC_CLASSICAL: 'CommonBuffId' = 258792 + SIM_PREFERENCE_LIKES_MUSIC_COTTAGE_CORE: 'CommonBuffId' = 274582 + SIM_PREFERENCE_LIKES_MUSIC_DJ: 'CommonBuffId' = 267533 + SIM_PREFERENCE_LIKES_MUSIC_EASY_LISTENING: 'CommonBuffId' = 265292 + SIM_PREFERENCE_LIKES_MUSIC_ELECTRONICA: 'CommonBuffId' = 258793 + SIM_PREFERENCE_LIKES_MUSIC_FOCUS: 'CommonBuffId' = 265308 + SIM_PREFERENCE_LIKES_MUSIC_HIP_HOP: 'CommonBuffId' = 258794 + SIM_PREFERENCE_LIKES_MUSIC_ISLAND: 'CommonBuffId' = 265304 + SIM_PREFERENCE_LIKES_MUSIC_JAPANESE_FOLK: 'CommonBuffId' = 265307 + SIM_PREFERENCE_LIKES_MUSIC_JAZZ: 'CommonBuffId' = 265295 + SIM_PREFERENCE_LIKES_MUSIC_KIDS: 'CommonBuffId' = 258734 + SIM_PREFERENCE_LIKES_MUSIC_LATIN: 'CommonBuffId' = 265299 + SIM_PREFERENCE_LIKES_MUSIC_LATIN_POP: 'CommonBuffId' = 265300 + SIM_PREFERENCE_LIKES_MUSIC_LULLABIES: 'CommonBuffId' = 258795 + SIM_PREFERENCE_LIKES_MUSIC_METAL: 'CommonBuffId' = 265309 + SIM_PREFERENCE_LIKES_MUSIC_NEW_AGE: 'CommonBuffId' = 265294 + SIM_PREFERENCE_LIKES_MUSIC_NU_DISCO: 'CommonBuffId' = 265298 + SIM_PREFERENCE_LIKES_MUSIC_OLDIES: 'CommonBuffId' = 312262 + SIM_PREFERENCE_LIKES_MUSIC_POP: 'CommonBuffId' = 258699 + SIM_PREFERENCE_LIKES_MUSIC_RANCH: 'CommonBuffId' = 334861 + SIM_PREFERENCE_LIKES_MUSIC_RETRO: 'CommonBuffId' = 258796 + SIM_PREFERENCE_LIKES_MUSIC_RNB: 'CommonBuffId' = 343315 + SIM_PREFERENCE_LIKES_MUSIC_ROMANCE: 'CommonBuffId' = 258797 + SIM_PREFERENCE_LIKES_MUSIC_SINGER_SONGWRITER: 'CommonBuffId' = 265395 + SIM_PREFERENCE_LIKES_MUSIC_SPOOKY: 'CommonBuffId' = 258798 + SIM_PREFERENCE_LIKES_MUSIC_STRANGE_TUNES: 'CommonBuffId' = 265301 + SIM_PREFERENCE_LIKES_MUSIC_SUMMER_STRUT: 'CommonBuffId' = 265303 + SIM_PREFERENCE_LIKES_MUSIC_S_POP: 'CommonBuffId' = 258799 + SIM_PREFERENCE_LIKES_MUSIC_TWEEN_POP: 'CommonBuffId' = 265396 + SIM_PREFERENCE_LIKES_MUSIC_WINTER_HOLIDAY: 'CommonBuffId' = 258800 + SIM_PREFERENCE_LIKES_MUSIC_WORLD: 'CommonBuffId' = 265302 + SIM_PREFERENCE_NO_GOOD_ENVIRONMENT: 'CommonBuffId' = 268284 + SIM_PREFERENCE_RECENT_DECOR_ART_DECO: 'CommonBuffId' = 325927 + SIM_PREFERENCE_RECENT_DECOR_BASICS: 'CommonBuffId' = 325929 + SIM_PREFERENCE_RECENT_DECOR_BOHO: 'CommonBuffId' = 325940 + SIM_PREFERENCE_RECENT_DECOR_CONTEMPORARY: 'CommonBuffId' = 325941 + SIM_PREFERENCE_RECENT_DECOR_COSMO_LUX: 'CommonBuffId' = 325942 + SIM_PREFERENCE_RECENT_DECOR_CUTE: 'CommonBuffId' = 325943 + SIM_PREFERENCE_RECENT_DECOR_FRENCH_COUNTRY: 'CommonBuffId' = 325944 + SIM_PREFERENCE_RECENT_DECOR_GARDEN: 'CommonBuffId' = 325945 + SIM_PREFERENCE_RECENT_DECOR_GOTHIC_FARMHOUSE: 'CommonBuffId' = 325946 + SIM_PREFERENCE_RECENT_DECOR_INDUSTRIAL: 'CommonBuffId' = 325947 + SIM_PREFERENCE_RECENT_DECOR_ISLAND: 'CommonBuffId' = 325948 + SIM_PREFERENCE_RECENT_DECOR_LUXE: 'CommonBuffId' = 325949 + SIM_PREFERENCE_RECENT_DECOR_MISSION: 'CommonBuffId' = 325950 + SIM_PREFERENCE_RECENT_DECOR_MODERN: 'CommonBuffId' = 325951 + SIM_PREFERENCE_RECENT_DECOR_PATIO: 'CommonBuffId' = 325952 + SIM_PREFERENCE_RECENT_DECOR_QUEEN_ANNE: 'CommonBuffId' = 325953 + SIM_PREFERENCE_RECENT_DECOR_SCANDINAVIAN_CONTEMPORARY: 'CommonBuffId' = 325954 + SIM_PREFERENCE_RECENT_DECOR_SHABBY: 'CommonBuffId' = 326019 + SIM_PREFERENCE_RECENT_DECOR_SUBURBAN_CONTEMPORARY: 'CommonBuffId' = 325957 + SIM_PREFERENCE_RECENT_DECOR_TUDOR: 'CommonBuffId' = 325955 + SIM_PREFERENCE_RECENT_DECOR_VINTAGE: 'CommonBuffId' = 325956 + SIM_PREFERENCE_RECENT_DISLIKES_ACTING: 'CommonBuffId' = 264362 + SIM_PREFERENCE_RECENT_DISLIKES_BAKING: 'CommonBuffId' = 264363 + SIM_PREFERENCE_RECENT_DISLIKES_BOWLING: 'CommonBuffId' = 264364 + SIM_PREFERENCE_RECENT_DISLIKES_COMEDY: 'CommonBuffId' = 264365 + SIM_PREFERENCE_RECENT_DISLIKES_COOKING: 'CommonBuffId' = 259487 + SIM_PREFERENCE_RECENT_DISLIKES_CROSS_STITCH: 'CommonBuffId' = 274552 + SIM_PREFERENCE_RECENT_DISLIKES_DANCING: 'CommonBuffId' = 264366 + SIM_PREFERENCE_RECENT_DISLIKES_DEBATING: 'CommonBuffId' = 264367 + SIM_PREFERENCE_RECENT_DISLIKES_DJ_MIXING: 'CommonBuffId' = 264368 + SIM_PREFERENCE_RECENT_DISLIKES_EQUESTRIAN_SKILL: 'CommonBuffId' = 340007 + SIM_PREFERENCE_RECENT_DISLIKES_FISHING: 'CommonBuffId' = 264369 + SIM_PREFERENCE_RECENT_DISLIKES_FITNESS: 'CommonBuffId' = 259490 + SIM_PREFERENCE_RECENT_DISLIKES_GARDENING: 'CommonBuffId' = 264370 + SIM_PREFERENCE_RECENT_DISLIKES_GUITAR: 'CommonBuffId' = 264371 + SIM_PREFERENCE_RECENT_DISLIKES_HANDINESS: 'CommonBuffId' = 264372 + SIM_PREFERENCE_RECENT_DISLIKES_KNITTING: 'CommonBuffId' = 274544 + SIM_PREFERENCE_RECENT_DISLIKES_MEDIA_PRODUCTION: 'CommonBuffId' = 264373 + SIM_PREFERENCE_RECENT_DISLIKES_MISCHIEF: 'CommonBuffId' = 264374 + SIM_PREFERENCE_RECENT_DISLIKES_MIXOLOGY: 'CommonBuffId' = 264375 + SIM_PREFERENCE_RECENT_DISLIKES_NECTAR_MAKING: 'CommonBuffId' = 340008 + SIM_PREFERENCE_RECENT_DISLIKES_PAINTING: 'CommonBuffId' = 259488 + SIM_PREFERENCE_RECENT_DISLIKES_PHOTOGRAPHY: 'CommonBuffId' = 264376 + SIM_PREFERENCE_RECENT_DISLIKES_PIANO: 'CommonBuffId' = 264377 + SIM_PREFERENCE_RECENT_DISLIKES_PIPE_ORGAN: 'CommonBuffId' = 264408 + SIM_PREFERENCE_RECENT_DISLIKES_PROGRAMMING: 'CommonBuffId' = 264786 + SIM_PREFERENCE_RECENT_DISLIKES_ROBOTICS: 'CommonBuffId' = 264378 + SIM_PREFERENCE_RECENT_DISLIKES_ROCKET_SCIENCE: 'CommonBuffId' = 264379 + SIM_PREFERENCE_RECENT_DISLIKES_ROCK_CLIMBING: 'CommonBuffId' = 264410 + SIM_PREFERENCE_RECENT_DISLIKES_SINGING: 'CommonBuffId' = 264380 + SIM_PREFERENCE_RECENT_DISLIKES_SKIING: 'CommonBuffId' = 264381 + SIM_PREFERENCE_RECENT_DISLIKES_SNOWBOARDING: 'CommonBuffId' = 264382 + SIM_PREFERENCE_RECENT_DISLIKES_VIDEO_GAMING: 'CommonBuffId' = 259485 + SIM_PREFERENCE_RECENT_DISLIKES_VIOLIN: 'CommonBuffId' = 259491 + SIM_PREFERENCE_RECENT_DISLIKES_WELLNESS: 'CommonBuffId' = 264383 + SIM_PREFERENCE_RECENT_DISLIKES_WRITING: 'CommonBuffId' = 264384 + SIM_PREFERENCE_RECENT_FASHION_DISLIKES_BASICS: 'CommonBuffId' = 272685 + SIM_PREFERENCE_RECENT_FASHION_DISLIKES_BOHO: 'CommonBuffId' = 283114 + SIM_PREFERENCE_RECENT_FASHION_DISLIKES_COUNTRY: 'CommonBuffId' = 283115 + SIM_PREFERENCE_RECENT_FASHION_DISLIKES_HIPSTER: 'CommonBuffId' = 283116 + SIM_PREFERENCE_RECENT_FASHION_DISLIKES_OUTDOORSY: 'CommonBuffId' = 283117 + SIM_PREFERENCE_RECENT_FASHION_DISLIKES_POLISHED: 'CommonBuffId' = 283118 + SIM_PREFERENCE_RECENT_FASHION_DISLIKES_PREPPY: 'CommonBuffId' = 283119 + SIM_PREFERENCE_RECENT_FASHION_DISLIKES_ROCKER: 'CommonBuffId' = 283120 + SIM_PREFERENCE_RECENT_FASHION_DISLIKES_STREETWEAR: 'CommonBuffId' = 283121 + SIM_PREFERENCE_RECENT_FASHION_LIKES_BASICS: 'CommonBuffId' = 272686 + SIM_PREFERENCE_RECENT_FASHION_LIKES_BOHO: 'CommonBuffId' = 283122 + SIM_PREFERENCE_RECENT_FASHION_LIKES_COUNTRY: 'CommonBuffId' = 283123 + SIM_PREFERENCE_RECENT_FASHION_LIKES_HIPSTER: 'CommonBuffId' = 283128 + SIM_PREFERENCE_RECENT_FASHION_LIKES_OUTDOORSY: 'CommonBuffId' = 283129 + SIM_PREFERENCE_RECENT_FASHION_LIKES_POLISHED: 'CommonBuffId' = 283130 + SIM_PREFERENCE_RECENT_FASHION_LIKES_PREPPY: 'CommonBuffId' = 283131 + SIM_PREFERENCE_RECENT_FASHION_LIKES_ROCKER: 'CommonBuffId' = 283132 + SIM_PREFERENCE_RECENT_FASHION_LIKES_STREETWEAR: 'CommonBuffId' = 283133 + SIM_PREFERENCE_RECENT_LIKES_ACTING: 'CommonBuffId' = 264385 + SIM_PREFERENCE_RECENT_LIKES_BAKING: 'CommonBuffId' = 264386 + SIM_PREFERENCE_RECENT_LIKES_BOWLING: 'CommonBuffId' = 264387 + SIM_PREFERENCE_RECENT_LIKES_COMEDY: 'CommonBuffId' = 264388 + SIM_PREFERENCE_RECENT_LIKES_COOKING: 'CommonBuffId' = 259492 + SIM_PREFERENCE_RECENT_LIKES_CROSS_STITCH: 'CommonBuffId' = 274553 + SIM_PREFERENCE_RECENT_LIKES_DANCING: 'CommonBuffId' = 264389 + SIM_PREFERENCE_RECENT_LIKES_DEBATING: 'CommonBuffId' = 264390 + SIM_PREFERENCE_RECENT_LIKES_DJ_MIXING: 'CommonBuffId' = 264391 + SIM_PREFERENCE_RECENT_LIKES_EQUESTRIAN_SKILL: 'CommonBuffId' = 340019 + SIM_PREFERENCE_RECENT_LIKES_FISHING: 'CommonBuffId' = 264412 + SIM_PREFERENCE_RECENT_LIKES_FITNESS: 'CommonBuffId' = 259493 + SIM_PREFERENCE_RECENT_LIKES_GARDENING: 'CommonBuffId' = 264392 + SIM_PREFERENCE_RECENT_LIKES_GUITAR: 'CommonBuffId' = 264393 + SIM_PREFERENCE_RECENT_LIKES_HANDINESS: 'CommonBuffId' = 264394 + SIM_PREFERENCE_RECENT_LIKES_KNITTING: 'CommonBuffId' = 274545 + SIM_PREFERENCE_RECENT_LIKES_MEDIA_PRODUCTION: 'CommonBuffId' = 264395 + SIM_PREFERENCE_RECENT_LIKES_MISCHIEF: 'CommonBuffId' = 264396 + SIM_PREFERENCE_RECENT_LIKES_MIXOLOGY: 'CommonBuffId' = 264397 + SIM_PREFERENCE_RECENT_LIKES_NECTAR_MAKING: 'CommonBuffId' = 340020 + SIM_PREFERENCE_RECENT_LIKES_PAINTING: 'CommonBuffId' = 259494 + SIM_PREFERENCE_RECENT_LIKES_PHOTOGRAPHY: 'CommonBuffId' = 264398 + SIM_PREFERENCE_RECENT_LIKES_PIANO: 'CommonBuffId' = 264399 + SIM_PREFERENCE_RECENT_LIKES_PIPE_ORGAN: 'CommonBuffId' = 264409 + SIM_PREFERENCE_RECENT_LIKES_PROGRAMMING: 'CommonBuffId' = 264785 + SIM_PREFERENCE_RECENT_LIKES_ROBOTICS: 'CommonBuffId' = 264400 + SIM_PREFERENCE_RECENT_LIKES_ROCKET_SCIENCE: 'CommonBuffId' = 264401 + SIM_PREFERENCE_RECENT_LIKES_ROCK_CLIMBING: 'CommonBuffId' = 264411 + SIM_PREFERENCE_RECENT_LIKES_SINGING: 'CommonBuffId' = 264402 + SIM_PREFERENCE_RECENT_LIKES_SKIING: 'CommonBuffId' = 264403 + SIM_PREFERENCE_RECENT_LIKES_SNOWBOARDING: 'CommonBuffId' = 264404 + SIM_PREFERENCE_RECENT_LIKES_VIDEO_GAMING: 'CommonBuffId' = 259496 + SIM_PREFERENCE_RECENT_LIKES_VIOLIN: 'CommonBuffId' = 259497 + SIM_PREFERENCE_RECENT_LIKES_WELLNESS: 'CommonBuffId' = 264405 + SIM_PREFERENCE_RECENT_LIKES_WRITING: 'CommonBuffId' = 264406 + SIM_PREFERENCE_RECENT_MUSIC_ALTERNATIVE: 'CommonBuffId' = 267542 + SIM_PREFERENCE_RECENT_MUSIC_AMERICANA: 'CommonBuffId' = 267543 + SIM_PREFERENCE_RECENT_MUSIC_BACKYARD: 'CommonBuffId' = 267544 + SIM_PREFERENCE_RECENT_MUSIC_BAROQUE: 'CommonBuffId' = 267545 + SIM_PREFERENCE_RECENT_MUSIC_BATUU: 'CommonBuffId' = 346391 + SIM_PREFERENCE_RECENT_MUSIC_BLUES: 'CommonBuffId' = 267546 + SIM_PREFERENCE_RECENT_MUSIC_BRAZILIAN: 'CommonBuffId' = 346392 + SIM_PREFERENCE_RECENT_MUSIC_CLASSICAL: 'CommonBuffId' = 267547 + SIM_PREFERENCE_RECENT_MUSIC_COTTAGE_CORE: 'CommonBuffId' = 274583 + SIM_PREFERENCE_RECENT_MUSIC_EASY_LISTENING: 'CommonBuffId' = 267548 + SIM_PREFERENCE_RECENT_MUSIC_ELECTRONICA: 'CommonBuffId' = 267549 + SIM_PREFERENCE_RECENT_MUSIC_FOCUS: 'CommonBuffId' = 267550 + SIM_PREFERENCE_RECENT_MUSIC_HIP_HOP: 'CommonBuffId' = 267551 + SIM_PREFERENCE_RECENT_MUSIC_ISLAND: 'CommonBuffId' = 267552 + SIM_PREFERENCE_RECENT_MUSIC_JAPANESE_FOLK: 'CommonBuffId' = 267553 + SIM_PREFERENCE_RECENT_MUSIC_JAZZ: 'CommonBuffId' = 267554 + SIM_PREFERENCE_RECENT_MUSIC_KIDS: 'CommonBuffId' = 267555 + SIM_PREFERENCE_RECENT_MUSIC_LATIN: 'CommonBuffId' = 267556 + SIM_PREFERENCE_RECENT_MUSIC_LATIN_POP: 'CommonBuffId' = 267557 + SIM_PREFERENCE_RECENT_MUSIC_LULLABIES: 'CommonBuffId' = 267558 + SIM_PREFERENCE_RECENT_MUSIC_METAL: 'CommonBuffId' = 267559 + SIM_PREFERENCE_RECENT_MUSIC_NEW_AGE: 'CommonBuffId' = 267560 + SIM_PREFERENCE_RECENT_MUSIC_NU_DISCO: 'CommonBuffId' = 267561 + SIM_PREFERENCE_RECENT_MUSIC_OLDIES: 'CommonBuffId' = 312263 + SIM_PREFERENCE_RECENT_MUSIC_POP: 'CommonBuffId' = 267562 + SIM_PREFERENCE_RECENT_MUSIC_RANCH: 'CommonBuffId' = 334862 + SIM_PREFERENCE_RECENT_MUSIC_RETRO: 'CommonBuffId' = 267563 + SIM_PREFERENCE_RECENT_MUSIC_RNB: 'CommonBuffId' = 343309 + SIM_PREFERENCE_RECENT_MUSIC_ROMANCE: 'CommonBuffId' = 267564 + SIM_PREFERENCE_RECENT_MUSIC_SINGER_SONGWRITER: 'CommonBuffId' = 267565 + SIM_PREFERENCE_RECENT_MUSIC_SPOOKY: 'CommonBuffId' = 267566 + SIM_PREFERENCE_RECENT_MUSIC_STRANGE_TUNES: 'CommonBuffId' = 267567 + SIM_PREFERENCE_RECENT_MUSIC_SUMMER_STRUT: 'CommonBuffId' = 267568 + SIM_PREFERENCE_RECENT_MUSIC_S_POP: 'CommonBuffId' = 267575 + SIM_PREFERENCE_RECENT_MUSIC_TWEEN_POP: 'CommonBuffId' = 267569 + SIM_PREFERENCE_RECENT_MUSIC_WINTER_HOLIDAY: 'CommonBuffId' = 267570 + SIM_PREFERENCE_RECENT_MUSIC_WORLD: 'CommonBuffId' = 267571 + SIM_PUBERTY_CHANGES_HAS_VISIBLE_BODY_HAIR_BG: 'CommonBuffId' = 303973 + SIM_RAY_CHILLED: 'CommonBuffId' = 105959 + SIM_RAY_FROZEN: 'CommonBuffId' = 103994 + SIM_RAY_FROZEN_CHILD: 'CommonBuffId' = 115718 + SIM_RAY_MIND_CONTROL_CLEAN: 'CommonBuffId' = 106199 + SIM_RAY_MIND_CONTROL_EAT: 'CommonBuffId' = 106127 + SIM_RAY_MIND_CONTROL_PANIC: 'CommonBuffId' = 106062 + SIM_RAY_MIND_CONTROL_SIT: 'CommonBuffId' = 106225 + SIM_RAY_MIND_CONTROL_SLEEP: 'CommonBuffId' = 106219 + SIM_RAY_MWHAHAHA: 'CommonBuffId' = 105904 + SIM_RAY_TRANSFORMED: 'CommonBuffId' = 103814 + SIM_REACT_TO_PET_BIRTH: 'CommonBuffId' = 169087 + SIM_READ_TO_THIS_SIM: 'CommonBuffId' = 153698 + SIM_RECENT_BIRTHDAY: 'CommonBuffId' = 125738 + SIM_RETURN_TO_LOT_COOLDOWN: 'CommonBuffId' = 177688 + SIM_SCARED_SCREAM_INCOHERENTLY_EMOTIONAL_SUPPORT: 'CommonBuffId' = 253289 + SIM_SCARED_SCREAM_INCOHERENTLY_IRRATIONAL_DANGER: 'CommonBuffId' = 253288 + SIM_SEASON_WEATHER_BLIZZARD_INSIDE: 'CommonBuffId' = 183483 + SIM_SEASON_WEATHER_BLIZZARD_OUTSIDE: 'CommonBuffId' = 183183 + SIM_SEASON_WEATHER_HIDDEN_ICY_ELDER_OUTSIDE: 'CommonBuffId' = 248759 + SIM_SEASON_WEATHER_HIDDEN_ICY_NON_ELDER: 'CommonBuffId' = 248770 + SIM_SEASON_WEATHER_HIDDEN_MOUNTAIN_SNOW_SNOW_ON_GROUND: 'CommonBuffId' = 248129 + SIM_SEASON_WEATHER_HIDDEN_STORMS_RAIN_INSIDE: 'CommonBuffId' = 183478 + SIM_SEASON_WEATHER_HIDDEN_STORMS_RAIN_OUTSIDE: 'CommonBuffId' = 183479 + SIM_SEASON_WEATHER_HIDDEN_STORMS_THUNDER_ANYWHERE: 'CommonBuffId' = 183480 + SIM_SEASON_WEATHER_HIDDEN_STORMS_THUNDER_INSIDE: 'CommonBuffId' = 183481 + SIM_SEASON_WEATHER_HIDDEN_STORMS_THUNDER_OUTSIDE: 'CommonBuffId' = 183482 + SIM_SEASON_WEATHER_RAIN_HEAVY_RAIN_INSIDE: 'CommonBuffId' = 183476 + SIM_SEASON_WEATHER_RAIN_HEAVY_RAIN_OUTSIDE: 'CommonBuffId' = 183123 + SIM_SEASON_WEATHER_RAIN_LIGHT_RAIN_INSIDE: 'CommonBuffId' = 183475 + SIM_SEASON_WEATHER_RAIN_LIGHT_RAIN_OUTSIDE: 'CommonBuffId' = 183122 + SIM_SHARE_DESIRE_FOR_INDEPENDENCE_COOLDOWN: 'CommonBuffId' = 340723 + SIM_SINGED: 'CommonBuffId' = 75843 + SIM_SOCIAL_HUG_COOLDOWN: 'CommonBuffId' = 215939 + SIM_SPEAKING_WITH_RELATIVE: 'CommonBuffId' = 127122 + SIM_STABLE_GOSSIP: 'CommonBuffId' = 340805 + SIM_START_GROUP_COOKING: 'CommonBuffId' = 270157 + SIM_SUPPRESS_TARGET_SIM_SOCIALS_HIDDEN: 'CommonBuffId' = 141984 + SIM_SUPPRESS_TARGET_SIM_SOCIALS_HIDDEN_AUTONOMOUS_ONLY: 'CommonBuffId' = 178272 + SIM_SUPPRESS_TARGET_SIM_SOCIALS_VAMPIRE_HIDDEN: 'CommonBuffId' = 176782 + SIM_TODDLER_CHANGE_DIAPER_DIRTY_DIAPER: 'CommonBuffId' = 151218 + SIM_TODDLER_CHANGE_DIAPER_DIRTY_DIAPER_DISASTER: 'CommonBuffId' = 151237 + SIM_TO_PET_HUG_HAPPY: 'CommonBuffId' = 160353 + SIM_TO_PET_HUG_HAPPY_DOG: 'CommonBuffId' = 167115 + SIM_TO_PET_KISS_HAPPY: 'CommonBuffId' = 160354 + SIM_TO_PET_KISS_HAPPY_DOG: 'CommonBuffId' = 167116 + SIM_VIBED_WITH_A_CHILL_HORSE: 'CommonBuffId' = 340910 + SIM_WAIT_STAFF_CUSTOMER_CHECK_ON_TABLE_COOLDOWN: 'CommonBuffId' = 134972 + SIM_WAKEUP_IN_X_HOURS_HIDDEN: 'CommonBuffId' = 77288 + SIM_WALK_STYLE_WALK_SLOWEST: 'CommonBuffId' = 253866 + SIM_WEATHER_BLIZZARD_SCARED_OUTSIDE: 'CommonBuffId' = 184861 + SIM_WEATHER_DISALLOW_FIRST_SNOW_REACT: 'CommonBuffId' = 302612 + SIM_WEATHER_HIDDEN_BLIZZARD: 'CommonBuffId' = 182690 + SIM_WEATHER_HIDDEN_CLOUDY: 'CommonBuffId' = 185980 + SIM_WEATHER_HIDDEN_CLOUDY_PARTIAL: 'CommonBuffId' = 211622 + SIM_WEATHER_HIDDEN_RAINING: 'CommonBuffId' = 182654 + SIM_WEATHER_HIDDEN_SNOWING: 'CommonBuffId' = 182653 + SIM_WEATHER_HIDDEN_SNOW_ON_GROUND: 'CommonBuffId' = 182698 + SIM_WEATHER_HIDDEN_SUNNY: 'CommonBuffId' = 185979 + SIM_WEATHER_HIDDEN_THUNDER_STORM: 'CommonBuffId' = 182691 + SIM_WEATHER_HIDDEN_WINDY: 'CommonBuffId' = 185981 + SIM_WEATHER_LIGHTNING_NEAR: 'CommonBuffId' = 185472 + SIM_WEATHER_LIGHTNING_NEAR_TODDLER: 'CommonBuffId' = 190217 + SIM_WEATHER_LIGHTNING_STRUCK: 'CommonBuffId' = 185540 + SIM_WEATHER_LIGHTNING_STRUCK_HYPER_CHARGED: 'CommonBuffId' = 186029 + SIM_WEATHER_LIGHTNING_STRUCK_INSANE: 'CommonBuffId' = 185568 + SIM_WEATHER_LIGHTNING_STRUCK_SUPERCHARGED: 'CommonBuffId' = 186028 + SIM_WEATHER_RAIN_GREAT_TIME: 'CommonBuffId' = 185735 + SIM_WEATHER_RAIN_PLAYING: 'CommonBuffId' = 184929 + SIM_WEATHER_RAIN_RUN_INSIDE: 'CommonBuffId' = 190792 + SIM_WEATHER_STORM_SCARED_INSIDE: 'CommonBuffId' = 184421 + SIM_WEATHER_STORM_SCARED_INSIDE_TODDLER: 'CommonBuffId' = 190218 + SIM_WEATHER_STORM_STORM_CHASER_INSIDE: 'CommonBuffId' = 185797 + SIM_WEATHER_STORM_STORM_CHASER_OUTSIDE: 'CommonBuffId' = 185798 + SIM_WEATHER_STORM_TENSE_OUTSIDE: 'CommonBuffId' = 184422 + SIM_WEATHER_STORM_TENSE_OUTSIDE_TODDLER: 'CommonBuffId' = 190219 + SIM_WEATHER_THUNDER_SNOWSTORM_SQUALL_OF_WONDERS: 'CommonBuffId' = 248793 + SIM_WETNESS_TODDLER: 'CommonBuffId' = 188071 + SIM_WETNESS_WET: 'CommonBuffId' = 183761 + SIM_WET_PUDDLE_COOLDOWN: 'CommonBuffId' = 190700 + SIM_WOKE_UP_NOT_LAZY: 'CommonBuffId' = 155804 + SITUATION_APARTMENT_NEIGHBORS_DOOR_ROUTED_TO_HIDDEN: 'CommonBuffId' = 139244 + SITUATION_APARTMENT_NEIGHBOR_BRAINSTORM_INSPIRED: 'CommonBuffId' = 153400 + SITUATION_APARTMENT_NEIGHBOR_INVITED_IN: 'CommonBuffId' = 139548 + SITUATION_APARTMENT_NEIGHBOR_NOISY_NEIGHBORS_ANGRY: 'CommonBuffId' = 136835 + SITUATION_APARTMENT_NEIGHBOR_NOISY_NEIGHBORS_TENSE: 'CommonBuffId' = 145007 + SITUATION_BETROTHED_BRONZE: 'CommonBuffId' = 76685 + SITUATION_BETROTHED_GOLD: 'CommonBuffId' = 76689 + SITUATION_BETROTHED_SILVER: 'CommonBuffId' = 76690 + SITUATION_BIRTHDAY_BRONZE: 'CommonBuffId' = 76662 + SITUATION_BIRTHDAY_GOLD: 'CommonBuffId' = 76664 + SITUATION_BIRTHDAY_SILVER: 'CommonBuffId' = 76663 + SITUATION_BREAK_IN: 'CommonBuffId' = 361112 + SITUATION_CAREGIVER_BABY: 'CommonBuffId' = 276011 + SITUATION_COOKOUT_PROPANE_VS_CHARCOAL: 'CommonBuffId' = 301548 + SITUATION_DATE_BRONZE: 'CommonBuffId' = 76687 + SITUATION_DATE_GOLD: 'CommonBuffId' = 76691 + SITUATION_DATE_SILVER: 'CommonBuffId' = 76692 + SITUATION_DOCTOR_CAREER_AT_WORK: 'CommonBuffId' = 112130 + SITUATION_DOCTOR_CAREER_DAY1: 'CommonBuffId' = 115809 + SITUATION_DOCTOR_CAREER_PATIENT_DIAGNOSIS_NO_ILLNESS: 'CommonBuffId' = 112642 + SITUATION_DOCTOR_CAREER_PATIENT_TREATED_MED_RECORD: 'CommonBuffId' = 112635 + SITUATION_DOCTOR_CAREER_SAMPLE_ANALYSIS_DATA_ENTRY: 'CommonBuffId' = 112636 + SITUATION_DOCTOR_CAREER_SAMPLE_ANALYSIS_DATA_ENTRY_EMERGENCY: 'CommonBuffId' = 116458 + SITUATION_DOCTOR_CAREER_SAMPLE_ANALYSIS_EMERGENCY_COLLECTED_ITEMS: 'CommonBuffId' = 116660 + SITUATION_FIRE_FINED_FOR_PHONY_CALL: 'CommonBuffId' = 239656 + SITUATION_FIRE_FIRE_BRIGADE_COOLDOWN: 'CommonBuffId' = 237751 + SITUATION_FIRE_FIRE_BRIGADE_ROLE_FIGHT_FIRE: 'CommonBuffId' = 237701 + SITUATION_FIRE_FIRE_FIGHTER_FINISHED_COOLDOWN: 'CommonBuffId' = 241074 + SITUATION_FIRE_FIRE_FIGHTER_ROLE_FIGHT_FIRE: 'CommonBuffId' = 234743 + SITUATION_FIRE_FIRE_FIGHTER_ROUTE_FAIL_COOLDOWN: 'CommonBuffId' = 234742 + SITUATION_FIRE_FIRE_FIGHTER_START_UP_COOLDOWN: 'CommonBuffId' = 241073 + SITUATION_FIRE_OVER: 'CommonBuffId' = 99542 + SITUATION_FIRE_PANIC: 'CommonBuffId' = 73844 + SITUATION_FIRE_PANIC_CAREGIVER: 'CommonBuffId' = 155636 + SITUATION_FIRE_SAFE: 'CommonBuffId' = 100125 + SITUATION_FIRE_SAFE_TODDLER: 'CommonBuffId' = 155675 + SITUATION_FIRE_SAVED_BY_FIRE_FIGHTER: 'CommonBuffId' = 234741 + SITUATION_GO_DANCING_NEGATIVE: 'CommonBuffId' = 125398 + SITUATION_GO_DANCING_POSITIVE: 'CommonBuffId' = 125397 + SITUATION_GUEST_BRONZE: 'CommonBuffId' = 76669 + SITUATION_GUEST_GOLD: 'CommonBuffId' = 76671 + SITUATION_GUEST_SILVER: 'CommonBuffId' = 76670 + SITUATION_HAPPY_HOUR: 'CommonBuffId' = 153663 + SITUATION_HIDDEN_PARTICIPATED_IN_KARAOKE_CONTEST: 'CommonBuffId' = 138183 + SITUATION_HOST_BRONZE: 'CommonBuffId' = 76673 + SITUATION_HOST_GOLD: 'CommonBuffId' = 76675 + SITUATION_HOST_SILVER: 'CommonBuffId' = 76674 + SITUATION_KARAOKE_CONTEST_WINNER: 'CommonBuffId' = 152874 + SITUATION_MULTI_SERVE_SITUATION_RANCH_NECTAR_AUTONOMOUS_COOLDOWN: 'CommonBuffId' = 336474 + SITUATION_NEIGHBORHOOD_POTLUCK_EAT: 'CommonBuffId' = 357113 + SITUATION_NEIGHBORHOOD_POTLUCK_GUEST: 'CommonBuffId' = 344236 + SITUATION_PATROL_IS_CRIMINAL: 'CommonBuffId' = 110750 + SITUATION_PATROL_TIMER_BUFF: 'CommonBuffId' = 116390 + SITUATION_PLAY_DATE_NPC_INVITE_BRONZE: 'CommonBuffId' = 117608 + SITUATION_PLAY_DATE_NPC_INVITE_GOLD: 'CommonBuffId' = 117610 + SITUATION_PLAY_DATE_NPC_INVITE_SILVER: 'CommonBuffId' = 117609 + SITUATION_POOL_PARTY_GUEST: 'CommonBuffId' = 344233 + SITUATION_POOL_PARTY_SWIM: 'CommonBuffId' = 357112 + SITUATION_POOL_PARTY_TOO_COLD: 'CommonBuffId' = 345154 + SITUATION_POOL_PARTY_TOO_HOT: 'CommonBuffId' = 345153 + SITUATION_PRE_POST_WEDDING_PARTIES_BACH_PARTY_ARRIVAL: 'CommonBuffId' = 275427 + SITUATION_PRE_POST_WEDDING_PARTIES_BACH_PARTY_BARFLY: 'CommonBuffId' = 275428 + SITUATION_PRE_POST_WEDDING_PARTIES_BACH_PARTY_DANCING: 'CommonBuffId' = 275429 + SITUATION_PRE_POST_WEDDING_PARTIES_BACH_PARTY_DESSERTS: 'CommonBuffId' = 275430 + SITUATION_PRE_POST_WEDDING_PARTIES_BACH_PARTY_DINNER: 'CommonBuffId' = 275431 + SITUATION_PRE_POST_WEDDING_PARTIES_BACH_PARTY_DRINKING: 'CommonBuffId' = 275432 + SITUATION_PRE_POST_WEDDING_PARTIES_BACH_PARTY_TOAST: 'CommonBuffId' = 275433 + SITUATION_PRE_POST_WEDDING_PARTIES_SLOW_MOTIVES: 'CommonBuffId' = 275422 + SITUATION_PRE_POST_WEDDING_PARTIES_TEA: 'CommonBuffId' = 278442 + SITUATION_S_S3_REQUEST: 'CommonBuffId' = 99555 + SITUATION_UNGREETED_PLAYER_VISITING_NPC: 'CommonBuffId' = 34725 + SITUATION_WEENIE_PARTY: 'CommonBuffId' = 192597 + SITUATION_WEENIE_ROAST_HOST_BRONZE: 'CommonBuffId' = 103827 + SITUATION_WEENIE_ROAST_HOST_GOLD: 'CommonBuffId' = 103829 + SITUATION_WEENIE_ROAST_HOST_SILVER: 'CommonBuffId' = 103828 + SITUATION_YOGA_CLASS_BENT_OUT_OF_SHAPE: 'CommonBuffId' = 118678 + SITUATION_YOGA_CLASS_CLASS_IS_JOINABLE: 'CommonBuffId' = 121561 + SITUATION_YOGA_CLASS_IS_OUTSIDE: 'CommonBuffId' = 272313 + SITUATION_YOGA_CLASS_MEMBER: 'CommonBuffId' = 120018 + SITUATION_YOGA_CLASS_MEMBER_PRE_CLASS: 'CommonBuffId' = 272015 + SITUATION_YOGA_CLASS_POST_CLASS: 'CommonBuffId' = 119972 + SIT_LOUNGE_FLOAT_LOUNGER_SPLASHED_ANGRY: 'CommonBuffId' = 212265 + SIT_LOUNGE_FLOAT_LOUNGER_SPLASHED_PLAYFUL: 'CommonBuffId' = 212273 + SIT_LOUNGE_FLOAT_LOUNGER_SPLASHED_RUDE_AWAKENING: 'CommonBuffId' = 212274 + SIT_LOUNGE_FLOAT_SUPER_SPLASHED_ANGRY: 'CommonBuffId' = 212275 + SIT_LOUNGE_FLOAT_SUPER_SPLASHED_PLAYFUL: 'CommonBuffId' = 212315 + SIT_LOUNGE_FLOAT_SUPER_SPLASH_PLAYFUL: 'CommonBuffId' = 212718 + SKELETON: 'CommonBuffId' = 175971 + SKELETON_HEARD_JOKE: 'CommonBuffId' = 176570 + SKELETON_SERVICE_SKELETON: 'CommonBuffId' = 177753 + SKELETON_SERVICE_SKELETON_LEAVE: 'CommonBuffId' = 178960 + SKELETON_SERVICE_SKELETON_RARE: 'CommonBuffId' = 177829 + SKELETON_SERVICE_SKELETON_UNCOMMON: 'CommonBuffId' = 177828 + SKIING_ADVICE_ON_AVOIDING_WIPE_OUTS_HIDDEN: 'CommonBuffId' = 245833 + SKIING_COACHED_HIDDEN: 'CommonBuffId' = 246329 + SKIING_COACH_FAILED_ON_COOLDOWN_HIDDEN: 'CommonBuffId' = 246478 + SKIING_DEATH_COOKIE_WARNING: 'CommonBuffId' = 245642 + SKIING_DEATH_COOKIE_WARNING_HIDDEN_COOLDOWN: 'CommonBuffId' = 245643 + SKIING_DISCUSS_PAST_SKI_EXPERIENCES_REMINISCING_ABOUT_GOODTIMES: 'CommonBuffId' = 246739 + SKIING_DISCUSS_PAST_SKI_EXPERIENCES_UNWANTED_MEMORIES: 'CommonBuffId' = 246740 + SKIING_GREAT_COACH: 'CommonBuffId' = 246327 + SKIING_NO_MATCH_FOR_THE_COOKIES: 'CommonBuffId' = 249599 + SKIING_OFFER_SKI_EXPERTISE_COOLDOWN_HIDDEN: 'CommonBuffId' = 246635 + SKIING_PREPARE_FOR_THE_MOMENT_COOLDOWN_HIDDEN: 'CommonBuffId' = 246766 + SKIING_PREPARE_FOR_THE_MOMENT_LOOKING_FOOLISH: 'CommonBuffId' = 246765 + SKIING_PREPARE_FOR_THE_MOMENT_READY_TO_SKI: 'CommonBuffId' = 246764 + SKIING_SKI_PUPIL: 'CommonBuffId' = 246328 + SKIING_TEACH_SKI_CLASS_KNOWLEDGE_SHARING: 'CommonBuffId' = 246289 + SKIING_WELL_WRITTEN_POST: 'CommonBuffId' = 245700 + SKILL_BARTENDING_HIGH: 'CommonBuffId' = 10357 + SKILL_BARTENDING_MED: 'CommonBuffId' = 10356 + SKILL_BARTENDING_TRICKS: 'CommonBuffId' = 98315 + SKILL_CHARISMA_GIVING_GUSTO_HIGH: 'CommonBuffId' = 31097 + SKILL_CHARISMA_GIVING_GUSTO_LOW: 'CommonBuffId' = 31093 + SKILL_CHARISMA_GIVING_GUSTO_MED: 'CommonBuffId' = 31096 + SKILL_CHARISMA_GIVING_GUSTO_SAD: 'CommonBuffId' = 31129 + SKILL_CHARISMA_SILVER_TONGUE: 'CommonBuffId' = 31301 + SKILL_COMEDY_BRIEFLY_AMUSED: 'CommonBuffId' = 31341 + SKILL_COMEDY_BUSTED_A_GUT: 'CommonBuffId' = 31345 + SKILL_COMEDY_COMEDY_GOLD: 'CommonBuffId' = 31346 + SKILL_COMEDY_FUNNY_BONE_TICKLED: 'CommonBuffId' = 31343 + SKILL_COMEDY_OVER_PRACTICED: 'CommonBuffId' = 30349 + SKILL_COMEDY_PERFECTLY_PRACTICED: 'CommonBuffId' = 30347 + SKILL_COMEDY_PERFORMANCE_PAYOUT_NORMAL: 'CommonBuffId' = 31625 + SKILL_COMEDY_PERFORMANCE_PAYOUT_OUTSTANDING: 'CommonBuffId' = 31624 + SKILL_COMEDY_PERFORMANCE_PAYOUT_POOR: 'CommonBuffId' = 31623 + SKILL_COMEDY_PSYCHED_SELF_OUT: 'CommonBuffId' = 30350 + SKILL_COMEDY_SOMEWHAT_PRACTICED: 'CommonBuffId' = 30346 + SKILL_COMEDY_WELL_PRACTICED: 'CommonBuffId' = 30348 + SKILL_COOKING_GOURMET: 'CommonBuffId' = 37341 + SKILL_COOKING_HIDDEN: 'CommonBuffId' = 76610 + SKILL_COOKING_HIGH: 'CommonBuffId' = 37340 + SKILL_COOKING_MED: 'CommonBuffId' = 37339 + SKILL_CREATIVITY_DAYDREAM: 'CommonBuffId' = 39396 + SKILL_EQUESTRIAN_SKILL_A_TERRIFIC_TROT: 'CommonBuffId' = 317973 + SKILL_EQUESTRIAN_SKILL_A_VIEW_FROM_HORSEBACK: 'CommonBuffId' = 317974 + SKILL_EQUESTRIAN_SKILL_BONDING_WITH_STEED: 'CommonBuffId' = 317975 + SKILL_EQUESTRIAN_SKILL_GIDDY_UP: 'CommonBuffId' = 317976 + SKILL_EQUESTRIAN_SKILL_HIGH_ON_THE_SADDLE: 'CommonBuffId' = 317971 + SKILL_EQUESTRIAN_SKILL_HORSING_AROUND: 'CommonBuffId' = 317977 + SKILL_EQUESTRIAN_SKILL_RIDING_RHYTHM: 'CommonBuffId' = 317978 + SKILL_EQUESTRIAN_SKILL_SADDLE_SORE: 'CommonBuffId' = 323078 + SKILL_EQUESTRIAN_SKILL_SADDLE_SORE_POST_RIDE: 'CommonBuffId' = 327015 + SKILL_EQUESTRIAN_SKILL_STAR_STUDENT: 'CommonBuffId' = 327171 + SKILL_EQUESTRIAN_SKILL_TAKIN_CARE_OF_BUSINESS: 'CommonBuffId' = 321626 + SKILL_FABRICATION_EXPLOSION: 'CommonBuffId' = 233402 + SKILL_FABRICATION_EXPLOSION_POSITIVE: 'CommonBuffId' = 237574 + SKILL_FABRICATION_FIGHT: 'CommonBuffId' = 233401 + SKILL_FABRICATION_RECENTLY_PROFESSED: 'CommonBuffId' = 237447 + SKILL_FISHING_AMAZING_CATCH: 'CommonBuffId' = 76428 + SKILL_FISHING_ANGLE_FOR_BIG_CATCH: 'CommonBuffId' = 208732 + SKILL_FISHING_CAUGHT_ENDANGERED_FISH: 'CommonBuffId' = 212672 + SKILL_FISHING_CAUGHT_EXCELLENT_FISH: 'CommonBuffId' = 216899 + SKILL_FISHING_CAUGHT_FISH: 'CommonBuffId' = 76816 + SKILL_FISHING_CAUGHT_FISH_WITH_BAIT: 'CommonBuffId' = 77314 + SKILL_FISHING_CAUGHT_LARGE_FISH: 'CommonBuffId' = 100093 + SKILL_FISHING_EXPERT_TIP_GIVER: 'CommonBuffId' = 214365 + SKILL_FISHING_FISH_FRIEND: 'CommonBuffId' = 212663 + SKILL_FISHING_GREAT_CATCH: 'CommonBuffId' = 76427 + SKILL_FISHING_TOLD_TO_FISH: 'CommonBuffId' = 212626 + SKILL_GARDENING_TEACH_ABOUT_PLANTS_COOLDOWN: 'CommonBuffId' = 263254 + SKILL_HANDINESS_OUCH: 'CommonBuffId' = 28424 + SKILL_HANDINESS_PRETTY_HANDY: 'CommonBuffId' = 28431 + SKILL_HANDINESS_SO_HANDY: 'CommonBuffId' = 28440 + SKILL_MENTAL_ATTEMPT_MENTAL_TELEPATHY: 'CommonBuffId' = 99501 + SKILL_MISCHIEF_FAILED_MONEY_SPAM: 'CommonBuffId' = 38483 + SKILL_MUSIC_COMPETENT_COMPOSER: 'CommonBuffId' = 37456 + SKILL_MUSIC_WRITE_LYRICS: 'CommonBuffId' = 153710 + SKILL_PAINTING_INSPIRING_ARTIST: 'CommonBuffId' = 37329 + SKILL_PAINTING_MADE_MASTERPIECE: 'CommonBuffId' = 98301 + SKILL_PAINTING_SPOKE_WITH_AGENT: 'CommonBuffId' = 38642 + SKILL_PROGRAMMING_CAUGHT_CHEATING: 'CommonBuffId' = 37294 + SKILL_PROGRAMMING_CAUGHT_HACKING_WORK_PERFORMANCE: 'CommonBuffId' = 38562 + SKILL_PROGRAMMING_HACKED_GRADES: 'CommonBuffId' = 37293 + SKILL_PROGRAMMING_HACKED_SUPERCOMPUTER: 'CommonBuffId' = 36845 + SKILL_PROGRAMMING_HACKED_TARGET1: 'CommonBuffId' = 31606 + SKILL_PROGRAMMING_HACKED_TARGET2: 'CommonBuffId' = 32388 + SKILL_PROGRAMMING_HACKED_TARGET3: 'CommonBuffId' = 32389 + SKILL_PROGRAMMING_HACKED_TARGET4: 'CommonBuffId' = 32390 + SKILL_PROGRAMMING_HACKED_TARGET5: 'CommonBuffId' = 32391 + SKILL_PROGRAMMING_HACKED_TARGET6: 'CommonBuffId' = 32392 + SKILL_PROGRAMMING_HACKED_WORK_PERFORMANCE: 'CommonBuffId' = 38554 + SKILL_ROCK_CLIMBING_BAR_CONSUME_TIMER_ENERGY: 'CommonBuffId' = 253715 + SKILL_ROCK_CLIMBING_BAR_CONSUME_TIMER_PROTEIN: 'CommonBuffId' = 253698 + SKILL_ROCK_CLIMBING_CHALK_HANDS_COOLDOWN: 'CommonBuffId' = 245982 + SKILL_ROCK_CLIMBING_COACHED_SKILL_GAIN: 'CommonBuffId' = 246956 + SKILL_ROCK_CLIMBING_CONFIDENT_GRIP: 'CommonBuffId' = 245986 + SKILL_ROCK_CLIMBING_GREAT_COACH: 'CommonBuffId' = 246954 + SKILL_ROCK_CLIMBING_HARD_HANDS: 'CommonBuffId' = 245993 + SKILL_ROCK_CLIMBING_MAKE_ENERGY_BAR_COOLDOWN: 'CommonBuffId' = 246413 + SKILL_ROCK_CLIMBING_MAKE_PROTEIN_BAR_COOLDOWN: 'CommonBuffId' = 246412 + SKILL_ROCK_CLIMBING_OFFER_TIPS_COOLDOWN: 'CommonBuffId' = 253070 + SKILL_ROCK_CLIMBING_PART_TIMER: 'CommonBuffId' = 245995 + SKILL_ROCK_CLIMBING_PASSABLE_PREPARATION: 'CommonBuffId' = 245989 + SKILL_ROCK_CLIMBING_PLANNED_FOR_THE_PINNACLE: 'CommonBuffId' = 245991 + SKILL_ROCK_CLIMBING_READY_AS_EVER: 'CommonBuffId' = 245988 + SKILL_ROCK_CLIMBING_ROCK_CLIMBING_PUPIL: 'CommonBuffId' = 245992 + SKILL_ROCK_CLIMBING_ROCK_CLIMBING_REBUTTAL: 'CommonBuffId' = 245997 + SKILL_ROCK_CLIMBING_STRETCH_TOO_FAR: 'CommonBuffId' = 245990 + SKILL_ROCK_CLIMBING_TASTES_LIKE_CARDBOARD: 'CommonBuffId' = 253700 + SKILL_ROCK_CLIMBING_VAUNTED_VISTA: 'CommonBuffId' = 245996 + SKILL_TRAIT_ENTREPRENEUR_THE_KNOWLEDGE: 'CommonBuffId' = 277993 + SKILL_UP_CHECK_FLAG: 'CommonBuffId' = 282273 + SKILL_VIDEO_GAMING_GAMED_OUT: 'CommonBuffId' = 31758 + SKILL_VIDEO_GAMING_GOOD_SESSION: 'CommonBuffId' = 38877 + SKILL_VIDEO_GAMING_TOURNAMENT_LOSS: 'CommonBuffId' = 31910 + SKILL_VIDEO_GAMING_TOURNAMENT_WIN: 'CommonBuffId' = 31909 + SKILL_WELLNESS_IDLE: 'CommonBuffId' = 118686 + SKILL_WOOHOO_COMPLETELY_SATISFIED: 'CommonBuffId' = 34027 + SKILL_WOOHOO_PERFORMED_POORLY: 'CommonBuffId' = 34021 + SKILL_WOOHOO_PLEASANTLY_SATISFIED: 'CommonBuffId' = 34026 + SKILL_WOOHOO_SEEING_STARS: 'CommonBuffId' = 34028 + SKILL_WOOHOO_UNSATISFIED: 'CommonBuffId' = 34034 + SKILL_WRITING_BEAT_WRITERS_BLOCK: 'CommonBuffId' = 34377 + SKILL_WRITING_LITERARY_EXAMPLE: 'CommonBuffId' = 34324 + SKILL_WRITING_NEW_NOVEL: 'CommonBuffId' = 34089 + SKILL_WRITING_PROLIFIC_WRITER: 'CommonBuffId' = 39302 + SKILL_WRITING_WRITERS_BLOCK: 'CommonBuffId' = 34131 + SLEEPING_BAG_CAMPIN_OUT: 'CommonBuffId' = 312948 + SLEEPING_BAG_EW_BUGS: 'CommonBuffId' = 312945 + SLEEPING_BAG_HOST_OF_HORROR: 'CommonBuffId' = 312951 + SLEEPING_BAG_JUST_A_STORY: 'CommonBuffId' = 312955 + SLEEPING_BAG_MY_BACK: 'CommonBuffId' = 312947 + SLEEPING_BAG_PILLOW_CONQUER: 'CommonBuffId' = 312954 + SLEEPING_BAG_PRANK_BROADCASTER: 'CommonBuffId' = 320652 + SLEEPING_BAG_PRANK_FEELING_IT: 'CommonBuffId' = 320651 + SLEEPING_BAG_PRANK_NOT_FEELING_IT: 'CommonBuffId' = 320650 + SLEEPING_BAG_PRANK_VIEWER: 'CommonBuffId' = 320649 + SLEEPING_BAG_PUMMELED_BY_PILLOWS: 'CommonBuffId' = 312953 + SLEEPING_BAG_SNUG_AS_A_BUG: 'CommonBuffId' = 312946 + SLEEPING_BAG_SPELLBOUND_SPECTATOR: 'CommonBuffId' = 312950 + SLEEPING_BAG_STORYWEAVER: 'CommonBuffId' = 312949 + SLEEPING_POD_CIRCADIAN_TWEAKER: 'CommonBuffId' = 200636 + SLEEPING_POD_MISCHIEF_ANGRY: 'CommonBuffId' = 200411 + SLEEPING_POD_MISCHIEF_BORED: 'CommonBuffId' = 200413 + SLEEPING_POD_MISCHIEF_CAUGHT_NEGATIVE: 'CommonBuffId' = 200895 + SLEEPING_POD_MISCHIEF_EMBARRASSED: 'CommonBuffId' = 200412 + SLEEPING_POD_MISCHIEF_NOT_CAUGHT_POSITIVE: 'CommonBuffId' = 200894 + SLEEPING_POD_MISCHIEF_SAD: 'CommonBuffId' = 200410 + SLEEPING_POD_MISCHIEF_TRAPPED: 'CommonBuffId' = 200425 + SLEEPING_POD_MISCHIEF_WITNESS_SABOTAGE: 'CommonBuffId' = 200947 + SLEEPING_POD_SLEEP_MOTIVE_DECAY_SUPPRESSION: 'CommonBuffId' = 201367 + SLEEPING_POD_SUBLIMINAL_TRANSMITTER_DREAMS_CONFIDENT: 'CommonBuffId' = 200402 + SLEEPING_POD_SUBLIMINAL_TRANSMITTER_DREAMS_EDUCATIONAL: 'CommonBuffId' = 200407 + SLEEPING_POD_SUBLIMINAL_TRANSMITTER_DREAMS_ENERGIZED: 'CommonBuffId' = 200404 + SLEEPING_POD_SUBLIMINAL_TRANSMITTER_DREAMS_FOCUSED: 'CommonBuffId' = 200403 + SLEEPING_POD_SUBLIMINAL_TRANSMITTER_DREAMS_FUN: 'CommonBuffId' = 200406 + SLEEPING_POD_SUBLIMINAL_TRANSMITTER_DREAMS_INSPIRED: 'CommonBuffId' = 200400 + SLEEPING_POD_SUBLIMINAL_TRANSMITTER_DREAMS_RESTFUL: 'CommonBuffId' = 200401 + SLEEPING_POD_SUBLIMINAL_TRANSMITTER_DREAMS_SOCIAL: 'CommonBuffId' = 200405 + SLEEPING_POD_SUBLIMINAL_TRANSMITTER_INTERRUPTED_DREAMS: 'CommonBuffId' = 201035 + SLEEPING_POD_UP_N_ATOMIZER: 'CommonBuffId' = 200960 + SLEEPOVER_SLEEPING_BAG_SETUP: 'CommonBuffId' = 333456 + SLEEPOVER_SNACKS_COOLDOWN: 'CommonBuffId' = 313777 + SLEEPOVER_TIME_FOR_BED: 'CommonBuffId' = 333627 + SLOW_EXPERIENCES_STATES_EMOTIONAL_CONTROL: 'CommonBuffId' = 245284 + SLOW_EXPERIENCES_STATES_SLOWED_DOWN: 'CommonBuffId' = 245283 + SLOW_EXPERIENCES_STATE_1: 'CommonBuffId' = 394567 + SLOW_EXPERIENCES_SURGE_EMOTION_ANGRY: 'CommonBuffId' = 245682 + SLOW_EXPERIENCES_SURGE_EMOTION_BORED: 'CommonBuffId' = 245683 + SLOW_EXPERIENCES_SURGE_EMOTION_CONFIDENT: 'CommonBuffId' = 245692 + SLOW_EXPERIENCES_SURGE_EMOTION_DAZED: 'CommonBuffId' = 245693 + SLOW_EXPERIENCES_SURGE_EMOTION_EMBARRASSED: 'CommonBuffId' = 245694 + SLOW_EXPERIENCES_SURGE_EMOTION_ENERGIZED: 'CommonBuffId' = 245695 + SLOW_EXPERIENCES_SURGE_EMOTION_FLIRTY: 'CommonBuffId' = 245684 + SLOW_EXPERIENCES_SURGE_EMOTION_FOCUSED: 'CommonBuffId' = 245685 + SLOW_EXPERIENCES_SURGE_EMOTION_HAPPY: 'CommonBuffId' = 245686 + SLOW_EXPERIENCES_SURGE_EMOTION_INSPIRED: 'CommonBuffId' = 245687 + SLOW_EXPERIENCES_SURGE_EMOTION_PLAYFUL: 'CommonBuffId' = 245688 + SLOW_EXPERIENCES_SURGE_EMOTION_SAD: 'CommonBuffId' = 245689 + SLOW_EXPERIENCES_SURGE_EMOTION_STRESSED: 'CommonBuffId' = 245690 + SLOW_EXPERIENCES_SURGE_EMOTION_UNCOMFORTABLE: 'CommonBuffId' = 245691 + SMALL_SLEEP_DESIRE: 'CommonBuffId' = 8847 + SNOOPING_BLACKMAIL_GENERIC: 'CommonBuffId' = 344320 + SNOOPING_BLACKMAIL_PUBLIC_MENACE: 'CommonBuffId' = 344321 + SNOOPING_BREAKING_AND_ENTERING_OCCUPANT_RETURN_ROLE: 'CommonBuffId' = 346271 + SNOOPING_BREAKING_AND_ENTERING_PLAYER_ROLE: 'CommonBuffId' = 346269 + SNOOPING_CAUGHT: 'CommonBuffId' = 343928 + SNOOPING_CAUGHT_VISIBLE: 'CommonBuffId' = 344405 + SNOOPING_CONFRONTED_BRIBE_AVAILABLE: 'CommonBuffId' = 346581 + SNOOPING_COOLDOWN: 'CommonBuffId' = 344323 + SNOOPING_GETTING_SECRET_FAIL: 'CommonBuffId' = 343938 + SNOOPING_GETTING_SECRET_SUCCESS: 'CommonBuffId' = 343940 + SNOOPING_KEEP_SECRET: 'CommonBuffId' = 344322 + SNOOPING_NO_CATCHING: 'CommonBuffId' = 343723 + SNOOPING_SEEKER_OF_SECRETS_FELINE_JESTER: 'CommonBuffId' = 347867 + SNOOPING_SEEKER_OF_SECRETS_FELINE_MASTER: 'CommonBuffId' = 347866 + SNOOPING_SEEKER_OF_SECRETS_OBJECTIVE_TRACKER_SECRET: 'CommonBuffId' = 347171 + SNOOPING_SEEKER_OF_SECRETS_OBJECTIVE_TRACKER_TIGER_BADGE: 'CommonBuffId' = 351117 + SNOOPING_SEEKER_OF_SECRETS_ULTIMATE_FELINE_MASTER: 'CommonBuffId' = 355672 + SNOOPING_TRAIT_BUFF_MENACE_HIDDEN: 'CommonBuffId' = 350411 + SNOOPING_TRAIT_BUFF_SAFE_KEEPER_HIDDEN: 'CommonBuffId' = 350412 + SNORKEL_MASK_ADULT: 'CommonBuffId' = 206585 + SNORKEL_MASK_CHILD: 'CommonBuffId' = 208767 + SNORKEL_SCUBA_FREE_DIVING_FLIPPERS_ADULT: 'CommonBuffId' = 214156 + SNORKEL_SCUBA_FREE_DIVING_FLIPPERS_CHILD: 'CommonBuffId' = 214160 + SNORKEL_SCUBA_FREE_DIVING_VISIBLE_SEASHELL_FAIL: 'CommonBuffId' = 208601 + SNORKEL_SCUBA_FREE_DIVING_VISIBLE_TREASURE_FAIL: 'CommonBuffId' = 208616 + SNOWBOARDING_GAPERS_GONNA_TACO: 'CommonBuffId' = 247392 + SNOWBOARDING_HIDDEN_ASK_TO_BE_SNOW_BRO_COOLDOWN: 'CommonBuffId' = 246928 + SNOWBOARDING_HIDDEN_CHECK_CONDITIONS_COOLDOWN: 'CommonBuffId' = 253673 + SNOWBOARDING_HIDDEN_COACH_FAILURE: 'CommonBuffId' = 247404 + SNOWBOARDING_HIDDEN_COACH_SUCCESS: 'CommonBuffId' = 247402 + SNOWBOARDING_HIDDEN_ENDURE_THE_BURN: 'CommonBuffId' = 247279 + SNOWBOARDING_HIDDEN_GET_HYPED_COOLDOWN: 'CommonBuffId' = 246900 + SNOWBOARDING_HIDDEN_PROVIDE_TIPS_COOLDOWN: 'CommonBuffId' = 246860 + SNOWBOARDING_HIDDEN_STRETCH_IT_OUT_COOLDOWN: 'CommonBuffId' = 247259 + SNOWBOARDING_LEFT_HANGING: 'CommonBuffId' = 246959 + SNOWBOARDING_MOCKING_BACKFIRE: 'CommonBuffId' = 247423 + SNOWBOARDING_NOT_A_GROM: 'CommonBuffId' = 247396 + SNOWBOARDING_PREPARED_FOR_FROST: 'CommonBuffId' = 247588 + SNOWBOARDING_READY_FOR_THE_RUN: 'CommonBuffId' = 246901 + SNOWBOARDING_READY_FOR_THE_RUN_HIGH_WEIGHT: 'CommonBuffId' = 246902 + SNOWBOARDING_SKIER_BURN: 'CommonBuffId' = 247385 + SNOWBOARDING_SNOW_BRO_HIGH_FIVE: 'CommonBuffId' = 246958 + SNOWBOARDING_TEACHN_TO_STOMP: 'CommonBuffId' = 247391 + SNOWBOARDING_WASNT_PREPARED: 'CommonBuffId' = 247590 + SNOW_DRIFT_SHOVEL: 'CommonBuffId' = 183790 + SNOW_DRIFT_SUPPRESS_IDLES_WHEN_SHOVELING: 'CommonBuffId' = 256563 + SNOW_EFFECTS_DISCIPLINE: 'CommonBuffId' = 190696 + SNOW_EFFECTS_LET_IT_SNOW: 'CommonBuffId' = 181132 + SNOW_EFFECTS_SNOWING_NEGATIVE: 'CommonBuffId' = 181134 + SNOW_EFFECTS_SNOWING_POSITIVE: 'CommonBuffId' = 181133 + SNOW_EFFECTS_SNOW_FACED: 'CommonBuffId' = 181151 + SNOW_EFFECTS_SNOW_FUN_HAPPY: 'CommonBuffId' = 181145 + SNOW_EFFECTS_SNOW_FUN_PLAYFUL: 'CommonBuffId' = 181147 + SNOW_EFFECTS_SNOW_IDLE: 'CommonBuffId' = 181002 + SNOW_PAL_ADD_SNOW_MIXER: 'CommonBuffId' = 189580 + SNOW_PAL_BUILD_MIXER: 'CommonBuffId' = 189585 + SNOW_PAL_BUILD_SNOW_PAL: 'CommonBuffId' = 180543 + SNOW_PAL_DESTROYED_SNOW_PAL: 'CommonBuffId' = 189633 + SNOW_PAL_PICKED_SIM: 'CommonBuffId' = 183011 + SNOW_PAL_RUNNING_INTERACTION: 'CommonBuffId' = 188806 + SNOW_PAL_SNOW_DRIFT: 'CommonBuffId' = 183053 + SNOW_PAL_SNOW_DRIFT_BOOST: 'CommonBuffId' = 188953 + SNOW_PAL_TELL_STORY: 'CommonBuffId' = 180568 + SNOW_SPORTS_SLOPE_AUTONOMY: 'CommonBuffId' = 248984 + SNOW_SPORTS_SLOPE_DEBUG_FORCE_FAILURE_OUTCOME: 'CommonBuffId' = 251479 + SNOW_SPORTS_SLOPE_DEBUG_FORCE_SUCCESS_OUTCOME: 'CommonBuffId' = 251478 + SNOW_SPORTS_SLOPE_DEBUG_FORCE_X_EVENT_FAIL: 'CommonBuffId' = 252123 + SNOW_SPORTS_SLOPE_DEBUG_FORCE_X_EVENT_SUCCESS: 'CommonBuffId' = 252122 + SNOW_SPORTS_SLOPE_DID_CRASH: 'CommonBuffId' = 252248 + SNOW_SPORTS_SLOPE_ENERGIZED_CERTIFIED_RIPPER: 'CommonBuffId' = 246446 + SNOW_SPORTS_SLOPE_ENERGIZED_SHREDDIN_THE_GNAR: 'CommonBuffId' = 246447 + SNOW_SPORTS_SLOPE_ENERGIZED_SKI_ENTHUSIAST: 'CommonBuffId' = 246450 + SNOW_SPORTS_SLOPE_HAPPY_DONE_WITH_STEEZ: 'CommonBuffId' = 246452 + SNOW_SPORTS_SLOPE_HAPPY_EXCELLENT_TIME_SKIING: 'CommonBuffId' = 246454 + SNOW_SPORTS_SLOPE_HAPPY_FEEL_LIKE_A_KID: 'CommonBuffId' = 246540 + SNOW_SPORTS_SLOPE_HAPPY_FEEL_THE_RUSH: 'CommonBuffId' = 246453 + SNOW_SPORTS_SLOPE_HAPPY_GLOWING_WITH_GLEE: 'CommonBuffId' = 246455 + SNOW_SPORTS_SLOPE_HAPPY_MASTER_OF_SKIIING: 'CommonBuffId' = 246451 + SNOW_SPORTS_SLOPE_HAPPY_SNOWBOARD_ENTHUSIAST: 'CommonBuffId' = 246469 + SNOW_SPORTS_SLOPE_HIGH_INTENSITY: 'CommonBuffId' = 247310 + SNOW_SPORTS_SLOPE_IS_SLEDDING: 'CommonBuffId' = 255270 + SNOW_SPORTS_SLOPE_LOW_INTENSITY: 'CommonBuffId' = 247309 + SNOW_SPORTS_SLOPE_MED_INTENSITY: 'CommonBuffId' = 247311 + SNOW_SPORTS_SLOPE_RECENT_EXTREME_SUCCESS: 'CommonBuffId' = 252869 + SNOW_SPORTS_SLOPE_RECENT_INJURY: 'CommonBuffId' = 254353 + SNOW_SPORTS_SLOPE_RECENT_SKI_OR_SNOWBOARD: 'CommonBuffId' = 252515 + SNOW_SPORTS_SLOPE_REMOVE_TURNS: 'CommonBuffId' = 256535 + SNOW_SPORTS_SLOPE_RENTAL_GEAR: 'CommonBuffId' = 253784 + SNOW_SPORTS_SLOPE_SAD_BETTER_LUCK_NEXT_TIME: 'CommonBuffId' = 246456 + SNOW_SPORTS_SLOPE_SAD_GETTING_TOOOLD: 'CommonBuffId' = 246448 + SNOW_SPORTS_SLOPE_SAD_IT_WASNT_MY_DAY: 'CommonBuffId' = 246457 + SNOW_SPORTS_SLOPE_SAD_I_CAN_DO_BETTER: 'CommonBuffId' = 246460 + SNOW_SPORTS_SLOPE_SAD_NEED_MORE_PRACTICE: 'CommonBuffId' = 246444 + SNOW_SPORTS_SLOPE_SAD_NOT_AS_READY_AS_I_THOUGHT: 'CommonBuffId' = 246445 + SNOW_SPORTS_SLOPE_SAD_SO_MANY_BUMPS: 'CommonBuffId' = 246459 + SNOW_SPORTS_SLOPE_SAD_TOO_MUCH_SLOPE: 'CommonBuffId' = 246458 + SNOW_SPORTS_SLOPE_SAD_WHAT_AM_I_DOING_WRONG: 'CommonBuffId' = 246443 + SNOW_SPORTS_SLOPE_SAD_WHAT_A_BIFF: 'CommonBuffId' = 246442 + SNOW_SPORTS_SLOPE_SLOPE_SETTINGS_CLEAR_TIMER: 'CommonBuffId' = 251990 + SNOW_SPORTS_SLOPE_UNCOMFORTABLE_SORE_FEET: 'CommonBuffId' = 248083 + SNOW_SPORTS_SLOPE_WEARING_BOOTS_SKI: 'CommonBuffId' = 255259 + SNOW_SPORTS_SLOPE_WEARING_BOOTS_SNOWBOARD: 'CommonBuffId' = 255258 + SNOW_SPORTS_SLOPE_WEAR_BOOTS_SKI: 'CommonBuffId' = 254529 + SNOW_SPORTS_SLOPE_WEAR_BOOTS_SNOWBOARD: 'CommonBuffId' = 254528 + SOCCER_BALL_AUTONOMOUS: 'CommonBuffId' = 230107 + SOCCER_BALL_HIDDEN_BALL_BUFFS_0: 'CommonBuffId' = 224525 + SOCCER_BALL_HIDDEN_BALL_BUFFS_1: 'CommonBuffId' = 224526 + SOCCER_BALL_HIDDEN_BALL_BUFFS_2: 'CommonBuffId' = 224527 + SOCCER_BALL_HIDDEN_BALL_BUFFS_3: 'CommonBuffId' = 224528 + SOCCER_BALL_HIDDEN_BALL_BUFFS_4: 'CommonBuffId' = 228801 + SOCCER_BALL_HIDDEN_KICKING: 'CommonBuffId' = 224631 + SOCCER_BALL_HIDDEN_PICKED_ALREADY: 'CommonBuffId' = 229827 + SOCCER_BALL_MISSED_THE_KICK: 'CommonBuffId' = 224617 + SOCCER_BALL_NEW_RECORD: 'CommonBuffId' = 224619 + SOCCER_BALL_SOCCER_RAGE: 'CommonBuffId' = 224462 + SOCCER_BALL_SOCCER_SUCKAGE: 'CommonBuffId' = 224459 + SOCCER_BALL_WHO_AM_I: 'CommonBuffId' = 224618 + SOCIALS_OCTOBER_CHALLENGE_TREAT: 'CommonBuffId' = 126732 + SOCIALS_OCTOBER_CHALLENGE_TRICK: 'CommonBuffId' = 126731 + SOCIAL_MEDIA_APPLICATION_DISABLE: 'CommonBuffId' = 303000 + SOCIAL_MEDIA_DISABLE_AT_FAMILY_DINNER: 'CommonBuffId' = 292431 + SOCIAL_MEDIA_DISABLE_AT_LUNCH: 'CommonBuffId' = 285137 + SOCIAL_MEDIA_DISABLE_AT_PROM: 'CommonBuffId' = 285122 + SOCIAL_MEDIA_DISABLE_BACK_FROM_WORK: 'CommonBuffId' = 292432 + SOCIAL_MEDIA_DISABLE_BROWSING_THRIFT_STORE: 'CommonBuffId' = 285196 + SOCIAL_MEDIA_DISABLE_CAREER_DAY_FINISHED: 'CommonBuffId' = 285144 + SOCIAL_MEDIA_DISABLE_CHANGED_OUTFIT: 'CommonBuffId' = 292434 + SOCIAL_MEDIA_DISABLE_CHEERLEADING_PRACTICE_FINISHED: 'CommonBuffId' = 285212 + SOCIAL_MEDIA_DISABLE_CHESS_PRACTICE_FINISHED: 'CommonBuffId' = 285213 + SOCIAL_MEDIA_DISABLE_COMPUTER_LAB_PRACTICE_FINISHED: 'CommonBuffId' = 285216 + SOCIAL_MEDIA_DISABLE_CRIED_IN_LOCKER: 'CommonBuffId' = 285155 + SOCIAL_MEDIA_DISABLE_DEATH_STINK_CAPSULE: 'CommonBuffId' = 285204 + SOCIAL_MEDIA_DISABLE_DEATH_URBAN_MYTH: 'CommonBuffId' = 285201 + SOCIAL_MEDIA_DISABLE_DETENTION_FINISHED: 'CommonBuffId' = 285139 + SOCIAL_MEDIA_DISABLE_DRINKING_BUBBLE_TEA: 'CommonBuffId' = 285184 + SOCIAL_MEDIA_DISABLE_DROPPED_OUT: 'CommonBuffId' = 285225 + SOCIAL_MEDIA_DISABLE_EATING_CAFETERIA_FOOD: 'CommonBuffId' = 285181 + SOCIAL_MEDIA_DISABLE_FINALS_FINISHED: 'CommonBuffId' = 285135 + SOCIAL_MEDIA_DISABLE_FIRE_DRILL_FINISHED: 'CommonBuffId' = 285146 + SOCIAL_MEDIA_DISABLE_FOOTBALL_PRACTICE_FINISHED: 'CommonBuffId' = 285209 + SOCIAL_MEDIA_DISABLE_GOING_ON_VACATION: 'CommonBuffId' = 292435 + SOCIAL_MEDIA_DISABLE_GOT_ENGAGED: 'CommonBuffId' = 292439 + SOCIAL_MEDIA_DISABLE_GOT_MARRIED: 'CommonBuffId' = 292440 + SOCIAL_MEDIA_DISABLE_GRADUATED: 'CommonBuffId' = 285128 + SOCIAL_MEDIA_DISABLE_HID_IN_LOCKER: 'CommonBuffId' = 285157 + SOCIAL_MEDIA_DISABLE_HOMEWORK_FINISHED: 'CommonBuffId' = 285228 + SOCIAL_MEDIA_DISABLE_HOSTING_PARTY: 'CommonBuffId' = 292441 + SOCIAL_MEDIA_DISABLE_JOINED_CLUB: 'CommonBuffId' = 285208 + SOCIAL_MEDIA_DISABLE_NEW_BABY: 'CommonBuffId' = 292442 + SOCIAL_MEDIA_DISABLE_ORIENTATION_FINISHED: 'CommonBuffId' = 285131 + SOCIAL_MEDIA_DISABLE_PASSION_EXCELLENCE: 'CommonBuffId' = 285193 + SOCIAL_MEDIA_DISABLE_PASSION_FASHION: 'CommonBuffId' = 285189 + SOCIAL_MEDIA_DISABLE_PASSION_PARTY: 'CommonBuffId' = 285192 + SOCIAL_MEDIA_DISABLE_PHOTO_BOOTH_PHOTO: 'CommonBuffId' = 285176 + SOCIAL_MEDIA_DISABLE_PHOTO_BOOTH_ROMANCE: 'CommonBuffId' = 285177 + SOCIAL_MEDIA_DISABLE_PILLOW_FIGHT: 'CommonBuffId' = 285089 + SOCIAL_MEDIA_DISABLE_PRANKED: 'CommonBuffId' = 285205 + SOCIAL_MEDIA_DISABLE_PREPARE_PROM: 'CommonBuffId' = 285118 + SOCIAL_MEDIA_DISABLE_PROMOTE_FASHION: 'CommonBuffId' = 285117 + SOCIAL_MEDIA_DISABLE_PROMOTE_SIMSFLUENCER: 'CommonBuffId' = 285185 + SOCIAL_MEDIA_DISABLE_PROMOTE_VIDEO_GAME_STREAM: 'CommonBuffId' = 285188 + SOCIAL_MEDIA_DISABLE_PROM_JESTER: 'CommonBuffId' = 285127 + SOCIAL_MEDIA_DISABLE_PROM_ROYALTY: 'CommonBuffId' = 285124 + SOCIAL_MEDIA_DISABLE_RETURNED_FROM_TRAVEL: 'CommonBuffId' = 292443 + SOCIAL_MEDIA_DISABLE_REVIEWED_BOOK: 'CommonBuffId' = 292444 + SOCIAL_MEDIA_DISABLE_REVIEWED_MEDIA: 'CommonBuffId' = 292445 + SOCIAL_MEDIA_DISABLE_SAW_FIGHT: 'CommonBuffId' = 285141 + SOCIAL_MEDIA_DISABLE_SNEAKING_OUT: 'CommonBuffId' = 285160 + SOCIAL_MEDIA_DISABLE_SOCIALLY_AWKWARD: 'CommonBuffId' = 285180 + SOCIAL_MEDIA_DISABLE_WENT_LOITERING: 'CommonBuffId' = 285166 + SOCIAL_MEDIA_DISABLE_WENT_ON_SHOPPING_TRIP: 'CommonBuffId' = 292446 + SOCIAL_MEDIA_DISABLE_WENT_ON_VACATION: 'CommonBuffId' = 292447 + SOCIAL_MEDIA_DISABLE_WENT_TO_COLLEGE_PARTY: 'CommonBuffId' = 285162 + SOCIAL_MEDIA_DISABLE_WENT_TO_CONCERT: 'CommonBuffId' = 285168 + SOCIAL_MEDIA_DISABLE_WENT_TO_FOOTBALL_GAME: 'CommonBuffId' = 285171 + SOCIAL_MEDIA_DISABLE_WENT_TO_HANG_OUT: 'CommonBuffId' = 285163 + SOCIAL_MEDIA_DISABLE_WENT_TO_R_MOVIE: 'CommonBuffId' = 285170 + SOCIAL_MEDIA_DISABLE_WENT_TO_SLEEPOVER: 'CommonBuffId' = 285174 + SOCIAL_MEDIA_DISABLE_WITNESSED_DEATH: 'CommonBuffId' = 292448 + SOCIAL_MEDIA_ENABLE_AT_FAMILY_DINNER: 'CommonBuffId' = 292500 + SOCIAL_MEDIA_ENABLE_AT_LUNCH: 'CommonBuffId' = 285136 + SOCIAL_MEDIA_ENABLE_AT_PROM: 'CommonBuffId' = 285121 + SOCIAL_MEDIA_ENABLE_BACK_FROM_WORK: 'CommonBuffId' = 292501 + SOCIAL_MEDIA_ENABLE_BROWSING_THRIFT_STORE: 'CommonBuffId' = 285195 + SOCIAL_MEDIA_ENABLE_CAREER_DAY_FINISHED: 'CommonBuffId' = 285143 + SOCIAL_MEDIA_ENABLE_CHANGED_OUTFIT: 'CommonBuffId' = 292503 + SOCIAL_MEDIA_ENABLE_CHEERLEADING_PRACTICE_FINISHED: 'CommonBuffId' = 285211 + SOCIAL_MEDIA_ENABLE_CHESS_PRACTICE_FINISHED: 'CommonBuffId' = 285214 + SOCIAL_MEDIA_ENABLE_COMPUTER_LAB_PRACTICE_FINISHED: 'CommonBuffId' = 285215 + SOCIAL_MEDIA_ENABLE_CRIED_IN_LOCKER: 'CommonBuffId' = 285156 + SOCIAL_MEDIA_ENABLE_DEATH_STINK_CAPSULE: 'CommonBuffId' = 285203 + SOCIAL_MEDIA_ENABLE_DEATH_URBAN_MYTH: 'CommonBuffId' = 285202 + SOCIAL_MEDIA_ENABLE_DETENTION_FINISHED: 'CommonBuffId' = 285138 + SOCIAL_MEDIA_ENABLE_DRINKING_BUBBLE_TEA: 'CommonBuffId' = 285183 + SOCIAL_MEDIA_ENABLE_DROPPED_OUT: 'CommonBuffId' = 285226 + SOCIAL_MEDIA_ENABLE_EATING_CAFETERIA_FOOD: 'CommonBuffId' = 285182 + SOCIAL_MEDIA_ENABLE_FINALS_FINISHED: 'CommonBuffId' = 285134 + SOCIAL_MEDIA_ENABLE_FIRE_DRILL_FINISHED: 'CommonBuffId' = 285145 + SOCIAL_MEDIA_ENABLE_FOOTBALL_PRACTICE_FINISHED: 'CommonBuffId' = 285210 + SOCIAL_MEDIA_ENABLE_GOING_ON_VACATION: 'CommonBuffId' = 292504 + SOCIAL_MEDIA_ENABLE_GOT_ENGAGED: 'CommonBuffId' = 292505 + SOCIAL_MEDIA_ENABLE_GOT_MARRIED: 'CommonBuffId' = 292506 + SOCIAL_MEDIA_ENABLE_GRADUATED: 'CommonBuffId' = 285129 + SOCIAL_MEDIA_ENABLE_HID_IN_LOCKER: 'CommonBuffId' = 285158 + SOCIAL_MEDIA_ENABLE_HOMEWORK_FINISHED: 'CommonBuffId' = 285227 + SOCIAL_MEDIA_ENABLE_HOSTING_PARTY: 'CommonBuffId' = 292507 + SOCIAL_MEDIA_ENABLE_JOINED_CLUB: 'CommonBuffId' = 285207 + SOCIAL_MEDIA_ENABLE_NEW_BABY: 'CommonBuffId' = 292508 + SOCIAL_MEDIA_ENABLE_ORIENTATION_FINISHED: 'CommonBuffId' = 285130 + SOCIAL_MEDIA_ENABLE_PASSION_EXCELLENCE: 'CommonBuffId' = 285194 + SOCIAL_MEDIA_ENABLE_PASSION_FASHION: 'CommonBuffId' = 285190 + SOCIAL_MEDIA_ENABLE_PASSION_PARTY: 'CommonBuffId' = 285191 + SOCIAL_MEDIA_ENABLE_PHOTO_BOOTH_PHOTO: 'CommonBuffId' = 285175 + SOCIAL_MEDIA_ENABLE_PHOTO_BOOTH_ROMANCE: 'CommonBuffId' = 285178 + SOCIAL_MEDIA_ENABLE_PILLOW_FIGHT: 'CommonBuffId' = 284506 + SOCIAL_MEDIA_ENABLE_PRANKED: 'CommonBuffId' = 285206 + SOCIAL_MEDIA_ENABLE_PREPARE_PROM: 'CommonBuffId' = 285119 + SOCIAL_MEDIA_ENABLE_PROMOTE_FASHION: 'CommonBuffId' = 285116 + SOCIAL_MEDIA_ENABLE_PROMOTE_SIMSFLUENCER: 'CommonBuffId' = 285186 + SOCIAL_MEDIA_ENABLE_PROMOTE_VIDEO_GAME_STREAM: 'CommonBuffId' = 285187 + SOCIAL_MEDIA_ENABLE_PROM_JESTER: 'CommonBuffId' = 285126 + SOCIAL_MEDIA_ENABLE_PROM_ROYALTY: 'CommonBuffId' = 285125 + SOCIAL_MEDIA_ENABLE_RETURNED_FROM_TRAVEL: 'CommonBuffId' = 292509 + SOCIAL_MEDIA_ENABLE_REVIEWED_BOOK: 'CommonBuffId' = 292510 + SOCIAL_MEDIA_ENABLE_REVIEWED_MEDIA: 'CommonBuffId' = 292511 + SOCIAL_MEDIA_ENABLE_SAW_FIGHT: 'CommonBuffId' = 285140 + SOCIAL_MEDIA_ENABLE_SNEAKING_OUT: 'CommonBuffId' = 285159 + SOCIAL_MEDIA_ENABLE_SOCIALLY_AWKWARD: 'CommonBuffId' = 285179 + SOCIAL_MEDIA_ENABLE_WENT_LOITERING: 'CommonBuffId' = 285165 + SOCIAL_MEDIA_ENABLE_WENT_ON_SHOPPING_TRIP: 'CommonBuffId' = 292512 + SOCIAL_MEDIA_ENABLE_WENT_ON_VACATION: 'CommonBuffId' = 292513 + SOCIAL_MEDIA_ENABLE_WENT_TO_COLLEGE_PARTY: 'CommonBuffId' = 285161 + SOCIAL_MEDIA_ENABLE_WENT_TO_CONCERT: 'CommonBuffId' = 285167 + SOCIAL_MEDIA_ENABLE_WENT_TO_FOOTBALL_GAME: 'CommonBuffId' = 285172 + SOCIAL_MEDIA_ENABLE_WENT_TO_HANG_OUT: 'CommonBuffId' = 285164 + SOCIAL_MEDIA_ENABLE_WENT_TO_R_MOVIE: 'CommonBuffId' = 285169 + SOCIAL_MEDIA_ENABLE_WENT_TO_SLEEPOVER: 'CommonBuffId' = 285173 + SOCIAL_MEDIA_ENABLE_WITNESSED_DEATH: 'CommonBuffId' = 292514 + SOCIAL_MEDIA_MOODLETS_ANGRY: 'CommonBuffId' = 283564 + SOCIAL_MEDIA_MOODLETS_CONFIDENT: 'CommonBuffId' = 283565 + SOCIAL_MEDIA_MOODLETS_EMBARRASSED: 'CommonBuffId' = 283566 + SOCIAL_MEDIA_MOODLETS_ENERGIZED: 'CommonBuffId' = 283567 + SOCIAL_MEDIA_MOODLETS_FLIRTY: 'CommonBuffId' = 283568 + SOCIAL_MEDIA_MOODLETS_HAPPY: 'CommonBuffId' = 283569 + SOCIAL_MEDIA_MOODLETS_SAD: 'CommonBuffId' = 283570 + SOCIAL_MEDIA_MOODLETS_STRESSED: 'CommonBuffId' = 283571 + SOCIAL_MEDIA_MOODLETS_SUPERIOR_ANGRY: 'CommonBuffId' = 283589 + SOCIAL_MEDIA_MOODLETS_SUPERIOR_CONFIDENT: 'CommonBuffId' = 283590 + SOCIAL_MEDIA_MOODLETS_SUPERIOR_EMBARRASSED: 'CommonBuffId' = 283591 + SOCIAL_MEDIA_MOODLETS_SUPERIOR_ENERGIZED: 'CommonBuffId' = 283592 + SOCIAL_MEDIA_MOODLETS_SUPERIOR_FLIRTY: 'CommonBuffId' = 283593 + SOCIAL_MEDIA_MOODLETS_SUPERIOR_HAPPY: 'CommonBuffId' = 283594 + SOCIAL_MEDIA_MOODLETS_SUPERIOR_SAD: 'CommonBuffId' = 283595 + SOCIAL_MEDIA_MOODLETS_SUPERIOR_STRESSED: 'CommonBuffId' = 283596 + SOCIAL_MEDIA_MOODLETS_SUPERIOR_UNCOMFORTABLE: 'CommonBuffId' = 285781 + SOCIAL_MEDIA_MOODLETS_UNCOMFORTABLE: 'CommonBuffId' = 285779 + SOCIAL_MEDIA_PANEL_ACTIVE: 'CommonBuffId' = 303905 + SOCIAL_MEDIA_POST_LESS_OFTEN: 'CommonBuffId' = 277258 + SOCIAL_MEDIA_POST_MORE_OFTEN: 'CommonBuffId' = 277252 + SOCIAL_MEDIA_SUPPRESS_TNS: 'CommonBuffId' = 298267 + SOCIAL_MEDIA_TALKED_ABOUT_MOODLETS_HIDDEN_NPC: 'CommonBuffId' = 283612 + SOCIAL_NETWORK_SOCIAL_MEDIA_FATIGUE: 'CommonBuffId' = 200267 + SOCIAL_SHOW_FLASH_CARDS_TODDLER_BOREDOM_ANGRY: 'CommonBuffId' = 143382 + SOCIAL_SHOW_FLASH_CARDS_TODDLER_BOREDOM_SAD: 'CommonBuffId' = 143383 + SOCIAL_SHOW_FLASH_CARDS_TODDLER_ENJOYING: 'CommonBuffId' = 146468 + SOCIAL_SHOW_FLASH_CARDS_TODDLER_GUESS_RIGHT: 'CommonBuffId' = 143277 + SOCIAL_SHOW_FLASH_CARDS_TODDLER_GUESS_WRONG: 'CommonBuffId' = 143278 + SOCIAL_SHOW_FLASH_CARDS_TODDLER_HOLDING_CARD: 'CommonBuffId' = 143275 + SOLAR_PANEL_TESTED_SELF_CLEAN_FAIL: 'CommonBuffId' = 238090 + SOLAR_PANEL_TESTED_SELF_CLEAN_SUCCESS: 'CommonBuffId' = 238089 + SPARKED_BY_CLOUDS: 'CommonBuffId' = 105319 + SPECIAL_MOMENTS_HAD_WOOHOO_MARRIED_ON_VACATION_HIDDEN: 'CommonBuffId' = 280580 + SPELLS_CASTING_SPELL_OBJECT_CLEAN: 'CommonBuffId' = 216176 + SPELLS_CASTING_SPELL_OBJECT_DUPLICATE: 'CommonBuffId' = 216177 + SPELLS_CASTING_SPELL_OBJECT_FIRE: 'CommonBuffId' = 216180 + SPELLS_CASTING_SPELL_OBJECT_LIGHTNING: 'CommonBuffId' = 216178 + SPELLS_CASTING_SPELL_OBJECT_REPAIR: 'CommonBuffId' = 216179 + SPELLS_CASTING_SPELL_SELF_CLONE: 'CommonBuffId' = 216201 + SPELLS_CASTING_SPELL_SIM_CHANGE_SIM_APPEARANCE: 'CommonBuffId' = 216203 + SPELLS_CASTING_SPELL_SIM_CONFUSE: 'CommonBuffId' = 216202 + SPELLS_CASTING_SPELL_SIM_FIRE: 'CommonBuffId' = 216200 + SPELLS_CASTING_SPELL_SIM_FREEZE: 'CommonBuffId' = 216199 + SPELLS_CASTING_SPELL_SIM_LIGHTNING: 'CommonBuffId' = 216197 + SPELLS_CASTING_SPELL_SIM_SADNESS: 'CommonBuffId' = 216196 + SPELLS_CASTING_SPELL_SIM_TRANSFORM: 'CommonBuffId' = 216198 + SPELLS_CASTING_SPELL_TERRAIN_CONJURE_FOOD: 'CommonBuffId' = 216259 + SPELLS_CASTING_SPELL_TERRAIN_SPAWN_PLANT: 'CommonBuffId' = 216261 + SPELLS_CASTING_SPELL_TERRAIN_TELEPORT: 'CommonBuffId' = 216260 + SPELLS_CAST_FIRE_NOPANIC: 'CommonBuffId' = 218910 + SPELLS_CLONE_BREAK_OBJECT_COOLDOWN: 'CommonBuffId' = 216326 + SPELLS_CLONE_CLEAN: 'CommonBuffId' = 215945 + SPELLS_CLONE_COOK: 'CommonBuffId' = 215974 + SPELLS_CLONE_FAIL_EVIL: 'CommonBuffId' = 216117 + SPELLS_CLONE_FIGHT_AUTONOMOUS_COOLDOWN: 'CommonBuffId' = 216325 + SPELLS_CLONE_MEAN_INT_COOLDOWN: 'CommonBuffId' = 216299 + SPELLS_CLONE_SUCCESS: 'CommonBuffId' = 215997 + SPELLS_DEBUG_OUTCOME_CHANCE_FAIL: 'CommonBuffId' = 216648 + SPELLS_DEBUG_OUTCOME_CHANCE_SUCCEED: 'CommonBuffId' = 216647 + SPELLS_FIGHT: 'CommonBuffId' = 215368 + SPELLS_FIRE: 'CommonBuffId' = 217264 + SPELLS_FREEZE_CHILLED: 'CommonBuffId' = 222804 + SPELLS_FROZEN: 'CommonBuffId' = 215498 + SPELLS_FROZEN_CHARGED: 'CommonBuffId' = 215587 + SPELLS_FROZEN_FAIL: 'CommonBuffId' = 221541 + SPELLS_FROZEN_FAIL_VISIBLE: 'CommonBuffId' = 222830 + SPELLS_LIGHTNING: 'CommonBuffId' = 217239 + SPELLS_LOVE: 'CommonBuffId' = 215401 + SPELLS_MIND_CONTROL_CONTROLLED_AI: 'CommonBuffId' = 216139 + SPELLS_MIND_CONTROL_CONTROLLED_AI_LONG_DURATION: 'CommonBuffId' = 216142 + SPELLS_PRACTICE_SPELLCASTING_LEARNED_SPELL: 'CommonBuffId' = 215007 + SPELLS_REACTION_COOLDOWN: 'CommonBuffId' = 214902 + SPELLS_REMOVE_CURSE_COOLDOWN: 'CommonBuffId' = 215991 + SPELLS_REMOVE_CURSE_COOLDOWN_SHORT: 'CommonBuffId' = 215992 + SPELLS_SEARCH_FOR_TOMES_COOLDOWN: 'CommonBuffId' = 216294 + SPELLS_SEARCH_FOR_TOMES_REMOVE_COUNTER: 'CommonBuffId' = 217669 + SPELLS_SIM_CLEAN_SLOW_HYGIENE_DECAY: 'CommonBuffId' = 215618 + SPELLS_SIM_CONFUSE_BE_CONFUSED: 'CommonBuffId' = 213320 + SPELLS_SIM_CONFUSE_BE_CONFUSED_CHARGED: 'CommonBuffId' = 213323 + SPELLS_SIM_GET_TRANSFORMED_IN_TO_OBJECT: 'CommonBuffId' = 213741 + SPELLS_SIM_GET_TRANSFORMED_IN_TO_OBJECT_LONG: 'CommonBuffId' = 221277 + SPELLS_SIM_RESURRECT: 'CommonBuffId' = 213595 + SPELLS_SIM_RESURRECT_CHARGED: 'CommonBuffId' = 213596 + SPELLS_SIM_RESURRECT_FAIL: 'CommonBuffId' = 213611 + SPELLS_SIM_SADNESS_BE_SAD: 'CommonBuffId' = 213372 + SPELLS_SIM_SADNESS_BE_SAD_CHARGED: 'CommonBuffId' = 213374 + SPELLS_STEAL_CAUGHT_STEALING: 'CommonBuffId' = 218608 + SPELLS_STEAL_SUCCESS: 'CommonBuffId' = 218602 + SPELLS_STEAL_WITNESS_STEALING: 'CommonBuffId' = 218605 + SPELLS_TEACH_SPELL_COOLDOWN_CATEGORY_MISCHIEF: 'CommonBuffId' = 213677 + SPELLS_TEACH_SPELL_COOLDOWN_CATEGORY_PRACTICAL: 'CommonBuffId' = 213681 + SPELLS_TEACH_SPELL_COOLDOWN_CATEGORY_UNTAMED: 'CommonBuffId' = 213682 + SPELL_REPULSIVENESS: 'CommonBuffId' = 216514 + SPELL_REPULSIVENESS_CHARGED: 'CommonBuffId' = 216521 + SPINE_TINGLING_THRILL: 'CommonBuffId' = 108014 + SPINE_TINGLING_THRILL_GREAT_STORYTELLER: 'CommonBuffId' = 109747 + SPIRIT_HOUSE_SOOTHING_SMELL: 'CommonBuffId' = 350193 + SPLASH_COOLDOWN: 'CommonBuffId' = 215761 + SPLASH_PAD_ANGRY_STOMP: 'CommonBuffId' = 304326 + SPLASH_PAD_COLD_WEATHER: 'CommonBuffId' = 304328 + SPLASH_PAD_RAINY: 'CommonBuffId' = 304327 + SPLASH_PAD_SHENANIGANS: 'CommonBuffId' = 304323 + SPLASH_PAD_STATISTIC: 'CommonBuffId' = 311089 + SPLASH_PAD_STOMPED: 'CommonBuffId' = 304325 + SPLASH_PAD_WATER_WET: 'CommonBuffId' = 304324 + SPLASH_WATER_IN_EYE: 'CommonBuffId' = 105900 + SPORE_HALLWAY_CONNECTIVITY: 'CommonBuffId' = 204775 + SPORTS_ARENA_LOSS_RIVAL_SCHOOL: 'CommonBuffId' = 222429 + SPORTS_ARENA_LOSS_RIVAL_SCHOOL_HOTHEADED: 'CommonBuffId' = 222432 + SPORTS_ARENA_NO_SCHOOL_SAW_A_GREAT_GAME: 'CommonBuffId' = 228163 + SPORTS_ARENA_WINNER_MY_SCHOOL: 'CommonBuffId' = 222427 + SPORTS_ARENA_WINNER_MY_SCHOOL_ACTIVE_TRAIT: 'CommonBuffId' = 222430 + SPRING_CHALLENGE_2016_GIVE_PRISTINE_GROWFRUIT: 'CommonBuffId' = 135591 + SPRING_CHALLENGE_2016_GIVE_X_GROWFRUIT: 'CommonBuffId' = 135429 + SPRING_CHALLENGE_PLANT_SIMS_NPC_ANGRY: 'CommonBuffId' = 163064 + SPRING_CHALLENGE_PLANT_SIMS_NPC_BEANS_GIVEN: 'CommonBuffId' = 163053 + SPRING_CHALLENGE_PLANT_SIMS_NPC_CONFIDENT: 'CommonBuffId' = 163066 + SPRING_CHALLENGE_PLANT_SIMS_NPC_FLIRTY: 'CommonBuffId' = 163067 + SPRING_CHALLENGE_PLANT_SIMS_NPC_PLAYFUL: 'CommonBuffId' = 163069 + SPRING_CHALLENGE_PLANT_SIMS_NPC_ROLE: 'CommonBuffId' = 163061 + SPRING_CHALLENGE_PLANT_SIMS_NPC_SAD: 'CommonBuffId' = 163065 + SPRING_CHALLENGE_PLANT_SIMS_NPC_UNCOMFORTABLE: 'CommonBuffId' = 163068 + SPRINKLER_PLAYED_IN: 'CommonBuffId' = 185928 + SPRINKLER_WET_FX_ADULT: 'CommonBuffId' = 189638 + SPRINKLER_WET_FX_CHILD: 'CommonBuffId' = 189656 + SPRINKLER_WET_FX_TODDLER: 'CommonBuffId' = 189772 + SQUAT_TOILET_ENERGIZED: 'CommonBuffId' = 351054 + SQUAT_TOILET_EXHAUSTED: 'CommonBuffId' = 351106 + STAGE_SOUND_TURN_OFF: 'CommonBuffId' = 198940 + STARTLED_BY_GHOST_TENSE: 'CommonBuffId' = 102401 + STOP_FLOATING: 'CommonBuffId' = 119855 + STORY_PROGRESSION_NEIGHBORHOOD_STORIES_RELATIONSHIP_UPDATES_NEIGHBOR_BECOMING_BEST_FRIENDS: 'CommonBuffId' = 381993 + STORY_PROGRESSION_NEIGHBORHOOD_STORIES_RELATIONSHIP_UPDATES_NEIGHBOR_BECOMING_DESPISED: 'CommonBuffId' = 381994 + STORY_PROGRESSION_NEIGHBORHOOD_STORIES_RELATIONSHIP_UPDATES_NEIGHBOR_BECOMING_FRIENDS: 'CommonBuffId' = 381926 + STORY_PROGRESSION_NEIGHBORHOOD_STORIES_RELATIONSHIP_UPDATES_NEIGHBOR_ROMANCE_RELATIONSHIP_END: 'CommonBuffId' = 381997 + STORY_PROGRESSION_NEIGHBORHOOD_STORIES_RELATIONSHIP_UPDATES_NEIGHBOR_ROMANCE_RELATIONSHIP_RESTART: 'CommonBuffId' = 381996 + STORY_PROGRESSION_NEIGHBORHOOD_STORIES_RELATIONSHIP_UPDATES_NEIGHBOR_ROMANCE_RELATIONSHIP_START: 'CommonBuffId' = 381995 + STRANGELY_CALMING_SCENT: 'CommonBuffId' = 118499 + STRAYS_HAS_EXPLORED_BUSH: 'CommonBuffId' = 175441 + STRAYS_HAS_EXPLORED_DIRT_MOUND: 'CommonBuffId' = 175444 + STRAYS_HAS_EXPLORED_FISH_PILE: 'CommonBuffId' = 175442 + STRAYS_HAS_EXPLORED_SEAWEED_PILE: 'CommonBuffId' = 175443 + STREAKER_REACTION_HIDDEN: 'CommonBuffId' = 100091 + STREAK_ENERGIZED: 'CommonBuffId' = 99588 + STREAMING_DRONE_HAPPY_STREAMING: 'CommonBuffId' = 200190 + STREAMING_DRONE_SAD_BROKEN: 'CommonBuffId' = 200192 + STREAMING_DRONE_STREAMING: 'CommonBuffId' = 193298 + STREET_BUSKER_ACTIVE_HIDDEN: 'CommonBuffId' = 140750 + STUDENT_COMMONS_ARTS_POETRY_PRESENTED_POETRY: 'CommonBuffId' = 221910 + STUDENT_COMMONS_ARTS_POETRY_READING: 'CommonBuffId' = 221765 + STUDENT_COMMONS_ARTS_POETRY_TEA_SERVING: 'CommonBuffId' = 221843 + STUDENT_COMMONS_ARTS_POETRY_WAITING: 'CommonBuffId' = 221842 + STUDENT_COMMONS_EXAM_CRAM_LAST_CHANCE_TO_STUDY: 'CommonBuffId' = 222223 + STUDENT_COMMONS_MIXER_JUICE_KEG_BEARER_ARRIVE: 'CommonBuffId' = 222117 + STUDENT_COMMONS_MIXER_PARTY: 'CommonBuffId' = 222166 + STUDENT_COMMONS_POETRY_TEA_SERVE_COOLDOWN: 'CommonBuffId' = 229861 + STUDENT_COMMONS_PROFESSOR_GOOD: 'CommonBuffId' = 222365 + STUDENT_COMMONS_PROFESSOR_GRUMPY: 'CommonBuffId' = 222362 + STUDENT_COMMONS_PROFESSOR_HIP: 'CommonBuffId' = 222363 + STUDENT_COMMONS_SCIENCE_E_SPORTS_EVENT_PARTICIPATING: 'CommonBuffId' = 221970 + STUDENT_COMMONS_SCIENCE_E_SPORTS_POWER_SIP_COOLDOWN: 'CommonBuffId' = 222312 + STUFFED_ANIMAL_INSPIRED: 'CommonBuffId' = 25068 + STUFFED_ANIMAL_TODDLER_TALK_BABBLE_COOLDOWN: 'CommonBuffId' = 328272 + STYLEBOARD_FIND_MUSE_MOOD_HIGH_CONFIDENT: 'CommonBuffId' = 198545 + STYLEBOARD_FIND_MUSE_MOOD_HIGH_ENERGIZED: 'CommonBuffId' = 198546 + STYLEBOARD_FIND_MUSE_MOOD_HIGH_FLIRTY: 'CommonBuffId' = 198548 + STYLEBOARD_FIND_MUSE_MOOD_HIGH_INSPIRED: 'CommonBuffId' = 198551 + STYLEBOARD_FIND_MUSE_MOOD_LOW_CONFIDENT: 'CommonBuffId' = 198538 + STYLEBOARD_FIND_MUSE_MOOD_LOW_ENERGIZED: 'CommonBuffId' = 198547 + STYLEBOARD_FIND_MUSE_MOOD_LOW_FLIRTY: 'CommonBuffId' = 198549 + STYLEBOARD_FIND_MUSE_MOOD_LOW_INSPIRED: 'CommonBuffId' = 198550 + STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_ATHLETIC_CONFIDENT: 'CommonBuffId' = 198311 + STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_ATHLETIC_ENERGIZED: 'CommonBuffId' = 198313 + STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_ATHLETIC_FLIRTY: 'CommonBuffId' = 198314 + STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_ATHLETIC_INSPIRED: 'CommonBuffId' = 198312 + STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_CAREER_CONFIDENT: 'CommonBuffId' = 198347 + STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_CAREER_ENERGIZED: 'CommonBuffId' = 198353 + STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_CAREER_FLIRTY: 'CommonBuffId' = 198359 + STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_CAREER_INSPIRED: 'CommonBuffId' = 198365 + STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_EVERYDAY_CONFIDENT: 'CommonBuffId' = 198348 + STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_EVERYDAY_ENERGIZED: 'CommonBuffId' = 198354 + STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_EVERYDAY_FLIRTY: 'CommonBuffId' = 198360 + STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_EVERYDAY_INSPIRED: 'CommonBuffId' = 198366 + STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_FORMAL_CONFIDENT: 'CommonBuffId' = 198352 + STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_FORMAL_ENERGIZED: 'CommonBuffId' = 198355 + STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_FORMAL_FLIRTY: 'CommonBuffId' = 198361 + STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_FORMAL_INSPIRED: 'CommonBuffId' = 198367 + STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_PARTY_CONFIDENT: 'CommonBuffId' = 198351 + STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_PARTY_ENERGIZED: 'CommonBuffId' = 198358 + STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_PARTY_FLIRTY: 'CommonBuffId' = 198364 + STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_PARTY_INSPIRED: 'CommonBuffId' = 198368 + STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_SLEEP_CONFIDENT: 'CommonBuffId' = 198350 + STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_SLEEP_ENERGIZED: 'CommonBuffId' = 198357 + STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_SLEEP_FLIRTY: 'CommonBuffId' = 198363 + STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_SLEEP_INSPIRED: 'CommonBuffId' = 198369 + STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_SWIMWEAR_CONFIDENT: 'CommonBuffId' = 198349 + STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_SWIMWEAR_ENERGIZED: 'CommonBuffId' = 198356 + STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_SWIMWEAR_FLIRTY: 'CommonBuffId' = 198362 + STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_SWIMWEAR_INSPIRED: 'CommonBuffId' = 198370 + STYLEBOARD_INFUSED_OUTFIT_MOOD_CONFIDENT: 'CommonBuffId' = 198489 + STYLEBOARD_INFUSED_OUTFIT_MOOD_ENERGIZED: 'CommonBuffId' = 198492 + STYLEBOARD_INFUSED_OUTFIT_MOOD_FLIRTY: 'CommonBuffId' = 198491 + STYLEBOARD_INFUSED_OUTFIT_MOOD_INSPIRED: 'CommonBuffId' = 198490 + STYLEBOARD_INFUSED_OUTFIT_TRIGGER_ATHLETIC_CONFIDENT: 'CommonBuffId' = 198324 + STYLEBOARD_INFUSED_OUTFIT_TRIGGER_ATHLETIC_ENERGIZED: 'CommonBuffId' = 198321 + STYLEBOARD_INFUSED_OUTFIT_TRIGGER_ATHLETIC_FLIRTY: 'CommonBuffId' = 198322 + STYLEBOARD_INFUSED_OUTFIT_TRIGGER_ATHLETIC_INSPIRED: 'CommonBuffId' = 198323 + STYLEBOARD_INFUSED_OUTFIT_TRIGGER_CAREER_CONFIDENT: 'CommonBuffId' = 198320 + STYLEBOARD_INFUSED_OUTFIT_TRIGGER_CAREER_ENERGIZED: 'CommonBuffId' = 198319 + STYLEBOARD_INFUSED_OUTFIT_TRIGGER_CAREER_FLIRTY: 'CommonBuffId' = 198318 + STYLEBOARD_INFUSED_OUTFIT_TRIGGER_CAREER_INSPIRED: 'CommonBuffId' = 198342 + STYLEBOARD_INFUSED_OUTFIT_TRIGGER_EVERYDAY_CONFIDENT: 'CommonBuffId' = 198341 + STYLEBOARD_INFUSED_OUTFIT_TRIGGER_EVERYDAY_ENERGIZED: 'CommonBuffId' = 198340 + STYLEBOARD_INFUSED_OUTFIT_TRIGGER_EVERYDAY_FLIRTY: 'CommonBuffId' = 198339 + STYLEBOARD_INFUSED_OUTFIT_TRIGGER_EVERYDAY_INSPIRED: 'CommonBuffId' = 198338 + STYLEBOARD_INFUSED_OUTFIT_TRIGGER_FORMAL_CONFIDENT: 'CommonBuffId' = 198337 + STYLEBOARD_INFUSED_OUTFIT_TRIGGER_FORMAL_ENERGIZED: 'CommonBuffId' = 198336 + STYLEBOARD_INFUSED_OUTFIT_TRIGGER_FORMAL_FLIRTY: 'CommonBuffId' = 198335 + STYLEBOARD_INFUSED_OUTFIT_TRIGGER_FORMAL_INSPIRED: 'CommonBuffId' = 198317 + STYLEBOARD_INFUSED_OUTFIT_TRIGGER_PARTY_CONFIDENT: 'CommonBuffId' = 198334 + STYLEBOARD_INFUSED_OUTFIT_TRIGGER_PARTY_ENERGIZED: 'CommonBuffId' = 198333 + STYLEBOARD_INFUSED_OUTFIT_TRIGGER_PARTY_FLIRTY: 'CommonBuffId' = 198332 + STYLEBOARD_INFUSED_OUTFIT_TRIGGER_PARTY_INSPIRED: 'CommonBuffId' = 198331 + STYLEBOARD_INFUSED_OUTFIT_TRIGGER_SLEEP_CONFIDENT: 'CommonBuffId' = 198330 + STYLEBOARD_INFUSED_OUTFIT_TRIGGER_SLEEP_ENERGIZED: 'CommonBuffId' = 198329 + STYLEBOARD_INFUSED_OUTFIT_TRIGGER_SLEEP_FLIRTY: 'CommonBuffId' = 198328 + STYLEBOARD_INFUSED_OUTFIT_TRIGGER_SLEEP_INSPIRED: 'CommonBuffId' = 198327 + STYLEBOARD_INFUSED_OUTFIT_TRIGGER_SWIMWEAR_CONFIDENT: 'CommonBuffId' = 198326 + STYLEBOARD_INFUSED_OUTFIT_TRIGGER_SWIMWEAR_ENERGIZED: 'CommonBuffId' = 198325 + STYLEBOARD_INFUSED_OUTFIT_TRIGGER_SWIMWEAR_FLIRTY: 'CommonBuffId' = 198316 + STYLEBOARD_INFUSED_OUTFIT_TRIGGER_SWIMWEAR_INSPIRED: 'CommonBuffId' = 198315 + SUNLIGHT_REVERSAL_COCKTAIL_HIDDEN: 'CommonBuffId' = 156617 + SUN_TAN_APPLIED_SUN_BLOCK: 'CommonBuffId' = 208856 + SUN_TAN_BURNING: 'CommonBuffId' = 209552 + SUN_TAN_BURNT: 'CommonBuffId' = 208517 + SUN_TAN_CURRENTLY_SUNBATHING: 'CommonBuffId' = 200789 + SUN_TAN_LOCK_DECAY: 'CommonBuffId' = 206066 + SUN_TAN_PRANK: 'CommonBuffId' = 209805 + SUN_TAN_PRANKED_EMBARRASSED: 'CommonBuffId' = 209804 + SUN_TAN_PRANKED_SIM: 'CommonBuffId' = 209768 + SUN_TAN_STARTING_TO_BURN: 'CommonBuffId' = 211808 + SUN_TAN_TANNED: 'CommonBuffId' = 208515 + SUN_TAN_TANNING: 'CommonBuffId' = 209554 + SUN_TAN_VFX: 'CommonBuffId' = 211913 + SUPER_PARENT_ROLE_MODEL_LIFE_SKILL_GAIN: 'CommonBuffId' = 165200 + SUPPRESS_ALL_AUTONOMY: 'CommonBuffId' = 169901 + SUPPRESS_ALL_INTERACTION: 'CommonBuffId' = 24732 + SUPPRESS_BE_AFFECTIONATE_ALL: 'CommonBuffId' = 389298 + SUPPRESS_BE_AFFECTIONATE_AS_ACTOR: 'CommonBuffId' = 389294 + SUPPRESS_BE_AFFECTIONATE_AS_TARGET: 'CommonBuffId' = 389297 + SUPPRESS_EMOTION_IDLE: 'CommonBuffId' = 129126 + SUPPRESS_EMOTION_IDLE_10_MIN: 'CommonBuffId' = 394162 + SUPPRESS_FRONT_PAGE_PIE_MENU: 'CommonBuffId' = 115761 + SUPPRESS_FRONT_PAGE_PIE_MENU: 'CommonBuffId' = 121942 + SUPPRESS_HOUSE_INFECTION: 'CommonBuffId' = 203134 + SUPPRESS_HUNGER_AUTONOMY: 'CommonBuffId' = 354328 + SUPPRESS_IN_LABOR: 'CommonBuffId' = 256302 + SUPPRESS_LOVE_LETTER: 'CommonBuffId' = 100870 + SUPPRESS_REACTION_SMELLS_BAD: 'CommonBuffId' = 99740 + SUPPRESS_ROMANTIC_SOCIALS_ACTOR: 'CommonBuffId' = 383351 + SUPPRESS_ROMANTIC_SOCIALS_TARGET: 'CommonBuffId' = 383749 + SUPPRESS_SIM_CHAT_ALL: 'CommonBuffId' = 394424 + SUPPRESS_SIM_CHAT_AS_ACTOR: 'CommonBuffId' = 394422 + SUPPRESS_SIM_CHAT_AS_TARGET: 'CommonBuffId' = 394423 + SUPPRESS_SNOW_IDLE: 'CommonBuffId' = 190542 + SUPPRESS_SOCIALS_TARGETED_ACTOR: 'CommonBuffId' = 384533 + SUPPRESS_SOCIALS_TARGETED_TARGET: 'CommonBuffId' = 384534 + SUPPRESS_SOCIAL_PICKER_SI_ALL: 'CommonBuffId' = 388560 + SUPPRESS_SOCIAL_PICKER_SI_AS_ACTOR: 'CommonBuffId' = 388562 + SUPPRESS_SOCIAL_PICKER_SI_AS_TARGET: 'CommonBuffId' = 388564 + SUPPRESS_TEMPERATURE_IDLE: 'CommonBuffId' = 188623 + SUPPRESS_TRAIT_IDLE: 'CommonBuffId' = 334350 + SUPPRESS_VISIBLE_MOTIVES: 'CommonBuffId' = 27833 + SUPPRESS_VISIBLE_MOTIVES_EXCLUDE_ENERGY: 'CommonBuffId' = 243486 + SURPRISE_HOLIDAY_BATTLE_ROYALE_AUTONOMY: 'CommonBuffId' = 182289 + SURPRISE_HOLIDAY_DISCOUNT_DAY: 'CommonBuffId' = 182267 + SURPRISE_HOLIDAY_LOTTERY_AUTONOMY: 'CommonBuffId' = 184906 + SURPRISE_HOLIDAY_LOTTERY_COOLDOWN: 'CommonBuffId' = 181580 + SURPRISE_HOLIDAY_LOTTERY_INSPIRED: 'CommonBuffId' = 181582 + SURPRISE_HOLIDAY_LOTTERY_SAD_BUFF: 'CommonBuffId' = 181900 + SURPRISE_HOLIDAY_LOTTERY_WIN_BUFF: 'CommonBuffId' = 181905 + SURPRISE_HOLIDAY_NIGHT_ON_THE_TOWN: 'CommonBuffId' = 182263 + SURPRISE_HOLIDAY_PIRATE_DAY_AUTONOMY: 'CommonBuffId' = 182293 + SURPRISE_HOLIDAY_PRANK_DAY_AUTONOMY: 'CommonBuffId' = 182296 + SURPRISE_HOLIDAY_SKILL_DAY_CONFIDENT: 'CommonBuffId' = 186641 + SURPRISE_HOLIDAY_SKILL_DAY_INCREASE_SKILL_GAIN: 'CommonBuffId' = 182300 + SURPRISE_HOLIDAY_TV_PREMIERE: 'CommonBuffId' = 182304 + SURPRISE_HOLIDAY_TV_PREMIERE_HAPPY_BUFF: 'CommonBuffId' = 183430 + SURPRISE_HOLIDAY_TV_PREMIERE_SPOILED: 'CommonBuffId' = 183488 + SURPRISE_HOLIDAY_TV_PREMIERE_WATCHED_HIDDEN: 'CommonBuffId' = 183431 + SWEAR_COOLDOWN: 'CommonBuffId' = 167444 + TALES_OF_THE_DEAD: 'CommonBuffId' = 103142 + TALES_OF_THE_DEAD_GREAT_STORYTELLER: 'CommonBuffId' = 109749 + TANDEM_SLEDDER_SITUATION_LEADER: 'CommonBuffId' = 251682 + TEACH_TO_SAY_PLEASE_ANGRY_TODDLER: 'CommonBuffId' = 161225 + TEACH_TO_SAY_PLEASE_BORED_CHILD: 'CommonBuffId' = 161226 + TEACH_TO_SAY_PLEASE_CONFIDENT_CHILD: 'CommonBuffId' = 161223 + TEACH_TO_SAY_PLEASE_HAPPY_TODDLER: 'CommonBuffId' = 161222 + TEACH_TO_SAY_PLEASE_INSPIRED_CHILD: 'CommonBuffId' = 161224 + TEACH_TO_SAY_SORRY_CHILD_BORED: 'CommonBuffId' = 166782 + TEACH_TO_SAY_SORRY_CHILD_CONFIDENT: 'CommonBuffId' = 166784 + TEACH_TO_SAY_SORRY_CHILD_INSPIRED: 'CommonBuffId' = 166783 + TEACH_TO_SAY_SORRY_TODDLER_ANGRY: 'CommonBuffId' = 166780 + TEACH_TO_SAY_SORRY_TODDLER_HAPPY: 'CommonBuffId' = 166781 + TEA_SET_PRIM_AND_PROPER: 'CommonBuffId' = 278935 + TEA_SET_TRADITIONAL_TEA: 'CommonBuffId' = 278934 + TEA_UPGRADED: 'CommonBuffId' = 28947 + TEEN_ASPIRATIONS_SOCIAL_FOLLOWERS: 'CommonBuffId' = 287404 + TEEN_MOOD_SWING_ANGRY: 'CommonBuffId' = 162334 + TEEN_MOOD_SWING_EMBARRASSED: 'CommonBuffId' = 162337 + TEEN_MOOD_SWING_LOUD_MUSIC_REACTION: 'CommonBuffId' = 163399 + TEEN_MOOD_SWING_PUSH_MOOD_SWING_COOLDOWN: 'CommonBuffId' = 162346 + TEEN_MOOD_SWING_SAD: 'CommonBuffId' = 162336 + TEEN_MOOD_SWING_STRESSED: 'CommonBuffId' = 162335 + TEEN_RELATIONSHIP_DRAMA_CRUSH_ANGRY: 'CommonBuffId' = 289490 + TEEN_RELATIONSHIP_DRAMA_CRUSH_BROADCASTER_INVISIBLE: 'CommonBuffId' = 289554 + TEEN_RELATIONSHIP_DRAMA_CRUSH_IN_ROOM: 'CommonBuffId' = 289483 + TEEN_RELATIONSHIP_DRAMA_CRUSH_NEGATIVE_CHAT: 'CommonBuffId' = 289485 + TEEN_RELATIONSHIP_DRAMA_CRUSH_POSITIVE_CHAT: 'CommonBuffId' = 289484 + TEEN_RELATIONSHIP_DRAMA_CRUSH_REJECTED: 'CommonBuffId' = 289482 + TEEN_RELATIONSHIP_DRAMA_CRUSH_SWOONING: 'CommonBuffId' = 289487 + TEEN_RELATIONSHIP_DRAMA_CRUSH_TENSE_CHAT: 'CommonBuffId' = 289486 + TEEN_RELATIONSHIP_DRAMA_CRUSH_TEXTING: 'CommonBuffId' = 289481 + TEEN_RELATIONSHIP_DRAMA_REJECTED_FRIEND: 'CommonBuffId' = 297948 + TEMPERAMENT_ANTI_CAPITALIST_CANINE_WORK_IS_THE_POOP: 'CommonBuffId' = 290871 + TEMPERAMENT_BIG_BAD_WOLF_OVERWHELMING_AGGRESSION: 'CommonBuffId' = 290507 + TEMPERAMENT_CARNIVORE_NEED_REAL_MEAT: 'CommonBuffId' = 293836 + TEMPERAMENT_COOLDOWN_GOTTA_MARK_SOMETHING: 'CommonBuffId' = 297153 + TEMPERAMENT_COOLDOWN_NEED_HIBERNATE: 'CommonBuffId' = 297097 + TEMPERAMENT_COOLDOWN_NEED_LOVE: 'CommonBuffId' = 297098 + TEMPERAMENT_COOLDOWN_OVERWHELMING_AGGRESSION: 'CommonBuffId' = 297096 + TEMPERAMENT_COOLDOWN_SUDDEN_CRAVING: 'CommonBuffId' = 297094 + TEMPERAMENT_COOLDOWN_WALLS_CLOSING_IN: 'CommonBuffId' = 297095 + TEMPERAMENT_EASILY_EXCITABLE_SCREEN_TIME: 'CommonBuffId' = 293838 + TEMPERAMENT_FEELS_OUTCASTED_BOTTOM_OF_THE_PACK: 'CommonBuffId' = 294002 + TEMPERAMENT_FEELS_OUTCASTED_NOBODY_UNDERSTANDSME: 'CommonBuffId' = 294001 + TEMPERAMENT_FRISKY_NEED_LOVE: 'CommonBuffId' = 295326 + TEMPERAMENT_HIDDEN_ANTI_CAPITALIST_CANINE: 'CommonBuffId' = 290555 + TEMPERAMENT_HIDDEN_BIG_BAD_WOLF: 'CommonBuffId' = 290107 + TEMPERAMENT_HIDDEN_BOTTOM_OF_THE_PACK_COOLDOWN: 'CommonBuffId' = 298500 + TEMPERAMENT_HIDDEN_CARNIVORE: 'CommonBuffId' = 293834 + TEMPERAMENT_HIDDEN_EASY_EXCITABLE: 'CommonBuffId' = 293840 + TEMPERAMENT_HIDDEN_FEELS_OUTCASTED: 'CommonBuffId' = 294000 + TEMPERAMENT_HIDDEN_FEELS_OUTCASTED_TRAIT: 'CommonBuffId' = 294003 + TEMPERAMENT_HIDDEN_FRISKY: 'CommonBuffId' = 295380 + TEMPERAMENT_HIDDEN_GRUMPY_WOLF: 'CommonBuffId' = 290108 + TEMPERAMENT_HIDDEN_HUNGRY_LIKE_WOLF: 'CommonBuffId' = 294057 + TEMPERAMENT_HIDDEN_LUNAR_FOREST: 'CommonBuffId' = 294324 + TEMPERAMENT_HIDDEN_LUNAR_HUNT: 'CommonBuffId' = 294325 + TEMPERAMENT_HIDDEN_LUNAR_NIGHT: 'CommonBuffId' = 294323 + TEMPERAMENT_HIDDEN_LUNAR_WOLF: 'CommonBuffId' = 294322 + TEMPERAMENT_HIDDEN_PRIDEFUL: 'CommonBuffId' = 290003 + TEMPERAMENT_HIDDEN_RESTLESS_ANIMAL: 'CommonBuffId' = 290111 + TEMPERAMENT_HIDDEN_RESTLESS_ANIMAL_REMOVE: 'CommonBuffId' = 294127 + TEMPERAMENT_HIDDEN_SENSITIVE_HEARING: 'CommonBuffId' = 294511 + TEMPERAMENT_HIDDEN_SENSITIVE_HEARING_COOLDOWN: 'CommonBuffId' = 299674 + TEMPERAMENT_HIDDEN_SURVIVAL_INSTINCTS: 'CommonBuffId' = 290110 + TEMPERAMENT_HIDDEN_WRACKED_WITH_GUILT: 'CommonBuffId' = 290109 + TEMPERAMENT_IM_SO_CLEAN: 'CommonBuffId' = 293999 + TEMPERAMENT_LUNAR_TEMPERAMENT_GAIN: 'CommonBuffId' = 299766 + TEMPERAMENT_MUST_BE_CLEAN: 'CommonBuffId' = 293996 + TEMPERAMENT_NEED_HIBERNATE: 'CommonBuffId' = 294124 + TEMPERAMENT_NIGHT_WOLF_DAY_TIME: 'CommonBuffId' = 294327 + TEMPERAMENT_NIGHT_WOLF_DAY_TIME_WHILE_SLEEPING: 'CommonBuffId' = 294329 + TEMPERAMENT_PRIDEFUL_NARCISSIST: 'CommonBuffId' = 295383 + TEMPERAMENT_PRIDEFUL_WOUNDED_PRIDE: 'CommonBuffId' = 295382 + TEMPERAMENT_RESTLESS_ANIMAL_WALLS_CLOSING_IN: 'CommonBuffId' = 290448 + TEMPERAMENT_SENSITIVE_HEARING_LOUD_NOISES: 'CommonBuffId' = 294513 + TEMPERAMENT_SUDDEN_CRAVING: 'CommonBuffId' = 294061 + TEMPERAMENT_SURVIVAL_INSTINCTS_FIGHT_OR_FLIGHT: 'CommonBuffId' = 290510 + TEMPERAMENT_TERRITORIAL_GOTTA_MARK_NOW: 'CommonBuffId' = 297152 + TEMPERAMENT_TERRITORIAL_GOTTA_MARK_SOMETHING: 'CommonBuffId' = 293884 + TEMPERAMENT_TERRITORY_MARKED: 'CommonBuffId' = 293998 + TEMPERAMENT_WET_AND_HATE_IT: 'CommonBuffId' = 294129 + TEMPERAMENT_WET_AND_HATE_IT_WHILE_WET: 'CommonBuffId' = 294342 + TEMPERAMENT_WOLF_BRAIN_HEAD_HURT: 'CommonBuffId' = 294326 + TEMPERAMENT_WRACKED_WITH_GUILT_TRANSFORMATION: 'CommonBuffId' = 290508 + TEMPERAMENT_WRACKED_WITH_GUILT_WHAT_HAVE_I_BECOME: 'CommonBuffId' = 290509 + TEMPERATURE_CHILLED: 'CommonBuffId' = 180207 + TEMPERATURE_DISCOURAGE_OUTSIDE_INTERACTIONS_HIDDEN: 'CommonBuffId' = 186065 + TEMPERATURE_FORCE_COMFORTABLE: 'CommonBuffId' = 182899 + TEMPERATURE_FREEZING: 'CommonBuffId' = 180208 + TEMPERATURE_FREEZING_EXTREME: 'CommonBuffId' = 182205 + TEMPERATURE_GHOST_FREEZE: 'CommonBuffId' = 182891 + TEMPERATURE_GHOST_GHOST_CHILLED_HAPPY: 'CommonBuffId' = 184144 + TEMPERATURE_GHOST_GHOST_CHILLED_UNCOMFORTABLE: 'CommonBuffId' = 184145 + TEMPERATURE_GHOST_PLASMA_WARMED_HAPPY: 'CommonBuffId' = 184146 + TEMPERATURE_GHOST_PLASMA_WARMED_UNCOMFORTABLE: 'CommonBuffId' = 184147 + TEMPERATURE_HIDDEN_CHILLED: 'CommonBuffId' = 185937 + TEMPERATURE_HIDDEN_EXTREME_FREEZING: 'CommonBuffId' = 186001 + TEMPERATURE_HIDDEN_EXTREME_MELTING: 'CommonBuffId' = 186004 + TEMPERATURE_HIDDEN_FREEZING: 'CommonBuffId' = 186000 + TEMPERATURE_HIDDEN_MELTING: 'CommonBuffId' = 186003 + TEMPERATURE_HIDDEN_NEUTRAL: 'CommonBuffId' = 190849 + TEMPERATURE_HIDDEN_OVERHEATING: 'CommonBuffId' = 186002 + TEMPERATURE_HIDDEN_TROPICAL_WARMTH: 'CommonBuffId' = 211084 + TEMPERATURE_IMMUNE_TO_TEMPERATURE: 'CommonBuffId' = 185065 + TEMPERATURE_INFANT_COLD: 'CommonBuffId' = 314015 + TEMPERATURE_INFANT_HOT: 'CommonBuffId' = 314016 + TEMPERATURE_MELTING: 'CommonBuffId' = 180206 + TEMPERATURE_MELTING_EXTREME: 'CommonBuffId' = 182207 + TEMPERATURE_OVERHEATING: 'CommonBuffId' = 180205 + TEMPERATURE_POOL_COLD: 'CommonBuffId' = 185467 + TEMPERATURE_POOL_FREEZING: 'CommonBuffId' = 185468 + TEMPERATURE_POOL_WARM: 'CommonBuffId' = 185469 + TEMPERATURE_POSITIVE_BURNING_MAN_BURNING: 'CommonBuffId' = 183574 + TEMPERATURE_POSITIVE_BURNING_MAN_HOT: 'CommonBuffId' = 183573 + TEMPERATURE_POSITIVE_ICE_MAN_COLD: 'CommonBuffId' = 183575 + TEMPERATURE_POSITIVE_ICE_MAN_FREEZING: 'CommonBuffId' = 183576 + TEMPERATURE_SIM_RAY_CHILLED: 'CommonBuffId' = 185173 + TEMPERATURE_SIM_RAY_FROZEN: 'CommonBuffId' = 185165 + TEMPERATURE_SUPPRESS_TEMPERATURE_OUTFIT_SWAP: 'CommonBuffId' = 184255 + TEMPERATURE_TODDLER_COLD: 'CommonBuffId' = 186083 + TEMPERATURE_TODDLER_HOT: 'CommonBuffId' = 186084 + TEMPERATURE_TRAIT_BURNING_MAN: 'CommonBuffId' = 183570 + TEMPERATURE_TRAIT_ICE_MAN: 'CommonBuffId' = 183571 + TEMPERATURE_VFX_COLD_BREATH_C: 'CommonBuffId' = 184196 + TEMPERATURE_VFX_COLD_BREATH_HORSE: 'CommonBuffId' = 335306 + TEMPERATURE_VFX_COLD_BREATH_I: 'CommonBuffId' = 334461 + TEMPERATURE_VFX_COLD_BREATH_P: 'CommonBuffId' = 184197 + TEMPERATURE_VFX_COLD_BREATH_TYAE: 'CommonBuffId' = 184195 + TEMPERATURE_VFX_COLD_BREATH_V: 'CommonBuffId' = 190826 + TEMPERATURE_WARM_WATER: 'CommonBuffId' = 209183 + TEMPLE_ARCHAEOLOGY_SKILL_GAIN: 'CommonBuffId' = 179377 + TEMPLE_GATE_TRY_TO_PASS_WITH_RELIC_GLOW: 'CommonBuffId' = 179553 + TEMPLE_HAPPY: 'CommonBuffId' = 345990 + TEMPLE_LOOK_AROUND_COOLDOWN: 'CommonBuffId' = 183238 + TEMPLE_PLANTS: 'CommonBuffId' = 179107 + TEMPLE_TRAP_ACTIVATE_SUCCESS: 'CommonBuffId' = 179533 + TEMPLE_TRAP_PUNISHMENT_BLADDER_SCARE: 'CommonBuffId' = 174448 + TEMPLE_TRAP_PUNISHMENT_BLADDER_SCARE_VAMPIRE: 'CommonBuffId' = 174452 + TEMPLE_TRAP_PUNISHMENT_BONE_DUST_HIDDEN: 'CommonBuffId' = 178285 + TEMPLE_TRAP_PUNISHMENT_FIRE_HIDDEN: 'CommonBuffId' = 178286 + TEMPLE_TRAP_PUNISHMENT_MISERABLE_VACATION: 'CommonBuffId' = 174451 + TEMPLE_TRAP_PUNISHMENT_NOTHING_BAD: 'CommonBuffId' = 174447 + TEMPLE_TRAP_PUNISHMENT_RESTLESS_HORROR: 'CommonBuffId' = 174449 + TEMPLE_TRAP_PUNISHMENT_SO_ALONE: 'CommonBuffId' = 174450 + TEMPORARY_CLONE_LEAVE: 'CommonBuffId' = 215169 + TEMPORARY_STAY_AWKWARD_TENSION: 'CommonBuffId' = 307449 + TEMPORARY_STAY_COOL_LINEAGE: 'CommonBuffId' = 307218 + TEMPORARY_STAY_DISASTER: 'CommonBuffId' = 319896 + TEMPORARY_STAY_DOPPEL_GANGER: 'CommonBuffId' = 312758 + TEMPORARY_STAY_EAT_CANDY: 'CommonBuffId' = 316262 + TEMPORARY_STAY_FAMILY_BONDS: 'CommonBuffId' = 307217 + TEMPORARY_STAY_FAMILY_FOREVER: 'CommonBuffId' = 307219 + TEMPORARY_STAY_GET_THEM_OUT: 'CommonBuffId' = 308306 + TEMPORARY_STAY_GLOOMY: 'CommonBuffId' = 310694 + TEMPORARY_STAY_GLOOMY_PRESENCE: 'CommonBuffId' = 310696 + TEMPORARY_STAY_GOOD_COMPANY: 'CommonBuffId' = 307448 + TEMPORARY_STAY_GOOD_FRIENDS: 'CommonBuffId' = 312759 + TEMPORARY_STAY_GRANDPARENT_LOVE: 'CommonBuffId' = 307224 + TEMPORARY_STAY_GRIEVING: 'CommonBuffId' = 312760 + TEMPORARY_STAY_HIDDEN_FAMILY_REUNION: 'CommonBuffId' = 307725 + TEMPORARY_STAY_HIDDEN_GOODBYE: 'CommonBuffId' = 310008 + TEMPORARY_STAY_HIDDEN_GUEST: 'CommonBuffId' = 303300 + TEMPORARY_STAY_HIDDEN_GUEST_HELP: 'CommonBuffId' = 308110 + TEMPORARY_STAY_HIDDEN_GUEST_SPECIAL_CLONE: 'CommonBuffId' = 312751 + TEMPORARY_STAY_HIDDEN_GUEST_SPECIAL_COUCH_SURFER: 'CommonBuffId' = 312750 + TEMPORARY_STAY_HIDDEN_GUEST_SPECIAL_COUCH_SURFER_KYLE: 'CommonBuffId' = 330800 + TEMPORARY_STAY_HIDDEN_GUEST_SPECIAL_DISASTER: 'CommonBuffId' = 312747 + TEMPORARY_STAY_HIDDEN_GUEST_SPECIAL_FRIEND: 'CommonBuffId' = 312752 + TEMPORARY_STAY_HIDDEN_GUEST_SPECIAL_HOUSEHOLD_LOSS: 'CommonBuffId' = 312753 + TEMPORARY_STAY_HIDDEN_GUEST_SPECIAL_INFANT_INTRO: 'CommonBuffId' = 324276 + TEMPORARY_STAY_HIDDEN_GUEST_SPECIAL_MOPEY: 'CommonBuffId' = 312430 + TEMPORARY_STAY_HIDDEN_GUEST_SPECIAL_PARENTAL_HELP: 'CommonBuffId' = 322376 + TEMPORARY_STAY_HIDDEN_HELP_BOOST: 'CommonBuffId' = 307215 + TEMPORARY_STAY_HIDDEN_INFANT_INTRO_START: 'CommonBuffId' = 324422 + TEMPORARY_STAY_HIDDEN_PARENTAL_BOOST: 'CommonBuffId' = 322377 + TEMPORARY_STAY_HIDDEN_PARENTAL_BOOST_COOLDOWN: 'CommonBuffId' = 323302 + TEMPORARY_STAY_HIDDEN_PARENTAL_HELP_SCHEDULE: 'CommonBuffId' = 327281 + TEMPORARY_STAY_HIDDEN_SPECIAL_BEHAVIOR_COOLDOWN: 'CommonBuffId' = 311524 + TEMPORARY_STAY_HIDDEN_SPECIAL_BEHAVIOR_COOLDOWN_CANDY: 'CommonBuffId' = 330801 + TEMPORARY_STAY_HIDDEN_SPECIAL_BEHAVIOR_COOLDOWN_KYLE: 'CommonBuffId' = 328182 + TEMPORARY_STAY_HIDDEN_STOP_HELPING: 'CommonBuffId' = 307216 + TEMPORARY_STAY_HIDDEN_SUMMON: 'CommonBuffId' = 323020 + TEMPORARY_STAY_HIDDEN_SUMMON_SNACKS_COOLDOWN: 'CommonBuffId' = 311088 + TEMPORARY_STAY_HIDDEN_WELCOME_ME: 'CommonBuffId' = 310003 + TEMPORARY_STAY_HIDDEN_WELCOME_ME_COOLDOWN: 'CommonBuffId' = 312770 + TEMPORARY_STAY_MEANING_OF_FAMILY: 'CommonBuffId' = 307220 + TEMPORARY_STAY_MEANING_OF_FAMILY_TODDLER: 'CommonBuffId' = 307222 + TEMPORARY_STAY_NICE_SEEING_FAMILY: 'CommonBuffId' = 307453 + TEMPORARY_STAY_NICE_SEEING_FRIENDS: 'CommonBuffId' = 307452 + TEMPORARY_STAY_NICE_SEEING_GRANDPARENTS: 'CommonBuffId' = 307451 + TEMPORARY_STAY_NICE_SEEING_PARENTS: 'CommonBuffId' = 307450 + TEMPORARY_STAY_POWER_SIP_LLAMA_BERRY: 'CommonBuffId' = 310415 + TEMPORARY_STAY_WHOSE_KID_IS_THIS: 'CommonBuffId' = 310698 + TEMP_RANDOM_CALC_01: 'CommonBuffId' = 144975 + TEMP_RANDOM_CALC_02: 'CommonBuffId' = 144976 + TENSE_GHOSTLY_YOWL_CAT: 'CommonBuffId' = 174603 + TENSE_GHOSTLY_YOWL_DOG: 'CommonBuffId' = 174604 + TENSION_RELIEF_SCENT: 'CommonBuffId' = 118498 + THERMOSTAT_COOLER_HAPPY: 'CommonBuffId' = 188978 + THERMOSTAT_COOLER_UNCOMFORTABLE: 'CommonBuffId' = 188980 + THERMOSTAT_HIDDEN_GLOBAL_HIGH: 'CommonBuffId' = 190651 + THERMOSTAT_HIDDEN_GLOBAL_LOW: 'CommonBuffId' = 190656 + THERMOSTAT_HIDDEN_GLOBAL_MEDIUM: 'CommonBuffId' = 190657 + THERMOSTAT_HIDDEN_TEMPERATURE_CHANGE_COOLER: 'CommonBuffId' = 190675 + THERMOSTAT_HIDDEN_TEMPERATURE_CHANGE_WARMER: 'CommonBuffId' = 190671 + THERMOSTAT_ROUTE_REACT_COOLDOWN: 'CommonBuffId' = 189619 + THERMOSTAT_WARMER_HAPPY: 'CommonBuffId' = 188979 + THERMOSTAT_WARMER_UNCOMFORTABLE: 'CommonBuffId' = 188981 + THREATENED_CRIMINAL: 'CommonBuffId' = 36592 + THREATENED_VICTIM: 'CommonBuffId' = 36593 + THRIFT_STORE_BUBBLE_BUNCH: 'CommonBuffId' = 282903 + THRIFT_STORE_BUBBLICIOUS_BEVERAGE: 'CommonBuffId' = 282910 + THRIFT_STORE_COMEDY_CALLING: 'CommonBuffId' = 282907 + THRIFT_STORE_EVENT_PERFORMED: 'CommonBuffId' = 280933 + THRIFT_STORE_FOBBED_OFF_FASHION: 'CommonBuffId' = 281215 + THRIFT_STORE_LIVE_POETS_SOCIETY: 'CommonBuffId' = 282909 + THRIFT_STORE_PERFORMANCE_FINISHED: 'CommonBuffId' = 300571 + THRIFT_STORE_STYLE_SESSION: 'CommonBuffId' = 282905 + THRIFT_STORE_TREND_TIP_BASICS: 'CommonBuffId' = 281224 + THRIFT_STORE_TREND_TIP_BOHO: 'CommonBuffId' = 281221 + THRIFT_STORE_TREND_TIP_COUNTRY: 'CommonBuffId' = 281217 + THRIFT_STORE_TREND_TIP_HIPSTER: 'CommonBuffId' = 281220 + THRIFT_STORE_TREND_TIP_NONE: 'CommonBuffId' = 281226 + THRIFT_STORE_TREND_TIP_OUTDOORSY: 'CommonBuffId' = 281223 + THRIFT_STORE_TREND_TIP_POLISHED: 'CommonBuffId' = 281227 + THRIFT_STORE_TREND_TIP_PREPPY: 'CommonBuffId' = 281219 + THRIFT_STORE_TREND_TIP_ROCKER: 'CommonBuffId' = 281225 + THRIFT_STORE_TREND_TIP_STREETWEAR: 'CommonBuffId' = 281222 + THROW_FOOTBALL_HEADING_FOR_THE_BIG_LEAGUES: 'CommonBuffId' = 283024 + THROW_FOOTBALL_HIDDEN_BALL_REGULAR: 'CommonBuffId' = 285958 + THROW_FOOTBALL_HIDDEN_BALL_REWARD: 'CommonBuffId' = 285959 + THROW_FOOTBALL_PRACTICE_MAKES_PAINFUL: 'CommonBuffId' = 283023 + THROW_FOOTBALL_SMELL_THE_GLORY: 'CommonBuffId' = 283025 + TODDLERS_AT_DAYCARE: 'CommonBuffId' = 157127 + TODDLERS_BIRTHDAY_CELEBRATION: 'CommonBuffId' = 157688 + TODDLERS_BITE: 'CommonBuffId' = 162589 + TODDLERS_BITE_CHILD: 'CommonBuffId' = 164670 + TODDLERS_BITE_TODDLER: 'CommonBuffId' = 164669 + TODDLERS_CAREGIVER_AWAKE: 'CommonBuffId' = 157452 + TODDLERS_CTYAE_CRYING_TODDLER: 'CommonBuffId' = 140754 + TODDLERS_CTYAE_ENOUGH_ALREADY: 'CommonBuffId' = 156740 + TODDLERS_CTYAE_GROWING_UP: 'CommonBuffId' = 156743 + TODDLERS_CTYAE_HIDDEN_PLAYING_DOLLS_WITH_TODDLER: 'CommonBuffId' = 156460 + TODDLERS_CTYAE_HIDDEN_WATCHING_TV_WITH_TODDLER: 'CommonBuffId' = 156459 + TODDLERS_CTYAE_STINKY_DIAPER: 'CommonBuffId' = 140767 + TODDLERS_CTYAE_TANTRUM_THROWING_TODDLER: 'CommonBuffId' = 151193 + TODDLERS_CTYAE_THAT_WAS_CUTE: 'CommonBuffId' = 156985 + TODDLERS_CTYAE_TODDLER_BIRTHDAY: 'CommonBuffId' = 156742 + TODDLERS_CTYAE_TODDLER_SAID_WHAT: 'CommonBuffId' = 156228 + TODDLERS_CTYAE_UGH_TODDLERS: 'CommonBuffId' = 156741 + TODDLERS_CTYAE_WATCH_TODDLER_TOY_SHOW: 'CommonBuffId' = 155714 + TODDLERS_DANCE_SHAKING_TAIL: 'CommonBuffId' = 147370 + TODDLERS_DEFIANCE_ACTOR_DISOBEDIENT_TODDLER: 'CommonBuffId' = 141558 + TODDLERS_DEFIANCE_ACTOR_UNCOOPERATIVE_TODDLER: 'CommonBuffId' = 141545 + TODDLERS_DEFIANCE_DONT_GIVE_ME_ORDERS: 'CommonBuffId' = 156771 + TODDLERS_DEFIANCE_DONT_WANT_TO: 'CommonBuffId' = 141541 + TODDLERS_DEFIANCE_DONT_WANT_TO_VISIBLE: 'CommonBuffId' = 156774 + TODDLERS_DEFIANCE_MEANIE: 'CommonBuffId' = 141565 + TODDLERS_DEFIANCE_SILLY_ADULTS: 'CommonBuffId' = 154240 + TODDLERS_DEFIANCE_TOO_HYPER: 'CommonBuffId' = 156769 + TODDLERS_GETTING_SO_BIG_UNCOMFORTABLE: 'CommonBuffId' = 145986 + TODDLERS_GROWING_SO_FAST_HAPPY: 'CommonBuffId' = 150540 + TODDLERS_HIDDEN_CAREGIVER_RECENTLY_RETURNED_FROM_WORK: 'CommonBuffId' = 154998 + TODDLERS_HIDDEN_CAREGIVER_SLEEP_DO_NOT_DISTURB: 'CommonBuffId' = 157458 + TODDLERS_HIDDEN_CAUGHT_BAD_BEHAVIOR: 'CommonBuffId' = 156593 + TODDLERS_HIDDEN_GREET_RETURNING_CAREGIVER: 'CommonBuffId' = 154980 + TODDLERS_HIDDEN_HAS_BEEN_COMFORTED: 'CommonBuffId' = 157007 + TODDLERS_HIDDEN_HAS_BEEN_WATCHED: 'CommonBuffId' = 151818 + TODDLERS_HIDDEN_HAS_NOT_BEEN_WATCHED: 'CommonBuffId' = 151819 + TODDLERS_HIDDEN_RECENTLY_SNUGGLED: 'CommonBuffId' = 156944 + TODDLERS_HIDDEN_SKILL_COMMUNICATION_LEVELS_1: 'CommonBuffId' = 154473 + TODDLERS_HIDDEN_SKILL_COMMUNICATION_LEVELS_2: 'CommonBuffId' = 154474 + TODDLERS_HIDDEN_SKILL_COMMUNICATION_LEVELS_3: 'CommonBuffId' = 154475 + TODDLERS_HIDDEN_SKILL_COMMUNICATION_LEVELS_4: 'CommonBuffId' = 154476 + TODDLERS_HIDDEN_SKILL_COMMUNICATION_LEVELS_5: 'CommonBuffId' = 154472 + TODDLERS_HIDDEN_SKILL_IMAGINATION_LEVELS_1: 'CommonBuffId' = 154478 + TODDLERS_HIDDEN_SKILL_IMAGINATION_LEVELS_2: 'CommonBuffId' = 154479 + TODDLERS_HIDDEN_SKILL_IMAGINATION_LEVELS_3: 'CommonBuffId' = 154480 + TODDLERS_HIDDEN_SKILL_IMAGINATION_LEVELS_4: 'CommonBuffId' = 154481 + TODDLERS_HIDDEN_SKILL_IMAGINATION_LEVELS_5: 'CommonBuffId' = 154477 + TODDLERS_HIDDEN_SKILL_MOVEMENT_LEVELS_1: 'CommonBuffId' = 147041 + TODDLERS_HIDDEN_SKILL_MOVEMENT_LEVELS_2: 'CommonBuffId' = 147033 + TODDLERS_HIDDEN_SKILL_MOVEMENT_LEVELS_3: 'CommonBuffId' = 154487 + TODDLERS_HIDDEN_SKILL_MOVEMENT_LEVELS_4: 'CommonBuffId' = 147035 + TODDLERS_HIDDEN_SKILL_MOVEMENT_LEVELS_5: 'CommonBuffId' = 154488 + TODDLERS_HIDDEN_SKILL_POTTY_LEVELS_1: 'CommonBuffId' = 154490 + TODDLERS_HIDDEN_SKILL_POTTY_LEVELS_2: 'CommonBuffId' = 154491 + TODDLERS_HIDDEN_SKILL_POTTY_LEVELS_3: 'CommonBuffId' = 154492 + TODDLERS_HIDDEN_SKILL_THINKING_LEVELS_1: 'CommonBuffId' = 154483 + TODDLERS_HIDDEN_SKILL_THINKING_LEVELS_2: 'CommonBuffId' = 154484 + TODDLERS_HIDDEN_SKILL_THINKING_LEVELS_3: 'CommonBuffId' = 154485 + TODDLERS_HIDDEN_SKILL_THINKING_LEVELS_4: 'CommonBuffId' = 154486 + TODDLERS_HIDDEN_SKILL_THINKING_LEVELS_5: 'CommonBuffId' = 154482 + TODDLERS_HIDDEN_STEREO_LISTENED_TO_LULLABIES: 'CommonBuffId' = 155940 + TODDLERS_HIDDEN_WAIT_TIMER: 'CommonBuffId' = 156791 + TODDLERS_HUG_LOVED: 'CommonBuffId' = 156981 + TODDLERS_LEFT_BEHIND: 'CommonBuffId' = 156744 + TODDLERS_LEFT_BEHIND_IN_HIGH_CHAIR: 'CommonBuffId' = 157129 + TODDLERS_LYING_DOWN_ABOUT_TO_SLEEP: 'CommonBuffId' = 157574 + TODDLERS_NAP_NOT_ENOUGH_NAP: 'CommonBuffId' = 156534 + TODDLERS_READ_TO_LOVED: 'CommonBuffId' = 156982 + TODDLERS_SNUGGLE_LOVED: 'CommonBuffId' = 156943 + TODDLERS_STRANGER_DANGER: 'CommonBuffId' = 154495 + TODDLERS_STRANGER_DANGER_CLINGY: 'CommonBuffId' = 154551 + TODDLERS_TEACH_TO_TALK_FRUSTRATED_WITH_WORDS: 'CommonBuffId' = 155780 + TODDLERS_TEACH_TO_TALK_LEARNED_WORDS: 'CommonBuffId' = 155779 + TODDLERS_TEACH_TO_TALK_P_HAS_RESPONDED: 'CommonBuffId' = 155761 + TODDLERS_TEACH_TO_TALK_TIRED_OF_WORDS: 'CommonBuffId' = 155781 + TODDLERS_TEACH_TO_TALK_TYAE_HAS_TAUGHT: 'CommonBuffId' = 155760 + TODDLERS_TODDLER_AWAKE: 'CommonBuffId' = 154183 + TODDLERS_TODDLER_CANT_TALK: 'CommonBuffId' = 156227 + TODDLERS_WAS_CAREGIVER: 'CommonBuffId' = 157470 + TODDLERS_WATCH_TODDLERS_DISTRESS_COOLDOWN: 'CommonBuffId' = 157524 + TODDLER_AUTONOMY_MOD_IN_HIGH_CHAIR: 'CommonBuffId' = 144745 + TODDLER_BED_AFTER_NIGHTMARE: 'CommonBuffId' = 157677 + TODDLER_BED_HAS_BEEN_READ_TO_SLEEP: 'CommonBuffId' = 150369 + TODDLER_BED_HAS_BEEN_TUCKED_IN: 'CommonBuffId' = 150406 + TODDLER_BED_HIDDEN_NIGHTMARE_INCEPTION: 'CommonBuffId' = 152878 + TODDLER_BED_LOVED: 'CommonBuffId' = 150399 + TODDLER_BED_MOMENTS_PEACE: 'CommonBuffId' = 150401 + TODDLER_BED_NIGHTMARE: 'CommonBuffId' = 152880 + TODDLER_BED_PUT_ME_TO_BED: 'CommonBuffId' = 157679 + TODDLER_BED_PUT_TODDLER_TO_BED_AUTONOMY: 'CommonBuffId' = 150557 + TODDLER_BED_RESTED: 'CommonBuffId' = 156726 + TODDLER_BED_TUCK_IN_AUTONOMY: 'CommonBuffId' = 149394 + TODDLER_BOREDOM_DOLLHOUSE_ANGRY: 'CommonBuffId' = 152295 + TODDLER_BOREDOM_DOLLHOUSE_SAD: 'CommonBuffId' = 152297 + TODDLER_BOREDOM_DOLLHOUSE_SATISFIED: 'CommonBuffId' = 152296 + TODDLER_BOREDOM_NESTING_BLOCKS_ANGRY: 'CommonBuffId' = 152270 + TODDLER_BOREDOM_NESTING_BLOCKS_SAD: 'CommonBuffId' = 152272 + TODDLER_BOREDOM_NESTING_BLOCKS_SATISFIED: 'CommonBuffId' = 152273 + TODDLER_BOREDOM_POTTY_SATISFIED: 'CommonBuffId' = 156764 + TODDLER_BOREDOM_ROUGHHOUSING_ANGRY: 'CommonBuffId' = 152280 + TODDLER_BOREDOM_ROUGHHOUSING_SAD: 'CommonBuffId' = 152281 + TODDLER_BOREDOM_ROUGHHOUSING_SATISFIED: 'CommonBuffId' = 152282 + TODDLER_BOREDOM_STEREO_ANGRY: 'CommonBuffId' = 152283 + TODDLER_BOREDOM_STEREO_DANCING_ANGRY: 'CommonBuffId' = 156723 + TODDLER_BOREDOM_STEREO_DANCING_SAD: 'CommonBuffId' = 156725 + TODDLER_BOREDOM_STEREO_DANCING_SATISFIED: 'CommonBuffId' = 156724 + TODDLER_BOREDOM_STEREO_SAD: 'CommonBuffId' = 152284 + TODDLER_BOREDOM_STEREO_SATISFIED: 'CommonBuffId' = 152285 + TODDLER_BOREDOM_TODDLER_BOOK_ANGRY: 'CommonBuffId' = 152286 + TODDLER_BOREDOM_TODDLER_BOOK_SAD: 'CommonBuffId' = 152287 + TODDLER_BOREDOM_TODDLER_BOOK_SATISFIED: 'CommonBuffId' = 152288 + TODDLER_BOREDOM_TOYS_ANGRY: 'CommonBuffId' = 152291 + TODDLER_BOREDOM_TOYS_SAD: 'CommonBuffId' = 152290 + TODDLER_BOREDOM_TOYS_SATISFIED: 'CommonBuffId' = 152289 + TODDLER_BOREDOM_TV_ANGRY: 'CommonBuffId' = 152292 + TODDLER_BOREDOM_TV_SAD: 'CommonBuffId' = 152293 + TODDLER_BOREDOM_TV_SATISFIED: 'CommonBuffId' = 152294 + TODDLER_CHECK_TODDLER_FEED_TODDLER: 'CommonBuffId' = 146039 + TODDLER_CHECK_TODDLER_FEED_TODDLER_DESSERT: 'CommonBuffId' = 153918 + TODDLER_CHECK_TODDLER_FEED_TODDLER_DRINK: 'CommonBuffId' = 152866 + TODDLER_DIAPER_RASH: 'CommonBuffId' = 156762 + TODDLER_HAS_DIRTY_DIAPER: 'CommonBuffId' = 140766 + TODDLER_JUNGLE_GYM_BALL_PIT: 'CommonBuffId' = 170762 + TODDLER_JUNGLE_GYM_SLIDE_CLIMBER_SLIDE_CATCH: 'CommonBuffId' = 172850 + TODDLER_JUNGLE_GYM_STARTING_MAKE_BELIEVE: 'CommonBuffId' = 173477 + TODDLER_PERSONALITY_ASK_TO_CARRY: 'CommonBuffId' = 318175 + TODDLER_PERSONALITY_BEING_CARRIED_ANGRY: 'CommonBuffId' = 313257 + TODDLER_PERSONALITY_BEING_CARRIED_HAPPY: 'CommonBuffId' = 313245 + TODDLER_PERSONALITY_BEING_CARRIED_SAD: 'CommonBuffId' = 313256 + TODDLER_PERSONALITY_DESTRUCTIVE_TODDLER: 'CommonBuffId' = 333448 + TODDLER_PERSONALITY_FORCED_TO_WAKE_UP: 'CommonBuffId' = 313466 + TODDLER_PERSONALITY_FORCED_TO_WAKE_UP_COOLDOWN: 'CommonBuffId' = 314214 + TODDLER_PERSONALITY_FORCED_TO_WAKE_UP_HATES_BED_TIME: 'CommonBuffId' = 314832 + TODDLER_PERSONALITY_GIVE_QUIRKS: 'CommonBuffId' = 336060 + TODDLER_PERSONALITY_HATES_BED_TIME_ENERGY_YELLOW_OVERRIDE: 'CommonBuffId' = 313690 + TODDLER_PERSONALITY_HATES_BED_TIME_ROLL_WAKE_UP: 'CommonBuffId' = 314212 + TODDLER_PERSONALITY_HEAVY_SLEEPER_SAFE_SLEEP: 'CommonBuffId' = 313461 + TODDLER_PERSONALITY_HIDDEN_BEING_HELD: 'CommonBuffId' = 314040 + TODDLER_PERSONALITY_HIDDEN_BEING_HELD_BY_CAREGIVER: 'CommonBuffId' = 322777 + TODDLER_PERSONALITY_HIDDEN_EARLY_RISER_COOLDOWN: 'CommonBuffId' = 319502 + TODDLER_PERSONALITY_HIDDEN_READ_TOME: 'CommonBuffId' = 318173 + TODDLER_PERSONALITY_HIDDEN_SING_A_SONG_TIME: 'CommonBuffId' = 334319 + TODDLER_PERSONALITY_LIGHT_SLEEPER_ROLL_WAKE_UP: 'CommonBuffId' = 313464 + TODDLER_PERSONALITY_PICKY_EATER_EWW_YUCK: 'CommonBuffId' = 313468 + TODDLER_PERSONALITY_PICKY_EATER_EWW_YUCK_MIXED: 'CommonBuffId' = 313687 + TODDLER_PERSONALITY_PICKY_EATER_HUNGER_YELLOW_OVERRIDE: 'CommonBuffId' = 313786 + TODDLER_PERSONALITY_REVEAL_DELAY: 'CommonBuffId' = 333670 + TODDLER_PERSONALITY_WAKING_UP_ANGRY: 'CommonBuffId' = 313262 + TODDLER_PERSONALITY_WAKING_UP_HAPPY: 'CommonBuffId' = 313260 + TODDLER_PERSONALITY_WAKING_UP_SAD: 'CommonBuffId' = 313261 + TODDLER_PLAY_IN_OCEAN_VFX: 'CommonBuffId' = 212940 + TODDLER_PLAY_IN_OCEAN_VFX_3: 'CommonBuffId' = 214476 + TODDLER_PLAY_IN_OCEAN_VFX_4: 'CommonBuffId' = 214477 + TODDLER_PLAY_IN_OCEAN_VFX_5: 'CommonBuffId' = 214478 + TODDLER_WHY_WEAR_CLOTHES: 'CommonBuffId' = 153408 + TOLD_GOODBYE_INVISIBLE: 'CommonBuffId' = 101049 + TOLD_GREAT_STORY: 'CommonBuffId' = 103136 + TOWN_MASCOT_BROADCASTERS_DANCE: 'CommonBuffId' = 251254 + TOWN_MASCOT_BUFFS_DANCE: 'CommonBuffId' = 250418 + TOWN_MASCOT_BUFFS_HANG_AROUND_STATUE_LOCK_OUT: 'CommonBuffId' = 252452 + TOWN_MASCOT_BUFFS_LOCK_OUTS_CAPSULE: 'CommonBuffId' = 251180 + TOWN_MASCOT_BUFFS_STATUE_LOT_VISIT: 'CommonBuffId' = 250682 + TOWN_MASCOT_BUFFS_STATUE_SELFIE: 'CommonBuffId' = 251859 + TOWN_SCULPTURE_BLESSED_BY_JUNGLE: 'CommonBuffId' = 175068 + TOWN_SCULPTURE_CURSED_NO_MORE: 'CommonBuffId' = 175071 + TOY_BALL_PET_HANDLED_CHEWED_BALL: 'CommonBuffId' = 164347 + TRAGIC_CLOWN_SUCH_TRAGEDY: 'CommonBuffId' = 139613 + TRAINING_DUMMY_FIGHT_LOST: 'CommonBuffId' = 203259 + TRAINING_DUMMY_TURN_TAKEN: 'CommonBuffId' = 203255 + TRAINING_DUMMY_WATCHING: 'CommonBuffId' = 203258 + TRAIT_ACTIVE: 'CommonBuffId' = 9328 + TRAIT_ACTIVE_ANTSY: 'CommonBuffId' = 27457 + TRAIT_ACTIVE_LOW_ACTIVITY_HIDDEN: 'CommonBuffId' = 40879 + TRAIT_ADOPT_TIGER_HIDDEN: 'CommonBuffId' = 353575 + TRAIT_ADULT: 'CommonBuffId' = 34526 + TRAIT_ADVENTUROUS: 'CommonBuffId' = 252086 + TRAIT_ALLURING: 'CommonBuffId' = 26189 + TRAIT_ALWAYS_WELCOME: 'CommonBuffId' = 35505 + TRAIT_AMBITIOUS: 'CommonBuffId' = 12650 + TRAIT_AMBITIOUS_LOW_ADVANCEMENT_HIDDEN: 'CommonBuffId' = 37817 + TRAIT_AMBITIOUS_PROMOTION_ANX: 'CommonBuffId' = 73908 + TRAIT_AMBITIOUS_PROMOTION_ANX_JOBLESS: 'CommonBuffId' = 97459 + TRAIT_ANGLERS_TRANQUILITY_FISHING: 'CommonBuffId' = 157955 + TRAIT_ANIMAL_ENTHUSIAST: 'CommonBuffId' = 257637 + TRAIT_ANIMAL_ENTHUSIAST_DANCE_FAIL: 'CommonBuffId' = 268090 + TRAIT_ANIMAL_ENTHUSIAST_DANCE_SUCCESS: 'CommonBuffId' = 268091 + TRAIT_ANIMAL_ENTHUSIAST_ENERGIZED_CONVERSATION: 'CommonBuffId' = 260395 + TRAIT_ANIMAL_ENTHUSIAST_HAPPY_BONDING: 'CommonBuffId' = 260391 + TRAIT_ANIMAL_ENTHUSIAST_INSPIRED_EGG: 'CommonBuffId' = 260396 + TRAIT_ANIMAL_ENTHUSIAST_PLAY_TO_COOLDOWN: 'CommonBuffId' = 270607 + TRAIT_ANIMAL_ENTHUSIAST_SAD_MISS_ANIMALS: 'CommonBuffId' = 260392 + TRAIT_ANIMAL_ENTHUSIAST_SELLING_ANIMAL_STRONGER: 'CommonBuffId' = 260394 + TRAIT_ANIMAL_WHISPERER: 'CommonBuffId' = 172194 + TRAIT_ANTISEPTIC: 'CommonBuffId' = 26372 + TRAIT_ARGUMENTATIVE: 'CommonBuffId' = 163099 + TRAIT_ART_LOVER: 'CommonBuffId' = 28555 + TRAIT_ART_LOVER_INSPIRED: 'CommonBuffId' = 28582 + TRAIT_ART_LOVER_NATURE_IS_ART: 'CommonBuffId' = 107784 + TRAIT_ASPIRATION_CHALLENGE_POSITIVITY_KINDNESS_AMBASSADOR: 'CommonBuffId' = 198886 + TRAIT_ASPIRATION_FTUE_CAREER_MINDED: 'CommonBuffId' = 201240 + TRAIT_ASPIRATION_FTUE_OVER_ACHIEVER: 'CommonBuffId' = 197774 + TRAIT_ASPIRATION_LORD_OF_THE_KNITS: 'CommonBuffId' = 240406 + TRAIT_ASPIRATION_SLINGER_OF_SPELLS: 'CommonBuffId' = 217374 + TRAIT_AT_PEACE_WITH_NATURE: 'CommonBuffId' = 108423 + TRAIT_BABY: 'CommonBuffId' = 34521 + TRAIT_BANE_SABOTAGE: 'CommonBuffId' = 27212 + TRAIT_BEACHBUM_LAIDBACK: 'CommonBuffId' = 308569 + TRAIT_BONEHILDA: 'CommonBuffId' = 253238 + TRAIT_BONEHILDA_AUTONOMY: 'CommonBuffId' = 253360 + TRAIT_BOOKWORM: 'CommonBuffId' = 28598 + TRAIT_BOOKWORM_INSPIRED: 'CommonBuffId' = 28599 + TRAIT_BRAVE: 'CommonBuffId' = 253270 + TRAIT_BRO: 'CommonBuffId' = 12655 + TRAIT_BRO_BROXIMITY_HIDDEN: 'CommonBuffId' = 12656 + TRAIT_BRO_BRO_LOVE: 'CommonBuffId' = 74074 + TRAIT_BRO_WATCHED_SPORTS: 'CommonBuffId' = 31208 + TRAIT_CAMPING_ADD_TRAIT_HIDDEN: 'CommonBuffId' = 104273 + TRAIT_CAMPING_HIDDEN: 'CommonBuffId' = 102266 + TRAIT_CAREER_SCOUTING_APTITUDE: 'CommonBuffId' = 187865 + TRAIT_CAREFREE: 'CommonBuffId' = 308568 + TRAIT_CAT_LOVER: 'CommonBuffId' = 157980 + TRAIT_CAT_LOVER_ADOPTION: 'CommonBuffId' = 174829 + TRAIT_CAT_LOVER_DEATH: 'CommonBuffId' = 174831 + TRAIT_CAT_LOVER_MET_NEW_CAT: 'CommonBuffId' = 158024 + TRAIT_CAT_LOVER_TAKEN: 'CommonBuffId' = 174830 + TRAIT_CHEERFUL: 'CommonBuffId' = 9324 + TRAIT_CHEERFUL_CHEERED_TO_DEATH: 'CommonBuffId' = 258458 + TRAIT_CHEERFUL_HAPPY_BONUS: 'CommonBuffId' = 258463 + TRAIT_CHEERFUL_LOOK_AT_BRIGHT_SIDE_COOLDOWN: 'CommonBuffId' = 258456 + TRAIT_CHILD: 'CommonBuffId' = 34523 + TRAIT_CHILDISH: 'CommonBuffId' = 12661 + TRAIT_CHILDISH_PLAYED_WITH_CHILDREN: 'CommonBuffId' = 37938 + TRAIT_CHILDISH_WATCHED_KIDS_CHANNEL: 'CommonBuffId' = 31237 + TRAIT_CHILD_OF_THE_OCEAN: 'CommonBuffId' = 204497 + TRAIT_CHILD_OF_THE_OCEAN_FISH_SADNESS: 'CommonBuffId' = 211734 + TRAIT_CHILD_OF_THE_OCEAN_VISIBLE_BIG_FISH: 'CommonBuffId' = 210724 + TRAIT_CHILD_OF_THE_OCEAN_VISIBLE_CHILD: 'CommonBuffId' = 210721 + TRAIT_CHILD_OF_THE_OCEAN_VISIBLE_FISH_FREEDOM: 'CommonBuffId' = 210716 + TRAIT_CHILD_OF_THE_OCEAN_VISIBLE_HURT_FISH: 'CommonBuffId' = 210715 + TRAIT_CHILD_OF_THE_OCEAN_VISIBLE_MAROONED: 'CommonBuffId' = 210722 + TRAIT_CHILD_OF_THE_OCEAN_VISIBLE_STOMACH_SQUALL: 'CommonBuffId' = 210714 + TRAIT_CHILD_OF_THE_OCEAN_WADING: 'CommonBuffId' = 214586 + TRAIT_CHILD_OF_THE_SEA: 'CommonBuffId' = 341882 + TRAIT_CHILD_OF_THE_SEA_COMMUNITY_CONTENDER: 'CommonBuffId' = 344489 + TRAIT_CHILD_OF_THE_SEA_CULTURAL_ACTIVITIES: 'CommonBuffId' = 344487 + TRAIT_CHILD_OF_THE_SEA_KINSHIP_COOLDOWN: 'CommonBuffId' = 341997 + TRAIT_CHILD_OF_THE_SEA_KINSHIP_HIDDEN: 'CommonBuffId' = 352290 + TRAIT_CHILD_OF_THE_SEA_SKY_LANTERN_COOLDOWN: 'CommonBuffId' = 353504 + TRAIT_CHILD_OF_THE_SEA_VISIBLE_ADRIFT: 'CommonBuffId' = 341999 + TRAIT_CHILD_OF_THE_SEA_VISIBLE_COMMUNITY_CONTENDER: 'CommonBuffId' = 344046 + TRAIT_CHILD_OF_THE_SEA_VISIBLE_CONNECTED_ROOTS: 'CommonBuffId' = 341998 + TRAIT_CHILD_OF_THE_SEA_VISIBLE_GREAT_RELEASE: 'CommonBuffId' = 342000 + TRAIT_CHILD_OF_THE_SEA_VISIBLE_RELATIVELY_DISTANT: 'CommonBuffId' = 341618 + TRAIT_CHILD_SKILL_HEAD_STRONG: 'CommonBuffId' = 308832 + TRAIT_CHILD_SKILL_PACK_ANIMAL_MENTOR: 'CommonBuffId' = 308833 + TRAIT_CLEAR_PERSPECTIVE: 'CommonBuffId' = 308570 + TRAIT_CLIMATE_CHANGE_WOKE_HIDDEN: 'CommonBuffId' = 179875 + TRAIT_CLUMSY: 'CommonBuffId' = 12664 + TRAIT_CLUMSY_SILLY_ME: 'CommonBuffId' = 37733 + TRAIT_CLUMSY_SLIP_COOLDOWN: 'CommonBuffId' = 258226 + TRAIT_COLDHEARTED: 'CommonBuffId' = 275545 + TRAIT_COMMITMENTPHOBE_BROKE_UP: 'CommonBuffId' = 74407 + TRAIT_COMMITMENT_ISSUES: 'CommonBuffId' = 74339 + TRAIT_COMMITMENT_ISSUES_CAREER_COMMITMENT_HIDDEN: 'CommonBuffId' = 12666 + TRAIT_COMMITMENT_ISSUES_FEELING_TRAPPED_CAREER: 'CommonBuffId' = 74358 + TRAIT_COMMITMENT_ISSUES_FEELING_TRAPPED_REL: 'CommonBuffId' = 74397 + TRAIT_COMMITMENT_ISSUES_QUIT_JOB: 'CommonBuffId' = 12665 + TRAIT_COMMITMENT_ISSUES_QUIT_JOB_COOLDOWN: 'CommonBuffId' = 98332 + TRAIT_COMMITMENT_ISSUES_RELATIONSHIP_COMMITMENT_HIDDEN: 'CommonBuffId' = 74350 + TRAIT_COMPASSIONATE: 'CommonBuffId' = 160863 + TRAIT_COTTAGE_WORLD_NPC_AGNES_CRUMPLEBOTTOM_ANGRY: 'CommonBuffId' = 264153 + TRAIT_COTTAGE_WORLD_NPC_HEADLINE_AGATHA_CRUMPLEBOTTOM: 'CommonBuffId' = 262913 + TRAIT_COTTAGE_WORLD_NPC_HEADLINE_AGNES_CRUMPLEBOTTOM: 'CommonBuffId' = 262914 + TRAIT_COTTAGE_WORLD_NPC_HEADLINE_CRITTER_TENDER: 'CommonBuffId' = 262915 + TRAIT_COTTAGE_WORLD_NPC_HEADLINE_GROCERY_DELIVERY: 'CommonBuffId' = 262916 + TRAIT_COTTAGE_WORLD_NPC_HEADLINE_GROCERY_OWNER: 'CommonBuffId' = 262917 + TRAIT_COTTAGE_WORLD_NPC_HEADLINE_MAYOR: 'CommonBuffId' = 262918 + TRAIT_COTTAGE_WORLD_NPC_HEADLINE_PUB_OWNER: 'CommonBuffId' = 262919 + TRAIT_COUNTRY_CARETAKER: 'CommonBuffId' = 265331 + TRAIT_CREATIVE: 'CommonBuffId' = 12697 + TRAIT_CREATIVELY_GIFTED: 'CommonBuffId' = 29625 + TRAIT_CREATIVE_BEAUTIFUL_INSPIRATION: 'CommonBuffId' = 107954 + TRAIT_CREATIVE_LOW_CREATIVITY_HIDDEN: 'CommonBuffId' = 27167 + TRAIT_CREATIVE_UNCREATIVE: 'CommonBuffId' = 74668 + TRAIT_CRINGE: 'CommonBuffId' = 341155 + TRAIT_CULINARY_TRAINING: 'CommonBuffId' = 28694 + TRAIT_CURIOUS_ABOUT_CLUBS: 'CommonBuffId' = 125557 + TRAIT_DANCE_MACHINE: 'CommonBuffId' = 126089 + TRAIT_DANCE_MACHINE_PARTY_TIME_ENERGIZED: 'CommonBuffId' = 126103 + TRAIT_DANCE_MACHINE_READY_TO_PARTY: 'CommonBuffId' = 126123 + TRAIT_DANCE_MACHINE_WHERES_THE_PARTY: 'CommonBuffId' = 126181 + TRAIT_DANCE_MACHINE_WORK_LOOT: 'CommonBuffId' = 126200 + TRAIT_DASTARDLY: 'CommonBuffId' = 27098 + TRAIT_DAUNTLESS: 'CommonBuffId' = 283720 + TRAIT_DEBUG_OUTCOMES: 'CommonBuffId' = 258315 + TRAIT_DISCERNING_DWELLER_NEIGHBORLY: 'CommonBuffId' = 350270 + TRAIT_DOG_LOVER: 'CommonBuffId' = 157981 + TRAIT_DOG_LOVER_ADOPTION: 'CommonBuffId' = 174832 + TRAIT_DOG_LOVER_DEATH: 'CommonBuffId' = 174834 + TRAIT_DOG_LOVER_MET_NEW_DOG: 'CommonBuffId' = 158023 + TRAIT_DOG_LOVER_TAKEN: 'CommonBuffId' = 174833 + TRAIT_ECO_MASTER: 'CommonBuffId' = 234890 + TRAIT_ECO_MASTER_HEADLINE: 'CommonBuffId' = 241275 + TRAIT_ELDER: 'CommonBuffId' = 34527 + TRAIT_EMOTIONAL_CONTROL: 'CommonBuffId' = 160276 + TRAIT_ENTREPRENEUR: 'CommonBuffId' = 234891 + TRAIT_ENTREPRENEUR_HEADLINE: 'CommonBuffId' = 241277 + TRAIT_EP14_WORLD_NPC_HEADLINE_HORSE_TRAINER: 'CommonBuffId' = 323474 + TRAIT_EP14_WORLD_NPC_HEADLINE_MYSTERIOUS_RANCHER: 'CommonBuffId' = 323473 + TRAIT_EP14_WORLD_NPC_HORSE_TRAINER: 'CommonBuffId' = 321629 + TRAIT_EP14_WORLD_NPC_MYSTERIOUS_RANCHER: 'CommonBuffId' = 319493 + TRAIT_EP16_SPECIAL_NPC_THERING_BEAR: 'CommonBuffId' = 370190 + TRAIT_ESSENCE_OF_FLAVOR: 'CommonBuffId' = 26186 + TRAIT_EVIL: 'CommonBuffId' = 12672 + TRAIT_EVIL_HELPED_OTHERS: 'CommonBuffId' = 151266 + TRAIT_EVIL_NEAR_MISERY: 'CommonBuffId' = 30202 + TRAIT_EVIL_NEAR_MISERY_HIDDEN: 'CommonBuffId' = 74235 + TRAIT_EVIL_SUPPRESS_MANIACAL_LAUGH: 'CommonBuffId' = 98694 + TRAIT_EXPLORER: 'CommonBuffId' = 368634 + TRAIT_FAMILY_ORIENTED: 'CommonBuffId' = 12675 + TRAIT_FAMILY_ORIENTED_HIDDEN: 'CommonBuffId' = 74232 + TRAIT_FAMILY_ORIENTED_LOW_FAMILY_TIME_HIDDEN: 'CommonBuffId' = 74244 + TRAIT_FAMILY_ORIENTED_MISSING_FAMILY: 'CommonBuffId' = 30696 + TRAIT_FAMILY_ORIENTED_NEAR_FAMILY: 'CommonBuffId' = 10610 + TRAIT_FARTISAN_KNOCKOUT: 'CommonBuffId' = 12681 + TRAIT_FEELING_ANGRY: 'CommonBuffId' = 27207 + TRAIT_FEELING_CONFIDENT: 'CommonBuffId' = 9289 + TRAIT_FEELING_ENERGIZED: 'CommonBuffId' = 9331 + TRAIT_FEELING_FLIRTY: 'CommonBuffId' = 9305 + TRAIT_FEELING_FOCUSED: 'CommonBuffId' = 9294 + TRAIT_FEELING_HAPPY: 'CommonBuffId' = 9323 + TRAIT_FEELING_INSPIRED: 'CommonBuffId' = 9300 + TRAIT_FEELING_PLAYFUL: 'CommonBuffId' = 9341 + TRAIT_FEELING_SAD: 'CommonBuffId' = 9336 + TRAIT_FOODIE: 'CommonBuffId' = 27178 + TRAIT_FOODIE_INSPIRED_TV: 'CommonBuffId' = 34198 + TRAIT_FOREVER_FRESH: 'CommonBuffId' = 183032 + TRAIT_FOREVER_FULL: 'CommonBuffId' = 183031 + TRAIT_FORTUNE_INVESTED_GIVE_INTEREST_CHECK: 'CommonBuffId' = 77748 + TRAIT_FOX_DEFAULT: 'CommonBuffId' = 259923 + TRAIT_FREEGAN: 'CommonBuffId' = 234436 + TRAIT_FREEGAN_BADDEAL: 'CommonBuffId' = 234613 + TRAIT_FREEGAN_CONSUMERIST_SHAME: 'CommonBuffId' = 234614 + TRAIT_FREEGAN_CORPORATE_SELLOUT: 'CommonBuffId' = 234621 + TRAIT_FREEGAN_DISCOUNT_DENIED: 'CommonBuffId' = 237105 + TRAIT_FREEGAN_DISCOUNT_DENIED_FINAL: 'CommonBuffId' = 237110 + TRAIT_FREEGAN_FREED_FROM_RAT_RACE: 'CommonBuffId' = 234622 + TRAIT_FREEGAN_JUST_FINE: 'CommonBuffId' = 234618 + TRAIT_FREEGAN_LUCKY_FIND: 'CommonBuffId' = 234619 + TRAIT_FREEGAN_MEALS_ON_THE_CHEAP: 'CommonBuffId' = 234617 + TRAIT_FREEGAN_PREVENTED_FOOD_WASTE: 'CommonBuffId' = 234620 + TRAIT_FREEGAN_RECENTLY_DOVE_FOR_MEALS: 'CommonBuffId' = 237555 + TRAIT_FREEGAN_RUMMAGE_COOLDOWN: 'CommonBuffId' = 237077 + TRAIT_FREEGAN_SWEET_SAVINGS: 'CommonBuffId' = 234623 + TRAIT_FREEGAN_TOUGH_NEGOTIATOR: 'CommonBuffId' = 234624 + TRAIT_FREEGAN_UNNECESSARY_SPENDING: 'CommonBuffId' = 234616 + TRAIT_FREEGAN_URBAN_SQUATTER: 'CommonBuffId' = 234505 + TRAIT_FROM_PROXIMITY_CHILD_OF_THE_SEA_NEARBY_RELATIONSHIP: 'CommonBuffId' = 341619 + TRAIT_GEEK: 'CommonBuffId' = 12684 + TRAIT_GEEKY_CONVERSATION: 'CommonBuffId' = 12685 + TRAIT_GEEK_ALIEN_TV: 'CommonBuffId' = 107151 + TRAIT_GEEK_COLLECTED_SOMETHING: 'CommonBuffId' = 35518 + TRAIT_GEEK_LOW_GAMING_NEED_HIDDEN: 'CommonBuffId' = 27549 + TRAIT_GEEK_NEED_TO_GAME: 'CommonBuffId' = 74952 + TRAIT_GEEK_NEED_TO_GAME_ACTIVE: 'CommonBuffId' = 98089 + TRAIT_GEEK_OUT: 'CommonBuffId' = 27543 + TRAIT_GENEROUS: 'CommonBuffId' = 341201 + TRAIT_GENIUS: 'CommonBuffId' = 12687 + TRAIT_GENIUS_GIVE_EUREKA_MOMENT_SKILL: 'CommonBuffId' = 258365 + TRAIT_GENIUS_SOLVE_HARD_PROBLEMS_COOLDOWN: 'CommonBuffId' = 258253 + TRAIT_GENIUS_UNCHALLENGED: 'CommonBuffId' = 28782 + TRAIT_GENIUS_UNCHALLENGED_HIDDEN: 'CommonBuffId' = 75499 + TRAIT_GLOOMY: 'CommonBuffId' = 9333 + TRAIT_GLOOMY_NEAR_GHOSTS: 'CommonBuffId' = 258933 + TRAIT_GLOOMY_NEAR_GHOST_HIDDEN: 'CommonBuffId' = 258931 + TRAIT_GLUTTON: 'CommonBuffId' = 12689 + TRAIT_GOOD: 'CommonBuffId' = 30413 + TRAIT_GOOD_DID_GOOD: 'CommonBuffId' = 35774 + TRAIT_GOOD_GOOD_VIBES: 'CommonBuffId' = 30482 + TRAIT_GOOD_GOOD_VIBES_HIDDEN: 'CommonBuffId' = 74236 + TRAIT_GOOFBALL: 'CommonBuffId' = 9338 + TRAIT_GREAT_KISSER: 'CommonBuffId' = 26644 + TRAIT_GREAT_STORYTELLER_CONFIDENT: 'CommonBuffId' = 110161 + TRAIT_GREAT_STORYTELLER_ENERGIZED: 'CommonBuffId' = 110159 + TRAIT_GREAT_STORYTELLER_INSPIRATIONAL_STORY: 'CommonBuffId' = 110156 + TRAIT_GREAT_STORYTELLER_PLAYFUL: 'CommonBuffId' = 110163 + TRAIT_GREEN_FIEND: 'CommonBuffId' = 233724 + TRAIT_GREEN_FIEND_VISIBLE_CLEAN_AIR_SPACE: 'CommonBuffId' = 231698 + TRAIT_GREEN_FIEND_VISIBLE_GREENER_WORLD: 'CommonBuffId' = 233587 + TRAIT_GREEN_FIEND_VISIBLE_UNCONTROLLABLE_FOOTPRINT: 'CommonBuffId' = 231680 + TRAIT_GREEN_FIEND_VISIBLE_UNNATURAL_ENVIRONMENT: 'CommonBuffId' = 231697 + TRAIT_GREGARIOUS: 'CommonBuffId' = 27090 + TRAIT_HAPPY_TODDLER: 'CommonBuffId' = 143163 + TRAIT_HAPPY_TODDLER_REMINISCENT: 'CommonBuffId' = 143166 + TRAIT_HARDLY_HUNGRY: 'CommonBuffId' = 26374 + TRAIT_HATES_CHILDREN: 'CommonBuffId' = 76800 + TRAIT_HATES_CHILDREN_AWAY_FROM_CHILDREN: 'CommonBuffId' = 258866 + TRAIT_HATES_CHILDREN_HIDDEN: 'CommonBuffId' = 74233 + TRAIT_HATES_CHILDREN_TRY_FOR_BABY: 'CommonBuffId' = 31305 + TRAIT_HATES_INFANTS: 'CommonBuffId' = 333376 + TRAIT_HATES_TODDLERS_HIDDEN: 'CommonBuffId' = 157197 + TRAIT_HAUNTED_HOUSE_TEMPERANCE: 'CommonBuffId' = 256354 + TRAIT_HEART_TO_HEART_NEAR_HAPPY_COUPLES: 'CommonBuffId' = 368499 + TRAIT_HERBALISM_POTION_GRILL_MASTER: 'CommonBuffId' = 105308 + TRAIT_HERO_OF_STRANGER_VILLE: 'CommonBuffId' = 204512 + TRAIT_HERO_OF_STRANGER_VILLE_PACKAGE_SCHEDULE: 'CommonBuffId' = 204515 + TRAIT_HIDDEN_CONSPIRACY_THEORIST: 'CommonBuffId' = 201419 + TRAIT_HIDDEN_CURIO_SHOP: 'CommonBuffId' = 204872 + TRAIT_HIDDEN_INFECTED: 'CommonBuffId' = 201416 + TRAIT_HIDDEN_MILITARY: 'CommonBuffId' = 201418 + TRAIT_HIDDEN_SCIENTIST: 'CommonBuffId' = 201417 + TRAIT_HIDDEN_VETERAN_HERMIT: 'CommonBuffId' = 203138 + TRAIT_HIGH_MAINTENANCE_COOLDOWN_HIDDEN: 'CommonBuffId' = 272494 + TRAIT_HIGH_MAINTENANCE_HIDDEN: 'CommonBuffId' = 272270 + TRAIT_HIGH_MAINTENANCE_IN_SUN_HIDDEN: 'CommonBuffId' = 272458 + TRAIT_HIGH_MAINTENANCE_SOLVE_STRUGGLE: 'CommonBuffId' = 272576 + TRAIT_HIGH_MAINTENANCE_VISIBLE_BUTT_HURT: 'CommonBuffId' = 272342 + TRAIT_HIGH_MAINTENANCE_VISIBLE_CATHARSIS: 'CommonBuffId' = 272521 + TRAIT_HIGH_MAINTENANCE_VISIBLE_DRANK_POOL: 'CommonBuffId' = 272346 + TRAIT_HIGH_MAINTENANCE_VISIBLE_DRANK_SEA: 'CommonBuffId' = 272347 + TRAIT_HIGH_MAINTENANCE_VISIBLE_HANG_NAIL: 'CommonBuffId' = 272345 + TRAIT_HIGH_MAINTENANCE_VISIBLE_HATE_SUN: 'CommonBuffId' = 272344 + TRAIT_HIGH_MAINTENANCE_VISIBLE_SHAMPOO_EYES: 'CommonBuffId' = 272349 + TRAIT_HIGH_MAINTENANCE_VISIBLE_SPLASH_BACK: 'CommonBuffId' = 272348 + TRAIT_HIGH_MAINTENANCE_VISIBLE_WEIRD_DREAM: 'CommonBuffId' = 272341 + TRAIT_HIGH_MAINTENANCE_VISIBLE_WORST_DAY: 'CommonBuffId' = 272350 + TRAIT_HIGH_MAINTENANCE_WORST_DAY_COOLDOWN_HIDDEN: 'CommonBuffId' = 272519 + TRAIT_HIGH_METABOLISM: 'CommonBuffId' = 27088 + TRAIT_HIGH_SCHOOL_TEAM_CHEER_TEAM: 'CommonBuffId' = 277049 + TRAIT_HIGH_SCHOOL_TEAM_CHESS_TEAM: 'CommonBuffId' = 277051 + TRAIT_HIGH_SCHOOL_TEAM_COMPUTER_TEAM: 'CommonBuffId' = 277052 + TRAIT_HIGH_SCHOOL_TEAM_FOOTBALL_TEAM: 'CommonBuffId' = 277050 + TRAIT_HILARIOUS: 'CommonBuffId' = 27171 + TRAIT_HILARIOUS_DAZED: 'CommonBuffId' = 99856 + TRAIT_HOLIDAY_TRADITION_FATHER_WINTER: 'CommonBuffId' = 183344 + TRAIT_HOLIDAY_TRADITION_FATHER_WINTER_BABY: 'CommonBuffId' = 183366 + TRAIT_HOME_TURF: 'CommonBuffId' = 144200 + TRAIT_HOME_TURF_AM_I_HOME: 'CommonBuffId' = 144209 + TRAIT_HOME_TURF_HOME_SWEET_HOME: 'CommonBuffId' = 144211 + TRAIT_HOME_TURF_HOME_SWEET_HOME_COOL_DOWN: 'CommonBuffId' = 144934 + TRAIT_HORSES_AGE_ADULT: 'CommonBuffId' = 321106 + TRAIT_HORSES_AGE_CHILD: 'CommonBuffId' = 321105 + TRAIT_HORSES_AGE_ELDER: 'CommonBuffId' = 321107 + TRAIT_HORSE_GAMEPLAY_CURIOUS: 'CommonBuffId' = 323853 + TRAIT_HORSE_GAMEPLAY_EQUESTRIAN_CENTER_CHAMPION_HORSE: 'CommonBuffId' = 331652 + TRAIT_HORSE_GAMEPLAY_HORSE_BREEDING_CHAMPION_GENES: 'CommonBuffId' = 323126 + TRAIT_HORSE_GAMEPLAY_PLAYFUL: 'CommonBuffId' = 322885 + TRAIT_HORSE_GAMEPLAY_TOP_NOTCH_FOAL: 'CommonBuffId' = 330838 + TRAIT_HORSE_LOVER: 'CommonBuffId' = 320899 + TRAIT_HORSE_LOVER_HORSE_EMPATHY_ANGRY: 'CommonBuffId' = 320902 + TRAIT_HORSE_LOVER_HORSE_EMPATHY_HAPPY: 'CommonBuffId' = 320964 + TRAIT_HORSE_LOVER_HORSE_EMPATHY_SAD: 'CommonBuffId' = 320963 + TRAIT_HORSE_LOVER_NEED_HORSE_INTERACTION_TIMER: 'CommonBuffId' = 320967 + TRAIT_HORSE_PERSONALITY_AGGRESSIVE: 'CommonBuffId' = 323825 + TRAIT_HORSE_PERSONALITY_BRAVE: 'CommonBuffId' = 322833 + TRAIT_HORSE_PERSONALITY_DEFIANT: 'CommonBuffId' = 323829 + TRAIT_HORSE_PERSONALITY_ENERGETIC: 'CommonBuffId' = 322879 + TRAIT_HORSE_PERSONALITY_FEARFUL: 'CommonBuffId' = 322835 + TRAIT_HORSE_PERSONALITY_FREE_SPIRIT: 'CommonBuffId' = 323827 + TRAIT_HORSE_PERSONALITY_FREE_SPIRIT_INSIDE: 'CommonBuffId' = 336664 + TRAIT_HORSE_PERSONALITY_FRIENDLY: 'CommonBuffId' = 322877 + TRAIT_HORSE_PERSONALITY_INDEPENDENT: 'CommonBuffId' = 323828 + TRAIT_HORSE_PERSONALITY_INTELLIGENT: 'CommonBuffId' = 322883 + TRAIT_HORSE_PERSONALITY_MELLOW: 'CommonBuffId' = 322881 + TRAIT_HORSE_PERSONALITY_NEEDY: 'CommonBuffId' = 327818 + TRAIT_HORSE_PERSONALITY_RESILIENT: 'CommonBuffId' = 327596 + TRAIT_HORSE_PLAYFUL_WANTS_TOYS: 'CommonBuffId' = 322888 + TRAIT_HOT_HEADED: 'CommonBuffId' = 12691 + TRAIT_HOT_HEATED_RILED: 'CommonBuffId' = 27214 + TRAIT_ICONIC: 'CommonBuffId' = 287318 + TRAIT_INDEPENDENT: 'CommonBuffId' = 26386 + TRAIT_INFANT: 'CommonBuffId' = 271169 + TRAIT_INSANE: 'CommonBuffId' = 12694 + TRAIT_INSANE_ANGRY: 'CommonBuffId' = 31530 + TRAIT_INSANE_FLIRTY: 'CommonBuffId' = 31532 + TRAIT_INSANE_HAPPY: 'CommonBuffId' = 31529 + TRAIT_INSANE_PRETTY_GIRL: 'CommonBuffId' = 76855 + TRAIT_INSANE_PRETTY_GIRL_HIDDEN: 'CommonBuffId' = 76707 + TRAIT_INSANE_SAD: 'CommonBuffId' = 31531 + TRAIT_INSIDER: 'CommonBuffId' = 125439 + TRAIT_INSIDER_MAX_STATISTIC: 'CommonBuffId' = 389119 + TRAIT_IRRESPONSIBLE: 'CommonBuffId' = 317400 + TRAIT_ISLAND_ANCESTORS: 'CommonBuffId' = 204496 + TRAIT_ISLAND_ANCESTORS_ENERGIZED: 'CommonBuffId' = 212072 + TRAIT_ISLAND_ANCESTORS_SPIRIT_BLESS_COOLDOWN: 'CommonBuffId' = 211657 + TRAIT_ISLAND_ANCESTORS_SPIRIT_DISAPPOINTED: 'CommonBuffId' = 212268 + TRAIT_ISLAND_ANCESTORS_SPIRIT_ELEMENTAL: 'CommonBuffId' = 211594 + TRAIT_ISLAND_ANCESTORS_SPIRIT_ELEMENTAL_POWER: 'CommonBuffId' = 211711 + TRAIT_ISLAND_ANCESTORS_SPIRIT_METEOR_COOLDOWN: 'CommonBuffId' = 211670 + TRAIT_ISLAND_ANCESTORS_SPIRIT_PUDDLE_COOLDOWN: 'CommonBuffId' = 212254 + TRAIT_ISLAND_ANCESTORS_SPIRIT_ROLE_AUTONOMY_NEGATIVE_JUDGING: 'CommonBuffId' = 214845 + TRAIT_ISLAND_ANCESTORS_SPIRIT_ROLE_AUTONOMY_POSITIVE_JUDGING: 'CommonBuffId' = 214844 + TRAIT_ISLAND_ANCESTORS_SUMMON: 'CommonBuffId' = 211255 + TRAIT_ISLAND_ANCESTORS_VISIBLE_BLESSING_OF_FORTUNE: 'CommonBuffId' = 211204 + TRAIT_ISLAND_ANCESTORS_VISIBLE_BLESSING_OF_FORTUNE_2: 'CommonBuffId' = 211239 + TRAIT_ISLAND_ANCESTORS_VISIBLE_BLESSING_OF_FRIENDSHIP: 'CommonBuffId' = 211202 + TRAIT_ISLAND_ANCESTORS_VISIBLE_BLESSING_OF_FRIENDSHIP_2: 'CommonBuffId' = 211240 + TRAIT_ISLAND_ANCESTORS_VISIBLE_BLESSING_OF_LOVE: 'CommonBuffId' = 211203 + TRAIT_ISLAND_ANCESTORS_VISIBLE_BLESSING_OF_LOVE_2: 'CommonBuffId' = 211241 + TRAIT_ISLAND_ANCESTORS_VISIBLE_CHILD_BLESSING: 'CommonBuffId' = 212089 + TRAIT_ISLAND_ANCESTORS_VISIBLE_DIFFERENCE: 'CommonBuffId' = 211168 + TRAIT_ISLAND_ANCESTORS_VISIBLE_DISAPPOINTED: 'CommonBuffId' = 211231 + TRAIT_ISLAND_ANCESTORS_VISIBLE_FEELIN_VIBES: 'CommonBuffId' = 211167 + TRAIT_ISLAND_ANCESTORS_VISIBLE_INCLUDED: 'CommonBuffId' = 211164 + TRAIT_ISLAND_ANCESTORS_VISIBLE_ISLAND_RECIPE: 'CommonBuffId' = 211165 + TRAIT_ISLAND_ANCESTORS_VISIBLE_TASTE_OF_HOME: 'CommonBuffId' = 211166 + TRAIT_IS_GHOST: 'CommonBuffId' = 187112 + TRAIT_JEALOUS: 'CommonBuffId' = 124880 + TRAIT_JEALOUSY_TALK_THROUGH_ISSUES_COOLDOWN: 'CommonBuffId' = 259628 + TRAIT_JEALOUS_JEALOUS_FURY: 'CommonBuffId' = 126687 + TRAIT_JEALOUS_LOVE_ENVY: 'CommonBuffId' = 126644 + TRAIT_JEALOUS_LOW_SO_TIME_HIDDEN: 'CommonBuffId' = 124936 + TRAIT_JEALOUS_MISSING_SO: 'CommonBuffId' = 124888 + TRAIT_JEALOUS_NEAR_SO: 'CommonBuffId' = 124882 + TRAIT_JEALOUS_NEAR_SO_HIDDEN: 'CommonBuffId' = 124884 + TRAIT_JEALOUS_PANGS: 'CommonBuffId' = 127141 + TRAIT_KINDNESS_AMBASSADOR_HAS_BEEN_CHALLENGED_POSITIVITY: 'CommonBuffId' = 198890 + TRAIT_KLEPTOMANIAC: 'CommonBuffId' = 131785 + TRAIT_KLEPTO_CAUGHT_STEALING: 'CommonBuffId' = 132374 + TRAIT_KLEPTO_EXHILARATING_STEAL: 'CommonBuffId' = 132237 + TRAIT_KLEPTO_EXHILARATING_STEAL_LOW_VALUE_OBJECT: 'CommonBuffId' = 132750 + TRAIT_KLEPTO_EXHILARATING_STEAL_MED_VALUE_OBJECT: 'CommonBuffId' = 132751 + TRAIT_KLEPTO_NEED_TO_SWIPE: 'CommonBuffId' = 132230 + TRAIT_KLEPTO_NEED_TO_SWIPE_HIDDEN: 'CommonBuffId' = 132224 + TRAIT_KLEPTO_RETURN_STOLEN_OBJECT: 'CommonBuffId' = 132241 + TRAIT_KLEPTO_WITNESS_STEALING: 'CommonBuffId' = 132376 + TRAIT_LACTOSE_INTOLERANT: 'CommonBuffId' = 257636 + TRAIT_LACTOSE_INTOLERANT_ATE_DAIRY: 'CommonBuffId' = 257774 + TRAIT_LACTOSE_INTOLERANT_ATE_DAIRY_AGAIN: 'CommonBuffId' = 257775 + TRAIT_LACTOSE_INTOLERANT_HAPPY_EATING_DAIRY: 'CommonBuffId' = 257773 + TRAIT_LACTOSE_INTOLERANT_NO_DAIRY: 'CommonBuffId' = 257777 + TRAIT_LAZY: 'CommonBuffId' = 9600 + TRAIT_LAZY_CHORES: 'CommonBuffId' = 28981 + TRAIT_LAZY_NAP: 'CommonBuffId' = 28980 + TRAIT_LAZY_TV: 'CommonBuffId' = 28949 + TRAIT_LEGENDARY: 'CommonBuffId' = 27092 + TRAIT_LEGENDARY_LANDLORD_HOME_MANAGER: 'CommonBuffId' = 350267 + TRAIT_LIFE_SKILLS_BAD_MANNERS: 'CommonBuffId' = 160849 + TRAIT_LIFE_SKILLS_GOOD_MANNERS: 'CommonBuffId' = 160842 + TRAIT_LONER: 'CommonBuffId' = 9603 + TRAIT_LONER_IS_ALONE: 'CommonBuffId' = 38731 + TRAIT_LONER_NEAR_STRANGERS: 'CommonBuffId' = 30712 + TRAIT_LONER_NEAR_STRANGERS_HIDDEN: 'CommonBuffId' = 74237 + TRAIT_LONER_NOT_ALONE: 'CommonBuffId' = 38730 + TRAIT_LOVES_OUTDOORS: 'CommonBuffId' = 75297 + TRAIT_LOVES_OUTDOORS_AM_I_OUTSIDE: 'CommonBuffId' = 37465 + TRAIT_LOVES_OUTDOORS_BEAUTIFUL_OUTDOORS: 'CommonBuffId' = 107785 + TRAIT_LOVES_OUTDOORS_CAUGHT_CRITTER: 'CommonBuffId' = 111309 + TRAIT_LOVES_OUTDOORS_COOPED_UP: 'CommonBuffId' = 31348 + TRAIT_LOVES_OUTDOORS_FRESH_AIR: 'CommonBuffId' = 31347 + TRAIT_LOVES_OUTDOORS_LOW_INSIDE_HIDDEN: 'CommonBuffId' = 75442 + TRAIT_LOVES_OUTDOORS_PEACEFUL_WAKING: 'CommonBuffId' = 107786 + TRAIT_LOVE_STRUCK: 'CommonBuffId' = 362410 + TRAIT_LOVE_STRUCK_HIDDEN_NEAR_PARTNER_COOLDOWN: 'CommonBuffId' = 370604 + TRAIT_LOVE_STRUCK_VISIBLE_ETERNAL_OPTIMISIM: 'CommonBuffId' = 362096 + TRAIT_LOVE_STRUCK_VISIBLE_LOVERS_BLISS: 'CommonBuffId' = 362095 + TRAIT_LOVE_STRUCK_VISIBLE_UNREQUITED_LOVE: 'CommonBuffId' = 362097 + TRAIT_LOYAL: 'CommonBuffId' = 311268 + TRAIT_LOYAL_CALLED_OUT: 'CommonBuffId' = 317408 + TRAIT_LOYAL_CHEATING_CONFESSED: 'CommonBuffId' = 311762 + TRAIT_LOYAL_CHEATING_CONFESSED_TARGET: 'CommonBuffId' = 312085 + TRAIT_LOYAL_CHEATING_GUILT_REMINDER: 'CommonBuffId' = 311764 + TRAIT_LOYAL_CHEATING_KNOWN_REMINDER: 'CommonBuffId' = 312301 + TRAIT_LOYAL_CHEATING_SECRET_GUILT: 'CommonBuffId' = 311761 + TRAIT_LOYAL_CONFRONT_ACTOR_COOLDOWN: 'CommonBuffId' = 314552 + TRAIT_LOYAL_DOG_OWNER_BOND: 'CommonBuffId' = 314272 + TRAIT_LOYAL_FRIEND_IS_TARGET_MEAN_INTERACTION: 'CommonBuffId' = 314551 + TRAIT_LOYAL_GRIEVING: 'CommonBuffId' = 314271 + TRAIT_LOYAL_IN_RELATIONSHIP: 'CommonBuffId' = 315357 + TRAIT_LOYAL_LOYAL_EMPLOYEE: 'CommonBuffId' = 317128 + TRAIT_LOYAL_MEAN_ACTOR: 'CommonBuffId' = 315356 + TRAIT_LOYAL_OCCULT_BOND: 'CommonBuffId' = 316056 + TRAIT_LOYAL_PRINCIPLES: 'CommonBuffId' = 316202 + TRAIT_LOYAL_PROMISED_HELP: 'CommonBuffId' = 313883 + TRAIT_LOYAL_ROMANCED_TAKEN_LOYAL_SIM: 'CommonBuffId' = 312302 + TRAIT_LOYAL_SAFE_SECRET: 'CommonBuffId' = 317406 + TRAIT_LOYAL_SURROUNDED: 'CommonBuffId' = 313587 + TRAIT_LOYAL_TRASH_TALKING_CONFESSED: 'CommonBuffId' = 312042 + TRAIT_LOYAL_TRASH_TALKING_GUILT: 'CommonBuffId' = 312043 + TRAIT_LOYAL_TRUST_REBUILT: 'CommonBuffId' = 311763 + TRAIT_LOYAL_TRUST_REBUILT_FAIL: 'CommonBuffId' = 312660 + TRAIT_LOYAL_TRUST_REBUILT_TARGET_COOLDOWN: 'CommonBuffId' = 312661 + TRAIT_LOYAL_WITNESSED_MEAN_BULLY: 'CommonBuffId' = 312055 + TRAIT_LOYAL_WITNESSED_MEAN_FRIEND: 'CommonBuffId' = 312056 + TRAIT_MAKER: 'CommonBuffId' = 230746 + TRAIT_MAKER_NPC: 'CommonBuffId' = 234892 + TRAIT_MAKER_NPC_HEADLINE: 'CommonBuffId' = 241274 + TRAIT_MAKER_VISIBLE_IDLE_HANDS: 'CommonBuffId' = 230751 + TRAIT_MAKER_VISIBLE_MAKIN_MATERIALS: 'CommonBuffId' = 230750 + TRAIT_MAKE_PREGNANT: 'CommonBuffId' = 238606 + TRAIT_MASTER_TRAINER: 'CommonBuffId' = 321398 + TRAIT_MATERIALISTIC: 'CommonBuffId' = 37716 + TRAIT_MATERIALISTIC_JUST_ADMIRED: 'CommonBuffId' = 35960 + TRAIT_MATERIALISTIC_JUST_ADMIRED2: 'CommonBuffId' = 75741 + TRAIT_MATERIALISTIC_JUST_ADMIRED3: 'CommonBuffId' = 75742 + TRAIT_MATERIALISTIC_NEED_TO_ADMIRE_HIDDEN: 'CommonBuffId' = 35961 + TRAIT_MATERIALISTIC_WANT_NEW_STUFF: 'CommonBuffId' = 75750 + TRAIT_MEAN: 'CommonBuffId' = 12700 + TRAIT_MEDIATOR: 'CommonBuffId' = 163098 + TRAIT_MELT_MASTER: 'CommonBuffId' = 132339 + TRAIT_MEMORABLE: 'CommonBuffId' = 32428 + TRAIT_MENTALLY_GIFTED: 'CommonBuffId' = 29627 + TRAIT_MISS_HANGING_OUT: 'CommonBuffId' = 125556 + TRAIT_MORNING_PERSON: 'CommonBuffId' = 32427 + TRAIT_MORNING_PERSON_ACTIVE: 'CommonBuffId' = 97673 + TRAIT_MORNING_PERSON_CHECK_ACTIVE: 'CommonBuffId' = 97685 + TRAIT_MUSEUM_PATRON_CONFIDENT: 'CommonBuffId' = 179088 + TRAIT_MUSEUM_PATRON_DONATED_TO_MUSEUM: 'CommonBuffId' = 179095 + TRAIT_MUSEUM_PATRON_FLIRTY: 'CommonBuffId' = 179089 + TRAIT_MUSIC_LOVER: 'CommonBuffId' = 9605 + TRAIT_MUSIC_LOVER_INSPIRED: 'CommonBuffId' = 35895 + TRAIT_MUSIC_LOVER_MUSIC_NEED_HIDDEN_TRIGGER: 'CommonBuffId' = 74088 + TRAIT_MUSIC_LOVER_NO_MUSIC: 'CommonBuffId' = 29315 + TRAIT_MUSIC_LOVER_PLAYING_MUSIC: 'CommonBuffId' = 29340 + TRAIT_NEAT: 'CommonBuffId' = 12701 + TRAIT_NEAT_CLEANING_FRENZY: 'CommonBuffId' = 35965 + TRAIT_NEAT_NEUROTIC_CLEAN: 'CommonBuffId' = 258246 + TRAIT_NEAT_TOO_MUCH_DIRT: 'CommonBuffId' = 107827 + TRAIT_NECTAR_KNOW_IT_ALL: 'CommonBuffId' = 340827 + TRAIT_NECTAR_KNOW_IT_ALL_DRUNK_NECTAR_SOOTH: 'CommonBuffId' = 340986 + TRAIT_NEEDS_NO_ONE: 'CommonBuffId' = 183030 + TRAIT_NEVER_WEARY: 'CommonBuffId' = 26378 + TRAIT_NIGHT_OWL: 'CommonBuffId' = 32425 + TRAIT_NIGHT_OWL_ACTIVE: 'CommonBuffId' = 97698 + TRAIT_NIGHT_OWL_CHECK_ACTIVE: 'CommonBuffId' = 97700 + TRAIT_NOSY: 'CommonBuffId' = 341157 + TRAIT_NPC_POLICE_ASSISTANT: 'CommonBuffId' = 114514 + TRAIT_NPC_POLICE_OFFICER: 'CommonBuffId' = 106176 + TRAIT_OUTGOING: 'CommonBuffId' = 29572 + TRAIT_OVER_ACHIEVER: 'CommonBuffId' = 284366 + TRAIT_OVER_ACHIEVER_CRAFTED_POOR_QUALITY: 'CommonBuffId' = 284143 + TRAIT_OVER_ACHIEVER_EXTRA_CREDIT_AVAILABLE: 'CommonBuffId' = 284513 + TRAIT_OVER_ACHIEVER_EYE_ROLL: 'CommonBuffId' = 284138 + TRAIT_OVER_ACHIEVER_FINISH_CAREER_TASK: 'CommonBuffId' = 284141 + TRAIT_OVER_ACHIEVER_FORGET_CAREER_TASK: 'CommonBuffId' = 284140 + TRAIT_OVER_ACHIEVER_NEARBY_OVER_ACHIEVER: 'CommonBuffId' = 284139 + TRAIT_OVER_ACHIEVER_NO_SKILL_UP: 'CommonBuffId' = 284142 + TRAIT_OVER_ACHIEVER_PREPARED_FAIL: 'CommonBuffId' = 284136 + TRAIT_OVER_ACHIEVER_PREPARED_SUCCESS_ENERGIZED: 'CommonBuffId' = 284137 + TRAIT_OVER_ACHIEVER_PREPARED_SUCCESS_FOCUSED: 'CommonBuffId' = 284151 + TRAIT_OVER_ACHIEVER_PREPARED_SUCCESS_INSPIRED: 'CommonBuffId' = 284150 + TRAIT_OVER_ACHIEVER_SKILL_MAX: 'CommonBuffId' = 284144 + TRAIT_OVER_ACHIEVER_SKILL_UP: 'CommonBuffId' = 284145 + TRAIT_PARANOID: 'CommonBuffId' = 203545 + TRAIT_PARANOID_COMPUTER_LOOK_UP_CONSPIRACY_THEORIES_ANGRY: 'CommonBuffId' = 203771 + TRAIT_PARANOID_COMPUTER_LOOK_UP_CONSPIRACY_THEORIES_CONFIDENT: 'CommonBuffId' = 203769 + TRAIT_PARANOID_COMPUTER_LOOK_UP_CONSPIRACY_THEORIES_TENSE: 'CommonBuffId' = 203770 + TRAIT_PARANOID_FROM_BEING_UNDERGROUND: 'CommonBuffId' = 203674 + TRAIT_PARANOID_FROM_OTHERS_TALKING: 'CommonBuffId' = 203630 + TRAIT_PARANOID_UNDERGROUND_CHECK_TIMER: 'CommonBuffId' = 203762 + TRAIT_PARTY_ANIMAL: 'CommonBuffId' = 284365 + TRAIT_PARTY_ANIMAL_AT_PARTY: 'CommonBuffId' = 284133 + TRAIT_PARTY_ANIMAL_AT_PARTY_AFTER_EFFECT: 'CommonBuffId' = 284876 + TRAIT_PARTY_ANIMAL_LARGE_SOCIAL_GROUP_HIDDEN: 'CommonBuffId' = 284842 + TRAIT_PARTY_ANIMAL_MISSED_PARTY: 'CommonBuffId' = 284131 + TRAIT_PARTY_ANIMAL_NO_PARTY_RECENTLY: 'CommonBuffId' = 284132 + TRAIT_PARTY_ANIMAL_PARTY_MEMORY_CONFIDENT: 'CommonBuffId' = 284126 + TRAIT_PARTY_ANIMAL_PARTY_MEMORY_ENERGIZED: 'CommonBuffId' = 284134 + TRAIT_PARTY_ANIMAL_PARTY_MEMORY_FAIL: 'CommonBuffId' = 284128 + TRAIT_PARTY_ANIMAL_PARTY_MEMORY_FOCUSED: 'CommonBuffId' = 284135 + TRAIT_PARTY_ANIMAL_PARTY_MEMORY_HAPPY: 'CommonBuffId' = 284127 + TRAIT_PARTY_ANIMAL_PARTY_MEMORY_INSPIRED: 'CommonBuffId' = 284125 + TRAIT_PARTY_ANIMAL_REJECTED_WOOOO: 'CommonBuffId' = 284124 + TRAIT_PARTY_ANIMAL_VIBE_CHECK_FAIL: 'CommonBuffId' = 284129 + TRAIT_PARTY_ANIMAL_VIBE_CHECK_SUCCESS: 'CommonBuffId' = 284130 + TRAIT_PARTY_ANIMAL_WOOOO_AUTONOMOUS_COOLDOWN_HIDDEN: 'CommonBuffId' = 290197 + TRAIT_PARTY_ANIMAL_WOOOO_TRACKER_HIDDEN: 'CommonBuffId' = 284832 + TRAIT_PATIENT: 'CommonBuffId' = 26375 + TRAIT_PERFECTIONIST: 'CommonBuffId' = 9618 + TRAIT_PERFECTIONIST_FOCUSED_PAY_OFF: 'CommonBuffId' = 258755 + TRAIT_PERFECTIONIST_IN_THE_ZONE: 'CommonBuffId' = 258633 + TRAIT_PERFECTIONIST_NO_RETRY_COOLDOWN: 'CommonBuffId' = 258842 + TRAIT_PERFECTIONIST_OUTSTANDING: 'CommonBuffId' = 33777 + TRAIT_PERFECTIONIST_POOR: 'CommonBuffId' = 33778 + TRAIT_PERFECTIONIST_QUALITY_INCREASE: 'CommonBuffId' = 258757 + TRAIT_PERFECTIONIST_RETRY_COOLDOWN: 'CommonBuffId' = 258590 + TRAIT_PERSONALITY_RECYCLE_DISCIPLE_REQUIRED_TO_RECYCLE: 'CommonBuffId' = 232796 + TRAIT_PERSONALITY_RECYCLE_DISCIPLE_RUMMAGE_COOLDOWN: 'CommonBuffId' = 232792 + TRAIT_PERSONALITY_RECYCLE_DISCIPLE_SALVAGE_THRILLS: 'CommonBuffId' = 232794 + TRAIT_PERSONALITY_RECYCLE_DISCIPLE_SCOLDED_TIMER: 'CommonBuffId' = 241625 + TRAIT_PERSONALITY_RECYCLE_DISCIPLE_STRAINING_TO_SCOUR: 'CommonBuffId' = 232795 + TRAIT_PERSONALITY_RECYCLE_DISCIPLE_UNDISCIPLINED_CRAVING: 'CommonBuffId' = 232797 + TRAIT_PET_ACTIVE: 'CommonBuffId' = 158205 + TRAIT_PET_ACTIVE_CAT: 'CommonBuffId' = 176165 + TRAIT_PET_AGE_ADULT: 'CommonBuffId' = 167110 + TRAIT_PET_AGE_CHILD: 'CommonBuffId' = 167108 + TRAIT_PET_AGE_ELDER: 'CommonBuffId' = 167109 + TRAIT_PET_AGGRESSIVE: 'CommonBuffId' = 158789 + TRAIT_PET_CURIOUS: 'CommonBuffId' = 158214 + TRAIT_PET_FRIENDLY: 'CommonBuffId' = 158786 + TRAIT_PET_GLUTTON: 'CommonBuffId' = 159983 + TRAIT_PET_HAIRY: 'CommonBuffId' = 158793 + TRAIT_PET_HUNTER: 'CommonBuffId' = 159985 + TRAIT_PET_INDEPENDENT: 'CommonBuffId' = 158791 + TRAIT_PET_LAZY: 'CommonBuffId' = 158206 + TRAIT_PET_NAUGHTY: 'CommonBuffId' = 159984 + TRAIT_PET_PLAYFUL: 'CommonBuffId' = 164047 + TRAIT_PET_PLAYFUL_TRAIT_INTERACTION: 'CommonBuffId' = 190999 + TRAIT_PET_PROTECTIVE: 'CommonBuffId' = 158792 + TRAIT_PET_QUIRK_FEAR_BREWER: 'CommonBuffId' = 160874 + TRAIT_PET_QUIRK_FEAR_COMPUTER: 'CommonBuffId' = 160875 + TRAIT_PET_QUIRK_FEAR_DISHWASHER: 'CommonBuffId' = 160885 + TRAIT_PET_QUIRK_FEAR_FIRE: 'CommonBuffId' = 160886 + TRAIT_PET_QUIRK_FEAR_FITNESS_EQUIPMENT: 'CommonBuffId' = 160887 + TRAIT_PET_QUIRK_FEAR_GAMING: 'CommonBuffId' = 160876 + TRAIT_PET_QUIRK_FEAR_INSTRUMENT: 'CommonBuffId' = 160877 + TRAIT_PET_QUIRK_FEAR_MICROWAVE: 'CommonBuffId' = 160878 + TRAIT_PET_QUIRK_FEAR_ROBOT_VACUUM: 'CommonBuffId' = 171325 + TRAIT_PET_QUIRK_FEAR_SHOWER: 'CommonBuffId' = 160879 + TRAIT_PET_QUIRK_FEAR_STEREO: 'CommonBuffId' = 160880 + TRAIT_PET_QUIRK_FEAR_SWIMMING: 'CommonBuffId' = 171911 + TRAIT_PET_QUIRK_FEAR_TOILET: 'CommonBuffId' = 160882 + TRAIT_PET_QUIRK_FEAR_TV: 'CommonBuffId' = 160883 + TRAIT_PET_QUIRK_FEAR_VACUUM: 'CommonBuffId' = 257146 + TRAIT_PET_QUIRK_OBSESS_BREWER: 'CommonBuffId' = 160804 + TRAIT_PET_QUIRK_OBSESS_COMPUTER: 'CommonBuffId' = 160805 + TRAIT_PET_QUIRK_OBSESS_COOKING: 'CommonBuffId' = 160814 + TRAIT_PET_QUIRK_OBSESS_DISHWASHER: 'CommonBuffId' = 160815 + TRAIT_PET_QUIRK_OBSESS_DOORBELL: 'CommonBuffId' = 160816 + TRAIT_PET_QUIRK_OBSESS_FIRE: 'CommonBuffId' = 160817 + TRAIT_PET_QUIRK_OBSESS_FISH_TANK: 'CommonBuffId' = 160806 + TRAIT_PET_QUIRK_OBSESS_FITNESS_EQUIPMENT: 'CommonBuffId' = 160807 + TRAIT_PET_QUIRK_OBSESS_FRIDGE: 'CommonBuffId' = 160808 + TRAIT_PET_QUIRK_OBSESS_GAMING: 'CommonBuffId' = 160809 + TRAIT_PET_QUIRK_OBSESS_INSTRUMENT: 'CommonBuffId' = 160810 + TRAIT_PET_QUIRK_OBSESS_MICROWAVE: 'CommonBuffId' = 160811 + TRAIT_PET_QUIRK_OBSESS_PET_MINOR_CAGE: 'CommonBuffId' = 184411 + TRAIT_PET_QUIRK_OBSESS_ROBOT_VACUUM: 'CommonBuffId' = 171326 + TRAIT_PET_QUIRK_OBSESS_SHOWER: 'CommonBuffId' = 160812 + TRAIT_PET_QUIRK_OBSESS_STEREO: 'CommonBuffId' = 160813 + TRAIT_PET_QUIRK_OBSESS_TOILET: 'CommonBuffId' = 160818 + TRAIT_PET_QUIRK_OBSESS_TV: 'CommonBuffId' = 160784 + TRAIT_PET_QUIRK_OBSESS_VACUUM: 'CommonBuffId' = 257150 + TRAIT_PET_SKITTISH: 'CommonBuffId' = 158787 + TRAIT_PET_SMART: 'CommonBuffId' = 158790 + TRAIT_PET_STUBBORN: 'CommonBuffId' = 158215 + TRAIT_PET_VOCAL: 'CommonBuffId' = 158788 + TRAIT_PET_WANDERLUST: 'CommonBuffId' = 158707 + TRAIT_PIPER_CAROL_OF_CLEANING: 'CommonBuffId' = 28069 + TRAIT_PLANT_SIM: 'CommonBuffId' = 162669 + TRAIT_POLY: 'CommonBuffId' = 368635 + TRAIT_PRACTICE_MAKES_PERFECT_CHILD_HIDDEN: 'CommonBuffId' = 374055 + TRAIT_PRACTICE_MAKES_PERFECT_CLEAR_MIND_INSPIRED: 'CommonBuffId' = 369453 + TRAIT_PRACTICE_MAKES_PERFECT_CREATIVE_TIER_0_HIDDEN: 'CommonBuffId' = 371144 + TRAIT_PRACTICE_MAKES_PERFECT_CREATIVE_TIER_1_HIDDEN: 'CommonBuffId' = 371069 + TRAIT_PRACTICE_MAKES_PERFECT_CREATIVE_TIER_2_HIDDEN: 'CommonBuffId' = 371070 + TRAIT_PRACTICE_MAKES_PERFECT_CREATIVE_TIER_3_HIDDEN: 'CommonBuffId' = 371071 + TRAIT_PRACTICE_MAKES_PERFECT_CREATIVE_TIER_4_HIDDEN: 'CommonBuffId' = 371145 + TRAIT_PRACTICE_MAKES_PERFECT_HIDDEN: 'CommonBuffId' = 369246 + TRAIT_PRACTICE_MAKES_PERFECT_LACK_OF_PRACTICE_SAD: 'CommonBuffId' = 370198 + TRAIT_PRACTICE_MAKES_PERFECT_LACK_OF_PRACTICE_SAD_MENTAL: 'CommonBuffId' = 381232 + TRAIT_PRACTICE_MAKES_PERFECT_LACK_OF_PRACTICE_SAD_PHYSICAL: 'CommonBuffId' = 381234 + TRAIT_PRACTICE_MAKES_PERFECT_LACK_OF_PRACTICE_SAD_SOCIAL: 'CommonBuffId' = 381233 + TRAIT_PRACTICE_MAKES_PERFECT_LIFE_HACK_INSPIRED: 'CommonBuffId' = 370159 + TRAIT_PRACTICE_MAKES_PERFECT_MENTAL_TIER_0_HIDDEN: 'CommonBuffId' = 371240 + TRAIT_PRACTICE_MAKES_PERFECT_MENTAL_TIER_1_HIDDEN: 'CommonBuffId' = 371139 + TRAIT_PRACTICE_MAKES_PERFECT_MENTAL_TIER_2_HIDDEN: 'CommonBuffId' = 371140 + TRAIT_PRACTICE_MAKES_PERFECT_MENTAL_TIER_3_HIDDEN: 'CommonBuffId' = 371141 + TRAIT_PRACTICE_MAKES_PERFECT_MENTAL_TIER_4_HIDDEN: 'CommonBuffId' = 371239 + TRAIT_PRACTICE_MAKES_PERFECT_MINDFUL_FOCUSED: 'CommonBuffId' = 370158 + TRAIT_PRACTICE_MAKES_PERFECT_ON_A_ROLL_FOCUSED: 'CommonBuffId' = 369240 + TRAIT_PRACTICE_MAKES_PERFECT_ON_A_ROLL_FOCUSED_MENTAL: 'CommonBuffId' = 381222 + TRAIT_PRACTICE_MAKES_PERFECT_ON_A_ROLL_FOCUSED_PHYSICAL: 'CommonBuffId' = 381223 + TRAIT_PRACTICE_MAKES_PERFECT_ON_A_ROLL_FOCUSED_SOCIAL: 'CommonBuffId' = 381224 + TRAIT_PRACTICE_MAKES_PERFECT_PAUSE_FOR_CLARITY_COOLDOWN: 'CommonBuffId' = 372129 + TRAIT_PRACTICE_MAKES_PERFECT_PERFECTED_FOCUSED: 'CommonBuffId' = 370200 + TRAIT_PRACTICE_MAKES_PERFECT_PERFECT_FOCUSED: 'CommonBuffId' = 370199 + TRAIT_PRACTICE_MAKES_PERFECT_PERFECT_FOCUSED_MENTAL: 'CommonBuffId' = 381235 + TRAIT_PRACTICE_MAKES_PERFECT_PERFECT_FOCUSED_PHYSICAL: 'CommonBuffId' = 381236 + TRAIT_PRACTICE_MAKES_PERFECT_PERFECT_FOCUSED_SOCIAL: 'CommonBuffId' = 381237 + TRAIT_PRACTICE_MAKES_PERFECT_PHYSICAL_TIER_0_HIDDEN: 'CommonBuffId' = 371242 + TRAIT_PRACTICE_MAKES_PERFECT_PHYSICAL_TIER_1_HIDDEN: 'CommonBuffId' = 371243 + TRAIT_PRACTICE_MAKES_PERFECT_PHYSICAL_TIER_2_HIDDEN: 'CommonBuffId' = 371244 + TRAIT_PRACTICE_MAKES_PERFECT_PHYSICAL_TIER_3_HIDDEN: 'CommonBuffId' = 371245 + TRAIT_PRACTICE_MAKES_PERFECT_PHYSICAL_TIER_4_HIDDEN: 'CommonBuffId' = 371246 + TRAIT_PRACTICE_MAKES_PERFECT_PRACTICE_SKILL_WHIM_HIDDEN: 'CommonBuffId' = 376449 + TRAIT_PRACTICE_MAKES_PERFECT_SOCIAL_TIER_0_HIDDEN: 'CommonBuffId' = 371248 + TRAIT_PRACTICE_MAKES_PERFECT_SOCIAL_TIER_1_HIDDEN: 'CommonBuffId' = 371249 + TRAIT_PRACTICE_MAKES_PERFECT_SOCIAL_TIER_2_HIDDEN: 'CommonBuffId' = 371250 + TRAIT_PRACTICE_MAKES_PERFECT_SOCIAL_TIER_3_HIDDEN: 'CommonBuffId' = 371251 + TRAIT_PRACTICE_MAKES_PERFECT_SOCIAL_TIER_4_HIDDEN: 'CommonBuffId' = 371252 + TRAIT_PRACTICE_MAKES_PERFECT_SO_BORING_BORED: 'CommonBuffId' = 370197 + TRAIT_PRACTICE_MAKES_PERFECT_WHIM_TRACKER_HIDDEN: 'CommonBuffId' = 372621 + TRAIT_PROFESSIONAL_SLACKER: 'CommonBuffId' = 308566 + TRAIT_PROPER: 'CommonBuffId' = 251987 + TRAIT_PROPER_CAREER_FIRED: 'CommonBuffId' = 252080 + TRAIT_PROPER_CAREER_MISSING_WORK: 'CommonBuffId' = 252082 + TRAIT_PROPER_CAREER_POOR_PERFORMANCE: 'CommonBuffId' = 252084 + TRAIT_PROPER_CAREER_PROMOTION: 'CommonBuffId' = 252083 + TRAIT_PROPER_CAREER_QUIT: 'CommonBuffId' = 252081 + TRAIT_PROPER_FORMAL_WEAR: 'CommonBuffId' = 252078 + TRAIT_PROPER_LOST_FIGHT: 'CommonBuffId' = 252292 + TRAIT_PROPER_WITNESSED_BEHAVIOR: 'CommonBuffId' = 252296 + TRAIT_PROPER_WON_FIGHT: 'CommonBuffId' = 252291 + TRAIT_QUICK_LEARNER: 'CommonBuffId' = 27106 + TRAIT_RANCHER: 'CommonBuffId' = 320972 + TRAIT_RANCHER_NEED_RANCH_INTERACTION_TIMER: 'CommonBuffId' = 320973 + TRAIT_RANCHER_RANCH_CHORES_EMBARASSED: 'CommonBuffId' = 320990 + TRAIT_RANCHER_RANCH_CHORES_HAPPY: 'CommonBuffId' = 320989 + TRAIT_RECYCLE_DISCIPLE: 'CommonBuffId' = 232714 + TRAIT_RECYCLE_DISCIPLE_CAUGHT_STEALING: 'CommonBuffId' = 232743 + TRAIT_RECYCLE_DISCIPLE_REQUIRED_CONTROLLER_HIDDEN: 'CommonBuffId' = 239443 + TRAIT_RELATABLE: 'CommonBuffId' = 282772 + TRAIT_RESPONSIBLE: 'CommonBuffId' = 329368 + TRAIT_REWARD_NEW_IN_TOWN_INSPIRED_EXPLORER: 'CommonBuffId' = 297770 + TRAIT_ROMANTIC: 'CommonBuffId' = 9302 + TRAIT_ROMANTICALLY_RESERVED: 'CommonBuffId' = 361648 + TRAIT_ROMANTICALLY_RESERVED_HIDDEN: 'CommonBuffId' = 361649 + TRAIT_ROMANTICALLY_RESERVED_HONORING_MYSELF: 'CommonBuffId' = 361972 + TRAIT_ROMANTICALLY_RESERVED_NEAR_ROMANCE_COOLDOWN_HIDDEN: 'CommonBuffId' = 370603 + TRAIT_ROMANTICALLY_RESERVED_ROMANTIC_YEARNING: 'CommonBuffId' = 361970 + TRAIT_ROMANTICALLY_RESERVED_UNWANTED_ADVANCES: 'CommonBuffId' = 361971 + TRAIT_ROMANTIC_CHARMED_BY_NATURE: 'CommonBuffId' = 107886 + TRAIT_ROMANTIC_LOVELORN: 'CommonBuffId' = 27518 + TRAIT_ROMANTIC_LOVELORN_HIDDEN: 'CommonBuffId' = 75034 + TRAIT_ROMANTIC_SAGE: 'CommonBuffId' = 378264 + TRAIT_SAVANT: 'CommonBuffId' = 39879 + TRAIT_SELDOM_SLEEPY: 'CommonBuffId' = 183028 + TRAIT_SELF_ABSORBED: 'CommonBuffId' = 317399 + TRAIT_SELF_ABSORBED_ATTENDING_ACTING_GIG: 'CommonBuffId' = 200009 + TRAIT_SELF_ABSORBED_FLATTERED: 'CommonBuffId' = 199776 + TRAIT_SELF_ABSORBED_FOR_ME: 'CommonBuffId' = 199779 + TRAIT_SELF_ABSORBED_GREAT_FRIENDS_I_HAVE: 'CommonBuffId' = 199778 + TRAIT_SELF_ABSORBED_HUNGRY_FOR_ATTENTION: 'CommonBuffId' = 199777 + TRAIT_SELF_ABSORBED_LACKING_ANONYMOUS_ATTENTION: 'CommonBuffId' = 199781 + TRAIT_SELF_ABSORBED_OUT_OF_SPOTLIGHT: 'CommonBuffId' = 199587 + TRAIT_SELF_ABSORBED_PICTURE_WORTHY: 'CommonBuffId' = 199714 + TRAIT_SELF_ABSORBED_POPULAR: 'CommonBuffId' = 199782 + TRAIT_SELF_ABSORBED_RECOGNIZED_ICON: 'CommonBuffId' = 199710 + TRAIT_SELF_ABSORBED_RESET_TIMER_NO_DEBUFF: 'CommonBuffId' = 203081 + TRAIT_SELF_ABSORBED_SIMSTA_FAMOUS: 'CommonBuffId' = 199783 + TRAIT_SELF_ABSORBED_SPOTLIGHT_READY: 'CommonBuffId' = 199729 + TRAIT_SELF_ASSURED: 'CommonBuffId' = 12652 + TRAIT_SINCERE: 'CommonBuffId' = 26904 + TRAIT_SLOB: 'CommonBuffId' = 12702 + TRAIT_SLOB_NATURAL_DIRT: 'CommonBuffId' = 108424 + TRAIT_SNOB: 'CommonBuffId' = 9622 + TRAIT_SNOB_NOT_ENOUGH_CULTURE: 'CommonBuffId' = 107828 + TRAIT_SNOB_UNITY: 'CommonBuffId' = 31905 + TRAIT_SNOB_UNITY_HIDDEN: 'CommonBuffId' = 74238 + TRAIT_SOCIALLY_AWKWARD: 'CommonBuffId' = 272886 + TRAIT_SOCIALLY_AWKWARD_HIDDEN_EXPRESS_NERVOUSNESS_AROUND_NEW_SIMS_COOLDOWN: 'CommonBuffId' = 295125 + TRAIT_SOCIALLY_AWKWARD_HIDDEN_ITS_OKAY_TO_BE_A_LITTLE_AWKWARD_COOLDOWN: 'CommonBuffId' = 272899 + TRAIT_SOCIALLY_AWKWARD_VISIBLE_BEFRIENDED_COWORKER: 'CommonBuffId' = 272901 + TRAIT_SOCIALLY_AWKWARD_VISIBLE_CENTER_OF_ATTENTION: 'CommonBuffId' = 272897 + TRAIT_SOCIALLY_AWKWARD_VISIBLE_COOLEST_KID_IN_SCHOOL: 'CommonBuffId' = 272903 + TRAIT_SOCIALLY_AWKWARD_VISIBLE_FEELING_ENCOURAGED: 'CommonBuffId' = 272896 + TRAIT_SOCIALLY_AWKWARD_VISIBLE_FEELING_OVERWHELMED: 'CommonBuffId' = 272893 + TRAIT_SOCIALLY_AWKWARD_VISIBLE_FEELING_UNDERSTOOD: 'CommonBuffId' = 272904 + TRAIT_SOCIALLY_AWKWARD_VISIBLE_INTIMIDATING_ENVIRONMENT: 'CommonBuffId' = 272895 + TRAIT_SOCIALLY_AWKWARD_VISIBLE_THAT_DID_NOT_GO_AS_PLANNED: 'CommonBuffId' = 272902 + TRAIT_SOCIALLY_AWKWARD_VISIBLE__WITH_MY_PEOPLE: 'CommonBuffId' = 272894 + TRAIT_SOCIALLY_GIFTED: 'CommonBuffId' = 29624 + TRAIT_SPECIES_CAT: 'CommonBuffId' = 144675 + TRAIT_SPECIES_DOG: 'CommonBuffId' = 131197 + TRAIT_SPECIES_EXTENDED_LARGE_DOG: 'CommonBuffId' = 173770 + TRAIT_SPECIES_EXTENDED_SMALL_DOG: 'CommonBuffId' = 173771 + TRAIT_SPEED_CLEANER: 'CommonBuffId' = 26620 + TRAIT_SPEED_READER: 'CommonBuffId' = 32627 + TRAIT_SQUEAMISH: 'CommonBuffId' = 102339 + TRAIT_SQUEAMISH_EWW_GROSS: 'CommonBuffId' = 102727 + TRAIT_SQUEAMISH_EWW_GROSS_FISHING: 'CommonBuffId' = 116275 + TRAIT_STEEL_BLADDER: 'CommonBuffId' = 26376 + TRAIT_SURVIVALIST_FRESH_INGREDIENTS: 'CommonBuffId' = 108879 + TRAIT_SURVIVALIST_PRIMITIVE_AWAKENING: 'CommonBuffId' = 108923 + TRAIT_SURVIVALIST_RUSTIC_COMFORT: 'CommonBuffId' = 108917 + TRAIT_SURVIVALIST_RUSTIC_COMFORT_NO_COMMODITY: 'CommonBuffId' = 116277 + TRAIT_SURVIVALIST_SIMPLE_SATISFACTION: 'CommonBuffId' = 108966 + TRAIT_SURVIVAL_INSTINCT: 'CommonBuffId' = 249918 + TRAIT_TEEN: 'CommonBuffId' = 34524 + TRAIT_THE_KNACK: 'CommonBuffId' = 99840 + TRAIT_TODDLER: 'CommonBuffId' = 141769 + TRAIT_TODDLER_ANGELIC: 'CommonBuffId' = 143170 + TRAIT_TODDLER_ANGELIC_EASYGOING: 'CommonBuffId' = 143251 + TRAIT_TODDLER_CHARMER: 'CommonBuffId' = 143177 + TRAIT_TODDLER_CHARMER_CHARMED: 'CommonBuffId' = 154709 + TRAIT_TODDLER_CHARMER_NEW_FRIENDS: 'CommonBuffId' = 154714 + TRAIT_TODDLER_CHARMER_WHERE_IS_EVERYONE: 'CommonBuffId' = 143271 + TRAIT_TODDLER_CLINGY: 'CommonBuffId' = 143171 + TRAIT_TODDLER_CLINGY_WHERES_MAMA_DADA: 'CommonBuffId' = 143284 + TRAIT_TODDLER_FUSSY: 'CommonBuffId' = 143172 + TRAIT_TODDLER_FUSSY_GOT_MY_WAY: 'CommonBuffId' = 154394 + TRAIT_TODDLER_FUSSY_LISTEN_TO_ME: 'CommonBuffId' = 154389 + TRAIT_TODDLER_FUSSY_OWWIE: 'CommonBuffId' = 154388 + TRAIT_TODDLER_FUSSY_TODDLER_ANGER: 'CommonBuffId' = 154408 + TRAIT_TODDLER_FUSSY_TODDLER_STRESS: 'CommonBuffId' = 154407 + TRAIT_TODDLER_FUSSY_UNDER_MY_THUMB: 'CommonBuffId' = 154392 + TRAIT_TODDLER_INDEPENDENT: 'CommonBuffId' = 143174 + TRAIT_TODDLER_INDEPENDENT_ON_MY_OWN: 'CommonBuffId' = 143347 + TRAIT_TODDLER_INQUISITIVE: 'CommonBuffId' = 143176 + TRAIT_TODDLER_INQUISITIVE_LEARNED_SOMETHING_NEW: 'CommonBuffId' = 154460 + TRAIT_TODDLER_INQUISITIVE_NEED_TO_LEARN: 'CommonBuffId' = 143348 + TRAIT_TODDLER_INQUISITIVE_NEED_TO_LEARN_LOOT_BUFF: 'CommonBuffId' = 157209 + TRAIT_TODDLER_PERSONALITY_AGGRESSIVE: 'CommonBuffId' = 306540 + TRAIT_TODDLER_PERSONALITY_AUDIO_LOVER: 'CommonBuffId' = 306541 + TRAIT_TODDLER_PERSONALITY_BOOK_LOVER: 'CommonBuffId' = 306550 + TRAIT_TODDLER_PERSONALITY_DESTRUCTIVE: 'CommonBuffId' = 306551 + TRAIT_TODDLER_PERSONALITY_GOOD_APPETITE: 'CommonBuffId' = 306553 + TRAIT_TODDLER_PERSONALITY_HATES_BED_TIME: 'CommonBuffId' = 306554 + TRAIT_TODDLER_PERSONALITY_HATES_CARRY: 'CommonBuffId' = 314339 + TRAIT_TODDLER_PERSONALITY_HEAVY_SLEEPER: 'CommonBuffId' = 313462 + TRAIT_TODDLER_PERSONALITY_LIGHT_SLEEPER: 'CommonBuffId' = 313463 + TRAIT_TODDLER_PERSONALITY_LOVES_CARRY: 'CommonBuffId' = 306544 + TRAIT_TODDLER_PERSONALITY_PICKY_EATER: 'CommonBuffId' = 313467 + TRAIT_TODDLER_PERSONALITY_SINGER: 'CommonBuffId' = 306549 + TRAIT_TODDLER_PERSONALITY_WATER_LOVER: 'CommonBuffId' = 305555 + TRAIT_TODDLER_SILLY: 'CommonBuffId' = 143175 + TRAIT_TODDLER_SILLY_BUTT_BUTT: 'CommonBuffId' = 154244 + TRAIT_TODDLER_SILLY_MADE_A_SILLY: 'CommonBuffId' = 156739 + TRAIT_TODDLER_SILLY_WHAGGA_WHAGGA: 'CommonBuffId' = 143290 + TRAIT_TODDLER_WILD: 'CommonBuffId' = 143173 + TRAIT_TODDLER_WILD_RUN_RUN_RUN: 'CommonBuffId' = 143296 + TRAIT_TODDLER_WILD_STUCK_INSIDE: 'CommonBuffId' = 154276 + TRAIT_TODDLER_WILD_WIND_IN_MY_HAIR: 'CommonBuffId' = 154275 + TRAIT_TOP_NOTCH_TODDLER: 'CommonBuffId' = 143164 + TRAIT_TOWN_MASCOT: 'CommonBuffId' = 249204 + TRAIT_TRUE_MASTER: 'CommonBuffId' = 156008 + TRAIT_UNCONTROLLED_EMOTION: 'CommonBuffId' = 160266 + TRAIT_UNFEELING: 'CommonBuffId' = 160955 + TRAIT_UNFLIRTY: 'CommonBuffId' = 132584 + TRAIT_UNFLIRTY_COMMITTED_CRASS_ACT_HIDDEN: 'CommonBuffId' = 133067 + TRAIT_UNFLIRTY_DEFROSTED_ACTOR_COLD_SHOULDER_OUTCOME_FAIL: 'CommonBuffId' = 132742 + TRAIT_UNFLIRTY_FLIRTY_DISASTER_ACTOR_OUTCOME_FAIL: 'CommonBuffId' = 132596 + TRAIT_UNFLIRTY_FLIRTY_RETARGET_OUTCOME_FAIL: 'CommonBuffId' = 132594 + TRAIT_UNFLIRTY_FOR_SHAME_TARGET_REPRIMAND_OUTCOME_SUCCESS: 'CommonBuffId' = 132739 + TRAIT_UNFLIRTY_HOLD_YOUR_HORSES_TARGET_OUTCOME_FAIL: 'CommonBuffId' = 132597 + TRAIT_UNFLIRTY_ICED_TARGET_COLD_SHOULDER_OUTCOME_SUCCESS: 'CommonBuffId' = 132741 + TRAIT_UNFLIRTY_MOVING_TOO_FAST: 'CommonBuffId' = 132595 + TRAIT_UNFLIRTY_SHAMING_BACKFIRE_ACTOR_REPRIMAND_OUTCOME_FAIL: 'CommonBuffId' = 132740 + TRAIT_UNFLIRTY_WITNESSED_CRASS_ACT: 'CommonBuffId' = 132593 + TRAIT_UNIVERSITY_HIGHER_EDUCATION: 'CommonBuffId' = 308613 + TRAIT_UNTROUBLED: 'CommonBuffId' = 283838 + TRAIT_VEGETARIAN_EATING_MEATY_FOOD: 'CommonBuffId' = 143538 + TRAIT_VEGETARIAN_EVANGELIZE_HIDDEN: 'CommonBuffId' = 152511 + TRAIT_VEGETARIAN_HAS_EATEN_HIDDEN: 'CommonBuffId' = 154206 + TRAIT_VEGETARIAN_HAS_EATEN_MEAT_SUBSTITUTE_HIDDEN: 'CommonBuffId' = 132738 + TRAIT_VEGETARIAN_SUPERIORITY_COMPLEX: 'CommonBuffId' = 132645 + TRAIT_VEGETARIAN_TAINTED_WITH_MEAT: 'CommonBuffId' = 132644 + TRAIT_VEGETARIAN_VEGETARIAN_APPROVED: 'CommonBuffId' = 132640 + TRAIT_WALK_STYLE_BATUU_STORMTROOPER: 'CommonBuffId' = 243235 + TRAIT_WALK_STYLE_BUTCH: 'CommonBuffId' = 29581 + TRAIT_WALK_STYLE_CELEBRITY: 'CommonBuffId' = 196761 + TRAIT_WALK_STYLE_CREEPY: 'CommonBuffId' = 155565 + TRAIT_WALK_STYLE_ENERGETIC: 'CommonBuffId' = 98759 + TRAIT_WALK_STYLE_FEMININE: 'CommonBuffId' = 29580 + TRAIT_WALK_STYLE_GOOFY: 'CommonBuffId' = 29579 + TRAIT_WALK_STYLE_PERKY: 'CommonBuffId' = 24602 + TRAIT_WALK_STYLE_SLEEPY: 'CommonBuffId' = 98758 + TRAIT_WALK_STYLE_SNOOTY: 'CommonBuffId' = 24600 + TRAIT_WALK_STYLE_SWAGGER: 'CommonBuffId' = 24601 + TRAIT_WEATHER_PREFERENCE_LOVES_RAIN: 'CommonBuffId' = 189225 + TRAIT_WEATHER_PREFERENCE_LOVES_SNOW: 'CommonBuffId' = 189232 + TRAIT_WISE: 'CommonBuffId' = 341159 + TRAIT_WITH_MY_FRIENDS: 'CommonBuffId' = 125555 + TRAIT_WORLDLY_KNOWLEDGE: 'CommonBuffId' = 249838 + TRAIT_WORLDLY_KNOWLEDGE_LOCAL_DELICACY: 'CommonBuffId' = 249957 + TRAIT_WORLDLY_KNOWLEDGE_NOTEWORTHY_NEGOTIATION: 'CommonBuffId' = 249840 + TRAIT_YOUNG_ADULT: 'CommonBuffId' = 34525 + TRASH_UPDATE_FLIES_FOOD_NOT_FRIENDS: 'CommonBuffId' = 232255 + TRASH_UPDATE_FRUSTRATION_INFESTATION: 'CommonBuffId' = 232257 + TRASH_UPDATE_NEAT_ON_LOT: 'CommonBuffId' = 238406 + TRASH_UPDATE_ROACH_WRANGLER: 'CommonBuffId' = 232256 + TRASH_UPDATE_SLOB_LAZY_ON_LOT: 'CommonBuffId' = 238844 + TRASH_UPDATE_SWATTED: 'CommonBuffId' = 232252 + TRASH_UPDATE_WASTE_MANAGER_AUTONOMY_MOD_CONSULT: 'CommonBuffId' = 235103 + TRASH_UPDATE_WASTE_MANAGER_AUTONOMY_MOD_LEAVE: 'CommonBuffId' = 235111 + TRASH_UPDATE_WASTE_MANAGER_AUTONOMY_MOD_PICK_UP_TRASH: 'CommonBuffId' = 235095 + TRASH_UPDATE_WASTE_MANAGER_AUTONOMY_MOD_PLAYER: 'CommonBuffId' = 235812 + TRASH_UPDATE_WASTE_MANAGER_AUTONOMY_MOD_PLAYER_END: 'CommonBuffId' = 239756 + TRASH_UPDATE_WASTE_MANAGER_AUTONOMY_MOD_PLAYER_TAKE_PAYMENT: 'CommonBuffId' = 235944 + TREASURED_TALE: 'CommonBuffId' = 108017 + TREASURED_TALE_GREAT_STORYTELLER: 'CommonBuffId' = 109751 + TREEHOUSE_MESS_AROUND_GOT_SOME_FRESH_AIR: 'CommonBuffId' = 323565 + TREEHOUSE_MESS_AROUND_SPLINTERS: 'CommonBuffId' = 323603 + TREEHOUSE_PLAY_ON_DURATION: 'CommonBuffId' = 315735 + TREEHOUSE_TREEHOUSE_ADVENTURES: 'CommonBuffId' = 308591 + TREEHOUSE_WOOHOO_GOT_SOME_FRESH_AIR: 'CommonBuffId' = 318687 + TREEHOUSE_WOOHOO_SPLINTERS: 'CommonBuffId' = 318686 + TRIVIA_BOX_GAME_END: 'CommonBuffId' = 365494 + TRIVIA_BOX_GAME_END_ABORT: 'CommonBuffId' = 383577 + TRIVIA_BOX_GUESS_TRACKING_CRY: 'CommonBuffId' = 365307 + TRIVIA_BOX_GUESS_TRACKING_MIND_BLOWN: 'CommonBuffId' = 365308 + TRIVIA_BOX_GUESS_TRACKING_SCREAM: 'CommonBuffId' = 358497 + TRIVIA_BOX_GUESS_TRACKING_SURPRISED: 'CommonBuffId' = 358498 + TRIVIA_BOX_GUESS_TRACKING_SWEAT_SMILE: 'CommonBuffId' = 358496 + TRIVIA_BOX_GUESS_TRACKING_THINKING: 'CommonBuffId' = 365309 + TRIVIA_BOX_GUESS_TRACKING_VOMIT: 'CommonBuffId' = 365310 + TRIVIA_BOX_GUESS_TRACKING_ZIPPER_MOUTH: 'CommonBuffId' = 365311 + TRIVIA_BOX_THUMBS_UP_HAPPY: 'CommonBuffId' = 366015 + TRIVIA_BOX_THUMBS_UP_TENSE: 'CommonBuffId' = 366016 + TRIVIA_BOX_WOO_WHO_ANSWER_TRACKER: 'CommonBuffId' = 363109 + TRIVIA_BOX_WOO_WHO_FLIRTY: 'CommonBuffId' = 366014 + TRIVIA_BOX_WOO_WHO_QUESTION_ASKER: 'CommonBuffId' = 363165 + TUCK_IN_COOLDOWN: 'CommonBuffId' = 168470 + TUTORIAL_ADD_BOOK: 'CommonBuffId' = 100486 + TUTORIAL_ADD_SATISFACTION_POINTS: 'CommonBuffId' = 100688 + TUTORIAL_HUNGER: 'CommonBuffId' = 99745 + TUTORIAL_INSPIRED: 'CommonBuffId' = 99216 + TUTORIAL_MOTIVES_HYGIENE_GRUNGY: 'CommonBuffId' = 99387 + TUTORIAL_REMOVE_INSPIRED: 'CommonBuffId' = 100159 + TV_BE_TWEEN_WATCHED: 'CommonBuffId' = 138243 + TYAE_BABY_FEED_BITTEN: 'CommonBuffId' = 275495 + TYAE_BABY_FEED_BITTEN_VAMPIRE_BABY: 'CommonBuffId' = 275496 + TYAE_BABY_FEED_SPIT_UP_ON: 'CommonBuffId' = 275498 + UMBRELLA_ADD_UMBRELLA: 'CommonBuffId' = 190771 + UMBRELLA_BROKEN: 'CommonBuffId' = 186660 + UMBRELLA_CLOSE: 'CommonBuffId' = 185734 + UMBRELLA_CLOSE_1_HOUR: 'CommonBuffId' = 191230 + UMBRELLA_OPEN: 'CommonBuffId' = 185715 + UMBRELLA_STORM: 'CommonBuffId' = 186643 + UNENLIGHTENING_LECTURE: 'CommonBuffId' = 118516 + UNFEELING_RILE_UP_ANGRY: 'CommonBuffId' = 160965 + UNFEELING_RILE_UP_EMBARRASSED: 'CommonBuffId' = 160967 + UNFEELING_RILE_UP_SAD: 'CommonBuffId' = 160968 + UNFEELING_RILE_UP_STRESSED: 'CommonBuffId' = 160969 + UNIT_RATING_MAINTENANCE_DAY_COOLDOWN: 'CommonBuffId' = 360952 + UNIVERSITY_AFTER_CLASS_GO_HOME: 'CommonBuffId' = 230556 + UNIVERSITY_CHEATING_CAUGHT: 'CommonBuffId' = 223206 + UNIVERSITY_CHEATING_CAUGHT_GOOD_TRAITS: 'CommonBuffId' = 223207 + UNIVERSITY_CHEATING_CAUGHT_HIDDEN: 'CommonBuffId' = 228382 + UNIVERSITY_CHEATING_SUCCESS: 'CommonBuffId' = 223209 + UNIVERSITY_CLASSROOM_SHELL_A_TASTE_OF_HIGHER_LEARNING: 'CommonBuffId' = 220314 + UNIVERSITY_CLASSROOM_SHELL_INSPIRED_QUOTE: 'CommonBuffId' = 220306 + UNIVERSITY_CLASSROOM_SHELL_TUTORIFIC: 'CommonBuffId' = 220307 + UNIVERSITY_CLASSROOM_SHELL_VISIT_OFFICE_HOURS_COOLDOWN_A: 'CommonBuffId' = 222234 + UNIVERSITY_CLASSROOM_SHELL_VISIT_OFFICE_HOURS_COOLDOWN_B: 'CommonBuffId' = 222239 + UNIVERSITY_CLASSROOM_SHELL_VISIT_OFFICE_HOURS_COOLDOWN_C: 'CommonBuffId' = 222240 + UNIVERSITY_CLASSROOM_SHELL_VISIT_OFFICE_HOURS_COOLDOWN_D: 'CommonBuffId' = 222241 + UNIVERSITY_EMAIL_PRFOESSOR_COOLDOWN_PHONE: 'CommonBuffId' = 224038 + UNIVERSITY_EMAIL_PROFESSOR_COOLDOWNS_A: 'CommonBuffId' = 224039 + UNIVERSITY_EMAIL_PROFESSOR_COOLDOWNS_B: 'CommonBuffId' = 224040 + UNIVERSITY_EMAIL_PROFESSOR_COOLDOWNS_C: 'CommonBuffId' = 224041 + UNIVERSITY_EMAIL_PROFESSOR_COOLDOWNS_D: 'CommonBuffId' = 224042 + UNIVERSITY_ENROLLMENT_ACCEPTANCE_HIGH: 'CommonBuffId' = 229214 + UNIVERSITY_ENROLLMENT_ACCEPTANCE_LOW: 'CommonBuffId' = 229212 + UNIVERSITY_ENROLLMENT_ACCEPTANCE_MEDIUM: 'CommonBuffId' = 229213 + UNIVERSITY_ENROLLMENT_CONFIDENCE_LOW: 'CommonBuffId' = 222411 + UNIVERSITY_ENROLLMENT_CONNECTIONS_FAILURE: 'CommonBuffId' = 219815 + UNIVERSITY_ENROLLMENT_CONNECTIONS_FAILURE_ARTS: 'CommonBuffId' = 227528 + UNIVERSITY_ENROLLMENT_CONNECTIONS_FAILURE_SCIENCE: 'CommonBuffId' = 227529 + UNIVERSITY_ENROLLMENT_CONNECTIONS_SUCCESS: 'CommonBuffId' = 219814 + UNIVERSITY_ENROLLMENT_CONNECTIONS_SUCCESS_ARTS: 'CommonBuffId' = 227525 + UNIVERSITY_ENROLLMENT_CONNECTIONS_SUCCESS_SCIENCE: 'CommonBuffId' = 227526 + UNIVERSITY_ENROLLMENT_DONATE_FAILURE: 'CommonBuffId' = 219817 + UNIVERSITY_ENROLLMENT_DONATE_SUCCESS: 'CommonBuffId' = 219816 + UNIVERSITY_ENROLLMENT_FIRST_UNIVERSITY_MEMORY: 'CommonBuffId' = 220046 + UNIVERSITY_ENROLLMENT_FLAUNT_FAME_FAILURE: 'CommonBuffId' = 219819 + UNIVERSITY_ENROLLMENT_FLAUNT_FAME_SUCCESS: 'CommonBuffId' = 219818 + UNIVERSITY_ENROLLMENT_STRESS_HIGH: 'CommonBuffId' = 222410 + UNIVERSITY_ENROLLMENT_STRESS_NORMAL: 'CommonBuffId' = 222357 + UNIVERSITY_FINAL_EXAM_PRACTICE_PRESENT_TRACKER: 'CommonBuffId' = 229023 + UNIVERSITY_FINAL_EXAM_STRESS: 'CommonBuffId' = 224028 + UNIVERSITY_FINAL_EXAM_UNCOMFORTABLE: 'CommonBuffId' = 229431 + UNIVERSITY_FINAL_EXAM_WENT_TO_CLASS: 'CommonBuffId' = 230493 + UNIVERSITY_GRADUATION_CAP: 'CommonBuffId' = 229460 + UNIVERSITY_GRADUATION_GRADUATED: 'CommonBuffId' = 228536 + UNIVERSITY_HIDDEN_FINAL_EXAM_DONE_A: 'CommonBuffId' = 230446 + UNIVERSITY_HIDDEN_FINAL_EXAM_DONE_B: 'CommonBuffId' = 230447 + UNIVERSITY_HIDDEN_FINAL_EXAM_DONE_C: 'CommonBuffId' = 230448 + UNIVERSITY_HIDDEN_FINAL_EXAM_DONE_D: 'CommonBuffId' = 230449 + UNIVERSITY_RIVALRY_CAUGHT_RED_HANDED: 'CommonBuffId' = 224643 + UNIVERSITY_RIVALRY_CAUGHT_RED_HANDED_ANGRY: 'CommonBuffId' = 226574 + UNIVERSITY_RIVALRY_CAUGHT_RED_HANDED_SAD: 'CommonBuffId' = 226575 + UNIVERSITY_RIVALRY_PRIDE_TARNISHED_SAD: 'CommonBuffId' = 226624 + UNIVERSITY_RIVALRY_ROLES_LEAVE: 'CommonBuffId' = 226698 + UNIVERSITY_RIVALRY_ROLES_PRANK: 'CommonBuffId' = 226697 + UNIVERSITY_RIVALRY_SCHOOL_PRIDE_LEVEL_1: 'CommonBuffId' = 226452 + UNIVERSITY_RIVALRY_SCHOOL_PRIDE_LEVEL_2: 'CommonBuffId' = 226454 + UNIVERSITY_RIVARLY_REMINDED_OF_SUPERIORITY_CONFIDENT: 'CommonBuffId' = 226593 + UNIVERSITY_RIVARLY_REMINDED_OF_SUPERIORITY_PLAYFUL: 'CommonBuffId' = 226592 + UNIVERSITY_SCHOLARSHIPS_FULL_RIDE: 'CommonBuffId' = 226282 + UNIVERSITY_SCHOLARSHIPS_PICKER_RESULT_CHECK: 'CommonBuffId' = 227898 + UNIVERSITY_SCHOLARSHIPS_SCHOLARSHIP_SURE: 'CommonBuffId' = 226277 + UNIVERSITY_SCHOLARSHIPS_SIZEABLE_SCHOLARSHIP: 'CommonBuffId' = 226283 + UNIVERSITY_SIGNING_BONUS_COOLDOWN: 'CommonBuffId' = 227984 + UNIVERSITY_STUDYING: 'CommonBuffId' = 223950 + UNIVERSITY_STUDYING_FEELING_STUDIOUS: 'CommonBuffId' = 223840 + UNIVERSITY_STUDYING_LOSING_FOCUS: 'CommonBuffId' = 223842 + UNIVERSITY_STUDYING_TRULY_CRAMMED: 'CommonBuffId' = 223843 + UNIVERSITY_STUDYING_WELL_PREPARED: 'CommonBuffId' = 223841 + UNIVERSITY_TERM_PRESENTATION_FEDBACK: 'CommonBuffId' = 225971 + UNIVERSITY_TERM_PRESENTATION_REACTION_HIGH: 'CommonBuffId' = 229324 + UNIVERSITY_TERM_PRESENTATION_REACTION_LOW: 'CommonBuffId' = 229322 + UNIVERSITY_TERM_PRESENTATION_REACTION_MED: 'CommonBuffId' = 229323 + UNIVERSITY_WITHDRAW_COOLDOWN: 'CommonBuffId' = 228136 + UNLEASH: 'CommonBuffId' = 178466 + UNWANTED_PROPOSAL: 'CommonBuffId' = 98093 + VACUUM_CLEANER_ALL_MESSES_TERMINATED: 'CommonBuffId' = 257419 + VACUUM_CLEANER_AUTONOMOUS_COOLDOWN: 'CommonBuffId' = 258689 + VACUUM_CLEANER_NO_DUST_LEFT_BEHIND: 'CommonBuffId' = 256898 + VACUUM_CLEANER_VAPORIZING_PULSE: 'CommonBuffId' = 258473 + VACUUM_CLEANER_WHAT_CANT_BE_VACUUMED: 'CommonBuffId' = 257797 + VAMPIRES_MOTIVES_ALL_MOTIVES_HIGH: 'CommonBuffId' = 155738 + VAMPIRES_MOTIVES_ALL_MOTIVES_PRETTY_HIGH: 'CommonBuffId' = 155739 + VAMPIRES_MOTIVES_DISPEL_GREEDY_NEEDS: 'CommonBuffId' = 182712 + VAMPIRES_PERSONA_POWERS_POTENT_POWER_LEVEL1: 'CommonBuffId' = 153431 + VAMPIRES_PERSONA_POWERS_POTENT_POWER_LEVEL2: 'CommonBuffId' = 153432 + VAMPIRES_PERSONA_POWERS_POTENT_POWER_LEVEL3: 'CommonBuffId' = 153433 + VAMPIRES_PERSONA_POWERS_VAMPIRIC_STRENGTH_LEVEL1: 'CommonBuffId' = 154687 + VAMPIRES_PERSONA_POWERS_VAMPIRIC_STRENGTH_LEVEL2: 'CommonBuffId' = 154688 + VAMPIRES_PERSONA_POWERS_VAMPIRIC_STRENGTH_LEVEL3: 'CommonBuffId' = 154686 + VAMPIRE_BAT_MESS_AROUND: 'CommonBuffId' = 156106 + VAMPIRE_BAT_WOOHOO: 'CommonBuffId' = 152748 + VAMPIRE_BURNED_BY_SUN: 'CommonBuffId' = 151450 + VAMPIRE_BURNED_BY_SUN_GHOST: 'CommonBuffId' = 153337 + VAMPIRE_BURNED_BY_SUN_GHOST_RESISTANCE_SOLIS_LEVEL1: 'CommonBuffId' = 155476 + VAMPIRE_BURNED_BY_SUN_GHOST_RESISTANCE_SOLIS_LEVEL2: 'CommonBuffId' = 155477 + VAMPIRE_BURNED_BY_SUN_GHOST_WEAKNESS_SUNLIGHT_LEVEL1: 'CommonBuffId' = 155478 + VAMPIRE_BURNED_BY_SUN_GHOST_WEAKNESS_SUNLIGHT_LEVEL2: 'CommonBuffId' = 155479 + VAMPIRE_BURNED_BY_SUN_GHOST_WEAKNESS_SUNLIGHT_LEVEL3: 'CommonBuffId' = 155480 + VAMPIRE_BURNED_BY_SUN_RESISTANCE_SOLIS_LEVEL1: 'CommonBuffId' = 151923 + VAMPIRE_BURNED_BY_SUN_RESISTANCE_SOLIS_LEVEL2: 'CommonBuffId' = 151924 + VAMPIRE_BURNED_BY_SUN_WEAKNESS_SUNLIGHT_LEVEL1: 'CommonBuffId' = 152506 + VAMPIRE_BURNED_BY_SUN_WEAKNESS_SUNLIGHT_LEVEL2: 'CommonBuffId' = 152507 + VAMPIRE_BURNED_BY_SUN_WEAKNESS_SUNLIGHT_LEVEL3: 'CommonBuffId' = 152505 + VAMPIRE_CHANCE_OF_VAMPIRE: 'CommonBuffId' = 155855 + VAMPIRE_CREATION_APPETITE_LOST: 'CommonBuffId' = 149428 + VAMPIRE_CREATION_DISGUSTED_BY_FOOD: 'CommonBuffId' = 149427 + VAMPIRE_CREATION_REACTION_COOLDOWN: 'CommonBuffId' = 156256 + VAMPIRE_CREATION_STRANGELY_HUNGRY: 'CommonBuffId' = 149423 + VAMPIRE_CREATION_STRANGE_THIRST: 'CommonBuffId' = 149536 + VAMPIRE_CURED_A_FRIEND: 'CommonBuffId' = 151512 + VAMPIRE_CURED_A_VAMPIRE: 'CommonBuffId' = 150158 + VAMPIRE_DARK_MEDITATION: 'CommonBuffId' = 155654 + VAMPIRE_DAY_TIME: 'CommonBuffId' = 151171 + VAMPIRE_DEFEATED_A_HUNTER: 'CommonBuffId' = 150160 + VAMPIRE_DONT_EAT: 'CommonBuffId' = 191752 + VAMPIRE_DRINK_IN_PROGRESS: 'CommonBuffId' = 151090 + VAMPIRE_DYING_FROM_SUN: 'CommonBuffId' = 151451 + VAMPIRE_DYING_FROM_SUN_RESISTANCE_SOLIS_LEVEL1: 'CommonBuffId' = 151910 + VAMPIRE_DYING_FROM_SUN_RESISTANCE_SOLIS_LEVEL2: 'CommonBuffId' = 151911 + VAMPIRE_DYING_FROM_SUN_WEAKNESS_SUNLIGHT_LEVEL1: 'CommonBuffId' = 152503 + VAMPIRE_DYING_FROM_SUN_WEAKNESS_SUNLIGHT_LEVEL2: 'CommonBuffId' = 152504 + VAMPIRE_DYING_FROM_SUN_WEAKNESS_SUNLIGHT_LEVEL3: 'CommonBuffId' = 152502 + VAMPIRE_HIDDEN_DRAIN_LIFE_SPIRIT_TARGET: 'CommonBuffId' = 151920 + VAMPIRE_HIDDEN_DRINK_DEEPLY_TARGET: 'CommonBuffId' = 151919 + VAMPIRE_HIDDEN_FAVOR_VAMPIRE_SOCIALS: 'CommonBuffId' = 154179 + VAMPIRE_INVITES_VAMPIRE_CREATION_NORMIE: 'CommonBuffId' = 152982 + VAMPIRE_INVITES_VAMPIRE_CREATION_TARGET: 'CommonBuffId' = 152760 + VAMPIRE_INVITES_VAMPIRE_CREATION_VAMPIRE_OFFER: 'CommonBuffId' = 152442 + VAMPIRE_IN_SUN: 'CommonBuffId' = 151170 + VAMPIRE_IS_VAMPIRE: 'CommonBuffId' = 149543 + VAMPIRE_MENTOR_TIMEOUT: 'CommonBuffId' = 156600 + VAMPIRE_MIND_POWERS_DISPEL: 'CommonBuffId' = 156589 + VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_ANGRY_1: 'CommonBuffId' = 150605 + VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_ANGRY_2: 'CommonBuffId' = 150606 + VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_ANGRY_3: 'CommonBuffId' = 150604 + VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_BORED_1: 'CommonBuffId' = 150611 + VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_BORED_2: 'CommonBuffId' = 150612 + VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_BORED_3: 'CommonBuffId' = 150610 + VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_CONFIDENT_1: 'CommonBuffId' = 150617 + VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_CONFIDENT_2: 'CommonBuffId' = 150618 + VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_CONFIDENT_3: 'CommonBuffId' = 150616 + VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_DAZED_1: 'CommonBuffId' = 150623 + VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_DAZED_2: 'CommonBuffId' = 150624 + VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_DAZED_3: 'CommonBuffId' = 150622 + VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_EMBARRASSED_1: 'CommonBuffId' = 150641 + VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_EMBARRASSED_2: 'CommonBuffId' = 150640 + VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_EMBARRASSED_3: 'CommonBuffId' = 150638 + VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_ENERGIZED_1: 'CommonBuffId' = 150634 + VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_ENERGIZED_2: 'CommonBuffId' = 150635 + VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_ENERGIZED_3: 'CommonBuffId' = 150633 + VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_FLIRTY_1: 'CommonBuffId' = 150586 + VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_FLIRTY_2: 'CommonBuffId' = 150587 + VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_FLIRTY_3: 'CommonBuffId' = 150585 + VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_FOCUSED_1: 'CommonBuffId' = 150592 + VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_FOCUSED_2: 'CommonBuffId' = 150593 + VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_FOCUSED_3: 'CommonBuffId' = 150591 + VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_HAPPY_1: 'CommonBuffId' = 150570 + VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_HAPPY_2: 'CommonBuffId' = 150583 + VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_HAPPY_3: 'CommonBuffId' = 150582 + VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_INSPIRED_1: 'CommonBuffId' = 150599 + VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_INSPIRED_2: 'CommonBuffId' = 150600 + VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_INSPIRED_3: 'CommonBuffId' = 150598 + VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_PLAYFUL_1: 'CommonBuffId' = 150649 + VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_PLAYFUL_2: 'CommonBuffId' = 150650 + VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_PLAYFUL_3: 'CommonBuffId' = 150648 + VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_SAD_1: 'CommonBuffId' = 150663 + VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_SAD_2: 'CommonBuffId' = 150664 + VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_SAD_3: 'CommonBuffId' = 150662 + VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_STRESSED_1: 'CommonBuffId' = 150666 + VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_STRESSED_2: 'CommonBuffId' = 150667 + VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_STRESSED_3: 'CommonBuffId' = 150665 + VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_UNCOMFORTABLE_1: 'CommonBuffId' = 150669 + VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_UNCOMFORTABLE_2: 'CommonBuffId' = 150670 + VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_UNCOMFORTABLE_3: 'CommonBuffId' = 150668 + VAMPIRE_MIND_POWERS_HALLUCINATE: 'CommonBuffId' = 150755 + VAMPIRE_MORTAL_MELANCHOLY: 'CommonBuffId' = 150162 + VAMPIRE_NON_VAMPIRE_EATS_PLASMA_FRUIT: 'CommonBuffId' = 153397 + VAMPIRE_NON_VAMPIRE_VAMPIRE_RESISTANCE_COCKTAIL: 'CommonBuffId' = 155487 + VAMPIRE_NPC_ENABLE_VAMPIRE_ROUTING: 'CommonBuffId' = 155269 + VAMPIRE_PLASMA_FRUIT_SALAD: 'CommonBuffId' = 156011 + VAMPIRE_RAGE_OUT: 'CommonBuffId' = 150063 + VAMPIRE_RECENTLY_BITTEN: 'CommonBuffId' = 150749 + VAMPIRE_RECENTLY_BITTEN_STRENGTH2: 'CommonBuffId' = 151763 + VAMPIRE_RECENTLY_BITTEN_STRENGTH3: 'CommonBuffId' = 151764 + VAMPIRE_RECENTLY_BITTEN_WITH_PERMISSION: 'CommonBuffId' = 156797 + VAMPIRE_RECENTLY_DRANK: 'CommonBuffId' = 150748 + VAMPIRE_RECENTLY_DRANK_STRENGTH2: 'CommonBuffId' = 151775 + VAMPIRE_RESEARCH_TOO_EASY: 'CommonBuffId' = 153826 + VAMPIRE_RESISTANCE_COCKTAIL_HIDDEN: 'CommonBuffId' = 156615 + VAMPIRE_SHOW_OFF_POWERS_ACTOR_HIDDEN: 'CommonBuffId' = 152822 + VAMPIRE_SLAYING_FOILED: 'CommonBuffId' = 150159 + VAMPIRE_SLEPT_LIKE_THE_UNDEAD: 'CommonBuffId' = 150163 + VAMPIRE_SPIRIT_POWERS_BAT_ENABLED: 'CommonBuffId' = 152520 + VAMPIRE_SPIRIT_POWERS_MIST_ENABLED: 'CommonBuffId' = 152521 + VAMPIRE_SPIRIT_POWERS_RESTORE_LIFE_SPIRIT: 'CommonBuffId' = 152829 + VAMPIRE_SPIRIT_POWERS_VAMPIRE_RUN_ENABLED: 'CommonBuffId' = 152621 + VAMPIRE_SUNLIGHT_RESISTANCE_SOLIS_LEVEL3: 'CommonBuffId' = 155245 + VAMPIRE_SUNLIGHT_REVERSAL: 'CommonBuffId' = 155561 + VAMPIRE_SUNLIGHT_REVERSAL_COCKTAIL: 'CommonBuffId' = 155530 + VAMPIRE_SUNLIGHT_REVERSAL_RESISTANCE_SOLIS_LEVEL1: 'CommonBuffId' = 155598 + VAMPIRE_SUNLIGHT_REVERSAL_RESISTANCE_SOLIS_LEVEL2: 'CommonBuffId' = 155599 + VAMPIRE_SUNLIGHT_REVERSAL_RESISTANCE_SOLIS_LEVEL3: 'CommonBuffId' = 155774 + VAMPIRE_SUNLIGHT_REVERSAL_WEAKNESS_SUNLIGHT_LEVEL1: 'CommonBuffId' = 155600 + VAMPIRE_SUNLIGHT_REVERSAL_WEAKNESS_SUNLIGHT_LEVEL2: 'CommonBuffId' = 155601 + VAMPIRE_SUNLIGHT_REVERSAL_WEAKNESS_SUNLIGHT_LEVEL3: 'CommonBuffId' = 155602 + VAMPIRE_TASTY_SIM: 'CommonBuffId' = 151570 + VAMPIRE_UNWILLING_SNACK: 'CommonBuffId' = 154327 + VAMPIRE_VAMPIRE_NO_MORE: 'CommonBuffId' = 150161 + VAMPIRE_VAMPIRIC_SPAR_GOOD_PRACTICE_DUEL: 'CommonBuffId' = 154309 + VAMPIRE_WEAKENED_FROM_FIGHT: 'CommonBuffId' = 151107 + VAMPIRE_WEAKNESSES_DAY_TIME_LEVEL1: 'CommonBuffId' = 152545 + VAMPIRE_WEAKNESSES_DAY_TIME_LEVEL2: 'CommonBuffId' = 152546 + VAMPIRE_WEAKNESSES_DAY_TIME_LEVEL3: 'CommonBuffId' = 152544 + VAMPIRE_WEAKNESSES_ETERNAL_SADNESS: 'CommonBuffId' = 152411 + VAMPIRE_WEAKNESSES_ETERNAL_SADNESS_HIDDEN: 'CommonBuffId' = 152410 + VAMPIRE_WEAKNESSES_INEFFICIENT_DRINKER: 'CommonBuffId' = 152484 + VAMPIRE_WEAKNESSES_INSATIABLE_THIRST: 'CommonBuffId' = 152609 + VAMPIRE_WEAKNESSES_SUNLIGHT_LEVEL1: 'CommonBuffId' = 153438 + VAMPIRE_WEAKNESSES_SUNLIGHT_LEVEL2: 'CommonBuffId' = 153439 + VAMPIRE_WEAKNESSES_SUNLIGHT_LEVEL3: 'CommonBuffId' = 153437 + VAMPIRE_WEAKNESSES_UNCONTROLLABLE_HISSING: 'CommonBuffId' = 152539 + VAMPIRE_WEAKNESSES_UNCONTROLLABLE_HISSING_HIDDEN: 'CommonBuffId' = 152596 + VAMPIRE_WEAKNESSES_UNPLEASANT_AURA: 'CommonBuffId' = 152808 + VAMPIRE_WEAKNESSES_VAMPIRE_WITH_A_CONSCIENCE_GUILTY_DRINKER: 'CommonBuffId' = 152618 + VAMPIRE_WEAKNESSES_WITHERED_STOMACH: 'CommonBuffId' = 152241 + VAULT_BUFFS_FOCUSED_EVERYTHING_BURNS: 'CommonBuffId' = 193491 + VAULT_BUFFS_HIDDEN_BREAKING_INTO_UNOWNED_SAFE: 'CommonBuffId' = 200889 + VAULT_BUFFS_HIDDEN_IS_MAKING_IT_RAIN: 'CommonBuffId' = 201908 + VAULT_BUFFS_HIDDEN_MONEY_PHONE_COOLDOWN: 'CommonBuffId' = 202366 + VAULT_BUFFS_MADE_IT_POUR_CONFIDENT: 'CommonBuffId' = 197950 + VAULT_BUFFS_MADE_IT_RAIN_PLAYFUL: 'CommonBuffId' = 193489 + VAULT_BUFFS_MADE_IT_TRICKLE_PLAYFUL: 'CommonBuffId' = 197949 + VAULT_BUFFS_PLAYFUL_MONEY_PHONE: 'CommonBuffId' = 201006 + VAULT_BUFFS_SAD_WATCH_THE_WORLD_BURN: 'CommonBuffId' = 193490 + VAULT_BUFFS_VAULT_DOOR_ANGRY_THIEF_RAGE: 'CommonBuffId' = 193486 + VAULT_BUFFS_VAULT_DOOR_CONFIDENT_MASTER_THIEF: 'CommonBuffId' = 193488 + VAULT_BUFFS_VAULT_DOOR_SAD_AWFUL_THIEF: 'CommonBuffId' = 193487 + VAULT_BUFFS_WALK_IN_SAFE_CONFIDENT_MASTER_ESCAPE_ARTIST: 'CommonBuffId' = 202081 + VAULT_BUFFS_WALK_IN_SAFE_EXCITED_IM_RICH: 'CommonBuffId' = 193483 + VAULT_BUFFS_WALK_IN_SAFE_FLIRTY_MONEY_LOVE: 'CommonBuffId' = 193482 + VAULT_BUFFS_WALK_IN_SAFE_FOCUSED_MONEY_DREAMS: 'CommonBuffId' = 193484 + VAULT_BUFFS_WALK_IN_SAFE_PLAYFUL_FUN_MONEY: 'CommonBuffId' = 193475 + VAULT_BUFFS_WALK_IN_SAFE_STRESSED_TRAPPED_IN_SAFE: 'CommonBuffId' = 202080 + VEHICLE_BIKE_FRESH_AIR: 'CommonBuffId' = 227649 + VEHICLE_BIKE_GREEN_TRAVELER: 'CommonBuffId' = 227715 + VEHICLE_BIKE_RIDING: 'CommonBuffId' = 211196 + VEHICLE_BIKE_RIDING_KIDS_BIKE_BIKING_IS_HARD: 'CommonBuffId' = 305934 + VEHICLE_BIKE_RIDING_KIDS_BIKE_CANT_CONCENTRATE: 'CommonBuffId' = 306734 + VEHICLE_BIKE_RIDING_KIDS_BIKE_CHILD_CAN_NOW_RIDE: 'CommonBuffId' = 305932 + VEHICLE_BIKE_RIDING_KIDS_BIKE_HIDDEN_HONK_HORN: 'CommonBuffId' = 313615 + VEHICLE_BIKE_RIDING_KIDS_BIKE_HIDDEN_HORN_COOLDOWN: 'CommonBuffId' = 313632 + VEHICLE_BIKE_RIDING_KIDS_BIKE_HIDDEN_IS_MENTORED: 'CommonBuffId' = 332946 + VEHICLE_BIKE_RIDING_KIDS_BIKE_HIDDEN_PRACTICE: 'CommonBuffId' = 313614 + VEHICLE_BIKE_RIDING_KIDS_BIKE_HIDDEN_PRACTICE_COOLDOWN: 'CommonBuffId' = 313634 + VEHICLE_BIKE_RIDING_KIDS_BIKE_HIDDEN_TRICK: 'CommonBuffId' = 313626 + VEHICLE_BIKE_RIDING_KIDS_BIKE_HIDDEN_TRICK_COOLDOWN: 'CommonBuffId' = 313633 + VEHICLE_BIKE_RIDING_KIDS_BIKE_MENTOR: 'CommonBuffId' = 313336 + VEHICLE_BIKE_RIDING_KIDS_BIKE_NEVER_GET_BETTER: 'CommonBuffId' = 305933 + VEHICLE_BIKE_RIDING_KIDS_BIKE_SICK_TRICKS: 'CommonBuffId' = 306664 + VEHICLE_BIKE_RIDING_KIDS_BIKE_TAKES_ME_BACK: 'CommonBuffId' = 321064 + VEHICLE_BIKE_RIDING_KIDS_BIKE_TAUGHT_BY_THE_BEST: 'CommonBuffId' = 321065 + VEHICLE_BIKE_RIDING_KIDS_BIKE_TAUGHT_TO_RIDE: 'CommonBuffId' = 305931 + VEHICLE_BIKE_RIDING_KIDS_BIKE_TAUGHT_TO_RIDE_NOT_PARENT: 'CommonBuffId' = 318213 + VEHICLE_BIKE_WEARING_HELMET: 'CommonBuffId' = 230889 + VENDING_MACHINE_ALL_WARMED_UP: 'CommonBuffId' = 251928 + VENDING_MACHINE_ATE_MY_MONEY: 'CommonBuffId' = 247241 + VENDING_MACHINE_BLACK_5_BURGER: 'CommonBuffId' = 247234 + VENDING_MACHINE_CHICKEN_TERIYAKI_PIZZA: 'CommonBuffId' = 247237 + VENDING_MACHINE_CHILLED_OUT: 'CommonBuffId' = 251929 + VENDING_MACHINE_CUPIDS_CUPCAKE: 'CommonBuffId' = 247238 + VENDING_MACHINE_DEBUG_ALWAYS_FAIL: 'CommonBuffId' = 251188 + VENDING_MACHINE_DEBUG_ALWAYS_SUCCEED: 'CommonBuffId' = 251186 + VENDING_MACHINE_FLUFFY_WHITE_RIBBON_CAKE: 'CommonBuffId' = 247240 + VENDING_MACHINE_GALACTIC_VITA_WATER: 'CommonBuffId' = 247239 + VENDING_MACHINE_GHOST_FLASHBACKS_OF_BEING_CRUSHED: 'CommonBuffId' = 252090 + VENDING_MACHINE_HIDDEN_SHAKE_COOLDOWN: 'CommonBuffId' = 255057 + VENDING_MACHINE_HIDDEN_WEARING_FESTIVAL_KIMONO: 'CommonBuffId' = 253161 + VENDING_MACHINE_HIDDEN_WEARING_FESTIVAL_PAPER_KABUTO: 'CommonBuffId' = 253163 + VENDING_MACHINE_HIDDEN_WEARING_FESTIVAL_SNOW_OUTFIT: 'CommonBuffId' = 253162 + VENDING_MACHINE_PURE_RAGE: 'CommonBuffId' = 251918 + VENDING_MACHINE_TOO_CHILLED_OUT: 'CommonBuffId' = 251982 + VENDING_MACHINE_TOO_WARMED_UP: 'CommonBuffId' = 251981 + VENDING_MACHINE_WASTE_OF_TIME: 'CommonBuffId' = 251917 + VENUE_BAR: 'CommonBuffId' = 370735 + VENUE_BEACH: 'CommonBuffId' = 370374 + VENUE_BEACH_MERFOLK_DISCOVERED_TEST: 'CommonBuffId' = 209098 + VENUE_GYM: 'CommonBuffId' = 365878 + VENUE_KARAOKE: 'CommonBuffId' = 370738 + VENUE_LIBRARY: 'CommonBuffId' = 365779 + VENUE_LOUNGE: 'CommonBuffId' = 370737 + VENUE_MUSEUM: 'CommonBuffId' = 365780 + VENUE_NIGHTCLUB: 'CommonBuffId' = 370736 + VET_BAD_BREATH: 'CommonBuffId' = 170079 + VET_CONE_OF_SHAME: 'CommonBuffId' = 171707 + VET_CONE_OF_SHAME_APPEARANCE_CAT: 'CommonBuffId' = 172531 + VET_CONE_OF_SHAME_APPEARANCE_DOG: 'CommonBuffId' = 172532 + VET_CONE_OF_SHAME_APPEARANCE_SMALL_DOG: 'CommonBuffId' = 172533 + VET_CONE_OF_SHAME_DURATION: 'CommonBuffId' = 171744 + VET_CONE_OF_SHAME_OWNER_REMOVAL: 'CommonBuffId' = 171742 + VET_CONE_OF_SHAME_SELF_REMOVAL: 'CommonBuffId' = 171743 + VET_GREET_PATIENT_COOLDOWN: 'CommonBuffId' = 174800 + VET_SOOTHE_COOLDOWN: 'CommonBuffId' = 178064 + VET_SURGERY_SUCCESSFUL_OUTCOME: 'CommonBuffId' = 175630 + VET_SYMPTOM_DISCOVERY: 'CommonBuffId' = 172256 + VET_SYMPTOM_DISCOVERY_LARGE: 'CommonBuffId' = 173175 + VIDEO_GAME_CONSOLE_PARTY_LOSER_MP: 'CommonBuffId' = 145532 + VIDEO_GAME_CONSOLE_PARTY_WINNER_MP: 'CommonBuffId' = 145531 + VIDEO_GAME_CONSOLE_PARTY_WINNER_SP: 'CommonBuffId' = 153532 + VIDEO_GAME_CONSOLE_PLATFORMER_WINNER_SP: 'CommonBuffId' = 152187 + VIDEO_GAME_CONSOLE_PLAYING_HIDDEN: 'CommonBuffId' = 145713 + VIDEO_GAME_CONSOLE_RACING_LOSER_MP: 'CommonBuffId' = 145536 + VIDEO_GAME_CONSOLE_RACING_WINNER_MP: 'CommonBuffId' = 145535 + VIDEO_GAME_CONSOLE_RACING_WINNER_SP: 'CommonBuffId' = 153531 + VIDEO_GAME_CONSOLE_RAGE_QUIT: 'CommonBuffId' = 145523 + VIDEO_GAME_CONSOLE_RPG_WINNER_SP: 'CommonBuffId' = 152188 + VIEW_ANGRY: 'CommonBuffId' = 12709 + VIEW_CONFIDENT: 'CommonBuffId' = 40816 + VIEW_ENERGIZED: 'CommonBuffId' = 12710 + VIEW_FLIRTY: 'CommonBuffId' = 12711 + VIEW_FOCUSED: 'CommonBuffId' = 12712 + VIEW_HAPPY: 'CommonBuffId' = 12713 + VIEW_IMAGINATIVE: 'CommonBuffId' = 12714 + VIEW_PLAYFUL: 'CommonBuffId' = 100356 + VIEW_SAD: 'CommonBuffId' = 12715 + VILLAGER_HELP_AGATHA_BERRY: 'CommonBuffId' = 268931 + VILLAGER_HELP_DISCOVERY_TNS_COOLDOWN: 'CommonBuffId' = 344536 + VILLAGER_HELP_IN_REGION_NPC_VILLAGER_DISCOVERY: 'CommonBuffId' = 268971 + VILLAGER_HELP_ON_QUEST_HIDDEN: 'CommonBuffId' = 268627 + VILLAGER_HELP_QUEST_COOLDOWN_FOOD_FORAGE_SHORT: 'CommonBuffId' = 267950 + VILLAGER_HELP_QUEST_COOLDOWN_GARDEN_SHORT: 'CommonBuffId' = 267948 + VILLAGER_HELP_QUEST_COOLDOWN_LIVESTOCK_GARDEN_LONG: 'CommonBuffId' = 267952 + VILLAGER_HELP_QUEST_COOLDOWN_LIVESTOCK_SHORT: 'CommonBuffId' = 267947 + VILLAGER_HELP_QUEST_COOLDOWN_SOCIAL_MEDIUM: 'CommonBuffId' = 267951 + VILLAGER_HELP_QUEST_COOLDOWN_SOCIAL_SHORT: 'CommonBuffId' = 267946 + VILLAGER_HELP_QUEST_COOLDOWN_WILD_ANIMAL_FOOD_LONG: 'CommonBuffId' = 267953 + VILLAGER_HELP_QUEST_COOLDOWN_WILD_ANIMAL_SHORT: 'CommonBuffId' = 267949 + VILLAGER_HELP_SITUATION_GOSSIPER: 'CommonBuffId' = 264050 + VILLAGE_FAIR_AUTONOMY_COMPETITOR_PEN: 'CommonBuffId' = 266346 + VILLAGE_FAIR_AUTONOMY_COMPETITOR_STAND_A: 'CommonBuffId' = 266564 + VILLAGE_FAIR_AUTONOMY_COMPETITOR_STAND_B: 'CommonBuffId' = 266565 + VILLAGE_FAIR_AUTONOMY_GENERIC_FESTIVAL_GOER: 'CommonBuffId' = 261209 + VILLAGE_FAIR_AUTONOMY_JUDGE: 'CommonBuffId' = 260706 + VILLAGE_FAIR_CUTTING_HEDGE_ART: 'CommonBuffId' = 268905 + VILLAGE_FAIR_HIDDEN_BRIBED: 'CommonBuffId' = 268291 + VILLAGE_FAIR_HIDDEN_CHEAT_1ST_PRIMARY: 'CommonBuffId' = 269089 + VILLAGE_FAIR_HIDDEN_CHEAT_1ST_SUB: 'CommonBuffId' = 269090 + VILLAGE_FAIR_HIDDEN_CHEAT_LAST_PRIMARY: 'CommonBuffId' = 269091 + VILLAGE_FAIR_HIDDEN_CHEAT_LAST_SUB: 'CommonBuffId' = 269092 + VILLAGE_FAIR_HIDDEN_JUDGED: 'CommonBuffId' = 260710 + VILLAGE_FAIR_HIDDEN_PLAYER: 'CommonBuffId' = 264543 + VILLAGE_FAIR_HIDDEN_SUBMITTED_A: 'CommonBuffId' = 260708 + VILLAGE_FAIR_HIDDEN_SUBMITTED_B: 'CommonBuffId' = 260709 + VILLAGE_FAIR_HIDDEN_VIEW_TNS_GIVEN: 'CommonBuffId' = 268548 + VILLAGE_FAIR_HIDDEN_VILLAGE_FAIR_TRADITIONS_COOLDOWN: 'CommonBuffId' = 268941 + VILLAGE_FAIR_SUBMITTED_ENTRY_EXCELLENT: 'CommonBuffId' = 261315 + VILLAGE_FAIR_SUBMITTED_ENTRY_NORMAL: 'CommonBuffId' = 261314 + VILLAGE_FAIR_SUBMITTED_ENTRY_POOR: 'CommonBuffId' = 261313 + VILLAGE_FAIR_VIEW_SUBMISSION_GOOD: 'CommonBuffId' = 261241 + VILLAGE_FAIR_VIEW_SUBMISSION_POOR: 'CommonBuffId' = 261240 + VILLAGE_SHOPS_RETAIL_THERAPY: 'CommonBuffId' = 268024 + VILLAGE_SHOPS_WINDOW_SHOP_HIDDEN: 'CommonBuffId' = 268025 + VIOLIN_SAD_SONG: 'CommonBuffId' = 9771 + VIP_ROPE_FIGHT_EMBARRASSED: 'CommonBuffId' = 195631 + VIP_ROPE_HIDDEN_ATTEMPT_TO_ENTER_COOLDOWN: 'CommonBuffId' = 200878 + VIP_ROPE_HIDDEN_MAX_BRIBE: 'CommonBuffId' = 199882 + VIP_ROPE_NPC_SUCCESS: 'CommonBuffId' = 199888 + VOLUNTEER_EVENTS_ADVENTURE_COMPLETE: 'CommonBuffId' = 160545 + VOLUNTEER_EVENTS_BAKE_SALE: 'CommonBuffId' = 160579 + VOLUNTEER_EVENTS_BEACH: 'CommonBuffId' = 160575 + VOLUNTEER_EVENTS_BEACH_EMBARRASSED: 'CommonBuffId' = 166105 + VOLUNTEER_EVENTS_BEACH_HAPPY: 'CommonBuffId' = 166108 + VOLUNTEER_EVENTS_HIDDEN_STOP: 'CommonBuffId' = 163909 + VOLUNTEER_EVENTS_NURSING_HOME: 'CommonBuffId' = 160577 + VOLUNTEER_EVENTS_NURSING_HOME_BORED: 'CommonBuffId' = 165916 + VOLUNTEER_EVENTS_NURSING_HOME_EMBARRASSED: 'CommonBuffId' = 161988 + VOLUNTEER_EVENTS_NURSING_HOME_ENERGIZED: 'CommonBuffId' = 165998 + VOLUNTEER_EVENTS_SOUP_KITCHEN: 'CommonBuffId' = 160578 + VOLUNTEER_EVENTS_VOLUNTEER_END_ANGRY: 'CommonBuffId' = 160584 + VOLUNTEER_EVENTS_VOLUNTEER_END_HAPPY: 'CommonBuffId' = 160583 + VOLUNTEER_EVENTS_WALK: 'CommonBuffId' = 160576 + VOODOO_BACKFIRE_BAD: 'CommonBuffId' = 9098 + VOODOO_BACKFIRE_SAD: 'CommonBuffId' = 9122 + VOODOO_BIND: 'CommonBuffId' = 36975 + VOODOO_DAZED: 'CommonBuffId' = 12717 + VOODOO_FUN: 'CommonBuffId' = 12718 + VOODOO_LOVE: 'CommonBuffId' = 12719 + VOODOO_PAIN: 'CommonBuffId' = 12720 + VOODOO_UNCOMFORTABLE: 'CommonBuffId' = 12721 + WAKEUP_UNCOMFORTABLE: 'CommonBuffId' = 12731 + WAKE_UP_TO_SLEEP: 'CommonBuffId' = 331067 + WALK_BY_DOORBELL_RINGER: 'CommonBuffId' = 12732 + WALK_BY_MAILBOX_VISIT: 'CommonBuffId' = 24824 + WALK_BY_NPC_RING_DOORBELL_COOLDOWN: 'CommonBuffId' = 100156 + WALK_BY_PET_WORLD_JOGGER: 'CommonBuffId' = 166527 + WALK_BY_PET_WORLD_NO_HUNGER: 'CommonBuffId' = 167531 + WALK_BY_RENT_DUE_APARTMENT_LANDLORD: 'CommonBuffId' = 143689 + WALK_BY_STAND_IDLE: 'CommonBuffId' = 12733 + WALK_STYLE_ANGRY: 'CommonBuffId' = 116080 + WANT_ASPIRATION_GOAL_COMPLETED: 'CommonBuffId' = 273579 + WANT_FEAR_CONFRONTATION_SUCCESS_INFERIOR_BE_PRAISED: 'CommonBuffId' = 309265 + WANT_FEAR_CONFRONTATION_SUCCESS_INFERIOR_BE_PRAISED_PARTIAL: 'CommonBuffId' = 309266 + WANT_FEAR_CONFRONTATION_SUCCESS_INFERIOR_COOLDOWN: 'CommonBuffId' = 319043 + WANT_FEAR_FULFILLMENT_NEGATIVE_LEVEL_1: 'CommonBuffId' = 272994 + WANT_FEAR_FULFILLMENT_NEGATIVE_LEVEL_2: 'CommonBuffId' = 272995 + WANT_FEAR_FULFILLMENT_NEGATIVE_LEVEL_3: 'CommonBuffId' = 272996 + WANT_FEAR_LIKED_MUSIC_COOLDOWN: 'CommonBuffId' = 344335 + WANT_FEAR_LIKED_MUSIC_LISTEN_TO_ALTERNATIVE: 'CommonBuffId' = 301398 + WANT_FEAR_LIKED_MUSIC_LISTEN_TO_AMERICANA: 'CommonBuffId' = 301440 + WANT_FEAR_LIKED_MUSIC_LISTEN_TO_BACKYARD: 'CommonBuffId' = 301427 + WANT_FEAR_LIKED_MUSIC_LISTEN_TO_BAROQUE: 'CommonBuffId' = 301431 + WANT_FEAR_LIKED_MUSIC_LISTEN_TO_BATUU: 'CommonBuffId' = 346289 + WANT_FEAR_LIKED_MUSIC_LISTEN_TO_BLUES: 'CommonBuffId' = 301402 + WANT_FEAR_LIKED_MUSIC_LISTEN_TO_BRAZILIAN: 'CommonBuffId' = 346290 + WANT_FEAR_LIKED_MUSIC_LISTEN_TO_CLASSICAL: 'CommonBuffId' = 301403 + WANT_FEAR_LIKED_MUSIC_LISTEN_TO_COTTAGE_CORE: 'CommonBuffId' = 301455 + WANT_FEAR_LIKED_MUSIC_LISTEN_TO_DJ: 'CommonBuffId' = 301429 + WANT_FEAR_LIKED_MUSIC_LISTEN_TO_EASY_LISTENING: 'CommonBuffId' = 301426 + WANT_FEAR_LIKED_MUSIC_LISTEN_TO_ELECTRONICA: 'CommonBuffId' = 301404 + WANT_FEAR_LIKED_MUSIC_LISTEN_TO_FOCUS: 'CommonBuffId' = 301442 + WANT_FEAR_LIKED_MUSIC_LISTEN_TO_HIP_HOP: 'CommonBuffId' = 301415 + WANT_FEAR_LIKED_MUSIC_LISTEN_TO_ISLAND: 'CommonBuffId' = 301439 + WANT_FEAR_LIKED_MUSIC_LISTEN_TO_JAPANESE_FOLK: 'CommonBuffId' = 301441 + WANT_FEAR_LIKED_MUSIC_LISTEN_TO_JAZZ: 'CommonBuffId' = 301430 + WANT_FEAR_LIKED_MUSIC_LISTEN_TO_KIDS: 'CommonBuffId' = 301416 + WANT_FEAR_LIKED_MUSIC_LISTEN_TO_LATIN: 'CommonBuffId' = 301434 + WANT_FEAR_LIKED_MUSIC_LISTEN_TO_LATIN_POP: 'CommonBuffId' = 301435 + WANT_FEAR_LIKED_MUSIC_LISTEN_TO_LULLABIES: 'CommonBuffId' = 301417 + WANT_FEAR_LIKED_MUSIC_LISTEN_TO_METAL: 'CommonBuffId' = 301443 + WANT_FEAR_LIKED_MUSIC_LISTEN_TO_NEW_AGE: 'CommonBuffId' = 301428 + WANT_FEAR_LIKED_MUSIC_LISTEN_TO_NU_DISCO: 'CommonBuffId' = 301456 + WANT_FEAR_LIKED_MUSIC_LISTEN_TO_OLDIES: 'CommonBuffId' = 312572 + WANT_FEAR_LIKED_MUSIC_LISTEN_TO_POP: 'CommonBuffId' = 301418 + WANT_FEAR_LIKED_MUSIC_LISTEN_TO_RANCH: 'CommonBuffId' = 334865 + WANT_FEAR_LIKED_MUSIC_LISTEN_TO_RETRO: 'CommonBuffId' = 301419 + WANT_FEAR_LIKED_MUSIC_LISTEN_TO_RNB: 'CommonBuffId' = 343181 + WANT_FEAR_LIKED_MUSIC_LISTEN_TO_ROMANCE: 'CommonBuffId' = 301420 + WANT_FEAR_LIKED_MUSIC_LISTEN_TO_SINGER_SONGWRITER: 'CommonBuffId' = 301437 + WANT_FEAR_LIKED_MUSIC_LISTEN_TO_SPOOKY: 'CommonBuffId' = 301421 + WANT_FEAR_LIKED_MUSIC_LISTEN_TO_STRANGE_TUNES: 'CommonBuffId' = 301436 + WANT_FEAR_LIKED_MUSIC_LISTEN_TO_SUMMER_STRUT: 'CommonBuffId' = 301438 + WANT_FEAR_LIKED_MUSIC_LISTEN_TO_S_POP: 'CommonBuffId' = 301422 + WANT_FEAR_LIKED_MUSIC_LISTEN_TO_TWEEN_POP: 'CommonBuffId' = 301432 + WANT_FEAR_LIKED_MUSIC_LISTEN_TO_WINTER_MUSIC: 'CommonBuffId' = 301423 + WANT_FEAR_LIKED_MUSIC_LISTEN_TO_WORLD: 'CommonBuffId' = 301424 + WANT_GAINED_CONFIDENT: 'CommonBuffId' = 291767 + WANT_GAINED_ENERGIZED: 'CommonBuffId' = 291771 + WANT_GAINED_FLIRTY: 'CommonBuffId' = 291766 + WANT_GAINED_FOCUSED: 'CommonBuffId' = 291770 + WANT_GAINED_HAPPY: 'CommonBuffId' = 284205 + WANT_GAINED_INSPIRED: 'CommonBuffId' = 291769 + WANT_GAINED_PLAYFUL: 'CommonBuffId' = 291768 + WANT_MAKE_CONNECTIONS_TRACKER: 'CommonBuffId' = 287474 + WANT_MISS_WORK_TRACKER: 'CommonBuffId' = 287490 + WANT_SLACK_OFF_TRACKER: 'CommonBuffId' = 287476 + WANT_WORK_HARD_TRACKER: 'CommonBuffId' = 287477 + WANT_WORK_TASK_COMPLETED: 'CommonBuffId' = 273587 + WARDROBE_PEDESTAL_STYLED_PLAYFUL: 'CommonBuffId' = 197876 + WARDROBE_PEDESTAL_STYLIST_ARRIVAL: 'CommonBuffId' = 191621 + WARDROBE_PEDESTAL_STYLIST_BORED: 'CommonBuffId' = 191622 + WARDROBE_PEDESTAL_STYLIST_WORKING: 'CommonBuffId' = 191623 + WATCH_AFFORDANCE: 'CommonBuffId' = 164176 + WATERFALL_WALL_CALMING_WATER: 'CommonBuffId' = 118021 + WEARING_PAPER_BAG: 'CommonBuffId' = 238402 + WEARING_PAPER_BAG_INFLUENCE_POINTS_COOLDOWN: 'CommonBuffId' = 239235 + WEATHER_PREFERENCE_LOVES_COLD_TEMP_IS_COLD: 'CommonBuffId' = 189166 + WEATHER_PREFERENCE_LOVES_COLD_TEMP_IS_FREEZING: 'CommonBuffId' = 189167 + WEATHER_PREFERENCE_LOVES_HOT_TEMP_IS_BURNING: 'CommonBuffId' = 189175 + WEATHER_PREFERENCE_LOVES_HOT_TEMP_IS_HOT: 'CommonBuffId' = 189174 + WEATHER_PREFERENCE_WIND_HATES_WIND: 'CommonBuffId' = 189205 + WEATHER_PREFERENCE_WIND_LOVES_WIND: 'CommonBuffId' = 189204 + WEATHER_TEMPERATURE_WARMED_BY_KISS: 'CommonBuffId' = 183659 + WEATHER_TEMPERATURE_WARMED_UP_FLIRTY: 'CommonBuffId' = 183657 + WEATHER_TEMPERATURE_WARMED_UP_HAPPY: 'CommonBuffId' = 183658 + WEATHER_TEMPERATURE_WARMED_UP_ITS_A_SIGN: 'CommonBuffId' = 188450 + WEDDING_AISLE_DEBUG: 'CommonBuffId' = 278003 + WEDDING_AISLE_PICKED_BOUQUET_TYPE_1_1: 'CommonBuffId' = 280291 + WEDDING_AISLE_PICKED_BOUQUET_TYPE_1_2: 'CommonBuffId' = 280292 + WEDDING_AISLE_PICKED_BOUQUET_TYPE_1_3: 'CommonBuffId' = 280293 + WEDDING_AISLE_PICKED_BOUQUET_TYPE_1_4: 'CommonBuffId' = 280294 + WEDDING_AISLE_PICKED_BOUQUET_TYPE_1_5: 'CommonBuffId' = 280295 + WEDDING_AISLE_PICKED_BOUQUET_TYPE_1_6: 'CommonBuffId' = 280296 + WEDDING_AISLE_PICKED_BOUQUET_TYPE_1_7: 'CommonBuffId' = 280290 + WEDDING_AISLE_PICKED_BOUQUET_TYPE_2_1: 'CommonBuffId' = 280299 + WEDDING_AISLE_PICKED_BOUQUET_TYPE_2_2: 'CommonBuffId' = 280300 + WEDDING_AISLE_PICKED_BOUQUET_TYPE_2_3: 'CommonBuffId' = 280301 + WEDDING_AISLE_PICKED_BOUQUET_TYPE_2_4: 'CommonBuffId' = 280302 + WEDDING_AISLE_PICKED_BOUQUET_TYPE_2_5: 'CommonBuffId' = 280303 + WEDDING_AISLE_PICKED_BOUQUET_TYPE_2_6: 'CommonBuffId' = 280304 + WEDDING_AISLE_PICKED_BOUQUET_TYPE_2_7: 'CommonBuffId' = 280305 + WEDDING_AISLE_PICKED_BOUQUET_TYPE_2_8: 'CommonBuffId' = 280298 + WEDDING_AISLE_WEDDING_EXCITEMENT: 'CommonBuffId' = 277751 + WEDDING_AISLE_WEDDING_NERVES: 'CommonBuffId' = 277750 + WEDDING_ARCH_FANTASIZE_ANGRY: 'CommonBuffId' = 12736 + WEDDING_ARCH_FANTASIZE_COMMITMENT_ISSUES: 'CommonBuffId' = 97346 + WEDDING_ARCH_FANTASIZE_FLIRTY: 'CommonBuffId' = 12737 + WEDDING_ARCH_FANTASIZE_HAPPY: 'CommonBuffId' = 12738 + WEDDING_BETROTHED_CEREMONY: 'CommonBuffId' = 9368 + WEDDING_BETROTHED_GATHER: 'CommonBuffId' = 9369 + WEDDING_BETROTHED_RECEPTION: 'CommonBuffId' = 9370 + WEDDING_CAKE_CUT_CAKE_JM_BUFF: 'CommonBuffId' = 12739 + WEDDING_CAKE_CUT_CAKE_NO_JM_BUFF: 'CommonBuffId' = 12740 + WEDDING_CAME_TO_WEDDING_DURATION: 'CommonBuffId' = 283185 + WEDDING_CAME_TO_WEDDING_LOOT: 'CommonBuffId' = 283180 + WEDDING_CATERER_PREP: 'CommonBuffId' = 12746 + WEDDING_CEREMONY_FLOWER_BOUQUET_CAUGHT: 'CommonBuffId' = 274213 + WEDDING_CEREMONY_FLOWER_BOUQUET_EXPRESS_ANGER: 'CommonBuffId' = 277595 + WEDDING_CEREMONY_FLOWER_BOUQUET_EXPRESS_JOY: 'CommonBuffId' = 277594 + WEDDING_CEREMONY_FLOWER_BOUQUET_ROSETHORN: 'CommonBuffId' = 277591 + WEDDING_CEREMONY_FLOWER_BOUQUET_TOSSED: 'CommonBuffId' = 277577 + WEDDING_CUSTOM_STATE_OFFICIANT_SPEECH_COMPLETE: 'CommonBuffId' = 278952 + WEDDING_CUSTOM_STATE_ROLES_COUPLE_ARRIVAL: 'CommonBuffId' = 275934 + WEDDING_CUSTOM_STATE_SPEECH_COMPLETE: 'CommonBuffId' = 282132 + WEDDING_GROUP_DANCING_ALL_SYNCED_UP: 'CommonBuffId' = 279766 + WEDDING_GROUP_DANCING_IS_DANCING: 'CommonBuffId' = 278208 + WEDDING_GUEST_CEREMONY: 'CommonBuffId' = 12751 + WEDDING_GUEST_GATHER: 'CommonBuffId' = 12752 + WEDDING_GUEST_GATHER_IMPATIENT: 'CommonBuffId' = 12753 + WEDDING_GUEST_POST_CAKE: 'CommonBuffId' = 12754 + WEDDING_GUEST_PRE_CAKE: 'CommonBuffId' = 12755 + WEDDING_GUEST_RECEPTION: 'CommonBuffId' = 12756 + WEDDING_PARTIES_ALL_OVER_AGAIN: 'CommonBuffId' = 274218 + WEDDING_PARTIES_PARTY_HEARTY: 'CommonBuffId' = 274216 + WEDDING_SHELL_DRESS_SHOP: 'CommonBuffId' = 276428 + WEDDING_SHELL_TOWN_HALL_GET_MARRIED_ROLE_GETTING_MARRIED: 'CommonBuffId' = 276445 + WEDDING_SHELL_TOWN_HALL_GET_MARRIED_ROLE_START: 'CommonBuffId' = 276382 + WEDDING_SHELL_TOWN_HALL_GET_MARRIED_SITUATION_ENDED: 'CommonBuffId' = 276429 + WEDDING_TOAST_FINISHED: 'CommonBuffId' = 291224 + WEDDING_TOAST_HEARD_TOAST_SUCCESS: 'CommonBuffId' = 280616 + WEDDING_TOAST_MADE_TOAST_FAILURE: 'CommonBuffId' = 280615 + WEDDING_TOAST_MADE_TOAST_SUCCESS: 'CommonBuffId' = 280614 + WEDDING_WASH_ON_OR_PARTY_DURATION: 'CommonBuffId' = 283182 + WEDDING_WASH_ON_OR_PARTY_LOOT: 'CommonBuffId' = 283189 + WEDDING_WEDDING_TRADITION_BOUQUET_TOSS: 'CommonBuffId' = 276469 + WEDDING_WEDDING_TRADITION_COUPLE_CUT_CAKE: 'CommonBuffId' = 276474 + WEDDING_WEDDING_TRADITION_FIRST_DANCE: 'CommonBuffId' = 276470 + WEDDING_WEDDING_TRADITION_GROUP_DANCE: 'CommonBuffId' = 280626 + WEDDING_WEDDING_TRADITION_HAD_BOUQET: 'CommonBuffId' = 276471 + WEDDING_WEDDING_TRADITION_HAD_WEDDING_CAKE: 'CommonBuffId' = 276472 + WEDDING_WEDDING_TRADITION_HONOR_US: 'CommonBuffId' = 281070 + WEDDING_WEDDING_TRADITION_INVITED_TO_WEDDING: 'CommonBuffId' = 281067 + WEDDING_WEDDING_TRADITION_ITS_AN_HONOR: 'CommonBuffId' = 281064 + WEDDING_WEDDING_TRADITION_RING_EXCHANGE: 'CommonBuffId' = 276468 + WEDDING_WEDDING_TRADITION_SOCIALS: 'CommonBuffId' = 280992 + WEDDING_WEDDING_TRADITION_SPOUSAL_KISS: 'CommonBuffId' = 276467 + WEDDING_WEDDING_TRADITION_WALKED_DOWN_AISLE: 'CommonBuffId' = 276473 + WEDDING_WORLD_BIOLUMINESCENT_BURST: 'CommonBuffId' = 279922 + WEDDING_WORLD_BROADCASTER_FOUNTAIN: 'CommonBuffId' = 279928 + WEDDING_WORLD_BROADCASTER_TREE: 'CommonBuffId' = 279929 + WEDDING_WORLD_GRAPE_THIEF: 'CommonBuffId' = 279923 + WEDDING_WORLD_HANDPICKED: 'CommonBuffId' = 279924 + WEDDING_WORLD_METHUSELAH_MYSTERY: 'CommonBuffId' = 279920 + WEDDING_WORLD_RIVIERA_REFRESHER: 'CommonBuffId' = 279921 + WEDDING_WORLD_ROMANTIC_COIN_TOSS: 'CommonBuffId' = 279925 + WEDDING_WORLD_TOWN_SQUARE_ROMANCE: 'CommonBuffId' = 279919 + WEDDING_WORLD_WATERFALL_WISTFULNESS: 'CommonBuffId' = 279918 + WELCOME_WAGON_FRUITCAKE_BEARER_PUT_DOWN_FRUITCAKE: 'CommonBuffId' = 120127 + WELLNESS_CALMING_AURA: 'CommonBuffId' = 272284 + WELLNESS_CALMING_AURA_COOLDOWN: 'CommonBuffId' = 272285 + WELLNESS_CALMING_AURA_TARGET: 'CommonBuffId' = 272286 + WELLNESS_CUCUMBER_POWER_SIP: 'CommonBuffId' = 272638 + WELLNESS_HUSTLE: 'CommonBuffId' = 272722 + WELLNESS_MAINTAIN_HARMONY: 'CommonBuffId' = 272537 + WELLNESS_MAINTAIN_HARMONY_COMPLETE: 'CommonBuffId' = 272538 + WELLNESS_MASTER_WELLNESS: 'CommonBuffId' = 272544 + WELLNESS_MOMENT_OF_CLARITY: 'CommonBuffId' = 272278 + WELLNESS_MOMENT_OF_CLARITY_COOLDOWN: 'CommonBuffId' = 272279 + WELLNESS_PEACEFUL: 'CommonBuffId' = 272429 + WELLNESS_PROMOTE_COOLDOWN: 'CommonBuffId' = 272652 + WELLNESS_REGULAR: 'CommonBuffId' = 272456 + WELLNESS_REPEAT_CUSTOMER_COOLDOWN: 'CommonBuffId' = 272853 + WELLNESS_SATISFIED: 'CommonBuffId' = 272452 + WELLNESS_TEA: 'CommonBuffId' = 272776 + WELLNESS_TEA_BREWER: 'CommonBuffId' = 272854 + WEREWOLF_ABILITIES_DIG_SPOT: 'CommonBuffId' = 292378 + WEREWOLF_ABILITIES_DONT_LOOK_AT_ME: 'CommonBuffId' = 292063 + WEREWOLF_ABILITIES_FRESH_MEAT: 'CommonBuffId' = 292755 + WEREWOLF_ABILITIES_HUNTER_STRIDE: 'CommonBuffId' = 290325 + WEREWOLF_ABILITIES_INTIMIDATION: 'CommonBuffId' = 292384 + WEREWOLF_ABILITIES_IS_SMELLING: 'CommonBuffId' = 297981 + WEREWOLF_ABILITIES_LUNAR_HOWL: 'CommonBuffId' = 298352 + WEREWOLF_ABILITIES_LUNAR_HOWL_COOLDOWN: 'CommonBuffId' = 292571 + WEREWOLF_ABILITIES_NATURAL_HEALING: 'CommonBuffId' = 290527 + WEREWOLF_ABILITIES_NEARBY_MARKED: 'CommonBuffId' = 292059 + WEREWOLF_ABILITIES_OCCULT_SMELL: 'CommonBuffId' = 297805 + WEREWOLF_ABILITIES_PACIFY_COOLDOWN: 'CommonBuffId' = 292124 + WEREWOLF_ABILITIES_PRIMAL: 'CommonBuffId' = 289930 + WEREWOLF_ABILITIES_RESIST_COOLDOWN: 'CommonBuffId' = 290215 + WEREWOLF_ABILITIES_RESIST_SUCCESS: 'CommonBuffId' = 297752 + WEREWOLF_ABILITIES_SAD_WOLF: 'CommonBuffId' = 290328 + WEREWOLF_ABILITIES_SMELLS_ALIEN: 'CommonBuffId' = 290205 + WEREWOLF_ABILITIES_SMELLS_ANGRY: 'CommonBuffId' = 290198 + WEREWOLF_ABILITIES_SMELLS_FLIRTY: 'CommonBuffId' = 290201 + WEREWOLF_ABILITIES_SMELLS_GENERIC: 'CommonBuffId' = 290183 + WEREWOLF_ABILITIES_SMELLS_LIKE_VAMPIRE: 'CommonBuffId' = 295321 + WEREWOLF_ABILITIES_SMELLS_MERMAID: 'CommonBuffId' = 290206 + WEREWOLF_ABILITIES_SMELLS_SCARED: 'CommonBuffId' = 290200 + WEREWOLF_ABILITIES_SMELLS_VAMPIRE: 'CommonBuffId' = 290203 + WEREWOLF_ABILITIES_SMELLS_WEREWOLF: 'CommonBuffId' = 290202 + WEREWOLF_ABILITIES_SMELLS_WITCH: 'CommonBuffId' = 290204 + WEREWOLF_ABILITIES_SOMBER_HOWL_COOLDOWN: 'CommonBuffId' = 290332 + WEREWOLF_ABILITIES_SPEED: 'CommonBuffId' = 290517 + WEREWOLF_ABILITIES_SURPRISINGLY_TASTY: 'CommonBuffId' = 293994 + WEREWOLF_ABILITIES_TANTALIZING_AROMA: 'CommonBuffId' = 290210 + WEREWOLF_ABILITIES_TANTALIZING_AROMA_FLIRTY: 'CommonBuffId' = 297756 + WEREWOLF_ABILITIES_TANTALIZING_AROMA_PLAYFUL: 'CommonBuffId' = 297757 + WEREWOLF_ABILITIES_TEACH_TO_HOWL: 'CommonBuffId' = 295585 + WEREWOLF_ABILITIES_THE_HORRORS: 'CommonBuffId' = 290324 + WEREWOLF_ABILITIES_TOOTHACHE: 'CommonBuffId' = 289514 + WEREWOLF_ABILITIES_WEREWOLF_DIPLOMACY: 'CommonBuffId' = 298161 + WEREWOLF_ABILITIES_WEREWOLF_DISTRUST: 'CommonBuffId' = 298160 + WEREWOLF_ABILITIES_WEREWOLF_GUIDANCE_PC: 'CommonBuffId' = 292126 + WEREWOLF_ABILITIES_WEREWOLF_GUIDANCE_PC_HAPPY: 'CommonBuffId' = 296231 + WEREWOLF_ABILITIES_WEREWOLF_GUIDANCE_TYAE: 'CommonBuffId' = 292125 + WEREWOLF_ABILITIES_WEREWOLF_MENACE: 'CommonBuffId' = 292065 + WEREWOLF_ABILITIES_WHAT_HAVE_I_DONE: 'CommonBuffId' = 289515 + WEREWOLF_ABILITIES_WOLF_AMONGUS: 'CommonBuffId' = 297758 + WEREWOLF_ACTOR_ABOUT_TO_FIGHT: 'CommonBuffId' = 290866 + WEREWOLF_ALL_AGES: 'CommonBuffId' = 291538 + WEREWOLF_ALPHA_OF_HOUSE: 'CommonBuffId' = 292947 + WEREWOLF_APEX: 'CommonBuffId' = 297282 + WEREWOLF_ASPIRATIONS_ALREADY_FAINTED: 'CommonBuffId' = 296166 + WEREWOLF_ASPIRATIONS_EXPERIENCE_FULL_MOON: 'CommonBuffId' = 291330 + WEREWOLF_ASPIRATIONS_FRIENDLY_WOLF: 'CommonBuffId' = 291634 + WEREWOLF_ASPIRATIONS_WIN_WEREWOLF_FIGHT: 'CommonBuffId' = 291341 + WEREWOLF_BATUU_WOLF: 'CommonBuffId' = 299990 + WEREWOLF_BEASTLY_GROWTH_SPURT: 'CommonBuffId' = 292942 + WEREWOLF_CD_LORE_BOOKS_NOTIF: 'CommonBuffId' = 300389 + WEREWOLF_COMMAND_TO_WORK_OUT: 'CommonBuffId' = 293826 + WEREWOLF_CREATION_ASKING_TO_BE_TURNED: 'CommonBuffId' = 293713 + WEREWOLF_CREATION_BECOMING_HUMAN: 'CommonBuffId' = 288322 + WEREWOLF_CREATION_BECOMING_HUMAN_WEREBIES: 'CommonBuffId' = 288332 + WEREWOLF_CREATION_BEING_TURNED: 'CommonBuffId' = 289681 + WEREWOLF_CREATION_CD_BEEN_ASKED: 'CommonBuffId' = 293712 + WEREWOLF_CREATION_FORCED_SCARED: 'CommonBuffId' = 289421 + WEREWOLF_CREATION_INSATIABLE_HUNGER_1: 'CommonBuffId' = 288315 + WEREWOLF_CREATION_INSATIABLE_HUNGER_2: 'CommonBuffId' = 288318 + WEREWOLF_CREATION_PAINFUL_BITE: 'CommonBuffId' = 293717 + WEREWOLF_CREATION_TURNED: 'CommonBuffId' = 288319 + WEREWOLF_CREATION_WEREBIES_1: 'CommonBuffId' = 288320 + WEREWOLF_CREATION_WEREBIES_2: 'CommonBuffId' = 288321 + WEREWOLF_CREATION_WEREBIES_PAUSED: 'CommonBuffId' = 292408 + WEREWOLF_CREATION_WITNESS_SCARED: 'CommonBuffId' = 289676 + WEREWOLF_DISGUST_COOLDOWN: 'CommonBuffId' = 300157 + WEREWOLF_DOG_WATER: 'CommonBuffId' = 295323 + WEREWOLF_DONT_BE_A_JERK: 'CommonBuffId' = 288741 + WEREWOLF_DONT_RESET_FURY: 'CommonBuffId' = 295135 + WEREWOLF_DONT_RUN_AWAY: 'CommonBuffId' = 299805 + WEREWOLF_ENRAGE_TARGET: 'CommonBuffId' = 298610 + WEREWOLF_FATED_MATES: 'CommonBuffId' = 293547 + WEREWOLF_FIGHT_SIM_LOST: 'CommonBuffId' = 287971 + WEREWOLF_FIGHT_SIM_WON: 'CommonBuffId' = 287973 + WEREWOLF_FIGHT_SPARRING: 'CommonBuffId' = 287966 + WEREWOLF_FIGHT_VAMPIRE_LOST: 'CommonBuffId' = 287968 + WEREWOLF_FIGHT_VAMPIRE_WON: 'CommonBuffId' = 287967 + WEREWOLF_FIGHT_WOLF_BEAT_SIM: 'CommonBuffId' = 287972 + WEREWOLF_FIGHT_WOLF_BEAT_VAMPIRE: 'CommonBuffId' = 287970 + WEREWOLF_FIGHT_WOLF_LOST_TO_SIM: 'CommonBuffId' = 287969 + WEREWOLF_FIGHT_WOLF_LOST_TO_VAMPIRE: 'CommonBuffId' = 287974 + WEREWOLF_FLUFFY_PUPPY: 'CommonBuffId' = 291181 + WEREWOLF_FURY_EXTREME: 'CommonBuffId' = 285805 + WEREWOLF_FURY_FREEZE: 'CommonBuffId' = 299670 + WEREWOLF_FURY_GLOW_EXTREME: 'CommonBuffId' = 290769 + WEREWOLF_FURY_GLOW_HIGH: 'CommonBuffId' = 290770 + WEREWOLF_FURY_HIGH: 'CommonBuffId' = 285804 + WEREWOLF_FURY_LOW: 'CommonBuffId' = 285802 + WEREWOLF_FURY_MEDIUM: 'CommonBuffId' = 285803 + WEREWOLF_FURY_RAMPAGE: 'CommonBuffId' = 285807 + WEREWOLF_HARASS_COOLDOWN: 'CommonBuffId' = 293625 + WEREWOLF_IN_BEAST_FORM: 'CommonBuffId' = 300835 + WEREWOLF_IS_WEREWOLF: 'CommonBuffId' = 276405 + WEREWOLF_KICKED_FROM_PACK: 'CommonBuffId' = 293156 + WEREWOLF_MOON_MADNESS: 'CommonBuffId' = 292945 + WEREWOLF_NEAR_TRANSFORMED_WEREWOLF: 'CommonBuffId' = 288846 + WEREWOLF_NEW_FANG_PAIN: 'CommonBuffId' = 292940 + WEREWOLF_NOT_MEANT_TO_BE: 'CommonBuffId' = 293548 + WEREWOLF_NPC_OUTSIDE_WOLF_TOWN_DEFAULT: 'CommonBuffId' = 293876 + WEREWOLF_NPC_OUTSIDE_WOLF_TOWN_RESTRICTED: 'CommonBuffId' = 293874 + WEREWOLF_PACK_A: 'CommonBuffId' = 290636 + WEREWOLF_PACK_ALLIANCE_FEUD_ALL_FOR_WOLF: 'CommonBuffId' = 289720 + WEREWOLF_PACK_ALLIANCE_FEUD_FEUDING: 'CommonBuffId' = 289721 + WEREWOLF_PACK_ALLIANCE_FEUD_HIDDEN_ALLIANCE: 'CommonBuffId' = 289717 + WEREWOLF_PACK_ALLIANCE_FEUD_HIDDEN_FEUD: 'CommonBuffId' = 289718 + WEREWOLF_PACK_ALLIANCE_FEUD_HIDDEN_NEUTRAL: 'CommonBuffId' = 289709 + WEREWOLF_PACK_A_NPC: 'CommonBuffId' = 293739 + WEREWOLF_PACK_B: 'CommonBuffId' = 290637 + WEREWOLF_PACK_BAD_PACK_MEMBER: 'CommonBuffId' = 290472 + WEREWOLF_PACK_B_NPC: 'CommonBuffId' = 293738 + WEREWOLF_PACK_CHECK_RESOURCES_COOLDOWN: 'CommonBuffId' = 289619 + WEREWOLF_PACK_CHECK_RESOURCES_COOLDOWN_SPECIAL_A: 'CommonBuffId' = 289628 + WEREWOLF_PACK_CHECK_RESOURCES_COOLDOWN_SPECIAL_B: 'CommonBuffId' = 289629 + WEREWOLF_PACK_COOLDOWN_CHALLENGE_LEADER: 'CommonBuffId' = 293734 + WEREWOLF_PACK_COOLDOWN_FRIENDLY_TUG_OF_WAR: 'CommonBuffId' = 296626 + WEREWOLF_PACK_DEMOTED: 'CommonBuffId' = 290944 + WEREWOLF_PACK_DISCIPLINED: 'CommonBuffId' = 293361 + WEREWOLF_PACK_DISCIPLINE_PROBATION: 'CommonBuffId' = 286088 + WEREWOLF_PACK_DISCIPLINE_PROBATION_LEADER: 'CommonBuffId' = 286783 + WEREWOLF_PACK_DISCIPLINE_REPORT_TO_LEADER: 'CommonBuffId' = 286152 + WEREWOLF_PACK_DISCIPLINE_REPORT_TO_LEADER_FRIEND_A: 'CommonBuffId' = 287086 + WEREWOLF_PACK_DISCIPLINE_REPORT_TO_LEADER_FRIEND_B: 'CommonBuffId' = 287087 + WEREWOLF_PACK_DISCIPLINE_STRONG_WARNING_DIPLOMACY: 'CommonBuffId' = 286153 + WEREWOLF_PACK_DISCIPLINE_STRONG_WARNING_EXPAND_EXPLORE: 'CommonBuffId' = 286202 + WEREWOLF_PACK_DISCIPLINE_STRONG_WARNING_PACK_PARTICIPATION: 'CommonBuffId' = 286203 + WEREWOLF_PACK_DISCIPLINE_STRONG_WARNING_SELF_IMPROVEMENT: 'CommonBuffId' = 286204 + WEREWOLF_PACK_DISCIPLINE_STRONG_WARNING_SELF_SUFFICIENCY: 'CommonBuffId' = 286205 + WEREWOLF_PACK_DISCIPLINE_WARNING: 'CommonBuffId' = 297603 + WEREWOLF_PACK_DISCIPLINE_WARNING_DIPLOMACY: 'CommonBuffId' = 286087 + WEREWOLF_PACK_DISCIPLINE_WARNING_EXPAND_EXPLORE: 'CommonBuffId' = 286195 + WEREWOLF_PACK_DISCIPLINE_WARNING_PACK_PARTICIPATION: 'CommonBuffId' = 286196 + WEREWOLF_PACK_DISCIPLINE_WARNING_SELF_IMPROVEMENT: 'CommonBuffId' = 286197 + WEREWOLF_PACK_DISCIPLINE_WARNING_SELF_SUFFICIENCY: 'CommonBuffId' = 286198 + WEREWOLF_PACK_FETCH_COOLDOWN: 'CommonBuffId' = 294217 + WEREWOLF_PACK_FRIEND_A: 'CommonBuffId' = 286992 + WEREWOLF_PACK_FRIEND_B: 'CommonBuffId' = 286993 + WEREWOLF_PACK_JOIN_TRIAL_GAVE_COLLECTABLE_PACK_A: 'CommonBuffId' = 287566 + WEREWOLF_PACK_JOIN_TRIAL_GAVE_COLLECTABLE_PACK_B: 'CommonBuffId' = 287568 + WEREWOLF_PACK_JOIN_TRIAL_GAVE_FOOD_PACK_A: 'CommonBuffId' = 287565 + WEREWOLF_PACK_JOIN_TRIAL_GAVE_FOOD_PACK_B: 'CommonBuffId' = 287567 + WEREWOLF_PACK_JOIN_TRIAL_IN_PROGRESS_PACK_A: 'CommonBuffId' = 292266 + WEREWOLF_PACK_JOIN_TRIAL_IN_PROGRESS_PACK_B: 'CommonBuffId' = 292267 + WEREWOLF_PACK_JOIN_TRIAL_LUNAR_EPIPHANY_PACK_A: 'CommonBuffId' = 292243 + WEREWOLF_PACK_JOIN_TRIAL_LUNAR_EPIPHANY_PACK_B: 'CommonBuffId' = 292244 + WEREWOLF_PACK_JOIN_TRIAL_PACK_HOWL_PACK_A: 'CommonBuffId' = 292247 + WEREWOLF_PACK_JOIN_TRIAL_PACK_HOWL_PACK_B: 'CommonBuffId' = 292248 + WEREWOLF_PACK_JOIN_TRIAL_SCAVENGE_PACK_A: 'CommonBuffId' = 292245 + WEREWOLF_PACK_JOIN_TRIAL_SCAVENGE_PACK_B: 'CommonBuffId' = 292246 + WEREWOLF_PACK_JOIN_TRIAL_SPAR_PACK_A: 'CommonBuffId' = 289579 + WEREWOLF_PACK_JOIN_TRIAL_SPAR_PACK_B: 'CommonBuffId' = 289580 + WEREWOLF_PACK_LEADER_TO_LEADER_ANGRY: 'CommonBuffId' = 293570 + WEREWOLF_PACK_LEADER_TO_LEADER_CD: 'CommonBuffId' = 293582 + WEREWOLF_PACK_LEADER_TO_LEADER_CONFIDENT: 'CommonBuffId' = 293569 + WEREWOLF_PACK_LET_DOWN_THE_PACK: 'CommonBuffId' = 290474 + WEREWOLF_PACK_NEW_ALPHA_IN_TOWN: 'CommonBuffId' = 290937 + WEREWOLF_PACK_NPC_ENTER_SHELL_COOLDOWN: 'CommonBuffId' = 290578 + WEREWOLF_PACK_NPC_GIVE_GIFT_COOLDOWN: 'CommonBuffId' = 292203 + WEREWOLF_PACK_PRIDE_OF_THE_PACK: 'CommonBuffId' = 290473 + WEREWOLF_PACK_PROMOTED: 'CommonBuffId' = 290945 + WEREWOLF_PACK_RECENTLY_DECLINED_INVITE_A: 'CommonBuffId' = 290560 + WEREWOLF_PACK_RECENTLY_DECLINED_INVITE_B: 'CommonBuffId' = 290561 + WEREWOLF_PACK_RECENTLY_DISCPLINED_CD: 'CommonBuffId' = 293360 + WEREWOLF_PACK_RECENTLY_GAVE_UP_LEADERSHIP: 'CommonBuffId' = 291004 + WEREWOLF_PACK_RECENTLY_GOT_GIFT_FROM_NPC: 'CommonBuffId' = 292204 + WEREWOLF_PACK_RECENTLY_KICKED_OUT_A: 'CommonBuffId' = 291065 + WEREWOLF_PACK_RECENTLY_KICKED_OUT_B: 'CommonBuffId' = 291066 + WEREWOLF_PACK_RECENTLY_LEFT_A: 'CommonBuffId' = 290556 + WEREWOLF_PACK_RECENTLY_LEFT_B: 'CommonBuffId' = 290557 + WEREWOLF_PACK_RECENTLY_LOST_TRUST_A: 'CommonBuffId' = 290558 + WEREWOLF_PACK_RECENTLY_LOST_TRUST_B: 'CommonBuffId' = 290559 + WEREWOLF_PACK_RECENTLY_MENTORED: 'CommonBuffId' = 292322 + WEREWOLF_PACK_TRUST_AT_RISK_FRIEND_A: 'CommonBuffId' = 286995 + WEREWOLF_PACK_TRUST_AT_RISK_FRIEND_B: 'CommonBuffId' = 286996 + WEREWOLF_PACK_TRUST_WARNING_COOLDOWN_FRIEND_A: 'CommonBuffId' = 287043 + WEREWOLF_PACK_TRUST_WARNING_COOLDOWN_FRIEND_B: 'CommonBuffId' = 287044 + WEREWOLF_PACK_UPHOLDING_PACK_VALUES: 'CommonBuffId' = 290471 + WEREWOLF_PACK_VALUE_EXPAND_EXPLORE_VISITING: 'CommonBuffId' = 289138 + WEREWOLF_PACK_VALUE_EXPAND_EXPLORE_VISIT_GAIN: 'CommonBuffId' = 289382 + WEREWOLF_PACK_VALUE_MOD_DIPLOMACY: 'CommonBuffId' = 289119 + WEREWOLF_PACK_VALUE_MOD_EXPAND_EXPLORE: 'CommonBuffId' = 289120 + WEREWOLF_PACK_VALUE_MOD_PACK_PARTICIPATION_A: 'CommonBuffId' = 289519 + WEREWOLF_PACK_VALUE_MOD_PACK_PARTICIPATION_B: 'CommonBuffId' = 289529 + WEREWOLF_PACK_VALUE_MOD_SELF_IMPROVEMENT: 'CommonBuffId' = 289123 + WEREWOLF_PACK_VALUE_MOD_SELF_SUFFICIENCY: 'CommonBuffId' = 289124 + WEREWOLF_PACK_VALUE_PAUSE_DECAY_A: 'CommonBuffId' = 298222 + WEREWOLF_PACK_VALUE_PAUSE_DECAY_B: 'CommonBuffId' = 298223 + WEREWOLF_RABBIT_HOLE_COOLDOWN: 'CommonBuffId' = 288570 + WEREWOLF_RAMPAGE: 'CommonBuffId' = 285810 + WEREWOLF_RAMPAGE_FIRST_TIME: 'CommonBuffId' = 288633 + WEREWOLF_RATHER_NOT_TALK: 'CommonBuffId' = 288598 + WEREWOLF_RAW_MEAT: 'CommonBuffId' = 290319 + WEREWOLF_ROLE_SHOW_WEREFORM: 'CommonBuffId' = 288997 + WEREWOLF_SCARED_REACTION: 'CommonBuffId' = 288087 + WEREWOLF_SHOULD_RAMPAGE_AFTER_FIGHT: 'CommonBuffId' = 290870 + WEREWOLF_SMASH_COOLDOWN: 'CommonBuffId' = 296725 + WEREWOLF_SORE_THROAT: 'CommonBuffId' = 298273 + WEREWOLF_SORE_THROAT_FORMER_LYCAN: 'CommonBuffId' = 298312 + WEREWOLF_STRONGER_THAN_I_THOUGHT: 'CommonBuffId' = 290925 + WEREWOLF_SYMPATHY_COOLDOWN: 'CommonBuffId' = 293315 + WEREWOLF_SYMPATHY_FAIL: 'CommonBuffId' = 293316 + WEREWOLF_THAT_WAS_WEIRD: 'CommonBuffId' = 288770 + WEREWOLF_TRANSFORMATION_MASTERY: 'CommonBuffId' = 288777 + WEREWOLF_WEREWOLF_AWESOME: 'CommonBuffId' = 294879 + WEREWOLF_WEREWOLF_REPAIRMAN_COOLDOWN: 'CommonBuffId' = 298904 + WEREWOLF_WET: 'CommonBuffId' = 292756 + WEREWOLF_WHAT_HAPPENED: 'CommonBuffId' = 288590 + WEREWOLF_WOLF_TOWN_RABBIT_HOLE_TRANSFORMATION: 'CommonBuffId' = 299770 + WEREWOLF_WOOHOO: 'CommonBuffId' = 293001 + WEREWOLF_WORST_HANGOVER: 'CommonBuffId' = 288592 + WEREWOLF_ZOOMIES_COOLDOWN: 'CommonBuffId' = 293627 + WETNESS_IMMUNE: 'CommonBuffId' = 190198 + WILDLIFE_ENCOUNTER_ALL_IN_THE_PREPARATION: 'CommonBuffId' = 248072 + WILDLIFE_ENCOUNTER_AS_BAD_AS_THEY_SAID: 'CommonBuffId' = 248075 + WILDLIFE_ENCOUNTER_ATTACKED: 'CommonBuffId' = 247863 + WILDLIFE_ENCOUNTER_AT_LEAST_NOT_ME: 'CommonBuffId' = 248071 + WILDLIFE_ENCOUNTER_BADLY_SCRATCHED_AND_BUFFETED: 'CommonBuffId' = 248077 + WILDLIFE_ENCOUNTER_CENTIPEDE_PANIC_RUN_ROUTE_EVENT: 'CommonBuffId' = 253928 + WILDLIFE_ENCOUNTER_DANGEROUS_OUT_HERE: 'CommonBuffId' = 248070 + WILDLIFE_ENCOUNTER_HIKING_TRAIL_ATTACK_COOLDOWN: 'CommonBuffId' = 249480 + WILDLIFE_ENCOUNTER_MIND_OVER_MENACE: 'CommonBuffId' = 248073 + WILDLIFE_ENCOUNTER_PAINFUL_BITE: 'CommonBuffId' = 248076 + WILDLIFE_ENCOUNTER_PEACEFUL_NATURE: 'CommonBuffId' = 248082 + WILDLIFE_ENCOUNTER_SHOCKING_ENCOUNTER: 'CommonBuffId' = 248078 + WILDLIFE_ENCOUNTER_SKILLFUL_SHIMMY: 'CommonBuffId' = 248074 + WILDLIFE_ENCOUNTER_SPIRITUAL_AWE: 'CommonBuffId' = 248080 + WILDLIFE_ENCOUNTER_SPIRITUAL_BLESSING: 'CommonBuffId' = 248079 + WILDLIFE_ENCOUNTER_SPIRITUAL_MISFORTUNE_BLADDER: 'CommonBuffId' = 249526 + WILDLIFE_ENCOUNTER_SPIRITUAL_MISFORTUNE_ENERGY: 'CommonBuffId' = 248081 + WILDLIFE_ENCOUNTER_SPIRITUAL_MISFORTUNE_FUN: 'CommonBuffId' = 249530 + WILDLIFE_ENCOUNTER_SPIRITUAL_MISFORTUNE_HUNGER: 'CommonBuffId' = 249529 + WILDLIFE_ENCOUNTER_SPIRITUAL_MISFORTUNE_HYGIENE: 'CommonBuffId' = 249527 + WILDLIFE_ENCOUNTER_SPIRITUAL_MISFORTUNE_SOCIAL: 'CommonBuffId' = 249528 + WISHING_WELL_ACCEPTED_FATE: 'CommonBuffId' = 131025 + WISHING_WELL_ADOPTION_PRE_APPROVED: 'CommonBuffId' = 131057 + WISHING_WELL_ALWAYS_SUNNY: 'CommonBuffId' = 131043 + WISHING_WELL_A_FEW_YEARS_YOUNGER: 'CommonBuffId' = 131050 + WISHING_WELL_CANT_GET_PREGNANT: 'CommonBuffId' = 133105 + WISHING_WELL_CANT_STOP_SMILING: 'CommonBuffId' = 131049 + WISHING_WELL_CHANCE_AT_LIFE: 'CommonBuffId' = 131022 + WISHING_WELL_EXPEDIENT_LEARNING: 'CommonBuffId' = 131030 + WISHING_WELL_EXTENDED_YOUTH: 'CommonBuffId' = 131051 + WISHING_WELL_EXTRA_VIGOR: 'CommonBuffId' = 131047 + WISHING_WELL_FEELING_YOUNG: 'CommonBuffId' = 131052 + WISHING_WELL_FOGGED_MIND: 'CommonBuffId' = 131031 + WISHING_WELL_FOREVER_CHEERFUL: 'CommonBuffId' = 131044 + WISHING_WELL_FORTUNES_ABOUND: 'CommonBuffId' = 131038 + WISHING_WELL_GRADES_DROPPED: 'CommonBuffId' = 131278 + WISHING_WELL_HAPPINESS_DOESNT_LAST_FOREVER: 'CommonBuffId' = 131046 + WISHING_WELL_HIDDEN_ALREADY_WISHED: 'CommonBuffId' = 132178 + WISHING_WELL_HIDDEN_ALWAYS_REVIVE: 'CommonBuffId' = 131231 + WISHING_WELL_HIDDEN_BLACKMAIL: 'CommonBuffId' = 131188 + WISHING_WELL_HIDDEN_CANNOT_REVIVE: 'CommonBuffId' = 131285 + WISHING_WELL_HIDDEN_ULTIMATE_PICK_UP_LINE: 'CommonBuffId' = 131189 + WISHING_WELL_HIDDEN_WHERES_MY_HAPPINESS_BROADCASTER: 'CommonBuffId' = 132123 + WISHING_WELL_HOPELESS_IN_ROMANCE: 'CommonBuffId' = 131027 + WISHING_WELL_INGREDIENTS_FOR_LIFE: 'CommonBuffId' = 132156 + WISHING_WELL_I_AM_HAPPY: 'CommonBuffId' = 131045 + WISHING_WELL_I_WISHED_FOR_BETTER_GRADES: 'CommonBuffId' = 131232 + WISHING_WELL_I_WISHED_FOR_THE_PROMOTION: 'CommonBuffId' = 131036 + WISHING_WELL_JOYS_OF_CHILDREN_ANGRY: 'CommonBuffId' = 131059 + WISHING_WELL_JOYS_OF_CHILDREN_HAPPY: 'CommonBuffId' = 131021 + WISHING_WELL_JUST_A_GHOST: 'CommonBuffId' = 131024 + WISHING_WELL_LACK_OF_TALENT: 'CommonBuffId' = 131033 + WISHING_WELL_LEAKING_HAPPINESS: 'CommonBuffId' = 131048 + WISHING_WELL_LEARNED_DARKEST_SECRETS: 'CommonBuffId' = 131039 + WISHING_WELL_LOSS_OF_YOUTH: 'CommonBuffId' = 131055 + WISHING_WELL_MICROTRANSACTIONS: 'CommonBuffId' = 131041 + WISHING_WELL_MIDAS_TOUCH: 'CommonBuffId' = 131040 + WISHING_WELL_MIND_NUMBED: 'CommonBuffId' = 131032 + WISHING_WELL_MIRACLE_REVIVAL: 'CommonBuffId' = 131229 + WISHING_WELL_MYSTICAL_ROMANCE_TIPS: 'CommonBuffId' = 131017 + WISHING_WELL_MY_SIMOLEONS_BURNED_UP: 'CommonBuffId' = 131042 + WISHING_WELL_NOT_WHAT_I_WISHED_FOR: 'CommonBuffId' = 131035 + WISHING_WELL_NOT_WHAT_I_WISHED_FOR_KIDS: 'CommonBuffId' = 133387 + WISHING_WELL_OVEREXERTED_SELF: 'CommonBuffId' = 131054 + WISHING_WELL_OVERFLOWING_VIGOR: 'CommonBuffId' = 131053 + WISHING_WELL_PERPETUAL_YOUTH: 'CommonBuffId' = 131056 + WISHING_WELL_RAISING_A_GHOST: 'CommonBuffId' = 131060 + WISHING_WELL_SKILL_LEARNED: 'CommonBuffId' = 131029 + WISHING_WELL_TRY_FOR_BABY: 'CommonBuffId' = 131058 + WISHING_WELL_ULTIMATE_FLIRTY: 'CommonBuffId' = 131018 + WISHING_WELL_UNIVERSAL_KNOWLEDGE: 'CommonBuffId' = 131028 + WISHING_WELL_WHERE_IS_MY_HAPPINESS: 'CommonBuffId' = 131020 + WISHING_WELL_WISH_NOT_GRANTED: 'CommonBuffId' = 131023 + WISHING_WELL_WON_THE_LOTTERY: 'CommonBuffId' = 131037 + WISHING_WELL_WORKED_SO_HARD: 'CommonBuffId' = 131019 + WITCH_OCCULT_BLOODLINE_ANCIENT: 'CommonBuffId' = 218079 + WITCH_OCCULT_BLOODLINE_STRONG: 'CommonBuffId' = 218078 + WITCH_OCCULT_BLOODLINE_WEAK: 'CommonBuffId' = 218077 + WITCH_OCCULT_BUILD_CHARGE_COOLDOWN: 'CommonBuffId' = 215424 + WITCH_OCCULT_BUILD_CHARGE_COOLDOWN_MAGICAL_RESONANCE: 'CommonBuffId' = 219110 + WITCH_OCCULT_CHARGE_1_CHARGED: 'CommonBuffId' = 213026 + WITCH_OCCULT_CHARGE_2_OVERCHARGED: 'CommonBuffId' = 213028 + WITCH_OCCULT_CHARGE_3_DANGEROUSLY_OVERCHARGED: 'CommonBuffId' = 213029 + WITCH_OCCULT_CHARGE_APPLY_FX_1_CHARGED: 'CommonBuffId' = 215727 + WITCH_OCCULT_CHARGE_APPLY_FX_2_OVERCHARGED: 'CommonBuffId' = 215730 + WITCH_OCCULT_CHARGE_APPLY_FX_3_DANGEROUSLY_OVERCHARGED: 'CommonBuffId' = 215729 + WITCH_OCCULT_CHARGE_REACTION_COOLDOWN: 'CommonBuffId' = 215508 + WITCH_OCCULT_DISCHARGE_COOLDOWN: 'CommonBuffId' = 215423 + WITCH_OCCULT_DISCHARGE_COOLDOWN_MAGICAL_RESONANCE: 'CommonBuffId' = 219113 + WITCH_OCCULT_IS_WITCH: 'CommonBuffId' = 213063 + WITCH_OCCULT_IS_WITCH_ANY_AGE: 'CommonBuffId' = 217701 + WITCH_OCCULT_LOCK_CHARGE: 'CommonBuffId' = 213035 + WITCH_OCCULT_LOCK_NPC_STATS: 'CommonBuffId' = 219035 + WITCH_OCCULT_MAGIC_TRAINING_STOP: 'CommonBuffId' = 215391 + WITCH_OCCULT_MOTE_SIGHT_TIMEOUT: 'CommonBuffId' = 215166 + WITCH_OCCULT_MY_POWER_GROWS: 'CommonBuffId' = 215360 + WITCH_OCCULT_RITE_OF_ASCENSION_COOLDOWN: 'CommonBuffId' = 215285 + WITCH_OCCULT_RUN_AWAY_FORCE_PANIC: 'CommonBuffId' = 215500 + WITCH_OCCULT_SCARED_BY_MAGIC: 'CommonBuffId' = 215490 + WITCH_OCCULT_USE_WAND: 'CommonBuffId' = 215320 + WITCH_OCCULT_USE_WAND_NPC: 'CommonBuffId' = 222845 + WITCH_OVERLOAD_DID_THEY_JUST_EXPLODE: 'CommonBuffId' = 222899 + WITCH_OVERLOAD_MAGICAL_OVERLOAD: 'CommonBuffId' = 216967 + WITCH_PERKS_CHARGE_CONTROL: 'CommonBuffId' = 217120 + WITCH_PERKS_DISCHARGE: 'CommonBuffId' = 218296 + WITCH_PERKS_EXTRA_CHEMISTRY_TASTY: 'CommonBuffId' = 217234 + WITCH_PERKS_HIDDEN_KNOWLEDGE_IS_MAGIC: 'CommonBuffId' = 218017 + WITCH_PERKS_MAGICAL_RESONANCE: 'CommonBuffId' = 219095 + WITCH_PERKS_MAGICAL_RESONANCE_APPLY_FX_ACTIVE: 'CommonBuffId' = 219109 + WITCH_PERKS_MAGICAL_RESONANCE_APPLY_FX_PASSIVE: 'CommonBuffId' = 219102 + WITCH_PERKS_POTENT_POTABLES: 'CommonBuffId' = 217928 + WITCH_PERKS_SOCIALITE: 'CommonBuffId' = 219681 + WITNESSED_DEATH_FRIEND: 'CommonBuffId' = 12757 + WITNESSED_DEATH_FRIEND_DOG: 'CommonBuffId' = 174973 + WITNESSED_DEATH_LOVED_ONE: 'CommonBuffId' = 12758 + WITNESSED_DEATH_NEMESIS: 'CommonBuffId' = 12759 + WITNESSED_DEATH_NEUTRAL: 'CommonBuffId' = 12760 + WITNESSED_HORSE_DEATH_FRIEND: 'CommonBuffId' = 352683 + WITNESSED_HORSE_DEATH_NEUTRAL: 'CommonBuffId' = 352682 + WITNESSED_PET_DEATH_FRIEND: 'CommonBuffId' = 175450 + WITNESSED_PET_DEATH_NEUTRAL: 'CommonBuffId' = 175451 + WITNESSED_RESCUED_NEGLECTED_CHILD: 'CommonBuffId' = 132511 + WITNESSED_RESCUED_NEGLECTED_HORSE: 'CommonBuffId' = 328099 + WITNESSED_RESCUED_PET: 'CommonBuffId' = 165472 + WITNESSED_SOLD_ADOPTED_PET: 'CommonBuffId' = 169860 + WOLF_TOWN_ADVENTURE_COOLDOWN_A_SCULPTURE_SECRET: 'CommonBuffId' = 288723 + WOLF_TOWN_ADVENTURE_COOLDOWN_B_OPEN_REWARD: 'CommonBuffId' = 288724 + WOLF_TOWN_ADVENTURE_EXIT_MINE: 'CommonBuffId' = 288575 + WOLF_TOWN_ADVENTURE_EXIT_ON_LOT: 'CommonBuffId' = 292620 + WOLF_TOWN_ADVENTURE_EXIT_PORTA: 'CommonBuffId' = 288580 + WOLF_TOWN_ADVENTURE_EXIT_SEWER: 'CommonBuffId' = 288581 + WOLF_TOWN_ADVENTURE_HAS_EXPLORED_FOR_AWHILE: 'CommonBuffId' = 288839 + WOLF_TOWN_ADVENTURE_NEXT_MOMENT_AREA_A: 'CommonBuffId' = 288638 + WOLF_TOWN_ADVENTURE_NEXT_MOMENT_AREA_B: 'CommonBuffId' = 288639 + WOLF_TOWN_ADVENTURE_NEXT_MOMENT_AREA_C: 'CommonBuffId' = 288640 + WOLF_TOWN_ADVENTURE_NEXT_MOMENT_SPLIT_A: 'CommonBuffId' = 288641 + WOLF_TOWN_ADVENTURE_NEXT_MOMENT_SPLIT_B: 'CommonBuffId' = 288643 + WOLF_TOWN_ADVENTURE_NEXT_MOMENT_SPLIT_C: 'CommonBuffId' = 288642 + WOLF_TOWN_ADVENTURE_PREVIOUS_MOMENT_AREA_A: 'CommonBuffId' = 288602 + WOLF_TOWN_ADVENTURE_PREVIOUS_MOMENT_AREA_B: 'CommonBuffId' = 288603 + WOLF_TOWN_ADVENTURE_PREVIOUS_MOMENT_AREA_C: 'CommonBuffId' = 288604 + WOLF_TOWN_ADVENTURE_PREVIOUS_MOMENT_SPLIT_A: 'CommonBuffId' = 288605 + WOLF_TOWN_ADVENTURE_PREVIOUS_MOMENT_SPLIT_B: 'CommonBuffId' = 288606 + WOLF_TOWN_ADVENTURE_PREVIOUS_MOMENT_SPLIT_C: 'CommonBuffId' = 288607 + WOLF_TOWN_DEBUG_BEAT_GREG: 'CommonBuffId' = 294238 + WOLF_TOWN_GREGS_GIFT: 'CommonBuffId' = 290243 + WOLF_TOWN_GREGS_GIFT_FROM_ASKING: 'CommonBuffId' = 290245 + WOLF_TOWN_GREGS_GIFT_MOTIVE_CHANGE: 'CommonBuffId' = 294848 + WOLF_TOWN_GREG_COMMUNICATION_DEFAULT: 'CommonBuffId' = 290130 + WOLF_TOWN_GREG_COMMUNICATION_MORE: 'CommonBuffId' = 290131 + WOLF_TOWN_GREG_DANGEROUS_SCENT: 'CommonBuffId' = 290120 + WOLF_TOWN_GREG_SOMETHINGS_WATCHING: 'CommonBuffId' = 290121 + WOLF_TOWN_GREG_SOMETHINGS_WATCHING_PARANOID: 'CommonBuffId' = 290123 + WOLF_TOWN_HOWL_SPOT_NIGHT: 'CommonBuffId' = 297835 + WOLF_TOWN_IN_REGION: 'CommonBuffId' = 287121 + WOLF_TOWN_LAKE_LUNVIK: 'CommonBuffId' = 291242 + WOLF_TOWN_NPC_CREATE_OBJECT_COOLDOWN: 'CommonBuffId' = 291325 + WOLF_TOWN_NPC_GREG: 'CommonBuffId' = 290061 + WOLF_TOWN_NPC_GREG_AUTO_HOWL_COOLDOWN: 'CommonBuffId' = 294572 + WOLF_TOWN_NPC_GREG_CONFUSED: 'CommonBuffId' = 294746 + WOLF_TOWN_NPC_GREG_FROG_COOLDOWN: 'CommonBuffId' = 300217 + WOLF_TOWN_NPC_GREG_NAP_COOLDOWN: 'CommonBuffId' = 296212 + WOLF_TOWN_NPC_GREG_NAP_COOLDOWN_SHORT: 'CommonBuffId' = 298568 + WOLF_TOWN_NPC_GREG_WANT_TO_LEAVE: 'CommonBuffId' = 294748 + WOLF_TOWN_PORTAL_ALLOWANCE_FLAG_ON_LOT: 'CommonBuffId' = 296885 + WOLF_TOWN_PORTAL_ALLOWANCE_FLAG_PORTAL_MINE: 'CommonBuffId' = 288344 + WOLF_TOWN_PORTAL_ALLOWANCE_FLAG_PORTAL_MINE_TEMP: 'CommonBuffId' = 301018 + WOLF_TOWN_PORTAL_ALLOWANCE_FLAG_PORTAL_SEWER: 'CommonBuffId' = 288345 + WOLF_TOWN_PORTAL_ALLOWANCE_FLAG_PORTAL_SEWER_MINE: 'CommonBuffId' = 288346 + WOLF_TOWN_PORTAL_ALLOWANCE_FLAG_PORTAL_SEWER_MINE_TEMP: 'CommonBuffId' = 301020 + WOLF_TOWN_PORTAL_ALLOWANCE_FLAG_PORTAL_SEWER_TEMP: 'CommonBuffId' = 301019 + WOLF_TOWN_PORTAL_BASIC_TELEPORT_FIRST_TIME: 'CommonBuffId' = 291547 + WOLF_TOWN_ROLE_BAR_WEREWOLF_ONLY: 'CommonBuffId' = 299741 + WOLF_TOWN_ROLE_FRIEND_SPAR: 'CommonBuffId' = 295337 + WOLF_TOWN_ROLE_GREG_IN_TOWN: 'CommonBuffId' = 290139 + WOLF_TOWN_ROLE_WANDER: 'CommonBuffId' = 292072 + WOLF_TOWN_ROLE_WEREWOLF_PACK_HANG_OUT_ACTIVE: 'CommonBuffId' = 290581 + WOLF_TOWN_ROLE_WEREWOLF_PACK_HANG_OUT_CHILL: 'CommonBuffId' = 290569 + WOLF_TOWN_ROLE_WEREWOLF_PACK_HANG_OUT_FOOD: 'CommonBuffId' = 290576 + WOLF_TOWN_ROLE_WEREWOLF_PACK_HANG_OUT_GARDEN: 'CommonBuffId' = 299591 + WOLF_TOWN_ROLE_WEREWOLF_PACK_HANG_OUT_SHELL_A: 'CommonBuffId' = 290562 + WOLF_TOWN_ROLE_WEREWOLF_PACK_HANG_OUT_SHELL_B: 'CommonBuffId' = 290563 + WOLF_TOWN_SIM_BEAT_GREG_HIDDEN: 'CommonBuffId' = 294237 + WOLF_TOWN_WOLF_EYES_EVERYWHERE: 'CommonBuffId' = 291282 + WOLF_TOWN_WOLF_EYES_EVERYWHERE_COOLDOWN: 'CommonBuffId' = 291287 + WON_FIGHT: 'CommonBuffId' = 12763 + WON_FIGHT_BEAR: 'CommonBuffId' = 108104 + WON_FIGHT_MEAN: 'CommonBuffId' = 36147 + WON_FIGHT_SUPER_NATURAL_SUPERIORITY: 'CommonBuffId' = 287975 + WON_FIGHT_VILLAIN: 'CommonBuffId' = 99533 + WOOHOO_AUTONOMY_COOLDOWN: 'CommonBuffId' = 132485 + WOOHOO_FIRST_TIME: 'CommonBuffId' = 99544 + WOOHOO_HAPPY_HOT_SPRINGS_COMPLETELY: 'CommonBuffId' = 248753 + WOOHOO_HAPPY_HOT_SPRINGS_PLEASANTLY: 'CommonBuffId' = 248752 + WOOHOO_HAPPY_LIVESTOCK_PEN_COMPLETELY: 'CommonBuffId' = 263125 + WOOHOO_HAPPY_LIVESTOCK_PEN_COMPLETELY_SLOB: 'CommonBuffId' = 263133 + WOOHOO_HAPPY_LIVESTOCK_PEN_PLEASANTLY: 'CommonBuffId' = 263126 + WOOHOO_HAPPY_ROMANTIC_BLANKET: 'CommonBuffId' = 366918 + WOOHOO_PLEASANTLY_SATISFIED_TEEN: 'CommonBuffId' = 97166 + WOOHOO_SEEING_STARS_TEEN: 'CommonBuffId' = 97181 + WOOHOO_SLEEPING_POD: 'CommonBuffId' = 200578 + WOOHOO_SLEEPING_POD_TEEN: 'CommonBuffId' = 200579 + WOOHOO_WITH_GHOST: 'CommonBuffId' = 102773 + WORKOUT_ENTHUSIASM: 'CommonBuffId' = 26365 + WORKOUT_VIDEOS_COMPLETED_POSE_1: 'CommonBuffId' = 166904 + WORKOUT_VIDEOS_COMPLETED_POSE_2: 'CommonBuffId' = 166905 + WORKOUT_VIDEOS_COMPLETED_POSE_3: 'CommonBuffId' = 166906 + WORKOUT_VIDEOS_COMPLETED_POSE_4: 'CommonBuffId' = 166907 + WORKOUT_VIDEOS_COMPLETED_POSE_5: 'CommonBuffId' = 166910 + WORKOUT_VIDEOS_COMPLETED_POSE_6: 'CommonBuffId' = 166911 + WORKOUT_VIDEOS_COMPLETED_POSE_7: 'CommonBuffId' = 166912 + WORKOUT_VIDEOS_COMPLETED_POSE_8: 'CommonBuffId' = 166913 + WORK_RIVAL_ADD_BIT_DELAYED: 'CommonBuffId' = 335741 + WORK_RIVAL_COOLDOWN: 'CommonBuffId' = 308711 + WORK_RIVAL_DEBUG_INCREASE_CHANCE: 'CommonBuffId' = 333237 + WORK_RIVAL_GUILTY_SABOTEUR: 'CommonBuffId' = 309021 + WORK_RIVAL_SATISFIED_SABOTEUR: 'CommonBuffId' = 309022 + XP_BOOSTS_FRIENDSHIP_REL_GAIN: 'CommonBuffId' = 149979 + XP_BOOSTS_FRIENDSHIP_REL_GAIN_CHILD: 'CommonBuffId' = 156796 + XP_BOOSTS_JOB_PERFORMANCE: 'CommonBuffId' = 149681 + XP_BOOSTS_MOTIVE_DECAY_DECREASE: 'CommonBuffId' = 149985 + XP_BOOSTS_MOTIVE_DECREASE_HYGIENE_HUNGER: 'CommonBuffId' = 189808 + XP_BOOSTS_SATISFACTION_POINTS_GAIN: 'CommonBuffId' = 149983 + XP_BOOSTS_SKILL_BOOST: 'CommonBuffId' = 149980 + XP_BOOSTS_SKILL_BOOST_ARTS: 'CommonBuffId' = 189806 + XP_BOOSTS_SKILL_BOOST_GARDENING_CULINARY: 'CommonBuffId' = 189785 + ZONE_MODIFIERS_CELEBRITY_HOME_LOT_TRAIT_EMBARRASSED: 'CommonBuffId' = 199708 + ZONE_MODIFIERS_CELEBRITY_HOME_LOT_TRAIT_HAPPY: 'CommonBuffId' = 199707 + ZONE_MODIFIERS_CELEBRITY_HOME_LOT_TRAIT_INVITED: 'CommonBuffId' = 199715 + ZONE_MODIFIERS_GEOTHERMAL_EFFECTIVE_TEMPERATURE: 'CommonBuffId' = 231818 + ZONE_MODIFIERS_GEOTHERMAL_SWIMMING_HAPPY: 'CommonBuffId' = 231825 + ZONE_MODIFIERS_NATURAL_WELL_DRINK_WATER_HAPPY: 'CommonBuffId' = 231826 + ZONE_MODIFIERS_NATURAL_WELL_EFFECTIVE_TEMPERATURE: 'CommonBuffId' = 231822 + ZONE_MODIFIERS_TINY_HOME_IDLE: 'CommonBuffId' = 230506 + ZONE_MODIFIERS_TINY_HOME_TIER_1: 'CommonBuffId' = 230340 + ZONE_MODIFIERS_TINY_HOME_TIER_2: 'CommonBuffId' = 230341 + ZONE_MODIFIERS_TINY_HOME_TIER_3: 'CommonBuffId' = 230342 + ZONE_MODIFIERS_VOLCANIC_ACTIVITY_MAJOR: 'CommonBuffId' = 208364 + ZONE_MODIFIERS_VOLCANIC_ACTIVITY_MINOR: 'CommonBuffId' = 208362 + ZONE_MODS_PETS_BREEDING_GROUND_ENERGIZED: 'CommonBuffId' = 172937 + ZONE_MODS_PETS_BREEDING_GROUND_VFX_HIDDEN: 'CommonBuffId' = 172935 + ZONE_MODS_PETS_TRAINING_GROUND_VFX_HIDDEN: 'CommonBuffId' = 172967 + ZONE_MODS_STUDY_SPOT: 'CommonBuffId' = 225841 + ZONE_MODS_STUDY_SPOT_STUDYING_HIGH: 'CommonBuffId' = 229230 + ZONE_MODS_STUDY_SPOT_STUDYING_LOW: 'CommonBuffId' = 229229 + ZONE_MODS_TRAIT_GREAT_VIEW_AUTONOMOUS_COOLDOWN_HIDDEN: 'CommonBuffId' = 155944 + ZONE_MOD_APARTMENT_CON_HAUNTED_TENSE: 'CommonBuffId' = 145596 + ZONE_MOD_CELEBRITY_HANG_OUT_LOW_FAME: 'CommonBuffId' = 191748 + ZONE_MOD_PRO_CHEFS_KITCHEN_VISIBLE: 'CommonBuffId' = 141962 + ZONE_MOD_PRO_CON_PRICEY_VISIBLE: 'CommonBuffId' = 152357 + ZONE_MOD_PRO_HOME_STUDIO_VISIBLE: 'CommonBuffId' = 141964 + ZONE_MOD_TRAIT_CHEFS_KITCHEN_VFX_HIDDEN: 'CommonBuffId' = 151957 + ZONE_MOD_TRAIT_CHILDS_PLAY_PLAYFUL_ADULT: 'CommonBuffId' = 147683 + ZONE_MOD_TRAIT_CHILDS_PLAY_PLAYFUL_CHILD_VISIBLE: 'CommonBuffId' = 147686 + ZONE_MOD_TRAIT_CHILDS_PLAY_VFX_HIDDEN: 'CommonBuffId' = 151960 + ZONE_MOD_TRAIT_CURSED_HIDDEN: 'CommonBuffId' = 154593 + ZONE_MOD_TRAIT_HOME_STUDIO_HANDINESS_VFX_HIDDEN: 'CommonBuffId' = 152191 + ZONE_MOD_TRAIT_HOME_STUDIO_VFX_HIDDEN: 'CommonBuffId' = 151958 + ZONE_MOD_TRAIT_MEAN_VIBE_ANGRY: 'CommonBuffId' = 145688 + ZONE_MOD_TRAIT_ON_LEY_LINE_ENERGIZED: 'CommonBuffId' = 147689 + ZONE_MOD_TRAIT_ON_LEY_LINE_VFX_HIDDEN: 'CommonBuffId' = 154284 + ZONE_MOD_TRAIT_PENNY_PIXIES_HAPPY: 'CommonBuffId' = 145693 + ZONE_MOD_TRAIT_PENNY_PIXIES_VFX_HIDDEN: 'CommonBuffId' = 145694 + ZONE_MOD_TRAIT_QUAKE_ZONE_REACTION_DELAY_MAJOR_HIDDEN: 'CommonBuffId' = 153353 + ZONE_MOD_TRAIT_QUAKE_ZONE_REACTION_DELAY_MINOR_HIDDEN: 'CommonBuffId' = 153092 + ZONE_MOD_TRAIT_QUAKE_ZONE_SCARED_ACTIVE_PET_CAT: 'CommonBuffId' = 176922 + ZONE_MOD_TRAIT_QUAKE_ZONE_SCARED_ACTIVE_PET_DOG: 'CommonBuffId' = 176919 + ZONE_MOD_TRAIT_QUAKE_ZONE_TENSE_ACTIVE: 'CommonBuffId' = 148228 + ZONE_MOD_TRAIT_QUAKE_ZONE_TENSE_PASSIVE: 'CommonBuffId' = 147685 + ZONE_MOD_TRAIT_ROMANTIC_ATMOSPHERE_CONFIDENT: 'CommonBuffId' = 145710 + ZONE_MOD_TRAIT_ROMANTIC_ATMOSPHERE_FLIRTY: 'CommonBuffId' = 145711 + ZONE_MOD_TRAIT_SUNNY_ASPECT_ENERGIZED: 'CommonBuffId' = 145551 + ZONE_MOD_TRAIT_SUNNY_ASPECT_HAPPY: 'CommonBuffId' = 153172 + ZONE_MOD_TRAIT_SUNNY_ASPECT_INSPIRED: 'CommonBuffId' = 153171 diff --git a/Scripts/s4ap/sims4communitylib/enums/clubs_enum.py b/Scripts/s4ap/sims4communitylib/enums/clubs_enum.py new file mode 100644 index 0000000..245ca17 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/clubs_enum.py @@ -0,0 +1,108 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonClubInteractionGroupId(CommonInt): + """Identifiers for vanilla club activities. + + """ + INVALID: 'CommonClubInteractionGroupId' = 0 + FOOD_AND_DRINK_GRILLED_CHEESE: 'CommonClubInteractionGroupId' = 132512 + FUN_AND_GAMES_BASKETBALL: 'CommonClubInteractionGroupId' = 151720 + FUN_AND_GAMES_SLIPPY_SLIDE: 'CommonClubInteractionGroupId' = 140842 + HOBBIES_BATTLE_MONSTERS: 'CommonClubInteractionGroupId' = 134452 + HOBBIES_PUPPET_PERFORMANCE: 'CommonClubInteractionGroupId' = 134451 + KLEPTO_SWIPE_OBJECTS: 'CommonClubInteractionGroupId' = 132513 + OBJECT_BASED_HOT_TUB_SP02: 'CommonClubInteractionGroupId' = 130264 + OBJECT_BASED_BONFIRE: 'CommonClubInteractionGroupId' = 123557 + OBJECT_BASED_BROWSE_WEB: 'CommonClubInteractionGroupId' = 129741 + OBJECT_BASED_BUBBLE_BLOWER: 'CommonClubInteractionGroupId' = 180935 + OBJECT_BASED_CLEAN: 'CommonClubInteractionGroupId' = 122483 + OBJECT_BASED_DANCE: 'CommonClubInteractionGroupId' = 122479 + OBJECT_BASED_DO_HOMEWORK: 'CommonClubInteractionGroupId' = 127699 + OBJECT_BASED_DRINK_BAR_DRINKS: 'CommonClubInteractionGroupId' = 122484 + OBJECT_BASED_DRINK_ESPRESSO: 'CommonClubInteractionGroupId' = 127694 + OBJECT_BASED_EAT: 'CommonClubInteractionGroupId' = 122480 + OBJECT_BASED_EXCAVATE: 'CommonClubInteractionGroupId' = 182934 + OBJECT_BASED_GATHER_FROGS: 'CommonClubInteractionGroupId' = 129789 + OBJECT_BASED_GRILL: 'CommonClubInteractionGroupId' = 122477 + OBJECT_BASED_LISTEN_TO_MUSIC: 'CommonClubInteractionGroupId' = 122469 + OBJECT_BASED_MAZE_WANDER: 'CommonClubInteractionGroupId' = 128518 + OBJECT_BASED_MEDITATE: 'CommonClubInteractionGroupId' = 129744 + OBJECT_BASED_MOVIES: 'CommonClubInteractionGroupId' = 129625 + OBJECT_BASED_PLAY_ARCADE_MACHINE: 'CommonClubInteractionGroupId' = 128638 + OBJECT_BASED_PLAY_BOWLING: 'CommonClubInteractionGroupId' = 161275 + OBJECT_BASED_PLAY_CARDS: 'CommonClubInteractionGroupId' = 122470 + OBJECT_BASED_PLAY_DARTS: 'CommonClubInteractionGroupId' = 128331 + OBJECT_BASED_PLAY_DONT_WAKE_THE_LLAMA: 'CommonClubInteractionGroupId' = 128334 + OBJECT_BASED_PLAY_FOOSBALL: 'CommonClubInteractionGroupId' = 128328 + OBJECT_BASED_PLAY_HORSESHOES: 'CommonClubInteractionGroupId' = 128631 + OBJECT_BASED_PLAY_IN_CLOSET: 'CommonClubInteractionGroupId' = 127750 + OBJECT_BASED_PLAY_ON_PLAY_GROUND: 'CommonClubInteractionGroupId' = 122471 + OBJECT_BASED_PLAY_PHYSICAL_GAMES: 'CommonClubInteractionGroupId' = 128505 + OBJECT_BASED_PLAY_PUB_GAMES: 'CommonClubInteractionGroupId' = 128541 + OBJECT_BASED_PLAY_WITH_TOYS: 'CommonClubInteractionGroupId' = 122473 + OBJECT_BASED_POPCORN: 'CommonClubInteractionGroupId' = 179311 + OBJECT_BASED_POSSESS: 'CommonClubInteractionGroupId' = 128422 + OBJECT_BASED_READ: 'CommonClubInteractionGroupId' = 122482 + OBJECT_BASED_SABOTAGE: 'CommonClubInteractionGroupId' = 128499 + OBJECT_BASED_SHOWER_AND_BATHE: 'CommonClubInteractionGroupId' = 122481 + OBJECT_BASED_SLEEP: 'CommonClubInteractionGroupId' = 122478 + OBJECT_BASED_SWIM: 'CommonClubInteractionGroupId' = 122476 + OBJECT_BASED_TRY_ON_OUTFITS: 'CommonClubInteractionGroupId' = 128542 + OBJECT_BASED_USE_JUMP_STAND: 'CommonClubInteractionGroupId' = 129742 + OBJECT_BASED_USE_SCIENCE_OBJECTS: 'CommonClubInteractionGroupId' = 126323 + OBJECT_BASED_VIE_WART: 'CommonClubInteractionGroupId' = 122472 + OBJECT_BASED_WATCH_LIVE_ENTERTAINMENT: 'CommonClubInteractionGroupId' = 129105 + OBJECT_BASED_WATCH_TV: 'CommonClubInteractionGroupId' = 122468 + OBJECT_BASED_YOGA: 'CommonClubInteractionGroupId' = 129745 + OTHER_USE_ALIEN_POWERS: 'CommonClubInteractionGroupId' = 126319 + OUTDOOR_PLAY_IN_FOUNTAIN: 'CommonClubInteractionGroupId' = 132964 + ROAR: 'CommonClubInteractionGroupId' = 128338 + SKILL_BUILDING_BAKING: 'CommonClubInteractionGroupId' = 126320 + SKILL_BUILDING_COOK: 'CommonClubInteractionGroupId' = 122443 + SKILL_BUILDING_DJ: 'CommonClubInteractionGroupId' = 122547 + SKILL_BUILDING_DO_COMEDY: 'CommonClubInteractionGroupId' = 122434 + SKILL_BUILDING_FISH: 'CommonClubInteractionGroupId' = 122444 + SKILL_BUILDING_FITNESS_WORKOUT: 'CommonClubInteractionGroupId' = 121923 + SKILL_BUILDING_FIX_OBJECTS: 'CommonClubInteractionGroupId' = 122450 + SKILL_BUILDING_GARDEN: 'CommonClubInteractionGroupId' = 122445 + SKILL_BUILDING_HACK: 'CommonClubInteractionGroupId' = 122437 + SKILL_BUILDING_MIX_BAR_DRINKS: 'CommonClubInteractionGroupId' = 122436 + SKILL_BUILDING_PAINT: 'CommonClubInteractionGroupId' = 122433 + SKILL_BUILDING_PLAY_AN_INSTRUMENT: 'CommonClubInteractionGroupId' = 122446 + SKILL_BUILDING_PLAY_CHESS: 'CommonClubInteractionGroupId' = 121700 + SKILL_BUILDING_PLAY_GUITAR: 'CommonClubInteractionGroupId' = 122447 + SKILL_BUILDING_PLAY_PIANO: 'CommonClubInteractionGroupId' = 122448 + SKILL_BUILDING_PLAY_PIPE_ORGAN: 'CommonClubInteractionGroupId' = 152374 + SKILL_BUILDING_PLAY_VIDEO_GAMES: 'CommonClubInteractionGroupId' = 122439 + SKILL_BUILDING_PLAY_VIOLIN: 'CommonClubInteractionGroupId' = 122449 + SKILL_BUILDING_PROGRAM: 'CommonClubInteractionGroupId' = 122438 + SKILL_BUILDING_ROCKET_SCIENCE_ACTIONS: 'CommonClubInteractionGroupId' = 121552 + SKILL_BUILDING_SINGING: 'CommonClubInteractionGroupId' = 149981 + SKILL_BUILDING_USE_MICROSCOPE: 'CommonClubInteractionGroupId' = 122452 + SKILL_BUILDING_USE_SCIENCE_TABLE: 'CommonClubInteractionGroupId' = 127751 + SKILL_BUILDING_USE_TELESCOPE: 'CommonClubInteractionGroupId' = 122435 + SKILL_BUILDING_WELLNESS: 'CommonClubInteractionGroupId' = 126340 + SKILL_BUILDING_WOODWORK: 'CommonClubInteractionGroupId' = 122441 + SKILL_BUILDING_WRITE: 'CommonClubInteractionGroupId' = 122440 + SOCIAL_BE_FRIENDLY: 'CommonClubInteractionGroupId' = 122422 + SOCIAL_BE_FUNNY: 'CommonClubInteractionGroupId' = 122426 + SOCIAL_BE_MEAN: 'CommonClubInteractionGroupId' = 121698 + SOCIAL_BE_MISCHIEVOUS: 'CommonClubInteractionGroupId' = 122429 + SOCIAL_BE_ROMANTIC: 'CommonClubInteractionGroupId' = 122431 + SOCIAL_FIGHT: 'CommonClubInteractionGroupId' = 122428 + SOCIAL_GIVE_SPEECHES: 'CommonClubInteractionGroupId' = 151396 + SOCIAL_HUG: 'CommonClubInteractionGroupId' = 122421 + SOCIAL_KISS: 'CommonClubInteractionGroupId' = 122424 + SOCIAL_SCARE: 'CommonClubInteractionGroupId' = 122430 + SOCIAL_TELL_JOKES: 'CommonClubInteractionGroupId' = 122427 + SOCIAL_WOOHOO: 'CommonClubInteractionGroupId' = 121679 + VAMPIRE_DRINK_PLASMA: 'CommonClubInteractionGroupId' = 154430 + VAMPIRE_USE_POWERS: 'CommonClubInteractionGroupId' = 154429 diff --git a/Scripts/s4ap/sims4communitylib/enums/common_age.py b/Scripts/s4ap/sims4communitylib/enums/common_age.py new file mode 100644 index 0000000..723ac8a --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_age.py @@ -0,0 +1,184 @@ +""" +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 +""" +from typing import Dict, Union, Tuple, Iterator + +from sims.sim_info import SimInfo +from sims.sim_info_types import Age +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonAge(CommonInt): + """Custom Age enum containing all ages, because there have been too many problems when referencing the vanilla Age in various places. + + """ + INVALID: 'CommonAge' = 0 + BABY: 'CommonAge' = 1 + INFANT: 'CommonAge' = 2 + TODDLER: 'CommonAge' = 4 + CHILD: 'CommonAge' = 8 + TEEN: 'CommonAge' = 16 + YOUNGADULT: 'CommonAge' = 32 + ADULT: 'CommonAge' = 64 + ELDER: 'CommonAge' = 128 + + @classmethod + def get_all(cls, exclude_values: Iterator['CommonAge'] = None) -> Tuple['CommonAge']: + """get_all(exclude_values=None) + + Get a collection of all values. + + :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonAge], optional + :return: A collection of all values. + :rtype: Tuple[CommonAge] + """ + if exclude_values is None: + exclude_values = (cls.INVALID,) + # noinspection PyTypeChecker + value_list: Tuple[CommonAge, ...] = tuple([value for value in cls.values if value not in exclude_values]) + return value_list + + @classmethod + def get_all_names(cls, exclude_values: Iterator['CommonAge'] = None) -> Tuple[str]: + """get_all_names(exclude_values=None) + + Retrieve a collection of the names of all values. + + :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonAge], optional + :return: A collection of the names of all values. + :rtype: Tuple[str] + """ + name_list: Tuple[str] = tuple([value.name for value in cls.get_all(exclude_values=exclude_values)]) + return name_list + + @classmethod + def get_comma_separated_names_string(cls, exclude_values: Iterator['CommonAge'] = None) -> str: + """get_comma_separated_names_string(exclude_values=None) + + Create a string containing all names of all values, separated by a comma. + + :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonAge], optional + :return: A string containing all names of all values, separated by a comma. + :rtype: str + """ + return ', '.join(cls.get_all_names(exclude_values=exclude_values)) + + @staticmethod + def get_age(sim_info: SimInfo) -> 'CommonAge': + """get_age(sim_info) + + Retrieve the CommonAge of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The CommonAge that represents what age a Sim is or INVALID if their age cannot be determined. + :rtype: CommonAge + """ + from sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils + if CommonAgeUtils.is_baby(sim_info): + return CommonAge.BABY + elif CommonAgeUtils.is_infant(sim_info): + return CommonAge.INFANT + elif CommonAgeUtils.is_toddler(sim_info): + return CommonAge.TODDLER + elif CommonAgeUtils.is_child(sim_info): + return CommonAge.CHILD + elif CommonAgeUtils.is_teen(sim_info): + return CommonAge.TEEN + elif CommonAgeUtils.is_young_adult(sim_info): + return CommonAge.YOUNGADULT + elif CommonAgeUtils.is_adult(sim_info): + return CommonAge.ADULT + elif CommonAgeUtils.is_elder(sim_info): + return CommonAge.ELDER + return CommonAge.INVALID + + @staticmethod + def convert_to_vanilla(value: 'CommonAge') -> Union[Age, None]: + """convert_to_vanilla(value) + + Convert a CommonAge into the vanilla Age enum. + + :param value: An instance of CommonAge + :type value: CommonAge + :return: The specified CommonAge translated to Age or None if the value could not be translated. + :rtype: Union[Age, None] + """ + if value is None or value == CommonAge.INVALID: + return None + if isinstance(value, Age): + return value + age_conversion_mapping: Dict[CommonAge, Age] = { + CommonAge.BABY: Age.BABY, + CommonAge.INFANT: Age.INFANT, + CommonAge.TODDLER: Age.TODDLER, + CommonAge.CHILD: Age.CHILD, + CommonAge.TEEN: Age.TEEN, + CommonAge.YOUNGADULT: Age.YOUNGADULT, + CommonAge.ADULT: Age.ADULT, + CommonAge.ELDER: Age.ELDER + } + return age_conversion_mapping.get(value, None) + + @staticmethod + def convert_from_vanilla(value: Union[int, Age]) -> 'CommonAge': + """convert_from_vanilla(value) + + Convert a vanilla Age to a CommonAge. + + :param value: An instance of Age + :type value: Age + :return: The specified Age translated to CommonAge or INVALID if the value could not be translated. + :rtype: CommonAge + """ + if value is None: + return CommonAge.INVALID + if isinstance(value, CommonAge): + return value + age_conversion_mapping: Dict[int, CommonAge] = { + int(Age.BABY): CommonAge.BABY, + int(Age.INFANT): CommonAge.INFANT, + int(Age.TODDLER): CommonAge.TODDLER, + int(Age.CHILD): CommonAge.CHILD, + int(Age.TEEN): CommonAge.TEEN, + int(Age.YOUNGADULT): CommonAge.YOUNGADULT, + int(Age.ADULT): CommonAge.ADULT, + int(Age.ELDER): CommonAge.ELDER + } + value = int(value) + if value not in age_conversion_mapping: + return CommonAge.INVALID + return age_conversion_mapping[value] + + @staticmethod + def convert_to_localized_string_id(value: Union[int, 'CommonAge']) -> Union[int, str]: + """convert_to_localized_string_id(value) + + Convert a CommonAge into a Localized String identifier. + + :param value: An instance of a CommonAge + :type value: CommonAge + :return: The specified CommonAge translated to a localized string identifier. If no localized string id is found, the name property of the value will be used instead. + :rtype: Union[int, str] + """ + from sims4communitylib.enums.strings_enum import CommonStringId + display_name_mapping = { + CommonAge.BABY: CommonStringId.BABY, + CommonAge.INFANT: CommonStringId.INFANT, + CommonAge.TODDLER: CommonStringId.TODDLER, + CommonAge.CHILD: CommonStringId.CHILD, + CommonAge.TEEN: CommonStringId.TEEN, + CommonAge.YOUNGADULT: CommonStringId.YOUNG_ADULT, + CommonAge.ADULT: CommonStringId.ADULT, + CommonAge.ELDER: CommonStringId.ELDER + } + if isinstance(value, int) and not isinstance(value, CommonAge): + value = CommonAge.convert_from_vanilla(value) + return display_name_mapping.get(value, value.name if hasattr(value, 'name') else str(value)) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_appearance_modifier_priority.py b/Scripts/s4ap/sims4communitylib/enums/common_appearance_modifier_priority.py new file mode 100644 index 0000000..ef36d68 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_appearance_modifier_priority.py @@ -0,0 +1,121 @@ +""" +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 +""" +from typing import Union, Iterator, Tuple + +from buffs.appearance_modifier.appearance_modifier import AppearanceModifierPriority +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonAppearanceModifierPriority(CommonInt): + """Priorities for appearance modifiers. These priorities determine the order in which appearance modifiers are applied, which ones override which.""" + INVALID: 'CommonAppearanceModifierPriority' = ... + FROZEN: 'CommonAppearanceModifierPriority' = ... + MANNEQUIN: 'CommonAppearanceModifierPriority' = ... + PATIENT: 'CommonAppearanceModifierPriority' = ... + SICKNESS: 'CommonAppearanceModifierPriority' = ... + TRANSFORMED: 'CommonAppearanceModifierPriority' = ... + + @classmethod + def get_all(cls, exclude_values: Iterator['CommonAppearanceModifierPriority'] = None) -> Tuple['CommonAppearanceModifierPriority']: + """get_all(exclude_values=None) + + Get a collection of all values. + + :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonAppearanceModifierPriority], optional + :return: A collection of all values. + :rtype: Tuple[CommonAppearanceModifierPriority] + """ + if exclude_values is None: + exclude_values = (cls.INVALID,) + # noinspection PyTypeChecker + value_list: Tuple[CommonAppearanceModifierPriority, ...] = tuple([value for value in cls.values if value not in exclude_values]) + return value_list + + @classmethod + def get_all_names(cls, exclude_values: Iterator['CommonAppearanceModifierPriority'] = None) -> Tuple[str]: + """get_all_names(exclude_values=None) + + Retrieve a collection of the names of all values. + + :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonAppearanceModifierPriority], optional + :return: A collection of the names of all values. + :rtype: Tuple[str] + """ + name_list: Tuple[str] = tuple([value.name for value in cls.get_all(exclude_values=exclude_values)]) + return name_list + + @classmethod + def get_comma_separated_names_string(cls, exclude_values: Iterator['CommonAppearanceModifierPriority'] = None) -> str: + """get_comma_separated_names_string(exclude_values=None) + + Create a string containing all names of all values, separated by a comma. + + :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonAppearanceModifierPriority], optional + :return: A string containing all names of all values, separated by a comma. + :rtype: str + """ + return ', '.join(cls.get_all_names(exclude_values=exclude_values)) + + @staticmethod + def convert_to_vanilla(value: 'CommonAppearanceModifierPriority') -> AppearanceModifierPriority: + """convert_to_vanilla(value) + + Convert a value into the vanilla AppearanceModifierPriority enum. + + :param value: An instance of CommonAppearanceModifierPriority + :type value: CommonAppearanceModifierPriority + :return: The specified value translated to AppearanceModifierPriority or INVALID if the value could not be translated. + :rtype: AppearanceModifierPriority + """ + if value is None or value == CommonAppearanceModifierPriority.INVALID: + return AppearanceModifierPriority.INVALID + if isinstance(value, AppearanceModifierPriority): + return value + mapping = dict() + if hasattr(AppearanceModifierPriority, 'MANNEQUIN'): + mapping[CommonAppearanceModifierPriority.MANNEQUIN] = AppearanceModifierPriority.MANNEQUIN + if hasattr(AppearanceModifierPriority, 'SICKNESS'): + mapping[CommonAppearanceModifierPriority.SICKNESS] = AppearanceModifierPriority.SICKNESS + if hasattr(AppearanceModifierPriority, 'PATIENT'): + mapping[CommonAppearanceModifierPriority.PATIENT] = AppearanceModifierPriority.PATIENT + if hasattr(AppearanceModifierPriority, 'TRANSFORMED'): + mapping[CommonAppearanceModifierPriority.TRANSFORMED] = AppearanceModifierPriority.TRANSFORMED + if hasattr(AppearanceModifierPriority, 'FROZEN'): + mapping[CommonAppearanceModifierPriority.FROZEN] = AppearanceModifierPriority.FROZEN + return mapping.get(value, AppearanceModifierPriority.INVALID) + + @staticmethod + def convert_from_vanilla(value: Union[int, AppearanceModifierPriority]) -> 'CommonAppearanceModifierPriority': + """convert_from_vanilla(value) + + Convert a value into a CommonAppearanceModifierPriority enum. + + :param value: An instance of AppearanceModifierPriority + :type value: AppearanceModifierPriority + :return: The specified value translated to CommonAppearanceModifierPriority or INVALID if the value could not be translated. + :rtype: CommonAppearanceModifierPriority + """ + if value is None or value == AppearanceModifierPriority.INVALID: + return CommonAppearanceModifierPriority.INVALID + if isinstance(value, CommonAppearanceModifierPriority): + return value + mapping = dict() + if hasattr(AppearanceModifierPriority, 'MANNEQUIN'): + mapping[AppearanceModifierPriority.MANNEQUIN] = CommonAppearanceModifierPriority.MANNEQUIN + if hasattr(AppearanceModifierPriority, 'SICKNESS'): + mapping[AppearanceModifierPriority.SICKNESS] = CommonAppearanceModifierPriority.SICKNESS + if hasattr(AppearanceModifierPriority, 'PATIENT'): + mapping[AppearanceModifierPriority.PATIENT] = CommonAppearanceModifierPriority.PATIENT + if hasattr(AppearanceModifierPriority, 'TRANSFORMED'): + mapping[AppearanceModifierPriority.TRANSFORMED] = CommonAppearanceModifierPriority.TRANSFORMED + if hasattr(AppearanceModifierPriority, 'FROZEN'): + mapping[AppearanceModifierPriority.FROZEN] = CommonAppearanceModifierPriority.FROZEN + return mapping.get(value, CommonAppearanceModifierPriority.INVALID) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_appearance_modifier_type.py b/Scripts/s4ap/sims4communitylib/enums/common_appearance_modifier_type.py new file mode 100644 index 0000000..ac16208 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_appearance_modifier_type.py @@ -0,0 +1,18 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonAppearanceModifierType(CommonInt): + """Types for appearance modifiers.""" + SET_CAS_PART: 'CommonAppearanceModifierType' = 0 + RANDOMIZE_BODY_TYPE_COLOR: 'CommonAppearanceModifierType' = 1 + RANDOMIZE_SKIN_TONE_FROM_TAGS: 'CommonAppearanceModifierType' = 2 + GENERATE_OUTFIT: 'CommonAppearanceModifierType' = 3 + RANDOMIZE_CAS_PART: 'CommonAppearanceModifierType' = 4 + CUSTOM: 'CommonAppearanceModifierType' = 5000 diff --git a/Scripts/s4ap/sims4communitylib/enums/common_body_frame.py b/Scripts/s4ap/sims4communitylib/enums/common_body_frame.py new file mode 100644 index 0000000..8e60f1c --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_body_frame.py @@ -0,0 +1,78 @@ +""" +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 +""" +from typing import Tuple, Iterator + +from sims.sim_info import SimInfo +from sims4communitylib.enums.enumtypes.common_int import CommonInt +from sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils +from sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils + + +class CommonBodyFrame(CommonInt): + """Custom Body Frames enum containing all body frames. + + """ + INVALID: 'CommonBodyFrame' = 0 + MASCULINE: 'CommonBodyFrame' = 1 + FEMININE: 'CommonBodyFrame' = 2 + + @classmethod + def get_all(cls, exclude_values: Iterator['CommonBodyFrame'] = None) -> Tuple['CommonBodyFrame']: + """get_all(exclude_values=None) + + Get a collection of all values. + + :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonBodyFrame], optional + :return: A collection of all values. + :rtype: Tuple[CommonBodyFrame] + """ + if exclude_values is None: + exclude_values = (cls.INVALID,) + # noinspection PyTypeChecker + value_list: Tuple[CommonBodyFrame] = tuple([value for value in cls.values if value not in exclude_values]) + return value_list + + @classmethod + def get_all_names(cls, exclude_values: Iterator['CommonBodyFrame'] = None) -> Tuple[str]: + """get_all_names(exclude_values=None) + + Retrieve a collection of the names of all values. + + :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonBodyFrame], optional + :return: A collection of the names of all values. + :rtype: Tuple[str] + """ + name_list: Tuple[str] = tuple([value.name for value in cls.get_all(exclude_values=exclude_values)]) + return name_list + + @staticmethod + def get_body_frame(sim_info: SimInfo) -> 'CommonBodyFrame': + """get_body_frame(sim_info) + + Retrieve the CommonBodyFrame of a sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The body frame of the Sim or INVALID if their current body frame cannot be determined. + :rtype: CommonBodyFrame + """ + from sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils + if CommonSpeciesUtils.is_animal(sim_info): + if CommonGenderUtils.is_male(sim_info): + return CommonBodyFrame.MASCULINE + if CommonGenderUtils.is_female(sim_info): + return CommonBodyFrame.FEMININE + return CommonBodyFrame.INVALID + + if CommonSimGenderOptionUtils.has_masculine_frame(sim_info): + return CommonBodyFrame.MASCULINE + if CommonSimGenderOptionUtils.has_feminine_frame(sim_info): + return CommonBodyFrame.FEMININE + return CommonBodyFrame.INVALID diff --git a/Scripts/s4ap/sims4communitylib/enums/common_body_slot.py b/Scripts/s4ap/sims4communitylib/enums/common_body_slot.py new file mode 100644 index 0000000..8df89ac --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_body_slot.py @@ -0,0 +1,728 @@ +""" +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 +""" +from typing import Union, Iterator, Tuple + +from sims.outfits.outfit_enums import BodyType +from sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags + + +class CommonBodySlot(CommonIntFlags): + """Slots on the body of Sims that CAS Parts can be attached to.""" + NONE: 'CommonBodySlot' = 0 + ACNE: 'CommonBodySlot' = 72 + ATTACHMENT_BACK: 'CommonBodySlot' = 88 + BIRTHMARK_ARMS: 'CommonBodySlot' = 94 + BIRTHMARK_FACE: 'CommonBodySlot' = 91 + BIRTHMARK_LEGS: 'CommonBodySlot' = 98 + BIRTHMARK_TORSO_BACK: 'CommonBodySlot' = 92 + BIRTHMARK_TORSO_FRONT: 'CommonBodySlot' = 93 + BITE: 'CommonBodySlot' = 76 + BLANKET: 'CommonBodySlot' = 104 + BLUSH: 'CommonBodySlot' = 32 + BODY_FRECKLES: 'CommonBodySlot' = 77 + BODY_HAIR_ARM: 'CommonBodySlot' = 78 + BODY_HAIR_LEG: 'CommonBodySlot' = 79 + BODY_HAIR_TORSO_BACK: 'CommonBodySlot' = 81 + BODY_HAIR_TORSO_FRONT: 'CommonBodySlot' = 80 + BODY_SCAR_ARM_LEFT: 'CommonBodySlot' = 82 + BODY_SCAR_ARM_RIGHT: 'CommonBodySlot' = 83 + BODY_SCAR_LEG_LEFT: 'CommonBodySlot' = 86 + BODY_SCAR_LEG_RIGHT: 'CommonBodySlot' = 87 + BODY_SCAR_TORSO_BACK: 'CommonBodySlot' = 85 + BODY_SCAR_TORSO_FRONT: 'CommonBodySlot' = 84 + BRIDLE: 'CommonBodySlot' = 102 + BROW_RING_LEFT: 'CommonBodySlot' = 20 + BROW_RING_RIGHT: 'CommonBodySlot' = 21 + CUMMERBUND: 'CommonBodySlot' = 9 + EARRINGS: 'CommonBodySlot' = 10 + EARS: 'CommonBodySlot' = 60 + EYE_COLOR: 'CommonBodySlot' = 35 + EYE_COLOR_SECONDARY: 'CommonBodySlot' = 63 + EYE_LINER: 'CommonBodySlot' = 31 + EYE_SHADOW: 'CommonBodySlot' = 30 + EYEBROWS: 'CommonBodySlot' = 34 + FACE_PAINT: 'CommonBodySlot' = 33 + FACE_SCAR: 'CommonBodySlot' = 90 + FACIAL_HAIR: 'CommonBodySlot' = 28 + FINGERNAIL: 'CommonBodySlot' = 73 + FOREARM_SCAR: 'CommonBodySlot' = 71 + FULL_BODY: 'CommonBodySlot' = 5 + FUR_BODY: 'CommonBodySlot' = 59 + GLASSES: 'CommonBodySlot' = 11 + GLOVES: 'CommonBodySlot' = 13 + HAIR: 'CommonBodySlot' = 2 + HAIR_COLOR_OVERRIDE: 'CommonBodySlot' = 75 + HAIR_FEATHERS: 'CommonBodySlot' = 109 + HAIR_FORELOCK: 'CommonBodySlot' = 108 + HAIR_MANE: 'CommonBodySlot' = 106 + HAIR_TAIL: 'CommonBodySlot' = 107 + HAT: 'CommonBodySlot' = 1 + HEAD: 'CommonBodySlot' = 3 + HORN: 'CommonBodySlot' = 110 + INDEX_FINGER_LEFT: 'CommonBodySlot' = 22 + INDEX_FINGER_RIGHT: 'CommonBodySlot' = 23 + LIP_RING_LEFT: 'CommonBodySlot' = 16 + LIP_RING_RIGHT: 'CommonBodySlot' = 17 + LIPSTICK: 'CommonBodySlot' = 29 + LOWER_BODY: 'CommonBodySlot' = 7 + EYELASHES: 'CommonBodySlot' = 37 + MIDDLE_FINGER_LEFT: 'CommonBodySlot' = 26 + MIDDLE_FINGER_RIGHT: 'CommonBodySlot' = 27 + MOLE_BACK_UPPER: 'CommonBodySlot' = 97 + MOLE_CHEST_UPPER: 'CommonBodySlot' = 96 + MOLE_FACE: 'CommonBodySlot' = 95 + NECKLACE: 'CommonBodySlot' = 12 + NOSE_RING_LEFT: 'CommonBodySlot' = 18 + NOSE_RING_RIGHT: 'CommonBodySlot' = 19 + OCCULT_BROW: 'CommonBodySlot' = 64 + OCCULT_EYE_SOCKET: 'CommonBodySlot' = 65 + OCCULT_EYELID: 'CommonBodySlot' = 66 + OCCULT_LEFT_CHEEK: 'CommonBodySlot' = 68 + OCCULT_MOUTH: 'CommonBodySlot' = 67 + OCCULT_NECK_SCAR: 'CommonBodySlot' = 70 + OCCULT_RIGHT_CHEEK: 'CommonBodySlot' = 69 + REINS: 'CommonBodySlot' = 103 + RING_FINGER_LEFT: 'CommonBodySlot' = 24 + RING_FINGER_RIGHT: 'CommonBodySlot' = 25 + SADDLE: 'CommonBodySlot' = 101 + SHOES: 'CommonBodySlot' = 8 + SKIN_DETAIL_ACNE_PUBERTY: 'CommonBodySlot' = 89 + SKIN_DETAIL_CREASE_FOREHEAD: 'CommonBodySlot' = 38 + SKIN_DETAIL_CREASE_MOUTH: 'CommonBodySlot' = 57 + SKIN_DETAIL_DIMPLE_LEFT: 'CommonBodySlot' = 40 + SKIN_DETAIL_DIMPLE_RIGHT: 'CommonBodySlot' = 41 + SKIN_DETAIL_FRECKLES: 'CommonBodySlot' = 39 + SKIN_DETAIL_HOOF_COLOR: 'CommonBodySlot' = 105 + SKIN_DETAIL_MOLE_CHEEK_LEFT: 'CommonBodySlot' = 55 + SKIN_DETAIL_MOLE_CHEEK_RIGHT: 'CommonBodySlot' = 56 + SKIN_DETAIL_MOLE_LIP_LEFT: 'CommonBodySlot' = 43 + SKIN_DETAIL_MOLE_LIP_RIGHT: 'CommonBodySlot' = 44 + SKIN_DETAIL_NOSE_COLOR: 'CommonBodySlot' = 62 + SKIN_OVERLAY: 'CommonBodySlot' = 58 + SOCKS: 'CommonBodySlot' = 36 + STRETCH_MARKS_BACK: 'CommonBodySlot' = 100 + STRETCH_MARKS_FRONT: 'CommonBodySlot' = 99 + TAIL: 'CommonBodySlot' = 61 + TAIL_BASE: 'CommonBodySlot' = 111 + TATTOO_ARM_LOWER_LEFT: 'CommonBodySlot' = 45 + TATTOO_ARM_LOWER_RIGHT: 'CommonBodySlot' = 47 + TATTOO_ARM_UPPER_LEFT: 'CommonBodySlot' = 46 + TATTOO_ARM_UPPER_RIGHT: 'CommonBodySlot' = 48 + TATTOO_LEG_LEFT: 'CommonBodySlot' = 49 + TATTOO_LEG_RIGHT: 'CommonBodySlot' = 50 + TATTOO_TORSO_BACK_LOWER: 'CommonBodySlot' = 51 + TATTOO_TORSO_BACK_UPPER: 'CommonBodySlot' = 52 + TATTOO_TORSO_FRONT_LOWER: 'CommonBodySlot' = 53 + TATTOO_TORSO_FRONT_UPPER: 'CommonBodySlot' = 54 + TEETH: 'CommonBodySlot' = 4 + TIGHTS: 'CommonBodySlot' = 42 + TOENAIL: 'CommonBodySlot' = 74 + UPPER_BODY: 'CommonBodySlot' = 6 + WRIST_LEFT: 'CommonBodySlot' = 14 + WRIST_RIGHT: 'CommonBodySlot' = 15 + + @classmethod + def get_all(cls, exclude_values: Iterator['CommonBodySlot'] = None) -> Tuple['CommonBodySlot']: + """get_all(exclude_values=None) + + Get a collection of all values. + + :param exclude_values: These values will be excluded. If set to None, NONE will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonBodySlot], optional + :return: A collection of all values. + :rtype: Tuple[CommonBodySlot] + """ + if exclude_values is None: + exclude_values = (cls.NONE,) + # noinspection PyTypeChecker + value_list: Tuple[CommonBodySlot, ...] = tuple([value for value in cls.values if value not in exclude_values]) + return value_list + + @classmethod + def get_all_names(cls, exclude_values: Iterator['CommonBodySlot'] = None) -> Tuple[str]: + """get_all_names(exclude_values=None) + + Retrieve a collection of the names of all values. + + :param exclude_values: These values will be excluded. If set to None, NONE will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonBodySlot], optional + :return: A collection of the names of all values. + :rtype: Tuple[str] + """ + name_list: Tuple[str] = tuple([value.name for value in cls.get_all(exclude_values=exclude_values)]) + return name_list + + @classmethod + def get_comma_separated_names_string(cls, exclude_values: Iterator['CommonBodySlot'] = None) -> str: + """get_comma_separated_names_string(exclude_values=None) + + Create a string containing all names of all values, separated by a comma. + + :param exclude_values: These values will be excluded. If set to None, NONE will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonBodySlot], optional + :return: A string containing all names of all values, separated by a comma. + :rtype: str + """ + return ', '.join(cls.get_all_names(exclude_values=exclude_values)) + + @staticmethod + def convert_to_vanilla(value: Union['CommonBodySlot', BodyType, int]) -> Union[BodyType, 'CommonBodySlot', int]: + """convert_to_vanilla(value) + + Convert a CommonBodySlot into the vanilla BodyType enum. + + :param value: An instance of a CommonBodySlot + :type value: CommonBodySlot + :return: The specified CommonBodySlot translated to a BodyType or the value itself if the CommonBodySlot could not be translated. + :rtype: Union[BodyType, int] + """ + if value is None or value == CommonBodySlot.NONE: + return BodyType.NONE + if isinstance(value, BodyType): + return value + mapping = dict() + if hasattr(BodyType, 'ACNE'): + mapping[CommonBodySlot.ACNE] = BodyType.ACNE + if hasattr(BodyType, 'ATTACHMENT_BACK'): + mapping[CommonBodySlot.ATTACHMENT_BACK] = BodyType.ATTACHMENT_BACK + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'BIRTHMARKARMS'): + mapping[CommonBodySlot.BIRTHMARK_ARMS] = BodyType.BIRTHMARKARMS + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'BIRTHMARKFACE'): + mapping[CommonBodySlot.BIRTHMARK_FACE] = BodyType.BIRTHMARKFACE + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'BIRTHMARKLEGS'): + mapping[CommonBodySlot.BIRTHMARK_LEGS] = BodyType.BIRTHMARKLEGS + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'BIRTHMARKTORSOBACK'): + mapping[CommonBodySlot.BIRTHMARK_TORSO_BACK] = BodyType.BIRTHMARKTORSOBACK + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'BIRTHMARKTORSOFRONT'): + mapping[CommonBodySlot.BIRTHMARK_TORSO_FRONT] = BodyType.BIRTHMARKTORSOFRONT + if hasattr(BodyType, 'BITE'): + mapping[CommonBodySlot.BITE] = BodyType.BITE + if hasattr(BodyType, 'BLANKET'): + mapping[CommonBodySlot.BLANKET] = BodyType.BLANKET + if hasattr(BodyType, 'BLUSH'): + mapping[CommonBodySlot.BLUSH] = BodyType.BLUSH + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'BODYFRECKLES'): + mapping[CommonBodySlot.BODY_FRECKLES] = BodyType.BODYFRECKLES + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'BODYHAIR_ARM'): + mapping[CommonBodySlot.BODY_HAIR_ARM] = BodyType.BODYHAIR_ARM + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'BODYHAIR_LEG'): + mapping[CommonBodySlot.BODY_HAIR_LEG] = BodyType.BODYHAIR_LEG + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'BODYHAIR_TORSOBACK'): + mapping[CommonBodySlot.BODY_HAIR_TORSO_BACK] = BodyType.BODYHAIR_TORSOBACK + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'BODYHAIR_TORSOFRONT'): + mapping[CommonBodySlot.BODY_HAIR_TORSO_FRONT] = BodyType.BODYHAIR_TORSOFRONT + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'BODYSCAR_ARMLEFT'): + mapping[CommonBodySlot.BODY_SCAR_ARM_LEFT] = BodyType.BODYSCAR_ARMLEFT + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'BODYSCAR_ARMRIGHT'): + mapping[CommonBodySlot.BODY_SCAR_ARM_RIGHT] = BodyType.BODYSCAR_ARMRIGHT + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'BODYSCAR_LEGLEFT'): + mapping[CommonBodySlot.BODY_SCAR_LEG_LEFT] = BodyType.BODYSCAR_LEGLEFT + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'BODYSCAR_LEGRIGHT'): + mapping[CommonBodySlot.BODY_SCAR_LEG_RIGHT] = BodyType.BODYSCAR_LEGRIGHT + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'BODYSCAR_TORSOBACK'): + mapping[CommonBodySlot.BODY_SCAR_TORSO_BACK] = BodyType.BODYSCAR_TORSOBACK + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'BODYSCAR_TORSOFRONT'): + mapping[CommonBodySlot.BODY_SCAR_TORSO_FRONT] = BodyType.BODYSCAR_TORSOFRONT + if hasattr(BodyType, 'BRIDLE'): + mapping[CommonBodySlot.BRIDLE] = BodyType.BRIDLE + if hasattr(BodyType, 'BROW_RING_LEFT'): + mapping[CommonBodySlot.BROW_RING_LEFT] = BodyType.BROW_RING_LEFT + if hasattr(BodyType, 'BROW_RING_RIGHT'): + mapping[CommonBodySlot.BROW_RING_RIGHT] = BodyType.BROW_RING_RIGHT + if hasattr(BodyType, 'CUMMERBUND'): + mapping[CommonBodySlot.CUMMERBUND] = BodyType.CUMMERBUND + if hasattr(BodyType, 'EARRINGS'): + mapping[CommonBodySlot.EARRINGS] = BodyType.EARRINGS + if hasattr(BodyType, 'EARS'): + mapping[CommonBodySlot.EARS] = BodyType.EARS + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'EYECOLOR'): + mapping[CommonBodySlot.EYE_COLOR] = BodyType.EYECOLOR + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'EYECOLOR_SECONDARY'): + mapping[CommonBodySlot.EYE_COLOR_SECONDARY] = BodyType.EYECOLOR_SECONDARY + if hasattr(BodyType, 'EYE_LINER'): + mapping[CommonBodySlot.EYE_LINER] = BodyType.EYE_LINER + if hasattr(BodyType, 'EYE_SHADOW'): + mapping[CommonBodySlot.EYE_SHADOW] = BodyType.EYE_SHADOW + if hasattr(BodyType, 'EYEBROWS'): + mapping[CommonBodySlot.EYEBROWS] = BodyType.EYEBROWS + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'FACEPAINT'): + mapping[CommonBodySlot.FACE_PAINT] = BodyType.FACEPAINT + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'SCARFACE'): + mapping[CommonBodySlot.FACE_SCAR] = BodyType.SCARFACE + if hasattr(BodyType, 'FACIAL_HAIR'): + mapping[CommonBodySlot.FACIAL_HAIR] = BodyType.FACIAL_HAIR + if hasattr(BodyType, 'FINGERNAIL'): + mapping[CommonBodySlot.FINGERNAIL] = BodyType.FINGERNAIL + if hasattr(BodyType, 'FOREARM_SCAR'): + mapping[CommonBodySlot.FOREARM_SCAR] = BodyType.FOREARM_SCAR + if hasattr(BodyType, 'FULL_BODY'): + mapping[CommonBodySlot.FULL_BODY] = BodyType.FULL_BODY + if hasattr(BodyType, 'FUR_BODY'): + mapping[CommonBodySlot.FUR_BODY] = BodyType.FUR_BODY + if hasattr(BodyType, 'GLASSES'): + mapping[CommonBodySlot.GLASSES] = BodyType.GLASSES + if hasattr(BodyType, 'GLOVES'): + mapping[CommonBodySlot.GLOVES] = BodyType.GLOVES + if hasattr(BodyType, 'HAIR'): + mapping[CommonBodySlot.HAIR] = BodyType.HAIR + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'HAIRCOLOR_OVERRIDE'): + mapping[CommonBodySlot.HAIR_COLOR_OVERRIDE] = BodyType.HAIRCOLOR_OVERRIDE + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'HAIR_FEATHERS'): + mapping[CommonBodySlot.HAIR_FEATHERS] = BodyType.HAIR_FEATHERS + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'HAIR_FORELOCK'): + mapping[CommonBodySlot.HAIR_FORELOCK] = BodyType.HAIR_FORELOCK + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'HAIR_MANE'): + mapping[CommonBodySlot.HAIR_MANE] = BodyType.HAIR_MANE + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'HAIR_TAIL'): + mapping[CommonBodySlot.HAIR_TAIL] = BodyType.HAIR_TAIL + if hasattr(BodyType, 'HAT'): + mapping[CommonBodySlot.HAT] = BodyType.HAT + if hasattr(BodyType, 'HEAD'): + mapping[CommonBodySlot.HEAD] = BodyType.HEAD + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'HORN'): + mapping[CommonBodySlot.HORN] = BodyType.HORN + if hasattr(BodyType, 'INDEX_FINGER_LEFT'): + mapping[CommonBodySlot.INDEX_FINGER_LEFT] = BodyType.INDEX_FINGER_LEFT + if hasattr(BodyType, 'INDEX_FINGER_RIGHT'): + mapping[CommonBodySlot.INDEX_FINGER_RIGHT] = BodyType.INDEX_FINGER_RIGHT + if hasattr(BodyType, 'LIP_RING_LEFT'): + mapping[CommonBodySlot.LIP_RING_LEFT] = BodyType.LIP_RING_LEFT + if hasattr(BodyType, 'LIP_RING_RIGHT'): + mapping[CommonBodySlot.LIP_RING_RIGHT] = BodyType.LIP_RING_RIGHT + if hasattr(BodyType, 'LIPS_TICK'): + mapping[CommonBodySlot.LIPSTICK] = BodyType.LIPS_TICK + if hasattr(BodyType, 'LOWER_BODY'): + mapping[CommonBodySlot.LOWER_BODY] = BodyType.LOWER_BODY + if hasattr(BodyType, 'EYELASHES'): + mapping[CommonBodySlot.EYELASHES] = BodyType.EYELASHES + if hasattr(BodyType, 'MIDDLE_FINGER_LEFT'): + mapping[CommonBodySlot.MIDDLE_FINGER_LEFT] = BodyType.MIDDLE_FINGER_LEFT + if hasattr(BodyType, 'MIDDLE_FINGER_RIGHT'): + mapping[CommonBodySlot.MIDDLE_FINGER_RIGHT] = BodyType.MIDDLE_FINGER_RIGHT + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'MOLEBACKUPPER'): + mapping[CommonBodySlot.MOLE_BACK_UPPER] = BodyType.MOLEBACKUPPER + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'MOLECHESTUPPER'): + mapping[CommonBodySlot.MOLE_CHEST_UPPER] = BodyType.MOLECHESTUPPER + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'MOLEFACE'): + mapping[CommonBodySlot.MOLE_FACE] = BodyType.MOLEFACE + if hasattr(BodyType, 'NECKLACE'): + mapping[CommonBodySlot.NECKLACE] = BodyType.NECKLACE + if hasattr(BodyType, 'NOSE_RING_LEFT'): + mapping[CommonBodySlot.NOSE_RING_LEFT] = BodyType.NOSE_RING_LEFT + if hasattr(BodyType, 'NOSE_RING_RIGHT'): + mapping[CommonBodySlot.NOSE_RING_RIGHT] = BodyType.NOSE_RING_RIGHT + if hasattr(BodyType, 'OCCULT_BROW'): + mapping[CommonBodySlot.OCCULT_BROW] = BodyType.OCCULT_BROW + if hasattr(BodyType, 'OCCULT_EYE_SOCKET'): + mapping[CommonBodySlot.OCCULT_EYE_SOCKET] = BodyType.OCCULT_EYE_SOCKET + if hasattr(BodyType, 'OCCULT_EYE_LID'): + mapping[CommonBodySlot.OCCULT_EYELID] = BodyType.OCCULT_EYE_LID + if hasattr(BodyType, 'OCCULT_LEFT_CHEEK'): + mapping[CommonBodySlot.OCCULT_LEFT_CHEEK] = BodyType.OCCULT_LEFT_CHEEK + if hasattr(BodyType, 'OCCULT_MOUTH'): + mapping[CommonBodySlot.OCCULT_MOUTH] = BodyType.OCCULT_MOUTH + if hasattr(BodyType, 'OCCULT_NECK_SCAR'): + mapping[CommonBodySlot.OCCULT_NECK_SCAR] = BodyType.OCCULT_NECK_SCAR + if hasattr(BodyType, 'OCCULT_RIGHT_CHEEK'): + mapping[CommonBodySlot.OCCULT_RIGHT_CHEEK] = BodyType.OCCULT_RIGHT_CHEEK + if hasattr(BodyType, 'REINS'): + mapping[CommonBodySlot.REINS] = BodyType.REINS + if hasattr(BodyType, 'RING_FINGER_LEFT'): + mapping[CommonBodySlot.RING_FINGER_LEFT] = BodyType.RING_FINGER_LEFT + if hasattr(BodyType, 'RING_FINGER_RIGHT'): + mapping[CommonBodySlot.RING_FINGER_RIGHT] = BodyType.RING_FINGER_RIGHT + if hasattr(BodyType, 'SADDLE'): + mapping[CommonBodySlot.SADDLE] = BodyType.SADDLE + if hasattr(BodyType, 'SHOES'): + mapping[CommonBodySlot.SHOES] = BodyType.SHOES + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'SKINDETAIL_ACNE_PUBERTY'): + mapping[CommonBodySlot.SKIN_DETAIL_ACNE_PUBERTY] = BodyType.SKINDETAIL_ACNE_PUBERTY + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'SKINDETAIL_CREASE_FOREHEAD'): + mapping[CommonBodySlot.SKIN_DETAIL_CREASE_FOREHEAD] = BodyType.SKINDETAIL_CREASE_FOREHEAD + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'SKINDETAIL_CREASE_MOUTH'): + mapping[CommonBodySlot.SKIN_DETAIL_CREASE_MOUTH] = BodyType.SKINDETAIL_CREASE_MOUTH + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'SKINDETAIL_DIMPLE_LEFT'): + mapping[CommonBodySlot.SKIN_DETAIL_DIMPLE_LEFT] = BodyType.SKINDETAIL_DIMPLE_LEFT + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'SKINDETAIL_DIMPLE_RIGHT'): + mapping[CommonBodySlot.SKIN_DETAIL_DIMPLE_RIGHT] = BodyType.SKINDETAIL_DIMPLE_RIGHT + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'SKINDETAIL_FRECKLES'): + mapping[CommonBodySlot.SKIN_DETAIL_FRECKLES] = BodyType.SKINDETAIL_FRECKLES + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'SKINDETAIL_HOOF_COLOR'): + mapping[CommonBodySlot.SKIN_DETAIL_HOOF_COLOR] = BodyType.SKINDETAIL_HOOF_COLOR + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'SKINDETAIL_MOLE_CHEEK_LEFT'): + mapping[CommonBodySlot.SKIN_DETAIL_MOLE_CHEEK_LEFT] = BodyType.SKINDETAIL_MOLE_CHEEK_LEFT + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'SKINDETAIL_MOLE_CHEEK_RIGHT'): + mapping[CommonBodySlot.SKIN_DETAIL_MOLE_CHEEK_RIGHT] = BodyType.SKINDETAIL_MOLE_CHEEK_RIGHT + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'SKINDETAIL_MOLE_LIP_LEFT'): + mapping[CommonBodySlot.SKIN_DETAIL_MOLE_LIP_LEFT] = BodyType.SKINDETAIL_MOLE_LIP_LEFT + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'SKINDETAIL_MOLE_LIP_RIGHT'): + mapping[CommonBodySlot.SKIN_DETAIL_MOLE_LIP_RIGHT] = BodyType.SKINDETAIL_MOLE_LIP_RIGHT + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'SKINDETAIL_NOSE_COLOR'): + mapping[CommonBodySlot.SKIN_DETAIL_NOSE_COLOR] = BodyType.SKINDETAIL_NOSE_COLOR + if hasattr(BodyType, 'SKIN_OVERLAY'): + mapping[CommonBodySlot.SKIN_OVERLAY] = BodyType.SKIN_OVERLAY + if hasattr(BodyType, 'SOCKS'): + mapping[CommonBodySlot.SOCKS] = BodyType.SOCKS + if hasattr(BodyType, 'STRETCHMARKS_BACK'): + mapping[CommonBodySlot.STRETCH_MARKS_BACK] = BodyType.STRETCHMARKS_BACK + if hasattr(BodyType, 'STRETCHMARKS_FRONT'): + mapping[CommonBodySlot.STRETCH_MARKS_FRONT] = BodyType.STRETCHMARKS_FRONT + if hasattr(BodyType, 'TAIL'): + mapping[CommonBodySlot.TAIL] = BodyType.TAIL + if hasattr(BodyType, 'TAIL_BASE'): + mapping[CommonBodySlot.TAIL_BASE] = BodyType.TAIL_BASE + if hasattr(BodyType, 'TATTOO_ARM_LOWER_LEFT'): + mapping[CommonBodySlot.TATTOO_ARM_LOWER_LEFT] = BodyType.TATTOO_ARM_LOWER_LEFT + if hasattr(BodyType, 'TATTOO_ARM_LOWER_RIGHT'): + mapping[CommonBodySlot.TATTOO_ARM_LOWER_RIGHT] = BodyType.TATTOO_ARM_LOWER_RIGHT + if hasattr(BodyType, 'TATTOO_ARM_UPPER_LEFT'): + mapping[CommonBodySlot.TATTOO_ARM_UPPER_LEFT] = BodyType.TATTOO_ARM_UPPER_LEFT + if hasattr(BodyType, 'TATTOO_ARM_UPPER_RIGHT'): + mapping[CommonBodySlot.TATTOO_ARM_UPPER_RIGHT] = BodyType.TATTOO_ARM_UPPER_RIGHT + if hasattr(BodyType, 'TATTOO_LEG_LEFT'): + mapping[CommonBodySlot.TATTOO_LEG_LEFT] = BodyType.TATTOO_LEG_LEFT + if hasattr(BodyType, 'TATTOO_LEG_RIGHT'): + mapping[CommonBodySlot.TATTOO_LEG_RIGHT] = BodyType.TATTOO_LEG_RIGHT + if hasattr(BodyType, 'TATTOO_TORSO_BACK_LOWER'): + mapping[CommonBodySlot.TATTOO_TORSO_BACK_LOWER] = BodyType.TATTOO_TORSO_BACK_LOWER + if hasattr(BodyType, 'TATTOO_TORSO_BACK_UPPER'): + mapping[CommonBodySlot.TATTOO_TORSO_BACK_UPPER] = BodyType.TATTOO_TORSO_BACK_UPPER + if hasattr(BodyType, 'TATTOO_TORSO_FRONT_LOWER'): + mapping[CommonBodySlot.TATTOO_TORSO_FRONT_LOWER] = BodyType.TATTOO_TORSO_FRONT_LOWER + if hasattr(BodyType, 'TATTOO_TORSO_FRONT_UPPER'): + mapping[CommonBodySlot.TATTOO_TORSO_FRONT_UPPER] = BodyType.TATTOO_TORSO_FRONT_UPPER + if hasattr(BodyType, 'TEETH'): + mapping[CommonBodySlot.TEETH] = BodyType.TEETH + if hasattr(BodyType, 'TIGHTS'): + mapping[CommonBodySlot.TIGHTS] = BodyType.TIGHTS + if hasattr(BodyType, 'TOENAIL'): + mapping[CommonBodySlot.TOENAIL] = BodyType.TOENAIL + if hasattr(BodyType, 'UPPER_BODY'): + mapping[CommonBodySlot.UPPER_BODY] = BodyType.UPPER_BODY + if hasattr(BodyType, 'WRIST_LEFT'): + mapping[CommonBodySlot.WRIST_LEFT] = BodyType.WRIST_LEFT + if hasattr(BodyType, 'WRIST_RIGHT'): + mapping[CommonBodySlot.WRIST_RIGHT] = BodyType.WRIST_RIGHT + return mapping.get(value, value) + + @staticmethod + def convert_from_vanilla(value: Union['CommonBodySlot', BodyType, int]) -> Union['CommonBodySlot', BodyType, int]: + """convert_from_vanilla(value) + + Convert a BodyType into a CommonBodySlot + + :param value: An instance of a BodyType + :type value: Union[CommonBodySlot, BodyType, int] + :return: The specified BodyType translated to a CommonBodySlot or the value itself if the BodyType could not be translated. + :rtype: Union[CommonBodySlot, int] + """ + if value is None or value == CommonBodySlot.NONE: + return CommonBodySlot.NONE + if isinstance(value, CommonBodySlot): + return value + mapping = dict() + if hasattr(BodyType, 'ACNE'): + mapping[BodyType.ACNE] = CommonBodySlot.ACNE + if hasattr(BodyType, 'ATTACHMENT_BACK'): + mapping[BodyType.ATTACHMENT_BACK] = CommonBodySlot.ATTACHMENT_BACK + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'BIRTHMARKARMS'): + mapping[BodyType.BIRTHMARKARMS] = CommonBodySlot.BIRTHMARK_ARMS + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'BIRTHMARKFACE'): + mapping[BodyType.BIRTHMARKFACE] = CommonBodySlot.BIRTHMARK_FACE + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'BIRTHMARKLEGS'): + mapping[BodyType.BIRTHMARKLEGS] = CommonBodySlot.BIRTHMARK_LEGS + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'BIRTHMARKTORSOBACK'): + mapping[BodyType.BIRTHMARKTORSOBACK] = CommonBodySlot.BIRTHMARK_TORSO_BACK + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'BIRTHMARKTORSOFRONT'): + mapping[BodyType.BIRTHMARKTORSOFRONT] = CommonBodySlot.BIRTHMARK_TORSO_FRONT + if hasattr(BodyType, 'BITE'): + mapping[BodyType.BITE] = CommonBodySlot.BITE + if hasattr(BodyType, 'BLANKET'): + mapping[BodyType.BLANKET] = CommonBodySlot.BLANKET + if hasattr(BodyType, 'BLUSH'): + mapping[BodyType.BLUSH] = CommonBodySlot.BLUSH + if hasattr(BodyType, 'BRIDLE'): + mapping[BodyType.BRIDLE] = CommonBodySlot.BRIDLE + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'BODYFRECKLES'): + mapping[BodyType.BODYFRECKLES] = CommonBodySlot.BODY_FRECKLES + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'BODYHAIR_ARM'): + mapping[BodyType.BODYHAIR_ARM] = CommonBodySlot.BODY_HAIR_ARM + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'BODYHAIR_LEG'): + mapping[BodyType.BODYHAIR_LEG] = CommonBodySlot.BODY_HAIR_LEG + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'BODYHAIR_TORSOBACK'): + mapping[BodyType.BODYHAIR_TORSOBACK] = CommonBodySlot.BODY_HAIR_TORSO_BACK + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'BODYHAIR_TORSOFRONT'): + mapping[BodyType.BODYHAIR_TORSOFRONT] = CommonBodySlot.BODY_HAIR_TORSO_FRONT + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'BODYSCAR_ARMLEFT'): + mapping[BodyType.BODYSCAR_ARMLEFT] = CommonBodySlot.BODY_SCAR_ARM_LEFT + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'BODYSCAR_ARMRIGHT'): + mapping[BodyType.BODYSCAR_ARMRIGHT] = CommonBodySlot.BODY_SCAR_ARM_RIGHT + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'BODYSCAR_LEGLEFT'): + mapping[BodyType.BODYSCAR_LEGLEFT] = CommonBodySlot.BODY_SCAR_LEG_LEFT + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'BODYSCAR_LEGRIGHT'): + mapping[BodyType.BODYSCAR_LEGRIGHT] = CommonBodySlot.BODY_SCAR_LEG_RIGHT + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'BODYSCAR_TORSOBACK'): + mapping[BodyType.BODYSCAR_TORSOBACK] = CommonBodySlot.BODY_SCAR_TORSO_BACK + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'BODYSCAR_TORSOFRONT'): + mapping[BodyType.BODYSCAR_TORSOFRONT] = CommonBodySlot.BODY_SCAR_TORSO_FRONT + if hasattr(BodyType, 'BROW_RING_LEFT'): + mapping[BodyType.BROW_RING_LEFT] = CommonBodySlot.BROW_RING_LEFT + if hasattr(BodyType, 'BROW_RING_RIGHT'): + mapping[BodyType.BROW_RING_RIGHT] = CommonBodySlot.BROW_RING_RIGHT + if hasattr(BodyType, 'CUMMERBUND'): + mapping[BodyType.CUMMERBUND] = CommonBodySlot.CUMMERBUND + if hasattr(BodyType, 'EARRINGS'): + mapping[BodyType.EARRINGS] = CommonBodySlot.EARRINGS + if hasattr(BodyType, 'EARS'): + mapping[BodyType.EARS] = CommonBodySlot.EARS + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'EYECOLOR'): + mapping[BodyType.EYECOLOR] = CommonBodySlot.EYE_COLOR + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'EYECOLOR_SECONDARY'): + mapping[BodyType.EYECOLOR_SECONDARY] = CommonBodySlot.EYE_COLOR_SECONDARY + if hasattr(BodyType, 'EYE_LINER'): + mapping[BodyType.EYE_LINER] = CommonBodySlot.EYE_LINER + if hasattr(BodyType, 'EYE_SHADOW'): + mapping[BodyType.EYE_SHADOW] = CommonBodySlot.EYE_SHADOW + if hasattr(BodyType, 'EYEBROWS'): + mapping[BodyType.EYEBROWS] = CommonBodySlot.EYEBROWS + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'FACEPAINT'): + mapping[BodyType.FACEPAINT] = CommonBodySlot.FACE_PAINT + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'SCARFACE'): + mapping[BodyType.SCARFACE] = CommonBodySlot.FACE_SCAR + if hasattr(BodyType, 'FACIAL_HAIR'): + mapping[BodyType.FACIAL_HAIR] = CommonBodySlot.FACIAL_HAIR + if hasattr(BodyType, 'FINGERNAIL'): + mapping[BodyType.FINGERNAIL] = CommonBodySlot.FINGERNAIL + if hasattr(BodyType, 'FOREARM_SCAR'): + mapping[BodyType.FOREARM_SCAR] = CommonBodySlot.FOREARM_SCAR + if hasattr(BodyType, 'FULL_BODY'): + mapping[BodyType.FULL_BODY] = CommonBodySlot.FULL_BODY + if hasattr(BodyType, 'FUR_BODY'): + mapping[BodyType.FUR_BODY] = CommonBodySlot.FUR_BODY + if hasattr(BodyType, 'GLASSES'): + mapping[BodyType.GLASSES] = CommonBodySlot.GLASSES + if hasattr(BodyType, 'GLOVES'): + mapping[BodyType.GLOVES] = CommonBodySlot.GLOVES + if hasattr(BodyType, 'HAIR'): + mapping[BodyType.HAIR] = CommonBodySlot.HAIR + if hasattr(BodyType, 'HAIR_FEATHERS'): + mapping[BodyType.HAIR_FEATHERS] = CommonBodySlot.HAIR_FEATHERS + if hasattr(BodyType, 'HAIR_FORELOCK'): + mapping[BodyType.HAIR_FORELOCK] = CommonBodySlot.HAIR_FORELOCK + if hasattr(BodyType, 'HAIR_MANE'): + mapping[BodyType.HAIR_MANE] = CommonBodySlot.HAIR_MANE + if hasattr(BodyType, 'HAIR_TAIL'): + mapping[BodyType.HAIR_TAIL] = CommonBodySlot.HAIR_TAIL + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'HAIRCOLOR_OVERRIDE'): + mapping[BodyType.HAIRCOLOR_OVERRIDE] = CommonBodySlot.HAIR_COLOR_OVERRIDE + if hasattr(BodyType, 'HAT'): + mapping[BodyType.HAT] = CommonBodySlot.HAT + if hasattr(BodyType, 'HEAD'): + mapping[BodyType.HEAD] = CommonBodySlot.HEAD + if hasattr(BodyType, 'HORN'): + mapping[BodyType.HORN] = CommonBodySlot.HORN + if hasattr(BodyType, 'INDEX_FINGER_LEFT'): + mapping[BodyType.INDEX_FINGER_LEFT] = CommonBodySlot.INDEX_FINGER_LEFT + if hasattr(BodyType, 'INDEX_FINGER_RIGHT'): + mapping[BodyType.INDEX_FINGER_RIGHT] = CommonBodySlot.INDEX_FINGER_RIGHT + if hasattr(BodyType, 'LIP_RING_LEFT'): + mapping[BodyType.LIP_RING_LEFT] = CommonBodySlot.LIP_RING_LEFT + if hasattr(BodyType, 'LIP_RING_RIGHT'): + mapping[BodyType.LIP_RING_RIGHT] = CommonBodySlot.LIP_RING_RIGHT + if hasattr(BodyType, 'LIPS_TICK'): + mapping[BodyType.LIPS_TICK] = CommonBodySlot.LIPSTICK + if hasattr(BodyType, 'LOWER_BODY'): + mapping[BodyType.LOWER_BODY] = CommonBodySlot.LOWER_BODY + if hasattr(BodyType, 'EYELASHES'): + mapping[BodyType.EYELASHES] = CommonBodySlot.EYELASHES + if hasattr(BodyType, 'MIDDLE_FINGER_LEFT'): + mapping[BodyType.MIDDLE_FINGER_LEFT] = CommonBodySlot.MIDDLE_FINGER_LEFT + if hasattr(BodyType, 'MIDDLE_FINGER_RIGHT'): + mapping[BodyType.MIDDLE_FINGER_RIGHT] = CommonBodySlot.MIDDLE_FINGER_RIGHT + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'MOLEBACKUPPER'): + mapping[BodyType.MOLEBACKUPPER] = CommonBodySlot.MOLE_BACK_UPPER + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'MOLECHESTUPPER'): + mapping[BodyType.MOLECHESTUPPER] = CommonBodySlot.MOLE_CHEST_UPPER + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'MOLEFACE'): + mapping[BodyType.MOLEFACE] = CommonBodySlot.MOLE_FACE + if hasattr(BodyType, 'NECKLACE'): + mapping[BodyType.NECKLACE] = CommonBodySlot.NECKLACE + if hasattr(BodyType, 'NOSE_RING_LEFT'): + mapping[BodyType.NOSE_RING_LEFT] = CommonBodySlot.NOSE_RING_LEFT + if hasattr(BodyType, 'NOSE_RING_RIGHT'): + mapping[BodyType.NOSE_RING_RIGHT] = CommonBodySlot.NOSE_RING_RIGHT + if hasattr(BodyType, 'OCCULT_BROW'): + mapping[BodyType.OCCULT_BROW] = CommonBodySlot.OCCULT_BROW + if hasattr(BodyType, 'OCCULT_EYE_SOCKET'): + mapping[BodyType.OCCULT_EYE_SOCKET] = CommonBodySlot.OCCULT_EYE_SOCKET + if hasattr(BodyType, 'OCCULT_EYE_LID'): + mapping[BodyType.OCCULT_EYE_LID] = CommonBodySlot.OCCULT_EYELID + if hasattr(BodyType, 'OCCULT_LEFT_CHEEK'): + mapping[BodyType.OCCULT_LEFT_CHEEK] = CommonBodySlot.OCCULT_LEFT_CHEEK + if hasattr(BodyType, 'OCCULT_MOUTH'): + mapping[BodyType.OCCULT_MOUTH] = CommonBodySlot.OCCULT_MOUTH + if hasattr(BodyType, 'OCCULT_NECK_SCAR'): + mapping[BodyType.OCCULT_NECK_SCAR] = CommonBodySlot.OCCULT_NECK_SCAR + if hasattr(BodyType, 'OCCULT_RIGHT_CHEEK'): + mapping[BodyType.OCCULT_RIGHT_CHEEK] = CommonBodySlot.OCCULT_RIGHT_CHEEK + if hasattr(BodyType, 'REINS'): + mapping[BodyType.REINS] = CommonBodySlot.REINS + if hasattr(BodyType, 'RING_FINGER_LEFT'): + mapping[BodyType.RING_FINGER_LEFT] = CommonBodySlot.RING_FINGER_LEFT + if hasattr(BodyType, 'RING_FINGER_RIGHT'): + mapping[BodyType.RING_FINGER_RIGHT] = CommonBodySlot.RING_FINGER_RIGHT + if hasattr(BodyType, 'SADDLE'): + mapping[BodyType.SADDLE] = CommonBodySlot.SADDLE + if hasattr(BodyType, 'SHOES'): + mapping[BodyType.SHOES] = CommonBodySlot.SHOES + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'SKINDETAIL_ACNE_PUBERTY'): + mapping[BodyType.SKINDETAIL_ACNE_PUBERTY] = CommonBodySlot.SKIN_DETAIL_ACNE_PUBERTY + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'SKINDETAIL_CREASE_FOREHEAD'): + mapping[BodyType.SKINDETAIL_CREASE_FOREHEAD] = CommonBodySlot.SKIN_DETAIL_CREASE_FOREHEAD + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'SKINDETAIL_CREASE_MOUTH'): + mapping[BodyType.SKINDETAIL_CREASE_MOUTH] = CommonBodySlot.SKIN_DETAIL_CREASE_MOUTH + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'SKINDETAIL_DIMPLE_LEFT'): + mapping[BodyType.SKINDETAIL_DIMPLE_LEFT] = CommonBodySlot.SKIN_DETAIL_DIMPLE_LEFT + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'SKINDETAIL_DIMPLE_RIGHT'): + mapping[BodyType.SKINDETAIL_DIMPLE_RIGHT] = CommonBodySlot.SKIN_DETAIL_DIMPLE_RIGHT + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'SKINDETAIL_FRECKLES'): + mapping[BodyType.SKINDETAIL_FRECKLES] = CommonBodySlot.SKIN_DETAIL_FRECKLES + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'SKINDETAIL_HOOF_COLOR'): + mapping[BodyType.SKINDETAIL_HOOF_COLOR] = CommonBodySlot.SKIN_DETAIL_HOOF_COLOR + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'SKINDETAIL_MOLE_CHEEK_LEFT'): + mapping[BodyType.SKINDETAIL_MOLE_CHEEK_LEFT] = CommonBodySlot.SKIN_DETAIL_MOLE_CHEEK_LEFT + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'SKINDETAIL_MOLE_CHEEK_RIGHT'): + mapping[BodyType.SKINDETAIL_MOLE_CHEEK_RIGHT] = CommonBodySlot.SKIN_DETAIL_MOLE_CHEEK_RIGHT + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'SKINDETAIL_MOLE_LIP_LEFT'): + mapping[BodyType.SKINDETAIL_MOLE_LIP_LEFT] = CommonBodySlot.SKIN_DETAIL_MOLE_LIP_LEFT + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'SKINDETAIL_MOLE_LIP_RIGHT'): + mapping[BodyType.SKINDETAIL_MOLE_LIP_RIGHT] = CommonBodySlot.SKIN_DETAIL_MOLE_LIP_RIGHT + # noinspection SpellCheckingInspection + if hasattr(BodyType, 'SKINDETAIL_NOSE_COLOR'): + mapping[BodyType.SKINDETAIL_NOSE_COLOR] = CommonBodySlot.SKIN_DETAIL_NOSE_COLOR + if hasattr(BodyType, 'SKIN_OVERLAY'): + mapping[BodyType.SKIN_OVERLAY] = CommonBodySlot.SKIN_OVERLAY + if hasattr(BodyType, 'SOCKS'): + mapping[BodyType.SOCKS] = CommonBodySlot.SOCKS + if hasattr(BodyType, 'STRETCHMARKS_BACK'): + mapping[BodyType.STRETCHMARKS_BACK] = CommonBodySlot.STRETCH_MARKS_BACK + if hasattr(BodyType, 'STRETCHMARKS_FRONT'): + mapping[BodyType.STRETCHMARKS_FRONT] = CommonBodySlot.STRETCH_MARKS_FRONT + if hasattr(BodyType, 'TAIL'): + mapping[BodyType.TAIL] = CommonBodySlot.TAIL + if hasattr(BodyType, 'TAIL_BASE'): + mapping[BodyType.TAIL_BASE] = CommonBodySlot.TAIL_BASE + if hasattr(BodyType, 'TATTOO_ARM_LOWER_LEFT'): + mapping[BodyType.TATTOO_ARM_LOWER_LEFT] = CommonBodySlot.TATTOO_ARM_LOWER_LEFT + if hasattr(BodyType, 'TATTOO_ARM_LOWER_RIGHT'): + mapping[BodyType.TATTOO_ARM_LOWER_RIGHT] = CommonBodySlot.TATTOO_ARM_LOWER_RIGHT + if hasattr(BodyType, 'TATTOO_ARM_UPPER_LEFT'): + mapping[BodyType.TATTOO_ARM_UPPER_LEFT] = CommonBodySlot.TATTOO_ARM_UPPER_LEFT + if hasattr(BodyType, 'TATTOO_ARM_UPPER_RIGHT'): + mapping[BodyType.TATTOO_ARM_UPPER_RIGHT] = CommonBodySlot.TATTOO_ARM_UPPER_RIGHT + if hasattr(BodyType, 'TATTOO_LEG_LEFT'): + mapping[BodyType.TATTOO_LEG_LEFT] = CommonBodySlot.TATTOO_LEG_LEFT + if hasattr(BodyType, 'TATTOO_LEG_RIGHT'): + mapping[BodyType.TATTOO_LEG_RIGHT] = CommonBodySlot.TATTOO_LEG_RIGHT + if hasattr(BodyType, 'TATTOO_TORSO_BACK_LOWER'): + mapping[BodyType.TATTOO_TORSO_BACK_LOWER] = CommonBodySlot.TATTOO_TORSO_BACK_LOWER + if hasattr(BodyType, 'TATTOO_TORSO_BACK_UPPER'): + mapping[BodyType.TATTOO_TORSO_BACK_UPPER] = CommonBodySlot.TATTOO_TORSO_BACK_UPPER + if hasattr(BodyType, 'TATTOO_TORSO_FRONT_LOWER'): + mapping[BodyType.TATTOO_TORSO_FRONT_LOWER] = CommonBodySlot.TATTOO_TORSO_FRONT_LOWER + if hasattr(BodyType, 'TATTOO_TORSO_FRONT_UPPER'): + mapping[BodyType.TATTOO_TORSO_FRONT_UPPER] = CommonBodySlot.TATTOO_TORSO_FRONT_UPPER + if hasattr(BodyType, 'TEETH'): + mapping[BodyType.TEETH] = CommonBodySlot.TEETH + if hasattr(BodyType, 'TIGHTS'): + mapping[BodyType.TIGHTS] = CommonBodySlot.TIGHTS + if hasattr(BodyType, 'TOENAIL'): + mapping[BodyType.TOENAIL] = CommonBodySlot.TOENAIL + if hasattr(BodyType, 'UPPER_BODY'): + mapping[BodyType.UPPER_BODY] = CommonBodySlot.UPPER_BODY + if hasattr(BodyType, 'WRIST_LEFT'): + mapping[BodyType.WRIST_LEFT] = CommonBodySlot.WRIST_LEFT + if hasattr(BodyType, 'WRIST_RIGHT'): + mapping[BodyType.WRIST_RIGHT] = CommonBodySlot.WRIST_RIGHT + return mapping.get(value, value) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_bucks_types.py b/Scripts/s4ap/sims4communitylib/enums/common_bucks_types.py new file mode 100644 index 0000000..007863f --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_bucks_types.py @@ -0,0 +1,203 @@ +""" +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 +""" +from typing import Iterator, Tuple, Union + +from bucks.bucks_enums import BucksType +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonBucksType(CommonInt): + """Variants of Bucks Types.""" + INVALID: 'CommonBucksType' = ... + RETAIL: 'CommonBucksType' = ... + VAMPIRE_POWER: 'CommonBucksType' = ... + VAMPIRE_WEAKNESS: 'CommonBucksType' = ... + VET: 'CommonBucksType' = ... + CLUB: 'CommonBucksType' = ... + RESTAURANT: 'CommonBucksType' = ... + RECYCLE_BITS: 'CommonBucksType' = ... + RECYCLE_PIECES: 'CommonBucksType' = ... + FAME_PERK: 'CommonBucksType' = ... + FAME_QUIRK: 'CommonBucksType' = ... + WITCH_PERK: 'CommonBucksType' = ... + INFLUENCE: 'CommonBucksType' = ... + GALACTIC_CREDIT: 'CommonBucksType' = ... + WEREWOLF_ABILITY: 'CommonBucksType' = ... + WEREWOLF_ABILITY_QUEST: 'CommonBucksType' = ... + + @classmethod + def get_all(cls, exclude_values: Iterator['CommonBucksType'] = None) -> Tuple['CommonBucksType']: + """get_all(exclude_values=None) + + Get a collection of all values. + + :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonBucksType], optional + :return: A collection of all values. + :rtype: Tuple[CommonBucksType] + """ + if exclude_values is None: + exclude_values = (cls.INVALID,) + # noinspection PyTypeChecker + value_list: Tuple[CommonBucksType, ...] = tuple([value for value in cls.values if value not in exclude_values]) + return value_list + + @classmethod + def get_all_names(cls, exclude_values: Iterator['CommonBucksType'] = None) -> Tuple[str]: + """get_all_names(exclude_values=None) + + Retrieve a collection of the names of all values. + + :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonBucksType], optional + :return: A collection of the names of all values. + :rtype: Tuple[str] + """ + name_list: Tuple[str] = tuple([value.name for value in cls.get_all(exclude_values=exclude_values)]) + return name_list + + @classmethod + def get_comma_separated_names_string(cls, exclude_values: Iterator['CommonBucksType'] = None) -> str: + """get_comma_separated_names_string(exclude_values=None) + + Create a string containing all names of all values, separated by a comma. + + :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonBucksType], optional + :return: A string containing all names of all values, separated by a comma. + :rtype: str + """ + return ', '.join(cls.get_all_names(exclude_values=exclude_values)) + + @staticmethod + def convert_to_vanilla(value: 'CommonBucksType') -> Union[BucksType, None]: + """convert_to_vanilla(value) + + Convert a value into the vanilla BucksType enum. + + :param value: An instance of CommonBucksType + :type value: CommonBucksType + :return: The specified value translated to BucksType or None if the value could not be translated. + :rtype: Union[BucksType, None] + """ + if value is None or value == CommonBucksType.INVALID: + return None + if isinstance(value, BucksType): + return value + mapping = dict() + if hasattr(BucksType, 'RetailBucks'): + mapping[CommonBucksType.RETAIL] = BucksType.RetailBucks + if hasattr(BucksType, 'VampirePowerBucks'): + mapping[CommonBucksType.VAMPIRE_POWER] = BucksType.VampirePowerBucks + if hasattr(BucksType, 'VampireWeaknessBucks'): + mapping[CommonBucksType.VAMPIRE_WEAKNESS] = BucksType.VampireWeaknessBucks + if hasattr(BucksType, 'VetBucks'): + mapping[CommonBucksType.VET] = BucksType.VetBucks + if hasattr(BucksType, 'ClubBucks'): + mapping[CommonBucksType.CLUB] = BucksType.ClubBucks + if hasattr(BucksType, 'RestaurantBucks'): + mapping[CommonBucksType.RESTAURANT] = BucksType.RestaurantBucks + if hasattr(BucksType, 'RecycleBitsBucks'): + mapping[CommonBucksType.RECYCLE_BITS] = BucksType.RecycleBitsBucks + if hasattr(BucksType, 'RecyclePiecesBucks'): + mapping[CommonBucksType.RECYCLE_PIECES] = BucksType.RecyclePiecesBucks + if hasattr(BucksType, 'FamePerkBucks'): + mapping[CommonBucksType.FAME_PERK] = BucksType.FamePerkBucks + if hasattr(BucksType, 'FameQuirkBucks'): + mapping[CommonBucksType.FAME_QUIRK] = BucksType.FameQuirkBucks + if hasattr(BucksType, 'WitchPerkBucks'): + mapping[CommonBucksType.WITCH_PERK] = BucksType.WitchPerkBucks + if hasattr(BucksType, 'InfluenceBuck'): + mapping[CommonBucksType.INFLUENCE] = BucksType.InfluenceBuck + if hasattr(BucksType, 'GalacticCredits'): + mapping[CommonBucksType.GALACTIC_CREDIT] = BucksType.GalacticCredits + if hasattr(BucksType, 'WerewolfAbilityBucks'): + mapping[CommonBucksType.WEREWOLF_ABILITY] = BucksType.WerewolfAbilityBucks + if hasattr(BucksType, 'WerewolfQuestAbilityBucks'): + mapping[CommonBucksType.WEREWOLF_ABILITY_QUEST] = BucksType.WerewolfQuestAbilityBucks + return mapping.get(value, None) + + @staticmethod + def convert_from_vanilla(value: Union[int, BucksType]) -> 'CommonBucksType': + """convert_from_vanilla(value) + + Convert a value into a CommonBucksType enum. + + :param value: An instance of BucksType + :type value: BucksType + :return: The specified value translated to CommonBucksType or INVALID if the value could not be translated. + :rtype: Union[BucksType, None] + """ + if value is None: + return CommonBucksType.INVALID + if isinstance(value, CommonBucksType): + return value + mapping = dict() + if hasattr(BucksType, 'RetailBucks'): + mapping[BucksType.RetailBucks] = CommonBucksType.RETAIL + if hasattr(BucksType, 'VampirePowerBucks'): + mapping[BucksType.VampirePowerBucks] = CommonBucksType.VAMPIRE_POWER + if hasattr(BucksType, 'VampireWeaknessBucks'): + mapping[BucksType.VampireWeaknessBucks] = CommonBucksType.VAMPIRE_WEAKNESS + if hasattr(BucksType, 'VetBucks'): + mapping[BucksType.VetBucks] = CommonBucksType.VET + if hasattr(BucksType, 'ClubBucks'): + mapping[BucksType.ClubBucks] = CommonBucksType.CLUB + if hasattr(BucksType, 'RestaurantBucks'): + mapping[BucksType.RestaurantBucks] = CommonBucksType.RESTAURANT + if hasattr(BucksType, 'RecycleBitsBucks'): + mapping[BucksType.RecycleBitsBucks] = CommonBucksType.RECYCLE_BITS + if hasattr(BucksType, 'RecyclePiecesBucks'): + mapping[BucksType.RecyclePiecesBucks] = CommonBucksType.RECYCLE_PIECES + if hasattr(BucksType, 'FamePerkBucks'): + mapping[BucksType.FamePerkBucks] = CommonBucksType.FAME_PERK + if hasattr(BucksType, 'FameQuirkBucks'): + mapping[BucksType.FameQuirkBucks] = CommonBucksType.FAME_QUIRK + if hasattr(BucksType, 'WitchPerkBucks'): + mapping[BucksType.WitchPerkBucks] = CommonBucksType.WITCH_PERK + if hasattr(BucksType, 'InfluenceBuck'): + mapping[BucksType.InfluenceBuck] = CommonBucksType.INFLUENCE + if hasattr(BucksType, 'GalacticCredits'): + mapping[BucksType.GalacticCredits] = CommonBucksType.GALACTIC_CREDIT + if hasattr(BucksType, 'WerewolfAbilityBucks'): + mapping[BucksType.WerewolfAbilityBucks] = CommonBucksType.WEREWOLF_ABILITY + if hasattr(BucksType, 'WerewolfQuestAbilityBucks'): + mapping[BucksType.WerewolfQuestAbilityBucks] = CommonBucksType.WEREWOLF_ABILITY_QUEST + return mapping.get(value, value) + + @staticmethod + def convert_to_localized_string_id(value: 'CommonBucksType') -> Union[int, str]: + """convert_to_localized_string_id(value) + + Convert a CommonBucksType into a Localized String identifier. + + :param value: An instance of a CommonBucksType + :type value: CommonBucksType + :return: The specified CommonBucksType translated to a localized string identifier. If no localized string id is found, the name property of the value will be used instead. + :rtype: Union[int, str] + """ + display_name_mapping = { + # CommonBucksType.RETAIL: 0, + # CommonBucksType.VAMPIRE_POWER: 0, + # CommonBucksType.VAMPIRE_WEAKNESS: 0, + # CommonBucksType.VET: 0, + # CommonBucksType.CLUB: 0, + # CommonBucksType.RESTAURANT: 0, + # CommonBucksType.RECYCLE_BITS: 0, + # CommonBucksType.RECYCLE_PIECES: 0, + # CommonBucksType.FAME_PERK: 0, + # CommonBucksType.FAME_QUIRK: 0, + # CommonBucksType.WITCH_PERK: 0, + # CommonBucksType.INFLUENCE: 0, + # CommonBucksType.GALACTIC_CREDIT: 0, + # CommonBucksType.WEREWOLF_ABILITY: 0, + # CommonBucksType.WEREWOLF_ABILITY_QUEST: 0, + } + if isinstance(value, int) and not isinstance(value, CommonBucksType): + value = CommonBucksType.convert_from_vanilla(value) + return display_name_mapping.get(value, value.name if hasattr(value, 'name') else str(value)) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_business_advertising_type.py b/Scripts/s4ap/sims4communitylib/enums/common_business_advertising_type.py new file mode 100644 index 0000000..2f5387e --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_business_advertising_type.py @@ -0,0 +1,141 @@ +""" +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 +""" +from typing import Iterator, Tuple, Union + +from business.business_enums import BusinessAdvertisingType +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonBusinessAdvertisingType(CommonInt): + """Advertising types for businesses.""" + INVALID: 'CommonBusinessAdvertisingType' = ... + BUSINESS_NONE: 'CommonBusinessAdvertisingType' = ... + BUSINESS_RADIO: 'CommonBusinessAdvertisingType' = ... + RETAIL_TV_LONG: 'CommonBusinessAdvertisingType' = ... + RETAIL_TV_SHORT: 'CommonBusinessAdvertisingType' = ... + RETAIL_WEB_LONG: 'CommonBusinessAdvertisingType' = ... + RETAIL_WEB_SHORT: 'CommonBusinessAdvertisingType' = ... + BUSINESS_WEB: 'CommonBusinessAdvertisingType' = ... + BUSINESS_NEWSPAPER: 'CommonBusinessAdvertisingType' = ... + BUSINESS_TV: 'CommonBusinessAdvertisingType' = ... + + @classmethod + def get_all(cls, exclude_values: Iterator['CommonBusinessAdvertisingType'] = None) -> Tuple['CommonBusinessAdvertisingType']: + """get_all(exclude_values=None) + + Get a collection of all values. + + :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonBusinessAdvertisingType], optional + :return: A collection of all values. + :rtype: Tuple[CommonBusinessAdvertisingType] + """ + if exclude_values is None: + exclude_values = (cls.INVALID,) + # noinspection PyTypeChecker + value_list: Tuple[CommonBusinessAdvertisingType, ...] = tuple([value for value in cls.values if value not in exclude_values]) + return value_list + + @classmethod + def get_all_names(cls, exclude_values: Iterator['CommonBusinessAdvertisingType'] = None) -> Tuple[str]: + """get_all_names(exclude_values=None) + + Retrieve a collection of the names of all values. + + :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonBusinessAdvertisingType], optional + :return: A collection of the names of all values. + :rtype: Tuple[str] + """ + name_list: Tuple[str] = tuple([value.name for value in cls.get_all(exclude_values=exclude_values)]) + return name_list + + @classmethod + def get_comma_separated_names_string(cls, exclude_values: Iterator['CommonBusinessAdvertisingType'] = None) -> str: + """get_comma_separated_names_string(exclude_values=None) + + Create a string containing all names of all values, separated by a comma. + + :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonBusinessAdvertisingType], optional + :return: A string containing all names of all values, separated by a comma. + :rtype: str + """ + return ', '.join(cls.get_all_names(exclude_values=exclude_values)) + + @staticmethod + def convert_to_vanilla(value: 'CommonBusinessAdvertisingType') -> BusinessAdvertisingType: + """convert_to_vanilla(value) + + Convert a value into the vanilla BusinessAdvertisingType enum. + + :param value: An instance of CommonBusinessAdvertisingType + :type value: CommonBusinessAdvertisingType + :return: The specified value translated to BusinessAdvertisingType or INVALID if the value could not be translated. + :rtype: BusinessAdvertisingType + """ + if value is None or value == CommonBusinessAdvertisingType.INVALID: + return BusinessAdvertisingType.INVALID + if isinstance(value, BusinessAdvertisingType): + return value + mapping = dict() + if hasattr(BusinessAdvertisingType, 'Business_None'): + mapping[CommonBusinessAdvertisingType.BUSINESS_NONE] = BusinessAdvertisingType.Business_None + if hasattr(BusinessAdvertisingType, 'Business_Radio'): + mapping[CommonBusinessAdvertisingType.BUSINESS_RADIO] = BusinessAdvertisingType.Business_Radio + if hasattr(BusinessAdvertisingType, 'Retail_TV_Long'): + mapping[CommonBusinessAdvertisingType.RETAIL_TV_LONG] = BusinessAdvertisingType.Retail_TV_Long + if hasattr(BusinessAdvertisingType, 'Retail_TV_Short'): + mapping[CommonBusinessAdvertisingType.RETAIL_TV_SHORT] = BusinessAdvertisingType.Retail_TV_Short + if hasattr(BusinessAdvertisingType, 'Retail_Web_Long'): + mapping[CommonBusinessAdvertisingType.RETAIL_WEB_LONG] = BusinessAdvertisingType.Retail_Web_Long + if hasattr(BusinessAdvertisingType, 'Retail_Web_Short'): + mapping[CommonBusinessAdvertisingType.RETAIL_WEB_SHORT] = BusinessAdvertisingType.Retail_Web_Short + if hasattr(BusinessAdvertisingType, 'Business_Web'): + mapping[CommonBusinessAdvertisingType.BUSINESS_WEB] = BusinessAdvertisingType.Business_Web + if hasattr(BusinessAdvertisingType, 'Business_Newspaper'): + mapping[CommonBusinessAdvertisingType.BUSINESS_NEWSPAPER] = BusinessAdvertisingType.Business_Newspaper + if hasattr(BusinessAdvertisingType, 'Business_TV'): + mapping[CommonBusinessAdvertisingType.BUSINESS_TV] = BusinessAdvertisingType.Business_TV + return mapping.get(value, BusinessAdvertisingType.INVALID) + + @staticmethod + def convert_from_vanilla(value: Union[int, BusinessAdvertisingType]) -> 'CommonBusinessAdvertisingType': + """convert_from_vanilla(value) + + Convert a value into a CommonBusinessAdvertisingType enum. + + :param value: An instance of BusinessAdvertisingType + :type value: BusinessAdvertisingType + :return: The specified value translated to CommonBusinessAdvertisingType or INVALID if the value could not be translated. + :rtype: CommonBusinessAdvertisingType + """ + if value is None or value == BusinessAdvertisingType.INVALID: + return CommonBusinessAdvertisingType.INVALID + if isinstance(value, CommonBusinessAdvertisingType): + return value + mapping = dict() + if hasattr(BusinessAdvertisingType, 'Business_None'): + mapping[BusinessAdvertisingType.Business_None] = CommonBusinessAdvertisingType.BUSINESS_NONE + if hasattr(BusinessAdvertisingType, 'Business_Radio'): + mapping[BusinessAdvertisingType.Business_Radio] = CommonBusinessAdvertisingType.BUSINESS_RADIO + if hasattr(BusinessAdvertisingType, 'Retail_TV_Long'): + mapping[BusinessAdvertisingType.Retail_TV_Long] = CommonBusinessAdvertisingType.RETAIL_TV_LONG + if hasattr(BusinessAdvertisingType, 'Retail_TV_Short'): + mapping[BusinessAdvertisingType.Retail_TV_Short] = CommonBusinessAdvertisingType.RETAIL_TV_SHORT + if hasattr(BusinessAdvertisingType, 'Retail_Web_Long'): + mapping[BusinessAdvertisingType.Retail_Web_Long] = CommonBusinessAdvertisingType.RETAIL_WEB_LONG + if hasattr(BusinessAdvertisingType, 'Retail_Web_Short'): + mapping[BusinessAdvertisingType.Retail_Web_Short] = CommonBusinessAdvertisingType.RETAIL_WEB_SHORT + if hasattr(BusinessAdvertisingType, 'Business_Web'): + mapping[BusinessAdvertisingType.Business_Web] = CommonBusinessAdvertisingType.BUSINESS_WEB + if hasattr(BusinessAdvertisingType, 'Business_Newspaper'): + mapping[BusinessAdvertisingType.Business_Newspaper] = CommonBusinessAdvertisingType.BUSINESS_NEWSPAPER + if hasattr(BusinessAdvertisingType, 'Business_TV'): + mapping[BusinessAdvertisingType.Business_TV] = CommonBusinessAdvertisingType.BUSINESS_TV + return mapping.get(value, CommonBusinessAdvertisingType.INVALID) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_business_customer_star_rating_type.py b/Scripts/s4ap/sims4communitylib/enums/common_business_customer_star_rating_type.py new file mode 100644 index 0000000..d547c38 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_business_customer_star_rating_type.py @@ -0,0 +1,148 @@ +""" +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 +""" +from typing import Iterator, Tuple, Union + +from business.business_enums import BusinessCustomerStarRatingBuffBuckets +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonBusinessCustomerStarRatingType(CommonInt): + """Customer star rating types""" + INVALID: 'CommonBusinessCustomerStarRatingType' = ... + SERVICE: 'CommonBusinessCustomerStarRatingType' = ... + AMBIANCE: 'CommonBusinessCustomerStarRatingType' = ... + FOOD_QUALITY: 'CommonBusinessCustomerStarRatingType' = ... + FOOD_VALUE: 'CommonBusinessCustomerStarRatingType' = ... + PERSONAL_TOUCH: 'CommonBusinessCustomerStarRatingType' = ... + WAIT_TIME: 'CommonBusinessCustomerStarRatingType' = ... + MISC: 'CommonBusinessCustomerStarRatingType' = ... + STRESS_LEVEL: 'CommonBusinessCustomerStarRatingType' = ... + SERVICE_VALUE: 'CommonBusinessCustomerStarRatingType' = ... + SERVICE_QUALITY: 'CommonBusinessCustomerStarRatingType' = ... + + @classmethod + def get_all(cls, exclude_values: Iterator['CommonBusinessCustomerStarRatingType'] = None) -> Tuple['CommonBusinessCustomerStarRatingType']: + """get_all(exclude_values=None) + + Get a collection of all values. + + :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonBusinessCustomerStarRatingType], optional + :return: A collection of all values. + :rtype: Tuple[CommonBusinessCustomerStarRatingType] + """ + if exclude_values is None: + exclude_values = (cls.INVALID,) + # noinspection PyTypeChecker + value_list: Tuple[CommonBusinessCustomerStarRatingType, ...] = tuple([value for value in cls.values if value not in exclude_values]) + return value_list + + @classmethod + def get_all_names(cls, exclude_values: Iterator['CommonBusinessCustomerStarRatingType'] = None) -> Tuple[str]: + """get_all_names(exclude_values=None) + + Retrieve a collection of the names of all values. + + :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonBusinessCustomerStarRatingType], optional + :return: A collection of the names of all values. + :rtype: Tuple[str] + """ + name_list: Tuple[str] = tuple([value.name for value in cls.get_all(exclude_values=exclude_values)]) + return name_list + + @classmethod + def get_comma_separated_names_string(cls, exclude_values: Iterator['CommonBusinessCustomerStarRatingType'] = None) -> str: + """get_comma_separated_names_string(exclude_values=None) + + Create a string containing all names of all values, separated by a comma. + + :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonBusinessCustomerStarRatingType], optional + :return: A string containing all names of all values, separated by a comma. + :rtype: str + """ + return ', '.join(cls.get_all_names(exclude_values=exclude_values)) + + @staticmethod + def convert_to_vanilla(value: 'CommonBusinessCustomerStarRatingType') -> BusinessCustomerStarRatingBuffBuckets: + """convert_to_vanilla(value) + + Convert a value into the vanilla BusinessCustomerStarRatingBuffBuckets enum. + + :param value: An instance of CommonBusinessCustomerStarRatingType + :type value: CommonBusinessCustomerStarRatingType + :return: The specified value translated to BusinessCustomerStarRatingBuffBuckets or INVALID if the value could not be translated. + :rtype: BusinessCustomerStarRatingBuffBuckets + """ + if value is None or value == CommonBusinessCustomerStarRatingType.INVALID: + return BusinessCustomerStarRatingBuffBuckets.INVALID + if isinstance(value, BusinessCustomerStarRatingBuffBuckets): + return value + mapping = dict() + if hasattr(BusinessCustomerStarRatingBuffBuckets, 'SERVICE'): + mapping[CommonBusinessCustomerStarRatingType.SERVICE] = BusinessCustomerStarRatingBuffBuckets.SERVICE + if hasattr(BusinessCustomerStarRatingBuffBuckets, 'AMBIANCE'): + mapping[CommonBusinessCustomerStarRatingType.AMBIANCE] = BusinessCustomerStarRatingBuffBuckets.AMBIANCE + if hasattr(BusinessCustomerStarRatingBuffBuckets, 'FOOD_QUALITY'): + mapping[CommonBusinessCustomerStarRatingType.FOOD_QUALITY] = BusinessCustomerStarRatingBuffBuckets.FOOD_QUALITY + if hasattr(BusinessCustomerStarRatingBuffBuckets, 'FOOD_VALUE'): + mapping[CommonBusinessCustomerStarRatingType.FOOD_VALUE] = BusinessCustomerStarRatingBuffBuckets.FOOD_VALUE + if hasattr(BusinessCustomerStarRatingBuffBuckets, 'PERSONAL_TOUCH'): + mapping[CommonBusinessCustomerStarRatingType.PERSONAL_TOUCH] = BusinessCustomerStarRatingBuffBuckets.PERSONAL_TOUCH + if hasattr(BusinessCustomerStarRatingBuffBuckets, 'WAIT_TIME'): + mapping[CommonBusinessCustomerStarRatingType.WAIT_TIME] = BusinessCustomerStarRatingBuffBuckets.WAIT_TIME + if hasattr(BusinessCustomerStarRatingBuffBuckets, 'MISC'): + mapping[CommonBusinessCustomerStarRatingType.MISC] = BusinessCustomerStarRatingBuffBuckets.MISC + if hasattr(BusinessCustomerStarRatingBuffBuckets, 'STRESS_LEVEL'): + mapping[CommonBusinessCustomerStarRatingType.STRESS_LEVEL] = BusinessCustomerStarRatingBuffBuckets.STRESS_LEVEL + if hasattr(BusinessCustomerStarRatingBuffBuckets, 'SERVICE_VALUE'): + mapping[CommonBusinessCustomerStarRatingType.SERVICE_VALUE] = BusinessCustomerStarRatingBuffBuckets.SERVICE_VALUE + if hasattr(BusinessCustomerStarRatingBuffBuckets, 'SERVICE_QUALITY'): + mapping[CommonBusinessCustomerStarRatingType.SERVICE_QUALITY] = BusinessCustomerStarRatingBuffBuckets.SERVICE_QUALITY + return mapping.get(value, BusinessCustomerStarRatingBuffBuckets.INVALID) + + @staticmethod + def convert_from_vanilla(value: Union[int, BusinessCustomerStarRatingBuffBuckets]) -> 'CommonBusinessCustomerStarRatingType': + """convert_from_vanilla(value) + + Convert a value into a CommonBusinessCustomerStarRatingType enum. + + :param value: An instance of BusinessCustomerStarRatingBuffBuckets + :type value: BusinessCustomerStarRatingBuffBuckets + :return: The specified value translated to CommonBusinessCustomerStarRatingType or INVALID if the value could not be translated. + :rtype: CommonBusinessCustomerStarRatingType + """ + if value is None or value == BusinessCustomerStarRatingBuffBuckets.INVALID: + return CommonBusinessCustomerStarRatingType.INVALID + if isinstance(value, CommonBusinessCustomerStarRatingType): + return value + mapping = dict() + if hasattr(BusinessCustomerStarRatingBuffBuckets, 'SERVICE'): + mapping[BusinessCustomerStarRatingBuffBuckets.SERVICE] = CommonBusinessCustomerStarRatingType.SERVICE + if hasattr(BusinessCustomerStarRatingBuffBuckets, 'AMBIANCE'): + mapping[BusinessCustomerStarRatingBuffBuckets.AMBIANCE] = CommonBusinessCustomerStarRatingType.AMBIANCE + if hasattr(BusinessCustomerStarRatingBuffBuckets, 'FOOD_QUALITY'): + mapping[BusinessCustomerStarRatingBuffBuckets.FOOD_QUALITY] = CommonBusinessCustomerStarRatingType.FOOD_QUALITY + if hasattr(BusinessCustomerStarRatingBuffBuckets, 'FOOD_VALUE'): + mapping[BusinessCustomerStarRatingBuffBuckets.FOOD_VALUE] = CommonBusinessCustomerStarRatingType.FOOD_VALUE + if hasattr(BusinessCustomerStarRatingBuffBuckets, 'PERSONAL_TOUCH'): + mapping[BusinessCustomerStarRatingBuffBuckets.PERSONAL_TOUCH] = CommonBusinessCustomerStarRatingType.PERSONAL_TOUCH + if hasattr(BusinessCustomerStarRatingBuffBuckets, 'WAIT_TIME'): + mapping[BusinessCustomerStarRatingBuffBuckets.WAIT_TIME] = CommonBusinessCustomerStarRatingType.WAIT_TIME + if hasattr(BusinessCustomerStarRatingBuffBuckets, 'MISC'): + mapping[BusinessCustomerStarRatingBuffBuckets.MISC] = CommonBusinessCustomerStarRatingType.MISC + if hasattr(BusinessCustomerStarRatingBuffBuckets, 'STRESS_LEVEL'): + mapping[BusinessCustomerStarRatingBuffBuckets.STRESS_LEVEL] = CommonBusinessCustomerStarRatingType.STRESS_LEVEL + if hasattr(BusinessCustomerStarRatingBuffBuckets, 'SERVICE_VALUE'): + mapping[BusinessCustomerStarRatingBuffBuckets.SERVICE_VALUE] = CommonBusinessCustomerStarRatingType.SERVICE_VALUE + if hasattr(BusinessCustomerStarRatingBuffBuckets, 'SERVICE_QUALITY'): + mapping[BusinessCustomerStarRatingBuffBuckets.SERVICE_QUALITY] = CommonBusinessCustomerStarRatingType.SERVICE_QUALITY + return mapping.get(value, CommonBusinessCustomerStarRatingType.INVALID) + + diff --git a/Scripts/s4ap/sims4communitylib/enums/common_business_employee_type.py b/Scripts/s4ap/sims4communitylib/enums/common_business_employee_type.py new file mode 100644 index 0000000..3b15b97 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_business_employee_type.py @@ -0,0 +1,122 @@ +""" +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 +""" +from typing import Iterator, Tuple, Union + +from business.business_enums import BusinessEmployeeType +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonBusinessEmployeeType(CommonInt): + """Employee types of various businesses.""" + INVALID: 'CommonBusinessEmployeeType' = ... + RETAIL: 'CommonBusinessEmployeeType' = ... + RESTAURANT_CHEF: 'CommonBusinessEmployeeType' = ... + RESTAURANT_WAITSTAFF: 'CommonBusinessEmployeeType' = ... + RESTAURANT_HOST: 'CommonBusinessEmployeeType' = ... + VET: 'CommonBusinessEmployeeType' = ... + + @classmethod + def get_all(cls, exclude_values: Iterator['CommonBusinessEmployeeType'] = None) -> Tuple['CommonBusinessEmployeeType']: + """get_all(exclude_values=None) + + Get a collection of all values. + + :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonBusinessEmployeeType], optional + :return: A collection of all values. + :rtype: Tuple[CommonBusinessEmployeeType] + """ + if exclude_values is None: + exclude_values = (cls.INVALID,) + # noinspection PyTypeChecker + value_list: Tuple[CommonBusinessEmployeeType, ...] = tuple([value for value in cls.values if value not in exclude_values]) + return value_list + + @classmethod + def get_all_names(cls, exclude_values: Iterator['CommonBusinessEmployeeType'] = None) -> Tuple[str]: + """get_all_names(exclude_values=None) + + Retrieve a collection of the names of all values. + + :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonBusinessEmployeeType], optional + :return: A collection of the names of all values. + :rtype: Tuple[str] + """ + name_list: Tuple[str] = tuple([value.name for value in cls.get_all(exclude_values=exclude_values)]) + return name_list + + @classmethod + def get_comma_separated_names_string(cls, exclude_values: Iterator['CommonBusinessEmployeeType'] = None) -> str: + """get_comma_separated_names_string(exclude_values=None) + + Create a string containing all names of all values, separated by a comma. + + :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonBusinessEmployeeType], optional + :return: A string containing all names of all values, separated by a comma. + :rtype: str + """ + return ', '.join(cls.get_all_names(exclude_values=exclude_values)) + + @staticmethod + def convert_to_vanilla(value: 'CommonBusinessEmployeeType') -> BusinessEmployeeType: + """convert_to_vanilla(value) + + Convert a value into the vanilla BusinessEmployeeType enum. + + :param value: An instance of CommonBusinessEmployeeType + :type value: CommonBusinessEmployeeType + :return: The specified value translated to BusinessEmployeeType or INVALID if the value could not be translated. + :rtype: BusinessEmployeeType + """ + if value is None or value == CommonBusinessEmployeeType.INVALID: + return BusinessEmployeeType.INVALID + if isinstance(value, BusinessEmployeeType): + return value + mapping = dict() + if hasattr(BusinessEmployeeType, 'RETAIL'): + mapping[CommonBusinessEmployeeType.RETAIL] = BusinessEmployeeType.RETAIL + if hasattr(BusinessEmployeeType, 'RESTAURANT_CHEF'): + mapping[CommonBusinessEmployeeType.RESTAURANT_CHEF] = BusinessEmployeeType.RESTAURANT_CHEF + if hasattr(BusinessEmployeeType, 'RESTAURANT_WAITSTAFF'): + mapping[CommonBusinessEmployeeType.RESTAURANT_WAITSTAFF] = BusinessEmployeeType.RESTAURANT_WAITSTAFF + if hasattr(BusinessEmployeeType, 'RESTAURANT_HOST'): + mapping[CommonBusinessEmployeeType.RESTAURANT_HOST] = BusinessEmployeeType.RESTAURANT_HOST + if hasattr(BusinessEmployeeType, 'VET'): + mapping[CommonBusinessEmployeeType.VET] = BusinessEmployeeType.VET + return mapping.get(value, BusinessEmployeeType.INVALID) + + @staticmethod + def convert_from_vanilla(value: Union[int, BusinessEmployeeType]) -> 'CommonBusinessEmployeeType': + """convert_from_vanilla(value) + + Convert a value into a CommonBusinessEmployeeType enum. + + :param value: An instance of BusinessEmployeeType + :type value: BusinessEmployeeType + :return: The specified value translated to CommonBusinessEmployeeType or INVALID if the value could not be translated. + :rtype: CommonBusinessEmployeeType + """ + if value is None or value == BusinessEmployeeType.INVALID: + return CommonBusinessEmployeeType.INVALID + if isinstance(value, CommonBusinessEmployeeType): + return value + mapping = dict() + if hasattr(BusinessEmployeeType, 'RETAIL'): + mapping[BusinessEmployeeType.RETAIL] = CommonBusinessEmployeeType.RETAIL + if hasattr(BusinessEmployeeType, 'RESTAURANT_CHEF'): + mapping[BusinessEmployeeType.RESTAURANT_CHEF] = CommonBusinessEmployeeType.RESTAURANT_CHEF + if hasattr(BusinessEmployeeType, 'RESTAURANT_WAITSTAFF'): + mapping[BusinessEmployeeType.RESTAURANT_WAITSTAFF] = CommonBusinessEmployeeType.RESTAURANT_WAITSTAFF + if hasattr(BusinessEmployeeType, 'RESTAURANT_HOST'): + mapping[BusinessEmployeeType.RESTAURANT_HOST] = CommonBusinessEmployeeType.RESTAURANT_HOST + if hasattr(BusinessEmployeeType, 'VET'): + mapping[BusinessEmployeeType.VET] = CommonBusinessEmployeeType.VET + return mapping.get(value, CommonBusinessEmployeeType.INVALID) + diff --git a/Scripts/s4ap/sims4communitylib/enums/common_business_quality_type.py b/Scripts/s4ap/sims4communitylib/enums/common_business_quality_type.py new file mode 100644 index 0000000..1b31fd0 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_business_quality_type.py @@ -0,0 +1,111 @@ +""" +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 +""" +from typing import Iterator, Tuple, Union + +from business.business_enums import BusinessQualityType +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonBusinessQualityType(CommonInt): + """Different quality types of a Business.""" + INVALID: 'CommonBusinessQualityType' = ... + LOW: 'CommonBusinessQualityType' = ... + MEDIUM: 'CommonBusinessQualityType' = ... + HIGH: 'CommonBusinessQualityType' = ... + + @classmethod + def get_all(cls, exclude_values: Iterator['CommonBusinessQualityType'] = None) -> Tuple['CommonBusinessQualityType']: + """get_all(exclude_values=None) + + Get a collection of all values. + + :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonBusinessQualityType], optional + :return: A collection of all values. + :rtype: Tuple[CommonBusinessQualityType] + """ + if exclude_values is None: + exclude_values = (cls.INVALID,) + # noinspection PyTypeChecker + value_list: Tuple[CommonBusinessQualityType, ...] = tuple([value for value in cls.values if value not in exclude_values]) + return value_list + + @classmethod + def get_all_names(cls, exclude_values: Iterator['CommonBusinessQualityType'] = None) -> Tuple[str]: + """get_all_names(exclude_values=None) + + Retrieve a collection of the names of all values. + + :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonBusinessQualityType], optional + :return: A collection of the names of all values. + :rtype: Tuple[str] + """ + name_list: Tuple[str] = tuple([value.name for value in cls.get_all(exclude_values=exclude_values)]) + return name_list + + @classmethod + def get_comma_separated_names_string(cls, exclude_values: Iterator['CommonBusinessQualityType'] = None) -> str: + """get_comma_separated_names_string(exclude_values=None) + + Create a string containing all names of all values, separated by a comma. + + :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonBusinessQualityType], optional + :return: A string containing all names of all values, separated by a comma. + :rtype: str + """ + return ', '.join(cls.get_all_names(exclude_values=exclude_values)) + + @staticmethod + def convert_to_vanilla(value: 'CommonBusinessQualityType') -> BusinessQualityType: + """convert_to_vanilla(value) + + Convert a value into the vanilla BusinessQualityType enum. + + :param value: An instance of CommonBusinessQualityType + :type value: CommonBusinessQualityType + :return: The specified value translated to BusinessQualityType or INVALID if the value could not be translated. + :rtype: BusinessQualityType + """ + if value is None or value == CommonBusinessQualityType.INVALID: + return BusinessQualityType.INVALID + if isinstance(value, BusinessQualityType): + return value + mapping = dict() + if hasattr(BusinessQualityType, 'LOW'): + mapping[CommonBusinessQualityType.LOW] = BusinessQualityType.LOW + if hasattr(BusinessQualityType, 'MEDIUM'): + mapping[CommonBusinessQualityType.MEDIUM] = BusinessQualityType.MEDIUM + if hasattr(BusinessQualityType, 'HIGH'): + mapping[CommonBusinessQualityType.HIGH] = BusinessQualityType.HIGH + return mapping.get(value, BusinessQualityType.INVALID) + + @staticmethod + def convert_from_vanilla(value: Union[int, BusinessQualityType]) -> 'CommonBusinessQualityType': + """convert_from_vanilla(value) + + Convert a value into a CommonBusinessQualityType enum. + + :param value: An instance of BusinessQualityType + :type value: BusinessQualityType + :return: The specified value translated to CommonBusinessQualityType or INVALID if the value could not be translated. + :rtype: CommonBusinessQualityType + """ + if value is None or value == BusinessQualityType.INVALID: + return CommonBusinessQualityType.INVALID + if isinstance(value, CommonBusinessQualityType): + return value + mapping = dict() + if hasattr(BusinessQualityType, 'LOW'): + mapping[BusinessQualityType.LOW] = CommonBusinessQualityType.LOW + if hasattr(BusinessQualityType, 'MEDIUM'): + mapping[BusinessQualityType.MEDIUM] = CommonBusinessQualityType.MEDIUM + if hasattr(BusinessQualityType, 'HIGH'): + mapping[BusinessQualityType.HIGH] = CommonBusinessQualityType.HIGH + return mapping.get(value, CommonBusinessQualityType.INVALID) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_career_ids.py b/Scripts/s4ap/sims4communitylib/enums/common_career_ids.py new file mode 100644 index 0000000..5122c93 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_career_ids.py @@ -0,0 +1,145 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonCareerId(CommonInt): + """Decimal Identifiers for Careers. + + """ + ACTIVE_ACTOR: 'CommonCareerId' = 189135 + ACTIVE_DOCTOR: 'CommonCareerId' = 107230 + ACTIVE_SCIENTIST: 'CommonCareerId' = 107255 + ACTIVIST: 'CommonCareerId' = 135201 + ASTRONAUT: 'CommonCareerId' = 12893 + ATHLETIC: 'CommonCareerId' = 106458 + BATUU_MISSIONS: 'CommonCareerId' = 231099 + BUSINESS: 'CommonCareerId' = 106460 + CIVIL_DESIGNER: 'CommonCareerId' = 232767 + CONSERVATIONIST: 'CommonCareerId' = 204960 + CORPORATE_WORKER: 'CommonCareerId' = 248315 + COTTAGE_WORLD_VILLAGER_HELP: 'CommonCareerId' = 260893 + CRIMINAL: 'CommonCareerId' = 27927 + CRITIC: 'CommonCareerId' = 136115 + CULINARY: 'CommonCareerId' = 9231 + DETECTIVE: 'CommonCareerId' = 106132 + EDUCATION: 'CommonCareerId' = 219591 + ENGINEER: 'CommonCareerId' = 217872 + ENTERTAINER: 'CommonCareerId' = 27929 + FREELANCER_WITH_AGENCY_ARTIST: 'CommonCareerId' = 205686 + FREELANCER_WITH_AGENCY_FASHION_PHOTOGRAPHER: 'CommonCareerId' = 214782 + FREELANCER_WITH_AGENCY_MAKER: 'CommonCareerId' = 232809 + FREELANCER_WITH_AGENCY_NONE: 'CommonCareerId' = 206791 + FREELANCER_WITH_AGENCY_PARANORMAL_INVESTIGATOR: 'CommonCareerId' = 252593 + FREELANCER_WITH_AGENCY_PROGRAMMER: 'CommonCareerId' = 207568 + FREELANCER_WITH_AGENCY_WRITER: 'CommonCareerId' = 207579 + GARDENER: 'CommonCareerId' = 186159 + INTERIOR_DECORATOR: 'CommonCareerId' = 257934 + LAW: 'CommonCareerId' = 223298 + MILITARY: 'CommonCareerId' = 202483 + NPC_ACTOR_CAREER_CAMERA_OPERATOR: 'CommonCareerId' = 196625 + NPC_ACTOR_CAREER_HAIR_AND_MAKEUP_STYLIST: 'CommonCareerId' = 195951 + NPC_ACTOR_CAREER_PRODUCER: 'CommonCareerId' = 196627 + NPC_ACTOR_CAREER_SPECIAL_EFFECTS_OPERATOR: 'CommonCareerId' = 196558 + NPC_ACTOR_CAREER_WARDROBE_STYLIST: 'CommonCareerId' = 195952 + NPC_BUSINESS_RESTAURANT_CHEF: 'CommonCareerId' = 136209 + NPC_BUSINESS_RESTAURANT_CRITIC: 'CommonCareerId' = 139565 + NPC_BUSINESS_RESTAURANT_HOST: 'CommonCareerId' = 136208 + NPC_BUSINESS_RESTAURANT_WAITER: 'CommonCareerId' = 136210 + NPC_BUSINESS_RETAIL_EMPLOYEE: 'CommonCareerId' = 110057 + NPC_BUSINESS_VET_CLINIC_VET: 'CommonCareerId' = 168569 + NPC_CHESTNUT_RIDGE_HORSE_TRAINER: 'CommonCareerId' = 324723 + NPC_CHESTNUT_RIDGE_MYSTERIOUS_RANCHER: 'CommonCareerId' = 324722 + NPC_COTTAGE_WORLD_GARDEN_SHOP_OWNER: 'CommonCareerId' = 260407 + NPC_COTTAGE_WORLD_GROCERY_STORE_DELIVERY: 'CommonCareerId' = 260409 + NPC_COTTAGE_WORLD_GROCERY_STORE_OWNER: 'CommonCareerId' = 260408 + NPC_HIGH_SCHOOL_ACTIVE_TEACHER: 'CommonCareerId' = 296393 + NPC_RANCH_HAND: 'CommonCareerId' = 304769 + NPC_SERVICES_BONEHILDA: 'CommonCareerId' = 256924 + NPC_SERVICES_BUTLER: 'CommonCareerId' = 147718 + NPC_SERVICES_DELIVERIES_FOOD: 'CommonCareerId' = 262368 + NPC_SERVICES_DELIVERIES_PIZZA: 'CommonCareerId' = 110043 + NPC_SERVICES_FIREFIGHTER: 'CommonCareerId' = 237780 + NPC_SERVICES_GARDENER: 'CommonCareerId' = 130529 + NPC_SERVICES_HOME_CHEF: 'CommonCareerId' = 140900 + NPC_SERVICES_MAID: 'CommonCareerId' = 109456 + NPC_SERVICES_MAIL: 'CommonCareerId' = 109457 + NPC_SERVICES_MASSAGE_THERAPIST: 'CommonCareerId' = 119666 + NPC_SERVICES_NANNY: 'CommonCareerId' = 141901 + NPC_SERVICES_REPAIR: 'CommonCareerId' = 129471 + NPC_SPECIAL_ADOPTION_OFFICER: 'CommonCareerId' = 175923 + NPC_SPECIAL_ECO_INSPECTOR: 'CommonCareerId' = 242362 + NPC_SPECIAL_FATHER_WINTER: 'CommonCareerId' = 183371 + NPC_SPECIAL_GRIM_REAPER: 'CommonCareerId' = 110326 + NPC_SPECIAL_GYM_TRAINER: 'CommonCareerId' = 112014 + NPC_SPECIAL_MASTER_FISHER: 'CommonCareerId' = 112090 + NPC_SPECIAL_RANGER: 'CommonCareerId' = 112104 + NPC_SPECIAL_TRAGIC_CLOWN: 'CommonCareerId' = 139889 + NPC_SPECIAL_YOGA_INSTRUCTOR: 'CommonCareerId' = 118612 + NPC_STRANGER_VILLE_ALIEN_POLLINATOR: 'CommonCareerId' = 115639 + NPC_STRANGER_VILLE_OGA: 'CommonCareerId' = 205712 + NPC_STRANGER_VILLE_SCIENTIST: 'CommonCareerId' = 205705 + NPC_UNIVERSITY_PROFESSOR_ARTS: 'CommonCareerId' = 224750 + NPC_UNIVERSITY_PROFESSOR_SCIENCE: 'CommonCareerId' = 224751 + NPC_VENUE_BARISTA: 'CommonCareerId' = 122270 + NPC_VENUE_BARTENDER: 'CommonCareerId' = 109458 + NPC_VENUE_BARTENDER_COMPANY: 'CommonCareerId' = 130590 + NPC_VENUE_BAR_REGULAR: 'CommonCareerId' = 122658 + NPC_VENUE_COMMUNITY_GARDENER: 'CommonCareerId' = 112083 + NPC_VENUE_CURIO_SHOP_OWNER: 'CommonCareerId' = 206662 + NPC_VENUE_DJ: 'CommonCareerId' = 122818 + NPC_VENUE_LANDLORD: 'CommonCareerId' = 143653 + NPC_VENUE_LIBRARIAN: 'CommonCareerId' = 112015 + NPC_VENUE_MASSAGE_THERAPIST: 'CommonCareerId' = 118550 + NPC_VENUE_MAYOR: 'CommonCareerId' = 260410 + NPC_VENUE_PAPARAZZI: 'CommonCareerId' = 197295 + NPC_VENUE_PUB_OWNER: 'CommonCareerId' = 260411 + NPC_VENUE_REFLEXOLOGIST: 'CommonCareerId' = 119506 + NPC_VENUE_STALL_VENDOR: 'CommonCareerId' = 143285 + NPC_VENUE_STALL_VENDOR_WEDDING_FLOWER: 'CommonCareerId' = 276665 + NPC_WOLF_TOWN_BARTENDER: 'CommonCareerId' = 294303 + ODD_JOB: 'CommonCareerId' = 207004 + PAINTER: 'CommonCareerId' = 27930 + PART_TIME_BABY_SITTER_ADULT: 'CommonCareerId' = 208723 + PART_TIME_BABY_SITTER_TEEN: 'CommonCareerId' = 35221 + PART_TIME_BARISTA_ADULT: 'CommonCareerId' = 208737 + PART_TIME_BARISTA_TEEN: 'CommonCareerId' = 35220 + PART_TIME_DIVER: 'CommonCareerId' = 208405 + PART_TIME_FAST_FOOD_ADULT: 'CommonCareerId' = 208761 + PART_TIME_FAST_FOOD_TEEN: 'CommonCareerId' = 35157 + PART_TIME_FISHERMAN: 'CommonCareerId' = 207607 + PART_TIME_LIFEGUARD_ADULT: 'CommonCareerId' = 205662 + PART_TIME_LIFEGUARD_TEEN: 'CommonCareerId' = 208881 + PART_TIME_MANUAL_LABOR_ADULT: 'CommonCareerId' = 208779 + PART_TIME_MANUAL_LABOR_TEEN: 'CommonCareerId' = 35218 + PART_TIME_RETAIL_ADULT: 'CommonCareerId' = 208874 + PART_TIME_RETAIL_TEEN: 'CommonCareerId' = 35219 + PART_TIME_SIMSFLUENCER_SIDE_HUSTLE_ADULT: 'CommonCareerId' = 277662 + PART_TIME_SIMSFLUENCER_SIDE_HUSTLE_TEEN: 'CommonCareerId' = 277663 + PART_TIME_STREAMER_SIDE_HUSTLE_ADULT: 'CommonCareerId' = 273912 + PART_TIME_STREAMER_SIDE_HUSTLE_TEEN: 'CommonCareerId' = 273911 + SCHOOL_CHILD: 'CommonCareerId' = 12895 + SCHOOL_TEEN: 'CommonCareerId' = 9541 + SECRET_AGENT: 'CommonCareerId' = 27931 + SOCIAL_MEDIA: 'CommonCareerId' = 135363 + STYLE_INFLUENCER: 'CommonCareerId' = 193202 + TECH_GURU: 'CommonCareerId' = 27932 + UNIVERSITY: 'CommonCareerId' = 223698 + UNIVERSITY_COURSE_SLOT_A: 'CommonCareerId' = 209979 + UNIVERSITY_COURSE_SLOT_B: 'CommonCareerId' = 209984 + UNIVERSITY_COURSE_SLOT_C: 'CommonCareerId' = 209988 + UNIVERSITY_COURSE_SLOT_D: 'CommonCareerId' = 209989 + VOLUNTEER_DRAMA_CLUB: 'CommonCareerId' = 199274 + VOLUNTEER_E_SPORTS: 'CommonCareerId' = 217092 + VOLUNTEER_HIGH_SCHOOL_TEAM_CHEER_TEAM: 'CommonCareerId' = 276604 + VOLUNTEER_HIGH_SCHOOL_TEAM_CHESS_TEAM: 'CommonCareerId' = 276602 + VOLUNTEER_HIGH_SCHOOL_TEAM_COMPUTER_TEAM: 'CommonCareerId' = 276603 + VOLUNTEER_HIGH_SCHOOL_TEAM_FOOTBALL_TEAM: 'CommonCareerId' = 276605 + VOLUNTEER_SCOUTING: 'CommonCareerId' = 186513 + VOLUNTEER_SOCCER_TEAM: 'CommonCareerId' = 220913 + WRITER: 'CommonCareerId' = 27933 diff --git a/Scripts/s4ap/sims4communitylib/enums/common_character_restrictions.py b/Scripts/s4ap/sims4communitylib/enums/common_character_restrictions.py new file mode 100644 index 0000000..f49406c --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_character_restrictions.py @@ -0,0 +1,16 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonCharacterRestriction(CommonInt): + """Character restrictions for use in text input fields. + + """ + NONE: 'CommonCharacterRestriction' = ... + NUMBERS_ONLY: 'CommonCharacterRestriction' = ... diff --git a/Scripts/s4ap/sims4communitylib/enums/common_civic_policy_status_type.py b/Scripts/s4ap/sims4communitylib/enums/common_civic_policy_status_type.py new file mode 100644 index 0000000..b5c727e --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_civic_policy_status_type.py @@ -0,0 +1,16 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonCivicPolicyStatusType(CommonInt): + """ The status a Civic Policy may have in a Zone or Venue. """ + ENACTED = ... + BALLOTED = ... + UP_FOR_REPEAL = ... + DORMANT = ... diff --git a/Scripts/s4ap/sims4communitylib/enums/common_civic_policy_type.py b/Scripts/s4ap/sims4communitylib/enums/common_civic_policy_type.py new file mode 100644 index 0000000..d0483de --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_civic_policy_type.py @@ -0,0 +1,14 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonCivicPolicyType(CommonInt): + """ The types of Civic Policies. """ + STREET = ... + VENUE = ... diff --git a/Scripts/s4ap/sims4communitylib/enums/common_cloud_type.py b/Scripts/s4ap/sims4communitylib/enums/common_cloud_type.py new file mode 100644 index 0000000..f0c8f14 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_cloud_type.py @@ -0,0 +1,116 @@ +""" +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 +""" +from typing import Tuple, Union, Iterator + +from sims4communitylib.enums.enumtypes.common_int import CommonInt + +# noinspection PyBroadException +try: + from weather.weather_enums import CloudType +except: + class CloudType(CommonInt): + """Mock class.""" + PARTLY_CLOUDY = 2000 + CLEAR = 2001 + LIGHT_RAINCLOUDS = 2002 + DARK_RAINCLOUDS = 2003 + # noinspection SpellCheckingInspection + LIGHT_SNOWCLOUDS = 2004 + # noinspection SpellCheckingInspection + DARK_SNOWCLOUDS = 2005 + CLOUDY = 2006 + HEATWAVE = 2007 + STRANGE = 2008 + VERY_STRANGE = 2009 + SKYBOX_INDUSTRIAL = 2010 + + +class CommonCloudType(CommonInt): + """Identifiers for cloud types.""" + PARTLY_CLOUDY: 'CommonCloudType' = ... + CLEAR: 'CommonCloudType' = ... + LIGHT_RAIN_CLOUDS: 'CommonCloudType' = ... + DARK_RAIN_CLOUDS: 'CommonCloudType' = ... + LIGHT_SNOW_CLOUDS: 'CommonCloudType' = ... + DARK_SNOW_CLOUDS: 'CommonCloudType' = ... + CLOUDY: 'CommonCloudType' = ... + HEATWAVE: 'CommonCloudType' = ... + STRANGE: 'CommonCloudType' = ... + VERY_STRANGE: 'CommonCloudType' = ... + SKY_BOX_INDUSTRIAL: 'CommonCloudType' = ... + + @classmethod + def get_all(cls, exclude_values: Iterator['CommonCloudType'] = ()) -> Tuple['CommonCloudType']: + """get_all(exclude_values=()) + + Get a collection of all values. + + :param exclude_values: These values will be excluded. Default is an empty collection. + :type exclude_values: Iterator[CommonCloudType], optional + :return: A collection of all values. + :rtype: Tuple[CommonCloudType] + """ + # noinspection PyTypeChecker + value_list: Tuple[CommonCloudType, ...] = tuple([value for value in cls.values if value not in exclude_values]) + return value_list + + @staticmethod + def convert_to_vanilla(value: 'CommonCloudType') -> Union[CloudType, None]: + """convert_to_vanilla(value) + + Convert a CommonCloudType into the vanilla CloudType enum. + + :param value: An instance of CommonCloudType + :type value: CommonCloudType + :return: The specified CommonCloudType translated to CloudType or None if a vanilla CloudType is not found. + :rtype: Union[CloudType, None] + """ + if isinstance(value, CloudType): + return value + mapping = { + CommonCloudType.PARTLY_CLOUDY: CloudType.PARTLY_CLOUDY, + CommonCloudType.CLEAR: CloudType.CLEAR, + CommonCloudType.LIGHT_RAIN_CLOUDS: CloudType.LIGHT_RAINCLOUDS, + CommonCloudType.DARK_RAIN_CLOUDS: CloudType.DARK_RAINCLOUDS, + CommonCloudType.LIGHT_SNOW_CLOUDS: CloudType.LIGHT_SNOWCLOUDS, + CommonCloudType.DARK_SNOW_CLOUDS: CloudType.DARK_SNOWCLOUDS, + CommonCloudType.CLOUDY: CloudType.CLOUDY, + CommonCloudType.HEATWAVE: CloudType.HEATWAVE, + CommonCloudType.STRANGE: CloudType.STRANGE, + CommonCloudType.VERY_STRANGE: CloudType.VERY_STRANGE, + CommonCloudType.SKY_BOX_INDUSTRIAL: CloudType.SKYBOX_INDUSTRIAL, + } + return mapping.get(value, value) + + @staticmethod + def convert_from_vanilla(value: CloudType) -> Union['CommonCloudType', None]: + """convert_from_vanilla(value) + + Convert a vanilla CloudType into a CommonCloudType enum. + + :param value: An instance of CommonCloudType + :type value: CommonCloudType + :return: The specified CloudType translated to CloudType or None if the value could not be translated. + :rtype: Union[CloudType, None] + """ + if isinstance(value, CommonCloudType): + return value + mapping = { + CloudType.PARTLY_CLOUDY: CommonCloudType.PARTLY_CLOUDY, + CloudType.CLEAR: CommonCloudType.CLEAR, + CloudType.LIGHT_RAINCLOUDS: CommonCloudType.LIGHT_RAIN_CLOUDS, + CloudType.DARK_RAINCLOUDS: CommonCloudType.DARK_RAIN_CLOUDS, + CloudType.LIGHT_SNOWCLOUDS: CommonCloudType.LIGHT_SNOW_CLOUDS, + CloudType.DARK_SNOWCLOUDS: CommonCloudType.DARK_SNOW_CLOUDS, + CloudType.CLOUDY: CommonCloudType.CLOUDY, + CloudType.HEATWAVE: CommonCloudType.HEATWAVE, + CloudType.STRANGE: CommonCloudType.STRANGE, + CloudType.VERY_STRANGE: CommonCloudType.VERY_STRANGE, + CloudType.SKYBOX_INDUSTRIAL: CommonCloudType.SKY_BOX_INDUSTRIAL, + } + return mapping.get(value, value) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_combined_species.py b/Scripts/s4ap/sims4communitylib/enums/common_combined_species.py new file mode 100644 index 0000000..3ff58b7 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_combined_species.py @@ -0,0 +1,96 @@ +""" +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 +""" +from typing import Tuple + +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonCombinedSpecies(CommonInt): + """Various combined species types to reduce code ugliness""" + NONE: 'CommonCombinedSpecies' = ... + HUMAN: 'CommonCombinedSpecies' = ... # Human + ANIMAL: 'CommonCombinedSpecies' = ... # Large Dog, Small Dog, Cat, Fox + PET: 'CommonCombinedSpecies' = ... # Large Dog, Small Dog, Cat + NON_PET: 'CommonCombinedSpecies' = ... # Fox + DOG: 'CommonCombinedSpecies' = ... # Large Dog, Small Dog + CAT: 'CommonCombinedSpecies' = ... # Cat + FOX: 'CommonCombinedSpecies' = ... # Fox + HORSE: 'CommonCombinedSpecies' = ... # Horse + + @classmethod + def convert_to_signature(cls, combined_species: 'CommonCombinedSpecies') -> str: + """convert_to_signature(combined_species) + + Convert a CommonCombinedSpecies to a unique signature. + + :param combined_species: The value to convert. + :type combined_species: CommonCombinedSpecies + :return: A string signature that uniquely represents the CommonCombinedSpecies or the name of the CommonCombinedSpecies, if no unique signature is found. + :rtype: str + """ + mapping = { + CommonCombinedSpecies.HUMAN: 'Human', + CommonCombinedSpecies.ANIMAL: 'Animal', + CommonCombinedSpecies.PET: 'Pet', + CommonCombinedSpecies.NON_PET: 'Non_Pet', + CommonCombinedSpecies.DOG: 'Dog', + CommonCombinedSpecies.CAT: 'Cat', + CommonCombinedSpecies.FOX: 'Fox', + CommonCombinedSpecies.HORSE: 'Horse', + } + return mapping.get(combined_species, combined_species.name) + + @classmethod + def convert_to_enum_xml(cls, combined_species: 'CommonCombinedSpecies') -> Tuple[str]: + """convert_to_species_xml(combined_species) + + Convert a CommonCombinedSpecies to the xml representations of species. i.e. ((species),) + + :param combined_species: The value to convert. + :type combined_species: CommonCombinedSpecies + :return: A collection of strings that represent the xml associated with the value. + :rtype: Tuple[str] + """ + if combined_species == CommonCombinedSpecies.ANIMAL: + result: Tuple[str, ...] = (*cls.convert_to_enum_xml(CommonCombinedSpecies.DOG), *cls.convert_to_enum_xml(CommonCombinedSpecies.CAT), *cls.convert_to_enum_xml(CommonCombinedSpecies.FOX), *cls.convert_to_enum_xml(CommonCombinedSpecies.HORSE)) + return result + if combined_species == CommonCombinedSpecies.PET: + result: Tuple[str, ...] = (*cls.convert_to_enum_xml(CommonCombinedSpecies.DOG), *cls.convert_to_enum_xml(CommonCombinedSpecies.CAT), *cls.convert_to_enum_xml(CommonCombinedSpecies.HORSE)) + return result + if combined_species == CommonCombinedSpecies.NON_PET: + result: Tuple[str, ...] = (*cls.convert_to_enum_xml(CommonCombinedSpecies.HUMAN),) + return result + + mapping = { + CommonCombinedSpecies.HUMAN: ('HUMAN',), + CommonCombinedSpecies.DOG: ('DOG',), + CommonCombinedSpecies.CAT: ('CAT',), + CommonCombinedSpecies.FOX: ('FOX',), + CommonCombinedSpecies.HORSE: ('HORSE',), + } + return mapping.get(combined_species, tuple()) + + @classmethod + def is_animal(cls, combined_species: 'CommonCombinedSpecies') -> bool: + """is_animal(combined_species) + + Determine if a value represents an animal. + + :param combined_species: The value to check. + :type combined_species: CommonCombinedSpecies + :return: True, if the value represents an Animal. False, if not. + :rtype: bool + """ + return combined_species in ( + CommonCombinedSpecies.ANIMAL, + CommonCombinedSpecies.PET, + CommonCombinedSpecies.DOG, + CommonCombinedSpecies.CAT, + CommonCombinedSpecies.FOX, + CommonCombinedSpecies.HORSE + ) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_currency_modify_reasons.py b/Scripts/s4ap/sims4communitylib/enums/common_currency_modify_reasons.py new file mode 100644 index 0000000..f973802 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_currency_modify_reasons.py @@ -0,0 +1,54 @@ +""" +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 +""" +from protocolbuffers import Consts_pb2 +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonCurrencyModifyReason(CommonInt): + """Various reasons for currencies to be modified.""" + # Change reasons + CHEAT: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_MONEY_CHEAT + SPLIT_HOUSEHOLD: 'CommonCurrencyModifyReason' = Consts_pb2.FUNDS_SPLIT_HOUSEHOLD + + # Add reasons + INTERACTION_REWARD: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_INTERACTION_REWARD + EVENT_REWARD: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_EVENET_REWARD + OBJECT_SELL: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_OBJECT_SELL + STRUCTURE_SELL: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_STRUCTURE_SELL + LOT_SELL: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_LOT_SELL + HOUSEHOLD_TRANSFER_GAIN: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_HOUSEHOLD_TRANSFER_GAIN + SIM_POINTS_EXCHANGED: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_SIM_POINTS_EXCHANGED + SIM_WALLET_FUNDED: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_SIM_WALLET_FUNDED + CAREER: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_MONEY_CAREER + ASPIRATION_REWARD: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_MONEY_ASPIRATION_REWARD + ROYALTY: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_MONEY_ROYALTY + FIRE_INSURANCE: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_MONEY_FIREINSURANCE + RETAIL_PROFITS: 'CommonCurrencyModifyReason' = Consts_pb2.FUNDS_RETAIL_PROFITS + RETAIL_TRANSFER_GAIN: 'CommonCurrencyModifyReason' = Consts_pb2.FUNDS_RETAIL_TRANSFER_GAIN + HOLIDAY_LOTTERY: 'CommonCurrencyModifyReason' = Consts_pb2.FUNDS_HOLIDAY_LOTTERY + LIFESTYLE_BRAND: 'CommonCurrencyModifyReason' = Consts_pb2.FUNDS_LIFESTYLE_BRAND + ROOMMATE_RENT: 'CommonCurrencyModifyReason' = Consts_pb2.FUNDS_ROOMMATE_RENT + SCHOLARSHIP_SURPLUS: 'CommonCurrencyModifyReason' = Consts_pb2.FUNDS_SCHOLARSHIP_SURPLUS + MARKETPLACE_OBJECT_SALE: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_MONEY_OBJECT_MARKETPLACE_SALE + + # Remove reasons + INTERACTION_COST: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_INTERACTION_COST + EVENT_COST: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_EVENT_COST + OBJECT_BUY: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_OBJECT_BUY + STRUCTURE_BUY: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_STRUCTURE_BUY + CAS_ITEM_BUY: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_CAS_BUY + BLUEPRINT_CONSTRUCTED: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_LOT_BUY + LOT_BUY: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_LOT_BUY + HOUSEHOLD_TRANSFER_LOSS: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_HOUSEHOLD_TRANSFER_LOSS + SIM_WALLET_EMPTIED: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_SIM_WALLET_EMPTIED + CRAFTING_COST: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_CRAFTING_COST + VACATION: 'CommonCurrencyModifyReason' = Consts_pb2.FUNDS_MONEY_VACATION + RETAIL_ITEM_BUY: 'CommonCurrencyModifyReason' = Consts_pb2.FUNDS_RETAIL_ITEM_BUY + RETAIL_TRANSFER_LOSS: 'CommonCurrencyModifyReason' = Consts_pb2.FUNDS_RETAIL_TRANSFER_LOSS + TUITION_COST: 'CommonCurrencyModifyReason' = Consts_pb2.FUNDS_TUITION_COST + SIM_DEATH_COST: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_LOANS_SIM_DEATH diff --git a/Scripts/s4ap/sims4communitylib/enums/common_death_types.py b/Scripts/s4ap/sims4communitylib/enums/common_death_types.py new file mode 100644 index 0000000..d37c420 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_death_types.py @@ -0,0 +1,213 @@ +""" +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 +""" +from typing import Union + +from interactions.utils.death import DeathType +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonDeathType(CommonInt): + """Various types of deaths Sims can have.""" + NONE: 'CommonDeathType' = ... + ANGER: 'CommonDeathType' = ... + CLIMBING_ROUTE: 'CommonDeathType' = ... + COW_PLANT: 'CommonDeathType' = ... + DEATH_FLOWER_ARRANGEMENT: 'CommonDeathType' = ... + DROWN: 'CommonDeathType' = ... + ELDER_EXHAUSTION: 'CommonDeathType' = ... + ELECTROCUTION: 'CommonDeathType' = ... + EMBARRASSMENT: 'CommonDeathType' = ... + FIRE: 'CommonDeathType' = ... + FLIES: 'CommonDeathType' = ... + FROZEN: 'CommonDeathType' = ... + HUNGER: 'CommonDeathType' = ... + KILLER_CHICKEN: 'CommonDeathType' = ... + KILLER_RABBIT: 'CommonDeathType' = ... + LAUGHTER: 'CommonDeathType' = ... + LIGHTNING: 'CommonDeathType' = ... + METEORITE: 'CommonDeathType' = ... + MOTHER_PLANT: 'CommonDeathType' = ... + MURPHY_BED: 'CommonDeathType' = ... + OLD_AGE: 'CommonDeathType' = ... + OVERHEAT: 'CommonDeathType' = ... + POISON: 'CommonDeathType' = ... + PUFFERFISH: 'CommonDeathType' = ... + RODENT_DISEASE: 'CommonDeathType' = ... + STEAM: 'CommonDeathType' = ... + STINK_BOMB: 'CommonDeathType' = ... + SUN: 'CommonDeathType' = ... + URBAN_MYTH: 'CommonDeathType' = ... + VENDING_MACHINE: 'CommonDeathType' = ... + WITCH_OVERLOAD: 'CommonDeathType' = ... + + @staticmethod + def get_random() -> 'CommonDeathType': + """get_random() + + Retrieve a random death type. + + :return: A death type. + :rtype: CommonDeathType + """ + return CommonDeathType.convert_from_vanilla(DeathType.get_random_death_type()) + + @staticmethod + def convert_to_vanilla(value: Union['CommonDeathType', int, DeathType]) -> Union[DeathType, 'CommonDeathType', int]: + """convert_to_vanilla(value) + + Convert a CommonDeathType into the vanilla DeathType enum. + + :param value: An instance of a CommonDeathType + :type value: CommonDeathType + :return: The specified value translated to a DeathType or the value itself if it could not be translated. + :rtype: DeathType + """ + if value is None or value == CommonDeathType.NONE: + return DeathType.NONE + if isinstance(value, DeathType): + return value + mapping = dict() + if hasattr(DeathType, 'Hunger'): + mapping[CommonDeathType.HUNGER] = DeathType.Hunger + if hasattr(DeathType, 'Old Age'): + mapping[CommonDeathType.OLD_AGE] = getattr(DeathType, 'Old Age') + if hasattr(DeathType, 'Cowplant'): + mapping[CommonDeathType.COW_PLANT] = DeathType.Cowplant + if hasattr(DeathType, 'Electrocution'): + mapping[CommonDeathType.ELECTROCUTION] = DeathType.Electrocution + if hasattr(DeathType, 'Anger'): + mapping[CommonDeathType.ANGER] = DeathType.Anger + if hasattr(DeathType, 'Laughter'): + mapping[CommonDeathType.LAUGHTER] = DeathType.Laughter + if hasattr(DeathType, 'ElderExhaustion'): + mapping[CommonDeathType.ELDER_EXHAUSTION] = DeathType.ElderExhaustion + if hasattr(DeathType, 'Embarrassment'): + mapping[CommonDeathType.EMBARRASSMENT] = DeathType.Embarrassment + if hasattr(DeathType, 'Fire'): + mapping[CommonDeathType.FIRE] = DeathType.Fire + if hasattr(DeathType, 'Drown'): + mapping[CommonDeathType.DROWN] = DeathType.Drown + if hasattr(DeathType, 'Steam'): + mapping[CommonDeathType.STEAM] = DeathType.Steam + if hasattr(DeathType, 'Pufferfish'): + mapping[CommonDeathType.PUFFERFISH] = DeathType.Pufferfish + if hasattr(DeathType, 'Sun'): + mapping[CommonDeathType.SUN] = DeathType.Sun + if hasattr(DeathType, 'Poison'): + mapping[CommonDeathType.POISON] = DeathType.Poison + if hasattr(DeathType, 'RodentDisease'): + mapping[CommonDeathType.RODENT_DISEASE] = DeathType.RodentDisease + if hasattr(DeathType, 'Frozen'): + mapping[CommonDeathType.FROZEN] = DeathType.Frozen + if hasattr(DeathType, 'Overheat'): + mapping[CommonDeathType.OVERHEAT] = DeathType.Overheat + if hasattr(DeathType, 'Lightning'): + mapping[CommonDeathType.LIGHTNING] = DeathType.Lightning + if hasattr(DeathType, 'DeathFlowerArrangement'): + mapping[CommonDeathType.DEATH_FLOWER_ARRANGEMENT] = DeathType.DeathFlowerArrangement + if hasattr(DeathType, 'MotherPlant'): + mapping[CommonDeathType.MOTHER_PLANT] = DeathType.MotherPlant + if hasattr(DeathType, 'WitchOverload'): + mapping[CommonDeathType.WITCH_OVERLOAD] = DeathType.WitchOverload + if hasattr(DeathType, 'MurphyBed'): + mapping[CommonDeathType.MURPHY_BED] = DeathType.MurphyBed + if hasattr(DeathType, 'Flies'): + mapping[CommonDeathType.FLIES] = DeathType.Flies + if hasattr(DeathType, 'VendingMachine'): + mapping[CommonDeathType.VENDING_MACHINE] = DeathType.VendingMachine + if hasattr(DeathType, 'ClimbingRoute'): + mapping[CommonDeathType.CLIMBING_ROUTE] = DeathType.ClimbingRoute + if hasattr(DeathType, 'KillerRabbit'): + mapping[CommonDeathType.KILLER_RABBIT] = DeathType.KillerRabbit + if hasattr(DeathType, 'KillerChicken'): + mapping[CommonDeathType.KILLER_CHICKEN] = DeathType.KillerChicken + if hasattr(DeathType, 'Meteorite'): + mapping[CommonDeathType.METEORITE] = DeathType.Meteorite + if hasattr(DeathType, 'StinkBomb'): + mapping[CommonDeathType.STINK_BOMB] = DeathType.StinkBomb + if hasattr(DeathType, 'UrbanMyth'): + mapping[CommonDeathType.URBAN_MYTH] = DeathType.UrbanMyth + return mapping.get(value, DeathType.NONE) + + @staticmethod + def convert_from_vanilla(value: Union[DeathType, int, 'CommonDeathType']) -> Union['CommonDeathType', DeathType, int]: + """convert_from_vanilla(value) + + Convert a DeathType into a CommonDeathType enum. + + :param value: An instance of a DeathType + :type value: DeathType + :return: The specified value translated to a CommonDeathType or NONE if it could not be translated. + :rtype: CommonDeathType + """ + if value is None or value == DeathType.NONE: + return CommonDeathType.NONE + if isinstance(value, CommonDeathType): + return value + mapping = dict() + if hasattr(DeathType, 'Hunger'): + mapping[DeathType.Hunger] = CommonDeathType.HUNGER + if hasattr(DeathType, 'Old Age'): + mapping[getattr(DeathType, 'Old Age')] = CommonDeathType.OLD_AGE + if hasattr(DeathType, 'Cowplant'): + mapping[DeathType.Cowplant] = CommonDeathType.COW_PLANT + if hasattr(DeathType, 'Electrocution'): + mapping[DeathType.Electrocution] = CommonDeathType.ELECTROCUTION + if hasattr(DeathType, 'Anger'): + mapping[DeathType.Anger] = CommonDeathType.ANGER + if hasattr(DeathType, 'Laughter'): + mapping[DeathType.Laughter] = CommonDeathType.LAUGHTER + if hasattr(DeathType, 'ElderExhaustion'): + mapping[DeathType.ElderExhaustion] = CommonDeathType.ELDER_EXHAUSTION + if hasattr(DeathType, 'Embarrassment'): + mapping[DeathType.Embarrassment] = CommonDeathType.EMBARRASSMENT + if hasattr(DeathType, 'Fire'): + mapping[DeathType.Fire] = CommonDeathType.FIRE + if hasattr(DeathType, 'Drown'): + mapping[DeathType.Drown] = CommonDeathType.DROWN + if hasattr(DeathType, 'Steam'): + mapping[DeathType.Steam] = CommonDeathType.STEAM + if hasattr(DeathType, 'Pufferfish'): + mapping[DeathType.Pufferfish] = CommonDeathType.PUFFERFISH + if hasattr(DeathType, 'Sun'): + mapping[DeathType.Sun] = CommonDeathType.SUN + if hasattr(DeathType, 'Poison'): + mapping[DeathType.Poison] = CommonDeathType.POISON + if hasattr(DeathType, 'RodentDisease'): + mapping[DeathType.RodentDisease] = CommonDeathType.RODENT_DISEASE + if hasattr(DeathType, 'Frozen'): + mapping[DeathType.Frozen] = CommonDeathType.FROZEN + if hasattr(DeathType, 'Overheat'): + mapping[DeathType.Overheat] = CommonDeathType.OVERHEAT + if hasattr(DeathType, 'Lightning'): + mapping[DeathType.Lightning] = CommonDeathType.LIGHTNING + if hasattr(DeathType, 'DeathFlowerArrangement'): + mapping[DeathType.DeathFlowerArrangement] = CommonDeathType.DEATH_FLOWER_ARRANGEMENT + if hasattr(DeathType, 'MotherPlant'): + mapping[DeathType.MotherPlant] = CommonDeathType.MOTHER_PLANT + if hasattr(DeathType, 'WitchOverload'): + mapping[DeathType.WitchOverload] = CommonDeathType.WITCH_OVERLOAD + if hasattr(DeathType, 'MurphyBed'): + mapping[DeathType.MurphyBed] = CommonDeathType.MURPHY_BED + if hasattr(DeathType, 'Flies'): + mapping[DeathType.Flies] = CommonDeathType.FLIES + if hasattr(DeathType, 'VendingMachine'): + mapping[DeathType.VendingMachine] = CommonDeathType.VENDING_MACHINE + if hasattr(DeathType, 'ClimbingRoute'): + mapping[DeathType.ClimbingRoute] = CommonDeathType.CLIMBING_ROUTE + if hasattr(DeathType, 'KillerRabbit'): + mapping[DeathType.KillerRabbit] = CommonDeathType.KILLER_RABBIT + if hasattr(DeathType, 'KillerChicken'): + mapping[DeathType.KillerChicken] = CommonDeathType.KILLER_CHICKEN + if hasattr(DeathType, 'Meteorite'): + mapping[DeathType.Meteorite] = CommonDeathType.METEORITE + if hasattr(DeathType, 'StinkBomb'): + mapping[DeathType.StinkBomb] = CommonDeathType.STINK_BOMB + if hasattr(DeathType, 'UrbanMyth'): + mapping[DeathType.UrbanMyth] = CommonDeathType.URBAN_MYTH + return mapping.get(value, CommonDeathType.NONE) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_enum.py b/Scripts/s4ap/sims4communitylib/enums/common_enum.py new file mode 100644 index 0000000..48774f6 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_enum.py @@ -0,0 +1,90 @@ +""" +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 +""" +from typing import Any, List, Union, Iterator + + +class CommonEnumMetaclass(type): + """A metaclass that converts the properties of a class into enum objects and allows iteration of those properties. + + """ + def __new__(mcs, cls: Any, bases: Any, class_dict: Any): + obj_attrs = set(dir(type(cls, (object,), {}))) + enum_cls = super().__new__(mcs, cls, bases, class_dict) + member_names = set(class_dict.keys()) - obj_attrs + enum_dict = dict() + for member_name in member_names: + if callable(getattr(enum_cls, member_name)) or (member_name.startswith('_') and member_name.endswith('_')): + continue + enum_dict[member_name] = getattr(enum_cls, member_name) + enum_cls._members_ = enum_dict + expected_enum_type = mcs.get_enum_type() + for enum_name, enum_value in enum_dict.items(): + if hasattr(enum_value, 'value'): + enum_value = enum_value.value + if expected_enum_type is not None and type(enum_value) != expected_enum_type: + raise ValueError('Incorrect enum value type for class \'{}\', expected type \'{}\', got type: \'{}\'. Enum Name: \'{}\', Enum Value: \'{}\''.format(cls, expected_enum_type, type(enum_value), enum_name, enum_value)) + common_enum = mcs._get_common_enum(enum_name, enum_value, enum_cls.__name__) + setattr(enum_cls, enum_name, common_enum) + + return enum_cls + + def __call__(cls, val: Any): + for (enum_name, enum_value) in cls._members_.items(): + if val == enum_name or val == enum_value: + return getattr(cls, enum_name) + raise KeyError('Value: \'{}\' not found within class \'{}\''.format(val, cls.__name__)) + + @classmethod + def _get_common_enum(mcs, enum_name: str, enum_value: Any, class_name: str): + from sims4communitylib.enums.enumtypes.object_enum import CommonEnumObject + return CommonEnumObject(enum_name, enum_value, class_name) + + @classmethod + def get_enum_type(mcs) -> Union[type, None]: + """Retrieve the enum type of this class. + + :return: The expected enum type. + :rtype: A base type. + """ + return None + + def items(cls) -> List[Any]: + """Retrieve all enum items of the class + + :return: A collection of the enum items of all enums of the class. + :rtype: List[Any] + """ + return [getattr(cls, name) for (name, value) in cls._members_.items()] + + def names(cls) -> List[str]: + """Retrieve all names of all enums of the class. + + :return: A collection of the names of all enums of the class. + :rtype: List[str] + """ + return list(cls._members_.keys()) + + def values(cls) -> List[Any]: + """Retrieve all enum values of all enums of this class + + :return: A collection of the enum values of all enums of the class. + :rtype: List[Any] + """ + return list(cls._members_.values()) + + def __getitem__(cls, key: str): + return getattr(cls._members_, key.upper()) + + def __iter__(cls) -> Iterator[Any]: + return cls._members_.__iter__() + + def __len__(cls) -> int: + return len(cls._members_) + + def __repr__(cls) -> str: + return '{}'.format(cls.__name__) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_fund_types.py b/Scripts/s4ap/sims4communitylib/enums/common_fund_types.py new file mode 100644 index 0000000..e3343ab --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_fund_types.py @@ -0,0 +1,13 @@ +""" +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 +""" + +# This class is obsolete, please use CommonFundsSource from common_funds_sources instead. +from sims4communitylib.enums.common_funds_sources import CommonFundsSource + + +CommonFundType = CommonFundsSource diff --git a/Scripts/s4ap/sims4communitylib/enums/common_funds_sources.py b/Scripts/s4ap/sims4communitylib/enums/common_funds_sources.py new file mode 100644 index 0000000..b752318 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_funds_sources.py @@ -0,0 +1,63 @@ +""" +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 +""" +from typing import Dict + +from sims.funds import FundsSource +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonFundsSource(CommonInt): + """Sources of funds.""" + HOUSEHOLD: 'CommonFundsSource' = ... + RETAIL: 'CommonFundsSource' = ... + BUSINESS: 'CommonFundsSource' = ... + STATISTIC: 'CommonFundsSource' = ... + BUCKS: 'CommonFundsSource' = ... + NO_SOURCE: 'CommonFundsSource' = ... + + @staticmethod + def convert_to_vanilla(value: 'CommonFundsSource') -> FundsSource: + """convert_to_vanilla(value) + + Convert a value into the vanilla FundsSource enum. + + :param value: An instance of the enum. + :type value: CommonFundsSource + :return: The specified value translated to FundsSource or HOUSEHOLD if the value could not be translated. + :rtype: Union[FundsSource, None] + """ + mapping: Dict[CommonFundsSource, FundsSource] = { + CommonFundsSource.HOUSEHOLD: FundsSource.HOUSEHOLD, + CommonFundsSource.RETAIL: FundsSource.RETAIL, + CommonFundsSource.BUSINESS: FundsSource.BUSINESS, + CommonFundsSource.STATISTIC: FundsSource.STATISTIC, + CommonFundsSource.BUCKS: FundsSource.BUCKS, + CommonFundsSource.NO_SOURCE: FundsSource.NO_SOURCE, + } + return mapping.get(value, FundsSource.HOUSEHOLD) + + @staticmethod + def convert_from_vanilla(value: FundsSource) -> 'CommonFundsSource': + """convert_from_vanilla(value) + + Convert a vanilla FundsSource to value. + + :param value: An instance of the enum. + :type value: FundsSource + :return: The specified value translated to CommonFundsSource or HOUSEHOLD if the value could not be translated. + :rtype: CommonFundsSource + """ + mapping: Dict[FundsSource, CommonFundsSource] = { + FundsSource.HOUSEHOLD: CommonFundsSource.HOUSEHOLD, + FundsSource.RETAIL: CommonFundsSource.RETAIL, + FundsSource.BUSINESS: CommonFundsSource.BUSINESS, + FundsSource.STATISTIC: CommonFundsSource.STATISTIC, + FundsSource.BUCKS: CommonFundsSource.BUCKS, + FundsSource.NO_SOURCE: CommonFundsSource.NO_SOURCE, + } + return mapping.get(value, CommonFundsSource.HOUSEHOLD) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_game_tag_category.py b/Scripts/s4ap/sims4communitylib/enums/common_game_tag_category.py new file mode 100644 index 0000000..00d0fab --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_game_tag_category.py @@ -0,0 +1,431 @@ +""" +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 +""" +from typing import Union, Tuple, Iterator + +from sims4communitylib.enums.enumtypes.common_int import CommonInt +from tag import TagCategory + + +class CommonGameTagCategory(CommonInt): + """Variants of Game Tag Categories.""" + INVALID: 'CommonGameTagCategory' = ... + ACCESSORIES: 'CommonGameTagCategory' = ... + ACNE_LEVEL: 'CommonGameTagCategory' = ... + AGE_APPROPRIATE: 'CommonGameTagCategory' = ... + APPEARANCE_MODIFIER: 'CommonGameTagCategory' = ... + ARCHETYPE: 'CommonGameTagCategory' = ... + BOTTOM: 'CommonGameTagCategory' = ... + BOTTOM_ACCESSORY: 'CommonGameTagCategory' = ... + BREED: 'CommonGameTagCategory' = ... + BREED_GROUP: 'CommonGameTagCategory' = ... + BUILD: 'CommonGameTagCategory' = ... + BUY_CAT_EE: 'CommonGameTagCategory' = ... + BUY_CAT_LD: 'CommonGameTagCategory' = ... + BUY_CAT_MAG: 'CommonGameTagCategory' = ... + BUY_CAT_PA: 'CommonGameTagCategory' = ... + BUY_CAT_SS: 'CommonGameTagCategory' = ... + BUY_CAT_VO: 'CommonGameTagCategory' = ... + COAT_PATTERN: 'CommonGameTagCategory' = ... + COLOR: 'CommonGameTagCategory' = ... + COLOR_PALETTE: 'CommonGameTagCategory' = ... + DOG_SIZE: 'CommonGameTagCategory' = ... + EARS: 'CommonGameTagCategory' = ... + ENSEMBLE: 'CommonGameTagCategory' = ... + EYE_BROW_SHAPE: 'CommonGameTagCategory' = ... + EYE_BROW_THICKNESS: 'CommonGameTagCategory' = ... + EYE_COLOR: 'CommonGameTagCategory' = ... + FABRIC: 'CommonGameTagCategory' = ... + FACE_DETAIL: 'CommonGameTagCategory' = ... + FACE_MAKE_UP: 'CommonGameTagCategory' = ... + FACIAL_HAIR: 'CommonGameTagCategory' = ... + FASHION: 'CommonGameTagCategory' = ... + FLOOR_PATTERN: 'CommonGameTagCategory' = ... + FULL_BODY: 'CommonGameTagCategory' = ... + FUR: 'CommonGameTagCategory' = ... + FUR_LENGTH: 'CommonGameTagCategory' = ... + GENDER_APPROPRIATE: 'CommonGameTagCategory' = ... + GROWTH_LEVEL: 'CommonGameTagCategory' = ... + GROWTH_TYPE: 'CommonGameTagCategory' = ... + HAIR: 'CommonGameTagCategory' = ... + HAIR_COLOR: 'CommonGameTagCategory' = ... + HAIR_LENGTH: 'CommonGameTagCategory' = ... + HAIR_TEXTURE: 'CommonGameTagCategory' = ... + HAT: 'CommonGameTagCategory' = ... + MOOD: 'CommonGameTagCategory' = ... + NOSE_COLOR: 'CommonGameTagCategory' = ... + NUDE_PART: 'CommonGameTagCategory' = ... + OCCULT: 'CommonGameTagCategory' = ... + OUTFIT_CATEGORY: 'CommonGameTagCategory' = ... + PATTERN: 'CommonGameTagCategory' = ... + PERSONA: 'CommonGameTagCategory' = ... + REWARD: 'CommonGameTagCategory' = ... + SHOES: 'CommonGameTagCategory' = ... + SKILL: 'CommonGameTagCategory' = ... + SKIN_HUE: 'CommonGameTagCategory' = ... + SKIN_TONE_BLEND: 'CommonGameTagCategory' = ... + SKIN_TONE_TYPE: 'CommonGameTagCategory' = ... + SKIN_VALUE: 'CommonGameTagCategory' = ... + SPECIAL: 'CommonGameTagCategory' = ... + SPECIAL_CONTENT: 'CommonGameTagCategory' = ... + STYLE: 'CommonGameTagCategory' = ... + TAIL: 'CommonGameTagCategory' = ... + TERRAIN_PAINT: 'CommonGameTagCategory' = ... + TOP: 'CommonGameTagCategory' = ... + TRAIT_GROUP: 'CommonGameTagCategory' = ... + UNIFORM: 'CommonGameTagCategory' = ... + VAMPIRE_ARCHETYPE: 'CommonGameTagCategory' = ... + WALL_PATTERN: 'CommonGameTagCategory' = ... + WORLD_LOG: 'CommonGameTagCategory' = ... + + @classmethod + def get_all(cls, exclude_values: Iterator['CommonGameTagCategory'] = None) -> Tuple['CommonGameTagCategory']: + """get_all(exclude_values=None) + + Get a collection of all values. + + :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonTagCategory], optional + :return: A collection of all values. + :rtype: Tuple[CommonGameTagCategory] + """ + if exclude_values is None: + exclude_values = (cls.INVALID,) + # noinspection PyTypeChecker + value_list: Tuple[CommonGameTagCategory, ...] = tuple([value for value in cls.values if value not in exclude_values]) + return value_list + + @classmethod + def get_all_names(cls, exclude_values: Iterator['CommonGameTagCategory'] = None) -> Tuple[str]: + """get_all_names(exclude_values=None) + + Retrieve a collection of the names of all values. + + :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonTagCategory], optional + :return: A collection of the names of all values. + :rtype: Tuple[str] + """ + name_list: Tuple[str] = tuple([value.name for value in cls.get_all(exclude_values=exclude_values)]) + return name_list + + @classmethod + def get_comma_separated_names_string(cls, exclude_values: Iterator['CommonGameTagCategory'] = None) -> str: + """get_comma_separated_names_string(exclude_values=None) + + Create a string containing all names of all values, separated by a comma. + + :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonTagCategory], optional + :return: A string containing all names of all values, separated by a comma. + :rtype: str + """ + return ', '.join(cls.get_all_names(exclude_values=exclude_values)) + + @staticmethod + def convert_to_vanilla(value: 'CommonGameTagCategory') -> Union[TagCategory, None]: + """convert_to_vanilla(value) + + Convert a value into the vanilla TagCategory enum. + + :param value: An instance of CommonTagCategory + :type value: CommonGameTagCategory + :return: The specified value translated to TagCategory or INVALID if the value could not be translated. + :rtype: Union[TagCategory, None] + """ + if value is None or value == CommonGameTagCategory.INVALID: + return TagCategory.INVALID + if isinstance(value, TagCategory): + return value + mapping = dict() + if hasattr(TagCategory, 'Mood'): + mapping[CommonGameTagCategory.MOOD] = TagCategory.Mood + if hasattr(TagCategory, 'Color'): + mapping[CommonGameTagCategory.COLOR] = TagCategory.Color + if hasattr(TagCategory, 'Style'): + mapping[CommonGameTagCategory.STYLE] = TagCategory.Style + if hasattr(TagCategory, 'AgeAppropriate'): + mapping[CommonGameTagCategory.AGE_APPROPRIATE] = TagCategory.AgeAppropriate + if hasattr(TagCategory, 'Archetype'): + mapping[CommonGameTagCategory.ARCHETYPE] = TagCategory.Archetype + if hasattr(TagCategory, 'OutfitCategory'): + mapping[CommonGameTagCategory.OUTFIT_CATEGORY] = TagCategory.OutfitCategory + if hasattr(TagCategory, 'Skill'): + mapping[CommonGameTagCategory.SKILL] = TagCategory.Skill + if hasattr(TagCategory, 'EyeColor'): + mapping[CommonGameTagCategory.EYE_COLOR] = TagCategory.EyeColor + if hasattr(TagCategory, 'Persona'): + mapping[CommonGameTagCategory.PERSONA] = TagCategory.Persona + if hasattr(TagCategory, 'Special'): + mapping[CommonGameTagCategory.SPECIAL] = TagCategory.Special + if hasattr(TagCategory, 'HairColor'): + mapping[CommonGameTagCategory.HAIR_COLOR] = TagCategory.HairColor + if hasattr(TagCategory, 'ColorPalette'): + mapping[CommonGameTagCategory.COLOR_PALETTE] = TagCategory.ColorPalette + if hasattr(TagCategory, 'Hair'): + mapping[CommonGameTagCategory.HAIR] = TagCategory.Hair + if hasattr(TagCategory, 'FacialHair'): + mapping[CommonGameTagCategory.FACIAL_HAIR] = TagCategory.FacialHair + if hasattr(TagCategory, 'Hat'): + mapping[CommonGameTagCategory.HAT] = TagCategory.Hat + if hasattr(TagCategory, 'FaceMakeup'): + mapping[CommonGameTagCategory.FACE_MAKE_UP] = TagCategory.FaceMakeup + if hasattr(TagCategory, 'Top'): + mapping[CommonGameTagCategory.TOP] = TagCategory.Top + if hasattr(TagCategory, 'Bottom'): + mapping[CommonGameTagCategory.BOTTOM] = TagCategory.Bottom + if hasattr(TagCategory, 'FullBody'): + mapping[CommonGameTagCategory.FULL_BODY] = TagCategory.FullBody + if hasattr(TagCategory, 'Shoes'): + mapping[CommonGameTagCategory.SHOES] = TagCategory.Shoes + if hasattr(TagCategory, 'BottomAccessory'): + mapping[CommonGameTagCategory.BOTTOM_ACCESSORY] = TagCategory.BottomAccessory + if hasattr(TagCategory, 'BuyCatEE'): + mapping[CommonGameTagCategory.BUY_CAT_EE] = TagCategory.BuyCatEE + if hasattr(TagCategory, 'BuyCatPA'): + mapping[CommonGameTagCategory.BUY_CAT_PA] = TagCategory.BuyCatPA + if hasattr(TagCategory, 'BuyCatLD'): + mapping[CommonGameTagCategory.BUY_CAT_LD] = TagCategory.BuyCatLD + if hasattr(TagCategory, 'BuyCatSS'): + mapping[CommonGameTagCategory.BUY_CAT_SS] = TagCategory.BuyCatSS + if hasattr(TagCategory, 'BuyCatVO'): + mapping[CommonGameTagCategory.BUY_CAT_VO] = TagCategory.BuyCatVO + if hasattr(TagCategory, 'Uniform'): + mapping[CommonGameTagCategory.UNIFORM] = TagCategory.Uniform + if hasattr(TagCategory, 'Accessories'): + mapping[CommonGameTagCategory.ACCESSORIES] = TagCategory.Accessories + if hasattr(TagCategory, 'BuyCatMAG'): + mapping[CommonGameTagCategory.BUY_CAT_MAG] = TagCategory.BuyCatMAG + if hasattr(TagCategory, 'FloorPattern'): + mapping[CommonGameTagCategory.FLOOR_PATTERN] = TagCategory.FloorPattern + if hasattr(TagCategory, 'WallPattern'): + mapping[CommonGameTagCategory.WALL_PATTERN] = TagCategory.WallPattern + if hasattr(TagCategory, 'Fabric'): + mapping[CommonGameTagCategory.FABRIC] = TagCategory.Fabric + if hasattr(TagCategory, 'Build'): + mapping[CommonGameTagCategory.BUILD] = TagCategory.Build + if hasattr(TagCategory, 'Pattern'): + mapping[CommonGameTagCategory.PATTERN] = TagCategory.Pattern + if hasattr(TagCategory, 'HairLength'): + mapping[CommonGameTagCategory.HAIR_LENGTH] = TagCategory.HairLength + if hasattr(TagCategory, 'HairTexture'): + mapping[CommonGameTagCategory.HAIR_TEXTURE] = TagCategory.HairTexture + if hasattr(TagCategory, 'TraitGroup'): + mapping[CommonGameTagCategory.TRAIT_GROUP] = TagCategory.TraitGroup + if hasattr(TagCategory, 'SkinHue'): + mapping[CommonGameTagCategory.SKIN_HUE] = TagCategory.SkinHue + if hasattr(TagCategory, 'Reward'): + mapping[CommonGameTagCategory.REWARD] = TagCategory.Reward + if hasattr(TagCategory, 'TerrainPaint'): + mapping[CommonGameTagCategory.TERRAIN_PAINT] = TagCategory.TerrainPaint + if hasattr(TagCategory, 'EyebrowThickness'): + mapping[CommonGameTagCategory.EYE_BROW_THICKNESS] = TagCategory.EyebrowThickness + if hasattr(TagCategory, 'EyebrowShape'): + mapping[CommonGameTagCategory.EYE_BROW_SHAPE] = TagCategory.EyebrowShape + if hasattr(TagCategory, 'Ensemble'): + mapping[CommonGameTagCategory.ENSEMBLE] = TagCategory.Ensemble + if hasattr(TagCategory, 'SkintoneType'): + mapping[CommonGameTagCategory.SKIN_TONE_TYPE] = TagCategory.SkintoneType + if hasattr(TagCategory, 'Occult'): + mapping[CommonGameTagCategory.OCCULT] = TagCategory.Occult + if hasattr(TagCategory, 'SkintoneBlend'): + mapping[CommonGameTagCategory.SKIN_TONE_BLEND] = TagCategory.SkintoneBlend + if hasattr(TagCategory, 'GenderAppropriate'): + mapping[CommonGameTagCategory.GENDER_APPROPRIATE] = TagCategory.GenderAppropriate + if hasattr(TagCategory, 'NudePart'): + mapping[CommonGameTagCategory.NUDE_PART] = TagCategory.NudePart + if hasattr(TagCategory, 'FaceDetail'): + mapping[CommonGameTagCategory.FACE_DETAIL] = TagCategory.FaceDetail + if hasattr(TagCategory, 'VampireArchetype'): + mapping[CommonGameTagCategory.VAMPIRE_ARCHETYPE] = TagCategory.VampireArchetype + if hasattr(TagCategory, 'Ears'): + mapping[CommonGameTagCategory.EARS] = TagCategory.Ears + if hasattr(TagCategory, 'Breed'): + mapping[CommonGameTagCategory.BREED] = TagCategory.Breed + if hasattr(TagCategory, 'Tail'): + mapping[CommonGameTagCategory.TAIL] = TagCategory.Tail + if hasattr(TagCategory, 'Fur'): + mapping[CommonGameTagCategory.FUR] = TagCategory.Fur + if hasattr(TagCategory, 'DogSize'): + mapping[CommonGameTagCategory.DOG_SIZE] = TagCategory.DogSize + if hasattr(TagCategory, 'BreedGroup'): + mapping[CommonGameTagCategory.BREED_GROUP] = TagCategory.BreedGroup + if hasattr(TagCategory, 'NoseColor'): + mapping[CommonGameTagCategory.NOSE_COLOR] = TagCategory.NoseColor + if hasattr(TagCategory, 'WorldLog'): + mapping[CommonGameTagCategory.WORLD_LOG] = TagCategory.WorldLog + if hasattr(TagCategory, 'CoatPattern'): + mapping[CommonGameTagCategory.COAT_PATTERN] = TagCategory.CoatPattern + if hasattr(TagCategory, 'FurLength'): + mapping[CommonGameTagCategory.FUR_LENGTH] = TagCategory.FurLength + if hasattr(TagCategory, 'AppearanceModifier'): + mapping[CommonGameTagCategory.APPEARANCE_MODIFIER] = TagCategory.AppearanceModifier + if hasattr(TagCategory, 'SpecialContent'): + mapping[CommonGameTagCategory.SPECIAL_CONTENT] = TagCategory.SpecialContent + if hasattr(TagCategory, 'Fashion'): + mapping[CommonGameTagCategory.FASHION] = TagCategory.Fashion + if hasattr(TagCategory, 'GrowthLevel'): + mapping[CommonGameTagCategory.GROWTH_LEVEL] = TagCategory.GrowthLevel + if hasattr(TagCategory, 'GrowthType'): + mapping[CommonGameTagCategory.GROWTH_TYPE] = TagCategory.GrowthType + if hasattr(TagCategory, 'SkinValue'): + mapping[CommonGameTagCategory.SKIN_VALUE] = TagCategory.SkinValue + if hasattr(TagCategory, 'AcneLevel'): + mapping[CommonGameTagCategory.ACNE_LEVEL] = TagCategory.AcneLevel + return mapping.get(value, TagCategory.INVALID) + + @staticmethod + def convert_from_vanilla(value: Union[int, TagCategory]) -> 'CommonGameTagCategory': + """convert_from_vanilla(value) + + Convert a value into a CommonTagCategory enum. + + :param value: An instance of TagCategory + :type value: TagCategory + :return: The specified value translated to CommonTagCategory or INVALID if the value could not be translated. + :rtype: TagCategory + """ + if value is None or value == TagCategory.INVALID: + return CommonGameTagCategory.INVALID + if isinstance(value, CommonGameTagCategory): + return value + mapping = dict() + if hasattr(TagCategory, 'Mood'): + mapping[TagCategory.Mood] = CommonGameTagCategory.MOOD + if hasattr(TagCategory, 'Color'): + mapping[TagCategory.Color] = CommonGameTagCategory.COLOR + if hasattr(TagCategory, 'Style'): + mapping[TagCategory.Style] = CommonGameTagCategory.STYLE + if hasattr(TagCategory, 'AgeAppropriate'): + mapping[TagCategory.AgeAppropriate] = CommonGameTagCategory.AGE_APPROPRIATE + if hasattr(TagCategory, 'Archetype'): + mapping[TagCategory.Archetype] = CommonGameTagCategory.ARCHETYPE + if hasattr(TagCategory, 'OutfitCategory'): + mapping[TagCategory.OutfitCategory] = CommonGameTagCategory.OUTFIT_CATEGORY + if hasattr(TagCategory, 'Skill'): + mapping[TagCategory.Skill] = CommonGameTagCategory.SKILL + if hasattr(TagCategory, 'EyeColor'): + mapping[TagCategory.EyeColor] = CommonGameTagCategory.EYE_COLOR + if hasattr(TagCategory, 'Persona'): + mapping[TagCategory.Persona] = CommonGameTagCategory.PERSONA + if hasattr(TagCategory, 'Special'): + mapping[TagCategory.Special] = CommonGameTagCategory.SPECIAL + if hasattr(TagCategory, 'HairColor'): + mapping[TagCategory.HairColor] = CommonGameTagCategory.HAIR_COLOR + if hasattr(TagCategory, 'ColorPalette'): + mapping[TagCategory.ColorPalette] = CommonGameTagCategory.COLOR_PALETTE + if hasattr(TagCategory, 'Hair'): + mapping[TagCategory.Hair] = CommonGameTagCategory.HAIR + if hasattr(TagCategory, 'FacialHair'): + mapping[TagCategory.FacialHair] = CommonGameTagCategory.FACIAL_HAIR + if hasattr(TagCategory, 'Hat'): + mapping[TagCategory.Hat] = CommonGameTagCategory.HAT + if hasattr(TagCategory, 'FaceMakeup'): + mapping[TagCategory.FaceMakeup] = CommonGameTagCategory.FACE_MAKE_UP + if hasattr(TagCategory, 'Top'): + mapping[TagCategory.Top] = CommonGameTagCategory.TOP + if hasattr(TagCategory, 'Bottom'): + mapping[TagCategory.Bottom] = CommonGameTagCategory.BOTTOM + if hasattr(TagCategory, 'FullBody'): + mapping[TagCategory.FullBody] = CommonGameTagCategory.FULL_BODY + if hasattr(TagCategory, 'Shoes'): + mapping[TagCategory.Shoes] = CommonGameTagCategory.SHOES + if hasattr(TagCategory, 'BottomAccessory'): + mapping[TagCategory.BottomAccessory] = CommonGameTagCategory.BOTTOM_ACCESSORY + if hasattr(TagCategory, 'BuyCatEE'): + mapping[TagCategory.BuyCatEE] = CommonGameTagCategory.BUY_CAT_EE + if hasattr(TagCategory, 'BuyCatPA'): + mapping[TagCategory.BuyCatPA] = CommonGameTagCategory.BUY_CAT_PA + if hasattr(TagCategory, 'BuyCatLD'): + mapping[TagCategory.BuyCatLD] = CommonGameTagCategory.BUY_CAT_LD + if hasattr(TagCategory, 'BuyCatSS'): + mapping[TagCategory.BuyCatSS] = CommonGameTagCategory.BUY_CAT_SS + if hasattr(TagCategory, 'BuyCatVO'): + mapping[TagCategory.BuyCatVO] = CommonGameTagCategory.BUY_CAT_VO + if hasattr(TagCategory, 'Uniform'): + mapping[TagCategory.Uniform] = CommonGameTagCategory.UNIFORM + if hasattr(TagCategory, 'Accessories'): + mapping[TagCategory.Accessories] = CommonGameTagCategory.ACCESSORIES + if hasattr(TagCategory, 'BuyCatMAG'): + mapping[TagCategory.BuyCatMAG] = CommonGameTagCategory.BUY_CAT_MAG + if hasattr(TagCategory, 'FloorPattern'): + mapping[TagCategory.FloorPattern] = CommonGameTagCategory.FLOOR_PATTERN + if hasattr(TagCategory, 'WallPattern'): + mapping[TagCategory.WallPattern] = CommonGameTagCategory.WALL_PATTERN + if hasattr(TagCategory, 'Fabric'): + mapping[TagCategory.Fabric] = CommonGameTagCategory.FABRIC + if hasattr(TagCategory, 'Build'): + mapping[TagCategory.Build] = CommonGameTagCategory.BUILD + if hasattr(TagCategory, 'Pattern'): + mapping[TagCategory.Pattern] = CommonGameTagCategory.PATTERN + if hasattr(TagCategory, 'HairLength'): + mapping[TagCategory.HairLength] = CommonGameTagCategory.HAIR_LENGTH + if hasattr(TagCategory, 'HairTexture'): + mapping[TagCategory.HairTexture] = CommonGameTagCategory.HAIR_TEXTURE + if hasattr(TagCategory, 'TraitGroup'): + mapping[TagCategory.TraitGroup] = CommonGameTagCategory.TRAIT_GROUP + if hasattr(TagCategory, 'SkinHue'): + mapping[TagCategory.SkinHue] = CommonGameTagCategory.SKIN_HUE + if hasattr(TagCategory, 'Reward'): + mapping[TagCategory.Reward] = CommonGameTagCategory.REWARD + if hasattr(TagCategory, 'TerrainPaint'): + mapping[TagCategory.TerrainPaint] = CommonGameTagCategory.TERRAIN_PAINT + if hasattr(TagCategory, 'EyebrowThickness'): + mapping[TagCategory.EyebrowThickness] = CommonGameTagCategory.EYE_BROW_THICKNESS + if hasattr(TagCategory, 'EyebrowShape'): + mapping[TagCategory.EyebrowShape] = CommonGameTagCategory.EYE_BROW_SHAPE + if hasattr(TagCategory, 'Ensemble'): + mapping[TagCategory.Ensemble] = CommonGameTagCategory.ENSEMBLE + if hasattr(TagCategory, 'SkintoneType'): + mapping[TagCategory.SkintoneType] = CommonGameTagCategory.SKIN_TONE_TYPE + if hasattr(TagCategory, 'Occult'): + mapping[TagCategory.Occult] = CommonGameTagCategory.OCCULT + if hasattr(TagCategory, 'SkintoneBlend'): + mapping[TagCategory.SkintoneBlend] = CommonGameTagCategory.SKIN_TONE_BLEND + if hasattr(TagCategory, 'GenderAppropriate'): + mapping[TagCategory.GenderAppropriate] = CommonGameTagCategory.GENDER_APPROPRIATE + if hasattr(TagCategory, 'NudePart'): + mapping[TagCategory.NudePart] = CommonGameTagCategory.NUDE_PART + if hasattr(TagCategory, 'FaceDetail'): + mapping[TagCategory.FaceDetail] = CommonGameTagCategory.FACE_DETAIL + if hasattr(TagCategory, 'VampireArchetype'): + mapping[TagCategory.VampireArchetype] = CommonGameTagCategory.VAMPIRE_ARCHETYPE + if hasattr(TagCategory, 'Ears'): + mapping[TagCategory.Ears] = CommonGameTagCategory.EARS + if hasattr(TagCategory, 'Breed'): + mapping[TagCategory.Breed] = CommonGameTagCategory.BREED + if hasattr(TagCategory, 'Tail'): + mapping[TagCategory.Tail] = CommonGameTagCategory.TAIL + if hasattr(TagCategory, 'Fur'): + mapping[TagCategory.Fur] = CommonGameTagCategory.FUR + if hasattr(TagCategory, 'DogSize'): + mapping[TagCategory.DogSize] = CommonGameTagCategory.DOG_SIZE + if hasattr(TagCategory, 'BreedGroup'): + mapping[TagCategory.BreedGroup] = CommonGameTagCategory.BREED_GROUP + if hasattr(TagCategory, 'NoseColor'): + mapping[TagCategory.NoseColor] = CommonGameTagCategory.NOSE_COLOR + if hasattr(TagCategory, 'WorldLog'): + mapping[TagCategory.WorldLog] = CommonGameTagCategory.WORLD_LOG + if hasattr(TagCategory, 'CoatPattern'): + mapping[TagCategory.CoatPattern] = CommonGameTagCategory.COAT_PATTERN + if hasattr(TagCategory, 'FurLength'): + mapping[TagCategory.FurLength] = CommonGameTagCategory.FUR_LENGTH + if hasattr(TagCategory, 'AppearanceModifier'): + mapping[TagCategory.AppearanceModifier] = CommonGameTagCategory.APPEARANCE_MODIFIER + if hasattr(TagCategory, 'SpecialContent'): + mapping[TagCategory.SpecialContent] = CommonGameTagCategory.SPECIAL_CONTENT + if hasattr(TagCategory, 'Fashion'): + mapping[TagCategory.Fashion] = CommonGameTagCategory.FASHION + if hasattr(TagCategory, 'GrowthLevel'): + mapping[TagCategory.GrowthLevel] = CommonGameTagCategory.GROWTH_LEVEL + if hasattr(TagCategory, 'GrowthType'): + mapping[TagCategory.GrowthType] = CommonGameTagCategory.GROWTH_TYPE + if hasattr(TagCategory, 'SkinValue'): + mapping[TagCategory.SkinValue] = CommonGameTagCategory.SKIN_VALUE + if hasattr(TagCategory, 'AcneLevel'): + mapping[TagCategory.AcneLevel] = CommonGameTagCategory.ACNE_LEVEL + return mapping.get(value, CommonGameTagCategory.INVALID) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_gender.py b/Scripts/s4ap/sims4communitylib/enums/common_gender.py new file mode 100644 index 0000000..21ffb27 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_gender.py @@ -0,0 +1,148 @@ +""" +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 +""" +from typing import Union, Tuple, Iterator + +from sims.sim_info import SimInfo +from sims.sim_info_types import Gender +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonGender(CommonInt): + """Custom Gender enum containing all genders. + + """ + INVALID: 'CommonGender' = 0 + MALE: 'CommonGender' = 4096 + FEMALE: 'CommonGender' = 8192 + + @classmethod + def get_all(cls, exclude_values: Iterator['CommonGender'] = None) -> Tuple['CommonGender']: + """get_all(exclude_values=None) + + Get a collection of all values. + + :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonGender], optional + :return: A collection of all values. + :rtype: Tuple[CommonGender] + """ + if exclude_values is None: + exclude_values = (cls.INVALID,) + # noinspection PyTypeChecker + value_list: Tuple[CommonGender, ...] = tuple([value for value in cls.values if value not in exclude_values]) + return value_list + + @classmethod + def get_all_names(cls, exclude_values: Iterator['CommonGender'] = None) -> Tuple[str]: + """get_all_names(exclude_values=None) + + Retrieve a collection of the names of all values. + + :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonGender], optional + :return: A collection of the names of all values. + :rtype: Tuple[str] + """ + name_list: Tuple[str] = tuple([value.name for value in cls.get_all(exclude_values=exclude_values)]) + return name_list + + @classmethod + def get_comma_separated_names_string(cls, exclude_values: Iterator['CommonGender'] = None) -> str: + """get_comma_separated_names_string(exclude_values=None) + + Create a string containing all names of all values, separated by a comma. + + :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonGender], optional + :return: A string containing all names of all values, separated by a comma. + :rtype: str + """ + return ', '.join(cls.get_all_names(exclude_values=exclude_values)) + + @staticmethod + def get_gender(sim_info: SimInfo) -> 'CommonGender': + """get_gender(sim_info) + + Retrieve the CommonGender of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The CommonGender that represents what gender a Sim is or CommonGender.INVALID if their gender cannot be determined. + :rtype: CommonGender + """ + from sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils + if CommonGenderUtils.is_male(sim_info): + return CommonGender.MALE + elif CommonGenderUtils.is_female(sim_info): + return CommonGender.FEMALE + return CommonGender.INVALID + + @staticmethod + def convert_to_vanilla(value: 'CommonGender') -> Union[Gender, None]: + """convert_to_vanilla(value) + + Convert a value into the vanilla Gender enum. + + :param value: An instance of CommonGender + :type value: CommonGender + :return: The specified value translated to Gender or None if the value could not be translated. + :rtype: Union[Gender, None] + """ + if value is None or value == CommonGender.INVALID: + return None + if isinstance(value, Gender): + return value + mapping = { + CommonGender.MALE: Gender.MALE, + CommonGender.FEMALE: Gender.FEMALE + } + return mapping.get(value, None) + + @staticmethod + def convert_from_vanilla(value: Union[int, Gender]) -> 'CommonGender': + """convert_from_vanilla(value) + + Convert a value into a CommonGender enum. + + :param value: An instance of Gender + :type value: Gender + :return: The specified value translated to CommonGender or INVALID if the value could not be translated. + :rtype: CommonGender + """ + if value is None: + return CommonGender.INVALID + if isinstance(value, CommonGender): + return value + mapping = { + int(Gender.MALE): CommonGender.MALE, + int(Gender.FEMALE): CommonGender.FEMALE + } + value = int(value) + if value not in mapping: + return CommonGender.INVALID + return mapping[value] + + @staticmethod + def convert_to_localized_string_id(value: 'CommonGender') -> Union[int, str]: + """convert_to_localized_string_id(value) + + Convert a CommonGender into a Localized String identifier. + + :param value: An instance of a CommonGender + :type value: CommonGender + :return: The specified CommonGender translated to a localized string identifier. If no localized string id is found, the name property of the value will be used instead. + :rtype: Union[int, str] + """ + from sims4communitylib.enums.strings_enum import CommonStringId + mapping = { + CommonGender.MALE: CommonStringId.MALE, + CommonGender.FEMALE: CommonStringId.FEMALE + } + if isinstance(value, int) and not isinstance(value, CommonGender): + value = CommonGender.convert_from_vanilla(value) + return mapping.get(value, value.name if hasattr(value, 'name') else str(value)) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_gender_preference_type.py b/Scripts/s4ap/sims4communitylib/enums/common_gender_preference_type.py new file mode 100644 index 0000000..d2426ef --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_gender_preference_type.py @@ -0,0 +1,67 @@ +""" +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 +""" +from typing import Dict, Union + +from sims.global_gender_preference_tuning import GenderPreferenceType +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonGenderPreferenceType(CommonInt): + """Custom Gender Preference Type enum. + + """ + INVALID: 'CommonGenderPreferenceType' = 0 + ROMANTIC: 'CommonGenderPreferenceType' = 1 + WOOHOO: 'CommonGenderPreferenceType' = 2 + + @staticmethod + def convert_to_vanilla(value: 'CommonGenderPreferenceType') -> Union[GenderPreferenceType, None]: + """convert_to_vanilla(value) + + Convert a CommonGenderPreferenceType into the vanilla GenderPreferenceType enum. + + :param value: An instance of Common Gender Preference Type + :type value: CommonGenderPreferenceType + :return: The specified CommonGenderPreferenceType translated to GenderPreferenceType or None if the value could not be translated. + :rtype: Union[GenderPreferenceType, None] + """ + if value is None or value == CommonGenderPreferenceType.INVALID: + return GenderPreferenceType.INVALID + if isinstance(value, GenderPreferenceType): + return value + conversion_mapping: Dict[CommonGenderPreferenceType, GenderPreferenceType] = { + CommonGenderPreferenceType.INVALID: GenderPreferenceType.INVALID, + CommonGenderPreferenceType.ROMANTIC: GenderPreferenceType.ROMANTIC, + CommonGenderPreferenceType.WOOHOO: GenderPreferenceType.WOOHOO, + } + return conversion_mapping.get(value, None) + + @staticmethod + def convert_from_vanilla(value: Union[int, GenderPreferenceType]) -> 'CommonGenderPreferenceType': + """convert_from_vanilla(value) + + Convert a vanilla GenderPreferenceType to a CommonGenderPreferenceType. + + :param value: An instance of Gender Preference Type + :type value: GenderPreferenceType + :return: The specified GenderPreferenceType translated to CommonGenderPreferenceType or INVALID if the value could not be translated. + :rtype: CommonGenderPreferenceType + """ + if value is None or value == GenderPreferenceType.INVALID: + return CommonGenderPreferenceType.INVALID + if isinstance(value, CommonGenderPreferenceType): + return value + conversion_mapping: Dict[int, CommonGenderPreferenceType] = { + int(GenderPreferenceType.INVALID): CommonGenderPreferenceType.INVALID, + int(GenderPreferenceType.ROMANTIC): CommonGenderPreferenceType.ROMANTIC, + int(GenderPreferenceType.WOOHOO): CommonGenderPreferenceType.WOOHOO + } + value = int(value) + if value not in conversion_mapping: + return CommonGenderPreferenceType.INVALID + return conversion_mapping[value] diff --git a/Scripts/s4ap/sims4communitylib/enums/common_ground_cover_type.py b/Scripts/s4ap/sims4communitylib/enums/common_ground_cover_type.py new file mode 100644 index 0000000..47e8b26 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_ground_cover_type.py @@ -0,0 +1,78 @@ +""" +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 +""" +from typing import Tuple, Union, Iterator + +from sims4communitylib.enums.enumtypes.common_int import CommonInt + +# noinspection PyBroadException +try: + from weather.weather_enums import GroundCoverType +except: + class GroundCoverType(CommonInt): + """Mock class.""" + RAIN_ACCUMULATION = 1002 + SNOW_ACCUMULATION = 1003 + + +class CommonGroundCoverType(CommonInt): + """Identifiers for ground cover types.""" + RAIN_ACCUMULATION: 'CommonGroundCoverType' = ... + SNOW_ACCUMULATION: 'CommonGroundCoverType' = ... + + @classmethod + def get_all(cls, exclude_values: Iterator['CommonGroundCoverType'] = ()) -> Tuple['CommonGroundCoverType']: + """get_all(exclude_values=()) + + Get a collection of all values. + + :param exclude_values: These values will be excluded. Default is an empty collection. + :type exclude_values: Iterator[CommonGroundCoverType], optional + :return: A collection of all values. + :rtype: Tuple[CommonGroundCoverType] + """ + # noinspection PyTypeChecker + value_list: Tuple[CommonGroundCoverType, ...] = tuple([value for value in cls.values if value not in exclude_values]) + return value_list + + @staticmethod + def convert_to_vanilla(value: 'CommonGroundCoverType') -> Union[GroundCoverType, None]: + """convert_to_vanilla(value) + + Convert a CommonGroundCoverType into the vanilla GroundCoverType enum. + + :param value: An instance of CommonGroundCoverType + :type value: CommonGroundCoverType + :return: The specified CommonGroundCoverType translated to GroundCoverType, or None if the value could not be translated. + :rtype: Union[GroundCoverType, None] + """ + if isinstance(value, GroundCoverType): + return value + mapping = { + CommonGroundCoverType.RAIN_ACCUMULATION: GroundCoverType.RAIN_ACCUMULATION, + CommonGroundCoverType.SNOW_ACCUMULATION: GroundCoverType.SNOW_ACCUMULATION + } + return mapping.get(value, None) + + @staticmethod + def convert_from_vanilla(value: GroundCoverType) -> Union['CommonGroundCoverType', None]: + """convert_from_vanilla(value) + + Convert a vanilla GroundCoverType into a CommonGroundCoverType enum. + + :param value: An instance of GroundCoverType + :type value: GroundCoverType + :return: The specified GroundCoverType translated to CommonGroundCoverType, or None if the value could not be translated. + :rtype: Union[CommonGroundCoverType, None] + """ + if isinstance(value, CommonGroundCoverType): + return value + mapping = { + GroundCoverType.RAIN_ACCUMULATION: CommonGroundCoverType.RAIN_ACCUMULATION, + GroundCoverType.SNOW_ACCUMULATION: CommonGroundCoverType.SNOW_ACCUMULATION + } + return mapping.get(value, None) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_key.py b/Scripts/s4ap/sims4communitylib/enums/common_key.py new file mode 100644 index 0000000..4969b46 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_key.py @@ -0,0 +1,230 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonKey(CommonInt): + """Keys and their Key Codes for various keys on the keyboard. Currently recognizes Windows and Mac keys.""" + INVALID: 'CommonKey' = -1 + # Windows Keys + BACKSPACE: 'CommonKey' = 8 + TAB: 'CommonKey' = 9 + NUM_PAD_OFF_5: 'CommonKey' = 12 + ENTER: 'CommonKey' = 13 + SHIFT: 'CommonKey' = 16 # Can be used for both Left and Right SHIFT + CTRL: 'CommonKey' = 17 # Can be used for both Left and Right CTRL + ALT: 'CommonKey' = 18 # Can be used for both Left and Right ALT + PAUSE: 'CommonKey' = 19 + CAPS_LOCK: 'CommonKey' = 20 + ESCAPE: 'CommonKey' = 27 + SPACE: 'CommonKey' = 32 + PAGE_UP: 'CommonKey' = 33 + PAGE_DOWN: 'CommonKey' = 34 + END: 'CommonKey' = 35 + HOME: 'CommonKey' = 36 + ARROW_LEFT: 'CommonKey' = 37 + ARROW_UP: 'CommonKey' = 38 + ARROW_RIGHT: 'CommonKey' = 39 + ARROW_DOWN: 'CommonKey' = 40 + SYSTEM_REQUEST: 'CommonKey' = 44 + INSERT: 'CommonKey' = 45 + DELETE: 'CommonKey' = 46 + KEY_0: 'CommonKey' = 48 + KEY_1: 'CommonKey' = 49 + KEY_2: 'CommonKey' = 50 + KEY_3: 'CommonKey' = 51 + KEY_4: 'CommonKey' = 52 + KEY_5: 'CommonKey' = 53 + KEY_6: 'CommonKey' = 54 + KEY_7: 'CommonKey' = 55 + KEY_8: 'CommonKey' = 56 + KEY_9: 'CommonKey' = 57 + KEY_A: 'CommonKey' = 65 + KEY_B: 'CommonKey' = 66 + KEY_C: 'CommonKey' = 67 + KEY_D: 'CommonKey' = 68 + KEY_E: 'CommonKey' = 69 + KEY_F: 'CommonKey' = 70 + KEY_G: 'CommonKey' = 71 + KEY_H: 'CommonKey' = 72 + KEY_I: 'CommonKey' = 73 + KEY_J: 'CommonKey' = 74 + KEY_K: 'CommonKey' = 75 + KEY_L: 'CommonKey' = 76 + KEY_M: 'CommonKey' = 77 + KEY_N: 'CommonKey' = 78 + KEY_O: 'CommonKey' = 79 + KEY_P: 'CommonKey' = 80 + KEY_Q: 'CommonKey' = 81 + KEY_R: 'CommonKey' = 82 + KEY_S: 'CommonKey' = 83 + KEY_T: 'CommonKey' = 84 + KEY_U: 'CommonKey' = 85 + KEY_V: 'CommonKey' = 86 + KEY_W: 'CommonKey' = 87 + KEY_X: 'CommonKey' = 88 + KEY_Y: 'CommonKey' = 89 + KEY_Z: 'CommonKey' = 90 + WINDOWS_LEFT: 'CommonKey' = 91 + WINDOWS_RIGHT: 'CommonKey' = 92 + APPLICATIONS: 'CommonKey' = 93 + NUM_PAD_0: 'CommonKey' = 96 + NUM_PAD_1: 'CommonKey' = 97 + NUM_PAD_2: 'CommonKey' = 98 + NUM_PAD_3: 'CommonKey' = 99 + NUM_PAD_4: 'CommonKey' = 100 + NUM_PAD_5: 'CommonKey' = 101 + NUM_PAD_6: 'CommonKey' = 102 + NUM_PAD_7: 'CommonKey' = 103 + NUM_PAD_8: 'CommonKey' = 104 + NUM_PAD_9: 'CommonKey' = 105 + NUM_PAD_MULTIPLY: 'CommonKey' = 106 + NUM_PAD_ADD: 'CommonKey' = 107 + NUM_PAD_SUBTRACT: 'CommonKey' = 109 + NUM_PAD_DECIMAL: 'CommonKey' = 110 + NUM_PAD_DIVIDE: 'CommonKey' = 111 + NUM_PAD_ENTER: 'CommonKey' = 13 + F1: 'CommonKey' = 112 + F2: 'CommonKey' = 113 + F3: 'CommonKey' = 114 + F4: 'CommonKey' = 115 + F5: 'CommonKey' = 116 + F6: 'CommonKey' = 117 + F7: 'CommonKey' = 118 + F8: 'CommonKey' = 119 + F9: 'CommonKey' = 120 + F10: 'CommonKey' = 121 + F11: 'CommonKey' = 122 + F12: 'CommonKey' = 123 + NUM_LOCK: 'CommonKey' = 144 + SCROLL_LOCK: 'CommonKey' = 145 + EQUAL: 'CommonKey' = 187 + SHIFT_LEFT: 'CommonKey' = 160 + SHIFT_RIGHT: 'CommonKey' = 161 + CTRL_LEFT: 'CommonKey' = 162 + CTRL_RIGHT: 'CommonKey' = 163 + ALT_LEFT: 'CommonKey' = 164 + ALT_RIGHT: 'CommonKey' = 165 + SEMICOLON: 'CommonKey' = 186 + COMMA: 'CommonKey' = 188 + SUBTRACT: 'CommonKey' = 189 + PERIOD: 'CommonKey' = 190 + FORWARD_SLASH: 'CommonKey' = 191 + BACK_SLASH: 'CommonKey' = 220 + TILDE: 'CommonKey' = 192 + SQUARE_BRACKET_LEFT: 'CommonKey' = 219 + SQUARE_BRACKET_RIGHT: 'CommonKey' = 221 + SINGLE_QUOTE: 'CommonKey' = 222 + + # noinspection PyBroadException + try: + import os + if os.name != 'nt': + # Mac Keys + BACKSPACE: 'CommonKey' = 51 + TAB: 'CommonKey' = 48 + ENTER: 'CommonKey' = 36 + SHIFT: 'CommonKey' = 56 # Left Shift since Mac does not have a common key code + CTRL: 'CommonKey' = 55 + ALT: 'CommonKey' = 58 # Left Alt since Mac does not have a common key code + CAPS_LOCK: 'CommonKey' = 57 + ESCAPE: 'CommonKey' = 53 + SPACE: 'CommonKey' = 49 + PAGE_UP: 'CommonKey' = 116 + PAGE_DOWN: 'CommonKey' = 121 + END: 'CommonKey' = 119 + HOME: 'CommonKey' = 115 + ARROW_LEFT: 'CommonKey' = 123 + ARROW_UP: 'CommonKey' = 126 + ARROW_RIGHT: 'CommonKey' = 124 + ARROW_DOWN: 'CommonKey' = 125 + INSERT: 'CommonKey' = -1 # No insert key on Mac + DELETE: 'CommonKey' = 117 + KEY_0: 'CommonKey' = 29 + KEY_1: 'CommonKey' = 18 + KEY_2: 'CommonKey' = 19 + KEY_3: 'CommonKey' = 20 + KEY_4: 'CommonKey' = 21 + KEY_5: 'CommonKey' = 23 + KEY_6: 'CommonKey' = 22 + KEY_7: 'CommonKey' = 26 + KEY_8: 'CommonKey' = 28 + KEY_9: 'CommonKey' = 25 + KEY_A: 'CommonKey' = 0 + KEY_B: 'CommonKey' = 11 + KEY_C: 'CommonKey' = 8 + KEY_D: 'CommonKey' = 2 + KEY_E: 'CommonKey' = 14 + KEY_F: 'CommonKey' = 3 + KEY_G: 'CommonKey' = 5 + KEY_H: 'CommonKey' = 4 + KEY_I: 'CommonKey' = 34 + KEY_J: 'CommonKey' = 38 + KEY_K: 'CommonKey' = 40 + KEY_L: 'CommonKey' = 37 + KEY_M: 'CommonKey' = 46 + KEY_N: 'CommonKey' = 45 + KEY_O: 'CommonKey' = 31 + KEY_P: 'CommonKey' = 35 + KEY_Q: 'CommonKey' = 12 + KEY_R: 'CommonKey' = 15 + KEY_S: 'CommonKey' = 1 + KEY_T: 'CommonKey' = 17 + KEY_U: 'CommonKey' = 32 + KEY_V: 'CommonKey' = 9 + KEY_W: 'CommonKey' = 13 + KEY_Y: 'CommonKey' = 16 + KEY_X: 'CommonKey' = 7 + KEY_Z: 'CommonKey' = 6 + NUM_PAD_0: 'CommonKey' = 82 + NUM_PAD_1: 'CommonKey' = 83 + NUM_PAD_2: 'CommonKey' = 84 + NUM_PAD_3: 'CommonKey' = 85 + NUM_PAD_4: 'CommonKey' = 86 + NUM_PAD_5: 'CommonKey' = 87 + NUM_PAD_6: 'CommonKey' = 88 + NUM_PAD_7: 'CommonKey' = 89 + NUM_PAD_8: 'CommonKey' = 91 + NUM_PAD_9: 'CommonKey' = 92 + NUM_PAD_MULTIPLY: 'CommonKey' = 67 + NUM_PAD_ADD: 'CommonKey' = 69 + NUM_PAD_SUBTRACT: 'CommonKey' = 78 + NUM_PAD_DECIMAL: 'CommonKey' = 65 + NUM_PAD_DIVIDE: 'CommonKey' = 75 + NUM_PAD_ENTER: 'CommonKey' = 76 + F1: 'CommonKey' = 122 + F2: 'CommonKey' = 120 + F3: 'CommonKey' = 99 + F4: 'CommonKey' = 118 + F5: 'CommonKey' = 96 + F6: 'CommonKey' = 97 + F7: 'CommonKey' = 98 + F8: 'CommonKey' = 100 + F9: 'CommonKey' = 101 + F10: 'CommonKey' = 109 + F11: 'CommonKey' = 103 + F12: 'CommonKey' = 111 + EQUAL: 'CommonKey' = 24 + SHIFT_LEFT: 'CommonKey' = 56 + SHIFT_RIGHT: 'CommonKey' = 60 + CTRL_LEFT: 'CommonKey' = 55 + CTRL_RIGHT: 'CommonKey' = 55 + ALT_LEFT: 'CommonKey' = 58 + ALT_RIGHT: 'CommonKey' = 61 + SEMICOLON: 'CommonKey' = 41 + COMMA: 'CommonKey' = 43 + SUBTRACT: 'CommonKey' = 27 + PERIOD: 'CommonKey' = 47 + FORWARD_SLASH: 'CommonKey' = 44 + BACK_SLASH: 'CommonKey' = 42 + TILDE: 'CommonKey' = 50 + SQUARE_BRACKET_LEFT: 'CommonKey' = 33 + SQUARE_BRACKET_RIGHT: 'CommonKey' = 30 + SINGLE_QUOTE: 'CommonKey' = 39 + except: + pass diff --git a/Scripts/s4ap/sims4communitylib/enums/common_object_delivery_method.py b/Scripts/s4ap/sims4communitylib/enums/common_object_delivery_method.py new file mode 100644 index 0000000..d0df384 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_object_delivery_method.py @@ -0,0 +1,109 @@ +""" +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 +""" +from typing import Iterator, Tuple + +from interactions.base.picker_interaction import PickerInteractionDeliveryMethod +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonObjectDeliveryMethod(CommonInt): + """A method of delivery for objects.""" + NONE: 'CommonObjectDeliveryMethod' = ... + DELIVERY_SERVICE: 'CommonObjectDeliveryMethod' = ... + INVENTORY: 'CommonObjectDeliveryMethod' = ... + MAIL: 'CommonObjectDeliveryMethod' = ... + + @classmethod + def get_all(cls, exclude_values: Iterator['CommonObjectDeliveryMethod'] = None) -> Tuple['CommonObjectDeliveryMethod']: + """get_all(exclude_values=None) + + Get a collection of all values. + + :param exclude_values: These values will be excluded. If set to None, NONE will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonObjectDeliveryMethod], optional + :return: A collection of all values. + :rtype: Tuple[CommonObjectDeliveryMethod] + """ + if exclude_values is None: + exclude_values = (cls.NONE,) + # noinspection PyTypeChecker + value_list: Tuple[CommonObjectDeliveryMethod, ...] = tuple([value for value in cls.values if value not in exclude_values]) + return value_list + + @classmethod + def get_all_names(cls, exclude_values: Iterator['CommonObjectDeliveryMethod'] = None) -> Tuple[str]: + """get_all_names(exclude_values=None) + + Retrieve a collection of the names of all values. + + :param exclude_values: These values will be excluded. If set to None, NONE will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonObjectDeliveryMethod], optional + :return: A collection of the names of all values. + :rtype: Tuple[str] + """ + name_list: Tuple[str] = tuple([value.name for value in cls.get_all(exclude_values=exclude_values)]) + return name_list + + @classmethod + def get_comma_separated_names_string(cls, exclude_values: Iterator['CommonObjectDeliveryMethod'] = None) -> str: + """get_comma_separated_names_string(exclude_values=None) + + Create a string containing all names of all values, separated by a comma. + + :param exclude_values: These values will be excluded. If set to None, NONE will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonObjectDeliveryMethod], optional + :return: A string containing all names of all values, separated by a comma. + :rtype: str + """ + return ', '.join(cls.get_all_names(exclude_values=exclude_values)) + + @staticmethod + def convert_to_vanilla(value: 'CommonObjectDeliveryMethod') -> PickerInteractionDeliveryMethod: + """convert_to_vanilla(value) + + Convert a value into the vanilla PickerInteractionDeliveryMethod enum. + + :param value: An instance of CommonObjectDeliveryMethod + :type value: CommonObjectDeliveryMethod + :return: The specified value translated to PickerInteractionDeliveryMethod or INVENTORY if the value could not be translated. + :rtype: PickerInteractionDeliveryMethod + """ + if value is None or value == CommonObjectDeliveryMethod.NONE: + return PickerInteractionDeliveryMethod.INVENTORY + if isinstance(value, PickerInteractionDeliveryMethod): + # noinspection PyTypeChecker + return value + mapping = { + CommonObjectDeliveryMethod.INVENTORY: PickerInteractionDeliveryMethod.INVENTORY, + CommonObjectDeliveryMethod.MAIL: PickerInteractionDeliveryMethod.MAILMAN, + CommonObjectDeliveryMethod.DELIVERY_SERVICE: PickerInteractionDeliveryMethod.DELIVERY_SERVICE_NPC, + } + return mapping.get(value, PickerInteractionDeliveryMethod.INVENTORY) + + @staticmethod + def convert_from_vanilla(value: PickerInteractionDeliveryMethod) -> 'CommonObjectDeliveryMethod': + """convert_from_vanilla(value) + + Convert a value into a CommonObjectDeliveryMethod enum. + + :param value: An instance of PickerInteractionDeliveryMethod + :type value: PickerInteractionDeliveryMethod + :return: The specified value translated to CommonObjectDeliveryMethod or INVENTORY if the value could not be translated. + :rtype: CommonObjectDeliveryMethod + """ + if value is None or value == CommonObjectDeliveryMethod.NONE: + return PickerInteractionDeliveryMethod.INVENTORY + if isinstance(value, PickerInteractionDeliveryMethod): + # noinspection PyTypeChecker + return value + mapping = { + PickerInteractionDeliveryMethod.INVENTORY: CommonObjectDeliveryMethod.INVENTORY, + PickerInteractionDeliveryMethod.MAILMAN: CommonObjectDeliveryMethod.MAIL, + PickerInteractionDeliveryMethod.DELIVERY_SERVICE_NPC: CommonObjectDeliveryMethod.DELIVERY_SERVICE, + } + return mapping.get(value, CommonObjectDeliveryMethod.INVENTORY) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_object_filter_type.py b/Scripts/s4ap/sims4communitylib/enums/common_object_filter_type.py new file mode 100644 index 0000000..34f64b0 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_object_filter_type.py @@ -0,0 +1,15 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonObjectFilterType(CommonInt): + """The type of an object filter.""" + OBJECT_DEFINITION_FILTER = 0 + OBJECT_TAG_FILTER = 1 + CUSTOM = 5000 diff --git a/Scripts/s4ap/sims4communitylib/enums/common_object_preference_tag.py b/Scripts/s4ap/sims4communitylib/enums/common_object_preference_tag.py new file mode 100644 index 0000000..ae33e75 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_object_preference_tag.py @@ -0,0 +1,23 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonObjectPreferenceTag(CommonInt): + """ Object preference tags. """ + INVALID: 'CommonObjectPreferenceTag' = -1 + LOVESEAT: 'CommonObjectPreferenceTag' = 0 + BED: 'CommonObjectPreferenceTag' = 1 + STUFFED_ANIMAL: 'CommonObjectPreferenceTag' = 2 + INSTRUMENT: 'CommonObjectPreferenceTag' = 3 + COMPUTER: 'CommonObjectPreferenceTag' = 4 + FOOD: 'CommonObjectPreferenceTag' = 5 + DRINK: 'CommonObjectPreferenceTag' = 6 + TENT: 'CommonObjectPreferenceTag' = 7 + FOOD_BOWL: 'CommonObjectPreferenceTag' = 8 + PET_SLEEP_OBJECT: 'CommonObjectPreferenceTag' = 9 diff --git a/Scripts/s4ap/sims4communitylib/enums/common_object_quality.py b/Scripts/s4ap/sims4communitylib/enums/common_object_quality.py new file mode 100644 index 0000000..77e9bf7 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_object_quality.py @@ -0,0 +1,55 @@ +""" +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 +""" +from typing import Tuple, Iterator + +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonObjectQuality(CommonInt): + """Various types of object quality.""" + POOR: 'CommonObjectQuality' = ... + NORMAL: 'CommonObjectQuality' = ... + OUTSTANDING: 'CommonObjectQuality' = ... + + @classmethod + def get_all(cls, exclude_values: Iterator['CommonObjectQuality'] = ()) -> Tuple['CommonObjectQuality']: + """get_all(exclude_values=()) + + Get a collection of all values. + + :param exclude_values: These values will be excluded. Default is an empty collection. + :type exclude_values: Iterator[CommonObjectQuality], optional + :return: A collection of all values. + :rtype: Tuple[CommonObjectQuality] + """ + # noinspection PyTypeChecker + value_list: Tuple[CommonObjectQuality, ...] = tuple([value for value in cls.values if value not in exclude_values]) + return value_list + + @classmethod + def get_all_names(cls, exclude_values: Iterator['CommonObjectQuality'] = ()) -> Tuple[str]: + """get_all_names(exclude_values=()) + + Retrieve a collection of the names of all values. + + :return: A collection of the names of all values. + :rtype: Tuple[str] + """ + name_list: Tuple[str] = tuple([value.name for value in cls.get_all(exclude_values=exclude_values)]) + return name_list + + @classmethod + def get_comma_separated_names_string(cls, exclude_values: Iterator['CommonObjectQuality'] = ()) -> str: + """get_comma_separated_names_string(exclude_values=()) + + Create a string containing all names of all values, separated by a comma. + + :return: A string containing all names of all values, separated by a comma. + :rtype: str + """ + return ', '.join(cls.get_all_names(exclude_values=exclude_values)) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_object_slot_name_ids.py b/Scripts/s4ap/sims4communitylib/enums/common_object_slot_name_ids.py new file mode 100644 index 0000000..b038d4d --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_object_slot_name_ids.py @@ -0,0 +1,13 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonObjectSlotNameId(CommonInt): + """The string identifiers of slot names of objects.""" + DECORATION_SMALL_2 = 0xC8DB9C09 # DECO_SML_2 diff --git a/Scripts/s4ap/sims4communitylib/enums/common_object_state_ids.py b/Scripts/s4ap/sims4communitylib/enums/common_object_state_ids.py new file mode 100644 index 0000000..4137836 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_object_state_ids.py @@ -0,0 +1,14 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonObjectStateId(CommonInt): + """Identifier for object states. In most cases you will want to use CommonObjectStateValueId instead!""" + COMPUTER = 15102 + QUALITY = 15303 diff --git a/Scripts/s4ap/sims4communitylib/enums/common_object_state_value_ids.py b/Scripts/s4ap/sims4communitylib/enums/common_object_state_value_ids.py new file mode 100644 index 0000000..b24a99c --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_object_state_value_ids.py @@ -0,0 +1,33 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonObjectStateValueId(CommonInt): + """Identifier for object state values.""" + MURPHY_BED_OPEN = 228113 + MURPHY_BED_CLOSED = 228114 + COMPUTER_GAME_MARIA_SISTERS = 32922 + COMPUTER_SPACE_WOOHOO = 96857 + COMPUTER_OFF = 15106 + QUALITY_NORMAL = 15304 + QUALITY_OUTSTANDING = 15305 + QUALITY_POOR = 15306 + WASH_TUB_FUNCTIONS_EMPTY = 176816 + WASH_TUB_FUNCTIONS_WASHING = 176817 + WASH_TUB_FUNCTIONS_WATER_DIRTY = 177286 + WASH_TUB_FUNCTIONS_WATER_CLEAN = 177285 + WASH_TUB_LOAD_PROGRESS_DONE = 179510 + WASH_TUB_LOAD_PROGRESS_INCOMPLETE = 179511 + + PREGNANT_IN_LABOR = 75273 + PREGNANT_FIRST_TRIMESTER = 15298 + PREGNANT_SECOND_TRIMESTER = 15301 + PREGNANT_THIRD_TRIMESTER = 15302 + PREGNANT_NOT_SHOWING = 15300 + PREGNANT_NOT_PREGNANT = 15299 diff --git a/Scripts/s4ap/sims4communitylib/enums/common_occult_type.py b/Scripts/s4ap/sims4communitylib/enums/common_occult_type.py new file mode 100644 index 0000000..29c0071 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_occult_type.py @@ -0,0 +1,175 @@ +""" +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 +""" +from typing import Union, Tuple, Iterator, Dict + +from protocolbuffers.Localization_pb2 import LocalizedString +from sims.occult.occult_enums import OccultType +from sims.sim_info import SimInfo +from sims4communitylib.enums.enumtypes.common_int import CommonInt +from sims4communitylib.enums.strings_enum import CommonStringId + + +class CommonOccultType(CommonInt): + """Custom Occult Types enum containing all occults. DLC not required. + + """ + NONE: 'CommonOccultType' = ... + ALIEN: 'CommonOccultType' = ... + GHOST: 'CommonOccultType' = ... + MERMAID: 'CommonOccultType' = ... + NON_OCCULT: 'CommonOccultType' = ... + PLANT_SIM: 'CommonOccultType' = ... + ROBOT: 'CommonOccultType' = ... + SCARECROW: 'CommonOccultType' = ... + SKELETON: 'CommonOccultType' = ... + VAMPIRE: 'CommonOccultType' = ... + WEREWOLF: 'CommonOccultType' = ... + WITCH: 'CommonOccultType' = ... + + @classmethod + def get_all(cls, exclude_occult_types: Iterator['CommonOccultType'] = None) -> Tuple['CommonOccultType']: + """get_all(exclude_occult_types=None) + + Get a collection of all values. + + :param exclude_occult_types: These values will be excluded. If set to None, NONE will be excluded automatically. Default is None. + :type exclude_occult_types: Iterator[CommonOccultType], optional + :return: A collection of all CommonOccultType, without CommonOccultType.NONE. + :rtype: Tuple[CommonOccultType] + """ + if exclude_occult_types is None: + exclude_occult_types = (cls.NONE,) + # noinspection PyTypeChecker + value_list: Tuple[CommonOccultType] = tuple([value for value in cls.values if value not in exclude_occult_types]) + return value_list + + @classmethod + def get_all_names(cls, exclude_occult_types: Iterator['CommonOccultType'] = None) -> Tuple[str]: + """get_all_names(exclude_occult_types=None) + + Retrieve a collection of the names of all values. + + :param exclude_occult_types: These values will be excluded. If set to None, NONE will be excluded automatically. Default is None. + :type exclude_occult_types: Iterator[CommonOccultType], optional + :return: A collection of the names of all values. + :rtype: Tuple[str] + """ + name_list: Tuple[str] = tuple([value.name for value in cls.get_all(exclude_occult_types=exclude_occult_types)]) + return name_list + + @classmethod + def get_comma_separated_names_string(cls, exclude_occult_types: Iterator['CommonOccultType'] = None) -> str: + """get_comma_separated_names_string(exclude_occult_types=None) + + Create a string containing all names of all values, separated by a comma. + + :param exclude_occult_types: These values will be excluded. If set to None, NONE will be excluded automatically. Default is None. + :type exclude_occult_types: Iterator[CommonOccultType], optional + :return: A string containing all names of all values, separated by a comma. + :rtype: str + """ + return ', '.join(cls.get_all_names(exclude_occult_types=exclude_occult_types)) + + @staticmethod + def determine_occult_type(sim_info: SimInfo) -> 'CommonOccultType': + """determine_occult_type(sim_info) + + Determine the type of Occult a Sim is. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The CommonOccultType that represents what a Sim is. + :rtype: CommonOccultType + """ + from sims4communitylib.utils.sims.common_sim_occult_type_utils import CommonSimOccultTypeUtils + return CommonSimOccultTypeUtils.determine_occult_type(sim_info) + + @staticmethod + def determine_current_occult_type(sim_info: SimInfo) -> 'CommonOccultType': + """determine_current_occult_type(sim_info) + + Determine the type of Occult a Sim is currently appearing as. + i.e. A mermaid with their tail out would currently be a MERMAID. But a Mermaid Sim with no tail out would currently be a CommonOccultType.NONE + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The CommonOccultType the Sim is currently appearing as, or CommonOccultType.NONE if they are not appearing as any Occult or are appearing as their HUMAN disguise/occult. + :rtype: CommonOccultType + """ + from sims4communitylib.utils.sims.common_sim_occult_type_utils import CommonSimOccultTypeUtils + return CommonSimOccultTypeUtils.determine_current_occult_type(sim_info) + + @staticmethod + def convert_to_vanilla(occult_type: 'CommonOccultType') -> Union[OccultType, None]: + """convert_to_vanilla(occult_type) + + Convert a CommonOccultType into the vanilla OccultType enum. + + .. note:: Not all CommonOccultTypes have an OccultType to convert to! They will return None in those cases! (Ghost, Plant Sim, Robot, Skeleton) + + :param occult_type: An instance of CommonOccultType + :type occult_type: CommonOccultType + :return: The specified CommonOccultType translated to OccultType, or None if the value could not be translated. + :rtype: Union[OccultType, None] + """ + from sims4communitylib.utils.sims.common_sim_occult_type_utils import CommonSimOccultTypeUtils + return CommonSimOccultTypeUtils.convert_custom_type_to_vanilla(occult_type) + + @staticmethod + def convert_from_vanilla(value: Union[OccultType, 'CommonOccultType', int]) -> Union['CommonOccultType', OccultType, int]: + """convert_from_vanilla(value) + + Convert a vanilla value into this enum. + + :param value: The value to convert. + :type value: Union[OccultType, 'CommonOccultType', int] + :return: The specified value translated to CommonOccultType. The value will be returned if it cannot be translated. + :rtype: Union['CommonOccultType', OccultType, int] + """ + mapping: Dict[OccultType, CommonOccultType] = dict() + if hasattr(OccultType, 'HUMAN'): + mapping[OccultType.HUMAN] = CommonOccultType.NON_OCCULT + if hasattr(OccultType, 'ALIEN'): + mapping[OccultType.ALIEN] = CommonOccultType.ALIEN + if hasattr(OccultType, 'VAMPIRE'): + mapping[OccultType.VAMPIRE] = CommonOccultType.VAMPIRE + if hasattr(OccultType, 'MERMAID'): + mapping[OccultType.MERMAID] = CommonOccultType.MERMAID + if hasattr(OccultType, 'WITCH'): + mapping[OccultType.WITCH] = CommonOccultType.WITCH + if hasattr(OccultType, 'WEREWOLF'): + mapping[OccultType.WEREWOLF] = CommonOccultType.WEREWOLF + return mapping.get(value, value) + + @staticmethod + def convert_to_localized_string_id(value: 'CommonOccultType') -> Union[int, str, CommonStringId, LocalizedString]: + """convert_to_localized_string_id(value) + + Convert a CommonOccultType into a Localized String identifier. + + :param value: An instance of a CommonOccultType + :type value: CommonOccultType + :return: The specified CommonOccultType translated to a localized string identifier. If no localized string id is found, the name property of the value will be used instead. + :rtype: Union[int, str, CommonStringId, LocalizedString] + """ + mapping: Dict[CommonOccultType, CommonStringId] = { + CommonOccultType.NONE: CommonStringId.S4CL_NONE, + CommonOccultType.ALIEN: CommonStringId.S4CL_ALIEN, + CommonOccultType.MERMAID: CommonStringId.S4CL_MERMAID, + CommonOccultType.ROBOT: CommonStringId.S4CL_ROBOT, + CommonOccultType.SCARECROW: CommonStringId.S4CL_SCARECROW, + CommonOccultType.SKELETON: CommonStringId.S4CL_SKELETON, + CommonOccultType.VAMPIRE: CommonStringId.S4CL_VAMPIRE, + CommonOccultType.WITCH: CommonStringId.S4CL_WITCH, + CommonOccultType.PLANT_SIM: CommonStringId.S4CL_PLANT_SIM, + CommonOccultType.GHOST: CommonStringId.S4CL_GHOST, + CommonOccultType.WEREWOLF: CommonStringId.S4CL_WEREWOLF, + CommonOccultType.NON_OCCULT: CommonStringId.S4CL_NON_OCCULT, + } + + return mapping.get(value, value.name if hasattr(value, 'name') else str(value)) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_posture_id.py b/Scripts/s4ap/sims4communitylib/enums/common_posture_id.py new file mode 100644 index 0000000..bb7806f --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_posture_id.py @@ -0,0 +1,186 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonPostureId(CommonInt): + """Identifiers for postures.""" + ALIEN_PORTAL: 'CommonPostureId' = 110849 + ARCADE_MACHINE: 'CommonPostureId' = 127556 + BAR_MAKE_DRINK: 'CommonPostureId' = 15514 + BATHTUB_TODDLER_BATH: 'CommonPostureId' = 143802 + BATHTUB_TAKE_BATH: 'CommonPostureId' = 15515 + BATHTUB_BUBBLE_BATH: 'CommonPostureId' = 35351 + BATHTUB_PET_BATH: 'CommonPostureId' = 165598 + BE_CARRIED: 'CommonPostureId' = 132262 + CARRY_SIM: 'CommonPostureId' = 132169 + CAVE_WOOHOO: 'CommonPostureId' = 252479 + BEACH_CAVE: 'CommonPostureId' = 210419 + BEACH_TOWEL: 'CommonPostureId' = 208930 + BED_NAP: 'CommonPostureId' = 15517 + BED_RELAX: 'CommonPostureId' = 15518 + BED_SLEEP: 'CommonPostureId' = 15519 + BED_UNDER_COVERS: 'CommonPostureId' = 33972 + BED_WOOHOO: 'CommonPostureId' = 15520 + BONFIRE_STAND_INTIMATE: 'CommonPostureId' = 126186 + BOOKING_STATION: 'CommonPostureId' = 109496 + BUSH: 'CommonPostureId' = 124832 + BUSH_FERTILIZE_STANDING: 'CommonPostureId' = 127097 + BUSH_WOOHOO: 'CommonPostureId' = 125220 + CARRY_NOTHING: 'CommonPostureId' = 15521 + CARRY_OBJECT: 'CommonPostureId' = 15522 + CLOSET: 'CommonPostureId' = 121953 + CLOSET_WOOHOO: 'CommonPostureId' = 123382 + COFFIN_SLEEP: 'CommonPostureId' = 149837 + COFFIN_WOOHOO: 'CommonPostureId' = 154863 + COOK: 'CommonPostureId' = 15525 + DANCE: 'CommonPostureId' = 15526 + DANCE_FLOOR: 'CommonPostureId' = 124490 + DART_BOARD: 'CommonPostureId' = 127819 + DENIZEN_SWIMS: 'CommonPostureId' = 200577 + DJ_BOOTH: 'CommonPostureId' = 121363 + DUMPSTER_NAP: 'CommonPostureId' = 239034 + DUMPSTER_WOOHOO: 'CommonPostureId' = 234105 + FLOATING: 'CommonPostureId' = 207354 + FOOSBALL_TABLE: 'CommonPostureId' = 121523 + FOUNTAIN: 'CommonPostureId' = 131552 + FOX_STEAL_EGG: 'CommonPostureId' = 267029 + GRILL: 'CommonPostureId' = 35023 + GROUP_DANCE: 'CommonPostureId' = 129321 + GROUP_DANCING: 'CommonPostureId' = 278187 + GROUP_WORKOUT_DANCE: 'CommonPostureId' = 166807 + GROUP_WORKOUT_POWER_SCULPT: 'CommonPostureId' = 164935 + HAIR_MAKE_UP_CHAIR_HAIR: 'CommonPostureId' = 189778 + HAIR_MAKE_UP_CHAIR_MAKE_UP: 'CommonPostureId' = 189779 + HIDE_UNDER_OBJECT: 'CommonPostureId' = 174205 + HOLDING_CELL_DOOR: 'CommonPostureId' = 109798 + HOSPITAL_EXAM_BED_RECLINE: 'CommonPostureId' = 107794 + HOSPITAL_EXAM_BED_SIT: 'CommonPostureId' = 107793 + HOSPITAL_EXAM_BED_STAND: 'CommonPostureId' = 110594 + HOSPITAL_TREADMILL_DOCTOR: 'CommonPostureId' = 111461 + HOSPITAL_TREADMILL_PATIENT_WAIT: 'CommonPostureId' = 111957 + HOT_SPRINGS_SIT: 'CommonPostureId' = 247297 + HOT_SPRINGS_STAND: 'CommonPostureId' = 247298 + HOT_SPRINGS_WOOHOO: 'CommonPostureId' = 247299 + HOT_TUB_SIT: 'CommonPostureId' = 117257 + HOT_TUB_STAND: 'CommonPostureId' = 117256 + HOT_TUB_WOOHOO: 'CommonPostureId' = 117782 + HUMANOID_ROBOT_ACTIVATE: 'CommonPostureId' = 229263 + HUMANOID_ROBOT_BROKEN: 'CommonPostureId' = 228705 + HUMANOID_ROBOT_POWERED_DOWN: 'CommonPostureId' = 229690 + HUMANOID_ROBOT_STASIS_SIT: 'CommonPostureId' = 228808 + HUMANOID_ROBOT_STASIS_STAND: 'CommonPostureId' = 228802 + ICE_SKATE: 'CommonPostureId' = 172634 + ISLAND_CANOE: 'CommonPostureId' = 206337 + ISLAND_CANOE_SIT: 'CommonPostureId' = 208298 + ISLAND_CANOE_STAND: 'CommonPostureId' = 208299 + ISLAND_WATERFALL_PLAY: 'CommonPostureId' = 207479 + ISLAND_WATERFALL_WOOHOO: 'CommonPostureId' = 207291 + JUICE_KEG_KEG_STAND: 'CommonPostureId' = 208473 + JUMP_STAND: 'CommonPostureId' = 128689 + JUNGLE_GYM: 'CommonPostureId' = 36915 + KARAOKE_MACHINE: 'CommonPostureId' = 137354 + KIDDIE_POOL_GIVE_POOL: 'CommonPostureId' = 188318 + KIDDIE_POOL_LOUNGE: 'CommonPostureId' = 188578 + KID_TENT: 'CommonPostureId' = 259639 + KNEEL: 'CommonPostureId' = 15527 + LAY_DOWN: 'CommonPostureId' = 161631 + LAY_DOWN_ON_GROUND: 'CommonPostureId' = 124535 + LIVESTOCK_PEN: 'CommonPostureId' = 263848 + LIVESTOCK_PEN_WOOHOO: 'CommonPostureId' = 263110 + LEAF_PILE_WOOHOO: 'CommonPostureId' = 185751 + LIGHTHOUSE_WOOHOO: 'CommonPostureId' = 172241 + LOUNGE_CHAIR: 'CommonPostureId' = 207639 + MASSAGE_CHAIR_FOOT_MASSAGE_LEFT: 'CommonPostureId' = 120080 + MASSAGE_CHAIR_FOOT_MASSAGE_RIGHT: 'CommonPostureId' = 120081 + MASSAGE_CHAIR_RECLINED: 'CommonPostureId' = 119303 + MASSAGE_TABLE_CUSTOMER: 'CommonPostureId' = 117578 + MASSAGE_TABLE_THERAPIST: 'CommonPostureId' = 120212 + MEDITATE_LEVITATION: 'CommonPostureId' = 118964 + MEDITATE_MEDITATION: 'CommonPostureId' = 118962 + MICROSCOPE: 'CommonPostureId' = 10477 + MONKEY_BARS_HANG_OUT: 'CommonPostureId' = 15529 + MONKEY_BARS_PLAY: 'CommonPostureId' = 15530 + MOTION_BASED_GAMING: 'CommonPostureId' = 37063 + MOVING_STAND: 'CommonPostureId' = 30530 + OBSERVATORY: 'CommonPostureId' = 34816 + PAIRED_DANCING: 'CommonPostureId' = 272515 + PET_INTIMATE: 'CommonPostureId' = 164333 + PING_PONG_READY_STANCE: 'CommonPostureId' = 212553 + PODIUM_PAIR_DEBATE: 'CommonPostureId' = 221261 + POTTY_CHAIR_SIT: 'CommonPostureId' = 144863 + PUBLIC_BATHROOM: 'CommonPostureId' = 38367 + PUNCHING_BAG: 'CommonPostureId' = 10254 + PUPPET_THEATER: 'CommonPostureId' = 135680 + RABBIT_HOLE_BRAMBLE: 'CommonPostureId' = 102995 + RABBIT_HOLE_CAVE: 'CommonPostureId' = 99237 + RABBIT_HOLE_EURO_BRAMBLE: 'CommonPostureId' = 126039 + RABBIT_HOLE_TREE: 'CommonPostureId' = 98538 + RELAXING_BATH: 'CommonPostureId' = 120382 + ROCKET_SHIP: 'CommonPostureId' = 34856 + ROCKET_SHIP_WOOHOO: 'CommonPostureId' = 15531 + ROLLER_SKATE: 'CommonPostureId' = 182936 + SHOWER: 'CommonPostureId' = 15532 + SHOWER_CLEAN: 'CommonPostureId' = 15533 + SHOWER_WOOHOO: 'CommonPostureId' = 227360 + SIT: 'CommonPostureId' = 15535 + SIT_INTIMATE: 'CommonPostureId' = 15536 + SIT_INTIMATE_BOOTH: 'CommonPostureId' = 131139 + SIT_IN_TODDLER_HIGH_CHAIR: 'CommonPostureId' = 135522 + SIT_LOUNGE_FLOAT: 'CommonPostureId' = 210552 + SIT_ON_GROUND: 'CommonPostureId' = 134340 + SIT_POOL_EDGE: 'CommonPostureId' = 103374 + SIT_TOGETHER: 'CommonPostureId' = 131565 + SIT_CHAISE: 'CommonPostureId' = 260053 + SIT_KOTATSU: 'CommonPostureId' = 247766 + SIT_ROBOT_VACUUM: 'CommonPostureId' = 170752 + SIT_ROCKING_CHAIR: 'CommonPostureId' = 240809 + SLEEPING_POD_SLEEP: 'CommonPostureId' = 200051 + SLEEPING_POD_WOOHOO: 'CommonPostureId' = 200543 + SMALL_TELESCOPE: 'CommonPostureId' = 292843 + SNOW_SPORTS_SLOPE_SKI: 'CommonPostureId' = 237666 + SNOW_SPORTS_SLOPE_SLED: 'CommonPostureId' = 246810 + SNOW_SPORTS_SLOPE_SLED_TOGETHER: 'CommonPostureId' = 238052 + SNOW_SPORTS_SLOPE_SNOWBOARD: 'CommonPostureId' = 246792 + SOFA_NAP: 'CommonPostureId' = 28879 + STAND: 'CommonPostureId' = 15537 + STAND_EXCLUSIVE: 'CommonPostureId' = 23832 + STAND_ON_OBJECT: 'CommonPostureId' = 158065 + STARGAZE: 'CommonPostureId' = 104171 + STEAM_ROOM_SIT: 'CommonPostureId' = 120222 + STEAM_ROOM_WOOHOO: 'CommonPostureId' = 119528 + SURGERY_TABLE_DOCTOR_STAND: 'CommonPostureId' = 110016 + SURGERY_TABLE_PATIENT_RECLINE: 'CommonPostureId' = 110017 + SWIM: 'CommonPostureId' = 39398 + SWING_SET: 'CommonPostureId' = 186153 + TELESCOPE_WOOHOO: 'CommonPostureId' = 15538 + TENT: 'CommonPostureId' = 103267 + TENT_WOOHOO: 'CommonPostureId' = 103266 + TODDLER_JUNGLE_GYM_BALL_PIT: 'CommonPostureId' = 170635 + TODDLER_JUNGLE_GYM_SLIDE: 'CommonPostureId' = 170664 + TODDLER_JUNGLE_GYM_TUNNELS: 'CommonPostureId' = 170645 + TOILET_SIT: 'CommonPostureId' = 15539 + TOILET_SIT_STALL: 'CommonPostureId' = 214050 + TOILET_STAND: 'CommonPostureId' = 15540 + TOILET_STAND_STALL: 'CommonPostureId' = 214049 + TREADMILL: 'CommonPostureId' = 15541 + VEHICLE_BIKE_SIT: 'CommonPostureId' = 209143 + WALK_IN_SAFE_WOOHOO: 'CommonPostureId' = 193829 + WARDROBE_PEDESTAL: 'CommonPostureId' = 191328 + WATCH_INTIMATE: 'CommonPostureId' = 129111 + WATER_SCOOTER: 'CommonPostureId' = 199821 + WEDDING_CAKE_CUT_TOGETHER: 'CommonPostureId' = 276773 + WEDDING_AISLE_RUNNER_WALK_TOGETHER: 'CommonPostureId' = 275168 + WORKOUT_MACHINE: 'CommonPostureId' = 15542 + XRAY_MACHINE_SCAN_DOCTOR: 'CommonPostureId' = 109936 + XRAY_MACHINE_SCAN_PATIENT: 'CommonPostureId' = 105968 + YOGA: 'CommonPostureId' = 117358 + VET_EXAM_TABLE_PET: 'CommonPostureId' = 165261 + VET_EXAM_TABLE_VET: 'CommonPostureId' = 165262 + VET_SURGERY_PET: 'CommonPostureId' = 171965 + VET_SURGERY_VET: 'CommonPostureId' = 166573 diff --git a/Scripts/s4ap/sims4communitylib/enums/common_precipitation_type.py b/Scripts/s4ap/sims4communitylib/enums/common_precipitation_type.py new file mode 100644 index 0000000..8e6d17a --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_precipitation_type.py @@ -0,0 +1,78 @@ +""" +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 +""" +from typing import Tuple, Union, Iterator + +from sims4communitylib.enums.enumtypes.common_int import CommonInt + +# noinspection PyBroadException +try: + from weather.weather_enums import PrecipitationType +except: + class PrecipitationType(CommonInt): + """Mock class.""" + RAIN = 1000 + SNOW = 1001 + + +class CommonPrecipitationType(CommonInt): + """Identifiers for precipitation types.""" + RAIN: 'CommonPrecipitationType' = ... + SNOW: 'CommonPrecipitationType' = ... + + @classmethod + def get_all(cls, exclude_values: Iterator['CommonPrecipitationType'] = ()) -> Tuple['CommonPrecipitationType']: + """get_all(exclude_values=()) + + Get a collection of all values. + + :param exclude_values: These values will be excluded. Default is an empty collection. + :type exclude_values: Iterator[CommonPrecipitationType], optional + :return: A collection of all values. + :rtype: Tuple[CommonPrecipitationType] + """ + # noinspection PyTypeChecker + value_list: Tuple[CommonPrecipitationType, ...] = tuple([value for value in cls.values if value not in exclude_values]) + return value_list + + @staticmethod + def convert_to_vanilla(value: 'CommonPrecipitationType') -> PrecipitationType: + """convert_to_vanilla(value) + + Convert a CommonPrecipitationType into PrecipitationType. + + :param value: An instance of CommonPrecipitationType + :type value: CommonPrecipitationType + :return: The specified CommonPrecipitationType translated to PrecipitationType, or the value itself if the value could not be translated. + :rtype: PrecipitationType + """ + if isinstance(value, PrecipitationType): + return value + mapping = { + CommonPrecipitationType.RAIN: PrecipitationType.RAIN, + CommonPrecipitationType.SNOW: PrecipitationType.SNOW + } + return mapping.get(value, value) + + @staticmethod + def convert_from_vanilla(value: PrecipitationType) -> Union['CommonPrecipitationType', None]: + """convert_from_vanilla(value) + + Convert a vanilla PrecipitationType into CommonPrecipitationType. + + :param value: An instance of PrecipitationType + :type value: PrecipitationType + :return: The specified PrecipitationType translated to CommonPrecipitationType, or the value itself if the value could not be translated. + :rtype: CommonPrecipitationType + """ + if isinstance(value, CommonPrecipitationType): + return value + mapping = { + PrecipitationType.RAIN: CommonPrecipitationType.RAIN, + PrecipitationType.SNOW: CommonPrecipitationType.SNOW + } + return mapping.get(value, value) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_pregnancy_origin.py b/Scripts/s4ap/sims4communitylib/enums/common_pregnancy_origin.py new file mode 100644 index 0000000..c541cab --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_pregnancy_origin.py @@ -0,0 +1,21 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonPregnancyOrigin(CommonInt): + """ Various origins that a pregnancy may come from. """ + VANILLA_WOOHOO = 0 + ALIEN_ABDUCTION = 64 + VAMPIRE_BATS = 65 + LIGHTHOUSE = 66 + FATHER_WINTER = 67 + MONEY_PILE = 68 + MERFOLK = 69 + ELEMENTAL = 70 + CUSTOM = 60000 diff --git a/Scripts/s4ap/sims4communitylib/enums/common_puddle_liquid.py b/Scripts/s4ap/sims4communitylib/enums/common_puddle_liquid.py new file mode 100644 index 0000000..65e6856 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_puddle_liquid.py @@ -0,0 +1,82 @@ +""" +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 +""" +from typing import Union + +from objects.puddles import PuddleLiquid +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonPuddleLiquid(CommonInt): + """ Various types of liquids a puddle may have. """ + INVALID: 'CommonPuddleLiquid' = ... + ACID: 'CommonPuddleLiquid' = ... + DARK_MATTER: 'CommonPuddleLiquid' = ... + GREEN_GOO: 'CommonPuddleLiquid' = ... + MUD: 'CommonPuddleLiquid' = ... + VOMIT: 'CommonPuddleLiquid' = ... + WATER: 'CommonPuddleLiquid' = ... + + @staticmethod + def convert_to_vanilla(value: 'CommonPuddleLiquid') -> Union[PuddleLiquid, None]: + """convert_to_vanilla(value) + + Convert a value into the vanilla PuddleLiquid enum. + + :param value: An instance of a CommonPuddleLiquid + :type value: CommonPuddleLiquid + :return: The specified value translated to a PuddleLiquid or INVALID if the value could not be translated. + :rtype: Union[PuddleLiquid, None] + """ + if value is None or value == CommonPuddleLiquid.INVALID: + return PuddleLiquid.INVALID + if isinstance(value, PuddleLiquid): + return value + mapping = dict() + if hasattr(PuddleLiquid, 'WATER'): + mapping[CommonPuddleLiquid.WATER] = PuddleLiquid.WATER + if hasattr(PuddleLiquid, 'Dark Matter'): + mapping[CommonPuddleLiquid.DARK_MATTER] = getattr(PuddleLiquid, 'Dark Matter') + if hasattr(PuddleLiquid, 'GreenGoo'): + mapping[CommonPuddleLiquid.GREEN_GOO] = PuddleLiquid.GreenGoo + if hasattr(PuddleLiquid, 'Vomit'): + mapping[CommonPuddleLiquid.VOMIT] = PuddleLiquid.Vomit + if hasattr(PuddleLiquid, 'Mud'): + mapping[CommonPuddleLiquid.MUD] = PuddleLiquid.Mud + if hasattr(PuddleLiquid, 'Acid'): + mapping[CommonPuddleLiquid.ACID] = PuddleLiquid.Acid + return mapping.get(value, PuddleLiquid.INVALID) + + @staticmethod + def convert_from_vanilla(value: PuddleLiquid) -> Union['CommonPuddleLiquid', None]: + """convert_from_vanilla(value) + + Convert a value into a CommonPuddleLiquid enum. + + :param value: An instance of a PuddleLiquid + :type value: PuddleLiquid + :return: The specified value translated to a CommonPuddleLiquid or INVALID if the value could not be translated. + :rtype: Union['CommonPuddleLiquid', None] + """ + if value is None or value == CommonPuddleLiquid.INVALID: + return PuddleLiquid.INVALID + if isinstance(value, CommonPuddleLiquid): + return value + mapping = dict() + if hasattr(PuddleLiquid, 'WATER'): + mapping[PuddleLiquid.WATER] = CommonPuddleLiquid.WATER + if hasattr(PuddleLiquid, 'Dark Matter'): + mapping[getattr(PuddleLiquid, 'Dark Matter')] = CommonPuddleLiquid.DARK_MATTER + if hasattr(PuddleLiquid, 'GreenGoo'): + mapping[PuddleLiquid.GreenGoo] = CommonPuddleLiquid.GREEN_GOO + if hasattr(PuddleLiquid, 'Vomit'): + mapping[PuddleLiquid.Vomit] = CommonPuddleLiquid.VOMIT + if hasattr(PuddleLiquid, 'Mud'): + mapping[PuddleLiquid.Mud] = CommonPuddleLiquid.MUD + if hasattr(PuddleLiquid, 'Acid'): + mapping[PuddleLiquid.Acid] = CommonPuddleLiquid.ACID + return mapping.get(value, PuddleLiquid.INVALID) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_puddle_size.py b/Scripts/s4ap/sims4communitylib/enums/common_puddle_size.py new file mode 100644 index 0000000..0a915eb --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_puddle_size.py @@ -0,0 +1,61 @@ +""" +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 +""" +from objects.puddles import PuddleSize +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonPuddleSize(CommonInt): + """ Various sizes of puddles. """ + NONE: 'CommonPuddleSize' = ... + SMALL: 'CommonPuddleSize' = ... + MEDIUM: 'CommonPuddleSize' = ... + LARGE: 'CommonPuddleSize' = ... + + @staticmethod + def convert_to_vanilla(value: 'CommonPuddleSize') -> PuddleSize: + """convert_to_vanilla(value) + + Convert a value into the vanilla PuddleSize enum. + + :param value: An instance of a CommonPuddleSize + :type value: CommonPuddleSize + :return: The specified value translated to a PuddleSize or NoPuddle if the value could not be translated. + :rtype: PuddleSize + """ + if value is None or value == CommonPuddleSize.NONE: + return PuddleSize.NoPuddle + if isinstance(value, PuddleSize): + return value + mapping = { + CommonPuddleSize.SMALL: PuddleSize.SmallPuddle, + CommonPuddleSize.MEDIUM: PuddleSize.MediumPuddle, + CommonPuddleSize.LARGE: PuddleSize.LargePuddle, + } + return mapping.get(value, PuddleSize.NoPuddle) + + @staticmethod + def convert_from_vanilla(value: PuddleSize) -> 'CommonPuddleSize': + """convert_from_vanilla(value) + + Convert a value into a CommonPuddleSize enum. + + :param value: An instance of a PuddleSize + :type value: PuddleSize + :return: The specified value translated to a CommonPuddleSize or NONE if the value could not be translated. + :rtype: CommonPuddleSize + """ + if value is None or value == PuddleSize.NoPuddle: + return CommonPuddleSize.NONE + if isinstance(value, CommonPuddleSize): + return value + mapping = { + PuddleSize.SmallPuddle: CommonPuddleSize.SMALL, + PuddleSize.MediumPuddle: CommonPuddleSize.MEDIUM, + PuddleSize.LargePuddle: CommonPuddleSize.LARGE, + } + return mapping.get(value, CommonPuddleSize.NONE) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_region_id.py b/Scripts/s4ap/sims4communitylib/enums/common_region_id.py new file mode 100644 index 0000000..72334a3 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_region_id.py @@ -0,0 +1,53 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonRegionId(CommonInt): + """Decimal Identifiers for Regions. + + """ + INVALID: 'CommonRegionId' = 0 + ACTING_STUDIO: 'CommonRegionId' = 190064 + ALIEN_WORLD: 'CommonRegionId' = 108705 + BATUU: 'CommonRegionId' = 231104 + BAY_AREA: 'CommonRegionId' = 302872 + CAMPING_FOREST: 'CommonRegionId' = 104096 + CAREER_DOCTOR_CLINIC: 'CommonRegionId' = 109306 + CHESTNUT_RIDGE: 'CommonRegionId' = 311185 + CITY_LIFE: 'CommonRegionId' = 134252 + COTTAGE_WORLD: 'CommonRegionId' = 257397 + ECO_WORLD: 'CommonRegionId' = 228200 + FAME_WORLD: 'CommonRegionId' = 195493 + FORGOTTEN_GROTTO: 'CommonRegionId' = 104062 + HIGH_SCHOOL_WORLD: 'CommonRegionId' = 272365 + ISLAND_WORLD: 'CommonRegionId' = 208308 + JUNGLE: 'CommonRegionId' = 173593 + MAGIC_VENUE: 'CommonRegionId' = 219134 + MAGIC_WORLD: 'CommonRegionId' = 216626 + MOUNTAIN_WORLD: 'CommonRegionId' = 238454 + NEW_CREST: 'CommonRegionId' = 119917 + NORTH_EUROPE: 'CommonRegionId' = 123129 + OASIS_SPRINGS: 'CommonRegionId' = 104065 + PET_WORLD: 'CommonRegionId' = 166547 + POLICE_STATION: 'CommonRegionId' = 108706 + RETAIL: 'CommonRegionId' = 108704 + SCIENCE_LAB: 'CommonRegionId' = 108707 + SLYVAN_GLADE: 'CommonRegionId' = 104063 + STRANGE_TOWN: 'CommonRegionId' = 201699 + TEST_WORLD: 'CommonRegionId' = 104066 + TEST_WORLD_EP07: 'CommonRegionId' = 197994 + TEST_WORLD_GP02: 'CommonRegionId' = 121398 + TEST_WORLD_MAGALOG: 'CommonRegionId' = 104067 + TEST_WORLD_MEGA_LOTS: 'CommonRegionId' = 131195 + TEST_WORLD_PERFORMANCE: 'CommonRegionId' = 104068 + UNIVERSITY_WORLD: 'CommonRegionId' = 208814 + VAMPIRE_WORLD: 'CommonRegionId' = 152175 + WEDDING_WORLD: 'CommonRegionId' = 272129 + WILLOW_CREEK: 'CommonRegionId' = 104064 + WOLF_TOWN: 'CommonRegionId' = 285909 diff --git a/Scripts/s4ap/sims4communitylib/enums/common_runnable_state.py b/Scripts/s4ap/sims4communitylib/enums/common_runnable_state.py new file mode 100644 index 0000000..d3bc9ad --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_runnable_state.py @@ -0,0 +1,17 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonRunnableState(CommonInt): + """ States that a runnable can be in. """ + STOPPED = ... + STOPPING = ... + RUNNING = ... + STARTING = ... + WAITING_TO_START = ... diff --git a/Scripts/s4ap/sims4communitylib/enums/common_runnable_state_type.py b/Scripts/s4ap/sims4communitylib/enums/common_runnable_state_type.py new file mode 100644 index 0000000..45d7ae3 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_runnable_state_type.py @@ -0,0 +1,17 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonRunnableStateType(CommonInt): + """ States that a runnable can be in. """ + STOPPED = ... + STOPPING = ... + RUNNING = ... + STARTING = ... + WAITING_TO_START = ... diff --git a/Scripts/s4ap/sims4communitylib/enums/common_side.py b/Scripts/s4ap/sims4communitylib/enums/common_side.py new file mode 100644 index 0000000..28e70fd --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_side.py @@ -0,0 +1,108 @@ +""" +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 +""" +from typing import Iterator, Tuple, Union + +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonSide(CommonInt): + """A side of an object.""" + NONE: 'CommonSide' = ... + LEFT: 'CommonSide' = ... + RIGHT: 'CommonSide' = ... + FRONT: 'CommonSide' = ... + BACK: 'CommonSide' = ... + TOP: 'CommonSide' = ... + BOTTOM: 'CommonSide' = ... + + @classmethod + def get_all(cls, exclude_values: Iterator['CommonSide'] = None) -> Tuple['CommonSide']: + """get_all(exclude_values=None) + + Get a collection of all values. + + :param exclude_values: These values will be excluded. If set to None, NONE will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonSide], optional + :return: A collection of all values. + :rtype: Tuple[CommonSide] + """ + if exclude_values is None: + exclude_values = (cls.NONE,) + # noinspection PyTypeChecker + result: Tuple[CommonSide, ...] = tuple([value for value in cls.values if value not in exclude_values]) + return result + + @classmethod + def get_all_names(cls, exclude_values: Iterator['CommonSide'] = None) -> Tuple[str]: + """get_all_names(exclude_values=None) + + Retrieve a collection of the names of all values. + + :param exclude_values: These values will not be returned. If set to None, NONE will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonSide], optional + :return: A collection of the names of all values. + :rtype: Tuple[str] + """ + name_list: Tuple[str] = tuple([value.name for value in cls.get_all(exclude_values=exclude_values)]) + return name_list + + @classmethod + def get_comma_separated_names_string(cls, exclude_values: Iterator['CommonSide'] = None) -> str: + """get_comma_separated_names_string(exclude_values=None) + + Create a string containing all names of all values, separated by a comma. + + :param exclude_values: These values will not be returned. If set to None, NONE will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonSide], optional + :return: A string containing all names of all values, separated by a comma. + :rtype: str + """ + return ', '.join(cls.get_all_names(exclude_values=exclude_values)) + + @classmethod + def convert_to_opposite(cls, value: 'CommonSide') -> 'CommonSide': + """convert_to_opposite(value) + + Convert a value to its opposite. + + :param value: An instance of a value + :type value: CommonSide + :return: The specified value converted to its opposite or the value itself if it could not be converted. + :rtype: CommonSide + """ + mapping = { + CommonSide.LEFT: CommonSide.RIGHT, + CommonSide.RIGHT: CommonSide.LEFT, + CommonSide.FRONT: CommonSide.BACK, + CommonSide.BACK: CommonSide.FRONT, + CommonSide.TOP: CommonSide.BOTTOM, + CommonSide.BOTTOM: CommonSide.TOP, + } + return mapping.get(value, value) + + @classmethod + def convert_to_localized_string_id(cls, value: Union[int, 'CommonSide']) -> Union[int, str]: + """convert_to_localized_string_id(value) + + Convert a value into a Localized String identifier. + + :param value: An instance of a value + :type value: CommonSide + :return: The specified value translated to a localized string identifier. If no localized string id is found, the name property of the value will be used instead. + :rtype: Union[int, str] + """ + from sims4communitylib.enums.strings_enum import CommonStringId + mapping = { + CommonSide.LEFT: CommonStringId.S4CL_LEFT, + CommonSide.RIGHT: CommonStringId.S4CL_RIGHT, + CommonSide.FRONT: CommonStringId.S4CL_FRONT, + CommonSide.BACK: CommonStringId.S4CL_BACK, + CommonSide.TOP: CommonStringId.S4CL_TOP, + CommonSide.BOTTOM: CommonStringId.S4CL_BOTTOM, + } + return mapping.get(value, value.name if hasattr(value, 'name') else str(value)) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_sim_demographic_types.py b/Scripts/s4ap/sims4communitylib/enums/common_sim_demographic_types.py new file mode 100644 index 0000000..3e7a4d6 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_sim_demographic_types.py @@ -0,0 +1,172 @@ +""" +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 +""" +from typing import Union, Tuple, Iterator, Dict, Set + +from protocolbuffers.Localization_pb2 import LocalizedString +from sims4communitylib.enums.enumtypes.common_versioned_int_flags import CommonVersionedIntFlags +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.utils.math.common_bitwise_utils import CommonBitwiseUtils + + +class CommonSimDemographicType(CommonVersionedIntFlags): + """ Various demographics of Sims. """ + NONE: 'CommonSimDemographicType' = ... + HOUSEHOLD: 'CommonSimDemographicType' = ... + NON_HOUSEHOLD: 'CommonSimDemographicType' = ... + CURRENTLY_CONTROLLED: 'CommonSimDemographicType' = ... + + # Gender + MALE: 'CommonSimDemographicType' = ... + FEMALE: 'CommonSimDemographicType' = ... + + # Age + BABY: 'CommonSimDemographicType' = ... + INFANT: 'CommonSimDemographicType' = ... + CHILD: 'CommonSimDemographicType' = ... + TODDLER: 'CommonSimDemographicType' = ... + TEEN: 'CommonSimDemographicType' = ... + ADULT: 'CommonSimDemographicType' = ... + YOUNG_ADULT: 'CommonSimDemographicType' = ... + ELDER: 'CommonSimDemographicType' = ... + + # Occult + ALIEN: 'CommonSimDemographicType' = ... + GHOST: 'CommonSimDemographicType' = ... + MERMAID: 'CommonSimDemographicType' = ... + NON_OCCULT: 'CommonSimDemographicType' = ... + PLANT: 'CommonSimDemographicType' = ... + ROBOT: 'CommonSimDemographicType' = ... + SKELETON: 'CommonSimDemographicType' = ... + VAMPIRE: 'CommonSimDemographicType' = ... + WEREWOLF: 'CommonSimDemographicType' = ... + WITCH: 'CommonSimDemographicType' = ... + + # Species + HUMAN: 'CommonSimDemographicType' = ... + SMALL_DOG: 'CommonSimDemographicType' = ... + LARGE_DOG: 'CommonSimDemographicType' = ... + CAT: 'CommonSimDemographicType' = ... + FOX: 'CommonSimDemographicType' = ... + HORSE: 'CommonSimDemographicType' = ... + + # Obsolete + PLAYER_SIMS: 'CommonSimDemographicType' = ... + NPC_SIMS: 'CommonSimDemographicType' = ... + ACTIVE_SIM: 'CommonSimDemographicType' = ... + CONTROLLED: 'CommonSimDemographicType' = ... + + @classmethod + def get_version(cls) -> str: + """The version of the enum. If this changes, it means values have changed and should be updated.""" + return 'v1.2' + + @classmethod + def get_all(cls, exclude_values: Iterator['CommonSimDemographicType'] = None) -> Tuple['CommonSimDemographicType']: + """get_all(exclude_values=None) + + Get a collection of all values. + + :param exclude_values: These values will be excluded. If set to None, NONE will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonTypesOfSims], optional + :return: A collection of all values. + :rtype: Tuple[CommonSimDemographicType] + """ + if exclude_values is None: + exclude_values = (cls.NONE,) + obsolete_values = cls.get_obsolete_values() + # noinspection PyTypeChecker + result: Tuple[CommonSimDemographicType, ...] = tuple([val for val in cls.values if val not in exclude_values and val not in obsolete_values]) + return result + + @classmethod + def get_all_flags(cls, exclude_values: Iterator['CommonSimDemographicType'] = None) -> 'CommonSimDemographicType': + """get_all_flags(exclude_values=None) + + Get a flag containing all values. + + :param exclude_values: These values will be excluded. If set to None, NONE will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonTypesOfSims], optional + :return: A flag containing all values. + :rtype: CommonSimDemographicType + """ + value_flags = CommonSimDemographicType.NONE + for value in cls.get_all(exclude_values=exclude_values): + if value_flags == CommonSimDemographicType.NONE: + value_flags = value + else: + value_flags = CommonBitwiseUtils.add_flags(value_flags, value) + return value_flags + + @staticmethod + def to_display_name(value: 'CommonSimDemographicType') -> Union[int, LocalizedString]: + """Convert a value to a display name.""" + mappings = { + CommonSimDemographicType.HOUSEHOLD: CommonStringId.S4CL_HOUSEHOLD, + CommonSimDemographicType.NON_HOUSEHOLD: CommonStringId.S4CL_NON_HOUSEHOLD, + CommonSimDemographicType.CURRENTLY_CONTROLLED: CommonStringId.S4CL_CURRENTLY_CONTROLLED, + # Gender + CommonSimDemographicType.MALE: CommonStringId.MALE, + CommonSimDemographicType.FEMALE: CommonStringId.FEMALE, + # Age + CommonSimDemographicType.BABY: CommonStringId.BABY, + CommonSimDemographicType.TODDLER: CommonStringId.TODDLER, + CommonSimDemographicType.CHILD: CommonStringId.CHILD, + CommonSimDemographicType.TEEN: CommonStringId.TEEN, + CommonSimDemographicType.ADULT: CommonStringId.ADULT, + CommonSimDemographicType.YOUNG_ADULT: CommonStringId.YOUNG_ADULT, + CommonSimDemographicType.ELDER: CommonStringId.ELDER, + # Occult + CommonSimDemographicType.ALIEN: CommonStringId.S4CL_ALIEN, + CommonSimDemographicType.GHOST: CommonStringId.S4CL_GHOST, + CommonSimDemographicType.MERMAID: CommonStringId.S4CL_MERMAID, + CommonSimDemographicType.NON_OCCULT: CommonStringId.S4CL_NON_OCCULT, + CommonSimDemographicType.PLANT: CommonStringId.S4CL_PLANT_SIM, + CommonSimDemographicType.ROBOT: CommonStringId.S4CL_ROBOT, + CommonSimDemographicType.SKELETON: CommonStringId.S4CL_SKELETON, + CommonSimDemographicType.VAMPIRE: CommonStringId.S4CL_VAMPIRE, + CommonSimDemographicType.WEREWOLF: CommonStringId.S4CL_WEREWOLF, + CommonSimDemographicType.WITCH: CommonStringId.S4CL_WITCH, + # Species + CommonSimDemographicType.HUMAN: CommonStringId.HUMAN, + CommonSimDemographicType.SMALL_DOG: CommonStringId.SMALL_DOG, + CommonSimDemographicType.LARGE_DOG: CommonStringId.LARGE_DOG, + CommonSimDemographicType.CAT: CommonStringId.CAT, + CommonSimDemographicType.FOX: CommonStringId.FOX, + CommonSimDemographicType.HORSE: CommonStringId.HORSE, + } + return mappings.get(value, value.name if hasattr(value, 'name') else str(value)) + + @staticmethod + def to_display_description(value: 'CommonSimDemographicType') -> Union[int, LocalizedString]: + """Convert a value to a display description.""" + mappings = { + CommonSimDemographicType.HOUSEHOLD: CommonStringId.S4CL_HOUSEHOLD_DESCRIPTION, + CommonSimDemographicType.NON_HOUSEHOLD: CommonStringId.S4CL_NON_HOUSEHOLD_DESCRIPTION, + CommonSimDemographicType.CURRENTLY_CONTROLLED: CommonStringId.S4CL_CURRENTLY_CONTROLLED_DESCRIPTION, + } + return mappings.get(value, 0) + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_obsolete_values(cls) -> Set['CommonSimDemographicType']: + return { + CommonSimDemographicType.ACTIVE_SIM, + CommonSimDemographicType.PLAYER_SIMS, + CommonSimDemographicType.NPC_SIMS, + CommonSimDemographicType.CONTROLLED + } + + @classmethod + def _get_obsolete_conversion_mapping(cls) -> Dict['CommonSimDemographicType', 'CommonSimDemographicType']: + mapping: Dict[CommonSimDemographicType, CommonSimDemographicType] = { + CommonSimDemographicType.ACTIVE_SIM: CommonSimDemographicType.CURRENTLY_CONTROLLED, + CommonSimDemographicType.CONTROLLED: CommonSimDemographicType.CURRENTLY_CONTROLLED, + CommonSimDemographicType.NPC_SIMS: CommonSimDemographicType.NON_HOUSEHOLD, + CommonSimDemographicType.PLAYER_SIMS: CommonSimDemographicType.HOUSEHOLD + } + return mapping diff --git a/Scripts/s4ap/sims4communitylib/enums/common_sim_name_type.py b/Scripts/s4ap/sims4communitylib/enums/common_sim_name_type.py new file mode 100644 index 0000000..4a01e18 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_sim_name_type.py @@ -0,0 +1,236 @@ +""" +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 +""" +from typing import Tuple, Iterator + +from sims.sim_spawner_enums import SimNameType +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonSimNameType(CommonInt): + """Types of names.""" + DEFAULT: 'CommonSimNameType' = ... + JAPANESE: 'CommonSimNameType' = ... + MOROCCAN: 'CommonSimNameType' = ... + INDIAN: 'CommonSimNameType' = ... + CAT: 'CommonSimNameType' = ... + DOG: 'CommonSimNameType' = ... + SKELETON: 'CommonSimNameType' = ... + LATIN: 'CommonSimNameType' = ... + ISLANDER: 'CommonSimNameType' = ... + CHINESE: 'CommonSimNameType' = ... + FAMILIAR_DRAGON: 'CommonSimNameType' = ... + FAMILIAR_BUNNERFLY: 'CommonSimNameType' = ... + FAMILIAR_FAIRY: 'CommonSimNameType' = ... + FAMILIAR_FROG: 'CommonSimNameType' = ... + FAMILIAR_OWL: 'CommonSimNameType' = ... + FAMILIAR_PHOENIX: 'CommonSimNameType' = ... + FAMILIAR_RAVEN: 'CommonSimNameType' = ... + FAMILIAR_SKULL: 'CommonSimNameType' = ... + FAMILIAR_VOID_CRITTER: 'CommonSimNameType' = ... + FAMILIAR_VOODOO_DOLL: 'CommonSimNameType' = ... + FAMILIAR_BAT: 'CommonSimNameType' = ... + HUMANOID_ROBOT: 'CommonSimNameType' = ... + HUMANOID_ROBOT_GENERIC: 'CommonSimNameType' = ... + MARKETPLACE_NAME: 'CommonSimNameType' = ... + MARKETPLACE_FASHION_NAME: 'CommonSimNameType' = ... + STAR_WARS_GENERAL: 'CommonSimNameType' = ... + STAR_WARS_FIRST_ORDER: 'CommonSimNameType' = ... + STAR_WARS_STORM_TROOPER: 'CommonSimNameType' = ... + FOX: 'CommonSimNameType' = ... + + @classmethod + def get_all(cls, exclude_values: Iterator['CommonSimNameType'] = None) -> Tuple['CommonSimNameType']: + """get_all(exclude_values=None) + + Get a collection of all values. + + :param exclude_values: These values will be excluded. If set to None, DEFAULT will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonSimNameType], optional + :return: A collection of all values. + :rtype: Tuple[CommonSimNameType] + """ + if exclude_values is None: + exclude_values = (cls.DEFAULT,) + # noinspection PyTypeChecker + value_list: Tuple[CommonSimNameType] = tuple([value for value in cls.values if value not in exclude_values]) + return value_list + + @classmethod + def get_all_names(cls, exclude_values: Iterator['CommonSimNameType'] = None) -> Tuple[str]: + """get_all_names(exclude_values=None) + + Retrieve a collection of the names of all values. + + :param exclude_values: These values will be excluded. If set to None, DEFAULT will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonSimNameType], optional + :return: A collection of the names of all values. + :rtype: Tuple[str] + """ + name_list: Tuple[str] = tuple([value.name for value in cls.get_all(exclude_values=exclude_values)]) + return name_list + + @classmethod + def get_comma_separated_names_string(cls, exclude_values: Iterator['CommonSimNameType'] = None) -> str: + """get_comma_separated_names_string(exclude_values=None) + + Create a string containing all names of all values, separated by a comma. + + :param exclude_values: These values will be excluded. If set to None, DEFAULT will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonSimNameType], optional + :return: A string containing all names of all values, separated by a comma. + :rtype: str + """ + return ', '.join(cls.get_all_names(exclude_values=exclude_values)) + + @classmethod + def convert_to_vanilla(cls, value: 'CommonSimNameType') -> SimNameType: + """convert_to_vanilla(value) + + Convert a value into the vanilla SimNameType enum. + + :param value: An instance of CommonSimNameType. + :type value: CommonSimNameType + :return: The specified value translated to SimNameType or DEFAULT if the value could not be translated. + :rtype: SimNameType + """ + if value is None or value == CommonSimNameType.DEFAULT: + return SimNameType.DEFAULT + if isinstance(value, SimNameType): + return value + mapping = dict() + if hasattr(SimNameType, 'Japanese'): + mapping[CommonSimNameType.JAPANESE] = SimNameType.Japanese + if hasattr(SimNameType, 'Moroccan'): + mapping[CommonSimNameType.MOROCCAN] = SimNameType.Moroccan + if hasattr(SimNameType, 'Indian'): + mapping[CommonSimNameType.INDIAN] = SimNameType.Indian + if hasattr(SimNameType, 'Cat'): + mapping[CommonSimNameType.CAT] = SimNameType.Cat + if hasattr(SimNameType, 'Dog'): + mapping[CommonSimNameType.DOG] = SimNameType.Dog + if hasattr(SimNameType, 'Skeleton'): + mapping[CommonSimNameType.SKELETON] = SimNameType.Skeleton + if hasattr(SimNameType, 'Latin'): + mapping[CommonSimNameType.LATIN] = SimNameType.Latin + if hasattr(SimNameType, 'Islander'): + mapping[CommonSimNameType.ISLANDER] = SimNameType.Islander + if hasattr(SimNameType, 'Chinese'): + mapping[CommonSimNameType.CHINESE] = SimNameType.Chinese + if hasattr(SimNameType, 'FamiliarDragon'): + mapping[CommonSimNameType.FAMILIAR_DRAGON] = SimNameType.FamiliarDragon + if hasattr(SimNameType, 'FamiliarBunnerfly'): + mapping[CommonSimNameType.FAMILIAR_BUNNERFLY] = SimNameType.FamiliarBunnerfly + if hasattr(SimNameType, 'FamiliarFairy'): + mapping[CommonSimNameType.FAMILIAR_FAIRY] = SimNameType.FamiliarFairy + if hasattr(SimNameType, 'FamiliarFrog'): + mapping[CommonSimNameType.FAMILIAR_FROG] = SimNameType.FamiliarFrog + if hasattr(SimNameType, 'FamiliarOwl'): + mapping[CommonSimNameType.FAMILIAR_OWL] = SimNameType.FamiliarOwl + if hasattr(SimNameType, 'FamiliarPhoenix'): + mapping[CommonSimNameType.FAMILIAR_PHOENIX] = SimNameType.FamiliarPhoenix + if hasattr(SimNameType, 'FamiliarRaven'): + mapping[CommonSimNameType.FAMILIAR_RAVEN] = SimNameType.FamiliarRaven + if hasattr(SimNameType, 'FamiliarSkull'): + mapping[CommonSimNameType.FAMILIAR_SKULL] = SimNameType.FamiliarSkull + if hasattr(SimNameType, 'FamiliarVoidcritter'): + mapping[CommonSimNameType.FAMILIAR_VOID_CRITTER] = SimNameType.FamiliarVoidcritter + if hasattr(SimNameType, 'FamiliarVoodooDoll'): + mapping[CommonSimNameType.FAMILIAR_VOODOO_DOLL] = SimNameType.FamiliarVoodooDoll + if hasattr(SimNameType, 'FamiliarBat'): + mapping[CommonSimNameType.FAMILIAR_BAT] = SimNameType.FamiliarBat + if hasattr(SimNameType, 'HumanoidRobot'): + mapping[CommonSimNameType.HUMANOID_ROBOT] = SimNameType.HumanoidRobot + if hasattr(SimNameType, 'HumanoidRobot_Generic'): + mapping[CommonSimNameType.HUMANOID_ROBOT_GENERIC] = SimNameType.HumanoidRobot_Generic + if hasattr(SimNameType, 'Marketplace_Name'): + mapping[CommonSimNameType.MARKETPLACE_NAME] = SimNameType.Marketplace_Name + if hasattr(SimNameType, 'StarWars_General'): + mapping[CommonSimNameType.STAR_WARS_GENERAL] = SimNameType.StarWars_General + if hasattr(SimNameType, 'StarWars_FirstOrder'): + mapping[CommonSimNameType.STAR_WARS_FIRST_ORDER] = SimNameType.StarWars_FirstOrder + if hasattr(SimNameType, 'StarWars_Stormtrooper'): + mapping[CommonSimNameType.STAR_WARS_STORM_TROOPER] = SimNameType.StarWars_Stormtrooper + if hasattr(SimNameType, 'Fox'): + mapping[CommonSimNameType.FOX] = SimNameType.Fox + if hasattr(SimNameType, 'FashionMarketplace_Name'): + mapping[CommonSimNameType.MARKETPLACE_FASHION_NAME] = SimNameType.FashionMarketplace_Name + return mapping.get(value, SimNameType.DEFAULT) + + @classmethod + def convert_from_vanilla(cls, value: SimNameType) -> 'CommonSimNameType': + """convert_from_vanilla(value) + + Convert a vanilla value into a CommonSimNameType enum. + + :param value: An instance of SimNameType. + :type value: SimNameType + :return: The specified value translated to CommonSimNameType or DEFAULT if the value could not be translated. + :rtype: CommonSimNameType + """ + if value is None or value == SimNameType.DEFAULT: + return CommonSimNameType.DEFAULT + if isinstance(value, CommonSimNameType): + return value + mapping = dict() + if hasattr(SimNameType, 'Japanese'): + mapping[SimNameType.Japanese] = CommonSimNameType.JAPANESE + if hasattr(SimNameType, 'Moroccan'): + mapping[SimNameType.Moroccan] = CommonSimNameType.MOROCCAN + if hasattr(SimNameType, 'Indian'): + mapping[SimNameType.Indian] = CommonSimNameType.INDIAN + if hasattr(SimNameType, 'Cat'): + mapping[SimNameType.Cat] = CommonSimNameType.CAT + if hasattr(SimNameType, 'Dog'): + mapping[SimNameType.Dog] = CommonSimNameType.DOG + if hasattr(SimNameType, 'Skeleton'): + mapping[SimNameType.Skeleton] = CommonSimNameType.SKELETON + if hasattr(SimNameType, 'Latin'): + mapping[SimNameType.Latin] = CommonSimNameType.LATIN + if hasattr(SimNameType, 'Islander'): + mapping[SimNameType.Islander] = CommonSimNameType.ISLANDER + if hasattr(SimNameType, 'Chinese'): + mapping[SimNameType.Chinese] = CommonSimNameType.CHINESE + if hasattr(SimNameType, 'FamiliarDragon'): + mapping[SimNameType.FamiliarDragon] = CommonSimNameType.FAMILIAR_DRAGON + if hasattr(SimNameType, 'FamiliarBunnerfly'): + mapping[SimNameType.FamiliarBunnerfly] = CommonSimNameType.FAMILIAR_BUNNERFLY + if hasattr(SimNameType, 'FamiliarFairy'): + mapping[SimNameType.FamiliarFairy] = CommonSimNameType.FAMILIAR_FAIRY + if hasattr(SimNameType, 'FamiliarFrog'): + mapping[SimNameType.FamiliarFrog] = CommonSimNameType.FAMILIAR_FROG + if hasattr(SimNameType, 'FamiliarOwl'): + mapping[SimNameType.FamiliarOwl] = CommonSimNameType.FAMILIAR_OWL + if hasattr(SimNameType, 'FamiliarPhoenix'): + mapping[SimNameType.FamiliarPhoenix] = CommonSimNameType.FAMILIAR_PHOENIX + if hasattr(SimNameType, 'FamiliarRaven'): + mapping[SimNameType.FamiliarRaven] = CommonSimNameType.FAMILIAR_RAVEN + if hasattr(SimNameType, 'FamiliarSkull'): + mapping[SimNameType.FamiliarSkull] = CommonSimNameType.FAMILIAR_SKULL + if hasattr(SimNameType, 'FamiliarVoidcritter'): + mapping[SimNameType.FamiliarVoidcritter] = CommonSimNameType.FAMILIAR_VOID_CRITTER + if hasattr(SimNameType, 'FamiliarVoodooDoll'): + mapping[SimNameType.FamiliarVoodooDoll] = CommonSimNameType.FAMILIAR_VOODOO_DOLL + if hasattr(SimNameType, 'FamiliarBat'): + mapping[SimNameType.FamiliarBat] = CommonSimNameType.FAMILIAR_BAT + if hasattr(SimNameType, 'HumanoidRobot'): + mapping[SimNameType.HumanoidRobot] = CommonSimNameType.HUMANOID_ROBOT + if hasattr(SimNameType, 'HumanoidRobot_Generic'): + mapping[SimNameType.HumanoidRobot_Generic] = CommonSimNameType.HUMANOID_ROBOT_GENERIC + if hasattr(SimNameType, 'Marketplace_Name'): + mapping[SimNameType.Marketplace_Name] = CommonSimNameType.MARKETPLACE_NAME + if hasattr(SimNameType, 'StarWars_General'): + mapping[SimNameType.StarWars_General] = CommonSimNameType.STAR_WARS_GENERAL + if hasattr(SimNameType, 'StarWars_FirstOrder'): + mapping[SimNameType.StarWars_FirstOrder] = CommonSimNameType.STAR_WARS_FIRST_ORDER + if hasattr(SimNameType, 'StarWars_Stormtrooper'): + mapping[SimNameType.StarWars_Stormtrooper] = CommonSimNameType.STAR_WARS_STORM_TROOPER + if hasattr(SimNameType, 'Fox'): + mapping[SimNameType.Fox] = CommonSimNameType.FOX + if hasattr(SimNameType, 'FashionMarketplace_Name'): + mapping[SimNameType.FashionMarketplace_Name] = CommonSimNameType.MARKETPLACE_FASHION_NAME + return mapping.get(value, CommonSimNameType.DEFAULT) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_skill_effectiveness.py b/Scripts/s4ap/sims4communitylib/enums/common_skill_effectiveness.py new file mode 100644 index 0000000..9f102a2 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_skill_effectiveness.py @@ -0,0 +1,107 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt +from statistics.skill import SkillEffectiveness + + +class CommonSkillEffectiveness(CommonInt): + """Various Skill Effectiveness.""" + HUGE: 'CommonSkillEffectiveness' = ... + LARGE: 'CommonSkillEffectiveness' = ... + PERIODIC_LARGE: 'CommonSkillEffectiveness' = ... + PERIODIC_SMALL: 'CommonSkillEffectiveness' = ... + PERIODIC_STANDARD: 'CommonSkillEffectiveness' = ... + PERIODIC_STANDARD_TODDLER: 'CommonSkillEffectiveness' = ... + PERIODIC_TONE: 'CommonSkillEffectiveness' = ... + PERIODIC_VERY_SMALL: 'CommonSkillEffectiveness' = ... + SMALL: 'CommonSkillEffectiveness' = ... + TINY: 'CommonSkillEffectiveness' = ... + TODDLER: 'CommonSkillEffectiveness' = ... + + @staticmethod + def convert_to_vanilla(value: 'CommonSkillEffectiveness') -> SkillEffectiveness: + """convert_to_vanilla(value) + + Convert a value into a vanilla SkillEffectiveness value. + + :param value: An instance of CommonSkillEffectiveness + :type value: CommonSkillEffectiveness + :return: The specified value translated to an SkillEffectiveness or StandardPeriodic if the value could not be translated. + :rtype: SkillEffectiveness + """ + if value is None: + # noinspection PyUnresolvedReferences + return SkillEffectiveness.StandardPeriodic + if isinstance(value, SkillEffectiveness): + return value + mapping = dict() + if hasattr(SkillEffectiveness, 'Small'): + mapping[CommonSkillEffectiveness.SMALL] = SkillEffectiveness.Small + if hasattr(SkillEffectiveness, 'Large'): + mapping[CommonSkillEffectiveness.LARGE] = SkillEffectiveness.Large + if hasattr(SkillEffectiveness, 'SmallPeriodic'): + mapping[CommonSkillEffectiveness.PERIODIC_SMALL] = SkillEffectiveness.SmallPeriodic + if hasattr(SkillEffectiveness, 'StandardPeriodic'): + mapping[CommonSkillEffectiveness.PERIODIC_STANDARD] = SkillEffectiveness.StandardPeriodic + if hasattr(SkillEffectiveness, 'LargePeriodic'): + mapping[CommonSkillEffectiveness.PERIODIC_LARGE] = SkillEffectiveness.LargePeriodic + if hasattr(SkillEffectiveness, 'Tiny'): + mapping[CommonSkillEffectiveness.TINY] = SkillEffectiveness.Tiny + if hasattr(SkillEffectiveness, 'Huge'): + mapping[CommonSkillEffectiveness.HUGE] = SkillEffectiveness.Huge + if hasattr(SkillEffectiveness, 'VerySmallPeriodic'): + mapping[CommonSkillEffectiveness.PERIODIC_VERY_SMALL] = SkillEffectiveness.VerySmallPeriodic + if hasattr(SkillEffectiveness, 'TonePeriodic'): + mapping[CommonSkillEffectiveness.PERIODIC_TONE] = SkillEffectiveness.TonePeriodic + if hasattr(SkillEffectiveness, 'Toddler'): + mapping[CommonSkillEffectiveness.TODDLER] = SkillEffectiveness.Toddler + if hasattr(SkillEffectiveness, 'ToddlerStandardPeriodic'): + mapping[CommonSkillEffectiveness.PERIODIC_STANDARD_TODDLER] = SkillEffectiveness.ToddlerStandardPeriodic + + return mapping.get(value, getattr(SkillEffectiveness, 'StandardPeriodic', None)) + + @staticmethod + def convert_from_vanilla(value: SkillEffectiveness) -> 'CommonSkillEffectiveness': + """convert_from_vanilla(value) + + Convert a vanilla value to a CommonSkillEffectiveness value. + + :param value: An instance of SkillEffectiveness + :type value: SkillEffectiveness + :return: The specified value translated to a CommonSkillEffectiveness or PERIODIC_STANDARD if the value could not be translated. + :rtype: CommonSkillEffectiveness + """ + if value is None: + return CommonSkillEffectiveness.PERIODIC_STANDARD + if isinstance(value, CommonSkillEffectiveness): + return value + mapping = dict() + if hasattr(SkillEffectiveness, 'Small'): + mapping[SkillEffectiveness.Small] = CommonSkillEffectiveness.SMALL + if hasattr(SkillEffectiveness, 'Large'): + mapping[SkillEffectiveness.Large] = CommonSkillEffectiveness.LARGE + if hasattr(SkillEffectiveness, 'SmallPeriodic'): + mapping[SkillEffectiveness.SmallPeriodic] = CommonSkillEffectiveness.PERIODIC_SMALL + if hasattr(SkillEffectiveness, 'StandardPeriodic'): + mapping[SkillEffectiveness.StandardPeriodic] = CommonSkillEffectiveness.PERIODIC_STANDARD + if hasattr(SkillEffectiveness, 'LargePeriodic'): + mapping[SkillEffectiveness.LargePeriodic] = CommonSkillEffectiveness.PERIODIC_LARGE + if hasattr(SkillEffectiveness, 'Tiny'): + mapping[SkillEffectiveness.Tiny] = CommonSkillEffectiveness.TINY + if hasattr(SkillEffectiveness, 'Huge'): + mapping[SkillEffectiveness.Huge] = CommonSkillEffectiveness.HUGE + if hasattr(SkillEffectiveness, 'VerySmallPeriodic'): + mapping[SkillEffectiveness.VerySmallPeriodic] = CommonSkillEffectiveness.PERIODIC_VERY_SMALL + if hasattr(SkillEffectiveness, 'TonePeriodic'): + mapping[SkillEffectiveness.TonePeriodic] = CommonSkillEffectiveness.PERIODIC_TONE + if hasattr(SkillEffectiveness, 'Toddler'): + mapping[SkillEffectiveness.Toddler] = CommonSkillEffectiveness.TODDLER + if hasattr(SkillEffectiveness, 'ToddlerStandardPeriodic'): + mapping[SkillEffectiveness.ToddlerStandardPeriodic] = CommonSkillEffectiveness.PERIODIC_STANDARD_TODDLER + + return mapping.get(value, CommonSkillEffectiveness.PERIODIC_STANDARD) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_slot_type.py b/Scripts/s4ap/sims4communitylib/enums/common_slot_type.py new file mode 100644 index 0000000..a330d3c --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_slot_type.py @@ -0,0 +1,116 @@ +""" +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 +""" + + +class CommonSlotType: + """Slot types for various objects. + + """ + ACTIVITY_TABLE_PAINTING: 'CommonSlotType' = 'ActivityTablePainting' + ANIMATION_SLOT_SIM_INTERACTION: 'CommonSlotType' = 'animationSlot_SimInteraction' + ANIMATION_SLOT_SIT_INDIVIDUAL: 'CommonSlotType' = 'animationSlot_SitIndividual' + ANIMATION_SLOT_SIT_SHARED: 'CommonSlotType' = 'animationSlot_SitShared' + APPLIANCE_EMBEDDED: 'CommonSlotType' = 'ApplianceEmbedded' + APPLIANCE_SURFACE: 'CommonSlotType' = 'ApplianceSurface' + ARCHAEOLOGY_TABLE: 'CommonSlotType' = 'archaeologyTable' + AUTO_PET_FEEDER: 'CommonSlotType' = 'AutoPetFeeder' + BANQUET_TABLE_CENTER_PIECE: 'CommonSlotType' = 'BanquetTableCenterpiece' + BAR_SERVE: 'CommonSlotType' = 'BarServe' + BOOKSHELVES_E: 'CommonSlotType' = 'BookShelves_E' + BOOKSHELVES_W: 'CommonSlotType' = 'BookShelves_W' + BOOTH: 'CommonSlotType' = 'Booth' + BOOTH_CORNER: 'CommonSlotType' = 'BoothCorner' + BULLETIN_BOARD_CURFEW_DRAWING: 'CommonSlotType' = 'bulletinBoardCurfewDrawing' + BULLETIN_BOARD_CURFEW_NOTE: 'CommonSlotType' = 'bulletinBoardCurfewNote' + CAMERA_TRIPOD: 'CommonSlotType' = 'Camera_Tripod' + CAMPFIRE_SIT: 'CommonSlotType' = 'CampfireSit' + CARVING_STATION: 'CommonSlotType' = 'CarvingStation' + CHEF_STATION_FOOD_PLATTER: 'CommonSlotType' = 'ChefStationFoodPlatter' + CHEMISTRY_LAB_SCIENCE: 'CommonSlotType' = 'ChemistryLabScience' + CLONING_MACHINE_CLONE: 'CommonSlotType' = 'CloningMachineClone' + CLONING_MACHINE_SIM: 'CommonSlotType' = 'CloningMachineSim' + CLONING_MACHINE_SOURCE: 'CommonSlotType' = 'CloningMachineSource' + COLLECTION_SKULL_DISPLAY: 'CommonSlotType' = 'Collection_Skull_Display' + COLLECT_MONSTER_BATTLE_CARD: 'CommonSlotType' = 'collectMonsterBattleCard' + CRAFT_ROBOTICS: 'CommonSlotType' = 'CraftRobotics' + CUPCAKE_MACHINE_SERVE: 'CommonSlotType' = 'CupcakeMachineServe' + CURTAIN: 'CommonSlotType' = 'Curtain' + DRINK_DECANTER: 'CommonSlotType' = 'DrinkDecanter' + DRINK_TRAY_SERVE: 'CommonSlotType' = 'DrinkTrayServe' + EASEL_PAINT: 'CommonSlotType' = 'EaselPaint' + ESPRESSO_BAR_BREW: 'CommonSlotType' = 'espressoBarBrew' + ESPRESSO_BAR_GRIND: 'CommonSlotType' = 'espressoBarGrind' + ESPRESSO_MACHINE_CUP: 'CommonSlotType' = 'EspressoMachineCup' + FENCE_DECO: 'CommonSlotType' = 'FenceDeco' + FENCE_RAIL_SIDE_DECO: 'CommonSlotType' = 'FenceRailSideDeco' + FLOOR_MURAL_PAINT: 'CommonSlotType' = 'FloorMuralPaint' + FLOWER_ARRANGEMENT: 'CommonSlotType' = 'FlowerArrangement' + GAMEPLAY_SLOT_DECO_LARGE: 'CommonSlotType' = '_gameplaySlot_Deco_Large' + GAMEPLAY_SLOT_DECO_MEDIUM: 'CommonSlotType' = '_gameplaySlot_Deco_Medium' + GAMEPLAY_SLOT_DECO_SMALL: 'CommonSlotType' = '_gameplaySlot_Deco_Small' + GARAGE_MURAL_PAINT: 'CommonSlotType' = 'GarageMuralPaint' + GLOBE_BAR_DECANTER: 'CommonSlotType' = 'GlobeBar_Decanter' + GRILL_COOK: 'CommonSlotType' = 'GrillCook' + HOLIDAY_TREE_DECORATION_GARLAND: 'CommonSlotType' = 'HolidayTree_Decoration_Garland' + HOLIDAY_TREE_DECORATION_ORNAMENT: 'CommonSlotType' = 'HolidayTree_Decoration_Ornament' + HOLIDAY_TREE_DECORATION_SKIRT: 'CommonSlotType' = 'HolidayTree_Decoration_Skirt' + HOLIDAY_TREE_DECORATION_TOPPER: 'CommonSlotType' = 'HolidayTree_Decoration_Topper' + HOLIDAY_TREE_PRESENT_PILE: 'CommonSlotType' = 'HolidayTree_PresentPile' + HUMANOID_BOT: 'CommonSlotType' = 'humanoidBot' + INVENTION_CONSTRUCTOR_SCIENCE: 'CommonSlotType' = 'InventionConstructorScience' + JUICE_KEG_CUP: 'CommonSlotType' = 'JuiceKegCup' + LAUNDRY_WASHING_MACHINE: 'CommonSlotType' = 'Laundry_WashingMachine' + MAGIC_WAND_DISPLAY: 'CommonSlotType' = 'MagicWandDisplay' + MECH_SUIT_HEAD: 'CommonSlotType' = 'MechSuitHead' + MICROWAVE_COOK: 'CommonSlotType' = 'MicrowaveCook' + MONSTER_BATTLE_SCREEN: 'CommonSlotType' = 'monsterBattleScreen' + NIGHTSTAND: 'CommonSlotType' = 'Nightstand' + OBJECT_SURFACE_2_X_1: 'CommonSlotType' = '2x1ObjectSurface' + OFFERING: 'CommonSlotType' = 'Offering' + OVEN_COOK: 'CommonSlotType' = 'OvenCook' + PARTY_BOT: 'CommonSlotType' = 'PartyBot' + PEDESTAL_STATUE: 'CommonSlotType' = 'PedestalStatue' + PHOTO_COLLAGE_FRAME_LANDSCAPE_MED: 'CommonSlotType' = 'PhotoCollageFrame_Landscape_Med' + PHOTO_COLLAGE_FRAME_LANDSCAPE_SMALL: 'CommonSlotType' = 'PhotoCollageFrame_Landscape_Small' + PHOTO_COLLAGE_FRAME_PORTRAIT_MED: 'CommonSlotType' = 'PhotoCollageFrame_Portrait_Med' + PHOTO_COLLAGE_FRAME_PORTRAIT_SMALL: 'CommonSlotType' = 'PhotoCollageFrame_Portrait_Small' + PING_PONG_CUP: 'CommonSlotType' = 'PingPongCup' + PLACEMAT_DRAWING: 'CommonSlotType' = 'PlacematDrawing' + PLANT_COW: 'CommonSlotType' = 'PlantCow' + PLANT_LARGE: 'CommonSlotType' = 'PlantLarge' + PLANT_SIMS_MAGIC_BEANS: 'CommonSlotType' = 'PlantSims_MagicBeans' + PLANT_SMALL: 'CommonSlotType' = 'PlantSmall' + POSTCARD_BOARD_COLLECT: 'CommonSlotType' = 'PostcardBoardCollect' + RESTAURANT_SIGN_DECAL_4_X_1_X_2: 'CommonSlotType' = 'RestaurantSignDecal4x1x2' + RESTAURANT_SIGN_DECAL: 'CommonSlotType' = 'RestaurantSignDecal' + RESTAURANT_SIGN_DECAL_LARGE: 'CommonSlotType' = 'RestaurantSignDecalLarge' + RETAIL_FOOD_DISPLAY_SHOW: 'CommonSlotType' = 'RetailFoodDisplayShow' + ROBOT_VACUUM: 'CommonSlotType' = 'RobotVacuum' + ROLLUP_MURAL_PAINT: 'CommonSlotType' = 'RollupMuralPaint' + SIT_CHAIR: 'CommonSlotType' = 'SitChair' + SIT_CHAIR_LARGE: 'CommonSlotType' = 'SitChairLrg' + SIT_CHAIR_TALL: 'CommonSlotType' = 'SitChairTall' + SIT_DRINK: 'CommonSlotType' = 'SitDrink' + SIT_EAT: 'CommonSlotType' = 'SitEat' + SIT_INDIVIDUAL: 'CommonSlotType' = 'SitIndividual' + SIT_SHARED: 'CommonSlotType' = 'SitShared' + SPAWN_POINT: 'CommonSlotType' = 'SpawnPoint' + STAGE: 'CommonSlotType' = 'Stage' + STAND_INDIVIDUAL: 'CommonSlotType' = 'StandIndividual' + STAND_SHARED: 'CommonSlotType' = 'StandShared' + STAR_TILE: 'CommonSlotType' = 'starTile' + STOVE_COOK: 'CommonSlotType' = 'StoveCook' + STYLEBOARD: 'CommonSlotType' = 'Styleboard' + SURGERY_TABLE_BASSINET: 'CommonSlotType' = 'SurgeryTable_Bassinet' + TABLE_GAME_INDIVIDUAL: 'CommonSlotType' = 'TableGameIndividual' + TABLE_GAME_SHARED: 'CommonSlotType' = 'TableGameShared' + TODDLER_SIPPY_CUP: 'CommonSlotType' = 'ToddlerSippyCup' + TV_STAND_TV: 'CommonSlotType' = 'TvStandTV' + VIDEO_STATION: 'CommonSlotType' = 'VideoStation' + WALL_MURAL_PAINT: 'CommonSlotType' = 'WallMuralPaint' + WOODWORK_IN_PROGRESS: 'CommonSlotType' = 'WoodworkInProgress' diff --git a/Scripts/s4ap/sims4communitylib/enums/common_species.py b/Scripts/s4ap/sims4communitylib/enums/common_species.py new file mode 100644 index 0000000..f101809 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_species.py @@ -0,0 +1,189 @@ +""" +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 +""" +from typing import Union, Tuple, Iterator + +from sims.sim_info import SimInfo +from sims.sim_info_types import Species, SpeciesExtended +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonSpecies(CommonInt): + """Custom Species enum containing all species (including extended species). + + """ + INVALID: 'CommonSpecies' = ... + HUMAN: 'CommonSpecies' = ... + SMALL_DOG: 'CommonSpecies' = ... + LARGE_DOG: 'CommonSpecies' = ... + CAT: 'CommonSpecies' = ... + FOX: 'CommonSpecies' = ... + HORSE: 'CommonSpecies' = ... + + @classmethod + def get_all(cls, exclude_values: Iterator['CommonSpecies'] = None) -> Tuple['CommonSpecies']: + """get_all(exclude_values=None) + + Get a collection of all values. + + :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonSpecies], optional + :return: A collection of all values. + :rtype: Tuple[CommonSpecies] + """ + if exclude_values is None: + exclude_values = (cls.INVALID,) + # noinspection PyTypeChecker + value_list: Tuple[CommonSpecies, ...] = tuple([value for value in cls.values if value not in exclude_values]) + return value_list + + @classmethod + def get_all_names(cls, exclude_values: Iterator['CommonSpecies'] = None) -> Tuple[str]: + """get_all_names(exclude_values=None) + + Retrieve a collection of the names of all values. + + :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonSpecies], optional + :return: A collection of the names of all values. + :rtype: Tuple[str] + """ + name_list: Tuple[str] = tuple([value.name for value in cls.get_all(exclude_values=exclude_values)]) + return name_list + + @classmethod + def get_comma_separated_names_string(cls, exclude_values: Iterator['CommonSpecies'] = None) -> str: + """get_comma_separated_names_string(exclude_values=None) + + Create a string containing all names of all values, separated by a comma. + + :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonSpecies], optional + :return: A string containing all names of all values, separated by a comma. + :rtype: str + """ + return ', '.join(cls.get_all_names(exclude_values=exclude_values)) + + @staticmethod + def get_species(sim_info: SimInfo) -> 'CommonSpecies': + """get_species(sim_info) + + Retrieve the CommonSpecies of a sim. Use this instead of CommonSpeciesUtils.get_species to determine a more specific species. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: A species matching the Sim or INVALID if no matching species is found. + :rtype: CommonSpecies + """ + from sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils + if CommonSpeciesUtils.is_human(sim_info): + return CommonSpecies.HUMAN + elif CommonSpeciesUtils.is_fox(sim_info): + return CommonSpecies.FOX + elif CommonSpeciesUtils.is_small_dog(sim_info): + return CommonSpecies.SMALL_DOG + elif CommonSpeciesUtils.is_large_dog(sim_info): + return CommonSpecies.LARGE_DOG + elif CommonSpeciesUtils.is_cat(sim_info): + return CommonSpecies.CAT + elif CommonSpeciesUtils.is_horse(sim_info): + return CommonSpecies.HORSE + return CommonSpecies.INVALID + + @staticmethod + def convert_to_vanilla(value: 'CommonSpecies') -> Union[SpeciesExtended, None]: + """convert_to_vanilla(value) + + Convert a value into the vanilla SpeciesExtended enum. + + :param value: An instance of CommonSpecies + :type value: CommonSpecies + :return: The specified value translated to SpeciesExtended or INVALID if the value could not be translated. + :rtype: Union[SpeciesExtended, None] + """ + if value is None or value == CommonSpecies.INVALID: + return None + if isinstance(value, SpeciesExtended) or isinstance(value, Species): + # noinspection PyTypeChecker + return value + mapping = { + CommonSpecies.HUMAN: SpeciesExtended.HUMAN, + } + if hasattr(SpeciesExtended, 'SMALLDOG'): + mapping[CommonSpecies.SMALL_DOG] = SpeciesExtended.SMALLDOG + if hasattr(SpeciesExtended, 'DOG'): + mapping[CommonSpecies.LARGE_DOG] = SpeciesExtended.DOG + if hasattr(SpeciesExtended, 'CAT'): + mapping[CommonSpecies.CAT] = SpeciesExtended.CAT + if hasattr(SpeciesExtended, 'FOX'): + mapping[CommonSpecies.FOX] = SpeciesExtended.FOX + if hasattr(SpeciesExtended, 'HORSE'): + mapping[CommonSpecies.HORSE] = SpeciesExtended.HORSE + return mapping.get(value, None) + + @staticmethod + def convert_from_vanilla(value: SpeciesExtended) -> 'CommonSpecies': + """convert_from_vanilla(value) + + Convert a value into a CommonSpecies enum. + + :param value: An instance of SpeciesExtended + :type value: SpeciesExtended + :return: The specified value translated to CommonSpecies or INVALID if the value could not be translated. + :rtype: CommonSpecies + """ + if value is None or value == CommonSpecies.INVALID: + return SpeciesExtended.INVALID + if isinstance(value, CommonSpecies): + # noinspection PyTypeChecker + return value + mapping = { + Species.HUMAN: CommonSpecies.HUMAN, + } + if hasattr(SpeciesExtended, 'SMALLDOG'): + mapping[SpeciesExtended.SMALLDOG] = CommonSpecies.SMALL_DOG + if hasattr(Species, 'DOG'): + mapping[Species.DOG] = CommonSpecies.LARGE_DOG + if hasattr(Species, 'CAT'): + mapping[Species.CAT] = CommonSpecies.CAT + if hasattr(Species, 'FOX'): + mapping[Species.FOX] = CommonSpecies.FOX + if hasattr(Species, 'HORSE'): + mapping[Species.HORSE] = CommonSpecies.HORSE + return mapping.get(value, CommonSpecies.INVALID) + + @staticmethod + def convert_to_localized_string_id(value: 'CommonSpecies') -> Union[int, str]: + """convert_to_localized_string_id(value) + + Convert a value into a Localized String identifier. + + :param value: An instance of a CommonSpecies + :type value: CommonSpecies + :return: The specified value translated to a localized string identifier. If no localized string id is found, the name property of the value will be used instead. + :rtype: Union[int, str] + """ + from sims4communitylib.enums.strings_enum import CommonStringId + display_name_mapping = { + CommonSpecies.HUMAN: CommonStringId.HUMAN, + CommonSpecies.LARGE_DOG: CommonStringId.LARGE_DOG, + CommonSpecies.SMALL_DOG: CommonStringId.SMALL_DOG, + CommonSpecies.CAT: CommonStringId.CAT, + CommonSpecies.FOX: CommonStringId.FOX, + CommonSpecies.HORSE: CommonStringId.HORSE, + } + if isinstance(value, int) and not isinstance(value, CommonSpecies): + from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + # noinspection PyTypeChecker + converted_value = CommonResourceUtils.get_enum_by_int_value(value, SpeciesExtended, default_value=None) + if converted_value is None: + return str(value) + value = CommonSpecies.convert_from_vanilla(converted_value) + if not isinstance(value, CommonSpecies): + # noinspection PyTypeChecker + value = CommonSpecies.convert_from_vanilla(value) + return display_name_mapping.get(value, value.name if hasattr(value, 'name') else str(value)) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_statistic_category.py b/Scripts/s4ap/sims4communitylib/enums/common_statistic_category.py new file mode 100644 index 0000000..6b47d73 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_statistic_category.py @@ -0,0 +1,75 @@ +""" +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 +""" +from typing import Union + +from sims4communitylib.enums.enumtypes.common_int import CommonInt +from sims4communitylib.utils.common_resource_utils import CommonResourceUtils +from statistics.statistic_categories import StatisticCategory + + +def _get_statistic_category(name: str) -> Union[StatisticCategory, int]: + return CommonResourceUtils.get_enum_by_name(name, StatisticCategory, default_value=StatisticCategory.INVALID) + + +class CommonStatisticCategory(CommonInt): + """Custom Statistic Category equivalent to the DynamicEnum statistics.statistic_categories.StatisticCategory + + """ + INVALID: 'CommonStatisticCategory' = _get_statistic_category('INVALID') + + ANGRY_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Angry_Buffs') + ASLEEP_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Asleep_Buffs') + BAD_FOOD_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('BadFood_Buffs') + BORED_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Bored_Buffs') + CHEF_COOK_STYLE_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('ChefCookStyle_Buffs') + CHILDHOOD_PHASE_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('ChildhoodPhase_Buffs') + CLOTHING_OPTIONAL_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('ClothingOptional_Buffs') + CONFIDENT_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Confident_Buffs') + EMBARRASSED_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Embarrassed_Buffs') + ENERGIZED_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Energized_Buffs') + FINE_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Fine_Buffs') + FLIRTY_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Flirty_Buffs') + FOCUSED_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Focused_Buffs') + GAMES_COM_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Gamescom_Buffs') + GROUNDED_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Grounded_Buffs') + HACKING_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Hacking_Buffs') + HAPPY_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Happy_Buffs') + INJURY_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Injury_Buffs') + INSPIRED_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Inspired_Buffs') + ITCHY_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Itchy_Buffs') + MIND_CONTROL_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('MindControl_Buffs') + MIND_POWERS_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('MindPowers_Buffs') + MODULE_TUNABLES: 'CommonStatisticCategory' = _get_statistic_category('MODULE_TUNABLES') + MOTIVE_COMMODITIES: 'CommonStatisticCategory' = _get_statistic_category('Motive_Commodities') + OBJECT_BED_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Object_Bed_Buffs') + OBJECT_BOOK_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Object_Book_Buffs') + OBJECT_JUNGLE_GYM_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Object_JungleGym_Buffs') + OBJECT_MICROSCOPE_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Object_Microscope_Buffs') + OBJECT_MIRROR_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Object_Mirror_Buffs') + OBJECT_MOTION_GAMING_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Object_MotionGaming_Buffs') + OBJECT_OBSERVATORY_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Object_Observatory_Buffs') + OBJECT_STEREO_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Object_Stereo_Buffs') + OBJECT_TOY_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Object_Toy_Buffs') + OBJECT_TV_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Object_TV_Buffs') + PET_SICKNESS_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('PetSickness_Buffs') + PLAYFUL_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Playful_Buffs') + PRANK_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Prank_Buffs') + PRANK_COOLDOWN_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('PrankCooldown_Buffs') + SAD_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Sad_Buffs') + SCARED_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Scared_Buffs') + SICKNESS_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Sickness_Buffs') + SLOSHED_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Sloshed_Buffs') + SOCIAL_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Social_Buffs') + STRESSED_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Stressed_Buffs') + SURVEY_COOLDOWN_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('SurveyCooldown_Buffs') + TEEN_MOOD_SWING_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('TeenMoodSwing_Buffs') + TEMPLE_FUN_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Temple_Fun_Buffs') + UNCOMFORTABLE_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Uncomfortable_Buffs') + UNIVERSITY_STUDYING_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('University_Studying_Buffs') + VAMPIRE_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Vampire_Buffs') + WILDLIFE_ENCOUNTER_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('WildlifeEncounter_Buffs') diff --git a/Scripts/s4ap/sims4communitylib/enums/common_street_civic_policy_ids.py b/Scripts/s4ap/sims4communitylib/enums/common_street_civic_policy_ids.py new file mode 100644 index 0000000..7d8b174 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_street_civic_policy_ids.py @@ -0,0 +1,37 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonStreetCivicPolicyId(CommonInt): + """ Identifiers of Street Civic Policies. """ + GENERAL_ECO_FRIENDLY_APPLIANCES: 'CommonStreetCivicPolicyId' = 232589 + GENERAL_SHUT_OFF_DAY_POWER: 'CommonStreetCivicPolicyId' = 233562 + GENERAL_SHUT_OFF_DAY_WATER: 'CommonStreetCivicPolicyId' = 233563 + GENERAL_COMMUNAL_OWNERSHIP: 'CommonStreetCivicPolicyId' = 237915 + GENERAL_BAG_NEIGHBORHOOD: 'CommonStreetCivicPolicyId' = 237916 + OBJECT_BASED_UPCYCLING_INITIATIVE: 'CommonStreetCivicPolicyId' = 226333 + OBJECT_BASED_UTILITY_PRODUCTION: 'CommonStreetCivicPolicyId' = 233559 + OBJECT_BASED_GREEN_GARDENING: 'CommonStreetCivicPolicyId' = 233560 + SKILL_BASED_OLD_DAYS: 'CommonStreetCivicPolicyId' = 237848 + SKILL_BASED_FREE_LOVE: 'CommonStreetCivicPolicyId' = 237846 + SKILL_BASED_AGGRESSION: 'CommonStreetCivicPolicyId' = 237847 + SKILL_BASED_SELF_CARE: 'CommonStreetCivicPolicyId' = 231968 + SKILL_BASED_JUICED_COMMUNITY: 'CommonStreetCivicPolicyId' = 231969 + SKILL_BASED_HOME_COOKING: 'CommonStreetCivicPolicyId' = 231970 + SKILL_BASED_TECHNOLOGICAL_PROGRESS: 'CommonStreetCivicPolicyId' = 231971 + SKILL_BASED_CREATIVE_ARTS: 'CommonStreetCivicPolicyId' = 231972 + SKILL_BASED_FUN_COMMUNITY: 'CommonStreetCivicPolicyId' = 231973 + SKILL_BASED_MUSIC_ARTS: 'CommonStreetCivicPolicyId' = 231974 + SKILL_BASED_SELF_SUFFICIENT: 'CommonStreetCivicPolicyId' = 231975 + NEIGHBORHOOD_RENOVATION_MODERN_POLICY_INNER_CITY: 'CommonStreetCivicPolicyId' = 233188 + NEIGHBORHOOD_RENOVATION_MODERN_POLICY_INDUSTRIAL: 'CommonStreetCivicPolicyId' = 233189 + NEIGHBORHOOD_RENOVATION_MODERN_POLICY_SUBURBAN: 'CommonStreetCivicPolicyId' = 233190 + NEIGHBORHOOD_RENOVATION_GREEN_POLICY_SUBURBAN: 'CommonStreetCivicPolicyId' = 233193 + NEIGHBORHOOD_RENOVATION_GREEN_POLICY_INDUSTRIAL: 'CommonStreetCivicPolicyId' = 233194 + NEIGHBORHOOD_RENOVATION_GREEN_POLICY_INNER_CITY: 'CommonStreetCivicPolicyId' = 233195 diff --git a/Scripts/s4ap/sims4communitylib/enums/common_temperature.py b/Scripts/s4ap/sims4communitylib/enums/common_temperature.py new file mode 100644 index 0000000..cf21d03 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_temperature.py @@ -0,0 +1,98 @@ +""" +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 +""" +from typing import Tuple, Union, Iterator + +from sims4communitylib.enums.enumtypes.common_int import CommonInt + +# noinspection PyBroadException +try: + from weather.weather_enums import Temperature +except: + class Temperature(CommonInt): + """Mock class.""" + FREEZING = -3 + COLD = -2 + COOL = -1 + WARM = 0 + HOT = 1 + BURNING = 2 + + +class CommonTemperature(CommonInt): + """Identifiers for temperatures.""" + FREEZING: 'CommonTemperature' = ... + COLD: 'CommonTemperature' = ... + COOL: 'CommonTemperature' = ... + WARM: 'CommonTemperature' = ... + HOT: 'CommonTemperature' = ... + BURNING: 'CommonTemperature' = ... + + @classmethod + def get_all(cls, exclude_values: Iterator['CommonTemperature'] = ()) -> Tuple['CommonTemperature']: + """get_all(exclude_values=()) + + Get a collection of all values. + + :param exclude_values: These values will be excluded. Default is an empty collection. + :type exclude_values: Iterator[CommonTemperature], optional + :return: A collection of all values. + :rtype: Tuple[CommonTemperature] + """ + # noinspection PyTypeChecker + value_list: Tuple[CommonTemperature, ...] = tuple([value for value in cls.values if value not in exclude_values]) + return value_list + + @staticmethod + def convert_to_vanilla(value: 'CommonTemperature') -> Union[Temperature, None]: + """convert_to_vanilla(value) + + Convert a value into Temperature. + + :param value: An instance of CommonTemperature + :type value: CommonTemperature + :return: The specified value translated to Temperature, or None if the value could not be translated. + :rtype: Union[Temperature, None] + """ + if value is None: + return None + if isinstance(value, Temperature): + return value + mapping = { + CommonTemperature.FREEZING: Temperature.FREEZING, + CommonTemperature.COLD: Temperature.COLD, + CommonTemperature.COOL: Temperature.COOL, + CommonTemperature.WARM: Temperature.WARM, + CommonTemperature.HOT: Temperature.HOT, + CommonTemperature.BURNING: Temperature.BURNING, + } + return mapping.get(value, None) + + @staticmethod + def convert_from_vanilla(value: Temperature) -> Union['CommonTemperature', None]: + """convert_from_vanilla(value) + + Convert a value into CommonTemperature. + + :param value: An instance of Temperature + :type value: Temperature + :return: The specified value translated to CommonTemperature, or None if the value could not be translated. + :rtype: Union[CommonTemperature, None] + """ + if value is None: + return None + if isinstance(value, CommonTemperature): + return value + mapping = { + Temperature.FREEZING: CommonTemperature.FREEZING, + Temperature.COLD: CommonTemperature.COLD, + Temperature.COOL: CommonTemperature.COOL, + Temperature.WARM: CommonTemperature.WARM, + Temperature.HOT: CommonTemperature.HOT, + Temperature.BURNING: CommonTemperature.BURNING, + } + return mapping.get(value, None) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_venue_civic_policy_ids.py b/Scripts/s4ap/sims4communitylib/enums/common_venue_civic_policy_ids.py new file mode 100644 index 0000000..dffeba5 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_venue_civic_policy_ids.py @@ -0,0 +1,16 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonVenueCivicPolicyId(CommonInt): + """ Identifiers of Venue Civic Policies. """ + COMMUNITY_LOT_DEFAULT: 'CommonVenueCivicPolicyId' = 228300 + COMMUNITY_LOT_GARDEN: 'CommonVenueCivicPolicyId' = 228267 + COMMUNITY_LOT_MAKER_SPACE: 'CommonVenueCivicPolicyId' = 231467 + COMMUNITY_LOT_MARKET: 'CommonVenueCivicPolicyId' = 228268 diff --git a/Scripts/s4ap/sims4communitylib/enums/common_voice_actor_type.py b/Scripts/s4ap/sims4communitylib/enums/common_voice_actor_type.py new file mode 100644 index 0000000..c9b7299 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_voice_actor_type.py @@ -0,0 +1,102 @@ +""" +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 +""" +from typing import Tuple, Iterator + +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonVoiceActorType(CommonInt): + """Various Voice Actor types.""" + UNKNOWN: 'CommonVoiceActorType' = 0 + MUTE: 'CommonVoiceActorType' = 1 + + # Special + KYLO_REN_1: 'CommonVoiceActorType' = 1719082469 + HONDO_OHNAKA_1: 'CommonVoiceActorType' = 1769415226 + REY_1: 'CommonVoiceActorType' = 1601639154 + + # Human + TODDLER_HUMAN_AMBIGUOUS_1: 'CommonVoiceActorType' = 1635194332 + + INFANT_HUMAN_AMBIGUOUS_1: 'CommonVoiceActorType' = 1752637603 + + CHILD_HUMAN_AMBIGUOUS_1: 'CommonVoiceActorType' = 1853303381 + CHILD_HUMAN_AMBIGUOUS_2: 'CommonVoiceActorType' = 1853303382 + + ADULT_HUMAN_AMBIGUOUS_1: 'CommonVoiceActorType' = 1802970399 + + ADULT_HUMAN_FEMININE_1: 'CommonVoiceActorType' = 1802970392 + ADULT_HUMAN_FEMININE_2: 'CommonVoiceActorType' = 1802970394 + + ADULT_HUMAN_MASCULINE_1: 'CommonVoiceActorType' = 1685527060 + ADULT_HUMAN_MASCULINE_2: 'CommonVoiceActorType' = 1685527061 + ADULT_HUMAN_MASCULINE_3: 'CommonVoiceActorType' = 1685527063 + + # Dog + CHILD_DOG_AMBIGUOUS_1: 'CommonVoiceActorType' = 1786192777 + + ADULT_DOG_AMBIGUOUS_1: 'CommonVoiceActorType' = 1836525760 + ADULT_DOG_AMBIGUOUS_2: 'CommonVoiceActorType' = 1836525762 + ADULT_DOG_AMBIGUOUS_3: 'CommonVoiceActorType' = 1836525763 + ADULT_DOG_AMBIGUOUS_4: 'CommonVoiceActorType' = 1836525765 + + # Cat + CHILD_CAT_AMBIGUOUS_1: 'CommonVoiceActorType' = 1719082493 + ADULT_CAT_AMBIGUOUS_1: 'CommonVoiceActorType' = 1702304872 + ADULT_CAT_AMBIGUOUS_2: 'CommonVoiceActorType' = 1702304875 + + # Fox + ADULT_FOX_AMBIGUOUS_1: 'CommonVoiceActorType' = 1886858530 + + # Horse + ADULT_HORSE_AMBIGUOUS_1: 'CommonVoiceActorType' = 1886858546 + CHILD_HORSE_AMBIGUOUS_1: 'CommonVoiceActorType' = 1853303388 + + @classmethod + def get_all(cls, exclude_values: Iterator['CommonVoiceActorType'] = None) -> Tuple['CommonVoiceActorType']: + """get_all(exclude_values=None) + + Get a collection of all values. + + :param exclude_values: These values will be excluded. If set to None, UNKNOWN will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonVoiceActorType], optional + :return: A collection of all values. + :rtype: Tuple[CommonVoiceActorType] + """ + if exclude_values is None: + exclude_values = (cls.UNKNOWN,) + # noinspection PyTypeChecker + value_list: Tuple[CommonVoiceActorType] = tuple([value for value in cls.values if value not in exclude_values]) + return value_list + + @classmethod + def get_all_names(cls, exclude_values: Iterator['CommonVoiceActorType'] = None) -> Tuple[str]: + """get_all_names(exclude_values=None) + + Retrieve a collection of the names of all values. + + :param exclude_values: These values will be excluded. If set to None, UNKNOWN will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonVoiceActorType], optional + :return: A collection of the names of all values. + :rtype: Tuple[str] + """ + name_list: Tuple[str] = tuple([value.name for value in cls.get_all(exclude_values=exclude_values)]) + return name_list + + @classmethod + def get_comma_separated_names_string(cls, exclude_values: Iterator['CommonVoiceActorType'] = None) -> str: + """get_comma_separated_names_string(exclude_values=None) + + Create a string containing all names of all values, separated by a comma. + + :param exclude_values: These values will be excluded. If set to None, UNKNOWN will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonVoiceActorType], optional + :return: A string containing all names of all values, separated by a comma. + :rtype: str + """ + return ', '.join(cls.get_all_names(exclude_values=exclude_values)) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_weather_effect_type.py b/Scripts/s4ap/sims4communitylib/enums/common_weather_effect_type.py new file mode 100644 index 0000000..c2e4ad5 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_weather_effect_type.py @@ -0,0 +1,124 @@ +""" +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 +""" +from typing import Tuple, Union, Iterator + +from sims4communitylib.enums.enumtypes.common_int import CommonInt + +# noinspection PyBroadException +try: + from weather.weather_enums import WeatherEffectType +except: + class WeatherEffectType(CommonInt): + """Mock class.""" + WINDOW_FROST = 1004 + WATER_FROZEN = 1005 + WIND = 1006 + TEMPERATURE = 1007 + THUNDER = 1008 + LIGHTNING = 1009 + SNOW_FRESHNESS = 1010 + STRANGERVILLE_ACT = 1011 + ECO_FOOTPRINT = 1012 + ACID_RAIN = 1013 + # noinspection SpellCheckingInspection + STARWARS_RESISTANCE = 1014 + # noinspection SpellCheckingInspection + STARWARS_FIRST_ORDER = 1015 + SNOW_ICINESS = 1016 + + +class CommonWeatherEffectType(CommonInt): + """Identifiers for weather effects types.""" + WINDOW_FROST: 'CommonWeatherEffectType' = ... + WATER_FROZEN: 'CommonWeatherEffectType' = ... + WIND: 'CommonWeatherEffectType' = ... + TEMPERATURE: 'CommonWeatherEffectType' = ... + THUNDER: 'CommonWeatherEffectType' = ... + LIGHTNING: 'CommonWeatherEffectType' = ... + SNOW_FRESHNESS: 'CommonWeatherEffectType' = ... + STRANGERVILLE_ACT: 'CommonWeatherEffectType' = ... + ECO_FOOTPRINT: 'CommonWeatherEffectType' = ... + ACID_RAIN: 'CommonWeatherEffectType' = ... + STAR_WARS_RESISTANCE: 'CommonWeatherEffectType' = ... + STAR_WARS_FIRST_ORDER: 'CommonWeatherEffectType' = ... + SNOW_ICINESS: 'CommonWeatherEffectType' = ... + + @classmethod + def get_all(cls, exclude_values: Iterator['CommonWeatherEffectType'] = ()) -> Tuple['CommonWeatherEffectType']: + """get_all(exclude_values=()) + + Get a collection of all values. + + :param exclude_values: These values will be excluded. Default is an empty collection. + :type exclude_values: Iterator[CommonWeatherEffectType], optional + :return: A collection of all values. + :rtype: Tuple[CommonWeatherEffectType] + """ + # noinspection PyTypeChecker + value_list: Tuple[CommonWeatherEffectType, ...] = tuple([value for value in cls.values if value not in exclude_values]) + return value_list + + @staticmethod + def convert_to_vanilla(value: 'CommonWeatherEffectType') -> Union[WeatherEffectType, None]: + """convert_to_vanilla(value) + + Convert a CommonWeatherEffectType into WeatherEffectType. + + :param value: An instance of CommonWeatherEffectType + :type value: CommonWeatherEffectType + :return: The specified CommonWeatherEffectType translated to WeatherEffectType, or None if the value could not be translated. + :rtype: Union[WeatherEffectType, None] + """ + if isinstance(value, WeatherEffectType): + return value + mapping = { + CommonWeatherEffectType.WINDOW_FROST: WeatherEffectType.WINDOW_FROST, + CommonWeatherEffectType.WATER_FROZEN: WeatherEffectType.WATER_FROZEN, + CommonWeatherEffectType.WIND: WeatherEffectType.WIND, + CommonWeatherEffectType.TEMPERATURE: WeatherEffectType.TEMPERATURE, + CommonWeatherEffectType.THUNDER: WeatherEffectType.THUNDER, + CommonWeatherEffectType.LIGHTNING: WeatherEffectType.LIGHTNING, + CommonWeatherEffectType.SNOW_FRESHNESS: WeatherEffectType.SNOW_FRESHNESS, + CommonWeatherEffectType.STRANGERVILLE_ACT: WeatherEffectType.STRANGERVILLE_ACT, + CommonWeatherEffectType.ECO_FOOTPRINT: WeatherEffectType.ECO_FOOTPRINT, + CommonWeatherEffectType.ACID_RAIN: WeatherEffectType.ACID_RAIN, + CommonWeatherEffectType.STAR_WARS_RESISTANCE: WeatherEffectType.STARWARS_RESISTANCE, + CommonWeatherEffectType.STAR_WARS_FIRST_ORDER: WeatherEffectType.STARWARS_FIRST_ORDER, + CommonWeatherEffectType.SNOW_ICINESS: WeatherEffectType.SNOW_ICINESS, + } + return mapping.get(value, None) + + @staticmethod + def convert_from_vanilla(value: WeatherEffectType) -> Union['CommonWeatherEffectType', None]: + """convert_from_vanilla(value) + + Convert a vanilla WeatherEffectType into CommonWeatherEffectType. + + :param value: An instance of WeatherEffectType + :type value: WeatherEffectType + :return: The specified WeatherEffectType translated to CommonWeatherEffectType, or None if the value could not be translated. + :rtype: Union[CommonWeatherEffectType, None] + """ + if isinstance(value, CommonWeatherEffectType): + return value + mapping = { + WeatherEffectType.WINDOW_FROST: CommonWeatherEffectType.WINDOW_FROST, + WeatherEffectType.WATER_FROZEN: CommonWeatherEffectType.WATER_FROZEN, + WeatherEffectType.WIND: CommonWeatherEffectType.WIND, + WeatherEffectType.TEMPERATURE: CommonWeatherEffectType.TEMPERATURE, + WeatherEffectType.THUNDER: CommonWeatherEffectType.THUNDER, + WeatherEffectType.LIGHTNING: CommonWeatherEffectType.LIGHTNING, + WeatherEffectType.SNOW_FRESHNESS: CommonWeatherEffectType.SNOW_FRESHNESS, + WeatherEffectType.STRANGERVILLE_ACT: CommonWeatherEffectType.STRANGERVILLE_ACT, + WeatherEffectType.ECO_FOOTPRINT: CommonWeatherEffectType.ECO_FOOTPRINT, + WeatherEffectType.ACID_RAIN: CommonWeatherEffectType.ACID_RAIN, + WeatherEffectType.STARWARS_RESISTANCE: CommonWeatherEffectType.STAR_WARS_RESISTANCE, + WeatherEffectType.STARWARS_FIRST_ORDER: CommonWeatherEffectType.STAR_WARS_FIRST_ORDER, + WeatherEffectType.SNOW_ICINESS: CommonWeatherEffectType.SNOW_ICINESS, + } + return mapping.get(value, None) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_weather_event_ids.py b/Scripts/s4ap/sims4communitylib/enums/common_weather_event_ids.py new file mode 100644 index 0000000..710d9e1 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_weather_event_ids.py @@ -0,0 +1,58 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonWeatherEventId(CommonInt): + """Identifiers for weather events.""" + CLEAR: 'CommonWeatherEventId' = 182337 + CLEAR_BURNING: 'CommonWeatherEventId' = 182381 + CLEAR_COLD: 'CommonWeatherEventId' = 182377 + CLEAR_COOL: 'CommonWeatherEventId' = 182378 + CLEAR_FREEZING: 'CommonWeatherEventId' = 182380 + CLEAR_HOT: 'CommonWeatherEventId' = 182379 + CLEAR_SHOWER_COOL: 'CommonWeatherEventId' = 182383 + CLEAR_SHOWER_HOT: 'CommonWeatherEventId' = 182384 + CLEAR_SHOWER_WARM: 'CommonWeatherEventId' = 182343 + CLEAR_WINDY_BURNING: 'CommonWeatherEventId' = 182388 + CLEAR_WINDY_COLD: 'CommonWeatherEventId' = 182385 + CLEAR_WINDY_COOL: 'CommonWeatherEventId' = 182389 + CLEAR_WINDY_FREEZING: 'CommonWeatherEventId' = 182386 + CLEAR_WINDY_HOT: 'CommonWeatherEventId' = 182387 + CLEAR_WINDY_WARM: 'CommonWeatherEventId' = 182341 + CLOUDY_COLD: 'CommonWeatherEventId' = 182354 + CLOUDY_COOL: 'CommonWeatherEventId' = 182335 + CLOUDY_FREEZING: 'CommonWeatherEventId' = 182356 + CLOUDY_HOT: 'CommonWeatherEventId' = 182355 + CLOUDY_LIGHTNING: 'CommonWeatherEventId' = 188032 + CLOUDY_WARM: 'CommonWeatherEventId' = 182353 + FAST_RAIN: 'CommonWeatherEventId' = 184681 + HEATWAVE: 'CommonWeatherEventId' = 182344 + MAGIC_REALM: 'CommonWeatherEventId' = 221119 + PARTLY_CLOUDY_COLD: 'CommonWeatherEventId' = 182359 + PARTLY_CLOUDY_COOL: 'CommonWeatherEventId' = 182360 + PARTLY_CLOUDY_FREEZING: 'CommonWeatherEventId' = 182361 + PARTLY_CLOUDY_HOT: 'CommonWeatherEventId' = 182362 + PARTLY_CLOUDY_SNOW_COLD: 'CommonWeatherEventId' = 254595 + PARTLY_CLOUDY_SNOW_COOL: 'CommonWeatherEventId' = 188239 + PARTLY_CLOUDY_WARM: 'CommonWeatherEventId' = 182339 + PARTLY_CLOUDY_WARM_DEFAULT: 'CommonWeatherEventId' = 254183 + RAINSTORM_COLD: 'CommonWeatherEventId' = 182370 + RAINSTORM_COOL: 'CommonWeatherEventId' = 182332 + RAINSTORM_WARM: 'CommonWeatherEventId' = 182371 + RAINSTORM_WARM_MONSOON: 'CommonWeatherEventId' = 212683 + RAIN_HEAVY_COLD: 'CommonWeatherEventId' = 182367 + RAIN_HEAVY_COOL: 'CommonWeatherEventId' = 182325 + RAIN_HEAVY_WARM: 'CommonWeatherEventId' = 182368 + RAIN_LIGHT_COLD: 'CommonWeatherEventId' = 182363 + RAIN_LIGHT_COOL: 'CommonWeatherEventId' = 182322 + RAIN_LIGHT_WARM: 'CommonWeatherEventId' = 182365 + SNOWSTORM: 'CommonWeatherEventId' = 182331 + SNOW_HEAVY_FREEZING: 'CommonWeatherEventId' = 182374 + SNOW_LIGHT_FREEZING: 'CommonWeatherEventId' = 182376 + SNOW_THUNDERSTORM: 'CommonWeatherEventId' = 187809 diff --git a/Scripts/s4ap/sims4communitylib/enums/common_weather_type.py b/Scripts/s4ap/sims4communitylib/enums/common_weather_type.py new file mode 100644 index 0000000..ade427b --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/common_weather_type.py @@ -0,0 +1,280 @@ +""" +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 +""" +from typing import Tuple, Union, Iterator + +from sims4communitylib.enums.common_temperature import Temperature +from sims4communitylib.enums.enumtypes.common_int import CommonInt + +# noinspection PyBroadException +try: + from weather.weather_enums import WeatherType +except: + class WeatherType(CommonInt): + """Mock class.""" + Freezing = Temperature.FREEZING + Cold = Temperature.COLD + Cool = Temperature.COOL + Warm = Temperature.WARM + Hot = Temperature.HOT + Burning = Temperature.BURNING + UNDEFINED = 10 + AnySnow = 11 + AnyRain = 12 + Max_Snow_Accumulation = 13 + Max_Rain_Accumulation = 14 + AnyLightning = 15 + StruckByLightning = 16 + + +class CommonWeatherType(CommonInt): + """Identifiers for weather types.""" + UNDEFINED: 'CommonWeatherType' = ... + FREEZING: 'CommonWeatherType' = ... + COLD: 'CommonWeatherType' = ... + COOL: 'CommonWeatherType' = ... + WARM: 'CommonWeatherType' = ... + HOT: 'CommonWeatherType' = ... + BURNING: 'CommonWeatherType' = ... + ANY_SNOW: 'CommonWeatherType' = ... + ANY_RAIN: 'CommonWeatherType' = ... + MAX_SNOW_ACCUMULATION: 'CommonWeatherType' = ... + MAX_RAIN_ACCUMULATION: 'CommonWeatherType' = ... + ANY_LIGHTNING: 'CommonWeatherType' = ... + STRUCK_BY_LIGHTNING: 'CommonWeatherType' = ... + RAIN_LIGHT: 'CommonWeatherType' = ... + RAIN_HEAVY: 'CommonWeatherType' = ... + RAIN_STORM: 'CommonWeatherType' = ... + SNOW_LIGHT: 'CommonWeatherType' = ... + SNOW_HEAVY: 'CommonWeatherType' = ... + SNOW_STORM: 'CommonWeatherType' = ... + CLOUDY_PARTIAL: 'CommonWeatherType' = ... + CLOUDY_FULL: 'CommonWeatherType' = ... + WINDY: 'CommonWeatherType' = ... + SUN_SHOWER: 'CommonWeatherType' = ... + SUNNY: 'CommonWeatherType' = ... + HEATWAVE: 'CommonWeatherType' = ... + THUNDER: 'CommonWeatherType' = ... + MIN_SNOW_ACCUMULATION: 'CommonWeatherType' = ... + MED_SNOW_ACCUMULATION: 'CommonWeatherType' = ... + HIGH_SNOW_ACCUMULATION: 'CommonWeatherType' = ... + VAMPIRE_SAFE_CLOUD_LEVEL: 'CommonWeatherType' = ... + CLEAR_SKIES: 'CommonWeatherType' = ... + THUNDER_SNOW: 'CommonWeatherType' = ... + SUNSNOW: 'CommonWeatherType' = ... + DRY_LIGHTNING: 'CommonWeatherType' = ... + WINDY_HOT: 'CommonWeatherType' = ... + CLOUDY_WARM: 'CommonWeatherType' = ... + STRANGE_WEATHER: 'CommonWeatherType' = ... + SUNBATHING_WEATHER: 'CommonWeatherType' = ... + ICY: 'CommonWeatherType' = ... + FROZEN_WATER: 'CommonWeatherType' = ... + + @classmethod + def get_all(cls, exclude_values: Iterator['CommonWeatherType'] = None) -> Tuple['CommonWeatherType']: + """get_all(exclude_values=None) + + Get a collection of all values. + + :param exclude_values: These values will be excluded. If set to None, UNDEFINED will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonWeatherType], optional + :return: A collection of all values. + :rtype: Tuple[CommonWeatherType] + """ + if exclude_values is None: + exclude_values = (cls.UNDEFINED,) + # noinspection PyTypeChecker + value_list: Tuple[CommonWeatherType, ...] = tuple([value for value in cls.values if value not in exclude_values]) + return value_list + + @staticmethod + def convert_to_vanilla(value: 'CommonWeatherType') -> Union[WeatherType, None]: + """convert_to_vanilla(value) + + Convert a CommonWeatherType into WeatherType. + + :param value: An instance of CommonWeatherType + :type value: CommonWeatherType + :return: The specified CommonWeatherType translated to WeatherType, or None if the value could not be translated. + :rtype: Union[WeatherType, None] + """ + mapping = dict() + if hasattr(WeatherType, 'Freezing'): + mapping[CommonWeatherType.FREEZING] = WeatherType.Freezing + if hasattr(WeatherType, 'Cold'): + mapping[CommonWeatherType.COLD] = WeatherType.Cold + if hasattr(WeatherType, 'Cool'): + mapping[CommonWeatherType.COOL] = WeatherType.Cool + if hasattr(WeatherType, 'Warm'): + mapping[CommonWeatherType.WARM] = WeatherType.Warm + if hasattr(WeatherType, 'Hot'): + mapping[CommonWeatherType.HOT] = WeatherType.Hot + if hasattr(WeatherType, 'Burning'): + mapping[CommonWeatherType.BURNING] = WeatherType.Burning + if hasattr(WeatherType, 'UNDEFINED'): + mapping[CommonWeatherType.UNDEFINED] = WeatherType.UNDEFINED + if hasattr(WeatherType, 'AnySnow'): + mapping[CommonWeatherType.ANY_SNOW] = WeatherType.AnySnow + if hasattr(WeatherType, 'AnyRain'): + mapping[CommonWeatherType.ANY_RAIN] = WeatherType.AnyRain + if hasattr(WeatherType, 'Max_Snow_Accumulation'): + mapping[CommonWeatherType.MAX_SNOW_ACCUMULATION] = WeatherType.Max_Snow_Accumulation + if hasattr(WeatherType, 'Max_Rain_Accumulation'): + mapping[CommonWeatherType.MAX_RAIN_ACCUMULATION] = WeatherType.Max_Rain_Accumulation + if hasattr(WeatherType, 'AnyLightning'): + mapping[CommonWeatherType.ANY_LIGHTNING] = WeatherType.AnyLightning + if hasattr(WeatherType, 'StruckByLightning'): + mapping[CommonWeatherType.STRUCK_BY_LIGHTNING] = WeatherType.StruckByLightning + if hasattr(WeatherType, 'Rain_Light'): + mapping[CommonWeatherType.RAIN_LIGHT] = WeatherType.Rain_Light + if hasattr(WeatherType, 'Rain_Heavy'): + mapping[CommonWeatherType.RAIN_HEAVY] = WeatherType.Rain_Heavy + if hasattr(WeatherType, 'Rain_Storm'): + mapping[CommonWeatherType.RAIN_STORM] = WeatherType.Rain_Storm + if hasattr(WeatherType, 'Snow_Light'): + mapping[CommonWeatherType.SNOW_LIGHT] = WeatherType.Snow_Light + if hasattr(WeatherType, 'Snow_Heavy'): + mapping[CommonWeatherType.SNOW_HEAVY] = WeatherType.Snow_Heavy + if hasattr(WeatherType, 'Snow_Storm'): + mapping[CommonWeatherType.SNOW_STORM] = WeatherType.Snow_Storm + if hasattr(WeatherType, 'Cloudy_Partial'): + mapping[CommonWeatherType.CLOUDY_PARTIAL] = WeatherType.Cloudy_Partial + if hasattr(WeatherType, 'Cloudy_Full'): + mapping[CommonWeatherType.CLOUDY_FULL] = WeatherType.Cloudy_Full + if hasattr(WeatherType, 'Windy'): + mapping[CommonWeatherType.WINDY] = WeatherType.Windy + if hasattr(WeatherType, 'Sun_Shower'): + mapping[CommonWeatherType.SUN_SHOWER] = WeatherType.Sun_Shower + if hasattr(WeatherType, 'Sunny'): + mapping[CommonWeatherType.SUNNY] = WeatherType.Sunny + if hasattr(WeatherType, 'Heatwave'): + mapping[CommonWeatherType.HEATWAVE] = WeatherType.Heatwave + if hasattr(WeatherType, 'Thunder'): + mapping[CommonWeatherType.THUNDER] = WeatherType.Thunder + if hasattr(WeatherType, 'Min_Snow_Accumulation'): + mapping[CommonWeatherType.MIN_SNOW_ACCUMULATION] = WeatherType.Min_Snow_Accumulation + if hasattr(WeatherType, 'Med_Snow_Accumulation'): + mapping[CommonWeatherType.MED_SNOW_ACCUMULATION] = WeatherType.Med_Snow_Accumulation + if hasattr(WeatherType, 'High_Snow_Accumulation'): + mapping[CommonWeatherType.HIGH_SNOW_ACCUMULATION] = WeatherType.High_Snow_Accumulation + if hasattr(WeatherType, 'Vampire_Safe_CloudLevel'): + mapping[CommonWeatherType.VAMPIRE_SAFE_CLOUD_LEVEL] = WeatherType.Vampire_Safe_CloudLevel + if hasattr(WeatherType, 'Clear_Skies'): + mapping[CommonWeatherType.CLEAR_SKIES] = WeatherType.Clear_Skies + if hasattr(WeatherType, 'Thundersnow'): + mapping[CommonWeatherType.THUNDER_SNOW] = WeatherType.Thundersnow + if hasattr(WeatherType, 'Sunsnow'): + mapping[CommonWeatherType.SUNSNOW] = WeatherType.Sunsnow + if hasattr(WeatherType, 'Dry_Lightning'): + mapping[CommonWeatherType.DRY_LIGHTNING] = WeatherType.Dry_Lightning + if hasattr(WeatherType, 'Windy_Hot'): + mapping[CommonWeatherType.WINDY_HOT] = WeatherType.Windy_Hot + if hasattr(WeatherType, 'Cloudy_Warm'): + mapping[CommonWeatherType.CLOUDY_WARM] = WeatherType.Cloudy_Warm + if hasattr(WeatherType, 'StrangeWeather'): + mapping[CommonWeatherType.STRANGE_WEATHER] = WeatherType.StrangeWeather + if hasattr(WeatherType, 'Sunbathing_Weather'): + mapping[CommonWeatherType.SUNBATHING_WEATHER] = WeatherType.Sunbathing_Weather + if hasattr(WeatherType, 'Icy'): + mapping[CommonWeatherType.ICY] = WeatherType.Icy + if hasattr(WeatherType, 'Frozen_Water'): + mapping[CommonWeatherType.FROZEN_WATER] = WeatherType.Frozen_Water + return mapping.get(value, None) + + @staticmethod + def convert_from_vanilla(value: WeatherType) -> Union['CommonWeatherType', None]: + """convert_from_vanilla(value) + + Convert a vanilla WeatherType into CommonWeatherType. + + :param value: An instance of WeatherType + :type value: WeatherType + :return: The specified WeatherType translated to CommonWeatherType, or None if the value could not be translated. + :rtype: Union[CommonWeatherType, None] + """ + mapping = dict() + if hasattr(WeatherType, 'Freezing'): + mapping[WeatherType.Freezing] = CommonWeatherType.FREEZING + if hasattr(WeatherType, 'Cold'): + mapping[WeatherType.Cold] = CommonWeatherType.COLD + if hasattr(WeatherType, 'Cool'): + mapping[WeatherType.Cool] = CommonWeatherType.COOL + if hasattr(WeatherType, 'Warm'): + mapping[WeatherType.Warm] = CommonWeatherType.WARM + if hasattr(WeatherType, 'Hot'): + mapping[WeatherType.Hot] = CommonWeatherType.HOT + if hasattr(WeatherType, 'Burning'): + mapping[WeatherType.Burning] = CommonWeatherType.BURNING + if hasattr(WeatherType, 'UNDEFINED'): + mapping[WeatherType.UNDEFINED] = CommonWeatherType.UNDEFINED + if hasattr(WeatherType, 'AnySnow'): + mapping[WeatherType.AnySnow] = CommonWeatherType.ANY_SNOW + if hasattr(WeatherType, 'AnyRain'): + mapping[WeatherType.AnyRain] = CommonWeatherType.ANY_RAIN + if hasattr(WeatherType, 'Max_Snow_Accumulation'): + mapping[WeatherType.Max_Snow_Accumulation] = CommonWeatherType.MAX_SNOW_ACCUMULATION + if hasattr(WeatherType, 'Max_Rain_Accumulation'): + mapping[WeatherType.Max_Rain_Accumulation] = CommonWeatherType.MAX_RAIN_ACCUMULATION + if hasattr(WeatherType, 'AnyLightning'): + mapping[WeatherType.AnyLightning] = CommonWeatherType.ANY_LIGHTNING + if hasattr(WeatherType, 'StruckByLightning'): + mapping[WeatherType.StruckByLightning] = CommonWeatherType.STRUCK_BY_LIGHTNING + if hasattr(WeatherType, 'Rain_Light'): + mapping[WeatherType.Rain_Light] = CommonWeatherType.RAIN_LIGHT + if hasattr(WeatherType, 'Rain_Heavy'): + mapping[WeatherType.Rain_Heavy] = CommonWeatherType.RAIN_HEAVY + if hasattr(WeatherType, 'Rain_Storm'): + mapping[WeatherType.Rain_Storm] = CommonWeatherType.RAIN_STORM + if hasattr(WeatherType, 'Snow_Light'): + mapping[WeatherType.Snow_Light] = CommonWeatherType.SNOW_LIGHT + if hasattr(WeatherType, 'Snow_Heavy'): + mapping[WeatherType.Snow_Heavy] = CommonWeatherType.SNOW_HEAVY + if hasattr(WeatherType, 'Snow_Storm'): + mapping[WeatherType.Snow_Storm] = CommonWeatherType.SNOW_STORM + if hasattr(WeatherType, 'Cloudy_Partial'): + mapping[WeatherType.Cloudy_Partial] = CommonWeatherType.CLOUDY_PARTIAL + if hasattr(WeatherType, 'Cloudy_Full'): + mapping[WeatherType.Cloudy_Full] = CommonWeatherType.CLOUDY_FULL + if hasattr(WeatherType, 'Windy'): + mapping[WeatherType.Windy] = CommonWeatherType.WINDY + if hasattr(WeatherType, 'Sun_Shower'): + mapping[WeatherType.Sun_Shower] = CommonWeatherType.SUN_SHOWER + if hasattr(WeatherType, 'Sunny'): + mapping[WeatherType.Sunny] = CommonWeatherType.SUNNY + if hasattr(WeatherType, 'Heatwave'): + mapping[WeatherType.Heatwave] = CommonWeatherType.HEATWAVE + if hasattr(WeatherType, 'Thunder'): + mapping[WeatherType.Thunder] = CommonWeatherType.THUNDER + if hasattr(WeatherType, 'Min_Snow_Accumulation'): + mapping[WeatherType.Min_Snow_Accumulation] = CommonWeatherType.MIN_SNOW_ACCUMULATION + if hasattr(WeatherType, 'Med_Snow_Accumulation'): + mapping[WeatherType.Med_Snow_Accumulation] = CommonWeatherType.MED_SNOW_ACCUMULATION + if hasattr(WeatherType, 'High_Snow_Accumulation'): + mapping[WeatherType.High_Snow_Accumulation] = CommonWeatherType.HIGH_SNOW_ACCUMULATION + if hasattr(WeatherType, 'Vampire_Safe_CloudLevel'): + mapping[WeatherType.Vampire_Safe_CloudLevel] = CommonWeatherType.VAMPIRE_SAFE_CLOUD_LEVEL + if hasattr(WeatherType, 'Clear_Skies'): + mapping[WeatherType.Clear_Skies] = CommonWeatherType.CLEAR_SKIES + if hasattr(WeatherType, 'Thundersnow'): + mapping[WeatherType.Thundersnow] = CommonWeatherType.THUNDER_SNOW + if hasattr(WeatherType, 'Sunsnow'): + mapping[WeatherType.Sunsnow] = CommonWeatherType.SUNSNOW + if hasattr(WeatherType, 'Dry_Lightning'): + mapping[WeatherType.Dry_Lightning] = CommonWeatherType.DRY_LIGHTNING + if hasattr(WeatherType, 'Windy_Hot'): + mapping[WeatherType.Windy_Hot] = CommonWeatherType.WINDY_HOT + if hasattr(WeatherType, 'Cloudy_Warm'): + mapping[WeatherType.Cloudy_Warm] = CommonWeatherType.CLOUDY_WARM + if hasattr(WeatherType, 'StrangeWeather'): + mapping[WeatherType.StrangeWeather] = CommonWeatherType.STRANGE_WEATHER + if hasattr(WeatherType, 'Sunbathing_Weather'): + mapping[WeatherType.Sunbathing_Weather] = CommonWeatherType.SUNBATHING_WEATHER + if hasattr(WeatherType, 'Icy'): + mapping[WeatherType.Icy] = CommonWeatherType.ICY + if hasattr(WeatherType, 'Frozen_Water'): + mapping[WeatherType.Frozen_Water] = CommonWeatherType.FROZEN_WATER + return mapping.get(value, None) diff --git a/Scripts/s4ap/sims4communitylib/enums/enumtypes/__init__.py b/Scripts/s4ap/sims4communitylib/enums/enumtypes/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/enumtypes/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/enums/enumtypes/common_int.py b/Scripts/s4ap/sims4communitylib/enums/enumtypes/common_int.py new file mode 100644 index 0000000..3c93619 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/enumtypes/common_int.py @@ -0,0 +1,130 @@ +""" +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 +""" +from collections import OrderedDict +from typing import Iterator, Union, Tuple + +# noinspection PyBroadException +try: + # noinspection PyUnresolvedReferences + from enum import Int +except: + # Created from example provided at https://stackoverflow.com/questions/5189699/how-to-make-a-class-property + # noinspection PyMissingOrEmptyDocstring + class _ClassPropertyDescriptor(object): + + # noinspection PyMissingTypeHints,SpellCheckingInspection + def __init__(self, fget, fset=None): + self.fget = fget + self.fset = fset + + # noinspection PyMissingTypeHints,SpellCheckingInspection + def __get__(self, obj, klass=None): + if klass is None: + # noinspection SpellCheckingInspection + klass = type(obj) + return self.fget.__get__(obj, klass)() + + # noinspection PyMissingTypeHints + def __set__(self, obj, value): + if not self.fset: + raise AttributeError("can't set attribute") + type_ = type(obj) + return self.fset.__get__(obj, type_)(value) + + # noinspection PyMissingTypeHints + def setter(self, func): + if not isinstance(func, (classmethod, staticmethod)): + func = classmethod(func) + # noinspection SpellCheckingInspection + self.fset = func + return self + + # noinspection PyMissingTypeHints,SpellCheckingInspection + def _classproperty(func): + if not isinstance(func, (classmethod, staticmethod)): + func = classmethod(func) + return _ClassPropertyDescriptor(func) + + # noinspection PyMissingOrEmptyDocstring + class Int: + # noinspection PyPropertyDefinition + @property + def name(self) -> str: + return '' + + # noinspection PyPropertyDefinition + @property + def value(self) -> int: + return 0 + + # noinspection PyPropertyDefinition,PyMethodParameters + @_classproperty + def values(cls) -> Iterator[int]: + return tuple() + + # noinspection PyPropertyDefinition,PyMethodParameters + @_classproperty + def name_to_value(cls) -> OrderedDict: + return OrderedDict() + + # noinspection PyPropertyDefinition,PyMethodParameters + @_classproperty + def value_to_name(cls) -> OrderedDict: + return OrderedDict() + + def __int__(self) -> int: + pass + + def __float__(self) -> float: + pass + + def __sub__(self, other: Union['Int', int]) -> int: + pass + + def __invert__(self) -> int: + pass + + def __add__(self, other: Union['Int', int]) -> int: + pass + + def __divmod__(self, other: Union['Int', int]) -> Tuple[int, int]: + pass + + def __mod__(self, other: Union['Int', int]) -> int: + pass + + def __mul__(self, other: Union['Int', int]) -> int: + pass + + def __neg__(self) -> int: + pass + + def __ge__(self, other: Union['Int', int]) -> bool: + pass + + def __le__(self, other: Union['Int', int]) -> bool: + pass + + def __lt__(self, other: Union['Int', int]) -> bool: + pass + + def __gt__(self, other: Union['Int', int]) -> bool: + pass + + def __eq__(self, other: Union['Int', int]) -> bool: + pass + + def __hash__(self) -> int: + pass + + +class CommonInt(Int): + """An inheritable class that inherits from the vanilla Sims 4 enum.Int class so you don't have to. + + """ + pass diff --git a/Scripts/s4ap/sims4communitylib/enums/enumtypes/common_int_flags.py b/Scripts/s4ap/sims4communitylib/enums/enumtypes/common_int_flags.py new file mode 100644 index 0000000..abde036 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/enumtypes/common_int_flags.py @@ -0,0 +1,160 @@ +""" +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 +""" +from collections import OrderedDict +from typing import Iterator, Union, Tuple, List + +# noinspection PyBroadException +try: + # noinspection PyUnresolvedReferences + from enum import IntFlags +except: + # noinspection PyMissingOrEmptyDocstring + class _ClassPropertyDescriptor(object): + + # noinspection PyMissingTypeHints,SpellCheckingInspection + def __init__(self, fget, fset=None): + self.fget = fget + self.fset = fset + + # noinspection PyMissingTypeHints,SpellCheckingInspection + def __get__(self, obj, klass=None): + if klass is None: + # noinspection SpellCheckingInspection + klass = type(obj) + return self.fget.__get__(obj, klass)() + + # noinspection PyMissingTypeHints + def __set__(self, obj, value): + if not self.fset: + raise AttributeError("can't set attribute") + type_ = type(obj) + return self.fset.__get__(obj, type_)(value) + + # noinspection PyMissingTypeHints + def setter(self, func): + if not isinstance(func, (classmethod, staticmethod)): + func = classmethod(func) + # noinspection SpellCheckingInspection + self.fset = func + return self + + + # noinspection PyMissingTypeHints,SpellCheckingInspection + def _classproperty(func): + if not isinstance(func, (classmethod, staticmethod)): + func = classmethod(func) + return _ClassPropertyDescriptor(func) + + # noinspection PyMissingOrEmptyDocstring + class IntFlags: + # From Int + # noinspection PyPropertyDefinition + @property + def name(self) -> str: + return '' + + # noinspection PyPropertyDefinition + @property + def value(self) -> int: + return 0 + + # noinspection PyPropertyDefinition,PyMethodParameters + @_classproperty + def values(cls) -> Iterator[int]: + return tuple() + + # noinspection PyPropertyDefinition,PyMethodParameters + @_classproperty + def name_to_value(cls) -> OrderedDict: + return OrderedDict() + + # noinspection PyPropertyDefinition,PyMethodParameters + @_classproperty + def value_to_name(cls) -> OrderedDict: + return OrderedDict() + + def __int__(self) -> int: + pass + + def __float__(self) -> float: + pass + + def __sub__(self, other: Union['IntFlags', int]) -> int: + pass + + def __invert__(self) -> int: + pass + + def __add__(self, other: Union['IntFlags', int]) -> int: + pass + + # noinspection SpellCheckingInspection + def __divmod__(self, other: Union['IntFlags', int]) -> Tuple[int, int]: + pass + + def __mod__(self, other: Union['IntFlags', int]) -> int: + pass + + def __mul__(self, other: Union['IntFlags', int]) -> int: + pass + + def __neg__(self) -> int: + pass + + def __ge__(self, other: Union['IntFlags', int]) -> bool: + pass + + def __le__(self, other: Union['IntFlags', int]) -> bool: + pass + + def __lt__(self, other: Union['IntFlags', int]) -> bool: + pass + + def __gt__(self, other: Union['IntFlags', int]) -> bool: + pass + + def __eq__(self, other: Union['IntFlags', int]) -> bool: + pass + + def __hash__(self) -> int: + pass + + # From IntFlags + @classmethod + def _get_unknown_value(cls, value: 'IntFlags') -> 'IntFlags': + pass + + @staticmethod + def _next_auto_value(value: 'IntFlags') -> 'IntFlags': + pass + + def _get_bits(self) -> Tuple[List[int], 'IntFlags']: + pass + + @classmethod + def list_values_from_flags(cls, value: 'IntFlags') -> List['IntFlags']: + pass + + def __iter__(self) -> Iterator['IntFlags']: + pass + + def __contains__(self, value: 'IntFlags'): + pass + + def __and__(self, other: 'IntFlags'): + pass + + def __or__(self, other: 'IntFlags'): + pass + + +class CommonIntFlags(IntFlags): + """An inheritable class that inherits from the vanilla Sims 4 enum.IntFlags class so you don't have to. + + """ + pass diff --git a/Scripts/s4ap/sims4communitylib/enums/enumtypes/common_versioned_int.py b/Scripts/s4ap/sims4communitylib/enums/enumtypes/common_versioned_int.py new file mode 100644 index 0000000..4e11232 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/enumtypes/common_versioned_int.py @@ -0,0 +1,55 @@ +""" +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 +""" +from typing import Set, Dict + +from sims4communitylib.enums.enumtypes.common_int import CommonInt +from sims4communitylib.enums.enumtypes.common_versioned_values_mixin import CommonVersionedValuesMixin + + +class CommonVersionedInt(CommonInt, CommonVersionedValuesMixin): + """Integer, but with a version.""" + + @classmethod + def get_version(cls) -> str: + """The version of the enum. If this changes, it means values have changed and should be updated.""" + raise NotImplementedError() + + @classmethod + def is_obsolete_value(cls, value: 'CommonVersionedInt') -> bool: + """Determine if a value is considered to be obsolete.""" + return value in cls.get_obsolete_values() + + @classmethod + def get_obsolete_values(cls) -> Set['CommonVersionedInt']: + """Retrieve a set of values considered as obsolete.""" + raise NotImplementedError() + + @classmethod + def _get_obsolete_conversion_mapping(cls) -> Dict['CommonVersionedInt', 'CommonVersionedInt']: + """_get_obsolete_conversion_mapping() + + Retrieve a mapping of obsolete values into non-obsolete values. + + :return: A mapping of obsolete values into non-obsolete values. + :type: Dict[CommonVersionedInt, CommonVersionedInt] + """ + raise NotImplementedError() + + @classmethod + def convert_obsolete_value(cls, value: 'CommonVersionedInt') -> 'CommonVersionedInt': + """convert_obsolete_value(value) + + Convert an obsolete value to its new equivalent, if there is one. + + + """ + mapping: Dict[CommonVersionedInt, CommonVersionedInt] = cls._get_obsolete_conversion_mapping() + convert_value = mapping.get(value, value) + if convert_value == value: + return convert_value + return cls.convert_obsolete_value(convert_value) diff --git a/Scripts/s4ap/sims4communitylib/enums/enumtypes/common_versioned_int_flags.py b/Scripts/s4ap/sims4communitylib/enums/enumtypes/common_versioned_int_flags.py new file mode 100644 index 0000000..0d75253 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/enumtypes/common_versioned_int_flags.py @@ -0,0 +1,55 @@ +""" +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 +""" +from typing import Set, Dict + +from sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags +from sims4communitylib.enums.enumtypes.common_versioned_values_mixin import CommonVersionedValuesMixin + + +class CommonVersionedIntFlags(CommonIntFlags, CommonVersionedValuesMixin): + """Integer flags, but with a version.""" + + @classmethod + def get_version(cls) -> str: + """The version of the enum. If this changes, it means values have changed and should be updated.""" + raise NotImplementedError() + + @classmethod + def is_obsolete_value(cls, value: 'CommonVersionedIntFlags') -> bool: + """Determine if a value is considered to be obsolete.""" + return value in cls.get_obsolete_values() + + @classmethod + def get_obsolete_values(cls) -> Set['CommonVersionedIntFlags']: + """Retrieve a set of values considered as obsolete.""" + raise NotImplementedError() + + @classmethod + def _get_obsolete_conversion_mapping(cls) -> Dict['CommonVersionedIntFlags', 'CommonVersionedIntFlags']: + """_get_obsolete_conversion_mapping() + + Retrieve a mapping of obsolete values into non-obsolete values. + + :return: A mapping of obsolete values into non-obsolete values. + :type: Dict[CommonVersionedIntFlags, CommonVersionedIntFlags] + """ + raise NotImplementedError() + + @classmethod + def convert_obsolete_value(cls, value: 'CommonVersionedIntFlags') -> 'CommonVersionedIntFlags': + """convert_obsolete_value(value) + + Convert an obsolete value to its new equivalent, if there is one. + + + """ + mapping: Dict[CommonVersionedIntFlags, CommonVersionedIntFlags] = cls._get_obsolete_conversion_mapping() + convert_value = mapping.get(value, value) + if convert_value == value: + return convert_value + return cls.convert_obsolete_value(convert_value) diff --git a/Scripts/s4ap/sims4communitylib/enums/enumtypes/common_versioned_values_mixin.py b/Scripts/s4ap/sims4communitylib/enums/enumtypes/common_versioned_values_mixin.py new file mode 100644 index 0000000..5a038ab --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/enumtypes/common_versioned_values_mixin.py @@ -0,0 +1,52 @@ +""" +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 +""" +from typing import Set, Dict + + +class CommonVersionedValuesMixin: + """A mixin that provides versioning for values.""" + + @classmethod + def get_version(cls) -> str: + """The version of the enum. If this changes, it means values have changed and should be updated.""" + raise NotImplementedError() + + @classmethod + def is_obsolete_value(cls, value: 'CommonVersionedValuesMixin') -> bool: + """Determine if a value is considered to be obsolete.""" + return value in cls.get_obsolete_values() + + @classmethod + def get_obsolete_values(cls) -> Set['CommonVersionedValuesMixin']: + """Retrieve a set of values considered as obsolete.""" + raise NotImplementedError() + + @classmethod + def _get_obsolete_conversion_mapping(cls) -> Dict['CommonVersionedValuesMixin', 'CommonVersionedValuesMixin']: + """_get_obsolete_conversion_mapping() + + Retrieve a mapping of obsolete values into non-obsolete values. + + :return: A mapping of obsolete values into non-obsolete values. + :type: Dict[CommonVersionedValuesMixin, CommonVersionedValuesMixin] + """ + raise NotImplementedError() + + @classmethod + def convert_obsolete_value(cls, value: 'CommonVersionedValuesMixin') -> 'CommonVersionedValuesMixin': + """convert_obsolete_value(value) + + Convert an obsolete value to its new equivalent, if there is one. + + + """ + mapping: Dict[CommonVersionedValuesMixin, CommonVersionedValuesMixin] = cls._get_obsolete_conversion_mapping() + convert_value = mapping.get(value, value) + if convert_value == value: + return convert_value + return cls.convert_obsolete_value(convert_value) diff --git a/Scripts/s4ap/sims4communitylib/enums/enumtypes/float_enum.py b/Scripts/s4ap/sims4communitylib/enums/enumtypes/float_enum.py new file mode 100644 index 0000000..de488e0 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/enumtypes/float_enum.py @@ -0,0 +1,87 @@ +""" +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 +""" +from typing import Any +from sims4communitylib.enums.common_enum import CommonEnumMetaclass + + +class CommonEnumFloat(float): + """CommonEnumFloat(enum_name, enum_value, class_name) + + An enum that holds a float value. + + :param enum_name: The name of the enum. + :type enum_name: str + :param enum_value: The value of the enum. + :type enum_value: float + :param class_name: The name of the class containing the enum. + :type class_name: str + """ + def __init__(self, enum_name: str, enum_value: float, class_name: str): + super().__init__() + self._name = enum_name + self._value = enum_value + self._class_name = class_name + + def __new__(cls, _, enum_value: float, class_name: str): + return super().__new__(cls, enum_value) + + @property + def name(self) -> str: + """The name of the enum. + + :return: The name of the enum. + :rtype: str + """ + return self._name + + @property + def value(self) -> float: + """The value of the enum. + + :return: The value of the enum. + :rtype: float + """ + return self._value + + def __eq__(self, other: Any): + other_value = other + if hasattr(other, 'value'): + other_value = other.value + return self.value.__eq__(other_value) + + def __repr__(self) -> str: + return '{}.{}'.format(self._class_name, self.name) + + def __str__(self) -> str: + return self.__repr__() + + def __hash__(self) -> int: + return hash(self.value) + + +class CommonEnumFloatMetaclass(CommonEnumMetaclass): + """A metaclass for float enums. + + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_enum_type(mcs) -> Any: + return float + + @classmethod + def _get_common_enum(mcs, enum_name: str, enum_value: float, class_name: str): + return CommonEnumFloat(enum_name, enum_value, class_name) + + +class CommonEnumFloatBase(float, metaclass=CommonEnumFloatMetaclass): + """An inheritable class to turn properties into float enums. + + """ + def __call__(self, val) -> CommonEnumFloat: + pass diff --git a/Scripts/s4ap/sims4communitylib/enums/enumtypes/int_enum.py b/Scripts/s4ap/sims4communitylib/enums/enumtypes/int_enum.py new file mode 100644 index 0000000..ab8a0f6 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/enumtypes/int_enum.py @@ -0,0 +1,90 @@ +""" +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 +""" +from typing import Any + +from sims4communitylib.enums.common_enum import CommonEnumMetaclass + + +class CommonEnumInt(int): + """CommonEnumInt(enum_name, enum_value, class_name) + + An enum that holds an integer value. + + :param enum_name: The name of the enum. + :type enum_name: str + :param enum_value: The value of the enum. + :type enum_value: int + :param class_name: The name of the class containing the enum. + :type class_name: str + """ + def __init__(self, enum_name: str, enum_value: int, class_name: str): + super().__init__() + self._name = enum_name + self._value = enum_value + self._class_name = class_name + + def __new__(cls, _, enum_value: int, class_name: str): + return super().__new__(cls, enum_value) + + @property + def name(self) -> str: + """The name of the enum. + + :return: The name of the enum. + :rtype: str + """ + return self._name + + @property + def value(self) -> int: + """The value of the enum. + + :return: The value of the enum. + :rtype: int + """ + return self._value + + def __eq__(self, other: Any): + other_value = other + if hasattr(other, 'value'): + other_value = other.value + return self.value.__eq__(other_value) + + def __repr__(self) -> str: + return '{}.{}'.format(self._class_name, self.name) + + def __str__(self) -> str: + return self.__repr__() + + def __hash__(self) -> int: + return hash(self.value) + + +class CommonEnumIntMetaclass(CommonEnumMetaclass): + """A metaclass for integer enums. + + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_enum_type(mcs) -> Any: + return int + + @classmethod + def _get_common_enum(mcs, enum_name: str, enum_value: int, class_name: str): + return CommonEnumInt(enum_name, enum_value, class_name) + + +class CommonEnumIntBase(int, metaclass=CommonEnumIntMetaclass): + """An inheritable class to turn properties into integer enums. + + .. warning:: This class is obsolete, please inherit from :class:`.CommonInt` instead. + + """ + def __call__(self, val) -> CommonEnumInt: + pass diff --git a/Scripts/s4ap/sims4communitylib/enums/enumtypes/object_enum.py b/Scripts/s4ap/sims4communitylib/enums/enumtypes/object_enum.py new file mode 100644 index 0000000..5ccfdaa --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/enumtypes/object_enum.py @@ -0,0 +1,87 @@ +""" +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 +""" +from typing import Any +from sims4communitylib.enums.common_enum import CommonEnumMetaclass + + +class CommonEnumObject(object): + """CommonEnumObject(enum_name, enum_value, class_name) + + An enum that holds an object value. + + :param enum_name: The name of the enum. + :type enum_name: str + :param enum_value: The value of the enum. + :type enum_value: object + :param class_name: The name of the class containing the enum. + :type class_name: str + """ + def __init__(self, enum_name: str, enum_value: object, class_name: str): + super().__init__() + self._name = enum_name + self._value = enum_value + self._class_name = class_name + + def __new__(cls, _, enum_value: object, class_name: str): + return super().__new__(cls, enum_value) + + @property + def name(self) -> str: + """The name of the enum. + + :return: The name of the enum. + :rtype: str + """ + return self._name + + @property + def value(self) -> object: + """The value of the enum. + + :return: The value of the enum. + :rtype: object + """ + return self._value + + def __eq__(self, other: Any): + other_value = other + if hasattr(other, 'value'): + other_value = other.value + return self.value.__eq__(other_value) + + def __repr__(self) -> str: + return '{}.{}'.format(self._class_name, self.name) + + def __str__(self) -> str: + return self.__repr__() + + def __hash__(self) -> int: + return hash(self.value) + + +class CommonEnumObjectMetaclass(CommonEnumMetaclass): + """A metaclass for object enums. + + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_enum_type(mcs) -> Any: + return object + + @classmethod + def _get_common_enum(mcs, enum_name: str, enum_value: object, class_name: str): + return CommonEnumObject(enum_name, enum_value, class_name) + + +class CommonEnumObjectBase(object, metaclass=CommonEnumObjectMetaclass): + """An inheritable class to turn properties of the class into object enums. + + """ + def __call__(self, val) -> CommonEnumObject: + pass diff --git a/Scripts/s4ap/sims4communitylib/enums/enumtypes/string_enum.py b/Scripts/s4ap/sims4communitylib/enums/enumtypes/string_enum.py new file mode 100644 index 0000000..57645ce --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/enumtypes/string_enum.py @@ -0,0 +1,87 @@ +""" +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 +""" +from typing import Any +from sims4communitylib.enums.common_enum import CommonEnumMetaclass + + +class CommonEnumString(str): + """CommonEnumString(enum_name, enum_value, class_name) + + An enum that holds a string value. + + :param enum_name: The name of the enum. + :type enum_name: str + :param enum_value: The value of the enum. + :type enum_value: str + :param class_name: The name of the class containing the enum. + :type class_name: str + """ + def __init__(self, enum_name: str, enum_value: str, class_name: str): + super().__init__() + self._name = enum_name + self._value = enum_value + self._class_name = class_name + + def __new__(cls, _, enum_value: float, class_name: str): + return super().__new__(cls, enum_value) + + @property + def name(self) -> str: + """The name of the enum. + + :return: The name of the enum. + :rtype: str + """ + return self._name + + @property + def value(self) -> str: + """The value of the enum. + + :return: The value of the enum. + :rtype: str + """ + return self._value + + def __eq__(self, other: Any): + other_value = other + if hasattr(other, 'value'): + other_value = other.value + return self.value.__eq__(other_value) + + def __repr__(self) -> str: + return '{}.{}'.format(self._class_name, self.name) + + def __str__(self) -> str: + return self.__repr__() + + def __hash__(self) -> int: + return hash(self.value) + + +class CommonEnumStringMetaclass(CommonEnumMetaclass): + """A metaclass for string enums. + + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_enum_type(mcs) -> Any: + return str + + @classmethod + def _get_common_enum(mcs, enum_name: str, enum_value: str, class_name: str): + return CommonEnumString(enum_name, enum_value, class_name) + + +class CommonEnumStringBase(str, metaclass=CommonEnumStringMetaclass): + """An inheritable class to turn properties into string enums. + + """ + def __call__(self, val) -> CommonEnumString: + pass diff --git a/Scripts/s4ap/sims4communitylib/enums/furniture_objects_enum.py b/Scripts/s4ap/sims4communitylib/enums/furniture_objects_enum.py new file mode 100644 index 0000000..534ade9 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/furniture_objects_enum.py @@ -0,0 +1,16 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonFurnitureObjectId(CommonInt): + """Identifiers for vanilla furniture. + + """ + INVALID: 'CommonFurnitureObjectId' = 0 + BASSINET_EMPTY_01: 'CommonFurnitureObjectId' = 36210 diff --git a/Scripts/s4ap/sims4communitylib/enums/icons_enum.py b/Scripts/s4ap/sims4communitylib/enums/icons_enum.py new file mode 100644 index 0000000..6ac4974 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/icons_enum.py @@ -0,0 +1,31 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonIconId(CommonInt): + """Identifiers for vanilla and Sims 4 Community Library icons. + + """ + # S4CL + INVALID: 'CommonIconId' = 0 + S4CLIB_ARROW_RIGHT_ICON: 'CommonIconId' = 3589997896388655139 + S4CLIB_ARROW_LEFT_ICON: 'CommonIconId' = 13667220474349513917 + S4CLIB_BLANK_SQUARE_ICON: 'CommonIconId' = 4439072745437234428 + S4CLIB_TEXT_PREV_SQUARE_ICON: 'CommonIconId' = 1424335400624427567 + S4CLIB_TEXT_NEXT_SQUARE_ICON: 'CommonIconId' = 14634347509917412899 + S4CLIB_UNFILLED_CIRCLE_ICON: 'CommonIconId' = 9610273937086697256 + S4CLIB_FILLED_CIRCLE_ICON: 'CommonIconId' = 10758398356376085395 + S4CLIB_CHECKED_CIRCLE_ICON: 'CommonIconId' = 16231466457332412750 + S4CLIB_X_ICON: 'CommonIconId' = 9145956676194943410 + S4CLIB_ARROW_NAVIGATE_INTO_ICON: 'CommonIconId' = 17672018034831121750 + S4CLIB_QUESTION_MARK_ICON: 'CommonIconId' = 16712671502182128037 + S4CLIB_SIX_SIDED_DICE_ICON: 'CommonIconId' = 1749603411595915770 + S4CLIB_CHECKED_SQUARE_ICON: 'CommonIconId' = 12632258471925492012 + S4CLIB_UNCHECKED_SQUARE_ICON: 'CommonIconId' = 6160391714040730819 + MISSING_IMAGE_ICON: 'CommonIconId' = 3526464109639239417 diff --git a/Scripts/s4ap/sims4communitylib/enums/interactions_enum.py b/Scripts/s4ap/sims4communitylib/enums/interactions_enum.py new file mode 100644 index 0000000..1e903a1 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/interactions_enum.py @@ -0,0 +1,145 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonInteractionId(CommonInt): + """Identifiers for interactions. + + """ + INVALID: 'CommonInteractionId' = 0 + PICK_UP_SIM: 'CommonInteractionId' = 141018 + PICK_UP_SIM_REVERSED: 'CommonInteractionId' = 141925 + CARRY_PICK_UP_TO_BED: 'CommonInteractionId' = 156217 + CARRY_PICK_UP: 'CommonInteractionId' = 134423 + CARRY_PICK_UP_FROM_SEATED: 'CommonInteractionId' = 155633 + CARRY_HUG: 'CommonInteractionId' = 155721 + CARRY_HOLD_OBJECT: 'CommonInteractionId' = 13135 + CARRY_HOLD_SIM: 'CommonInteractionId' = 132170 + CALL_INTO_ARMS_PICK_UP_PET: 'CommonInteractionId' = 173668 + SIM_TO_PET_NON_TOUCHING_PICKUP_PET: 'CommonInteractionId' = 186124 + SOCIAL_MIXER_SUPER_PICK_UP_PET: 'CommonInteractionId' = 160585 + MIXER_SOCIAL_T_PETS_FRIENDLY_HOLD_UP_CARRYING_CHILD: 'CommonInteractionId' = 168236 + GO_HERE: 'CommonInteractionId' = 14410 + SUPER_INTERACTION_GO_HERE: 'CommonInteractionId' = 27242 + GUITAR_PRACTICE: 'CommonInteractionId' = 13471 + + SIM_STAND: 'CommonInteractionId' = 13983 + SIM_STAND_EXCLUSIVE: 'CommonInteractionId' = 23835 + STAND_PASSIVE: 'CommonInteractionId' = 14310 + SIM_SWIM: 'CommonInteractionId' = 102325 + SIM_CHAT: 'CommonInteractionId' = 13998 + SIM_BE_AFFECTIONATE: 'CommonInteractionId' = 13991 + CAT_STAND: 'CommonInteractionId' = 120562 + CAT_STAND_PASSIVE: 'CommonInteractionId' = 120558 + DOG_STAND: 'CommonInteractionId' = 120569 + DOG_STAND_PASSIVE: 'CommonInteractionId' = 120561 + DOG_SWIM: 'CommonInteractionId' = 170682 + DOG_SWIM_PASSIVE: 'CommonInteractionId' = 174558 + FOX_STAND: 'CommonInteractionId' = 257164 + FOX_STAND_PASSIVE: 'CommonInteractionId' = 257160 + + HORSE_STAND: 'CommonInteractionId' = 120430 + HORSE_STAND_PASSIVE: 'CommonInteractionId' = 120431 + + # Deliver Baby + DELIVER_BABY_CAT: 'CommonInteractionId' = 159901 + DELIVER_BABY_DOG: 'CommonInteractionId' = 159902 + BASSINET_DELIVER_BABY: 'CommonInteractionId' = 13070 + SIM_DELIVER_BABY_CREATE_BASSINET: 'CommonInteractionId' = 97294 + + # Sit + SEATING_SIT: 'CommonInteractionId' = 31564 + SEATING_SIT_TODDLER_BED: 'CommonInteractionId' = 156920 + SEATING_SIT_SINGLE: 'CommonInteractionId' = 74779 + SEATING_SIT_CTYAE: 'CommonInteractionId' = 157667 + SEATING_SIT_RESTAURANT_RALLY_ONLY: 'CommonInteractionId' = 134949 + SEATING_SIT_POST_GRAND_MEAL_WAIT_ENJOY_COMPANY: 'CommonInteractionId' = 182774 + SEATING_SIT_DIRECTOR_CHAIR: 'CommonInteractionId' = 191162 + SEATING_SIT_HAIR_MAKE_UP_CHAIR: 'CommonInteractionId' = 201508 + SIT_PASSIVE: 'CommonInteractionId' = 14244 + + # Shower + GENERIC_SHOWER: 'CommonInteractionId' = 13439 + SHOWER_TAKE_SHOWER: 'CommonInteractionId' = 13950 + SHOWER_TAKE_SHOWER_NO_PRIVACY: 'CommonInteractionId' = 110817 + SHOWER_TAKE_SHOWER_PASSIVE: 'CommonInteractionId' = 13952 + SHOWER_TAKE_SHOWER_APARTMENT_NEIGHBOR_FLIRTY: 'CommonInteractionId' = 154397 + SHOWER_TAKE_SHOWER_BRISK: 'CommonInteractionId' = 39965 + SHOWER_TAKE_SHOWER_BRISK_NO_PRIVACY: 'CommonInteractionId' = 110818 + SHOWER_TAKE_SHOWER_COLD_SHOWER: 'CommonInteractionId' = 24332 + SHOWER_TAKE_SHOWER_COLD_SHOWER_NO_PRIVACY: 'CommonInteractionId' = 110819 + SHOWER_TAKE_SHOWER_ENERGIZED: 'CommonInteractionId' = 23839 + SHOWER_TAKE_SHOWER_ENERGIZED_NO_PRIVACY: 'CommonInteractionId' = 110820 + SHOWER_TAKE_SHOWER_SING_IN_SHOWER: 'CommonInteractionId' = 141926 + SHOWER_TAKE_SHOWER_STEAMY: 'CommonInteractionId' = 39860 + SHOWER_TAKE_SHOWER_STEAMY_NO_PRIVACY: 'CommonInteractionId' = 110821 + SHOWER_TAKE_SHOWER_THOUGHTFUL: 'CommonInteractionId' = 39845 + SHOWER_TAKE_SHOWER_THOUGHTFUL_NO_PRIVACY: 'CommonInteractionId' = 110822 + SUPER_INTERACTION_CAMPING_BATHROOM_SHOWER_FEMALE: 'CommonInteractionId' = 104658 + SUPER_INTERACTION_CAMPING_BATHROOM_SHOWER_MALE: 'CommonInteractionId' = 104659 + SIM_RAIN_SHOWER: 'CommonInteractionId' = 185951 + SOCIAL_MIXER_SHOWER_SING_IN_SHOWER: 'CommonInteractionId' = 141216 + SOCIAL_MIXER_SHOWER_SING_IN_SHOWER_AUTONOMOUS: 'CommonInteractionId' = 141928 + + # Bath + GENERIC_BATH: 'CommonInteractionId' = 13427 + GENERIC_BUBBLE_BATH: 'CommonInteractionId' = 35352 + GENERIC_RELAXING_BATH: 'CommonInteractionId' = 120467 + BATHTUB_TAKE_BATH_LOOP: 'CommonInteractionId' = 13085 + BATHTUB_TAKE_BATH_RELAXING_BATH_IDLE_LOOP: 'CommonInteractionId' = 120473 + BATHTUB_TAKE_BATH_RELAXING_BATH_PLAY: 'CommonInteractionId' = 120474 + BATHTUB_TAKE_BATH_RELAXING_BATH_FALL_ASLEEP: 'CommonInteractionId' = 120475 + BATHTUB_TAKE_BATH_RELAXING_BATH_IDLE_LOOP_MUD: 'CommonInteractionId' = 121800 + BATHTUB_TAKE_BATH_RELAXING_BATH_PLAY_MUD: 'CommonInteractionId' = 121804 + BATHTUB_TAKE_BATH_RELAXING_BATH_FALL_ASLEEP_MUD: 'CommonInteractionId' = 121802 + BATHTUB_TAKE_BUBBLE_BATH_MERMAID: 'CommonInteractionId' = 213939 + BATHTUB_TAKE_BATH_MERMAID: 'CommonInteractionId' = 213938 + BATHTUB_NAP_MERMAID: 'CommonInteractionId' = 215915 + BATHTUB_PLAY_MERMAID: 'CommonInteractionId' = 215876 + IDLE_HYGIENE_MERMAID: 'CommonInteractionId' = 215764 + + # S4CL + S4CL_DEBUG_SHOW_RUNNING_AND_QUEUED_INTERACTIONS: 'CommonInteractionId' = 5900237111545222349 + S4CL_DEBUG_SHOW_ACTIVE_BUFFS: 'CommonInteractionId' = 12481803320243318715 + S4CL_DEBUG_SHOW_TRAITS: 'CommonInteractionId' = 2108116777929577381 + S4CL_DEBUG_SHOW_RUNNING_SITUATIONS: 'CommonInteractionId' = 10355438442708473961 + S4CL_DEBUG_LOG_ALL_INTERACTIONS: 'CommonInteractionId' = 741312864308659038 + S4CL_DEBUG_LOG_ALL_INTERACTIONS_PHONE: 'CommonInteractionId' = 2534976194662328318 + S4CL_DEBUG_INDUCE_LABOR: 'CommonInteractionId' = 5145499017874001819 + S4CL_DEBUG_OBJECT_BREAK: 'CommonInteractionId' = 14420264135453255013 + S4CL_DEBUG_OBJECT_FIX: 'CommonInteractionId' = 11726582335911165817 + S4CL_DEBUG_OBJECT_MAKE_DIRTY: 'CommonInteractionId' = 1799349573117453079 + S4CL_DEBUG_OBJECT_MAKE_CLEAN: 'CommonInteractionId' = 5335871574274933500 + S4CL_DEBUG_LOG_ALL_GAME_TAGS: 'CommonInteractionId' = 13483495329565765760 + S4CL_DEBUG_CHANGE_OBJECT_STATES: 'CommonInteractionId' = 15058010603771996272 + + S4CL_SOCIAL_SUPER_SIM_TO_PET_HUMAN: 'CommonInteractionId' = 17045599576038631962 + S4CL_SOCIAL_SUPER_SIM_TO_PET_PET: 'CommonInteractionId' = 17048453908224900188 + + S4CL_SOCIAL_SUPER_SIM_TO_FOX_HUMAN: 'CommonInteractionId' = 0xCC4FDF3D68E78F5E + S4CL_SOCIAL_SUPER_SIM_TO_FOX_FOX: 'CommonInteractionId' = 0xCC2B053D68C8B3F0 + + SHOWER_TAKE_SHOWER_WALL_PRIVACY_CHILD_TEEN = 224187 + GENERIC_TOILET_SIT_STALL = 213986 + + # bar_OrderDrink + BAR_ORDER_DRINK = 13050 + # bar_PushOrderDrink_Autonomous + BAR_ORDER_DRINK_AUTONOMOUS = 13053 + # bar_Order_Food + BAR_ORDER_FOOD = 178213 + + # bar_WaitForDrink + BAR_WAIT_FOR_DRINK = 13065 + # bar_WaitFor_Food + BAR_WAIT_FOR_FOOD = 178214 + # bar_WaitForFood_CriticCareer + BAR_WAIT_FOR_FOOD_CRITIC = 137790 + + TOGGLE_PHONE_SILENCE = 40130 # toggle_phone_silence diff --git a/Scripts/s4ap/sims4communitylib/enums/long_term_sentiments_enum.py b/Scripts/s4ap/sims4communitylib/enums/long_term_sentiments_enum.py new file mode 100644 index 0000000..bbec778 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/long_term_sentiments_enum.py @@ -0,0 +1,38 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonLongTermSentimentId(CommonInt): + """Identifiers for vanilla long term sentiments.""" + INVALID: 'CommonLongTermSentimentId' = 0 + ADORING_LIFESAVER: 'CommonLongTermSentimentId' = 246646 + ADORING_WEDDING_TRADITION_BEST_MAN: 'CommonLongTermSentimentId' = 276284 + ADORING_WEDDING_TRADITION_MAID_OF_HONOR: 'CommonLongTermSentimentId' = 276285 + BITTER_CHEATING: 'CommonLongTermSentimentId' = 246536 + BITTER_GRUDGE: 'CommonLongTermSentimentId' = 239982 + BITTER_MOUNTAIN_CLIMB_ACT2_CANCELLATION: 'CommonLongTermSentimentId' = 249892 + CLOSE_GENERIC: 'CommonLongTermSentimentId' = 239984 + CLOSE_I_KNOW_THEY_HAVE_GOT_MY_BACK: 'CommonLongTermSentimentId' = 273246 + CLOSE_LYCAN_BOND: 'CommonLongTermSentimentId' = 288810 + CLOSE_MOUNTAIN_CLIMB_ACT3_GOLD: 'CommonLongTermSentimentId' = 249898 + CLOSE_THEY_UNDERSTAND: 'CommonLongTermSentimentId' = 273068 + CLOSE_TWO_PEAS_IN_A_POD: 'CommonLongTermSentimentId' = 273067 + CRUSH_GENERIC: 'CommonLongTermSentimentId' = 272840 + ENAMORED_COTTAGE_WORLD_RUINS: 'CommonLongTermSentimentId' = 268491 + ENAMORED_FATED_TO_WED: 'CommonLongTermSentimentId' = 293551 + ENAMORED_FULL_MOON_FIRST_KISS: 'CommonLongTermSentimentId' = 290598 + ENAMORED_GENERIC: 'CommonLongTermSentimentId' = 246613 + ENAMORED_LIGHT_FESTIVAL_KISS: 'CommonLongTermSentimentId' = 253185 + ENAMORED_MOUNTAIN_CLIMB: 'CommonLongTermSentimentId' = 252690 + ENAMORED_MOUNTAIN_NEIGHBORHOOD: 'CommonLongTermSentimentId' = 252689 + GUILTY_FATE_DEFIED: 'CommonLongTermSentimentId' = 293552 + GUILTY_MOUNTAIN_CLIMB_ACT_2_CANCELLATION: 'CommonLongTermSentimentId' = 249896 + HURT_GENERIC: 'CommonLongTermSentimentId' = 246637 + NEEDS_DISTANCE_PROPOSAL: 'CommonLongTermSentimentId' = 278170 + REJECTED_PROPOSAL: 'CommonLongTermSentimentId' = 278176 diff --git a/Scripts/s4ap/sims4communitylib/enums/lot_traits_enum.py b/Scripts/s4ap/sims4communitylib/enums/lot_traits_enum.py new file mode 100644 index 0000000..158a5bf --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/lot_traits_enum.py @@ -0,0 +1,67 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonLotTraitId(CommonInt): + """Identifiers for vanilla lot traits. + + """ + INVALID: 'CommonLotTraitId' = 0 + CELEBRITY_HANG_OUT_HIGH_FAME: 'CommonLotTraitId' = 191710 + CELEBRITY_HANG_OUT_LOW_FAME: 'CommonLotTraitId' = 191708 + CELEBRITY_HOME_LOT_TRAIT: 'CommonLotTraitId' = 199661 + CHILDS_PLAY: 'CommonLotTraitId' = 144151 + CON_CURSED: 'CommonLotTraitId' = 137285 + CON_HAUNTED: 'CommonLotTraitId' = 137286 + CON_LIVELY_NEIGHBORS: 'CommonLotTraitId' = 137276 + CON_NEEDS_TLC: 'CommonLotTraitId' = 137283 + CON_PRICEY: 'CommonLotTraitId' = 137272 + CONVIVIAL: 'CommonLotTraitId' = 144156 + CREEPY_CRAWLIES: 'CommonLotTraitId' = 179482 + FILTHY: 'CommonLotTraitId' = 144148 + FRESH_AIR: 'CommonLotTraitId' = 144158 + GNOMES: 'CommonLotTraitId' = 147778 + GREAT_ACOUSTICS: 'CommonLotTraitId' = 144154 + GREAT_SOIL: 'CommonLotTraitId' = 144150 + GREMLINS: 'CommonLotTraitId' = 147847 + GRODY: 'CommonLotTraitId' = 144146 + HAUNTED: 'CommonLotTraitId' = 149429 + HIGH_SPEED_INTERNET: 'CommonLotTraitId' = 144153 + HOMEY: 'CommonLotTraitId' = 144152 + MEAN_VIBE: 'CommonLotTraitId' = 144144 + NATURAL_LIGHT: 'CommonLotTraitId' = 144157 + NO_TRESPASSING: 'CommonLotTraitId' = 144159 + ON_DARK_LEY_LINE: 'CommonLotTraitId' = 154647 + PEACE_AND_QUIET: 'CommonLotTraitId' = 179555 + PENNY_PIXIES: 'CommonLotTraitId' = 144147 + PET_WORLD_BREEDING_GROUND: 'CommonLotTraitId' = 170199 + PET_WORLD_CAT_FRIENDLY: 'CommonLotTraitId' = 170196 + PET_WORLD_CAT_HANGOUT: 'CommonLotTraitId' = 170190 + PET_WORLD_DOG_FRIENDLY: 'CommonLotTraitId' = 170197 + PET_WORLD_DOG_HANGOUT: 'CommonLotTraitId' = 170191 + PET_WORLD_TRAINING_GROUND: 'CommonLotTraitId' = 170198 + PRO_CHEAP: 'CommonLotTraitId' = 137273 + PRO_CHEFS_KITCHEN: 'CommonLotTraitId' = 137281 + PRO_GREAT_ATMOSPHERE: 'CommonLotTraitId' = 137287 + PRO_GREAT_VIEW: 'CommonLotTraitId' = 137278 + PRO_HISTORICAL: 'CommonLotTraitId' = 137280 + PRO_HOME_STUDIO: 'CommonLotTraitId' = 137284 + PRO_LOW_DEPOSIT: 'CommonLotTraitId' = 137282 + PRO_NEAR_GOOD_SCHOOLS: 'CommonLotTraitId' = 137223 + PRO_ON_LEY_LINE: 'CommonLotTraitId' = 137275 + PRO_QUIET: 'CommonLotTraitId' = 137277 + PRO_ROMANTIC_FIREPLACE: 'CommonLotTraitId' = 137279 + PRO_SERVICED_APARTMENT: 'CommonLotTraitId' = 137274 + QUAKE_ZONE: 'CommonLotTraitId' = 144143 + REGISTERED_VAMPIRE_LAIR: 'CommonLotTraitId' = 155246 + ROMANTIC_ATMOSPHERE: 'CommonLotTraitId' = 144149 + SCIENCE_LAIR: 'CommonLotTraitId' = 144155 + SUNNY_ASPECT: 'CommonLotTraitId' = 144145 + TEEN_HANG_OUT: 'CommonLotTraitId' = 162560 + VAMPIRE_NEXUS: 'CommonLotTraitId' = 154888 diff --git a/Scripts/s4ap/sims4communitylib/enums/moods_enum.py b/Scripts/s4ap/sims4communitylib/enums/moods_enum.py new file mode 100644 index 0000000..4ffcf8d --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/moods_enum.py @@ -0,0 +1,35 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonMoodId(CommonInt): + """Identifiers for vanilla sim moods. + + """ + INVALID: 'CommonMoodId' = 0 + CONFIDENT: 'CommonMoodId' = 14634 + SLEEPING: 'CommonMoodId' = 27149 + STRESSED: 'CommonMoodId' = 14645 + EMBARRASSED: 'CommonMoodId' = 14635 + FLIRTY: 'CommonMoodId' = 14638 + ENERGIZED: 'CommonMoodId' = 14636 + ANGRY: 'CommonMoodId' = 14632 + FOCUSED: 'CommonMoodId' = 14639 + HAPPY: 'CommonMoodId' = 14640 + UNCOMFORTABLE: 'CommonMoodId' = 14646 + BORED: 'CommonMoodId' = 14633 + DAZED: 'CommonMoodId' = 14644 + PLAYFUL: 'CommonMoodId' = 14642 + SAD: 'CommonMoodId' = 14643 + FINE: 'CommonMoodId' = 14637 + INSPIRED: 'CommonMoodId' = 14641 + POSSESSED: 'CommonMoodId' = 201531 + SCARED: 'CommonMoodId' = 251719 + SCARED_DOG: 'CommonMoodId' = 158181 + SCARED_CAT: 'CommonMoodId' = 158442 \ No newline at end of file diff --git a/Scripts/s4ap/sims4communitylib/enums/motives_enum.py b/Scripts/s4ap/sims4communitylib/enums/motives_enum.py new file mode 100644 index 0000000..d4a9e0d --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/motives_enum.py @@ -0,0 +1,53 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonMotiveId(CommonInt): + """Identifiers for vanilla sim motives. + + """ + INVALID: 'CommonMotiveId' = 0 + BLADDER: 'CommonMotiveId' = 16652 # motive_Bladder + ANIMAL_FOX_BLADDER: 'CommonMotiveId' = 270467 # commodity_Motive_Fox_Bladder + PET_CAT_BLADDER: 'CommonMotiveId' = 151036 # commodity_Motive_PetCat_Bladder + PET_DOG_BLADDER: 'CommonMotiveId' = 151032 # commodity_Motive_PetDog_Bladder + PET_HORSE_BLADDER: 'CommonMotiveId' = 312267 # motive_Horse_Bladder + # This motive doesn't actually exist, it is used when mapping motives. The value is arbitrary. + BOWEL: 'CommonMotiveId' = INVALID + PET_CAT_BOWEL: 'CommonMotiveId' = 157949 # commodity_Motive_PetCat_Bowel + PET_DOG_BOWEL: 'CommonMotiveId' = 158698 # commodity_Motive_PetDog_Bowel + ENERGY: 'CommonMotiveId' = 16654 # motive_Energy + PET_CAT_ENERGY: 'CommonMotiveId' = 151037 # commodity_Motive_PetCat_Energy + PET_DOG_ENERGY: 'CommonMotiveId' = 151033 # commodity_Motive_PetDog_Energy + PET_HORSE_ENERGY: 'CommonMotiveId' = 312266 # motive_Horse_Energy + SERVO_CHARGE: 'CommonMotiveId' = 218484 # motive_Robots_Charge + FUN: 'CommonMotiveId' = 16655 # motive_Fun + PET_CAT_PLAY: 'CommonMotiveId' = 157718 # commodity_Motive_PetCat_Play + PET_DOG_PLAY: 'CommonMotiveId' = 158699 # commodity_Motive_PetDog_Play + PET_HORSE_FUN: 'CommonMotiveId' = 312268 # motive_Horse_Fun + HUNGER: 'CommonMotiveId' = 16656 # motive_Hunger + PET_CAT_HUNGER: 'CommonMotiveId' = 151035 # commodity_Motive_PetCat_Hunger + PET_DOG_HUNGER: 'CommonMotiveId' = 151031 # commodity_Motive_PetDog_Hunger + PET_HORSE_HUNGER: 'CommonMotiveId' = 312265 # motive_Horse_Hunger + HYGIENE: 'CommonMotiveId' = 16657 # motive_Hygiene + ANIMAL_FOX_HYGIENE: 'CommonMotiveId' = 270701 # motive_Hygiene_Fox + PET_CAT_HYGIENE: 'CommonMotiveId' = 157055 # commodity_Motive_PetCat_Hygiene + PET_DOG_HYGIENE: 'CommonMotiveId' = 157056 # commodity_Motive_PetDog_Hygiene + PET_HORSE_HYGIENE: 'CommonMotiveId' = 312269 # motive_Horse_Hygiene + SOCIAL: 'CommonMotiveId' = 16658 # motive_Social + PET_CAT_AFFECTION: 'CommonMotiveId' = 151038 # commodity_Motive_PetCat_Affection + PET_DOG_AFFECTION: 'CommonMotiveId' = 151034 # commodity_Motive_PetDog_Affection + PET_HORSE_SOCIAL: 'CommonMotiveId' = 312270 # motive_Horse_Social + VAMPIRE_POWER: 'CommonMotiveId' = 150238 # commodity_Motive_Visible_Vampire_Power + VAMPIRE_THIRST: 'CommonMotiveId' = 149541 # commodity_Motive_Visible_Vampire_Thirst + PLANT_SIM_WATER: 'CommonMotiveId' = 162675 # motive_PlantSim_Water + SERVO_DURABILITY: 'CommonMotiveId' = 218485 # motive_Robots_Durability + MERMAID_HYDRATION: 'CommonMotiveId' = HYGIENE + WITCH_MAGIC: 'CommonMotiveId' = 213024 # commodity_Motive_WitchOccult_Charge + WEREWOLF_FURY: 'CommonMotiveId' = 276223 # commodity_Motive_Werewolf_Fury diff --git a/Scripts/s4ap/sims4communitylib/enums/relationship_bit_collection_uids_enum.py b/Scripts/s4ap/sims4communitylib/enums/relationship_bit_collection_uids_enum.py new file mode 100644 index 0000000..2ad7743 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/relationship_bit_collection_uids_enum.py @@ -0,0 +1,38 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonRelationshipBitCollectionUid(CommonInt): + """The values within the dynamic RelationshipBitCollectionUid enum.""" + INVALID: 'CommonRelationshipBitCollectionUid' = 0 + ALL: 'CommonRelationshipBitCollectionUid' = 1 + CHILD: 'CommonRelationshipBitCollectionUid' = 72 + ENGAGED: 'CommonRelationshipBitCollectionUid' = 67 + FAMILY: 'CommonRelationshipBitCollectionUid' = 64 + FAMILY_ACQUIRED_NEGATIVE: 'CommonRelationshipBitCollectionUid' = 68 + FAMILY_ACQUIRED_NEUTRAL: 'CommonRelationshipBitCollectionUid' = 71 + FAMILY_ACQUIRED_POSITIVE: 'CommonRelationshipBitCollectionUid' = 69 + FRIEND: 'CommonRelationshipBitCollectionUid' = 65 + GIGS: 'CommonRelationshipBitCollectionUid' = 73 + PET: 'CommonRelationshipBitCollectionUid' = 70 + ROMANCE: 'CommonRelationshipBitCollectionUid' = 66 + SENTIMENT_ADORING: 'CommonRelationshipBitCollectionUid' = 82 + SENTIMENT_BITTER: 'CommonRelationshipBitCollectionUid' = 76 + SENTIMENT_CLOSE: 'CommonRelationshipBitCollectionUid' = 78 + SENTIMENT_ENAMORED: 'CommonRelationshipBitCollectionUid' = 79 + SENTIMENT_FURIOUS: 'CommonRelationshipBitCollectionUid' = 77 + SENTIMENT_GUILTY: 'CommonRelationshipBitCollectionUid' = 84 + SENTIMENT_HURT: 'CommonRelationshipBitCollectionUid' = 83 + SENTIMENT_LONG_TERM: 'CommonRelationshipBitCollectionUid' = 81 + SENTIMENT_MOTIVATING: 'CommonRelationshipBitCollectionUid' = 85 + SENTIMENT_NEGATIVE: 'CommonRelationshipBitCollectionUid' = 74 + SENTIMENT_POSITIVE: 'CommonRelationshipBitCollectionUid' = 75 + SENTIMENT_SHORT_TERM: 'CommonRelationshipBitCollectionUid' = 80 + + diff --git a/Scripts/s4ap/sims4communitylib/enums/relationship_bit_collections_enum.py b/Scripts/s4ap/sims4communitylib/enums/relationship_bit_collections_enum.py new file mode 100644 index 0000000..d854669 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/relationship_bit_collections_enum.py @@ -0,0 +1,34 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonRelationshipBitCollectionId(CommonInt): + """Identifiers for vanilla relationship bit collections.""" + INVALID: 'CommonRelationshipBitCollectionId' = 0 + CHILD: 'CommonRelationshipBitCollectionId' = 195565 + FAMILY: 'CommonRelationshipBitCollectionId' = 15806 + FAMILY_ACQUIRED_NEGATIVE: 'CommonRelationshipBitCollectionId' = 162462 + FAMILY_ACQUIRED_NEUTRAL: 'CommonRelationshipBitCollectionId' = 164649 + FAMILY_ACQUIRED_POSITIVE: 'CommonRelationshipBitCollectionId' = 164128 + FRIEND: 'CommonRelationshipBitCollectionId' = 15807 + FRIEND_AT_LEAST_FRIEND: 'CommonRelationshipBitCollectionId' = 273773 + ROMANTIC: 'CommonRelationshipBitCollectionId' = 240628 + ROMANTIC_HAVE_BEEN_EXES: 'CommonRelationshipBitCollectionId' = 274292 + SENTIMENT_ADORING: 'CommonRelationshipBitCollectionId' = 246492 + SENTIMENT_BITTER: 'CommonRelationshipBitCollectionId' = 240104 + SENTIMENT_CLOSE: 'CommonRelationshipBitCollectionId' = 240103 + SENTIMENT_ENAMORED: 'CommonRelationshipBitCollectionId' = 240107 + SENTIMENT_FURIOUS: 'CommonRelationshipBitCollectionId' = 240105 + SENTIMENT_GUILTY: 'CommonRelationshipBitCollectionId' = 246491 + SENTIMENT_HURT: 'CommonRelationshipBitCollectionId' = 246490 + SENTIMENT_LONG_TERM: 'CommonRelationshipBitCollectionId' = 240114 + SENTIMENT_MOTIVATING: 'CommonRelationshipBitCollectionId' = 252843 + SENTIMENT_NEGATIVE: 'CommonRelationshipBitCollectionId' = 240110 + SENTIMENT_POSITIVE: 'CommonRelationshipBitCollectionId' = 240109 + SENTIMENT_SHORT_TERM: 'CommonRelationshipBitCollectionId' = 240113 diff --git a/Scripts/s4ap/sims4communitylib/enums/relationship_bits_enum.py b/Scripts/s4ap/sims4communitylib/enums/relationship_bits_enum.py new file mode 100644 index 0000000..f3f5219 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/relationship_bits_enum.py @@ -0,0 +1,514 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonRelationshipBitId(CommonInt): + """Identifiers for vanilla sim relationship bits. + + """ + INVALID: 'CommonRelationshipBitId' = 0 + ACTOR_CAREER_COWORKER_REL_BITS_COMMERCIAL_DIRECTOR: 'CommonRelationshipBitId' = 194371 + ACTOR_CAREER_COWORKER_REL_BITS_COSTAR1: 'CommonRelationshipBitId' = 196312 + ACTOR_CAREER_COWORKER_REL_BITS_COSTAR2: 'CommonRelationshipBitId' = 197701 + ACTOR_CAREER_COWORKER_REL_BITS_FILM_DIRECTOR: 'CommonRelationshipBitId' = 194696 + ACTOR_CAREER_COWORKER_REL_BITS_HIGH_BUDGET_TV_DIRECTOR: 'CommonRelationshipBitId' = 194373 + ACTOR_CAREER_COWORKER_REL_BITS_LOW_BUDGET_TV_DIRECTOR: 'CommonRelationshipBitId' = 194372 + APARTMENT_NEIGHBOR_HAS_KEY: 'CommonRelationshipBitId' = 135106 + ASKED_FOR_SIGNATURE: 'CommonRelationshipBitId' = 234697 + AUTHORITY_DEFAULT: 'CommonRelationshipBitId' = 161996 + BATUU_MISSIONS_FS7_SPY_SHARED_FAKE_INFO_NOT_SPY_1: 'CommonRelationshipBitId' = 248907 + BATUU_MISSIONS_FS7_SPY_SHARED_FAKE_INFO_NOT_SPY_2: 'CommonRelationshipBitId' = 248908 + BATUU_MISSIONS_FS7_SPY_SHARED_FAKE_INFO_NOT_SPY_3: 'CommonRelationshipBitId' = 248906 + BATUU_MISSIONS_FS7_SPY_SHARED_FAKE_INFO_SPY_1: 'CommonRelationshipBitId' = 248893 + BATUU_MISSIONS_FS7_SPY_SHARED_FAKE_INFO_SPY_2: 'CommonRelationshipBitId' = 248894 + BATUU_MISSIONS_FS7_SPY_SHARED_FAKE_INFO_SPY_3: 'CommonRelationshipBitId' = 248892 + BOUQUET_HAS_CAUGHT_BOUQUET: 'CommonRelationshipBitId' = 278814 + BOUQUET_HAS_THROWN_BOUQUET: 'CommonRelationshipBitId' = 278811 + CAT_OWNED: 'CommonRelationshipBitId' = 148063 + CAT_OWNER: 'CommonRelationshipBitId' = 148062 + CELEBRITY_ACQUAINTANCE: 'CommonRelationshipBitId' = 192631 + CELEBRITY_SHUNNED: 'CommonRelationshipBitId' = 194919 + CELEBRITY_SOCIAL_TIMEOUT_ASK: 'CommonRelationshipBitId' = 195082 + CELEBRITY_SOCIAL_TIMEOUT_COMPARE: 'CommonRelationshipBitId' = 195075 + CELEBRITY_SOCIAL_TIMEOUT_DIP_KISS: 'CommonRelationshipBitId' = 195080 + CELEBRITY_SOCIAL_TIMEOUT_FIRST_KISS: 'CommonRelationshipBitId' = 195096 + CELEBRITY_SOCIAL_TIMEOUT_IMPLY: 'CommonRelationshipBitId' = 195076 + CELEBRITY_SOCIAL_TIMEOUT_INTERESTS: 'CommonRelationshipBitId' = 195073 + CELEBRITY_SOCIAL_TIMEOUT_KISS_HAND: 'CommonRelationshipBitId' = 195078 + CELEBRITY_SOCIAL_TIMEOUT_NAUGHTY: 'CommonRelationshipBitId' = 195077 + CELEBRITY_SOCIAL_TIMEOUT_PERSONAL_STORY: 'CommonRelationshipBitId' = 195079 + CELEBRITY_SOCIAL_TIMEOUT_TENDER_KISS: 'CommonRelationshipBitId' = 195081 + CELEBRITY_SOCIAL_TIMEOUT_WOOHOO: 'CommonRelationshipBitId' = 195083 + CLONE: 'CommonRelationshipBitId' = 216270 + CLUBS_GAMES_COM_SECRET_CRUSH: 'CommonRelationshipBitId' = 122859 + COMMUNITY_CLOSENESS_BORROWED_SIMOLEONS: 'CommonRelationshipBitId' = 232917 + COMMUNITY_CLOSENESS_WRONG_NUMBER_DEBT: 'CommonRelationshipBitId' = 239192 + CT_NOT_PARENT_CARE_DEPENDENT: 'CommonRelationshipBitId' = 162483 + CT_NOT_PARENT_CARE_GIVER: 'CommonRelationshipBitId' = 162482 + DARED: 'CommonRelationshipBitId' = 121352 + DATE_SITUATION_BIT: 'CommonRelationshipBitId' = 37762 + DATE_SITUATION_BIT_BLIND_DATE: 'CommonRelationshipBitId' = 201485 + DEBUG_SITUATION_BIT: 'CommonRelationshipBitId' = 37769 + DETECTIVE_CAREER_ARRESTED: 'CommonRelationshipBitId' = 113055 + DETECTIVE_CAREER_CRIMINAL: 'CommonRelationshipBitId' = 113060 + DETECTIVE_FOUND_GUILTY: 'CommonRelationshipBitId' = 116146 + DOG_OWNED: 'CommonRelationshipBitId' = 148061 + DOG_OWNER: 'CommonRelationshipBitId' = 148060 + E_SPORTS_TEAMMATES: 'CommonRelationshipBitId' = 226586 + FAMILIAR: 'CommonRelationshipBitId' = 215119 + FAMILY_ACQUIRED_CHILD_HIGH_REL_HIGH_AUTH: 'CommonRelationshipBitId' = 161969 + FAMILY_ACQUIRED_CHILD_HIGH_REL_LOW_AUTH: 'CommonRelationshipBitId' = 161971 + FAMILY_ACQUIRED_CHILD_MAX_REL_HIGH_AUTH: 'CommonRelationshipBitId' = 161973 + FAMILY_ACQUIRED_CHILD_MAX_REL_LOW_AUTH: 'CommonRelationshipBitId' = 161975 + FAMILY_ACQUIRED_CHILD_NEUTRAL_REL_HIGH_AUTH: 'CommonRelationshipBitId' = 161977 + FAMILY_ACQUIRED_CHILD_NEUTRAL_REL_LOW_AUTH: 'CommonRelationshipBitId' = 161979 + FAMILY_ACQUIRED_CHILD_POOR_REL_HIGH_AUTH: 'CommonRelationshipBitId' = 161981 + FAMILY_ACQUIRED_CHILD_POOR_REL_LOW_AUTH: 'CommonRelationshipBitId' = 161983 + FAMILY_ACQUIRED_GRANDCHILD_HIGH_REL: 'CommonRelationshipBitId' = 161910 + FAMILY_ACQUIRED_GRANDCHILD_NEUTRAL_REL: 'CommonRelationshipBitId' = 161922 + FAMILY_ACQUIRED_GRANDCHILD_POOR_REL: 'CommonRelationshipBitId' = 161924 + FAMILY_ACQUIRED_GRANDPARENT_HIGH_REL: 'CommonRelationshipBitId' = 161909 + FAMILY_ACQUIRED_GRANDPARENT_NEUTRAL_REL: 'CommonRelationshipBitId' = 161911 + FAMILY_ACQUIRED_GRANDPARENT_POOR_REL: 'CommonRelationshipBitId' = 161923 + FAMILY_ACQUIRED_PARENT_HIGH_REL_HIGH_AUTH: 'CommonRelationshipBitId' = 161968 + FAMILY_ACQUIRED_PARENT_HIGH_REL_LOW_AUTH: 'CommonRelationshipBitId' = 161970 + FAMILY_ACQUIRED_PARENT_MAX_REL_HIGH_AUTH: 'CommonRelationshipBitId' = 161972 + FAMILY_ACQUIRED_PARENT_MAX_REL_LOW_AUTH: 'CommonRelationshipBitId' = 161974 + FAMILY_ACQUIRED_PARENT_NEUTRAL_REL_HIGH_AUTH: 'CommonRelationshipBitId' = 161976 + FAMILY_ACQUIRED_PARENT_NEUTRAL_REL_LOW_AUTH: 'CommonRelationshipBitId' = 161978 + FAMILY_ACQUIRED_PARENT_POOR_REL_HIGH_AUTH: 'CommonRelationshipBitId' = 161980 + FAMILY_ACQUIRED_PARENT_POOR_REL_LOW_AUTH: 'CommonRelationshipBitId' = 161982 + FAMILY_ACQUIRED_SIBLING_HIGH_REL_HIGH_RIVAL: 'CommonRelationshipBitId' = 161931 + FAMILY_ACQUIRED_SIBLING_HIGH_REL_LOW_RIVAL: 'CommonRelationshipBitId' = 161930 + FAMILY_ACQUIRED_SIBLING_NEUTRAL_REL_HIGH_RIVAL: 'CommonRelationshipBitId' = 161932 + FAMILY_ACQUIRED_SIBLING_NEUTRAL_REL_LOW_RIVAL: 'CommonRelationshipBitId' = 161933 + FAMILY_ACQUIRED_SIBLING_POOR_REL_HIGH_RIVAL: 'CommonRelationshipBitId' = 161934 + FAMILY_ACQUIRED_SIBLING_POOR_REL_LOW_RIVAL: 'CommonRelationshipBitId' = 161935 + FAMILY_AUNT_UNCLE: 'CommonRelationshipBitId' = 8829 + FAMILY_BROTHER_SISTER: 'CommonRelationshipBitId' = 8802 + FAMILY_COUSIN: 'CommonRelationshipBitId' = 8826 + FAMILY_GRANDCHILD: 'CommonRelationshipBitId' = 8807 + FAMILY_GRANDPARENT: 'CommonRelationshipBitId' = 8808 + FAMILY_HUSBAND_WIFE: 'CommonRelationshipBitId' = 24490 + FAMILY_NIECE_NEPHEW: 'CommonRelationshipBitId' = 9989 + FAMILY_PARENT: 'CommonRelationshipBitId' = 8809 + FAMILY_SON_DAUGHTER: 'CommonRelationshipBitId' = 8805 + FAMILY_STEP_SIBLING: 'CommonRelationshipBitId' = 8824 + FAN_STAN_STAN: 'CommonRelationshipBitId' = 194374 + FAN_STAN_STAN_COOLDOWN: 'CommonRelationshipBitId' = 194411 + FEAR_BEING_CHEATED_ON_TRACKER: 'CommonRelationshipBitId' = 278255 + FEAR_BEING_JUDGED_MEAN_TRACKER: 'CommonRelationshipBitId' = 288656 + FEUD_NEUTRAL: 'CommonRelationshipBitId' = 193903 + FEUD_TARGET: 'CommonRelationshipBitId' = 193944 + FOX_DONT_STEAL: 'CommonRelationshipBitId' = 260898 + FRIENDSHIP_ACQUAINTANCES: 'CommonRelationshipBitId' = 15792 + FRIENDSHIP_BFF: 'CommonRelationshipBitId' = 15794 + FRIENDSHIP_BFF_BROMANTIC_PARTNER: 'CommonRelationshipBitId' = 31211 + FRIENDSHIP_BFF_EVIL: 'CommonRelationshipBitId' = 15795 + FRIENDSHIP_CONFIDANT: 'CommonRelationshipBitId' = 248676 + FRIENDSHIP_DESPISED: 'CommonRelationshipBitId' = 15796 + FRIENDSHIP_DISLIKED: 'CommonRelationshipBitId' = 15802 + FRIENDSHIP_FRIEND: 'CommonRelationshipBitId' = 15797 + FRIENDSHIP_FRIEND_EVIL: 'CommonRelationshipBitId' = 15798 + FRIENDSHIP_GOOD_FRIENDS: 'CommonRelationshipBitId' = 15799 + FRIENDSHIP_GOOD_FRIENDS_EVIL: 'CommonRelationshipBitId' = 15800 + FRIENDSHIP_NEMESIS: 'CommonRelationshipBitId' = 15801 + FRIENDSHIP_NEUTRAL_BIT: 'CommonRelationshipBitId' = 15809 + HAS_BEEN_FRIENDS: 'CommonRelationshipBitId' = 129295 + HAS_MET: 'CommonRelationshipBitId' = 15803 + HAVE_BEEN_EXES: 'CommonRelationshipBitId' = 274289 + HAVE_BEEN_ROMANTIC: 'CommonRelationshipBitId' = 98756 + HELP_BATUUANS_CHEER_UP: 'CommonRelationshipBitId' = 244327 + HELP_BATUUANS_CHEER_UP_FINISHED: 'CommonRelationshipBitId' = 244328 + HELP_BATUUANS_GIVE_CREDITS: 'CommonRelationshipBitId' = 244005 + HELP_BATUUANS_GIVE_CREDITS_FINISHED: 'CommonRelationshipBitId' = 244006 + HELP_BATUUANS_GIVE_DROID_PARTS: 'CommonRelationshipBitId' = 244000 + HELP_BATUUANS_GIVE_DROID_PARTS_FINISHED: 'CommonRelationshipBitId' = 244001 + HELP_BATUUANS_GIVE_FOOD: 'CommonRelationshipBitId' = 243995 + HELP_BATUUANS_GIVE_FOOD_FINISHED: 'CommonRelationshipBitId' = 243996 + HELP_BATUUANS_PLAY_SABACC: 'CommonRelationshipBitId' = 243893 + HELP_BATUUANS_PLAY_SABACC_FINISHED: 'CommonRelationshipBitId' = 243920 + HIGH_SCHOOL_TEAM_CHEER_TEAM_TEAMMATES: 'CommonRelationshipBitId' = 276585 + HIGH_SCHOOL_TEAM_CHESS_TEAM_TEAMMATES: 'CommonRelationshipBitId' = 276584 + HIGH_SCHOOL_TEAM_COMPUTER_TEAM_TEAMMATES: 'CommonRelationshipBitId' = 276586 + HIGH_SCHOOL_TEAM_FOOTBALL_TEAM_TEAMMATES: 'CommonRelationshipBitId' = 276587 + HIGH_SCHOOL_TEAM_RIVAL: 'CommonRelationshipBitId' = 277655 + INTERIOR_DECORATOR_CLIENT: 'CommonRelationshipBitId' = 259991 + INTERIOR_DECORATOR_CLIENT_COOLDOWN_FIRED: 'CommonRelationshipBitId' = 264540 + INTERIOR_DECORATOR_CLIENT_COOLDOWN_NORMAL: 'CommonRelationshipBitId' = 264537 + INTERIOR_DECORATOR_CLIENT_FOLLOW_UP_CLIENT_CALL_NPC_INVITE_POST_SITUATION: 'CommonRelationshipBitId' = 260877 + INTERIOR_DECORATOR_CLIENT_FOLLOW_UP_OFFERED_GIG_REFERRED: 'CommonRelationshipBitId' = 260531 + INTERIOR_DECORATOR_CLIENT_FOLLOW_UP_OFFERED_GIG_RETURNING_NEGATIVE: 'CommonRelationshipBitId' = 260532 + INTERIOR_DECORATOR_CLIENT_FOLLOW_UP_OFFERED_GIG_RETURNING_POSITIVE: 'CommonRelationshipBitId' = 260533 + INTERIOR_DECORATOR_CLIENT_FOLLOW_UP_RETURNING_GIG_COOLDOWN: 'CommonRelationshipBitId' = 261233 + INTERROGATION_FINISHED: 'CommonRelationshipBitId' = 109991 + INVESTIGATION_SYSTEM_DISCUSSED_SPORES: 'CommonRelationshipBitId' = 203603 + INVESTIGATION_SYSTEM_RECRUITED: 'CommonRelationshipBitId' = 203604 + INVESTIGATION_SYSTEM_REL_BITS_FAILED_TO_RECRUIT: 'CommonRelationshipBitId' = 205562 + INVESTIGATION_SYSTEM_REQUESTED_KEY_CARD: 'CommonRelationshipBitId' = 204495 + INVESTIGATION_SYSTEM_VACCINE_TEST_SUBJECT: 'CommonRelationshipBitId' = 206182 + IS_CLONE: 'CommonRelationshipBitId' = 109549 + LANDLORD: 'CommonRelationshipBitId' = 135305 + LEGAL_CLIENT: 'CommonRelationshipBitId' = 228184 + LISTENING_DEVICE_BUGGED_BUGGEE: 'CommonRelationshipBitId' = 202324 + LISTENING_DEVICE_BUGGED_BUGGER: 'CommonRelationshipBitId' = 201980 + LIVING_ROOMMATE: 'CommonRelationshipBitId' = 8812 + LOAN_LARGE: 'CommonRelationshipBitId' = 28912 + LOAN_SMALL: 'CommonRelationshipBitId' = 28911 + MERMAID_MERFOLK_WOKE: 'CommonRelationshipBitId' = 208278 + MET_DISGUISED_ALIEN: 'CommonRelationshipBitId' = 185854 + MISCHIEF_NEUTRAL_BIT: 'CommonRelationshipBitId' = 26922 + MISCHIEF_PARTNERS_IN_CRIME: 'CommonRelationshipBitId' = 26923 + NEIGHBOR: 'CommonRelationshipBitId' = 75294 + NEIGHBOR_HAS_KEY: 'CommonRelationshipBitId' = 195367 + NO_LONGER_FRIENDS: 'CommonRelationshipBitId' = 273547 + OBJECT_FRIENDSHIP_ACQUAINTANCES: 'CommonRelationshipBitId' = 204519 + OBJECT_FRIENDSHIP_DESPISED: 'CommonRelationshipBitId' = 204523 + OBJECT_FRIENDSHIP_DISLIKED: 'CommonRelationshipBitId' = 204524 + OBJECT_FRIENDSHIP_FRIEND: 'CommonRelationshipBitId' = 204525 + OBJECT_FRIENDSHIP_GOOD_FRIENDS: 'CommonRelationshipBitId' = 204527 + OBJECT_FRIENDSHIP_NEMESIS: 'CommonRelationshipBitId' = 204529 + OPENABLE_WINDOW_EVENT_INVITE_TRACKER: 'CommonRelationshipBitId' = 283043 + PERSONALITY_ANALYZED: 'CommonRelationshipBitId' = 107716 + PET_TO_PET_FRIENDLY: 'CommonRelationshipBitId' = 159636 + PET_TO_PET_HOSTILE: 'CommonRelationshipBitId' = 159635 + PET_TO_PET_NEUTRAL: 'CommonRelationshipBitId' = 159634 + PLAY_DATE_SITUATION_BIT: 'CommonRelationshipBitId' = 117189 + POSSESSED_ALLOW_WAKE_UP: 'CommonRelationshipBitId' = 204754 + PREGNANCY_BIRTH_PARENT: 'CommonRelationshipBitId' = 100705 + PROFESSOR_NPC: 'CommonRelationshipBitId' = 227706 + PROM_HIGH_SCHOOL_PROM_DATE: 'CommonRelationshipBitId' = 295931 + PROM_HIGH_SCHOOL_PROM_DATE_FRIENDS: 'CommonRelationshipBitId' = 295932 + PROM_HIGH_SCHOOL_PROM_DITCHING_PROM: 'CommonRelationshipBitId' = 295930 + RBC_CHILD: 'CommonRelationshipBitId' = 195565 + RBC_FAMILY: 'CommonRelationshipBitId' = 15806 + RBC_FAMILY_ACQUIRED_NEGATIVE: 'CommonRelationshipBitId' = 162462 + RBC_FAMILY_ACQUIRED_NEUTRAL: 'CommonRelationshipBitId' = 164649 + RBC_FAMILY_ACQUIRED_POSITIVE: 'CommonRelationshipBitId' = 164128 + RBC_FRIEND: 'CommonRelationshipBitId' = 15807 + RELATIONSHIP_BIT_COLLECTION_FRIEND_AT_LEAST_FRIEND: 'CommonRelationshipBitId' = 273773 + RELATIONSHIP_BIT_COLLECTION_ROMANTIC: 'CommonRelationshipBitId' = 240628 + RELATIONSHIP_BIT_COLLECTION_ROMANTIC_HAVE_BEEN_EXES: 'CommonRelationshipBitId' = 274292 + RELATIONSHIP_BIT_COLLECTION_SENTIMENT_ADORING: 'CommonRelationshipBitId' = 246492 + RELATIONSHIP_BIT_COLLECTION_SENTIMENT_BITTER: 'CommonRelationshipBitId' = 240104 + RELATIONSHIP_BIT_COLLECTION_SENTIMENT_CLOSE: 'CommonRelationshipBitId' = 240103 + RELATIONSHIP_BIT_COLLECTION_SENTIMENT_ENAMORED: 'CommonRelationshipBitId' = 240107 + RELATIONSHIP_BIT_COLLECTION_SENTIMENT_FURIOUS: 'CommonRelationshipBitId' = 240105 + RELATIONSHIP_BIT_COLLECTION_SENTIMENT_GUILTY: 'CommonRelationshipBitId' = 246491 + RELATIONSHIP_BIT_COLLECTION_SENTIMENT_HURT: 'CommonRelationshipBitId' = 246490 + RELATIONSHIP_BIT_COLLECTION_SENTIMENT_LONG_TERM: 'CommonRelationshipBitId' = 240114 + RELATIONSHIP_BIT_COLLECTION_SENTIMENT_MOTIVATING: 'CommonRelationshipBitId' = 252843 + RELATIONSHIP_BIT_COLLECTION_SENTIMENT_NEGATIVE: 'CommonRelationshipBitId' = 240110 + RELATIONSHIP_BIT_COLLECTION_SENTIMENT_POSITIVE: 'CommonRelationshipBitId' = 240109 + RELATIONSHIP_BIT_COLLECTION_SENTIMENT_SHORT_TERM: 'CommonRelationshipBitId' = 240113 + RELATIONSHIP_BIT_CO_WORKERS: 'CommonRelationshipBitId' = 107373 + RELATIONSHIP_BIT_KNOWS_IS_ALIEN: 'CommonRelationshipBitId' = 103299 + RELATIONSHIP_BIT_KNOWS_IS_ALIEN_BOTH_SIMS_ARE_ALIENS: 'CommonRelationshipBitId' = 116465 + RETAIL_EMPLOYEES_WONT_TALK_TO_LOT_OWNERS: 'CommonRelationshipBitId' = 117017 + RIVALRY_DEFAULT: 'CommonRelationshipBitId' = 161997 + ROBOT_ACTIVATION_MARKER: 'CommonRelationshipBitId' = 230574 + ROBOT_CREATION: 'CommonRelationshipBitId' = 218722 + ROBOT_CREATOR: 'CommonRelationshipBitId' = 218723 + ROMANCE_FAITHFUL: 'CommonRelationshipBitId' = 187709 + ROMANCE_NEUTRAL_BIT: 'CommonRelationshipBitId' = 15810 + ROMANTIC_BROKEN_UP: 'CommonRelationshipBitId' = 15811 + ROMANTIC_BROKEN_UP_ENGAGED: 'CommonRelationshipBitId' = 15812 + ROMANTIC_CHEATED_WITH: 'CommonRelationshipBitId' = 37265 + ROMANTIC_COMBO_ACQUAINTANCES: 'CommonRelationshipBitId' = 77585 + ROMANTIC_COMBO_AWKWARD_FRIENDS: 'CommonRelationshipBitId' = 15826 + ROMANTIC_COMBO_AWKWARD_LOVERS: 'CommonRelationshipBitId' = 15827 + ROMANTIC_COMBO_BAD_MATCH: 'CommonRelationshipBitId' = 15828 + ROMANTIC_COMBO_BAD_ROMANCE: 'CommonRelationshipBitId' = 15843 + ROMANTIC_COMBO_DESPISED: 'CommonRelationshipBitId' = 77648 + ROMANTIC_COMBO_DISLIKED: 'CommonRelationshipBitId' = 77647 + ROMANTIC_COMBO_ENEMIES_WITH_BENEFITS: 'CommonRelationshipBitId' = 15830 + ROMANTIC_COMBO_FRENEMIES: 'CommonRelationshipBitId' = 15831 + ROMANTIC_COMBO_HOT_AND_COLD: 'CommonRelationshipBitId' = 15832 + ROMANTIC_COMBO_ITS_AWKWARD: 'CommonRelationshipBitId' = 15833 + ROMANTIC_COMBO_ITS_COMPLICATED: 'CommonRelationshipBitId' = 15834 + ROMANTIC_COMBO_ITS_VERY_AWKWARD: 'CommonRelationshipBitId' = 15835 + ROMANTIC_COMBO_ITS_VERY_COMPLICATED: 'CommonRelationshipBitId' = 15836 + ROMANTIC_COMBO_JUST_FRIENDS: 'CommonRelationshipBitId' = 77633 + ROMANTIC_COMBO_JUST_GOOD_FRIENDS: 'CommonRelationshipBitId' = 77634 + ROMANTIC_COMBO_LOVEBIRDS: 'CommonRelationshipBitId' = 15829 + ROMANTIC_COMBO_LOVERS: 'CommonRelationshipBitId' = 15837 + ROMANTIC_COMBO_ROMANTIC_INTEREST: 'CommonRelationshipBitId' = 15838 + ROMANTIC_COMBO_SOUL_MATES: 'CommonRelationshipBitId' = 15839 + ROMANTIC_COMBO_SWEETHEARTS: 'CommonRelationshipBitId' = 15840 + ROMANTIC_COMBO_TERRIBLE_MATCH: 'CommonRelationshipBitId' = 15841 + ROMANTIC_COMBO_TOTAL_OPPOSITES: 'CommonRelationshipBitId' = 15842 + ROMANTIC_DEAD_SPOUSE: 'CommonRelationshipBitId' = 104161 + ROMANTIC_DESPISED_EX: 'CommonRelationshipBitId' = 15814 + ROMANTIC_DIVORCED: 'CommonRelationshipBitId' = 15815 + ROMANTIC_ENGAGED: 'CommonRelationshipBitId' = 15816 + ROMANTIC_EXCHANGED_NUMBERS: 'CommonRelationshipBitId' = 127076 + ROMANTIC_FATED_MATES: 'CommonRelationshipBitId' = 293538 + ROMANTIC_FIRST_KISS: 'CommonRelationshipBitId' = 10150 + ROMANTIC_FRUSTRATED_EX: 'CommonRelationshipBitId' = 15817 + ROMANTIC_GETTING_MARRIED: 'CommonRelationshipBitId' = 15818 + ROMANTIC_GOT_COLD_FEET: 'CommonRelationshipBitId' = 15819 + ROMANTIC_HAS_BEEN_UNFAITHFUL: 'CommonRelationshipBitId' = 36957 + ROMANTIC_HAVE_DONE_WOOHOO: 'CommonRelationshipBitId' = 34619 + ROMANTIC_HAVE_DONE_WOOHOO_RECENTLY: 'CommonRelationshipBitId' = 97154 + ROMANTIC_LEAVE_AT_THE_ALTAR: 'CommonRelationshipBitId' = 39356 + ROMANTIC_LEFT_AT_THE_ALTAR: 'CommonRelationshipBitId' = 15821 + ROMANTIC_MARRIED: 'CommonRelationshipBitId' = 15822 + ROMANTIC_MARRIED_NEWLY_WED: 'CommonRelationshipBitId' = 274846 + ROMANTIC_PROMISED: 'CommonRelationshipBitId' = 99429 + ROMANTIC_RENEWING_VOWS: 'CommonRelationshipBitId' = 99616 + ROMANTIC_SIGNIFICANT_OTHER: 'CommonRelationshipBitId' = 15825 + ROMANTIC_WIDOW: 'CommonRelationshipBitId' = 102081 + ROMANTIC_WIDOWER: 'CommonRelationshipBitId' = 102911 + ROOMMATE_NPC: 'CommonRelationshipBitId' = 209563 + SECRET_AGENT_DEFEATED_SUPER_VILLAIN: 'CommonRelationshipBitId' = 99522 + SECRET_AGENT_EXPOSED_AS_SUPER_VILLAIN: 'CommonRelationshipBitId' = 38788 + SECRET_AGENT_INVESTIGATED: 'CommonRelationshipBitId' = 37066 + SECRET_AGENT_KNOWN_SUPER_VILLAIN: 'CommonRelationshipBitId' = 38790 + SENTIMENT_LONG_TERM_ADORING_LIFESAVER: 'CommonRelationshipBitId' = 246646 + SENTIMENT_LONG_TERM_ADORING_WEDDING_TRADITION_BEST_MAN: 'CommonRelationshipBitId' = 276284 + SENTIMENT_LONG_TERM_ADORING_WEDDING_TRADITION_MAID_OF_HONOR: 'CommonRelationshipBitId' = 276285 + SENTIMENT_LONG_TERM_BITTER_CHEATING: 'CommonRelationshipBitId' = 246536 + SENTIMENT_LONG_TERM_BITTER_GRUDGE: 'CommonRelationshipBitId' = 239982 + SENTIMENT_LONG_TERM_BITTER_MOUNTAIN_CLIMB_ACT2_CANCELLATION: 'CommonRelationshipBitId' = 249892 + SENTIMENT_LONG_TERM_CLOSE_GENERIC: 'CommonRelationshipBitId' = 239984 + SENTIMENT_LONG_TERM_CLOSE_I_KNOW_THEY_HAVE_GOT_MY_BACK: 'CommonRelationshipBitId' = 273246 + SENTIMENT_LONG_TERM_CLOSE_LYCAN_BOND: 'CommonRelationshipBitId' = 288810 + SENTIMENT_LONG_TERM_CLOSE_MOUNTAIN_CLIMB_ACT3_GOLD: 'CommonRelationshipBitId' = 249898 + SENTIMENT_LONG_TERM_CLOSE_THEY_UNDERSTAND: 'CommonRelationshipBitId' = 273068 + SENTIMENT_LONG_TERM_CLOSE_TWO_PEAS_IN_A_POD: 'CommonRelationshipBitId' = 273067 + SENTIMENT_LONG_TERM_CRUSH_GENERIC: 'CommonRelationshipBitId' = 272840 + SENTIMENT_LONG_TERM_ENAMORED_COTTAGE_WORLD_RUINS: 'CommonRelationshipBitId' = 268491 + SENTIMENT_LONG_TERM_ENAMORED_FATED_TO_WED: 'CommonRelationshipBitId' = 293551 + SENTIMENT_LONG_TERM_ENAMORED_FULL_MOON_FIRST_KISS: 'CommonRelationshipBitId' = 290598 + SENTIMENT_LONG_TERM_ENAMORED_GENERIC: 'CommonRelationshipBitId' = 246613 + SENTIMENT_LONG_TERM_ENAMORED_LIGHT_FESTIVAL_KISS: 'CommonRelationshipBitId' = 253185 + SENTIMENT_LONG_TERM_ENAMORED_MOUNTAIN_CLIMB: 'CommonRelationshipBitId' = 252690 + SENTIMENT_LONG_TERM_ENAMORED_MOUNTAIN_NEIGHBORHOOD: 'CommonRelationshipBitId' = 252689 + SENTIMENT_LONG_TERM_GUILTY_FATE_DEFIED: 'CommonRelationshipBitId' = 293552 + SENTIMENT_LONG_TERM_GUILTY_MOUNTAIN_CLIMB_ACT_2_CANCELLATION: 'CommonRelationshipBitId' = 249896 + SENTIMENT_LONG_TERM_HURT_GENERIC: 'CommonRelationshipBitId' = 246637 + SENTIMENT_LONG_TERM_NEEDS_DISTANCE_PROPOSAL: 'CommonRelationshipBitId' = 278170 + SENTIMENT_LONG_TERM_REJECTED_PROPOSAL: 'CommonRelationshipBitId' = 278176 + SENTIMENT_SHORT_TERM_ADORING_CONSOLE_DEATH: 'CommonRelationshipBitId' = 273923 + SENTIMENT_SHORT_TERM_ADORING_DECORATOR_GOOD_BUILD: 'CommonRelationshipBitId' = 268267 + SENTIMENT_SHORT_TERM_ADORING_GENERIC: 'CommonRelationshipBitId' = 246530 + SENTIMENT_SHORT_TERM_ADORING_IMPRESSED: 'CommonRelationshipBitId' = 246535 + SENTIMENT_SHORT_TERM_ADORING_WEDDING_TRADITION_GAVE_GOOD_SPEECH: 'CommonRelationshipBitId' = 276548 + SENTIMENT_SHORT_TERM_BITTER_BREAKUP: 'CommonRelationshipBitId' = 246538 + SENTIMENT_SHORT_TERM_BITTER_CRUMPLE_BOTTOMED: 'CommonRelationshipBitId' = 264465 + SENTIMENT_SHORT_TERM_BITTER_DIVORCE: 'CommonRelationshipBitId' = 246539 + SENTIMENT_SHORT_TERM_BITTER_EXCURSION_CANCEL_ACT1: 'CommonRelationshipBitId' = 249751 + SENTIMENT_SHORT_TERM_BITTER_FIGHT: 'CommonRelationshipBitId' = 246597 + SENTIMENT_SHORT_TERM_BITTER_GRUDGE_AGAINST_PACK_A: 'CommonRelationshipBitId' = 290940 + SENTIMENT_SHORT_TERM_BITTER_GRUDGE_AGAINST_PACK_B: 'CommonRelationshipBitId' = 290941 + SENTIMENT_SHORT_TERM_BITTER_HIGH_SCHOOL_PROM_NO_PROM_INVITE: 'CommonRelationshipBitId' = 282640 + SENTIMENT_SHORT_TERM_BITTER_HIKING_TRAIL_GROUP_HIKE_TIN_REWARD: 'CommonRelationshipBitId' = 250363 + SENTIMENT_SHORT_TERM_BITTER_LIFESTYLE_WORKAHOLIC: 'CommonRelationshipBitId' = 252693 + SENTIMENT_SHORT_TERM_BITTER_LIVESTOCK_SOLD: 'CommonRelationshipBitId' = 263707 + SENTIMENT_SHORT_TERM_BITTER_OPENABLE_WINDOW_FAIL_EVENT: 'CommonRelationshipBitId' = 283047 + SENTIMENT_SHORT_TERM_BITTER_VILLAGE_FAIR_BRIBE_FAIL: 'CommonRelationshipBitId' = 268415 + SENTIMENT_SHORT_TERM_BITTER_WEDDING_TRADITION_NOT_INVITED_TO_WEDDING: 'CommonRelationshipBitId' = 276835 + SENTIMENT_SHORT_TERM_BITTER_WEDDING_TRADITION_NOT_SELECTED_BEST_MAN: 'CommonRelationshipBitId' = 276551 + SENTIMENT_SHORT_TERM_BITTER_WEDDING_TRADITION_NOT_SELECTED_MAID_OF_HONOR: 'CommonRelationshipBitId' = 276553 + SENTIMENT_SHORT_TERM_BITTER_YOGA_CLASS: 'CommonRelationshipBitId' = 271953 + SENTIMENT_SHORT_TERM_CLOSE_ADOPTION: 'CommonRelationshipBitId' = 246610 + SENTIMENT_SHORT_TERM_CLOSE_CANNING_RECEIVE_GIFT: 'CommonRelationshipBitId' = 260816 + SENTIMENT_SHORT_TERM_CLOSE_COTTAGE_WORLD_NPC_GOSSIP: 'CommonRelationshipBitId' = 264954 + SENTIMENT_SHORT_TERM_CLOSE_GENERIC: 'CommonRelationshipBitId' = 246604 + SENTIMENT_SHORT_TERM_CLOSE_GOOD_FIRST_IMPRESSION: 'CommonRelationshipBitId' = 273242 + SENTIMENT_SHORT_TERM_CLOSE_GROUP_COOKING_COOKING_TOGETHER: 'CommonRelationshipBitId' = 262317 + SENTIMENT_SHORT_TERM_CLOSE_HIGH_SCHOOL_PROM_SKIPPING_PROM_TOGETHER: 'CommonRelationshipBitId' = 282637 + SENTIMENT_SHORT_TERM_CLOSE_HIKING_TRAIL_GROUP_HIKE_GOLD_REWARD: 'CommonRelationshipBitId' = 250366 + SENTIMENT_SHORT_TERM_CLOSE_HOTPOT: 'CommonRelationshipBitId' = 252685 + SENTIMENT_SHORT_TERM_CLOSE_LIFESTYLE_CLOSE_KNIT: 'CommonRelationshipBitId' = 252687 + SENTIMENT_SHORT_TERM_CLOSE_LIGHT_FESTIVAL_WISH: 'CommonRelationshipBitId' = 253253 + SENTIMENT_SHORT_TERM_CLOSE_NEAR_DEATH: 'CommonRelationshipBitId' = 246647 + SENTIMENT_SHORT_TERM_CLOSE_ONSEN: 'CommonRelationshipBitId' = 252680 + SENTIMENT_SHORT_TERM_CLOSE_OPENABLE_WINDOW_SUCCESS_EVENT: 'CommonRelationshipBitId' = 283050 + SENTIMENT_SHORT_TERM_CLOSE_PARTY: 'CommonRelationshipBitId' = 246606 + SENTIMENT_SHORT_TERM_CLOSE_PICNIC_BASKET_PICNIC_BONDING: 'CommonRelationshipBitId' = 260815 + SENTIMENT_SHORT_TERM_CLOSE_QUALITY_TIME: 'CommonRelationshipBitId' = 246603 + SENTIMENT_SHORT_TERM_CLOSE_SNOW: 'CommonRelationshipBitId' = 252567 + SENTIMENT_SHORT_TERM_CLOSE_SNOW_FESTIVAL_PARTY: 'CommonRelationshipBitId' = 253207 + SENTIMENT_SHORT_TERM_CLOSE_SNOW_FESTIVAL_PLAY: 'CommonRelationshipBitId' = 253194 + SENTIMENT_SHORT_TERM_CLOSE_TEA_SET_TEA_PARTY: 'CommonRelationshipBitId' = 280848 + SENTIMENT_SHORT_TERM_CLOSE_THROW_FOOTBALL_BONDING_MOMENT: 'CommonRelationshipBitId' = 286015 + SENTIMENT_SHORT_TERM_CLOSE_TRUSTING: 'CommonRelationshipBitId' = 283871 + SENTIMENT_SHORT_TERM_CLOSE_VACATION_SNOWY: 'CommonRelationshipBitId' = 252426 + SENTIMENT_SHORT_TERM_CLOSE_VILLAGER_HELP_HELPED_OUT: 'CommonRelationshipBitId' = 266363 + SENTIMENT_SHORT_TERM_CLOSE_VILLAGE_FAIR_BRIBE_SUCCESS: 'CommonRelationshipBitId' = 268392 + SENTIMENT_SHORT_TERM_CLOSE_WOLFY_WARMTH: 'CommonRelationshipBitId' = 290478 + SENTIMENT_SHORT_TERM_CLOSE_YOUTH_FESTIVAL_BLESSED: 'CommonRelationshipBitId' = 253254 + SENTIMENT_SHORT_TERM_ENAMORED_CANNING_GIFT_JAR: 'CommonRelationshipBitId' = 260818 + SENTIMENT_SHORT_TERM_ENAMORED_FATED_MATES: 'CommonRelationshipBitId' = 293545 + SENTIMENT_SHORT_TERM_ENAMORED_GENERIC: 'CommonRelationshipBitId' = 239988 + SENTIMENT_SHORT_TERM_ENAMORED_HIGH_SCHOOL_PROM_IMPRESSED_BY_PROMPOSAL: 'CommonRelationshipBitId' = 282638 + SENTIMENT_SHORT_TERM_ENAMORED_LIFESTYLES_SHARED: 'CommonRelationshipBitId' = 252423 + SENTIMENT_SHORT_TERM_ENAMORED_MOUNTAIN: 'CommonRelationshipBitId' = 252688 + SENTIMENT_SHORT_TERM_ENAMORED_OPPOSITES: 'CommonRelationshipBitId' = 252422 + SENTIMENT_SHORT_TERM_ENAMORED_PAIRED_DANCING_FIRST_DANCE: 'CommonRelationshipBitId' = 280849 + SENTIMENT_SHORT_TERM_FURIOUS_CHEATING: 'CommonRelationshipBitId' = 246622 + SENTIMENT_SHORT_TERM_FURIOUS_DECORATOR_BAD_BUILD: 'CommonRelationshipBitId' = 268257 + SENTIMENT_SHORT_TERM_FURIOUS_GENERIC: 'CommonRelationshipBitId' = 239980 + SENTIMENT_SHORT_TERM_FURIOUS_LIGHT_FESTIVAL_JEALOUS: 'CommonRelationshipBitId' = 253211 + SENTIMENT_SHORT_TERM_FURIOUS_PACK_RIVALRY: 'CommonRelationshipBitId' = 290475 + SENTIMENT_SHORT_TERM_FURIOUS_WEDDING: 'CommonRelationshipBitId' = 246623 + SENTIMENT_SHORT_TERM_FURIOUS_WEDDING_PARTIES_EJECTED_GUEST: 'CommonRelationshipBitId' = 280830 + SENTIMENT_SHORT_TERM_FURIOUS_WEDDING_TRADITION_ATE_CAKE_EARLY: 'CommonRelationshipBitId' = 276559 + SENTIMENT_SHORT_TERM_FURIOUS_WEDDING_TRADITION_GOT_INTO_FIGHT: 'CommonRelationshipBitId' = 276557 + SENTIMENT_SHORT_TERM_FURIOUS_WEDDING_TRADITION_INTERRUPTED_CEREMONY: 'CommonRelationshipBitId' = 276558 + SENTIMENT_SHORT_TERM_FURIOUS_WEDDING_TRADITION_ROMANTICALLY_UP_STAGED: 'CommonRelationshipBitId' = 276660 + SENTIMENT_SHORT_TERM_FURIOUS_WEDDING_TRADITION_YOU_DIED: 'CommonRelationshipBitId' = 276555 + SENTIMENT_SHORT_TERM_GUILTY_ABANDONED_PACK: 'CommonRelationshipBitId' = 290477 + SENTIMENT_SHORT_TERM_GUILTY_AWKWARD_DATE: 'CommonRelationshipBitId' = 246631 + SENTIMENT_SHORT_TERM_GUILTY_BAD_PARTY: 'CommonRelationshipBitId' = 246633 + SENTIMENT_SHORT_TERM_GUILTY_BIG_SAD_WOLF: 'CommonRelationshipBitId' = 288509 + SENTIMENT_SHORT_TERM_GUILTY_GENERIC: 'CommonRelationshipBitId' = 246630 + SENTIMENT_SHORT_TERM_GUILTY_HIGH_SCHOOL_PROM_BROKEN_PACT: 'CommonRelationshipBitId' = 287902 + SENTIMENT_SHORT_TERM_GUILTY_LIFESTYLE_CLOSE_KNIT: 'CommonRelationshipBitId' = 252691 + SENTIMENT_SHORT_TERM_GUILTY_VILLAGE_FAIR_BRIBE_FAIL: 'CommonRelationshipBitId' = 268427 + SENTIMENT_SHORT_TERM_HURT_GENERIC: 'CommonRelationshipBitId' = 246644 + SENTIMENT_SHORT_TERM_HURT_HIGH_SCHOOL_PROM_BROKEN_DITCH_PROMISE: 'CommonRelationshipBitId' = 282639 + SENTIMENT_SHORT_TERM_HURT_HURT_BY_PACK_MATE: 'CommonRelationshipBitId' = 290476 + SENTIMENT_SHORT_TERM_HURT_LIFESTYLE_NETWORKER: 'CommonRelationshipBitId' = 252692 + SENTIMENT_SHORT_TERM_HURT_LIVESTOCK_SOLD: 'CommonRelationshipBitId' = 263706 + SENTIMENT_SHORT_TERM_HURT_REJECTION: 'CommonRelationshipBitId' = 246640 + SENTIMENT_SHORT_TERM_HURT_ROMANTIC: 'CommonRelationshipBitId' = 246638 + SENTIMENT_SHORT_TERM_HURT_SADDENED: 'CommonRelationshipBitId' = 246642 + SENTIMENT_SHORT_TERM_HURT_SUSPICIOUS: 'CommonRelationshipBitId' = 283870 + SENTIMENT_SHORT_TERM_HURT_YOUTH_FESTIVAL_UNBLESSED: 'CommonRelationshipBitId' = 253227 + SENTIMENT_SHORT_TERM_MOTIVATING_EXTREME_SPORTS: 'CommonRelationshipBitId' = 252845 + SENTIMENT_SHORT_TERM_MOTIVATING_FRIENDLY_ADVICE: 'CommonRelationshipBitId' = 273845 + SENTIMENT_SHORT_TERM_NEEDS_DISTANCE_FRIEND: 'CommonRelationshipBitId' = 278173 + SENTIMENT_SHORT_TERM_NEEDS_DISTANCE_GENERIC_ROMANTIC: 'CommonRelationshipBitId' = 278172 + SENTIMENT_SHORT_TERM_REJECTED_FRIEND: 'CommonRelationshipBitId' = 278178 + SENTIMENT_SHORT_TERM_REJECTED_GENERIC_ROMANTIC: 'CommonRelationshipBitId' = 278177 + SEXUAL_ORIENTATION_WOOHOO_PARTNERS: 'CommonRelationshipBitId' = 291678 + SHORT_TERMS_ASKED_ABOUT_SENTIMENT_COOLDOWN: 'CommonRelationshipBitId' = 250188 + SHORT_TERM_BITS_ARGUMENTS_HAD_ARGUMENT: 'CommonRelationshipBitId' = 162652 + SHORT_TERM_BITS_CLUBS_NEW_MEMBER_GREETED: 'CommonRelationshipBitId' = 130611 + SHORT_TERM_BITS_KICKED_OUT_INAPPROPRIATE_BEHAVIOR: 'CommonRelationshipBitId' = 129869 + SHORT_TERM_BITS_QUICK_SOCIAL_HUG_NOT_VISIBLE: 'CommonRelationshipBitId' = 77250 + SHORT_TERM_BITS_QUICK_SOCIAL_KISS_NOT_VISIBLE: 'CommonRelationshipBitId' = 77251 + SHORT_TERM_BITS_QUICK_SOCIAL_SHOW_FUNNY_VIDEO_NOT_VISIBLE: 'CommonRelationshipBitId' = 77252 + SHORT_TERM_BITS_RESTAURANTS_DINING: 'CommonRelationshipBitId' = 132610 + SHORT_TERM_BITS_TREAD_MILL_ROCK_CLIMBING_WALL_BEAT_HIGH_SCORE: 'CommonRelationshipBitId' = 167893 + SHORT_TERM_HEALED_NEGATIVE_SENTIMENT: 'CommonRelationshipBitId' = 250815 + SHORT_TERM_HIGH_SCHOOL_ACTIVE_ASKED_CAREER_DETAILS: 'CommonRelationshipBitId' = 289096 + SHORT_TERM_IN_FIGHT_WITH: 'CommonRelationshipBitId' = 15845 + SHORT_TERM_IN_QUARREL_WITH: 'CommonRelationshipBitId' = 15846 + SHORT_TERM_JUST_BROKE_UP_OR_DIVORCED: 'CommonRelationshipBitId' = 97332 + SHORT_TERM_MIND_POWERS_ALLURING_VISAGE_SOCIAL_ENCOURAGE: 'CommonRelationshipBitId' = 150062 + SHORT_TERM_ORDERING_SIM: 'CommonRelationshipBitId' = 265566 + SHORT_TERM_RECENT_FIRST_KISS: 'CommonRelationshipBitId' = 77371 + SHORT_TERM_RECENT_NEGATIVE_SOCIAL: 'CommonRelationshipBitId' = 99712 + SHORT_TERM_SNOOPED_IN_JOURNAL: 'CommonRelationshipBitId' = 160252 + SHORT_TERM_SOCIAL_MEDIA_CAREER_REPRESENT: 'CommonRelationshipBitId' = 145918 + SHORT_TERM_VILLAGER_HELP_SHORT_SOCIAL_PACKAGE_COOLDOWN: 'CommonRelationshipBitId' = 263907 + SHORT_TERM_WEDDING_TRADITION_ASK_TO_BE_IN_WEDDING_PARTY: 'CommonRelationshipBitId' = 276839 + SHORT_TERM_WEDDING_TRADITION_ASK_TO_COME_TO_WEDDING: 'CommonRelationshipBitId' = 276837 + SIM_TO_ANIMAL_OBJECT_ACQUAINTANCES: 'CommonRelationshipBitId' = 271028 + SIM_TO_ANIMAL_OBJECT_DESPISED: 'CommonRelationshipBitId' = 271030 + SIM_TO_ANIMAL_OBJECT_DISLIKED: 'CommonRelationshipBitId' = 271029 + SIM_TO_ANIMAL_OBJECT_FRIEND: 'CommonRelationshipBitId' = 271026 + SIM_TO_ANIMAL_OBJECT_GOOD_FRIEND: 'CommonRelationshipBitId' = 271027 + SIM_TO_DOLPHIN_BEST_FRIEND: 'CommonRelationshipBitId' = 207283 + SIM_TO_DOLPHIN_CHUM: 'CommonRelationshipBitId' = 207281 + SIM_TO_DOLPHIN_CURIOUS: 'CommonRelationshipBitId' = 207280 + SIM_TO_DOLPHIN_DISLIKED: 'CommonRelationshipBitId' = 207277 + SIM_TO_DOLPHIN_FEARED: 'CommonRelationshipBitId' = 207276 + SIM_TO_DOLPHIN_FRIEND: 'CommonRelationshipBitId' = 207282 + SIM_TO_DOLPHIN_INDIFFERENT: 'CommonRelationshipBitId' = 207279 + SIM_TO_DOLPHIN_SOULMATE: 'CommonRelationshipBitId' = 207284 + SIM_TO_DOLPHIN_WARY: 'CommonRelationshipBitId' = 207278 + SIM_TO_PET_00_DESPISED: 'CommonRelationshipBitId' = 159231 + SIM_TO_PET_01_DISLIKED: 'CommonRelationshipBitId' = 159232 + SIM_TO_PET_02_ACQUAINTANCE: 'CommonRelationshipBitId' = 159233 + SIM_TO_PET_03_FRIEND: 'CommonRelationshipBitId' = 159236 + SIM_TO_PET_04_GOOD_FRIEND: 'CommonRelationshipBitId' = 159234 + SIM_TO_PET_05_COMPANION: 'CommonRelationshipBitId' = 159235 + SIM_TO_PET_INDIFFERENT_NEUTRAL_BIT: 'CommonRelationshipBitId' = 159230 + SITUATION_BIT_BIRTHDAY_GUEST: 'CommonRelationshipBitId' = 38420 + SITUATION_BIT_WEDDING_COUPLE: 'CommonRelationshipBitId' = 38422 + SITUATION_BIT_WEDDING_GUEST: 'CommonRelationshipBitId' = 38421 + SITUATION_BIT_WELCOME_WAGON_GUEST: 'CommonRelationshipBitId' = 120016 + SITUATION_BIT_WOLF_TOWN_SPARRING_PARTNER: 'CommonRelationshipBitId' = 291740 + SNOW_BRO: 'CommonRelationshipBitId' = 246797 + SOCCER_TEAM_TEAMMATES: 'CommonRelationshipBitId' = 221133 + SOCIAL_CONTEXT_AWKWARDNESS_AWKWARD: 'CommonRelationshipBitId' = 24089 + SOCIAL_CONTEXT_AWKWARDNESS_CASUAL: 'CommonRelationshipBitId' = 115902 + SOCIAL_CONTEXT_AWKWARDNESS_VERY_AWKWARD: 'CommonRelationshipBitId' = 24090 + SOCIAL_CONTEXT_BIT_INTERROGATION_TABLE_CALM: 'CommonRelationshipBitId' = 103962 + SOCIAL_CONTEXT_BIT_INTERROGATION_TABLE_DEFENSIVE: 'CommonRelationshipBitId' = 103961 + SOCIAL_CONTEXT_BIT_INTERROGATION_TABLE_FRIENDLY: 'CommonRelationshipBitId' = 103960 + SOCIAL_CONTEXT_BIT_INTERROGATION_TABLE_FURIOUS: 'CommonRelationshipBitId' = 103959 + SOCIAL_CONTEXT_BIT_INTERROGATION_TABLE_SHY: 'CommonRelationshipBitId' = 103958 + SOCIAL_CONTEXT_BIT_INTERROGATION_TABLE_SMUG: 'CommonRelationshipBitId' = 104781 + SOCIAL_CONTEXT_BIT_INTERROGATION_TABLE_SUSPICIOUS: 'CommonRelationshipBitId' = 103957 + SOCIAL_CONTEXT_BIT_INTERROGATION_TABLE_TENSE: 'CommonRelationshipBitId' = 103956 + SOCIAL_CONTEXT_BIT_INTERROGATION_TABLE_TENSE_DEFAULT: 'CommonRelationshipBitId' = 105228 + SOCIAL_CONTEXT_BIT_INTERROGATION_TABLE_TERRIFIED: 'CommonRelationshipBitId' = 103636 + SOCIAL_CONTEXT_BIT_INTERROGATION_TABLE_VERY_WORRIED: 'CommonRelationshipBitId' = 103955 + SOCIAL_CONTEXT_BIT_INTERROGATION_TABLE_WORRIED: 'CommonRelationshipBitId' = 103953 + SOCIAL_CONTEXT_CASUAL: 'CommonRelationshipBitId' = 24032 + SOCIAL_CONTEXT_FRIENDSHIP_ABHORRENT: 'CommonRelationshipBitId' = 24088 + SOCIAL_CONTEXT_FRIENDSHIP_DISTASTEFUL: 'CommonRelationshipBitId' = 24086 + SOCIAL_CONTEXT_FRIENDSHIP_FRIENDLY: 'CommonRelationshipBitId' = 24085 + SOCIAL_CONTEXT_FRIENDSHIP_OFFENSIVE: 'CommonRelationshipBitId' = 24087 + SOCIAL_CONTEXT_FUN_BORING: 'CommonRelationshipBitId' = 24081 + SOCIAL_CONTEXT_FUN_CASUAL: 'CommonRelationshipBitId' = 115903 + SOCIAL_CONTEXT_FUN_FUNNY: 'CommonRelationshipBitId' = 24077 + SOCIAL_CONTEXT_FUN_HILARIOUS: 'CommonRelationshipBitId' = 24079 + SOCIAL_CONTEXT_FUN_INSUFFERABLY_TEDIOUS: 'CommonRelationshipBitId' = 24083 + SOCIAL_CONTEXT_FUN_TEDIOUS: 'CommonRelationshipBitId' = 24082 + SOCIAL_CONTEXT_RETAIL_MILDLY_INTERESTED: 'CommonRelationshipBitId' = 111602 + SOCIAL_CONTEXT_RETAIL_UNINTERESTED: 'CommonRelationshipBitId' = 111600 + SOCIAL_CONTEXT_RETAIL_VERY_INTERESTED: 'CommonRelationshipBitId' = 111601 + SOCIAL_CONTEXT_ROMANCE_AMOROUS: 'CommonRelationshipBitId' = 24076 + SOCIAL_CONTEXT_ROMANCE_CASUAL: 'CommonRelationshipBitId' = 115904 + SOCIAL_CONTEXT_ROMANCE_STEAMY: 'CommonRelationshipBitId' = 24080 + SOCIAL_CONTEXT_ROMANCE_SUGGESTIVE: 'CommonRelationshipBitId' = 24078 + SOCIAL_MEDIA_CONTACTLIST: 'CommonRelationshipBitId' = 277014 + SPECIAL_BITS_ARCH_ENEMIES: 'CommonRelationshipBitId' = 26561 + SPECIAL_BITS_DECLARED_ARCH_ENEMY: 'CommonRelationshipBitId' = 26566 + SPECIAL_BITS_ENEMY: 'CommonRelationshipBitId' = 26560 + SPECIAL_BITS_GREETED: 'CommonRelationshipBitId' = 122768 + SPELLS_MIND_CONTROLLED: 'CommonRelationshipBitId' = 216188 + SQUAD_MEMBER: 'CommonRelationshipBitId' = 196234 + SUMMON_GHOST_FAIL: 'CommonRelationshipBitId' = 215677 + TANDEM_SLEDDERS: 'CommonRelationshipBitId' = 251537 + TENANT: 'CommonRelationshipBitId' = 148657 + TODDLER_CARE_DEPENDENT_EFFECTIVE: 'CommonRelationshipBitId' = 155923 + TODDLER_CARE_GIVER_EFFECTIVE: 'CommonRelationshipBitId' = 155918 + TODDLER_NOT_PARENT_CARE_DEPENDENT: 'CommonRelationshipBitId' = 152851 + TODDLER_NOT_PARENT_CARE_GIVER: 'CommonRelationshipBitId' = 146488 + TODDLER_STRANGER: 'CommonRelationshipBitId' = 141125 + TRY_TO_GREET: 'CommonRelationshipBitId' = 194904 + VAMPIRE_MASTER: 'CommonRelationshipBitId' = 149548 + VAMPIRE_OFFSPRING: 'CommonRelationshipBitId' = 149549 + VILLAGER_HELP_AGATHA_2_ACCEPTED_ROSE: 'CommonRelationshipBitId' = 269871 + VILLAGER_HELP_AGATHA_2_SOLD_TO: 'CommonRelationshipBitId' = 268939 + VILLAGER_HELP_GOT_GROCERY_ORDER_ALREADY: 'CommonRelationshipBitId' = 267298 + VILLAGER_HELP_MYSTERY_GIFTER_NO: 'CommonRelationshipBitId' = 265418 + VILLAGER_HELP_MYSTERY_GIFTER_YES: 'CommonRelationshipBitId' = 265417 + WEDDING_CUSTOM_STATE_FLOWER_SPREADER: 'CommonRelationshipBitId' = 275958 + WEDDING_CUSTOM_STATE_FLOWER_SPREADER_SIGNIFICANT_OTHER: 'CommonRelationshipBitId' = 281996 + WEDDING_CUSTOM_STATE_HONORED_WEDDING_PARTY: 'CommonRelationshipBitId' = 283690 + WEDDING_CUSTOM_STATE_HONOR_ATTENDANT: 'CommonRelationshipBitId' = 275959 + WEDDING_CUSTOM_STATE_HONOR_ATTENDANT_SIGNIFICANT_OTHER: 'CommonRelationshipBitId' = 281997 + WEDDING_CUSTOM_STATE_OFFICIANT: 'CommonRelationshipBitId' = 275957 + WEDDING_CUSTOM_STATE_OFFICIANT_SIGNIFICANT_OTHER: 'CommonRelationshipBitId' = 281998 + WEDDING_CUSTOM_STATE_RING_BEARER: 'CommonRelationshipBitId' = 279776 + WEDDING_CUSTOM_STATE_RING_BEARER_SIGNIFICANT_OTHER: 'CommonRelationshipBitId' = 281999 + WEDDING_VOW_RENEWAL_CUSTOM_STATE_HONOR_ATTENDANT: 'CommonRelationshipBitId' = 289919 + WEDDING_VOW_RENEWAL_CUSTOM_STATE_HONOR_ATTENDANT_SIGNIFICANT_OTHER: 'CommonRelationshipBitId' = 289920 + WELLNESS_REPEAT_CUSTOMER: 'CommonRelationshipBitId' = 276949 + WRITING_JOURNALISM_ARTICLE_INTERVIEW: 'CommonRelationshipBitId' = 33719 + WRITING_JOURNALISM_ARTICLE_INTERVIEW_NEGATIVE: 'CommonRelationshipBitId' = 33720 + WRITING_JOURNALISM_ARTICLE_INTERVIEW_POSITIVE: 'CommonRelationshipBitId' = 33721 diff --git a/Scripts/s4ap/sims4communitylib/enums/relationship_tracks_enum.py b/Scripts/s4ap/sims4communitylib/enums/relationship_tracks_enum.py new file mode 100644 index 0000000..3d26d72 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/relationship_tracks_enum.py @@ -0,0 +1,23 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonRelationshipTrackId(CommonInt): + """Identifiers for vanilla sim relationship tracks. + + """ + INVALID: 'CommonRelationshipTrackId' = 0 + AUTHORITY: 'CommonRelationshipTrackId' = 161998 + FEUD: 'CommonRelationshipTrackId' = 193901 + FRIENDSHIP: 'CommonRelationshipTrackId' = 16650 + MISCHIEF: 'CommonRelationshipTrackId' = 26920 + RIVALRY: 'CommonRelationshipTrackId' = 161999 + ROMANCE: 'CommonRelationshipTrackId' = 16651 + SIM_TO_PET_FRIENDSHIP: 'CommonRelationshipTrackId' = 159228 + SMART_HUB_FRIENDSHIP: 'CommonRelationshipTrackId' = 203686 diff --git a/Scripts/s4ap/sims4communitylib/enums/relationship_types_enum.py b/Scripts/s4ap/sims4communitylib/enums/relationship_types_enum.py new file mode 100644 index 0000000..c6d0c34 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/relationship_types_enum.py @@ -0,0 +1,21 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonRelationshipTypeId(CommonInt): + """Identifiers for relationship types.""" + INVALID: 'CommonRelationshipTypeId' = 0 + ROMANTIC: 'CommonRelationshipTypeId' = 2 + UPSET_WITH: 'CommonRelationshipTypeId' = 3 + FAMILY: 'CommonRelationshipTypeId' = 4 + SIGNIFICANT_OTHER: 'CommonRelationshipTypeId' = 5 + WRITING_JOURNALISM_INTERVIEW: 'CommonRelationshipTypeId' = 6 + ACQUIRED_FAMILY: 'CommonRelationshipTypeId' = 7 + PET_RELATIONSHIP: 'CommonRelationshipTypeId' = 8 + SENTIMENT: 'CommonRelationshipTypeId' = 9 diff --git a/Scripts/s4ap/sims4communitylib/enums/short_term_relationship_tracks_enum.py b/Scripts/s4ap/sims4communitylib/enums/short_term_relationship_tracks_enum.py new file mode 100644 index 0000000..d401670 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/short_term_relationship_tracks_enum.py @@ -0,0 +1,30 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonShortTermRelationshipTrackId(CommonInt): + """Identifiers for vanilla sim short-term relationship tracks. + + """ + INVALID: 'CommonShortTermRelationshipTrackId' = 0 + AWKWARDNESS: 'CommonShortTermRelationshipTrackId' = 24098 + FRIENDSHIP: 'CommonShortTermRelationshipTrackId' = 24099 + FUN: 'CommonShortTermRelationshipTrackId' = 24100 + INTERROGATION_TABLE_CALM: 'CommonShortTermRelationshipTrackId' = 103618 + INTERROGATION_TABLE_DEFENSIVE: 'CommonShortTermRelationshipTrackId' = 103617 + INTERROGATION_TABLE_FRIENDLY: 'CommonShortTermRelationshipTrackId' = 103613 + INTERROGATION_TABLE_FURIOUS: 'CommonShortTermRelationshipTrackId' = 103616 + INTERROGATION_TABLE_SHY: 'CommonShortTermRelationshipTrackId' = 103598 + INTERROGATION_TABLE_SMUG: 'CommonShortTermRelationshipTrackId' = 103619 + INTERROGATION_TABLE_SUSPICIOUS: 'CommonShortTermRelationshipTrackId' = 103612 + INTERROGATION_TABLE_TENSE: 'CommonShortTermRelationshipTrackId' = 103615 + INTERROGATION_TABLE_TERRIFIED: 'CommonShortTermRelationshipTrackId' = 103614 + INTERROGATION_TABLE_WORRIED: 'CommonShortTermRelationshipTrackId' = 103620 + RETAIL_PURCHASE_INTEREST: 'CommonShortTermRelationshipTrackId' = 111598 + ROMANCE: 'CommonShortTermRelationshipTrackId' = 24101 diff --git a/Scripts/s4ap/sims4communitylib/enums/short_term_sentiments_enum.py b/Scripts/s4ap/sims4communitylib/enums/short_term_sentiments_enum.py new file mode 100644 index 0000000..fb96606 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/short_term_sentiments_enum.py @@ -0,0 +1,107 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonShortTermSentimentId(CommonInt): + """Identifiers for vanilla short term sentiments.""" + INVALID: 'CommonShortTermSentimentId' = 0 + ADORING_CONSOLE_DEATH: 'CommonShortTermSentimentId' = 273923 + ADORING_DECORATOR_GOOD_BUILD: 'CommonShortTermSentimentId' = 268267 + ADORING_GENERIC: 'CommonShortTermSentimentId' = 246530 + ADORING_IMPRESSED: 'CommonShortTermSentimentId' = 246535 + ADORING_WEDDING_TRADITION_GAVE_GOOD_SPEECH: 'CommonShortTermSentimentId' = 276548 + BITTER_CRUMPLE_BOTTOMED: 'CommonShortTermSentimentId' = 264465 + BITTER_BREAKUP: 'CommonShortTermSentimentId' = 246538 + BITTER_DIVORCE: 'CommonShortTermSentimentId' = 246539 + BITTER_EXCURSION_CANCEL_ACT1: 'CommonShortTermSentimentId' = 249751 + BITTER_FIGHT: 'CommonShortTermSentimentId' = 246597 + BITTER_GRUDGE_AGAINST_PACK_A: 'CommonShortTermSentimentId' = 290940 + BITTER_GRUDGE_AGAINST_PACK_B: 'CommonShortTermSentimentId' = 290941 + BITTER_HIGH_SCHOOL_PROM_NO_PROM_INVITE: 'CommonShortTermSentimentId' = 282640 + BITTER_HIKING_TRAIL_GROUP_HIKE_TIN_REWARD: 'CommonShortTermSentimentId' = 250363 + BITTER_LIFESTYLE_WORKAHOLIC: 'CommonShortTermSentimentId' = 252693 + BITTER_LIVESTOCK_SOLD: 'CommonShortTermSentimentId' = 263707 + BITTER_OPENABLE_WINDOW_FAIL_EVENT: 'CommonShortTermSentimentId' = 283047 + BITTER_VILLAGE_FAIR_BRIBE_FAIL: 'CommonShortTermSentimentId' = 268415 + BITTER_WEDDING_TRADITION_NOT_INVITED_TO_WEDDING: 'CommonShortTermSentimentId' = 276835 + BITTER_WEDDING_TRADITION_NOT_SELECTED_BEST_MAN: 'CommonShortTermSentimentId' = 276551 + BITTER_WEDDING_TRADITION_NOT_SELECTED_MAID_OF_HONOR: 'CommonShortTermSentimentId' = 276553 + BITTER_YOGA_CLASS: 'CommonShortTermSentimentId' = 271953 + CLOSE_ADOPTION: 'CommonShortTermSentimentId' = 246610 + CLOSE_CANNING_RECEIVE_GIFT: 'CommonShortTermSentimentId' = 260816 + CLOSE_COTTAGE_WORLD_NPC_GOSSIP: 'CommonShortTermSentimentId' = 264954 + CLOSE_GENERIC: 'CommonShortTermSentimentId' = 246604 + CLOSE_GOOD_FIRST_IMPRESSION: 'CommonShortTermSentimentId' = 273242 + CLOSE_GROUP_COOKING_COOKING_TOGETHER: 'CommonShortTermSentimentId' = 262317 + CLOSE_NEAR_DEATH: 'CommonShortTermSentimentId' = 246647 + CLOSE_PARTY: 'CommonShortTermSentimentId' = 246606 + CLOSE_QUALITY_TIME: 'CommonShortTermSentimentId' = 246603 + CLOSE_HIGH_SCHOOL_PROM_SKIPPING_PROM_TOGETHER: 'CommonShortTermSentimentId' = 282637 + CLOSE_HIKING_TRAIL_GROUP_HIKE_GOLD_REWARD: 'CommonShortTermSentimentId' = 250366 + CLOSE_HOTPOT: 'CommonShortTermSentimentId' = 252685 + CLOSE_LIFESTYLE_CLOSE_KNIT: 'CommonShortTermSentimentId' = 252687 + CLOSE_LIGHT_FESTIVAL_WISH: 'CommonShortTermSentimentId' = 253253 + CLOSE_ONSEN: 'CommonShortTermSentimentId' = 252680 + CLOSE_OPENABLE_WINDOW_SUCCESS_EVENT: 'CommonShortTermSentimentId' = 283050 + CLOSE_PICNIC_BASKET_PICNIC_BONDING: 'CommonShortTermSentimentId' = 260815 + CLOSE_SNOW: 'CommonShortTermSentimentId' = 252567 + CLOSE_SNOW_FESTIVAL_PARTY: 'CommonShortTermSentimentId' = 253207 + CLOSE_SNOW_FESTIVAL_PLAY: 'CommonShortTermSentimentId' = 253194 + CLOSE_TEA_SET_TEA_PARTY: 'CommonShortTermSentimentId' = 280848 + CLOSE_THROW_FOOTBALL_BONDING_MOMENT: 'CommonShortTermSentimentId' = 286015 + CLOSE_TRUSTING: 'CommonShortTermSentimentId' = 283871 + CLOSE_VACATION_SNOWY: 'CommonShortTermSentimentId' = 252426 + CLOSE_VILLAGE_FAIR_BRIBE_SUCCESS: 'CommonShortTermSentimentId' = 268392 + CLOSE_VILLAGER_HELP_HELPED_OUT: 'CommonShortTermSentimentId' = 266363 + CLOSE_WOLFY_WARMTH: 'CommonShortTermSentimentId' = 290478 + CLOSE_YOUTH_FESTIVAL_BLESSED: 'CommonShortTermSentimentId' = 253254 + ENAMORED_CANNING_GIFT_JAR: 'CommonShortTermSentimentId' = 260818 + ENAMORED_FATED_MATES: 'CommonShortTermSentimentId' = 293545 + ENAMORED_GENERIC: 'CommonShortTermSentimentId' = 239988 + ENAMORED_HIGH_SCHOOL_PROM_IMPRESSED_BY_PROMPOSAL: 'CommonShortTermSentimentId' = 282638 + ENAMORED_LIFESTYLES_SHARED: 'CommonShortTermSentimentId' = 252423 + ENAMORED_MOUNTAIN: 'CommonShortTermSentimentId' = 252688 + ENAMORED_OPPOSITES: 'CommonShortTermSentimentId' = 252422 + ENAMORED_PAIRED_DANCING_FIRST_DANCE: 'CommonShortTermSentimentId' = 280849 + FURIOUS_CHEATING: 'CommonShortTermSentimentId' = 246622 + FURIOUS_DECORATOR_BAD_BUILD: 'CommonShortTermSentimentId' = 268257 + FURIOUS_GENERIC: 'CommonShortTermSentimentId' = 239980 + FURIOUS_LIGHT_FESTIVAL_JEALOUS: 'CommonShortTermSentimentId' = 253211 + FURIOUS_PACK_RIVALRY: 'CommonShortTermSentimentId' = 290475 + FURIOUS_WEDDING: 'CommonShortTermSentimentId' = 246623 + FURIOUS_WEDDING_PARTIES_EJECTED_GUEST: 'CommonShortTermSentimentId' = 280830 + FURIOUS_WEDDING_TRADITION_ATE_CAKE_EARLY: 'CommonShortTermSentimentId' = 276559 + FURIOUS_WEDDING_TRADITION_GOT_INTO_FIGHT: 'CommonShortTermSentimentId' = 276557 + FURIOUS_WEDDING_TRADITION_INTERRUPTED_CEREMONY: 'CommonShortTermSentimentId' = 276558 + FURIOUS_WEDDING_TRADITION_ROMANTICALLY_UP_STAGED: 'CommonShortTermSentimentId' = 276660 + FURIOUS_WEDDING_TRADITION_YOU_DIED: 'CommonShortTermSentimentId' = 276555 + GUILTY_ABANDONED_PACK: 'CommonShortTermSentimentId' = 290477 + GUILTY_AWKWARD_DATE: 'CommonShortTermSentimentId' = 246631 + GUILTY_BAD_PARTY: 'CommonShortTermSentimentId' = 246633 + GUILTY_BIG_SAD_WOLF: 'CommonShortTermSentimentId' = 288509 + GUILTY_GENERIC: 'CommonShortTermSentimentId' = 246630 + GUILTY_HIGH_SCHOOL_PROM_BROKEN_PACT: 'CommonShortTermSentimentId' = 287902 + GUILTY_LIFESTYLE_CLOSE_KNIT: 'CommonShortTermSentimentId' = 252691 + GUILTY_VILLAGE_FAIR_BRIBE_FAIL: 'CommonShortTermSentimentId' = 268427 + HURT_GENERIC: 'CommonShortTermSentimentId' = 246644 + HURT_HIGH_SCHOOL_PROM_BROKEN_DITCH_PROMISE: 'CommonShortTermSentimentId' = 282639 + HURT_HURT_BY_PACK_MATE: 'CommonShortTermSentimentId' = 290476 + HURT_LIVESTOCK_SOLD: 'CommonShortTermSentimentId' = 263706 + HURT_REJECTION: 'CommonShortTermSentimentId' = 246640 + HURT_ROMANTIC: 'CommonShortTermSentimentId' = 246638 + HURT_SADDENED: 'CommonShortTermSentimentId' = 246642 + HURT_SUSPICIOUS: 'CommonShortTermSentimentId' = 283870 + HURT_LIFESTYLE_NETWORKER: 'CommonShortTermSentimentId' = 252692 + HURT_YOUTH_FESTIVAL_UNBLESSED: 'CommonShortTermSentimentId' = 253227 + MOTIVATING_EXTREME_SPORTS: 'CommonShortTermSentimentId' = 252845 + MOTIVATING_FRIENDLY_ADVICE: 'CommonShortTermSentimentId' = 273845 + NEEDS_DISTANCE_FRIEND: 'CommonShortTermSentimentId' = 278173 + NEEDS_DISTANCE_GENERIC_ROMANTIC: 'CommonShortTermSentimentId' = 278172 + REJECTED_FRIEND: 'CommonShortTermSentimentId' = 278178 + REJECTED_GENERIC_ROMANTIC: 'CommonShortTermSentimentId' = 278177 diff --git a/Scripts/s4ap/sims4communitylib/enums/sim_type.py b/Scripts/s4ap/sims4communitylib/enums/sim_type.py new file mode 100644 index 0000000..3907e1d --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/sim_type.py @@ -0,0 +1,629 @@ +""" +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 +""" +from typing import Tuple, Iterator + +from sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags + + +class CommonSimType(CommonIntFlags): + """Various Sim Types that describe the Age, Species, and Occult Type of a Sim in a single value.""" + NONE: 'CommonSimType' = ... + + ELDER_HUMAN: 'CommonSimType' = ... + ELDER_HUMAN_VAMPIRE: 'CommonSimType' = ... + ELDER_HUMAN_GHOST: 'CommonSimType' = ... + ELDER_HUMAN_ALIEN: 'CommonSimType' = ... + ELDER_HUMAN_MERMAID: 'CommonSimType' = ... + ELDER_HUMAN_WITCH: 'CommonSimType' = ... + ELDER_HUMAN_ROBOT: 'CommonSimType' = ... + ELDER_HUMAN_SCARECROW: 'CommonSimType' = ... + ELDER_HUMAN_SKELETON: 'CommonSimType' = ... + ELDER_HUMAN_PLANT_SIM: 'CommonSimType' = ... + ELDER_HUMAN_WEREWOLF: 'CommonSimType' = ... + + ADULT_HUMAN: 'CommonSimType' = ... + ADULT_HUMAN_VAMPIRE: 'CommonSimType' = ... + ADULT_HUMAN_GHOST: 'CommonSimType' = ... + ADULT_HUMAN_ALIEN: 'CommonSimType' = ... + ADULT_HUMAN_MERMAID: 'CommonSimType' = ... + ADULT_HUMAN_WITCH: 'CommonSimType' = ... + ADULT_HUMAN_ROBOT: 'CommonSimType' = ... + ADULT_HUMAN_SCARECROW: 'CommonSimType' = ... + ADULT_HUMAN_SKELETON: 'CommonSimType' = ... + ADULT_HUMAN_PLANT_SIM: 'CommonSimType' = ... + ADULT_HUMAN_WEREWOLF: 'CommonSimType' = ... + + YOUNG_ADULT_HUMAN: 'CommonSimType' = ... + YOUNG_ADULT_HUMAN_VAMPIRE: 'CommonSimType' = ... + YOUNG_ADULT_HUMAN_GHOST: 'CommonSimType' = ... + YOUNG_ADULT_HUMAN_ALIEN: 'CommonSimType' = ... + YOUNG_ADULT_HUMAN_MERMAID: 'CommonSimType' = ... + YOUNG_ADULT_HUMAN_WITCH: 'CommonSimType' = ... + YOUNG_ADULT_HUMAN_ROBOT: 'CommonSimType' = ... + YOUNG_ADULT_HUMAN_SCARECROW: 'CommonSimType' = ... + YOUNG_ADULT_HUMAN_SKELETON: 'CommonSimType' = ... + YOUNG_ADULT_HUMAN_PLANT_SIM: 'CommonSimType' = ... + YOUNG_ADULT_HUMAN_WEREWOLF: 'CommonSimType' = ... + + TEEN_HUMAN: 'CommonSimType' = ... + TEEN_HUMAN_VAMPIRE: 'CommonSimType' = ... + TEEN_HUMAN_GHOST: 'CommonSimType' = ... + TEEN_HUMAN_ALIEN: 'CommonSimType' = ... + TEEN_HUMAN_MERMAID: 'CommonSimType' = ... + TEEN_HUMAN_WITCH: 'CommonSimType' = ... + TEEN_HUMAN_ROBOT: 'CommonSimType' = ... + TEEN_HUMAN_SCARECROW: 'CommonSimType' = ... + TEEN_HUMAN_SKELETON: 'CommonSimType' = ... + TEEN_HUMAN_PLANT_SIM: 'CommonSimType' = ... + TEEN_HUMAN_WEREWOLF: 'CommonSimType' = ... + + CHILD_HUMAN: 'CommonSimType' = ... + CHILD_HUMAN_VAMPIRE: 'CommonSimType' = ... + CHILD_HUMAN_GHOST: 'CommonSimType' = ... + CHILD_HUMAN_ALIEN: 'CommonSimType' = ... + CHILD_HUMAN_MERMAID: 'CommonSimType' = ... + CHILD_HUMAN_WITCH: 'CommonSimType' = ... + CHILD_HUMAN_ROBOT: 'CommonSimType' = ... + CHILD_HUMAN_SCARECROW: 'CommonSimType' = ... + CHILD_HUMAN_SKELETON: 'CommonSimType' = ... + CHILD_HUMAN_PLANT_SIM: 'CommonSimType' = ... + CHILD_HUMAN_WEREWOLF: 'CommonSimType' = ... + + TODDLER_HUMAN: 'CommonSimType' = ... + TODDLER_HUMAN_VAMPIRE: 'CommonSimType' = ... + TODDLER_HUMAN_GHOST: 'CommonSimType' = ... + TODDLER_HUMAN_ALIEN: 'CommonSimType' = ... + TODDLER_HUMAN_MERMAID: 'CommonSimType' = ... + TODDLER_HUMAN_WITCH: 'CommonSimType' = ... + TODDLER_HUMAN_ROBOT: 'CommonSimType' = ... + TODDLER_HUMAN_SCARECROW: 'CommonSimType' = ... + TODDLER_HUMAN_SKELETON: 'CommonSimType' = ... + TODDLER_HUMAN_PLANT_SIM: 'CommonSimType' = ... + TODDLER_HUMAN_WEREWOLF: 'CommonSimType' = ... + + INFANT_HUMAN: 'CommonSimType' = ... + INFANT_HUMAN_VAMPIRE: 'CommonSimType' = ... + INFANT_HUMAN_GHOST: 'CommonSimType' = ... + INFANT_HUMAN_ALIEN: 'CommonSimType' = ... + INFANT_HUMAN_MERMAID: 'CommonSimType' = ... + INFANT_HUMAN_WITCH: 'CommonSimType' = ... + INFANT_HUMAN_ROBOT: 'CommonSimType' = ... + INFANT_HUMAN_SCARECROW: 'CommonSimType' = ... + INFANT_HUMAN_SKELETON: 'CommonSimType' = ... + INFANT_HUMAN_PLANT_SIM: 'CommonSimType' = ... + INFANT_HUMAN_WEREWOLF: 'CommonSimType' = ... + + BABY_HUMAN: 'CommonSimType' = ... + BABY_HUMAN_VAMPIRE: 'CommonSimType' = ... + BABY_HUMAN_GHOST: 'CommonSimType' = ... + BABY_HUMAN_ALIEN: 'CommonSimType' = ... + BABY_HUMAN_MERMAID: 'CommonSimType' = ... + BABY_HUMAN_WITCH: 'CommonSimType' = ... + BABY_HUMAN_ROBOT: 'CommonSimType' = ... + BABY_HUMAN_SCARECROW: 'CommonSimType' = ... + BABY_HUMAN_SKELETON: 'CommonSimType' = ... + BABY_HUMAN_PLANT_SIM: 'CommonSimType' = ... + BABY_HUMAN_WEREWOLF: 'CommonSimType' = ... + + CHILD_DOG: 'CommonSimType' = ... + CHILD_DOG_VAMPIRE: 'CommonSimType' = ... + CHILD_DOG_GHOST: 'CommonSimType' = ... + CHILD_DOG_ALIEN: 'CommonSimType' = ... + CHILD_DOG_MERMAID: 'CommonSimType' = ... + CHILD_DOG_WITCH: 'CommonSimType' = ... + CHILD_DOG_ROBOT: 'CommonSimType' = ... + CHILD_DOG_SCARECROW: 'CommonSimType' = ... + CHILD_DOG_SKELETON: 'CommonSimType' = ... + CHILD_DOG_PLANT_SIM: 'CommonSimType' = ... + CHILD_DOG_WEREWOLF: 'CommonSimType' = ... + + ELDER_SMALL_DOG: 'CommonSimType' = ... + ELDER_SMALL_DOG_VAMPIRE: 'CommonSimType' = ... + ELDER_SMALL_DOG_GHOST: 'CommonSimType' = ... + ELDER_SMALL_DOG_ALIEN: 'CommonSimType' = ... + ELDER_SMALL_DOG_MERMAID: 'CommonSimType' = ... + ELDER_SMALL_DOG_WITCH: 'CommonSimType' = ... + ELDER_SMALL_DOG_ROBOT: 'CommonSimType' = ... + ELDER_SMALL_DOG_SCARECROW: 'CommonSimType' = ... + ELDER_SMALL_DOG_SKELETON: 'CommonSimType' = ... + ELDER_SMALL_DOG_PLANT_SIM: 'CommonSimType' = ... + ELDER_SMALL_DOG_WEREWOLF: 'CommonSimType' = ... + + ADULT_SMALL_DOG: 'CommonSimType' = ... + ADULT_SMALL_DOG_VAMPIRE: 'CommonSimType' = ... + ADULT_SMALL_DOG_GHOST: 'CommonSimType' = ... + ADULT_SMALL_DOG_ALIEN: 'CommonSimType' = ... + ADULT_SMALL_DOG_MERMAID: 'CommonSimType' = ... + ADULT_SMALL_DOG_WITCH: 'CommonSimType' = ... + ADULT_SMALL_DOG_ROBOT: 'CommonSimType' = ... + ADULT_SMALL_DOG_SCARECROW: 'CommonSimType' = ... + ADULT_SMALL_DOG_SKELETON: 'CommonSimType' = ... + ADULT_SMALL_DOG_PLANT_SIM: 'CommonSimType' = ... + ADULT_SMALL_DOG_WEREWOLF: 'CommonSimType' = ... + + CHILD_SMALL_DOG: 'CommonSimType' = ... + CHILD_SMALL_DOG_VAMPIRE: 'CommonSimType' = ... + CHILD_SMALL_DOG_GHOST: 'CommonSimType' = ... + CHILD_SMALL_DOG_ALIEN: 'CommonSimType' = ... + CHILD_SMALL_DOG_MERMAID: 'CommonSimType' = ... + CHILD_SMALL_DOG_WITCH: 'CommonSimType' = ... + CHILD_SMALL_DOG_ROBOT: 'CommonSimType' = ... + CHILD_SMALL_DOG_SCARECROW: 'CommonSimType' = ... + CHILD_SMALL_DOG_SKELETON: 'CommonSimType' = ... + CHILD_SMALL_DOG_PLANT_SIM: 'CommonSimType' = ... + CHILD_SMALL_DOG_WEREWOLF: 'CommonSimType' = ... + + ELDER_LARGE_DOG: 'CommonSimType' = ... + ELDER_LARGE_DOG_VAMPIRE: 'CommonSimType' = ... + ELDER_LARGE_DOG_GHOST: 'CommonSimType' = ... + ELDER_LARGE_DOG_ALIEN: 'CommonSimType' = ... + ELDER_LARGE_DOG_MERMAID: 'CommonSimType' = ... + ELDER_LARGE_DOG_WITCH: 'CommonSimType' = ... + ELDER_LARGE_DOG_ROBOT: 'CommonSimType' = ... + ELDER_LARGE_DOG_SCARECROW: 'CommonSimType' = ... + ELDER_LARGE_DOG_SKELETON: 'CommonSimType' = ... + ELDER_LARGE_DOG_PLANT_SIM: 'CommonSimType' = ... + ELDER_LARGE_DOG_WEREWOLF: 'CommonSimType' = ... + + ADULT_LARGE_DOG: 'CommonSimType' = ... + ADULT_LARGE_DOG_VAMPIRE: 'CommonSimType' = ... + ADULT_LARGE_DOG_GHOST: 'CommonSimType' = ... + ADULT_LARGE_DOG_ALIEN: 'CommonSimType' = ... + ADULT_LARGE_DOG_MERMAID: 'CommonSimType' = ... + ADULT_LARGE_DOG_WITCH: 'CommonSimType' = ... + ADULT_LARGE_DOG_ROBOT: 'CommonSimType' = ... + ADULT_LARGE_DOG_SCARECROW: 'CommonSimType' = ... + ADULT_LARGE_DOG_SKELETON: 'CommonSimType' = ... + ADULT_LARGE_DOG_PLANT_SIM: 'CommonSimType' = ... + ADULT_LARGE_DOG_WEREWOLF: 'CommonSimType' = ... + + CHILD_LARGE_DOG: 'CommonSimType' = ... + CHILD_LARGE_DOG_VAMPIRE: 'CommonSimType' = ... + CHILD_LARGE_DOG_GHOST: 'CommonSimType' = ... + CHILD_LARGE_DOG_ALIEN: 'CommonSimType' = ... + CHILD_LARGE_DOG_MERMAID: 'CommonSimType' = ... + CHILD_LARGE_DOG_WITCH: 'CommonSimType' = ... + CHILD_LARGE_DOG_ROBOT: 'CommonSimType' = ... + CHILD_LARGE_DOG_SCARECROW: 'CommonSimType' = ... + CHILD_LARGE_DOG_SKELETON: 'CommonSimType' = ... + CHILD_LARGE_DOG_PLANT_SIM: 'CommonSimType' = ... + CHILD_LARGE_DOG_WEREWOLF: 'CommonSimType' = ... + + ELDER_CAT: 'CommonSimType' = ... + ELDER_CAT_VAMPIRE: 'CommonSimType' = ... + ELDER_CAT_GHOST: 'CommonSimType' = ... + ELDER_CAT_ALIEN: 'CommonSimType' = ... + ELDER_CAT_MERMAID: 'CommonSimType' = ... + ELDER_CAT_WITCH: 'CommonSimType' = ... + ELDER_CAT_ROBOT: 'CommonSimType' = ... + ELDER_CAT_SCARECROW: 'CommonSimType' = ... + ELDER_CAT_SKELETON: 'CommonSimType' = ... + ELDER_CAT_PLANT_SIM: 'CommonSimType' = ... + ELDER_CAT_WEREWOLF: 'CommonSimType' = ... + + ADULT_CAT: 'CommonSimType' = ... + ADULT_CAT_VAMPIRE: 'CommonSimType' = ... + ADULT_CAT_GHOST: 'CommonSimType' = ... + ADULT_CAT_ALIEN: 'CommonSimType' = ... + ADULT_CAT_MERMAID: 'CommonSimType' = ... + ADULT_CAT_WITCH: 'CommonSimType' = ... + ADULT_CAT_ROBOT: 'CommonSimType' = ... + ADULT_CAT_SCARECROW: 'CommonSimType' = ... + ADULT_CAT_SKELETON: 'CommonSimType' = ... + ADULT_CAT_PLANT_SIM: 'CommonSimType' = ... + ADULT_CAT_WEREWOLF: 'CommonSimType' = ... + + CHILD_CAT: 'CommonSimType' = ... + CHILD_CAT_VAMPIRE: 'CommonSimType' = ... + CHILD_CAT_GHOST: 'CommonSimType' = ... + CHILD_CAT_ALIEN: 'CommonSimType' = ... + CHILD_CAT_MERMAID: 'CommonSimType' = ... + CHILD_CAT_WITCH: 'CommonSimType' = ... + CHILD_CAT_ROBOT: 'CommonSimType' = ... + CHILD_CAT_SCARECROW: 'CommonSimType' = ... + CHILD_CAT_SKELETON: 'CommonSimType' = ... + CHILD_CAT_PLANT_SIM: 'CommonSimType' = ... + CHILD_CAT_WEREWOLF: 'CommonSimType' = ... + + ELDER_FOX: 'CommonSimType' = ... + ELDER_FOX_VAMPIRE: 'CommonSimType' = ... + ELDER_FOX_GHOST: 'CommonSimType' = ... + ELDER_FOX_ALIEN: 'CommonSimType' = ... + ELDER_FOX_MERMAID: 'CommonSimType' = ... + ELDER_FOX_WITCH: 'CommonSimType' = ... + ELDER_FOX_ROBOT: 'CommonSimType' = ... + ELDER_FOX_SCARECROW: 'CommonSimType' = ... + ELDER_FOX_SKELETON: 'CommonSimType' = ... + ELDER_FOX_PLANT_SIM: 'CommonSimType' = ... + ELDER_FOX_WEREWOLF: 'CommonSimType' = ... + + ADULT_FOX: 'CommonSimType' = ... + ADULT_FOX_VAMPIRE: 'CommonSimType' = ... + ADULT_FOX_GHOST: 'CommonSimType' = ... + ADULT_FOX_ALIEN: 'CommonSimType' = ... + ADULT_FOX_MERMAID: 'CommonSimType' = ... + ADULT_FOX_WITCH: 'CommonSimType' = ... + ADULT_FOX_ROBOT: 'CommonSimType' = ... + ADULT_FOX_SCARECROW: 'CommonSimType' = ... + ADULT_FOX_SKELETON: 'CommonSimType' = ... + ADULT_FOX_PLANT_SIM: 'CommonSimType' = ... + ADULT_FOX_WEREWOLF: 'CommonSimType' = ... + + CHILD_FOX: 'CommonSimType' = ... + CHILD_FOX_VAMPIRE: 'CommonSimType' = ... + CHILD_FOX_GHOST: 'CommonSimType' = ... + CHILD_FOX_ALIEN: 'CommonSimType' = ... + CHILD_FOX_MERMAID: 'CommonSimType' = ... + CHILD_FOX_WITCH: 'CommonSimType' = ... + CHILD_FOX_ROBOT: 'CommonSimType' = ... + CHILD_FOX_SCARECROW: 'CommonSimType' = ... + CHILD_FOX_SKELETON: 'CommonSimType' = ... + CHILD_FOX_PLANT_SIM: 'CommonSimType' = ... + CHILD_FOX_WEREWOLF: 'CommonSimType' = ... + + ELDER_HORSE: 'CommonSimType' = ... + ELDER_HORSE_VAMPIRE: 'CommonSimType' = ... + ELDER_HORSE_GHOST: 'CommonSimType' = ... + ELDER_HORSE_ALIEN: 'CommonSimType' = ... + ELDER_HORSE_MERMAID: 'CommonSimType' = ... + ELDER_HORSE_WITCH: 'CommonSimType' = ... + ELDER_HORSE_ROBOT: 'CommonSimType' = ... + ELDER_HORSE_SCARECROW: 'CommonSimType' = ... + ELDER_HORSE_SKELETON: 'CommonSimType' = ... + ELDER_HORSE_PLANT_SIM: 'CommonSimType' = ... + ELDER_HORSE_WEREWOLF: 'CommonSimType' = ... + + ADULT_HORSE: 'CommonSimType' = ... + ADULT_HORSE_VAMPIRE: 'CommonSimType' = ... + ADULT_HORSE_GHOST: 'CommonSimType' = ... + ADULT_HORSE_ALIEN: 'CommonSimType' = ... + ADULT_HORSE_MERMAID: 'CommonSimType' = ... + ADULT_HORSE_WITCH: 'CommonSimType' = ... + ADULT_HORSE_ROBOT: 'CommonSimType' = ... + ADULT_HORSE_SCARECROW: 'CommonSimType' = ... + ADULT_HORSE_SKELETON: 'CommonSimType' = ... + ADULT_HORSE_PLANT_SIM: 'CommonSimType' = ... + ADULT_HORSE_WEREWOLF: 'CommonSimType' = ... + + CHILD_HORSE: 'CommonSimType' = ... + CHILD_HORSE_VAMPIRE: 'CommonSimType' = ... + CHILD_HORSE_GHOST: 'CommonSimType' = ... + CHILD_HORSE_ALIEN: 'CommonSimType' = ... + CHILD_HORSE_MERMAID: 'CommonSimType' = ... + CHILD_HORSE_WITCH: 'CommonSimType' = ... + CHILD_HORSE_ROBOT: 'CommonSimType' = ... + CHILD_HORSE_SCARECROW: 'CommonSimType' = ... + CHILD_HORSE_SKELETON: 'CommonSimType' = ... + CHILD_HORSE_PLANT_SIM: 'CommonSimType' = ... + CHILD_HORSE_WEREWOLF: 'CommonSimType' = ... + + @classmethod + def get_all(cls, include_teen_young_adult_and_elder: bool = False, include_baby: bool = False, include_infant: bool = False, include_separate_child_dog_types: bool = False, exclude_values: Iterator['CommonSimType'] = None) -> Tuple['CommonSimType']: + """get_all(include_teen_young_adult_and_elder=False, include_baby=False, include_infant=False, include_separate_child_dog_types=False, exclude_values=None) + + Retrieve a collection of all Sim Types. + + :param include_teen_young_adult_and_elder: If set to True, the TEEN, YOUNG_ADULT, and ELDER Sim Types will be returned. If False, they will be excluded. Default is False. + :type include_teen_young_adult_and_elder: bool, optional + :param include_baby: If set to True, the BABY Sim Type will be included in the result. If False, the BABY Sim Type will not be included. Default is False. + :type include_baby: bool, optional + :param include_infant: If set to True, the INFANT Sim Type will be included in the result. If False, the INFANT Sim Type will not be included. Default is False. + :type include_infant: bool, optional + :param include_separate_child_dog_types: If set to True, the Child Dog Sim Types (CHILD_LARGE_DOG, CHILD_SMALL_DOG, etc.) will be included in the result. If False, they will not be included. Default is False. + :type include_separate_child_dog_types: bool, optional + :param exclude_values: These values will be excluded. If set to None, NONE will be excluded automatically. Default is None. + :type exclude_values: Iterator[CommonSimType], optional + :return: A collection of all Sim Types. + :rtype: Tuple[CommonSimType] + """ + if exclude_values is None: + exclude_values = (cls.NONE,) + sim_types: Tuple[CommonSimType, ...] = ( + CommonSimType.ADULT_HUMAN, + CommonSimType.ADULT_HUMAN_VAMPIRE, + CommonSimType.ADULT_HUMAN_GHOST, + CommonSimType.ADULT_HUMAN_ALIEN, + CommonSimType.ADULT_HUMAN_MERMAID, + CommonSimType.ADULT_HUMAN_WITCH, + CommonSimType.ADULT_HUMAN_ROBOT, + CommonSimType.ADULT_HUMAN_SCARECROW, + CommonSimType.ADULT_HUMAN_SKELETON, + CommonSimType.ADULT_HUMAN_PLANT_SIM, + CommonSimType.ADULT_HUMAN_WEREWOLF, + + CommonSimType.CHILD_HUMAN, + CommonSimType.CHILD_HUMAN_VAMPIRE, + CommonSimType.CHILD_HUMAN_GHOST, + CommonSimType.CHILD_HUMAN_ALIEN, + CommonSimType.CHILD_HUMAN_MERMAID, + CommonSimType.CHILD_HUMAN_WITCH, + CommonSimType.CHILD_HUMAN_ROBOT, + CommonSimType.CHILD_HUMAN_SCARECROW, + CommonSimType.CHILD_HUMAN_SKELETON, + CommonSimType.CHILD_HUMAN_PLANT_SIM, + CommonSimType.CHILD_HUMAN_WEREWOLF, + + CommonSimType.TODDLER_HUMAN, + CommonSimType.TODDLER_HUMAN_VAMPIRE, + CommonSimType.TODDLER_HUMAN_GHOST, + CommonSimType.TODDLER_HUMAN_ALIEN, + CommonSimType.TODDLER_HUMAN_MERMAID, + CommonSimType.TODDLER_HUMAN_WITCH, + CommonSimType.TODDLER_HUMAN_ROBOT, + CommonSimType.TODDLER_HUMAN_SCARECROW, + CommonSimType.TODDLER_HUMAN_SKELETON, + CommonSimType.TODDLER_HUMAN_PLANT_SIM, + CommonSimType.TODDLER_HUMAN_WEREWOLF, + + CommonSimType.ADULT_SMALL_DOG, + CommonSimType.ADULT_SMALL_DOG_VAMPIRE, + CommonSimType.ADULT_SMALL_DOG_GHOST, + CommonSimType.ADULT_SMALL_DOG_ALIEN, + CommonSimType.ADULT_SMALL_DOG_MERMAID, + CommonSimType.ADULT_SMALL_DOG_WITCH, + CommonSimType.ADULT_SMALL_DOG_ROBOT, + CommonSimType.ADULT_SMALL_DOG_SCARECROW, + CommonSimType.ADULT_SMALL_DOG_SKELETON, + CommonSimType.ADULT_SMALL_DOG_PLANT_SIM, + CommonSimType.ADULT_SMALL_DOG_WEREWOLF, + + CommonSimType.ADULT_LARGE_DOG, + CommonSimType.ADULT_LARGE_DOG_VAMPIRE, + CommonSimType.ADULT_LARGE_DOG_GHOST, + CommonSimType.ADULT_LARGE_DOG_ALIEN, + CommonSimType.ADULT_LARGE_DOG_MERMAID, + CommonSimType.ADULT_LARGE_DOG_WITCH, + CommonSimType.ADULT_LARGE_DOG_ROBOT, + CommonSimType.ADULT_LARGE_DOG_SCARECROW, + CommonSimType.ADULT_LARGE_DOG_SKELETON, + CommonSimType.ADULT_LARGE_DOG_PLANT_SIM, + CommonSimType.ADULT_LARGE_DOG_WEREWOLF, + + CommonSimType.ADULT_CAT, + CommonSimType.ADULT_CAT_VAMPIRE, + CommonSimType.ADULT_CAT_GHOST, + CommonSimType.ADULT_CAT_ALIEN, + CommonSimType.ADULT_CAT_MERMAID, + CommonSimType.ADULT_CAT_WITCH, + CommonSimType.ADULT_CAT_ROBOT, + CommonSimType.ADULT_CAT_SCARECROW, + CommonSimType.ADULT_CAT_SKELETON, + CommonSimType.ADULT_CAT_PLANT_SIM, + CommonSimType.ADULT_CAT_WEREWOLF, + + CommonSimType.CHILD_CAT, + CommonSimType.CHILD_CAT_VAMPIRE, + CommonSimType.CHILD_CAT_GHOST, + CommonSimType.CHILD_CAT_ALIEN, + CommonSimType.CHILD_CAT_MERMAID, + CommonSimType.CHILD_CAT_WITCH, + CommonSimType.CHILD_CAT_ROBOT, + CommonSimType.CHILD_CAT_SCARECROW, + CommonSimType.CHILD_CAT_SKELETON, + CommonSimType.CHILD_CAT_PLANT_SIM, + CommonSimType.CHILD_CAT_WEREWOLF, + + CommonSimType.ADULT_FOX, + CommonSimType.ADULT_FOX_VAMPIRE, + CommonSimType.ADULT_FOX_GHOST, + CommonSimType.ADULT_FOX_ALIEN, + CommonSimType.ADULT_FOX_MERMAID, + CommonSimType.ADULT_FOX_WITCH, + CommonSimType.ADULT_FOX_ROBOT, + CommonSimType.ADULT_FOX_SCARECROW, + CommonSimType.ADULT_FOX_SKELETON, + CommonSimType.ADULT_FOX_PLANT_SIM, + CommonSimType.ADULT_FOX_WEREWOLF, + + CommonSimType.CHILD_FOX, + CommonSimType.CHILD_FOX_VAMPIRE, + CommonSimType.CHILD_FOX_GHOST, + CommonSimType.CHILD_FOX_ALIEN, + CommonSimType.CHILD_FOX_MERMAID, + CommonSimType.CHILD_FOX_WITCH, + CommonSimType.CHILD_FOX_ROBOT, + CommonSimType.CHILD_FOX_SCARECROW, + CommonSimType.CHILD_FOX_SKELETON, + CommonSimType.CHILD_FOX_PLANT_SIM, + CommonSimType.CHILD_FOX_WEREWOLF, + + CommonSimType.CHILD_DOG, + CommonSimType.CHILD_DOG_VAMPIRE, + CommonSimType.CHILD_DOG_GHOST, + CommonSimType.CHILD_DOG_ALIEN, + CommonSimType.CHILD_DOG_MERMAID, + CommonSimType.CHILD_DOG_WITCH, + CommonSimType.CHILD_DOG_ROBOT, + CommonSimType.CHILD_DOG_SCARECROW, + CommonSimType.CHILD_DOG_SKELETON, + CommonSimType.CHILD_DOG_PLANT_SIM, + CommonSimType.CHILD_DOG_WEREWOLF, + + CommonSimType.ADULT_HORSE, + CommonSimType.ADULT_HORSE_VAMPIRE, + CommonSimType.ADULT_HORSE_GHOST, + CommonSimType.ADULT_HORSE_ALIEN, + CommonSimType.ADULT_HORSE_MERMAID, + CommonSimType.ADULT_HORSE_WITCH, + CommonSimType.ADULT_HORSE_ROBOT, + CommonSimType.ADULT_HORSE_SCARECROW, + CommonSimType.ADULT_HORSE_SKELETON, + CommonSimType.ADULT_HORSE_PLANT_SIM, + CommonSimType.ADULT_HORSE_WEREWOLF, + + CommonSimType.CHILD_HORSE, + CommonSimType.CHILD_HORSE_VAMPIRE, + CommonSimType.CHILD_HORSE_GHOST, + CommonSimType.CHILD_HORSE_ALIEN, + CommonSimType.CHILD_HORSE_MERMAID, + CommonSimType.CHILD_HORSE_WITCH, + CommonSimType.CHILD_HORSE_ROBOT, + CommonSimType.CHILD_HORSE_SCARECROW, + CommonSimType.CHILD_HORSE_SKELETON, + CommonSimType.CHILD_HORSE_PLANT_SIM, + CommonSimType.CHILD_HORSE_WEREWOLF, + ) + if include_teen_young_adult_and_elder: + sim_types: Tuple[CommonSimType, ...] = ( + *sim_types, + CommonSimType.ELDER_HUMAN, + CommonSimType.ELDER_HUMAN_VAMPIRE, + CommonSimType.ELDER_HUMAN_GHOST, + CommonSimType.ELDER_HUMAN_ALIEN, + CommonSimType.ELDER_HUMAN_MERMAID, + CommonSimType.ELDER_HUMAN_WITCH, + CommonSimType.ELDER_HUMAN_ROBOT, + CommonSimType.ELDER_HUMAN_SCARECROW, + CommonSimType.ELDER_HUMAN_SKELETON, + CommonSimType.ELDER_HUMAN_PLANT_SIM, + CommonSimType.ELDER_HUMAN_WEREWOLF, + + CommonSimType.YOUNG_ADULT_HUMAN, + CommonSimType.YOUNG_ADULT_HUMAN_VAMPIRE, + CommonSimType.YOUNG_ADULT_HUMAN_GHOST, + CommonSimType.YOUNG_ADULT_HUMAN_ALIEN, + CommonSimType.YOUNG_ADULT_HUMAN_MERMAID, + CommonSimType.YOUNG_ADULT_HUMAN_WITCH, + CommonSimType.YOUNG_ADULT_HUMAN_ROBOT, + CommonSimType.YOUNG_ADULT_HUMAN_SCARECROW, + CommonSimType.YOUNG_ADULT_HUMAN_SKELETON, + CommonSimType.YOUNG_ADULT_HUMAN_PLANT_SIM, + CommonSimType.YOUNG_ADULT_HUMAN_WEREWOLF, + + CommonSimType.TEEN_HUMAN, + CommonSimType.TEEN_HUMAN_VAMPIRE, + CommonSimType.TEEN_HUMAN_GHOST, + CommonSimType.TEEN_HUMAN_ALIEN, + CommonSimType.TEEN_HUMAN_MERMAID, + CommonSimType.TEEN_HUMAN_WITCH, + CommonSimType.TEEN_HUMAN_ROBOT, + CommonSimType.TEEN_HUMAN_SCARECROW, + CommonSimType.TEEN_HUMAN_SKELETON, + CommonSimType.TEEN_HUMAN_PLANT_SIM, + CommonSimType.TEEN_HUMAN_WEREWOLF, + + CommonSimType.ELDER_SMALL_DOG, + CommonSimType.ELDER_SMALL_DOG_VAMPIRE, + CommonSimType.ELDER_SMALL_DOG_GHOST, + CommonSimType.ELDER_SMALL_DOG_ALIEN, + CommonSimType.ELDER_SMALL_DOG_MERMAID, + CommonSimType.ELDER_SMALL_DOG_WITCH, + CommonSimType.ELDER_SMALL_DOG_ROBOT, + CommonSimType.ELDER_SMALL_DOG_SCARECROW, + CommonSimType.ELDER_SMALL_DOG_SKELETON, + CommonSimType.ELDER_SMALL_DOG_PLANT_SIM, + CommonSimType.ELDER_SMALL_DOG_WEREWOLF, + + CommonSimType.ELDER_LARGE_DOG, + CommonSimType.ELDER_LARGE_DOG_VAMPIRE, + CommonSimType.ELDER_LARGE_DOG_GHOST, + CommonSimType.ELDER_LARGE_DOG_ALIEN, + CommonSimType.ELDER_LARGE_DOG_MERMAID, + CommonSimType.ELDER_LARGE_DOG_WITCH, + CommonSimType.ELDER_LARGE_DOG_ROBOT, + CommonSimType.ELDER_LARGE_DOG_SCARECROW, + CommonSimType.ELDER_LARGE_DOG_SKELETON, + CommonSimType.ELDER_LARGE_DOG_PLANT_SIM, + CommonSimType.ELDER_LARGE_DOG_WEREWOLF, + + CommonSimType.ELDER_CAT, + CommonSimType.ELDER_CAT_VAMPIRE, + CommonSimType.ELDER_CAT_GHOST, + CommonSimType.ELDER_CAT_ALIEN, + CommonSimType.ELDER_CAT_MERMAID, + CommonSimType.ELDER_CAT_WITCH, + CommonSimType.ELDER_CAT_ROBOT, + CommonSimType.ELDER_CAT_SCARECROW, + CommonSimType.ELDER_CAT_SKELETON, + CommonSimType.ELDER_CAT_PLANT_SIM, + CommonSimType.ELDER_CAT_WEREWOLF, + + CommonSimType.ELDER_FOX, + CommonSimType.ELDER_FOX_VAMPIRE, + CommonSimType.ELDER_FOX_GHOST, + CommonSimType.ELDER_FOX_ALIEN, + CommonSimType.ELDER_FOX_MERMAID, + CommonSimType.ELDER_FOX_WITCH, + CommonSimType.ELDER_FOX_ROBOT, + CommonSimType.ELDER_FOX_SCARECROW, + CommonSimType.ELDER_FOX_SKELETON, + CommonSimType.ELDER_FOX_PLANT_SIM, + CommonSimType.ELDER_FOX_WEREWOLF, + + CommonSimType.ELDER_HORSE, + CommonSimType.ELDER_HORSE_VAMPIRE, + CommonSimType.ELDER_HORSE_GHOST, + CommonSimType.ELDER_HORSE_ALIEN, + CommonSimType.ELDER_HORSE_MERMAID, + CommonSimType.ELDER_HORSE_WITCH, + CommonSimType.ELDER_HORSE_ROBOT, + CommonSimType.ELDER_HORSE_SCARECROW, + CommonSimType.ELDER_HORSE_SKELETON, + CommonSimType.ELDER_HORSE_PLANT_SIM, + CommonSimType.ELDER_HORSE_WEREWOLF, + ) + if include_baby: + sim_types: Tuple[CommonSimType, ...] = ( + *sim_types, + CommonSimType.BABY_HUMAN, + CommonSimType.BABY_HUMAN_VAMPIRE, + CommonSimType.BABY_HUMAN_GHOST, + CommonSimType.BABY_HUMAN_ALIEN, + CommonSimType.BABY_HUMAN_MERMAID, + CommonSimType.BABY_HUMAN_WITCH, + CommonSimType.BABY_HUMAN_ROBOT, + CommonSimType.BABY_HUMAN_SCARECROW, + CommonSimType.BABY_HUMAN_SKELETON, + CommonSimType.BABY_HUMAN_PLANT_SIM, + CommonSimType.BABY_HUMAN_WEREWOLF, + ) + if include_infant: + sim_types: Tuple[CommonSimType, ...] = ( + *sim_types, + CommonSimType.INFANT_HUMAN, + CommonSimType.INFANT_HUMAN_VAMPIRE, + CommonSimType.INFANT_HUMAN_GHOST, + CommonSimType.INFANT_HUMAN_ALIEN, + CommonSimType.INFANT_HUMAN_MERMAID, + CommonSimType.INFANT_HUMAN_WITCH, + CommonSimType.INFANT_HUMAN_ROBOT, + CommonSimType.INFANT_HUMAN_SCARECROW, + CommonSimType.INFANT_HUMAN_SKELETON, + CommonSimType.INFANT_HUMAN_PLANT_SIM, + CommonSimType.INFANT_HUMAN_WEREWOLF, + ) + if include_separate_child_dog_types: + sim_types: Tuple[CommonSimType, ...] = ( + *sim_types, + CommonSimType.CHILD_SMALL_DOG, + CommonSimType.CHILD_SMALL_DOG_VAMPIRE, + CommonSimType.CHILD_SMALL_DOG_GHOST, + CommonSimType.CHILD_SMALL_DOG_ALIEN, + CommonSimType.CHILD_SMALL_DOG_MERMAID, + CommonSimType.CHILD_SMALL_DOG_WITCH, + CommonSimType.CHILD_SMALL_DOG_ROBOT, + CommonSimType.CHILD_SMALL_DOG_SCARECROW, + CommonSimType.CHILD_SMALL_DOG_SKELETON, + CommonSimType.CHILD_SMALL_DOG_PLANT_SIM, + CommonSimType.CHILD_SMALL_DOG_WEREWOLF, + + CommonSimType.CHILD_LARGE_DOG, + CommonSimType.CHILD_LARGE_DOG_VAMPIRE, + CommonSimType.CHILD_LARGE_DOG_GHOST, + CommonSimType.CHILD_LARGE_DOG_ALIEN, + CommonSimType.CHILD_LARGE_DOG_MERMAID, + CommonSimType.CHILD_LARGE_DOG_WITCH, + CommonSimType.CHILD_LARGE_DOG_ROBOT, + CommonSimType.CHILD_LARGE_DOG_SCARECROW, + CommonSimType.CHILD_LARGE_DOG_SKELETON, + CommonSimType.CHILD_LARGE_DOG_PLANT_SIM, + CommonSimType.CHILD_LARGE_DOG_WEREWOLF, + ) + # noinspection PyTypeChecker + value_list: Tuple[CommonSimType] = tuple([value for value in sim_types if value not in exclude_values]) + return value_list diff --git a/Scripts/s4ap/sims4communitylib/enums/situation_jobs_enum.py b/Scripts/s4ap/sims4communitylib/enums/situation_jobs_enum.py new file mode 100644 index 0000000..b396ea7 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/situation_jobs_enum.py @@ -0,0 +1,1083 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonSituationJobId(CommonInt): + """Identifiers for vanilla situation jobs. + + """ + INVALID: 'CommonSituationJobId' = 0 + ACTOR_CAREER_BACKGROUND_ACTOR: 'CommonSituationJobId' = 191066 + ACTOR_CAREER_BACKGROUND_PRODUCER: 'CommonSituationJobId' = 191067 + ACTOR_CAREER_COSTAR1: 'CommonSituationJobId' = 189270 + ACTOR_CAREER_CO_STAR2: 'CommonSituationJobId' = 189271 + ACTOR_CAREER_DIRECTOR_COMMERCIAL: 'CommonSituationJobId' = 197472 + ACTOR_CAREER_DIRECTOR_FILM: 'CommonSituationJobId' = 197475 + ACTOR_CAREER_DIRECTOR_HIGH_BUDGET_TV: 'CommonSituationJobId' = 197474 + ACTOR_CAREER_DIRECTOR_LOW_BUDGET_TV: 'CommonSituationJobId' = 197473 + ACTOR_CAREER_DOLLY_CAMERA_OPERATOR: 'CommonSituationJobId' = 190526 + ACTOR_CAREER_PLAYER: 'CommonSituationJobId' = 189160 + ACTOR_CAREER_SPECIAL_EFFECTS_OPERATOR: 'CommonSituationJobId' = 192113 + ACTOR_CAREER_STATIONARY_CAMERA_OPERATOR: 'CommonSituationJobId' = 191283 + ARTIST_MUSEUM: 'CommonSituationJobId' = 29789 + ART_SOCIETY_BAR_NIGHT_MEET_UP_PARTICIPANT: 'CommonSituationJobId' = 226520 + BARFLY: 'CommonSituationJobId' = 16158 + BARFLY_ALIEN: 'CommonSituationJobId' = 122605 + BARFLY_ALIEN_WORLD: 'CommonSituationJobId' = 114218 + BARFLY_BEAR: 'CommonSituationJobId' = 126606 + BARFLY_CAREER: 'CommonSituationJobId' = 122661 + BARFLY_FEMALE: 'CommonSituationJobId' = 122607 + BARFLY_GHOST: 'CommonSituationJobId' = 122608 + BARFLY_JUNGLE: 'CommonSituationJobId' = 180837 + BARFLY_KARAOKE: 'CommonSituationJobId' = 138046 + BARFLY_KARAOKE_CAREER: 'CommonSituationJobId' = 138047 + BARFLY_KARAOKE_CAREER_HAPPY_HOUR: 'CommonSituationJobId' = 138116 + BARFLY_KARAOKE_PLAYER: 'CommonSituationJobId' = 138193 + BARFLY_KNIGHT: 'CommonSituationJobId' = 129889 + BARFLY_LOUNGE: 'CommonSituationJobId' = 74683 + BARFLY_LOUNGE_ELDER: 'CommonSituationJobId' = 110052 + BARFLY_LOUNGE_PLAYER: 'CommonSituationJobId' = 134421 + BARFLY_MALE: 'CommonSituationJobId' = 122609 + BARFLY_MILITARY: 'CommonSituationJobId' = 204036 + BARFLY_PLAYER: 'CommonSituationJobId' = 126354 + BARFLY_REGULARS: 'CommonSituationJobId' = 122563 + BARFLY_SINGLE: 'CommonSituationJobId' = 122610 + BARFLY_VISITOR: 'CommonSituationJobId' = 122601 + BARTENDER: 'CommonSituationJobId' = 16159 + BARTENDER_ALIEN_WORLD: 'CommonSituationJobId' = 114208 + BARTENDER_BAR: 'CommonSituationJobId' = 16161 + BARTENDER_BAR_MYSHUNO_MEADOWS: 'CommonSituationJobId' = 147048 + BARTENDER_BIRTHDAY_PARTY: 'CommonSituationJobId' = 31638 + BARTENDER_BLACK_AND_WHITE_PARTY: 'CommonSituationJobId' = 35089 + BARTENDER_COSTUME_PARTY: 'CommonSituationJobId' = 35083 + BARTENDER_DINNER_PARTY: 'CommonSituationJobId' = 16154 + BARTENDER_GO_DANCING: 'CommonSituationJobId' = 130591 + BARTENDER_HIRED_NPC: 'CommonSituationJobId' = 123712 + BARTENDER_JUNGLE: 'CommonSituationJobId' = 185004 + BARTENDER_OPEN_STREET: 'CommonSituationJobId' = 153474 + BARTENDER_SINGLES_PARTY: 'CommonSituationJobId' = 16177 + BARTENDER_WEDDING: 'CommonSituationJobId' = 16169 + BAR_LADY: 'CommonSituationJobId' = 16162 + BAR_NIGHT_ART_SOCIETY_PLAYER: 'CommonSituationJobId' = 231031 + BAR_NIGHT_DEBATE_ORG_PLAYER: 'CommonSituationJobId' = 231032 + BAR_NIGHT_HONOR_SOCIETY_PLAYER: 'CommonSituationJobId' = 231033 + BAR_NIGHT_PARTY_PLAYER: 'CommonSituationJobId' = 231034 + BAR_NIGHT_PRANK_PLAYER: 'CommonSituationJobId' = 231035 + BAR_NIGHT_ROBOTICS_PLAYER: 'CommonSituationJobId' = 231036 + BASIC_TRAIT_ECO_PERSONALITY_ECO_MASTER: 'CommonSituationJobId' = 234900 + BASIC_TRAIT_ECO_PERSONALITY_ENTREPRENEUR: 'CommonSituationJobId' = 234899 + BASIC_TRAIT_ECO_PERSONALITY_MAKER: 'CommonSituationJobId' = 234898 + BIRTHDAY_CELEBRANT: 'CommonSituationJobId' = 31925 + BIRTHDAY_CELEBRANT_NPC_INVITER: 'CommonSituationJobId' = 117396 + BUTLER: 'CommonSituationJobId' = 145805 + CAFE_BARISTA: 'CommonSituationJobId' = 122242 + CAFE_BARISTA_HIRED_NPC: 'CommonSituationJobId' = 123734 + CAFE_CUSTOMERS_BUSINESS_CUSTOMER: 'CommonSituationJobId' = 122261 + CAFE_CUSTOMERS_CAFE_FRIEND: 'CommonSituationJobId' = 122262 + CAFE_CUSTOMERS_GENERIC_CUSTOMER: 'CommonSituationJobId' = 122310 + CAFE_CUSTOMERS_MEDIA_ADDICT: 'CommonSituationJobId' = 122240 + CAFE_CUSTOMERS_READER: 'CommonSituationJobId' = 122241 + CAFE_CUSTOMERS_TO_GO_CUSTOMER: 'CommonSituationJobId' = 122260 + CAREER_DETECTIVE_POLICE_STATION_CHIEF: 'CommonSituationJobId' = 116692 + CAREER_DETECTIVE_POLICE_STATION_LAB_TECH: 'CommonSituationJobId' = 115813 + CAREER_DETECTIVE_POLICE_STATION_NPC_DETECTIVE: 'CommonSituationJobId' = 116596 + CAREER_DETECTIVE_POLICE_STATION_RECEPTIONIST: 'CommonSituationJobId' = 114834 + CAREER_DOCTOR_PLAYER: 'CommonSituationJobId' = 110837 + CAREER_SCIENTIST_ALIEN_VISIT_ALIEN: 'CommonSituationJobId' = 113537 + CAREER_SCIENTIST_COWORKER: 'CommonSituationJobId' = 107568 + CAREER_SCIENTIST_COWORKER_FRONT_DESK: 'CommonSituationJobId' = 115833 + CAREER_SCIENTIST_PLAYER: 'CommonSituationJobId' = 107504 + CATERER: 'CommonSituationJobId' = 16163 + CATERER_BIRTHDAY_PARTY: 'CommonSituationJobId' = 31636 + CATERER_BIRTHDAY_PARTY_NPC_INVITE: 'CommonSituationJobId' = 117411 + CATERER_BLACK_AND_WHITE_PARTY: 'CommonSituationJobId' = 35086 + CATERER_COSTUME_PARTY: 'CommonSituationJobId' = 35082 + CATERER_DINNER_PARTY: 'CommonSituationJobId' = 16155 + CATERER_HIRED_NPC: 'CommonSituationJobId' = 123704 + CATERER_SPOOKY_PARTY: 'CommonSituationJobId' = 125425 + CATERER_VEGETARIAN_HIRED_NPC: 'CommonSituationJobId' = 150485 + CATERER_WEDDING: 'CommonSituationJobId' = 16171 + CHEF_FAMILY_MEAL: 'CommonSituationJobId' = 33907 + CHEF_GASTROPUB: 'CommonSituationJobId' = 9223 + CHESS_PLAYER_PARK: 'CommonSituationJobId' = 27468 + CHILD_PLAYING_PARK: 'CommonSituationJobId' = 27504 + CIVIC_INSPECTOR_INSPECTOR: 'CommonSituationJobId' = 233262 + CLUB_GATHERING: 'CommonSituationJobId' = 122316 + CLUB_PARTY_ACTOR_TARGET: 'CommonSituationJobId' = 126458 + CLUB_PARTY_CLUB_MEMBERS: 'CommonSituationJobId' = 126456 + CLUB_PARTY_INVITE_SIM_PICKER: 'CommonSituationJobId' = 126658 + CLUB_PARTY_NPC_INVITE: 'CommonSituationJobId' = 126457 + COLLEGE_ORGANIZATIONS_ROBOTICS_ROBOTICS_EXHIBITION_HUMANOID_BOT: 'CommonSituationJobId' = 223676 + COLLEGE_ORGANIZATIONS_ROBOTICS_ROBOTICS_EXHIBITION_JUDGE: 'CommonSituationJobId' = 223677 + COLLEGE_ORGANIZATIONS_ROBOTICS_ROBOTICS_EXHIBITION_PARTICIPANT: 'CommonSituationJobId' = 223675 + COLLEGE_ORGANIZATIONS_ROBOTICS_ROBOTICS_EXHIBITION_PLAYER: 'CommonSituationJobId' = 223872 + COLLEGE_ORGANIZATIONS_ROBOTICS_ROBOT_BUILDING_SESSION_PARTICIPANT: 'CommonSituationJobId' = 225325 + COLLEGE_ORGANIZATIONS_ROBOTICS_ROBOT_BUILDING_SESSION_PLAYER: 'CommonSituationJobId' = 225324 + COLLEGE_ORGANIZATIONS_SCHOOL_SPIRIT_PARTY_GAME_DAY_PARTY_MEMBER: 'CommonSituationJobId' = 225089 + COLLEGE_ORGANIZATIONS_SCHOOL_SPIRIT_PARTY_GAME_DAY_PARTY_PARTY_GOER: 'CommonSituationJobId' = 225090 + COLLEGE_ORGANIZATIONS_SCHOOL_SPIRIT_PARTY_GAME_DAY_PARTY_PLAYER: 'CommonSituationJobId' = 225052 + COLLEGE_ORGANIZATIONS_SCHOOL_SPIRIT_PARTY_SCHOOL_SPIRIT_DAY_MEMBER: 'CommonSituationJobId' = 208844 + COLLEGE_ORGANIZATIONS_SCHOOL_SPIRIT_PARTY_SCHOOL_SPIRIT_DAY_PLAYER: 'CommonSituationJobId' = 209370 + COLLEGE_ORGANIZATIONS_SCHOOL_SPIRIT_PARTY_SCHOOL_SPIRIT_DAY_STUDENT: 'CommonSituationJobId' = 208843 + COLLEGE_ORGANIZATIONS_SCHOOL_SPIRIT_PRANK_CREATIVITY_CELEBRATION_MASCOT: 'CommonSituationJobId' = 230450 + COLLEGE_ORGANIZATIONS_SCHOOL_SPIRIT_PRANK_CREATIVITY_CELEBRATION_MEMBER: 'CommonSituationJobId' = 223233 + COLLEGE_ORGANIZATIONS_SCHOOL_SPIRIT_PRANK_CREATIVITY_CELEBRATION_PLAYER: 'CommonSituationJobId' = 223231 + COLLEGE_ORGANIZATIONS_SCHOOL_SPIRIT_PRANK_CREATIVITY_CELEBRATION_STUDENT: 'CommonSituationJobId' = 223234 + COLLEGE_ORGANIZATIONS_SCHOOL_SPIRIT_PRANK_GAME_DAY_PARTY_MEMBER: 'CommonSituationJobId' = 223246 + COLLEGE_ORGANIZATIONS_SCHOOL_SPIRIT_PRANK_GAME_DAY_PARTY_PLAYER: 'CommonSituationJobId' = 223324 + COLLEGE_ORGANIZATIONS_SCHOOL_SPIRIT_PRANK_GAME_DAY_PARTY_RIVAL: 'CommonSituationJobId' = 223247 + COLLEGE_ORGANIZATIONS_SECRET_SOCIETY_RITUAL_MEMBER: 'CommonSituationJobId' = 221500 + COLLEGE_ORGANIZATIONS_SECRET_SOCIETY_RITUAL_PLAYER: 'CommonSituationJobId' = 223039 + COLLEGE_ORGANIZATIONS_STUDY_GROUP_MEMBERS: 'CommonSituationJobId' = 209041 + COLLEGE_ORGANIZATIONS_STUDY_GROUP_PLAYER: 'CommonSituationJobId' = 209036 + COLLEGE_ORGANIZATION_SECRET_SOCIETY_JOIN_VISIT: 'CommonSituationJobId' = 222431 + COMMUNITY_CLOSENESS_COMPLAINT: 'CommonSituationJobId' = 233537 + COMMUNITY_CLOSENESS_HANDY_NEIGHBOR: 'CommonSituationJobId' = 233540 + COMMUNITY_CLOSENESS_INTRO_TO_CIVIC_POLICIES_ECO_MASTER: 'CommonSituationJobId' = 238069 + COMMUNITY_CLOSENESS_INTRO_TO_CIVIC_POLICIES_ENTREPRENEUR: 'CommonSituationJobId' = 238070 + COMMUNITY_CLOSENESS_RANDOM_GIFT: 'CommonSituationJobId' = 233539 + COMMUNITY_CLOSENESS_SPARE_RECYCLING: 'CommonSituationJobId' = 233542 + COMMUNITY_CLOSENESS_TRASH_HELP: 'CommonSituationJobId' = 233541 + COWORKER_PROMOTION_PARTY: 'CommonSituationJobId' = 125926 + COWORKER_PROMOTION_PARTY_ACTOR_TARGET: 'CommonSituationJobId' = 125928 + COWORKER_PROMOTION_PARTY_INVITE_SIM_PICKER: 'CommonSituationJobId' = 126659 + COWORKER_PROMOTION_PARTY_NPC_INVITE: 'CommonSituationJobId' = 126278 + DATE_ACTOR: 'CommonSituationJobId' = 34258 + DATE_ACTOR_TARGET: 'CommonSituationJobId' = 117124 + DATE_ACTOR_TEEN: 'CommonSituationJobId' = 99351 + DATE_NPC_INVITER: 'CommonSituationJobId' = 117102 + DATE_TARGET: 'CommonSituationJobId' = 34256 + DATE_TARGET_TEEN: 'CommonSituationJobId' = 99352 + DEBATE_BAR_NIGHT_MEET_UP_PARTICIPANT: 'CommonSituationJobId' = 222257 + DEBATE_DEBATER: 'CommonSituationJobId' = 222727 + DEBUG_BARTENDER_JOB: 'CommonSituationJobId' = 16150 + DEBUG_CATERER_JOB: 'CommonSituationJobId' = 16151 + DEBUG_GUEST_JOB: 'CommonSituationJobId' = 16152 + DEBUG_HOST_JOB: 'CommonSituationJobId' = 16153 + DEBUG_MULTI_GUEST_JOB: 'CommonSituationJobId' = 26109 + DEBUG_SOAK_GUEST_JOB: 'CommonSituationJobId' = 101359 + DYNAMIC_OBJECT_BOARD_DEBATER: 'CommonSituationJobId' = 224289 + DYNAMIC_OBJECT_TRASH_DIVER: 'CommonSituationJobId' = 224216 + ECO_INSPECTOR_INSPECTOR: 'CommonSituationJobId' = 232057 + ECO_PERSONALITY_ECO_MASTER: 'CommonSituationJobId' = 235532 + ECO_PERSONALITY_ECO_MASTER_WALK_BY: 'CommonSituationJobId' = 241203 + ECO_PERSONALITY_ENTREPRENEUR: 'CommonSituationJobId' = 235534 + ECO_PERSONALITY_ENTREPRENEUR_WALK_BY: 'CommonSituationJobId' = 241202 + ECO_PERSONALITY_MAKER: 'CommonSituationJobId' = 235533 + ECO_PERSONALITY_MAKER_WALK_BY: 'CommonSituationJobId' = 241201 + ENTERTAINER_BIRTHDAY_PARTY: 'CommonSituationJobId' = 32407 + ENTERTAINER_BLACK_AND_WHITE_PARTY: 'CommonSituationJobId' = 35087 + ENTERTAINER_GUITAR_AT_HOME: 'CommonSituationJobId' = 123625 + ENTERTAINER_LOUNGE: 'CommonSituationJobId' = 40134 + ENTERTAINER_MIC_COMEDY_AT_HOME: 'CommonSituationJobId' = 123691 + ENTERTAINER_MIC_COMEDY_AT_HOME_LAMPOON: 'CommonSituationJobId' = 202118 + ENTERTAINER_MIC_COMEDY_AT_HOME_NPC_HIRED: 'CommonSituationJobId' = 202446 + ENTERTAINER_MIC_COMEDY_HIRE_FROM_MICROPHONE: 'CommonSituationJobId' = 202692 + ENTERTAINER_ORGAN_AT_HOME: 'CommonSituationJobId' = 155974 + ENTERTAINER_PIANO_AT_HOME: 'CommonSituationJobId' = 123592 + ENTERTAINER_VIOLIN_AT_HOME: 'CommonSituationJobId' = 123681 + ENTERTAINER_WEDDING: 'CommonSituationJobId' = 99098 + EVENT_NPC_CALL_OVER: 'CommonSituationJobId' = 149783 + EVENT_NPC_CALL_OVER_MBB: 'CommonSituationJobId' = 198849 + EXERCISE_GYM: 'CommonSituationJobId' = 16165 + E_SPORTS_TEAMMATE: 'CommonSituationJobId' = 227362 + E_SPORTS_TEAMMATE_ARTS: 'CommonSituationJobId' = 229681 + FAN_STAN_CELEBRITY_SIM: 'CommonSituationJobId' = 193805 + FAN_STAN_FAN: 'CommonSituationJobId' = 194429 + FAN_STAN_FAN_CHILD: 'CommonSituationJobId' = 201698 + FAN_STAN_FAN_TEEN: 'CommonSituationJobId' = 202007 + FAN_STAN_STAN: 'CommonSituationJobId' = 194426 + FASHION_SUBJECT: 'CommonSituationJobId' = 215289 + FESTIVAL_BLOSSOM_ARTIST: 'CommonSituationJobId' = 136083 + FESTIVAL_BLOSSOM_BARTENDER: 'CommonSituationJobId' = 140533 + FESTIVAL_BLOSSOM_CRAFT_SALES_TABLE_VENDOR_PAINTING: 'CommonSituationJobId' = 153678 + FESTIVAL_BLOSSOM_CRAZY_TEEN: 'CommonSituationJobId' = 135707 + FESTIVAL_BLOSSOM_ENTERTAINER: 'CommonSituationJobId' = 140536 + FESTIVAL_BLOSSOM_GENERAL: 'CommonSituationJobId' = 140495 + FESTIVAL_BLOSSOM_LOVE_GURU: 'CommonSituationJobId' = 146779 + FESTIVAL_BLOSSOM_MARKET_STALLS_VENDOR: 'CommonSituationJobId' = 140503 + FESTIVAL_BLOSSOM_PETAL_HEAD: 'CommonSituationJobId' = 135706 + FESTIVAL_BLOSSOM_ROMANTIC_COUPLE: 'CommonSituationJobId' = 146787 + FESTIVAL_BLOSSOM_SLEAZE: 'CommonSituationJobId' = 136243 + FESTIVAL_FLEA_MARKET_CRAFT_SALES_TABLE_VENDOR: 'CommonSituationJobId' = 146841 + FESTIVAL_FLEA_MARKET_CRAFT_SALES_TABLE_VENDOR_PAINTING: 'CommonSituationJobId' = 153687 + FESTIVAL_FLEA_MARKET_ENTERTAINER: 'CommonSituationJobId' = 142723 + FESTIVAL_FLEA_MARKET_GENERAL: 'CommonSituationJobId' = 140497 + FESTIVAL_FLEA_MARKET_HAGGLER: 'CommonSituationJobId' = 142229 + FESTIVAL_FLEA_MARKET_MARKET_STALLS_VENDOR: 'CommonSituationJobId' = 140528 + FESTIVAL_FLEA_MARKET_VENDOR: 'CommonSituationJobId' = 139947 + FESTIVAL_FOOD_BARTENDER: 'CommonSituationJobId' = 140534 + FESTIVAL_FOOD_ENTERTAINER: 'CommonSituationJobId' = 140546 + FESTIVAL_FOOD_GENERAL: 'CommonSituationJobId' = 140498 + FESTIVAL_FOOD_GRILL_MASTER: 'CommonSituationJobId' = 140103 + FESTIVAL_FOOD_MARKET_STALLS_VENDOR: 'CommonSituationJobId' = 140529 + FESTIVAL_FOOD_OVER_EATER: 'CommonSituationJobId' = 136419 + FESTIVAL_GARDENER: 'CommonSituationJobId' = 139636 + FESTIVAL_LAMP_BARTENDER: 'CommonSituationJobId' = 140535 + FESTIVAL_LAMP_DARK_CONTESTANT: 'CommonSituationJobId' = 146833 + FESTIVAL_LAMP_DARK_SIDER: 'CommonSituationJobId' = 143377 + FESTIVAL_LAMP_ENTERTAINER: 'CommonSituationJobId' = 140547 + FESTIVAL_LAMP_GENERAL: 'CommonSituationJobId' = 140500 + FESTIVAL_LAMP_LIGHT_CONTESTANT: 'CommonSituationJobId' = 146834 + FESTIVAL_LAMP_MARKET_STALLS_VENDOR: 'CommonSituationJobId' = 140531 + FESTIVAL_LIGHT_DARK_SIDERS: 'CommonSituationJobId' = 134836 + FESTIVAL_LOGIC_FAIR_COSPLAYER: 'CommonSituationJobId' = 137227 + FESTIVAL_LOGIC_FAIR_GAMERS: 'CommonSituationJobId' = 140932 + FESTIVAL_LOGIC_FAIR_GENERAL: 'CommonSituationJobId' = 140501 + FESTIVAL_LOGIC_FAIR_HACKERS: 'CommonSituationJobId' = 141163 + FESTIVAL_LOGIC_FAIR_MARKET_STALLS_VENDOR: 'CommonSituationJobId' = 140532 + FESTIVAL_LOGIC_FAIR_ROCKET_SHIP_WOOHOOERS: 'CommonSituationJobId' = 142734 + # Also known as UGT: 'CommonSituationJobId' = Ultimate Gaming Test + FESTIVAL_LOGIC_FAIR_ULTIMATE_GAMING_TESTERS: 'CommonSituationJobId' = 141303 + FESTIVAL_PLAYER_SIM: 'CommonSituationJobId' = 140377 + FIRE: 'CommonSituationJobId' = 73823 + FIRE_BRIGADE_VOLUNTEER: 'CommonSituationJobId' = 208733 + FREELANCER_FASHION_PHOTOGRAPHER: 'CommonSituationJobId' = 216224 + FREELANCER_FASHION_PHOTOGRAPHER_STYLE_INFLUENCER: 'CommonSituationJobId' = 216220 + GARDENER_SERVICE: 'CommonSituationJobId' = 130543 + GENERIC: 'CommonSituationJobId' = 99709 + GENERIC_ANY_SPECIES: 'CommonSituationJobId' = 168875 + GENERIC_NO_CHURN: 'CommonSituationJobId' = 101227 + GHOST: 'CommonSituationJobId' = 101847 + GHOST_HAUNTED_APARTMENT: 'CommonSituationJobId' = 139825 + GHOST_PETS: 'CommonSituationJobId' = 165594 + GO_FOR_WALK_DOG: 'CommonSituationJobId' = 165052 + GO_FOR_WALK_SIM: 'CommonSituationJobId' = 165051 + GREETED_NPC_VISING_NPC: 'CommonSituationJobId' = 34419 + GREETED_PLAYER_VISITING_NPC: 'CommonSituationJobId' = 34420 + GREETED_RUDE_ALIEN: 'CommonSituationJobId' = 108084 + GREETED_TUTORIAL_HOUSEMATE: 'CommonSituationJobId' = 198048 + GRILL_MASTER_WEENIE_ROAST: 'CommonSituationJobId' = 103692 + GRIM_REAPER: 'CommonSituationJobId' = 16180 + GUEST_BIRTHDAY_PARTY: 'CommonSituationJobId' = 31633 + GUEST_BIRTHDAY_PARTY_ACTOR_TARGET: 'CommonSituationJobId' = 117383 + GUEST_BIRTHDAY_PARTY_NPC_INVITE: 'CommonSituationJobId' = 117544 + GUEST_BIRTHDAY_PARTY_NPC_INVITE_SIM_PICKER: 'CommonSituationJobId' = 117841 + GUEST_BLACK_AND_WHITE_PARTY: 'CommonSituationJobId' = 35084 + GUEST_CHARITY_BENEFIT_PARTY: 'CommonSituationJobId' = 200793 + GUEST_COSTUME_PARTY: 'CommonSituationJobId' = 35080 + GUEST_EATER_FAMILY_MEAL: 'CommonSituationJobId' = 33909 + GUEST_GUEST_OF_HONOR: 'CommonSituationJobId' = 197863 + GUEST_LAMPOON_PARTY: 'CommonSituationJobId' = 201956 + GUEST_PARTY: 'CommonSituationJobId' = 16167 + GUEST_SPOOKY_PARTY: 'CommonSituationJobId' = 125415 + GUEST_WEDDING: 'CommonSituationJobId' = 16173 + GUEST_WEENIE_ROAST: 'CommonSituationJobId' = 103719 + HAIR_MAKE_UP_CHAIR_STYLIST: 'CommonSituationJobId' = 189486 + HOLIDAY_TRADITION_FATHER_WINTER: 'CommonSituationJobId' = 181420 + HOLIDAY_TRADITION_FLOWER_BUNNY: 'CommonSituationJobId' = 186903 + HOLIDAY_TRADITION_TRICK_OR_TREAT: 'CommonSituationJobId' = 187508 + HOLIDAY_TRADITION_WALK_BYS_GHOSTS: 'CommonSituationJobId' = 187133 + HOLIDAY_TRADITION_WALK_BYS_NUDISTS: 'CommonSituationJobId' = 190699 + HOLIDAY_TRADITION_WALK_BYS_TRICK_OR_TREAT: 'CommonSituationJobId' = 188034 + HOLIDAY_TRADITION_WALK_BY_FESTIVE_OUTFITS: 'CommonSituationJobId' = 182163 + HOLIDAY_TRADITION_WALK_BY_FORMAL_OUTFITS: 'CommonSituationJobId' = 182178 + HONOR_SOCIETY_BAR_NIGHT_MEET_UP_PARTICIPANT: 'CommonSituationJobId' = 229024 + HOSPITAL_PATIENT_1: 'CommonSituationJobId' = 108631 + HOSPITAL_PATIENT_ADMITTED: 'CommonSituationJobId' = 113608 + HOSPITAL_PATIENT_ADMITTED_CHILDREN: 'CommonSituationJobId' = 115599 + HOSPITAL_PATIENT_ADMITTED_ELDER: 'CommonSituationJobId' = 115989 + HOSPITAL_PATIENT_ADMITTED_T_YA: 'CommonSituationJobId' = 115990 + HOSPITAL_PATIENT_AWAY_EVENT_TRIGGER: 'CommonSituationJobId' = 114202 + HOSPITAL_PATIENT_LOW_LEVEL_ALL: 'CommonSituationJobId' = 116215 + HOSPITAL_PATIENT_PLAYER_BABY_LABOR: 'CommonSituationJobId' = 112164 + HOST_BLACK_AND_WHITE_PARTY: 'CommonSituationJobId' = 35085 + HOST_COSTUME_PARTY: 'CommonSituationJobId' = 35081 + HOST_SPOOKY_PARTY: 'CommonSituationJobId' = 125420 + HOST_WEENIE_ROAST: 'CommonSituationJobId' = 103721 + HOUSEHOLD_EATER_FAMILY_MEAL: 'CommonSituationJobId' = 33908 + INVITED_OVER: 'CommonSituationJobId' = 40350 + INVITED_SUMMONED_GHOST: 'CommonSituationJobId' = 108709 + INVITE_TO: 'CommonSituationJobId' = 40715 + INVITE_TO_MAGIC_PORTAL: 'CommonSituationJobId' = 222422 + ISLANDER_CULTURE_ACTOR: 'CommonSituationJobId' = 208466 + ISLANDER_CULTURE_DOOR_KNOCKER: 'CommonSituationJobId' = 208465 + ISLANDER_CULTURE_DOOR_KNOCKER_EXTRA_FOOD: 'CommonSituationJobId' = 209456 + ISLANDER_CULTURE_FOOD_BEARER: 'CommonSituationJobId' = 208464 + ISLANDER_CULTURE_NEED_SOMETHING_FIXED_REPAIRMAN: 'CommonSituationJobId' = 208712 + ISLANDER_CULTURE_NEIGHBOR: 'CommonSituationJobId' = 208467 + ISLAND_ANCESTORS_VISIT_ISLAND_ELEMENTAL: 'CommonSituationJobId' = 210214 + ISLAND_CONSERVATION_ANTI_ENVIRONMENTALIST: 'CommonSituationJobId' = 208860 + ISLAND_CONSERVATION_CONSERVATIONIST: 'CommonSituationJobId' = 211665 + ISLAND_CONSERVATION_LITTERING_SIM: 'CommonSituationJobId' = 208859 + ISLAND_CONSERVATION_POACHING_SIM: 'CommonSituationJobId' = 208858 + ISLAND_EVENTS_BEACH_BONFIRE_TOWN_LOCAL: 'CommonSituationJobId' = 205612 + ISLAND_EVENTS_FAMILY_FUN_DAY_LOCAL_KID: 'CommonSituationJobId' = 205615 + ISLAND_EVENTS_FAMILY_FUN_DAY_LOCAL_PARENT: 'CommonSituationJobId' = 205616 + ISLAND_EVENTS_FAMILY_FUN_DAY_VENDOR: 'CommonSituationJobId' = 205614 + ISLAND_EVENTS_FISHING_COMPETITION_CONTESTANT: 'CommonSituationJobId' = 204668 + ISLAND_EVENTS_FISHING_COMPETITION_HOST: 'CommonSituationJobId' = 204677 + ISLAND_EVENTS_FLOWERS_AND_MUSIC_MUSICIAN: 'CommonSituationJobId' = 205618 + ISLAND_EVENTS_FLOWERS_AND_MUSIC_TOWN_LOCAL: 'CommonSituationJobId' = 205617 + ISLAND_EVENTS_ISLAND_CELEBRATION_PAINTER_FIRE_DANCER: 'CommonSituationJobId' = 204999 + ISLAND_EVENTS_ISLAND_CELEBRATION_SAND_ARTIST_MUSICIAN: 'CommonSituationJobId' = 205645 + ISLAND_EVENTS_ISLAND_CELEBRATION_STALL_VENDOR: 'CommonSituationJobId' = 205644 + ISLAND_EVENTS_ISLAND_CELEBRATION_TABLE_VENDOR: 'CommonSituationJobId' = 205643 + ISLAND_EVENTS_ISLAND_CELEBRATION_TOWN_LOCAL: 'CommonSituationJobId' = 205646 + ISLAND_EVENTS_POTLUCK_TOWN_LOCAL: 'CommonSituationJobId' = 204560 + ISLAND_EVENTS_TOWN_BBQ_ISLAND_COOK: 'CommonSituationJobId' = 205634 + ISLAND_EVENTS_TOWN_BBQ_TOWN_LOCAL: 'CommonSituationJobId' = 205633 + ISLAND_EVENTS_TURTLE_HATCHING_CONSERVATIONIST: 'CommonSituationJobId' = 205490 + ISLAND_EVENTS_TURTLE_HATCHING_FANATIC: 'CommonSituationJobId' = 205488 + ISLAND_EVENTS_TURTLE_HATCHING_LOCALS: 'CommonSituationJobId' = 205489 + ISLAND_SPIRITS_VISIT_EMPTY: 'CommonSituationJobId' = 211703 + KARAOKE_CONTESTANT: 'CommonSituationJobId' = 138152 + KARAOKE_CONTESTANT_SCORED: 'CommonSituationJobId' = 153657 + KARAOKE_DUET: 'CommonSituationJobId' = 140815 + KARAOKE_SINGLE: 'CommonSituationJobId' = 138189 + KAVA_PARTY_GUEST: 'CommonSituationJobId' = 206387 + KAVA_PARTY_HOST: 'CommonSituationJobId' = 206388 + KAVA_PARTY_ISLAND_GUEST: 'CommonSituationJobId' = 206390 + LIBRARIAN: 'CommonSituationJobId' = 40082 + LIBRARY_READER_PLAYER: 'CommonSituationJobId' = 134429 + LIBRARY_STRANGER_VILLE_CONSPIRACIST: 'CommonSituationJobId' = 204087 + LIBRARY_STRANGER_VILLE_SCIENTIST: 'CommonSituationJobId' = 204079 + LOUNGE_EVENT_AWARD_ATTENDEE: 'CommonSituationJobId' = 192672 + LOUNGE_EVENT_AWARD_HOST: 'CommonSituationJobId' = 192673 + LOUNGE_EVENT_MEET_A_CELEBRITY: 'CommonSituationJobId' = 192670 + LOUNGE_EVENT_OPEN_MIC: 'CommonSituationJobId' = 192671 + LOUNGE_EVENT_OPEN_MIC_CONTESTANT_PLAYER: 'CommonSituationJobId' = 195978 + LOUNGE_EVENT_PLAYER_CONTROLLER: 'CommonSituationJobId' = 195977 + MAGIC_HQ_PLAYER: 'CommonSituationJobId' = 223444 + MAGIC_SAGE_MISCHIEF: 'CommonSituationJobId' = 212837 + MAGIC_SAGE_PRACTICAL: 'CommonSituationJobId' = 212838 + MAGIC_SAGE_UNTAMED: 'CommonSituationJobId' = 212839 + MAGIC_VENUE_NPC_INTERMEDIATE: 'CommonSituationJobId' = 213056 + MAGIC_VENUE_NPC_NOVICE: 'CommonSituationJobId' = 212936 + MAID: 'CommonSituationJobId' = 16174 + MAID_UNIVERSITY_HOUSING: 'CommonSituationJobId' = 221343 + MAILMAN: 'CommonSituationJobId' = 16175 + MARKET_STALLS_CUSTOMER_MAGIC: 'CommonSituationJobId' = 217683 + MARKET_STALLS_VENDOR_CAFETERIA_STATION: 'CommonSituationJobId' = 220130 + MARKET_STALLS_VENDOR_CAFETERIA_STATION_HIRED_NPC: 'CommonSituationJobId' = 217900 + MARKET_STALLS_VENDOR_COFFEE_CART: 'CommonSituationJobId' = 225987 + MARKET_STALLS_VENDOR_COFFEE_CART_HIRED_NPC: 'CommonSituationJobId' = 226531 + MARKET_STALLS_VENDOR_ISLAND_WORLD: 'CommonSituationJobId' = 215327 + MARKET_STALLS_VENDOR_MAGIC: 'CommonSituationJobId' = 216970 + MARKET_STALLS_VENDOR_MAGIC_HIRED_NPC_BROOM: 'CommonSituationJobId' = 217645 + MARKET_STALLS_VENDOR_MAGIC_HIRED_NPC_POTION: 'CommonSituationJobId' = 217839 + MARKET_STALLS_VENDOR_MAGIC_HIRED_NPC_WAND: 'CommonSituationJobId' = 217840 + MARKET_STALLS_VENDOR_MAGIC_POTION: 'CommonSituationJobId' = 217866 + MARKET_STALLS_VENDOR_MAGIC_WAND: 'CommonSituationJobId' = 217867 + MARKET_STALLS_VENDOR_ROBOTICS_EXHIBITION: 'CommonSituationJobId' = 230069 + MASSAGE_THERAPIST_SERVICE: 'CommonSituationJobId' = 118593 + MEDITATION_TELEPORT_TO: 'CommonSituationJobId' = 119810 + MENTOR_LIBRARY_MUSEUM: 'CommonSituationJobId' = 27651 + MOTHER_PLANT_BATTLE_HELPERS_1: 'CommonSituationJobId' = 203318 + MOTHER_PLANT_BATTLE_HELPERS_2: 'CommonSituationJobId' = 203319 + MOTHER_PLANT_BATTLE_HELPERS_3: 'CommonSituationJobId' = 203320 + MOTHER_PLANT_BATTLE_OTHER_PLAYERS: 'CommonSituationJobId' = 203322 + MOTHER_PLANT_BATTLE_PRIMARY_PLAYER: 'CommonSituationJobId' = 203321 + MOTHER_PLANT_BATTLE_RUN_AWAY: 'CommonSituationJobId' = 207317 + MOTHER_PLANT_BATTLE_ZOMBIE: 'CommonSituationJobId' = 203330 + NANNY: 'CommonSituationJobId' = 141842 + NATURAL_POOL_SWIMMER: 'CommonSituationJobId' = 175205 + NIGHT_STALKER: 'CommonSituationJobId' = 216315 + NIGHT_STALKER_TARGET: 'CommonSituationJobId' = 216402 + NPC_INVITES_ANGRY_TEXT_ACTOR_TARGET: 'CommonSituationJobId' = 127301 + NPC_INVITES_ANGRY_TEXT_INVITE_SIM_PICKER: 'CommonSituationJobId' = 127302 + NPC_INVITES_ANGRY_TEXT_NPC_INVITE: 'CommonSituationJobId' = 127303 + NPC_INVITES_BAR_ACTOR_TARGET: 'CommonSituationJobId' = 127377 + NPC_INVITES_BAR_INVITE_SIM_PICKER: 'CommonSituationJobId' = 127378 + NPC_INVITES_BAR_NPC_INVITE: 'CommonSituationJobId' = 127379 + NPC_INVITES_FLIRTY_TEXT_ACTOR_TARGET: 'CommonSituationJobId' = 127281 + NPC_INVITES_FLIRTY_TEXT_INVITE_SIM_PICKER: 'CommonSituationJobId' = 127282 + NPC_INVITES_FLIRTY_TEXT_NPC_INVITE: 'CommonSituationJobId' = 127283 + NPC_INVITES_GYM_ACTOR_TARGET: 'CommonSituationJobId' = 127225 + NPC_INVITES_GYM_INVITE_SIM_PICKER: 'CommonSituationJobId' = 127227 + NPC_INVITES_GYM_NPC_INVITE: 'CommonSituationJobId' = 127226 + NPC_INVITES_HAPPY_ACTOR_TARGET: 'CommonSituationJobId' = 127246 + NPC_INVITES_HAPPY_TEXT_INVITE_SIM_PICKER: 'CommonSituationJobId' = 127247 + NPC_INVITES_HAPPY_TEXT_NPC_INVITE: 'CommonSituationJobId' = 127248 + NPC_INVITES_INVITE_OVER_ACTOR_TARGET: 'CommonSituationJobId' = 128964 + NPC_INVITES_INVITE_OVER_INVITE_SIM_PICKER: 'CommonSituationJobId' = 128965 + NPC_INVITES_INVITE_OVER_NPC_INVITE: 'CommonSituationJobId' = 128966 + NPC_INVITES_MAGIC_DUEL_CHALLENGE_CHALLENGED: 'CommonSituationJobId' = 218374 + NPC_INVITES_MAGIC_DUEL_CHALLENGE_CHALLENGER: 'CommonSituationJobId' = 218469 + NPC_INVITES_PLAYFUL_TEXT_ACTOR_TARGET: 'CommonSituationJobId' = 127271 + NPC_INVITES_PLAYFUL_TEXT_INVITE_SIM_PICKER: 'CommonSituationJobId' = 127270 + NPC_INVITES_PLAYFUL_TEXT_NPC_INVITE: 'CommonSituationJobId' = 127272 + NPC_INVITES_RECOMMEND_LOCAL_HANGOUT_BAR_ACTOR_TARGET: 'CommonSituationJobId' = 137953 + NPC_INVITES_RECOMMEND_LOCAL_HANGOUT_BAR_INVITE_SIM_PICKER: 'CommonSituationJobId' = 137954 + NPC_INVITES_RECOMMEND_LOCAL_HANGOUT_BAR_NPC_INVITE: 'CommonSituationJobId' = 137955 + NPC_INVITES_RECOMMEND_RESTAURANT_ACTOR_TARGET: 'CommonSituationJobId' = 140078 + NPC_INVITES_RECOMMEND_RESTAURANT_INVITE_SIM_PICKER: 'CommonSituationJobId' = 140079 + NPC_INVITES_RECOMMEND_RESTAURANT_NPC_INVITE: 'CommonSituationJobId' = 140080 + NPC_INVITES_RESTAURANT_ACTOR_TARGET: 'CommonSituationJobId' = 131937 + NPC_INVITES_RESTAURANT_INVITE_SIM_PICKER: 'CommonSituationJobId' = 131938 + NPC_INVITES_RESTAURANT_NPC_INVITE: 'CommonSituationJobId' = 131939 + NPC_SPA_GUEST_ANNOYING: 'CommonSituationJobId' = 118873 + NPC_SPA_GUEST_BULL_IN_CHINA_SHOP: 'CommonSituationJobId' = 118872 + NPC_SPA_GUEST_NORMAL: 'CommonSituationJobId' = 118874 + NPC_SPA_GUEST_NORMAL_COUPLE: 'CommonSituationJobId' = 119687 + NPC_SPA_GUEST_PRANKSTER: 'CommonSituationJobId' = 118875 + NPC_SPA_GUEST_SNOB: 'CommonSituationJobId' = 118876 + OBJECT_FASHION_STUDIO_TRIPOD_PHOTOGRAPHER: 'CommonSituationJobId' = 216822 + OBJECT_FASHION_STUDIO_TRIPOD_SUBJECT: 'CommonSituationJobId' = 216823 + OBJECT_FASHION_STUDIO_TRIPOD_SUBJECT_2: 'CommonSituationJobId' = 217664 + OBJECT_FASHION_STUDIO_TRIPOD_SUBJECT_3: 'CommonSituationJobId' = 217665 + OBJECT_FASHION_STUDIO_TRIPOD_SUBJECT_CARRY: 'CommonSituationJobId' = 217895 + OPEN_STREETS_ALIEN: 'CommonSituationJobId' = 113917 + OPEN_STREETS_BBQ: 'CommonSituationJobId' = 38902 + OPEN_STREETS_BONFIRE: 'CommonSituationJobId' = 126403 + OPEN_STREETS_CAMPING_FOREST_CAMPFIRE: 'CommonSituationJobId' = 107878 + OPEN_STREETS_CAMPING_FOREST_FISHERMAN: 'CommonSituationJobId' = 106104 + OPEN_STREETS_CAMPING_FOREST_FOREST_GHOST: 'CommonSituationJobId' = 108332 + OPEN_STREETS_CAMPING_FOREST_FOREST_RANGER: 'CommonSituationJobId' = 108823 + OPEN_STREETS_CAMPING_FOREST_RANGER_STATION: 'CommonSituationJobId' = 106107 + OPEN_STREETS_CAMPING_FOREST_RESTROOM: 'CommonSituationJobId' = 106106 + OPEN_STREETS_CAMPING_FOREST_RESTROOM_SHOWER: 'CommonSituationJobId' = 110034 + OPEN_STREETS_CHALET_GARDENS_FAMILY_TOURIST2: 'CommonSituationJobId' = 126379 + OPEN_STREETS_CHALET_GARDENS_FAMILY_TOURIST: 'CommonSituationJobId' = 126351 + OPEN_STREETS_CHALET_GARDENS_FLIRTY_TOURIST2: 'CommonSituationJobId' = 126390 + OPEN_STREETS_CHALET_GARDENS_FLIRTY_TOURIST: 'CommonSituationJobId' = 126389 + OPEN_STREETS_CHALET_GARDENS_GENERIC_TOURIST2: 'CommonSituationJobId' = 126353 + OPEN_STREETS_CHALET_GARDENS_GENERIC_TOURIST: 'CommonSituationJobId' = 126238 + OPEN_STREETS_CHALET_GARDENS_GHOST_GARDENER: 'CommonSituationJobId' = 125473 + OPEN_STREETS_CHALET_GARDENS_GHOST_PAINTER: 'CommonSituationJobId' = 125472 + OPEN_STREETS_CHALET_GARDENS_LONELY_TOURIST: 'CommonSituationJobId' = 126243 + OPEN_STREETS_CHESS: 'CommonSituationJobId' = 38487 + OPEN_STREETS_CITY_LIFE_BASKET_BALLER: 'CommonSituationJobId' = 149957 + OPEN_STREETS_CITY_LIFE_CITY_REPAIR: 'CommonSituationJobId' = 144296 + OPEN_STREETS_CITY_LIFE_LIVING_STATUE_BUSKER: 'CommonSituationJobId' = 134262 + OPEN_STREETS_CITY_LIFE_MURAL_PAINTER: 'CommonSituationJobId' = 149971 + OPEN_STREETS_CITY_LIFE_MYSHUNO_MEADOWS_GENERIC_TOURIST: 'CommonSituationJobId' = 138477 + OPEN_STREETS_CITY_LIFE_TOURIST: 'CommonSituationJobId' = 134261 + OPEN_STREETS_CITY_LIFE_WEIRDO: 'CommonSituationJobId' = 134263 + OPEN_STREETS_CITY_LIFE_WEIRDO_BATHROBE_ELDER: 'CommonSituationJobId' = 145027 + OPEN_STREETS_CITY_LIFE_WEIRDO_RACCOON: 'CommonSituationJobId' = 145029 + OPEN_STREETS_CITY_LIFE_WEIRDO_TOWELS: 'CommonSituationJobId' = 145030 + OPEN_STREETS_EUROPE_BRAWL: 'CommonSituationJobId' = 122808 + OPEN_STREETS_EUROPE_TOURIST: 'CommonSituationJobId' = 122809 + OPEN_STREETS_EVENT_NPC_CHALLENGE: 'CommonSituationJobId' = 133758 + OPEN_STREETS_FAME_WORLD_CELEBRITY: 'CommonSituationJobId' = 197062 + OPEN_STREETS_FAME_WORLD_TOURIST: 'CommonSituationJobId' = 197053 + OPEN_STREETS_FISHER: 'CommonSituationJobId' = 77049 + OPEN_STREETS_FISHER_LOCAL: 'CommonSituationJobId' = 127055 + OPEN_STREETS_GARDEN: 'CommonSituationJobId' = 38936 + OPEN_STREETS_GRILL_GROUP: 'CommonSituationJobId' = 126543 + OPEN_STREETS_ISLAND_FISHER: 'CommonSituationJobId' = 216172 + OPEN_STREETS_ISLAND_WORLD_MERFOLK: 'CommonSituationJobId' = 210407 + OPEN_STREETS_ISLAND_WORLD_TOWN_VISITOR: 'CommonSituationJobId' = 210410 + OPEN_STREETS_JOGGER: 'CommonSituationJobId' = 40409 + OPEN_STREETS_JUNGLE_MARKETPLACE_BROWSER: 'CommonSituationJobId' = 178175 + OPEN_STREETS_JUNGLE_MARKETPLACE_FISHERMAN: 'CommonSituationJobId' = 178121 + OPEN_STREETS_JUNGLE_MARKETPLACE_TOURIST_TAKE_PHOTO: 'CommonSituationJobId' = 178230 + OPEN_STREETS_LOUNGER: 'CommonSituationJobId' = 77025 + OPEN_STREETS_MARKET_STALLS_CUSTOMER: 'CommonSituationJobId' = 181017 + OPEN_STREETS_MASTER_FISHERMAN: 'CommonSituationJobId' = 40509 + OPEN_STREETS_MASTER_GARDENER: 'CommonSituationJobId' = 40366 + OPEN_STREETS_MYSHUNO_MEADOWS_CHILDREN_PLAYING: 'CommonSituationJobId' = 154536 + OPEN_STREETS_MYSHUNO_MEADOWS_FISHER: 'CommonSituationJobId' = 155931 + OPEN_STREETS_MYSHUNO_MEADOWS_FORMAL_VISITORS: 'CommonSituationJobId' = 154537 + OPEN_STREETS_MYSHUNO_MEADOWS_JOGGER: 'CommonSituationJobId' = 155567 + OPEN_STREETS_MYSHUNO_MEADOWS_LIVING_STATUE_BUSKER: 'CommonSituationJobId' = 151727 + OPEN_STREETS_MYSHUNO_MEADOWS_TOWNIE: 'CommonSituationJobId' = 155682 + OPEN_STREETS_MYSHUNO_MEADOWS_WEIRDO: 'CommonSituationJobId' = 151728 + OPEN_STREETS_PAINTER: 'CommonSituationJobId' = 126203 + OPEN_STREETS_PICNIC_TABLE: 'CommonSituationJobId' = 126163 + OPEN_STREETS_PLAYGROUND: 'CommonSituationJobId' = 38312 + OPEN_STREETS_RESTROOM: 'CommonSituationJobId' = 40786 + OPEN_STREETS_RESTROOM_LOCAL: 'CommonSituationJobId' = 127059 + OPEN_STREETS_SEASONAL_LEAVES: 'CommonSituationJobId' = 181007 + OPEN_STREETS_SEASONAL_PUDDLES: 'CommonSituationJobId' = 181009 + OPEN_STREETS_SEASONAL_SKATER: 'CommonSituationJobId' = 181008 + OPEN_STREETS_SEASONAL_SKATER_PRO: 'CommonSituationJobId' = 185771 + OPEN_STREETS_SEASONAL_SNOW_CHILD: 'CommonSituationJobId' = 185707 + OPEN_STREETS_SEASONAL_SNOW_TYAE: 'CommonSituationJobId' = 181488 + OPEN_STREET_CITY_LIFE_LIVES_ON_STREET_ADULT: 'CommonSituationJobId' = 134683 + OPEN_STREET_CITY_LIFE_LIVES_ON_STREET_CHILD: 'CommonSituationJobId' = 152482 + ORG_EVENT_DEBATE_SHOWDOWN_AUDIENCE_MEMBER: 'CommonSituationJobId' = 222731 + ORG_EVENT_DEBATE_SHOWDOWN_JUDGE: 'CommonSituationJobId' = 222729 + ORG_EVENT_DEBATE_SHOWDOWN_JUDGE_DECLARE: 'CommonSituationJobId' = 229268 + ORG_EVENT_DEBATE_SHOWDOWN_PARTICIPANT: 'CommonSituationJobId' = 222730 + ORG_EVENT_DEBATE_SHOWDOWN_PLAYER: 'CommonSituationJobId' = 225829 + ORG_EVENT_DEBATE_SHOWDOWN_PLAYER_PRACTICE: 'CommonSituationJobId' = 230077 + ORG_EVENT_DEBATE_SHOWDOWN_PRACTICE_PARTICIPANT: 'CommonSituationJobId' = 228583 + ORG_EVENT_PAINTING_IN_THE_PARK_MEMBERS: 'CommonSituationJobId' = 223216 + ORG_EVENT_PAINTING_IN_THE_PARK_MODEL: 'CommonSituationJobId' = 227009 + ORG_EVENT_PAINTING_IN_THE_PARK_PLAYER: 'CommonSituationJobId' = 223358 + PAPARAZZI_LOCKED_OUT: 'CommonSituationJobId' = 200949 + PAPARAZZI_PAPARAZZI: 'CommonSituationJobId' = 196400 + PARK_DEFAULT: 'CommonSituationJobId' = 76134 + PARK_DEFAULT_PCTYAE: 'CommonSituationJobId' = 157919 + PARK_FISHER: 'CommonSituationJobId' = 77050 + PARK_GARDENER: 'CommonSituationJobId' = 77051 + PARK_PLAYER: 'CommonSituationJobId' = 134438 + PARTY_BAR_NIGHT_MEET_UP_PARTICIPANT: 'CommonSituationJobId' = 229025 + PARTY_HOST: 'CommonSituationJobId' = 16168 + PARTY_HOST_CHARITY_BENEFIT: 'CommonSituationJobId' = 202428 + PARTY_HOST_KEG_PARTY: 'CommonSituationJobId' = 222556 + PARTY_HOST_LAMPOON: 'CommonSituationJobId' = 202122 + PARTY_RESIDENT: 'CommonSituationJobId' = 26053 + PATIENT_AWAY_EVENT_HOUSE_CALL: 'CommonSituationJobId' = 114053 + PATIENT_AWAY_EVENT_OUTBREAK: 'CommonSituationJobId' = 114027 + PATRON_MUSEUM: 'CommonSituationJobId' = 29785 + PATRON_MUSEUM_JUNGLE_NATIVE: 'CommonSituationJobId' = 185013 + PATRON_MUSEUM_JUNGLE_TOURIST: 'CommonSituationJobId' = 185021 + PATRON_MUSEUM_PLAYER: 'CommonSituationJobId' = 134430 + PET_CARE_PET: 'CommonSituationJobId' = 164140 + PET_CARE_PET_CARE_WORKER: 'CommonSituationJobId' = 164139 + PET_OBSTACLE_COURSE_PET: 'CommonSituationJobId' = 172175 + PET_OBSTACLE_COURSE_PET_OWNER: 'CommonSituationJobId' = 172176 + PIZZA_DELIVERY: 'CommonSituationJobId' = 9830 + PLAY_DATE_ACTOR_TARGET: 'CommonSituationJobId' = 117181 + PLAY_DATE_NPC_INVITER: 'CommonSituationJobId' = 117173 + PLAY_DATE_NPC_PARENT: 'CommonSituationJobId' = 117184 + PLAY_DATE_PLAYER_PARENT: 'CommonSituationJobId' = 118329 + PLAY_HOOKY_ACTOR_TARGET: 'CommonSituationJobId' = 125960 + PLAY_HOOKY_INVITE_SIM_PICKER: 'CommonSituationJobId' = 126661 + PLAY_HOOKY_NPC_HOST: 'CommonSituationJobId' = 125959 + PRANK_BAR_NIGHT_MEET_UP_PARTICIPANT: 'CommonSituationJobId' = 229026 + PRESENT_PILE_GROUP: 'CommonSituationJobId' = 185128 + PRESENT_PILE_SIM: 'CommonSituationJobId' = 185129 + PROTESTER: 'CommonSituationJobId' = 136556 + READER_LIBRARY: 'CommonSituationJobId' = 27571 + RECOMMEND_LOCAL_HANGOUT_CLUB_PARTY_ACTOR_TARGET: 'CommonSituationJobId' = 137956 + RECOMMEND_LOCAL_HANGOUT_CLUB_PARTY_CLUB_MEMBERS: 'CommonSituationJobId' = 137957 + RECOMMEND_LOCAL_HANGOUT_CLUB_PARTY_INVITE: 'CommonSituationJobId' = 137964 + RECOMMEND_LOCAL_HANGOUT_CLUB_PARTY_SIM_PICKER: 'CommonSituationJobId' = 137958 + RECOMMEND_LOCAL_HANGOUT_MUSEUM_ACTOR_TARGET: 'CommonSituationJobId' = 137995 + RECOMMEND_LOCAL_HANGOUT_MUSEUM_INVITE_SIM_PICKER: 'CommonSituationJobId' = 137996 + RECOMMEND_LOCAL_HANGOUT_MUSEUM_NPC_INVITE: 'CommonSituationJobId' = 137997 + RELAXATION_VENUES_CELEBRITY_HANG_OUT_HIGH_FAME: 'CommonSituationJobId' = 195426 + RELAXATION_VENUES_CELEBRITY_HANG_OUT_LOW_FAME: 'CommonSituationJobId' = 195425 + RELAXATION_VENUE_BARTENDER: 'CommonSituationJobId' = 156407 + RELAXATION_VENUE_MASSAGE_THERAPIST: 'CommonSituationJobId' = 117815 + RELAXATION_VENUE_REFLEXOLOGIST: 'CommonSituationJobId' = 119519 + REPAIR: 'CommonSituationJobId' = 129478 + RESTAURANT_DINER_BACKGROUND_BAD_DATE_ANGRY_SIM: 'CommonSituationJobId' = 132758 + RESTAURANT_DINER_BACKGROUND_BAD_DATE_FLIRTY_SIM: 'CommonSituationJobId' = 132759 + RESTAURANT_DINER_BACKGROUND_HAPPY_DATE: 'CommonSituationJobId' = 132676 + RESTAURANT_DINER_BACKGROUND_NPC_CELEBRITY: 'CommonSituationJobId' = 196197 + RESTAURANT_DINER_BACKGROUND_NPC_CRITIC: 'CommonSituationJobId' = 141387 + RESTAURANT_DINER_BACKGROUND_NPC_EARLY_BIRDS: 'CommonSituationJobId' = 132779 + RESTAURANT_DINER_BACKGROUND_NPC_FAMILY_MEAL_CHILD: 'CommonSituationJobId' = 132883 + RESTAURANT_DINER_BACKGROUND_NPC_FAMILY_MEAL_PARENT: 'CommonSituationJobId' = 132884 + RESTAURANT_DINER_BACKGROUND_STANDARD: 'CommonSituationJobId' = 132459 + RESTAURANT_DINER_EVENTS_NPC_BUSINESS_SUITS: 'CommonSituationJobId' = 133907 + RESTAURANT_DINER_EVENTS_NPC_COSPLAY: 'CommonSituationJobId' = 133902 + RESTAURANT_DINER_EVENTS_NPC_GHOSTS: 'CommonSituationJobId' = 133903 + RESTAURANT_DINER_EVENTS_NPC_NEARLY_NUDE: 'CommonSituationJobId' = 133909 + RESTAURANT_DINER_EVENTS_NPC_SPACE_RACE: 'CommonSituationJobId' = 133908 + RESTAURANT_DINER_SUB_NPC_BAD_DATE_ANGRY_SIM: 'CommonSituationJobId' = 132757 + RESTAURANT_DINER_SUB_NPC_BAD_DATE_FLIRTY_SIM: 'CommonSituationJobId' = 132756 + RESTAURANT_DINER_SUB_NPC_CELEBRITY: 'CommonSituationJobId' = 196200 + RESTAURANT_DINER_SUB_NPC_CRITIC: 'CommonSituationJobId' = 141389 + RESTAURANT_DINER_SUB_NPC_EARLY_BIRDS: 'CommonSituationJobId' = 132778 + RESTAURANT_DINER_SUB_NPC_FAMILY_MEAL_CHILD: 'CommonSituationJobId' = 132885 + RESTAURANT_DINER_SUB_NPC_FAMILY_MEAL_PARENT: 'CommonSituationJobId' = 132886 + RESTAURANT_DINER_SUB_NPC_HAPPY_DATE: 'CommonSituationJobId' = 132675 + RESTAURANT_DINER_SUB_STANDARD: 'CommonSituationJobId' = 132458 + ROBOTICS_BAR_NIGHT_MEET_UP_PARTICIPANT: 'CommonSituationJobId' = 229042 + ROOMMATE_NPC_EVENT: 'CommonSituationJobId' = 221661 + ROOMMATE_NPC_EVENT_ARGUMENT: 'CommonSituationJobId' = 223202 + ROOMMATE_NPC_EVENT_GET_HYPE: 'CommonSituationJobId' = 223201 + ROOMMATE_NPC_EVENT_LOCKED_OUT: 'CommonSituationJobId' = 223199 + ROOMMATE_NPC_EVENT_WHISPERS: 'CommonSituationJobId' = 223203 + ROOMMATE_NPC_EVENT_WOOING: 'CommonSituationJobId' = 223200 + ROOMMATE_NPC_STANDARD: 'CommonSituationJobId' = 208141 + ROOMMATE_NPC_STANDARD_FRIENDS: 'CommonSituationJobId' = 210614 + ROOMMATE_NPC_STANDARD_PARTY: 'CommonSituationJobId' = 212049 + ROOMMATE_NPC_STANDARD_POTENTIAL: 'CommonSituationJobId' = 220605 + ROOMMATE_NPC_STANDARD_SIGNIFICANT_OTHER: 'CommonSituationJobId' = 210690 + SECRET_LAB_PLAYER: 'CommonSituationJobId' = 204571 + SITUATION_APARTMENT_NEIGHBORS_VISITOR_COMPLAINT_NOISE: 'CommonSituationJobId' = 146044 + SITUATION_APARTMENT_NEIGHBORS_VISITOR_INTRIGUED_NOISE: 'CommonSituationJobId' = 146051 + SITUATION_APARTMENT_NEIGHBORS_VISITOR_INTRIGUED_SMELL: 'CommonSituationJobId' = 146054 + SITUATION_APARTMENT_NEIGHBOR_NPC_CHAT: 'CommonSituationJobId' = 155249 + SITUATION_APARTMENT_NEIGHBOR_NPC_CHECK_MAIL: 'CommonSituationJobId' = 137333 + SITUATION_APARTMENT_NEIGHBOR_NPC_HOST_LOUD_FIGHT: 'CommonSituationJobId' = 145044 + SITUATION_APARTMENT_NEIGHBOR_NPC_HOST_LOUD_MUSIC: 'CommonSituationJobId' = 138077 + SITUATION_APARTMENT_NEIGHBOR_NPC_HOST_LOUD_WOOHOO: 'CommonSituationJobId' = 138078 + SITUATION_APARTMENT_NEIGHBOR_NPC_INVITED_HANGOUT: 'CommonSituationJobId' = 146556 + SITUATION_APARTMENT_NEIGHBOR_NPC_TAKE_OUT_TRASH: 'CommonSituationJobId' = 137046 + SITUATION_APARTMENT_NEIGHBOR_PLAYER_HOST_CHAT: 'CommonSituationJobId' = 155252 + SITUATION_APARTMENT_NEIGHBOR_PLAYER_HOST_HANGOUT_GENERIC: 'CommonSituationJobId' = 139272 + SITUATION_APARTMENT_NEIGHBOR_VISITOR_HANGOUT_BRAINSTORM_ART_LOVER: 'CommonSituationJobId' = 141312 + SITUATION_APARTMENT_NEIGHBOR_VISITOR_HANGOUT_BRAINSTORM_CREATIVE: 'CommonSituationJobId' = 141311 + SITUATION_APARTMENT_NEIGHBOR_VISITOR_HANGOUT_CHILDS_PLAY: 'CommonSituationJobId' = 141134 + SITUATION_APARTMENT_NEIGHBOR_VISITOR_HANGOUT_CHILD_COMPLAINT: 'CommonSituationJobId' = 141133 + SITUATION_APARTMENT_NEIGHBOR_VISITOR_HANGOUT_FLIRTY_SHOWER: 'CommonSituationJobId' = 141135 + SITUATION_APARTMENT_NEIGHBOR_VISITOR_HANGOUT_GEEK_OUT: 'CommonSituationJobId' = 141132 + SITUATION_APARTMENT_NEIGHBOR_VISITOR_HANGOUT_GENERIC_BORED: 'CommonSituationJobId' = 139265 + SITUATION_APARTMENT_NEIGHBOR_VISITOR_HANGOUT_KEY_GROUP: 'CommonSituationJobId' = 140397 + SITUATION_APARTMENT_NEIGHBOR_VISITOR_HANGOUT_MUNCHIES_FOODIE: 'CommonSituationJobId' = 141313 + SITUATION_APARTMENT_NEIGHBOR_VISITOR_HANGOUT_MUNCHIES_GLUTTON: 'CommonSituationJobId' = 141314 + SITUATION_APARTMENT_NEIGHBOR_VISITOR_HANGOUT_UNINVITED_GOOFBALL: 'CommonSituationJobId' = 141929 + SITUATION_APARTMENT_NEIGHBOR_VISITOR_HANGOUT_UNINVITED_INSANE: 'CommonSituationJobId' = 141935 + SITUATION_APARTMENT_NEIGHBOR_VISITOR_HANGOUT_WORKOUT: 'CommonSituationJobId' = 141131 + SITUATION_BASIC_TRAIT_STRANGER_VILLE_NPC_CONSPIRACIST: 'CommonSituationJobId' = 206856 + SITUATION_BASIC_TRAIT_STRANGER_VILLE_NPC_MILITARY: 'CommonSituationJobId' = 206855 + SITUATION_BASIC_TRAIT_STRANGER_VILLE_NPC_SCIENTIST: 'CommonSituationJobId' = 206857 + SITUATION_CAREER_DOCTOR_NPC_ASSISTANT: 'CommonSituationJobId' = 111986 + SITUATION_CAREER_DOCTOR_NPC_DOCTOR: 'CommonSituationJobId' = 111985 + SITUATION_CAREER_DOCTOR_NPC_DOCTOR_DIAGNOSER: 'CommonSituationJobId' = 116252 + SITUATION_CAREER_DOCTOR_NPC_NURSE: 'CommonSituationJobId' = 111276 + SITUATION_CAREER_DOCTOR_NPC_OBGYN: 'CommonSituationJobId' = 116172 + SITUATION_CAREER_DOCTOR_NPC_ORDERLY: 'CommonSituationJobId' = 112046 + SITUATION_CAREER_DOCTOR_PATIENT_ADMITTED_LOW: 'CommonSituationJobId' = 113532 + SITUATION_CELEBRITY: 'CommonSituationJobId' = 196518 + SITUATION_CELEBRITY_GUITAR: 'CommonSituationJobId' = 202419 + SITUATION_CELEBRITY_MEET_AND_GREET_CELEBRITY: 'CommonSituationJobId' = 199570 + SITUATION_CELEBRITY_MEET_AND_GREET_FAN: 'CommonSituationJobId' = 199571 + SITUATION_CELEBRITY_TILE_PLACEMENT_CEREMONY_CROWD_MEMBER: 'CommonSituationJobId' = 195785 + SITUATION_CELEBRITY_TILE_PLACEMENT_CEREMONY_HONOREE: 'CommonSituationJobId' = 195784 + SITUATION_CITY_INVITES_ACTOR: 'CommonSituationJobId' = 139546 + SITUATION_CITY_INVITES_TARGET_SIM: 'CommonSituationJobId' = 143134 + SITUATION_CLUB_GO_DANCING_BACKGROUND_PARTY_GOER: 'CommonSituationJobId' = 123414 + SITUATION_CLUB_GO_DANCING_NPC_DANCER: 'CommonSituationJobId' = 123140 + SITUATION_CLUB_GO_DANCING_NPC_DANCE_PARTY_POOPER: 'CommonSituationJobId' = 123154 + SITUATION_CLUB_GO_DANCING_NPC_DJ: 'CommonSituationJobId' = 122831 + SITUATION_CLUB_GO_DANCING_NPC_DJ_AUDIENCE: 'CommonSituationJobId' = 123014 + SITUATION_CLUB_GO_DANCING_NPC_DJ_HIRED: 'CommonSituationJobId' = 123727 + SITUATION_CLUB_GO_DANCING_NPC_DJ_HIRED_LEVEL10: 'CommonSituationJobId' = 124275 + SITUATION_CLUB_GO_DANCING_NPC_DJ_LEVEL10: 'CommonSituationJobId' = 124255 + SITUATION_CLUB_GO_DANCING_PARTY_GOER: 'CommonSituationJobId' = 123013 + SITUATION_CLUB_GO_DANCING_PARTY_GOER_ACTOR: 'CommonSituationJobId' = 125412 + SITUATION_COUNTER: 'CommonSituationJobId' = 181150 + SITUATION_CRAFT_SALES_TABLE_OWNER: 'CommonSituationJobId' = 155035 + SITUATION_CRAFT_SALES_TABLE_VENDOR: 'CommonSituationJobId' = 153605 + SITUATION_CRAFT_SALES_TABLE_VENDOR_JUNGLE: 'CommonSituationJobId' = 177941 + SITUATION_CRAFT_SALES_TABLE_VENDOR_PAINTER: 'CommonSituationJobId' = 154396 + SITUATION_DANCE_BATTLE_FOLLOWER: 'CommonSituationJobId' = 128538 + SITUATION_DANCE_BATTLE_LEADER: 'CommonSituationJobId' = 128537 + SITUATION_DANCE_TOGETHER_FOLLOWER: 'CommonSituationJobId' = 128100 + SITUATION_DANCE_TOGETHER_LEADER: 'CommonSituationJobId' = 128099 + SITUATION_DETECTIVE_APB_CRIMINAL: 'CommonSituationJobId' = 107969 + SITUATION_DETECTIVE_APB_DECOY: 'CommonSituationJobId' = 108028 + SITUATION_DETECTIVE_APB_DETECTIVE: 'CommonSituationJobId' = 108029 + SITUATION_DETECTIVE_APB_NEUTRAL: 'CommonSituationJobId' = 109091 + SITUATION_DETECTIVE_CRIME_SCENE_OFFICER: 'CommonSituationJobId' = 109168 + SITUATION_DETECTIVE_CRIME_SCENE_PLAYER: 'CommonSituationJobId' = 109056 + SITUATION_DETECTIVE_CRIME_SCENE_WITNESS: 'CommonSituationJobId' = 109167 + SITUATION_DETECTIVE_PATROL_FIGHTER: 'CommonSituationJobId' = 110694 + SITUATION_DETECTIVE_PATROL_PLAYER: 'CommonSituationJobId' = 110742 + SITUATION_DETECTIVE_POLICE_STATION_ARRESTED: 'CommonSituationJobId' = 109134 + SITUATION_DETECTIVE_POLICE_STATION_CIVILIAN: 'CommonSituationJobId' = 108698 + SITUATION_DETECTIVE_POLICE_STATION_CRIMINAL: 'CommonSituationJobId' = 112327 + SITUATION_DETECTIVE_POLICE_STATION_NPC_ASSISTANT: 'CommonSituationJobId' = 114512 + SITUATION_DETECTIVE_POLICE_STATION_NPC_OFFICER: 'CommonSituationJobId' = 109997 + SITUATION_DETECTIVE_POLICE_STATION_PLAYER: 'CommonSituationJobId' = 109187 + SITUATION_DOCTOR_CAREER_PATIENT_ADMITTED_LOW_RECLINE: 'CommonSituationJobId' = 116177 + SITUATION_DOCTOR_CAREER_PATIENT_PREGNANT_EMERGENCY: 'CommonSituationJobId' = 113635 + SITUATION_GROUP_INTERACTION_FOLLOWER: 'CommonSituationJobId' = 187208 + SITUATION_GROUP_INTERACTION_LEADER: 'CommonSituationJobId' = 187206 + SITUATION_HOLIDAY: 'CommonSituationJobId' = 182319 + SITUATION_INFECTED: 'CommonSituationJobId' = 202598 + SITUATION_INFECTED_ATTACK: 'CommonSituationJobId' = 204727 + SITUATION_LANDLORD: 'CommonSituationJobId' = 135301 + SITUATION_LEAVE_NOW: 'CommonSituationJobId' = 24225 + SITUATION_LEAVE_NOW_MUST_RUN: 'CommonSituationJobId' = 24321 + SITUATION_LEAVE_SOON: 'CommonSituationJobId' = 24221 + SITUATION_MARKET_STALLS_CUSTOMER: 'CommonSituationJobId' = 132960 + SITUATION_MARKET_STALLS_VENDOR: 'CommonSituationJobId' = 132892 + SITUATION_MARKET_STALLS_VENDOR_CURIO_SHOP: 'CommonSituationJobId' = 202393 + SITUATION_MARKET_STALLS_VENDOR_HIRED_NPC: 'CommonSituationJobId' = 132882 + SITUATION_MARKET_STALLS_VENDOR_JUNGLE: 'CommonSituationJobId' = 182887 + SITUATION_MARKET_STALLS_VENDOR_SEASONAL: 'CommonSituationJobId' = 191308 + SITUATION_NPC_INVITES_LOUNGE_EVENT_ACTOR: 'CommonSituationJobId' = 198863 + SITUATION_NPC_INVITES_LOUNGE_EVENT_TARGET_SIM: 'CommonSituationJobId' = 198864 + SITUATION_PENTHOUSE_NEIGHBORS_HANGOUT_MUNCHIES_KEY_HOLDERS_FOODIE: 'CommonSituationJobId' = 146195 + SITUATION_PENTHOUSE_NEIGHBORS_HANGOUT_MUNCHIES_KEY_HOLDERS_GLUTTON: 'CommonSituationJobId' = 146196 + SITUATION_PENTHOUSE_NEIGHBORS_HANGOUT_MUNCHIES_NON_KEY_HOLDERS_FOODIE: 'CommonSituationJobId' = 146193 + SITUATION_PENTHOUSE_NEIGHBORS_HANGOUT_MUNCHIES_NON_KEY_HOLDERS_GLUTTON: 'CommonSituationJobId' = 146194 + SITUATION_PENTHOUSE_NEIGHBORS_VISITOR_HANGOUT_BRAINSTORM_KEY_HOLDERS_ART_LOVER: 'CommonSituationJobId' = 146280 + SITUATION_PENTHOUSE_NEIGHBORS_VISITOR_HANGOUT_BRAINSTORM_KEY_HOLDERS_CREATIVE: 'CommonSituationJobId' = 146279 + SITUATION_PENTHOUSE_NEIGHBORS_VISITOR_HANGOUT_BRAINSTORM_NON_KEY_HOLDERS_ART_LOVER: 'CommonSituationJobId' = 146278 + SITUATION_PENTHOUSE_NEIGHBORS_VISITOR_HANGOUT_BRAINSTORM_NON_KEY_HOLDERS_CREATIVE: 'CommonSituationJobId' = 146282 + SITUATION_PENTHOUSE_NEIGHBORS_VISITOR_HANGOUT_CHILDS_PLAY_KEY_HOLDERS: 'CommonSituationJobId' = 146408 + SITUATION_PENTHOUSE_NEIGHBORS_VISITOR_HANGOUT_CHILDS_PLAY_NON_KEY_HOLDERS: 'CommonSituationJobId' = 146409 + SITUATION_PENTHOUSE_NEIGHBORS_VISITOR_HANGOUT_GEEK_OUT_KEY_HOLDERS: 'CommonSituationJobId' = 146405 + SITUATION_PENTHOUSE_NEIGHBORS_VISITOR_HANGOUT_GEEK_OUT_NON_KEY_HOLDERS: 'CommonSituationJobId' = 146406 + SITUATION_PENTHOUSE_NEIGHBORS_VISITOR_HANGOUT_GENERIC_BORED_KEY_HOLDERS: 'CommonSituationJobId' = 146328 + SITUATION_PENTHOUSE_NEIGHBORS_VISITOR_HANGOUT_GENERIC_BORED_NON_KEY_HOLDERS: 'CommonSituationJobId' = 146329 + SITUATION_PENTHOUSE_NEIGHBORS_VISITOR_HANGOUT_UNINVITED_KEY_HOLDERS_GOOFBALL: 'CommonSituationJobId' = 146356 + SITUATION_PENTHOUSE_NEIGHBORS_VISITOR_HANGOUT_UNINVITED_KEY_HOLDERS_INSANE: 'CommonSituationJobId' = 146357 + SITUATION_PENTHOUSE_NEIGHBORS_VISITOR_HANGOUT_UNINVITED_NON_KEY_HOLDERS_GOOFBALL: 'CommonSituationJobId' = 146359 + SITUATION_PENTHOUSE_NEIGHBORS_VISITOR_HANGOUT_UNINVITED_NON_KEY_HOLDERS_INSANE: 'CommonSituationJobId' = 146360 + SITUATION_PENTHOUSE_NEIGHBORS_VISITOR_HANGOUT_WORKOUT_KEY_HOLDERS: 'CommonSituationJobId' = 146402 + SITUATION_PENTHOUSE_NEIGHBORS_VISITOR_HANGOUT_WORKOUT_NON_KEY_HOLDERS: 'CommonSituationJobId' = 146403 + SITUATION_PERFORMANCE_SPACE_BUSKER_HIRED_GUITAR: 'CommonSituationJobId' = 152921 + SITUATION_PERFORMANCE_SPACE_BUSKER_HIRED_VIOLIN: 'CommonSituationJobId' = 152920 + SITUATION_PERFORMANCE_SPACE_BUSKER_OPEN_STREET: 'CommonSituationJobId' = 142718 + SITUATION_PERFORMANCE_SPACE_BUSKER_VIOLIN: 'CommonSituationJobId' = 142060 + SITUATION_PET_ADOPTION_ADOPTABLE_PET: 'CommonSituationJobId' = 166817 + SITUATION_PET_ADOPTION_ADOPTION_OFFICER: 'CommonSituationJobId' = 166816 + SITUATION_POSSESSED: 'CommonSituationJobId' = 202246 + SITUATION_RETAIL_CUSTOMER_BARGAIN_SHOPPER: 'CommonSituationJobId' = 109149 + SITUATION_RETAIL_CUSTOMER_CELEBRITY_HIGH_FAME: 'CommonSituationJobId' = 195643 + SITUATION_RETAIL_CUSTOMER_CELEBRITY_LOW_FAME: 'CommonSituationJobId' = 195641 + SITUATION_RETAIL_CUSTOMER_LOITERER: 'CommonSituationJobId' = 109150 + SITUATION_RETAIL_CUSTOMER_MID_RANGE: 'CommonSituationJobId' = 109151 + SITUATION_RETAIL_CUSTOMER_SOCIALIZER: 'CommonSituationJobId' = 109152 + SITUATION_RETAIL_CUSTOMER_WEALTHY: 'CommonSituationJobId' = 109044 + SITUATION_RETAIL_EMPLOYEE: 'CommonSituationJobId' = 109248 + SITUATION_RETAIL_NPC_EMPLOYEE: 'CommonSituationJobId' = 112113 + SITUATION_SCARECROW: 'CommonSituationJobId' = 187081 + SITUATION_SCARECROW_PURPLE: 'CommonSituationJobId' = 191041 + SITUATION_SCARECROW_RED: 'CommonSituationJobId' = 191040 + SITUATION_SERVICE_SKELETON: 'CommonSituationJobId' = 177648 + SITUATION_SET_TABLE: 'CommonSituationJobId' = 161858 + SITUATION_SINGLE_SIM_LEAVE: 'CommonSituationJobId' = 101252 + SITUATION_SQUAD_PERK_SQUAD_LEADER: 'CommonSituationJobId' = 195512 + SITUATION_SQUAD_PERK_SQUAD_MEMBER: 'CommonSituationJobId' = 195505 + SITUATION_TEMPLE_SKELETON: 'CommonSituationJobId' = 178432 + SITUATION_TODDLER_CAREGIVER: 'CommonSituationJobId' = 156098 + SITUATION_TV_WORK_OUT_TOGETHER_FOLLOWER: 'CommonSituationJobId' = 164401 + SITUATION_TV_WORK_OUT_TOGETHER_LEADER: 'CommonSituationJobId' = 164400 + SITUATION_VIP_ROPE_BOUNCER: 'CommonSituationJobId' = 191861 + SLEEPER_PARK: 'CommonSituationJobId' = 27474 + SPA_GUEST_PLAYER: 'CommonSituationJobId' = 118867 + STAY_THE_NIGHT: 'CommonSituationJobId' = 40429 + STUDENT_LIBRARY_MUSEUM: 'CommonSituationJobId' = 27676 + TEEN_PARK: 'CommonSituationJobId' = 40112 + TELEPORT_TO_MAGIC_HQ_FAIL: 'CommonSituationJobId' = 215130 + TEMPORARY_CLONE: 'CommonSituationJobId' = 215158 + TODDLER_PLAY_DATE_GUEST_CAREGIVER: 'CommonSituationJobId' = 170144 + TODDLER_PLAY_DATE_GUEST_TODDLER: 'CommonSituationJobId' = 170082 + TODDLER_PLAY_DATE_HOST_CARE_GIVER: 'CommonSituationJobId' = 170083 + TODDLER_PLAY_DATE_HOST_TODDLER: 'CommonSituationJobId' = 170084 + TRAGIC_CLOWN: 'CommonSituationJobId' = 139603 + TRAINER_GYM: 'CommonSituationJobId' = 40327 + TRAINING_DUMMY_GROUP: 'CommonSituationJobId' = 203290 + TRAINING_DUMMY_SIM: 'CommonSituationJobId' = 203291 + TRASH_DUMPER: 'CommonSituationJobId' = 234516 + TRASH_UPDATE_WASTE_MANAGER: 'CommonSituationJobId' = 235043 + TRASH_UPDATE_WASTE_MANAGER_PLAYER: 'CommonSituationJobId' = 235802 + TUTORIAL_WELCOME_WAGON: 'CommonSituationJobId' = 77001 + UNGREETED_NPC_VISITING_NPC: 'CommonSituationJobId' = 34418 + UNGREETED_NPC_VISITING_NPC_UNIVERSITY: 'CommonSituationJobId' = 230379 + UNGREETED_PLAYER_VISITING_NPC: 'CommonSituationJobId' = 34417 + UNIVERSITY_GRADUATION_CEREMONY_ARTS: 'CommonSituationJobId' = 227001 + UNIVERSITY_GRADUATION_CEREMONY_ARTS_HOST: 'CommonSituationJobId' = 227912 + UNIVERSITY_GRADUATION_CEREMONY_ARTS_HOUSEHOLD: 'CommonSituationJobId' = 230458 + UNIVERSITY_GRADUATION_CEREMONY_SCIENCE: 'CommonSituationJobId' = 227003 + UNIVERSITY_GRADUATION_CEREMONY_SCIENCE_HOST: 'CommonSituationJobId' = 227918 + UNIVERSITY_GRADUATION_CEREMONY_SCIENCE_HOUSEHOLD: 'CommonSituationJobId' = 230455 + UNIVERSITY_RIVALS_RIVALS_ARTS: 'CommonSituationJobId' = 226703 + UNIVERSITY_RIVALS_RIVALS_SCIENCE: 'CommonSituationJobId' = 226701 + UNIVERSITY_STUDENT: 'CommonSituationJobId' = 221720 + UNIVERSITY_WORLD_ARTS_GHOST: 'CommonSituationJobId' = 222905 + UNIVERSITY_WORLD_ARTS_MASCOT: 'CommonSituationJobId' = 222866 + UNIVERSITY_WORLD_ARTS_STUDENT: 'CommonSituationJobId' = 222511 + UNIVERSITY_WORLD_CTYAE_SWIMMER: 'CommonSituationJobId' = 222840 + UNIVERSITY_WORLD_SCIENCE_MASCOT: 'CommonSituationJobId' = 222867 + UNIVERSITY_WORLD_SCIENCE_ROBOT: 'CommonSituationJobId' = 222943 + UNIVERSITY_WORLD_SCIENCE_STUDENT: 'CommonSituationJobId' = 222537 + UNIVERSITY_WORLD_TOURING_TEEN: 'CommonSituationJobId' = 222768 + UNIVERSITY_WORLD_YA_SWIMMER: 'CommonSituationJobId' = 222764 + VAMPIRE_INVITES_VAMPIRE_CREATION_NORMIE: 'CommonSituationJobId' = 152831 + VAMPIRE_INVITES_VAMPIRE_CREATION_VAMPIRE: 'CommonSituationJobId' = 152407 + VAMPIRE_VISIT: 'CommonSituationJobId' = 152616 + VAMPIRE_VISIT_INITIAL: 'CommonSituationJobId' = 155259 + VENUE_ARTS_CENTER_FORMAL_VIEWER: 'CommonSituationJobId' = 144891 + VENUE_ARTS_CENTER_GHOST_VIEWER: 'CommonSituationJobId' = 144899 + VENUE_ARTS_CENTER_MUSICIAN_GUITAR: 'CommonSituationJobId' = 144841 + VENUE_ARTS_CENTER_MUSICIAN_PIANO: 'CommonSituationJobId' = 144853 + VENUE_ARTS_CENTER_MUSICIAN_VIOLIN: 'CommonSituationJobId' = 144854 + VENUE_ARTS_CENTER_PAINTER: 'CommonSituationJobId' = 144674 + VENUE_ARTS_CENTER_PARTY_MUSICIAN_GUITAR: 'CommonSituationJobId' = 144879 + VENUE_ARTS_CENTER_PARTY_MUSICIAN_PIANO: 'CommonSituationJobId' = 144880 + VENUE_ARTS_CENTER_PARTY_MUSICIAN_VIOLIN: 'CommonSituationJobId' = 144881 + VENUE_ARTS_CENTER_PARTY_PAINTER: 'CommonSituationJobId' = 144894 + VENUE_ARTS_CENTER_PARTY_VIEWER: 'CommonSituationJobId' = 144893 + VENUE_ARTS_CENTER_PLAYER: 'CommonSituationJobId' = 148660 + VENUE_ARTS_CENTER_SCULPTOR: 'CommonSituationJobId' = 144777 + VENUE_ARTS_CENTER_VIEWER: 'CommonSituationJobId' = 144266 + VENUE_ARTS_CENTER_YOUNG_MUSICIAN_PIANO: 'CommonSituationJobId' = 144856 + VENUE_ARTS_CENTER_YOUNG_MUSICIAN_VIOLIN: 'CommonSituationJobId' = 144855 + VENUE_ARTS_CENTER_YOUNG_PAINTER: 'CommonSituationJobId' = 144834 + VENUE_ARTS_CENTER_YOUNG_VIEWER: 'CommonSituationJobId' = 144835 + VENUE_BAR_ALIEN_NIGHT: 'CommonSituationJobId' = 122626 + VENUE_BAR_BEAR_NIGHT: 'CommonSituationJobId' = 126612 + VENUE_BAR_GHOST_NIGHT: 'CommonSituationJobId' = 122625 + VENUE_BAR_GUYS_NIGHT: 'CommonSituationJobId' = 122629 + VENUE_BAR_HAPPY_HOUR: 'CommonSituationJobId' = 121146 + VENUE_BAR_KNIGHT_NIGHT: 'CommonSituationJobId' = 130283 + VENUE_BAR_LADIES_NIGHT: 'CommonSituationJobId' = 122627 + VENUE_BAR_SINGLES_NIGHT: 'CommonSituationJobId' = 122628 + VENUE_BEACH_BEACH_COMBER: 'CommonSituationJobId' = 207758 + VENUE_BEACH_BEACH_COMBER_WALK_BY: 'CommonSituationJobId' = 212410 + VENUE_BEACH_LIFE_GUARD: 'CommonSituationJobId' = 207759 + VENUE_BEACH_MERFOLK: 'CommonSituationJobId' = 207760 + VENUE_BEACH_SAND_ARTIST: 'CommonSituationJobId' = 207761 + VENUE_BEACH_SWIMMER: 'CommonSituationJobId' = 205337 + VENUE_BEACH_TANNER: 'CommonSituationJobId' = 207762 + VENUE_BEACH_WATER_ENTHUSIAST: 'CommonSituationJobId' = 207763 + VENUE_BOWLING_BOWLER: 'CommonSituationJobId' = 160124 + VENUE_BOWLING_GROUP_2_BOWLER: 'CommonSituationJobId' = 161094 + VENUE_BOWLING_GROUP_3_BOWLER: 'CommonSituationJobId' = 161106 + VENUE_BOWLING_GROUP_4_BOWLER: 'CommonSituationJobId' = 161107 + VENUE_BOWLING_GROUP_BOWLER: 'CommonSituationJobId' = 161083 + VENUE_BOWLING_TEEN_BOWLER: 'CommonSituationJobId' = 160167 + VENUE_CHEF: 'CommonSituationJobId' = 130833 + VENUE_COMMUNITY_GARDEN_GARDENER_GROUP: 'CommonSituationJobId' = 223954 + VENUE_COMMUNITY_MARKET_SHOPPER_GROUP: 'CommonSituationJobId' = 224112 + VENUE_COMMUNITY_SHARED_CANDLE_CRAFTER: 'CommonSituationJobId' = 235342 + VENUE_COMMUNITY_SHARED_CHILD: 'CommonSituationJobId' = 232586 + VENUE_COMMUNITY_SHARED_FABRICATOR: 'CommonSituationJobId' = 232583 + VENUE_COMMUNITY_SHARED_GARDENER: 'CommonSituationJobId' = 232370 + VENUE_COMMUNITY_SHARED_INSECT_FARMER: 'CommonSituationJobId' = 233424 + VENUE_COMMUNITY_SHARED_PAINTER: 'CommonSituationJobId' = 232585 + VENUE_COMMUNITY_SHARED_SCROUNGER: 'CommonSituationJobId' = 234657 + VENUE_COMMUNITY_SHARED_SCROUNGER_WOOHOO: 'CommonSituationJobId' = 235511 + VENUE_COMMUNITY_SHARED_WOODWORKER: 'CommonSituationJobId' = 232584 + VENUE_HOME_CHEF: 'CommonSituationJobId' = 140124 + VENUE_HOST: 'CommonSituationJobId' = 131306 + VENUE_MAKER_SPACE_MENTOR: 'CommonSituationJobId' = 232587 + VENUE_MAKER_SPACE_RECYCLING_GURU: 'CommonSituationJobId' = 232588 + VENUE_MARKETPLACE_SHOPPER: 'CommonSituationJobId' = 233861 + VENUE_MASTER_FISHERMAN: 'CommonSituationJobId' = 77065 + VENUE_MASTER_GARDENER: 'CommonSituationJobId' = 77066 + VENUE_MASTER_HERBALIST: 'CommonSituationJobId' = 102179 + VENUE_NIGHTCLUB_NPC_DANCER: 'CommonSituationJobId' = 123554 + VENUE_PETS_BLACKLIST: 'CommonSituationJobId' = 169533 + VENUE_PETS_CAT: 'CommonSituationJobId' = 170229 + VENUE_PETS_DOG: 'CommonSituationJobId' = 169532 + VENUE_PETS_PET_OWNER_CAT_ARTS_CENTER: 'CommonSituationJobId' = 172750 + VENUE_PETS_PET_OWNER_CAT_BAR: 'CommonSituationJobId' = 170226 + VENUE_PETS_PET_OWNER_CAT_CAFE: 'CommonSituationJobId' = 179099 + VENUE_PETS_PET_OWNER_CAT_CLUB: 'CommonSituationJobId' = 172494 + VENUE_PETS_PET_OWNER_CAT_GYM: 'CommonSituationJobId' = 172547 + VENUE_PETS_PET_OWNER_CAT_KARAOKE: 'CommonSituationJobId' = 172778 + VENUE_PETS_PET_OWNER_CAT_LIBRARY: 'CommonSituationJobId' = 172647 + VENUE_PETS_PET_OWNER_CAT_LOUNGE: 'CommonSituationJobId' = 172677 + VENUE_PETS_PET_OWNER_CAT_MUSEUM: 'CommonSituationJobId' = 172703 + VENUE_PETS_PET_OWNER_CAT_PARK: 'CommonSituationJobId' = 170227 + VENUE_PETS_PET_OWNER_CAT_POOL: 'CommonSituationJobId' = 172804 + VENUE_PETS_PET_OWNER_DOG_ARTS_CENTER: 'CommonSituationJobId' = 172751 + VENUE_PETS_PET_OWNER_DOG_BAR: 'CommonSituationJobId' = 169522 + VENUE_PETS_PET_OWNER_DOG_CAFE: 'CommonSituationJobId' = 179102 + VENUE_PETS_PET_OWNER_DOG_CLUB: 'CommonSituationJobId' = 172495 + VENUE_PETS_PET_OWNER_DOG_GYM: 'CommonSituationJobId' = 172558 + VENUE_PETS_PET_OWNER_DOG_KARAOKE: 'CommonSituationJobId' = 172780 + VENUE_PETS_PET_OWNER_DOG_LIBRARY: 'CommonSituationJobId' = 172656 + VENUE_PETS_PET_OWNER_DOG_LOUNGE: 'CommonSituationJobId' = 172678 + VENUE_PETS_PET_OWNER_DOG_MUSEUM: 'CommonSituationJobId' = 172704 + VENUE_PETS_PET_OWNER_DOG_PARK: 'CommonSituationJobId' = 169523 + VENUE_PETS_PET_OWNER_DOG_POOL: 'CommonSituationJobId' = 172803 + VENUE_POOL_CHILD_SWIMMER: 'CommonSituationJobId' = 125100 + VENUE_POOL_ELDER_SWIMMER: 'CommonSituationJobId' = 125101 + VENUE_POOL_GENERIC_SWIMMER: 'CommonSituationJobId' = 125099 + VENUE_POOL_LOUNGER: 'CommonSituationJobId' = 125102 + VENUE_POOL_PLAYER_SWIMMER: 'CommonSituationJobId' = 176643 + VENUE_RESTAURANT_DINER_PLAYER: 'CommonSituationJobId' = 132719 + VENUE_RESTAURANT_PLAYER_GROUP_IDLE: 'CommonSituationJobId' = 135262 + VENUE_STUDENT_COMMONS_ARTS_MIXER_JUICE_KEG_BEARER: 'CommonSituationJobId' = 222054 + VENUE_STUDENT_COMMONS_ARTS_MIXER_MASCOT: 'CommonSituationJobId' = 229957 + VENUE_STUDENT_COMMONS_ARTS_MIXER_STUDENT: 'CommonSituationJobId' = 222134 + VENUE_STUDENT_COMMONS_ARTS_POETRY_CONTESTANT: 'CommonSituationJobId' = 221663 + VENUE_STUDENT_COMMONS_ARTS_POETRY_CONTESTANT_PLAYER: 'CommonSituationJobId' = 221589 + VENUE_STUDENT_COMMONS_ARTS_POETRY_PLAYER_CONTROLLER: 'CommonSituationJobId' = 221628 + VENUE_STUDENT_COMMONS_ARTS_POETRY_TEA_SERVER: 'CommonSituationJobId' = 221800 + VENUE_STUDENT_COMMONS_EXAM_CRAM_PLAYER: 'CommonSituationJobId' = 222192 + VENUE_STUDENT_COMMONS_MIXER_PROFESSOR: 'CommonSituationJobId' = 222136 + VENUE_STUDENT_COMMONS_PROFESSOR_ARTS_GOOD: 'CommonSituationJobId' = 219265 + VENUE_STUDENT_COMMONS_PROFESSOR_ARTS_GRUMPY: 'CommonSituationJobId' = 219264 + VENUE_STUDENT_COMMONS_PROFESSOR_ARTS_HIP: 'CommonSituationJobId' = 219263 + VENUE_STUDENT_COMMONS_PROFESSOR_ARTS_SMART: 'CommonSituationJobId' = 226916 + VENUE_STUDENT_COMMONS_PROFESSOR_SCIENCE_GOOD: 'CommonSituationJobId' = 219267 + VENUE_STUDENT_COMMONS_PROFESSOR_SCIENCE_GRUMPY: 'CommonSituationJobId' = 219268 + VENUE_STUDENT_COMMONS_PROFESSOR_SCIENCE_HIP: 'CommonSituationJobId' = 219269 + VENUE_STUDENT_COMMONS_PROFESSOR_SCIENCE_SMART: 'CommonSituationJobId' = 226915 + VENUE_STUDENT_COMMONS_SCIENCE_E_SPORTS_CONTESTANT: 'CommonSituationJobId' = 221664 + VENUE_STUDENT_COMMONS_SCIENCE_E_SPORTS_EXPERT_CONTESTANT: 'CommonSituationJobId' = 221971 + VENUE_STUDENT_COMMONS_SCIENCE_MIXER_JUICE_KEG_BEARER: 'CommonSituationJobId' = 220377 + VENUE_STUDENT_COMMONS_SCIENCE_MIXER_MASCOT: 'CommonSituationJobId' = 229952 + VENUE_STUDENT_COMMONS_SCIENCE_MIXER_PROFESSOR: 'CommonSituationJobId' = 230396 + VENUE_STUDENT_COMMONS_SCIENCE_MIXER_STUDENT: 'CommonSituationJobId' = 222135 + VENUE_STUDENT_COMMONS_STUDENTS_ARTS: 'CommonSituationJobId' = 219230 + VENUE_STUDENT_COMMONS_STUDENTS_SCIENCE: 'CommonSituationJobId' = 219231 + VENUE_STUDENT_COMMONS_VISITORS_ARTS: 'CommonSituationJobId' = 219232 + VENUE_STUDENT_COMMONS_VISITORS_SCIENCE: 'CommonSituationJobId' = 219233 + VENUE_WAITER: 'CommonSituationJobId' = 130418 + VET_EMPLOYEE: 'CommonSituationJobId' = 165162 + VET_PET: 'CommonSituationJobId' = 164710 + VET_PET_EXAM: 'CommonSituationJobId' = 170927 + VET_PET_OWNER: 'CommonSituationJobId' = 164711 + VET_PLAYER: 'CommonSituationJobId' = 168071 + VET_PLAYER_PET_EXAM: 'CommonSituationJobId' = 174920 + VET_VENDING_MACHINE_CUSTOMER: 'CommonSituationJobId' = 172630 + VISITOR: 'CommonSituationJobId' = 16182 + VISITOR_PET: 'CommonSituationJobId' = 175547 + VISITOR_ROOMMATE: 'CommonSituationJobId' = 196885 + VOODOO_SUMMONED: 'CommonSituationJobId' = 40531 + WALKER_BEAR: 'CommonSituationJobId' = 104590 + WALKER_CAMPING_FOREST: 'CommonSituationJobId' = 106140 + WALKER_CITY_LIFE_APARTMENT_NEIGHBOR_VISITOR_COME_FROM_APT: 'CommonSituationJobId' = 141055 + WALKER_CITY_LIFE_APARTMENT_NEIGHBOR_VISITOR_GO_TO_APT: 'CommonSituationJobId' = 141054 + WALKER_CITY_LIFE_COFFEE_DRINKER: 'CommonSituationJobId' = 134352 + WALKER_CITY_LIFE_COMMUTER: 'CommonSituationJobId' = 134353 + WALKER_CITY_LIFE_COMMUTER_APARTMENT_NEIGHBOR_SCHOOL_COME_FROM_APT: 'CommonSituationJobId' = 139560 + WALKER_CITY_LIFE_COMMUTER_APARTMENT_NEIGHBOR_SCHOOL_GO_TO_APT: 'CommonSituationJobId' = 141047 + WALKER_CITY_LIFE_COMMUTER_APARTMENT_NEIGHBOR_WORK_COME_FROM_APT: 'CommonSituationJobId' = 139556 + WALKER_CITY_LIFE_COMMUTER_APARTMENT_NEIGHBOR_WORK_GO_TO_APT: 'CommonSituationJobId' = 141048 + WALKER_CITY_LIFE_LIVES_ON_STREET: 'CommonSituationJobId' = 155986 + WALKER_CITY_LIFE_PHONE_CHATTER: 'CommonSituationJobId' = 134355 + WALKER_CITY_LIFE_SNACKER: 'CommonSituationJobId' = 134354 + WALKER_CLOWN: 'CommonSituationJobId' = 97228 + WALKER_CRIMINAL: 'CommonSituationJobId' = 97224 + WALKER_DESERT_OASIS: 'CommonSituationJobId' = 9484 + WALKER_DOG_BEING_WALKED: 'CommonSituationJobId' = 133588 + WALKER_GARDENER: 'CommonSituationJobId' = 196906 + WALKER_GARDENER_TO_LOT: 'CommonSituationJobId' = 200555 + WALKER_GARDEN_DISTRICT: 'CommonSituationJobId' = 9485 + WALKER_GARDEN_DISTRICT_FAMILY_TIME: 'CommonSituationJobId' = 36749 + WALKER_GARDEN_DISTRICT_ON_THE_TOWN: 'CommonSituationJobId' = 36748 + WALKER_GARDEN_DISTRICT_PARK_AFTER_DARK: 'CommonSituationJobId' = 36772 + WALKER_GARDEN_DISTRICT_PARK_JOGGER: 'CommonSituationJobId' = 36773 + WALKER_GARDEN_DISTRICT_PARK_PLAY_TIME: 'CommonSituationJobId' = 36771 + WALKER_GARDEN_DISTRICT_PARK_RELAXER: 'CommonSituationJobId' = 36775 + WALKER_GARDEN_DISTRICT_PARK_STREAKER: 'CommonSituationJobId' = 238444 + WALKER_GARDEN_DISTRICT_SCHOOL_COMMUTER: 'CommonSituationJobId' = 36744 + WALKER_GARDEN_DISTRICT_WORK_COMMUTER: 'CommonSituationJobId' = 36732 + WALKER_HOT_DOG: 'CommonSituationJobId' = 97231 + WALKER_JOB: 'CommonSituationJobId' = 16183 + WALKER_JUNGLE_STRAY_CAT: 'CommonSituationJobId' = 181416 + WALKER_JUNGLE_STRAY_DOG: 'CommonSituationJobId' = 181417 + WALKER_MAID: 'CommonSituationJobId' = 97236 + WALKER_MAID_TO_LOT: 'CommonSituationJobId' = 200553 + WALKER_NEIGHBOR: 'CommonSituationJobId' = 120058 + WALKER_NEIGHBOR_PARK_JOGGER: 'CommonSituationJobId' = 126209 + WALKER_NEIGHBOR_SCHOOL_COMMUTER: 'CommonSituationJobId' = 126177 + WALKER_PET_WORLD_DOG_WALKERS_DOG: 'CommonSituationJobId' = 168142 + WALKER_PET_WORLD_DOG_WALKERS_WALKER: 'CommonSituationJobId' = 168143 + WALKER_PET_WORLD_GHOST_CAT: 'CommonSituationJobId' = 164210 + WALKER_PET_WORLD_GHOST_DOG: 'CommonSituationJobId' = 164209 + WALKER_PET_WORLD_GHOST_DOG_LIGHTHOUSE: 'CommonSituationJobId' = 175691 + WALKER_PET_WORLD_SIM_BEACH_JOGGER: 'CommonSituationJobId' = 164199 + WALKER_PET_WORLD_SIM_BEACH_WALKER: 'CommonSituationJobId' = 164200 + WALKER_PET_WORLD_SIM_WORKER: 'CommonSituationJobId' = 163998 + WALKER_PET_WORLD_STRAY_CAT: 'CommonSituationJobId' = 164205 + WALKER_PET_WORLD_STRAY_CAT_FISHER: 'CommonSituationJobId' = 164207 + WALKER_PET_WORLD_STRAY_CAT_IN_HEAT: 'CommonSituationJobId' = 164206 + WALKER_PET_WORLD_STRAY_CAT_ON_LOT: 'CommonSituationJobId' = 178581 + WALKER_PET_WORLD_STRAY_DOG: 'CommonSituationJobId' = 164203 + WALKER_PET_WORLD_STRAY_DOG_IN_HEAT: 'CommonSituationJobId' = 164204 + WALKER_PET_WORLD_STRAY_DOG_ON_LOT: 'CommonSituationJobId' = 178589 + WALKER_PIZZA: 'CommonSituationJobId' = 97237 + WALKER_RENT_DUE_APARTMENT_LANDLORD: 'CommonSituationJobId' = 143687 + WALKER_REPAIRMAN: 'CommonSituationJobId' = 197789 + WALKER_REPAIRMAN_TO_LOT: 'CommonSituationJobId' = 200557 + WALKER_RING_DOORBELL_ACQUIRED_FAMILY_REL_BIT: 'CommonSituationJobId' = 164640 + WALKER_RING_DOORBELL_NEIGHBOR: 'CommonSituationJobId' = 100054 + WALKER_RING_DOORBELL_VAMPIRE: 'CommonSituationJobId' = 153168 + WALKER_RING_DOORBELL_WITH_RELATIONSHIP: 'CommonSituationJobId' = 40341 + WALKER_TEEN: 'CommonSituationJobId' = 160243 + WALKER_VAMPIRE: 'CommonSituationJobId' = 153740 + WALKER_VAMPIRE_HAS_HOME: 'CommonSituationJobId' = 156392 + WALKER_WALK_OF_SHAME: 'CommonSituationJobId' = 76150 + WALKER_WINDENBURG: 'CommonSituationJobId' = 9486 + WALK_BY_ALIEN: 'CommonSituationJobId' = 113924 + WALK_BY_ALIEN_IN_DISGUISE: 'CommonSituationJobId' = 116921 + WALK_BY_CELEBRITY_HANG_OUT_HIGH_FAME: 'CommonSituationJobId' = 191718 + WALK_BY_CELEBRITY_HANG_OUT_HIGH_FAME_YAE: 'CommonSituationJobId' = 202103 + WALK_BY_CELEBRITY_HANG_OUT_LOW_FAME: 'CommonSituationJobId' = 191719 + WALK_BY_CELEBRITY_HANG_OUT_LOW_FAME_YAE: 'CommonSituationJobId' = 202104 + WALK_BY_ECO_WORLD_FREEGAN: 'CommonSituationJobId' = 236937 + WALK_BY_ECO_WORLD_VOTER_WALK_BY: 'CommonSituationJobId' = 234197 + WALK_BY_EVENT_FALL_CHALLENGE_2016_DO_TD_CELEBRATOR: 'CommonSituationJobId' = 153130 + WALK_BY_EVENT_SPRING_CHALLENGE_PLANT_SIM_NPC: 'CommonSituationJobId' = 163058 + WALK_BY_FAKE_VAMPIRE: 'CommonSituationJobId' = 153770 + WALK_BY_FAME_WORLD_CELEBRITY_LEAVE_HOME: 'CommonSituationJobId' = 196918 + WALK_BY_FAME_WORLD_CELEBRITY_RETURN_HOME: 'CommonSituationJobId' = 196919 + WALK_BY_FAME_WORLD_PAPARAZZI: 'CommonSituationJobId' = 200337 + WALK_BY_FAME_WORLD_RESIDENTS_SCHOOL_LEAVE_HOME: 'CommonSituationJobId' = 196881 + WALK_BY_FAME_WORLD_RESIDENTS_SCHOOL_RETURN_HOME: 'CommonSituationJobId' = 196886 + WALK_BY_FAME_WORLD_RESIDENTS_WORK_LEAVE_HOME: 'CommonSituationJobId' = 196817 + WALK_BY_FAME_WORLD_RESIDENTS_WORK_RETURN_HOME: 'CommonSituationJobId' = 196818 + WALK_BY_FAME_WORLD_STUDIO_ACTOR: 'CommonSituationJobId' = 197814 + WALK_BY_FAME_WORLD_STUDIO_ASSISTANT: 'CommonSituationJobId' = 197788 + WALK_BY_FAME_WORLD_TOURIST: 'CommonSituationJobId' = 201115 + WALK_BY_ISLANDER: 'CommonSituationJobId' = 216000 + WALK_BY_ISLANDER_JOGGER: 'CommonSituationJobId' = 216137 + WALK_BY_ISLANDER_LOUNGER: 'CommonSituationJobId' = 216537 + WALK_BY_ISLANDER_TEEN: 'CommonSituationJobId' = 216147 + WALK_BY_JUNGLE_CHILD: 'CommonSituationJobId' = 181345 + WALK_BY_JUNGLE_TYAE: 'CommonSituationJobId' = 181344 + WALK_BY_MAGIC_DUELIST: 'CommonSituationJobId' = 216809 + WALK_BY_MAGIC_PORTAL_GO_TO_PORTAL: 'CommonSituationJobId' = 217141 + WALK_BY_MAGIC_PORTAL_LEAVE_PORTAL: 'CommonSituationJobId' = 217139 + WALK_BY_POLICE_PATROL: 'CommonSituationJobId' = 112412 + WALK_BY_RING_DOORBELL_MAX_FAMILY_REL_BIT: 'CommonSituationJobId' = 168417 + WALK_BY_SCOUTING: 'CommonSituationJobId' = 188543 + WALK_BY_SEASONAL_FALL: 'CommonSituationJobId' = 184890 + WALK_BY_SEASONAL_SPRING: 'CommonSituationJobId' = 184888 + WALK_BY_SEASONAL_SUMMER: 'CommonSituationJobId' = 184889 + WALK_BY_SEASONAL_WINTER: 'CommonSituationJobId' = 184891 + WALK_BY_STRANGER_VILLE_CONSPIRACIST: 'CommonSituationJobId' = 203308 + WALK_BY_STRANGER_VILLE_CONSPIRACIST_LIBRARY: 'CommonSituationJobId' = 207322 + WALK_BY_STRANGER_VILLE_INFECTED: 'CommonSituationJobId' = 203974 + WALK_BY_STRANGER_VILLE_MILITARY: 'CommonSituationJobId' = 203293 + WALK_BY_STRANGER_VILLE_MILITARY_BAR: 'CommonSituationJobId' = 207323 + WALK_BY_STRANGER_VILLE_OGA: 'CommonSituationJobId' = 203307 + WALK_BY_STRANGER_VILLE_SCIENTIST: 'CommonSituationJobId' = 203294 + WALK_BY_STRANGER_VILLE_SCIENTIST_LIBRARY: 'CommonSituationJobId' = 207324 + WALK_BY_SURPRISE_HOLIDAY_PIRATE_DAY: 'CommonSituationJobId' = 182814 + WALK_BY_TRAGIC_CLOWN: 'CommonSituationJobId' = 139892 + WALK_BY_UNIVERSITY_STUDENT_HANGOUT_ARTS_STUDENT: 'CommonSituationJobId' = 225745 + WALK_BY_UNIVERSITY_STUDENT_HANGOUT_PROFESSOR: 'CommonSituationJobId' = 225747 + WALK_BY_UNIVERSITY_STUDENT_HANGOUT_SCIENCE_PROFESSOR: 'CommonSituationJobId' = 230611 + WALK_BY_UNIVERSITY_STUDENT_HANGOUT_SCIENCE_STUDENT: 'CommonSituationJobId' = 225746 + WALK_BY_UNIVERSITY_WORLD_ARTS_FROM_ARENA_ATHLETE_E_SPORTS: 'CommonSituationJobId' = 222568 + WALK_BY_UNIVERSITY_WORLD_ARTS_FROM_ARENA_ATHLETE_SOCCER: 'CommonSituationJobId' = 222569 + WALK_BY_UNIVERSITY_WORLD_ARTS_FROM_ARENA_MASCOT: 'CommonSituationJobId' = 222864 + WALK_BY_UNIVERSITY_WORLD_ARTS_FROM_ARENA_SPORTS_FAN_E_SPORTS: 'CommonSituationJobId' = 222570 + WALK_BY_UNIVERSITY_WORLD_ARTS_FROM_ARENA_SPORTS_FAN_SOCCER: 'CommonSituationJobId' = 222571 + WALK_BY_UNIVERSITY_WORLD_ARTS_FROM_CLASS_BIKE_STUDENT: 'CommonSituationJobId' = 222818 + WALK_BY_UNIVERSITY_WORLD_ARTS_FROM_CLASS_PROFESSOR: 'CommonSituationJobId' = 222574 + WALK_BY_UNIVERSITY_WORLD_ARTS_FROM_CLASS_STUDENT: 'CommonSituationJobId' = 222573 + WALK_BY_UNIVERSITY_WORLD_ARTS_SCHOOL_GHOST: 'CommonSituationJobId' = 222757 + WALK_BY_UNIVERSITY_WORLD_ARTS_TO_ARENA_ATHLETE_E_SPORTS: 'CommonSituationJobId' = 222549 + WALK_BY_UNIVERSITY_WORLD_ARTS_TO_ARENA_ATHLETE_SOCCER: 'CommonSituationJobId' = 222552 + WALK_BY_UNIVERSITY_WORLD_ARTS_TO_ARENA_MASCOT: 'CommonSituationJobId' = 222863 + WALK_BY_UNIVERSITY_WORLD_ARTS_TO_ARENA_SPORTS_FAN_E_SPORTS: 'CommonSituationJobId' = 222550 + WALK_BY_UNIVERSITY_WORLD_ARTS_TO_ARENA_SPORTS_FAN_SOCCER: 'CommonSituationJobId' = 222551 + WALK_BY_UNIVERSITY_WORLD_ARTS_TO_CLASS_BIKE_STUDENT: 'CommonSituationJobId' = 222816 + WALK_BY_UNIVERSITY_WORLD_ARTS_TO_CLASS_PROFESSOR: 'CommonSituationJobId' = 222581 + WALK_BY_UNIVERSITY_WORLD_ARTS_TO_CLASS_STUDENT: 'CommonSituationJobId' = 222582 + WALK_BY_UNIVERSITY_WORLD_GENERAL_ARTS_BIKE_STUDENT: 'CommonSituationJobId' = 228134 + WALK_BY_UNIVERSITY_WORLD_GENERAL_ARTS_STUDENT: 'CommonSituationJobId' = 222662 + WALK_BY_UNIVERSITY_WORLD_GENERAL_PROFESSOR: 'CommonSituationJobId' = 222664 + WALK_BY_UNIVERSITY_WORLD_GENERAL_SCIENCE_BIKE_STUDENT: 'CommonSituationJobId' = 228135 + WALK_BY_UNIVERSITY_WORLD_GENERAL_SCIENCE_STUDENT: 'CommonSituationJobId' = 222663 + WALK_BY_UNIVERSITY_WORLD_SCIENCE_FROM_ARENA_ATHLETE_E_SPORTS: 'CommonSituationJobId' = 222616 + WALK_BY_UNIVERSITY_WORLD_SCIENCE_FROM_ARENA_ATHLETE_SOCCER: 'CommonSituationJobId' = 222617 + WALK_BY_UNIVERSITY_WORLD_SCIENCE_FROM_ARENA_MASCOT: 'CommonSituationJobId' = 222861 + WALK_BY_UNIVERSITY_WORLD_SCIENCE_FROM_ARENA_SPORTS_FAN_E_SPORTS: 'CommonSituationJobId' = 222618 + WALK_BY_UNIVERSITY_WORLD_SCIENCE_FROM_ARENA_SPORTS_FAN_SOCCER: 'CommonSituationJobId' = 222619 + WALK_BY_UNIVERSITY_WORLD_SCIENCE_FROM_CLASS_BIKE_STUDENT: 'CommonSituationJobId' = 222815 + WALK_BY_UNIVERSITY_WORLD_SCIENCE_FROM_CLASS_PROFESSOR: 'CommonSituationJobId' = 222621 + WALK_BY_UNIVERSITY_WORLD_SCIENCE_FROM_CLASS_STUDENT: 'CommonSituationJobId' = 222622 + WALK_BY_UNIVERSITY_WORLD_SCIENCE_TO_ARENA_ATHLETE_E_SPORTS: 'CommonSituationJobId' = 222626 + WALK_BY_UNIVERSITY_WORLD_SCIENCE_TO_ARENA_ATHLETE_SOCCER: 'CommonSituationJobId' = 222627 + WALK_BY_UNIVERSITY_WORLD_SCIENCE_TO_ARENA_MASCOT: 'CommonSituationJobId' = 222862 + WALK_BY_UNIVERSITY_WORLD_SCIENCE_TO_ARENA_SPORTS_FAN_E_SPORTS: 'CommonSituationJobId' = 222628 + WALK_BY_UNIVERSITY_WORLD_SCIENCE_TO_ARENA_SPORTS_FAN_SOCCER: 'CommonSituationJobId' = 222629 + WALK_BY_UNIVERSITY_WORLD_SCIENCE_TO_CLASS_BIKE_STUDENT: 'CommonSituationJobId' = 222814 + WALK_BY_UNIVERSITY_WORLD_SCIENCE_TO_CLASS_PROFESSOR: 'CommonSituationJobId' = 222631 + WALK_BY_UNIVERSITY_WORLD_SCIENCE_TO_CLASS_STUDENT: 'CommonSituationJobId' = 222632 + WALK_BY_WEATHER_RAINING: 'CommonSituationJobId' = 184885 + WALK_BY_WEATHER_SNOWING: 'CommonSituationJobId' = 184886 + WARDROBE_PEDESTAL_STYLIST: 'CommonSituationJobId' = 191613 + WATER_SCOOTER_WALK_BY_JOB: 'CommonSituationJobId' = 209405 + WEDDING_BETROTHED: 'CommonSituationJobId' = 9363 + WELCOME_WAGON_DOOR_KNOCKER_NEIGHBOR: 'CommonSituationJobId' = 119786 + WELCOME_WAGON_DOOR_KNOCKER_NEIGHBOR_INFECTED: 'CommonSituationJobId' = 202804 + WELCOME_WAGON_FRUIT_BEARER_NEIGHBOR: 'CommonSituationJobId' = 119361 + WELCOME_WAGON_FRUIT_BEARER_NEIGHBOR_INFECTED: 'CommonSituationJobId' = 202805 + WELCOME_WAGON_NEW_NEIGHBOR_ACTOR: 'CommonSituationJobId' = 119362 + WELCOME_WAGON_NEW_NEIGHBOR_ACTOR_STRANGE: 'CommonSituationJobId' = 204555 + WELCOME_WAGON_SECRET_AGENT: 'CommonSituationJobId' = 202808 + WELCOME_WAGON_WELCOMING_NEIGHBOR: 'CommonSituationJobId' = 119352 + WELCOME_WAGON_WELCOMING_NEIGHBOR_INFECTED: 'CommonSituationJobId' = 202806 + YOGA_CLASS_MEMBER: 'CommonSituationJobId' = 118131 + YOGA_INSTRUCTOR: 'CommonSituationJobId' = 118130 + YOGA_INSTRUCTOR_IDLE: 'CommonSituationJobId' = 118373 diff --git a/Scripts/s4ap/sims4communitylib/enums/situations_enum.py b/Scripts/s4ap/sims4communitylib/enums/situations_enum.py new file mode 100644 index 0000000..74ac7fa --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/situations_enum.py @@ -0,0 +1,1217 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonSituationId(CommonInt): + """Identifiers for vanilla situations. + + """ + INVALID: 'CommonSituationId' = 0 + ACTOR_CAREER_BACKGROUND_ACTOR: 'CommonSituationId' = 191064 + ACTOR_CAREER_BACKGROUND_PRODUCER: 'CommonSituationId' = 191065 + ACTOR_CAREER_CO_STAR1: 'CommonSituationId' = 189568 + ACTOR_CAREER_CO_STAR2: 'CommonSituationId' = 189569 + ACTOR_CAREER_DIRECTOR_COMMERCIAL: 'CommonSituationId' = 197476 + ACTOR_CAREER_DIRECTOR_FILM: 'CommonSituationId' = 197479 + ACTOR_CAREER_DIRECTOR_HIGH_BUDGET_TV: 'CommonSituationId' = 197478 + ACTOR_CAREER_DIRECTOR_LOW_BUDGET_TV: 'CommonSituationId' = 197477 + ACTOR_CAREER_DOLLY_CAMERA_OPERATOR: 'CommonSituationId' = 190522 + ACTOR_CAREER_SINGING_IN_THE_RAIN_CO_STAR1_MALE: 'CommonSituationId' = 190331 + ACTOR_CAREER_SPECIAL_EFFECTS_OPERATOR: 'CommonSituationId' = 192112 + ACTOR_CAREER_STATIONARY_CAMERA_OPERATOR: 'CommonSituationId' = 191287 + ALIEN_BARFLY: 'CommonSituationId' = 122604 + ALIEN_NIGHT: 'CommonSituationId' = 122635 + ALIEN_WORLD_BARFLY: 'CommonSituationId' = 114215 + ALIEN_WORLD_BARTENDER: 'CommonSituationId' = 114212 + ANCHORED_OPEN_STREETS_BONFIRE_THREE_SIMS: 'CommonSituationId' = 126402 + ANCHORED_OPEN_STREETS_BONFIRE_TWO_SIMS: 'CommonSituationId' = 126401 + APARTMENTS_NEIGHBOR_CHECK_MAIL: 'CommonSituationId' = 137329 + APARTMENTS_NEIGHBOR_TRASH_CHUTE_USE: 'CommonSituationId' = 137041 + ARTS_CENTER_VENUE_FORMAL_VIEWER: 'CommonSituationId' = 144897 + ARTS_CENTER_VENUE_GHOST_VIEWER: 'CommonSituationId' = 144898 + ARTS_CENTER_VENUE_MUSICIAN_GUITAR: 'CommonSituationId' = 144843 + ARTS_CENTER_VENUE_MUSICIAN_PIANO: 'CommonSituationId' = 144839 + ARTS_CENTER_VENUE_MUSICIAN_VIOLIN: 'CommonSituationId' = 144844 + ARTS_CENTER_VENUE_PAINTER: 'CommonSituationId' = 144672 + ARTS_CENTER_VENUE_PARTY_MUSICIAN_GUITAR: 'CommonSituationId' = 144883 + ARTS_CENTER_VENUE_PARTY_MUSICIAN_PIANO: 'CommonSituationId' = 144889 + ARTS_CENTER_VENUE_PARTY_MUSICIAN_VIOLIN: 'CommonSituationId' = 144890 + ARTS_CENTER_VENUE_PARTY_PAINTER: 'CommonSituationId' = 144895 + ARTS_CENTER_VENUE_PARTY_VIEWER: 'CommonSituationId' = 144896 + ARTS_CENTER_VENUE_SCULPTOR: 'CommonSituationId' = 144771 + ARTS_CENTER_VENUE_VIEWER: 'CommonSituationId' = 144259 + ARTS_CENTER_VENUE_VIEWER_DRINKER: 'CommonSituationId' = 154450 + ARTS_CENTER_VENUE_YOUNG_MUSICIAN_PIANO: 'CommonSituationId' = 144857 + ARTS_CENTER_VENUE_YOUNG_MUSICIAN_VIOLIN: 'CommonSituationId' = 144845 + ARTS_CENTER_VENUE_YOUNG_PAINTER: 'CommonSituationId' = 144833 + ARTS_CENTER_VENUE_YOUNG_VIEWER: 'CommonSituationId' = 144836 + AUTONOMOUS_HOLIDAY_TRADITION_FLOWER_BUNNY: 'CommonSituationId' = 186910 + AUTONOMOUS_OPEN_STREETS_BBQ: 'CommonSituationId' = 38900 + AUTONOMOUS_OPEN_STREETS_BUSH: 'CommonSituationId' = 126332 + AUTONOMOUS_OPEN_STREETS_BUSH_NEIGHBOR: 'CommonSituationId' = 127058 + AUTONOMOUS_OPEN_STREETS_CITY_LIFE_CITY_REPAIR: 'CommonSituationId' = 144295 + AUTONOMOUS_OPEN_STREETS_CITY_LIFE_LIVES_ON_STREET_ADULT: 'CommonSituationId' = 184969 + AUTONOMOUS_OPEN_STREETS_CITY_LIFE_LIVES_ON_STREET_ADULT_A: 'CommonSituationId' = 134673 + AUTONOMOUS_OPEN_STREETS_CITY_LIFE_LIVES_ON_STREET_ADULT_B: 'CommonSituationId' = 155988 + AUTONOMOUS_OPEN_STREETS_CITY_LIFE_LIVES_ON_STREET_ADULT_C: 'CommonSituationId' = 155989 + AUTONOMOUS_OPEN_STREETS_CITY_LIFE_LIVES_ON_STREET_ADULT_D: 'CommonSituationId' = 155990 + AUTONOMOUS_OPEN_STREETS_CITY_LIFE_LIVES_ON_STREET_CHILD: 'CommonSituationId' = 152483 + AUTONOMOUS_OPEN_STREETS_CITY_LIFE_LIVING_STATUE_BUSKER: 'CommonSituationId' = 134212 + AUTONOMOUS_OPEN_STREETS_CITY_LIFE_TOURIST: 'CommonSituationId' = 134209 + AUTONOMOUS_OPEN_STREETS_CITY_LIFE_WEIRDOS: 'CommonSituationId' = 139837 + AUTONOMOUS_OPEN_STREETS_CITY_LIFE_WEIRDO_BATHROBE_ELDER: 'CommonSituationId' = 145068 + AUTONOMOUS_OPEN_STREETS_CITY_LIFE_WEIRDO_DAY_TIME: 'CommonSituationId' = 134211 + AUTONOMOUS_OPEN_STREETS_CITY_LIFE_WEIRDO_RACCOON: 'CommonSituationId' = 145070 + AUTONOMOUS_OPEN_STREETS_FISH: 'CommonSituationId' = 77048 + AUTONOMOUS_OPEN_STREETS_FISH_NEIGHBOR: 'CommonSituationId' = 127054 + AUTONOMOUS_OPEN_STREETS_GARDEN: 'CommonSituationId' = 38937 + AUTONOMOUS_OPEN_STREETS_JOGGER: 'CommonSituationId' = 40408 + AUTONOMOUS_OPEN_STREETS_MARKET_STALLS_CUSTOMER: 'CommonSituationId' = 180994 + AUTONOMOUS_OPEN_STREETS_MARKET_STALLS_CUSTOMER_ISLANDER: 'CommonSituationId' = 215816 + AUTONOMOUS_OPEN_STREETS_MARKET_STALLS_CUSTOMER_SEASONAL: 'CommonSituationId' = 191323 + AUTONOMOUS_OPEN_STREETS_MASTER_FISHERMAN: 'CommonSituationId' = 40505 + AUTONOMOUS_OPEN_STREETS_MASTER_GARDENER: 'CommonSituationId' = 40367 + AUTONOMOUS_OPEN_STREETS_PAINTER: 'CommonSituationId' = 126202 + AUTONOMOUS_OPEN_STREETS_RESTROOM: 'CommonSituationId' = 40785 + AUTONOMOUS_OPEN_STREETS_SEASONAL_LEAVES: 'CommonSituationId' = 180995 + AUTONOMOUS_OPEN_STREETS_SEASONAL_SKATER: 'CommonSituationId' = 180996 + AUTONOMOUS_OPEN_STREETS_SEASONAL_SKATER_PRO: 'CommonSituationId' = 185769 + AUTONOMOUS_OPEN_STREETS_SEASONAL_SNOW_CHILD: 'CommonSituationId' = 185706 + AUTONOMOUS_OPEN_STREETS_SEASONAL_SNOW_TYAE: 'CommonSituationId' = 181487 + AUTONOMOUS_OPEN_STREETS_TOURIST: 'CommonSituationId' = 122804 + AUTONOMOUS_OPEN_STREET_BRAWL: 'CommonSituationId' = 122806 + AUTONOMOUS_OPEN_STREET_CITY_LIFE_WEIRDO_DAY_TIME_RACCOON: 'CommonSituationId' = 145065 + AUTONOMOUS_OPEN_STREET_CITY_LIFE_WEIRDO_DAY_TIME_TOWELS: 'CommonSituationId' = 145066 + AUTO_SMOKE_PARTY: 'CommonSituationId' = 16184 + BABY_BIRTH_HOSPITAL: 'CommonSituationId' = 112065 + BACKGROUND_CAFE: 'CommonSituationId' = 122313 + BARISTA_VENUE: 'CommonSituationId' = 122314 + BARTENDER_RELAXATION_VENUE: 'CommonSituationId' = 156409 + BARTENDER_RESTAURANT: 'CommonSituationId' = 134881 + BAR_BARFLY: 'CommonSituationId' = 121150 + BAR_BARTENDER: 'CommonSituationId' = 121151 + BAR_BARTENDER_ARTS_CENTER_VENUE: 'CommonSituationId' = 144979 + BAR_BARTENDER_GO_DANCING: 'CommonSituationId' = 128105 + BAR_BARTENDER_JUNGLE: 'CommonSituationId' = 185003 + BAR_BARTENDER_MYSHUNO_MEADOWS: 'CommonSituationId' = 147049 + BAR_COLLEGE_EVENT_ART_SOCIETY_PLAYER: 'CommonSituationId' = 231023 + BAR_COLLEGE_EVENT_DEBATE_ORG_PLAYER: 'CommonSituationId' = 231024 + BAR_COLLEGE_EVENT_HONOR_SOCIETY_PLAYER: 'CommonSituationId' = 231025 + BAR_COLLEGE_EVENT_PARTY_PLAYER: 'CommonSituationId' = 231026 + BAR_COLLEGE_EVENT_PRANK_PLAYER: 'CommonSituationId' = 231027 + BAR_COLLEGE_EVENT_ROBOTICS_PLAYER: 'CommonSituationId' = 231019 + BAR_HAPPY_HOUR: 'CommonSituationId' = 121141 + BASIC_TRAIT_SITUATION_ECO_PERSONALITY_ECO_MASTER: 'CommonSituationId' = 234896 + BASIC_TRAIT_SITUATION_ECO_PERSONALITY_ENTREPRENEUR: 'CommonSituationId' = 234895 + BASIC_TRAIT_SITUATION_ECO_PERSONALITY_MAKER: 'CommonSituationId' = 234894 + BASIC_TRAIT_STRANGERVILLE_NPC_SCIENTIST: 'CommonSituationId' = 206839 + BASIC_TRAIT_STRANGER_VILLE_NPC_CONSPIRACIST: 'CommonSituationId' = 206838 + BASIC_TRAIT_STRANGER_VILLE_NPC_MILITARY: 'CommonSituationId' = 206840 + BASIC_TRAIT_STRANGER_VILLE_NPC_SCIENTIST: 'CommonSituationId' = 2068390186 + BEACH_VENUE_BEACH_COMBER: 'CommonSituationId' = 205294 + BEACH_VENUE_LIFE_GUARD: 'CommonSituationId' = 205296 + BEACH_VENUE_MERFOLK: 'CommonSituationId' = 205293 + BEACH_VENUE_SAND_ARTIST: 'CommonSituationId' = 205295 + BEACH_VENUE_SUN_TANNER_SITUATION: 'CommonSituationId' = 210067 + BEACH_VENUE_SWIMMER: 'CommonSituationId' = 207831 + BEACH_VENUE_TANNER: 'CommonSituationId' = 205292 + BEACH_VENUE_WATER_ENTHUSIAST: 'CommonSituationId' = 205291 + BEAR_BARFLY: 'CommonSituationId' = 126605 + BEAR_NIGHT: 'CommonSituationId' = 126611 + BIRTHDAY_PARTY: 'CommonSituationId' = 31635 + BLACK_AND_WHITE_PARTY: 'CommonSituationId' = 35077 + BOWLING_VENUE_FAMILY_BOWLING: 'CommonSituationId' = 160120 + BOWLING_VENUE_GROUP_2_BOWLING: 'CommonSituationId' = 161096 + BOWLING_VENUE_GROUP_3_BOWLING: 'CommonSituationId' = 161104 + BOWLING_VENUE_GROUP_4_BOWLING: 'CommonSituationId' = 161105 + BOWLING_VENUE_GROUP_BOWLING: 'CommonSituationId' = 160163 + BOWLING_VENUE_TEEN_GROUP_BOWLING: 'CommonSituationId' = 160228 + BOWLING_VENUE_TEEN_HANG_OUT: 'CommonSituationId' = 160164 + BUTLER_SITUATION: 'CommonSituationId' = 145804 + CAFE_BUSINESS_PARTNERS: 'CommonSituationId' = 122325 + CAFE_FRIENDS: 'CommonSituationId' = 122323 + CAFE_GENERIC_CUSTOMER: 'CommonSituationId' = 122309 + CAFE_MEDIA_ADDICT: 'CommonSituationId' = 122319 + CAFE_READER: 'CommonSituationId' = 122320 + CAFE_TO_GO_CUSTOMER: 'CommonSituationId' = 122321 + CALLBACK_TO_LODGING: 'CommonSituationId' = 111723 + CALL_EVENT_NPC_OVER: 'CommonSituationId' = 149685 + CALL_EVENT_NPC_OVER_FALL_CHALLENGE: 'CommonSituationId' = 153349 + CALL_EVENT_NPC_OVER_POSITIVITY_CHALLENGE: 'CommonSituationId' = 198764 + CALL_EVENT_NPC_OVER_SPRING_CHALLENGE: 'CommonSituationId' = 162944 + CAMPFIRE_FOUR_SIMS: 'CommonSituationId' = 106016 + CAMPFIRE_THREE_SIMS: 'CommonSituationId' = 106015 + CAMPFIRE_TWO_SIMS: 'CommonSituationId' = 105947 + CAREER_ACTOR_CAREER_COMMERCIAL_HOSPITAL: 'CommonSituationId' = 192847 + CAREER_ACTOR_CAREER_COMMERCIAL_HOUSE_NICE: 'CommonSituationId' = 193601 + CAREER_ACTOR_CAREER_COMMERCIAL_KIDS: 'CommonSituationId' = 193603 + CAREER_ACTOR_CAREER_COMMERCIAL_PIRATE: 'CommonSituationId' = 192688 + CAREER_ACTOR_CAREER_COMMERCIAL_WESTERN: 'CommonSituationId' = 193599 + CAREER_ACTOR_CAREER_MOVIE_CITY: 'CommonSituationId' = 189158 + CAREER_ACTOR_CAREER_MOVIE_MEDIEVAL: 'CommonSituationId' = 193677 + CAREER_ACTOR_CAREER_MOVIE_PIRATE: 'CommonSituationId' = 193678 + CAREER_ACTOR_CAREER_MOVIE_SUPERHERO: 'CommonSituationId' = 193680 + CAREER_ACTOR_CAREER_MOVIE_VICTORIAN: 'CommonSituationId' = 193679 + CAREER_ACTOR_CAREER_MOVIE_WESTERN: 'CommonSituationId' = 193676 + CAREER_ACTOR_CAREER_TV_HIGH_APOCALYPSE: 'CommonSituationId' = 193646 + CAREER_ACTOR_CAREER_TV_HIGH_HOSPITAL: 'CommonSituationId' = 193647 + CAREER_ACTOR_CAREER_TV_HIGH_POLICE: 'CommonSituationId' = 193650 + CAREER_ACTOR_CAREER_TV_HIGH_VICTORIAN: 'CommonSituationId' = 193649 + CAREER_ACTOR_CAREER_TV_HIGH_WESTERN: 'CommonSituationId' = 193648 + CAREER_ACTOR_CAREER_TV_LOW_HOUSE_LOW: 'CommonSituationId' = 193619 + CAREER_ACTOR_CAREER_TV_LOW_HOUSE_NICE: 'CommonSituationId' = 193617 + CAREER_ACTOR_CAREER_TV_LOW_KIDS: 'CommonSituationId' = 193620 + CAREER_ACTOR_CAREER_TV_LOW_PIRATE: 'CommonSituationId' = 193616 + CAREER_ACTOR_CAREER_TV_LOW_WESTERN: 'CommonSituationId' = 193618 + CAREER_BARFLY: 'CommonSituationId' = 122660 + CAREER_DETECTIVE_APB_PLAYER: 'CommonSituationId' = 115361 + CAREER_DETECTIVE_CRIME_SCENE: 'CommonSituationId' = 108865 + CAREER_DETECTIVE_CRIME_SCENE_PLAYER: 'CommonSituationId' = 115003 + CAREER_DETECTIVE_PATROL: 'CommonSituationId' = 110690 + CAREER_DETECTIVE_POLICE_STATION_CHIEF: 'CommonSituationId' = 116968 + CAREER_DETECTIVE_POLICE_STATION_CRIMINALS: 'CommonSituationId' = 112325 + CAREER_DETECTIVE_POLICE_STATION_NPC_OFFICERS: 'CommonSituationId' = 109998 + CAREER_DOCTOR_AWAY_EVENTS_HOUSE_CALL_PATIENT: 'CommonSituationId' = 114221 + CAREER_DOCTOR_AWAY_EVENTS_OUTBREAK_PATIENT: 'CommonSituationId' = 114222 + CAREER_DOCTOR_AWAY_EVENT_DOCTOR: 'CommonSituationId' = 114242 + CAREER_DOCTOR_HOUSE_CALL_TRIGGER: 'CommonSituationId' = 114186 + CAREER_DOCTOR_NPC_ASSISTANT: 'CommonSituationId' = 112371 + CAREER_DOCTOR_NPC_DOCTOR: 'CommonSituationId' = 112370 + CAREER_DOCTOR_NPC_DOCTOR_DIAGNOSER: 'CommonSituationId' = 116250 + CAREER_DOCTOR_NPC_NURSE: 'CommonSituationId' = 112409 + CAREER_DOCTOR_NPC_ORDERLY: 'CommonSituationId' = 112408 + CAREER_DOCTOR_NPC_PATIENT_ADMITTED: 'CommonSituationId' = 112666 + CAREER_DOCTOR_NPC_PATIENT_ADMITTED_RECLINE: 'CommonSituationId' = 116179 + CAREER_DOCTOR_OUTBREAK_TRIGGER: 'CommonSituationId' = 114271 + CAREER_EVENT_DETECTIVE_CAREER_1: 'CommonSituationId' = 108607 + CAREER_EVENT_DETECTIVE_CAREER_APB_NO_SUSPECT: 'CommonSituationId' = 112177 + CAREER_EVENT_DETECTIVE_CAREER_CLUES_NO_APB_NO_SUSPECT: 'CommonSituationId' = 112176 + CAREER_EVENT_DETECTIVE_CAREER_DAY01: 'CommonSituationId' = 112170 + CAREER_EVENT_DETECTIVE_CAREER_DAY02: 'CommonSituationId' = 112171 + CAREER_EVENT_DETECTIVE_CAREER_DAY03: 'CommonSituationId' = 112172 + CAREER_EVENT_DETECTIVE_CAREER_HAVE_SUSPECT: 'CommonSituationId' = 112173 + CAREER_EVENT_DETECTIVE_CAREER_NO_CASE: 'CommonSituationId' = 112174 + CAREER_EVENT_DETECTIVE_CAREER_NO_CLUES_NO_SUSPECT: 'CommonSituationId' = 112175 + CAREER_EVENT_DOCTOR_CAREER_ROUNDS_HIGH: 'CommonSituationId' = 112606 + CAREER_EVENT_DOCTOR_CAREER_ROUNDS_HIGH_COLLAPSED_PATIENT: 'CommonSituationId' = 115225 + CAREER_EVENT_DOCTOR_CAREER_ROUNDS_HIGH_DELIVER_BABY: 'CommonSituationId' = 115227 + CAREER_EVENT_DOCTOR_CAREER_ROUNDS_HIGH_HOUSE_CALL: 'CommonSituationId' = 114263 + CAREER_EVENT_DOCTOR_CAREER_ROUNDS_HIGH_OUTBREAK: 'CommonSituationId' = 114283 + CAREER_EVENT_DOCTOR_CAREER_ROUNDS_LOW: 'CommonSituationId' = 112628 + CAREER_EVENT_DOCTOR_CAREER_ROUNDS_LOW_SAMPLE_ANALYSIS: 'CommonSituationId' = 115234 + CAREER_EVENT_DOCTOR_CAREER_ROUNDS_MID: 'CommonSituationId' = 108049 + CAREER_EVENT_DOCTOR_CAREER_ROUNDS_MID_COLLAPSED_PATIENT: 'CommonSituationId' = 115231 + CAREER_EVENT_DOCTOR_CAREER_ROUNDS_MID_HOUSE_CALL: 'CommonSituationId' = 114292 + CAREER_EVENT_DOCTOR_CAREER_ROUNDS_MID_SAMPLE_ANALYSIS: 'CommonSituationId' = 115232 + CAREER_EVENT_DOCTOR_CAREER_SOCIALIZE: 'CommonSituationId' = 112664 + CAREER_EVENT_DOCTOR_CAREER_SOCIALIZE_DAY2: 'CommonSituationId' = 115773 + CAREER_EVENT_DOCTOR_UNDERSTAFFED: 'CommonSituationId' = 112676 + CAREER_EVENT_DOCTOR_UNDERSTAFFED_COLLAPSED_PATIENT: 'CommonSituationId' = 116016 + CAREER_EVENT_DOCTOR_UNDERSTAFFED_DELIVER_BABY: 'CommonSituationId' = 116017 + CAREER_EVENT_DOCTOR_UNDERSTAFFED_HOUSE_CALL: 'CommonSituationId' = 114250 + CAREER_EVENT_DOCTOR_UNDERSTAFFED_OUTBREAK: 'CommonSituationId' = 114279 + CAREER_EVENT_SCIENTIST_CAREER_ALIEN_VISIT: 'CommonSituationId' = 113534 + CAREER_EVENT_SCIENTIST_CAREER_ALIEN_WORLD_EVENT: 'CommonSituationId' = 113611 + CAREER_EVENT_SCIENTIST_CAREER_MAIN: 'CommonSituationId' = 112350 + CAREER_EVENT_SCIENTIST_CAREER_SIM_RAY_SURPRISE: 'CommonSituationId' = 113546 + CAREER_EVENT_SCIENTIST_CAREER_SURPRISE_COLLECT: 'CommonSituationId' = 112977 + CAREER_EVENT_SCIENTIST_CAREER_SURPRISE_GOOD_BAD: 'CommonSituationId' = 112743 + CAREGIVER_TODDLER: 'CommonSituationId' = 155917 + CAT_HANGOUT_STRAY_ON_LOT: 'CommonSituationId' = 178578 + CELEBRITY_GUITAR: 'CommonSituationId' = 202414 + CELEBRITY_HANG_OUT_HIGH_FAME: 'CommonSituationId' = 191716 + CELEBRITY_HANG_OUT_HIGH_FAME_YAE: 'CommonSituationId' = 202101 + CELEBRITY_HANG_OUT_LOW_FAME: 'CommonSituationId' = 191715 + CELEBRITY_HANG_OUT_LOW_FAME_YAE: 'CommonSituationId' = 202102 + CELEBRITY_TILE_PLACEMENT_CEREMONY_SITUATION: 'CommonSituationId' = 195786 + CHALET_GARDENS_FLIRTY_COUPLE: 'CommonSituationId' = 126388 + CHALET_GARDENS_PLAYER: 'CommonSituationId' = 127063 + CHARITY_BENEFIT_PARTY_NPC_HOSTED: 'CommonSituationId' = 202445 + CHARITY_BENEFIT_PARTY_SITUATION: 'CommonSituationId' = 197576 + CHEF_SITUATION: 'CommonSituationId' = 131068 + CITY_INVITES_FESTIVALS_ALL_BUY_A_SHIRT: 'CommonSituationId' = 149687 + CITY_INVITES_FESTIVALS_BLOSSOM_DRINK_TEA: 'CommonSituationId' = 138970 + CITY_INVITES_FESTIVALS_BLOSSOM_KISS: 'CommonSituationId' = 138971 + CITY_INVITES_FESTIVALS_BLOSSOM_MEET_PEOPLE: 'CommonSituationId' = 138951 + CITY_INVITES_FESTIVALS_BLOSSOM_PAINT: 'CommonSituationId' = 138950 + CITY_INVITES_FESTIVALS_BLOSSOM_THROW_PETALS: 'CommonSituationId' = 138949 + CITY_INVITES_FESTIVALS_FLEA_MARKET_BUY_SOMETHING: 'CommonSituationId' = 138973 + CITY_INVITES_FESTIVALS_FLEA_MARKET_HAGGLE: 'CommonSituationId' = 138972 + CITY_INVITES_FESTIVALS_FLEA_MARKET_WATCH_PERFORMER: 'CommonSituationId' = 138974 + CITY_INVITES_FESTIVALS_FOOD_BLOW_BUBBLES: 'CommonSituationId' = 148686 + CITY_INVITES_FESTIVALS_FOOD_BUY_INGREDIENTS: 'CommonSituationId' = 138953 + CITY_INVITES_FESTIVALS_FOOD_DISCUSS_LOCAL_CUISINE: 'CommonSituationId' = 138975 + CITY_INVITES_FESTIVALS_FOOD_EAT_BURRITO: 'CommonSituationId' = 138969 + CITY_INVITES_FESTIVALS_FOOD_EAT_SPICY: 'CommonSituationId' = 138948 + CITY_INVITES_FESTIVALS_FOOD_HARVEST: 'CommonSituationId' = 138983 + CITY_INVITES_FESTIVALS_FOOD_SAMPLE: 'CommonSituationId' = 138946 + CITY_INVITES_FESTIVALS_FOOD_TRY_CHOPSTICKS_FOOD: 'CommonSituationId' = 149417 + CITY_INVITES_FESTIVALS_LAMP_BUY_SHIRT: 'CommonSituationId' = 138954 + CITY_INVITES_FESTIVALS_LAMP_DRINK_TEA: 'CommonSituationId' = 138956 + CITY_INVITES_FESTIVALS_LAMP_EAT_FOOD: 'CommonSituationId' = 138978 + CITY_INVITES_FESTIVALS_LAMP_LIGHT_FIREWORKS: 'CommonSituationId' = 149688 + CITY_INVITES_FESTIVALS_LAMP_WATCH_FIREWORKS: 'CommonSituationId' = 138955 + CITY_INVITES_FESTIVALS_LOGIC_BUILD_ROCKET: 'CommonSituationId' = 138952 + CITY_INVITES_FESTIVALS_LOGIC_MOTION_GAMING: 'CommonSituationId' = 138979 + CITY_INVITES_FESTIVALS_LOGIC_OBSERVATORY: 'CommonSituationId' = 138982 + CITY_INVITES_FESTIVALS_LOGIC_PARTICIPATE_IN_CONTEST: 'CommonSituationId' = 138977 + CITY_INVITES_FESTIVALS_LOGIC_PROGRAM: 'CommonSituationId' = 138981 + CITY_INVITES_VENUE_INVITES_BAR: 'CommonSituationId' = 138976 + CITY_INVITES_VENUE_INVITES_GYM: 'CommonSituationId' = 138980 + CITY_INVITES_VENUE_INVITES_KARAOKE: 'CommonSituationId' = 142958 + CITY_INVITES_VENUE_INVITES_PARK: 'CommonSituationId' = 142959 + CIVIC_INSPECTOR_SITUATION: 'CommonSituationId' = 233261 + CLUB_GATHERING_SITUATION: 'CommonSituationId' = 122304 + COLLEGE_ORGANIZATIONS_EVENTS_SCHOOL_SPIRIT_DAY_MASCOT: 'CommonSituationId' = 208840 + COLLEGE_ORGANIZATIONS_EVENTS_SCHOOL_SPIRIT_PARTY_GAME_DAY_PARTY: 'CommonSituationId' = 208839 + COLLEGE_ORGANIZATIONS_EVENTS_SCHOOL_SPIRIT_PARTY_SCHOOL_SPIRIT_DAY: 'CommonSituationId' = 208838 + COLLEGE_ORGANIZATIONS_EVENTS_SCHOOL_SPIRIT_PRANK_ARTS_MASCOT: 'CommonSituationId' = 223449 + COLLEGE_ORGANIZATIONS_EVENTS_SCHOOL_SPIRIT_PRANK_SCIENCE_MASCOT: 'CommonSituationId' = 223450 + COLLEGE_ORGANIZATIONS_SMALL_EVENTS_STUDY_GROUP: 'CommonSituationId' = 209035 + COLLEGE_ORGANIZATION_PLAYER_DEBATE: 'CommonSituationId' = 225827 + COLLEGE_ORGANIZATION_PLAYER_DEBATE_PRACTICE: 'CommonSituationId' = 230075 + COLLEGE_ORGANIZATION_PLAYER_ROBOTICS_EXHIBITION: 'CommonSituationId' = 223860 + COLLEGE_ORGANIZATION_PLAYER_ROBOT_BUILDING_SESSION: 'CommonSituationId' = 225320 + COLLEGE_ORGANIZATION_PLAYER_SCHOOL_SPIRIT_PARTY_GAME_DAY_PARTY: 'CommonSituationId' = 225054 + COLLEGE_ORGANIZATION_PLAYER_SCHOOL_SPIRIT_PARTY_SCHOOL_SPIRIT_DAY: 'CommonSituationId' = 209367 + COLLEGE_ORGANIZATION_PLAYER_SCHOOL_SPIRIT_PRANK_CREATIVITY_CELEBRATION: 'CommonSituationId' = 223221 + COLLEGE_ORGANIZATION_PLAYER_SCHOOL_SPIRIT_PRANK_GAME_DAY_PARTY: 'CommonSituationId' = 223255 + COLLEGE_ORGANIZATION_PLAYER_SECRET_SOCIETY_RITUAL: 'CommonSituationId' = 223040 + COLLEGE_ORGANIZATION_ROBOTICS_EXHIBITION: 'CommonSituationId' = 223865 + COLLEGE_ORGANIZATION_SCHOOL_SPIRIT_PRANK_CREATIVITY_CELEBRATION: 'CommonSituationId' = 223236 + COLLEGE_ORGANIZATION_SCHOOL_SPIRIT_PRANK_GAME_DAY_PARTY: 'CommonSituationId' = 223248 + COMMUNITY_CLOSENESS_BIRTHDAY_GIFT: 'CommonSituationId' = 235003 + COMMUNITY_CLOSENESS_COMPLAINT: 'CommonSituationId' = 233496 + COMMUNITY_CLOSENESS_HANDY_NEIGHBOR: 'CommonSituationId' = 233495 + COMMUNITY_CLOSENESS_INTRO_TO_CIVIC_POLICIES_ECO_MASTER: 'CommonSituationId' = 237860 + COMMUNITY_CLOSENESS_INTRO_TO_CIVIC_POLICIES_ENTREPRENEUR: 'CommonSituationId' = 238041 + COMMUNITY_CLOSENESS_RANDOM_GIFT: 'CommonSituationId' = 233499 + COMMUNITY_CLOSENESS_SPARE_RECYCLING: 'CommonSituationId' = 233497 + COMMUNITY_CLOSENESS_TRASH_HELP: 'CommonSituationId' = 233498 + COMMUNITY_GARDEN_GARDENER: 'CommonSituationId' = 223951 + COMMUNITY_GROUP_MARKETPLACE_SHOPPER_PARENTS_WITH_CHILD: 'CommonSituationId' = 233879 + COMMUNITY_GROUP_SCROUNGER_WOOHOO: 'CommonSituationId' = 234659 + COMMUNITY_LOT_BOARD_DEBATER: 'CommonSituationId' = 224288 + COMMUNITY_MAKER_SPACE_MENTOR: 'CommonSituationId' = 232581 + COMMUNITY_MAKER_SPACE_RECYCLING_GURU: 'CommonSituationId' = 232582 + COMMUNITY_MARKETPLACE_SHOPPER: 'CommonSituationId' = 233862 + COMMUNITY_MARKET_SHOPPERS: 'CommonSituationId' = 224110 + COMMUNITY_SHARED_CANDLE_CRAFTER: 'CommonSituationId' = 235341 + COMMUNITY_SHARED_CHILD: 'CommonSituationId' = 232580 + COMMUNITY_SHARED_FABRICATOR: 'CommonSituationId' = 232577 + COMMUNITY_SHARED_GARDENER: 'CommonSituationId' = 232071 + COMMUNITY_SHARED_INSECT_FARMER: 'CommonSituationId' = 233423 + COMMUNITY_SHARED_PAINTER: 'CommonSituationId' = 232579 + COMMUNITY_SHARED_SCROUNGER: 'CommonSituationId' = 234655 + COMMUNITY_SHARED_WOODWORKER: 'CommonSituationId' = 232578 + COMPLEX_CLUB_DANCER: 'CommonSituationId' = 123532 + COMPLEX_CLUB_DANCER_SKILLED: 'CommonSituationId' = 123139 + COMPLEX_CLUB_DANCE_PARTY_POOPER: 'CommonSituationId' = 123156 + COMPLEX_CLUB_DJ_AUDIENCE: 'CommonSituationId' = 122997 + COMPLEX_EXPERIMENT: 'CommonSituationId' = 16185 + COSTUME_PARTY: 'CommonSituationId' = 35078 + COUNTDOWN_SITUATION: 'CommonSituationId' = 181148 + CRAFT_SALES_TABLE_OPEN_STREET_SALE: 'CommonSituationId' = 146715 + CRAFT_SALES_TABLE_OPEN_STREET_SALE_CUSTOMER: 'CommonSituationId' = 146713 + CRAFT_SALES_TABLE_YARD_SALE: 'CommonSituationId' = 146680 + CRAFT_SALES_TABLE_YARD_SALE_CUSTOMER: 'CommonSituationId' = 146683 + CREATE_AND_USE_OBJECT_FASHION_STUDIO_TRIPOD_TAKE_PHOTO_OF: 'CommonSituationId' = 216818 + CREATE_AND_USE_OBJECT_FASHION_STUDIO_TRIPOD_TAKE_PHOTO_OF_3_SIMS: 'CommonSituationId' = 217702 + CREATE_AND_USE_OBJECT_FASHION_STUDIO_TRIPOD_TAKE_PHOTO_OF_3_SIMS_SOLO: 'CommonSituationId' = 218299 + CREATE_AND_USE_OBJECT_FASHION_STUDIO_TRIPOD_TAKE_PHOTO_OF_CARRY: 'CommonSituationId' = 217892 + CREATE_AND_USE_OBJECT_FASHION_STUDIO_TRIPOD_TAKE_PHOTO_OF_CARRY_PET: 'CommonSituationId' = 218213 + CREATE_AND_USE_OBJECT_FASHION_STUDIO_TRIPOD_TAKE_PHOTO_OF_PAIRED: 'CommonSituationId' = 218091 + CREATE_AND_USE_OBJECT_FASHION_STUDIO_TRIPOD_TAKE_PHOTO_OF_PAIRED_LARGE_PET: 'CommonSituationId' = 219953 + CREATE_AND_USE_OBJECT_FASHION_STUDIO_TRIPOD_TAKE_PHOTO_OF_SINGLE_SIM: 'CommonSituationId' = 218739 + CREATE_AND_USE_OBJECT_FASHION_STUDIO_TRIPOD_TAKE_PHOTO_WITH_2_SIMS: 'CommonSituationId' = 218016 + CREATE_AND_USE_OBJECT_FASHION_STUDIO_TRIPOD_TAKE_PHOTO_WITH_3_SIMS: 'CommonSituationId' = 218412 + DANCE_BATTLE_SITUATION: 'CommonSituationId' = 128467 + DANCE_TOGETHER_SET_01: 'CommonSituationId' = 128577 + DANCE_TOGETHER_SET_02: 'CommonSituationId' = 129197 + DANCE_TOGETHER_SET_03: 'CommonSituationId' = 129194 + DANCE_TOGETHER_SET_04: 'CommonSituationId' = 129195 + DANCE_TOGETHER_SET_05: 'CommonSituationId' = 129196 + DANCE_TOGETHER_SET_06: 'CommonSituationId' = 129198 + DATE: 'CommonSituationId' = 16193 + DATE_TEEN: 'CommonSituationId' = 76577 + DEBATE_SHOWDOWN_DEBATE: 'CommonSituationId' = 222726 + DEBUG_PARTY: 'CommonSituationId' = 16186 + DETECTIVE_APB: 'CommonSituationId' = 107968 + DETECTIVE_APB_NEUTRAL: 'CommonSituationId' = 109103 + DETECTIVE_POLICE_STATION_ARREST: 'CommonSituationId' = 109132 + DETECTIVE_POLICE_STATION_CIVILIAN: 'CommonSituationId' = 108697 + DINNER_PARTY: 'CommonSituationId' = 16194 + DOG_HANGOUT_STRAY_ON_LOT: 'CommonSituationId' = 178594 + ECO_FOOTPRINT_SUN_RAYS: 'CommonSituationId' = 232861 + ECO_INSPECTOR_SITUATION: 'CommonSituationId' = 231860 + ECO_PERSONALITY_ECO_MASTER: 'CommonSituationId' = 235528 + ECO_PERSONALITY_ENTREPRENEUR: 'CommonSituationId' = 235529 + ECO_PERSONALITY_MAKER: 'CommonSituationId' = 235527 + EMPTY_LOT_NO_PAPARAZZI: 'CommonSituationId' = 197035 + ENSEMBLE_GROUP_CAFE_BUSINESS_MEETING: 'CommonSituationId' = 124925 + ENSEMBLE_GROUP_CAFE_FRIENDS: 'CommonSituationId' = 124926 + EVENT_LOGIC_FESTIVAL_HACKATHON: 'CommonSituationId' = 141300 + EVENT_LOGIC_FESTIVAL_UGT: 'CommonSituationId' = 141142 + E_SPORTS_ASSEMBLE_THE_TEAM: 'CommonSituationId' = 227361 + E_SPORTS_ASSEMBLE_THE_TEAM_ARTS: 'CommonSituationId' = 229679 + FAMILY_MEAL: 'CommonSituationId' = 33906 + FAN_FAN_STAN_FAN_TEEN: 'CommonSituationId' = 202009 + FAN_MEET_AND_GREET: 'CommonSituationId' = 201177 + FAN_STAN_CELEBRITY_SIMS: 'CommonSituationId' = 193803 + FAN_STAN_FAN: 'CommonSituationId' = 194437 + FAN_STAN_FAN_CHILD: 'CommonSituationId' = 201696 + FAN_STAN_STAN: 'CommonSituationId' = 194420 + FEMALE_BARFLY: 'CommonSituationId' = 122617 + FESTIVAL_BARTENDER_BLOSSOM_FESTIVAL: 'CommonSituationId' = 140557 + FESTIVAL_BARTENDER_FOOD_FESTIVAL: 'CommonSituationId' = 140572 + FESTIVAL_BARTENDER_LAMP_FESTIVAL: 'CommonSituationId' = 140559 + FESTIVAL_BLOSSOM_ARTIST: 'CommonSituationId' = 136082 + FESTIVAL_BLOSSOM_CRAFT_SALES_TABLE_VENDOR_PAINTING: 'CommonSituationId' = 153686 + FESTIVAL_BLOSSOM_CRAZY_TEEN: 'CommonSituationId' = 135712 + FESTIVAL_BLOSSOM_FESTIVAL_ROMANTIC_COUPLE: 'CommonSituationId' = 146773 + FESTIVAL_BLOSSOM_GENERAL: 'CommonSituationId' = 140573 + FESTIVAL_BLOSSOM_LOVE_GURU: 'CommonSituationId' = 146774 + FESTIVAL_BLOSSOM_PETAL_HEAD: 'CommonSituationId' = 135711 + FESTIVAL_BLOSSOM_SLEAZE: 'CommonSituationId' = 136236 + FESTIVAL_BLOSSOM_VIEWERS: 'CommonSituationId' = 143728 + FESTIVAL_BUSKER_BLOSSOM: 'CommonSituationId' = 142677 + FESTIVAL_BUSKER_FLEA_MARKET: 'CommonSituationId' = 142722 + FESTIVAL_BUSKER_FOOD: 'CommonSituationId' = 142675 + FESTIVAL_BUSKER_LAMP: 'CommonSituationId' = 142676 + FESTIVAL_FLEA_MARKET_CRAFT_SALES_TABLE_GENERAL_VENDOR: 'CommonSituationId' = 146944 + FESTIVAL_FLEA_MARKET_CRAFT_SALES_TABLE_PAINTING_VENDOR: 'CommonSituationId' = 146943 + FESTIVAL_FLEA_MARKET_GENERAL: 'CommonSituationId' = 140579 + FESTIVAL_FLEA_MARKET_HAGGLERS: 'CommonSituationId' = 142228 + FESTIVAL_FLEA_MARKET_VENDOR: 'CommonSituationId' = 139946 + FESTIVAL_FOOD_BUBBLE_BLOWERS: 'CommonSituationId' = 140104 + FESTIVAL_FOOD_GENERAL: 'CommonSituationId' = 140574 + FESTIVAL_FOOD_OVER_EATER: 'CommonSituationId' = 136423 + FESTIVAL_GARDENER: 'CommonSituationId' = 139615 + FESTIVAL_GUITARIST: 'CommonSituationId' = 134971 + FESTIVAL_LAMP_CONTEST_SITUATION: 'CommonSituationId' = 146802 + FESTIVAL_LAMP_DARK_SIDER: 'CommonSituationId' = 134839 + FESTIVAL_LAMP_DAZER: 'CommonSituationId' = 150997 + FESTIVAL_LAMP_FIREWORK_LIGHTERS: 'CommonSituationId' = 140105 + FESTIVAL_LAMP_GENERAL: 'CommonSituationId' = 140575 + FESTIVAL_LAMP_LIGHT_SIDER: 'CommonSituationId' = 134838 + FESTIVAL_LOGIC_CHESS: 'CommonSituationId' = 141323 + FESTIVAL_LOGIC_COSPLAYER: 'CommonSituationId' = 140789 + FESTIVAL_LOGIC_FAIR_ROCKET_SHIP_WOOHOOERS: 'CommonSituationId' = 142271 + FESTIVAL_LOGIC_GAMERS: 'CommonSituationId' = 140931 + FESTIVAL_LOGIC_GENERAL: 'CommonSituationId' = 140577 + FESTIVAL_LOGIC_ROCKET_SHIP_HOBBYIST: 'CommonSituationId' = 140938 + FESTIVAL_LOGIC_ROCKET_SHIP_USERS: 'CommonSituationId' = 140947 + FESTIVAL_ORGANIZATION_EVENT_PAINTING_IN_THE_PARK_MODEL: 'CommonSituationId' = 227365 + FESTIVAL_ORGANIZATION_EVENT_PAINTING_IN_THE_PARK_PAINTERS: 'CommonSituationId' = 223213 + FESTIVAL_ORGANIZATION_EVENT_PAINTING_IN_THE_PARK_PLAYER: 'CommonSituationId' = 223357 + FESTIVAL_ORGANIZATION_EVENT_TYPE_SECRET_SOCIETY_RITUAL_MEMBER: 'CommonSituationId' = 222542 + FESTIVAL_PLAYER_BLOSSOM_FESTIVAL: 'CommonSituationId' = 140632 + FESTIVAL_PLAYER_FLEA_MARKET: 'CommonSituationId' = 140633 + FESTIVAL_PLAYER_FOOD_FESTIVAL: 'CommonSituationId' = 140634 + FESTIVAL_PLAYER_LAMP_FESTIVAL: 'CommonSituationId' = 140635 + FESTIVAL_PLAYER_LOGIC_FAIR: 'CommonSituationId' = 140636 + FESTIVAL_SERVER: 'CommonSituationId' = 136515 + FESTIVAL_STALL_VENDOR_ARTS_QUAD: 'CommonSituationId' = 228432 + FESTIVAL_STALL_VENDOR_BLOSSOM_FESTIVAL: 'CommonSituationId' = 140568 + FESTIVAL_STALL_VENDOR_FLEA_MARKET: 'CommonSituationId' = 140567 + FESTIVAL_STALL_VENDOR_FOOD_FESTIVAL: 'CommonSituationId' = 140570 + FESTIVAL_STALL_VENDOR_LAMP_FESTIVAL: 'CommonSituationId' = 140569 + FESTIVAL_STALL_VENDOR_LOGIC_FAIR: 'CommonSituationId' = 140571 + FESTIVAL_TRAVEL_WITH_NPC: 'CommonSituationId' = 149285 + FIRE: 'CommonSituationId' = 73821 + FOREST_RANGER_VACATION_ARRIVAL: 'CommonSituationId' = 109025 + GARDENER_SERVICE_SITUATION: 'CommonSituationId' = 130533 + GARDEN_CHALET_FAMILY: 'CommonSituationId' = 126380 + GARDEN_CHALET_GHOST_COUPLE: 'CommonSituationId' = 125461 + GARDEN_CHALET_TOURIST_COUPLE: 'CommonSituationId' = 126350 + GHOST: 'CommonSituationId' = 101846 + GHOST_BARFLY: 'CommonSituationId' = 122619 + GHOST_NIGHT: 'CommonSituationId' = 122623 + GHOST_PETS: 'CommonSituationId' = 165585 + GHOST_STORY_SUMMONED_GHOST: 'CommonSituationId' = 108708 + GO_DANCING_BACKGROUND_PARTY_GOER_SITUATION: 'CommonSituationId' = 123650 + GO_DANCING_BACKGROUND_SITUATION: 'CommonSituationId' = 123649 + GO_DANCING_COMPLEX_CLUB_PARTY_GOER: 'CommonSituationId' = 122998 + GO_DANCING_COMPLEX_CLUB_PARTY_GOER_BLUFFS_ONLY: 'CommonSituationId' = 127427 + GO_DANCING_COMPLEX_CLUB_PARTY_GOER_CHALET_ONLY: 'CommonSituationId' = 127428 + GO_DANCING_COMPLEX_CLUB_PARTY_GOER_NIGHTCLUB_ONLY: 'CommonSituationId' = 127425 + GO_DANCING_COMPLEX_CLUB_PARTY_GOER_RUINS_ONLY: 'CommonSituationId' = 127426 + GREETED_NPC_VISITING_NPC: 'CommonSituationId' = 34412 + GREETED_NPC_VISITING_PLAYER_PET: 'CommonSituationId' = 175544 + GREETED_NPC_VISITING_PLAYER_ROOMMATE: 'CommonSituationId' = 196880 + GREETED_NPC_VISITING_PLAYER_SITUATION: 'CommonSituationId' = 39299 + GREETED_PLAYER_VISITING_NPC: 'CommonSituationId' = 34413 + GRILL_THREE_SIMS: 'CommonSituationId' = 126542 + GRILL_TWO_SIMS: 'CommonSituationId' = 126541 + GRIM_REAPER: 'CommonSituationId' = 16195 + GROUP_SING_HAPPY_BIRTHDAY: 'CommonSituationId' = 188118 + GROUP_SING_JIGGLE_BELLS: 'CommonSituationId' = 188119 + GROUP_SING_JOLLY_FELLOW: 'CommonSituationId' = 188120 + GROUP_SING_MAYZIE: 'CommonSituationId' = 188121 + GROUP_SING_SITUATION: 'CommonSituationId' = 187204 + GUYS_NIGHT: 'CommonSituationId' = 122637 + GYM_PLAYER: 'CommonSituationId' = 122389 + GYM_TRAINER_VENUE: 'CommonSituationId' = 120466 + GYM_VISITOR: 'CommonSituationId' = 120521 + HAIR_MAKE_UP_CHAIR_STYLIST: 'CommonSituationId' = 189456 + HARVEST_FEST_GNOME: 'CommonSituationId' = 181583 + HARVEST_FEST_GNOME_BERSERK: 'CommonSituationId' = 187566 + HIRED_NPC_BARISTA: 'CommonSituationId' = 123735 + HIRED_NPC_BARTENDER: 'CommonSituationId' = 123711 + HIRED_NPC_CATERER: 'CommonSituationId' = 123703 + HIRED_NPC_CATERER_VEGETARIAN: 'CommonSituationId' = 150481 + HIRED_NPC_DJ: 'CommonSituationId' = 123728 + HIRED_NPC_DJ_LEVEL10: 'CommonSituationId' = 124280 + HIRED_NPC_ENTERTAINER_GUITAR: 'CommonSituationId' = 123632 + HIRED_NPC_ENTERTAINER_MIC_COMEDY: 'CommonSituationId' = 123693 + HIRED_NPC_ENTERTAINER_ORGAN: 'CommonSituationId' = 155970 + HIRED_NPC_ENTERTAINER_PIANO: 'CommonSituationId' = 123599 + HIRED_NPC_ENTERTAINER_VIOLIN: 'CommonSituationId' = 123683 + HIRED_NPC_FASHION_SUBJECT: 'CommonSituationId' = 215288 + HIRED_NPC_MAGIC_VENDOR_STALL_BROOM: 'CommonSituationId' = 217636 + HIRED_NPC_MAGIC_VENDOR_STALL_POTION: 'CommonSituationId' = 217847 + HIRED_NPC_MAGIC_VENDOR_STALL_WAND: 'CommonSituationId' = 217848 + HIRED_NPC_STALL_VENDOR: 'CommonSituationId' = 132880 + HIRED_NPC_VENDOR_STALL: 'CommonSituationId' = 143512 + HIRED_NPC_VENDOR_STALL_CAFETERIA_STATION: 'CommonSituationId' = 217903 + HOLIDAY_SITUATION: 'CommonSituationId' = 182317 + HOLIDAY_TRADITIONS_WALK_BYS_FESTIVE_OUTFITS: 'CommonSituationId' = 182161 + HOLIDAY_TRADITIONS_WALK_BYS_FORMAL_OUTFITS: 'CommonSituationId' = 182177 + HOLIDAY_TRADITIONS_WALK_BYS_GHOSTS: 'CommonSituationId' = 182187 + HOLIDAY_TRADITIONS_WALK_BYS_NUDE_SIMS: 'CommonSituationId' = 190698 + HOLIDAY_TRADITIONS_WALK_BYS_TRICK_OR_TREAT: 'CommonSituationId' = 188033 + HOLIDAY_VISITOR_HOLIDAY_TRADITION_FATHER_WINTER: 'CommonSituationId' = 181459 + HOME_CHEF_SITUATION: 'CommonSituationId' = 134741 + HOSPITAL_PATIENT_ADMITTED: 'CommonSituationId' = 112448 + HOSPITAL_PATIENT_ADMITTED_HIGH_LEVEL: 'CommonSituationId' = 114457 + HOSPITAL_PATIENT_DIAGNOSED_BLOATY_HEAD: 'CommonSituationId' = 115279 + HOSPITAL_PATIENT_DIAGNOSED_GAS_AND_GIGGLES: 'CommonSituationId' = 115278 + HOSPITAL_PATIENT_DIAGNOSED_LLAMA_FLU: 'CommonSituationId' = 115277 + HOSPITAL_PATIENT_DIAGNOSED_STARRY_EYES: 'CommonSituationId' = 115276 + HOSPITAL_PATIENT_HIGH_LEVEL: 'CommonSituationId' = 112414 + HOSPITAL_PATIENT_LOW_LEVEL: 'CommonSituationId' = 108587 + HOSPITAL_PATIENT_LOW_LEVEL_CHILD: 'CommonSituationId' = 115642 + HOSPITAL_PATIENT_LOW_LEVEL_ELDER: 'CommonSituationId' = 115974 + HOST_1: 'CommonSituationId' = 132187 + HOUSE_PARTY: 'CommonSituationId' = 33294 + INFECTED_SITUATION: 'CommonSituationId' = 202595 + INVITE_OVER: 'CommonSituationId' = 40353 + INVITE_TO: 'CommonSituationId' = 40714 + INVITE_TO_MAGIC_PORTAL: 'CommonSituationId' = 222413 + ISLANDER_CULTURE_FIRE_BRIGADE: 'CommonSituationId' = 208895 + ISLANDER_CULTURE_NEED_SOMETHING_FIXED: 'CommonSituationId' = 208713 + ISLAND_ANCESTORS: 'CommonSituationId' = 210248 + ISLAND_EVENTS_ONE_STATE_BEACH_BONFIRE_TOWN_LOCAL: 'CommonSituationId' = 205603 + ISLAND_EVENTS_ONE_STATE_FAMILY_FUN_DAY_LOCAL_KID: 'CommonSituationId' = 205599 + ISLAND_EVENTS_ONE_STATE_FAMILY_FUN_DAY_LOCAL_PARENT: 'CommonSituationId' = 205600 + ISLAND_EVENTS_ONE_STATE_FAMILY_FUN_DAY_VENDOR: 'CommonSituationId' = 205598 + ISLAND_EVENTS_ONE_STATE_FLOWERS_AND_MUSIC_MUSICIAN: 'CommonSituationId' = 205602 + ISLAND_EVENTS_ONE_STATE_FLOWERS_AND_MUSIC_TOWN_LOCAL: 'CommonSituationId' = 205601 + ISLAND_EVENTS_ONE_STATE_TOWN_BBQ_ISLAND_COOK: 'CommonSituationId' = 205597 + ISLAND_EVENTS_ONE_STATE_TOWN_BBQ_TOWN_LOCAL: 'CommonSituationId' = 205596 + ISLAND_EVENTS_ONE_STATE_TURTLE_HATCHING_CONSERVATIONIST: 'CommonSituationId' = 205482 + ISLAND_EVENTS_ONE_STATE_TURTLE_HATCHING_FANATIC: 'CommonSituationId' = 205480 + ISLAND_EVENTS_ONE_STATE_TURTLE_HATCHING_LOCALS: 'CommonSituationId' = 205481 + ISLAND_EVENTS_POTLUCK_TOWN_POTLUCK_TOWN_LOCAL: 'CommonSituationId' = 204558 + ISLAND_EVENTS_POTLUCK_TOWN_POTLUCK_TOWN_LOCAL_BONFIRE: 'CommonSituationId' = 214655 + ISLAND_EVENTS_TWO_STATE_FISHING_COMPETITION_CATCH_FISH_WATCH_CEREMONY: 'CommonSituationId' = 208694 + ISLAND_EVENTS_TWO_STATE_FISHING_COMPETITION_VENDOR_ANNOUNCER: 'CommonSituationId' = 208695 + ISLAND_EVENTS_TWO_STATE_ISLAND_CELEBRATION_PAINTER_FIRE_DANCER: 'CommonSituationId' = 204998 + ISLAND_EVENTS_TWO_STATE_ISLAND_CELEBRATION_SAND_ARTIST_MUSICIAN: 'CommonSituationId' = 205641 + ISLAND_EVENTS_TWO_STATE_ISLAND_CELEBRATION_STALL_VENDOR: 'CommonSituationId' = 205639 + ISLAND_EVENTS_TWO_STATE_ISLAND_CELEBRATION_TABLE_VENDOR: 'CommonSituationId' = 205640 + ISLAND_EVENTS_TWO_STATE_ISLAND_CELEBRATION_TOWN_LOCAL: 'CommonSituationId' = 205642 + ISLAND_PRE_WELCOME_WAGON: 'CommonSituationId' = 211430 + ISLAND_SPIRITS_ACTIVE: 'CommonSituationId' = 208519 + ISLAND_SPIRITS_INACTIVE: 'CommonSituationId' = 209377 + ISLAND_WELCOME_WAGON: 'CommonSituationId' = 211431 + JUNGLE_BARFLY: 'CommonSituationId' = 180836 + KARAOKE_BARFLY: 'CommonSituationId' = 138040 + KARAOKE_CAREER_BARFLY: 'CommonSituationId' = 138083 + KARAOKE_CONTEST: 'CommonSituationId' = 138148 + KARAOKE_CONTESTANT: 'CommonSituationId' = 153658 + KARAOKE_DUET: 'CommonSituationId' = 140814 + KARAOKE_DUET_GROUP: 'CommonSituationId' = 150234 + KARAOKE_DUET_SIM: 'CommonSituationId' = 150244 + KARAOKE_HAPPY_HOUR: 'CommonSituationId' = 138114 + KARAOKE_SINGLE: 'CommonSituationId' = 138196 + KAVA_PARTY_SITUATION: 'CommonSituationId' = 206333 + KEG_PARTY: 'CommonSituationId' = 221796 + KNIGHT_BARFLY: 'CommonSituationId' = 129888 + KNIGHT_NIGHT: 'CommonSituationId' = 130282 + LADIES_NIGHT: 'CommonSituationId' = 16196 + LADIES_NIGHTS: 'CommonSituationId' = 122636 + LAMPOON_PARTY_NPC_INVITE: 'CommonSituationId' = 202448 + LAMPOON_PARTY_SITUATION: 'CommonSituationId' = 197831 + LANDLORD: 'CommonSituationId' = 135299 + LEAVE: 'CommonSituationId' = 24196 + LEAVE_NOW_MUST_RUN: 'CommonSituationId' = 24322 + LIBRARY_MUSEUM_VENUE_MENTOR: 'CommonSituationId' = 134234 + LIBRARY_MUSEUM_VENUE_STUDENT: 'CommonSituationId' = 134242 + LIBRARY_VENUE_CHESS_PLAYER: 'CommonSituationId' = 134244 + LIBRARY_VENUE_LIBRARIAN: 'CommonSituationId' = 134232 + LIBRARY_VENUE_READER: 'CommonSituationId' = 134240 + LIBRARY_VENUE_STRANGER_VILLE_CONSPIRACIST: 'CommonSituationId' = 204076 + LIBRARY_VENUE_STRANGER_VILLE_SCIENTIST: 'CommonSituationId' = 204075 + LKG_PARTY: 'CommonSituationId' = 16187 + LOOPING_INTERACTION_SET_THE_TABLE: 'CommonSituationId' = 161838 + LOOPING_INTERACTION_SET_THE_TABLE_AUTONOMOUS: 'CommonSituationId' = 163857 + LOUD_NEIGHBOR_APARTMENT_FIGHT: 'CommonSituationId' = 145041 + LOUD_NEIGHBOR_APARTMENT_MUSIC: 'CommonSituationId' = 138071 + LOUD_NEIGHBOR_APARTMENT_NPC_ANSWER_DOOR_LOUD_FIGHT: 'CommonSituationId' = 145043 + LOUD_NEIGHBOR_APARTMENT_NPC_ANSWER_DOOR_LOUD_MUSIC: 'CommonSituationId' = 138072 + LOUD_NEIGHBOR_APARTMENT_NPC_ANSWER_DOOR_LOUD_WOOHOO: 'CommonSituationId' = 138079 + LOUD_NEIGHBOR_APARTMENT_WOOHOO: 'CommonSituationId' = 138070 + LOUNGE_EVENT_AWARD_CELEBRITY: 'CommonSituationId' = 197816 + LOUNGE_EVENT_AWARD_HOST: 'CommonSituationId' = 197605 + LOUNGE_EVENT_AWARD_PLAYER: 'CommonSituationId' = 197824 + LOUNGE_EVENT_MEET_A_CELEBRITY: 'CommonSituationId' = 197592 + LOUNGE_VENUE_BARFLY: 'CommonSituationId' = 134267 + LOUNGE_VENUE_BARFLY_ELDER: 'CommonSituationId' = 134268 + LOUNGE_VENUE_COMEDIAN_ENTERTAINER: 'CommonSituationId' = 134259 + LOUNGE_VENUE_INSTRUMENT_ENTERTAINER: 'CommonSituationId' = 134341 + MAGIC_DUEL_CHALLENGE: 'CommonSituationId' = 218413 + MAGIC_DUEL_CHALLENGE_ARTIFACT: 'CommonSituationId' = 220266 + MAGIC_DUEL_CHALLENGE_HEATED: 'CommonSituationId' = 220223 + MAGIC_DUEL_CHALLENGE_ITEMS: 'CommonSituationId' = 220268 + MAGIC_DUEL_CHALLENGE_KNOWLEDGE: 'CommonSituationId' = 220267 + MAGIC_HQ_PLAYER: 'CommonSituationId' = 223442 + MAID_SITUATION: 'CommonSituationId' = 16188 + MAILMAN_SITUATION: 'CommonSituationId' = 16189 + MALE_BARFLY: 'CommonSituationId' = 122618 + MASSAGE_THERAPIST_SERVICE_CALL: 'CommonSituationId' = 119133 + MASSAGE_THERAPIST_VENUE: 'CommonSituationId' = 119161 + MEDITATION_TELEPORT_TO: 'CommonSituationId' = 119817 + MEET_WITH_STYLE_INFLUENCER: 'CommonSituationId' = 216216 + MOTHER_PLANT_BATTLE_SITUATION: 'CommonSituationId' = 203311 + MTX_TEST_EVENT: 'CommonSituationId' = 25897 + MUSEUM_VENUE_ARTIST: 'CommonSituationId' = 134377 + MUSEUM_VENUE_PATRON: 'CommonSituationId' = 134376 + MUSEUM_VENUE_PATRON_JUNGLE_NATIVE: 'CommonSituationId' = 185010 + MUSEUM_VENUE_PATRON_JUNGLE_TOURIST: 'CommonSituationId' = 185019 + MYSHUNO_MEADOWS_ADULT_VISITOR: 'CommonSituationId' = 138475 + MYSHUNO_MEADOWS_CHILD_VISITOR: 'CommonSituationId' = 154529 + MYSHUNO_MEADOWS_FISHER: 'CommonSituationId' = 152409 + MYSHUNO_MEADOWS_FORMAL_VISITOR: 'CommonSituationId' = 154539 + MYSHUNO_MEADOWS_INVITE: 'CommonSituationId' = 138476 + MYSHUNO_MEADOWS_JOGGER: 'CommonSituationId' = 155568 + MYSHUNO_MEADOWS_LIVING_STATUE_BUSKER: 'CommonSituationId' = 151393 + MYSHUNO_MEADOWS_WEIRDO: 'CommonSituationId' = 151391 + NANNY_SITUATION: 'CommonSituationId' = 141841 + NATURAL_POOL_SWIMMER_SITUATION: 'CommonSituationId' = 175204 + NPC_HOSTED_BIRTHDAY_PARTY: 'CommonSituationId' = 117360 + NPC_INVITES_ANGRY_TEXT: 'CommonSituationId' = 127298 + NPC_INVITES_BAR_NIGHT: 'CommonSituationId' = 127380 + NPC_INVITES_BAR_NIGHT_ALIENS_NIGHT: 'CommonSituationId' = 128117 + NPC_INVITES_BAR_NIGHT_BEAR_NIGHT: 'CommonSituationId' = 128118 + NPC_INVITES_BAR_NIGHT_GHOSTS_NIGHT: 'CommonSituationId' = 128119 + NPC_INVITES_BAR_NIGHT_GUYS_NIGHT: 'CommonSituationId' = 128120 + NPC_INVITES_BAR_NIGHT_KNIGHT_NIGHT: 'CommonSituationId' = 130365 + NPC_INVITES_BAR_NIGHT_LADIES_NIGHT: 'CommonSituationId' = 128121 + NPC_INVITES_BAR_NIGHT_SINGLES_NIGHT: 'CommonSituationId' = 128122 + NPC_INVITES_CLUB_PARTY: 'CommonSituationId' = 126453 + NPC_INVITES_ENERGIZED_TEXT_GYM: 'CommonSituationId' = 127222 + NPC_INVITES_FAMILY_VENUE: 'CommonSituationId' = 165289 + NPC_INVITES_FLIRTY_TEXT: 'CommonSituationId' = 127278 + NPC_INVITES_HAPPY_TEXT: 'CommonSituationId' = 127242 + NPC_INVITES_INVITE_TO_NPC_HOME: 'CommonSituationId' = 128961 + NPC_INVITES_INVITE_TO_NPC_HOME_FAMILY: 'CommonSituationId' = 165264 + NPC_INVITES_LOUNGE_EVENT: 'CommonSituationId' = 215483 + NPC_INVITES_PLAYFUL_TEXT: 'CommonSituationId' = 127267 + NPC_INVITE_DATE: 'CommonSituationId' = 117059 + NPC_INVITE_DATE_BLIND: 'CommonSituationId' = 201483 + NPC_INVITE_PLAY_DATE: 'CommonSituationId' = 117170 + NPC_INVITE_PLAY_HOOKY: 'CommonSituationId' = 125950 + NPC_INVITE_PROMOTION_PARTY: 'CommonSituationId' = 125930 + NPC_INVITE_RECOMMEND_RESTAURANT: 'CommonSituationId' = 140076 + NPC_INVITE_RESTAURANT_DATE: 'CommonSituationId' = 136713 + NPC_INVITE_RESTAURANT_FRIENDLY: 'CommonSituationId' = 136766 + NPC_INVITE_RESTAURANT_STANDARD: 'CommonSituationId' = 136626 + NPC_SPA_GUEST_ANNOYING: 'CommonSituationId' = 119060 + NPC_SPA_GUEST_BULL: 'CommonSituationId' = 119062 + NPC_SPA_GUEST_CELEBRITY_HIGH_FAME: 'CommonSituationId' = 195410 + NPC_SPA_GUEST_CELEBRITY_LOW_FAME: 'CommonSituationId' = 195428 + NPC_SPA_GUEST_COUPLE_MASSAGE: 'CommonSituationId' = 119306 + NPC_SPA_GUEST_COUPLE_STEAM_ROOM: 'CommonSituationId' = 119503 + NPC_SPA_GUEST_COUPLE_YOGA: 'CommonSituationId' = 119307 + NPC_SPA_GUEST_NORMAL: 'CommonSituationId' = 119059 + NPC_SPA_GUEST_PRANKSTER: 'CommonSituationId' = 119061 + NPC_SPA_GUEST_SNOB: 'CommonSituationId' = 119063 + NPC_SPA_GUEST_VISITOR: 'CommonSituationId' = 129884 + NPC_VISIT_ANY_VENUE: 'CommonSituationId' = 101273 + OPEN_MIC_CONTESTANT_NPC: 'CommonSituationId' = 197205 + OPEN_MIC_CONTESTANT_PLAYER: 'CommonSituationId' = 197206 + OPEN_MIC_CONTESTANT_STUDENT_COMMONS_ARTS_POETRY_NPC: 'CommonSituationId' = 221612 + OPEN_MIC_CONTESTANT_STUDENT_COMMONS_ARTS_POETRY_PLAYER: 'CommonSituationId' = 221613 + OPEN_MIC_PLAYER_CONTROLLER_SITUATION: 'CommonSituationId' = 195976 + OPEN_MIC_PLAYER_CONTROLLER_STUDENT_COMMONS_ARTS_POETRY: 'CommonSituationId' = 221561 + OPEN_STREETS_ALIEN: 'CommonSituationId' = 113847 + OPEN_STREETS_AUTONOMY_CHALET_GARDENS_LONELY: 'CommonSituationId' = 126236 + OPEN_STREETS_AUTONOMY_CHALET_GARDENS_SINGLE_TOURIST: 'CommonSituationId' = 126237 + OPEN_STREETS_AUTONOMY_CHALET_GARDENS_VISITOR: 'CommonSituationId' = 129882 + OPEN_STREETS_AUTONOMY_CITY_LIFE_BASKET_BALLER: 'CommonSituationId' = 184971 + OPEN_STREETS_AUTONOMY_CITY_LIFE_BASKET_BALLER_A: 'CommonSituationId' = 149955 + OPEN_STREETS_AUTONOMY_CITY_LIFE_BASKET_BALLER_B: 'CommonSituationId' = 149968 + OPEN_STREETS_AUTONOMY_CITY_LIFE_MURAL_PAINTER: 'CommonSituationId' = 149970 + OPEN_STREETS_AUTONOMY_EVENT_NPC_CHALLENGE: 'CommonSituationId' = 133756 + OPEN_STREETS_AUTONOMY_FAME_WORLD_CELEBRITY: 'CommonSituationId' = 197063 + OPEN_STREETS_AUTONOMY_FAME_WORLD_TOURIST: 'CommonSituationId' = 196926 + OPEN_STREETS_AUTONOMY_FAME_WORLD_TOURIST_LOT_TRAIT: 'CommonSituationId' = 201123 + OPEN_STREETS_AUTONOMY_ISLAND_FISHERMAN: 'CommonSituationId' = 216171 + OPEN_STREETS_AUTONOMY_ISLAND_WORLD_BEACH_COMBER: 'CommonSituationId' = 210660 + OPEN_STREETS_AUTONOMY_ISLAND_WORLD_MERFOLK: 'CommonSituationId' = 210415 + OPEN_STREETS_AUTONOMY_ISLAND_WORLD_TOWN_VISITOR: 'CommonSituationId' = 210414 + OPEN_STREETS_AUTONOMY_JUNGLE_MARKETPLACE_BROWSER: 'CommonSituationId' = 178171 + OPEN_STREETS_AUTONOMY_JUNGLE_MARKETPLACE_FISH: 'CommonSituationId' = 178117 + OPEN_STREETS_AUTONOMY_JUNGLE_MARKETPLACE_TOURIST_TAKE_PHOTO: 'CommonSituationId' = 178229 + OPEN_STREETS_AUTONOMY_PET_WORLD_STRAY_CAT_FISHER: 'CommonSituationId' = 163983 + OPEN_STREETS_AUTONOMY_PET_WORLD_STRAY_CAT_GHOST: 'CommonSituationId' = 163985 + OPEN_STREETS_AUTONOMY_PET_WORLD_STRAY_CAT_IN_HEAT: 'CommonSituationId' = 163982 + OPEN_STREETS_AUTONOMY_PET_WORLD_STRAY_CAT_JUNGLE: 'CommonSituationId' = 181421 + OPEN_STREETS_AUTONOMY_PET_WORLD_STRAY_CAT_WANDERER: 'CommonSituationId' = 163981 + OPEN_STREETS_AUTONOMY_PET_WORLD_STRAY_DOG_GHOST: 'CommonSituationId' = 163984 + OPEN_STREETS_AUTONOMY_PET_WORLD_STRAY_DOG_IN_HEAT: 'CommonSituationId' = 163980 + OPEN_STREETS_AUTONOMY_PET_WORLD_STRAY_DOG_JUNGLE: 'CommonSituationId' = 181422 + OPEN_STREETS_AUTONOMY_PET_WORLD_STRAY_DOG_WANDERER: 'CommonSituationId' = 163979 + OPEN_STREETS_AUTONOMY_UNIVERSITY_RIVALRY_PRANK_ARTS: 'CommonSituationId' = 226693 + OPEN_STREETS_AUTONOMY_UNIVERSITY_RIVALRY_PRANK_SCIENCE: 'CommonSituationId' = 226710 + OPEN_STREETS_AUTONOMY_UNIVERSITY_WORLD_ARTS_GHOST: 'CommonSituationId' = 222904 + OPEN_STREETS_AUTONOMY_UNIVERSITY_WORLD_ARTS_MASCOT: 'CommonSituationId' = 222870 + OPEN_STREETS_AUTONOMY_UNIVERSITY_WORLD_ARTS_STUDENT: 'CommonSituationId' = 222901 + OPEN_STREETS_AUTONOMY_UNIVERSITY_WORLD_CTYAE_SWIMMER: 'CommonSituationId' = 222841 + OPEN_STREETS_AUTONOMY_UNIVERSITY_WORLD_SCIENCE_MASCOT: 'CommonSituationId' = 222871 + OPEN_STREETS_AUTONOMY_UNIVERSITY_WORLD_SCIENCE_ROBOT: 'CommonSituationId' = 222942 + OPEN_STREETS_AUTONOMY_UNIVERSITY_WORLD_SCIENCE_STUDENT: 'CommonSituationId' = 222902 + OPEN_STREETS_AUTONOMY_UNIVERSITY_WORLD_TOURING_TEEN: 'CommonSituationId' = 222766 + OPEN_STREETS_AUTONOMY_UNIVERSITY_WORLD_YA_SWIMMER: 'CommonSituationId' = 222763 + OPEN_STREETS_BARTENDER: 'CommonSituationId' = 142879 + OPEN_STREETS_CAMPING_FOREST_BEAR: 'CommonSituationId' = 104740 + OPEN_STREETS_CAMPING_FOREST_FISH: 'CommonSituationId' = 106116 + OPEN_STREETS_CAMPING_FOREST_FOREST_GHOST: 'CommonSituationId' = 108333 + OPEN_STREETS_CAMPING_FOREST_FOREST_RANGER: 'CommonSituationId' = 108824 + OPEN_STREETS_CAMPING_FOREST_RANGER_STATION: 'CommonSituationId' = 106119 + OPEN_STREETS_CAMPING_FOREST_RESTROOM: 'CommonSituationId' = 106117 + OPEN_STREETS_CAMPING_FOREST_RESTROOM_SHOWER: 'CommonSituationId' = 110032 + OPEN_STREETS_CHESS: 'CommonSituationId' = 38486 + OPEN_STREETS_ISLAND_LOUNGER: 'CommonSituationId' = 216155 + OPEN_STREETS_LOUNGER: 'CommonSituationId' = 76164 + OPEN_STREETS_NOBODY: 'CommonSituationId' = 77328 + OPEN_STREETS_PLAYGROUND: 'CommonSituationId' = 38307 + OPEN_STREETS_STALL_VENDOR: 'CommonSituationId' = 136915 + OPEN_STREETS_STALL_VENDOR_COFFEE_CART: 'CommonSituationId' = 225986 + OPEN_STREETS_STALL_VENDOR_CURIO_SHOP: 'CommonSituationId' = 202394 + OPEN_STREETS_STALL_VENDOR_ISLAND_WORLD: 'CommonSituationId' = 215326 + OPEN_STREETS_STALL_VENDOR_JUNGLE: 'CommonSituationId' = 182889 + OPEN_STREETS_STALL_VENDOR_MAGIC: 'CommonSituationId' = 216971 + OPEN_STREETS_STALL_VENDOR_MAGIC_POTION: 'CommonSituationId' = 217862 + OPEN_STREETS_STALL_VENDOR_MAGIC_WAND: 'CommonSituationId' = 217863 + OPEN_STREETS_STALL_VENDOR_SEASONAL: 'CommonSituationId' = 191307 + OPEN_STREET_CRAFT_SALES_TABLE_VENDOR: 'CommonSituationId' = 153603 + OPEN_STREET_CRAFT_SALES_TABLE_VENDORS_PAINTINGS: 'CommonSituationId' = 153604 + OPEN_STREET_CRAFT_SALES_TABLE_VENDOR_JUNGLE: 'CommonSituationId' = 177663 + OPEN_STREET_STRANGER_VILLE_CONSPIRACIST_01: 'CommonSituationId' = 203329 + OPEN_STREET_STRANGER_VILLE_CONSPIRACIST_02: 'CommonSituationId' = 206165 + OPEN_STREET_STRANGER_VILLE_CONSPIRACIST_03: 'CommonSituationId' = 206166 + OPEN_STREET_STRANGER_VILLE_INFECTED: 'CommonSituationId' = 203973 + OPEN_STREET_STRANGER_VILLE_OGA_01: 'CommonSituationId' = 203328 + OPEN_STREET_STRANGER_VILLE_OGA_02: 'CommonSituationId' = 206200 + OPEN_STREET_STRANGER_VILLE_OGA_03: 'CommonSituationId' = 206202 + ORGANIZATION_EVENT_STALL_VENDOR_CREATIVITY_CELEBRATION: 'CommonSituationId' = 228429 + ORGANIZATION_EVENT_STALL_VENDOR_ROBOTIC_EXHIBITION: 'CommonSituationId' = 228431 + ORGANIZATION_EVENT_STALL_VENDOR_SCHOOL_SPIRIT_DAY: 'CommonSituationId' = 228430 + PAPARAZZI_LOCK_OUT_SITUATION: 'CommonSituationId' = 200979 + PAPARAZZI_PAPARAZZI: 'CommonSituationId' = 196395 + PAPARAZZI_PAPARAZZI_LOCKED: 'CommonSituationId' = 201019 + PAPARAZZI_PAPARAZZI_UNLOCKED: 'CommonSituationId' = 200991 + PARK_CHESS_PLAYER: 'CommonSituationId' = 124376 + PARK_CHILD_PLAYING: 'CommonSituationId' = 124379 + PARK_DEFAULT: 'CommonSituationId' = 124378 + PARK_GARDENER: 'CommonSituationId' = 124381 + PARK_PLAYER: 'CommonSituationId' = 126602 + PARK_SLEEPER: 'CommonSituationId' = 124377 + PARK_TEEN: 'CommonSituationId' = 124384 + PARK_VISITOR: 'CommonSituationId' = 126603 + PATIENT_EMERGENCY_COLLAPSED_PATIENT: 'CommonSituationId' = 113496 + PATIENT_EMERGENCY_DELIVER_BABY: 'CommonSituationId' = 113524 + PATIENT_EMERGENCY_SAMPLE_ANALYSIS: 'CommonSituationId' = 114096 + PERFORMANCE_SPACE_BUSKER_OPEN_STREET: 'CommonSituationId' = 142719 + PERFORMANCE_SPACE_BUSKER_OPEN_STREET_VIOLIN: 'CommonSituationId' = 156102 + PERFORMANCE_SPACE_HIRED_NPC_BUSKER_GUITAR: 'CommonSituationId' = 142065 + PERFORMANCE_SPACE_HIRED_NPC_BUSKER_VIOLIN: 'CommonSituationId' = 142066 + PET_ADOPTION: 'CommonSituationId' = 166801 + PET_CARE_SELL_ADOPT: 'CommonSituationId' = 169806 + PET_CARE_SELL_ADOPT_SELL: 'CommonSituationId' = 170954 + PET_CARE_SITUATION: 'CommonSituationId' = 164137 + PET_OBSTACLE_COURSE: 'CommonSituationId' = 172224 + PICNIC_TABLE_THREE_SIMS: 'CommonSituationId' = 126174 + PICNIC_TABLE_TWO_SIMS: 'CommonSituationId' = 126161 + PIZZA_DELIVERY_NEW: 'CommonSituationId' = 74299 + PLAYER_ARTS_CENTER_VENUE: 'CommonSituationId' = 148725 + PLAYER_BARFLY: 'CommonSituationId' = 126352 + PLAYER_BARFLY_KARAOKE: 'CommonSituationId' = 138195 + PLAYER_BARFLY_LOUNGE: 'CommonSituationId' = 134424 + PLAYER_PARK_DEFAULT: 'CommonSituationId' = 134437 + PLAYER_PATRON_MUSEUM: 'CommonSituationId' = 134427 + PLAYER_PET_OWNER_CHECK_UP_PET: 'CommonSituationId' = 169163 + PLAYER_PET_OWNER_NEUTER: 'CommonSituationId' = 175468 + PLAYER_PET_OWNER_SICK_PET: 'CommonSituationId' = 169162 + PLAYER_PET_OWNER_SPAY: 'CommonSituationId' = 169864 + PLAYER_PET_OWNER_UNNEUTER: 'CommonSituationId' = 175467 + PLAYER_PET_OWNER_UN_SPAY: 'CommonSituationId' = 169909 + PLAYER_READER_LIBRARY: 'CommonSituationId' = 134431 + PLAYER_SECRET_LAB: 'CommonSituationId' = 204565 + POOL_VENUE_LOUNGER_LOUNGER: 'CommonSituationId' = 125575 + POOL_VENUE_SWIMMER_CHILD_SWIMMER: 'CommonSituationId' = 125572 + POOL_VENUE_SWIMMER_ELDER_SWIMMER: 'CommonSituationId' = 125573 + POOL_VENUE_SWIMMER_GENERIC_SWIMMER: 'CommonSituationId' = 125574 + POOL_VENUE_SWIMMER_PLAYER_SWIMMER: 'CommonSituationId' = 125697 + POOL_VENUE_SWIMMER_VISITOR_SWIMMER: 'CommonSituationId' = 129881 + POSSESSED_SITUATION: 'CommonSituationId' = 202077 + PRESENT_PILE_OPEN_PRESENTS: 'CommonSituationId' = 186232 + PRE_WELCOME_WAGON: 'CommonSituationId' = 156258 + PRE_WELCOME_WAGON_ISLANDER_CULTURE_DEATH_COMFORT: 'CommonSituationId' = 208663 + PRE_WELCOME_WAGON_ISLANDER_CULTURE_EXTRA_FOOD: 'CommonSituationId' = 208434 + PROTEST: 'CommonSituationId' = 136560 + REFLEXOLOGIST_VENUE: 'CommonSituationId' = 119511 + REGULAR_BARFLY: 'CommonSituationId' = 122622 + REPAIR_SITUATION: 'CommonSituationId' = 129479 + REPO_SITUATION: 'CommonSituationId' = 224390 + RESTAURANT_DINER_BACKGROUND_NPC_BAD_DATE: 'CommonSituationId' = 132752 + RESTAURANT_DINER_BACKGROUND_NPC_CELEBRITY_HIGH_FAME: 'CommonSituationId' = 196202 + RESTAURANT_DINER_BACKGROUND_NPC_CELEBRITY_LOW_FAME: 'CommonSituationId' = 196203 + RESTAURANT_DINER_BACKGROUND_NPC_CRITIC: 'CommonSituationId' = 141385 + RESTAURANT_DINER_BACKGROUND_NPC_EARLY_BIRDS: 'CommonSituationId' = 132776 + RESTAURANT_DINER_BACKGROUND_NPC_FAMILY_MEAL: 'CommonSituationId' = 132887 + RESTAURANT_DINER_BACKGROUND_NPC_HAPPY_DATE: 'CommonSituationId' = 132672 + RESTAURANT_DINER_BACKGROUND_NPC_STANDARD: 'CommonSituationId' = 132428 + RESTAURANT_DINER_EVENTS_NPC_BUSINESS_LUNCH: 'CommonSituationId' = 133881 + RESTAURANT_DINER_EVENTS_NPC_COSPLAY_NIGHT: 'CommonSituationId' = 133883 + RESTAURANT_DINER_EVENTS_NPC_DATE_NIGHT: 'CommonSituationId' = 133887 + RESTAURANT_DINER_EVENTS_NPC_EARLY_BIRD_SPECIAL: 'CommonSituationId' = 133882 + RESTAURANT_DINER_EVENTS_NPC_FAMILY_NIGHT: 'CommonSituationId' = 133880 + RESTAURANT_DINER_EVENTS_NPC_GHOST_NIGHT: 'CommonSituationId' = 133885 + RESTAURANT_DINER_EVENTS_NPC_NEARLY_NUDE_NIGHT: 'CommonSituationId' = 133884 + RESTAURANT_DINER_EVENTS_NPC_SPACE_RACE_DAY: 'CommonSituationId' = 133886 + RESTAURANT_DINER_SUB_NPC_BAD_DATE_ANGRY_SIM: 'CommonSituationId' = 132753 + RESTAURANT_DINER_SUB_NPC_BAD_DATE_FLIRTY_SIM: 'CommonSituationId' = 132755 + RESTAURANT_DINER_SUB_NPC_CELEBRITY: 'CommonSituationId' = 196206 + RESTAURANT_DINER_SUB_NPC_CRITIC: 'CommonSituationId' = 141388 + RESTAURANT_DINER_SUB_NPC_EARLY_BIRDS: 'CommonSituationId' = 132777 + RESTAURANT_DINER_SUB_NPC_FAMILY_MEAL_CHILD: 'CommonSituationId' = 132889 + RESTAURANT_DINER_SUB_NPC_FAMILY_MEAL_PARENT: 'CommonSituationId' = 132888 + RESTAURANT_DINER_SUB_NPC_HAPPY_DATE: 'CommonSituationId' = 132674 + RESTAURANT_DINER_SUB_NPC_STANDARD: 'CommonSituationId' = 132503 + RESTAURANT_PLAYER_GROUP: 'CommonSituationId' = 132711 + RESTAURANT_PLAYER_GROUP_IDLE: 'CommonSituationId' = 135258 + RESTAURANT_WAIT_STAFF: 'CommonSituationId' = 132213 + RETAIL_CUSTOMER_BARGAIN_SHOPPER: 'CommonSituationId' = 109145 + RETAIL_CUSTOMER_BARGAIN_SHOPPER_1: 'CommonSituationId' = 115725 + RETAIL_CUSTOMER_CELEBRITY_HANG_OUT_HIGH_FAME: 'CommonSituationId' = 195646 + RETAIL_CUSTOMER_CELEBRITY_HANG_OUT_LOW_FAME: 'CommonSituationId' = 195645 + RETAIL_CUSTOMER_LOITERER: 'CommonSituationId' = 109147 + RETAIL_CUSTOMER_MID_RANGE: 'CommonSituationId' = 109148 + RETAIL_CUSTOMER_MID_RANGE_1: 'CommonSituationId' = 115729 + RETAIL_CUSTOMER_MID_RANGE_2: 'CommonSituationId' = 115730 + RETAIL_CUSTOMER_SOCAILIZER: 'CommonSituationId' = 109146 + RETAIL_CUSTOMER_WEALTHY: 'CommonSituationId' = 109045 + RETAIL_CUSTOMER_WEALTHY_1: 'CommonSituationId' = 115732 + RETAIL_CUSTOMER_WEALTHY_2: 'CommonSituationId' = 115733 + RETAIL_CUSTOMER_WEALTHY_3: 'CommonSituationId' = 115734 + RETAIL_EMPLOYEE_HARD_WORKER: 'CommonSituationId' = 110399 + RETAIL_EMPLOYEE_NPC_STORE_HARD_WORKER: 'CommonSituationId' = 112196 + ROOMMATE_NPC_EVENTS_ARGUMENT: 'CommonSituationId' = 220805 + ROOMMATE_NPC_EVENTS_GET_HYPE: 'CommonSituationId' = 220807 + ROOMMATE_NPC_EVENTS_LOCKED_OUT: 'CommonSituationId' = 220806 + ROOMMATE_NPC_EVENTS_WHISPERS: 'CommonSituationId' = 220809 + ROOMMATE_NPC_EVENTS_WOOING: 'CommonSituationId' = 220808 + ROOMMATE_NPC_FRIEND: 'CommonSituationId' = 210758 + ROOMMATE_NPC_PARTY: 'CommonSituationId' = 212048 + ROOMMATE_NPC_POTENTIAL_ROOMMATE: 'CommonSituationId' = 220813 + ROOMMATE_NPC_SIGNIFICANT_OTHER: 'CommonSituationId' = 210759 + ROOMMATE_NPC_SITUATION: 'CommonSituationId' = 209550 + SCARECROW_PURPLE: 'CommonSituationId' = 191044 + SCARECROW_RED: 'CommonSituationId' = 191043 + SCARECROW_SITUATION: 'CommonSituationId' = 187072 + SCIENTIST_LAB_ALIEN_VISIT_ALIEN: 'CommonSituationId' = 113536 + SERVICE_SKELETON: 'CommonSituationId' = 177640 + SERVICE_SKELETON_RARE: 'CommonSituationId' = 177857 + SERVICE_SKELETON_UNCOMMON: 'CommonSituationId' = 177858 + SIMPLE_TELEPORT_TO_MAGIC_HQ_FAIL: 'CommonSituationId' = 215556 + SIM_BACKGROUND_CELEBRITY: 'CommonSituationId' = 196516 + SINGLES_BARFLY: 'CommonSituationId' = 122620 + SINGLES_NIGHT: 'CommonSituationId' = 122638 + SINGLE_JOB_CHALET_GARDENS_VISITOR: 'CommonSituationId' = 130273 + SINGLE_JOB_CLUB_DJ: 'CommonSituationId' = 122995 + SINGLE_JOB_CLUB_DJ_LEVEL10: 'CommonSituationId' = 124257 + SINGLE_JOB_COWORKER_RETAIL_EMPLOYEE: 'CommonSituationId' = 109236 + SINGLE_JOB_COWORKER_SCIENTIST: 'CommonSituationId' = 108670 + SINGLE_JOB_COWORKER_SCIENTIST_FRONT_DESK: 'CommonSituationId' = 115831 + SINGLE_JOB_MAGIC_SAGE_MISCHIEF: 'CommonSituationId' = 212842 + SINGLE_JOB_MAGIC_SAGE_PRACTICAL: 'CommonSituationId' = 212843 + SINGLE_JOB_MAGIC_SAGE_UNTAMED: 'CommonSituationId' = 212844 + SINGLE_JOB_MAGIC_VENUE_NPC_INTERMEDIATE: 'CommonSituationId' = 213051 + SINGLE_JOB_MAGIC_VENUE_NPC_INTERMEDIATE_USE_WAND: 'CommonSituationId' = 222850 + SINGLE_JOB_MAGIC_VENUE_NPC_NOVICE: 'CommonSituationId' = 212927 + SINGLE_JOB_MAGIC_VENUE_NPC_NOVICE_USE_WAND: 'CommonSituationId' = 222852 + SINGLE_JOB_MARKET_STALLS_CUSTOMER: 'CommonSituationId' = 132959 + SINGLE_JOB_MARKET_STALLS_CUSTOMER_MAGIC: 'CommonSituationId' = 217680 + SINGLE_JOB_MOTHER_PLANT_RUN_AWAY: 'CommonSituationId' = 207316 + SINGLE_SIM_LEAVE: 'CommonSituationId' = 101251 + SINGLE_SIM_VISITOR_TRICK_OR_TREAT: 'CommonSituationId' = 187507 + SITUATION_COMPLEX_APARTMENT_GROUP_HANGOUT: 'CommonSituationId' = 140390 + SITUATION_COMPLEX_APARTMENT_GROUP_HANGOUT_GAME_TIME: 'CommonSituationId' = 142201 + SITUATION_COMPLEX_APARTMENT_GROUP_HANGOUT_PRE_PARTY: 'CommonSituationId' = 142200 + SITUATION_COMPLEX_APARTMENT_NEIGHBOR_CHAT: 'CommonSituationId' = 155007 + SITUATION_COMPLEX_GHOST_HAUNTED_APARTMENT: 'CommonSituationId' = 139824 + SITUATION_COMPLEX_NEIGHBOR_COMPLAINT_NOISE: 'CommonSituationId' = 146032 + SITUATION_COMPLEX_NEIGHBOR_HANGOUT_BRAINSTORM_ART_LOVER: 'CommonSituationId' = 141316 + SITUATION_COMPLEX_NEIGHBOR_HANGOUT_BRAINSTORM_CREATIVE: 'CommonSituationId' = 141317 + SITUATION_COMPLEX_NEIGHBOR_HANGOUT_CHILDS_PLAY: 'CommonSituationId' = 141116 + SITUATION_COMPLEX_NEIGHBOR_HANGOUT_CHILD_COMPLAINT: 'CommonSituationId' = 141118 + SITUATION_COMPLEX_NEIGHBOR_HANGOUT_FLIRTY_SHOWER: 'CommonSituationId' = 141120 + SITUATION_COMPLEX_NEIGHBOR_HANGOUT_GEEK_OUT: 'CommonSituationId' = 141117 + SITUATION_COMPLEX_NEIGHBOR_HANGOUT_GENERIC: 'CommonSituationId' = 139264 + SITUATION_COMPLEX_NEIGHBOR_HANGOUT_MUNCHIES_FOODIE: 'CommonSituationId' = 141319 + SITUATION_COMPLEX_NEIGHBOR_HANGOUT_MUNCHIES_GLUTTON: 'CommonSituationId' = 141318 + SITUATION_COMPLEX_NEIGHBOR_HANGOUT_PENTHOUSE_BRAINSTORM_KEY_HOLDERS_ART_LOVER: 'CommonSituationId' = 146268 + SITUATION_COMPLEX_NEIGHBOR_HANGOUT_PENTHOUSE_BRAINSTORM_KEY_HOLDERS_CREATIVE: 'CommonSituationId' = 146269 + SITUATION_COMPLEX_NEIGHBOR_HANGOUT_PENTHOUSE_BRAINSTORM_NON_KEY_HOLDERS_ART_LOVER: 'CommonSituationId' = 146270 + SITUATION_COMPLEX_NEIGHBOR_HANGOUT_PENTHOUSE_BRAINSTORM_NON_KEY_HOLDERS_CREATIVE: 'CommonSituationId' = 146273 + SITUATION_COMPLEX_NEIGHBOR_HANGOUT_PENTHOUSE_CHILDS_PLAY_KEY_HOLDERS: 'CommonSituationId' = 146418 + SITUATION_COMPLEX_NEIGHBOR_HANGOUT_PENTHOUSE_CHILDS_PLAY_NON_KEY_HOLDERS: 'CommonSituationId' = 146419 + SITUATION_COMPLEX_NEIGHBOR_HANGOUT_PENTHOUSE_GEEK_OUT_KEY_HOLDERS: 'CommonSituationId' = 146414 + SITUATION_COMPLEX_NEIGHBOR_HANGOUT_PENTHOUSE_GEEK_OUT_NON_KEY_HOLDERS: 'CommonSituationId' = 146415 + SITUATION_COMPLEX_NEIGHBOR_HANGOUT_PENTHOUSE_GENERIC_KEY_HOLDERS: 'CommonSituationId' = 146331 + SITUATION_COMPLEX_NEIGHBOR_HANGOUT_PENTHOUSE_GENERIC_NON_KEY_HOLDERS: 'CommonSituationId' = 146332 + SITUATION_COMPLEX_NEIGHBOR_HANGOUT_PENTHOUSE_MUNCHIES_KEY_HOLDERS_FOODIE: 'CommonSituationId' = 146197 + SITUATION_COMPLEX_NEIGHBOR_HANGOUT_PENTHOUSE_MUNCHIES_KEY_HOLDERS_GLUTTON: 'CommonSituationId' = 146198 + SITUATION_COMPLEX_NEIGHBOR_HANGOUT_PENTHOUSE_MUNCHIES_NON_KEY_HOLDERS_FOODIE: 'CommonSituationId' = 146165 + SITUATION_COMPLEX_NEIGHBOR_HANGOUT_PENTHOUSE_MUNCHIES_NON_KEY_HOLDERS_GLUTTON: 'CommonSituationId' = 146166 + SITUATION_COMPLEX_NEIGHBOR_HANGOUT_PENTHOUSE_UNINVITED_KEY_HOLDERS_GOOFBALL: 'CommonSituationId' = 146378 + SITUATION_COMPLEX_NEIGHBOR_HANGOUT_PENTHOUSE_UNINVITED_KEY_HOLDERS_INSANE: 'CommonSituationId' = 146379 + SITUATION_COMPLEX_NEIGHBOR_HANGOUT_PENTHOUSE_UNINVITED_NON_KEY_HOLDERS_GOOFBALL: 'CommonSituationId' = 146380 + SITUATION_COMPLEX_NEIGHBOR_HANGOUT_PENTHOUSE_UNINVITED_NON_KEY_HOLDERS_INSANE: 'CommonSituationId' = 146381 + SITUATION_COMPLEX_NEIGHBOR_HANGOUT_PENTHOUSE_WORKOUT_KEY_HOLDERS: 'CommonSituationId' = 146411 + SITUATION_COMPLEX_NEIGHBOR_HANGOUT_PENTHOUSE_WORKOUT_NON_KEY_HOLDERS: 'CommonSituationId' = 146412 + SITUATION_COMPLEX_NEIGHBOR_HANGOUT_UNINVITED_GOOFBALL: 'CommonSituationId' = 141943 + SITUATION_COMPLEX_NEIGHBOR_HANGOUT_UNINVITED_INSANE: 'CommonSituationId' = 141927 + SITUATION_COMPLEX_NEIGHBOR_HANGOUT_WORKOUT: 'CommonSituationId' = 141119 + SITUATION_COMPLEX_NEIGHBOR_INTRIGUED_NOISE: 'CommonSituationId' = 146090 + SITUATION_COMPLEX_NEIGHBOR_INTRIGUED_SMELL: 'CommonSituationId' = 146089 + SITUATION_SIMPLE_APARTMENT_NEIGHBORS_INVITED_HANGOUT: 'CommonSituationId' = 146518 + SITUATION_SIMPLE_INFECTED_ATTACK: 'CommonSituationId' = 204726 + SITUATION_SIMPLE_NPC_INVITE_CRITIC_CAREER_RECOMMEND_LOCAL_HANGOUT_BAR: 'CommonSituationId' = 137936 + SITUATION_SIMPLE_NPC_INVITE_CRITIC_CAREER_RECOMMEND_LOCAL_HANGOUT_CLUB: 'CommonSituationId' = 137937 + SITUATION_SIMPLE_NPC_INVITE_CRITIC_CAREER_RECOMMEND_LOCAL_HANGOUT_MUSEUM: 'CommonSituationId' = 137938 + SITUATION_SIMPLE_RUDE_ALIEN_VISITORS: 'CommonSituationId' = 108167 + SITUATION_SIMPLE_TEMPLE_SKELETON: 'CommonSituationId' = 178516 + SITUATION_SIMPLE_TUTORIAL_HOUSEMATE: 'CommonSituationId' = 198047 + SITUATION_SIMPLE_VAMPIRE_CREATION_AT_NPC_HOME: 'CommonSituationId' = 152886 + SITUATION_SIMPLE_VAMPIRE_CREATION_AT_PLAYER_HOME: 'CommonSituationId' = 152907 + SOAK_PARTY: 'CommonSituationId' = 101358 + SPA_GUEST_PLAYER: 'CommonSituationId' = 118687 + SPECTRAL_STALKER_SITUATION: 'CommonSituationId' = 216307 + SPELL_SUMMON_GHOST_FAIL: 'CommonSituationId' = 215671 + SPOOKY_PARTY_SP04: 'CommonSituationId' = 125869 + SPOOKY_PARTY_S_P04: 'CommonSituationId' = 125869 + SQUAD_GATHERING: 'CommonSituationId' = 196099 + STAY_THE_NIGHT: 'CommonSituationId' = 40440 + STRANGER_VILLE_MILITARY_BARFLY: 'CommonSituationId' = 204035 + STRANGE_POST_WELCOME_WAGON: 'CommonSituationId' = 202792 + STRANGE_PRE_WELCOME_WAGON: 'CommonSituationId' = 202793 + STRANGE_WELCOME_WAGON: 'CommonSituationId' = 202794 + STUDENT_COMMONS_ARTS_EXAM_CRAM_STUDENT: 'CommonSituationId' = 230200 + STUDENT_COMMONS_ARTS_MIXER_MASCOT: 'CommonSituationId' = 229947 + STUDENT_COMMONS_ARTS_MIXER_STUDENT: 'CommonSituationId' = 222139 + STUDENT_COMMONS_ARTS_POETRY_TEA_SERVER: 'CommonSituationId' = 221830 + STUDENT_COMMONS_ARTS_PROFESSORS_GOOD: 'CommonSituationId' = 219186 + STUDENT_COMMONS_ARTS_PROFESSORS_GRUMPY: 'CommonSituationId' = 219185 + STUDENT_COMMONS_ARTS_PROFESSORS_HIP: 'CommonSituationId' = 219184 + STUDENT_COMMONS_ARTS_PROFESSORS_SMART: 'CommonSituationId' = 226919 + STUDENT_COMMONS_ARTS_STUDENTS_SLACKER: 'CommonSituationId' = 219181 + STUDENT_COMMONS_ARTS_STUDENTS_SOCIAL: 'CommonSituationId' = 219180 + STUDENT_COMMONS_ARTS_STUDENTS_STUDIOUS: 'CommonSituationId' = 219182 + STUDENT_COMMONS_ARTS_VISITORS: 'CommonSituationId' = 219187 + STUDENT_COMMONS_EXAM_CRAM_PLAYER: 'CommonSituationId' = 222195 + STUDENT_COMMONS_MIXER_PROFESSOR: 'CommonSituationId' = 222140 + STUDENT_COMMONS_SCIENCE_EXAM_CRAM_STUDENT: 'CommonSituationId' = 230202 + STUDENT_COMMONS_SCIENCE_E_SPORTS_CONTESTANT: 'CommonSituationId' = 221978 + STUDENT_COMMONS_SCIENCE_E_SPORTS_EXPERT_CONTESTANT: 'CommonSituationId' = 221979 + STUDENT_COMMONS_SCIENCE_MIXER_MASCOT: 'CommonSituationId' = 229948 + STUDENT_COMMONS_SCIENCE_MIXER_STUDENT: 'CommonSituationId' = 222158 + STUDENT_COMMONS_SCIENCE_PROFESSORS_GOOD: 'CommonSituationId' = 219191 + STUDENT_COMMONS_SCIENCE_PROFESSORS_GRUMPY: 'CommonSituationId' = 219192 + STUDENT_COMMONS_SCIENCE_PROFESSORS_HIP: 'CommonSituationId' = 219193 + STUDENT_COMMONS_SCIENCE_PROFESSORS_SMART: 'CommonSituationId' = 226918 + STUDENT_COMMONS_SCIENCE_STUDENTS_SLACKER: 'CommonSituationId' = 219195 + STUDENT_COMMONS_SCIENCE_STUDENTS_SOCIAL: 'CommonSituationId' = 219196 + STUDENT_COMMONS_SCIENCE_STUDENTS_STUDIOUS: 'CommonSituationId' = 219197 + STUDENT_COMMONS_SCIENCE_VISITORS: 'CommonSituationId' = 219189 + SUB_PRESENT_PILE_OPEN_PRESENTS: 'CommonSituationId' = 186233 + SUB_RESTAURANT_PLAYER_GROUP: 'CommonSituationId' = 132748 + SUB_TRAINING_DUMMY_PRACTICE_FIGHTING_WITH: 'CommonSituationId' = 203279 + SUMMON_LIGHTHOUSE_GHOST_DOG: 'CommonSituationId' = 175666 + TEMPORARY_CLONE: 'CommonSituationId' = 215157 + TEMPORARY_CLONE_CHARGED: 'CommonSituationId' = 216362 + TEMPORARY_CLONE_FAIL: 'CommonSituationId' = 216123 + TEST_FESTIVAL_ONE_STATE_EVENT: 'CommonSituationId' = 133655 + TEST_FESTIVAL_TWO_STATE_EVENT: 'CommonSituationId' = 133656 + TODDLER_PLAY_DATE: 'CommonSituationId' = 170158 + TOURIST_BARFLY_MYSHUNO_MEADOWS: 'CommonSituationId' = 151725 + TRAGIC_CLOWN: 'CommonSituationId' = 139602 + TRAINING_DUMMY_PRACTICE_FIGHTING_WITH: 'CommonSituationId' = 203278 + TRASH_DIVER: 'CommonSituationId' = 224194 + TRASH_DUMPER: 'CommonSituationId' = 234514 + TRASH_UPDATE_WASTE_MANAGER: 'CommonSituationId' = 235041 + UNGREETED_NPC_VISITING_NPC: 'CommonSituationId' = 34410 + UNGREETED_NPC_VISITING_NPC_UNIVERSITY: 'CommonSituationId' = 230377 + UNGREETED_PLAYER_VISITING_NPC: 'CommonSituationId' = 34411 + UNIVERSITY_ART_SOCIETY_BAR_NIGHT: 'CommonSituationId' = 226488 + UNIVERSITY_DEBATE_ORG_BAR_NIGHT: 'CommonSituationId' = 222303 + UNIVERSITY_GRADUATION_ARTS: 'CommonSituationId' = 226999 + UNIVERSITY_GRADUATION_SCIENCE: 'CommonSituationId' = 227006 + UNIVERSITY_HONOR_SOCIETY_BAR_NIGHT: 'CommonSituationId' = 226481 + UNIVERSITY_HOUSING_KICK_OUT_SITUATION: 'CommonSituationId' = 220603 + UNIVERSITY_HOUSING_MAID: 'CommonSituationId' = 222805 + UNIVERSITY_MIXER_PARTY_STUDENT_COMMONS_ART_MIXER_JUICE_KEG: 'CommonSituationId' = 222126 + UNIVERSITY_MIXER_PARTY_STUDENT_COMMONS_SCIENCE_MIXER_JUICE_KEG: 'CommonSituationId' = 220359 + UNIVERSITY_ORGANIZATION_DEBATE_SQUAD_DEBATE_SHOWDOWN: 'CommonSituationId' = 222828 + UNIVERSITY_ORGANIZATION_MEMBER_SINGLE_JOB_DEBATE_PRACTICE: 'CommonSituationId' = 228356 + UNIVERSITY_ORGANIZATION_MEMBER_SINGLE_JOB_ROBOT_BUILDING_SESSION: 'CommonSituationId' = 228362 + UNIVERSITY_ORGANIZATION_MEMBER_SINGLE_JOB_SECRET_SOCIETY_JOIN_VISIT: 'CommonSituationId' = 222710 + UNIVERSITY_PARTY_BAR_NIGHT: 'CommonSituationId' = 227731 + UNIVERSITY_PRANK_BAR_NIGHT: 'CommonSituationId' = 226489 + UNIVERSITY_ROBOTICS_BAR_NIGHT: 'CommonSituationId' = 226490 + UNIVERSITY_STUDENT_HANGOUT_ARTS_STUDENT: 'CommonSituationId' = 225553 + UNIVERSITY_STUDENT_HANGOUT_PROFESSOR: 'CommonSituationId' = 225550 + UNIVERSITY_STUDENT_HANGOUT_SCIENCE_PROFESSOR: 'CommonSituationId' = 230609 + UNIVERSITY_STUDENT_HANGOUT_SCIENCE_STUDENT: 'CommonSituationId' = 225558 + VAMPIRE_NIGHTTIME: 'CommonSituationId' = 152610 + VAMPIRE_NIGHTTIME_INITIAL: 'CommonSituationId' = 155503 + VENDOR_STALL_CAFETERIA_STATION: 'CommonSituationId' = 220129 + VENDOR_STALL_COFFEE_CART_HIRED_NPC: 'CommonSituationId' = 226530 + VENDOR_STALL_COFFEE_CART_VENUE: 'CommonSituationId' = 226020 + VENUE_BACKGROUND_HOSPITAL: 'CommonSituationId' = 115405 + VENUE_BAR: 'CommonSituationId' = 29374 + VENUE_CRAFT_SALES_TABLE_VENDOR: 'CommonSituationId' = 224122 + VENUE_CRAFT_SALES_TABLE_VENDOR_PAINTINGS: 'CommonSituationId' = 234949 + VENUE_GENERIC: 'CommonSituationId' = 99708 + VENUE_GYM: 'CommonSituationId' = 16199 + VENUE_HERMIT: 'CommonSituationId' = 105590 + VENUE_PARK: 'CommonSituationId' = 27467 + VENUE_PET_OWNER_CAT_ARTS_CENTER: 'CommonSituationId' = 172749 + VENUE_PET_OWNER_CAT_BAR: 'CommonSituationId' = 170211 + VENUE_PET_OWNER_CAT_CAFE: 'CommonSituationId' = 179098 + VENUE_PET_OWNER_CAT_CLUB: 'CommonSituationId' = 172492 + VENUE_PET_OWNER_CAT_GYM: 'CommonSituationId' = 172580 + VENUE_PET_OWNER_CAT_KARAOKE: 'CommonSituationId' = 172784 + VENUE_PET_OWNER_CAT_LIBRARY: 'CommonSituationId' = 172643 + VENUE_PET_OWNER_CAT_LOUNGE: 'CommonSituationId' = 172679 + VENUE_PET_OWNER_CAT_MUSEUM: 'CommonSituationId' = 172710 + VENUE_PET_OWNER_CAT_PARK: 'CommonSituationId' = 170212 + VENUE_PET_OWNER_CAT_POOL: 'CommonSituationId' = 172808 + VENUE_PET_OWNER_DOG_ARTS_CENTER: 'CommonSituationId' = 172752 + VENUE_PET_OWNER_DOG_BAR: 'CommonSituationId' = 169502 + VENUE_PET_OWNER_DOG_CAFE: 'CommonSituationId' = 179103 + VENUE_PET_OWNER_DOG_CLUB: 'CommonSituationId' = 172496 + VENUE_PET_OWNER_DOG_GYM: 'CommonSituationId' = 172583 + VENUE_PET_OWNER_DOG_KARAOKE: 'CommonSituationId' = 172785 + VENUE_PET_OWNER_DOG_LIBRARY: 'CommonSituationId' = 172652 + VENUE_PET_OWNER_DOG_LOUNGE: 'CommonSituationId' = 172680 + VENUE_PET_OWNER_DOG_MUSEUM: 'CommonSituationId' = 172711 + VENUE_PET_OWNER_DOG_PARK: 'CommonSituationId' = 169465 + VENUE_PET_OWNER_DOG_POOL: 'CommonSituationId' = 172809 + VET_CHECK_UP_CAT: 'CommonSituationId' = 167591 + VET_CHECK_UP_CAT_TEEN: 'CommonSituationId' = 174419 + VET_CHECK_UP_DOG: 'CommonSituationId' = 167592 + VET_CHECK_UP_DOG_TEEN: 'CommonSituationId' = 174425 + VET_CUSTOMER_VENDING_MACHINE_SITUATION: 'CommonSituationId' = 172624 + VET_DIAGNOSIS: 'CommonSituationId' = 165425 + VET_EMPLOYEE: 'CommonSituationId' = 165161 + VET_PLAYER: 'CommonSituationId' = 168070 + VET_SICK_CAT: 'CommonSituationId' = 167550 + VET_SICK_CAT_HIGH_LEVEL: 'CommonSituationId' = 175540 + VET_SICK_CAT_HIGH_LEVEL_TEEN: 'CommonSituationId' = 175542 + VET_SICK_CAT_MID_LEVEL: 'CommonSituationId' = 175539 + VET_SICK_CAT_MID_LEVEL_TEEN: 'CommonSituationId' = 175541 + VET_SICK_CAT_TEEN: 'CommonSituationId' = 174441 + VET_SICK_DOG: 'CommonSituationId' = 164629 + VET_SICK_DOG_HIGH_LEVEL: 'CommonSituationId' = 175550 + VET_SICK_DOG_HIGH_LEVEL_TEEN: 'CommonSituationId' = 175551 + VET_SICK_DOG_MID_LEVEL: 'CommonSituationId' = 175548 + VET_SICK_DOG_MID_LEVEL_TEEN: 'CommonSituationId' = 175549 + VET_SICK_DOG_TEEN: 'CommonSituationId' = 174438 + VIP_ROPE_BOUNCER: 'CommonSituationId' = 194488 + VISITOR_BARFLY: 'CommonSituationId' = 122602 + VOODOO_SUMMON: 'CommonSituationId' = 40508 + WALK_BY_AMBIENT: 'CommonSituationId' = 24807 + WALK_BY_AMBIENT_ALIEN: 'CommonSituationId' = 113923 + WALK_BY_AMBIENT_ALIEN_IN_DISGUISE: 'CommonSituationId' = 116920 + WALK_BY_AMBIENT_CAMPING_FOREST: 'CommonSituationId' = 106136 + WALK_BY_AMBIENT_CITY_LIFE_APARTMENT_NEIGHBORS_COMMUTER_SCHOOL_COME_FROM_APT: 'CommonSituationId' = 139559 + WALK_BY_AMBIENT_CITY_LIFE_APARTMENT_NEIGHBORS_COMMUTER_SCHOOL_GO_TO_APT: 'CommonSituationId' = 141062 + WALK_BY_AMBIENT_CITY_LIFE_APARTMENT_NEIGHBORS_COMMUTER_WORK_COME_FROM_APT: 'CommonSituationId' = 139550 + WALK_BY_AMBIENT_CITY_LIFE_APARTMENT_NEIGHBORS_COMMUTER_WORK_GO_TO_APT: 'CommonSituationId' = 141061 + WALK_BY_AMBIENT_CITY_LIFE_APARTMENT_NEIGHBORS_VISITOR_COME_FROM_APT: 'CommonSituationId' = 141060 + WALK_BY_AMBIENT_CITY_LIFE_APARTMENT_NEIGHBORS_VISITOR_GO_TO_APT: 'CommonSituationId' = 141059 + WALK_BY_AMBIENT_CITY_LIFE_COFFEE_DRINKER: 'CommonSituationId' = 134206 + WALK_BY_AMBIENT_CITY_LIFE_COMMUTER: 'CommonSituationId' = 134208 + WALK_BY_AMBIENT_CITY_LIFE_LIVES_ON_STREET: 'CommonSituationId' = 155984 + WALK_BY_AMBIENT_CITY_LIFE_PHONE_CHATTER: 'CommonSituationId' = 134210 + WALK_BY_AMBIENT_CITY_LIFE_SNACKER: 'CommonSituationId' = 134207 + WALK_BY_AMBIENT_CITY_LIFE_WEIRDO_TOWELS: 'CommonSituationId' = 145071 + WALK_BY_AMBIENT_CLOWN: 'CommonSituationId' = 97227 + WALK_BY_AMBIENT_CRIMINAL: 'CommonSituationId' = 97223 + WALK_BY_AMBIENT_DESERT_OASIS: 'CommonSituationId' = 25166 + WALK_BY_AMBIENT_ECO_WORLD_FREEGAN: 'CommonSituationId' = 236933 + WALK_BY_AMBIENT_ECO_WORLD_VOTER_WALK_BY: 'CommonSituationId' = 234195 + WALK_BY_AMBIENT_EVENT_NPC_FALL_CHALLENGE: 'CommonSituationId' = 153170 + WALK_BY_AMBIENT_EVENT_NPC_SPRING_CHALLENGE: 'CommonSituationId' = 162934 + WALK_BY_AMBIENT_EVENT_NPC_XP_BOOST: 'CommonSituationId' = 149996 + WALK_BY_AMBIENT_FAKE_VAMPIRE_AFTER_DARK: 'CommonSituationId' = 153768 + WALK_BY_AMBIENT_FAME_WORLD_PAPARAZZI: 'CommonSituationId' = 200334 + WALK_BY_AMBIENT_FAME_WORLD_RESIDENTS_CELEBRITY_LEAVE_HOME: 'CommonSituationId' = 196922 + WALK_BY_AMBIENT_FAME_WORLD_RESIDENTS_CELEBRITY_RETURN_HOME: 'CommonSituationId' = 196923 + WALK_BY_AMBIENT_FAME_WORLD_RESIDENTS_SCHOOL_LEAVE_HOME: 'CommonSituationId' = 196887 + WALK_BY_AMBIENT_FAME_WORLD_RESIDENTS_SCHOOL_RETURN_HOME: 'CommonSituationId' = 196889 + WALK_BY_AMBIENT_FAME_WORLD_RESIDENTS_WORK_LEAVE_HOME: 'CommonSituationId' = 196863 + WALK_BY_AMBIENT_FAME_WORLD_RESIDENTS_WORK_RETURN_HOME: 'CommonSituationId' = 196865 + WALK_BY_AMBIENT_FAME_WORLD_STUDIO_ACTOR: 'CommonSituationId' = 197813 + WALK_BY_AMBIENT_FAME_WORLD_STUDIO_ASSISTANT: 'CommonSituationId' = 197811 + WALK_BY_AMBIENT_FAME_WORLD_TOURIST: 'CommonSituationId' = 201114 + WALK_BY_AMBIENT_GARDENER: 'CommonSituationId' = 196892 + WALK_BY_AMBIENT_GARDENER_TO_LOT: 'CommonSituationId' = 200559 + WALK_BY_AMBIENT_GARDEN_DISTRICT: 'CommonSituationId' = 25165 + WALK_BY_AMBIENT_GARDEN_DISTRICT_FAMILY_TIME: 'CommonSituationId' = 36751 + WALK_BY_AMBIENT_GARDEN_DISTRICT_ON_THE_TOWN: 'CommonSituationId' = 36750 + WALK_BY_AMBIENT_GARDEN_DISTRICT_PARK_AFTER_DARK: 'CommonSituationId' = 36779 + WALK_BY_AMBIENT_GARDEN_DISTRICT_PARK_JOGGER: 'CommonSituationId' = 36777 + WALK_BY_AMBIENT_GARDEN_DISTRICT_PARK_PLAY_TIME: 'CommonSituationId' = 36766 + WALK_BY_AMBIENT_GARDEN_DISTRICT_PARK_RELAXER: 'CommonSituationId' = 36778 + WALK_BY_AMBIENT_GARDEN_DISTRICT_PARK_STREAKER: 'CommonSituationId' = 238441 + WALK_BY_AMBIENT_GARDEN_DISTRICT_SCHOOL_COMMUTE: 'CommonSituationId' = 36743 + WALK_BY_AMBIENT_GARDEN_DISTRICT_WORK_COMMUTE: 'CommonSituationId' = 36650 + WALK_BY_AMBIENT_HOT_DOG: 'CommonSituationId' = 97230 + WALK_BY_AMBIENT_ISLAND_WORLD_FAMILY_TIME: 'CommonSituationId' = 216134 + WALK_BY_AMBIENT_ISLAND_WORLD_JOGGER: 'CommonSituationId' = 216130 + WALK_BY_AMBIENT_ISLAND_WORLD_RELAXER: 'CommonSituationId' = 216135 + WALK_BY_AMBIENT_ISLAND_WORLD_TEEN: 'CommonSituationId' = 216131 + WALK_BY_AMBIENT_MAGIC_PORTAL_GO_TO_PORTAL: 'CommonSituationId' = 217134 + WALK_BY_AMBIENT_MAGIC_PORTAL_LEAVE_PORTAL: 'CommonSituationId' = 217131 + WALK_BY_AMBIENT_MAID: 'CommonSituationId' = 97233 + WALK_BY_AMBIENT_MAID_TO_LOT: 'CommonSituationId' = 200551 + WALK_BY_AMBIENT_MAILMAN: 'CommonSituationId' = 112304 + WALK_BY_AMBIENT_NEIGHBOR_JOGGER: 'CommonSituationId' = 126207 + WALK_BY_AMBIENT_NEIGHBOR_SCHOOL_COMMUTE: 'CommonSituationId' = 126180 + WALK_BY_AMBIENT_PET_WORLD_BEACH_JOGGER: 'CommonSituationId' = 163939 + WALK_BY_AMBIENT_PET_WORLD_BEACH_WALKER: 'CommonSituationId' = 163940 + WALK_BY_AMBIENT_PET_WORLD_DOG_WALKER: 'CommonSituationId' = 167623 + WALK_BY_AMBIENT_PET_WORLD_WORKER: 'CommonSituationId' = 163938 + WALK_BY_AMBIENT_PIZZA: 'CommonSituationId' = 97234 + WALK_BY_AMBIENT_POLICE_PATROL: 'CommonSituationId' = 112411 + WALK_BY_AMBIENT_REPAIRMAN: 'CommonSituationId' = 196916 + WALK_BY_AMBIENT_REPAIRMAN_TO_LOT: 'CommonSituationId' = 200561 + WALK_BY_AMBIENT_SCOUTING: 'CommonSituationId' = 188541 + WALK_BY_AMBIENT_STRANGER_VILLE_MILITARY_01: 'CommonSituationId' = 203282 + WALK_BY_AMBIENT_STRANGER_VILLE_MILITARY_02: 'CommonSituationId' = 206206 + WALK_BY_AMBIENT_STRANGER_VILLE_MILITARY_03: 'CommonSituationId' = 206207 + WALK_BY_AMBIENT_STRANGER_VILLE_MILITARY_04: 'CommonSituationId' = 206208 + WALK_BY_AMBIENT_STRANGER_VILLE_SCIENTIST_01: 'CommonSituationId' = 203281 + WALK_BY_AMBIENT_STRANGER_VILLE_SCIENTIST_02: 'CommonSituationId' = 206214 + WALK_BY_AMBIENT_STRANGER_VILLE_SCIENTIST_03: 'CommonSituationId' = 206215 + WALK_BY_AMBIENT_STRANGER_VILLE_SCIENTIST_04: 'CommonSituationId' = 206217 + WALK_BY_AMBIENT_TEEN: 'CommonSituationId' = 160242 + WALK_BY_AMBIENT_TRAGIC_CLOWN: 'CommonSituationId' = 139893 + WALK_BY_AMBIENT_VAMPIRE_AFTER_DARK: 'CommonSituationId' = 153739 + WALK_BY_AMBIENT_VAMPIRE_AFTER_DARK_HAS_HOME: 'CommonSituationId' = 156394 + WALK_BY_AMBIENT_WALK_OF_SHAME: 'CommonSituationId' = 76157 + WALK_BY_AMBIENT_WEATHER_RAINING: 'CommonSituationId' = 184882 + WALK_BY_AMBIENT_WEATHER_SNOWING: 'CommonSituationId' = 184883 + WALK_BY_AMBIENT_WINDENBURG: 'CommonSituationId' = 25167 + WALK_BY_DOG_WALKER_WALK_TYAE: 'CommonSituationId' = 168135 + WALK_BY_ECO_PERSONALITY_ECO_MASTER: 'CommonSituationId' = 241169 + WALK_BY_ECO_PERSONALITY_ENTREPRENEUR: 'CommonSituationId' = 241170 + WALK_BY_ECO_PERSONALITY_MAKER: 'CommonSituationId' = 241171 + WALK_BY_EVENT_FALL_CHALLENGE2016_DO_TD_CELEBRATOR: 'CommonSituationId' = 153126 + WALK_BY_EVENT_SPRING_CHALLENGE_PLANT_SIM_NPC: 'CommonSituationId' = 163056 + WALK_BY_ISLAND_CONSERVATION_ANTI_ENVIRONMENTALIST: 'CommonSituationId' = 210237 + WALK_BY_ISLAND_CONSERVATION_CONSERVATIONIST: 'CommonSituationId' = 211666 + WALK_BY_ISLAND_CONSERVATION_LITTERING_SIM: 'CommonSituationId' = 210238 + WALK_BY_ISLAND_CONSERVATION_POACHING_SIM: 'CommonSituationId' = 210239 + WALK_BY_JUNGLE_CHILD: 'CommonSituationId' = 181342 + WALK_BY_JUNGLE_TYAE: 'CommonSituationId' = 181341 + WALK_BY_MAGIC_DUEL: 'CommonSituationId' = 216807 + WALK_BY_NEIGHBOR: 'CommonSituationId' = 120057 + WALK_BY_NOBODY: 'CommonSituationId' = 77411 + WALK_BY_RENT_DUE_APARTMENT_LANDLORD: 'CommonSituationId' = 143686 + WALK_BY_RING_DOORBELL_ACQUIRED_FAMILY_REL_BIT: 'CommonSituationId' = 164639 + WALK_BY_RING_DOORBELL_MAX_FAMILY_REL_BIT: 'CommonSituationId' = 168415 + WALK_BY_RING_DOORBELL_NEIGHBOR: 'CommonSituationId' = 100055 + WALK_BY_RING_DOORBELL_VAMPIRE: 'CommonSituationId' = 153167 + WALK_BY_RING_DOORBELL_VAMPIRES_INITIAL: 'CommonSituationId' = 157974 + WALK_BY_RING_DOORBELL_WITH_RELATIONSHIP: 'CommonSituationId' = 35723 + WALK_BY_SURPRISE_HOLIDAY_PIRATE_DAY: 'CommonSituationId' = 182798 + WALK_BY_UNIVERSITY_WORLD_ARTS_FROM_ARENA_ATHLETE_E_SPORTS: 'CommonSituationId' = 222604 + WALK_BY_UNIVERSITY_WORLD_ARTS_FROM_ARENA_ATHLETE_SOCCER: 'CommonSituationId' = 222605 + WALK_BY_UNIVERSITY_WORLD_ARTS_FROM_ARENA_MASCOT: 'CommonSituationId' = 222859 + WALK_BY_UNIVERSITY_WORLD_ARTS_FROM_ARENA_SPORTS_FAN_E_SPORTS: 'CommonSituationId' = 222606 + WALK_BY_UNIVERSITY_WORLD_ARTS_FROM_ARENA_SPORTS_FAN_SOCCER: 'CommonSituationId' = 222607 + WALK_BY_UNIVERSITY_WORLD_ARTS_FROM_CLASS_BIKE_STUDENT: 'CommonSituationId' = 222810 + WALK_BY_UNIVERSITY_WORLD_ARTS_FROM_CLASS_PROFESSOR: 'CommonSituationId' = 222598 + WALK_BY_UNIVERSITY_WORLD_ARTS_FROM_CLASS_STUDENT: 'CommonSituationId' = 222599 + WALK_BY_UNIVERSITY_WORLD_ARTS_TO_ARENA_ATHLETE_E_SPORTS: 'CommonSituationId' = 222608 + WALK_BY_UNIVERSITY_WORLD_ARTS_TO_ARENA_ATHLETE_SOCCER: 'CommonSituationId' = 222609 + WALK_BY_UNIVERSITY_WORLD_ARTS_TO_ARENA_MASCOT: 'CommonSituationId' = 222860 + WALK_BY_UNIVERSITY_WORLD_ARTS_TO_ARENA_SPORTS_FAN_E_SPORTS: 'CommonSituationId' = 222610 + WALK_BY_UNIVERSITY_WORLD_ARTS_TO_ARENA_SPORTS_FAN_SOCCER: 'CommonSituationId' = 222611 + WALK_BY_UNIVERSITY_WORLD_ARTS_TO_CLASS_BIKE_STUDENT: 'CommonSituationId' = 222811 + WALK_BY_UNIVERSITY_WORLD_ARTS_TO_CLASS_PROFESSOR: 'CommonSituationId' = 222602 + WALK_BY_UNIVERSITY_WORLD_ARTS_TO_CLASS_STUDENT: 'CommonSituationId' = 222603 + WALK_BY_UNIVERSITY_WORLD_GENERAL_ARTS_BIKE_STUDENT: 'CommonSituationId' = 222820 + WALK_BY_UNIVERSITY_WORLD_GENERAL_ARTS_STUDENT: 'CommonSituationId' = 222666 + WALK_BY_UNIVERSITY_WORLD_GENERAL_PROFESSOR: 'CommonSituationId' = 222668 + WALK_BY_UNIVERSITY_WORLD_GENERAL_SCIENCE_BIKE_STUDENT: 'CommonSituationId' = 222821 + WALK_BY_UNIVERSITY_WORLD_GENERAL_SCIENCE_STUDENT: 'CommonSituationId' = 222667 + WALK_BY_UNIVERSITY_WORLD_NOTEBOOK_STUDENTS_ARTS: 'CommonSituationId' = 229520 + WALK_BY_UNIVERSITY_WORLD_NOTEBOOK_STUDENTS_SCIENCE: 'CommonSituationId' = 229521 + WALK_BY_UNIVERSITY_WORLD_SCIENCE_FROM_ARENA_ATHLETE_E_SPORTS: 'CommonSituationId' = 222636 + WALK_BY_UNIVERSITY_WORLD_SCIENCE_FROM_ARENA_ATHLETE_SOCCER: 'CommonSituationId' = 222637 + WALK_BY_UNIVERSITY_WORLD_SCIENCE_FROM_ARENA_MASCOT: 'CommonSituationId' = 222857 + WALK_BY_UNIVERSITY_WORLD_SCIENCE_FROM_ARENA_SPORTS_FAN_E_SPORTS: 'CommonSituationId' = 222638 + WALK_BY_UNIVERSITY_WORLD_SCIENCE_FROM_ARENA_SPORTS_FAN_SOCCER: 'CommonSituationId' = 222639 + WALK_BY_UNIVERSITY_WORLD_SCIENCE_FROM_CLASS_BIKE_STUDENT: 'CommonSituationId' = 222812 + WALK_BY_UNIVERSITY_WORLD_SCIENCE_FROM_CLASS_PROFESSOR: 'CommonSituationId' = 222642 + WALK_BY_UNIVERSITY_WORLD_SCIENCE_FROM_CLASS_STUDENT: 'CommonSituationId' = 222643 + WALK_BY_UNIVERSITY_WORLD_SCIENCE_TO_ARENA_ATHLETE_E_SPORTS: 'CommonSituationId' = 222646 + WALK_BY_UNIVERSITY_WORLD_SCIENCE_TO_ARENA_ATHLETE_SOCCER: 'CommonSituationId' = 222647 + WALK_BY_UNIVERSITY_WORLD_SCIENCE_TO_ARENA_MASCOT: 'CommonSituationId' = 222858 + WALK_BY_UNIVERSITY_WORLD_SCIENCE_TO_ARENA_SPORTS_FAN_E_SPORTS: 'CommonSituationId' = 222649 + WALK_BY_UNIVERSITY_WORLD_SCIENCE_TO_ARENA_SPORTS_FAN_SOCCER: 'CommonSituationId' = 222650 + WALK_BY_UNIVERSITY_WORLD_SCIENCE_TO_CLASS_BIKE_STUDENT: 'CommonSituationId' = 222813 + WALK_BY_UNIVERSITY_WORLD_SCIENCE_TO_CLASS_PROFESSOR: 'CommonSituationId' = 222653 + WALK_BY_UNIVERSITY_WORLD_SCIENCE_TO_CLASS_STUDENT: 'CommonSituationId' = 222654 + WALK_BY_WATER_SCOOTER_1: 'CommonSituationId' = 209284 + WALK_BY_WATER_SCOOTER_ISLAND_CANOE: 'CommonSituationId' = 214012 + WALK_DOG_GO_FOR_JOG: 'CommonSituationId' = 166358 + WALK_DOG_LONG: 'CommonSituationId' = 166533 + WALK_DOG_SHORT: 'CommonSituationId' = 166532 + WALK_DOG_SITUATION: 'CommonSituationId' = 165652 + WARDROBE_PEDESTAL_STYLIST: 'CommonSituationId' = 191614 + WEDDING: 'CommonSituationId' = 16202 + WEENIE_ROAST: 'CommonSituationId' = 103691 + WELCOME_WAGON: 'CommonSituationId' = 119785 + WELCOME_WAGON_ISLANDER_CULTURE_DEATH_COMFORT: 'CommonSituationId' = 208665 + WELCOME_WAGON_ISLANDER_CULTURE_EXTRA_FOOD: 'CommonSituationId' = 208435 + WORK_OUT_DANCE_TOGETHER: 'CommonSituationId' = 166819 + WORK_OUT_POWER_SCULPTING_TOGETHER: 'CommonSituationId' = 164398 + YOGA_CLASS_BRAIN_BOOSTING: 'CommonSituationId' = 118796 + YOGA_CLASS_ENERGY_CENTERING: 'CommonSituationId' = 118132 + YOGA_CLASS_MIND_CONCENTRATING: 'CommonSituationId' = 118797 + YOGA_CLASS_POST_HANGOUT: 'CommonSituationId' = 122121 + YOGA_INSTRUCTOR_VENUE: 'CommonSituationId' = 12 diff --git a/Scripts/s4ap/sims4communitylib/enums/skills_enum.py b/Scripts/s4ap/sims4communitylib/enums/skills_enum.py new file mode 100644 index 0000000..e40eba6 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/skills_enum.py @@ -0,0 +1,154 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonSkillId(CommonInt): + """Identifiers for sim skills. + + """ + INVALID: 'CommonSkillId' = 0 + ACTING: 'CommonSkillId' = 194727 + ARCHAEOLOGY: 'CommonSkillId' = 174237 + BAKING: 'CommonSkillId' = 104198 + BOWLING: 'CommonSkillId' = 158659 + CHARISMA: 'CommonSkillId' = 16699 + CHOPSTICKS: 'CommonSkillId' = 142593 + COMEDY: 'CommonSkillId' = 16698 + COMMUNICATION: 'CommonSkillId' = 140170 + COOKING: 'CommonSkillId' = 16705 + CREATIVITY: 'CommonSkillId' = 16718 + CROSS_STITCH: 'CommonSkillId' = 259758 + DANCING: 'CommonSkillId' = 128145 + DARTBOARD_DARTS: 'CommonSkillId' = 127868 + DJ_MIXING: 'CommonSkillId' = 121612 + ENTREPRENEUR: 'CommonSkillId' = 274197 + EQUESTRIAN_SKILL: 'CommonSkillId' = 322708 + FABRICATION: 'CommonSkillId' = 231908 + FISHING: 'CommonSkillId' = 39397 + FITNESS: 'CommonSkillId' = 16659 + FLOWER_ARRANGING: 'CommonSkillId' = 186703 + FOOSBALL: 'CommonSkillId' = 122854 + GARDENING: 'CommonSkillId' = 16700 + GOURMET_COOKING: 'CommonSkillId' = 16701 + GUITAR: 'CommonSkillId' = 16702 + HANDINESS: 'CommonSkillId' = 16704 + HERBALISM: 'CommonSkillId' = 101920 + HORSE_AGILITY: 'CommonSkillId' = 324632 + HORSE_ENDURANCE: 'CommonSkillId' = 324634 + HORSE_JUMPING: 'CommonSkillId' = 324633 + HORSE_TEMPERAMENT: 'CommonSkillId' = 324631 + HUMANOID_ROBOT_ENHANCEMENT: 'CommonSkillId' = 224672 + IMAGINATION: 'CommonSkillId' = 140706 + INFANT_CRAWL_HIDDEN: 'CommonSkillId' = 297187 + INFANT_MILESTONE_FINE_MOTOR_HIDDEN: 'CommonSkillId' = 273725 + INFANT_MILESTONE_GROSS_MOTOR_HIDDEN: 'CommonSkillId' = 273723 + INFANT_MILESTONE_SOCIAL_HIDDEN: 'CommonSkillId' = 273726 + INFANT_SOCIAL_AGE_UP_HIDDEN: 'CommonSkillId' = 324352 + JUICE_FIZZING: 'CommonSkillId' = 234806 + JUICE_PONG: 'CommonSkillId' = 213548 + KNITTING: 'CommonSkillId' = 239521 + LOGIC: 'CommonSkillId' = 16706 + MAINTENANCE: 'CommonSkillId' = 111904 + MEDIA_PRODUCTION: 'CommonSkillId' = 192655 + MEDIUM: 'CommonSkillId' = 255249 + MENTAL: 'CommonSkillId' = 16719 + MISCHIEF: 'CommonSkillId' = 16707 + MIXOLOGY: 'CommonSkillId' = 16695 + MOTOR: 'CommonSkillId' = 16720 + MOVEMENT: 'CommonSkillId' = 136140 + PAINTING: 'CommonSkillId' = 16708 + PARENTING: 'CommonSkillId' = 160504 + PET_POOP_CLEAN_UP: 'CommonSkillId' = 161097 + PET_TRAINING: 'CommonSkillId' = 161220 + PHOTOGRAPHY: 'CommonSkillId' = 105774 + PIANO: 'CommonSkillId' = 16709 + PING_PONG: 'CommonSkillId' = 212561 + PIPE_ORGAN: 'CommonSkillId' = 149665 + POTTY: 'CommonSkillId' = 144913 + PROGRAMMING: 'CommonSkillId' = 16703 + RANCH_NECTAR: 'CommonSkillId' = 315761 + RESEARCH_AND_DEBATE: 'CommonSkillId' = 221014 + ROBOTICS: 'CommonSkillId' = 217413 + ROCKET_SCIENCE: 'CommonSkillId' = 16710 + ROCK_CLIMBING: 'CommonSkillId' = 245639 + ROCK_CLIMBING_HIDDEN: 'CommonSkillId' = 165900 + SALES: 'CommonSkillId' = 111902 + SELVADORADIAN_CULTURE: 'CommonSkillId' = 174687 + SHELL_TUTOR_PICKED_SKILL_HIDDEN: 'CommonSkillId' = 224628 + SINGING: 'CommonSkillId' = 137811 + SKATING_HIDDEN: 'CommonSkillId' = 179925 + SKIING: 'CommonSkillId' = 245613 + SNOWBOARDING: 'CommonSkillId' = 246054 + SOCIAL: 'CommonSkillId' = 16721 + SPICY_FOOD: 'CommonSkillId' = 142592 + THINKING: 'CommonSkillId' = 140504 + THROWING_THINGS: 'CommonSkillId' = DARTBOARD_DARTS + VAMPIRE_LORE_HIDDEN: 'CommonSkillId' = 149556 + VETERINARIAN: 'CommonSkillId' = 161190 + VIDEO_GAMING: 'CommonSkillId' = 16712 + VIOLIN: 'CommonSkillId' = 16713 + WELLNESS: 'CommonSkillId' = 117858 + WORK_ETHIC: 'CommonSkillId' = 111903 + WRITING: 'CommonSkillId' = 16714 + + # All of the following values are obsolete, please use the above values instead! + ADULT_MAJOR_ACTING: 'CommonSkillId' = ACTING + ADULT_MAJOR_ARCHAEOLOGY: 'CommonSkillId' = ARCHAEOLOGY + ADULT_MAJOR_BAKING: 'CommonSkillId' = BAKING + ADULT_MAJOR_BAR_TENDING: 'CommonSkillId' = MIXOLOGY + ADULT_MAJOR_CHARISMA: 'CommonSkillId' = CHARISMA + ADULT_MAJOR_COMEDY: 'CommonSkillId' = COMEDY + ADULT_MAJOR_DJ_MIXING: 'CommonSkillId' = DJ_MIXING + ADULT_MAJOR_FABRICATION: 'CommonSkillId' = FABRICATION + ADULT_MAJOR_FISHING: 'CommonSkillId' = FISHING + ADULT_MAJOR_FLOWER_ARRANGING: 'CommonSkillId' = FLOWER_ARRANGING + ADULT_MAJOR_GARDENING: 'CommonSkillId' = GARDENING + ADULT_MAJOR_GOURMET_COOKING: 'CommonSkillId' = GOURMET_COOKING + ADULT_MAJOR_GUITAR: 'CommonSkillId' = GUITAR + ADULT_MAJOR_HANDINESS: 'CommonSkillId' = HANDINESS + ADULT_MAJOR_HERBALISM: 'CommonSkillId' = HERBALISM + ADULT_MAJOR_HOME_STYLE_COOKING: 'CommonSkillId' = COOKING + ADULT_MAJOR_LOGIC: 'CommonSkillId' = LOGIC + ADULT_MAJOR_MISCHIEF: 'CommonSkillId' = MISCHIEF + ADULT_MAJOR_PAINTING: 'CommonSkillId' = PAINTING + ADULT_MAJOR_PARENTING: 'CommonSkillId' = PARENTING + ADULT_MAJOR_PHOTOGRAPHY: 'CommonSkillId' = PHOTOGRAPHY + ADULT_MAJOR_PIANO: 'CommonSkillId' = PIANO + ADULT_MAJOR_PIPE_ORGAN: 'CommonSkillId' = PIPE_ORGAN + ADULT_MAJOR_PROGRAMMING: 'CommonSkillId' = PROGRAMMING + ADULT_MAJOR_ROCKET_SCIENCE: 'CommonSkillId' = ROCKET_SCIENCE + ADULT_MAJOR_SINGING: 'CommonSkillId' = SINGING + ADULT_MAJOR_VETERINARIAN: 'CommonSkillId' = VETERINARIAN + ADULT_MAJOR_VIDEO_GAMING: 'CommonSkillId' = VIDEO_GAMING + ADULT_MAJOR_VIOLIN: 'CommonSkillId' = VIOLIN + ADULT_MAJOR_WELLNESS: 'CommonSkillId' = WELLNESS + ADULT_MAJOR_WRITING: 'CommonSkillId' = WRITING + ADULT_MINOR_DANCING: 'CommonSkillId' = DANCING + ADULT_MINOR_JUICE_FIZZING: 'CommonSkillId' = JUICE_FIZZING + ADULT_MINOR_LOCAL_CULTURE: 'CommonSkillId' = SELVADORADIAN_CULTURE + ADULT_MINOR_MEDIA_PRODUCTION: 'CommonSkillId' = MEDIA_PRODUCTION + CHILD_CREATIVITY: 'CommonSkillId' = CREATIVITY + CHILD_MENTAL: 'CommonSkillId' = MENTAL + CHILD_MOTOR: 'CommonSkillId' = MOTOR + CHILD_SOCIAL: 'CommonSkillId' = SOCIAL + DOG_TRAINING: 'CommonSkillId' = PET_TRAINING + SKATING = SKATING_HIDDEN + HIDDEN_SKATING: 'CommonSkillId' = SKATING_HIDDEN + HIDDEN_TREAD_MILL_ROCK_CLIMBING_WALL_CLIMB: 'CommonSkillId' = ROCK_CLIMBING_HIDDEN + HIDDEN_VAMPIRE_LORE: 'CommonSkillId' = VAMPIRE_LORE_HIDDEN + OBJECT_UPGRADE_COMPUTER_GAMING: 'CommonSkillId' = 29027 + RETAIL_MAINTENANCE: 'CommonSkillId' = MAINTENANCE + RETAIL_SALES: 'CommonSkillId' = SALES + RETAIL_WORK_ETHIC: 'CommonSkillId' = WORK_ETHIC + TODDLER_COMMUNICATION: 'CommonSkillId' = COMMUNICATION + TODDLER_IMAGINATION: 'CommonSkillId' = IMAGINATION + TODDLER_MOVEMENT: 'CommonSkillId' = MOVEMENT + TODDLER_POTTY: 'CommonSkillId' = POTTY + TODDLER_THINKING: 'CommonSkillId' = THINKING + VAMPIRE_LORE = VAMPIRE_LORE_HIDDEN diff --git a/Scripts/s4ap/sims4communitylib/enums/statistics_enum.py b/Scripts/s4ap/sims4communitylib/enums/statistics_enum.py new file mode 100644 index 0000000..f0cfd0d --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/statistics_enum.py @@ -0,0 +1,1698 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonStatisticId(CommonInt): + """Identifiers for vanilla statistics. + + """ + INVALID: 'CommonStatisticId' = 0 + ACTOR_CAREER_MAIN_GOAL: 'CommonStatisticId' = 197925 + ACTOR_CAREER_PRE_PERFORMANCE_DIRECTOR_PRODUCER: 'CommonStatisticId' = 193186 + ACTOR_CAREER_PRE_PERFORMANCE_DOLLY_CAMERA: 'CommonStatisticId' = 194698 + ACTOR_CAREER_PRE_PERFORMANCE_STATIONARY_CAMERA: 'CommonStatisticId' = 194697 + ACTOR_CAREER_PREP_TASK_PRACTICE_ACTION: 'CommonStatisticId' = 199419 + ACTOR_CAREER_PREP_TASK_PRACTICE_DRAMATIC: 'CommonStatisticId' = 199420 + ACTOR_CAREER_PREP_TASK_PRACTICE_ROMANTIC: 'CommonStatisticId' = 199418 + ACTOR_CAREER_PREP_TASK_RELATIONSHIP_CO_STAR: 'CommonStatisticId' = 197221 + ACTOR_CAREER_PREP_TASK_RELATIONSHIP_DIRECTOR: 'CommonStatisticId' = 197222 + ACTOR_CAREER_PREP_TASK_RESEARCH_FLIRTY: 'CommonStatisticId' = 199421 + ACTOR_CAREER_PREP_TASK_RESEARCH_FUNNY: 'CommonStatisticId' = 199422 + ACTOR_CAREER_PREP_TASK_RESEARCH_MEAN: 'CommonStatisticId' = 199423 + ACTOR_CAREER_PREP_TASK_SKILL_ACTING: 'CommonStatisticId' = 199417 + ACTOR_CAREER_PREP_TASK_SKILL_CHARISMA: 'CommonStatisticId' = 197223 + ACTOR_CAREER_PREP_TASK_SKILL_COMEDY: 'CommonStatisticId' = 197225 + ACTOR_CAREER_PREP_TASK_SKILL_FITNESS: 'CommonStatisticId' = 197224 + ACTOR_CAREER_PREP_TASK_SKILL_GUITAR: 'CommonStatisticId' = 197226 + ACTOR_CAREER_PREP_TASK_SKILL_HANDINESS: 'CommonStatisticId' = 197227 + ACTOR_CAREER_SAFE_OUTCOME: 'CommonStatisticId' = 197349 + ADVENTUROUS_PET_GO_ON_ADVENTURE_LIGHTHOUSE_PROGRESS: 'CommonStatisticId' = 175555 + AGE_ADULT: 'CommonStatisticId' = 38438 + AGE_CHILD: 'CommonStatisticId' = 38441 + AGE_ELDER: 'CommonStatisticId' = 38437 + AGE_TEEN: 'CommonStatisticId' = 38440 + AGE_YOUNG_ADULT: 'CommonStatisticId' = 38439 + ALIEN_ABDUCTION_COOLDOWN: 'CommonStatisticId' = 102866 + ALIEN_ABDUCTION_TRACKER: 'CommonStatisticId' = 102865 + ALIEN_MEMORY_ERASE_COOLDOWN: 'CommonStatisticId' = 103694 + ALIEN_WATCH_ALIEN_TV: 'CommonStatisticId' = 107154 + ANCIENT_ARTIFACT_UNCOVER_STATE_FLAG: 'CommonStatisticId' = 184279 + APARTMENT_BULLETIN_BOARD_TIMER: 'CommonStatisticId' = 145322 + ARCADE_MACHINE_GAME_OVER_TIME_OUT: 'CommonStatisticId' = 128204 + ARCADE_MACHINE_LIVES_LEFT: 'CommonStatisticId' = 127410 + ARCADE_MACHINE_NUMBER_OF_PLAYERS: 'CommonStatisticId' = 128094 + ARCADE_MACHINE_PROGRESSION: 'CommonStatisticId' = 127408 + ARCHAEOLOGY_SKILL_GIVE_AUTHENTICATION_MAIL: 'CommonStatisticId' = 176117 + ARCHAEOLOGY_TABLE_ANALYZE_COLLECTIBLE: 'CommonStatisticId' = 182766 + ARCHAEOLOGY_TABLE_AUTHENTICATE_ARTIFACT: 'CommonStatisticId' = 182767 + ARCHAEOLOGY_TABLE_EXTRACT_ELEMENT: 'CommonStatisticId' = 182769 + ARCHAEOLOGY_TABLE_REFINE_CRYSTAL: 'CommonStatisticId' = 182768 + ARCHAEOLOGY_TABLE_UNCOVER_ARTIFACT: 'CommonStatisticId' = 182770 + ASKED_FOR_ADVICE: 'CommonStatisticId' = 166010 + ASPIRATION_WORLD_FAMOUS_CELEBRITY_ASKED_FOR_SELFIE_COUNT: 'CommonStatisticId' = 197546 + ASPIRATION_WORLD_FAMOUS_CELEBRITY_INCITE_CHEER_COUNT: 'CommonStatisticId' = 197547 + ATTRACTOR_POINTS_TOURIST_TAKE_PHOTO: 'CommonStatisticId' = 178223 + ATTRACTOR_POINTS_TOURIST_VIEW: 'CommonStatisticId' = 196996 + AUTO_PET_FEEDER_FOOD_REMAINING: 'CommonStatisticId' = 159119 + AUTONOMY_FAMILY_BULLETIN_BOARD: 'CommonStatisticId' = 166672 + AUTONOMY_GHOST_HAUNT: 'CommonStatisticId' = 102775 + AUTONOMY_TRAIT_GHOST_COW_PLANT: 'CommonStatisticId' = 102856 + AWAY_ACTION_DIRTY: 'CommonStatisticId' = 75572 + AWAY_ACTION_GARDEN: 'CommonStatisticId' = 75733 + AWAY_ACTIONS_BEDS: 'CommonStatisticId' = 76162 + AWAY_ACTIONS_GARDEN_PLANTS: 'CommonStatisticId' = 76182 + AWAY_ACTIONS_HAS_SKILL_OBJECTS_BARTENDING: 'CommonStatisticId' = 76256 + AWAY_ACTIONS_HAS_SKILL_OBJECTS_CHARISMA: 'CommonStatisticId' = 76257 + AWAY_ACTIONS_HAS_SKILL_OBJECTS_CHILD_CREATIVITY: 'CommonStatisticId' = 76272 + AWAY_ACTIONS_HAS_SKILL_OBJECTS_CHILD_MENTAL: 'CommonStatisticId' = 76273 + AWAY_ACTIONS_HAS_SKILL_OBJECTS_CHILD_MOTOR: 'CommonStatisticId' = 76274 + AWAY_ACTIONS_HAS_SKILL_OBJECTS_CHILD_SOCIAL: 'CommonStatisticId' = 76275 + AWAY_ACTIONS_HAS_SKILL_OBJECTS_COMEDY: 'CommonStatisticId' = 76258 + AWAY_ACTIONS_HAS_SKILL_OBJECTS_COOKING: 'CommonStatisticId' = 76263 + AWAY_ACTIONS_HAS_SKILL_OBJECTS_FISHING: 'CommonStatisticId' = 76259 + AWAY_ACTIONS_HAS_SKILL_OBJECTS_FITNESS: 'CommonStatisticId' = 76276 + AWAY_ACTIONS_HAS_SKILL_OBJECTS_GUITAR: 'CommonStatisticId' = 76261 + AWAY_ACTIONS_HAS_SKILL_OBJECTS_HANDINESS: 'CommonStatisticId' = 76262 + AWAY_ACTIONS_HAS_SKILL_OBJECTS_LOGIC: 'CommonStatisticId' = 76260 + AWAY_ACTIONS_HAS_SKILL_OBJECTS_MISCHIEF: 'CommonStatisticId' = 76264 + AWAY_ACTIONS_HAS_SKILL_OBJECTS_PAINTING: 'CommonStatisticId' = 76265 + AWAY_ACTIONS_HAS_SKILL_OBJECTS_PIANO: 'CommonStatisticId' = 76266 + AWAY_ACTIONS_HAS_SKILL_OBJECTS_PROGRAMMING: 'CommonStatisticId' = 76267 + AWAY_ACTIONS_HAS_SKILL_OBJECTS_ROCKET_SCIENCE: 'CommonStatisticId' = 76268 + AWAY_ACTIONS_HAS_SKILL_OBJECTS_VIDEO_GAMING: 'CommonStatisticId' = 76269 + AWAY_ACTIONS_HAS_SKILL_OBJECTS_VIOLIN: 'CommonStatisticId' = 76270 + AWAY_ACTIONS_HAS_SKILL_OBJECTS_WELLNESS: 'CommonStatisticId' = 118846 + AWAY_ACTIONS_HAS_SKILL_OBJECTS_WRITING: 'CommonStatisticId' = 76271 + AWAY_ACTIONS_ITEMS_TO_CLEAN: 'CommonStatisticId' = 76166 + BABY_CARE_HUNGER: 'CommonStatisticId' = 38633 + BABY_CARE_HYGIENE: 'CommonStatisticId' = 38632 + BABY_CARE_SOCIAL: 'CommonStatisticId' = 38634 + BABY_FALLING_ASLEEP: 'CommonStatisticId' = 100020 + BABY_NEW: 'CommonStatisticId' = 98939 + BANQUET_TABLE_FOOD_SPAWNED: 'CommonStatisticId' = 116824 + BASKETBALL_COACH_TIMER: 'CommonStatisticId' = 154698 + BASSINET_NEGLECTED: 'CommonStatisticId' = 100339 + BECOMING_VAMPIRE: 'CommonStatisticId' = 149438 + BED_MONSTER_UNDER_REL_TRACKER: 'CommonStatisticId' = 136457 + BEE_BOX_HONEY: 'CommonStatisticId' = 186126 + BEE_BOX_MITES_COUNTDOWN: 'CommonStatisticId' = 190590 + BEE_BOX_MOOD: 'CommonStatisticId' = 186127 + BIRD_FLOCK_DESTROY_FLOCK: 'CommonStatisticId' = 174711 + BLESSINGS_ANCIENT_JOY_CONTAGIOUS: 'CommonStatisticId' = 175092 + BONFIRE_FIRE_INTENSITY: 'CommonStatisticId' = 121461 + BONSAI_GROWTH: 'CommonStatisticId' = 16450 + BOOK_CRAFTING_LEVEL: 'CommonStatisticId' = 100664 + BOOKING_STATION_FINGERPRINT_COOLDOWN: 'CommonStatisticId' = 110663 + BOOKING_STATION_MUGSHOT_COOLDOWN: 'CommonStatisticId' = 110664 + BOOKING_STATION_SEARCH_COOLDOWN: 'CommonStatisticId' = 110646 + BREW_POT: 'CommonStatisticId' = 27539 + BREW_SINGLE: 'CommonStatisticId' = 27552 + BUFF_ALL_MOTIVES_HIGH_GATE: 'CommonStatisticId' = 27153 + BUFF_BURNING_LOVE_START_FIRE: 'CommonStatisticId' = 107076 + BUFF_CLEANING_EMOTION: 'CommonStatisticId' = 24005 + BUFF_CONFIDENT_BY_POTION: 'CommonStatisticId' = 26335 + BUFF_DROWN_GHOST_FEAR_OF_WATER: 'CommonStatisticId' = 107571 + BUFF_ENERGIZED_BY_POTION: 'CommonStatisticId' = 26337 + BUFF_ENOUGH_ALREADY: 'CommonStatisticId' = 157743 + BUFF_FLIRTY_BY_POTION: 'CommonStatisticId' = 26305 + BUFF_FOCUSED_BY_POTION: 'CommonStatisticId' = 26338 + BUFF_GHOST_ANGRY: 'CommonStatisticId' = 102473 + BUFF_GHOST_EMBARRASSMENT: 'CommonStatisticId' = 102525 + BUFF_GHOST_PLAYFUL: 'CommonStatisticId' = 102501 + BUFF_HAPPY_BY_POTION: 'CommonStatisticId' = 26339 + BUFF_HERBALIST_POTION_INSECT_REPELLENT: 'CommonStatisticId' = 104530 + BUFF_HERBALIST_POTION_SKIN_BALM: 'CommonStatisticId' = 104568 + BUFF_HYPER_CHARGED: 'CommonStatisticId' = 190884 + BUFF_INSIDER_TRAIT_CURIOUS_ABOUT_CLUBS: 'CommonStatisticId' = 125580 + BUFF_INSIDER_TRAIT_MISS_HANGING_OUT: 'CommonStatisticId' = 125579 + BUFF_INSPIRED_BY_POTION: 'CommonStatisticId' = 26340 + BUFF_LOST_FIGHT: 'CommonStatisticId' = 16445 + BUFF_OBJECT_BATHTUB_BUBBLES: 'CommonStatisticId' = 16480 + BUFF_OBJECT_BATHTUB_PLAY: 'CommonStatisticId' = 8229 + BUFF_OBJECT_BED_RELAX: 'CommonStatisticId' = 16482 + BUFF_OBJECT_BONSAI_ONE_WITH_PLANT: 'CommonStatisticId' = 40066 + BUFF_OBJECT_BOOK_READ_FLIRTY_LOW: 'CommonStatisticId' = 16490 + BUFF_OBJECT_BOOK_READ_FOCUSED_LOW: 'CommonStatisticId' = 16491 + BUFF_OBJECT_BOOK_READ_PLAYFUL_DIRTY: 'CommonStatisticId' = 16494 + BUFF_OBJECT_BOOK_READ_SKILL_TOO_EASY: 'CommonStatisticId' = 16497 + BUFF_OBJECT_BOOK_READ_SKILL_TOO_HARD: 'CommonStatisticId' = 16498 + BUFF_OBJECT_BOOK_SKILL_TOO_EASY_VAMPIRE_BOOK: 'CommonStatisticId' = 149624 + BUFF_OBJECT_BOOK_SKILL_TOO_HARD_VAMPIRE_BOOK: 'CommonStatisticId' = 149626 + BUFF_OBJECT_CELEBU_SERUM_DRANK_CONFIDENT: 'CommonStatisticId' = 194907 + BUFF_OBJECT_CELEBU_SERUM_DRANK_ENERGY: 'CommonStatisticId' = 194909 + BUFF_OBJECT_CELEBU_SERUM_DRANK_FLIRTY: 'CommonStatisticId' = 194910 + BUFF_OBJECT_CELEBU_SERUM_DRANK_FOCUS: 'CommonStatisticId' = 194911 + BUFF_OBJECT_CELEBU_SERUM_DRANK_FUN: 'CommonStatisticId' = 194905 + BUFF_OBJECT_CELEBU_SERUM_DRANK_HAPPY: 'CommonStatisticId' = 194912 + BUFF_OBJECT_CELEBU_SERUM_DRANK_HYGIENE: 'CommonStatisticId' = 194906 + BUFF_OBJECT_CELEBU_SERUM_DRANK_INSPIRED: 'CommonStatisticId' = 194914 + BUFF_OBJECT_CELEBU_SERUM_DRANK_SLEEP: 'CommonStatisticId' = 194915 + BUFF_OBJECT_COFFEE_CAFFEINE0: 'CommonStatisticId' = 100836 + BUFF_OBJECT_COFFEE_CAFFEINE1: 'CommonStatisticId' = 16500 + BUFF_OBJECT_COFFEE_CAFFEINE2: 'CommonStatisticId' = 99750 + BUFF_OBJECT_COFFEE_OVERLOAD: 'CommonStatisticId' = 99782 + BUFF_OBJECT_COMPUTER_BRAIN_FRIED: 'CommonStatisticId' = 36128 + BUFF_OBJECT_COMPUTER_VAMPIRE_RESEARCH_TOO_EASY: 'CommonStatisticId' = 153825 + BUFF_OBJECT_COOKING_OBJECTS: 'CommonStatisticId' = 76609 + BUFF_OBJECT_FITNESS_FATIGUE: 'CommonStatisticId' = 16508 + BUFF_OBJECT_FITNESS_GOOD_WORKOUT: 'CommonStatisticId' = 97348 + BUFF_OBJECT_FITNESS_PULLED_MUSCLE: 'CommonStatisticId' = 97347 + BUFF_OBJECT_HOT_TUB_AROMATHERAPY_JASMINE: 'CommonStatisticId' = 118694 + BUFF_OBJECT_HOT_TUB_AROMATHERAPY_LEMON: 'CommonStatisticId' = 118693 + BUFF_OBJECT_HOT_TUB_AROMATHERAPY_PEPPERMINT: 'CommonStatisticId' = 118696 + BUFF_OBJECT_HOT_TUB_AROMATHERAPY_SAGE: 'CommonStatisticId' = 118695 + BUFF_OBJECT_MIRROR_BODY_SPRAY: 'CommonStatisticId' = 16522 + BUFF_OBJECT_MIRROR_BREATH_SPRAY: 'CommonStatisticId' = 16523 + BUFF_OBJECT_MIRROR_GUSSY_UP: 'CommonStatisticId' = 16525 + BUFF_OBJECT_MONKEY_BARS_PLAY: 'CommonStatisticId' = 31634 + BUFF_OBJECT_PLUMBING_USE_DIRTY: 'CommonStatisticId' = 10164 + BUFF_OBJECT_SEATING_COMFORT: 'CommonStatisticId' = 25002 + BUFF_OBJECT_SEATING_DISCOMFORT: 'CommonStatisticId' = 24998 + BUFF_OBJECT_SHOWER_TAKE_SHOWER_HIGH_QUALITY: 'CommonStatisticId' = 9963 + BUFF_OBJECT_SHOWER_TAKE_SHOWER_HIGH_QUALITY_UPGRADE: 'CommonStatisticId' = 10132 + BUFF_OBJECT_SHOWER_TAKE_SHOWER_LOW_QUALITY: 'CommonStatisticId' = 9964 + BUFF_OBJECT_SHOWER_TAKE_SHOWER_UPGRADE: 'CommonStatisticId' = 10133 + BUFF_OBJECT_STEAM_ROOM_COMFORT: 'CommonStatisticId' = 119390 + BUFF_OBJECT_STEAM_ROOM_EXPOSURE: 'CommonStatisticId' = 119409 + BUFF_OBJECT_STEREO_MUSIC_TODDLER: 'CommonStatisticId' = 147770 + BUFF_OBJECT_SURFACE_USE_DIRTY: 'CommonStatisticId' = 36390 + BUFF_OBJECT_TV_GENERIC_WATCH: 'CommonStatisticId' = 31014 + BUFF_OBJECT_VOODOO_DOLL_DAZED: 'CommonStatisticId' = 16540 + BUFF_OBJECT_VOODOO_DOLL_FUN: 'CommonStatisticId' = 16541 + BUFF_OBJECT_VOODOO_DOLL_LOVE: 'CommonStatisticId' = 16542 + BUFF_OBJECT_VOODOO_DOLL_PAIN: 'CommonStatisticId' = 16543 + BUFF_OBJECT_VOODOO_DOLL_UNCOMFORTABLE: 'CommonStatisticId' = 16544 + BUFF_OBJECT_WRITING_WRITERS_BLOCK: 'CommonStatisticId' = 34130 + BUFF_ON_FOREIGN_LOT: 'CommonStatisticId' = 16446 + BUFF_RELATIONSHIP_FIGHT_WIN: 'CommonStatisticId' = 16552 + BUFF_RELATIONSHIP_FIGHT_WIN_VILLAIN: 'CommonStatisticId' = 99532 + BUFF_RELATIONSHIP_LOST_FIGHT_VILLAIN: 'CommonStatisticId' = 99536 + BUFF_RELATIONSHIP_NEW_SIBLING: 'CommonStatisticId' = 97689 + BUFF_RELATIONSHIP_NEW_SIBLING_BABY: 'CommonStatisticId' = 97930 + BUFF_SERENADED: 'CommonStatisticId' = 39460 + BUFF_SERUM_FAILURES_TRACKER: 'CommonStatisticId' = 105159 + BUFF_SOCIAL_ANGRY_CONVERSATION: 'CommonStatisticId' = 10642 + BUFF_SOCIAL_AWKWARD_TURTLE: 'CommonStatisticId' = 37843 + BUFF_SOCIAL_BORING_CONVERSATION: 'CommonStatisticId' = 10645 + BUFF_SOCIAL_DULL_HUMOR: 'CommonStatisticId' = 37856 + BUFF_SOCIAL_EMBARRASSING_CONVERSATION: 'CommonStatisticId' = 10643 + BUFF_SOCIAL_FLATTERED: 'CommonStatisticId' = 37857 + BUFF_SOCIAL_FLIRTY_CONVERSATION: 'CommonStatisticId' = 10641 + BUFF_SOCIAL_HAPPY_CONVERSATION: 'CommonStatisticId' = 10644 + BUFF_SOCIAL_HOT_N_HEAVY: 'CommonStatisticId' = 37858 + BUFF_SOCIAL_MADE_A_DEEP_CONNECTION: 'CommonStatisticId' = 37948 + BUFF_SOCIAL_ON_A_ROLL: 'CommonStatisticId' = 37950 + BUFF_SOCIAL_PLAYFUL_CONVERSATION: 'CommonStatisticId' = 10640 + BUFF_STEREO_MUSIC: 'CommonStatisticId' = 96813 + BUFF_STEREO_NEW_AGE_BORED: 'CommonStatisticId' = 118098 + BUFF_STEREO_NEW_AGE_FOCUSED: 'CommonStatisticId' = 118099 + BUFF_STEREO_SUMMER_STRUT: 'CommonStatisticId' = 186227 + BUFF_STEREO_WINTER_HOLIDAY: 'CommonStatisticId' = 186234 + BUFF_TIME_IN_RESTAURANT_FLIRTY_BREAKFAST: 'CommonStatisticId' = 133606 + BUFF_TIME_IN_RESTAURANT_FLIRTY_DINNER: 'CommonStatisticId' = 133608 + BUFF_TIME_IN_RESTAURANT_FLIRTY_LUNCH: 'CommonStatisticId' = 133607 + BUFF_TIME_IN_RESTAURANT_HAPPY_BREAKFAST: 'CommonStatisticId' = 133362 + BUFF_TIME_IN_RESTAURANT_HAPPY_DINNER: 'CommonStatisticId' = 133416 + BUFF_TIME_IN_RESTAURANT_HAPPY_LUNCH: 'CommonStatisticId' = 133415 + BUFF_TODDLER_AWAKE: 'CommonStatisticId' = 154194 + BUFF_TODDLER_CAREGIVER_AWAKE: 'CommonStatisticId' = 157460 + BUFF_TRAIT_FARTISAN_KNOCK_OUT: 'CommonStatisticId' = 16570 + BUFF_TRAIT_GHOST_OLD_AGE_PET_IDLE_YOWL: 'CommonStatisticId' = 166679 + BUFF_TRAIT_SNOB_HORSESHOES_BORING: 'CommonStatisticId' = 111547 + BUFF_WEATHER_TV_CLIMATE_CHANGE: 'CommonStatisticId' = 179838 + BUSH_PET_AVAILABLE: 'CommonStatisticId' = 171519 + BUSKING_TOTAL_TIPS_TNS: 'CommonStatisticId' = 144187 + CAMPFIRE_FIRE_INTENSITY: 'CommonStatisticId' = 101759 + CAREER_ACTIVIST_PROMOTED_CAUSE_SIMS_COUNT: 'CommonStatisticId' = 135405 + CAREER_ACTIVIST_PROMOTED_POLICY_SIMS_COUNT: 'CommonStatisticId' = 135568 + CAREER_ACTIVIST_SECURED_VOTE_SIMS_COUNT: 'CommonStatisticId' = 136297 + CAREER_ACTIVIST_SIMOLEONS_RAISED_FOR_CAUSE_ALL: 'CommonStatisticId' = 135754 + CAREER_ACTIVIST_SIMOLEONS_RAISED_FOR_CAUSE_ECONOMY_STATISTIC: 'CommonStatisticId' = 135469 + CAREER_ACTIVIST_SIMOLEONS_RAISED_FOR_CAUSE_ECONOMY: 'CommonStatisticId' = 136369 + CAREER_ACTIVIST_SIMOLEONS_RAISED_FOR_CAUSE_ENVIRONMENT_STATISTIC: 'CommonStatisticId' = 135467 + CAREER_ACTIVIST_SIMOLEONS_RAISED_FOR_CAUSE_ENVIRONMENT: 'CommonStatisticId' = 136370 + CAREER_ACTIVIST_SIMOLEONS_RAISED_FOR_CAUSE_JUSTICE_STATISTIC: 'CommonStatisticId' = 135471 + CAREER_ACTIVIST_SIMOLEONS_RAISED_FOR_CAUSE_JUSTICE: 'CommonStatisticId' = 136371 + CAREER_ACTIVIST_SIMOLEONS_RAISED_FOR_CAUSE_PEACE_STATISTIC: 'CommonStatisticId' = 135470 + CAREER_ACTIVIST_SIMOLEONS_RAISED_FOR_CAUSE_PEACE: 'CommonStatisticId' = 136372 + CAREER_ACTIVIST_SIMOLEONS_RAISED_FOR_CAUSE_TAX_STATISTIC: 'CommonStatisticId' = 135468 + CAREER_ACTIVIST_SIMOLEONS_RAISED_FOR_CAUSE_TAX: 'CommonStatisticId' = 136373 + CAREER_BANK_BLUEPRINT_INSIDE_SCOOP: 'CommonStatisticId' = 33952 + CAREER_BENEFIT_ACTIVIST: 'CommonStatisticId' = 135207 + CAREER_BENEFIT_ACTIVIST_CHARITY: 'CommonStatisticId' = 151710 + CAREER_BENEFIT_ACTIVIST_POLITICIAN: 'CommonStatisticId' = 153615 + CAREER_BENEFIT_AGENT: 'CommonStatisticId' = 76229 + CAREER_BENEFIT_ASTRONAUT: 'CommonStatisticId' = 76227 + CAREER_BENEFIT_ATHLETE: 'CommonStatisticId' = 106738 + CAREER_BENEFIT_BUSINESS: 'CommonStatisticId' = 106739 + CAREER_BENEFIT_CRIMINAL: 'CommonStatisticId' = 76225 + CAREER_BENEFIT_CRITIC: 'CommonStatisticId' = 136153 + CAREER_BENEFIT_CULINARY: 'CommonStatisticId' = 76232 + CAREER_BENEFIT_DRAMA_CLUB: 'CommonStatisticId' = 199910 + CAREER_BENEFIT_ENTERTAINER: 'CommonStatisticId' = 76234 + CAREER_BENEFIT_GARDENER: 'CommonStatisticId' = 186189 + CAREER_BENEFIT_PAINTER: 'CommonStatisticId' = 76236 + CAREER_BENEFIT_SCOUTING: 'CommonStatisticId' = 187002 + CAREER_BENEFIT_SOCIAL_MEDIA: 'CommonStatisticId' = 135396 + CAREER_BENEFIT_STYLE_INFLUENCER: 'CommonStatisticId' = 193215 + CAREER_BENEFIT_TECH: 'CommonStatisticId' = 76237 + CAREER_BENEFIT_WRITER: 'CommonStatisticId' = 76238 + CAREER_CHILD_NEGLECT: 'CommonStatisticId' = 98946 + CAREER_DETECTIVE_ANALYZE_CLUE_HANDICAP: 'CommonStatisticId' = 115370 + CAREER_DETECTIVE_ARRESTED_SUSPECT: 'CommonStatisticId' = 112060 + CAREER_DETECTIVE_CASES_SOLVED: 'CommonStatisticId' = 111452 + CAREER_DETECTIVE_DEBUG_EVENT_SELECTED: 'CommonStatisticId' = 112734 + CAREER_DETECTIVE_HAS_CASE: 'CommonStatisticId' = 112059 + CAREER_DETECTIVE_INTERROGATION_AT100: 'CommonStatisticId' = 116463 + CAREER_DETECTIVE_ON_PATROL_TIMER: 'CommonStatisticId' = 116389 + CAREER_DETECTIVE_SINGLE_DAY_GOAL_TRACKING_CITATIONS: 'CommonStatisticId' = 116375 + CAREER_DETECTIVE_SINGLE_DAY_GOAL_TRACKING_CRIME_PICS: 'CommonStatisticId' = 116378 + CAREER_DETECTIVE_SINGLE_DAY_GOAL_TRACKING_EVIDENCE_COLLECTED: 'CommonStatisticId' = 116377 + CAREER_DETECTIVE_SINGLE_DAY_GOAL_TRACKING_SOCIAL_CIV: 'CommonStatisticId' = 116376 + CAREER_DETECTIVE_SINGLE_DAY_GOAL_TRACKING_WITNESS_REPORTS: 'CommonStatisticId' = 116379 + CAREER_DIVERT_FUNDS_COOLDOWN: 'CommonStatisticId' = 36961 + CAREER_HACK_PAYOUT_MULTIPLIER: 'CommonStatisticId' = 33981 + CAREER_HOMEWORK: 'CommonStatisticId' = 16571 + CAREER_HOMEWORK_EXTRA_CREDIT: 'CommonStatisticId' = 33900 + CAREER_HOMEWORK_MAKEUP: 'CommonStatisticId' = 33899 + CAREER_INSTANT_BACKGROUND_CHECK_COOLDOWN: 'CommonStatisticId' = 34735 + CAREER_INTELLIGENCE_DB_WORK_PERF: 'CommonStatisticId' = 34167 + CAREER_INVESTIGATE_SIM_COOLDOWN: 'CommonStatisticId' = 34203 + CAREER_PAINTER_AGENT: 'CommonStatisticId' = 30738 + CAREER_PERFORMANCE: 'CommonStatisticId' = 16662 + CAREER_PERFORMANCE_ACTIVIST: 'CommonStatisticId' = 141770 + CAREER_PERFORMANCE_ACTOR: 'CommonStatisticId' = 196749 + CAREER_PERFORMANCE_ASTRONAUT: 'CommonStatisticId' = 24170 + CAREER_PERFORMANCE_ATHLETE: 'CommonStatisticId' = 106741 + CAREER_PERFORMANCE_BUSINESS: 'CommonStatisticId' = 106742 + CAREER_PERFORMANCE_CRIMINAL: 'CommonStatisticId' = 27782 + CAREER_PERFORMANCE_CRITIC: 'CommonStatisticId' = 136181 + CAREER_PERFORMANCE_CULINARY: 'CommonStatisticId' = 24167 + CAREER_PERFORMANCE_DETECTIVE: 'CommonStatisticId' = 108581 + CAREER_PERFORMANCE_DOCTOR: 'CommonStatisticId' = 108718 + CAREER_PERFORMANCE_DRAMA_CLUB: 'CommonStatisticId' = 199905 + CAREER_PERFORMANCE_ENTERTAINER: 'CommonStatisticId' = 27781 + CAREER_PERFORMANCE_GARDENER: 'CommonStatisticId' = 186187 + CAREER_PERFORMANCE_GRADE_SCHOOL: 'CommonStatisticId' = 24169 + CAREER_PERFORMANCE_HIGHSCHOOL: 'CommonStatisticId' = 24168 + CAREER_PERFORMANCE_MILITARY: 'CommonStatisticId' = 202507 + CAREER_PERFORMANCE_PAINTER: 'CommonStatisticId' = 27786 + CAREER_PERFORMANCE_SCIENTIST: 'CommonStatisticId' = 108717 + CAREER_PERFORMANCE_SECRET_AGENT: 'CommonStatisticId' = 27780 + CAREER_PERFORMANCE_SOCIAL_MEDIA: 'CommonStatisticId' = 135394 + CAREER_PERFORMANCE_STYLE_INFLUENCER: 'CommonStatisticId' = 193216 + CAREER_PERFORMANCE_TECH_GURU: 'CommonStatisticId' = 27783 + CAREER_PERFORMANCE_TEEN_BABYSITTER: 'CommonStatisticId' = 35169 + CAREER_PERFORMANCE_TEEN_BARISTA: 'CommonStatisticId' = 35168 + CAREER_PERFORMANCE_TEEN_FAST_FOOD: 'CommonStatisticId' = 35165 + CAREER_PERFORMANCE_TEEN_MANUAL_LABOR: 'CommonStatisticId' = 35166 + CAREER_PERFORMANCE_TEEN_RETAIL: 'CommonStatisticId' = 35167 + CAREER_PERFORMANCE_VOLUNTEER_SCOUTING: 'CommonStatisticId' = 186592 + CAREER_PERFORMANCE_WRITER: 'CommonStatisticId' = 27784 + CAREER_PICKPOCKET_COOLDOWN: 'CommonStatisticId' = 36960 + CAREER_SCIENTIST_BREAKTHROUGH_LEVEL: 'CommonStatisticId' = 114887 + CAREER_SCIENTIST_BREAKTHROUGH_PROGRESS: 'CommonStatisticId' = 108216 + CAREER_SCIENTIST_INVENT_ALIEN_PORTAL: 'CommonStatisticId' = 115207 + CAREER_SCIENTIST_INVENT_CLONING_MACHINE: 'CommonStatisticId' = 115208 + CAREER_SCIENTIST_INVENT_HOVER_LAMP: 'CommonStatisticId' = 115205 + CAREER_SCIENTIST_INVENT_MOMENTUM_CONSERVER: 'CommonStatisticId' = 115204 + CAREER_SCIENTIST_INVENT_SATELLITE_DISH: 'CommonStatisticId' = 115203 + CAREER_SCIENTIST_INVENT_SIM_RAY: 'CommonStatisticId' = 115206 + CAREER_SCIENTIST_INVENTING: 'CommonStatisticId' = 113011 + CAREER_SCIENTIST_SITUATION_GOAL_CHAIN_BREAKTHROUGH_10: 'CommonStatisticId' = 112767 + CAREER_SCIENTIST_SITUATION_GOAL_CHAIN_BREAKTHROUGH_11: 'CommonStatisticId' = 112768 + CAREER_SCIENTIST_SITUATION_GOAL_CHAIN_BREAKTHROUGH_12: 'CommonStatisticId' = 112769 + CAREER_SCIENTIST_SITUATION_GOAL_CHAIN_BREAKTHROUGH_13: 'CommonStatisticId' = 112770 + CAREER_SCIENTIST_SITUATION_GOAL_CHAIN_BREAKTHROUGH_14: 'CommonStatisticId' = 112771 + CAREER_SCIENTIST_SITUATION_GOAL_CHAIN_BREAKTHROUGH_15: 'CommonStatisticId' = 112772 + CAREER_SCIENTIST_SITUATION_GOAL_CHAIN_BREAKTHROUGH_16: 'CommonStatisticId' = 112773 + CAREER_SCIENTIST_SITUATION_GOAL_CHAIN_BREAKTHROUGH_17: 'CommonStatisticId' = 112774 + CAREER_SCIENTIST_SITUATION_GOAL_CHAIN_BREAKTHROUGH_18: 'CommonStatisticId' = 112775 + CAREER_SCIENTIST_SITUATION_GOAL_CHAIN_BREAKTHROUGH_19: 'CommonStatisticId' = 112776 + CAREER_SCIENTIST_SITUATION_GOAL_CHAIN_BREAKTHROUGH_1: 'CommonStatisticId' = 112715 + CAREER_SCIENTIST_SITUATION_GOAL_CHAIN_BREAKTHROUGH_20: 'CommonStatisticId' = 112817 + CAREER_SCIENTIST_SITUATION_GOAL_CHAIN_BREAKTHROUGH_21: 'CommonStatisticId' = 112758 + CAREER_SCIENTIST_SITUATION_GOAL_CHAIN_BREAKTHROUGH_2: 'CommonStatisticId' = 112759 + CAREER_SCIENTIST_SITUATION_GOAL_CHAIN_BREAKTHROUGH_3: 'CommonStatisticId' = 112760 + CAREER_SCIENTIST_SITUATION_GOAL_CHAIN_BREAKTHROUGH_4: 'CommonStatisticId' = 112761 + CAREER_SCIENTIST_SITUATION_GOAL_CHAIN_BREAKTHROUGH_5: 'CommonStatisticId' = 112762 + CAREER_SCIENTIST_SITUATION_GOAL_CHAIN_BREAKTHROUGH_6: 'CommonStatisticId' = 112763 + CAREER_SCIENTIST_SITUATION_GOAL_CHAIN_BREAKTHROUGH_7: 'CommonStatisticId' = 112764 + CAREER_SCIENTIST_SITUATION_GOAL_CHAIN_BREAKTHROUGH_8: 'CommonStatisticId' = 112765 + CAREER_SCIENTIST_SITUATION_GOAL_CHAIN_BREAKTHROUGH_9: 'CommonStatisticId' = 112766 + CAREER_SCIENTIST_UPGRADE_CLONE_SIM: 'CommonStatisticId' = 113556 + CAREER_SCIENTIST_UPGRADE_DETECT_ALIENS: 'CommonStatisticId' = 113555 + CAREER_SCIENTIST_UPGRADE_MIND_CONTROL_CHANGE_CLOTHES: 'CommonStatisticId' = 113336 + CAREER_SCIENTIST_UPGRADE_MIND_CONTROL_CLEAN: 'CommonStatisticId' = 113333 + CAREER_SCIENTIST_UPGRADE_MIND_CONTROL_EAT: 'CommonStatisticId' = 113335 + CAREER_SCIENTIST_UPGRADE_MIND_CONTROL_PANIC: 'CommonStatisticId' = 113339 + CAREER_SCIENTIST_UPGRADE_MIND_CONTROL_SIT: 'CommonStatisticId' = 113338 + CAREER_SCIENTIST_UPGRADE_MIND_CONTROL_SLEEP: 'CommonStatisticId' = 113337 + CAREER_SCIENTIST_UPGRADE_TRANSFORM: 'CommonStatisticId' = 113247 + CAREER_SCIENTIST_UPGRADE_TRANSFORM_SIM: 'CommonStatisticId' = 113299 + CAREER_SCIENTIST_UPGRADE_TRAVEL_ALIEN_WORLD: 'CommonStatisticId' = 113557 + CAREER_SCOUTING_BADGES_COLLECTED: 'CommonStatisticId' = 187093 + CAREER_SESSION_PERFORMANCE_CHANGE: 'CommonStatisticId' = 99886 + CAREER_SOCIAL_MEDIA_FOLLOWERS_LOST_GAINED_TNS_TOTAL: 'CommonStatisticId' = 143928 + CAREER_SOCIAL_MEDIA_PROFIT_GAINED_TNS_TOTAL: 'CommonStatisticId' = 143927 + CAREER_SOCIAL_MEDIA_PUBLIC_RELATIONS_REPRESENT: 'CommonStatisticId' = 145911 + CAREER_TECH_GURU_FREELANCE_MULTIPLIER: 'CommonStatisticId' = 34384 + CAREER_TONE_PERFORMANCE: 'CommonStatisticId' = 75576 + CAT_COLD_WEATHER_GET_WARM: 'CommonStatisticId' = 185585 + CAT_HOT_WEATHER_LAZE: 'CommonStatisticId' = 183616 + CHALET_GARDENS_WANDER_MAZE_COOLDOWN: 'CommonStatisticId' = 126322 + CHEF_STATION_IN_USE: 'CommonStatisticId' = 156196 + CHEF_STATION_ORDER_COUNT: 'CommonStatisticId' = 131251 + CHILDHOOD_PHASE: 'CommonStatisticId' = 164773 + COLLECT_AFTER_EATING_TIMER: 'CommonStatisticId' = 74875 + COLLECT_SPORE_GLOW: 'CommonStatisticId' = 205802 + COLLECTABLE_ROCK_DECAY: 'CommonStatisticId' = 77481 + COLLECTION_CITY_LIFE_POWER_BOX_POSTERS_SPAWN_TIMER: 'CommonStatisticId' = 143929 + COLLECTION_SPAWN_GROUND_OBJECT: 'CommonStatisticId' = 16572 + COLLECTION_SPAWN_SLOT_OBJECT: 'CommonStatisticId' = 16573 + COMEDY_SKILL_PERFORMANCE_PAYOUT: 'CommonStatisticId' = 31619 + COMEDY_SKILL_PRACTICE_ROUTINE: 'CommonStatisticId' = 30481 + CRAFT_SALES_TABLE_CREATE_OBJECT: 'CommonStatisticId' = 147957 + CRAFTING_PROGRESS: 'CommonStatisticId' = 16574 + CRIME_MAP_ANALYZE_COOLDOWN: 'CommonStatisticId' = 107612 + CULLING_GHOST: 'CommonStatisticId' = 161328 + CULTURAL_FOOD_RECIPE_UNLOCKS: 'CommonStatisticId' = 137036 + CURIOUS_TRAIT_SEARCH_COUNT: 'CommonStatisticId' = 172155 + CURSES_ANCIENT_SICKNESS_CONTAGIOUS_COMMON: 'CommonStatisticId' = 175025 + CURSES_ANCIENT_SICKNESS_CONTAGIOUS_RARE: 'CommonStatisticId' = 175029 + CURSES_ANCIENT_SICKNESS_CONTAGIOUS_UNCOMMON: 'CommonStatisticId' = 175030 + CURSES_SEEING_THINGS_DISPEL_COUNTER: 'CommonStatisticId' = 175277 + DANCE_BATTLE_SCORE: 'CommonStatisticId' = 128954 + DEATH_ELDER_EXHAUSTION: 'CommonStatisticId' = 9451 + DEATH_ELDER_EXHAUSTION_TRACKER: 'CommonStatisticId' = 9450 + DEATH_ELECTROCUTION: 'CommonStatisticId' = 8938 + DEATH_ELECTROCUTION_TRACKER: 'CommonStatisticId' = 8935 + DEATH_PUFFER_FISH: 'CommonStatisticId' = 135086 + DEATH_TEMPERATURE_BURNING: 'CommonStatisticId' = 182175 + DEATH_TEMPERATURE_FREEZING: 'CommonStatisticId' = 182176 + DENIZEN_POND_CLEANING: 'CommonStatisticId' = 194428 + DENIZEN_POND_DIRTINESS: 'CommonStatisticId' = 200850 + DENIZEN_POND_FEEDING: 'CommonStatisticId' = 196544 + DENIZEN_POND_HUNGER: 'CommonStatisticId' = 192251 + DIRT_MOUND_AVAILABILITY: 'CommonStatisticId' = 173092 + DIRT_MOUND_DUG: 'CommonStatisticId' = 172107 + DIRTINESS: 'CommonStatisticId' = 16575 + DISCIPLINE_CAT_JUMP_ON_COUNTERS: 'CommonStatisticId' = 170719 + DISCIPLINE_CAT_SCRATCHING: 'CommonStatisticId' = 162259 + DISCIPLINE_DOG_BARK: 'CommonStatisticId' = 165941 + DISCIPLINE_DOG_EAT_POOP: 'CommonStatisticId' = 168488 + DISCIPLINE_DOG_JUMP_ON_COUNTERS: 'CommonStatisticId' = 170720 + DISCIPLINE_DOG_PUDDLES_PLAY: 'CommonStatisticId' = 162273 + DISCIPLINE_DOG_TOILET: 'CommonStatisticId' = 162261 + DISCIPLINE_FREQUENCY_CAT_JUMP_ON_COUNTERS: 'CommonStatisticId' = 177148 + DISCIPLINE_FREQUENCY_CAT_SCRATCHING: 'CommonStatisticId' = 177149 + DISCIPLINE_FREQUENCY_DOG_BARK: 'CommonStatisticId' = 177150 + DISCIPLINE_FREQUENCY_DOG_CHASE: 'CommonStatisticId' = 177151 + DISCIPLINE_FREQUENCY_DOG_EAT_POOP: 'CommonStatisticId' = 177153 + DISCIPLINE_FREQUENCY_DOG_JUMP_ON_COUNTERS: 'CommonStatisticId' = 177154 + DISCIPLINE_FREQUENCY_DOG_PUDDLES_PLAY: 'CommonStatisticId' = 177155 + DISCIPLINE_FREQUENCY_DOG_TOILET: 'CommonStatisticId' = 177156 + DISCIPLINE_FREQUENCY_PET_ATTACK: 'CommonStatisticId' = 177157 + DISCIPLINE_FREQUENCY_PET_BAT_KNOCK_TRASH: 'CommonStatisticId' = 177158 + DISCIPLINE_FREQUENCY_PET_BEG_EATING: 'CommonStatisticId' = 177159 + DISCIPLINE_FREQUENCY_PET_EAT_PEOPLE_FOOD: 'CommonStatisticId' = 177160 + DISCIPLINE_FREQUENCY_PET_POTTY_TRAINING: 'CommonStatisticId' = 177161 + DISCIPLINE_FREQUENCY_PET_PUDDLES_DRINK: 'CommonStatisticId' = 177162 + DISCIPLINE_FREQUENCY_PET_TRASH_EAT: 'CommonStatisticId' = 177163 + DISCIPLINE_FREQUENCY_PET_TRASH_PLAY: 'CommonStatisticId' = 177164 + DISCIPLINE_FREQUENCY_PET_TRASH_RUMMAGE: 'CommonStatisticId' = 177165 + DISCIPLINE_FREQUENCY_PET_WAKE_UP_SIMS: 'CommonStatisticId' = 177166 + DISCIPLINE_NEED_CAT_JUMP_ON_COUNTERS: 'CommonStatisticId' = 170723 + DISCIPLINE_NEED_CAT_SCRATCHING: 'CommonStatisticId' = 163620 + DISCIPLINE_NEED_DOG_BARK: 'CommonStatisticId' = 168560 + DISCIPLINE_NEED_DOG_CHASE: 'CommonStatisticId' = 163625 + DISCIPLINE_NEED_DOG_EAT_POOP: 'CommonStatisticId' = 168489 + DISCIPLINE_NEED_DOG_JUMP_ON_COUNTERS: 'CommonStatisticId' = 170724 + DISCIPLINE_NEED_DOG_PUDDLES_PLAY: 'CommonStatisticId' = 163629 + DISCIPLINE_NEED_DOG_TOILET: 'CommonStatisticId' = 163630 + DISCIPLINE_NEED_PET_ATTACK: 'CommonStatisticId' = 163631 + DISCIPLINE_NEED_PET_BAT_KNOCK_TRASH: 'CommonStatisticId' = 163731 + DISCIPLINE_NEED_PET_BEG_EATING: 'CommonStatisticId' = 163632 + DISCIPLINE_NEED_PET_EAT_PEOPLE_FOOD: 'CommonStatisticId' = 170722 + DISCIPLINE_NEED_PET_POTTY_TRAINING: 'CommonStatisticId' = 163628 + DISCIPLINE_NEED_PET_PUDDLES_DRINK: 'CommonStatisticId' = 163635 + DISCIPLINE_NEED_PET_TRASH_EAT: 'CommonStatisticId' = 163636 + DISCIPLINE_NEED_PET_TRASH_PLAY: 'CommonStatisticId' = 163637 + DISCIPLINE_NEED_PET_TRASH_RUMMAGE: 'CommonStatisticId' = 163752 + DISCIPLINE_NEED_PET_WAKE_UP_SIMS: 'CommonStatisticId' = 170721 + DISCIPLINE_PET_ATTACK: 'CommonStatisticId' = 162272 + DISCIPLINE_PET_BEG_EATING: 'CommonStatisticId' = 162269 + DISCIPLINE_PET_CHASE: 'CommonStatisticId' = 162263 + DISCIPLINE_PET_EAT_PEOPLE_FOOD: 'CommonStatisticId' = 170717 + DISCIPLINE_PET_POTTY_TRAINING: 'CommonStatisticId' = 162264 + DISCIPLINE_PET_PUDDLES_DRINK: 'CommonStatisticId' = 162265 + DISCIPLINE_PET_TRASH_EAT: 'CommonStatisticId' = 162266 + DISCIPLINE_PET_TRASH_PLAY: 'CommonStatisticId' = 162267 + DISCIPLINE_PET_WAKE_UP_SIMS: 'CommonStatisticId' = 170718 + DOCTOR_CAREER_WORKED_HOURS: 'CommonStatisticId' = 112129 + DOCTOR_PLAY_SET_TOTAL_PLAYTIME: 'CommonStatisticId' = 168522 + DOG_HOT_WEATHER_PANT: 'CommonStatisticId' = 183492 + DOG_SNOWING_RUN: 'CommonStatisticId' = 184225 + DOG_TRAINING_FETCH: 'CommonStatisticId' = 161288 + DOG_TRAINING_HEEL: 'CommonStatisticId' = 161283 + DOG_TRAINING_LIE_DOWN: 'CommonStatisticId' = 161287 + DOG_TRAINING_PLAY_DEAD: 'CommonStatisticId' = 161289 + DOG_TRAINING_ROLL_OVER: 'CommonStatisticId' = 161285 + DOG_TRAINING_SHAKE: 'CommonStatisticId' = 161290 + DOG_TRAINING_SHOW_OFF_TRICKS: 'CommonStatisticId' = 170020 + DOG_TRAINING_SIT: 'CommonStatisticId' = 161284 + DOG_TRAINING_SPEAK: 'CommonStatisticId' = 161286 + DOG_WALK_DOG_TIMER: 'CommonStatisticId' = 166678 + DOLLHOUSE_SMASHED: 'CommonStatisticId' = 35314 + DYNAMIC_SIGN_TIMER: 'CommonStatisticId' = 133263 + EMOTION_AUTONOMY_ANGRY: 'CommonStatisticId' = 16455 + EMOTION_AUTONOMY_ASLEEP: 'CommonStatisticId' = 27146 + EMOTION_AUTONOMY_BORED: 'CommonStatisticId' = 16456 + EMOTION_AUTONOMY_CONFIDENT: 'CommonStatisticId' = 16457 + EMOTION_AUTONOMY_DAZED: 'CommonStatisticId' = 16470 + EMOTION_AUTONOMY_EMBARRASSED: 'CommonStatisticId' = 16462 + EMOTION_AUTONOMY_ENERGIZED: 'CommonStatisticId' = 16463 + EMOTION_AUTONOMY_FLIRTY: 'CommonStatisticId' = 16464 + EMOTION_AUTONOMY_FOCUSED: 'CommonStatisticId' = 16465 + EMOTION_AUTONOMY_HAPPY: 'CommonStatisticId' = 16466 + EMOTION_AUTONOMY_INSPIRED: 'CommonStatisticId' = 16467 + EMOTION_AUTONOMY_PLAYFUL: 'CommonStatisticId' = 16468 + EMOTION_AUTONOMY_POSSESSED: 'CommonStatisticId' = 202880 + EMOTION_AUTONOMY_SAD: 'CommonStatisticId' = 16469 + EMOTION_AUTONOMY_STRESSED: 'CommonStatisticId' = 16471 + EMOTION_AUTONOMY_UNCOMFORTABLE: 'CommonStatisticId' = 16472 + EMOTION_PETS_ANGRY_DOG: 'CommonStatisticId' = 158224 + EMOTION_PETS_ANXIOUS_DOG: 'CommonStatisticId' = 158223 + EMOTION_PETS_ASHAMED_DOG: 'CommonStatisticId' = 158230 + EMOTION_PETS_ASLEEP_DOG: 'CommonStatisticId' = 158229 + EMOTION_PETS_AUTONOMY_HYPER: 'CommonStatisticId' = 157907 + EMOTION_PETS_CATS_AUTONOMY_ANGRY: 'CommonStatisticId' = 158406 + EMOTION_PETS_CATS_AUTONOMY_ANXIOUS: 'CommonStatisticId' = 158189 + EMOTION_PETS_CATS_AUTONOMY_ASLEEP: 'CommonStatisticId' = 158551 + EMOTION_PETS_CATS_AUTONOMY_DROWSY: 'CommonStatisticId' = 158142 + EMOTION_PETS_CATS_AUTONOMY_FLIRTY: 'CommonStatisticId' = 158408 + EMOTION_PETS_CATS_AUTONOMY_HAPPY: 'CommonStatisticId' = 158410 + EMOTION_PETS_CATS_AUTONOMY_SCARED: 'CommonStatisticId' = 158409 + EMOTION_PETS_EXCITED_DOG: 'CommonStatisticId' = 158220 + EMOTION_PETS_FLIRTY_DOG: 'CommonStatisticId' = 158226 + EMOTION_PETS_HAPPY_DOG: 'CommonStatisticId' = 158228 + EMOTION_PETS_MOPEY_DOG: 'CommonStatisticId' = 158222 + EMOTION_PETS_SAD_DOG: 'CommonStatisticId' = 158221 + EMOTION_PETS_SCARED_DOG: 'CommonStatisticId' = 158227 + ENVIRONMENT_ANGRY: 'CommonStatisticId' = 16576 + ENVIRONMENT_ASLEEP: 'CommonStatisticId' = 99396 + ENVIRONMENT_BORED: 'CommonStatisticId' = 16577 + ENVIRONMENT_CONFIDENT: 'CommonStatisticId' = 16578 + ENVIRONMENT_DAZED: 'CommonStatisticId' = 99395 + ENVIRONMENT_DROWSY_PETS: 'CommonStatisticId' = 158141 + ENVIRONMENT_EMBARRASSED: 'CommonStatisticId' = 16579 + ENVIRONMENT_ENERGIZED: 'CommonStatisticId' = 16580 + ENVIRONMENT_FINE: 'CommonStatisticId' = 99397 + ENVIRONMENT_FLIRTY: 'CommonStatisticId' = 16581 + ENVIRONMENT_FOCUSED: 'CommonStatisticId' = 16582 + ENVIRONMENT_HAPPY: 'CommonStatisticId' = 16583 + ENVIRONMENT_HYPER_PETS: 'CommonStatisticId' = 157870 + ENVIRONMENT_IMAGINATIVE: 'CommonStatisticId' = 16584 + ENVIRONMENT_NEGATIVE: 'CommonStatisticId' = 16585 + ENVIRONMENT_PETS_ANXIOUS: 'CommonStatisticId' = 158190 + ENVIRONMENT_PLAYFUL: 'CommonStatisticId' = 16586 + ENVIRONMENT_POSITIVE: 'CommonStatisticId' = 97781 + ENVIRONMENT_POSSESSED: 'CommonStatisticId' = 201541 + ENVIRONMENT_SAD: 'CommonStatisticId' = 16587 + ENVIRONMENT_TENSE: 'CommonStatisticId' = 16588 + ENVIRONMENT_UNCOMFORTABLE: 'CommonStatisticId' = 99394 + EXCAVATION_PILE_PROGRESS: 'CommonStatisticId' = 177105 + FAME_PERK_BRAND_ALL_NIGHTER_CHARITY_STREAM: 'CommonStatisticId' = 196060 + FAME_PERK_BRAND_ALL_NIGHTER_CHARITY_STREAM_CANCELLATION: 'CommonStatisticId' = 196090 + FAME_PERK_BRAND_ALL_NIGHTER_CHARITY_STREAM_FAME_PAYOUT: 'CommonStatisticId' = 198519 + FAME_PERK_CAREER_HOPPER_MULTIPLIER: 'CommonStatisticId' = 195757 + FAME_PERK_SQUAD_MEMBER_AUTONOMY: 'CommonStatisticId' = 201645 + FAME_PERKS_INFLUENCER_GIFT_DELIVERY: 'CommonStatisticId' = 194664 + FAME_QUIRK_A_SERIOUS_ACTOR_ANGER: 'CommonStatisticId' = 195906 + FAME_QUIRK_BRUSHES_WITH_FAME_TOUCH_METER: 'CommonStatisticId' = 194072 + FAME_QUIRK_EMOTION_BOMB_ANGER: 'CommonStatisticId' = 200818 + FAME_QUIRK_EMOTION_BOMB_SADNESS: 'CommonStatisticId' = 200819 + FAME_QUIRK_NO_TOUCHING_TOUCH_METER: 'CommonStatisticId' = 194071 + FAME_QUIRK_PHONE_FANATIC: 'CommonStatisticId' = 191706 + FAME_QUIRK_VAIN_STREET_VAIN_METER: 'CommonStatisticId' = 195986 + FAME_QUIRKS_FAN_MAIL_GIFT_DELIVERY: 'CommonStatisticId' = 195790 + FAME_QUIRKS_JUICE_ENTHUSIAST_CHILD: 'CommonStatisticId' = 196278 + FAME_QUIRKS_JUICE_ENTHUSIAST_TYAE: 'CommonStatisticId' = 196262 + FAME_WORLD_TAKE_PHOTO_NO_ATTRACTOR: 'CommonStatisticId' = 201140 + FESTIVAL_BLOSSOM_DRINK_TEA: 'CommonStatisticId' = 150594 + FESTIVAL_BLOSSOM_VIEW_PLANTS: 'CommonStatisticId' = 143730 + FESTIVAL_DARK_SIDER_DRINK_TEA: 'CommonStatisticId' = 135530 + FESTIVAL_FIREWORKS_FIREWORK_DISPLAY_TIMER: 'CommonStatisticId' = 135874 + FESTIVAL_FIREWORKS_FIREWORK_INDOOR_EXPLOSION: 'CommonStatisticId' = 142083 + FESTIVAL_FIREWORKS_FUSE_TIMER: 'CommonStatisticId' = 135047 + FESTIVAL_FIREWORKS_FUSE_TIMER_DUD: 'CommonStatisticId' = 135831 + FESTIVAL_FIREWORKS_FUSE_TIMER_INDOORS: 'CommonStatisticId' = 142073 + FESTIVAL_FIREWORKS_FUSE_TIMER_NEIGHBOR: 'CommonStatisticId' = 150515 + FESTIVAL_FIREWORKS_FUSE_TIMER_QUICK: 'CommonStatisticId' = 135830 + FESTIVAL_FIREWORKS_REPEATER_RESET_TIMER: 'CommonStatisticId' = 140909 + FESTIVAL_FIREWORKS_SPARKLER_TIMER: 'CommonStatisticId' = 143690 + FESTIVAL_FIREWORKS_SPENT_TIMER: 'CommonStatisticId' = 142168 + FESTIVAL_FIREWORKS_WATCHING: 'CommonStatisticId' = 150511 + FESTIVAL_FLEA_MARKET_HAGGLER: 'CommonStatisticId' = 142222 + FESTIVAL_GENERAL_EAT_FOOD: 'CommonStatisticId' = 134829 + FESTIVAL_LIGHT_SIDER_DRINK_TEA: 'CommonStatisticId' = 135529 + FESTIVAL_NPC_BUFF_TIMERS: 'CommonStatisticId' = 149281 + FESTIVAL_NPC_BUFF_TIMERS_AT_FESTIVAL: 'CommonStatisticId' = 149282 + FESTIVAL_PLAYER_BUFF_TIMERS_AT_FESTIVAL_BLOSSOM: 'CommonStatisticId' = 144007 + FESTIVAL_PLAYER_BUFF_TIMERS_AT_FESTIVAL_FLEA_MARKET: 'CommonStatisticId' = 144008 + FESTIVAL_PLAYER_BUFF_TIMERS_AT_FESTIVAL_FOOD: 'CommonStatisticId' = 144009 + FESTIVAL_PLAYER_BUFF_TIMERS_AT_FESTIVAL_LAMP: 'CommonStatisticId' = 144010 + FESTIVAL_PLAYER_BUFF_TIMERS_AT_FESTIVAL_LOGIC: 'CommonStatisticId' = 143990 + FESTIVAL_PLAYER_BUFF_TIMERS_BLOSSOM: 'CommonStatisticId' = 144004 + FESTIVAL_PLAYER_BUFF_TIMERS_FLEA_MARKET: 'CommonStatisticId' = 144005 + FESTIVAL_PLAYER_BUFF_TIMERS_FOOD: 'CommonStatisticId' = 144003 + FESTIVAL_PLAYER_BUFF_TIMERS_LAMP: 'CommonStatisticId' = 144006 + FESTIVAL_PLAYER_BUFF_TIMERS_LOGIC: 'CommonStatisticId' = 143789 + FESTIVAL_WATCH_INTERACTIONS: 'CommonStatisticId' = 136205 + FESTIVALS_HACK_THE_PLANET_SCORE: 'CommonStatisticId' = 141090 + FESTIVALS_UGT_GAME_COUNT_ADVENTURE: 'CommonStatisticId' = 141685 + FESTIVALS_UGT_GAME_COUNT_FAMILY: 'CommonStatisticId' = 141687 + FESTIVALS_UGT_GAME_COUNT_PUZZLE: 'CommonStatisticId' = 141686 + FESTIVALS_UGT_GAME_COUNT_SPORTS: 'CommonStatisticId' = 141688 + FESTIVALS_UGT_GAME_COUNT_TOTAL: 'CommonStatisticId' = 141735 + FESTIVALS_UGT_PLAYER_SCORE_ADVENTURE: 'CommonStatisticId' = 141690 + FESTIVALS_UGT_PLAYER_SCORE_FAMILY: 'CommonStatisticId' = 141693 + FESTIVALS_UGT_PLAYER_SCORE_PUZZLE: 'CommonStatisticId' = 141692 + FESTIVALS_UGT_PLAYER_SCORE_SPORTS: 'CommonStatisticId' = 141691 + FESTIVALS_UGT_SCORE: 'CommonStatisticId' = 141046 + FISH_FRESHNESS: 'CommonStatisticId' = 77040 + FISHING_FAIL_AT_FISHING: 'CommonStatisticId' = 76386 + FISHING_LOCATION_RECENTLY_EXAMINED: 'CommonStatisticId' = 76365 + FISHING_NEED_TO_CAST: 'CommonStatisticId' = 74423 + FISHING_WEIGHT: 'CommonStatisticId' = 76023 + FITNESS_FAT: 'CommonStatisticId' = 16589 + FITNESS_FIT: 'CommonStatisticId' = 16590 + FLOWER_ARRANGEMENT_BEGONIA_CURSED_EFFECTS: 'CommonStatisticId' = 188243 + FLOWER_ARRANGEMENT_SCENT_CROCUS: 'CommonStatisticId' = 186913 + FLOWER_ARRANGEMENT_SCENT_LILY_LIFE_ESSENCE: 'CommonStatisticId' = 188710 + FLOWER_ARRANGEMENT_TULIP_FAITHFUL_EFFECTS: 'CommonStatisticId' = 188190 + FLOWER_ARRANGEMENT_WILTING: 'CommonStatisticId' = 186915 + FLOWER_BUNNY_PLACED_FLOWER_NEARBY: 'CommonStatisticId' = 187682 + FLOWER_DROP_COUNTER: 'CommonStatisticId' = 187473 + FOOD_POISONING: 'CommonStatisticId' = 131883 + FRESHNESS: 'CommonStatisticId' = 16591 + FROGS_FROG_BREEDING_COOLDOWN_FOR_SIM: 'CommonStatisticId' = 98396 + FRUIT_PUNCH_FOUNTAIN_SERVINGS: 'CommonStatisticId' = 116834 + GAME_FOREVER: 'CommonStatisticId' = 38997 + GARDENING_AGGREGATE: 'CommonStatisticId' = 8776 + GARDENING_DECAY: 'CommonStatisticId' = 16592 + GARDENING_EVOLUTION: 'CommonStatisticId' = 39327 + GARDENING_EXPIRATION: 'CommonStatisticId' = 16593 + GARDENING_FERTILIZER: 'CommonStatisticId' = 16594 + GARDENING_FERTILIZER_B: 'CommonStatisticId' = 16595 + GARDENING_FERTILIZER_C: 'CommonStatisticId' = 16596 + GARDENING_FRUIT_DECAY: 'CommonStatisticId' = 16597 + GARDENING_FRUIT_SIZE: 'CommonStatisticId' = 16598 + GARDENING_GERMINATION: 'CommonStatisticId' = 16599 + GARDENING_GROWTH: 'CommonStatisticId' = 16600 + GARDENING_INFESTATION: 'CommonStatisticId' = 16601 + GARDENING_MOISTURE: 'CommonStatisticId' = 16602 + GARDENING_TEMPLE: 'CommonStatisticId' = 179472 + GARDENING_WEEDS: 'CommonStatisticId' = 16603 + GARLIC_BRAID_GARLIC_LEVEL: 'CommonStatisticId' = 151174 + GENDER_PREFERENCE_FEMALE: 'CommonStatisticId' = 16663 + GENDER_PREFERENCE_MALE: 'CommonStatisticId' = 16664 + GIVE_ROMANTIC_GIFT_AUTONOMY: 'CommonStatisticId' = 186035 + GLOAT: 'CommonStatisticId' = 34085 + GO_FOR_WALK_DOG_BEHAVIOR: 'CommonStatisticId' = 166364 + GO_FOR_WALK_SIM_BEHAVIOR: 'CommonStatisticId' = 166218 + GRILLED_CHEESE_ASPIRATION_GRILLED_CHEESE_ATE: 'CommonStatisticId' = 132369 + GRIM_REAPER_DEATH_COUNT: 'CommonStatisticId' = 16665 + GROUP_STORY_WAITING: 'CommonStatisticId' = 110879 + HAIR_MAKE_UP_CHAIR_WARDROBE_PEDESTAL_LOOP_COUNT: 'CommonStatisticId' = 189981 + HAVE_BABY_AT_HOSPITAL_LEAVE: 'CommonStatisticId' = 116653 + HOLDING_CELL_CAPACITY: 'CommonStatisticId' = 105310 + HOLIDAY_TREE_FESTIVE: 'CommonStatisticId' = 180629 + HOLIDAY_TREE_GARLAND_PROGRESS: 'CommonStatisticId' = 180422 + HOLIDAY_TREE_ORNAMENTS_PROGRESS: 'CommonStatisticId' = 180421 + HOLIDAY_TREE_SKIRT_PROGRESS: 'CommonStatisticId' = 181647 + HOLIDAY_TREE_TOPPER_PROGRESS: 'CommonStatisticId' = 180423 + HORSESHOE_BAD_THROWS: 'CommonStatisticId' = 111640 + INCENSE_TIME_LEFT: 'CommonStatisticId' = 118476 + INFECTED_CHEMICAL_ANALYZER_PROGRESS: 'CommonStatisticId' = 204831 + INFECTION_CURE_EXPERIMENTAL_TRACKER: 'CommonStatisticId' = 204175 + INFECTION_CURE_VACCINE_DURATION: 'CommonStatisticId' = 207420 + INFECTION_SCANNER_CHARGE: 'CommonStatisticId' = 203442 + INSECT_SPAWNER_VISIBILITY: 'CommonStatisticId' = 110554 + INTERACTIVE_BUSH_DIRTINESS: 'CommonStatisticId' = 124865 + INTERROGATION_TABLE_PROGRESS: 'CommonStatisticId' = 104629 + INVESTIGATION_SYSTEM_STRANGER_VILLE_CRATER_INVESTIGATION_COUNT: 'CommonStatisticId' = 205430 + JUNGLE_WORLD_LOOK_AROUND: 'CommonStatisticId' = 181759 + JUNK_PILE_SEARCHES_AVAILABLE: 'CommonStatisticId' = 204673 + KARAOKE_MACHINE_CONTEST_SCORE: 'CommonStatisticId' = 153653 + KARAOKE_MACHINE_SCORE: 'CommonStatisticId' = 137536 + LAUNDRY_AMOUNT: 'CommonStatisticId' = 175582 + LAUNDRY_DRYER_LINT_TRAY_VOLUME: 'CommonStatisticId' = 176404 + LAUNDRY_DRYER_OBJECT_DRYING_DURATION: 'CommonStatisticId' = 176051 + LAUNDRY_HAMPER_CAPACITY: 'CommonStatisticId' = 175574 + LAUNDRY_OBJECT_CLEANLINESS: 'CommonStatisticId' = 175411 + LAUNDRY_OBJECT_DRYNESS: 'CommonStatisticId' = 175430 + LAUNDRY_OBJECT_SCENTED: 'CommonStatisticId' = 175436 + LAUNDRY_OBJECT_WASHING_MACHINE_BROKENESS_PLUMBING: 'CommonStatisticId' = 177039 + LAUNDRY_WASHING_MACHINE_CLEANING_ADDITIVE: 'CommonStatisticId' = 176375 + LAUNDRY_WASHING_MACHINE_OBJECT_CLEANING_DURATION: 'CommonStatisticId' = 175882 + LICENSE_LYRICS: 'CommonStatisticId' = 153883 + LICENSE_LYRICS_GUITAR: 'CommonStatisticId' = 139953 + LICENSE_LYRICS_MICROPHONE: 'CommonStatisticId' = 139859 + LICENSE_LYRICS_PIANO: 'CommonStatisticId' = 139954 + LICENSE_SONG_DJ_MIX: 'CommonStatisticId' = 126100 + LICENSE_SONG_GUITAR: 'CommonStatisticId' = 16605 + LICENSE_SONG_PIANO: 'CommonStatisticId' = 16606 + LICENSE_SONG_PIPE_ORGAN: 'CommonStatisticId' = 151358 + LICENSE_SONG_VIOLIN: 'CommonStatisticId' = 16607 + LIFE_SKILL_CONFLICT_RESOLUTION: 'CommonStatisticId' = 161616 + LIFE_SKILL_EMOTIONAL_CONTROL: 'CommonStatisticId' = 161618 + LIFE_SKILL_EMPATHY: 'CommonStatisticId' = 161617 + LIFE_SKILL_MANNERS: 'CommonStatisticId' = 161614 + LIFE_SKILL_RESPONSIBILITY: 'CommonStatisticId' = 161615 + LIFE_SKILLS_AUTONOMY_CONFLICT_RESOLUTION_NEGATIVE: 'CommonStatisticId' = 163757 + LIFE_SKILLS_AUTONOMY_CONFLICT_RESOLUTION_POSITIVE: 'CommonStatisticId' = 163756 + LIFE_SKILLS_AUTONOMY_EMOTIONAL_CONTROL_NEGATIVE: 'CommonStatisticId' = 163759 + LIFE_SKILLS_AUTONOMY_EMOTIONAL_CONTROL_POSITIVE: 'CommonStatisticId' = 163758 + LIFE_SKILLS_AUTONOMY_EMPATHY_NEGATIVE: 'CommonStatisticId' = 163761 + LIFE_SKILLS_AUTONOMY_EMPATHY_POSITIVE: 'CommonStatisticId' = 163760 + LIFE_SKILLS_AUTONOMY_MANNERS_NEGATIVE: 'CommonStatisticId' = 163771 + LIFE_SKILLS_AUTONOMY_MANNERS_POSITIVE: 'CommonStatisticId' = 163770 + LIFE_SKILLS_AUTONOMY_RESPONSIBILITY_NEGATIVE: 'CommonStatisticId' = 163755 + LIFE_SKILLS_AUTONOMY_RESPONSIBILITY_POSITIVE: 'CommonStatisticId' = 163754 + LOCAL_CULTURE_SKILL_FOOD_TOLERANCE: 'CommonStatisticId' = 176981 + LOT_DECORATED_STATE_VALUE: 'CommonStatisticId' = 183842 + LTR_FEUD_MAIN: 'CommonStatisticId' = 193901 + LTR_FRIENDSHIP_MAIN: 'CommonStatisticId' = 16650 + LTR_MISCHIEF_MAIN: 'CommonStatisticId' = 26920 + LTR_ROMANCE_MAIN: 'CommonStatisticId' = 16651 + LTR_SIM_TO_PET_FRIENDSHIP_MAIN: 'CommonStatisticId' = 159228 + MAKE_A_MESS_FLOUR_VARIANT_D: 'CommonStatisticId' = 165012 + MAKE_A_MESS_FLOUR_VARIANT_E: 'CommonStatisticId' = 165138 + MAKE_A_MESS_FLOUR_VARIANT_F: 'CommonStatisticId' = 165139 + MAKE_A_MESS_VARIANT_A: 'CommonStatisticId' = 162810 + MAKE_A_MESS_VARIANT_B: 'CommonStatisticId' = 162995 + MAKE_A_MESS_VARIANT_C: 'CommonStatisticId' = 162997 + MARKET_STALL_FOOD_STALL_ORDER: 'CommonStatisticId' = 178814 + MARKET_STALLS_BROWSE: 'CommonStatisticId' = 170543 + MASSAGE_TABLE_FINISHED: 'CommonStatisticId' = 121999 + MASSAGE_TABLE_STONE_MASSAGE: 'CommonStatisticId' = 120462 + MICROSCOPE_COLLECT: 'CommonStatisticId' = 31894 + MOTHER_PLANT_BATTLE_MOTHER_HEALTH: 'CommonStatisticId' = 204445 + MOTHER_PLANT_BATTLE_PLAYER_HEALTH: 'CommonStatisticId' = 203584 + MOTHER_PLANT_ENRAGE: 'CommonStatisticId' = 204704 + MOTIVE_BABY_BLADDER: 'CommonStatisticId' = 16609 + MOTIVE_BABY_DISTRACTION: 'CommonStatisticId' = 8947 + MOTIVE_BABY_ENERGY: 'CommonStatisticId' = 16610 + MOTIVE_BABY_HUNGER: 'CommonStatisticId' = 16611 + MOTIVE_BABY_SOCIAL: 'CommonStatisticId' = 16612 + MOTIVE_BLADDER: 'CommonStatisticId' = 16652 + MOTIVE_CAMPING_FOREST_GOOD_AT_PEACE: 'CommonStatisticId' = 108425 + MOTIVE_CAMPING_FOREST_HOME_SICK: 'CommonStatisticId' = 104114 + MOTIVE_CAMPING_FOREST_NEAT_TOO_MUCH_DIRT: 'CommonStatisticId' = 107835 + MOTIVE_CAMPING_FOREST_REFRESHED: 'CommonStatisticId' = 104832 + MOTIVE_CAMPING_FOREST_SLOB_NATURAL_DIRT: 'CommonStatisticId' = 108426 + MOTIVE_CAMPING_FOREST_SNOB_NOT_ENOUGH_CULTURE: 'CommonStatisticId' = 107829 + MOTIVE_COMFORT: 'CommonStatisticId' = 16653 + MOTIVE_ENERGY: 'CommonStatisticId' = 16654 + MOTIVE_FUN: 'CommonStatisticId' = 16655 + MOTIVE_HANG_OUT: 'CommonStatisticId' = 16615 + MOTIVE_HUNGER: 'CommonStatisticId' = 16656 + MOTIVE_HYGIENE: 'CommonStatisticId' = 16657 + MOTIVE_HYGIENE_HANDS: 'CommonStatisticId' = 16616 + MOTIVE_HYGIENE_ORAL: 'CommonStatisticId' = 16617 + MOTIVE_MAKE_ONE_DESSERT: 'CommonStatisticId' = 34124 + MOTIVE_MAKE_ONE_GROUP_MEAL: 'CommonStatisticId' = 34123 + MOTIVE_MOURN_FRIEND: 'CommonStatisticId' = 99668 + MOTIVE_MOURN_LOVED_ONE: 'CommonStatisticId' = 99667 + MOTIVE_MOURN_NEMESIS: 'CommonStatisticId' = 99669 + MOTIVE_NAUSEA: 'CommonStatisticId' = 16618 + MOTIVE_ANIMAL_FOX_BLADDER: 'CommonStatisticId' = 270467 + MOTIVE_ANIMAL_FOX_HYGIENE: 'CommonStatisticId' = 270701 + MOTIVE_PET_CAT_AFFECTION: 'CommonStatisticId' = 151038 + MOTIVE_PET_CAT_BLADDER: 'CommonStatisticId' = 151036 + MOTIVE_PET_CAT_BOWEL: 'CommonStatisticId' = 157949 + MOTIVE_PET_CAT_ENERGY: 'CommonStatisticId' = 151037 + MOTIVE_PET_CAT_HUNGER: 'CommonStatisticId' = 151035 + MOTIVE_PET_CAT_HYGIENE: 'CommonStatisticId' = 157055 + MOTIVE_PET_CAT_PLAY: 'CommonStatisticId' = 157718 + MOTIVE_PET_DOG_AFFECTION: 'CommonStatisticId' = 151034 + MOTIVE_PET_DOG_BLADDER: 'CommonStatisticId' = 151032 + MOTIVE_PET_DOG_BOWEL: 'CommonStatisticId' = 158698 + MOTIVE_PET_DOG_ENERGY: 'CommonStatisticId' = 151033 + MOTIVE_PET_DOG_HUNGER: 'CommonStatisticId' = 151031 + MOTIVE_PET_DOG_HYGIENE: 'CommonStatisticId' = 157056 + MOTIVE_PET_DOG_PLAY: 'CommonStatisticId' = 158699 + MOTIVE_PLANT_SIM_WATER: 'CommonStatisticId' = 162675 + MOTIVE_ROLE_ALIEN_VISIT_ALIEN: 'CommonStatisticId' = 114183 + MOTIVE_ROLE_BAR_MINGLER: 'CommonStatisticId' = 16620 + MOTIVE_ROLE_BARTENDER: 'CommonStatisticId' = 16623 + MOTIVE_ROLE_BARTENDER_TEND: 'CommonStatisticId' = 16622 + MOTIVE_ROLE_CATERER: 'CommonStatisticId' = 16624 + MOTIVE_ROLE_DINNER_PARTY_HOST: 'CommonStatisticId' = 16625 + MOTIVE_ROLE_DRINK: 'CommonStatisticId' = 101020 + MOTIVE_ROLE_EAT: 'CommonStatisticId' = 122235 + MOTIVE_ROLE_EAT_ONE_SLICE_OF_CAKE: 'CommonStatisticId' = 8901 + MOTIVE_ROLE_GRIM_REAPER: 'CommonStatisticId' = 16628 + MOTIVE_ROLE_GRIM_REAPER_REAP_SOUL: 'CommonStatisticId' = 16627 + MOTIVE_ROLE_SMUGGLER: 'CommonStatisticId' = 28804 + MOTIVE_ROLE_WEDDING_GUEST: 'CommonStatisticId' = 8898 + MOTIVE_ROLE_WORKOUT: 'CommonStatisticId' = 97594 + MOTIVE_SOCIAL: 'CommonStatisticId' = 16658 + MOTIVE_THIRST: 'CommonStatisticId' = 10020 + MOTIVE_TODDLER_ATTENTION: 'CommonStatisticId' = 142037 + MOTIVE_VISIBLE_VAMPIRE_POWER: 'CommonStatisticId' = 150238 + MOTIVE_VISIBLE_VAMPIRE_THIRST: 'CommonStatisticId' = 149541 + MURAL_ACTIVIST_GLOBE: 'CommonStatisticId' = 148595 + MURAL_ACTIVIST_TREES: 'CommonStatisticId' = 148594 + MURAL_CANYON: 'CommonStatisticId' = 148589 + MURAL_CULTURAL_ELEPHANT: 'CommonStatisticId' = 148911 + MURAL_CULTURAL_FISH: 'CommonStatisticId' = 148909 + MURAL_CULTURAL_GIRL: 'CommonStatisticId' = 148912 + MURAL_CULTURAL_JAPANESE: 'CommonStatisticId' = 148910 + MURAL_DECAY: 'CommonStatisticId' = 147256 + MURAL_EGYPT: 'CommonStatisticId' = 148482 + MURAL_FIG_GIRL: 'CommonStatisticId' = 150994 + MURAL_FIG_HAT_LADY: 'CommonStatisticId' = 150995 + MURAL_FIG_HEART: 'CommonStatisticId' = 150993 + MURAL_FIG_PENGUIN: 'CommonStatisticId' = 150996 + MURAL_FISH: 'CommonStatisticId' = 146763 + MURAL_FLOWERS: 'CommonStatisticId' = 146762 + MURAL_GANG: 'CommonStatisticId' = 148484 + MURAL_GARDEN: 'CommonStatisticId' = 148590 + MURAL_GEISHA: 'CommonStatisticId' = 148483 + MURAL_GRAF_PIECE: 'CommonStatisticId' = 148913 + MURAL_GRAF_PURPLE: 'CommonStatisticId' = 148914 + MURAL_ILLUSION_BIRDS: 'CommonStatisticId' = 151702 + MURAL_ILLUSION_FISH: 'CommonStatisticId' = 151672 + MURAL_ILLUSION_FOUNTAIN: 'CommonStatisticId' = 151671 + MURAL_ILLUSION_RAINBOW: 'CommonStatisticId' = 151673 + MURAL_KING: 'CommonStatisticId' = 148481 + MURAL_KOI: 'CommonStatisticId' = 148588 + MURAL_LEAVES: 'CommonStatisticId' = 147390 + MURAL_MAGENTA_CITY: 'CommonStatisticId' = 147837 + MURAL_MOSAIC_CITY: 'CommonStatisticId' = 147838 + MURAL_ORANGE_CITY: 'CommonStatisticId' = 148485 + MURAL_TREE: 'CommonStatisticId' = 147494 + MURAL_UNIVERSE: 'CommonStatisticId' = 148591 + MURAL_ZILLA_CITY: 'CommonStatisticId' = 148486 + MUSIC_PRODUCTION_STATION_CD_ON_RADIO: 'CommonStatisticId' = 203042 + MUSIC_PRODUCTION_STATION_MUSIC_LABEL_DINKY_BEATS: 'CommonStatisticId' = 194714 + MUSIC_PRODUCTION_STATION_MUSIC_LABEL_MAXIS_MUSIC_MACHINE: 'CommonStatisticId' = 194715 + MUSIC_PRODUCTION_STATION_MUSIC_LABEL_NEW_TASTE_MAKERS: 'CommonStatisticId' = 194716 + MUSIC_PRODUCTION_STATION_RELEASE_COOLDOWN: 'CommonStatisticId' = 201546 + MYSTICAL_RELIC_COOLDOWN: 'CommonStatisticId' = 179668 + NATURAL_DANGERS: 'CommonStatisticId' = 176613 + NATURAL_DANGERS_TEMPLE: 'CommonStatisticId' = 181822 + NEW_OBJECT: 'CommonStatisticId' = 167504 + NPC_GRIM_REAPER_BE_REAPED: 'CommonStatisticId' = 16666 + NPC_GRIM_REAPER_CLEMENCY: 'CommonStatisticId' = 16667 + NPC_GRIM_REAPER_COUNT: 'CommonStatisticId' = 16668 + OBJECT_APARTMENT_PROBLEM_FLOWING_PUDDLE: 'CommonStatisticId' = 155520 + OBJECT_APARTMENT_PROBLEM_POWER_OUTAGE: 'CommonStatisticId' = 133845 + OBJECT_APARTMENT_PROBLEM_SEVERITY: 'CommonStatisticId' = 133061 + OBJECT_AUTO_PET_FEEDER_REFILL_VFX: 'CommonStatisticId' = 160119 + OBJECT_AUTO_PET_FEEDER_SCHEDULE_TIMER: 'CommonStatisticId' = 159034 + OBJECT_AUTOGRAPHED_OBJECT_APPRAISAL_COOLDOWN_TIMER: 'CommonStatisticId' = 200664 + OBJECT_BACKYARD_DRINK_TRAY_SERVINGS: 'CommonStatisticId' = 140055 + OBJECT_BASKETBALL_COMPETITION_TIMER: 'CommonStatisticId' = 153689 + OBJECT_BASKETBALL_GLASS_STATUS: 'CommonStatisticId' = 153627 + OBJECT_BASKETBALL_IN_THE_ZONE_SHOT_TRACKER: 'CommonStatisticId' = 147787 + OBJECT_BASKETBALL_ON_FIRE_SHOT_TRACKER: 'CommonStatisticId' = 147788 + OBJECT_BATTLE_STATION_PROGRESS: 'CommonStatisticId' = 134837 + OBJECT_BED_MONSTER_UNDER_PREVENT_SPAWN_COUNTER: 'CommonStatisticId' = 135989 + OBJECT_BEE_BOX_RELATIONSHIP: 'CommonStatisticId' = 186135 + OBJECT_BLOCK_CONSTRUCTION_TABLE_PROGRESS: 'CommonStatisticId' = 165304 + OBJECT_BOOK_PROGRESS: 'CommonStatisticId' = 36408 + OBJECT_BOOKS_BROWSED: 'CommonStatisticId' = 76992 + OBJECT_BOWLING_LANE_GAME_IN_PROGRESS: 'CommonStatisticId' = 161517 + OBJECT_BOWLING_LANE_RELATIONSHIP: 'CommonStatisticId' = 160133 + OBJECT_BOWLING_LANE_RERACK_RESET: 'CommonStatisticId' = 158519 + OBJECT_BOWLING_LANE_SORE_ARMS_TRACKER: 'CommonStatisticId' = 162030 + OBJECT_BOWLING_LANE_STRIKE_COUNTER: 'CommonStatisticId' = 162431 + OBJECT_BOWLING_LANE_TURKEY_STRIKES_COUNTER: 'CommonStatisticId' = 162393 + OBJECT_BROKENNESS: 'CommonStatisticId' = 16633 + OBJECT_BUBBLE_BLOWER_CARTRIDGE_CHARGES: 'CommonStatisticId' = 133034 + OBJECT_BURNING: 'CommonStatisticId' = 39470 + OBJECT_CHESS_TABLE_PROGRESS: 'CommonStatisticId' = 16669 + OBJECT_CLAY_BLOB_PROGRESS: 'CommonStatisticId' = 16670 + OBJECT_CLEAR_EASEL: 'CommonStatisticId' = 154802 + OBJECT_CLOSET_CHANGE_COUNTER: 'CommonStatisticId' = 126939 + OBJECT_CLOSET_TRYING_OUTFITS_ON: 'CommonStatisticId' = 143372 + OBJECT_COMPUTER_CHARITY_COOLDOWN: 'CommonStatisticId' = 31127 + OBJECT_COMPUTER_GAME_MOD_BLICBLOCK: 'CommonStatisticId' = 32835 + OBJECT_COMPUTER_GAME_MOD_HILLOCK: 'CommonStatisticId' = 32839 + OBJECT_COMPUTER_GAME_MOD_INCREDIBLE_SPORTS: 'CommonStatisticId' = 32840 + OBJECT_COMPUTER_GAME_MOD_MARIA_SISTERS: 'CommonStatisticId' = 32841 + OBJECT_COMPUTER_GAME_MOD_REFUGE: 'CommonStatisticId' = 32842 + OBJECT_COMPUTER_GAME_MOD_ROAD_RIVAL: 'CommonStatisticId' = 32843 + OBJECT_COMPUTER_GAME_MOD_SIMS_FOREVER_RENAMED: 'CommonStatisticId' = 32838 + OBJECT_COMPUTER_GAME_TOURNAMENT_PAYOUT_MULTIPLIER: 'CommonStatisticId' = 31893 + OBJECT_COMPUTER_REPAIR_TIMEOUT: 'CommonStatisticId' = 203501 + OBJECT_COMPUTER_SOCIAL_NETWORK_FOLLOWERS: 'CommonStatisticId' = 31167 + OBJECT_COMPUTER_SOCIAL_NETWORK_IMAGE_COOLDOWN: 'CommonStatisticId' = 31198 + OBJECT_COMPUTER_SOCIAL_NETWORK_ON: 'CommonStatisticId' = 31166 + OBJECT_COMPUTER_SOCIAL_NETWORK_VIDEO_COOLDOWN: 'CommonStatisticId' = 31203 + OBJECT_COMPUTER_VIDEO_GAMING_RESEARCH: 'CommonStatisticId' = 32053 + OBJECT_COMPUTER_VIDEO_GAMING_STREAMS: 'CommonStatisticId' = 32054 + OBJECT_COMPUTER_VIDEO_GAMING_FAN_COUNT: 'CommonStatisticId' = 33411 + OBJECT_CONSUMABLE: 'CommonStatisticId' = 16634 + OBJECT_CONSUMABLE_QUALITY: 'CommonStatisticId' = 16671 + OBJECT_CONSUMABLE_SABOTAGED: 'CommonStatisticId' = 187177 + OBJECT_CONSUMABLE_SERVINGS: 'CommonStatisticId' = 16672 + OBJECT_COUNT_TOYS: 'CommonStatisticId' = 176598 + OBJECT_COW_PLANT_HUNGER: 'CommonStatisticId' = 16635 + OBJECT_CRAFT_SALES_TABLE_AUTONOMY_BROWSE_TABLE: 'CommonStatisticId' = 145285 + OBJECT_CRIME_SCENE_PHOTO_TAKEN: 'CommonStatisticId' = 108811 + OBJECT_CRIME_SCENE_PRINTS_TAKEN: 'CommonStatisticId' = 108812 + OBJECT_CRIME_SCENE_SAMPLE_TAKEN: 'CommonStatisticId' = 108813 + OBJECT_CRIME_SCENE_WITNESS_REPORT_TAKEN: 'CommonStatisticId' = 108814 + OBJECT_CRYSTAL_HELMET_CRYSTAL_BATTERY_LIFE: 'CommonStatisticId' = 192883 + OBJECT_CUPCAKE_FACTORY_BATTER: 'CommonStatisticId' = 16636 + OBJECT_DANCE_FLOOR_SHOW_OFF_MOVES: 'CommonStatisticId' = 125306 + OBJECT_DARTBOARD_GAME_IN_PROGRESS: 'CommonStatisticId' = 130238 + OBJECT_DARTBOARD_ROUND_SCORE: 'CommonStatisticId' = 127975 + OBJECT_DISHES_DISH_COUNT: 'CommonStatisticId' = 16674 + OBJECT_DISHWASHER_TIME_LEFT: 'CommonStatisticId' = 122157 + OBJECT_DJ_BOOTH_ACTOR_JUST_TIPPED: 'CommonStatisticId' = 130631 + OBJECT_DJ_BOOTH_AUDIENCE_PARTICIPATION: 'CommonStatisticId' = 125698 + OBJECT_DJ_BOOTH_AUDIENCE_POSITIVE_BUFF: 'CommonStatisticId' = 128368 + OBJECT_DJ_BOOTH_DJ_PERFORMANCE_DURATION: 'CommonStatisticId' = 123799 + OBJECT_DJ_BOOTH_PERFORMANCE_STATE_DECAY: 'CommonStatisticId' = 124623 + OBJECT_DJ_BOOTH_SHOW_QUALITY: 'CommonStatisticId' = 123168 + OBJECT_DJ_BOOTH_TIPS: 'CommonStatisticId' = 127877 + OBJECT_DOLLHOUSE_PLAY_COUNT: 'CommonStatisticId' = 37467 + OBJECT_DONT_WAKE_LLAMA_BOT_SECTION: 'CommonStatisticId' = 127158 + OBJECT_DONT_WAKE_LLAMA_GAME_COUNT: 'CommonStatisticId' = 130258 + OBJECT_DONT_WAKE_LLAMA_TOP_SECTION: 'CommonStatisticId' = 127160 + OBJECT_EGG_FOUND: 'CommonStatisticId' = 190498 + OBJECT_FERTILIZER_COOLDOWN: 'CommonStatisticId' = 97593 + OBJECT_FIRE_BEEN_EXTINGUISHED: 'CommonStatisticId' = 75770 + OBJECT_FIRE_RAIN: 'CommonStatisticId' = 190384 + OBJECT_FIRE_STRENGTH: 'CommonStatisticId' = 39323 + OBJECT_FIRE_LEAF_ELIXIR_OF_BURNING: 'CommonStatisticId' = 104298 + OBJECT_FIRE_LEAF_NEAR: 'CommonStatisticId' = 104033 + OBJECT_FIRE_LEAF_RASH: 'CommonStatisticId' = 104035 + OBJECT_FRONT_DESK_AWAY_EVENT_TIMER: 'CommonStatisticId' = 115560 + OBJECT_FRONT_DESK_HOUSE_CALL_TIMER: 'CommonStatisticId' = 115536 + OBJECT_FRONT_DESK_OUTBREAK_TIMER: 'CommonStatisticId' = 115537 + OBJECT_GNOME_RELATIONSHIP: 'CommonStatisticId' = 180290 + OBJECT_GUITAR_ROCKIN_RIFFS: 'CommonStatisticId' = 34551 + OBJECT_GUITAR_SINGING_QUALITY: 'CommonStatisticId' = 110731 + OBJECT_HOLIDAY_CANDLE_LIT: 'CommonStatisticId' = 110394 + OBJECT_HOSPITAL_EXAM_BED_DIRTINESS: 'CommonStatisticId' = 107405 + OBJECT_HOT_TUB_IN_USE: 'CommonStatisticId' = 119029 + OBJECT_INFECTED_PLANT_RECENTLY_NURTURED: 'CommonStatisticId' = 202472 + OBJECT_INVENTION_CONSTRUCTOR_ASSEMBLE_MIXER_TRACKER: 'CommonStatisticId' = 109959 + OBJECT_INVENTION_CONSTRUCTOR_INVENT_MIXER_TRACKER: 'CommonStatisticId' = 110100 + OBJECT_JIG_ALIEN_ORB_VFX: 'CommonStatisticId' = 116352 + OBJECT_KARAOKE_MACHINE_START_DUET: 'CommonStatisticId' = 149672 + OBJECT_LASER_LIGHT_SHOW_ROTATION: 'CommonStatisticId' = 35336 + OBJECT_LEAF_PILE_COUNT: 'CommonStatisticId' = 180201 + OBJECT_LEAF_PILE_DESTROY_TIMER: 'CommonStatisticId' = 207084 + OBJECT_LEAF_PILE_FIRE_INTENSITY: 'CommonStatisticId' = 182939 + OBJECT_LEAF_PILE_FRESHNESS: 'CommonStatisticId' = 183132 + OBJECT_LIGHT: 'CommonStatisticId' = 99424 + OBJECT_LITTER_BOX_RAKE: 'CommonStatisticId' = 161504 + OBJECT_LITTER_BOX_STORAGE: 'CommonStatisticId' = 170290 + OBJECT_LITTER_BOX_TURRET: 'CommonStatisticId' = 161505 + OBJECT_MAILBOX_INVENTORY_COUNT: 'CommonStatisticId' = 16675 + OBJECT_MAILBOX_WALL_AUTONOMOUS_DELIVERY: 'CommonStatisticId' = 143559 + OBJECT_MASSAGE_CHAIR_FOOT_MASSAGE: 'CommonStatisticId' = 119766 + OBJECT_MASSAGE_CHAIR_HAND_MASSAGE: 'CommonStatisticId' = 119765 + OBJECT_MICROWAVE_FLAVOR_UPGRADED: 'CommonStatisticId' = 97014 + OBJECT_MINOR_PET_CAGE_ACTIVITY: 'CommonStatisticId' = 180912 + OBJECT_MINOR_PET_CAGE_AGE: 'CommonStatisticId' = 183341 + OBJECT_MINOR_PET_CAGE_ATTENTION: 'CommonStatisticId' = 180913 + OBJECT_MINOR_PET_CAGE_CLEANLINESS: 'CommonStatisticId' = 183955 + OBJECT_MINOR_PET_CAGE_ENERGY: 'CommonStatisticId' = 181288 + OBJECT_MINOR_PET_CAGE_HUNGER: 'CommonStatisticId' = 180911 + OBJECT_MINOR_PET_CAGE_RODENT_DISEASE: 'CommonStatisticId' = 185283 + OBJECT_MIRROR_EPIC_STORY: 'CommonStatisticId' = 31306 + OBJECT_MONSTERS_LEVEL: 'CommonStatisticId' = 134167 + OBJECT_MOTHER_PLANT_RELATIONSHIP: 'CommonStatisticId' = 206016 + OBJECT_MOTHER_PLANT_DEFEAT: 'CommonStatisticId' = 205212 + OBJECT_MOTION_GAMING_RIG_ADVENTURE: 'CommonStatisticId' = 29386 + OBJECT_MOTION_GAMING_RIG_FAMILY: 'CommonStatisticId' = 29387 + OBJECT_MOTION_GAMING_RIG_PUZZLE: 'CommonStatisticId' = 39919 + OBJECT_MOTION_GAMING_RIG_SPORTS: 'CommonStatisticId' = 29388 + OBJECT_MOVIE_ENJOYMENT: 'CommonStatisticId' = 128901 + OBJECT_MOVIE_LENGTH: 'CommonStatisticId' = 129182 + OBJECT_MURAL_KICK_OFF_TRACKER: 'CommonStatisticId' = 154292 + OBJECT_MUSIC_PRODUCTION_STATION_TRACKS_RELEASED: 'CommonStatisticId' = 194853 + OBJECT_MUSIC_PRODUCTION_STATION_TRACKS_RELEASED_DINKY_BEATS: 'CommonStatisticId' = 197041 + OBJECT_MUSIC_PRODUCTION_STATION_TRACKS_RELEASED_MAXIS_MUSIC_MACHINE: 'CommonStatisticId' = 197042 + OBJECT_MUSIC_PRODUCTION_STATION_TRACKS_RELEASED_NEW_TASTE_MAKERS: 'CommonStatisticId' = 197043 + OBJECT_NUM_SIMS_WATCHING: 'CommonStatisticId' = 31618 + OBJECT_OVEN_COOKING_PROGRESS: 'CommonStatisticId' = 16637 + OBJECT_PARK_FOUNTAIN_SOAP: 'CommonStatisticId' = 131534 + OBJECT_PET_MINOR_CAGE_FOOD: 'CommonStatisticId' = 181295 + OBJECT_PET_MINOR_CAGE_RELATIONSHIP: 'CommonStatisticId' = 180924 + OBJECT_PET_POOP_DESTROY: 'CommonStatisticId' = 161056 + OBJECT_PHOTO_STUDIO_IN_PLACE_COUNT_2_SIMS: 'CommonStatisticId' = 111877 + OBJECT_PHOTO_STUDIO_IN_PLACE_COUNT_3_SIMS: 'CommonStatisticId' = 111830 + OBJECT_PIANO_COOL_KEY_CHORDS: 'CommonStatisticId' = 34518 + OBJECT_PIPE_ORGAN_PALLIATIVE_PIPES: 'CommonStatisticId' = 151296 + OBJECT_PODIUM_SPEECH_HAPPY_COUNT: 'CommonStatisticId' = 147282 + OBJECT_PODIUM_SPEECH_UNHAPPY_COUNT: 'CommonStatisticId' = 147283 + OBJECT_POPCORN_BURNING_CARAMEL: 'CommonStatisticId' = 130645 + OBJECT_POPCORN_BURNING_CHEDDAR: 'CommonStatisticId' = 130646 + OBJECT_POPCORN_BURNING_KETTLE: 'CommonStatisticId' = 130647 + OBJECT_POPCORN_BURNING_POPCORN: 'CommonStatisticId' = 130648 + OBJECT_POPCORN_POPPER_PROGRESS: 'CommonStatisticId' = 129056 + OBJECT_POPCORN_POPPER_SERVINGS: 'CommonStatisticId' = 128955 + OBJECT_POSTCARD_COOLDOWN_APPALOOSA_PLAINS: 'CommonStatisticId' = 29793 + OBJECT_POSTCARD_COOLDOWN_BARNACLE_BAY: 'CommonStatisticId' = 29794 + OBJECT_POSTCARD_COOLDOWN_BRIDGEPORT: 'CommonStatisticId' = 29795 + OBJECT_POSTCARD_COOLDOWN_CHAMPS_LES_SIMS: 'CommonStatisticId' = 29796 + OBJECT_POSTCARD_COOLDOWN_DRAGON_VALLEY: 'CommonStatisticId' = 29797 + OBJECT_POSTCARD_COOLDOWN_ISLA_PARADISO: 'CommonStatisticId' = 29798 + OBJECT_POSTCARD_COOLDOWN_LITTLE_HAVEN: 'CommonStatisticId' = 29799 + OBJECT_POSTCARD_COOLDOWN_LUCKY_PALMS: 'CommonStatisticId' = 29800 + OBJECT_POSTCARD_COOLDOWN_LUNAR_LAKES: 'CommonStatisticId' = 29801 + OBJECT_POSTCARD_COOLDOWN_MIDNIGHT_HOLLOW: 'CommonStatisticId' = 29802 + OBJECT_POSTCARD_COOLDOWN_MOONLIGHT_FALLS: 'CommonStatisticId' = 29803 + OBJECT_POSTCARD_COOLDOWN_RIVERVIEW: 'CommonStatisticId' = 29804 + OBJECT_POSTCARD_COOLDOWN_SUNSET_VALLEY: 'CommonStatisticId' = 29805 + OBJECT_POSTCARD_COOLDOWN_TWINBROOK: 'CommonStatisticId' = 29806 + OBJECT_POSTCARD_PENPAL_REPLY: 'CommonStatisticId' = 29756 + OBJECT_POSTCARDS_APPALOOSA_PLAINS: 'CommonStatisticId' = 29715 + OBJECT_POSTCARDS_BARNACLE_BAY: 'CommonStatisticId' = 29719 + OBJECT_POSTCARDS_BRIDGEPORT: 'CommonStatisticId' = 29712 + OBJECT_POSTCARDS_CHAMPS_LES_SIMS: 'CommonStatisticId' = 29720 + OBJECT_POSTCARDS_DRAGON_VALLEY: 'CommonStatisticId' = 29724 + OBJECT_POSTCARDS_ISLA_PARADISO: 'CommonStatisticId' = 29723 + OBJECT_POSTCARDS_LITTLE_HAVEN: 'CommonStatisticId' = 29714 + OBJECT_POSTCARDS_LUCKY_PALMS: 'CommonStatisticId' = 29717 + OBJECT_POSTCARDS_LUNAR_LAKES: 'CommonStatisticId' = 29721 + OBJECT_POSTCARDS_MIDNIGHT_HOLLOW: 'CommonStatisticId' = 29722 + OBJECT_POSTCARDS_MOONLIGHT_FALLS: 'CommonStatisticId' = 29716 + OBJECT_POSTCARDS_RIVERVIEW: 'CommonStatisticId' = 29713 + OBJECT_POSTCARDS_SUNSET_VALLEY: 'CommonStatisticId' = 29710 + OBJECT_POSTCARDS_TWINBROOK: 'CommonStatisticId' = 29711 + OBJECT_POSTCARDS_WAITING_FOR_PENPAL_REPLY: 'CommonStatisticId' = 29757 + OBJECT_POTTY_CHAIR_CONFIDENCE: 'CommonStatisticId' = 144921 + OBJECT_PUBLIC_BATHROOM_CAPACITY: 'CommonStatisticId' = 102628 + OBJECT_PUDDLE_EVAPORATION: 'CommonStatisticId' = 183781 + OBJECT_PUDDLE_WATER: 'CommonStatisticId' = 16676 + OBJECT_PUPPET_THEATER_CLAP: 'CommonStatisticId' = 135935 + OBJECT_PUPPET_THEATER_FAILURES: 'CommonStatisticId' = 133858 + OBJECT_PUPPET_THEATER_JOKE: 'CommonStatisticId' = 135934 + OBJECT_PUPPET_THEATER_SCARED: 'CommonStatisticId' = 135936 + OBJECT_PUPPET_THEATER_STAGE: 'CommonStatisticId' = 133859 + OBJECT_RABBIT_HOLE_BRAMBLE_ADVENTURE_STATE: 'CommonStatisticId' = 103097 + OBJECT_RABBIT_HOLE_CAVE_ADVENTURE_STATE: 'CommonStatisticId' = 77469 + OBJECT_RABBIT_HOLE_RELATIONSHIP: 'CommonStatisticId' = 74098 + OBJECT_RABBIT_HOLE_TREE_ADVENTURE_STATE: 'CommonStatisticId' = 77452 + OBJECT_ROAST_MARSHMALLOW_PROGRESS: 'CommonStatisticId' = 112001 + OBJECT_ROBOT_VACUUM_AUTO_CLEAN_TIMER: 'CommonStatisticId' = 173413 + OBJECT_ROBOT_VACUUM_CLEAR_TRASH: 'CommonStatisticId' = 176156 + OBJECT_ROBOT_VACUUM_DOCK_AUTO_CLEAN_TIMER: 'CommonStatisticId' = 173318 + OBJECT_ROBOT_VACUUM_DOCKED_VFX: 'CommonStatisticId' = 176678 + OBJECT_ROBOT_VACUUM_RUNNING_TIME: 'CommonStatisticId' = 173116 + OBJECT_ROBOT_VACUUM_TRASH_CAPACITY: 'CommonStatisticId' = 173115 + OBJECT_ROCKET_SHIP_FUEL: 'CommonStatisticId' = 9691 + OBJECT_ROCKET_SHIP_PROGRESS: 'CommonStatisticId' = 16677 + OBJECT_ROCKET_SHIP_ROCKETS_IN_SPACE: 'CommonStatisticId' = 16678 + OBJECT_ROCKET_SHIP_SABOTAGE: 'CommonStatisticId' = 29448 + OBJECT_ROCKET_SHIP_SPACE_WOOHOO_COUNT: 'CommonStatisticId' = 16679 + OBJECT_SCARECROW_REL: 'CommonStatisticId' = 187939 + OBJECT_SCHOOL_PROJECT_BOX_PROGRESS: 'CommonStatisticId' = 161800 + OBJECT_SCHOOL_PROJECT_BOX_QUALITY: 'CommonStatisticId' = 161799 + OBJECT_SCULPTURE_CONTROL_OVER_SIM: 'CommonStatisticId' = 24887 + OBJECT_SCULPTURE_ENERGY: 'CommonStatisticId' = 24767 + OBJECT_SCULPTURE_RELATIONSHIP: 'CommonStatisticId' = 9892 + OBJECT_SEED_AMOUNT: 'CommonStatisticId' = 140672 + OBJECT_SIM_RAY_CHILLED: 'CommonStatisticId' = 109432 + OBJECT_SIM_RAY_FROZEN: 'CommonStatisticId' = 105910 + OBJECT_SIM_RAY_FROZEN_CHILD: 'CommonStatisticId' = 115717 + OBJECT_SKATING_RINK_ROUTINE_MISTAKES: 'CommonStatisticId' = 180586 + OBJECT_SKATING_RINK_ROUTINE_TOTAL: 'CommonStatisticId' = 180593 + OBJECT_SKATING_RINK_SKATERS_ACTIVE: 'CommonStatisticId' = 180133 + OBJECT_SKATING_RINK_WATCHER_TOTAL: 'CommonStatisticId' = 191312 + OBJECT_SKULL_DISPLAY_CASE_CELEBRATE_COOL_DOWN_TIMER: 'CommonStatisticId' = 154769 + OBJECT_SLEEPING_POD_SLEEP_DURATION: 'CommonStatisticId' = 201167 + OBJECT_SLIPPY_SLIDE_IN_USE: 'CommonStatisticId' = 140219 + OBJECT_SLIPPY_SLIDE_SLIDE_AMOUNT: 'CommonStatisticId' = 140357 + OBJECT_SLIPPY_SLIDE_SLIDING: 'CommonStatisticId' = 143922 + OBJECT_SLIPPY_SLIDE_SOAP: 'CommonStatisticId' = 140670 + OBJECT_SMART_HUB_REL: 'CommonStatisticId' = 203455 + OBJECT_SMOKE_SOURCES: 'CommonStatisticId' = 75461 + OBJECT_SNOW_PAL_HEALTH: 'CommonStatisticId' = 180385 + OBJECT_SNOW_PAL_RELATIONSHIP: 'CommonStatisticId' = 180500 + OBJECT_SNOW_SNOW_MELT: 'CommonStatisticId' = 180386 + OBJECT_SNOW_SNOW_MELT_FIRE: 'CommonStatisticId' = 188747 + OBJECT_SPRINKLERS_DISABLED_NUM: 'CommonStatisticId' = 184640 + OBJECT_SPRINKLERS_ENABLED_NUM: 'CommonStatisticId' = 184403 + OBJECT_STAFF_ASSIGNED_RELATIONSHIP: 'CommonStatisticId' = 119087 + OBJECT_STAFF_ASSIGNED_RELATIONSHIP_BG: 'CommonStatisticId' = 132465 + OBJECT_STAFF_STUDIO_OBJECTS: 'CommonStatisticId' = 189729 + OBJECT_STATE_VALUE_ELIXIR_OF_BURNING_APPLIED: 'CommonStatisticId' = 104263 + OBJECT_STATE_VALUE_HERBICIDE_APPLIED: 'CommonStatisticId' = 111940 + OBJECT_STEAM_ROOM_SABOTAGE_FIRE_LEAF: 'CommonStatisticId' = 120043 + OBJECT_STEAM_ROOM_SABOTAGE_SULFUR: 'CommonStatisticId' = 119485 + OBJECT_STINGS_NEGATIVE: 'CommonStatisticId' = 131012 + OBJECT_STINGS_NEUTRAL: 'CommonStatisticId' = 131013 + OBJECT_STINGS_OVERWHELMING_NEGATIVE: 'CommonStatisticId' = 131014 + OBJECT_STINGS_OVERWHELMING_POSITIVE: 'CommonStatisticId' = 131015 + OBJECT_STINGS_POSITIVE: 'CommonStatisticId' = 131011 + OBJECT_STOVE_FLAVORIZED: 'CommonStatisticId' = 37345 + OBJECT_STREAMING_DRONE_BATTERY: 'CommonStatisticId' = 194617 + OBJECT_STUFFED_ANIMAL_RELATIONSHIP: 'CommonStatisticId' = 10229 + OBJECT_TALKING_TOILET_BIDET_TIMER: 'CommonStatisticId' = 146291 + OBJECT_TALKING_TOILET_BIDET_VFX: 'CommonStatisticId' = 146290 + OBJECT_TALKING_TOILET_BROKENNESS_ELECTRONIC: 'CommonStatisticId' = 132902 + OBJECT_TALKING_TOILET_REL_STC: 'CommonStatisticId' = 138082 + OBJECT_TALKING_TOILET_RELATIONSHIP: 'CommonStatisticId' = 134179 + OBJECT_TALKING_TOILET_ROOM_DRYING_VFX: 'CommonStatisticId' = 139985 + OBJECT_TALKING_TOILET_SELF_CLEANING_VFX: 'CommonStatisticId' = 142671 + OBJECT_TEMPLE_TRAP_ACTIVATED_0: 'CommonStatisticId' = 179617 + OBJECT_TEMPLE_TRAP_ACTIVATED_1: 'CommonStatisticId' = 179618 + OBJECT_TEMPLE_TRAP_ACTIVATED_2: 'CommonStatisticId' = 179619 + OBJECT_TEMPLE_TRAP_ACTIVATED_3: 'CommonStatisticId' = 179620 + OBJECT_TEMPLE_TRAP_EXAMINE_0: 'CommonStatisticId' = 174002 + OBJECT_TEMPLE_TRAP_EXAMINE_1: 'CommonStatisticId' = 174003 + OBJECT_TEMPLE_TRAP_EXAMINE_2: 'CommonStatisticId' = 174004 + OBJECT_TEMPLE_TRAP_EXAMINE_3: 'CommonStatisticId' = 174005 + OBJECT_TEMPLE_TRAP_EXAMINE_PROGRESS: 'CommonStatisticId' = 179014 + OBJECT_TENT_SIM_CHATTING: 'CommonStatisticId' = 111162 + OBJECT_TENT_SIMS_IN_TENT: 'CommonStatisticId' = 110685 + OBJECT_THERMOSTAT_LOT_STAT_COUNTER: 'CommonStatisticId' = 188002 + OBJECT_THERMOSTAT_LOT_STAT_SETTING: 'CommonStatisticId' = 187710 + OBJECT_TIMER: 'CommonStatisticId' = 154238 + OBJECT_TOY_BALL_PET_CHEWEDNESS: 'CommonStatisticId' = 157968 + OBJECT_TRASH_AMOUNT: 'CommonStatisticId' = 16680 + OBJECT_TRASH_CAPACITY: 'CommonStatisticId' = 16681 + OBJECT_TRASH_CHUTE_BROKENNESS_JAM: 'CommonStatisticId' = 133525 + OBJECT_TRASH_CONSUMABLE: 'CommonStatisticId' = 76727 + OBJECT_TRASH_GROWTH: 'CommonStatisticId' = 16639 + OBJECT_TRASH_HI_TECH_CYCLE: 'CommonStatisticId' = 27561 + OBJECT_TRASH_JUST_FAILED_OUTDOOR: 'CommonStatisticId' = 99446 + OBJECT_TRASH_STINK: 'CommonStatisticId' = 27382 + OBJECT_TREAD_MILL_ROCK_CLIMBING_WALL_CLIMB_PROGRESS: 'CommonStatisticId' = 166015 + OBJECT_TREAD_MILL_ROCK_CLIMBING_WALL_SELF_REPAIR_PROGRESS: 'CommonStatisticId' = 167831 + OBJECT_UPGRADE_AROMATHERAPY: 'CommonStatisticId' = 118643 + OBJECT_UPGRADE_BOWLING_LANE_MOON_LIGHT: 'CommonStatisticId' = 158115 + OBJECT_UPGRADE_CHEMICAL_ANALYZER_NEVER_BREAKS: 'CommonStatisticId' = 108304 + OBJECT_UPGRADE_CHEMISTRY_LAB: 'CommonStatisticId' = 105358 + OBJECT_UPGRADE_COFFEE_MAKER_INFUSER: 'CommonStatisticId' = 26045 + OBJECT_UPGRADE_COMPUTER_GAMING_SKILL: 'CommonStatisticId' = 29027 + OBJECT_UPGRADE_COMPUTER_HACKING_MONEY: 'CommonStatisticId' = 29028 + OBJECT_UPGRADE_DISHWASHER_QUIET_RUNNING: 'CommonStatisticId' = 122287 + OBJECT_UPGRADE_DISHWASHER_SPEEDY_CLEANER: 'CommonStatisticId' = 122275 + OBJECT_UPGRADE_DJ_BOOTH_FIREPROOF: 'CommonStatisticId' = 123463 + OBJECT_UPGRADE_DJ_BOOTH_TELESPLOSION: 'CommonStatisticId' = 123465 + OBJECT_UPGRADE_DJ_BOOTH_VFX_EMITTER: 'CommonStatisticId' = 123921 + OBJECT_UPGRADE_DJ_BOOTH_VIDEO_SCREEN: 'CommonStatisticId' = 123464 + OBJECT_UPGRADE_ESPRESSO_MACHINE: 'CommonStatisticId' = 126466 + OBJECT_UPGRADE_FIREPLACE_AUTO_LIGHT: 'CommonStatisticId' = 74684 + OBJECT_UPGRADE_FIREPLACE_FIRESAFE: 'CommonStatisticId' = 74685 + OBJECT_UPGRADE_GENERIC_FAST_ENERGY: 'CommonStatisticId' = 28491 + OBJECT_UPGRADE_GENERIC_FAST_HYGIENE: 'CommonStatisticId' = 9761 + OBJECT_UPGRADE_GENERIC_FASTER_HYGIENE: 'CommonStatisticId' = 9762 + OBJECT_UPGRADE_GENERIC_INCREASE_QUALITY: 'CommonStatisticId' = 16682 + OBJECT_UPGRADE_GENERIC_LOCK_BROKENNESS: 'CommonStatisticId' = 16683 + OBJECT_UPGRADE_GENERIC_LOCK_DIRTINESS: 'CommonStatisticId' = 16684 + OBJECT_UPGRADE_GENERIC_LOCK_HYGIENE: 'CommonStatisticId' = 16685 + OBJECT_UPGRADE_GENERIC_LOWER_BROKENNESS: 'CommonStatisticId' = 16686 + OBJECT_UPGRADE_GENERIC_LOWER_DIRTINESS: 'CommonStatisticId' = 16687 + OBJECT_UPGRADE_HEAT_LAMP_FIRE_SAFE: 'CommonStatisticId' = 131676 + OBJECT_UPGRADE_INVENTION_CONSTRUCTOR_UPGRADE: 'CommonStatisticId' = 112000 + OBJECT_UPGRADE_KARAOKE_MACHINE_AUTO_TUNE: 'CommonStatisticId' = 141793 + OBJECT_UPGRADE_KARAOKE_MACHINE_TELESPLOSION: 'CommonStatisticId' = 141791 + OBJECT_UPGRADE_LAUNDRY_CLOTHES_LINE_IRON_LINE: 'CommonStatisticId' = 177424 + OBJECT_UPGRADE_LAUNDRY_DRYER_LINT_LESS: 'CommonStatisticId' = 177310 + OBJECT_UPGRADE_LAUNDRY_DRYER_NEVER_BREAKS: 'CommonStatisticId' = 177308 + OBJECT_UPGRADE_LAUNDRY_DRYER_QUIET: 'CommonStatisticId' = 177309 + OBJECT_UPGRADE_LAUNDRY_DRYER_SPEED_CYCLE: 'CommonStatisticId' = 177307 + OBJECT_UPGRADE_LAUNDRY_WASHING_MACHINE_INGREDIENT_TRAY: 'CommonStatisticId' = 176336 + OBJECT_UPGRADE_LAUNDRY_WASHING_MACHINE_NEVER_BREAKS: 'CommonStatisticId' = 177242 + OBJECT_UPGRADE_LAUNDRY_WASHING_MACHINE_NOISELESS: 'CommonStatisticId' = 176958 + OBJECT_UPGRADE_LAUNDRY_WASHING_MACHINE_PRE_SOAK: 'CommonStatisticId' = 176953 + OBJECT_UPGRADE_LAUNDRY_WASHING_MACHINE_SPEED_CYCLE: 'CommonStatisticId' = 176951 + OBJECT_UPGRADE_MICROSCOPE_PRECISION_LENSES: 'CommonStatisticId' = 16688 + OBJECT_UPGRADE_MOVIE_BETTER_PROJECTION: 'CommonStatisticId' = 129336 + OBJECT_UPGRADE_ROBOT_VACUUM_DOCK_CLEAR_TRASH: 'CommonStatisticId' = 173324 + OBJECT_UPGRADE_ROBOT_VACUUM_DOCK_MORE_AUTO_CLEAN: 'CommonStatisticId' = 173341 + OBJECT_UPGRADE_ROBOT_VACUUM_FASTER: 'CommonStatisticId' = 171242 + OBJECT_UPGRADE_ROBOT_VACUUM_MORE_STORAGE: 'CommonStatisticId' = 171243 + OBJECT_UPGRADE_ROBOT_VACUUM_QUIET: 'CommonStatisticId' = 171244 + OBJECT_UPGRADE_ROBOT_VACUUM_WET_VAC: 'CommonStatisticId' = 171246 + OBJECT_UPGRADE_ROCKET_SHIP_CARGO_BAY: 'CommonStatisticId' = 38971 + OBJECT_UPGRADE_ROCKET_SHIP_FUEL_STORAGE: 'CommonStatisticId' = 16689 + OBJECT_UPGRADE_ROCKET_SHIP_ION_CANNON: 'CommonStatisticId' = 16690 + OBJECT_UPGRADE_ROCKET_SHIP_LANDING_COMPUTER: 'CommonStatisticId' = 16691 + OBJECT_UPGRADE_ROCKET_SHIP_LANDING_STABILIZERS: 'CommonStatisticId' = 16692 + OBJECT_UPGRADE_ROCKET_SHIP_MANEUVERING_THRUSTERS: 'CommonStatisticId' = 16693 + OBJECT_UPGRADE_ROCKET_SHIP_RAM_SCOOP: 'CommonStatisticId' = 16694 + OBJECT_UPGRADE_ROCKET_SHIP_WORMHOLE_GENERATOR: 'CommonStatisticId' = 114437 + OBJECT_UPGRADE_SIM_RAY_MIND_CONTROL_CHANGE_CLOTHES: 'CommonStatisticId' = 114363 + OBJECT_UPGRADE_SIM_RAY_MIND_CONTROL_CLEAN: 'CommonStatisticId' = 114364 + OBJECT_UPGRADE_SIM_RAY_MIND_CONTROL_EAT: 'CommonStatisticId' = 114365 + OBJECT_UPGRADE_SIM_RAY_MIND_CONTROL_PANIC: 'CommonStatisticId' = 114366 + OBJECT_UPGRADE_SIM_RAY_MIND_CONTROL_SIT: 'CommonStatisticId' = 114367 + OBJECT_UPGRADE_SIM_RAY_MIND_CONTROL_SLEEP: 'CommonStatisticId' = 114368 + OBJECT_UPGRADE_SIM_RAY_TRANSFORM_OBJECT: 'CommonStatisticId' = 114361 + OBJECT_UPGRADE_SIM_RAY_TRANSFORM_SIM: 'CommonStatisticId' = 114362 + OBJECT_UPGRADE_SKETCHPAD_HIGH_PERFORMANCE: 'CommonStatisticId' = 198094 + OBJECT_UPGRADE_SLEEPING_POD_CIRCADIAN_TWEAKER: 'CommonStatisticId' = 200135 + OBJECT_UPGRADE_SLEEPING_POD_EMOTION_DEPRIVATION: 'CommonStatisticId' = 200137 + OBJECT_UPGRADE_SLEEPING_POD_FLOOR_LIGHTING: 'CommonStatisticId' = 200136 + OBJECT_UPGRADE_SLEEPING_POD_SUBLIMINAL_TRANSMITTER: 'CommonStatisticId' = 200122 + OBJECT_UPGRADE_SLEEPING_POD_UNBREAKABLE: 'CommonStatisticId' = 200138 + OBJECT_UPGRADE_SLEEPING_POD_UP_N_ATOMIZER: 'CommonStatisticId' = 200140 + OBJECT_UPGRADE_SPRINKLER_PUDDLE_PREVENTION: 'CommonStatisticId' = 184668 + OBJECT_UPGRADE_SPRINKLER_UNBREAKABLE: 'CommonStatisticId' = 184667 + OBJECT_UPGRADE_STEAM_ROOM_PRECISION_TEMPERATURE: 'CommonStatisticId' = 119102 + OBJECT_UPGRADE_STEREO: 'CommonStatisticId' = 118642 + OBJECT_UPGRADE_STREAMING_DRONE_BATTERY: 'CommonStatisticId' = 194536 + OBJECT_UPGRADE_STREAMING_DRONE_BREAKS_LESS: 'CommonStatisticId' = 194537 + OBJECT_UPGRADE_STREAMING_DRONE_VIDEO_QUALITY: 'CommonStatisticId' = 194538 + OBJECT_UPGRADE_TALKING_TOILET_BIDET_SHOW: 'CommonStatisticId' = 146240 + OBJECT_UPGRADE_TALKING_TOILET_CUSTOM_PERSONA: 'CommonStatisticId' = 135636 + OBJECT_UPGRADE_TALKING_TOILET_LOCK_BROKENNESS_ELECTRONIC: 'CommonStatisticId' = 141810 + OBJECT_UPGRADE_TALKING_TOILET_LOCK_BROKENNESS_PLUMBING: 'CommonStatisticId' = 141801 + OBJECT_UPGRADE_TALKING_TOILET_LOWER_BROKENNESS_ELECTRONIC: 'CommonStatisticId' = 141800 + OBJECT_UPGRADE_TALKING_TOILET_ROOM_DRYING: 'CommonStatisticId' = 132923 + OBJECT_UPGRADE_TALKING_TOILET_SELF_CLEANING: 'CommonStatisticId' = 132925 + OBJECT_UPGRADE_TALKING_TOILET_VFX_EMITTER: 'CommonStatisticId' = 132924 + OBJECT_UPGRADE_TELESCOPE_PRECISION_EYEPIECE: 'CommonStatisticId' = 9700 + OBJECT_UPGRADE_TRASH_CHUTE_NEVER_JAM: 'CommonStatisticId' = 141324 + OBJECT_UPGRADE_TREAD_MILL_ROCK_CLIMBING_WALL_SELF_REPAIRING: 'CommonStatisticId' = 165741 + OBJECT_UPGRADE_TV_SUPER_RECEPTION: 'CommonStatisticId' = 10516 + OBJECT_UPGRADE_UNBREAKABLE: 'CommonStatisticId' = 118644 + OBJECT_UPGRADE_VIDEO_GAME_CONSOLE_TELESPLOSION: 'CommonStatisticId' = 145555 + OBJECT_UPGRADE_VIDEO_GAME_CONSOLE_TIGHTEN_UP_GRAPHICS: 'CommonStatisticId' = 145557 + OBJECT_UPGRADE_VIDEO_GAME_CONSOLE_UNBREAKABLE: 'CommonStatisticId' = 145556 + OBJECT_UPGRADE_VIDEO_STATION_LIGHTS: 'CommonStatisticId' = 192501 + OBJECT_UPGRADE_VIDEO_STATION_STORAGE: 'CommonStatisticId' = 192500 + OBJECT_UPGRADE_VIDEO_STATION_UNBREAKABLE: 'CommonStatisticId' = 192499 + OBJECT_UPGRADE_WEATHER_CONTROLLER_CAPACITIVE_EFFICIENCY: 'CommonStatisticId' = 186466 + OBJECT_UPGRADE_WEATHER_CONTROLLER_CLIMATIC_HYDRATOR: 'CommonStatisticId' = 186464 + OBJECT_UPGRADE_WEATHER_CONTROLLER_GYROSCOPE_DURABILITY: 'CommonStatisticId' = 186460 + OBJECT_UPGRADE_WEATHER_CONTROLLER_HUMIDITY_CHILLER: 'CommonStatisticId' = 186463 + OBJECT_UPGRADE_WEATHER_CONTROLLER_MOISTURE_VAPORATOR: 'CommonStatisticId' = 186465 + OBJECT_UPGRADE_WEATHER_CONTROLLER_SELF_REPAIRING_NANITES: 'CommonStatisticId' = 186461 + OBJECT_UPGRADE_WEATHER_CONTROLLER_TEMPORAL_MODIFIER_UNIT: 'CommonStatisticId' = 186462 + OBJECT_UPGRADE_XRAY_MACHINE_AUTO_CALIBRATE: 'CommonStatisticId' = 109287 + OBJECT_UPGRADE_XRAY_MACHINE_NEVER_BREAKS: 'CommonStatisticId' = 109286 + OBJECT_VFX_MACHINE_CONTROL_UNIT: 'CommonStatisticId' = 193877 + OBJECT_VFX_MACHINE_TOGGLE: 'CommonStatisticId' = 193900 + OBJECT_VIDEO_RECORDING_POLISH: 'CommonStatisticId' = 192402 + OBJECT_VIDEO_RECORDING_QUALITY: 'CommonStatisticId' = 192412 + OBJECT_VIDEOS_UPLOADED: 'CommonStatisticId' = 203205 + OBJECT_VIOLIN_SOOTHING_STRINGS: 'CommonStatisticId' = 34552 + OBJECT_VIP_ROPE_RELATIONSHIP: 'CommonStatisticId' = 194781 + OBJECT_VOODOO_DOLL_RELATIONSHIP: 'CommonStatisticId' = 97150 + OBJECT_WATER_BUCKET_CAPACITY: 'CommonStatisticId' = 183213 + OBJECT_WEATHER_CONTROLLER_IN_USE: 'CommonStatisticId' = 187982 + OBJECT_WIND_CHIME_ANNOYING_CHIMES: 'CommonStatisticId' = 143516 + OBJECT_WIND_CHIME_SOOTHING_CHIMES: 'CommonStatisticId' = 143518 + OBJECT_WIND_CHIME_SOUNDS_OF_WIND: 'CommonStatisticId' = 141179 + OBJECT_WIND_CHIMES_ANIMATE: 'CommonStatisticId' = 140783 + OBJECT_WIND_CHIMES_TIMING: 'CommonStatisticId' = 140435 + OBJECT_XRAY_MACHINE_CALIBRATE: 'CommonStatisticId' = 105834 + OWNABLE_BUSINESS_ADVERTISING_INTERNET: 'CommonStatisticId' = 141297 + OWNABLE_BUSINESS_ADVERTISING_NEWSPAPER: 'CommonStatisticId' = 141295 + OWNABLE_BUSINESS_ADVERTISING_RADIO: 'CommonStatisticId' = 141296 + OWNABLE_BUSINESS_ADVERTISING_TV: 'CommonStatisticId' = 141298 + OWNABLE_BUSINESS_EMPLOYEE_SATISFACTION: 'CommonStatisticId' = 137205 + OWNABLE_BUSINESS_TRAINING_BRIEF: 'CommonStatisticId' = 143640 + OWNABLE_BUSINESS_TRAINING_EXTENSIVE: 'CommonStatisticId' = 143641 + OWNABLE_BUSINESS_TRAINING_STANDARD: 'CommonStatisticId' = 143636 + OWNABLE_RESTAURANT_CUSTOMER_QUALITY: 'CommonStatisticId' = 142184 + OWNABLE_RESTAURANT_CUSTOMER_STAR_RATING: 'CommonStatisticId' = 142545 + OWNABLE_RESTAURANT_CUSTOMER_VALUE: 'CommonStatisticId' = 142185 + OWNABLE_RESTAURANT_CUSTOMER_WAIT_TIME: 'CommonStatisticId' = 140530 + OWNABLE_RESTAURANT_EMPLOYEE_CHEF_COOK_STYLE_CAREFUL: 'CommonStatisticId' = 144017 + OWNABLE_RESTAURANT_EMPLOYEE_CHEF_COOK_STYLE_NORMAL: 'CommonStatisticId' = 144019 + OWNABLE_RESTAURANT_EMPLOYEE_CHEF_COOK_STYLE_QUICK: 'CommonStatisticId' = 144020 + OWNABLE_VET_CLINIC_CUSTOMER_VALUE_OF_SERVICE: 'CommonStatisticId' = 168448 + OWNABLE_VET_CLINIC_CUSTOMER_WAIT_TIME: 'CommonStatisticId' = 167884 + OWNABLE_VET_CLINIC_TRAINING_BRIEF: 'CommonStatisticId' = 167734 + OWNABLE_VET_CLINIC_TRAINING_EXTENSIVE: 'CommonStatisticId' = 167737 + OWNABLE_VET_CLINIC_TRAINING_STANDARD: 'CommonStatisticId' = 167741 + OWNABLE_VET_CLINIC_VET_MEDICINE_VENDING_MACHINE_INVENTORY_COUNT: 'CommonStatisticId' = 172459 + OWNABLE_VET_CUSTOMER_STAR_RATING: 'CommonStatisticId' = 158853 + PAPARAZZI_FULFILMENT: 'CommonStatisticId' = 196693 + PAPARAZZI_MELTDOWN: 'CommonStatisticId' = 191956 + PARENTING_CHANCE_CARDS_ADVENTURE_COOLDOWN: 'CommonStatisticId' = 167856 + PARENTING_SKILL_SUPER_PARENT: 'CommonStatisticId' = 160760 + PATH_OBSTACLE_CLEAR: 'CommonStatisticId' = 181047 + PATH_OBSTACLE_TEMPLE_LOCK: 'CommonStatisticId' = 178563 + PATH_OBSTACLE_TRAVEL_THROUGH_ADVENTURE: 'CommonStatisticId' = 175717 + PERFORMANCE_SPACE_LID: 'CommonStatisticId' = 143479 + PET_CAT_PREGNANCY_VOMIT_COUNT: 'CommonStatisticId' = 174482 + PET_EMOTION_TRIGGERS_ELDER_DROWSY: 'CommonStatisticId' = 160997 + PET_EMOTION_TRIGGERS_EXCITED: 'CommonStatisticId' = 164472 + PET_EMOTION_TRIGGERS_HYPER: 'CommonStatisticId' = 164475 + PET_EMOTION_TRIGGERS_IN_HEAT_CAT: 'CommonStatisticId' = 160498 + PET_EMOTION_TRIGGERS_IN_HEAT_DOG: 'CommonStatisticId' = 160519 + PET_FOOD_BOWL_FRESHNESS: 'CommonStatisticId' = 158892 + PET_HAIRY_TRAIT_SHED_COUNTER: 'CommonStatisticId' = 178058 + PET_OBSTACLE_COURSE_FAULTS: 'CommonStatisticId' = 170390 + PET_PHOTOGRAPHY_SIMSTAGRAM: 'CommonStatisticId' = 170340 + PET_WORLD_WALK_BYS_CAT_BEG: 'CommonStatisticId' = 165423 + PET_WORLD_WALK_BYS_CAT_FIND_OBJECT: 'CommonStatisticId' = 165416 + PET_WORLD_WALK_BYS_CAT_SLEEP: 'CommonStatisticId' = 165424 + PET_WORLD_WALK_BYS_CAT_SOCIALIZE: 'CommonStatisticId' = 165426 + PET_WORLD_WALK_BYS_DOG_BEG: 'CommonStatisticId' = 165414 + PET_WORLD_WALK_BYS_DOG_SLEEP: 'CommonStatisticId' = 165415 + PET_WORLD_WALK_BYS_DOG_SOCIALIZE: 'CommonStatisticId' = 165413 + PETS_CAT_SCRATCH_FURNITURE_OBJECT: 'CommonStatisticId' = 163404 + PETS_SELL_VALUE_AGGRESSIVE: 'CommonStatisticId' = 174211 + PETS_SELL_VALUE_FRIENDLY: 'CommonStatisticId' = 169906 + PETS_SELL_VALUE_LOYAL: 'CommonStatisticId' = 169905 + PETS_SELL_VALUE_NAUGHTY: 'CommonStatisticId' = 174210 + PETS_SELL_VALUE_PLAYFUL: 'CommonStatisticId' = 174209 + PETS_SELL_VALUE_SMART: 'CommonStatisticId' = 169907 + PETS_SELL_VALUE_STUBBORN: 'CommonStatisticId' = 174212 + PETS_SNIFF_NEW_OBJECT: 'CommonStatisticId' = 175857 + PETS_SPIN_LOW_BLADDER_BOWEL: 'CommonStatisticId' = 171061 + POISONED_ANCIENT_RELIC_CURSE: 'CommonStatisticId' = 179713 + POISONED_BIT_BY_SPIDER: 'CommonStatisticId' = 179715 + POISONED_GATE: 'CommonStatisticId' = 180017 + POISONED_GHOST_BELCH: 'CommonStatisticId' = 179719 + POISONED_POISON_DART: 'CommonStatisticId' = 179716 + POISONED_POISON_GAS: 'CommonStatisticId' = 180263 + POISONED_STUNG_BY_BEE: 'CommonStatisticId' = 179714 + POISONED_STUNG_BY_SCORPION: 'CommonStatisticId' = 179718 + POLITE_HUNGER: 'CommonStatisticId' = 27956 + PREGNANCY: 'CommonStatisticId' = 16640 + PREGNANCY_CAT: 'CommonStatisticId' = 169190 + PREGNANCY_HORSE: 'CommonStatisticId' = 323070 + PREGNANCY_CONTRACTION_MAX: 'CommonStatisticId' = 76975 + PREGNANCY_CONTRACTION_TIMER: 'CommonStatisticId' = 76973 + PREGNANCY_DISCOVERY: 'CommonStatisticId' = 16641 + PREGNANCY_DISCOVERY_PET: 'CommonStatisticId' = 169238 + PREGNANCY_DOG: 'CommonStatisticId' = 169191 + PREGNANCY_GENDER_CHANCE: 'CommonStatisticId' = 117011 + PRESENT_PILE_BIRTHDAY_COUNT: 'CommonStatisticId' = 188867 + PRESENT_PILE_PRESENT_AMOUNT: 'CommonStatisticId' = 180947 + PROGRAMMING_SKILL_APP_PROGRESS: 'CommonStatisticId' = 33284 + PROGRAMMING_SKILL_FREELANCE_PROGRESS: 'CommonStatisticId' = 33234 + PROGRAMMING_SKILL_GAME_PROGRESS: 'CommonStatisticId' = 36387 + PROGRAMMING_SKILL_PLUGIN_PROGRESS: 'CommonStatisticId' = 31410 + PROGRAMMING_SKILL_VIRUS_PROGRESS: 'CommonStatisticId' = 33259 + PTO: 'CommonStatisticId' = 111109 + RABBIT_HOLE_BRAMBLE_HERBICIDE_COOLDOWN: 'CommonStatisticId' = 103189 + RAIN_OBJECT_WETNESS: 'CommonStatisticId' = 183352 + RAIN_PET_WETNESS: 'CommonStatisticId' = 186244 + RAIN_SIM_WETNESS: 'CommonStatisticId' = 183350 + RAINBOW: 'CommonStatisticId' = 187940 + RANDOM: 'CommonStatisticId' = 161235 + RANKED_FAME: 'CommonStatisticId' = 188229 + RANKED_FAME_QUIRKS_A_SERIOUS_ACTOR: 'CommonStatisticId' = 199731 + RANKED_FAME_QUIRKS_BRUSHES_WITH_FAME: 'CommonStatisticId' = 199740 + RANKED_FAME_QUIRKS_EMOTION_BOMB: 'CommonStatisticId' = 199738 + RANKED_FAME_QUIRKS_FAN_MAIL: 'CommonStatisticId' = 199737 + RANKED_FAME_QUIRKS_JUICE_ENTHUSIAST: 'CommonStatisticId' = 199742 + RANKED_FAME_QUIRKS_NO_TOUCHING: 'CommonStatisticId' = 199739 + RANKED_FAME_QUIRKS_PAPARAZZI_DARLING: 'CommonStatisticId' = 199736 + RANKED_FAME_QUIRKS_PHONE_FANATIC: 'CommonStatisticId' = 199741 + RANKED_FAME_QUIRKS_PUBLIC_NUMBER: 'CommonStatisticId' = 199733 + RANKED_FAME_QUIRKS_REFINED_PALATE: 'CommonStatisticId' = 199735 + RANKED_FAME_QUIRKS_STAN: 'CommonStatisticId' = 199743 + RANKED_FAME_QUIRKS_VAIN_STREET: 'CommonStatisticId' = 199734 + RANKED_OCCULT_VAMPIRE_DO_NOT_DRINK_DEEPLY: 'CommonStatisticId' = 155468 + RANKED_OCCULT_VAMPIRE_DO_NOT_DRINK_WITHOUT_PERMISSION: 'CommonStatisticId' = 155644 + RANKED_OCCULT_VAMPIRE_SURVIVE_DAY_TRACKER: 'CommonStatisticId' = 155663 + RANKED_OCCULT_VAMPIRE_XP: 'CommonStatisticId' = 150071 + RANKED_REPUTATION: 'CommonStatisticId' = 192283 + RANKED_SOCIAL_NETWORK_FATIGUE_COUNTER: 'CommonStatisticId' = 200264 + RELATIONSHIP_TRACK_AUTHORITY: 'CommonStatisticId' = 161998 + RELATIONSHIP_TRACK_RIVALRY: 'CommonStatisticId' = 161999 + RELATIONSHIP_TRACK_SHORT_TERM_CONTEXT_INTERROGATION_TABLE_CALM: 'CommonStatisticId' = 103618 + RELATIONSHIP_TRACK_SHORT_TERM_CONTEXT_INTERROGATION_TABLE_DEFENSIVE: 'CommonStatisticId' = 103617 + RELATIONSHIP_TRACK_SHORT_TERM_CONTEXT_INTERROGATION_TABLE_FRIENDLY: 'CommonStatisticId' = 103613 + RELATIONSHIP_TRACK_SHORT_TERM_CONTEXT_INTERROGATION_TABLE_FURIOUS: 'CommonStatisticId' = 103616 + RELATIONSHIP_TRACK_SHORT_TERM_CONTEXT_INTERROGATION_TABLE_SHY: 'CommonStatisticId' = 103598 + RELATIONSHIP_TRACK_SHORT_TERM_CONTEXT_INTERROGATION_TABLE_SMUG: 'CommonStatisticId' = 103619 + RELATIONSHIP_TRACK_SHORT_TERM_CONTEXT_INTERROGATION_TABLE_SUSPICIOUS: 'CommonStatisticId' = 103612 + RELATIONSHIP_TRACK_SHORT_TERM_CONTEXT_INTERROGATION_TABLE_TENSE: 'CommonStatisticId' = 103615 + RELATIONSHIP_TRACK_SHORT_TERM_CONTEXT_INTERROGATION_TABLE_TERRIFIED: 'CommonStatisticId' = 103614 + RELATIONSHIP_TRACK_SHORT_TERM_CONTEXT_INTERROGATION_TABLE_WORRIED: 'CommonStatisticId' = 103620 + RELATIONSHIP_TRACK_SHORT_TERM_CONTEXT_RETAIL_PURCHASE_INTEREST: 'CommonStatisticId' = 111598 + RETAIL_ADVERTISE_ON_THE_WEB_LONG: 'CommonStatisticId' = 116021 + RETAIL_ADVERTISE_ON_THE_WEB_SHORT: 'CommonStatisticId' = 114453 + RETAIL_ADVERTISE_TV_LONG: 'CommonStatisticId' = 116024 + RETAIL_ADVERTISE_TV_SHORT: 'CommonStatisticId' = 114173 + RETAIL_EMPLOYEE_SATISFACTION: 'CommonStatisticId' = 112066 + RETAIL_PRICE_RANGE_MAX: 'CommonStatisticId' = 112493 + RETAIL_PRICE_RANGE_MIN: 'CommonStatisticId' = 112494 + RETAIL_PURCHASE_INTENT: 'CommonStatisticId' = 113505 + RETAIL_WAIT_TO_PURCHASE: 'CommonStatisticId' = 112136 + ROLL_UP_BUTTERFLY: 'CommonStatisticId' = 149258 + ROLL_UP_CITY_CLOUDS: 'CommonStatisticId' = 149268 + ROLL_UP_CITY_LAYERS: 'CommonStatisticId' = 149265 + ROLL_UP_CITY_LINES: 'CommonStatisticId' = 149266 + ROLL_UP_CITY_NIGHT: 'CommonStatisticId' = 149267 + ROLL_UP_CUL_BUTTERFLY: 'CommonStatisticId' = 149261 + ROLL_UP_CUL_FLOWER: 'CommonStatisticId' = 149262 + ROLL_UP_CUL_OCTOPUS: 'CommonStatisticId' = 149264 + ROLL_UP_CUL_PEACOCK: 'CommonStatisticId' = 149260 + ROLL_UP_GRAF_GOLD: 'CommonStatisticId' = 149269 + ROLL_UP_GRAF_GREEN: 'CommonStatisticId' = 149270 + ROLL_UP_TREES: 'CommonStatisticId' = 149259 + ROOMMATE_COUNTER: 'CommonStatisticId' = 200721 + SATELLITE_DISH_DEFLECT_VFX_COOLDOWN: 'CommonStatisticId' = 115909 + SATELLITE_DISH_HIVE_MIND_COOLDOWN: 'CommonStatisticId' = 107519 + SATELLITE_DISH_VFX_COOLDOWN: 'CommonStatisticId' = 115520 + SERUMS_TESTS_COMPLETED_AGE_AWAY: 'CommonStatisticId' = 104968 + SERUMS_TESTS_COMPLETED_ALIEN_AURA: 'CommonStatisticId' = 104969 + SERUMS_TESTS_COMPLETED_EMBIGGEN: 'CommonStatisticId' = 104978 + SERUMS_TESTS_COMPLETED_FIXERS_LUCK: 'CommonStatisticId' = 104979 + SERUMS_TESTS_COMPLETED_GHOST_GOO: 'CommonStatisticId' = 104980 + SERUMS_TESTS_COMPLETED_NEED_FIXER: 'CommonStatisticId' = 104981 + SERUMS_TESTS_COMPLETED_OX_STRENGTH: 'CommonStatisticId' = 104982 + SERUMS_TESTS_COMPLETED_REAPERS_FRIEND: 'CommonStatisticId' = 104970 + SERUMS_TESTS_COMPLETED_RED_HOT: 'CommonStatisticId' = 104971 + SERUMS_TESTS_COMPLETED_ROSE_PERFUME: 'CommonStatisticId' = 104972 + SERUMS_TESTS_COMPLETED_SLIMIFY: 'CommonStatisticId' = 104973 + SERUMS_TESTS_COMPLETED_SMART: 'CommonStatisticId' = 104974 + SERUMS_TESTS_COMPLETED_SNAKE_OIL: 'CommonStatisticId' = 104975 + SERUMS_TESTS_COMPLETED_SPARK_DRIVE: 'CommonStatisticId' = 104976 + SERUMS_TESTS_COMPLETED_SYNTHETIC_FOOD: 'CommonStatisticId' = 104977 + SERVICE_NPC_WAIT_FOR_WORK: 'CommonStatisticId' = 29694 + SICKNESS_BEHAVIOR: 'CommonStatisticId' = 169645 + SICKNESS_CRITICAL_DURATION_BARFING: 'CommonStatisticId' = 168431 + SICKNESS_CRITICAL_DURATION_EXTREME_LETHARGY: 'CommonStatisticId' = 168432 + SICKNESS_CRITICAL_DURATION_FLEAS: 'CommonStatisticId' = 168433 + SICKNESS_CRITICAL_DURATION_GLOWING_NOSE: 'CommonStatisticId' = 168434 + SICKNESS_CRITICAL_DURATION_GOLDEN_POOP: 'CommonStatisticId' = 168435 + SICKNESS_CRITICAL_DURATION_HOT_FEET: 'CommonStatisticId' = 168441 + SICKNESS_CRITICAL_DURATION_ICEY_FUR: 'CommonStatisticId' = 168436 + SICKNESS_CRITICAL_DURATION_MOUTH_MOTHS: 'CommonStatisticId' = 168437 + SICKNESS_CRITICAL_DURATION_RAINBOW_POOP: 'CommonStatisticId' = 168438 + SICKNESS_CRITICAL_DURATION_STINKY_FUR: 'CommonStatisticId' = 168440 + SICKNESS_CRITICAL_DURATION_UNCONTROLLABLE_DROOLING: 'CommonStatisticId' = 168439 + SICKNESS_DAYS_SINCE_LAST_SICK: 'CommonStatisticId' = 169731 + SICKNESS_SINCE_LAST_SICK_TIMER: 'CommonStatisticId' = 169732 + SICKNESS_SYSTEM_DOCTOR_EXAMS_RAN: 'CommonStatisticId' = 116636 + SICKNESS_SYSTEM_HOME_REMEDY: 'CommonStatisticId' = 108660 + SICKNESS_SYSTEM_ILLNESS_DURATION: 'CommonStatisticId' = 105481 + SICKNESS_SYSTEM_PATIENT_DIAGNOSIS: 'CommonStatisticId' = 107214 + SICKNESS_SYSTEM_PATIENT_EXAM_RESULTS: 'CommonStatisticId' = 107988 + SICKNESS_SYSTEM_PATIENT_EXAMS_RAN: 'CommonStatisticId' = 107999 + SICKNESS_SYSTEM_SURGERY_TABLE_PATIENT_TREATMENTS: 'CommonStatisticId' = 110400 + SICKNESS_SYSTEM_SYMPTOM_TRIGGER: 'CommonStatisticId' = 105528 + SIM_BODY_TEMPERATURE: 'CommonStatisticId' = 181210 + SIM_BUBBLE_BLOWER_EFFECTIVENESS: 'CommonStatisticId' = 135797 + SIM_EFFECTIVE_TEMPERATURE: 'CommonStatisticId' = 181204 + SIM_INFO_BASKETBALL_WINS: 'CommonStatisticId' = 147473 + SIM_INFO_OUTDOORS_CHECK: 'CommonStatisticId' = 76777 + SIM_INFO_TIME_SINCE_LAST_SLEPT: 'CommonStatisticId' = 33350 + SIM_INFO_TIME_SINCE_LAST_SOCIAL: 'CommonStatisticId' = 33351 + SIM_OBJECT_FAMILIARITY_BUBBLE_BLOWER: 'CommonStatisticId' = 134849 + SIM_OBJECT_FAMILIARITY_TALKING_TOILET: 'CommonStatisticId' = 134821 + SIM_OVERHEATING: 'CommonStatisticId' = 190848 + SIM_SWIMMING: 'CommonStatisticId' = 103887 + SIM_TO_PET_IMITATE_PET: 'CommonStatisticId' = 173475 + SITUATION_APB_ASKED_ABOUT_SUSPECT: 'CommonStatisticId' = 109995 + SITUATION_DANCE_FEVER: 'CommonStatisticId' = 74758 + SITUATION_SEASONAL_GO_SKATE: 'CommonStatisticId' = 181135 + SITUATION_SEASONAL_PLAY_IN_LEAVES: 'CommonStatisticId' = 181137 + SITUATION_SEASONAL_SNOW: 'CommonStatisticId' = 181492 + SKELETON: 'CommonStatisticId' = 175973 + SKELETON_JOKE_COUNT: 'CommonStatisticId' = 176171 + SKILL_ADULT_MAJOR_ACTING: 'CommonStatisticId' = 194727 + SKILL_ADULT_MAJOR_ARCHAEOLOGY: 'CommonStatisticId' = 174237 + SKILL_ADULT_MAJOR_BAKING: 'CommonStatisticId' = 104198 + SKILL_ADULT_MAJOR_BARTENDING: 'CommonStatisticId' = 16695 + SKILL_ADULT_MAJOR_CHARISMA: 'CommonStatisticId' = 16699 + SKILL_ADULT_MAJOR_COMEDY: 'CommonStatisticId' = 16698 + SKILL_ADULT_MAJOR_DJ_MIXING: 'CommonStatisticId' = 121612 + SKILL_ADULT_MAJOR_FABRICATION: 'CommonStatisticId' = 231908 + SKILL_ADULT_MAJOR_FISHING: 'CommonStatisticId' = 39397 + SKILL_ADULT_MAJOR_FLOWER_ARRANGING: 'CommonStatisticId' = 186703 + SKILL_ADULT_MAJOR_GARDENING: 'CommonStatisticId' = 16700 + SKILL_ADULT_MAJOR_GOURMET_COOKING: 'CommonStatisticId' = 16701 + SKILL_ADULT_MAJOR_GUITAR: 'CommonStatisticId' = 16702 + SKILL_ADULT_MAJOR_HANDINESS: 'CommonStatisticId' = 16704 + SKILL_ADULT_MAJOR_HERBALISM: 'CommonStatisticId' = 101920 + SKILL_ADULT_MAJOR_HOME_STYLE_COOKING: 'CommonStatisticId' = 16705 + SKILL_ADULT_MAJOR_LOGIC: 'CommonStatisticId' = 16706 + SKILL_ADULT_MAJOR_MISCHIEF: 'CommonStatisticId' = 16707 + SKILL_ADULT_MAJOR_PAINTING: 'CommonStatisticId' = 16708 + SKILL_ADULT_MAJOR_PARENTING: 'CommonStatisticId' = 160504 + SKILL_ADULT_MAJOR_PHOTOGRAPHY: 'CommonStatisticId' = 105774 + SKILL_ADULT_MAJOR_PIANO: 'CommonStatisticId' = 16709 + SKILL_ADULT_MAJOR_PIPE_ORGAN: 'CommonStatisticId' = 149665 + SKILL_ADULT_MAJOR_PROGRAMMING: 'CommonStatisticId' = 16703 + SKILL_ADULT_MAJOR_ROCKET_SCIENCE: 'CommonStatisticId' = 16710 + SKILL_ADULT_MAJOR_SINGING: 'CommonStatisticId' = 137811 + SKILL_ADULT_MAJOR_VETERINARIAN: 'CommonStatisticId' = 161190 + SKILL_ADULT_MAJOR_VIDEO_GAMING: 'CommonStatisticId' = 16712 + SKILL_ADULT_MAJOR_VIOLIN: 'CommonStatisticId' = 16713 + SKILL_ADULT_MAJOR_WELLNESS: 'CommonStatisticId' = 117858 + SKILL_ADULT_MAJOR_WRITING: 'CommonStatisticId' = 16714 + SKILL_ADULT_MINOR_DANCING: 'CommonStatisticId' = 128145 + SKILL_ADULT_MINOR_JUICE_FIZZING: 'CommonStatisticId' = 234806 + SKILL_ADULT_MINOR_LOCAL_CULTURE: 'CommonStatisticId' = 174687 + SKILL_ADULT_MINOR_MEDIA_PRODUCTION: 'CommonStatisticId' = 192655 + SKILL_BOWLING: 'CommonStatisticId' = 158659 + SKILL_CHARISMA_NEGOTIATE_PROMOTION_COOLDOWN: 'CommonStatisticId' = 37246 + SKILL_CHILD_CREATIVITY: 'CommonStatisticId' = 16718 + SKILL_CHILD_MENTAL: 'CommonStatisticId' = 16719 + SKILL_CHILD_MOTOR: 'CommonStatisticId' = 16720 + SKILL_CHILD_SOCIAL: 'CommonStatisticId' = 16721 + SKILL_CHOPSTICKS: 'CommonStatisticId' = 142593 + SKILL_DOG_TRAINING: 'CommonStatisticId' = 161220 + SKILL_FITNESS: 'CommonStatisticId' = 16659 + SKILL_FOOSBALL: 'CommonStatisticId' = 122854 + SKILL_HIDDEN_SKATING: 'CommonStatisticId' = 179925 + SKILL_HIDDEN_TREAD_MILL_ROCK_CLIMBING_WALL_CLIMB: 'CommonStatisticId' = 165900 + SKILL_HIDDEN_VAMPIRE_LORE: 'CommonStatisticId' = 149556 + SKILL_HORSE_SHOES: 'CommonStatisticId' = 104859 + SKILL_PET_POOP_CLEANUP: 'CommonStatisticId' = 161097 + SKILL_RETAIL_MAINTENANCE: 'CommonStatisticId' = 111904 + SKILL_RETAIL_SALES: 'CommonStatisticId' = 111902 + SKILL_RETAIL_WORK_ETHIC: 'CommonStatisticId' = 111903 + SKILL_SPICY_FOOD: 'CommonStatisticId' = 142592 + SKILL_THROWING_THINGS: 'CommonStatisticId' = 127868 + SKILL_TODDLER_COMMUNICATION: 'CommonStatisticId' = 140170 + SKILL_TODDLER_IMAGINATION: 'CommonStatisticId' = 140706 + SKILL_TODDLER_MOVEMENT: 'CommonStatisticId' = 136140 + SKILL_TODDLER_POTTY: 'CommonStatisticId' = 144913 + SKILL_TODDLER_THINKING: 'CommonStatisticId' = 140504 + SKILL_VIDEO_GAMING_BLICBLOCK: 'CommonStatisticId' = 31807 + SKILL_VIDEO_GAMING_HILLOCK: 'CommonStatisticId' = 31813 + SKILL_VIDEO_GAMING_INCREDIBLE_SPORTS: 'CommonStatisticId' = 31808 + SKILL_VIDEO_GAMING_MANIAC_MATCHUMS: 'CommonStatisticId' = 31811 + SKILL_VIDEO_GAMING_MARIA_SISTERS: 'CommonStatisticId' = 31809 + SKILL_VIDEO_GAMING_PARTY: 'CommonStatisticId' = 145448 + SKILL_VIDEO_GAMING_PLATFORMER: 'CommonStatisticId' = 145447 + SKILL_VIDEO_GAMING_RACING: 'CommonStatisticId' = 145450 + SKILL_VIDEO_GAMING_REFUGE: 'CommonStatisticId' = 31810 + SKILL_VIDEO_GAMING_ROAD_RIVAL: 'CommonStatisticId' = 31812 + SKILL_VIDEO_GAMING_RPG: 'CommonStatisticId' = 145449 + SKILL_VIDEO_GAMING_SIMS_FOREVER_RENAMED: 'CommonStatisticId' = 31806 + SMART_HUB_FRIENDSHIP_MAIN: 'CommonStatisticId' = 203686 + SOCIAL_CONTEXT_AWKWARDNESS: 'CommonStatisticId' = 24098 + SOCIAL_CONTEXT_FRIENDSHIP: 'CommonStatisticId' = 24099 + SOCIAL_CONTEXT_FUN: 'CommonStatisticId' = 24100 + SOCIAL_CONTEXT_ROMANCE: 'CommonStatisticId' = 24101 + SOCIAL_NETWORK_FOLLOWERS_TNS_TOTAL: 'CommonStatisticId' = 144940 + SPRING_CHALLENGE_2016_NPC_FERTILIZER_STOCK: 'CommonStatisticId' = 135535 + STUFFED_ANIMAL_LOVE: 'CommonStatisticId' = 8240 + STYLE_INFLUENCER_ARTICLE_PROGRESS: 'CommonStatisticId' = 198610 + STYLEBOARD_COMPLETION: 'CommonStatisticId' = 198120 + TEMPLE_EXCAVATION_SITE_PROGRESS: 'CommonStatisticId' = 183739 + TEMPLE_TRAP_VIEW: 'CommonStatisticId' = 183186 + TIME_MOOD_NEUTRAL_MAINTAINED: 'CommonStatisticId' = 77762 + TODDLER_DIAPER_LOAD: 'CommonStatisticId' = 140764 + TODDLER_JUNGLE_GYM_PLAY_PRETEND_COUNTER: 'CommonStatisticId' = 174394 + TODDLERS_CAREGIVER_PLAY_WITH_TODDLER: 'CommonStatisticId' = 157445 + TODDLERS_CAREGIVER_WATCH_TODDLER: 'CommonStatisticId' = 151787 + TODDLERS_WATCH: 'CommonStatisticId' = 144294 + TODDLERS_WILD_OUTSIDE_OR_INSIDE: 'CommonStatisticId' = 154270 + TOURIST_CELEBRITY_TILE_VIEW: 'CommonStatisticId' = 197022 + TRAIT_ACTIVE_ACTIVITY: 'CommonStatisticId' = 27458 + TRAIT_ACTIVE_TENSE_TIMER: 'CommonStatisticId' = 99491 + TRAIT_AMBITIOUS_NEED_TO_ADVANCE: 'CommonStatisticId' = 29116 + TRAIT_AUTONOMY_ACTIVE: 'CommonStatisticId' = 29105 + TRAIT_AUTONOMY_ART_LOVER: 'CommonStatisticId' = 28563 + TRAIT_AUTONOMY_BOOKWORM: 'CommonStatisticId' = 28597 + TRAIT_AUTONOMY_BRO: 'CommonStatisticId' = 29124 + TRAIT_AUTONOMY_CHILDHOOD_PHASE_LOUD: 'CommonStatisticId' = 165673 + TRAIT_AUTONOMY_CHILDHOOD_PHASE_REBELLIOUS: 'CommonStatisticId' = 165366 + TRAIT_AUTONOMY_CHILDISH: 'CommonStatisticId' = 29125 + TRAIT_AUTONOMY_CREATIVE: 'CommonStatisticId' = 28630 + TRAIT_AUTONOMY_DANCE_MACHINE: 'CommonStatisticId' = 126090 + TRAIT_AUTONOMY_EMOTIONAL_CONTROL: 'CommonStatisticId' = 160277 + TRAIT_AUTONOMY_EVIL: 'CommonStatisticId' = 29117 + TRAIT_AUTONOMY_FAMILY_ORIENTED: 'CommonStatisticId' = 29118 + TRAIT_AUTONOMY_FOODIE: 'CommonStatisticId' = 29084 + TRAIT_AUTONOMY_GEEK: 'CommonStatisticId' = 29107 + TRAIT_AUTONOMY_GENIUS: 'CommonStatisticId' = 29109 + TRAIT_AUTONOMY_GHOST: 'CommonStatisticId' = 115027 + TRAIT_AUTONOMY_GHOST_FROZEN: 'CommonStatisticId' = 187684 + TRAIT_AUTONOMY_GHOST_OVERHEAT: 'CommonStatisticId' = 187685 + TRAIT_AUTONOMY_GLUTTON: 'CommonStatisticId' = 29120 + TRAIT_AUTONOMY_GOOD: 'CommonStatisticId' = 29121 + TRAIT_AUTONOMY_GOOFBALL: 'CommonStatisticId' = 29110 + TRAIT_AUTONOMY_HATES_CHILDREN: 'CommonStatisticId' = 29129 + TRAIT_AUTONOMY_HOT_HEADED: 'CommonStatisticId' = 29104 + TRAIT_AUTONOMY_INSANE: 'CommonStatisticId' = 76587 + TRAIT_AUTONOMY_INSIDER: 'CommonStatisticId' = 125438 + TRAIT_AUTONOMY_JEALOUS: 'CommonStatisticId' = 124989 + TRAIT_AUTONOMY_KLEPTOMANIAC: 'CommonStatisticId' = 131787 + TRAIT_AUTONOMY_LAZY: 'CommonStatisticId' = 29111 + TRAIT_AUTONOMY_LIFE_SKILLS_BAD_MANNERS: 'CommonStatisticId' = 160850 + TRAIT_AUTONOMY_LONER: 'CommonStatisticId' = 77332 + TRAIT_AUTONOMY_LOVES_OUTDOORS: 'CommonStatisticId' = 77338 + TRAIT_AUTONOMY_MATERIALISTIC: 'CommonStatisticId' = 29153 + TRAIT_AUTONOMY_MEAN: 'CommonStatisticId' = 29112 + TRAIT_AUTONOMY_MUSIC_LOVER: 'CommonStatisticId' = 29113 + TRAIT_AUTONOMY_NEAT: 'CommonStatisticId' = 29114 + TRAIT_AUTONOMY_PARANOID: 'CommonStatisticId' = 203546 + TRAIT_AUTONOMY_ROMANTIC: 'CommonStatisticId' = 29106 + TRAIT_AUTONOMY_SELF_ABSORBED: 'CommonStatisticId' = 199605 + TRAIT_AUTONOMY_SLOB: 'CommonStatisticId' = 29123 + TRAIT_AUTONOMY_SNOB: 'CommonStatisticId' = 29151 + TRAIT_AUTONOMY_UNCONTROLLED_EMOTION: 'CommonStatisticId' = 160267 + TRAIT_AUTONOMY_WEATHER_PREFERENCE_LOVES_RAIN: 'CommonStatisticId' = 189201 + TRAIT_AUTONOMY_WEATHER_PREFERENCE_LOVES_SNOW: 'CommonStatisticId' = 189231 + TRAIT_BRO_BROXIMITY: 'CommonStatisticId' = 74073 + TRAIT_CAT_LOVER_NEAR_CATS: 'CommonStatisticId' = 158004 + TRAIT_COMMITMENT_ISSUES_CAREER_COMMITMENT: 'CommonStatisticId' = 37524 + TRAIT_COMMITMENT_ISSUES_RELATIONSHIP_COMMITMENT: 'CommonStatisticId' = 31262 + TRAIT_CREATIVE_CREATIVITY: 'CommonStatisticId' = 27162 + TRAIT_CREATIVE_TENSE_TIMER: 'CommonStatisticId' = 99719 + TRAIT_DANCE_MACHINE_DANCE_NEED: 'CommonStatisticId' = 126188 + TRAIT_DOG_LOVER_NEAR_DOGS: 'CommonStatisticId' = 158005 + TRAIT_EVIL_MISERY_NEARBY: 'CommonStatisticId' = 74224 + TRAIT_FAMILY_ORIENTED_FAMILY_TIME: 'CommonStatisticId' = 30687 + TRAIT_FAMILY_ORIENTED_MISSING_FAMILY_SAD_TIMER: 'CommonStatisticId' = 99795 + TRAIT_FAMILY_ORIENTED_NEAR_FAMILY: 'CommonStatisticId' = 74225 + TRAIT_FAMILY_ORIENTED_NEAR_FAMILY_HAPPY_TIMER: 'CommonStatisticId' = 99814 + TRAIT_FORTUNE_INVESTED_INTEREST_CHECK_TIMER: 'CommonStatisticId' = 27949 + TRAIT_GEEK_ALIEN_TV: 'CommonStatisticId' = 107152 + TRAIT_GEEK_GAMING_NEED: 'CommonStatisticId' = 27550 + TRAIT_GEEK_GAMING_NEED_BUFF_DECAY: 'CommonStatisticId' = 98070 + TRAIT_GEEK_GEEK_OUT: 'CommonStatisticId' = 39000 + TRAIT_GENIUS_MENTAL_STIMULATION: 'CommonStatisticId' = 28786 + TRAIT_GOOD_NEAR_POSITIVITY: 'CommonStatisticId' = 74226 + TRAIT_HATES_CHILDREN_NEAR_CHILDREN: 'CommonStatisticId' = 74227 + TRAIT_HATES_CHILDREN_NEAR_TODDLERS: 'CommonStatisticId' = 157196 + TRAIT_INSANE_INSANITY: 'CommonStatisticId' = 29131 + TRAIT_JEALOUS_MISSING_SO_SAD_TIMER: 'CommonStatisticId' = 124917 + TRAIT_JEALOUS_NEAR_SO: 'CommonStatisticId' = 124881 + TRAIT_JEALOUS_NEAR_SO_HAPPY_TIMER: 'CommonStatisticId' = 124918 + TRAIT_JEALOUS_SO_TIME: 'CommonStatisticId' = 124957 + TRAIT_KLEPTOMANIAC_NEED_TO_SWIPE: 'CommonStatisticId' = 132222 + TRAIT_LAZY_TV: 'CommonStatisticId' = 103226 + TRAIT_LONER_NEAR_LOW_RELATIONS: 'CommonStatisticId' = 74228 + TRAIT_LONER_SOLITUDE: 'CommonStatisticId' = 29122 + TRAIT_LOVES_THE_OUTDOORS: 'CommonStatisticId' = 29152 + TRAIT_LOVES_THE_OUTDOORS_AM_I_OUTSIDE: 'CommonStatisticId' = 75462 + TRAIT_LOVES_THE_OUTDOORS_TENSE_TIMER: 'CommonStatisticId' = 98963 + TRAIT_MATERIALISTIC_ADMIRE_NEED: 'CommonStatisticId' = 35959 + TRAIT_MATERIALISTIC_ADMIRE_OBJECT: 'CommonStatisticId' = 98882 + TRAIT_MORNING_PERSON_CHECK_ACTIVE: 'CommonStatisticId' = 97676 + TRAIT_MUSIC_LOVER_INSPIRED_BY_MUSIC: 'CommonStatisticId' = 74243 + TRAIT_MUSIC_LOVER_INSPIRED_PLAY: 'CommonStatisticId' = 74104 + TRAIT_MUSIC_LOVER_MUSIC_NEED: 'CommonStatisticId' = 29314 + TRAIT_NIGHT_OWL_CHECK_ACTIVE: 'CommonStatisticId' = 97703 + TRAIT_OCCULT_ALIEN_BRAIN_POWER: 'CommonStatisticId' = 103330 + TRAIT_PET_ACTIVE: 'CommonStatisticId' = 158207 + TRAIT_PET_AGGRESSIVE: 'CommonStatisticId' = 158810 + TRAIT_PET_CURIOUS: 'CommonStatisticId' = 158216 + TRAIT_PET_FRIENDLY: 'CommonStatisticId' = 158806 + TRAIT_PET_GLUTTON: 'CommonStatisticId' = 159988 + TRAIT_PET_HAIRY: 'CommonStatisticId' = 158814 + TRAIT_PET_HUNTER: 'CommonStatisticId' = 159986 + TRAIT_PET_INDEPENDENT: 'CommonStatisticId' = 158812 + TRAIT_PET_LAZY: 'CommonStatisticId' = 158208 + TRAIT_PET_NAUGHTY: 'CommonStatisticId' = 159987 + TRAIT_PET_PLAYFUL: 'CommonStatisticId' = 164048 + TRAIT_PET_PROTECTIVE: 'CommonStatisticId' = 158822 + TRAIT_PET_QUIRK_FEAR_COFFEE_MAKER: 'CommonStatisticId' = 161771 + TRAIT_PET_QUIRK_FEAR_COMPUTER: 'CommonStatisticId' = 161772 + TRAIT_PET_QUIRK_FEAR_COOKING: 'CommonStatisticId' = 161773 + TRAIT_PET_QUIRK_FEAR_DISHWASHER: 'CommonStatisticId' = 161774 + TRAIT_PET_QUIRK_FEAR_FIRE: 'CommonStatisticId' = 161776 + TRAIT_PET_QUIRK_FEAR_FITNESS_EQUIPMENT: 'CommonStatisticId' = 161778 + TRAIT_PET_QUIRK_FEAR_GAMING: 'CommonStatisticId' = 161780 + TRAIT_PET_QUIRK_FEAR_INSTRUMENT: 'CommonStatisticId' = 161781 + TRAIT_PET_QUIRK_FEAR_MICROWAVE: 'CommonStatisticId' = 161782 + TRAIT_PET_QUIRK_FEAR_ROBOT_VACUUM: 'CommonStatisticId' = 171322 + TRAIT_PET_QUIRK_FEAR_SHOWER: 'CommonStatisticId' = 161783 + TRAIT_PET_QUIRK_FEAR_STEREO: 'CommonStatisticId' = 161784 + TRAIT_PET_QUIRK_FEAR_TOILET: 'CommonStatisticId' = 161785 + TRAIT_PET_QUIRK_FEAR_TV: 'CommonStatisticId' = 161786 + TRAIT_PET_QUIRK_OBSESS_COFFEE_MAKER: 'CommonStatisticId' = 159259 + TRAIT_PET_QUIRK_OBSESS_COMPUTER: 'CommonStatisticId' = 159263 + TRAIT_PET_QUIRK_OBSESS_COOKING: 'CommonStatisticId' = 159253 + TRAIT_PET_QUIRK_OBSESS_DISHWASHER: 'CommonStatisticId' = 159255 + TRAIT_PET_QUIRK_OBSESS_DOORBELL: 'CommonStatisticId' = 160803 + TRAIT_PET_QUIRK_OBSESS_FIRE: 'CommonStatisticId' = 159256 + TRAIT_PET_QUIRK_OBSESS_FISH_TANK: 'CommonStatisticId' = 159261 + TRAIT_PET_QUIRK_OBSESS_FITNESS_EQUIPMENT: 'CommonStatisticId' = 159258 + TRAIT_PET_QUIRK_OBSESS_FRIDGE: 'CommonStatisticId' = 159266 + TRAIT_PET_QUIRK_OBSESS_GAMING: 'CommonStatisticId' = 159260 + TRAIT_PET_QUIRK_OBSESS_INSTRUMENT: 'CommonStatisticId' = 159254 + TRAIT_PET_QUIRK_OBSESS_MICROWAVE: 'CommonStatisticId' = 159257 + TRAIT_PET_QUIRK_OBSESS_PET_MINOR_CAGE: 'CommonStatisticId' = 184412 + TRAIT_PET_QUIRK_OBSESS_ROBOT_VACUUM: 'CommonStatisticId' = 171321 + TRAIT_PET_QUIRK_OBSESS_SHOWER: 'CommonStatisticId' = 159265 + TRAIT_PET_QUIRK_OBSESS_STEREO: 'CommonStatisticId' = 159252 + TRAIT_PET_QUIRK_OBSESS_SWIMMING: 'CommonStatisticId' = 171913 + TRAIT_PET_QUIRK_OBSESS_TOILET: 'CommonStatisticId' = 159264 + TRAIT_PET_QUIRK_OBSESS_TV: 'CommonStatisticId' = 158819 + TRAIT_PET_SKITTISH: 'CommonStatisticId' = 158808 + TRAIT_PET_SMART: 'CommonStatisticId' = 158811 + TRAIT_PET_STUBBORN: 'CommonStatisticId' = 158217 + TRAIT_PET_VOCAL: 'CommonStatisticId' = 158809 + TRAIT_PET_WANDERLUST: 'CommonStatisticId' = 158709 + TRAIT_PLANT_SIM_EAT_TIMER: 'CommonStatisticId' = 162818 + TRAIT_PLANT_SIM_TIMER: 'CommonStatisticId' = 164593 + TRAIT_ROMANTIC_AFFECTION: 'CommonStatisticId' = 27519 + TRAIT_SELF_ABSORBED_OUT_OF_SPOTLIGHT_TIMER: 'CommonStatisticId' = 199573 + TRAIT_SNOB_NEAR_SNOBS: 'CommonStatisticId' = 74229 + TRAIT_THE_KNACK_UPGRADE_TIMER: 'CommonStatisticId' = 99841 + TRAIT_TODDLER_ANGELIC_RANDOMLY_GETS_HAPPY: 'CommonStatisticId' = 143246 + TRAIT_TODDLER_AUTONOMY_ANGELIC: 'CommonStatisticId' = 143221 + TRAIT_TODDLER_AUTONOMY_CHARMER: 'CommonStatisticId' = 143230 + TRAIT_TODDLER_AUTONOMY_CLINGY: 'CommonStatisticId' = 143223 + TRAIT_TODDLER_AUTONOMY_FUSSY: 'CommonStatisticId' = 143231 + TRAIT_TODDLER_AUTONOMY_INDEPENDENT: 'CommonStatisticId' = 143232 + TRAIT_TODDLER_AUTONOMY_INQUISITIVE: 'CommonStatisticId' = 143233 + TRAIT_TODDLER_AUTONOMY_SILLY: 'CommonStatisticId' = 143234 + TRAIT_TODDLER_AUTONOMY_WILD: 'CommonStatisticId' = 143235 + TRAIT_TODDLER_CHARMER_NO_SOCIALIZATION_SADNESS: 'CommonStatisticId' = 143261 + TRAIT_TODDLER_CLINGY_NO_PARENTS_SADNESS: 'CommonStatisticId' = 143345 + TRAIT_TODDLER_INDEPENDENT_NO_PARENTS_HAPPINESS: 'CommonStatisticId' = 143344 + TRAIT_TODDLER_INQUISITIVE_NO_THINKING_SADNESS: 'CommonStatisticId' = 143342 + TRAIT_TODDLER_SILLY_RANDOMLY_GETS_PLAYFUL: 'CommonStatisticId' = 143288 + TRAIT_TODDLER_WILD_RANDOMLY_GETS_ENERGY: 'CommonStatisticId' = 143294 + TURNS: 'CommonStatisticId' = 16726 + TV_CHANNEL_SURF_COOLDOWN: 'CommonStatisticId' = 130211 + UMBRELLA_BREAK: 'CommonStatisticId' = 186447 + VAMPIRE_SUN_EXPOSURE: 'CommonStatisticId' = 151449 + VAULT_WALK_IN_SAFE_SIMOLEONS: 'CommonStatisticId' = 193396 + VET_STRESS_FAILS_CUMULATIVE: 'CommonStatisticId' = 178675 + VET_TREATMENT_DISCOVERY: 'CommonStatisticId' = 158913 + VET_TREATMENT_PREVENT_STRESS: 'CommonStatisticId' = 177681 + VET_TREATMENT_STRESS: 'CommonStatisticId' = 158956 + VET_TREATMENT_STRESS_CUMULATIVE: 'CommonStatisticId' = 168206 + VIDEO_GAME_CONSOLE_NUMBER_OF_PLAYERS: 'CommonStatisticId' = 152671 + VIDEO_GAMING_SKILL_GAMED_OUT: 'CommonStatisticId' = 31760 + VIDEO_GAMING_SKILL_GOOD_SESSION: 'CommonStatisticId' = 38981 + WALK_DOG_WAIT_AROUND: 'CommonStatisticId' = 173999 + WATCH_CAT: 'CommonStatisticId' = 166989 + WATCH_DOG: 'CommonStatisticId' = 166994 + WEDDING_PROGRESS: 'CommonStatisticId' = 16643 + WOODWORK_FURNITURE: 'CommonStatisticId' = 16644 + WOODWORK_FURNITURE_CURVED: 'CommonStatisticId' = 16645 + WOODWORK_MUSIC: 'CommonStatisticId' = 16646 + WOODWORK_SCULPTURE_LARGE: 'CommonStatisticId' = 16647 + WOODWORK_SCULPTURE_SMALL: 'CommonStatisticId' = 16648 + WOOHOO_ENERGY: 'CommonStatisticId' = 16649 + WRITING_SKILL_LITERARY_DIGEST: 'CommonStatisticId' = 35340 diff --git a/Scripts/s4ap/sims4communitylib/enums/strings_enum.py b/Scripts/s4ap/sims4communitylib/enums/strings_enum.py new file mode 100644 index 0000000..af3295d --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/strings_enum.py @@ -0,0 +1,269 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonStringId(CommonInt): + """Identifiers for localization strings. + + .. note:: These identifiers point to strings within String Tables within package files. + + """ + INVALID: 'CommonStringId' = 0 + # Notifications + EXCEPTION_OCCURRED_TITLE: 'CommonStringId' = 3506527463 + EXCEPTION_OCCURRED_TITLE_FOR_MOD: 'CommonStringId' = 1541569535 + # 0.String + EXCEPTION_OCCURRED_TEXT: 'CommonStringId' = 1656389837 + + # Dialog + OK: 'CommonStringId' = 3648501874 + OK_ALL_CAPS: 'CommonStringId' = 1102906806 + CANCEL: 'CommonStringId' = 3497542682 + CANCEL_ALL_CAPS: 'CommonStringId' = 1249800636 + + # Navigation + NEXT: 'CommonStringId' = 982796106 + PREVIOUS: 'CommonStringId' = 4210670582 + # Tokens: {0.String} + GO_TO_STRING: 'CommonStringId' = 3934117375 + + # Text + # Tokens: {0.String} + TEXT_WITH_GREEN_COLOR: 'CommonStringId' = 3458194999 + # Tokens: {0.String} + TEXT_WITH_RED_COLOR: 'CommonStringId' = 835489330 + # Tokens: {0.String} + TEXT_WITH_BLUE_COLOR: 'CommonStringId' = 1505840180 + # Tokens: {0.String} + TEXT_WITH_YELLOW_COLOR: 'CommonStringId' = 3457894271 + # Tokens: {0.String} + TEXT_WITH_ORANGE_COLOR: 'CommonStringId' = 2567694686 + + # Ages + BABY: 'CommonStringId' = 4016862175 + INFANT: 'CommonStringId' = 0xD0D04D65 + TODDLER: 'CommonStringId' = 3252370736 + CHILD: 'CommonStringId' = 2993678259 + TEEN: 'CommonStringId' = 1166433319 + YOUNG_ADULT: 'CommonStringId' = 2053658442 + ADULT: 'CommonStringId' = 1747466136 + ELDER: 'CommonStringId' = 685867388 + + # Gender + MALE: 'CommonStringId' = 434606820 + FEMALE: 'CommonStringId' = 2933657479 + + # Species + HUMAN: 'CommonStringId' = 3519680994 + SMALL_DOG: 'CommonStringId' = 698804483 + LARGE_DOG: 'CommonStringId' = 1545624565 + CAT: 'CommonStringId' = 1720023562 + FOX: 'CommonStringId' = 0xCE739947 + HORSE: 'CommonStringId' = 0x773BB19E + + S4CL_ALIEN: 'CommonStringId' = 0x340EA312 + S4CL_GHOST: 'CommonStringId' = 0xEFCD14BE + S4CL_MERMAID: 'CommonStringId' = 0x9E3A9746 + S4CL_NON_OCCULT: 'CommonStringId' = 0x2763B1A0 + S4CL_PLANT_SIM: 'CommonStringId' = 0x64E66FA1 + S4CL_ROBOT: 'CommonStringId' = 0x730D2277 + S4CL_SCARECROW: 'CommonStringId' = 0x3AFF1B32 + S4CL_SKELETON: 'CommonStringId' = 0xCF5256A8 + S4CL_VAMPIRE: 'CommonStringId' = 0x760EC7C9 + S4CL_WEREWOLF: 'CommonStringId' = 0xA3E400E6 + S4CL_WITCH: 'CommonStringId' = 0x2D55956A + S4CL_HOUSEHOLD: 'CommonStringId' = 0x846D3A8C + S4CL_HOUSEHOLD_DESCRIPTION: 'CommonStringId' = 0xC04E5A9E + S4CL_NON_HOUSEHOLD: 'CommonStringId' = 0xC3AAF6A2 + S4CL_NON_HOUSEHOLD_DESCRIPTION: 'CommonStringId' = 0xC07E9015 + S4CL_CURRENTLY_CONTROLLED: 'CommonStringId' = 0x0EF5C39D + S4CL_CURRENTLY_CONTROLLED_DESCRIPTION: 'CommonStringId' = 0xBF7B9D74 + + # Pregnancy + GET_PREGNANT: 'CommonStringId' = 3694037554 + GET_OTHER_PREGNANT: 'CommonStringId' = 3780444441 + CANNOT_EDIT_PREGNANT_SIMS: 'CommonStringId' = 1715308569 + PREGNANT_OUTCOME: 'CommonStringId' = 3717297329 + + # Gender Options + TOILET_USE_STANDING: 'CommonStringId' = 3730566822 + TOILET_USE_SITTING: 'CommonStringId' = 4265081704 + SEXUAL_ORIENTATION: 'CommonStringId' = 0xB4F0EDC8 + THIS_SIM_IS_ROMANTICALLY_ATTRACTED_TO: 'CommonStringId' = 0xF808D0AB + THIS_SIM_IS_EXPLORING_ROMANTICALLY: 'CommonStringId' = 0x52609912 + THIS_SIM_IS_INTERESTED_IN_WOOHOO_WITH: 'CommonStringId' = 0x4790F2DC + + # Misc Text + CUSTOM_GENDER_SETTINGS: 'CommonStringId' = 2156245727 + CLOTHING_PREFERENCE: 'CommonStringId' = 611620004 + MASCULINE: 'CommonStringId' = 585998164 + FEMININE: 'CommonStringId' = 667254132 + PHYSICAL_FRAME: 'CommonStringId' = 2574825855 + ZERO_THROUGH_NINE = 0x8FE40C44 + + # Store + THIS_REWARD_IS_NOT_AVAILABLE_FOR_YOUR_SIM_OR_IT_IS_ALREADY_OWNED_BY_YOUR_SIM = 0x0709B9CC + INSUFFICIENT_POINTS = 0x67D91493 + + # Text + # Tokens: {0.String} + STRING_NOT_FOUND_WITH_IDENTIFIER: 'CommonStringId' = 3037244137 + + # Test + TESTING_TEST_BUTTON_ONE: 'CommonStringId' = 367590350 + TESTING_TEST_BUTTON_TWO: 'CommonStringId' = 367590349 + TESTING_SOME_TEXT_FOR_TESTING: 'CommonStringId' = 1352970207 + TESTING_TEST_TEXT_NO_TOKENS: 'CommonStringId' = 3987872118 + # Tokens: {0.SimFirstName} {0.SimLastName} + TESTING_TEST_TEXT_WITH_SIM_FIRST_AND_LAST_NAME: 'CommonStringId' = 4280406738 + # Tokens: {0.String} + TESTING_TEST_TEXT_WITH_STRING_TOKEN: 'CommonStringId' = 2977195159 + # Tokens: {0.Number} + TESTING_TEST_TEXT_WITH_NUMBER_TOKEN: 'CommonStringId' = 4138001347 + + # S4CL + S4CL_SIMS_4_COMMUNITY_LIBRARY: 'CommonStringId' = 1638558923 + S4CL_LOG_ALL_INTERACTIONS: 'CommonStringId' = 3133049591 + # Tokens: {0.String} + S4CL_DONE_LOGGING_ALL_INTERACTIONS: 'CommonStringId' = 207690817 + + # Sim Actions. + S4CL_OBJECT_IS_IN_USE = 0x7EC77EF6 + # Tokens: {0.SimFirstName} + S4CL_SIM_NOT_ALLOWED_THERE = 0x48245F2A + # Tokens: {0.SimFirstName} + S4CL_SIM_CANNOT_REACH_THAT_SPOT = 0x6B324A52 + # Tokens: {0.SimFirstName} {1.SimFirstName} + S4CL_SIM_CANNOT_REACH_SIM = 0x6B324A52 + # Tokens: {0.SimFirstName} + S4CL_NOT_ENOUGH_ROOM_FOR_SIM_HERE = 0x36EB7A72 + # Tokens: {0.SimFirstName} + S4CL_SIM_IS_NOT_PREGNANT: 'CommonStringId' = 0x4992E851 + # Tokens: {0.SimFirstName} {0.SimLastName} (Sim) + S4CL_SIM_CANNOT_BE_PICKED_UP = 0xAB3DD412 + + # Tokens: {0.SimFirstName} + S4CL_SIM_ALREADY_HAS_THIS_TRAIT = 0x854F2F29 + # Tokens: {0.SimFirstName} + S4CL_SIM_DOES_NOT_HAVE_THIS_TRAIT = 0x663E6FD7 + + S4CL_YES: 'CommonStringId' = 0x3A6189A6 + S4CL_NO: 'CommonStringId' = 0x6377188C + S4CL_RANDOM: 'CommonStringId' = 0xB5ADADF0 + S4CL_CONFIRMATION: 'CommonStringId' = 0x963ACF86 + S4CL_GO_BACK = 0xD74B6B28 + S4CL_NONE = 0x2CA33BDB + S4CL_NO_SIMS = 0x90F0B600 + S4CL_NO_OPTIONS_WILL_BE_INCLUDED = 0xF3E7F3A3 + S4CL_ALL = 0x419C2C6E + S4CL_ALL_SIMS = 0x6B670346 + S4CL_ALL_OPTIONS_WILL_BE_INCLUDED = 0x36CAAB74 + S4CL_ANY = 0x3F9C28A5 + S4CL_DECLINED = 0x5FD633CB + S4CL_ACCEPTED = 0xB667ABF6 + S4CL_ACCEPT = 0xD0F420D1 + S4CL_DECLINE = 0xA60FC6F5 + S4CL_DEFAULT = 0x2EA8FB98 + S4CL_REMOVE_ALL = 0x5C6C2580 + S4CL_REMOVE = 0x8B3681B1 + S4CL_NOT_IMPLEMENTED = 0x54860E10 + S4CL_CUSTOM_BREED = 0x599432EA + + # Species + S4CL_DOG: 'CommonStringId' = 0x20953C2D + + # Separators + # {0.String}{1.String} + S4CL_COMBINE_TWO_STRINGS: 'CommonStringId' = 4217460952 + # Tokens: {0.String}: {1.String} + STRING_COLON_SPACE_STRING = 0x6284ACBA + # Tokens: {0.String}, {1.String} + STRING_COMMA_SPACE_STRING = 0x1429B07C + # Tokens: {0.String} {1.String} + STRING_SPACE_STRING = 0x0699D5F4 + # Tokens: {0.String} ({1.String}) + STRING_SPACE_PARENTHESIS_SURROUNDED_STRING = 0x1A406429 + # Tokens: {0.String}\n{1.String} + STRING_NEWLINE_STRING = 0xCE1E042E + # Tokens: {0.String}\n\n{1.String} + STRING_NEWLINE_NEWLINE_STRING = 0xBA331D00 + # Tokens: {0.String}-{1.String} + STRING_HYPHEN_STRING = 0x032A81F9 + # Tokens: {0.String} are {1.String} + S4CL_STRING_ARE_STRING = 0x92AF2862 + # Tokens: {0.String} is {1.String} + S4CL_STRING_IS_STRING = 0xC1166AC4 + # Tokens: {0.String}+{1.String} + S4CL_STRING_PLUS_STRING = 0x82ED46EB + # Tokens: {0.String} or {1.String} + S4CL_STRING_OR_STRING = 0x1DC61DF5 + # Tokens: {0.String}, or {1.String} + S4CL_STRING_COMMA_SPACE_OR_STRING = 0x34E0269D + # Tokens: {0.String} and {1.String} + S4CL_STRING_AND_STRING = 0xCFB35A51 + # Tokens: {0.String}, and {1.String} + S4CL_STRING_COMMA_SPACE_AND_STRING = 0x419E6969 + + # String Modifiers + # Tokens: ({0.String}) + S4CL_PARENTHESIS_SURROUNDED_STRING = 0xD7FDCAF5 + + S4CL_PLEASE_WAIT = 0xF2237D1E + S4CL_RANDOMIZATION_COMPLETE = 0x8ABA94C5 + + S4CL_PREGNANCY = 0x3F70BCAA + + S4CL_RESTART_REQUIRED = 0x955D0179 + S4CL_CHANGES_MADE_RESTART_REQUIRED_DESCRIPTION = 0x6B5119FB + # (From Debug) + S4CL_BUFF_REASON_FROM_DEBUG = 0x38C2E6F7 + + # Purchase + S4CL_PURCHASE_SUCCESSFUL = 0xF3C59252 + S4CL_YOUR_PURCHASED_ITEMS_ARE_ON_THE_WAY = 0x5A8D580D + S4CL_YOUR_PURCHASED_ITEMS_ARE_IN_YOUR_INVENTORY = 0xF33F9A95 + S4CL_TOO_EXPENSIVE = 0x59F9C698 + + S4CL_THIS_FEATURE_IS_NOT_YET_IMPLEMENTED = 0x556801EE + + # Sim Name + # Tokens: {0.SimFirstName} {0.SimLastName} (Sim One) + S4CL_SIM_NAME = 0xAC8F626F + # Tokens: {0.SimFirstName} {0.SimLastName} (Sim One) {1.SimFirstName} {1.SimLastName} (Sim Two) + S4CL_SIM_NAME_AND_SIM_NAME = 0xD8740FE4 + # Tokens: {0.String} (A String) {1.SimFirstName} {1.SimLastName} (The Last Sim) + S4CL_STRING_COMMA_SPACE_AND_SIM_NAME = 0x2EACE203 + # Tokens: {0.SimFirstName} {0.SimLastName} (The First Sim) {1.String} (A String) + S4CL_SIM_NAME_COMMA_SPACE_AND_STRING = 0x2A8148D8 + + # Tokens: {0.String} + S4CL_UID_STRING = 0x0313D2A0 + # Tokens: {0.String} (Current) + S4CL_CURRENT_STRING = 0x860F13B5 + # Tokens: {0.String} (Count) + S4CL_COUNT_STRING = 0x423122EB + # Tokens: {0.String} (Error Message) + S4CL_ERROR_STRING = 0xA1C925BC + # Tokens: {0.String} (Failed Message) + S4CL_FAILED_STRING = 0x0F818D6F + # Tokens: {0.String} (Failure Message) + S4CL_FAILURE_STRING = 0x33A94544 + # Tokens: {0.String} (Success Message) + S4CL_SUCCESS_STRING = 0xC6D15497 + # Tokens: {0.String} (String Message) + S4CL_EXCLAMATION_EXCLAMATION_STRING = 0xA07FA6C6 + + S4CL_LEFT = 0x003EB432 + S4CL_RIGHT = 0xE816F049 + S4CL_FRONT = 0x4B21A032 + S4CL_BACK = 0x5CF9CF48 + S4CL_TOP = 0x406CCC4A + S4CL_BOTTOM = 0xE864BA60 + S4CL_UP = 0x5C770DAE + S4CL_DOWN = 0x87EDD469 diff --git a/Scripts/s4ap/sims4communitylib/enums/tags_enum.py b/Scripts/s4ap/sims4communitylib/enums/tags_enum.py new file mode 100644 index 0000000..40c3e56 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/tags_enum.py @@ -0,0 +1,4867 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +# noinspection SpellCheckingInspection +class CommonGameTag(CommonInt): + """Identifiers for vanilla game tags (These have been gathered dynamically from the :class:`.Tag` enum). + + """ + INVALID: 'CommonGameTag' = 0 + ACNE_LEVEL_HEAVY: 'CommonGameTag' = 114722 + ACNE_LEVEL_LIGHT: 'CommonGameTag' = 114724 + ACNE_LEVEL_MEDIUM: 'CommonGameTag' = 114723 + ACNE_LEVEL_NONE: 'CommonGameTag' = 114732 + AGE_APPROPRIATE_ADULT: 'CommonGameTag' = 84 + AGE_APPROPRIATE_CHILD: 'CommonGameTag' = 85 + AGE_APPROPRIATE_ELDER: 'CommonGameTag' = 72 + AGE_APPROPRIATE_INFANT: 'CommonGameTag' = 2912 + AGE_APPROPRIATE_TEEN: 'CommonGameTag' = 291 + AGE_APPROPRIATE_TODDLER: 'CommonGameTag' = 1657 + AGE_APPROPRIATE_YOUNG_ADULT: 'CommonGameTag' = 71 + APPEARANCE_MODIFIER_HAIR_MAKEUP_CHAIR_HAIR_STYLE: 'CommonGameTag' = 61494 + APPEARANCE_MODIFIER_HAIR_MAKEUP_CHAIR_MAKEUP: 'CommonGameTag' = 61609 + APPROPRIATENESS_BARTENDING: 'CommonGameTag' = 406 + APPROPRIATENESS_BATHING: 'CommonGameTag' = 402 + APPROPRIATENESS_CAKE: 'CommonGameTag' = 605 + APPROPRIATENESS_CALL_TO_MEAL: 'CommonGameTag' = 1170 + APPROPRIATENESS_CLEANING: 'CommonGameTag' = 404 + APPROPRIATENESS_COMPUTER: 'CommonGameTag' = 1373 + APPROPRIATENESS_COOKING: 'CommonGameTag' = 405 + APPROPRIATENESS_DANCING: 'CommonGameTag' = 603 + APPROPRIATENESS_DESK_CLEAN: 'CommonGameTag' = 2838 + APPROPRIATENESS_EATING: 'CommonGameTag' = 604 + APPROPRIATENESS_FRONT_DESK: 'CommonGameTag' = 12413 + APPROPRIATENESS_GRAB_SNACK: 'CommonGameTag' = 939 + APPROPRIATENESS_GUEST: 'CommonGameTag' = 367 + APPROPRIATENESS_HIRED_WORKER: 'CommonGameTag' = 368 + APPROPRIATENESS_HOST: 'CommonGameTag' = 370 + APPROPRIATENESS_NOT_DURING_WORK: 'CommonGameTag' = 1274 + APPROPRIATENESS_NOT_DURING_WORK_LUNCH: 'CommonGameTag' = 1275 + APPROPRIATENESS_PHONE: 'CommonGameTag' = 1594 + APPROPRIATENESS_PHONE_GAME: 'CommonGameTag' = 1626 + APPROPRIATENESS_PLAYING: 'CommonGameTag' = 1539 + APPROPRIATENESS_PLAY_INSTRUMENT: 'CommonGameTag' = 2156 + APPROPRIATENESS_READ_BOOKS: 'CommonGameTag' = 1276 + APPROPRIATENESS_SERVICE_NPC: 'CommonGameTag' = 369 + APPROPRIATENESS_SHOWER: 'CommonGameTag' = 352 + APPROPRIATENESS_SINGING: 'CommonGameTag' = 55385 + APPROPRIATENESS_SLEEPING: 'CommonGameTag' = 403 + APPROPRIATENESS_SNOW_SHOVELING: 'CommonGameTag' = 69706 + APPROPRIATENESS_SOCIAL_PICKER: 'CommonGameTag' = 1645 + APPROPRIATENESS_STEREO: 'CommonGameTag' = 530 + APPROPRIATENESS_TIP: 'CommonGameTag' = 2155 + APPROPRIATENESS_TOUCHING: 'CommonGameTag' = 1526 + APPROPRIATENESS_TRASH: 'CommonGameTag' = 12423 + APPROPRIATENESS_TV_WATCHING: 'CommonGameTag' = 1273 + APPROPRIATENESS_VIEW: 'CommonGameTag' = 12428 + APPROPRIATENESS_VISITOR: 'CommonGameTag' = 1497 + APPROPRIATENESS_WORKOUT: 'CommonGameTag' = 1277 + APPROPRIATENESS_WORK_SCIENTIST: 'CommonGameTag' = 12297 + ARCHETYPE_AFRICAN: 'CommonGameTag' = 73 + ARCHETYPE_ASIAN: 'CommonGameTag' = 75 + ARCHETYPE_CAUCASIAN: 'CommonGameTag' = 76 + ARCHETYPE_ISLAND: 'CommonGameTag' = 2206 + ARCHETYPE_LATIN: 'CommonGameTag' = 312 + ARCHETYPE_MIDDLE_EASTERN: 'CommonGameTag' = 74 + ARCHETYPE_NATIVE_AMERICAN: 'CommonGameTag' = 2996 + ARCHETYPE_NORTH_AMERICAN: 'CommonGameTag' = 89 + ARCHETYPE_SOUTH_ASIAN: 'CommonGameTag' = 88 + ATTRACTOR_POINT_BEACH: 'CommonGameTag' = 2194 + ATTRACTOR_POINT_BEACH_WALK_BY: 'CommonGameTag' = 2204 + ATTRACTOR_POINT_BLOSSOM_GURU: 'CommonGameTag' = 55386 + ATTRACTOR_POINT_BUSKER: 'CommonGameTag' = 1571 + ATTRACTOR_POINT_DYNAMIC_SPAWN_POINT: 'CommonGameTag' = 1915 + ATTRACTOR_POINT_FIREWORKS: 'CommonGameTag' = 55399 + ATTRACTOR_POINT_FLEA_MARKET_VENDOR: 'CommonGameTag' = 55334 + ATTRACTOR_POINT_GO_FOR_WALK: 'CommonGameTag' = 1916 + ATTRACTOR_POINT_GO_FOR_WALK_LONG: 'CommonGameTag' = 57394 + ATTRACTOR_POINT_GO_FOR_WALK_LONG_02: 'CommonGameTag' = 57432 + ATTRACTOR_POINT_GO_FOR_WALK_LONG_03: 'CommonGameTag' = 57433 + ATTRACTOR_POINT_GO_FOR_WALK_MEDIUM: 'CommonGameTag' = 57393 + ATTRACTOR_POINT_GO_FOR_WALK_MED_02: 'CommonGameTag' = 57436 + ATTRACTOR_POINT_GO_FOR_WALK_MED_03: 'CommonGameTag' = 57437 + ATTRACTOR_POINT_GO_FOR_WALK_SHORT: 'CommonGameTag' = 57389 + ATTRACTOR_POINT_GO_FOR_WALK_SHORT_02: 'CommonGameTag' = 57434 + ATTRACTOR_POINT_GO_FOR_WALK_SHORT_03: 'CommonGameTag' = 57435 + ATTRACTOR_POINT_GUITAR: 'CommonGameTag' = 2158 + ATTRACTOR_POINT_MAGIC_DUELING: 'CommonGameTag' = 2222 + ATTRACTOR_POINT_PROTESTER: 'CommonGameTag' = 1582 + ATTRACTOR_POINT_TOURIST: 'CommonGameTag' = 1570 + ATTRACTOR_POINT_UNIVERSITY_QUAD: 'CommonGameTag' = 2230 + ATTRACTOR_POINT_VILLAGE_SQUARE: 'CommonGameTag' = 2600 + ATTRACTOR_POINT_WOODS_POINT_OF_INTEREST: 'CommonGameTag' = 2599 + BOTTOM_BIKINI: 'CommonGameTag' = 1235 + BOTTOM_CROPPED: 'CommonGameTag' = 945 + BOTTOM_JEANS: 'CommonGameTag' = 382 + BOTTOM_LEGGINGS: 'CommonGameTag' = 381 + BOTTOM_PANTS: 'CommonGameTag' = 152 + BOTTOM_SHORTS: 'CommonGameTag' = 154 + BOTTOM_SKIRT: 'CommonGameTag' = 153 + BOTTOM_SWIMSHORT: 'CommonGameTag' = 1238 + BOTTOM_SWIMWEAR: 'CommonGameTag' = 1544 + BOTTOM_UNDERWEAR: 'CommonGameTag' = 1543 + BOTTOM_UNDERWEAR_FEMALE: 'CommonGameTag' = 946 + BOTTOM_UNDERWEAR_MALE: 'CommonGameTag' = 1040 + BREED_CAT_ABYSSINIAN: 'CommonGameTag' = 1830 + BREED_CAT_AMERICAN_BOBTAIL: 'CommonGameTag' = 1831 + BREED_CAT_AMERICAN_LONGHAIR: 'CommonGameTag' = 1931 + BREED_CAT_AMERICAN_SHORTHAIR: 'CommonGameTag' = 1833 + BREED_CAT_AMERICAN_WIREHAIR: 'CommonGameTag' = 1834 + BREED_CAT_BALINESE: 'CommonGameTag' = 1835 + BREED_CAT_BENGAL: 'CommonGameTag' = 1836 + BREED_CAT_BIRMAN: 'CommonGameTag' = 1837 + BREED_CAT_BLACK_CAT: 'CommonGameTag' = 1838 + BREED_CAT_BOMBAY: 'CommonGameTag' = 1839 + BREED_CAT_BRITISH_LONGHAIR: 'CommonGameTag' = 1840 + BREED_CAT_BRITISH_SHORTHAIR: 'CommonGameTag' = 1841 + BREED_CAT_BURMESE: 'CommonGameTag' = 1842 + BREED_CAT_CALICO: 'CommonGameTag' = 1843 + BREED_CAT_CHARTREUX: 'CommonGameTag' = 1844 + BREED_CAT_COLORPOINT_SHORTHAIR: 'CommonGameTag' = 1845 + BREED_CAT_CORNISH_REX: 'CommonGameTag' = 1832 + BREED_CAT_DEVON_REX: 'CommonGameTag' = 1846 + BREED_CAT_EGYPTIAN_MAU: 'CommonGameTag' = 1847 + BREED_CAT_GERMAN_REX: 'CommonGameTag' = 1848 + BREED_CAT_HAVANA_BROWN: 'CommonGameTag' = 1849 + BREED_CAT_HIMALAYAN: 'CommonGameTag' = 1850 + BREED_CAT_JAPANESE_BOBTAIL: 'CommonGameTag' = 1851 + BREED_CAT_JAVANESE: 'CommonGameTag' = 1852 + BREED_CAT_KORAT: 'CommonGameTag' = 1853 + BREED_CAT_KURILIAN_BOBTAIL: 'CommonGameTag' = 1854 + BREED_CAT_LA_PERM: 'CommonGameTag' = 1855 + BREED_CAT_LYKOI: 'CommonGameTag' = 1975 + BREED_CAT_MAINE_COON: 'CommonGameTag' = 1856 + BREED_CAT_MANX: 'CommonGameTag' = 1857 + BREED_CAT_MIXED: 'CommonGameTag' = 1926 + BREED_CAT_NORWEGIAN_FOREST: 'CommonGameTag' = 1858 + BREED_CAT_OCICAT: 'CommonGameTag' = 1859 + BREED_CAT_ORIENTAL: 'CommonGameTag' = 1860 + BREED_CAT_ORIENTAL_SHORTHAIR: 'CommonGameTag' = 1861 + BREED_CAT_PERSIAN: 'CommonGameTag' = 1862 + BREED_CAT_RACCOON: 'CommonGameTag' = 1974 + BREED_CAT_RAGDOLL: 'CommonGameTag' = 1863 + BREED_CAT_RUSSIAN_BLUE: 'CommonGameTag' = 1864 + BREED_CAT_SAVANNAH: 'CommonGameTag' = 1865 + BREED_CAT_SCOTTISH_FOLD: 'CommonGameTag' = 1866 + BREED_CAT_SHORTHAIR_TABBY: 'CommonGameTag' = 1867 + BREED_CAT_SIAMESE: 'CommonGameTag' = 1868 + BREED_CAT_SIBERIAN: 'CommonGameTag' = 1869 + BREED_CAT_SINGAPURA: 'CommonGameTag' = 1870 + BREED_CAT_SOMALI: 'CommonGameTag' = 1871 + BREED_CAT_SPHYNX: 'CommonGameTag' = 1886 + BREED_CAT_TONKINESE: 'CommonGameTag' = 1872 + BREED_CAT_TURKISH_ANGORA: 'CommonGameTag' = 1873 + BREED_CAT_TUXEDO_CAT: 'CommonGameTag' = 1874 + BREED_FOX_WILD_FOX: 'CommonGameTag' = 112662 + BREED_GROUP_HERDING: 'CommonGameTag' = 1893 + BREED_GROUP_HOUND: 'CommonGameTag' = 1894 + BREED_GROUP_NON_SPORTING: 'CommonGameTag' = 1911 + BREED_GROUP_SPORTING: 'CommonGameTag' = 1895 + BREED_GROUP_TERRIER: 'CommonGameTag' = 1896 + BREED_GROUP_TOY: 'CommonGameTag' = 1897 + BREED_GROUP_WORKING: 'CommonGameTag' = 1898 + BREED_HORSE_AKHAL_TEKE: 'CommonGameTag' = 118866 + BREED_HORSE_AMERICAN_QUARTER_HORSE: 'CommonGameTag' = 118815 + BREED_HORSE_AMERICAN_SADDLEBRED: 'CommonGameTag' = 118816 + BREED_HORSE_AMERICAN_STANDARDBRED: 'CommonGameTag' = 118824 + BREED_HORSE_ANDALUSIAN: 'CommonGameTag' = 118817 + BREED_HORSE_ANGLO_ARABIAN: 'CommonGameTag' = 118818 + BREED_HORSE_APPALOOSA: 'CommonGameTag' = 118819 + BREED_HORSE_ARABIAN: 'CommonGameTag' = 118820 + BREED_HORSE_AUSTRALIAN_STOCK_HORSE: 'CommonGameTag' = 118821 + BREED_HORSE_BARB: 'CommonGameTag' = 118822 + BREED_HORSE_CLYDESDALE: 'CommonGameTag' = 118808 + BREED_HORSE_COLORADO_RANGER: 'CommonGameTag' = 118809 + BREED_HORSE_DUTCH_WARMBLOOD: 'CommonGameTag' = 118810 + BREED_HORSE_FRIESIAN: 'CommonGameTag' = 118823 + BREED_HORSE_GELDERLANDER: 'CommonGameTag' = 118811 + BREED_HORSE_GYPSY_VANNER: 'CommonGameTag' = 118825 + BREED_HORSE_HANOVERIAN: 'CommonGameTag' = 118826 + BREED_HORSE_HOLSTEINER: 'CommonGameTag' = 118827 + BREED_HORSE_IRISH_DRAUGHT: 'CommonGameTag' = 118828 + BREED_HORSE_LIPIZZANER: 'CommonGameTag' = 118829 + BREED_HORSE_LUSITANO: 'CommonGameTag' = 118802 + BREED_HORSE_MISSOURI_FOX_TROTTER: 'CommonGameTag' = 118873 + BREED_HORSE_MIXED: 'CommonGameTag' = 3003 + BREED_HORSE_MORGAN: 'CommonGameTag' = 118796 + BREED_HORSE_MUSTANG: 'CommonGameTag' = 118803 + BREED_HORSE_NEZ_PERCE: 'CommonGameTag' = 118804 + BREED_HORSE_NOKOTA: 'CommonGameTag' = 118805 + BREED_HORSE_PAINT: 'CommonGameTag' = 118867 + BREED_HORSE_PALOMINO: 'CommonGameTag' = 118868 + BREED_HORSE_PERCHERON: 'CommonGameTag' = 118869 + BREED_HORSE_SELLE_FRANCAIS: 'CommonGameTag' = 118870 + BREED_HORSE_SHIRE: 'CommonGameTag' = 118830 + BREED_HORSE_TENNESSEE_WALKER: 'CommonGameTag' = 118832 + BREED_HORSE_THOROUGHBRED: 'CommonGameTag' = 118807 + BREED_HORSE_TRAKEHNER: 'CommonGameTag' = 118831 + BREED_HORSE_WELSH_COB: 'CommonGameTag' = 118806 + BREED_LARGE_DOG_AFGHAN_HOUND: 'CommonGameTag' = 1814 + BREED_LARGE_DOG_AIREDALE_TERRIER: 'CommonGameTag' = 1745 + BREED_LARGE_DOG_AKITA: 'CommonGameTag' = 1746 + BREED_LARGE_DOG_ALASKAN_MALAMUTE: 'CommonGameTag' = 1747 + BREED_LARGE_DOG_AMERICAN_ESKIMO: 'CommonGameTag' = 1748 + BREED_LARGE_DOG_AMERICAN_FOXHOUND: 'CommonGameTag' = 1797 + BREED_LARGE_DOG_AUSTRALIAN_CATTLE_DOG: 'CommonGameTag' = 1750 + BREED_LARGE_DOG_AUSTRALIAN_SHEPHERD: 'CommonGameTag' = 1735 + BREED_LARGE_DOG_BEDLINGTON_TERRIER: 'CommonGameTag' = 1950 + BREED_LARGE_DOG_BERNESE_MOUNTAIN_DOG: 'CommonGameTag' = 1751 + BREED_LARGE_DOG_BLACK_AND_TAN_COONHOUND: 'CommonGameTag' = 1798 + BREED_LARGE_DOG_BLACK_RUSSIAN_TERRIER: 'CommonGameTag' = 1961 + BREED_LARGE_DOG_BLOODHOUND: 'CommonGameTag' = 1753 + BREED_LARGE_DOG_BLUETICK_COONHOUND: 'CommonGameTag' = 1796 + BREED_LARGE_DOG_BORDER_COLLIE: 'CommonGameTag' = 1736 + BREED_LARGE_DOG_BORZOI: 'CommonGameTag' = 1826 + BREED_LARGE_DOG_BOXER: 'CommonGameTag' = 1755 + BREED_LARGE_DOG_BRITTANY: 'CommonGameTag' = 1816 + BREED_LARGE_DOG_BULLMASTIFF: 'CommonGameTag' = 1951 + BREED_LARGE_DOG_CANAAN: 'CommonGameTag' = 1952 + BREED_LARGE_DOG_CHESAPEAKE_BAY_RETRIEVER: 'CommonGameTag' = 1795 + BREED_LARGE_DOG_CHOW_CHOW: 'CommonGameTag' = 1759 + BREED_LARGE_DOG_CHOW_LAB_MIX: 'CommonGameTag' = 1953 + BREED_LARGE_DOG_COLLIE: 'CommonGameTag' = 1740 + BREED_LARGE_DOG_CURLY_COATED_RETRIEVER: 'CommonGameTag' = 1794 + BREED_LARGE_DOG_DALMATIAN: 'CommonGameTag' = 1741 + BREED_LARGE_DOG_DINGO: 'CommonGameTag' = 1954 + BREED_LARGE_DOG_DOBERMAN: 'CommonGameTag' = 1742 + BREED_LARGE_DOG_DOBERMAN_PINSCHER: 'CommonGameTag' = 1761 + BREED_LARGE_DOG_ENGLISH_FOXHOUND: 'CommonGameTag' = 1821 + BREED_LARGE_DOG_ENGLISH_SETTER: 'CommonGameTag' = 1819 + BREED_LARGE_DOG_ENGLISH_SPRINGER_SPANIEL: 'CommonGameTag' = 1762 + BREED_LARGE_DOG_FIELD_SPANIEL: 'CommonGameTag' = 1801 + BREED_LARGE_DOG_GERMAN_POINTER: 'CommonGameTag' = 1737 + BREED_LARGE_DOG_GERMAN_SHEPHERD: 'CommonGameTag' = 1743 + BREED_LARGE_DOG_GIANT_SCHNAUZER: 'CommonGameTag' = 1792 + BREED_LARGE_DOG_GOLDEN_DOODLE: 'CommonGameTag' = 1800 + BREED_LARGE_DOG_GOLDEN_RETRIEVER: 'CommonGameTag' = 1731 + BREED_LARGE_DOG_GREAT_DANE: 'CommonGameTag' = 1734 + BREED_LARGE_DOG_GREAT_PYRANEES: 'CommonGameTag' = 1955 + BREED_LARGE_DOG_GREYHOUND: 'CommonGameTag' = 1764 + BREED_LARGE_DOG_HUSKY: 'CommonGameTag' = 1744 + BREED_LARGE_DOG_IBIZAN: 'CommonGameTag' = 1738 + BREED_LARGE_DOG_IRISH_RED_AND_WHITE_SETTER: 'CommonGameTag' = 1802 + BREED_LARGE_DOG_IRISH_SETTER: 'CommonGameTag' = 1803 + BREED_LARGE_DOG_IRISH_TERRIER: 'CommonGameTag' = 1828 + BREED_LARGE_DOG_IRISH_WOLFHOUND: 'CommonGameTag' = 1827 + BREED_LARGE_DOG_KEESHOND: 'CommonGameTag' = 1767 + BREED_LARGE_DOG_KERRY_BLUE_TERRIER: 'CommonGameTag' = 1956 + BREED_LARGE_DOG_LABRADOODLE: 'CommonGameTag' = 1957 + BREED_LARGE_DOG_LABRADOR_RETRIEVER: 'CommonGameTag' = 1768 + BREED_LARGE_DOG_MASTIFF: 'CommonGameTag' = 1804 + BREED_LARGE_DOG_MIXED: 'CommonGameTag' = 1928 + BREED_LARGE_DOG_NEWFOUNDLAND: 'CommonGameTag' = 1769 + BREED_LARGE_DOG_NORWEGIAN_ELK_SHEPHERD: 'CommonGameTag' = 1958 + BREED_LARGE_DOG_OLD_ENGLISH_SHEEPDOG: 'CommonGameTag' = 1771 + BREED_LARGE_DOG_OTTERHOUND: 'CommonGameTag' = 1772 + BREED_LARGE_DOG_PHARAOH_HOUND: 'CommonGameTag' = 1774 + BREED_LARGE_DOG_PIT_BULL: 'CommonGameTag' = 1749 + BREED_LARGE_DOG_POINTER: 'CommonGameTag' = 1775 + BREED_LARGE_DOG_POLISH_LOWLAND_SHEEPDOG: 'CommonGameTag' = 1807 + BREED_LARGE_DOG_POODLE: 'CommonGameTag' = 1777 + BREED_LARGE_DOG_PORTUGUESE_WATER_DOG: 'CommonGameTag' = 1791 + BREED_LARGE_DOG_REDBONE_COONHOUND: 'CommonGameTag' = 1810 + BREED_LARGE_DOG_RHODESIAN_RIDGEBACK: 'CommonGameTag' = 1815 + BREED_LARGE_DOG_ROTTWEILER: 'CommonGameTag' = 1779 + BREED_LARGE_DOG_SAINT_BERNARD: 'CommonGameTag' = 1780 + BREED_LARGE_DOG_SAMOYED: 'CommonGameTag' = 1781 + BREED_LARGE_DOG_SCHNAUZER: 'CommonGameTag' = 1732 + BREED_LARGE_DOG_SHAR_PEI: 'CommonGameTag' = 1959 + BREED_LARGE_DOG_SIBERIAN_HUSKY: 'CommonGameTag' = 1812 + BREED_LARGE_DOG_TIBETAN_MASTIFF: 'CommonGameTag' = 1960 + BREED_LARGE_DOG_VIZSLA: 'CommonGameTag' = 1809 + BREED_LARGE_DOG_WEIMARANER: 'CommonGameTag' = 1788 + BREED_LARGE_DOG_WELSH_SPRINGER_SPANIEL: 'CommonGameTag' = 1808 + BREED_LARGE_DOG_WHEATENS_TERRIER: 'CommonGameTag' = 1962 + BREED_NONE: 'CommonGameTag' = 1733 + BREED_SMALL_DOG_BASENJI: 'CommonGameTag' = 1817 + BREED_SMALL_DOG_BEAGLE: 'CommonGameTag' = 1739 + BREED_SMALL_DOG_BICHON_FRISE: 'CommonGameTag' = 1752 + BREED_SMALL_DOG_BOCKER: 'CommonGameTag' = 1963 + BREED_SMALL_DOG_BOSTON_TERRIER: 'CommonGameTag' = 1754 + BREED_SMALL_DOG_BULLDOG: 'CommonGameTag' = 1756 + BREED_SMALL_DOG_BULL_TERRIER: 'CommonGameTag' = 1829 + BREED_SMALL_DOG_CARDIGAN_WELSH_CORGI: 'CommonGameTag' = 1964 + BREED_SMALL_DOG_CAVALIER_KING_CHARLES_SPANIEL: 'CommonGameTag' = 1757 + BREED_SMALL_DOG_CHIHUAHUA: 'CommonGameTag' = 1758 + BREED_SMALL_DOG_COCKAPOO: 'CommonGameTag' = 1965 + BREED_SMALL_DOG_COCKER_SPANIEL: 'CommonGameTag' = 1760 + BREED_SMALL_DOG_DASCHUND: 'CommonGameTag' = 1966 + BREED_SMALL_DOG_ENGLISH_COCKER_SPANIEL: 'CommonGameTag' = 1818 + BREED_SMALL_DOG_ENGLISH_TOY_SPANIEL: 'CommonGameTag' = 1967 + BREED_SMALL_DOG_FOX: 'CommonGameTag' = 1968 + BREED_SMALL_DOG_FRENCH_BULLDOG: 'CommonGameTag' = 1763 + BREED_SMALL_DOG_HAVANESE: 'CommonGameTag' = 1793 + BREED_SMALL_DOG_ICELANDIC_SHEEP_DOG: 'CommonGameTag' = 1993 + BREED_SMALL_DOG_ITALIAN_GREYHOUND: 'CommonGameTag' = 1825 + BREED_SMALL_DOG_JACK_RUSSEL_TERRIER: 'CommonGameTag' = 1766 + BREED_SMALL_DOG_LHASA_APSO: 'CommonGameTag' = 1823 + BREED_SMALL_DOG_MALTESE: 'CommonGameTag' = 1943 + BREED_SMALL_DOG_MINIATURE_PINSCHER: 'CommonGameTag' = 1805 + BREED_SMALL_DOG_MINIATURE_POODLE: 'CommonGameTag' = 1969 + BREED_SMALL_DOG_MINIATURE_SCHNAUZER: 'CommonGameTag' = 1806 + BREED_SMALL_DOG_MIXED: 'CommonGameTag' = 1927 + BREED_SMALL_DOG_NORWEGIAN_BUHUND: 'CommonGameTag' = 1992 + BREED_SMALL_DOG_PAPILLON: 'CommonGameTag' = 1773 + BREED_SMALL_DOG_PARSON_RUSSEL_TERRIER: 'CommonGameTag' = 1970 + BREED_SMALL_DOG_PEKINGESE: 'CommonGameTag' = 1770 + BREED_SMALL_DOG_PEMBROKE_WELSH_CORGI: 'CommonGameTag' = 1971 + BREED_SMALL_DOG_POMERANIAN: 'CommonGameTag' = 1776 + BREED_SMALL_DOG_PUG: 'CommonGameTag' = 1778 + BREED_SMALL_DOG_PUGGLE: 'CommonGameTag' = 1820 + BREED_SMALL_DOG_SCHIPPERKE: 'CommonGameTag' = 1782 + BREED_SMALL_DOG_SCHNOODLE: 'CommonGameTag' = 1972 + BREED_SMALL_DOG_SCOTTISH_TERRIER: 'CommonGameTag' = 1783 + BREED_SMALL_DOG_SHETLAND_SHEEPDOG: 'CommonGameTag' = 1811 + BREED_SMALL_DOG_SHIBA_INU: 'CommonGameTag' = 1784 + BREED_SMALL_DOG_SHIH_TZU: 'CommonGameTag' = 1785 + BREED_SMALL_DOG_SILKY_TERRIER: 'CommonGameTag' = 1973 + BREED_SMALL_DOG_SMOOTH_FOX_TERRIER: 'CommonGameTag' = 1813 + BREED_SMALL_DOG_SPITZ: 'CommonGameTag' = 1991 + BREED_SMALL_DOG_STAFFORDSHIRE_BULL_TERRIER: 'CommonGameTag' = 1824 + BREED_SMALL_DOG_STANDARD_SCHNAUZER: 'CommonGameTag' = 1786 + BREED_SMALL_DOG_TOY_FOX_TERRIER: 'CommonGameTag' = 1787 + BREED_SMALL_DOG_WEST_HIGHLAND_WHITE_TERRIER: 'CommonGameTag' = 1822 + BREED_SMALL_DOG_WHIPPET: 'CommonGameTag' = 1799 + BREED_SMALL_DOG_WIRE_FOX_TERRIER: 'CommonGameTag' = 1789 + BREED_SMALL_DOG_YORKSHIRE_TERRIER: 'CommonGameTag' = 1790 + BUFF_AGGRAVATING_CONVERSATION: 'CommonGameTag' = 2784 + BUFF_APPEARANCE_MODIFIER_MAKEUP: 'CommonGameTag' = 2154 + BUFF_BUSINESS_CUSTOMER_STAR_RATING: 'CommonGameTag' = 1551 + BUFF_BUSINESS_EMPLOYEE_TRAINING: 'CommonGameTag' = 1548 + BUFF_CAULDRON_POTION_MAKE_GLOWY_FAILURE_VFX: 'CommonGameTag' = 49168 + BUFF_DAY_NIGHT_TRACKING: 'CommonGameTag' = 1678 + BUFF_DISLIKE_MUSIC: 'CommonGameTag' = 2791 + BUFF_HUMANOID_ROBOT_MOOD_VFX: 'CommonGameTag' = 65653 + BUFF_MYSTICAL_RELIC_CURSE: 'CommonGameTag' = 45079 + BUFF_NAILS_ALMOND: 'CommonGameTag' = 18473 + BUFF_NAILS_COFFIN: 'CommonGameTag' = 18467 + BUFF_NAILS_COMMUNITY: 'CommonGameTag' = 18481 + BUFF_NAILS_PICKER: 'CommonGameTag' = 18470 + BUFF_NAILS_ROUND: 'CommonGameTag' = 18468 + BUFF_NAILS_SHORT: 'CommonGameTag' = 18480 + BUFF_NAILS_STILETTO: 'CommonGameTag' = 18469 + BUFF_NAILS_VISIBLE: 'CommonGameTag' = 18484 + BUFF_NECTAR_JUICE_MOOD_DRINK_1: 'CommonGameTag' = 2969 + BUFF_NECTAR_JUICE_MOOD_DRINK_2: 'CommonGameTag' = 2970 + BUFF_NECTAR_JUICE_MOOD_DRINK_3: 'CommonGameTag' = 2971 + BUFF_NECTAR_JUICE_MOOD_DRINK_4: 'CommonGameTag' = 2972 + BUFF_OWNABLE_RESTAURANT_CUSTOMER: 'CommonGameTag' = 2150 + BUFF_POSSESSED_BUFFS: 'CommonGameTag' = 47139 + BUFF_POSSESSED_BUFFS_NO_ANIMATE: 'CommonGameTag' = 47148 + BUFF_SCENARIOS_ACCEPTED_ASTRONAUT: 'CommonGameTag' = 2840 + BUFF_SCHOOL_NEGATIVE: 'CommonGameTag' = 2728 + BUFF_SOCIAL_MEDIA_ENABLE_POST: 'CommonGameTag' = 114738 + BUFF_SPELLS_CASTING_SPELL: 'CommonGameTag' = 49157 + BUFF_TEMPERATURE: 'CommonGameTag' = 2481 + BUFF_VAMPIRE_SUNLIGHT: 'CommonGameTag' = 40989 + BUFF_WEATHER: 'CommonGameTag' = 59431 + BUFF_WEDDING_GUEST_DANCE: 'CommonGameTag' = 133147 + BUILD_ARCH: 'CommonGameTag' = 561 + BUILD_BB_GAMEPLAY_EFFECT_COLUMNS_BILLS_DECREASE: 'CommonGameTag' = 2419 + BUILD_BB_GAMEPLAY_EFFECT_COLUMNS_BILLS_INCREASE: 'CommonGameTag' = 2420 + BUILD_BB_GAMEPLAY_EFFECT_COLUMNS_ECO_FOOTPRINT_MINUS1: 'CommonGameTag' = 2413 + BUILD_BB_GAMEPLAY_EFFECT_COLUMNS_ECO_FOOTPRINT_MINUS2: 'CommonGameTag' = 2414 + BUILD_BB_GAMEPLAY_EFFECT_COLUMNS_ECO_FOOTPRINT_PLUS1: 'CommonGameTag' = 2411 + BUILD_BB_GAMEPLAY_EFFECT_COLUMNS_ECO_FOOTPRINT_PLUS2: 'CommonGameTag' = 2412 + BUILD_BB_GAMEPLAY_EFFECT_COLUMNS_ENVIRONMENT_SCORE_MINUS1: 'CommonGameTag' = 2417 + BUILD_BB_GAMEPLAY_EFFECT_COLUMNS_ENVIRONMENT_SCORE_MINUS2: 'CommonGameTag' = 2418 + BUILD_BB_GAMEPLAY_EFFECT_COLUMNS_ENVIRONMENT_SCORE_PLUS1: 'CommonGameTag' = 2415 + BUILD_BB_GAMEPLAY_EFFECT_COLUMNS_ENVIRONMENT_SCORE_PLUS2: 'CommonGameTag' = 2416 + BUILD_BB_GAMEPLAY_EFFECT_FENCES_BILLS_DECREASE: 'CommonGameTag' = 2409 + BUILD_BB_GAMEPLAY_EFFECT_FENCES_BILLS_INCREASE: 'CommonGameTag' = 2410 + BUILD_BB_GAMEPLAY_EFFECT_FENCES_ECO_FOOTPRINT_MINUS1: 'CommonGameTag' = 2403 + BUILD_BB_GAMEPLAY_EFFECT_FENCES_ECO_FOOTPRINT_MINUS2: 'CommonGameTag' = 2404 + BUILD_BB_GAMEPLAY_EFFECT_FENCES_ECO_FOOTPRINT_PLUS1: 'CommonGameTag' = 2401 + BUILD_BB_GAMEPLAY_EFFECT_FENCES_ECO_FOOTPRINT_PLUS2: 'CommonGameTag' = 2402 + BUILD_BB_GAMEPLAY_EFFECT_FENCES_ENVIRONMENT_SCORE_MINUS1: 'CommonGameTag' = 2407 + BUILD_BB_GAMEPLAY_EFFECT_FENCES_ENVIRONMENT_SCORE_MINUS2: 'CommonGameTag' = 2408 + BUILD_BB_GAMEPLAY_EFFECT_FENCES_ENVIRONMENT_SCORE_PLUS1: 'CommonGameTag' = 2405 + BUILD_BB_GAMEPLAY_EFFECT_FENCES_ENVIRONMENT_SCORE_PLUS2: 'CommonGameTag' = 2406 + BUILD_BB_GAMEPLAY_EFFECT_FLOOR_PATTERN_DECREASE_BILLS: 'CommonGameTag' = 2329 + BUILD_BB_GAMEPLAY_EFFECT_FLOOR_PATTERN_ECO_FOOTPRINT_MINUS1: 'CommonGameTag' = 2308 + BUILD_BB_GAMEPLAY_EFFECT_FLOOR_PATTERN_ECO_FOOTPRINT_MINUS2: 'CommonGameTag' = 2309 + BUILD_BB_GAMEPLAY_EFFECT_FLOOR_PATTERN_ECO_FOOTPRINT_PLUS1: 'CommonGameTag' = 2306 + BUILD_BB_GAMEPLAY_EFFECT_FLOOR_PATTERN_ECO_FOOTPRINT_PLUS2: 'CommonGameTag' = 2307 + BUILD_BB_GAMEPLAY_EFFECT_FLOOR_PATTERN_ENVIRONMENT_SCORE_MINUS1: 'CommonGameTag' = 2296 + BUILD_BB_GAMEPLAY_EFFECT_FLOOR_PATTERN_ENVIRONMENT_SCORE_MINUS2: 'CommonGameTag' = 2297 + BUILD_BB_GAMEPLAY_EFFECT_FLOOR_PATTERN_ENVIRONMENT_SCORE_PLUS1: 'CommonGameTag' = 2294 + BUILD_BB_GAMEPLAY_EFFECT_FLOOR_PATTERN_ENVIRONMENT_SCORE_PLUS2: 'CommonGameTag' = 2295 + BUILD_BB_GAMEPLAY_EFFECT_FLOOR_PATTERN_INCREASE_BILLS: 'CommonGameTag' = 2328 + BUILD_BB_GAMEPLAY_EFFECT_OBJECT_DECREASE_BILLS: 'CommonGameTag' = 2327 + BUILD_BB_GAMEPLAY_EFFECT_OBJECT_ECO_FOOTPRINT_MINUS1: 'CommonGameTag' = 2300 + BUILD_BB_GAMEPLAY_EFFECT_OBJECT_ECO_FOOTPRINT_MINUS2: 'CommonGameTag' = 2301 + BUILD_BB_GAMEPLAY_EFFECT_OBJECT_ECO_FOOTPRINT_PLUS1: 'CommonGameTag' = 2298 + BUILD_BB_GAMEPLAY_EFFECT_OBJECT_ECO_FOOTPRINT_PLUS2: 'CommonGameTag' = 2299 + BUILD_BB_GAMEPLAY_EFFECT_OBJECT_ECO_FOOTPRINT_PLUS_PARK: 'CommonGameTag' = 2444 + BUILD_BB_GAMEPLAY_EFFECT_OBJECT_ENVIRONMENT_SCORE_MINUS1: 'CommonGameTag' = 2288 + BUILD_BB_GAMEPLAY_EFFECT_OBJECT_ENVIRONMENT_SCORE_MINUS2: 'CommonGameTag' = 2289 + BUILD_BB_GAMEPLAY_EFFECT_OBJECT_ENVIRONMENT_SCORE_PLUS1: 'CommonGameTag' = 2286 + BUILD_BB_GAMEPLAY_EFFECT_OBJECT_ENVIRONMENT_SCORE_PLUS2: 'CommonGameTag' = 2287 + BUILD_BB_GAMEPLAY_EFFECT_OBJECT_INCREASE_BILLS: 'CommonGameTag' = 2326 + BUILD_BB_GAMEPLAY_EFFECT_OBJECT_POWER_CONSUMER: 'CommonGameTag' = 2314 + BUILD_BB_GAMEPLAY_EFFECT_OBJECT_POWER_PRODUCER: 'CommonGameTag' = 2316 + BUILD_BB_GAMEPLAY_EFFECT_OBJECT_WATER_CONSUMER: 'CommonGameTag' = 2315 + BUILD_BB_GAMEPLAY_EFFECT_OBJECT_WATER_PRODUCER: 'CommonGameTag' = 2317 + BUILD_BB_GAMEPLAY_EFFECT_POOL_SURFACE_POWER_CONSUMER: 'CommonGameTag' = 2322 + BUILD_BB_GAMEPLAY_EFFECT_POOL_SURFACE_POWER_PRODUCER: 'CommonGameTag' = 2324 + BUILD_BB_GAMEPLAY_EFFECT_POOL_SURFACE_WATER_CONSUMER: 'CommonGameTag' = 2323 + BUILD_BB_GAMEPLAY_EFFECT_POOL_SURFACE_WATER_PRODUCER: 'CommonGameTag' = 2325 + BUILD_BB_GAMEPLAY_EFFECT_ROOF_MATERIAL_DECREASE_BILLS: 'CommonGameTag' = 2333 + BUILD_BB_GAMEPLAY_EFFECT_ROOF_MATERIAL_ECO_FOOTPRINT_MINUS1: 'CommonGameTag' = 2312 + BUILD_BB_GAMEPLAY_EFFECT_ROOF_MATERIAL_ECO_FOOTPRINT_MINUS2: 'CommonGameTag' = 2313 + BUILD_BB_GAMEPLAY_EFFECT_ROOF_MATERIAL_ECO_FOOTPRINT_PLUS1: 'CommonGameTag' = 2310 + BUILD_BB_GAMEPLAY_EFFECT_ROOF_MATERIAL_ECO_FOOTPRINT_PLUS2: 'CommonGameTag' = 2311 + BUILD_BB_GAMEPLAY_EFFECT_ROOF_MATERIAL_ENVIRONMENT_SCORE_MINUS1: 'CommonGameTag' = 2319 + BUILD_BB_GAMEPLAY_EFFECT_ROOF_MATERIAL_ENVIRONMENT_SCORE_PLUS1: 'CommonGameTag' = 2318 + BUILD_BB_GAMEPLAY_EFFECT_ROOF_MATERIAL_INCREASE_BILLS: 'CommonGameTag' = 2332 + BUILD_BB_GAMEPLAY_EFFECT_ROOF_MATERIAL_POWER_PRODUCER: 'CommonGameTag' = 2320 + BUILD_BB_GAMEPLAY_EFFECT_ROOF_MATERIAL_WATER_PRODUCER: 'CommonGameTag' = 2321 + BUILD_BB_GAMEPLAY_EFFECT_WALL_PATTERN_DECREASE_BILLS: 'CommonGameTag' = 2331 + BUILD_BB_GAMEPLAY_EFFECT_WALL_PATTERN_ECO_FOOTPRINT_MINUS1: 'CommonGameTag' = 2304 + BUILD_BB_GAMEPLAY_EFFECT_WALL_PATTERN_ECO_FOOTPRINT_MINUS2: 'CommonGameTag' = 2305 + BUILD_BB_GAMEPLAY_EFFECT_WALL_PATTERN_ECO_FOOTPRINT_PLUS1: 'CommonGameTag' = 2302 + BUILD_BB_GAMEPLAY_EFFECT_WALL_PATTERN_ECO_FOOTPRINT_PLUS2: 'CommonGameTag' = 2303 + BUILD_BB_GAMEPLAY_EFFECT_WALL_PATTERN_ENVIRONMENT_SCORE_MINUS1: 'CommonGameTag' = 2292 + BUILD_BB_GAMEPLAY_EFFECT_WALL_PATTERN_ENVIRONMENT_SCORE_MINUS2: 'CommonGameTag' = 2293 + BUILD_BB_GAMEPLAY_EFFECT_WALL_PATTERN_ENVIRONMENT_SCORE_PLUS1: 'CommonGameTag' = 2290 + BUILD_BB_GAMEPLAY_EFFECT_WALL_PATTERN_ENVIRONMENT_SCORE_PLUS2: 'CommonGameTag' = 2291 + BUILD_BB_GAMEPLAY_EFFECT_WALL_PATTERN_INCREASE_BILLS: 'CommonGameTag' = 2330 + BUILD_BLOCK: 'CommonGameTag' = 548 + BUILD_BLOCK_BASEMENT: 'CommonGameTag' = 242 + BUILD_BLOCK_CURVED_WALL: 'CommonGameTag' = 2829 + BUILD_BLOCK_DECK: 'CommonGameTag' = 1062 + BUILD_BLOCK_DIAGONAL: 'CommonGameTag' = 1070 + BUILD_BLOCK_FOUNTAIN: 'CommonGameTag' = 232 + BUILD_BLOCK_FOUNTAIN_TOOL: 'CommonGameTag' = 233 + BUILD_BLOCK_NO_WALLS: 'CommonGameTag' = 1064 + BUILD_BLOCK_PLATFORM: 'CommonGameTag' = 2491 + BUILD_BLOCK_PLATFORM_TOOL: 'CommonGameTag' = 2492 + BUILD_BLOCK_POOL: 'CommonGameTag' = 1226 + BUILD_BLOCK_POOL_TOOL: 'CommonGameTag' = 1227 + BUILD_BLOCK_WALL_TOOL: 'CommonGameTag' = 653 + BUILD_BLOCK_WITH_WALLS: 'CommonGameTag' = 1063 + BUILD_BUY_AUTONOMY_MARKER_ATTRACTOR: 'CommonGameTag' = 1638 + BUILD_BUY_NO_AUTONOMY_LIGHTS: 'CommonGameTag' = 1637 + BUILD_BUY_NO_AUTONOMY_PLANTS: 'CommonGameTag' = 1636 + BUILD_BUY_NO_AUTONOMY_RUGS: 'CommonGameTag' = 1639 + BUILD_BUY_NO_AUTONOMY_SCULPTURES: 'CommonGameTag' = 1634 + BUILD_BUY_WORLD_OBJECTS: 'CommonGameTag' = 787 + BUILD_COLUMN: 'CommonGameTag' = 538 + BUILD_DOOR: 'CommonGameTag' = 535 + BUILD_DOOR_CURVED: 'CommonGameTag' = 2827 + BUILD_DOOR_CURVED_SMALL: 'CommonGameTag' = 2830 + BUILD_DOOR_DOUBLE: 'CommonGameTag' = 918 + BUILD_DOOR_SINGLE: 'CommonGameTag' = 974 + BUILD_ELEVATOR: 'CommonGameTag' = 1611 + BUILD_FENCE: 'CommonGameTag' = 544 + BUILD_FLOOR_PATTERN: 'CommonGameTag' = 541 + BUILD_FLOOR_TRIM: 'CommonGameTag' = 554 + BUILD_FLOWER: 'CommonGameTag' = 556 + BUILD_FLOWER_BUSH: 'CommonGameTag' = 1068 + BUILD_FLOWER_GROUND_COVER: 'CommonGameTag' = 1067 + BUILD_FLOWER_MISC: 'CommonGameTag' = 1069 + BUILD_FOUNDATION: 'CommonGameTag' = 552 + BUILD_FOUNTAIN_TRIM: 'CommonGameTag' = 1081 + BUILD_FRIEZE: 'CommonGameTag' = 550 + BUILD_GATE: 'CommonGameTag' = 537 + BUILD_GATE_DOUBLE: 'CommonGameTag' = 915 + BUILD_GATE_SINGLE: 'CommonGameTag' = 976 + BUILD_GENERIC: 'CommonGameTag' = 1596 + BUILD_HALF_WALL: 'CommonGameTag' = 1441 + BUILD_HALF_WALL_TRIM: 'CommonGameTag' = 1442 + BUILD_IS_SHELL_BUILDING: 'CommonGameTag' = 1574 + BUILD_LADDER: 'CommonGameTag' = 2425 + BUILD_PLATFORM_TRIM: 'CommonGameTag' = 2483 + BUILD_POND: 'CommonGameTag' = 2570 + BUILD_POOL_STYLES: 'CommonGameTag' = 251 + BUILD_POOL_TRIM: 'CommonGameTag' = 250 + BUILD_POST: 'CommonGameTag' = 782 + BUILD_RAILING: 'CommonGameTag' = 547 + BUILD_ROCK: 'CommonGameTag' = 560 + BUILD_ROOF: 'CommonGameTag' = 540 + BUILD_ROOF_ATTACHMENT: 'CommonGameTag' = 539 + BUILD_ROOF_ATTACHMENT_MISC: 'CommonGameTag' = 975 + BUILD_ROOF_CHIMNEY: 'CommonGameTag' = 919 + BUILD_ROOF_DIAGONAL: 'CommonGameTag' = 906 + BUILD_ROOF_ORTHOGONAL: 'CommonGameTag' = 977 + BUILD_ROOF_PATTERN: 'CommonGameTag' = 543 + BUILD_ROOF_TRIM: 'CommonGameTag' = 551 + BUILD_RUG: 'CommonGameTag' = 559 + BUILD_SHRUB: 'CommonGameTag' = 557 + BUILD_SHRUB_BUSH: 'CommonGameTag' = 1065 + BUILD_SHRUB_CACTUS: 'CommonGameTag' = 1066 + BUILD_SPANDREL: 'CommonGameTag' = 545 + BUILD_STAIR: 'CommonGameTag' = 546 + BUILD_STYLE: 'CommonGameTag' = 549 + BUILD_STYLES_UBURBAN_CONTEMPORARY: 'CommonGameTag' = 2546 + BUILD_STYLE_ART_DECO: 'CommonGameTag' = 2825 + BUILD_STYLE_BASICS: 'CommonGameTag' = 2537 + BUILD_STYLE_BOHO: 'CommonGameTag' = 2534 + BUILD_STYLE_CONTEMPORARY: 'CommonGameTag' = 2535 + BUILD_STYLE_COSMOLUX: 'CommonGameTag' = 2536 + BUILD_STYLE_CUTE: 'CommonGameTag' = 2908 + BUILD_STYLE_DOUBLE_GALLERY: 'CommonGameTag' = 2539 + BUILD_STYLE_EVENTS: 'CommonGameTag' = 2745 + BUILD_STYLE_FRENCH_COUNTRY: 'CommonGameTag' = 2540 + BUILD_STYLE_GARDEN: 'CommonGameTag' = 2549 + BUILD_STYLE_GOTHIC_FARMHOUSE: 'CommonGameTag' = 2541 + BUILD_STYLE_HOLIDAYS: 'CommonGameTag' = 2744 + BUILD_STYLE_INDUSTRIAL: 'CommonGameTag' = 2727 + BUILD_STYLE_ISLAND: 'CommonGameTag' = 2548 + BUILD_STYLE_LUXE: 'CommonGameTag' = 2841 + BUILD_STYLE_MID_CENTURY: 'CommonGameTag' = 2555 + BUILD_STYLE_MISSION: 'CommonGameTag' = 2542 + BUILD_STYLE_MODERN: 'CommonGameTag' = 2543 + BUILD_STYLE_PATIO: 'CommonGameTag' = 2538 + BUILD_STYLE_QUEEN_ANNE: 'CommonGameTag' = 2544 + BUILD_STYLE_SCANDINAVIAN_CONTEMPORARY: 'CommonGameTag' = 2550 + BUILD_STYLE_SHOTGUN: 'CommonGameTag' = 2545 + BUILD_STYLE_TUDOR: 'CommonGameTag' = 2547 + BUILD_STYLE_VINTAGE: 'CommonGameTag' = 2826 + BUILD_TREE: 'CommonGameTag' = 558 + BUILD_WALL_ATTACHMENT: 'CommonGameTag' = 555 + BUILD_WALL_PATTERN: 'CommonGameTag' = 542 + BUILD_WATER_OBJECTS_BUILD_MODE_WATER_STYLES: 'CommonGameTag' = 2636 + BUILD_WATER_OBJECTS_BY_FUNCTION_WATER_STYLES: 'CommonGameTag' = 2643 + BUILD_WEDDING_ARCH: 'CommonGameTag' = 981 + BUILD_WINDOW: 'CommonGameTag' = 536 + BUILD_WINDOW_CURVED: 'CommonGameTag' = 2828 + BUILD_WINDOW_CURVED_SMALL: 'CommonGameTag' = 2831 + BUYCAT_WATER_OBJECTS_BUILD_MODE_ATTRACTORS: 'CommonGameTag' = 2637 + BUYCAT_WATER_OBJECTS_BUILD_MODE_FOUNTAIN_DECORATIONS: 'CommonGameTag' = 2633 + BUYCAT_WATER_OBJECTS_BUILD_MODE_POND_ITEMS: 'CommonGameTag' = 2632 + BUYCAT_WATER_OBJECTS_BUILD_MODE_POOL_OBJECTS: 'CommonGameTag' = 2635 + BUYCAT_WATER_OBJECTS_BY_FUNCTION_ATTRACTORS: 'CommonGameTag' = 2644 + BUYCAT_WATER_OBJECTS_BY_FUNCTION_FOUNTAIN_DECORATIONS: 'CommonGameTag' = 2639 + BUYCAT_WATER_OBJECTS_BY_FUNCTION_OPEN_WATER_OBJECTS: 'CommonGameTag' = 2642 + BUYCAT_WATER_OBJECTS_BY_FUNCTION_POOL_OBJECTS: 'CommonGameTag' = 2641 + BUYCAT_WATER_OBJECTS_BY_FUNCTION_WATER_EMITTERS: 'CommonGameTag' = 2640 + BUYCAT_WATER_OBJECTS_BY_ROOM_WATER_DECORATIONS: 'CommonGameTag' = 2638 + BUY_CAT_CLEAN_POWER: 'CommonGameTag' = 67591 + BUY_CAT_COLLECTION_ALIEN: 'CommonGameTag' = 1044 + BUY_CAT_COLLECTION_ALL: 'CommonGameTag' = 1053 + BUY_CAT_COLLECTION_CAPSULE: 'CommonGameTag' = 69729 + BUY_CAT_COLLECTION_CITY_POSTER: 'CommonGameTag' = 55378 + BUY_CAT_COLLECTION_CRYSTAL: 'CommonGameTag' = 1041 + BUY_CAT_COLLECTION_ELEMENT: 'CommonGameTag' = 1042 + BUY_CAT_COLLECTION_FISH: 'CommonGameTag' = 1051 + BUY_CAT_COLLECTION_FOSSIL: 'CommonGameTag' = 1043 + BUY_CAT_COLLECTION_FROG: 'CommonGameTag' = 1052 + BUY_CAT_COLLECTION_GACHAPON: 'CommonGameTag' = 69728 + BUY_CAT_COLLECTION_GARDENING: 'CommonGameTag' = 1159 + BUY_CAT_COLLECTION_METAL: 'CommonGameTag' = 1045 + BUY_CAT_COLLECTION_MY_SIM: 'CommonGameTag' = 1046 + BUY_CAT_COLLECTION_POSTCARD: 'CommonGameTag' = 1049 + BUY_CAT_COLLECTION_SLIDE: 'CommonGameTag' = 1048 + BUY_CAT_COLLECTION_SNOW_GLOBE: 'CommonGameTag' = 55377 + BUY_CAT_COLLECTION_SPACE_PRINT: 'CommonGameTag' = 1047 + BUY_CAT_COLLECTION_SPACE_ROCK: 'CommonGameTag' = 1050 + BUY_CAT_COLLECTION_TREASURE: 'CommonGameTag' = 2043 + BUY_CAT_COLUMNS: 'CommonGameTag' = 429 + BUY_CAT_COMMUNITY: 'CommonGameTag' = 1352 + BUY_CAT_EASEL: 'CommonGameTag' = 440 + BUY_CAT_EE_ACTIVE_ACTIVITY: 'CommonGameTag' = 970 + BUY_CAT_EE_ALARM: 'CommonGameTag' = 169 + BUY_CAT_EE_AUDIO: 'CommonGameTag' = 163 + BUY_CAT_EE_BAR: 'CommonGameTag' = 176 + BUY_CAT_EE_BASKETBALL: 'CommonGameTag' = 456 + BUY_CAT_EE_CHESS_TABLE: 'CommonGameTag' = 457 + BUY_CAT_EE_CLOCK: 'CommonGameTag' = 171 + BUY_CAT_EE_COMPUTER: 'CommonGameTag' = 162 + BUY_CAT_EE_CREATIVE_ACTIVITY: 'CommonGameTag' = 968 + BUY_CAT_EE_GARDENING: 'CommonGameTag' = 2075 + BUY_CAT_EE_HOBBY_SKILL: 'CommonGameTag' = 165 + BUY_CAT_EE_INDOOR_ACTIVITY: 'CommonGameTag' = 173 + BUY_CAT_EE_KID_ACTIVITY: 'CommonGameTag' = 174 + BUY_CAT_EE_KID_FURNITURE: 'CommonGameTag' = 167 + BUY_CAT_EE_KID_TOY: 'CommonGameTag' = 168 + BUY_CAT_EE_KNOWLEDGE_ACTIVITY: 'CommonGameTag' = 969 + BUY_CAT_EE_MISC_ELECTRONICS: 'CommonGameTag' = 177 + BUY_CAT_EE_MISC_ENTERTAINMENT: 'CommonGameTag' = 178 + BUY_CAT_EE_MISC_KIDS: 'CommonGameTag' = 179 + BUY_CAT_EE_MONKEY_BARS: 'CommonGameTag' = 458 + BUY_CAT_EE_OUTDOOR_ACTIVITY: 'CommonGameTag' = 175 + BUY_CAT_EE_PARTY: 'CommonGameTag' = 166 + BUY_CAT_EE_PET_ACTIVITY_TOYS: 'CommonGameTag' = 2014 + BUY_CAT_EE_PET_MISC: 'CommonGameTag' = 1948 + BUY_CAT_EE_PET_TOYS: 'CommonGameTag' = 1944 + BUY_CAT_EE_PET_VET: 'CommonGameTag' = 1947 + BUY_CAT_EE_TODDLERS: 'CommonGameTag' = 172 + BUY_CAT_EE_TRANSPORTATION: 'CommonGameTag' = 2237 + BUY_CAT_EE_TV: 'CommonGameTag' = 161 + BUY_CAT_EE_TV_SETS: 'CommonGameTag' = 164 + BUY_CAT_EE_TV_STAND: 'CommonGameTag' = 1122 + BUY_CAT_EE_VIDEO_GAME_CONSOLE: 'CommonGameTag' = 55356 + BUY_CAT_HOLIDAY_ALL: 'CommonGameTag' = 2084 + BUY_CAT_HOLIDAY_DECOR_ALL: 'CommonGameTag' = 2085 + BUY_CAT_INSTRUMENT: 'CommonGameTag' = 441 + BUY_CAT_LD_AWNING: 'CommonGameTag' = 979 + BUY_CAT_LD_BATHROOM_ACCENT: 'CommonGameTag' = 194 + BUY_CAT_LD_CEILING_DECORATION: 'CommonGameTag' = 2188 + BUY_CAT_LD_CEILING_LIGHT: 'CommonGameTag' = 205 + BUY_CAT_LD_CLUTTER: 'CommonGameTag' = 823 + BUY_CAT_LD_CURTAIN_BLIND: 'CommonGameTag' = 978 + BUY_CAT_LD_FIREPLACE: 'CommonGameTag' = 785 + BUY_CAT_LD_FLOOR_LAMP: 'CommonGameTag' = 204 + BUY_CAT_LD_FOUNTAIN_DECORATION: 'CommonGameTag' = 199 + BUY_CAT_LD_FOUNTAIN_EMITTER: 'CommonGameTag' = 231 + BUY_CAT_LD_FOUNTAIN_OBJECTS: 'CommonGameTag' = 252 + BUY_CAT_LD_KID_DECORATION: 'CommonGameTag' = 196 + BUY_CAT_LD_LAWN_ORNAMENT: 'CommonGameTag' = 195 + BUY_CAT_LD_MIRROR: 'CommonGameTag' = 207 + BUY_CAT_LD_MIRROR_FREESTANDING: 'CommonGameTag' = 965 + BUY_CAT_LD_MIRROR_WALL: 'CommonGameTag' = 964 + BUY_CAT_LD_MISC_DECORATION: 'CommonGameTag' = 209 + BUY_CAT_LD_MISC_LIGHT: 'CommonGameTag' = 208 + BUY_CAT_LD_NIGHT_LIGHT: 'CommonGameTag' = 1718 + BUY_CAT_LD_OUTDOOR_LIGHT: 'CommonGameTag' = 206 + BUY_CAT_LD_PLANT: 'CommonGameTag' = 202 + BUY_CAT_LD_POOL_DECORATIONS: 'CommonGameTag' = 1246 + BUY_CAT_LD_POOL_OBJECTS: 'CommonGameTag' = 1228 + BUY_CAT_LD_POOL_OBJECTS_INVENTORYABLE: 'CommonGameTag' = 2211 + BUY_CAT_LD_RUG: 'CommonGameTag' = 198 + BUY_CAT_LD_RUG_MANAGED: 'CommonGameTag' = 1496 + BUY_CAT_LD_SCULPTURE: 'CommonGameTag' = 200 + BUY_CAT_LD_TABLE_LAMP: 'CommonGameTag' = 203 + BUY_CAT_LD_WALL_DECORATION: 'CommonGameTag' = 201 + BUY_CAT_LD_WALL_LIGHT: 'CommonGameTag' = 310 + BUY_CAT_LD_WALL_SCULPTURE: 'CommonGameTag' = 824 + BUY_CAT_LD_WINDOW_TREATMENT: 'CommonGameTag' = 197 + BUY_CAT_LOT_REQ_ELEVATOR: 'CommonGameTag' = 55374 + BUY_CAT_LOT_REQ_ELEVATOR_BG: 'CommonGameTag' = 2240 + BUY_CAT_LOT_REQ_MAILBOX: 'CommonGameTag' = 55375 + BUY_CAT_LOT_REQ_MAILBOX_BG: 'CommonGameTag' = 2241 + BUY_CAT_LOT_REQ_TRASH_CHUTE: 'CommonGameTag' = 55376 + BUY_CAT_LOT_REQ_TRASH_CHUTE_BG: 'CommonGameTag' = 2242 + BUY_CAT_MAG_BATHROOM: 'CommonGameTag' = 271 + BUY_CAT_MAG_BEDROOM: 'CommonGameTag' = 272 + BUY_CAT_MAG_CAREER: 'CommonGameTag' = 468 + BUY_CAT_MAG_DINING_ROOM: 'CommonGameTag' = 273 + BUY_CAT_MAG_KIDS: 'CommonGameTag' = 864 + BUY_CAT_MAG_KITCHEN: 'CommonGameTag' = 274 + BUY_CAT_MAG_LIVING_ROOM: 'CommonGameTag' = 270 + BUY_CAT_MAG_MISC: 'CommonGameTag' = 407 + BUY_CAT_MAG_OUTDOOR: 'CommonGameTag' = 275 + BUY_CAT_MAG_STUDY: 'CommonGameTag' = 276 + BUY_CAT_OTG_APPLIANCES: 'CommonGameTag' = 2380 + BUY_CAT_OTG_CRAFTING: 'CommonGameTag' = 2381 + BUY_CAT_OTG_LIGHTING: 'CommonGameTag' = 2382 + BUY_CAT_OTG_MISC: 'CommonGameTag' = 2383 + BUY_CAT_OTG_OUTDOOR_ACTIVITIES: 'CommonGameTag' = 2384 + BUY_CAT_OTG_PLUMBING: 'CommonGameTag' = 2385 + BUY_CAT_PAINTING: 'CommonGameTag' = 446 + BUY_CAT_PA_COFFEE_MAKER: 'CommonGameTag' = 966 + BUY_CAT_PA_DISPOSABLE: 'CommonGameTag' = 188 + BUY_CAT_PA_DISPOSAL_INDOOR: 'CommonGameTag' = 972 + BUY_CAT_PA_DISPOSAL_OUTDOOR: 'CommonGameTag' = 973 + BUY_CAT_PA_LARGE_APPLIANCE: 'CommonGameTag' = 185 + BUY_CAT_PA_LITTER_BOX: 'CommonGameTag' = 1978 + BUY_CAT_PA_MICROWAVE: 'CommonGameTag' = 967 + BUY_CAT_PA_MISC_APPLIANCE: 'CommonGameTag' = 193 + BUY_CAT_PA_MISC_PLUMBING: 'CommonGameTag' = 192 + BUY_CAT_PA_MISC_SMALL_APPLIANCE: 'CommonGameTag' = 191 + BUY_CAT_PA_OUTDOOR_COOKING: 'CommonGameTag' = 190 + BUY_CAT_PA_PET_CARE: 'CommonGameTag' = 1945 + BUY_CAT_PA_PET_FOOD: 'CommonGameTag' = 1976 + BUY_CAT_PA_PUBLIC_RESTROOM: 'CommonGameTag' = 2042 + BUY_CAT_PA_REFRIGERATOR: 'CommonGameTag' = 189 + BUY_CAT_PA_SHOWER: 'CommonGameTag' = 183 + BUY_CAT_PA_SINK: 'CommonGameTag' = 180 + BUY_CAT_PA_SINK_COUNTER: 'CommonGameTag' = 920 + BUY_CAT_PA_SINK_FREESTANDING: 'CommonGameTag' = 182 + BUY_CAT_PA_SMALL_APPLIANCE: 'CommonGameTag' = 186 + BUY_CAT_PA_STOVE: 'CommonGameTag' = 187 + BUY_CAT_PA_STOVE_HOOD: 'CommonGameTag' = 913 + BUY_CAT_PA_TOILET: 'CommonGameTag' = 181 + BUY_CAT_PA_TUB: 'CommonGameTag' = 184 + BUY_CAT_SHAREABLE: 'CommonGameTag' = 1261 + BUY_CAT_SPANDRELS_FRIEZES_TRIM: 'CommonGameTag' = 430 + BUY_CAT_SS_ACCENT_TABLE: 'CommonGameTag' = 1123 + BUY_CAT_SS_BARSTOOL: 'CommonGameTag' = 224 + BUY_CAT_SS_BED: 'CommonGameTag' = 225 + BUY_CAT_SS_BED_DOUBLE: 'CommonGameTag' = 914 + BUY_CAT_SS_BED_SINGLE: 'CommonGameTag' = 971 + BUY_CAT_SS_BOOKSHELF: 'CommonGameTag' = 226 + BUY_CAT_SS_BUNK_BED: 'CommonGameTag' = 2526 + BUY_CAT_SS_CABINET: 'CommonGameTag' = 211 + BUY_CAT_SS_COFFEE_TABLE: 'CommonGameTag' = 214 + BUY_CAT_SS_COUNTER: 'CommonGameTag' = 210 + BUY_CAT_SS_DESK: 'CommonGameTag' = 215 + BUY_CAT_SS_DESK_CHAIR: 'CommonGameTag' = 222 + BUY_CAT_SS_DINING_CHAIR: 'CommonGameTag' = 217 + BUY_CAT_SS_DINING_TABLE: 'CommonGameTag' = 212 + BUY_CAT_SS_DINING_TABLE_LONG: 'CommonGameTag' = 963 + BUY_CAT_SS_DINING_TABLE_SHORT: 'CommonGameTag' = 962 + BUY_CAT_SS_DISPLAY: 'CommonGameTag' = 216 + BUY_CAT_SS_DRESSER: 'CommonGameTag' = 227 + BUY_CAT_SS_DRESSER_CLOTHES: 'CommonGameTag' = 2553 + BUY_CAT_SS_ELEMENT_DISPLAY: 'CommonGameTag' = 1072 + BUY_CAT_SS_END_TABLE: 'CommonGameTag' = 213 + BUY_CAT_SS_HALLWAY_TABLE: 'CommonGameTag' = 1126 + BUY_CAT_SS_LIVING_CHAIR: 'CommonGameTag' = 221 + BUY_CAT_SS_LOVE_SEAT: 'CommonGameTag' = 219 + BUY_CAT_SS_MISC_COMFORT: 'CommonGameTag' = 229 + BUY_CAT_SS_MISC_STORAGE: 'CommonGameTag' = 230 + BUY_CAT_SS_MISC_SURFACE: 'CommonGameTag' = 228 + BUY_CAT_SS_MODULAR_SHELVING: 'CommonGameTag' = 2527 + BUY_CAT_SS_OUTDOOR_BENCH: 'CommonGameTag' = 916 + BUY_CAT_SS_OUTDOOR_CHAIR: 'CommonGameTag' = 220 + BUY_CAT_SS_OUTDOOR_SEATING: 'CommonGameTag' = 223 + BUY_CAT_SS_OUTDOOR_TABLE: 'CommonGameTag' = 917 + BUY_CAT_SS_PET_BED: 'CommonGameTag' = 1977 + BUY_CAT_SS_PET_FURNITURE: 'CommonGameTag' = 1946 + BUY_CAT_SS_POSTCARD_BOARD: 'CommonGameTag' = 1071 + BUY_CAT_SS_SCRATCHING_POST: 'CommonGameTag' = 1979 + BUY_CAT_SS_SOFA: 'CommonGameTag' = 218 + BUY_CAT_VENUE_ARTS_CENTER: 'CommonGameTag' = 1604 + BUY_CAT_VENUE_ARTS_COMMONS: 'CommonGameTag' = 2273 + BUY_CAT_VENUE_AUDITORIUM: 'CommonGameTag' = 114756 + BUY_CAT_VENUE_AUDITORIUM_CAREER_DAY: 'CommonGameTag' = 114759 + BUY_CAT_VENUE_AUDITORIUM_FORMAL_DANCE: 'CommonGameTag' = 114758 + BUY_CAT_VENUE_AUDITORIUM_GRADUATION: 'CommonGameTag' = 114760 + BUY_CAT_VENUE_BAR: 'CommonGameTag' = 1353 + BUY_CAT_VENUE_BEACH: 'CommonGameTag' = 2199 + BUY_CAT_VENUE_BLUFFS: 'CommonGameTag' = 24612 + BUY_CAT_VENUE_CAFE: 'CommonGameTag' = 24578 + BUY_CAT_VENUE_CAFE_BG: 'CommonGameTag' = 2731 + BUY_CAT_VENUE_CHALET: 'CommonGameTag' = 24611 + BUY_CAT_VENUE_CLUB: 'CommonGameTag' = 1354 + BUY_CAT_VENUE_COMMUNITY_SPACE_DEFAULT: 'CommonGameTag' = 2438 + BUY_CAT_VENUE_COMMUNITY_SPACE_GARDEN: 'CommonGameTag' = 2440 + BUY_CAT_VENUE_COMMUNITY_SPACE_MAKER_SPACE: 'CommonGameTag' = 2439 + BUY_CAT_VENUE_COMMUNITY_SPACE_MARKETPLACE: 'CommonGameTag' = 2441 + BUY_CAT_VENUE_DOCTOR_CLINIC: 'CommonGameTag' = 1362 + BUY_CAT_VENUE_FOREST_PARK: 'CommonGameTag' = 1355 + BUY_CAT_VENUE_GYM: 'CommonGameTag' = 1356 + BUY_CAT_VENUE_HIGH_SCHOOL: 'CommonGameTag' = 114752 + BUY_CAT_VENUE_KARAOKE: 'CommonGameTag' = 1579 + BUY_CAT_VENUE_LIBRARY: 'CommonGameTag' = 1357 + BUY_CAT_VENUE_LOUNGE: 'CommonGameTag' = 1358 + BUY_CAT_VENUE_MUSEUM: 'CommonGameTag' = 1359 + BUY_CAT_VENUE_ONSEN: 'CommonGameTag' = 69662 + BUY_CAT_VENUE_PARK: 'CommonGameTag' = 1360 + BUY_CAT_VENUE_PENTHOUSE: 'CommonGameTag' = 55373 + BUY_CAT_VENUE_PENTHOUSE_BG: 'CommonGameTag' = 2239 + BUY_CAT_VENUE_POLICE_STATION: 'CommonGameTag' = 1363 + BUY_CAT_VENUE_POOL: 'CommonGameTag' = 1459 + BUY_CAT_VENUE_REC_CENTER: 'CommonGameTag' = 116755 + BUY_CAT_VENUE_RELAXATION_CENTER: 'CommonGameTag' = 18436 + BUY_CAT_VENUE_RESTAURANT: 'CommonGameTag' = 26625 + BUY_CAT_VENUE_RESTAURANT_BG: 'CommonGameTag' = 2730 + BUY_CAT_VENUE_RETAIL: 'CommonGameTag' = 1361 + BUY_CAT_VENUE_RUINS: 'CommonGameTag' = 24613 + BUY_CAT_VENUE_SCIENCE_COMMONS: 'CommonGameTag' = 2272 + BUY_CAT_VENUE_SCIENTIST_LAB: 'CommonGameTag' = 1364 + BUY_CAT_VENUE_STAR_GARDEN: 'CommonGameTag' = 1580 + BUY_CAT_VENUE_THRIFT_STORE: 'CommonGameTag' = 114757 + BUY_CAT_VENUE_UNIVERSITY_HOUSING: 'CommonGameTag' = 2229 + BUY_CAT_VENUE_VET: 'CommonGameTag' = 57401 + BUY_CAT_VENUE_VET_BG: 'CommonGameTag' = 2729 + BUY_CAT_VENUE_WEDDING: 'CommonGameTag' = 2746 + BUY_CAT_WINDOWS: 'CommonGameTag' = 428 + BUY_TAG_DISABLE_PLACEMENT_OUTLINE: 'CommonGameTag' = 43017 + BUY_TAG_NOT_AUTO_COUNTER_APPLIANCE: 'CommonGameTag' = 2274 + BUY_TAG_SHOW_IF_WALLS_CUTAWAY: 'CommonGameTag' = 1492 + CAS_CATEGORY_MEDICAL_WEARABLE_BODY_TORSO: 'CommonGameTag' = 2911 + CAS_CATEGORY_MEDICAL_WEARABLE_FACE: 'CommonGameTag' = 2910 + CAS_STORY_ADD_CAREER: 'CommonGameTag' = 2213 + CAS_STORY_ADD_FUNDS: 'CommonGameTag' = 2212 + CAS_STORY_ADD_OCCULT: 'CommonGameTag' = 2215 + CAS_STORY_ADD_SKILL: 'CommonGameTag' = 2214 + COAT_PATTERN_BICOLOR: 'CommonGameTag' = 2004 + COAT_PATTERN_BLANKET: 'CommonGameTag' = 2991 + COAT_PATTERN_BRINDLE: 'CommonGameTag' = 1995 + COAT_PATTERN_CALICO: 'CommonGameTag' = 2006 + COAT_PATTERN_COLORPOINT: 'CommonGameTag' = 2019 + COAT_PATTERN_DAPPLE: 'CommonGameTag' = 2989 + COAT_PATTERN_FANTASY: 'CommonGameTag' = 2009 + COAT_PATTERN_HARLEQUIN: 'CommonGameTag' = 2022 + COAT_PATTERN_LEOPARD: 'CommonGameTag' = 2990 + COAT_PATTERN_MASK: 'CommonGameTag' = 2001 + COAT_PATTERN_MERLE: 'CommonGameTag' = 1999 + COAT_PATTERN_PAINT: 'CommonGameTag' = 2988 + COAT_PATTERN_ROSETTE: 'CommonGameTag' = 2008 + COAT_PATTERN_SABLE: 'CommonGameTag' = 1996 + COAT_PATTERN_SADDLE: 'CommonGameTag' = 2000 + COAT_PATTERN_SOLID: 'CommonGameTag' = 1994 + COAT_PATTERN_SPECKLED: 'CommonGameTag' = 1998 + COAT_PATTERN_SPOTTED: 'CommonGameTag' = 1997 + COAT_PATTERN_STRIPED: 'CommonGameTag' = 2003 + COAT_PATTERN_TABBY: 'CommonGameTag' = 2002 + COAT_PATTERN_TIPPED: 'CommonGameTag' = 2007 + COAT_PATTERN_TORTOISESHELL: 'CommonGameTag' = 2005 + COAT_PATTERN_TRI_COLOR: 'CommonGameTag' = 2021 + COLOR_BLACK: 'CommonGameTag' = 93 + COLOR_BLUE: 'CommonGameTag' = 68 + COLOR_BROWN: 'CommonGameTag' = 91 + COLOR_BROWN_LIGHT: 'CommonGameTag' = 293 + COLOR_CHESTNUT_HORSE: 'CommonGameTag' = 2992 + COLOR_DARK_BROWN: 'CommonGameTag' = 90 + COLOR_FANTASY_HORSE: 'CommonGameTag' = 2994 + COLOR_GOLD_HORSE: 'CommonGameTag' = 2993 + COLOR_GRAY: 'CommonGameTag' = 92 + COLOR_GREEN: 'CommonGameTag' = 69 + COLOR_ORANGE: 'CommonGameTag' = 95 + COLOR_PALETTE_EARTH_TONES: 'CommonGameTag' = 280 + COLOR_PALETTE_GOTH_ROCK_PUNK: 'CommonGameTag' = 288 + COLOR_PALETTE_GRAYSCALE_DARK: 'CommonGameTag' = 282 + COLOR_PALETTE_GRAYSCALE_LIGHT: 'CommonGameTag' = 283 + COLOR_PALETTE_JEWEL: 'CommonGameTag' = 141 + COLOR_PALETTE_SPRING: 'CommonGameTag' = 285 + COLOR_PALETTE_SUMMER: 'CommonGameTag' = 286 + COLOR_PALETTE_WINTER: 'CommonGameTag' = 287 + COLOR_PINK: 'CommonGameTag' = 106 + COLOR_PURPLE: 'CommonGameTag' = 107 + COLOR_RED: 'CommonGameTag' = 65 + COLOR_WHITE: 'CommonGameTag' = 105 + COLOR_YELLOW: 'CommonGameTag' = 104 + CRAFTING_GARDENING: 'CommonGameTag' = 424 + CRAFTING_SONG: 'CommonGameTag' = 447 + DD_BUFF_OWNABLEBROTHEL_PATRON: 'CommonGameTag' = 1000001 + DD_BUYCAT_VENUE_BROTHEL: 'CommonGameTag' = 1000011 + DD_FILTER_BROTHELPATRON_STANDARD: 'CommonGameTag' = 1000007 + DD_INTERACTION_BROTHELSTAFF_HARLOTSTUD_IDLE: 'CommonGameTag' = 1000010 + DD_JOB_BROTHELPATRON: 'CommonGameTag' = 1000002 + DD_ROLE_BROTHELPATRON: 'CommonGameTag' = 1000003 + DD_ROLE_BROTHELPATRONFREEROAM: 'CommonGameTag' = 1000020 + DD_ROLE_BROTHELPATRONFREEROAM_READYFORSERVICE: 'CommonGameTag' = 1000021 + DD_ROLE_BROTHELPATRONSITDOWN: 'CommonGameTag' = 1000026 + DD_ROLE_BROTHELPATRON_BESERVICED: 'CommonGameTag' = 1000005 + DD_ROLE_BROTHELPATRON_READYFORSTAFFTOTAKEORDER: 'CommonGameTag' = 1000004 + DD_ROLE_BROTHELSTAFF: 'CommonGameTag' = 1000009 + DD_ROLE_BROTHELSTAFF_BARTENDER: 'CommonGameTag' = 1000017 + DD_ROLE_BROTHELSTAFF_MAINTENANCE: 'CommonGameTag' = 1000016 + DD_ROLE_BROTHELSTAFF_STRIPPER: 'CommonGameTag' = 1000012 + DD_SITUATION_BROTHELPATRON: 'CommonGameTag' = 1000006 + DD_SITUATION_BROTHELPATRON_PLAYER: 'CommonGameTag' = 1000025 + DD_SITUATION_BROTHELSTAFF: 'CommonGameTag' = 1000013 + DD_SITUATION_BROTHELSTAFF_AUTONOMOUS: 'CommonGameTag' = 1000018 + DD_SITUATION_BROTHELSTAFF_BARTENDER: 'CommonGameTag' = 1000023 + DD_SITUATION_BROTHELSTAFF_HARLOTSTUD: 'CommonGameTag' = 1000022 + DD_SITUATION_BROTHELSTAFF_HOST: 'CommonGameTag' = 1000024 + DD_SITUATION_BROTHELSTAFF_MAINTENANCE: 'CommonGameTag' = 1000015 + DD_SITUATION_BROTHELSTAFF_PLAYER: 'CommonGameTag' = 1000019 + DD_SITUATION_BROTHELSTAFF_STRIPPER: 'CommonGameTag' = 1000014 + DEPRECIATED: 'CommonGameTag' = 118792 + DOG_SIZE_LARGE: 'CommonGameTag' = 1892 + DOG_SIZE_SMALL: 'CommonGameTag' = 1891 + DRINKS_ANY: 'CommonGameTag' = 159 + DRINKS_BAR_ALCOHOLIC: 'CommonGameTag' = 157 + DRINKS_BAR_ANY: 'CommonGameTag' = 160 + DRINKS_BAR_NON_ALCOHOLIC: 'CommonGameTag' = 158 + DRINK_ALCOHOLIC: 'CommonGameTag' = 264 + DRINK_ANY: 'CommonGameTag' = 269 + DRINK_BUBBLE_TEA: 'CommonGameTag' = 114701 + DRINK_CRAFTED: 'CommonGameTag' = 351 + DRINK_CRAFTED_COFFEE_TEA: 'CommonGameTag' = 459 + DRINK_FIZZY: 'CommonGameTag' = 18451 + DRINK_KAVA: 'CommonGameTag' = 63538 + DRINK_MILK: 'CommonGameTag' = 2948 + DRINK_NON_ALCOHOLIC: 'CommonGameTag' = 265 + DRINK_SERUM: 'CommonGameTag' = 12290 + DRINK_SPACE_ENERGY: 'CommonGameTag' = 691 + DRINK_TODDLER: 'CommonGameTag' = 1661 + DUPLICATE_AFFORDANCE_ANIMAL_WATCH: 'CommonGameTag' = 2702 + DUPLICATE_AFFORDANCE_COMPUTER: 'CommonGameTag' = 2836 + DUPLICATE_AFFORDANCE_COUNTER: 'CommonGameTag' = 57450 + DUPLICATE_AFFORDANCE_HIGH_SCHOOL_ACTIVE_CLEAN_SINK: 'CommonGameTag' = 114744 + DUPLICATE_AFFORDANCE_HIGH_SCHOOL_ACTIVE_CLEAN_TABLE: 'CommonGameTag' = 114741 + DUPLICATE_AFFORDANCE_HIGH_SCHOOL_ACTIVE_CLEAN_TOILET: 'CommonGameTag' = 114742 + DUPLICATE_AFFORDANCE_HIGH_SCHOOL_ACTIVE_CREATE_PUDDLE: 'CommonGameTag' = 114743 + DUPLICATE_AFFORDANCE_HIGH_SCHOOL_BACKGROUND: 'CommonGameTag' = 114736 + DUPLICATE_AFFORDANCE_INFANT_WATCH: 'CommonGameTag' = 2952 + DUPLICATE_AFFORDANCE_MAGIC_HQ_BE_AMAZED: 'CommonGameTag' = 49184 + DUPLICATE_AFFORDANCE_MAGIC_HQ_BROWSE_BOOKS: 'CommonGameTag' = 49185 + DUPLICATE_AFFORDANCE_MIRROR: 'CommonGameTag' = 2172 + DUPLICATE_AFFORDANCE_PONDS: 'CommonGameTag' = 2589 + DUPLICATE_AFFORDANCE_READ: 'CommonGameTag' = 1173 + DUPLICATE_AFFORDANCE_SCRATCH: 'CommonGameTag' = 57449 + DUPLICATE_AFFORDANCE_SINK: 'CommonGameTag' = 2096 + DUPLICATE_AFFORDANCE_TALK_TO_PLANT: 'CommonGameTag' = 2701 + DUPLICATE_AFFORDANCE_TOYS_PICK_UP: 'CommonGameTag' = 1697 + DUPLICATE_AFFORDANCE_TOYS_PLAY_WITH: 'CommonGameTag' = 1696 + DUPLICATE_AFFORDANCE_TRAIT_INTERACTIONS: 'CommonGameTag' = 1174 + DUPLICATE_AFFORDANCE_VIEW: 'CommonGameTag' = 1175 + DUPLICATE_AFFORDANCE_WASH_HANDS: 'CommonGameTag' = 2837 + DUPLICATE_AFFORDANCE_WILD_GRASS_HARVEST: 'CommonGameTag' = 118878 + EARS_DOWN: 'CommonGameTag' = 57347 + EARS_UP: 'CommonGameTag' = 57348 + ENSEMBLE_FIN_ORANGE_RED: 'CommonGameTag' = 63537 + ENSEMBLE_FIN_PASTEL: 'CommonGameTag' = 63535 + ENSEMBLE_FIN_TEAL_PURPLE: 'CommonGameTag' = 63536 + ENSEMBLE_SWIM_BANDEAU_BLACK: 'CommonGameTag' = 1257 + ENSEMBLE_SWIM_BANDEAU_BLUE: 'CommonGameTag' = 1258 + ENSEMBLE_SWIM_BANDEAU_CORAL: 'CommonGameTag' = 1251 + ENSEMBLE_SWIM_BANDEAU_YELLOW: 'CommonGameTag' = 1254 + ENSEMBLE_SWIM_HALTER_BLACK: 'CommonGameTag' = 1239 + ENSEMBLE_SWIM_HALTER_LIME: 'CommonGameTag' = 1255 + ENSEMBLE_SWIM_HALTER_RED: 'CommonGameTag' = 1252 + ENSEMBLE_SWIM_HALTER_WHITE: 'CommonGameTag' = 1256 + ENSEMBLE_SWIM_METAL_BROWN: 'CommonGameTag' = 1259 + ENSEMBLE_SWIM_METAL_GREEN: 'CommonGameTag' = 1260 + ENSEMBLE_SWIM_METAL_PINK: 'CommonGameTag' = 1250 + ENSEMBLE_SWIM_METAL_TEAL: 'CommonGameTag' = 1253 + EYEBROW_SHAPE_ARCHED: 'CommonGameTag' = 1060 + EYEBROW_SHAPE_CURVED: 'CommonGameTag' = 1059 + EYEBROW_SHAPE_STRAIGHT: 'CommonGameTag' = 1058 + EYEBROW_THICKNESS_BALD: 'CommonGameTag' = 12393 + EYEBROW_THICKNESS_BUSHY: 'CommonGameTag' = 1054 + EYEBROW_THICKNESS_MEDIUM: 'CommonGameTag' = 1057 + EYEBROW_THICKNESS_SPARSE: 'CommonGameTag' = 1056 + EYEBROW_THICKNESS_THIN: 'CommonGameTag' = 1055 + EYE_COLOR_ALIEN: 'CommonGameTag' = 12392 + EYE_COLOR_AMBER: 'CommonGameTag' = 114 + EYE_COLOR_AQUA: 'CommonGameTag' = 115 + EYE_COLOR_BLACK: 'CommonGameTag' = 116 + EYE_COLOR_BLUE: 'CommonGameTag' = 117 + EYE_COLOR_BLUE_GRAY: 'CommonGameTag' = 1884 + EYE_COLOR_BROWN: 'CommonGameTag' = 118 + EYE_COLOR_DARK_BROWN: 'CommonGameTag' = 119 + EYE_COLOR_GOLDEN: 'CommonGameTag' = 423 + EYE_COLOR_GRAY: 'CommonGameTag' = 120 + EYE_COLOR_GREEN: 'CommonGameTag' = 121 + EYE_COLOR_HAZEL: 'CommonGameTag' = 421 + EYE_COLOR_HAZEL_BLUE: 'CommonGameTag' = 122 + EYE_COLOR_HAZEL_GREEN: 'CommonGameTag' = 123 + EYE_COLOR_HONEY: 'CommonGameTag' = 422 + EYE_COLOR_LIGHT_BLUE: 'CommonGameTag' = 124 + EYE_COLOR_LIGHT_BROWN: 'CommonGameTag' = 125 + EYE_COLOR_LIGHT_GREEN: 'CommonGameTag' = 126 + EYE_COLOR_LIGHT_YELLOW: 'CommonGameTag' = 1880 + EYE_COLOR_PURPLE: 'CommonGameTag' = 2763 + EYE_COLOR_VAMPIRE_BLACK: 'CommonGameTag' = 40988 + EYE_COLOR_VAMPIRE_BLUE_BLACK: 'CommonGameTag' = 40980 + EYE_COLOR_VAMPIRE_GREEN: 'CommonGameTag' = 40981 + EYE_COLOR_VAMPIRE_ICE_BLUE: 'CommonGameTag' = 40982 + EYE_COLOR_VAMPIRE_PURPLE: 'CommonGameTag' = 40983 + EYE_COLOR_VAMPIRE_RED: 'CommonGameTag' = 40984 + EYE_COLOR_VAMPIRE_RED_BLACK: 'CommonGameTag' = 40985 + EYE_COLOR_VAMPIRE_WHITE: 'CommonGameTag' = 40986 + EYE_COLOR_VAMPIRE_YELLOW: 'CommonGameTag' = 40987 + EYE_COLOR_YELLOW: 'CommonGameTag' = 1879 + EYE_COLOR_YELLOW_GREEN: 'CommonGameTag' = 1885 + FABRIC_COTTON: 'CommonGameTag' = 532 + FABRIC_DENIM: 'CommonGameTag' = 587 + FABRIC_LEATHER: 'CommonGameTag' = 531 + FABRIC_METAL: 'CommonGameTag' = 932 + FABRIC_SILK: 'CommonGameTag' = 585 + FABRIC_SILVER: 'CommonGameTag' = 933 + FABRIC_SYNTHETIC: 'CommonGameTag' = 584 + FABRIC_WOOL: 'CommonGameTag' = 586 + FACE_DETAIL_FRECKLES_NOSE: 'CommonGameTag' = 1651 + FACE_DETAIL_FRECKLES_SPREAD: 'CommonGameTag' = 1650 + FACE_DETAIL_TEETH_BUCK: 'CommonGameTag' = 1647 + FACE_DETAIL_TEETH_GAP: 'CommonGameTag' = 1649 + FACE_DETAIL_TEETH_SNAGGLE: 'CommonGameTag' = 1648 + FACE_DETAIL_TEETH_STRAIGHT: 'CommonGameTag' = 1652 + FACIAL_HAIR_BEARD: 'CommonGameTag' = 378 + FACIAL_HAIR_GOATEE: 'CommonGameTag' = 379 + FACIAL_HAIR_MUSTACHE: 'CommonGameTag' = 380 + FASHION_RARITY_COMMON: 'CommonGameTag' = 2803 + FASHION_RARITY_EXCLUSIVE: 'CommonGameTag' = 2806 + FASHION_RARITY_EXCLUSIVE_DEPOP: 'CommonGameTag' = 2807 + FASHION_RARITY_RARE: 'CommonGameTag' = 2804 + FASHION_RARITY_VERY_RARE: 'CommonGameTag' = 2805 + FIRE_FLAMMABLE_AUTO_ADDED: 'CommonGameTag' = 1925 + FLOOR_PATTERN_CARPET: 'CommonGameTag' = 298 + FLOOR_PATTERN_DIRT_SAND: 'CommonGameTag' = 309 + FLOOR_PATTERN_FLOWERS: 'CommonGameTag' = 308 + FLOOR_PATTERN_GRASS: 'CommonGameTag' = 307 + FLOOR_PATTERN_LINOLEUM: 'CommonGameTag' = 303 + FLOOR_PATTERN_MASONRY: 'CommonGameTag' = 302 + FLOOR_PATTERN_METAL: 'CommonGameTag' = 304 + FLOOR_PATTERN_MISC: 'CommonGameTag' = 305 + FLOOR_PATTERN_OUTDOOR: 'CommonGameTag' = 306 + FLOOR_PATTERN_STONE: 'CommonGameTag' = 301 + FLOOR_PATTERN_TILE: 'CommonGameTag' = 299 + FLOOR_PATTERN_WOOD: 'CommonGameTag' = 300 + FOOD_ANY: 'CommonGameTag' = 268 + FOOD_AROMATIC: 'CommonGameTag' = 1614 + FOOD_BATUU: 'CommonGameTag' = 51240 + FOOD_BEACH_BUM: 'CommonGameTag' = 2203 + FOOD_BURRITO: 'CommonGameTag' = 1602 + FOOD_CAFETERIA_STATION_PRANKED: 'CommonGameTag' = 65551 + FOOD_CAMPFIRE: 'CommonGameTag' = 10263 + FOOD_CHOPSTICKS: 'CommonGameTag' = 55379 + FOOD_DESSERT: 'CommonGameTag' = 359 + FOOD_DISH_BOWL: 'CommonGameTag' = 1980 + FOOD_DISH_PLATE: 'CommonGameTag' = 1981 + FOOD_DISH_SHORT_FOOD: 'CommonGameTag' = 1988 + FOOD_DISH_TALL_FOOD: 'CommonGameTag' = 1987 + FOOD_EAT_WITH_TODDLER_SIZED: 'CommonGameTag' = 1675 + FOOD_EAT_WITH_UTENSIL: 'CommonGameTag' = 1674 + FOOD_EXOTIC: 'CommonGameTag' = 2939 + FOOD_FOOD_BLOB_APPLESAUCE_LIGHT_BROWN: 'CommonGameTag' = 1687 + FOOD_FOOD_BLOB_FRUIT_SALAD_RED_YELLOW_BLUE: 'CommonGameTag' = 1688 + FOOD_FOOD_BLOB_MAC_CHEESE_YELLOW_SPOTTY: 'CommonGameTag' = 1689 + FOOD_FOOD_BLOB_MINESTRONE_REDDISH_BROWN: 'CommonGameTag' = 1690 + FOOD_FOOD_BLOB_OATMEAL_LIGHT_BROWN_SPOTTY: 'CommonGameTag' = 1691 + FOOD_FOOD_BLOB_PEAS_GREEN: 'CommonGameTag' = 1693 + FOOD_FOOD_BLOB_YOGURT_PINK_WHITISH: 'CommonGameTag' = 1692 + FOOD_FRIDGE: 'CommonGameTag' = 348 + FOOD_GOURMET_MEAL: 'CommonGameTag' = 2511 + FOOD_GRAND_MEAL_EP05: 'CommonGameTag' = 2083 + FOOD_GRILLED_CHEESE: 'CommonGameTag' = 1499 + FOOD_HAS_FISH: 'CommonGameTag' = 2201 + FOOD_HAS_MEAT: 'CommonGameTag' = 1572 + FOOD_HAS_MEAT_SUBSTITUTE: 'CommonGameTag' = 1573 + FOOD_HAY: 'CommonGameTag' = 118801 + FOOD_HEALTHY: 'CommonGameTag' = 2494 + FOOD_HEALTHY_MEAL: 'CommonGameTag' = 2754 + FOOD_HORSE_FRIENDLY: 'CommonGameTag' = 2973 + FOOD_ICO: 'CommonGameTag' = 1984 + FOOD_ISLAND: 'CommonGameTag' = 63511 + FOOD_JUNGLE: 'CommonGameTag' = 45089 + FOOD_JUNK: 'CommonGameTag' = 2495 + FOOD_JUNK_SUGAR_ADDED: 'CommonGameTag' = 2755 + FOOD_KALUA_PORK: 'CommonGameTag' = 63512 + FOOD_MADE_WITH_GOLDEN_EGG: 'CommonGameTag' = 2627 + FOOD_MADE_WITH_OBSIDIAN_EGG: 'CommonGameTag' = 2628 + FOOD_MEAL_BREAKFAST: 'CommonGameTag' = 1728 + FOOD_MEAL_DINNER: 'CommonGameTag' = 1730 + FOOD_MEAL_LUNCH: 'CommonGameTag' = 1729 + FOOD_MULTI: 'CommonGameTag' = 347 + FOOD_PICKY_EATER_A_LIKE: 'CommonGameTag' = 1712 + FOOD_PICKY_EATER_B_LIKE: 'CommonGameTag' = 1713 + FOOD_PICKY_EATER_C_LIKE: 'CommonGameTag' = 1714 + FOOD_PICKY_EATER_DISLIKE: 'CommonGameTag' = 1717 + FOOD_PICKY_EATER_D_LIKE: 'CommonGameTag' = 1715 + FOOD_PICKY_EATER_E_LIKE: 'CommonGameTag' = 1716 + FOOD_PIE: 'CommonGameTag' = 2609 + FOOD_PREPARED: 'CommonGameTag' = 759 + FOOD_QUICK_MEAL: 'CommonGameTag' = 2236 + FOOD_SACK_LUNCH: 'CommonGameTag' = 43025 + FOOD_SINGLE: 'CommonGameTag' = 1686 + FOOD_SNACK: 'CommonGameTag' = 651 + FOOD_SPICY: 'CommonGameTag' = 1603 + FOOD_TODDLER_DISLIKE: 'CommonGameTag' = 1659 + FOOD_TODDLER_LIKE: 'CommonGameTag' = 1660 + FULL_BODY_APRON: 'CommonGameTag' = 951 + FULL_BODY_COSTUME: 'CommonGameTag' = 948 + FULL_BODY_JUMPSUITS: 'CommonGameTag' = 374 + FULL_BODY_LINGERIE: 'CommonGameTag' = 950 + FULL_BODY_LONG_DRESS: 'CommonGameTag' = 375 + FULL_BODY_OUTERWEAR: 'CommonGameTag' = 947 + FULL_BODY_OVERALL: 'CommonGameTag' = 952 + FULL_BODY_ROBE: 'CommonGameTag' = 949 + FULL_BODY_SHORT_DRESS: 'CommonGameTag' = 376 + FULL_BODY_SUITS: 'CommonGameTag' = 377 + FULL_BODY_SWIMSUIT: 'CommonGameTag' = 1237 + FUNC_ACCURSED_OBJECT: 'CommonGameTag' = 86019 + FUNC_ACCURSED_OBJECT_REWARD_DOLL: 'CommonGameTag' = 86026 + FUNC_ACCURSED_OBJECT_REWARD_TENDRIL: 'CommonGameTag' = 86027 + FUNC_ACID_MUD_PUDDLE: 'CommonGameTag' = 67625 + FUNC_ACTIVITY_TABLE: 'CommonGameTag' = 688 + FUNC_ACTIVITY_TABLE_DRAWING: 'CommonGameTag' = 934 + FUNC_ACTOR_CAREER_CELL_DOOR: 'CommonGameTag' = 61496 + FUNC_ACTOR_CAREER_FRIDGE: 'CommonGameTag' = 61495 + FUNC_ACTOR_CAREER_HOSPITAL_EXAM_BED: 'CommonGameTag' = 61497 + FUNC_ACTOR_CAREER_MOVIE_MEDIEVAL_STAGE_PROP: 'CommonGameTag' = 61647 + FUNC_ACTOR_CAREER_MOVIE_PIRATE_STAGE_PROP: 'CommonGameTag' = 61625 + FUNC_ACTOR_CAREER_MOVIE_SUPER_HERO_STAGE_PROP: 'CommonGameTag' = 61627 + FUNC_ACTOR_CAREER_PEDESTAL: 'CommonGameTag' = 61498 + FUNC_ACTOR_CAREER_PIRATE_WHEEL: 'CommonGameTag' = 61499 + FUNC_ACTOR_CAREER_STAGE_MARK_LARGE: 'CommonGameTag' = 61500 + FUNC_ACTOR_CAREER_STAGE_OBJECT_ALL: 'CommonGameTag' = 61611 + FUNC_ACTOR_CAREER_STAGE_OBJECT_CAMPFIRE: 'CommonGameTag' = 61633 + FUNC_ACTOR_CAREER_STUDIO_DOOR_PRIVATE: 'CommonGameTag' = 61641 + FUNC_ACTOR_CAREER_TV_HIGH_APOCALYPSE_STAGE_PROP: 'CommonGameTag' = 61626 + FUNC_ADVENTURE_GEAR: 'CommonGameTag' = 69710 + FUNC_AIR: 'CommonGameTag' = 1284 + FUNC_ALERT: 'CommonGameTag' = 1392 + FUNC_ALIEN: 'CommonGameTag' = 12397 + FUNC_ALIEN_PORTAL: 'CommonGameTag' = 12436 + FUNC_ALIEN_SATELLITE_DISH: 'CommonGameTag' = 12370 + FUNC_AMBROSIA: 'CommonGameTag' = 1989 + FUNC_AMBROSIA_TREAT: 'CommonGameTag' = 57399 + FUNC_ANIMAL: 'CommonGameTag' = 506 + FUNC_ANIMAL_OBJECT: 'CommonGameTag' = 2709 + FUNC_ANIMAL_OBJECT_ANIMAL_CLOTHES: 'CommonGameTag' = 2602 + FUNC_ANIMAL_OBJECT_ANIMAL_CLOTHES_FOR_CHICKEN: 'CommonGameTag' = 2604 + FUNC_ANIMAL_OBJECT_ANIMAL_CLOTHES_FOR_COW: 'CommonGameTag' = 2605 + FUNC_ANIMAL_OBJECT_ANIMAL_CLOTHES_FOR_FOX: 'CommonGameTag' = 2634 + FUNC_ANIMAL_OBJECT_ANIMAL_CLOTHES_FOR_LLAMA: 'CommonGameTag' = 2606 + FUNC_ANIMAL_OBJECT_ANIMAL_CLOTHES_FOR_RABBIT: 'CommonGameTag' = 2603 + FUNC_ANIMAL_OBJECT_FEEDER: 'CommonGameTag' = 3002 + FUNC_ANIMAL_OBJECT_LIVESTOCK: 'CommonGameTag' = 2710 + FUNC_ANIMAL_OBJECT_LIVESTOCK_CHICKEN: 'CommonGameTag' = 2711 + FUNC_ANIMAL_OBJECT_LIVESTOCK_CHICKEN_CHICK: 'CommonGameTag' = 2714 + FUNC_ANIMAL_OBJECT_LIVESTOCK_CHICKEN_EGG: 'CommonGameTag' = 2715 + FUNC_ANIMAL_OBJECT_LIVESTOCK_CHICKEN_HEN: 'CommonGameTag' = 2712 + FUNC_ANIMAL_OBJECT_LIVESTOCK_CHICKEN_ROOSTER: 'CommonGameTag' = 2713 + FUNC_ANIMAL_OBJECT_LIVESTOCK_CHICKEN_SPECIAL_EGG: 'CommonGameTag' = 2697 + FUNC_ANIMAL_OBJECT_LIVESTOCK_COOP: 'CommonGameTag' = 2718 + FUNC_ANIMAL_OBJECT_LIVESTOCK_COW: 'CommonGameTag' = 2716 + FUNC_ANIMAL_OBJECT_LIVESTOCK_GOAT: 'CommonGameTag' = 118785 + FUNC_ANIMAL_OBJECT_LIVESTOCK_LLAMA: 'CommonGameTag' = 2717 + FUNC_ANIMAL_OBJECT_LIVESTOCK_PEN: 'CommonGameTag' = 2719 + FUNC_ANIMAL_OBJECT_LIVESTOCK_SHEEP: 'CommonGameTag' = 118786 + FUNC_ANIMAL_OBJECT_LIVESTOCK_SHEEP_BLACK: 'CommonGameTag' = 118813 + FUNC_ANIMAL_OBJECT_LIVESTOCK_SHEEP_COLORS: 'CommonGameTag' = 118814 + FUNC_ANIMAL_OBJECT_LIVESTOCK_SHEEP_WHITE: 'CommonGameTag' = 118812 + FUNC_ANIMAL_OBJECT_WILD: 'CommonGameTag' = 2720 + FUNC_ANIMAL_OBJECT_WILD_BIRD_HOME: 'CommonGameTag' = 2722 + FUNC_ANIMAL_OBJECT_WILD_BIRD_HOME_ANIMATED_BIRD: 'CommonGameTag' = 112664 + FUNC_ANIMAL_OBJECT_WILD_RABBIT: 'CommonGameTag' = 2721 + FUNC_ANIMAL_OBJECT_WILD_RABBIT_HOME: 'CommonGameTag' = 2723 + FUNC_ANIMAL_OBJECT_WILD_RABBIT_MOUND: 'CommonGameTag' = 2724 + FUNC_ANNIVERSARY: 'CommonGameTag' = 1366 + FUNC_ANNIVERSARY_21: 'CommonGameTag' = 2519 + FUNC_APARTMENT_PROBLEM: 'CommonGameTag' = 55333 + FUNC_APPARITION: 'CommonGameTag' = 1195 + FUNC_AQUARIUM: 'CommonGameTag' = 1109 + FUNC_ARCADE: 'CommonGameTag' = 24605 + FUNC_ARCHAEOLOGY_CAN_BE_STUDIED: 'CommonGameTag' = 45112 + FUNC_ARCHAEOLOGY_CAN_BE_STUDIED_BG: 'CommonGameTag' = 2051 + FUNC_ARCHAEOLOGY_ITEM_MED: 'CommonGameTag' = 45073 + FUNC_ARCHAEOLOGY_ITEM_SMALL: 'CommonGameTag' = 45074 + FUNC_ARCHAEOLOGY_TABLE: 'CommonGameTag' = 45072 + FUNC_ART: 'CommonGameTag' = 484 + FUNC_ARTS_UNIVERSITY_SHELL: 'CommonGameTag' = 65548 + FUNC_ARTS_UNIVERSITY_SHELL_SHELL1: 'CommonGameTag' = 65560 + FUNC_ARTS_UNIVERSITY_SHELL_SHELL2: 'CommonGameTag' = 65561 + FUNC_ART_SCULPTURE: 'CommonGameTag' = 2209 + FUNC_ASH_PILE: 'CommonGameTag' = 1465 + FUNC_ASTRONAUT: 'CommonGameTag' = 1131 + FUNC_ATHLETIC: 'CommonGameTag' = 476 + FUNC_ATMOSPHERIC_CONDENSER: 'CommonGameTag' = 67616 + FUNC_ATOM: 'CommonGameTag' = 1394 + FUNC_AURAL_USE_TERRAIN_TYPES: 'CommonGameTag' = 2525 + FUNC_AUTHOR: 'CommonGameTag' = 1119 + FUNC_AUTOGRAPHED_OBJECT: 'CommonGameTag' = 61614 + FUNC_AUTONOMY_AREA_MARKER: 'CommonGameTag' = 2186 + FUNC_AUTO_PET_FEEDER: 'CommonGameTag' = 57396 + FUNC_AWNING: 'CommonGameTag' = 1155 + FUNC_BABY: 'CommonGameTag' = 744 + FUNC_BABY_SHOWER_GIFT: 'CommonGameTag' = 116740 + FUNC_BABY_YODA: 'CommonGameTag' = 2280 + FUNC_BADGE: 'CommonGameTag' = 1421 + FUNC_BAIT_CRYSTAL: 'CommonGameTag' = 983 + FUNC_BAIT_ELEMENT: 'CommonGameTag' = 982 + FUNC_BAIT_FRESH_FLOWER: 'CommonGameTag' = 827 + FUNC_BAIT_FRESH_FRUIT: 'CommonGameTag' = 825 + FUNC_BAIT_FROG: 'CommonGameTag' = 788 + FUNC_BAIT_MED_FISH: 'CommonGameTag' = 829 + FUNC_BAIT_METAL: 'CommonGameTag' = 984 + FUNC_BAIT_ORGANIC: 'CommonGameTag' = 789 + FUNC_BAIT_PLASMA_FRUIT: 'CommonGameTag' = 40972 + FUNC_BAIT_ROTTEN_FLOWER: 'CommonGameTag' = 828 + FUNC_BAIT_ROTTEN_FRUIT: 'CommonGameTag' = 826 + FUNC_BAIT_SMALL_FISH: 'CommonGameTag' = 796 + FUNC_BAIT_TRASH: 'CommonGameTag' = 830 + FUNC_BAKE: 'CommonGameTag' = 1385 + FUNC_BAKING: 'CommonGameTag' = 1387 + FUNC_BALL: 'CommonGameTag' = 528 + FUNC_BANQUET: 'CommonGameTag' = 8218 + FUNC_BANQUET_TABLE: 'CommonGameTag' = 8213 + FUNC_BAR: 'CommonGameTag' = 498 + FUNC_BARBECUE: 'CommonGameTag' = 1079 + FUNC_BARREL: 'CommonGameTag' = 12378 + FUNC_BAR_GLOBE: 'CommonGameTag' = 36865 + FUNC_BASEBOARD: 'CommonGameTag' = 1084 + FUNC_BASIN: 'CommonGameTag' = 1110 + FUNC_BASKET: 'CommonGameTag' = 527 + FUNC_BASKETBALL: 'CommonGameTag' = 55404 + FUNC_BASKETBALL_HOOP: 'CommonGameTag' = 55402 + FUNC_BASSINET: 'CommonGameTag' = 2926 + FUNC_BAT: 'CommonGameTag' = 1220 + FUNC_BATH: 'CommonGameTag' = 1022 + FUNC_BATHROOM: 'CommonGameTag' = 1023 + FUNC_BATHTUB: 'CommonGameTag' = 990 + FUNC_BATTLE_STATION: 'CommonGameTag' = 32770 + FUNC_BATUU_ANTIQUITIES: 'CommonGameTag' = 51230 + FUNC_BATUU_BINOCULARS: 'CommonGameTag' = 51238 + FUNC_BATUU_BLASTER: 'CommonGameTag' = 51233 + FUNC_BATUU_COMM_LINK: 'CommonGameTag' = 51234 + FUNC_BATUU_CONTROL_PANEL: 'CommonGameTag' = 51239 + FUNC_BATUU_CONTROL_PANEL_FIRST_ORDER: 'CommonGameTag' = 51250 + FUNC_BATUU_CONTROL_PANEL_FIRST_ORDER_COMMUNICATIONS_TOWER: 'CommonGameTag' = 51244 + FUNC_BATUU_CONTROL_PANEL_MAIN_STRIP: 'CommonGameTag' = 51257 + FUNC_BATUU_CONTROL_PANEL_RESISTANCE: 'CommonGameTag' = 51256 + FUNC_BATUU_DATA_SPIKE: 'CommonGameTag' = 51235 + FUNC_BATUU_FAKE_ID: 'CommonGameTag' = 51236 + FUNC_BATUU_MISSION_RS8_RESCUE_PREP_OBJ: 'CommonGameTag' = 51245 + FUNC_BATUU_MISSION_VALUABLE: 'CommonGameTag' = 51242 + FUNC_BATUU_PORG: 'CommonGameTag' = 51271 + FUNC_BATUU_SHELL: 'CommonGameTag' = 51249 + FUNC_BATUU_SHELL_DOCKING_BAY: 'CommonGameTag' = 51247 + FUNC_BATUU_SHELL_DWELLING: 'CommonGameTag' = 51248 + FUNC_BATUU_SUPPLY_CRATE: 'CommonGameTag' = 51206 + FUNC_BATUU_SUPPLY_CRATE_BLACK_SPIRE: 'CommonGameTag' = 51268 + FUNC_BATUU_SUPPLY_CRATE_FIRST_ORDER: 'CommonGameTag' = 51267 + FUNC_BATUU_SUPPLY_CRATE_RESISTANCE: 'CommonGameTag' = 51266 + FUNC_BATUU_THERMAL_DETONATOR: 'CommonGameTag' = 51237 + FUNC_BBQ: 'CommonGameTag' = 1078 + FUNC_BEACH_CAVE: 'CommonGameTag' = 63534 + FUNC_BEAM: 'CommonGameTag' = 1427 + FUNC_BEAR: 'CommonGameTag' = 508 + FUNC_BEAST: 'CommonGameTag' = 1216 + FUNC_BED: 'CommonGameTag' = 777 + FUNC_BEDSIDE_TABLE: 'CommonGameTag' = 1009 + FUNC_BED_KID: 'CommonGameTag' = 888 + FUNC_BED_VALID_MONSTER_UNDER_TARGET: 'CommonGameTag' = 1542 + FUNC_BEE_BOX: 'CommonGameTag' = 59449 + FUNC_BEE_SWARM: 'CommonGameTag' = 59452 + FUNC_BENCH: 'CommonGameTag' = 494 + FUNC_BEVERAGE: 'CommonGameTag' = 500 + FUNC_BG_PIPE_ORGAN: 'CommonGameTag' = 1709 + FUNC_BG_YOGA_MAT: 'CommonGameTag' = 1710 + FUNC_BICYCLE: 'CommonGameTag' = 2956 + FUNC_BIKE: 'CommonGameTag' = 2278 + FUNC_BIN: 'CommonGameTag' = 925 + FUNC_BIO_FUEL: 'CommonGameTag' = 2336 + FUNC_BIRD_FEEDER: 'CommonGameTag' = 34820 + FUNC_BIZARRE_IDOL: 'CommonGameTag' = 86030 + FUNC_BLADDER: 'CommonGameTag' = 995 + FUNC_BLINDS: 'CommonGameTag' = 1153 + FUNC_BLOB: 'CommonGameTag' = 512 + FUNC_BLOCK_CONSTRUCTION_TABLE: 'CommonGameTag' = 43029 + FUNC_BONE: 'CommonGameTag' = 1210 + FUNC_BONFIRE: 'CommonGameTag' = 2190 + FUNC_BONY: 'CommonGameTag' = 1211 + FUNC_BOOK: 'CommonGameTag' = 893 + FUNC_BOOKCASE: 'CommonGameTag' = 1389 + FUNC_BOOK_BOOK_OF_LIFE: 'CommonGameTag' = 1177 + FUNC_BOOK_DO_NOT_PUT_AWAY: 'CommonGameTag' = 2839 + FUNC_BOOK_HOMEWORK: 'CommonGameTag' = 1080 + FUNC_BOOK_MAGIC_TOME: 'CommonGameTag' = 49153 + FUNC_BOOK_MANUAL: 'CommonGameTag' = 2767 + FUNC_BOOK_PLAYER_CREATED: 'CommonGameTag' = 656 + FUNC_BOOK_WEREWOLF: 'CommonGameTag' = 135184 + FUNC_BOOMBOX: 'CommonGameTag' = 991 + FUNC_BOOTH: 'CommonGameTag' = 26629 + FUNC_BOOTH_BANQUETTE: 'CommonGameTag' = 26641 + FUNC_BOOTH_CORNER: 'CommonGameTag' = 26636 + FUNC_BOTTLE: 'CommonGameTag' = 1160 + FUNC_BOWL: 'CommonGameTag' = 1222 + FUNC_BOWLING: 'CommonGameTag' = 38925 + FUNC_BOWLING_LANE: 'CommonGameTag' = 38913 + FUNC_BOWLING_LANE_BG: 'CommonGameTag' = 1720 + FUNC_BOX: 'CommonGameTag' = 579 + FUNC_BOX_OF_DECORATIONS: 'CommonGameTag' = 59408 + FUNC_BREWER: 'CommonGameTag' = 1882 + FUNC_BRICK: 'CommonGameTag' = 1086 + FUNC_BRIEFCASE: 'CommonGameTag' = 55407 + FUNC_BUBBLE_BLOWER: 'CommonGameTag' = 55310 + FUNC_BUBBLE_TEA_COUNTER: 'CommonGameTag' = 114698 + FUNC_BUCKET: 'CommonGameTag' = 1291 + FUNC_BUFFET: 'CommonGameTag' = 8217 + FUNC_BUILD_OBJ_HAS_ADDITIONAL_GAMEPLAY: 'CommonGameTag' = 2808 + FUNC_BUSH: 'CommonGameTag' = 1163 + FUNC_BUSINESS: 'CommonGameTag' = 1323 + FUNC_BUSINESS_LIGHT: 'CommonGameTag' = 1545 + FUNC_CABINET: 'CommonGameTag' = 1409 + FUNC_CAFETERIA_STATION: 'CommonGameTag' = 65550 + FUNC_CAGE: 'CommonGameTag' = 1431 + FUNC_CAKE: 'CommonGameTag' = 1391 + FUNC_CALENDAR: 'CommonGameTag' = 1395 + FUNC_CAMERAS: 'CommonGameTag' = 1381 + FUNC_CAMERA_NORMAL: 'CommonGameTag' = 12342 + FUNC_CAMERA_OUTSTANDING: 'CommonGameTag' = 12343 + FUNC_CAMERA_POOR: 'CommonGameTag' = 12341 + FUNC_CAMERA_PRO: 'CommonGameTag' = 79875 + FUNC_CAMERA_SLOT_TRIPOD: 'CommonGameTag' = 2221 + FUNC_CAMERA_TRIPOD: 'CommonGameTag' = 79873 + FUNC_CAMERA_TRIPOD_ANCHOR_MARK: 'CommonGameTag' = 79877 + FUNC_CAMPFIRE: 'CommonGameTag' = 10246 + FUNC_CAMPING: 'CommonGameTag' = 10245 + FUNC_CANDLE: 'CommonGameTag' = 1207 + FUNC_CANDLES: 'CommonGameTag' = 1328 + FUNC_CANDLE_MAKING_STATION: 'CommonGameTag' = 67628 + FUNC_CANDY_BOWL: 'CommonGameTag' = 2117 + FUNC_CANDY_SKULL: 'CommonGameTag' = 1554 + FUNC_CANDY_SKULL_01: 'CommonGameTag' = 1555 + FUNC_CANDY_SKULL_02: 'CommonGameTag' = 1556 + FUNC_CANDY_SKULL_03: 'CommonGameTag' = 1557 + FUNC_CANDY_SKULL_04: 'CommonGameTag' = 1558 + FUNC_CANDY_SKULL_05: 'CommonGameTag' = 1559 + FUNC_CANDY_SKULL_06: 'CommonGameTag' = 1560 + FUNC_CANDY_SKULL_07: 'CommonGameTag' = 1561 + FUNC_CANDY_SKULL_08: 'CommonGameTag' = 1562 + FUNC_CANDY_SKULL_09: 'CommonGameTag' = 1563 + FUNC_CANDY_SKULL_10: 'CommonGameTag' = 1564 + FUNC_CANNED_GOOD: 'CommonGameTag' = 2580 + FUNC_CANS: 'CommonGameTag' = 1297 + FUNC_CANT_REPOSSESS: 'CommonGameTag' = 2276 + FUNC_CANVAS: 'CommonGameTag' = 573 + FUNC_CAN_BE_VACUUMED: 'CommonGameTag' = 94213 + FUNC_CAN_BE_VACUUMED_GROSS: 'CommonGameTag' = 94214 + FUNC_CAN_BE_VACUUMED_HANDHELD: 'CommonGameTag' = 94224 + FUNC_CARDS: 'CommonGameTag' = 1316 + FUNC_CARD_GAME: 'CommonGameTag' = 922 + FUNC_CARD_TABLE: 'CommonGameTag' = 988 + FUNC_CARPENTER: 'CommonGameTag' = 492 + FUNC_CARPET: 'CommonGameTag' = 1161 + FUNC_CART: 'CommonGameTag' = 1402 + FUNC_CARVED_PUMPKIN: 'CommonGameTag' = 22529 + FUNC_CARVING_STATION: 'CommonGameTag' = 22540 + FUNC_CASE: 'CommonGameTag' = 1411 + FUNC_CAT_CONDO: 'CommonGameTag' = 57383 + FUNC_CAT_WAND: 'CommonGameTag' = 57429 + FUNC_CAT_WAND_RAINBOW: 'CommonGameTag' = 57453 + FUNC_CAULDRON: 'CommonGameTag' = 49155 + FUNC_CAULDRON_BG: 'CommonGameTag' = 2597 + FUNC_CAULDRON_POTION: 'CommonGameTag' = 49156 + FUNC_CELEBRITY_FAN_TARGETABLE: 'CommonGameTag' = 61475 + FUNC_CELEBRITY_TILE_ORIGINAL: 'CommonGameTag' = 61636 + FUNC_CELL: 'CommonGameTag' = 1378 + FUNC_CEMETERY: 'CommonGameTag' = 1200 + FUNC_CHAIR: 'CommonGameTag' = 1303 + FUNC_CHAIR_DEBATE_SHOWDOWN_AUDIENCE: 'CommonGameTag' = 65592 + FUNC_CHAIR_DEBATE_SHOWDOWN_JUDGE: 'CommonGameTag' = 65593 + FUNC_CHALKBOARD: 'CommonGameTag' = 1426 + FUNC_CHANGE_CLOTHES: 'CommonGameTag' = 1448 + FUNC_CHANGING_TABLE: 'CommonGameTag' = 2957 + FUNC_CHARISMA: 'CommonGameTag' = 1099 + FUNC_CHEER_MAT_GROUP: 'CommonGameTag' = 114753 + FUNC_CHEER_MAT_SOLO: 'CommonGameTag' = 114754 + FUNC_CHEF: 'CommonGameTag' = 1115 + FUNC_CHEF_STATION: 'CommonGameTag' = 26627 + FUNC_CHEM_ANALYZER: 'CommonGameTag' = 12361 + FUNC_CHEM_LAB: 'CommonGameTag' = 12360 + FUNC_CHESS: 'CommonGameTag' = 485 + FUNC_CHILD: 'CommonGameTag' = 1136 + FUNC_CHILD_VIOLIN: 'CommonGameTag' = 1176 + FUNC_CHIMNEY: 'CommonGameTag' = 1164 + FUNC_CHRISTMAS: 'CommonGameTag' = 1327 + FUNC_CLAY: 'CommonGameTag' = 511 + FUNC_CLIMBING_ROUTE: 'CommonGameTag' = 69692 + FUNC_CLIMBING_ROUTE_LARGE: 'CommonGameTag' = 69701 + FUNC_CLIMBING_ROUTE_MEDIUM: 'CommonGameTag' = 69700 + FUNC_CLIMBING_ROUTE_SMALL: 'CommonGameTag' = 69699 + FUNC_CLOBBERS_SNOW_FOOTPRINTS: 'CommonGameTag' = 2114 + FUNC_CLONE_NORMAL_MIN: 'CommonGameTag' = 12344 + FUNC_CLOSET: 'CommonGameTag' = 1139 + FUNC_CLOTHES: 'CommonGameTag' = 1162 + FUNC_CLUBS: 'CommonGameTag' = 24593 + FUNC_CLUE: 'CommonGameTag' = 12371 + FUNC_COAT_RACK: 'CommonGameTag' = 1500 + FUNC_COBWEB: 'CommonGameTag' = 1193 + FUNC_COCONUT_PLANT: 'CommonGameTag' = 63518 + FUNC_COFFEE: 'CommonGameTag' = 525 + FUNC_COFFEE_CART: 'CommonGameTag' = 65603 + FUNC_COFFEE_MAKER: 'CommonGameTag' = 1167 + FUNC_COFFIN: 'CommonGameTag' = 40970 + FUNC_COLLECTIBLE: 'CommonGameTag' = 2787 + FUNC_COLLECTION_MONSTERS: 'CommonGameTag' = 32771 + FUNC_COLLECTION_SPAWNER: 'CommonGameTag' = 12425 + FUNC_COLLECTION_WEREWOLF: 'CommonGameTag' = 2792 + FUNC_COLLECT_ARTIFACT: 'CommonGameTag' = 45075 + FUNC_COLLECT_ARTIFACT_FAKE: 'CommonGameTag' = 45076 + FUNC_COLLECT_ARTIFACT_GENUINE: 'CommonGameTag' = 45092 + FUNC_COLLECT_ARTIFACT_KNIFE: 'CommonGameTag' = 45098 + FUNC_COLLECT_ARTIFACT_MAIL: 'CommonGameTag' = 45077 + FUNC_COLLECT_ARTIFACT_MAIL_FAKE: 'CommonGameTag' = 45093 + FUNC_COLLECT_ARTIFACT_MASK: 'CommonGameTag' = 45099 + FUNC_COLLECT_ARTIFACT_SKULL: 'CommonGameTag' = 45100 + FUNC_COLLECT_ARTIFACT_STATUE: 'CommonGameTag' = 45101 + FUNC_COLLECT_ARTIFACT_VASE: 'CommonGameTag' = 45097 + FUNC_COLOR_FROM_SAND: 'CommonGameTag' = 2200 + FUNC_COMEDY: 'CommonGameTag' = 1130 + FUNC_COMEDY_ROUTINE: 'CommonGameTag' = 589 + FUNC_COMEDY_ROUTINE_LONG: 'CommonGameTag' = 594 + FUNC_COMEDY_ROUTINE_MEDIUM: 'CommonGameTag' = 593 + FUNC_COMEDY_ROUTINE_SHORT: 'CommonGameTag' = 592 + FUNC_COMMUNITY_BOARD_BG: 'CommonGameTag' = 2284 + FUNC_COMMUNITY_BOARD_EP14: 'CommonGameTag' = 118798 + FUNC_COMPUTER: 'CommonGameTag' = 514 + FUNC_COMPUTER_GLASSES: 'CommonGameTag' = 65655 + FUNC_CONCEPT_ECO_INVENTION: 'CommonGameTag' = 67612 + FUNC_CONCEPT_MUNICIPAL: 'CommonGameTag' = 67611 + FUNC_CONCRETE: 'CommonGameTag' = 1092 + FUNC_COOK: 'CommonGameTag' = 524 + FUNC_COOKING: 'CommonGameTag' = 1102 + FUNC_COOLER: 'CommonGameTag' = 10243 + FUNC_CORPORATE_WORKER_APOLOGY_GIFT: 'CommonGameTag' = 69742 + FUNC_COT: 'CommonGameTag' = 1287 + FUNC_COUCH: 'CommonGameTag' = 989 + FUNC_COUNTER: 'CommonGameTag' = 1525 + FUNC_COW: 'CommonGameTag' = 112681 + FUNC_COWPLANT: 'CommonGameTag' = 1375 + FUNC_CRAFT: 'CommonGameTag' = 513 + FUNC_CRAFTED_CANDLE: 'CommonGameTag' = 67622 + FUNC_CRAFTED_OBJECT_GENERIC: 'CommonGameTag' = 2824 + FUNC_CRAFT_SALES_TABLE: 'CommonGameTag' = 55365 + FUNC_CRAFT_SALES_TABLE_JUNGLE_SUPPLIES_FUN: 'CommonGameTag' = 2047 + FUNC_CRAFT_SALES_TABLE_JUNGLE_SUPPLIES_FURNITURE: 'CommonGameTag' = 2046 + FUNC_CRAFT_SALES_TABLE_JUNGLE_SUPPLIES_PET: 'CommonGameTag' = 2048 + FUNC_CRAFT_SALES_TABLE_JUNGLE_SUPPLIES_SUPPLIES: 'CommonGameTag' = 2045 + FUNC_CRAFT_SALES_TABLE_PAINTING: 'CommonGameTag' = 2387 + FUNC_CRAFT_SALES_TABLE_REQUIRED_OBJECT_BG: 'CommonGameTag' = 2285 + FUNC_CRAFT_SALES_TABLE_SECRET_ITEMS_COLLECTIBLES: 'CommonGameTag' = 2050 + FUNC_CRAFT_SALES_TABLE_SECRET_ITEMS_SUPPLIES: 'CommonGameTag' = 2049 + FUNC_CRAFT_SALES_TABLE_TABLE: 'CommonGameTag' = 2386 + FUNC_CRATE: 'CommonGameTag' = 12379 + FUNC_CRATES: 'CommonGameTag' = 1401 + FUNC_CRATES_ROUTABLE: 'CommonGameTag' = 57385 + FUNC_CREATIVITY: 'CommonGameTag' = 24597 + FUNC_CRIB: 'CommonGameTag' = 745 + FUNC_CRIME_MAP: 'CommonGameTag' = 12372 + FUNC_CRIMINAL: 'CommonGameTag' = 1113 + FUNC_CROSS_STITCH: 'CommonGameTag' = 2577 + FUNC_CROSS_STITCH_HOOP: 'CommonGameTag' = 2613 + FUNC_CROSS_STITCH_HOOP_COMPLETE: 'CommonGameTag' = 2614 + FUNC_CRYPT: 'CommonGameTag' = 1201 + FUNC_CRYSTAL_BALL: 'CommonGameTag' = 1184 + FUNC_CUBE: 'CommonGameTag' = 502 + FUNC_CULINARY: 'CommonGameTag' = 1114 + FUNC_CULLING_PORTAL: 'CommonGameTag' = 1546 + FUNC_CUP: 'CommonGameTag' = 1302 + FUNC_CUPBOARD: 'CommonGameTag' = 1012 + FUNC_CUPCAKE_MACHINE: 'CommonGameTag' = 1376 + FUNC_CURTAIN: 'CommonGameTag' = 1014 + FUNC_DANCEFLOOR: 'CommonGameTag' = 1455 + FUNC_DANCING: 'CommonGameTag' = 24601 + FUNC_DARTBOARD: 'CommonGameTag' = 24609 + FUNC_DAY_OF_THE_DEAD: 'CommonGameTag' = 1565 + FUNC_DEATH: 'CommonGameTag' = 575 + FUNC_DECAL: 'CommonGameTag' = 1151 + FUNC_DENIZEN_POND: 'CommonGameTag' = 2157 + FUNC_DESSERT: 'CommonGameTag' = 1386 + FUNC_DETECTIVE: 'CommonGameTag' = 12327 + FUNC_DETECTIVE_CHIEF_CHAIR: 'CommonGameTag' = 12435 + FUNC_DETECTIVE_CLUE_ADD_TO_MAP: 'CommonGameTag' = 12318 + FUNC_DETECTIVE_CLUE_CHEMICAL: 'CommonGameTag' = 12296 + FUNC_DETECTIVE_CLUE_DATABASE: 'CommonGameTag' = 12326 + FUNC_DETECTIVE_CLUE_PICTURE: 'CommonGameTag' = 12312 + FUNC_DETECTIVE_CLUE_SAMPLE: 'CommonGameTag' = 12313 + FUNC_DEW_COLLECTOR: 'CommonGameTag' = 67615 + FUNC_DEW_COLLECTOR_HIGH_QUALITY: 'CommonGameTag' = 67646 + FUNC_DIA_DE_LOS_MUERTOS: 'CommonGameTag' = 1566 + FUNC_DIGITAL_FRAME: 'CommonGameTag' = 2216 + FUNC_DINING: 'CommonGameTag' = 1124 + FUNC_DINING_CHAIR: 'CommonGameTag' = 1006 + FUNC_DINING_HUTCH: 'CommonGameTag' = 1125 + FUNC_DINOSAUR: 'CommonGameTag' = 509 + FUNC_DIPLOMA: 'CommonGameTag' = 1415 + FUNC_DIRECTOR_CHAIR: 'CommonGameTag' = 61463 + FUNC_DISABLE_AUTO_SHAPE: 'CommonGameTag' = 2551 + FUNC_DISABLE_IN_LOT_THUMBNAILS: 'CommonGameTag' = 2100 + FUNC_DISHWASHER: 'CommonGameTag' = 1451 + FUNC_DISPENSER: 'CommonGameTag' = 1419 + FUNC_DIVIDER: 'CommonGameTag' = 1033 + FUNC_DJING: 'CommonGameTag' = 24600 + FUNC_DJ_BOOTH: 'CommonGameTag' = 1456 + FUNC_DOCTOR: 'CommonGameTag' = 12328 + FUNC_DOCTOR_ITEM_SAMPLE: 'CommonGameTag' = 12330 + FUNC_DOCTOR_OBJECT_EXAM_BED: 'CommonGameTag' = 12329 + FUNC_DOCTOR_OBJECT_MEDICAL_TREADMILL: 'CommonGameTag' = 12348 + FUNC_DOCTOR_OBJECT_SURGERY_TABLE: 'CommonGameTag' = 12333 + FUNC_DOCTOR_OBJECT_XRAY_MACHINE: 'CommonGameTag' = 12332 + FUNC_DOCTOR_PLAYSET: 'CommonGameTag' = 43030 + FUNC_DOESNT_SPAWN_FIRE: 'CommonGameTag' = 1494 + FUNC_DOLL: 'CommonGameTag' = 580 + FUNC_DOLLHOUSE: 'CommonGameTag' = 666 + FUNC_DOLLY_CAMERA: 'CommonGameTag' = 61462 + FUNC_DOLPHIN_ALBINO: 'CommonGameTag' = 63492 + FUNC_DOLPHIN_MERFOLK: 'CommonGameTag' = 63493 + FUNC_DOLPHIN_SPAWNER: 'CommonGameTag' = 63494 + FUNC_DOLPHIN_STANDARD: 'CommonGameTag' = 63491 + FUNC_DONT_WAKE_LLAMA: 'CommonGameTag' = 24608 + FUNC_DOUBLE_BED: 'CommonGameTag' = 778 + FUNC_DRAGON: 'CommonGameTag' = 510 + FUNC_DRAWING_POSTED: 'CommonGameTag' = 43011 + FUNC_DRAW_SOMETHING: 'CommonGameTag' = 1003 + FUNC_DRINK: 'CommonGameTag' = 499 + FUNC_DRINK_GIFTING: 'CommonGameTag' = 2666 + FUNC_DRINK_TRAY: 'CommonGameTag' = 1552 + FUNC_DROID_BB_SERIES: 'CommonGameTag' = 51219 + FUNC_DROID_PERSONALITY_CHIP: 'CommonGameTag' = 51211 + FUNC_DROID_PERSONALITY_CHIP_FIRST_ORDER: 'CommonGameTag' = 51213 + FUNC_DROID_PERSONALITY_CHIP_FIRST_ORDER_2: 'CommonGameTag' = 51252 + FUNC_DROID_PERSONALITY_CHIP_RESISTANCE: 'CommonGameTag' = 51212 + FUNC_DROID_PERSONALITY_CHIP_RESISTANCE_2: 'CommonGameTag' = 51251 + FUNC_DROID_PERSONALITY_CHIP_SCOUNDREL: 'CommonGameTag' = 51214 + FUNC_DROID_PERSONALITY_CHIP_SCOUNDREL_2: 'CommonGameTag' = 51253 + FUNC_DROID_R_SERIES: 'CommonGameTag' = 51220 + FUNC_DROPS_LEAVES_EP10_MAPLE_GREEN: 'CommonGameTag' = 2513 + FUNC_DROPS_LEAVES_EP10_MAPLE_RED: 'CommonGameTag' = 2514 + FUNC_DROPS_LEAVES_LARGE: 'CommonGameTag' = 2063 + FUNC_DROPS_LEAVES_MEDIUM: 'CommonGameTag' = 2062 + FUNC_DROPS_LEAVES_SMALL: 'CommonGameTag' = 2056 + FUNC_DROPS_LEAVES_X_LARGE: 'CommonGameTag' = 2064 + FUNC_DUCT: 'CommonGameTag' = 1428 + FUNC_DUMPSTER: 'CommonGameTag' = 67605 + FUNC_DUMPSTER_DEAL_APPLIANCE: 'CommonGameTag' = 2446 + FUNC_DUMPSTER_DEAL_BURNT_AND_SCRATCHED: 'CommonGameTag' = 2445 + FUNC_DUMPSTER_DEAL_COLLECTIBLE: 'CommonGameTag' = 2454 + FUNC_DUMPSTER_DEAL_CRAFTABLE: 'CommonGameTag' = 2455 + FUNC_DUMPSTER_DEAL_MISCELLANEOUS: 'CommonGameTag' = 2448 + FUNC_DUMPSTER_DEAL_PLUMBING: 'CommonGameTag' = 2447 + FUNC_DUMPSTER_DEAL_UPGRADE_PART: 'CommonGameTag' = 2456 + FUNC_DUMPSTER_HIGH_PRICE_DROP: 'CommonGameTag' = 67610 + FUNC_DUMPSTER_INSECT: 'CommonGameTag' = 67645 + FUNC_DUMPSTER_LOW_PRICE_DROP: 'CommonGameTag' = 67609 + FUNC_DUMPSTER_MEAL_FOOD: 'CommonGameTag' = 2452 + FUNC_DUMPSTER_MEAL_INGREDIENT: 'CommonGameTag' = 2451 + FUNC_DUMPSTER_MEAL_INSECT: 'CommonGameTag' = 2453 + FUNC_DUMPSTER_UNIQUE_DROP: 'CommonGameTag' = 67608 + FUNC_DUST_BUNNY: 'CommonGameTag' = 94216 + FUNC_DUST_FRIEND: 'CommonGameTag' = 94215 + FUNC_DUST_PILE: 'CommonGameTag' = 94209 + FUNC_EARBUDS: 'CommonGameTag' = 1725 + FUNC_EASEL: 'CommonGameTag' = 482 + FUNC_EASTER_EGG: 'CommonGameTag' = 2082 + FUNC_ECO_ECO_FRIENDLY_APPLIANCES: 'CommonGameTag' = 2375 + FUNC_ECO_FOOTPRINT_OBJECT_STATE: 'CommonGameTag' = 2376 + FUNC_ECO_FOOTPRINT_SUN_RAY: 'CommonGameTag' = 67588 + FUNC_ECO_GREEN_GARDENING: 'CommonGameTag' = 2374 + FUNC_ECO_NEIGHBORHOOD_UTILITY: 'CommonGameTag' = 2372 + FUNC_ECO_UPCYCLING_INITIATIVE: 'CommonGameTag' = 2373 + FUNC_EGG: 'CommonGameTag' = 2576 + FUNC_EGG_SEARCH: 'CommonGameTag' = 112685 + FUNC_ENERGY: 'CommonGameTag' = 997 + FUNC_ENHANCED_SMELL: 'CommonGameTag' = 135183 + FUNC_ENTERTAINER: 'CommonGameTag' = 1129 + FUNC_ENTERTAINMENT_CENTER: 'CommonGameTag' = 2940 + FUNC_EP01_ALIEN_TRANSMUTE_COMPATIBLE: 'CommonGameTag' = 12369 + FUNC_EP01_COLLECTIBLE_BG: 'CommonGameTag' = 2038 + FUNC_EP01_SERUM_AGE_AWAY: 'CommonGameTag' = 12422 + FUNC_EP01_SERUM_ALIEN_AURA: 'CommonGameTag' = 12421 + FUNC_EP01_SERUM_EMBIGGEN: 'CommonGameTag' = 12416 + FUNC_EP01_SERUM_FIXERS_LUCK: 'CommonGameTag' = 12419 + FUNC_EP01_SERUM_GHOST_GOO: 'CommonGameTag' = 12417 + FUNC_EP01_SERUM_NEED_FIXER: 'CommonGameTag' = 12354 + FUNC_EP01_SERUM_OX_STRENGTH: 'CommonGameTag' = 12418 + FUNC_EP01_SERUM_REAPERS_FRIEND: 'CommonGameTag' = 12420 + FUNC_EP01_SERUM_RED_HOT: 'CommonGameTag' = 12414 + FUNC_EP01_SERUM_ROSE_PERFUME: 'CommonGameTag' = 12352 + FUNC_EP01_SERUM_SLIMIFY: 'CommonGameTag' = 12415 + FUNC_EP01_SERUM_SMART: 'CommonGameTag' = 12356 + FUNC_EP01_SERUM_SNAKE_OIL: 'CommonGameTag' = 12353 + FUNC_EP01_SERUM_SPARK_DRIVE: 'CommonGameTag' = 12355 + FUNC_EP01_SERUM_SYNTHETIC_FOOD: 'CommonGameTag' = 12351 + FUNC_EP10_FESTIVAL_FOOD: 'CommonGameTag' = 69732 + FUNC_EQUESTRIAN_CENTER: 'CommonGameTag' = 118871 + FUNC_ESPORTS_GAMER: 'CommonGameTag' = 1134 + FUNC_ESPRESSO_BAR: 'CommonGameTag' = 1452 + FUNC_ESPRESSO_GRINDER: 'CommonGameTag' = 1454 + FUNC_ESPRESSO_MACHINE: 'CommonGameTag' = 1453 + FUNC_ETAGERE: 'CommonGameTag' = 1035 + FUNC_EXERCISE: 'CommonGameTag' = 473 + FUNC_EXIT: 'CommonGameTag' = 1416 + FUNC_EXPERIMENTAL_FOOD: 'CommonGameTag' = 26631 + FUNC_EXTINGUISHER: 'CommonGameTag' = 1417 + FUNC_FABRICATED_ITEM: 'CommonGameTag' = 67587 + FUNC_FABRICATION_DYE: 'CommonGameTag' = 67590 + FUNC_FABRICATION_DYE_COMMON: 'CommonGameTag' = 67637 + FUNC_FABRICATOR: 'CommonGameTag' = 67586 + FUNC_FACE: 'CommonGameTag' = 1214 + FUNC_FACIAL_MASK: 'CommonGameTag' = 18472 + FUNC_FAMILY_BULLETIN_BOARD: 'CommonGameTag' = 43016 + FUNC_FAN: 'CommonGameTag' = 1414 + FUNC_FASHION_STUDIO_SEARCH: 'CommonGameTag' = 2220 + FUNC_FAUCET: 'CommonGameTag' = 1138 + FUNC_FAVORITE_CHOPSTICKS: 'CommonGameTag' = 69685 + FUNC_FAVORITE_CHOPSTICK_CLASSIC_WOOD: 'CommonGameTag' = 69741 + FUNC_FAVORITE_CHOPSTICK_PLASTIC: 'CommonGameTag' = 69687 + FUNC_FAVORITE_CHOPSTICK_STEEL: 'CommonGameTag' = 69688 + FUNC_FAVORITE_CHOPSTICK_WOOD: 'CommonGameTag' = 69686 + FUNC_FESTIVAL_AUTONOMY_AREA_MARKER: 'CommonGameTag' = 1575 + FUNC_FESTIVAL_AUTONOMY_AREA_MARKER: 'CommonGameTag' = 55297 + FUNC_FESTIVAL_BLOSSOM_TEA_FOUNTAIN: 'CommonGameTag' = 55388 + FUNC_FESTIVAL_CURRY_CONTEST: 'CommonGameTag' = 55369 + FUNC_FESTIVAL_FIREWORKS_DARK_SIDE: 'CommonGameTag' = 55366 + FUNC_FESTIVAL_FIREWORKS_LIGHT_SIDE: 'CommonGameTag' = 55367 + FUNC_FESTIVAL_FLEA_MARKET_OBJECTS: 'CommonGameTag' = 55392 + FUNC_FESTIVAL_LAMP_TEA_FOUNTAINS: 'CommonGameTag' = 55387 + FUNC_FESTIVAL_TEA_DARK_TEA: 'CommonGameTag' = 55345 + FUNC_FESTIVAL_TEA_LIGHT_TEA: 'CommonGameTag' = 55346 + FUNC_FESTIVAL_TEA_SAKURA: 'CommonGameTag' = 55347 + FUNC_FETCHABLE: 'CommonGameTag' = 1875 + FUNC_FIGURINE: 'CommonGameTag' = 1157 + FUNC_FILE_HOLDER: 'CommonGameTag' = 1425 + FUNC_FILTH_FIEND: 'CommonGameTag' = 94217 + FUNC_FIRE: 'CommonGameTag' = 1305 + FUNC_FIREPLACE_MAGIC: 'CommonGameTag' = 49183 + FUNC_FIREWORKS: 'CommonGameTag' = 1578 + FUNC_FIREWORKS_ARTS_CRAFTS: 'CommonGameTag' = 1588 + FUNC_FIREWORKS_BLOSSOM: 'CommonGameTag' = 1583 + FUNC_FIREWORKS_FOOD: 'CommonGameTag' = 1586 + FUNC_FIREWORKS_LAMP: 'CommonGameTag' = 1585 + FUNC_FIREWORKS_LOGIC: 'CommonGameTag' = 1584 + FUNC_FIREWORKS_MUSIC: 'CommonGameTag' = 1587 + FUNC_FIREWORKS_SPARKLER: 'CommonGameTag' = 1590 + FUNC_FIREWORKS_SPARKLER_BLOSSOM: 'CommonGameTag' = 55408 + FUNC_FIREWORKS_SPARKLER_FOOD: 'CommonGameTag' = 55409 + FUNC_FIREWORKS_SPARKLER_LAMP: 'CommonGameTag' = 55410 + FUNC_FIREWORKS_SPARKLER_LOGIC: 'CommonGameTag' = 55411 + FUNC_FIREWORKS_SPARKLER_WEDDING: 'CommonGameTag' = 55412 + FUNC_FIREWORKS_WEDDING: 'CommonGameTag' = 1589 + FUNC_FIRE_ALARM: 'CommonGameTag' = 1165 + FUNC_FIRE_PIT: 'CommonGameTag' = 1306 + FUNC_FISH: 'CommonGameTag' = 992 + FUNC_FISHING_LOCATION_ANY: 'CommonGameTag' = 2164 + FUNC_FISHING_LOCATION_HOLE: 'CommonGameTag' = 937 + FUNC_FISHING_LOCATION_SPOT: 'CommonGameTag' = 938 + FUNC_FISHING_SPOT_BAY: 'CommonGameTag' = 63528 + FUNC_FISHING_SPOT_COMMON: 'CommonGameTag' = 2193 + FUNC_FISHING_SPOT_RARE: 'CommonGameTag' = 2192 + FUNC_FISHING_SPOT_TROPICAL: 'CommonGameTag' = 63526 + FUNC_FISHING_SPOT_UNCOMMON: 'CommonGameTag' = 2191 + FUNC_FISH_ENDANGERED: 'CommonGameTag' = 63503 + FUNC_FISH_FISHBOWL: 'CommonGameTag' = 869 + FUNC_FISH_INVASIVE: 'CommonGameTag' = 2195 + FUNC_FITNESS: 'CommonGameTag' = 474 + FUNC_FLAG: 'CommonGameTag' = 1403 + FUNC_FLAGSTONE: 'CommonGameTag' = 1094 + FUNC_FLOWER: 'CommonGameTag' = 1314 + FUNC_FLOWERS_10: 'CommonGameTag' = 59490 + FUNC_FLOWERS_3: 'CommonGameTag' = 59483 + FUNC_FLOWERS_4: 'CommonGameTag' = 59484 + FUNC_FLOWERS_5: 'CommonGameTag' = 59485 + FUNC_FLOWERS_6: 'CommonGameTag' = 59486 + FUNC_FLOWERS_7: 'CommonGameTag' = 59487 + FUNC_FLOWERS_8: 'CommonGameTag' = 59488 + FUNC_FLOWERS_9: 'CommonGameTag' = 59489 + FUNC_FLOWERS_BOP_BEG: 'CommonGameTag' = 2106 + FUNC_FLOWERS_CHRY_SNAP: 'CommonGameTag' = 2104 + FUNC_FLOWERS_DAI_BLU: 'CommonGameTag' = 2102 + FUNC_FLOWERS_LILY_DEATH: 'CommonGameTag' = 2107 + FUNC_FLOWERS_ROS_DAH: 'CommonGameTag' = 2103 + FUNC_FLOWERS_SCENT: 'CommonGameTag' = 2090 + FUNC_FLOWERS_SCENT_RARE: 'CommonGameTag' = 2091 + FUNC_FLOWERS_SNO_CROC: 'CommonGameTag' = 2101 + FUNC_FLOWERS_TUL_CHRI: 'CommonGameTag' = 2105 + FUNC_FLOWER_ARRANGEMENT: 'CommonGameTag' = 59457 + FUNC_FLOWER_GIFTING: 'CommonGameTag' = 2668 + FUNC_FOLDERS: 'CommonGameTag' = 1412 + FUNC_FOLDING: 'CommonGameTag' = 1304 + FUNC_FOOD: 'CommonGameTag' = 520 + FUNC_FOOD_PET_EDIBLE: 'CommonGameTag' = 2030 + FUNC_FOOD_PLATTER: 'CommonGameTag' = 26643 + FUNC_FOOSBALL_TABLE: 'CommonGameTag' = 24591 + FUNC_FORAGED_PLANT: 'CommonGameTag' = 2698 + FUNC_FORTUNE: 'CommonGameTag' = 1180 + FUNC_FORTUNE_TELLING: 'CommonGameTag' = 8200 + FUNC_FOSSIL_BRUSHED: 'CommonGameTag' = 2044 + FUNC_FOSSIL_ROCK: 'CommonGameTag' = 2037 + FUNC_FOUNTAIN: 'CommonGameTag' = 8216 + FUNC_FOX: 'CommonGameTag' = 2591 + FUNC_FOX_DEN: 'CommonGameTag' = 2629 + FUNC_FREELANCER_CANVAS_CHARACTER_DESIGN: 'CommonGameTag' = 2177 + FUNC_FREELANCER_CANVAS_ENVIRONMENT_DESIGN: 'CommonGameTag' = 2178 + FUNC_FREELANCER_CANVAS_ICON: 'CommonGameTag' = 2183 + FUNC_FREELANCER_CANVAS_ILLUSTRATIVE: 'CommonGameTag' = 2184 + FUNC_FREELANCER_CANVAS_LOGO: 'CommonGameTag' = 2182 + FUNC_FREELANCER_CANVAS_PORTRAIT: 'CommonGameTag' = 2179 + FUNC_FREELANCER_CANVAS_RECREATED_ART: 'CommonGameTag' = 2181 + FUNC_FREELANCER_CANVAS_REFERENCE: 'CommonGameTag' = 2185 + FUNC_FREELANCER_CANVAS_SPLASH_ART: 'CommonGameTag' = 2180 + FUNC_FREELANCE_MAKER_CARVED_CANDLES: 'CommonGameTag' = 67599 + FUNC_FREELANCE_MAKER_COUCH: 'CommonGameTag' = 67596 + FUNC_FREELANCE_MAKER_CRAFTED_CANDLES: 'CommonGameTag' = 67601 + FUNC_FREELANCE_MAKER_FINE_WALL_DECOR: 'CommonGameTag' = 67602 + FUNC_FREELANCE_MAKER_FLOOR_LIGHTS: 'CommonGameTag' = 67598 + FUNC_FREELANCE_MAKER_JAR_CANDLES: 'CommonGameTag' = 67595 + FUNC_FREELANCE_MAKER_KIDS_BED: 'CommonGameTag' = 67600 + FUNC_FREELANCE_MAKER_KOMBUCHA: 'CommonGameTag' = 67597 + FUNC_FREELANCE_MAKER_RUGS: 'CommonGameTag' = 67593 + FUNC_FREELANCE_MAKER_TOFIZZ: 'CommonGameTag' = 67594 + FUNC_FRIDGE: 'CommonGameTag' = 1002 + FUNC_FRIDGE_MINI: 'CommonGameTag' = 2233 + FUNC_FRIDGE_SKIN_CARE: 'CommonGameTag' = 18471 + FUNC_FRIENDSHIP_BRACELET: 'CommonGameTag' = 116749 + FUNC_FROG_PUMP: 'CommonGameTag' = 2798 + FUNC_FRONT_DESK: 'CommonGameTag' = 12331 + FUNC_FROSTY: 'CommonGameTag' = 1337 + FUNC_FRUIT_CAKE: 'CommonGameTag' = 1445 + FUNC_FRUIT_PUNCH_FOUNTAIN: 'CommonGameTag' = 8214 + FUNC_FRYING_PAN: 'CommonGameTag' = 2449 + FUNC_FUN: 'CommonGameTag' = 999 + FUNC_FUTURE: 'CommonGameTag' = 503 + FUNC_GAME: 'CommonGameTag' = 481 + FUNC_GAMING: 'CommonGameTag' = 1075 + FUNC_GARBAGE: 'CommonGameTag' = 924 + FUNC_GARDEN: 'CommonGameTag' = 1150 + FUNC_GARDENING: 'CommonGameTag' = 1107 + FUNC_GARDENING_FERTILIZER_BAD: 'CommonGameTag' = 862 + FUNC_GARDENING_FERTILIZER_HIGH: 'CommonGameTag' = 859 + FUNC_GARDENING_FERTILIZER_LOW: 'CommonGameTag' = 861 + FUNC_GARDENING_FERTILIZER_MAX: 'CommonGameTag' = 870 + FUNC_GARDENING_FERTILIZER_MED: 'CommonGameTag' = 860 + FUNC_GARDENING_FLOWERS: 'CommonGameTag' = 59463 + FUNC_GARDENING_FORBIDDEN_FRUIT: 'CommonGameTag' = 1708 + FUNC_GARDENING_GRAFTABLE: 'CommonGameTag' = 2092 + FUNC_GARDENING_GROWFRUIT: 'CommonGameTag' = 1502 + FUNC_GARDENING_MONEY_TREE: 'CommonGameTag' = 59482 + FUNC_GARDENING_PATCH: 'CommonGameTag' = 112641 + FUNC_GARDENING_SEEDS: 'CommonGameTag' = 1029 + FUNC_GARDENING_SEED_COMMON: 'CommonGameTag' = 831 + FUNC_GARDENING_SEED_RARE: 'CommonGameTag' = 833 + FUNC_GARDENING_SEED_UNCOMMON: 'CommonGameTag' = 832 + FUNC_GARDENING_SKILL_PLANT: 'CommonGameTag' = 1721 + FUNC_GARDENING_SPRINKLER: 'CommonGameTag' = 59437 + FUNC_GARDENING_TOXIC: 'CommonGameTag' = 10254 + FUNC_GARDENING_WILD: 'CommonGameTag' = 1272 + FUNC_GARDEN_FLOWER: 'CommonGameTag' = 2781 + FUNC_GARDEN_GARLIC: 'CommonGameTag' = 40971 + FUNC_GARDEN_GHOST_DESTROY: 'CommonGameTag' = 2176 + FUNC_GARDEN_PLASMA_TREE: 'CommonGameTag' = 40973 + FUNC_GARLAND: 'CommonGameTag' = 1334 + FUNC_GARLIC: 'CommonGameTag' = 40962 + FUNC_GATE: 'CommonGameTag' = 1390 + FUNC_GATOR: 'CommonGameTag' = 112694 + FUNC_GETS_DIRTY: 'CommonGameTag' = 2516 + FUNC_GHOST: 'CommonGameTag' = 1190 + FUNC_GIANT_CROPS_FERTILIZER: 'CommonGameTag' = 112642 + FUNC_GIANT_CROPS_FRUIT: 'CommonGameTag' = 112645 + FUNC_GIANT_CROPS_FRUIT_GIANT_MUSHROOM: 'CommonGameTag' = 112680 + FUNC_GIANT_CROPS_PLANT: 'CommonGameTag' = 112644 + FUNC_GIANT_CROPS_SEED_PACKET: 'CommonGameTag' = 112643 + FUNC_GIANT_CROP_LARGE: 'CommonGameTag' = 2612 + FUNC_GIANT_CROP_MEDIUM: 'CommonGameTag' = 2611 + FUNC_GIANT_CROP_SMALL: 'CommonGameTag' = 2610 + FUNC_GIVE_GIFT_NOT_GIFTABLE: 'CommonGameTag' = 2160 + FUNC_GIVE_GIFT_REWARD: 'CommonGameTag' = 2088 + FUNC_GLASS: 'CommonGameTag' = 1432 + FUNC_GNOME: 'CommonGameTag' = 1365 + FUNC_GNOME_KICK_REWARD: 'CommonGameTag' = 2087 + FUNC_GONDOLA_BOTTOM: 'CommonGameTag' = 69654 + FUNC_GONDOLA_TOP: 'CommonGameTag' = 69653 + FUNC_GOURMET_COOKING: 'CommonGameTag' = 1104 + FUNC_GO_DANCING_OBJECT_VISIBILITY: 'CommonGameTag' = 24587 + FUNC_GO_FOR_WALK_DOG_INTERACTIONS: 'CommonGameTag' = 57395 + FUNC_GRAFFITI: 'CommonGameTag' = 55403 + FUNC_GRAND_MEAL: 'CommonGameTag' = 2095 + FUNC_GRASS: 'CommonGameTag' = 1093 + FUNC_GRAVE: 'CommonGameTag' = 1198 + FUNC_GRAVESTONE: 'CommonGameTag' = 1203 + FUNC_GREEN_SCREEN: 'CommonGameTag' = 61465 + FUNC_GRILL_RECIPE: 'CommonGameTag' = 1247 + FUNC_GUITAR: 'CommonGameTag' = 565 + FUNC_GYM: 'CommonGameTag' = 562 + FUNC_GYPSY: 'CommonGameTag' = 1183 + FUNC_HABITAT: 'CommonGameTag' = 77826 + FUNC_HAIR_MAKEUP_CHAIR: 'CommonGameTag' = 61442 + FUNC_HAIR_PILE: 'CommonGameTag' = 57411 + FUNC_HALLOWEEN: 'CommonGameTag' = 1179 + FUNC_HAMPER: 'CommonGameTag' = 75783 + FUNC_HAMSTER: 'CommonGameTag' = 77828 + FUNC_HAND: 'CommonGameTag' = 1209 + FUNC_HANDINESS: 'CommonGameTag' = 1100 + FUNC_HANUKKAH: 'CommonGameTag' = 1329 + FUNC_HARDWOOD: 'CommonGameTag' = 1095 + FUNC_HARVESTABLE: 'CommonGameTag' = 2126 + FUNC_HARVESTABLE_COW: 'CommonGameTag' = 2590 + FUNC_HARVESTABLE_FRUIT: 'CommonGameTag' = 2592 + FUNC_HARVESTABLE_LARGE: 'CommonGameTag' = 2587 + FUNC_HARVESTABLE_RARE: 'CommonGameTag' = 2072 + FUNC_HARVESTABLE_SUPER_RARE: 'CommonGameTag' = 2074 + FUNC_HARVESTABLE_UNCOMMON: 'CommonGameTag' = 2073 + FUNC_HARVESTABLE_WALL: 'CommonGameTag' = 2588 + FUNC_HAUNTED: 'CommonGameTag' = 1223 + FUNC_HAUNTED_PAINTING: 'CommonGameTag' = 86028 + FUNC_HEAD: 'CommonGameTag' = 1213 + FUNC_HEALTH: 'CommonGameTag' = 475 + FUNC_HEART: 'CommonGameTag' = 1369 + FUNC_HEAT_LAMP: 'CommonGameTag' = 14338 + FUNC_HEAT_LAMP_BG: 'CommonGameTag' = 1520 + FUNC_HEDGEHOG: 'CommonGameTag' = 77829 + FUNC_HEN: 'CommonGameTag' = 112684 + FUNC_HERBALISM: 'CommonGameTag' = 10249 + FUNC_HERBALISM_INGREDIENT: 'CommonGameTag' = 10251 + FUNC_HERBALISM_INGREDIENT_CHAMOMILE: 'CommonGameTag' = 10271 + FUNC_HERBALISM_INGREDIENT_ELDERBERRY: 'CommonGameTag' = 10272 + FUNC_HERBALISM_INGREDIENT_FIRELEAF: 'CommonGameTag' = 10273 + FUNC_HERBALISM_INGREDIENT_HUCKLEBERRY: 'CommonGameTag' = 10274 + FUNC_HERBALISM_INGREDIENT_MOREL_MUSHROOM: 'CommonGameTag' = 10275 + FUNC_HERBALISM_PLANT: 'CommonGameTag' = 10250 + FUNC_HERBALISM_POTION: 'CommonGameTag' = 10255 + FUNC_HIDEABLE: 'CommonGameTag' = 1914 + FUNC_HIGH_CHAIR: 'CommonGameTag' = 1654 + FUNC_HIGH_CHAIR_DRINK: 'CommonGameTag' = 1695 + FUNC_HIGH_CHAIR_FOOD: 'CommonGameTag' = 1694 + FUNC_HIGH_SCHOOL_ACTIVE_AMPHITHEATRE: 'CommonGameTag' = 114709 + FUNC_HIGH_SCHOOL_ACTIVE_CAFETERIA_STATION: 'CommonGameTag' = 114693 + FUNC_HIGH_SCHOOL_ACTIVE_CAREER_DAY_TABLE: 'CommonGameTag' = 114731 + FUNC_HIGH_SCHOOL_ACTIVE_EXAM_BOOK: 'CommonGameTag' = 114690 + FUNC_HIGH_SCHOOL_ACTIVE_FIELD: 'CommonGameTag' = 114708 + FUNC_HIGH_SCHOOL_ACTIVE_PRINCIPAL_DESK: 'CommonGameTag' = 114717 + FUNC_HIGH_SCHOOL_ACTIVE_SPEAKER: 'CommonGameTag' = 114700 + FUNC_HIGH_SCHOOL_ACTIVE_WHITEBOARD: 'CommonGameTag' = 114691 + FUNC_HIGH_SCHOOL_ACTIVE_WORK_BOOK: 'CommonGameTag' = 114689 + FUNC_HIGH_SCHOOL_PROM_BULLETIN_BOARD: 'CommonGameTag' = 114716 + FUNC_HIGH_SCHOOL_PROM_DRINK_FOUNTAIN: 'CommonGameTag' = 114719 + FUNC_HIGH_SCHOOL_PROM_PODIUM: 'CommonGameTag' = 2822 + FUNC_HOLIDAY: 'CommonGameTag' = 1326 + FUNC_HOLIDAY_CANDLE: 'CommonGameTag' = 2128 + FUNC_HOLIDAY_CANDLE_2: 'CommonGameTag' = 59478 + FUNC_HOLIDAY_DECO_OBJECTS: 'CommonGameTag' = 2098 + FUNC_HOLIDAY_FESTIVE_LIGHTING: 'CommonGameTag' = 2129 + FUNC_HOLIDAY_GNOME_GROUP01: 'CommonGameTag' = 2121 + FUNC_HOLIDAY_GNOME_GROUP02: 'CommonGameTag' = 2122 + FUNC_HOLIDAY_GNOME_GROUP03: 'CommonGameTag' = 2123 + FUNC_HOLIDAY_GNOME_GROUP04: 'CommonGameTag' = 2124 + FUNC_HOLIDAY_TRADITION_BAKING_RECIPE: 'CommonGameTag' = 2116 + FUNC_HOLIDAY_TRADITION_BONFIRE: 'CommonGameTag' = 2109 + FUNC_HOLIDAY_TRADITION_DECO_BE_ROMANTIC: 'CommonGameTag' = 2108 + FUNC_HOLIDAY_TRADITION_HAVE_DECORATIONS: 'CommonGameTag' = 2110 + FUNC_HOLIDAY_TRADITION_OPEN_PRESENTS: 'CommonGameTag' = 2111 + FUNC_HOLIDAY_TRADITION_PARTY: 'CommonGameTag' = 2112 + FUNC_HOLIDAY_TREE: 'CommonGameTag' = 59409 + FUNC_HOLIDAY_TREE_GARLAND: 'CommonGameTag' = 59412 + FUNC_HOLIDAY_TREE_ORNAMENTS: 'CommonGameTag' = 59411 + FUNC_HOLIDAY_TREE_SKIRT: 'CommonGameTag' = 59413 + FUNC_HOLIDAY_TREE_TOPPER: 'CommonGameTag' = 59414 + FUNC_HOLOTABLE: 'CommonGameTag' = 51223 + FUNC_HOLOTABLE_FIRST_ORDER_PURCHASE: 'CommonGameTag' = 51207 + FUNC_HOLOTABLE_RESISTANCE_PURCHASE: 'CommonGameTag' = 51208 + FUNC_HONEY: 'CommonGameTag' = 59450 + FUNC_HOOD: 'CommonGameTag' = 1168 + FUNC_HOOP: 'CommonGameTag' = 553 + FUNC_HORSE: 'CommonGameTag' = 118906 + FUNC_HORSE_BARRELS: 'CommonGameTag' = 118883 + FUNC_HORSE_BED: 'CommonGameTag' = 118787 + FUNC_HORSE_JUMPS: 'CommonGameTag' = 118882 + FUNC_HORSE_MANURE: 'CommonGameTag' = 2978 + FUNC_HORSE_TOY: 'CommonGameTag' = 118797 + FUNC_HOSPITAL: 'CommonGameTag' = 1377 + FUNC_HOST_STATION: 'CommonGameTag' = 26628 + FUNC_HOT_SAUCE: 'CommonGameTag' = 1300 + FUNC_HOT_SPRINGS: 'CommonGameTag' = 69675 + FUNC_HOT_TUB: 'CommonGameTag' = 1444 + FUNC_HOUSE: 'CommonGameTag' = 1224 + FUNC_HOUSEHOLD_INVENTORY_OBJECT_PROXY: 'CommonGameTag' = 2388 + FUNC_HUNGER: 'CommonGameTag' = 996 + FUNC_HUTCH: 'CommonGameTag' = 1030 + FUNC_HYDRAULIC: 'CommonGameTag' = 1429 + FUNC_HYGIENE: 'CommonGameTag' = 998 + FUNC_ICE_CHEST: 'CommonGameTag' = 1249 + FUNC_ICE_CREAM: 'CommonGameTag' = 20486 + FUNC_ICE_CREAM_BOWL: 'CommonGameTag' = 20483 + FUNC_ICE_CREAM_CARTON: 'CommonGameTag' = 20482 + FUNC_ICE_CREAM_CONE: 'CommonGameTag' = 20484 + FUNC_ICE_CREAM_MACHINE: 'CommonGameTag' = 20481 + FUNC_ICE_CREAM_MILK_SHAKE: 'CommonGameTag' = 20485 + FUNC_IMPORTANT_ITEMS: 'CommonGameTag' = 2283 + FUNC_INCENSE: 'CommonGameTag' = 18442 + FUNC_INFANT_CRIB: 'CommonGameTag' = 2913 + FUNC_INFANT_MESMERIZE: 'CommonGameTag' = 2946 + FUNC_INFANT_PLAY_MAT: 'CommonGameTag' = 2914 + FUNC_INFECTED_PLANT: 'CommonGameTag' = 47129 + FUNC_INFLATABLE: 'CommonGameTag' = 1286 + FUNC_INFO_BOARD: 'CommonGameTag' = 69714 + FUNC_INGREDIENT: 'CommonGameTag' = 523 + FUNC_INGREDIENT_APPLE: 'CommonGameTag' = 2654 + FUNC_INGREDIENT_ARTISAN_HERB_BREAD: 'CommonGameTag' = 12302 + FUNC_INGREDIENT_AUBERGINE: 'CommonGameTag' = 112648 + FUNC_INGREDIENT_AUBERGINE_BG: 'CommonGameTag' = 2616 + FUNC_INGREDIENT_BEETLE: 'CommonGameTag' = 10253 + FUNC_INGREDIENT_BERRY: 'CommonGameTag' = 2584 + FUNC_INGREDIENT_BLACKBERRY: 'CommonGameTag' = 2651 + FUNC_INGREDIENT_BLUEBERRY: 'CommonGameTag' = 2620 + FUNC_INGREDIENT_BREAD: 'CommonGameTag' = 2595 + FUNC_INGREDIENT_CHEESE: 'CommonGameTag' = 2593 + FUNC_INGREDIENT_CHOCOLATE: 'CommonGameTag' = 2607 + FUNC_INGREDIENT_COWBERRY_JAM_OR_HONEY: 'CommonGameTag' = 2586 + FUNC_INGREDIENT_COWPLANT_ESSENCE: 'CommonGameTag' = 12373 + FUNC_INGREDIENT_CRAWDAD: 'CommonGameTag' = 10241 + FUNC_INGREDIENT_CROSS_STITCH_WOOL: 'CommonGameTag' = 112650 + FUNC_INGREDIENT_CRYSTAL: 'CommonGameTag' = 1345 + FUNC_INGREDIENT_CRYSTAL_ALIEN: 'CommonGameTag' = 12386 + FUNC_INGREDIENT_CRYSTAL_COMMON: 'CommonGameTag' = 1349 + FUNC_INGREDIENT_CRYSTAL_RARE: 'CommonGameTag' = 1351 + FUNC_INGREDIENT_CRYSTAL_UNCOMMON: 'CommonGameTag' = 1350 + FUNC_INGREDIENT_EXOTIC_FRUIT_PIE: 'CommonGameTag' = 12305 + FUNC_INGREDIENT_EXOTIC_FRUIT_TART: 'CommonGameTag' = 12301 + FUNC_INGREDIENT_FISH: 'CommonGameTag' = 817 + FUNC_INGREDIENT_FISH_PIE: 'CommonGameTag' = 12303 + FUNC_INGREDIENT_FISH_PUFFERFISH: 'CommonGameTag' = 55335 + FUNC_INGREDIENT_FIZZY_JUICE: 'CommonGameTag' = 67631 + FUNC_INGREDIENT_FIZZY_JUICE_EP09: 'CommonGameTag' = 2429 + FUNC_INGREDIENT_FLOUR_OR_SUGAR: 'CommonGameTag' = 2618 + FUNC_INGREDIENT_FRUIT: 'CommonGameTag' = 795 + FUNC_INGREDIENT_FRUITCAKE_SET1: 'CommonGameTag' = 12307 + FUNC_INGREDIENT_FRUITCAKE_SET2: 'CommonGameTag' = 12308 + FUNC_INGREDIENT_FRUIT_MUFFINS: 'CommonGameTag' = 12298 + FUNC_INGREDIENT_FRUIT_OR_VEGGIE: 'CommonGameTag' = 2585 + FUNC_INGREDIENT_FRUIT_SCONES: 'CommonGameTag' = 12299 + FUNC_INGREDIENT_GRIMBUCHA_EP09: 'CommonGameTag' = 2432 + FUNC_INGREDIENT_HERB: 'CommonGameTag' = 816 + FUNC_INGREDIENT_INFECTED_SPORE: 'CommonGameTag' = 47142 + FUNC_INGREDIENT_INSECT: 'CommonGameTag' = 1242 + FUNC_INGREDIENT_JELLY_FILLED_DOUGHNUTS: 'CommonGameTag' = 12306 + FUNC_INGREDIENT_JELLY_OR_JAM: 'CommonGameTag' = 2619 + FUNC_INGREDIENT_KOMBUCHA: 'CommonGameTag' = 67632 + FUNC_INGREDIENT_KOMBUCHA_EP09: 'CommonGameTag' = 2430 + FUNC_INGREDIENT_LETTUCE: 'CommonGameTag' = 112646 + FUNC_INGREDIENT_LETTUCE_BG: 'CommonGameTag' = 2615 + FUNC_INGREDIENT_LOCUST: 'CommonGameTag' = 10242 + FUNC_INGREDIENT_MEAT: 'CommonGameTag' = 2594 + FUNC_INGREDIENT_MEAT_RED: 'CommonGameTag' = 2785 + FUNC_INGREDIENT_MEAT_SUBSTITUTE: 'CommonGameTag' = 2630 + FUNC_INGREDIENT_MEAT_SUBSTITUTE_SOURCE: 'CommonGameTag' = 2631 + FUNC_INGREDIENT_METAL: 'CommonGameTag' = 1344 + FUNC_INGREDIENT_METAL_ALIEN: 'CommonGameTag' = 12387 + FUNC_INGREDIENT_METAL_COMMON: 'CommonGameTag' = 1346 + FUNC_INGREDIENT_METAL_RARE: 'CommonGameTag' = 1348 + FUNC_INGREDIENT_METAL_UNCOMMON: 'CommonGameTag' = 1347 + FUNC_INGREDIENT_MILK_OR_EGGS: 'CommonGameTag' = 2648 + FUNC_INGREDIENT_MUSHROOM: 'CommonGameTag' = 1243 + FUNC_INGREDIENT_PLANT_ALIEN: 'CommonGameTag' = 12388 + FUNC_INGREDIENT_PUMPKIN: 'CommonGameTag' = 112647 + FUNC_INGREDIENT_PUMPKIN_BG: 'CommonGameTag' = 2617 + FUNC_INGREDIENT_RAINBOW_GELATIN_CAKE_SET1: 'CommonGameTag' = 12309 + FUNC_INGREDIENT_RAINBOW_GELATIN_CAKE_SET2: 'CommonGameTag' = 12310 + FUNC_INGREDIENT_RASPBERRY: 'CommonGameTag' = 2652 + FUNC_INGREDIENT_ROSE_QUARTZ: 'CommonGameTag' = 12364 + FUNC_INGREDIENT_SELTZER: 'CommonGameTag' = 67633 + FUNC_INGREDIENT_STANDARD_FRUIT_PIE: 'CommonGameTag' = 12304 + FUNC_INGREDIENT_STANDARD_FRUIT_TART: 'CommonGameTag' = 12300 + FUNC_INGREDIENT_STRAWBERRY: 'CommonGameTag' = 2653 + FUNC_INGREDIENT_SUSPICIOUS: 'CommonGameTag' = 67634 + FUNC_INGREDIENT_SUSPICIOUS_EP09: 'CommonGameTag' = 2431 + FUNC_INGREDIENT_TOMATO: 'CommonGameTag' = 2596 + FUNC_INGREDIENT_VEGGIE: 'CommonGameTag' = 815 + FUNC_INGREDIENT_WATERMELON: 'CommonGameTag' = 112663 + FUNC_INGREDIENT_WAX_BLOCK: 'CommonGameTag' = 67636 + FUNC_INSANE_TALK_TO_OBJECTS: 'CommonGameTag' = 1929 + FUNC_INSECT: 'CommonGameTag' = 2575 + FUNC_INSECT_FARM: 'CommonGameTag' = 67592 + FUNC_INSECT_FARMED: 'CommonGameTag' = 67649 + FUNC_INSECT_WILD: 'CommonGameTag' = 10298 + FUNC_INSTRUMENT: 'CommonGameTag' = 570 + FUNC_INSTRUMENTS: 'CommonGameTag' = 1413 + FUNC_INTERACTIVE_BUSH: 'CommonGameTag' = 24588 + FUNC_INTERACTIVE_BUSH_BG: 'CommonGameTag' = 2070 + FUNC_INTERACTIVE_CLOSET: 'CommonGameTag' = 24589 + FUNC_INTERIOR_DECORATOR_GIG_OBJECT_WEIRD: 'CommonGameTag' = 53253 + FUNC_INTERIOR_DECORATOR_NEW: 'CommonGameTag' = 53251 + FUNC_INVENTION_CONSTRUCTOR: 'CommonGameTag' = 12394 + FUNC_INVESTIGATION_DOSSIER: 'CommonGameTag' = 47165 + FUNC_INVESTIGATION_EVIDENCE: 'CommonGameTag' = 47106 + FUNC_INVESTIGATION_HAZMAT_SUIT: 'CommonGameTag' = 47147 + FUNC_INVESTIGATION_JUNK_PILE: 'CommonGameTag' = 47126 + FUNC_INVESTIGATION_KEYCARD: 'CommonGameTag' = 47164 + FUNC_INVESTIGATION_SEALED_DOOR_FLOOR: 'CommonGameTag' = 47136 + FUNC_INVESTIGATION_SEALED_DOOR_HALLWAY: 'CommonGameTag' = 47138 + FUNC_INVESTIGATION_SEALED_DOOR_MOTHER_PLANT: 'CommonGameTag' = 47137 + FUNC_INVESTIGATION_SPORE_FILTER: 'CommonGameTag' = 47146 + FUNC_INVESTIGATION_SPORE_SAMPLE: 'CommonGameTag' = 47135 + FUNC_INVISIBLE: 'CommonGameTag' = 1219 + FUNC_ISLAND_CANOE: 'CommonGameTag' = 63501 + FUNC_ISLAND_CANOE_BEACH_VENUE: 'CommonGameTag' = 2198 + FUNC_ISLAND_SPIRIT: 'CommonGameTag' = 63497 + FUNC_ISLAND_SPIRIT_INACTIVE: 'CommonGameTag' = 63498 + FUNC_ITEM_BATUU: 'CommonGameTag' = 2464 + FUNC_JACK_O_LANTERN: 'CommonGameTag' = 1206 + FUNC_JAIL: 'CommonGameTag' = 1379 + FUNC_JIG: 'CommonGameTag' = 1342 + FUNC_JOURNAL: 'CommonGameTag' = 43009 + FUNC_JOURNALIST: 'CommonGameTag' = 1118 + FUNC_JOURNAL_BASE_GAME: 'CommonGameTag' = 1724 + FUNC_JUICE_FIZZER: 'CommonGameTag' = 67629 + FUNC_JUICE_FIZZING_PRODUCT: 'CommonGameTag' = 67635 + FUNC_JUICE_KEG: 'CommonGameTag' = 65539 + FUNC_JUICE_KEG_CONFIDENT: 'CommonGameTag' = 65543 + FUNC_JUICE_KEG_FLIRTY: 'CommonGameTag' = 65542 + FUNC_JUICE_KEG_HAPPY: 'CommonGameTag' = 65544 + FUNC_JUICE_KEG_PLAYFUL: 'CommonGameTag' = 65545 + FUNC_JUMP_STAND: 'CommonGameTag' = 24604 + FUNC_JUNGLE: 'CommonGameTag' = 563 + FUNC_JUNGLE_GYM: 'CommonGameTag' = 1034 + FUNC_KARAOKE_MACHINE: 'CommonGameTag' = 1581 + FUNC_KEROSENE: 'CommonGameTag' = 1282 + FUNC_KETCHUP: 'CommonGameTag' = 1298 + FUNC_KETTLE: 'CommonGameTag' = 1221 + FUNC_KID: 'CommonGameTag' = 1091 + FUNC_KIDDIE_POOL: 'CommonGameTag' = 59462 + FUNC_KIDS_TENT: 'CommonGameTag' = 2554 + FUNC_KNIFE: 'CommonGameTag' = 1140 + FUNC_KNITTING: 'CommonGameTag' = 83992 + FUNC_KNITTING_BABY_ONESIE: 'CommonGameTag' = 83983 + FUNC_KNITTING_BEANIE: 'CommonGameTag' = 83973 + FUNC_KNITTING_CHILD_SWEATER: 'CommonGameTag' = 83988 + FUNC_KNITTING_CLOTHING: 'CommonGameTag' = 83993 + FUNC_KNITTING_DECORATION: 'CommonGameTag' = 83979 + FUNC_KNITTING_FURNISHING: 'CommonGameTag' = 83975 + FUNC_KNITTING_GIFTED: 'CommonGameTag' = 83990 + FUNC_KNITTING_GRIM: 'CommonGameTag' = 83987 + FUNC_KNITTING_ONESIE: 'CommonGameTag' = 83980 + FUNC_KNITTING_POUFFE: 'CommonGameTag' = 83978 + FUNC_KNITTING_RUG: 'CommonGameTag' = 83976 + FUNC_KNITTING_SOCKS: 'CommonGameTag' = 83974 + FUNC_KNITTING_SWEATER: 'CommonGameTag' = 83977 + FUNC_KNITTING_SWEATER_SCARF: 'CommonGameTag' = 83981 + FUNC_KNITTING_TOY: 'CommonGameTag' = 83982 + FUNC_KNITTING_WIP: 'CommonGameTag' = 2463 + FUNC_KNIVES: 'CommonGameTag' = 1141 + FUNC_KNOWLEDGE: 'CommonGameTag' = 24595 + FUNC_KWANZAA: 'CommonGameTag' = 1330 + FUNC_LAB: 'CommonGameTag' = 1400 + FUNC_LAB_DOOR: 'CommonGameTag' = 47105 + FUNC_LADDER: 'CommonGameTag' = 1230 + FUNC_LAMP: 'CommonGameTag' = 1283 + FUNC_LAMP_POST: 'CommonGameTag' = 1293 + FUNC_LANDFILL_DUMPABLE_APPLIANCE: 'CommonGameTag' = 67607 + FUNC_LANTERN: 'CommonGameTag' = 1205 + FUNC_LAPTOP: 'CommonGameTag' = 515 + FUNC_LASER: 'CommonGameTag' = 1396 + FUNC_LASER_LIGHT: 'CommonGameTag' = 24577 + FUNC_LAUNDRY_CLOTHES_LINE: 'CommonGameTag' = 75781 + FUNC_LAUNDRY_DRYER: 'CommonGameTag' = 75779 + FUNC_LAUNDRY_HAMPER: 'CommonGameTag' = 2033 + FUNC_LAUNDRY_HERO_OBJECT: 'CommonGameTag' = 2032 + FUNC_LAUNDRY_PILE: 'CommonGameTag' = 75777 + FUNC_LAUNDRY_SEARCH_TERM: 'CommonGameTag' = 75782 + FUNC_LAUNDRY_WASHING_MACHINE: 'CommonGameTag' = 75778 + FUNC_LAUNDRY_WASH_TUB: 'CommonGameTag' = 75780 + FUNC_LAVA_ROCK: 'CommonGameTag' = 63499 + FUNC_LEAF_PILE: 'CommonGameTag' = 59432 + FUNC_LECTERN: 'CommonGameTag' = 55405 + FUNC_LIFESTYLES_ELECTRONICS: 'CommonGameTag' = 2493 + FUNC_LIFESTYLES_TECH_BOOK: 'CommonGameTag' = 2505 + FUNC_LIFESTYLES_TECH_SCHOOL_PROJECT: 'CommonGameTag' = 2506 + FUNC_LIFE_MILESTONE_MEMORABILIA: 'CommonGameTag' = 2917 + FUNC_LIGHTING_NOT_STAGE_LIGHTS: 'CommonGameTag' = 61467 + FUNC_LIGHTNING_CAN_STRIKE: 'CommonGameTag' = 2076 + FUNC_LIGHTNING_CLEANUP: 'CommonGameTag' = 59491 + FUNC_LIGHTNING_OBJECT: 'CommonGameTag' = 59440 + FUNC_LIGHTS: 'CommonGameTag' = 1338 + FUNC_LIGHTSABER_CRYSTAL: 'CommonGameTag' = 51203 + FUNC_LIGHTSABER_HILT: 'CommonGameTag' = 51204 + FUNC_LIGHT_CANDLE_WITH_AUTO_LIGHTS: 'CommonGameTag' = 1446 + FUNC_LIGHT_NON_ELECTRIC: 'CommonGameTag' = 1374 + FUNC_LIGHT_NO_AUTO_LIGHTS: 'CommonGameTag' = 1325 + FUNC_LINOLEUM: 'CommonGameTag' = 1097 + FUNC_LISTENING_DEVICE_BUG: 'CommonGameTag' = 47145 + FUNC_LITTER_BOX: 'CommonGameTag' = 57355 + FUNC_LITTER_BOX_HIGH_TECH: 'CommonGameTag' = 57360 + FUNC_LIVESTOCK_FEED: 'CommonGameTag' = 2726 + FUNC_LIVESTOCK_FEED_FISHY: 'CommonGameTag' = 2571 + FUNC_LIVESTOCK_FEED_HEALTHY: 'CommonGameTag' = 2572 + FUNC_LIVESTOCK_FEED_PILE: 'CommonGameTag' = 2649 + FUNC_LIVESTOCK_FEED_PILE_BASIC: 'CommonGameTag' = 2699 + FUNC_LIVE_DRAG_ALLOWED_WITH_CHILDREN: 'CommonGameTag' = 1722 + FUNC_LIVING_CHAIR: 'CommonGameTag' = 1005 + FUNC_LLAMA: 'CommonGameTag' = 112682 + FUNC_LOCATOR_BEACH_PORTAL: 'CommonGameTag' = 2187 + FUNC_LOCATOR_TERRAIN_WALKSTYLE_PORTAL: 'CommonGameTag' = 2482 + FUNC_LOG: 'CommonGameTag' = 1307 + FUNC_LOGIC: 'CommonGameTag' = 1098 + FUNC_LOTUS: 'CommonGameTag' = 1288 + FUNC_LOUD_TOYS: 'CommonGameTag' = 2967 + FUNC_LOUNGE_EVENT_AWARD_TROPHY: 'CommonGameTag' = 61632 + FUNC_MACHINE: 'CommonGameTag' = 578 + FUNC_MAGAZINE: 'CommonGameTag' = 1405 + FUNC_MAGIC_BEAN: 'CommonGameTag' = 1701 + FUNC_MAGIC_BEAN_ANGRY_RED: 'CommonGameTag' = 1702 + FUNC_MAGIC_BEAN_CONFIDENT_LIGHT_BLUE: 'CommonGameTag' = 1707 + FUNC_MAGIC_BEAN_FLIRTY_PINK: 'CommonGameTag' = 1705 + FUNC_MAGIC_BEAN_PLAYFUL_GREEN: 'CommonGameTag' = 1703 + FUNC_MAGIC_BEAN_SAD_NAVY_BLUE: 'CommonGameTag' = 1706 + FUNC_MAGIC_BEAN_UNCOMFORTABLE_ORANGE: 'CommonGameTag' = 1704 + FUNC_MAGIC_BROOM: 'CommonGameTag' = 49169 + FUNC_MAGIC_PORTAL_DUELING_TO_HQ: 'CommonGameTag' = 49159 + FUNC_MAGIC_PORTAL_HQ_TO_DUELING: 'CommonGameTag' = 49160 + FUNC_MAGIC_PORTAL_HQ_TO_MARKET: 'CommonGameTag' = 49161 + FUNC_MAGIC_PORTAL_HQ_TO_VISTA: 'CommonGameTag' = 49162 + FUNC_MAGIC_PORTAL_MARKET_TO_HQ: 'CommonGameTag' = 49163 + FUNC_MAGIC_PORTAL_VISTA_TO_HQ: 'CommonGameTag' = 49164 + FUNC_MAHI_MAHI: 'CommonGameTag' = 63509 + FUNC_MAILBOX: 'CommonGameTag' = 954 + FUNC_MAILBOX_GROUND: 'CommonGameTag' = 2954 + FUNC_MAILBOX_WALL: 'CommonGameTag' = 2168 + FUNC_MAKEUP_TABLE: 'CommonGameTag' = 36868 + FUNC_MANNEQUIN: 'CommonGameTag' = 1322 + FUNC_MANSION: 'CommonGameTag' = 1225 + FUNC_MAP: 'CommonGameTag' = 1312 + FUNC_MARKET_STALL: 'CommonGameTag' = 55298 + FUNC_MARKET_STALLS: 'CommonGameTag' = 1932 + FUNC_MARKET_STALLS_DOCKYARD_PETS: 'CommonGameTag' = 57410 + FUNC_MARKET_STALLS_PURCHASE_FOOD: 'CommonGameTag' = 2378 + FUNC_MARKET_STALLS_PURCHASE_NON_FOOD: 'CommonGameTag' = 2379 + FUNC_MARKET_STALLS_SEAFOOD: 'CommonGameTag' = 1936 + FUNC_MARKET_STALLS_SEASONAL_FALL: 'CommonGameTag' = 59404 + FUNC_MARKET_STALLS_SEASONAL_SPRING: 'CommonGameTag' = 59403 + FUNC_MARKET_STALLS_SEASONAL_SUMMER: 'CommonGameTag' = 59402 + FUNC_MARKET_STALLS_SEASONAL_WINTER: 'CommonGameTag' = 59405 + FUNC_MARKET_STALLS_SQUARE_SNACKS: 'CommonGameTag' = 57405 + FUNC_MARKET_STALLS_SQUARE_SNACKS_PETS: 'CommonGameTag' = 57406 + FUNC_MARKET_STALL_MUSIC_FOOD: 'CommonGameTag' = 2561 + FUNC_MARKET_STALL_MUSIC_SHOP: 'CommonGameTag' = 2562 + FUNC_MASCOT: 'CommonGameTag' = 1295 + FUNC_MASONRY: 'CommonGameTag' = 1096 + FUNC_MASSAGE: 'CommonGameTag' = 18454 + FUNC_MASSAGE_CHAIR: 'CommonGameTag' = 18440 + FUNC_MASSAGE_TABLE: 'CommonGameTag' = 18434 + FUNC_MATTRESS: 'CommonGameTag' = 1285 + FUNC_MEAL: 'CommonGameTag' = 521 + FUNC_MEAL_MEAT: 'CommonGameTag' = 2573 + FUNC_MEAL_VEGGIE: 'CommonGameTag' = 2574 + FUNC_MEAT_WALL: 'CommonGameTag' = 67648 + FUNC_MECH_SUIT_BODY: 'CommonGameTag' = 65639 + FUNC_MECH_SUIT_HEAD: 'CommonGameTag' = 65640 + FUNC_MEDITATION: 'CommonGameTag' = 18452 + FUNC_MEDITATION_STOOL: 'CommonGameTag' = 18438 + FUNC_MEDITATION_STOOL_TEMP: 'CommonGameTag' = 18482 + FUNC_MEDIUM: 'CommonGameTag' = 1188 + FUNC_MEGAPHONE: 'CommonGameTag' = 55406 + FUNC_MENTAL: 'CommonGameTag' = 24599 + FUNC_MERCHANDISE_VENDING_MACHINE: 'CommonGameTag' = 2508 + FUNC_MESS: 'CommonGameTag' = 43031 + FUNC_METAL: 'CommonGameTag' = 1090 + FUNC_MICROPHONE: 'CommonGameTag' = 488 + FUNC_MICROSCOPE: 'CommonGameTag' = 857 + FUNC_MICROWAVE: 'CommonGameTag' = 526 + FUNC_MILITARY_CAREER_MEDAL: 'CommonGameTag' = 47143 + FUNC_MILK: 'CommonGameTag' = 2579 + FUNC_MILK_BASIC: 'CommonGameTag' = 2977 + FUNC_MINI_BOTS: 'CommonGameTag' = 65582 + FUNC_MINI_BOTS_PARTY: 'CommonGameTag' = 65641 + FUNC_MINI_BOTS_WORKER: 'CommonGameTag' = 2275 + FUNC_MIRROR_NO_VANITY: 'CommonGameTag' = 2165 + FUNC_MIXOLOGIST: 'CommonGameTag' = 1116 + FUNC_MIXOLOGY: 'CommonGameTag' = 1103 + FUNC_MODEL: 'CommonGameTag' = 1158 + FUNC_MONKEY: 'CommonGameTag' = 564 + FUNC_MONKEY_BARS: 'CommonGameTag' = 1001 + FUNC_MONSTER: 'CommonGameTag' = 1217 + FUNC_MOTHER_PLANT: 'CommonGameTag' = 47131 + FUNC_MOTHER_PLANT_PIT: 'CommonGameTag' = 47144 + FUNC_MOTION: 'CommonGameTag' = 480 + FUNC_MOTION_GAMING_RIG: 'CommonGameTag' = 1016 + FUNC_MOTOR: 'CommonGameTag' = 24598 + FUNC_MOVIE: 'CommonGameTag' = 1498 + FUNC_MOVIE_THEATER: 'CommonGameTag' = 116737 + FUNC_MUD_BATH: 'CommonGameTag' = 18456 + FUNC_MUD_PUDDLE: 'CommonGameTag' = 59406 + FUNC_MUG: 'CommonGameTag' = 1301 + FUNC_MURAL: 'CommonGameTag' = 55371 + FUNC_MUSIC: 'CommonGameTag' = 491 + FUNC_MUSICIAN: 'CommonGameTag' = 1083 + FUNC_MUSIC_DISC: 'CommonGameTag' = 61470 + FUNC_MUSIC_PRODUCTION_STATION: 'CommonGameTag' = 61469 + FUNC_MUSTARD: 'CommonGameTag' = 1299 + FUNC_MYSTICAL_RELIC_BOTTOM: 'CommonGameTag' = 45067 + FUNC_MYSTICAL_RELIC_CRYSTAL: 'CommonGameTag' = 45068 + FUNC_MYSTICAL_RELIC_FUSED: 'CommonGameTag' = 45078 + FUNC_MYSTICAL_RELIC_TOP: 'CommonGameTag' = 45066 + FUNC_MYSTICAL_RELIC_UNBREAKABLE: 'CommonGameTag' = 45111 + FUNC_NECTAR: 'CommonGameTag' = 1527 + FUNC_NECTAR_MAKER: 'CommonGameTag' = 118885 + FUNC_NECTAR_RACK: 'CommonGameTag' = 118884 + FUNC_NEON: 'CommonGameTag' = 12400 + FUNC_NESTING_BLOCKS: 'CommonGameTag' = 1662 + FUNC_NEVER_RECEIVES_SNOW: 'CommonGameTag' = 2069 + FUNC_NON_BAR_JUICE_ENTHUSIAST_QUIRK: 'CommonGameTag' = 2144 + FUNC_NOT_MANAGED_AS_RUG: 'CommonGameTag' = 2752 + FUNC_NO_AUTONOMOUS_VIEW: 'CommonGameTag' = 2703 + FUNC_NO_CLEAN_UP_FROM_INVENTORY: 'CommonGameTag' = 2210 + FUNC_OBJECT_UPGRADE_PART: 'CommonGameTag' = 780 + FUNC_OBSERVATORY: 'CommonGameTag' = 572 + FUNC_OFF_THE_GRID: 'CommonGameTag' = 2219 + FUNC_OFF_THE_GRID_TOGGLE_UTILITY_USAGE: 'CommonGameTag' = 2427 + FUNC_OPENABLE_WINDOW: 'CommonGameTag' = 2823 + FUNC_ORACLE: 'CommonGameTag' = 1185 + FUNC_ORRERY: 'CommonGameTag' = 12429 + FUNC_OTTOMAN: 'CommonGameTag' = 1007 + FUNC_OUTDOOR: 'CommonGameTag' = 1430 + FUNC_OUTDOORS: 'CommonGameTag' = 1280 + FUNC_OUTDOOR_CHAIR: 'CommonGameTag' = 1004 + FUNC_OUTDOOR_PLANT: 'CommonGameTag' = 1013 + FUNC_OVEN: 'CommonGameTag' = 748 + FUNC_PAINT: 'CommonGameTag' = 483 + FUNC_PAINTER: 'CommonGameTag' = 1120 + FUNC_PAINTING: 'CommonGameTag' = 894 + FUNC_PAINTING_EMOTIONAL: 'CommonGameTag' = 2799 + FUNC_PAINTING_GIFTING: 'CommonGameTag' = 2667 + FUNC_PAINTING_HAUNTED: 'CommonGameTag' = 2515 + FUNC_PANS: 'CommonGameTag' = 1296 + FUNC_PAPER: 'CommonGameTag' = 1418 + FUNC_PAPER_POSTED: 'CommonGameTag' = 43010 + FUNC_PARK_FOUNTAIN: 'CommonGameTag' = 30721 + FUNC_PARTY: 'CommonGameTag' = 529 + FUNC_PATH_OBSTACLE_JUNGLE_01_ENTRANCE: 'CommonGameTag' = 45060 + FUNC_PATH_OBSTACLE_JUNGLE_01_EXIT: 'CommonGameTag' = 45061 + FUNC_PATH_OBSTACLE_JUNGLE_02_ENTRANCE: 'CommonGameTag' = 45062 + FUNC_PATH_OBSTACLE_JUNGLE_02_EXIT: 'CommonGameTag' = 45063 + FUNC_PATH_OBSTACLE_JUNGLE_03_ENTRANCE: 'CommonGameTag' = 45080 + FUNC_PATH_OBSTACLE_JUNGLE_03_EXIT: 'CommonGameTag' = 45081 + FUNC_PATH_OBSTACLE_JUNGLE_04_ENTRANCE: 'CommonGameTag' = 45082 + FUNC_PATH_OBSTACLE_JUNGLE_04_EXIT: 'CommonGameTag' = 45083 + FUNC_PATH_OBSTACLE_JUNGLE_05_ENTRANCE: 'CommonGameTag' = 45084 + FUNC_PATH_OBSTACLE_JUNGLE_05_EXIT: 'CommonGameTag' = 45085 + FUNC_PATH_OBSTACLE_JUNGLE_06_ENTRANCE: 'CommonGameTag' = 45086 + FUNC_PATH_OBSTACLE_JUNGLE_06_EXIT: 'CommonGameTag' = 45087 + FUNC_PATH_OBSTACLE_JUNGLE_POOL_ENTRANCE: 'CommonGameTag' = 45095 + FUNC_PATH_OBSTACLE_JUNGLE_POOL_EXIT: 'CommonGameTag' = 45096 + FUNC_PATH_OBSTACLE_JUNGLE_TEMPLE_ENTRANCE: 'CommonGameTag' = 45064 + FUNC_PATH_OBSTACLE_JUNGLE_TEMPLE_EXIT: 'CommonGameTag' = 45065 + FUNC_PATIO_FURNITURE: 'CommonGameTag' = 1011 + FUNC_PEDESTAL: 'CommonGameTag' = 1399 + FUNC_PEN: 'CommonGameTag' = 112687 + FUNC_PERFORMANCE_SPACE: 'CommonGameTag' = 55299 + FUNC_PET_BALL: 'CommonGameTag' = 57412 + FUNC_PET_BED: 'CommonGameTag' = 57386 + FUNC_PET_BOWL: 'CommonGameTag' = 1876 + FUNC_PET_BUSH: 'CommonGameTag' = 57445 + FUNC_PET_CATNIP: 'CommonGameTag' = 57421 + FUNC_PET_CRATE: 'CommonGameTag' = 57388 + FUNC_PET_DIRT_MOUND: 'CommonGameTag' = 57448 + FUNC_PET_DOG_TOY: 'CommonGameTag' = 57454 + FUNC_PET_FEAR_SOUNDS_BG: 'CommonGameTag' = 2171 + FUNC_PET_FILLER: 'CommonGameTag' = 57380 + FUNC_PET_FILLER_THREE: 'CommonGameTag' = 57382 + FUNC_PET_FILLER_TWO: 'CommonGameTag' = 57381 + FUNC_PET_FISH_PILE: 'CommonGameTag' = 57446 + FUNC_PET_FOOD: 'CommonGameTag' = 57379 + FUNC_PET_GIFT: 'CommonGameTag' = 57444 + FUNC_PET_HIDE_NO_FADE: 'CommonGameTag' = 2031 + FUNC_PET_MINOR_CAGE: 'CommonGameTag' = 77825 + FUNC_PET_MINOR_CAGE_BG: 'CommonGameTag' = 2052 + FUNC_PET_NO_ROUTE_UNDER: 'CommonGameTag' = 2028 + FUNC_PET_OBSTACLE_COURSE: 'CommonGameTag' = 57415 + FUNC_PET_OBSTACLE_COURSE_HOOP: 'CommonGameTag' = 57416 + FUNC_PET_OBSTACLE_COURSE_PLATFORM: 'CommonGameTag' = 57418 + FUNC_PET_OBSTACLE_COURSE_RAMP: 'CommonGameTag' = 57417 + FUNC_PET_OBSTACLE_COURSE_TUNNEL: 'CommonGameTag' = 57420 + FUNC_PET_OBSTACLE_COURSE_WEAVING_FLAGS: 'CommonGameTag' = 57419 + FUNC_PET_POOP: 'CommonGameTag' = 57361 + FUNC_PET_POOP_NO_CLEAN: 'CommonGameTag' = 57455 + FUNC_PET_RECIPE: 'CommonGameTag' = 57404 + FUNC_PET_RECIPE_FOOD: 'CommonGameTag' = 1930 + FUNC_PET_SCRATCHABLE_FURNITURE: 'CommonGameTag' = 1878 + FUNC_PET_SEAWEED: 'CommonGameTag' = 57447 + FUNC_PET_SQUEAKY_BALL: 'CommonGameTag' = 57413 + FUNC_PET_TOY: 'CommonGameTag' = 1877 + FUNC_PET_TOY_BOX: 'CommonGameTag' = 57376 + FUNC_PET_TOY_NEW: 'CommonGameTag' = 57440 + FUNC_PET_TOY_SMART_TRAIT_CARRY: 'CommonGameTag' = 57456 + FUNC_PET_TREAT: 'CommonGameTag' = 57426 + FUNC_PET_TREAT_EDIBLE: 'CommonGameTag' = 57431 + FUNC_PET_TREAT_EDIBLE_CHILD: 'CommonGameTag' = 57438 + FUNC_PET_TREAT_EDIBLE_ELDER: 'CommonGameTag' = 57439 + FUNC_PET_VACUUM: 'CommonGameTag' = 2518 + FUNC_PHANTOM: 'CommonGameTag' = 1194 + FUNC_PHOTO: 'CommonGameTag' = 1382 + FUNC_PHOTOGRAPHY: 'CommonGameTag' = 1383 + FUNC_PHOTOGRAPHY_DISALLOW: 'CommonGameTag' = 1438 + FUNC_PHOTO_BOOTH: 'CommonGameTag' = 114718 + FUNC_PHOTO_COLLAGE: 'CommonGameTag' = 79874 + FUNC_PHOTO_OP_STAND: 'CommonGameTag' = 114702 + FUNC_PHOTO_STUDIO: 'CommonGameTag' = 1941 + FUNC_PHOTO_STUDIO_SEARCH: 'CommonGameTag' = 2218 + FUNC_PIANO: 'CommonGameTag' = 566 + FUNC_PICNIC: 'CommonGameTag' = 1317 + FUNC_PICNICBASKET_BG: 'CommonGameTag' = 2700 + FUNC_PICNIC_BASKET: 'CommonGameTag' = 112649 + FUNC_PICNIC_TABLE: 'CommonGameTag' = 1248 + FUNC_PIER_ATTRACTIONS: 'CommonGameTag' = 114720 + FUNC_PILLAR: 'CommonGameTag' = 1010 + FUNC_PIPE: 'CommonGameTag' = 1410 + FUNC_PIPE_ORGAN: 'CommonGameTag' = 40963 + FUNC_PIRATE: 'CommonGameTag' = 501 + FUNC_PIT_BBQ: 'CommonGameTag' = 63527 + FUNC_PIZZA_DELIVERY_POST_JOB_LOSS: 'CommonGameTag' = 116738 + FUNC_PLACEABLE_ON_TREEHOUSE: 'CommonGameTag' = 2968 + FUNC_PLACEMAT_DRAWING: 'CommonGameTag' = 26639 + FUNC_PLACEMAT_FORMAL: 'CommonGameTag' = 1711 + FUNC_PLANTER_BOX: 'CommonGameTag' = 1149 + FUNC_PLAQUE: 'CommonGameTag' = 1420 + FUNC_PLAY: 'CommonGameTag' = 1142 + FUNC_PLUSH: 'CommonGameTag' = 1021 + FUNC_PODIUM: 'CommonGameTag' = 1577 + FUNC_PODIUM_PAIR: 'CommonGameTag' = 65591 + FUNC_PODIUM_PAIR_DEBATE_SHOWDOWN: 'CommonGameTag' = 65594 + FUNC_POLE: 'CommonGameTag' = 1404 + FUNC_POLICE: 'CommonGameTag' = 12398 + FUNC_POND: 'CommonGameTag' = 2645 + FUNC_POND_FISHSIGN: 'CommonGameTag' = 2601 + FUNC_POOL: 'CommonGameTag' = 1233 + FUNC_POOL_LADDER: 'CommonGameTag' = 1240 + FUNC_POOL_LIGHT: 'CommonGameTag' = 1234 + FUNC_POPCORN: 'CommonGameTag' = 28674 + FUNC_POPCORN_BUTTERED: 'CommonGameTag' = 28678 + FUNC_POPCORN_CARAMEL: 'CommonGameTag' = 28676 + FUNC_POPCORN_CHEDDAR: 'CommonGameTag' = 28675 + FUNC_POPCORN_KETTLE: 'CommonGameTag' = 28677 + FUNC_POPCORN_POPPER: 'CommonGameTag' = 28673 + FUNC_PORTABLE_BAR: 'CommonGameTag' = 24602 + FUNC_PORTABLE_KEYBOARD: 'CommonGameTag' = 1627 + FUNC_PORTAL: 'CommonGameTag' = 1435 + FUNC_PORTRAIT: 'CommonGameTag' = 1422 + FUNC_POSTER: 'CommonGameTag' = 895 + FUNC_POT: 'CommonGameTag' = 1144 + FUNC_POTION: 'CommonGameTag' = 993 + FUNC_POTTY: 'CommonGameTag' = 1664 + FUNC_POWER_GENERATOR: 'CommonGameTag' = 67617 + FUNC_PREGENERATE_DEFAULT_MAT_GEO_STATE_THUMBNAIL_ONLY: 'CommonGameTag' = 2170 + FUNC_PRESENT_PILE: 'CommonGameTag' = 59410 + FUNC_PRESENT_PILE_LARGE: 'CommonGameTag' = 59416 + FUNC_PRESENT_PILE_SMALL: 'CommonGameTag' = 59415 + FUNC_PREVENT_RECYCLING: 'CommonGameTag' = 2442 + FUNC_PRISON: 'CommonGameTag' = 1380 + FUNC_PRIVACY_OBEY_APPROPRIATE: 'CommonGameTag' = 61640 + FUNC_PRODUCE: 'CommonGameTag' = 2582 + FUNC_PROGRAMMING: 'CommonGameTag' = 1101 + FUNC_PROPANE: 'CommonGameTag' = 1281 + FUNC_PSYCHIC: 'CommonGameTag' = 1186 + FUNC_PUBLIC_BATHROOM: 'CommonGameTag' = 1340 + FUNC_PUDDLE: 'CommonGameTag' = 567 + FUNC_PUMPKIN: 'CommonGameTag' = 1204 + FUNC_PUNCHING: 'CommonGameTag' = 477 + FUNC_PUPPET_THEATER: 'CommonGameTag' = 32769 + FUNC_PURCHASE_BEACH: 'CommonGameTag' = 63506 + FUNC_PURCHASE_BEACH_ACCESSORIES: 'CommonGameTag' = 63532 + FUNC_PURCHASE_BEACH_FISHING: 'CommonGameTag' = 63529 + FUNC_PURCHASE_BEACH_FRUITS: 'CommonGameTag' = 63533 + FUNC_PURCHASE_BEACH_LEISURE: 'CommonGameTag' = 63530 + FUNC_PURCHASE_BEACH_VEHICLES: 'CommonGameTag' = 63531 + FUNC_PURCHASE_MUSIC_FESTIVAL: 'CommonGameTag' = 2564 + FUNC_PURCHASE_PICKER_CATEGORY_BOOK_EMOTIONAL: 'CommonGameTag' = 1037 + FUNC_PURCHASE_PICKER_CATEGORY_BOOK_SKILL: 'CommonGameTag' = 1036 + FUNC_PURCHASE_VACATION_FUN: 'CommonGameTag' = 2503 + FUNC_PURCHASE_VACATION_FURNITURE: 'CommonGameTag' = 2500 + FUNC_PURCHASE_VACATION_MISC: 'CommonGameTag' = 2504 + FUNC_PURCHASE_VACATION_SUPPLIES: 'CommonGameTag' = 2502 + FUNC_PURCHASE_VACATION_TENTS: 'CommonGameTag' = 2501 + FUNC_PUZZLES: 'CommonGameTag' = 2949 + FUNC_PUZZLES_PIECES: 'CommonGameTag' = 116757 + FUNC_QUADCOPTER: 'CommonGameTag' = 65624 + FUNC_RACK: 'CommonGameTag' = 1146 + FUNC_RANCH_NECTAR: 'CommonGameTag' = 118791 + FUNC_RANCH_NECTARITEMS: 'CommonGameTag' = 118876 + FUNC_RANCH_NECTARMAKER: 'CommonGameTag' = 118875 + FUNC_RANCH_NECTAR_BOTTLE: 'CommonGameTag' = 118790 + FUNC_RANGE: 'CommonGameTag' = 1169 + FUNC_RANGER_STATION: 'CommonGameTag' = 1341 + FUNC_RANGER_STATION_CATEGORY_FUN: 'CommonGameTag' = 1889 + FUNC_RANGER_STATION_CATEGORY_FURNITURE: 'CommonGameTag' = 1888 + FUNC_RANGER_STATION_CATEGORY_INGREDIENT: 'CommonGameTag' = 1890 + FUNC_RANGER_STATION_CATEGORY_PET: 'CommonGameTag' = 2012 + FUNC_RANGER_STATION_CATEGORY_SUPPLIES: 'CommonGameTag' = 1887 + FUNC_RANGER_STATION_FUN: 'CommonGameTag' = 10269 + FUNC_RANGER_STATION_FURNITURE: 'CommonGameTag' = 10268 + FUNC_RANGER_STATION_INGREDIENT: 'CommonGameTag' = 10270 + FUNC_RANGER_STATION_SUPPLIES: 'CommonGameTag' = 10267 + FUNC_RAT: 'CommonGameTag' = 77830 + FUNC_REAPER: 'CommonGameTag' = 576 + FUNC_REBATE_PLANT: 'CommonGameTag' = 2205 + FUNC_RECIPE: 'CommonGameTag' = 522 + FUNC_RECIPE_BAKING_CUPCAKE_FACTORY: 'CommonGameTag' = 12377 + FUNC_RECIPE_BAKING_OVEN: 'CommonGameTag' = 12376 + FUNC_RECLINER: 'CommonGameTag' = 1111 + FUNC_RECORDING: 'CommonGameTag' = 47149 + FUNC_RECYCLER: 'CommonGameTag' = 67585 + FUNC_REFRIGERATOR: 'CommonGameTag' = 519 + FUNC_REGISTERED_VAMPIRE_LAIR: 'CommonGameTag' = 2271 + FUNC_REGISTERS: 'CommonGameTag' = 12395 + FUNC_RELAXATION: 'CommonGameTag' = 18457 + FUNC_REPAIR_BURNT: 'CommonGameTag' = 67644 + FUNC_REPAIR_BURNT_VARIABLE_HEIGHT: 'CommonGameTag' = 67643 + FUNC_REPAIR_BURNT_VARIABLE_HEIGHT_BG: 'CommonGameTag' = 2435 + FUNC_REQUIRES_OCEAN_LOT: 'CommonGameTag' = 63519 + FUNC_RESEARCH_MACHINE: 'CommonGameTag' = 65631 + FUNC_RESTAURANT_NOT_A_TABLE: 'CommonGameTag' = 26649 + FUNC_RETAIL: 'CommonGameTag' = 1321 + FUNC_RETAIL_FRIDGE: 'CommonGameTag' = 12431 + FUNC_RETAIL_NEON_LIGHT: 'CommonGameTag' = 12365 + FUNC_RETAIL_NPC_ITEM_FOR_SALE: 'CommonGameTag' = 12384 + FUNC_RETAIL_PEDESTAL: 'CommonGameTag' = 12383 + FUNC_RETAIL_REGISTER: 'CommonGameTag' = 12311 + FUNC_REVIEW_PRODUCT_BEAUTY: 'CommonGameTag' = 61557 + FUNC_REVIEW_PRODUCT_GADGET: 'CommonGameTag' = 61559 + FUNC_REVIEW_PRODUCT_TECH: 'CommonGameTag' = 61558 + FUNC_REWARD: 'CommonGameTag' = 1121 + FUNC_RIG: 'CommonGameTag' = 1015 + FUNC_ROBOTICS_TABLE: 'CommonGameTag' = 65565 + FUNC_ROBOTIC_ARM: 'CommonGameTag' = 2281 + FUNC_ROBOT_VACUUM: 'CommonGameTag' = 1982 + FUNC_ROBOT_VACUUM_BASE: 'CommonGameTag' = 1983 + FUNC_ROBOT_VACUUM_CLEAN_DEFAULT: 'CommonGameTag' = 57422 + FUNC_ROBOT_VACUUM_CLEAN_UPGRADE: 'CommonGameTag' = 57423 + FUNC_ROBOT_VACUUM_MESS_DEFAULT_CLEAN: 'CommonGameTag' = 2010 + FUNC_ROBOT_VACUUM_MESS_UPGRADED_CLEAN: 'CommonGameTag' = 2011 + FUNC_ROCK: 'CommonGameTag' = 1318 + FUNC_ROCKET: 'CommonGameTag' = 495 + FUNC_ROCKET_SCIENCE: 'CommonGameTag' = 1105 + FUNC_ROCKING_CHAIR: 'CommonGameTag' = 2462 + FUNC_ROCKING_CHAIR_ARM_CHAIR: 'CommonGameTag' = 83986 + FUNC_ROCK_CLIMBING_WALL: 'CommonGameTag' = 71681 + FUNC_ROCK_WALL: 'CommonGameTag' = 71682 + FUNC_ROOMMATE_ABSENT: 'CommonGameTag' = 2263 + FUNC_ROOMMATE_ART: 'CommonGameTag' = 2259 + FUNC_ROOMMATE_BAKING: 'CommonGameTag' = 2257 + FUNC_ROOMMATE_BATHROOM_HOG: 'CommonGameTag' = 2262 + FUNC_ROOMMATE_BIG_CLOSET: 'CommonGameTag' = 2264 + FUNC_ROOMMATE_BREAKER: 'CommonGameTag' = 2256 + FUNC_ROOMMATE_CANT_STOP_THE_BEAT: 'CommonGameTag' = 2255 + FUNC_ROOMMATE_CHEERLEADER: 'CommonGameTag' = 2248 + FUNC_ROOMMATE_CLINGY_SOCIALITE: 'CommonGameTag' = 2251 + FUNC_ROOMMATE_COMPUTER: 'CommonGameTag' = 2260 + FUNC_ROOMMATE_COUCH_POTATO: 'CommonGameTag' = 2252 + FUNC_ROOMMATE_EMO_LONER: 'CommonGameTag' = 2254 + FUNC_ROOMMATE_FITNESS: 'CommonGameTag' = 2261 + FUNC_ROOMMATE_FIXER: 'CommonGameTag' = 2250 + FUNC_ROOMMATE_LATE_ON_RENT: 'CommonGameTag' = 2267 + FUNC_ROOMMATE_MEAL_MAKER: 'CommonGameTag' = 2249 + FUNC_ROOMMATE_MUSIC: 'CommonGameTag' = 2258 + FUNC_ROOMMATE_PARTY_PLANNER: 'CommonGameTag' = 2253 + FUNC_ROOMMATE_PRANKSTER: 'CommonGameTag' = 2266 + FUNC_ROOMMATE_PUBLIC_AFFECTION_DISPLAYER: 'CommonGameTag' = 2265 + FUNC_ROOMMATE_SUPER_NEAT: 'CommonGameTag' = 2247 + FUNC_ROOSTER: 'CommonGameTag' = 112683 + FUNC_RUBBISH: 'CommonGameTag' = 923 + FUNC_RUG: 'CommonGameTag' = 2020 + FUNC_RUSTIC: 'CommonGameTag' = 1320 + FUNC_SABACC_CHIP_PILE: 'CommonGameTag' = 51254 + FUNC_SACRED_CANDLE: 'CommonGameTag' = 86020 + FUNC_SADCLOWN: 'CommonGameTag' = 2943 + FUNC_SALE: 'CommonGameTag' = 1406 + FUNC_SALINE: 'CommonGameTag' = 1407 + FUNC_SAUCER: 'CommonGameTag' = 1393 + FUNC_SAUCE_POT: 'CommonGameTag' = 2450 + FUNC_SAUNA: 'CommonGameTag' = 18455 + FUNC_SAWHORSE: 'CommonGameTag' = 1408 + FUNC_SCARECROW: 'CommonGameTag' = 59459 + FUNC_SCENT_FLOWER_HIGH_SKILL: 'CommonGameTag' = 59470 + FUNC_SCENT_FLOWER_LOW_SKILL: 'CommonGameTag' = 59469 + FUNC_SCHOOL_LOCKER: 'CommonGameTag' = 114692 + FUNC_SCHOOL_PROJECT_BOX_CHILD: 'CommonGameTag' = 43013 + FUNC_SCHOOL_PROJECT_BOX_TEEN: 'CommonGameTag' = 43014 + FUNC_SCIENCE: 'CommonGameTag' = 1019 + FUNC_SCIENCE_TABLE: 'CommonGameTag' = 858 + FUNC_SCIENCE_UNIVERSITY_SHELL: 'CommonGameTag' = 65549 + FUNC_SCIENCE_UNIVERSITY_SHELL_SHELL_1: 'CommonGameTag' = 65562 + FUNC_SCIENCE_UNIVERSITY_SHELL_SHELL_2: 'CommonGameTag' = 65563 + FUNC_SCIENTIST: 'CommonGameTag' = 12396 + FUNC_SCRATCHED_ALL: 'CommonGameTag' = 57369 + FUNC_SCRATCHED_LOW: 'CommonGameTag' = 57368 + FUNC_SCRATCHING_POST: 'CommonGameTag' = 57384 + FUNC_SCREEN: 'CommonGameTag' = 1031 + FUNC_SCULPTURE: 'CommonGameTag' = 2581 + FUNC_SCYTHE: 'CommonGameTag' = 574 + FUNC_SEANCE: 'CommonGameTag' = 1189 + FUNC_SEANCE_CIRCLE: 'CommonGameTag' = 86018 + FUNC_SEANCE_TABLE: 'CommonGameTag' = 86017 + FUNC_SEASHELL: 'CommonGameTag' = 63508 + FUNC_SEASONAL: 'CommonGameTag' = 59445 + FUNC_SECRET_AGENT: 'CommonGameTag' = 1127 + FUNC_SECRET_SOCIETY_GARDEN: 'CommonGameTag' = 65569 + FUNC_SECTIONAL_SOFA_CHAISE: 'CommonGameTag' = 53249 + FUNC_SECTIONAL_SOFA_PIECE: 'CommonGameTag' = 2558 + FUNC_SECTIONAL_SOFA_WHOLE: 'CommonGameTag' = 2557 + FUNC_SEER: 'CommonGameTag' = 1187 + FUNC_SERUMS: 'CommonGameTag' = 12430 + FUNC_SERVICE_INDOOR: 'CommonGameTag' = 2976 + FUNC_SERVICE_OUTDOOR: 'CommonGameTag' = 2975 + FUNC_SHADES: 'CommonGameTag' = 1154 + FUNC_SHEET: 'CommonGameTag' = 1290 + FUNC_SHELF: 'CommonGameTag' = 1148 + FUNC_SHELL_INTERACTIVE: 'CommonGameTag' = 2245 + FUNC_SHIP: 'CommonGameTag' = 496 + FUNC_SHOES_SEARCH: 'CommonGameTag' = 2556 + FUNC_SHOWER: 'CommonGameTag' = 1315 + FUNC_SHOWER_TUB: 'CommonGameTag' = 1663 + FUNC_SHUTTLE: 'CommonGameTag' = 1397 + FUNC_SIGN: 'CommonGameTag' = 1027 + FUNC_SIMBLES: 'CommonGameTag' = 2953 + FUNC_SIM_RAY: 'CommonGameTag' = 1278 + FUNC_SIM_RAY_NOT_VALID_TRANSFORM_RESULT: 'CommonGameTag' = 2778 + FUNC_SIM_RAY_NOT_VALID_TRANSFORM_RESULT_BG: 'CommonGameTag' = 1528 + FUNC_SIM_RAY_TRANSFORM_ALIEN_VISITOR_ALLOW: 'CommonGameTag' = 12362 + FUNC_SING: 'CommonGameTag' = 489 + FUNC_SINGLE_BED: 'CommonGameTag' = 779 + FUNC_SINK: 'CommonGameTag' = 1313 + FUNC_SIT: 'CommonGameTag' = 1434 + FUNC_SIT_LOUNGE: 'CommonGameTag' = 2196 + FUNC_SIT_LOUNGE_FLOAT: 'CommonGameTag' = 2202 + FUNC_SKATING_RINK: 'CommonGameTag' = 59407 + FUNC_SKATING_RINK_ICE_NATURAL: 'CommonGameTag' = 59399 + FUNC_SKATING_RINK_ICE_RINK: 'CommonGameTag' = 59398 + FUNC_SKATING_RINK_LARGE: 'CommonGameTag' = 59436 + FUNC_SKATING_RINK_ROLLER_RINK: 'CommonGameTag' = 59400 + FUNC_SKATING_RINK_SEASONAL: 'CommonGameTag' = 59448 + FUNC_SKATING_RINK_SMALL: 'CommonGameTag' = 59435 + FUNC_SKELETON: 'CommonGameTag' = 1208 + FUNC_SKETCHPAD: 'CommonGameTag' = 2159 + FUNC_SKILLS: 'CommonGameTag' = 1384 + FUNC_SKULL: 'CommonGameTag' = 1212 + FUNC_SLEEP: 'CommonGameTag' = 1143 + FUNC_SLEEPING_BAG: 'CommonGameTag' = 2931 + FUNC_SLEEPING_BAG_TODDLER: 'CommonGameTag' = 2932 + FUNC_SLEEPING_POD: 'CommonGameTag' = 61624 + FUNC_SLIDE_LAWN: 'CommonGameTag' = 34818 + FUNC_SLIPPY_SLIDE: 'CommonGameTag' = 34817 + FUNC_SMART_HUB: 'CommonGameTag' = 2174 + FUNC_SNOB_ART_ASSESS: 'CommonGameTag' = 2133 + FUNC_SNOB_ART_ASSESS_NO_RESERVE: 'CommonGameTag' = 2134 + FUNC_SNOW: 'CommonGameTag' = 1333 + FUNC_SNOW_ANGEL: 'CommonGameTag' = 2484 + FUNC_SNOW_DRIFT: 'CommonGameTag' = 2485 + FUNC_SNOW_MAN: 'CommonGameTag' = 1336 + FUNC_SNOW_PAL: 'CommonGameTag' = 2486 + FUNC_SNOW_SPORTS_SLOPE_BUNNY_SLOPE: 'CommonGameTag' = 69646 + FUNC_SNOW_SPORTS_SLOPE_EASY_SLOPE: 'CommonGameTag' = 69647 + FUNC_SNOW_SPORTS_SLOPE_EXPERT_SLOPE: 'CommonGameTag' = 69649 + FUNC_SNOW_SPORTS_SLOPE_EXTREME_SLOPE: 'CommonGameTag' = 69650 + FUNC_SNOW_SPORTS_SLOPE_INTERMEDIATE_SLOPE: 'CommonGameTag' = 69648 + FUNC_SNOW_SPORTS_SLOPE_SKIS: 'CommonGameTag' = 69643 + FUNC_SNOW_SPORTS_SLOPE_SKIS_ADULT: 'CommonGameTag' = 69715 + FUNC_SNOW_SPORTS_SLOPE_SKIS_ADULT_RENTABLE: 'CommonGameTag' = 69717 + FUNC_SNOW_SPORTS_SLOPE_SKIS_CHILD: 'CommonGameTag' = 69676 + FUNC_SNOW_SPORTS_SLOPE_SKIS_CHILD_RENTABLE: 'CommonGameTag' = 69719 + FUNC_SNOW_SPORTS_SLOPE_SKIS_RENTED: 'CommonGameTag' = 69678 + FUNC_SNOW_SPORTS_SLOPE_SLED: 'CommonGameTag' = 69645 + FUNC_SNOW_SPORTS_SLOPE_SNOWBOARD: 'CommonGameTag' = 69644 + FUNC_SNOW_SPORTS_SLOPE_SNOWBOARD_ADULT: 'CommonGameTag' = 69716 + FUNC_SNOW_SPORTS_SLOPE_SNOWBOARD_ADULT_RENTABLE: 'CommonGameTag' = 69718 + FUNC_SNOW_SPORTS_SLOPE_SNOWBOARD_CHILD: 'CommonGameTag' = 69677 + FUNC_SNOW_SPORTS_SLOPE_SNOWBOARD_CHILD_RENTABLE: 'CommonGameTag' = 69720 + FUNC_SNOW_SPORTS_SLOPE_SNOWBOARD_RENTED: 'CommonGameTag' = 69679 + FUNC_SOAP: 'CommonGameTag' = 1423 + FUNC_SOCCER_BALL: 'CommonGameTag' = 65540 + FUNC_SOCIAL: 'CommonGameTag' = 1000 + FUNC_SOLAR_PANEL: 'CommonGameTag' = 67613 + FUNC_SOUND: 'CommonGameTag' = 517 + FUNC_SPACE: 'CommonGameTag' = 497 + FUNC_SPACESHIP: 'CommonGameTag' = 994 + FUNC_SPACE_RANGER: 'CommonGameTag' = 1132 + FUNC_SPAWNER: 'CommonGameTag' = 2782 + FUNC_SPECTER: 'CommonGameTag' = 86022 + FUNC_SPECTER_JAR_FRIENDLY: 'CommonGameTag' = 86023 + FUNC_SPECTER_JAR_MEAN: 'CommonGameTag' = 86024 + FUNC_SPECTER_JAR_MYSTERIOUS: 'CommonGameTag' = 86025 + FUNC_SPELLS_DUPLICATE: 'CommonGameTag' = 49165 + FUNC_SPELLS_DUPLICATE_BG: 'CommonGameTag' = 2268 + FUNC_SPELLS_STEAL: 'CommonGameTag' = 49167 + FUNC_SPELLS_STEAL_BG: 'CommonGameTag' = 2436 + FUNC_SPIDER: 'CommonGameTag' = 1192 + FUNC_SPIRIT: 'CommonGameTag' = 1197 + FUNC_SPLASH_PAD: 'CommonGameTag' = 116739 + FUNC_SPLASH_PAD_OPEN_STREET: 'CommonGameTag' = 116758 + FUNC_SPLASH_PAD_PLAY_ON: 'CommonGameTag' = 116756 + FUNC_SPLASH_PAD_WHALE: 'CommonGameTag' = 116759 + FUNC_SPOOK: 'CommonGameTag' = 1196 + FUNC_SPOOKY: 'CommonGameTag' = 1178 + FUNC_SPORTS_ARENA_ARTS: 'CommonGameTag' = 65607 + FUNC_SPORTS_ARENA_SCIENCE: 'CommonGameTag' = 65608 + FUNC_SPRINKLER: 'CommonGameTag' = 1061 + FUNC_SPRINKLER_FLOOR: 'CommonGameTag' = 2099 + FUNC_SP_TABLE: 'CommonGameTag' = 1182 + FUNC_STAGE_GATE_ACTORS: 'CommonGameTag' = 61464 + FUNC_STAGE_LIGHT_ALL: 'CommonGameTag' = 61461 + FUNC_STAGE_MARK_DUO_1_1: 'CommonGameTag' = 61443 + FUNC_STAGE_MARK_DUO_1_2: 'CommonGameTag' = 61444 + FUNC_STAGE_MARK_DUO_1_3: 'CommonGameTag' = 61445 + FUNC_STAGE_MARK_DUO_2_1: 'CommonGameTag' = 61481 + FUNC_STAGE_MARK_DUO_2_2: 'CommonGameTag' = 61482 + FUNC_STAGE_MARK_DUO_2_3: 'CommonGameTag' = 61483 + FUNC_STAGE_MARK_DUO_3_1: 'CommonGameTag' = 61484 + FUNC_STAGE_MARK_DUO_3_2: 'CommonGameTag' = 61485 + FUNC_STAGE_MARK_DUO_3_3: 'CommonGameTag' = 61486 + FUNC_STAGE_MARK_DUO_SWORD_FIGHT: 'CommonGameTag' = 61623 + FUNC_STAGE_MARK_SOLO_1_1: 'CommonGameTag' = 61446 + FUNC_STAGE_MARK_SOLO_1_2: 'CommonGameTag' = 61447 + FUNC_STAGE_MARK_SOLO_1_3: 'CommonGameTag' = 61448 + FUNC_STAGE_MARK_SOLO_2_1: 'CommonGameTag' = 61487 + FUNC_STAGE_MARK_SOLO_2_2: 'CommonGameTag' = 61488 + FUNC_STAGE_MARK_SOLO_2_3: 'CommonGameTag' = 61489 + FUNC_STAGE_MARK_SOLO_3_1: 'CommonGameTag' = 61490 + FUNC_STAGE_MARK_SOLO_3_2: 'CommonGameTag' = 61491 + FUNC_STAGE_MARK_SOLO_3_3: 'CommonGameTag' = 61492 + FUNC_STAGE_MARK_SOLO_DEATH: 'CommonGameTag' = 61622 + FUNC_STALLS_CURIO_SHOP_OBJECTS: 'CommonGameTag' = 47107 + FUNC_STALLS_PRODUCE_CURRY_CHILI: 'CommonGameTag' = 55342 + FUNC_STALLS_PRODUCE_GROCERY: 'CommonGameTag' = 55341 + FUNC_STALLS_PRODUCE_SAFFRON: 'CommonGameTag' = 55343 + FUNC_STALLS_PRODUCE_WASABI: 'CommonGameTag' = 55344 + FUNC_STALLS_SCHWAG_FESTIVAL_ALL_STALLS: 'CommonGameTag' = 55349 + FUNC_STALLS_SCHWAG_FESTIVAL_BLOSSOM: 'CommonGameTag' = 55336 + FUNC_STALLS_SCHWAG_FESTIVAL_FLEA_MARKET: 'CommonGameTag' = 55337 + FUNC_STALLS_SCHWAG_FESTIVAL_FOOD: 'CommonGameTag' = 55338 + FUNC_STALLS_SCHWAG_FESTIVAL_LAMP: 'CommonGameTag' = 55339 + FUNC_STALLS_SCHWAG_FESTIVAL_LOGIC: 'CommonGameTag' = 55340 + FUNC_STAND: 'CommonGameTag' = 1166 + FUNC_STANDING_LAMP: 'CommonGameTag' = 1137 + FUNC_STATUE: 'CommonGameTag' = 1156 + FUNC_STEAM_FISSURE: 'CommonGameTag' = 24585 + FUNC_STEAM_ROOM: 'CommonGameTag' = 18444 + FUNC_STEAM_VENT: 'CommonGameTag' = 63500 + FUNC_STEPS: 'CommonGameTag' = 1077 + FUNC_STEREO: 'CommonGameTag' = 516 + FUNC_STEREO_PUBLIC: 'CommonGameTag' = 2135 + FUNC_STICKER: 'CommonGameTag' = 1152 + FUNC_STONE: 'CommonGameTag' = 1089 + FUNC_STOOL: 'CommonGameTag' = 1008 + FUNC_STORE: 'CommonGameTag' = 12424 + FUNC_STRATEGY: 'CommonGameTag' = 487 + FUNC_STRIPED: 'CommonGameTag' = 1388 + FUNC_STUFFED: 'CommonGameTag' = 504 + FUNC_STUFFED_ANIMAL: 'CommonGameTag' = 1020 + FUNC_STUMP: 'CommonGameTag' = 1308 + FUNC_STYLEBOARD: 'CommonGameTag' = 2130 + FUNC_SUGAR_SKULL: 'CommonGameTag' = 1567 + FUNC_SUITCASE: 'CommonGameTag' = 2950 + FUNC_SUITCASE_CHILD: 'CommonGameTag' = 116754 + FUNC_SUITCASE_DESTROY: 'CommonGameTag' = 116751 + FUNC_SUNFLOWER: 'CommonGameTag' = 1398 + FUNC_SUPPLIES: 'CommonGameTag' = 1294 + FUNC_SWIM: 'CommonGameTag' = 1231 + FUNC_SWIMMING_POOL: 'CommonGameTag' = 1232 + FUNC_SWING_SET: 'CommonGameTag' = 2125 + FUNC_SWING_SET_BG: 'CommonGameTag' = 2120 + FUNC_SWIPE_BASIC: 'CommonGameTag' = 2136 + FUNC_SWIPE_HIGH_SKILL: 'CommonGameTag' = 2138 + FUNC_SWIPE_HOUSEHOLD_INVENTORY_BASIC: 'CommonGameTag' = 2139 + FUNC_SWIPE_HOUSEHOLD_INVENTORY_HIGH_SKILL: 'CommonGameTag' = 2141 + FUNC_SWIPE_HOUSEHOLD_INVENTORY_MED_SKILL: 'CommonGameTag' = 2140 + FUNC_SWIPE_MED_SKILL: 'CommonGameTag' = 2137 + FUNC_SYNC_SHOE_REMOVAL_RULE: 'CommonGameTag' = 69667 + FUNC_SYSTEM: 'CommonGameTag' = 518 + FUNC_SYSTEM_SPAWNED_DUST_FRIEND: 'CommonGameTag' = 2522 + FUNC_SYSTEM_SPAWNED_DUST_PILE: 'CommonGameTag' = 2523 + FUNC_SYSTEM_SPAWNED_SPECTER: 'CommonGameTag' = 2524 + FUNC_SYSTEM_SPAWNED_WILD_GRASS: 'CommonGameTag' = 2983 + FUNC_TABLE: 'CommonGameTag' = 486 + FUNC_TABLET: 'CommonGameTag' = 1108 + FUNC_TABLE_CHANGE_DIAPER: 'CommonGameTag' = 2915 + FUNC_TABLE_CLOTH: 'CommonGameTag' = 1335 + FUNC_TABLE_DINING: 'CommonGameTag' = 2769 + FUNC_TABLE_DINING_BAR: 'CommonGameTag' = 1538 + FUNC_TABLE_DINING_UMBRELLA: 'CommonGameTag' = 1547 + FUNC_TABLE_LOW: 'CommonGameTag' = 2507 + FUNC_TANK: 'CommonGameTag' = 1433 + FUNC_TARP: 'CommonGameTag' = 1289 + FUNC_TEA: 'CommonGameTag' = 577 + FUNC_TEA_SET: 'CommonGameTag' = 133126 + FUNC_TECH_GURU: 'CommonGameTag' = 1133 + FUNC_TEDDY: 'CommonGameTag' = 1073 + FUNC_TEDDY_BEAR: 'CommonGameTag' = 1074 + FUNC_TELESCOPE: 'CommonGameTag' = 571 + FUNC_TELEVISION: 'CommonGameTag' = 470 + FUNC_TELLER: 'CommonGameTag' = 1181 + FUNC_TEMPERATURE_COOLER: 'CommonGameTag' = 2060 + FUNC_TEMPERATURE_HEATER: 'CommonGameTag' = 2059 + FUNC_TEMPLE_CHEST: 'CommonGameTag' = 45091 + FUNC_TEMPLE_GATE: 'CommonGameTag' = 45057 + FUNC_TEMPLE_TRAP: 'CommonGameTag' = 45058 + FUNC_TEMP_CRAFT_SALES_TABLE_CREATED_OBJECTS: 'CommonGameTag' = 55370 + FUNC_TEMP_CRAFT_SALES_TABLE_CREATED_OBJECTS_BG: 'CommonGameTag' = 2040 + FUNC_TENT: 'CommonGameTag' = 2478 + FUNC_TERM_PRESENTATION_CLASS_A: 'CommonGameTag' = 65649 + FUNC_TERM_PRESENTATION_CLASS_B: 'CommonGameTag' = 65650 + FUNC_TERM_PRESENTATION_CLASS_C: 'CommonGameTag' = 65651 + FUNC_TERM_PRESENTATION_CLASS_D: 'CommonGameTag' = 65652 + FUNC_TERRACOTTA: 'CommonGameTag' = 1087 + FUNC_TERRARIUM: 'CommonGameTag' = 77827 + FUNC_THERMOSTAT: 'CommonGameTag' = 59456 + FUNC_THRIFT_STORE_RETAIL_RACK: 'CommonGameTag' = 114699 + FUNC_THROWING_MUD: 'CommonGameTag' = 59428 + FUNC_THROWING_SNOWBALLS: 'CommonGameTag' = 2487 + FUNC_THROWING_WATER_BALLOONS: 'CommonGameTag' = 59427 + FUNC_THROW_FOOTBALL: 'CommonGameTag' = 114737 + FUNC_TILE: 'CommonGameTag' = 1088 + FUNC_TOASTING_BUCKET: 'CommonGameTag' = 133149 + FUNC_TOASTING_BUCKET_BG: 'CommonGameTag' = 2764 + FUNC_TODDLER: 'CommonGameTag' = 1685 + FUNC_TODDLER_BALL_PIT: 'CommonGameTag' = 73734 + FUNC_TODDLER_BED: 'CommonGameTag' = 1658 + FUNC_TODDLER_BOOKCASE: 'CommonGameTag' = 1666 + FUNC_TODDLER_GYM_OBJECT_BALL_PIT: 'CommonGameTag' = 2928 + FUNC_TODDLER_GYM_OBJECT_FULL: 'CommonGameTag' = 1727 + FUNC_TODDLER_GYM_OBJECT_SLIDE: 'CommonGameTag' = 1726 + FUNC_TODDLER_GYM_OBJECT_SLIDE_CLIMBER: 'CommonGameTag' = 2929 + FUNC_TODDLER_GYM_OBJECT_TUNNELS: 'CommonGameTag' = 2930 + FUNC_TODDLER_JUNGLE_GYM_OBJECT: 'CommonGameTag' = 73729 + FUNC_TODDLER_PERSONALITY_PICKY_EATER_MIXED_FOOD: 'CommonGameTag' = 2933 + FUNC_TODDLER_SEATING: 'CommonGameTag' = 1676 + FUNC_TODDLER_SLIDE: 'CommonGameTag' = 2935 + FUNC_TODDLER_TOY_BOX: 'CommonGameTag' = 1665 + FUNC_TOILET: 'CommonGameTag' = 1881 + FUNC_TOILET_TALKING: 'CommonGameTag' = 55311 + FUNC_TOMB: 'CommonGameTag' = 1202 + FUNC_TOMBSTONE: 'CommonGameTag' = 1199 + FUNC_TOWEL: 'CommonGameTag' = 1147 + FUNC_TOY: 'CommonGameTag' = 505 + FUNC_TOY_BOX: 'CommonGameTag' = 1018 + FUNC_TOY_BOX_PURCHASE: 'CommonGameTag' = 1646 + FUNC_TOY_BOX_TOYS_TO_CLEAN_UP: 'CommonGameTag' = 533 + FUNC_TOY_ROBOT: 'CommonGameTag' = 65625 + FUNC_TRASH: 'CommonGameTag' = 581 + FUNC_TRASHCAN_DIAPER_PAIL: 'CommonGameTag' = 2916 + FUNC_TRASHCAN_INDOOR_LIDDED: 'CommonGameTag' = 2951 + FUNC_TRASH_CAN: 'CommonGameTag' = 891 + FUNC_TRASH_CAN_HI_TECH: 'CommonGameTag' = 2443 + FUNC_TRASH_CAN_INDOOR: 'CommonGameTag' = 2349 + FUNC_TRASH_CAN_OUTDOOR: 'CommonGameTag' = 892 + FUNC_TRASH_PILE: 'CommonGameTag' = 568 + FUNC_TRASH_PILE_COMPOSTABLE: 'CommonGameTag' = 2335 + FUNC_TRASH_PILE_RECYCLABLE: 'CommonGameTag' = 2334 + FUNC_TREADMILL: 'CommonGameTag' = 478 + FUNC_TREASURE: 'CommonGameTag' = 63510 + FUNC_TREASURE_CHEST: 'CommonGameTag' = 45113 + FUNC_TREE: 'CommonGameTag' = 1332 + FUNC_TREEHOUSE: 'CommonGameTag' = 116752 + FUNC_TREEHOUSE_BASE: 'CommonGameTag' = 116743 + FUNC_TREEHOUSE_BELL: 'CommonGameTag' = 116746 + FUNC_TREEHOUSE_COMPATIBLE: 'CommonGameTag' = 116750 + FUNC_TREEHOUSE_LIGHTS: 'CommonGameTag' = 116753 + FUNC_TREEHOUSE_POLE: 'CommonGameTag' = 116745 + FUNC_TREEHOUSE_SLIDE: 'CommonGameTag' = 116744 + FUNC_TREND_CELEBRITY: 'CommonGameTag' = 61638 + FUNC_TREND_PRODUCT_REVIEW_BEAUTY: 'CommonGameTag' = 61547 + FUNC_TREND_PRODUCT_REVIEW_TECH: 'CommonGameTag' = 61548 + FUNC_TREND_PRODUCT_REVIEW_TOY: 'CommonGameTag' = 61549 + FUNC_TREND_SKILL_ACTING: 'CommonGameTag' = 61635 + FUNC_TREND_SKILL_ARCHAEOLOGY: 'CommonGameTag' = 61501 + FUNC_TREND_SKILL_BAKING: 'CommonGameTag' = 61502 + FUNC_TREND_SKILL_BOWLING: 'CommonGameTag' = 61503 + FUNC_TREND_SKILL_CHARISMA: 'CommonGameTag' = 61504 + FUNC_TREND_SKILL_COMEDY: 'CommonGameTag' = 61505 + FUNC_TREND_SKILL_COOKING_GOURMET: 'CommonGameTag' = 61506 + FUNC_TREND_SKILL_COOKING_HOME_STYLE: 'CommonGameTag' = 61507 + FUNC_TREND_SKILL_DANCING: 'CommonGameTag' = 61508 + FUNC_TREND_SKILL_DJ_MIXING: 'CommonGameTag' = 61509 + FUNC_TREND_SKILL_FISHING: 'CommonGameTag' = 61510 + FUNC_TREND_SKILL_FITNESS: 'CommonGameTag' = 61511 + FUNC_TREND_SKILL_FLOWER_ARRANGING: 'CommonGameTag' = 2750 + FUNC_TREND_SKILL_GARDENING: 'CommonGameTag' = 61513 + FUNC_TREND_SKILL_GUITAR: 'CommonGameTag' = 61514 + FUNC_TREND_SKILL_HANDINESS: 'CommonGameTag' = 61515 + FUNC_TREND_SKILL_HERBALISM: 'CommonGameTag' = 61516 + FUNC_TREND_SKILL_JUICE_FIZZING: 'CommonGameTag' = 67619 + FUNC_TREND_SKILL_KNIT: 'CommonGameTag' = 2460 + FUNC_TREND_SKILL_KNITTING: 'CommonGameTag' = 83970 + FUNC_TREND_SKILL_LOCAL_CULTURE: 'CommonGameTag' = 61517 + FUNC_TREND_SKILL_LOGIC: 'CommonGameTag' = 61518 + FUNC_TREND_SKILL_MEDIA_PRODUCTION: 'CommonGameTag' = 61630 + FUNC_TREND_SKILL_MISCHIEF: 'CommonGameTag' = 61519 + FUNC_TREND_SKILL_MIXOLOGY: 'CommonGameTag' = 61520 + FUNC_TREND_SKILL_PAINTING: 'CommonGameTag' = 61521 + FUNC_TREND_SKILL_PARENTING: 'CommonGameTag' = 61522 + FUNC_TREND_SKILL_PET_TRAINING: 'CommonGameTag' = 61523 + FUNC_TREND_SKILL_PHOTOGRAPHY: 'CommonGameTag' = 61524 + FUNC_TREND_SKILL_PIANO: 'CommonGameTag' = 61525 + FUNC_TREND_SKILL_PIPE_ORGAN: 'CommonGameTag' = 61526 + FUNC_TREND_SKILL_PROGRAMMING: 'CommonGameTag' = 61527 + FUNC_TREND_SKILL_ROBOTICS: 'CommonGameTag' = 65632 + FUNC_TREND_SKILL_ROCKET_SCIENCE: 'CommonGameTag' = 61631 + FUNC_TREND_SKILL_SINGING: 'CommonGameTag' = 61528 + FUNC_TREND_SKILL_VAMPIRE_LORE: 'CommonGameTag' = 61529 + FUNC_TREND_SKILL_VETERINARIAN: 'CommonGameTag' = 61530 + FUNC_TREND_SKILL_VIDEO_GAMING: 'CommonGameTag' = 61531 + FUNC_TREND_SKILL_VIOLIN: 'CommonGameTag' = 61532 + FUNC_TREND_SKILL_WELLNESS: 'CommonGameTag' = 61533 + FUNC_TREND_SKILL_WRITING: 'CommonGameTag' = 61534 + FUNC_TREND_TIPS_BEAUTY: 'CommonGameTag' = 61545 + FUNC_TREND_TIPS_FASHION: 'CommonGameTag' = 61546 + FUNC_TREND_TODDLER_CHILD: 'CommonGameTag' = 61550 + FUNC_TREND_TRAVEL: 'CommonGameTag' = 61551 + FUNC_TREND_VLOG_ANGRY: 'CommonGameTag' = 61535 + FUNC_TREND_VLOG_CONFIDENT: 'CommonGameTag' = 61536 + FUNC_TREND_VLOG_DAZED: 'CommonGameTag' = 61537 + FUNC_TREND_VLOG_EMBARRASSED: 'CommonGameTag' = 61538 + FUNC_TREND_VLOG_ENERGIZED: 'CommonGameTag' = 61539 + FUNC_TREND_VLOG_FLIRTY: 'CommonGameTag' = 61540 + FUNC_TREND_VLOG_FOCUSED: 'CommonGameTag' = 61610 + FUNC_TREND_VLOG_HAPPY: 'CommonGameTag' = 61541 + FUNC_TREND_VLOG_INSPIRED: 'CommonGameTag' = 61542 + FUNC_TREND_VLOG_PLAYFUL: 'CommonGameTag' = 61543 + FUNC_TREND_VLOG_SAD: 'CommonGameTag' = 61544 + FUNC_TRIANGLE: 'CommonGameTag' = 1424 + FUNC_TRIM: 'CommonGameTag' = 1135 + FUNC_TRUNK: 'CommonGameTag' = 1292 + FUNC_TURTLE: 'CommonGameTag' = 1241 + FUNC_TV: 'CommonGameTag' = 471 + FUNC_TV_STAND_SEARCH: 'CommonGameTag' = 2243 + FUNC_TWIST: 'CommonGameTag' = 8215 + FUNC_UMBRELLA: 'CommonGameTag' = 59430 + FUNC_UMBRELLA_ADULT: 'CommonGameTag' = 59443 + FUNC_UMBRELLA_CHILD: 'CommonGameTag' = 59444 + FUNC_UMBRELLA_RACK: 'CommonGameTag' = 59441 + FUNC_UMBRELLA_TABLE: 'CommonGameTag' = 1553 + FUNC_UMBRELLA_USER: 'CommonGameTag' = 2118 + FUNC_UNBREAKABLE_OBJECT: 'CommonGameTag' = 1172 + FUNC_UNICORN: 'CommonGameTag' = 507 + FUNC_UNIVERSITY_HOUSING_BED: 'CommonGameTag' = 65626 + FUNC_UNIVERSITY_KIOSK_ACADEMIC: 'CommonGameTag' = 65575 + FUNC_UNIVERSITY_KIOSK_DECO_SURFACE: 'CommonGameTag' = 65574 + FUNC_UNIVERSITY_KIOSK_DECO_WALL: 'CommonGameTag' = 65573 + FUNC_UNIVERSITY_KIOSK_DECO_WALL_ST: 'CommonGameTag' = 65615 + FUNC_UNIVERSITY_KIOSK_ITEM: 'CommonGameTag' = 65564 + FUNC_UNIVERSITY_KIOSK_ITEM_ST: 'CommonGameTag' = 65614 + FUNC_UNIVERSITY_TEXT_BOOK: 'CommonGameTag' = 2235 + FUNC_UNUSED_USE_ME: 'CommonGameTag' = 2175 + FUNC_UNUSED_USE_ME_2: 'CommonGameTag' = 2228 + FUNC_URN: 'CommonGameTag' = 1076 + FUNC_URNSTONE: 'CommonGameTag' = 814 + FUNC_USE_SLOTTING_SOUND_OVERRIDE: 'CommonGameTag' = 2552 + FUNC_VACUUM_CLEANER: 'CommonGameTag' = 94210 + FUNC_VACUUM_CLEANER_HANDHELD: 'CommonGameTag' = 94211 + FUNC_VACUUM_CLEANER_HIGH: 'CommonGameTag' = 94218 + FUNC_VACUUM_CLEANER_LOW: 'CommonGameTag' = 94226 + FUNC_VACUUM_CLEANER_MED: 'CommonGameTag' = 94219 + FUNC_VACUUM_CLEANER_UPRIGHT: 'CommonGameTag' = 94212 + FUNC_VACUUM_HEIGHT_FLOOR: 'CommonGameTag' = 94220 + FUNC_VACUUM_HEIGHT_HIGH: 'CommonGameTag' = 94223 + FUNC_VACUUM_HEIGHT_LOW: 'CommonGameTag' = 94221 + FUNC_VACUUM_HEIGHT_MEDIUM: 'CommonGameTag' = 94222 + FUNC_VALENTINES_DAY: 'CommonGameTag' = 1370 + FUNC_VAMPIRE_TOME: 'CommonGameTag' = 40961 + FUNC_VAMPIRE_TOME_SET_1: 'CommonGameTag' = 40974 + FUNC_VAMPIRE_TOME_SET_2: 'CommonGameTag' = 40975 + FUNC_VAMPIRE_TOME_SET_3: 'CommonGameTag' = 40976 + FUNC_VAMPIRE_TOME_ULTIMATE: 'CommonGameTag' = 40977 + FUNC_VANITY_TABLE: 'CommonGameTag' = 36866 + FUNC_VASE: 'CommonGameTag' = 1145 + FUNC_VAULT_DOOR: 'CommonGameTag' = 61472 + FUNC_VAULT_SAFE: 'CommonGameTag' = 61471 + FUNC_VEHICLE: 'CommonGameTag' = 2226 + FUNC_VEHICLE_BIKE: 'CommonGameTag' = 2227 + FUNC_VEHICLE_BIKE_CHILD: 'CommonGameTag' = 2936 + FUNC_VEHICLE_BIKE_HORN: 'CommonGameTag' = 2937 + FUNC_VEHICLE_BIKE_TYAE: 'CommonGameTag' = 2938 + FUNC_VEHICLE_LAND: 'CommonGameTag' = 2231 + FUNC_VEHICLE_WATER: 'CommonGameTag' = 2232 + FUNC_VENDING_MACHINE_COLD_DRINK_AND_SNACK_ENERGY_EP10: 'CommonGameTag' = 69672 + FUNC_VENDING_MACHINE_COLD_DRINK_AND_SNACK_FOOD_EP10: 'CommonGameTag' = 69671 + FUNC_VENDING_MACHINE_COLD_DRINK_AND_SNACK_FRUIT_EP10: 'CommonGameTag' = 69673 + FUNC_VENDING_MACHINE_HOT_FOOD_AND_DRINK_ENERGY_EP10: 'CommonGameTag' = 69670 + FUNC_VENDING_MACHINE_HOT_FOOD_AND_DRINK_FOOD_EP10: 'CommonGameTag' = 69669 + FUNC_VENUE_NOT_DESTROYABLE_BY_CLEAN_UP: 'CommonGameTag' = 2013 + FUNC_VENUE_NOT_UNBROKEN_BY_CLEAN_UP: 'CommonGameTag' = 2509 + FUNC_VERTICAL_GARDEN: 'CommonGameTag' = 67618 + FUNC_VET: 'CommonGameTag' = 57378 + FUNC_VET_EXAM_TABLE: 'CommonGameTag' = 57375 + FUNC_VET_MEDICINE_STATION: 'CommonGameTag' = 57428 + FUNC_VET_PODIUM: 'CommonGameTag' = 57374 + FUNC_VET_SURGERY_STATION: 'CommonGameTag' = 57390 + FUNC_VET_VENDING_MACHINE: 'CommonGameTag' = 57430 + FUNC_VFX_MACHINE_CONTROL_DESK: 'CommonGameTag' = 61479 + FUNC_VFX_MACHINE_EMITTER: 'CommonGameTag' = 61468 + FUNC_VIDEO_GAME: 'CommonGameTag' = 1644 + FUNC_VIDEO_GAME_2: 'CommonGameTag' = 479 + FUNC_VIDEO_GAME_CONSOLE_DISPLAY: 'CommonGameTag' = 55368 + FUNC_VIDEO_GAMING: 'CommonGameTag' = 24596 + FUNC_VIDEO_RECORDING: 'CommonGameTag' = 61474 + FUNC_VIDEO_RECORDING_BG: 'CommonGameTag' = 2189 + FUNC_VIDEO_STATION: 'CommonGameTag' = 61473 + FUNC_VILLAGE_FAIR_COMPETITION_STAND: 'CommonGameTag' = 112665 + FUNC_VILLAGE_FAIR_COMPETITION_STAND_A: 'CommonGameTag' = 112667 + FUNC_VILLAGE_FAIR_COMPETITION_STAND_B: 'CommonGameTag' = 112668 + FUNC_VILLAGE_FAIR_NPC_CHICKEN: 'CommonGameTag' = 112689 + FUNC_VILLAGE_SHOPS_CAT_ANIMAL: 'CommonGameTag' = 2655 + FUNC_VILLAGE_SHOPS_CAT_BOOKS: 'CommonGameTag' = 2656 + FUNC_VILLAGE_SHOPS_CAT_FISH: 'CommonGameTag' = 2657 + FUNC_VILLAGE_SHOPS_CAT_FLOWERS: 'CommonGameTag' = 2658 + FUNC_VILLAGE_SHOPS_CAT_FRUIT: 'CommonGameTag' = 2659 + FUNC_VILLAGE_SHOPS_CAT_GARDEN_INGREDIENTS: 'CommonGameTag' = 2660 + FUNC_VILLAGE_SHOPS_CAT_GROCERY_INGREDIENTS: 'CommonGameTag' = 2661 + FUNC_VILLAGE_SHOPS_CAT_MISC: 'CommonGameTag' = 2662 + FUNC_VILLAGE_SHOPS_CAT_SEEDS: 'CommonGameTag' = 2663 + FUNC_VILLAGE_SHOPS_CAT_SPECIAL: 'CommonGameTag' = 2664 + FUNC_VILLAGE_SHOPS_CAT_VEGETABLES: 'CommonGameTag' = 2665 + FUNC_VILLAGE_SHOPS_SELLABLE: 'CommonGameTag' = 2583 + FUNC_VILLAGE_SIGN: 'CommonGameTag' = 112688 + FUNC_VILLAIN: 'CommonGameTag' = 1128 + FUNC_VIOLIN: 'CommonGameTag' = 569 + FUNC_VIOLIN_ADULT: 'CommonGameTag' = 1635 + FUNC_VIP_ROPE: 'CommonGameTag' = 61477 + FUNC_VOCAL: 'CommonGameTag' = 490 + FUNC_VOODOO: 'CommonGameTag' = 582 + FUNC_WAINSCOTING: 'CommonGameTag' = 1085 + FUNC_WAITER_STATION: 'CommonGameTag' = 26626 + FUNC_WALL_LAMP: 'CommonGameTag' = 1112 + FUNC_WALL_TEST_LINE_OF_SIGHT: 'CommonGameTag' = 2029 + FUNC_WANDS: 'CommonGameTag' = 49173 + FUNC_WARDROBE_PEDESTAL: 'CommonGameTag' = 61441 + FUNC_WARMING_RACK: 'CommonGameTag' = 12375 + FUNC_WATER_SCOOTER: 'CommonGameTag' = 63490 + FUNC_WATER_SCOOTER_BEACH_VENUE: 'CommonGameTag' = 2197 + FUNC_WATER_TROUGH: 'CommonGameTag' = 118877 + FUNC_WAX_BLOCK: 'CommonGameTag' = 67630 + FUNC_WEB: 'CommonGameTag' = 1191 + FUNC_WEDDING_AISLE: 'CommonGameTag' = 2756 + FUNC_WEDDING_AISLE_LONG: 'CommonGameTag' = 2772 + FUNC_WEDDING_AISLE_MEDIUM: 'CommonGameTag' = 2771 + FUNC_WEDDING_AISLE_SHORT: 'CommonGameTag' = 2770 + FUNC_WEDDING_ARCH: 'CommonGameTag' = 2747 + FUNC_WEDDING_BOUQUET: 'CommonGameTag' = 2751 + FUNC_WEDDING_CAKE_CUPCAKE_TOWER: 'CommonGameTag' = 133128 + FUNC_WEDDING_CAKE_CYLINDER: 'CommonGameTag' = 133129 + FUNC_WEDDING_CAKE_CYLINDER_3D: 'CommonGameTag' = 133130 + FUNC_WEDDING_CAKE_CYLINDER_BEACHY: 'CommonGameTag' = 133131 + FUNC_WEDDING_CAKE_CYLINDER_FLORAL: 'CommonGameTag' = 133132 + FUNC_WEDDING_CAKE_HEART: 'CommonGameTag' = 133133 + FUNC_WEDDING_CAKE_HEXAGON: 'CommonGameTag' = 133134 + FUNC_WEDDING_CAKE_LARGE_ANIM: 'CommonGameTag' = 2758 + FUNC_WEDDING_CAKE_PILLOW: 'CommonGameTag' = 133135 + FUNC_WEDDING_CAKE_PROP_CHOCOLATE: 'CommonGameTag' = 2760 + FUNC_WEDDING_CAKE_PROP_RED_VELVET: 'CommonGameTag' = 2762 + FUNC_WEDDING_CAKE_PROP_VANILLA: 'CommonGameTag' = 2761 + FUNC_WEDDING_CAKE_SQUARE: 'CommonGameTag' = 133136 + FUNC_WEDDING_CAKE_TOPPER: 'CommonGameTag' = 2757 + FUNC_WEDDING_CAKE_TOPPER_COW_PLANT: 'CommonGameTag' = 133137 + FUNC_WEDDING_CAKE_TOPPER_CUT_OUT: 'CommonGameTag' = 133138 + FUNC_WEDDING_CAKE_TOPPER_FIGURES: 'CommonGameTag' = 133139 + FUNC_WEDDING_CAKE_TOPPER_FLORAL_ROSE: 'CommonGameTag' = 133140 + FUNC_WEDDING_CAKE_TOPPER_FLORAL_TROPICAL: 'CommonGameTag' = 133141 + FUNC_WEDDING_CAKE_TOPPER_HEARTS: 'CommonGameTag' = 133142 + FUNC_WEDDING_CAKE_TOPPER_LETTERING: 'CommonGameTag' = 133143 + FUNC_WEDDING_CAKE_TOPPER_PENNANTS: 'CommonGameTag' = 133144 + FUNC_WEDDING_CAKE_TOPPER_RAINBOW: 'CommonGameTag' = 133145 + FUNC_WEDDING_CAKE_TOPPER_STARS: 'CommonGameTag' = 133146 + FUNC_WELLNESS: 'CommonGameTag' = 18453 + FUNC_WELLNESS_MONEY: 'CommonGameTag' = 2793 + FUNC_WEREWOLF: 'CommonGameTag' = 1215 + FUNC_WEREWOLF_CANNOT_DEVOUR: 'CommonGameTag' = 2794 + FUNC_WEREWOLF_PACK_ACCEPTABLE_GIFT: 'CommonGameTag' = 2786 + FUNC_WFS: 'CommonGameTag' = 61480 + FUNC_WFS_PRE_MADE_CELEBRITY: 'CommonGameTag' = 61612 + FUNC_WHIRLPOOL_TUB: 'CommonGameTag' = 882 + FUNC_WILDERNESS: 'CommonGameTag' = 1279 + FUNC_WILDLIFE_ENCOUNTER_DETERRENT: 'CommonGameTag' = 69665 + FUNC_WILDLIFE_ENCOUNTER_REMEDY: 'CommonGameTag' = 69666 + FUNC_WILD_GRASS: 'CommonGameTag' = 118789 + FUNC_WILD_GRASS_SYSTEM_SPAWNED: 'CommonGameTag' = 118788 + FUNC_WIND_CHIMES: 'CommonGameTag' = 34819 + FUNC_WIND_TURBINE: 'CommonGameTag' = 67614 + FUNC_WIND_TURBINE_UPGRADED_LIGHTNING_ROD: 'CommonGameTag' = 2437 + FUNC_WISHING_WELL: 'CommonGameTag' = 30722 + FUNC_WITCH: 'CommonGameTag' = 1218 + FUNC_WOLF_TOWN_GREG_SIGN: 'CommonGameTag' = 135185 + FUNC_WOLF_TOWN_PORTAL_HOWL_SPOT_BOTTOM: 'CommonGameTag' = 135171 + FUNC_WOLF_TOWN_PORTAL_HOWL_SPOT_TOP: 'CommonGameTag' = 135172 + FUNC_WOLF_TOWN_PORTAL_MINE: 'CommonGameTag' = 135173 + FUNC_WOLF_TOWN_PORTAL_ON_LOT_VERSION: 'CommonGameTag' = 135176 + FUNC_WOLF_TOWN_PORTAL_PORTA_POTTY: 'CommonGameTag' = 135174 + FUNC_WOLF_TOWN_PORTAL_SEWER: 'CommonGameTag' = 135175 + FUNC_WOLF_TOWN_SHELL_PACK_A: 'CommonGameTag' = 135169 + FUNC_WOLF_TOWN_SHELL_PACK_B: 'CommonGameTag' = 135170 + FUNC_WOOD: 'CommonGameTag' = 1319 + FUNC_WOODWORKING: 'CommonGameTag' = 1462 + FUNC_WOOL: 'CommonGameTag' = 2578 + FUNC_WOOL_SEARCH: 'CommonGameTag' = 112686 + FUNC_WORKBENCH: 'CommonGameTag' = 493 + FUNC_WORKOUT: 'CommonGameTag' = 472 + FUNC_WORKOUT_MACHINE: 'CommonGameTag' = 1324 + FUNC_WRITER: 'CommonGameTag' = 1117 + FUNC_WRITING: 'CommonGameTag' = 1106 + FUNC_XMAS: 'CommonGameTag' = 1331 + FUNC_YARNY: 'CommonGameTag' = 83971 + FUNC_YARNY_STATUE: 'CommonGameTag' = 83991 + FUNC_YARN_BASKET: 'CommonGameTag' = 2625 + FUNC_YOGA: 'CommonGameTag' = 18458 + FUNC_YOGA_CLASS_INSTRUCTOR_MAT: 'CommonGameTag' = 18447 + FUNC_YOGA_CLASS_MEMBER_MAT: 'CommonGameTag' = 18448 + FUNC_YOGA_CLASS_MEMBER_TEMP_MAT: 'CommonGameTag' = 18449 + FUNC_YOGA_MAT: 'CommonGameTag' = 18433 + FUR_CHOW: 'CommonGameTag' = 57356 + FUR_COLLIE: 'CommonGameTag' = 57364 + FUR_LENGTH_HAIRLESS: 'CommonGameTag' = 2018 + FUR_LENGTH_LONG_HAIR: 'CommonGameTag' = 2017 + FUR_LENGTH_SHORT_HAIR: 'CommonGameTag' = 2016 + FUR_MEDIUM_SMOOTH: 'CommonGameTag' = 57357 + FUR_MEDIUM_WIRY: 'CommonGameTag' = 57366 + FUR_POODLE: 'CommonGameTag' = 57358 + FUR_RETRIEVER: 'CommonGameTag' = 57359 + FUR_SPANIEL: 'CommonGameTag' = 57365 + GENDER_APPROPRIATE_FEMALE: 'CommonGameTag' = 1530 + GENDER_APPROPRIATE_MALE: 'CommonGameTag' = 1529 + GENRE_ACTIVITY_TABLE_DINO: 'CommonGameTag' = 877 + GENRE_ACTIVITY_TABLE_FAMILY: 'CommonGameTag' = 878 + GENRE_ACTIVITY_TABLE_HORSE: 'CommonGameTag' = 879 + GENRE_ACTIVITY_TABLE_SHAPES: 'CommonGameTag' = 880 + GENRE_ACTIVITY_TABLE_TRUCK: 'CommonGameTag' = 881 + GENRE_BOOK_BIOGRAPHY: 'CommonGameTag' = 768 + GENRE_BOOK_CHILDRENS: 'CommonGameTag' = 769 + GENRE_BOOK_EMOTIONAL: 'CommonGameTag' = 980 + GENRE_BOOK_EMOTION_CONFIDENT: 'CommonGameTag' = 790 + GENRE_BOOK_EMOTION_ENERGIZED: 'CommonGameTag' = 791 + GENRE_BOOK_EMOTION_FLIRTY: 'CommonGameTag' = 792 + GENRE_BOOK_EMOTION_FOCUSED: 'CommonGameTag' = 1038 + GENRE_BOOK_EMOTION_INSPIRED: 'CommonGameTag' = 1039 + GENRE_BOOK_EMOTION_PLAYFUL: 'CommonGameTag' = 793 + GENRE_BOOK_EMOTION_SAD: 'CommonGameTag' = 794 + GENRE_BOOK_FANTASY: 'CommonGameTag' = 770 + GENRE_BOOK_MAGIC: 'CommonGameTag' = 2224 + GENRE_BOOK_MYSTERY_THRILLER: 'CommonGameTag' = 866 + GENRE_BOOK_NON_FICTION: 'CommonGameTag' = 771 + GENRE_BOOK_POEMS: 'CommonGameTag' = 772 + GENRE_BOOK_ROMANCE: 'CommonGameTag' = 773 + GENRE_BOOK_SCI_FI: 'CommonGameTag' = 774 + GENRE_BOOK_SCREEN_PLAY: 'CommonGameTag' = 775 + GENRE_BOOK_SHORT_STORIES: 'CommonGameTag' = 776 + GENRE_BOOK_SKILL: 'CommonGameTag' = 1032 + GENRE_BOOK_SKILL_ACTING: 'CommonGameTag' = 61493 + GENRE_BOOK_SKILL_ARCHAEOLOGY: 'CommonGameTag' = 45069 + GENRE_BOOK_SKILL_BARTENDING: 'CommonGameTag' = 797 + GENRE_BOOK_SKILL_CHARISMA: 'CommonGameTag' = 798 + GENRE_BOOK_SKILL_COMEDY: 'CommonGameTag' = 799 + GENRE_BOOK_SKILL_COOKING: 'CommonGameTag' = 800 + GENRE_BOOK_SKILL_EQUESTRIAN_SKILL: 'CommonGameTag' = 2981 + GENRE_BOOK_SKILL_FABRICATION: 'CommonGameTag' = 67621 + GENRE_BOOK_SKILL_FISHING: 'CommonGameTag' = 921 + GENRE_BOOK_SKILL_FITNESS: 'CommonGameTag' = 810 + GENRE_BOOK_SKILL_GARDENING: 'CommonGameTag' = 801 + GENRE_BOOK_SKILL_GOURMET: 'CommonGameTag' = 802 + GENRE_BOOK_SKILL_GUITAR: 'CommonGameTag' = 803 + GENRE_BOOK_SKILL_HACKING: 'CommonGameTag' = 804 + GENRE_BOOK_SKILL_HANDINESS: 'CommonGameTag' = 805 + GENRE_BOOK_SKILL_HERBALISM: 'CommonGameTag' = 10256 + GENRE_BOOK_SKILL_KNITTING: 'CommonGameTag' = 2766 + GENRE_BOOK_SKILL_LOGIC: 'CommonGameTag' = 806 + GENRE_BOOK_SKILL_MISCHIEF: 'CommonGameTag' = 807 + GENRE_BOOK_SKILL_PAINTING: 'CommonGameTag' = 808 + GENRE_BOOK_SKILL_PARENTING: 'CommonGameTag' = 43012 + GENRE_BOOK_SKILL_PIANO: 'CommonGameTag' = 809 + GENRE_BOOK_SKILL_RESEARCH_DEBATE: 'CommonGameTag' = 2246 + GENRE_BOOK_SKILL_ROBOTICS: 'CommonGameTag' = 65623 + GENRE_BOOK_SKILL_ROCKET_SCIENCE: 'CommonGameTag' = 811 + GENRE_BOOK_SKILL_VIDEO_GAMING: 'CommonGameTag' = 812 + GENRE_BOOK_SKILL_VIOLIN: 'CommonGameTag' = 813 + GENRE_BOOK_SKILL_WELLNESS: 'CommonGameTag' = 18483 + GENRE_BOOK_SKILL_WOO_HOO: 'CommonGameTag' = 865 + GENRE_BOOK_SKILL_WRITING: 'CommonGameTag' = 818 + GENRE_BOOK_SUPERNATURAL: 'CommonGameTag' = 819 + GENRE_BOOK_TODDLER_PICTURE_BOOK: 'CommonGameTag' = 1656 + GENRE_BOOK_TRAVEL_GUIDE: 'CommonGameTag' = 45071 + GENRE_PAINTING_ABSTRACT: 'CommonGameTag' = 667 + GENRE_PAINTING_CLASSICS: 'CommonGameTag' = 669 + GENRE_PAINTING_IMPRESSIONISM: 'CommonGameTag' = 670 + GENRE_PAINTING_LANDSCAPE: 'CommonGameTag' = 10260 + GENRE_PAINTING_MATHEMATICS: 'CommonGameTag' = 671 + GENRE_PAINTING_POP_ART: 'CommonGameTag' = 672 + GENRE_PAINTING_REALISM: 'CommonGameTag' = 673 + GENRE_PAINTING_SURREALISM: 'CommonGameTag' = 674 + GP09: 'CommonGameTag' = 51270 + GROUP_PHOTO_X_ACTOR: 'CommonGameTag' = 1436 + GROUP_PHOTO_Y_ACTOR: 'CommonGameTag' = 1437 + GROUP_PHOTO_Z_ACTOR: 'CommonGameTag' = 2217 + GROWTH_LEVEL_HAIR_0: 'CommonGameTag' = 2810 + GROWTH_LEVEL_HAIR_1: 'CommonGameTag' = 2811 + GROWTH_LEVEL_HAIR_2: 'CommonGameTag' = 2812 + GROWTH_LEVEL_HAIR_3: 'CommonGameTag' = 2813 + GROWTH_TYPE_FACIAL_HAIR_BEARD: 'CommonGameTag' = 2817 + GROWTH_TYPE_FACIAL_HAIR_CHIN_STRAP: 'CommonGameTag' = 2818 + GROWTH_TYPE_FACIAL_HAIR_GOATEE: 'CommonGameTag' = 2820 + GROWTH_TYPE_FACIAL_HAIR_MUSTACHE: 'CommonGameTag' = 2819 + GROWTH_TYPE_FACIAL_HAIR_SOUL_PATCH: 'CommonGameTag' = 2821 + GROWTH_TYPE_HAIR_ARMS: 'CommonGameTag' = 2814 + GROWTH_TYPE_HAIR_LEGS: 'CommonGameTag' = 2815 + GROWTH_TYPE_HAIR_TORSO: 'CommonGameTag' = 2816 + GROWTH_TYPE_HAIR_TORSO_BACK: 'CommonGameTag' = 114735 + GROWTH_TYPE_HAIR_TORSO_BELLY: 'CommonGameTag' = 114734 + GROWTH_TYPE_HAIR_TORSO_CHEST: 'CommonGameTag' = 114733 + HAIR_COLOR_AUBURN: 'CommonGameTag' = 896 + HAIR_COLOR_BAY_ROAN: 'CommonGameTag' = 118833 + HAIR_COLOR_BLACK: 'CommonGameTag' = 131 + HAIR_COLOR_BLACK_SALT_AND_PEPPER: 'CommonGameTag' = 897 + HAIR_COLOR_BLONDE: 'CommonGameTag' = 94 + HAIR_COLOR_BROWN: 'CommonGameTag' = 132 + HAIR_COLOR_BROWN_DUN: 'CommonGameTag' = 118834 + HAIR_COLOR_BROWN_SALT_AND_PEPPER: 'CommonGameTag' = 898 + HAIR_COLOR_BUCK_SKIN: 'CommonGameTag' = 118835 + HAIR_COLOR_CHESTNUT: 'CommonGameTag' = 118836 + HAIR_COLOR_CREMELLO: 'CommonGameTag' = 118837 + HAIR_COLOR_DARK_BAY: 'CommonGameTag' = 118838 + HAIR_COLOR_DARK_BLUE: 'CommonGameTag' = 899 + HAIR_COLOR_DARK_BROWN: 'CommonGameTag' = 133 + HAIR_COLOR_DARK_GRAY: 'CommonGameTag' = 118839 + HAIR_COLOR_DARK_GRAY_COOL: 'CommonGameTag' = 118840 + HAIR_COLOR_DARK_GRAY_WARM: 'CommonGameTag' = 118841 + HAIR_COLOR_DIRTY_BLOND: 'CommonGameTag' = 900 + HAIR_COLOR_GOLD: 'CommonGameTag' = 118842 + HAIR_COLOR_GRAY: 'CommonGameTag' = 134 + HAIR_COLOR_GRAY_WARM: 'CommonGameTag' = 118843 + HAIR_COLOR_GREEN: 'CommonGameTag' = 901 + HAIR_COLOR_HOT_PINK: 'CommonGameTag' = 902 + HAIR_COLOR_LIGHT_BAY: 'CommonGameTag' = 118844 + HAIR_COLOR_LIGHT_BLONDE: 'CommonGameTag' = 2532 + HAIR_COLOR_LIGHT_BROWN: 'CommonGameTag' = 2530 + HAIR_COLOR_LIGHT_CHESTNUT: 'CommonGameTag' = 118845 + HAIR_COLOR_LIGHT_GRAY_COOL: 'CommonGameTag' = 118846 + HAIR_COLOR_LIGHT_GRAY_WARM: 'CommonGameTag' = 118847 + HAIR_COLOR_LIVER_CHESTNUT: 'CommonGameTag' = 118848 + HAIR_COLOR_MOUSE_DUN: 'CommonGameTag' = 118849 + HAIR_COLOR_NEUTRAL_BLACK: 'CommonGameTag' = 2528 + HAIR_COLOR_NEUTRAL_BLONDE: 'CommonGameTag' = 2531 + HAIR_COLOR_ORANGE: 'CommonGameTag' = 135 + HAIR_COLOR_PALOMINO: 'CommonGameTag' = 118850 + HAIR_COLOR_PASTEL_BLUE: 'CommonGameTag' = 118851 + HAIR_COLOR_PASTEL_GREEN: 'CommonGameTag' = 118852 + HAIR_COLOR_PASTEL_HOT_PINK: 'CommonGameTag' = 118853 + HAIR_COLOR_PASTEL_ORANGE: 'CommonGameTag' = 118854 + HAIR_COLOR_PASTEL_PINK: 'CommonGameTag' = 118855 + HAIR_COLOR_PASTEL_PURPLE: 'CommonGameTag' = 118856 + HAIR_COLOR_PASTEL_RED: 'CommonGameTag' = 118857 + HAIR_COLOR_PASTEL_TURQUOISE: 'CommonGameTag' = 118858 + HAIR_COLOR_PASTEL_YELLOW: 'CommonGameTag' = 118859 + HAIR_COLOR_PLATINUM: 'CommonGameTag' = 96 + HAIR_COLOR_PURPLE_PASTEL: 'CommonGameTag' = 903 + HAIR_COLOR_RED: 'CommonGameTag' = 136 + HAIR_COLOR_RED_DUN: 'CommonGameTag' = 118860 + HAIR_COLOR_RED_ROAN: 'CommonGameTag' = 118861 + HAIR_COLOR_ROSE_GRAY: 'CommonGameTag' = 118864 + HAIR_COLOR_SEAL_BROWN: 'CommonGameTag' = 118862 + HAIR_COLOR_TURQUOISE: 'CommonGameTag' = 904 + HAIR_COLOR_WARM_BROWN: 'CommonGameTag' = 2529 + HAIR_COLOR_WHITE: 'CommonGameTag' = 905 + HAIR_COLOR_WHITE_BLONDE: 'CommonGameTag' = 2533 + HAIR_COLOR_YELLOW_DUN: 'CommonGameTag' = 118863 + HAIR_CURLY: 'CommonGameTag' = 314 + HAIR_LENGTH_LONG: 'CommonGameTag' = 664 + HAIR_LENGTH_MEDIUM: 'CommonGameTag' = 820 + HAIR_LENGTH_SHORT: 'CommonGameTag' = 662 + HAIR_LENGTH_UPDO: 'CommonGameTag' = 2173 + HAIR_LONG: 'CommonGameTag' = 151 + HAIR_MEDIUM: 'CommonGameTag' = 150 + HAIR_SHORT: 'CommonGameTag' = 149 + HAIR_STRAIGHT: 'CommonGameTag' = 313 + HAIR_TEXTURE_BALD: 'CommonGameTag' = 12391 + HAIR_TEXTURE_CURLY: 'CommonGameTag' = 821 + HAIR_TEXTURE_STRAIGHT: 'CommonGameTag' = 822 + HAIR_TEXTURE_WAVY: 'CommonGameTag' = 663 + HAIR_WAVY: 'CommonGameTag' = 315 + HAT_BRIM: 'CommonGameTag' = 371 + HAT_BRIMLESS: 'CommonGameTag' = 372 + HAT_CAP: 'CommonGameTag' = 373 + HAT_PAPER_BAG: 'CommonGameTag' = 2428 + HOOF_COLOR_DARK: 'CommonGameTag' = 118900 + HOOF_COLOR_DARK_MIX: 'CommonGameTag' = 118901 + HOOF_COLOR_LIGHT: 'CommonGameTag' = 118902 + HOOF_COLOR_LIGHT_MIX: 'CommonGameTag' = 118903 + HOOF_COLOR_MIX: 'CommonGameTag' = 118904 + HORN_COLOR_BLACK: 'CommonGameTag' = 118887 + HORN_COLOR_BLACK_GOLD: 'CommonGameTag' = 118888 + HORN_COLOR_BLACK_SILVER: 'CommonGameTag' = 118889 + HORN_COLOR_GOLD: 'CommonGameTag' = 118890 + HORN_COLOR_HOT_PINK: 'CommonGameTag' = 118899 + HORN_COLOR_PASTEL: 'CommonGameTag' = 118891 + HORN_COLOR_PINK: 'CommonGameTag' = 118892 + HORN_COLOR_PINK_PURPLE: 'CommonGameTag' = 118893 + HORN_COLOR_RAINBOW: 'CommonGameTag' = 118894 + HORN_COLOR_SILVER: 'CommonGameTag' = 118895 + HORN_COLOR_WHITE: 'CommonGameTag' = 118896 + HORN_COLOR_WHITE_GOLD: 'CommonGameTag' = 118897 + HORN_COLOR_WHITE_SILVER: 'CommonGameTag' = 118898 + HOUSEHOLD_MEMBER_1: 'CommonGameTag' = 642 + HOUSEHOLD_MEMBER_2: 'CommonGameTag' = 643 + HOUSEHOLD_MEMBER_3: 'CommonGameTag' = 644 + HOUSEHOLD_MEMBER_4: 'CommonGameTag' = 645 + HOUSEHOLD_MEMBER_5: 'CommonGameTag' = 646 + HOUSEHOLD_MEMBER_6: 'CommonGameTag' = 647 + HOUSEHOLD_MEMBER_7: 'CommonGameTag' = 648 + HOUSEHOLD_MEMBER_8: 'CommonGameTag' = 649 + INSTRUMENT_VIOLIN: 'CommonGameTag' = 401 + INTERACTION_ADOPTION: 'CommonGameTag' = 57441 + INTERACTION_ADVENTUROUS_ONE_SHOT: 'CommonGameTag' = 69723 + INTERACTION_ALL: 'CommonGameTag' = 462 + INTERACTION_ANIMAL_OBJECTS_SOCIAL_ALL: 'CommonGameTag' = 2982 + INTERACTION_ARGUMENT: 'CommonGameTag' = 43015 + INTERACTION_ASK_TO_LEAVE_LOT: 'CommonGameTag' = 689 + INTERACTION_BAR_VENUE: 'CommonGameTag' = 1599 + INTERACTION_BASKETBALL_PLAY: 'CommonGameTag' = 2127 + INTERACTION_BATHTUB: 'CommonGameTag' = 2348 + INTERACTION_BATUU_IGNORE_REPUTATION: 'CommonGameTag' = 51246 + INTERACTION_BE_READ_TO: 'CommonGameTag' = 863 + INTERACTION_BONFIRE: 'CommonGameTag' = 24590 + INTERACTION_BROWSE_RESEARCH: 'CommonGameTag' = 757 + INTERACTION_BURNOUT_ALL_DECREASE_LARGE: 'CommonGameTag' = 2923 + INTERACTION_BURNOUT_ALL_DECREASE_SMALL: 'CommonGameTag' = 2922 + INTERACTION_BURNOUT_CREATIVE_INCREASE_LARGE: 'CommonGameTag' = 2919 + INTERACTION_BURNOUT_CREATIVE_INCREASE_SMALL: 'CommonGameTag' = 2918 + INTERACTION_BURNOUT_MENTAL_INCREASE_LARGE: 'CommonGameTag' = 2921 + INTERACTION_BURNOUT_MENTAL_INCREASE_SMALL: 'CommonGameTag' = 2920 + INTERACTION_CAMPFIRE: 'CommonGameTag' = 2775 + INTERACTION_CAREER_WORK_RABBIT_HOLE: 'CommonGameTag' = 2490 + INTERACTION_CAREGIVER_SITUATION_MOTIVE_SOLVED: 'CommonGameTag' = 2945 + INTERACTION_CHARITY: 'CommonGameTag' = 750 + INTERACTION_CHAT: 'CommonGameTag' = 342 + INTERACTION_CLEAN: 'CommonGameTag' = 781 + INTERACTION_CLIMBING_ROUTE: 'CommonGameTag' = 69691 + INTERACTION_COLLECT: 'CommonGameTag' = 1309 + INTERACTION_COMEDY_MIC: 'CommonGameTag' = 1613 + INTERACTION_COMPUTER: 'CommonGameTag' = 439 + INTERACTION_COMPUTER_TYPING: 'CommonGameTag' = 1367 + INTERACTION_CONSUME: 'CommonGameTag' = 394 + INTERACTION_COOK: 'CommonGameTag' = 358 + INTERACTION_COUNTRY_CARETAKER_GIVE_GIFT: 'CommonGameTag' = 112655 + INTERACTION_COUNTRY_CARETAKER_SOCIALIZE_WITH_CRITTERS: 'CommonGameTag' = 112656 + INTERACTION_COUNTRY_CARETAKER_TAKE_GIFT: 'CommonGameTag' = 112657 + INTERACTION_CREATIVE_CRAFT: 'CommonGameTag' = 2942 + INTERACTION_CURIO_SHOP_BROWSE_BUY: 'CommonGameTag' = 47134 + INTERACTION_DEATH: 'CommonGameTag' = 425 + INTERACTION_DOCTOR_TREAT_PATIENT: 'CommonGameTag' = 12337 + INTERACTION_DRINK: 'CommonGameTag' = 654 + INTERACTION_ECO_FOOTPRINT_GREEN: 'CommonGameTag' = 67603 + INTERACTION_EXAM_TABLE_EXAM: 'CommonGameTag' = 57391 + INTERACTION_EXTREME_SPORTS: 'CommonGameTag' = 69727 + INTERACTION_FASHION_BLOG: 'CommonGameTag' = 2131 + INTERACTION_FEAR_PLANT: 'CommonGameTag' = 2802 + INTERACTION_FESTIVE: 'CommonGameTag' = 2058 + INTERACTION_FOOSBALL_TABLE_PLAY: 'CommonGameTag' = 24581 + INTERACTION_FRIENDLY: 'CommonGameTag' = 431 + INTERACTION_FUNNY: 'CommonGameTag' = 432 + INTERACTION_GAME_CONSOLE: 'CommonGameTag' = 55384 + INTERACTION_GO_JOGGING: 'CommonGameTag' = 926 + INTERACTION_GREEN_UPGRADED: 'CommonGameTag' = 67589 + INTERACTION_GREETING: 'CommonGameTag' = 453 + INTERACTION_GROUP_DANCE_TOGETHER: 'CommonGameTag' = 24607 + INTERACTION_GROUP_WORKOUT: 'CommonGameTag' = 71683 + INTERACTION_HACK: 'CommonGameTag' = 435 + INTERACTION_HUG: 'CommonGameTag' = 1990 + INTERACTION_IGNORE_GROUNDING: 'CommonGameTag' = 43028 + INTERACTION_INFECT_HOUSE: 'CommonGameTag' = 47125 + INTERACTION_INSTRUMENT_LISTEN: 'CommonGameTag' = 639 + INTERACTION_INTELLIGENCE_RESEARCH: 'CommonGameTag' = 746 + INTERACTION_INVENTION_CONSTRUCTOR_UPGRADE: 'CommonGameTag' = 12368 + INTERACTION_INVITE_TO_STAY: 'CommonGameTag' = 417 + INTERACTION_JOKE: 'CommonGameTag' = 871 + INTERACTION_JUICE_KEG: 'CommonGameTag' = 2347 + INTERACTION_KARAOKE_VENUE: 'CommonGameTag' = 1600 + INTERACTION_KISS: 'CommonGameTag' = 350 + INTERACTION_KNITTING: 'CommonGameTag' = 2624 + INTERACTION_LAUNDRY_GENERATE_NO_PILE: 'CommonGameTag' = 2035 + INTERACTION_LAUNDRY_PUT_AWAY_FINISHED_LAUNDRY: 'CommonGameTag' = 2034 + INTERACTION_LEAVE: 'CommonGameTag' = 420 + INTERACTION_LEAVE_MUST_RUN: 'CommonGameTag' = 419 + INTERACTION_LIFESTYLES_ADRENALINE_SEEKER_DISCOURAGE_AUTONOMY: 'CommonGameTag' = 69730 + INTERACTION_LIFESTYLES_ADRENALINE_SEEKER_FLEXIBLE_LENGTH: 'CommonGameTag' = 69655 + INTERACTION_LIFESTYLES_ADRENALINE_SEEKER_MUNDANE: 'CommonGameTag' = 69712 + INTERACTION_LIFESTYLES_ADRENALINE_SEEKER_ONE_SHOT: 'CommonGameTag' = 69656 + INTERACTION_LIFESTYLES_ELECTRONICS: 'CommonGameTag' = 69651 + INTERACTION_LIFESTYLES_ELECTRONICS_REPAIR: 'CommonGameTag' = 69652 + INTERACTION_LIFESTYLES_ENERGETIC_AUTONOMY: 'CommonGameTag' = 69737 + INTERACTION_LIFESTYLES_ENERGETIC_FLEXIBLE_LENGTH: 'CommonGameTag' = 69634 + INTERACTION_LIFESTYLES_ENERGETIC_ONE_SHOT: 'CommonGameTag' = 69690 + INTERACTION_LIFESTYLES_FREQUENT_TRAVELER_FLEXIBLE_LENGTH: 'CommonGameTag' = 69636 + INTERACTION_LIFESTYLES_FREQUENT_TRAVELER_ONE_SHOT: 'CommonGameTag' = 69635 + INTERACTION_LIFESTYLES_INDOORSY_AUTONOMY: 'CommonGameTag' = 69731 + INTERACTION_LIFESTYLES_INDOORSY_FLEXIBLE_LENGTH: 'CommonGameTag' = 2749 + INTERACTION_LIFESTYLES_INDOORSY_ONE_SHOT: 'CommonGameTag' = 69658 + INTERACTION_LIFESTYLES_OUTDOORSY_AUTONOMY: 'CommonGameTag' = 69734 + INTERACTION_LIFESTYLES_OUTDOORSY_FLEXIBLE_LENGTH: 'CommonGameTag' = 2776 + INTERACTION_LIFESTYLES_OUTDOORSY_ONE_SHOT: 'CommonGameTag' = 2777 + INTERACTION_LIFESTYLES_ROMANTIC_MEDIA: 'CommonGameTag' = 69713 + INTERACTION_LIFESTYLES_SEDENTARY_AUTONOMY: 'CommonGameTag' = 69736 + INTERACTION_LIFESTYLES_SEDENTARY_FLEXIBLE_LENGTH: 'CommonGameTag' = 2759 + INTERACTION_LIFESTYLES_SEDENTARY_ONE_SHOT: 'CommonGameTag' = 69689 + INTERACTION_LIFESTYLES_TECHIE_AUTONOMY: 'CommonGameTag' = 69735 + INTERACTION_LIFESTYLES_TECHIE_FLEXIBLE_LENGTH: 'CommonGameTag' = 69638 + INTERACTION_LIFESTYLES_TECHIE_ONE_SHOT: 'CommonGameTag' = 69639 + INTERACTION_LIFESTYLES_TECHNOPHOBE_FLEXIBLE_LENGTH: 'CommonGameTag' = 69641 + INTERACTION_LIFESTYLES_TECHNOPHOBE_ONE_SHOT: 'CommonGameTag' = 69640 + INTERACTION_LIFESTYLES_TECHNOPHOBE_SABOTAGE: 'CommonGameTag' = 69704 + INTERACTION_LIFESTYLES_TECH_CAREER: 'CommonGameTag' = 69663 + INTERACTION_LISTEN_MUSIC: 'CommonGameTag' = 444 + INTERACTION_MAKE_APP: 'CommonGameTag' = 683 + INTERACTION_MAKE_COFFEE_OR_TEA: 'CommonGameTag' = 1028 + INTERACTION_MARKET_STALLS_TEND: 'CommonGameTag' = 1934 + INTERACTION_MARKET_STALL_TEND: 'CommonGameTag' = 55400 + INTERACTION_MASSAGE_TABLE: 'CommonGameTag' = 18439 + INTERACTION_MEAN: 'CommonGameTag' = 433 + INTERACTION_MENTOR: 'CommonGameTag' = 455 + INTERACTION_MENTOR_MUSIC: 'CommonGameTag' = 695 + INTERACTION_MENTOR_SKILL: 'CommonGameTag' = 2809 + INTERACTION_MISCHIEVOUS: 'CommonGameTag' = 434 + INTERACTION_MIXER: 'CommonGameTag' = 461 + INTERACTION_NAP: 'CommonGameTag' = 591 + INTERACTION_NESTING_BLOCKS: 'CommonGameTag' = 1698 + INTERACTION_NOISY_ELECTRONICS: 'CommonGameTag' = 1628 + INTERACTION_OBSERVATORY: 'CommonGameTag' = 1598 + INTERACTION_OLD_DAY_FINE: 'CommonGameTag' = 67638 + INTERACTION_PAINT: 'CommonGameTag' = 694 + INTERACTION_PAINT_BY_REFERENCE: 'CommonGameTag' = 1372 + INTERACTION_PAINT_MURAL: 'CommonGameTag' = 55359 + INTERACTION_PARK_VENUE: 'CommonGameTag' = 1601 + INTERACTION_PARTY: 'CommonGameTag' = 2061 + INTERACTION_PERFORM_COMEDY_ROUTINE: 'CommonGameTag' = 469 + INTERACTION_PETS_FRIENDLY: 'CommonGameTag' = 57370 + INTERACTION_PETS_GREETING: 'CommonGameTag' = 57372 + INTERACTION_PETS_MEAN: 'CommonGameTag' = 57371 + INTERACTION_PETS_SS3_ALLOWED: 'CommonGameTag' = 2015 + INTERACTION_PET_MISBEHAVIOR: 'CommonGameTag' = 57397 + INTERACTION_PHOTO_STUDIO_TAKE_PICTURE: 'CommonGameTag' = 1942 + INTERACTION_PLANT_SIM_PLANT_CARE: 'CommonGameTag' = 2774 + INTERACTION_PLANT_SIM_WATER: 'CommonGameTag' = 2773 + INTERACTION_PLAY_DJ_BOOTH: 'CommonGameTag' = 1618 + INTERACTION_PLAY_GAME: 'CommonGameTag' = 640 + INTERACTION_PLAY_GUITAR: 'CommonGameTag' = 1615 + INTERACTION_PLAY_GUITAR_FOR_TIPS: 'CommonGameTag' = 1024 + INTERACTION_PLAY_INSTRUMENT: 'CommonGameTag' = 442 + INTERACTION_PLAY_INSTRUMENT_FOR_TIPS: 'CommonGameTag' = 443 + INTERACTION_PLAY_INSTRUMENT_OR_COMEDY_FOR_TIPS: 'CommonGameTag' = 606 + INTERACTION_PLAY_PIANO: 'CommonGameTag' = 690 + INTERACTION_PLAY_PIANO_FOR_TIPS: 'CommonGameTag' = 1025 + INTERACTION_PLAY_TOY: 'CommonGameTag' = 1339 + INTERACTION_PLAY_VIDEO_GAMES: 'CommonGameTag' = 685 + INTERACTION_PLAY_VIOLIN: 'CommonGameTag' = 1616 + INTERACTION_PLAY_VIOLIN_FOR_TIPS: 'CommonGameTag' = 1026 + INTERACTION_PLAY_WITH_CAT: 'CommonGameTag' = 57362 + INTERACTION_PLAY_WITH_DOG: 'CommonGameTag' = 57363 + INTERACTION_PRACTICE_ACTING: 'CommonGameTag' = 61552 + INTERACTION_PRACTICE_CODING: 'CommonGameTag' = 693 + INTERACTION_PRACTICE_DEBATE: 'CommonGameTag' = 65648 + INTERACTION_PRACTICE_WRITING: 'CommonGameTag' = 692 + INTERACTION_PRANK: 'CommonGameTag' = 583 + INTERACTION_PRANK_OBJECT: 'CommonGameTag' = 752 + INTERACTION_PROGRAMMING: 'CommonGameTag' = 751 + INTERACTION_PUBLISH_BOOK: 'CommonGameTag' = 660 + INTERACTION_PUNCHING_BAG: 'CommonGameTag' = 2788 + INTERACTION_QUICK_SOCIAL: 'CommonGameTag' = 2832 + INTERACTION_READ_TO_CHILD: 'CommonGameTag' = 931 + INTERACTION_RELATIONSHIP_PANEL_INVITEO_VER: 'CommonGameTag' = 2834 + INTERACTION_REPAIR: 'CommonGameTag' = 464 + INTERACTION_RESTAURANT_WAIT_TO_PLACE_ORDER: 'CommonGameTag' = 2151 + INTERACTION_RETAIL: 'CommonGameTag' = 12347 + INTERACTION_RIVAL_REMINISCE: 'CommonGameTag' = 2795 + INTERACTION_ROCKET: 'CommonGameTag' = 465 + INTERACTION_ROCKETSHIP_BUILD: 'CommonGameTag' = 2941 + INTERACTION_ROCKET_SHIP_LAUNCH: 'CommonGameTag' = 438 + INTERACTION_ROCKET_SHIP_UPGRADE: 'CommonGameTag' = 437 + INTERACTION_RUN_AWAY: 'CommonGameTag' = 57443 + INTERACTION_SCHOOL_WORK: 'CommonGameTag' = 43026 + INTERACTION_SCIENCE_TABLE: 'CommonGameTag' = 786 + INTERACTION_SEASON_FALL: 'CommonGameTag' = 59420 + INTERACTION_SEASON_SPRING: 'CommonGameTag' = 59418 + INTERACTION_SEASON_SUMMER: 'CommonGameTag' = 59419 + INTERACTION_SEASON_WINTER: 'CommonGameTag' = 59421 + INTERACTION_SELL_ART: 'CommonGameTag' = 661 + INTERACTION_SHOWER: 'CommonGameTag' = 1447 + INTERACTION_SHOWOFF: 'CommonGameTag' = 427 + INTERACTION_SIM_TV: 'CommonGameTag' = 55362 + INTERACTION_SITUATION_PHOTOGRAPHY: 'CommonGameTag' = 79876 + INTERACTION_SKATING_ICE_SKATING: 'CommonGameTag' = 59395 + INTERACTION_SKATING_ROLLER_SKATING: 'CommonGameTag' = 59396 + INTERACTION_SKATING_ROUTINE: 'CommonGameTag' = 59397 + INTERACTION_SKATING_SKATING: 'CommonGameTag' = 59394 + INTERACTION_SKATING_TRICK: 'CommonGameTag' = 59401 + INTERACTION_SKETCH: 'CommonGameTag' = 2132 + INTERACTION_SKIING: 'CommonGameTag' = 69726 + INTERACTION_SKILL_ACTING: 'CommonGameTag' = 2340 + INTERACTION_SKILL_BAKING: 'CommonGameTag' = 2346 + INTERACTION_SKILL_BARTENDING: 'CommonGameTag' = 835 + INTERACTION_SKILL_CHARISMA: 'CommonGameTag' = 837 + INTERACTION_SKILL_CHILD_CREATIVITY: 'CommonGameTag' = 853 + INTERACTION_SKILL_CHILD_MENTAL: 'CommonGameTag' = 854 + INTERACTION_SKILL_CHILD_MOTOR: 'CommonGameTag' = 855 + INTERACTION_SKILL_CHILD_SOCIAL: 'CommonGameTag' = 856 + INTERACTION_SKILL_COMEDY: 'CommonGameTag' = 838 + INTERACTION_SKILL_DANCING: 'CommonGameTag' = 2343 + INTERACTION_SKILL_DJ_MIXING: 'CommonGameTag' = 2342 + INTERACTION_SKILL_DOG_TRAINING: 'CommonGameTag' = 57373 + INTERACTION_SKILL_EQUESTRIAN_SKILL: 'CommonGameTag' = 2980 + INTERACTION_SKILL_FABRICATION: 'CommonGameTag' = 2434 + INTERACTION_SKILL_FISHING: 'CommonGameTag' = 839 + INTERACTION_SKILL_FITNESS: 'CommonGameTag' = 836 + INTERACTION_SKILL_FLOWER_ARRANGEMENT: 'CommonGameTag' = 2344 + INTERACTION_SKILL_GARDENING: 'CommonGameTag' = 834 + INTERACTION_SKILL_GOURMET_COOKING: 'CommonGameTag' = 840 + INTERACTION_SKILL_GUITAR: 'CommonGameTag' = 841 + INTERACTION_SKILL_HANDINESS: 'CommonGameTag' = 842 + INTERACTION_SKILL_HERBALISM: 'CommonGameTag' = 2339 + INTERACTION_SKILL_HOME_STYLE_COOKING: 'CommonGameTag' = 843 + INTERACTION_SKILL_JUICE_FIZZING: 'CommonGameTag' = 2424 + INTERACTION_SKILL_KNITTING: 'CommonGameTag' = 2461 + INTERACTION_SKILL_LOGIC: 'CommonGameTag' = 844 + INTERACTION_SKILL_MEDIA_PRODUCTION: 'CommonGameTag' = 2338 + INTERACTION_SKILL_MISCHIEF: 'CommonGameTag' = 845 + INTERACTION_SKILL_PAINTING: 'CommonGameTag' = 846 + INTERACTION_SKILL_PHOTOGRAPHY: 'CommonGameTag' = 1938 + INTERACTION_SKILL_PIANO: 'CommonGameTag' = 847 + INTERACTION_SKILL_PIPE_ORGAN: 'CommonGameTag' = 2341 + INTERACTION_SKILL_PROGRAMMING: 'CommonGameTag' = 848 + INTERACTION_SKILL_RANCH_NECTAR: 'CommonGameTag' = 118865 + INTERACTION_SKILL_ROBOTICS: 'CommonGameTag' = 2345 + INTERACTION_SKILL_ROCKET_SCIENCE: 'CommonGameTag' = 849 + INTERACTION_SKILL_SINGING: 'CommonGameTag' = 55364 + INTERACTION_SKILL_SINGING_KARAOKE: 'CommonGameTag' = 1617 + INTERACTION_SKILL_VIDEO_GAMING: 'CommonGameTag' = 850 + INTERACTION_SKILL_VIOLIN: 'CommonGameTag' = 851 + INTERACTION_SKILL_WELLNESS: 'CommonGameTag' = 18465 + INTERACTION_SKILL_WELLNESS_BG: 'CommonGameTag' = 2337 + INTERACTION_SKILL_WRITING: 'CommonGameTag' = 852 + INTERACTION_SKY_GAZE: 'CommonGameTag' = 2944 + INTERACTION_SLEDDING: 'CommonGameTag' = 69725 + INTERACTION_SLEEP: 'CommonGameTag' = 451 + INTERACTION_SLEEP_GROUP: 'CommonGameTag' = 2094 + INTERACTION_SLEEP_NAP: 'CommonGameTag' = 59477 + INTERACTION_SNIFF_NEW_OBJECTS: 'CommonGameTag' = 2093 + INTERACTION_SNOWBOARDING: 'CommonGameTag' = 69724 + INTERACTION_SOCIAL_ALL: 'CommonGameTag' = 2161 + INTERACTION_SOCIAL_CONTAGIOUS: 'CommonGameTag' = 2041 + INTERACTION_SOCIAL_FIGHT: 'CommonGameTag' = 2801 + INTERACTION_SOCIAL_HORSE_TO_SIM: 'CommonGameTag' = 118905 + INTERACTION_SOCIAL_MEDIA_CHECK_IN: 'CommonGameTag' = 1619 + INTERACTION_SOCIAL_MEDIA_PERSUADE_TO: 'CommonGameTag' = 55319 + INTERACTION_SOCIAL_MIXER: 'CommonGameTag' = 2162 + INTERACTION_SOCIAL_NETWORK: 'CommonGameTag' = 1595 + INTERACTION_SOCIAL_SUPER: 'CommonGameTag' = 454 + INTERACTION_SOCIAL_TOUCHING: 'CommonGameTag' = 2163 + INTERACTION_SPRAY_GRAFFITI: 'CommonGameTag' = 55361 + INTERACTION_STEREO_DANCE: 'CommonGameTag' = 876 + INTERACTION_STEREO_LISTEN: 'CommonGameTag' = 638 + INTERACTION_STUFFED_ANIMAL_BABBLE: 'CommonGameTag' = 1723 + INTERACTION_SUPER: 'CommonGameTag' = 460 + INTERACTION_SURGERY_STATION_EXAM: 'CommonGameTag' = 57392 + INTERACTION_SWIM: 'CommonGameTag' = 1591 + INTERACTION_TAKE_PHOTO: 'CommonGameTag' = 1939 + INTERACTION_TAKE_PIZZA: 'CommonGameTag' = 1640 + INTERACTION_TALK_LIKE_A_PIRATE_DAY: 'CommonGameTag' = 2480 + INTERACTION_TEEN_CAREER_RABBIT_HOLE: 'CommonGameTag' = 1719 + INTERACTION_TELESCOPE: 'CommonGameTag' = 436 + INTERACTION_TELL_STORY: 'CommonGameTag' = 466 + INTERACTION_TENT_SLEEP: 'CommonGameTag' = 2477 + INTERACTION_THROWING: 'CommonGameTag' = 2488 + INTERACTION_THROWING_MUD: 'CommonGameTag' = 59425 + INTERACTION_THROWING_SNOWBALL: 'CommonGameTag' = 2489 + INTERACTION_THROWING_WATER_BALLOON: 'CommonGameTag' = 59426 + INTERACTION_TODDLER_EAT_ACTIVE: 'CommonGameTag' = 2934 + INTERACTION_TOURNAMENT: 'CommonGameTag' = 749 + INTERACTION_TRANSFER_FIRELEAF_RASH: 'CommonGameTag' = 2479 + INTERACTION_TREADMILL: 'CommonGameTag' = 353 + INTERACTION_TRY_FOR_BABY: 'CommonGameTag' = 452 + INTERACTION_UNIVERSITY_STUDY_WITH: 'CommonGameTag' = 65609 + INTERACTION_UPGRADE: 'CommonGameTag' = 658 + INTERACTION_UPGRADE_CLEAN_BREAK: 'CommonGameTag' = 2517 + INTERACTION_USE_TOILET: 'CommonGameTag' = 396 + INTERACTION_VACUUM: 'CommonGameTag' = 94225 + INTERACTION_VIDEO_GAME_LIVESTREAM: 'CommonGameTag' = 1641 + INTERACTION_VIDEO_GAME_MONEY: 'CommonGameTag' = 655 + INTERACTION_VIDEO_GAME_STREAM_LETS_PLAY: 'CommonGameTag' = 1642 + INTERACTION_VIEW_ART: 'CommonGameTag' = 758 + INTERACTION_VISIT_LOT: 'CommonGameTag' = 449 + INTERACTION_VOODOO: 'CommonGameTag' = 426 + INTERACTION_WAITSTAFF_IDLE: 'CommonGameTag' = 26634 + INTERACTION_WAIT_IN_LINE: 'CommonGameTag' = 2497 + INTERACTION_WATCH_PERFORMER: 'CommonGameTag' = 1597 + INTERACTION_WATCH_TV: 'CommonGameTag' = 450 + INTERACTION_WATCH_TV_COOKING: 'CommonGameTag' = 55320 + INTERACTION_WATCH_TV_ROM_COM_ACT: 'CommonGameTag' = 55321 + INTERACTION_WEATHER_RAIN: 'CommonGameTag' = 59423 + INTERACTION_WEATHER_SNOW: 'CommonGameTag' = 59422 + INTERACTION_WELLNESS_GUIDE: 'CommonGameTag' = 18477 + INTERACTION_WELLNESS_HUSTLE: 'CommonGameTag' = 18479 + INTERACTION_WELLNESS_MINDFULNESS: 'CommonGameTag' = 18474 + INTERACTION_WELLNESS_PEACEFUL: 'CommonGameTag' = 18476 + INTERACTION_WELLNESS_REGULAR: 'CommonGameTag' = 18478 + INTERACTION_WELLNESS_RELAXATION: 'CommonGameTag' = 18475 + INTERACTION_WOODWORKING: 'CommonGameTag' = 1612 + INTERACTION_WORKOUT: 'CommonGameTag' = 463 + INTERACTION_WORKOUT_MACHINE: 'CommonGameTag' = 354 + INTERACTION_WORKOUT_PUSH_THE_LIMITS: 'CommonGameTag' = 1171 + INTERACTION_WRITE: 'CommonGameTag' = 55360 + INTERACTION_WRITE_ARTICLE: 'CommonGameTag' = 665 + INTERACTION_WRITE_JOKES: 'CommonGameTag' = 696 + INTERACTION_YOGA_CLASS_MEMBER: 'CommonGameTag' = 18461 + INVALID: 'CommonGameTag' = 0 + INVENTORY_ANIMAL_CARE_ANIMALS: 'CommonGameTag' = 2984 + INVENTORY_ANIMAL_CARE_CARE: 'CommonGameTag' = 2985 + INVENTORY_BOOKS_FUN: 'CommonGameTag' = 2350 + INVENTORY_BOOKS_OTHER: 'CommonGameTag' = 2352 + INVENTORY_BOOKS_SKILL: 'CommonGameTag' = 2351 + INVENTORY_COLLECTIBLE_CREATURE: 'CommonGameTag' = 2353 + INVENTORY_COLLECTIBLE_DECORATION: 'CommonGameTag' = 2354 + INVENTORY_COLLECTIBLE_NATURAL: 'CommonGameTag' = 2355 + INVENTORY_COLLECTIBLE_OTHER: 'CommonGameTag' = 2356 + INVENTORY_CONSUMABLE_DRINK: 'CommonGameTag' = 2358 + INVENTORY_CONSUMABLE_FOOD: 'CommonGameTag' = 2357 + INVENTORY_CONSUMABLE_OTHER: 'CommonGameTag' = 2359 + INVENTORY_FASHION_ALL: 'CommonGameTag' = 114707 + INVENTORY_FASHION_LISTED: 'CommonGameTag' = 114704 + INVENTORY_FASHION_PENDING_SALE: 'CommonGameTag' = 114705 + INVENTORY_FASHION_UNAVAILABLE: 'CommonGameTag' = 114706 + INVENTORY_GARDENING_OTHER: 'CommonGameTag' = 2360 + INVENTORY_HOME_SKILL_DECORATION: 'CommonGameTag' = 2362 + INVENTORY_HOME_SKILL_HOME: 'CommonGameTag' = 2363 + INVENTORY_HOME_SKILL_LITTLE_ONES: 'CommonGameTag' = 2364 + INVENTORY_HOME_SKILL_SKILL: 'CommonGameTag' = 2361 + INVENTORY_PLOPSY_ALL: 'CommonGameTag' = 2459 + INVENTORY_PLOPSY_LISTED: 'CommonGameTag' = 2457 + INVENTORY_PLOPSY_PENDING_SALE: 'CommonGameTag' = 2458 + INVENTORY_PLOPSY_UNAVAILABLE: 'CommonGameTag' = 83989 + INVENTORY_SCRAPS_JUNK: 'CommonGameTag' = 2371 + INVENTORY_SCRAPS_PARTS: 'CommonGameTag' = 2370 + INVENTORY_SIM_CRAFTED_ARTWORK: 'CommonGameTag' = 2368 + INVENTORY_SIM_CRAFTED_OTHER: 'CommonGameTag' = 2369 + INVENTORY_SPECIAL_CAREER_ACTIVITY: 'CommonGameTag' = 2365 + INVENTORY_SPECIAL_EDUCATION: 'CommonGameTag' = 2366 + INVENTORY_SPECIAL_STORY: 'CommonGameTag' = 2367 + JOB_BATUU_NPC: 'CommonGameTag' = 2512 + JOB_RESTAURANT_DINER: 'CommonGameTag' = 2145 + JOB_VENUE: 'CommonGameTag' = 1464 + JOB_VET_PATIENT: 'CommonGameTag' = 57442 + JOB_WALKBY: 'CommonGameTag' = 1463 + LESSON_ASPIRATIONS_WANTS: 'CommonGameTag' = 2869 + LESSON_BEGINNER: 'CommonGameTag' = 2848 + LESSON_BEGINNER_BUILD_MODE: 'CommonGameTag' = 2857 + LESSON_BEGINNER_CAS: 'CommonGameTag' = 2855 + LESSON_BEGINNER_CONTROLS: 'CommonGameTag' = 2858 + LESSON_BEGINNER_LIVE_MODE: 'CommonGameTag' = 2856 + LESSON_BUILDING: 'CommonGameTag' = 2875 + LESSON_BUILD_MODE: 'CommonGameTag' = 2852 + LESSON_CAS: 'CommonGameTag' = 2849 + LESSON_CHILD_ACCOUNT_ONLY: 'CommonGameTag' = 2906 + LESSON_CHILD_ACCOUNT_RESTRICTED: 'CommonGameTag' = 2907 + LESSON_CONSOLE_ONLY: 'CommonGameTag' = 2902 + LESSON_DEBUG_CATEGORY: 'CommonGameTag' = 2845 + LESSON_DEBUG_SUBCATEGORY: 'CommonGameTag' = 2846 + LESSON_DESK_TOP_ONLY: 'CommonGameTag' = 2901 + LESSON_EMOTIONS: 'CommonGameTag' = 2867 + LESSON_EP01_GET_TO_WORK: 'CommonGameTag' = 2883 + LESSON_EP02_GET_TOGETHER: 'CommonGameTag' = 2880 + LESSON_EP03_CITY_LIVING: 'CommonGameTag' = 2884 + LESSON_EP04_CAP: 'CommonGameTag' = 2881 + LESSON_EP04_CATS_AND_DOGS: 'CommonGameTag' = 2885 + LESSON_EP05_SEASONS: 'CommonGameTag' = 2882 + LESSON_EP06_GET_FAMOUS: 'CommonGameTag' = 2886 + LESSON_EP07_ISLAND_LIVING: 'CommonGameTag' = 2887 + LESSON_EP08_DISCOVER_UNIVERSITY: 'CommonGameTag' = 2888 + LESSON_EP09_ECO_LIFESTYLE: 'CommonGameTag' = 2889 + LESSON_EP10_SNOWY_ESCAPE: 'CommonGameTag' = 2890 + LESSON_EP11_COTTAGE_LIVING: 'CommonGameTag' = 2891 + LESSON_EP12_HIGH_SCHOOL_YEARS: 'CommonGameTag' = 2892 + LESSON_EP13_GROWING_TOGETHER: 'CommonGameTag' = 2955 + LESSON_FACEBODY: 'CommonGameTag' = 2860 + LESSON_FAMILY: 'CommonGameTag' = 2873 + LESSON_FILTER_SEARCH_BUILD_MODE: 'CommonGameTag' = 2879 + LESSON_GALLERY: 'CommonGameTag' = 2854 + LESSON_GP01_OUTDOOR_RETREAT: 'CommonGameTag' = 2900 + LESSON_GP02_SPA_DAY: 'CommonGameTag' = 2893 + LESSON_GP03_DINE_OUT: 'CommonGameTag' = 2894 + LESSON_GP05_PARENTHOOD: 'CommonGameTag' = 2895 + LESSON_GP06_JUNGLE_ADVENTURE: 'CommonGameTag' = 2896 + LESSON_GP10_DREAM_HOME_DECORATOR: 'CommonGameTag' = 2897 + LESSON_GP11_MY_WEDDING_STORIES: 'CommonGameTag' = 2898 + LESSON_GP12_WEREWOLVES: 'CommonGameTag' = 2899 + LESSON_IDENTITY_PERSONALITY: 'CommonGameTag' = 2859 + LESSON_INVENTORY_COLLECTIBLES: 'CommonGameTag' = 2903 + LESSON_LANDSCAPING: 'CommonGameTag' = 2877 + LESSON_LIFE_DEATH: 'CommonGameTag' = 2865 + LESSON_LIVE_MODE: 'CommonGameTag' = 2851 + LESSON_LOT_SETTINGS: 'CommonGameTag' = 2878 + LESSON_MONEY_WORK: 'CommonGameTag' = 2870 + LESSON_NEEDS: 'CommonGameTag' = 2866 + LESSON_NEIGHBOHOOD_STORIES: 'CommonGameTag' = 2863 + LESSON_NEIGHBORS_HOUSEHOLDS: 'CommonGameTag' = 2862 + LESSON_OBJECTS: 'CommonGameTag' = 2876 + LESSON_OUTFITS: 'CommonGameTag' = 2861 + LESSON_PERSONALITY: 'CommonGameTag' = 2868 + LESSON_PRONOUNS: 'CommonGameTag' = 2905 + LESSON_RELATIONSHIPS: 'CommonGameTag' = 2872 + LESSON_SCENARIOS: 'CommonGameTag' = 2853 + LESSON_SKILLS: 'CommonGameTag' = 2871 + LESSON_TIME: 'CommonGameTag' = 2864 + LESSON_TOOLBAR: 'CommonGameTag' = 2904 + LESSON_TRAVEL_MOVING: 'CommonGameTag' = 2874 + LESSON_UNCATEGORIZED: 'CommonGameTag' = 2847 + LESSON_WORLD_MAP: 'CommonGameTag' = 2850 + LIFESTYLES_DANGEROUS_CAREER: 'CommonGameTag' = 69711 + LIFESTYLES_HIGH_ENERGY_CAREER: 'CommonGameTag' = 69683 + LIFESTYLES_INDOORSY_CAREER: 'CommonGameTag' = 69733 + LIFESTYLES_LOW_ENERGY_CAREER: 'CommonGameTag' = 69684 + LIFESTYLES_OUTDOORSY_CAREER: 'CommonGameTag' = 69721 + MAILBOX: 'CommonGameTag' = 346 + MAIN_PET_SOCIAL: 'CommonGameTag' = 57349 + MENTOR_ACTIVITY_TABLE: 'CommonGameTag' = 588 + MENTOR_EASEL: 'CommonGameTag' = 365 + MENTOR_FITNESS: 'CommonGameTag' = 357 + MENTOR_GUITAR: 'CommonGameTag' = 361 + MENTOR_MURAL: 'CommonGameTag' = 55398 + MENTOR_PIANO: 'CommonGameTag' = 362 + MENTOR_REPAIR: 'CommonGameTag' = 765 + MENTOR_TREADMILL: 'CommonGameTag' = 355 + MENTOR_UPGRADE: 'CommonGameTag' = 766 + MENTOR_VIOLIN: 'CommonGameTag' = 363 + MENTOR_WOODWORKING_TABLE: 'CommonGameTag' = 764 + MENTOR_WORKOUT_MACHINE: 'CommonGameTag' = 356 + MICROSCOPE_SLIDE_CRYSTAL: 'CommonGameTag' = 344 + MICROSCOPE_SLIDE_FOSSIL: 'CommonGameTag' = 343 + MICROSCOPE_SLIDE_PLANT: 'CommonGameTag' = 345 + MOOD_ANGRY: 'CommonGameTag' = 317 + MOOD_BORED: 'CommonGameTag' = 318 + MOOD_CONFIDENT: 'CommonGameTag' = 319 + MOOD_CRANKY: 'CommonGameTag' = 320 + MOOD_DEPRESSED: 'CommonGameTag' = 321 + MOOD_DRUNK: 'CommonGameTag' = 322 + MOOD_EMBARRASSED: 'CommonGameTag' = 323 + MOOD_ENERGIZED: 'CommonGameTag' = 324 + MOOD_FINE: 'CommonGameTag' = 331 + MOOD_FLIRTY: 'CommonGameTag' = 325 + MOOD_FOCUSED: 'CommonGameTag' = 326 + MOOD_HAPPY: 'CommonGameTag' = 328 + MOOD_IMAGINATIVE: 'CommonGameTag' = 329 + MOOD_OPTIMISM: 'CommonGameTag' = 64 + MOOD_PLAYFUL: 'CommonGameTag' = 332 + MOOD_SAD: 'CommonGameTag' = 333 + MOOD_SLOSHED: 'CommonGameTag' = 334 + MOOD_TENSE: 'CommonGameTag' = 327 + MOOD_UNCOMFORTABLE: 'CommonGameTag' = 330 + NONE_EP03_PLEASE_REUSE_ME: 'CommonGameTag' = 24592 + NOSE_COLOR_BLACK: 'CommonGameTag' = 1917 + NOSE_COLOR_BLACK_PINK: 'CommonGameTag' = 1922 + NOSE_COLOR_BROWN: 'CommonGameTag' = 1918 + NOSE_COLOR_BROWN_PINK: 'CommonGameTag' = 1923 + NOSE_COLOR_LIVER: 'CommonGameTag' = 1919 + NOSE_COLOR_PINK: 'CommonGameTag' = 1920 + NOSE_COLOR_TAN: 'CommonGameTag' = 1921 + NUDE_PART_ALWAYS: 'CommonGameTag' = 1540 + NUDE_PART_MALE_WITH_BREAST: 'CommonGameTag' = 1541 + OBJECT_BAR: 'CommonGameTag' = 349 + OBJECT_MURAL: 'CommonGameTag' = 55363 + OCCULT_ALIEN: 'CommonGameTag' = 12319 + OCCULT_HUMAN: 'CommonGameTag' = 1310 + OCCULT_MERMAID: 'CommonGameTag' = 2208 + OCCULT_VAMPIRE: 'CommonGameTag' = 1677 + OCCULT_WEREWOLF: 'CommonGameTag' = 2779 + OCCULT_WITCH: 'CommonGameTag' = 2279 + OUTFIT_ARTS_CRITIC: 'CommonGameTag' = 55301 + OUTFIT_ART_CRITIC_LEVEL10: 'CommonGameTag' = 55393 + OUTFIT_CATEGORY_ATHLETIC: 'CommonGameTag' = 80 + OUTFIT_CATEGORY_BATHING: 'CommonGameTag' = 82 + OUTFIT_CATEGORY_BATUU: 'CommonGameTag' = 2470 + OUTFIT_CATEGORY_CAREER: 'CommonGameTag' = 263 + OUTFIT_CATEGORY_COLD_WEATHER: 'CommonGameTag' = 2054 + OUTFIT_CATEGORY_EVERYDAY: 'CommonGameTag' = 77 + OUTFIT_CATEGORY_FORMAL: 'CommonGameTag' = 78 + OUTFIT_CATEGORY_HOT_WEATHER: 'CommonGameTag' = 2053 + OUTFIT_CATEGORY_PARTY: 'CommonGameTag' = 83 + OUTFIT_CATEGORY_RETAIL_UNIFORMS: 'CommonGameTag' = 1371 + OUTFIT_CATEGORY_SITUATION: 'CommonGameTag' = 335 + OUTFIT_CATEGORY_SLEEP: 'CommonGameTag' = 81 + OUTFIT_CATEGORY_SWIMWEAR: 'CommonGameTag' = 1229 + OUTFIT_CATEGORY_UNUSED: 'CommonGameTag' = 79 + OUTFIT_CATEGORY_WITCH: 'CommonGameTag' = 8210 + OUTFIT_FOOD_CRITIC: 'CommonGameTag' = 55300 + OUTFIT_FOOD_CRITIC_LEVEL10: 'CommonGameTag' = 55394 + PATTERN_ANIMAL: 'CommonGameTag' = 590 + PATTERN_BICOLOR: 'CommonGameTag' = 1905 + PATTERN_BRINDLE: 'CommonGameTag' = 1902 + PATTERN_CALICO: 'CommonGameTag' = 1912 + PATTERN_HARLEQUIN: 'CommonGameTag' = 1909 + PATTERN_MERLE: 'CommonGameTag' = 1907 + PATTERN_SABLE: 'CommonGameTag' = 1910 + PATTERN_SADDLE: 'CommonGameTag' = 1903 + PATTERN_SPECKLED: 'CommonGameTag' = 1913 + PATTERN_SPOTTED: 'CommonGameTag' = 1900 + PATTERN_STRIPED: 'CommonGameTag' = 1901 + PATTERN_SWIRLED: 'CommonGameTag' = 1904 + PATTERN_TABBY: 'CommonGameTag' = 1899 + PATTERN_TRICOLOR: 'CommonGameTag' = 1906 + PATTERN_TUXEDO: 'CommonGameTag' = 1908 + PERSONA_BOHO: 'CommonGameTag' = 130 + PERSONA_FASHIONISTA: 'CommonGameTag' = 129 + PERSONA_MOM: 'CommonGameTag' = 148 + PERSONA_ROCKER: 'CommonGameTag' = 128 + PORTAL_DISALLOWANCE_MASCOT: 'CommonGameTag' = 69745 + PORTAL_DISALLOWANCE_UNGREETED: 'CommonGameTag' = 668 + POSTURE_LIFESTYLES_RELAXED_SIT: 'CommonGameTag' = 69695 + RECIPE_BANQUET_TABLE_OPTION: 'CommonGameTag' = 2753 + RECIPE_CANDLE_MAKING_STATION_CANDLE: 'CommonGameTag' = 67604 + RECIPE_CATEGORY_CAKE_PIE: 'CommonGameTag' = 1536 + RECIPE_CATEGORY_CHOCOLATE: 'CommonGameTag' = 1537 + RECIPE_CATEGORY_COLD: 'CommonGameTag' = 1533 + RECIPE_CATEGORY_DRINKS: 'CommonGameTag' = 1518 + RECIPE_CATEGORY_EGGS: 'CommonGameTag' = 112677 + RECIPE_CATEGORY_FIZZY: 'CommonGameTag' = 1531 + RECIPE_CATEGORY_FRUIT: 'CommonGameTag' = 1532 + RECIPE_CATEGORY_GRAINS: 'CommonGameTag' = 1515 + RECIPE_CATEGORY_HOT: 'CommonGameTag' = 1534 + RECIPE_CATEGORY_MEAT: 'CommonGameTag' = 1513 + RECIPE_CATEGORY_MILK: 'CommonGameTag' = 112678 + RECIPE_CATEGORY_MISC: 'CommonGameTag' = 1517 + RECIPE_CATEGORY_NECTAR: 'CommonGameTag' = 1535 + RECIPE_CATEGORY_SEAFOOD: 'CommonGameTag' = 1519 + RECIPE_CATEGORY_SWEETS: 'CommonGameTag' = 1516 + RECIPE_CATEGORY_VEGETARIAN: 'CommonGameTag' = 1514 + RECIPE_CATEGORY_VILLAGE_FAIR_NPC_EGG: 'CommonGameTag' = 112690 + RECIPE_CATEGORY_VILLAGE_FAIR_NPC_MILK: 'CommonGameTag' = 112692 + RECIPE_CATEGORY_VILLAGE_FAIR_NPC_WOOL: 'CommonGameTag' = 112691 + RECIPE_CATEGORY_WATER: 'CommonGameTag' = 1522 + RECIPE_CATEGORY_WHOLE_PIE: 'CommonGameTag' = 2647 + RECIPE_CAULDRON_POTION: 'CommonGameTag' = 49154 + RECIPE_CHEFS_CHOICE_CHILD_FRIENDLY: 'CommonGameTag' = 1521 + RECIPE_CHILD_RESTRICTED: 'CommonGameTag' = 1523 + RECIPE_COURSE_APPETIZER: 'CommonGameTag' = 1507 + RECIPE_COURSE_DESSERT: 'CommonGameTag' = 1509 + RECIPE_COURSE_DRINK: 'CommonGameTag' = 1524 + RECIPE_COURSE_MAIN: 'CommonGameTag' = 1508 + RECIPE_FASHION_TRENDI_BROWSER: 'CommonGameTag' = 114703 + RECIPE_FLOWER_ARRANGEMENT: 'CommonGameTag' = 59472 + RECIPE_GROUP_COOKING_USES_CUTTING_BOARD: 'CommonGameTag' = 2669 + RECIPE_GROUP_COOKING_USES_CUTTING_BOARD_APPLE: 'CommonGameTag' = 2677 + RECIPE_GROUP_COOKING_USES_CUTTING_BOARD_ASPARAGUS: 'CommonGameTag' = 2678 + RECIPE_GROUP_COOKING_USES_CUTTING_BOARD_BEANS: 'CommonGameTag' = 2671 + RECIPE_GROUP_COOKING_USES_CUTTING_BOARD_BELLPEPPER: 'CommonGameTag' = 2679 + RECIPE_GROUP_COOKING_USES_CUTTING_BOARD_BREAD: 'CommonGameTag' = 2680 + RECIPE_GROUP_COOKING_USES_CUTTING_BOARD_CHICKEN: 'CommonGameTag' = 2672 + RECIPE_GROUP_COOKING_USES_CUTTING_BOARD_DOUGH: 'CommonGameTag' = 2673 + RECIPE_GROUP_COOKING_USES_CUTTING_BOARD_FISH: 'CommonGameTag' = 2674 + RECIPE_GROUP_COOKING_USES_CUTTING_BOARD_FISH_WHITE: 'CommonGameTag' = 2675 + RECIPE_GROUP_COOKING_USES_CUTTING_BOARD_LETTUCE: 'CommonGameTag' = 2681 + RECIPE_GROUP_COOKING_USES_CUTTING_BOARD_MEATRED: 'CommonGameTag' = 2676 + RECIPE_GROUP_COOKING_USES_CUTTING_BOARD_MELON: 'CommonGameTag' = 2682 + RECIPE_GROUP_COOKING_USES_CUTTING_BOARD_ONION: 'CommonGameTag' = 2683 + RECIPE_GROUP_COOKING_USES_CUTTING_BOARD_POTATO: 'CommonGameTag' = 2686 + RECIPE_GROUP_COOKING_USES_CUTTING_BOARD_SHRIMP: 'CommonGameTag' = 2684 + RECIPE_GROUP_COOKING_USES_CUTTING_BOARD_TOMATO: 'CommonGameTag' = 2685 + RECIPE_GROUP_COOKING_USES_MIXING_BOWL: 'CommonGameTag' = 2670 + RECIPE_GROUP_COOKING_USES_MIXING_BOWL_CASSOROLE_WHITE: 'CommonGameTag' = 2687 + RECIPE_GROUP_COOKING_USES_MIXING_BOWL_CHOCOLATE: 'CommonGameTag' = 2688 + RECIPE_GROUP_COOKING_USES_MIXING_BOWL_DOUGH: 'CommonGameTag' = 2690 + RECIPE_GROUP_COOKING_USES_MIXING_BOWL_EGGS: 'CommonGameTag' = 2695 + RECIPE_GROUP_COOKING_USES_MIXING_BOWL_MEAT: 'CommonGameTag' = 2694 + RECIPE_GROUP_COOKING_USES_MIXING_BOWL_PASTA: 'CommonGameTag' = 2693 + RECIPE_GROUP_COOKING_USES_MIXING_BOWL_SALAD: 'CommonGameTag' = 2689 + RECIPE_GROUP_COOKING_USES_MIXING_BOWL_SALAD_FRUIT: 'CommonGameTag' = 2692 + RECIPE_GROUP_COOKING_USES_MIXING_BOWL_SPICE: 'CommonGameTag' = 2691 + RECIPE_GROUP_COOKING_USES_MIXING_BOWL_WHITE_SAUCE: 'CommonGameTag' = 2696 + RECIPE_MEAL_BREAKFAST: 'CommonGameTag' = 1510 + RECIPE_MEAL_DINNER: 'CommonGameTag' = 1512 + RECIPE_MEAL_LUNCH: 'CommonGameTag' = 1511 + RECIPE_PLOPSY_BROWSER: 'CommonGameTag' = 83985 + RECIPE_TYPE_BAKING_SKILL: 'CommonGameTag' = 2621 + RECIPE_TYPE_COOKING_SKILL: 'CommonGameTag' = 2623 + RECIPE_TYPE_CROSS_STITCH_ANIMALS: 'CommonGameTag' = 112651 + RECIPE_TYPE_CROSS_STITCH_FOODS: 'CommonGameTag' = 112652 + RECIPE_TYPE_CROSS_STITCH_NATURE: 'CommonGameTag' = 112653 + RECIPE_TYPE_DRINK: 'CommonGameTag' = 1506 + RECIPE_TYPE_DRINK_PRANK: 'CommonGameTag' = 2423 + RECIPE_TYPE_FOOD: 'CommonGameTag' = 1505 + RECIPE_TYPE_GOURMET_COOKING_SKILL: 'CommonGameTag' = 2622 + RECIPE_TYPE_LIVESTOCK_FEED: 'CommonGameTag' = 2725 + RECIPE_TYPE_PET_DRINK: 'CommonGameTag' = 57425 + RECIPE_TYPE_PET_FOOD: 'CommonGameTag' = 57424 + REGION_ACTIVE_CAREER: 'CommonGameTag' = 12437 + REGION_CAMPING: 'CommonGameTag' = 1245 + REGION_JUNGLE: 'CommonGameTag' = 45059 + REGION_RESIDENTIAL: 'CommonGameTag' = 1244 + REGION_RETAIL: 'CommonGameTag' = 12374 + RESERVED_TEMP_BETA_FIX_DO_NOT_USE_1: 'CommonGameTag' = 138 + RESERVED_TEMP_BETA_FIX_DO_NOT_USE_2: 'CommonGameTag' = 139 + RESERVED_TEMP_BETA_FIX_DO_NOT_USE_3: 'CommonGameTag' = 142 + RESERVED_TEMP_BETA_FIX_DO_NOT_USE_4: 'CommonGameTag' = 143 + RESERVED_TEMP_BETA_FIX_DO_NOT_USE_5: 'CommonGameTag' = 144 + RESERVED_TEMP_BETA_FIX_DO_NOT_USE_6: 'CommonGameTag' = 147 + RESERVED_TEMP_BETA_FIX_DO_NOT_USE_7: 'CommonGameTag' = 281 + RESERVED_TEMP_BETA_FIX_DO_NOT_USE_8: 'CommonGameTag' = 284 + RESERVED_TEMP_BETA_FIX_DO_NOT_USE_9: 'CommonGameTag' = 290 + REWARD_CAS_PART: 'CommonGameTag' = 767 + ROLE_BAKE_ONE_CAKE: 'CommonGameTag' = 2277 + ROLE_BARTENDER: 'CommonGameTag' = 277 + ROLE_BUSINESS_CUSTOMER: 'CommonGameTag' = 1924 + ROLE_CAREER: 'CommonGameTag' = 467 + ROLE_CATERER: 'CommonGameTag' = 278 + ROLE_COLLEGE_ORGANIZATION_EVENT: 'CommonGameTag' = 65583 + ROLE_COWORKER: 'CommonGameTag' = 12292 + ROLE_CUSTOMER: 'CommonGameTag' = 2142 + ROLE_DATE: 'CommonGameTag' = 1439 + ROLE_DETECTIVE: 'CommonGameTag' = 12294 + ROLE_DOCTOR: 'CommonGameTag' = 12295 + ROLE_ENTERTAINER: 'CommonGameTag' = 650 + ROLE_EXCLUDE_FROM_YOGA_AND_MEDITATION_CLASS: 'CommonGameTag' = 2732 + ROLE_FESTIVAL_ARTS_CRAFTS: 'CommonGameTag' = 55317 + ROLE_FESTIVAL_BLOSSOM: 'CommonGameTag' = 55312 + ROLE_FESTIVAL_FLEA_MARKET: 'CommonGameTag' = 55318 + ROLE_FESTIVAL_FOOD: 'CommonGameTag' = 55315 + ROLE_FESTIVAL_LAMP: 'CommonGameTag' = 55313 + ROLE_FESTIVAL_LOGIC: 'CommonGameTag' = 55314 + ROLE_FESTIVAL_MUSIC: 'CommonGameTag' = 55316 + ROLE_FORTUNE_TELLER: 'CommonGameTag' = 8199 + ROLE_GUEST: 'CommonGameTag' = 266 + ROLE_HOST: 'CommonGameTag' = 267 + ROLE_HOST_AT_STATION: 'CommonGameTag' = 26635 + ROLE_LEAVE: 'CommonGameTag' = 418 + ROLE_MAID: 'CommonGameTag' = 279 + ROLE_NO_VISIT_COOLDOWN: 'CommonGameTag' = 2650 + ROLE_RESTAURANT_DINER: 'CommonGameTag' = 2147 + ROLE_RESTAURANT_EAT: 'CommonGameTag' = 2148 + ROLE_RESTAURANT_POST_PLACE_ORDER: 'CommonGameTag' = 2149 + ROLE_RESTAURANT_STAFF: 'CommonGameTag' = 26633 + ROLE_ROOMMATE_NPC: 'CommonGameTag' = 65541 + ROLE_SCIENTIST: 'CommonGameTag' = 12293 + ROLE_SERVICE: 'CommonGameTag' = 416 + ROLE_SPA_STAFF_BORED: 'CommonGameTag' = 18441 + ROLE_STATE_EP01_PATIENT_TREATED: 'CommonGameTag' = 12434 + ROLE_VET_PATIENT: 'CommonGameTag' = 57400 + ROLE_VIP_ROPE_ALLOWED: 'CommonGameTag' = 2143 + ROLE_WEDDING_PARTY: 'CommonGameTag' = 2748 + ROLE_YOGA_CLASS_POST_CLASS: 'CommonGameTag' = 18435 + ROLE_YOGA_PRE_CLASS: 'CommonGameTag' = 18463 + ROYALTY_APPS: 'CommonGameTag' = 908 + ROYALTY_BOOKS: 'CommonGameTag' = 909 + ROYALTY_GAMES: 'CommonGameTag' = 910 + ROYALTY_LYRICS: 'CommonGameTag' = 1629 + ROYALTY_PAINTINGS: 'CommonGameTag' = 911 + ROYALTY_SONGS: 'CommonGameTag' = 912 + SHOES_BOOTS: 'CommonGameTag' = 384 + SHOES_FLATS: 'CommonGameTag' = 385 + SHOES_HEELS: 'CommonGameTag' = 386 + SHOES_LACE_UP_ADULT: 'CommonGameTag' = 387 + SHOES_LACE_UP_CHILDREN: 'CommonGameTag' = 388 + SHOES_LOAFERS: 'CommonGameTag' = 389 + SHOES_SANDALS: 'CommonGameTag' = 390 + SHOES_SLIPPERS: 'CommonGameTag' = 391 + SHOES_SNEAKERS: 'CommonGameTag' = 392 + SHOES_WEDGES: 'CommonGameTag' = 393 + SICKNESS_CHECK_UP: 'CommonGameTag' = 57407 + SICKNESS_CURED_BY_EXAM_TABLE: 'CommonGameTag' = 57451 + SICKNESS_CURED_BY_SURGERY_STATION: 'CommonGameTag' = 57452 + SICKNESS_ILLNESS: 'CommonGameTag' = 57408 + SICKNESS_PET_EXAM: 'CommonGameTag' = 57403 + SITUATION_ACTIVE_CAREER: 'CommonGameTag' = 12358 + SITUATION_ACTIVE_CAREER_ADULT: 'CommonGameTag' = 2835 + SITUATION_ACTIVE_CAREER_HIGH_SCHOOL: 'CommonGameTag' = 114710 + SITUATION_ACTIVE_CAREER_SCIENTIST: 'CommonGameTag' = 12427 + SITUATION_ACTOR_CAREER_COMMERCIAL: 'CommonGameTag' = 61553 + SITUATION_ACTOR_CAREER_MOVIE: 'CommonGameTag' = 61556 + SITUATION_ACTOR_CAREER_PREP_TASK_ACTING: 'CommonGameTag' = 61615 + SITUATION_ACTOR_CAREER_PREP_TASK_CHARISMA: 'CommonGameTag' = 61458 + SITUATION_ACTOR_CAREER_PREP_TASK_COMEDY: 'CommonGameTag' = 61456 + SITUATION_ACTOR_CAREER_PREP_TASK_CO_STAR_REL: 'CommonGameTag' = 61454 + SITUATION_ACTOR_CAREER_PREP_TASK_DIRECTOR_REL: 'CommonGameTag' = 61455 + SITUATION_ACTOR_CAREER_PREP_TASK_FITNESS: 'CommonGameTag' = 61459 + SITUATION_ACTOR_CAREER_PREP_TASK_GUITAR: 'CommonGameTag' = 61460 + SITUATION_ACTOR_CAREER_PREP_TASK_HANDINESS: 'CommonGameTag' = 61457 + SITUATION_ACTOR_CAREER_PREP_TASK_PRACTICE_ACTION: 'CommonGameTag' = 61619 + SITUATION_ACTOR_CAREER_PREP_TASK_PRACTICE_DRAMATIC: 'CommonGameTag' = 61620 + SITUATION_ACTOR_CAREER_PREP_TASK_PRACTICE_ROMANTIC: 'CommonGameTag' = 61621 + SITUATION_ACTOR_CAREER_PREP_TASK_RESEARCH_FLIRTY: 'CommonGameTag' = 61616 + SITUATION_ACTOR_CAREER_PREP_TASK_RESEARCH_FUNNY: 'CommonGameTag' = 61617 + SITUATION_ACTOR_CAREER_PREP_TASK_RESEARCH_MEAN: 'CommonGameTag' = 61618 + SITUATION_ACTOR_CAREER_TV_HIGH: 'CommonGameTag' = 61555 + SITUATION_ACTOR_CAREER_TV_LOW: 'CommonGameTag' = 61554 + SITUATION_APARTMENT_NEIGHBOR_ANSWER_DOOR_COMPLAINT: 'CommonGameTag' = 55304 + SITUATION_APARTMENT_NEIGHBOR_LOUD_NOISES: 'CommonGameTag' = 55303 + SITUATION_BASKET_BALLER_A: 'CommonGameTag' = 55381 + SITUATION_BASKET_BALLER_B: 'CommonGameTag' = 55382 + SITUATION_BATUU_ARREST: 'CommonGameTag' = 51231 + SITUATION_BATUU_FR13_MISSION: 'CommonGameTag' = 51278 + SITUATION_BATUU_FS2_MISSION: 'CommonGameTag' = 51263 + SITUATION_BATUU_FS3_MISSION: 'CommonGameTag' = 51264 + SITUATION_BATUU_FS4_CRIMINAL: 'CommonGameTag' = 51255 + SITUATION_BATUU_FS6_MISSION: 'CommonGameTag' = 51262 + SITUATION_BATUU_FS7_MISSION: 'CommonGameTag' = 51261 + SITUATION_BATUU_INSPECTION: 'CommonGameTag' = 51232 + SITUATION_BATUU_MISSION_LIGHTSABER: 'CommonGameTag' = 51241 + SITUATION_BATUU_OGAS_CELEBRATION_BLACKLISTED: 'CommonGameTag' = 51243 + SITUATION_BATUU_RS2_MISSION: 'CommonGameTag' = 51272 + SITUATION_BATUU_RS4_MISSION: 'CommonGameTag' = 51269 + SITUATION_BATUU_RS6_MISSION: 'CommonGameTag' = 51273 + SITUATION_BATUU_RS7_MISSION: 'CommonGameTag' = 51274 + SITUATION_BATUU_SABACC_OPPONENT_1: 'CommonGameTag' = 51258 + SITUATION_BATUU_SABACC_OPPONENT_2: 'CommonGameTag' = 51259 + SITUATION_BATUU_SABACC_OPPONENT_3: 'CommonGameTag' = 51260 + SITUATION_BATUU_SR4_MISSION: 'CommonGameTag' = 51275 + SITUATION_BATUU_SR9_MISSION: 'CommonGameTag' = 51265 + SITUATION_BATUU_SS8_MISSION: 'CommonGameTag' = 51276 + SITUATION_BATUU_SS9_MISSION: 'CommonGameTag' = 51277 + SITUATION_BEAR: 'CommonGameTag' = 10247 + SITUATION_BONFIRE: 'CommonGameTag' = 24586 + SITUATION_BOWLING_GROUP: 'CommonGameTag' = 38919 + SITUATION_BOWLING_GROUP_2: 'CommonGameTag' = 38920 + SITUATION_BOWLING_GROUP_3: 'CommonGameTag' = 38921 + SITUATION_BOWLING_GROUP_4: 'CommonGameTag' = 38922 + SITUATION_BUSKER: 'CommonGameTag' = 55308 + SITUATION_BUTLER: 'CommonGameTag' = 36867 + SITUATION_CELEBRITY_FAN: 'CommonGameTag' = 61476 + SITUATION_CITY_INVITES: 'CommonGameTag' = 55380 + SITUATION_CITY_REPAIR: 'CommonGameTag' = 55355 + SITUATION_CLOWN: 'CommonGameTag' = 955 + SITUATION_COMPLAINT_NOISE: 'CommonGameTag' = 55425 + SITUATION_COOKING_INTERACTIONS: 'CommonGameTag' = 1017 + SITUATION_CRIMINAL: 'CommonGameTag' = 956 + SITUATION_DANCE_TOGETHER: 'CommonGameTag' = 24606 + SITUATION_DECORATOR_CAREER_HIDE_CLIENTS: 'CommonGameTag' = 53250 + SITUATION_DJ_PERFORMANCE: 'CommonGameTag' = 24582 + SITUATION_EVENT_NPC: 'CommonGameTag' = 1501 + SITUATION_FESTIVAL: 'CommonGameTag' = 55401 + SITUATION_FESTIVAL_BLOSSOM_ROMANTIC_COUPLE: 'CommonGameTag' = 55390 + SITUATION_FESTIVAL_LOGIC_ROCKET_SHIP_WOOHOOERS: 'CommonGameTag' = 55389 + SITUATION_FIREFIGHTER: 'CommonGameTag' = 2377 + SITUATION_FLOWER_BUNNY: 'CommonGameTag' = 59476 + SITUATION_FOREST_GHOST: 'CommonGameTag' = 10259 + SITUATION_FOREST_RANGER: 'CommonGameTag' = 10264 + SITUATION_FOX_ON_LOT: 'CommonGameTag' = 112671 + SITUATION_GARDENER: 'CommonGameTag' = 2152 + SITUATION_GNOME_BERSERK: 'CommonGameTag' = 59455 + SITUATION_GNOME_NORMAL: 'CommonGameTag' = 59454 + SITUATION_GP07_WALKBY_CONSPIRACIST_01: 'CommonGameTag' = 47158 + SITUATION_GP07_WALKBY_CONSPIRACIST_02: 'CommonGameTag' = 47159 + SITUATION_GP07_WALKBY_CONSPIRACIST_03: 'CommonGameTag' = 47160 + SITUATION_GP07_WALKBY_FBI_01: 'CommonGameTag' = 47161 + SITUATION_GP07_WALKBY_FBI_02: 'CommonGameTag' = 47162 + SITUATION_GP07_WALKBY_FBI_03: 'CommonGameTag' = 47163 + SITUATION_GP07_WALKBY_MILITARY_01: 'CommonGameTag' = 47150 + SITUATION_GP07_WALKBY_MILITARY_02: 'CommonGameTag' = 47151 + SITUATION_GP07_WALKBY_MILITARY_03: 'CommonGameTag' = 47152 + SITUATION_GP07_WALKBY_MILITARY_04: 'CommonGameTag' = 47153 + SITUATION_GP07_WALKBY_SCIENTIST_01: 'CommonGameTag' = 47154 + SITUATION_GP07_WALKBY_SCIENTIST_02: 'CommonGameTag' = 47155 + SITUATION_GP07_WALKBY_SCIENTIST_03: 'CommonGameTag' = 47156 + SITUATION_GP07_WALKBY_SCIENTIST_04: 'CommonGameTag' = 47157 + SITUATION_GRILL_GROUP: 'CommonGameTag' = 1461 + SITUATION_GROUP_CHEER: 'CommonGameTag' = 114739 + SITUATION_GROUP_COOKING: 'CommonGameTag' = 2646 + SITUATION_GROUP_DANCING: 'CommonGameTag' = 133127 + SITUATION_GROUP_WALKING: 'CommonGameTag' = 116747 + SITUATION_HIGH_SCHOOL_ACTIVE_HOOKY_AT_SCHOOL: 'CommonGameTag' = 114711 + SITUATION_HIKING_TRAIL: 'CommonGameTag' = 69746 + SITUATION_HIRED_NANNY: 'CommonGameTag' = 1550 + SITUATION_HOLIDAY: 'CommonGameTag' = 59460 + SITUATION_HOME_CHEF: 'CommonGameTag' = 26642 + SITUATION_HOT_DOG: 'CommonGameTag' = 958 + SITUATION_INTERIOR_DECORATOR_GIG_DEPENDENT: 'CommonGameTag' = 53252 + SITUATION_INTRIGUED_NOISE: 'CommonGameTag' = 55426 + SITUATION_INTRIGUED_SMELL: 'CommonGameTag' = 55427 + SITUATION_ISLAND_SPIRITS: 'CommonGameTag' = 63496 + SITUATION_KIDS_BIKE_PRACTICE: 'CommonGameTag' = 116742 + SITUATION_LIVES_ON_STREET_A: 'CommonGameTag' = 55435 + SITUATION_LIVES_ON_STREET_B: 'CommonGameTag' = 55436 + SITUATION_LIVES_ON_STREET_C: 'CommonGameTag' = 55437 + SITUATION_LIVES_ON_STREET_D: 'CommonGameTag' = 55438 + SITUATION_MAID: 'CommonGameTag' = 957 + SITUATION_MAILMAN: 'CommonGameTag' = 1343 + SITUATION_MARKET_STALL_VENDOR: 'CommonGameTag' = 1949 + SITUATION_MASTER_FISHERMAN: 'CommonGameTag' = 889 + SITUATION_MASTER_GARDENER: 'CommonGameTag' = 890 + SITUATION_MURAL_PAINTER: 'CommonGameTag' = 55383 + SITUATION_NIGHT_TIME_VISIT: 'CommonGameTag' = 1679 + SITUATION_PET_OBSTACLE_COURSE: 'CommonGameTag' = 57427 + SITUATION_PICNIC_TABLE: 'CommonGameTag' = 1460 + SITUATION_PIZZA: 'CommonGameTag' = 960 + SITUATION_PLAYER_FACING_CAN_HOST: 'CommonGameTag' = 1643 + SITUATION_PLAYER_VISITING_NPC: 'CommonGameTag' = 1493 + SITUATION_POSSESSED: 'CommonGameTag' = 47124 + SITUATION_PROMO_NIGHT: 'CommonGameTag' = 24594 + SITUATION_RANCH_HAND: 'CommonGameTag' = 118800 + SITUATION_REAPER: 'CommonGameTag' = 959 + SITUATION_REPAIRMAN: 'CommonGameTag' = 2153 + SITUATION_RESTAURANT_DINING: 'CommonGameTag' = 2146 + SITUATION_RETAIL_CUSTOMER: 'CommonGameTag' = 12323 + SITUATION_RETAIL_EMPLOYEE: 'CommonGameTag' = 12324 + SITUATION_RING_DOORBELL: 'CommonGameTag' = 684 + SITUATION_ROOMMATE_NPC_POTENTIAL: 'CommonGameTag' = 65572 + SITUATION_SECRET_SOCIETY: 'CommonGameTag' = 65570 + SITUATION_SLEEP_OVER: 'CommonGameTag' = 116741 + SITUATION_SPOOKY_PARTY: 'CommonGameTag' = 22541 + SITUATION_SQUAD: 'CommonGameTag' = 61634 + SITUATION_STAY_OVER: 'CommonGameTag' = 116748 + SITUATION_SUN_RAY: 'CommonGameTag' = 67647 + SITUATION_TRAGIC_CLOWN: 'CommonGameTag' = 1504 + SITUATION_TUTORIAL_FTUE: 'CommonGameTag' = 2167 + SITUATION_UMBRELLA_USER: 'CommonGameTag' = 2119 + SITUATION_UNIVERSITY_HOUSING_KICK_OUT_BLOCKER: 'CommonGameTag' = 65571 + SITUATION_UNIVERSITY_RIVALS_PRANK: 'CommonGameTag' = 65606 + SITUATION_VENUE_KARAOKE_DUETERS: 'CommonGameTag' = 55391 + SITUATION_VET_PLAYER_PET_OWNER: 'CommonGameTag' = 2498 + SITUATION_VET_SICK_PET: 'CommonGameTag' = 2499 + SITUATION_VIP_ROPE_BOUNCER: 'CommonGameTag' = 61613 + SITUATION_VISITOR_NPCS: 'CommonGameTag' = 2282 + SITUATION_VISITOR_NPC_ANGRY_SIM: 'CommonGameTag' = 67606 + SITUATION_WAIT_IN_LINE_TOGETHER: 'CommonGameTag' = 2496 + SITUATION_WALKBY_FIRST_ORDER_OFFICER_SPY: 'CommonGameTag' = 51226 + SITUATION_WEATHER_RAIN_HEAVY: 'CommonGameTag' = 2078 + SITUATION_WEATHER_RAIN_LIGHT: 'CommonGameTag' = 2079 + SITUATION_WEATHER_RAIN_STORM: 'CommonGameTag' = 2077 + SITUATION_WEATHER_SNOW_HEAVY: 'CommonGameTag' = 2080 + SITUATION_WEATHER_SNOW_STORM: 'CommonGameTag' = 2081 + SITUATION_WEDDING: 'CommonGameTag' = 133148 + SITUATION_WEIRDO: 'CommonGameTag' = 55309 + SITUATION_WELCOME_WAGON: 'CommonGameTag' = 1457 + SITUATION_WELCOME_WAGON_MAIN: 'CommonGameTag' = 2844 + SITUATION_YOGA_CLASS: 'CommonGameTag' = 18462 + SKILL_ADULT: 'CommonGameTag' = 2925 + SKILL_ALL: 'CommonGameTag' = 448 + SKILL_ALL_VISIBLE: 'CommonGameTag' = 2097 + SKILL_ARCHAEOLOGY: 'CommonGameTag' = 45094 + SKILL_ATHLETIC: 'CommonGameTag' = 86 + SKILL_BARTENDING: 'CommonGameTag' = 137 + SKILL_CHARISMA: 'CommonGameTag' = 676 + SKILL_CHILD: 'CommonGameTag' = 641 + SKILL_CLIMBING_SKIING_SNOWBOARDING: 'CommonGameTag' = 69698 + SKILL_COMEDY: 'CommonGameTag' = 2797 + SKILL_COMEDY_OR_MISCHIEF: 'CommonGameTag' = 1576 + SKILL_COOKING: 'CommonGameTag' = 87 + SKILL_CREATIVE: 'CommonGameTag' = 336 + SKILL_CROSS_STITCH: 'CommonGameTag' = 112661 + SKILL_DOG_TRAINING: 'CommonGameTag' = 57367 + SKILL_EQUESTRIAN_SKILL: 'CommonGameTag' = 2979 + SKILL_FITNESS_OR_PROGRAMMING: 'CommonGameTag' = 652 + SKILL_FLOWER_ARRANGING: 'CommonGameTag' = 59451 + SKILL_GARDENING: 'CommonGameTag' = 1605 + SKILL_GUITAR_OR_COMEDY: 'CommonGameTag' = 935 + SKILL_HANDINESS: 'CommonGameTag' = 1368 + SKILL_HORSE: 'CommonGameTag' = 2974 + SKILL_JUICE_FIZZING: 'CommonGameTag' = 67620 + SKILL_KNITTING: 'CommonGameTag' = 2626 + SKILL_LIFE: 'CommonGameTag' = 2986 + SKILL_LOCAL_CULTURE: 'CommonGameTag' = 45070 + SKILL_LOGIC: 'CommonGameTag' = 677 + SKILL_MENTAL: 'CommonGameTag' = 337 + SKILL_MENTORABLE: 'CommonGameTag' = 2765 + SKILL_MISCHIEF: 'CommonGameTag' = 2796 + SKILL_MUSICAL: 'CommonGameTag' = 445 + SKILL_MUSIC_OR_COMEDY: 'CommonGameTag' = 55305 + SKILL_PAINTING: 'CommonGameTag' = 1607 + SKILL_PERFORMANCE: 'CommonGameTag' = 1630 + SKILL_PHOTOGRAPHY: 'CommonGameTag' = 1940 + SKILL_PHOTOGRAPHY_BG: 'CommonGameTag' = 1609 + SKILL_PHYSICAL: 'CommonGameTag' = 338 + SKILL_PIPE_ORGAN: 'CommonGameTag' = 40969 + SKILL_PROGRAMMING: 'CommonGameTag' = 1606 + SKILL_PSYCHIC: 'CommonGameTag' = 8194 + SKILL_RANCH_NECTAR: 'CommonGameTag' = 2987 + SKILL_ROCKET_SCIENCE: 'CommonGameTag' = 678 + SKILL_ROCK_CLIMBING: 'CommonGameTag' = 69697 + SKILL_SCHOOL_TASK: 'CommonGameTag' = 1653 + SKILL_SINGING: 'CommonGameTag' = 1633 + SKILL_SKATING: 'CommonGameTag' = 59393 + SKILL_SKIING: 'CommonGameTag' = 69637 + SKILL_SNOWBOARDING: 'CommonGameTag' = 69696 + SKILL_SOCIAL: 'CommonGameTag' = 339 + SKILL_TODDLER: 'CommonGameTag' = 1655 + SKILL_VIDEO_GAMING: 'CommonGameTag' = 675 + SKILL_VIOLIN_OR_GUITAR: 'CommonGameTag' = 936 + SKILL_WELLNESS: 'CommonGameTag' = 18466 + SKILL_WELLNESS_BG: 'CommonGameTag' = 1608 + SKILL_WRITING: 'CommonGameTag' = 679 + SKINTONE_BLEND_YES: 'CommonGameTag' = 1458 + SKINTONE_TYPE_FANTASY: 'CommonGameTag' = 12317 + SKINTONE_TYPE_NATURAL: 'CommonGameTag' = 12316 + SKINTONE_TYPE_SICKNESS_1: 'CommonGameTag' = 12320 + SKINTONE_TYPE_SICKNESS_2: 'CommonGameTag' = 12321 + SKINTONE_TYPE_SICKNESS_3: 'CommonGameTag' = 12322 + SKINTONE_TYPE_SICKNESS_GREEN: 'CommonGameTag' = 12325 + SKIN_HUE_BLUE: 'CommonGameTag' = 12382 + SKIN_HUE_BLUE_SKIN: 'CommonGameTag' = 1449 + SKIN_HUE_GREEN: 'CommonGameTag' = 12389 + SKIN_HUE_GREEN_SKIN: 'CommonGameTag' = 1450 + SKIN_HUE_OLIVE: 'CommonGameTag' = 763 + SKIN_HUE_PURPLE: 'CommonGameTag' = 12390 + SKIN_HUE_RED: 'CommonGameTag' = 761 + SKIN_HUE_RED_SKIN: 'CommonGameTag' = 1625 + SKIN_HUE_YELLOW: 'CommonGameTag' = 762 + SKIN_VALUE_0: 'CommonGameTag' = 114730 + SKIN_VALUE_1: 'CommonGameTag' = 114725 + SKIN_VALUE_2: 'CommonGameTag' = 114726 + SKIN_VALUE_3: 'CommonGameTag' = 114727 + SKIN_VALUE_4: 'CommonGameTag' = 114728 + SKIN_VALUE_5: 'CommonGameTag' = 114729 + SOCIAL_BLACK_AND_WHITE: 'CommonGameTag' = 686 + SOCIAL_COSTUME_PARTY: 'CommonGameTag' = 687 + SOCIAL_FLIRTY: 'CommonGameTag' = 340 + SOCIAL_WEENIE_ROAST: 'CommonGameTag' = 10244 + SOCIAL_WOOHOO: 'CommonGameTag' = 364 + SP03_PLEASE_REUSE_ME_I_WAS_BLANK_ON_ACCIDENT: 'CommonGameTag' = 20487 + SP03_PLEASE_REUSE_ME_I_WAS_BLANK_ON_ACCIDENT_2: 'CommonGameTag' = 20488 + SPAWN_ARRIVAL: 'CommonGameTag' = 397 + SPAWN_ARTS_PARK: 'CommonGameTag' = 65622 + SPAWN_ARTS_QUAD: 'CommonGameTag' = 65619 + SPAWN_ARTS_UNIVERSITY_SHELL: 'CommonGameTag' = 65546 + SPAWN_ARTS_UNIVERSITY_SHELL_SHELL_1: 'CommonGameTag' = 65556 + SPAWN_ARTS_UNIVERSITY_SHELL_SHELL_2: 'CommonGameTag' = 65557 + SPAWN_BATTLE_HELPER: 'CommonGameTag' = 47133 + SPAWN_BATUU_DWELLING: 'CommonGameTag' = 51216 + SPAWN_BATUU_FIRST_ORDER_PATROL: 'CommonGameTag' = 51227 + SPAWN_BATUU_LT_AGNON: 'CommonGameTag' = 51218 + SPAWN_BATUU_RESISTANCE_PATROL_1: 'CommonGameTag' = 51228 + SPAWN_BATUU_RESISTANCE_PATROL_2: 'CommonGameTag' = 51229 + SPAWN_BATUU_VI_MORADI: 'CommonGameTag' = 51217 + SPAWN_CLOTHING_STORE: 'CommonGameTag' = 118795 + SPAWN_COTTAGE_WORLD_CRITTER_TENDER: 'CommonGameTag' = 112670 + SPAWN_COTTAGE_WORLD_FOXHOLE: 'CommonGameTag' = 112669 + SPAWN_EQUESTRIAN_CENTER: 'CommonGameTag' = 118793 + SPAWN_EQUESTRIAN_CENTER_EXIT: 'CommonGameTag' = 118872 + SPAWN_FIREPLACE: 'CommonGameTag' = 2057 + SPAWN_GENERIC_01: 'CommonGameTag' = 2465 + SPAWN_GENERIC_02: 'CommonGameTag' = 2466 + SPAWN_GENERIC_03: 'CommonGameTag' = 2467 + SPAWN_GENERIC_04: 'CommonGameTag' = 2468 + SPAWN_GENERIC_05: 'CommonGameTag' = 2469 + SPAWN_GRIM_REAPER: 'CommonGameTag' = 987 + SPAWN_GROCERY_STORE: 'CommonGameTag' = 118794 + SPAWN_LIGHTHOUSE: 'CommonGameTag' = 57409 + SPAWN_LIGHTHOUSE_ARRIVAL: 'CommonGameTag' = 1935 + SPAWN_MAGIC_PORTAL: 'CommonGameTag' = 2223 + SPAWN_MAGIC_PORTAL_MARKET: 'CommonGameTag' = 49182 + SPAWN_MARKET_STALL_MAGIC_BROOM: 'CommonGameTag' = 49166 + SPAWN_MARKET_STALL_MAGIC_POTION: 'CommonGameTag' = 49171 + SPAWN_MARKET_STALL_MAGIC_WAND: 'CommonGameTag' = 49172 + SPAWN_MARKET_STALL_WEDDING_CHINESE: 'CommonGameTag' = 133123 + SPAWN_MARKET_STALL_WEDDING_INDIAN: 'CommonGameTag' = 133124 + SPAWN_MARKET_STALL_WEDDING_PATISSERIE: 'CommonGameTag' = 133125 + SPAWN_MUSIC_FESTIVAL: 'CommonGameTag' = 2559 + SPAWN_NIGHT_STALKER: 'CommonGameTag' = 49158 + SPAWN_PET_CRATE: 'CommonGameTag' = 57387 + SPAWN_PIER_ARRIVAL: 'CommonGameTag' = 114749 + SPAWN_REAR_WALKBY: 'CommonGameTag' = 400 + SPAWN_SCIENCE_QUAD: 'CommonGameTag' = 65620 + SPAWN_SCIENCE_UNIVERSITY_SHELL: 'CommonGameTag' = 65547 + SPAWN_SCIENCE_UNIVERSITY_SHELL_SHELL_1: 'CommonGameTag' = 65558 + SPAWN_SCIENCE_UNIVERSITY_SHELL_SHELL_2: 'CommonGameTag' = 65559 + SPAWN_SEANCE: 'CommonGameTag' = 86021 + SPAWN_SECRET_SOCIETY: 'CommonGameTag' = 65621 + SPAWN_SHELL_ARRIVAL: 'CommonGameTag' = 1933 + SPAWN_SKELETON_ARRIVAL: 'CommonGameTag' = 2039 + SPAWN_SNOW_SPORTS_SLOPE_BUNNY_SLOPE: 'CommonGameTag' = 69740 + SPAWN_STAGE_ARTIST: 'CommonGameTag' = 2560 + SPAWN_STARSHIP: 'CommonGameTag' = 51215 + SPAWN_VISITOR_ARRIVAL: 'CommonGameTag' = 399 + SPAWN_WALKBY: 'CommonGameTag' = 398 + SPAWN_WALKBY_SPORTS_SHELL_EP08: 'CommonGameTag' = 2234 + SPAWN_WALK_BY_SHELL_01: 'CommonGameTag' = 2924 + SPAWN_WOLF_TOWN_GREG: 'CommonGameTag' = 135181 + SPAWN_WOLF_TOWN_HOWL_SPOT_TOP: 'CommonGameTag' = 135182 + SPAWN_WOLF_TOWN_MINE: 'CommonGameTag' = 135177 + SPAWN_WOLF_TOWN_ON_LOT_VERSION: 'CommonGameTag' = 135180 + SPAWN_WOLF_TOWN_PORTA_POTTY: 'CommonGameTag' = 135178 + SPAWN_WOLF_TOWN_SEWER: 'CommonGameTag' = 135179 + SPAWN_ZOMBIE: 'CommonGameTag' = 47132 + SPECIAL_CONTENT_ANNIVERSARY_21: 'CommonGameTag' = 2521 + SPECIAL_NUDE: 'CommonGameTag' = 127 + SPELL_MAGIC: 'CommonGameTag' = 49170 + STYLE_ARTS_QUARTER: 'CommonGameTag' = 55330 + STYLE_BOHEMIAN: 'CommonGameTag' = 1495 + STYLE_BUSINESS: 'CommonGameTag' = 1593 + STYLE_CAS_BLACK_HISTORY_MONTH: 'CommonGameTag' = 2768 + STYLE_CAS_BRANDED_ANNIVERSARY_21: 'CommonGameTag' = 2520 + STYLE_CAS_BRANDED_MAC: 'CommonGameTag' = 2433 + STYLE_CAS_BRANDED_ME_UNDIES: 'CommonGameTag' = 167937 + STYLE_CAS_DEPOP: 'CommonGameTag' = 114740 + STYLE_CAS_DESIGNED_BY: 'CommonGameTag' = 2909 + STYLE_CAS_EBONIX_NAILS: 'CommonGameTag' = 18485 + STYLE_CLASSICS: 'CommonGameTag' = 239 + STYLE_COUNTRY: 'CommonGameTag' = 985 + STYLE_FASHION_DISTRICT: 'CommonGameTag' = 55331 + STYLE_FESTIVAL_BLOSSOM: 'CommonGameTag' = 55348 + STYLE_FESTIVAL_DARK: 'CommonGameTag' = 1623 + STYLE_FESTIVAL_FOOD: 'CommonGameTag' = 1624 + STYLE_FESTIVAL_LIGHT: 'CommonGameTag' = 1622 + STYLE_FESTIVAL_NERD: 'CommonGameTag' = 1621 + STYLE_FESTIVAL_ROMANCE: 'CommonGameTag' = 1620 + STYLE_FORMAL_MODERN: 'CommonGameTag' = 248 + STYLE_FORMAL_TRENDY: 'CommonGameTag' = 249 + STYLE_FRANKENSTEIN: 'CommonGameTag' = 8197 + STYLE_GAMER: 'CommonGameTag' = 2842 + STYLE_GEN_CITY_SLEEK: 'CommonGameTag' = 238 + STYLE_GEN_CONTEMPORARY_BASIC: 'CommonGameTag' = 240 + STYLE_GEN_CONTEMPORARY_DESIGNER: 'CommonGameTag' = 241 + STYLE_GEN_OUTDOOR_EXPLORER: 'CommonGameTag' = 243 + STYLE_GEN_PARTY_TRENDY: 'CommonGameTag' = 244 + STYLE_GEN_POLISHED: 'CommonGameTag' = 245 + STYLE_GEN_PREPPY: 'CommonGameTag' = 246 + STYLE_GEN_ROMANTIC: 'CommonGameTag' = 247 + STYLE_GEN_SUMMER: 'CommonGameTag' = 237 + STYLE_GLAMPING: 'CommonGameTag' = 10265 + STYLE_GOTH_ROCK_PUNK: 'CommonGameTag' = 289 + STYLE_HIPSTER: 'CommonGameTag' = 986 + STYLE_ISLANDER: 'CommonGameTag' = 63495 + STYLE_ISLAND_ELEMENTAL: 'CommonGameTag' = 63517 + STYLE_JAPANESE_CONTEMPORARY: 'CommonGameTag' = 69693 + STYLE_JUNGLE: 'CommonGameTag' = 2036 + STYLE_NATIVE_AMERICAN: 'CommonGameTag' = 2995 + STYLE_PIRATE: 'CommonGameTag' = 8196 + STYLE_PROFESSOR_NPC_GOOD: 'CommonGameTag' = 65597 + STYLE_PROFESSOR_NPC_GRUMPY: 'CommonGameTag' = 65596 + STYLE_PROFESSOR_NPC_HIP: 'CommonGameTag' = 65595 + STYLE_PROFESSOR_NPC_SMART: 'CommonGameTag' = 65598 + STYLE_SEASONAL_FALL: 'CommonGameTag' = 2066 + STYLE_SEASONAL_SPRING: 'CommonGameTag' = 2067 + STYLE_SEASONAL_SUMMER: 'CommonGameTag' = 2068 + STYLE_SEASONAL_WINTER: 'CommonGameTag' = 2065 + STYLE_SHABBY: 'CommonGameTag' = 2780 + STYLE_SPICE_MARKET: 'CommonGameTag' = 55332 + STYLE_SPORTY: 'CommonGameTag' = 2843 + STYLE_STREET: 'CommonGameTag' = 1592 + STYLE_VAMPIRE_ARCHETYPE_DRACULA: 'CommonGameTag' = 1681 + STYLE_VAMPIRE_ARCHETYPE_MODERN: 'CommonGameTag' = 1682 + STYLE_VAMPIRE_ARCHETYPE_NOSFERATU: 'CommonGameTag' = 1680 + STYLE_VAMPIRE_ARCHETYPE_PUNK: 'CommonGameTag' = 1684 + STYLE_VAMPIRE_ARCHETYPE_VICTORIAN: 'CommonGameTag' = 1683 + STYLE_VAMPIRE_WALKBY_MODERN: 'CommonGameTag' = 40966 + STYLE_VAMPIRE_WALKBY_NOSFERATU: 'CommonGameTag' = 40964 + STYLE_VAMPIRE_WALKBY_PUNK: 'CommonGameTag' = 40968 + STYLE_VAMPIRE_WALKBY_VICTORIAN: 'CommonGameTag' = 40967 + STYLE_WITCH: 'CommonGameTag' = 8195 + TAIL_LONG: 'CommonGameTag' = 2707 + TAIL_RING: 'CommonGameTag' = 2704 + TAIL_SABER: 'CommonGameTag' = 2705 + TAIL_SCREW: 'CommonGameTag' = 2706 + TAIL_STUB: 'CommonGameTag' = 2708 + TERRAIN_MANIP_ALL: 'CommonGameTag' = 2169 + TERRAIN_PAINT_ALL: 'CommonGameTag' = 1082 + TERRAIN_PAINT_DIRT: 'CommonGameTag' = 872 + TERRAIN_PAINT_GRASS: 'CommonGameTag' = 873 + TERRAIN_PAINT_MISC: 'CommonGameTag' = 875 + TERRAIN_PAINT_STONE: 'CommonGameTag' = 874 + TOOLTIP_AMBIENCE_ANGRY: 'CommonGameTag' = 732 + TOOLTIP_AMBIENCE_BORED: 'CommonGameTag' = 733 + TOOLTIP_AMBIENCE_CONFIDENT: 'CommonGameTag' = 734 + TOOLTIP_AMBIENCE_EMBARRASSED: 'CommonGameTag' = 735 + TOOLTIP_AMBIENCE_ENERGIZED: 'CommonGameTag' = 736 + TOOLTIP_AMBIENCE_FLIRTY: 'CommonGameTag' = 737 + TOOLTIP_AMBIENCE_FOCUSED: 'CommonGameTag' = 738 + TOOLTIP_AMBIENCE_HAPPY: 'CommonGameTag' = 739 + TOOLTIP_AMBIENCE_IMAGINATIVE: 'CommonGameTag' = 740 + TOOLTIP_AMBIENCE_PLAYFUL: 'CommonGameTag' = 741 + TOOLTIP_AMBIENCE_SAD: 'CommonGameTag' = 742 + TOOLTIP_AMBIENCE_TENSE: 'CommonGameTag' = 743 + TOOLTIP_BILLS_DECREASE: 'CommonGameTag' = 2396 + TOOLTIP_BILLS_INCREASE: 'CommonGameTag' = 2395 + TOOLTIP_COLUMN_HEIGHT_RESTRICTED: 'CommonGameTag' = 2238 + TOOLTIP_CRAFTING_QUALITY_CARPENTRY: 'CommonGameTag' = 706 + TOOLTIP_CRAFTING_QUALITY_COOKING: 'CommonGameTag' = 703 + TOOLTIP_CRAFTING_QUALITY_DRINKS: 'CommonGameTag' = 704 + TOOLTIP_CRAFTING_QUALITY_PAINTING: 'CommonGameTag' = 705 + TOOLTIP_ECO_FOOTPRINT_NEGATIVE: 'CommonGameTag' = 67624 + TOOLTIP_ECO_FOOTPRINT_POSITIVE: 'CommonGameTag' = 67623 + TOOLTIP_ENVIRONMENT_SCORE_NEGATIVE: 'CommonGameTag' = 2389 + TOOLTIP_ENVIRONMENT_SCORE_POSITIVE: 'CommonGameTag' = 2390 + TOOLTIP_EP02_SKILL_DANCE: 'CommonGameTag' = 3001 + TOOLTIP_EP09_ECO_FOOTPRINT_NEGATIVE: 'CommonGameTag' = 2422 + TOOLTIP_EP09_ECO_FOOTPRINT_POSITIVE: 'CommonGameTag' = 2421 + TOOLTIP_HIGH_FIRE_RESISTANCE: 'CommonGameTag' = 2392 + TOOLTIP_HIGH_WATER_RESISTANCE: 'CommonGameTag' = 2394 + TOOLTIP_LOW_FIRE_RESISTANCE: 'CommonGameTag' = 2391 + TOOLTIP_LOW_WATER_RESISTANCE: 'CommonGameTag' = 2393 + TOOLTIP_MISC_CATS_ONLY: 'CommonGameTag' = 2027 + TOOLTIP_MISC_CHILDREN_ONLY: 'CommonGameTag' = 783 + TOOLTIP_MISC_CHILDREN_TODDLER_INFANT_ONLY: 'CommonGameTag' = 2960 + TOOLTIP_MISC_CHILDREN_TODDLER_ONLY: 'CommonGameTag' = 2959 + TOOLTIP_MISC_COMFORT: 'CommonGameTag' = 784 + TOOLTIP_MISC_DOGS_ONLY: 'CommonGameTag' = 2026 + TOOLTIP_MISC_INFANT_ONLY: 'CommonGameTag' = 2958 + TOOLTIP_MISC_NEWBORN_ONLY: 'CommonGameTag' = 2927 + TOOLTIP_MISC_PETS_ONLY: 'CommonGameTag' = 2025 + TOOLTIP_MISC_RELIABILITY: 'CommonGameTag' = 907 + TOOLTIP_MISC_TODDLER_INFANT_ONLY: 'CommonGameTag' = 2961 + TOOLTIP_MISC_TODDLER_ONLY: 'CommonGameTag' = 1667 + TOOLTIP_MISC_UNBREAKABLE: 'CommonGameTag' = 731 + TOOLTIP_MISC_UNCOMFORTABLE: 'CommonGameTag' = 747 + TOOLTIP_MISC_UNCOMFORTABLE_FOR_ADULTS: 'CommonGameTag' = 940 + TOOLTIP_MISC_WEREWOLF_ONLY_DOOR: 'CommonGameTag' = 2783 + TOOLTIP_MOOD_RELIEF_ANGRY: 'CommonGameTag' = 710 + TOOLTIP_MOOD_RELIEF_BORED: 'CommonGameTag' = 711 + TOOLTIP_MOOD_RELIEF_EMBARRASSED: 'CommonGameTag' = 712 + TOOLTIP_MOOD_RELIEF_SAD: 'CommonGameTag' = 709 + TOOLTIP_MOOD_RELIEF_STRESS: 'CommonGameTag' = 707 + TOOLTIP_MOOD_RELIEF_UNCOMFORTABLE: 'CommonGameTag' = 708 + TOOLTIP_MOTIVE_BLADDER: 'CommonGameTag' = 701 + TOOLTIP_MOTIVE_ENERGY: 'CommonGameTag' = 698 + TOOLTIP_MOTIVE_FUN: 'CommonGameTag' = 699 + TOOLTIP_MOTIVE_HUNGER: 'CommonGameTag' = 702 + TOOLTIP_MOTIVE_HYGIENE: 'CommonGameTag' = 697 + TOOLTIP_MOTIVE_SOCIAL: 'CommonGameTag' = 700 + TOOLTIP_OFF_THE_GRID: 'CommonGameTag' = 2207 + TOOLTIP_POWER_CONSUMER: 'CommonGameTag' = 2398 + TOOLTIP_POWER_PRODUCER: 'CommonGameTag' = 2397 + TOOLTIP_SKILL_ACTING: 'CommonGameTag' = 61637 + TOOLTIP_SKILL_AGILITY: 'CommonGameTag' = 2999 + TOOLTIP_SKILL_ARCHAEOLOGY: 'CommonGameTag' = 45110 + TOOLTIP_SKILL_BARTENDING: 'CommonGameTag' = 717 + TOOLTIP_SKILL_CHARISMA: 'CommonGameTag' = 729 + TOOLTIP_SKILL_COMEDY: 'CommonGameTag' = 726 + TOOLTIP_SKILL_COMMUNICATION: 'CommonGameTag' = 1670 + TOOLTIP_SKILL_COOKING: 'CommonGameTag' = 713 + TOOLTIP_SKILL_CREATIVITY: 'CommonGameTag' = 927 + TOOLTIP_SKILL_DANCE: 'CommonGameTag' = 24615 + TOOLTIP_SKILL_DJ: 'CommonGameTag' = 24614 + TOOLTIP_SKILL_DOG_TRAINING: 'CommonGameTag' = 2023 + TOOLTIP_SKILL_ENTREPRENEUR: 'CommonGameTag' = 2964 + TOOLTIP_SKILL_EQUESTRIAN: 'CommonGameTag' = 3000 + TOOLTIP_SKILL_FITNESS: 'CommonGameTag' = 716 + TOOLTIP_SKILL_FLOWER_ARRANGING: 'CommonGameTag' = 2115 + TOOLTIP_SKILL_GARDENING: 'CommonGameTag' = 728 + TOOLTIP_SKILL_GUITAR: 'CommonGameTag' = 727 + TOOLTIP_SKILL_HANDINESS: 'CommonGameTag' = 719 + TOOLTIP_SKILL_IMAGINATION: 'CommonGameTag' = 1669 + TOOLTIP_SKILL_JUMPING: 'CommonGameTag' = 2998 + TOOLTIP_SKILL_LOGIC: 'CommonGameTag' = 721 + TOOLTIP_SKILL_MENTAL: 'CommonGameTag' = 928 + TOOLTIP_SKILL_MISCHIEF: 'CommonGameTag' = 722 + TOOLTIP_SKILL_MOTOR: 'CommonGameTag' = 929 + TOOLTIP_SKILL_MOVEMENT: 'CommonGameTag' = 1668 + TOOLTIP_SKILL_NECTAR_MAKING: 'CommonGameTag' = 2997 + TOOLTIP_SKILL_PAINTING: 'CommonGameTag' = 718 + TOOLTIP_SKILL_PARENTING: 'CommonGameTag' = 2962 + TOOLTIP_SKILL_PIANO: 'CommonGameTag' = 724 + TOOLTIP_SKILL_PIPE_ORGAN: 'CommonGameTag' = 40978 + TOOLTIP_SKILL_POTTY: 'CommonGameTag' = 1672 + TOOLTIP_SKILL_PROGRAMMING: 'CommonGameTag' = 715 + TOOLTIP_SKILL_PSYCHIC: 'CommonGameTag' = 8212 + TOOLTIP_SKILL_RESEARCH_DEBATE: 'CommonGameTag' = 2269 + TOOLTIP_SKILL_ROBOTICS: 'CommonGameTag' = 2270 + TOOLTIP_SKILL_ROCKET_SCIENCE: 'CommonGameTag' = 720 + TOOLTIP_SKILL_SINGING: 'CommonGameTag' = 55434 + TOOLTIP_SKILL_SKIING: 'CommonGameTag' = 2965 + TOOLTIP_SKILL_SNOWBOARDING: 'CommonGameTag' = 2966 + TOOLTIP_SKILL_SOCIAL: 'CommonGameTag' = 930 + TOOLTIP_SKILL_THINKING: 'CommonGameTag' = 1671 + TOOLTIP_SKILL_VAMPIRE_LORE: 'CommonGameTag' = 2963 + TOOLTIP_SKILL_VET: 'CommonGameTag' = 2024 + TOOLTIP_SKILL_VIDEO_GAMING: 'CommonGameTag' = 714 + TOOLTIP_SKILL_VIOLIN: 'CommonGameTag' = 725 + TOOLTIP_SKILL_WELLNESS: 'CommonGameTag' = 18459 + TOOLTIP_SKILL_WOOHOO: 'CommonGameTag' = 730 + TOOLTIP_SKILL_WRITING: 'CommonGameTag' = 723 + TOOLTIP_WATER_CONSUMER: 'CommonGameTag' = 2400 + TOOLTIP_WATER_PRODUCER: 'CommonGameTag' = 2399 + TOP_BIKINI: 'CommonGameTag' = 1236 + TOP_BLOUSE: 'CommonGameTag' = 155 + TOP_BRASSIERE: 'CommonGameTag' = 944 + TOP_BUTTON_UPS: 'CommonGameTag' = 395 + TOP_JACKET: 'CommonGameTag' = 295 + TOP_POLO: 'CommonGameTag' = 943 + TOP_SHIRT_TEE: 'CommonGameTag' = 296 + TOP_SUIT_JACKET: 'CommonGameTag' = 942 + TOP_SWEATER: 'CommonGameTag' = 297 + TOP_SWEATSHIRT: 'CommonGameTag' = 941 + TOP_TANKTOP: 'CommonGameTag' = 360 + TOP_VEST: 'CommonGameTag' = 156 + TRAIT_ACHIEVEMENT: 'CommonGameTag' = 235 + TRAIT_AGE: 'CommonGameTag' = 657 + TRAIT_GROUP_EMOTIONAL: 'CommonGameTag' = 753 + TRAIT_GROUP_HOBBIES: 'CommonGameTag' = 754 + TRAIT_GROUP_LIFESTYLE: 'CommonGameTag' = 755 + TRAIT_GROUP_SOCIAL: 'CommonGameTag' = 756 + TRAIT_PERSONALITY: 'CommonGameTag' = 234 + TRAIT_WALKSTYLE: 'CommonGameTag' = 236 + UNIFORM_ACTIVIST_CRIMINAL_JUSTICE: 'CommonGameTag' = 55413 + UNIFORM_ACTIVIST_ECONOMIC_GROWTH: 'CommonGameTag' = 55414 + UNIFORM_ACTIVIST_ENVIRONMENT: 'CommonGameTag' = 55415 + UNIFORM_ACTIVIST_GLOBAL_PEACE: 'CommonGameTag' = 55416 + UNIFORM_ACTIVIST_TAX_REFORM: 'CommonGameTag' = 55417 + UNIFORM_ACTOR_CAREER_COMMERCIAL_HOSPITAL_ACTOR: 'CommonGameTag' = 61561 + UNIFORM_ACTOR_CAREER_COMMERCIAL_HOSPITAL_CO_STAR: 'CommonGameTag' = 61562 + UNIFORM_ACTOR_CAREER_COMMERCIAL_HOUSE_NICE_ACTOR: 'CommonGameTag' = 61564 + UNIFORM_ACTOR_CAREER_COMMERCIAL_HOUSE_NICE_CO_STAR: 'CommonGameTag' = 61565 + UNIFORM_ACTOR_CAREER_COMMERCIAL_KIDS_ACTOR: 'CommonGameTag' = 61566 + UNIFORM_ACTOR_CAREER_COMMERCIAL_PIRATE_ACTOR: 'CommonGameTag' = 61560 + UNIFORM_ACTOR_CAREER_COMMERCIAL_WESTERN_ACTOR: 'CommonGameTag' = 61563 + UNIFORM_ACTOR_CAREER_MOVIE_CITY_ACTOR: 'CommonGameTag' = 61608 + UNIFORM_ACTOR_CAREER_MOVIE_CITY_CO_STAR: 'CommonGameTag' = 61452 + UNIFORM_ACTOR_CAREER_MOVIE_CITY_LOVE_INTEREST: 'CommonGameTag' = 61451 + UNIFORM_ACTOR_CAREER_MOVIE_MEDIEVAL_ACTOR: 'CommonGameTag' = 61594 + UNIFORM_ACTOR_CAREER_MOVIE_MEDIEVAL_LOVE_INTEREST: 'CommonGameTag' = 61596 + UNIFORM_ACTOR_CAREER_MOVIE_MEDIEVAL_VILLAIN: 'CommonGameTag' = 61595 + UNIFORM_ACTOR_CAREER_MOVIE_PIRATE_ACTOR: 'CommonGameTag' = 61591 + UNIFORM_ACTOR_CAREER_MOVIE_PIRATE_LOVE_INTEREST: 'CommonGameTag' = 61593 + UNIFORM_ACTOR_CAREER_MOVIE_PIRATE_VILLAIN: 'CommonGameTag' = 61592 + UNIFORM_ACTOR_CAREER_MOVIE_SUPER_HERO_ACTOR: 'CommonGameTag' = 61603 + UNIFORM_ACTOR_CAREER_MOVIE_SUPER_HERO_LOVE_INTEREST: 'CommonGameTag' = 61605 + UNIFORM_ACTOR_CAREER_MOVIE_SUPER_HERO_VILLAIN: 'CommonGameTag' = 61604 + UNIFORM_ACTOR_CAREER_MOVIE_VICTORIAN_ACTOR: 'CommonGameTag' = 61600 + UNIFORM_ACTOR_CAREER_MOVIE_VICTORIAN_CO_STAR: 'CommonGameTag' = 61602 + UNIFORM_ACTOR_CAREER_MOVIE_VICTORIAN_LOVE_INTEREST: 'CommonGameTag' = 61601 + UNIFORM_ACTOR_CAREER_MOVIE_WESTERN_ACTOR: 'CommonGameTag' = 61597 + UNIFORM_ACTOR_CAREER_MOVIE_WESTERN_ALIEN: 'CommonGameTag' = 61599 + UNIFORM_ACTOR_CAREER_MOVIE_WESTERN_CREATURE: 'CommonGameTag' = 61598 + UNIFORM_ACTOR_CAREER_TV_HIGH_APOCALYPSE_ACTOR: 'CommonGameTag' = 61577 + UNIFORM_ACTOR_CAREER_TV_HIGH_APOCALYPSE_CO_STAR: 'CommonGameTag' = 61578 + UNIFORM_ACTOR_CAREER_TV_HIGH_APOCALYPSE_VILLAIN: 'CommonGameTag' = 61579 + UNIFORM_ACTOR_CAREER_TV_HIGH_HOSPITAL_ACTOR: 'CommonGameTag' = 61580 + UNIFORM_ACTOR_CAREER_TV_HIGH_HOSPITAL_CO_STAR: 'CommonGameTag' = 61582 + UNIFORM_ACTOR_CAREER_TV_HIGH_HOSPITAL_LOVE_INTEREST: 'CommonGameTag' = 61581 + UNIFORM_ACTOR_CAREER_TV_HIGH_POLICE_ACTOR: 'CommonGameTag' = 61588 + UNIFORM_ACTOR_CAREER_TV_HIGH_POLICE_CO_STAR: 'CommonGameTag' = 61590 + UNIFORM_ACTOR_CAREER_TV_HIGH_POLICE_VILLAIN: 'CommonGameTag' = 61589 + UNIFORM_ACTOR_CAREER_TV_HIGH_VICTORIAN_ACTOR: 'CommonGameTag' = 61585 + UNIFORM_ACTOR_CAREER_TV_HIGH_VICTORIAN_CO_STAR: 'CommonGameTag' = 61587 + UNIFORM_ACTOR_CAREER_TV_HIGH_VICTORIAN_LOVE_INTEREST: 'CommonGameTag' = 61586 + UNIFORM_ACTOR_CAREER_TV_HIGH_WESTERN_ACTOR: 'CommonGameTag' = 61583 + UNIFORM_ACTOR_CAREER_TV_HIGH_WESTERN_VILLAIN: 'CommonGameTag' = 61584 + UNIFORM_ACTOR_CAREER_TV_LOW_HOUSE_LOW_ACTOR: 'CommonGameTag' = 61574 + UNIFORM_ACTOR_CAREER_TV_LOW_HOUSE_LOW_CO_STAR: 'CommonGameTag' = 61575 + UNIFORM_ACTOR_CAREER_TV_LOW_HOUSE_NICE_ACTOR: 'CommonGameTag' = 61570 + UNIFORM_ACTOR_CAREER_TV_LOW_HOUSE_NICE_CO_STAR: 'CommonGameTag' = 61571 + UNIFORM_ACTOR_CAREER_TV_LOW_KIDS_ACTOR: 'CommonGameTag' = 61576 + UNIFORM_ACTOR_CAREER_TV_LOW_PIRATE_ACTOR: 'CommonGameTag' = 61567 + UNIFORM_ACTOR_CAREER_TV_LOW_PIRATE_CO_STAR: 'CommonGameTag' = 61569 + UNIFORM_ACTOR_CAREER_TV_LOW_PIRATE_LOVE_INTEREST: 'CommonGameTag' = 61568 + UNIFORM_ACTOR_CAREER_TV_LOW_WESTERN_ACTOR: 'CommonGameTag' = 61572 + UNIFORM_ACTOR_CAREER_TV_LOW_WESTERN_CO_STAR: 'CommonGameTag' = 61573 + UNIFORM_ARRESTED: 'CommonGameTag' = 12336 + UNIFORM_ARTS_CENTER_PAINTER: 'CommonGameTag' = 55357 + UNIFORM_ART_CRITIC_SHOW_FORMAL: 'CommonGameTag' = 55395 + UNIFORM_ASTRONAUT_STATUE_GOLD: 'CommonGameTag' = 55302 + UNIFORM_ASTRONAUT_STATUE_SILVER: 'CommonGameTag' = 55354 + UNIFORM_ASTRONAUT_SUIT: 'CommonGameTag' = 614 + UNIFORM_ATHLETIC_CHEERLEADER: 'CommonGameTag' = 1262 + UNIFORM_ATHLETIC_LIFTER: 'CommonGameTag' = 1263 + UNIFORM_ATHLETIC_MAJOR_LEAGUER: 'CommonGameTag' = 1266 + UNIFORM_ATHLETIC_MASCOT: 'CommonGameTag' = 1264 + UNIFORM_ATHLETIC_MINOR_LEAGUER: 'CommonGameTag' = 1267 + UNIFORM_ATHLETIC_TRACK_SUIT: 'CommonGameTag' = 1265 + UNIFORM_BABYSITTER: 'CommonGameTag' = 887 + UNIFORM_BACKGROUND_ACTOR_COSTUME_1: 'CommonGameTag' = 61642 + UNIFORM_BACKGROUND_ACTOR_COSTUME_2: 'CommonGameTag' = 61643 + UNIFORM_BACKGROUND_ACTOR_COSTUME_3: 'CommonGameTag' = 61644 + UNIFORM_BACKGROUND_ACTOR_COSTUME_4: 'CommonGameTag' = 61645 + UNIFORM_BACKGROUND_ACTOR_COSTUME_5: 'CommonGameTag' = 61646 + UNIFORM_BARISTA: 'CommonGameTag' = 884 + UNIFORM_BARTENDER: 'CommonGameTag' = 621 + UNIFORM_BARTENDER_JUNGLE: 'CommonGameTag' = 45090 + UNIFORM_BARTENDER_WOLF_TOWN: 'CommonGameTag' = 2789 + UNIFORM_BATUU_ALIEN_ABEDNEDO: 'CommonGameTag' = 2471 + UNIFORM_BATUU_ALIEN_BITH: 'CommonGameTag' = 2472 + UNIFORM_BATUU_ALIEN_MIRIALAN: 'CommonGameTag' = 2473 + UNIFORM_BATUU_ALIEN_TWILEK: 'CommonGameTag' = 2474 + UNIFORM_BATUU_ALIEN_WEEQUAY: 'CommonGameTag' = 2475 + UNIFORM_BATUU_ALIEN_ZABRAK: 'CommonGameTag' = 2476 + UNIFORM_BATUU_BARTENDER: 'CommonGameTag' = 51225 + UNIFORM_BATUU_CITIZEN: 'CommonGameTag' = 51210 + UNIFORM_BATUU_FIRST_ORDER_OFFICER: 'CommonGameTag' = 51205 + UNIFORM_BATUU_FIRST_ORDER_PILOT: 'CommonGameTag' = 51221 + UNIFORM_BATUU_FIRST_ORDER_STORMTROOPER: 'CommonGameTag' = 51201 + UNIFORM_BATUU_RESISTANCE_MEMBER: 'CommonGameTag' = 51202 + UNIFORM_BATUU_RESISTANCE_PILOT: 'CommonGameTag' = 51222 + UNIFORM_BATUU_SCOUNDREL_MEMBER: 'CommonGameTag' = 51209 + UNIFORM_BATUU_SERVICE_NPC: 'CommonGameTag' = 51224 + UNIFORM_BEAR_SUIT: 'CommonGameTag' = 10258 + UNIFORM_BED_UPDATES_NO_CROSS_LEGGED: 'CommonGameTag' = 2833 + UNIFORM_BEE_KEEPING_SUIT: 'CommonGameTag' = 59466 + UNIFORM_BIG_HEAD: 'CommonGameTag' = 2244 + UNIFORM_BIKE_HELMET: 'CommonGameTag' = 65618 + UNIFORM_BLACK_AND_WHITE_PARTY: 'CommonGameTag' = 682 + UNIFORM_BLACK_TURTLENECK: 'CommonGameTag' = 627 + UNIFORM_BONEHILDA: 'CommonGameTag' = 86029 + UNIFORM_BOWLING_GLOVES: 'CommonGameTag' = 38924 + UNIFORM_BOWLING_NPC: 'CommonGameTag' = 38918 + UNIFORM_BOWLING_SHOES: 'CommonGameTag' = 38923 + UNIFORM_BOWLING_TEAM_1: 'CommonGameTag' = 38914 + UNIFORM_BOWLING_TEAM_2: 'CommonGameTag' = 38915 + UNIFORM_BOWLING_TEAM_3: 'CommonGameTag' = 38916 + UNIFORM_BOWLING_TEAM_4: 'CommonGameTag' = 38917 + UNIFORM_BUSINESS_CHEAP_SUIT: 'CommonGameTag' = 1269 + UNIFORM_BUSINESS_DECENT_SUIT: 'CommonGameTag' = 1270 + UNIFORM_BUSINESS_EXPENSIVE_SUIT: 'CommonGameTag' = 1271 + UNIFORM_BUSINESS_OFFICE_WORKER: 'CommonGameTag' = 1268 + UNIFORM_BUTLER: 'CommonGameTag' = 36869 + UNIFORM_CAMERA_OPERATOR: 'CommonGameTag' = 61450 + UNIFORM_CAREER_CRIMINAL_BASE: 'CommonGameTag' = 2734 + UNIFORM_CAREER_CRIMINAL_ORACLE_BASE: 'CommonGameTag' = 2735 + UNIFORM_CAREER_ENGINEER_BASE: 'CommonGameTag' = 2736 + UNIFORM_CAREER_ENGINEER_COMPUTER: 'CommonGameTag' = 2737 + UNIFORM_CAREER_ENGINEER_MECHANICAL: 'CommonGameTag' = 2738 + UNIFORM_CAREER_ENTERTAINER_BASE: 'CommonGameTag' = 2733 + UNIFORM_CAREER_GARDENER_BOTANIST: 'CommonGameTag' = 59480 + UNIFORM_CAREER_GARDENER_FLORIST: 'CommonGameTag' = 59481 + UNIFORM_CAREER_GARDENER_MAIN: 'CommonGameTag' = 59479 + UNIFORM_CAREER_SOCIAL_MEDIA_BASE: 'CommonGameTag' = 2739 + UNIFORM_CAREER_SOCIAL_MEDIA_INTERNET: 'CommonGameTag' = 2740 + UNIFORM_CAREER_STYLE_INFLUENCER: 'CommonGameTag' = 2741 + UNIFORM_CAREER_TECH_GURU_BASE: 'CommonGameTag' = 2742 + UNIFORM_CAREER_TECH_GURU_START_UP: 'CommonGameTag' = 2743 + UNIFORM_CHEF: 'CommonGameTag' = 620 + UNIFORM_CHILDHOOD_PHASE_BEAR: 'CommonGameTag' = 43027 + UNIFORM_CIVIC_INSPECTOR: 'CommonGameTag' = 67627 + UNIFORM_CIVIL_DESIGNER_CIVIC_PLANNER: 'CommonGameTag' = 67641 + UNIFORM_CIVIL_DESIGNER_GREEN_TECHNICIAN: 'CommonGameTag' = 67640 + UNIFORM_CIVIL_DESIGNER_MAIN: 'CommonGameTag' = 67639 + UNIFORM_CLOWN: 'CommonGameTag' = 680 + UNIFORM_CONCERT_OUTFIT: 'CommonGameTag' = 618 + UNIFORM_CONSERVATIONIST_ENVIRONMENTAL_MANAGER: 'CommonGameTag' = 63523 + UNIFORM_CONSERVATIONIST_MAIN: 'CommonGameTag' = 63522 + UNIFORM_CONSERVATIONIST_MARINE_BIOLOGIST: 'CommonGameTag' = 63524 + UNIFORM_CONSPIRACIST: 'CommonGameTag' = 47130 + UNIFORM_COOK: 'CommonGameTag' = 619 + UNIFORM_CORPORATE_WORKER_EXPERT: 'CommonGameTag' = 69708 + UNIFORM_CORPORATE_WORKER_MAIN: 'CommonGameTag' = 69707 + UNIFORM_CORPORATE_WORKER_SUPERVISOR: 'CommonGameTag' = 69709 + UNIFORM_COSTUME_AAYLA_SECURA: 'CommonGameTag' = 1486 + UNIFORM_COSTUME_ALIEN_HUNTER: 'CommonGameTag' = 1700 + UNIFORM_COSTUME_ANIMAL_HOOD: 'CommonGameTag' = 2113 + UNIFORM_COSTUME_ANIMAL_HOODIE: 'CommonGameTag' = 59475 + UNIFORM_COSTUME_ASTRONAUT_ORANGE: 'CommonGameTag' = 1480 + UNIFORM_COSTUME_ASTRONAUT_WHITE: 'CommonGameTag' = 1466 + UNIFORM_COSTUME_BOBA_FETT: 'CommonGameTag' = 1475 + UNIFORM_COSTUME_CARTOON_PLUMBERS: 'CommonGameTag' = 1631 + UNIFORM_COSTUME_CHEERLEADER_GREEN: 'CommonGameTag' = 1476 + UNIFORM_COSTUME_CLOWN_PINK: 'CommonGameTag' = 1481 + UNIFORM_COSTUME_CLOWN_YELLOW: 'CommonGameTag' = 1467 + UNIFORM_COSTUME_COLORFUL_ANIMALS: 'CommonGameTag' = 1632 + UNIFORM_COSTUME_DARTH_MAUL: 'CommonGameTag' = 1474 + UNIFORM_COSTUME_DARTH_VADER: 'CommonGameTag' = 1473 + UNIFORM_COSTUME_FAIRY: 'CommonGameTag' = 22530 + UNIFORM_COSTUME_FAIRY_BLUE: 'CommonGameTag' = 22547 + UNIFORM_COSTUME_FAIRY_GREEN: 'CommonGameTag' = 22546 + UNIFORM_COSTUME_FAIRY_PURPLE: 'CommonGameTag' = 22548 + UNIFORM_COSTUME_HOLIDAY_HELPER: 'CommonGameTag' = 59473 + UNIFORM_COSTUME_HOT_DOG_RED: 'CommonGameTag' = 1468 + UNIFORM_COSTUME_LEGIONNAIRE: 'CommonGameTag' = 22532 + UNIFORM_COSTUME_LEIA: 'CommonGameTag' = 1485 + UNIFORM_COSTUME_LLAMA: 'CommonGameTag' = 22531 + UNIFORM_COSTUME_LLAMA_GIRL_PURPLE: 'CommonGameTag' = 22549 + UNIFORM_COSTUME_LLAMA_MAN_BLACK: 'CommonGameTag' = 22544 + UNIFORM_COSTUME_LUKE_SKYWALKER: 'CommonGameTag' = 1472 + UNIFORM_COSTUME_MAID_BLACK: 'CommonGameTag' = 1483 + UNIFORM_COSTUME_MAID_BLUE: 'CommonGameTag' = 1470 + UNIFORM_COSTUME_MAILMAN_BLUE: 'CommonGameTag' = 1479 + UNIFORM_COSTUME_MASCOT_BLUE_BLACK: 'CommonGameTag' = 1469 + UNIFORM_COSTUME_MASCOT_WHITE: 'CommonGameTag' = 1482 + UNIFORM_COSTUME_MONSTER: 'CommonGameTag' = 1699 + UNIFORM_COSTUME_NINJA: 'CommonGameTag' = 22533 + UNIFORM_COSTUME_NINJA_RED: 'CommonGameTag' = 22543 + UNIFORM_COSTUME_PIRATE: 'CommonGameTag' = 22534 + UNIFORM_COSTUME_PIRATE_BROWN: 'CommonGameTag' = 22559 + UNIFORM_COSTUME_PIRATE_NAVY: 'CommonGameTag' = 22542 + UNIFORM_COSTUME_PIRATE_RED: 'CommonGameTag' = 22550 + UNIFORM_COSTUME_PIRATE_WHITE: 'CommonGameTag' = 22566 + UNIFORM_COSTUME_PIZZA_ORANGE: 'CommonGameTag' = 1471 + UNIFORM_COSTUME_PIZZA_RED: 'CommonGameTag' = 1484 + UNIFORM_COSTUME_PRINCESS: 'CommonGameTag' = 22537 + UNIFORM_COSTUME_PRINCESS_BLUE: 'CommonGameTag' = 22556 + UNIFORM_COSTUME_PRINCESS_GOLD: 'CommonGameTag' = 22557 + UNIFORM_COSTUME_PRINCESS_PINK: 'CommonGameTag' = 22558 + UNIFORM_COSTUME_PUMPKIN_BROWN: 'CommonGameTag' = 22564 + UNIFORM_COSTUME_PUMPKIN_MAN: 'CommonGameTag' = 22535 + UNIFORM_COSTUME_PUMPKIN_NAVY: 'CommonGameTag' = 22563 + UNIFORM_COSTUME_PUMPKIN_PLUM: 'CommonGameTag' = 22565 + UNIFORM_COSTUME_ROBO_HAT: 'CommonGameTag' = 2225 + UNIFORM_COSTUME_SAUSAGE_GRAY: 'CommonGameTag' = 1489 + UNIFORM_COSTUME_SCHOOL_GIRL: 'CommonGameTag' = 22538 + UNIFORM_COSTUME_SKELETON: 'CommonGameTag' = 22539 + UNIFORM_COSTUME_SKELETON_GREEN: 'CommonGameTag' = 22561 + UNIFORM_COSTUME_SKELETON_ORANGE: 'CommonGameTag' = 22562 + UNIFORM_COSTUME_SKELETON_WHITE: 'CommonGameTag' = 22560 + UNIFORM_COSTUME_SMUGGLER_BROWN: 'CommonGameTag' = 1488 + UNIFORM_COSTUME_SMUGGLER_TAN: 'CommonGameTag' = 1477 + UNIFORM_COSTUME_SPACE_RANGER_BLACK: 'CommonGameTag' = 1487 + UNIFORM_COSTUME_SPACE_RANGER_BLUE: 'CommonGameTag' = 1478 + UNIFORM_COSTUME_SPARTAN_BROWN: 'CommonGameTag' = 22551 + UNIFORM_COSTUME_SPARTAN_GOLD: 'CommonGameTag' = 22545 + UNIFORM_COSTUME_TREE_FIR: 'CommonGameTag' = 59474 + UNIFORM_COSTUME_WITCH: 'CommonGameTag' = 22536 + UNIFORM_COSTUME_WITCH_BLACK: 'CommonGameTag' = 22552 + UNIFORM_COSTUME_WITCH_GREEN: 'CommonGameTag' = 22553 + UNIFORM_COSTUME_WITCH_ORANGE: 'CommonGameTag' = 22554 + UNIFORM_COSTUME_YODA: 'CommonGameTag' = 1490 + UNIFORM_COSTUME_ZOMBIE_BLUE: 'CommonGameTag' = 22555 + UNIFORM_COTTAGE_WORLD_NPC_CRITTER_TENDER: 'CommonGameTag' = 112672 + UNIFORM_COTTAGE_WORLD_NPC_GROCERY_DELIVERY: 'CommonGameTag' = 112673 + UNIFORM_COTTAGE_WORLD_NPC_GROCERY_OWNER: 'CommonGameTag' = 112674 + UNIFORM_COTTAGE_WORLD_NPC_MAYOR: 'CommonGameTag' = 112675 + UNIFORM_COTTAGE_WORLD_NPC_MAYOR_MALE: 'CommonGameTag' = 112679 + UNIFORM_COTTAGE_WORLD_NPC_PUB_OWNER: 'CommonGameTag' = 112676 + UNIFORM_COWBOY_STATUE_GOLD: 'CommonGameTag' = 55433 + UNIFORM_CRIME_BOSS: 'CommonGameTag' = 623 + UNIFORM_CRIME_LORD_HAT: 'CommonGameTag' = 622 + UNIFORM_DAY_OF_THE_DEAD_WALKBY: 'CommonGameTag' = 1568 + UNIFORM_DAY_OF_THE_DEAD_WALKBY_FEMALE: 'CommonGameTag' = 1569 + UNIFORM_DEBATE_JUDGE: 'CommonGameTag' = 65590 + UNIFORM_DELIVERIES_FOOD_DELIVERY: 'CommonGameTag' = 2598 + UNIFORM_DELIVERIES_GROCERY_DELIVERY: 'CommonGameTag' = 112654 + UNIFORM_DETECTIVE: 'CommonGameTag' = 12334 + UNIFORM_DIRECTOR: 'CommonGameTag' = 61449 + UNIFORM_DIVER: 'CommonGameTag' = 63515 + UNIFORM_DJ_HIGH: 'CommonGameTag' = 24584 + UNIFORM_DJ_LOW: 'CommonGameTag' = 24583 + UNIFORM_DOCTOR_HIGH: 'CommonGameTag' = 12340 + UNIFORM_DOCTOR_LOW: 'CommonGameTag' = 12339 + UNIFORM_DRAMA_CLUB: 'CommonGameTag' = 61639 + UNIFORM_ECO_INSPECTOR: 'CommonGameTag' = 67626 + UNIFORM_EDUCATION: 'CommonGameTag' = 65552 + UNIFORM_EDUCATION_ADMIN: 'CommonGameTag' = 65553 + UNIFORM_EDUCATION_PROFESSOR: 'CommonGameTag' = 65554 + UNIFORM_ELBOW_PATCH_JACKET: 'CommonGameTag' = 625 + UNIFORM_EP01_ALIEN: 'CommonGameTag' = 12385 + UNIFORM_EP01_DOCTOR_MID: 'CommonGameTag' = 12357 + UNIFORM_EP01_POLICE_CHIEF: 'CommonGameTag' = 12426 + UNIFORM_EP01_RETAIL_EMPLOYEE: 'CommonGameTag' = 12412 + UNIFORM_EP01_SCIENTIST_ALIEN_HUNTER: 'CommonGameTag' = 12381 + UNIFORM_EP01_SCIENTIST_HIGH: 'CommonGameTag' = 12349 + UNIFORM_EP01_SCIENTIST_LOW: 'CommonGameTag' = 12350 + UNIFORM_EP01_SCIENTIST_MID: 'CommonGameTag' = 12359 + UNIFORM_EP01_SCIENTIST_VERY_HIGH: 'CommonGameTag' = 12399 + UNIFORM_EP01_SUSPECT_BLACK_HAIR: 'CommonGameTag' = 12401 + UNIFORM_EP01_SUSPECT_BLONDE_HAIR: 'CommonGameTag' = 12367 + UNIFORM_EP01_SUSPECT_BOTTOM_PANTS: 'CommonGameTag' = 12408 + UNIFORM_EP01_SUSPECT_BOTTOM_SHORTS: 'CommonGameTag' = 12411 + UNIFORM_EP01_SUSPECT_BOTTOM_SKIRT: 'CommonGameTag' = 12409 + UNIFORM_EP01_SUSPECT_BOTTOM_SLACKS: 'CommonGameTag' = 12410 + UNIFORM_EP01_SUSPECT_BROWN_HAIR: 'CommonGameTag' = 12402 + UNIFORM_EP01_SUSPECT_GREY_HAIR: 'CommonGameTag' = 12432 + UNIFORM_EP01_SUSPECT_RED_HAIR: 'CommonGameTag' = 12366 + UNIFORM_EP01_SUSPECT_TOP_BLOUSE: 'CommonGameTag' = 12406 + UNIFORM_EP01_SUSPECT_TOP_JACKET: 'CommonGameTag' = 12404 + UNIFORM_EP01_SUSPECT_TOP_LONG_SLEEVE: 'CommonGameTag' = 12405 + UNIFORM_EP01_SUSPECT_TOP_SHORT_SLEEVE: 'CommonGameTag' = 12403 + UNIFORM_EP01_SUSPECT_TOP_TANK: 'CommonGameTag' = 12407 + UNIFORM_EP07_VENDOR: 'CommonGameTag' = 63525 + UNIFORM_EP14_HORSE_TRAINER: 'CommonGameTag' = 118886 + UNIFORM_ESPORTS_PLAYER_ARTS: 'CommonGameTag' = 65601 + UNIFORM_ESPORTS_PLAYER_SCIENCE: 'CommonGameTag' = 65602 + UNIFORM_FAIRY: 'CommonGameTag' = 8209 + UNIFORM_FAST_FOOD: 'CommonGameTag' = 883 + UNIFORM_FATHER_WINTER: 'CommonGameTag' = 2071 + UNIFORM_FATHER_WINTER_SUMMER: 'CommonGameTag' = 2086 + UNIFORM_FESTIVAL_BLOSSOM_SHIRT: 'CommonGameTag' = 55350 + UNIFORM_FESTIVAL_FOOD_CURRY_CONTEST_SHIRT: 'CommonGameTag' = 55397 + UNIFORM_FESTIVAL_FOOD_SHIRT: 'CommonGameTag' = 55351 + UNIFORM_FESTIVAL_LAMP_SHIRT: 'CommonGameTag' = 55352 + UNIFORM_FESTIVAL_LLAMA_BLUE: 'CommonGameTag' = 55421 + UNIFORM_FESTIVAL_LLAMA_GOLD: 'CommonGameTag' = 55423 + UNIFORM_FESTIVAL_LLAMA_SILVER: 'CommonGameTag' = 55424 + UNIFORM_FESTIVAL_LLAMA_YELLOW: 'CommonGameTag' = 55422 + UNIFORM_FESTIVAL_LOGIC_SHIRT: 'CommonGameTag' = 55353 + UNIFORM_FESTIVAL_MUSIC_SHIRT: 'CommonGameTag' = 2563 + UNIFORM_FESTIVAL_VILLAGE_FAIR_ATTENDEE: 'CommonGameTag' = 112666 + UNIFORM_FESTIVE_SPIRIT: 'CommonGameTag' = 2089 + UNIFORM_FIREFIGHTER: 'CommonGameTag' = 2426 + UNIFORM_FLOWER_BUNNY: 'CommonGameTag' = 59458 + UNIFORM_FOOD_CRITIC_RESTAURANT_CASUAL: 'CommonGameTag' = 55396 + UNIFORM_FOREST_RANGER: 'CommonGameTag' = 10266 + UNIFORM_FORTUNE_TELLER: 'CommonGameTag' = 8198 + UNIFORM_FRANKENSTEIN: 'CommonGameTag' = 8201 + UNIFORM_GAMESCOM_CLOSET_FAIL: 'CommonGameTag' = 24579 + UNIFORM_GAMESCOM_CLOSET_SUCCEED: 'CommonGameTag' = 24580 + UNIFORM_GP01_CF_TANK_LACE: 'CommonGameTag' = 10291 + UNIFORM_GP01_CU_POCKET_ZIP: 'CommonGameTag' = 10288 + UNIFORM_GP01_CU_TEE_LONG_SHIRT_PANTS: 'CommonGameTag' = 10290 + UNIFORM_GP01_CU_TEE_LONG_SHIRT_SHORTS: 'CommonGameTag' = 10287 + UNIFORM_GP01_CU_VEST_DOWN: 'CommonGameTag' = 10289 + UNIFORM_GP01_WALKBYS_1: 'CommonGameTag' = 10292 + UNIFORM_GP01_WALKBYS_2: 'CommonGameTag' = 10293 + UNIFORM_GP01_WALKBYS_3: 'CommonGameTag' = 10294 + UNIFORM_GP01_WALKBYS_4: 'CommonGameTag' = 10295 + UNIFORM_GP01_WALKBYS_5: 'CommonGameTag' = 10296 + UNIFORM_GP01_WALKBYS_6: 'CommonGameTag' = 10297 + UNIFORM_GP01_YF_JACKET_FLEECE: 'CommonGameTag' = 10279 + UNIFORM_GP01_YF_LAYERS: 'CommonGameTag' = 10276 + UNIFORM_GP01_YF_LAYERS_HAT: 'CommonGameTag' = 10277 + UNIFORM_GP01_YF_TEE_TIED: 'CommonGameTag' = 10281 + UNIFORM_GP01_YF_VEST_FLANNEL: 'CommonGameTag' = 10278 + UNIFORM_GP01_YF_VEST_TEE: 'CommonGameTag' = 10280 + UNIFORM_GP01_YM_FINGER_SHIRT: 'CommonGameTag' = 10285 + UNIFORM_GP01_YM_TANK: 'CommonGameTag' = 10283 + UNIFORM_GP01_YM_THICK_LAYERS: 'CommonGameTag' = 10284 + UNIFORM_GP01_YM_VEST_CARABINER: 'CommonGameTag' = 10282 + UNIFORM_GP01_YM_VEST_FLEECE: 'CommonGameTag' = 10286 + UNIFORM_GRIM_REAPER: 'CommonGameTag' = 316 + UNIFORM_GRIM_REAPER_HELPER: 'CommonGameTag' = 366 + UNIFORM_HACKER: 'CommonGameTag' = 624 + UNIFORM_HAIR_MAKEUP_CHAIR_STYLIST: 'CommonGameTag' = 61453 + UNIFORM_HAZMAT_SUIT: 'CommonGameTag' = 47127 + UNIFORM_HAZMAT_SUIT_WITH_FILTER: 'CommonGameTag' = 47128 + UNIFORM_HERMIT: 'CommonGameTag' = 10257 + UNIFORM_HIGH_SCHOOL_ACTIVE_PRINCIPAL: 'CommonGameTag' = 114750 + UNIFORM_HIGH_SCHOOL_ACTIVE_TEACHER: 'CommonGameTag' = 114751 + UNIFORM_HIGH_SCHOOL_FESTIVAL_CHEER_REWARD: 'CommonGameTag' = 114713 + UNIFORM_HIGH_SCHOOL_FESTIVAL_CHESS_REWARD: 'CommonGameTag' = 114714 + UNIFORM_HIGH_SCHOOL_FESTIVAL_COMPUTER_REWARD: 'CommonGameTag' = 114715 + UNIFORM_HIGH_SCHOOL_FESTIVAL_FOOTBALL_REWARD: 'CommonGameTag' = 114712 + UNIFORM_HIGH_SCHOOL_GRADUATION: 'CommonGameTag' = 114721 + UNIFORM_HIGH_SCHOOL_TEAM_CHEER_TEAM: 'CommonGameTag' = 114694 + UNIFORM_HIGH_SCHOOL_TEAM_CHESS_TEAM: 'CommonGameTag' = 114696 + UNIFORM_HIGH_SCHOOL_TEAM_COMPUTER_TEAM: 'CommonGameTag' = 114697 + UNIFORM_HIGH_SCHOOL_TEAM_FOOTBALL_TEAM: 'CommonGameTag' = 114695 + UNIFORM_HIGH_SCHOOL_TEAM_SUPPORT_CHEER: 'CommonGameTag' = 114745 + UNIFORM_HIGH_SCHOOL_TEAM_SUPPORT_CHESS: 'CommonGameTag' = 114746 + UNIFORM_HIGH_SCHOOL_TEAM_SUPPORT_COMPUTER: 'CommonGameTag' = 114747 + UNIFORM_HIGH_SCHOOL_TEAM_SUPPORT_FOOTBALL: 'CommonGameTag' = 114748 + UNIFORM_HIRED_NANNY: 'CommonGameTag' = 1549 + UNIFORM_HORSE_CHILD_SADDLE: 'CommonGameTag' = 118874 + UNIFORM_HOT_DOG: 'CommonGameTag' = 681 + UNIFORM_INVESTIGATIVE_JOURNALIST: 'CommonGameTag' = 626 + UNIFORM_ISLAND_ELEMENTAL: 'CommonGameTag' = 63516 + UNIFORM_ISLAND_LOCAL: 'CommonGameTag' = 63513 + UNIFORM_ISLAND_LOCAL_FLOWER_MUSIC: 'CommonGameTag' = 63514 + UNIFORM_JAPANESE_TRADITIONAL: 'CommonGameTag' = 69694 + UNIFORM_JUNGLE_VENDOR1: 'CommonGameTag' = 45102 + UNIFORM_JUNGLE_VENDOR2: 'CommonGameTag' = 45103 + UNIFORM_JUNGLE_VENDOR3: 'CommonGameTag' = 45104 + UNIFORM_KIDS_BIKE_HELMET: 'CommonGameTag' = 2947 + UNIFORM_KNIGHT_SUIT: 'CommonGameTag' = 24610 + UNIFORM_LAW_CAREER_JUDGE: 'CommonGameTag' = 65628 + UNIFORM_LAW_CAREER_MAIN: 'CommonGameTag' = 65627 + UNIFORM_LAW_CAREER_MAIN_HIGH: 'CommonGameTag' = 65630 + UNIFORM_LAW_CAREER_PRIVATE_ATTORNEY: 'CommonGameTag' = 65629 + UNIFORM_LIBRARIAN_WOLF_TOWN: 'CommonGameTag' = 2790 + UNIFORM_LIFEGUARD: 'CommonGameTag' = 63502 + UNIFORM_LOVE_GURU: 'CommonGameTag' = 55358 + UNIFORM_MAID: 'CommonGameTag' = 262 + UNIFORM_MAID_DEPRECATED: 'CommonGameTag' = 636 + UNIFORM_MAILMAN: 'CommonGameTag' = 341 + UNIFORM_MAINTENANCE_WORKER: 'CommonGameTag' = 613 + UNIFORM_MANUAL_LABOR: 'CommonGameTag' = 885 + UNIFORM_MASCOT_ALT_ARTS: 'CommonGameTag' = 65588 + UNIFORM_MASCOT_ALT_SCIENCE: 'CommonGameTag' = 65589 + UNIFORM_MASCOT_ARTS: 'CommonGameTag' = 65586 + UNIFORM_MASCOT_SCIENCE: 'CommonGameTag' = 65587 + UNIFORM_MASSAGE_THERAPIST: 'CommonGameTag' = 18446 + UNIFORM_MASSAGE_TOWEL: 'CommonGameTag' = 18450 + UNIFORM_MASTER_FISHERMAN: 'CommonGameTag' = 867 + UNIFORM_MASTER_GARDENER: 'CommonGameTag' = 868 + UNIFORM_MILITARY_COVERT_HEADSET: 'CommonGameTag' = 47123 + UNIFORM_MILITARY_COVERT_SUIT: 'CommonGameTag' = 47121 + UNIFORM_MILITARY_COVERT_SUNGLASSES: 'CommonGameTag' = 47122 + UNIFORM_MILITARY_MAIN_LEVEL_01: 'CommonGameTag' = 47111 + UNIFORM_MILITARY_MAIN_LEVEL_02: 'CommonGameTag' = 47112 + UNIFORM_MILITARY_MAIN_LEVEL_03: 'CommonGameTag' = 47113 + UNIFORM_MILITARY_MAIN_LEVEL_04: 'CommonGameTag' = 47114 + UNIFORM_MILITARY_MAIN_LEVEL_05: 'CommonGameTag' = 47115 + UNIFORM_MILITARY_OFFICER_LEVEL_01: 'CommonGameTag' = 47116 + UNIFORM_MILITARY_OFFICER_LEVEL_02: 'CommonGameTag' = 47117 + UNIFORM_MILITARY_OFFICER_LEVEL_03: 'CommonGameTag' = 47118 + UNIFORM_MILITARY_OFFICER_LEVEL_04: 'CommonGameTag' = 47119 + UNIFORM_MILITARY_OFFICER_LEVEL_05: 'CommonGameTag' = 47120 + UNIFORM_MUSIC_FESTIVAL_SHIRT_BEBE: 'CommonGameTag' = 2566 + UNIFORM_MUSIC_FESTIVAL_SHIRT_DAVE: 'CommonGameTag' = 2569 + UNIFORM_MUSIC_FESTIVAL_SHIRT_JOY: 'CommonGameTag' = 2568 + UNIFORM_MUSIC_FESTIVAL_SHIRT_SIM_SESSIONS: 'CommonGameTag' = 2565 + UNIFORM_MUSIC_FESTIVAL_SHIRT_SOM: 'CommonGameTag' = 2567 + UNIFORM_NINJA: 'CommonGameTag' = 8205 + UNIFORM_OFFICE_WORKER: 'CommonGameTag' = 607 + UNIFORM_ONSEN_VENUE_EMPLOYEE: 'CommonGameTag' = 69664 + UNIFORM_ORACLE: 'CommonGameTag' = 659 + UNIFORM_ORGANIZATION_ART_SOCIETY_MEMBER: 'CommonGameTag' = 65617 + UNIFORM_ORGANIZATION_ART_SOCIETY_MODEL: 'CommonGameTag' = 65616 + UNIFORM_ORGANIZATION_DEBATE: 'CommonGameTag' = 65635 + UNIFORM_ORGANIZATION_DEBATE_JUDGE: 'CommonGameTag' = 65642 + UNIFORM_ORGANIZATION_DEBATE_SHOWDOWN: 'CommonGameTag' = 65643 + UNIFORM_ORGANIZATION_DEBATE_SHOWDOWN_FOXBURY: 'CommonGameTag' = 65654 + UNIFORM_ORGANIZATION_HONOR: 'CommonGameTag' = 65636 + UNIFORM_ORGANIZATION_PARTY: 'CommonGameTag' = 65637 + UNIFORM_ORGANIZATION_PRANK: 'CommonGameTag' = 65638 + UNIFORM_ORGANIZATION_ROBOTICS: 'CommonGameTag' = 65634 + UNIFORM_PAINTER: 'CommonGameTag' = 629 + UNIFORM_PAPARAZZI: 'CommonGameTag' = 61606 + UNIFORM_PARTS_BRIDE: 'CommonGameTag' = 631 + UNIFORM_PARTS_GROOM: 'CommonGameTag' = 630 + UNIFORM_PARTS_LIBRARIAN: 'CommonGameTag' = 633 + UNIFORM_PARTS_OFFICE_WORKER: 'CommonGameTag' = 634 + UNIFORM_PARTS_PARK_SLEEPER: 'CommonGameTag' = 635 + UNIFORM_PARTY_PARTY_HATS: 'CommonGameTag' = 632 + UNIFORM_PART_TIME_FISHERMAN: 'CommonGameTag' = 63520 + UNIFORM_PATIENT: 'CommonGameTag' = 12338 + UNIFORM_PIRATE: 'CommonGameTag' = 8203 + UNIFORM_PIZZA_DELIVERY: 'CommonGameTag' = 637 + UNIFORM_POLICE_OFFICER: 'CommonGameTag' = 12335 + UNIFORM_POLITICIAN_HIGH_LEVEL: 'CommonGameTag' = 55418 + UNIFORM_POLITICIAN_LOW_LEVEL: 'CommonGameTag' = 55420 + UNIFORM_POLITICIAN_MEDIUM_LEVEL: 'CommonGameTag' = 55419 + UNIFORM_PRINCESS: 'CommonGameTag' = 8208 + UNIFORM_PRODUCER: 'CommonGameTag' = 61628 + UNIFORM_PROFESSOR_NPC_GOOD: 'CommonGameTag' = 65647 + UNIFORM_PROFESSOR_NPC_GRUMPY: 'CommonGameTag' = 65646 + UNIFORM_PROFESSOR_NPC_HIP: 'CommonGameTag' = 65645 + UNIFORM_PROFESSOR_NPC_SMART: 'CommonGameTag' = 65644 + UNIFORM_PRO_GAMER: 'CommonGameTag' = 628 + UNIFORM_PUMPKIN: 'CommonGameTag' = 8206 + UNIFORM_RACCOON: 'CommonGameTag' = 55372 + UNIFORM_RANCH_HAND: 'CommonGameTag' = 118799 + UNIFORM_REFLEXOLOGIST: 'CommonGameTag' = 18460 + UNIFORM_REPAIR: 'CommonGameTag' = 1491 + UNIFORM_REPO_PERSON: 'CommonGameTag' = 65633 + UNIFORM_RESTAURANT_CRITIC: 'CommonGameTag' = 26644 + UNIFORM_RETAIL: 'CommonGameTag' = 886 + UNIFORM_ROBE: 'CommonGameTag' = 18437 + UNIFORM_ROCK_CLIMBING_GEAR_GLOVES: 'CommonGameTag' = 69743 + UNIFORM_ROCK_CLIMBING_GEAR_SHOES: 'CommonGameTag' = 69744 + UNIFORM_SCHOOL_GIRL: 'CommonGameTag' = 8207 + UNIFORM_SCOUT_BASIC: 'CommonGameTag' = 59464 + UNIFORM_SCOUT_EXPERT: 'CommonGameTag' = 59465 + UNIFORM_SECRET_SOCIETY_LEVEL_1: 'CommonGameTag' = 65566 + UNIFORM_SECRET_SOCIETY_LEVEL_2: 'CommonGameTag' = 65567 + UNIFORM_SECRET_SOCIETY_LEVEL_3: 'CommonGameTag' = 65568 + UNIFORM_SHOES_OFF_INDOORS: 'CommonGameTag' = 69703 + UNIFORM_SKATING_GENERIC: 'CommonGameTag' = 59471 + UNIFORM_SKATING_ICE: 'CommonGameTag' = 59433 + UNIFORM_SKATING_PRO: 'CommonGameTag' = 59442 + UNIFORM_SKATING_ROLLER: 'CommonGameTag' = 59434 + UNIFORM_SKELETON: 'CommonGameTag' = 8204 + UNIFORM_SKELETON_GP06: 'CommonGameTag' = 45088 + UNIFORM_SKI_BOOTS: 'CommonGameTag' = 69738 + UNIFORM_SLIPPERS_INDOORS: 'CommonGameTag' = 69702 + UNIFORM_SMUGGLER: 'CommonGameTag' = 616 + UNIFORM_SNOWBOARD_BOOTS: 'CommonGameTag' = 69739 + UNIFORM_SNOWY_VENDOR: 'CommonGameTag' = 69722 + UNIFORM_SOCCER_PLAYER_ARTS: 'CommonGameTag' = 65599 + UNIFORM_SOCCER_PLAYER_SCIENCE: 'CommonGameTag' = 65600 + UNIFORM_SPACE_RANGER: 'CommonGameTag' = 615 + UNIFORM_SPARTAN: 'CommonGameTag' = 8211 + UNIFORM_SPELLCASTER_EDGY: 'CommonGameTag' = 49177 + UNIFORM_SPELLCASTER_FAIRYTALE: 'CommonGameTag' = 49176 + UNIFORM_SPELLCASTER_SAGE: 'CommonGameTag' = 49178 + UNIFORM_SPELLCASTER_SAGE_MISCHIEF: 'CommonGameTag' = 49180 + UNIFORM_SPELLCASTER_SAGE_PRACTICAL: 'CommonGameTag' = 49179 + UNIFORM_SPELLCASTER_SAGE_UNTAMED: 'CommonGameTag' = 49181 + UNIFORM_SPELLCASTER_STREET_MODERN: 'CommonGameTag' = 49175 + UNIFORM_SPELLCASTER_VINTAGE: 'CommonGameTag' = 49174 + UNIFORM_SPORTS_FAN_ARTS: 'CommonGameTag' = 65604 + UNIFORM_SPORTS_FAN_SCIENCE: 'CommonGameTag' = 65605 + UNIFORM_STALLS_CURIO_SHOP_HAT: 'CommonGameTag' = 47109 + UNIFORM_STALLS_CURIO_SHOP_SHIRT: 'CommonGameTag' = 47110 + UNIFORM_STALLS_CURIO_SHOP_VENDOR: 'CommonGameTag' = 47108 + UNIFORM_STALLS_FOOD_FESTIVAL: 'CommonGameTag' = 55429 + UNIFORM_STALLS_GENERIC: 'CommonGameTag' = 55428 + UNIFORM_STALLS_GENERIC_MARKET_STALLS: 'CommonGameTag' = 1937 + UNIFORM_STALLS_LAMP_FESTIVAL: 'CommonGameTag' = 55430 + UNIFORM_STALLS_NERD_FESTIVAL: 'CommonGameTag' = 55432 + UNIFORM_STALLS_PET_WORLD: 'CommonGameTag' = 1986 + UNIFORM_STALLS_ROMANCE_FESTIVAL: 'CommonGameTag' = 55431 + UNIFORM_STALLS_WEDDING_FLOWER: 'CommonGameTag' = 133121 + UNIFORM_STALLS_WEDDING_PATISSERIE: 'CommonGameTag' = 133122 + UNIFORM_STRANGERVILLE_SCIENTIST: 'CommonGameTag' = 47140 + UNIFORM_SUIT: 'CommonGameTag' = 608 + UNIFORM_SUIT_LEISURE: 'CommonGameTag' = 617 + UNIFORM_SUMMIT_STUDENT: 'CommonGameTag' = 69674 + UNIFORM_SUPER_TUXEDO: 'CommonGameTag' = 610 + UNIFORM_TACTICAL_TURTLENECK: 'CommonGameTag' = 612 + UNIFORM_TEENAGER: 'CommonGameTag' = 760 + UNIFORM_TODDLER_DIAPER_ONLY: 'CommonGameTag' = 1673 + UNIFORM_TOURIST: 'CommonGameTag' = 55306 + UNIFORM_TOURIST_BASE_GAME: 'CommonGameTag' = 2166 + UNIFORM_TOWEL: 'CommonGameTag' = 1440 + UNIFORM_TRAGIC_CLOWN: 'CommonGameTag' = 1503 + UNIFORM_TURTLE_FANATIC: 'CommonGameTag' = 63521 + UNIFORM_TUXEDO: 'CommonGameTag' = 609 + UNIFORM_UNIVERSITY_GRADUATION_ARTS: 'CommonGameTag' = 65610 + UNIFORM_UNIVERSITY_GRADUATION_ARTS_NO_CAP: 'CommonGameTag' = 65611 + UNIFORM_UNIVERSITY_GRADUATION_SCIENCE: 'CommonGameTag' = 65612 + UNIFORM_UNIVERSITY_GRADUATION_SCIENCE_NO_CAP: 'CommonGameTag' = 65613 + UNIFORM_UNIVERSITY_KIOSK_BOTTOM_AH: 'CommonGameTag' = 65578 + UNIFORM_UNIVERSITY_KIOSK_BOTTOM_ST: 'CommonGameTag' = 65579 + UNIFORM_UNIVERSITY_KIOSK_HAT_AH: 'CommonGameTag' = 65580 + UNIFORM_UNIVERSITY_KIOSK_HAT_ST: 'CommonGameTag' = 65581 + UNIFORM_UNIVERSITY_KIOSK_TOP_AH: 'CommonGameTag' = 65576 + UNIFORM_UNIVERSITY_KIOSK_TOP_ST: 'CommonGameTag' = 65577 + UNIFORM_UNIVERSITY_STUDENT: 'CommonGameTag' = 65555 + UNIFORM_UNIVERSITY_STUDENT_ARTS: 'CommonGameTag' = 65584 + UNIFORM_UNIVERSITY_STUDENT_SCIENCE: 'CommonGameTag' = 65585 + UNIFORM_VENDING_MACHINE_PAPER_HAT: 'CommonGameTag' = 69681 + UNIFORM_VENDING_MACHINE_SNOW_OUTFIT: 'CommonGameTag' = 69682 + UNIFORM_VENDING_MACHINE_YUKATA: 'CommonGameTag' = 69680 + UNIFORM_VET: 'CommonGameTag' = 57398 + UNIFORM_VFX_MACHINE_OPERATOR: 'CommonGameTag' = 61629 + UNIFORM_VILLAIN: 'CommonGameTag' = 611 + UNIFORM_VIP_ROPE_BOUNCER: 'CommonGameTag' = 61478 + UNIFORM_WARDROBE_PEDESTAL_STYLIST: 'CommonGameTag' = 61466 + UNIFORM_WASTE_MANAGER: 'CommonGameTag' = 67642 + UNIFORM_WEIRDO: 'CommonGameTag' = 55307 + UNIFORM_WINDENBURG_BARISTA: 'CommonGameTag' = 24603 + UNIFORM_WITCH: 'CommonGameTag' = 8202 + UNIFORM_YOGA_INSTRUCTOR: 'CommonGameTag' = 18445 + VENUE_OBJECT_BENCH: 'CommonGameTag' = 598 + VENUE_OBJECT_CHAIR: 'CommonGameTag' = 961 + VENUE_OBJECT_EXERCISE: 'CommonGameTag' = 601 + VENUE_OBJECT_LOCKER: 'CommonGameTag' = 1443 + VENUE_OBJECT_MICROPHONE: 'CommonGameTag' = 597 + VENUE_OBJECT_MONKEY_BARS: 'CommonGameTag' = 599 + VENUE_OBJECT_ONSEN_LOCKER: 'CommonGameTag' = 69661 + VENUE_OBJECT_PAINTING: 'CommonGameTag' = 595 + VENUE_OBJECT_PATIO_TABLE: 'CommonGameTag' = 602 + VENUE_OBJECT_PLAYGROUND: 'CommonGameTag' = 600 + VENUE_OBJECT_RELAXATION: 'CommonGameTag' = 18443 + VENUE_OBJECT_SCULPTURE: 'CommonGameTag' = 596 + WALL_PATTERN_MASONRY: 'CommonGameTag' = 412 + WALL_PATTERN_MISC: 'CommonGameTag' = 415 + WALL_PATTERN_PAINT: 'CommonGameTag' = 408 + WALL_PATTERN_PANELING: 'CommonGameTag' = 411 + WALL_PATTERN_ROCK_AND_STONE: 'CommonGameTag' = 413 + WALL_PATTERN_SIDING: 'CommonGameTag' = 414 + WALL_PATTERN_TILE: 'CommonGameTag' = 410 + WALL_PATTERN_WALLPAPER: 'CommonGameTag' = 409 + WORLD_LOG_NOT_INTERACTIVE: 'CommonGameTag' = 1985 diff --git a/Scripts/s4ap/sims4communitylib/enums/traits_enum.py b/Scripts/s4ap/sims4communitylib/enums/traits_enum.py new file mode 100644 index 0000000..78349d4 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/traits_enum.py @@ -0,0 +1,2715 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +# noinspection SpellCheckingInspection +class CommonTraitId(CommonInt): + """Identifiers for vanilla sim traits. + + """ + INVALID: 'CommonTraitId' = 0 + # S4CL + S4CL_MAIN_TRAIT: 'CommonTraitId' = 11620901522964063678 + S4CL_MAIN_TRAIT_HUMAN: 'CommonTraitId' = 14622983050963926956 + S4CL_MAIN_TRAIT_LARGE_DOG: 'CommonTraitId' = 16449767532803985357 + S4CL_MAIN_TRAIT_SMALL_DOG: 'CommonTraitId' = 5284118362600111737 + S4CL_MAIN_TRAIT_CAT: 'CommonTraitId' = 4108675957767251387 + S4CL_MAIN_TRAIT_FOX: 'CommonTraitId' = 0x38F9F903CFDDA804 + S4CL_MAIN_TRAIT_HORSE: 'CommonTraitId' = 0xAB4F5D9C641CB480 + S4CL_GENDER_OPTIONS_TOILET_UNKNOWN: 'CommonTraitId' = 0xCDD5658C08ED76D1 + S4CL_GENDER_OPTIONS_TOILET_STANDING_LARGE_DOG: 'CommonTraitId' = 0x596114D020EC43FA + S4CL_GENDER_OPTIONS_TOILET_SITTING_LARGE_DOG: 'CommonTraitId' = 0x1CE27237D2E3CA18 + S4CL_GENDER_OPTIONS_TOILET_STANDING_SMALL_DOG: 'CommonTraitId' = 0x65563037218958A2 + S4CL_GENDER_OPTIONS_TOILET_SITTING_SMALL_DOG: 'CommonTraitId' = 0x0B510ED610177874 + S4CL_GENDER_OPTIONS_TOILET_STANDING_CAT: 'CommonTraitId' = 0x044F7270266F8418 + S4CL_GENDER_OPTIONS_TOILET_SITTING_CAT: 'CommonTraitId' = 0xDB01DDB64FBD9B1E + S4CL_GENDER_OPTIONS_TOILET_STANDING_FOX: 'CommonTraitId' = 0x043E787026611B13 + S4CL_GENDER_OPTIONS_TOILET_SITTING_FOX: 'CommonTraitId' = 0xDAF0EFB64FAF46B5 + S4CL_GENDER_OPTIONS_TOILET_STANDING_HORSE: 'CommonTraitId' = 0x68AE8C13E8E70F1B + S4CL_GENDER_OPTIONS_TOILET_SITTING_HORSE: 'CommonTraitId' = 0xFE5E27AB9E824119 + + S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_LARGE_DOG: 'CommonTraitId' = 0x4F78FA2C6D704D37 + S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_LARGE_DOG: 'CommonTraitId' = 0x297A1DAA08640410 + S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_SMALL_DOG: 'CommonTraitId' = 0x4FA275D67AD6D9BF + S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_SMALL_DOG: 'CommonTraitId' = 0x5FE2BF1B88452A0C + S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_CAT: 'CommonTraitId' = 0x9CBE8604CD20F86D + S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_CAT: 'CommonTraitId' = 0xECCA44C52A8A9586 + S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_FOX: 'CommonTraitId' = 0x9CB49004CD18B4EA + S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_FOX: 'CommonTraitId' = 0xECB946C52A7C265D + S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_HORSE: 'CommonTraitId' = 0xAB4B78269AB15E72 + S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_HORSE: 'CommonTraitId' = 0xA6B30A268329CB01 + + S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_LARGE_DOG: 'CommonTraitId' = 0xF49A4DA8F37E4700 + S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_LARGE_DOG: 'CommonTraitId' = 0x66DBBBCC31E8E9B5 + S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_SMALL_DOG: 'CommonTraitId' = 0x408C1088D2971E7C + S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_SMALL_DOG: 'CommonTraitId' = 0xBF34158EBC37DAA1 + S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_CAT: 'CommonTraitId' = 0x085EA775A40A2216 + S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_CAT: 'CommonTraitId' = 0xAFF7AF13EBFD7673 + S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_FOX: 'CommonTraitId' = 0x084DA975A3FBB2ED + S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_FOX: 'CommonTraitId' = 0xAFED8513EBF4DA5C + S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_HORSE: 'CommonTraitId' = 0x8B87472A135AB931 + S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_HORSE: 'CommonTraitId' = 0xAE2C5DC67BD07418 + + # Obsolete backwards compatible traits (These are traits that EA removed) + ACTOR_CAREER_HIDDEN_AUDITION_AWAITING_AUDITION: 'CommonTraitId' = 198564 # Apparently EA deleted this trait. + ACTOR_CAREER_HIDDEN_CHECKPOINTS_AUDITION_SUCCESS_COMMERCIAL: 'CommonTraitId' = 198583 # Apparently EA deleted this trait. + ACTOR_CAREER_HIDDEN_CHECKPOINTS_AUDITION_SUCCESS_FILM: 'CommonTraitId' = 198584 # Apparently EA deleted this trait. + ACTOR_CAREER_HIDDEN_CHECKPOINTS_AUDITION_SUCCESS_HIGH_BUDGET_TV: 'CommonTraitId' = 198581 # Apparently EA deleted this trait. + ACTOR_CAREER_HIDDEN_CHECKPOINTS_AUDITION_SUCCESS_LOW_BUDGET_TV: 'CommonTraitId' = 198582 # Apparently EA deleted this trait. + PET_INSIDE_OUTSIDE: 'CommonTraitId' = 158719 # Apparently EA deleted this trait. + ACCEPTED_TO_UNIVERSITY: 'CommonTraitId' = 219693 + ACTIVE: 'CommonTraitId' = 27419 + ACTOR_CAREER_HIDDEN_CHECKPOINTS_NEW_TO_ACTOR_CAREER: 'CommonTraitId' = 198763 + ADOPT_TIGER_COMMODITY_HIDDEN: 'CommonTraitId' = 357832 + ADOPT_TIGER_HIDDEN: 'CommonTraitId' = 353574 + ADULT: 'CommonTraitId' = 34319 + ADVENTUROUS: 'CommonTraitId' = 252085 + ALLURING: 'CommonTraitId' = 26200 + ALWAYS_WELCOME: 'CommonTraitId' = 35504 + AMBITIOUS: 'CommonTraitId' = 16823 + ANGLERS_TRANQUILITY: 'CommonTraitId' = 26390 + ANIMAL_ATTRACTION: 'CommonTraitId' = 171824 + ANIMAL_CLOTHING_FOX_GRANDMA_1: 'CommonTraitId' = 268721 + ANIMAL_CLOTHING_FOX_GRANDMA_2: 'CommonTraitId' = 270028 + ANIMAL_CLOTHING_FOX_GRANDMA_3: 'CommonTraitId' = 270029 + ANIMAL_CLOTHING_FOX_GRANDMA_4: 'CommonTraitId' = 270030 + ANIMAL_CLOTHING_FOX_GRANDMA_5: 'CommonTraitId' = 270027 + ANIMAL_CLOTHING_FOX_GRANDMA_6: 'CommonTraitId' = 270026 + ANIMAL_CLOTHING_FOX_ROBBER_1: 'CommonTraitId' = 268722 + ANIMAL_CLOTHING_FOX_ROBBER_2: 'CommonTraitId' = 270033 + ANIMAL_CLOTHING_FOX_ROBBER_3: 'CommonTraitId' = 270034 + ANIMAL_CLOTHING_FOX_ROBBER_4: 'CommonTraitId' = 270035 + ANIMAL_CLOTHING_FOX_ROBBER_5: 'CommonTraitId' = 270036 + ANIMAL_CLOTHING_FOX_ROBBER_6: 'CommonTraitId' = 270031 + ANIMAL_CLOTHING_FOX_ROBBER_7: 'CommonTraitId' = 270032 + ANIMAL_CLOTHING_FOX_ROBIN_HOOD_1: 'CommonTraitId' = 268727 + ANIMAL_CLOTHING_FOX_ROBIN_HOOD_2: 'CommonTraitId' = 270039 + ANIMAL_CLOTHING_FOX_ROBIN_HOOD_3: 'CommonTraitId' = 270040 + ANIMAL_CLOTHING_FOX_ROBIN_HOOD_4: 'CommonTraitId' = 270041 + ANIMAL_CLOTHING_FOX_ROBIN_HOOD_5: 'CommonTraitId' = 270038 + ANIMAL_CLOTHING_FOX_ROBIN_HOOD_6: 'CommonTraitId' = 270037 + ANIMAL_ENTHUSIAST: 'CommonTraitId' = 257365 + ANIMAL_WHISPERER: 'CommonTraitId' = 171817 + ANTISEPTIC: 'CommonTraitId' = 26388 + APPRAISER: 'CommonTraitId' = 76821 + ARCHAEOLOGY_SCHOLAR_MUSEUM_PATRON: 'CommonTraitId' = 179023 + ARCHAEOLOGY_SKILL_GIVE_AUTHENTICATION_MAIL_PROHIBIT: 'CommonTraitId' = 176123 + ART_LOVER: 'CommonTraitId' = 27918 + ATTRACTION_ACTIVITIES_BROKE_TURN_OFF: 'CommonTraitId' = 365709 + ATTRACTION_ACTIVITIES_BROKE_TURN_ON: 'CommonTraitId' = 365708 + ATTRACTION_ACTIVITIES_CAREER_MINDED_TURN_OFF: 'CommonTraitId' = 365711 + ATTRACTION_ACTIVITIES_CAREER_MINDED_TURN_ON: 'CommonTraitId' = 365710 + ATTRACTION_ACTIVITIES_HIGHLY_SKILLED_TURN_OFF: 'CommonTraitId' = 365735 + ATTRACTION_ACTIVITIES_HIGHLY_SKILLED_TURN_ON: 'CommonTraitId' = 365734 + ATTRACTION_ACTIVITIES_SELF_EMPLOYED_TURN_OFF: 'CommonTraitId' = 365741 + ATTRACTION_ACTIVITIES_SELF_EMPLOYED_TURN_ON: 'CommonTraitId' = 365740 + ATTRACTION_ACTIVITIES_SLACKER_TURN_OFF: 'CommonTraitId' = 365743 + ATTRACTION_ACTIVITIES_SLACKER_TURN_ON: 'CommonTraitId' = 365742 + ATTRACTION_ACTIVITIES_TAKEN_TURN_OFF: 'CommonTraitId' = 365745 + ATTRACTION_ACTIVITIES_TAKEN_TURN_ON: 'CommonTraitId' = 365744 + ATTRACTION_ACTIVITIES_WEALTHY_TURN_OFF: 'CommonTraitId' = 365747 + ATTRACTION_ACTIVITIES_WEALTHY_TURN_ON: 'CommonTraitId' = 365746 + ATTRACTION_CHANGE_ATTRACTION_SETTINGS_TURN_OFF: 'CommonTraitId' = 373234 + ATTRACTION_CHARACTERISTICS_AMBITIONLESS_TURN_OFF: 'CommonTraitId' = 363398 + ATTRACTION_CHARACTERISTICS_AMBITIONLESS_TURN_ON: 'CommonTraitId' = 363397 + ATTRACTION_CHARACTERISTICS_AMBITIOUS_TURN_OFF: 'CommonTraitId' = 363922 + ATTRACTION_CHARACTERISTICS_AMBITIOUS_TURN_ON: 'CommonTraitId' = 363923 + ATTRACTION_CHARACTERISTICS_ARGUMENTATIVE_TURN_OFF: 'CommonTraitId' = 363924 + ATTRACTION_CHARACTERISTICS_ARGUMENTATIVE_TURN_ON: 'CommonTraitId' = 363925 + ATTRACTION_CHARACTERISTICS_CEREBRAL_TURN_OFF: 'CommonTraitId' = 363926 + ATTRACTION_CHARACTERISTICS_CEREBRAL_TURN_ON: 'CommonTraitId' = 363927 + ATTRACTION_CHARACTERISTICS_CLEAN_TURN_OFF: 'CommonTraitId' = 363928 + ATTRACTION_CHARACTERISTICS_CLEAN_TURN_ON: 'CommonTraitId' = 363929 + ATTRACTION_CHARACTERISTICS_EGOTISTICAL_TURN_OFF: 'CommonTraitId' = 363930 + ATTRACTION_CHARACTERISTICS_EGOTISTICAL_TURN_ON: 'CommonTraitId' = 363931 + ATTRACTION_CHARACTERISTICS_EMOTIONAL_DECISION_MAKERS_TURN_OFF: 'CommonTraitId' = 363932 + ATTRACTION_CHARACTERISTICS_EMOTIONAL_DECISION_MAKERS_TURN_ON: 'CommonTraitId' = 363933 + ATTRACTION_CHARACTERISTICS_FAMILY_MOTIVATED_TURN_OFF: 'CommonTraitId' = 363934 + ATTRACTION_CHARACTERISTICS_FAMILY_MOTIVATED_TURN_ON: 'CommonTraitId' = 363935 + ATTRACTION_CHARACTERISTICS_FUNNY_TURN_OFF: 'CommonTraitId' = 363936 + ATTRACTION_CHARACTERISTICS_FUNNY_TURN_ON: 'CommonTraitId' = 363937 + ATTRACTION_CHARACTERISTICS_HARD_WORKING_TURN_OFF: 'CommonTraitId' = 363938 + ATTRACTION_CHARACTERISTICS_HARD_WORKING_TURN_ON: 'CommonTraitId' = 363939 + ATTRACTION_CHARACTERISTICS_HIGH_ENERGY_TURN_OFF: 'CommonTraitId' = 363940 + ATTRACTION_CHARACTERISTICS_HIGH_ENERGY_TURN_ON: 'CommonTraitId' = 363941 + ATTRACTION_CHARACTERISTICS_HOME_BODY_TURN_OFF: 'CommonTraitId' = 363942 + ATTRACTION_CHARACTERISTICS_HOME_BODY_TURN_ON: 'CommonTraitId' = 363943 + ATTRACTION_CHARACTERISTICS_IDEALIST_TURN_OFF: 'CommonTraitId' = 363944 + ATTRACTION_CHARACTERISTICS_IDEALIST_TURN_ON: 'CommonTraitId' = 363945 + ATTRACTION_CHARACTERISTICS_MESSY_TURN_OFF: 'CommonTraitId' = 363946 + ATTRACTION_CHARACTERISTICS_MESSY_TURN_ON: 'CommonTraitId' = 363947 + ATTRACTION_CHARACTERISTICS_NATURE_ENTHUSIAST_TURN_OFF: 'CommonTraitId' = 363948 + ATTRACTION_CHARACTERISTICS_NATURE_ENTHUSIAST_TURN_ON: 'CommonTraitId' = 363949 + ATTRACTION_CHARACTERISTICS_OPTIMISTIC_TURN_OFF: 'CommonTraitId' = 363950 + ATTRACTION_CHARACTERISTICS_OPTIMISTIC_TURN_ON: 'CommonTraitId' = 363951 + ATTRACTION_CHARACTERISTICS_PESSIMISTIC_TURN_OFF: 'CommonTraitId' = 363952 + ATTRACTION_CHARACTERISTICS_PESSIMISTIC_TURN_ON: 'CommonTraitId' = 363953 + ATTRACTION_CHARACTERISTICS_PET_ENTHUSIAST_TURN_OFF: 'CommonTraitId' = 363954 + ATTRACTION_CHARACTERISTICS_PET_ENTHUSIAST_TURN_ON: 'CommonTraitId' = 363955 + ATTRACTION_CHARACTERISTICS_SPIRITED_TURN_OFF: 'CommonTraitId' = 363956 + ATTRACTION_CHARACTERISTICS_SPIRITED_TURN_ON: 'CommonTraitId' = 363957 + ATTRACTION_FASHION_BASICS_TURN_OFF: 'CommonTraitId' = 363402 + ATTRACTION_FASHION_BASICS_TURN_ON: 'CommonTraitId' = 363401 + ATTRACTION_FASHION_BOHO_TURN_OFF: 'CommonTraitId' = 364950 + ATTRACTION_FASHION_BOHO_TURN_ON: 'CommonTraitId' = 364951 + ATTRACTION_FASHION_COSTUMES_TURN_OFF: 'CommonTraitId' = 373277 + ATTRACTION_FASHION_COSTUMES_TURN_ON: 'CommonTraitId' = 373276 + ATTRACTION_FASHION_COUNTRY_TURN_OFF: 'CommonTraitId' = 364952 + ATTRACTION_FASHION_COUNTRY_TURN_ON: 'CommonTraitId' = 364953 + ATTRACTION_FASHION_HIPSTER_TURN_OFF: 'CommonTraitId' = 364955 + ATTRACTION_FASHION_HIPSTER_TURN_ON: 'CommonTraitId' = 364954 + ATTRACTION_FASHION_OUTDOORSY_TURN_OFF: 'CommonTraitId' = 364957 + ATTRACTION_FASHION_OUTDOORSY_TURN_ON: 'CommonTraitId' = 364956 + ATTRACTION_FASHION_POLISHED_TURN_OFF: 'CommonTraitId' = 364958 + ATTRACTION_FASHION_POLISHED_TURN_ON: 'CommonTraitId' = 364959 + ATTRACTION_FASHION_PREPPY_TURN_OFF: 'CommonTraitId' = 364960 + ATTRACTION_FASHION_PREPPY_TURN_ON: 'CommonTraitId' = 364961 + ATTRACTION_FASHION_ROCKER_TURN_OFF: 'CommonTraitId' = 364963 + ATTRACTION_FASHION_ROCKER_TURN_ON: 'CommonTraitId' = 364962 + ATTRACTION_FASHION_STREETWEAR_TURN_OFF: 'CommonTraitId' = 364965 + ATTRACTION_FASHION_STREETWEAR_TURN_ON: 'CommonTraitId' = 364964 + ATTRACTION_HAIR_COLOR_AUBURN_TURN_OFF: 'CommonTraitId' = 363405 + ATTRACTION_HAIR_COLOR_AUBURN_TURN_ON: 'CommonTraitId' = 363406 + ATTRACTION_HAIR_COLOR_BLACK_TURN_OFF: 'CommonTraitId' = 364993 + ATTRACTION_HAIR_COLOR_BLACK_TURN_ON: 'CommonTraitId' = 364992 + ATTRACTION_HAIR_COLOR_BLONDE_TURN_OFF: 'CommonTraitId' = 364994 + ATTRACTION_HAIR_COLOR_BLONDE_TURN_ON: 'CommonTraitId' = 364995 + ATTRACTION_HAIR_COLOR_BROWN_TURN_OFF: 'CommonTraitId' = 364998 + ATTRACTION_HAIR_COLOR_BROWN_TURN_ON: 'CommonTraitId' = 364999 + ATTRACTION_HAIR_COLOR_DARK_BLUE_TURN_OFF: 'CommonTraitId' = 364997 + ATTRACTION_HAIR_COLOR_DARK_BLUE_TURN_ON: 'CommonTraitId' = 364996 + ATTRACTION_HAIR_COLOR_GRAY_TURN_OFF: 'CommonTraitId' = 365000 + ATTRACTION_HAIR_COLOR_GRAY_TURN_ON: 'CommonTraitId' = 365001 + ATTRACTION_HAIR_COLOR_GREEN_TURN_OFF: 'CommonTraitId' = 365003 + ATTRACTION_HAIR_COLOR_GREEN_TURN_ON: 'CommonTraitId' = 365002 + ATTRACTION_HAIR_COLOR_HOT_PINK_TURN_OFF: 'CommonTraitId' = 365004 + ATTRACTION_HAIR_COLOR_HOT_PINK_TURN_ON: 'CommonTraitId' = 365005 + ATTRACTION_HAIR_COLOR_ORANGE_TURN_OFF: 'CommonTraitId' = 365007 + ATTRACTION_HAIR_COLOR_ORANGE_TURN_ON: 'CommonTraitId' = 365006 + ATTRACTION_HAIR_COLOR_PLATINUM_TURN_OFF: 'CommonTraitId' = 365009 + ATTRACTION_HAIR_COLOR_PLATINUM_TURN_ON: 'CommonTraitId' = 365008 + ATTRACTION_HAIR_COLOR_PURPLE_PASTEL_TURN_OFF: 'CommonTraitId' = 365011 + ATTRACTION_HAIR_COLOR_PURPLE_PASTEL_TURN_ON: 'CommonTraitId' = 365010 + ATTRACTION_HAIR_COLOR_RED_TURN_OFF: 'CommonTraitId' = 365013 + ATTRACTION_HAIR_COLOR_RED_TURN_ON: 'CommonTraitId' = 365012 + ATTRACTION_HAIR_COLOR_TURQUOISE_TURN_OFF: 'CommonTraitId' = 365015 + ATTRACTION_HAIR_COLOR_TURQUOISE_TURN_ON: 'CommonTraitId' = 365014 + ATTRACTION_HAIR_COLOR_WHITE_TURN_OFF: 'CommonTraitId' = 365017 + ATTRACTION_HAIR_COLOR_WHITE_TURN_ON: 'CommonTraitId' = 365016 + ATTRACTION_OUTFIT_COLOR_BLACK_TURN_OFF: 'CommonTraitId' = 363480 + ATTRACTION_OUTFIT_COLOR_BLACK_TURN_ON: 'CommonTraitId' = 363481 + ATTRACTION_OUTFIT_COLOR_BLUE_TURN_OFF: 'CommonTraitId' = 365029 + ATTRACTION_OUTFIT_COLOR_BLUE_TURN_ON: 'CommonTraitId' = 365028 + ATTRACTION_OUTFIT_COLOR_BROWN_TURN_OFF: 'CommonTraitId' = 365031 + ATTRACTION_OUTFIT_COLOR_BROWN_TURN_ON: 'CommonTraitId' = 365030 + ATTRACTION_OUTFIT_COLOR_GRAY_TURN_OFF: 'CommonTraitId' = 365033 + ATTRACTION_OUTFIT_COLOR_GRAY_TURN_ON: 'CommonTraitId' = 365032 + ATTRACTION_OUTFIT_COLOR_GREEN_TURN_OFF: 'CommonTraitId' = 365035 + ATTRACTION_OUTFIT_COLOR_GREEN_TURN_ON: 'CommonTraitId' = 365034 + ATTRACTION_OUTFIT_COLOR_ORANGE_TURN_OFF: 'CommonTraitId' = 365037 + ATTRACTION_OUTFIT_COLOR_ORANGE_TURN_ON: 'CommonTraitId' = 365036 + ATTRACTION_OUTFIT_COLOR_PINK_TURN_OFF: 'CommonTraitId' = 365039 + ATTRACTION_OUTFIT_COLOR_PINK_TURN_ON: 'CommonTraitId' = 365038 + ATTRACTION_OUTFIT_COLOR_PURPLE_TURN_OFF: 'CommonTraitId' = 365041 + ATTRACTION_OUTFIT_COLOR_PURPLE_TURN_ON: 'CommonTraitId' = 365040 + ATTRACTION_OUTFIT_COLOR_RED_TURN_OFF: 'CommonTraitId' = 365042 + ATTRACTION_OUTFIT_COLOR_RED_TURN_ON: 'CommonTraitId' = 365043 + ATTRACTION_OUTFIT_COLOR_WHITE_TURN_OFF: 'CommonTraitId' = 365045 + ATTRACTION_OUTFIT_COLOR_WHITE_TURN_ON: 'CommonTraitId' = 365044 + ATTRACTION_OUTFIT_COLOR_YELLOW_TURN_OFF: 'CommonTraitId' = 365047 + ATTRACTION_OUTFIT_COLOR_YELLOW_TURN_ON: 'CommonTraitId' = 365046 + ATTRACTION_ROMANCE_STYLES_AFFECTION_TURN_OFF: 'CommonTraitId' = 363455 + ATTRACTION_ROMANCE_STYLES_AFFECTION_TURN_ON: 'CommonTraitId' = 363456 + ATTRACTION_ROMANCE_STYLES_FLIRTING_TURN_OFF: 'CommonTraitId' = 364600 + ATTRACTION_ROMANCE_STYLES_FLIRTING_TURN_ON: 'CommonTraitId' = 364601 + ATTRACTION_ROMANCE_STYLES_GIFT_GIVING_TURN_OFF: 'CommonTraitId' = 364660 + ATTRACTION_ROMANCE_STYLES_GIFT_GIVING_TURN_ON: 'CommonTraitId' = 364661 + ATTRACTION_ROMANCE_STYLES_PHYSICAL_INTIMACY_TURN_OFF: 'CommonTraitId' = 364662 + ATTRACTION_ROMANCE_STYLES_PHYSICAL_INTIMACY_TURN_ON: 'CommonTraitId' = 364663 + ATTRACTION_ROMANCE_STYLES_WOOHOO_TURN_OFF: 'CommonTraitId' = 364664 + ATTRACTION_ROMANCE_STYLES_WOOHOO_TURN_ON: 'CommonTraitId' = 364665 + ATTRACTION_SKILL_ARCHETYPES_ACADEMIC_TURN_OFF: 'CommonTraitId' = 377508 + ATTRACTION_SKILL_ARCHETYPES_ACADEMIC_TURN_ON: 'CommonTraitId' = 377507 + ATTRACTION_SKILL_ARCHETYPES_ARTS_AND_CRAFTS_TURN_OFF: 'CommonTraitId' = 377495 + ATTRACTION_SKILL_ARCHETYPES_ARTS_AND_CRAFTS_TURN_ON: 'CommonTraitId' = 377494 + ATTRACTION_SKILL_ARCHETYPES_COOKING_TURN_OFF: 'CommonTraitId' = 377510 + ATTRACTION_SKILL_ARCHETYPES_COOKING_TURN_ON: 'CommonTraitId' = 377509 + ATTRACTION_SKILL_ARCHETYPES_DRINK_MAKING_TURN_OFF: 'CommonTraitId' = 377512 + ATTRACTION_SKILL_ARCHETYPES_DRINK_MAKING_TURN_ON: 'CommonTraitId' = 377511 + ATTRACTION_SKILL_ARCHETYPES_ENGINEERING_TURN_OFF: 'CommonTraitId' = 377514 + ATTRACTION_SKILL_ARCHETYPES_ENGINEERING_TURN_ON: 'CommonTraitId' = 377513 + ATTRACTION_SKILL_ARCHETYPES_HEALTH_AND_SPORTS_TURN_OFF: 'CommonTraitId' = 377516 + ATTRACTION_SKILL_ARCHETYPES_HEALTH_AND_SPORTS_TURN_ON: 'CommonTraitId' = 377515 + ATTRACTION_SKILL_ARCHETYPES_INTERPERSONAL_TURN_OFF: 'CommonTraitId' = 377518 + ATTRACTION_SKILL_ARCHETYPES_INTERPERSONAL_TURN_ON: 'CommonTraitId' = 377517 + ATTRACTION_SKILL_ARCHETYPES_MEDIA_AND_TECH_TURN_OFF: 'CommonTraitId' = 377520 + ATTRACTION_SKILL_ARCHETYPES_MEDIA_AND_TECH_TURN_ON: 'CommonTraitId' = 377519 + ATTRACTION_SKILL_ARCHETYPES_NATURE_TURN_OFF: 'CommonTraitId' = 377522 + ATTRACTION_SKILL_ARCHETYPES_NATURE_TURN_ON: 'CommonTraitId' = 377521 + ATTRACTION_SKILL_ARCHETYPES_PERFORMER_TURN_OFF: 'CommonTraitId' = 377524 + ATTRACTION_SKILL_ARCHETYPES_PERFORMER_TURN_ON: 'CommonTraitId' = 377523 + ATTRACTION_SKILL_ARCHETYPES_SENSE_OF_HUMOR_TURN_OFF: 'CommonTraitId' = 377526 + ATTRACTION_SKILL_ARCHETYPES_SENSE_OF_HUMOR_TURN_ON: 'CommonTraitId' = 377525 + AT_DAYCARE: 'CommonTraitId' = 105482 + BABY: 'CommonTraitId' = 34314 + BANE: 'CommonTraitId' = 27217 + BATUU_ALIEN: 'CommonTraitId' = 238971 + BATUU_ALIEN_ABEDNEDO: 'CommonTraitId' = 239906 + BATUU_ALIEN_BITH: 'CommonTraitId' = 239907 + BATUU_ALIEN_MIRIALAN: 'CommonTraitId' = 239904 + BATUU_ALIEN_TWILEK: 'CommonTraitId' = 239903 + BATUU_ALIEN_WEEQUAY: 'CommonTraitId' = 239902 + BATUU_ALIEN_ZABRAK: 'CommonTraitId' = 239905 + BATUU_FIRST_ORDER: 'CommonTraitId' = 233327 + BATUU_FIRST_ORDER_OFFICER: 'CommonTraitId' = 233345 + BATUU_FIRST_ORDER_OFFICER_RESISTANCE_SPY: 'CommonTraitId' = 249384 + BATUU_FIRST_ORDER_STORMTROOPER: 'CommonTraitId' = 233346 + BATUU_KNOWN: 'CommonTraitId' = 245215 + BATUU_LIGHTSABER: 'CommonTraitId' = 243724 + BATUU_LIGHTSABER_BLUE: 'CommonTraitId' = 235144 + BATUU_LIGHTSABER_GREEN: 'CommonTraitId' = 235145 + BATUU_LIGHTSABER_RED: 'CommonTraitId' = 235110 + BATUU_MISSION_ASK_ABOUT_FIRST_ORDER: 'CommonTraitId' = 237697 + BATUU_MISSION_ASK_ABOUT_RESISTANCE: 'CommonTraitId' = 237696 + BATUU_MISSION_BRIBE_CREDITS: 'CommonTraitId' = 240384 + BATUU_MISSION_BRIBE_DROID_PARTS: 'CommonTraitId' = 240386 + BATUU_MISSION_BRIBE_FOOD: 'CommonTraitId' = 240385 + BATUU_MISSION_BRIBE_HAS_BEEN_BRIBED: 'CommonTraitId' = 240413 + BATUU_MISSION_BRIBE_KYBER: 'CommonTraitId' = 248127 + BATUU_MISSION_BRIBE_PORG: 'CommonTraitId' = 248126 + BATUU_MISSION_CONVINCED_SCIENTIST_JOIN_FIRST_ORDER: 'CommonTraitId' = 241596 + BATUU_MISSION_DEFECTOR: 'CommonTraitId' = 243568 + BATUU_MISSION_FIRST_ORDER_REPEATABLE_1: 'CommonTraitId' = 244522 + BATUU_MISSION_FIRST_ORDER_REPEATABLE_13: 'CommonTraitId' = 244465 + BATUU_MISSION_FIRST_ORDER_REPEATABLE_2: 'CommonTraitId' = 244224 + BATUU_MISSION_FIRST_ORDER_REPEATABLE_3: 'CommonTraitId' = 244225 + BATUU_MISSION_FIRST_ORDER_STORY_4: 'CommonTraitId' = 246285 + BATUU_MISSION_FIRST_ORDER_STORY_4_CRIMINAL: 'CommonTraitId' = 245960 + BATUU_MISSION_FIRST_ORDER_STORY_4_CRIMINAL_HELPER: 'CommonTraitId' = 245961 + BATUU_MISSION_FIRST_ORDER_STORY_4_OBTAINED_CRIMINAL_INFO: 'CommonTraitId' = 241263 + BATUU_MISSION_FIRST_ORDER_STORY_6_SCIENTIST_JOINED: 'CommonTraitId' = 243731 + BATUU_MISSION_FIRST_ORDER_STORY_7_SHARED_FAKE_INFO_ALL: 'CommonTraitId' = 241718 + BATUU_MISSION_FREE_DRINKS_AT_OGAS_CANTINA: 'CommonTraitId' = 244158 + BATUU_MISSION_GIVEN_INFO: 'CommonTraitId' = 240524 + BATUU_MISSION_IS_INFORMANT: 'CommonTraitId' = 239909 + BATUU_MISSION_IS_RESISTANCE_SYMPATHIZER: 'CommonTraitId' = 243525 + BATUU_MISSION_RESISTANCE_CONTACT: 'CommonTraitId' = 240037 + BATUU_MISSION_RESISTANCE_REPEATABLE_15_CAN_RETRIEVE_DATA: 'CommonTraitId' = 245194 + BATUU_MISSION_RESISTANCE_REPEATABLE_1_PART_1: 'CommonTraitId' = 244227 + BATUU_MISSION_RESISTANCE_REPEATABLE_1_PART_2: 'CommonTraitId' = 244228 + BATUU_MISSION_RESISTANCE_REPEATABLE_2: 'CommonTraitId' = 244229 + BATUU_MISSION_RESISTANCE_STORY_2_OBTAINED_FIRST_ORDER_ACCESS_CODE: 'CommonTraitId' = 239472 + BATUU_MISSION_RESISTANCE_STORY_3_REPAIRED: 'CommonTraitId' = 251238 + BATUU_MISSION_RESISTANCE_STORY_3_SCRAMBLED: 'CommonTraitId' = 251237 + BATUU_MISSION_RESISTANCE_STORY_9_DESTROY_JAMMING_EQUIPMENT: 'CommonTraitId' = 243978 + BATUU_MISSION_SABACC_TOURNAMENT_1ST_OPPONENT: 'CommonTraitId' = 244445 + BATUU_MISSION_SABACC_TOURNAMENT_2ND_OPPONENT: 'CommonTraitId' = 244446 + BATUU_MISSION_SABACC_TOURNAMENT_FINAL_OPPONENT: 'CommonTraitId' = 244447 + BATUU_MISSION_SABACC_TOURNAMENT_PLAYED_ALL_OPPONENTS: 'CommonTraitId' = 250970 + BATUU_MISSION_SCIENTIST_DO_WORK: 'CommonTraitId' = 247605 + BATUU_MISSION_SCOUNDREL_CONTACT: 'CommonTraitId' = 240262 + BATUU_MISSION_SCOUNDREL_REPEATABLE_4_CONTRABAND_LOCATION_BLACK_SPIRE_OUTPOST: 'CommonTraitId' = 244602 + BATUU_MISSION_SCOUNDREL_REPEATABLE_4_CONTRABAND_LOCATION_FIRST_ORDER: 'CommonTraitId' = 244601 + BATUU_MISSION_SCOUNDREL_STORY_7_RECRUITED_HEIST: 'CommonTraitId' = 244826 + BATUU_MISSION_STORMTROOPER_CHECK_ID: 'CommonTraitId' = 243985 + BATUU_NPC: 'CommonTraitId' = 231263 + BATUU_NPC_CITIZEN: 'CommonTraitId' = 235820 + BATUU_REPUTATION_NEGATIVE_FIRST_ORDER_MODIFIER_LEVEL_1: 'CommonTraitId' = 243013 + BATUU_REPUTATION_NEGATIVE_FIRST_ORDER_MODIFIER_LEVEL_2: 'CommonTraitId' = 243040 + BATUU_REPUTATION_NEGATIVE_FIRST_ORDER_MODIFIER_LEVEL_3: 'CommonTraitId' = 243041 + BATUU_REPUTATION_NEGATIVE_FIRST_ORDER_MODIFIER_LEVEL_4: 'CommonTraitId' = 243039 + BATUU_REPUTATION_NEGATIVE_FIRST_ORDER_MODIFIER_LEVEL_5: 'CommonTraitId' = 243038 + BATUU_REPUTATION_NEGATIVE_RESISTANCE_MODIFIER_LEVEL_1: 'CommonTraitId' = 243062 + BATUU_REPUTATION_NEGATIVE_RESISTANCE_MODIFIER_LEVEL_2: 'CommonTraitId' = 243063 + BATUU_REPUTATION_NEGATIVE_RESISTANCE_MODIFIER_LEVEL_3: 'CommonTraitId' = 243064 + BATUU_REPUTATION_NEGATIVE_RESISTANCE_MODIFIER_LEVEL_4: 'CommonTraitId' = 243065 + BATUU_REPUTATION_NEGATIVE_RESISTANCE_MODIFIER_LEVEL_5: 'CommonTraitId' = 243066 + BATUU_REPUTATION_NEGATIVE_SCOUNDREL_MODIFIER_LEVEL_1: 'CommonTraitId' = 243069 + BATUU_REPUTATION_NEGATIVE_SCOUNDREL_MODIFIER_LEVEL_2: 'CommonTraitId' = 243070 + BATUU_REPUTATION_NEGATIVE_SCOUNDREL_MODIFIER_LEVEL_3: 'CommonTraitId' = 243071 + BATUU_REPUTATION_NEGATIVE_SCOUNDREL_MODIFIER_LEVEL_4: 'CommonTraitId' = 243072 + BATUU_REPUTATION_NEGATIVE_SCOUNDREL_MODIFIER_LEVEL_5: 'CommonTraitId' = 243073 + BATUU_RESISTANCE: 'CommonTraitId' = 233326 + BATUU_RICH_SCOUNDREL: 'CommonTraitId' = 244192 + BATUU_SCOUNDREL: 'CommonTraitId' = 233344 + BAY_AREA_NPC_ADHARA_MICHAELSON_HIDDEN: 'CommonTraitId' = 302879 + BAY_AREA_NPC_AURELIO_ROBLES_HIDDEN: 'CommonTraitId' = 302877 + BAY_AREA_NPC_BERNICE_ROBLES_HIDDEN: 'CommonTraitId' = 302875 + BAY_AREA_NPC_CHRISTOPHER_MICHAELSON_HIDDEN: 'CommonTraitId' = 302878 + BAY_AREA_NPC_DOLI_RUANO_HIDDEN: 'CommonTraitId' = 302881 + BAY_AREA_NPC_ELEANOR_SULLIVAN_HIDDEN: 'CommonTraitId' = 302885 + BAY_AREA_NPC_IAN_ROBLES_HIDDEN: 'CommonTraitId' = 302876 + BAY_AREA_NPC_IGNACIO_ROBLES_HIDDEN: 'CommonTraitId' = 302874 + BAY_AREA_NPC_JAY_ROBLES_HIDDEN: 'CommonTraitId' = 302880 + BAY_AREA_NPC_KARMINE_LUNA_HIDDEN: 'CommonTraitId' = 302884 + BAY_AREA_NPC_KYLE_KYLESON_HIDDEN: 'CommonTraitId' = 302886 + BAY_AREA_NPC_ORION_MICHAELSON_HIDDEN: 'CommonTraitId' = 308600 + BAY_AREA_NPC_PENELOPE_MICHAELSON_HIDDEN: 'CommonTraitId' = 308601 + BAY_AREA_NPC_TALA_RUANO_HIDDEN: 'CommonTraitId' = 302882 + BAY_AREA_NPC_XOCHITL_LUNA_HIDDEN: 'CommonTraitId' = 302883 + BEACH_BUM_LAID_BACK: 'CommonTraitId' = 211971 + BEGUILING: 'CommonTraitId' = 26203 + BONEHILDA: 'CommonTraitId' = 253237 + BOOKWORM: 'CommonTraitId' = 27916 + BRAVE: 'CommonTraitId' = 253268 + BREASTS_FORCE_OFF: 'CommonTraitId' = 136862 + BREASTS_FORCE_ON: 'CommonTraitId' = 136863 + BRO: 'CommonTraitId' = 16826 + BUSINESS_SAVVY: 'CommonTraitId' = 27082 + CAREER_FREELANCER_AGENCIES_FASHION_PHOTOGRAPHER: 'CommonTraitId' = 214787 + CAREER_FREELANCER_AGENCIES_INTERIOR_DECORATOR: 'CommonTraitId' = 257957 + CAREER_FREELANCER_AGENCIES_MAKER: 'CommonTraitId' = 234236 + CAREER_FREELANCER_AGENCIES_PAINTING: 'CommonTraitId' = 205700 + CAREER_FREELANCER_AGENCIES_PARANORMAL_INVESTIGATOR: 'CommonTraitId' = 252647 + CAREER_FREELANCER_AGENCIES_PROGRAMMING: 'CommonTraitId' = 205701 + CAREER_FREELANCER_AGENCIES_WRITING: 'CommonTraitId' = 205702 + CAREER_FREELANCER_BONUS_GIG_PAYOUT: 'CommonTraitId' = 211624 + CAREER_FREELANCER_COMPLETED_MEET_WITH_CLIENT: 'CommonTraitId' = 212114 + CAREER_FREELANCER_FASHION_PHOTOGRAPHER_UNLOCKED_MAGAZINE_COVER_SUBMISSION: 'CommonTraitId' = 219050 + CAREER_FREELANCER_FASHION_PHOTOGRAPHER_UNLOCKED_PHOTO_EDITOR: 'CommonTraitId' = 219051 + CAREER_FREELANCER_FASHION_PHOTOGRAPHER_WAITING_FOR_MAGAZINE: 'CommonTraitId' = 221339 + CAREER_FREELANCER_PARANORMAL_INVESTIGATOR_LICENSE: 'CommonTraitId' = 252818 + CAREER_FREELANCER_UNLOCKED_MEET: 'CommonTraitId' = 211942 + CAREER_FREELANCER_UNLOCKED_OVERCLOCK: 'CommonTraitId' = 209478 + CAREER_LIFEGUARD_REWARDS_LEVEL_2: 'CommonTraitId' = 212019 + CAREER_LIFEGUARD_REWARDS_LEVEL_3: 'CommonTraitId' = 212020 + CAREER_PAY_BOOSTS_LAW_CLIENTS_1: 'CommonTraitId' = 228732 + CAREER_PAY_BOOSTS_LAW_CLIENTS_10: 'CommonTraitId' = 228741 + CAREER_PAY_BOOSTS_LAW_CLIENTS_2: 'CommonTraitId' = 228733 + CAREER_PAY_BOOSTS_LAW_CLIENTS_3: 'CommonTraitId' = 228734 + CAREER_PAY_BOOSTS_LAW_CLIENTS_4: 'CommonTraitId' = 228735 + CAREER_PAY_BOOSTS_LAW_CLIENTS_5: 'CommonTraitId' = 228736 + CAREER_PAY_BOOSTS_LAW_CLIENTS_6: 'CommonTraitId' = 228737 + CAREER_PAY_BOOSTS_LAW_CLIENTS_7: 'CommonTraitId' = 228738 + CAREER_PAY_BOOSTS_LAW_CLIENTS_8: 'CommonTraitId' = 228739 + CAREER_PAY_BOOSTS_LAW_CLIENTS_9: 'CommonTraitId' = 228740 + CAREER_SCIENTIST_EVENT_INVENTING: 'CommonTraitId' = 112700 + CAREER_SIMSFLUENCER_SIDE_HUSTLE_CAN_REVIEW: 'CommonTraitId' = 278995 + CAREER_SIMSFLUENCER_SIDE_HUSTLE_GIFT_DELIVERY: 'CommonTraitId' = 278996 + CAREFREE: 'CommonTraitId' = 26476 + CARRIER_PREFERENCE_INFANT_BLACK_YELLOW: 'CommonTraitId' = 325315 + CARRIER_PREFERENCE_INFANT_GREY: 'CommonTraitId' = 307874 + CARRIER_PREFERENCE_INFANT_PINK: 'CommonTraitId' = 307875 + CARRIER_PREFERENCE_INFANT_STURDY_BLUE: 'CommonTraitId' = 325317 + CARRIER_PREFERENCE_INFANT_STURDY_GRAY: 'CommonTraitId' = 325318 + CARRIER_PREFERENCE_INFANT_STURDY_GREEN: 'CommonTraitId' = 325319 + CARRIER_PREFERENCE_INFANT_STURDY_ORANGE: 'CommonTraitId' = 317068 + CARRIER_PREFERENCE_INFANT_STURDY_RED: 'CommonTraitId' = 325320 + CARRIER_PREFERENCE_INFANT_WHITE: 'CommonTraitId' = 325316 + CAS_STORY_CAREER_ACTIVIST: 'CommonTraitId' = 213270 + CAS_STORY_CAREER_ACTIVIST_LEVEL_2: 'CommonTraitId' = 216463 + CAS_STORY_CAREER_ACTIVIST_LEVEL_3: 'CommonTraitId' = 216464 + CAS_STORY_CAREER_ACTOR: 'CommonTraitId' = 213263 + CAS_STORY_CAREER_ACTOR_LEVEL_2: 'CommonTraitId' = 216475 + CAS_STORY_CAREER_ACTOR_LEVEL_3: 'CommonTraitId' = 216476 + CAS_STORY_CAREER_ASTRONAUT: 'CommonTraitId' = 213204 + CAS_STORY_CAREER_ASTRONAUT_LEVEL_2: 'CommonTraitId' = 216412 + CAS_STORY_CAREER_ASTRONAUT_LEVEL_3: 'CommonTraitId' = 216413 + CAS_STORY_CAREER_ATHLETIC: 'CommonTraitId' = 217480 + CAS_STORY_CAREER_ATHLETIC_2: 'CommonTraitId' = 217481 + CAS_STORY_CAREER_ATHLETIC_3: 'CommonTraitId' = 217482 + CAS_STORY_CAREER_BUSINESS: 'CommonTraitId' = 213205 + CAS_STORY_CAREER_BUSINESS_LEVEL_2: 'CommonTraitId' = 216421 + CAS_STORY_CAREER_BUSINESS_LEVEL_3: 'CommonTraitId' = 216422 + CAS_STORY_CAREER_CIVIL_DESIGNER: 'CommonTraitId' = 239454 + CAS_STORY_CAREER_CIVIL_DESIGNER_LEVEL_2: 'CommonTraitId' = 239456 + CAS_STORY_CAREER_CIVIL_DESIGNER_LEVEL_3: 'CommonTraitId' = 239455 + CAS_STORY_CAREER_CONSERVATIONIST: 'CommonTraitId' = 215946 + CAS_STORY_CAREER_CONSERVATIONIST_LEVEL_2: 'CommonTraitId' = 216478 + CAS_STORY_CAREER_CONSERVATIONIST_LEVEL_3: 'CommonTraitId' = 216479 + CAS_STORY_CAREER_CORPORATE_0: 'CommonTraitId' = 251783 + CAS_STORY_CAREER_CORPORATE_LEVEL_2: 'CommonTraitId' = 251784 + CAS_STORY_CAREER_CORPORATE_LEVEL_3: 'CommonTraitId' = 251785 + CAS_STORY_CAREER_CRIMINAL: 'CommonTraitId' = 213206 + CAS_STORY_CAREER_CRIMINAL_LEVEL_2: 'CommonTraitId' = 216424 + CAS_STORY_CAREER_CRIMINAL_LEVEL_3: 'CommonTraitId' = 216425 + CAS_STORY_CAREER_CRITIC: 'CommonTraitId' = 213267 + CAS_STORY_CAREER_CRITIC_LEVEL_2: 'CommonTraitId' = 216466 + CAS_STORY_CAREER_CRITIC_LEVEL_3: 'CommonTraitId' = 216467 + CAS_STORY_CAREER_CULINARY: 'CommonTraitId' = 213207 + CAS_STORY_CAREER_CULINARY_LEVEL_2: 'CommonTraitId' = 216427 + CAS_STORY_CAREER_CULINARY_LEVEL_3: 'CommonTraitId' = 216428 + CAS_STORY_CAREER_DETECTIVE: 'CommonTraitId' = 213264 + CAS_STORY_CAREER_DETECTIVE_LEVEL_2: 'CommonTraitId' = 216451 + CAS_STORY_CAREER_DETECTIVE_LEVEL_3: 'CommonTraitId' = 216452 + CAS_STORY_CAREER_DIVER: 'CommonTraitId' = 215948 + CAS_STORY_CAREER_DIVER_LEVEL_2: 'CommonTraitId' = 216481 + CAS_STORY_CAREER_DIVER_LEVEL_3: 'CommonTraitId' = 216482 + CAS_STORY_CAREER_DOCTOR: 'CommonTraitId' = 213265 + CAS_STORY_CAREER_DOCTOR_LEVEL_2: 'CommonTraitId' = 216454 + CAS_STORY_CAREER_DOCTOR_LEVEL_3: 'CommonTraitId' = 216455 + CAS_STORY_CAREER_EDUCATION: 'CommonTraitId' = 227290 + CAS_STORY_CAREER_EDUCATION_LEVEL_2: 'CommonTraitId' = 227291 + CAS_STORY_CAREER_EDUCATION_LEVEL_3: 'CommonTraitId' = 227292 + CAS_STORY_CAREER_ENGINEER: 'CommonTraitId' = 227295 + CAS_STORY_CAREER_ENGINEER_LEVEL_2: 'CommonTraitId' = 227296 + CAS_STORY_CAREER_ENGINEER_LEVEL_3: 'CommonTraitId' = 227297 + CAS_STORY_CAREER_ENTERTAINER: 'CommonTraitId' = 213208 + CAS_STORY_CAREER_ENTERTAINER_LEVEL_2: 'CommonTraitId' = 216430 + CAS_STORY_CAREER_ENTERTAINER_LEVEL_3: 'CommonTraitId' = 216431 + CAS_STORY_CAREER_FISHERMAN: 'CommonTraitId' = 216487 + CAS_STORY_CAREER_FISHERMAN_LEVEL_2: 'CommonTraitId' = 216484 + CAS_STORY_CAREER_FISHERMAN_LEVEL_3: 'CommonTraitId' = 216485 + CAS_STORY_CAREER_FREELANCER: 'CommonTraitId' = 213209 + CAS_STORY_CAREER_GARDENER: 'CommonTraitId' = 213269 + CAS_STORY_CAREER_GARDENER_LEVEL_2: 'CommonTraitId' = 216472 + CAS_STORY_CAREER_GARDENER_LEVEL_3: 'CommonTraitId' = 216473 + CAS_STORY_CAREER_LAW: 'CommonTraitId' = 227298 + CAS_STORY_CAREER_LAW_LEVEL_2: 'CommonTraitId' = 227299 + CAS_STORY_CAREER_LAW_LEVEL_3: 'CommonTraitId' = 227300 + CAS_STORY_CAREER_LIFEGUARD: 'CommonTraitId' = 217924 + CAS_STORY_CAREER_LIFEGUARD_LEVEL_2: 'CommonTraitId' = 217925 + CAS_STORY_CAREER_LIFEGUARD_LEVEL_3: 'CommonTraitId' = 217926 + CAS_STORY_CAREER_MILITARY: 'CommonTraitId' = 215965 + CAS_STORY_CAREER_MILITARY_LEVEL_2: 'CommonTraitId' = 216460 + CAS_STORY_CAREER_MILITARY_LEVEL_3: 'CommonTraitId' = 216461 + CAS_STORY_CAREER_PAINTER: 'CommonTraitId' = 213177 + CAS_STORY_CAREER_PAINTER_LEVEL_2: 'CommonTraitId' = 216436 + CAS_STORY_CAREER_PAINTER_LEVEL_3: 'CommonTraitId' = 216437 + CAS_STORY_CAREER_ROMANCE_CONSULTANT_LEVEL_1: 'CommonTraitId' = 365475 + CAS_STORY_CAREER_ROMANCE_CONSULTANT_LEVEL_2: 'CommonTraitId' = 365476 + CAS_STORY_CAREER_ROMANCE_CONSULTANT_LEVEL_3: 'CommonTraitId' = 365477 + CAS_STORY_CAREER_SCIENTIST: 'CommonTraitId' = 213266 + CAS_STORY_CAREER_SCIENTIST_LEVEL_2: 'CommonTraitId' = 216457 + CAS_STORY_CAREER_SCIENTIST_LEVEL_3: 'CommonTraitId' = 216458 + CAS_STORY_CAREER_SECRET_AGENT: 'CommonTraitId' = 213210 + CAS_STORY_CAREER_SECRET_AGENT_LEVEL_2: 'CommonTraitId' = 216439 + CAS_STORY_CAREER_SECRET_AGENT_LEVEL_3: 'CommonTraitId' = 216440 + CAS_STORY_CAREER_SOCIAL_MEDIA: 'CommonTraitId' = 213268 + CAS_STORY_CAREER_SOCIAL_MEDIA_LEVEL_2: 'CommonTraitId' = 216469 + CAS_STORY_CAREER_SOCIAL_MEDIA_LEVEL_3: 'CommonTraitId' = 216470 + CAS_STORY_CAREER_STYLE_INFLUENCER: 'CommonTraitId' = 213211 + CAS_STORY_CAREER_STYLE_INFLUENCER_LEVEL_2: 'CommonTraitId' = 216442 + CAS_STORY_CAREER_STYLE_INFLUENCER_LEVEL_3: 'CommonTraitId' = 216443 + CAS_STORY_CAREER_TECH_GURU: 'CommonTraitId' = 213212 + CAS_STORY_CAREER_TECH_GURU_LEVEL_2: 'CommonTraitId' = 216445 + CAS_STORY_CAREER_TECH_GURU_LEVEL_3: 'CommonTraitId' = 216446 + CAS_STORY_CAREER_UNEMPLOYED: 'CommonTraitId' = 216896 + CAS_STORY_CAREER_WRITER: 'CommonTraitId' = 213213 + CAS_STORY_CAREER_WRITER_LEVEL_2: 'CommonTraitId' = 216448 + CAS_STORY_CAREER_WRITER_LEVEL_3: 'CommonTraitId' = 216449 + CAS_STORY_HOUSEHOLD_FUNDS_HIGH: 'CommonTraitId' = 215921 + CAS_STORY_HOUSEHOLD_FUNDS_LOW: 'CommonTraitId' = 215919 + CAS_STORY_HOUSEHOLD_FUNDS_MED: 'CommonTraitId' = 215920 + CAS_STORY_OCCULT_GHOST: 'CommonTraitId' = 213178 + CAS_STORY_OCCULT_VAMPIRE: 'CommonTraitId' = 213261 + CAS_STORY_SKILL_ACTING: 'CommonTraitId' = 213281 + CAS_STORY_SKILL_ACTING_3: 'CommonTraitId' = 216742 + CAS_STORY_SKILL_ARCHAEOLOGY: 'CommonTraitId' = 213277 + CAS_STORY_SKILL_ARCHAEOLOGY_3: 'CommonTraitId' = 216734 + CAS_STORY_SKILL_BAKING: 'CommonTraitId' = 213272 + CAS_STORY_SKILL_BAKING_3: 'CommonTraitId' = 216722 + CAS_STORY_SKILL_BOWLING: 'CommonTraitId' = 215951 + CAS_STORY_SKILL_BOWLING_3: 'CommonTraitId' = 216728 + CAS_STORY_SKILL_CHARISMA: 'CommonTraitId' = 213189 + CAS_STORY_SKILL_CHARISMA_3: 'CommonTraitId' = 216676 + CAS_STORY_SKILL_COMEDY: 'CommonTraitId' = 213190 + CAS_STORY_SKILL_COMEDY_3: 'CommonTraitId' = 216678 + CAS_STORY_SKILL_COOKING: 'CommonTraitId' = 213185 + CAS_STORY_SKILL_COOKING_3: 'CommonTraitId' = 216680 + CAS_STORY_SKILL_CROSS_STITCH: 'CommonTraitId' = 260955 + CAS_STORY_SKILL_CROSS_STITCH_3: 'CommonTraitId' = 260956 + CAS_STORY_SKILL_DANCING_1: 'CommonTraitId' = 213203 + CAS_STORY_SKILL_DANCING_2: 'CommonTraitId' = 216777 + CAS_STORY_SKILL_DANCING_3: 'CommonTraitId' = 216778 + CAS_STORY_SKILL_DJ_MIXING: 'CommonTraitId' = 213274 + CAS_STORY_SKILL_DJ_MIXING_3: 'CommonTraitId' = 216726 + CAS_STORY_SKILL_ENTREPRENEUR: 'CommonTraitId' = 288961 + CAS_STORY_SKILL_ENTREPRENEUR_3: 'CommonTraitId' = 288962 + CAS_STORY_SKILL_EQUESTRIAN_SKILL: 'CommonTraitId' = 334054 + CAS_STORY_SKILL_EQUESTRIAN_SKILL_3: 'CommonTraitId' = 334055 + CAS_STORY_SKILL_FABRICATION: 'CommonTraitId' = 239334 + CAS_STORY_SKILL_FABRICATION_3: 'CommonTraitId' = 239335 + CAS_STORY_SKILL_FISHING: 'CommonTraitId' = 213191 + CAS_STORY_SKILL_FISHING_3: 'CommonTraitId' = 216684 + CAS_STORY_SKILL_FITNESS: 'CommonTraitId' = 213187 + CAS_STORY_SKILL_FITNESS_3: 'CommonTraitId' = 216686 + CAS_STORY_SKILL_FLOWER_ARRANGING: 'CommonTraitId' = 213280 + CAS_STORY_SKILL_FLOWER_ARRANGING_3: 'CommonTraitId' = 216740 + CAS_STORY_SKILL_GARDENING: 'CommonTraitId' = 213192 + CAS_STORY_SKILL_GARDENING_3: 'CommonTraitId' = 216688 + CAS_STORY_SKILL_GOURMET_COOKING: 'CommonTraitId' = 213193 + CAS_STORY_SKILL_GOURMET_COOKING_3: 'CommonTraitId' = 216690 + CAS_STORY_SKILL_GUITAR: 'CommonTraitId' = 213194 + CAS_STORY_SKILL_GUITAR_3: 'CommonTraitId' = 216692 + CAS_STORY_SKILL_HANDINESS: 'CommonTraitId' = 213195 + CAS_STORY_SKILL_HANDINESS_3: 'CommonTraitId' = 216694 + CAS_STORY_SKILL_HERBALISM: 'CommonTraitId' = 213271 + CAS_STORY_SKILL_HERBALISM_3: 'CommonTraitId' = 216720 + CAS_STORY_SKILL_JUICE_FIZZING: 'CommonTraitId' = 239333 + CAS_STORY_SKILL_JUICE_FIZZING_3: 'CommonTraitId' = 239337 + CAS_STORY_SKILL_LOCAL_CULTURE: 'CommonTraitId' = 217042 + CAS_STORY_SKILL_LOCAL_CULTURE_3: 'CommonTraitId' = 217043 + CAS_STORY_SKILL_LOGIC: 'CommonTraitId' = 213196 + CAS_STORY_SKILL_LOGIC_3: 'CommonTraitId' = 216696 + CAS_STORY_SKILL_MISCHIEF: 'CommonTraitId' = 213197 + CAS_STORY_SKILL_MISCHIEF_3: 'CommonTraitId' = 216698 + CAS_STORY_SKILL_MIXOLOGY: 'CommonTraitId' = 213188 + CAS_STORY_SKILL_MIXOLOGY_3: 'CommonTraitId' = 216700 + CAS_STORY_SKILL_NECTAR: 'CommonTraitId' = 334061 + CAS_STORY_SKILL_NECTAR_3: 'CommonTraitId' = 334062 + CAS_STORY_SKILL_PAINTING: 'CommonTraitId' = 213176 + CAS_STORY_SKILL_PAINTING_3: 'CommonTraitId' = 216702 + CAS_STORY_SKILL_PARENTING: 'CommonTraitId' = 213276 + CAS_STORY_SKILL_PARENTING_3: 'CommonTraitId' = 216732 + CAS_STORY_SKILL_PET_TRAINING: 'CommonTraitId' = 217046 + CAS_STORY_SKILL_PET_TRAINING_3: 'CommonTraitId' = 217047 + CAS_STORY_SKILL_PHOTOGRAPHY: 'CommonTraitId' = 213198 + CAS_STORY_SKILL_PHOTOGRAPHY_3: 'CommonTraitId' = 216704 + CAS_STORY_SKILL_PIANO: 'CommonTraitId' = 213199 + CAS_STORY_SKILL_PIANO_3: 'CommonTraitId' = 216706 + CAS_STORY_SKILL_PIPE_ORGAN: 'CommonTraitId' = 213275 + CAS_STORY_SKILL_PIPE_ORGAN_3: 'CommonTraitId' = 216730 + CAS_STORY_SKILL_PROGRAMMING: 'CommonTraitId' = 213184 + CAS_STORY_SKILL_PROGRAMMING_3: 'CommonTraitId' = 216708 + CAS_STORY_SKILL_RESEARCH_DEBATE: 'CommonTraitId' = 227287 + CAS_STORY_SKILL_RESEARCH_DEBATE_3: 'CommonTraitId' = 227288 + CAS_STORY_SKILL_ROBOTICS: 'CommonTraitId' = 227278 + CAS_STORY_SKILL_ROBOTICS_3: 'CommonTraitId' = 227279 + CAS_STORY_SKILL_ROCKET_SCIENCE: 'CommonTraitId' = 213200 + CAS_STORY_SKILL_ROCKET_SCIENCE_3: 'CommonTraitId' = 216710 + CAS_STORY_SKILL_ROCK_CLIMBING: 'CommonTraitId' = 251792 + CAS_STORY_SKILL_ROCK_CLIMBING_3: 'CommonTraitId' = 251793 + CAS_STORY_SKILL_ROMANCE: 'CommonTraitId' = 365472 + CAS_STORY_SKILL_SINGING: 'CommonTraitId' = 213278 + CAS_STORY_SKILL_SINGING_3: 'CommonTraitId' = 216736 + CAS_STORY_SKILL_SKIING: 'CommonTraitId' = 251797 + CAS_STORY_SKILL_SKIING_3: 'CommonTraitId' = 251798 + CAS_STORY_SKILL_SNOWBOARDING: 'CommonTraitId' = 251799 + CAS_STORY_SKILL_SNOWBOARDING_3: 'CommonTraitId' = 251800 + CAS_STORY_SKILL_VAMPIRE_LORE: 'CommonTraitId' = 217484 + CAS_STORY_SKILL_VAMPIRE_LORE_3: 'CommonTraitId' = 217485 + CAS_STORY_SKILL_VETERINARIAN: 'CommonTraitId' = 213279 + CAS_STORY_SKILL_VETERINARIAN_3: 'CommonTraitId' = 216738 + CAS_STORY_SKILL_VIDEO_GAMING: 'CommonTraitId' = 213201 + CAS_STORY_SKILL_VIDEO_GAMING_3: 'CommonTraitId' = 216713 + CAS_STORY_SKILL_VIOLIN: 'CommonTraitId' = 213202 + CAS_STORY_SKILL_VIOLIN_3: 'CommonTraitId' = 216716 + CAS_STORY_SKILL_WELLNESS: 'CommonTraitId' = 213273 + CAS_STORY_SKILL_WELLNESS_3: 'CommonTraitId' = 216724 + CAS_STORY_SKILL_WRITING: 'CommonTraitId' = 213186 + CAS_STORY_SKILL_WRITING_3: 'CommonTraitId' = 216718 + CAT_LOVER: 'CommonTraitId' = 157978 + CAT_QUIRK_SLEEP_STYLE_BACK: 'CommonTraitId' = 155557 + CAT_QUIRK_SLEEP_STYLE_CURL: 'CommonTraitId' = 155556 + CAT_QUIRK_STAND_WATCH_FALSE: 'CommonTraitId' = 173581 + CAT_QUIRK_STAND_WATCH_TRUE: 'CommonTraitId' = 173582 + CAULDRON_POTION_IMMORTALITY: 'CommonTraitId' = 214389 + CAULDRON_POTION_LUCK_CLUMSY: 'CommonTraitId' = 215779 + CELEBRITY_FANS_NERVOUS: 'CommonTraitId' = 196899 + CELEBRITY_FANS_SOCIAL: 'CommonTraitId' = 196900 + CELEBRITY_FANS_TOUCHY: 'CommonTraitId' = 196902 + CHALLENGE_KINDNESS_AMBASSADOR: 'CommonTraitId' = 198885 + CHAMPION_OF_THE_PEOPLE: 'CommonTraitId' = 234567 + CHEERFUL: 'CommonTraitId' = 9322 + CHILD: 'CommonTraitId' = 34316 + CHILDHOOD_PHASE_BEAR: 'CommonTraitId' = 164767 + CHILDHOOD_PHASE_CLINGY: 'CommonTraitId' = 164764 + CHILDHOOD_PHASE_DISTANT: 'CommonTraitId' = 164768 + CHILDHOOD_PHASE_LOUD: 'CommonTraitId' = 164766 + CHILDHOOD_PHASE_MEAN_STREAK: 'CommonTraitId' = 164769 + CHILDHOOD_PHASE_PICKY_EATER_A: 'CommonTraitId' = 164763 + CHILDHOOD_PHASE_PICKY_EATER_B: 'CommonTraitId' = 164972 + CHILDHOOD_PHASE_PICKY_EATER_C: 'CommonTraitId' = 164973 + CHILDHOOD_PHASE_PICKY_EATER_D: 'CommonTraitId' = 164974 + CHILDHOOD_PHASE_PICKY_EATER_DISGUSTED_BY_FOOD: 'CommonTraitId' = 165165 + CHILDHOOD_PHASE_PICKY_EATER_E: 'CommonTraitId' = 164975 + CHILDHOOD_PHASE_REBELLIOUS: 'CommonTraitId' = 164765 + CHILDISH: 'CommonTraitId' = 16830 + CHILD_CONFIDENCE_HIGH: 'CommonTraitId' = 314056 + CHILD_CONFIDENCE_LOW: 'CommonTraitId' = 314054 + CHILD_CONFIDENCE_NEUTRAL: 'CommonTraitId' = 314055 + CHILD_OF_THE_ISLANDS: 'CommonTraitId' = 204492 + CHILD_OF_THE_OCEAN: 'CommonTraitId' = 204493 + CHILD_OF_THE_OCEAN_DISGUSTED_BY_FISH: 'CommonTraitId' = 213619 + CHILD_OF_THE_SEA: 'CommonTraitId' = 341881 + CHILD_ROMANTIC_SAGE_HIDDEN: 'CommonTraitId' = 378263 + CHILD_SKILL_REWARD_HEAD_STRONG: 'CommonTraitId' = 308365 + CHILD_SKILL_REWARD_IDEA_PERSON: 'CommonTraitId' = 308367 + CHILD_SKILL_REWARD_PACK_ANIMAL: 'CommonTraitId' = 308366 + CHILD_SKILL_REWARD_PRATICED_HOST: 'CommonTraitId' = 308364 + CHOPSTICK_SAVVY: 'CommonTraitId' = 146104 + CHRONICLER: 'CommonTraitId' = 27692 + CIVIC_POLICY_COMMUNAL_OWNERSHIP: 'CommonTraitId' = 237950 + CIVIC_POLICY_ECO_FRIENDLY_APPLIANCES: 'CommonTraitId' = 232593 + CIVIC_POLICY_GREEN_GARDENING: 'CommonTraitId' = 233572 + CIVIC_POLICY_MODERN_POLICY: 'CommonTraitId' = 234944 + CIVIC_POLICY_REPEAL_STARTED: 'CommonTraitId' = 233502 + CIVIC_POLICY_SKILL_BASED_AGGRESSION: 'CommonTraitId' = 237910 + CIVIC_POLICY_SKILL_BASED_CREATIVE_ARTS: 'CommonTraitId' = 232030 + CIVIC_POLICY_SKILL_BASED_FREE_LOVE: 'CommonTraitId' = 237911 + CIVIC_POLICY_SKILL_BASED_FUN_COMMUNITY: 'CommonTraitId' = 232031 + CIVIC_POLICY_SKILL_BASED_HOME_COOKING: 'CommonTraitId' = 232032 + CIVIC_POLICY_SKILL_BASED_JUICED_COMMUNITY: 'CommonTraitId' = 232033 + CIVIC_POLICY_SKILL_BASED_MUSIC_ARTS: 'CommonTraitId' = 232034 + CIVIC_POLICY_SKILL_BASED_OLD_DAYS: 'CommonTraitId' = 237912 + CIVIC_POLICY_SKILL_BASED_SELF_CARE: 'CommonTraitId' = 232035 + CIVIC_POLICY_SKILL_BASED_SELF_SUFFICIENT: 'CommonTraitId' = 232036 + CIVIC_POLICY_SKILL_BASED_TECHNOLOGICAL_PROGRESS: 'CommonTraitId' = 232028 + CIVIC_POLICY_UPCYCLING_INITIATIVE: 'CommonTraitId' = 226549 + CIVIC_POLICY_UTILITY_PRODUCTION: 'CommonTraitId' = 233573 + CLUB_PRESIDENT: 'CommonTraitId' = 122922 + CLUMSY: 'CommonTraitId' = 16832 + COLD_HEARTED: 'CommonTraitId' = 275418 + COLLECTOR: 'CommonTraitId' = 35719 + COLLEGE_ORGANIZATIONS_ART_SOCIETY_RANK_1: 'CommonTraitId' = 229134 + COLLEGE_ORGANIZATIONS_ART_SOCIETY_RANK_2: 'CommonTraitId' = 223669 + COLLEGE_ORGANIZATIONS_ART_SOCIETY_RANK_3: 'CommonTraitId' = 223663 + COLLEGE_ORGANIZATIONS_DEBATE_RANK_1: 'CommonTraitId' = 229135 + COLLEGE_ORGANIZATIONS_DEBATE_RANK_2: 'CommonTraitId' = 224179 + COLLEGE_ORGANIZATIONS_DEBATE_RANK_3: 'CommonTraitId' = 224180 + COLLEGE_ORGANIZATIONS_HONOR_SOCIETY_RANK_1: 'CommonTraitId' = 229136 + COLLEGE_ORGANIZATIONS_HONOR_SOCIETY_RANK_2: 'CommonTraitId' = 226876 + COLLEGE_ORGANIZATIONS_HONOR_SOCIETY_RANK_3: 'CommonTraitId' = 226877 + COLLEGE_ORGANIZATIONS_ROBOTICS_RANK_1: 'CommonTraitId' = 229137 + COLLEGE_ORGANIZATIONS_ROBOTICS_RANK_2: 'CommonTraitId' = 223079 + COLLEGE_ORGANIZATIONS_ROBOTICS_RANK_3: 'CommonTraitId' = 223080 + COLLEGE_ORGANIZATIONS_SCHOOL_SPIRIT_PARTY_RANK_1: 'CommonTraitId' = 229138 + COLLEGE_ORGANIZATIONS_SCHOOL_SPIRIT_PARTY_RANK_2: 'CommonTraitId' = 225314 + COLLEGE_ORGANIZATIONS_SCHOOL_SPIRIT_PARTY_RANK_3: 'CommonTraitId' = 229139 + COLLEGE_ORGANIZATIONS_SCHOOL_SPIRIT_PRANK_RANK_1: 'CommonTraitId' = 229140 + COLLEGE_ORGANIZATIONS_SCHOOL_SPIRIT_PRANK_RANK_2: 'CommonTraitId' = 224603 + COLLEGE_ORGANIZATIONS_SCHOOL_SPIRIT_PRANK_RANK_3: 'CommonTraitId' = 229141 + COLLEGE_ORGANIZATIONS_SECRET_SOCIETY_FAVOR_HIGH: 'CommonTraitId' = 227496 + COLLEGE_ORGANIZATIONS_SECRET_SOCIETY_FAVOR_LOW: 'CommonTraitId' = 227494 + COLLEGE_ORGANIZATIONS_SECRET_SOCIETY_FAVOR_MED: 'CommonTraitId' = 227495 + COLLEGE_ORGANIZATIONS_SECRET_SOCIETY_JOIN_VISIT_MARKED: 'CommonTraitId' = 228781 + COLLEGE_ORGANIZATIONS_SECRET_SOCIETY_MEMBER: 'CommonTraitId' = 219299 + COMMITMENT_ISSUES: 'CommonTraitId' = 16833 + COMMUNITY_BOARD_ASKED_ABOUT_COMMUNITY: 'CommonTraitId' = 341810 + COMPUTER_GLASSES_WEARING: 'CommonTraitId' = 225007 + COMPUTER_GLASSES_WEARING_BLUE: 'CommonTraitId' = 225161 + COMPUTER_GLASSES_WEARING_GREEN: 'CommonTraitId' = 225162 + COMPUTER_GLASSES_WEARING_ORANGE: 'CommonTraitId' = 225163 + COMPUTER_GLASSES_WEARING_PINK: 'CommonTraitId' = 225160 + COMPUTER_GLASSES_WEARING_RED: 'CommonTraitId' = 225159 + COMPUTER_GLASSES_WEARING_YELLOW: 'CommonTraitId' = 225164 + CONNECTIONS: 'CommonTraitId' = 32431 + CORPORATE_WORKER_CHARISMATIC_CROONER: 'CommonTraitId' = 248982 + CORPORATE_WORKER_LEGENDARY_STAMINA: 'CommonTraitId' = 248983 + COTTAGE_WORLD_NPC_AGATHA_CRUMPLEBOTTOM: 'CommonTraitId' = 260169 + COTTAGE_WORLD_NPC_AGNES_CRUMPLEBOTTOM: 'CommonTraitId' = 259314 + COTTAGE_WORLD_NPC_CRITTER_TENDER: 'CommonTraitId' = 260173 + COTTAGE_WORLD_NPC_GROCERY_DELIVERY: 'CommonTraitId' = 260172 + COTTAGE_WORLD_NPC_GROCERY_OWNER: 'CommonTraitId' = 260171 + COTTAGE_WORLD_NPC_MAYOR: 'CommonTraitId' = 260170 + COTTAGE_WORLD_NPC_PUB_OWNER: 'CommonTraitId' = 260174 + CREATIVE: 'CommonTraitId' = 16850 + CREATIVELY_GIFTED: 'CommonTraitId' = 29619 + CREATIVE_VISIONARY: 'CommonTraitId' = 32423 + CRINGE: 'CommonTraitId' = 341153 + CRYSTAL_HELMET_ALABASTER: 'CommonTraitId' = 193977 + CRYSTAL_HELMET_ALEXANDRITE_EP: 'CommonTraitId' = 193979 + CRYSTAL_HELMET_AMAZONITE_EP: 'CommonTraitId' = 193980 + CRYSTAL_HELMET_AMETHYST: 'CommonTraitId' = 193528 + CRYSTAL_HELMET_CITRINE: 'CommonTraitId' = 193983 + CRYSTAL_HELMET_CRANDESTINE_EP: 'CommonTraitId' = 193984 + CRYSTAL_HELMET_DIAMOND: 'CommonTraitId' = 193985 + CRYSTAL_HELMET_EMERALD: 'CommonTraitId' = 193986 + CRYSTAL_HELMET_FIRE_OPAL: 'CommonTraitId' = 193987 + CRYSTAL_HELMET_HEMATITE: 'CommonTraitId' = 193988 + CRYSTAL_HELMET_JET: 'CommonTraitId' = 193989 + CRYSTAL_HELMET_JONQUILYST: 'CommonTraitId' = 193990 + CRYSTAL_HELMET_NITELITE_EP: 'CommonTraitId' = 193991 + CRYSTAL_HELMET_ORANGE_TOPAZ: 'CommonTraitId' = 193992 + CRYSTAL_HELMET_PEACH: 'CommonTraitId' = 193993 + CRYSTAL_HELMET_PLUMBITE: 'CommonTraitId' = 193994 + CRYSTAL_HELMET_QUARTZ: 'CommonTraitId' = 193995 + CRYSTAL_HELMET_RAINBORZ: 'CommonTraitId' = 193996 + CRYSTAL_HELMET_ROSE: 'CommonTraitId' = 193997 + CRYSTAL_HELMET_RUBY: 'CommonTraitId' = 193998 + CRYSTAL_HELMET_SAPPHIRE: 'CommonTraitId' = 193999 + CRYSTAL_HELMET_SHINALITE: 'CommonTraitId' = 194000 + CRYSTAL_HELMET_SIMANITE: 'CommonTraitId' = 194001 + CRYSTAL_HELMET_TURQUOISE: 'CommonTraitId' = 194002 + CURSES_FOUNTAIN_OF_MAGIC: 'CommonTraitId' = 214645 + CURSES_HEX_OF_DUELIST: 'CommonTraitId' = 214644 + CURSES_INFECTIOUS_LAUGHTER: 'CommonTraitId' = 214650 + CURSES_NIGHT_STALKER: 'CommonTraitId' = 214649 + CURSES_PUNCHABLE_FACE: 'CommonTraitId' = 214646 + CURSES_REPULSIVENESS: 'CommonTraitId' = 214643 + CURSES_SWEATY_STENCH: 'CommonTraitId' = 214647 + CURSES_TOUCHY_FEELY: 'CommonTraitId' = 214648 + CURSES_WILD_MAGIC: 'CommonTraitId' = 213183 + DANCE_MACHINE: 'CommonTraitId' = 126088 + DASTARDLY: 'CommonTraitId' = 27084 + DAUNTLESS: 'CommonTraitId' = 283147 + DETECTIVE_CAREER_CRIMINAL: 'CommonTraitId' = 113564 + DETECTIVE_CAREER_POLICE_STATION_CRIMINAL_NPC: 'CommonTraitId' = 116487 + DIAPER_PREFERENCE_BABY_CLOTH: 'CommonTraitId' = 306617 + DISCIPLINED_OUT_CAT_JUMP_ON_COUNTERS: 'CommonTraitId' = 170710 + DISCIPLINED_OUT_CAT_SCRATCHING: 'CommonTraitId' = 167067 + DISCIPLINED_OUT_DOG_BARK: 'CommonTraitId' = 167071 + DISCIPLINED_OUT_DOG_EAT_POOP: 'CommonTraitId' = 168486 + DISCIPLINED_OUT_DOG_JUMP_ON_COUNTERS: 'CommonTraitId' = 170709 + DISCIPLINED_OUT_DOG_PUDDLES_PLAY: 'CommonTraitId' = 167069 + DISCIPLINED_OUT_DOG_TOILET: 'CommonTraitId' = 167068 + DISCIPLINED_OUT_PET_ATTACK: 'CommonTraitId' = 167058 + DISCIPLINED_OUT_PET_BEG_EATING: 'CommonTraitId' = 167059 + DISCIPLINED_OUT_PET_EAT_PEOPLE_FOOD: 'CommonTraitId' = 170712 + DISCIPLINED_OUT_PET_POTTY_TRAINING: 'CommonTraitId' = 167072 + DISCIPLINED_OUT_PET_PUDDLES_DRINK: 'CommonTraitId' = 167061 + DISCIPLINED_OUT_PET_TRASH_EAT: 'CommonTraitId' = 167062 + DISCIPLINED_OUT_PET_TRASH_PLAY: 'CommonTraitId' = 167063 + DISCIPLINED_OUT_PET_WAKE_UP_SIMS: 'CommonTraitId' = 170711 + DISCIPLINE_PET_POTTY_TRAINING: 'CommonTraitId' = 162247 + DISGUSTED_BY_FOOD: 'CommonTraitId' = 149446 + DISGUSTED_BY_FOOD_ANIMATION: 'CommonTraitId' = 248309 + DOCTOR_SICKNESS_RESISTANT: 'CommonTraitId' = 114410 + DOG_LOVER: 'CommonTraitId' = 157979 + DOG_QUIRK_BARKER_LOUD: 'CommonTraitId' = 148643 + DOG_QUIRK_BARKER_NEUTRAL: 'CommonTraitId' = 148645 + DOG_QUIRK_BARKER_QUIET: 'CommonTraitId' = 148644 + ECO_ENGINEER: 'CommonTraitId' = 234566 + ECO_MASTER: 'CommonTraitId' = 234887 + EDUCATION_TEACH_10: 'CommonTraitId' = 220312 + EDUCATION_TEACH_7: 'CommonTraitId' = 220305 + EDUCATION_TEACH_8: 'CommonTraitId' = 220310 + EDUCATION_TEACH_9: 'CommonTraitId' = 220311 + ELDER: 'CommonTraitId' = 34320 + ENTREPRENEUR: 'CommonTraitId' = 234889 + ENTREPRENEURIAL: 'CommonTraitId' = 32444 + ENTREPRENEUR_THE_KNOWLEDGE: 'CommonTraitId' = 277990 + EP14_WORLD_HAS_WON_HORSE_COMPETITION_HIDDEN: 'CommonTraitId' = 338664 + EP14_WORLD_LOCAL_HIDDEN: 'CommonTraitId' = 340041 + EP14_WORLD_NPC_HAS_ASKED_ABOUT_LIFE_NECTAR_HIDDEN: 'CommonTraitId' = 322422 + EP14_WORLD_NPC_HORSE_TRAINER_GOODBYE_HIDDEN: 'CommonTraitId' = 350340 + EP14_WORLD_NPC_HORSE_TRAINER_HELLO_HIDDEN: 'CommonTraitId' = 350339 + EP14_WORLD_NPC_HORSE_TRAINER_HIDDEN: 'CommonTraitId' = 321628 + EP14_WORLD_NPC_MYSTERIOUS_RANCHER_HIDDEN: 'CommonTraitId' = 321627 + EP15_LOCAL_HIDDEN: 'CommonTraitId' = 343326 + EP15_NPC_ALON_SADYA_HIDDEN: 'CommonTraitId' = 343822 + EP15_NPC_ARTURO_LINH_HIDDEN: 'CommonTraitId' = 343820 + EP15_NPC_BUA_BUN_MA_HIDDEN: 'CommonTraitId' = 343816 + EP15_NPC_CHANH_LINH_HIDDEN: 'CommonTraitId' = 343819 + EP15_NPC_KASEM_BUN_MA_HIDDEN: 'CommonTraitId' = 343818 + EP15_NPC_LIEN_SADYA_HIDDEN: 'CommonTraitId' = 343821 + EP15_NPC_NIN_BUN_MA_HIDDEN: 'CommonTraitId' = 343817 + EP15_NPC_THI_LINH_HIDDEN: 'CommonTraitId' = 343823 + EP15_NPC_VANESHA_CAHYAPUTRI_HIDDEN: 'CommonTraitId' = 343824 + EP15_NPC_ZHAFIRA_CAHYAPUTRI_HIDDEN: 'CommonTraitId' = 343825 + EP16_WORLD_WALL_OF_LOVE_WROTE_ON_WALL_HIDDEN: 'CommonTraitId' = 369483 + EPIC_POET: 'CommonTraitId' = 30922 + ESSENCE_OF_FLAVOR: 'CommonTraitId' = 26197 + ETERNAL_BOND: 'CommonTraitId' = 26201 + EVICTION_SYSTEM_USED_FREE_CHANCE_HIDDEN: 'CommonTraitId' = 351533 + EVIL: 'CommonTraitId' = 16836 + EVIL_BEGONIA_SCENT: 'CommonTraitId' = 188801 + EXCURSION_MOUNTAINEER_RANK_1: 'CommonTraitId' = 249427 + EXCURSION_MOUNTAINEER_RANK_2: 'CommonTraitId' = 249430 + EXCURSION_MOUNTAINEER_RANK_3: 'CommonTraitId' = 249429 + EXPRESSIONISTIC: 'CommonTraitId' = 75815 + E_SPORTS: 'CommonTraitId' = 226661 + E_SPORTS_OFFERED: 'CommonTraitId' = 227952 + E_SPORTS_ONE_MATCHES_WON: 'CommonTraitId' = 227110 + E_SPORTS_TWO_MATCHES_WON: 'CommonTraitId' = 227111 + FAKE_GENIUS: 'CommonTraitId' = 106999 + FAME_LEVEL1: 'CommonTraitId' = 191807 + FAME_LEVEL2: 'CommonTraitId' = 191819 + FAME_LEVEL3: 'CommonTraitId' = 191820 + FAME_LEVEL4: 'CommonTraitId' = 191817 + FAME_LEVEL5: 'CommonTraitId' = 191818 + FAME_TRAITS_CELEBRITY_WALK_ON: 'CommonTraitId' = 204539 + FAME_TRAITS_SHINE_OFF: 'CommonTraitId' = 199156 + FAME_TRAITS_SHINE_ON_RANK4: 'CommonTraitId' = 199155 + FAME_TRAITS_SHINE_ON_RANK5: 'CommonTraitId' = 199223 + FAMILY_ORIENTED: 'CommonTraitId' = 16838 + FAMILY_SIM: 'CommonTraitId' = 27083 + FASHION_MARKETPLACE_SOLD_HYPE_OUTFIT: 'CommonTraitId' = 287494 + FASHION_MARKETPLACE_WEARING_OUTFIT: 'CommonTraitId' = 286922 + FAST_FASTIDIOUS: 'CommonTraitId' = 256786 + FEAR_BEING_ALONE: 'CommonTraitId' = 364229 + FEAR_BEING_CHEATED_ON: 'CommonTraitId' = 277086 + FEAR_BEING_JUDGED: 'CommonTraitId' = 277087 + FEAR_COW_PLANT: 'CommonTraitId' = 277088 + FEAR_CROWDED_PLACES: 'CommonTraitId' = 277089 + FEAR_DARK: 'CommonTraitId' = 277094 + FEAR_DEAD_END_JOB: 'CommonTraitId' = 277090 + FEAR_DEATH: 'CommonTraitId' = 277091 + FEAR_DEATH_GHOST_URBAN_MYTH_EP12: 'CommonTraitId' = 285880 + FEAR_DISAPPOINTING_PARENTS: 'CommonTraitId' = 277098 + FEAR_DISAPPOINTING_PARENTS_PARENT_DECEASED_FLAG: 'CommonTraitId' = 304222 + FEAR_EVICTION: 'CommonTraitId' = 342289 + FEAR_FAILING_AFTER_SCHOOL_ACTIVITIES: 'CommonTraitId' = 277095 + FEAR_FAILING_CLASS: 'CommonTraitId' = 277096 + FEAR_FAILING_TESTS: 'CommonTraitId' = 277097 + FEAR_FAILURE: 'CommonTraitId' = 277080 + FEAR_FIRE: 'CommonTraitId' = 277081 + FEAR_GHOSTS: 'CommonTraitId' = 277082 + FEAR_HOMEWORK: 'CommonTraitId' = 277099 + FEAR_HORSES: 'CommonTraitId' = 323758 + FEAR_HORSES_PROGRESS: 'CommonTraitId' = 324580 + FEAR_INFERIOR: 'CommonTraitId' = 307957 + FEAR_INTIMACY: 'CommonTraitId' = 362851 + FEAR_SWIMMING: 'CommonTraitId' = 277083 + FEAR_UNFULFILLED: 'CommonTraitId' = 277084 + FEED_PREFERENCE_BABY_BODY: 'CommonTraitId' = 305140 + FEED_PREFERENCE_BABY_BOTTLE: 'CommonTraitId' = 305139 + FERTILE: 'CommonTraitId' = 26498 + FILTH_DWELLER: 'CommonTraitId' = 256785 + FIZZY_HEAD: 'CommonTraitId' = 236949 + FLOWER_BUNNY: 'CommonTraitId' = 186785 + FOODIE: 'CommonTraitId' = 27176 + FOOD_PREFERENCE_INFANT_APPLESAUCE: 'CommonTraitId' = 289167 + FOOD_PREFERENCE_INFANT_BANANA_SLICES: 'CommonTraitId' = 289275 + FOOD_PREFERENCE_INFANT_CRUSHED_CARROTS: 'CommonTraitId' = 289182 + FOOD_PREFERENCE_INFANT_HOMEMADE_HUMMUS: 'CommonTraitId' = 289183 + FOOD_PREFERENCE_INFANT_ICE_CREAM: 'CommonTraitId' = 289192 + FOOD_PREFERENCE_INFANT_MASHED_MANGO: 'CommonTraitId' = 289193 + FOOD_PREFERENCE_INFANT_MASHED_PEAS: 'CommonTraitId' = 289194 + FOOD_PREFERENCE_INFANT_OATMEAL_CEREAL: 'CommonTraitId' = 289184 + FOOD_PREFERENCE_INFANT_OAT_YOS: 'CommonTraitId' = 289277 + FOOD_PREFERENCE_INFANT_PAPAYA_PASTE: 'CommonTraitId' = 289185 + FOOD_PREFERENCE_INFANT_PEANUT_BUTTER_PUFFS: 'CommonTraitId' = 289278 + FOOD_PREFERENCE_INFANT_PUMPKIN_PUREE: 'CommonTraitId' = 289186 + FOOD_PREFERENCE_INFANT_RICE_PORRIDGE: 'CommonTraitId' = 289187 + FOOD_PREFERENCE_INFANT_SMASHED_AVOCADO: 'CommonTraitId' = 289188 + FOOD_PREFERENCE_INFANT_SMASHED_LEMON: 'CommonTraitId' = 289189 + FOOD_PREFERENCE_INFANT_SWEET_POTATO_PUREE: 'CommonTraitId' = 289190 + FOOD_PREFERENCE_INFANT_YOGURT: 'CommonTraitId' = 289191 + FOOD_PREFERENCE_INFANT_YOGURT_MELTS: 'CommonTraitId' = 289276 + FOREST_GHOST: 'CommonTraitId' = 108313 + FOREST_GHOST_GLOOMY: 'CommonTraitId' = 108315 + FOREST_GHOST_GOOFY: 'CommonTraitId' = 108316 + FOREST_GHOST_MEAN: 'CommonTraitId' = 108317 + FOREVER_FRESH: 'CommonTraitId' = 183037 + FOREVER_FULL: 'CommonTraitId' = 183035 + FOX_ADULT: 'CommonTraitId' = 267313 + FOX_ELDER: 'CommonTraitId' = 267314 + FREEGAN: 'CommonTraitId' = 234414 + FREE_SERVICES: 'CommonTraitId' = 32110 + FRESH_CHEF: 'CommonTraitId' = 26199 + FRIENDSHIP_BRACELET_1_HIDDEN: 'CommonTraitId' = 320053 + FRIENDSHIP_BRACELET_2_HIDDEN: 'CommonTraitId' = 320054 + FRIENDSHIP_BRACELET_3_HIDDEN: 'CommonTraitId' = 320055 + FRIENDSHIP_BRACELET_4_HIDDEN: 'CommonTraitId' = 320052 + FRIENDSHIP_BRACELET_5_HIDDEN: 'CommonTraitId' = 319942 + FRIENDSHIP_BRACELET_NEEDS_CLEANUP_HIDDEN: 'CommonTraitId' = 329148 + FRIEND_OF_THE_SEA: 'CommonTraitId' = 206419 + FRUGAL: 'CommonTraitId' = 32111 + FTUE_CAREER_MINDED_INITIAL: 'CommonTraitId' = 200838 + FTUE_OVER_ACHIEVER: 'CommonTraitId' = 197728 + GAMEPLAY_MOUNTED_BUFFS: 'CommonTraitId' = 335365 + GEEK: 'CommonTraitId' = 16841 + GENDER_FEMALE: 'CommonTraitId' = 102448 + GENDER_MALE: 'CommonTraitId' = 102447 + GENDER_OPTIONS_ATTRACTED_TO_FEMALE: 'CommonTraitId' = 276492 + GENDER_OPTIONS_ATTRACTED_TO_MALE: 'CommonTraitId' = 276493 + GENDER_OPTIONS_ATTRACTED_TO_NOT_FEMALE: 'CommonTraitId' = 276494 + GENDER_OPTIONS_ATTRACTED_TO_NOT_MALE: 'CommonTraitId' = 276495 + GENDER_OPTIONS_CLOTHING_MENS_WEAR: 'CommonTraitId' = 136879 + GENDER_OPTIONS_CLOTHING_WOMENS_WEAR: 'CommonTraitId' = 136880 + GENDER_OPTIONS_FRAME_FEMININE: 'CommonTraitId' = 136878 + GENDER_OPTIONS_FRAME_MASCULINE: 'CommonTraitId' = 136877 + GENDER_OPTIONS_LACTATION_CANNOT_LACTATE: 'CommonTraitId' = 275052 + GENDER_OPTIONS_LACTATION_CAN_LACTATE: 'CommonTraitId' = 274985 + GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED: 'CommonTraitId' = 136875 + GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE: 'CommonTraitId' = 136874 + GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED: 'CommonTraitId' = 137716 + GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE: 'CommonTraitId' = 137717 + GENDER_OPTIONS_SEXUALITY_EXPLORING: 'CommonTraitId' = 276496 + GENDER_OPTIONS_SEXUALITY_NOT_EXPLORING: 'CommonTraitId' = 276497 + GENDER_OPTIONS_TOILET_SITTING: 'CommonTraitId' = 137718 + GENDER_OPTIONS_TOILET_STANDING: 'CommonTraitId' = 136876 + GENEROUS: 'CommonTraitId' = 341152 + GENIUS: 'CommonTraitId' = 27917 + GHOST_ANGER: 'CommonTraitId' = 101679 + GHOST_ANIMAL_OBJECTS_KILLER_CHICKEN: 'CommonTraitId' = 267992 + GHOST_ANIMAL_OBJECTS_KILLER_RABBIT: 'CommonTraitId' = 258168 + GHOST_BEETLE: 'CommonTraitId' = 235995 + GHOST_BROKEN_HEART: 'CommonTraitId' = 379066 + GHOST_CAULDRON_POTION_IMMORTALITY_FAILURE: 'CommonTraitId' = 214409 + GHOST_CLIMBING_ROUTE: 'CommonTraitId' = 250224 + GHOST_COW_PLANT: 'CommonTraitId' = 101704 + GHOST_CURSES_NIGHT_STALKER_STALKER: 'CommonTraitId' = 216314 + GHOST_DEATH_FLOWER: 'CommonTraitId' = 190748 + GHOST_DROWN: 'CommonTraitId' = 103599 + GHOST_ELDER_EXHAUSTION: 'CommonTraitId' = 101680 + GHOST_ELECTROCUTION: 'CommonTraitId' = 101681 + GHOST_EMBARRASSMENT: 'CommonTraitId' = 101682 + GHOST_FIRE: 'CommonTraitId' = 101676 + GHOST_FLIES: 'CommonTraitId' = 234848 + GHOST_FROZEN: 'CommonTraitId' = 182185 + GHOST_HUNGER: 'CommonTraitId' = 101683 + GHOST_LAUGHTER: 'CommonTraitId' = 101684 + GHOST_LIGHTNING: 'CommonTraitId' = 186331 + GHOST_METEORITE: 'CommonTraitId' = 294292 + GHOST_MOLD_SYSTEM: 'CommonTraitId' = 343869 + GHOST_MOTHER_PLANT: 'CommonTraitId' = 204157 + GHOST_MURPHY_BED: 'CommonTraitId' = 228335 + GHOST_OLD_AGE: 'CommonTraitId' = 101685 + GHOST_OVERHEAT: 'CommonTraitId' = 184951 + GHOST_POISON: 'CommonTraitId' = 176264 + GHOST_PUFFER_FISH: 'CommonTraitId' = 137461 + GHOST_RISEN: 'CommonTraitId' = 103032 + GHOST_RODENT_DISEASE: 'CommonTraitId' = 181918 + GHOST_SEANCE_TABLE: 'CommonTraitId' = 255360 + GHOST_STEAM: 'CommonTraitId' = 119951 + GHOST_STINK_BOMB: 'CommonTraitId' = 284364 + GHOST_URBAN_MYTH: 'CommonTraitId' = 284363 + GHOST_URBAN_MYTH_EP12: 'CommonTraitId' = 285905 + GHOST_VAMPIRE_SUN: 'CommonTraitId' = 151547 + GHOST_VENDING_MACHINE: 'CommonTraitId' = 249747 + GHOST_WITCH_OVERLOAD: 'CommonTraitId' = 216974 + GLOOMY: 'CommonTraitId' = 9332 + GLUTTON: 'CommonTraitId' = 16843 + GOOD: 'CommonTraitId' = 27915 + GOOFBALL: 'CommonTraitId' = 9337 + GRADE_SCHOOL_A: 'CommonTraitId' = 98698 + GRADE_SCHOOL_B: 'CommonTraitId' = 98699 + GRADE_SCHOOL_C: 'CommonTraitId' = 98700 + GRADE_SCHOOL_D: 'CommonTraitId' = 98701 + GRADE_SCHOOL_F: 'CommonTraitId' = 98702 + GREAT_KISSER: 'CommonTraitId' = 26686 + GREAT_STORYTELLER: 'CommonTraitId' = 103263 + GREEN_FIEND: 'CommonTraitId' = 231699 + GREGARIOUS: 'CommonTraitId' = 27087 + GYM_RAT: 'CommonTraitId' = 26427 + HANDEDNESS_LEFT: 'CommonTraitId' = 113589 + HANDEDNESS_RIGHT: 'CommonTraitId' = 113588 + HANDY_PERSON_GOLDEN_WRENCH: 'CommonTraitId' = 354602 + HAPPY_TODDLER: 'CommonTraitId' = 143145 + HARDLY_HUNGRY: 'CommonTraitId' = 26389 + HAS_MET_NANNY: 'CommonTraitId' = 143765 + HAS_MET_RANCH_HAND: 'CommonTraitId' = 339307 + HAS_VISITED_DEEP_WOODS: 'CommonTraitId' = 132285 + HAS_VISITED_FORGOTTEN_GROTTO: 'CommonTraitId' = 119496 + HAS_VISITED_SYLVAN_GLADE: 'CommonTraitId' = 119401 + HATES_CHILDREN: 'CommonTraitId' = 16844 + HATES_MAYO: 'CommonTraitId' = 267875 + HAUNTED_HOUSE_TEMPERANCE: 'CommonTraitId' = 256353 + HEART_TO_HEART: 'CommonTraitId' = 368493 + HEROIC_PRESENCE: 'CommonTraitId' = 238654 + HERO_OF_STRANGER_VILLE: 'CommonTraitId' = 204044 + HIDDEN_ACTOR_CAREER_AGENCY_AI_STAFFING: 'CommonTraitId' = 193399 + HIDDEN_ACTOR_CAREER_AGENCY_EVERYDAY_EXTRAS: 'CommonTraitId' = 193398 + HIDDEN_ACTOR_CAREER_AGENCY_GRAN: 'CommonTraitId' = 193401 + HIDDEN_ACTOR_CAREER_AGENCY_WELL_SUITED: 'CommonTraitId' = 193400 + HIDDEN_BASKETBALL_DREAM_BIG: 'CommonTraitId' = 145874 + HIDDEN_BEEN_KISSED: 'CommonTraitId' = 101390 + HIDDEN_BOWLED_PERFECT_LLAMA: 'CommonTraitId' = 162471 + HIDDEN_CAMPING: 'CommonTraitId' = 102265 + HIDDEN_CAREER_ACTIVIST_CAUSE_ECONOMY: 'CommonTraitId' = 135285 + HIDDEN_CAREER_ACTIVIST_CAUSE_ENVIRONMENT: 'CommonTraitId' = 135277 + HIDDEN_CAREER_ACTIVIST_CAUSE_JUSTICE: 'CommonTraitId' = 135288 + HIDDEN_CAREER_ACTIVIST_CAUSE_PEACE: 'CommonTraitId' = 135287 + HIDDEN_CAREER_ACTIVIST_CAUSE_TAX: 'CommonTraitId' = 135284 + HIDDEN_CAREER_ACTIVIST_HAS_CAUSE: 'CommonTraitId' = 136437 + HIDDEN_CAREER_ACTIVIST_POLITICAL_POSITION_LEFT: 'CommonTraitId' = 136608 + HIDDEN_CAREER_ACTIVIST_POLITICAL_POSITION_RIGHT: 'CommonTraitId' = 136609 + HIDDEN_CAREER_CRITIC_THRIFTY: 'CommonTraitId' = 139623 + HIDDEN_CAREER_CUSTOM: 'CommonTraitId' = 192698 + HIDDEN_CAREER_PAY_BOOSTS_2X: 'CommonTraitId' = 196731 + HIDDEN_CHALLENGE_POSITIVITY_COLLECTED_REWARD_1: 'CommonTraitId' = 198899 + HIDDEN_CHALLENGE_POSITIVITY_COLLECTED_REWARD_2: 'CommonTraitId' = 198900 + HIDDEN_CHALLENGE_POSITIVITY_COLLECTED_REWARD_3: 'CommonTraitId' = 198901 + HIDDEN_CHALLENGE_POSITIVITY_COLLECTED_REWARD_4: 'CommonTraitId' = 198902 + HIDDEN_CHILD_CANNOT_AGE_UP_DOES_NOT_PERSIST: 'CommonTraitId' = 116617 + HIDDEN_CLIMATE_CHANGE_WOKE: 'CommonTraitId' = 179869 + HIDDEN_DRAMA_CLUB: 'CommonTraitId' = 199635 + HIDDEN_DRAMA_CLUB_CRY_ON_DEMAND: 'CommonTraitId' = 201079 + HIDDEN_EAR_BUDS_MUSIC_LOVER_HAS_BEEN_GIVEN: 'CommonTraitId' = 166558 + HIDDEN_EMPLOYEE_QUIT: 'CommonTraitId' = 174483 + HIDDEN_EVENT_FALL_CHALLENGE_DO_TD_RECEIVED_SKULL_DISPLAY: 'CommonTraitId' = 153497 + HIDDEN_FAME_CELEBRITY_TILE_ACHIEVED: 'CommonTraitId' = 197536 + HIDDEN_FAME_QUIRK_STAR_TREATMENT: 'CommonTraitId' = 196358 + HIDDEN_FAVORITE_MOVIE_ACTION: 'CommonTraitId' = 128970 + HIDDEN_FAVORITE_MOVIE_COMEDY: 'CommonTraitId' = 128972 + HIDDEN_FAVORITE_MOVIE_FAMILY: 'CommonTraitId' = 128974 + HIDDEN_FAVORITE_MOVIE_HORROR: 'CommonTraitId' = 128971 + HIDDEN_FAVORITE_MOVIE_ROMANCE: 'CommonTraitId' = 128973 + HIDDEN_FIRST_SNOW: 'CommonTraitId' = 183661 + HIDDEN_FOOD_FESTIVAL_CURRY_CONTEST_WINNER: 'CommonTraitId' = 146178 + HIDDEN_HAD_FIGHT: 'CommonTraitId' = 101391 + HIDDEN_HAD_WOOHOO: 'CommonTraitId' = 101389 + HIDDEN_HAS_BEEN_SCIENTIST: 'CommonTraitId' = 131641 + HIDDEN_HAS_MONSTER_FRIEND: 'CommonTraitId' = 139186 + HIDDEN_HAS_RESEARCHED_RODENT_DISEASE: 'CommonTraitId' = 182224 + HIDDEN_HAS_TASTED_EXPERIMENTAL_FOOD: 'CommonTraitId' = 134072 + HIDDEN_HAS_ULTIMATE_SNOW_PAL: 'CommonTraitId' = 185954 + HIDDEN_HATES_FRUITCAKE: 'CommonTraitId' = 119187 + HIDDEN_HATES_FRUIT_CAKE_CONTROLLER: 'CommonTraitId' = 124839 + HIDDEN_IS_ADOPTION_OFFICER: 'CommonTraitId' = 175924 + HIDDEN_IS_DISGUISED: 'CommonTraitId' = 200510 + HIDDEN_IS_EVENT_NPC_CHALLENGE: 'CommonTraitId' = 133798 + HIDDEN_IS_EVENT_NPC_CHALLENGE_MBB: 'CommonTraitId' = 204280 + HIDDEN_IS_NATIVE: 'CommonTraitId' = 180954 + HIDDEN_IS_NATIVE_STRAY: 'CommonTraitId' = 181434 + HIDDEN_IS_NOT_DISGUISED: 'CommonTraitId' = 200511 + HIDDEN_JOINED_FIFTY_MILE_HIGH_CLUB: 'CommonTraitId' = 8612 + HIDDEN_JOINED_FIFTY_MILE_HIGH_CLUB_TEEN: 'CommonTraitId' = 100786 + HIDDEN_JUNGLE_WELCOME_PACKAGE_RECEIVED: 'CommonTraitId' = 183129 + HIDDEN_LANDLORD: 'CommonTraitId' = 133800 + HIDDEN_LIGHTHOUSE_CONCEPTION: 'CommonTraitId' = 172412 + HIDDEN_LIKES_FRUITCAKE: 'CommonTraitId' = 119186 + HIDDEN_NPC_IS_DJ: 'CommonTraitId' = 122820 + HIDDEN_PAINTING_MASTER: 'CommonTraitId' = 27014 + HIDDEN_PET_MINOR_CAGE_RODENT_DISEASE_IMMUNE: 'CommonTraitId' = 183401 + HIDDEN_PET_MINOR_CAGE_RODENT_DISEASE_REMOVED_COSTUME: 'CommonTraitId' = 185712 + HIDDEN_RECEIVED_EXPERIMENTAL_FOOD_TNS: 'CommonTraitId' = 143126 + HIDDEN_RESTAURANT_AT_WORK: 'CommonTraitId' = 144761 + HIDDEN_ROCKET_SHIP_HAS_WATCHED_ALIEN: 'CommonTraitId' = 103205 + HIDDEN_ROLE_STATE_VET_EMPLOYEE_CLEAN: 'CommonTraitId' = 178713 + HIDDEN_ROLE_STATE_VET_EMPLOYEE_DONT_CLEAN: 'CommonTraitId' = 178714 + HIDDEN_ROLE_STATE_VET_EMPLOYEE_DONT_TREAT: 'CommonTraitId' = 178716 + HIDDEN_ROLE_STATE_VET_EMPLOYEE_TREAT: 'CommonTraitId' = 178715 + HIDDEN_SKELETON: 'CommonTraitId' = 175972 + HIDDEN_SKELETON_SERVICE_SKELETON: 'CommonTraitId' = 177810 + HIDDEN_SKELETON_TEMPLE_SKELETON: 'CommonTraitId' = 178437 + HIDDEN_SPRING_CHALLENGE2016_GOT_GROW_FRUIT_STARTER: 'CommonTraitId' = 137247 + HIDDEN_SPRING_CHALLENGE_2016_GAVE_PRISTINE_GROW_FRUIT: 'CommonTraitId' = 135593 + HIDDEN_SPRING_CHALLENGE_2016_GAVE_X_GROW_FRUIT_COMPLETED: 'CommonTraitId' = 135551 + HIDDEN_SUPER_FERTILIZER_UNLOCK: 'CommonTraitId' = 109815 + HIDDEN_TEMPERATURE_PREFERENCE_COOL: 'CommonTraitId' = 179141 + HIDDEN_TEMPERATURE_PREFERENCE_WARM: 'CommonTraitId' = 179142 + HIDDEN_TREAD_MILL_CLIMBING_WALL_CHALLENGE_COMPLETE_1: 'CommonTraitId' = 167758 + HIDDEN_TREAD_MILL_CLIMBING_WALL_CHALLENGE_COMPLETE_2: 'CommonTraitId' = 167759 + HIDDEN_TREAD_MILL_CLIMBING_WALL_CHALLENGE_COMPLETE_3: 'CommonTraitId' = 167760 + HIDDEN_TREAD_MILL_CLIMBING_WALL_CHALLENGE_COMPLETE_4: 'CommonTraitId' = 167761 + HIDDEN_TREAD_MILL_CLIMBING_WALL_CHALLENGE_COMPLETE_5: 'CommonTraitId' = 167762 + HIDDEN_UNLOCKED_GRILLED_CHEESE_ASPIRATION: 'CommonTraitId' = 132500 + HIDDEN_UNLOCKED_POSITIVITY_CHALLENGE_ASPIRATION: 'CommonTraitId' = 198781 + HIDDEN_UNLOCK_CAMPING_SCULPTURE: 'CommonTraitId' = 108125 + HIDDEN_VAMPIRE_POWER_SUSCEPTIBILITY: 'CommonTraitId' = 151836 + HIDDEN_VAMPIRE_SPIRIT_POWERS_BAT_ENABLED: 'CommonTraitId' = 155860 + HIDDEN_VAMPIRE_SPIRIT_POWERS_MIST_ENABLED: 'CommonTraitId' = 155861 + HIDDEN_VAMPIRE_SPIRIT_POWERS_VAMPIRE_RUN_ENABLED: 'CommonTraitId' = 155862 + HIDDEN_VFX_MASK_CURSED: 'CommonTraitId' = 181193 + HIDDEN_WEATHER_RAIN_HATE: 'CommonTraitId' = 179138 + HIDDEN_WEATHER_RAIN_LOVE: 'CommonTraitId' = 179137 + HIDDEN_WEATHER_SNOW_HATE: 'CommonTraitId' = 179140 + HIDDEN_WEATHER_SNOW_LOVE: 'CommonTraitId' = 179139 + HIDDEN_WEATHER_SUN_HATE: 'CommonTraitId' = 179134 + HIDDEN_WEATHER_SUN_LOVE: 'CommonTraitId' = 179133 + HIDDEN_WEATHER_WIND_HATE: 'CommonTraitId' = 179136 + HIDDEN_WEATHER_WIND_LOVE: 'CommonTraitId' = 179135 + HIGH_FLIER: 'CommonTraitId' = 283144 + HIGH_MAINTENANCE: 'CommonTraitId' = 272336 + HIGH_METABOLISM: 'CommonTraitId' = 27080 + HIGH_SCHOOL_A: 'CommonTraitId' = 98707 + HIGH_SCHOOL_ACTIVE_HAD_ORIENTATION: 'CommonTraitId' = 276765 + HIGH_SCHOOL_ACTIVE_LEARNED_TPOSE_CHALLENGE: 'CommonTraitId' = 300531 + HIGH_SCHOOL_B: 'CommonTraitId' = 98706 + HIGH_SCHOOL_C: 'CommonTraitId' = 98705 + HIGH_SCHOOL_D: 'CommonTraitId' = 98704 + HIGH_SCHOOL_EXIT_DROPOUT: 'CommonTraitId' = 277741 + HIGH_SCHOOL_EXIT_EARNED_GED: 'CommonTraitId' = 291086 + HIGH_SCHOOL_EXIT_EXPELLED: 'CommonTraitId' = 277742 + HIGH_SCHOOL_EXIT_GRADUATE_EARLY: 'CommonTraitId' = 277740 + HIGH_SCHOOL_EXIT_GRADUATE_HONORS: 'CommonTraitId' = 277738 + HIGH_SCHOOL_EXIT_GRADUATE_VALEDICTORIAN: 'CommonTraitId' = 277739 + HIGH_SCHOOL_F: 'CommonTraitId' = 98703 + HIGH_SCHOOL_NPC_ASH_HARJO: 'CommonTraitId' = 301315 + HIGH_SCHOOL_NPC_CAFETERIA_WORKER: 'CommonTraitId' = 300519 + HIGH_SCHOOL_NPC_JANITOR: 'CommonTraitId' = 300488 + HIGH_SCHOOL_NPC_PRINCIPLE: 'CommonTraitId' = 300487 + HIGH_SCHOOL_NPC_TEACHER_1: 'CommonTraitId' = 300380 + HIGH_SCHOOL_NPC_TEACHER_2: 'CommonTraitId' = 300382 + HIGH_SCHOOL_NPC_THRIFT_STORE_OWNER: 'CommonTraitId' = 300384 + HIGH_SCHOO_ACTIVE_CLASS_1_STUDENT: 'CommonTraitId' = 293779 + HIGH_SKILL_FISHING: 'CommonTraitId' = 215146 + HILARIOUS: 'CommonTraitId' = 27170 + HOLIDAY_TRADITION_FATHER_WINTER: 'CommonTraitId' = 183343 + HOLIDAY_TRADITION_FATHER_WINTER_BABY: 'CommonTraitId' = 183361 + HOME_TURF: 'CommonTraitId' = 144199 + HORSE_AGE_ADULT: 'CommonTraitId' = 321082 + HORSE_AGE_CHILD: 'CommonTraitId' = 321081 + HORSE_AGE_ELDER: 'CommonTraitId' = 321083 + HORSE_COMPETITION_BARREL_RACING_BEGINNER_COMPLETE_HIDDEN: 'CommonTraitId' = 349913 + HORSE_COMPETITION_BARREL_RACING_EXPERT_COMPLETE_HIDDEN: 'CommonTraitId' = 349916 + HORSE_COMPETITION_BARREL_RACING_INTERMEDIATE_COMPLETE_HIDDEN: 'CommonTraitId' = 349919 + HORSE_COMPETITION_BARREL_RACING_MASTER_COMPLETE_HIDDEN: 'CommonTraitId' = 350467 + HORSE_COMPETITION_ENDURACE_RACING_BEGINNER_COMPLETE_HIDDEN: 'CommonTraitId' = 349922 + HORSE_COMPETITION_ENDURACE_RACING_EXPERT_COMPLETE_HIDDEN: 'CommonTraitId' = 349923 + HORSE_COMPETITION_ENDURACE_RACING_INTERMEDIATE_COMPLETE_HIDDEN: 'CommonTraitId' = 349924 + HORSE_COMPETITION_ENDURACE_RACING_MASTER_COMPLETE_HIDDEN: 'CommonTraitId' = 350468 + HORSE_COMPETITION_SHOW_JUMPING_BEGINNER_COMPLETE_HIDDEN: 'CommonTraitId' = 349926 + HORSE_COMPETITION_SHOW_JUMPING_EXPERT_COMPLETE_HIDDEN: 'CommonTraitId' = 349927 + HORSE_COMPETITION_SHOW_JUMPING_INTERMEDIATE_COMPLETE_HIDDEN: 'CommonTraitId' = 349928 + HORSE_COMPETITION_SHOW_JUMPING_MASTER_COMPLETE_HIDDEN: 'CommonTraitId' = 350469 + HORSE_COMPETITION_WESTERN_PLEASURE_BEGINNER_COMPLETE_HIDDEN: 'CommonTraitId' = 349931 + HORSE_COMPETITION_WESTERN_PLEASURE_EXPERT_COMPLETE_HIDDEN: 'CommonTraitId' = 349932 + HORSE_COMPETITION_WESTERN_PLEASURE_INTERMEDIATE_COMPLETE_HIDDEN: 'CommonTraitId' = 349933 + HORSE_COMPETITION_WESTERN_PLEASURE_MASTER_COMPLETE_HIDDEN: 'CommonTraitId' = 350470 + HORSE_GAMEPLAY_CURIOUS: 'CommonTraitId' = 323854 + HORSE_GAMEPLAY_EQUESTRIAN_CENTER_CHAMPION_HORSE: 'CommonTraitId' = 331651 + HORSE_GAMEPLAY_HORSE_BREEDING_CHAMPION_GENES: 'CommonTraitId' = 323125 + HORSE_GAMEPLAY_MOUNTED_BUFFS_REINS_MODIFIER: 'CommonTraitId' = 335364 + HORSE_GAMEPLAY_PLAYFUL: 'CommonTraitId' = 322884 + HORSE_GAMEPLAY_RESILIENT: 'CommonTraitId' = 327598 + HORSE_GAMEPLAY_REWARD_TRAIT_TOP_NOTCH_FOAL: 'CommonTraitId' = 330841 + HORSE_HORSE_COMPETITION_BARREL_RACING_BEGINNER_1ST: 'CommonTraitId' = 332577 + HORSE_HORSE_COMPETITION_BARREL_RACING_BEGINNER_2ND: 'CommonTraitId' = 332605 + HORSE_HORSE_COMPETITION_BARREL_RACING_BEGINNER_3RD: 'CommonTraitId' = 332606 + HORSE_HORSE_COMPETITION_BARREL_RACING_EXPERT_1ST: 'CommonTraitId' = 332610 + HORSE_HORSE_COMPETITION_BARREL_RACING_EXPERT_2ND: 'CommonTraitId' = 332611 + HORSE_HORSE_COMPETITION_BARREL_RACING_EXPERT_3RD: 'CommonTraitId' = 332612 + HORSE_HORSE_COMPETITION_BARREL_RACING_INTERMEDIATE_1ST: 'CommonTraitId' = 332607 + HORSE_HORSE_COMPETITION_BARREL_RACING_INTERMEDIATE_2ND: 'CommonTraitId' = 332608 + HORSE_HORSE_COMPETITION_BARREL_RACING_INTERMEDIATE_3RD: 'CommonTraitId' = 332609 + HORSE_HORSE_COMPETITION_BARREL_RACING_MASTER_1ST: 'CommonTraitId' = 332613 + HORSE_HORSE_COMPETITION_BARREL_RACING_MASTER_2ND: 'CommonTraitId' = 332614 + HORSE_HORSE_COMPETITION_BARREL_RACING_MASTER_3RD: 'CommonTraitId' = 332615 + HORSE_HORSE_COMPETITION_ENDURANCE_RACING_BEGINNER_1ST: 'CommonTraitId' = 332630 + HORSE_HORSE_COMPETITION_ENDURANCE_RACING_BEGINNER_2ND: 'CommonTraitId' = 332631 + HORSE_HORSE_COMPETITION_ENDURANCE_RACING_BEGINNER_3RD: 'CommonTraitId' = 332632 + HORSE_HORSE_COMPETITION_ENDURANCE_RACING_EXPERT_1ST: 'CommonTraitId' = 332636 + HORSE_HORSE_COMPETITION_ENDURANCE_RACING_EXPERT_2ND: 'CommonTraitId' = 332637 + HORSE_HORSE_COMPETITION_ENDURANCE_RACING_EXPERT_3RD: 'CommonTraitId' = 332638 + HORSE_HORSE_COMPETITION_ENDURANCE_RACING_INTERMEDIATE_1ST: 'CommonTraitId' = 332633 + HORSE_HORSE_COMPETITION_ENDURANCE_RACING_INTERMEDIATE_2ND: 'CommonTraitId' = 332634 + HORSE_HORSE_COMPETITION_ENDURANCE_RACING_INTERMEDIATE_3RD: 'CommonTraitId' = 332635 + HORSE_HORSE_COMPETITION_ENDURANCE_RACING_MASTER_1ST: 'CommonTraitId' = 332639 + HORSE_HORSE_COMPETITION_ENDURANCE_RACING_MASTER_2ND: 'CommonTraitId' = 332640 + HORSE_HORSE_COMPETITION_ENDURANCE_RACING_MASTER_3RD: 'CommonTraitId' = 332641 + HORSE_HORSE_COMPETITION_NO_COMPETITIONS_WON: 'CommonTraitId' = 332655 + HORSE_HORSE_COMPETITION_SHOW_JUMPING_BEGINNER_1ST: 'CommonTraitId' = 332617 + HORSE_HORSE_COMPETITION_SHOW_JUMPING_BEGINNER_2ND: 'CommonTraitId' = 332618 + HORSE_HORSE_COMPETITION_SHOW_JUMPING_BEGINNER_3RD: 'CommonTraitId' = 332619 + HORSE_HORSE_COMPETITION_SHOW_JUMPING_EXPERT_1ST: 'CommonTraitId' = 332623 + HORSE_HORSE_COMPETITION_SHOW_JUMPING_EXPERT_2ND: 'CommonTraitId' = 332624 + HORSE_HORSE_COMPETITION_SHOW_JUMPING_EXPERT_3RD: 'CommonTraitId' = 332625 + HORSE_HORSE_COMPETITION_SHOW_JUMPING_INTERMEDIATE_1ST: 'CommonTraitId' = 332620 + HORSE_HORSE_COMPETITION_SHOW_JUMPING_INTERMEDIATE_2ND: 'CommonTraitId' = 332621 + HORSE_HORSE_COMPETITION_SHOW_JUMPING_INTERMEDIATE_3RD: 'CommonTraitId' = 332622 + HORSE_HORSE_COMPETITION_SHOW_JUMPING_MASTER_1ST: 'CommonTraitId' = 332626 + HORSE_HORSE_COMPETITION_SHOW_JUMPING_MASTER_2ND: 'CommonTraitId' = 332627 + HORSE_HORSE_COMPETITION_SHOW_JUMPING_MASTER_3RD: 'CommonTraitId' = 332628 + HORSE_HORSE_COMPETITION_ULTIMATE_CHAMPIONSHIP_1ST: 'CommonTraitId' = 334426 + HORSE_HORSE_COMPETITION_ULTIMATE_CHAMPIONSHIP_2ND: 'CommonTraitId' = 334427 + HORSE_HORSE_COMPETITION_ULTIMATE_CHAMPIONSHIP_3RD: 'CommonTraitId' = 334428 + HORSE_HORSE_COMPETITION_WESTERN_PLEASURE_BEGINNER_1ST: 'CommonTraitId' = 332643 + HORSE_HORSE_COMPETITION_WESTERN_PLEASURE_BEGINNER_2ND: 'CommonTraitId' = 332644 + HORSE_HORSE_COMPETITION_WESTERN_PLEASURE_BEGINNER_3RD: 'CommonTraitId' = 332645 + HORSE_HORSE_COMPETITION_WESTERN_PLEASURE_EXPERT_1ST: 'CommonTraitId' = 332649 + HORSE_HORSE_COMPETITION_WESTERN_PLEASURE_EXPERT_2ND: 'CommonTraitId' = 332650 + HORSE_HORSE_COMPETITION_WESTERN_PLEASURE_EXPERT_3RD: 'CommonTraitId' = 332651 + HORSE_HORSE_COMPETITION_WESTERN_PLEASURE_INTERMEDIATE_1ST: 'CommonTraitId' = 332646 + HORSE_HORSE_COMPETITION_WESTERN_PLEASURE_INTERMEDIATE_2ND: 'CommonTraitId' = 332647 + HORSE_HORSE_COMPETITION_WESTERN_PLEASURE_INTERMEDIATE_3RD: 'CommonTraitId' = 332648 + HORSE_HORSE_COMPETITION_WESTERN_PLEASURE_MASTER_1ST: 'CommonTraitId' = 332652 + HORSE_HORSE_COMPETITION_WESTERN_PLEASURE_MASTER_2ND: 'CommonTraitId' = 332653 + HORSE_HORSE_COMPETITION_WESTERN_PLEASURE_MASTER_3RD: 'CommonTraitId' = 332654 + HORSE_HORSE_TRANSACTION_RESCUE_HIDDEN: 'CommonTraitId' = 342879 + HORSE_LOVER: 'CommonTraitId' = 320965 + HORSE_PERSONALITY_AGGRESSIVE: 'CommonTraitId' = 323824 + HORSE_PERSONALITY_BRAVE: 'CommonTraitId' = 322830 + HORSE_PERSONALITY_DEFIANT: 'CommonTraitId' = 323821 + HORSE_PERSONALITY_ENERGETIC: 'CommonTraitId' = 322878 + HORSE_PERSONALITY_FEARFUL: 'CommonTraitId' = 322834 + HORSE_PERSONALITY_FREESPIRIT: 'CommonTraitId' = 323822 + HORSE_PERSONALITY_FRIENDLY: 'CommonTraitId' = 322836 + HORSE_PERSONALITY_INDEPENDENT: 'CommonTraitId' = 323823 + HORSE_PERSONALITY_INTELLIGENT: 'CommonTraitId' = 322882 + HORSE_PERSONALITY_MELLOW: 'CommonTraitId' = 322880 + HORSE_PERSONALITY_NEEDY: 'CommonTraitId' = 327817 + HOT_HEADED: 'CommonTraitId' = 16845 + HUMANOID_ROBOT_BEHAVIOR_MODULES_CHILD_CARE_ACTIVE: 'CommonTraitId' = 218976 + HUMANOID_ROBOT_BEHAVIOR_MODULES_CHILD_CARE_LEARNED: 'CommonTraitId' = 224700 + HUMANOID_ROBOT_BEHAVIOR_MODULES_CHILD_CARE_NOT_LEARNED: 'CommonTraitId' = 221933 + HUMANOID_ROBOT_BEHAVIOR_MODULES_CHILD_CARE_TRIGGER_UNLOCK: 'CommonTraitId' = 224686 + HUMANOID_ROBOT_BEHAVIOR_MODULES_CLEANING_ACTIVE: 'CommonTraitId' = 218970 + HUMANOID_ROBOT_BEHAVIOR_MODULES_CLEANING_LEARNED: 'CommonTraitId' = 224694 + HUMANOID_ROBOT_BEHAVIOR_MODULES_CLEANING_NOT_LEARNED: 'CommonTraitId' = 221934 + HUMANOID_ROBOT_BEHAVIOR_MODULES_CLEANING_TRIGGER_UNLOCK: 'CommonTraitId' = 224680 + HUMANOID_ROBOT_BEHAVIOR_MODULES_GARDENING_ACTIVE: 'CommonTraitId' = 218972 + HUMANOID_ROBOT_BEHAVIOR_MODULES_GARDENING_LEARNED: 'CommonTraitId' = 224696 + HUMANOID_ROBOT_BEHAVIOR_MODULES_GARDENING_NOT_LEARNED: 'CommonTraitId' = 221936 + HUMANOID_ROBOT_BEHAVIOR_MODULES_GARDENING_TRIGGER_UNLOCK: 'CommonTraitId' = 224687 + HUMANOID_ROBOT_BEHAVIOR_MODULES_PARTY_ACTIVE: 'CommonTraitId' = 219663 + HUMANOID_ROBOT_BEHAVIOR_MODULES_PARTY_LEARNED: 'CommonTraitId' = 224697 + HUMANOID_ROBOT_BEHAVIOR_MODULES_PARTY_NOT_LEARNED: 'CommonTraitId' = 221937 + HUMANOID_ROBOT_BEHAVIOR_MODULES_PARTY_TRIGGER_UNLOCK: 'CommonTraitId' = 224688 + HUMANOID_ROBOT_BEHAVIOR_MODULES_REPAIR_ACTIVE: 'CommonTraitId' = 218973 + HUMANOID_ROBOT_BEHAVIOR_MODULES_REPAIR_LEARNED: 'CommonTraitId' = 224698 + HUMANOID_ROBOT_BEHAVIOR_MODULES_REPAIR_NOT_LEARNED: 'CommonTraitId' = 221938 + HUMANOID_ROBOT_BEHAVIOR_MODULES_REPAIR_TRIGGER_UNLOCK: 'CommonTraitId' = 224689 + HUMANOID_ROBOT_BEHAVIOR_MODULES_SECURITY_ACTIVE: 'CommonTraitId' = 218974 + HUMANOID_ROBOT_BEHAVIOR_MODULES_SECURITY_LEARNED: 'CommonTraitId' = 224699 + HUMANOID_ROBOT_BEHAVIOR_MODULES_SECURITY_NOT_LEARNED: 'CommonTraitId' = 221939 + HUMANOID_ROBOT_BEHAVIOR_MODULES_SECURITY_TRIGGER_UNLOCK: 'CommonTraitId' = 224682 + HUMANOID_ROBOT_ENHANCEMENT_LEVEL_1: 'CommonTraitId' = 219911 + HUMANOID_ROBOT_ENHANCEMENT_LEVEL_10: 'CommonTraitId' = 219910 + HUMANOID_ROBOT_ENHANCEMENT_LEVEL_2: 'CommonTraitId' = 219912 + HUMANOID_ROBOT_ENHANCEMENT_LEVEL_3: 'CommonTraitId' = 219913 + HUMANOID_ROBOT_ENHANCEMENT_LEVEL_4: 'CommonTraitId' = 219914 + HUMANOID_ROBOT_ENHANCEMENT_LEVEL_5: 'CommonTraitId' = 219915 + HUMANOID_ROBOT_ENHANCEMENT_LEVEL_6: 'CommonTraitId' = 219916 + HUMANOID_ROBOT_ENHANCEMENT_LEVEL_7: 'CommonTraitId' = 219917 + HUMANOID_ROBOT_ENHANCEMENT_LEVEL_8: 'CommonTraitId' = 219918 + HUMANOID_ROBOT_ENHANCEMENT_LEVEL_9: 'CommonTraitId' = 219919 + HUMANOID_ROBOT_HOVER: 'CommonTraitId' = 229578 + HUMANOID_ROBOT_OUTFIT_BEIGE_WHITE: 'CommonTraitId' = 228855 + HUMANOID_ROBOT_OUTFIT_BLACK_BLUE: 'CommonTraitId' = 228856 + HUMANOID_ROBOT_OUTFIT_BLUE_RED: 'CommonTraitId' = 228858 + HUMANOID_ROBOT_OUTFIT_GRAY_BROWN: 'CommonTraitId' = 228857 + HUMANOID_ROBOT_OUTFIT_GREEN_BROWN: 'CommonTraitId' = 228859 + HUMANOID_ROBOT_OUTFIT_RED_GREEN: 'CommonTraitId' = 228860 + HUMANOID_ROBOT_OUTFIT_WHITE_COPPER: 'CommonTraitId' = 228861 + ICONIC: 'CommonTraitId' = 282899 + IDENTIFIED_CHAMOMILE: 'CommonTraitId' = 104486 + IDENTIFIED_CHAMOMILE_TOXIC: 'CommonTraitId' = 104487 + IDENTIFIED_ELDERBERRY: 'CommonTraitId' = 104480 + IDENTIFIED_ELDERBERRY_TOXIC: 'CommonTraitId' = 104481 + IDENTIFIED_FIRE_LEAF: 'CommonTraitId' = 104484 + IDENTIFIED_FIRE_LEAF_TOXIC: 'CommonTraitId' = 104485 + IDENTIFIED_HUCKLEBERRY: 'CommonTraitId' = 104482 + IDENTIFIED_HUCKLEBERRY_TOXIC: 'CommonTraitId' = 104483 + IDENTIFIED_MOREL: 'CommonTraitId' = 104488 + IDENTIFIED_MOREL_TOXIC: 'CommonTraitId' = 104489 + INCREDIBLY_FRIENDLY: 'CommonTraitId' = 102783 + INDEPENDENT: 'CommonTraitId' = 26393 + INFANT: 'CommonTraitId' = 266297 + INFANT_CALM: 'CommonTraitId' = 273755 + INFANT_CAUTIOUS: 'CommonTraitId' = 273756 + INFANT_INTENSE: 'CommonTraitId' = 273757 + INFANT_MILESTONE_BG_UNLOCK_CORE_HIDDEN: 'CommonTraitId' = 289863 + INFANT_MILESTONE_BG_UNLOCK_FIRST_BATH_HIDDEN: 'CommonTraitId' = 287069 + INFANT_MILESTONE_BG_UNLOCK_FIRST_BLOWOUT_HIDDEN: 'CommonTraitId' = 321444 + INFANT_MILESTONE_BG_UNLOCK_FIRST_BUBBLE_BATH_HIDDEN: 'CommonTraitId' = 287070 + INFANT_MILESTONE_BG_UNLOCK_FIRST_FOOD_HIDDEN: 'CommonTraitId' = 287066 + INFANT_MILESTONE_BG_UNLOCK_FIRST_TRIP_TO_PARK_HIDDEN: 'CommonTraitId' = 287072 + INFANT_MILESTONE_BG_UNLOCK_FIRST_VACATION_HIDDEN: 'CommonTraitId' = 287073 + INFANT_MILESTONE_BG_UNLOCK_FIRST_VISITORS_HIDDEN: 'CommonTraitId' = 287071 + INFANT_MILESTONE_BG_UNLOCK_FIRST_VISIT_TO_FAMILY_HIDDEN: 'CommonTraitId' = 287074 + INFANT_MILESTONE_BG_UNLOCK_PEES_ON_PARENT_HIDDEN: 'CommonTraitId' = 287068 + INFANT_MILESTONE_CAN_CRAWL_HIDDEN: 'CommonTraitId' = 322737 + INFANT_MILESTONE_CLAP_HIDDEN: 'CommonTraitId' = 291534 + INFANT_MILESTONE_COO_HIDDEN: 'CommonTraitId' = 291535 + INFANT_MILESTONE_IMMOBILE_HIDDEN: 'CommonTraitId' = 291557 + INFANT_MILESTONE_LAUGH_HIDDEN: 'CommonTraitId' = 291533 + INFANT_MILESTONE_SIT_UP_HIDDEN: 'CommonTraitId' = 287588 + INFANT_MILESTONE_SLEPT_THROUGH_NIGHT_HIDDEN: 'CommonTraitId' = 331334 + INFANT_PERSONALITY_FREQUENTLY_HICCUPS_HIDDEN: 'CommonTraitId' = 286064 + INFANT_PERSONALITY_FREQUENTLY_HICCUPS_VISIBLE: 'CommonTraitId' = 319874 + INFANT_PERSONALITY_FREQUENTLY_SNEEZES_HIDDEN: 'CommonTraitId' = 286065 + INFANT_PERSONALITY_FREQUENTLY_SNEEZES_VISIBLE: 'CommonTraitId' = 319875 + INFANT_PERSONALITY_GASSY_HIDDEN: 'CommonTraitId' = 286074 + INFANT_PERSONALITY_GASSY_VISIBLE: 'CommonTraitId' = 319914 + INFANT_PERSONALITY_GOOD_APPETITE_HIDDEN: 'CommonTraitId' = 286075 + INFANT_PERSONALITY_GOOD_APPETITE_VISIBLE: 'CommonTraitId' = 319915 + INFANT_PERSONALITY_HAPPY_SPITTER_HIDDEN: 'CommonTraitId' = 286076 + INFANT_PERSONALITY_HAPPY_SPITTER_VISIBLE: 'CommonTraitId' = 319916 + INFANT_PERSONALITY_HATES_BEING_HELD_HIDDEN: 'CommonTraitId' = 286077 + INFANT_PERSONALITY_HATES_BEING_HELD_VISIBLE: 'CommonTraitId' = 319917 + INFANT_PERSONALITY_HATES_WAKING_UP_HIDDEN: 'CommonTraitId' = 286078 + INFANT_PERSONALITY_HATES_WAKING_UP_VISIBLE: 'CommonTraitId' = 319918 + INFANT_PERSONALITY_LOVES_BEING_HELD_HIDDEN: 'CommonTraitId' = 286079 + INFANT_PERSONALITY_LOVES_BEING_HELD_VISIBLE: 'CommonTraitId' = 319919 + INFANT_PERSONALITY_LOVES_WAKING_UP_HIDDEN: 'CommonTraitId' = 286080 + INFANT_PERSONALITY_LOVES_WAKING_UP_VISIBLE: 'CommonTraitId' = 319920 + INFANT_PERSONALITY_MESSY_EATER_HIDDEN: 'CommonTraitId' = 286081 + INFANT_PERSONALITY_MESSY_EATER_VISIBLE: 'CommonTraitId' = 319921 + INFANT_PERSONALITY_OBSESSED_WITH_SOUND_HIDDEN: 'CommonTraitId' = 286073 + INFANT_PERSONALITY_OBSESSED_WITH_SOUND_VISIBLE: 'CommonTraitId' = 319876 + INFANT_PERSONALITY_ONLY_SLEEPS_WHEN_HELD_HIDDEN: 'CommonTraitId' = 286072 + INFANT_PERSONALITY_ONLY_SLEEPS_WHEN_HELD_VISIBLE: 'CommonTraitId' = 319877 + INFANT_PERSONALITY_PEES_DURING_CHANGES_HIDDEN: 'CommonTraitId' = 286071 + INFANT_PERSONALITY_PEES_DURING_CHANGES_VISIBLE: 'CommonTraitId' = 319878 + INFANT_PERSONALITY_PEES_DURING_FEEDING_HIDDEN: 'CommonTraitId' = 286070 + INFANT_PERSONALITY_PEES_DURING_FEEDING_VISIBLE: 'CommonTraitId' = 319879 + INFANT_PERSONALITY_PICKY_EATER_HIDDEN: 'CommonTraitId' = 286069 + INFANT_PERSONALITY_PICKY_EATER_VISIBLE: 'CommonTraitId' = 319880 + INFANT_PERSONALITY_RISES_WITH_THE_SUN_HIDDEN: 'CommonTraitId' = 286067 + INFANT_PERSONALITY_RISES_WITH_THE_SUN_VISIBLE: 'CommonTraitId' = 319881 + INFANT_PERSONALITY_SELF_SOOTHER_HIDDEN: 'CommonTraitId' = 286066 + INFANT_PERSONALITY_SELF_SOOTHER_VISIBLE: 'CommonTraitId' = 319912 + INFANT_PERSONALITY_TALKER_HIDDEN: 'CommonTraitId' = 286068 + INFANT_PERSONALITY_TALKER_VISIBLE: 'CommonTraitId' = 319913 + INFANT_SENSITIVE: 'CommonTraitId' = 273758 + INFANT_SUNNY: 'CommonTraitId' = 273759 + INFANT_WIGGLY: 'CommonTraitId' = 273760 + INSANE: 'CommonTraitId' = 16848 + INSIDER: 'CommonTraitId' = 125437 + INTERIOR_DECORATOR_CLIENT_COOLDOWN: 'CommonTraitId' = 265334 + INTERIOR_DECORATOR_CLIENT_FOLLOW_UP_GIG_NEGATIVE: 'CommonTraitId' = 265375 + INTERIOR_DECORATOR_CLIENT_FOLLOW_UP_GIG_POSITIVE: 'CommonTraitId' = 265376 + INTERIOR_DECORATOR_CLIENT_FOLLOW_UP_GIG_REFERRED: 'CommonTraitId' = 265374 + INTERIOR_DECORATOR_HIDE_CLIENTS: 'CommonTraitId' = 261858 + INTRO_TO_VAMPIRE_CALLER: 'CommonTraitId' = 154812 + INVESTED: 'CommonTraitId' = 27942 + IN_THE_KNOW: 'CommonTraitId' = 144978 + ISLANDER_CULTURE_ISLANDER: 'CommonTraitId' = 208611 + IS_ALIEN_POLLINATOR: 'CommonTraitId' = 112688 + IS_BEAR: 'CommonTraitId' = 104472 + IS_BORN_FROM_ALIEN_ABDUCTION: 'CommonTraitId' = 102922 + IS_BUTLER: 'CommonTraitId' = 147121 + IS_CHALET_GARDENS_GHOST: 'CommonTraitId' = 125534 + IS_CITY_REPAIR: 'CommonTraitId' = 155997 + IS_CUSTOM_GENDER: 'CommonTraitId' = 136866 + IS_FIREFIGHTER: 'CommonTraitId' = 237784 + IS_FOREST_RANGER: 'CommonTraitId' = 108760 + IS_GARDENER: 'CommonTraitId' = 196904 + IS_GARDENER_SERVICE: 'CommonTraitId' = 130541 + IS_GRIM_REAPER: 'CommonTraitId' = 16851 + IS_IN_COLLEGE_ORGANIZATION: 'CommonTraitId' = 210946 + IS_LAND_ANCESTOR_ELEMENTAL: 'CommonTraitId' = 211645 + IS_MAID: 'CommonTraitId' = 16852 + IS_MAILMAN: 'CommonTraitId' = 16853 + IS_MASSAGE_THERAPIST: 'CommonTraitId' = 119668 + IS_MASTER_FISHERMAN: 'CommonTraitId' = 40467 + IS_MASTER_GARDENER: 'CommonTraitId' = 40359 + IS_MASTER_HERBALIST: 'CommonTraitId' = 101850 + IS_NANNY: 'CommonTraitId' = 141854 + IS_PIZZA_DELIVERY: 'CommonTraitId' = 10581 + IS_PLANT_SIM_NPC: 'CommonTraitId' = 164296 + IS_PREGNANT: 'CommonTraitId' = 16854 + IS_PREGNANT_ALIEN_ABDUCTION: 'CommonTraitId' = 139579 + IS_PREMADE_PO: 'CommonTraitId' = 350528 + IS_RANCH_HAND: 'CommonTraitId' = 303813 + IS_REPAIR: 'CommonTraitId' = 129480 + IS_RESTAURANT_CRITIC: 'CommonTraitId' = 139513 + IS_SCHOOL_GHOST: 'CommonTraitId' = 229389 + IS_STATUE_BUSKER: 'CommonTraitId' = 155999 + IS_TRAGIC_CLOWN: 'CommonTraitId' = 139879 + IS_WEIRDO: 'CommonTraitId' = 155998 + JEALOUS: 'CommonTraitId' = 124879 + JOB_LOSS_IN_LAY_OFF_PERIOD: 'CommonTraitId' = 306064 + JUNGLE_EXPLORER_TREASURE_HUNTER: 'CommonTraitId' = 178994 + JUNGLE_EXPLORER_TREASURE_HUNTER_BG: 'CommonTraitId' = 194391 + KEEPSAKE_BOX_DESIGNATED_HIDDEN: 'CommonTraitId' = 322584 + KIDS_BIKE_CANT_RIDE: 'CommonTraitId' = 305615 + KIDS_BIKE_CAN_RIDE: 'CommonTraitId' = 305620 + KLEPTOMANIAC: 'CommonTraitId' = 131783 + KNITTING_GIFTED_GRIM: 'CommonTraitId' = 243910 + KNOWLEDGE_SLINGER_OF_SPELLS: 'CommonTraitId' = 217373 + LACTOSE_INTOLERANT: 'CommonTraitId' = 257367 + LAZY: 'CommonTraitId' = 9599 + LEGENDARY: 'CommonTraitId' = 27091 + LIFESTYLE_ADRENALINE_SEEKER: 'CommonTraitId' = 248829 + LIFESTYLE_CLOSE_KNIT: 'CommonTraitId' = 248617 + LIFESTYLE_COFFEE_FANATIC: 'CommonTraitId' = 246515 + LIFESTYLE_ENERGETIC: 'CommonTraitId' = 248151 + LIFESTYLE_FREQUENT_TRAVELER: 'CommonTraitId' = 246345 + LIFESTYLE_HEALTH_FOOD_NUT: 'CommonTraitId' = 247602 + LIFESTYLE_HUNGRY_FOR_HUMAN_LOVE: 'CommonTraitId' = 250662 + LIFESTYLE_INDOORSY: 'CommonTraitId' = 248830 + LIFESTYLE_JUNK_FOOD_DEVOURER: 'CommonTraitId' = 247603 + LIFESTYLE_NETWORKER: 'CommonTraitId' = 248616 + LIFESTYLE_NO_NEED_FOR_HUMAN_ROMANCE: 'CommonTraitId' = 250661 + LIFESTYLE_OUTDOORSY: 'CommonTraitId' = 248831 + LIFESTYLE_SEDENTARY: 'CommonTraitId' = 248133 + LIFESTYLE_TECHIE: 'CommonTraitId' = 246953 + LIFESTYLE_TECHNOPHOBE: 'CommonTraitId' = 246952 + LIFESTYLE_WORKAHOLIC: 'CommonTraitId' = 245828 + LIFE_SKILLS_ARGUMENTATIVE: 'CommonTraitId' = 161628 + LIFE_SKILLS_BAD_MANNERS: 'CommonTraitId' = 160848 + LIFE_SKILLS_COMPASSIONATE: 'CommonTraitId' = 160862 + LIFE_SKILLS_EMOTIONAL_CONTROL: 'CommonTraitId' = 160275 + LIFE_SKILLS_GOOD_MANNERS: 'CommonTraitId' = 160841 + LIFE_SKILLS_IRRESPONSIBLE: 'CommonTraitId' = 161626 + LIFE_SKILLS_MEDIATOR: 'CommonTraitId' = 161627 + LIFE_SKILLS_RESPONSIBLE: 'CommonTraitId' = 161625 + LIFE_SKILLS_UNCONTROLLED_EMOTION: 'CommonTraitId' = 160265 + LIFE_SKILLS_UNFEELING: 'CommonTraitId' = 160954 + LIKES_MAYO: 'CommonTraitId' = 267876 + LIVING_VICARIOUSLY: 'CommonTraitId' = 29837 + LONER: 'CommonTraitId' = 9602 + LONGEVITY: 'CommonTraitId' = 27081 + LOT_TRAIT_SIMPLE_LIVING_COOK_BOOK: 'CommonTraitId' = 268277 + LOVESTRUCK: 'CommonTraitId' = 362090 + LOVES_OUTDOORS: 'CommonTraitId' = 27914 + LOVE_EXPLORER: 'CommonTraitId' = 367987 + LOVE_GURU: 'CommonTraitId' = 146648 + LOVE_POLY: 'CommonTraitId' = 367988 + LOYAL: 'CommonTraitId' = 311267 + MAGIC_DARREL_CHARM: 'CommonTraitId' = 220515 + MAGIC_EMILIA_ERNEST: 'CommonTraitId' = 220554 + MAGIC_GEMMA_CHARM: 'CommonTraitId' = 220555 + MAGIC_GRACE_ANANSI: 'CommonTraitId' = 220816 + MAGIC_MARKET_STALL_SPECTRAL_LOOK: 'CommonTraitId' = 217017 + MAGIC_MINERVA_CHARM: 'CommonTraitId' = 220508 + MAGIC_PERKS_MAGIC_VENUE_NPC: 'CommonTraitId' = 219098 + MAGIC_POTIONS_INTERMEDIATE: 'CommonTraitId' = 218530 + MAGIC_POTIONS_NOVICE: 'CommonTraitId' = 218532 + MAGIC_POTIONS_SAGE: 'CommonTraitId' = 218531 + MAGIC_SAGE_MISCHIEF: 'CommonTraitId' = 212849 + MAGIC_SAGE_PRACTICAL: 'CommonTraitId' = 212850 + MAGIC_SAGE_UNTAMED: 'CommonTraitId' = 212851 + MAGIC_SPELLS_MAGIC_SAGE_MISCHIEF: 'CommonTraitId' = 215988 + MAGIC_SPELLS_MAGIC_SAGE_PRACTICAL: 'CommonTraitId' = 215989 + MAGIC_SPELLS_MAGIC_SAGE_UNTAMED: 'CommonTraitId' = 215987 + MAGIC_SPELLS_MAGIC_VENUE_NPC_INTERMEDIATE: 'CommonTraitId' = 215986 + MAGIC_SPELLS_MAGIC_VENUE_NPC_NOVICE: 'CommonTraitId' = 215984 + MAGIC_TOMAX_COLLETTE: 'CommonTraitId' = 220818 + MAKER: 'CommonTraitId' = 230745 + MAKE_PREGNANT: 'CommonTraitId' = 238592 + MARKETABLE: 'CommonTraitId' = 31924 + MASTERMIND: 'CommonTraitId' = 27184 + MASTER_MAKER: 'CommonTraitId' = 231700 + MASTER_TRAINER: 'CommonTraitId' = 321397 + MATCHMAKING_DISABLED_HIDDEN: 'CommonTraitId' = 365861 + MATERIALISTIC: 'CommonTraitId' = 27913 + MEAN: 'CommonTraitId' = 16857 + MECHANICAL_SUIT_HOVER_ENGAGED: 'CommonTraitId' = 226744 + MECHANICAL_SUIT_WEARING_BODY_BEIGE_WHITE: 'CommonTraitId' = 226777 + MECHANICAL_SUIT_WEARING_BODY_BLACK_BLUE: 'CommonTraitId' = 226778 + MECHANICAL_SUIT_WEARING_BODY_BLUE_RED: 'CommonTraitId' = 226783 + MECHANICAL_SUIT_WEARING_BODY_GRAY_BROWN: 'CommonTraitId' = 226779 + MECHANICAL_SUIT_WEARING_BODY_GREEN_BROWN: 'CommonTraitId' = 226780 + MECHANICAL_SUIT_WEARING_BODY_RED_GREEN: 'CommonTraitId' = 226781 + MECHANICAL_SUIT_WEARING_BODY_WHITE_COPPER: 'CommonTraitId' = 226782 + MECHANICAL_SUIT_WEARING_HELMET_BLACK_BLUE: 'CommonTraitId' = 226800 + MECHANICAL_SUIT_WEARING_HELMET_BLACK_COPPER: 'CommonTraitId' = 226801 + MECHANICAL_SUIT_WEARING_HELMET_BLACK_GOLD: 'CommonTraitId' = 226802 + MECHANICAL_SUIT_WEARING_HELMET_BLACK_GRAY: 'CommonTraitId' = 226803 + MECHANICAL_SUIT_WEARING_HELMET_BLUE_GRAY: 'CommonTraitId' = 226804 + MECHANICAL_SUIT_WEARING_HELMET_GRAY_BLACK: 'CommonTraitId' = 226805 + MECHANICAL_SUIT_WEARING_HELMET_GREEN_BLACK: 'CommonTraitId' = 226806 + MEDIUM_SWIMMING: 'CommonTraitId' = 212821 + MELT_MASTER: 'CommonTraitId' = 132296 + MEMORABLE: 'CommonTraitId' = 32429 + MENTALLY_GIFTED: 'CommonTraitId' = 29620 + MENTOR: 'CommonTraitId' = 26691 + MIDLIFE_CRISIS_HAD_A_CRISIS: 'CommonTraitId' = 313577 + MISBEHAVIOR_CAT_JUMP_ON_COUNTERS: 'CommonTraitId' = 170714 + MISBEHAVIOR_CAT_SCRATCHING: 'CommonTraitId' = 162242 + MISBEHAVIOR_DOG_BARK: 'CommonTraitId' = 165942 + MISBEHAVIOR_DOG_EAT_POOP: 'CommonTraitId' = 168487 + MISBEHAVIOR_DOG_JUMP_ON_COUNTERS: 'CommonTraitId' = 170713 + MISBEHAVIOR_DOG_PUDDLES_PLAY: 'CommonTraitId' = 162246 + MISBEHAVIOR_DOG_TOILET: 'CommonTraitId' = 162243 + MISBEHAVIOR_PET_ATTACK: 'CommonTraitId' = 162253 + MISBEHAVIOR_PET_BEG_EATING: 'CommonTraitId' = 162252 + MISBEHAVIOR_PET_DEBUG: 'CommonTraitId' = 173099 + MISBEHAVIOR_PET_EAT_PEOPLE_FOOD: 'CommonTraitId' = 170716 + MISBEHAVIOR_PET_PUDDLES_DRINK: 'CommonTraitId' = 162249 + MISBEHAVIOR_PET_TRASH_EAT: 'CommonTraitId' = 162250 + MISBEHAVIOR_PET_TRASH_PLAY: 'CommonTraitId' = 162251 + MISBEHAVIOR_PET_WAKE_UP_SIMS: 'CommonTraitId' = 170715 + MORNING_PERSON: 'CommonTraitId' = 32426 + MULTI_UNIT_ASPIRATION_DISCERNING_DWELLER: 'CommonTraitId' = 341149 + MULTI_UNIT_ASPIRATION_FOUNTAIN_OF_LOCAL_KNOWLEDGE: 'CommonTraitId' = 341160 + MULTI_UNIT_ASPIRATION_LEGENDARY_LANDLORD: 'CommonTraitId' = 341148 + MULTI_UNIT_ASPIRATION_SEEKER_OF_SECRETS: 'CommonTraitId' = 341161 + MULTI_UNIT_EVENT_TENANT_REVOLT_GENERIC_CAUSE_HIDDEN: 'CommonTraitId' = 344508 + MULTI_UNIT_GUIDE_KNOWLEDGEABLE_LEASER: 'CommonTraitId' = 352408 + MUSER: 'CommonTraitId' = 27085 + MUSIC_FESTIVAL_BEBE_REXHA: 'CommonTraitId' = 269689 + MUSIC_FESTIVAL_DAVE_BAYLEY: 'CommonTraitId' = 269691 + MUSIC_FESTIVAL_JOY_OLADOKUN: 'CommonTraitId' = 269690 + MUSIC_LOVER: 'CommonTraitId' = 9604 + NATURAL_SPEAKER: 'CommonTraitId' = 206416 + NATURE_COUNTRY_CARETAKER_NATURE_CONVERSATIONALIST: 'CommonTraitId' = 260922 + NATURE_INFLUENTIAL_INDIVIDUAL: 'CommonTraitId' = 232081 + NATURE_MASTER_MIXER: 'CommonTraitId' = 217412 + NEAT: 'CommonTraitId' = 16858 + NECTAR_KNOW_IT_ALL: 'CommonTraitId' = 340646 + NEEDS_NO_ONE: 'CommonTraitId' = 183034 + NEVER_WEARY: 'CommonTraitId' = 26392 + NEW_IN_TOWN_INSPIRED_EXPLORER: 'CommonTraitId' = 297768 + NIGHT_OWL: 'CommonTraitId' = 32424 + NIGHT_OWL_CRYSTAL_HELMET: 'CommonTraitId' = 198854 + NOSY: 'CommonTraitId' = 341150 + NOSY_NEIGHBOR: 'CommonTraitId' = 274012 + NPC_MAKER: 'CommonTraitId' = 234888 + NPC_TENANT_APPLICANT_HIDDEN: 'CommonTraitId' = 350825 + OBSERVANT: 'CommonTraitId' = 32635 + OCCULT_ALIEN: 'CommonTraitId' = 102785 + OCCULT_ALIEN_CURRENT: 'CommonTraitId' = 103230 + OCCULT_ALIEN_FAKE_ALIEN: 'CommonTraitId' = 105149 + OCCULT_ALIEN_PART: 'CommonTraitId' = 102784 + OCCULT_MERFOLK_WOKE: 'CommonTraitId' = 206170 + OCCULT_MERMAID: 'CommonTraitId' = 199043 + OCCULT_MERMAID_DISCOVERED: 'CommonTraitId' = 215252 + OCCULT_MERMAID_MERMAID_FORM: 'CommonTraitId' = 199044 + OCCULT_MERMAID_TEMPORARY_DISCOVERED: 'CommonTraitId' = 215414 + OCCULT_MERMAID_TYAE: 'CommonTraitId' = 211545 + OCCULT_NO_OCCULT: 'CommonTraitId' = 154191 + OCCULT_ROBOT: 'CommonTraitId' = 218444 + OCCULT_VAMPIRE: 'CommonTraitId' = 149527 + OCCULT_VAMPIRE_BAT_BABY: 'CommonTraitId' = 152783 + OCCULT_VAMPIRE_CURED: 'CommonTraitId' = 150164 + OCCULT_VAMPIRE_DARK_FORM: 'CommonTraitId' = 149528 + OCCULT_VAMPIRE_DARK_LEY_LINE: 'CommonTraitId' = 154672 + OCCULT_VAMPIRE_MANIFESTED: 'CommonTraitId' = 153867 + OCCULT_VAMPIRE_MANUAL_DARK_FORM: 'CommonTraitId' = 156397 + OCCULT_WEREWOLF: 'CommonTraitId' = 289780 + OCCULT_WEREWOLF_ABILITIES_TRANSFORMATION_MASTERY: 'CommonTraitId' = 300559 + OCCULT_WEREWOLF_ASPIRATION_TRAITS_BETTER_FURY_CONTROL: 'CommonTraitId' = 291632 + OCCULT_WEREWOLF_ASPIRATION_TRAITS_BETTER_TURNING: 'CommonTraitId' = 291633 + OCCULT_WEREWOLF_ASPIRATION_TRAITS_FORMERLY_CAN: 'CommonTraitId' = 294207 + OCCULT_WEREWOLF_ASPIRATION_TRAITS_FRIENDLY_WOLF: 'CommonTraitId' = 291631 + OCCULT_WEREWOLF_ASPIRATION_TRAITS_MORE_FEAR: 'CommonTraitId' = 291635 + OCCULT_WEREWOLF_DORMANT_WOLF: 'CommonTraitId' = 288908 + OCCULT_WEREWOLF_GREATER_WOLF_BLOOD: 'CommonTraitId' = 289080 + OCCULT_WEREWOLF_HAD_FIRST_FULL_MOON: 'CommonTraitId' = 294966 + OCCULT_WEREWOLF_HAD_FIRST_TRANSFORMATION: 'CommonTraitId' = 288566 + OCCULT_WEREWOLF_HAS_FATED_MATE: 'CommonTraitId' = 293542 + OCCULT_WEREWOLF_IMMORTAL_WOLF: 'CommonTraitId' = 290521 + OCCULT_WEREWOLF_INITIATION_BONUS_TRAIT: 'CommonTraitId' = 290981 + OCCULT_WEREWOLF_MANIFESTED: 'CommonTraitId' = 276221 + OCCULT_WEREWOLF_NATURAL_HEALING: 'CommonTraitId' = 290526 + OCCULT_WEREWOLF_NO_FURY_GLOW: 'CommonTraitId' = 290772 + OCCULT_WEREWOLF_PRIMAL_INSTINCT: 'CommonTraitId' = 289945 + OCCULT_WEREWOLF_SUPER_SPEED: 'CommonTraitId' = 299122 + OCCULT_WEREWOLF_TEACH_TO_HOWL: 'CommonTraitId' = 295581 + OCCULT_WEREWOLF_TEMPERAMENTS_ANTI_CAPITALIST_CANINE: 'CommonTraitId' = 285387 + OCCULT_WEREWOLF_TEMPERAMENTS_BIG_BAD_WOLF: 'CommonTraitId' = 285363 + OCCULT_WEREWOLF_TEMPERAMENTS_CARNIVORE: 'CommonTraitId' = 285386 + OCCULT_WEREWOLF_TEMPERAMENTS_EASY_EXCITABLE: 'CommonTraitId' = 285388 + OCCULT_WEREWOLF_TEMPERAMENTS_FEELS_OUTCASTED: 'CommonTraitId' = 285371 + OCCULT_WEREWOLF_TEMPERAMENTS_FRISKY: 'CommonTraitId' = 285383 + OCCULT_WEREWOLF_TEMPERAMENTS_GRUMPY_WOLF: 'CommonTraitId' = 285381 + OCCULT_WEREWOLF_TEMPERAMENTS_HATES_BEING_WET: 'CommonTraitId' = 285382 + OCCULT_WEREWOLF_TEMPERAMENTS_HUNGRY_LIKE_THE_WOLF: 'CommonTraitId' = 285372 + OCCULT_WEREWOLF_TEMPERAMENTS_LUNAR_FOREST_MARK: 'CommonTraitId' = 291646 + OCCULT_WEREWOLF_TEMPERAMENTS_LUNAR_HUNT_MARK: 'CommonTraitId' = 291647 + OCCULT_WEREWOLF_TEMPERAMENTS_LUNAR_NIGHT_MARK: 'CommonTraitId' = 291645 + OCCULT_WEREWOLF_TEMPERAMENTS_LUNAR_WOLF_MARK: 'CommonTraitId' = 291644 + OCCULT_WEREWOLF_TEMPERAMENTS_MUST_BE_CLEAN: 'CommonTraitId' = 285369 + OCCULT_WEREWOLF_TEMPERAMENTS_NIGHT_WOLF: 'CommonTraitId' = 285391 + OCCULT_WEREWOLF_TEMPERAMENTS_PRIDEFUL: 'CommonTraitId' = 285368 + OCCULT_WEREWOLF_TEMPERAMENTS_RESTLESS_ANIMAL: 'CommonTraitId' = 285385 + OCCULT_WEREWOLF_TEMPERAMENTS_SENSITIVE_HEARING: 'CommonTraitId' = 285389 + OCCULT_WEREWOLF_TEMPERAMENTS_SURVIVAL_INSTINCTS: 'CommonTraitId' = 285367 + OCCULT_WEREWOLF_TEMPERAMENTS_TERRITORIAL: 'CommonTraitId' = 285366 + OCCULT_WEREWOLF_TEMPERAMENTS_WOLF_BRAIN: 'CommonTraitId' = 285390 + OCCULT_WEREWOLF_TEMPERAMENTS_WRACKED_WITH_GUILT: 'CommonTraitId' = 285364 + OCCULT_WEREWOLF_WEREFORM: 'CommonTraitId' = 276222 + OCCULT_WEREWOLF_WEREWOLF_ALLY: 'CommonTraitId' = 290172 + OCCULT_WITCH: 'CommonTraitId' = 213050 + OCCULT_WITCH_ASKED_ABOUT_MAGIC: 'CommonTraitId' = 215188 + OCCULT_WITCH_BLOODLINE_ANCIENT: 'CommonTraitId' = 218027 + OCCULT_WITCH_BLOODLINE_STRONG: 'CommonTraitId' = 218026 + OCCULT_WITCH_BLOODLINE_WEAK: 'CommonTraitId' = 218025 + OCCULT_WITCH_BROOM_USE_BROOM_TELEPORT: 'CommonTraitId' = 217844 + OCCULT_WITCH_FORMER_WITCH: 'CommonTraitId' = 215284 + OCCULT_WITCH_MANIFESTED: 'CommonTraitId' = 213061 + OCCULT_WITCH_MOTE_SIGHT: 'CommonTraitId' = 215163 + OCCULT_WITCH_PERKS_MOTE_HOUND: 'CommonTraitId' = 217145 + OCCULT_WITCH_TELEPORT: 'CommonTraitId' = 214838 + OCCULT_WITCH_WANDS_PREFER_WANDS: 'CommonTraitId' = 215298 + OCCULT_WITCH_WANDS_USE_WAND: 'CommonTraitId' = 215301 + ONE_WITH_NATURE: 'CommonTraitId' = 76817 + ON_TRASH_UPDATE_LOT: 'CommonTraitId' = 238937 + OUTGOING: 'CommonTraitId' = 29571 + OVER_ACHIEVER: 'CommonTraitId' = 284113 + PAPARAZZI: 'CommonTraitId' = 191783 + PARANOID: 'CommonTraitId' = 203542 + PARANORMAL_INVESTIGATOR_ASKED_GRIM: 'CommonTraitId' = 254374 + PARANORMAL_INVESTIGATOR_MEDIUM: 'CommonTraitId' = 255255 + PARENTING_SKILL_UNDERSTAND_BABY: 'CommonTraitId' = 163783 + PARTY_ANIMAL: 'CommonTraitId' = 284112 + PA_MATRIARCH: 'CommonTraitId' = 29827 + PERFECTIONIST: 'CommonTraitId' = 9617 + PERFECT_HOST: 'CommonTraitId' = 27172 + PERK_FEUD_TARGET: 'CommonTraitId' = 200795 + PETS_ADVENTURE_A: 'CommonTraitId' = 173060 + PETS_ADVENTURE_AA_UNSEEN: 'CommonTraitId' = 175942 + PETS_ADVENTURE_AB_UNSEEN: 'CommonTraitId' = 175943 + PETS_ADVENTURE_AC_UNSEEN: 'CommonTraitId' = 175944 + PETS_ADVENTURE_B: 'CommonTraitId' = 173058 + PETS_ADVENTURE_C: 'CommonTraitId' = 173059 + PETS_ADVENTURE_CA: 'CommonTraitId' = 175945 + PETS_ADVENTURE_CB: 'CommonTraitId' = 175946 + PETS_ADVENTURE_CC: 'CommonTraitId' = 175947 + PETS_ADVENTURE_LIGHTHOUSE_DOG: 'CommonTraitId' = 175660 + PETS_ADVENTURE_XA: 'CommonTraitId' = 173061 + PETS_ADVENTURE_XB: 'CommonTraitId' = 173062 + PETS_ADVENTURE_XC: 'CommonTraitId' = 173063 + PETS_TRAINING_COMMAND_FETCH: 'CommonTraitId' = 161172 + PETS_TRAINING_COMMAND_HEEL: 'CommonTraitId' = 161173 + PETS_TRAINING_COMMAND_LIE_DOWN: 'CommonTraitId' = 161170 + PETS_TRAINING_COMMAND_PLAY_DEAD: 'CommonTraitId' = 161174 + PETS_TRAINING_COMMAND_ROLL_OVER: 'CommonTraitId' = 161171 + PETS_TRAINING_COMMAND_SHAKE: 'CommonTraitId' = 161175 + PETS_TRAINING_COMMAND_SIT: 'CommonTraitId' = 161168 + PETS_TRAINING_COMMAND_SPEAK: 'CommonTraitId' = 161169 + PET_ACTIVE_CAT: 'CommonTraitId' = 158201 + PET_ACTIVE_DOG: 'CommonTraitId' = 171613 + PET_AGE_ADULT: 'CommonTraitId' = 167104 + PET_AGE_CHILD: 'CommonTraitId' = 167107 + PET_AGE_ELDER: 'CommonTraitId' = 167106 + PET_AGGRESSIVE_CAT: 'CommonTraitId' = 158768 + PET_AGGRESSIVE_DOG: 'CommonTraitId' = 171612 + PET_CURIOUS_CAT: 'CommonTraitId' = 158211 + PET_CURIOUS_DOG: 'CommonTraitId' = 171611 + PET_FRIENDLY_CAT: 'CommonTraitId' = 158765 + PET_FRIENDLY_DOG: 'CommonTraitId' = 171610 + PET_GLUTTON_CAT: 'CommonTraitId' = 159977 + PET_GLUTTON_DOG: 'CommonTraitId' = 171609 + PET_HAIRY_CAT: 'CommonTraitId' = 158772 + PET_HAIRY_DOG: 'CommonTraitId' = 171608 + PET_HUNTER_CAT: 'CommonTraitId' = 159972 + PET_HUNTER_DOG: 'CommonTraitId' = 171607 + PET_INDEPENDENT_CAT: 'CommonTraitId' = 158770 + PET_INDEPENDENT_DOG: 'CommonTraitId' = 171605 + PET_INSIDE_ONLY: 'CommonTraitId' = 158717 + PET_LAZY_CAT: 'CommonTraitId' = 158202 + PET_LAZY_DOG: 'CommonTraitId' = 171606 + PET_LOYAL_CAT: 'CommonTraitId' = 158771 + PET_LOYAL_DOG: 'CommonTraitId' = 171604 + PET_MISSING_PET: 'CommonTraitId' = 173563 + PET_NAUGHTY_CAT: 'CommonTraitId' = 159976 + PET_NAUGHTY_DOG: 'CommonTraitId' = 171603 + PET_OUTSIDE_ONLY: 'CommonTraitId' = 158718 + PET_PARENT_ADVENTURE: 'CommonTraitId' = 173544 + PET_PLAYFUL_CAT: 'CommonTraitId' = 164046 + PET_PLAYFUL_DOG: 'CommonTraitId' = 171602 + PET_QUIRK_FEAR_COFFEE_MAKER: 'CommonTraitId' = 159300 + PET_QUIRK_FEAR_COMPUTER: 'CommonTraitId' = 159302 + PET_QUIRK_FEAR_DISHWASHER: 'CommonTraitId' = 159295 + PET_QUIRK_FEAR_DOOR_BELL: 'CommonTraitId' = 159311 + PET_QUIRK_FEAR_FIRE: 'CommonTraitId' = 159296 + PET_QUIRK_FEAR_FITNESS_EQUIPMENT: 'CommonTraitId' = 159299 + PET_QUIRK_FEAR_GAMING: 'CommonTraitId' = 159301 + PET_QUIRK_FEAR_INSTRUMENT: 'CommonTraitId' = 159294 + PET_QUIRK_FEAR_MICROWAVE: 'CommonTraitId' = 159298 + PET_QUIRK_FEAR_ROBOT_VACUUM: 'CommonTraitId' = 171319 + PET_QUIRK_FEAR_SHOWER: 'CommonTraitId' = 159304 + PET_QUIRK_FEAR_STEREO: 'CommonTraitId' = 159292 + PET_QUIRK_FEAR_STOVE: 'CommonTraitId' = 159293 + PET_QUIRK_FEAR_SWIMMING: 'CommonTraitId' = 159297 + PET_QUIRK_FEAR_TOILET: 'CommonTraitId' = 159303 + PET_QUIRK_FEAR_TV: 'CommonTraitId' = 158096 + PET_QUIRK_FEAR_VACUUM: 'CommonTraitId' = 257142 + PET_QUIRK_OBSESSED_COFFEE_MAKER: 'CommonTraitId' = 159244 + PET_QUIRK_OBSESSED_COMPUTER: 'CommonTraitId' = 159248 + PET_QUIRK_OBSESSED_COOKING: 'CommonTraitId' = 159238 + PET_QUIRK_OBSESSED_DISHWASHER: 'CommonTraitId' = 159240 + PET_QUIRK_OBSESSED_DOOR_BELL: 'CommonTraitId' = 159312 + PET_QUIRK_OBSESSED_FIRE: 'CommonTraitId' = 159241 + PET_QUIRK_OBSESSED_FISH_TANKS: 'CommonTraitId' = 159246 + PET_QUIRK_OBSESSED_FITNESS_EQUIPMENT: 'CommonTraitId' = 159243 + PET_QUIRK_OBSESSED_FRIDGE: 'CommonTraitId' = 159251 + PET_QUIRK_OBSESSED_GAMING: 'CommonTraitId' = 159245 + PET_QUIRK_OBSESSED_INSTRUMENT: 'CommonTraitId' = 159239 + PET_QUIRK_OBSESSED_MICROWAVE: 'CommonTraitId' = 159242 + PET_QUIRK_OBSESSED_PET_MINOR_CAGE: 'CommonTraitId' = 184406 + PET_QUIRK_OBSESSED_ROBOT_VACUUM: 'CommonTraitId' = 171320 + PET_QUIRK_OBSESSED_SHOWER: 'CommonTraitId' = 159250 + PET_QUIRK_OBSESSED_STEREO: 'CommonTraitId' = 159237 + PET_QUIRK_OBSESSED_SWIMMING: 'CommonTraitId' = 171912 + PET_QUIRK_OBSESSED_TOILET: 'CommonTraitId' = 159249 + PET_QUIRK_OBSESSED_TV: 'CommonTraitId' = 158739 + PET_QUIRK_OBSESSED_VACUUM: 'CommonTraitId' = 257156 + PET_QUIRK_PET_BED_SPIN: 'CommonTraitId' = 174976 + PET_QUIRK_PREGNANCY_VOMITING_NO: 'CommonTraitId' = 174466 + PET_QUIRK_PREGNANCY_VOMITING_YES: 'CommonTraitId' = 174465 + PET_SKITTISH_CAT: 'CommonTraitId' = 158766 + PET_SKITTISH_DOG: 'CommonTraitId' = 171601 + PET_SMART_CAT: 'CommonTraitId' = 158769 + PET_SMART_DOG: 'CommonTraitId' = 171600 + PET_STUBBORN_CAT: 'CommonTraitId' = 158210 + PET_STUBBORN_DOG: 'CommonTraitId' = 171599 + PET_VOCAL_CAT: 'CommonTraitId' = 158767 + PET_VOCAL_DOG: 'CommonTraitId' = 171598 + PET_WANDERLUST_CAT: 'CommonTraitId' = 158693 + PET_WANDERLUST_DOG: 'CommonTraitId' = 171597 + PHONE_BLACK: 'CommonTraitId' = 149328 + PHONE_BLACK_STRIPES: 'CommonTraitId' = 149329 + PHONE_BLUE_POLKA: 'CommonTraitId' = 149330 + PHONE_BROWN: 'CommonTraitId' = 149331 + PHONE_COLOR_ASTRO_BLACK: 'CommonTraitId' = 284068 + PHONE_COLOR_ASTRO_GRAY: 'CommonTraitId' = 284069 + PHONE_COLOR_ASTRO_MAROON: 'CommonTraitId' = 284070 + PHONE_COLOR_ASTRO_PEACH: 'CommonTraitId' = 284071 + PHONE_COLOR_ASTRO_PINK: 'CommonTraitId' = 284072 + PHONE_COLOR_ASTRO_PURPLE: 'CommonTraitId' = 284073 + PHONE_COLOR_CASSETTE_BLACK: 'CommonTraitId' = 284318 + PHONE_COLOR_CASSETTE_BLUE: 'CommonTraitId' = 284320 + PHONE_COLOR_CASSETTE_GREEN: 'CommonTraitId' = 284319 + PHONE_COLOR_CASSETTE_ORANGE: 'CommonTraitId' = 284322 + PHONE_COLOR_CASSETTE_PINK: 'CommonTraitId' = 284321 + PHONE_COLOR_CASSETTE_RED: 'CommonTraitId' = 284317 + PHONE_COLOR_DUO_BABY_BLUE: 'CommonTraitId' = 284346 + PHONE_COLOR_DUO_BLACK: 'CommonTraitId' = 284349 + PHONE_COLOR_DUO_GREEN: 'CommonTraitId' = 284348 + PHONE_COLOR_DUO_LAVENDER: 'CommonTraitId' = 284347 + PHONE_COLOR_DUO_SLATE: 'CommonTraitId' = 284344 + PHONE_COLOR_DUO_UMBER: 'CommonTraitId' = 284345 + PHONE_COLOR_FLORAL_GREEN_BLUE: 'CommonTraitId' = 284269 + PHONE_COLOR_FLORAL_MAUVE: 'CommonTraitId' = 284271 + PHONE_COLOR_FLORAL_PEACH: 'CommonTraitId' = 284268 + PHONE_COLOR_FLORAL_PINK: 'CommonTraitId' = 284272 + PHONE_COLOR_FLORAL_SLATE: 'CommonTraitId' = 284273 + PHONE_COLOR_FLORAL_YELLOW: 'CommonTraitId' = 284270 + PHONE_COLOR_GEO_BLUE: 'CommonTraitId' = 284293 + PHONE_COLOR_GEO_BROWN: 'CommonTraitId' = 284298 + PHONE_COLOR_GEO_GOLD: 'CommonTraitId' = 284297 + PHONE_COLOR_GEO_GREEN: 'CommonTraitId' = 284295 + PHONE_COLOR_GEO_RED: 'CommonTraitId' = 284294 + PHONE_COLOR_GEO_SILVER: 'CommonTraitId' = 284296 + PHONE_COLOR_PAINT_BLACK: 'CommonTraitId' = 284040 + PHONE_COLOR_PAINT_BLUE: 'CommonTraitId' = 284041 + PHONE_COLOR_PAINT_CANARY: 'CommonTraitId' = 284042 + PHONE_COLOR_PAINT_GREEN: 'CommonTraitId' = 284044 + PHONE_COLOR_PAINT_TEAL: 'CommonTraitId' = 284046 + PHONE_COLOR_PAINT_WHITE: 'CommonTraitId' = 284047 + PHONE_COLOR_ROSE_BLACK: 'CommonTraitId' = 284244 + PHONE_COLOR_ROSE_BLUE: 'CommonTraitId' = 284245 + PHONE_COLOR_ROSE_GREEN: 'CommonTraitId' = 284246 + PHONE_COLOR_ROSE_LAVENDER: 'CommonTraitId' = 284247 + PHONE_COLOR_ROSE_METAL_GOLD: 'CommonTraitId' = 284248 + PHONE_COLOR_ROSE_WHITE: 'CommonTraitId' = 284249 + PHONE_COLOR_SWIRL_BLUE: 'CommonTraitId' = 283981 + PHONE_COLOR_SWIRL_GRAY: 'CommonTraitId' = 283985 + PHONE_COLOR_SWIRL_GREEN: 'CommonTraitId' = 283980 + PHONE_COLOR_SWIRL_ORANGE: 'CommonTraitId' = 283983 + PHONE_COLOR_SWIRL_PINK: 'CommonTraitId' = 283982 + PHONE_COLOR_SWIRL_PURPLE: 'CommonTraitId' = 283984 + PHONE_DARK_BLUE: 'CommonTraitId' = 149332 + PHONE_DARK_GREEN: 'CommonTraitId' = 149333 + PHONE_GOLD: 'CommonTraitId' = 149334 + PHONE_HOT_PINK_POLKA: 'CommonTraitId' = 149335 + PHONE_LIGHT_PINK: 'CommonTraitId' = 149336 + PHONE_LIME: 'CommonTraitId' = 149320 + PHONE_MINT_GREEN_STRIPES: 'CommonTraitId' = 149321 + PHONE_ORANGE_POLKA: 'CommonTraitId' = 149322 + PHONE_PURPLE: 'CommonTraitId' = 149323 + PHONE_RED: 'CommonTraitId' = 149324 + PHONE_ROSE_GOLD: 'CommonTraitId' = 149325 + PHONE_SILVER: 'CommonTraitId' = 149326 + PHONE_TURQUOISE_STRIPES: 'CommonTraitId' = 149319 + PHONE_WHITE: 'CommonTraitId' = 149327 + PHYSICALLY_GIFTED: 'CommonTraitId' = 29618 + PIPER: 'CommonTraitId' = 28009 + PLANT_SIM: 'CommonTraitId' = 162668 + PLANT_SIM_CHALLENGE_RECEIVED_STUMP: 'CommonTraitId' = 163733 + PLAYER: 'CommonTraitId' = 26202 + POTION_MASTER: 'CommonTraitId' = 26198 + PRACTICE_MAKES_PERFECT: 'CommonTraitId' = 368744 + PRACTICE_MAKES_PERFECT_BUFF_TRAIT_CREATIVE_TIER_0: 'CommonTraitId' = 371379 + PRACTICE_MAKES_PERFECT_BUFF_TRAIT_CREATIVE_TIER_1: 'CommonTraitId' = 371389 + PRACTICE_MAKES_PERFECT_BUFF_TRAIT_CREATIVE_TIER_2: 'CommonTraitId' = 371390 + PRACTICE_MAKES_PERFECT_BUFF_TRAIT_CREATIVE_TIER_3: 'CommonTraitId' = 371391 + PRACTICE_MAKES_PERFECT_BUFF_TRAIT_CREATIVE_TIER_4: 'CommonTraitId' = 371392 + PRACTICE_MAKES_PERFECT_BUFF_TRAIT_MENTAL_TIER_0: 'CommonTraitId' = 371393 + PRACTICE_MAKES_PERFECT_BUFF_TRAIT_MENTAL_TIER_1: 'CommonTraitId' = 371394 + PRACTICE_MAKES_PERFECT_BUFF_TRAIT_MENTAL_TIER_2: 'CommonTraitId' = 371395 + PRACTICE_MAKES_PERFECT_BUFF_TRAIT_MENTAL_TIER_3: 'CommonTraitId' = 371396 + PRACTICE_MAKES_PERFECT_BUFF_TRAIT_MENTAL_TIER_4: 'CommonTraitId' = 371397 + PRACTICE_MAKES_PERFECT_BUFF_TRAIT_PHYSICAL_TIER_0: 'CommonTraitId' = 371398 + PRACTICE_MAKES_PERFECT_BUFF_TRAIT_PHYSICAL_TIER_1: 'CommonTraitId' = 371399 + PRACTICE_MAKES_PERFECT_BUFF_TRAIT_PHYSICAL_TIER_2: 'CommonTraitId' = 371400 + PRACTICE_MAKES_PERFECT_BUFF_TRAIT_PHYSICAL_TIER_3: 'CommonTraitId' = 371401 + PRACTICE_MAKES_PERFECT_BUFF_TRAIT_PHYSICAL_TIER_4: 'CommonTraitId' = 371402 + PRACTICE_MAKES_PERFECT_BUFF_TRAIT_SOCIAL_TIER_0: 'CommonTraitId' = 371403 + PRACTICE_MAKES_PERFECT_BUFF_TRAIT_SOCIAL_TIER_1: 'CommonTraitId' = 371404 + PRACTICE_MAKES_PERFECT_BUFF_TRAIT_SOCIAL_TIER_2: 'CommonTraitId' = 371405 + PRACTICE_MAKES_PERFECT_BUFF_TRAIT_SOCIAL_TIER_3: 'CommonTraitId' = 371406 + PRACTICE_MAKES_PERFECT_BUFF_TRAIT_SOCIAL_TIER_4: 'CommonTraitId' = 371407 + PRACTICE_MAKES_PERFECT_TRACKING_CREATIVE: 'CommonTraitId' = 370886 + PRACTICE_MAKES_PERFECT_TRACKING_MENTAL: 'CommonTraitId' = 370887 + PRACTICE_MAKES_PERFECT_TRACKING_PHYSICAL: 'CommonTraitId' = 370888 + PRACTICE_MAKES_PERFECT_TRACKING_SOCIAL: 'CommonTraitId' = 370885 + PREGNANCY_OPTIONS_PET_CAN_NOT_REPRODUCE: 'CommonTraitId' = 162564 + PREGNANCY_OPTIONS_PET_CAN_REPRODUCE: 'CommonTraitId' = 162563 + PREPARED_VOYAGER: 'CommonTraitId' = 238653 + PROFESSIONAL_SLACKER: 'CommonTraitId' = 32442 + PROFESSOR_NPC_COURSE_ARTS_A: 'CommonTraitId' = 221851 + PROFESSOR_NPC_COURSE_ARTS_B: 'CommonTraitId' = 224821 + PROFESSOR_NPC_COURSE_ARTS_C: 'CommonTraitId' = 224822 + PROFESSOR_NPC_COURSE_ARTS_D: 'CommonTraitId' = 224823 + PROFESSOR_NPC_COURSE_SCIENCE_A: 'CommonTraitId' = 224863 + PROFESSOR_NPC_COURSE_SCIENCE_B: 'CommonTraitId' = 224864 + PROFESSOR_NPC_COURSE_SCIENCE_C: 'CommonTraitId' = 224865 + PROFESSOR_NPC_COURSE_SCIENCE_D: 'CommonTraitId' = 224866 + PROFESSOR_NPC_IS_ARTS_PROFESSOR: 'CommonTraitId' = 224965 + PROFESSOR_NPC_IS_SCIENCE_PROFESSOR: 'CommonTraitId' = 224966 + PROPER: 'CommonTraitId' = 251970 + PUBERTY_CHANGES_EXPERIENCED_FIRST_TIME: 'CommonTraitId' = 286434 + QUICK_LEARNER: 'CommonTraitId' = 27086 + RANCHER: 'CommonTraitId' = 320988 + RECYCLE_DISCIPLE: 'CommonTraitId' = 232692 + REGAINED_HUMANITY: 'CommonTraitId' = 154825 + RELATABLE: 'CommonTraitId' = 282767 + RELATIONSHIP_EXPECTATIONS_EMOTIONAL_EXCLUSIVITY_NO: 'CommonTraitId' = 361822 + RELATIONSHIP_EXPECTATIONS_EMOTIONAL_EXCLUSIVITY_YES: 'CommonTraitId' = 361821 + RELATIONSHIP_EXPECTATIONS_OPEN_TO_CHANGE_NO: 'CommonTraitId' = 361824 + RELATIONSHIP_EXPECTATIONS_OPEN_TO_CHANGE_YES: 'CommonTraitId' = 361823 + RELATIONSHIP_EXPECTATIONS_PHYSICAL_EXCLUSIVITY_NO: 'CommonTraitId' = 361820 + RELATIONSHIP_EXPECTATIONS_PHYSICAL_EXCLUSIVITY_YES: 'CommonTraitId' = 361819 + RELATIONSHIP_EXPECTATIONS_WOOHOO_EXCLUSIVITY_NO: 'CommonTraitId' = 373826 + RELATIONSHIP_EXPECTATIONS_WOOHOO_EXCLUSIVITY_YES: 'CommonTraitId' = 373825 + REPUTATION_HAS_BEEN_RANK_1_TERRIBLE: 'CommonTraitId' = 194218 + REPUTATION_HAS_BEEN_RANK_2_REALLY_BAD: 'CommonTraitId' = 194219 + REPUTATION_HAS_BEEN_RANK_3_BAD: 'CommonTraitId' = 194220 + REPUTATION_HAS_BEEN_RANK_4_NEUTRAL: 'CommonTraitId' = 194221 + REPUTATION_HAS_BEEN_RANK_5_GOOD: 'CommonTraitId' = 194222 + REPUTATION_HAS_BEEN_RANK_6_REALLY_GOOD: 'CommonTraitId' = 194225 + REPUTATION_HAS_BEEN_RANK_7_PRISTINE: 'CommonTraitId' = 194226 + REPUTATION_RANK_1_TERRIBLE: 'CommonTraitId' = 194206 + REPUTATION_RANK_2_REALLY_BAD: 'CommonTraitId' = 194209 + REPUTATION_RANK_3_BAD: 'CommonTraitId' = 194212 + REPUTATION_RANK_4_NEUTRAL: 'CommonTraitId' = 194214 + REPUTATION_RANK_5_GOOD: 'CommonTraitId' = 194215 + REPUTATION_RANK_6_REALLY_GOOD: 'CommonTraitId' = 194217 + REPUTATION_RANK_7_PRISTINE: 'CommonTraitId' = 194224 + RESEARCH_MACHINE_ACTING: 'CommonTraitId' = 227795 + RESEARCH_MACHINE_CHARISMA: 'CommonTraitId' = 227796 + RESEARCH_MACHINE_COMEDY: 'CommonTraitId' = 227797 + RESEARCH_MACHINE_COOKING: 'CommonTraitId' = 227799 + RESEARCH_MACHINE_FITNESS: 'CommonTraitId' = 227787 + RESEARCH_MACHINE_GARDENING: 'CommonTraitId' = 227800 + RESEARCH_MACHINE_HANDINESS: 'CommonTraitId' = 227788 + RESEARCH_MACHINE_LOGIC: 'CommonTraitId' = 227801 + RESEARCH_MACHINE_PAINTING: 'CommonTraitId' = 227798 + RESEARCH_MACHINE_PHOTOGRAPHY: 'CommonTraitId' = 227802 + RESEARCH_MACHINE_PROGRAMMING: 'CommonTraitId' = 227791 + RESEARCH_MACHINE_RESEARCH: 'CommonTraitId' = 227789 + RESEARCH_MACHINE_ROBOTICS: 'CommonTraitId' = 227792 + RESEARCH_MACHINE_ROCKET_SCIENCE: 'CommonTraitId' = 227793 + RESEARCH_MACHINE_VIDEO_GAMING: 'CommonTraitId' = 227794 + RESEARCH_MACHINE_WRITING: 'CommonTraitId' = 227790 + REWARD_CHILD_CONFIDENCE_HIGH_SELF_ESTEEM: 'CommonTraitId' = 307541 + REWARD_CHILD_CONFIDENCE_LOW_SELF_ESTEEM: 'CommonTraitId' = 307542 + REWARD_HIGH_SCHOOL_TEAM_CHEER_TEAM: 'CommonTraitId' = 277021 + REWARD_HIGH_SCHOOL_TEAM_CHESS_TEAM: 'CommonTraitId' = 277022 + REWARD_HIGH_SCHOOL_TEAM_COMPUTER_TEAM: 'CommonTraitId' = 277024 + REWARD_HIGH_SCHOOL_TEAM_FOOTBALL_TEAM: 'CommonTraitId' = 277023 + REWARD_INFANT_HAPPY: 'CommonTraitId' = 273819 + REWARD_INFANT_TOP_NOTCH: 'CommonTraitId' = 273820 + REWARD_INFANT_UNHAPPY: 'CommonTraitId' = 273818 + RIDER_GAMEPLAY_MOUNTED_REINS_DOWN: 'CommonTraitId' = 348818 + ROBOTICS_ARM_WEARING_BEIGE_WHITE: 'CommonTraitId' = 228954 + ROBOTICS_ARM_WEARING_BLACK_BLUE: 'CommonTraitId' = 228977 + ROBOTICS_ARM_WEARING_BLUE_RED: 'CommonTraitId' = 228978 + ROBOTICS_ARM_WEARING_GRAY_BROWN: 'CommonTraitId' = 228979 + ROBOTICS_ARM_WEARING_GREEN_BROWN: 'CommonTraitId' = 228980 + ROBOTICS_ARM_WEARING_RED_GREEN: 'CommonTraitId' = 228981 + ROBOTICS_ARM_WEARING_WHITE_COPPER: 'CommonTraitId' = 228982 + ROCK_CLIMBING_GEAR_HAS_GEAR: 'CommonTraitId' = 246686 + ROCK_CLIMBING_GEAR_WEARING_GEAR: 'CommonTraitId' = 253624 + ROMANTIC: 'CommonTraitId' = 27454 + ROMANTICALLY_RESERVED: 'CommonTraitId' = 361564 + ROMANTIC_SAGE: 'CommonTraitId' = 377565 + ROOMMATE_NPC_ARCHETYPE_BREAKER: 'CommonTraitId' = 220348 + ROOMMATE_NPC_ARCHETYPE_CHEERLEADER: 'CommonTraitId' = 211764 + ROOMMATE_NPC_ARCHETYPE_CLINGY_SOCIALITE: 'CommonTraitId' = 207908 + ROOMMATE_NPC_ARCHETYPE_COUCH_POTATO: 'CommonTraitId' = 207909 + ROOMMATE_NPC_ARCHETYPE_EMO_LONER: 'CommonTraitId' = 211741 + ROOMMATE_NPC_ARCHETYPE_FIXER: 'CommonTraitId' = 211765 + ROOMMATE_NPC_ARCHETYPE_LOUD_MUSIC: 'CommonTraitId' = 211740 + ROOMMATE_NPC_ARCHETYPE_MEAL_MAKER: 'CommonTraitId' = 207907 + ROOMMATE_NPC_ARCHETYPE_PARTY_PLANNER: 'CommonTraitId' = 211742 + ROOMMATE_NPC_ARCHETYPE_SUPER_NEAT: 'CommonTraitId' = 207906 + ROOMMATE_NPC_INTEREST_ART: 'CommonTraitId' = 211745 + ROOMMATE_NPC_INTEREST_BAKING: 'CommonTraitId' = 211743 + ROOMMATE_NPC_INTEREST_COMPUTERS: 'CommonTraitId' = 207911 + ROOMMATE_NPC_INTEREST_FITNESS: 'CommonTraitId' = 211744 + ROOMMATE_NPC_INTEREST_MUSIC: 'CommonTraitId' = 207910 + ROOMMATE_NPC_QUIRK_ABSENT: 'CommonTraitId' = 211746 + ROOMMATE_NPC_QUIRK_BATHROOM_HOG: 'CommonTraitId' = 207912 + ROOMMATE_NPC_QUIRK_BIG_CLOSET: 'CommonTraitId' = 211747 + ROOMMATE_NPC_QUIRK_LATE_ON_RENT: 'CommonTraitId' = 220349 + ROOMMATE_NPC_QUIRK_PRANKSTER: 'CommonTraitId' = 211748 + ROOMMATE_NPC_QUIRK_PUBLIC_AFFECTION_DISPLAYER: 'CommonTraitId' = 207913 + ROOMMATE_NPC_STANDARD: 'CommonTraitId' = 208150 + SACRED_KNITTING_KNOWLEDGE: 'CommonTraitId' = 240379 + SAVANT: 'CommonTraitId' = 39880 + SCARECROW: 'CommonTraitId' = 187088 + SCENARIO_ALIEN_ADBUCTION_ADULTS: 'CommonTraitId' = 305121 + SCENARIO_COOKOUT: 'CommonTraitId' = 301713 + SCENARIO_EXPLORE_THE_NIGHT: 'CommonTraitId' = 301995 + SCENARIO_EXPLORE_THE_NIGHT_STAYED_UP: 'CommonTraitId' = 302450 + SCENARIO_INHERITANCE_GOAL_GRANDMOTHER_GHOST: 'CommonTraitId' = 343559 + SCENARIO_INHERITANCE_GOAL_MONEY_DONATED: 'CommonTraitId' = 343560 + SCENARIO_INHERITANCE_GOAL_READ_WILL: 'CommonTraitId' = 345458 + SCENARIO_INHERITANCE_GOAL_SIBLINGS_FRIENDS: 'CommonTraitId' = 343561 + SCENARIO_INHERITANCE_GRANDMOTHER: 'CommonTraitId' = 339198 + SCENARIO_IN_THE_MOODLET: 'CommonTraitId' = 296354 + SCENARIO_NEW_IN_TOWN: 'CommonTraitId' = 296645 + SCENARIO_NEW_IN_TOWN_P1_7A_INTRO: 'CommonTraitId' = 297992 + SCENARIO_NEW_IN_TOWN_P1_7B_INTRO: 'CommonTraitId' = 297993 + SCENARIO_NEW_IN_TOWN_P1_7C_INTRO: 'CommonTraitId' = 297994 + SCENARIO_NEW_IN_TOWN_P3A_INTRO: 'CommonTraitId' = 297995 + SCENARIO_NEW_IN_TOWN_P3A_NEW_ACQUAINTANCE_CALLER_FRIEND_GYM: 'CommonTraitId' = 301762 + SCENARIO_NEW_IN_TOWN_P3B_INTRO: 'CommonTraitId' = 297996 + SCENARIO_NEW_IN_TOWN_P3B_NEW_ACQUAINTANCE_CALLER_FRIEND_BAR: 'CommonTraitId' = 301767 + SCENARIO_NEW_IN_TOWN_P3B_NEW_ACQUAINTANCE_CALLER_ROMANCE_BAR: 'CommonTraitId' = 301768 + SCENARIO_NEW_IN_TOWN_P4_RELATIONSHIP_GAIN: 'CommonTraitId' = 297998 + SCENARIO_NEW_IN_TOWN_WOOHOOED: 'CommonTraitId' = 297997 + SCENARIO_NO_SKILLS_NO_PROBLEM: 'CommonTraitId' = 282974 + SCENARIO_PARENTING_PREDICAMENTS_CHILD: 'CommonTraitId' = 299357 + SCENARIO_PARENTING_PREDICAMENTS_FINAL_GRADE_LEONARDO_A: 'CommonTraitId' = 306256 + SCENARIO_PARENTING_PREDICAMENTS_FINAL_GRADE_LEONARDO_F: 'CommonTraitId' = 306257 + SCENARIO_PARENTING_PREDICAMENTS_FINAL_GRADE_SOFIA_A: 'CommonTraitId' = 306254 + SCENARIO_PARENTING_PREDICAMENTS_FINAL_GRADE_SOFIA_F: 'CommonTraitId' = 306255 + SCENARIO_PARENTING_PREDICAMENTS_JENNIFER: 'CommonTraitId' = 298981 + SCENARIO_PARENTING_PREDICAMENTS_LEONARDO: 'CommonTraitId' = 298983 + SCENARIO_PARENTING_PREDICAMENTS_PABLO: 'CommonTraitId' = 298982 + SCENARIO_PARENTING_PREDICAMENTS_PARENT: 'CommonTraitId' = 299358 + SCENARIO_PARENTING_PREDICAMENTS_PRINCIPAL: 'CommonTraitId' = 303367 + SCENARIO_PARENTING_PREDICAMENTS_SOFIA: 'CommonTraitId' = 298984 + SCENARIO_PREMADES_NOT_RIVAL: 'CommonTraitId' = 299962 + SCENARIO_PREMADES_RIVAL: 'CommonTraitId' = 295011 + SCENARIO_PROUD_PARENT: 'CommonTraitId' = 300938 + SCENARIO_STUCK_IN_THEIR_SHADOW_NOVA: 'CommonTraitId' = 298980 + SCENARIO_STUCK_IN_THEIR_SHADOW_P1_COMPLETED_MOTIVES: 'CommonTraitId' = 302191 + SCENARIO_STUCK_IN_THEIR_SHADOW_P1_COMPLETED_PROGRAMMING: 'CommonTraitId' = 302192 + SCENARIO_STUCK_IN_THEIR_SHADOW_P2_RIVAL_PURCHASES: 'CommonTraitId' = 302194 + SCENARIO_STUCK_IN_THEIR_SHADOW_P3_COMPLETED_IMPROVE_WORSEN: 'CommonTraitId' = 302193 + SCENARIO_STUCK_IN_THEIR_SHADOW_P3_DECISION_GOAL_ACTIVE: 'CommonTraitId' = 302202 + SCENARIO_STUCK_IN_THEIR_SHADOW_P3_RIVAL_ARRIVED: 'CommonTraitId' = 302185 + SCENARIO_STUCK_IN_THEIR_SHADOW_P3_RIVAL_INVITED: 'CommonTraitId' = 302198 + SCENARIO_STUCK_IN_THEIR_SHADOW_P3_RIVAL_KICKED: 'CommonTraitId' = 302200 + SCENARIO_STUCK_IN_THEIR_SHADOW_P3_RIVAL_SLEEPOVER: 'CommonTraitId' = 302201 + SCENARIO_STUCK_IN_THEIR_SHADOW_P3_START: 'CommonTraitId' = 302199 + SCENARIO_STUCK_IN_THEIR_SHADOW_P3_VOODOO_OWNER: 'CommonTraitId' = 302340 + SCENARIO_STUCK_IN_THEIR_SHADOW_P4A_ASKED_ABOUT_CAREER: 'CommonTraitId' = 302187 + SCENARIO_STUCK_IN_THEIR_SHADOW_P4A_ASTRONAUT_NO: 'CommonTraitId' = 302254 + SCENARIO_STUCK_IN_THEIR_SHADOW_P4A_ASTRONAUT_YES: 'CommonTraitId' = 302189 + SCENARIO_STUCK_IN_THEIR_SHADOW_P4B_CAN_QUIT: 'CommonTraitId' = 302190 + SCENARIO_STUCK_IN_THEIR_SHADOW_P4B_INDIE_DEVELOPER_ACCEPTED: 'CommonTraitId' = 302197 + SCENARIO_STUCK_IN_THEIR_SHADOW_P4B_INDIE_DEVELOPER_REJECTED: 'CommonTraitId' = 302196 + SCENARIO_STUCK_IN_THEIR_SHADOW_P4B_PROMOTED: 'CommonTraitId' = 303245 + SCENARIO_UNLUCKY_CHEF: 'CommonTraitId' = 282934 + SCHOOL_LOCKER_CLAIMED: 'CommonTraitId' = 277724 + SCIENTIST_EXPERT_REPAIR: 'CommonTraitId' = 109675 + SCOUTING_APTITUDE: 'CommonTraitId' = 187481 + SCUBA_GEAR_DIVE_KNIFE: 'CommonTraitId' = 206056 + SCUBA_GEAR_REBREATHER: 'CommonTraitId' = 206055 + SCUBA_GEAR_SPEAR_FISHING_GUN: 'CommonTraitId' = 206057 + SCUBA_GEAR_TREASURE_TOOL: 'CommonTraitId' = 206054 + SCUBA_GEAR_UNDERWATER_CAMERA: 'CommonTraitId' = 206058 + SEASONED_GAMER: 'CommonTraitId' = 226681 + SELDOM_SLEEPY: 'CommonTraitId' = 183024 + SELF_ABSORBED: 'CommonTraitId' = 199561 + SELF_ASSURED: 'CommonTraitId' = 16824 + SELF_DISCOVERY_MAX_HIDDEN: 'CommonTraitId' = 315699 + SEXUAL_ORIENTATION_WOOHOO_INTERESTS_FEMALE: 'CommonTraitId' = 291675 + SEXUAL_ORIENTATION_WOOHOO_INTERESTS_MALE: 'CommonTraitId' = 291674 + SEXUAL_ORIENTATION_WOOHOO_INTERESTS_NOT_FEMALE: 'CommonTraitId' = 292092 + SEXUAL_ORIENTATION_WOOHOO_INTERESTS_NOT_MALE: 'CommonTraitId' = 292093 + SHAMELESS: 'CommonTraitId' = 26439 + SICKNESS_IMMUNITY: 'CommonTraitId' = 231050 + SIM_PREFERENCE_ACTIVE_DISLIKE: 'CommonTraitId' = 266824 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_ACTING: 'CommonTraitId' = 264140 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_BAKING: 'CommonTraitId' = 264546 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_BOWLING: 'CommonTraitId' = 264142 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_COMEDY: 'CommonTraitId' = 264143 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_COOKING: 'CommonTraitId' = 258758 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_CROSS_STITCH: 'CommonTraitId' = 274573 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_DANCING: 'CommonTraitId' = 264144 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_DEBATING: 'CommonTraitId' = 264159 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_DJ_MIXING: 'CommonTraitId' = 264170 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_EQUESTRIAN_SKILL: 'CommonTraitId' = 339782 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_FISHING: 'CommonTraitId' = 264145 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_FITNESS: 'CommonTraitId' = 258759 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_GARDENING: 'CommonTraitId' = 264146 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_GUITAR: 'CommonTraitId' = 264171 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_HANDINESS: 'CommonTraitId' = 264147 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_KNITTING: 'CommonTraitId' = 274572 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_MEDIA_PRODUCTION: 'CommonTraitId' = 264148 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_MISCHIEF: 'CommonTraitId' = 264149 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_MIXOLOGY: 'CommonTraitId' = 264150 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_NECTAR_MAKING: 'CommonTraitId' = 339781 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_PAINTING: 'CommonTraitId' = 258760 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_PHOTOGRAPHY: 'CommonTraitId' = 264151 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_PIANO: 'CommonTraitId' = 264172 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_PIPE_ORGAN: 'CommonTraitId' = 264173 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_PROGRAMMING: 'CommonTraitId' = 264160 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_ROBOTICS: 'CommonTraitId' = 264162 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_ROCKET_SCIENCE: 'CommonTraitId' = 264164 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_ROCK_CLIMBING: 'CommonTraitId' = 264163 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_ROMANCE_SKILL: 'CommonTraitId' = 395731 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_SINGING: 'CommonTraitId' = 264174 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_SKIING: 'CommonTraitId' = 264165 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_SNOWBOARDING: 'CommonTraitId' = 264166 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_VIDEO_GAMING: 'CommonTraitId' = 258761 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_VIOLIN: 'CommonTraitId' = 258762 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_WELLNESS: 'CommonTraitId' = 269263 + SIM_PREFERENCE_DISLIKES_ACTIVITIES_WRITING: 'CommonTraitId' = 264168 + SIM_PREFERENCE_DISLIKES_CHARACTERISTIC_AMBITIONLESS: 'CommonTraitId' = 306407 + SIM_PREFERENCE_DISLIKES_CHARACTERISTIC_ARGUMENTATIVE: 'CommonTraitId' = 306408 + SIM_PREFERENCE_DISLIKES_CHARACTERISTIC_CEREBRAL: 'CommonTraitId' = 306423 + SIM_PREFERENCE_DISLIKES_CHARACTERISTIC_EGOTISTICAL: 'CommonTraitId' = 306410 + SIM_PREFERENCE_DISLIKES_CHARACTERISTIC_EMOTIONAL_DECISION_MAKER: 'CommonTraitId' = 306411 + SIM_PREFERENCE_DISLIKES_CHARACTERISTIC_FUNNY: 'CommonTraitId' = 306412 + SIM_PREFERENCE_DISLIKES_CHARACTERISTIC_HARD_WORKER: 'CommonTraitId' = 306413 + SIM_PREFERENCE_DISLIKES_CHARACTERISTIC_HIGH_ENERGY: 'CommonTraitId' = 306414 + SIM_PREFERENCE_DISLIKES_CHARACTERISTIC_HOMEBODY: 'CommonTraitId' = 306417 + SIM_PREFERENCE_DISLIKES_CHARACTERISTIC_IDEALIST: 'CommonTraitId' = 306415 + SIM_PREFERENCE_DISLIKES_CHARACTERISTIC_KID_ENTHUSIAST: 'CommonTraitId' = 306416 + SIM_PREFERENCE_DISLIKES_CHARACTERISTIC_MISCHIEVOUS: 'CommonTraitId' = 306418 + SIM_PREFERENCE_DISLIKES_CHARACTERISTIC_NATURE_ENTHUSIAST: 'CommonTraitId' = 306409 + SIM_PREFERENCE_DISLIKES_CHARACTERISTIC_OPTIMIST: 'CommonTraitId' = 306419 + SIM_PREFERENCE_DISLIKES_CHARACTERISTIC_PESSIMIST: 'CommonTraitId' = 306420 + SIM_PREFERENCE_DISLIKES_CHARACTERISTIC_PET_ENTHUSIAST: 'CommonTraitId' = 306421 + SIM_PREFERENCE_DISLIKES_CHARACTERISTIC_ROMANCE_ENTHUSIAST: 'CommonTraitId' = 306422 + SIM_PREFERENCE_DISLIKES_CHARACTERISTIC_SPIRITED: 'CommonTraitId' = 306424 + SIM_PREFERENCE_DISLIKES_COLOR_BLACK: 'CommonTraitId' = 258209 + SIM_PREFERENCE_DISLIKES_COLOR_BLUE: 'CommonTraitId' = 258205 + SIM_PREFERENCE_DISLIKES_COLOR_BROWN: 'CommonTraitId' = 258208 + SIM_PREFERENCE_DISLIKES_COLOR_GRAY: 'CommonTraitId' = 258211 + SIM_PREFERENCE_DISLIKES_COLOR_GREEN: 'CommonTraitId' = 258204 + SIM_PREFERENCE_DISLIKES_COLOR_ORANGE: 'CommonTraitId' = 257860 + SIM_PREFERENCE_DISLIKES_COLOR_PINK: 'CommonTraitId' = 258212 + SIM_PREFERENCE_DISLIKES_COLOR_PURPLE: 'CommonTraitId' = 258207 + SIM_PREFERENCE_DISLIKES_COLOR_RED: 'CommonTraitId' = 257855 + SIM_PREFERENCE_DISLIKES_COLOR_WHITE: 'CommonTraitId' = 258210 + SIM_PREFERENCE_DISLIKES_COLOR_YELLOW: 'CommonTraitId' = 257861 + SIM_PREFERENCE_DISLIKES_COMMUNICATION_AFFECTION: 'CommonTraitId' = 306481 + SIM_PREFERENCE_DISLIKES_COMMUNICATION_ARGUMENTS: 'CommonTraitId' = 306482 + SIM_PREFERENCE_DISLIKES_COMMUNICATION_COMPLAINTS: 'CommonTraitId' = 306483 + SIM_PREFERENCE_DISLIKES_COMMUNICATION_COMPLIMENTS: 'CommonTraitId' = 306484 + SIM_PREFERENCE_DISLIKES_COMMUNICATION_DECEPTION: 'CommonTraitId' = 306485 + SIM_PREFERENCE_DISLIKES_COMMUNICATION_DEEP_THOUGHTS: 'CommonTraitId' = 306486 + SIM_PREFERENCE_DISLIKES_COMMUNICATION_FLIRTATION: 'CommonTraitId' = 306487 + SIM_PREFERENCE_DISLIKES_COMMUNICATION_GOSSIP: 'CommonTraitId' = 306488 + SIM_PREFERENCE_DISLIKES_COMMUNICATION_HOBBIES: 'CommonTraitId' = 306489 + SIM_PREFERENCE_DISLIKES_COMMUNICATION_INTERESTS: 'CommonTraitId' = 306490 + SIM_PREFERENCE_DISLIKES_COMMUNICATION_JOKES: 'CommonTraitId' = 306491 + SIM_PREFERENCE_DISLIKES_COMMUNICATION_MALICIOUS: 'CommonTraitId' = 306492 + SIM_PREFERENCE_DISLIKES_COMMUNICATION_PHYSICAL_INTIMACY: 'CommonTraitId' = 306493 + SIM_PREFERENCE_DISLIKES_COMMUNICATION_POTTY_HUMOR: 'CommonTraitId' = 306494 + SIM_PREFERENCE_DISLIKES_COMMUNICATION_PRANKS: 'CommonTraitId' = 306495 + SIM_PREFERENCE_DISLIKES_COMMUNICATION_SILLY_BEHAVIOR: 'CommonTraitId' = 306496 + SIM_PREFERENCE_DISLIKES_COMMUNICATION_SMALL_TALK: 'CommonTraitId' = 306497 + SIM_PREFERENCE_DISLIKES_COMMUNICATION_STORIES: 'CommonTraitId' = 306498 + SIM_PREFERENCE_DISLIKES_DECOR_ART_DECO: 'CommonTraitId' = 325842 + SIM_PREFERENCE_DISLIKES_DECOR_BASICS: 'CommonTraitId' = 257867 + SIM_PREFERENCE_DISLIKES_DECOR_BOHO: 'CommonTraitId' = 257886 + SIM_PREFERENCE_DISLIKES_DECOR_CONTEMPORARY: 'CommonTraitId' = 257868 + SIM_PREFERENCE_DISLIKES_DECOR_COSMOLUX: 'CommonTraitId' = 257873 + SIM_PREFERENCE_DISLIKES_DECOR_CUTE: 'CommonTraitId' = 325849 + SIM_PREFERENCE_DISLIKES_DECOR_FRENCH_COUNTRY: 'CommonTraitId' = 257875 + SIM_PREFERENCE_DISLIKES_DECOR_GARDEN: 'CommonTraitId' = 257888 + SIM_PREFERENCE_DISLIKES_DECOR_GOTHIC_FARMHOUSE: 'CommonTraitId' = 257876 + SIM_PREFERENCE_DISLIKES_DECOR_INDUSTRIAL: 'CommonTraitId' = 325840 + SIM_PREFERENCE_DISLIKES_DECOR_ISLAND: 'CommonTraitId' = 257887 + SIM_PREFERENCE_DISLIKES_DECOR_LUXE: 'CommonTraitId' = 325846 + SIM_PREFERENCE_DISLIKES_DECOR_MISSION: 'CommonTraitId' = 257877 + SIM_PREFERENCE_DISLIKES_DECOR_MODERN: 'CommonTraitId' = 257878 + SIM_PREFERENCE_DISLIKES_DECOR_PATIO: 'CommonTraitId' = 257869 + SIM_PREFERENCE_DISLIKES_DECOR_QUEEN_ANNE: 'CommonTraitId' = 257879 + SIM_PREFERENCE_DISLIKES_DECOR_SCANDINAVIAN_CONTEMPORARY: 'CommonTraitId' = 258202 + SIM_PREFERENCE_DISLIKES_DECOR_SHABBY: 'CommonTraitId' = 326010 + SIM_PREFERENCE_DISLIKES_DECOR_SUBURBAN_CONTEMPORARY: 'CommonTraitId' = 257884 + SIM_PREFERENCE_DISLIKES_DECOR_TUDOR: 'CommonTraitId' = 257885 + SIM_PREFERENCE_DISLIKES_DECOR_VINTAGE: 'CommonTraitId' = 325844 + SIM_PREFERENCE_DISLIKES_FASHION_BASICS: 'CommonTraitId' = 272669 + SIM_PREFERENCE_DISLIKES_FASHION_BOHO: 'CommonTraitId' = 283148 + SIM_PREFERENCE_DISLIKES_FASHION_COUNTRY: 'CommonTraitId' = 283149 + SIM_PREFERENCE_DISLIKES_FASHION_HIPSTER: 'CommonTraitId' = 283150 + SIM_PREFERENCE_DISLIKES_FASHION_OUTDOORSY: 'CommonTraitId' = 283151 + SIM_PREFERENCE_DISLIKES_FASHION_POLISHED: 'CommonTraitId' = 283152 + SIM_PREFERENCE_DISLIKES_FASHION_PREPPY: 'CommonTraitId' = 283153 + SIM_PREFERENCE_DISLIKES_FASHION_ROCKER: 'CommonTraitId' = 283154 + SIM_PREFERENCE_DISLIKES_FASHION_STREETWEAR: 'CommonTraitId' = 283155 + SIM_PREFERENCE_DISLIKES_MUSIC_ALTERNATIVE: 'CommonTraitId' = 258255 + SIM_PREFERENCE_DISLIKES_MUSIC_AMERICANA: 'CommonTraitId' = 259055 + SIM_PREFERENCE_DISLIKES_MUSIC_BACKYARD: 'CommonTraitId' = 259056 + SIM_PREFERENCE_DISLIKES_MUSIC_BAROQUE: 'CommonTraitId' = 259057 + SIM_PREFERENCE_DISLIKES_MUSIC_BATUU: 'CommonTraitId' = 346277 + SIM_PREFERENCE_DISLIKES_MUSIC_BLUES: 'CommonTraitId' = 258256 + SIM_PREFERENCE_DISLIKES_MUSIC_BRAZILLIAN: 'CommonTraitId' = 346276 + SIM_PREFERENCE_DISLIKES_MUSIC_CLASSICAL: 'CommonTraitId' = 258257 + SIM_PREFERENCE_DISLIKES_MUSIC_COTTAGE_CORE: 'CommonTraitId' = 274593 + SIM_PREFERENCE_DISLIKES_MUSIC_DJ: 'CommonTraitId' = 267538 + SIM_PREFERENCE_DISLIKES_MUSIC_EASY_LISTENING: 'CommonTraitId' = 259058 + SIM_PREFERENCE_DISLIKES_MUSIC_ELECTRONICA: 'CommonTraitId' = 258258 + SIM_PREFERENCE_DISLIKES_MUSIC_FOCUS: 'CommonTraitId' = 259059 + SIM_PREFERENCE_DISLIKES_MUSIC_HIP_HOP: 'CommonTraitId' = 258259 + SIM_PREFERENCE_DISLIKES_MUSIC_ISLAND: 'CommonTraitId' = 259060 + SIM_PREFERENCE_DISLIKES_MUSIC_JAPANESE_FOLK: 'CommonTraitId' = 259075 + SIM_PREFERENCE_DISLIKES_MUSIC_JAZZ: 'CommonTraitId' = 259076 + SIM_PREFERENCE_DISLIKES_MUSIC_KIDS: 'CommonTraitId' = 258260 + SIM_PREFERENCE_DISLIKES_MUSIC_LATIN: 'CommonTraitId' = 259077 + SIM_PREFERENCE_DISLIKES_MUSIC_LATIN_POP: 'CommonTraitId' = 259078 + SIM_PREFERENCE_DISLIKES_MUSIC_LULLABIES: 'CommonTraitId' = 258261 + SIM_PREFERENCE_DISLIKES_MUSIC_METAL: 'CommonTraitId' = 259079 + SIM_PREFERENCE_DISLIKES_MUSIC_NEW_AGE: 'CommonTraitId' = 259080 + SIM_PREFERENCE_DISLIKES_MUSIC_NU_DISCO: 'CommonTraitId' = 259081 + SIM_PREFERENCE_DISLIKES_MUSIC_OLDIES: 'CommonTraitId' = 312568 + SIM_PREFERENCE_DISLIKES_MUSIC_POP: 'CommonTraitId' = 258262 + SIM_PREFERENCE_DISLIKES_MUSIC_RANCH: 'CommonTraitId' = 334822 + SIM_PREFERENCE_DISLIKES_MUSIC_RETRO: 'CommonTraitId' = 258263 + SIM_PREFERENCE_DISLIKES_MUSIC_RNB: 'CommonTraitId' = 343175 + SIM_PREFERENCE_DISLIKES_MUSIC_ROMANCE: 'CommonTraitId' = 258264 + SIM_PREFERENCE_DISLIKES_MUSIC_SINGER_SONGWRITER: 'CommonTraitId' = 259082 + SIM_PREFERENCE_DISLIKES_MUSIC_SPOOKY: 'CommonTraitId' = 258265 + SIM_PREFERENCE_DISLIKES_MUSIC_STRANGE_TUNES: 'CommonTraitId' = 259083 + SIM_PREFERENCE_DISLIKES_MUSIC_SUMMER_STRUT: 'CommonTraitId' = 259084 + SIM_PREFERENCE_DISLIKES_MUSIC_S_POP: 'CommonTraitId' = 258266 + SIM_PREFERENCE_DISLIKES_MUSIC_TWEEN_POP: 'CommonTraitId' = 259085 + SIM_PREFERENCE_DISLIKES_MUSIC_WINTER_HOLIDAY: 'CommonTraitId' = 258267 + SIM_PREFERENCE_DISLIKES_MUSIC_WORLD: 'CommonTraitId' = 259086 + SIM_PREFERENCE_LIKES_ACTIVITIES_ACTING: 'CommonTraitId' = 264175 + SIM_PREFERENCE_LIKES_ACTIVITIES_BAKING: 'CommonTraitId' = 264547 + SIM_PREFERENCE_LIKES_ACTIVITIES_BOWLING: 'CommonTraitId' = 264177 + SIM_PREFERENCE_LIKES_ACTIVITIES_COMEDY: 'CommonTraitId' = 264178 + SIM_PREFERENCE_LIKES_ACTIVITIES_COOKING: 'CommonTraitId' = 258764 + SIM_PREFERENCE_LIKES_ACTIVITIES_CROSS_STITCH: 'CommonTraitId' = 274575 + SIM_PREFERENCE_LIKES_ACTIVITIES_DANCING: 'CommonTraitId' = 264179 + SIM_PREFERENCE_LIKES_ACTIVITIES_DEBATING: 'CommonTraitId' = 264188 + SIM_PREFERENCE_LIKES_ACTIVITIES_DJ_MIXING: 'CommonTraitId' = 264196 + SIM_PREFERENCE_LIKES_ACTIVITIES_EQUESTRIAN_SKILL: 'CommonTraitId' = 339784 + SIM_PREFERENCE_LIKES_ACTIVITIES_FISHING: 'CommonTraitId' = 264180 + SIM_PREFERENCE_LIKES_ACTIVITIES_FITNESS: 'CommonTraitId' = 258765 + SIM_PREFERENCE_LIKES_ACTIVITIES_GARDENING: 'CommonTraitId' = 264181 + SIM_PREFERENCE_LIKES_ACTIVITIES_GUITAR: 'CommonTraitId' = 264197 + SIM_PREFERENCE_LIKES_ACTIVITIES_HANDINESS: 'CommonTraitId' = 264182 + SIM_PREFERENCE_LIKES_ACTIVITIES_KNITTING: 'CommonTraitId' = 274574 + SIM_PREFERENCE_LIKES_ACTIVITIES_MEDIA_PRODUCTION: 'CommonTraitId' = 264183 + SIM_PREFERENCE_LIKES_ACTIVITIES_MISCHIEF: 'CommonTraitId' = 264184 + SIM_PREFERENCE_LIKES_ACTIVITIES_MIXOLOGY: 'CommonTraitId' = 264185 + SIM_PREFERENCE_LIKES_ACTIVITIES_NECTAR_MAKING: 'CommonTraitId' = 339783 + SIM_PREFERENCE_LIKES_ACTIVITIES_PAINTING: 'CommonTraitId' = 258766 + SIM_PREFERENCE_LIKES_ACTIVITIES_PHOTOGRAPHY: 'CommonTraitId' = 264186 + SIM_PREFERENCE_LIKES_ACTIVITIES_PIANO: 'CommonTraitId' = 264198 + SIM_PREFERENCE_LIKES_ACTIVITIES_PIPE_ORGAN: 'CommonTraitId' = 264199 + SIM_PREFERENCE_LIKES_ACTIVITIES_PROGRAMMING: 'CommonTraitId' = 264187 + SIM_PREFERENCE_LIKES_ACTIVITIES_ROBOTICS: 'CommonTraitId' = 264189 + SIM_PREFERENCE_LIKES_ACTIVITIES_ROCKET_SCIENCE: 'CommonTraitId' = 264191 + SIM_PREFERENCE_LIKES_ACTIVITIES_ROCK_CLIMBING: 'CommonTraitId' = 264190 + SIM_PREFERENCE_LIKES_ACTIVITIES_ROMANCE_SKILL: 'CommonTraitId' = 395732 + SIM_PREFERENCE_LIKES_ACTIVITIES_SINGING: 'CommonTraitId' = 264200 + SIM_PREFERENCE_LIKES_ACTIVITIES_SKIING: 'CommonTraitId' = 264192 + SIM_PREFERENCE_LIKES_ACTIVITIES_SNOWBOARDING: 'CommonTraitId' = 264193 + SIM_PREFERENCE_LIKES_ACTIVITIES_VIDEO_GAMING: 'CommonTraitId' = 258767 + SIM_PREFERENCE_LIKES_ACTIVITIES_VIOLIN: 'CommonTraitId' = 258768 + SIM_PREFERENCE_LIKES_ACTIVITIES_WELLNESS: 'CommonTraitId' = 269262 + SIM_PREFERENCE_LIKES_ACTIVITIES_WRITING: 'CommonTraitId' = 264195 + SIM_PREFERENCE_LIKES_CHARACTERISTIC_AMBITIONLESS: 'CommonTraitId' = 305973 + SIM_PREFERENCE_LIKES_CHARACTERISTIC_ARGUMENTATIVE: 'CommonTraitId' = 305945 + SIM_PREFERENCE_LIKES_CHARACTERISTIC_CEREBRAL: 'CommonTraitId' = 305970 + SIM_PREFERENCE_LIKES_CHARACTERISTIC_EGOTISTICAL: 'CommonTraitId' = 305948 + SIM_PREFERENCE_LIKES_CHARACTERISTIC_EMOTIONAL_DECISION_MAKER: 'CommonTraitId' = 305947 + SIM_PREFERENCE_LIKES_CHARACTERISTIC_FUNNY: 'CommonTraitId' = 305969 + SIM_PREFERENCE_LIKES_CHARACTERISTIC_HARD_WORKER: 'CommonTraitId' = 305972 + SIM_PREFERENCE_LIKES_CHARACTERISTIC_HIGH_ENERGY: 'CommonTraitId' = 305964 + SIM_PREFERENCE_LIKES_CHARACTERISTIC_HOME_BODY: 'CommonTraitId' = 305965 + SIM_PREFERENCE_LIKES_CHARACTERISTIC_HOMEBODY: 'CommonTraitId' = SIM_PREFERENCE_LIKES_CHARACTERISTIC_HOME_BODY + SIM_PREFERENCE_LIKES_CHARACTERISTIC_IDEALIST: 'CommonTraitId' = 305946 + SIM_PREFERENCE_LIKES_CHARACTERISTIC_KID_ENTHUSIAST: 'CommonTraitId' = 305960 + SIM_PREFERENCE_LIKES_CHARACTERISTIC_MISCHIEVOUS: 'CommonTraitId' = 305968 + SIM_PREFERENCE_LIKES_CHARACTERISTIC_NATURE_ENTHUSIAST: 'CommonTraitId' = 305967 + SIM_PREFERENCE_LIKES_CHARACTERISTIC_OPTIMIST: 'CommonTraitId' = 305971 + SIM_PREFERENCE_LIKES_CHARACTERISTIC_PESSIMIST: 'CommonTraitId' = 305944 + SIM_PREFERENCE_LIKES_CHARACTERISTIC_PET_ENTHUSIAST: 'CommonTraitId' = 305961 + SIM_PREFERENCE_LIKES_CHARACTERISTIC_ROMANCE_ENTHUSIAST: 'CommonTraitId' = 305949 + SIM_PREFERENCE_LIKES_CHARACTERISTIC_SPIRITED: 'CommonTraitId' = 305966 + SIM_PREFERENCE_LIKES_COLOR_BLACK: 'CommonTraitId' = 258213 + SIM_PREFERENCE_LIKES_COLOR_BLUE: 'CommonTraitId' = 258214 + SIM_PREFERENCE_LIKES_COLOR_BROWN: 'CommonTraitId' = 258215 + SIM_PREFERENCE_LIKES_COLOR_GRAY: 'CommonTraitId' = 258216 + SIM_PREFERENCE_LIKES_COLOR_GREEN: 'CommonTraitId' = 258217 + SIM_PREFERENCE_LIKES_COLOR_ORANGE: 'CommonTraitId' = 257862 + SIM_PREFERENCE_LIKES_COLOR_PINK: 'CommonTraitId' = 258218 + SIM_PREFERENCE_LIKES_COLOR_PURPLE: 'CommonTraitId' = 258219 + SIM_PREFERENCE_LIKES_COLOR_RED: 'CommonTraitId' = 257863 + SIM_PREFERENCE_LIKES_COLOR_WHITE: 'CommonTraitId' = 258220 + SIM_PREFERENCE_LIKES_COLOR_YELLOW: 'CommonTraitId' = 257864 + SIM_PREFERENCE_LIKES_COMMUNICATION_AFFECTION: 'CommonTraitId' = 306474 + SIM_PREFERENCE_LIKES_COMMUNICATION_ARGUMENTS: 'CommonTraitId' = 306473 + SIM_PREFERENCE_LIKES_COMMUNICATION_COMPLAINTS: 'CommonTraitId' = 306479 + SIM_PREFERENCE_LIKES_COMMUNICATION_COMPLIMENTS: 'CommonTraitId' = 306464 + SIM_PREFERENCE_LIKES_COMMUNICATION_DECEPTION: 'CommonTraitId' = 306471 + SIM_PREFERENCE_LIKES_COMMUNICATION_DEEP_THOUGHTS: 'CommonTraitId' = 306465 + SIM_PREFERENCE_LIKES_COMMUNICATION_FLIRTATION: 'CommonTraitId' = 306463 + SIM_PREFERENCE_LIKES_COMMUNICATION_GOSSIP: 'CommonTraitId' = 306478 + SIM_PREFERENCE_LIKES_COMMUNICATION_HOBBIES: 'CommonTraitId' = 306476 + SIM_PREFERENCE_LIKES_COMMUNICATION_INTERESTS: 'CommonTraitId' = 306477 + SIM_PREFERENCE_LIKES_COMMUNICATION_JOKES: 'CommonTraitId' = 306469 + SIM_PREFERENCE_LIKES_COMMUNICATION_MALICIOUS: 'CommonTraitId' = 306472 + SIM_PREFERENCE_LIKES_COMMUNICATION_PHYSICAL_INTIMACY: 'CommonTraitId' = 306462 + SIM_PREFERENCE_LIKES_COMMUNICATION_POTTY_HUMOR: 'CommonTraitId' = 306468 + SIM_PREFERENCE_LIKES_COMMUNICATION_PRANKS: 'CommonTraitId' = 306470 + SIM_PREFERENCE_LIKES_COMMUNICATION_SILLY_BEHAVIOR: 'CommonTraitId' = 306467 + SIM_PREFERENCE_LIKES_COMMUNICATION_SMALL_TALK: 'CommonTraitId' = 306475 + SIM_PREFERENCE_LIKES_COMMUNICATION_STORIES: 'CommonTraitId' = 306466 + SIM_PREFERENCE_LIKES_DECOR_ART_DECO: 'CommonTraitId' = 325843 + SIM_PREFERENCE_LIKES_DECOR_BASICS: 'CommonTraitId' = 257870 + SIM_PREFERENCE_LIKES_DECOR_BOHO: 'CommonTraitId' = 257889 + SIM_PREFERENCE_LIKES_DECOR_CONTEMPORARY: 'CommonTraitId' = 257871 + SIM_PREFERENCE_LIKES_DECOR_COSMOLUX: 'CommonTraitId' = 257890 + SIM_PREFERENCE_LIKES_DECOR_CUTE: 'CommonTraitId' = 325848 + SIM_PREFERENCE_LIKES_DECOR_FRENCH_COUNTRY: 'CommonTraitId' = 257892 + SIM_PREFERENCE_LIKES_DECOR_GARDEN: 'CommonTraitId' = 257893 + SIM_PREFERENCE_LIKES_DECOR_GOTHIC_FARMHOUSE: 'CommonTraitId' = 257894 + SIM_PREFERENCE_LIKES_DECOR_INDUSTRIAL: 'CommonTraitId' = 325841 + SIM_PREFERENCE_LIKES_DECOR_ISLAND: 'CommonTraitId' = 257895 + SIM_PREFERENCE_LIKES_DECOR_LUXE: 'CommonTraitId' = 325847 + SIM_PREFERENCE_LIKES_DECOR_MISSION: 'CommonTraitId' = 257896 + SIM_PREFERENCE_LIKES_DECOR_MODERN: 'CommonTraitId' = 257897 + SIM_PREFERENCE_LIKES_DECOR_PATIO: 'CommonTraitId' = 257872 + SIM_PREFERENCE_LIKES_DECOR_QUEEN_ANNE: 'CommonTraitId' = 257898 + SIM_PREFERENCE_LIKES_DECOR_SCANDINAVIAN_CONTEMPORARY: 'CommonTraitId' = 258203 + SIM_PREFERENCE_LIKES_DECOR_SHABBY: 'CommonTraitId' = 326011 + SIM_PREFERENCE_LIKES_DECOR_SUBURBAN_CONTEMPORARY: 'CommonTraitId' = 257900 + SIM_PREFERENCE_LIKES_DECOR_TUDOR: 'CommonTraitId' = 257901 + SIM_PREFERENCE_LIKES_DECOR_VINTAGE: 'CommonTraitId' = 325845 + SIM_PREFERENCE_LIKES_FASHION_BASICS: 'CommonTraitId' = 272670 + SIM_PREFERENCE_LIKES_FASHION_BOHO: 'CommonTraitId' = 283161 + SIM_PREFERENCE_LIKES_FASHION_COUNTRY: 'CommonTraitId' = 283162 + SIM_PREFERENCE_LIKES_FASHION_HIPSTER: 'CommonTraitId' = 283164 + SIM_PREFERENCE_LIKES_FASHION_OUTDOORSY: 'CommonTraitId' = 283165 + SIM_PREFERENCE_LIKES_FASHION_POLISHED: 'CommonTraitId' = 283166 + SIM_PREFERENCE_LIKES_FASHION_PREPPY: 'CommonTraitId' = 283167 + SIM_PREFERENCE_LIKES_FASHION_ROCKER: 'CommonTraitId' = 283168 + SIM_PREFERENCE_LIKES_FASHION_STREETWEAR: 'CommonTraitId' = 283169 + SIM_PREFERENCE_LIKES_MUSIC_ALTERNATIVE: 'CommonTraitId' = 258269 + SIM_PREFERENCE_LIKES_MUSIC_AMERICANA: 'CommonTraitId' = 259041 + SIM_PREFERENCE_LIKES_MUSIC_BACKYARD: 'CommonTraitId' = 259015 + SIM_PREFERENCE_LIKES_MUSIC_BAROQUE: 'CommonTraitId' = 259017 + SIM_PREFERENCE_LIKES_MUSIC_BATUU: 'CommonTraitId' = 346279 + SIM_PREFERENCE_LIKES_MUSIC_BLUES: 'CommonTraitId' = 258270 + SIM_PREFERENCE_LIKES_MUSIC_BRAZILLIAN: 'CommonTraitId' = 346280 + SIM_PREFERENCE_LIKES_MUSIC_CLASSICAL: 'CommonTraitId' = 258271 + SIM_PREFERENCE_LIKES_MUSIC_COTTAGE_CORE: 'CommonTraitId' = 274594 + SIM_PREFERENCE_LIKES_MUSIC_DJ: 'CommonTraitId' = 267539 + SIM_PREFERENCE_LIKES_MUSIC_EASY_LISTENING: 'CommonTraitId' = 259014 + SIM_PREFERENCE_LIKES_MUSIC_ELECTRONICA: 'CommonTraitId' = 258272 + SIM_PREFERENCE_LIKES_MUSIC_FOCUS: 'CommonTraitId' = 259043 + SIM_PREFERENCE_LIKES_MUSIC_HIP_HOP: 'CommonTraitId' = 258273 + SIM_PREFERENCE_LIKES_MUSIC_ISLAND: 'CommonTraitId' = 259040 + SIM_PREFERENCE_LIKES_MUSIC_JAPANESE_FOLK: 'CommonTraitId' = 259047 + SIM_PREFERENCE_LIKES_MUSIC_JAZZ: 'CommonTraitId' = 259024 + SIM_PREFERENCE_LIKES_MUSIC_KIDS: 'CommonTraitId' = 258274 + SIM_PREFERENCE_LIKES_MUSIC_LATIN: 'CommonTraitId' = 259032 + SIM_PREFERENCE_LIKES_MUSIC_LATIN_POP: 'CommonTraitId' = 259031 + SIM_PREFERENCE_LIKES_MUSIC_LULLABIES: 'CommonTraitId' = 258275 + SIM_PREFERENCE_LIKES_MUSIC_METAL: 'CommonTraitId' = 259045 + SIM_PREFERENCE_LIKES_MUSIC_NEW_AGE: 'CommonTraitId' = 259016 + SIM_PREFERENCE_LIKES_MUSIC_NU_DISCO: 'CommonTraitId' = 259029 + SIM_PREFERENCE_LIKES_MUSIC_OLDIES: 'CommonTraitId' = 312569 + SIM_PREFERENCE_LIKES_MUSIC_POP: 'CommonTraitId' = 258276 + SIM_PREFERENCE_LIKES_MUSIC_RANCH: 'CommonTraitId' = 334823 + SIM_PREFERENCE_LIKES_MUSIC_RETRO: 'CommonTraitId' = 258277 + SIM_PREFERENCE_LIKES_MUSIC_RNB: 'CommonTraitId' = 343176 + SIM_PREFERENCE_LIKES_MUSIC_ROMANCE: 'CommonTraitId' = 258278 + SIM_PREFERENCE_LIKES_MUSIC_SINGER_SONGWRITER: 'CommonTraitId' = 259030 + SIM_PREFERENCE_LIKES_MUSIC_SPOOKY: 'CommonTraitId' = 258279 + SIM_PREFERENCE_LIKES_MUSIC_STRANGE_TUNES: 'CommonTraitId' = 259039 + SIM_PREFERENCE_LIKES_MUSIC_SUMMER_STRUT: 'CommonTraitId' = 259038 + SIM_PREFERENCE_LIKES_MUSIC_S_POP: 'CommonTraitId' = 258280 + SIM_PREFERENCE_LIKES_MUSIC_TWEEN_POP: 'CommonTraitId' = 259026 + SIM_PREFERENCE_LIKES_MUSIC_WINTER_HOLIDAY: 'CommonTraitId' = 258281 + SIM_PREFERENCE_LIKES_MUSIC_WORLD: 'CommonTraitId' = 259028 + SIM_PREFERENCE_NO_OPINION_ACTIVITIES_ACTING: 'CommonTraitId' = 266840 + SIM_PREFERENCE_NO_OPINION_ACTIVITIES_BAKING: 'CommonTraitId' = 266818 + SIM_PREFERENCE_NO_OPINION_ACTIVITIES_BOWLING: 'CommonTraitId' = 266834 + SIM_PREFERENCE_NO_OPINION_ACTIVITIES_COMEDY: 'CommonTraitId' = 266799 + SIM_PREFERENCE_NO_OPINION_ACTIVITIES_COOKING: 'CommonTraitId' = 266800 + SIM_PREFERENCE_NO_OPINION_ACTIVITIES_CROSS_STITCH: 'CommonTraitId' = 274576 + SIM_PREFERENCE_NO_OPINION_ACTIVITIES_DANCING: 'CommonTraitId' = 266823 + SIM_PREFERENCE_NO_OPINION_ACTIVITIES_DEBATING: 'CommonTraitId' = 266843 + SIM_PREFERENCE_NO_OPINION_ACTIVITIES_DJ_MIXING: 'CommonTraitId' = 266833 + SIM_PREFERENCE_NO_OPINION_ACTIVITIES_EQUESTRIAN_SKILL: 'CommonTraitId' = 339800 + SIM_PREFERENCE_NO_OPINION_ACTIVITIES_FISHING: 'CommonTraitId' = 266801 + SIM_PREFERENCE_NO_OPINION_ACTIVITIES_FITNESS: 'CommonTraitId' = 266802 + SIM_PREFERENCE_NO_OPINION_ACTIVITIES_GARDENING: 'CommonTraitId' = 266803 + SIM_PREFERENCE_NO_OPINION_ACTIVITIES_GUITAR: 'CommonTraitId' = 266804 + SIM_PREFERENCE_NO_OPINION_ACTIVITIES_HANDINESS: 'CommonTraitId' = 266805 + SIM_PREFERENCE_NO_OPINION_ACTIVITIES_KNITTING: 'CommonTraitId' = 274577 + SIM_PREFERENCE_NO_OPINION_ACTIVITIES_MEDIA_PRODUCTION: 'CommonTraitId' = 266842 + SIM_PREFERENCE_NO_OPINION_ACTIVITIES_MISCHIEF: 'CommonTraitId' = 266806 + SIM_PREFERENCE_NO_OPINION_ACTIVITIES_MIXOLOGY: 'CommonTraitId' = 266809 + SIM_PREFERENCE_NO_OPINION_ACTIVITIES_NECTAR_MAKING: 'CommonTraitId' = 339799 + SIM_PREFERENCE_NO_OPINION_ACTIVITIES_PAINTING: 'CommonTraitId' = 266810 + SIM_PREFERENCE_NO_OPINION_ACTIVITIES_PHOTOGRAPHY: 'CommonTraitId' = 266819 + SIM_PREFERENCE_NO_OPINION_ACTIVITIES_PIANO: 'CommonTraitId' = 266811 + SIM_PREFERENCE_NO_OPINION_ACTIVITIES_PIPE_ORGAN: 'CommonTraitId' = 266838 + SIM_PREFERENCE_NO_OPINION_ACTIVITIES_PROGRAMMING: 'CommonTraitId' = 266812 + SIM_PREFERENCE_NO_OPINION_ACTIVITIES_ROBOTICS: 'CommonTraitId' = 266844 + SIM_PREFERENCE_NO_OPINION_ACTIVITIES_ROCKET_SCIENCE: 'CommonTraitId' = 266813 + SIM_PREFERENCE_NO_OPINION_ACTIVITIES_ROCK_CLIMBING: 'CommonTraitId' = 266845 + SIM_PREFERENCE_NO_OPINION_ACTIVITIES_SINGING: 'CommonTraitId' = 266839 + SIM_PREFERENCE_NO_OPINION_ACTIVITIES_SKIING: 'CommonTraitId' = 266846 + SIM_PREFERENCE_NO_OPINION_ACTIVITIES_SNOWBOARDING: 'CommonTraitId' = 266847 + SIM_PREFERENCE_NO_OPINION_ACTIVITIES_VIDEO_GAMING: 'CommonTraitId' = 261875 + SIM_PREFERENCE_NO_OPINION_ACTIVITIES_VIOLIN: 'CommonTraitId' = 266815 + SIM_PREFERENCE_NO_OPINION_ACTIVITIES_WELLNESS: 'CommonTraitId' = 266816 + SIM_PREFERENCE_NO_OPINION_ACTIVITIES_WRITING: 'CommonTraitId' = 266817 + SIM_PREFERENCE_NO_OPINION_CHARACTERISTIC_AMBITIONLESS: 'CommonTraitId' = 316490 + SIM_PREFERENCE_NO_OPINION_CHARACTERISTIC_ARGUMENTATIVE: 'CommonTraitId' = 316491 + SIM_PREFERENCE_NO_OPINION_CHARACTERISTIC_CEREBRAL: 'CommonTraitId' = 316517 + SIM_PREFERENCE_NO_OPINION_CHARACTERISTIC_EGOTISTICAL: 'CommonTraitId' = 316518 + SIM_PREFERENCE_NO_OPINION_CHARACTERISTIC_EMOTIONAL_DECISION_MAKER: 'CommonTraitId' = 316519 + SIM_PREFERENCE_NO_OPINION_CHARACTERISTIC_FUNNY: 'CommonTraitId' = 316520 + SIM_PREFERENCE_NO_OPINION_CHARACTERISTIC_HARD_WORKER: 'CommonTraitId' = 316521 + SIM_PREFERENCE_NO_OPINION_CHARACTERISTIC_HIGH_ENERGY: 'CommonTraitId' = 316522 + SIM_PREFERENCE_NO_OPINION_CHARACTERISTIC_HOMEBODY: 'CommonTraitId' = 316523 + SIM_PREFERENCE_NO_OPINION_CHARACTERISTIC_IDEALIST: 'CommonTraitId' = 316524 + SIM_PREFERENCE_NO_OPINION_CHARACTERISTIC_KID_ENTHUSIAST: 'CommonTraitId' = 316492 + SIM_PREFERENCE_NO_OPINION_CHARACTERISTIC_MISCHIEVOUS: 'CommonTraitId' = 316493 + SIM_PREFERENCE_NO_OPINION_CHARACTERISTIC_NATURE_ENTHUSIAST: 'CommonTraitId' = 316494 + SIM_PREFERENCE_NO_OPINION_CHARACTERISTIC_OPTIMIST: 'CommonTraitId' = 316495 + SIM_PREFERENCE_NO_OPINION_CHARACTERISTIC_PESSIMIST: 'CommonTraitId' = 316496 + SIM_PREFERENCE_NO_OPINION_CHARACTERISTIC_PET_ENTHUSIAST: 'CommonTraitId' = 316497 + SIM_PREFERENCE_NO_OPINION_CHARACTERISTIC_ROMANCE_ENTHUSIAST: 'CommonTraitId' = 316515 + SIM_PREFERENCE_NO_OPINION_CHARACTERISTIC_SPIRITED: 'CommonTraitId' = 316516 + SIM_PREFERENCE_NO_OPINION_COMMUNICATION_AFFECTION: 'CommonTraitId' = 312878 + SIM_PREFERENCE_NO_OPINION_COMMUNICATION_ARGUMENTS: 'CommonTraitId' = 312879 + SIM_PREFERENCE_NO_OPINION_COMMUNICATION_COMPLAINTS: 'CommonTraitId' = 312898 + SIM_PREFERENCE_NO_OPINION_COMMUNICATION_COMPLIMENTS: 'CommonTraitId' = 312899 + SIM_PREFERENCE_NO_OPINION_COMMUNICATION_DECEPTION: 'CommonTraitId' = 312900 + SIM_PREFERENCE_NO_OPINION_COMMUNICATION_DEEP_THOUGHTS: 'CommonTraitId' = 312901 + SIM_PREFERENCE_NO_OPINION_COMMUNICATION_FLIRTATION: 'CommonTraitId' = 312902 + SIM_PREFERENCE_NO_OPINION_COMMUNICATION_GOSSIP: 'CommonTraitId' = 312903 + SIM_PREFERENCE_NO_OPINION_COMMUNICATION_HOBBIES: 'CommonTraitId' = 312904 + SIM_PREFERENCE_NO_OPINION_COMMUNICATION_INTERESTS: 'CommonTraitId' = 312905 + SIM_PREFERENCE_NO_OPINION_COMMUNICATION_JOKES: 'CommonTraitId' = 312880 + SIM_PREFERENCE_NO_OPINION_COMMUNICATION_MALICIOUS: 'CommonTraitId' = 312881 + SIM_PREFERENCE_NO_OPINION_COMMUNICATION_PHYSICAL_INTIMACY: 'CommonTraitId' = 312882 + SIM_PREFERENCE_NO_OPINION_COMMUNICATION_POTTY_HUMOR: 'CommonTraitId' = 312883 + SIM_PREFERENCE_NO_OPINION_COMMUNICATION_PRANKS: 'CommonTraitId' = 312894 + SIM_PREFERENCE_NO_OPINION_COMMUNICATION_SILLY_BEHAVIOR: 'CommonTraitId' = 312895 + SIM_PREFERENCE_NO_OPINION_COMMUNICATION_SMALL_TALK: 'CommonTraitId' = 312896 + SIM_PREFERENCE_NO_OPINION_COMMUNICATION_STORIES: 'CommonTraitId' = 312897 + SIM_PREFERENCE_NO_OPINION_FASHION_BASICS: 'CommonTraitId' = 272672 + SIM_PREFERENCE_NO_OPINION_FASHION_BOHO: 'CommonTraitId' = 283171 + SIM_PREFERENCE_NO_OPINION_FASHION_COUNTRY: 'CommonTraitId' = 283172 + SIM_PREFERENCE_NO_OPINION_FASHION_HIPSTER: 'CommonTraitId' = 283173 + SIM_PREFERENCE_NO_OPINION_FASHION_OUTDOORSY: 'CommonTraitId' = 283174 + SIM_PREFERENCE_NO_OPINION_FASHION_POLISHED: 'CommonTraitId' = 283175 + SIM_PREFERENCE_NO_OPINION_FASHION_PREPPY: 'CommonTraitId' = 283184 + SIM_PREFERENCE_NO_OPINION_FASHION_ROCKER: 'CommonTraitId' = 283186 + SIM_PREFERENCE_NO_OPINION_FASHION_STREETWEAR: 'CommonTraitId' = 283188 + SIM_PREFERENCE_NO_OPINION_MUSIC_ALL: 'CommonTraitId' = 266000 + SIM_PREFERENCE_NO_OPINION_VIDEO_GAMING: 'CommonTraitId' = 266814 + SIM_REPUTATION_HOST: 'CommonTraitId' = 195566 + SINCERE: 'CommonTraitId' = 26899 + SKILL_IMAGINATION_1: 'CommonTraitId' = 156834 + SKILL_IMAGINATION_2: 'CommonTraitId' = 156835 + SKILL_IMAGINATION_3: 'CommonTraitId' = 156836 + SKILL_IMAGINATION_4: 'CommonTraitId' = 156837 + SKILL_IMAGINATION_5: 'CommonTraitId' = 156838 + SLEIGHT_OF_HAND: 'CommonTraitId' = 238656 + SLOB: 'CommonTraitId' = 16860 + SMART_HUB_WAKE_UP_ROUTINE_DAILY_AFFIRMATION: 'CommonTraitId' = 203984 + SMART_HUB_WAKE_UP_ROUTINE_DAILY_JOKE: 'CommonTraitId' = 203993 + SMART_HUB_WAKE_UP_ROUTINE_DAILY_NEWS: 'CommonTraitId' = 204005 + SNOB: 'CommonTraitId' = 9620 + SNOOPING_MENACE: 'CommonTraitId' = 350399 + SNOOPING_SAFE_KEEPER: 'CommonTraitId' = 350400 + SNOWBOARDING_GOOFY: 'CommonTraitId' = 252108 + SNOW_SPORTS_SLOPE_INTENSITY_HIGH: 'CommonTraitId' = 249604 + SNOW_SPORTS_SLOPE_INTENSITY_LOW: 'CommonTraitId' = 249602 + SNOW_SPORTS_SLOPE_INTENSITY_MED: 'CommonTraitId' = 249603 + SNOW_SPORTS_SLOPE_SLED_ARMS_UP: 'CommonTraitId' = 253763 + SNOW_SPORTS_SLOPE_SNOWBOARDING_RECORD_VIDEO: 'CommonTraitId' = 250347 + SOCCER_TEAM_PRO_SPORTS: 'CommonTraitId' = 226864 + SOCIALLY_AWKWARD: 'CommonTraitId' = 272629 + SOCIALLY_GIFTED: 'CommonTraitId' = 29622 + SOCIAL_MEDIA_APPLICATION_DISABLE: 'CommonTraitId' = 298846 + SOCIAL_MEDIA_NOTIFICATION_DISABLE: 'CommonTraitId' = 298867 + SPECIAL_NPC_AGNON: 'CommonTraitId' = 239021 + SPECIAL_NPC_GUIDRY: 'CommonTraitId' = 252849 + SPECIAL_NPC_HONDO: 'CommonTraitId' = 238708 + SPECIAL_NPC_IS_FTUE_ROOMMATE: 'CommonTraitId' = 200832 + SPECIAL_NPC_KYLO_REN: 'CommonTraitId' = 238970 + SPECIAL_NPC_REY: 'CommonTraitId' = 238969 + SPECIAL_NPC_SAMMY_GARCIA: 'CommonTraitId' = 376258 + SPECIAL_NPC_THERING_BEAR: 'CommonTraitId' = 369735 + SPECIAL_NPC_VI: 'CommonTraitId' = 239020 + SPECIAL_NP_CS_BABY_ARIEL: 'CommonTraitId' = 202424 + SPECIAL_NP_CS_GAMES_COM_LOVE_INTEREST: 'CommonTraitId' = 123110 + SPECIES_CAT: 'CommonTraitId' = 144685 + SPECIES_DOG: 'CommonTraitId' = 131194 + SPECIES_EXTENDED_LARGE_DOGS: 'CommonTraitId' = 173557 + SPECIES_EXTENDED_SMALL_DOGS: 'CommonTraitId' = 173556 + SPECIES_FOX: 'CommonTraitId' = 259921 + SPECIES_HORSE: 'CommonTraitId' = 308723 + SPECIES_HUMAN: 'CommonTraitId' = 151039 + SPEED_CLEANER: 'CommonTraitId' = 26639 + SPEED_READER: 'CommonTraitId' = 32621 + SPELLCASTER_PRE_MADE: 'CommonTraitId' = 221486 + SPICE_HOUND: 'CommonTraitId' = 146103 + SQUEAMISH: 'CommonTraitId' = 102336 + STEEL_BLADDER: 'CommonTraitId' = 26391 + STORM_CHASER: 'CommonTraitId' = 185795 + STOVES_AND_GRILLS_MASTER: 'CommonTraitId' = 104880 + STRANGER_VILLE_ACTIVELY_POSSESSED_OVERLAY: 'CommonTraitId' = 203163 + STRANGER_VILLE_EXAMINED_LAB_DOOR: 'CommonTraitId' = 201957 + STRANGER_VILLE_HAS_ASKED_AROUND: 'CommonTraitId' = 205285 + STRANGER_VILLE_HAS_DEFEATED_MOTHER_PLANT: 'CommonTraitId' = 206106 + STRANGER_VILLE_HAS_OPENED_DOOR: 'CommonTraitId' = 203165 + STRANGER_VILLE_HAS_SEEN_MOTHER_PLANT: 'CommonTraitId' = 206105 + STRANGER_VILLE_INFECTED: 'CommonTraitId' = 201407 + STRANGER_VILLE_VACCINATED: 'CommonTraitId' = 207348 + STRANGER_VILLE_VETERAN_HERMIT: 'CommonTraitId' = 203142 + STRANGE_TOWN_AGENT: 'CommonTraitId' = 201990 + STRANGE_TOWN_CONSPIRACIST: 'CommonTraitId' = 201991 + STRANGE_TOWN_CURIO_SHOP: 'CommonTraitId' = 204106 + STRANGE_TOWN_MILITARY: 'CommonTraitId' = 201988 + STRANGE_TOWN_NPC_PRE_MADE_SIM: 'CommonTraitId' = 207204 + STRANGE_TOWN_SCIENTIST: 'CommonTraitId' = 201989 + SUMMIT_LOCAL: 'CommonTraitId' = 246366 + SUPER_GREEN_THUMB: 'CommonTraitId' = 35511 + SUPER_PARENT_ROLE_MODEL: 'CommonTraitId' = 165025 + SUPREME_AUTHORITY: 'CommonTraitId' = 238655 + SURPRISE_HOLIDAY_DISCOUNT_DAY: 'CommonTraitId' = 181915 + SURPRISE_HOLIDAY_PIRATE_DAY: 'CommonTraitId' = 184130 + SURVIVALIST: 'CommonTraitId' = 108876 + SURVIVAL_INSTINCT: 'CommonTraitId' = 249731 + TAIL_STYLE_DOWN: 'CommonTraitId' = 128513 + TAIL_STYLE_UP: 'CommonTraitId' = 128514 + TEEN: 'CommonTraitId' = 34317 + TEEN_PRANKS_PRANKSTER: 'CommonTraitId' = 292269 + TEMPERATURE_BURNING_MAN: 'CommonTraitId' = 183508 + TEMPERATURE_COLD_ACCLIMATION: 'CommonTraitId' = 183505 + TEMPERATURE_HEAT_ACCLIMATION: 'CommonTraitId' = 183506 + TEMPERATURE_ICE_MAN: 'CommonTraitId' = 183507 + TEMPORARY_STAY_GUEST_HIDDEN: 'CommonTraitId' = 303296 + TEMPORARY_STAY_HAD_INFANT_INTRO_HIDDEN: 'CommonTraitId' = 324274 + TEMPORARY_STAY_RECENTLY_ARRIVED_HIDDEN: 'CommonTraitId' = 323019 + THE_KNACK: 'CommonTraitId' = 27328 + THE_MASTER: 'CommonTraitId' = 155323 + TODDLER: 'CommonTraitId' = 133125 + TODDLER_ANGELIC: 'CommonTraitId' = 140740 + TODDLER_CHARMER: 'CommonTraitId' = 140742 + TODDLER_CLINGY: 'CommonTraitId' = 140744 + TODDLER_FUSSY: 'CommonTraitId' = 140739 + TODDLER_HAPPY: 'CommonTraitId' = 216611 + TODDLER_INDEPENDENT: 'CommonTraitId' = 140746 + TODDLER_INQUISITIVE: 'CommonTraitId' = 140745 + TODDLER_PERSONALITY_AGGRESSIVE_HIDDEN: 'CommonTraitId' = 306521 + TODDLER_PERSONALITY_AGGRESSIVE_VISIBLE: 'CommonTraitId' = 319855 + TODDLER_PERSONALITY_AUDIO_LOVER_HIDDEN: 'CommonTraitId' = 306525 + TODDLER_PERSONALITY_AUDIO_LOVER_VISIBLE: 'CommonTraitId' = 319856 + TODDLER_PERSONALITY_BOOK_LOVER_HIDDEN: 'CommonTraitId' = 306524 + TODDLER_PERSONALITY_BOOK_LOVER_VISIBLE: 'CommonTraitId' = 319865 + TODDLER_PERSONALITY_DESTRUCTIVE_HIDDEN: 'CommonTraitId' = 306522 + TODDLER_PERSONALITY_DESTRUCTIVE_VISIBLE: 'CommonTraitId' = 319866 + TODDLER_PERSONALITY_EARLY_RISER_HIDDEN: 'CommonTraitId' = 306528 + TODDLER_PERSONALITY_EARLY_RISER_VISIBLE: 'CommonTraitId' = 319867 + TODDLER_PERSONALITY_GOOD_APPETITE_HIDDEN: 'CommonTraitId' = 306531 + TODDLER_PERSONALITY_GOOD_APPETITE_VISIBLE: 'CommonTraitId' = 319868 + TODDLER_PERSONALITY_HATES_BED_TIME_HIDDEN: 'CommonTraitId' = 306527 + TODDLER_PERSONALITY_HATES_BED_TIME_VISIBLE: 'CommonTraitId' = 319869 + TODDLER_PERSONALITY_HATES_CARRY_HIDDEN: 'CommonTraitId' = 306532 + TODDLER_PERSONALITY_HATES_CARRY_VISIBLE: 'CommonTraitId' = 319870 + TODDLER_PERSONALITY_HATES_WAKE_UP_HIDDEN: 'CommonTraitId' = 306533 + TODDLER_PERSONALITY_HATES_WAKE_UP_VISIBLE: 'CommonTraitId' = 319871 + TODDLER_PERSONALITY_HEAVY_SLEEPER_HIDDEN: 'CommonTraitId' = 306534 + TODDLER_PERSONALITY_HEAVY_SLEEPER_VISIBLE: 'CommonTraitId' = 319872 + TODDLER_PERSONALITY_LIGHT_SLEEPER_HIDDEN: 'CommonTraitId' = 306535 + TODDLER_PERSONALITY_LIGHT_SLEEPER_VISIBLE: 'CommonTraitId' = 319857 + TODDLER_PERSONALITY_LOVES_CARRY_HIDDEN: 'CommonTraitId' = 306536 + TODDLER_PERSONALITY_LOVES_CARRY_VISIBLE: 'CommonTraitId' = 319858 + TODDLER_PERSONALITY_LOVES_WAKE_UP_HIDDEN: 'CommonTraitId' = 306537 + TODDLER_PERSONALITY_LOVES_WAKE_UP_VISIBLE: 'CommonTraitId' = 319859 + TODDLER_PERSONALITY_MESSY_EATER_HIDDEN: 'CommonTraitId' = 306523 + TODDLER_PERSONALITY_MESSY_EATER_VISIBLE: 'CommonTraitId' = 319860 + TODDLER_PERSONALITY_PICKY_EATER_HIDDEN: 'CommonTraitId' = 306526 + TODDLER_PERSONALITY_PICKY_EATER_VISIBLE: 'CommonTraitId' = 319861 + TODDLER_PERSONALITY_RUNS_AWAY_HIDDEN: 'CommonTraitId' = 306529 + TODDLER_PERSONALITY_RUNS_AWAY_VISIBLE: 'CommonTraitId' = 319862 + TODDLER_PERSONALITY_SINGER_HIDDEN: 'CommonTraitId' = 306530 + TODDLER_PERSONALITY_SINGER_VISIBLE: 'CommonTraitId' = 319863 + TODDLER_PERSONALITY_WATER_LOVER_HIDDEN: 'CommonTraitId' = 305298 + TODDLER_PERSONALITY_WATER_LOVER_VISIBLE: 'CommonTraitId' = 319864 + TODDLER_SILLY: 'CommonTraitId' = 140743 + TODDLER_TOP_NOTCH: 'CommonTraitId' = 216610 + TODDLER_WILD: 'CommonTraitId' = 140741 + TOP_NOTCH_TODDLER: 'CommonTraitId' = 143156 + TOP_RIDER_HAS_WON_ULTIMATE_CHAMPIONSHIP_HIDDEN: 'CommonTraitId' = 332409 + TOWN_MASCOT: 'CommonTraitId' = 249203 + TRUE_MASTER: 'CommonTraitId' = 155322 + UMBRELLA_PREFERENCE_ADULT_1: 'CommonTraitId' = 185828 + UMBRELLA_PREFERENCE_ADULT_10: 'CommonTraitId' = 185837 + UMBRELLA_PREFERENCE_ADULT_11: 'CommonTraitId' = 185838 + UMBRELLA_PREFERENCE_ADULT_12: 'CommonTraitId' = 185839 + UMBRELLA_PREFERENCE_ADULT_2: 'CommonTraitId' = 185829 + UMBRELLA_PREFERENCE_ADULT_3: 'CommonTraitId' = 185830 + UMBRELLA_PREFERENCE_ADULT_4: 'CommonTraitId' = 185831 + UMBRELLA_PREFERENCE_ADULT_5: 'CommonTraitId' = 185832 + UMBRELLA_PREFERENCE_ADULT_6: 'CommonTraitId' = 185833 + UMBRELLA_PREFERENCE_ADULT_7: 'CommonTraitId' = 185834 + UMBRELLA_PREFERENCE_ADULT_8: 'CommonTraitId' = 185835 + UMBRELLA_PREFERENCE_ADULT_9: 'CommonTraitId' = 185836 + UMBRELLA_PREFERENCE_CHILD_1: 'CommonTraitId' = 185881 + UMBRELLA_PREFERENCE_CHILD_10: 'CommonTraitId' = 185890 + UMBRELLA_PREFERENCE_CHILD_11: 'CommonTraitId' = 185891 + UMBRELLA_PREFERENCE_CHILD_12: 'CommonTraitId' = 185892 + UMBRELLA_PREFERENCE_CHILD_2: 'CommonTraitId' = 185882 + UMBRELLA_PREFERENCE_CHILD_3: 'CommonTraitId' = 185883 + UMBRELLA_PREFERENCE_CHILD_4: 'CommonTraitId' = 185884 + UMBRELLA_PREFERENCE_CHILD_5: 'CommonTraitId' = 185885 + UMBRELLA_PREFERENCE_CHILD_6: 'CommonTraitId' = 185886 + UMBRELLA_PREFERENCE_CHILD_7: 'CommonTraitId' = 185887 + UMBRELLA_PREFERENCE_CHILD_8: 'CommonTraitId' = 185888 + UMBRELLA_PREFERENCE_CHILD_9: 'CommonTraitId' = 185889 + UMBRELLA_USER: 'CommonTraitId' = 188000 + UNFLIRTY: 'CommonTraitId' = 132589 + UNIVERSITY_DEGREE_ART_HISTORY_BA: 'CommonTraitId' = 218112 + UNIVERSITY_DEGREE_ART_HISTORY_BA_HONORS: 'CommonTraitId' = 218113 + UNIVERSITY_DEGREE_ART_HISTORY_BS: 'CommonTraitId' = 218114 + UNIVERSITY_DEGREE_ART_HISTORY_BS_HONORS: 'CommonTraitId' = 218115 + UNIVERSITY_DEGREE_BARTENDER: 'CommonTraitId' = 219807 + UNIVERSITY_DEGREE_BIOLOGY_BA: 'CommonTraitId' = 218117 + UNIVERSITY_DEGREE_BIOLOGY_BA_HONORS: 'CommonTraitId' = 218118 + UNIVERSITY_DEGREE_BIOLOGY_BS: 'CommonTraitId' = 218119 + UNIVERSITY_DEGREE_BIOLOGY_BS_HONORS: 'CommonTraitId' = 218120 + UNIVERSITY_DEGREE_COMMUNICATIONS_BA: 'CommonTraitId' = 218122 + UNIVERSITY_DEGREE_COMMUNICATIONS_BA_HONORS: 'CommonTraitId' = 218123 + UNIVERSITY_DEGREE_COMMUNICATIONS_BS: 'CommonTraitId' = 218124 + UNIVERSITY_DEGREE_COMMUNICATIONS_BS_HONORS: 'CommonTraitId' = 218125 + UNIVERSITY_DEGREE_COMPUTER_SCIENCE_BA: 'CommonTraitId' = 218127 + UNIVERSITY_DEGREE_COMPUTER_SCIENCE_BA_HONORS: 'CommonTraitId' = 218128 + UNIVERSITY_DEGREE_COMPUTER_SCIENCE_BS: 'CommonTraitId' = 218129 + UNIVERSITY_DEGREE_COMPUTER_SCIENCE_BS_HONORS: 'CommonTraitId' = 218130 + UNIVERSITY_DEGREE_CULINARY_ARTS_BA: 'CommonTraitId' = 218165 + UNIVERSITY_DEGREE_CULINARY_ARTS_BA_HONORS: 'CommonTraitId' = 218166 + UNIVERSITY_DEGREE_CULINARY_ARTS_BS: 'CommonTraitId' = 218167 + UNIVERSITY_DEGREE_CULINARY_ARTS_BS_HONORS: 'CommonTraitId' = 218168 + UNIVERSITY_DEGREE_DRAMA_BA: 'CommonTraitId' = 218170 + UNIVERSITY_DEGREE_DRAMA_BA_HONORS: 'CommonTraitId' = 218171 + UNIVERSITY_DEGREE_DRAMA_BS: 'CommonTraitId' = 218172 + UNIVERSITY_DEGREE_DRAMA_BS_HONORS: 'CommonTraitId' = 218173 + UNIVERSITY_DEGREE_ECONOMICS_BA: 'CommonTraitId' = 211507 + UNIVERSITY_DEGREE_ECONOMICS_BA_HONORS: 'CommonTraitId' = 218054 + UNIVERSITY_DEGREE_ECONOMICS_BS: 'CommonTraitId' = 218052 + UNIVERSITY_DEGREE_ECONOMICS_BS_HONORS: 'CommonTraitId' = 218053 + UNIVERSITY_DEGREE_FINE_ART_BA: 'CommonTraitId' = 218176 + UNIVERSITY_DEGREE_FINE_ART_BA_HONORS: 'CommonTraitId' = 218177 + UNIVERSITY_DEGREE_FINE_ART_BS: 'CommonTraitId' = 218178 + UNIVERSITY_DEGREE_FINE_ART_BS_HONORS: 'CommonTraitId' = 218179 + UNIVERSITY_DEGREE_HIGHER_EDUCATION: 'CommonTraitId' = 227102 + UNIVERSITY_DEGREE_HISTORY_BA: 'CommonTraitId' = 218182 + UNIVERSITY_DEGREE_HISTORY_BA_HONORS: 'CommonTraitId' = 218183 + UNIVERSITY_DEGREE_HISTORY_BS: 'CommonTraitId' = 218184 + UNIVERSITY_DEGREE_HISTORY_BS_HONORS: 'CommonTraitId' = 218185 + UNIVERSITY_DEGREE_LANGUAGE_AND_LITERATURE_BA: 'CommonTraitId' = 218187 + UNIVERSITY_DEGREE_LANGUAGE_AND_LITERATURE_BA_HONORS: 'CommonTraitId' = 218188 + UNIVERSITY_DEGREE_LANGUAGE_AND_LITERATURE_BS: 'CommonTraitId' = 218189 + UNIVERSITY_DEGREE_LANGUAGE_AND_LITERATURE_BS_HONORS: 'CommonTraitId' = 218190 + UNIVERSITY_DEGREE_PHYSICS_BA: 'CommonTraitId' = 218192 + UNIVERSITY_DEGREE_PHYSICS_BA_HONORS: 'CommonTraitId' = 218193 + UNIVERSITY_DEGREE_PHYSICS_BS: 'CommonTraitId' = 218194 + UNIVERSITY_DEGREE_PHYSICS_BS_HONORS: 'CommonTraitId' = 218195 + UNIVERSITY_DEGREE_PSYCHOLOGY_BA: 'CommonTraitId' = 218198 + UNIVERSITY_DEGREE_PSYCHOLOGY_BA_HONORS: 'CommonTraitId' = 218199 + UNIVERSITY_DEGREE_PSYCHOLOGY_BS: 'CommonTraitId' = 218200 + UNIVERSITY_DEGREE_PSYCHOLOGY_BS_HONORS: 'CommonTraitId' = 218201 + UNIVERSITY_DEGREE_VILLAINY_BA: 'CommonTraitId' = 218203 + UNIVERSITY_DEGREE_VILLAINY_BA_HONORS: 'CommonTraitId' = 218204 + UNIVERSITY_DEGREE_VILLAINY_BS: 'CommonTraitId' = 218205 + UNIVERSITY_DEGREE_VILLAINY_BS_HONORS: 'CommonTraitId' = 218206 + UNIVERSITY_ENROLLMENT_HAS_SEEN_ENROLLMENT_INFO: 'CommonTraitId' = 230113 + UNIVERSITY_HAS_EARNED_DEGREE_ART_HISTORY: 'CommonTraitId' = 230321 + UNIVERSITY_HAS_EARNED_DEGREE_BIOLOGY: 'CommonTraitId' = 230322 + UNIVERSITY_HAS_EARNED_DEGREE_COMMUNICATIONS: 'CommonTraitId' = 230324 + UNIVERSITY_HAS_EARNED_DEGREE_COMPUTER_SCIENCE: 'CommonTraitId' = 230325 + UNIVERSITY_HAS_EARNED_DEGREE_CULINARY_ARTS: 'CommonTraitId' = 230326 + UNIVERSITY_HAS_EARNED_DEGREE_DRAMA: 'CommonTraitId' = 230328 + UNIVERSITY_HAS_EARNED_DEGREE_ECONOMICS: 'CommonTraitId' = 230329 + UNIVERSITY_HAS_EARNED_DEGREE_FINE_ART: 'CommonTraitId' = 230330 + UNIVERSITY_HAS_EARNED_DEGREE_HISTORY: 'CommonTraitId' = 230331 + UNIVERSITY_HAS_EARNED_DEGREE_LANGUAGE_AND_LITERATURE: 'CommonTraitId' = 230332 + UNIVERSITY_HAS_EARNED_DEGREE_PHYSICS: 'CommonTraitId' = 230333 + UNIVERSITY_HAS_EARNED_DEGREE_PSYCHOLOGY: 'CommonTraitId' = 230334 + UNIVERSITY_HAS_EARNED_DEGREE_TYPE_ARTS: 'CommonTraitId' = 230337 + UNIVERSITY_HAS_EARNED_DEGREE_TYPE_HONORS: 'CommonTraitId' = 230336 + UNIVERSITY_HAS_EARNED_DEGREE_VILLAINY: 'CommonTraitId' = 230335 + UNIVERSITY_STUDENT: 'CommonTraitId' = 228185 + UNSTOPPABLE_FAME: 'CommonTraitId' = 192900 + UNTROUBLED: 'CommonTraitId' = 283156 + VALUED_CUSTOMER: 'CommonTraitId' = 27947 + VEGETARIAN: 'CommonTraitId' = 132627 + VILLAGER_HELP_CRITTER_TENDER_GOT_MUSHROOM_MASH_ONCE: 'CommonTraitId' = 267609 + VILLAGER_HELP_ON_QUEST_AGATHA_CRUMPLEBOTTOM: 'CommonTraitId' = 267179 + VILLAGER_HELP_ON_QUEST_AGATHA_CRUMPLEBOTTOM_2: 'CommonTraitId' = 268881 + VILLAGER_HELP_ON_QUEST_AGNES_CRUMPLEBOTTOM: 'CommonTraitId' = 268149 + VILLAGER_HELP_ON_QUEST_AGNES_CRUMPLEBOTTOM_2: 'CommonTraitId' = 268792 + VILLAGER_HELP_ON_QUEST_CRITTER_TENDER: 'CommonTraitId' = 267515 + VILLAGER_HELP_ON_QUEST_FOOD_SHORT: 'CommonTraitId' = 266038 + VILLAGER_HELP_ON_QUEST_GARDEN_SHORT: 'CommonTraitId' = 265857 + VILLAGER_HELP_ON_QUEST_GROCERY_DELIVERY: 'CommonTraitId' = 267385 + VILLAGER_HELP_ON_QUEST_GROCERY_OWNER: 'CommonTraitId' = 267229 + VILLAGER_HELP_ON_QUEST_LIVESTOCK_LONG: 'CommonTraitId' = 265644 + VILLAGER_HELP_ON_QUEST_LIVESTOCK_SHORT: 'CommonTraitId' = 265676 + VILLAGER_HELP_ON_QUEST_MAYOR: 'CommonTraitId' = 267405 + VILLAGER_HELP_ON_QUEST_PUB_OWNER: 'CommonTraitId' = 267454 + VILLAGER_HELP_ON_QUEST_SOCIAL_MEDIUM: 'CommonTraitId' = 268151 + VILLAGER_HELP_ON_QUEST_SOCIAL_SHORT: 'CommonTraitId' = 268150 + VILLAGER_HELP_ON_QUEST_WILD_ANIMAL_FOOD_LONG: 'CommonTraitId' = 266229 + VILLAGER_HELP_ON_QUEST_WILD_ANIMAL_SHORT: 'CommonTraitId' = 265875 + WALK_BY_WITCH_BROOM: 'CommonTraitId' = 218416 + WALK_STYLE_CREEPY: 'CommonTraitId' = 155564 + WALK_STYLE_DEFAULT: 'CommonTraitId' = 9094 + WALK_STYLE_ENERGETIC: 'CommonTraitId' = 98760 + WALK_STYLE_FEMININE: 'CommonTraitId' = 29593 + WALK_STYLE_FOX: 'CommonTraitId' = 261220 + WALK_STYLE_GOOFY: 'CommonTraitId' = 29600 + WALK_STYLE_PERKY: 'CommonTraitId' = 9095 + WALK_STYLE_SLEEPY: 'CommonTraitId' = 98757 + WALK_STYLE_SNOOTY: 'CommonTraitId' = 9096 + WALK_STYLE_SWAGGER: 'CommonTraitId' = 9293 + WALK_STYLE_TOUGH: 'CommonTraitId' = 29594 + WATERPROOF: 'CommonTraitId' = 185794 + WEB_MASTER: 'CommonTraitId' = 27772 + WEDDING_TRADITION_BOUQUET_TOSS: 'CommonTraitId' = 276253 + WEDDING_TRADITION_COUPLE_CAKE_CUT: 'CommonTraitId' = 276251 + WEDDING_TRADITION_FIRST_DANCE: 'CommonTraitId' = 276252 + WEDDING_TRADITION_GROUP_DANCE: 'CommonTraitId' = 280624 + WEDDING_TRADITION_HAD_BOUQUET: 'CommonTraitId' = 276255 + WEDDING_TRADITION_HAD_WEDDING_CAKE: 'CommonTraitId' = 276254 + WEDDING_TRADITION_RING_EXCHANGE: 'CommonTraitId' = 276249 + WEDDING_TRADITION_SPOUSAL_KISS: 'CommonTraitId' = 276248 + WEDDING_TRADITION_WALKED_DOWN_AISLE: 'CommonTraitId' = 276250 + WEDDING_WORLD_NPC_ARNESSA_THEBE: 'CommonTraitId' = 278728 + WEDDING_WORLD_NPC_CAMILLE_SOTO: 'CommonTraitId' = 278733 + WEDDING_WORLD_NPC_DOMINIQUE_SOTO: 'CommonTraitId' = 278734 + WEDDING_WORLD_NPC_FAIZ_JALEEL: 'CommonTraitId' = 278735 + WEDDING_WORLD_NPC_GRETA_LAURENT: 'CommonTraitId' = 278725 + WEDDING_WORLD_NPC_HECTOR_LAURENT: 'CommonTraitId' = 278724 + WEDDING_WORLD_NPC_HILARY_LAURENT: 'CommonTraitId' = 278727 + WEDDING_WORLD_NPC_JACE_LAURENT: 'CommonTraitId' = 278726 + WEDDING_WORLD_NPC_LUCIA_MARKOVIC: 'CommonTraitId' = 278730 + WEDDING_WORLD_NPC_MATEO_MARKOVIC: 'CommonTraitId' = 278729 + WEDDING_WORLD_NPC_TOMI_MARKOVIC: 'CommonTraitId' = 278731 + WELLNESS_CALMING_AURA: 'CommonTraitId' = 270903 + WELLNESS_CLEAR_PERSPECTIVE: 'CommonTraitId' = 270902 + WELLNESS_MOMENT_OF_CLARITY: 'CommonTraitId' = 272283 + WELLNESS_SELF_CARE_EXPERTISE: 'CommonTraitId' = 270904 + WELLNESS_SPA_MEMBERSHIP: 'CommonTraitId' = 270900 + WEREWOLF_BOOK_READ_PETER_BARKER_1: 'CommonTraitId' = 298879 + WEREWOLF_BOOK_READ_PETER_BARKER_2: 'CommonTraitId' = 298880 + WEREWOLF_BOOK_READ_PETER_BARKER_3: 'CommonTraitId' = 298889 + WEREWOLF_BOOK_READ_PETER_BARKER_4: 'CommonTraitId' = 298890 + WEREWOLF_BOOK_READ_SECRET_1: 'CommonTraitId' = 298882 + WEREWOLF_BOOK_READ_SECRET_2: 'CommonTraitId' = 298883 + WEREWOLF_BOOK_READ_SECRET_3: 'CommonTraitId' = 298884 + WEREWOLF_BOOK_READ_SECRET_4: 'CommonTraitId' = 298885 + WEREWOLF_BOOK_READ_VULFGANG_1: 'CommonTraitId' = 298891 + WEREWOLF_BOOK_READ_VULFGANG_2: 'CommonTraitId' = 298892 + WEREWOLF_BOOK_READ_VULFGANG_3: 'CommonTraitId' = 298893 + WEREWOLF_BOOK_READ_VULFGANG_4: 'CommonTraitId' = 298881 + WEREWOLF_INTEREST_DONT_WANT: 'CommonTraitId' = 293565 + WEREWOLF_INTEREST_WANT: 'CommonTraitId' = 293564 + WEREWOLF_PACK_A: 'CommonTraitId' = 284944 + WEREWOLF_PACK_ALLIANCE_FEUD_ALLIANCE: 'CommonTraitId' = 289716 + WEREWOLF_PACK_ALLIANCE_FEUD_FEUD: 'CommonTraitId' = 289723 + WEREWOLF_PACK_ALLIANCE_FEUD_NEUTRAL: 'CommonTraitId' = 289741 + WEREWOLF_PACK_A_LEADER: 'CommonTraitId' = 284985 + WEREWOLF_PACK_A_MEMBER: 'CommonTraitId' = 285566 + WEREWOLF_PACK_B: 'CommonTraitId' = 284945 + WEREWOLF_PACK_B_LEADER: 'CommonTraitId' = 284986 + WEREWOLF_PACK_B_MEMBER: 'CommonTraitId' = 285567 + WEREWOLF_PACK_DISCIPLINE_PROBATION: 'CommonTraitId' = 286781 + WEREWOLF_PACK_DISCIPLINE_REPORT_TO_LEADER: 'CommonTraitId' = 286782 + WEREWOLF_PACK_DISCIPLINE_WARNING: 'CommonTraitId' = 297602 + WEREWOLF_PACK_FRIEND_A: 'CommonTraitId' = 286986 + WEREWOLF_PACK_FRIEND_A_REPORT_TO_LEADER: 'CommonTraitId' = 287050 + WEREWOLF_PACK_FRIEND_B: 'CommonTraitId' = 286987 + WEREWOLF_PACK_FRIEND_B_REPORT_TO_LEADER: 'CommonTraitId' = 287051 + WEREWOLF_PACK_LEADER_HAS_NOT_REDECORATED: 'CommonTraitId' = 293513 + WEREWOLF_PACK_REPORT_TO_LEADER_OTHER: 'CommonTraitId' = 290934 + WISE: 'CommonTraitId' = 341151 + WITH_NANNY: 'CommonTraitId' = 105483 + WOLF_TOWN_ADVENTURE_KNOWS_SCULPTURE_SECRET: 'CommonTraitId' = 288791 + WOLF_TOWN_NPC_CELENE_LOPEZ: 'CommonTraitId' = 288301 + WOLF_TOWN_NPC_GREG: 'CommonTraitId' = 288294 + WOLF_TOWN_NPC_JACOB_VOLKOV: 'CommonTraitId' = 288299 + WOLF_TOWN_NPC_KRISTOPHER_VOLKOV: 'CommonTraitId' = 288297 + WOLF_TOWN_NPC_LILY_ZHU: 'CommonTraitId' = 288303 + WOLF_TOWN_NPC_LOU_HOWELL: 'CommonTraitId' = 288302 + WOLF_TOWN_NPC_RORY_OAKLOW: 'CommonTraitId' = 288298 + WOLF_TOWN_NPC_WOLFGANG_WILDER: 'CommonTraitId' = 288300 + WOLF_TOWN_PORTAL_UNLOCK_PORTAL_MINE: 'CommonTraitId' = 288386 + WOLF_TOWN_PORTAL_UNLOCK_PORTAL_SEWER: 'CommonTraitId' = 288387 + WOLF_TOWN_PORTAL_UNLOCK_PORTAL_SEWER_MINE: 'CommonTraitId' = 288388 + WORLDLY_KNOWLEDGE: 'CommonTraitId' = 249732 + WORLD_RENOWNED_ACTOR: 'CommonTraitId' = 193531 + YOUNG_ADULT: 'CommonTraitId' = 34318 diff --git a/Scripts/s4ap/sims4communitylib/enums/types/__init__.py b/Scripts/s4ap/sims4communitylib/enums/types/__init__.py new file mode 100644 index 0000000..3251898 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/types/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" \ No newline at end of file diff --git a/Scripts/s4ap/sims4communitylib/enums/types/component_types.py b/Scripts/s4ap/sims4communitylib/enums/types/component_types.py new file mode 100644 index 0000000..8fb1c8e --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/types/component_types.py @@ -0,0 +1,94 @@ +""" +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 +""" +from typing import Any + + +class CommonComponentType: + """Various component types of vanilla Sims 4 + + Components are essentially just Tuning files in package files. + + """ + def _get_component_type(*args) -> Any: + try: + import objects.components.types as component_types + return getattr(component_types, args[0]) + except KeyError: + return args[0] + + ANIMATION: 'CommonComponentType' = _get_component_type('ANIMATION_COMPONENT') + AUDIO: 'CommonComponentType' = _get_component_type('AUDIO_COMPONENT') + EFFECTS: 'CommonComponentType' = _get_component_type('EFFECTS_COMPONENT') + FOOTPRINT: 'CommonComponentType' = _get_component_type('FOOTPRINT_COMPONENT') + GAMEPLAY: 'CommonComponentType' = _get_component_type('GAMEPLAY_COMPONENT') + LIVE_DRAG: 'CommonComponentType' = _get_component_type('LIVE_DRAG_COMPONENT') + POSITION: 'CommonComponentType' = _get_component_type('POSITION_COMPONENT') + RENDER: 'CommonComponentType' = _get_component_type('RENDER_COMPONENT') + ROUTING: 'CommonComponentType' = _get_component_type('ROUTING_COMPONENT') + SIM: 'CommonComponentType' = _get_component_type('SIM_COMPONENT') + VIDEO: 'CommonComponentType' = _get_component_type('VIDEO_COMPONENT') + AFFORDANCE_TUNING: 'CommonComponentType' = _get_component_type('AFFORDANCE_TUNING_COMPONENT') + ANIMATION_OVERLAY: 'CommonComponentType' = _get_component_type('ANIMATION_OVERLAY_COMPONENT') + AUTONOMY: 'CommonComponentType' = _get_component_type('AUTONOMY_COMPONENT') + AWARENESS: 'CommonComponentType' = _get_component_type('AWARENESS_COMPONENT') + BUFF: 'CommonComponentType' = _get_component_type('BUFF_COMPONENT') + CAMERA_VIEW: 'CommonComponentType' = _get_component_type('CAMERA_VIEW_COMPONENT') + CANVAS: 'CommonComponentType' = _get_component_type('CANVAS_COMPONENT') + CARRYABLE: 'CommonComponentType' = _get_component_type('CARRYABLE_COMPONENT') + CARRYING: 'CommonComponentType' = _get_component_type('CARRYING_COMPONENT') + CHANNEL: 'CommonComponentType' = _get_component_type('CHANNEL_COMPONENT') + CENSOR_GRID: 'CommonComponentType' = _get_component_type('CENSOR_GRID_COMPONENT') + COLLECTABLE: 'CommonComponentType' = _get_component_type('COLLECTABLE_COMPONENT') + CONSUMABLE: 'CommonComponentType' = _get_component_type('CONSUMABLE_COMPONENT') + CRAFTING: 'CommonComponentType' = _get_component_type('CRAFTING_COMPONENT') + CRAFTING_STATION: 'CommonComponentType' = _get_component_type('CRAFTING_STATION_COMPONENT') + CURFEW: 'CommonComponentType' = _get_component_type('CURFEW_COMPONENT') + ENSEMBLE: 'CommonComponentType' = _get_component_type('ENSEMBLE_COMPONENT') + ENVIRONMENT_SCORE: 'CommonComponentType' = _get_component_type('ENVIRONMENT_SCORE_COMPONENT') + FLOWING_PUDDLE: 'CommonComponentType' = _get_component_type('FLOWING_PUDDLE_COMPONENT') + FOCUS: 'CommonComponentType' = _get_component_type('FOCUS_COMPONENT') + GAME: 'CommonComponentType' = _get_component_type('GAME_COMPONENT') + GARDENING: 'CommonComponentType' = _get_component_type('GARDENING_COMPONENT') + IDLE: 'CommonComponentType' = _get_component_type('IDLE_COMPONENT') + INVENTORY: 'CommonComponentType' = _get_component_type('INVENTORY_COMPONENT') + INVENTORY_ITEM: 'CommonComponentType' = _get_component_type('INVENTORY_ITEM_COMPONENT') + LIGHTING: 'CommonComponentType' = _get_component_type('LIGHTING_COMPONENT') + LINE_OF_SIGHT: 'CommonComponentType' = _get_component_type('LINE_OF_SIGHT_COMPONENT') + LINKED_OBJECT: 'CommonComponentType' = _get_component_type('LINKED_OBJECT_COMPONENT') + LIVE_DRAG_TARGET: 'CommonComponentType' = _get_component_type('LIVE_DRAG_TARGET_COMPONENT') + MANNEQUIN: 'CommonComponentType' = _get_component_type('MANNEQUIN_COMPONENT') + NAME: 'CommonComponentType' = _get_component_type('NAME_COMPONENT') + NEW_OBJECT: 'CommonComponentType' = _get_component_type('NEW_OBJECT_COMPONENT') + OBJECT_AGE: 'CommonComponentType' = _get_component_type('OBJECT_AGE_COMPONENT') + OBJECT_RELATIONSHIP: 'CommonComponentType' = _get_component_type('OBJECT_RELATIONSHIP_COMPONENT') + OBJECT_ROUTING: 'CommonComponentType' = _get_component_type('OBJECT_ROUTING_COMPONENT') + OBJECT_TELEPORTATION: 'CommonComponentType' = _get_component_type('OBJECT_TELEPORTATION_COMPONENT') + OWNABLE: 'CommonComponentType' = _get_component_type('OWNABLE_COMPONENT') + PARENT_TO_SIM_HEAD: 'CommonComponentType' = _get_component_type('PARENT_TO_SIM_HEAD_COMPONENT') + PORTAL: 'CommonComponentType' = _get_component_type('PORTAL_COMPONENT') + PORTAL_ANIMATION: 'CommonComponentType' = _get_component_type('PORTAL_ANIMATION_COMPONENT') + PORTAL_LOCKING: 'CommonComponentType' = _get_component_type('PORTAL_LOCKING_COMPONENT') + PROXIMITY: 'CommonComponentType' = _get_component_type('PROXIMITY_COMPONENT') + SEASON_AWARE: 'CommonComponentType' = _get_component_type('SEASON_AWARE_COMPONENT') + SLOT: 'CommonComponentType' = _get_component_type('SLOT_COMPONENT') + SPAWN_POINT: 'CommonComponentType' = _get_component_type('SPAWN_POINT_COMPONENT') + SPAWNER: 'CommonComponentType' = _get_component_type('SPAWNER_COMPONENT') + STATE: 'CommonComponentType' = _get_component_type('STATE_COMPONENT') + STATISTIC: 'CommonComponentType' = _get_component_type('STATISTIC_COMPONENT') + STORED_OBJECT_INFO: 'CommonComponentType' = _get_component_type('STORED_OBJECT_INFO_COMPONENT') + STORED_SIM_INFO: 'CommonComponentType' = _get_component_type('STORED_SIM_INFO_COMPONENT') + TIME_OF_DAY: 'CommonComponentType' = _get_component_type('TIME_OF_DAY_COMPONENT') + TOOLTIP: 'CommonComponentType' = _get_component_type('TOOLTIP_COMPONENT') + TOPIC: 'CommonComponentType' = _get_component_type('TOPIC_COMPONENT') + FISHING_LOCATION: 'CommonComponentType' = _get_component_type('FISHING_LOCATION_COMPONENT') + WAITING_LINE: 'CommonComponentType' = _get_component_type('WAITING_LINE_COMPONENT') + DISPLAY: 'CommonComponentType' = _get_component_type('DISPLAY_COMPONENT') + RETAIL: 'CommonComponentType' = _get_component_type('RETAIL_COMPONENT') + STOLEN: 'CommonComponentType' = _get_component_type('STOLEN_COMPONENT') + EXAMPLE: 'CommonComponentType' = _get_component_type('EXAMPLE_COMPONENT') + WEATHER_AWARE: 'CommonComponentType' = _get_component_type('WEATHER_AWARE_COMPONENT') diff --git a/Scripts/s4ap/sims4communitylib/enums/venues_enum.py b/Scripts/s4ap/sims4communitylib/enums/venues_enum.py new file mode 100644 index 0000000..c96836f --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/venues_enum.py @@ -0,0 +1,56 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonVenueType(CommonInt): + """Identifiers for vanilla venue types. + + """ + INVALID: 'CommonVenueType' = 0 + ACTING_STUDIO: 'CommonVenueType' = 190058 + ARTS_CENTER: 'CommonVenueType' = 144206 + BAR: 'CommonVenueType' = 16869 + CAFE: 'CommonVenueType' = 122247 + CHALET_GARDENS: 'CommonVenueType' = 125223 + CLUB: 'CommonVenueType' = 16870 + DOCTOR_CLINIC: 'CommonVenueType' = 110576 + FOREST_PARK: 'CommonVenueType' = 107453 + GENERIC: 'CommonVenueType' = 9279 + GYM: 'CommonVenueType' = 16873 + HERMIT: 'CommonVenueType' = 105591 + HIDDEN_ALIEN_WORLD: 'CommonVenueType' = 111611 + HIDDEN_CAVE: 'CommonVenueType' = 98133 + HIDDEN_GLADE: 'CommonVenueType' = 98132 + KARAOKE: 'CommonVenueType' = 137844 + LIBRARY: 'CommonVenueType' = 16874 + LOUNGE: 'CommonVenueType' = 16875 + MUSEUM: 'CommonVenueType' = 16876 + MYSHUNO_MEADOWS: 'CommonVenueType' = 138380 + NATURAL_POOL: 'CommonVenueType' = 175123 + OCEAN_BLUFF: 'CommonVenueType' = 125071 + PARK: 'CommonVenueType' = 25847 + PENTHOUSE: 'CommonVenueType' = 149495 + PENTHOUSE_EP08: 'CommonVenueType' = 227304 + POLICE_STATION: 'CommonVenueType' = 109774 + POOL: 'CommonVenueType' = 123794 + RELAXATION_CENTER: 'CommonVenueType' = 118135 + RENTABLE_CABIN: 'CommonVenueType' = 103675 + RENTABLE_JUNGLE: 'CommonVenueType' = 173833 + RENTABLE_UNIVERSITY_HOUSING: 'CommonVenueType' = 208182 + RESIDENTIAL: 'CommonVenueType' = 28614 + RESIDENTIAL_TINY_HOME: 'CommonVenueType' = 229251 + RESTAURANT: 'CommonVenueType' = 130713 + RETAIL: 'CommonVenueType' = 105157 + RUINS: 'CommonVenueType' = 123132 + SCIENTIST_LAB: 'CommonVenueType' = 107487 + TEMPLE: 'CommonVenueType' = 173492 + UNIVERSITY_STUDENT_COMMONS_ARTS: 'CommonVenueType' = 218857 + UNIVERSITY_STUDENT_COMMONS_SCIENCE: 'CommonVenueType' = 218858 + VET: 'CommonVenueType' = 158847 + VISITORS_ALLOWED: 'CommonVenueType' = 98817 diff --git a/Scripts/s4ap/sims4communitylib/enums/whims_enum.py b/Scripts/s4ap/sims4communitylib/enums/whims_enum.py new file mode 100644 index 0000000..904b313 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/whims_enum.py @@ -0,0 +1,242 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonWhimSetId(CommonInt): + """Identifiers for vanilla whim sets. + + """ + INVALID: 'CommonWhimSetId' = 0 + APARTMENT_PROBLEMS: 'CommonWhimSetId' = 142026 + APARTMENTS_INDOORS_GO_OUTSIDE: 'CommonWhimSetId' = 142732 + APARTMENTS_LOT_TRAITS: 'CommonWhimSetId' = 142085 + APARTMENTS_NEIGHBOR_SITUATION_COMPLAIN_ABOUT_NOISE: 'CommonWhimSetId' = 140901 + APARTMENTS_NEIGHBOR_SITUATION_GIVE_KEY: 'CommonWhimSetId' = 140954 + ASP_ANIMAL_FRIEND_OF_THE_ANIMALS: 'CommonWhimSetId' = 172197 + ASP_ATHLETIC_BODYBUILDER: 'CommonWhimSetId' = 97876 + ASP_CREATIVITY_MUSICAL: 'CommonWhimSetId' = 97877 + ASP_CREATIVITY_PAINTER: 'CommonWhimSetId' = 97878 + ASP_CREATIVITY_WRITER: 'CommonWhimSetId' = 97879 + ASP_DEVIANCE_ENEMY: 'CommonWhimSetId' = 97880 + ASP_DEVIANCE_MISCHIEF: 'CommonWhimSetId' = 97881 + ASP_FAMILY_HAPPY_FAMILY: 'CommonWhimSetId' = 97882 + ASP_FAMILY_SUCCESSFUL: 'CommonWhimSetId' = 97885 + ASP_FOOD_BARTENDER: 'CommonWhimSetId' = 97883 + ASP_FOOD_CHEF: 'CommonWhimSetId' = 97884 + ASP_FORTUNE_MANSION: 'CommonWhimSetId' = 97886 + ASP_FORTUNE_WEALTHY: 'CommonWhimSetId' = 97887 + ASP_KNOWLEDGE_COMPUTER: 'CommonWhimSetId' = 97898 + ASP_KNOWLEDGE_NERD: 'CommonWhimSetId' = 97897 + ASP_KNOWLEDGE_RENAISSANCE: 'CommonWhimSetId' = 97896 + ASP_LOCATION_CITY_LIFE: 'CommonWhimSetId' = 144970 + ASP_LOVE_HOPEFUL_ROMANTIC: 'CommonWhimSetId' = 97895 + ASP_LOVE_SOUL_MATE: 'CommonWhimSetId' = 97894 + ASP_NATURE_ANGLING: 'CommonWhimSetId' = 97893 + ASP_NATURE_BOTANIST: 'CommonWhimSetId' = 97892 + ASP_NATURE_CURATOR: 'CommonWhimSetId' = 97890 + ASP_NATURE_OUTDOORS: 'CommonWhimSetId' = 108794 + ASP_POPULARITY_FRIEND: 'CommonWhimSetId' = 97889 + ASP_POPULARITY_JOKE_STAR: 'CommonWhimSetId' = 97891 + ASP_POPULARITY_LEADER_OF_THE_PACK: 'CommonWhimSetId' = 122936 + ASP_POPULARITY_PARTY: 'CommonWhimSetId' = 97888 + BAKING: 'CommonWhimSetId' = 115144 + BAR: 'CommonWhimSetId' = 129728 + BARTENDING: 'CommonWhimSetId' = 31709 + BEING_IN_CLUB: 'CommonWhimSetId' = 125284 + BLUFFS: 'CommonWhimSetId' = 129737 + BONFIRE: 'CommonWhimSetId' = 125676 + BUBBLE_BLOWER: 'CommonWhimSetId' = 143236 + BUSH: 'CommonWhimSetId' = 131179 + BUY_CITY_REGION: 'CommonWhimSetId' = 144959 + BUY_ADVANCED: 'CommonWhimSetId' = 105598 + BUY_BASICS: 'CommonWhimSetId' = 36954 + CAFE: 'CommonWhimSetId' = 124371 + CAMPFIRE: 'CommonWhimSetId' = 104505 + CAREER_ACTIVIST_CHARITY: 'CommonWhimSetId' = 136429 + CAREER_ACTIVIST_MAIN: 'CommonWhimSetId' = 136434 + CAREER_ACTIVIST_POLITICS: 'CommonWhimSetId' = 136428 + CAREER_ASTRONAUT: 'CommonWhimSetId' = 35096 + CAREER_ATHLETIC: 'CommonWhimSetId' = 110186 + CAREER_BUSINESS: 'CommonWhimSetId' = 110187 + CAREER_CRIMINAL: 'CommonWhimSetId' = 35100 + CAREER_CRITIC_ARTS: 'CommonWhimSetId' = 136200 + CAREER_CRITIC_BASIC: 'CommonWhimSetId' = 136198 + CAREER_CRITIC_FOOD: 'CommonWhimSetId' = 136199 + CAREER_CULINARY: 'CommonWhimSetId' = 35101 + CAREER_DETECTIVE: 'CommonWhimSetId' = 114617 + CAREER_DOCTOR: 'CommonWhimSetId' = 114611 + CAREER_ENTERTAINER: 'CommonWhimSetId' = 35102 + CAREER_PAINTER: 'CommonWhimSetId' = 106085 + CAREER_SCIENTIST: 'CommonWhimSetId' = 107573 + CAREER_SECRET_AGENT: 'CommonWhimSetId' = 35103 + CAREER_SOCIAL_MEDIA_INTERNET_PERSONALITY: 'CommonWhimSetId' = 135648 + CAREER_SOCIAL_MEDIA_MAIN: 'CommonWhimSetId' = 135647 + CAREER_SOCIAL_MEDIA_PUBLIC_RELATIONS: 'CommonWhimSetId' = 135649 + CAREER_TECH_GURU: 'CommonWhimSetId' = 35104 + CAREER_WRITER: 'CommonWhimSetId' = 35099 + CHALET: 'CommonWhimSetId' = 129738 + CHARISMA: 'CommonWhimSetId' = 32927 + CHILD_CREATIVE: 'CommonWhimSetId' = 34693 + CHILD_MENTAL: 'CommonWhimSetId' = 34689 + CHILD_MONSTER_UNDER_THE_BED: 'CommonWhimSetId' = 136480 + CHILD_MOTOR: 'CommonWhimSetId' = 34670 + CHILD_SOCIAL: 'CommonWhimSetId' = 34685 + CHILD_TEEN_HOMEWORK: 'CommonWhimSetId' = 75518 + CLOSET: 'CommonWhimSetId' = 125548 + CLUB: 'CommonWhimSetId' = 129729 + COLLECTION_SET: 'CommonWhimSetId' = 38419 + COMEDY: 'CommonWhimSetId' = 35061 + COOKING: 'CommonWhimSetId' = 31708 + DANCE_FLOOR_ON_LOT: 'CommonWhimSetId' = 129758 + DANCE_FLOOR_OWNED: 'CommonWhimSetId' = 129762 + DANCING_SKILL: 'CommonWhimSetId' = 128197 + DARES: 'CommonWhimSetId' = 121308 + DARTBOARD: 'CommonWhimSetId' = 129777 + DJ_BOOTH_ON_LOT: 'CommonWhimSetId' = 124412 + DJ_BOOTH_OWNED: 'CommonWhimSetId' = 124410 + EMOTION_ANGRY: 'CommonWhimSetId' = 25426 + EMOTION_BORED: 'CommonWhimSetId' = 25422 + EMOTION_CONFIDENT: 'CommonWhimSetId' = 25424 + EMOTION_DAZED: 'CommonWhimSetId' = 25423 + EMOTION_EMBARRASSED: 'CommonWhimSetId' = 25427 + EMOTION_ENERGIZED: 'CommonWhimSetId' = 25384 + EMOTION_FLIRTY: 'CommonWhimSetId' = 25386 + EMOTION_FOCUSED: 'CommonWhimSetId' = 38413 + EMOTION_HAPPY: 'CommonWhimSetId' = 25383 + EMOTION_INSPIRED: 'CommonWhimSetId' = 25378 + EMOTION_PLAYFUL: 'CommonWhimSetId' = 25421 + EMOTION_SAD: 'CommonWhimSetId' = 25425 + EMOTION_STRESSED: 'CommonWhimSetId' = 25428 + ENEMIES: 'CommonWhimSetId' = 28028 + ENEMY_PROGRESS: 'CommonWhimSetId' = 32646 + FESTIVALS_BLOSSOM: 'CommonWhimSetId' = 142968 + FESTIVALS_FLEA_MARKET: 'CommonWhimSetId' = 142969 + FESTIVALS_FOOD: 'CommonWhimSetId' = 142970 + FESTIVALS_LAMP: 'CommonWhimSetId' = 142971 + FESTIVALS_LOGIC: 'CommonWhimSetId' = 142967 + FISHING: 'CommonWhimSetId' = 77374 + FITNESS: 'CommonWhimSetId' = 33091 + FOOSBALL_TABLE: 'CommonWhimSetId' = 125726 + FRIEND_PROGRESS: 'CommonWhimSetId' = 28013 + FRIENDSHIP: 'CommonWhimSetId' = 28026 + GARDENING: 'CommonWhimSetId' = 33150 + GHOST: 'CommonWhimSetId' = 102667 + GUITAR: 'CommonWhimSetId' = 34339 + HANDINESS: 'CommonWhimSetId' = 35063 + HAS_TRAIT_ACTIVE: 'CommonWhimSetId' = 34777 + HAS_TRAIT_AMBITIOUS: 'CommonWhimSetId' = 34778 + HAS_TRAIT_ART_LOVER: 'CommonWhimSetId' = 34779 + HAS_TRAIT_BOOKWORM: 'CommonWhimSetId' = 34780 + HAS_TRAIT_BRO: 'CommonWhimSetId' = 34781 + HAS_TRAIT_CAT_LOVER: 'CommonWhimSetId' = 157994 + HAS_TRAIT_CHEERFUL: 'CommonWhimSetId' = 34782 + HAS_TRAIT_CHILDISH: 'CommonWhimSetId' = 34783 + HAS_TRAIT_CLUMSY: 'CommonWhimSetId' = 34784 + HAS_TRAIT_COMMITMENTPHOBE: 'CommonWhimSetId' = 34785 + HAS_TRAIT_COMPASSIONATE: 'CommonWhimSetId' = 160864 + HAS_TRAIT_CREATIVE: 'CommonWhimSetId' = 34786 + HAS_TRAIT_DANCE_MACHINE: 'CommonWhimSetId' = 126091 + HAS_TRAIT_DOG_LOVER: 'CommonWhimSetId' = 157995 + HAS_TRAIT_EVIL: 'CommonWhimSetId' = 34787 + HAS_TRAIT_FAMILY_ORIENTED: 'CommonWhimSetId' = 34788 + HAS_TRAIT_FOODIE: 'CommonWhimSetId' = 28155 + HAS_TRAIT_GEEK: 'CommonWhimSetId' = 34790 + HAS_TRAIT_GENIUS: 'CommonWhimSetId' = 34791 + HAS_TRAIT_GLOOMY: 'CommonWhimSetId' = 34792 + HAS_TRAIT_GLUTTON: 'CommonWhimSetId' = 34793 + HAS_TRAIT_GOOD: 'CommonWhimSetId' = 34794 + HAS_TRAIT_GOOD_CHILD: 'CommonWhimSetId' = 155380 + HAS_TRAIT_GOOFBALL: 'CommonWhimSetId' = 34795 + HAS_TRAIT_GOOFBALL_CHILD: 'CommonWhimSetId' = 155382 + HAS_TRAIT_HATES_CHILDREN: 'CommonWhimSetId' = 34796 + HAS_TRAIT_HOTHEADED: 'CommonWhimSetId' = 34797 + HAS_TRAIT_INSANE: 'CommonWhimSetId' = 34798 + HAS_TRAIT_INSIDER: 'CommonWhimSetId' = 125440 + HAS_TRAIT_IRRESPONSIBLE: 'CommonWhimSetId' = 163674 + HAS_TRAIT_JEALOUSY: 'CommonWhimSetId' = 127089 + HAS_TRAIT_KLEPTOMANIAC: 'CommonWhimSetId' = 131919 + HAS_TRAIT_LAZY: 'CommonWhimSetId' = 34799 + HAS_TRAIT_LIFE_SKILLS_ARGUMENTATIVE: 'CommonWhimSetId' = 163188 + HAS_TRAIT_LIFE_SKILLS_BAD_MANNERS: 'CommonWhimSetId' = 160852 + HAS_TRAIT_LIFE_SKILLS_GOOD_MANNERS: 'CommonWhimSetId' = 160845 + HAS_TRAIT_LIFE_SKILLS_MEDIATOR: 'CommonWhimSetId' = 163189 + HAS_TRAIT_LIKES_FRUITCAKE: 'CommonWhimSetId' = 120193 + HAS_TRAIT_LONER: 'CommonWhimSetId' = 34800 + HAS_TRAIT_LOVES_OUTDOORS: 'CommonWhimSetId' = 34801 + HAS_TRAIT_MATERIALISTIC: 'CommonWhimSetId' = 34802 + HAS_TRAIT_MEAN: 'CommonWhimSetId' = 34803 + HAS_TRAIT_MELT_MASTER: 'CommonWhimSetId' = 132360 + HAS_TRAIT_MUSIC_LOVER: 'CommonWhimSetId' = 34804 + HAS_TRAIT_NEAT: 'CommonWhimSetId' = 26090 + HAS_TRAIT_OUTGOING: 'CommonWhimSetId' = 34806 + HAS_TRAIT_PERFECTIONIST: 'CommonWhimSetId' = 34807 + HAS_TRAIT_RESPONSIBLE: 'CommonWhimSetId' = 163573 + HAS_TRAIT_ROMANTIC: 'CommonWhimSetId' = 28154 + HAS_TRAIT_SELF_ASSURED: 'CommonWhimSetId' = 34808 + HAS_TRAIT_SLOB: 'CommonWhimSetId' = 34809 + HAS_TRAIT_SNOB: 'CommonWhimSetId' = 34810 + HAS_TRAIT_SQUEAMISH: 'CommonWhimSetId' = 102729 + HAS_TRAIT_UNCONTROLLED_EMOTION_: 'CommonWhimSetId' = 166098 + HAS_TRAIT_UNFEELING: 'CommonWhimSetId' = 160957 + HAS_TRAIT_UNFLIRTY: 'CommonWhimSetId' = 132586 + HAS_TRAIT_VAMPIRE: 'CommonWhimSetId' = 153501 + HAS_TRAIT_VEGETARIAN: 'CommonWhimSetId' = 132630 + HERBALISM: 'CommonWhimSetId' = 105193 + HORSESHOES: 'CommonWhimSetId' = 106043 + INCENSE: 'CommonWhimSetId' = 119380 + KARAOKE_MACHINE: 'CommonWhimSetId' = 148669 + LOGIC: 'CommonWhimSetId' = 34444 + MISCHIEF: 'CommonWhimSetId' = 34448 + NEW_ROMANCE: 'CommonWhimSetId' = 28027 + NEW_ROMANCE_PLUS: 'CommonWhimSetId' = 32523 + NOT_VAMPIRE: 'CommonWhimSetId' = 154203 + PAINTING: 'CommonWhimSetId' = 35064 + PARENTING: 'CommonWhimSetId' = 164174 + PARENT_TO_BABY: 'CommonWhimSetId' = 97290 + PARENT_TO_CHILD: 'CommonWhimSetId' = 32933 + PARENT_TO_TODDLER: 'CommonWhimSetId' = 155375 + PARTNERS: 'CommonWhimSetId' = 28017 + PET_CAT_OWNER: 'CommonWhimSetId' = 159319 + PET_DOG_OWNER: 'CommonWhimSetId' = 159318 + PET_OWNER: 'CommonWhimSetId' = 169589 + PHOTOGRAPHY: 'CommonWhimSetId' = 112131 + PIANO: 'CommonWhimSetId' = 34340 + PIPE_ORGAN: 'CommonWhimSetId' = 151435 + POOL: 'CommonWhimSetId' = 129736 + POOLS: 'CommonWhimSetId' = 103901 + PROGRAMMING: 'CommonWhimSetId' = 35070 + RELAXATION_CENTER: 'CommonWhimSetId' = 121106 + RESTAURANT: 'CommonWhimSetId' = 131257 + ROCKET_SCIENCE: 'CommonWhimSetId' = 35072 + RUINS: 'CommonWhimSetId' = 129739 + SICKNESS_SYMPTOMS_CURE: 'CommonWhimSetId' = 111514 + SINGING: 'CommonWhimSetId' = 140016 + SOCIAL_MEET_NEW: 'CommonWhimSetId' = 25464 + STEREO_RADIO_CHANNELS: 'CommonWhimSetId' = 146257 + TEENS: 'CommonWhimSetId' = 117896 + TELEVISION_CHANNELS: 'CommonWhimSetId' = 146256 + TENT: 'CommonWhimSetId' = 105274 + TODDLER_CHAOS_SET: 'CommonWhimSetId' = 154890 + TODDLER_GROWTH_SET: 'CommonWhimSetId' = 154892 + TODDLER_NURTURING_SET: 'CommonWhimSetId' = 154914 + TODDLER_TRAIT_ANGELIC_SET: 'CommonWhimSetId' = 154893 + TODDLER_TRAIT_CHARMER_SET: 'CommonWhimSetId' = 154900 + TODDLER_TRAIT_CLINGY_SET: 'CommonWhimSetId' = 154894 + TODDLER_TRAIT_FUSSY_SET: 'CommonWhimSetId' = 154899 + TODDLER_TRAIT_INDEPENDENT_SET: 'CommonWhimSetId' = 154898 + TODDLER_TRAIT_INQUISITIVE_SET: 'CommonWhimSetId' = 154896 + TODDLER_TRAIT_SILLY_SET: 'CommonWhimSetId' = 154897 + TODDLER_TRAIT_WILD_SET: 'CommonWhimSetId' = 154895 + TREADMILL_ROCK_CLIMBING_WALL_OWNED: 'CommonWhimSetId' = 167506 + VET: 'CommonWhimSetId' = 170146 + VET_VENDING_MACHINE: 'CommonWhimSetId' = 176348 + VIDEO_GAMING: 'CommonWhimSetId' = 34449 + VIOLIN: 'CommonWhimSetId' = 34341 + WELLNESS: 'CommonWhimSetId' = 118587 + WRITING: 'CommonWhimSetId' = 35073 diff --git a/Scripts/s4ap/sims4communitylib/enums/world_types_enum.py b/Scripts/s4ap/sims4communitylib/enums/world_types_enum.py new file mode 100644 index 0000000..d29959b --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/enums/world_types_enum.py @@ -0,0 +1,84 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonWorldTypeId(CommonInt): + """Identifiers for various vanilla world types. + + """ + INVALID: 'CommonWorldTypeId' = 0 + ACQUISITION_BUTTE: 'CommonWorldTypeId' = 23279 + ARTS_QUARTER: 'CommonWorldTypeId' = 121286 + SPICE_MARKET: 'CommonWorldTypeId' = 117423 + BEDROCK_STRAIT: 'CommonWorldTypeId' = 23278 + BELOMISIA_JUNGLE: 'CommonWorldTypeId' = 179659 + BG_DEBUG_MEGALOTS_TEST_WORLD: 'CommonWorldTypeId' = 117183 + BRIDGEVIEW: 'CommonWorldTypeId' = 93560 + BUSINESS_DISTRICT: 'CommonWorldTypeId' = 100125 + CAVALIER_COVE: 'CommonWorldTypeId' = 164436 + CHIRON_ONE_LOT_CLIFF_TEST_WORLD: 'CommonWorldTypeId' = 21147 + CHIRON_ONE_LOT_HILL: 'CommonWorldTypeId' = 21148 + CHIRON_ONE_LOT_TEST_WORLD: 'CommonWorldTypeId' = 21145 + COURTYARD_LANE: 'CommonWorldTypeId' = 20382 + DEADGRASS_ISLE: 'CommonWorldTypeId' = 164437 + DESERT_BLOOM: 'CommonWorldTypeId' = 42521 + DISCOVER_JUNGLE_SECRETS: 'CommonWorldTypeId' = 188795 + EP01_ALIEN_WORLD_01: 'CommonWorldTypeId' = 72720 + EP01_CIVIC_CENTER_01: 'CommonWorldTypeId' = 72467 + EP01_CIVIC_CENTER_02: 'CommonWorldTypeId' = 88225 + EP01_SCIENCE_LAB_01: 'CommonWorldTypeId' = 72721 + EP02_CHALET_GARDEN_01: 'CommonWorldTypeId' = 107138 + EP02_ISLAND_BLUFF_01: 'CommonWorldTypeId' = 106836 + EP02_OLD_TOWN_01: 'CommonWorldTypeId' = 100127 + EP02_OLD_TOWN_RUINS_01: 'CommonWorldTypeId' = 103613 + EP07_RESORT_ISLAND: 'CommonWorldTypeId' = 207075 + EP07_LOCAL_ISLAND_01: 'CommonWorldTypeId' = 208803 + EP07_NATURAL_ISLAND_01: 'CommonWorldTypeId' = 212324 + FASHION_DISTRICT: 'CommonWorldTypeId' = 120336 + FORGOTTEN_GROTTO: 'CommonWorldTypeId' = 47905 + FOUNDRY_COVE: 'CommonWorldTypeId' = 20384 + GALLERY_LOT_BUILD_WORLD: 'CommonWorldTypeId' = 62773 + GD_WARD_VENUE_01: 'CommonWorldTypeId' = 36244 + GP01_CAMPGROUND_01: 'CommonWorldTypeId' = 65991 + GP01_FOREST_01: 'CommonWorldTypeId' = 65996 + GP01_HERMIT_DWELLING_01: 'CommonWorldTypeId' = 65997 + GP04_VAMPIRE_WORLD_01: 'CommonWorldTypeId' = 146194 + GP07_CRATER_BASE_01: 'CommonWorldTypeId' = 208774 + GP07_DOWNTOWN_01: 'CommonWorldTypeId' = 208775 + GP07_OUTSKIRTS_01: 'CommonWorldTypeId' = 208823 + GP08_MAGIC_REALM_01: 'CommonWorldTypeId' = 222658 + GP08_VILLAGE_01: 'CommonWorldTypeId' = 222659 + ISLAND: 'CommonWorldTypeId' = 100126 + LLAMA_LAGOON: 'CommonWorldTypeId' = 93559 + LOT_1: 'CommonWorldTypeId' = 31580 + MAGALOG_9_LOT_WORLD: 'CommonWorldTypeId' = 62772 + MAGNOLIA_BLOSSOM: 'CommonWorldTypeId' = 42525 + MIRAGE_PARK: 'CommonWorldTypeId' = 201096 + MYSHUNO_MEADOWS: 'CommonWorldTypeId' = 132618 + OLD_TOWN: 'CommonWorldTypeId' = 101536 + PARCHED_PROSPECT: 'CommonWorldTypeId' = 23280 + PENDULA_VIEW: 'CommonWorldTypeId' = 20383 + PLUMBOB_PICTURES: 'CommonWorldTypeId' = 197665 + PUERTO_LLAMANTE_MARKETPLACE: 'CommonWorldTypeId' = 176581 + RETAIL_LOT_NAME_PLACEHOLDER: 'CommonWorldTypeId' = 72719 + RIDGELINE_DRIVE: 'CommonWorldTypeId' = 93558 + RURAL_VILLAGE: 'CommonWorldTypeId' = 100124 + SABLE_SQUARE: 'CommonWorldTypeId' = 164438 + SAGE_ESTATES: 'CommonWorldTypeId' = 20381 + SEASONS_ART_TEST_WORLD: 'CommonWorldTypeId' = 175243 + SKYWARD_PALMS: 'CommonWorldTypeId' = 23281 + SO_CACTUS_VENUS_01: 'CommonWorldTypeId' = 36256 + SO_RBH_CAVE_01: 'CommonWorldTypeId' = 45699 + SQE_EMPTY_LOT_AREA_TEST_WORLD: 'CommonWorldTypeId' = 21143 + SQE_GAMEPLAY_PROFILE_AREA3_TEST_WORLD: 'CommonWorldTypeId' = 21146 + STARLIGHT_BOULEVARD: 'CommonWorldTypeId' = 201098 + SYLVAN_GLADE: 'CommonWorldTypeId' = 47906 + THE_PINNACLES: 'CommonWorldTypeId' = 201097 + UPTOWN: 'CommonWorldTypeId' = 118767 + WHISKERMANS_WHARF: 'CommonWorldTypeId' = 164435 diff --git a/Scripts/s4ap/sims4communitylib/events/__init__.py b/Scripts/s4ap/sims4communitylib/events/__init__.py new file mode 100644 index 0000000..3251898 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" \ No newline at end of file diff --git a/Scripts/s4ap/sims4communitylib/events/build_buy/__init__.py b/Scripts/s4ap/sims4communitylib/events/build_buy/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/build_buy/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/events/build_buy/common_build_buy_event_dispatcher.py b/Scripts/s4ap/sims4communitylib/events/build_buy/common_build_buy_event_dispatcher.py new file mode 100644 index 0000000..b3eb1ad --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/build_buy/common_build_buy_event_dispatcher.py @@ -0,0 +1,65 @@ +""" +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 +""" +from typing import Any + +from sims4communitylib.events.build_buy.events.build_buy_enter import S4CLBuildBuyEnterEvent +from sims4communitylib.events.build_buy.events.build_buy_exit import S4CLBuildBuyExitEvent +from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry +from sims4communitylib.logging.has_class_log import HasClassLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.common_service import CommonService +from sims4communitylib.utils.common_injection_utils import CommonInjectionUtils +from zone import Zone + + +class CommonBuildBuyEventDispatcherService(CommonService, HasClassLog): + """A service that dispatches Build/Buy events. + + .. warning:: Do not use this service directly to listen for events!\ + Use the :class:`.CommonEventRegistry` to listen for dispatched events. + + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + return ModInfo.get_identity() + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 's4cl_build_buy_event_dispatcher' + + def _on_build_buy_enter(self, zone: Zone, *_, **__): + return CommonEventRegistry.get().dispatch(S4CLBuildBuyEnterEvent(zone)) + + def _on_build_buy_exit(self, zone: Zone, *_, **__): + return CommonEventRegistry.get().dispatch(S4CLBuildBuyExitEvent(zone)) + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), Zone, Zone.on_build_buy_enter.__name__) +def _common_build_buy_enter(original, self, *args, **kwargs) -> Any: + try: + result = original(self, *args, **kwargs) + except Exception as ex: + CommonBuildBuyEventDispatcherService.get_log().format_error_with_message('An error occurred when performing Zone.on_build_buy_enter. (This exception is not caused by S4CL, but rather caught)', owner=self, argles=args, kwargles=kwargs, exception=ex) + return + CommonBuildBuyEventDispatcherService.get()._on_build_buy_enter(self, *args, **kwargs) + return result + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), Zone, Zone.on_build_buy_exit.__name__) +def _common_build_buy_exit(original, self, *args, **kwargs) -> Any: + try: + result = original(self, *args, **kwargs) + except Exception as ex: + CommonBuildBuyEventDispatcherService.get_log().format_error_with_message('An error occurred when performing Zone.on_build_buy_exit. (This exception is not caused by S4CL, but rather caught)', owner=self, argles=args, kwargles=kwargs, exception=ex) + return + CommonBuildBuyEventDispatcherService.get()._on_build_buy_exit(self, *args, **kwargs) + return result diff --git a/Scripts/s4ap/sims4communitylib/events/build_buy/events/__init__.py b/Scripts/s4ap/sims4communitylib/events/build_buy/events/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/build_buy/events/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/events/build_buy/events/build_buy_enter.py b/Scripts/s4ap/sims4communitylib/events/build_buy/events/build_buy_enter.py new file mode 100644 index 0000000..fb29387 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/build_buy/events/build_buy_enter.py @@ -0,0 +1,51 @@ +""" +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 +""" +from sims4communitylib.events.event_handling.common_event import CommonEvent +from zone import Zone + + +class S4CLBuildBuyEnterEvent(CommonEvent): + """S4CLBuildBuyEnterEvent(zone) + + An event that occurs upon entering Build/Buy on a lot. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity().name) + def handle_event(event_data: S4CLBuildBuyEnterEvent): + pass + + :param zone: The zone the player has entered Build/Buy on. + :type zone: Zone + """ + + def __init__(self, zone: Zone): + self._zone = zone + + @property + def zone(self) -> Zone: + """The zone the event occurred on. + + :return: The zone the event occurred on. + :rtype: Zone + """ + return self._zone diff --git a/Scripts/s4ap/sims4communitylib/events/build_buy/events/build_buy_exit.py b/Scripts/s4ap/sims4communitylib/events/build_buy/events/build_buy_exit.py new file mode 100644 index 0000000..5931f3b --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/build_buy/events/build_buy_exit.py @@ -0,0 +1,51 @@ +""" +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 +""" +from sims4communitylib.events.event_handling.common_event import CommonEvent +from zone import Zone + + +class S4CLBuildBuyExitEvent(CommonEvent): + """S4CLBuildBuyEnterEvent(zone) + + An event that occurs upon exiting Build/Buy on a lot. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity().name) + def handle_event(event_data: S4CLBuildBuyExitEvent): + pass + + :param zone: The zone the player has exited Build/Buy on. + :type zone: Zone + """ + + def __init__(self, zone: Zone): + self._zone = zone + + @property + def zone(self) -> Zone: + """The zone the event occurred on. + + :return: The zone the event occurred on. + :rtype: Zone + """ + return self._zone diff --git a/Scripts/s4ap/sims4communitylib/events/event_handling/__init__.py b/Scripts/s4ap/sims4communitylib/events/event_handling/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/event_handling/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/events/event_handling/common_event.py b/Scripts/s4ap/sims4communitylib/events/event_handling/common_event.py new file mode 100644 index 0000000..84db0c8 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/event_handling/common_event.py @@ -0,0 +1,25 @@ +""" +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 +""" + + +class CommonEvent: + """ A custom event, for use with the :class:`.CommonEventHandler`. """ + @property + def event_name(self) -> str: + """The name of this event. + + :return: The name of the event. + :rtype: str + """ + return self.__class__.__name__ + + def __str__(self) -> str: + return 'CommonEvent[Name:{}]'.format(self.event_name) + + def __repr__(self) -> str: + return 'common_event_name_{}'.format(self.event_name) diff --git a/Scripts/s4ap/sims4communitylib/events/event_handling/common_event_handler.py b/Scripts/s4ap/sims4communitylib/events/event_handling/common_event_handler.py new file mode 100644 index 0000000..bdc11ce --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/event_handling/common_event_handler.py @@ -0,0 +1,100 @@ +""" +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 +""" +import inspect +from typing import Callable, Any, Union + +from sims4communitylib.events.event_handling.common_event import CommonEvent +from sims4communitylib.mod_support.mod_identity import CommonModIdentity + + +class CommonEventHandler: + """CommonEventHandler(mod_identifier, event_function) + + Handles events. + + :param mod_identifier: The name or identity of the mod handling events. + :type mod_identifier: Union[str, CommonModIdentity] + :param event_function: The function this handler invokes. + :type event_function: Callable[[CommonEvent], Any] + :exception RuntimeError: When event_function is None. + :exception TypeError: When event_function is not a callable function. + :exception AssertionError: When the event_function is missing the event_data argument, when the event_function contains a self or cls argument, or when more than one argument is found. + """ + def __init__(self, mod_identifier: Union[str, CommonModIdentity], event_function: Callable[[CommonEvent], Any]): + if event_function is None: + raise RuntimeError('Required parameter \'event_function\' required for event function from mod: {}'.format(repr(mod_identifier))) + if not inspect.isfunction(event_function): + raise TypeError('\'event_function\' with name \'{}\' was not a callable function. Mod Name: \'{}\''.format(event_function.__name__, repr(mod_identifier))) + function_signature = inspect.signature(event_function) + if function_signature.parameters is None or len(function_signature.parameters) == 0 or len(function_signature.parameters) > 1: + raise AssertionError('Event Function has an incorrect number of parameters, Mod Name: \'{}\' Func Name: \'{}\''.format(repr(mod_identifier), event_function.__name__)) + if 'event_data' not in function_signature.parameters: + raise AssertionError('Event Function \'{}\' is missing the required argument with name \'event_data\'') + if 'self' in function_signature.parameters or 'cls' in function_signature.parameters: + raise AssertionError('Event functions must be static methods. Mod Name: \'{}\', Function: \'{}\''.format(repr(mod_identifier), event_function.__name__)) + from sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils + self._mod_name = CommonModIdentityUtils.determine_mod_name_from_identifier(mod_identifier) + self._event_function = event_function + self._event_type = function_signature.parameters['event_data'].annotation + + @property + def mod_name(self) -> str: + """The name of the mod this event handler was created for. + + :return: The name of the Mod that owns this handler. + :rtype: str + """ + return self._mod_name + + @property + def event_function(self) -> Callable[[CommonEvent], Any]: + """The action to take upon receiving an event. + + :return: The function that handles events. + :rtype: Callable[[CommonEvent], Any] + """ + return self._event_function + + @property + def event_type(self) -> type: + """The class type of events this Event Handler will handle. + + :return: The types of events the handler handles. + :rtype: type + """ + return self._event_type + + def can_handle_event(self, event: CommonEvent) -> bool: + """can_handle_event(event) + + Determine if this event handler can handle the type of the event. + + :param event: The event to check. + :type event: CommonEvent + :return: True, if this handler can handle the event. False, if not. + :rtype: bool + """ + return isinstance(event, self.event_type) + + def handle_event(self, event: CommonEvent) -> bool: + """handle_event(event) + + Handle the event data. + + :param event: The event to handle. + :type event: CommonEvent + :return: True, if the event was successful. False, if not. + :rtype: bool + """ + return self.event_function(event) + + def __repr__(self) -> str: + return 'mod_name_{}_function_{}_event_type_{}'.format(self.mod_name, self.event_function.__name__, self.event_type.__name__) + + def __str__(self) -> str: + return 'CommonEventHandler Mod Name: \'{}\' Function: \'{}\' Event Type: \'{}\''.format(self.mod_name, self.event_function.__name__, self.event_type.__name__) diff --git a/Scripts/s4ap/sims4communitylib/events/event_handling/common_event_registry.py b/Scripts/s4ap/sims4communitylib/events/event_handling/common_event_registry.py new file mode 100644 index 0000000..ef2b88d --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/event_handling/common_event_registry.py @@ -0,0 +1,78 @@ +""" +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 +""" +from typing import List, Callable, Any, Union +from sims4communitylib.events.event_handling.common_event import CommonEvent +from sims4communitylib.events.event_handling.common_event_handler import CommonEventHandler +from sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.common_service import CommonService + + +class CommonEventRegistry(CommonService): + """Register event listeners and dispatch events to any that are registered. + + """ + + def __init__(self) -> None: + self._event_handlers: List[CommonEventHandler] = [] + + @staticmethod + def handle_events(mod_identifier: Union[str, CommonModIdentity]) -> Callable[[Callable[[CommonEvent], bool]], Callable[[CommonEvent], bool]]: + """handle_events(mod_identifier) + + Decorate functions with this static method to register that function to handle an event. + + :warning:: Event functions MUST be decorated with staticmethod and must only have a single argument with the name 'event_data' (Errors will be thrown upon loading the game otherwise) + + :param mod_identifier: The name or identity of the mod the class is being registered for. + :type mod_identifier: Union[str, CommonModIdentity] + :return: A callable function wrapped to handle events. + :rtype: Callable[[Callable[[CommonEvent], bool]], Callable[[CommonEvent], bool]] + """ + def _wrapper(event_function: Callable[[CommonEvent], bool]) -> Callable[..., Any]: + CommonEventRegistry.get()._register_event_handler(mod_identifier, event_function) + return event_function + return _wrapper + + def _register_event_handler(self, mod_identifier: Union[str, CommonModIdentity], event_function: Callable[[CommonEvent], bool]): + event_handler = CommonEventHandler(mod_identifier, event_function) + self._event_handlers.append(event_handler) + + def dispatch(self, event: CommonEvent) -> bool: + """dispatch(event) + + Dispatch an event to any event handlers listening for it. + + .. note:: If any listeners return False or None when they handle the event, the total result of dispatch will be False as well. + + :param event: An instance of an Event to dispatch to listeners. + :type event: CommonEvent + :return: True, if the Event was dispatched to all listeners successfully. False, if any listeners failed to handle the event. + :rtype: bool + """ + return self._dispatch(event) + + def _dispatch(self, event: CommonEvent) -> bool: + event_handlers = list(self._event_handlers) + result = True + try: + for event_handler in event_handlers: + if not event_handler.can_handle_event(event): + continue + try: + handle_result = event_handler.handle_event(event) + if not handle_result: + result = False + except Exception as ex: + CommonExceptionHandler.log_exception(event_handler.mod_name, 'Error occurred when attempting to handle event type \'{}\' via event handler \'{}\''.format(type(event), str(event_handler)), exception=ex) + continue + except Exception as ex: + CommonExceptionHandler.log_exception(ModInfo.get_identity(), 'Failed to dispatch event \'{}\''.format(event), exception=ex) + return False + return result diff --git a/Scripts/s4ap/sims4communitylib/events/game_object/__init__.py b/Scripts/s4ap/sims4communitylib/events/game_object/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/game_object/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/events/game_object/common_game_object_event_dispatcher.py b/Scripts/s4ap/sims4communitylib/events/game_object/common_game_object_event_dispatcher.py new file mode 100644 index 0000000..cc5284e --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/game_object/common_game_object_event_dispatcher.py @@ -0,0 +1,131 @@ +""" +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 +""" +from typing import Any + +from objects.game_object import GameObject +from objects.script_object import ScriptObject +from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry +from sims4communitylib.events.game_object.events.game_object_added_to_inventory import S4CLGameObjectAddedToInventoryEvent +from sims4communitylib.events.game_object.events.game_object_pre_despawned import S4CLGameObjectPreDespawnedEvent +from sims4communitylib.events.game_object.events.game_object_pre_deleted import S4CLGameObjectPreDeletedEvent +from sims4communitylib.events.game_object.events.game_object_initialized import S4CLGameObjectInitializedEvent +from sims4communitylib.events.game_object.events.game_object_loaded import S4CLGameObjectLoadedEvent +from sims4communitylib.events.game_object.events.game_object_pre_removed_from_inventory import \ + S4CLGameObjectPreRemovedFromInventoryEvent +from sims4communitylib.events.game_object.events.game_object_spawned import S4CLGameObjectSpawnedEvent +from sims4communitylib.events.game_object.events.game_object_added_to_game_object_inventory import \ + S4CLGameObjectAddedToGameObjectInventoryEvent +from sims4communitylib.events.game_object.events.game_object_pre_removed_from_game_object_inventory import \ + S4CLGameObjectPreRemovedFromGameObjectInventoryEvent +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.common_service import CommonService +from sims4communitylib.utils.common_injection_utils import CommonInjectionUtils + + +class CommonGameObjectEventDispatcherService(CommonService): + """A service that dispatches Game Object events (Init, Spawn, Destroy, etc.). + + .. warning:: Do not use this service directly to listen for events!\ + Use the :class:`.CommonEventRegistry` to listen for dispatched events. + + """ + + def _on_game_object_init(self, game_object: GameObject, *_, **__) -> bool: + return CommonEventRegistry.get().dispatch(S4CLGameObjectInitializedEvent(game_object)) + + def _on_game_object_load(self, game_object: GameObject, *_, **__) -> bool: + from sims4communitylib.events.zone_spin.common_zone_spin_event_dispatcher import CommonZoneSpinEventDispatcher + if CommonZoneSpinEventDispatcher.get().game_loading: + return False + return CommonEventRegistry.get().dispatch(S4CLGameObjectLoadedEvent(game_object)) + + def _on_game_object_spawned(self, game_object: GameObject, *_, **__) -> bool: + return CommonEventRegistry.get().dispatch(S4CLGameObjectSpawnedEvent(game_object)) + + def _on_game_object_despawned(self, game_object: GameObject, *_, **__) -> bool: + return CommonEventRegistry.get().dispatch(S4CLGameObjectPreDespawnedEvent(game_object)) + + def _on_game_object_destroy(self, game_object: GameObject, *_, **__) -> bool: + return CommonEventRegistry.get().dispatch(S4CLGameObjectPreDeletedEvent(game_object)) + + def _on_game_object_added_to_inventory(self, game_object: GameObject, *_, **__) -> bool: + return CommonEventRegistry.get().dispatch(S4CLGameObjectAddedToInventoryEvent(game_object)) + + def _on_game_object_pre_removed_from_inventory(self, game_object: GameObject, *_, **__) -> bool: + return CommonEventRegistry.get().dispatch(S4CLGameObjectPreRemovedFromInventoryEvent(game_object)) + + def _on_game_object_added_to_game_object_inventory(self, game_object: GameObject, added_object: GameObject) -> None: + CommonEventRegistry.get().dispatch(S4CLGameObjectAddedToGameObjectInventoryEvent(game_object, added_object)) + + def _on_game_object_pre_removed_from_game_object_inventory(self, game_object: GameObject, removed_object: GameObject) -> None: + CommonEventRegistry.get().dispatch(S4CLGameObjectPreRemovedFromGameObjectInventoryEvent(game_object, removed_object)) + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), GameObject, GameObject.__init__.__name__, handle_exceptions=False) +def _common_on_game_object_init(original, self, *args, **kwargs) -> Any: + result = original(self, *args, **kwargs) + CommonGameObjectEventDispatcherService.get()._on_game_object_init(self, *args, **kwargs) + return result + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), GameObject, GameObject.load_object.__name__, handle_exceptions=False) +def _common_on_game_object_load(original, self, *args, **kwargs) -> Any: + result = original(self, *args, **kwargs) + CommonGameObjectEventDispatcherService.get()._on_game_object_load(self, *args, **kwargs) + return result + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), GameObject, GameObject.destroy.__name__, handle_exceptions=False) +def _common_on_game_object_load(original, self, *args, **kwargs) -> Any: + CommonGameObjectEventDispatcherService.get()._on_game_object_destroy(self, *args, **kwargs) + result = original(self, *args, **kwargs) + return result + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), GameObject, GameObject.on_add.__name__) +def _common_on_game_object_added(original, self, *args, **kwargs) -> Any: + result = original(self, *args, **kwargs) + CommonGameObjectEventDispatcherService.get()._on_game_object_spawned(self, *args, **kwargs) + return result + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), GameObject, GameObject.on_remove.__name__) +def _common_on_game_object_removed(original, self, *args, **kwargs) -> Any: + CommonGameObjectEventDispatcherService.get()._on_game_object_despawned(self, *args, **kwargs) + result = original(self, *args, **kwargs) + return result + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), GameObject, GameObject.on_added_to_inventory.__name__) +def _common_on_game_object_added_to_inventory(original, self, *args, **kwargs) -> Any: + result = original(self, *args, **kwargs) + CommonGameObjectEventDispatcherService.get()._on_game_object_added_to_inventory(self, *args, **kwargs) + return result + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), GameObject, GameObject.on_removed_from_inventory.__name__) +def _common_on_game_object_removed_from_inventory(original, self, *args, **kwargs) -> Any: + CommonGameObjectEventDispatcherService.get()._on_game_object_pre_removed_from_inventory(self, *args, **kwargs) + result = original(self, *args, **kwargs) + return result + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), GameObject, GameObject.on_object_added_to_inventory.__name__, handle_exceptions=False) +def _common_on_game_object_added_to_game_object_inventory(original, self: GameObject, obj: ScriptObject, *args, **kwargs): + result = original(self, obj, *args, **kwargs) + if isinstance(obj, GameObject): + CommonGameObjectEventDispatcherService.get()._on_game_object_added_to_game_object_inventory(self, obj) + return result + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), GameObject, GameObject.on_object_removed_from_inventory.__name__, handle_exceptions=False) +def _common_on_game_object_removed_from_game_object_inventory(original, self: GameObject, obj: ScriptObject, *args, **kwargs): + if isinstance(obj, GameObject): + CommonGameObjectEventDispatcherService.get()._on_game_object_pre_removed_from_game_object_inventory(self, obj) + result = original(self, obj, *args, **kwargs) + return result diff --git a/Scripts/s4ap/sims4communitylib/events/game_object/events/__init__.py b/Scripts/s4ap/sims4communitylib/events/game_object/events/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/game_object/events/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_added_to_game_object_inventory.py b/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_added_to_game_object_inventory.py new file mode 100644 index 0000000..9419f66 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_added_to_game_object_inventory.py @@ -0,0 +1,83 @@ +""" +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 +""" +from objects.game_object import GameObject +from sims4communitylib.events.event_handling.common_event import CommonEvent +from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils + + +class S4CLGameObjectAddedToGameObjectInventoryEvent(CommonEvent): + """S4CLGameObjectAddedToGameObjectInventoryEvent(game_object, added_game_object) + + An event that occurs when a GameObject is added to the inventory of another Game Object. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity()) + def handle_event(event_data: S4CLGameObjectAddedToGameObjectInventoryEvent): + pass + + :param game_object: The Game Object that changed. + :type game_object: GameObject + :param added_game_object: The Object that was added to the inventory of the Game Object. + :type added_game_object: GameObject + """ + + def __init__(self, game_object: GameObject, added_game_object: GameObject): + self._game_object = game_object + self._added_game_object = added_game_object + + @property + def game_object(self) -> GameObject: + """The Game Object that had the Game Object added to its inventory. + + :return: The Game Object that had the Game Object added to its inventory. + :rtype: GameObject + """ + return self._game_object + + @property + def added_game_object(self) -> GameObject: + """The Game Object that was added. + + :return: The Game Object that was added. + :rtype: GameObject + """ + return self._added_game_object + + @property + def added_game_object_id(self) -> int: + """The decimal identifier of the Game Object that was added. + + :return: The decimal identifier of the Game Object that was added. + :rtype: int + """ + return CommonObjectUtils.get_object_id(self.added_game_object) + + @property + def added_game_object_guid(self) -> int: + """The guid identifier of the Game Object that was added. + + :return: The guid identifier of the Game Object that was added. + :rtype: int + """ + # noinspection PyTypeChecker + return CommonObjectUtils.get_object_guid(self.added_game_object) diff --git a/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_added_to_inventory.py b/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_added_to_inventory.py new file mode 100644 index 0000000..d6e68e6 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_added_to_inventory.py @@ -0,0 +1,51 @@ +""" +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 +""" +from objects.game_object import GameObject +from sims4communitylib.events.event_handling.common_event import CommonEvent + + +class S4CLGameObjectAddedToInventoryEvent(CommonEvent): + """S4CLGameObjectAddedToInventoryEvent(game_object) + + An event that occurs after a Game Object has been added to the inventory of something. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity().name) + def handle_event(event_data: S4CLGameObjectAddedToInventoryEvent): + pass + + :param game_object: The Object has been added to the inventory of something. + :type game_object: GameObject + """ + + def __init__(self, game_object: GameObject): + self._game_object = game_object + + @property + def game_object(self) -> GameObject: + """The Game Object that was added to the inventory. + + :return: The Game Object that was added to the inventory. + :rtype: GameObject + """ + return self._game_object diff --git a/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_initialized.py b/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_initialized.py new file mode 100644 index 0000000..2001c19 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_initialized.py @@ -0,0 +1,51 @@ +""" +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 +""" +from objects.game_object import GameObject +from sims4communitylib.events.event_handling.common_event import CommonEvent + + +class S4CLGameObjectInitializedEvent(CommonEvent): + """S4CLGameObjectInitializedEvent(game_object) + + An event that occurs after a Game Object has been initialized. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity().name) + def handle_event(event_data: S4CLGameObjectInitializedEvent): + pass + + :param game_object: The Game Object that was initialized. + :type game_object: GameObject + """ + + def __init__(self, game_object: GameObject): + self._game_object = game_object + + @property + def game_object(self) -> GameObject: + """The Game Object that was initialized. + + :return: The Game Object that was initialized. + :rtype: GameObject + """ + return self._game_object diff --git a/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_loaded.py b/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_loaded.py new file mode 100644 index 0000000..9eb0120 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_loaded.py @@ -0,0 +1,51 @@ +""" +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 +""" +from objects.game_object import GameObject +from sims4communitylib.events.event_handling.common_event import CommonEvent + + +class S4CLGameObjectLoadedEvent(CommonEvent): + """S4CLGameObjectLoadedEvent(game_object) + + An event that occurs after a Game Object has been loaded. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity().name) + def handle_event(event_data: S4CLGameObjectLoadedEvent): + pass + + :param game_object: The Game Object that was loaded. + :type game_object: GameObject + """ + + def __init__(self, game_object: GameObject): + self._game_object = game_object + + @property + def game_object(self) -> GameObject: + """The Game Object that was loaded. + + :return: The Game Object that was loaded. + :rtype: GameObject + """ + return self._game_object diff --git a/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_deleted.py b/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_deleted.py new file mode 100644 index 0000000..3fd8d8f --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_deleted.py @@ -0,0 +1,51 @@ +""" +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 +""" +from objects.game_object import GameObject +from sims4communitylib.events.event_handling.common_event import CommonEvent + + +class S4CLGameObjectPreDeletedEvent(CommonEvent): + """S4CLGameObjectPreDeletedEvent(game_object) + + An event that occurs before a Game Object has been deleted. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity().name) + def handle_event(event_data: S4CLGameObjectPreDeletedEvent): + pass + + :param game_object: The Game Object that will be deleted. + :type game_object: GameObject + """ + + def __init__(self, game_object: GameObject): + self._game_object = game_object + + @property + def game_object(self) -> GameObject: + """The Game Object that will be deleted. + + :return: The Game Object that will be deleted. + :rtype: GameObject + """ + return self._game_object diff --git a/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_despawned.py b/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_despawned.py new file mode 100644 index 0000000..c0b9eb4 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_despawned.py @@ -0,0 +1,51 @@ +""" +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 +""" +from objects.game_object import GameObject +from sims4communitylib.events.event_handling.common_event import CommonEvent + + +class S4CLGameObjectPreDespawnedEvent(CommonEvent): + """S4CLGameObjectPreDespawnedEvent(game_object) + + An event that occurs before an Object is despawned. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity().name) + def handle_event(event_data: S4CLGameObjectPreDespawnedEvent): + pass + + :param game_object: The Game Object that will be despawned. + :type game_object: GameObject + """ + + def __init__(self, game_object: GameObject): + self._game_object = game_object + + @property + def game_object(self) -> GameObject: + """The Game Object that will be despawned. + + :return: The Game Object that will be despawned. + :rtype: GameObject + """ + return self._game_object diff --git a/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_removed_from_game_object_inventory.py b/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_removed_from_game_object_inventory.py new file mode 100644 index 0000000..0f7fe7f --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_removed_from_game_object_inventory.py @@ -0,0 +1,83 @@ +""" +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 +""" +from objects.game_object import GameObject +from sims4communitylib.events.event_handling.common_event import CommonEvent +from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils + + +class S4CLGameObjectPreRemovedFromGameObjectInventoryEvent(CommonEvent): + """S4CLGameObjectPreRemovedFromGameObjectInventoryEvent(game_object, removed_game_object) + + An event that occurs before a Game Object is removed from the inventory of another Game Object. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity()) + def handle_event(event_data: S4CLGameObjectPreRemovedFromGameObjectInventoryEvent): + pass + + :param game_object: The Game Object that changed. + :type game_object: GameObject + :param removed_game_object: The Object that was removed from the inventory of the Game Object. + :type removed_game_object: GameObject + """ + + def __init__(self, game_object: GameObject, removed_game_object: GameObject): + self._game_object = game_object + self._removed_game_object = removed_game_object + + @property + def game_object(self) -> GameObject: + """The Game Object that is having the Game Object removed from its inventory. + + :return: The Game Object that is having the Game Object removed from its inventory. + :rtype: GameObject + """ + return self._game_object + + @property + def removed_game_object(self) -> GameObject: + """The Game Object that is being removed. + + :return: The Game Object that is being removed. + :rtype: GameObject + """ + return self._removed_game_object + + @property + def removed_game_object_id(self) -> int: + """The decimal identifier of the Game Object that is being removed. + + :return: The decimal identifier of the Game Object that is being removed. + :rtype: int + """ + return CommonObjectUtils.get_object_id(self.removed_game_object) + + @property + def removed_game_object_guid(self) -> int: + """The guid identifier of the Game Object that is being removed. + + :return: The guid identifier of the Game Object that is being removed. + :rtype: int + """ + # noinspection PyTypeChecker + return CommonObjectUtils.get_object_guid(self.removed_game_object) diff --git a/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_removed_from_inventory.py b/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_removed_from_inventory.py new file mode 100644 index 0000000..e15fb56 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_removed_from_inventory.py @@ -0,0 +1,51 @@ +""" +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 +""" +from objects.game_object import GameObject +from sims4communitylib.events.event_handling.common_event import CommonEvent + + +class S4CLGameObjectPreRemovedFromInventoryEvent(CommonEvent): + """S4CLGameObjectPreRemovedFromInventoryEvent(game_object) + + An event that occurs before a Game Object has been removed from the inventory of something. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity().name) + def handle_event(event_data: S4CLGameObjectPreRemovedFromInventoryEvent): + pass + + :param game_object: The Game Object that will be removed from the inventory of something. + :type game_object: GameObject + """ + + def __init__(self, game_object: GameObject): + self._game_object = game_object + + @property + def game_object(self) -> GameObject: + """The Game Object that will be removed from the inventory. + + :return: The Game Object that will be removed from the inventory. + :rtype: GameObject + """ + return self._game_object diff --git a/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_spawned.py b/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_spawned.py new file mode 100644 index 0000000..2290cee --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_spawned.py @@ -0,0 +1,51 @@ +""" +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 +""" +from objects.game_object import GameObject +from sims4communitylib.events.event_handling.common_event import CommonEvent + + +class S4CLGameObjectSpawnedEvent(CommonEvent): + """S4CLGameObjectSpawnedEvent(game_object) + + An event that occurs after a Game Object has been spawned. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity().name) + def handle_event(event_data: S4CLGameObjectSpawnedEvent): + pass + + :param game_object: The Game Object that was spawned. + :type game_object: GameObject + """ + + def __init__(self, game_object: GameObject): + self._game_object = game_object + + @property + def game_object(self) -> GameObject: + """The Game Object that was spawned. + + :return: The Game Object that was spawned. + :rtype: GameObject + """ + return self._game_object diff --git a/Scripts/s4ap/sims4communitylib/events/interaction/__init__.py b/Scripts/s4ap/sims4communitylib/events/interaction/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/interaction/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/events/interaction/common_interaction_event_dispatcher.py b/Scripts/s4ap/sims4communitylib/events/interaction/common_interaction_event_dispatcher.py new file mode 100644 index 0000000..f5c82d1 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/interaction/common_interaction_event_dispatcher.py @@ -0,0 +1,497 @@ +""" +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 +""" +import os +from pprint import pformat +from typing import Union, Any +from interactions.base.interaction import Interaction +from interactions.base.mixer_interaction import MixerInteraction +from interactions.base.super_interaction import SuperInteraction +from interactions.interaction_finisher import FinishingType +from interactions.interaction_queue import InteractionQueue +from interactions.utils.outcome import InteractionOutcome +from interactions.utils.outcome_enums import OutcomeResult +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry +from sims4communitylib.events.interaction.events.interaction_cancelled import S4CLInteractionCancelledEvent +from sims4communitylib.events.interaction.events.interaction_outcome import S4CLInteractionOutcomeEvent +from sims4communitylib.events.interaction.events.interaction_post_queued import S4CLInteractionPostQueuedEvent +from sims4communitylib.events.interaction.events.interaction_pre_run import S4CLInteractionPreRunEvent +from sims4communitylib.events.interaction.events.interaction_queued import S4CLInteractionQueuedEvent +from sims4communitylib.events.interaction.events.interaction_run import S4CLInteractionRunEvent +from sims4communitylib.events.interaction.events.interaction_started import S4CLInteractionStartedEvent +from sims4communitylib.events.interaction.events.mixer_interaction_cancelled import S4CLMixerInteractionCancelledEvent +from sims4communitylib.events.interaction.events.super_interaction_cancelled import S4CLSuperInteractionCancelledEvent +from sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler +from sims4communitylib.logging.has_log import HasLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.common_service import CommonService +from sims4communitylib.utils.common_injection_utils import CommonInjectionUtils +from sims4communitylib.utils.resources.common_interaction_utils import CommonInteractionUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + +ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' + +# If on Read The Docs, create fake versions of extended objects to fix the error of inheriting from multiple MockObjects. +if ON_RTD: + # noinspection PyMissingOrEmptyDocstring + class Timeline: + pass + +if not ON_RTD: + from scheduling import Timeline + + +class CommonInteractionEventDispatcherService(CommonService, HasLog): + """A service that dispatches interaction events (Run, Queued, Performed, etc.). + + .. warning:: Do not use this service directly to listen for events!\ + Use the :class:`.CommonEventRegistry` to listen for dispatched events. + + """ + + # noinspection PyMissingOrEmptyDocstring + @property + def mod_identity(self) -> CommonModIdentity: + return ModInfo.get_identity() + + # noinspection PyUnusedLocal + def _on_interaction_pre_run(self, interaction_queue: InteractionQueue, timeline: Timeline, interaction: Interaction, *_, **__) -> Union[bool, None]: + if interaction is None or interaction.sim is None: + return None + try: + if not CommonEventRegistry().dispatch(S4CLInteractionPreRunEvent(interaction, interaction_queue, timeline)): + return False + except Exception as ex: + CommonExceptionHandler.log_exception( + None, + 'Error occurred while running _on_interaction_pre_run for interaction {} with short name \'{}\' and display name {}. (This exception is not caused by S4CL, but rather caught) Args: {}, Kwargs: {}' + .format( + pformat(interaction), + CommonInteractionUtils.get_interaction_short_name(interaction), + CommonInteractionUtils.get_interaction_display_name(interaction), + _, + __ + ), + exception=ex + ) + return None + + # noinspection PyUnusedLocal + def _on_interaction_run(self, interaction_queue: InteractionQueue, timeline: Timeline, interaction: Interaction, run_result: bool, *_, **__) -> None: + if interaction is None or interaction.sim is None: + return None + try: + CommonEventRegistry().dispatch(S4CLInteractionRunEvent(interaction, interaction_queue, run_result)) + except Exception as ex: + CommonExceptionHandler.log_exception( + None, + 'Error occurred while running _on_interaction_run for interaction {} with short name \'{}\' and display name {}. (This exception is not caused by S4CL, but rather caught) Original Run Result: {}, Args: {}, Kwargs: {}'.format( + pformat(interaction), + CommonInteractionUtils.get_interaction_short_name(interaction), + CommonInteractionUtils.get_interaction_display_name(interaction), + str(run_result), + _, + __ + ), + exception=ex + ) + return None + + # noinspection PyUnusedLocal + def _on_interaction_started(self, interaction: Interaction, *_, **__) -> None: + if interaction is None or interaction.sim is None: + return None + try: + source_sim_info = CommonSimUtils.get_sim_info(interaction.sim) + target = interaction.target + CommonEventRegistry().dispatch(S4CLInteractionStartedEvent(interaction, source_sim_info, target)) + except Exception as ex: + CommonExceptionHandler.log_exception( + None, + 'Error occurred while running _on_interaction_started for interaction {} with short name \'{}\' and display name {}. (This exception is not caused by S4CL, but rather caught) Args: {}, Kwargs: {}'.format( + pformat(interaction), + CommonInteractionUtils.get_interaction_short_name(interaction), + CommonInteractionUtils.get_interaction_display_name(interaction), + _, + __ + ), + exception=ex + ) + return None + + def _on_interaction_queued(self, interaction_queue: InteractionQueue, interaction: Interaction, *_, **__) -> Union[CommonTestResult, None]: + if interaction is None or interaction.sim is None: + return None + try: + if not CommonEventRegistry().dispatch(S4CLInteractionQueuedEvent(interaction, interaction_queue)): + return CommonTestResult(False, reason='Interaction \'{}\' Failed to Queue'.format(pformat(interaction))) + except Exception as ex: + CommonExceptionHandler.log_exception( + None, + 'Error occurred while running _on_interaction_queued for interaction {} with short name \'{}\' and display name {}. (This exception is not caused by S4CL, but rather caught) Args: {}, Kwargs: {}'.format( + pformat(interaction), + CommonInteractionUtils.get_interaction_short_name(interaction), + CommonInteractionUtils.get_interaction_display_name(interaction), + _, + __ + ), + exception=ex + ) + return None + + def _on_interaction_post_queued(self, interaction_queue: InteractionQueue, interaction: Interaction, queue_result: CommonTestResult, *_, **__) -> None: + if interaction is None or interaction.sim is None: + return None + try: + CommonEventRegistry().dispatch(S4CLInteractionPostQueuedEvent(interaction, interaction_queue, queue_result)) + except Exception as ex: + CommonExceptionHandler.log_exception( + None, + 'Error occurred while running _on_interaction_post_queued for interaction {} with short name \'{}\' and display name {}. (This exception is not caused by S4CL, but rather caught) Queue Result: {}, Args: {}, Kwargs: {}'.format( + pformat(interaction), + CommonInteractionUtils.get_interaction_short_name(interaction), + CommonInteractionUtils.get_interaction_display_name(interaction), + queue_result, + _, + __ + ), + exception=ex + ) + return None + + def _on_interaction_outcome(self, interaction: Interaction, outcome: InteractionOutcome, result: OutcomeResult) -> None: + if interaction.sim is None: + return None + try: + CommonEventRegistry().dispatch(S4CLInteractionOutcomeEvent(interaction, outcome, result)) + except Exception as ex: + CommonExceptionHandler.log_exception( + None, + 'Error occurred while running _on_interaction_outcome for interaction {} with short name \'{}\' and display name {}. (This exception is not caused by S4CL, but rather caught) Outcome: {}, Result: {}'.format( + pformat(interaction), + CommonInteractionUtils.get_interaction_short_name(interaction), + CommonInteractionUtils.get_interaction_display_name(interaction), + outcome, + result + ), + exception=ex + ) + return None + + def _on_interaction_cancelled(self, interaction: Interaction, finishing_type: FinishingType, cancel_reason_msg: str, ignore_must_run: bool=False, **__) -> None: + if finishing_type is None: + return None + try: + CommonEventRegistry().dispatch(S4CLInteractionCancelledEvent(interaction, finishing_type, cancel_reason_msg, ignore_must_run=ignore_must_run, **__)) + except Exception as ex: + CommonExceptionHandler.log_exception( + None, + 'Error occurred while running _on_interaction_cancelled for interaction {} with short name \'{}\' and display name {}. (This exception is not caused by S4CL, but rather caught) Finishing Type: {}, Cancel Reason: {}, Ignore Must Run: {}, Kwargs: {}'.format( + pformat(interaction), + CommonInteractionUtils.get_interaction_short_name(interaction), + CommonInteractionUtils.get_interaction_display_name(interaction), + finishing_type, + cancel_reason_msg, + ignore_must_run, + __ + ), + exception=ex + ) + return None + + def _on_mixer_interaction_cancelled(self, interaction: MixerInteraction, finishing_type: FinishingType, cancel_reason_msg: str, **__) -> None: + if finishing_type is None: + return None + try: + CommonEventRegistry().dispatch(S4CLMixerInteractionCancelledEvent(interaction, finishing_type, cancel_reason_msg, **__)) + except Exception as ex: + CommonExceptionHandler.log_exception( + None, + 'Error occurred while running _on_mixer_interaction_cancelled for interaction {} with short name \'{}\' and display name {}. (This exception is not caused by S4CL, but rather caught) Finishing Type: {}, Cancel Reason: {}, Kwargs: {}'.format( + pformat(interaction), + CommonInteractionUtils.get_interaction_short_name(interaction), + CommonInteractionUtils.get_interaction_display_name(interaction), + finishing_type, + cancel_reason_msg, + __ + ), + exception=ex + ) + return None + + def _on_super_interaction_cancelled(self, interaction: SuperInteraction, finishing_type: FinishingType, cancel_reason_msg: str, **__) -> None: + if interaction is None or finishing_type is None: + return None + try: + CommonEventRegistry().dispatch(S4CLSuperInteractionCancelledEvent(interaction, finishing_type, cancel_reason_msg, **__)) + except Exception as ex: + CommonExceptionHandler.log_exception( + None, + 'Error occurred while running _on_super_interaction_cancelled for interaction {} with short name \'{}\' and display name {}. (This exception is not caused by S4CL, but rather caught) Finishing Type: {}, Cancel Reason: {}, Kwargs: {}'.format( + pformat(interaction), + CommonInteractionUtils.get_interaction_short_name(interaction), + CommonInteractionUtils.get_interaction_display_name(interaction), + finishing_type, + cancel_reason_msg, + __ + ), + exception=ex + ) + return None + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), InteractionQueue, InteractionQueue.run_interaction_gen.__name__) +def _common_on_interaction_run(original, self, timeline: Timeline, interaction: Interaction, *_, **__) -> bool: + try: + result = CommonInteractionEventDispatcherService()._on_interaction_pre_run(self, timeline, interaction, *_, **__) + if result is None or result: + try: + original_result = original(self, timeline, interaction, *_, **__) + except Exception as ex: + CommonExceptionHandler.log_exception( + None, + 'Error occurred while running _on_interaction_run for interaction {} with short name \'{}\' and display name {}. (This exception is not caused by S4CL, but rather caught) Args: {}, Kwargs: {}'.format( + pformat(interaction), + CommonInteractionUtils.get_interaction_short_name(interaction), + CommonInteractionUtils.get_interaction_display_name(interaction), + _, + __ + ), + exception=ex + ) + return False + CommonInteractionEventDispatcherService()._on_interaction_run(self, timeline, interaction, original_result, *_, **__) + return original_result + return result + except Exception as ex: + CommonExceptionHandler.log_exception( + ModInfo.get_identity(), + 'Error occurred while running _on_interaction_run for interaction {} with short name \'{}\' and display name {}. Args: {}, Kwargs: {}'.format( + pformat(interaction), + CommonInteractionUtils.get_interaction_short_name(interaction), + CommonInteractionUtils.get_interaction_display_name(interaction), + _, + __ + ), + exception=ex + ) + return False + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), Interaction, Interaction._trigger_interaction_start_event.__name__) +def _common_on_interaction_started(original, self, *_, **__) -> bool: + try: + try: + original_result = original(self, *_, **__) + except Exception as ex: + CommonExceptionHandler.log_exception( + None, + 'Error occurred while running _trigger_interaction_start_event for interaction {} with short name \'{}\' and display name {}. (This exception is not caused by S4CL, but rather caught) Args: {}, Kwargs: {}'.format( + pformat(self), + CommonInteractionUtils.get_interaction_short_name(self), + CommonInteractionUtils.get_interaction_display_name(self), + _, + __ + ), + exception=ex + ) + return False + CommonInteractionEventDispatcherService()._on_interaction_started(self, *_, **__) + return original_result + except Exception as ex: + CommonExceptionHandler.log_exception( + ModInfo.get_identity(), + 'Error occurred while running _trigger_interaction_start_event for interaction {} with short name \'{}\' and display name {}. Args: {}, Kwargs: {}'.format( + pformat(self), + CommonInteractionUtils.get_interaction_short_name(self), + CommonInteractionUtils.get_interaction_display_name(self), + _, + __ + ), + exception=ex + ) + return False + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), InteractionQueue, InteractionQueue.append.__name__) +def _common_on_interaction_queued(original, self, interaction: Interaction, *_, **__) -> CommonTestResult: + try: + result = CommonInteractionEventDispatcherService()._on_interaction_queued(self, interaction, *_, **__) + if result is None or result: + try: + original_result = original(self, interaction, *_, **__) + except Exception as ex: + CommonExceptionHandler.log_exception( + None, + 'Error occurred while running _on_interaction_queued for interaction {} with short name \'{}\' and display name {}. (This exception is not caused by S4CL, but rather caught) Args: {}, Kwargs: {}'.format( + pformat(interaction), + CommonInteractionUtils.get_interaction_short_name(interaction), + CommonInteractionUtils.get_interaction_display_name(interaction), + _, + __ + ), + exception=ex + ) + return CommonTestResult.NONE + original_result: CommonTestResult = CommonTestResult.convert_from_vanilla(original_result) + CommonInteractionEventDispatcherService()._on_interaction_post_queued(self, interaction, original_result, *_, **__) + return original_result + return result + except Exception as ex: + CommonExceptionHandler.log_exception( + ModInfo.get_identity(), + 'Error occurred while running _on_interaction_queued for interaction {} with short name \'{}\' and display name {}. Args: {}, Kwargs: {}'.format( + pformat(interaction), + CommonInteractionUtils.get_interaction_short_name(interaction), + CommonInteractionUtils.get_interaction_display_name(interaction), + _, + __ + ), + exception=ex + ) + return CommonTestResult(False, reason='Interaction \'{}\' with short name \'{}\' Failed to Queue'.format( + pformat(interaction), + CommonInteractionUtils.get_interaction_short_name(interaction) + )) + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), Interaction, Interaction.store_result_for_outcome.__name__) +def _common_on_interaction_outcome(original, self, *_, **__) -> Any: + try: + CommonInteractionEventDispatcherService()._on_interaction_outcome(self, *_, **__) + except Exception as ex: + CommonExceptionHandler.log_exception( + ModInfo.get_identity(), + 'Error occurred while running _on_interaction_outcome for interaction {} with short name \'{}\' and display name {}. Args: {}, Kwargs: {}'.format( + pformat(self), + CommonInteractionUtils.get_interaction_short_name(self), + CommonInteractionUtils.get_interaction_display_name(self), + _, + __ + ), + exception=ex + ) + + try: + return original(self, *_, **__) + except Exception as ex: + CommonExceptionHandler.log_exception( + None, + 'Error occurred while running _on_interaction_outcome for interaction {} with short name \'{}\' and display name {}. (This exception is not caused by S4CL, but rather caught) Args: {}, Kwargs: {}'.format( + pformat(self), + CommonInteractionUtils.get_interaction_short_name(self), + CommonInteractionUtils.get_interaction_display_name(self), + _, + __ + ), + exception=ex + ) + return False + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), Interaction, Interaction.cancel.__name__) +def _common_on_interaction_cancelled(original, self, *_, **__) -> Any: + try: + CommonInteractionEventDispatcherService()._on_interaction_cancelled(self, *_, **__) + except Exception as ex: + CommonExceptionHandler.log_exception( + ModInfo.get_identity(), + 'Error occurred while running _on_interaction_cancelled for interaction {} with short name \'{}\' and display name {}. Args: {}, Kwargs: {}'.format( + pformat(self), + CommonInteractionUtils.get_interaction_short_name(self), + CommonInteractionUtils.get_interaction_display_name(self), + _, + __ + ), + exception=ex + ) + + try: + return original(self, *_, **__) + except Exception as ex: + CommonExceptionHandler.log_exception( + None, + 'Error occurred while running _on_interaction_cancelled for interaction {} with short name \'{}\' and display name {}. (This exception is not caused by S4CL, but rather caught) Args: {}, Kwargs: {}'.format( + pformat(self), + CommonInteractionUtils.get_interaction_short_name(self), + CommonInteractionUtils.get_interaction_display_name(self), + _, + __ + ), + exception=ex + ) + return False + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), MixerInteraction, MixerInteraction.cancel.__name__) +def _common_on_mixer_interaction_cancelled(original, self, *_, **__) -> Any: + try: + CommonInteractionEventDispatcherService()._on_mixer_interaction_cancelled(self, *_, **__) + except Exception as ex: + CommonExceptionHandler.log_exception( + ModInfo.get_identity(), + 'Error occurred while running _on_mixer_interaction_cancelled for interaction {} with short name \'{}\' and display name {}. Args: {}, Kwargs: {}'.format( + pformat(self), + CommonInteractionUtils.get_interaction_short_name(self), + CommonInteractionUtils.get_interaction_display_name(self), + _, + __ + ), + exception=ex + ) + + try: + return original(self, *_, **__) + except Exception as ex: + CommonExceptionHandler.log_exception( + None, + 'Error occurred while running _on_mixer_interaction_cancelled for interaction {} with short name \'{}\' and display name {}. (This exception is not caused by S4CL, but rather caught) Args: {}, Kwargs: {}'.format( + pformat(self), + CommonInteractionUtils.get_interaction_short_name(self), + CommonInteractionUtils.get_interaction_display_name(self), + _, + __ + ), + exception=ex + ) + return False + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), SuperInteraction, SuperInteraction.cancel.__name__) +def _common_on_super_interaction_cancelled(original, self, *_, **__) -> Any: + try: + CommonInteractionEventDispatcherService()._on_super_interaction_cancelled(self, *_, **__) + except Exception as ex: + CommonExceptionHandler.log_exception( + ModInfo.get_identity(), + 'Error occurred while running _on_super_interaction_cancelled for interaction {} with short name \'{}\' and display name {}. Args: {}, Kwargs: {}'.format( + pformat(self), + CommonInteractionUtils.get_interaction_short_name(self), + CommonInteractionUtils.get_interaction_display_name(self), + _, + __ + ), + exception=ex + ) + + try: + return original(self, *_, **__) + except Exception as ex: + CommonExceptionHandler.log_exception( + None, + 'Error occurred while running _on_super_interaction_cancelled for interaction {} with short name \'{}\' and display name {}. (This exception is not caused by S4CL, but rather caught) Args: {}, Kwargs: {}'.format( + pformat(self), + CommonInteractionUtils.get_interaction_short_name(self), + CommonInteractionUtils.get_interaction_display_name(self), + _, + __ + ), + exception=ex + ) + return None diff --git a/Scripts/s4ap/sims4communitylib/events/interaction/events/__init__.py b/Scripts/s4ap/sims4communitylib/events/interaction/events/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/interaction/events/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_cancelled.py b/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_cancelled.py new file mode 100644 index 0000000..7c47e60 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_cancelled.py @@ -0,0 +1,102 @@ +""" +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 +""" +from typing import Any, Dict +from interactions.base.interaction import Interaction +from interactions.interaction_finisher import FinishingType +from sims4communitylib.events.event_handling.common_event import CommonEvent + + +class S4CLInteractionCancelledEvent(CommonEvent): + """S4CLInteractionCancelledEvent(interaction, finishing_type, cancel_reason, ignore_must_run=False, **kwargs) + + An event that occurs upon an interaction being cancelled. + + .. note:: This event fires BEFORE the interaction is actually cancelled. Like a Pre-Cancel. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name or identity of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity()) + def handle_event(event_data: S4CLInteractionCancelledEvent) -> bool: + # Return True from here to signify the event listener ran successfully. Return False or None here to signify the event listener failed to run successfully. + return True + + :param interaction: The interaction that is being cancelled. + :type interaction: Interaction + :param finishing_type: The finishing type of the interaction. + :type finishing_type: FinishingType + :param cancel_reason_msg: The reason the interaction was cancelled. + :type cancel_reason_msg: str + :param ignore_must_run: If True, interactions flagged as "Must Run" will be ignored. Default is False. + :type ignore_must_run: bool, optional + """ + + def __init__(self, interaction: Interaction, finishing_type: FinishingType, cancel_reason: str, ignore_must_run: bool=False, **kwargs): + self._interaction = interaction + self._finishing_type = finishing_type + self._cancel_reason = cancel_reason + self._ignore_must_run = ignore_must_run + self._kwargs = kwargs + + @property + def interaction(self) -> Interaction: + """The interaction that is being cancelled. + + :return: The interaction that is being cancelled. + :rtype: Interaction + """ + return self._interaction + + @property + def finishing_type(self) -> FinishingType: + """The finishing type of the interaction. + + :return: The finishing type of the interaction. + :rtype: FinishingType + """ + return self._finishing_type + + @property + def cancel_reason(self) -> str: + """The reason the interaction was cancelled. + + :return: The reason the interaction was cancelled. + :rtype: str + """ + return self._cancel_reason + + @property + def ignore_must_run(self) -> bool: + """Whether or not interactions flagged as "Must Run" will be cancelled. + + :return: If True, interactions flagged as "Must Run" will be cancelled. If False, interactions flagged as "Must Run" will not be cancelled. + :rtype: bool + """ + return self._ignore_must_run + + @property + def keyword_arguments(self) -> Dict[str, Any]: + """Keyword arguments sent to the cancelled interaction. + + :return: Keyword arguments sent to the cancelled interaction. + :rtype: Dict[str, Any] + """ + return self._kwargs diff --git a/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_outcome.py b/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_outcome.py new file mode 100644 index 0000000..3628c53 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_outcome.py @@ -0,0 +1,94 @@ +""" +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 +""" +from interactions.base.interaction import Interaction +from interactions.utils.outcome import InteractionOutcome +from interactions.utils.outcome_enums import OutcomeResult +from sims4communitylib.events.event_handling.common_event import CommonEvent + + +class S4CLInteractionOutcomeEvent(CommonEvent): + """S4CLInteractionOutcomeEvent(interaction, outcome, outcome_result) + + An event that occurs after a Sim has performed an interaction. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name or identity of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity()) + def handle_event(event_data: S4CLInteractionOutcomeEvent) -> bool: + # Return True from here to signify the event listener ran successfully. Return False or None here to signify the event listener failed to run. + return True + + :param interaction: The interaction that was performed. + :type interaction: Interaction + :param outcome: The outcome of the interaction that was performed. + :type outcome: InteractionOutcome + :param outcome_result: The result of the interaction that was performed. + :type outcome_result: OutcomeResult + """ + + def __init__(self, interaction: Interaction, outcome: InteractionOutcome, outcome_result: OutcomeResult): + self._interaction = interaction + self._outcome = outcome + self._outcome_result = outcome_result + + @property + def interaction(self) -> Interaction: + """The interaction that was performed. + + :return: The interaction that was performed. + :rtype: Interaction + """ + return self._interaction + + @property + def outcome(self) -> InteractionOutcome: + """The outcome of the interaction that was performed. + + :return: The outcome of the interaction that was performed. + :rtype: InteractionOutcome + """ + return self._outcome + + @property + def outcome_result(self) -> OutcomeResult: + """The result of the interaction that was performed. + + :return: The result of the interaction that was performed. + :rtype: OutcomeResult + """ + return self._outcome_result + + def is_success(self) -> bool: + """Determine if the outcome was a success. + + :return: True, if the interaction was performed successfully. False, if the interaction was not performed successfully. + :rtype: bool + """ + return self.outcome_result == OutcomeResult.SUCCESS + + def is_failure(self) -> bool: + """Determine if the outcome was a failure. + + :return: True, if the interaction was not performed successfully. False, if the interaction was performed successfully. + :rtype: bool + """ + return self.outcome_result == OutcomeResult.FAILURE diff --git a/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_post_queued.py b/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_post_queued.py new file mode 100644 index 0000000..3c8e541 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_post_queued.py @@ -0,0 +1,80 @@ +""" +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 +""" +from interactions.base.interaction import Interaction +from interactions.interaction_queue import InteractionQueue +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.events.event_handling.common_event import CommonEvent + + +class S4CLInteractionPostQueuedEvent(CommonEvent): + """S4CLInteractionPostQueuedEvent(interaction, interaction_queue, queue_result) + + An event that occurs after a Sim adds an interaction to their interaction queue. + + .. note:: This event fires AFTER the interaction is actually queued. Like a Post-Queue. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name or identity of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity()) + def handle_event(event_data: S4CLInteractionPostQueuedEvent) -> bool: + # Return True here to signify the event listener ran successfully. Return False or None here to signify the event listener failed to run. + return True + + :param interaction: The interaction that was queued. + :type interaction: Interaction + :param interaction_queue: The interaction queue of the Sim. + :type interaction_queue: InteractionQueue + :param queue_result: The result of the interaction being Queued. + :type queue_result: CommonTestResult + """ + + def __init__(self, interaction: Interaction, interaction_queue: InteractionQueue, queue_result: CommonTestResult): + self._interaction = interaction + self._interaction_queue = interaction_queue + self._queue_result = queue_result + + @property + def interaction(self) -> Interaction: + """The interaction that was queued. + + :return: The interaction that was queued. + :rtype: Interaction + """ + return self._interaction + + @property + def interaction_queue(self) -> InteractionQueue: + """The interaction queue of the Sim that queued the interaction. + + :return: The interaction queue of the Sim that queued the interaction. + :rtype: InteractionQueue + """ + return self._interaction_queue + + @property + def queue_result(self) -> CommonTestResult: + """The result of the interaction being Queued. + + :return: The result of the interaction being Queued. + :rtype: CommonTestResult + """ + return self._queue_result diff --git a/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_pre_run.py b/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_pre_run.py new file mode 100644 index 0000000..bcdf0f4 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_pre_run.py @@ -0,0 +1,91 @@ +""" +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 +""" +import os +from interactions.base.interaction import Interaction +from interactions.interaction_queue import InteractionQueue +from sims4communitylib.events.event_handling.common_event import CommonEvent + +ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' + +# If on Read The Docs, create fake versions of extended objects to fix the error of inheriting from multiple MockObjects. +if ON_RTD: + # noinspection PyMissingOrEmptyDocstring + class Timeline: + pass + +if not ON_RTD: + from scheduling import Timeline + + +class S4CLInteractionPreRunEvent(CommonEvent): + """S4CLInteractionPreRunEvent(interaction, interaction_queue, timeline) + + An event that occurs upon a Sim running an interaction. + + .. note:: This event fires BEFORE the interaction is actually run. Like a Pre-Run. If False or None is returned from any of the listeners of this event, the interaction will be prevented from running; All subsequent listeners will still receive the event, but their return will be ignored. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name or identity of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity()) + def handle_event(event_data: S4CLInteractionPreRunEvent) -> bool: + # Return True here to allow the interaction to run and to signify the event listener ran successfully. Return False or None here to prevent the interaction from being run or to signify the event listener failed to run. + return True + + :param interaction: The interaction that is being run. + :type interaction: Interaction + :param interaction_queue: The interaction queue of the Sim. + :type interaction_queue: InteractionQueue + :param timeline: The timeline of the interaction. + :type timeline: Timeline + """ + + def __init__(self, interaction: Interaction, interaction_queue: InteractionQueue, timeline: Timeline): + self._interaction = interaction + self._interaction_queue = interaction_queue + self._timeline = timeline + + @property + def interaction(self) -> Interaction: + """The interaction that is being run. + + :return: The interaction that is being run. + :rtype: Interaction + """ + return self._interaction + + @property + def interaction_queue(self) -> InteractionQueue: + """The interaction queue of the Sim that is running the interaction. + + :return: The interaction queue of the Sim that is running the interaction. + :rtype: InteractionQueue + """ + return self._interaction_queue + + @property + def timeline(self) -> Timeline: + """The timeline of the interaction. + + :return: The timeline of the interaction. + :rtype: Timeline + """ + return self._timeline diff --git a/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_queued.py b/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_queued.py new file mode 100644 index 0000000..dc2cebf --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_queued.py @@ -0,0 +1,84 @@ +""" +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 +""" +from typing import Union + +from interactions.base.interaction import Interaction +from interactions.interaction_queue import InteractionQueue +from sims.sim import Sim +from sims.sim_info import SimInfo +from sims4communitylib.events.event_handling.common_event import CommonEvent +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + + +class S4CLInteractionQueuedEvent(CommonEvent): + """S4CLInteractionQueuedEvent(interaction, interaction_queue) + + An event that occurs upon a Sim adding an interaction to their interaction queue. + + .. note:: This event fires BEFORE the interaction is actually queued. Like a Pre-Queue. If False or None is returned from any of the listeners of this event, the interaction will be prevented from queuing; All subsequent listeners will still receive the event, but their return will be ignored. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name or identity of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity()) + def handle_event(event_data: S4CLInteractionQueuedEvent) -> bool: + # Return True here to allow the interaction to queue and to signify the event listener ran successfully. Return False or None here to prevent the interaction from being queued or to signify the event listener failed to run. + return True + + :param interaction: The interaction that is being queued. + :type interaction: Interaction + :param interaction_queue: The interaction queue of the Sim. + :type interaction_queue: InteractionQueue + """ + + def __init__(self, interaction: Interaction, interaction_queue: InteractionQueue): + self._interaction = interaction + self._interaction_queue = interaction_queue + + @property + def queuing_sim(self) -> Union[Sim, None]: + """The Sim that is putting the interaction into their queue.""" + if self._interaction is None: + return None + return self._interaction.context.sim + + @property + def queuing_sim_info(self) -> Union[SimInfo, None]: + """The SimInfo of the Sim that is putting the interaction into their queue.""" + return CommonSimUtils.get_sim_info(self.queuing_sim) + + @property + def interaction(self) -> Interaction: + """The interaction that is being queued. + + :return: The interaction that was queued. + :rtype: Interaction + """ + return self._interaction + + @property + def interaction_queue(self) -> InteractionQueue: + """The interaction queue of the Sim that is queuing the interaction. + + :return: The interaction queue of the Sim that is queuing the interaction. + :rtype: InteractionQueue + """ + return self._interaction_queue diff --git a/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_run.py b/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_run.py new file mode 100644 index 0000000..e767e3d --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_run.py @@ -0,0 +1,79 @@ +""" +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 +""" +from interactions.base.interaction import Interaction +from interactions.interaction_queue import InteractionQueue +from sims4communitylib.events.event_handling.common_event import CommonEvent + + +class S4CLInteractionRunEvent(CommonEvent): + """S4CLInteractionRunEvent(interaction, interaction_queue, run_result) + + An event that occurs after a Sim has run an interaction. + + .. note:: This event fires AFTER the interaction is actually run. Like a Post-Run. If False or None is returned from any of the listeners of this event, the interaction will be prevented from running; All subsequent listeners will still receive the event, but their return will be ignored. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name or identity of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity()) + def handle_event(event_data: S4CLInteractionRunEvent) -> bool: + # Return True here to signify the event listener ran successfully. Return False or None here to signify the event listener failed to run. + return True + + :param interaction: The interaction that was run. + :type interaction: Interaction + :param interaction_queue: The interaction queue of the Sim. + :type interaction_queue: InteractionQueue + :param run_result: The result of the interaction being run. + :type run_result: bool + """ + + def __init__(self, interaction: Interaction, interaction_queue: InteractionQueue, run_result: bool): + self._interaction = interaction + self._interaction_queue = interaction_queue + self._run_result = run_result + + @property + def interaction(self) -> Interaction: + """The interaction that was run. + + :return: The interaction that was run. + :rtype: Interaction + """ + return self._interaction + + @property + def interaction_queue(self) -> InteractionQueue: + """The interaction queue of the Sim that ran the interaction. + + :return: The interaction queue of the Sim ran the interaction. + :rtype: InteractionQueue + """ + return self._interaction_queue + + @property + def run_result(self) -> bool: + """The result of the interaction being run. + + :return: True, if the interaction was run successfully. False, if not. + :rtype: bool + """ + return self._run_result diff --git a/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_started.py b/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_started.py new file mode 100644 index 0000000..794227e --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_started.py @@ -0,0 +1,71 @@ +""" +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 +""" +from typing import Any + +from interactions.base.interaction import Interaction +from sims.sim_info import SimInfo +from sims4communitylib.events.event_handling.common_event import CommonEvent + + +class S4CLInteractionStartedEvent(CommonEvent): + """S4CLInteractionStartedEvent(interaction, sim_info, target) + + An event that occurs when a Sim has started an interaction. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name or identity of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity()) + def handle_event(event_data: S4CLInteractionStartedEvent) -> bool: + # Return True here to signify the event listener ran successfully. Return False or None here to signify the event listener failed to run. + return True + + :param interaction: The interaction that was run. + :type interaction: Interaction + :param sim_info: The Sim doing the interaction. + :type sim_info: SimInfo + :param target: The Target of the interaction. + :type target: Any + """ + + def __init__(self, interaction: Interaction, sim_info: SimInfo, target: Any): + self._sim_info = sim_info + self._target = target + self._interaction = interaction + + @property + def interaction(self) -> Interaction: + """The interaction that was run. + + :return: The interaction that was run. + :rtype: Interaction + """ + return self._interaction + + @property + def sim_info(self) -> SimInfo: + """The Sim that started the interaction.""" + return self._sim_info + + @property + def target(self) -> Any: + """The target of the interaction.""" + return self._target diff --git a/Scripts/s4ap/sims4communitylib/events/interaction/events/mixer_interaction_cancelled.py b/Scripts/s4ap/sims4communitylib/events/interaction/events/mixer_interaction_cancelled.py new file mode 100644 index 0000000..d941604 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/interaction/events/mixer_interaction_cancelled.py @@ -0,0 +1,90 @@ +""" +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 +""" +from typing import Any, Dict +from interactions.base.mixer_interaction import MixerInteraction +from interactions.interaction_finisher import FinishingType +from sims4communitylib.events.event_handling.common_event import CommonEvent + + +class S4CLMixerInteractionCancelledEvent(CommonEvent): + """S4CLMixerInteractionCancelledEvent(interaction, finishing_type, cancel_reason_msg, **kwargs) + + An event that occurs upon a mixer interaction being cancelled. + + .. note:: This event fires BEFORE the mixer interaction is actually cancelled. Like a Pre-Cancel. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name or identity of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity()) + def handle_event(event_data: S4CLMixerInteractionCancelledEvent) -> bool: + # Return True from here to signify the event listener ran successfully. Return False or None here to signify the event listener failed to run successfully. + return True + + :param interaction: The mixer interaction that is being cancelled. + :type interaction: MixerInteraction + :param finishing_type: The finishing type of the interaction. + :type finishing_type: FinishingType + :param cancel_reason_msg: The reason the interaction was cancelled. + :type cancel_reason_msg: str + """ + + def __init__(self, interaction: MixerInteraction, finishing_type: FinishingType, cancel_reason: str, **kwargs): + self._interaction = interaction + self._finishing_type = finishing_type + self._cancel_reason = cancel_reason + self._kwargs = kwargs + + @property + def interaction(self) -> MixerInteraction: + """The mixer interaction that is being cancelled. + + :return: The mixer interaction that is being cancelled. + :rtype: MixerInteraction + """ + return self._interaction + + @property + def finishing_type(self) -> FinishingType: + """The finishing type of the interaction. + + :return: The finishing type of the interaction. + :rtype: FinishingType + """ + return self._finishing_type + + @property + def cancel_reason(self) -> str: + """The reason the interaction was cancelled. + + :return: The reason the interaction was cancelled. + :rtype: str + """ + return self._cancel_reason + + @property + def keyword_arguments(self) -> Dict[str, Any]: + """Keyword arguments sent to the cancelled interaction. + + :return: Keyword arguments sent to the cancelled interaction. + :rtype: Dict[str, Any] + """ + return self._kwargs diff --git a/Scripts/s4ap/sims4communitylib/events/interaction/events/super_interaction_cancelled.py b/Scripts/s4ap/sims4communitylib/events/interaction/events/super_interaction_cancelled.py new file mode 100644 index 0000000..edc317c --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/interaction/events/super_interaction_cancelled.py @@ -0,0 +1,90 @@ +""" +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 +""" +from typing import Any, Dict +from interactions.base.super_interaction import SuperInteraction +from interactions.interaction_finisher import FinishingType +from sims4communitylib.events.event_handling.common_event import CommonEvent + + +class S4CLSuperInteractionCancelledEvent(CommonEvent): + """S4CLSuperInteractionCancelledEvent(interaction, finishing_type, cancel_reason_msg, **kwargs) + + An event that occurs upon a super interaction being cancelled. + + .. note:: This event fires BEFORE the super interaction is actually cancelled. Like a Pre-Cancel. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name or identity of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity()) + def handle_event(event_data: S4CLSuperInteractionCancelledEvent) -> bool: + # Return True from here to signify the event listener ran successfully. Return False or None here to signify the event listener failed to run successfully. + return True + + :param interaction: The super interaction that is being cancelled. + :type interaction: SuperInteraction + :param finishing_type: The finishing type of the interaction. + :type finishing_type: FinishingType + :param cancel_reason_msg: The reason the interaction was cancelled. + :type cancel_reason_msg: str + """ + + def __init__(self, interaction: SuperInteraction, finishing_type: FinishingType, cancel_reason: str, **kwargs): + self._interaction = interaction + self._finishing_type = finishing_type + self._cancel_reason = cancel_reason + self._kwargs = kwargs + + @property + def interaction(self) -> SuperInteraction: + """The super interaction that is being cancelled. + + :return: The super interaction that is being cancelled. + :rtype: SuperInteraction + """ + return self._interaction + + @property + def finishing_type(self) -> FinishingType: + """The finishing type of the interaction. + + :return: The finishing type of the interaction. + :rtype: FinishingType + """ + return self._finishing_type + + @property + def cancel_reason(self) -> str: + """The reason the interaction was cancelled. + + :return: The reason the interaction was cancelled. + :rtype: str + """ + return self._cancel_reason + + @property + def keyword_arguments(self) -> Dict[str, Any]: + """Keyword arguments sent to the cancelled interaction. + + :return: Keyword arguments sent to the cancelled interaction. + :rtype: Dict[str, Any] + """ + return self._kwargs diff --git a/Scripts/s4ap/sims4communitylib/events/interval/__init__.py b/Scripts/s4ap/sims4communitylib/events/interval/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/interval/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/events/interval/common_interval_event_service.py b/Scripts/s4ap/sims4communitylib/events/interval/common_interval_event_service.py new file mode 100644 index 0000000..20c9926 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/interval/common_interval_event_service.py @@ -0,0 +1,241 @@ +""" +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 +""" +from typing import Callable, Any, List, Union +from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry +from sims4communitylib.events.zone_update.events.zone_update_event import S4CLZoneUpdateEvent +from sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.common_service import CommonService + + +class CommonIntervalDispatcher: + """CommonIntervalDispatcher(mod_identifier, milliseconds, listening_func, run_once=False) + + A dispatcher that invokes a callback based on the amount of time passed. + + .. note:: The dispatcher will only keep track of the amount of time passed while the game was not paused.\ + It will never dispatch while the game is paused. + + :param mod_identifier: The name or identity of the mod the dispatcher belongs to. + :type mod_identifier: Union[str, CommonModIdentity] + :param milliseconds: The number of milliseconds that need to pass before `listening_func` will be invoked. + :type milliseconds: int + :param listening_func: A callback invoked after an amount of time has passed. + :type listening_func: Callable[..., Any] + :param run_once: If set to True, the dispatcher will only invoke `listening_func` once before it stops listening.\ + If set to False, the dispatcher will invoke `listening_func` every time the specified number of milliseconds has passed. + :type run_once: bool + """ + def __init__(self, mod_identifier: Union[str, CommonModIdentity], milliseconds: int, listening_func: Callable[..., Any], run_once: bool=False): + from sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils + self._mod_name = CommonModIdentityUtils.determine_mod_name_from_identifier(mod_identifier) + self._minimum_milliseconds_to_dispatch = milliseconds + self._listening_func = listening_func + self.total_milliseconds_passed = 0.0 + self._run_once = run_once + + @property + def total_milliseconds_passed(self) -> float: + """The amount of time in milliseconds that has passed since the dispatcher started keeping track. + + :return: The amount of time in milliseconds that has passed since the dispatcher started keeping track. + :rtype: float + """ + return self._total_milliseconds_passed + + @total_milliseconds_passed.setter + def total_milliseconds_passed(self, milliseconds: float): + self._total_milliseconds_passed = milliseconds + + @property + def minimum_milliseconds_to_dispatch(self) -> int: + """The minimum amount of time in milliseconds that must pass before `listening_func` will be run. + + :return: The minimum amount of time in milliseconds that must pass before `listening_func` will be run. + :rtype: int + """ + return self._minimum_milliseconds_to_dispatch + + @minimum_milliseconds_to_dispatch.setter + def minimum_milliseconds_to_dispatch(self, val: int): + self._minimum_milliseconds_to_dispatch = val + + @property + def mod_name(self) -> str: + """The name of the mod the dispatcher belongs to. + + :return: The name of the mod the dispatcher belongs to. + :rtype: str + """ + return self._mod_name + + @property + def listening_func_name(self) -> str: + """The name of the function waiting for invocation. + + :return: The name of the function waiting for invocation. + :rtype: str + """ + return self._listening_func.__name__ + + @property + def run_once(self) -> bool: + """Determine if the dispatch will run only once. + + :return: True, if the dispatcher will only run once. False, if the dispatcher runs more than once. + :rtype: bool + """ + return self._run_once + + def try_dispatch(self, milliseconds_since_last_update: int) -> bool: + """Attempt to run the dispatcher. + + :param milliseconds_since_last_update: The amount of time in milliseconds that has passed since the last update. + :type milliseconds_since_last_update: int + :return: True, if the event was run. False, if the event was not run or not enough time has passed. + :rtype: bool + """ + self.total_milliseconds_passed += milliseconds_since_last_update + if self.total_milliseconds_passed < self.minimum_milliseconds_to_dispatch: + return False + self.total_milliseconds_passed = max(0.0, self.total_milliseconds_passed - self.minimum_milliseconds_to_dispatch) + self._listening_func() + return True + + +class CommonIntervalEventRegistry(CommonService): + """A registry that will run functions based on an amount of time. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + # This is an example showing how you may register your functions to run on intervals. + class ExampleIntervalListener: + # This function will run only once, after 200 milliseconds have passed. It will then stop listening. + @staticmethod + @CommonIntervalEventRegistry.run_once(ModInfo.get_identity().name, milliseconds=200) + def _example_run_once(): + pass + + # This function will run every 500 milliseconds. It will continue listening until the game is closed or until it is manually unregistered. + @staticmethod + @CommonIntervalEventRegistry.run_every(ModInfo.get_identity().name, milliseconds=500) + def _example_run_every(): + pass + + """ + + def __init__(self) -> None: + self._registered_interval_trackers: List[CommonIntervalDispatcher] = [] + + @staticmethod + def run_every(mod_identifier: Union[str, CommonModIdentity], milliseconds: int=1500) -> Callable[..., Callable[..., Any]]: + """run_every(mod_identifier, milliseconds=1500) + + Register a function to run in intervals of the specified time. + + .. note:: The function will run in intervals every time the amount of time has occurred. + + :param mod_identifier: The name or identity of the mod registering the listener. + :type mod_identifier: Union[str, CommonModIdentity] + :param milliseconds: The amount of time in milliseconds that must pass before the decorated function will be run. + :type milliseconds: int + :return: A callable function wrapped that runs in intervals. + :rtype: Callable[..., Callable[..., Any]] + """ + def _wrapper(listening_func) -> Callable[..., Any]: + CommonIntervalEventRegistry.get()._add_tracker(mod_identifier, milliseconds, listening_func) + return listening_func + return _wrapper + + @staticmethod + def run_once(mod_identifier: Union[str, CommonModIdentity], milliseconds: int=1500) -> Callable[..., Callable[..., Any]]: + """run_once(mod_identifier, milliseconds=1500) + + Register a function to run a single time after a certain amount of time. + + .. note:: A function decorated with this decorator will only run once. + + :param mod_identifier: The name or identity of the mod registering the listener. + :type mod_identifier: Union[str, CommonModIdentity] + :param milliseconds: The amount of time in milliseconds that must pass before the decorated function will be run. + :type milliseconds: int + :return: A callable function wrapped to run once. + :rtype: Callable[..., Callable[..., Any]] + """ + + def _wrapper(listening_func) -> Any: + CommonIntervalEventRegistry.get()._add_tracker(mod_identifier, milliseconds, listening_func, run_once=True) + return listening_func + return _wrapper + + def register_dispatcher(self, mod_identity: CommonModIdentity, milliseconds: int, listening_func: Callable[..., Any], run_once: bool=False) -> Union[CommonIntervalDispatcher, None]: + """register_dispatcher(mod_identity, milliseconds, listening_func, run_once=False) + + Manually register a new dispatcher to the registry. + + :param mod_identity: The identity of the mod that owns the interval dispatcher. + :type mod_identity: CommonModIdentity + :param milliseconds: How much time before the dispatcher runs the first time as well as how much time before it runs again. + :type milliseconds: int + :param listening_func: The function to invoke after the set amount of time. + :type listening_func: Callable[..., Any] + :param run_once: If True, the dispatcher will run a single time, then be removed from the registry. If False, the dispatcher will continue running after the specified milliseconds and will repeat. Default is False. + :type run_once: bool, optional + :return: A dispatcher that will trigger after a set amount of time or None if an error occurs while registering a dispatcher. + :rtype: Union[CommonIntervalDispatcher, None] + """ + if milliseconds <= 0: + CommonExceptionHandler.log_exception(mod_identity, 'Failed to registry an interval dispatcher. The specified milliseconds must be above zero.') + return None + return self._add_tracker(mod_identity, milliseconds, listening_func, run_once=run_once) + + def _add_tracker(self, mod_identifier: Union[str, CommonModIdentity], milliseconds: int, listening_func: Callable[..., Any], run_once: bool=False) -> CommonIntervalDispatcher: + dispatcher = CommonIntervalDispatcher(mod_identifier, milliseconds, listening_func, run_once=run_once) + self._registered_interval_trackers.append(dispatcher) + return dispatcher + + def _attempt_to_dispatch(self, milliseconds_since_last_update: int): + interval_trackers = list(self._registered_interval_trackers) + for interval_tracker in interval_trackers: + try: + interval_tracker.try_dispatch(milliseconds_since_last_update) + except Exception as ex: + CommonExceptionHandler.log_exception(interval_tracker.mod_name, 'Error occurred when attempting to dispatch listener \'{}\''.format(interval_tracker.listening_func_name), exception=ex) + try: + if interval_tracker.run_once: + self._registered_interval_trackers.remove(interval_tracker) + except Exception as ex: + CommonExceptionHandler.log_exception(interval_tracker.mod_name, 'Error occurred when attempting to unregister listener \'{}\''.format(interval_tracker.listening_func_name), exception=ex) + + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity()) + def _update_game_tick_on_zone_update(event_data: S4CLZoneUpdateEvent) -> bool: + from sims4communitylib.events.zone_spin.common_zone_spin_event_dispatcher import CommonZoneSpinEventDispatcher + if event_data.is_paused or CommonZoneSpinEventDispatcher().game_loading: + return False + CommonIntervalEventRegistry.get()._attempt_to_dispatch(event_data.ticks_since_last_update) + return True + + +# noinspection PyMissingOrEmptyDocstring +class ExampleIntervalListener: + # This function will run once after 200 milliseconds have passed. Then it stops listening. + @staticmethod + # @CommonIntervalEventRegistry.run_once(ModInfo.get_identity().name, milliseconds=200) + def _example_run_once() -> None: + pass + + # This function will run every 500 milliseconds. It will continue listening until the game is closed or until it is manually unregistered. + @staticmethod + # @CommonIntervalEventRegistry.run_every(ModInfo.get_identity().name, milliseconds=500) + def _example_run_every() -> None: + pass diff --git a/Scripts/s4ap/sims4communitylib/events/save/__init__.py b/Scripts/s4ap/sims4communitylib/events/save/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/save/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/events/save/common_save_event_dispatcher.py b/Scripts/s4ap/sims4communitylib/events/save/common_save_event_dispatcher.py new file mode 100644 index 0000000..9531a5d --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/save/common_save_event_dispatcher.py @@ -0,0 +1,66 @@ +""" +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 +""" +import os + +from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry +from sims4communitylib.events.save.events.save_loaded import S4CLSaveLoadedEvent +from sims4communitylib.events.save.events.save_saved import S4CLSaveSavedEvent +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.common_service import CommonService +from sims4communitylib.utils.common_injection_utils import CommonInjectionUtils + +ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' + +if ON_RTD: + # noinspection PyMissingOrEmptyDocstring + class SaveGameData: + pass + +if not ON_RTD: + from services.persistence_service import SaveGameData + + +class CommonSaveEventDispatcher(CommonService): + """A service that dispatches save file save/load events. + + .. warning:: Do not use this service directly to listen for events!\ + Use the :class:`.CommonEventRegistry` to listen for dispatched events. + + """ + def __init__(self) -> None: + self._current_save_slot_guid = None + + def _on_game_save(self, save_game_data: SaveGameData): + CommonEventRegistry.get().dispatch(S4CLSaveSavedEvent(save_game_data)) + + def _on_save_loaded(self) -> None: + from sims4communitylib.utils.save_load.common_save_utils import CommonSaveUtils + current_save_slot_guid = CommonSaveUtils().get_save_slot_guid() + if self._current_save_slot_guid is None: + self._current_save_slot_guid = current_save_slot_guid + CommonEventRegistry.get().dispatch(S4CLSaveLoadedEvent()) + elif self._current_save_slot_guid != current_save_slot_guid: + self._current_save_slot_guid = current_save_slot_guid + CommonEventRegistry.get().dispatch(S4CLSaveLoadedEvent()) + + +if not ON_RTD: + from game_services import GameServiceManager + from services.persistence_service import PersistenceService, SaveGameData + + @CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), PersistenceService, PersistenceService.save_game_gen.__name__, handle_exceptions=False) + def _common_save_game_gen(original, self: PersistenceService, timeline, save_game_data: SaveGameData, send_save_message: bool=True, **kwargs): + if send_save_message: + CommonSaveEventDispatcher.get()._on_game_save(save_game_data) + return original(self, timeline, save_game_data, send_save_message=send_save_message, **kwargs) + + @CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), GameServiceManager, GameServiceManager.on_all_households_and_sim_infos_loaded.__name__, handle_exceptions=False) + def _common_save_game_loaded(original, self: GameServiceManager, *args, **kwargs): + result = original(self, *args, **kwargs) + CommonSaveEventDispatcher()._on_save_loaded() + return result diff --git a/Scripts/s4ap/sims4communitylib/events/save/events/__init__.py b/Scripts/s4ap/sims4communitylib/events/save/events/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/save/events/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/events/save/events/save_loaded.py b/Scripts/s4ap/sims4communitylib/events/save/events/save_loaded.py new file mode 100644 index 0000000..afe976f --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/save/events/save_loaded.py @@ -0,0 +1,37 @@ +""" +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 +""" +from sims4communitylib.events.event_handling.common_event import CommonEvent + + +class S4CLSaveLoadedEvent(CommonEvent): + """S4CLSaveLoadedEvent(save_slot_data) + + An event that occurs upon a Save being loaded (After it has been loaded). + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity().name) + def handle_event(event_data: S4CLSaveLoadedEvent): + pass + + """ + pass diff --git a/Scripts/s4ap/sims4communitylib/events/save/events/save_saved.py b/Scripts/s4ap/sims4communitylib/events/save/events/save_saved.py new file mode 100644 index 0000000..aedeac0 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/save/events/save_saved.py @@ -0,0 +1,61 @@ +""" +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 +""" +from typing import Any + +from services.persistence_service import SaveGameData +from sims4communitylib.events.event_handling.common_event import CommonEvent + + +class S4CLSaveSavedEvent(CommonEvent): + """S4CLSaveSavedEvent(save_slot_data) + + An event that occurs upon a Save being saved (Before it has been saved). + + .. note:: This event will only occur when the Player manually saves the game. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity().name) + def handle_event(event_data: S4CLSaveSavedEvent): + pass + + :param save_game_data: The data that will be saved. + :type save_game_data: SaveGameData + """ + + def __init__(self, save_game_data: SaveGameData): + self._save_game_data = save_game_data + + @property + def save_game_data(self) -> Any: + """The game data that will be saved.""" + return self._save_game_data + + @property + def save_slot_name(self) -> str: + """The name of the save slot.""" + return self.save_game_data.slot_name + + @property + def save_slot_id(self) -> int: + """The id of the save slot.""" + return self.save_game_data.slot_id diff --git a/Scripts/s4ap/sims4communitylib/events/sim/__init__.py b/Scripts/s4ap/sims4communitylib/events/sim/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/sim/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/events/sim/common_sim_event_dispatcher.py b/Scripts/s4ap/sims4communitylib/events/sim/common_sim_event_dispatcher.py new file mode 100644 index 0000000..0e48070 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/sim/common_sim_event_dispatcher.py @@ -0,0 +1,385 @@ +""" +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 +""" +from typing import Any, Tuple, Union + +from buffs.buff import Buff +from interactions.utils.death import DeathTracker, DeathType +from objects.components.buff_component import BuffComponent +from objects.game_object import GameObject +from objects.script_object import ScriptObject +from relationships.relationship_objects.relationship import Relationship +from relationships.relationship_bit import RelationshipBit +from relationships.data.relationship_data import RelationshipData +from sims.aging.aging_mixin import AgingMixin +from sims.occult.occult_enums import OccultType +from sims.occult.occult_tracker import OccultTracker +from sims.outfits.outfit_enums import OutfitCategory +from sims.sim import Sim +from sims.sim_info import SimInfo +from sims.sim_info_types import Age +from sims.sim_spawner import SimSpawner +from sims4communitylib.enums.common_age import CommonAge +from sims4communitylib.enums.common_death_types import CommonDeathType +from sims4communitylib.enums.common_gender import CommonGender +from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry +from sims4communitylib.events.sim.events.sim_added_occult_type import S4CLSimAddedOccultTypeEvent +from sims4communitylib.events.sim.events.sim_after_set_current_outfit import S4CLSimAfterSetCurrentOutfitEvent +from sims4communitylib.events.sim.events.sim_buff_added import S4CLSimBuffAddedEvent +from sims4communitylib.events.sim.events.sim_buff_removed import S4CLSimBuffRemovedEvent +from sims4communitylib.events.sim.events.sim_changed_age import S4CLSimChangedAgeEvent +from sims4communitylib.events.sim.events.sim_changed_gender_options_body_frame import S4CLSimChangedGenderOptionsBodyFrameEvent +from sims4communitylib.events.sim.events.sim_changed_gender_options_breasts import \ + S4CLSimChangedGenderOptionsBreastsEvent +from sims4communitylib.events.sim.events.sim_changed_gender_options_can_impregnate import \ + S4CLSimChangedGenderOptionsCanImpregnateEvent +from sims4communitylib.events.sim.events.sim_changed_gender_options_can_reproduce import \ + S4CLSimChangedGenderOptionsCanReproduceEvent +from sims4communitylib.events.sim.events.sim_changed_gender_options_clothing_preference import S4CLSimChangedGenderOptionsClothingPreferenceEvent +from sims4communitylib.events.sim.events.sim_changed_gender import S4CLSimChangedGenderEvent +from sims4communitylib.events.sim.events.sim_changed_occult_type import S4CLSimChangedOccultTypeEvent +from sims4communitylib.events.sim.events.sim_changed_gender_options_can_be_impregnated import S4CLSimChangedGenderOptionsCanBeImpregnatedEvent +from sims4communitylib.events.sim.events.sim_changed_gender_options_toilet_usage import S4CLSimChangedGenderOptionsToiletUsageEvent +from sims4communitylib.events.sim.events.sim_changing_occult_type import S4CLSimChangingOccultTypeEvent +from sims4communitylib.events.sim.events.sim_died import S4CLSimDiedEvent +from sims4communitylib.events.sim.events.sim_pre_despawned import S4CLSimPreDespawnedEvent +from sims4communitylib.events.sim.events.sim_initialized import S4CLSimInitializedEvent +from sims4communitylib.events.sim.events.sim_loaded import S4CLSimLoadedEvent +from sims4communitylib.events.sim.events.game_object_added_to_sim_inventory import S4CLGameObjectAddedToSimInventoryEvent +from sims4communitylib.events.sim.events.game_object_pre_removed_from_sim_inventory import S4CLGameObjectPreRemovedFromSimInventoryEvent +from sims4communitylib.events.sim.events.sim_relationship_bit_added import S4CLSimRelationshipBitAddedEvent +from sims4communitylib.events.sim.events.sim_relationship_bit_removed import S4CLSimRelationshipBitRemovedEvent +from sims4communitylib.events.sim.events.sim_removed_occult_type import S4CLSimRemovedOccultTypeEvent +from sims4communitylib.events.sim.events.sim_revived import S4CLSimRevivedEvent +from sims4communitylib.events.sim.events.sim_set_current_outfit import S4CLSimSetCurrentOutfitEvent +from sims4communitylib.events.sim.events.sim_skill_leveled_up import S4CLSimSkillLeveledUpEvent +from sims4communitylib.events.sim.events.sim_spawned import S4CLSimSpawnedEvent +from sims4communitylib.events.sim.events.sim_trait_added import S4CLSimTraitAddedEvent +from sims4communitylib.events.sim.events.sim_trait_removed import S4CLSimTraitRemovedEvent +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.common_service import CommonService +from sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils +from sims4communitylib.utils.common_injection_utils import CommonInjectionUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from statistics.skill import Skill +from traits.trait_tracker import TraitTracker +from traits.traits import Trait + + +class CommonSimEventDispatcherService(CommonService): + """A service that dispatches Sim events (Init, Spawn, Add Occult, Remove Occult, Change Gender, etc.). + + .. warning:: Do not use this service directly to listen for events!\ + Use the :class:`.CommonEventRegistry` to listen for dispatched events. + + """ + + def _on_sim_change_gender(self, sim_info: SimInfo) -> bool: + from sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils + new_gender = CommonGender.get_gender(sim_info) + if CommonGenderUtils.is_male_gender(new_gender): + # If they are now Male, it means they used to be Female. + old_gender = CommonGender.FEMALE + else: + # If they are now Female, it means they used to be Male. + old_gender = CommonGender.MALE + return CommonEventRegistry.get().dispatch(S4CLSimChangedGenderEvent(sim_info, old_gender, new_gender)) + + def _on_sim_change_gender_options_breasts(self, sim_info: SimInfo) -> bool: + return CommonEventRegistry.get().dispatch(S4CLSimChangedGenderOptionsBreastsEvent(sim_info)) + + def _on_sim_change_gender_options_toilet_usage(self, sim_info: SimInfo) -> bool: + return CommonEventRegistry.get().dispatch(S4CLSimChangedGenderOptionsToiletUsageEvent(sim_info)) + + def _on_sim_change_gender_options_body_frame(self, sim_info: SimInfo) -> bool: + return CommonEventRegistry.get().dispatch(S4CLSimChangedGenderOptionsBodyFrameEvent(sim_info)) + + def _on_sim_change_gender_options_clothing_preference(self, sim_info: SimInfo) -> bool: + return CommonEventRegistry.get().dispatch(S4CLSimChangedGenderOptionsClothingPreferenceEvent(sim_info)) + + def _on_sim_change_gender_options_can_impregnate(self, sim_info: SimInfo) -> bool: + return CommonEventRegistry.get().dispatch(S4CLSimChangedGenderOptionsCanImpregnateEvent(sim_info)) + + def _on_sim_change_gender_options_can_be_impregnated(self, sim_info: SimInfo) -> bool: + return CommonEventRegistry.get().dispatch(S4CLSimChangedGenderOptionsCanBeImpregnatedEvent(sim_info)) + + def _on_sim_change_gender_options_can_reproduce(self, sim_info: SimInfo) -> bool: + return CommonEventRegistry.get().dispatch(S4CLSimChangedGenderOptionsCanReproduceEvent(sim_info)) + + def _on_sim_init(self, sim_info: SimInfo, *_, **__) -> bool: + return CommonEventRegistry.get().dispatch(S4CLSimInitializedEvent(sim_info)) + + def _on_sim_load(self, sim_info: SimInfo, *_, **__) -> bool: + from sims4communitylib.events.zone_spin.common_zone_spin_event_dispatcher import CommonZoneSpinEventDispatcher + if CommonZoneSpinEventDispatcher.get().game_loading: + return False + return CommonEventRegistry.get().dispatch(S4CLSimLoadedEvent(sim_info)) + + def _on_sim_spawned(self, sim_info: SimInfo, *_, **__) -> bool: + from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + return CommonEventRegistry.get().dispatch(S4CLSimSpawnedEvent(CommonSimUtils.get_sim_info(sim_info))) + + def _on_sim_died(self, sim_info: SimInfo, death_type: CommonDeathType, is_off_lot_death: bool, *_, **__) -> bool: + return CommonEventRegistry.get().dispatch(S4CLSimDiedEvent(sim_info, death_type, is_off_lot_death)) + + def _on_sim_revived(self, sim_info: SimInfo, previous_death_type: CommonDeathType, *_, **__) -> bool: + return CommonEventRegistry.get().dispatch(S4CLSimRevivedEvent(sim_info, previous_death_type)) + + def _pre_sim_despawned(self, sim_info: SimInfo, *_, **__) -> bool: + return CommonEventRegistry.get().dispatch(S4CLSimPreDespawnedEvent(sim_info)) + + def _on_sim_change_age(self, sim_info: SimInfo, new_age: Age, current_age: Age) -> bool: + from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + return CommonEventRegistry.get().dispatch(S4CLSimChangedAgeEvent(CommonSimUtils.get_sim_info(sim_info), CommonAge.convert_from_vanilla(current_age), CommonAge.convert_from_vanilla(new_age))) + + def _on_sim_add_occult_type(self, occult_tracker: OccultTracker, occult_type: OccultType) -> bool: + sim_info = occult_tracker._sim_info + return CommonEventRegistry.get().dispatch(S4CLSimAddedOccultTypeEvent(sim_info, occult_type, occult_tracker)) + + def _on_sim_changing_occult_type(self, occult_tracker: OccultTracker, occult_type: OccultType, *_, **__) -> bool: + sim_info = occult_tracker._sim_info + return CommonEventRegistry.get().dispatch(S4CLSimChangingOccultTypeEvent(sim_info, occult_type, occult_tracker)) + + def _on_sim_changed_occult_type(self, occult_tracker: OccultTracker, occult_type: OccultType, *_, **__) -> bool: + sim_info = occult_tracker._sim_info + return CommonEventRegistry.get().dispatch(S4CLSimChangedOccultTypeEvent(sim_info, occult_type, occult_tracker)) + + def _on_sim_remove_occult_type(self, occult_tracker: OccultTracker, occult_type: OccultType) -> bool: + sim_info = occult_tracker._sim_info + return CommonEventRegistry.get().dispatch(S4CLSimRemovedOccultTypeEvent(sim_info, occult_type, occult_tracker)) + + def _on_sim_trait_added(self, trait_tracker: TraitTracker, trait: Trait, *_, **__) -> None: + sim_info = trait_tracker.get_sim_info_from_provider() + if sim_info is None: + return + CommonEventRegistry.get().dispatch(S4CLSimTraitAddedEvent(sim_info, trait, trait_tracker)) + + def _on_sim_trait_removed(self, trait_tracker: TraitTracker, trait: Trait, *_, **__) -> None: + sim_info = trait_tracker.get_sim_info_from_provider() + if sim_info is None: + return + CommonEventRegistry.get().dispatch(S4CLSimTraitRemovedEvent(sim_info, trait, trait_tracker)) + + def _on_sim_buff_added(self, buff: Buff, sim_id: int) -> None: + sim_info = CommonSimUtils.get_sim_info(sim_id) + if sim_info is None: + return + CommonEventRegistry.get().dispatch(S4CLSimBuffAddedEvent(sim_info, buff)) + + def _on_sim_buff_removed(self, buff: Buff, sim_id: int) -> None: + sim_info = CommonSimUtils.get_sim_info(sim_id) + if sim_info is None: + return + CommonEventRegistry.get().dispatch(S4CLSimBuffRemovedEvent(sim_info, buff)) + + def _on_sim_set_current_outfit(self, sim_info: SimInfo, outfit_category_and_index: Tuple[OutfitCategory, int]) -> None: + from sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils + CommonEventRegistry.get().dispatch(S4CLSimSetCurrentOutfitEvent(sim_info, CommonOutfitUtils.get_current_outfit(sim_info), outfit_category_and_index)) + + def _after_sim_set_current_outfit(self, sim_info: SimInfo, previous_outfit_category_and_index: Tuple[OutfitCategory, int], outfit_category_and_index: Tuple[OutfitCategory, int]) -> None: + CommonEventRegistry.get().dispatch(S4CLSimAfterSetCurrentOutfitEvent(sim_info, previous_outfit_category_and_index, outfit_category_and_index)) + + def _on_skill_leveled_up(self, skill: Skill, old_skill_level: int, new_skill_level: int) -> None: + if skill.tracker is None or skill.tracker._owner is None: + return + sim_info = CommonSimUtils.get_sim_info(skill.tracker._owner) + CommonEventRegistry.get().dispatch(S4CLSimSkillLeveledUpEvent(sim_info, skill, old_skill_level, new_skill_level)) + + def _on_object_added_to_sim_inventory(self, sim: Sim, added_game_object: GameObject) -> None: + sim_info = CommonSimUtils.get_sim_info(sim) + if sim_info is None: + return + CommonEventRegistry.get().dispatch(S4CLGameObjectAddedToSimInventoryEvent(sim_info, added_game_object)) + + def _on_object_removed_from_sim_inventory(self, sim: Sim, removed_game_object: GameObject) -> None: + sim_info = CommonSimUtils.get_sim_info(sim) + if sim_info is None: + return + CommonEventRegistry.get().dispatch(S4CLGameObjectPreRemovedFromSimInventoryEvent(sim_info, removed_game_object)) + + def _on_relationship_bit_added(self, sim_id_a: int, sim_id_b: int, relationship_bit: RelationshipBit) -> None: + sim_info_a = CommonSimUtils.get_sim_info(sim_id_a) + if sim_info_a is None: + return + sim_info_b = CommonSimUtils.get_sim_info(sim_id_b) + if sim_info_b is None: + return + CommonEventRegistry.get().dispatch(S4CLSimRelationshipBitAddedEvent(sim_info_a, sim_info_b, relationship_bit)) + + def _on_relationship_bit_removed(self, sim_id_a: int, sim_id_b: int, relationship_bit: RelationshipBit) -> None: + sim_info_a = CommonSimUtils.get_sim_info(sim_id_a) + if sim_info_a is None: + return + sim_info_b = CommonSimUtils.get_sim_info(sim_id_b) + if sim_info_b is None: + return + CommonEventRegistry.get().dispatch(S4CLSimRelationshipBitRemovedEvent(sim_info_a, sim_info_b, relationship_bit)) + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), SimInfo, SimInfo.__init__.__name__, handle_exceptions=False) +def _common_on_sim_init(original, self, *args, **kwargs) -> Any: + result = original(self, *args, **kwargs) + CommonSimEventDispatcherService.get()._on_sim_init(self, *args, **kwargs) + return result + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), SimInfo, SimInfo.load_sim_info.__name__, handle_exceptions=False) +def _common_on_sim_load(original, self, *args, **kwargs) -> Any: + result = original(self, *args, **kwargs) + CommonSimEventDispatcherService.get()._on_sim_load(self, *args, **kwargs) + return result + + +# noinspection PyUnusedLocal +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), SimSpawner, SimSpawner.spawn_sim.__name__, handle_exceptions=False) +def _common_on_sim_spawn(original, cls, *args, **kwargs) -> Any: + result = original(*args, **kwargs) + if result: + CommonSimEventDispatcherService.get()._on_sim_spawned(*args, **kwargs) + return result + + +# noinspection PyUnusedLocal +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), Sim, Sim.destroy.__name__, handle_exceptions=False) +def _common_on_sim_despawn(original, self, *args, **kwargs) -> Any: + CommonSimEventDispatcherService.get()._pre_sim_despawned(CommonSimUtils.get_sim_info(self), *args, **kwargs) + return original(self, *args, **kwargs) + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), DeathTracker, DeathTracker.set_death_type.__name__) +def _common_on_sim_set_death_type(original, self, death_type: Union[DeathType, None], is_off_lot_death: bool = False, *_, **__) -> Any: + previous_death_type = self._death_type + original_result = original(self, death_type, is_off_lot_death=is_off_lot_death, *_, **__) + if death_type is None and previous_death_type is None: + return original_result + + sim_info = CommonSimUtils.get_sim_info(self._sim_info) + if death_type is None: + CommonSimEventDispatcherService.get()._on_sim_revived(sim_info, CommonDeathType.convert_from_vanilla(previous_death_type)) + else: + if previous_death_type is None: + CommonSimEventDispatcherService.get()._on_sim_died(sim_info, CommonDeathType.convert_from_vanilla(death_type), is_off_lot_death) + return original_result + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), DeathTracker, DeathTracker.clear_death_type.__name__) +def _common_on_sim_clear_death_type(original, self, *_, **__) -> Any: + previous_death_type = self._death_type + original_result = original(self, *_, **__) + if previous_death_type is None: + return original_result + sim_info = CommonSimUtils.get_sim_info(self._sim_info) + CommonSimEventDispatcherService.get()._on_sim_revived(sim_info, CommonDeathType.convert_from_vanilla(previous_death_type)) + return original_result + + +# noinspection PyUnusedLocal +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), Skill, Skill.on_skill_level_up.__name__, handle_exceptions=False) +def _common_on_sim_skill_level_up(original, self, *args, **kwargs) -> Any: + result = original(self, *args, **kwargs) + if result: + CommonSimEventDispatcherService.get()._on_skill_leveled_up(self, *args, **kwargs) + return result + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), AgingMixin, AgingMixin.change_age.__name__, handle_exceptions=False) +def _common_on_sim_change_age(original, self, *args, **kwargs) -> Any: + result = original(self, *args, **kwargs) + CommonSimEventDispatcherService.get()._on_sim_change_age(self, *args, **kwargs) + return result + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), OccultTracker, OccultTracker.add_occult_type.__name__, handle_exceptions=False) +def _common_on_sim_add_occult_type(original, self, *args, **kwargs) -> Any: + result = original(self, *args, **kwargs) + CommonSimEventDispatcherService.get()._on_sim_add_occult_type(self, *args, **kwargs) + return result + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), OccultTracker, OccultTracker.switch_to_occult_type.__name__, handle_exceptions=False) +def _common_on_sim_change_occult_type(original, self, *args, **kwargs) -> Any: + CommonSimEventDispatcherService.get()._on_sim_changing_occult_type(self, *args, **kwargs) + result = original(self, *args, **kwargs) + CommonSimEventDispatcherService.get()._on_sim_changed_occult_type(self, *args, **kwargs) + return result + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), OccultTracker, OccultTracker.remove_occult_type.__name__, handle_exceptions=False) +def _common_on_sim_remove_occult_type(original, self, *args, **kwargs) -> Any: + result = original(self, *args, **kwargs) + CommonSimEventDispatcherService.get()._on_sim_remove_occult_type(self, *args, **kwargs) + return result + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), SimInfo, SimInfo.set_current_outfit.__name__, handle_exceptions=False) +def _common_on_sim_set_current_outfit(original, self, *args, **kwargs) -> Any: + old_outfit_category_and_index = CommonOutfitUtils.get_current_outfit(self) + CommonSimEventDispatcherService.get()._on_sim_set_current_outfit(self, *args, **kwargs) + result = original(self, *args, **kwargs) + CommonSimEventDispatcherService.get()._after_sim_set_current_outfit(self, old_outfit_category_and_index, *args, **kwargs) + return result + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), TraitTracker, TraitTracker._add_trait.__name__, handle_exceptions=False) +def _common_on_sim_trait_added(original, self: TraitTracker, *args, **kwargs): + result = original(self, *args, **kwargs) + CommonSimEventDispatcherService.get()._on_sim_trait_added(self, *args, **kwargs) + return result + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), TraitTracker, TraitTracker._remove_trait.__name__, handle_exceptions=False) +def _common_on_sim_trait_removed(original, self: TraitTracker, *args, **kwargs): + result = original(self, *args, **kwargs) + CommonSimEventDispatcherService.get()._on_sim_trait_removed(self, *args, **kwargs) + return result + + +@CommonEventRegistry.handle_events(ModInfo.get_identity()) +def _common_register_buff_added_or_removed_on_sim_spawned(event_data: S4CLSimSpawnedEvent) -> bool: + from sims4communitylib.utils.sims.common_buff_utils import CommonBuffUtils + buff_component: BuffComponent = CommonBuffUtils.get_buff_component(event_data.sim_info) + if not buff_component: + return False + + dispatcher_service = CommonSimEventDispatcherService() + if dispatcher_service._on_sim_buff_added not in buff_component.on_buff_added: + buff_component.on_buff_added.append(dispatcher_service._on_sim_buff_added) + + if dispatcher_service._on_sim_buff_removed not in buff_component.on_buff_removed: + buff_component.on_buff_removed.append(dispatcher_service._on_sim_buff_removed) + return True + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), Sim, Sim.on_object_added_to_inventory.__name__, handle_exceptions=False) +def _common_on_object_added_to_sim_inventory(original, self: Sim, obj: ScriptObject, *args, **kwargs): + result = original(self, obj, *args, **kwargs) + if isinstance(obj, GameObject): + CommonSimEventDispatcherService.get()._on_object_added_to_sim_inventory(self, obj) + return result + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), Sim, Sim.on_object_removed_from_inventory.__name__, handle_exceptions=False) +def _common_on_object_removed_from_sim_inventory(original, self: Sim, obj: ScriptObject, *args, **kwargs): + if isinstance(obj, GameObject): + CommonSimEventDispatcherService.get()._on_object_removed_from_sim_inventory(self, obj) + result = original(self, obj, *args, **kwargs) + return result + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), Relationship, Relationship.add_relationship_bit.__name__) +def _common_on_add_relationship_bit(original, self: Relationship, actor_sim_id: int, target_sim_id: int, bit_to_add: RelationshipBit, *_, **__): + result = original(self, actor_sim_id, target_sim_id, bit_to_add, *_, **__) + CommonSimEventDispatcherService()._on_relationship_bit_added(actor_sim_id, target_sim_id, bit_to_add) + return result + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), RelationshipData, RelationshipData.remove_bit.__name__) +def _common_on_remove_relationship_bit(original, self: RelationshipData, bit: RelationshipBit, *_, **__): + result = original(self, bit, *_, **__) + (actor_sim_id, target_sim_id) = self._sim_ids() + CommonSimEventDispatcherService()._on_relationship_bit_removed(actor_sim_id, target_sim_id, bit) + return result diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/__init__.py b/Scripts/s4ap/sims4communitylib/events/sim/events/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/game_object_added_to_sim_inventory.py b/Scripts/s4ap/sims4communitylib/events/sim/events/game_object_added_to_sim_inventory.py new file mode 100644 index 0000000..1a411d4 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/game_object_added_to_sim_inventory.py @@ -0,0 +1,83 @@ +""" +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 +""" +from objects.game_object import GameObject +from sims.sim_info import SimInfo +from sims4communitylib.events.event_handling.common_event import CommonEvent +from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils + + +class S4CLGameObjectAddedToSimInventoryEvent(CommonEvent): + """S4CLGameObjectAddedToSimInventoryEvent(sim_info, added_game_object) + + An event that occurs when a Game Object is added to the inventory of a Sim. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity()) + def handle_event(event_data: S4CLGameObjectAddedToSimInventoryEvent): + pass + + :param sim_info: The Sim that changed. + :type sim_info: SimInfo + :param added_game_object: The Game Object that was added to the inventory of the Sim. + :type added_game_object: GameObject + """ + + def __init__(self, sim_info: SimInfo, added_game_object: GameObject): + self._sim_info = sim_info + self._added_game_object = added_game_object + + @property + def sim_info(self) -> SimInfo: + """The Sim that received the added object. + + :return: The Sim that received the added object. + :rtype: SimInfo + """ + return self._sim_info + + @property + def added_game_object(self) -> GameObject: + """The Game Object that was added. + + :return: The Game Object that was added. + :rtype: GameObject + """ + return self._added_game_object + + @property + def added_game_object_id(self) -> int: + """The decimal identifier of the Game Object that was added. + + :return: The decimal identifier of the Game Object that was added. + :rtype: int + """ + return CommonObjectUtils.get_object_id(self.added_game_object) + + @property + def added_object_guid(self) -> int: + """The guid identifier of the Game Object that was added. + + :return: The guid identifier of the Game Object that was added. + :rtype: int + """ + return CommonObjectUtils.get_object_guid(self.added_game_object) diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/game_object_pre_removed_from_sim_inventory.py b/Scripts/s4ap/sims4communitylib/events/sim/events/game_object_pre_removed_from_sim_inventory.py new file mode 100644 index 0000000..05e4fe3 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/game_object_pre_removed_from_sim_inventory.py @@ -0,0 +1,84 @@ +""" +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 +""" +from objects.game_object import GameObject +from sims.sim_info import SimInfo +from sims4communitylib.events.event_handling.common_event import CommonEvent +from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils + + +class S4CLGameObjectPreRemovedFromSimInventoryEvent(CommonEvent): + """S4CLGameObjectPreRemovedFromSimInventoryEvent(sim_info, removed_game_object) + + An event that occurs before a Game Object is removed from the inventory of a Sim. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity()) + def handle_event(event_data: S4CLGameObjectPreRemovedFromSimInventoryEvent): + pass + + :param sim_info: The Sim that changed. + :type sim_info: SimInfo + :param removed_game_object: The Game Object that was removed from the inventory of the Sim. + :type removed_game_object: GameObject + """ + + def __init__(self, sim_info: SimInfo, removed_game_object: GameObject): + self._sim_info = sim_info + self._removed_game_object = removed_game_object + + @property + def sim_info(self) -> SimInfo: + """The Sim that is having the object removed. + + :return: The Sim that is having the object removed. + :rtype: SimInfo + """ + return self._sim_info + + @property + def removed_game_object(self) -> GameObject: + """The Game Object that is being removed. + + :return: The Game Object that is being removed. + :rtype: GameObject + """ + return self._removed_game_object + + @property + def removed_game_object_id(self) -> int: + """The decimal identifier of the Game Object that was removed. + + :return: The decimal identifier of the Game Object that was removed. + :rtype: int + """ + return CommonObjectUtils.get_object_id(self.removed_game_object) + + @property + def removed_game_object_guid(self) -> int: + """The guid identifier of the Game Object that was removed. + + :return: The guid identifier of the Game Object that was removed. + :rtype: int + """ + # noinspection PyTypeChecker + return CommonObjectUtils.get_object_guid(self.removed_game_object) diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_added_occult_type.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_added_occult_type.py new file mode 100644 index 0000000..b36e7e0 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_added_occult_type.py @@ -0,0 +1,77 @@ +""" +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 +""" +from sims.occult.occult_enums import OccultType +from sims.occult.occult_tracker import OccultTracker +from sims.sim_info import SimInfo +from sims4communitylib.events.event_handling.common_event import CommonEvent + + +class S4CLSimAddedOccultTypeEvent(CommonEvent): + """S4CLSimAddedOccultTypeEvent(sim_info, occult_type, occult_tracker) + + An event that occurs when an OccultType has been added to a Sim. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity().name) + def handle_event(event_data: S4CLSimAddedOccultTypeEvent): + pass + + :param sim_info: The Sim the Occult Type was added to. + :type sim_info: SimInfo + :param occult_type: The OccultType that was added. + :type occult_type: OccultType + :param occult_tracker: A tracker that keeps track of the occult status of the Sim. + :type occult_tracker: OccultTracker + """ + + def __init__(self, sim_info: SimInfo, occult_type: OccultType, occult_tracker: OccultTracker): + self._sim_info = sim_info + self._occult_type = occult_type + self._occult_tracker = occult_tracker + + @property + def sim_info(self) -> SimInfo: + """The Sim the OccultType was added to. + + :return: The Sim the OccultType was added to. + :rtype: SimInfo + """ + return self._sim_info + + @property + def occult_type(self) -> OccultType: + """The OccultType that was added. + + :return: The OccultType that was added. + :rtype: OccultType + """ + return self._occult_type + + @property + def occult_tracker(self) -> OccultTracker: + """A tracker that keeps track of the occult status of the Sim. + + :return: A tracker that keeps track of the occult status of the Sim. + :rtype: OccultTracker + """ + return self._occult_tracker diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_after_set_current_outfit.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_after_set_current_outfit.py new file mode 100644 index 0000000..bea89cf --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_after_set_current_outfit.py @@ -0,0 +1,66 @@ +""" +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 +""" +from typing import Tuple + +from sims.outfits.outfit_enums import OutfitCategory +from sims.sim_info import SimInfo +from sims4communitylib.events.event_handling.common_event import CommonEvent + + +class S4CLSimAfterSetCurrentOutfitEvent(CommonEvent): + """S4CLSimAfterSetCurrentOutfitEvent(sim_info, old_outfit_category_and_index, new_outfit_category_and_index) + + An event that occurs after the current outfit of a Sim is set. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity().name) + def handle_event(event_data: S4CLSimAfterSetCurrentOutfitEvent): + pass + + :param sim_info: The Sim that changed. + :type sim_info: SimInfo + :param old_outfit_category_and_index: The outfit category and index for the outfit the Sim has changed from. + :type old_outfit_category_and_index: Tuple[OutfitCategory, int] + :param new_outfit_category_and_index: The outfit category and index for the outfit the Sim has changed to. + :type new_outfit_category_and_index: Tuple[OutfitCategory, int] + """ + + def __init__(self, sim_info: SimInfo, old_outfit_category_and_index: Tuple[OutfitCategory, int], new_outfit_category_and_index: Tuple[OutfitCategory, int]): + self._sim_info = sim_info + self._old_outfit_category_and_index = old_outfit_category_and_index + self._new_outfit_category_and_index = new_outfit_category_and_index + + @property + def sim_info(self) -> SimInfo: + """The Sim that changed.""" + return self._sim_info + + @property + def old_outfit_category_and_index(self) -> Tuple[OutfitCategory, int]: + """The outfit category and index for the outfit the Sim has changed from.""" + return self._old_outfit_category_and_index + + @property + def new_outfit_category_and_index(self) -> Tuple[OutfitCategory, int]: + """The outfit category and index for the outfit the Sim has changed to.""" + return self._new_outfit_category_and_index diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_buff_added.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_buff_added.py new file mode 100644 index 0000000..4f13d68 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_buff_added.py @@ -0,0 +1,74 @@ +""" +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 +""" +from buffs.buff import Buff +from sims.sim_info import SimInfo +from sims4communitylib.events.event_handling.common_event import CommonEvent +from sims4communitylib.utils.sims.common_buff_utils import CommonBuffUtils + + +class S4CLSimBuffAddedEvent(CommonEvent): + """S4CLSimBuffAddedEvent(sim_info, buff) + + An event that occurs when a Buff is added to a Sim. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity()) + def handle_event(event_data: S4CLSimBuffAddedEvent): + pass + + :param sim_info: The Sim that changed. + :type sim_info: SimInfo + :param buff: The Buff that was added. + :type buff: Buff + """ + + def __init__(self, sim_info: SimInfo, buff: Buff): + self._sim_info = sim_info + self._buff = buff + + @property + def sim_info(self) -> SimInfo: + """The Sim that received the buff. + + :return: The Sim that received the buff. + :rtype: SimInfo + """ + return self._sim_info + + @property + def buff(self) -> Buff: + """The Buff that was added. + + :return: The Buff that was added. + :rtype: Buff + """ + return self._buff + + @property + def buff_id(self) -> int: + """The decimal identifier of the Buff. + + :return: The decimal identifier of the Buff. + :rtype: int + """ + return CommonBuffUtils.get_buff_id(self.buff) diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_buff_removed.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_buff_removed.py new file mode 100644 index 0000000..59a199a --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_buff_removed.py @@ -0,0 +1,74 @@ +""" +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 +""" +from buffs.buff import Buff +from sims.sim_info import SimInfo +from sims4communitylib.events.event_handling.common_event import CommonEvent +from sims4communitylib.utils.sims.common_buff_utils import CommonBuffUtils + + +class S4CLSimBuffRemovedEvent(CommonEvent): + """S4CLSimBuffRemovedEvent(sim_info, buff) + + An event that occurs when a Buff is removed from a Sim. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity()) + def handle_event(event_data: S4CLSimBuffRemovedEvent): + pass + + :param sim_info: The Sim that changed. + :type sim_info: SimInfo + :param buff: The Buff that was removed. + :type buff: Buff + """ + + def __init__(self, sim_info: SimInfo, buff: Buff): + self._sim_info = sim_info + self._buff = buff + + @property + def sim_info(self) -> SimInfo: + """The Sim that lost the buff. + + :return: The Sim that lost the buff. + :rtype: SimInfo + """ + return self._sim_info + + @property + def buff(self) -> Buff: + """The Buff that was removed. + + :return: The Buff that was removed. + :rtype: Buff + """ + return self._buff + + @property + def buff_id(self) -> int: + """The decimal identifier of the Buff. + + :return: The decimal identifier of the Buff. + :rtype: int + """ + return CommonBuffUtils.get_buff_id(self.buff) diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_age.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_age.py new file mode 100644 index 0000000..8533d5b --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_age.py @@ -0,0 +1,66 @@ +""" +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 +""" +from sims.sim_info import SimInfo +from sims4communitylib.enums.common_age import CommonAge +from sims4communitylib.events.event_handling.common_event import CommonEvent + + +class S4CLSimChangedAgeEvent(CommonEvent): + """S4CLSimChangedAgeEvent(sim_info, old_age, new_age) + + An event that occurs when a Sim has changed their current Age. + + .. note:: This can occur when a Child Sim becomes a Teen Sim, a Teen Sim becomes a Child Sim, etc. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity().name) + def handle_event(event_data: S4CLSimChangedAgeEvent): + pass + + :param sim_info: The Sim that changed. + :type sim_info: SimInfo + :param old_age: The age the Sim has changed from. + :type old_age: CommonAge + :param new_age: The age the Sim has changed to. + :type new_age: CommonAge + """ + + def __init__(self, sim_info: SimInfo, old_age: CommonAge, new_age: CommonAge): + self._sim_info = sim_info + self._old_age = old_age + self._new_age = new_age + + @property + def sim_info(self) -> SimInfo: + """The Sim that changed.""" + return self._sim_info + + @property + def old_age(self) -> CommonAge: + """The age the Sim has changed from.""" + return self._old_age + + @property + def new_age(self) -> CommonAge: + """The age the Sim has changed to.""" + return self._new_age diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender.py new file mode 100644 index 0000000..7c74da2 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender.py @@ -0,0 +1,64 @@ +""" +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 +""" +from sims.sim_info import SimInfo +from sims4communitylib.enums.common_gender import CommonGender +from sims4communitylib.events.event_handling.common_event import CommonEvent + + +class S4CLSimChangedGenderEvent(CommonEvent): + """S4CLSimChangedGenderEvent(sim_info, old_gender, new_gender) + + An event that occurs when a Sim has changed their current gender. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity().name) + def handle_event(event_data: S4CLSimChangedGenderEvent): + pass + + :param sim_info: The Sim that changed. + :type sim_info: SimInfo + :param old_gender: The gender the Sim has changed from. + :type old_gender: CommonGender + :param new_gender: The gender the Sim has changed to. + :type new_gender: CommonGender + """ + + def __init__(self, sim_info: SimInfo, old_gender: CommonGender, new_gender: CommonGender): + self._sim_info = sim_info + self._old_gender = old_gender + self._new_gender = new_gender + + @property + def sim_info(self) -> SimInfo: + """The Sim that changed.""" + return self._sim_info + + @property + def old_gender(self) -> CommonGender: + """The gender the Sim has changed from.""" + return self._old_gender + + @property + def new_gender(self) -> CommonGender: + """The gender the Sim has changed to.""" + return self._new_gender diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_body_frame.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_body_frame.py new file mode 100644 index 0000000..d82986d --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_body_frame.py @@ -0,0 +1,51 @@ +""" +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 +""" +from sims.sim_info import SimInfo +from sims4communitylib.events.event_handling.common_event import CommonEvent + + +class S4CLSimChangedGenderOptionsBodyFrameEvent(CommonEvent): + """S4CLSimChangedGenderOptionsBodyFrameEvent(sim_info) + + An event that occurs when a Sim has changed their body frame. i.e. Masculine to Feminine or vice verse + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity()) + def handle_event(event_data: S4CLSimChangedGenderOptionsBodyFrameEvent): + pass + + :param sim_info: The Sim that changed. + :type sim_info: SimInfo + """ + + def __init__(self, sim_info: SimInfo): + self._sim_info = sim_info + + @property + def sim_info(self) -> SimInfo: + """The Sim that changed. + + :return: The Sim that changed. + :rtype: SimInfo + """ + return self._sim_info diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_breasts.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_breasts.py new file mode 100644 index 0000000..07eb92c --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_breasts.py @@ -0,0 +1,51 @@ +""" +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 +""" +from sims.sim_info import SimInfo +from sims4communitylib.events.event_handling.common_event import CommonEvent + + +class S4CLSimChangedGenderOptionsBreastsEvent(CommonEvent): + """S4CLSimChangedGenderOptionsBreastsEvent(sim_info) + + An event that occurs when a Sim has changed whether or not they have breasts. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity()) + def handle_event(event_data: S4CLSimChangedGenderOptionsBreastsEvent): + pass + + :param sim_info: The Sim that changed. + :type sim_info: SimInfo + """ + + def __init__(self, sim_info: SimInfo): + self._sim_info = sim_info + + @property + def sim_info(self) -> SimInfo: + """The Sim that changed. + + :return: The Sim that changed. + :rtype: SimInfo + """ + return self._sim_info diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_can_be_impregnated.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_can_be_impregnated.py new file mode 100644 index 0000000..5e6d211 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_can_be_impregnated.py @@ -0,0 +1,51 @@ +""" +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 +""" +from sims.sim_info import SimInfo +from sims4communitylib.events.event_handling.common_event import CommonEvent + + +class S4CLSimChangedGenderOptionsCanBeImpregnatedEvent(CommonEvent): + """S4CLSimChangedGenderOptionsCanBeImpregnatedEvent(sim_info) + + An event that occurs when a Human Sim has changed whether they can be impregnated by other Sims or not. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity().name) + def handle_event(event_data: S4CLSimChangedGenderOptionsCanBeImpregnatedEvent): + pass + + :param sim_info: The Sim that changed. + :type sim_info: SimInfo + """ + + def __init__(self, sim_info: SimInfo): + self._sim_info = sim_info + + @property + def sim_info(self) -> SimInfo: + """The Sim that changed. + + :return: The Sim that changed. + :rtype: SimInfo + """ + return self._sim_info diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_can_impregnate.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_can_impregnate.py new file mode 100644 index 0000000..0bd47fd --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_can_impregnate.py @@ -0,0 +1,51 @@ +""" +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 +""" +from sims.sim_info import SimInfo +from sims4communitylib.events.event_handling.common_event import CommonEvent + + +class S4CLSimChangedGenderOptionsCanImpregnateEvent(CommonEvent): + """S4CLSimChangedGenderOptionsCanImpregnateEvent(sim_info) + + An event that occurs when a Human Sim has changed whether they can impregnate other Sims or not. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity().name) + def handle_event(event_data: S4CLSimChangedGenderOptionsCanImpregnateEvent): + pass + + :param sim_info: The Sim that changed. + :type sim_info: SimInfo + """ + + def __init__(self, sim_info: SimInfo): + self._sim_info = sim_info + + @property + def sim_info(self) -> SimInfo: + """The Sim that changed. + + :return: The Sim that changed. + :rtype: SimInfo + """ + return self._sim_info diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_can_reproduce.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_can_reproduce.py new file mode 100644 index 0000000..36dabcc --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_can_reproduce.py @@ -0,0 +1,51 @@ +""" +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 +""" +from sims.sim_info import SimInfo +from sims4communitylib.events.event_handling.common_event import CommonEvent + + +class S4CLSimChangedGenderOptionsCanReproduceEvent(CommonEvent): + """S4CLSimChangedGenderOptionsCanReproduceEvent(sim_info) + + An event that occurs when a Pet Sim has changed whether they can reproduce or not. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity().name) + def handle_event(event_data: S4CLSimChangedGenderOptionsCanReproduceEvent): + pass + + :param sim_info: The Sim that changed. + :type sim_info: SimInfo + """ + + def __init__(self, sim_info: SimInfo): + self._sim_info = sim_info + + @property + def sim_info(self) -> SimInfo: + """The Sim that changed. + + :return: The Sim that changed. + :rtype: SimInfo + """ + return self._sim_info diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_clothing_preference.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_clothing_preference.py new file mode 100644 index 0000000..4b83a1a --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_clothing_preference.py @@ -0,0 +1,51 @@ +""" +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 +""" +from sims.sim_info import SimInfo +from sims4communitylib.events.event_handling.common_event import CommonEvent + + +class S4CLSimChangedGenderOptionsClothingPreferenceEvent(CommonEvent): + """S4CLSimChangedGenderOptionsClothingPreferenceEvent(sim_info) + + An event that occurs when a Sim has changed their clothing preference. i.e. Menswear to Womenswear or vice verse + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity().name) + def handle_event(event_data: S4CLSimChangedGenderOptionsClothingPreferenceEvent): + pass + + :param sim_info: The Sim that changed. + :type sim_info: SimInfo + """ + + def __init__(self, sim_info: SimInfo): + self._sim_info = sim_info + + @property + def sim_info(self) -> SimInfo: + """The Sim that changed. + + :return: The Sim that changed. + :rtype: SimInfo + """ + return self._sim_info diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_toilet_usage.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_toilet_usage.py new file mode 100644 index 0000000..bb8c3f6 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_toilet_usage.py @@ -0,0 +1,51 @@ +""" +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 +""" +from sims.sim_info import SimInfo +from sims4communitylib.events.event_handling.common_event import CommonEvent + + +class S4CLSimChangedGenderOptionsToiletUsageEvent(CommonEvent): + """S4CLSimChangedGenderOptionsToiletUsageEvent(sim_info) + + An event that occurs when a Sim has changed the way they use the toilet. i.e. Toilet Standing to Toilet Sitting or Toilet Sitting to Toilet Standing. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity().name) + def handle_event(event_data: S4CLSimChangedGenderOptionsToiletUsageEvent): + pass + + :param sim_info: The Sim that changed. + :type sim_info: SimInfo + """ + + def __init__(self, sim_info: SimInfo): + self._sim_info = sim_info + + @property + def sim_info(self) -> SimInfo: + """The Sim that changed. + + :return: The Sim that changed. + :rtype: SimInfo + """ + return self._sim_info diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_occult_type.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_occult_type.py new file mode 100644 index 0000000..03cf473 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_occult_type.py @@ -0,0 +1,79 @@ +""" +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 +""" +from sims.occult.occult_enums import OccultType +from sims.occult.occult_tracker import OccultTracker +from sims.sim_info import SimInfo +from sims4communitylib.events.event_handling.common_event import CommonEvent + + +class S4CLSimChangedOccultTypeEvent(CommonEvent): + """S4CLSimChangedOccultTypeEvent(sim_info, occult_type, occult_tracker) + + An event that occurs when a Sim has changed their current OccultType. + + .. note:: This can occur when an Alien Sim changes between their Disguised form and their True form. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity().name) + def handle_event(event_data: S4CLSimChangedOccultTypeEvent): + pass + + :param sim_info: The Sim that changed OccultTypes. + :type sim_info: SimInfo + :param occult_type: The OccultType the Sim has changed to. + :type occult_type: OccultType + :param occult_tracker: A tracker that keeps track of the occult status of the Sim. + :type occult_tracker: OccultTracker + """ + + def __init__(self, sim_info: SimInfo, occult_type: OccultType, occult_tracker: OccultTracker): + self._sim_info = sim_info + self._occult_type = occult_type + self._occult_tracker = occult_tracker + + @property + def sim_info(self) -> SimInfo: + """The Sim that changed OccultTypes. + + :return: The Sim that changed OccultTypes. + :rtype: SimInfo + """ + return self._sim_info + + @property + def occult_type(self) -> OccultType: + """The OccultType the Sim has changed to. + + :return: The OccultType the Sim has changed to. + :rtype: OccultType + """ + return self._occult_type + + @property + def occult_tracker(self) -> OccultTracker: + """A tracker that keeps track of the occult status of the Sim. + + :return: A tracker that keeps track of the occult status of the Sim. + :rtype: OccultTracker + """ + return self._occult_tracker diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changing_occult_type.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changing_occult_type.py new file mode 100644 index 0000000..8c0d504 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changing_occult_type.py @@ -0,0 +1,79 @@ +""" +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 +""" +from sims.occult.occult_enums import OccultType +from sims.occult.occult_tracker import OccultTracker +from sims.sim_info import SimInfo +from sims4communitylib.events.event_handling.common_event import CommonEvent + + +class S4CLSimChangingOccultTypeEvent(CommonEvent): + """S4CLSimChangingOccultTypeEvent(sim_info, occult_type, occult_tracker) + + An event that occurs when a Sim is changing their current OccultType. (But before they have changed!) + + .. note:: This can occur when an Alien Sim changes between their Disguised form and their True form or when a Mermaid changes from their Non-Mermaid form to their Mermaid form. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity().name) + def handle_event(event_data: S4CLSimChangingOccultTypeEvent): + pass + + :param sim_info: The Sim that changing OccultTypes. + :type sim_info: SimInfo + :param occult_type: The OccultType the Sim is changing to. + :type occult_type: OccultType + :param occult_tracker: A tracker that keeps track of the occult status of the Sim. + :type occult_tracker: OccultTracker + """ + + def __init__(self, sim_info: SimInfo, occult_type: OccultType, occult_tracker: OccultTracker): + self._sim_info = sim_info + self._occult_type = occult_type + self._occult_tracker = occult_tracker + + @property + def sim_info(self) -> SimInfo: + """The Sim that changed OccultTypes. + + :return: The Sim that changed OccultTypes. + :rtype: SimInfo + """ + return self._sim_info + + @property + def occult_type(self) -> OccultType: + """The OccultType the Sim is changing to. + + :return: The OccultType the Sim is changing to. + :rtype: OccultType + """ + return self._occult_type + + @property + def occult_tracker(self) -> OccultTracker: + """A tracker that keeps track of the occult status of the Sim. + + :return: A tracker that keeps track of the occult status of the Sim. + :rtype: OccultTracker + """ + return self._occult_tracker diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_died.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_died.py new file mode 100644 index 0000000..f26c726 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_died.py @@ -0,0 +1,68 @@ +""" +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 +""" +from sims.sim_info import SimInfo +from sims4communitylib.enums.common_death_types import CommonDeathType +from sims4communitylib.events.event_handling.common_event import CommonEvent + + +class S4CLSimDiedEvent(CommonEvent): + """S4CLSimDiedEvent(sim_info, death_type, died_off_lot) + + An event that occurs when a Sim has died. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity().name) + def handle_event(event_data: S4CLSimDiedEvent): + pass + + :param sim_info: The Sim that died. + :type sim_info: SimInfo + :param death_type: The type of Death that befell the Sim. + :type death_type: CommonDeathType + :param died_off_lot: True, if the Sim died off the active lot. False, if not. + :type died_off_lot: bool + """ + + def __init__(self, sim_info: SimInfo, death_type: CommonDeathType, died_off_lot: bool): + self._sim_info = sim_info + self._death_type = death_type + self._died_off_lot = died_off_lot + + @property + def sim_info(self) -> SimInfo: + """The Sim that died. + + :return: The Sim that died. + :rtype: SimInfo + """ + return self._sim_info + + @property + def death_type(self) -> CommonDeathType: + """The type of Death that befell the Sim.""" + return self._death_type + + @property + def died_off_lot(self) -> bool: + """True, if the Sim died off the active lot. False, if not.""" + return self._died_off_lot diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_initialized.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_initialized.py new file mode 100644 index 0000000..84c0d77 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_initialized.py @@ -0,0 +1,51 @@ +""" +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 +""" +from sims.sim_info import SimInfo +from sims4communitylib.events.event_handling.common_event import CommonEvent + + +class S4CLSimInitializedEvent(CommonEvent): + """S4CLSimInitializedEvent(sim_info) + + An event that occurs after a Sim has been initialized. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity().name) + def handle_event(event_data: S4CLSimInitializedEvent): + pass + + :param sim_info: The Sim that was initialized. + :type sim_info: SimInfo + """ + + def __init__(self, sim_info: SimInfo): + self._sim_info = sim_info + + @property + def sim_info(self) -> SimInfo: + """The Sim that was initialized. + + :return: The Sim that was initialized. + :rtype: SimInfo + """ + return self._sim_info diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_loaded.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_loaded.py new file mode 100644 index 0000000..1617792 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_loaded.py @@ -0,0 +1,51 @@ +""" +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 +""" +from sims.sim_info import SimInfo +from sims4communitylib.events.event_handling.common_event import CommonEvent + + +class S4CLSimLoadedEvent(CommonEvent): + """S4CLSimLoadedEvent(sim_info) + + An event that occurs after a Sim has been loaded. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity().name) + def handle_event(event_data: S4CLSimLoadedEvent): + pass + + :param sim_info: The Sim that was loaded. + :type sim_info: SimInfo + """ + + def __init__(self, sim_info: SimInfo): + self._sim_info = sim_info + + @property + def sim_info(self) -> SimInfo: + """The Sim that was loaded. + + :return: The Sim that was loaded. + :rtype: SimInfo + """ + return self._sim_info diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_pre_despawned.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_pre_despawned.py new file mode 100644 index 0000000..f89282a --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_pre_despawned.py @@ -0,0 +1,51 @@ +""" +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 +""" +from sims.sim_info import SimInfo +from sims4communitylib.events.event_handling.common_event import CommonEvent + + +class S4CLSimPreDespawnedEvent(CommonEvent): + """S4CLSimPreDespawnedEvent(sim_info) + + An event that occurs when a Sim is being despawned. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity().name) + def handle_event(event_data: S4CLSimPreDespawnedEvent): + pass + + :param sim_info: The Sim that is being despawned. + :type sim_info: SimInfo + """ + + def __init__(self, sim_info: SimInfo): + self._sim_info = sim_info + + @property + def sim_info(self) -> SimInfo: + """The Sim that is being despawned. + + :return: The Sim that is being despawned. + :rtype: SimInfo + """ + return self._sim_info diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_relationship_bit_added.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_relationship_bit_added.py new file mode 100644 index 0000000..757a5e4 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_relationship_bit_added.py @@ -0,0 +1,86 @@ +""" +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 +""" +from relationships.relationship_bit import RelationshipBit +from sims.sim_info import SimInfo +from sims4communitylib.events.event_handling.common_event import CommonEvent + + +class S4CLSimRelationshipBitAddedEvent(CommonEvent): + """S4CLSimRelationshipBitAddedEvent(sim_info_a, sim_info_b, relationship_bit) + + An event that occurs when a Relationship Bit is added from Sim A to Sim B. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity()) + def handle_event(event_data: S4CLSimRelationshipBitAddedEvent): + pass + + :param sim_info_a: The Sim with the relationship bit toward Sim B. + :type sim_info_a: SimInfo + :param sim_info_b: The Sim with the relationship bit from Sim A. + :type sim_info_b: SimInfo + :param relationship_bit: The RelationshipBit that was added. + :type relationship_bit: RelationshipBit + """ + + def __init__(self, sim_info_a: SimInfo, sim_info_b: SimInfo, relationship_bit: RelationshipBit): + self._sim_info_a = sim_info_a + self._sim_info_b = sim_info_b + self._relationship_bit = relationship_bit + + @property + def sim_info_a(self) -> SimInfo: + """The Sim that has a Relationship Bit toward Sim B. + + :return: The Sim that has a Relationship Bit toward Sim B. + :rtype: SimInfo + """ + return self._sim_info_a + + @property + def sim_info_b(self) -> SimInfo: + """The Sim that has a Relationship Bit from Sim A. + + :return: The Sim that has a Relationship Bit from Sim A. + :rtype: SimInfo + """ + return self._sim_info_b + + @property + def relationship_bit(self) -> RelationshipBit: + """The RelationshipBit that was added. + + :return: The RelationshipBit that was added. + :rtype: RelationshipBit + """ + return self._relationship_bit + + @property + def relationship_bit_id(self) -> int: + """The decimal identifier of the RelationshipBit. + + :return: The decimal identifier of the RelationshipBit. + :rtype: int + """ + from sims4communitylib.utils.sims.common_relationship_utils import CommonRelationshipUtils + return CommonRelationshipUtils.get_relationship_bit_guid(self.relationship_bit) diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_relationship_bit_removed.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_relationship_bit_removed.py new file mode 100644 index 0000000..ba02788 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_relationship_bit_removed.py @@ -0,0 +1,86 @@ +""" +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 +""" +from relationships.relationship_bit import RelationshipBit +from sims.sim_info import SimInfo +from sims4communitylib.events.event_handling.common_event import CommonEvent + + +class S4CLSimRelationshipBitRemovedEvent(CommonEvent): + """S4CLSimRelationshipBitRemovedEvent(sim_info_a, sim_info_b, relationship_bit) + + An event that occurs when a Relationship Bit is removed from Sim A to Sim B. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity()) + def handle_event(event_data: S4CLSimRelationshipBitRemovedEvent): + pass + + :param sim_info_a: The Sim with the relationship bit toward Sim B. + :type sim_info_a: SimInfo + :param sim_info_b: The Sim with the relationship bit from Sim A. + :type sim_info_b: SimInfo + :param relationship_bit: The RelationshipBit that was removed. + :type relationship_bit: RelationshipBit + """ + + def __init__(self, sim_info_a: SimInfo, sim_info_b: SimInfo, relationship_bit: RelationshipBit): + self._sim_info_a = sim_info_a + self._sim_info_b = sim_info_b + self._relationship_bit = relationship_bit + + @property + def sim_info_a(self) -> SimInfo: + """The Sim that has a Relationship Bit toward Sim B. + + :return: The Sim that has a Relationship Bit toward Sim B. + :rtype: SimInfo + """ + return self._sim_info_a + + @property + def sim_info_b(self) -> SimInfo: + """The Sim that has a Relationship Bit from Sim A. + + :return: The Sim that has a Relationship Bit from Sim A. + :rtype: SimInfo + """ + return self._sim_info_b + + @property + def relationship_bit(self) -> RelationshipBit: + """The RelationshipBit that was removed. + + :return: The RelationshipBit that was removed. + :rtype: RelationshipBit + """ + return self._relationship_bit + + @property + def relationship_bit_id(self) -> int: + """The decimal identifier of the RelationshipBit. + + :return: The decimal identifier of the RelationshipBit. + :rtype: int + """ + from sims4communitylib.utils.sims.common_relationship_utils import CommonRelationshipUtils + return CommonRelationshipUtils.get_relationship_bit_guid(self.relationship_bit) diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_removed_occult_type.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_removed_occult_type.py new file mode 100644 index 0000000..bc868a7 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_removed_occult_type.py @@ -0,0 +1,77 @@ +""" +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 +""" +from sims.occult.occult_enums import OccultType +from sims.occult.occult_tracker import OccultTracker +from sims.sim_info import SimInfo +from sims4communitylib.events.event_handling.common_event import CommonEvent + + +class S4CLSimRemovedOccultTypeEvent(CommonEvent): + """S4CLSimRemovedOccultTypeEvent(sim_info, occult_type, occult_tracker) + + An event that occurs when an OccultType has been removed from a Sim. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity().name) + def handle_event(event_data: S4CLSimRemovedOccultTypeEvent): + pass + + :param sim_info: The Sim the Occult Type was removed from. + :type sim_info: SimInfo + :param occult_type: The OccultType that was removed. + :type occult_type: OccultType + :param occult_tracker: A tracker that keeps track of the occult status of the Sim. + :type occult_tracker: OccultTracker + """ + + def __init__(self, sim_info: SimInfo, occult_type: OccultType, occult_tracker: OccultTracker): + self._sim_info = sim_info + self._occult_type = occult_type + self._occult_tracker = occult_tracker + + @property + def sim_info(self) -> SimInfo: + """The Sim the OccultType was removed from. + + :return: The Sim the OccultType was removed from. + :rtype: SimInfo + """ + return self._sim_info + + @property + def occult_type(self) -> OccultType: + """The OccultType that was removed. + + :return: The OccultType that was removed. + :rtype: OccultType + """ + return self._occult_type + + @property + def occult_tracker(self) -> OccultTracker: + """A tracker that keeps track of the occult status of the Sim. + + :return: A tracker that keeps track of the occult status of the Sim. + :rtype: OccultTracker + """ + return self._occult_tracker diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_revived.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_revived.py new file mode 100644 index 0000000..c9c3aef --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_revived.py @@ -0,0 +1,56 @@ +""" +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 +""" +from sims.sim_info import SimInfo +from sims4communitylib.enums.common_death_types import CommonDeathType +from sims4communitylib.events.event_handling.common_event import CommonEvent + + +class S4CLSimRevivedEvent(CommonEvent): + """S4CLSimRevivedEvent(sim_info, previous_death_type) + + An event that occurs when a Sim has been revived after having previously been dead. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity().name) + def handle_event(event_data: S4CLSimRevivedEvent): + pass + + :param sim_info: The Sim that was revived. + :type sim_info: SimInfo + :param previous_death_type: The type of Death that befell the Sim before they were revived. + :type previous_death_type: CommonDeathType + """ + + def __init__(self, sim_info: SimInfo, previous_death_type: CommonDeathType): + self._sim_info = sim_info + self._previous_death_type = previous_death_type + + @property + def sim_info(self) -> SimInfo: + """The Sim that was revived.""" + return self._sim_info + + @property + def previous_death_type(self) -> CommonDeathType: + """The type of Death that befell the Sim before they were revived.""" + return self._previous_death_type diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_set_current_outfit.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_set_current_outfit.py new file mode 100644 index 0000000..d7804f1 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_set_current_outfit.py @@ -0,0 +1,66 @@ +""" +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 +""" +from typing import Tuple + +from sims.outfits.outfit_enums import OutfitCategory +from sims.sim_info import SimInfo +from sims4communitylib.events.event_handling.common_event import CommonEvent + + +class S4CLSimSetCurrentOutfitEvent(CommonEvent): + """S4CLSimSetCurrentOutfitEvent(sim_info, old_outfit_category_and_index, new_outfit_category_and_index) + + An event that occurs when the current outfit of a Sim is being set. (Before it is actually set) + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity().name) + def handle_event(event_data: S4CLSimSetCurrentOutfitEvent): + pass + + :param sim_info: The Sim that changed. + :type sim_info: SimInfo + :param old_outfit_category_and_index: The outfit category and index for the outfit the Sim is changing from. + :type old_outfit_category_and_index: Tuple[OutfitCategory, int] + :param new_outfit_category_and_index: The outfit category and index for the outfit the Sim is changing to. + :type new_outfit_category_and_index: Tuple[OutfitCategory, int] + """ + + def __init__(self, sim_info: SimInfo, old_outfit_category_and_index: Tuple[OutfitCategory, int], new_outfit_category_and_index: Tuple[OutfitCategory, int]): + self._sim_info = sim_info + self._old_outfit_category_and_index = old_outfit_category_and_index + self._new_outfit_category_and_index = new_outfit_category_and_index + + @property + def sim_info(self) -> SimInfo: + """The Sim that is changing.""" + return self._sim_info + + @property + def old_outfit_category_and_index(self) -> Tuple[OutfitCategory, int]: + """The outfit category and index for the outfit the Sim is changing from.""" + return self._old_outfit_category_and_index + + @property + def new_outfit_category_and_index(self) -> Tuple[OutfitCategory, int]: + """The outfit category and index for the outfit the Sim is changing to.""" + return self._new_outfit_category_and_index diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_skill_leveled_up.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_skill_leveled_up.py new file mode 100644 index 0000000..fc1d6e3 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_skill_leveled_up.py @@ -0,0 +1,78 @@ +""" +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 +""" +from sims.sim_info import SimInfo +from sims4communitylib.events.event_handling.common_event import CommonEvent +from sims4communitylib.utils.resources.common_skill_utils import CommonSkillUtils +from statistics.skill import Skill + + +class S4CLSimSkillLeveledUpEvent(CommonEvent): + """S4CLSimSkillLeveledUpEvent(sim_info, skill, old_skill_level, new_skill_level) + + An event that occurs when a Sim levels up in a Skill. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity()) + def handle_event(event_data: S4CLSimSkillLeveledUpEvent): + pass + + :param sim_info: The Sim that changed. + :type sim_info: SimInfo + :param skill: The Skill that was leveled up. + :type skill: Skill + :param old_skill_level: The level the Sim was at before leveling up. + :type old_skill_level: int + :param new_skill_level: The level the Sim will be after leveling up. + :type new_skill_level: int + """ + + def __init__(self, sim_info: SimInfo, skill: Skill, old_skill_level: int, new_skill_level: int): + self._sim_info = sim_info + self._skill = skill + self._old_skill_level = old_skill_level + self._new_skill_level = new_skill_level + + @property + def new_skill_level(self) -> int: + """The level the Sim will be after leveling up.""" + return self._new_skill_level + + @property + def old_skill_level(self) -> int: + """The level the Sim was at before leveling up.""" + return self._old_skill_level + + @property + def sim_info(self) -> SimInfo: + """The Sim that leveled up in a Skill.""" + return self._sim_info + + @property + def skill(self) -> Skill: + """The Skill that was leveled up.""" + return self._skill + + @property + def skill_id(self) -> int: + """The decimal identifier of the Skill.""" + return CommonSkillUtils.get_skill_id(self.skill) diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_spawned.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_spawned.py new file mode 100644 index 0000000..6da5c6b --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_spawned.py @@ -0,0 +1,51 @@ +""" +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 +""" +from sims.sim_info import SimInfo +from sims4communitylib.events.event_handling.common_event import CommonEvent + + +class S4CLSimSpawnedEvent(CommonEvent): + """S4CLSimSpawnedEvent(sim_info) + + An event that occurs after a Sim has been spawned. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity().name) + def handle_event(event_data: S4CLSimSpawnedEvent): + pass + + :param sim_info: The Sim that was spawned. + :type sim_info: SimInfo + """ + + def __init__(self, sim_info: SimInfo): + self._sim_info = sim_info + + @property + def sim_info(self) -> SimInfo: + """The Sim that was spawned. + + :return: The Sim that was spawned. + :rtype: SimInfo + """ + return self._sim_info diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_trait_added.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_trait_added.py new file mode 100644 index 0000000..c5a67ad --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_trait_added.py @@ -0,0 +1,87 @@ +""" +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 +""" +from sims.sim_info import SimInfo +from sims4communitylib.events.event_handling.common_event import CommonEvent +from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils +from traits.trait_tracker import TraitTracker +from traits.traits import Trait + + +class S4CLSimTraitAddedEvent(CommonEvent): + """S4CLSimTraitAddedEvent(sim_info, trait, trait_tracker) + + An event that occurs when a Trait is added to a Sim. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity()) + def handle_event(event_data: S4CLSimTraitAddedEvent): + pass + + :param sim_info: The Sim that changed. + :type sim_info: SimInfo + :param trait: The Trait that was added. + :type trait: Trait + :param trait_tracker: The Trait Tracker being added to. + :type trait_tracker: TraitTracker + """ + + def __init__(self, sim_info: SimInfo, trait: Trait, trait_tracker: TraitTracker): + self._sim_info = sim_info + self._trait = trait + self._trait_tracker = trait_tracker + + @property + def sim_info(self) -> SimInfo: + """The Sim that received the trait. + + :return: The Sim that received the trait. + :rtype: SimInfo + """ + return self._sim_info + + @property + def trait(self) -> Trait: + """The Trait that was added. + + :return: The Trait that was added. + :rtype: Trait + """ + return self._trait + + @property + def trait_tracker(self) -> TraitTracker: + """The Trait Tracker being added to. + + :return: The Trait Tracker being added to. + :rtype: TraitTracker + """ + return self._trait_tracker + + @property + def trait_id(self) -> int: + """The decimal identifier of the Trait. + + :return: The decimal identifier of the Trait. + :rtype: int + """ + return CommonTraitUtils.get_trait_id(self.trait) diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_trait_removed.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_trait_removed.py new file mode 100644 index 0000000..30a1d4e --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_trait_removed.py @@ -0,0 +1,87 @@ +""" +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 +""" +from sims.sim_info import SimInfo +from sims4communitylib.events.event_handling.common_event import CommonEvent +from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils +from traits.trait_tracker import TraitTracker +from traits.traits import Trait + + +class S4CLSimTraitRemovedEvent(CommonEvent): + """S4CLSimTraitRemovedEvent(sim_info, trait, trait_tracker) + + An event that occurs when a Trait is removed from a Sim. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity()) + def handle_event(event_data: S4CLSimTraitRemovedEvent): + pass + + :param sim_info: The Sim that changed. + :type sim_info: SimInfo + :param trait: The Trait that was removed. + :type trait: Trait + :param trait_tracker: The Trait Tracker being removed from. + :type trait_tracker: TraitTracker + """ + + def __init__(self, sim_info: SimInfo, trait: Trait, trait_tracker: TraitTracker): + self._sim_info = sim_info + self._trait = trait + self._trait_tracker = trait_tracker + + @property + def sim_info(self) -> SimInfo: + """The Sim that lost the trait. + + :return: The Sim that lost the trait. + :rtype: SimInfo + """ + return self._sim_info + + @property + def trait(self) -> Trait: + """The Trait that was removed. + + :return: The Trait that was removed. + :rtype: Trait + """ + return self._trait + + @property + def trait_tracker(self) -> TraitTracker: + """The Trait Tracker being removed from. + + :return: The Trait Tracker being removed from. + :rtype: TraitTracker + """ + return self._trait_tracker + + @property + def trait_id(self) -> int: + """The decimal identifier of the Trait. + + :return: The decimal identifier of the Trait. + :rtype: int + """ + return CommonTraitUtils.get_trait_id(self.trait) diff --git a/Scripts/s4ap/sims4communitylib/events/zone_spin/__init__.py b/Scripts/s4ap/sims4communitylib/events/zone_spin/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/zone_spin/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/events/zone_spin/common_zone_spin_event_dispatcher.py b/Scripts/s4ap/sims4communitylib/events/zone_spin/common_zone_spin_event_dispatcher.py new file mode 100644 index 0000000..6ccbaeb --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/zone_spin/common_zone_spin_event_dispatcher.py @@ -0,0 +1,114 @@ +""" +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 +""" +from typing import Any + +from server.client import Client +from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry +from sims4communitylib.events.zone_spin.events.zone_early_load import S4CLZoneEarlyLoadEvent +from sims4communitylib.events.zone_spin.events.zone_late_load import S4CLZoneLateLoadEvent +from sims4communitylib.events.zone_spin.events.zone_manager_start_event import S4CLZoneManagerStartEvent +from sims4communitylib.events.zone_spin.events.zone_post_load import \ + S4CLZonePostLoadEvent +from sims4communitylib.events.zone_spin.events.zone_save import S4CLZoneSaveEvent +from sims4communitylib.events.zone_spin.events.zone_teardown import S4CLZoneTeardownEvent +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.common_service import CommonService +from sims4communitylib.utils.common_injection_utils import CommonInjectionUtils +from zone import Zone +from zone_manager import ZoneManager + + +class CommonZoneSpinEventDispatcher(CommonService): + """A service that dispatches zone spin events (Teardown, Save, Early/Late Load). + + .. warning:: Do not use this service directly to listen for events!\ + Use the :class:`.CommonEventRegistry` to listen for dispatched events. + + """ + def __init__(self: 'CommonZoneSpinEventDispatcher'): + self._game_loaded = False + self._game_loading = True + + @property + def game_loaded(self) -> bool: + """Determine if the game has loaded. + + :return: True, if the game has loaded. False, if the game has not loaded. + :rtype: bool + """ + return self._game_loaded + + @property + def game_loading(self) -> bool: + """Determine if the game is loading. + + :return: True, if the game is currently loading. False, if the game is not currently loading. + :rtype: bool + """ + return self._game_loading + + def _on_early_zone_load(self, zone: Zone): + CommonEventRegistry.get().dispatch(S4CLZoneEarlyLoadEvent(zone, game_loaded=self.game_loaded, game_loading=self.game_loading)) + + def _on_late_zone_load(self, zone: Zone, household_id: int, active_sim_id: int): + CommonEventRegistry.get().dispatch(S4CLZoneLateLoadEvent(zone, household_id, active_sim_id, game_loaded=self.game_loaded, game_loading=self.game_loading)) + self._game_loaded = True + self._game_loading = False + + def _on_zone_teardown(self, zone: Zone, client: Client): + CommonEventRegistry.get().dispatch(S4CLZoneTeardownEvent(zone, client, game_loaded=self.game_loaded, game_loading=self.game_loading)) + self._game_loading = True + + def _on_zone_save(self, zone: Zone, save_slot_data: Any = None): + CommonEventRegistry.get().dispatch(S4CLZoneSaveEvent(zone, save_slot_data=save_slot_data, game_loaded=self.game_loaded, game_loading=self.game_loading)) + + def _on_loading_screen_animation_finished(self, zone: Zone): + CommonEventRegistry.get().dispatch(S4CLZonePostLoadEvent(zone, game_loaded=self.game_loaded, game_loading=self.game_loading)) + + def _on_zone_manager_start(self, zone_manager: ZoneManager): + CommonEventRegistry.get().dispatch(S4CLZoneManagerStartEvent(zone_manager)) + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), Zone, Zone.load_zone.__name__, handle_exceptions=False) +def _common_on_early_zone_load(original, self: Zone, *args, **kwargs): + result = original(self, *args, **kwargs) + CommonZoneSpinEventDispatcher.get()._on_early_zone_load(self) + return result + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), Zone, Zone.do_zone_spin_up.__name__, handle_exceptions=False) +def _common_on_late_zone_load(original, self: Zone, *args, **kwargs): + result = original(self, *args, **kwargs) + CommonZoneSpinEventDispatcher.get()._on_late_zone_load(self, *args, **kwargs) + return result + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), Zone, Zone.on_teardown.__name__, handle_exceptions=False) +def _common_on_zone_teardown(original, self: Zone, client): + CommonZoneSpinEventDispatcher.get()._on_zone_teardown(self, client) + return original(self, client) + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), Zone, Zone.save_zone.__name__, handle_exceptions=False) +def _common_on_zone_save(original, self: Zone, *args, **kwargs): + CommonZoneSpinEventDispatcher.get()._on_zone_save(self, *args, **kwargs) + return original(self, *args, **kwargs) + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), Zone, Zone.on_loading_screen_animation_finished.__name__, handle_exceptions=False) +def _common_on_loading_screen_animation_finished(original, self: Zone, *args, **kwargs): + original_result = original(self, *args, **kwargs) + CommonZoneSpinEventDispatcher.get()._on_loading_screen_animation_finished(self) + return original_result + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), ZoneManager, ZoneManager.start.__name__, handle_exceptions=False) +def _common_on_zone_manager_start(original, self: ZoneManager, *args, **kwargs): + original_result = original(self, *args, **kwargs) + CommonZoneSpinEventDispatcher.get()._on_zone_manager_start(self) + return original_result diff --git a/Scripts/s4ap/sims4communitylib/events/zone_spin/events/__init__.py b/Scripts/s4ap/sims4communitylib/events/zone_spin/events/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/zone_spin/events/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_early_load.py b/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_early_load.py new file mode 100644 index 0000000..633d747 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_early_load.py @@ -0,0 +1,77 @@ +""" +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 +""" +from sims4communitylib.events.event_handling.common_event import CommonEvent +from zone import Zone + + +class S4CLZoneEarlyLoadEvent(CommonEvent): + """S4CLZoneEarlyLoadEvent(zone, game_loaded=False, game_loading=False) + + An event that occurs when a Zone has loaded. + + .. note:: This event occurs before the :class:`.S4CLZoneLateLoadEvent` + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity().name) + def handle_event(event_data: S4CLZoneEarlyLoadEvent): + pass + + :param zone: The Zone that was loaded. + :type zone: Zone + :param game_loaded: A value indicating if the game has been loaded. + :type game_loaded: bool + :param game_loading: A value indicating if the game is currently loading. + :type game_loading: bool + """ + + def __init__(self, zone: Zone, game_loaded: bool=False, game_loading: bool=False): + self._zone = zone + self._game_loaded = game_loaded + self._game_loading = game_loading + + @property + def zone(self) -> Zone: + """The Zone that was loaded. + + :return: The Zone that was loaded. + :rtype: Zone + """ + return self._zone + + @property + def game_loaded(self) -> bool: + """Determine if the game has loaded. + + :return: True, if the game has loaded. False, if the game has not loaded. + :rtype: bool + """ + return self._game_loaded + + @property + def game_loading(self) -> bool: + """Determine if the game is loading. + + :return: True, if the game is currently loading. False, if the game is not currently loading. + :rtype: bool + """ + return self._game_loading diff --git a/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_late_load.py b/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_late_load.py new file mode 100644 index 0000000..b49f44f --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_late_load.py @@ -0,0 +1,101 @@ +""" +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 +""" +from sims4communitylib.events.event_handling.common_event import CommonEvent +from zone import Zone + + +class S4CLZoneLateLoadEvent(CommonEvent): + """S4CLZoneLateLoadEvent(zone, household_id, active_sim_id, game_loaded=False, game_loading=False) + + An event that occurs when a Zone has finished spinning up. + + .. note:: This event occurs after the :class:`.S4CLZoneEarlyLoadEvent` and before the :class:`.S4CLZoneFinishedLoadEvent` + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity().name) + def handle_event(event_data: S4CLZoneLateLoadEvent): + pass + + :param zone: The Zone that has finished spinning up. + :type zone: Zone + :param household_id: The identifier of the Household that owns the Zone. + :type household_id: int + :param active_sim_id: The identifier of the Active Sim. + :type active_sim_id: int + :param game_loaded: A value indicating if the game has been loaded. + :type game_loaded: bool + :param game_loading: A value indicating if the game is currently loading. + :type game_loading: bool + """ + + def __init__(self, zone: Zone, household_id: int, active_sim_id: int, game_loaded: bool=False, game_loading: bool=False): + self._zone = zone + self._household_id = household_id + self._active_sim_id = active_sim_id + self._game_loaded = game_loaded + self._game_loading = game_loading + + @property + def zone(self) -> Zone: + """The Zone that has finished spinning up. + + :return: The Zone that has finished spinning up. + :rtype: Zone + """ + return self._zone + + @property + def household_id(self) -> int: + """The identifier of the Household that owns the Zone. + + :return: The identifier of the Household that owns the Zone. + :rtype: int + """ + return self._household_id + + @property + def active_sim_id(self) -> int: + """The identifier of the Active Sim. + + :return: The identifier of the Active Sim. + :rtype: int + """ + return self._active_sim_id + + @property + def game_loaded(self) -> bool: + """Determine if the game has loaded. + + :return: True, if the game has loaded. False, if the game has not loaded. + :rtype: bool + """ + return self._game_loaded + + @property + def game_loading(self) -> bool: + """Determine if the game is loading. + + :return: True, if the game is currently loading. False, if the game is not currently loading. + :rtype: bool + """ + return self._game_loading diff --git a/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_manager_start_event.py b/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_manager_start_event.py new file mode 100644 index 0000000..fa6768c --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_manager_start_event.py @@ -0,0 +1,51 @@ +""" +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 +""" +from sims4communitylib.events.event_handling.common_event import CommonEvent +from zone_manager import ZoneManager + + +class S4CLZoneManagerStartEvent(CommonEvent): + """S4CLZoneManagerStartEvent(zone_manager) + + An event that occurs after the Zone Manager is started. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity().name) + def handle_event(event_data: S4CLZoneManagerStartEvent): + pass + + :param zone_manager: The Zone Manager. + :type zone_manager: ZoneManager + """ + + def __init__(self, zone_manager: ZoneManager): + self._zone_manager = zone_manager + + @property + def zone_manager(self) -> ZoneManager: + """The Zone Manager + + :return: The Zone Manager. + :rtype: ZoneManager + """ + return self._zone_manager \ No newline at end of file diff --git a/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_post_load.py b/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_post_load.py new file mode 100644 index 0000000..0317910 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_post_load.py @@ -0,0 +1,75 @@ +""" +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 +""" +from sims4communitylib.events.event_handling.common_event import CommonEvent +from zone import Zone + + +class S4CLZonePostLoadEvent(CommonEvent): + """S4CLZonePostLoadEvent(zone, game_loaded=False, game_loading=False) + + An event that occurs when the Zone has finished loading and the loading screen is no longer visible. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity().name) + def handle_event(event_data: S4CLZonePostLoadEvent): + pass + + :param zone: The Zone that was loaded. + :type zone: Zone + :param game_loaded: A value indicating if the game has been loaded. + :type game_loaded: bool + :param game_loading: A value indicating if the game is currently loading. + :type game_loading: bool + """ + + def __init__(self, zone: Zone, game_loaded: bool=False, game_loading: bool=False): + self._zone = zone + self._game_loaded = game_loaded + self._game_loading = game_loading + + @property + def zone(self) -> Zone: + """The Zone that was loaded. + + :return: The Zone that was loaded. + :rtype: Zone + """ + return self._zone + + @property + def game_loaded(self) -> bool: + """Determine if the game has loaded at least once. + + :return: True, if the game has loaded at least once. False, if the game has not loaded. + :rtype: bool + """ + return self._game_loaded + + @property + def game_loading(self) -> bool: + """Determine if the game is loading. + + :return: True, if the game is currently loading. False, if the game is not currently loading. + :rtype: bool + """ + return self._game_loading diff --git a/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_save.py b/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_save.py new file mode 100644 index 0000000..29eab47 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_save.py @@ -0,0 +1,93 @@ +""" +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 +""" +from typing import Any + +from sims4communitylib.events.event_handling.common_event import CommonEvent +from zone import Zone + + +class S4CLZoneSaveEvent(CommonEvent): + """S4CLZoneSaveEvent(zone, save_slot_data=None, game_loaded=False, game_loading=False) + + An event that occurs upon a Zone being saved (Before it has been saved). + + .. note:: This event can occur when the Player is saving the game, switching save files, or traveling to a new zone. + + .. warning:: This event will also occur when the Player closes the game without saving. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity().name) + def handle_event(event_data: S4CLZoneSaveEvent): + pass + + :param zone: The Zone being saved. + :type zone: Zone + :param save_slot_data: The data that will be saved. + :type save_slot_data: Any + :param game_loaded: A value indicating if the game has been loaded. + :type game_loaded: bool + :param game_loading: A value indicating if the game is currently loading. + :type game_loading: bool + """ + + def __init__(self, zone: Zone, save_slot_data: Any=None, game_loaded: bool=False, game_loading: bool=False): + self._zone = zone + self._save_slot_data = save_slot_data + self._game_loaded = game_loaded + self._game_loading = game_loading + + @property + def zone(self) -> Zone: + """The Zone being saved. + + :return: The Zone being saved. + :rtype: Zone + """ + return self._zone + + @property + def save_slot_data(self) -> Any: + """The data that will be saved. + + :return: The data that will be saved. + :rtype: Any + """ + return self._save_slot_data + + @property + def game_loaded(self) -> bool: + """Determine if the game has loaded. + + :return: True, if the game has loaded. False, if the game has not loaded. + :rtype: bool + """ + return self._game_loaded + + @property + def game_loading(self) -> bool: + """Determine if the game is loading. + + :return: True, if the game is currently loading. False, if the game is not currently loading. + :rtype: bool + """ + return self._game_loading diff --git a/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_teardown.py b/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_teardown.py new file mode 100644 index 0000000..d365ef0 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_teardown.py @@ -0,0 +1,92 @@ +""" +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 +""" +from server.client import Client +from sims4communitylib.events.event_handling.common_event import CommonEvent +from zone import Zone + + +class S4CLZoneTeardownEvent(CommonEvent): + """S4CLZoneTeardownEvent(zone, client, game_loaded=False, game_loading=False) + + An event that occurs upon a Zone being saved (Before it has been torn down). + + .. note:: This event can occur when the Player travels to another lot. + + .. warning:: This event will also occur when the Player closes the game without saving. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity().name) + def handle_event(event_data: S4CLZoneTeardownEvent): + pass + + :param zone: The Zone being torn down. + :type zone: Zone + :param client: An instance of the Client. + :type client: Client + :param game_loaded: A value indicating if the game has been loaded. + :type game_loaded: bool + :param game_loading: A value indicating if the game is currently loading. + :type game_loading: bool + """ + + def __init__(self, zone: Zone, client: Client, game_loaded: bool=False, game_loading: bool=False): + self._zone = zone + self._client = client + self._game_loaded = game_loaded + self._game_loading = game_loading + + @property + def zone(self) -> Zone: + """The Zone being torn down. + + :return: The Zone being torn down. + :rtype: Zone + """ + return self._zone + + @property + def client(self) -> Client: + """An instance of the Client. + + :return: An instance of the Client. + :rtype: Client + """ + return self._client + + @property + def game_loaded(self) -> bool: + """Determine if the game has loaded. + + :return: True, if the game has loaded. False, if the game has not loaded. + :rtype: bool + """ + return self._game_loaded + + @property + def game_loading(self) -> bool: + """Determine if the game is loading. + + :return: True, if the game is currently loading. False, if the game is not currently loading. + :rtype: bool + """ + return self._game_loading diff --git a/Scripts/s4ap/sims4communitylib/events/zone_update/__init__.py b/Scripts/s4ap/sims4communitylib/events/zone_update/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/zone_update/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/events/zone_update/common_zone_update_event_dispatcher.py b/Scripts/s4ap/sims4communitylib/events/zone_update/common_zone_update_event_dispatcher.py new file mode 100644 index 0000000..ac2ce52 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/zone_update/common_zone_update_event_dispatcher.py @@ -0,0 +1,81 @@ +""" +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 +""" +import math +from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry +from sims4communitylib.events.zone_update.events.zone_update_event import S4CLZoneUpdateEvent +from sims4communitylib.logging.has_log import HasLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.common_service import CommonService +from sims4communitylib.utils.common_injection_utils import CommonInjectionUtils +from sims4communitylib.utils.common_time_utils import CommonTimeUtils +from zone import Zone + + +class CommonZoneUpdateEventDispatcherService(CommonService, HasLog): + """A service that dispatches zone update events. + + .. warning:: Do not use this service directly to listen for events!\ + Use the :class:`.CommonEventRegistry` to listen for dispatched events. + + """ + + # noinspection PyMissingOrEmptyDocstring + @property + def mod_identity(self) -> CommonModIdentity: + return ModInfo.get_identity() + + def __init__(self: 'CommonZoneUpdateEventDispatcherService'): + super().__init__() + self._last_absolute_ticks = 0 + self._ticks_since_last_zone_update = 0 + self._ticks_since_last_zone_update_error = 0 + + @property + def ticks_since_last_zone_update(self) -> int: + """The amount of time that has passed since the last zone update. + + :return: The amount of time that has passed in milliseconds + :rtype: int + """ + return self._ticks_since_last_zone_update + + @ticks_since_last_zone_update.setter + def ticks_since_last_zone_update(self, val: int): + self._ticks_since_last_zone_update = val + + def _update_ticks(self, diff_ticks: int): + if diff_ticks > 5000: + diff_ticks = 5000 + ideal_diff_ticks = diff_ticks * CommonTimeUtils.get_clock_speed_scale() + self._ticks_since_last_zone_update_error + rounded_ticks = math.floor(ideal_diff_ticks + 0.5) + ticks_error = ideal_diff_ticks - rounded_ticks + self._ticks_since_last_zone_update_error += max(min(ticks_error, 1), -1) + self.ticks_since_last_zone_update = rounded_ticks + + def _on_zone_update(self, zone: Zone, absolute_ticks: int): + try: + if not zone.is_zone_running: + return False + is_paused = CommonTimeUtils.game_is_paused() + if not is_paused: + diff_ticks = absolute_ticks - self._last_absolute_ticks + if diff_ticks < 0: + return False + self._update_ticks(diff_ticks) + self._last_absolute_ticks = absolute_ticks + return CommonEventRegistry.get().dispatch(S4CLZoneUpdateEvent(zone, is_paused, self.ticks_since_last_zone_update)) + except Exception as ex: + self.log.error('Failed to run internal method \'{}\' at \'{}\'.'.format(CommonZoneUpdateEventDispatcherService._on_zone_update.__name__, Zone.update.__name__), exception=ex) + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity().name, Zone, Zone.update.__name__, handle_exceptions=False) +def _common_zone_update(original, self: Zone, *_, **__): + result = original(self, *_, **__) + CommonZoneUpdateEventDispatcherService.get()._on_zone_update(self, *_, **__) + return result diff --git a/Scripts/s4ap/sims4communitylib/events/zone_update/events/__init__.py b/Scripts/s4ap/sims4communitylib/events/zone_update/events/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/zone_update/events/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/events/zone_update/events/zone_update_event.py b/Scripts/s4ap/sims4communitylib/events/zone_update/events/zone_update_event.py new file mode 100644 index 0000000..b1fbfd7 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/events/zone_update/events/zone_update_event.py @@ -0,0 +1,77 @@ +""" +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 +""" +from sims4communitylib.events.event_handling.common_event import CommonEvent +from zone import Zone + + +class S4CLZoneUpdateEvent(CommonEvent): + """S4CLZoneUpdateEvent(zone, is_paused, ticks_since_last_update) + + An event that occurs when a Zone has been updated. + + .. note:: This event can occur while the game is paused. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from sims4communitylib.modinfo import ModInfo + + class ExampleEventListener: + + # In order to listen to an event, your function must match these criteria: + # - The function is static (staticmethod). + # - The first and only required argument has the name "event_data". + # - The first and only required argument has the Type Hint for the event you are listening for. + # - The argument passed to "handle_events" is the name of your Mod. + @staticmethod + @CommonEventRegistry.handle_events(ModInfo.get_identity().name) + def handle_event(event_data: S4CLZoneUpdateEvent): + pass + + :param zone: The Zone that was updated. + :type zone: Zone + :param is_paused: A value indicating if the game was paused during the dispatching of this event. + :type is_paused: bool + :param ticks_since_last_update: The number of ticks since the last zone update in milliseconds. + :type ticks_since_last_update: int + """ + + def __init__(self, zone: Zone, is_paused: bool, ticks_since_last_update: int): + self._zone = zone + self._is_paused = is_paused + self._ticks_since_last_update = ticks_since_last_update + + @property + def zone(self) -> Zone: + """The Zone that was updated. + + :return: The Zone that was updated. + :rtype: Zone + """ + return self._zone + + @property + def is_paused(self) -> bool: + """Determine if the game was paused during the update. + + :return: True, if the game was paused. False, if the game was not paused. + :rtype: bool + """ + return self._is_paused + + @property + def ticks_since_last_update(self) -> int: + """The number of ticks in milliseconds since the last zone update. + + :return: The number of ticks in milliseconds since the last zone update. + :rtype: int + """ + return self._ticks_since_last_update diff --git a/Scripts/s4ap/sims4communitylib/examples/__init__.py b/Scripts/s4ap/sims4communitylib/examples/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/examples/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/examples/common_example_apply_bare_feet_buff.py b/Scripts/s4ap/sims4communitylib/examples/common_example_apply_bare_feet_buff.py new file mode 100644 index 0000000..fd8255a --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/examples/common_example_apply_bare_feet_buff.py @@ -0,0 +1,140 @@ +""" +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 +""" +from typing import Tuple + +from buffs.appearance_modifier.appearance_modifier import AppearanceModifier +from buffs.buff import Buff +from sims.sim_info import SimInfo +from sims4.tuning.tunable import TunableList, TunableTuple, TunableVariant, OptionalTunable +from sims4communitylib.classes.appearance_modifiers.common_attach_cas_parts_appearance_modifier import \ + CommonAttachCASPartsAppearanceModifier +from sims4communitylib.dtos.common_cas_part import CommonCASPart +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.utils.cas.common_cas_utils import CommonCASUtils +from sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils +from sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils +from sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils +from tunable_multiplier import TunableMultiplier + + +class CommonExampleApplyBareFeetAppearanceModifier(AppearanceModifier): + """An appearance modifier that applies bare feet to a Sim.""" + + class CommonAttachBareFeetModifier(CommonAttachCASPartsAppearanceModifier): + """Apply bare feet to a Sim.""" + # noinspection PyMissingOrEmptyDocstring + @property + def mod_identity(self) -> CommonModIdentity: + return ModInfo.get_identity() + + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + return 'common_example_apply_bare_feet' + + def _get_cas_parts( + self, + source_sim_info: SimInfo, + modified_sim_info: SimInfo, + original_unmodified_sim_info: SimInfo, + random_seed: int + ) -> Tuple[CommonCASPart]: + # Human + # yfShoes_Nude + adult_human_female_bare_feet_id = 6543 + # ymShoes_Nude + adult_human_male_bare_feet_id = 6563 + # cuShoes_Nude + child_human_bare_feet_id = 22018 + # puShoes_Nude + toddler_human_bare_feet_id = 132818 + + # Dog + # adShoes_Nude + adult_large_dog_bare_feet_id = 125251 + # alShoes_Nude + adult_small_dog_bare_feet_id = 148839 + # cdShoes_Nude + child_dog_bare_feet_id = 158046 + + # Cat + # acShoes_Nude + adult_cat_bare_feet_id = 150367 + # ccShoes_Nude + child_cat_bare_feet_id = 164111 + + # Fox + adult_fox_bare_feet_id = 277492 + + # Horse + adult_horse_bare_feet_id = 337140 + child_horse_bare_feet_id = 343457 + + bare_feet_cas_part_id = None + if CommonAgeUtils.is_teen_adult_or_elder(original_unmodified_sim_info): + if CommonSpeciesUtils.is_human(original_unmodified_sim_info): + if CommonGenderUtils.is_female(original_unmodified_sim_info): + bare_feet_cas_part_id = adult_human_female_bare_feet_id + elif CommonGenderUtils.is_male(original_unmodified_sim_info): + bare_feet_cas_part_id = adult_human_male_bare_feet_id + elif CommonSpeciesUtils.is_large_dog(original_unmodified_sim_info): + bare_feet_cas_part_id = adult_large_dog_bare_feet_id + elif CommonSpeciesUtils.is_small_dog(original_unmodified_sim_info): + bare_feet_cas_part_id = adult_small_dog_bare_feet_id + elif CommonSpeciesUtils.is_cat(original_unmodified_sim_info): + bare_feet_cas_part_id = adult_cat_bare_feet_id + elif CommonSpeciesUtils.is_fox(original_unmodified_sim_info): + bare_feet_cas_part_id = adult_fox_bare_feet_id + elif CommonSpeciesUtils.is_horse(original_unmodified_sim_info): + bare_feet_cas_part_id = adult_horse_bare_feet_id + elif CommonAgeUtils.is_child(original_unmodified_sim_info): + if CommonSpeciesUtils.is_human(original_unmodified_sim_info): + bare_feet_cas_part_id = child_human_bare_feet_id + elif CommonSpeciesUtils.is_large_dog(original_unmodified_sim_info) or CommonSpeciesUtils.is_small_dog(original_unmodified_sim_info): + bare_feet_cas_part_id = child_dog_bare_feet_id + elif CommonSpeciesUtils.is_cat(original_unmodified_sim_info): + bare_feet_cas_part_id = child_cat_bare_feet_id + elif CommonSpeciesUtils.is_horse(original_unmodified_sim_info): + bare_feet_cas_part_id = child_horse_bare_feet_id + elif CommonAgeUtils.is_toddler(original_unmodified_sim_info): + bare_feet_cas_part_id = toddler_human_bare_feet_id + + if bare_feet_cas_part_id is None: + return tuple() + + return CommonCASPart(bare_feet_cas_part_id, CommonCASUtils.get_body_type_of_cas_part(bare_feet_cas_part_id)), + + # We override the original "appearance_modifiers" to so we can insert our custom appearance modifier. + FACTORY_TUNABLES = { + 'appearance_modifiers': TunableList( + description='\n The specific appearance modifiers to use for this buff.\n ', + tunable=TunableList( + description='\n A tunable list of weighted modifiers. When applying modifiers\n one of the modifiers in this list will be applied. The weight\n will be used to run a weighted random selection.\n ', + tunable=TunableTuple( + description='\n A Modifier to apply and weight for the weighted random \n selection.\n ', + modifier=TunableVariant( + custom_bare_feet_modifier=CommonAttachBareFeetModifier.TunableFactory(), + ), + weight=TunableMultiplier.TunableFactory( + description='\n A weight with testable multipliers that is used to \n determine how likely this entry is to be picked when \n selecting randomly.\n ' + ) + ) + ) + ) + } + + +# We use this buff in a Buff tuning and then apply the buff to the Sim. +class CommonExampleApplyBareFeetBuff(Buff): + """A buff that applies bare feet to a Sim.""" + + # We override the original "appearance_modifier" to so we can insert our custom appearance modifier. + INSTANCE_TUNABLES = { + 'appearance_modifier': OptionalTunable(CommonExampleApplyBareFeetAppearanceModifier.TunableFactory()), + } diff --git a/Scripts/s4ap/sims4communitylib/exceptions/__init__.py b/Scripts/s4ap/sims4communitylib/exceptions/__init__.py new file mode 100644 index 0000000..3251898 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/exceptions/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" \ No newline at end of file diff --git a/Scripts/s4ap/sims4communitylib/exceptions/common_exceptions_handler.py b/Scripts/s4ap/sims4communitylib/exceptions/common_exceptions_handler.py new file mode 100644 index 0000000..edb78d9 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/exceptions/common_exceptions_handler.py @@ -0,0 +1,102 @@ +""" +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 +""" +from functools import wraps +from typing import Any, Callable, Union +from sims4communitylib.exceptions.common_stacktrace_utils import CommonStacktraceUtil +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.utils.common_date_utils import CommonRealDateUtils +from sims4communitylib.utils.common_io_utils import CommonIOUtils + + +class CommonExceptionHandler: + """A class for catching and logging exceptions to a file on the system. + + """ + + @staticmethod + def log_exception(mod_identifier: Union[str, CommonModIdentity, None], exception_message: str, exception: Exception=None, custom_file_path: str=None) -> bool: + """log_exception(mod_identifier, exception_message, exception=None, custom_file_path=None) + + Manually log an exception with a custom message. + + :param mod_identifier: The name or identity of the mod logging the exception. + :type mod_identifier: Union[str, CommonModIdentity] + :param exception_message: A message to provide more information about the exception. + :type exception_message: str + :param exception: The exception being logged. Default is None. + :type exception: Exception, optional + :param custom_file_path: A custom file path relative to The Sims 4 folder. Example: Value is 'fake_path/to/directory', the final path would be 'The Sims 4/fake_path/to_directory'. Default is None. + :type custom_file_path: str, optional + :return: True, if the message was successfully logged. False, if the message was not successfully logged. + :rtype: bool + """ + from sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils + mod_identifier = CommonModIdentityUtils.determine_mod_name_from_identifier(mod_identifier) + exceptions = CommonStacktraceUtil.get_full_stack_trace() + stack_trace = '{}{} -> {}: {}\n'.format(''.join(exceptions), exception_message, type(exception).__name__, exception) + from sims4communitylib.utils.common_log_registry import CommonLogUtils + file_path = CommonLogUtils.get_exceptions_file_path(mod_identifier, custom_file_path=custom_file_path) + result = CommonExceptionHandler._log_stacktrace(mod_identifier, stack_trace, file_path) + if result: + CommonExceptionHandler._notify_exception_occurred(file_path, mod_identifier=mod_identifier) + return result + + @staticmethod + def catch_exceptions(mod_identifier: Union[str, CommonModIdentity], fallback_return: Any=None) -> Callable[..., Any]: + """catch_exceptions(mod_identifier, fallback_return=None) + + Automatically catch exceptions thrown by the decorated function, log them to a file, and notify the player about the exception. + + .. note:: Decorate functions with this decorator to catch and log exceptions + + :param mod_identifier: The name or identity of the mod catching exceptions. + :type mod_identifier: Union[str, CommonModIdentity] + :param fallback_return: A value to return upon an exception being caught. Default is None. + :type fallback_return: Any, optional + :return: A function wrapped to catch and log exceptions. + :rtype: Callable[..., Any] + """ + from sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils + mod_identifier = CommonModIdentityUtils.determine_mod_name_from_identifier(mod_identifier) + + def _catch_exception(exception_function: Callable[..., Any]): + @wraps(exception_function) + def _wrapper(*args, **kwargs) -> Any: + try: + return exception_function(*args, **kwargs) + except Exception as ex: + CommonExceptionHandler.log_exception(mod_identifier, 'Exception caught while invoking: {}'.format(exception_function.__name__), exception=ex) + return fallback_return + return _wrapper + return _catch_exception + + @staticmethod + def _log_stacktrace(mod_identifier: Union[str, CommonModIdentity], _traceback: str, file_path: str) -> bool: + from sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils + mod_identifier = CommonModIdentityUtils.determine_mod_name_from_identifier(mod_identifier) + exception_traceback_text = '[{}] {} {}\n'.format(mod_identifier, CommonRealDateUtils.get_current_date_string(), _traceback) + return CommonIOUtils.write_to_file(file_path, exception_traceback_text, ignore_errors=True) + + @staticmethod + def _notify_exception_occurred(file_path: str, mod_identifier: Union[str, CommonModIdentity]=None): + from ui.ui_dialog_notification import UiDialogNotification + from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification + from sims4communitylib.enums.strings_enum import CommonStringId + from sims4communitylib.events.zone_spin.common_zone_spin_event_dispatcher import CommonZoneSpinEventDispatcher + if not CommonZoneSpinEventDispatcher.get().game_loaded: + return + from sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils + mod_identifier = CommonModIdentityUtils.determine_mod_name_from_identifier(mod_identifier) + basic_notification = CommonBasicNotification( + CommonStringId.EXCEPTION_OCCURRED_TITLE_FOR_MOD, + CommonStringId.EXCEPTION_OCCURRED_TEXT, + title_tokens=(mod_identifier,), + description_tokens=(file_path,), + urgency=UiDialogNotification.UiDialogNotificationUrgency.URGENT + ) + basic_notification.show() diff --git a/Scripts/s4ap/sims4communitylib/exceptions/common_stacktrace_utils.py b/Scripts/s4ap/sims4communitylib/exceptions/common_stacktrace_utils.py new file mode 100644 index 0000000..32bc3fe --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/exceptions/common_stacktrace_utils.py @@ -0,0 +1,73 @@ +""" +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 +""" +import sys +import traceback +from collections import namedtuple +from typing import Union, Any, List + +# The following was tweaked slightly from the publicly made available, copyright free code here: https://stackoverflow.com/questions/13210436/get-full-traceback +from sims4communitylib.utils.common_collection_utils import CommonCollectionUtils + +FullTraceback = namedtuple('FullTraceback', ('tb_frame', 'tb_lineno', 'tb_next')) + + +class CommonStacktraceUtil: + """Utilities for accessing the full stack trace of your application. + + """ + @staticmethod + def current_stack(skip: int=0) -> Any: + """Retrieve the current stack + + :param skip: The number of lines to skip + :return: A collection of the current stack. + """ + cur_frame = None + try: + 1/0 + except ZeroDivisionError: + cur_frame = sys.exc_info()[2].tb_frame + for i in range(skip + 2): + cur_frame = cur_frame.f_back + stack_trace = [] + while cur_frame is not None: + stack_trace.append((cur_frame, cur_frame.f_lineno)) + cur_frame = cur_frame.f_back + return stack_trace + + @staticmethod + def _extend_traceback(tb, stack) -> FullTraceback: + """Extend traceback with stack info. + + """ + head = tb + for traceback_frame, traceback_line_number in stack: + head = FullTraceback(traceback_frame, traceback_line_number, head) + return head + + @staticmethod + def full_exception_info() -> Union[type, Any, FullTraceback]: + """Like sys.exc_info, but includes the full traceback. + + """ + exception_type, exception_value, exception_traceback = sys.exc_info() + full_traceback = CommonStacktraceUtil._extend_traceback(exception_traceback, CommonStacktraceUtil.current_stack(1)) + return exception_type, exception_value, full_traceback + + @staticmethod + def get_full_stack_trace() -> List[str]: + """Retrieve the full stacktrace from the current stack. + + :return: A collection of stack trace strings. + """ + exception_info = CommonStacktraceUtil.full_exception_info() + if CommonCollectionUtils.is_collection(exception_info): + exceptions = traceback.format_exception(*exception_info) + else: + exceptions = traceback.format_stack() + return exceptions diff --git a/Scripts/s4ap/sims4communitylib/exceptions/generic_error_handling.py b/Scripts/s4ap/sims4communitylib/exceptions/generic_error_handling.py new file mode 100644 index 0000000..74278f0 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/exceptions/generic_error_handling.py @@ -0,0 +1,34 @@ +""" +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 +""" +from pprint import pformat + +from broadcasters.broadcaster import Broadcaster +from sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.utils.common_injection_utils import CommonInjectionUtils +from sims4communitylib.utils.resources.common_interaction_utils import CommonInteractionUtils + + +# Some interactions cause an error in this function, this is here to catch those errors and provide more information about them. +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), Broadcaster, Broadcaster.apply_broadcaster_effect.__name__, handle_exceptions=False) +def _common_broadcaster_apply(original, self: Broadcaster, *_, **__) -> None: + try: + return original(self, *_, **__) + except Exception as ex: + if self.interaction is not None: + interaction = self.interaction + # noinspection PyTypeChecker + CommonExceptionHandler.log_exception(None, 'Error occurred while running apply_broadcaster_effect for broadcaster {} for interaction {} with short name {} and display name {} (This exception is not caused by S4CL, but rather caught)'.format(pformat(self), pformat(interaction), CommonInteractionUtils.get_interaction_short_name(interaction), CommonInteractionUtils.get_interaction_display_name(interaction)), exception=ex) + elif self.broadcasting_object is not None: + broadcasting_object = self.broadcasting_object + # noinspection PyTypeChecker + CommonExceptionHandler.log_exception(None, 'Error occurred while running apply_broadcaster_effect for broadcaster {} from object {} (This exception is not caused by S4CL, but rather caught)'.format(pformat(self), pformat(broadcasting_object)), exception=ex) + else: + # noinspection PyTypeChecker + CommonExceptionHandler.log_exception(None, 'Error occurred while running apply_broadcaster_effect for broadcaster {} (This exception is not caused by S4CL, but rather caught)'.format(pformat(self)), exception=ex) + return None diff --git a/Scripts/s4ap/sims4communitylib/logging/__init__.py b/Scripts/s4ap/sims4communitylib/logging/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/logging/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/logging/_has_s4cl_class_log.py b/Scripts/s4ap/sims4communitylib/logging/_has_s4cl_class_log.py new file mode 100644 index 0000000..05cdf19 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/logging/_has_s4cl_class_log.py @@ -0,0 +1,28 @@ +""" +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 +""" +from sims4communitylib.logging.has_class_log import HasClassLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo + + +class _HasS4CLClassLog(HasClassLog): + """_HasS4CLClassLog() + + .. note:: This class should only be used by S4CL itself, do not inherit from this class in your own mods! + + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + return ModInfo.get_identity() + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + raise NotImplementedError() diff --git a/Scripts/s4ap/sims4communitylib/logging/_has_s4cl_log.py b/Scripts/s4ap/sims4communitylib/logging/_has_s4cl_log.py new file mode 100644 index 0000000..d88bf1b --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/logging/_has_s4cl_log.py @@ -0,0 +1,28 @@ +""" +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 +""" +from sims4communitylib.logging.has_log import HasLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo + + +class _HasS4CLLog(HasLog): + """_HasS4CLLog() + + .. note:: This class should only be used by S4CL itself, do not inherit from this class in your own mods! + + """ + + # noinspection PyMissingOrEmptyDocstring + @property + def mod_identity(self) -> CommonModIdentity: + return ModInfo.get_identity() + + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + raise NotImplementedError() diff --git a/Scripts/s4ap/sims4communitylib/logging/_logging_commands.py b/Scripts/s4ap/sims4communitylib/logging/_logging_commands.py new file mode 100644 index 0000000..29e2bb5 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/logging/_logging_commands.py @@ -0,0 +1,156 @@ +""" +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 +""" +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + CommonConsoleCommandArgument +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.common_log_registry import CommonLogRegistry + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.enable_log', + 'Enable a log. Once enabled, any code that uses the functions of the log will starting logging their messages to "The Sims 4/mod_logs/modname_Messages.txt"', + command_arguments=( + CommonConsoleCommandArgument('log_name', 'Text', 'The name of a log to enable.'), + CommonConsoleCommandArgument('mod_name', 'Text', 'The name of the mod to enable the log for. If a log is not available for a mod, but you know it exists, specify this argument to enable it without having to wait for the log itself to be used in the code first. If not specified, then the log will be enabled for all mods.', is_optional=True, default_value='All Mods'), + ), + command_aliases=( + 's4clib.enablelog', + ) +) +def _common_command_enable_log(output: CommonConsoleCommandOutput, log_name: str, mod_name: str=None): + if log_name is None: + output('ERROR: No log name specified (See all logs via "s4clib.logs" command)') + return + if mod_name is None: + output(f'Attempting to enable log \'{log_name}\'.') + else: + output(f'Attempting to enable log \'{log_name}\' for mod \'{mod_name}\'.') + if CommonLogRegistry.get().log_exists(log_name, mod_identifier=mod_name) or mod_name is not None: + if CommonLogRegistry.get().enable_logs(log_name, mod_identifier=mod_name): + if mod_name is None: + output(f'SUCCESS: Log \'{log_name}\' was successfully enabled.') + else: + output(f'SUCCESS: Log \'{log_name}\' was successfully enabled for mod \'{mod_name}\'.') + else: + if mod_name is None: + output(f'FAILED: Failed to enable log \'{log_name}\'. Do you need to specify a mod name?') + else: + output(f'FAILED: Failed to enable log \'{log_name}\' for mod \'{mod_name}\'.') + else: + if mod_name is None: + output(f'ERROR: No log found with name \'{log_name}\'.') + else: + output(f'ERROR: No log found with name \'{log_name}\' for mod \'{mod_name}\'.') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.disable_log', + 'Disable a log. Once disabled, any code that uses the functions of the log will stop logging their messages to "The Sims 4/mod_logs/modname_Messages.txt"', + command_arguments=( + CommonConsoleCommandArgument('log_name', 'Text', 'The name of a log to disable.'), + CommonConsoleCommandArgument('mod_name', 'Text', 'The name of the mod to disable the log for. If not specified, then the log will be disabled for all mods.', is_optional=True, default_value='All Mods'), + ), + command_aliases=( + 's4clib.disablelog', + ) +) +def _common_command_disable_log(output: CommonConsoleCommandOutput, log_name: str, mod_name: str=None): + if log_name is None: + output('specify a log name (See all logs via "s4clib.logs" command)') + return + if mod_name is None: + output(f'Attempting to disable log \'{log_name}\'.') + else: + output(f'Attempting to disable log \'{log_name}\' for mod \'{mod_name}\'.') + if CommonLogRegistry().log_exists(log_name, mod_identifier=mod_name): + if CommonLogRegistry().disable_logs(log_name, mod_identifier=mod_name): + if mod_name is None: + output(f'SUCCESS: Log \'{log_name}\' was successfully disabled.') + else: + output(f'SUCCESS: Log \'{log_name}\' was successfully disabled for mod \'{mod_name}\'.') + else: + if mod_name is None: + output(f'Failed to disable log \'{log_name}\'. Do you need to specify a mod name?') + else: + output(f'Failed to disable log \'{log_name}\' for mod \'{mod_name}\'.') + else: + if mod_name is None: + output(f'ERROR: Log \'{log_name}\' did not exist.') + else: + output(f'ERROR: Log \'{log_name}\' did not exist for mod \'{mod_name}\'.') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.disable_all_logs', + 'Disable all logs.', + command_arguments=( + CommonConsoleCommandArgument('mod_name', 'Text', 'The name of the mod to disable logs for. If not specified, then logs will be disabled for all mods.', is_optional=True, default_value='All Mods'), + ), + command_aliases=( + 's4clib.disablealllogs', + ) +) +def _common_command_disable_all_logs(output: CommonConsoleCommandOutput, mod_name: str=None): + if mod_name is None: + output('Disabling all logs.') + else: + output(f'Disabling all logs for mod \'{mod_name}\'.') + CommonLogRegistry.get().disable_all_logs(mod_identifier=mod_name) + if mod_name is None: + output(f'SUCCESS: All logs successfully disabled.') + else: + output(f'SUCCESS: All logs for mod \'{mod_name}\' successfully disabled.') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.enablealllogs', + 'Enable all logs.', + command_arguments=( + CommonConsoleCommandArgument('mod_name', 'Text', 'The name of the mod to enable logs for. If not specified, then logs will be enabled for all mods.', is_optional=True, default_value='All Mods'), + ), + command_aliases=( + 's4clib.enablealllogs', + ) +) +def _common_command_enable_all_logs(output: CommonConsoleCommandOutput, mod_name: str=None): + if mod_name is None: + output(f'Attempting to enable all logs.') + else: + output(f'Attempting to enable log for mod \'{mod_name}\'.') + CommonLogRegistry.get().enable_all_logs(mod_identifier=mod_name) + if mod_name is None: + output(f'SUCCESS: All logs successfully enabled.') + else: + output(f'SUCCESS: All logs for mod \'{mod_name}\' successfully enabled.') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.logs', + 'Print a list of all available logs.', + command_arguments=( + CommonConsoleCommandArgument('mod_name', 'Text', 'If specified, all logs related to the specified mod will be listed. If not specified, all logs will be listed.', is_optional=True, default_value=None), + ) +) +def _common_command_show_all_logs(output: CommonConsoleCommandOutput, mod_name: str=None): + log_names = CommonLogRegistry.get().get_registered_log_names(mod_identifier=mod_name) + if log_names is None: + return + if not log_names: + if mod_name is None: + output(f'FAILED: No mods have registered any logs') + else: + output(f'FAILED: \'{mod_name} has not registered any logs') + return + for log_name in log_names: + output(str(log_name)) diff --git a/Scripts/s4ap/sims4communitylib/logging/has_class_log.py b/Scripts/s4ap/sims4communitylib/logging/has_class_log.py new file mode 100644 index 0000000..8181883 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/logging/has_class_log.py @@ -0,0 +1,132 @@ +""" +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 +""" +from typing import TYPE_CHECKING + +from sims4communitylib.logging.has_log import HasLog +from sims4communitylib.mod_support.has_class_mod_identity import HasClassModIdentity +from sims4communitylib.mod_support.mod_identity import CommonModIdentity + +if TYPE_CHECKING: + from sims4communitylib.utils.common_log_registry import CommonLog, CommonLogRegistry + + +class HasClassLog(HasClassModIdentity, HasLog): + """HasClassLog() + + An inheritable class that will add a log and mod identity to a class. + + .. note:: This class inherits from :class:`.HasLog` and may be used as an alternative to it. + + """ + def __init__(self) -> None: + super().__init__() + HasLog.__init__(self) + + # noinspection PyMissingOrEmptyDocstring + @property + def mod_identity(self) -> CommonModIdentity: + return self.__class__.get_mod_identity() + + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + return self.__class__.get_log_identifier() + + # noinspection PyMissingOrEmptyDocstring + @property + def verbose_log_identifier(self) -> str: + return self.__class__.get_verbose_log_identifier() + + # noinspection PyMissingOrEmptyDocstring + @property + def log(self) -> 'CommonLog': + return self.__class__.get_log() + + # noinspection PyMissingOrEmptyDocstring + @property + def verbose_log(self) -> 'CommonLog': + return self.__class__.get_verbose_log() + + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + """get_mod_identity() + + Retrieve the identity of the mod that owns the class. + + .. warning:: Override this function with the :class:`.CommonModIdentity` of your mod. + + This is a *MUST* override to allow for proper Exception Handling and Logging! + + :return: An instance of CommonModIdentity + :rtype: CommonModIdentity + :exception NotImplementedError: Thrown when the function is not implemented. + """ + raise NotImplementedError(f'Missing \'{cls.__name__}.get_mod_identity\'.') + + @classmethod + def get_log(cls) -> 'CommonLog': + """get_log() + + Retrieve a log for the class. + + .. note:: This function uses the :func:`~get_mod_identity` and :func:`~get_log_identifier` functions when logging. + + :return: An instance of CommonLog + :rtype: CommonLog + """ + from sims4communitylib.utils.common_log_registry import CommonLogRegistry + if not hasattr(cls, '_log') or getattr(cls, '_log', None) is None: + setattr(cls, '_log', CommonLogRegistry().register_log(cls.get_mod_identity(), cls.get_log_identifier())) + if not hasattr(cls, '_verbose_log') or getattr(cls, '_verbose_log', None) is None: + setattr(cls, '_verbose_log', CommonLogRegistry().register_log(cls.get_mod_identity(), cls.get_verbose_log_identifier())) + return getattr(cls, '_log', None) + + @classmethod + def get_verbose_log(cls) -> 'CommonLog': + """get_verbose_log() + + Retrieve a verbose log for the class. + + .. note:: This function uses the :func:`~get_mod_identity` and :func:`~get_verbose_log_identifier` functions when logging. + + .. note:: This log can be used to log extra details that you don't want to appear when using the non verbose log. + + :return: An instance of CommonLog + :rtype: CommonLog + """ + from sims4communitylib.utils.common_log_registry import CommonLogRegistry + if not hasattr(cls, '_verbose_log') or getattr(cls, '_verbose_log', None) is None: + setattr(cls, '_verbose_log', CommonLogRegistry().register_log(cls.get_mod_identity(), cls.get_verbose_log_identifier())) + return getattr(cls, '_verbose_log', None) + + @classmethod + def get_log_identifier(cls) -> str: + """get_log_identifier() + + A string identifier for the log of the class. + + .. note:: This is the text that will appear when logging messages. + + :return: The identifier for the log + :rtype: str + """ + return cls.__name__ + + @classmethod + def get_verbose_log_identifier(cls) -> str: + """get_verbose_log_identifier() + + A string identifier for the log of the class. + + .. note:: This is the text that will appear when logging messages. + + :return: The identifier for the log + :rtype: str + """ + log_identifier = cls.get_log_identifier() + return f'{log_identifier}_verbose' diff --git a/Scripts/s4ap/sims4communitylib/logging/has_log.py b/Scripts/s4ap/sims4communitylib/logging/has_log.py new file mode 100644 index 0000000..f6ac1c0 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/logging/has_log.py @@ -0,0 +1,93 @@ +""" +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 +""" +from typing import TYPE_CHECKING, Union +from sims4communitylib.mod_support.has_mod_identity import HasModIdentity +from sims4communitylib.mod_support.mod_identity import CommonModIdentity + +if TYPE_CHECKING: + from sims4communitylib.utils.common_log_registry import CommonLog, CommonLogRegistry + + +class HasLog(HasModIdentity): + """HasLog() + + An inheritable class that will add a log and mod identity to a class. + + """ + def __init__(self) -> None: + self._log: Union['CommonLog', None] = None + self._verbose_log: Union['CommonLog', None] = None + self._mod_identity: Union[CommonModIdentity, None] = None + + @property + def mod_identity(self) -> CommonModIdentity: + """The identity of the mod that owns this property + + .. warning:: Override this property with the :class:`.CommonModIdentity` of your mod. + + This is a *MUST* override to allow for proper Exception Handling and Logging! + + :return: An instance of CommonModIdentity + :rtype: CommonModIdentity + :exception NotImplementedError: Thrown when the property is not implemented. + """ + raise NotImplementedError(f'Missing \'{self.__class__.__name__}.mod_identity\'.') + + @property + def verbose_log(self) -> 'CommonLog': + """The verbose log for instances of the class. + + .. note:: It uses the `mod_identity` and `verbose_log_identifier` when logging. + + .. note:: This log can be used to log extra details that you don't want to appear when using the non verbose log. + + :return: An instance of CommonLog + :rtype: CommonLog + """ + if self._verbose_log is None: + from sims4communitylib.utils.common_log_registry import CommonLogRegistry + self._verbose_log = CommonLogRegistry.get().register_log(self.mod_identity, self.verbose_log_identifier) + return self._verbose_log + + @property + def log(self) -> 'CommonLog': + """The log for instances of the class. + + .. note:: It uses the `mod_identity` and `log_identifier` when logging. + + :return: An instance of CommonLog + :rtype: CommonLog + """ + if self._log is None: + from sims4communitylib.utils.common_log_registry import CommonLogRegistry + self._log = CommonLogRegistry.get().register_log(self.mod_identity, self.log_identifier) + if self._verbose_log is None: + self._verbose_log = CommonLogRegistry.get().register_log(self.mod_identity, self.verbose_log_identifier) + return self._log + + @property + def log_identifier(self) -> str: + """A string identifier for the log used by instances of the class. + + .. note:: This is the message identifier that will appear when logging messages. + + :return: The identifier of the log + :rtype: str + """ + return self.__class__.__name__ + + @property + def verbose_log_identifier(self) -> str: + """A string identifier for the verbose log used by instances of the class. + + .. note:: This is the message identifier that will appear when logging messages. + + :return: The identifier of the verbose log + :rtype: str + """ + return f'{self.log_identifier}_verbose' diff --git a/Scripts/s4ap/sims4communitylib/logging/vanilla_logging.py b/Scripts/s4ap/sims4communitylib/logging/vanilla_logging.py new file mode 100644 index 0000000..4baa404 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/logging/vanilla_logging.py @@ -0,0 +1,211 @@ +""" +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 +""" +from typing import Any + +from sims4.log import Logger +from sims4communitylib.classes.time.common_stop_watch import CommonStopWatch +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.s4cl_configuration import S4CLConfiguration +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.services.common_service import CommonService +from sims4communitylib.utils.common_injection_utils import CommonInjectionUtils +from sims4communitylib.utils.common_log_registry import CommonLogRegistry, CommonLog +from sims4communitylib.utils.misc.common_text_utils import CommonTextUtils + + +class _CommonVanillaLogOverride(CommonService): + def __init__(self) -> None: + self.logs_enabled = S4CLConfiguration().enable_vanilla_logging + self.logs = list() + self.stop_watches = dict() + self.last_time = dict() + + def get_log(self, log_name: str) -> CommonLog: + """ Get a log for a log name. """ + _log = CommonLogRegistry().register_log(f'{log_name}_S4CLVanillaLog', 'log', 'vanilla_logs') + _log.enable() + self.logs.append(_log) + return _log + + def _format_message(self, message, *args, owner=None, **__) -> str: + to_log_message = message + if args: + to_log_message = to_log_message.format(*args) + if owner: + to_log_message = f'[{owner}] {to_log_message}' + return to_log_message + + def enable_logs(self) -> None: + """ Enable logs. """ + self.logs_enabled = True + + def disable_logs(self) -> None: + """ Disable logs. """ + self.logs_enabled = False + + def _log(self, log_name: str, message: str, *args, level, owner=None, **kwargs) -> Any: + if not self.logs_enabled: + return + message = self._append_time(log_name, message) + _log = _CommonVanillaLogOverride().get_log(log_name) + to_log_message = _CommonVanillaLogOverride()._format_message(message, *args, owner=owner, **kwargs) + _log.debug(f'{level}: {to_log_message}') + + def _debug(self, log_name: str, message: str, *args, owner=None, **kwargs) -> Any: + if not self.logs_enabled: + return + message = self._append_time(log_name, message) + _log = _CommonVanillaLogOverride().get_log(log_name) + to_log_message = _CommonVanillaLogOverride()._format_message(message, *args, owner=owner, **kwargs) + _log.debug(to_log_message) + + def _info(self, log_name: str, message: str, *args, owner=None, **kwargs) -> Any: + if not self.logs_enabled: + return + message = self._append_time(log_name, message) + _log = _CommonVanillaLogOverride().get_log(log_name) + to_log_message = _CommonVanillaLogOverride()._format_message(message, *args, owner=owner, **kwargs) + _log.info(to_log_message) + + def _warn(self, log_name: str, message: str, *args, owner=None, **kwargs) -> Any: + if not self.logs_enabled: + return + message = self._append_time(log_name, message) + _log = _CommonVanillaLogOverride().get_log(log_name) + to_log_message = _CommonVanillaLogOverride()._format_message(message, *args, owner=owner, **kwargs) + _log.warn(to_log_message) + + def _error(self, log_name: str, message: str, *args, owner=None, **kwargs) -> Any: + if not self.logs_enabled: + return + message = self._append_time(log_name, message) + _log = _CommonVanillaLogOverride().get_log(log_name) + to_log_message = _CommonVanillaLogOverride()._format_message(message, *args, owner=owner, **kwargs) + _log.error(to_log_message + ' (This exception is not caused by S4CL, but rather caught)') + + def _exception(self, log_name: str, message: str, *args, exc: Exception = None, owner=None, **kwargs) -> Any: + if not self.logs_enabled: + return + message = self._append_time(log_name, message) + _log = _CommonVanillaLogOverride().get_log(log_name) + to_log_message = _CommonVanillaLogOverride()._format_message(message, *args, owner=owner, **kwargs) + _log.error(to_log_message + ' (This exception is not caused by S4CL, but rather caught)', exception=exc, throw=True) + + def _append_time(self, log_name: str, message: str) -> str: + stop_watch = self._get_stop_watch(log_name) + interval = stop_watch.interval_milliseconds() + if log_name not in self.last_time: + self.last_time[log_name] = interval + compare_time = 0 + else: + last_time = self.last_time[log_name] + compare_time = interval - last_time + self.last_time[log_name] = interval + interval_str = CommonTextUtils.to_truncated_decimal(interval) + compare_time_str = CommonTextUtils.to_truncated_decimal(compare_time) + return f'{interval_str}ms +{compare_time_str}ms {message}' + + def _get_stop_watch(self, log_name: str) -> CommonStopWatch: + if log_name not in self.stop_watches: + stop_watch = CommonStopWatch() + stop_watch.start() + self.stop_watches[log_name] = stop_watch + return self.stop_watches[log_name] + + def _clear_log_times(self) -> None: + stop_watches = list(self.stop_watches.values()) + self.stop_watches.clear() + self.stop_watches.clear() + self.last_time.clear() + for stop_watch in stop_watches: + stop_watch.stop() + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.enable_vanilla_logs', + 'Enable the Vanilla Logs. Vanilla Logs are useful for discovering previously unknown exceptions and messages being logged by the game itself. Vanilla logs appear under "The Sims 4/mod_logs/vanilla_logs"', + command_aliases=( + 's4clib.enablevanillalogs', + ) +) +def _common_enable_vanilla_logs(output: CommonConsoleCommandOutput): + output('Enabling the Vanilla Logs.') + if _CommonVanillaLogOverride().logs_enabled: + output('The Vanilla Logs are already enabled.') + return + _CommonVanillaLogOverride()._clear_log_times() + _CommonVanillaLogOverride().enable_logs() + output('Vanilla Logs are now enabled.') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.disable_vanilla_logs', + 'Disable the Vanilla Logs.', + command_aliases=( + 's4clib.disablevanillalogs', + ) +) +def _common_disable_vanilla_logs(output: CommonConsoleCommandOutput): + output('Disabling the Vanilla Logs.') + if not _CommonVanillaLogOverride().logs_enabled: + output('The Vanilla Logs are already disabled.') + return + _CommonVanillaLogOverride().disable_logs() + _CommonVanillaLogOverride()._clear_log_times() + output('Vanilla Logs are now disabled.') + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), Logger, 'log', handle_exceptions=False) +def _common_logger_log(original, self, message, *args, level, owner=None, **kwargs) -> Any: + log_name = self.group + _CommonVanillaLogOverride()._log(log_name, message, *args, level, owner=owner or self.default_owner, **kwargs) + return original(self, message, *args, level, owner=owner, **kwargs) + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), Logger, 'debug', handle_exceptions=False) +def _common_logger_debug(original, self, message, *args, owner=None, **kwargs) -> Any: + log_name = self.group + _CommonVanillaLogOverride()._debug(log_name, message, *args, owner=owner or self.default_owner, **kwargs) + return original(self, message, *args, owner=owner, **kwargs) + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), Logger, 'info', handle_exceptions=False) +def _common_logger_info(original, self, message, *args, owner=None, **kwargs) -> Any: + log_name = self.group + _CommonVanillaLogOverride()._info(log_name, message, *args, owner=owner or self.default_owner, **kwargs) + return original(self, message, *args, owner=owner, **kwargs) + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), Logger, 'warn', handle_exceptions=False) +def _common_logger_warn(original, self, message, *args, owner=None, **kwargs) -> Any: + log_name = self.group + _CommonVanillaLogOverride()._warn(log_name, message, *args, owner=owner or self.default_owner, **kwargs) + return original(self, message, *args, owner=owner, **kwargs) + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), Logger, 'error', handle_exceptions=False) +def _common_logger_error(original, self, message, *args, owner=None, **kwargs) -> Any: + log_name = self.group + _CommonVanillaLogOverride()._error(log_name, message, *args, owner=owner or self.default_owner, **kwargs) + return original(self, message, *args, owner=owner, **kwargs) + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), Logger, 'exception', handle_exceptions=False) +def _common_logger_exception(original, self, message, *args, exc=None, owner=None, **kwargs) -> Any: + log_name = self.group + _CommonVanillaLogOverride()._exception(log_name, message, *args, exc=exc, owner=owner or self.default_owner, **kwargs) + return original(self, message, *args, exc=exc, owner=owner, **kwargs) + + +@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.clear_log_times', 'Clear the stop watches for the vanilla logs', show_with_help_command=False) +def _common_clear_log_times(output: CommonConsoleCommandOutput): + output('Clearing Vanilla Logs log times.') + _CommonVanillaLogOverride()._clear_log_times() diff --git a/Scripts/s4ap/sims4communitylib/mod_support/__init__.py b/Scripts/s4ap/sims4communitylib/mod_support/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/mod_support/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/mod_support/common_mod_info.py b/Scripts/s4ap/sims4communitylib/mod_support/common_mod_info.py new file mode 100644 index 0000000..b6aab9c --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/mod_support/common_mod_info.py @@ -0,0 +1,85 @@ +""" +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 +""" +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.services.common_service import CommonService + + +class CommonModInfo(CommonService): + """Provide information about your mod. + + For information on what each of the properties represents, see :class:`.CommonModIdentity` + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from sims4communitylib.mod_support.common_mod_info import CommonModInfo + + # This is how the sims4communitylib.modinfo.ModInfo implementation works. + class ModInfo(CommonModInfo): + _FILE_PATH: str = str(__file__) + + @property + def _name(self) -> str: + return 'Sims4CommunityLib' + + @property + def _author(self) -> str: + return 'ColonolNutty' + + @property + def _base_namespace(self) -> str: + return 'sims4communitylib' + + @property + def _file_path(self) -> str: + return ModInfo._FILE_PATH + + @property + def _version(self) -> str: + return '3.5.6' + + """ + @classmethod + def get_identity(cls) -> CommonModIdentity: + """The identity of a mod + + .. note:: It contains information about a mod such as Mod Name, Mod Author,\ + the script base namespace, and the file path to your mod. + + :return: The identity of a mod. + :rtype: CommonModIdentity + """ + identity_property_name = '_MOD_IDENTITY' + mod_identity = getattr(cls, identity_property_name, None) + if mod_identity is None: + mod_info: CommonModInfo = cls.get() + mod_identity = CommonModIdentity(mod_info._name, mod_info._author, mod_info._base_namespace, mod_info._file_path, mod_info._version) + setattr(cls, identity_property_name, mod_identity) + return mod_identity + + @property + def _name(self) -> str: + raise NotImplementedError(f'Missing \'{self.__class__.__name__}._name\'.') + + @property + def _author(self) -> str: + raise NotImplementedError(f'Missing \'{self.__class__.__name__}._author\'.') + + @property + def _base_namespace(self) -> str: + raise NotImplementedError(f'Missing \'{self.__class__.__name__}._base_namespace\'.') + + @property + def _file_path(self) -> str: + raise NotImplementedError(f'Missing \'{self.__class__.__name__}._file_path\'.') + + @property + def _version(self) -> str: + return '1.0' diff --git a/Scripts/s4ap/sims4communitylib/mod_support/has_class_mod_identity.py b/Scripts/s4ap/sims4communitylib/mod_support/has_class_mod_identity.py new file mode 100644 index 0000000..dffff25 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/mod_support/has_class_mod_identity.py @@ -0,0 +1,33 @@ +""" +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 +""" +from sims4communitylib.mod_support.has_mod_identity import HasModIdentity +from sims4communitylib.mod_support.mod_identity import CommonModIdentity + + +class HasClassModIdentity(HasModIdentity): + """An inheritable class that provides Mod Info for a class. + + .. note:: This class inherits from :class:`.HasModIdentity` and may be used as an alternative to it. + + """ + # noinspection PyMissingOrEmptyDocstring + @property + def mod_identity(self) -> CommonModIdentity: + return self.__class__.get_mod_identity() + + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + """The identity of a mod. + + .. note:: It contains information about a mod such as Mod Name, Mod Author,\ + the script base namespace, and the file path to your mod. + + :return: The identity of a mod. + :rtype: CommonModIdentity + """ + raise NotImplementedError(f'Missing \'{cls.get_mod_identity.__name__}\'.') diff --git a/Scripts/s4ap/sims4communitylib/mod_support/has_mod_identity.py b/Scripts/s4ap/sims4communitylib/mod_support/has_mod_identity.py new file mode 100644 index 0000000..b9454cd --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/mod_support/has_mod_identity.py @@ -0,0 +1,26 @@ +""" +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 +""" +from sims4communitylib.mod_support.mod_identity import CommonModIdentity + + +class HasModIdentity: + """An inheritable class that provides Mod Info for a class. + + """ + @property + def mod_identity(self) -> CommonModIdentity: + """The identity of a mod. + + .. note:: It contains information about a mod such as Mod Name, Mod Author,\ + the script base namespace, and the file path to your mod. + + :return: The identity of a mod. + :rtype: CommonModIdentity + :exception NotImplementedError: Thrown when the property is not implemented. + """ + raise NotImplementedError('Missing \'{}.mod_identity\'.'.format(self.__class__.__name__)) diff --git a/Scripts/s4ap/sims4communitylib/mod_support/mod_identity.py b/Scripts/s4ap/sims4communitylib/mod_support/mod_identity.py new file mode 100644 index 0000000..2f43ecd --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/mod_support/mod_identity.py @@ -0,0 +1,108 @@ +""" +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 +""" +from typing import Union + + +class CommonModIdentity: + """CommonModIdentity(name, author, base_namespace, file_path) + + The identity of a mod + + .. note:: It contains information about a mod such as Mod Name, Mod Author,\ + the script base namespace, and the file path to your mod. + + :param name: The name of a mod. + :type name: str + :param author: The author of a mod. + :type author: str + :param base_namespace: The base namespace of the `.ts4script` file of a mod. + :type base_namespace: str + :param file_path: The path to the ts4script file of a mod. + :type file_path: str + """ + def __init__(self, name: str, author: str, base_namespace: str, file_path: str, version: str): + self._name = name.replace(' ', '_') + self._author = author + self._base_namespace = base_namespace + self._script_file_path = file_path + self._version = version + + @property + def name(self) -> str: + """The name of a mod. + + .. note:: The name should not contain spaces. + + :return: The name of a mod. + :rtype: str + """ + return str(self._name) + + @property + def author(self) -> str: + """The author of a mod. + + :return: The name of the author of a mod. + :rtype: str + """ + return str(self._author) + + @property + def base_namespace(self) -> str: + """The base namespace of the `.ts4script` file of a mod. + + .. note:: S4CL has the base namespace of `sims4communitylib`. + + :return: The base script namespace of a mod. + :rtype: str + """ + return str(self._base_namespace) + + @property + def file_path(self) -> str: + """The path to the ts4script file of a mod. + + .. note:: + + A good override value can be `__file__`, it will retrieve the file path automatically,\ + assuming the inheriting class is at the root of the mod. + + :return: The file path to a mod. + :rtype: str + """ + return str(self._script_file_path) + + @property + def version(self) -> str: + """The version a mod is currently at. + + :return: The version of a mod. The Default value is '1.0'. + :rtype: str + """ + return str(self._version) + + @staticmethod + def _get_mod_name(mod_identifier: Union[str, 'CommonModIdentity']) -> Union[str, None]: + from sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils + return CommonModIdentityUtils.determine_mod_name_from_identifier(mod_identifier) + + def __eq__(self, other: 'CommonModIdentity') -> bool: + if isinstance(other, str): + return self.name == other + if not isinstance(other, CommonModIdentity): + return False + return self.name == other.name + + def __hash__(self) -> int: + return hash(self.name) + + def __repr__(self) -> str: + return 'mod_{}_version_{}_author_{}_namespace_{}'.format(self.name, self.version.replace('.', '_').replace('/', '_').replace('\\', '_'), self.author, self.base_namespace) + + def __str__(self) -> str: + return 'Identity:\n Mod Name: {}\n Version: {}\n Mod Author: {}\n Base Namespace: {}\n Path To Mod: {}'.format(self.name, self.version, self.author, self.base_namespace, self.file_path) diff --git a/Scripts/s4ap/sims4communitylib/modinfo.py b/Scripts/s4ap/sims4communitylib/modinfo.py new file mode 100644 index 0000000..59ae16d --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/modinfo.py @@ -0,0 +1,35 @@ +""" +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 +""" +from sims4communitylib.mod_support.common_mod_info import CommonModInfo + + +class ModInfo(CommonModInfo): + """Contains details related to the mod itself. + + """ + _FILE_PATH: str = str(__file__) + + @property + def _name(self) -> str: + return 'Sims4CommunityLib' + + @property + def _author(self) -> str: + return 'ColonolNutty' + + @property + def _base_namespace(self) -> str: + return 'sims4communitylib' + + @property + def _file_path(self) -> str: + return ModInfo._FILE_PATH + + @property + def _version(self) -> str: + return '3.10' diff --git a/Scripts/s4ap/sims4communitylib/notifications/__init__.py b/Scripts/s4ap/sims4communitylib/notifications/__init__.py new file mode 100644 index 0000000..3251898 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/notifications/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" \ No newline at end of file diff --git a/Scripts/s4ap/sims4communitylib/notifications/common_basic_notification.py b/Scripts/s4ap/sims4communitylib/notifications/common_basic_notification.py new file mode 100644 index 0000000..c4e3278 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/notifications/common_basic_notification.py @@ -0,0 +1,177 @@ +""" +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 +""" +from typing import Any, Union, Tuple, Iterator +from distributor.shared_messages import IconInfoData +from protocolbuffers.Localization_pb2 import LocalizedString +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from ui.ui_dialog import UiDialogResponse +from ui.ui_dialog_notification import UiDialogNotification + + +class CommonBasicNotification: + """CommonBasicNotification(\ + title_identifier,\ + description_identifier,\ + title_tokens=(),\ + description_tokens=(),\ + urgency=UiDialogNotification.UiDialogNotificationUrgency.DEFAULT,\ + information_level=UiDialogNotification.UiDialogNotificationLevel.SIM,\ + expand_behavior=UiDialogNotification.UiDialogNotificationExpandBehavior.USER_SETTING,\ + visual_type=UiDialogNotification.UiDialogNotificationVisualType.INFORMATION,\ + ui_responses=()\ + ) + + A basic notification. + + .. note:: Notifications are the messages that appear at the top right in-game. + + .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_basic_notification` in the in-game console. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + # Will display a test dialog. + def _common_testing_show_basic_notification(): + # LocalizedStrings within other LocalizedStrings + title_tokens = ( + CommonLocalizationUtils.create_localized_string( + CommonStringId.TESTING_SOME_TEXT_FOR_TESTING, + text_color=CommonLocalizedStringColor.BLUE + ), + ) + 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 + ), + ) + dialog = CommonBasicNotification( + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + title_tokens=title_tokens, + description_tokens=description_tokens, + urgency=UiDialogNotification.UiDialogNotificationUrgency.URGENT + ) + dialog.show() + + :param title_identifier: The title to display in the dialog. + :type title_identifier: Union[int, str, LocalizedString, CommonStringId] + :param description_identifier: The description to display in the dialog. + :type description_identifier: Union[int, str, LocalizedString, CommonStringId] + :param title_tokens: Tokens to format into the title. + :type title_tokens: Iterator[Any], optional + :param description_tokens: Tokens to format into the description. + :type description_tokens: Iterator[Any], optional + :param urgency: The urgency to which the notification will appear. (URGENT makes it orange) Default is Default (Blue). + :type urgency: UiDialogNotification.UiDialogNotificationUrgency, optional + :param information_level: The information level of the notification. Default is Sim. + :type information_level: UiDialogNotification.UiDialogNotificationLevel, optional + :param expand_behavior: Specify how the notification will expand. Default is User Setting. + :type expand_behavior: UiDialogNotification.UiDialogNotificationExpandBehavior, optional + :param visual_type: How the notification should appear. Default is Information + :type visual_type: UiDialogNotification.UiDialogNotificationVisualType, optional + :param ui_responses: A collection of UI Responses that may be performed within the notification. + :type ui_responses: Tuple[UiDialogResponse], optional + """ + def __init__( + self, + title_identifier: Union[int, str, LocalizedString, CommonStringId], + description_identifier: Union[int, str, LocalizedString, CommonStringId], + title_tokens: Iterator[Any] = (), + description_tokens: Iterator[Any] = (), + urgency: UiDialogNotification.UiDialogNotificationUrgency = UiDialogNotification.UiDialogNotificationUrgency.DEFAULT, + information_level: UiDialogNotification.UiDialogNotificationLevel = UiDialogNotification.UiDialogNotificationLevel.SIM, + expand_behavior: UiDialogNotification.UiDialogNotificationExpandBehavior = UiDialogNotification.UiDialogNotificationExpandBehavior.USER_SETTING, + visual_type: UiDialogNotification.UiDialogNotificationVisualType = UiDialogNotification.UiDialogNotificationVisualType.INFORMATION, + ui_responses: Tuple[UiDialogResponse] = () + ): + self.title = CommonLocalizationUtils.create_localized_string(title_identifier, tokens=tuple(title_tokens)) + self.description = CommonLocalizationUtils.create_localized_string(description_identifier, tokens=tuple(description_tokens)) + self.visual_type = visual_type + self.urgency = urgency + self.information_level = information_level + self.expand_behavior = expand_behavior + self.ui_responses = ui_responses + + def show(self, icon: IconInfoData = None, secondary_icon: IconInfoData = None): + """show(icon=None, secondary_icon=None) + + Show the notification to the player. + + :param icon: The first icon that will display in the notification. + :type icon: IconInfoData, optional + :param secondary_icon: The second icon that will display in the notification. + :type secondary_icon: IconInfoData, optional + """ + _notification = self._create_dialog() + if _notification is None: + return + + _notification.show_dialog( + icon_override=icon, + secondary_icon_override=secondary_icon + ) + + def _create_dialog(self) -> Union[UiDialogNotification, None]: + """_create_dialog() + + Create a dialog for use in :func:``show`. + + .. note:: Override this method with any arguments you want to. + """ + 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 + ) + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_testing.show_basic_notification', + 'Show an example of CommonBasicNotification.' +) +def _common_testing_show_basic_notification(output: CommonConsoleCommandOutput): + output('Showing test basic notification.') + + # LocalizedStrings within other LocalizedStrings + title_tokens = ( + CommonLocalizationUtils.create_localized_string( + CommonStringId.TESTING_SOME_TEXT_FOR_TESTING, + text_color=CommonLocalizedStringColor.BLUE + ), + ) + 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 + ), + ) + dialog = CommonBasicNotification( + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, + title_tokens=title_tokens, + description_tokens=description_tokens, + urgency=UiDialogNotification.UiDialogNotificationUrgency.URGENT + ) + dialog.show() diff --git a/Scripts/s4ap/sims4communitylib/persistence/__init__.py b/Scripts/s4ap/sims4communitylib/persistence/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/persistence/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/persistence/common_game_object_data_storage.py b/Scripts/s4ap/sims4communitylib/persistence/common_game_object_data_storage.py new file mode 100644 index 0000000..6e2276b --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/persistence/common_game_object_data_storage.py @@ -0,0 +1,230 @@ +""" +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 +""" +import sys +from pprint import pformat +from typing import Dict, Any, Callable +from typing import Union +from objects.game_object import GameObject +from sims4communitylib.classes.serialization.common_serializable import CommonSerializable +from sims4communitylib.logging.has_class_log import HasClassLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.utils.common_type_utils import CommonTypeUtils +from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils + + +class _CommonGameObjectDataStorageMetaclass(type): + _game_object_storage_instances: Dict[str, Dict[int, '_CommonGameObjectDataStorageMetaclass']] = dict() + + def __call__(cls, game_object: GameObject): + mod_identity = cls.get_mod_identity() + game_object_id = CommonObjectUtils.get_object_id(game_object) + mod_name = mod_identity.name + if mod_name is None: + return None + identifier = f'{mod_name}_{cls.__name__}' + if identifier not in cls._game_object_storage_instances: + cls._game_object_storage_instances[identifier] = dict() + if game_object_id not in cls._game_object_storage_instances[identifier]: + cls._game_object_storage_instances[identifier][game_object_id] = super(_CommonGameObjectDataStorageMetaclass, cls).__call__(game_object) + stored_obj = cls._game_object_storage_instances[identifier][game_object_id] + if stored_obj.__class__.__name__ != cls.__name__: + cls._game_object_storage_instances[identifier][game_object_id] = super(_CommonGameObjectDataStorageMetaclass, cls).__call__(game_object) + return cls._game_object_storage_instances[identifier][game_object_id] + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(mcs) -> CommonModIdentity: + raise NotImplementedError() + + @classmethod + def clear_instances(mcs, mod_identity: CommonModIdentity) -> None: + """Clear the cached instances of this type of Object Storage.""" + mod_name = mod_identity.name + if mod_name is None: + return + identifier = f'{mod_name}_{mcs.__name__}' + if identifier in _CommonGameObjectDataStorageMetaclass._game_object_storage_instances: + del _CommonGameObjectDataStorageMetaclass._game_object_storage_instances[identifier] + + +class _CommonGameObjectDataStorage(HasClassLog, metaclass=_CommonGameObjectDataStorageMetaclass): + def __init__(self, game_object: GameObject): + super().__init__() + if not CommonTypeUtils.is_game_object(game_object): + raise AssertionError('game_object was not of type GameObject! {}'.format(game_object)) + self._game_object_id = CommonObjectUtils.get_object_id(game_object) + self._game_object = game_object + self._data: Dict[str, Any] = dict() + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + raise NotImplementedError('Missing \'{}\' inside {}.'.format(cls.get_mod_identity.__name__, cls.__class__)) + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return '{}_game_object_data_storage'.format(cls.get_mod_identity().base_namespace) + + @property + def game_object(self) -> GameObject: + """The GameObject the storage applies to. + + :return: An instance of an Object. + :rtype: GameObject + """ + return self._game_object + + @property + def game_object_id(self) -> int: + """The decimal identifier of the GameObject. + + :return: The decimal identifier of the GameObject. + :rtype: int + """ + return self._game_object_id + + def get_data(self, default: Any=None, key: str=None, encode: Callable[[Any], Any]=None, decode: Callable[[Any], Any]=None) -> Union[Any, None]: + """get_data(default=None, key=None, encode=None, decode=None) + + Retrieve stored data. + + :param default: The default data to return. The default value is None. + :type default: Dict[Any, Any], optional + :param key: The key for the data. If None, the name of the calling function will be used. + :type key: str, optional + :param encode: If specified, the data will be encoded using this function and the result will be the new data stored. Default is None. + :type encode: Callable[[Any], Any], optional + :param decode: If specified, the data will be decoded using this function and the result will be the new result of "get_data". Default is None. + :type decode: Callable[[Any], Any], optional + :return: The stored data. + :rtype: Union[Any, None] + """ + # noinspection PyUnresolvedReferences + key = key or str(sys._getframe(1).f_code.co_name) + if key not in self._data: + self.log.format_with_message('Key not found in data.', key=key, data=self._data) + if default is not None: + if encode is not None: + self._data[key] = encode(default) + else: + self._data[key] = default + return default + data = self._data.get(key) + if decode is not None and not isinstance(data, CommonSerializable): + decoded = decode(data) + if isinstance(data, CommonSerializable): + self._data[key] = decoded + return decoded + return data + + def set_data(self, value: Any, key: str=None, encode: Callable[[Any], Any]=None): + """set_data(value, key=None, encode=None) + + Set stored data. + + :param value: The value of the data. + :type value: Any + :param key: The key for the data. If None, the name of the calling function will be used. + :type key: str, optional + :param encode: If specified, the data will be encoded using this function and the result will be the new data stored. Default is None. + :type encode: Callable[[Any], Any], optional + """ + # noinspection PyUnresolvedReferences + key = key or str(sys._getframe(1).f_code.co_name) + if encode is not None: + value = encode(value) + self._data[key] = value + + def remove_data(self, key: str=None): + """remove_data(key=None) + + Remove stored data. + + :param key: The key for the data. If None, the name of the calling function will be used. + :type key: str, optional + """ + # noinspection PyUnresolvedReferences + key = key or str(sys._getframe(1).f_code.co_name) + if key not in self._data: + self.log.format_with_message('Key not found in data.', key=key, data=self._data) + return + del self._data[key] + + def __repr__(self) -> str: + return ''.join(['{}: {}\n'.format(pformat(key), pformat(value)) for (key, value) in self._data.items()]) + + def __str__(self) -> str: + return self.__repr__() + + +class CommonGameObjectDataStorage(_CommonGameObjectDataStorage): + """CommonGameObjectDataStorage(game_object) + + A wrapper for Object instances that allows storing of data. + + .. warning:: Data stored within is not persisted when closing and reopening the game! + .. warning:: DO NOT CREATE THIS CLASS DIRECTLY, IT IS ONLY MEANT TO INHERIT FROM! + + :Example usage: + + .. highlight:: python + .. code-block:: python + + # Inherit from CommonGameObjectDataStorage + class _ExampleGameObjectDataStorage(CommonGameObjectDataStorage): + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + # !!!Override with the CommonModIdentity of your own mod!!! + from sims4communitylib.modinfo import ModInfo + return ModInfo.get_identity() + + @property + def example_property_one(self) -> bool: + # Could also be written self.get_data(default=False, key='example_property_one') and it would do the same thing. + return self.get_data(default=False) + + @example_property_one.setter + def example_property_one(self, value: bool): + # Could also be written self.set_data(value, key='example_property_one') and it would do the same thing. + self.set_data(value) + + :param game_object: An instance of an Object. + :type game_object: GameObject + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + raise NotImplementedError('Missing \'{}\' inside {}.'.format(cls.get_mod_identity.__name__, cls.__class__)) + + def __init__(self, game_object: GameObject): + super().__init__(game_object) + if self.__class__.__name__ is CommonGameObjectDataStorage.__name__: + raise RuntimeError('{} cannot be created directly. You must inherit from it to create an instance of it.'.format(self.__class__.__name__)) + + +# noinspection PyMissingOrEmptyDocstring +class _ExampleGameObjectDataStorage(CommonGameObjectDataStorage): + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + # !!!Override with the CommonModIdentity of your own mod!!! + from sims4communitylib.modinfo import ModInfo + return ModInfo.get_identity() + + @property + def example_property_one(self) -> bool: + # Could also be written self.get_data(default=False, key='example_property_one') and it would do the same thing. + return self.get_data(default=False) + + @example_property_one.setter + def example_property_one(self, value: bool): + # Could also be written self.set_data(value, key='example_property_one') and it would do the same thing. + self.set_data(value) diff --git a/Scripts/s4ap/sims4communitylib/persistence/common_persisted_game_object_data_storage.py b/Scripts/s4ap/sims4communitylib/persistence/common_persisted_game_object_data_storage.py new file mode 100644 index 0000000..6f84199 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/persistence/common_persisted_game_object_data_storage.py @@ -0,0 +1,156 @@ +""" +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 +""" +from typing import Dict, Any, Tuple, Type + +from objects.game_object import GameObject +from sims4communitylib.classes.serialization.common_serializable import CommonSerializable +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.persistence.data_management.common_data_manager import CommonDataManager +from sims4communitylib.persistence.data_stores.common_data_store import CommonDataStore +from sims4communitylib.persistence.common_game_object_data_storage import CommonGameObjectDataStorage +from sims4communitylib.persistence.data_stores.common_game_object_data_store import CommonGameObjectDataStore + + +class CommonPersistedGameObjectDataStorage(CommonGameObjectDataStorage): + """CommonPersistedGameObjectDataStorage(game_object) + + A wrapper for Game Object instances that allows storing of data and persisting it between saves. + + .. warning:: Data stored within will be persisted for a Save even when closing and reopening the game! + .. warning:: DO NOT CREATE THIS CLASS DIRECTLY, IT IS ONLY MEANT TO INHERIT FROM! + + :Example usage: + + .. highlight:: python + .. code-block:: python + + # Inherit from CommonPersistedGameObjectDataStorage + class ExamplePersistedGameObjectDataStorage(CommonPersistedGameObjectDataStorage): + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + # !!!Override with the CommonModIdentity of your own mod!!! + from sims4communitylib.modinfo import ModInfo + return ModInfo.get_identity() + + @property + def example_property_one(self) -> bool: + # Could also be written self.get_data(default=False, key='example_property_one') and it would do the same thing. + return self.get_data(default=False) + + @example_property_one.setter + def example_property_one(self, value: bool): + # Could also be written self.set_data(value, key='example_property_one') and it would do the same thing. + self.set_data(value) + + :param game_object: An instance of a GameObject + :type game_object: GameObject + """ + def __init__(self, game_object: GameObject): + super().__init__(game_object) + if self.__class__.__name__ is CommonPersistedGameObjectDataStorage.__name__: + raise RuntimeError('{} cannot be created directly. You must inherit from it to create an instance of it.'.format(self.__class__.__name__)) + from sims4communitylib.persistence.data_management.common_data_manager_registry import CommonDataManagerRegistry + self._data_manager_registry = CommonDataManagerRegistry() + self.__data_manager: CommonDataManager = None + self._data = self._load_persisted_data() + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + raise NotImplementedError('Missing \'{}\' inside {}.'.format(cls.get_mod_identity.__name__, cls.__class__)) + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 'common_persisted_game_object_data_storage' + + @property + def data_store_type(self) -> Type[CommonDataStore]: + """data_store_type() + + The type of data store used for saving and loading data. + + :return: The type of the data store to use when saving and loading data. + :rtype: Type[CommonDataStore] + """ + return CommonGameObjectDataStore + + @property + def whitelist_property_names(self) -> Tuple[str]: + """ + If a property is within this list, it will be persisted when saving. By default all properties are whitelisted. + + :return: A collection of property names. + :rtype: Tuple[str] + """ + return tuple(self._data.keys()) + + @property + def blacklist_property_names(self) -> Tuple[str]: + """ + If a property is within this list, it will not be persisted when saving. By default no properties are blacklisted. + + :return: A collection of property names. + :rtype: Tuple[str] + """ + return tuple() + + @property + def _persist_empty_values(self) -> bool: + return False + + @property + def _data_manager(self) -> CommonDataManager: + if self.__data_manager is None: + self.__data_manager = self._data_manager_registry.locate_data_manager(self.mod_identity) + if self.__data_manager is None: + raise RuntimeError('Failed to locate a data manager for {}, maybe you forgot to register one?'.format(self.mod_identity.name)) + return self.__data_manager + + def customize_data_pre_save(self, data: Dict[str, Any]) -> Dict[str, Any]: + """customize_data_pre_save(data) + + A hook that allows customization of data before it is persisted/saved. + + :param data: The data intending to be saved, it is available for customization. + :type data: Dict[str, Any] + :return: The customized data. + :rtype: Dict[str, Any] + """ + data_to_save = dict(data) + for (key, value) in data_to_save.items(): + if not hasattr(self, key): + del data[key] + return data + + def _save_persisted_data(self) -> None: + data_to_save = dict() + for data_property_name in self._data.keys(): + if data_property_name not in self.whitelist_property_names or data_property_name in self.blacklist_property_names: + continue + data = self._data[data_property_name] + if self._persist_empty_values: + data_to_save[data_property_name] = data.serialize() if isinstance(data, CommonSerializable) else data + else: + if data is None or (data != 0 and not isinstance(data, bool) and not data): + continue + serialized_data = data.serialize() if isinstance(data, CommonSerializable) else data + if data is None or (serialized_data != 0 and not isinstance(data, bool) and not serialized_data): + continue + data_to_save[data_property_name] = serialized_data + data_to_save = self.customize_data_pre_save(data_to_save) + if data_to_save is None: + return + if not self._persist_empty_values: + if not data_to_save: + self._data_manager.get_data_store_by_type(self.data_store_type).remove_data_by_key(str(self.game_object_id)) + return + self._data_manager.get_data_store_by_type(self.data_store_type).set_value_by_key(str(self.game_object_id), data_to_save) + + def _load_persisted_data(self) -> Dict[str, Any]: + return self._data_manager.get_data_store_by_type(self.data_store_type).get_value_by_key(str(self.game_object_id)) diff --git a/Scripts/s4ap/sims4communitylib/persistence/common_persisted_sim_data_storage.py b/Scripts/s4ap/sims4communitylib/persistence/common_persisted_sim_data_storage.py new file mode 100644 index 0000000..f9a21e0 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/persistence/common_persisted_sim_data_storage.py @@ -0,0 +1,157 @@ +""" +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 +""" +from typing import Dict, Any, Tuple, Type + +from sims.sim_info import SimInfo +from sims4communitylib.classes.serialization.common_serializable import CommonSerializable +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.persistence.data_management.common_data_manager import CommonDataManager +from sims4communitylib.persistence.data_stores.common_data_store import CommonDataStore +from sims4communitylib.persistence.common_sim_data_storage import CommonSimDataStorage +from sims4communitylib.persistence.data_stores.common_sim_data_store import CommonSimDataStore + + +class CommonPersistedSimDataStorage(CommonSimDataStorage): + """CommonPersistedSimDataStorage(sim_info) + + A wrapper for Sim instances that allows storing of data and persisting it between saves. + + .. warning:: Data stored within will be persisted for a Save even when closing and reopening the game! + .. warning:: DO NOT CREATE THIS CLASS DIRECTLY, IT IS ONLY MEANT TO INHERIT FROM! + + :Example usage: + + .. highlight:: python + .. code-block:: python + + # Inherit from CommonPersistedSimDataStorage + class ExamplePersistedSimDataStorage(CommonPersistedSimDataStorage): + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + # !!!Override with the CommonModIdentity of your own mod!!! + from sims4communitylib.modinfo import ModInfo + return ModInfo.get_identity() + + @property + def example_property_one(self) -> bool: + # Could also be written self.get_data(default=False, key='example_property_one') and it would do the same thing. + return self.get_data(default=False) + + @example_property_one.setter + def example_property_one(self, value: bool): + # Could also be written self.set_data(value, key='example_property_one') and it would do the same thing. + self.set_data(value) + + :param sim_info: The SimInfo of a Sim. + :type sim_info: SimInfo + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + raise NotImplementedError('Missing \'{}\' inside {}.'.format(cls.get_mod_identity.__name__, cls.__class__)) + + def __init__(self, sim_info: SimInfo): + super().__init__(sim_info) + if self.__class__.__name__ is CommonPersistedSimDataStorage.__name__: + raise RuntimeError('{} cannot be created directly. You must inherit from it to create an instance of it.'.format(self.__class__.__name__)) + from sims4communitylib.persistence.data_management.common_data_manager_registry import CommonDataManagerRegistry + self._data_manager_registry = CommonDataManagerRegistry() + self.__data_manager: CommonDataManager = None + self._data = self._load_persisted_data() + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 'common_persisted_sim_data_storage' + + @property + def data_store_type(self) -> Type[CommonDataStore]: + """data_store_type() + + The type of data store used for saving and loading data. + + :return: The type of the data store to use when saving and loading data. + :rtype: Type[CommonDataStore] + """ + return CommonSimDataStore + + @property + def whitelist_property_names(self) -> Tuple[str]: + """ + If a property is within this list, it will be persisted when saving. By default all properties are whitelisted. + + :return: A collection of property names. + :rtype: Tuple[str] + """ + return tuple(self._data.keys()) + + @property + def blacklist_property_names(self) -> Tuple[str]: + """ + If a property is within this list, it will not be persisted when saving. By default no properties are blacklisted. + + :return: A collection of property names. + :rtype: Tuple[str] + """ + return tuple() + + @property + def _data_manager(self) -> CommonDataManager: + if self.__data_manager is None: + self.__data_manager = self._data_manager_registry.locate_data_manager(self.mod_identity) + if self.__data_manager is None: + raise RuntimeError('Failed to locate a data manager for {}, maybe you forgot to register one?'.format(self.mod_identity.name)) + return self.__data_manager + + @property + def _persist_empty_values(self) -> bool: + return False + + def customize_data_pre_save(self, data: Dict[str, Any]) -> Dict[str, Any]: + """customize_data_pre_save(data) + + A hook that allows customization of data before it is persisted/saved. + + :param data: The data intending to be saved, it is available for customization. + :type data: Dict[str, Any] + :return: The customized data. + :rtype: Dict[str, Any] + """ + data_to_save = dict(data) + for (key, value) in data_to_save.items(): + if not hasattr(self, key): + del data[key] + return data + + def _save_persisted_data(self) -> None: + data_to_save = dict() + for data_property_name in self._data.keys(): + if data_property_name not in self.whitelist_property_names or data_property_name in self.blacklist_property_names: + continue + data = self._data[data_property_name] + if self._persist_empty_values: + data_to_save[data_property_name] = data.serialize() if isinstance(data, CommonSerializable) else data + else: + if data is None or (data != 0 and not isinstance(data, bool) and not data): + continue + serialized_data = data.serialize() if isinstance(data, CommonSerializable) else data + if data is None or (serialized_data != 0 and not isinstance(data, bool) and not serialized_data): + continue + data_to_save[data_property_name] = serialized_data + data_to_save = self.customize_data_pre_save(data_to_save) + if data_to_save is None: + return + if not self._persist_empty_values: + if not data_to_save: + self._data_manager.get_data_store_by_type(self.data_store_type).remove_data_by_key(str(self.sim_id)) + return + self._data_manager.get_data_store_by_type(self.data_store_type).set_value_by_key(str(self.sim_id), data_to_save) + + def _load_persisted_data(self) -> Dict[str, Any]: + return self._data_manager.get_data_store_by_type(self.data_store_type).get_value_by_key(str(self.sim_id)) diff --git a/Scripts/s4ap/sims4communitylib/persistence/common_sim_data_storage.py b/Scripts/s4ap/sims4communitylib/persistence/common_sim_data_storage.py new file mode 100644 index 0000000..e8e1273 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/persistence/common_sim_data_storage.py @@ -0,0 +1,234 @@ +""" +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 +""" +import sys +from pprint import pformat +from typing import Dict, Any, Callable +from typing import Union +from sims.sim_info import SimInfo +from sims4communitylib.classes.serialization.common_serializable import CommonSerializable +from sims4communitylib.logging.has_class_log import HasClassLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.utils.common_type_utils import CommonTypeUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + + +class _CommonSimDataStorageMetaclass(type): + _sim_storage_instances: Dict[str, Dict[int, '_CommonSimDataStorageMetaclass']] = {} + + def __call__(cls, sim_info: SimInfo): + mod_identity = cls.get_mod_identity() + sim_id = CommonSimUtils.get_sim_id(sim_info) + mod_name = mod_identity.name + if mod_name is None: + return None + identifier = f'{mod_name}_{cls.__name__}' + if identifier not in cls._sim_storage_instances: + cls._sim_storage_instances[identifier] = dict() + if sim_id not in cls._sim_storage_instances[identifier]: + cls._sim_storage_instances[identifier][sim_id] = super(_CommonSimDataStorageMetaclass, cls).__call__(sim_info) + stored_obj = cls._sim_storage_instances[identifier][sim_id] + if stored_obj.__class__.__name__ != cls.__name__: + cls._sim_storage_instances[identifier][sim_id] = super(_CommonSimDataStorageMetaclass, cls).__call__(sim_info) + return cls._sim_storage_instances[identifier][sim_id] + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(mcs) -> CommonModIdentity: + raise NotImplementedError() + + @classmethod + def clear_instances(mcs, mod_identity: CommonModIdentity) -> None: + """Clear the cached instances of this type of Sim Storage.""" + mod_name = mod_identity.name + if mod_name is None: + return + identifier = f'{mod_name}_{mcs.__name__}' + if identifier in _CommonSimDataStorageMetaclass._sim_storage_instances: + del _CommonSimDataStorageMetaclass._sim_storage_instances[identifier] + + +class _CommonSimDataStorage(HasClassLog, metaclass=_CommonSimDataStorageMetaclass): + def __init__(self, sim_info: SimInfo): + super().__init__() + if not CommonTypeUtils.is_sim_info(sim_info) and not CommonTypeUtils.is_sim_info_base_wrapper(sim_info): + raise AssertionError('sim_info was not of type SimInfo! {}'.format(sim_info if sim_info is None else type(sim_info))) + self._sim_id = CommonSimUtils.get_sim_id(sim_info) + self._sim_info = sim_info + self._data: Dict[str, Any] = dict() + if sim_info is not None: + from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils + sim_name = CommonSimNameUtils.get_full_name(sim_info) + if sim_name is not None: + self._data['sim_name'] = sim_name + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + raise NotImplementedError('Missing \'{}\' inside {}.'.format(cls.get_mod_identity.__name__, cls.__class__)) + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return '{}_sim_data_storage'.format(cls.get_mod_identity().base_namespace) + + @property + def sim_info(self) -> SimInfo: + """The SimInfo of a Sim. + + :return: The SimInfo of a Sim. + :rtype: SimInfo + """ + return self._sim_info + + @property + def sim_id(self) -> int: + """The decimal identifier of a Sim. + + :return: The decimal identifier of a Sim. + :rtype: int + """ + return self._sim_id + + def get_data(self, default: Any=None, key: str=None, encode: Callable[[Any], Any]=None, decode: Callable[[Any], Any]=None) -> Union[Any, None]: + """get_data(default=None, key=None, encode=None, decode=None) + + Retrieve stored data. + + :param default: The default data to return. The default value is None. + :type default: Dict[Any, Any], optional + :param key: The key for the data. If None, the name of the calling function will be used. + :type key: str, optional + :param encode: If specified, the data will be encoded using this function and the result will be the new data stored. Default is None. + :type encode: Callable[[Any], Any], optional + :param decode: If specified, the data will be decoded using this function and the result will be the new result of "get_data". Default is None. + :type decode: Callable[[Any], Any], optional + :return: The stored data. + :rtype: Union[Any, None] + """ + # noinspection PyUnresolvedReferences + key = key or str(sys._getframe(1).f_code.co_name) + if key not in self._data: + self.log.format_with_message('Key not found in data. Setting to default value.', sim=self.sim_info, key=key, data=self._data, default=default) + if default is not None: + if encode is not None: + self._data[key] = encode(default) + else: + self._data[key] = default + return default + data = self._data.get(key) + if decode is not None and not isinstance(data, CommonSerializable): + decoded = decode(data) + if isinstance(data, CommonSerializable): + self._data[key] = decoded + return decoded + return data + + def set_data(self, value: Any, key: str=None, encode: Callable[[Any], Any]=None): + """set_data(value, key=None, encode=None) + + Set stored data. + + :param value: The value of the data. + :type value: Any + :param key: The key for the data. If None, the name of the calling function will be used. + :type key: str, optional + :param encode: If specified, the data will be encoded using this function and the result will be the new data stored. Default is None. + :type encode: Callable[[Any], Any], optional + """ + # noinspection PyUnresolvedReferences + key = key or str(sys._getframe(1).f_code.co_name) + if encode is not None: + value = encode(value) + self._data[key] = value + + def remove_data(self, key: str=None): + """remove_data(key=None) + + Remove stored data. + + :param key: The key for the data. If None, the name of the calling function will be used. + :type key: str, optional + """ + # noinspection PyUnresolvedReferences + key = key or str(sys._getframe(1).f_code.co_name) + if key not in self._data: + self.log.format_with_message('Key not found in data. Not removing it.', sim=self.sim_info, key=key, data=self._data) + return + del self._data[key] + + def __repr__(self) -> str: + return ''.join(['{}: {}\n'.format(pformat(key), pformat(value)) for (key, value) in self._data.items()]) + + def __str__(self) -> str: + return self.__repr__() + + +class CommonSimDataStorage(_CommonSimDataStorage): + """CommonSimDataStorage(sim_info) + + A wrapper for Sim instances that allows storing of data. + + .. warning:: Data stored within is not persisted when closing and reopening the game! + .. warning:: DO NOT CREATE THIS CLASS DIRECTLY, IT IS ONLY MEANT TO INHERIT FROM! + + :Example usage: + + .. highlight:: python + .. code-block:: python + + # Inherit from CommonSimDataStorage + class _ExampleSimDataStorage(CommonSimDataStorage): + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + # !!!Override with the CommonModIdentity of your own mod!!! + from sims4communitylib.modinfo import ModInfo + return ModInfo.get_identity() + + @property + def example_property_one(self) -> bool: + # Could also be written self.get_data(default=False, key='example_property_one') and it would do the same thing. + return self.get_data(default=False) + + @example_property_one.setter + def example_property_one(self, value: bool): + # Could also be written self.set_data(value, key='example_property_one') and it would do the same thing. + self.set_data(value) + + :param sim_info: The SimInfo of a Sim. + :type sim_info: SimInfo + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + raise NotImplementedError('Missing \'{}\' inside {}.'.format(cls.get_mod_identity.__name__, cls.__class__)) + + def __init__(self, sim_info: SimInfo): + super().__init__(sim_info) + if self.__class__.__name__ is CommonSimDataStorage.__name__: + raise RuntimeError('{} cannot be created directly. You must inherit from it to create an instance of it.'.format(self.__class__.__name__)) + + +# noinspection PyMissingOrEmptyDocstring +class _ExampleSimDataStorage(CommonSimDataStorage): + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + # !!!Override with the CommonModIdentity of your own mod!!! + from sims4communitylib.modinfo import ModInfo + return ModInfo.get_identity() + + @property + def example_property_one(self) -> bool: + # Could also be written self.get_data(default=False, key='example_property_one') and it would do the same thing. + return self.get_data(default=False) + + @example_property_one.setter + def example_property_one(self, value: bool): + # Could also be written self.set_data(value, key='example_property_one') and it would do the same thing. + self.set_data(value) diff --git a/Scripts/s4ap/sims4communitylib/persistence/data_management/__init__.py b/Scripts/s4ap/sims4communitylib/persistence/data_management/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/persistence/data_management/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/persistence/data_management/common_data_manager.py b/Scripts/s4ap/sims4communitylib/persistence/data_management/common_data_manager.py new file mode 100644 index 0000000..e239187 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/persistence/data_management/common_data_manager.py @@ -0,0 +1,232 @@ +""" +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 +""" +from typing import Dict, Any, Type, Tuple + +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.logging.has_log import HasLog +from sims4communitylib.persistence.data_stores.common_data_store import CommonDataStore +from sims4communitylib.persistence.persistence_services.common_persistence_service import CommonPersistenceService + + +class CommonDataManager(HasLog): + """CommonDataManager() + + Manage a storage of data. + + """ + # noinspection PyMissingOrEmptyDocstring + @property + def mod_identity(self) -> CommonModIdentity: + return super().mod_identity + + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + return super().log_identifier + + def __init__(self, identifier: str=None) -> None: + super().__init__() + self._identifier = identifier + self.__data_store_data = None + self.__data_stores = dict() + self._loaded = False + self._can_be_saved = True + self._persistence_service = None + + @property + def _can_be_saved(self) -> bool: + return self.__can_be_saved + + @_can_be_saved.setter + def _can_be_saved(self, val: bool): + self.__can_be_saved = val + + @property + def persistence_services(self) -> Tuple[CommonPersistenceService]: + """A collection of services that save and load data for the manager using the Mod Identity of the manager. + + .. note:: The precedence of data being loaded/saved is in the order you return them in.\ + For example, with (CommonHiddenHouseholdPersistenceService, CommonFilePersistenceService), data loaded via the file will override data loaded via the hidden household + + :return: A collection of persistence services. + :rtype: Tuple[CommonPersistenceService] + """ + raise NotImplementedError() + + @property + def _data_store_data(self) -> Dict[str, Dict[str, Any]]: + """ + Data stores owned by a Mod in serializable form organized by identifiers. + + .. note:: The Key is the identifier of a setting collection. The value is the library of settings related to the setting collection. + + :return: Data stores in serializable form organized by a Sub Name. + :rtype: Dict[str, Dict[str, Any]] + """ + if not self._loaded or self.__data_store_data is None: + self.load() + return self.__data_store_data + + @property + def _data_stores(self) -> Dict[str, CommonDataStore]: + """ + + Data stores owned by a Mod organized by identifiers + + .. note:: The Key is the identifier of a setting collection. The value is the library of settings related to the setting collection. + + :return: Data stores owned by a Mod organized by identifiers + :rtype: Dict[str, CommonDataStore] + """ + return self.__data_stores + + def get_data_store_by_type(self, data_store_type: Type[CommonDataStore]) -> CommonDataStore: + """get_data_store_by_type(data_store_type) + + Retrieve a data store by its type. + + .. note:: This will also add the data store using the type if it does not exist already. + + :param data_store_type: The type of data store. + :type data_store_type: Type[CommonDataStore] + :return: The data store. + :rtype: CommonDataStore + """ + name = data_store_type.get_identifier() + if name in self._data_stores: + return self._data_stores[name] + default_data_store: CommonDataStore = data_store_type() + if name not in self._data_store_data: + self._data_store_data[name] = dict() + + default_data_store.update_data(self._data_store_data[name]) + self.log.format_with_message('Created data store', name=default_data_store.get_identifier()) + self._data_store_data[name] = default_data_store.get_store_data_for_persistence() + self._data_stores[name] = default_data_store + return self._data_stores[name] + + def load(self) -> None: + """load() + + Load data into the data manager. + """ + if self._loaded: + return + try: + self.log.debug('Loading data.') + self.__data_store_data = self._load() + self._loaded = True + except Exception as ex: + self.log.error('Error occurred while loading data \'{}\'.'.format(self.__repr__()), exception=ex) + self.__data_store_data = dict() + self._loaded = True + + def reload(self) -> None: + """reload() + + Reloads data into the data manager. + """ + self._loaded = False + self.load() + + def save(self) -> bool: + """save() + + Save data from the data manager. + + :return: True, if save was successful. False, if not. + :rtype: bool + """ + try: + self.log.debug('Saving data.') + # Update global data with data from the data stores. + for (name, data_store) in self._data_stores.items(): + data_store: CommonDataStore = data_store + self._data_store_data[name] = data_store.get_store_data_for_persistence() + return self._save() + except Exception as ex: + self.log.error('Error occurred while saving data \'{}\'.'.format(self.__repr__()), exception=ex) + return False + + def clear(self) -> None: + """clear() + + Clear all data from the data manager. + """ + self.__data_store_data = dict() + self.__data_stores = dict() + self._loaded = False + + def remove_all_data(self, prevent_save: bool=False) -> bool: + """remove_all_data(prevent_save=False) + + Reset the data store to default values and remove persisted files. + + :param prevent_save: If True, when the game is saved, the data will not be persisted. + :type prevent_save: bool + :return: True, if all data was successfully removed. False, if not. + :rtype: bool + """ + try: + self.__data_store_data = dict() + self.__data_stores = dict() + if prevent_save: + self._can_be_saved = False + return self._remove() + except Exception as ex: + self.log.error('Error while resetting settings.', exception=ex) + return False + + def remove_data_store_by_name(self, name: str) -> bool: + """remove_data_store_by_name(name) + + Remove a data store by its name. + + :param name: The name of a data store. + :param name: str + :return: True, if successfully removed. False, if not. + :rtype: bool + """ + if name in self._data_stores: + del self._data_stores[name] + if name in self._data_store_data: + del self._data_store_data[name] + return True + + def _load(self) -> Dict[str, Dict[str, Any]]: + data = dict() + for persistence_service in self.persistence_services: + loaded_data = persistence_service.load(self.mod_identity, identifier=self._identifier) + self.log.format_with_message('Loaded data.', loaded_data=loaded_data) + data.update(loaded_data) + return data + + def _save(self) -> bool: + if not self._can_be_saved: + return False + success = True + self.log.format_with_message('Save data.', save_data=self._data_store_data) + for persistence_service in self.persistence_services: + success = persistence_service.save(self.mod_identity, self._data_store_data, identifier=self._identifier) + if not success: + success = False + return success + + def _remove(self) -> bool: + success = True + for persistence_service in self.persistence_services: + success = persistence_service.remove(self.mod_identity, identifier=self._identifier) + if not success: + success = False + return success + + def __repr__(self) -> str: + return self.__str__() + + def __str__(self) -> str: + return 'Data Manager: \'{}\'\n Data Stores:\n{}'.format(repr(self.mod_identity), self._data_stores) diff --git a/Scripts/s4ap/sims4communitylib/persistence/data_management/common_data_manager_registry.py b/Scripts/s4ap/sims4communitylib/persistence/data_management/common_data_manager_registry.py new file mode 100644 index 0000000..b085afa --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/persistence/data_management/common_data_manager_registry.py @@ -0,0 +1,189 @@ +""" +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 +""" +from typing import Union, Dict, Any, Type, Callable + +from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry +from sims4communitylib.events.save.events.save_loaded import S4CLSaveLoadedEvent +from sims4communitylib.events.save.events.save_saved import S4CLSaveSavedEvent +from sims4communitylib.logging.has_class_log import HasClassLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.persistence.data_management.common_data_manager import CommonDataManager +from sims4communitylib.services.common_service import CommonService + + +class CommonDataManagerRegistry(CommonService, HasClassLog): + """CommonDataManagerRegistry() + + A registry that maintains data managers for saving and loading of data. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + from typing import Tuple + from sims4communitylib.mod_support.mod_identity import CommonModIdentity + from sims4communitylib.persistence.data_management.common_data_manager import CommonDataManager + from sims4communitylib.persistence.data_management.common_data_manager_registry import CommonDataManagerRegistry + from sims4communitylib.persistence.persistence_services.common_persistence_service import CommonPersistenceService + + + # This attribute will register the data manager to the registry. + # @CommonDataManagerRegistry.common_data_manager() + # Passing an identifier argument will give a unique identifier to the data manager, but it isn't required unless you have multiple managers for your mod. + @CommonDataManagerRegistry.common_data_manager(identifier='I_am_unique') + class ExampleDataManager(CommonDataManager): + # noinspection PyMissingOrEmptyDocstring + @property + def mod_identity(self) -> CommonModIdentity: + # !!! Override this property using your own CommonModIdentity !!! + return ModInfo.get_identity() + + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + return 'the_example_data_manager' + + # noinspection PyMissingOrEmptyDocstring + @property + def persistence_services(self) -> Tuple[CommonPersistenceService]: + from sims4communitylib.persistence.persistence_services.common_hidden_household_persistence_service import \ + CommonHiddenHouseholdPersistenceService + from sims4communitylib.persistence.persistence_services.common_file_persistence_service import \ + CommonFilePersistenceService + # The order matters. The later services will override data loaded from the earlier services. In the follow, any data loaded from the file will override any matching data that was loaded from the hidden household. + result: Tuple[CommonPersistenceService] = ( + # Having this will result in the data being saved to a hidden household. + CommonHiddenHouseholdPersistenceService(), + # Having this will result in the data also being saved to a file at saves\\mod_name\\do_not_remove_mod_name_author_I_am_unique_id_1234_guid_5435.json (Notice that "I_am_unique" becomes a part of the file name because it was specified as the identifier) + CommonFilePersistenceService() + ) + return result + + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + return ModInfo.get_identity() + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 'common_data_manager_registry' + + def __init__(self) -> None: + super().__init__() + self._data_managers: Dict[str, CommonDataManager] = dict() + + @staticmethod + def common_data_manager(identifier: str = None) -> Callable[[Type[CommonDataManager]], Any]: + """common_data_manager(identifier=None) + + An attribute that will register the decorated data manager to the registry. + + :param identifier: If you need to distinguish two different data managers for your mod, this will be the unique identifier. Default is None. + :type identifier: str, optional + """ + def _inner_test_class(cls: Type[CommonDataManager]) -> Any: + nonlocal identifier + if identifier is None: + if hasattr(cls, 'get_identifier'): + identifier = cls.get_identifier() + CommonDataManagerRegistry()._register_data_manager(cls(identifier=identifier), identifier=identifier) + return cls + return _inner_test_class + + def _register_data_manager(self, data_manager: CommonDataManager, identifier: str = None): + self.log.format_with_message('Registering data store.', data_store=data_manager) + formatted_identifier = self._format_identifier(data_manager.mod_identity, identifier=identifier) + if formatted_identifier not in self._data_managers: + self._data_managers[formatted_identifier] = data_manager + + def save_data(self) -> None: + """save_data() + + Save the data of all data managers. + + """ + self.log.debug('Saving data managers.') + from sims4communitylib.persistence.common_game_object_data_storage import _CommonGameObjectDataStorageMetaclass + for (mod_name, data_storage_library) in _CommonGameObjectDataStorageMetaclass._game_object_storage_instances.items(): + data_storage_library: Dict[int, '_CommonGameObjectDataStorageMetaclass'] = data_storage_library + for data_storage in data_storage_library.values(): + if hasattr(data_storage, '_save_persisted_data'): + data_storage._save_persisted_data() + from sims4communitylib.persistence.common_sim_data_storage import _CommonSimDataStorageMetaclass + for (mod_name, data_storage_library) in _CommonSimDataStorageMetaclass._sim_storage_instances.items(): + data_storage_library: Dict[int, '_CommonSimDataStorageMetaclass'] = data_storage_library + for data_storage in data_storage_library.values(): + if hasattr(data_storage, '_save_persisted_data'): + data_storage._save_persisted_data() + for data_manager in self._data_managers.values(): + self.log.format_with_message('Saving data manager', data_manager=data_manager) + data_manager.save() + self.log.debug('Done saving data managers.') + + def clear_data(self) -> None: + """clear_data() + + Clear all data managers in the registry. + """ + self.log.debug('Clearing data managers.') + from sims4communitylib.persistence.common_game_object_data_storage import _CommonGameObjectDataStorageMetaclass + _CommonGameObjectDataStorageMetaclass._game_object_storage_instances = dict() + from sims4communitylib.persistence.common_sim_data_storage import _CommonSimDataStorageMetaclass + _CommonSimDataStorageMetaclass._sim_storage_instances = dict() + for data_manager in self._data_managers.values(): + try: + self.log.format_with_message('Saving data manager', data_manager=data_manager) + data_manager.clear() + except Exception as ex: + self.log.format_error_with_message('Failed to clear data manager. An error occurred.', data_manager=data_manager, exception=ex) + self.log.debug('Done clearing data managers.') + + def locate_data_manager(self, mod_identity: CommonModIdentity, identifier: str = None) -> Union[CommonDataManager, None]: + """locate_data_manager(mod_identity, identifier=None) + + Locate a data manager for a mod. + + :param mod_identity: The identity of the Mod. + :type mod_identity: CommonModIdentity + :param identifier: If you distinguished your data manager with an identifier when registering it, provide it here to locate the correct data manager, otherwise leave it as None. Default is None. + :type identifier: str, optional + :return: The data manager for the specified mod with the specified identifier (if specified) or None if not found. + :rtype: Union[CommonDataManager, None] + """ + formatted_identifier = self._format_identifier(mod_identity, identifier=identifier) + self.log.format_with_message('Attempting to locate data manager.', identifier=formatted_identifier) + if formatted_identifier not in self._data_managers: + self.log.format_with_message(f'Data manager not registered for mod \'{mod_identity.name}\', adding the default data manager.') + return None + self.log.debug('Located data manager.') + return self._data_managers[formatted_identifier] + + def _format_identifier(self, mod_identity: CommonModIdentity, identifier: str = None) -> str: + if identifier is None: + return repr(mod_identity) + else: + return f'{repr(mod_identity)}_{identifier}' + + +# noinspection PyUnusedLocal +@CommonEventRegistry.handle_events(ModInfo.get_identity()) +def _common_save_data_on_save_saved(event_data: S4CLSaveSavedEvent) -> bool: + CommonDataManagerRegistry().save_data() + return True + + +# noinspection PyUnusedLocal +@CommonEventRegistry.handle_events(ModInfo.get_identity()) +def _common_clear_data_on_save_loaded(event_data: S4CLSaveLoadedEvent) -> bool: + CommonDataManagerRegistry().clear_data() + return True diff --git a/Scripts/s4ap/sims4communitylib/persistence/data_stores/__init__.py b/Scripts/s4ap/sims4communitylib/persistence/data_stores/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/persistence/data_stores/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/persistence/data_stores/common_data_store.py b/Scripts/s4ap/sims4communitylib/persistence/data_stores/common_data_store.py new file mode 100644 index 0000000..a52e42c --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/persistence/data_stores/common_data_store.py @@ -0,0 +1,223 @@ +""" +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 +""" +from typing import Dict, Any, Callable, Tuple + +from sims4communitylib.classes.serialization.common_serializable import CommonSerializable + + +class CommonDataStore: + """CommonDataStore() + + Manage a subset of data. + """ + _VERSION = 'version' + + def __init__(self) -> None: + self._storage = dict(self._default_data) + + @classmethod + def get_identifier(cls) -> str: + """ The identifier of the data store. """ + raise NotImplementedError(f'Missing get_identifier class method in \'{cls.__name__}\'.') + + @property + def _version(self) -> int: + raise NotImplementedError(f'Missing _version property in \'{self.__class__.__name__}\'.') + + @property + def _default_data(self) -> Dict[str, Any]: + raise NotImplementedError(f'Missing _default_data property in \'{self.__class__.__name__}\'') + + @property + def _storage(self) -> Dict[str, Any]: + """ + A storage of data organized by identifiers. + + :return: A storage of data organized by identifiers. + :rtype: Dict[str, Any] + """ + return self.__storage + + @_storage.setter + def _storage(self, value: Dict[str, Any]): + self.__storage = value + + @property + def _persist_empty_values(self) -> bool: + return False + + @property + def whitelist_property_names(self) -> Tuple[str]: + """ + If a property is within this list, it will be persisted when saving. By default all properties are whitelisted. + + :return: A collection of property names. + :rtype: Tuple[str] + """ + return tuple(self._storage.keys()) + + @property + def blacklist_property_names(self) -> Tuple[str]: + """ + If a property is within this list, it will not be persisted when saving. By default no properties are blacklisted. + + :return: A collection of property names. + :rtype: Tuple[str] + """ + return tuple() + + def set_value_by_key(self, key: str, value: Any, encode: Callable[[Any], Any]=None): + """set_value_by_key(key, value, encode=None) + + Set data in storage by its key. + + :param key: An identifier. + :type key: str + :param value: A value. + :type value: Any + :param encode: If specified, the data will be encoded using this function and the result will be the new data stored. Default is None. + :type encode: Callable[[Any], Any], optional + """ + if encode is not None: + value = encode(value) + self._storage[key] = value + + def get_value_by_key(self, key: str, encode: Callable[[Any], Any]=None, decode: Callable[[Any], Any]=None) -> Any: + """get_value_by_key(key, encode=None, decode=None) + + Get data from storage by its key. + + :param key: An identifier. + :type key: str + :param encode: If specified, the data will be encoded using this function and the result will be the new data stored. Default is None. + :type encode: Callable[[Any], Any], optional + :param decode: If specified, the data will be decoded using this function and the result will be the new result of "get_data". Default is None. + :type decode: Callable[[Any], Any], optional + :return: The value assigned to the key or the default value if not found. + :rtype: Any + """ + if key not in self._storage: + default_val = self.get_default_value_by_key(key) + if default_val is not None: + if encode is not None: + self._storage[key] = encode(default_val) + else: + self._storage[key] = default_val + return default_val + data = self._storage.get(key) + if decode is not None and not isinstance(data, CommonSerializable): + decoded = decode(data) + if isinstance(data, CommonSerializable): + self._storage[key] = decoded + return decoded + return data + + def get_default_value_by_key(self, key: str) -> Any: + """get_default_value_by_key(key) + + Get the default value + + :param key: An identifier. + :type key: str + :return: The default value associated with the specified key or None if no default value has been provided for the specified key. + :rtype: Any + """ + if key not in self._default_data: + return None + return self._default_data[key] + + def remove_data_by_key(self, key: str) -> bool: + """remove_data_by_key(key) + + Remove data from storage. + + :param key: An identifier. + :type key: str + :return: True, if the data with the specified identifier is removed successfully. False, if not. + :rtype: bool + """ + if key not in self._storage: + return False + del self._storage[key] + return True + + def update_data(self, data: Dict[str, Any]): + """update_data(data) + + Replace the data contained within the data store. + + :param data: A library of data. + :type data: Dict[str, Any] + """ + + version_name = self.__class__._VERSION + + if data is None or not data: + self._storage = dict(self._default_data) + if version_name not in self._storage: + self._storage[version_name] = self._version + return + + if version_name not in data or int(data[version_name]) != int(self._version): + new_data = dict(data) + default_data = dict(self._default_data) + for (default_data_key, default_data_value) in default_data.items(): + # If Data has the key, we don't want to override it. Keep the old data. + if default_data_key in new_data: + continue + new_data[default_data_key] = default_data[default_data_key] + new_data[version_name] = self._version + data = new_data + + self._storage = data + + def customize_data_pre_save(self, data: Dict[str, Any]) -> Dict[str, Any]: + """customize_data_pre_save(data) + + A hook that allows customization of data before it is persisted/saved. + + :param data: The data intending to be saved, it is available for customization. + :type data: Dict[str, Any] + :return: The customized data. + :rtype: Dict[str, Any] + """ + return data + + def get_store_data_for_persistence(self) -> Dict[str, Any]: + """get_store_data_for_persistence() + + :return: The data of this data store, but in an easy to serialize format. + :rtype: Dict[str, Any] + """ + data_to_save = dict() + for data_property_name in self._storage.keys(): + if data_property_name not in self.whitelist_property_names or data_property_name in self.blacklist_property_names: + continue + data = self._storage[data_property_name] + if self._persist_empty_values: + data_to_save[data_property_name] = data.serialize() if isinstance(data, CommonSerializable) else data + else: + if data is None or (data != 0 and not isinstance(data, bool) and not data): + continue + serialized_data = data.serialize() if isinstance(data, CommonSerializable) else data + if data is None or (serialized_data != 0 and not isinstance(data, bool) and not serialized_data): + continue + data_to_save[data_property_name] = serialized_data + data_to_save = self.customize_data_pre_save(data_to_save) + if data_to_save is None: + return dict() + if not self._persist_empty_values: + if not data_to_save: + return dict() + return data_to_save + + def __repr__(self) -> str: + return self.__class__.get_identifier() + + def __str__(self) -> str: + return 'Data Store: \'{}\'\n Storage:\n{}'.format(str(self.__class__.get_identifier()), self._storage) diff --git a/Scripts/s4ap/sims4communitylib/persistence/data_stores/common_game_object_data_store.py b/Scripts/s4ap/sims4communitylib/persistence/data_stores/common_game_object_data_store.py new file mode 100644 index 0000000..f26891d --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/persistence/data_stores/common_game_object_data_store.py @@ -0,0 +1,30 @@ +""" +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 +""" +from typing import Dict, Any +from sims4communitylib.persistence.data_stores.common_data_store import CommonDataStore + + +class CommonGameObjectDataStore(CommonDataStore): + """ A store of Game Object Data. """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_identifier(cls) -> str: + return 'game_object_data' + + @property + def _version(self) -> int: + return 1 + + @property + def _default_data(self) -> Dict[str, Any]: + return dict() + + # noinspection PyMissingOrEmptyDocstring + def get_default_value_by_key(self, key: str) -> Any: + return dict() diff --git a/Scripts/s4ap/sims4communitylib/persistence/data_stores/common_sim_data_store.py b/Scripts/s4ap/sims4communitylib/persistence/data_stores/common_sim_data_store.py new file mode 100644 index 0000000..581799c --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/persistence/data_stores/common_sim_data_store.py @@ -0,0 +1,30 @@ +""" +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 +""" +from typing import Dict, Any +from sims4communitylib.persistence.data_stores.common_data_store import CommonDataStore + + +class CommonSimDataStore(CommonDataStore): + """ A store of Sim Data. """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_identifier(cls) -> str: + return 'sim_data' + + @property + def _version(self) -> int: + return 1 + + @property + def _default_data(self) -> Dict[str, Any]: + return dict() + + # noinspection PyMissingOrEmptyDocstring + def get_default_value_by_key(self, key: str) -> Any: + return dict() diff --git a/Scripts/s4ap/sims4communitylib/persistence/persistence_services/__init__.py b/Scripts/s4ap/sims4communitylib/persistence/persistence_services/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/persistence/persistence_services/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_file_persistence_service.py b/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_file_persistence_service.py new file mode 100644 index 0000000..6586623 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_file_persistence_service.py @@ -0,0 +1,120 @@ +""" +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 +""" +import os +from typing import Dict, Any + +from sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.persistence.persistence_services.common_persistence_service import CommonPersistenceService +from sims4communitylib.utils.common_json_io_utils import CommonJSONIOUtils +from sims4communitylib.utils.save_load.common_save_utils import CommonSaveUtils + + +class CommonFilePersistenceService(CommonPersistenceService): + """CommonFilePersistenceService(per_save=True, per_save_slot=False, folder_name=None, custom_file_name=None, data_folder_path=None) + + A service that persists data into a file and loads data from a file on the system. + + :param per_save: If True, the data will persist for each Game Save file (Set "per_save_slot" to True to persist per save SLOT as well!). If False, the data will persist for all Game Save files. Default is True. + :type per_save: bool, optional + :param per_save_slot: If True, the data will persist for each Save slot. If False, the data will persist for each Game file only. Default is False. (This argument requires "per_save" to be True as well!) + :type per_save_slot: bool, optional + :param folder_name: Use to specify a custom file path after the normal file path, example: "The Sims 4/Mods/mod_data//". Default is None. + :type folder_name: str, optional + :param custom_file_name: Use to specify a custom name for the loaded and saved file. example: "The Sims 4/Mods/mod_data//" and if "folder_name" is specified: "The Sims 4/Mods/mod_data///". Default is None. + :type custom_file_name; str, optional + :param data_folder_path: Use to specify a custom folder path at the top level for which to save/load data to/from. Default is "Mods/mod_data". + :type data_folder_path: str, optional + """ + + def __init__(self, per_save: bool=True, per_save_slot: bool=False, folder_name: str=None, custom_file_name: str=None, data_folder_path: str=None) -> None: + super().__init__() + self._per_save = per_save + self._per_save_slot = per_save_slot + self._folder_name = folder_name + self._custom_file_name = custom_file_name + from sims4communitylib.utils.common_log_utils import CommonLogUtils + self._data_folder_path = data_folder_path or CommonLogUtils.get_mod_data_location_path() + + # noinspection PyMissingOrEmptyDocstring + def load(self, mod_identity: CommonModIdentity, identifier: str=None) -> Dict[str, Any]: + file_path = self._file_path(mod_identity, identifier=identifier) + if not file_path: + return dict() + + self.log.format_with_message('Loading data.', mod=mod_identity, file_path=file_path) + + if not os.path.exists(file_path): + self.log.format_with_message('No data was found at path.', mod=mod_identity, file_path=file_path) + return dict() + + loaded_data: Dict[str, Any] = CommonJSONIOUtils.load_from_file(file_path) + if loaded_data is None: + return dict() + self.log.format_with_message('Done loading data.', mod=mod_identity, file_path=file_path, loaded_data=loaded_data) + return loaded_data + + # noinspection PyMissingOrEmptyDocstring + def save(self, mod_identity: CommonModIdentity, data: Dict[str, Any], identifier: str=None) -> bool: + if not data: + return False + file_path = self._file_path(mod_identity, identifier=identifier) + if not file_path: + return False + + self.log.format_with_message('Loading data.', mod=mod_identity, file_path=file_path) + + os.makedirs(os.path.dirname(file_path), exist_ok=True) + if os.path.exists(file_path): + self.log.debug('File existed already, removing the existing one.') + os.rename(file_path, file_path + '.Old') + + try: + result = CommonJSONIOUtils.write_to_file(file_path, data) + self.log.format_with_message('Done saving data.', file_path=file_path) + except Exception as ex: + CommonExceptionHandler.log_exception(mod_identity, 'Failed to save data', exception=ex) + if os.path.exists(file_path + '.Old'): + os.rename(file_path + '.Old', file_path) + return False + if result and os.path.exists(file_path + '.Old'): + os.remove(file_path + '.Old') + return result + + # noinspection PyMissingOrEmptyDocstring + def remove(self, mod_identity: CommonModIdentity, identifier: str=None) -> bool: + file_path = self._file_path(mod_identity, identifier=identifier) + + self.log.format_with_message('Loading data.', mod=mod_identity, file_path=file_path) + + if os.path.exists(file_path): + self.log.debug('File existed already, removing the existing one.') + os.remove(file_path) + + self.log.format_with_message('Data deleted successfully.', file_path=file_path) + return not os.path.exists(file_path) + + def _file_path(self, mod_identity: CommonModIdentity, identifier: str=None) -> str: + data_name = self._format_data_name(mod_identity, identifier=identifier) + folder_path = os.path.join(self._data_folder_path, mod_identity.base_namespace.lower()) + if self._folder_name is not None: + folder_path = os.path.join(folder_path, self._folder_name) + if self._custom_file_name is not None: + return os.path.join(folder_path, self._custom_file_name) + if self._per_save: + save_slot_guid = CommonSaveUtils.get_save_slot_guid() + from sims4communitylib.s4cl_configuration import S4CLConfiguration + if self._per_save_slot or S4CLConfiguration().persist_mod_data_per_save_slot: + save_slot_id = CommonSaveUtils.get_save_slot_id() + if save_slot_id == 0: + return '' + return os.path.join(folder_path, f'{data_name}_id_{save_slot_id}_guid_{save_slot_guid}.json') + else: + return os.path.join(folder_path, f'{data_name}_guid_{save_slot_guid}.json') + else: + return os.path.join(folder_path, f'{data_name}.json') diff --git a/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_folder_persistence_service.py b/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_folder_persistence_service.py new file mode 100644 index 0000000..8b9e212 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_folder_persistence_service.py @@ -0,0 +1,152 @@ +""" +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 +""" +import os +from typing import Dict, Any + +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.persistence.persistence_services.common_persistence_service import CommonPersistenceService +from sims4communitylib.utils.common_collection_utils import CommonCollectionUtils +from sims4communitylib.utils.common_json_io_utils import CommonJSONIOUtils +from sims4communitylib.utils.common_log_registry import CommonLogRegistry + + +class CommonFolderPersistenceService(CommonPersistenceService): + """CommonFolderPersistenceService(main_file_name='main.json', combined_file_name='combined.json', allow_duplicates_in_collections=False, data_folder_path=None) + + A service that persists data to a file within a folder on the system. It also loads all data from a folder on the system while loading the main file last. + + :param main_file_name: A file that will be loaded after the other files in the folder specified by folder_name. Default is 'main.json'. + :type main_file_name: str, optional + :param combined_file_name: The name of the file to persist data to when saving. Default is combined.json + :type combined_file_name: str, optional + :param allow_duplicates_in_collections: When loading the dictionary data and merging it, if set to True, duplicate values will be allowed to exist within collections within those dictionaries. Default is False. + :type allow_duplicates_in_collections: bool, optional + :param data_folder_path: Use to specify a custom folder path at the top level for which to save/load data to/from. Default is "Mods/mod_data". + :type data_folder_path: str, optional + :param create_combined_file: If True, after reading through all json files, a combined.json file will be created that will include all other json data. If false, a combined.json file will not be created. Default is false. + :type create_combined_file: bool, optional + """ + + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + return 'common_folder_persistence_service' + + def __init__( + self, + main_file_name: str='main.json', + combined_file_name: str='combined.json', + allow_duplicates_in_collections: bool=False, + data_folder_path: str=None, + create_combined_file: bool=False + ) -> None: + super().__init__() + self._main_file_name = main_file_name + self._combined_file_name = combined_file_name + self._allow_duplicates_in_collections = allow_duplicates_in_collections + from sims4communitylib.utils.common_log_utils import CommonLogUtils + self._data_folder_path = data_folder_path or CommonLogUtils.get_mod_data_location_path() + from sims4communitylib.s4cl_configuration import S4CLConfiguration + self._create_combined_file = create_combined_file or S4CLConfiguration().create_combined_json + + # noinspection PyMissingOrEmptyDocstring + def load(self, mod_identity: CommonModIdentity, identifier: str=None) -> Dict[str, Any]: + # mod_folder_persistence_service + log = CommonLogRegistry().register_log(mod_identity, '{}_{}'.format(mod_identity.base_namespace, self.log_identifier)) + folder_path = self._folder_path(mod_identity, identifier=identifier) + + log.format_with_message('Loading data.', mod=mod_identity, folder_path=folder_path) + + if not os.path.exists(folder_path): + log.format_with_message('No folder was found at path.', mod=mod_identity, folder_path=folder_path) + return dict() + file_names = list() + + main_file_path = os.path.join(folder_path, self._main_file_name) + loaded_main_data: Dict[str, Any] = CommonJSONIOUtils.load_from_file(main_file_path) + if loaded_main_data is None: + log.format_with_message('Missing main data!', main_file_path=main_file_path) + loaded_main_data = dict() + + file_names.append(self._main_file_name) + + if self._create_combined_file: + combined_file_path = os.path.join(folder_path, self._combined_file_name) + loaded_combined_data: Dict[str, Any] = CommonJSONIOUtils.load_from_file(combined_file_path) + else: + loaded_combined_data = None + + def _on_file_read_failure(file_path: str, ex: Exception): + log.error('Failed to read file with path {}'.format(file_path), exception=ex) + return True + + loaded_data: Dict[str, Dict[str, Any]] = CommonJSONIOUtils.load_from_folder( + folder_path, + skip_file_names=(self._main_file_name, self._combined_file_name), + on_file_read_failure=_on_file_read_failure + ) + if loaded_data is None: + return dict() + complete_data = dict() + for (key, val) in loaded_data.items(): + file_names.append(key) + complete_data = CommonCollectionUtils.merge_dict(complete_data, val, prefer_source_values=True, allow_duplicates_in_collections=self._allow_duplicates_in_collections) + if self._create_combined_file: + if loaded_combined_data is not None: + complete_data = CommonCollectionUtils.merge_dict(loaded_combined_data, complete_data, prefer_source_values=True, allow_duplicates_in_collections=self._allow_duplicates_in_collections) + complete_data = CommonCollectionUtils.merge_dict(complete_data, loaded_main_data, prefer_source_values=True, allow_duplicates_in_collections=self._allow_duplicates_in_collections) + log.format_with_message('Done loading data.', mod=mod_identity, folder_path=folder_path, complete_data=complete_data, file_names=file_names) + complete_data['loaded_file_names'] = file_names + return complete_data + + # noinspection PyMissingOrEmptyDocstring + def save(self, mod_identity: CommonModIdentity, data: Dict[str, Any], identifier: str=None) -> bool: + # mod_folder_persistence_service + log = CommonLogRegistry().register_log(mod_identity, '{}_{}'.format(mod_identity.base_namespace, self.log_identifier)) + folder_path = self._folder_path(mod_identity, identifier=identifier) + data_to_save = data.copy() + + if self._create_combined_file: + file_path = os.path.join(folder_path, self._combined_file_name) + log.format_with_message('Loading data.', mod=mod_identity, file_path=file_path) + if 'loaded_file_names' in data_to_save: + del data_to_save['loaded_file_names'] + + os.makedirs(folder_path, exist_ok=True) + if os.path.exists(file_path): + log.debug('File existed already, removing the existing one.') + os.remove(file_path) + + result = CommonJSONIOUtils.write_to_file(file_path, data_to_save) + log.format_with_message('Done saving data.', file_path=file_path) + return result + return True + + # noinspection PyMissingOrEmptyDocstring + def remove(self, mod_identity: CommonModIdentity, identifier: str=None) -> bool: + # mod_folder_persistence_service + log = CommonLogRegistry().register_log(mod_identity, '{}_{}'.format(mod_identity.base_namespace, self.log_identifier)) + folder_path = self._folder_path(mod_identity, identifier=identifier) + + if self._create_combined_file: + file_path = os.path.join(folder_path, self._combined_file_name) + log.format_with_message('Removing data.', mod=mod_identity, file_path=file_path) + + if os.path.exists(file_path): + log.debug('Data existed, removing it.') + os.remove(file_path) + + log.format_with_message('Data deleted successfully.', file_path=file_path) + return not os.path.exists(file_path) + return True + + def _folder_path(self, mod_identity: CommonModIdentity, identifier: str=None) -> str: + folder_path = os.path.join(self._data_folder_path, mod_identity.base_namespace.lower()) + if identifier is not None: + folder_path = os.path.join(folder_path, identifier) + return folder_path diff --git a/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_hidden_household_persistence_service.py b/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_hidden_household_persistence_service.py new file mode 100644 index 0000000..0f5b1af --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_hidden_household_persistence_service.py @@ -0,0 +1,118 @@ +""" +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 +""" +import json +from typing import Dict, Any + +from sims.household import Household +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.persistence.persistence_services.common_persistence_service import CommonPersistenceService +from sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils + + +class CommonHiddenHouseholdPersistenceService(CommonPersistenceService): + """CommonHiddenHouseholdPersistenceService() + + A service that persists data into a hidden household. (This data is per save file, it won't carry to other Saves) + """ + + # noinspection PyMissingOrEmptyDocstring + def load(self, mod_identity: CommonModIdentity, identifier: str=None) -> Dict[str, Any]: + data_name = self._format_data_name(mod_identity, identifier=identifier) + all_households = tuple(CommonHouseholdUtils.get_all_households_generator()) + if not all_households: + raise Exception(f'Households have not been loaded yet, but data with name {data_name} is attempting to be loaded! Please try to use the data after the households have been loaded instead. (Households are available when the S4CLZoneLateLoadEvent event is dispatched)') + + self.log.format_with_message('Loading data.', data_name=data_name) + loaded_data: Dict[str, Any] = None + loaded_household: Household = None + + def _load_data_from_household(household: Household) -> Dict[str, Any]: + # noinspection PyPropertyAccess + _household_name = household.name + # noinspection PyPropertyAccess + self.log.format_with_message('Attempting to read data stored within household.', household_name=_household_name, household_id=household.id) + # noinspection PyPropertyAccess + raw_data = household.description + if not raw_data: + self.log.format_with_message('No raw data found, returning default data.', data=household) + return dict() + self.log.debug('Data found, attempting to parse data.') + return json.loads(raw_data) + + self.log.format_with_message('Attempting to locate data by exact name', data_name=data_name) + located_household = CommonHouseholdUtils.locate_household_by_name(data_name) + if located_household is not None: + self.log.format_with_message('Located data with exact name.', data_name=data_name) + loaded_data = _load_data_from_household(located_household) + if loaded_data is not None: + loaded_household = located_household + + self.log.format_with_message('Attempting to locate data containing name.', data_name=data_name) + for persisted_household in CommonHouseholdUtils.locate_households_by_name_generator(data_name, allow_partial_match=True): + if persisted_household is None or (loaded_household is not None and persisted_household is loaded_household): + self.log.debug('Household does not match.') + continue + # noinspection PyPropertyAccess + household_name = persisted_household.name + if loaded_data is not None: + # noinspection PyPropertyAccess + self.log.format_with_message('Duplicate household found, attempting to remove duplicate.', household_name=household_name, household_id=persisted_household.id) + if CommonHouseholdUtils.delete_household(persisted_household): + self.log.format_with_message('Successfully deleted duplicate household.', household_name=household_name) + else: + self.log.format_with_message('Failed to delete duplicate household.', household_name=household_name) + continue + loaded_data = _load_data_from_household(persisted_household) + if loaded_data is not None: + loaded_household = persisted_household + if loaded_data is None: + return dict() + self.log.format_with_message('Done loading data.', data_name=data_name, loaded_data=loaded_data) + return loaded_data + + # noinspection PyMissingOrEmptyDocstring + def save(self, mod_identity: CommonModIdentity, data: Dict[str, Any], identifier: str=None) -> bool: + data_name = self._format_data_name(mod_identity, identifier=identifier) + self.log.format_with_message('Saving data.', data_name=data_name) + self.log.format_with_message('Attempting to locate data.', data_name=data_name) + persisted_data_storage = CommonHouseholdUtils.locate_household_by_name(data_name) + if persisted_data_storage is None: + self.log.debug('No persisted data found, creating new persisted data.') + persisted_data_storage = CommonHouseholdUtils.create_empty_household(as_hidden_household=True) + if persisted_data_storage is None: + self.log.debug('Failed to persisted data.') + return False + self.log.debug('Persisted data created successfully. Setting properties.') + persisted_data_storage.name = data_name + persisted_data_storage.creator_id = 0 + persisted_data_storage.creator_name = data_name + persisted_data_storage.creator_uuid = b'' + else: + self.log.format_with_message('Found persisted data. Attempting to save data.', data=persisted_data_storage) + self.log.format_with_message('Attempting to save data.', data=persisted_data_storage) + try: + self.log.format(data_being_saved=data) + json_save_data = json.dumps(data) + persisted_data_storage.description = json_save_data + except Exception as ex: + self.log.format_error_with_message('Failed to save data.', data_name=data_name, exception=ex) + raise ex + self.log.format_with_message('Done saving data.', data_name=data_name) + return True + + # noinspection PyMissingOrEmptyDocstring + def remove(self, mod_identity: CommonModIdentity, identifier: str=None) -> bool: + data_name = self._format_data_name(mod_identity, identifier=identifier) + self.log.format_with_message('Removing data.', data_name=data_name) + self.log.format_with_message('Attempting to remove data.', data_name=data_name) + result = CommonHouseholdUtils.delete_households_with_name(data_name, allow_partial_match=True) + if not result: + self.log.format_with_message('Failed to delete data.', data_name=data_name) + return result + self.log.format_with_message('Data deleted successfully.', data_name=data_name) + return result diff --git a/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_individual_folder_persistence_service.py b/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_individual_folder_persistence_service.py new file mode 100644 index 0000000..ebe9455 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_individual_folder_persistence_service.py @@ -0,0 +1,114 @@ +""" +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 +""" +import os +from typing import Dict, Any + +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.persistence.persistence_services.common_persistence_service import CommonPersistenceService +from sims4communitylib.utils.common_json_io_utils import CommonJSONIOUtils +from sims4communitylib.utils.common_log_registry import CommonLogRegistry + + +class CommonIndividualFolderPersistenceService(CommonPersistenceService): + """CommonIndividualFolderPersistenceService(main_file_name='main.json', combined_file_name='combined.json', allow_duplicates_in_collections=False, data_folder_path=None) + + A service that persists data to a file within a folder on the system. It also loads all data from a folder on the system while loading the main file last. + + :param main_file_name: A file that will be loaded after the other files in the folder specified by folder_name. Default is 'main.json'. + :type main_file_name: str, optional + :param data_folder_path: Use to specify a custom folder path at the top level for which to save/load data to/from. Default is "Mods/mod_data". + :type data_folder_path: str, optional + """ + + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + return 'common_individual_folder_persistence_service' + + def __init__( + self, + main_file_name: str = 'main.json', + data_folder_path: str = None + ) -> None: + super().__init__() + self._main_file_name = main_file_name + from sims4communitylib.utils.common_log_utils import CommonLogUtils + self._data_folder_path = data_folder_path or CommonLogUtils.get_mod_data_location_path() + + # noinspection PyMissingOrEmptyDocstring + def load(self, mod_identity: CommonModIdentity, identifier: str = None) -> Dict[str, Dict[str, Any]]: + # mod_folder_persistence_service + log = CommonLogRegistry().register_log(mod_identity, f'{mod_identity.base_namespace}_{self.log_identifier}') + folder_path = self._folder_path(mod_identity, identifier=identifier) + + log.format_with_message('Loading data.', mod=mod_identity, folder_path=folder_path, identifier=identifier) + + if not os.path.exists(folder_path): + log.format_with_message('No folder was found at path.', mod=mod_identity, folder_path=folder_path) + return dict() + file_names = list() + + main_file_path = os.path.join(folder_path, self._main_file_name) + loaded_main_data: Dict[str, Any] = CommonJSONIOUtils.load_from_file(main_file_path) + if loaded_main_data is None: + log.format_with_message('Missing main data!', main_file_path=main_file_path) + loaded_main_data = dict() + + file_names.append(self._main_file_name) + + def _on_file_read_failure(file_path: str, ex: Exception): + log.error(f'Failed to read file with path {file_path}', exception=ex) + return True + + loaded_data: Dict[str, Dict[str, Any]] = CommonJSONIOUtils.load_from_folder( + folder_path, + skip_file_names=(self._main_file_name,), + on_file_read_failure=_on_file_read_failure + ) + log.format_with_message('Got loaded data.', loaded_data=loaded_data) + if loaded_data is None: + return dict() + data_by_file_name: Dict[str, Dict[str, Any]] = dict() + for (key, val) in loaded_data.items(): + data_by_file_name[key] = val + file_names.append(key) + data_by_file_name[self._main_file_name] = loaded_main_data + log.format_with_message('Done loading data.', mod=mod_identity, folder_path=folder_path, complete_data=data_by_file_name, file_names=file_names) + return data_by_file_name + + # noinspection PyMissingOrEmptyDocstring + def save(self, mod_identity: CommonModIdentity, data: Dict[str, Dict[str, Any]], identifier: str = None) -> bool: + # mod_folder_persistence_service + log = CommonLogRegistry().register_log(mod_identity, f'{mod_identity.base_namespace}_{self.log_identifier}') + folder_path = self._folder_path(mod_identity, identifier=identifier) + for (file_name, file_data) in data.items(): + if file_name == 'main.json': + continue + file_path = os.path.join(folder_path, file_name) + log.format_with_message('Loading data.', mod=mod_identity, file_path=file_path) + + os.makedirs(folder_path, exist_ok=True) + if os.path.exists(file_path): + log.debug('File existed already, removing the existing one.') + os.remove(file_path) + + result = CommonJSONIOUtils.write_to_file(file_path, file_data) + log.format_with_message('Done saving data.', file_path=file_path) + if not result: + log.format_with_message('Failed to save data.', file_path=file_path, data=file_data) + return True + + # noinspection PyMissingOrEmptyDocstring + def remove(self, mod_identity: CommonModIdentity, identifier: str = None) -> bool: + return True + + def _folder_path(self, mod_identity: CommonModIdentity, identifier: str = None) -> str: + folder_path = os.path.join(self._data_folder_path, mod_identity.base_namespace.lower()) + if identifier is not None: + folder_path = os.path.join(folder_path, identifier) + return folder_path diff --git a/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_persistence_service.py b/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_persistence_service.py new file mode 100644 index 0000000..4103134 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_persistence_service.py @@ -0,0 +1,85 @@ +""" +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 +""" +from typing import Dict, Any + +from sims4communitylib.logging.has_log import HasLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo + + +class CommonPersistenceService(HasLog): + """CommonPersistenceService() + + A service used to persist data. + + """ + + # noinspection PyMissingOrEmptyDocstring + @property + def mod_identity(self) -> CommonModIdentity: + return ModInfo.get_identity() + + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + return 'common_persistence_service' + + def __init__(self) -> None: + super().__init__() + if self.__class__.__name__ == CommonPersistenceService.__name__: + raise RuntimeError('{} cannot be created directly. You must inherit from it to create an instance of it.'.format(self.__class__.__name__)) + + def _format_data_name(self, mod_identity: CommonModIdentity, identifier: str=None) -> str: + if identifier is not None: + return '{}_{}'.format(mod_identity.base_namespace, identifier.replace(' ', '_')).lower() + else: + return '{}_main'.format(mod_identity.base_namespace).lower() + + def load(self, mod_identity: CommonModIdentity, identifier: str=None) -> Dict[str, Any]: + """load(mod_identity, identifier=None) + + Load persisted data for the specified Mod Identity. + + :param mod_identity: The identity of the mod that data is being loaded for. + :type mod_identity: CommonModIdentity + :param identifier: If set, the identifier will be used to make the data name even more unique. Don't set it if you don't need to! Default is None. + :type identifier: str, optional + :return: A library of data. + :rtype: Dict[str, Any] + """ + raise NotImplementedError() + + def save(self, mod_identity: CommonModIdentity, data: Dict[str, Any], identifier: str=None) -> bool: + """save(mod_identity, data, identifier=None) + + Save persisted data for the specified Mod Identity. + + :param mod_identity: The identity of the mod that data is being saved for. + :type mod_identity: CommonModIdentity + :param data: The data being persisted. + :type data: Dict[str, Any] + :param identifier: If set, the identifier will be used to make the data name even more unique. Don't set it if you don't need to! Default is None. + :type identifier: str, optional + :return: True, if the data was persisted successfully. False, if not. + :rtype: bool + """ + raise NotImplementedError() + + def remove(self, mod_identity: CommonModIdentity, identifier: str=None) -> bool: + """remove(mod_identity) + + Removed persisted data for the specified Mod Identity. + + :param mod_identity: The identity of the mod that data is being removed for. + :type mod_identity: CommonModIdentity + :param identifier: If set, the identifier will be used to make the data name even more unique. Don't set it if you don't need to! Default is None. + :type identifier: str, optional + :return: True, if the data was removed successfully. False, if not. + :rtype: bool + """ + raise NotImplementedError() diff --git a/Scripts/s4ap/sims4communitylib/s4cl_commands.py b/Scripts/s4ap/sims4communitylib/s4cl_commands.py new file mode 100644 index 0000000..e78da68 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/s4cl_commands.py @@ -0,0 +1,87 @@ +""" +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 +""" +from objects.game_object import GameObject +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + CommonConsoleCommandArgument +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.common_log_registry import CommonLogRegistry +from sims4communitylib.utils.misc.common_fire_utils import CommonFireUtils +from sims4communitylib.utils.objects.common_object_location_utils import CommonObjectLocationUtils +from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils +from sims4communitylib.utils.sims.common_sim_location_utils import CommonSimLocationUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils + +log = CommonLogRegistry().register_log(ModInfo.get_identity(), 's4cl_commands') +log.enable() + + +@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.the_mother_calls', 'Invokes the mothers call.', show_with_help_command=False) +def _common_the_mother_calls(output: CommonConsoleCommandOutput): + output('She calls and you must listen! Who shall answer the call?') + sim_count = 0 + # trait_Strangerville_Infected + trait_id = 201407 + output(f'The call has begun, who shall answer it?') + for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): + if CommonTraitUtils.has_trait(sim_info, trait_id): + continue + if CommonTraitUtils.add_trait(sim_info, trait_id): + sim_count += 1 + output(f'{sim_count} Sim(s) have answered the call.') + + +@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.come_to_me_now', 'Formally request all objects in the area to come to the active Sim.', show_with_help_command=False) +def _common_come_to_me_now(output: CommonConsoleCommandOutput): + sim_info = CommonSimUtils.get_active_sim_info() + new_location = CommonSimLocationUtils.get_location(sim_info) + object_count = 0 + output(f'Attempting to request all objects to come to {sim_info}.') + for game_object in CommonObjectUtils.get_instance_for_all_game_objects_generator(): + # noinspection PyBroadException + try: + CommonObjectLocationUtils.set_location(game_object, new_location) + object_count += 1 + except: + continue + output(f'{object_count} Object(s) came to {sim_info}.') + + +@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.burn_it_all', 'Some Sims just want to see the world burn.', show_with_help_command=False) +def _common_burn_it_all(output: CommonConsoleCommandOutput): + object_count = 0 + output(f'Do you smell smoke?') + for game_object in CommonObjectUtils.get_instance_for_all_game_objects_generator(): + # noinspection PyBroadException + try: + if CommonFireUtils.spawn_fires_on_object(game_object): + object_count += 1 + except: + continue + output(f'{object_count} Object(s) have been set ablaze. You might want to run now.') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.burn_it', + 'Some Sims just want to see the world burn.', + command_arguments=( + CommonConsoleCommandArgument('game_object', 'Decimal ID', 'The Decimal Identifier of the object to spawn a fire at.'), + ), + show_with_help_command=False +) +def _common_burn_it(output: CommonConsoleCommandOutput, game_object: GameObject): + output(f'Do you smell smoke?') + if not CommonFireUtils.is_fire_allowed_at_location(CommonObjectLocationUtils.get_location(game_object)): + output(f'Fires are not allowed on the object. {game_object}.') + return + if CommonFireUtils.spawn_fires_on_object(game_object): + output(f'{game_object} has been set ablaze. You might want to run now.') + else: + output(f'For some reason {game_object} failed to catch fire.') diff --git a/Scripts/s4ap/sims4communitylib/s4cl_configuration.py b/Scripts/s4ap/sims4communitylib/s4cl_configuration.py new file mode 100644 index 0000000..81f7799 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/s4cl_configuration.py @@ -0,0 +1,130 @@ +""" +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 +""" +import os +from typing import Tuple, Dict, List, Any + +from sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler +from sims4communitylib.logging.has_log import HasLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.common_service import CommonService +from sims4communitylib.utils.common_json_io_utils import CommonJSONIOUtils +from sims4communitylib.utils.common_log_registry import CommonMessageType +from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + +ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' + + +class S4CLConfiguration(HasLog, CommonService): + """ Manages configuration via the sims4communitylib.config file. """ + _CONFIGURATION_FILE_NAME = 'sims4communitylib.config' + if not ON_RTD: + _DEFAULT_CONFIG_DATA = { + 'enable_vanilla_logging': False, + 'enable_extra_shift_click_menus': True, + 'persist_mod_data_per_save_slot': False, + 'create_combined_json': False, + 'max_output_file_size_in_bytes': 524288000, + 'enable_logs': { + 'example_log_that_is_enabled': ['DEBUG', 'WARN'] + } + } + else: + _DEFAULT_CONFIG_DATA = dict() + + # noinspection PyMissingOrEmptyDocstring + @property + def mod_identity(self) -> CommonModIdentity: + return ModInfo.get_identity() + + def __init__(self) -> None: + self._config_data = dict() + super().__init__() + self._config_data: Dict[str, Any] = S4CLConfiguration._DEFAULT_CONFIG_DATA.copy() + try: + file_path = os.path.dirname(os.path.dirname(os.path.dirname(self.mod_identity.file_path.rstrip('/').rstrip('\\')))) + full_file_path = os.path.join(file_path, S4CLConfiguration._CONFIGURATION_FILE_NAME) + try: + if os.path.exists(full_file_path): + existing_config_data = CommonJSONIOUtils.load_from_file(full_file_path) or dict() + if 'enable_logs_result' in existing_config_data: + del existing_config_data['enable_logs_result'] + self._config_data.update(existing_config_data) + CommonJSONIOUtils.write_to_file(full_file_path, self._config_data) + else: + CommonJSONIOUtils.write_to_file(full_file_path, self._config_data) + except Exception as ex: + CommonExceptionHandler.log_exception(self.mod_identity, 'Failed to read the configuration file named {} at path "{}"!'.format(S4CLConfiguration._CONFIGURATION_FILE_NAME, full_file_path), exception=ex) + if not os.path.exists(full_file_path): + # noinspection PyBroadException + try: + CommonJSONIOUtils.write_to_file(full_file_path, self._config_data) + except: + pass + except Exception as ex: + CommonExceptionHandler.log_exception(self.mod_identity, 'Failed to format the file path to the S4CL configuration file.', exception=ex) + + @property + def persist_mod_data_per_save_slot(self) -> bool: + """Whether or not mod_data should include the save slot id within the persisted data file names. If False, only the Guid will be present in the file names. This value will also have an effect on loading files too!""" + if self._config_data is None or not self._config_data: + return False + return self._config_data.get('persist_mod_data_per_save_slot', False) + + @property + def enable_vanilla_logging(self) -> bool: + """ Whether or not vanilla logging should be enabled. """ + if self._config_data is None or not self._config_data: + return False + return self._config_data.get('enable_vanilla_logging', False) + + @property + def max_output_file_size_in_bytes(self) -> int: + """ The maximum size a file created by S4CL can be in bytes. """ + if self._config_data is None or not self._config_data: + return False + return self._config_data.get('max_output_file_size_in_bytes', 524288000) + + @property + def enable_extra_shift_click_menus(self) -> bool: + """ Whether or not to enable the SHIFT+CLICK menu in places that normally do not have a SHIFT+CLICK menu due to the ignorance of the SHIFT key. i.e. Relationship Panel, Phone, and Inventory. """ + if self._config_data is None or not self._config_data: + return False + return self._config_data.get('enable_extra_shift_click_menus', False) + + @property + def create_combined_json(self) -> bool: + """ Whether or not to create a combined.json file when reading through folders. """ + if self._config_data is None or not self._config_data: + return False + return self._config_data.get('create_combined_json', False) + + @property + def enable_logs(self) -> Dict[str, Tuple[CommonMessageType]]: + """ Logs to enable before loading The Sims 4. """ + if self._config_data is None or not self._config_data: + return dict() + if 'enable_logs_result' in self._config_data: + return self._config_data.get('enable_logs_result', dict()) + enable_logs = self._config_data.get('enable_logs', dict()) + enable_logs_result: Dict[str, Tuple[CommonMessageType]] = dict() + try: + for (key, message_type_strings) in enable_logs.items(): + message_types: List[CommonMessageType] = list() + for message_type_string in message_type_strings: + message_type: CommonMessageType = CommonResourceUtils.get_enum_by_name(message_type_string, CommonMessageType, default_value=CommonMessageType.INVALID) + if message_type is None: + continue + message_types.append(message_type) + if message_types: + enable_logs_result[key] = tuple(message_types) + except Exception as ex: + CommonExceptionHandler.log_exception(self.mod_identity, 'Error occurred while parsing the enable_logs configuration value.', exception=ex) + return dict() + self._config_data['enable_logs_result'] = enable_logs_result + return enable_logs_result diff --git a/Scripts/s4ap/sims4communitylib/services/__init__.py b/Scripts/s4ap/sims4communitylib/services/__init__.py new file mode 100644 index 0000000..3251898 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/services/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" \ No newline at end of file diff --git a/Scripts/s4ap/sims4communitylib/services/commands/__init__.py b/Scripts/s4ap/sims4communitylib/services/commands/__init__.py new file mode 100644 index 0000000..3251898 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/services/commands/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" \ No newline at end of file diff --git a/Scripts/s4ap/sims4communitylib/services/commands/common_console_command.py b/Scripts/s4ap/sims4communitylib/services/commands/common_console_command.py new file mode 100644 index 0000000..f469bcd --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/services/commands/common_console_command.py @@ -0,0 +1,664 @@ +""" +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 +""" +import inspect +from functools import wraps +from typing import Any, Dict, Union, Iterator, Tuple, Type, List, TYPE_CHECKING + +from objects.game_object import GameObject +from sims.sim_info import SimInfo +from sims4.commands import CommandType, CommandRestrictionFlags, Output, CustomParam +from sims4.common import Pack +from sims4communitylib.logging.has_class_log import HasClassLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.services.common_service import CommonService +from singletons import UNSET + +if TYPE_CHECKING: + from sims4communitylib.utils.common_log_registry import CommonLog + + +class CommonConsoleCommandArgument: + """CommonConsoleCommandArgument(arg_name, arg_type_name, arg_description, is_optional=False, default_value=None) + + An object that describes details about an argument that is used in a command. + + :param arg_name: A name to display for the argument. + :type arg_name: str + :param arg_type_name: Text to display that represents the type of the argument. + :type arg_type_name: str + :param arg_description: Text that describes what the argument is for. + :type arg_description: str + :param is_optional: Whether or not the argument is optional or required to be specified in the command. Default is False. + :type is_optional: bool, optional + :param default_value: If the argument is optional, this is the default value that will be used for the argument. Default is None. + :type default_value: Any, optional + """ + def __init__(self, arg_name: str, arg_type_name: str, arg_description: str, is_optional: bool=False, default_value: Any=None): + self.arg_name = arg_name + self.arg_type_name = arg_type_name + self.arg_description = arg_description or 'No Description Provided' + self.is_optional = is_optional or (default_value is not None) + self.default_value = default_value + + def __repr__(self) -> str: + name = self.arg_name + if self.is_optional: + default_value = self.default_value + name = f'[{name}={default_value}]' + else: + name = f'{name}' + return name + + def __str__(self) -> str: + repr_result = self.__repr__() + arg_type_name = self.arg_type_name + description = self.arg_description + return f'{repr_result} ({arg_type_name}) - {description}' + + +class CommonConsoleCommandOptionalArgument(CommonConsoleCommandArgument): + """CommonConsoleCommandArgument(arg_name, arg_type_name, arg_description, default_value) + + An object that describes details about an Optional argument that is used in a command. + + :param arg_name: A name to display for the argument. + :type arg_name: str + :param arg_type_name: Text to display that represents the type of the argument. + :type arg_type_name: str + :param arg_description: Text that describes what the argument is for. + :type arg_description: str + :param default_value: This is the default value that will be used for the argument. + :type default_value: Any + """ + def __init__(self, arg_name: str, arg_type_name: str, arg_description: str, default_value: Any): + super().__init__(arg_name, arg_type_name, arg_description, is_optional=True, default_value=default_value) + + +class CommonConsoleCommandRequiredArgument(CommonConsoleCommandArgument): + """CommonConsoleCommandArgument(arg_name, arg_type_name, arg_description) + + An object that describes details about a Required argument that is used in a command. + + :param arg_name: A name to display for the argument. + :type arg_name: str + :param arg_type_name: Text to display that represents the type of the argument. + :type arg_type_name: str + :param arg_description: Text that describes what the argument is for. + :type arg_description: str + """ + def __init__(self, arg_name: str, arg_type_name: str, arg_description: str): + super().__init__(arg_name, arg_type_name, arg_description, is_optional=False) + + +class _CommonConsoleCommandMetaclass(type): + def __call__( + cls, + mod_identity: CommonModIdentity, + command_name: str, + command_description: str, + command_aliases: Iterator[str]=(), + command_arguments: Iterator[CommonConsoleCommandArgument]=(), + command_type: CommandType=CommandType.Live, + command_restriction_flags: CommandRestrictionFlags=CommandRestrictionFlags.UNRESTRICTED, + required_pack_flags: Pack=None, + console_type: CommandType=None, + show_with_help_command: bool=True + ) -> Union['_CommonConsoleCommandMetaclass', None]: + mod_name = mod_identity.name + if mod_name is None: + return None + command = CommonConsoleCommandService().get_command_by_mod_and_name(mod_identity, command_name) + if command is None: + command = super(_CommonConsoleCommandMetaclass, cls).__call__( + mod_identity, + command_name, + command_description, + command_aliases=command_aliases, + command_arguments=command_arguments, + command_type=command_type, + command_restriction_flags=command_restriction_flags, + required_pack_flags=required_pack_flags, + console_type=console_type, + show_with_help_command=show_with_help_command + ) + CommonConsoleCommandService()._add_command(command) + return CommonConsoleCommandService().command(mod_identity, command_name, *command_aliases, command_type=command_type, command_restriction_flags=command_restriction_flags, required_pack_flags=required_pack_flags, console_type=console_type) + + +class CommonConsoleCommand(metaclass=_CommonConsoleCommandMetaclass): + """CommonConsoleCommand(\ + mod_identity,\ + command_name,\ + command_description,\ + command_aliases=(),\ + command_arguments=(),\ + command_type=CommandType.Live,\ + command_restriction_flags=CommandRestrictionFlags.UNRESTRICTED,\ + required_pack_flags=None,\ + console_type=None,\ + show_with_help_command=True\ + ) + + Used to indicate a command that can be run in the CTRL+SHIFT+C console. + + .. note:: When a command is created, a Help command is also created for your Mod using the mod_identity.name (If it does not already exist) ".help". Use this command to display all commands that have been registered using CommonConsoleCommand. + + .. note:: To see an example command, run the command :class:`s4clib_testing.example_command` in the in-game console. + .. note:: If the command_name contains underscores, a variant of the command_name without underscores will be added to command_aliases. i.e. 's4cl.do_thing' will be added as 's4cl.dothing' to command_aliases. + .. note:: If any command_aliases contain underscores, variants of those command_aliases without underscores will be added to command_aliases. i.e. 's4cl.do_the_thing' will be added as 's4cl.dothething' to command_aliases. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + @CommonConsoleCommand(ModInfo.get_identity(), 's4clib_testing.example_command', 'Print an example message', command_aliases=('s4clib_testing.examplecommand',), command_arguments=(CommonConsoleCommandArgument('thing_to_print', 'Text or Num', 'If specified, this value will be printed to the console. Default is "24".'),)) + def _common_testing_do_example_command(output: Output, thing_to_print: str='24'): + output(f'Here is what to print: {thing_to_print}') + + :param mod_identity: The identity of the mod that owns this command. + :type mod_identity: CommonModIdentity + :param command_name: The name of the command. This name can be used to run this command in the console. + :type command_name: str + :param command_description: Text that describes the purpose of this command and what it does. + :type command_description: str + :param command_aliases: Alternative names for the command that can be used to run this command in the console. Default is no aliases. + :type command_aliases: Iterator[str], optional + :param command_arguments: Command arguments that are used to describe details about the arguments of the command. Default is no arguments described. + :type command_arguments: Iterator[CommonConsoleCommandArgument], optional + :param command_type: The type of command, most of the time you will want it to be CommandType.Live. Default is CommandType.Live. + :type command_type: CommandType, optional + :param command_restriction_flags: Flags that indicate restrictions of the command. Default is CommandRestrictionFlags.UNRESTRICTED. + :type command_restriction_flags: CommandRestrictionFlags, optional + :param required_pack_flags: Flags to indicate what Game Packs are required in order for this command to be available. If set to None, no Game Packs will be required to run this command. Default is None. + :type required_pack_flags: Pack, optional + :param console_type: The type of console the command may be run in. If set to None, the default console will be used. Default is None. + :type console_type: CommandType, optional + :param show_with_help_command: If True, this command will appear when a player does ".help". If False, it will not appear when a player does ".help" but will still appear when they do ".help ". Default is True. + :type show_with_help_command: bool, optional + """ + def __init__( + self, + mod_identity: CommonModIdentity, + command_name: str, + command_description: str, + command_aliases: Iterator[str] = (), + command_arguments: Iterator[CommonConsoleCommandArgument] = (), + command_type: CommandType = CommandType.Live, + command_restriction_flags: CommandRestrictionFlags = CommandRestrictionFlags.UNRESTRICTED, + required_pack_flags: Pack = None, + console_type: CommandType = None, + show_with_help_command: bool = True + ) -> None: + self.mod_identity = mod_identity + self.command_name = command_name + command_without_underscores = command_name.replace('_', '') + new_command_aliases = list(command_aliases) + if command_without_underscores != command_name and command_without_underscores not in command_aliases: + new_command_aliases.append(command_without_underscores) + for command_alias in command_aliases: + command_alias_without_underscores = command_alias.replace('_', '') + if command_alias_without_underscores != command_alias and command_alias_without_underscores not in command_aliases: + new_command_aliases.append(command_alias_without_underscores) + command_aliases = new_command_aliases + self.command_aliases = tuple(command_aliases) + self.command_description = command_description + self.command_type = command_type + self.command_restriction_flags = command_restriction_flags + self.required_pack_flags = required_pack_flags + self.console_type = console_type + self.show_with_help_command = show_with_help_command + self.command_arguments: Dict[str, CommonConsoleCommandArgument] = { + arg.arg_name: arg + for arg in command_arguments + if arg.arg_name is not None + } + + @property + def arguments(self) -> Tuple[CommonConsoleCommandArgument]: + """The arguments of the command.""" + return tuple(self.command_arguments.values()) + + def __call__(self, *args, **kwargs) -> Any: + # noinspection PyUnresolvedReferences + return super().__call__(self, *args, **kwargs) + + def __repr__(self) -> str: + arg_str = ' '.join([repr(command_argument) for command_argument in self.arguments]) + name = self.command_name + description = self.command_description + return f'{name} {arg_str} - {description}' + + def __str__(self) -> str: + arg_str = '\n '.join([str(command_argument) for command_argument in self.arguments]) + name = self.command_name + description = self.command_description + return f'{name} - {description}\n {arg_str}' + + +class CommonConsoleCommandService(CommonService, HasClassLog): + """A service for creating and managing console commands.""" + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + return ModInfo.get_identity() + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 'common_console_command_service' + + def __init__(self) -> None: + super().__init__() + self._commands_by_mod_name: Dict[str, Dict[str, CommonConsoleCommand]] = dict() + + def _add_command(self, command: CommonConsoleCommand) -> None: + """Add a command to the library of commands.""" + mod_identity = command.mod_identity + mod_name = CommonModIdentity._get_mod_name(mod_identity.name).lower() + if mod_name not in self._commands_by_mod_name: + self._commands_by_mod_name[mod_name] = dict() + self._commands_by_mod_name[mod_name][command.command_name] = command + + self._create_help_command(mod_identity) + + def _help_command_name(self, mod_identity: CommonModIdentity) -> str: + mod_name = CommonModIdentity._get_mod_name(mod_identity.name).lower() + return f'{mod_name}.help' + + def _create_help_command(self, mod_identity: CommonModIdentity) -> None: + from sims4communitylib.utils.common_log_registry import CommonLogRegistry + help_log = CommonLogRegistry().register_log(mod_identity, f'{mod_identity.name}_help') + mod_name = CommonModIdentity._get_mod_name(mod_identity.name).lower() + if mod_name not in self._commands_by_mod_name: + self._commands_by_mod_name[mod_name] = dict() + + help_command_name = self._help_command_name(mod_identity) + if help_command_name not in self._commands_by_mod_name[mod_name]: + @CommonConsoleCommand( + mod_identity, + help_command_name, + f'Show commands for the {mod_identity.name} mod.', + command_arguments=( + CommonConsoleCommandOptionalArgument('command_name', 'Text', f'If set, "{help_command_name}" will print the details of the instead of all commands. Example: "{help_command_name} {help_command_name}"', default_value=None), + )) + def _common_help_command(output: CommonConsoleCommandOutput, command_name: str=None): + try: + help_log.enable() + output('--------------------') + help_log.debug('--------------------') + output(f'NOTE: The following details have also been logged to "The Sims 4/mod_logs/_Messages.txt", in case not all data is shown.') + if command_name: + _command = CommonConsoleCommandService().get_command_by_mod_and_name(mod_identity, command_name) + if _command is None: + output(f'No command found with name. {command_name}') + help_log.debug(f'No command found with name. {command_name}') + else: + command_str = str(_command) + output(command_str) + help_log.debug(command_str) + else: + output(f'{mod_identity.name} Commands:') + output('- Angle Brackets (<>) means the argument is Required and must be provided when running the command') + output('- Square Brackets ([]) means the argument is Optional and does not need to be provided when running the command.') + output('- The "=..." part of an argument indicates the default value of that argument IF NOT SPECIFIED when invoking the command.') + output(f'- For specific details about a command, run the command like so "{help_command_name} "') + output(' ') + help_log.debug(f'{mod_identity.name} Commands:') + help_log.debug('- Angle Brackets (<>) means the argument is Required and must be provided when running the command') + help_log.debug('- Square Brackets ([]) means the argument is Optional and does not need to be provided when running the command.') + help_log.debug('- The "=..." part of an argument indicates the default value of that argument IF NOT SPECIFIED when invoking the command.') + help_log.debug(f'- For specific details about a command, run the command like so "{help_command_name} "') + help_log.debug(' ') + for (_command_name, _command) in sorted(list(CommonConsoleCommandService().get_commands_by_mod(mod_identity).items()), key=lambda x: x[0]): + _command: CommonConsoleCommand = _command + if not _command.show_with_help_command: + continue + command_repr = repr(_command) + output(command_repr) + help_log.debug(command_repr) + output('--------------------') + help_log.debug('--------------------') + output(f'NOTE: The above details have also been logged to "The Sims 4/mod_logs/_Messages.txt", in case not all data is shown.') + finally: + help_log.disable() + + def get_commands_by_mod(self, mod_identity: CommonModIdentity) -> Dict[str, CommonConsoleCommand]: + """Retrieve the commands available for a mod.""" + mod_name = CommonModIdentity._get_mod_name(mod_identity.name).lower() + if mod_name not in self._commands_by_mod_name: + return dict() + return self._commands_by_mod_name[mod_name] + + def get_command_by_mod_and_name(self, mod_identity: CommonModIdentity, command_name: str) -> Union[CommonConsoleCommand, None]: + """Retrieve the commands available for a mod.""" + mod_name = CommonModIdentity._get_mod_name(mod_identity.name).lower() + if mod_name not in self._commands_by_mod_name or command_name not in self._commands_by_mod_name[mod_name]: + return None + return self._commands_by_mod_name[mod_name][command_name] + + @classmethod + def command(cls, mod_identity: CommonModIdentity, *command_aliases: str, command_type: CommandType=CommandType.Live, command_restriction_flags: CommandRestrictionFlags=CommandRestrictionFlags.UNRESTRICTED, required_pack_flags: Pack=None, console_type: CommandType=None) -> Any: + """Create a command.""" + from sims4communitylib.utils.common_log_registry import CommonLogRegistry + log = CommonLogRegistry().register_log(mod_identity, f'{mod_identity.name}_command_log') + _command = cls._command(log, *command_aliases, command_type=command_type, command_restrictions=command_restriction_flags, pack=required_pack_flags, console_type=console_type) + + help_command_name = CommonConsoleCommandService()._help_command_name(mod_identity) + + def _wrapped_command(func) -> Any: + # command_name = command_aliases[0] + full_arg_spec = inspect.getfullargspec(func) + + @wraps(func) + def _wrapped_func(output: CommonConsoleCommandOutput, *_, _connection: int=None, _account: int=None, **__): + try: + if '_account' in full_arg_spec.args or '_account' in full_arg_spec.kwonlyargs: + __['_account'] = _account + if '_connection' in full_arg_spec.args or '_connection' in full_arg_spec.kwonlyargs: + __['_connection'] = _connection + # output(f'Running command "{command_name}"') + command_result = func(output, *_, **__) + # output(f'Command "{command_name}" finished running.') + return command_result + except Exception as ex: + log.error(f'An exception occurred while running command. {func.__name__}', exception=ex) + output(f'Error: "{ex}"') + + result = _command(_wrapped_func, func, help_command_name) + return result + + return _wrapped_command + + # noinspection PyMissingTypeHints + @classmethod + def _command(cls, log: 'CommonLog', *aliases: str, command_type: CommandType=CommandType.DebugOnly, command_restrictions: CommandRestrictionFlags=CommandRestrictionFlags.UNRESTRICTED, pack: Pack=None, console_type: CommandType=None): + # noinspection PyBroadException + try: + import sims4.common + import paths + import sims4.telemetry + except: + # noinspection PyUnusedLocal + def _named_command(wrapped_func, original_func, help_command_name) -> Any: + return + return _named_command + + from sims4.commands import CommandType, \ + is_command_available, cheats_writer, TELEMETRY_FIELD_NAME, TELEMETRY_FIELD_ARGS, TELEMETRY_HOOK_COMMAND, CustomParam, \ + prettify_usage, register + if console_type is not None and not paths.IS_DESKTOP: + relevant_type = console_type + else: + relevant_type = command_type + if console_type is not None: + most_limited_type = min(command_type, console_type) + else: + most_limited_type = command_type + + def _is_valid_command() -> bool: + if relevant_type == CommandType.DebugOnly: + return False + elif pack and not sims4.common.are_packs_available(pack): + return False + return True + + def _named_command(wrapped_func, original_func, help_command_name) -> Any: + if not _is_valid_command(): + return + name = aliases[0] + arguments = inspect.signature(original_func).parameters + num_of_arguments = len(arguments) - 1 + num_of_required_arguments = len([v for k, v in arguments.items() if v.default is inspect.Parameter.empty]) - 1 + full_arg_spec = inspect.getfullargspec(original_func) + spec_args = [_arg for _arg in full_arg_spec.args] + arg_names: Tuple[str, ...] = tuple([arg_name for (arg_name, (k, v)) in zip(spec_args, arguments.items()) if arg_name != 'output' and v.default is inspect.Parameter.empty]) + kwarg_parameters_by_name = {arg_name: v.default for (arg_name, (k, v)) in zip(spec_args, arguments.items()) if arg_name != 'output' and v.default is not inspect.Parameter.empty} + + def _invoke_command(*args: str, _session_id: int=0, **kwargs): + output = CommonConsoleCommandOutput(_session_id) + try: + if not is_command_available(relevant_type): + return False + args = cls._parse_arguments(full_arg_spec, tuple(args), arg_names, kwarg_parameters_by_name, kwargs, output) + if args is None: + output('No args specified.') + return False + if len(args) + len(kwargs) > num_of_arguments: + output('Too many arguments were passed in.') + output(f'Use the help command "{help_command_name} {name}" to see what arguments are needed!') + return False + if len(args) < num_of_required_arguments: + num_of_args = len(args) + output(f'Missing some arguments. Specified Args: {num_of_args}, Required Args: {num_of_required_arguments}') + output(f'Use the help command "{help_command_name} {name}" to see what arguments are required!') + return False + kwargs['_account'] = _session_id + kwargs['_connection'] = _session_id + if relevant_type == CommandType.Cheat: + with sims4.telemetry.begin_hook(cheats_writer, TELEMETRY_HOOK_COMMAND) as hook: + hook.write_string(TELEMETRY_FIELD_NAME, name) + hook.write_string(TELEMETRY_FIELD_ARGS, str(args)) + cls.get_log().format_with_message('Invoking the command now.', command_name=name, with_args=args, with_kwargs=kwargs) + return wrapped_func(output, *args, **kwargs) + except Exception as ex: + output(f'ERROR: {ex}') + if (full_arg_spec.varargs is None or full_arg_spec.varkw is None) and any(inspect.isclass(arg_type) and isinstance(arg_type, type) and issubclass(arg_type, CustomParam) for arg_type in full_arg_spec.annotations.values()): + log.format_error_with_message(f'Command "{name}" has CustomParams, consider adding *args and **kwargs to your command params', exception=ex) + else: + log.error(f'Error executing command {name}', exception=ex) + raise ex + + _invoke_command.__name__ = 'invoke_command ({})'.format(name) + # noinspection PyDeprecation + usage = prettify_usage(str.format(inspect.formatargspec(*full_arg_spec))) + description = '' + for alias in aliases: + register(alias, command_restrictions, _invoke_command, description, usage, most_limited_type) + return wrapped_func + + return _named_command + + @classmethod + def _clean_arguments(cls, args: Tuple[str]) -> Tuple[Tuple[str], Dict[str, str]]: + cleaned_args: List[str] = list() + cleaned_kwargs: Dict[str, Any] = dict() + + def _add_cleaned_arg_value(_cleaned_arg) -> None: + if '=' in _cleaned_arg: + split_val = _cleaned_arg.split('=') + cleaned_kwargs[split_val[0]] = split_val[1] + else: + cleaned_args.append(_cleaned_arg) + + cls.get_log().format_with_message('Cleaning args.', args=args) + + waiting_for_match_arg: Union[str, None] = None + for arg_val in args: + if waiting_for_match_arg is not None: + if '=' in arg_val: + # The start of a new argument, thus ending the previous one. + _add_cleaned_arg_value(waiting_for_match_arg) + waiting_for_match_arg = arg_val + elif '"' in arg_val: + # The end value that results in the complete argument. + waiting_for_match_arg += arg_val.replace('"', '') + _add_cleaned_arg_value(waiting_for_match_arg) + waiting_for_match_arg = None + continue + else: + # A continuation of the argument we are waiting for. + waiting_for_match_arg += arg_val + continue + + if '"' in arg_val: + # The start of an argument that has multiple values. + waiting_for_match_arg = arg_val.replace('"', '') + continue + + _add_cleaned_arg_value(arg_val) + + if waiting_for_match_arg is not None: + # If we are still waiting for an argument, we'll just put it at the end. + _add_cleaned_arg_value(waiting_for_match_arg) + cls.get_log().format_with_message('Cleaned up args.', args=args, cleaned_args=cleaned_args, cleaned_kwargs=cleaned_kwargs) + return tuple(cleaned_args), cleaned_kwargs + + @classmethod + def _parse_arguments(cls, full_arg_spec: inspect.FullArgSpec, args: Tuple[str], arg_names: Tuple[str], kwargs_by_name, kwargs: Dict[str, Any], output: Union[CommonConsoleCommandOutput, Output]): + (cleaned_args, cleaned_kwargs) = cls._clean_arguments(args) + + from sims4communitylib.services.commands.common_console_command_parameters import CommonConsoleCommandParameter,\ + CommonOptionalSimInfoConsoleCommandParameter, CommonRequiredGameObjectConsoleCommandParameter, \ + CommonRequiredSimInfoConsoleCommandParameter + arg_length = len(cleaned_args) + new_args = list() + unassigned_cleaned_args = list(cleaned_args) + if len(cleaned_args) > len(arg_names): + # If there are more specified arguments than there are actual arguments, we chop off the extra specified arguments to be used as kwargs instead. + unassigned_cleaned_args = list(cleaned_args[len(arg_names):]) + cleaned_args = list(cleaned_args[:len(arg_names)]) + elif len(cleaned_args) <= len(arg_names): + arg_names = arg_names[:len(cleaned_args)] + unassigned_cleaned_args = list() + for (name, cleaned_arg_value, index) in zip(arg_names, cleaned_args, range(len(arg_names))): + if index >= arg_length: + continue + arg_type = full_arg_spec.annotations.get(name) + arg_values = cleaned_arg_value.split(' ') + if inspect.isclass(arg_type) and ((isinstance(arg_type, type) and issubclass(arg_type, CustomParam)) or arg_type is SimInfo or issubclass(arg_type, SimInfo) or arg_type is GameObject or issubclass(arg_type, GameObject)): + if arg_type is SimInfo or issubclass(arg_type, SimInfo): + arg_value = CommonRequiredSimInfoConsoleCommandParameter.get_value(output, *arg_values) + elif arg_type is GameObject or issubclass(arg_type, GameObject): + arg_value = CommonRequiredGameObjectConsoleCommandParameter.get_value(output, *arg_values) + elif arg_type is CommonConsoleCommandParameter or issubclass(arg_type, CommonConsoleCommandParameter): + arg_value = arg_type.get_value(output, *arg_values) + else: + arg_value = arg_type.get_arg_count_and_value(*arg_values)[1] + + if arg_value is UNSET: + new_args.append(arg_type(*arg_values)) + else: + new_args.append(arg_value) + + elif arg_type is not None: + new_args.append(cls._parse_arg(arg_type, cleaned_arg_value, name, None, output)) + + if full_arg_spec.varargs is not None: + arg_type = full_arg_spec.annotations.get(full_arg_spec.varargs) + if arg_type is not None: + name = full_arg_spec.varargs + for arg_value in unassigned_cleaned_args: + new_args.append(cls._parse_arg(arg_type, arg_value, name, None, output)) + + cls.get_log().format_with_message('Finished parsing arg values', unassigned_cleaned_args=unassigned_cleaned_args, kwargs_by_name=kwargs_by_name) + + for (kwarg_name, kwarg_default_val) in kwargs_by_name.items(): + if kwarg_name not in cleaned_kwargs or cleaned_kwargs[kwarg_name] is None: + if not unassigned_cleaned_args: + if kwarg_default_val is not None: + kwargs[kwarg_name] = kwarg_default_val + continue + kwarg_values = () + else: + kwarg_values = unassigned_cleaned_args.pop(0).split(' ') + else: + kwarg_values = cleaned_kwargs[kwarg_name].split(' ') + + kwarg_type = full_arg_spec.annotations.get(kwarg_name) + if inspect.isclass(kwarg_type) and ((isinstance(kwarg_type, type) and issubclass(kwarg_type, CustomParam)) or kwarg_type is SimInfo or issubclass(kwarg_type, SimInfo) or kwarg_type is GameObject or issubclass(kwarg_type, GameObject)): + if kwarg_type is SimInfo or issubclass(kwarg_type, SimInfo): + kwarg_value = CommonOptionalSimInfoConsoleCommandParameter.get_value(output, *kwarg_values) + elif kwarg_type is GameObject or issubclass(kwarg_type, GameObject): + kwarg_value = CommonRequiredGameObjectConsoleCommandParameter.get_value(output, *kwarg_values) + elif kwarg_type is CommonConsoleCommandParameter or issubclass(kwarg_type, CommonConsoleCommandParameter): + kwarg_value = kwarg_type.get_value(output, *kwarg_values) + else: + (_, kwarg_value) = kwarg_type.get_arg_count_and_value(*kwarg_values) + + if kwarg_value is UNSET: + kwargs[kwarg_name] = kwarg_type(*kwarg_values) + else: + kwargs[kwarg_name] = kwarg_value + + elif kwarg_type is not None: + kwargs[kwarg_name] = cls._parse_arg(kwarg_type, ' '.join(kwarg_values), kwarg_name, kwarg_default_val, output) + cls.get_log().format_with_message('Finished parsing arguments.', args=new_args, kwargs=kwargs) + return new_args + + @classmethod + def _parse_arg(cls, arg_type: Type, arg_value: Any, name: str, default_value: Any, output: Output) -> Any: + from sims4.commands import CustomParam, BOOL_TRUE, BOOL_FALSE + arg_type_name = arg_type.__name__ if hasattr(arg_type, '__name__') else name + if isinstance(arg_value, str): + if arg_type is bool: + lower_arg_value = arg_value.lower() + if lower_arg_value in BOOL_TRUE: + return True + elif lower_arg_value in BOOL_FALSE: + return False + else: + output(f'ERROR: Invalid entry specified for bool {name}: {arg_value} (Expected one of {BOOL_TRUE} for True, or one of {BOOL_FALSE} for False.)') + raise ValueError('invalid literal for boolean parameter') + else: + from sims4communitylib.enums.enumtypes.common_int import CommonInt + from sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags + if inspect.isclass(arg_type) and (arg_type is CommonInt or arg_type is CommonIntFlags or issubclass(arg_type, CommonInt) or issubclass(arg_type, CommonIntFlags)): + if arg_value is not None: + from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + result = CommonResourceUtils.get_enum_by_name(arg_value.upper(), arg_type, default_value=default_value) + if result is None: + # noinspection PyUnresolvedReferences,PyTypeChecker + valid_values = ', '.join([val.name for val in arg_type.values]) + output(f'ERROR: {arg_value} is not a valid {arg_type_name}. Valid {arg_type_name}: {valid_values}') + return None + return result + elif arg_type is float: + # noinspection PyBroadException + try: + return float(arg_value) + except: + output(f'ERROR: Failed to parse float value {arg_value} as {arg_type_name}. Value is not a {arg_type_name}.') + return default_value + elif arg_type is int or arg_value.isnumeric(): + # noinspection PyBroadException + try: + return int(arg_value, base=0) + except: + output(f'ERROR: Failed to parse int value {arg_value} as {arg_type_name}. Value is not an {arg_type_name}.') + return default_value + elif arg_type is str and not arg_value: + return default_value + elif inspect.isclass(arg_type) and ((isinstance(arg_type, type) and issubclass(arg_type, CustomParam)) or arg_type is SimInfo or issubclass(arg_type, SimInfo) or arg_type is GameObject or issubclass(arg_type, GameObject)): + pass + else: + try: + return arg_type(arg_value) + except ValueError as ex: + output(f'ERROR: Failed to parse value {arg_value} as {arg_type_name}: {ex}') + return default_value + except Exception as ex: + output(f'ERROR: Failed to parse custom value {arg_value} as {arg_type_name}: {ex}') + raise ex + return arg_value + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_testing.example_command', + 'Print an example message', + command_aliases=('s4clib_testing.alternativeexamplecommand',), + command_arguments=( + CommonConsoleCommandArgument('thing_to_print', 'Text or Num', 'If specified, this value will be printed to the console.', is_optional=True, default_value='example message'), + ) +) +def _common_testing_do_example_command(output: CommonConsoleCommandOutput, thing_to_print: str = 'example message'): + output(f'Here is what to print: {thing_to_print}') diff --git a/Scripts/s4ap/sims4communitylib/services/commands/common_console_command_output.py b/Scripts/s4ap/sims4communitylib/services/commands/common_console_command_output.py new file mode 100644 index 0000000..6acfc91 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/services/commands/common_console_command_output.py @@ -0,0 +1,60 @@ +""" +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 +""" +from typing import Union + +from objects.game_object import GameObject +from server_commands.argument_helpers import OptionalTargetParam, RequiredTargetParam +from sims.sim_info import SimInfo +from sims4.commands import CheatOutput + + +class CommonConsoleCommandOutput(CheatOutput): + """An output object used when writing text to the console.""" + @property + def connection(self) -> int: + """The connection id to the console.""" + return self._context + + def get_sim(self, target: Union[OptionalTargetParam, RequiredTargetParam]) -> Union[SimInfo, None]: + """get_sim(target) + + Retrieve an instance of a Sim referenced by an OptionalTargetParam or RequiredTargetParam. + + :param target: A target param. + :type target: Union[OptionalTargetParam, RequiredTargetParam] + :return: An instance of the Sim that matches the target or None if not found. + :rtype: Union[Sim, None] + """ + from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + from server_commands.argument_helpers import get_optional_target + sim = get_optional_target(target, self.connection) + sim_info = CommonSimUtils.get_sim_info(sim) + if sim_info is None: + self(f'Failed, Sim {target} did not exist.') + return + return sim_info + + def get_object(self, target: Union[OptionalTargetParam, RequiredTargetParam]) -> Union[GameObject, None]: + """get_object(target) + + Retrieve an instance of a Game Object referenced by an OptionalTargetParam or RequiredTargetParam. + + :param target: A target param. + :type target: Union[OptionalTargetParam, RequiredTargetParam] + :return: An instance of the Sim that matches the target or None if not found. + :rtype: Union[Sim, None] + """ + if isinstance(target, OptionalTargetParam): + from server_commands.argument_helpers import get_optional_target + game_object = get_optional_target(target, self.connection) + else: + game_object: GameObject = target + if game_object is None: + self(f'Failed, Game Object {target} did not exist.') + return + return game_object diff --git a/Scripts/s4ap/sims4communitylib/services/commands/common_console_command_parameters.py b/Scripts/s4ap/sims4communitylib/services/commands/common_console_command_parameters.py new file mode 100644 index 0000000..0801eda --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/services/commands/common_console_command_parameters.py @@ -0,0 +1,151 @@ +""" +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 +""" +from typing import Union, Tuple, Any + +from objects.game_object import GameObject +from sims.sim_info import SimInfo +from sims4.commands import CustomParam +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput + + +class CommonConsoleCommandParameter(CustomParam): + """A custom console command parameter.""" + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_value(cls, output: CommonConsoleCommandOutput, *args: str) -> Any: + return cls.get_arg_count_and_value(output, *args)[1] + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_arg_count_and_value(cls, output: CommonConsoleCommandOutput, *args: str) -> Tuple[int, Any]: + return super().get_arg_count_and_value(*args) + + +class CommonRequiredSimInfoConsoleCommandParameter(CommonConsoleCommandParameter): + """A param that requires a Sim ID, a Sims First Name, or a Sims First and Last Name of a Sim to be specified.""" + + @classmethod + def _get_target_id(cls, arg) -> Union[int, None]: + try: + int_val = int(arg, 0) + except ValueError: + int_val = None + return int_val + + @classmethod + def get_value(cls, output: CommonConsoleCommandOutput, *args: str) -> SimInfo: + """Retrieve the number of arguments taken and the value returned.""" + from singletons import UNSET + from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils + if len(args) == 0: + return UNSET + sim_id = cls._get_target_id(args[0]) + if sim_id: + sim_info_from_id = CommonSimUtils.get_sim_info(sim_id) + if sim_info_from_id is not None: + return sim_info_from_id + else: + output(f'ERROR: Failed to locate Sim with id {args[0]}') + + if len(args) >= 2 and isinstance(args[1], str): + first_name = args[0].lower() + last_name = args[1].lower() + for _sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): + if CommonSimNameUtils.get_first_name(_sim_info).lower() != first_name: + continue + lower_last_name = CommonSimNameUtils.get_last_name(_sim_info).lower() + if lower_last_name == last_name: + return _sim_info + if lower_last_name == '': + return _sim_info + + if len(args) >= 1 and isinstance(args[0], str): + first_name = args[0].lower() + for _sim_info in CommonSimUtils.get_sim_info_for_all_sims_with_first_name_generator(first_name): + return _sim_info + output(f'ERROR: Failed to locate Sim with first name {args[0]}') + return super().get_value(output, *args) + + def __new__(cls, output: CommonConsoleCommandOutput, *args: str) -> Union[SimInfo, None]: + from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils + if len(args) == 0: + return None + int_val = cls._get_target_id(args[0]) + if int_val is not None: + sim_info = CommonSimUtils.get_sim_info(int_val) + if sim_info is not None: + return sim_info + + first_name = args[0] + last_name = '' if len(args) == 1 else args[1] + for sim_info in CommonSimUtils.get_sim_info_for_all_sims_with_first_name_generator(first_name): + if last_name == '': + return sim_info + lower_last_name = CommonSimNameUtils.get_last_name(sim_info).lower() + if lower_last_name == last_name: + return sim_info + return None + + +class CommonOptionalSimInfoConsoleCommandParameter(CommonRequiredSimInfoConsoleCommandParameter): + """A param that optionally requires a Sim ID, a Sims First Name, or a Sims First and Last Name of a Sim to be specified. If not provided, the active SimInfo will be supplied instead.""" + + @classmethod + def get_value(cls, output: CommonConsoleCommandOutput, *args: str) -> SimInfo: + """Retrieve the number of arguments taken and the value returned.""" + from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + sim_info = super().get_value(output, *args) + from singletons import UNSET + if sim_info is UNSET: + return CommonSimUtils.get_active_sim_info() + return sim_info + + def __new__(cls, output: CommonConsoleCommandOutput, *args: str) -> Union[SimInfo, None]: + from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + return super().__new__(cls, output, *args) or CommonSimUtils.get_active_sim_info() + + +class CommonRequiredGameObjectConsoleCommandParameter(CommonConsoleCommandParameter): + """A param that requires the ID of a Game Object to specified.""" + + @classmethod + def _get_target_id(cls, arg: str) -> Union[int, None]: + try: + int_val = int(arg, 0) + except ValueError: + int_val = None + return int_val + + @classmethod + def get_value(cls, output: CommonConsoleCommandOutput, *args: str) -> GameObject: + """Retrieve the number of arguments taken and the value returned.""" + from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils + from singletons import UNSET + if len(args) == 0: + return UNSET + obj_id = cls._get_target_id(args[0]) + if obj_id: + game_object = CommonObjectUtils.get_game_object(obj_id) + if game_object is not None: + return game_object + output(f'Failed to locate Object with id {args[0]}') + return super().get_value(output, *args) + + def __new__(cls, output: CommonConsoleCommandOutput, *args: str) -> Union[GameObject, None]: + from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils + from singletons import UNSET + if len(args) == 0: + return UNSET + int_val = cls._get_target_id(args[0]) + if int_val is not None: + game_object = CommonObjectUtils.get_game_object(int_val) + if game_object is not None: + return game_object + return None diff --git a/Scripts/s4ap/sims4communitylib/services/common_service.py b/Scripts/s4ap/sims4communitylib/services/common_service.py new file mode 100644 index 0000000..410cd63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/services/common_service.py @@ -0,0 +1,52 @@ +""" +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 +""" +from typing import TypeVar, Any + +ServiceType = TypeVar('ServiceType', bound=object) + + +class _Singleton(type): + def __init__(cls, *args, **kwargs) -> None: + super(_Singleton, cls).__init__(*args, **kwargs) + cls._instances = {} + + def __call__(cls, *args, **kwargs) -> 'CommonService': + if cls not in cls._instances: + cls._instances[cls] = super(_Singleton, cls).__call__(*args, **kwargs) + return cls._instances[cls] + + +class CommonService(metaclass=_Singleton): + """An inheritable class that turns a class into a singleton, create an instance by invoking :func:`~get`. + + + :Example usage: + + .. highlight:: python + .. code-block:: python + + class ExampleService(CommonService): + @property + def first_value(self) -> str: + return 'yes' + + # ExampleService.get() returns an instance of ExampleService. + # Calling ExampleService.get() again, will return the same instance. + ExampleService.get().first_value + + """ + @classmethod + def get(cls: Any, *_, **__) -> 'CommonService': + """get() + + Retrieve an instance of the service + + :return: An instance of the service + :rtype: The type of the inheriting class + """ + return cls(*_, **__) diff --git a/Scripts/s4ap/sims4communitylib/services/interactions/__init__.py b/Scripts/s4ap/sims4communitylib/services/interactions/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/services/interactions/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/services/interactions/interaction_registration_service.py b/Scripts/s4ap/sims4communitylib/services/interactions/interaction_registration_service.py new file mode 100644 index 0000000..ad43ecc --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/services/interactions/interaction_registration_service.py @@ -0,0 +1,337 @@ +""" +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 +""" +from typing import Tuple, Iterator, Callable, Any +from interactions.base.interaction import Interaction +from objects.script_object import ScriptObject +from services.terrain_service import TerrainService +from sims.sim import Sim +from sims4communitylib.enums.enumtypes.common_int import CommonInt +from sims4communitylib.logging._has_s4cl_log import _HasS4CLLog +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.common_service import CommonService +from sims4communitylib.utils.common_injection_utils import CommonInjectionUtils +from sims4communitylib.utils.common_type_utils import CommonTypeUtils + + +class CommonInteractionType(CommonInt): + """The type of object/area to add interactions to. + + """ + ON_TERRAIN_LOAD: 'CommonInteractionType' = ... + ON_OCEAN_LOAD: 'CommonInteractionType' = ... + ON_SCRIPT_OBJECT_LOAD: 'CommonInteractionType' = ... + ADD_PRE_ROLL_SUPER_INTERACTION_ON_SCRIPT_OBJECT_LOAD: 'CommonInteractionType' = ... + ADD_TO_SIM_RELATIONSHIP_PANEL_INTERACTIONS: 'CommonInteractionType' = ... + ADD_TO_SIM_PHONE_INTERACTIONS: 'CommonInteractionType' = ... + + +class CommonInteractionHandler: + """An interaction handler that adds interactions to script objects, the terrain, or the ocean. + + """ + def __init__(self) -> None: + self._cached_interactions_to_add = None + + @property + def interactions_to_add(self) -> Tuple[int]: + """A collection of interaction identifiers being added by the interaction handler. + + :return: A collection of interaction identifiers. + :rtype: Tuple[int] + """ + raise NotImplementedError() + + def _interactions_to_add_gen(self) -> Iterator[Interaction]: + if self._cached_interactions_to_add is not None: + yield from self._cached_interactions_to_add + else: + cached_interactions = list() + from sims4communitylib.utils.resources.common_interaction_utils import CommonInteractionUtils + affordance_manager = CommonInteractionUtils.get_instance_manager() + for affordance_id in self.interactions_to_add: + affordance_instance = affordance_manager.get(affordance_id) + if affordance_instance is None: + continue + yield affordance_instance + cached_interactions.append(affordance_instance) + self._cached_interactions_to_add = cached_interactions + + +class CommonScriptObjectInteractionHandler(CommonInteractionHandler): + """An inheritable class that enables registration of interactions to script objects. + + .. note:: Script Objects can be both Sims and Furniture. + + :Example usage: + + .. highlight:: python + .. code-block:: python + + # In this example, the interaction `sim-chat` will be added to any script object that is a `Sim`. + @CommonInteractionRegistry.register_interaction_handler(CommonInteractionType.ON_SCRIPT_OBJECT_LOAD) + class ExampleInteractionHandler(CommonScriptObjectInteractionHandler): + @property + def interactions_to_add(self) -> Tuple[int]: + # Interaction Ids + # These are the decimal identifiers of the interactions from a package file. + from sims4communitylib.enums.interactions_enum import CommonInteractionId + return tuple([int(CommonInteractionId.SIM_CHAT), 2]) + + def should_add(self, script_object: ScriptObject, *args, **kwargs) -> bool: + # Verify it is the object your are expecting. Return True, if it is. + # In this case we are adding these interactions to Sims. + from sims.sim import Sim + return isinstance(script_object, Sim) + + """ + @property + def interactions_to_add(self) -> Tuple[int]: + """A collection of interactions that will be added to the script objects that pass the :func:`~should_add` check. + + :return: A collection of interaction decimal identifiers. + :rtype: Tuple[int] + """ + raise NotImplementedError() + + def should_add(self, script_object: ScriptObject, *args, **kwargs) -> bool: + """should_add(script_object, args, kwargs) + + Determine whether to add the interactions of this handler to the script object. + + :param script_object: An object of type ScriptObject + :param script_object: ScriptObject + :return: True if the interactions specified by `interactions_to_add` should be added to the `script_object`. False if not. + :rtype: bool + """ + raise NotImplementedError() + + +class CommonInteractionRegistry(CommonService, _HasS4CLLog): + """Manage the registration of interactions to script objects, terrain, sims, etc. + + .. note:: Take a look at :class:`.CommonScriptObjectInteractionHandler` for more info and an example of usage. + + """ + + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + return 'common_interaction_registry' + + def __init__(self) -> None: + super().__init__() + self._interaction_handlers = { + CommonInteractionType.ON_TERRAIN_LOAD: list(), + CommonInteractionType.ON_OCEAN_LOAD: list(), + CommonInteractionType.ON_SCRIPT_OBJECT_LOAD: list(), + CommonInteractionType.ADD_PRE_ROLL_SUPER_INTERACTION_ON_SCRIPT_OBJECT_LOAD: list(), + CommonInteractionType.ADD_TO_SIM_RELATIONSHIP_PANEL_INTERACTIONS: list(), + CommonInteractionType.ADD_TO_SIM_PHONE_INTERACTIONS: list() + } + + def on_script_object_add(self, script_object: ScriptObject, *args, **kwargs): + """on_script_object_add(script_object, *args, **kwargs) + + A hook that occurs upon a Script Object being added. + + :param script_object: The script object being added. + :type script_object: ScriptObject + """ + script_object_type = type(script_object) + self.log.format_with_message('Adding interactions for type', script_object_type=script_object_type) + if not hasattr(script_object_type, '_super_affordances'): + self.verbose_log.format_with_message('Object did not have super affordances.', script_object=script_object_type) + return + new_super_affordances = list() + for interaction_handler in self._interaction_handlers[CommonInteractionType.ON_SCRIPT_OBJECT_LOAD]: + if hasattr(interaction_handler, 'should_add') and not interaction_handler.should_add(script_object, *args, **kwargs): + continue + for interaction_instance in interaction_handler._interactions_to_add_gen(): + if interaction_instance in new_super_affordances or interaction_instance in script_object_type._super_affordances: + self.verbose_log.format_with_message('Interaction was already found in the interactions list.', script_object_type=script_object_type, interaction_instance=interaction_instance) + continue + new_super_affordances.append(interaction_instance) + self.log.format_with_message('Adding super affordances to object.', script_object=script_object, script_object_type=script_object_type, new_super_affordances=new_super_affordances) + script_object_type._super_affordances += tuple(new_super_affordances) + new_script_object_super_affordances = list() + for new_super_affordance in new_super_affordances: + if new_super_affordance in script_object._super_affordances: + continue + new_script_object_super_affordances.append(new_super_affordance) + script_object._super_affordances += tuple(new_script_object_super_affordances) + + def register_pre_roll_super_interactions_on_script_object_add(self, script_object: ScriptObject, *args, **kwargs): + """register_pre_roll_super_interactions_on_script_object_add(script_object, *args, **kwargs) + + A hook that occurs upon a Script Object being added. + + :param script_object: The script object being added. + :type script_object: ScriptObject + """ + script_object_type = type(script_object) + self.log.format_with_message('Adding pre roll super interactions for type', script_object_type=script_object_type) + if not hasattr(script_object_type, '_preroll_super_affordances'): + self.verbose_log.format_with_message('Object did not have super affordances.', script_object=script_object_type) + return + new_preroll_super_affordances = list() + for interaction_handler in self._interaction_handlers[CommonInteractionType.ADD_PRE_ROLL_SUPER_INTERACTION_ON_SCRIPT_OBJECT_LOAD]: + if hasattr(interaction_handler, 'should_add') and not interaction_handler.should_add(script_object, *args, **kwargs): + continue + for interaction_instance in interaction_handler._interactions_to_add_gen(): + if interaction_instance in new_preroll_super_affordances or interaction_instance in script_object_type._preroll_super_affordances: + self.verbose_log.format_with_message('Interaction was already found in the interactions list.', script_object_type=script_object_type, interaction_instance=interaction_instance) + continue + new_preroll_super_affordances.append(interaction_instance) + self.log.format_with_message('Adding super affordances to object.', script_object=script_object, script_object_type=script_object_type, new_preroll_super_affordances=new_preroll_super_affordances) + script_object_type._preroll_super_affordances += tuple(new_preroll_super_affordances) + new_script_object_preroll_super_affordances = list() + for new_super_affordance in new_preroll_super_affordances: + if new_super_affordance in script_object._preroll_super_affordances: + continue + new_script_object_preroll_super_affordances.append(new_super_affordance) + script_object._preroll_super_affordances += tuple(new_script_object_preroll_super_affordances) + + def _on_sim_relationship_panel_load(self, sim: Sim, *args, **kwargs): + sim_class = type(sim) + if not hasattr(sim_class, '_relation_panel_affordances'): + return + new_relationship_panel_affordances = list() + for interaction_handler in self._interaction_handlers[CommonInteractionType.ADD_TO_SIM_RELATIONSHIP_PANEL_INTERACTIONS]: + if hasattr(interaction_handler, 'should_add') and not interaction_handler.should_add(sim, *args, **kwargs): + continue + for interaction_instance in interaction_handler._interactions_to_add_gen(): + if interaction_instance in new_relationship_panel_affordances or interaction_instance in sim_class._relation_panel_affordances: + continue + new_relationship_panel_affordances.append(interaction_instance) + sim_class._relation_panel_affordances += tuple(new_relationship_panel_affordances) + + def _on_sim_phone_load(self, sim: Sim, *args, **kwargs): + sim_class = type(sim) + if not hasattr(sim_class, '_phone_affordances'): + return + new_phone_affordances_affordances = list() + for interaction_handler in self._interaction_handlers[CommonInteractionType.ADD_TO_SIM_PHONE_INTERACTIONS]: + if hasattr(interaction_handler, 'should_add') and not interaction_handler.should_add(sim, *args, **kwargs): + continue + for interaction_instance in interaction_handler._interactions_to_add_gen(): + if interaction_instance in new_phone_affordances_affordances or interaction_instance in sim_class._phone_affordances: + continue + new_phone_affordances_affordances.append(interaction_instance) + sim_class._phone_affordances += tuple(new_phone_affordances_affordances) + + def on_terrain_load(self, terrain_service: TerrainService, *_, **__): + """on_terrain_load(terrain_service, *_, **__) + + A hook that occurs upon the Terrain loading + + :param terrain_service: The terrain service + :type terrain_service: TerrainService + """ + new_super_affordances = list() + for interaction_handler in self._interaction_handlers[CommonInteractionType.ON_TERRAIN_LOAD]: + for interaction_instance in interaction_handler._interactions_to_add_gen(): + if interaction_instance in new_super_affordances or interaction_instance in terrain_service.TERRAIN_DEFINITION.cls._super_affordances: + continue + new_super_affordances.append(interaction_instance) + new_terrain_definition_class = terrain_service.TERRAIN_DEFINITION.cls + new_terrain_definition_class._super_affordances += tuple(new_super_affordances) + terrain_service.TERRAIN_DEFINITION.set_class(new_terrain_definition_class) + + def on_ocean_load(self, terrain_service: TerrainService, *_, **__): + """on_ocean_load(terrain_service, *_, **__) + + A hook that occurs upon the Ocean loading + + :param terrain_service: The terrain service + :type terrain_service: TerrainService + """ + new_super_affordances = list() + for interaction_handler in self._interaction_handlers[CommonInteractionType.ON_OCEAN_LOAD]: + for interaction_instance in interaction_handler._interactions_to_add_gen(): + if interaction_instance in new_super_affordances or interaction_instance in terrain_service.OCEAN_DEFINITION.cls._super_affordances: + continue + new_super_affordances.append(interaction_instance) + new_ocean_definition_class = terrain_service.OCEAN_DEFINITION.cls + new_ocean_definition_class._super_affordances += tuple(new_super_affordances) + terrain_service.OCEAN_DEFINITION.set_class(new_ocean_definition_class) + + def register_handler(self, handler: CommonInteractionHandler, interaction_type: CommonInteractionType): + """register_handler(handler, interaction_type) + + Manually register an interaction handler. + + .. note:: It is recommended to decorate classes with :func:`~register_interaction_handler`\ + instead of manually registering interaction handlers. + + :param handler: The interaction handler being registered. + :type handler: CommonInteractionHandler + :param interaction_type: The type of place the interactions will show up. + :type interaction_type: CommonInteractionType + """ + self._interaction_handlers[interaction_type].append(handler) + + @staticmethod + def register_interaction_handler(interaction_type: CommonInteractionType) -> Callable[..., Any]: + """register_interaction_handler(interaction_type) + + Decorate a class to register that class as an interaction handler. + + .. note:: Take a look at :class:`.CommonScriptObjectInteractionHandler` for more info and example usage. + + :param interaction_type: The type of place the interactions will show up. + :type interaction_type: CommonInteractionType + :return: A wrapped function. + :rtype: Callable[..., Any] + """ + def _wrapper(interaction_handler) -> CommonInteractionHandler: + CommonInteractionRegistry().register_handler(interaction_handler(), interaction_type) + return interaction_handler + return _wrapper + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), ScriptObject, ScriptObject.on_add.__name__, handle_exceptions=False) +def _common_script_object_on_add(original, self, *args, **kwargs) -> Any: + result = original(self, *args, **kwargs) + CommonInteractionRegistry().on_script_object_add(self, *args, **kwargs) + CommonInteractionRegistry().register_pre_roll_super_interactions_on_script_object_add(self, *args, **kwargs) + if CommonTypeUtils.is_sim_instance(self): + CommonInteractionRegistry()._on_sim_relationship_panel_load(self, *args, **kwargs) + CommonInteractionRegistry()._on_sim_phone_load(self, *args, **kwargs) + return result + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), TerrainService, TerrainService.start.__name__, handle_exceptions=False) +def _common_terrain_service_start(original, self, *args, **kwargs) -> Any: + result = original(self, *args, **kwargs) + CommonInteractionRegistry().on_terrain_load(self, *args, **kwargs) + return result + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), TerrainService, TerrainService.on_zone_load.__name__, handle_exceptions=False) +def _common_terrain_service_on_zone_load(original, self, *args, **kwargs) -> Any: + result = original(self, *args, **kwargs) + CommonInteractionRegistry().on_ocean_load(self, *args, **kwargs) + return result + + +# noinspection PyMissingOrEmptyDocstring +# @CommonInteractionRegistry.register_interaction_handler(CommonInteractionType.ON_SCRIPT_OBJECT_LOAD) +class ExampleInteractionHandler(CommonScriptObjectInteractionHandler): + @property + def interactions_to_add(self) -> Tuple[int]: + # Interaction Ids + # These are the decimal identifiers of the interactions from a package file. + from sims4communitylib.enums.interactions_enum import CommonInteractionId + # noinspection PyTypeChecker + return tuple([int(CommonInteractionId.SIM_CHAT), 2]) + + def should_add(self, script_object: ScriptObject, *args, **kwargs) -> bool: + # Verify it is the object your are expecting. Return True, if it is. + # In this case we are adding these interactions to Sims. + from sims.sim import Sim + return isinstance(script_object, Sim) diff --git a/Scripts/s4ap/sims4communitylib/services/resources/__init__.py b/Scripts/s4ap/sims4communitylib/services/resources/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/services/resources/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/services/resources/common_instance_manager_modification_registry.py b/Scripts/s4ap/sims4communitylib/services/resources/common_instance_manager_modification_registry.py new file mode 100644 index 0000000..78a1c8e --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/services/resources/common_instance_manager_modification_registry.py @@ -0,0 +1,75 @@ +""" +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 +""" +from typing import Callable, Any, Type, List + +from sims4.tuning.instance_manager import InstanceManager +from sims4communitylib.logging._has_s4cl_log import _HasS4CLLog +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.common_service import CommonService +from sims4communitylib.services.resources.modification_handlers.common_instance_manager_modification_handler import \ + CommonInstanceManagerModificationHandler +from sims4communitylib.utils.common_injection_utils import CommonInjectionUtils + + +class CommonInstanceManagerModificationRegistry(CommonService, _HasS4CLLog): + """A registry containing handlers that manipulate and modify instance managers. + + """ + + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + return 'common_instance_manager_modification_registry' + + def __init__(self) -> None: + super().__init__() + self._handlers: List[CommonInstanceManagerModificationHandler] = list() + + def _try_modify(self, instance_manager: InstanceManager): + for handler in self._handlers: + try: + if handler.should_apply_modifications(instance_manager): + handler.apply_modifications(instance_manager) + except Exception as ex: + self.log.format_error_with_message('An error occurred while applying modification.', handler=handler, exception=ex) + + def register_handler(self, handler: CommonInstanceManagerModificationHandler): + """register_handler(handler) + + Manually register a handler. + + .. note:: It is recommended to decorate classes with :func:`~register_modification_handler`\ + instead of manually registering handlers. + + :param handler: The handler being registered. + :type handler: CommonInstanceManagerModificationHandler + """ + if handler in self._handlers: + return + self._handlers.append(handler) + + @staticmethod + def register_modification_handler() -> Callable[..., Any]: + """register_modification_handler() + + Decorate a class with this to register that class as a modification handler. + """ + def _wrapper(_handler: Type[CommonInstanceManagerModificationHandler]) -> Type[CommonInstanceManagerModificationHandler]: + if not issubclass(_handler, CommonInstanceManagerModificationHandler): + raise AssertionError( + f'{_handler} is not an instance of {CommonInstanceManagerModificationHandler.__name__}') + CommonInstanceManagerModificationRegistry().register_handler(_handler()) + return _handler + return _wrapper + + +@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), InstanceManager, InstanceManager.load_data_into_class_instances.__name__, handle_exceptions=False) +def _common_modify_instance_manager_on_load_data(original, self: InstanceManager, *_, **__) -> Any: + result = original(self, *_, **__) + CommonInstanceManagerModificationRegistry()._try_modify(self) + return result diff --git a/Scripts/s4ap/sims4communitylib/services/resources/common_posture_constraint_service.py b/Scripts/s4ap/sims4communitylib/services/resources/common_posture_constraint_service.py new file mode 100644 index 0000000..96dbfdf --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/services/resources/common_posture_constraint_service.py @@ -0,0 +1,80 @@ +""" +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 +""" +from typing import Iterator, Union + +from interactions.constraints import Constraint, _ConstraintSet, Nowhere +from sims4communitylib.services.common_service import CommonService + + +class CommonPostureConstraintService(CommonService): + """CommonPostureConstraintService() + + Utilities for providing and manipulating posture constraints of Sims. + """ + + def __init__(self) -> None: + self._stand_or_swim = None + + @property + def stand(self) -> Constraint: + """ A posture constraint for a Sim to stand at a target. + + :return: An instance of a Constraint. + :rtype: Constraint + """ + from animation.posture_manifest_constants import STAND_AT_NONE_CONSTRAINT + return STAND_AT_NONE_CONSTRAINT + + @property + def stand_at_none(self) -> Constraint: + """ A posture constraint for a Sim to stand at no target. + + :return: An instance of a Constraint. + :rtype: Constraint + """ + from animation.posture_manifest_constants import STAND_AT_NONE_CONSTRAINT + return STAND_AT_NONE_CONSTRAINT + + @property + def swim_at_none(self) -> Constraint: + """ A posture constraint for a Sim to swim at no target. + + :return: An instance of a Constraint. + :rtype: Constraint + """ + from animation.posture_manifest_constants import SWIM_AT_NONE_CONSTRAINT + return SWIM_AT_NONE_CONSTRAINT + + @property + def stand_or_swim_at_none(self) -> Constraint: + """ A posture constraint for a Sim to stand at a target or to swim at no target. + + :return: An instance of a Constraint. + :rtype: Constraint + """ + if self._stand_or_swim is None: + self._stand_or_swim = CommonPostureConstraintService.combine_constraints((self.stand_at_none, self.swim_at_none), debug_name='Stand-Or-Swim@None') + return self._stand_or_swim + + @staticmethod + def combine_constraints(constraints: Iterator[Constraint], fallback_constraints: Iterator[Constraint]=(), debug_name: str='Combined') -> Union[_ConstraintSet, Constraint, Nowhere]: + """combine_constraints(constraints, fallback_constraints=(), debug_name='Combined') + + Attempt to combine similar constraints into a constraint set. + + :param constraints: A collection of Constraints. + :type constraints: Iterator[Constraint] + :param fallback_constraints: A collection of Constraints to choose from as a fallback when the primary constraints fail to combine. Default is an empty collection. + :type fallback_constraints: Iterator[Constraint], optional + :param debug_name: The name of the constraint set being created. Default is 'Combined'. + :type debug_name: str, optional + :return: A constraint set containing the specified constraints, a Constraint chosen from one of the specified fallback constraints, or Nowhere when everything else fails. + :rtype: Union[_ConstraintSet, Constraint, Nowhere] + """ + from interactions.constraints import create_constraint_set + return create_constraint_set(tuple(constraints), invalid_constraints=tuple(fallback_constraints), debug_name=debug_name) diff --git a/Scripts/s4ap/sims4communitylib/services/resources/modification_handlers/__init__.py b/Scripts/s4ap/sims4communitylib/services/resources/modification_handlers/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/services/resources/modification_handlers/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/services/resources/modification_handlers/common_add_interactions_to_affordance_lists_handler.py b/Scripts/s4ap/sims4communitylib/services/resources/modification_handlers/common_add_interactions_to_affordance_lists_handler.py new file mode 100644 index 0000000..2de05eb --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/services/resources/modification_handlers/common_add_interactions_to_affordance_lists_handler.py @@ -0,0 +1,54 @@ +""" +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 +""" +from sims4.resources import Types +from sims4.tuning.instance_manager import InstanceManager +from typing import Tuple + +from sims4communitylib.classes.mixins.common_affordance_lists_mixin import \ + CommonAffordanceListsMixin +from sims4communitylib.classes.mixins.common_interactions_mixin import \ + CommonInteractionsMixin +from sims4communitylib.services.resources.modification_handlers.common_instance_manager_modification_handler import \ + CommonInstanceManagerModificationHandler + + +class CommonAddInteractionsToAffordanceListsModificationHandler(CommonInstanceManagerModificationHandler, CommonInteractionsMixin, CommonAffordanceListsMixin): + """A handler that will add interactions to affordance lists.""" + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def instance_manager_type(cls) -> Types: + return Types.SNIPPET + + # noinspection PyMissingOrEmptyDocstring + @property + def interaction_ids(self) -> Tuple[int]: + raise NotImplementedError() + + # noinspection PyMissingOrEmptyDocstring + @property + def affordance_list_ids(self) -> Tuple[int]: + raise NotImplementedError() + + def __init__(self, *_, **__) -> None: + super().__init__(*_, **__) + CommonInteractionsMixin.__init__(self) + CommonAffordanceListsMixin.__init__(self) + + # noinspection PyMissingOrEmptyDocstring + def apply_modifications(self, instance_manager: InstanceManager): + instances = self._load_instances_from_manager(instance_manager, self.affordance_list_ids) + for instance in instances: + new_interactions = list() + for interaction_instance_to_add in self._interaction_instances_gen(): + if interaction_instance_to_add in instance.value: + continue + new_interactions.append(interaction_instance_to_add) + if not new_interactions: + continue + instance.value += tuple(new_interactions) diff --git a/Scripts/s4ap/sims4communitylib/services/resources/modification_handlers/common_instance_manager_modification_handler.py b/Scripts/s4ap/sims4communitylib/services/resources/modification_handlers/common_instance_manager_modification_handler.py new file mode 100644 index 0000000..fd1b570 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/services/resources/modification_handlers/common_instance_manager_modification_handler.py @@ -0,0 +1,50 @@ +""" +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 +""" +from typing import Tuple, Any + +from sims4.resources import Types +from sims4.tuning.instance_manager import InstanceManager + + +class CommonInstanceManagerModificationHandler: + """A modification handler that will modify an instance manager. + + """ + @classmethod + def instance_manager_type(cls) -> Types: + """The type of instances this handler modifies.""" + raise NotImplementedError() + + def should_apply_modifications(self, instance_manager: InstanceManager) -> bool: + """should_apply_modifications(instance_manager) + + Whether or not this handler should apply its modifications to an Instance Manager. + + :param instance_manager: The instance manager to check. + :type instance_manager: InstanceManager + :return: True, if this handler should apply its modifications. False, if not. + :rtype: bool + """ + return self.__class__.instance_manager_type() == instance_manager.TYPE + + def apply_modifications(self, instance_manager: InstanceManager): + """apply_modifications(instance_manager) + + Apply modifications to an Instance Manager. + + :param instance_manager: The instance manager to modify. + :type instance_manager: InstanceManager + """ + raise NotImplementedError() + + def _load_instances_from_manager(self, instance_manager: InstanceManager, instance_ids: Tuple[int]) -> Tuple[Any]: + instances = list() + for (key, cls) in tuple(instance_manager._tuned_classes.items()): + if key.instance in instance_ids: + instances.append(cls) + return tuple(instances) diff --git a/Scripts/s4ap/sims4communitylib/services/sim/__init__.py b/Scripts/s4ap/sims4communitylib/services/sim/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/services/sim/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/services/sim/cas/__init__.py b/Scripts/s4ap/sims4communitylib/services/sim/cas/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/services/sim/cas/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/services/sim/cas/common_sim_outfit_io.py b/Scripts/s4ap/sims4communitylib/services/sim/cas/common_sim_outfit_io.py new file mode 100644 index 0000000..4fb9db8 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/services/sim/cas/common_sim_outfit_io.py @@ -0,0 +1,396 @@ +""" +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 +""" +from typing import Tuple, FrozenSet, Dict, List, Union + +from cas.cas import OutfitData +from protocolbuffers import S4Common_pb2, Outfits_pb2 +from sims.outfits.outfit_enums import OutfitCategory, BodyType +from sims.sim_info import SimInfo +from sims.sim_info_base_wrapper import SimInfoBaseWrapper +from sims4communitylib.enums.common_body_slot import CommonBodySlot +from sims4communitylib.logging.has_log import HasLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils +from sims4communitylib.utils.common_resource_utils import CommonResourceUtils +from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils + + +class CommonSimOutfitIO(HasLog): + """CommonSimOutfitIO(sim_info, outfit_category_and_index=None, override_outfit_parts=None) + + Make changes to an outfit of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: Union[SimInfo, SimInfoBaseWrapper] + :param outfit_category_and_index: The OutfitCategory and Index of the Outfit being written to or read from. Default is the current outfit of the Sim. + :type outfit_category_and_index: Tuple[OutfitCategory, int], optional + :param initial_outfit_parts: A library of body types and cas parts to use in place of the normal parts of their outfit. If set to None, OutfitParts will be loaded from the specified OutfitCategory and Index. Default is None. + :type initial_outfit_parts: Dict[BodyType, int], optional + :param mod_identity: The identity of the mod making changes. Default is None. Optional, but highly recommended! + :type mod_identity: CommonModIdentity, optional + """ + # noinspection PyMissingOrEmptyDocstring + @property + def mod_identity(self) -> CommonModIdentity: + return self._mod_identity + + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + return 'common_sim_outfit_io' + + def __init__(self, sim_info: Union[SimInfo, SimInfoBaseWrapper], outfit_category_and_index: Tuple[OutfitCategory, int]=None, initial_outfit_parts: Dict[BodyType, int]=None, mod_identity: CommonModIdentity=None): + super().__init__() + self._mod_identity = mod_identity + self.log.enable_logging_extra_sim_details() + self._sim_info = sim_info + self._current_outfit_category_and_index = CommonOutfitUtils.get_current_outfit(sim_info) + self._outfit_category_and_index: Tuple[OutfitCategory, int] = (CommonOutfitUtils.convert_value_to_outfit_category(outfit_category_and_index[0]), outfit_category_and_index[1]) if outfit_category_and_index is not None else self._current_outfit_category_and_index + self._outfit_data: OutfitData = None + self._outfit_parts: Dict[BodyType, int] = None + self._original_outfit_data: FrozenSet[int] = None + self._outfit_body_types: List[Union[BodyType, int]] = list() + self._outfit_part_ids: List[int] = list() + if not CommonOutfitUtils.has_outfit(self._sim_info, self._outfit_category_and_index): + self.log.format_warn_with_message('Sim did not have the specified outfit category and index!', sim=self._sim_info, outfit_category_and_index=self._outfit_category_and_index) + self._load(initial_outfit_parts=initial_outfit_parts) + + @property + def sim_info(self) -> Union[SimInfo, SimInfoBaseWrapper]: + """ The Sim to apply Outfit changes to. + + :return: An instance of a Sim. + :rtype: Union[SimInfo, SimInfoBaseWrapper] + """ + return self._sim_info + + @property + def outfit_category_and_index(self) -> Tuple[OutfitCategory, int]: + """ The OutfitCategory and Index of the Outfit being written to. + + :return: The OutfitCategory and Index of the Outfit being written to. + :rtype: Tuple[OutfitCategory, int] + """ + return self._outfit_category_and_index + + @property + def outfit_parts(self) -> Dict[Union[BodyType, int], int]: + """A library of Body Types to CAS Part Ids""" + return self._to_outfit_dictionary(self.body_types, self.cas_part_ids) + + @property + def cas_part_ids(self) -> Tuple[int]: + """The decimal identifiers of CAS Parts attached to the outfit. + + :return: A collection of decimal identifiers of CAS Parts attached to the outfit. + :rtype: Tuple[int] + """ + return tuple(self._outfit_part_ids) + + @property + def body_types(self) -> Tuple[Union[BodyType, int]]: + """The body types attached to the outfit. + + :return: A collection of body types attached to the outfit. + :rtype: Tuple[Union[BodyType, int]] + """ + return tuple(self._outfit_body_types) + + def is_body_type_attached(self, body_type: Union[BodyType, int]) -> bool: + """is_body_type_attached(body_type) + + Determine if the specified BodyType is attached to the outfit. + + :param body_type: The BodyType to look for. + :type body_type: Union[BodyType, int] + :return: True, if the specified BodyType is attached to the outfit. False, if not. + :rtype: bool + """ + return self.is_any_body_type_attached((body_type,)) + + def is_any_body_type_attached(self, body_types: Tuple[Union[BodyType, int]]) -> bool: + """is_any_body_type_attached(body_types) + + Determine if any of the specified BodyTypes are attached to the outfit. + + :param body_types: The BodyType to look for. + :type body_types: Union[BodyType, int] + :return: True, if any of the specified BodyTypes are attached to the outfit. False, if not. + :rtype: bool + """ + for body_type in body_types: + for outfit_body_type in self._outfit_body_types: + if int(body_type) == int(outfit_body_type): + return True + return False + + def is_cas_part_attached(self, cas_part_id: int) -> bool: + """is_cas_part_attached(cas_part_id) + + Determine if the specified CAS Part is attached to the outfit. + + :param cas_part_id: The decimal identifier of a CAS Part. + :type cas_part_id: int + :return: True, if the specified CAS Part is attached to the outfit. False, if not. + :rtype: bool + """ + return self.is_any_cas_part_attached((cas_part_id,)) + + def is_any_cas_part_attached(self, cas_part_ids: Tuple[int]) -> bool: + """is_any_cas_part_attached(cas_part_ids) + + Determine if any of the specified CAS Parts are attached to the outfit. + + :param cas_part_ids: A collection of decimal identifiers of CAS Parts. + :type cas_part_ids: Tuple[int] + :return: True, if any of the specified CAS Parts are attached to the outfit. False, if not. + :rtype: bool + """ + return any((int(cas_part_id) in self._outfit_part_ids for cas_part_id in cas_part_ids)) + + def get_body_type_cas_part_is_attached_to(self, cas_part_id: int) -> int: + """get_body_type_cas_part_is_attached_to(cas_part_id) + + Retrieve the Body Type the specified CAS Part is attached to. + + :param cas_part_id: The decimal identifier of a CAS Part. + :type cas_part_id: int + :return: The Body Type the specified CAS Part was located at or -1 if the Outfit does not have the CAS Part or the CAS Part is empty. + :rtype: Union[int, BodyType] + """ + for (_body_type, _cas_part_id) in zip(self.body_types, self.cas_part_ids): + if int(_cas_part_id) == int(cas_part_id): + return _body_type + self.log.format_with_message('CAS Part not found.', cas_part_id=cas_part_id) + return -1 + + def get_cas_part_at_body_type(self, body_type: Union[CommonBodySlot, BodyType, int]) -> int: + """get_cas_part_at_body_type(body_type) + + Retrieve the CAS Part located at the specified body type. + + :param body_type: The BodyType to look at. + :type body_type: Union[CommonBodySlot, BodyType, int] + :return: The decimal identifier of the CAS Part located at the specified body part or -1 if the Outfit does not have the body type or the body type is empty. + :rtype: int + """ + for (_body_type, _cas_part_id) in zip(self.body_types, self.cas_part_ids): + if int(_body_type) == int(body_type): + return _cas_part_id + self.log.format_with_message('Body type not found.', body_type=body_type) + return -1 + + def attach_cas_part(self, cas_part_id: int, body_type: Union[BodyType, int]=BodyType.NONE) -> bool: + """attach_cas_part(cas_part_id, body_type=BodyType.NONE) + + Attach a CAS Part to the specified body type. + + ..note:: This will override the CAS Part located at the body type, if there is one. + + :param cas_part_id: The decimal identifier of a CAS Part. + :type cas_part_id: int + :param body_type: The BodyType the CAS Part will be attached to. Default is the BodyType of the CAS Part + :type body_type: Union[BodyType, int], optional + :return: True, if the CAS Part was attached successfully. False, if not. + :rtype: bool + """ + from sims4communitylib.utils.cas.common_cas_utils import CommonCASUtils + if cas_part_id == -1 or cas_part_id is None: + self.log.format_error_with_message('Attempted to attach a negative or None CAS Part to the outfit of a Sim!', sim=self.sim_info, body_type=body_type, cas_part_id=cas_part_id, outfit_category_and_index=self._outfit_category_and_index) + return False + if body_type == BodyType.NONE: + body_type = CommonCASUtils.get_body_type_of_cas_part(cas_part_id) + self.log.format_with_message('Attempting to attach cas part to body type.', cas_part=cas_part_id, body_type=body_type) + if self.is_body_type_attached(body_type): + self.detach_body_type(body_type) + self.log.format_with_message('Attaching CAS Part.', cas_part=cas_part_id, body_type=body_type) + self._outfit_body_types.append(body_type) + self._outfit_part_ids.append(cas_part_id) + self.log.format_with_message('Finished adding cas part to body type.', cas_part=cas_part_id, body_type=body_type) + return True + + def detach_cas_part(self, cas_part_id: int) -> bool: + """detach_cas_part(cas_part_id) + + Detach a CAS Part from all body types of the Outfit. + + :param cas_part_id: The decimal identifier of a CAS Part. + :type cas_part_id: int + :return: True, if the CAS Part was erased from all body types successfully. False, if not. + :rtype: bool + """ + self.log.format_with_message('Attempting to detach cas part', cas_part=cas_part_id, current_body_types=self._outfit_body_types, current_cas_parts=self._outfit_body_types) + new_body_types = list() + new_part_ids = list() + for (_body_type, _cas_part_id) in zip(self.body_types, self.cas_part_ids): + if int(_cas_part_id) == int(cas_part_id): + self.log.format_with_message('Detaching CAS Part.', cas_part=cas_part_id) + continue + self.log.format_with_message('Keeping CAS Part.', cas_part=cas_part_id, other_cas_part=_cas_part_id) + new_body_types.append(_body_type) + new_part_ids.append(_cas_part_id) + self._outfit_body_types = new_body_types + self._outfit_part_ids = new_part_ids + return True + + def detach_body_type(self, body_type: Union[BodyType, int]) -> bool: + """detach_body_type(body_type) + + Detach the BodyType including the CAS Part attached to it from the outfit. + + :param body_type: The BodyType being detached. + :type body_type: Union[BodyType, int] + :return: True, if the Body Type was detached from the outfit successfully. False, if not. + :rtype: bool + """ + self.log.format_with_message('Attempting to detach body type', body_type=body_type) + self.log.format(current_body_types=self._outfit_body_types) + new_body_types = list() + new_part_ids = list() + for (_body_type, _cas_part_id) in zip(self.body_types, self.cas_part_ids): + if int(_body_type) == int(body_type): + self.log.format_with_message('Detaching body type', body_type=body_type) + continue + self.log.format_with_message('Keeping body type.', body_type=body_type, other_body_type=_body_type) + new_body_types.append(_body_type) + new_part_ids.append(_cas_part_id) + self._outfit_body_types = new_body_types + self._outfit_part_ids = new_part_ids + return True + + def apply( + self, + resend_outfits_after_apply: bool=True, + change_sim_to_outfit_after_apply: bool=True, + apply_to_all_outfits_in_same_category: bool=False, + apply_to_outfit_category_and_index: Tuple[OutfitCategory, int]=None + ) -> bool: + """apply(resend_outfits_after_apply=True, change_sim_to_outfit_after_apply=True, apply_to_all_outfits_in_same_category=False, apply_to_outfit_category_and_index=None) + + Apply all changes made to the Outfit. + + :param resend_outfits_after_apply: If set to True, the outfits of the Sim will be re-sent after changes have been applied. Default is True. + :type resend_outfits_after_apply: bool, optional + :param change_sim_to_outfit_after_apply: If set to True, the Sim will change to the outfit after the outfit is updated. Default is True. + :type change_sim_to_outfit_after_apply: bool, optional + :param apply_to_all_outfits_in_same_category: If set to True, changes will be applied to all Outfits in the same category. If set to False, changes will only be applied to the outfit provided at initialization. Default is False. + :type apply_to_all_outfits_in_same_category: bool, optional + :param apply_to_outfit_category_and_index: The OutfitCategory and Index to apply changes to. If set to None, it will be the OutfitCategory and Index provided at initialization. Default is None. + :type apply_to_outfit_category_and_index: Tuple[OutfitCategory, int], optional + :return: True, if changes were applied successfully. False, if not. + :rtype: bool + """ + sim_name = CommonSimNameUtils.get_full_name(self.sim_info) + self.log.format_with_message( + 'Applying changes to outfit', + sim=sim_name, + resend_outfits=resend_outfits_after_apply, + change_to_outfit=change_sim_to_outfit_after_apply, + initial_outfit_category_and_index=self.outfit_category_and_index, + apply_to_all_outfits_in_same_category=apply_to_all_outfits_in_same_category, + apply_to_outfit_category_and_index=apply_to_outfit_category_and_index + ) + apply_to_outfit_category_and_index = apply_to_outfit_category_and_index or self.outfit_category_and_index + outfit_to_apply_to_data = CommonOutfitUtils.get_outfit_data(self.sim_info, outfit_category_and_index=apply_to_outfit_category_and_index) + outfit_to_apply_to_parts = CommonOutfitUtils.get_outfit_parts(self.sim_info, outfit_category_and_index=apply_to_outfit_category_and_index) + outfit_to_apply_to_original_data: FrozenSet[int] = frozenset(outfit_to_apply_to_parts.items()) + saved_outfits = self.sim_info.save_outfits() + self.log.format_with_message('Applying Outfit IO Changes to outfits', sim=self.sim_info, outfits=saved_outfits.outfits, outfit_part_ids=self._outfit_part_ids, outfit_body_types=self._outfit_body_types) + for saved_outfit in saved_outfits.outfits: + if int(saved_outfit.category) != int(apply_to_outfit_category_and_index[0]): + self.log.format_with_message('Ignoring saved outfit due to wrong category.', sim=self.sim_info, outfit_category=saved_outfit.category, expected_category=apply_to_outfit_category_and_index[0]) + continue + + if not apply_to_all_outfits_in_same_category: + self.log.format_with_message('Changes are not being applied to all outfits in the same category.', sim=self.sim_info, outfit_category_and_index=apply_to_outfit_category_and_index) + # noinspection PyUnresolvedReferences + saved_outfit_data = self._to_outfit_data(saved_outfit.body_types_list.body_types, saved_outfit.parts.ids) + self.log.format_with_message('Checking if sub outfit data matches', saved_outfit_data=saved_outfit_data) + if int(saved_outfit.outfit_id) != int(outfit_to_apply_to_data.outfit_id) or saved_outfit_data != outfit_to_apply_to_original_data: + self.log.format_with_message('Sub outfit data did not match!', saved_outfit_id=saved_outfit.outfit_id, self_outfit_id=outfit_to_apply_to_data.outfit_id, saved_outfit_data=saved_outfit_data, original_outfit_data=outfit_to_apply_to_original_data) + continue + else: + self.log.format_with_message('Sub outfit matches.', saved_outfit_id=saved_outfit.outfit_id, self_outfit_id=outfit_to_apply_to_data.outfit_id, saved_outfit_data=saved_outfit_data, original_outfit_data=outfit_to_apply_to_original_data) + + saved_outfit.parts = S4Common_pb2.IdList() + # noinspection PyUnresolvedReferences + saved_outfit.parts.ids.extend(self._outfit_part_ids) + saved_outfit.body_types_list = Outfits_pb2.BodyTypesList() + # noinspection PyUnresolvedReferences + saved_outfit.body_types_list.body_types.extend([int(body_type) for body_type in self._outfit_body_types]) + # noinspection PyUnresolvedReferences + saved_outfit_data = self._to_outfit_data(saved_outfit.body_types_list.body_types, saved_outfit.parts.ids) + self.log.format_with_message('Changes made.', saved_outfit_data=saved_outfit_data) + if not apply_to_all_outfits_in_same_category: + self.log.format_with_message('Skipping the other outfit indexes, since we do not want to apply to all outfits in the same category.', sim=self.sim_info, outfit_category_and_index_applied_to=apply_to_outfit_category_and_index) + break + + self.sim_info._base.outfits = saved_outfits.SerializeToString() + if change_sim_to_outfit_after_apply: + self.sim_info._base.outfit_type_and_index = apply_to_outfit_category_and_index + else: + self.sim_info._base.outfit_type_and_index = self._current_outfit_category_and_index + self.log.format_with_message('Finished applying outfit changes.', sim=self.sim_info, outfit_category_and_index_applid_to=apply_to_outfit_category_and_index) + if resend_outfits_after_apply: + CommonOutfitUtils.refresh_outfit(self.sim_info, outfit_category_and_index=self._current_outfit_category_and_index) + return CommonOutfitUtils.resend_outfits(self.sim_info) + return True + + def _load(self, initial_outfit_parts: Dict[BodyType, int]=None) -> bool: + target_sim_name = CommonSimNameUtils.get_full_name(self.sim_info) + self._outfit_parts = CommonOutfitUtils.get_outfit_parts(self.sim_info, outfit_category_and_index=self._outfit_category_and_index) or dict() + self._original_outfit_data: FrozenSet[int] = frozenset(self._outfit_parts.items()) + if initial_outfit_parts is not None: + cleaned_initial_outfit_parts = self._clean_outfit_parts(initial_outfit_parts) + + self._outfit_body_types = list(cleaned_initial_outfit_parts.keys()) + self._outfit_part_ids = list(initial_outfit_parts.values()) + else: + if self._outfit_parts is None: + self.log.format_error_with_message('No outfit parts for available Sim \'{}\' and Outfit Category and Index {}'.format(target_sim_name, self._outfit_category_and_index), initial_outfit_parts=initial_outfit_parts, throw=True) + return False + self._outfit_parts = self._clean_outfit_parts(self._outfit_parts) + + self._outfit_body_types: List[Union[BodyType, int]] = list(self._outfit_parts.keys()) + self._outfit_part_ids: List[int] = list(self._outfit_parts.values()) + if len(self._outfit_body_types) != len(self._outfit_part_ids): + self.log.format_error_with_message('\'{}\': The number of cas parts did not match the number of body types for Outfit Category and Index {}.'.format(target_sim_name, self._outfit_category_and_index), outfit_category_and_index=self.outfit_category_and_index, outfit_parts=self._outfit_parts, throw=True) + return False + return True + + def _clean_outfit_parts(self, outfit_parts: Dict[Union[BodyType, int], int]) -> Dict[Union[BodyType, int], int]: + cleaned_outfit_parts = dict() + for (body_type, cas_part_id) in outfit_parts.items(): + if (not isinstance(body_type, int) and not isinstance(body_type, BodyType)) or not isinstance(cas_part_id, int): + self.log.format_error_with_message('outfit_body_parts contains non-integer variables body_type: {} cas_part_id: {}.'.format(body_type, cas_part_id), sim=self.sim_info, body_type=body_type, cas_part_id=cas_part_id, outfit_parts=outfit_parts) + continue + if cas_part_id == -1 or cas_part_id is None: + self.log.format_with_message('Ignoring body_type with negative or None cas_part_id.', sim=self.sim_info, outfit_category_and_index=self.outfit_category_and_index, body_type=body_type, cas_part_id=cas_part_id) + continue + # noinspection PyUnresolvedReferences + if isinstance(body_type, int) and body_type in BodyType.value_to_name: + # noinspection PyUnresolvedReferences + new_body_type = CommonResourceUtils.get_enum_by_name(BodyType.value_to_name[body_type], BodyType, default_value=-1) + if new_body_type == -1: + new_body_type = body_type + else: + new_body_type = body_type + cleaned_outfit_parts[new_body_type] = cas_part_id + return cleaned_outfit_parts + + def _to_outfit_dictionary(self, body_types: Tuple[Union[BodyType, int]], part_ids: Tuple[int]) -> Dict[Union[BodyType, int], int]: + return dict(zip(list(body_types), list(part_ids))) + + def _to_outfit_data(self, body_types: Tuple[Union[BodyType, int]], part_ids: Tuple[int]) -> FrozenSet[Union[BodyType, int]]: + return frozenset(dict(zip(list(body_types), list(part_ids))).items()) + + def __repr__(self) -> str: + return self.__str__() + + def __str__(self) -> str: + return f'<{self.__class__.__name__}: OCI: {self.outfit_category_and_index}, Parts: {self._outfit_parts}>' diff --git a/Scripts/s4ap/sims4communitylib/services/sim/cas/common_temporary_sim_clone_in_cas_service.py b/Scripts/s4ap/sims4communitylib/services/sim/cas/common_temporary_sim_clone_in_cas_service.py new file mode 100644 index 0000000..97d6cf9 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/services/sim/cas/common_temporary_sim_clone_in_cas_service.py @@ -0,0 +1,283 @@ +""" +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 +""" +import services +from typing import List, Callable, Dict, Tuple +from sims.outfits.outfit_enums import OutfitCategory, BodyType +from sims.sim_info import SimInfo +from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry +from sims4communitylib.events.sim.events.sim_set_current_outfit import S4CLSimSetCurrentOutfitEvent +from sims4communitylib.events.zone_spin.events.zone_late_load import S4CLZoneLateLoadEvent +from sims4communitylib.logging.has_log import HasLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + CommonConsoleCommandArgument +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.services.common_service import CommonService +from sims4communitylib.services.sim.cas.common_sim_outfit_io import CommonSimOutfitIO +from sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils +from sims4communitylib.utils.sims.common_sim_location_utils import CommonSimLocationUtils +from sims4communitylib.utils.sims.common_sim_spawn_utils import CommonSimSpawnUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + + +class CommonEditSimCloneInCASResponseHandle: + """CommonEditSimCloneInCASResponseHandle(\ + sim_clone_id,\ + on_outfit_modified=CommonFunctionUtils.noop,\ + on_finished=CommonFunctionUtils.noop,\ + ) + + A handle for when changes are made (or not made) to a temporary Sim Clone. + + :param sim_clone_id: The decimal identifier of the Sim clone the handle is for. + :type sim_clone_id: int + :param on_outfit_modified: A callback invoked when the outfit of the Sim Clone is modified. It will receive the Sim Clone object itself as well as an Outfit IO for easy retrieval of outfit parts. Default is Noop. + :type on_outfit_modified: Callable[[SimInfo, CommonSimOutfitIO], None], optional + :param on_finished: A callback invoked when the outfit is either modified or not. Default is noop. + :type on_finished: Callable[[], None], optional + """ + + def __init__( + self, + sim_clone_id: int, + on_outfit_modified: Callable[[SimInfo, CommonSimOutfitIO], None]=CommonFunctionUtils.noop, + on_finished: Callable[[], None]=CommonFunctionUtils.noop + ): + self.sim_clone_id = sim_clone_id + self.on_outfit_modified = on_outfit_modified + self.on_finished = on_finished + + +class CommonEditSimCloneInCASService(CommonService, HasLog): + """CommonEditSimCloneInCASService() + + A service that will create a Sim clone, open CAS with that Sim clone for edit, invoke callbacks when the outfit of the Sim clone is modified, and finally delete the Sim clone. + + """ + + # noinspection PyMissingOrEmptyDocstring + @property + def mod_identity(self) -> CommonModIdentity: + return ModInfo.get_identity() + + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + return 'common_edit_sim_clone_in_cas_service' + + def __init__(self, outfit_category_and_index: Tuple[OutfitCategory, int]=(OutfitCategory.EVERYDAY, 0)) -> None: + super().__init__() + self._sim_clone_response_handle_library: Dict[int, CommonEditSimCloneInCASResponseHandle] = dict() + self._sim_clone_sim_ids_awaiting_destruction: List[int] = list() + self._outfit_category_and_index = outfit_category_and_index + + def modify_sim_clone_for_sim( + self, + sim_info: SimInfo, + setup_outfit: Callable[[CommonSimOutfitIO], None]=CommonFunctionUtils.noop, + on_outfit_modified: Callable[[SimInfo, CommonSimOutfitIO], None]=CommonFunctionUtils.noop, + on_finished: Callable[[], None]=CommonFunctionUtils.noop + ) -> None: + """modify_sim_clone_for_sim() + + Modify a Clone of a Sim in CAS + + """ + self.modify_sim_clone(sim_info, setup_outfit=setup_outfit, on_outfit_modified=on_outfit_modified, on_finished=on_finished) + + def modify_sim_clone( + self, + source_sim_info: SimInfo, + setup_outfit: Callable[[CommonSimOutfitIO], None]=CommonFunctionUtils.noop, + on_outfit_modified: Callable[[SimInfo, CommonSimOutfitIO], None]=CommonFunctionUtils.noop, + on_finished: Callable[[], None]=CommonFunctionUtils.noop + ) -> None: + """Create a temporary Sim clone, open cas with it, and invoke callbacks when the Sim clone outfit is modified.""" + if source_sim_info is None: + self.log.error('No Sim was specified for cloning!') + return + if on_outfit_modified is None: + self.log.error('Missing on_outfit_modified.') + return + if self._sim_clone_sim_ids_awaiting_destruction: + sim_clone_sim_ids_awaiting_destruction = tuple(self._sim_clone_sim_ids_awaiting_destruction) + for _sim_clone_sim_id in sim_clone_sim_ids_awaiting_destruction: + _clone_sim_info = CommonSimUtils.get_sim_info(_sim_clone_sim_id) + if _clone_sim_info is None: + continue + if CommonSimSpawnUtils.delete_sim(_clone_sim_info, source=f'{self.mod_identity.name} Destroy Old Sim Clone', cause='Sim Clone is Old'): + if _sim_clone_sim_id in self._sim_clone_sim_ids_awaiting_destruction: + self._sim_clone_sim_ids_awaiting_destruction.remove(_sim_clone_sim_id) + # if CommonOccultUtils.has_any_occult(source_sim_info): + # CommonOccultUtils.switch_to_occult_form(source_sim_info, CommonOccultType.NON_OCCULT) + + clone_sim_info = CommonSimSpawnUtils.clone_sim(source_sim_info, add_to_household=True) + if clone_sim_info is None: + self.log.format_error('Failed to create Clone Sim.') + return + try: + clone_household_id = CommonHouseholdUtils.get_household_id(clone_sim_info) + CommonSimSpawnUtils.spawn_sim(clone_sim_info, location=CommonSimLocationUtils.get_location(source_sim_info)) + self._delete_other_outfits(clone_sim_info) + sim_clone_sim_id = CommonSimUtils.get_sim_id(clone_sim_info) + clone_sim_info.skin_tone = source_sim_info.skin_tone + clone_sim_info.skin_tone_val_shift = source_sim_info.skin_tone_val_shift + + self.verbose_log.format_with_message('Current Sim clone outfit', outfit_parts=CommonOutfitUtils.get_outfit_parts(clone_sim_info)) + self._setup_sim_clone_outfit(clone_sim_info, CommonOutfitUtils.get_outfit_parts(source_sim_info, outfit_category_and_index=(OutfitCategory.BATHING, 0)), setup_outfit) + client = services.client_manager().get_first_client() + self.log.format_with_message('Adding Sim Id to response handle library', sim_id=sim_clone_sim_id, sim=clone_sim_info) + self._sim_clone_response_handle_library[sim_clone_sim_id] = CommonEditSimCloneInCASResponseHandle(sim_clone_sim_id, on_outfit_modified=on_outfit_modified, on_finished=on_finished) + if client is not None: + import sims4.commands + sims4.commands.client_cheat('cas.fulleditmode', client.id) + sims4.commands.client_cheat('sims.exit2cas {} {} {}'.format(sim_clone_sim_id, clone_household_id, CommonSimUtils.get_sim_info(source_sim_info)), client.id) + except Exception as ex: + self.log.error('An error occurred when trying to display clone Sim.', exception=ex) + if clone_sim_info is not None: + CommonSimSpawnUtils.delete_sim(clone_sim_info, source=f'{self.mod_identity.name} Destroy Sim Clone due to error', cause='Deleting Sim Clone due to error') + + def _setup_sim_clone_outfit( + self, + clone_sim_info: SimInfo, + initial_outfit_parts: Dict[BodyType, int], + setup_outfit: Callable[[CommonSimOutfitIO], None]=CommonFunctionUtils.noop + ): + self.log.format_with_message('Setting up Sim clone outfit', sim_clone_sim_info=clone_sim_info, initial_outfit_parts=initial_outfit_parts, outfit_category_and_index=CommonOutfitUtils.get_current_outfit(clone_sim_info)) + # noinspection PyTypeChecker + outfit_io = CommonSimOutfitIO(clone_sim_info, outfit_category_and_index=self._outfit_category_and_index, initial_outfit_parts=initial_outfit_parts, mod_identity=self.mod_identity) + if setup_outfit is not None: + setup_outfit(outfit_io) + + # from sims4communitylib.utils.sims.common_occult_utils import CommonOccultUtils + # if CommonOccultUtils.has_any_occult(clone_sim_info): + # CommonOccultUtils.switch_to_occult_form(clone_sim_info, OccultType.HUMAN) + if outfit_io.apply(apply_to_all_outfits_in_same_category=True, apply_to_outfit_category_and_index=self._outfit_category_and_index): + clone_sim_info.on_outfit_generated(*self._outfit_category_and_index) + clone_sim_info.set_outfit_dirty(self._outfit_category_and_index[0]) + clone_sim_info.set_current_outfit(self._outfit_category_and_index) + + def _on_sim_clone_outfit_changed( + self, + clone_sim_info: SimInfo, + outfit_category_and_index: Tuple[OutfitCategory, int] + ) -> None: + clone_sim_id = CommonSimUtils.get_sim_id(clone_sim_info) + if clone_sim_id not in self._sim_clone_response_handle_library: + self.log.format_with_message('No response handle found waiting for Sim clone outfit change.', clone_sim_id=clone_sim_id, sim=clone_sim_info) + return + self.log.format_with_message( + 'Sim Clone outfit changed', + sim_clone_id=clone_sim_id, + clone_sim_info=clone_sim_info, + outfit_category_and_index=outfit_category_and_index + ) + # noinspection PyTypeChecker + outfit_io = CommonSimOutfitIO(clone_sim_info, mod_identity=ModInfo.get_identity(), outfit_category_and_index=self._outfit_category_and_index) + + sim_clone_response_handle = self._sim_clone_response_handle_library[clone_sim_id] + try: + if sim_clone_response_handle is None: + self.log.format_with_message('No response handle found. Done handling on outfit changed', clone_sim_id=clone_sim_id) + return + self.log.format_with_message('Response handle found, invoking Sim clone callback', clone_sim_id=clone_sim_id) + sim_clone_response_handle.on_outfit_modified(clone_sim_info, outfit_io) + except Exception as ex: + self.log.error('Error occurred while invoking Sim clone callback', exception=ex) + finally: + if clone_sim_id not in self._sim_clone_sim_ids_awaiting_destruction: + self._sim_clone_sim_ids_awaiting_destruction.append(clone_sim_id) + + def _clean_up_sim_clones(self) -> None: + for (sim_clone_id, response_handle) in self._sim_clone_response_handle_library.items(): + sim_clone_sim_info = CommonSimUtils.get_sim_info(sim_clone_id) + if sim_clone_sim_info is not None: + self._on_sim_clone_outfit_changed(sim_clone_sim_info, CommonOutfitUtils.get_current_outfit(sim_clone_sim_info)) + + if not self._sim_clone_sim_ids_awaiting_destruction: + self.log.debug('No sim_clones were awaiting destruction') + return + + sim_clone_ids_awaiting_destruction = tuple(self._sim_clone_sim_ids_awaiting_destruction) + for sim_clone_sim_id in sim_clone_ids_awaiting_destruction: + self.log.format_with_message('Cleaning up Sim clone.', sim_clone_id=sim_clone_sim_id) + if sim_clone_sim_id in self._sim_clone_response_handle_library: + sim_clone_response_handle = self._sim_clone_response_handle_library[sim_clone_sim_id] + try: + if sim_clone_response_handle is not None: + self.log.format_with_message('Calling response handle on finished.', sim_clone_id=sim_clone_sim_id) + if sim_clone_response_handle.on_finished is not None: + sim_clone_response_handle.on_finished() + except Exception as ex: + self.log.error('An error occurred while invoking on finished.', exception=ex) + finally: + del self._sim_clone_response_handle_library[sim_clone_sim_id] + + clone_sim_info = CommonSimUtils.get_sim_info(sim_clone_sim_id) + if clone_sim_info is None: + self.log.format_with_message('Sim Clone SimInfo not found.', sim_clone_id=sim_clone_sim_id) + continue + + self.log.format_with_message('Destroying Sim Clone.', sim_clone_id=sim_clone_sim_id) + + if CommonSimSpawnUtils.delete_sim(clone_sim_info, source=self.mod_identity.name, cause=f'{self.mod_identity.name}: Sim Clone is being cleaned up'): + if sim_clone_sim_id in self._sim_clone_sim_ids_awaiting_destruction: + self._sim_clone_sim_ids_awaiting_destruction.remove(sim_clone_sim_id) + + def _delete_other_outfits(self, sim_info: SimInfo): + from sims.outfits.outfit_tracker import OutfitTrackerMixin + outfits: OutfitTrackerMixin = sim_info.get_outfits() + current_outfit = CommonOutfitUtils.get_current_outfit(sim_info) + for outfit_category in CommonOutfitUtils.get_all_outfit_categories(): + for outfit_index in range(CommonOutfitUtils.get_maximum_number_of_outfits_for_category(outfit_category)): + outfit = (outfit_category, outfit_index) + if outfit_category in (self._outfit_category_and_index[0], OutfitCategory.BATHING, OutfitCategory.SPECIAL) and outfit_index == 0: + self.log.format_with_message('Skipping first outfit.', sim=sim_info, outfit=outfit) + continue + if not CommonOutfitUtils.has_outfit(sim_info, outfit): + self.log.format_with_message('Sim did not have outfit.', sim=sim_info, outfit=outfit) + continue + outfits.remove_outfit(outfit_category, outfit_index=outfit_index) + self.log.format_with_message('Removed outfit.', sim=sim_info, outfit=outfit) + sim_info.appearance_tracker.evaluate_appearance_modifiers() + CommonOutfitUtils.resend_outfits(sim_info) + CommonOutfitUtils.set_current_outfit(sim_info, current_outfit) + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.modify_sim_clone', + 'Create a Clone of a Sim and open CAS to modify them.', + command_arguments=( + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to create and modify a clone of.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.modifysimclone', + ) +) +def _s4clib_modify_sim_clone(output: CommonConsoleCommandOutput, sim_info: SimInfo=None): + if sim_info is None: + return + output(f'Modifying a clone of Sim \'{sim_info}\' in CAS.') + CommonEditSimCloneInCASService().modify_sim_clone_for_sim(sim_info) + output('Done') + + +# noinspection PyUnusedLocal +@CommonEventRegistry.handle_events(ModInfo.get_identity()) +def _common_clean_sim_clones_on_zone_load(event_data: S4CLZoneLateLoadEvent): + CommonEditSimCloneInCASService()._clean_up_sim_clones() + + +@CommonEventRegistry.handle_events(ModInfo.get_identity()) +def _common_sim_clone_on_outfit_change(event_data: S4CLSimSetCurrentOutfitEvent) -> bool: + CommonEditSimCloneInCASService()._on_sim_clone_outfit_changed(event_data.sim_info, event_data.new_outfit_category_and_index) + return True diff --git a/Scripts/s4ap/sims4communitylib/systems/__init__.py b/Scripts/s4ap/sims4communitylib/systems/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/systems/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/systems/caching/__init__.py b/Scripts/s4ap/sims4communitylib/systems/caching/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/systems/caching/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/systems/caching/common_serializable_object_cache.py b/Scripts/s4ap/sims4communitylib/systems/caching/common_serializable_object_cache.py new file mode 100644 index 0000000..b966920 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/systems/caching/common_serializable_object_cache.py @@ -0,0 +1,69 @@ +""" +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 +""" +from typing import Union, Dict, Any, Type, Tuple, TypeVar, Generic, List + +from sims4communitylib.classes.serialization.common_serializable import CommonSerializable + +CommonSerializableObjectCacheType = TypeVar('CommonSerializableObjectCacheType', bound=CommonSerializable) + + +class CommonSerializableObjectCache(CommonSerializable, Generic[CommonSerializableObjectCacheType]): + """A cache of serializable objects.""" + + def __init__(self, cached_objects: Tuple[CommonSerializableObjectCacheType], checksums: Dict[str, int]): + self._cached_objects = cached_objects + self._checksums = checksums + + @property + def cached_objects(self) -> Tuple[CommonSerializableObjectCacheType]: + """Cached objects""" + return self._cached_objects + + @property + def cached_checksums(self) -> Dict[str, int]: + """Cached checksums, these are used to check if the cache needs updating.""" + return self._checksums + + # noinspection PyMissingOrEmptyDocstring + def serialize(self: 'CommonSerializableObjectCache') -> Union[str, Dict[str, Any]]: + data = dict() + data['cached_checksums'] = self._checksums + data['cached_objects'] = [cached_object.serialize() for cached_object in self.cached_objects] + return data + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def deserialize( + cls: Type['CommonSerializableObjectCache'], + data: Union[str, Dict[str, Any]] + ) -> Union['CommonSerializableObjectCache', None]: + checksums = data.get('cached_checksums', None) + if checksums is None: + return None + cached_objects_data = data.get('cached_objects', tuple()) + + if not cached_objects_data: + return None + + cached_objects: List[CommonSerializableObjectCacheType] = list() + for object_data in cached_objects_data: + cached_object = cls._deserialize_object(object_data) + if cached_object is None: + continue + cached_objects.append(cached_object) + if not cached_objects: + return None + + return cls( + tuple(cached_objects), + checksums + ) + + @classmethod + def _deserialize_object(cls, data: Union[str, Dict[str, Any]]) -> Union[CommonSerializableObjectCacheType, None]: + return CommonSerializableObjectCacheType.deserialize(data) diff --git a/Scripts/s4ap/sims4communitylib/systems/caching/common_serializable_object_cache_service.py b/Scripts/s4ap/sims4communitylib/systems/caching/common_serializable_object_cache_service.py new file mode 100644 index 0000000..07c0f7c --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/systems/caching/common_serializable_object_cache_service.py @@ -0,0 +1,104 @@ +""" +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 +""" +import os +from typing import Union, Generic, TypeVar, Tuple, Dict, Any + +from sims4communitylib.systems.caching.common_serializable_object_cache import CommonSerializableObjectCache +from sims4communitylib.classes.serialization.common_serializable import CommonSerializable +from sims4communitylib.logging.has_log import HasLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.services.common_service import CommonService +from sims4communitylib.utils.common_io_utils import CommonIOUtils +from sims4communitylib.utils.common_json_io_utils import CommonJSONIOUtils +from sims4communitylib.utils.common_log_utils import CommonLogUtils + + +CommonSerializableObjectCacheType = TypeVar('CommonSerializableObjectCacheType', bound=CommonSerializableObjectCache[CommonSerializable]) + + +class CommonSerializableObjectCacheService(CommonService, HasLog, Generic[CommonSerializableObjectCacheType]): + """A service that manages a cache of serializable objects.""" + + # noinspection PyMissingOrEmptyDocstring + @property + def mod_identity(self) -> CommonModIdentity: + raise NotImplementedError() + + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + return 'common_serializable_object_cache_service' + + @property + def _cache_file_name(self) -> str: + raise NotImplementedError() + + def __init__(self) -> None: + super().__init__() + self._cache = None + + def cache_needs_update(self, new_checksum_data: Any) -> bool: + """Determine if the cache needs to be updated or not.""" + cache = self.load_from_cache() + if cache is None or not cache.cached_checksums: + return False + (snippet_name, snippet_id, new_checksum) = new_checksum_data + checksums = cache.cached_checksums + key = f'{snippet_name}-{snippet_id}' + if checksums.get(key, -1) != new_checksum: + return True + return False + + def save_to_cache(self, cache: CommonSerializableObjectCacheType) -> None: + """Save a cache of data.""" + file_path = self._get_cache_file_path() + folder_path = self._get_cache_folder_path() + if os.path.exists(file_path): + CommonIOUtils.delete_file(file_path) + + if not os.path.exists(folder_path): + os.makedirs(folder_path, exist_ok=True) + + CommonJSONIOUtils.write_to_file(file_path, cache.serialize()) + self._cache = cache + + def load_from_cache(self) -> Union[CommonSerializableObjectCacheType, None]: + """Load the cached data.""" + if self._cache is not None: + return self._cache + file_path = self._get_cache_file_path() + if os.path.exists(file_path): + self._cache = self._deserialize_cache(CommonJSONIOUtils.load_from_file(file_path)) + else: + self._cache = None + return self._cache + + def clear_cache(self) -> None: + """Clear the cached data""" + file_path = self._get_cache_file_path() + if os.path.exists(file_path): + CommonIOUtils.delete_file(file_path) + self._cache = None + + def _get_cache_folder_path(self) -> str: + return os.path.join(CommonLogUtils.get_mod_data_location_path(), self.mod_identity.base_namespace.lower(), 'caches') + + def _get_cache_file_path(self) -> str: + return os.path.join(self._get_cache_folder_path(), f'{self._cache_file_name}_cache.json') + + def _deserialize_cache(self, data: Union[str, Dict[str, Any]]) -> CommonSerializableObjectCacheType: + return CommonSerializableObjectCacheType[CommonSerializable].deserialize(data) + + def create_cache(self, objects: Tuple[CommonSerializable], checksums: Tuple[Any]) -> CommonSerializableObjectCacheType: + """ + Create a new cache. + """ + checksum_data = dict() + for (snippet_name, snippet_id, checksum_value) in checksums: + checksum_data[f'{snippet_name}-{snippet_id}'] = checksum_value + return CommonSerializableObjectCache[CommonSerializable](objects, checksum_data) diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/__init__.py b/Scripts/s4ap/sims4communitylib/systems/item_query/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/systems/item_query/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/common_loaded_item_query_registry.py b/Scripts/s4ap/sims4communitylib/systems/item_query/common_loaded_item_query_registry.py new file mode 100644 index 0000000..5e8b6a6 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/systems/item_query/common_loaded_item_query_registry.py @@ -0,0 +1,545 @@ +""" +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 +""" +import collections +from typing import List, Dict, Any, Tuple, Set, Callable, Union, Iterator, TypeVar, Generic + +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.systems.item_query.item_tests.common_loaded_item_test import CommonLoadedItemTest +from sims4communitylib.systems.item_query.query.common_loaded_item_filter_request import CommonLoadedItemFilterRequest +from sims4communitylib.systems.item_query.query.common_loaded_item_organizer import CommonLoadedItemOrganizer +from sims4communitylib.systems.item_query.dtos.common_loaded_item import CommonLoadedItem +from sims4communitylib.systems.item_query.common_loaded_item_registry import CommonLoadedItemRegistry +from sims4communitylib.classes.time.common_stop_watch import CommonStopWatch +from sims4communitylib.events.zone_spin.events.zone_early_load import S4CLZoneEarlyLoadEvent +from sims4communitylib.events.zone_spin.events.zone_late_load import S4CLZoneLateLoadEvent +from sims4communitylib.logging.has_log import HasLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification +from sims4communitylib.services.common_service import CommonService +from sims4communitylib.systems.item_query.enums.common_query_method_type import CommonQueryMethodType +from sims4communitylib.utils.misc.common_text_utils import CommonTextUtils + +CommonLoadedItemType = TypeVar('CommonLoadedItemType', bound=CommonLoadedItem) + + +class CommonLoadedItemQueryRegistry(CommonService, HasLog, Generic[CommonLoadedItemType]): + """ Registry handling item queries. """ + + # noinspection PyMissingOrEmptyDocstring + @property + def mod_identity(self) -> CommonModIdentity: + raise NotImplementedError() + + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + raise NotImplementedError() + + def __init__(self) -> None: + super().__init__() + self._collecting = False + self.item_library = collections.defaultdict(set) + self.__item_organizers: List[CommonLoadedItemOrganizer] = list() + self._all: List[CommonLoadedItemType] = list() + self._total = 0 + self._total_valid = 0 + self._total_invalid = 0 + self._duplicates = 0 + + @property + def _registry(self) -> CommonLoadedItemRegistry: + raise NotImplementedError() + + @property + def _item_organizers(self) -> List[CommonLoadedItemOrganizer]: + return self.__item_organizers + + @property + def _item_name(self) -> str: + return 'item' + + @property + def collecting(self) -> bool: + """Determine if items are being collected.""" + return self._collecting + + @property + def item_library(self) -> Dict[Tuple[Any, Any], Set[str]]: + """ A library of items organized by filter keys. """ + return self._item_library + + @item_library.setter + def item_library(self, value: Dict[Tuple[Any, Any], Set[str]]): + self._item_library = value + + @property + def total(self) -> int: + """The total number of items that were looked at""" + return self._total + + @property + def total_invalid(self) -> int: + """The total number of items that were invalid.""" + return self._total_invalid + + @property + def total_valid(self) -> int: + """The total number of items that were valid.""" + return self._total_valid + + @property + def duplicates(self) -> int: + """The total number of items that were valid.""" + return self._duplicates + + def add_item_organizer( + self, + item_organizer_init: Callable[[Any], CommonLoadedItemOrganizer], + key_type: Any + ): + """ Add an item organizer. """ + self._item_organizers.append(item_organizer_init(key_type)) + + def has_items(self, requests: Tuple[CommonLoadedItemFilterRequest]) -> bool: + """ Determine if items exist for queries. """ + if self.log.enabled: + self.log.format_with_message(f'Checking if has {self._item_name}s', queries=requests) + for _ in self.get_items_gen(requests): + return True + return False + + def get_items_gen(self, requests: Tuple[CommonLoadedItemFilterRequest]) -> Iterator[CommonLoadedItemType]: + """ Retrieve items matching the requests. """ + if self.log.enabled: + self.log.format_with_message(f'Getting {self._item_name}s', requests=requests) + if self._collecting: + return tuple() + for request in requests: + yield from self._query_items(request, request.item_tests) + if self.verbose_log.enabled: + self.verbose_log.debug(f'Finished locating {self._item_name}s') + + def _run_tests(self, item: CommonLoadedItemType, item_tests: Iterator[CommonLoadedItemTest]) -> CommonTestResult: + for _item_test in item_tests: + _result = _item_test.test_item(item) + if not _result: + return _result + return CommonTestResult.TRUE + + def _query_items(self, request: CommonLoadedItemFilterRequest, item_tests: Iterator[CommonLoadedItemTest]) -> Iterator[CommonLoadedItemType]: + if self.log.enabled: + self.log.format_with_message(f'Querying for {self._item_name}s using query', query=request, item_tests=item_tests) + item_tests = tuple(item_tests) + all_keys = request.include_all_keys + any_keys = request.include_any_keys + exclude_keys = request.exclude_keys + match_at_least_one_key_sets = request.must_match_at_least_one_key_sets + found_item_identifiers = None + + def _convert_found_items(_found_identifiers: Set[str]) -> Iterator[CommonLoadedItemType]: + count = 0 + for _item_identifier in _found_identifiers: + _item = self._registry.locate_by_identifier(_item_identifier) + if _item is None: + continue + _passes_tests = self._run_tests(_item, item_tests) + if not _passes_tests: + if self.log.is_enabled: + self.log.format_with_message(f'{self._item_name} failed item test', item=_item.short_name, reason=_passes_tests.reason) + continue + count += 1 + yield _item + + if self.log.enabled: + self.log.debug(f'After item tests keys {count}') + + if self.log.enabled: + self.log.format_with_message('Using match_at_least_one_sets', match_at_least_one_sets=match_at_least_one_key_sets) + if match_at_least_one_key_sets: + self.verbose_log.format_with_message('Has match at least one sets.', match_at_least_one_sets=match_at_least_one_key_sets) + found_all_matching = False + for match_at_least_one_key_set in match_at_least_one_key_sets: + if self.log.enabled: + self.log.format_with_message('Attempting to locate a match for set.', match_at_least_one_set=match_at_least_one_key_set) + found_matching = False + total_matching_items = None + for match_at_least_one_key in match_at_least_one_key_set: + if match_at_least_one_key is None: + continue + if match_at_least_one_key.key not in self.item_library: + # One of the Match At Least One keys is not within the Item library! This means no Items pass the Match At Least One keys. + if self.log.enabled: + self.log.format_with_message(f'Match At Least One Key not found within the {self._item_name} library, meaning there are no {self._item_name}s available for it! Skipping this key.', key=match_at_least_one_key.key) + continue + new_found_items = self.item_library[match_at_least_one_key.key] + if total_matching_items is not None: + if self.log.enabled: + self.log.debug(f'Looking for key {match_at_least_one_key}') + before_intersect_match_at_least_one_count = len(total_matching_items) + self.log.format_with_message(f'Before intersect for match_at_least_one_keys {before_intersect_match_at_least_one_count}', match=match_at_least_one_key) + if len(new_found_items) != 0: + found_matching = True + new_found_items = total_matching_items | new_found_items + if self.log.enabled: + after_intersect_match_at_least_one_count = len(new_found_items) + self.log.format_with_message(f'After intersect for match_at_least_one_keys {after_intersect_match_at_least_one_count}', match=match_at_least_one_key) + total_matching_items = new_found_items + else: + if self.log.enabled: + new_found_match_at_least_one_count = len(new_found_items) + self.log.format_with_message(f'Found with match_at_least_one_keys {new_found_match_at_least_one_count}', match=match_at_least_one_key) + if new_found_items is not None and len(new_found_items) != 0: + found_matching = True + total_matching_items = new_found_items + + if not found_matching or not total_matching_items: + if self.log.enabled: + self.log.format_with_message(f'No {self._item_name}s found for match_at_least_one_set.', match_at_least_one_set=match_at_least_one_key_set) + return tuple() + self.verbose_log.format_with_message('Located a match for set, combining it with what currently exists.', match_at_least_one_set=match_at_least_one_key_set) + if found_item_identifiers is not None: + if self.log.enabled: + self.log.debug(f'Connecting set {match_at_least_one_key_set}') + total_count_before = len(total_matching_items) + self.log.debug(f'Before intersect for match_at_least_one_set {total_count_before}') + if len(total_matching_items) != 0: + found_all_matching = True + total_matching_items = found_item_identifiers & total_matching_items + if self.log.enabled: + total_count_after = len(total_matching_items) + self.log.debug(f'After intersect for match_at_least_one_set {total_count_after}') + found_item_identifiers = total_matching_items + else: + if self.log.enabled: + total_count_after = len(total_matching_items) + self.log.debug(f'Found with match_at_least_ones {total_count_after}') + if total_matching_items is not None and len(total_matching_items) != 0: + found_all_matching = True + found_item_identifiers = total_matching_items + if not found_all_matching: + if self.log.enabled: + self.log.format_with_message(f'No {self._item_name}s found for match_at_least_one_set', match_at_least_one_sets=match_at_least_one_key_sets) + return tuple() + + self.log.format_with_message('Using all_keys', all_keys=all_keys) + for include_all_key in all_keys: + if include_all_key is None: + continue + if include_all_key.key not in self.item_library: + # One of All keys is not within the item library! This means no items match ALL keys. + if self.log.enabled: + self.log.format_with_message(f'All Key not found within the {self._item_name} library, meaning there are no {self._item_name}s available for it! Skipping this key.', key=include_all_key.key) + return tuple() + new_found_items = self.item_library[include_all_key.key] + if found_item_identifiers is not None: + if self.log.enabled: + before_intersect_all_count = len(found_item_identifiers) + self.log.format_with_message(f'Before intersect for all_keys {before_intersect_all_count}', include_all_key=include_all_key) + new_found_items = found_item_identifiers & new_found_items + if self.log.enabled: + after_intersect_all_count = len(new_found_items) + self.log.format_with_message(f'After intersect for all_keys {after_intersect_all_count}', include_all_key=include_all_key) + else: + if self.log.enabled: + new_match_all_count = len(new_found_items) + self.log.format_with_message(f'Found with all_keys {new_match_all_count}', include_all_key=include_all_key) + + found_item_identifiers = new_found_items + + if found_item_identifiers is None and all_keys: + if self.log.enabled: + self.log.format_with_message(f'No {self._item_name}s found for all_keys.', all_keys=all_keys) + return tuple() + + if self.log.enabled: + after_all_keys = len(found_item_identifiers) if found_item_identifiers is not None else 0 + self.log.debug(f'After all_keys {after_all_keys}') + if self.verbose_log.enabled: + if found_item_identifiers is not None: + found_all_items: List[str] = list() + for anim_identifier in found_item_identifiers: + item = self._registry.locate_by_identifier(anim_identifier) + if item is None: + continue + found_all_items.append(item.short_name) + self.verbose_log.format_with_message(f'Found {self._item_name}s via all keys', items=found_all_items) + + self.log.format_with_message('Using any_keys', any_keys=any_keys) + found_items_via_any_keys = set() + for include_any_key in any_keys: + if include_any_key is None: + continue + if include_any_key.key not in self.item_library: + if self.log.enabled: + self.log.format_with_message(f'Any Key not found within the {self._item_name} library, meaning there are no {self._item_name}s available for it! Skipping this key.', key=include_any_key.key) + continue + found_items_via_any_keys = found_items_via_any_keys | self.item_library[include_any_key.key] + + if self.log.enabled: + found_any_keys_count = len(found_items_via_any_keys) if found_items_via_any_keys is not None else 0 + self.log.debug(f'Found {self._item_name}s via any {found_any_keys_count}') + + if self.verbose_log.enabled: + found_any_items: List[str] = list() + for anim_identifier in found_items_via_any_keys: + item = self._registry.locate_by_identifier(anim_identifier) + if item is None: + continue + found_any_items.append(item.short_name) + self.verbose_log.format_with_message(f'Found {self._item_name}s via any keys', items=found_any_items) + + if found_item_identifiers is None: + if self.log.enabled: + self.log.debug(f'No {self._item_name}s found for all_keys.') + if not all_keys: + self.log.debug('Returning any keys.') + yield from _convert_found_items(found_items_via_any_keys) + return tuple() + else: + query_type = request.query_type + if not any_keys and (query_type == CommonQueryMethodType.ALL_INTERSECT_ANY or query_type == CommonQueryMethodType.ALL_INTERSECT_ANY_MUST_HAVE_ONE): + query_type = CommonQueryMethodType.ALL_PLUS_ANY + if query_type == CommonQueryMethodType.ALL_PLUS_ANY: + found_item_identifiers = found_item_identifiers | found_items_via_any_keys + elif query_type == CommonQueryMethodType.ALL_INTERSECT_ANY: + found_item_identifiers = found_item_identifiers & found_items_via_any_keys + + if query_type == CommonQueryMethodType.ALL_PLUS_ANY_MUST_HAVE_ONE: + if not found_items_via_any_keys: + return tuple() + found_item_identifiers = found_item_identifiers | found_items_via_any_keys + elif query_type == CommonQueryMethodType.ALL_INTERSECT_ANY_MUST_HAVE_ONE: + if not found_items_via_any_keys: + return tuple() + found_item_identifiers = found_item_identifiers & found_items_via_any_keys + + if found_item_identifiers is None or not found_item_identifiers: + if self.log.enabled: + self.log.debug(f'No found {self._item_name}s after combining any keys. All Keys: {all_keys} Any Keys: {any_keys}') + return tuple() + + if self.log.enabled: + after_any_keys_count = len(found_item_identifiers) + self.log.debug(f'After any keys {after_any_keys_count}') + + self.log.format_with_message('Using exclude', exclude_keys=exclude_keys) + for exclude_key in exclude_keys: + if exclude_key is None: + continue + exclude_key = exclude_key.key + if exclude_key not in self.item_library: + continue + to_exclude_items = self.item_library[exclude_key] + if self.log.enabled: + before_found_item_count = len(found_item_identifiers) + before_to_exclude_item_count = len(to_exclude_items) + self.log.debug(f'Before exclude key {exclude_key} {before_found_item_count} to exclude {before_to_exclude_item_count}') + found_item_identifiers = found_item_identifiers - to_exclude_items + if self.log.enabled: + after_found_item_count = len(found_item_identifiers) + after_to_exclude_item_count = len(to_exclude_items) + self.log.debug(f'After exclude key {exclude_key} {after_found_item_count} to exclude {after_to_exclude_item_count}') + + if self.log.enabled: + after_exclude_item_count = len(found_item_identifiers) + self.log.debug(f'After exclude {after_exclude_item_count}') + stop_watch = CommonStopWatch() + stop_watch.start() + yield from _convert_found_items(found_item_identifiers) + + if self.log.enabled: + time_taken = CommonTextUtils.to_truncated_decimal(stop_watch.stop_milliseconds()) + self.log.format_with_message(f'Finished running loaded item tests in {time_taken}ms') + else: + stop_watch.stop() + + def get_all(self) -> Tuple[CommonLoadedItemType]: + """ Get all items. """ + if self._collecting: + return tuple() + return tuple(self._all) + + def _organize(self, items: Tuple[CommonLoadedItemType]): + if self.log.enabled: + self.log.debug(f'Collecting {self._item_name}s Query Data...') + self.item_library.clear() + new_item_library = dict() + item_organizers = tuple(self._item_organizers) + for item in items: + item.clear_cached_data() + if self.log.enabled: + self.log.format_with_message(f'Handling keys for {self._item_name}', item=item.short_name) + item_identifier = item.identifier + item_keys = list() + for item_organizer in item_organizers: + if not item_organizer.applies(item): + continue + item_key_type = item_organizer.key_type + for item_key_value in item_organizer.get_key_values(item): + item_key = (item_key_type, item_key_value) + item_keys.append(item_key) + if item_key not in new_item_library: + new_item_library[item_key] = set() + if item_identifier in new_item_library[item_key]: + continue + new_item_library[item_key].add(item_identifier) + if self.log.enabled: + self.log.format_with_message(f'Applied keys to {self._item_name}.', name=item.short_name, keys=item_keys) + + if self.log.enabled: + self.log.format_with_message(f'Completed collecting {self._item_name} Query Data.', item_library=new_item_library) + self.item_library = new_item_library + + def trigger_collection(self, show_loading_notification: bool = True) -> None: + """trigger_collection(show_loading_notification=True) + + Trigger the action code to collect all items and organize them by a number of keys. + + :param show_loading_notification: If set to True, the Loading Item's notification will be shown. If set to False, the Loading Item's notification will not be shown. Default is True. + :type show_loading_notification: bool, optional + """ + def _recollect_data() -> None: + try: + if not self._registry.loaded or self._registry.loading: + def _on_finished_loading() -> None: + self.trigger_collection(show_loading_notification=False) + + if show_loading_notification: + CommonBasicNotification( + self._loading_items_title(), + self._loading_items_description() + ).show() + self._registry.register_on_finished_loading_callback(_on_finished_loading) + self._registry.load() + return + + number_of_items = self._collect() + if number_of_items == -1: + return + CommonBasicNotification( + self._finished_loading_title(), + self._finished_loading_description(), + description_tokens=(str(self.total_valid), str(self.total), str(self.duplicates), str(self.total_invalid)) + ).show() + except Exception as ex: + self.log.error(f'Error occurred while collecting {self._item_name}s.', exception=ex) + finally: + self._collecting = False + + _recollect_data() + + def _collect(self) -> int: + if self._collecting: + return -1 + self._collecting = True + try: + # noinspection PyTypeChecker + self._all: Tuple[CommonLoadedItemType] = tuple(self._registry.loaded_items.values()) + self._total = self._registry.total + self._total_valid = self._registry.total_valid + self._total_invalid = self._registry.total_invalid + self._duplicates = self._registry.duplicates + self.log.format_with_message( + f'Loaded {self._item_name}s', + all_list=self._all + ) + enabled = self.log.enabled + self.log.enable() + after_load_time = CommonTextUtils.to_truncated_decimal(self._registry.total_time) + loaded_items_count = len(self._all) + self.log.debug(f'Took {after_load_time}ms to collect {loaded_items_count} {self._item_name}s.') + if not enabled: + self.log.disable() + stop_watch = CommonStopWatch() + stop_watch.start() + self._organize(self._all) + self._collecting = False + self.log.enable() + time_taken = CommonTextUtils.to_truncated_decimal(stop_watch.stop_milliseconds()) + after_organize_time = time_taken + found_count = len(self._all) + self.log.debug(f'Took {after_organize_time}ms to organize {found_count} {self._item_name}s') + if not enabled: + self.log.disable() + if self.log.enabled: + found_all_count = len(self._all) + self.log.debug(f'Loaded {found_all_count} {self._item_name}s.') + return len(self._all) + except Exception as ex: + self.log.error(f'Error occurred while collecting {self._item_name}s.', exception=ex) + return -1 + finally: + self._collecting = False + + @classmethod + def register_item_organizer(cls, key_type: Any) -> Callable[[Any], Any]: + """ Register an item organizer. """ + return cls()._register_item_organizer(key_type) + + def _register_item_organizer(self, key_type: Any) -> Callable[[Any], Any]: + def _method_wrapper(item_filter: Callable[[int], CommonLoadedItemOrganizer]): + self.add_item_organizer(item_filter, key_type) + return item_filter + return _method_wrapper + + @classmethod + def _should_show_finished_loading_notification(cls) -> bool: + return True + + @classmethod + def _finished_loading_title(cls) -> Union[int, str]: + raise NotImplementedError() + + @classmethod + def _finished_loading_description(cls) -> Union[int, str]: + raise NotImplementedError() + + @classmethod + def _loading_items_title(cls) -> Union[int, str]: + raise NotImplementedError() + + @classmethod + def _loading_items_description(cls) -> Union[int, str]: + raise NotImplementedError() + + @classmethod + def _load_items_on_zone_early_load(cls, event_data: S4CLZoneEarlyLoadEvent, show_loading_notification: bool = False): + if event_data.game_loaded: + # If the game is already loaded, we've already loaded the data once. + return False + cls().trigger_collection(show_loading_notification=show_loading_notification) + return True + + @classmethod + def _load_items_on_zone_late_load(cls, event_data: S4CLZoneLateLoadEvent, show_loading_notification: bool = True): + if event_data.game_loaded: + # If the game is already loaded, we've already loaded the data once. + return False + cls().trigger_collection(show_loading_notification=show_loading_notification) + return True + + @classmethod + def _notify_items_loaded_on_zone_late_load(cls, event_data: S4CLZoneLateLoadEvent): + if event_data.game_loaded: + # If the game is already loaded, we've already notified about the data once. + return False + if not cls().collecting and cls._should_show_finished_loading_notification(): + CommonBasicNotification( + cls._finished_loading_title(), + cls._finished_loading_description(), + description_tokens=(str(cls().total_valid), str(cls().total), str(cls().duplicates), str(cls().total_invalid)) + ).show() + return True + + @classmethod + def _show_item_loading_notification_on_first_update(cls) -> None: + if cls().collecting: + CommonBasicNotification( + cls._loading_items_title(), + cls._loading_items_description() + ).show() diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/common_loaded_item_registry.py b/Scripts/s4ap/sims4communitylib/systems/item_query/common_loaded_item_registry.py new file mode 100644 index 0000000..5112b9a --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/systems/item_query/common_loaded_item_registry.py @@ -0,0 +1,269 @@ +""" +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 +""" +from threading import Thread +from typing import Iterator, Dict, List, Union, TypeVar, Generic, Tuple, Any + +from sims4communitylib.systems.item_query.persistence.common_loaded_item_cache import CommonLoadedItemCache +from sims4communitylib.systems.item_query.persistence.common_loaded_item_cache_service import \ + CommonLoadedItemCacheService +from sims4communitylib.systems.item_query.item_loaders.common_base_item_loader import CommonBaseItemLoader +from sims4communitylib.systems.item_query.dtos.common_loaded_item import CommonLoadedItem +from sims4.callback_utils import CallableList +from sims4communitylib.classes.time.common_stop_watch import CommonStopWatch +from sims4communitylib.logging.has_log import HasLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.services.common_service import CommonService + +CommonLoadedItemType = TypeVar('CommonLoadedItemType', bound=CommonLoadedItem) + + +class CommonLoadedItemRegistry(CommonService, HasLog, Generic[CommonLoadedItemType]): + """ A registry that contains loaded items. """ + + # noinspection PyMissingOrEmptyDocstring + @property + def mod_identity(self) -> CommonModIdentity: + raise NotImplementedError() + + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + raise NotImplementedError() + + def __init__(self) -> None: + super().__init__() + self._loaded = False + self.item_loaders = list() + self.loaded_items = None + self._total = 0 + self._total_valid = 0 + self._total_invalid = 0 + self._total_time = 0.0 + self._duplicates = 0 + self._loading = False + self._load_thread: Union[Thread, None] = None + self._on_finished_loading_callback = CallableList() + + @property + def loaded(self) -> bool: + """True, if the registry has finished loading.""" + return self._loaded + + @property + def loading(self) -> bool: + """True, if the registry is currently loading.""" + return self._loading + + @property + def total(self) -> int: + """The total number of items that were found""" + return self._total + + @property + def total_invalid(self) -> int: + """The total number of items that were invalid.""" + return self._total_invalid + + @property + def total_valid(self) -> int: + """The total number of items that were valid.""" + return self._total_valid + + @property + def item_loaders(self) -> List[CommonBaseItemLoader]: + """Loaders that load items.""" + return self._item_loaders + + @property + def duplicates(self) -> int: + """The total number of duplicate items that were found.""" + return self._duplicates + + @property + def total_time(self) -> float: + """The total time the registry took to load in milliseconds.""" + return self._total_time + + @item_loaders.setter + def item_loaders(self, value: List[CommonBaseItemLoader]): + self._item_loaders = value + + def register_on_finished_loading_callback(self, callback) -> None: + """Finished loading callback.""" + if callback not in self._on_finished_loading_callback: + self._on_finished_loading_callback.append(callback) + + @property + def loaded_items(self) -> Dict[str, CommonLoadedItemType]: + """A library of items organized by their identifiers.""" + return self._loaded_items + + @loaded_items.setter + def loaded_items(self, value: Dict[str, CommonLoadedItemType]): + self._loaded_items = value + + def add_item_loader(self, item_loader: CommonBaseItemLoader) -> bool: + """ Add a loader of items. """ + if item_loader in self.item_loaders: + return False + self.item_loaders.append(item_loader) + return True + + def add_item(self, item: CommonLoadedItemType) -> bool: + """add_item(item) + + Add an Item to the registry. + + :param item: An instance of an Item + :type item: CommonLoadedItemType + :return: True, if the item was successfully added. False, if not. + :rtype: bool + """ + if not self.loaded or self.loading: + def _add_on_finished_loading() -> None: + _unique_id = item.identifier + if _unique_id in self.loaded_items: + return + self.loaded_items[_unique_id] = item + return + + self.register_on_finished_loading_callback(_add_on_finished_loading) + self.load() + return True + unique_id = item.identifier + if unique_id in self.loaded_items: + return False + self.loaded_items[unique_id] = item + return True + + def load(self) -> None: + """ Load data. """ + if self._loaded or self._loading: + self.log.format_with_message('Not loading because already loaded.', loaded=self._loaded, loading=self._loading) + return + try: + self._loading = True + + should_use_cache = self._should_use_cache() + + stop_watch = CommonStopWatch() + stop_watch.start() + self._total_time = 0.0 + self._total = 0 + self._total_valid = 0 + self._total_invalid = 0 + items_library: Dict[str, CommonLoadedItemType] = dict() + if not should_use_cache or self._update_cache(): + self.log.debug(f'Clearing {self.__class__.__name__} cache.') + self._clear_cache() + + loaded_items_cache = self._load_from_cache() + if should_use_cache and loaded_items_cache is not None: + items: Tuple[CommonLoadedItem, ...] = loaded_items_cache.cached_objects + self._total = len(items) + self._total_valid = self._total + should_verify = True + else: + items: Tuple[CommonLoadedItem, ...] = tuple(self._load()) + cache_service = self._get_cache_service() + if cache_service is not None: + self._save_to_cache(cache_service.create_cache(items, self._get_checksums())) + should_verify = False + + self._duplicates = 0 + for item in items: + if should_verify and not item.verify(): + self._total_valid -= 1 + self._total_invalid += 1 + continue + identifier = item.identifier + if identifier in items_library: + self._duplicates += 1 + self._total_valid -= 1 + continue + self._add_additional_item_data(item) + items_library[identifier] = item + + self.loaded_items = items_library + self._loaded = True + self._load_thread = None + self._loading = False + self._total_time = stop_watch.stop_milliseconds() + self._on_finished_loading_callback() + self._on_finished_loading_callback.clear() + self.log.debug('Finished loading items.') + except Exception as ex: + self.log.error('Error occurred while loading items.', exception=ex) + + def _should_use_cache(self) -> bool: + return True + + def _save_to_cache(self, item_cache: CommonLoadedItemCache[CommonLoadedItemType]): + cache_service = self._get_cache_service() + if cache_service is None: + return + return cache_service.save_to_cache(item_cache) + + def _load_from_cache(self) -> Union[CommonLoadedItemCache[CommonLoadedItemType], None]: + cache_service = self._get_cache_service() + if cache_service is None: + return + return cache_service.load_from_cache() + + def _clear_cache(self) -> None: + cache_service = self._get_cache_service() + if cache_service is None: + return + return cache_service.clear_cache() + + def _get_cache_service(self) -> Union[CommonLoadedItemCacheService[CommonLoadedItemType], None]: + return None + + def locate_by_identifier(self, identifier: str) -> Union[CommonLoadedItemType, None]: + """Locate an item by an identifier.""" + if identifier is None: + return None + return self.loaded_items.get(identifier, None) + + def _get_checksums(self) -> Tuple[Any]: + checksums: List[Any] = list() + for item_loader in self.item_loaders: + for new_checksum_data in item_loader.get_checksum_data_gen(): + checksums.append(new_checksum_data) + return tuple(checksums) + + def _update_cache(self) -> bool: + cache_service = self._get_cache_service() + if cache_service is None: + self.log.debug(f'No cache service found. {self.__class__.__name__}') + return False + for item_loader in self.item_loaders: + for new_checksum_data in item_loader.get_checksum_data_gen(): + if cache_service.cache_needs_update(new_checksum_data): + self.log.debug(f'Found a checksum that was different. {self.__class__.__name__} {new_checksum_data}') + return True + self.log.debug(f'Cache does not need update. {self.__class__.__name__}') + return False + + def _load(self) -> Iterator[CommonLoadedItemType]: + total_invalid = 0 + total_valid = 0 + for item_loader in self.item_loaders: + for item in item_loader.load(): + if item is None: + total_valid -= 1 + total_invalid += 1 + continue + yield item + self.log.format_with_message('Done loading for loader.', loader=item_loader) + self._total += item_loader.total + self._total_valid += item_loader.total_valid + total_valid + self._total_invalid += item_loader.total_invalid + total_invalid + + def _add_additional_item_data(self, item: CommonLoadedItemType) -> None: + raise NotImplementedError() diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/dtos/__init__.py b/Scripts/s4ap/sims4communitylib/systems/item_query/dtos/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/systems/item_query/dtos/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/dtos/common_loaded_item.py b/Scripts/s4ap/sims4communitylib/systems/item_query/dtos/common_loaded_item.py new file mode 100644 index 0000000..5b7767c --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/systems/item_query/dtos/common_loaded_item.py @@ -0,0 +1,198 @@ +""" +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 +""" +from typing import Union, Tuple, Any, Set, Iterator, Dict, Type + +from sims4communitylib.classes.serialization.common_serializable import CommonSerializable +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.logging.has_class_log import HasClassLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.utils.common_log_registry import CommonLog + + +class CommonLoadedItem(CommonSerializable, HasClassLog): + """ Contains information about an item that was loaded from a Snippet. """ + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + raise NotImplementedError() + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + raise NotImplementedError() + + def __init__( + self, + tags: Set[Any], + is_original: bool = False + ): + super().__init__() + HasClassLog.__init__(self) + self._tags = tuple(tags) + if is_original: + self._original = self + else: + self._original = self.clone() + self.is_original = is_original + # These are set to None initially to prevent the item from not being able to find them. + self._identifier = None + self._identifiers_backwards_compatible = None + self._identifier = self._get_identifier().lower().strip() + self._identifiers_backwards_compatible = tuple([identifier.lower().strip() for identifier in self._get_backwards_compatible_identifiers()]) + + @property + def original(self) -> 'CommonLoadedItem': + """The original unmodified item.""" + return self._original + + @property + def identifier(self) -> str: + """ The identifier of the item. """ + return self._identifier + + @property + def identifiers_backwards_compatible(self) -> Tuple[str]: + """ The backwards compatible identifier of the item. """ + return self._identifiers_backwards_compatible + + def _get_backwards_compatible_identifiers(self) -> Tuple[str]: + """Create a collection of old hashed identifiers for the item, in case the original identifier changes.""" + return tuple() + + def _get_identifier(self) -> str: + """ Creates a hashed identifier for the item. """ + raise NotImplementedError() + + @property + def short_name(self) -> str: + """ A short name for the item. """ + return self.identifier + + @property + def is_available(self) -> bool: + """Determine if the item is available.""" + return True + + @property + def tags(self) -> Tuple[Any]: + """ A collection of tags that apply to the item. """ + return self._tags + + @tags.setter + def tags(self, value: Iterator[Any]): + self._tags = tuple(value) + + def has_tag(self, tag: Any) -> bool: + """ Determine if the item has a tag. """ + return tag in self.tags + + def has_any_tags(self, tags: Iterator[Any]) -> CommonTestResult: + """ Determine if the item has any of the specified tags. """ + for tag in tags: + if self.has_tag(tag): + return CommonTestResult(True, reason=f'Has tag {tag}') + tags_text = ', '.join([str(tag) for tag in tags]) + return CommonTestResult(False, reason=f'Missing tags {tags_text}') + + def has_all_tags(self, tags: Iterator[Any]) -> CommonTestResult: + """ Determine if the item has all the specified tags. """ + for tag in tags: + if not self.has_tag(tag): + return CommonTestResult(False, reason=f'Missing tag {tag}') + return CommonTestResult.TRUE + + def add_tag(self, tag: Any): + """ Add a tag to the item. """ + new_tags = list(self._tags) + if tag not in new_tags: + new_tags.append(tag) + self._tags = tuple(new_tags) + + def add_tags(self, tags: Iterator[Any]): + """ Add tags to the item. """ + new_tags = list(self._tags) + for tag in tags: + if tag not in new_tags: + new_tags.append(tag) + self._tags = tuple(new_tags) + + def replace_tag(self, tag_to_remove: Any, tag_to_add: Any): + """ Replace one tag with another on the item. """ + self.remove_tags((tag_to_remove,)) + self.add_tags((tag_to_add,)) + + def remove_tag(self, tag: Any): + """ Remove a tag from the item. """ + return self.remove_tags((tag, )) + + def remove_tags(self, tags: Iterator[Any]): + """ Remove tags from the item. """ + new_tags = list(self._tags) + for tag in tags: + if tag in new_tags: + new_tags.remove(tag) + self._tags = tuple(new_tags) + + def verify(self) -> CommonTestResult: + """Verify the item.""" + raise NotImplementedError() + + def clone(self) -> 'CommonLoadedItem': + """Clone the item.""" + raise NotImplementedError() + + def __eq__(self, other: 'CommonLoadedItem') -> bool: + if not isinstance(other, CommonLoadedItem): + return False + return self.identifier == other.identifier + + def __hash__(self) -> int: + return hash((str(self.identifier),)) + + def __repr__(self) -> str: + tags_str = ', '.join((tag.name if hasattr(tag, 'name') else tag for tag in self.tags)) + return f'ID: {self.identifier}' \ + f'\nTags: ({tags_str})' + + def __str__(self) -> str: + return self.__repr__() + + @classmethod + def load_from_package( + cls, + package_item: Any, + tuning_name: str, + log: CommonLog + ) -> Union['CommonLoadedItem', None]: + """load_from_package(package_item, tuning_name, log) + + Load an item from a package. + + :param package_item: A package item. + :type package_item: Any + :param tuning_name: The name of the tuning being read from. + :type tuning_name: str + :param log: A log for warnings. + :type log: CommonLog + :return: An item or None if an error occurs. + :rtype: Union[CommonLoadedItem, None] + """ + raise NotImplementedError() + + def clear_cached_data(self) -> None: + """Clear cached data.""" + pass + + # noinspection PyMissingOrEmptyDocstring + def serialize(self: 'CommonLoadedItem') -> Union[str, Dict[str, Any]]: + raise NotImplementedError() + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def deserialize(cls: Type['CommonLoadedItem'], data: Union[str, Dict[str, Any]]) -> Union['CommonLoadedItem', None]: + raise NotImplementedError() diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/enums/__init__.py b/Scripts/s4ap/sims4communitylib/systems/item_query/enums/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/systems/item_query/enums/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/enums/common_query_method_type.py b/Scripts/s4ap/sims4communitylib/systems/item_query/enums/common_query_method_type.py new file mode 100644 index 0000000..3837ae6 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/systems/item_query/enums/common_query_method_type.py @@ -0,0 +1,16 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt + + +class CommonQueryMethodType(CommonInt): + """ Various methods to query for items. """ + ALL_PLUS_ANY: 'CommonQueryMethodType' = ... + ALL_INTERSECT_ANY: 'CommonQueryMethodType' = ... + ALL_PLUS_ANY_MUST_HAVE_ONE: 'CommonQueryMethodType' = ... + ALL_INTERSECT_ANY_MUST_HAVE_ONE: 'CommonQueryMethodType' = ... diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/item_loaders/__init__.py b/Scripts/s4ap/sims4communitylib/systems/item_query/item_loaders/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/systems/item_query/item_loaders/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/item_loaders/common_base_item_loader.py b/Scripts/s4ap/sims4communitylib/systems/item_query/item_loaders/common_base_item_loader.py new file mode 100644 index 0000000..5491f12 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/systems/item_query/item_loaders/common_base_item_loader.py @@ -0,0 +1,106 @@ +""" +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 +""" +from typing import Tuple, Iterator, Any, Union, TypeVar, Generic + +from sims4communitylib.systems.item_query.dtos.common_loaded_item import CommonLoadedItem +from sims4.resources import Types +from sims4communitylib.logging.has_log import HasLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.services.common_service import CommonService +from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + +CommonLoadedItemType = TypeVar('CommonLoadedItemType', bound=CommonLoadedItem) + + +class CommonBaseItemLoader(CommonService, HasLog, Generic[CommonLoadedItemType]): + """ Loads items. """ + + # noinspection PyMissingOrEmptyDocstring + @property + def mod_identity(self) -> CommonModIdentity: + raise NotImplementedError() + + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + raise NotImplementedError() + + @property + def snippet_names(self) -> Tuple[str]: + """ The names of snippets containing items. """ + raise NotImplementedError() + + def __init__(self) -> None: + super().__init__() + self._total = 0 + self._total_valid = 0 + self._total_invalid = 0 + + @property + def total(self) -> int: + """The total number of items that were looked at""" + return self._total + + @property + def total_valid(self) -> int: + """The total number of items that were valid.""" + return self._total_valid + + @property + def total_invalid(self) -> int: + """The total number of items that were invalid.""" + return self._total_invalid + + def get_checksum_data_gen(self) -> Iterator[Tuple[str, int, int]]: + """Generate checksums.""" + raise NotImplementedError() + + def load(self) -> Iterator[CommonLoadedItemType]: + """load() + + Loads all items. + + :return: An iterator of the valid items. + :rtype: Iterator[Any] + """ + self._total = 0 + self._total_valid = 0 + self._total_invalid = 0 + snippet_names: Tuple[str] = self.snippet_names + for item_package in CommonResourceUtils.load_instances_with_any_tags(Types.SNIPPET, snippet_names): + tuning_name = item_package.__name__ + try: + items = tuple(self._load(item_package, tuning_name)) + + total = 0 + total_valid = 0 + total_invalid = 0 + + for item in items: + total += 1 + + if item is None: + total_invalid += 1 + continue + verify_result = item.verify() + if verify_result: + total_valid += 1 + yield item + else: + self.log.warn(f'{item.short_name} was not valid. Reason: {verify_result}') + total_invalid += 1 + + self._total += total + self._total_valid += total_valid + self._total_invalid += total_invalid + self.log.warn(f'Loaded {tuning_name}, Valid: {total_valid}, Total Invalid: {total_invalid}, Total: {total}') + except Exception as ex: + self.log.error(f'An error occurred while parsing items from snippet \'{tuning_name}\'', exception=ex) + + def _load(self, package_item: Any, tuning_name: str) -> Tuple[Union[CommonLoadedItemType, None]]: + raise NotImplementedError() diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/item_tests/__init__.py b/Scripts/s4ap/sims4communitylib/systems/item_query/item_tests/__init__.py new file mode 100644 index 0000000..3251898 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/systems/item_query/item_tests/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" \ No newline at end of file diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/item_tests/common_loaded_item_is_available_test.py b/Scripts/s4ap/sims4communitylib/systems/item_query/item_tests/common_loaded_item_is_available_test.py new file mode 100644 index 0000000..0fbd09d --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/systems/item_query/item_tests/common_loaded_item_is_available_test.py @@ -0,0 +1,32 @@ +""" +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 +""" +from sims4communitylib.systems.item_query.dtos.common_loaded_item import CommonLoadedItem +from sims4communitylib.systems.item_query.item_tests.common_loaded_item_test import CommonLoadedItemTest +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo + + +class CommonLoadedItemIsAvailableTest(CommonLoadedItemTest[CommonLoadedItem]): + """ Test for an item is available. """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + return ModInfo.get_identity() + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 'common_loaded_item_is_available' + + # noinspection PyMissingOrEmptyDocstring + def test_item(self, item: CommonLoadedItem) -> CommonTestResult: + if not item.is_available: + return CommonTestResult(False, reason='Item is not available.') + return CommonTestResult.TRUE diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/item_tests/common_loaded_item_is_not_available_test.py b/Scripts/s4ap/sims4communitylib/systems/item_query/item_tests/common_loaded_item_is_not_available_test.py new file mode 100644 index 0000000..cc606f3 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/systems/item_query/item_tests/common_loaded_item_is_not_available_test.py @@ -0,0 +1,32 @@ +""" +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 +""" +from sims4communitylib.systems.item_query.dtos.common_loaded_item import CommonLoadedItem +from sims4communitylib.systems.item_query.item_tests.common_loaded_item_test import CommonLoadedItemTest +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo + + +class CommonLoadedItemIsNotAvailableTest(CommonLoadedItemTest[CommonLoadedItem]): + """ Test for an item to not be available. """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + return ModInfo.get_identity() + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 'common_loaded_item_is_not_available' + + # noinspection PyMissingOrEmptyDocstring + def test_item(self, item: CommonLoadedItem) -> CommonTestResult: + if item.is_available: + return CommonTestResult(False, reason='Item is available.') + return CommonTestResult.TRUE diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/item_tests/common_loaded_item_test.py b/Scripts/s4ap/sims4communitylib/systems/item_query/item_tests/common_loaded_item_test.py new file mode 100644 index 0000000..2d9594e --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/systems/item_query/item_tests/common_loaded_item_test.py @@ -0,0 +1,34 @@ +""" +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 +""" +from typing import TypeVar, Generic + +from sims4communitylib.systems.item_query.dtos.common_loaded_item import CommonLoadedItem +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.logging.has_class_log import HasClassLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity + + +CommonLoadedItemType = TypeVar('CommonLoadedItemType', bound=CommonLoadedItem) + + +class CommonLoadedItemTest(HasClassLog, Generic[CommonLoadedItemType]): + """ A test that is run to test a loaded item. """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + raise NotImplementedError() + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + raise NotImplementedError() + + def test_item(self, item: CommonLoadedItemType) -> CommonTestResult: + """Test an item for a match.""" + raise NotImplementedError() diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/persistence/__init__.py b/Scripts/s4ap/sims4communitylib/systems/item_query/persistence/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/systems/item_query/persistence/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/persistence/common_loaded_item_cache.py b/Scripts/s4ap/sims4communitylib/systems/item_query/persistence/common_loaded_item_cache.py new file mode 100644 index 0000000..f5ef1b9 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/systems/item_query/persistence/common_loaded_item_cache.py @@ -0,0 +1,18 @@ +""" +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 +""" +from typing import TypeVar, Generic + +from sims4communitylib.systems.item_query.dtos.common_loaded_item import CommonLoadedItem +from sims4communitylib.systems.caching.common_serializable_object_cache import CommonSerializableObjectCache + +CommonLoadedItemCacheType = TypeVar('CommonLoadedItemCacheType', bound=CommonLoadedItem) + + +class CommonLoadedItemCache(CommonSerializableObjectCache[CommonLoadedItemCacheType], Generic[CommonLoadedItemCacheType]): + """A cache of Loaded Items.""" + pass diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/persistence/common_loaded_item_cache_service.py b/Scripts/s4ap/sims4communitylib/systems/item_query/persistence/common_loaded_item_cache_service.py new file mode 100644 index 0000000..0d4565b --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/systems/item_query/persistence/common_loaded_item_cache_service.py @@ -0,0 +1,45 @@ +""" +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 +""" +from typing import Generic, TypeVar, Tuple, Union, Dict, Any + +from sims4communitylib.systems.item_query.dtos.common_loaded_item import CommonLoadedItem +from sims4communitylib.systems.item_query.persistence.common_loaded_item_cache import CommonLoadedItemCache +from sims4communitylib.systems.caching.common_serializable_object_cache_service import \ + CommonSerializableObjectCacheService +from sims4communitylib.mod_support.mod_identity import CommonModIdentity + + +CommonLoadedItemCacheType = TypeVar('CommonLoadedItemCacheType', bound=CommonLoadedItemCache[CommonLoadedItem]) + + +class CommonLoadedItemCacheService(CommonSerializableObjectCacheService[CommonLoadedItemCacheType], Generic[CommonLoadedItemCacheType]): + """A service that manages a cache of Loaded Items.""" + + # noinspection PyMissingOrEmptyDocstring + @property + def mod_identity(self) -> CommonModIdentity: + raise NotImplementedError() + + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + return 'common_loaded_item_cache_service' + + @property + def _cache_file_name(self) -> str: + raise NotImplementedError() + + def _deserialize_cache(self, data: Union[str, Dict[str, Any]]) -> CommonLoadedItemCacheType: + raise NotImplementedError() + + # noinspection PyMissingOrEmptyDocstring + def create_cache(self, objects: Tuple[CommonLoadedItem], checksums: Tuple[Any]) -> CommonLoadedItemCacheType: + checksum_data = dict() + for (snippet_name, snippet_id, checksum_value) in checksums: + checksum_data[f'{snippet_name}-{snippet_id}'] = checksum_value + return CommonLoadedItemCacheType[Any](objects, checksum_data) diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/query/__init__.py b/Scripts/s4ap/sims4communitylib/systems/item_query/query/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/systems/item_query/query/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_filter.py b/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_filter.py new file mode 100644 index 0000000..67fdca6 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_filter.py @@ -0,0 +1,93 @@ +""" +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 +""" +from typing import Tuple, Union, TypeVar, Generic + +from sims4communitylib.enums.enumtypes.common_int import CommonInt +from sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags +from sims4communitylib.systems.item_query.query.common_loaded_item_key import CommonLoadedItemKey +from sims4communitylib.logging.has_log import HasLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity + +ItemKeyType = TypeVar('ItemKeyType', int, CommonInt, CommonIntFlags) + + +class CommonLoadedItemFilter(HasLog, Generic[ItemKeyType]): + """ A filter for use when querying loaded items. """ + + # noinspection PyMissingOrEmptyDocstring + @property + def mod_identity(self) -> CommonModIdentity: + raise NotImplementedError() + + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + raise NotImplementedError() + + def __init__( + self, + match_all: bool, + match_at_least_one: bool = False, + exclude: bool = False, + key_type: ItemKeyType = None + ): + super().__init__() + self._match_all = match_all + self._match_at_least_one = match_at_least_one + self._exclude = exclude + self._key_type = key_type + + @property + def _match_text(self) -> str: + match_text = '' + if self.match_all and not self.exclude: + match_text = 'has all' + if self.match_at_least_one and not self.exclude: + match_text = 'has any' + if self.exclude: + match_text = 'has none' + return match_text + + @property + def key_type(self) -> Union[ItemKeyType, None]: + """ The type of keys produced by this filter. """ + return self._key_type + + @property + def match_all(self) -> bool: + """ + Determine if we should match all (True) the keys or any (False) of them. + """ + return self._match_all + + @property + def exclude(self) -> bool: + """ + Determine if we should not have any of the keys. + """ + return self._exclude + + @property + def match_at_least_one(self) -> bool: + """ + Determine if we should match at least one key. + """ + return self._match_at_least_one + + def get_keys(self) -> Tuple[CommonLoadedItemKey]: + """ Retrieve the keys of this filter. """ + return tuple() + + def __repr__(self) -> str: + return self.__str__() + + def __str__(self) -> str: + match_text = self._match_text + if self._key_type is None: + return f'{self.__class__.__name__}, {match_text}' + return f'{self._key_type.name}, {match_text}' diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_filter_request.py b/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_filter_request.py new file mode 100644 index 0000000..d4b41c2 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_filter_request.py @@ -0,0 +1,131 @@ +""" +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 +""" +from pprint import pformat +from typing import Tuple, Callable, List, TypeVar, Generic, Iterator + +from sims4communitylib.systems.item_query.enums.common_query_method_type import CommonQueryMethodType +from sims4communitylib.systems.item_query.item_tests.common_loaded_item_test import CommonLoadedItemTest +from sims4communitylib.systems.item_query.query.common_loaded_item_key import CommonLoadedItemKey +from sims4communitylib.systems.item_query.query.common_loaded_item_filter import CommonLoadedItemFilter + +CommonLoadedItemFilterType = TypeVar('CommonLoadedItemFilterType', bound=CommonLoadedItemFilter) +CommonLoadedItemTestType = TypeVar('CommonLoadedItemTestType', bound=CommonLoadedItemTest) +CommonLoadedItemKeyType = TypeVar('CommonLoadedItemKeyType', bound=CommonLoadedItemKey) + + +class CommonLoadedItemFilterRequest(Generic[CommonLoadedItemFilterType, CommonLoadedItemTestType, CommonLoadedItemKeyType]): + """ A request used to locate things. """ + def __init__( + self, + item_filters: Iterator[CommonLoadedItemFilterType], + item_tests: Iterator[CommonLoadedItemTestType], + query_type: CommonQueryMethodType = CommonQueryMethodType.ALL_INTERSECT_ANY + ): + self._item_filters = tuple(item_filters) + self._item_tests = tuple(item_tests) + self._query_type = query_type + self._include_all_keys = None + self._include_any_keys = None + self._exclude_keys = None + self._must_match_at_least_one_key_sets = None + + @property + def query_type(self) -> CommonQueryMethodType: + """ The method used to query items. """ + return self._query_type + + @property + def item_tests(self) -> Tuple[CommonLoadedItemTestType]: + """Tests to run on items.""" + return self._item_tests + + @property + def item_filters(self) -> Tuple[CommonLoadedItemFilterType]: + """Filters used to filter items.""" + return self._item_filters + + @property + def include_all_keys(self) -> Tuple[CommonLoadedItemKeyType]: + """ Must have all these keys to match. """ + if self._include_all_keys is not None: + return self._include_all_keys + + def _include_item_filter(_item_filter: CommonLoadedItemFilterType) -> bool: + return _item_filter.match_all and not _item_filter.exclude + + self._include_all_keys = self._get_item_keys(_include_item_filter) + return self._include_all_keys + + @property + def include_any_keys(self) -> Tuple[CommonLoadedItemKeyType]: + """ Must have any of these keys to match. """ + if self._include_any_keys is not None: + return self._include_any_keys + + def _include_item_filter(_item_filter: CommonLoadedItemFilterType) -> bool: + return not _item_filter.match_all and not _item_filter.exclude and not _item_filter.match_at_least_one + + self._include_any_keys = self._get_item_keys(_include_item_filter) + return self._include_any_keys + + @property + def exclude_keys(self) -> Tuple[CommonLoadedItemKeyType]: + """ Must NOT have any of these keys to match. """ + if self._exclude_keys is not None: + return self._exclude_keys + + def _include_item_filter(_item_filter: CommonLoadedItemFilterType) -> bool: + return _item_filter.exclude + + self._exclude_keys = self._get_item_keys(_include_item_filter) + return self._exclude_keys + + @property + def must_match_at_least_one_key_sets(self) -> Tuple[Tuple[CommonLoadedItemKeyType]]: + """ Must match at least one of these keys. """ + if self._must_match_at_least_one_key_sets is not None: + return self._must_match_at_least_one_key_sets + + def _get_match_at_least_one_item_filter_sets() -> Tuple[Tuple[CommonLoadedItemKeyType]]: + item_keys: List[Tuple[CommonLoadedItemKeyType]] = list() + for _item_filter in self._item_filters: + if _item_filter.exclude or not _item_filter.match_at_least_one: + continue + item_keys.append(_item_filter.get_keys()) + return tuple(item_keys) + + self._must_match_at_least_one_key_sets = _get_match_at_least_one_item_filter_sets() + return self._must_match_at_least_one_key_sets + + def _get_item_keys(self, include_item_filter_callback: Callable[[CommonLoadedItemFilterType], bool]) -> Tuple[CommonLoadedItemKeyType]: + item_keys: List[CommonLoadedItemKeyType] = [] + for _item_filter in self._item_filters: + if not include_item_filter_callback(_item_filter): + continue + for item_key in _item_filter.get_keys(): + item_keys.append(item_key) + return tuple(item_keys) + + def __repr__(self) -> str: + return '{}:\n' \ + 'Include All: {}\n' \ + 'Include Any: {}\n' \ + 'Exclude All: {}\n' \ + 'Match One Sets: {}\n' \ + 'Query Type: {}'\ + .format( + self.__class__.__name__, + pformat(self.include_all_keys), + pformat(self.include_any_keys), + pformat(self.exclude_keys), + pformat(self.must_match_at_least_one_key_sets), + pformat(self.query_type) + ) + + def __str__(self) -> str: + return self.__repr__() diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_key.py b/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_key.py new file mode 100644 index 0000000..3bddcaf --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_key.py @@ -0,0 +1,42 @@ +""" +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 +""" +from typing import Any, Tuple, TypeVar, Generic + +from sims4communitylib.enums.enumtypes.common_int import CommonInt +from sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags + +ItemKeyType = TypeVar('ItemKeyType', int, CommonInt, CommonIntFlags) + + +class CommonLoadedItemKey(Generic[ItemKeyType]): + """ A key for a loaded item. """ + def __init__(self, key_type: ItemKeyType, value: Any): + self._key_type = key_type + self._value = value + self._key = (key_type, value) + + @property + def key_type(self) -> ItemKeyType: + """ The type of key. """ + return self._key_type + + @property + def value(self) -> Any: + """ The value. """ + return self._value + + @property + def key(self) -> Tuple[ItemKeyType, Any]: + """ The combination of the type and value. """ + return self._key + + def __repr__(self) -> str: + return str(self.key) + + def __str__(self) -> str: + return self.__repr__() diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_organizer.py b/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_organizer.py new file mode 100644 index 0000000..f6fd7f8 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_organizer.py @@ -0,0 +1,35 @@ +""" +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 +""" +from typing import Any, Tuple, Generic, TypeVar + +from sims4communitylib.enums.enumtypes.common_int import CommonInt +from sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags +from sims4communitylib.systems.item_query.dtos.common_loaded_item import CommonLoadedItem + +CommonLoadedItemKeyType = TypeVar('CommonLoadedItemKeyType', int, CommonInt, CommonIntFlags) +CommonLoadedItemType = TypeVar('CommonLoadedItemType', bound=CommonLoadedItem) + + +class CommonLoadedItemOrganizer(Generic[CommonLoadedItemKeyType, CommonLoadedItemType]): + """ An organizer of items. """ + def __init__(self, key_type: CommonLoadedItemKeyType): + self._key_type = key_type + + @property + def key_type(self) -> CommonLoadedItemKeyType: + """ The type of keys this organizer produces. """ + return self._key_type + + def get_key_values(self, item: CommonLoadedItemType) -> Tuple[Any]: + """ Retrieve key values for this organizer. """ + raise NotImplementedError + + # noinspection PyUnusedLocal + def applies(self, item: CommonLoadedItemType) -> bool: + """ Determine if this organizer applies to an item. """ + return True diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_query_utils.py b/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_query_utils.py new file mode 100644 index 0000000..ecdf2ca --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_query_utils.py @@ -0,0 +1,160 @@ +""" +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 +""" +import random +from typing import Tuple, Iterator, Union, Generic, TypeVar + +from sims4communitylib.systems.item_query.item_tests.common_loaded_item_test import CommonLoadedItemTest +from sims4communitylib.systems.item_query.item_tests.common_loaded_item_is_available_test import \ + CommonLoadedItemIsAvailableTest +from sims4communitylib.systems.item_query.query.common_loaded_item_filter import CommonLoadedItemFilter + +from sims4communitylib.systems.item_query.enums.common_query_method_type import CommonQueryMethodType +from sims4communitylib.systems.item_query.dtos.common_loaded_item import CommonLoadedItem +from sims4communitylib.systems.item_query.common_loaded_item_query_registry import CommonLoadedItemQueryRegistry +from sims4communitylib.logging.has_log import HasLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.systems.item_query.query.common_loaded_item_filter_request import CommonLoadedItemFilterRequest + +CommonLoadedItemType = TypeVar('CommonLoadedItemType', bound=CommonLoadedItem) + + +class CommonLoadedItemQueryUtils(HasLog, Generic[CommonLoadedItemType]): + """ Query for items using various filter configurations. """ + + # noinspection PyMissingOrEmptyDocstring + @property + def mod_identity(self) -> CommonModIdentity: + raise NotImplementedError() + + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + raise NotImplementedError() + + @property + def _query_registry(self) -> CommonLoadedItemQueryRegistry: + raise NotImplementedError() + + def get_all(self) -> Tuple[CommonLoadedItemType]: + """ Get all items. """ + return self._query_registry.get_all() + + def locate_by_identifier(self, identifier: str) -> Union[CommonLoadedItemType, None]: + """ Locate a CAS Part by its identifier. """ + return self._query_registry._registry.locate_by_identifier(identifier) + + def create_filter_request( + self, + item_filters: Tuple[CommonLoadedItemFilter], + item_tests: Iterator[CommonLoadedItemTest], + query_type: CommonQueryMethodType = CommonQueryMethodType.ALL_INTERSECT_ANY + ) -> CommonLoadedItemFilterRequest: + """ Create a filter request for items. """ + return CommonLoadedItemFilterRequest(item_filters, item_tests, query_type=query_type) + + def has_for_filters( + self, + item_filters: Tuple[CommonLoadedItemFilter], + item_tests: Iterator[CommonLoadedItemTest], + query_type: CommonQueryMethodType = CommonQueryMethodType.ALL_INTERSECT_ANY + ) -> bool: + """Determine if any items are available that match filters.""" + filter_request = self.create_filter_request(item_filters, item_tests, query_type=query_type) + return self._query_registry.has_items((filter_request, )) + + def get_for_filters_gen( + self, + item_filters: Tuple[CommonLoadedItemFilter], + item_tests: Iterator[CommonLoadedItemTest], + query_type: CommonQueryMethodType = CommonQueryMethodType.ALL_INTERSECT_ANY + ) -> Iterator[CommonLoadedItemType]: + """ Get all items matching filters. """ + self.log.format_with_message( + 'Getting items that match filters', + item_filters=item_filters, + item_tests=item_tests, + query_type=query_type + ) + filter_request = self.create_filter_request(item_filters, item_tests, query_type=query_type) + query_result = self._query_registry.get_items_gen((filter_request,)) + had_items = False + for item in query_result: + had_items = True + yield item + if not had_items: + self.log.debug('No items found matching filters.') + + def get_random_for_filters( + self, + item_filters: Tuple[CommonLoadedItemFilter], + item_tests: Tuple[CommonLoadedItemTest], + query_type: CommonQueryMethodType = CommonQueryMethodType.ALL_INTERSECT_ANY + ) -> Union[CommonLoadedItemType, None]: + """Get a random item that matches filters.""" + if not self.has_for_filters( + item_filters, + item_tests, + query_type=query_type + ): + return None + + items = tuple(self.get_for_filters_gen( + item_filters, + item_tests, + query_type=query_type + )) + if not items: + return None + return random.choice(items) + + def has_available_for_filters( + self, + item_filters: Tuple[CommonLoadedItemFilter], + item_tests: Iterator[CommonLoadedItemTest], + query_type: CommonQueryMethodType = CommonQueryMethodType.ALL_INTERSECT_ANY + ) -> bool: + """Determine if any items are available that match filters and are marked as being available.""" + item_tests: Tuple[CommonLoadedItemTest, ...] = ( + CommonLoadedItemIsAvailableTest(), + *item_tests + ) + return self.has_for_filters( + item_filters, + item_tests, + query_type=query_type + ) + + def get_available_for_filters_gen( + self, + item_filters: Tuple[CommonLoadedItemFilter], + item_tests: Tuple[CommonLoadedItemTest], + query_type: CommonQueryMethodType = CommonQueryMethodType.ALL_INTERSECT_ANY + ) -> Iterator[CommonLoadedItemType]: + """Get all items matching filters that are marked as being available.""" + item_tests: Tuple[CommonLoadedItemTest, ...] = ( + CommonLoadedItemIsAvailableTest(), + *item_tests + ) + yield from self.get_for_filters_gen( + item_filters, + item_tests, + query_type=query_type + ) + + def get_random_from_available_for_filters( + self, + item_filters: Tuple[CommonLoadedItemFilter], + item_tests: Tuple[CommonLoadedItemTest], + query_type: CommonQueryMethodType = CommonQueryMethodType.ALL_INTERSECT_ANY + ) -> Union[CommonLoadedItemType, None]: + """Get a random item that matches filters and is marked as being available.""" + item_tests: Tuple[CommonLoadedItemTest, ...] = ( + CommonLoadedItemIsAvailableTest(), + *item_tests + ) + return self.get_random_for_filters(item_filters, item_tests, query_type=query_type) diff --git a/Scripts/s4ap/sims4communitylib/systems/settings/__init__.py b/Scripts/s4ap/sims4communitylib/systems/settings/__init__.py new file mode 100644 index 0000000..3251898 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/systems/settings/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" \ No newline at end of file diff --git a/Scripts/s4ap/sims4communitylib/systems/settings/common_setting_utils.py b/Scripts/s4ap/sims4communitylib/systems/settings/common_setting_utils.py new file mode 100644 index 0000000..07aef38 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/systems/settings/common_setting_utils.py @@ -0,0 +1,112 @@ +""" +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 +""" +from typing import Any, Tuple, Callable, TypeVar, Type, Generic + +from sims4communitylib.classes.enums.common_versioned_enum_value_collection import CommonVersionedEnumValueCollection +from sims4communitylib.enums.enumtypes.common_int import CommonInt +from sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags +from sims4communitylib.enums.enumtypes.common_versioned_int import CommonVersionedInt +from sims4communitylib.enums.enumtypes.common_versioned_int_flags import CommonVersionedIntFlags +from sims4communitylib.systems.settings.common_settings_data_store import CommonSettingsDataStore +from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + +SettingEnumType = TypeVar('SettingEnumType', CommonInt, CommonIntFlags, CommonVersionedInt, CommonVersionedIntFlags) +SettingDataStoreType = TypeVar('SettingDataStoreType', bound=CommonSettingsDataStore) +SettingEnumValueCollectionType = TypeVar('SettingEnumValueCollectionType', bound=CommonVersionedEnumValueCollection) + + +class CommonSettingUtils(Generic[SettingDataStoreType]): + """ Utilities for settings. """ + @classmethod + def get_enum_tuple_setting(cls, key: str, enum_type: Type[SettingEnumType], invalid_enum_value: SettingEnumType) -> Tuple[SettingEnumType]: + """ Retrieve a setting that is a collection of enum values. """ + result: Tuple[SettingEnumType] = cls._get_tuple_enum_value(key, enum_type, invalid_enum_value) + return result + + @classmethod + def set_enum_tuple_setting(cls, key: str, value: Tuple[SettingEnumType]): + """ Set a setting that is a collection of enum values. """ + cls._set_tuple_enum_value(key, value) + + @classmethod + def get_enum_value_collection_setting(cls, key: str, enum_value_collection_type: Type[SettingEnumValueCollectionType]) -> SettingEnumValueCollectionType: + """ Retrieve an enum value collection setting. """ + result: SettingEnumValueCollectionType = cls._get_enum_value_collection(key, enum_value_collection_type) + return result + + @classmethod + def set_enum_value_collection_setting(cls, key: str, value: SettingEnumValueCollectionType): + """ Set an enum value collection setting. """ + cls._set_enum_value_collection(key, value) + + @classmethod + def _get_enum_value_collection(cls, key: str, enum_value_collection_type: Type[SettingEnumValueCollectionType]) -> SettingEnumValueCollectionType: + enum_value_collection = cls.get_value( + key, + encode=lambda _enum_data: _enum_data.serialize(), + decode=lambda _enum_data: enum_value_collection_type.deserialize(_enum_data) or cls._data_store().get_default_value_by_key(key) + ) + if not enum_value_collection: + return cls._data_store().get_default_value_by_key(key) + return enum_value_collection + + @classmethod + def _set_enum_value_collection(cls, key: str, value: SettingEnumValueCollectionType) -> None: + cls.set_value( + key, + value, + encode=lambda _enum_value: _enum_value.serialize(), + ) + + @classmethod + def _get_enum_value(cls, key: str, enum_type: Type[SettingEnumType], invalid_enum_value: SettingEnumType) -> SettingEnumType: + return cls.get_value( + key, + encode=lambda _enum_val: _enum_val.name, + decode=lambda _enum_str: CommonResourceUtils.get_enum_by_name(_enum_str, enum_type, default_value=invalid_enum_value) + ) + + @classmethod + def _set_enum_value(cls, key: str, value: SettingEnumType): + return cls.set_value( + key, + value, + encode=lambda _enum_val: _enum_val.name, + ) + + @classmethod + def _get_tuple_enum_value(cls, key: str, enum_type: Type[SettingEnumType], invalid_enum_value: SettingEnumType) -> Tuple[SettingEnumType]: + enum_val_list = cls.get_value( + key, + encode=lambda _enum_val_list: [_enum_val.name if hasattr(_enum_val, 'name') else _enum_val for _enum_val in _enum_val_list], + decode=lambda _str_val_list: [CommonResourceUtils.get_enum_by_name(enum_str, enum_type, default_value=invalid_enum_value) if isinstance(enum_str, str) else enum_str for enum_str in _str_val_list] + ) + result: Tuple[SettingEnumType, ...] = tuple([enum_val for enum_val in enum_val_list if enum_val != invalid_enum_value]) + return result + + @classmethod + def _set_tuple_enum_value(cls, key: str, value: Tuple[SettingEnumType]) -> None: + cls.set_value( + key, + value, + encode=lambda _enum_list: [enum_value.name for enum_value in _enum_list], + ) + + @classmethod + def get_value(cls, key: str, encode: Callable[[Any], Any] = None, decode: Callable[[Any], Any] = None) -> Any: + """Get a value using an encoding and decoding.""" + return cls._data_store().get_value_by_key(key, encode=encode, decode=decode) + + @classmethod + def set_value(cls, key: str, value: Any, encode: Callable[[Any], Any] = None) -> Any: + """Set a value using an encoding and decoding.""" + return cls._data_store().set_value_by_key(key, value, encode=encode) + + @classmethod + def _data_store(cls) -> SettingDataStoreType: + raise NotImplementedError() diff --git a/Scripts/s4ap/sims4communitylib/systems/settings/common_settings_data_manager.py b/Scripts/s4ap/sims4communitylib/systems/settings/common_settings_data_manager.py new file mode 100644 index 0000000..13c5ec3 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/systems/settings/common_settings_data_manager.py @@ -0,0 +1,41 @@ +""" +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 +""" +from typing import Tuple +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.persistence.data_management.common_data_manager import CommonDataManager +from sims4communitylib.persistence.persistence_services.common_persistence_service import CommonPersistenceService + + +class CommonSettingsDataManager(CommonDataManager): + """ Manage a storage of settings data. """ + @classmethod + def get_identifier(cls) -> str: + """Retrieve the identifier of the data manager. This identifier is used in the name of the settings file.""" + if hasattr(cls, 'IDENTIFIER'): + return cls.IDENTIFIER + raise NotImplementedError() + + # noinspection PyMissingOrEmptyDocstring + @property + def mod_identity(self) -> CommonModIdentity: + raise NotImplementedError() + + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + raise NotImplementedError() + + # noinspection PyMissingOrEmptyDocstring + @property + def persistence_services(self) -> Tuple[CommonPersistenceService]: + from sims4communitylib.persistence.persistence_services.common_file_persistence_service import \ + CommonFilePersistenceService + result: Tuple[CommonPersistenceService] = ( + CommonFilePersistenceService(per_save=False), + ) + return result diff --git a/Scripts/s4ap/sims4communitylib/systems/settings/common_settings_data_manager_utils.py b/Scripts/s4ap/sims4communitylib/systems/settings/common_settings_data_manager_utils.py new file mode 100644 index 0000000..2553c43 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/systems/settings/common_settings_data_manager_utils.py @@ -0,0 +1,61 @@ +""" +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 +""" +from typing import Type, Union, Dict, Any, TypeVar + +from sims4communitylib.logging.has_log import HasLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.persistence.data_management.common_data_manager_registry import CommonDataManagerRegistry +from sims4communitylib.persistence.data_stores.common_data_store import CommonDataStore +from sims4communitylib.services.common_service import CommonService +from sims4communitylib.systems.settings.common_settings_data_manager import CommonSettingsDataManager + +CommonDataStoreType = TypeVar('CommonDataStoreType', bound=CommonDataStore) + + +class CommonSettingsDataManagerUtils(CommonService, HasLog): + """ Utilities to manage settings data. """ + + # noinspection PyMissingOrEmptyDocstring + @property + def mod_identity(self) -> CommonModIdentity: + raise NotImplementedError() + + # noinspection PyMissingOrEmptyDocstring + @property + def log_identifier(self) -> str: + raise NotImplementedError() + + @property + def _data_manager_type(self) -> Type[CommonSettingsDataManager]: + raise NotImplementedError() + + def __init__(self) -> None: + super().__init__() + self.__data_manager: Union[CommonSettingsDataManager, None] = None + + @property + def _data_manager(self) -> CommonSettingsDataManager: + """ The data manager containing data. """ + if self.__data_manager is None: + self.__data_manager = CommonDataManagerRegistry().locate_data_manager(self.mod_identity, identifier=self._data_manager_type.get_identifier()) + return self.__data_manager + + def _get_data_store(self, data_store_type: Type[CommonDataStoreType]) -> Union[CommonDataStoreType, None]: + return self._data_manager.get_data_store_by_type(data_store_type) + + def get_all_data(self) -> Dict[str, Dict[str, Any]]: + """ Get all data. """ + return self._data_manager._data_store_data + + def save(self) -> bool: + """ Save data. """ + return self._data_manager.save() + + def reset(self, prevent_save: bool = False) -> bool: + """ Reset data. """ + return self._data_manager.remove_all_data(prevent_save=prevent_save) diff --git a/Scripts/s4ap/sims4communitylib/systems/settings/common_settings_data_store.py b/Scripts/s4ap/sims4communitylib/systems/settings/common_settings_data_store.py new file mode 100644 index 0000000..1442338 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/systems/settings/common_settings_data_store.py @@ -0,0 +1,35 @@ +""" +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 +""" +from typing import Any, Dict + +from sims4communitylib.persistence.data_stores.common_data_store import CommonDataStore + + +class CommonSettingsDataStore(CommonDataStore): + """ Manages main settings for CM. """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_identifier(cls) -> str: + raise NotImplementedError() + + @property + def _version(self) -> int: + """This version indicates the current version of the default data. Changing this value will cause all settings to be wiped and replaced with the default data.""" + raise NotImplementedError() + + @property + def _default_data(self) -> Dict[str, Any]: + """ The data used as a default for the settings. """ + return { + self.__class__._VERSION: self._version, + **self._build_default_data() + }.copy() + + def _build_default_data(self) -> Dict[str, Any]: + raise NotImplementedError() diff --git a/Scripts/s4ap/sims4communitylib/testing/__init__.py b/Scripts/s4ap/sims4communitylib/testing/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/testing/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/testing/common_assertion_utils.py b/Scripts/s4ap/sims4communitylib/testing/common_assertion_utils.py new file mode 100644 index 0000000..e9cdd91 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/testing/common_assertion_utils.py @@ -0,0 +1,282 @@ +""" +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 +""" +from typing import Any, List, Union, Tuple, Callable, Dict + +from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.utils.common_collection_utils import CommonCollectionUtils + + +class CommonAssertionUtils: + """Utilities for used to assert within tests. They can be used outside tests if need be. + + """ + @staticmethod + def are_equal(value_one: Any, value_two: Any, message: str='') -> bool: + """are_equal(value_one, value_two, message='') + + Assert two values are equal to each other. + + If the values are both collections, then the values contained within will be asserted to be equal. + + .. note:: The order of the values in each collection is asserted. + + :param value_one: The first value. + :type value_one: Any + :param value_two: The second value. + :type value_two: Any + :param message: A custom message to include when the assertion fails. Default is Empty String. + :type message: str, optional + :return: True, if the assertion succeeds. + :rtype: bool + :exception AssertionError: when the assertion fails. + """ + if CommonCollectionUtils.is_collection(value_one) or CommonCollectionUtils.is_collection(value_two): + return CommonAssertionUtils.lists_are_equal(value_one, value_two, message=message) + if value_one != value_two: + raise AssertionError(f'{message}: expected\n {value_one}\n to be equal to\n {value_two}') + return True + + @staticmethod + def are_similar(value_one: Any, value_two: Any, message: str='') -> bool: + """are_similar(value_one, value_two, message='') + + Assert two values are similar. + + If the values are both collections, then the values contained within will be asserted to be similar. + + .. note:: The order of the values in each collection is ignored. + + :param value_one: The first value. + :type value_one: Any + :param value_two: The second value. + :type value_two: Any + :param message: A custom message to include when the assertion fails. Default is Empty String. + :type message: str, optional + :return: True, if the assertion succeeds. + :rtype: bool + :exception AssertionError: when the assertion fails. + """ + if CommonCollectionUtils.is_collection(value_one) or CommonCollectionUtils.is_collection(value_two): + return CommonAssertionUtils.list_contents_are_same(value_one, value_two, message=message) + if value_one != value_two: + raise AssertionError(f'{message}: expected\n {value_one}\n to be similar to\n {value_two}') + return True + + @staticmethod + def lists_are_equal(list_one: Union[Tuple[Any], List[Any]], list_two: Union[Tuple[Any], List[Any]], message: str='') -> bool: + """lists_are_equal(list_one, list_two, message='') + + Assert two collections contain tbe exact same values. + + .. note:: The order of the values in each collection will be asserted. + + :param list_one: The first value. (Can be any collection type) + :type list_one: Union[Tuple[Any], List[Any]] + :param list_two: The second value. (Can be any collection type) + :type list_two: Union[Tuple[Any], List[Any]] + :param message: A custom message to include when the assertion fails. Default is Empty String. + :type message: str, optional + :return: True, if the assertion succeeds. + :rtype: bool + :exception AssertionError: when the assertion fails. + """ + if not CommonCollectionUtils.is_collection(list_one): + raise AssertionError(f'{message}: expected\n {list_one}\n to be equal to\n {list_two}') + if not CommonCollectionUtils.is_collection(list_two): + raise AssertionError(f'{message}: expected\n {list_one}\n to be equal to\n {list_two}') + if len(list_one) != len(list_two): + raise AssertionError(f'{message}: expected\n {list_one}\n to be equal to\n {list_two}') + if isinstance(list_one, set) or isinstance(list_two, set): + return list_one == list_two + current_idx = 0 + while current_idx < len(list_one): + item_one = list_one[current_idx] + item_two = list_two[current_idx] + if item_one != item_two: + raise AssertionError(f'{message}: expected\n {list_one}\n to be equal to\n {list_two}\n Difference:\n {item_one}\n should be\n {item_two}\n at index {current_idx}') + current_idx += 1 + return True + + @staticmethod + def list_contents_are_same(list_one: Union[Tuple[Any], List[Any]], list_two: Union[Tuple[Any], List[Any]], message: str='') -> bool: + """list_contents_are_same(list_one, list_two, message='') + + Assert the values contained within two collections are the same. + + .. note:: The order of the values in each collection is ignored. + + :param list_one: The first value. (Can be any collection type) + :type list_one: Union[Tuple[Any], List[Any]] + :param list_two: The second value. (Can be any collection type) + :type list_two: Union[Tuple[Any], List[Any]] + :param message: A custom message to include when the assertion fails. Default is Empty String. + :type message: str, optional + :return: True, if the assertion succeeds. + :rtype: bool + :exception AssertionError: when the assertion fails. + """ + if not CommonCollectionUtils.is_collection(list_one): + raise AssertionError(f'{message}: {list_one} is not a collection') + if not CommonCollectionUtils.is_collection(list_two): + raise AssertionError(f'{message}: {list_two} is not a collection') + if len(list_one) != len(list_two): + raise AssertionError(f'{message}: expected\n {list_one}\n to be equal to\n {list_two}') + for item_one in list_one: + if item_one not in list_two: + raise AssertionError(f'{message}: expected\n {list_one}\n contents to be equal to\n {list_two}\n {item_one} not found in\n {list_two}') + for item_one in list_two: + if item_one not in list_one: + raise AssertionError(f'{message}: expected\n {list_one}\n contents to be equal to\n {list_two}\n {item_one} not found in\n {list_one}') + return True + + @staticmethod + def is_true(value: Union[bool, CommonTestResult, CommonExecutionResult], message: str='') -> bool: + """is_true(value, message='') + + Assert a value is True. + + :param value: The value being asserted. + :type value: Union[bool, CommonTestResult, CommonExecutionResult] + :param message: A custom message to include when the assertion fails. Default is Empty String. + :type message: str, optional + :return: True if the value is True. + :rtype: bool + :exception AssertionError: when the assertion fails. + """ + if isinstance(value, CommonTestResult) or isinstance(value, CommonExecutionResult): + if value.result is not True: + raise AssertionError(f'{message} {value.reason}: expected True, but was {value.result}') + return True + if value is not True: + raise AssertionError(f'{message}: expected True, but was {value}') + return True + + @staticmethod + def is_false(value: Union[bool, CommonTestResult, CommonExecutionResult], message: str='') -> bool: + """is_false(value, message='') + + Assert value is False. + + :param value: The value being asserted. + :type value: Union[bool, CommonTestResult, CommonExecutionResult] + :param message: A custom message to include when the assertion fails. + :type message: str, optional + :return: True if the value is False. + :rtype: bool + :exception AssertionError: when the assertion fails. + """ + if isinstance(value, CommonTestResult) or isinstance(value, CommonExecutionResult): + if value.result is not False: + raise AssertionError(f'{message} {value.reason}: expected False, but was {value.result}') + return True + if value is not False: + raise AssertionError(f'{message}: expected False, but was {value}') + return True + + @staticmethod + def has_length(value: Union[Tuple[Any], List[Any]], expected_length: int, message: str='') -> bool: + """has_length(value, expected_length, message='') + + Assert a collection has the specified length. + + :param value: The collection being asserted. (Any collection that works with `len()` can be used) + :type value: Union[Tuple[Any], List[Any]] + :param expected_length: The length expected of the collection. + :type expected_length: int + :param message: A custom message to include when the assertion fails. Default is Empty String. + :type message: str, optional + :return: True if the length matches. + :rtype: bool + :exception AssertionError: when the assertion fails. + """ + if not CommonCollectionUtils.is_collection(value): + raise AssertionError(f'{message}: expected collection {value} to have length {expected_length}, but was not a collection') + if len(value) != expected_length: + raise AssertionError(f'{message}: expected collection {value} to have length {expected_length}, but was {len(value)}') + return True + + @staticmethod + def contains(collection: Union[Tuple[Any], List[Any], Dict[Any, Any]], value: Any, message: str='') -> bool: + """contains(collection, value, message='') + + Assert a value is contained within a collection + + :param collection: The collection being checked (Any collection that works with `len()` can be used) + :type collection: Union[Tuple[Any], List[Any], Dict[Any, Any]] + :param value: The value being located. + :type value: Any + :param message: A custom message to include when the assertion fails. Default is Empty String. + :type message: str, optional + :return: True, if the value is contained within the collection. False, if it is not. + :rtype: bool + :exception AssertionError: when the assertion fails. + """ + if value not in collection: + raise AssertionError(f'{message}: expected {collection} to contain {value}, but it did not.') + return True + + @staticmethod + def not_contains(collection: Union[Tuple[Any], List[Any], Dict[Any, Any]], value: Any, message: str='') -> bool: + """not_contains(collection, value, message='') + + Assert a value is NOT contained within a collection + + :param collection: The collection being checked (Any collection that works with `len()` can be used) + :type collection: Union[Tuple[Any], List[Any], Dict[Any, Any]] + :param value: The value being located. + :type value: Any + :param message: A custom message to include when the assertion fails. Default is Empty String. + :type message: str, optional + :return: True, if the value is NOT contained within the collection. False, if it is. + :rtype: bool + :exception AssertionError: when the assertion fails. + """ + if value in collection: + raise AssertionError(f'{message}: expected {collection} to not contain {value}, but it did.') + return True + + @staticmethod + def throws(callback: Callable[..., Any], message: str='') -> Exception: + """throws(callback, message='') + + Assert calling a function will raise an Exception. + + :param callback: The function to invoke. + :type callback: Callable[..., Any] + :param message: A custom message to include when the assertion fails. Default is Empty String. + :type message: str, optional + :return: The exception that was thrown. + :rtype: Exception + :exception AssertionError: when the assertion fails. + """ + try: + callback() + except Exception as ex: + return ex + raise AssertionError(f'{message}: expected function to throw an exception, but it did not.') + + @staticmethod + def not_throws(callback: Callable[..., Any], message: str='') -> bool: + """not_throws(callback, message='') + + Assert calling a function will not raise an Exception. + + :param callback: The function to invoke. + :type callback: Callable[..., Any] + :param message: A custom message to include when the assertion fails. Default is Empty String. + :type message: str, optional + :return: True, if the assertion was successful. + :rtype: bool + :exception AssertionError: when the assertion fails. + """ + try: + callback() + except Exception as ex: + raise AssertionError(f'{message}: expected function to not throw an exception, but it did. Exception: {ex}') + return True diff --git a/Scripts/s4ap/sims4communitylib/testing/common_test_service.py b/Scripts/s4ap/sims4communitylib/testing/common_test_service.py new file mode 100644 index 0000000..558f741 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/testing/common_test_service.py @@ -0,0 +1,345 @@ +""" +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 +""" +from typing import Callable, Any, Dict, List, Union, Tuple +from functools import wraps +from traceback import format_exc +from sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.common_service import CommonService +# This try catch is here for when tests are being run via PyCharm rather than from in-game. +try: + from sims4communitylib.utils.common_log_registry import CommonLogRegistry + + community_test_log_log = CommonLogRegistry().register_log(ModInfo.get_identity(), 'community_test_log') + community_test_log_log.enable() + + def _community_test_log(val: str): + community_test_log_log.debug(val) +except ModuleNotFoundError: + # noinspection PyMissingOrEmptyDocstring + class CommonLogRegistry: + + @classmethod + def get(cls, *_, **__) -> 'CommonLogRegistry': + pass + + def register_log(self) -> None: + pass + + def _community_test_log(_: str): + pass + + +class CommonTestResultType: + """Use to identify the results of running a test. + + """ + FAILED = 'FAILED' + SUCCESS = 'SUCCESS' + + +class CommonTestService(CommonService): + """Use to register and run python tests. + + :Example Test Registration: + + .. highlight:: python + .. code-block:: python + + @CommonTestService.test_class('mod_name') + class TestClass: + # Important that it is a static method, you won't get a cls or self value passed in, so don't expect one! + @staticmethod + @CommonTestService.test(1, 1, expected_value=2) + @CommonTestService.test(2, 1, expected_value=3) + def example_add_test(one: int, two: int, expected_value: int=24): + result = one + two + CommonAssertionUtils.are_equal(result, expected_value, message='{} plus {} did not equal {}!'.format(one, two, expected_value)) + + """ + def __init__(self) -> None: + self._tests_by_mod_identity = dict() + self._test_count = 0 + + def add_test(self, mod_identity: CommonModIdentity, test_name: str, test_function: Callable[..., Any], class_name: str=None): + """add_test(mod_identity, test_name, test_function, class_name=None) + + Register a test with the specified name and class name. + + :param mod_identity: The identity of the mod the test is for. + :type mod_identity: CommonModIdentity + :param test_name: The name of the test. + :type test_name: str + :param test_function: The test itself. + :type test_function: Callable[..., Any] + :param class_name: The name of the class the test is contained within. + :type class_name: str + """ + if class_name is None: + class_name = 'generic' + else: + class_name = class_name.lower() + class_tests_by_name = self.get_test_library_by_mod(mod_identity) + class_tests = class_tests_by_name.get(class_name, list()) + class_tests.append((test_name, test_function)) + self._test_count += 1 + class_tests_by_name[class_name] = class_tests + self._tests_by_mod_identity[mod_identity] = class_tests_by_name + + @property + def total_test_count(self) -> int: + """Get a count of the number of tests. + + :return: The number of registered tests. + :rtype: int + """ + return self._test_count + + @property + def all_tests(self) -> Dict[str, Dict[str, Any]]: + """Get all registered tests. + + :return: A dictionary of tests by mod name. + :rtype: Dict[str, Dict[str, Any]] + """ + return self._tests_by_mod_identity + + def get_tests_by_class_name(self, class_name: str) -> List[Any]: + """get_tests_by_class_name(class_name) + + Retrieve tests by their class name. + + :param class_name: The name of the class to locate tests for. + :type class_name: str + :return: A list of tests matching the class name. + :rtype: List[Any] + """ + class_tests = list() + for (_, class_tests_by_class_name) in self._tests_by_mod_identity.items(): + class_tests.extend(class_tests_by_class_name.get(class_name, list())) + return class_tests + + def get_test_library_by_mod(self, mod_identifier: Union[str, CommonModIdentity]) -> Dict[str, Any]: + """get_test_library_by_mod(mod_identifier) + + Retrieve a library of tests for a Mod organized by class name. + + :param mod_identifier: The name or identity of the mod to search tests for. + :param mod_identifier: Union[str, CommonModIdentity] + :return: A library of tests for the specified Mod organized by class name. + :rtype: Dict[str, Any] + """ + from sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils + mod_name = CommonModIdentityUtils.determine_mod_name_from_identifier(mod_identifier, include_version=False).lower() + for (mod_identity, tests_by_class_name) in self._tests_by_mod_identity.items(): + lower_mod_name = CommonModIdentityUtils.determine_mod_name_from_identifier(mod_identity, include_version=False).lower() + if lower_mod_name == mod_name: + return tests_by_class_name + return dict() + + def get_tests_by_mod_name(self, mod_identifier: Union[str, CommonModIdentity]) -> Tuple[Any]: + """get_tests_by_mod_name(mod_name) + + Retrieve tests by a mod name. + + :param mod_identifier: The name or identity of the mod that owns the tests within the class. + :param mod_identifier: Union[str, CommonModIdentity] + :return: A collection of tests for the specified Mod. + :rtype: Tuple[Any] + """ + from sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils + mod_name = CommonModIdentityUtils.determine_mod_name_from_identifier(mod_identifier, include_version=False).lower() + class_tests_by_class_name = self._tests_by_mod_identity.get(mod_name, dict()) + all_tests: List[Any] = list() + for (_, tests) in class_tests_by_class_name.items(): + all_tests.extend(tests) + return tuple(all_tests) + + @classmethod + def _format_test_result(cls, test_result: str, test_name: str, stacktrace: str=None): + return 'TEST {}: {} {}\n'.format(test_result, test_name, stacktrace or '') + + @staticmethod + def test_class(mod_identity: CommonModIdentity) -> Any: + """test_class(mod_identity) + + Decorate a class with this to register a class as containing tests. + + :param mod_identity: The identity of the mod that owns the tests within the class. + :param mod_identity: CommonModIdentity + :return: A class wrapped to run tests. + :rtype: Any + """ + @CommonExceptionHandler.catch_exceptions(mod_identity) + def _inner_test_class(cls) -> Any: + name_of_class = cls.__name__ + if CommonLogRegistry is not None: + cls.test_log_log = CommonLogRegistry().register_log(mod_identity, name_of_class) + cls.test_log_log.enable() + cls.test_log = lambda val: cls.test_log_log.debug(val) + else: + cls.test_log = lambda val: print(val) + for method_name in dir(cls): + method = getattr(cls, method_name) + if not hasattr(method, 'is_test'): + continue + + def _test_function(class_name, test_name, test_method, *_, **__) -> None: + @wraps(test_method) + def _wrapper(*args, **kwargs) -> str: + arguments = (_ + args) + new_test_name = '{} (Arguments: {}, Keyword Arguments: {})'.format(test_name, arguments, (kwargs, __)) + # noinspection PyBroadException + try: + test_method(*(_ + args), **kwargs, **__) + cls.test_log(CommonTestService._format_test_result(CommonTestResultType.SUCCESS, new_test_name)) + except AssertionError: + cls.test_log(CommonTestService._format_test_result(CommonTestResultType.FAILED, new_test_name, stacktrace=format_exc())) + return CommonTestResultType.FAILED + except Exception: + cls.test_log(CommonTestService._format_test_result(CommonTestResultType.FAILED, new_test_name, stacktrace=format_exc())) + return CommonTestResultType.FAILED + return CommonTestResultType.SUCCESS + CommonTestService.get().add_test(mod_identity, test_name, _wrapper, class_name=class_name) + if hasattr(method, 'test_parameters') and len(method.test_parameters) > 0: + idx = 1 + for test_args, test_kwargs in method.test_parameters: + _test_function(name_of_class, '{} {}'.format(method_name, str(idx)), method, *test_args, **test_kwargs) + idx += 1 + else: + _test_function(name_of_class, method_name, method) + return cls + return _inner_test_class + + @staticmethod + def test(*args, **kwargs) -> Callable[..., Any]: + """test(args, kwargs) + + Decorate a function with this to register that function as a test. + When the test is run, it will be sent the specified arguments and keyword arguments. + + .. warning:: The function being registered MUST be a staticmethod. + + :param args: The arguments that will be sent to the function upon run. + :type args: Any + :param kwargs: The keyword arguments that will be sent to the function upon run. + :type kwargs: Any + :return: A function wrapped to run a test upon invocation. + :rtype: Callable[..., Any] + """ + def _test_func(test_function) -> Any: + test_function.is_test = True + if not hasattr(test_function, 'test_parameters'): + test_function.test_parameters = list() + test_function.test_parameters.append((args, kwargs)) + return test_function + return _test_func + + def run_tests(self, class_names: Tuple[str]=tuple(), callback: Callable[..., Any]=print): + """run_tests(class_names=tuple(), callback=print) + + Run all tests for the specified classes names. + + :param class_names: A collection of classes to run tests for. + :type class_names: Tuple[str] + :param callback: Any time a message needs to be printed or logged, it will be sent to this callback. Default is print. + :type callback: Callable[str, Any] + """ + return self._run_tests(mod_identifier=None, class_names=class_names, callback=callback) + + def run_tests_by_mod_name(self, mod_identifier: Union[str, CommonModIdentity], class_names: Tuple[str]=tuple(), callback: Callable[..., Any]=print): + """run_tests_by_mod_name(mod_identifier, class_names=tuple(), callback=print) + + Run all tests for the specified classes names for a specific Mod. + + :param mod_identifier: The name or identity of the mod to run tests for. + :param mod_identifier: Union[str, CommonModIdentity] + :param class_names: A collection of classes to run tests for. Default is all tests. + :type class_names: Tuple[str], optional + :param callback: Any time a message needs to be printed or logged, it will be sent to this callback. Default is print. + :type callback: Callable[str, Any] + """ + return self._run_tests(mod_identifier=mod_identifier, class_names=class_names, callback=callback) + + def _run_tests(self, mod_identifier: Union[str, CommonModIdentity]=None, class_names: Tuple[str]=tuple(), callback: Callable[..., Any]=print): + total_run_test_count = 0 + total_failed_test_count = 0 + from sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils + if mod_identifier: + to_run_mod_name = CommonModIdentityUtils.determine_mod_name_from_identifier(mod_identifier, include_version=False).lower() + else: + to_run_mod_name = None + for (mod_identity, class_tests_by_class_name) in self.all_tests.items(): + mod_name = mod_identity.name + if to_run_mod_name: + from sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils + cleaned_mod_name = CommonModIdentityUtils.determine_mod_name_from_identifier(mod_identity, include_version=False).lower() + if cleaned_mod_name != to_run_mod_name: + continue + mod_log = CommonLogRegistry().register_log(mod_identity, 'test_log') + try: + mod_log.enable() + callback(f'Running Tests for mod \'{mod_name}\'') + mod_log.debug(f'Running Tests for mod \'{mod_name}\'') + for (class_name, tests) in class_tests_by_class_name.items(): + if class_names and class_name not in class_names: + continue + class_log = CommonLogRegistry().register_log(mod_identity, class_name) + try: + class_log.enable() + callback(f'Running Tests for class \'{class_name}\'') + class_log.debug(f'Running Tests for class \'{class_name}\'') + total_test_count = len(tests) + failed_test_count = 0 + current_test_count = 0 + for test_name, test in tests: + total_run_test_count += 1 + current_test_count += 1 + result = test() + if result == CommonTestResultType.FAILED: + failed_test_count += 1 + total_failed_test_count += 1 + callback(f'{current_test_count} of {total_test_count} {result} {test_name}') + class_log.debug(f'{current_test_count} of {total_test_count} {result} {test_name}') + total_passed = total_test_count-failed_test_count + callback(f'{total_passed} of {total_test_count} tests Succeeded for class \'{class_name}\'\n') + class_log.debug(f'{total_passed} of {total_test_count} tests Succeeded for class \'{class_name}\'\n') + finally: + class_log.disable() + total_run_passed = total_run_test_count-total_failed_test_count + callback(f'{total_run_passed} of {total_run_test_count} total tests Succeeded') + mod_log.debug(f'{total_run_passed} of {total_run_test_count} total tests Succeeded') + finally: + mod_log.disable() + + +try: + from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + CommonConsoleCommandArgument + from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput + + @CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.run_tests', + 'Run any tests that are registered with S4CL (Only useful to mod authors)', + command_arguments=( + CommonConsoleCommandArgument('class_name', 'Text', 'If specified, only the tests located within the class matching this name will be run. If not specified, all registered tests will run.', is_optional=True, default_value='All Tests'), + CommonConsoleCommandArgument('mod_name', 'Text', 'If specified, only the tests registered by the mod with this name will be run. If not specified, all registered tests by all mods will run.', is_optional=True, default_value='All Mods'), + ) + ) + def _common_run_tests(output: CommonConsoleCommandOutput, class_name: str=None, mod_name: str=None): + class_names = tuple() + if class_name is not None: + class_names = (class_name,) + if mod_name is not None: + CommonTestService().run_tests_by_mod_name(mod_name, class_names, callback=output) + else: + CommonTestService.get().run_tests(class_names, callback=output) +except ModuleNotFoundError: + pass diff --git a/Scripts/s4ap/sims4communitylib/utils/__init__.py b/Scripts/s4ap/sims4communitylib/utils/__init__.py new file mode 100644 index 0000000..3251898 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" \ No newline at end of file diff --git a/Scripts/s4ap/sims4communitylib/utils/cas/__init__.py b/Scripts/s4ap/sims4communitylib/utils/cas/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/cas/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/utils/cas/common_cas_utils.py b/Scripts/s4ap/sims4communitylib/utils/cas/common_cas_utils.py new file mode 100644 index 0000000..3637e36 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/cas/common_cas_utils.py @@ -0,0 +1,975 @@ +""" +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 +""" +import os +from typing import Tuple, Union, Iterator, Dict, List + +from sims4.utils import classproperty +from sims4communitylib.classes.time.common_stop_watch import CommonStopWatch +from sims4communitylib.dtos.common_cas_part import CommonCASPart +from sims4communitylib.enums.common_body_slot import CommonBodySlot +from sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + CommonConsoleCommandArgument +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.services.sim.cas.common_sim_outfit_io import CommonSimOutfitIO +from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + +ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' + +if ON_RTD: + # noinspection PyMissingOrEmptyDocstring + class OutfitCategory: + + @classproperty + def value_to_name(self) -> Dict['OutfitCategory', str]: + pass + + # noinspection PyMissingOrEmptyDocstring + class BodyType: + NONE = 0 + + @classproperty + def value_to_name(self) -> Dict['BodyType', str]: + pass + + @classproperty + def name_to_value(self) -> Dict[str, 'BodyType']: + pass + + # noinspection PyMissingOrEmptyDocstring + class SimInfo: + pass + +if not ON_RTD: + from sims.outfits.outfit_enums import OutfitCategory, BodyType + from sims.sim_info import SimInfo + + +class CommonCASUtils(_HasS4CLClassLog): + """Utilities for manipulating the CAS parts of Sims. + + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 'common_cas_utils' + + @staticmethod + def is_cas_part_loaded(cas_part_id: int) -> bool: + """is_cas_part_loaded(cas_part_id) + + Determine if a CAS part is loaded within the game. + + .. note:: If the CAS part is part of a package that is not installed, it will be considered as not loaded. + + .. note:: A CAS part is considered as "loaded" when the BodyType it has can be found within the sims.outfits.outfit_enums.BodyType enum. + + :param cas_part_id: The Decimal identifier of a CAS part. + :type cas_part_id: int + :return: True if the CAS part is loaded within the game, False if not. + :rtype: bool + """ + body_type = CommonCASUtils.get_body_type_of_cas_part(cas_part_id) + return body_type is not None and body_type > 0 + + @staticmethod + def get_body_type_of_cas_part(cas_part_id: int) -> Union[BodyType, int]: + """get_body_type_of_cas_part(cas_part_id) + + Retrieve the BodyType of a CAS part. + + .. note:: Some Body Types don't appear in the BodyType enum. + + :param cas_part_id: The decimal identifier of a CAS part. + :type cas_part_id: int + :return: The default BodyType of the CAS part or an int if the Body Type is not within the BodyType enum. + :rtype: Union[BodyType, int] + """ + from cas.cas import get_caspart_bodytype + body_type = get_caspart_bodytype(cas_part_id) + if isinstance(body_type, int) and body_type in BodyType.value_to_name: + new_body_type = CommonResourceUtils.get_enum_by_name(BodyType.value_to_name[body_type], BodyType, default_value=None) + if new_body_type is not None: + body_type = new_body_type + return body_type + + @staticmethod + def get_body_type_by_name(name: str, default_body_type: Union[BodyType, None] = BodyType.NONE) -> BodyType: + """get_body_type_by_name(name, default_value=BodyType.NONE) + + Retrieve an BodyType by name. + + :param name: The name of a body type. + :type name: str + :param default_body_type: The default body type to use if a body type is not found using the specified name. Default is BodyType.NONE + :type default_body_type: Union[BodyType, None], optional + :return: The BodyType with the specified name or the default body type if no body type was found using the specified name. + :rtype: BodyType + """ + upper_case_name = str(name).upper().strip() + return CommonResourceUtils.get_enum_by_name(upper_case_name, BodyType, default_value=default_body_type) + + @staticmethod + def convert_value_to_body_type(value: Union[BodyType, int]) -> Union[BodyType, int]: + """convert_value_to_body_type(value) + + Retrieve an BodyType by value. + + :param value: The value of a body type. + :type value: Union[BodyType, int] + :return: The BodyType with the specified value or the specified value if no BodyType was found. + :rtype: Union[BodyType, int] + """ + if isinstance(value, BodyType): + return value + if value in BodyType.value_to_name: + return CommonResourceUtils.get_enum_by_name(BodyType.value_to_name[value], BodyType, default_value=value) + return value + + @classmethod + def attach_cas_part_to_sim(cls, sim_info: SimInfo, cas_part_id: int, body_type: Union[BodyType, int] = None, outfit_category_and_index: Union[Tuple[OutfitCategory, int], None] = None, **__) -> bool: + """attach_cas_part_to_sim(sim_info, cas_part_id, body_type=None, outfit_category_and_index=None, **__) + + Add a CAS part at the specified BodyType to the Sims outfit. + + :param sim_info: The SimInfo of a Sim to add the CAS part to. + :type sim_info: SimInfo + :param cas_part_id: The decimal identifier of a CAS part to attach to the Sim. + :type cas_part_id: int + :param body_type: The BodyType the CAS part will be attached to. If no value is provided, the BodyType of the CAS part itself will be used. Default is None. + :type body_type: Union[BodyType, int], optional + :param outfit_category_and_index: The outfit category and index of the Sims outfit to modify. If no value is provided, the Sims current outfit will be used. + :type outfit_category_and_index: Union[Tuple[OutfitCategory, int], None], optional + :return: True if the CAS part was successfully attached to the Sim. False if the CAS part was not successfully attached to the Sim. + :rtype: bool + """ + if cas_part_id == -1 or cas_part_id is None: + raise RuntimeError('No cas_part_id was provided.') + + cls.get_log().format_with_message('Attempting to attach CAS part to Sim', sim=sim_info, cas_part_id=cas_part_id, body_type=body_type, outfit_category_and_index=outfit_category_and_index) + cas_part = CommonCASPart(cas_part_id, body_type=body_type if body_type != BodyType.NONE else None) + return cls.attach_cas_part_to_outfit_of_sim(sim_info, cas_part, outfit_category_and_index=outfit_category_and_index) + + @classmethod + def attach_cas_part_to_all_outfits_of_sim(cls, sim_info: SimInfo, cas_part: CommonCASPart) -> bool: + """attach_cas_part_to_all_outfits_of_sim(sim_info, cas_part) + + Attach a CAS part to all outfits of a Sim. + + :param sim_info: The SimInfo of a Sim to modify. + :type sim_info: SimInfo + :param cas_part: The CAS Part to attach. + :type cas_part: CommonCASPart + :return: True, if the CAS part was successfully attached to the Sim. False, if not. + :rtype: bool + """ + return cls.attach_cas_parts_to_all_outfits_of_sim(sim_info, (cas_part,)) + + @classmethod + def attach_cas_parts_to_all_outfits_of_sim(cls, sim_info: SimInfo, cas_parts: Iterator[CommonCASPart]) -> bool: + """attach_cas_parts_to_all_outfits_of_sim(sim_info, cas_parts) + + Attach a collection of CAS Parts to all outfits of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param cas_parts: A collection of CAS Parts to attach. + :type cas_parts: Iterator[CommonCASPart] + :return: True, if all CAS Parts were successfully attached to the Sim. False, if not. + """ + _log = cls.get_log() + cas_parts_by_body_type = dict() + for cas_part in cas_parts: + cas_parts_by_body_type[int(CommonBodySlot.convert_to_vanilla(cas_part.body_type))] = cas_part + cas_part_body_types = [int(CommonBodySlot.convert_to_vanilla(cas_part.body_type)) for cas_part in cas_parts] + from sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils + current_outfit = CommonOutfitUtils.get_current_outfit(sim_info) + from protocolbuffers import S4Common_pb2, Outfits_pb2 + saved_outfits = sim_info.save_outfits() + for saved_outfit in saved_outfits.outfits: + # noinspection PyUnresolvedReferences + saved_outfit_parts = dict(zip(list(saved_outfit.body_types_list.body_types), list(saved_outfit.parts.ids))) + body_types = list() + part_ids = list() + handled_body_types: List[int] = list() + _log.format_with_message('Before modify parts.', outfit_category=saved_outfit.category, body_types=tuple(saved_outfit_parts.keys()), part_ids=tuple(saved_outfit_parts.values())) + for (body_type, part_id) in saved_outfit_parts.items(): + body_type_int = int(body_type) + if body_type_int in cas_parts_by_body_type: + # Remove the existing body types that match the ones we are replacing. + handled_body_types.append(body_type_int) + part = cas_parts_by_body_type[body_type_int] + _log.format_with_message('Replacing body type with CAS Part', original_body_type=body_type, cas_part=part, original_part_id=part_id) + body_types.append(CommonBodySlot.convert_to_vanilla(part.body_type)) + part_ids.append(part.cas_part_id) + continue + _log.format_with_message('Keeping body type.', original_body_type=body_type, cas_part_body_types=cas_part_body_types, original_part_id=part_id) + body_types.append(body_type) + part_ids.append(part_id) + + # Adding the rest of the CAS Parts. + _log.format_with_message('Adding the rest of the CAS Parts.', body_types=body_types, part_ids=part_ids, cas_parts_by_body_type=cas_parts_by_body_type, handled_body_types=handled_body_types) + for cas_part in cas_parts_by_body_type.values(): + cas_part_body_type = CommonBodySlot.convert_to_vanilla(cas_part.body_type) + if int(cas_part_body_type) in handled_body_types: + continue + body_types.append(cas_part_body_type) + part_ids.append(cas_part.cas_part_id) + + _log.format_with_message('After modify parts.', outfit_category=saved_outfit.category, body_types=body_types, part_ids=part_ids) + + # Save the parts. + saved_outfit.parts = S4Common_pb2.IdList() + # noinspection PyUnresolvedReferences + saved_outfit.parts.ids.extend(part_ids) + saved_outfit.body_types_list = Outfits_pb2.BodyTypesList() + # noinspection PyUnresolvedReferences + saved_outfit.body_types_list.body_types.extend([int(body_type) for body_type in body_types]) + sim_info._base.outfits = saved_outfits.SerializeToString() + sim_info._base.outfit_type_and_index = current_outfit + sim_info.resend_outfits() + sim_info.on_outfit_generated(*current_outfit) + sim_info.set_outfit_dirty(current_outfit[0]) + sim_info.set_current_outfit(current_outfit) + return True + + @classmethod + def attach_cas_part_to_outfit_of_sim(cls, sim_info: SimInfo, cas_part: CommonCASPart, outfit_category_and_index: Tuple[OutfitCategory, int] = None) -> bool: + """attach_cas_part_to_outfit_of_sim(sim_info, cas_part, outfit_category_and_index=None) + + Attach a CAS part to an outfit of a Sim. + + :param sim_info: The SimInfo of a Sim to modify. + :type sim_info: SimInfo + :param cas_part: The CAS Part to attach. + :type cas_part: CommonCASPart + :return: True, if the CAS part was successfully attached to the Sim. False, if not. + :param outfit_category_and_index: The outfit category and index of the Sims outfit to modify. If no value is provided, the Sims current outfit will be used. Default is current outfit. + :type outfit_category_and_index: Union[Tuple[OutfitCategory, int], None], optional + :return: True, if the CAS part was successfully attached to the outfit of the Sim. False, if not. + :rtype: bool + """ + return cls.attach_cas_parts_to_outfit_of_sim(sim_info, (cas_part,), outfit_category_and_index=outfit_category_and_index) + + @classmethod + def attach_cas_parts_to_outfit_of_sim(cls, sim_info: SimInfo, cas_parts: Iterator[CommonCASPart], outfit_category_and_index: Tuple[OutfitCategory, int] = None, set_outfit: bool = True) -> bool: + """attach_cas_parts_to_outfit_of_sim(sim_info, cas_parts, outfit_category_and_index=None) + + Attach CAS parts to an outfit of a Sim. + + :param sim_info: The SimInfo of a Sim to modify. + :type sim_info: SimInfo + :param cas_parts: A collection of CAS Parts to attach. + :type cas_parts: Iterator[CommonCASPart] + :param outfit_category_and_index: The outfit category and index of the Sims outfit to modify. If no value is provided, the Sims current outfit will be used. Default is current outfit. + :type outfit_category_and_index: Union[Tuple[OutfitCategory, int], None], optional + :return: True, if the CAS parts were successfully attached to the Sim. False, if not. + :rtype: bool + """ + stop_watch = CommonStopWatch() + try: + stop_watch.start() + from sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils + current_outfit = CommonOutfitUtils.get_current_outfit(sim_info) + if outfit_category_and_index is None: + outfit_category_and_index = current_outfit + existing_outfit_data = sim_info.get_outfit(outfit_category_and_index[0], outfit_category_and_index[1]) + cas_part_body_types = [int(CommonBodySlot.convert_to_vanilla(cas_part.body_type)) for cas_part in cas_parts] + from protocolbuffers import S4Common_pb2, Outfits_pb2 + saved_outfits = sim_info.save_outfits() + cls.get_log().format_with_message('Got Saved Outfits', time_milliseconds=stop_watch.interval_milliseconds()) + for saved_outfit in saved_outfits.outfits: + if int(saved_outfit.outfit_id) != int(existing_outfit_data.outfit_id): + continue + # noinspection PyUnresolvedReferences + saved_outfit_parts = dict(zip(list(saved_outfit.body_types_list.body_types), list(saved_outfit.parts.ids))) + body_types = list() + part_ids = list() + for (body_type, part_id) in saved_outfit_parts.items(): + if int(body_type) in cas_part_body_types: + # Remove the existing body types that match the ones we are replacing. + continue + body_types.append(body_type) + part_ids.append(part_id) + + # Add the new cas parts and their body types. + for cas_part in cas_parts: + body_types.append(CommonBodySlot.convert_to_vanilla(cas_part.body_type)) + part_ids.append(cas_part.cas_part_id) + + # Save the parts. + saved_outfit.parts = S4Common_pb2.IdList() + # noinspection PyUnresolvedReferences + saved_outfit.parts.ids.extend(part_ids) + saved_outfit.body_types_list = Outfits_pb2.BodyTypesList() + # noinspection PyUnresolvedReferences + saved_outfit.body_types_list.body_types.extend([int(body_type) for body_type in body_types]) + cls.get_log().format_with_message('Finished updating Saved Outfits. Setting outfits.', time_milliseconds=stop_watch.interval_milliseconds()) + sim_info._base.outfits = saved_outfits.SerializeToString() + sim_info._base.outfit_type_and_index = current_outfit + sim_info.resend_outfits() + cls.get_log().format_with_message('Finished resending outfits.', time_milliseconds=stop_watch.interval_milliseconds()) + sim_info.on_outfit_generated(*current_outfit) + sim_info.set_outfit_dirty(current_outfit[0]) + sim_info.set_current_outfit(current_outfit) + cls.get_log().format_with_message('Finished setting current outfit.', time_milliseconds=stop_watch.interval_milliseconds()) + return True + finally: + stop_watch.stop() + + @classmethod + def detach_cas_part_from_all_outfits_of_sim(cls, sim_info: SimInfo, cas_part: CommonCASPart) -> bool: + """detach_cas_part_from_all_outfits_of_sim(sim_info, cas_part) + + Detach a CAS Part from all outfits of a Sim. + + :param sim_info: The SimInfo of a Sim to modify. + :type sim_info: SimInfo + :param cas_part: A CAS Part to detach. + :type cas_part: CommonCASPart + :return: True, if the CAS Part was successfully detached from all outfits of the Sim. False, if not. + """ + return cls.detach_cas_parts_from_all_outfits_of_sim(sim_info, (cas_part,)) + + @classmethod + def detach_cas_parts_from_all_outfits_of_sim(cls, sim_info: SimInfo, cas_parts: Iterator[CommonCASPart]) -> bool: + """detach_cas_parts_from_all_outfits_of_sim(sim_info, cas_parts) + + Detach a collection of CAS Parts from all outfits of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param cas_parts: A collection of CAS Parts to detach. + :type cas_parts: Iterator[CommonCASPart] + :return: True, if all CAS Parts were successfully detached from all outfits of the Sim. False, if not. + """ + _log = cls.get_log() + cas_part_ids = tuple([cas_part.cas_part_id for cas_part in cas_parts]) + from sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils + current_outfit = CommonOutfitUtils.get_current_outfit(sim_info) + from protocolbuffers import S4Common_pb2, Outfits_pb2 + saved_outfits = sim_info.save_outfits() + for saved_outfit in saved_outfits.outfits: + # noinspection PyUnresolvedReferences + saved_outfit_parts = dict(zip(list(saved_outfit.body_types_list.body_types), list(saved_outfit.parts.ids))) + body_types = list() + part_ids = list() + _log.format_with_message('Before modify parts.', outfit_category=saved_outfit.category, body_types=tuple(saved_outfit_parts.keys()), part_ids=tuple(saved_outfit_parts.values())) + for (body_type, part_id) in saved_outfit_parts.items(): + if part_id in cas_part_ids: + # Remove cas_part_ids + continue + _log.format_with_message('Keeping body type.', original_body_type=body_type, original_part_id=part_id) + body_types.append(body_type) + part_ids.append(part_id) + + _log.format_with_message('After modify parts.', outfit_category=saved_outfit.category, body_types=body_types, part_ids=part_ids) + + # Save the parts. + saved_outfit.parts = S4Common_pb2.IdList() + # noinspection PyUnresolvedReferences + saved_outfit.parts.ids.extend(part_ids) + saved_outfit.body_types_list = Outfits_pb2.BodyTypesList() + # noinspection PyUnresolvedReferences + saved_outfit.body_types_list.body_types.extend([int(body_type) for body_type in body_types]) + sim_info._base.outfits = saved_outfits.SerializeToString() + sim_info._base.outfit_type_and_index = current_outfit + sim_info.resend_outfits() + sim_info.on_outfit_generated(*current_outfit) + sim_info.set_outfit_dirty(current_outfit[0]) + sim_info.set_current_outfit(current_outfit) + return True + + @classmethod + def detach_cas_part_from_outfit_of_sim(cls, sim_info: SimInfo, cas_part: CommonCASPart, outfit_category_and_index: Tuple[OutfitCategory, int] = None) -> bool: + """detach_cas_part_from_outfit_of_sim(sim_info, cas_part, outfit_category_and_index=None) + + Detach a CAS part from an outfit of a Sim. + + :param sim_info: The SimInfo of a Sim to modify. + :type sim_info: SimInfo + :param cas_part: A CAS Part to detach. + :type cas_part: CommonCASPart + :param outfit_category_and_index: The outfit category and index of the Sims outfit to modify. If no value is provided, the Sims current outfit will be used. Default is current outfit. + :type outfit_category_and_index: Union[Tuple[OutfitCategory, int], None], optional + :return: True, if the CAS part was successfully detached from the outfit of the Sim. False, if not. + :rtype: bool + """ + return cls.detach_cas_parts_from_outfit_of_sim(sim_info, (cas_part,), outfit_category_and_index=outfit_category_and_index) + + @classmethod + def detach_cas_parts_from_outfit_of_sim(cls, sim_info: SimInfo, cas_parts: Iterator[CommonCASPart], outfit_category_and_index: Tuple[OutfitCategory, int] = None) -> bool: + """detach_cas_parts_from_outfit_of_sim(sim_info, cas_parts, outfit_category_and_index=None) + + Detach CAS parts from an outfit of a Sim. + + :param sim_info: The SimInfo of a Sim to modify. + :type sim_info: SimInfo + :param cas_parts: A collection of CAS Parts to detach. + :type cas_parts: Iterator[CommonCASPart] + :param outfit_category_and_index: The outfit category and index of the Sims outfit to modify. If no value is provided, the Sims current outfit will be used. Default is current outfit. + :type outfit_category_and_index: Union[Tuple[OutfitCategory, int], None], optional + :return: True, if the CAS parts were successfully detached from the outfit of the Sim. False, if not. + :rtype: bool + """ + from sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils + current_outfit = CommonOutfitUtils.get_current_outfit(sim_info) + if outfit_category_and_index is None: + outfit_category_and_index = current_outfit + existing_outfit_data = sim_info.get_outfit(outfit_category_and_index[0], outfit_category_and_index[1]) + cas_part_ids = [cas_part.cas_part_id for cas_part in cas_parts] + from protocolbuffers import S4Common_pb2, Outfits_pb2 + saved_outfits = sim_info.save_outfits() + for saved_outfit in saved_outfits.outfits: + if int(saved_outfit.outfit_id) != int(existing_outfit_data.outfit_id): + continue + # noinspection PyUnresolvedReferences + saved_outfit_parts = dict(zip(list(saved_outfit.body_types_list.body_types), list(saved_outfit.parts.ids))) + body_types = list() + part_ids = list() + for (body_type, part_id) in saved_outfit_parts.items(): + if part_id in cas_part_ids: + # Remove the CAS Part Id. + continue + body_types.append(body_type) + part_ids.append(part_id) + + # Save the parts. + saved_outfit.parts = S4Common_pb2.IdList() + # noinspection PyUnresolvedReferences + saved_outfit.parts.ids.extend(part_ids) + saved_outfit.body_types_list = Outfits_pb2.BodyTypesList() + # noinspection PyUnresolvedReferences + saved_outfit.body_types_list.body_types.extend([int(body_type) for body_type in body_types]) + sim_info._base.outfits = saved_outfits.SerializeToString() + sim_info._base.outfit_type_and_index = current_outfit + sim_info.resend_outfits() + sim_info.on_outfit_generated(*current_outfit) + sim_info.set_outfit_dirty(current_outfit[0]) + sim_info.set_current_outfit(current_outfit) + return True + + # noinspection PyUnusedLocal + @classmethod + def detach_cas_part_from_sim(cls, sim_info: SimInfo, cas_part_id: int, body_type: Union[BodyType, int, None] = None, outfit_category_and_index: Union[Tuple[OutfitCategory, int], None] = None, **__) -> bool: + """detach_cas_part_from_sim(sim_info, cas_part_id, body_type=None, outfit_category_and_index=None, **__) + + Remove a CAS part at the specified BodyType from the Sims outfit. + + :param sim_info: The SimInfo of a Sim to remove the CAS part from. + :type sim_info: SimInfo + :param cas_part_id: The decimal identifier of a CAS part to detach from the Sim. + :type cas_part_id: int + :param body_type: The BodyType the CAS part will be detached from. If BodyType.NONE is provided, the BodyType of the CAS Part itself will be used. If set to None, the CAS part will be removed from all BodyTypes. Default is None. + :type body_type: Union[BodyType, int, None], optional + :param outfit_category_and_index: The outfit category and index of the Sims outfit to modify. If no value is provided, the Sims current outfit will be used. Default is current outfit. + :type outfit_category_and_index: Union[Tuple[OutfitCategory, int], None], optional + :return: True if the CAS part was successfully detached from the Sim. False if the CAS part was not successfully detached from the Sim. + :rtype: bool + """ + if cas_part_id == -1 or cas_part_id is None: + raise RuntimeError('No cas_part_id was provided.') + cas_part = CommonCASPart(cas_part_id, body_type=body_type if body_type != BodyType.NONE else None) + return cls.detach_cas_part_from_outfit_of_sim(sim_info, cas_part, outfit_category_and_index=outfit_category_and_index) + + @classmethod + def detach_body_type_from_all_outfits_of_sim(cls, sim_info: SimInfo, body_type_to_remove: Union[BodyType, int]): + """detach_body_type_from_all_outfits_of_sim(sim_info, body_type_to_remove) + + Detach a body type from all outfits of a Sim. + + :param sim_info: The SimInfo of a Sim to modify. + :type sim_info: SimInfo + :param body_type_to_remove: The body type to remove. + :type body_type_to_remove: Union[BodyType, int] + """ + return cls.detach_body_types_from_all_outfits_of_sim(sim_info, (body_type_to_remove,)) + + @classmethod + def detach_body_types_from_all_outfits_of_sim(cls, sim_info: SimInfo, body_types_to_remove: Iterator[Union[BodyType, int]]): + """detach_body_types_from_all_outfits_of_sim(sim_info, body_types_to_remove) + + Detach body types from all outfits of a Sim. + + :param sim_info: The SimInfo of a Sim to modify. + :type sim_info: SimInfo + :param body_types_to_remove: A collection of body types to remove. + :type body_types_to_remove: Iterator[Union[BodyType, int]] + """ + body_types_to_remove = tuple([int(body_type) for body_type in body_types_to_remove]) + from protocolbuffers import S4Common_pb2, Outfits_pb2 + saved_outfits = sim_info.save_outfits() + for saved_outfit in saved_outfits.outfits: + # noinspection PyUnresolvedReferences + saved_outfit_parts = dict(zip(list(saved_outfit.body_types_list.body_types), list(saved_outfit.parts.ids))) + body_types = list() + part_ids = list() + # Remove existing body type and its associated part that matches the one we are replacing. + for (body_type, part_id) in saved_outfit_parts.items(): + if int(body_type) in body_types_to_remove: + # Remove body type. + continue + body_types.append(body_type) + part_ids.append(part_id) + + # Save the parts. + saved_outfit.parts = S4Common_pb2.IdList() + # noinspection PyUnresolvedReferences + saved_outfit.parts.ids.extend(part_ids) + saved_outfit.body_types_list = Outfits_pb2.BodyTypesList() + # noinspection PyUnresolvedReferences + saved_outfit.body_types_list.body_types.extend(body_types) + sim_info._base.outfits = saved_outfits.SerializeToString() + + @classmethod + def detach_body_type_from_outfit_of_sim(cls, sim_info: SimInfo, body_type_to_remove: Union[BodyType, int], outfit_category_and_index: Tuple[OutfitCategory, int] = None) -> bool: + """detach_body_type_from_outfit_of_sim(sim_info, body_type_to_remove, outfit_category_and_index=None) + + Detach the CAS Part at a specific body type from an outfit of a Sim. + + :param sim_info: The SimInfo of a Sim to modify. + :type sim_info: SimInfo + :param body_type_to_remove: The body type to remove. + :type body_type_to_remove: Union[BodyType, int] + :param outfit_category_and_index: The outfit category and index of the Sims outfit to modify. If no value is provided, the Sims current outfit will be used. Default is current outfit. + :type outfit_category_and_index: Union[Tuple[OutfitCategory, int], None], optional + :return: True, if the body type was successfully detached from the outfit of the Sim. False, if not. + :rtype: bool + """ + return cls.detach_body_types_from_outfit_of_sim(sim_info, (body_type_to_remove,), outfit_category_and_index=outfit_category_and_index) + + @classmethod + def detach_body_types_from_outfit_of_sim(cls, sim_info: SimInfo, body_types_to_remove: Iterator[Union[BodyType, int]], outfit_category_and_index: Tuple[OutfitCategory, int] = None) -> bool: + """detach_body_types_from_outfit_of_sim(sim_info, body_types_to_remove, outfit_category_and_index=None) + + Detach any CAS Parts at specific body types from an outfit of a Sim. + + :param sim_info: The SimInfo of a Sim to modify. + :type sim_info: SimInfo + :param body_types_to_remove: A collection of body types to remove. + :type body_types_to_remove: Iterator[Union[BodyType, int]] + :param outfit_category_and_index: The outfit category and index of the Sims outfit to modify. If no value is provided, the Sims current outfit will be used. Default is current outfit. + :type outfit_category_and_index: Union[Tuple[OutfitCategory, int], None], optional + :return: True, if the body types were successfully detached from the outfit of the Sim. False, if not. + :rtype: bool + """ + from sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils + current_outfit = CommonOutfitUtils.get_current_outfit(sim_info) + if outfit_category_and_index is None: + outfit_category_and_index = current_outfit + existing_outfit_data = sim_info.get_outfit(outfit_category_and_index[0], outfit_category_and_index[1]) + body_types_to_remove = tuple([int(body_type) for body_type in body_types_to_remove]) + from protocolbuffers import S4Common_pb2, Outfits_pb2 + saved_outfits = sim_info.save_outfits() + for saved_outfit in saved_outfits.outfits: + if int(saved_outfit.outfit_id) != int(existing_outfit_data.outfit_id): + continue + # noinspection PyUnresolvedReferences + saved_outfit_parts = dict(zip(list(saved_outfit.body_types_list.body_types), list(saved_outfit.parts.ids))) + body_types = list() + part_ids = list() + for (body_type, part_id) in saved_outfit_parts.items(): + if int(body_type) in body_types_to_remove: + # Remove body type. + continue + body_types.append(body_type) + part_ids.append(part_id) + + # Save the parts. + saved_outfit.parts = S4Common_pb2.IdList() + # noinspection PyUnresolvedReferences + saved_outfit.parts.ids.extend(part_ids) + saved_outfit.body_types_list = Outfits_pb2.BodyTypesList() + # noinspection PyUnresolvedReferences + saved_outfit.body_types_list.body_types.extend(body_types) + sim_info._base.outfits = saved_outfits.SerializeToString() + sim_info._base.outfit_type_and_index = current_outfit + sim_info.resend_outfits() + return True + + @classmethod + def has_cas_part_attached(cls, sim_info: SimInfo, cas_part_id: int, body_type: Union[BodyType, int, None] = None, outfit_category_and_index: Tuple[OutfitCategory, int] = None, mod_identity: CommonModIdentity = None) -> bool: + """has_cas_part_attached(sim_info, cas_part_id, body_type=None, outfit_category_and_index=None, mod_identity=None) + + Determine if a Sim has the specified CAS part attached to their outfit. + + :param sim_info: The SimInfo of the Sim to check. + :type sim_info: SimInfo + :param cas_part_id: A decimal identifier of the CAS part to locate. + :type cas_part_id: int + :param body_type: The BodyType the CAS part will be located at. If BodyType.NONE is provided, the body type of the CAS Part itself will be used. If set to None, the CAS part will be located within any BodyType. Default is None. + :type body_type: Union[BodyType, int, None], optional + :param outfit_category_and_index: The outfit category and index of the Sims outfit to check. Default is the Sims current outfit. + :type outfit_category_and_index: Union[Tuple[OutfitCategory, int], None], optional + :param mod_identity: The identity of the mod performing the function. Default is None. Optional, but highly recommended! + :type mod_identity: CommonModIdentity, optional + :return: True, if the Sims outfit contain the specified CAS part. False, if the Sims outfit does not contain the specified CAS part. + :rtype: bool + """ + cls.get_log().format_with_message('Checking if CAS part is attached to Sim.', sim=sim_info, cas_part_id=cas_part_id, body_type=body_type, outfit_category_and_index=outfit_category_and_index) + outfit_io = CommonSimOutfitIO(sim_info, outfit_category_and_index=outfit_category_and_index, mod_identity=mod_identity) + if body_type is None: + return outfit_io.is_cas_part_attached(cas_part_id) + if body_type == BodyType.NONE: + body_type = CommonCASUtils.get_body_type_of_cas_part(cas_part_id) + return outfit_io.get_cas_part_at_body_type(body_type) == cas_part_id + + @staticmethod + def has_any_cas_part_attached_to_body_type(sim_info: SimInfo, body_type: Union[BodyType, int], outfit_category_and_index: Tuple[OutfitCategory, int] = None, mod_identity: CommonModIdentity = None) -> bool: + """has_any_cas_part_attached_to_body_type(sim_info, body_type, outfit_category_and_index=None, mod_identity=None) + + Determine if a Sim has a CAS Part attached to a BodyType. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param body_type: A BodyType to check. + :type body_type: Union[BodyType, int] + :param outfit_category_and_index: An outfit category and index of the outfit. Default is None, which is whatever outfit a Sim is currently wearing. + :type outfit_category_and_index: Tuple[OutfitCategory, int], optional + :param mod_identity: The identity of the mod performing the function. Default is None. Optional, but highly recommended! + :type mod_identity: CommonModIdentity, optional + :return: True, if the Sim has any CAS Part attached to the specified BodyType for the specified outfit. False, it not. + :rtype: bool + """ + return CommonCASUtils.get_cas_part_id_at_body_type(sim_info, body_type, outfit_category_and_index=outfit_category_and_index, mod_identity=mod_identity) != -1 + + @classmethod + def get_body_type_cas_part_is_attached_to(cls, sim_info: SimInfo, cas_part_id: int, outfit_category_and_index: Tuple[OutfitCategory, int] = None, mod_identity: CommonModIdentity = None) -> Union[BodyType, int]: + """get_body_type_cas_part_is_attached_to(sim_info, cas_part_id, outfit_category_and_index=None, mod_identity=None) + + Retrieve the BodyType that a CAS part is attached to within a Sims outfit. + + :param sim_info: The SimInfo of the Sim to check. + :type sim_info: SimInfo + :param cas_part_id: A decimal identifier of the CAS part to locate. + :type cas_part_id: int + :param outfit_category_and_index: The outfit category and index of the Sims outfit to check. If None, the current outfit of the Sim will be used. + :type outfit_category_and_index: Tuple[OutfitCategory, int], optional + :param mod_identity: The identity of the mod performing the function. Default is None. Optional, but highly recommended! + :type mod_identity: CommonModIdentity, optional + :return: The BodyType the specified CAS part id is attached to or BodyType.NONE if the CAS part is not found or the Sim does not have body parts for their outfit. + :rtype: Union[BodyType, int] + """ + cls.get_log().format_with_message('Retrieving BodyType for CAS part.', sim=sim_info, cas_part_id=cas_part_id, outfit_category_and_index=outfit_category_and_index) + outfit_io = CommonSimOutfitIO(sim_info, outfit_category_and_index=outfit_category_and_index, mod_identity=mod_identity) + return outfit_io.get_body_type_cas_part_is_attached_to(cas_part_id) + + @classmethod + def get_cas_part_id_at_body_type(cls, sim_info: SimInfo, body_type: Union[BodyType, int], outfit_category_and_index: Tuple[OutfitCategory, int] = None, mod_identity: CommonModIdentity = None) -> int: + """get_cas_part_id_at_body_type(sim_info, body_type, outfit_category_and_index=None, mod_identity=None) + + Retrieve the CAS part identifier attached to the specified BodyType within a Sims outfit. + + :param sim_info: The SimInfo of the Sim to check. + :type sim_info: SimInfo + :param body_type: The BodyType to check. + :type body_type: Union[BodyType, int] + :param outfit_category_and_index: The outfit category and index of the Sims outfit to check. Default is the Sims current outfit. + :type outfit_category_and_index: Tuple[OutfitCategory, int], optional + :param mod_identity: The identity of the mod performing the function. Default is None. Optional, but highly recommended! + :type mod_identity: CommonModIdentity, optional + :return: The CAS part identifier attached to the specified BodyType or -1 if the BodyType is not found. + :rtype: int + """ + cls.get_log().format_with_message('Checking if CAS part is attached to Sim.', sim=sim_info, body_type=body_type, outfit_category_and_index=outfit_category_and_index) + outfit_io = CommonSimOutfitIO(sim_info, outfit_category_and_index=outfit_category_and_index, mod_identity=mod_identity) + return outfit_io.get_cas_part_at_body_type(body_type) + + @staticmethod + def get_skin_tone(sim_info: SimInfo) -> int: + """get_skin_tone(sim_info) + + Retrieve the id for the Skin Tone of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The decimal identifier of the skin tone of the specified Sim. + :rtype: int + """ + return sim_info.skin_tone + + @staticmethod + def get_skin_tone_value_shift(sim_info: SimInfo) -> int: + """get_skin_tone_value_shift(sim_info) + + Retrieve the value shift for the Skin Tone of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The value shift for the Skin Tone of a Sim. + :rtype: int + """ + return sim_info.skin_tone_val_shift + + @staticmethod + def set_skin_tone(sim_info: SimInfo, skin_tone: int): + """set_skin_tone(sim_info, skin_tone) + + Set the skin tone of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param skin_tone: The decimal identifier of the skin tone to set the Sim to. + :type skin_tone: int + """ + sim_info.skin_tone = skin_tone + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.attach_cas_part_to_all_outfits', + 'Attach a CAS Part to all outfits of a Sim. This is a permanent change to all of their outfits!', + command_arguments=( + CommonConsoleCommandArgument('cas_part_id', 'Decimal Identifier', 'The decimal identifier of the CAS Part to attach.'), + CommonConsoleCommandArgument('body_type', 'Body Type Name or Number', 'The body type to attach the CAS Part to. If not specified the body type of the CAS Part itself will be used.', is_optional=True, default_value='CAS Part Default Body Type'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to attach the CAS Part to.', is_optional=True, default_value='Active Sim') + ), + command_aliases=( + 's4clib.attachcasparttoalloutfits', + ) +) +def _s4clib_attach_cas_part_to_all_outfits(output: CommonConsoleCommandOutput, cas_part_id: int, body_type: str = 'any', sim_info: SimInfo = None): + if sim_info is None: + return + if cas_part_id < 0: + output('ERROR: CAS Part must be a positive number.') + return + if not CommonCASUtils.is_cas_part_loaded(cas_part_id): + output(f'ERROR: No CAS Part was found with id: {cas_part_id}') + return + if body_type is None: + output('ERROR: No Body Type specified.') + return + if body_type == 'any': + body_type_value = BodyType.NONE + elif isinstance(body_type, int): + body_type_value = body_type + elif isinstance(body_type, str) and body_type.isnumeric(): + try: + body_type_value = int(body_type) + except ValueError: + output(f'ERROR: The specified body type is neither a number nor the name of a BodyType {body_type}') + return + else: + body_type_value = CommonResourceUtils.get_enum_by_name(body_type.upper(), BodyType, default_value=BodyType.NONE) + if body_type_value == BodyType.NONE: + output(f'ERROR: The specified body type is neither a number nor the name of a BodyType {body_type}') + return + + output(f'Attempting to attach CAS Part \'{cas_part_id}\' to Sim {sim_info} at body location {body_type_value}') + cas_part = CommonCASPart(cas_part_id, body_type=body_type_value) + if CommonCASUtils.attach_cas_parts_to_all_outfits_of_sim(sim_info, (cas_part,)): + output(f'SUCCESS: CAS Part has been successfully attached to Sim {sim_info}.') + else: + output(f'FAILED: CAS Part failed to attach to Sim {sim_info}.') + output('Done attaching CAS Part to the Sim.') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.attach_cas_part', + 'Attach a CAS Part to a Sim. This is a permanent change to their current outfit!', + command_arguments=( + CommonConsoleCommandArgument('cas_part_id', 'Decimal Identifier', 'The decimal identifier of the CAS Part to attach.'), + CommonConsoleCommandArgument('body_type', 'Body Type Name or Number', 'The body type to attach the CAS Part to. If not specified the body type of the CAS Part itself will be used.', is_optional=True, default_value='CAS Part Default Body Type'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to attach the CAS Part to.', is_optional=True, default_value='Active Sim') + ), + command_aliases=( + 's4clib.attachcaspart', + ) +) +def _s4clib_attach_cas_part(output: CommonConsoleCommandOutput, cas_part_id: int, body_type: str = 'any', sim_info: SimInfo = None): + if sim_info is None: + return + if cas_part_id < 0: + output('ERROR: CAS Part must be a positive number.') + return + if not CommonCASUtils.is_cas_part_loaded(cas_part_id): + output(f'ERROR: No CAS Part was found with id: {cas_part_id}') + return + if body_type is None: + output('ERROR: No Body Type specified.') + return + if body_type == 'any': + body_type_value = BodyType.NONE + elif isinstance(body_type, int): + body_type_value = body_type + elif isinstance(body_type, str) and body_type.isnumeric(): + try: + body_type_value = int(body_type) + except ValueError: + output(f'ERROR: The specified body type is neither a number nor the name of a BodyType {body_type}') + return + else: + body_type_value = CommonResourceUtils.get_enum_by_name(body_type.upper(), CommonBodySlot, default_value=None) + if body_type_value is None: + body_type_value = CommonResourceUtils.get_enum_by_name(body_type.upper(), BodyType, default_value=BodyType.NONE) + if body_type_value == BodyType.NONE: + output(f'ERROR: The specified body type is neither a number nor the name of a BodyType {body_type}') + return + + if body_type_value == BodyType.NONE: + body_type_value = CommonCASUtils.get_body_type_of_cas_part(cas_part_id) + + output(f'Attempting to attach CAS Part \'{cas_part_id}\' to Sim {sim_info} at body location {body_type_value}') + if CommonCASUtils.attach_cas_part_to_sim(sim_info, cas_part_id, body_type=body_type_value): + output(f'SUCCESS: CAS Part has been successfully attached to Sim {sim_info}.') + else: + output(f'FAILED: CAS Part failed to attach to Sim {sim_info}.') + output('Done attaching CAS Part to the Sim.') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.detach_cas_part', + 'Detach a CAS Part from a Sim. This is a permanent change to their current outfit!', + command_arguments=( + CommonConsoleCommandArgument('cas_part_id', 'Decimal Identifier', 'The decimal identifier of the CAS Part to detach.'), + CommonConsoleCommandArgument('body_type', 'Body Type Name or Number', 'The body type to detach the CAS Part from. If not specified the CAS part will be removed from any body types it is attached to on the Sim.', is_optional=True, default_value='All Body Types'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to detach the CAS Part from.', is_optional=True, default_value='Active Sim') + ), + command_aliases=( + 's4clib.detachcaspart', + ) +) +def _s4clib_detach_cas_part(output: CommonConsoleCommandOutput, cas_part_id: int, body_type: str = 'all', sim_info: SimInfo = None): + if sim_info is None: + return + if cas_part_id < 0: + output('ERROR: CAS Part Id must be a positive number.') + return + if not CommonCASUtils.is_cas_part_loaded(cas_part_id): + output(f'ERROR: No CAS Part was found with id: {cas_part_id}') + return + if body_type is None: + output('ERROR: No Body Type was specified.') + return + if body_type == 'all': + body_type_value = None + elif isinstance(body_type, int): + body_type_value = body_type + elif isinstance(body_type, str) and body_type.isnumeric(): + try: + body_type_value = int(body_type) + except ValueError: + output(f'ERROR: The specified body type is neither a number nor the name of a BodyType {body_type}') + return + else: + body_type_value = CommonResourceUtils.get_enum_by_name(body_type.upper(), CommonBodySlot, default_value=None) + if body_type_value is None: + body_type_value = CommonResourceUtils.get_enum_by_name(body_type.upper(), BodyType, default_value=BodyType.NONE) + + if body_type_value == BodyType.NONE: + body_type_value = CommonCASUtils.get_body_type_of_cas_part(cas_part_id) + output(f'Attempting to detach CAS Part \'{cas_part_id}\' from Sim {sim_info} at Body Type(s) {body_type}') + if CommonCASUtils.detach_cas_part_from_sim(sim_info, cas_part_id, body_type=body_type_value): + output(f'SUCCESS: CAS Part has been successfully detached from Sim {sim_info}.') + else: + output(f'FAILED: CAS Part failed to detach from Sim {sim_info}.') + output('Done detaching CAS Part from the Sim.') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.print_cas_part_at_body_type', + 'Print the Decimal Identifier of the CAS Part located at a specified Body Type on the current outfit of a Sim.', + command_arguments=( + CommonConsoleCommandArgument('body_type', 'Body Type Name or Number', 'The Body Type on the Sim to check.'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to check.', is_optional=True, default_value='Active Sim') + ) +) +def _s4clib_print_cas_part_at_body_type(output: CommonConsoleCommandOutput, body_type: str, sim_info: SimInfo = None): + if sim_info is None: + return + if body_type is None: + output('ERROR: No Body Type was specified.') + return + if isinstance(body_type, int): + body_type_value = body_type + elif isinstance(body_type, str) and not body_type.isnumeric(): + body_type_value = CommonResourceUtils.get_enum_by_name(body_type.upper(), BodyType, default_value=BodyType.NONE) + if body_type_value == BodyType.NONE: + output(f'ERROR: The specified body type is neither a number nor the name of a BodyType {body_type}') + return + else: + try: + body_type_value = int(body_type) + except ValueError: + output(f'ERROR: The specified body type is neither a number nor the name of a BodyType {body_type}') + return + output(f'Attempting to Print the ID of the CAS Part located at body type {body_type} on the outfit of {sim_info}.') + cas_part_id = CommonCASUtils.get_cas_part_id_at_body_type(sim_info, body_type_value) + output(f'Finished locating CAS Part Id. Sim: {sim_info} Body Type: {body_type}: CAS Part Id: {cas_part_id}') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.is_cas_part_available', + 'Determine if a CAS Part is available by its Decimal Identifier.', + command_arguments=( + CommonConsoleCommandArgument('cas_part_id', 'Decimal Identifier', 'The CAS Part to check.'), + ) +) +def _s4clib_is_cas_part_available(output: CommonConsoleCommandOutput, cas_part_id: int): + if cas_part_id is None: + output('ERROR: No CAS Part was specified!') + return + output(f'Checking if CAS Part with Id {cas_part_id} is available.') + if CommonCASUtils.is_cas_part_loaded(cas_part_id): + body_type = CommonCASUtils.get_body_type_of_cas_part(cas_part_id) + output(f'SUCCESS: The CAS Part with id {cas_part_id} is available with body location {body_type}.') + else: + output(f'FAILED: The CAS Part with id {cas_part_id} is not available.') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.print_skin_tone', + 'Print the Id of the Skin Tone of a Sim.', + command_arguments=( + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to retrieve the information from.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.printskintone', + ) +) +def _common_print_skin_tone(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): + if sim_info is None: + output('ERROR: Failed, no Sim was specified or the specified Sim was not found!') + return + output(f'Attempting to print the Skin Tone of Sim {sim_info}.') + output(f'Sim: {sim_info}') + skin_tone_id = CommonCASUtils.get_skin_tone(sim_info) + output(f'Skin Tone: {skin_tone_id}') + skin_tone_value_shift = CommonCASUtils.get_skin_tone_value_shift(sim_info) + output(f'Skin Tone Value Shift: {skin_tone_value_shift}') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.set_skin_tone', + 'Change the Skin Tone of a Sim to a specified Skin Tone.', + command_arguments=( + CommonConsoleCommandArgument('skin_tone_id', 'Decimal Identifier', 'The decimal identifier of the Skin Tone to change the Sim to.'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to change the Skin Tone of.', is_optional=True, default_value='Active Sim') + ), + command_aliases=( + 's4clib.setskintone', + ) +) +def _common_set_skin_tone(output: CommonConsoleCommandOutput, skin_tone_id: int, sim_info: SimInfo = None): + if sim_info is None: + output('ERROR: Failed, no Sim was specified or the specified Sim was not found!') + return + output(f'Attempting to set the skin tone of Sim {sim_info} to \'{skin_tone_id}\'.') + CommonCASUtils.set_skin_tone(sim_info, skin_tone_id) + output(f'Done setting the Skin Tone of the Sim {sim_info}.') diff --git a/Scripts/s4ap/sims4communitylib/utils/cas/common_outfit_utils.py b/Scripts/s4ap/sims4communitylib/utils/cas/common_outfit_utils.py new file mode 100644 index 0000000..e4f85e1 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/cas/common_outfit_utils.py @@ -0,0 +1,1466 @@ +""" +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 +""" +import os + +from animation.arb import Arb +from buffs.appearance_modifier.appearance_modifier import AppearanceModifier +from buffs.appearance_modifier.appearance_modifier_type import AppearanceModifierType +from buffs.appearance_modifier.appearance_tracker import ModifierInfo +from cas.cas import OutfitData +from sims.outfits.outfit_enums import OutfitCategory, BodyType, OutfitFilterFlag, BodyTypeFlag +from sims.sim_info import SimInfo +from sims.sim_info_base_wrapper import SimInfoBaseWrapper +from sims4.utils import classproperty +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.enums.buffs_enum import CommonBuffId +from sims4communitylib.enums.tags_enum import CommonGameTag +from sims4communitylib.logging.has_class_log import HasClassLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + CommonConsoleCommandArgument +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.common_log_registry import CommonLogRegistry +from sims4communitylib.utils.common_resource_utils import CommonResourceUtils +from sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils +from sims4communitylib.utils.sims.common_buff_utils import CommonBuffUtils +from singletons import DEFAULT +from typing import Tuple, Union, Dict, Callable, Iterator, Set + +ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' + +if ON_RTD: + # noinspection PyMissingOrEmptyDocstring + class OutfitCategory: + + @classproperty + def value_to_name(self) -> Dict['OutfitCategory', str]: + pass + + @classproperty + def name_to_value(self) -> Dict[str, 'OutfitCategory']: + pass + + # noinspection PyMissingOrEmptyDocstring + class BodyType: + NONE = 0 + + @classproperty + def value_to_name(self) -> Dict['BodyType', str]: + pass + + @classproperty + def name_to_value(self) -> Dict[str, 'BodyType']: + pass + + # noinspection PyMissingOrEmptyDocstring + class SimInfo: + pass + +if not ON_RTD: + from sims.outfits.outfit_enums import OutfitCategory, BodyType + from sims.sim_info import SimInfo + + +class CommonOutfitUtils(HasClassLog): + """Utilities for handling Sim outfits. + + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + return ModInfo.get_identity() + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 'common_outfit_utils' + + @classmethod + def has_permission_to_change_to_nude(cls, sim_info: SimInfo) -> CommonTestResult: + """has_permission_to_change_to_nude(sim_info) + + Determine if a Sim has permission to change to their Nude (Bathing) outfit. + + .. note:: In the vanilla game, only Adult and Elder Sims have permission to change to Nude. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of the test. True, if the test passes. False, if the test fails. + :rtype: CommonTestResult + """ + if not CommonAgeUtils.is_teen_adult_or_elder(sim_info): + return CommonTestResult(False, reason=f'{sim_info} does not have permission to change to Nude. They are neither an Adult nor Elder Sim.') + return CommonTestResult(True, reason=f'{sim_info} has permission to change to their Nude outfit.') + + @classmethod + def is_every_day_category(cls, 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 int(outfit_category) == int(OutfitCategory.EVERYDAY) + + @classmethod + def is_formal_category(cls, 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 int(outfit_category) == int(OutfitCategory.FORMAL) + + @classmethod + def is_athletic_category(cls, 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 int(outfit_category) == int(OutfitCategory.ATHLETIC) + + @classmethod + def is_sleep_category(cls, 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 int(outfit_category) == int(OutfitCategory.SLEEP) + + @classmethod + def is_party_category(cls, 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 int(outfit_category) == int(OutfitCategory.PARTY) + + @classmethod + def is_bathing_category(cls, 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 int(outfit_category) == int(OutfitCategory.BATHING) + + @classmethod + def is_career_category(cls, 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 int(outfit_category) == int(OutfitCategory.CAREER) + + @classmethod + def is_situation_category(cls, 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 int(outfit_category) == int(OutfitCategory.SITUATION) + + @classmethod + def is_special_category(cls, 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 int(outfit_category) == int(OutfitCategory.SPECIAL) + + @classmethod + def is_swimwear_category(cls, 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 int(outfit_category) == int(OutfitCategory.SWIMWEAR) + + @classmethod + def is_hot_weather_category(cls, 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 int(outfit_category) == int(OutfitCategory.HOTWEATHER) + except: + return False + + @classmethod + def is_cold_weather_category(cls, 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 int(outfit_category) == int(OutfitCategory.COLDWEATHER) + except: + return False + + @classmethod + def is_batuu_category(cls, 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 int(outfit_category) == int(OutfitCategory.BATUU) + except: + return False + + @classmethod + def get_all_outfit_categories(cls) -> 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) + + @classmethod + def is_wearing_everyday_outfit(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper]) -> 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: Union[SimInfo, SimInfoBaseWrapper] + :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)) + + @classmethod + def is_wearing_formal_outfit(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper]) -> 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: Union[SimInfo, SimInfoBaseWrapper] + :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)) + + @classmethod + def is_wearing_athletic_outfit(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper]) -> 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: Union[SimInfo, SimInfoBaseWrapper] + :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)) + + @classmethod + def is_wearing_sleep_outfit(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper]) -> 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: Union[SimInfo, SimInfoBaseWrapper] + :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)) + + @classmethod + def is_wearing_party_outfit(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper]) -> 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: Union[SimInfo, SimInfoBaseWrapper] + :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)) + + @classmethod + def is_wearing_bathing_outfit(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper]) -> 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: Union[SimInfo, SimInfoBaseWrapper] + :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)) + + @classmethod + def is_wearing_career_outfit(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper]) -> 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: Union[SimInfo, SimInfoBaseWrapper] + :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)) + + @classmethod + def is_wearing_situation_outfit(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper]) -> 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: Union[SimInfo, SimInfoBaseWrapper] + :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)) + + @classmethod + def is_wearing_special_outfit(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper]) -> 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: Union[SimInfo, SimInfoBaseWrapper] + :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)) + + @classmethod + def is_wearing_swimwear_outfit(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper]) -> 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: Union[SimInfo, SimInfoBaseWrapper] + :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)) + + @classmethod + def is_wearing_hot_weather_outfit(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper]) -> 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: Union[SimInfo, SimInfoBaseWrapper] + :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)) + + @classmethod + def is_wearing_cold_weather_outfit(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper]) -> 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: Union[SimInfo, SimInfoBaseWrapper] + :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)) + + @classmethod + def is_wearing_batuu_outfit(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper]) -> 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: Union[SimInfo, SimInfoBaseWrapper] + :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)) + + @classmethod + def is_wearing_towel(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper]) -> CommonTestResult: + """is_wearing_towel(sim_info) + + Determine if a Sim is currently wearing a towel. + + :param sim_info: The Sim to check. + :type sim_info: Union[SimInfo, SimInfoBaseWrapper] + :return: The result of testing. True, if the sim is wearing a towel. False, if not. + :rtype: CommonTestResult + """ + return CommonBuffUtils.has_buff(sim_info, CommonBuffId.IS_WEARING_TOWEL) + + @classmethod + def get_outfit_category_by_name(cls, name: str, default_category: Union[OutfitCategory, None] = OutfitCategory.CURRENT_OUTFIT) -> OutfitCategory: + """get_outfit_category_by_name(name, default_value=OutfitCategory.CURRENT_OUTFIT) + + Retrieve an OutfitCategory by name. + + :param name: The name of an outfit category. + :type name: str + :param default_category: The default outfit category to use if the outfit category is not found using the specified name. Default is OutfitCategory.CURRENT_OUTFIT. + :type default_category: Union[OutfitCategory, None], optional + :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=default_category) + + @classmethod + def convert_value_to_outfit_category(cls, value: Union[OutfitCategory, int]) -> Union[OutfitCategory, int]: + """convert_value_to_outfit_category(value) + + Retrieve an OutfitCategory by value. + + :param value: The value of an outfit category. + :type value: Union[OutfitCategory, int] + :return: The OutfitCategory with the specified value or the specified value if no OutfitCategory was found. + :rtype: Union[OutfitCategory, int] + """ + if isinstance(value, OutfitCategory): + return value + if value in OutfitCategory.value_to_name: + return CommonResourceUtils.get_enum_by_name(OutfitCategory.value_to_name[value], OutfitCategory, default_value=value) + return value + + @classmethod + def get_current_outfit_category(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper]) -> 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: Union[SimInfo, SimInfoBaseWrapper] + :return: The OutfitCategory of the current outfit a Sim is wearing. + :rtype: OutfitCategory + """ + return CommonOutfitUtils.get_current_outfit(sim_info)[0] + + @classmethod + def get_current_outfit_index(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper]) -> 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: Union[SimInfo, SimInfoBaseWrapper] + :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] + + @classmethod + def get_current_outfit(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper]) -> 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: Union[SimInfo, SimInfoBaseWrapper] + :return: The OutfitCategory and index of the current outfit a Sim is wearing. + :rtype: Tuple[OutfitCategory, int] + """ + if sim_info is None: + return OutfitCategory.EVERYDAY, 0 + current_outfit = sim_info.get_current_outfit() + # noinspection PyBroadException + try: + current_outfit_category = cls.convert_value_to_outfit_category(current_outfit[0]) + except: + current_outfit_category = current_outfit[0] + if current_outfit_category is None: + current_outfit_category = current_outfit[0] + return current_outfit_category, current_outfit[1] + + @classmethod + def get_appearance_modifiers_gen(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper], appearance_modifier_type: AppearanceModifierType, include_appearance_modifier_callback: Callable[[ModifierInfo], bool] = None) -> Iterator[AppearanceModifier]: + """get_appearance_modifiers_gen(sim_info, appearance_modifier_type, include_appearance_modifier_callback=None) + + Retrieve the appearance modifiers of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: Union[SimInfo, SimInfoBaseWrapper] + :param appearance_modifier_type: The type of appearance modifiers to retrieve. + :type appearance_modifier_type: AppearanceModifierType + :param include_appearance_modifier_callback: If an appearance modifier matches this callback, then it will be returned. Default is None. + :type include_appearance_modifier_callback: Callable[[ModifierInfo], bool], optional + :return: A collection of appearance modifiers. + :rtype: Iterator[AppearanceModifier] + """ + if sim_info is None: + return tuple() + if not hasattr(sim_info, 'appearance_tracker') or sim_info.appearance_tracker is None: + return tuple() + if appearance_modifier_type is None: + return + active_appearance_modifier_info_library: Dict[AppearanceModifierType, Tuple[ModifierInfo]] = sim_info.appearance_tracker._active_appearance_modifier_infos + if active_appearance_modifier_info_library is None: + return tuple() + if appearance_modifier_type not in active_appearance_modifier_info_library: + return tuple() + modifier_info_list = active_appearance_modifier_info_library[appearance_modifier_type] + if not modifier_info_list: + return tuple() + for modifier_info in modifier_info_list: + if modifier_info is None: + continue + if include_appearance_modifier_callback is not None and not include_appearance_modifier_callback(modifier_info): + continue + yield modifier_info.modifier + + @classmethod + def get_outfit_data(cls, sim_info: Union[Union[SimInfo, SimInfoBaseWrapper], SimInfoBaseWrapper], outfit_category_and_index: Union[Tuple[OutfitCategory, int], None] = None) -> Union[OutfitData, None]: + """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: Union[SimInfo, SimInfoBaseWrapper] + :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 or None if the Sim does not have the specified outfit. + :rtype: Union[OutfitData, None] + """ + if outfit_category_and_index is None: + outfit_category_and_index = CommonOutfitUtils.get_current_outfit(sim_info) + if not cls.has_outfit(sim_info, outfit_category_and_index): + return None + return sim_info.get_outfit(outfit_category_and_index[0], outfit_category_and_index[1]) + + @classmethod + def has_cas_part_attached(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper], 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: Union[SimInfo, SimInfoBaseWrapper] + :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) + + @classmethod + def has_any_cas_parts_attached(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper], 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: Union[SimInfo, SimInfoBaseWrapper] + :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 + + @classmethod + def get_outfit_parts(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper], outfit_category_and_index: Union[Tuple[OutfitCategory, int], None] = None) -> Dict[Union[BodyType, int], 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: Union[SimInfo, SimInfoBaseWrapper] + :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. If an outfit does not exist, an empty dict will be returned. + :rtype: Dict[Union[BodyType, int], int] + """ + if outfit_category_and_index is None: + outfit_category_and_index = CommonOutfitUtils.get_current_outfit(sim_info) + if not cls.has_outfit(sim_info, outfit_category_and_index): + return dict() + 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))) + + @classmethod + def refresh_outfit(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper], outfit_category_and_index: Union[Tuple[OutfitCategory, int], None] = None): + """refresh_outfit(sim_info, outfit_category_and_index=None) + + Refresh the outfit of a Sim. + + :param sim_info: The info of a Sim. + :type sim_info: Union[SimInfo, SimInfoBaseWrapper] + :param outfit_category_and_index: The OutfitCategory and index to refresh. Default is the Sims current outfit. + :type outfit_category_and_index: Tuple[OutfitCategory, int], optional + """ + if outfit_category_and_index is None: + outfit_category_and_index = CommonOutfitUtils.get_current_outfit(sim_info) + if not cls.has_outfit(sim_info, outfit_category_and_index): + return + cls.trigger_outfit_generated(sim_info, outfit_category_and_index) + cls.set_outfit_dirty(sim_info, outfit_category_and_index[0]) + cls.set_current_outfit(sim_info, outfit_category_and_index) + + @classmethod + def trigger_outfit_generated(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper], outfit_category_and_index: Tuple[OutfitCategory, int]): + """trigger_outfit_generated(sim_info, outfit_category_and_index) + + Trigger the outfit generated callbacks for a Sim with an OutfitCategory and Index. + + :param sim_info: The info of a Sim. + :type sim_info: Union[SimInfo, SimInfoBaseWrapper] + :param outfit_category_and_index: The OutfitCategory and index to send. + :type outfit_category_and_index: Tuple[OutfitCategory, int] + """ + sim_info.on_outfit_generated(*outfit_category_and_index) + + @classmethod + def set_current_outfit(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper], 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: Union[SimInfo, SimInfoBaseWrapper] + :param outfit_category_and_index: The OutfitCategory and index to change to. + :type outfit_category_and_index: Tuple[OutfitCategory, int] + """ + arb = Arb() + sim_info.try_set_current_outfit(outfit_category_and_index, arb=arb) + + @classmethod + def set_outfit_dirty(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper], 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: Union[SimInfo, SimInfoBaseWrapper] + :param outfit_category: The OutfitCategory being flagged. + :type outfit_category: OutfitCategory + """ + sim_info.set_outfit_dirty(outfit_category) + + @classmethod + def set_outfit_clean(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper], 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: Union[SimInfo, SimInfoBaseWrapper] + :param outfit_category: The OutfitCategory being flagged. + :type outfit_category: OutfitCategory + """ + sim_info.clear_outfit_dirty(outfit_category) + + @classmethod + def generate_outfit( + cls, + sim_info: Union[SimInfo, SimInfoBaseWrapper], + outfit_category_and_index: Tuple[OutfitCategory, int], + tag_list: Tuple[CommonGameTag] = (), + outfit_filter_flag: OutfitFilterFlag = DEFAULT, + body_type_flags: BodyTypeFlag = DEFAULT, + ignore_if_exists: bool = False, + **kwargs + ) -> bool: + """generate_outfit(\ + sim_info,\ + outfit_category_and_index,\ + tag_list=(),\ + outfit_filter_flag=DEFAULT,\ + body_type_flags=DEFAULT,\ + ignore_if_exists=False,\ + **kwargs\ + ) + + 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: Union[SimInfo, SimInfoBaseWrapper] + :param outfit_category_and_index: The OutfitCategory and Index of the outfit to generate. + :type outfit_category_and_index: Tuple[OutfitCategory, int] + :param tag_list: A collection of tags to match CAS Parts to. Default is any tag. + :type tag_list: Tuple[CommonGameTag], optional + :param outfit_filter_flag: Flags to filter CAS Parts with. Default is no flags. + :type outfit_filter_flag: OutfitFilterFlag, optional + :param body_type_flags: Flags to filter CAS Parts with. Default is no flags. + :type body_type_flags: BodyTypeFlag, optional + :param ignore_if_exists: If set to True, the outfit will not be generated if an outfit already exists at the specified Outfit Category and Index. + :return: True, if an outfit was generated successfully. False, if not. + :rtype: bool + """ + + if ignore_if_exists and CommonOutfitUtils.has_outfit(sim_info, outfit_category_and_index): + cls.get_log().format_with_message('Outfit already existed, no need to generate it!', sim=sim_info, outfit_category_and_index=outfit_category_and_index) + return False + + outfit_category = outfit_category_and_index[0] + outfit_index = outfit_category_and_index[1] + return sim_info.generate_outfit(outfit_category, outfit_index=outfit_index, tag_list=tag_list, filter_flag=outfit_filter_flag, body_type_flags=body_type_flags, **kwargs) + + @classmethod + def copy_outfit(cls, mod_identity: CommonModIdentity, sim_info: SimInfo, from_outfit_category_and_index: Tuple[OutfitCategory, int], to_outfit_category_and_index: Tuple[OutfitCategory, int], change_sim_to_outfit_after_apply: bool = False) -> bool: + """copy_outfit(mod_identity, sim_info, from_outfit_category_and_index, to_outfit_category_and_index, change_sim_to_outfit_after_apply=False) + + Copy one Outfit of a Sim to another Outfit of the same Sim. + + :param mod_identity: The identity of the mod copying the outfit. + :type mod_identity: CommonModIdentity + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param from_outfit_category_and_index: The Outfit Category and Index to copy CAS Parts from. + :type from_outfit_category_and_index: Tuple[OutfitCategory, int] + :param to_outfit_category_and_index: The Outfit Category and Index to copy CAS Parts to. + :type to_outfit_category_and_index: Tuple[OutfitCategory, int] + :param change_sim_to_outfit_after_apply: Set to True to change the Sim to the outfit after the changes are applied. Default is False. + :type change_sim_to_outfit_after_apply: bool, optional + :return: True, if CAS Parts were copied successfully. False, if not. + :rtype: bool + """ + from sims4communitylib.services.sim.cas.common_sim_outfit_io import CommonSimOutfitIO + outfit_io = CommonSimOutfitIO(sim_info, outfit_category_and_index=from_outfit_category_and_index, mod_identity=mod_identity) + return outfit_io.apply(change_sim_to_outfit_after_apply=change_sim_to_outfit_after_apply, apply_to_all_outfits_in_same_category=False, apply_to_outfit_category_and_index=to_outfit_category_and_index) + + @classmethod + def regenerate_outfit(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper], outfit_category_and_index: Tuple[OutfitCategory, int]) -> None: + """regenerate_outfit(sim_info, outfit_category_and_index) + + Delete and regenerate an outfit of a Sim. + + .. note:: If the Sim does not have the specified outfit to regenerate, it will be generated instead. + + :param sim_info: An instance of a Sim. + :type sim_info: Union[SimInfo, SimInfoBaseWrapper] + :param outfit_category_and_index: The OutfitCategory and index to regenerate for the Sim. + :type outfit_category_and_index: Tuple[OutfitCategory, int] + """ + current_outfit = CommonOutfitUtils.get_current_outfit(sim_info) + outfit_flags = OutfitFilterFlag.USE_EXISTING_IF_APPROPRIATE & OutfitFilterFlag.USE_VALID_FOR_LIVE_RANDOM + tags = tuple() + from sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils + if CommonSimGenderOptionUtils.prefers_menswear(sim_info): + tags = (CommonGameTag.GENDER_APPROPRIATE_MALE,) + elif CommonSimGenderOptionUtils.prefers_womenswear(sim_info): + tags = (CommonGameTag.GENDER_APPROPRIATE_FEMALE,) + outfit = outfit_category_and_index + cls.get_log().format_with_message('Generating outfit', outfit=outfit) + generate_result = CommonOutfitUtils.generate_outfit(sim_info, outfit, outfit_filter_flag=outfit_flags, tag_list=tags) + cls.get_log().format_with_message('Finished generating outfit', outfit=outfit, generate_result=generate_result, outfit_flags=outfit_flags, tags=tags) + sim_info.appearance_tracker.evaluate_appearance_modifiers() + CommonOutfitUtils.resend_outfits(sim_info) + CommonOutfitUtils.set_current_outfit(sim_info, current_outfit) + + @classmethod + def regenerate_all_outfits(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper]) -> None: + """regenerate_all_outfits(sim_info) + + Delete and regenerate all outfits for a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: Union[SimInfo, SimInfoBaseWrapper] + """ + current_outfit = CommonOutfitUtils.get_current_outfit(sim_info) + outfit_flags = OutfitFilterFlag.USE_EXISTING_IF_APPROPRIATE & OutfitFilterFlag.USE_VALID_FOR_LIVE_RANDOM + tags = tuple() + from sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils + if CommonSimGenderOptionUtils.prefers_menswear(sim_info): + tags = (CommonGameTag.GENDER_APPROPRIATE_MALE,) + elif CommonSimGenderOptionUtils.prefers_womenswear(sim_info): + tags = (CommonGameTag.GENDER_APPROPRIATE_FEMALE,) + for outfit_category in CommonOutfitUtils.get_all_outfit_categories(): + for outfit_index in range(cls.get_maximum_number_of_outfits_for_category(outfit_category)): + outfit = (outfit_category, outfit_index) + if not CommonOutfitUtils.has_outfit(sim_info, outfit): + cls.get_log().format_with_message('Sim did not have outfit.', sim=sim_info, outfit=outfit) + continue + cls.get_log().format_with_message('Generating outfit', outfit=outfit) + generate_result = CommonOutfitUtils.generate_outfit(sim_info, outfit, outfit_filter_flag=outfit_flags, tag_list=tags) + cls.get_log().format_with_message('Finished generating outfit', outfit=outfit, generate_result=generate_result, outfit_flags=outfit_flags, tags=tags) + sim_info.appearance_tracker.evaluate_appearance_modifiers() + CommonOutfitUtils.resend_outfits(sim_info) + CommonOutfitUtils.set_current_outfit(sim_info, current_outfit) + + @classmethod + def resend_outfits(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper]) -> 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: Union[SimInfo, SimInfoBaseWrapper] + :return: True, if outfits were resent successfully. False, if not. + :rtype: bool + """ + sim_info.resend_outfits() + return True + + @classmethod + def get_maximum_number_of_outfits_for_category(cls, outfit_category: OutfitCategory) -> int: + """get_maximum_number_of_outfits_for_category(outfit_category) + + Retrieve the maximum number of outfits allowed for an outfit category. + + :param outfit_category: The outfit category to check. + :type outfit_category: OutfitCategory + :return: The maximum number of Outfits a Sim may have within the specified outfit category. + :rtype: int + """ + if outfit_category is None: + return 0 + from sims.outfits.outfit_utils import get_maximum_outfits_for_category + return get_maximum_outfits_for_category(outfit_category) + + @classmethod + def get_previous_outfit(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper], 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: Union[SimInfo, SimInfoBaseWrapper] + :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 + + @classmethod + def remove_previous_outfit(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper]): + """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: Union[SimInfo, SimInfoBaseWrapper] + """ + sim_info.set_previous_outfit(None, force=True) + + @classmethod + def get_all_outfit_category_and_indexes(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper], include_outfit_categories: Tuple[OutfitCategory] = ()) -> Tuple[Tuple[OutfitCategory, int]]: + """get_all_outfit_category_and_indexes(sim_info, include_outfit_categories=()) + + Retrieve a collection of outfit category and index for each outfit available to a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: Union[SimInfo, SimInfoBaseWrapper] + :param include_outfit_categories: A collection of outfit categories to include. If empty, all outfit categories will be included. Default is empty. + :type include_outfit_categories: Tuple[OutfitCategory], optional + :return: A collection of outfit category and index for each outfit available to a Sim. + :rtype: Tuple[Tuple[OutfitCategory, int]] + """ + outfits = sim_info.get_outfits() + outfit_list = list() + for (outfit_category, _outfit_list) in outfits.get_all_outfits(): + outfit_category: OutfitCategory = outfit_category + if include_outfit_categories and outfit_category not in include_outfit_categories: + continue + for (outfit_index, _) in enumerate(_outfit_list): + outfit_index: int = outfit_index + outfit_list.append((outfit_category, outfit_index)) + return tuple(outfit_list) + + @classmethod + def has_outfit(cls, sim_info: Union[Union[SimInfo, SimInfoBaseWrapper], SimInfoBaseWrapper], 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: Union[Union[SimInfo, SimInfoBaseWrapper], SimInfoBaseWrapper] + :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) + + @classmethod + def update_outfits(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper]) -> bool: + """update_outfits(sim_info) + + Update all outfits of a Sim. + + :param sim_info: The Sim to update outfits for. + :type sim_info: Union[SimInfo, SimInfoBaseWrapper] + :return: True, if the outfits were updated successfully. False, if not. + :rtype: bool + """ + sim_info.on_outfit_changed(sim_info, CommonOutfitUtils.get_current_outfit(sim_info), CommonOutfitUtils.get_current_outfit(sim_info)) + CommonOutfitUtils.resend_outfits(sim_info) + sim_info.appearance_tracker.evaluate_appearance_modifiers() + return True + + @classmethod + def has_tag_on_outfit(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper], tag: Union[int, CommonGameTag], outfit_category_and_index: Union[Tuple[OutfitCategory, int], None] = None) -> bool: + """has_tag_on_outfit(sim_info, tag, outfit_category_and_index=None) + + Determine if the Outfit of a Sim has the specified tag. + + :param sim_info: An instance of a Sim. + :type sim_info: Union[SimInfo, SimInfoBaseWrapper] + :param tag: A tag to locate. + :type tag: Union[int, CommonGameTag] + :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: True, if the Outfit of the Sim has the specified tag. False, if not. + :rtype: bool + """ + return CommonOutfitUtils.has_any_tags_on_outfit(sim_info, (tag, ), outfit_category_and_index=outfit_category_and_index) + + @classmethod + def has_any_tags_on_outfit(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper], tags: Iterator[Union[int, CommonGameTag]], outfit_category_and_index: Union[Tuple[OutfitCategory, int], None] = None) -> bool: + """has_any_tags_on_outfit(sim_info, tags, outfit_category_and_index=None) + + Determine if the Outfit of a Sim has any of the specified tags. + + :param sim_info: An instance of a Sim. + :type sim_info: Union[SimInfo, SimInfoBaseWrapper] + :param tags: A collection of tags to locate. + :type tags: Iterator[Union[int, CommonGameTag]] + :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: True, if the Outfit of the Sim has any of the specified tags. False, if not. + :rtype: bool + """ + if sim_info is None: + return False + if not tags: + return False + outfit_tags = CommonOutfitUtils.get_all_outfit_tags(sim_info, outfit_category_and_index=outfit_category_and_index) + for tag in tags: + if tag in outfit_tags: + return True + return False + + @classmethod + def has_all_tags_on_outfit(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper], tags: Iterator[Union[int, CommonGameTag]], outfit_category_and_index: Union[Tuple[OutfitCategory, int], None] = None) -> bool: + """has_all_tags_on_outfit(sim_info, tags, outfit_category_and_index=None) + + Determine if the Outfit of a Sim has all of the specified tags. + + :param sim_info: An instance of a Sim. + :type sim_info: Union[SimInfo, SimInfoBaseWrapper] + :param tags: A collection of tags to locate. + :type tags: Iterator[Union[int, CommonGameTag]] + :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: True, if the Outfit of the Sim has all of the specified tags. False, if not. + :rtype: bool + """ + if sim_info is None: + return False + if not tags: + return False + outfit_tags = CommonOutfitUtils.get_all_outfit_tags(sim_info, outfit_category_and_index=outfit_category_and_index) + for tag in tags: + if tag not in outfit_tags: + return False + return True + + @classmethod + def get_all_outfit_tags(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper], outfit_category_and_index: Union[Tuple[OutfitCategory, int], None] = None) -> Tuple[CommonGameTag]: + """get_all_outfit_tags(sim_info, outfit_category_and_index=None) + + Retrieve a collection of game tags that apply to the outfit of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: Union[SimInfo, SimInfoBaseWrapper] + :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 collection of Game Tags that apply to the outfit of a Sim. + :rtype: Tuple[CommonGameTag] + """ + if sim_info is None: + return tuple() + combined_game_tags = list() + for game_tags in CommonOutfitUtils.get_outfit_tags_by_cas_part_id(sim_info, outfit_category_and_index=outfit_category_and_index).values(): + for game_tag in game_tags: + if game_tag not in combined_game_tags: + combined_game_tags.append(game_tag) + return tuple(combined_game_tags) + + @classmethod + def get_outfit_tags_by_cas_part_id(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper], outfit_category_and_index: Union[Tuple[OutfitCategory, int], None] = None) -> Dict[int, Set[CommonGameTag]]: + """get_outfit_tags_by_cas_part_id(sim_info, outfit_category_and_index=None) + + Retrieve the game tags of the outfit of a Sim grouped by CAS Part Id. + + :param sim_info: An instance of a Sim. + :type sim_info: Union[SimInfo, SimInfoBaseWrapper] + :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 library of Game Tags grouped by CAS Part Id. + :rtype: Dict[int, Tuple[CommonGameTag]] + """ + if sim_info is None: + return dict() + from cas.cas import get_tags_from_outfit + outfit_category_and_index = outfit_category_and_index or CommonOutfitUtils.get_current_outfit(sim_info) + # noinspection PyBroadException + try: + return get_tags_from_outfit(sim_info._base, outfit_category_and_index[0], outfit_category_and_index[1]) + except: + return dict() + + @classmethod + def _print_outfit(cls, sim_info: SimInfo, outfit_category: OutfitCategory, outfit_index: int, output: CommonConsoleCommandOutput): + from sims4communitylib.services.sim.cas.common_sim_outfit_io import CommonSimOutfitIO + if not isinstance(outfit_category, OutfitCategory): + # noinspection PyBroadException + try: + outfit_category = CommonResourceUtils.get_enum_by_int_value(int(outfit_category), OutfitCategory, default_value=outfit_category) + except: + output(f'ERROR: Failed to parse {outfit_category} as OutfitCategory.') + return + + # noinspection PyBroadException + if hasattr(outfit_category, 'name'): + outfit_category_name = outfit_category.name + else: + outfit_category_name = outfit_category + + output(f'Outfit Info for outfit ({outfit_category_name}, {outfit_index}) of Sim {sim_info}') + outfit_commands_log.debug(f'Outfit Info for outfit ({outfit_category_name}, {outfit_index}) of Sim {sim_info}') + outfit_io = CommonSimOutfitIO(sim_info, outfit_category_and_index=(outfit_category, outfit_index)) + output(f'------Outfit: ({outfit_category_name}, {outfit_index})------') + outfit_commands_log.debug(f'------Outfit: ({outfit_category_name}, {outfit_index})------') + for (body_type, cas_part_id) in zip(outfit_io.body_types, outfit_io.cas_part_ids): + body_type_value = int(body_type) + if not isinstance(body_type, BodyType): + # noinspection PyBroadException + try: + body_type = CommonResourceUtils.get_enum_by_int_value(int(body_type), BodyType, default_value=body_type) + except: + output(f' {str(body_type)} ({body_type_value}): {cas_part_id}') + outfit_commands_log.debug(f'{str(body_type)} ({body_type_value}): {cas_part_id}') + continue + if hasattr(body_type, 'name'): + body_type_name = body_type.name + else: + body_type_name = str(body_type) + output(f' {body_type_name} ({body_type_value}): {cas_part_id}') + outfit_commands_log.debug(f'{body_type_name} ({body_type_value}): {cas_part_id}') + output('----------------------------') + output('-') + outfit_commands_log.debug('----------------------------') + outfit_commands_log.debug('-') + + @classmethod + def _parse_outfit_category_and_index_from_str(cls, output: CommonConsoleCommandOutput, outfit_category: str, outfit_index: int, sim_info: SimInfo = None, check_for_missing_outfit: bool = True, outfit_category_required: bool = False) -> Union[Tuple[OutfitCategory, int], None]: + outfit_category_value_names = ', '.join(OutfitCategory.name_to_value.keys()) + if outfit_category is None: + if outfit_category_required: + output(f'ERROR: Outfit Category not specified. Valid OutfitCategory: ({outfit_category_value_names})') + return None + if outfit_index <= 0: + output('ERROR: Outfit Index must be a value above Zero.') + return None + if not outfit_category.isnumeric(): + outfit_category_value = CommonResourceUtils.get_enum_by_name(outfit_category.upper(), OutfitCategory, default_value=None) + if outfit_category_value is None: + output(f'ERROR: No Outfit Category existed with name {outfit_category}. Valid OutfitCategory: ({outfit_category_value_names})') + return + else: + try: + outfit_category_value = int(outfit_category) + except ValueError: + output(f'ERROR: The specified outfit category is neither a number nor the name of an OutfitCategory {outfit_category}. Valid OutfitCategory: ({outfit_category_value_names})') + return + outfit_category_value = CommonResourceUtils.get_enum_by_int_value(outfit_category_value, OutfitCategory, default_value=None) + if outfit_category_value is None: + output(f'ERROR: No Outfit Category existed with value {outfit_category}. Valid OutfitCategory: ({outfit_category_value_names})') + return + + outfit_category_and_index = (outfit_category_value, outfit_index) + if check_for_missing_outfit and sim_info is not None: + if not CommonOutfitUtils.has_outfit(sim_info, outfit_category_and_index): + output(f'ERROR: The Sim {sim_info} did not have the specified outfit {outfit_category_and_index[0].name} at index {outfit_category_and_index[1]}') + return + return outfit_category_and_index + + +outfit_commands_log = CommonLogRegistry().register_log(ModInfo.get_identity(), 's4cl_outfit_commands') +outfit_commands_log.enable() + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_testing.print_all_outfit_categories', + 'Print a list of all outfit categories that are available to Sims.' +) +def _s4clib_testing_print_all_outfit_categories(output: CommonConsoleCommandOutput): + output('Printing all outfit categories.') + outfit_categories_name_str = ', '.join([outfit_category.name if hasattr(outfit_category, 'name') else str(outfit_category) for outfit_category in CommonOutfitUtils.get_all_outfit_categories()]) + output(f'Outfit categories: {outfit_categories_name_str}') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_testing.print_outfit_tags', + 'Print a list of all Game Tags applied to the outfit of a Sim.', + command_arguments=( + CommonConsoleCommandArgument('outfit_category', 'Value or Name', 'The Value or Name of the Outfit Category to check.', is_optional=True, default_value='Current Outfit'), + CommonConsoleCommandArgument('outfit_index', 'Positive Number', 'The index of the outfit to check. This value does nothing if an Outfit Category is not specified.', is_optional=True, default_value=1), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to check.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib_testing.printoutfittags', + ) +) +def _s4clib_testing_print_outfit_tags(output: CommonConsoleCommandOutput, outfit_category: str = None, outfit_index: int = 1, sim_info: SimInfo = None): + if sim_info is None: + return + outfit_category_and_index = CommonOutfitUtils._parse_outfit_category_and_index_from_str(output, outfit_category=outfit_category, outfit_index=outfit_index, sim_info=sim_info) + if outfit_category_and_index is None: + outfit_category_and_index = CommonOutfitUtils.get_current_outfit(sim_info) + + output(f'Attempting to print all game tags of outfit ({outfit_category_and_index[0].name}, {outfit_category_and_index[1]}) for Sim {sim_info}.') + outfit_commands_log.debug(f'Printing all game tags of outfit ({outfit_category_and_index[0].name}, {outfit_category_and_index[1]}) for Sim {sim_info}.') + outfit_commands_log.debug(f'-------Game Tags For Outfit Category: ({outfit_category_and_index[0].name}, {outfit_category_and_index[1]})-------') + tag_values = CommonOutfitUtils.get_all_outfit_tags(sim_info, outfit_category_and_index=outfit_category_and_index) + cleaned_tag_names = list() + for tag_value in tag_values: + if isinstance(tag_value, CommonGameTag): + tag = tag_value + else: + tag = CommonResourceUtils.get_enum_by_int_value(int(tag_value), CommonGameTag, default_value=tag_value) + cleaned_tag_names.append(tag.name if hasattr(tag, 'name') else str(tag)) + + sorted_tag_names = sorted(cleaned_tag_names) + tags_str = ', '.join(sorted_tag_names) + output(f'Game Tags: {tags_str}') + for sorted_tag_name in sorted_tag_names: + outfit_commands_log.debug(str(sorted_tag_name)) + outfit_commands_log.debug(f'--------------------------------') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_testing.print_outfit_tags_by_cas_part', + 'Print a list of the Game Tags applied to each CAS Part in the outfit of a Sim.', + command_arguments=( + CommonConsoleCommandArgument('outfit_category', 'Value or Name', 'The Value or Name of the Outfit Category to check.', is_optional=True, default_value='Current Outfit'), + CommonConsoleCommandArgument('outfit_index', 'Positive Number', 'The index of the outfit to check. This value does nothing if an Outfit Category is not specified.', is_optional=True, default_value=1), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to check.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib_testing.printoutfittagsbycaspart', + ) +) +def _s4clib_testing_print_outfit_tags_by_cas_part(output: CommonConsoleCommandOutput, outfit_category: str = None, outfit_index: int = 1, sim_info: SimInfo = None): + from sims4communitylib.utils.cas.common_cas_utils import CommonCASUtils + if sim_info is None: + return + outfit_category_and_index = CommonOutfitUtils._parse_outfit_category_and_index_from_str(output, outfit_category=outfit_category, outfit_index=outfit_index, sim_info=sim_info) + if outfit_category_and_index is None: + outfit_category_and_index = CommonOutfitUtils.get_current_outfit(sim_info) + output(f'Attempting to print game tags for each CAS Part in outfit ({outfit_category_and_index[0].name}, {outfit_category_and_index[1]}) for Sim {sim_info}.') + outfit_commands_log.debug(f'Printing all game tags for each CAS Part in outfit ({outfit_category_and_index[0].name}, {outfit_category_and_index[1]}) for Sim {sim_info}.') + outfit_commands_log.debug(f'-------Game Tags For CAS Parts of Outfit Category: ({outfit_category_and_index[0].name}, {outfit_category_and_index[1]})-------') + tags_by_cas_part_id = CommonOutfitUtils.get_outfit_tags_by_cas_part_id(sim_info, outfit_category_and_index=outfit_category_and_index) + for (cas_part_id, tag_values) in tags_by_cas_part_id.items(): + output(f'CAS Part Id: {cas_part_id}') + body_type_val = int(CommonCASUtils.get_body_type_cas_part_is_attached_to(sim_info, cas_part_id)) + body_type = CommonResourceUtils.get_enum_by_int_value(body_type_val, BodyType, default_value=None) + if body_type is None: + body_type = str(body_type_val) + body_type_str = body_type.name if hasattr(body_type, 'name') else str(body_type) + output(f'Body Type: {body_type_str}') + cleaned_tag_names = list() + for tag_value in tag_values: + if isinstance(tag_value, CommonGameTag): + tag = tag_value + else: + tag = CommonResourceUtils.get_enum_by_int_value(int(tag_value), CommonGameTag, default_value=None) + if tag is None: + tag = str(tag_value) + cleaned_tag_names.append(tag.name if hasattr(tag, 'name') else str(tag)) + sorted_tag_names = sorted(cleaned_tag_names) + tags_str = ', '.join(sorted_tag_names) + output(f'Game Tags: {tags_str}') + outfit_commands_log.debug( + f'---ID: {cas_part_id} (BodyType: {body_type_str})---') + for sorted_tag_name in sorted_tag_names: + outfit_commands_log.debug(str(sorted_tag_name)) + outfit_commands_log.debug(f'---------') + + outfit_commands_log.debug(f'--------------------------------') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.print_previous_outfit', + 'Print information about the previous outfit a Sim was wearing.', + command_arguments=( + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to check.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.printpreviousoutfit', + ) +) +def _s4clib_print_previous_outfit(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): + if sim_info is None: + output('ERROR: Failed, no Sim was specified or the specified Sim was not found!') + return + previous_outfit = CommonOutfitUtils.get_previous_outfit(sim_info, default_outfit_category_and_index=tuple()) + if not previous_outfit: + output(f'FAILED: No information about the previous outfit was found for {sim_info}') + return + output(f'Previous Outfit Info for {sim_info}') + outfit_commands_log.debug(f'Previous Outfit Info for {sim_info}') + CommonOutfitUtils._print_outfit(sim_info, previous_outfit[0], previous_outfit[1], output) + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.print_outfit', + 'Print information about an outfit a Sim has.', + command_arguments=( + CommonConsoleCommandArgument('outfit_category', 'Value or Name', 'The Value or Name of the Outfit Category to check.', is_optional=True, default_value='Current Outfit'), + CommonConsoleCommandArgument('outfit_index', 'Positive Number', 'The index of the outfit to check. This value does nothing if an Outfit Category is not specified.', is_optional=True, default_value=1), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to check.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.printoutfit', + ) +) +def _s4clib_print_outfit(output: CommonConsoleCommandOutput, outfit_category: str = None, outfit_index: int = 1, sim_info: SimInfo = None): + if sim_info is None: + output('Failed, no Sim was specified or the specified Sim was not found!') + return + outfit_category_and_index = CommonOutfitUtils._parse_outfit_category_and_index_from_str(output, outfit_category, outfit_index=outfit_index, sim_info=sim_info) + if outfit_category_and_index is None: + outfit_category_and_index = CommonOutfitUtils.get_current_outfit(sim_info) + CommonOutfitUtils._print_outfit(sim_info, outfit_category_and_index[0], outfit_category_and_index[1], output) + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.print_outfits', + 'Print information about all outfits of a Sim.', + command_arguments=( + CommonConsoleCommandArgument('show_missing_outfit_info', 'True or False', 'If True, information about the outfits a Sim does not have will be displayed.', is_optional=True, default_value=False), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to print the outfits of.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.printoutfits', + ) +) +def _s4clib_print_outfits(output: CommonConsoleCommandOutput, show_missing_outfit_info: bool = False, sim_info: SimInfo = None): + if sim_info is None: + output('ERROR: no Sim was specified or the specified Sim was not found!') + return + current_outfit = CommonOutfitUtils.get_current_outfit(sim_info) + current_outfit_category = current_outfit[0] + if not isinstance(current_outfit_category, OutfitCategory): + # noinspection PyBroadException + try: + current_outfit_category = CommonResourceUtils.get_enum_by_int_value(int(current_outfit_category), OutfitCategory, default_value=current_outfit_category) + except: + output(f'ERROR: Failed to parse {current_outfit_category} as Outfit Category.') + return + + # noinspection PyBroadException + if hasattr(current_outfit_category, 'name'): + current_outfit_category_name = current_outfit_category.name + else: + current_outfit_category_name = current_outfit_category + + output(f'Outfit Info for {sim_info}, Current Outfit: ({current_outfit_category_name}, {current_outfit[1]})') + outfit_commands_log.debug(f'Outfit Info for {sim_info}, Current Outfit: ({current_outfit_category_name}, {current_outfit[1]})') + output('------') + outfit_commands_log.debug('------') + for outfit_category in CommonOutfitUtils.get_all_outfit_categories(): + # noinspection PyBroadException + try: + outfit_category_name = outfit_category.name + except: + outfit_category_name = outfit_category + + for outfit_index in range(CommonOutfitUtils.get_maximum_number_of_outfits_for_category(outfit_category)): + if not CommonOutfitUtils.has_outfit(sim_info, (outfit_category, outfit_index)): + if show_missing_outfit_info: + output(f'MISSING: Sim {sim_info} did not have outfit ({outfit_category_name}, {outfit_index})') + outfit_commands_log.debug(f'MISSING: Sim {sim_info} did not have outfit ({outfit_category_name}, {outfit_index})') + continue + CommonOutfitUtils._print_outfit(sim_info, outfit_category, outfit_index, output) + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.generate_outfit', + 'Generate an outfit for a Sim.', + command_arguments=( + CommonConsoleCommandArgument('outfit_category', 'Value or Name', 'The Value or Name of the Outfit Category to generate.'), + CommonConsoleCommandArgument('outfit_index', 'Positive Number', 'The index of the outfit to generate.'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to generate an outfit for.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.generateoutfit', + ) +) +def _s4clib_generate_outfit(output: CommonConsoleCommandOutput, outfit_category: str = None, outfit_index_val: int = 1, sim_info: SimInfo = None): + outfit_category_and_index = CommonOutfitUtils._parse_outfit_category_and_index_from_str(output, outfit_category, outfit_index_val, sim_info=sim_info, check_for_missing_outfit=False, outfit_category_required=True) + if outfit_category_and_index is None: + return + if sim_info is None: + output('ERROR: No Sim was specified or the specified Sim was not found!') + return + outfit_category_value = outfit_category_and_index[0] + outfit_category_name = outfit_category_value.name + outfit_index = outfit_category_and_index[1] + output(f'Attempting to generate outfit ({outfit_category_name}, {outfit_index}) for Sim {sim_info}') + if CommonOutfitUtils.has_outfit(sim_info, (outfit_category_value, outfit_index)): + output(f'FAILED: Sim {sim_info} already has an outfit ({outfit_category_name}, {outfit_index})') + return + generated = CommonOutfitUtils.generate_outfit(sim_info, (outfit_category_value, outfit_index)) + if generated: + output(f'SUCCESS: Outfit ({outfit_category_name}, {outfit_index}) has been successfully generated for Sim {sim_info}.') + else: + output(f'FAILED: Outfit ({outfit_category_name}, {outfit_index}) failed to generate for Sim {sim_info}.') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.regenerate_outfit', + 'Regenerate an outfit of a Sim.', + command_arguments=( + CommonConsoleCommandArgument('outfit_category', 'Value or Name', 'The Value or Name of the Outfit Category to regenerate.', is_optional=True, default_value='Current Outfit'), + CommonConsoleCommandArgument('outfit_index', 'Positive Number', 'The index of the outfit to regenerate. This value does nothing if an Outfit Category is not specified.', is_optional=True, default_value=1), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to regenerate the outfit of.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.regenerateoutfit', + ) +) +def _common_regenerate_outfit(output: CommonConsoleCommandOutput, outfit_category: str = None, outfit_index: int = 1, sim_info: SimInfo = None): + outfit_category_and_index = CommonOutfitUtils._parse_outfit_category_and_index_from_str(output, outfit_category, outfit_index, sim_info=sim_info) + if outfit_category_and_index is None: + return + if sim_info is None: + output('ERROR: No Sim was specified or the specified Sim was not found!') + return + output(f'Attempting to regenerate the current outfit of {sim_info}') + CommonOutfitUtils.regenerate_outfit(sim_info, outfit_category_and_index) + output(f'Done regenerating the current outfit of {sim_info}') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.regenerate_all_outfits', + 'Regenerate all outfits of a Sim.', + command_arguments=( + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to regenerate the outfit of.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.regeneratealloutfits', + ) +) +def _common_regenerate_all_outfits(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): + if sim_info is None: + output('ERROR: No Sim was specified or the specified Sim was not found!') + return + output(f'Attempting to regenerate all outfits for {sim_info}') + CommonOutfitUtils.regenerate_all_outfits(sim_info) + output(f'Done regenerating all outfits for {sim_info}.') diff --git a/Scripts/s4ap/sims4communitylib/utils/common_collection_utils.py b/Scripts/s4ap/sims4communitylib/utils/common_collection_utils.py new file mode 100644 index 0000000..f8c6815 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/common_collection_utils.py @@ -0,0 +1,260 @@ +""" +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 +""" +import itertools +from typing import List, Any, Dict, Union, Tuple, Set + + +class CommonCollectionUtils: + """Utilities for collections. + + """ + @staticmethod + def is_collection(obj: Any) -> bool: + """is_collection(obj) + + Determine if an object is a collection or not. + + :param obj: An object. + :type obj: Any + :return: True, if the object is a collection, False, if not. + :rtype: bool + """ + if obj is None: + return False + return isinstance(obj, list)\ + or isinstance(obj, tuple)\ + or isinstance(obj, set)\ + or isinstance(obj, frozenset)\ + or isinstance(obj, dict) + + @staticmethod + def lists_are_equal(list_one: Union[Tuple[Any], List[Any]], list_two: Union[Tuple[Any], List[Any]]) -> bool: + """lists_are_equal(list_one, list_two) + + Determine if two collections contain tbe exact same values. + + .. note:: The order of the values in each collection will be asserted. + + :param list_one: The first value. (Can be any collection type) + :type list_one: Union[Tuple[Any], List[Any]] + :param list_two: The second value. (Can be any collection type) + :type list_two: Union[Tuple[Any], List[Any]] + :return: True, if both lists are exactly the same. False, if not. + :rtype: bool + """ + if not CommonCollectionUtils.is_collection(list_one): + return False + if not CommonCollectionUtils.is_collection(list_two): + return False + if len(list_one) != len(list_two): + return False + if isinstance(list_one, set) or isinstance(list_two, set): + return list_one == list_two + current_idx = 0 + while current_idx < len(list_one): + item_one = list_one[current_idx] + item_two = list_two[current_idx] + if item_one != item_two: + return False + current_idx += 1 + return True + + @staticmethod + def intersects(list_one: List[Any], *list_items: Any) -> bool: + """intersects(list_one, *list_items) + + Determine if a list contains any of the specified items. + + :param list_one: The list being checked. + :type list_one: List[Any] + :param list_items: An iterator of items being searched for. + :type list_items: Any + :return: True, if the list contains any of the specified items. False, if not. + :rtype: bool + """ + if list_one is None or list_items is None: + return False + for list_item in list_items: + for item in list_item: + if item in list_one: + return True + return False + + @staticmethod + def add_to_dict_if_not_exist(dictionary_one: Dict[Any, Any], dictionary_two: Dict[Any, Any]) -> Dict[Any, Any]: + """add_to_dict_if_not_exist(dictionary_one, dictionary_two) + + Combine two dictionaries. + + .. note:: If a key already exists in the first dictionary, the value from the second dictionary is ignored. + + :param dictionary_one: The first dictionary. + :type dictionary_one: Dict[Any, Any] + :param dictionary_two: The second dictionary. + :type dictionary_two: Dict[Any, Any] + :return: A new combined dictionary. + :rtype: Dict[Any, Any] + """ + if dictionary_one is None or dictionary_two is None: + return dict() + has_new_keys = False + new_dict = dict() + for (to_add_key, to_add_value) in dictionary_two.items(): + if to_add_key in dictionary_one: + continue + has_new_keys = True + new_dict[to_add_key] = to_add_value + if not has_new_keys: + return dictionary_one + for (key, value) in dictionary_one.items(): + new_dict[key] = value + return new_dict + + @staticmethod + def flatten(to_flatten: Any) -> Union[Any, List[Any]]: + """flatten(to_flatten) + + Flatten a collection of collections to a single list or itself if already flattened. + + :param to_flatten: A collection of items. + :type to_flatten: Any + :return: A single flattened list or `to_flatten` if already flattened. + :rtype: Union[Any, List[Any]] + """ + if not CommonCollectionUtils.is_collection(to_flatten): + return to_flatten + flat_list = list() + for value in to_flatten: + flat_list.append(CommonCollectionUtils.flatten(value)) + return flat_list + + @staticmethod + def create_possible_combinations(items: Union[List[Any], Tuple[Any]], items_per_combination: int) -> Set[Tuple[Any]]: + """create_possible_combinations(items, items_per_combination) + + Create a collection of all possible combinations of the specified items. + + .. note:: Example: With items: [1, 2, 3] and combination_length: 2 the result will be: {(1, 2), (1, 3), (2, 3)} + + :param items: A collection of items to create combinations from. + :type items: Union[List[Any], Tuple[Any]] + :param items_per_combination: The number of items in each combination. + :type items_per_combination: int + :return: A collection of combinations + :rtype: Set[Tuple[Any]] + """ + possible_combinations = set() + combinations = itertools.combinations(items, items_per_combination) + for combination in combinations: + (is_processed, new_combination_sets) = CommonCollectionUtils._process_item_sets(combination) + if is_processed: + for new_combination_set in new_combination_sets: + possible_combinations.add(tuple(new_combination_set)) + else: + possible_combinations.add(tuple(combination)) + return possible_combinations + + @staticmethod + def merge_dict(destination: Dict[Any, Any], source: Dict[Any, Any], prefer_source_values: bool=True, allow_duplicates_in_collections: bool=True) -> Dict[Any, Any]: + """merge_dict(destination, source, prefer_source_values=True, allow_duplicates_in_collections=True) + + Merge a source dictionary into a destination dictionary. The destination will not be modified! + + :param destination: The dictionary to use as the destination. Source will be merged into this. + :type destination: Dict[Any, Any] + :param source: The dictionary to use as the source. Destination will have this merged into itself. + :type source: Dict[Any, Any] + :param prefer_source_values: When an entry is found within both the destination and the source, setting it to True will prefer to overwrite the destination value with the source value, setting this to False will prefer to use the destination value. Default is True. + :type prefer_source_values: bool, optional + :param allow_duplicates_in_collections: When a collection is found within both dictionaries, setting this to True will allow duplicate entries, setting it to False will not allow duplicate entries. Default is True. + :type allow_duplicates_in_collections: bool, optional + :return: A dictionary containing the source merged into the destination. + :rtype: Dict[Any, Any] + """ + merged = destination.copy() + for (source_key, source_val) in source.items(): + source_val = source[source_key] + if source_key in merged: + destination_val = merged[source_key] + if isinstance(source_val, dict) and isinstance(destination_val, dict): + merged[source_key] = CommonCollectionUtils.merge_dict(destination_val, source_val, allow_duplicates_in_collections=allow_duplicates_in_collections) + elif CommonCollectionUtils.is_collection(source_val) and CommonCollectionUtils.is_collection(destination_val): + if allow_duplicates_in_collections: + if prefer_source_values: + merged[source_key] = ( + *source_val, + *destination_val + ) + else: + merged[source_key] = ( + *destination_val, + *source_val + ) + else: + new_collection = list(destination_val) + for val in source_val: + if val not in new_collection: + new_collection.append(val) + merged[source_key] = tuple(new_collection) + elif source_val == destination_val: + continue + else: + if prefer_source_values: + merged[source_key] = source_val + else: + merged[source_key] = source_val + return merged + + @staticmethod + def _process_item_sets(item_set: Union[Tuple[Any], List[Any], Set[Any]]) -> Tuple[bool, Union[Set[Any], List[Any]]]: + item_sets = [] + # Item count 2 + # I1, T1 + # ((I1, I2), T1) + # ((I1, I2), (T1, T2)) + # Item count 3 + # I1, T1, K1 + # ((I1, I2), T1, K1) + # ((I1, I2), (T1, T2), K1) + # ((I1, I2), (T1, T2), (K1, K2)) + has_unprocessed = False + unprocessed_item_sets = [] + idx = 0 + for item in item_set: + if isinstance(item, tuple) or isinstance(item, list) or isinstance(item, set): + has_unprocessed = True + elements_before = item_set[:idx] + elements_after = item_set[idx + 1:] + for items_in_set in item: + current_set = [] + for element_before in elements_before: + current_set.append(element_before) + current_set.append(items_in_set) + for element_after in elements_after: + current_set.append(element_after) + unprocessed_item_sets.append(current_set) + break + idx += 1 + if len(unprocessed_item_sets) > 0: + item_sets = [] + for unprocessed_item_set in unprocessed_item_sets: + (is_processed, result) = CommonCollectionUtils._process_item_sets(unprocessed_item_set) + if is_processed: + for new_item_set in result: + item_sets.append(new_item_set) + else: + item_sets.append(unprocessed_item_set) + return True, item_sets + if not has_unprocessed: + if isinstance(item_set, list) or isinstance(item_set, tuple): + new_item_set = set() + for item in item_set: + new_item_set.add(item) + return False, new_item_set + return False, item_set + return True, item_sets diff --git a/Scripts/s4ap/sims4communitylib/utils/common_component_utils.py b/Scripts/s4ap/sims4communitylib/utils/common_component_utils.py new file mode 100644 index 0000000..5296100 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/common_component_utils.py @@ -0,0 +1,79 @@ +""" +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 +""" +from typing import Union, TypeVar, Type + +from objects.components import ComponentContainer, Component +from sims4communitylib.enums.types.component_types import CommonComponentType + + +CommonExpectedReturnType = TypeVar('CommonExpectedReturnType', bound=Component) + + +class CommonComponentUtils: + """Utilities for handling components of component containers. + + """ + @staticmethod + def has_component(component_container: ComponentContainer, component_type: CommonComponentType) -> bool: + """has_component(component_container, component_type) + + Determine if a ComponentContainer has a component of the specified type. + + :param component_container: The ComponentContainer to check. + :type component_container: ComponentContainer + :param component_type: The type of component to locate. + :type component_type: CommonComponentType + :return: True, if the ComponentContainer contains a component of the specified type. False, if not. + :rtype: bool + """ + if component_type is None or not isinstance(component_container, ComponentContainer) or not hasattr(component_container, 'has_component'): + return False + return component_container.has_component(component_type) + + # noinspection PyUnusedLocal + @staticmethod + def get_component(component_container: ComponentContainer, component_type: CommonComponentType, add_dynamic: bool = False, return_type: Type[CommonExpectedReturnType] = Component) -> Union[CommonExpectedReturnType, None]: + """get_component(component_container, component_type, add_dynamic=False, return_type=Component) + + Retrieve a component from a ComponentContainer. + + :param component_container: The ComponentContainer to retrieve a component from. + :type component_container: ComponentContainer + :param component_type: The type of component being retrieved. + :type component_type: CommonComponentType + :param add_dynamic: If True, the component will be added dynamically. If False, the component will not be added dynamically. Default is False. + :type add_dynamic: bool, optional + :param return_type: The type of the returned value. (This is to make type hinting more accurate). It is not actually used in the function. Default is Component. + :type return_type: Type[CommonExpectedReturnType], optional + :return: An object of type Component, or None if the specified component type is not found. + :rtype: Union[CommonExpectedReturnType, None] + """ + if component_type is None or not isinstance(component_container, ComponentContainer) or not hasattr(component_container, 'get_component'): + return None + if add_dynamic and not component_container.has_component(component_type): + return CommonComponentUtils.add_dynamic_component(component_container, component_type) + return component_container.get_component(component_type) + + @staticmethod + def add_dynamic_component(component_container: ComponentContainer, component_type: CommonComponentType) -> Union[Component, None]: + """add_dynamic_component(component_container, component_type) + + Add a dynamic component to a ComponentContainer. + + :param component_container: The ComponentContainer to add to. + :type component_container: ComponentContainer + :param component_type: The type of component being added. + :type component_type: CommonComponentType + :return: The added Component or None + :rtype: Union[Component, None] + """ + if component_type is None or not hasattr(component_container, 'add_dynamic_component') or not hasattr(component_container, 'get_component'): + return None + if not component_container.add_dynamic_component(component_type): + return None + return component_container.get_component(component_type) diff --git a/Scripts/s4ap/sims4communitylib/utils/common_date_utils.py b/Scripts/s4ap/sims4communitylib/utils/common_date_utils.py new file mode 100644 index 0000000..ca906b6 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/common_date_utils.py @@ -0,0 +1,37 @@ +""" +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 +""" +from datetime import datetime + + +class CommonRealDateUtils: + """A utility for managing real life date and time. + + .. note:: This utility is used to handle the Real Time and not the Game Time. + + """ + @staticmethod + def get_current_date_time() -> datetime: + """get_current_date_time() + + Retrieve the current date and time. + + :return: The current real date and time. + :rtype: datetime + """ + return datetime.now() + + @staticmethod + def get_current_date_string() -> str: + """get_current_date_string() + + Retrieve the current date as a pre-formatted string. + + :return: The string representation of the current real date. + :rtype: str + """ + return str(datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')) diff --git a/Scripts/s4ap/sims4communitylib/utils/common_function_utils.py b/Scripts/s4ap/sims4communitylib/utils/common_function_utils.py new file mode 100644 index 0000000..5bf8ee1 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/common_function_utils.py @@ -0,0 +1,245 @@ +""" +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 +""" +from typing import Any, Callable, Iterator, Union + +from sims4communitylib.classes.testing.common_enqueue_result import CommonEnqueueResult +from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.utils.common_log_registry import CommonLog + + +class CommonFunctionUtils: + """Utilities for manipulating functions. + + """ + + @staticmethod + def noop(*_, **__) -> None: + """noop(*_, **__) + + An empty function that does nothing. Useful when you need something to do nothing. + + .. note:: Use this when you want something to do nothing. + + """ + pass + + @staticmethod + def noop_execution_result(*_, **__) -> CommonExecutionResult: + """noop_execution_result(*_, **__) + + An empty function that does nothing but return :func:`CommonExecutionResult.NONE`. Useful when you need something to simply return CommonExecutionResult.NONE. + + .. note:: Use this when you want something to simply return CommonExecutionResult.NONE. + + :return: Returns CommonExecutionResult.NONE. + :rtype: CommonExecutionResult + """ + return CommonExecutionResult.NONE + + @staticmethod + def noop_test_result(*_, **__) -> CommonTestResult: + """noop_test_result(*_, **__) + + An empty function that does nothing but return :func:`CommonTestResult.NONE`. Useful when you need something to simply return CommonTestResult.NONE. + + .. note:: Use this when you want something to simply return CommonTestResult.NONE. + + :return: Returns CommonTestResult.NONE. + :rtype: CommonTestResult + """ + return CommonTestResult.NONE + + @staticmethod + def noop_enqueue(*_, **__) -> CommonEnqueueResult: + """noop_enqueue(*_, **__) + + An empty function that does nothing but return :func:`CommonEnqueueResult.NONE`. Useful when you need something to simply return CommonEnqueueResult.NONE. + + .. note:: Use this when you want something to simply return CommonEnqueueResult.NONE. + + :return: Returns CommonEnqueueResult.NONE. + :rtype: CommonEnqueueResult + """ + return CommonEnqueueResult.NONE + + @staticmethod + def noop_true(*_, **__) -> bool: + """noop_true(*_, **__) + + An empty function that does nothing but return True. Useful when you need something to simply return True. + + .. note:: Use this when you want something to simply return True. + + :return: Returns True. + :rtype: bool + """ + return True + + @staticmethod + def noop_false(*_, **__) -> bool: + """noop_false(*_, **__) + + An empty function that does nothing but return False. Useful when you need something to simply return False. + + .. note:: Use this when you want something to simply return False. + + :return: Returns False. + :rtype: bool + """ + return False + + @staticmethod + def print_arguments(log: CommonLog, func_identifier: str = 'NO_IDENTIFIER_SPECIFIED') -> Callable[..., Any]: + """print_arguments(log, func_identifier='NO_IDENTIFIER_SPECIFIED') + + Create a function that will log the arguments and keyword arguments it receives + + :param log: The log to print the arguments to. + :type log: CommonLog + :param func_identifier: An identifier for the function to determine which function was invoked + :type func_identifier: str + :return: A function that will print the arguments sent to it when the original function is invoked. + :rtype: Callable[..., Any] + """ + + def _print_arguments(*_: Any, **__: Any): + log.enable() + log.format_with_message(f'print_arguments invoked for identifier \'{func_identifier}\':', argles=_, kwargles=__) + log.disable() + + return _print_arguments + + @staticmethod + def safe_run(mod_identity: CommonModIdentity, primary_function: Callable[..., Any], fallback_function: Callable[..., Any], *args: Any, **kwargs: Any) -> Any: + """safe_run(mod_identity, primary_function, fallback_function, *args, **kwargs) + + Safely run a function, if the primary function throws an exception, the fallback function will be run instead. + + :param mod_identity: The identity of the mod running a function safely. + :type mod_identity: CommonModIdentity + :param primary_function: The primary function to safely run. + :type primary_function: Callable[..., Any] + :param fallback_function: A function called when the primary function throws an exception. + :type fallback_function: Callable[..., Any] + :param args: Arguments to pass to both the primary function and fallback function. + :type args: Any + :param kwargs: Keyword Arguments to pass to both the primary function and fallback function. + :type kwargs: Any + :return: The result of either the primary function or the fallback function if the primary threw an exception. + :rtype: Any + """ + try: + if primary_function is None: + if fallback_function is None: + return + return fallback_function(*args, **kwargs) + return primary_function(*args, **kwargs) + except Exception as ex: + # noinspection PyBroadException + try: + from sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler + CommonExceptionHandler.log_exception( + mod_identity, + f'Error occurred while running \'{primary_function.__name__}\'', + exception=ex + ) + except Exception: + pass + # noinspection PyBroadException + try: + if fallback_function is None: + return + return fallback_function(*args, **kwargs) + except: + pass + + @staticmethod + def run_predicates_as_one(predicate_functions: Iterator[Callable[..., Union[bool, CommonExecutionResult, CommonTestResult]]], all_must_pass: bool = True) -> Callable[..., Union[bool, CommonExecutionResult, CommonTestResult]]: + """run_predicates_as_one(predicate_functions, all_must_pass=True) + + Wrap all predicate functions into a single predicate function. (See returned value for more information). + + .. note:: + + If `all_must_pass` is True a wrapped function that will return a value of: + + - True, if all predicates resulted in a True value. + - False, if any predicates resulted in a False value. + + If `all_must_pass` is False a wrapped function that will return a value of: + + - True, if any predicates resulted in a True value. + - False, if all predicates resulted in a False value. + + :param predicate_functions: The predicate functions to run as one. + :type predicate_functions: Iterator[Callable[..., bool]] + :param all_must_pass: If True, all the predicates must return a True value. If False, any of the predicates must return a True value. + :type all_must_pass: bool, optional + :return: The result of running all functions. + :rtype: bool + """ + def _wrapper(*_: Any, **__: Any): + if all_must_pass: + for primary_function in predicate_functions: + if primary_function is None: + continue + if not primary_function(*_, **__): + return False + return True + else: + for primary_function in predicate_functions: + if primary_function is None: + continue + if primary_function(*_, **__): + return True + return False + _wrapper.__name__ = ', '.join([func.__name__ for func in predicate_functions if func is not None]) + return _wrapper + + @staticmethod + def run_predicate_with_reversed_result(predicate_function: Callable[..., Union[bool, CommonExecutionResult, CommonTestResult]]) -> Callable[..., Union[bool, CommonExecutionResult, CommonTestResult]]: + """run_predicate_with_reversed_result(predicate_function) + + Wrap the specified predicate function and reverse the result of it when the function is invoked. + + :param predicate_function: The predicate function to reverse the result of. + :type predicate_function: Callable[..., bool] + :return: A function that will reverse the result of `predicate_function` upon invocation. + :rtype: Callable[..., bool] + """ + def _wrapper(*_: Any, **__: Any) -> Any: + if predicate_function is None: + return False + result = predicate_function(*_, **__) + if isinstance(result, CommonExecutionResult) or isinstance(result, CommonTestResult): + return result.reverse_result() + return not result + if predicate_function is not None: + _wrapper.__name__ = predicate_function.__name__ + return _wrapper + + @staticmethod + def run_with_arguments(primary_function: Callable[..., Any], *args: Any, **kwargs: Any) -> Callable[..., Any]: + """run_with_arguments(primary_function, *args, **kwargs) + + Wrap a function and run it with additional arguments when something invokes it. + + :param primary_function: The function that will be run. + :type primary_function: Callable[..., Any] + :return: A function that will send extra arguments upon invocation. + :rtype: Callable[..., Any] + """ + def _wrapper(*_: Any, **__: Any) -> Any: + if primary_function is None: + return False + return primary_function(*_, *args, **__, **kwargs) + if primary_function is not None: + _wrapper.__name__ = primary_function.__name__ + return _wrapper diff --git a/Scripts/s4ap/sims4communitylib/utils/common_icon_utils.py b/Scripts/s4ap/sims4communitylib/utils/common_icon_utils.py new file mode 100644 index 0000000..a9b5e66 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/common_icon_utils.py @@ -0,0 +1,189 @@ +""" +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 +""" +from typing import Any, Union +from sims4.resources import Types +from sims4communitylib.enums.enumtypes.common_int import CommonInt +from sims4communitylib.enums.icons_enum import CommonIconId +from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + + +class CommonIconUtils: + """Utilities for loading icons. + + """ + @classmethod + def load_arrow_right_icon(cls) -> Any: + """load_arrow_right_icon() + + Get the Resource Key for the ARROW_RIGHT_ICON. + + :return: An identifier for the icon. + :rtype: Any + """ + return cls.load_icon_by_id(CommonIconId.S4CLIB_ARROW_RIGHT_ICON) + + @classmethod + def load_arrow_left_icon(cls) -> Any: + """load_arrow_left_icon() + + Get the Resource Key for the ARROW_LEFT_ICON. + + :return: An identifier for the icon. + :rtype: Any + """ + return cls.load_icon_by_id(CommonIconId.S4CLIB_ARROW_LEFT_ICON) + + @classmethod + def load_arrow_navigate_into_icon(cls) -> Any: + """load_arrow_navigate_into_icon() + + Get the Resource Key for the ARROW_NAVIGATE_INTO_ICON. + + :return: An identifier for the icon. + :rtype: Any + """ + return cls.load_icon_by_id(CommonIconId.S4CLIB_ARROW_NAVIGATE_INTO_ICON) + + @classmethod + def load_question_mark_icon(cls) -> Any: + """load_question_mark_icon() + + Get the Resource Key for the QUESTION_MARK_ICON. + + :return: An identifier for the icon. + :rtype: Any + """ + return cls.load_icon_by_id(CommonIconId.S4CLIB_QUESTION_MARK_ICON) + + @classmethod + def load_checked_square_icon(cls) -> Any: + """load_checked_square_icon() + + Get the Resource Key for the CHECKED_SQUARE_ICON. + + :return: An identifier for the icon. + :rtype: Any + """ + return cls.load_icon_by_id(CommonIconId.S4CLIB_CHECKED_SQUARE_ICON) + + @classmethod + def load_checked_circle_icon(cls) -> Any: + """load_checked_circle_icon() + + Get the Resource Key for the CHECKED_CIRCLE_ICON. + + :return: An identifier for the icon. + :rtype: Any + """ + return cls.load_icon_by_id(CommonIconId.S4CLIB_CHECKED_CIRCLE_ICON) + + @classmethod + def load_unchecked_square_icon(cls) -> Any: + """load_unchecked_square_icon() + + Get the Resource Key for the UNCHECKED_SQUARE_ICON. + + :return: An identifier for the icon. + :rtype: Any + """ + return cls.load_icon_by_id(CommonIconId.S4CLIB_UNCHECKED_SQUARE_ICON) + + @classmethod + def load_x_icon(cls) -> Any: + """load_x_icon() + + Get the Resource Key for the X_ICON. + + :return: An identifier for the icon. + :rtype: Any + """ + return cls.load_icon_by_id(CommonIconId.S4CLIB_X_ICON) + + @classmethod + def load_six_sided_dice_icon(cls) -> Any: + """load_six_sided_dice_icon() + + Get the Resource Key for the SIX_SIDED_DICE_ICON. + + :return: An identifier for the icon. + :rtype: Any + """ + return cls.load_icon_by_id(CommonIconId.S4CLIB_SIX_SIDED_DICE_ICON) + + @classmethod + def load_blank_square_icon(cls) -> Any: + """load_blank_square_icon() + + Get the Resource Key for the BLANK_SQUARE_ICON. + + :return: An identifier for the icon. + :rtype: Any + """ + return cls.load_icon_by_id(CommonIconId.S4CLIB_BLANK_SQUARE_ICON) + + @classmethod + def load_text_prev_icon(cls) -> Any: + """load_text_prev_icon() + + Get the Resource Key for the TEXT_PREV_SQUARE_ICON. + + :return: An identifier for the icon. + :rtype: Any + """ + return cls.load_icon_by_id(CommonIconId.S4CLIB_TEXT_PREV_SQUARE_ICON) + + @classmethod + def load_text_next_icon(cls) -> Any: + """load_text_next_icon() + + Get the Resource Key for the TEXT_NEXT_SQUARE_ICON. + + :return: An identifier for the icon. + :rtype: Any + """ + return cls.load_icon_by_id(CommonIconId.S4CLIB_TEXT_NEXT_SQUARE_ICON) + + @classmethod + def load_unfilled_circle_icon(cls) -> Any: + """load_unfilled_circle_icon() + + Get the Resource Key for the UNFILLED_CIRCLE_ICON. + + :return: An identifier for the icon. + :rtype: Any + """ + return cls.load_icon_by_id(CommonIconId.S4CLIB_UNFILLED_CIRCLE_ICON) + + @classmethod + def load_filled_circle_icon(cls) -> Any: + """load_filled_circle_icon() + + Get the Resource Key for the FILLED_CIRCLE_ICON. + + :return: An identifier for the icon. + :rtype: Any + """ + return cls.load_icon_by_id(CommonIconId.S4CLIB_FILLED_CIRCLE_ICON) + + @classmethod + def load_icon_by_id(cls, icon: Union[int, CommonIconId, CommonInt]) -> Union[Any, None]: + """load_icon_by_id(icon) + + Load an instance of an Icon by its identifier. + + :param icon: The identifier of an Icon. + :type icon: Union[int, CommonIconId, CommonInt] + :return: An instance of an Icon matching the decimal identifier or None if not found. + :rtype: Union[Any, None] + """ + return CommonResourceUtils.get_resource_key(Types.PNG, icon) + + @staticmethod + def _load_icon(icon_id: Union[int, CommonIconId]) -> Any: + """Obsolete, please use load_icon_by_id instead.""" + return CommonIconUtils.load_icon_by_id(icon_id) diff --git a/Scripts/s4ap/sims4communitylib/utils/common_injection_utils.py b/Scripts/s4ap/sims4communitylib/utils/common_injection_utils.py new file mode 100644 index 0000000..ea5582b --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/common_injection_utils.py @@ -0,0 +1,417 @@ +""" +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 +""" +import os +from functools import wraps +from typing import Any, Callable, TYPE_CHECKING + +from sims4communitylib.mod_support.mod_identity import CommonModIdentity + +if TYPE_CHECKING: + from sims4communitylib.utils.common_log_registry import CommonLog +ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' + + +class _TypeChecking: + # noinspection PyMissingTypeHints,PyMissingOrEmptyDocstring + @classmethod + def class_method(cls): + pass + + # noinspection PyMissingTypeHints,PyMissingOrEmptyDocstring + def self_method(self): + pass + + # noinspection PyPropertyDefinition,PyMissingTypeHints,PyMissingOrEmptyDocstring + @property + def property_type(self): + pass + + # noinspection PyMissingTypeHints,PyMissingOrEmptyDocstring + @staticmethod + def static_method(): + pass + + +ClassMethodType = type(_TypeChecking.class_method) +SelfMethodType = type(_TypeChecking.self_method) +StaticMethodType = type(_TypeChecking.static_method) +PropertyType = type(_TypeChecking.property_type) + + +class CommonInjectionUtils: + """Utilities to inject custom functionality into functions. + + """ + @staticmethod + def inject_into(target_object: Any, target_function_name: str) -> Callable: + """inject_into(target_object, target_function_name) + + .. warning:: This function is DEPRECATED.\ + Use :func:`~inject_safely_into` instead. + + """ + # noinspection PyTypeChecker + return CommonInjectionUtils.inject_safely_into(None, target_object, target_function_name) + + @staticmethod + def inject_safely_into(mod_identity: CommonModIdentity, target_object: Any, target_function_name: str, handle_exceptions: bool = True) -> Callable: + """inject_safely_into(mod_identity, target_object, target_function_name, handle_exceptions=True) + + A decorator used to inject code into a function. + It will run the original function should any problems occur. + If handle_exceptions is True, it will catch and log exceptions. + + :Example of cls usage: + + .. highlight:: python + .. code-block:: python + + # cls usage + @CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), SimSpawner, SimSpawner.spawn_sim._name__) + def do_custom_spawn_sim(original, cls, *args, **kwargs): + return original(*args, **kwargs) + + :Example of self usage: + + .. highlight:: python + .. code-block:: python + + # Self usage + @CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), SimInfo, SimInfo.load_sim_info.__name__) + def do_custom_load_sim_info(original, self, *args, **kwargs): + return original(self, *args, **kwargs) + + .. note:: + + Injection WILL work on + + - Functions decorated with 'property' + - Functions decorated with 'classmethod' + - Functions decorated with 'staticmethod' + - Functions with 'cls' or 'self' as the first argument. + + .. note:: + + Injection WILL NOT work on + + - Global functions, i.e. Functions not contained within a class. + - Global variables, i.e. Variables not contained within a class or function. + + :param mod_identity: The identity of the Mod that is injecting custom code. + :type mod_identity: CommonModIdentity + :param target_object: The class that contains the target function. + :type target_object: Any + :param target_function_name: The name of the function being injected to. + :type target_function_name: str + :param handle_exceptions: If set to True, any exceptions thrown by the wrapped function will be handled. If set to False, any exceptions thrown by the wrapped function will not be caught. Default is True. + :type handle_exceptions: bool, optional + :return: A wrapped function. + :rtype: Callable + """ + if ON_RTD: + def _injected(wrap_function) -> Any: + return wrap_function + return _injected + + if handle_exceptions: + def _function_wrapper(original_function, new_function: Callable[..., Any]) -> Any: + # noinspection PyBroadException + try: + if isinstance(original_function, ClassMethodType): + original_function_func = original_function.__func__ + + # noinspection PyDecorator + @wraps(original_function) + def _wrapped_class_function(cls, *args, **kwargs) -> Any: + try: + # noinspection PyMissingTypeHints + def _do_original(*_, **__): + return original_function_func(cls, *_, **__) + + return new_function(_do_original, cls, *args, **kwargs) + except Exception as ex: + # noinspection PyBroadException + try: + from sims4communitylib.exceptions.common_exceptions_handler import \ + CommonExceptionHandler + CommonExceptionHandler.log_exception(mod_identity, 'Error occurred while injecting into function \'{}\' of class \'{}\''.format(new_function.__name__, target_object.__name__), exception=ex) + except Exception: + pass + return original_function_func(cls, *args, **kwargs) + return classmethod(_wrapped_class_function) + + if isinstance(original_function, SelfMethodType): + @wraps(original_function) + def _wrapped_self_function(self, *args, **kwargs) -> Any: + try: + return new_function(original_function, self, *args, **kwargs) + except Exception as ex: + # noinspection PyBroadException + try: + from sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler + CommonExceptionHandler.log_exception(mod_identity, 'Error occurred while injecting into function \'{}\' of class \'{}\''.format(new_function.__name__, target_object.__name__), exception=ex) + except Exception: + pass + return original_function(self, *args, **kwargs) + + return _wrapped_self_function + + if isinstance(original_function, PropertyType): + # noinspection PyTypeChecker + @wraps(original_function) + def _wrapped_property_function(self, *args, **kwargs) -> Any: + try: + return new_function(original_function.fget, self, *args, **kwargs) + except Exception as ex: + # noinspection PyBroadException + try: + from sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler + CommonExceptionHandler.log_exception(mod_identity, 'Error occurred while injecting into function \'{}\' of class \'{}\''.format(new_function.__name__, target_object.__name__), exception=ex) + except Exception: + pass + return original_function(self, *args, **kwargs) + + return property(_wrapped_property_function) + + if isinstance(original_function, StaticMethodType): + original_function_func = original_function.__func__ + + # noinspection PyDecorator + @wraps(original_function) + def _wrapped_static_function(*args, **kwargs) -> Any: + try: + # noinspection PyMissingTypeHints + def _do_original(*_, **__): + return original_function_func(*_, **__) + + return new_function(_do_original, *args, **kwargs) + except Exception as ex: + # noinspection PyBroadException + try: + from sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler + CommonExceptionHandler.log_exception(mod_identity, 'Error occurred while injecting into function \'{}\' of class \'{}\''.format(new_function.__name__, target_object.__name__), exception=ex) + except Exception: + pass + return original_function_func(*args, **kwargs) + + return staticmethod(_wrapped_static_function) + + @wraps(original_function) + def _wrapped_other_function(*args, **kwargs) -> Any: + try: + return new_function(original_function, *args, **kwargs) + except Exception as ex: + # noinspection PyBroadException + try: + from sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler + CommonExceptionHandler.log_exception(mod_identity, 'Error occurred while injecting into function \'{}\' of class \'{}\''.format(new_function.__name__, target_object.__name__), exception=ex) + except Exception: + pass + return original_function(*args, **kwargs) + + return _wrapped_other_function + except: + def _func(*_, **__) -> Any: + pass + return _func + else: + def _function_wrapper(original_function, new_function: Callable[..., Any]) -> Any: + # noinspection PyBroadException + try: + if isinstance(original_function, ClassMethodType): + original_function_func = original_function.__func__ + + # noinspection PyDecorator + @wraps(original_function) + def _wrapped_class_function(cls, *args, **kwargs) -> Any: + # noinspection PyMissingTypeHints + def _do_original(*_, **__): + return original_function_func(cls, *_, **__) + + return new_function(_do_original, cls, *args, **kwargs) + return classmethod(_wrapped_class_function) + + if isinstance(original_function, SelfMethodType): + @wraps(original_function) + def _wrapped_self_function(self, *args, **kwargs) -> Any: + return new_function(original_function, self, *args, **kwargs) + + return _wrapped_self_function + + if isinstance(original_function, PropertyType): + # noinspection PyTypeChecker + @wraps(original_function) + def _wrapped_property_function(self, *args, **kwargs) -> Any: + return new_function(original_function.fget, self, *args, **kwargs) + + return property(_wrapped_property_function) + + if isinstance(original_function, StaticMethodType): + original_function_func = original_function.__func__ + + # noinspection PyDecorator + @wraps(original_function) + def _wrapped_static_function(*args, **kwargs) -> Any: + # noinspection PyMissingTypeHints + def _do_original(*_, **__): + return original_function_func(*_, **__) + + return new_function(_do_original, *args, **kwargs) + + return staticmethod(_wrapped_static_function) + + @wraps(original_function) + def _wrapped_other_function(*args, **kwargs) -> Any: + return new_function(original_function, *args, **kwargs) + + return _wrapped_other_function + except: + def _func(*_, **__) -> Any: + pass + return _func + + def _injected(wrap_function) -> Any: + original_function = getattr(target_object, str(target_function_name)) + setattr(target_object, str(target_function_name), _function_wrapper(original_function, wrap_function)) + return wrap_function + return _injected + + @staticmethod + def inject_safely_into_function(mod_identity: CommonModIdentity, target_object: Any, target_function_name: str, callback: Callable[..., Any], replace_return: bool = False, handle_exceptions: bool = True) -> Callable: + """inject_safely_into_function(mod_identity, target_object, target_function_name, callback, replace_return=False, handle_exceptions=True) + + A decorator used to inject code into a function. + It will run the original function should any problems occur. + If handle_exceptions is True, it will catch and log exceptions. + + :Example of cls usage: + + .. highlight:: python + .. code-block:: python + + # cls usage + @CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), SimSpawner, SimSpawner.spawn_sim._name__) + def do_custom_spawn_sim(original, cls, *args, **kwargs): + return original(*args, **kwargs) + + :Example of self usage: + + .. highlight:: python + .. code-block:: python + + # Self usage + @CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), SimInfo, SimInfo.load_sim_info.__name__) + def do_custom_load_sim_info(original, self, *args, **kwargs): + return original(self, *args, **kwargs) + + .. note:: + + Injection WILL work on + + - Functions decorated with 'property' + - Functions decorated with 'classmethod' + - Functions decorated with 'staticmethod' + - Functions with 'cls' or 'self' as the first argument. + + .. note:: + + Injection WILL NOT work on + + - Global functions, i.e. Functions not contained within a class. + - Global variables, i.e. Variables not contained within a class or function. + + :param mod_identity: The identity of the Mod that is injecting custom code. + :type mod_identity: CommonModIdentity + :param target_object: The class that contains the target function. + :type target_object: Any + :param target_function_name: The name of the function being injected to. + :type target_function_name: str + :param callback: When the injected function is invoked, this callback will be invoked. + :type callback: Callable[..., Any] + :param replace_return: If True, the returned result of the callback argument will replace the returned result of the original function. If False, the callback will be invoked, but the result of invoking the original function will be returned. Default is False. + :type replace_return: bool, optional + :param handle_exceptions: If set to True, any exceptions thrown by the wrapped function will be handled. If set to False, any exceptions thrown by the wrapped function will not be caught. Default is True. + :type handle_exceptions: bool, optional + :return: A wrapped function. + :rtype: Callable + """ + + @CommonInjectionUtils.inject_safely_into(mod_identity, target_object, target_function_name, handle_exceptions=handle_exceptions) + def _inject_and_invoke_callback(original, *args, **kwargs) -> Any: + callback_result = callback(*args, **kwargs) + if replace_return: + return callback_result + return original(*args, **kwargs) + + return _inject_and_invoke_callback + + @staticmethod + def inject_and_print_arguments(mod_identity: CommonModIdentity, target_object: Any, target_function_name: str, log: 'CommonLog', log_stack_trace: bool = False, handle_exceptions: bool = True) -> Callable: + """inject_and_print_arguments(mod_identity, target_object, target_function_name, log, log_stack_trace=False, handle_exceptions=True) + + A decorator used to inject code into a function and print any arguments or keyword arguments passed to it. + + .. note:: See documentation of :func:`~inject_safely_into` for more details about the arguments and keyword arguments. + + :Example of cls usage: + + .. highlight:: python + .. code-block:: python + + # cls usage + @CommonInjectionUtils.inject_and_print_arguments(ModInfo.get_identity(), SimSpawner, SimSpawner.spawn_sim._name__) + + :Example of self usage: + + .. highlight:: python + .. code-block:: python + + # Self usage + @CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), SimInfo, SimInfo.load_sim_info.__name__) + def do_custom_load_sim_info(original, self, *args, **kwargs): + return original(self, *args, **kwargs) + + .. note:: + + Injection WILL work on + + - Functions decorated with 'property' + - Functions decorated with 'classmethod' + - Functions decorated with 'staticmethod' + - Functions with 'cls' or 'self' as the first argument. + + .. note:: + + Injection WILL NOT work on + + - Global functions, i.e. Functions not contained within a class. + - Global variables, i.e. Variables not contained within a class or function. + + :param mod_identity: The identity of the Mod that is injecting custom code. + :type mod_identity: CommonModIdentity + :param target_object: The class that contains the target function. + :type target_object: Any + :param target_function_name: The name of the function being injected to. + :type target_function_name: str + :param log: The log being printed to when the injected function is invoked. The arguments and keyword arguments sent to the function will be printed. + :type log: CommonLog + :param log_stack_trace: If True, the stack trace will be logged in addition to the arguments and keyword arguments. If False, the stack trace will not be logged. Default is False. + :type log_stack_trace: bool, optional + :param handle_exceptions: If set to True, any exceptions thrown by the wrapped function will be handled. If set to False, any exceptions thrown by the wrapped function will not be caught. Default is True. + :type handle_exceptions: bool, optional + :return: A wrapped function. + :rtype: Callable + """ + @CommonInjectionUtils.inject_safely_into(mod_identity, target_object, target_function_name, handle_exceptions=handle_exceptions) + def _inject_and_print(original, *args, **kwargs) -> Any: + log.format_with_message('{}.{}'.format(target_object, target_function_name), argles=args, kwargles=kwargs) + if log_stack_trace: + log.log_stack() + return original(*args, **kwargs) + + return _inject_and_print diff --git a/Scripts/s4ap/sims4communitylib/utils/common_io_utils.py b/Scripts/s4ap/sims4communitylib/utils/common_io_utils.py new file mode 100644 index 0000000..1a7348d --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/common_io_utils.py @@ -0,0 +1,119 @@ +""" +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 +""" +import os +import shutil +from typing import Union + + +class CommonIOUtils: + """Utilities for reading/writing to and from files. + + """ + @staticmethod + def delete_file(file_path: str, ignore_errors: bool=False) -> bool: + """delete_file(file_path, ignore_errors=False) + + Delete a file. + + :param file_path: The file to delete. + :type file_path: str + :param ignore_errors: If True, any exceptions thrown will be ignored (Useful in preventing infinite loops) + :type ignore_errors: bool, optional + :return: True if successful. False if not. + :rtype: bool + """ + if file_path is None: + return False + try: + if os.path.exists(file_path): + os.remove(file_path) + except Exception as ex: + if ignore_errors: + return False + raise ex + return True + + @staticmethod + def delete_directory(directory_path: str, ignore_errors: bool=False) -> bool: + """delete_directory(directory_path, ignore_errors=False) + + Delete a directory. + + :param directory_path: The folder to delete. + :type directory_path: str + :param ignore_errors: If True, any exceptions thrown will be ignored (Useful in preventing infinite loops) + :type ignore_errors: bool, optional + :return: True if successful. False if not. + :rtype: bool + """ + if directory_path is None: + return False + try: + if os.path.exists(directory_path): + shutil.rmtree(directory_path) + except Exception as ex: + if ignore_errors: + return False + raise ex + return True + + @staticmethod + def write_to_file(file_path: str, data: str, buffering: int=1, encoding: str='utf-8', ignore_errors: bool=False, remove_if_exists: bool=False) -> bool: + """write_to_file(file_path, data, buffering=1, encoding='utf-8', ignore_errors=False, remove_if_exists=False) + + Write string data to a file. + + :param file_path: The file to write to. + :type file_path: str + :param data: The data to write. + :type data: str + :param buffering: See the built-in python :func:`~open` function documentation for more details. + :type buffering: int, optional + :param encoding: See the built-in python :func:`~open` function documentation for more details. + :type encoding: str, optional + :param ignore_errors: If True, any exceptions thrown will be ignored (Useful in preventing infinite loops) + :type ignore_errors: bool, optional + :param remove_if_exists: If True and the File exists already, it will be deleted before writing the data. If False and the File exists already, the data will be appended to the end of it. Default is False. + :type remove_if_exists: bool, optional + :return: True if successful. False if not. + :rtype: bool + """ + if file_path is None or data is None: + return False + try: + if remove_if_exists: + CommonIOUtils.delete_file(file_path, ignore_errors=ignore_errors) + with open(file_path, mode='a', buffering=buffering, encoding=encoding) as opened_file: + opened_file.write(data) + opened_file.flush() + opened_file.close() + except Exception as ex: + if ignore_errors: + return False + raise ex + return True + + @staticmethod + def load_from_file(file_path: str, buffering: int=1, encoding: str='utf-8') -> Union[str, None]: + """load_from_file(file_path, buffering=1, encoding='utf-8') + + Load string data from a file. + + :param file_path: The file to read from. + :type file_path: str + :param buffering: See the built-in python :func:`~open` function documentation for more details. + :type buffering: int, optional + :param encoding: See the built-in python :func:`~open` function documentation for more details. + :type encoding: str, optional + :return: The contents of the file as a string or None if an error occurred. + :rtype: Union[str, None] + """ + if not os.path.isfile(file_path): + return None + with open(file_path, mode='r', buffering=buffering, encoding=encoding) as file: + return file.read() diff --git a/Scripts/s4ap/sims4communitylib/utils/common_json_io_utils.py b/Scripts/s4ap/sims4communitylib/utils/common_json_io_utils.py new file mode 100644 index 0000000..91e31e4 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/common_json_io_utils.py @@ -0,0 +1,155 @@ +""" +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 +""" +import json +import os +from json import JSONEncoder, JSONDecoder +from os import DirEntry +from typing import Union, Any, Iterator, Dict, Type, Callable + +from sims4communitylib.classes.serialization.common_serializable import CommonSerializable +from sims4communitylib.utils.common_io_utils import CommonIOUtils + + +class CommonJSONIOUtils: + """Utilities for reading/writing JSON data to and from files.""" + @staticmethod + def write_to_file(file_path: str, obj: Any, buffering: int=1, encoding: str='utf-8', encoder_class: Type[JSONEncoder]=None) -> bool: + """write_to_file(file_path, obj, buffering=1, encoding='utf-8', encoder_class=None) + + Serialize an object to a file as JSON. + + :param file_path: The file to write to. + :type file_path: str + :param obj: The object to write as JSON. + :type obj: Any + :param buffering: See the built-in python :func:`~open` function documentation for more details. + :type buffering: int, optional + :param encoding: See the built-in python :func:`~open` function documentation for more details. + :type encoding: str, optional + :param encoder_class: Specify a custom JSON encoder class to use in place of the default serialization. Default is None. + :type encoder_class: Type[JSONEncoder], optional + :return: True if successful. False if not. + :rtype: bool + """ + if file_path is None or obj is None: + return False + dir_name = os.path.dirname(file_path) + temp_file_name = 'temp' + os.path.basename(file_path) + temp_file_path = os.path.join(dir_name, temp_file_name) + if encoder_class is not None: + json_obj = json.dumps(obj, cls=encoder_class, indent=2) + else: + json_obj = json.dumps(obj, default=lambda o: o.serialize() if isinstance(o, CommonSerializable) else o.__dict__ if hasattr(o, '__dict__') else o, indent=2) + + with open(temp_file_path, mode='w+', buffering=buffering, encoding=encoding) as file: + file.write(json_obj) + file.flush() + + # File is empty. + if os.stat(temp_file_path).st_size != 0: + if os.path.exists(file_path): + os.remove(file_path) + os.rename(temp_file_path, file_path) + else: + os.remove(temp_file_path) + raise Exception(f'Failed to write file {file_path}, it wrote empty for some reason!') + return True + + @staticmethod + def load_from_file(file_path: str, buffering: int=1, encoding: str='utf-8', decoder_class: Type[JSONDecoder]=None, object_hook: Callable[[Dict[str, Any]], Any]=None) -> Union[Any, None]: + """load_from_file(file_path, buffering=1, encoding='utf-8', decoder_class=None, object_hook=None) + + Deserialize an object from a JSON file. + + :param file_path: The file to read from. + :type: file_path: str + :param buffering: See the built-in python :func:`~open` function documentation for more details. + :type buffering: int, optional + :param encoding: See the built-in python :func:`~open` function documentation for more details. + :type encoding: str, optional + :param decoder_class: Specify a custom JSON decoder class to use in place of the default deserialization. Default is None. + :type decoder_class: Type[JSONDecoder], optional + :param object_hook: A callable that will be called whenever a dictionary appears while decoding JSON. It can be used to create custom objects from data. Default is None. + :type object_hook: Callable[[Dict[str, Any]], Any], optional + :return: The contents of the file as an object or None if an error occurred. + :rtype: Union[Any, None] + """ + try: + file_contents: str = CommonIOUtils.load_from_file(file_path, buffering=buffering, encoding=encoding) + if file_contents is None: + return None + if len(file_contents) == 0: + return None + return json.loads(file_contents, cls=decoder_class, object_hook=object_hook) + except Exception as ex: + raise Exception(f'Failed to read file {file_path}, it is either corrupted, or happened to be locked at the time of trying to read it.') from ex + + @staticmethod + def load_from_folder( + folder_path: str, + skip_file_names: Iterator[str]=(), + buffering: int=1, + encoding: str='utf-8', + decoder_class: Type[JSONDecoder]=None, + object_hook: Callable[[Dict[str, Any]], Any]=None, + on_file_read_failure: Callable[[str, Exception], bool]=lambda *_, **__: True + ) -> Union[Dict[str, Any], None]: + """load_from_folder(\ + folder_path,\ + skip_file_names=(),\ + buffering=1,\ + encoding='utf-8',\ + decoder_class=None,\ + object_hook=None,\ + on_file_read_failure=lambda \*_, \*\*__: True\ + ) + + Deserialize objects from a folder containing JSON files. + + :param folder_path: The folder to read from. + :type: folder_path: str + :param skip_file_names: A collection of file names to ignore. Default is an empty collection. + :type skip_file_names: Iterator[str], optional + :param buffering: See the built-in python :func:`~open` function documentation for more details. + :type buffering: int, optional + :param encoding: See the built-in python :func:`~open` function documentation for more details. + :type encoding: str, optional + :param decoder_class: Specify a custom JSON decoder class to use in place of the default deserialization. Default is None. + :type decoder_class: Type[JSONDecoder], optional + :param object_hook: A callable that will be called whenever a dictionary appears while decoding JSON. It can be used to create custom objects from data. Default is None. + :type object_hook: Callable[[Dict[str, Any]], Any], optional + :param on_file_read_failure: When a file fails to read due to an exception, this callback will be called. If the callback returns False, no more files will be read. If the callback returns True, the rest of the files will continue to be read. Default is a callback that returns True. + :type on_file_read_failure: Callable[[str, Exception], bool], optional + :return: A dictionary of the contents of each file within the specified folder organized by file name or None if the folder path does not exist. + :rtype: Union[Dict[str, Any], None] + """ + if not os.path.exists(folder_path): + return None + if skip_file_names is None: + skip_file_names = tuple() + skip_file_names = tuple(skip_file_names) + skip_file_names = ( + *skip_file_names, + '.DS_Store', + 'desktop.ini' + ) + data = dict() + for entry in os.scandir(folder_path): + entry: DirEntry = entry + if not entry.is_file() or entry.name is None or entry.name in skip_file_names: + continue + try: + file_contents: str = CommonJSONIOUtils.load_from_file(entry.path, buffering=buffering, encoding=encoding, decoder_class=decoder_class, object_hook=object_hook) + except Exception as ex: + if not on_file_read_failure(entry.path, ex): + break + continue + if file_contents is None: + continue + data[entry.name] = file_contents + return data diff --git a/Scripts/s4ap/sims4communitylib/utils/common_keyboard_utils.py b/Scripts/s4ap/sims4communitylib/utils/common_keyboard_utils.py new file mode 100644 index 0000000..69877e8 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/common_keyboard_utils.py @@ -0,0 +1,161 @@ +""" +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 +""" +import os + +from sims4communitylib.enums.common_key import CommonKey +from sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.utils.common_log_registry import CommonLogRegistry + +log = CommonLogRegistry().register_log(ModInfo.get_identity(), 'common_keyboard_utils') +# noinspection PyBroadException +try: + if os.name == 'nt': + import _s4cl_ctypes_module + _user32 = _s4cl_ctypes_module.WinDLL('user32', use_last_error=True) + if _user32 is not None: + _user32.GetKeyState.restype = _s4cl_ctypes_module.c_uint16 + + def _can_detect_key_state_for_current_os() -> bool: + return _user32 is not None + + def _is_holding_key_down(key: CommonKey) -> bool: + key_code = _translate_to_key_code(key) + if key_code == -1: + log.format_with_message('No Key Code found to check for Pressed (Windows)', key=key) + return False + key_state = _user32.GetKeyState(key_code) + key_state_has_value = key_state & 0x8000 + result = bool(key_state_has_value) + log.format_with_message('Is Key Pressed (Windows)', key=key, key_code=key_code, key_state=key_state, key_state_has_value=key_state_has_value, result=result) + return result + + def _is_key_toggled_on(key: CommonKey): + key_code = _translate_to_key_code(key) + if key_code == -1: + log.format_with_message('No Key Code found to check for Toggled On (Windows)', key=key) + return False + key_state = _user32.GetKeyState(key_code) + key_state_has_value = key_state & 0x0001 + result = bool(key_state_has_value) + log.format_with_message('Is Key Toggled On (Windows)', key=key, key_code=key_code, key_state=key_state, key_state_has_value=key_state_has_value, result=result) + return result + + def _translate_to_key_code(key: CommonKey) -> int: + if isinstance(key, int): + return key + if key is None: + return -1 + try: + if isinstance(key, CommonKey): + letter_key = key.name.replace('KEY_', '') + if len(letter_key) != 1: + return int(key) + + virtual_key = _user32.VkKeyScanW(ord(letter_key)) + if virtual_key == -1: + return int(key) + + mapped_virtual_key = _user32.MapVirtualKeyW(virtual_key & 255, 0) + mapped_scan_key = _user32.MapVirtualKeyW(mapped_virtual_key & 255, 1) + if mapped_scan_key == 0: + return int(key) + return mapped_scan_key + except Exception as ex: + CommonExceptionHandler.log_exception(ModInfo.get_identity(), 'An error occurred while translating key to key code. {}'.format(key.name), exception=ex) + return int(key) + else: + # noinspection PyUnresolvedReferences, PyPackageRequirements + import Quartz as _Quartz + + def _can_detect_key_state_for_current_os() -> bool: + return _Quartz.CGEventSourceKeyState is not None + + def _is_holding_key_down(key: CommonKey) -> bool: + key_code = _translate_to_key_code(key) + if key_code == -1: + log.format_with_message('No Key Code found to check for Pressed or Toggled On (Mac)', key=key) + return False + result = bool(_Quartz.CGEventSourceKeyState(_Quartz.kCGEventSourceStateHIDSystemState, key_code)) + log.format_with_message('Is Key Pressed or Toggled On (Mac)', key=key, key_code=key_code, result=result) + return result + + def _is_key_toggled_on(key: CommonKey): + return _is_holding_key_down(key) + + def _translate_to_key_code(key: CommonKey) -> int: + if key is None: + return -1 + return int(key) +except: + def _can_detect_key_state_for_current_os() -> bool: + return False + + def _is_holding_key_down(_: CommonKey) -> bool: + return False + + def _is_key_toggled_on(_: CommonKey) -> bool: + return False + + def _translate_to_key_code(key: CommonKey) -> int: + if key is None: + return -1 + return int(key) + + +class CommonKeyboardUtils: + """Utilities for manipulating the keyboard.""" + @staticmethod + def can_detect_key_state_for_current_os() -> bool: + """can_detect_key_state_for_current_os() + + Determine if CommonKeyboardUtils can detect the state of a key on the keyboard for the current Operating System. + + :return: True, if CommonKeyboardUtils can detect the state of a key on the keyboard for the current Operating System. False, if not. + :rtype: bool + """ + return _can_detect_key_state_for_current_os() + + @staticmethod + def is_holding_key_down(key: CommonKey) -> bool: + """is_holding_key_down(key) + + Determine if the player is holding a keyboard key down. + + :param key: The Key to check. + :type key: CommonKey + :return: True, if the player is holding the specified key down. False, if not. + :rtype: bool + """ + return _is_holding_key_down(key) + + @staticmethod + def key_is_toggled_on(key: CommonKey) -> bool: + """key_is_toggled_on(key) + + Determine if the player has a key set to the ON state, such as the CAPS LOCK key. + + :param key: The Key to check. + :type key: CommonKey + :return: True, if the player has the specified key set to the ON state. False, if not. + :rtype: bool + """ + return _is_key_toggled_on(key) + + @staticmethod + def translate_to_key_code(key: CommonKey) -> int: + """translate_to_key_code(key) + + Translate a Key to its Key Code counterpart. + + :param key: The Key to convert. + :type key: CommonKey + :return: The integer representation of the specified key or -1 if not found. + :rtype: int + """ + return _translate_to_key_code(key) diff --git a/Scripts/s4ap/sims4communitylib/utils/common_log_registry.py b/Scripts/s4ap/sims4communitylib/utils/common_log_registry.py new file mode 100644 index 0000000..e70cd7e --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/common_log_registry.py @@ -0,0 +1,818 @@ +""" +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 +""" +import os +from typing import List, Dict, Any, Union, Tuple, Iterator +from pprint import pformat + +from sims4communitylib.enums.enumtypes.common_int import CommonInt +from sims4communitylib.exceptions.common_stacktrace_utils import CommonStacktraceUtil +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.common_service import CommonService +from sims4communitylib.utils.common_io_utils import CommonIOUtils +from sims4communitylib.utils.common_log_utils import CommonLogUtils + +_log = None + + +class CommonMessageType(CommonInt): + """Message types for use when logging. + + """ + INVALID: 'CommonMessageType' = 0 + ERROR: 'CommonMessageType' = 1 + WARN: 'CommonMessageType' = 2 + DEBUG: 'CommonMessageType' = 3 + INFO: 'CommonMessageType' = 4 + + +class CommonLog: + """CommonLog(mod_identifier, log_name, custom_file_path=None) + + A class used to log messages. + + :param mod_identifier: The name or identity of the Mod that owns the log. + :type mod_identifier: Union[str, CommonModIdentity] + :param log_name: The name of the log, used when enabling/disabling logs via commands + :type log_name: str + :param custom_file_path: A custom file path relative to The Sims 4 folder. Example: Value is 'fake_path/to/directory', the final path would be 'The Sims 4/fake_path/to_directory'. Default is None. + :type custom_file_path: str, optional + """ + def __init__(self, mod_identifier: Union[str, CommonModIdentity], log_name: str, custom_file_path: str = None): + self._log_name = log_name + from sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils + self._mod_name = CommonModIdentityUtils.determine_mod_name_from_identifier(mod_identifier) + self._custom_file_path = custom_file_path + self._enabled_message_types = tuple() + self._should_log_extra_sim_details = False + + def debug(self, message: str): + """debug(message) + + Log a message with message type DEBUG. + + :param message: The message to log. + :type message: str + """ + if self.is_enabled(CommonMessageType.DEBUG): + self._log_message(CommonMessageType.DEBUG, message) + + def info(self, message: str): + """info(message) + + Log a message with message type INFO. + + :param message: The message to log. + :type message: str + """ + if self.is_enabled(CommonMessageType.INFO): + self._log_message(CommonMessageType.INFO, message) + + def format_info(self, *args: Any, update_tokens: bool = True, **kwargs: Any): + """format_info(*args, update_tokens=True, **kwargs) + + Log a non-descriptive message containing pformatted arguments and keyword arguments with message type INFO. + + :param update_tokens: If set to True, when an arg or kwarg value is a Sim or SimInfo, it will be converted to their name before format occurs. Default is True. + :type update_tokens: bool, optional + :param args: Arguments to format into the message. + :type args: Any + :param kwargs: Keyword Arguments to format into the message. + :type kwargs: Any + """ + self.format(*args, message_type=CommonMessageType.INFO, update_tokens=update_tokens, **kwargs) + + def format_info_with_message(self, message: str, *args, update_tokens: bool = True, **kwargs): + """format_info_with_message(message, *args, update_tokens=True, **kwargs) + + Log a message containing pformatted arguments and keyword arguments with message type INFO. + + :param message: The message to log. + :type message: str + :param update_tokens: If set to True, when an arg or kwarg value is a Sim or SimInfo, it will be converted to their name before format occurs. Default is True. + :type update_tokens: bool, optional + :param args: Arguments to format into the message. + :type args: Any + :param kwargs: Keyword Arguments to format into the message. + :type kwargs: Any + """ + self.format_with_message(message, *args, message_type=CommonMessageType.INFO, update_tokens=update_tokens, **kwargs) + + def format( + self, + *args, + message_type: CommonMessageType = CommonMessageType.DEBUG, + update_tokens: bool = True, + **kwargs + ): + """format(*args, message_type=CommonMessageType.DEBUG, update_tokens=True, **kwargs) + + Log a non-descriptive message containing pformatted arguments and keyword arguments with the specified message type. + + :param message_type: The MessageType of the logged message. Default is CommonMessageType.DEBUG. + :type message_type: CommonMessageType, optional + :param update_tokens: If set to True, when an arg or kwarg value is a Sim or SimInfo, it will be converted to their name before format occurs. Default is True. + :type update_tokens: bool, optional + :param args: Arguments to format into the message. + :type args: Any + :param kwargs: Keyword Arguments to format into the message. + :type kwargs: Any + """ + if self.is_enabled(message_type): + if update_tokens: + args = self._update_args(*args) + kwargs = self._update_kwargs(**kwargs) + if args and kwargs: + self._log_message(message_type, '{}, {}'.format(pformat(args), pformat(kwargs))) + elif args: + self._log_message(message_type, '{}'.format(pformat(args))) + else: + self._log_message(message_type, '{}'.format(pformat(kwargs))) + + def format_with_message( + self, + message: str, + *args, + message_type: CommonMessageType = CommonMessageType.DEBUG, + update_tokens: bool = True, + **kwargs + ): + """format_with_message(message, *args, message_type=CommonMessageType.DEBUG, update_tokens=True, **kwargs) + + Log a message containing pformatted arguments and keyword arguments with the specified message type. + + :param message: The message to log. + :type message: str + :param message_type: The type of message being logged. Default is CommonMessageType.DEBUG. + :type message_type: CommonMessageType, optional + :param update_tokens: If set to True, when an arg or kwarg value is a Sim or SimInfo, it will be converted to their name before format occurs. Default is True. + :type update_tokens: bool, optional + :param args: Arguments to format into the message. + :type args: Any + :param kwargs: Keyword Arguments to format into the message. + :type kwargs: Any + """ + if self.is_enabled(message_type): + if update_tokens: + args = self._update_args(*args) + kwargs = self._update_kwargs(**kwargs) + if args and kwargs: + self._log_message(message_type, '{} {}, {}'.format(message, pformat(args), pformat(kwargs))) + elif args: + self._log_message(message_type, '{} {}'.format(message, pformat(args))) + elif kwargs: + self._log_message(message_type, '{} {}'.format(message, pformat(kwargs))) + else: + self._log_message(message_type, message) + + def warn(self, message: str): + """warn(message) + + Log a message with message type WARN. + + :param message: The message to log. + :type message: str + """ + if self.is_enabled(CommonMessageType.WARN): + self._log_message(CommonMessageType.WARN, message) + + def format_warn(self, *args: Any, update_tokens: bool = True, **kwargs: Any): + """format_warn(*args, update_tokens=True, **kwargs) + + Log a non-descriptive message containing pformatted arguments and keyword arguments with message type WARN. + + :param update_tokens: If set to True, when an arg or kwarg value is a Sim or SimInfo, it will be converted to their name before format occurs. Default is True. + :type update_tokens: bool, optional + :param args: Arguments to format into the message. + :type args: Any + :param kwargs: Keyword Arguments to format into the message. + :type kwargs: Any + """ + self.format(*args, message_type=CommonMessageType.WARN, update_tokens=update_tokens, **kwargs) + + def format_warn_with_message(self, message: str, *args, update_tokens: bool = True, **kwargs): + """format_warn_with_message(message, *args, update_tokens=True, **kwargs) + + Log a message containing pformatted arguments and keyword arguments with message type WARN. + + :param message: The message to log. + :type message: str + :param update_tokens: If set to True, when an arg or kwarg value is a Sim or SimInfo, it will be converted to their name before format occurs. Default is True. + :type update_tokens: bool, optional + :param args: Arguments to format into the message. + :type args: Any + :param kwargs: Keyword Arguments to format into the message. + :type kwargs: Any + """ + self.format_with_message(message, *args, message_type=CommonMessageType.WARN, update_tokens=update_tokens, **kwargs) + + def error( + self, + message: str, + message_type: CommonMessageType = CommonMessageType.ERROR, + exception: Exception = None, + throw: bool = True, + stack_trace: List[str] = None + ): + """error(message, message_type=CommonMessageType.ERROR, exception=None, throw=True, stack_trace=None) + + Log an error message with the specified message type + + :param message: The message to log. + :type message: str + :param message_type: The message type of the error message. Default is CommonMessageType.ERROR. + :type message_type: CommonMessageType, optional + :param exception: The exception that occurred. Default is None. + :type exception: Exception, optional + :param stack_trace: The stack trace leading to the exception, if not supplied, a stack trace will be gathered for you. Default is None. + :type stack_trace: List[str], optional + :param throw: If set to True, the exception will be rethrown. + :type throw: bool, optional + """ + if throw: + stack_trace = stack_trace or CommonStacktraceUtil.get_full_stack_trace() + self._log_error(message, exception=exception, stack_trace=stack_trace) + self._log_message(message_type, message) + if exception is not None: + self._log_message(message_type, pformat(exception)) + + def format_error( + self, + *args, + exception: Exception = None, + throw: bool = True, + update_tokens: bool = True, + stack_trace: List[str] = None, + **kwargs + ): + """format_error(*args, exception=None, throw=True, update_tokens=True, stack_trace=None, **kwargs) + + Log a non-descriptive error message containing pformatted arguments and keyword arguments. + + :param exception: The exception that occurred. + :type exception: Exception, optional + :param throw: If set to True, the exception will be rethrown. + :type throw: bool, optional + :param update_tokens: If set to True, when an arg or kwarg value is a Sim or SimInfo, it will be converted to their name before format occurs. Default is True. + :type update_tokens: bool, optional + :param stack_trace: The stack trace leading to the exception, if not supplied, a stack trace will be gathered for you. Default is None. + :type stack_trace: List[str], optional + :param args: Arguments to format into the message. + :type args: Any + :param kwargs: Keyword Arguments to format into the message. + :type kwargs: Any + """ + if update_tokens: + args = self._update_args(*args) + kwargs = self._update_kwargs(**kwargs) + stack_trace = stack_trace or CommonStacktraceUtil.get_full_stack_trace() + if args and kwargs: + self.error('{}, {}'.format(pformat(args), pformat(kwargs)), exception=exception, throw=throw, stack_trace=stack_trace) + elif args: + self.error('{}'.format(pformat(args)), exception=exception, throw=throw, stack_trace=stack_trace) + else: + self.error('{}'.format(pformat(kwargs)), exception=exception, throw=throw, stack_trace=stack_trace) + + def format_error_with_message( + self, + message: str, + *args, + exception: Exception = None, + throw: bool = True, + update_tokens: bool = True, + stack_trace: List[str] = None, + **kwargs + ): + """format_error_with_message(\ + message,\ + *args,\ + exception=None,\ + throw=True,\ + update_tokens=True,\ + stack_trace=None,\ + **kwargs\ + ) + + Log an error message containing pformatted arguments and keyword arguments. + + :param message: The message to log. + :type message: str + :param exception: The exception that occurred. Default is None. + :type exception: Exception, None + :param throw: If set to True, the exception will be rethrown. Default is True. + :type throw: bool, optional + :param update_tokens: If set to True, when an arg or kwarg value is a Sim or SimInfo, it will be converted to their name before format occurs. Default is True. + :type update_tokens: bool, optional + :param stack_trace: The stack trace leading to the exception, if not supplied, a stack trace will be gathered for you. Default is None. + :type stack_trace: List[str], optional + :param args: Arguments to format into the message. + :type args: Any + :param kwargs: Keyword Arguments to format into the message. + :type kwargs: Any + """ + if update_tokens: + args = self._update_args(*args) + kwargs = self._update_kwargs(**kwargs) + stack_trace = stack_trace or CommonStacktraceUtil.get_full_stack_trace() + if args and kwargs: + self.error('{} {}, {}'.format(message, pformat(args), pformat(kwargs)), exception=exception, throw=throw, stack_trace=stack_trace) + elif args: + self.error('{} {}'.format(message, pformat(args)), exception=exception, throw=throw, stack_trace=stack_trace) + elif kwargs: + self.error('{} {}'.format(message, pformat(kwargs)), exception=exception, throw=throw, stack_trace=stack_trace) + else: + self.error(message, exception=exception, throw=throw, stack_trace=stack_trace) + + def log_stack(self) -> None: + """log_stack() + + Log the current stack trace and the calling frames + + .. note:: The best use for this is to find the path of invocation to the location this function is called at. + + """ + if not self.is_enabled(CommonMessageType.DEBUG): + return + import inspect + current_frame = inspect.currentframe() + calling_frame = inspect.getouterframes(current_frame, 2) + self.format(calling_frame) + + def enable( + self, + message_types: Iterator[CommonMessageType] = ( + CommonMessageType.WARN, + CommonMessageType.DEBUG, + CommonMessageType.INFO + ), + enable_logging_extra_sim_details: bool = False + ) -> None: + """enable(\ + message_types=(CommonMessageType.WARN, CommonMessageType.DEBUG, CommonMessageType.INFO),\ + enable_extra_sim_details=False\ + ) + + Enable the log or specific types of logs. + + :param message_types: The types of messages to enable for logging. Default message types are Info, Debug, and Warn. + :rtype message_types: Tuple[CommonMessageTypes], optional + :param enable_logging_extra_sim_details: If True, when a Sim is being logged, extra Sim details, such as Sim Type and Current Sim Type, will be logged in addition to their name and id. If False, only their name and id will be logged. Default is False. + :type enable_logging_extra_sim_details: bool, optional + """ + self._enabled_message_types = message_types or tuple() + if enable_logging_extra_sim_details: + self.enable_logging_extra_sim_details() + + def enable_logging_extra_sim_details(self) -> None: + """enable_logging_extra_sim_details() + + Enable the logging of extra Sim details, when logging a Sim, such as Sim Type and Sim Current Type. + """ + self._should_log_extra_sim_details = True + + def disable_logging_extra_sim_details(self) -> None: + """disable_logging_extra_sim_details() + + Disable the logging of extra Sim details when logging a Sim, such as Sim Type and Sim Current Type. + """ + self._should_log_extra_sim_details = False + + def disable(self) -> None: + """disable() + + Disable the log + + """ + self._enabled_message_types = tuple() + self.disable_logging_extra_sim_details() + + @property + def enabled(self) -> bool: + """Determine whether the log is enabled or not. + + .. note:: All logs are disabled by default. + + :return: True, if the log is enabled. False, if the log is disabled. + :rtype: bool + """ + return any(self._enabled_message_types) + + @property + def name(self) -> str: + """The identifier of this log. + + :return: A string identifier. + :rtype: str + """ + return self._log_name + + @property + def mod_name(self) -> str: + """The name of the mod that owns the log. + + :return: The name of the mod that owns the log + :rtype: str + """ + return self._mod_name + + @property + def messages_file_path(self) -> str: + """The file path messages are logged to. + + :return: The file path messages are logged to. + :rtype: str + """ + return CommonLogUtils.get_message_file_path(self.mod_name, custom_file_path=self._custom_file_path) + + @property + def exceptions_file_path(self) -> str: + """The file path exceptions are logged to. + + :return: The file path exceptions are logged to. + :rtype: str + """ + return CommonLogUtils.get_exceptions_file_path(self.mod_name, custom_file_path=self._custom_file_path) + + def is_enabled(self, message_type: CommonMessageType) -> bool: + """is_enabled(message_type) + + Determine if a message type is enabled for logging. + + :param message_type: The type of messages to check for allowance. + :type message_type: CommonMessageType + :return: True, if the specified message type is enabled for logging. False, if not. + :rtype: bool + """ + return message_type in self._enabled_message_types + + def _log_message(self, message_type: CommonMessageType, message: str): + from sims4communitylib.utils.common_date_utils import CommonRealDateUtils + from sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler + current_date_time = CommonRealDateUtils.get_current_date_string() + new_message = '{} {}: [{}]: {}\n'.format(current_date_time, getattr(message_type, 'name', str(message_type)), self.name, message) + try: + from sims4communitylib.utils.common_io_utils import CommonIOUtils + file_path = self.messages_file_path + os.makedirs(os.path.dirname(file_path), exist_ok=True) + CommonIOUtils.write_to_file(file_path, new_message, ignore_errors=True) + except Exception as ex: + CommonExceptionHandler.log_exception(self.mod_name, 'Error occurred while attempting to log message: {}'.format(pformat(message)), exception=ex, custom_file_path=self._custom_file_path) + + def _log_error(self, message: str, exception: Exception = None, stack_trace: List[str] = None): + from sims4communitylib.utils.common_date_utils import CommonRealDateUtils + from sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler + try: + exceptions = stack_trace or CommonStacktraceUtil.get_full_stack_trace() + if exception is not None: + stack_trace_message = '{}{} -> {}: {}\n'.format(''.join(exceptions), message, type(exception).__name__, exception) + else: + stack_trace_message = '{}{}\n'.format(''.join(exceptions), message) + file_path = self.exceptions_file_path + os.makedirs(os.path.dirname(file_path), exist_ok=True) + exception_traceback_text = '[{}] {} {}\n'.format(self.mod_name, CommonRealDateUtils.get_current_date_string(), stack_trace_message) + result = CommonIOUtils.write_to_file(file_path, exception_traceback_text, ignore_errors=True) + if result: + CommonExceptionHandler._notify_exception_occurred(file_path, mod_identifier=self.mod_name) + except Exception as ex: + CommonExceptionHandler.log_exception(self.mod_name, 'Error occurred while attempting to log message: {}'.format(pformat(message)), exception=ex, custom_file_path=self._custom_file_path) + + def _update_args(self, *args: Any) -> Tuple[Any]: + if not args: + return args + from sims4communitylib.utils.common_type_utils import CommonTypeUtils + from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils + from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + new_args: List[Any] = list() + for arg in args: + if CommonTypeUtils.is_sim_or_sim_info(arg) or CommonTypeUtils.is_sim_info_base_wrapper(arg): + obj_type_acronym = 'Unknown' + if CommonTypeUtils.is_sim_info(arg): + obj_type_acronym = 'SI' + elif CommonTypeUtils.is_sim_instance(arg): + obj_type_acronym = 'S' + elif CommonTypeUtils.is_sim_info_base_wrapper(arg): + obj_type_acronym = 'SIBW' + if self._should_log_extra_sim_details: + from sims4communitylib.utils.sims.common_sim_type_utils import CommonSimTypeUtils + sim_info = CommonSimUtils.get_sim_info(arg) + sim_types = tuple(CommonSimTypeUtils.get_all_sim_types_gen(sim_info, combine_teen_young_adult_and_elder_age=False, combine_child_dog_types=False)) + current_sim_type = CommonSimTypeUtils.determine_sim_type(sim_info, combine_teen_young_adult_and_elder_age=False, combine_child_dog_types=False, use_current_occult_type=True) + new_args.append('{} ({}, ({}), C:{}) [{}]'.format(CommonSimNameUtils.get_full_name(arg), str(CommonSimUtils.get_sim_id(arg)), ', '.join([sim_type.name for sim_type in sim_types]), current_sim_type.name, obj_type_acronym)) + else: + new_args.append('{} ({}) [{}]'.format(CommonSimNameUtils.get_full_name(arg), str(CommonSimUtils.get_sim_id(arg)), obj_type_acronym)) + else: + new_args.append(arg) + return tuple(new_args) + + def _update_kwargs(self, **kwargs: Any) -> Dict[str, Any]: + if not kwargs: + return kwargs + new_kwargs: Dict[str, Any] = dict() + from sims4communitylib.utils.common_type_utils import CommonTypeUtils + from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils + from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + for (key, val) in kwargs.items(): + if CommonTypeUtils.is_sim_or_sim_info(val) or CommonTypeUtils.is_sim_info_base_wrapper(val): + obj_type_acronym = 'UnknownType' + if CommonTypeUtils.is_sim_info(val): + obj_type_acronym = 'SI' + elif CommonTypeUtils.is_sim_instance(val): + obj_type_acronym = 'S' + elif CommonTypeUtils.is_sim_info_base_wrapper(val): + obj_type_acronym = 'SIBW' + + if self._should_log_extra_sim_details: + from sims4communitylib.utils.sims.common_sim_type_utils import CommonSimTypeUtils + sim_info = CommonSimUtils.get_sim_info(val) + sim_types = tuple(CommonSimTypeUtils.get_all_sim_types_gen(sim_info, combine_teen_young_adult_and_elder_age=False, combine_child_dog_types=False)) + current_sim_type = CommonSimTypeUtils.determine_sim_type(sim_info, combine_teen_young_adult_and_elder_age=False, combine_child_dog_types=False, use_current_occult_type=True) + new_kwargs[key] = '{} ({}, ({}), C:{}) [{}]'.format(CommonSimNameUtils.get_full_name(val), str(CommonSimUtils.get_sim_id(val)), ', '.join([sim_type.name for sim_type in sim_types]), current_sim_type.name, obj_type_acronym) + else: + new_kwargs[key] = '{} ({}) [{}]'.format(CommonSimNameUtils.get_full_name(val), str(CommonSimUtils.get_sim_id(val)), obj_type_acronym) + else: + new_kwargs[key] = val + return new_kwargs + + +class CommonLogRegistry(CommonService): + """CommonLogRegistry() + + Used to register logs. + + .. note:: To register your own logs, please use :func:`~get` to create a CommonLogRegistry (CommonLogRegistry.get()). + + + :Example Usage: + + .. highlight:: python + .. code-block:: python + + # Register the log, Logs will appear in a file titled "MOD_NAME_Messages.txt" and messages logged using this log will be prefixed with "s4cl_log_name" + log = CommonLogRegistry.get().register_log('MOD_NAME', 's4cl_log_name') + # Enable the log, if not enabled, messages will not be logged. + log.enable() + # Log a message + log.debug('Printing a message to the log.') + # Disable the log + log.disable() + + # The MOD_NAME_Messages.txt file will contain the "Printing a message to the log." message. + + .. note:: + + Available Commands: + + - `s4clib.enable_log` or `s4clib.enablelog` + - `s4clib.disable_log` or `s4clib.disablelog` + - `s4clib.disable_all_logs` or `s4clib.disablealllogs` + - `s4clib.logs` + + """ + def __init__(self) -> None: + self._registered_logs: Dict[str, Dict[str, CommonLog]] = dict() + self._delete_old_log_files() + + def get_registered_log_names(self, mod_identifier: Union[str, CommonModIdentity] = None) -> List[str]: + """get_registered_log_names() + + Retrieve the names of all registered logs. + + :param mod_identifier: The name or identifier of the mod the log is registered for. Default is None. + :type mod_identifier: Union[str, CommonModIdentity], optional + :return: A collection of registered logs. + :rtype: List[str] + """ + if self._registered_logs is None: + return list() + if mod_identifier is None: + log_names = [] + for log_mod_name in self._registered_logs: + for log_name in self._registered_logs[log_mod_name]: + log_names.append(log_name) + return log_names + else: + mod_name = CommonModIdentity._get_mod_name(mod_identifier) + mod_name = mod_name.lower() + if mod_name not in self._registered_logs: + return list() + return list(self._registered_logs[mod_name].keys()) + + def register_log(self, mod_identifier: Union[str, CommonModIdentity], log_name: str, custom_file_path: str = None) -> CommonLog: + """register_log(mod_identifier, log_name, custom_file_path: str=None) + + Create and register a log with the specified name. + + .. note:: If `log_name` matches the name of a Log already registered, that log will be returned rather than creating a new Log. + + :param mod_identifier: The name or identifier of the mod the log is registered for. + :type mod_identifier: Union[str, CommonModIdentity] + :param log_name: The name of the log. + :type log_name: str + :param custom_file_path: A custom file path relative to The Sims 4 folder. Example: Value is 'fake_path/to/directory', the final path would be 'The Sims 4/fake_path/to_directory'. Default is None. + :type custom_file_path: str, optional + :return: An object of type CommonLog + :rtype: CommonLog + """ + if self._registered_logs is None: + self._registered_logs = dict() + mod_name = CommonModIdentity._get_mod_name(mod_identifier) + mod_name = mod_name.lower() + first_time_log = False + # Dict[str, Dict[str, CommonLog]] + if mod_name not in self._registered_logs: + first_time_log = True + self._registered_logs[mod_name] = dict() + # Dict[str, CommonLog] + if log_name in self._registered_logs[mod_name]: + return self._registered_logs[mod_name][log_name] + log = CommonLog(mod_identifier, log_name, custom_file_path=custom_file_path) + from sims4communitylib.s4cl_configuration import S4CLConfiguration + if log_name in S4CLConfiguration().enable_logs: + log.enable(message_types=S4CLConfiguration().enable_logs[log_name]) + self._registered_logs[mod_name][log_name] = log + if first_time_log: + if mod_identifier is not None: + if _log is not None: + _log.enable() + if isinstance(mod_identifier, CommonModIdentity): + _log.debug(f'{mod_identifier.name} Version "{mod_identifier.version}" detected.') + else: + _log.debug(f'{mod_identifier} detected.') + _log.disable() + else: + current_game_version = CommonLogUtils.get_sims_4_game_version() + log.enable() + log.debug(f'The Sims 4 Game Version "{current_game_version}" detected.') + if isinstance(mod_identifier, CommonModIdentity): + log.debug(f'{mod_identifier.name} Version "{mod_identifier.version}" detected.') + else: + log.debug(f'{mod_identifier} detected.') + log.disable() + return log + + def _delete_old_log_files(self) -> None: + from sims4communitylib.utils.common_io_utils import CommonIOUtils + files_to_delete = ( + os.path.join(CommonLogUtils.get_sims_documents_location_path(), 'mod_logs'), + ) + for file_to_delete in files_to_delete: + # noinspection PyBroadException + try: + if os.path.isfile(file_to_delete): + CommonIOUtils.delete_file(file_to_delete, ignore_errors=True) + else: + CommonIOUtils.delete_directory(file_to_delete, ignore_errors=True) + except: + continue + + # noinspection PyUnusedLocal + def log_exists(self, log_name: str, mod_identifier: Union[str, CommonModIdentity] = None) -> bool: + """log_exists(log_name, mod_identifier=None) + + Determine if logs exist with the specified name. + + :param log_name: The name of the log to locate. + :type log_name: str + :param mod_identifier: The name or identity of the mod the log belongs to. Default is None. + :type mod_identifier: Union[str, CommonModIdentity], optional + :return: True, if a handler exists with the specified name. + :rtype: bool + """ + if self._registered_logs is None: + return False + if mod_identifier is None: + for log_mod_name in self._registered_logs: + if log_name not in self._registered_logs[log_mod_name]: + continue + return True + else: + mod_name = CommonModIdentity._get_mod_name(mod_identifier) + mod_name = mod_name.lower() + return mod_name in self._registered_logs and log_name in self._registered_logs[mod_name] + + # noinspection PyUnusedLocal + def enable_logs(self, log_name: str, mod_identifier: Union[str, CommonModIdentity] = None) -> bool: + """enable_logs(log_name, mod_identifier=None) + + Enable all logs with the specified name. + + :param log_name: The name of the logs to enable. + :type log_name: str + :param mod_identifier: The name or identity of the mod the log belongs to. Default is None. + :type mod_identifier: Union[str, CommonModIdentity], optional + :return: True, if successful. False, if not. + :rtype: bool + """ + if self._registered_logs is None: + self._registered_logs = dict() + if mod_identifier is None: + for log_mod_name in self._registered_logs: + if log_name not in self._registered_logs[log_mod_name]: + continue + log = self._registered_logs[log_mod_name][log_name] + log.enable() + else: + mod_name = CommonModIdentity._get_mod_name(mod_identifier) + mod_name = mod_name.lower() + if mod_name not in self._registered_logs: + return False + if log_name not in self._registered_logs[mod_name]: + log = self.register_log(mod_name, log_name) + if log is not None: + log.enable() + return True + return False + self._registered_logs[mod_name][log_name].enable() + return True + + # noinspection PyUnusedLocal + def disable_logs(self, log_name: str, mod_identifier: Union[str, CommonModIdentity] = None) -> bool: + """disable_logs(log_name, mod_identifier=None) + + Disable all logs with the specified name. + + :param log_name: The name of the logs to disable. + :type log_name: str + :param mod_identifier: The name or identity of the mod to disable logs for. Default is None. + :type mod_identifier: Union[str, CommonModIdentity], optional + :return: True, if successful. False, if not. + :rtype: bool + """ + if self._registered_logs is None: + self._registered_logs = dict() + if mod_identifier is None: + for log_mod_name in self._registered_logs: + if log_name not in self._registered_logs[log_mod_name]: + continue + log = self._registered_logs[log_mod_name][log_name] + log.disable() + else: + mod_name = CommonModIdentity._get_mod_name(mod_identifier) + mod_name = mod_name.lower() + if mod_name not in self._registered_logs: + return False + if log_name not in self._registered_logs[mod_name]: + return False + self._registered_logs[mod_name][log_name].disable() + return True + + # noinspection PyUnusedLocal + def enable_all_logs(self, mod_identifier: Union[str, CommonModIdentity] = None) -> bool: + """enable_all_logs(mod_identifier=None) + + Enable all logs from logging + + :param mod_identifier: The name or identity of the mod to enable logs for. Default is None. + :type mod_identifier: Union[str, CommonModIdentity], optional + :return: True, if successful. False, if not. + :rtype: bool + """ + if self._registered_logs is None: + self._registered_logs = dict() + if mod_identifier is None: + for log_mod_name in self._registered_logs: + for log_name in self._registered_logs[log_mod_name]: + self._registered_logs[log_mod_name][log_name].enable() + else: + mod_name = CommonModIdentity._get_mod_name(mod_identifier) + mod_name = mod_name.lower() + if mod_name not in self._registered_logs: + return False + for log_name in self._registered_logs[mod_name]: + self._registered_logs[mod_name][log_name].enable() + return True + + # noinspection PyUnusedLocal + def disable_all_logs(self, mod_identifier: Union[str, CommonModIdentity] = None) -> bool: + """disable_all_logs(mod_identifier=None) + + Disable all logs from logging + + :param mod_identifier: The name or identity of the mod to disable logs for. Default is None. + :type mod_identifier: Union[str, CommonModIdentity], optional + :return: True, if successful. False, if not. + :rtype: bool + """ + if self._registered_logs is None: + self._registered_logs = dict() + if mod_identifier is None: + for log_mod_name in self._registered_logs: + for log_name in self._registered_logs[log_mod_name]: + self._registered_logs[log_mod_name][log_name].disable() + else: + mod_name = CommonModIdentity._get_mod_name(mod_identifier) + mod_name = mod_name.lower() + if mod_name not in self._registered_logs: + return False + for log_name in self._registered_logs[mod_name]: + self._registered_logs[mod_name][log_name].disable() + return True + + +# noinspection PyRedeclaration +_log = CommonLogRegistry().register_log(ModInfo.get_identity(), 's4cl_log_registry') diff --git a/Scripts/s4ap/sims4communitylib/utils/common_log_utils.py b/Scripts/s4ap/sims4communitylib/utils/common_log_utils.py new file mode 100644 index 0000000..2ee2307 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/common_log_utils.py @@ -0,0 +1,206 @@ +""" +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 +""" +import os +from typing import Union + +from sims4communitylib.mod_support.mod_identity import CommonModIdentity + + +class CommonLogUtils: + """Utilities for retrieving the paths used for logging. + + """ + + @staticmethod + def get_sims_4_game_version() -> str: + """get_sims_4_game_version() + + Retrieve the current game version of Sims 4. + + :return: The current game version of Sims 4. + :rtype: str + """ + the_sims_4_folder = CommonLogUtils.get_sims_documents_location_path() + filename = os.path.join(the_sims_4_folder, 'GameVersion.txt') + import re + with open(filename, 'rb') as fp: + v = fp.read().decode(errors='ignore') # convert b to str and ignore errors + v = re.sub(r'[^0-9.]', '', v) # in case of UTF-8 characters which survived 'ignore': replace everything with '' except of '0-9' and '.' + return v + + @staticmethod + def get_exceptions_file_path(mod_identifier: Union[str, CommonModIdentity], custom_file_path: str=None) -> str: + """get_exceptions_file_path(mod_identifier, custom_file_path=None) + + Retrieve the file path to the Exceptions file used for logging error messages. + + :param mod_identifier: The name or identity of the mod requesting the file path. + :type mod_identifier: Union[str, CommonModIdentity] + :param custom_file_path: A custom file path relative to The Sims 4 folder. Example: Value is 'fake_path/to/directory', the final path would be 'The Sims 4/fake_path/to_directory'. Default is None. + :type custom_file_path: str, optional + :return: A file path to the Exceptions file. + :rtype: str + """ + return CommonLogUtils._get_file_name(mod_identifier, 'Exceptions', custom_file_path=custom_file_path) + + @staticmethod + def get_message_file_path(mod_identifier: Union[str, CommonModIdentity], custom_file_path: str=None) -> str: + """get_message_file_path(mod_identifier, custom_file_path=None) + + Retrieve the file path to the Messages file used for logging info/debug messages. + + :param mod_identifier: The name of the mod requesting the file path. + :type mod_identifier: Union[str, CommonModIdentity] + :param custom_file_path: A custom file path relative to The Sims 4 folder. Example: Value is 'fake_path/to/directory', the final path would be 'The Sims 4/fake_path/to_directory'. Default is None. + :type custom_file_path: str, optional + :return: A file path to the Messages file. + :rtype: str + """ + return CommonLogUtils._get_file_name(mod_identifier, 'Messages', custom_file_path=custom_file_path) + + @staticmethod + def get_old_exceptions_file_path(mod_identifier: Union[str, CommonModIdentity], custom_file_path: str=None) -> str: + """get_old_exceptions_file_path(mod_identifier, custom_file_path=None) + + Retrieve the file path to the Old Exceptions file used as the overflow when the main Exception file becomes too large. + + :param mod_identifier: The name or identity of the mod requesting the file path. + :type mod_identifier: Union[str, CommonModIdentity] + :param custom_file_path: A custom file path relative to The Sims 4 folder. Example: Value is 'fake_path/to/directory', the final path would be 'The Sims 4/fake_path/to_directory'. Default is None. + :type custom_file_path: str, optional + :return: A file path to the Old Exceptions file. + :rtype: str + """ + return CommonLogUtils._get_old_file_path_name(mod_identifier, 'Exceptions', custom_file_path=custom_file_path) + + @staticmethod + def get_old_message_file_path(mod_identifier: Union[str, CommonModIdentity], custom_file_path: str=None) -> str: + """get_old_message_file_path(mod_identifier, custom_file_path=None) + + Retrieve the file path to the Old Messages file used as the overflow when the main Messages file becomes too large. + + :param mod_identifier: The name of the mod requesting the file path. + :type mod_identifier: Union[str, CommonModIdentity] + :param custom_file_path: A custom file path relative to The Sims 4 folder. Example: Value is 'fake_path/to/directory', the final path would be 'The Sims 4/fake_path/to_directory'. Default is None. + :type custom_file_path: str, optional + :return: A file path to the Old Messages file. + :rtype: str + """ + return CommonLogUtils._get_old_file_path_name(mod_identifier, 'Messages', custom_file_path=custom_file_path) + + @staticmethod + def get_sims_documents_location_path() -> str: + """get_sims_documents_location_path() + + Retrieve the full path of the folder 'Documents\Electronic Arts\The Sims 4' + + :return: The file path to 'Documents\Electronic Arts\The Sims 4' folder. + :rtype: str + """ + # return os.environ['TS4_MODS_FOLDER'] + documents_path = os.path.dirname(CommonLogUtils.get_mods_location_path()) + if os.path.exists(documents_path): + return documents_path + from sims4communitylib.modinfo import ModInfo + root_file = os.path.normpath(os.path.dirname(os.path.realpath(ModInfo.get_identity().file_path))).replace(os.sep, '/') + root_file_split = root_file.split('/') + if 'Mods' not in root_file_split: + return '' + file_path = '' + # noinspection PyTypeChecker + exit_index = len(root_file_split) - root_file_split.index('Mods') + for index in range(0, len(root_file_split) - exit_index): + file_path = os.path.join(file_path + os.sep, str(root_file_split[index])) + return file_path + + @staticmethod + def get_mods_location_path() -> str: + """get_sims_mods_location_path() + + Retrieve the full path of the folder 'Documents\Electronic Arts\The Sims 4\Mods' + + :return: The file path to 'Documents\Electronic Arts\The Sims 4\Mods' folder. + :rtype: str + """ + current_file_path = os.path.dirname(os.path.abspath(__file__)) + mods_folder = os.path.join(current_file_path.partition(f"{os.sep}Mods{os.sep}")[0], 'Mods') + return mods_folder + + @staticmethod + def get_mod_logs_location_path() -> str: + """get_mod_logs_location_path() + + Retrieve the full path of the folder 'Documents\Electronic Arts\The Sims 4\mod_logs' + + :return: The file path to 'Documents\Electronic Arts\The Sims 4\mod_logs' folder. + :rtype: str + """ + sims_documents_location = CommonLogUtils.get_sims_documents_location_path() + if sims_documents_location == '': + return '' + return os.path.join(sims_documents_location, 'mod_logs') + + @staticmethod + def get_mod_data_location_path() -> str: + """get_mod_data_location_path() + + Retrieve the full path of the folder 'Documents\Electronic Arts\The Sims 4\Mods\mod_data' + + :return: The file path to 'Documents\Electronic Arts\The Sims 4\Mods\mod_data' folder. + :rtype: str + """ + mods_location = CommonLogUtils.get_mods_location_path() + if mods_location == '': + return '' + return os.path.join(mods_location, 'mod_data') + + @staticmethod + def _get_file_name(mod_identifier: Union[str, CommonModIdentity], file_name: str, custom_file_path: str=None) -> str: + from sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils + mod_identifier = CommonModIdentityUtils.determine_mod_name_from_identifier(mod_identifier) + file_path = CommonLogUtils.get_mod_logs_location_path() + file_name = '{}_{}.txt'.format(mod_identifier, file_name) + if not os.path.exists(file_path): + os.makedirs(file_path, exist_ok=True) + if custom_file_path is not None: + file_path = os.path.join(file_path, custom_file_path) + current_file = os.path.join(file_path, file_name) + try: + if os.path.exists(current_file) and CommonLogUtils._file_is_too_big(current_file): + new_file_name = file_name.replace('.txt', '') + old_file_name = None + for x in range(20): + old_file_name = 'Old_{}_{}.txt'.format(new_file_name, x) + if not os.path.exists(os.path.join(file_path, old_file_name)): + break + if old_file_name is None: + return current_file + old_file_path = os.path.join(file_path, old_file_name) + if os.path.exists(old_file_path): + os.remove(old_file_path) + os.rename(current_file, old_file_path) + except PermissionError: + pass + return current_file + + @staticmethod + def _get_old_file_path_name(mod_identifier: Union[str, CommonModIdentity], file_name: str, custom_file_path: str=None) -> str: + from sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils + mod_identifier = CommonModIdentityUtils.determine_mod_name_from_identifier(mod_identifier) + file_path = CommonLogUtils.get_mod_logs_location_path() + old_file_name = 'Old_{}_{}.txt'.format(mod_identifier, file_name) + if not os.path.exists(file_path): + os.makedirs(file_path, exist_ok=True) + if custom_file_path is not None: + file_path = os.path.join(file_path, custom_file_path) + return os.path.join(file_path, old_file_name) + + @staticmethod + def _file_is_too_big(file_path: str) -> bool: + from sims4communitylib.s4cl_configuration import S4CLConfiguration + return os.path.getsize(file_path) > S4CLConfiguration().max_output_file_size_in_bytes diff --git a/Scripts/s4ap/sims4communitylib/utils/common_math_utils.py b/Scripts/s4ap/sims4communitylib/utils/common_math_utils.py new file mode 100644 index 0000000..c7c91fb --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/common_math_utils.py @@ -0,0 +1,97 @@ +""" +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 +""" +import math +import sims4.math as sims_math + +from sims4communitylib.classes.math.common_vector3 import CommonVector3 + + +class CommonMathUtils: + """ Utilities for math operations. """ + + @staticmethod + def calculate_degrees_between_positions(position_one: CommonVector3, position_two: CommonVector3) -> float: + """calculate_degrees_between_positions(position_one, position_two) + + Calculate the degrees between two positions. + + :param position_one: An instance of a Vector. + :type position_one: CommonVector3 + :param position_two: An instance of a Vector. + :type position_two: CommonVector3 + :return: The degrees between the specified Vectors. + :rtype: float + """ + return CommonMathUtils.radian_to_degrees(math.atan2(position_two.x - position_one.x, position_two.z - position_one.z)) + + @staticmethod + def radian_to_degrees(radian: float) -> float: + """radian_to_degrees(radian) + + Translate Radian to Degrees. + + :param radian: The value to convert. + :type radian: float + :return: The value as Degrees. + :rtype: float + """ + return radian * 180.0 / math.pi + + @staticmethod + def degrees_to_radian(degrees: float) -> float: + """degrees_to_radian(degrees) + + Translate Degrees to Radian. + + :param degrees: The value to convert. + :type degrees: float + :return: The value as Radian. + :rtype: float + """ + return degrees * math.pi / 180.0 + + @staticmethod + def calculate_distance(position_one: CommonVector3, position_two: CommonVector3, flatten_positions: bool=True) -> float: + """calculate_distance(position_one, position_two, flatten_positions=True) + + Calculate the distance between two vectors. + + :param position_one: An instance of a Vector. + :type position_one: CommonVector3 + :param position_two: An instance of a Vector. + :type position_two: CommonVector3 + :param flatten_positions: If True, both Vectors will be flattened before calculations will occur. Default is True. + :type flatten_positions: bool, optional + :return: The distance between the two specified vectors. + :rtype: float + """ + if flatten_positions: + position_one = CommonVector3.flatten(position_one) + position_two = CommonVector3.flatten(position_one) + return CommonVector3.distance_between(position_one, position_two) + + @staticmethod + def calculate_offset_from_degrees(position: CommonVector3, degrees: float, length: float) -> CommonVector3: + """calculate_offset_from_degrees(position, degrees, length) + + Calculate an offset vector based on the forward axis from a vector. + + :param position: The original position. + :type position: CommonVector3 + :param degrees: Amount of degrees to offset. + :type degrees: float + :param length: The length of the offset. + :type length: float + :return: The vector offset. + :rtype: CommonVector3 + """ + offset_vector = sims_math.FORWARD_AXIS + # noinspection PyUnresolvedReferences + offset_vector = CommonQuaternion.from_degrees(degrees).transform_vector(offset_vector) + offset_vector = sims_math.vector_normalize(offset_vector) * length + return position + offset_vector diff --git a/Scripts/s4ap/sims4communitylib/utils/common_resource_utils.py b/Scripts/s4ap/sims4communitylib/utils/common_resource_utils.py new file mode 100644 index 0000000..792aee2 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/common_resource_utils.py @@ -0,0 +1,437 @@ +""" +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 +""" +import services +from io import BytesIO +from typing import ItemsView, Any, Union, Tuple, Type, ValuesView, Dict, TypeVar, List +try: + from sims4.resources import ResourceLoader, Types + from sims4.tuning.instance_manager import InstanceManager + from sims4.tuning.merged_tuning_manager import get_manager + from sims4.tuning.dynamic_enum import DynamicEnumLocked, DynamicEnum + # noinspection PyUnresolvedReferences + from sims4.tuning.serialization import ETreeTuningLoader + from sims4.tuning.tunable_base import LoadingTags +except: + # noinspection PyMissingOrEmptyDocstring + class Types: + pass + + # noinspection PyMissingOrEmptyDocstring + class ResourceLoader: + pass + + # noinspection PyMissingOrEmptyDocstring + class InstanceManager: + pass + + # noinspection PyMissingTypeHints,PyMissingOrEmptyDocstring + def get_manager(): + pass + + # noinspection PyMissingOrEmptyDocstring + class DynamicEnumLocked: + pass + + # noinspection PyMissingOrEmptyDocstring + class DynamicEnum: + pass + + # noinspection PyMissingOrEmptyDocstring + class ETreeTuningLoader: + pass + + # noinspection PyMissingOrEmptyDocstring + class LoadingTags: + pass + +from sims4communitylib.classes.common_resource_key import CommonResourceKey +from sims4communitylib.enums.enumtypes.common_int import Int, CommonInt +from sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags +from sims4communitylib.mod_support.mod_identity import CommonModIdentity + +CommonEnumTypeValueType = TypeVar('CommonEnumTypeValueType', int, CommonInt, CommonIntFlags, Int, DynamicEnum, DynamicEnumLocked) + +CommonExpectedReturnType = TypeVar('CommonExpectedReturnType', bound=Any) + + +class CommonResourceUtils: + """Utilities for retrieving the Tuning files and instances of various resources. (Objects, Snippets, Statistics, etc.). + + """ + + # noinspection PyUnusedLocal + @staticmethod + def load_instance(instance_type: Types, instance_id: int, return_type: Type[CommonExpectedReturnType] = Any) -> CommonExpectedReturnType: + """load_instance(instance_type, instance_id, return_type=Any) + + Load an instance of the specified type. + + :Example Usage 1: + + .. highlight:: python + .. code-block:: python + + # This will retrieve an instance for the Confident mood and will be of type statistics.mood.Mood + mood_instance = CommonResourceUtils.load_instance(Types.MOOD, CommonMoodId.CONFIDENT) + + :Example Usage 2: + + .. highlight:: python + .. code-block:: python + + # This will retrieve an instance for the Walk Style Angry buff and will be of type buffs.buff.Buff + buff_instance = CommonResourceUtils.load_instance(Types.BUFF, CommonBuffId.WALK_STYLE_ANGRY) + + :param instance_type: The type of instance being loaded. + :type instance_type: Types + :param instance_id: The decimal identifier of an instance. + :type instance_id: int + :param return_type: The type of the returned value. (This is to make type hinting more accurate). It is not actually used in the function. Default is Any. + :type return_type: Type[CommonExpectedReturnType], optional + :return: An instance of the specified type or None if no instance was found. + :rtype: Any + """ + instance_manager = CommonResourceUtils.get_instance_manager(instance_type) + return CommonResourceUtils.load_instance_from_manager(instance_manager, instance_id) + + # noinspection PyUnusedLocal + @staticmethod + def load_instance_from_manager(instance_manager: InstanceManager, instance_id: int, return_type: Type[CommonExpectedReturnType] = Any) -> CommonExpectedReturnType: + """load_instance_from_manager(instance_manager, instance_id, return_type=Any) + + Load an instance from the specified InstanceManager. + + :param instance_manager: The InstanceManager an instance will be loaded from. + :type instance_manager: InstanceManager + :param instance_id: The decimal identifier of an instance. + :type instance_id: int + :param return_type: The type of the returned value. (This is to make type hinting more accurate). It is not actually used in the function. Default is Any. + :type return_type: Type[CommonExpectedReturnType], optional + :return: An instance of the specified type or None if no instance was found. + :rtype: Any + """ + return instance_manager.get(instance_id) + + # noinspection PyUnusedLocal + @staticmethod + def load_all_instances(instance_type: Types, return_type: Type[CommonExpectedReturnType] = Any) -> ItemsView[str, CommonExpectedReturnType]: + """load_all_instances(instance_type, return_type=Any) + + Load all instances of the specified type. + + :param instance_type: The type of instances being loaded. + :type instance_type: Types + :param return_type: The type of the returned value. (This is to make type hinting more accurate). It is not actually used in the function. Default is Any. + :type return_type: Type[CommonExpectedReturnType], optional + :return: An items view of all instances of the specified type. (Resource Key, Instance) + :rtype: ItemsView[str, Any] + """ + return CommonResourceUtils.get_instance_manager(instance_type).types.items() + + # noinspection PyUnusedLocal + @staticmethod + def load_all_instances_as_guid_to_instance(instance_type: Types, return_type: Type[CommonExpectedReturnType] = Any) -> Dict[int, CommonExpectedReturnType]: + """load_all_instances_as_guid_to_instance(instance_type, return_type=Any) + + Load all instances of the specified type and convert it to a dictionary mapping of GUID to Instance. + + :param instance_type: The type of instances being loaded. + :type instance_type: Types + :param return_type: The type of the returned value. (This is to make type hinting more accurate). It is not actually used in the function. Default is Any. + :type return_type: Type[CommonExpectedReturnType], optional + :return: A dictionary of instance GUID to instances of the specified type. + :rtype: Dict[int, Any] + """ + return dict([(value_key.instance, value) for (value_key, value) in CommonResourceUtils.load_all_instances(instance_type)]) + + # noinspection PyUnusedLocal + @staticmethod + def load_all_instance_types(instance_type: Types, return_type: Type[CommonExpectedReturnType] = Any) -> Dict[str, CommonExpectedReturnType]: + """load_all_instance_types(instance_type, return_type=Any) + + Load all instances of the specified type. + + :param instance_type: The type of instances being loaded. + :type instance_type: Types + :param return_type: The type of the returned value. (This is to make type hinting more accurate). It is not actually used in the function. Default is Any. + :type return_type: Type[CommonExpectedReturnType], optional + :return: A dictionary of resource keys to Instances of the specified type. + :rtype: Dict[str, Any] + """ + return CommonResourceUtils.get_instance_manager(instance_type).types + + # noinspection PyUnusedLocal + @staticmethod + def load_all_instance_values(instance_type: Types, return_type: Type[CommonExpectedReturnType] = Any) -> ValuesView[CommonExpectedReturnType]: + """load_all_instance_values(instance_type, return_type=Any) + + Load all instance values of the specified type. + + :param instance_type: The type of instances being loaded. + :type instance_type: Types + :param return_type: The type of the returned value. (This is to make type hinting more accurate). It is not actually used in the function. Default is Any. + :type return_type: Type[CommonExpectedReturnType], optional + :return: All instance values of the specified type. + :rtype: ValuesView[Any] + """ + return CommonResourceUtils.get_instance_manager(instance_type).types.values() + + @staticmethod + def get_instance_manager(instance_manager_type: Types) -> Union[InstanceManager, None]: + """get_instance_manager(instance_manager_type) + + Get an InstanceManager for the specified type. + + :param instance_manager_type: The type of InstanceManager to get. + :type instance_manager_type: Types + :return: An InstanceManager for the specified type, or None if no InstanceManager is found. + :rtype: Union[InstanceManager, None] + """ + return services.get_instance_manager(instance_manager_type) + + @staticmethod + def get_resource_key(resource_type: Types, resource_key: Union[int, str]) -> CommonResourceKey: + """get_resource_key(resource_type, resource_key) + + Retrieve the resource key of a resource in the format: 00000000(Type):00000000(Group):00000000000000000(Instance Guid) + + .. note:: + + Possible Usages: + + - Retrieve the identifier of an Icon to display next to an Interaction in the Pie Menu. + - Retrieve the identifier of an Image for display in Dialogs or Notifications. + + :Example Usage: + + .. highlight:: python + .. code-block:: python + + # This will retrieve the key for the image with identifier 1234 + icon_resource_key = CommonResourceUtils.get_resource_key(Types.PNG, 1234) + + :param resource_type: The type of resource being loaded. + :type resource_type: Types + :param resource_key: The decimal identifier or string resource key of the resource. + :type resource_key: Union[int, str] + :return: The resource key of an instance or None if no instance was found. + :rtype: CommonResourceKey + """ + from sims4.resources import get_resource_key, ResourceKeyWrapper + key = get_resource_key(resource_key, resource_type) + if isinstance(key, str) and ':' in key: + # noinspection PyBroadException + try: + key = CommonResourceKey.from_resource_key(ResourceKeyWrapper(key)) + return key + except: + return key + result = CommonResourceKey.from_resource_key(key) + return result + + @staticmethod + def load_instances_with_any_tags(resource_type: Types, tags: Tuple[str], return_type: Type[CommonExpectedReturnType] = Any) -> Tuple[CommonExpectedReturnType]: + """load_instances_with_any_tags(resource_type, tags, return_type=Any) + + Retrieve all resources that contain the specified tag names within their tuning file. + + .. note:: + + Possible Usages: + + - Load all Snippet files containing properties with any of the specified tags. + + :param resource_type: The type of resource being loaded. + :type resource_type: Types + :param tags: A collection of tag names to locate within a tuning file. + :type tags: Tuple[str] + :param return_type: The type of the returned value. (This is to make type hinting more accurate). It is not actually used in the function. Default is Any. + :type return_type: Type[CommonExpectedReturnType], optional + :return: A collection of resources that contain any of the specified tags. + :rtype: Tuple[Any] + """ + instances: List[CommonExpectedReturnType] = [] + for (_, instance_class) in CommonResourceUtils.load_all_instances(resource_type, return_type=return_type): + for tag in tags: + if not hasattr(instance_class, tag): + continue + instances.append(instance_class) + break + return tuple(instances) + + @staticmethod + def get_enum_by_name(name: str, enum_type: Type[CommonEnumTypeValueType], default_value: CommonEnumTypeValueType = None) -> CommonEnumTypeValueType: + """get_enum_by_name(name, enum_type, default_value=None) + + Retrieve an enum value by its name. + + :param name: The name of the enum value to retrieve. + :type name: str + :param enum_type: The type of enum to retrieve. + :type enum_type: Any + :param default_value: The default value to return if an enum value was not found using the specified name. Default is None. + :type default_value: Any, optional + :return: The enum value with a name matching the specified name. + :rtype: Any + """ + if hasattr(enum_type, name): + return getattr(enum_type, name) + # noinspection PyBroadException + try: + # noinspection PyTypeChecker + if name in enum_type: + return enum_type[name] + except: + pass + if hasattr(enum_type, 'name_to_value') and name in enum_type.name_to_value: + return enum_type.name_to_value.get(name) + return default_value + + @staticmethod + def get_enum_by_int_value(value: int, enum_type: Type[CommonEnumTypeValueType], default_value: CommonEnumTypeValueType = None) -> CommonEnumTypeValueType: + """get_enum_by_int_value(value, enum_type, default_value=None) + + Retrieve an enum value by its value. + + :param value: The integer value of the enum value to retrieve. + :type value: int + :param enum_type: The type of enum to retrieve. + :type enum_type: Any + :param default_value: The default value to return if an enum value was not found using the specified name. Default is None. + :type default_value: Any, optional + :return: The enum value with a value matching the specified value or the default value if not found. + :rtype: Any + """ + if hasattr(enum_type, 'value_to_name') and value in enum_type.value_to_name: + return CommonResourceUtils.get_enum_by_name(enum_type.value_to_name[value], enum_type, default_value=default_value) + return default_value + + @staticmethod + def convert_str_to_fnv32(text: str, seed: int = 2166136261, high_bit: bool = True) -> int: + """convert_str_to_fnv32(text, seed=2166136261, high_bit=True) + + Convert a text string into an FNV32 decimal identifier. + + :param text: The text to convert. + :type text: str + :param seed: A seed to use when converting. Default value is 2166136261. + :type seed: int + :param high_bit: If True, the high FNV bit will be returned. If False, a low FNV bit will be returned. + :type high_bit: bool + :return: The text converted to a FNV32 decimal identifier. + :rtype: int + """ + fnv_hash = CommonResourceUtils._str_to_fnv(text, seed, 16777619, 4294967296) + if high_bit: + fnv_hash |= 2147483648 + return fnv_hash + + @staticmethod + def convert_str_to_fnv64(text: str, seed: int = 14695981039346656037, high_bit: bool = True) -> int: + """convert_str_to_fnv64(text, seed=14695981039346656037, high_bit=True) + + Convert a text string into an FNV64 decimal identifier. + + :param text: The text to convert. + :type text: str + :param seed: A seed to use when converting. Default value is 14695981039346656037. + :type seed: int + :param high_bit: If True, a high bit version of the FNV bit will be returned. If False, a low bit version of the FNV bit will be returned. + :type high_bit: bool + :return: The text converted to an FNV64 decimal identifier. + :rtype: int + """ + fnv_hash = CommonResourceUtils._str_to_fnv(text, seed, 1099511628211, 18446744073709551616) + if high_bit: + fnv_hash |= 9223372036854775808 + return fnv_hash + + @staticmethod + def register_tuning(mod_identity: CommonModIdentity, class_type: Type, tuning_type: Types, tuning_id: int, tuning_contents: str): + """register_tuning(mod_identity, class_type, tuning_type, tuning_identifier, tuning_contents) + + Dynamically register a tuning instance. + + :param mod_identity: The identity of the mod registering the tuning. + :type mod_identity: CommonModIdentity + :param class_type: The type of class being registered. + :type class_type: Type + :param tuning_type: The type of tuning being registered. + :type tuning_type: Types + :param tuning_id: The decimal identifier of the tuning being registered. + :type tuning_id: int + :param tuning_contents: The xml contents of the tuning. + :type tuning_contents: str + """ + from sims4.resources import TYPE_RES_DICT + tuning_instance_key = CommonResourceUtils.get_resource_key(tuning_type, tuning_id) + # noinspection PyArgumentList + tuning_loader = ETreeTuningLoader(class_type, '[{}] Dynamic Instance: {}'.format(mod_identity.name.replace(' ', '_'), class_type), loading_tag=LoadingTags.Instance) + # noinspection PyUnresolvedReferences + tuning_loader.feed(BytesIO(tuning_contents.encode('utf-8'))) + if tuning_instance_key.type in TYPE_RES_DICT: + res_ext = TYPE_RES_DICT[tuning_instance_key.type] + mtg = get_manager() + # noinspection PyUnresolvedReferences + mtg._tuning_resources[res_ext][tuning_instance_key.instance] = tuning_loader.root + else: + # noinspection PyUnresolvedReferences + cls = tuning_loader.module + tuning_manage = CommonResourceUtils.get_instance_manager(tuning_type) + tuning_manage.register_tuned_class(cls, tuning_instance_key) + + @staticmethod + def _str_to_fnv(text: str, seed: int, prime: int, size: int) -> int: + string_bytes = text.lower().encode(encoding='utf-8') + hash_value = seed + for byte in string_bytes: + hash_value = hash_value * prime % size + hash_value = hash_value ^ byte + return hash_value + + @staticmethod + def load_resource_bytes(resource_key: CommonResourceKey, silent_fail: bool = True) -> BytesIO: + """load_resource_bytes(resource_key, silent_fail=True) + + Retrieve the bytes of a resource. + + :param resource_key: The key of the resource. + :type resource_key: CommonResourceKey + :param silent_fail: Set to True to ignore errors if they occur. Set to False to throw errors when they occur. Default is True. + :type silent_fail: bool, optional + :return: An Input Output Byte reader/writer for the resource. + :rtype: BytesIO + """ + return ResourceLoader(resource_key).load(silent_fail=silent_fail) + + @staticmethod + def load_resource_bytes_by_name(resource_type: Types, resource_name: str, has_fnv64_identifier: bool = True, has_high_bit_identifier: bool = False) -> Union[BytesIO, None]: + """load_resource_bytes_by_name(resource_type, resource_name, fnv64=True, high_bit=False) + + Load the bytes of a resource into a Bytes Reader. + + .. note:: This function will only work if the instance key/decimal identifier of the resource equates to the name of the resource. + + :param resource_type: The type of resource being loaded. + :type resource_type: Types + :param resource_name: The tuning name of the resource. + :type resource_name: str + :param has_fnv64_identifier: Set to True to indicate the resource uses a 64 bit identifier. Set to False to indicate the resource uses a 32 bit identifier. Default is True. + :type has_fnv64_identifier: bool, optional + :param has_high_bit_identifier: Set to True to indicate the resource uses a high bit identifier. Set to False to indicate the resource uses a low bit identifier. Default is False. + :type has_high_bit_identifier: bool, optional + :return: An Input Output Byte reader/writer for the resource or None if a problem occurs. + :rtype: Union[BytesIO, None] + """ + conversion_func = CommonResourceUtils.convert_str_to_fnv32 + if has_fnv64_identifier: + conversion_func = CommonResourceUtils.convert_str_to_fnv64 + resource_key = CommonResourceUtils.get_resource_key(resource_type, conversion_func(resource_name, high_bit=has_high_bit_identifier)) + if resource_key is None: + return None + return CommonResourceUtils.load_resource_bytes(resource_key) diff --git a/Scripts/s4ap/sims4communitylib/utils/common_time_utils.py b/Scripts/s4ap/sims4communitylib/utils/common_time_utils.py new file mode 100644 index 0000000..27dd17f --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/common_time_utils.py @@ -0,0 +1,592 @@ +""" +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 +""" + +import clock +import services +from clock import ClockSpeedMode, GameClock, ClockSpeedMultiplierType +from date_and_time import DateAndTime, TimeSpan +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + CommonConsoleCommandArgument +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from time_service import TimeService + + +class CommonTimeUtils: + """Utilities for handling the in-game Time, also known as Sim Time. + + """ + @staticmethod + def pause_the_game() -> bool: + """pause_the_game() + + Pause the game. + + :return: True, if successful. False, if not. + :rtype: bool + """ + return CommonTimeUtils.set_clock_speed(ClockSpeedMode.PAUSED) + + @staticmethod + def game_is_paused() -> bool: + """game_is_paused() + + Determine if the game is paused. + + :return: True, if the game is paused. False, if not. + :rtype: bool + """ + return CommonTimeUtils.game_is_running_at_speed(ClockSpeedMode.PAUSED) + + @staticmethod + def game_is_running_at_speed(clock_speed: ClockSpeedMode) -> bool: + """game_is_running_at_speed(clock_speed) + + Determine if the game is running at the specified speed. + + :param clock_speed: The speed to change the game time to. + :type clock_speed: ClockSpeedMode + :return: True, if the game is running at the specified speed. False, if not. + :rtype: bool + """ + return CommonTimeUtils.get_clock_speed() == clock_speed + + @staticmethod + def set_game_speed_normal() -> bool: + """set_game_speed_normal() + + Change the speed of the game clock to Normal speed. + + :return: True, if successful. False, if not. + :rtype: bool + """ + return CommonTimeUtils.set_clock_speed(ClockSpeedMode.NORMAL) + + @staticmethod + def set_game_speed_to_speed_two() -> bool: + """set_game_speed_to_speed_two() + + Change the speed of the game clock to Speed Two. + + :return: True, if successful. False, if not. + :rtype: bool + """ + return CommonTimeUtils.set_clock_speed(ClockSpeedMode.SPEED2) + + @staticmethod + def set_game_speed_to_speed_three() -> bool: + """set_game_speed_to_speed_three() + + Change the speed of the game clock to Speed Three. + + :return: True, if successful. False, if not. + :rtype: bool + """ + return CommonTimeUtils.set_clock_speed(ClockSpeedMode.SPEED3) + + @staticmethod + def set_game_speed_to_interaction_startup_speed() -> bool: + """set_game_speed_to_interaction_startup_speed() + + Change the speed of the game clock to Interaction Startup Speed. + + :return: True, if successful. False, if not. + :rtype: bool + """ + return CommonTimeUtils.set_clock_speed(ClockSpeedMode.INTERACTION_STARTUP_SPEED) + + @staticmethod + def set_game_speed_to_super_speed_three() -> bool: + """set_game_speed_to_super_speed_three() + + Change the speed of the game clock to Super Speed Three. + + :return: True, if successful. False, if not. + :rtype: bool + """ + return CommonTimeUtils.set_clock_speed(ClockSpeedMode.SUPER_SPEED3) + + @staticmethod + def get_clock_speed() -> ClockSpeedMode: + """get_clock_speed() + + Retrieve the current clock speed. + + :return: The current speed of the game clock. + :rtype: ClockSpeedMode + """ + return CommonTimeUtils.get_game_clock().clock_speed + + @staticmethod + def get_clock_speed_scale() -> ClockSpeedMultiplierType: + """get_clock_speed_scale() + + Retrieve the current clock speed multiplier. + + :return: The current speed multiplier of the game clock. + :rtype: ClockSpeedMultiplierType + """ + return CommonTimeUtils.get_game_clock().current_clock_speed_scale() + + @staticmethod + def set_clock_speed(clock_speed: ClockSpeedMode) -> bool: + """set_clock_speed(clock_speed) + + Set the clock speed. + + :param clock_speed: The speed to set the game clock to. + :type clock_speed: ClockSpeedMode + :return: True, if successful. False, if not. + :rtype: bool + """ + return CommonTimeUtils.get_game_clock().set_clock_speed(clock_speed) + + @staticmethod + def set_current_time(hours: int, minutes: int, seconds: int): + """set_current_time(hours, minutes, seconds) + + Set the current time. + + :param hours: The hour of the day to set the time to. + :type hours: int + :param minutes: The minute of the hour to set the time to. + :type minutes: int + :param seconds: The second of the minute to set the time to. + :type seconds: int + """ + CommonTimeUtils.get_game_clock().set_game_time(hours, minutes, seconds) + + @staticmethod + def advance_current_time(hours: int = 0, minutes: int = 0, seconds: int = 0): + """advance_current_time(hours=0, minutes=0, seconds=0) + + Advance the current time by the specified amounts. + + :param hours: The number of hours to advance. + :type hours: int, optional + :param minutes: The number of minutes to advance. + :type minutes: int, optional + :param seconds: The number of seconds to advance. + :type seconds: int, optional + """ + CommonTimeUtils.get_game_clock().advance_game_time(hours=hours, minutes=minutes, seconds=seconds) + + @staticmethod + def get_current_date_and_time() -> DateAndTime: + """get_current_date_and_time() + + Retrieve the current date and time. + + :return: The current date and time. + :rtype: DateAndTime + """ + return services.time_service().sim_now + + @staticmethod + def get_current_second(date_and_time: DateAndTime = None) -> int: + """get_current_second(date_and_time) + + Retrieve the current Sim second of the minute. + + :param date_and_time: The date and time to retrieve the value from. If not specified, the current date and time will be used. Default is None. + :type date_and_time: DateAndTime, optional + :return: The current Sim second of the minute. + :rtype: int + """ + if date_and_time is None: + date_and_time = CommonTimeUtils.get_current_date_and_time() + return int(date_and_time.second()) + + @staticmethod + def get_current_minute(date_and_time: DateAndTime = None) -> int: + """get_current_minute(date_and_time) + + Retrieve the current Sim minute of the hour. + + :param date_and_time: The date and time to retrieve the value from. If not specified, the current date and time will be used. Default is None. + :type date_and_time: DateAndTime, optional + :return: The current Sim minute of the hour. + :rtype: int + """ + if date_and_time is None: + date_and_time = CommonTimeUtils.get_current_date_and_time() + return int(date_and_time.minute()) + + @staticmethod + def get_current_hour(date_and_time: DateAndTime = None) -> int: + """get_current_hour(date_and_time) + + Retrieve the current Sim hour of the day in military time. + + :param date_and_time: The date and time to retrieve the value from. If not specified, the current date and time will be used. Default is None. + :type date_and_time: DateAndTime, optional + :return: The current Sim hour of the day in military time. + :rtype: int + """ + if date_and_time is None: + date_and_time = CommonTimeUtils.get_current_date_and_time() + return int(date_and_time.hour()) + + @staticmethod + def get_current_day(date_and_time: DateAndTime = None) -> int: + """get_current_day(date_and_time) + + Retrieve the current Sim day of the month. + + :param date_and_time: The date and time to retrieve the value from. If not specified, the current date and time will be used. Default is None. + :type date_and_time: DateAndTime, optional + :return: The current Sim day of the month. + :rtype: int + """ + if date_and_time is None: + date_and_time = CommonTimeUtils.get_current_date_and_time() + return int(date_and_time.day()) + + @staticmethod + def get_current_week(date_and_time: DateAndTime = None) -> int: + """get_current_week(date_and_time) + + Retrieve the current Sim week of the month. + + :param date_and_time: The date and time to retrieve the value from. If not specified, the current date and time will be used. Default is None. + :type date_and_time: DateAndTime, optional + :return: The current Sim week of the month. + :rtype: int + """ + if date_and_time is None: + date_and_time = CommonTimeUtils.get_current_date_and_time() + return int(date_and_time.week()) + + @staticmethod + def get_total_ticks(date_and_time: DateAndTime = None) -> int: + """get_total_ticks(date_and_time) + + Retrieve the total Sim ticks since the start of the day. + + :param date_and_time: The date and time to retrieve the value from. If not specified, the current date and time will be used. Default is None. + :type date_and_time: DateAndTime, optional + :return: The total number of Sim ticks in milliseconds since the start of the day. + :rtype: int + """ + if date_and_time is None: + date_and_time = CommonTimeUtils.get_current_date_and_time() + return int(date_and_time.absolute_ticks()) + + @staticmethod + def get_total_seconds(date_and_time: DateAndTime = None) -> float: + """get_total_seconds(date_and_time) + + Retrieve the total Sim seconds since the start of the day. + + :param date_and_time: The date and time to retrieve the value from. If not specified, the current date and time will be used. Default is None. + :type date_and_time: DateAndTime, optional + :return: The total number of Sim seconds since the start of the day. + :rtype: int + """ + if date_and_time is None: + date_and_time = CommonTimeUtils.get_current_date_and_time() + return int(date_and_time.absolute_seconds()) + + @staticmethod + def get_total_minutes(date_and_time: DateAndTime = None) -> float: + """get_total_minutes(date_and_time) + + Retrieve the total Sim minutes since the start of the day. + + :param date_and_time: The date and time to retrieve the value from. If not specified, the current date and time will be used. Default is None. + :type date_and_time: DateAndTime, optional + :return: The total number of Sim minutes since the start of the day. + :rtype: int + """ + if date_and_time is None: + date_and_time = CommonTimeUtils.get_current_date_and_time() + return int(date_and_time.absolute_minutes()) + + @staticmethod + def get_total_hours(date_and_time: DateAndTime = None) -> float: + """get_total_hours(date_and_time) + + Retrieve the total Sim hours since the start of the day in military time. + + :param date_and_time: The date and time to retrieve the value from. If not specified, the current date and time will be used. Default is None. + :type date_and_time: DateAndTime, optional + :return: The total number of Sim hours since the start of the day in military time. + :rtype: int + """ + if date_and_time is None: + date_and_time = CommonTimeUtils.get_current_date_and_time() + return int(date_and_time.absolute_hours()) + + @staticmethod + def get_total_days(date_and_time: DateAndTime = None) -> float: + """get_total_days(date_and_time) + + Retrieve the total Sim days since the start of the season. + + :param date_and_time: The date and time to retrieve the value from. If not specified, the current date and time will be used. Default is None. + :type date_and_time: DateAndTime, optional + :return: The total number of Sim days since the start of the season. + :rtype: int + """ + if date_and_time is None: + date_and_time = CommonTimeUtils.get_current_date_and_time() + return int(date_and_time.absolute_days()) + + @staticmethod + def get_total_weeks(date_and_time: DateAndTime = None) -> float: + """get_total_weeks(date_and_time) + + Retrieve the total Sim weeks since the start of the season. + + :param date_and_time: The date and time to retrieve the value from. If not specified, the current date and time will be used. Default is None. + :type date_and_time: DateAndTime, optional + :return: The total number of Sim weeks since the start of the season. + :rtype: int + """ + if date_and_time is None: + date_and_time = CommonTimeUtils.get_current_date_and_time() + return int(date_and_time.absolute_weeks()) + + @staticmethod + def get_day_of_week(date_and_time: DateAndTime = None) -> int: + """get_day_of_week(date_and_time) + + Retrieve the current day of the week. + + :param date_and_time: The date and time to retrieve the value from. If not specified, the current date and time will be used. Default is None. + :type date_and_time: DateAndTime, optional + :return: The current day of the week. 0-6 + :rtype: int + """ + if date_and_time is None: + date_and_time = CommonTimeUtils.get_current_date_and_time() + return int(date_and_time.day()) + + @staticmethod + def create_interval_from_sim_seconds(seconds: int) -> TimeSpan: + """create_interval_from_sim_seconds(seconds) + + Create a time span interval that spans from the current Sim time to a number of Sim seconds in the future. + + :param seconds: A number of Sim seconds in the future the time span will indicate. + :type seconds: int + :return: A time span that will occur a number of Sim seconds in the future. + :rtype: TimeSpan + """ + return clock.interval_in_sim_seconds(seconds) + + @staticmethod + def create_interval_from_sim_minutes(minutes: int) -> TimeSpan: + """create_interval_from_sim_minutes(minutes) + + Create a time span interval that spans from the current Sim time to a number of Sim minutes in the future. + + :param minutes: A number of Sim minutes in the future the time span will indicate. + :type minutes: int + :return: A time span that will occur a number of Sim minutes in the future. + :rtype: TimeSpan + """ + return clock.interval_in_sim_minutes(minutes) + + @staticmethod + def create_interval_from_sim_hours(hours: int) -> TimeSpan: + """create_interval_from_sim_hours(hours) + + Create a time span interval that spans from the current Sim time to a number of Sim hours in the future. + + :param hours: A number of Sim hours in the future the time span will indicate. + :type hours: int + :return: A time span that will occur a number of Sim hours in the future. + :rtype: TimeSpan + """ + return clock.interval_in_sim_hours(hours) + + @staticmethod + def interval_in_sim_days(days: int) -> TimeSpan: + """interval_in_sim_days(days) + + Create a time span interval that spans from the current Sim time to a number of Sim days in the future. + + :param days: A number of Sim days in the future the time span will indicate. + :type days: int + :return: A time span that will occur a number of Sim days in the future. + :rtype: TimeSpan + """ + return clock.interval_in_sim_days(days) + + @staticmethod + def interval_in_sim_weeks(weeks: int) -> TimeSpan: + """interval_in_sim_weeks(weeks) + + Create a time span interval that spans from the current Sim time to a number of Sim weeks in the future. + + :param weeks: A number of Sim weeks in the future the time span will indicate. + :type weeks: int + :return: A time span that will occur a number of Sim weeks in the future. + :rtype: TimeSpan + """ + return clock.interval_in_sim_weeks(weeks) + + @staticmethod + def create_time_span(minutes: int = 0, hours: int = 0, days: int = 0) -> TimeSpan: + """create_time_span(minutes=0, hours=0, days=0) + + Create a time span that spans from the current Sim time to a number of Sim minutes, hours, or days in the future. + + :param minutes: A number of Sim minutes in the future the time span will indicate. Default is 0 Sim minutes. + :type minutes: int, optional + :param hours: A number of Sim hours in the future the time span will indicate. Default is 0 Sim hours. + :type hours: int, optional + :param days: A number of Sim days in the future the time span will indicate. Default is 0 Sim days. + :type days: int, optional + :return: A time span that will occur a number of Sim minutes, hours, or days in the future. + :rtype: TimeSpan + """ + from date_and_time import create_time_span + return create_time_span(days=days, hours=hours, minutes=minutes) + + @staticmethod + def create_date_and_time(minutes: int = 0, hours: int = 0, days: int = 0) -> DateAndTime: + """create_date_and_time(minutes=0, hours=0, days=0) + + Create a date and time that takes place a number of Sim minutes, hours, or days in the future. + + :param minutes: A number of Sim minutes in the future the date and time will be set at. Default is 0 Sim minutes. + :type minutes: int, optional + :param hours: A number of Sim hours in the future the date and time will be set at. Default is 0 Sim hours. + :type hours: int, optional + :param days: A number of Sim days in the future the date and time will be set at. Default is 0 Sim days. + :type days: int, optional + :return: A date and time that will occur a number of Sim minutes, hours, or days in the future. + :rtype: DateAndTime + """ + from date_and_time import create_date_and_time + return create_date_and_time(days=days, hours=hours, minutes=minutes) + + @staticmethod + def convert_milliseconds_to_seconds(milliseconds: float) -> float: + """convert_milliseconds_to_seconds(milliseconds) + + Convert Milliseconds to Seconds. + + :param milliseconds: The value to convert. + :type milliseconds: float + :return: The converted value in seconds. + :rtype: float + """ + from date_and_time import MILLISECONDS_PER_SECOND + if MILLISECONDS_PER_SECOND <= 0: + return milliseconds/1000 + return milliseconds/MILLISECONDS_PER_SECOND + + @staticmethod + def convert_seconds_to_milliseconds(seconds: float) -> float: + """convert_seconds_to_milliseconds(milliseconds) + + Convert Seconds to Milliseconds. + + :param seconds: The value to convert. + :type seconds: float + :return: The converted value in milliseconds. + :rtype: float + """ + from date_and_time import MILLISECONDS_PER_SECOND + if MILLISECONDS_PER_SECOND <= 0: + return seconds * 1000 + return seconds * MILLISECONDS_PER_SECOND + + @staticmethod + def is_sun_out() -> bool: + """is_sun_out() + + Determine if the Sun is currently out. + + :return: True, if the sun is out. False, if not. + :rtype: bool + """ + return CommonTimeUtils.get_time_service().is_sun_out() + + @staticmethod + def is_day_time(date_and_time: DateAndTime = None) -> bool: + """is_day_time(date_and_time=None) + + Determine if it is currently Day Time. + + :param date_and_time: A date and time to check. If not specified, the current time will be used instead. Default is unspecified. + :type date_and_time: DateAndTime, optional + :return: True, if it is day time. False, if not. + :rtype: bool + """ + return CommonTimeUtils.get_time_service().is_day_time(time=date_and_time) + + @staticmethod + def is_night_time(date_and_time: DateAndTime = None) -> bool: + """is_night_time(date_and_time=None) + + Determine if it is currently Night Time. + + :param date_and_time: A date and time to check. If not specified, the current time will be used instead. Default is unspecified. + :type date_and_time: DateAndTime, optional + :return: True, if it is night time. False, if not. + :rtype: bool + """ + return not CommonTimeUtils.is_day_time(date_and_time=date_and_time) + + @staticmethod + def get_time_service() -> TimeService: + """get_time_service() + + Get an instance of the TimeService. + + :return: An instance of the Time Service. + :rtype: TimeService + """ + return services.time_service() + + @staticmethod + def get_game_clock() -> GameClock: + """get_game_clock() + + Get an instance of the GameClock. + + :return: An instance of the game clock. + :rtype: GameClock + """ + return services.game_clock_service() + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.pause_game', + 'Pause the game.' +) +def _s4clib_pause_game(output: CommonConsoleCommandOutput): + output('Attempting to pause the game.') + CommonTimeUtils.pause_the_game() + output('Game paused successfully.') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.advance_time', + 'Advance the time in-game.', + command_arguments=( + CommonConsoleCommandArgument('seconds', 'Positive Number', 'The number of seconds to advance time by. Default is 0.', is_optional=True, default_value=0), + CommonConsoleCommandArgument('minutes', 'Positive Number', 'The number of minutes to advance time by. Default is 0.', is_optional=True, default_value=0), + CommonConsoleCommandArgument('hours', 'Positive Number', 'The number of hours to advance time by. Default is 0.', is_optional=True, default_value=0), + ) +) +def _s4clib_advance_time( + output: CommonConsoleCommandOutput, + seconds: int = 0, + minutes: int = 0, + hours: int = 0 +): + output(f'Attempting to advance time by {hours}h {minutes}m {seconds}s') + CommonTimeUtils.advance_current_time(hours=hours, minutes=minutes, seconds=seconds) + output('Finished advancing time.') diff --git a/Scripts/s4ap/sims4communitylib/utils/common_type_utils.py b/Scripts/s4ap/sims4communitylib/utils/common_type_utils.py new file mode 100644 index 0000000..d0e3427 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/common_type_utils.py @@ -0,0 +1,271 @@ +""" +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 +""" +from typing import Any +from sims.sim import Sim +from sims.sim_info import SimInfo +from sims.sim_info_base_wrapper import SimInfoBaseWrapper +from sims4.math import Location +from objects.game_object import GameObject +from objects.script_object import ScriptObject + + +class CommonTypeUtils: + """Utilities for determining the type of an object. + + """ + @staticmethod + def is_sim_or_sim_info(obj: Any) -> bool: + """is_sim_or_sim_info(obj) + + Determine if an object is either of type Sim or type SimInfo + + :param obj: The object to check. + :type obj: Any + :return: True, if it is. False, if it is not. + :rtype: bool + """ + return CommonTypeUtils.is_sim_instance(obj) or CommonTypeUtils.is_sim_info(obj) + + @staticmethod + def is_sim_instance(obj: Any) -> bool: + """is_sim_instance(obj) + + Determine if an object is of type Sim + + :param obj: The object to check. + :type obj: Any + :return: True, if it is. False, if it is not. + :rtype: bool + """ + return isinstance(obj, Sim) + + @staticmethod + def is_sim_info(obj: Any) -> bool: + """is_sim_info(obj) + + Determine if an object is of type SimInfo + + :param obj: The object to check. + :type obj: Any + :return: True, if it is. False, if it is not. + :rtype: bool + """ + return isinstance(obj, SimInfo) + + @staticmethod + def is_sim_info_base_wrapper(obj: Any) -> bool: + """is_sim_info_base_wrapper(obj) + + Determine if an object is of type SimInfo + + :param obj: The object to check. + :type obj: Any + :return: True, if it is. False, if it is not. + :rtype: bool + """ + return isinstance(obj, SimInfoBaseWrapper) + + @staticmethod + def is_script_object(obj: Any) -> bool: + """is_script_object(obj) + + Determine if an object is of type ScriptObject + + .. note:: GameObjects, Terrain, and Sims are all ScriptObjects. Try also :func:`~is_game_object`, :func:`~is_terrain`, and :func:`~is_sim_instance` + + :param obj: The object to check. + :type obj: Any + :return: True, if it is. False, if it is not. + :rtype: bool + """ + return isinstance(obj, ScriptObject) + + @staticmethod + def is_game_object(obj: Any) -> bool: + """is_game_object(obj) + + Determine if an object is of type GameObject + + :param obj: The object to check. + :type obj: Any + :return: True, if it is. False, if it is not. + :rtype: bool + """ + return isinstance(obj, GameObject) + + @staticmethod + def is_terrain(obj: Any) -> bool: + """is_terrain(obj) + + Determine if an object is of type Terrain + + :param obj: The object to check. + :type obj: Any + :return: True, if it is. False, if it is not. + :rtype: bool + """ + from objects.terrain import Terrain + return isinstance(obj, Terrain) + + @staticmethod + def is_land(obj: Any) -> bool: + """is_land(obj) + + Determine if an object is of type Terrain or TerrainPoint. + + :param obj: The object to check. + :type obj: Any + :return: True, if it is. False, if it is not. + :rtype: bool + """ + return CommonTypeUtils.is_terrain(obj) or CommonTypeUtils.is_terrain_point(obj) + + @staticmethod + def is_water(obj: Any) -> bool: + """is_water(obj) + + Determine if an object is of type Ocean, OceanPoint, SwimmingPool, or PoolPoint. + + :param obj: The object to check. + :type obj: Any + :return: True, if it is. False, if it is not. + :rtype: bool + """ + return CommonTypeUtils.is_ocean(obj) or CommonTypeUtils.is_ocean_point(obj) or CommonTypeUtils.is_swimming_pool(obj) or CommonTypeUtils.is_pool_point(obj) + + @staticmethod + def is_ocean(obj: Any) -> bool: + """is_ocean(obj) + + Determine if an object is of type Ocean. + + :param obj: The object to check. + :type obj: Any + :return: True, if it is. False, if it is not. + :rtype: bool + """ + try: + from objects.pools.ocean import Ocean + except ModuleNotFoundError: + return False + return isinstance(obj, Ocean) + + @staticmethod + def is_swimming_pool(obj: Any) -> bool: + """is_swimming_pool(obj) + + Determine if an object is of type SwimmingPool. + + :param obj: The object to check. + :type obj: Any + :return: True, if it is. False, if it is not. + :rtype: bool + """ + from sims4communitylib.utils.objects.common_object_type_utils import CommonObjectTypeUtils + return CommonObjectTypeUtils.is_swimming_pool(obj) + + @staticmethod + def is_door(obj: Any) -> bool: + """is_door(obj) + + Determine if an Object is of type Door + + :param obj: The object to check. + :type obj: Any + :return: True, if it is. False, if it is not. + :rtype: bool + """ + from sims4communitylib.utils.objects.common_object_type_utils import CommonObjectTypeUtils + return CommonObjectTypeUtils.is_door(obj) + + @staticmethod + def is_location(obj: Any) -> bool: + """is_location(obj) + + Determine if an object is of type Location. + + :param obj: The object to check. + :type obj: Any + :return: True, if it is. False, if it is not. + :rtype: bool + """ + from sims4communitylib.classes.math.common_location import CommonLocation + return isinstance(obj, Location) or isinstance(obj, CommonLocation) + + @staticmethod + def is_location_point(obj: Any) -> bool: + """is_location_point(obj) + + Determine if an object is of type _LocationPoint. + + :param obj: The object to check. + :type obj: Any + :return: True, if it is. False, if it is not. + :rtype: bool + """ + from objects.terrain import _LocationPoint + return isinstance(obj, _LocationPoint) + + @staticmethod + def is_terrain_point(obj: Any) -> bool: + """is_terrain_point(obj) + + Determine if an object is of type TerrainPoint. + + :param obj: The object to check. + :type obj: Any + :return: True, if it is. False, if it is not. + :rtype: bool + """ + from objects.terrain import TerrainPoint + return isinstance(obj, TerrainPoint) + + @staticmethod + def is_ocean_point(obj: Any) -> bool: + """is_ocean_point(obj) + + Determine if an object is of type OceanPoint. + + :param obj: The object to check. + :type obj: Any + :return: True, if it is. False, if it is not. + :rtype: bool + """ + try: + from objects.terrain import OceanPoint + except ModuleNotFoundError: + return False + return isinstance(obj, OceanPoint) + + @staticmethod + def is_pool_point(obj: Any) -> bool: + """is_pool_point(obj) + + Determine if an object is of type PoolPoint. + + :param obj: The object to check. + :type obj: Any + :return: True, if it is. False, if it is not. + :rtype: bool + """ + from objects.terrain import PoolPoint + return isinstance(obj, PoolPoint) + + @staticmethod + def is_pool_seat(obj: Any) -> bool: + """is_pool_seat(obj) + + Determine if an Object is a Pool Seat. + + :param obj: An instance of an Object. + :type: Any + :return: True, if the Object is a Pool Seat. False, if not. + :rtype: bool + """ + from sims4communitylib.utils.objects.common_object_type_utils import CommonObjectTypeUtils + return CommonObjectTypeUtils.is_swimming_pool_seat(obj) diff --git a/Scripts/s4ap/sims4communitylib/utils/common_weather_utils.py b/Scripts/s4ap/sims4communitylib/utils/common_weather_utils.py new file mode 100644 index 0000000..5baf403 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/common_weather_utils.py @@ -0,0 +1,308 @@ +""" +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 +""" +from typing import Iterator, Union + +from objects.game_object import GameObject +from server_commands.argument_helpers import TunableInstanceParam +from sims.sim_info import SimInfo +from sims4.resources import Types +from sims4communitylib.enums.common_cloud_type import CommonCloudType +from sims4communitylib.enums.common_temperature import CommonTemperature +from sims4communitylib.enums.common_weather_effect_type import CommonWeatherEffectType +from sims4communitylib.enums.common_weather_event_ids import CommonWeatherEventId +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + CommonConsoleCommandArgument +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.common_time_utils import CommonTimeUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from weather.weather_enums import PrecipitationType, WeatherEffectType +from weather.weather_event import WeatherEvent +from weather.weather_service import WeatherService + + +class CommonWeatherUtils: + """Utilities for manipulating the weather. + + """ + + @classmethod + def weather_effect_is_active(cls, weather_effect_type: CommonWeatherEffectType) -> bool: + """weather_effect_is_active(weather_effect_type) + + Determine if the specified weather effect is currently active. + + :param weather_effect_type: The weather effect to check for. + :type weather_effect_type: CommonWeatherEffectType + :return: True, if the weather is active. False, if it is not. + :rtype: bool + """ + return cls.weather_effects_are_active((weather_effect_type,)) + + @classmethod + def weather_effects_are_active(cls, weather_effect_types: Iterator[CommonWeatherEffectType]) -> bool: + """weather_effects_are_active(weather_effect_types) + + Determine if any of the specified weather effects are currently active. + + :param weather_effect_types: An iterator of weather effects to check for. + :type weather_effect_types: Iterator[CommonWeatherEffectType] + :return: True, if any of the weathers is active. False, if none of the weathers are active. + :rtype: bool + """ + weather_service: WeatherService = cls.get_weather_service() + if weather_service is None: + return False + for weather_effect_type in weather_effect_types: + if not bool(weather_service.get_weather_element_value(weather_effect_type, default=0.0)): + continue + return True + return False + + @classmethod + def current_temperature_is_cold_or_freezing(cls) -> bool: + """current_temperature_is_cold_or_freezing() + + Determine if the current temperature is cold or freezing. + + :return: True, if the current temperature contains cold or freezing. False, if not. + :rtype: bool + """ + current_temperature = cls.get_current_temperature() + return current_temperature == CommonTemperature.COLD or current_temperature == CommonTemperature.FREEZING + + @classmethod + def current_weather_contains_thunder_or_lightning(cls) -> bool: + """current_weather_contains_thunder_or_lightning() + + Determine if the current weather contains lightning or thunder. + + :return: True, if the current weather contains thunder or lightning. False, if not. + :rtype: bool + """ + return cls.weather_effects_are_active((CommonWeatherEffectType.LIGHTNING, CommonWeatherEffectType.THUNDER)) + + @classmethod + def get_current_temperature(cls) -> CommonTemperature: + """get_current_temperature() + + Retrieve the current temperature. + + :return: The current temperature. + :rtype: CommonTemperature + """ + weather_service = cls.get_weather_service() + if weather_service is not None: + return CommonTemperature.convert_from_vanilla(weather_service.get_weather_element_value(CommonWeatherEffectType.TEMPERATURE, default=CommonTemperature.WARM)) + return CommonTemperature.WARM + + @classmethod + def get_current_wind_speed(cls) -> int: + """get_current_wind_speed() + + Retrieve the current wind speed. + + :return: The current speed of the wind. + :rtype: int + """ + weather_service = cls.get_weather_service() + if weather_service is None: + return 0 + return weather_service.get_weather_element_value(WeatherEffectType.WIND, time=CommonTimeUtils.get_current_date_and_time()) + + @classmethod + def get_current_precipitation_level(cls, precipitation_type: PrecipitationType) -> int: + """get_current_precipitation_level(precipitation_type) + + Retrieve the current precipitation level. + + :param precipitation_type: The type of precipitation to get. + :type precipitation_type: PrecipitationType + :return: The current precipitation level. + :rtype: int + """ + weather_service = cls.get_weather_service() + if weather_service is None: + return 0 + return weather_service.get_weather_element_value(precipitation_type, time=CommonTimeUtils.get_current_date_and_time()) + + @classmethod + def get_current_lightning_level(cls) -> int: + """get_current_lightning_level() + + Retrieve the current lightning level. + + :return: The current lightning level. + :rtype: int + """ + weather_service = cls.get_weather_service() + if weather_service is None: + return 0 + return weather_service.get_weather_element_value(WeatherEffectType.LIGHTNING, time=CommonTimeUtils.get_current_date_and_time()) + + @classmethod + def get_weather_cloud_type(cls) -> CommonCloudType: + """get_weather_cloud_type() + + Retrieve the current cloud type. + + :return: The current cloud type or CLEAR if weather is not available. + :rtype: CommonCloudType + """ + weather_service = cls.get_weather_service() + if weather_service is None: + return CommonCloudType.CLEAR + for cloud_type in CommonCloudType.get_all(): + vanilla_cloud_type = CommonCloudType.convert_to_vanilla(cloud_type) + if not weather_service.get_weather_element_value(vanilla_cloud_type, default=0.0): + continue + return cloud_type + return CommonCloudType.CLEAR + + @classmethod + def start_weather_event(cls, weather_event: Union[int, CommonWeatherEventId, WeatherEvent], duration_in_hours: int) -> None: + """start_weather_event(weather_event, duration_in_hours) + + Start a weather event. Essentially changing the current weather. + + :param weather_event: The identifier of the weather event to start. + :type weather_event: Union[int, CommonWeatherEventId, WeatherEvent] + :param duration_in_hours: The number of Sim hours to run the weather event for. + :type duration_in_hours: int + """ + weather_service = cls.get_weather_service() + if weather_service is None: + return + weather_event = cls.load_weather_event_by_id(weather_event) + weather_service.start_weather_event(weather_event, duration_in_hours) + + @classmethod + def get_weather_service(cls) -> Union[WeatherService, None]: + """get_weather_service() + + Retrieve the service that handles the weather. + + :return: An instance of the service for handling weather or None if there is no weather service. + :rtype: Union[WeatherService, None] + """ + import services + if not hasattr(services, 'weather_service'): + return None + return services.weather_service() + + @classmethod + def load_weather_event_by_id(cls, weather_event: Union[int, CommonWeatherEventId, WeatherEvent]) -> Union[WeatherEvent, None]: + """load_weather_event_by_id(weather_event) + + Load an instance of a Weather Event by its identifier. + + :param weather_event: The identifier of a Weather Event. + :type weather_event: Union[int, CommonWeatherEventId, WeatherEvent] + :return: An instance of a WeatherEvent matching the decimal identifier or None if not found. + :rtype: Union[WeatherEvent, None] + """ + if isinstance(weather_event, WeatherEvent): + return weather_event + # noinspection PyBroadException + try: + weather_event: int = int(weather_event) + except: + # noinspection PyTypeChecker + weather_event: WeatherEvent = weather_event + return weather_event + + from sims4.resources import Types + from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + return CommonResourceUtils.load_instance(Types.WEATHER_EVENT, weather_event) + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.clear_weather', + 'Change the weather to clear, with sunny skies!', + command_arguments=( + CommonConsoleCommandArgument('duration_in_hours', 'Number', 'The number of Sim hours the weather should last.', is_optional=True, default_value='6 Hours'), + ) +) +def _common_set_weather(output: CommonConsoleCommandOutput, duration_in_hours: int=6): + output(f'Changing the weather to clear') + CommonWeatherUtils.start_weather_event(CommonWeatherEventId.CLEAR, duration_in_hours) + return True + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.change_weather', + 'Set the weather', + command_arguments=( + CommonConsoleCommandArgument('weather', 'Weather Id or Tuning Name', 'The decimal identifier or Tuning Name of the Weather to add.'), + CommonConsoleCommandArgument('duration_in_hours', 'Number', 'The number of Sim hours the weather should last.', is_optional=True, default_value='6 Hours'), + ) +) +def _common_set_weather(output: CommonConsoleCommandOutput, weather: TunableInstanceParam(Types.WEATHER_EVENT), duration_in_hours: int=6): + if not weather or isinstance(weather, int) or isinstance(weather, float) or isinstance(weather, str): + output(f'Weather \'{weather}\' was not found.') + return False + output(f'Changing the weather to {weather}') + CommonWeatherUtils.start_weather_event(weather, duration_in_hours) + return True + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.smite_sim', + 'A Sim will be struck by the power of Zeus.', + command_aliases=( + 's4clib.smite_me', + ), + command_arguments=( + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance id or name of a Sim to smite.', is_optional=True, default_value='Active Sim'), + ) +) +def _common_smite_sim(output: CommonConsoleCommandOutput, sim_info: SimInfo=None): + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + output(f'Sim was not found nearby. {sim_info}') + return + output(f'Smiting Sim {sim_info} with the power of Zeus.') + from weather.lightning import LightningStrike + LightningStrike.strike_sim(sim_to_strike=sim) + return True + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.smite_object', + 'An object will be struck by the power of Zeus.', + command_aliases=( + 's4clib.smite_it', + ), + command_arguments=( + CommonConsoleCommandArgument('game_object', 'Object Id or Name', 'The instance id or name of an Object to smite.'), + ) +) +def _common_smite_object(output: CommonConsoleCommandOutput, game_object: GameObject): + output(f'Smiting Object {game_object} with the power of Zeus.') + from weather.lightning import LightningStrike + LightningStrike.strike_object(obj_to_strike=game_object) + return True + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.angry_zeus', + 'Zeus be Angry.' +) +def _common_smite_object(output: CommonConsoleCommandOutput, zeus_fury_count: int=100): + output(f'Zeus be angry, I hope your Sims are indoors!') + from weather.lightning import LightningStrike + count = 0 + while count <= zeus_fury_count: + LightningStrike.perform_active_lightning_strike() + count += 1 + return True diff --git a/Scripts/s4ap/sims4communitylib/utils/effects/__init__.py b/Scripts/s4ap/sims4communitylib/utils/effects/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/effects/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/utils/effects/common_visual_effect_commands.py b/Scripts/s4ap/sims4communitylib/utils/effects/common_visual_effect_commands.py new file mode 100644 index 0000000..a4d048a --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/effects/common_visual_effect_commands.py @@ -0,0 +1,192 @@ +""" +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 +""" +from typing import Dict, List + +import clock +from date_and_time import TimeSpan +from objects.game_object import GameObject +from sims.sim_info import SimInfo +from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry +from sims4communitylib.events.zone_spin.events.zone_teardown import S4CLZoneTeardownEvent +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommandArgument, \ + CommonConsoleCommand +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.services.common_service import CommonService +from sims4communitylib.classes.effects.common_visual_effect import CommonVisualEffect +from sims4communitylib.utils.common_type_utils import CommonTypeUtils +from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + + +class _CommonVisualEffectCommandService(CommonService): + def __init__(self) -> None: + super().__init__() + self._running_effects_list: Dict[int, List[CommonVisualEffect]] = dict() + + # noinspection PyMissingOrEmptyDocstring + def play_visual_effect( + self, + target: GameObject, + effect_name: str, + joint_bone_name: str = 'b__Head__', + time_span: TimeSpan = None, + target_joint_bone_name: str = None, + **kwargs + ): + effect = CommonVisualEffect( + ModInfo.get_identity(), + target, + effect_name, + joint_bone_name=joint_bone_name, + target_joint_bone_name=target_joint_bone_name, + **kwargs + ) + + if CommonTypeUtils.is_sim_or_sim_info(target): + # noinspection PyTypeChecker + object_id = CommonSimUtils.get_sim_id(target) + else: + object_id = CommonObjectUtils.get_object_id(target) + + def _on_end(_effect: CommonVisualEffect): + if object_id in self._running_effects_list and _effect in self._running_effects_list[object_id]: + self._running_effects_list[object_id].remove(_effect) + + effect.start(time_span=time_span, on_end=_on_end) + if object_id not in self._running_effects_list: + self._running_effects_list[object_id] = list() + self._running_effects_list[object_id].append(effect) + + # noinspection PyMissingOrEmptyDocstring + def stop_all_visual_effects(self, target: GameObject = None) -> None: + if target is None: + for (object_id, effects) in tuple(self._running_effects_list.items()): + for effect in effects: + effect.stop() + self._running_effects_list[object_id].remove(effect) + else: + if CommonTypeUtils.is_sim_or_sim_info(target): + # noinspection PyTypeChecker + object_id = CommonSimUtils.get_sim_id(target) + else: + object_id = CommonObjectUtils.get_object_id(target) + + if object_id not in self._running_effects_list: + return + + for effect in tuple(self._running_effects_list[object_id]): + effect.stop() + self._running_effects_list[object_id].remove(effect) + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.play_visual_effect', + 'Play a VFX on a Sim. Run `s4clib.stop_all_visual_effects` to stop the visual effect.', + command_arguments=( + CommonConsoleCommandArgument('effect_name', 'Text', 'The name of an effect to play.'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Id or Name of a Sim to attach the VFX to.', is_optional=True, default_value='Active Sim'), + CommonConsoleCommandArgument('sim_minutes_until_end', 'Number', 'The number of Sim Minutes to play the effect for before it auto stops.', is_optional=True, default_value='Effect default length'), + CommonConsoleCommandArgument('joint_bone_name', 'Text', 'The name of the bone or joint to attach the effect to on the source object.', is_optional=True, default_value='b__Head__'), + CommonConsoleCommandArgument('target_joint_bone_name', 'Text', 'The name of the bone or joint to attach the effect to on the target object.', is_optional=True, default_value=None), + ) +) +def _common_play_visual_effect( + output: CommonConsoleCommandOutput, + effect_name: str, + sim_info: SimInfo = None, + sim_minutes_until_end: int = None, + joint_bone_name: str = 'b__Head__', + target_joint_bone_name: str = None +): + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + output(f'FAILED: Sim {sim_info} was not found nearby.') + return False + output(f'Running VFX {effect_name} on Sim {sim_info}') + + time_span = None + if sim_minutes_until_end is not None: + time_span = clock.interval_in_sim_minutes(sim_minutes_until_end) + _CommonVisualEffectCommandService().play_visual_effect(sim, effect_name, joint_bone_name=joint_bone_name, target_joint_bone_name=target_joint_bone_name, time_span=time_span) + output(f'Started effect {effect_name} on Sim {sim_info}') + return True + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.play_visual_effect_object', + 'Play a VFX on an Object. Run `s4clib.stop_all_visual_effects` to stop the visual effect.', + command_arguments=( + CommonConsoleCommandArgument('effect_name', 'Text', 'The name of an effect to play.'), + CommonConsoleCommandArgument('game_object', 'Instance Id of Object', 'The instance id of an Object to attach the VFX to.'), + CommonConsoleCommandArgument('sim_minutes_until_end', 'Number', 'The number of Sim Minutes to play the effect for before it auto stops.', is_optional=True, default_value='Effect default length'), + CommonConsoleCommandArgument('joint_bone_name', 'Text', 'The name of the bone or joint to attach the effect to on the source object.', is_optional=True, default_value='b__Head__'), + CommonConsoleCommandArgument('target_joint_bone_name', 'Text', 'The name of the bone or joint to attach the effect to on the target object.', is_optional=True, default_value=None), + ) +) +def _common_play_visual_effect( + output: CommonConsoleCommandOutput, + effect_name: str, + game_object: GameObject, + sim_minutes_until_end: int = None, + joint_bone_name: str = 'b__Root__', + target_joint_bone_name: str = None +): + output(f'Running VFX {effect_name} on Game Object {game_object}') + + time_span = None + if sim_minutes_until_end is not None: + time_span = clock.interval_in_sim_minutes(sim_minutes_until_end) + _CommonVisualEffectCommandService().play_visual_effect(game_object, effect_name, joint_bone_name=joint_bone_name, target_joint_bone_name=target_joint_bone_name, time_span=time_span) + output(f'Started effect {effect_name} on Game Object {game_object}') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.stop_visual_effects_sim', + 'Stop all running effects that were started via `s4clib.play_visual_effect` on a Sim.', + command_arguments=( + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Id or Name of a Sim to attach the VFX to.', is_optional=True, default_value='Active Sim'), + ) +) +def _common_stop_debug_visual_effects_on_sim(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): + output(f'Stopping all debug added VFX on {sim_info}.') + _CommonVisualEffectCommandService().stop_all_visual_effects(target=sim_info) + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.stop_visual_effects_object', + 'Stop all running effects that were started via `s4clib.play_visual_effect` on a Game Object.', + command_arguments=( + CommonConsoleCommandArgument('game_object', 'Instance Id of Object', 'The instance id of an Object to attach the VFX to.'), + ) +) +def _common_stop_debug_visual_effects_on_object(output: CommonConsoleCommandOutput, game_object: GameObject): + if not isinstance(game_object, GameObject): + return False + output(f'Stopping all debug added VFX on {game_object}.') + _CommonVisualEffectCommandService().stop_all_visual_effects(target=game_object) + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.stop_all_visual_effects', + 'Stop all running effects that were started via `s4clib.play_visual_effect`.' +) +def _common_stop_all_debug_visual_effects(output: CommonConsoleCommandOutput): + output('Stopping all debug added VFX.') + _CommonVisualEffectCommandService().stop_all_visual_effects() + + +# noinspection PyUnusedLocal +@CommonEventRegistry.handle_events(ModInfo.get_identity()) +def _common_stop_all_debug_visual_effects_on_zone_teardown(event_data: S4CLZoneTeardownEvent): + _CommonVisualEffectCommandService().stop_all_visual_effects() diff --git a/Scripts/s4ap/sims4communitylib/utils/environment/__init__.py b/Scripts/s4ap/sims4communitylib/utils/environment/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/environment/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/utils/environment/common_business_utils.py b/Scripts/s4ap/sims4communitylib/utils/environment/common_business_utils.py new file mode 100644 index 0000000..a4e77c9 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/environment/common_business_utils.py @@ -0,0 +1,80 @@ +""" +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 +""" +from typing import Union + +from business.business_funds import BusinessFunds +from business.business_manager import BusinessManager +from business.business_service import BusinessService + + +class CommonBusinessUtils: + """Utilities for manipulating Businesses.""" + @classmethod + def get_business_manager_for_current_zone(cls) -> BusinessManager: + """get_business_manager_for_current_zone() + + Retrieve a Business Manager for the current Zone. + + :return: A Business Manager for the current zone. + :rtype: BusinessManager + """ + from sims4communitylib.utils.location.common_location_utils import CommonLocationUtils + return cls.get_business_manager_by_zone_id(CommonLocationUtils.get_current_zone_id()) + + @classmethod + def get_business_manager_by_zone_id(cls, zone_id: int) -> BusinessManager: + """get_business_manager_by_zone_id(zone_id) + + Retrieve a Business Manager for a Zone. + + :param zone_id: The identifier of the Zone to retrieve a Business Manager from. + :type zone_id: int + :return: A Business Manager for the specified zone. + :rtype: BusinessManager + """ + return cls.get_business_service().get_business_manager_for_zone(zone_id=zone_id) + + @classmethod + def get_business_funds_for_current_zone(cls) -> Union[BusinessFunds, None]: + """get_business_funds_for_current_zone() + + Retrieve the Funds object that manages the Simoleons for the Business of the current Zone. + + :return: The BusinessFunds object of the Business at the current Zone or None if the current Zone did not have a Business. + :rtype: Union[BusinessFunds, None] + """ + from sims4communitylib.utils.location.common_location_utils import CommonLocationUtils + return cls.get_business_funds_by_zone_id(CommonLocationUtils.get_current_zone_id()) + + @classmethod + def get_business_funds_by_zone_id(cls, zone_id: int) -> Union[BusinessFunds, None]: + """get_business_funds_by_zone_id(zone_id) + + Retrieve the Funds object that manages the Simoleons for the Business of a Zone. + + :param zone_id: The identifier of the Zone to retrieve a Business from. Default is the current zone. + :type zone_id: int, optional + :return: The BusinessFunds object of the Business at the specified zone or None if the specified Zone did not have a Business. + :rtype: Union[BusinessFunds, None] + """ + business_manager = CommonBusinessUtils.get_business_manager_by_zone_id(zone_id) + if business_manager is None: + return + return business_manager.funds + + @classmethod + def get_business_service(cls) -> BusinessService: + """get_business_service() + + Retrieve an instance of the Business Service. + + :return: An instance of the Business Service. + :rtype: BusinessService + """ + import services + return services.business_service() diff --git a/Scripts/s4ap/sims4communitylib/utils/environment/common_civic_policy_utils.py b/Scripts/s4ap/sims4communitylib/utils/environment/common_civic_policy_utils.py new file mode 100644 index 0000000..d408b68 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/environment/common_civic_policy_utils.py @@ -0,0 +1,455 @@ +""" +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 +""" +from typing import Union, Tuple + +from civic_policies.base_civic_policy import BaseCivicPolicy +from civic_policies.street_civic_policy import StreetCivicPolicy +from civic_policies.street_civic_policy_provider import StreetProvider +from sims4communitylib.enums.common_civic_policy_status_type import CommonCivicPolicyStatusType +from sims4communitylib.enums.common_street_civic_policy_ids import CommonStreetCivicPolicyId +from sims4communitylib.enums.common_venue_civic_policy_ids import CommonVenueCivicPolicyId +from sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.location.common_location_utils import CommonLocationUtils +from venues.civic_policies.venue_civic_policy import VenueCivicPolicy +from venues.civic_policies.venue_civic_policy_provider import VenueCivicPolicyProvider + + +class CommonCivicPolicyUtils(_HasS4CLClassLog): + """Utilities for manipulating civic policies.""" + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 'common_civic_policy_utils' + + @classmethod + def is_free_love_enacted(cls) -> bool: + """is_free_love_enacted() + + Determine if the Free Love civic policy has been enacted in the current zone. + + :return: True, if the policy is enacted. False, if not. + :rtype: bool + """ + return cls.is_policy_enacted_in_current_zone(CommonStreetCivicPolicyId.SKILL_BASED_FREE_LOVE) + + @classmethod + def is_policy_enacted_in_zone(cls, zone_id: int, policy: Union[int, CommonVenueCivicPolicyId, CommonStreetCivicPolicyId, BaseCivicPolicy]) -> bool: + """is_policy_enacted_in_zone(zone_id, policy) + + Determine if a Policy is currently enacted in a Zone. + + :param zone_id: The identifier of the Zone to check. + :type zone_id: int + :param policy: The policy to look for. + :type policy: Union[int, CommonVenueCivicPolicyId, CommonStreetCivicPolicyId, BaseCivicPolicy] + :return: True, if the specified policy is currently enacted in a Zone. False, if not. + :rtype: bool + """ + return cls.is_policy_in_zone(zone_id, policy, CommonCivicPolicyStatusType.ENACTED) + + @classmethod + def is_policy_balloted_in_zone(cls, zone_id: int, policy: Union[int, CommonVenueCivicPolicyId, CommonStreetCivicPolicyId, BaseCivicPolicy]) -> bool: + """is_policy_balloted_in_zone(zone_id, policy) + + Determine if a Policy is currently balloted in a Zone. + + :param zone_id: The identifier of the Zone to check. + :type zone_id: int + :param policy: The policy to look for. + :type policy: Union[int, CommonVenueCivicPolicyId, CommonStreetCivicPolicyId, BaseCivicPolicy] + :return: True, if the specified policy is currently balloted in a Zone. False, if not. + :rtype: bool + """ + return cls.is_policy_in_zone(zone_id, policy, CommonCivicPolicyStatusType.BALLOTED) + + @classmethod + def is_policy_up_for_repeal_in_zone(cls, zone_id: int, policy: Union[int, CommonVenueCivicPolicyId, CommonStreetCivicPolicyId, BaseCivicPolicy]) -> bool: + """is_up_for_repeal_in_zone(zone_id, policy) + + Determine if a Policy is currently up for repeal in a Zone. + + :param zone_id: The identifier of the Zone to check. + :type zone_id: int + :param policy: The policy to look for. + :type policy: Union[int, CommonVenueCivicPolicyId, CommonStreetCivicPolicyId, BaseCivicPolicy] + :return: True, if the specified policy is currently up for repeal in a Zone. False, if not. + :rtype: bool + """ + return cls.is_policy_in_zone(zone_id, policy, CommonCivicPolicyStatusType.UP_FOR_REPEAL) + + @classmethod + def is_dormant_in_zone(cls, zone_id: int, policy: Union[int, CommonVenueCivicPolicyId, CommonStreetCivicPolicyId, BaseCivicPolicy]) -> bool: + """is_dormant_in_zone(zone_id, policy) + + Determine if a Policy is currently up for repeal in a Zone. + + :param zone_id: The identifier of the Zone to check. + :type zone_id: int + :param policy: The policy to look for. + :type policy: Union[int, CommonVenueCivicPolicyId, CommonStreetCivicPolicyId, BaseCivicPolicy] + :return: True, if the specified policy is currently up for repeal in a Zone. False, if not. + :rtype: bool + """ + return cls.is_policy_in_zone(zone_id, policy, CommonCivicPolicyStatusType.DORMANT) + + @classmethod + def is_policy_enacted_in_current_zone(cls, policy: Union[int, CommonVenueCivicPolicyId, CommonStreetCivicPolicyId, BaseCivicPolicy]) -> bool: + """is_policy_enacted_in_current_zone(policy) + + Determine if a Policy is currently enacted in the current Zone. + + :param policy: The policy to look for. + :type policy: Union[int, CommonVenueCivicPolicyId, CommonStreetCivicPolicyId, BaseCivicPolicy] + :return: True, if the specified policy is currently enacted in the current Zone. False, if not. + :rtype: bool + """ + return cls.is_policy_in_zone(CommonLocationUtils.get_current_zone_id(), policy, CommonCivicPolicyStatusType.ENACTED) + + @classmethod + def is_policy_balloted_in_current_zone(cls, policy: Union[int, CommonVenueCivicPolicyId, CommonStreetCivicPolicyId, BaseCivicPolicy]) -> bool: + """is_policy_balloted_in_current_zone(policy) + + Determine if a Policy is currently balloted in the current Zone. + + :param policy: The policy to look for. + :type policy: Union[int, CommonVenueCivicPolicyId, CommonStreetCivicPolicyId, BaseCivicPolicy] + :return: True, if the specified policy is currently balloted in the current Zone. False, if not. + :rtype: bool + """ + return cls.is_policy_in_zone(CommonLocationUtils.get_current_zone_id(), policy, CommonCivicPolicyStatusType.BALLOTED) + + @classmethod + def is_policy_up_for_repeal_in_current_zone(cls, policy: Union[int, CommonVenueCivicPolicyId, CommonStreetCivicPolicyId, BaseCivicPolicy]) -> bool: + """is_up_for_repeal_in_current_zone(policy) + + Determine if a Policy is currently up for repeal in the current Zone. + + :param policy: The policy to look for. + :type policy: Union[int, CommonVenueCivicPolicyId, CommonStreetCivicPolicyId, BaseCivicPolicy] + :return: True, if the specified policy is currently up for repeal in the current Zone. False, if not. + :rtype: bool + """ + return cls.is_policy_in_zone(CommonLocationUtils.get_current_zone_id(), policy, CommonCivicPolicyStatusType.UP_FOR_REPEAL) + + @classmethod + def is_dormant_in_current_zone(cls, policy: Union[int, CommonVenueCivicPolicyId, CommonStreetCivicPolicyId, BaseCivicPolicy]) -> bool: + """is_dormant_in_current_zone(policy) + + Determine if a Policy is currently up for repeal in the current Zone. + + :param policy: The policy to look for. + :type policy: Union[int, CommonVenueCivicPolicyId, CommonStreetCivicPolicyId, BaseCivicPolicy] + :return: True, if the specified policy is currently up for repeal in the current Zone. False, if not. + :rtype: bool + """ + return cls.is_policy_in_zone(CommonLocationUtils.get_current_zone_id(), policy, CommonCivicPolicyStatusType.DORMANT) + + @classmethod + def is_policy_in_zone(cls, zone_id: int, policy: Union[int, CommonVenueCivicPolicyId, CommonStreetCivicPolicyId, BaseCivicPolicy], policy_status: CommonCivicPolicyStatusType) -> bool: + """is_policy_in_current_zone(zone_id, policy, policy_status) + + Determine if a Policy has a specific Status in a Zone. + + :param zone_id: The identifier of the Zone to check. + :type zone_id: int + :param policy: The policy to look for. + :type policy: Union[int, CommonVenueCivicPolicyId, CommonStreetCivicPolicyId, BaseCivicPolicy] + :param policy_status: The status of the policies to check. + :type policy_status: CommonCivicPolicyStatusType + :return: True, if the specified policy has the specified status in a Zone. False, if not. + :rtype: bool + """ + policy = cls.load_civic_policy_by_id(policy) + if policy is None: + return False + if isinstance(policy, StreetCivicPolicy): + policies = cls.get_street_civic_policies_by_zone_id(zone_id, policy_status) + elif isinstance(policy, VenueCivicPolicy): + policies = cls.get_venue_civic_policies_by_zone_id(zone_id, policy_status) + else: + return False + return policy in policies + + @classmethod + def is_policy_in_current_zone(cls, policy: Union[int, CommonVenueCivicPolicyId, CommonStreetCivicPolicyId, BaseCivicPolicy], policy_status: CommonCivicPolicyStatusType) -> bool: + """is_policy_in_current_zone(policy, policy_status) + + Determine if a Policy has a specific Status in the current Zone. + + :param policy: The policy to look for. + :type policy: Union[int, CommonVenueCivicPolicyId, CommonStreetCivicPolicyId, BaseCivicPolicy] + :param policy_status: The status of the policies to check. + :type policy_status: CommonCivicPolicyStatusType + :return: True, if the specified policy has the specified status in the current Zone. False, if not. + :rtype: bool + """ + return cls.is_policy_in_zone(CommonLocationUtils.get_current_zone_id(), policy, policy_status) + + @classmethod + def get_street_civic_policies_by_zone_id(cls, zone_id: int, policy_status: CommonCivicPolicyStatusType) -> Tuple[StreetCivicPolicy]: + """get_street_civic_policies_by_zone_id(zone_id, policy_status) + + Retrieve Street Civic Policies with the specifies status from the specified zone. + + :param zone_id: The identifier of the Zone to retrieve the civic policies from. + :type zone_id: int + :param policy_status: The status of the policies to look for. + :type policy_status: CommonCivicPolicyStatusType + :return: A collection of Street Civic Policies with the specified status from the specified zone. + :rtype: Tuple[StreetCivicPolicy] + """ + provider = CommonCivicPolicyUtils.get_street_civic_policy_provider_by_zone_id(zone_id) + if provider is None: + return tuple() + if policy_status == CommonCivicPolicyStatusType.ENACTED: + return provider.get_enacted_policies() + if policy_status == CommonCivicPolicyStatusType.BALLOTED: + return provider.get_balloted_policies() + if policy_status == CommonCivicPolicyStatusType.UP_FOR_REPEAL: + return provider.get_up_for_repeal_policies() + if policy_status == CommonCivicPolicyStatusType.DORMANT: + return provider.get_dormant_policies() + return tuple() + + @classmethod + def get_street_civic_policies_in_current_zone(cls, policy_status: CommonCivicPolicyStatusType) -> Tuple[StreetCivicPolicy]: + """get_street_civic_policies_in_current_zone(policy_status) + + Retrieve Street Civic Policies with the specifies status from the current zone. + + :param policy_status: The status of the policies to look for. + :type policy_status: CommonCivicPolicyStatusType + :return: A collection of Street Civic Policies with the specified status from the current zone. + :rtype: Tuple[StreetCivicPolicy] + """ + return cls.get_street_civic_policies_by_zone_id(CommonLocationUtils.get_current_zone_id(), policy_status) + + @classmethod + def get_street_civic_policy_provider_for_current_zone(cls) -> Union[StreetProvider, None]: + """get_street_civic_policy_provider_for_current_zone(zone_id) + + Retrieve the Street Civic Policy Provider for the current Zone. + + :return: The Street Civic Policy Provider for the current Zone or None if the street service is unavailable or there is no street for the current Zone. + :rtype: Union[StreetProvider, None] + """ + return cls.get_street_civic_policy_provider_by_zone_id(CommonLocationUtils.get_current_zone_id()) + + @classmethod + def get_street_civic_policy_provider_by_world_id(cls, world_id: int) -> Union[StreetProvider, None]: + """get_street_civic_policy_provider_by_world_id(zone_id) + + Retrieve the Street Civic Policy Provider for a World. + + :param world_id: The identifier of the World to retrieve the civic policy provider from. + :type world_id: int + :return: The Street Civic Policy Provider for the specified World or None if the street service is unavailable or there is no street for the specified World. + :rtype: Union[StreetProvider, None] + """ + street_service = CommonLocationUtils.get_street_service() + if street_service is None: + return None + street = CommonLocationUtils.get_street_by_world_id(world_id) + if street is None: + return None + return street_service.get_provider(street) + + @classmethod + def get_street_civic_policy_provider_by_zone_id(cls, zone_id: int) -> Union[StreetProvider, None]: + """get_street_civic_policy_provider_by_zone_id(zone_id) + + Retrieve the Street Civic Policy Provider for a Zone. + + :param zone_id: The identifier of the Zone to retrieve the civic policy provider from. + :type zone_id: int + :return: The Street Civic Policy Provider for the specified Zone or None if the street service is unavailable or there is no street for the specified Zone. + :rtype: Union[StreetProvider, None] + """ + street_service = CommonLocationUtils.get_street_service() + if street_service is None: + return None + street = CommonLocationUtils.get_street_by_zone_id(zone_id) + if street is None: + return None + return street_service.get_provider(street) + + @classmethod + def get_venue_civic_policies_by_zone_id(cls, zone_id: int, policy_status: CommonCivicPolicyStatusType) -> Tuple[VenueCivicPolicy]: + """get_venue_civic_policies_by_zone_id(zone_id, policy_status) + + Retrieve Venue Civic Policies with the specifies status from the specified zone. + + :param zone_id: The identifier of the Zone to retrieve the civic policies from. + :type zone_id: int + :param policy_status: The status of the policies to look for. + :type policy_status: CommonCivicPolicyStatusType + :return: A collection of Venue Civic Policies with the specified status from the specified zone. + :rtype: Tuple[VenueCivicPolicy] + """ + provider = CommonCivicPolicyUtils.get_venue_civic_policy_provider_by_zone_id(zone_id) + if provider is None: + return tuple() + if policy_status == CommonCivicPolicyStatusType.ENACTED: + return provider.get_enacted_policies() + if policy_status == CommonCivicPolicyStatusType.BALLOTED: + return provider.get_balloted_policies() + if policy_status == CommonCivicPolicyStatusType.UP_FOR_REPEAL: + return provider.get_up_for_repeal_policies() + if policy_status == CommonCivicPolicyStatusType.DORMANT: + return provider.get_dormant_policies() + return tuple() + + @classmethod + def get_venue_civic_policies_in_current_zone(cls, policy_status: CommonCivicPolicyStatusType) -> Tuple[VenueCivicPolicy]: + """get_venue_civic_policies_in_current_zone(policy_status) + + Retrieve Venue Civic Policies with the specifies status from the current zone. + + :param policy_status: The status of the policies to look for. + :type policy_status: CommonCivicPolicyStatusType + :return: A collection of Venue Civic Policies with the specified status from the current zone. + :rtype: Tuple[VenueCivicPolicy] + """ + return cls.get_venue_civic_policies_by_zone_id(CommonLocationUtils.get_current_zone_id(), policy_status) + + @classmethod + def get_venue_civic_policy_provider_for_current_zone(cls) -> Union[VenueCivicPolicyProvider, None]: + """get_venue_civic_policy_provider_for_current_zone() + + Retrieve the Venue Civic Policy Provider for a Zone. + + :return: The Venue Civic Policy Provider for the current Zone or None if the current Zone does not have a venue. + :rtype: Union[VenueCivicPolicyProvider, None] + """ + return cls.get_venue_civic_policy_provider_by_zone_id(CommonLocationUtils.get_current_zone_id()) + + @classmethod + def get_venue_civic_policy_provider_by_zone_id(cls, zone_id: int) -> Union[VenueCivicPolicyProvider, None]: + """get_venue_civic_policy_provider_by_zone_id(zone_id) + + Retrieve the Venue Civic Policy Provider for a Zone. + + :param zone_id: The identifier of the Zone to retrieve the civic policy provider from. + :type zone_id: int + :return: The Venue Civic Policy Provider for the specified Zone or None if the specified Zone does not have a venue. + :rtype: Union[VenueCivicPolicyProvider, None] + """ + venue = CommonLocationUtils.get_venue_by_zone_id(zone_id) + if venue is None: + return None + return venue.civic_policy_provider + + @classmethod + def load_civic_policy_by_id(cls, policy: Union[int, CommonVenueCivicPolicyId, CommonStreetCivicPolicyId, BaseCivicPolicy]) -> Union[BaseCivicPolicy, None]: + """load_civic_policy_by_id(policy) + + Load an instance of a Civic Policy by its identifier. + + :param policy: The identifier of a Civic Policy. + :type policy: Union[int, CommonVenueCivicPolicyId, CommonStreetCivicPolicyId, BaseCivicPolicy] + :return: An instance of a Civic Policy matching the decimal identifier or None if not found. + :rtype: Union[BaseCivicPolicy, None] + """ + if isinstance(policy, BaseCivicPolicy): + return policy + # noinspection PyBroadException + try: + # noinspection PyCallingNonCallable + policy_instance = policy() + if isinstance(policy_instance, BaseCivicPolicy): + # noinspection PyTypeChecker + return policy + except: + pass + # noinspection PyBroadException + try: + policy: int = int(policy) + except: + # noinspection PyTypeChecker + policy: BaseCivicPolicy = policy + return policy + + from sims4.resources import Types + from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + return CommonResourceUtils.load_instance(Types.SNIPPET, policy) + + +@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.print_enacted_street_policies', 'Print a list of enacted policies.') +def _common_print_street_civic_policies(output: CommonConsoleCommandOutput, policy_status: CommonCivicPolicyStatusType): + log = CommonCivicPolicyUtils.get_log() + try: + log.enable() + provider = CommonCivicPolicyUtils.get_street_civic_policy_provider_for_current_zone() + policies = provider.get_enacted_policies(tuning=True) + output(f'------------{policy_status.name} Street Civic Policies------------') + log.debug(f'------------{policy_status.name} Street Civic Policies------------') + for policy in policies: + output(f'Policy: {policy}') + log.format_with_message(f'Policy: {policy}') + output('------------------------------------------------------') + log.debug('------------------------------------------------------') + finally: + log.disable() + + +@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.print_enacted_street_policies', 'Print a list of enacted policies.') +def _common_print_enacted_street_policies(output: CommonConsoleCommandOutput): + log = CommonCivicPolicyUtils.get_log() + try: + log.enable() + provider = CommonCivicPolicyUtils.get_street_civic_policy_provider_for_current_zone() + policies = provider.get_enacted_policies(tuning=True) + output('------------Enacted Street Civic Policies------------') + log.debug('------------Enacted Street Civic Policies------------') + for policy in policies: + output(f'Policy: {policy}') + log.format_with_message(f'Policy: {policy}') + output('------------------------------------------------------') + log.debug('------------------------------------------------------') + finally: + log.disable() + + +@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.print_balloted_street_policies', 'Print a list of balloted policies.') +def _common_print_balloted_street_policies(output: CommonConsoleCommandOutput): + log = CommonCivicPolicyUtils.get_log() + try: + log.enable() + provider = CommonCivicPolicyUtils.get_street_civic_policy_provider_for_current_zone() + policies = provider.get_balloted_policies(tuning=True) + output('------------Balloted Street Civic Policies------------') + log.debug('------------Balloted Street Civic Policies------------') + for policy in policies: + output(f'Policy: {policy}') + log.format_with_message(f'Policy: {policy}') + output('------------------------------------------------------') + log.debug('------------------------------------------------------') + finally: + log.disable() + + +@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.print_dormant_street_policies', 'Print a list of dormant policies.') +def _common_print_dormant_street_policies(output: CommonConsoleCommandOutput): + log = CommonCivicPolicyUtils.get_log() + try: + log.enable() + provider = CommonCivicPolicyUtils.get_street_civic_policy_provider_for_current_zone() + policies = provider.get_dormant_policies(tuning=True) + output('------------Dormant Street Civic Policies------------') + log.debug('------------Dormant Street Civic Policies------------') + for policy in policies: + output(f'Policy: {policy}') + log.format_with_message(f'Policy: {policy}') + output('------------------------------------------------------') + log.debug('------------------------------------------------------') + finally: + log.disable() diff --git a/Scripts/s4ap/sims4communitylib/utils/localization/__init__.py b/Scripts/s4ap/sims4communitylib/utils/localization/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/localization/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/utils/localization/common_localization_utils.py b/Scripts/s4ap/sims4communitylib/utils/localization/common_localization_utils.py new file mode 100644 index 0000000..36dbc32 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/localization/common_localization_utils.py @@ -0,0 +1,245 @@ +""" +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 +""" +from typing import Union, Any, Iterator + +from protocolbuffers.Localization_pb2 import LocalizedString +from sims4.localization import LocalizationHelperTuning, _create_localized_string, create_tokens, \ + TunableLocalizedStringFactory +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from sims4communitylib.utils.localization.common_localized_string_separators import CommonLocalizedStringSeparator + + +class CommonLocalizationUtils: + """Utilities for handling localization strings. + + .. note:: Localized Strings are the python equivalent of values within a StringTable. + + """ + class LocalizedTooltip(TunableLocalizedStringFactory._Wrapper): + """CommonLocalizationUtils.LocalizedTooltip(string_id, *tokens) + + A LocalizedTooltip used when displaying tooltips. + + :param string_id: The text that will display in the tooltip. + :type string_id: Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator] + :param tokens: A collection of objects to format into the `string_id` + :type tokens: Any + """ + def __init__(self, string_id: Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator], *tokens: Any): + super().__init__(string_id) + self._tokens = tokens + + def __call__(self, *_) -> LocalizedString: + return CommonLocalizationUtils.create_localized_string(self._string_id, tokens=self._tokens) + + @staticmethod + def create_localized_tooltip(tooltip_text: Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator], tooltip_tokens: Iterator[Any]=()) -> 'LocalizedTooltip': + """create_localized_tooltip(tooltip_text, tooltip_tokens=()) + + Create a LocalizedTooltip use this when you wish to display a tooltip on various things. + + :param tooltip_text: The text that will be displayed. + :type tooltip_text: Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator] + :param tooltip_tokens: A collection of objects to format into the localized string. (They can be anything. LocalizedString, str, int, SimInfo, just to name a few) + :type tooltip_tokens: Iterator[Any], optional + :return: A tooltip ready for display. + :rtype: LocalizedTooltip + """ + if isinstance(tooltip_text, CommonLocalizationUtils.LocalizedTooltip): + return tooltip_text + return CommonLocalizationUtils.LocalizedTooltip(tooltip_text, *tuple(tooltip_tokens)) + + @staticmethod + def create_localized_string(identifier: Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator], tokens: Iterator[Any] = (), localize_tokens: bool = True, text_color: CommonLocalizedStringColor = CommonLocalizedStringColor.DEFAULT) -> LocalizedString: + """create_localized_string(identifier, tokens=(), localize_tokens=True, text_color=CommonLocalizedStringColor.DEFAULT) + + Create a LocalizedString formatted with the specified tokens. + + :param identifier: An identifier to locate a LocalizedString with, text that will be turned into a LocalizedString, or a LocalizedString itself. + :type identifier: Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator] + :param tokens: A collection of objects to format into the localized string. (They can be anything. LocalizedString, str, int, SimInfo, just to name a few) + :type tokens: Iterator[Any] + :param localize_tokens: If True, the specified tokens will be localized. If False, the specified tokens will be formatted into the LocalizedString as they are. Default is True + :type localize_tokens: bool + :param text_color: The color the text will be when displayed. + :type text_color: CommonLocalizedStringColor + :return: A localized string ready for display. + :rtype: LocalizedString + """ + if identifier is None: + return CommonLocalizationUtils.create_localized_string(CommonStringId.STRING_NOT_FOUND_WITH_IDENTIFIER, tokens=('None',), text_color=text_color) + if localize_tokens: + tokens = tuple(CommonLocalizationUtils._normalize_tokens(*tokens)) + if isinstance(identifier, LocalizedString) and hasattr(identifier, 'tokens'): + create_tokens(identifier.tokens, tokens) + return CommonLocalizationUtils.colorize(identifier, text_color=text_color) + if isinstance(identifier, TunableLocalizedStringFactory._Wrapper): + if isinstance(identifier._string_id, str): + string_id = CommonLocalizationUtils.create_from_string(identifier._string_id) + else: + string_id = CommonLocalizationUtils.create_from_int(identifier._string_id, *tuple(tokens)) + return CommonLocalizationUtils.colorize(string_id, text_color=text_color) + if isinstance(identifier, int): + return CommonLocalizationUtils.colorize(CommonLocalizationUtils.create_from_int(identifier, *tuple(tokens)), text_color=text_color) + if hasattr(identifier, 'sim_info'): + return identifier.sim_info + if hasattr(identifier, 'get_sim_info'): + return identifier.get_sim_info() + if isinstance(identifier, str): + return CommonLocalizationUtils.create_localized_string(CommonLocalizationUtils.create_from_string(identifier), tokens=tokens, text_color=text_color) + return CommonLocalizationUtils.create_localized_string(str(identifier), tokens=tokens, text_color=text_color) + + @staticmethod + def combine_localized_strings(identifier_list: Iterator[Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator]], separator: CommonLocalizedStringSeparator=CommonLocalizedStringSeparator.NO_SEPARATOR) -> LocalizedString: + """combine_localized_strings(identifier_list, separator=CommonLocalizedStringSeparator.NO_SEPARATOR) + + Combine multiple localized strings by a separator. + + :param identifier_list: A collection of identifiers to locate LocalizedStrings with, text that will be turned into a LocalizedString and combined with the other strings in the collection. + :type identifier_list: Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator] + :param separator: The separator to use when combining the strings. Default is to combine all of the strings by no separator, i.e. an empty space. + :type separator: CommonLocalizedStringSeparator, optional + :return: A localized string with all Localized Strings combined by the specified separator. + :rtype: LocalizedString + """ + localized = None + for identifier in identifier_list: + if localized is None: + localized = identifier + else: + localized = CommonLocalizationUtils.create_localized_string(separator, tokens=(localized, identifier)) + return localized + + @staticmethod + def combine_localized_strings_with_comma_space_and(identifier_list: Iterator[Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator]]) -> LocalizedString: + """combine_localized_strings_with_comma_space_and(identifier_list) + + Combine multiple localized strings and formulate a string that is of format "{0.String}", "{0.String} and {1.String}", or "{0.String}, and {1.String}". With {0.String} being the first strings in the collection and {1.String} being the last string in the collection. + + .. note:: Example: ['one'] will turn into "one". ['one', 'two'] will turn into "one and two". ['one', 'two', 'three'] will turn into "one, two, and three". + + :param identifier_list: A collection of identifiers to combine. + :type identifier_list: Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator] + :return: A localized string with all Localized Strings combined with a "comma space and" separator. + :rtype: LocalizedString + """ + identifier_list = tuple(identifier_list) + if not identifier_list: + return CommonStringId.S4CL_NONE + + if len(identifier_list) <= 1: + return CommonLocalizationUtils.combine_localized_strings(identifier_list, separator=CommonLocalizedStringSeparator.COMMA_SPACE) + + last_tag_text = identifier_list[-1] + combined_tags_text = CommonLocalizationUtils.combine_localized_strings(identifier_list[:-1], separator=CommonLocalizedStringSeparator.COMMA_SPACE) + if len(identifier_list) == 2: + return CommonLocalizationUtils.combine_localized_strings((combined_tags_text, last_tag_text), separator=CommonLocalizedStringSeparator.AND) + else: + return CommonLocalizationUtils.combine_localized_strings((combined_tags_text, last_tag_text), separator=CommonLocalizedStringSeparator.COMMA_SPACE_AND) + + @staticmethod + def combine_localized_strings_with_comma_space_or(identifier_list: Iterator[Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator]]) -> LocalizedString: + """combine_localized_strings_with_comma_space_or(identifier_list) + + Combine multiple localized strings and formulate a string that is of format "{0.String}", "{0.String} or {1.String}", or "{0.String}, or {1.String}". With {0.String} being the first strings in the collection and {1.String} being the last string in the collection. + + .. note:: Example: ['one'] will turn into "one". ['one', 'two'] will turn into "one or two". ['one', 'two', 'three'] will turn into "one, two, or three". + + :param identifier_list: A collection of identifiers to combine. + :type identifier_list: Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator] + :return: A localized string with all Localized Strings combined with a "comma space or" separator. + :rtype: LocalizedString + """ + identifier_list = tuple(identifier_list) + if not identifier_list: + return CommonStringId.S4CL_NONE + + if len(identifier_list) <= 1: + return CommonLocalizationUtils.combine_localized_strings(identifier_list, separator=CommonLocalizedStringSeparator.COMMA_SPACE) + + last_tag_text = identifier_list[-1] + combined_tags_text = CommonLocalizationUtils.combine_localized_strings(identifier_list[:-1], separator=CommonLocalizedStringSeparator.COMMA_SPACE) + if len(identifier_list) == 2: + return CommonLocalizationUtils.combine_localized_strings((combined_tags_text, last_tag_text), separator=CommonLocalizedStringSeparator.OR) + else: + return CommonLocalizationUtils.combine_localized_strings((combined_tags_text, last_tag_text), separator=CommonLocalizedStringSeparator.COMMA_SPACE_OR) + + @staticmethod + def create_from_string(string_text: str) -> LocalizedString: + """create_from_string(string_text) + + Create a LocalizedString from a string. + + :param string_text: The string to localize. The resulting LocalizedString will be '{0.String}' + :type string_text: str + :return: A LocalizedString created from the specified string. + :rtype: LocalizedString + """ + return LocalizationHelperTuning.get_raw_text(string_text) + + @staticmethod + def create_from_int(identifier: int, *tokens: Any) -> LocalizedString: + """create_from_int(identifier, *tokens) + + Locate a LocalizedString by an identifier and format tokens into it. + + :param identifier: A decimal number that identifies an existing LocalizedString. + :type identifier: int + :param tokens: A collection of objects to format into the LocalizedString. (Example types: LocalizedString, str, int, etc.) + :type tokens: Iterator[Any] + :return: A LocalizedString with the specified tokens formatted into it. + :rtype: LocalizedString + """ + return _create_localized_string(identifier, *tokens) + + @staticmethod + def colorize(localized_string: LocalizedString, text_color: CommonLocalizedStringColor=CommonLocalizedStringColor.DEFAULT) -> LocalizedString: + """colorize(localized_string, text_color=CommonLocalizedStringColor.DEFAULT) + + Set the text color of a LocalizedString. + + :param localized_string: The LocalizedString to set the text color of. + :type localized_string: LocalizedString + :param text_color: The text will become this color. + :type text_color: CommonLocalizedStringColor + :return: A LocalizedString with text in the specified color. + :rtype: LocalizedString + """ + if text_color == CommonLocalizedStringColor.DEFAULT: + return localized_string + if not hasattr(text_color, 'value'): + return localized_string + return CommonLocalizationUtils.create_localized_string(text_color.value, tokens=(localized_string,)) + + @staticmethod + def get_localized_string_hash(localized_string: LocalizedString) -> int: + """get_localized_string_hash(localized_string) + + Retrieve the hash value of a Localized String. + + :param localized_string: An instance of a Localized String. + :type localized_string: LocalizedString + :return: The hash value of the Localized String or 0 if a problem occurs. + :rtype: int + """ + if localized_string is None: + return 0 + # noinspection PyBroadException + try: + # noinspection PyUnresolvedReferences + return localized_string.hash + except: + return 0 + + @staticmethod + def _normalize_tokens(*tokens: Any) -> Iterator[LocalizedString]: + new_tokens = [] + for token in tokens: + new_tokens.append(CommonLocalizationUtils.create_localized_string(token)) + return tuple(new_tokens) diff --git a/Scripts/s4ap/sims4communitylib/utils/localization/common_localized_string_colors.py b/Scripts/s4ap/sims4communitylib/utils/localization/common_localized_string_colors.py new file mode 100644 index 0000000..ba8fd99 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/localization/common_localized_string_colors.py @@ -0,0 +1,23 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt +from sims4communitylib.enums.strings_enum import CommonStringId + + +class CommonLocalizedStringColor(CommonInt): + """Used to set the text color of LocalizedString. + + See the :func:`.CommonLocalizationUtils.colorize` function for more details. + + """ + DEFAULT: 'CommonLocalizedStringColor' = -1 + BLUE: 'CommonLocalizedStringColor' = CommonStringId.TEXT_WITH_BLUE_COLOR + GREEN: 'CommonLocalizedStringColor' = CommonStringId.TEXT_WITH_GREEN_COLOR + RED: 'CommonLocalizedStringColor' = CommonStringId.TEXT_WITH_RED_COLOR + YELLOW: 'CommonLocalizedStringColor' = CommonStringId.TEXT_WITH_YELLOW_COLOR + ORANGE: 'CommonLocalizedStringColor' = CommonStringId.TEXT_WITH_ORANGE_COLOR diff --git a/Scripts/s4ap/sims4communitylib/utils/localization/common_localized_string_separators.py b/Scripts/s4ap/sims4communitylib/utils/localization/common_localized_string_separators.py new file mode 100644 index 0000000..aa7ae18 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/localization/common_localized_string_separators.py @@ -0,0 +1,65 @@ +""" +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 +""" +from sims4communitylib.enums.enumtypes.common_int import CommonInt +from sims4communitylib.enums.strings_enum import CommonStringId + + +class CommonLocalizedStringSeparator(CommonInt): + """Used to separate multiple LocalizedString. + + See the :func:`.CommonLocalizationUtils.combine_localized_strings` function for more details. + + .. note:: The values are as follows: + + NO_SEPARATOR = "StringString" + AND = "{String} and {String}" + ARE = "String are String" + COLON_SPACE = "String: String" + COMMA_SPACE = "String, String" + COMMA_SPACE_AND = "{String}, and {String}" + COMMA_SPACE_OR = "{String}, or {String}" + HYPHEN = "String-String" + IS = "String is String" + NEWLINE = "String\nString" + NEWLINE_NEWLINE = "String\n\nString" + OR = "String or String" + PLUS = "String+String" + SPACE = "String String" + SPACE_PARENTHESIS_SURROUNDED = "String (String)" + + """ + # {String}{String} + NO_SEPARATOR: 'CommonLocalizedStringSeparator' = CommonStringId.S4CL_COMBINE_TWO_STRINGS + # {String} and {String} + AND: 'CommonLocalizedStringSeparator' = CommonStringId.S4CL_STRING_AND_STRING + # {String} are {String} + ARE: 'CommonLocalizedStringSeparator' = CommonStringId.S4CL_STRING_ARE_STRING + # {String}: {String} + COLON_SPACE: 'CommonLocalizedStringSeparator' = CommonStringId.STRING_COLON_SPACE_STRING + # {String}, {String} + COMMA_SPACE: 'CommonLocalizedStringSeparator' = CommonStringId.STRING_COMMA_SPACE_STRING + # {String}, and {String} + COMMA_SPACE_AND: 'CommonLocalizedStringSeparator' = CommonStringId.S4CL_STRING_COMMA_SPACE_AND_STRING + # {String}, or {String} + COMMA_SPACE_OR: 'CommonLocalizedStringSeparator' = CommonStringId.S4CL_STRING_COMMA_SPACE_OR_STRING + # {String}-{String} + HYPHEN: 'CommonLocalizedStringSeparator' = CommonStringId.STRING_HYPHEN_STRING + # {String} is {String} + IS: 'CommonLocalizedStringSeparator' = CommonStringId.S4CL_STRING_IS_STRING + # {String}\n{String} + NEWLINE: 'CommonLocalizedStringSeparator' = CommonStringId.STRING_NEWLINE_STRING + # {String}\n\n{String} + NEWLINE_NEWLINE: 'CommonLocalizedStringSeparator' = CommonStringId.STRING_NEWLINE_NEWLINE_STRING + # {String} or {String} + OR: 'CommonLocalizedStringSeparator' = CommonStringId.S4CL_STRING_OR_STRING + # {String}+{String} + PLUS: 'CommonLocalizedStringSeparator' = CommonStringId.S4CL_STRING_PLUS_STRING + # {String} {String} + SPACE: 'CommonLocalizedStringSeparator' = CommonStringId.STRING_SPACE_STRING + # {String} ({String}) + SPACE_PARENTHESIS_SURROUNDED: 'CommonLocalizedStringSeparator' = CommonStringId.STRING_SPACE_PARENTHESIS_SURROUNDED_STRING diff --git a/Scripts/s4ap/sims4communitylib/utils/location/__init__.py b/Scripts/s4ap/sims4communitylib/utils/location/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/location/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/utils/location/common_location_utils.py b/Scripts/s4ap/sims4communitylib/utils/location/common_location_utils.py new file mode 100644 index 0000000..b46521a --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/location/common_location_utils.py @@ -0,0 +1,979 @@ +""" +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 +""" +import services + +from typing import Tuple, Union, Any, Dict, List + +import build_buy +from civic_policies.street_civic_policy_service import StreetService +from sims4communitylib.classes.math.common_location import CommonLocation +from sims4communitylib.classes.math.common_surface_identifier import CommonSurfaceIdentifier +from sims4communitylib.classes.math.common_vector3 import CommonVector3 +from sims4communitylib.enums.common_region_id import CommonRegionId +from world.region import Region +from world.street import Street + +try: + import _buildbuy +except ImportError: + # noinspection SpellCheckingInspection + _buildbuy = build_buy +from sims4.resources import Types +from sims4communitylib.utils.common_resource_utils import CommonResourceUtils +from venues.venue_tuning import Venue, VenueTypes +from world.lot import Lot +from zone import Zone +from zone_modifier.zone_modifier import ZoneModifier + + +class CommonLocationUtils: + """Utilities for manipulating locations and lots. + + To manipulate the location of Sims, see :class:`.CommonSimLocationUtils`. + To manipulate the location of Objects, see :class:`.CommonObjectLocationUtils`. + + """ + + @classmethod + def get_current_region(cls) -> Region: + """get_current_region() + + Retrieve the current region. + + :return: The current region. + :rtype: Region + """ + return services.current_region() + + @classmethod + def get_current_region_id(cls) -> int: + """get_current_region_id() + + Retrieve the id of the current region. + + :return: The id of the current region. + :rtype: int + """ + region = cls.get_current_region() + return cls.get_region_id(region) + + @classmethod + def get_region_id(cls, region: Region) -> int: + """get_region_id(region) + + Retrieve the id of a region. + + :return: The id of a region. + :rtype: int + """ + if region is None: + return 0 + return getattr(region, 'guid64', 0) + + @classmethod + def is_current_region(cls, region: Union[int, CommonRegionId, Region]) -> bool: + """is_current_region(region) + + Determine if a region is the current one. + + :param region: The region to check. + :type region: Union[int, CommonRegionId, Region] + :return: True, if the specified region is the current one. False, if not. + :rtype: bool + """ + region = cls.load_region_by_id(region) + if region is None: + return False + return region == cls.get_current_region() + + @classmethod + def load_region_by_id(cls, region: Union[int, CommonRegionId, Region]) -> Union[Region, None]: + """load_region_by_id(region) + + Load an instance of a Region by its identifier. + + :param region: The identifier of a Region. + :type region: Union[int, CommonRegionId, Region] + :return: An instance of a Region matching the decimal identifier or None if not found. + :rtype: Union[Region, None] + """ + if region is None: + return None + if isinstance(region, Region): + return region + # noinspection PyBroadException + try: + # noinspection PyCallingNonCallable + region_instance = region() + if isinstance(region_instance, Region): + # noinspection PyTypeChecker + return region + except: + pass + # noinspection PyBroadException + try: + region: int = int(region) + except: + # noinspection PyTypeChecker + region: Region = region + return region + + from sims4.resources import Types + from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + return CommonResourceUtils.load_instance(Types.REGION, region) + + @staticmethod + def get_lot_corners(lot: Lot) -> Tuple[Any]: + """get_lot_corners(lot) + + Retrieve the corners of a Lot. + + :return: A collection of corners of the specified Lot. + :rtype: Tuple[Any] + """ + return tuple(lot.corners) + + @staticmethod + def get_lot_corners_of_current_lot() -> Tuple[Any]: + """get_lot_corners_of_current_lot() + + Retrieve the corners of the current Lot. + + :return: A collection of corners on the current Lot. + :rtype: Tuple[Any] + """ + return CommonLocationUtils.get_lot_corners(CommonLocationUtils.get_current_lot()) + + @staticmethod + def get_zone_id(zone: Zone) -> int: + """get_zone_id(zone) + + Retrieve the identifier of the specified Zone. + + :param zone: The Zone to get the identifier of. + :type zone: Zone + :return: The identifier of the specified Zone. + :rtype: int + """ + return zone.id + + @staticmethod + def get_zone(zone_id: int, allow_unloaded_zones: bool = False) -> Zone: + """get_zone(zone_id, allow_unloaded_zones=False) + + Retrieve the Zone matching an identifier. + + :param zone_id: The decimal identifier of a Zone. + :type zone_id: int + :param allow_unloaded_zones: If set to True, Zones that are currently not loaded (or have not been loaded) will be considered. If set to False, Zones that have yet to be loaded will not be considered. Default is False. + :type allow_unloaded_zones: bool, optional + :return: The Zone with the specified zone id or None if it was not found. + :rtype: Zone + """ + return services.get_zone(zone_id, allow_uninstantiated_zones=allow_unloaded_zones) + + @staticmethod + def get_zone_lot(zone: Zone) -> Union[Lot, None]: + """get_zone_lot(zone) + + Retrieve the lot of a Zone. + + :param zone: An instance of a Zone. + :type zone: Zone + :return: The Lot within the specified Zone or None if a problem occurs. + :rtype: Union[Lot, None] + """ + if zone is None: + return None + return zone.lot + + @staticmethod + def get_current_zone_plex_id() -> int: + """get_current_zone_plex_id() + + Retrieve the plex id of the current zone. + + .. note:: A plex id is basically a Room location. + + :return: The ID of the current zone plex or 0 if the current zone does not have a plex id. + :rtype: int + """ + from services import get_plex_service + return get_plex_service().get_active_zone_plex_id() or 0 + + @staticmethod + def get_plex_id_for_zone(zone: Zone) -> int: + """get_plex_id_for_zone(zone) + + Retrieve the plex id for a Zone. + + :return: The Plex ID of the specified zone or -1 if it was not found. + :rtype: int + """ + zone_id = CommonLocationUtils.get_zone_id(zone) + return CommonLocationUtils.get_plex_id(zone_id) + + @staticmethod + def get_plex_id(zone_id: int) -> int: + """get_plex_id(zone_id) + + Retrieve the plex id of a Zone. + + :return: The Plex ID of the specified zone or 0 if it was not found. + :rtype: int + """ + plex_service = services.get_plex_service() + if zone_id not in plex_service._zone_to_master_map: + return 0 + (_, plex_id) = plex_service._zone_to_master_map[zone_id] + if plex_id == -1: + return 0 + return plex_id + + @staticmethod + def get_all_block_ids(zone_id: int) -> Tuple[int]: + """get_all_block_ids(zone_id) + + Retrieve a collection of all Block ids for a Zone. + + :param zone_id: The id of the Zone to retrieve the block ids of. + :type zone_id: int + :return: A collection of block ids. + :rtype: Tuple[int] + """ + plex_id = CommonLocationUtils.get_plex_id(zone_id) + if plex_id == -1: + return tuple() + # noinspection PyArgumentList + return tuple(_buildbuy.get_all_block_polygons(zone_id, plex_id).keys()) + + @staticmethod + def get_block_id_in_zone(zone_id: int, position: CommonVector3, surface_level: int) -> int: + """get_block_id_in_zone(zone_id, position, level) + + Retrieve the id of the block containing the position within a specified Zone. + + .. note:: A Block is the same thing as a Room. This information can be used to determine which Room something is located in as well. + + .. note:: The entirety of Outside has a room id of 0. + + :param zone_id: The zone to search. + :type zone_id: int + :param position: An instance of a vector. + :type position: CommonVector3 + :param surface_level: The surface level of the position. + :type surface_level: int + :return: The id of the block containing the position. + :rtype: int + """ + return CommonLocationUtils.get_block_id(zone_id, position, surface_level) + + @staticmethod + def get_block_id_in_current_zone(position: CommonVector3, surface_level: int) -> int: + """get_block_id_in_current_zone(position, level) + + Retrieve the id of the block containing the position. + + .. note:: A Block is the same thing as a Room. This information can be used to determine which Room something is located in as well. + + .. note:: The entirety of Outside has a room id of 0. + + :param position: An instance of a vector. + :type position: CommonVector3 + :param surface_level: The surface level of the position. + :type surface_level: int + :return: The id of the block containing the position. + :rtype: int + """ + return CommonLocationUtils.get_block_id(CommonLocationUtils.get_current_zone_id(), position, surface_level) + + @staticmethod + def get_all_block_ids_in_current_zone() -> Tuple[int]: + """get_all_block_ids_in_current_zone() + + Retrieve a collection of all Block Identifiers for the current zone. + + .. note:: A Block Id is essentially an identifier for a Room. + + :return: A collection of block decimal identifiers. + :rtype: Tuple[int] + """ + return tuple(CommonLocationUtils.get_all_block_polygons_of_current_zone().keys()) + + @staticmethod + def get_all_block_polygons_of_current_zone() -> Dict[int, Tuple[Tuple[List[CommonVector3]]]]: + """get_all_block_polygons_of_current_zone() + + Retrieve all block polygons for the current Zone. + + :return: A dictionary of polygons for the current Zone with the Block Ids as the key. + :rtype: Dict[int, Tuple[Tuple[Polygon]]] + """ + # noinspection PyArgumentList + return _buildbuy.get_all_block_polygons(CommonLocationUtils.get_current_zone_id(), CommonLocationUtils.get_current_zone_plex_id()) + + @staticmethod + def get_all_block_polygons(zone_id: int) -> Dict[int, Tuple[Tuple[List[CommonVector3]]]]: + """get_all_block_polygons(zone_id) + + Retrieve all block polygons for a Zone. + + .. note:: A Block is essentially just a Room. + + :param zone_id: A decimal identifier of a Zone. + :type zone_id: int + :return: A collection of polygons for the specified Zone. + :rtype: Dict[int, Tuple[Tuple[List[CommonVector3]]]] + """ + plex_id = CommonLocationUtils.get_plex_id(zone_id) + if plex_id == -1: + return dict() + # noinspection PyArgumentList + return _buildbuy.get_all_block_polygons(zone_id, plex_id) + + @staticmethod + def get_block_id(zone_id: int, position: CommonVector3, surface_level: int) -> int: + """get_block_id(zone_id, position, surface_level) + + Retrieve the decimal identifier of the block containing the position. + + :param zone_id: The decimal identifier of a Zone. + :type zone_id: int + :param position: An instance of a vector. + :type position: CommonVector3 + :param surface_level: The surface level of the position. + :type surface_level: int + :return: A decimal identifier of the block containing the position. + :rtype: int + """ + return build_buy.get_block_id(zone_id, position, surface_level) + + @staticmethod + def get_lot_id(lot: Lot) -> int: + """get_lot_id(lot) + + Retrieve the decimal identifier of a Lot. + + :param lot: An instance of a Lot. + :type lot: Lot + :return: The decimal identifier of the specified lot or -1 if a problem occurs. + :rtype: int + """ + if lot is None: + return -1 + return lot.lot_id + + @staticmethod + def get_current_zone() -> Zone: + """get_current_zone() + + Retrieve the current zone. + + :return: The current Zone + :rtype: Zone + """ + return services.current_zone() + + @staticmethod + def get_current_zone_id() -> int: + """get_current_zone_id() + + Retrieve the current zone id. + + :return: The identifier of the current Zone. + :rtype: int + """ + return services.current_zone_id() + + @staticmethod + def get_current_lot() -> Lot: + """get_current_lot() + + Retrieve the current lot. + + :return: The current Lot. + :rtype: Lot + """ + return services.active_lot() + + @staticmethod + def get_current_lot_id() -> int: + """get_current_lot_id() + + Retrieve the decimal identifier of the current Lot. + + :return: The decimal identifier of the current Lot or -1 if a problem occurs. + :rtype: int + """ + return services.active_lot_id() or -1 + + @staticmethod + def is_location_outside_current_lot(location: CommonLocation) -> bool: + """is_location_outside_current_lot(location) + + Determine if a location is outside of the current lot or not. + + :param location: The Location to check. + :type location: CommonLocation + :return: True, if the location is outside of the current lot. False, if not. + :rtype: bool + """ + return CommonLocationUtils.is_location_outside_lot(location, CommonLocationUtils.get_current_zone_id()) + + @staticmethod + def is_location_outside_lot(location: CommonLocation, zone_id: int) -> bool: + """is_location_outside_lot(location, lot_id) + + Determine if a location is outside of the Lot with the specified identifier. + + :param location: The Location to check. + :type location: CommonLocation + :param zone_id: The identifier of a Zone to check for the Location to be outside of. + :type zone_id: int + :return: True, if location is outside of the Lot with the specified lot_id. False, if not. + :rtype: bool + """ + try: + # noinspection PyTypeChecker,PyArgumentList + return _buildbuy.is_location_outside(zone_id, location.transform.translation, location.routing_surface.secondary_id) + except RuntimeError: + return False + + @staticmethod + def is_position_on_current_lot(position: CommonVector3) -> bool: + """is_position_on_current_lot(position) + + Determine if a sim is on the current lot. + + :param position: The position to check. + :type position: CommonVector3 + :return: True, if the specified position is within the bounds of the current lot. False, if not. + :rtype: bool + """ + return position is not None and services.active_lot().is_position_on_lot(position) + + @staticmethod + def is_position_within_range_of_position(position_a: CommonVector3, position_b: CommonVector3, distance_in_squares: float) -> bool: + """is_position_within_range_of_position(position_a, position_b, distance_in_squares) + + Determine if Position A is within a certain distance of Position B. + + :param position_a: The first position. + :type position_a: CommonVector3 + :param position_b: The second position. + :type position_b: CommonVector3 + :param distance_in_squares: A unit measured in squares. 1 square is the size of 1 square in the Build/Buy mode visual grid. For comparison, a dining chair would be 1 square by 1 square. 0.5 would be half a square, or half a dining chair. + :type distance_in_squares: float + :return: True, if the distance between Position A and Position B is less than or equal to the specified distance in squares. False, if not. + :return: bool + """ + from sims4communitylib.utils.common_math_utils import CommonMathUtils + distance_between_positions = CommonMathUtils.calculate_distance(position_a, position_b, flatten_positions=False) + return distance_between_positions <= distance_in_squares + + @staticmethod + def is_location_within_range_of_location(location_a: CommonLocation, location_b: CommonLocation, distance_in_squares: float) -> bool: + """is_location_within_range_of_location(location_a, location_b, distance_in_squares) + + Determine if Location A is within a certain distance of Location B. + + :param location_a: The first location. + :type location_a: CommonLocation + :param location_b: The second location. + :type location_b: CommonLocation + :param distance_in_squares: A unit measured in squares. 1 square is the size of 1 square in the Build/Buy mode visual grid. For comparison, a dining chair would be 1 square by 1 square. 0.5 would be half a square, or half a dining chair. + :type distance_in_squares: float + :return: True, if the distance between Location A and Location B is less than or equal to the specified distance in squares. False, if not. + :return: bool + """ + position_a = location_a.transform.translation + position_b = location_b.transform.translation + return CommonLocationUtils.is_position_within_range_of_position(position_a, position_b, distance_in_squares) + + @staticmethod + def get_lot_traits(zone_id: int) -> Tuple[ZoneModifier]: + """get_lot_traits(lot_id) + + Retrieve the Lot Traits of a Lot with the specified identifier. + + :param zone_id: The lot to retrieve the traits of. + :type zone_id: int + :return: A collection of Lot Traits for the specified lot. + :rtype: Tuple[ZoneModifier] + """ + return tuple(services.get_zone_modifier_service().get_zone_modifiers(zone_id)) + + @staticmethod + def get_lot_traits_of_current_lot() -> Tuple[ZoneModifier]: + """get_lot_traits_of_current_lot() + + Retrieve the Lot Traits of the Current Lot. + + :return: A collection of Lot Traits for the current lot. + :rtype: Tuple[ZoneModifier] + """ + return CommonLocationUtils.get_lot_traits(CommonLocationUtils.get_current_zone_id()) + + @staticmethod + def current_lot_has_trait(lot_trait_id: int) -> bool: + """current_lot_has_trait(lot_trait_id) + + Determine if the Current Lot has the specified Lot Trait. + + :param lot_trait_id: The trait to look for. + :type lot_trait_id: int + :return: True, if the current lot has the specified trait. False, if not. + :rtype: bool + """ + return CommonLocationUtils.lot_has_trait(CommonLocationUtils.get_current_zone_id(), lot_trait_id) + + @staticmethod + def current_lot_has_any_traits(lot_trait_ids: Tuple[int]) -> bool: + """current_lot_has_any_traits(lot_trait_ids) + + Determine if the Current Lot has any of the specified Lot Traits. + + :param lot_trait_ids: A collection of traits to look for. + :type lot_trait_ids: Tuple[int] + :return: True, if the current lot has any of the specified traits. False, if not. + :rtype: bool + """ + return CommonLocationUtils.lot_has_any_traits(CommonLocationUtils.get_current_zone_id(), lot_trait_ids) + + @staticmethod + def current_lot_has_all_traits(lot_trait_ids: Tuple[int]) -> bool: + """current_lot_has_all_traits(lot_trait_ids) + + Determine if the Current Lot has all of the specified Lot Traits. + + :param lot_trait_ids: A collection of traits to look for. + :type lot_trait_ids: Tuple[int] + :return: True, if the current lot has all of the specified traits. False, if not. + :rtype: bool + """ + return CommonLocationUtils.lot_has_all_traits(CommonLocationUtils.get_current_zone_id(), lot_trait_ids) + + @staticmethod + def lot_has_trait(zone_id: int, lot_trait_id: int) -> bool: + """lot_has_trait(zone_id, lot_trait_id) + + Determine if a Lot has the specified Lot Trait. + + :param zone_id: The identifier of the zone to check. + :type zone_id: int + :param lot_trait_id: The trait to look for. + :type lot_trait_id: int + :return: True, if the specified lot has the specified trait. False, if not. + :rtype: bool + """ + return CommonLocationUtils.lot_has_all_traits(zone_id, (lot_trait_id,)) + + @staticmethod + def lot_has_any_traits(zone_id: int, lot_trait_ids: Tuple[int]) -> bool: + """lot_has_any_traits(zone_id, lot_trait_ids) + + Determine if a Lot has any of the specified Lot Traits. + + :param zone_id: The identifier of the zone to check. + :type zone_id: int + :param lot_trait_ids: A collection of traits to look for. + :type lot_trait_ids: Tuple[int] + :return: True, if the specified lot has any of the specified traits. False, if not. + :rtype: bool + """ + target_lot_trait_ids = [getattr(lot_trait, 'guid64', None) for lot_trait in CommonLocationUtils.get_lot_traits(zone_id)] + for lot_trait_id in lot_trait_ids: + if lot_trait_id in target_lot_trait_ids: + return True + return False + + @staticmethod + def lot_has_all_traits(zone_id: int, lot_trait_ids: Tuple[int]) -> bool: + """lot_has_all_traits(zone_id, lot_trait_ids) + + Determine if a Lot has all of the specified Lot Traits. + + :param zone_id: The identifier of the zone to check. + :type zone_id: int + :param lot_trait_ids: A collection of traits to look for. + :type lot_trait_ids: Tuple[int] + :return: True, if the specified lot has all of the specified traits. False, if not. + :rtype: bool + """ + target_lot_trait_ids = [getattr(lot_trait, 'guid64', None) for lot_trait in CommonLocationUtils.get_lot_traits(zone_id)] + if not target_lot_trait_ids: + return False + for lot_trait_id in lot_trait_ids: + if lot_trait_id in target_lot_trait_ids: + continue + return False + return True + + @classmethod + def get_current_venue(cls) -> Venue: + """get_current_venue() + + Retrieve the current venue. + + :return: The current venue. + :rtype: Venue + """ + return services.get_current_venue() + + @classmethod + def get_current_venue_id(cls) -> int: + """get_current_venue_id() + + Retrieve the id of the current venue. + + :return: The id of the current venue. + :rtype: int + """ + venue = cls.get_current_venue() + return cls.get_venue_id(venue) + + @classmethod + def get_venue_id(cls, venue: Venue) -> int: + """get_venue_id(venue) + + Retrieve the id of a venue. + + :return: The id of a venue. + :rtype: int + """ + if venue is None: + return 0 + return getattr(venue, 'guid64', 0) + + @classmethod + def load_venue_by_guid(cls, venue: Union[int, Venue]) -> Union[Venue, None]: + """load_venue_by_guid(venue) + + Load an instance of a Region by its identifier. + + :param venue: The identifier of a Venue. + :type venue: Union[int, Venue] + :return: An instance of a Venue matching the decimal identifier or None if not found. + :rtype: Union[Venue, None] + """ + if venue is None: + return None + if isinstance(venue, Venue): + return venue + # noinspection PyBroadException + try: + # noinspection PyCallingNonCallable + venue_instance = venue() + if isinstance(venue_instance, Venue): + # noinspection PyTypeChecker + return venue + except: + pass + # noinspection PyBroadException + try: + venue: int = int(venue) + except: + # noinspection PyTypeChecker + venue: Venue = venue + return venue + + from sims4.resources import Types + from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + return CommonResourceUtils.load_instance(Types.VENUE, venue) + + @classmethod + def get_current_venue_type(cls) -> VenueTypes: + """get_current_venue_type() + + Retrieve the type of the current venue. + + :return: The VenueType of the current lot. + :rtype: VenueTypes + """ + return cls.get_venue_type_by_zone_id(CommonLocationUtils.get_current_zone_id()) + + @classmethod + def get_venue_of_current_lot(cls) -> Venue: + """get_venue_of_current_lot() + + Retrieve a Venue for the current lot. + + :return: The Venue of the current lot. + :rtype: Venue + """ + return cls.get_venue_by_zone_id(CommonLocationUtils.get_current_zone_id()) + + @classmethod + def get_venue_type_by_zone_id(cls, zone_id: int) -> VenueTypes: + """get_venue_type_by_zone_id() + + Retrieve the Venue type of a Zone. + + :return: The VenueType of the specified Zone. + :rtype: VenueTypes + """ + return build_buy.get_current_venue(zone_id) + + @classmethod + def get_venue_by_zone_id(cls, zone_id: int) -> Venue: + """get_venue_by_zone_id(zone_id) + + Retrieve the Venue for a Zone. + + :param zone_id: The identifier of a Zone. + :type zone_id: int + :return: The Venue instance for the specified Zone. + :rtype: Venue + """ + return CommonResourceUtils.load_instance(Types.VENUE, cls.get_venue_type_by_zone_id(zone_id)) + + @staticmethod + def is_current_venue_residential() -> bool: + """is_current_venue_residential() + + Determine if a venue is residential. + + :return: True, if the venue of the current lot is residential. False, if not. + :rtype: bool + """ + venue_instance = CommonLocationUtils.get_venue_of_current_lot() + if venue_instance is None: + return False + # noinspection PyUnresolvedReferences + return venue_instance.residential + + @staticmethod + def current_venue_requires_player_greeting() -> bool: + """current_venue_requires_player_greeting() + + Determine if the current venue requires player greeting. + + :return: True, if the venue of the current lot requires the player to be greeted. False, if not. + :rtype: bool + """ + venue_instance = CommonLocationUtils.get_venue_of_current_lot() + if venue_instance is None: + return False + return venue_instance.requires_visitation_rights + + @staticmethod + def current_venue_allows_role_state_routing() -> bool: + """current_venue_allows_role_state_routing() + + Determine if the current venue allows routing for role states. + + :return: True, if the venue of the current lot allows routing by role state. False, if not. + :rtype: bool + """ + venue_instance = CommonLocationUtils.get_venue_of_current_lot() + if venue_instance is None: + return False + # noinspection PyUnresolvedReferences + return venue_instance.allow_rolestate_routing_on_navmesh + + @staticmethod + def is_position_on_lot(position: CommonVector3, lot: Lot) -> bool: + """is_position_on_lot(position, lot) + + Determine if a Position is located on a Lot. + + :param position: An instance of a CommonVector + :type position: CommonVector3 + :param lot: An instance of a Lot. + :type lot: Lot + :return: True, if the Sim is on the specified Lot. False, if not. + :rtype: bool + """ + return position is not None and lot.is_position_on_lot(position) + + @staticmethod + def can_location_be_routed_to(location: CommonLocation) -> bool: + """can_location_be_routed_to(location) + + Determine if a location can be routed to by a Sim. + + :param location: The location to check. + :type location: CommonLocation + :return: True, if the location can be routed to by a Sim. False, it not. + :rtype: bool + """ + return CommonLocationUtils.can_position_be_routed_to(location.transform.translation, location.routing_surface) + + @staticmethod + def can_position_be_routed_to(position: CommonVector3, surface_identifier: CommonSurfaceIdentifier) -> bool: + """can_position_be_routed_to(position, surface_identifier) + + Determine if a position and surface can be routed to by a Sim. + + :param position: The position to check. + :type position: CommonVector3 + :param surface_identifier: The surface to check. + :type surface_identifier: CommonSurfaceIdentifier + :return: True, if the position can be routed to by a Sim. False, it not. + :rtype: bool + """ + from routing import test_point_placement_in_navmesh + return test_point_placement_in_navmesh(surface_identifier, position) + + @staticmethod + def get_surface_height_at(x: float, z: float, routing_surface: CommonSurfaceIdentifier) -> float: + """get_surface_height_at(x, z, routing_surface) + + Calculate the height of a surface. + + :param x: The x position of the surface. + :type x: float + :param z: The z position of the surface. + :type z: float + :param routing_surface: The surface. + :type routing_surface: CommonSurfaceIdentifier + :return: The height of the surface. + :rtype: float + """ + # noinspection PyUnresolvedReferences + return services.terrain_service.terrain_object().get_routing_surface_height_at(x, z, routing_surface) + + @staticmethod + def get_current_zone_world_id() -> int: + """get_current_zone_world_id() + + Retrieve the world id of the current Zone. + + :return: The world id of the current Zone. + :rtype: int + """ + return CommonLocationUtils.get_zone_world_id(CommonLocationUtils.get_current_zone_id()) + + @staticmethod + def get_current_zone_world_description_id() -> int: + """get_current_zone_world_description_id() + + Retrieve the world description id of the current Zone. + + :return: The world description id of the current Zone. + :rtype: int + """ + return CommonLocationUtils.get_zone_world_description_id(CommonLocationUtils.get_current_zone_id()) + + @staticmethod + def get_zone_world_id(zone_id: int) -> int: + """get_zone_world_id(zone_id) + + Retrieve the world id of the a Zone. + + :param zone_id: The decimal identifier of a Zone. + :type zone_id: int + :return: The world id of the specified Zone. + :rtype: int + """ + return services.get_persistence_service().get_world_id_from_zone(zone_id) + + @staticmethod + def get_zone_world_description_id(zone_id: int) -> int: + """get_zone_world_description_id(zone_id) + + Retrieve the world description id of the a Zone. + + :param zone_id: The decimal identifier of a Zone. + :type zone_id: int + :return: The world description id of the the specified Zone. + :rtype: int + """ + return services.get_world_description_id(CommonLocationUtils.get_zone_world_id(zone_id)) + + @staticmethod + def apply_surface_level_to_position(position: CommonVector3, surface_identifier: CommonSurfaceIdentifier) -> CommonVector3: + """apply_surface_level_to_position(game_object, interaction_context=None) + + Get the position of the surface of an Object. + + :param position: The position to update. + :type position: CommonVector3 + :param surface_identifier: The surface identifier to apply. + :type surface_identifier: CommonSurfaceIdentifier + :return: The position with a surface level applied. + :rtype: CommonVector3 + """ + position = CommonVector3.from_vector3(position) + surface_identifier = CommonSurfaceIdentifier.from_surface_identifier(surface_identifier) + position = CommonVector3(position.x, CommonLocationUtils.get_surface_height_at(position.x, position.z, surface_identifier), position.z) + return CommonVector3.from_vector3(position) + + @classmethod + def get_current_world_id(cls) -> int: + """get_current_world_id() + + Retrieve the identifier of the World which the current Zone is in. + + :return: The identifier of the World which the current Zone is in. + :rtype: int + """ + return cls.get_world_id_by_zone_id(CommonLocationUtils.get_current_zone_id()) + + @classmethod + def get_world_id_by_zone_id(cls, zone_id: int) -> int: + """get_world_id_by_zone_id(zone_id) + + Retrieve the identifier of the World which a Zone is in. + + :param zone_id: The identifier of the zone to use. + :type zone_id: int + :return: The identifier of the World which a Zone is in. + :rtype: int + """ + return services.get_persistence_service().get_world_id_from_zone(zone_id) + + @classmethod + def get_street_service(cls) -> StreetService: + """get_street_service() + + Retrieve an instance of the street service. + + :return: An instance of the street service. + :rtype: StreetService + """ + return services.street_service() + + @classmethod + def get_street_of_current_zone(cls) -> Street: + """get_street_from_current_zone() + + Retrieve a Street instance using the current Zone. + + :return: The Street instance for the current Zone. + :rtype: Street + """ + return cls.get_street_by_zone_id(CommonLocationUtils.get_current_zone_id()) + + @classmethod + def get_street_by_zone_id(cls, zone_id: int) -> Street: + """get_street_by_zone_id(zone_id) + + Retrieve the Street instance for a Zone. + + :param zone_id: The identifier of the Zone to use. + :type zone_id: int + :return: The Street instance of the specified zone. + :rtype: Street + """ + from world.street import get_street_instance_from_zone_id + return get_street_instance_from_zone_id(zone_id) + + @classmethod + def get_street_by_world_id(cls, world_id: int) -> Street: + """get_street_by_world_id(world_id) + + Retrieve a Street instance using a World Id. + + :param world_id: The identifier of the World to use. + :type world_id: int + :return: The Street instance of the specified World. + :rtype: Street + """ + from world.street import get_street_instance_from_world_id + return get_street_instance_from_world_id(world_id) diff --git a/Scripts/s4ap/sims4communitylib/utils/location/common_terrain_utils.py b/Scripts/s4ap/sims4communitylib/utils/location/common_terrain_utils.py new file mode 100644 index 0000000..a3fe36e --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/location/common_terrain_utils.py @@ -0,0 +1,14 @@ +""" +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 +""" + +from sims4communitylib.utils.terrain.common_terrain_location_utils import CommonTerrainLocationUtils as NewCommonTerrainLocationUtils + + +class CommonTerrainUtils(NewCommonTerrainLocationUtils): + """An obsolete utility for manipulating terrain location. Use CommonTerrainLocationUtils from sims4communitylib.utils.terrain.common_terrain_location_utils instead.""" + pass diff --git a/Scripts/s4ap/sims4communitylib/utils/location/common_travel_utils.py b/Scripts/s4ap/sims4communitylib/utils/location/common_travel_utils.py new file mode 100644 index 0000000..e021320 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/location/common_travel_utils.py @@ -0,0 +1,80 @@ +""" +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 +""" +from sims.sim_info import SimInfo +from sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils + + +class CommonTravelUtils: + """Utilities for moving Sims around. + + """ + + @staticmethod + def get_travel_group_id(sim_info: SimInfo) -> int: + """get_travel_group_id(sim_info) + + Retrieve a decimal identifier for the Travel Group of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The decimal identifier of the Travel Group of the Sim or -1 if a problem occurs. + :rtype: int + """ + if sim_info is None: + return -1 + return sim_info.travel_group_id + + @staticmethod + def travel_to_lot(sim_info: SimInfo, lot_id: int): + """travel_to_lot(sim_info, lot_id) + + Travel with the specified Sim to the Lot with the specified identifier. + + :param sim_info: The Sim to travel with. + :type sim_info: SimInfo + :param lot_id: The identifier of the lot to travel to. + :type lot_id: int + """ + sim_info.send_travel_switch_to_zone_op(zone_id=lot_id) + + @staticmethod + def travel_to_zone(sim_info: SimInfo, zone_id: int): + """travel_to_zone(sim_info, zone_id) + + Travel with the specified Sim to a Zone. + + :param sim_info: The Sim to travel with. + :type sim_info: SimInfo + :param zone_id: The identifier of the zone to travel to. + :type zone_id: int + """ + sim_info.send_travel_switch_to_zone_op(zone_id=zone_id) + + @staticmethod + def travel_to_home_lot_of(sim_info: SimInfo): + """travel_to_home_lot_of(sim_info) + + Travel to the home lot of a Sim. + + :param sim_info: The owner of the home lot to travel to. + :type sim_info: SimInfo + """ + lot_id = CommonHouseholdUtils.get_household_zone_id(sim_info) + CommonTravelUtils.travel_to_lot(sim_info, lot_id) + + @staticmethod + def travel_to_home_lot_of_active_sim(sim_info: SimInfo): + """travel_to_home_lot_of_active_sim(sim_info) + + Travel with the specified Sim to the home lot of the Active Sim. + + :param sim_info: The Sim to travel with. + :type sim_info: SimInfo + """ + lot_id = CommonHouseholdUtils.get_household_home_zone_id(CommonHouseholdUtils.get_active_household()) + CommonTravelUtils.travel_to_lot(sim_info, lot_id) diff --git a/Scripts/s4ap/sims4communitylib/utils/math/__init__.py b/Scripts/s4ap/sims4communitylib/utils/math/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/math/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/utils/math/common_bitwise_utils.py b/Scripts/s4ap/sims4communitylib/utils/math/common_bitwise_utils.py new file mode 100644 index 0000000..e3d9c89 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/math/common_bitwise_utils.py @@ -0,0 +1,110 @@ +""" +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 +""" +from typing import Union, Tuple, TypeVar + +from sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags +from sims4communitylib.utils.common_collection_utils import CommonCollectionUtils + +CommonEnumFlagsTypeValueType = TypeVar('CommonEnumFlagsTypeValueType', int, CommonIntFlags) + + +class CommonBitwiseUtils: + """Utilities for performing bitwise operations, so you do not have to remember how they are done.""" + + @staticmethod + def add_flags(value: CommonEnumFlagsTypeValueType, flags: Union[CommonEnumFlagsTypeValueType, Tuple[CommonEnumFlagsTypeValueType]]) -> CommonEnumFlagsTypeValueType: + """add_flags(value, flags) + + Add Flags to a value. + + :param value: A flags enum or an integer. + :type value: CommonEnumFlagsTypeValueType + :param flags: A flags enum, an integer, or a collection of flags enums or integers. + :type flags: Union[CommonIntFlags, int, Tuple[CommonEnumFlagsTypeValueType]] + :return: The new value. + :rtype: CommonEnumFlagsTypeValueType + """ + if CommonCollectionUtils.is_collection(value): + for _flags in flags: + value = CommonBitwiseUtils.add_flags(value, _flags) + return value + return value | flags + + @staticmethod + def remove_flags(value: CommonEnumFlagsTypeValueType, flags: Union[CommonIntFlags, int, Tuple[CommonEnumFlagsTypeValueType]]) -> CommonEnumFlagsTypeValueType: + """remove_flags(value, flags) + + Remove Flags from a value. + + :param value: A flags enum or an integer. + :type value: CommonEnumFlagsTypeValueType + :param flags: A flags enum, an integer, or a collection of flags enums or integers. + :type flags: Union[CommonIntFlags, int, Tuple[CommonEnumFlagsTypeValueType]] + :return: The new value. + :rtype: CommonEnumFlagsTypeValueType + """ + if CommonCollectionUtils.is_collection(flags): + for _flags in flags: + value = CommonBitwiseUtils.remove_flags(value, _flags) + return value + return value & ~flags + + @staticmethod + def contains_all_flags(value: CommonEnumFlagsTypeValueType, flags: Union[CommonIntFlags, int, Tuple[CommonEnumFlagsTypeValueType]]) -> bool: + """contains_all_flags(value, flags) + + Determine if all of the Flags are found within a value. + + :param value: A flags enum or an integer. + :type value: CommonEnumFlagsTypeValueType + :param flags: A flags enum, an integer, or a collection of flags enums or integers. + :type flags: Union[CommonIntFlags, int, Tuple[CommonEnumFlagsTypeValueType]] + :return: True, if all of the specified Flags are found within the value. False, if not. + :rtype: bool + """ + if CommonCollectionUtils.is_collection(flags): + for _flags in flags: + if not CommonBitwiseUtils.contains_all_flags(value, _flags): + return False + return True + return flags == (flags & value) + + @staticmethod + def contains_any_flags(value: CommonEnumFlagsTypeValueType, flags: Union[CommonIntFlags, int, Tuple[CommonEnumFlagsTypeValueType]]) -> bool: + """contains_any_flags(value, flags) + + Determine if any of the Flags are found within a value. + + :param value: A flags enum or an integer. + :type value: CommonEnumFlagsTypeValueType + :param flags: A flags enum, an integer, or a collection of flags enums or integers. + :type flags: Union[CommonIntFlags, int, Tuple[CommonEnumFlagsTypeValueType]] + :return: True, if any of the specified Flags are found within the value. False, if not. + :rtype: bool + """ + if CommonCollectionUtils.is_collection(flags): + for _flags in flags: + if CommonBitwiseUtils.contains_any_flags(value, _flags): + return True + return False + return (flags & value) != 0 + + @staticmethod + def contains_no_flags(value: CommonEnumFlagsTypeValueType, flags: Union[CommonIntFlags, int, Tuple[CommonEnumFlagsTypeValueType]]) -> bool: + """contains_no_flags(value, flags) + + Determine if none of the Flags are found within a value. + + :param value: A flags enum or an integer. + :type value: CommonEnumFlagsTypeValueType + :param flags: A flags enum, an integer, or a collection of flags enums or integers. + :type flags: Union[CommonIntFlags, int, Tuple[CommonEnumFlagsTypeValueType]] + :return: True, if none of the specified Flags are found within the value. False, if not. + :rtype: bool + """ + return not CommonBitwiseUtils.contains_any_flags(value, flags) diff --git a/Scripts/s4ap/sims4communitylib/utils/misc/__init__.py b/Scripts/s4ap/sims4communitylib/utils/misc/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/misc/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/utils/misc/common_camera_utils.py b/Scripts/s4ap/sims4communitylib/utils/misc/common_camera_utils.py new file mode 100644 index 0000000..3a8a606 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/misc/common_camera_utils.py @@ -0,0 +1,141 @@ +""" +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 +""" +from typing import Union + +from objects.game_object import GameObject +from server.client import Client +from sims.sim_info import SimInfo +from sims4communitylib.classes.math.common_vector3 import CommonVector3 +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + CommonConsoleCommandArgument +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.common_type_utils import CommonTypeUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + + +class CommonCameraUtils: + """ Utilities for controlling the camera. """ + @classmethod + def start_focus(cls, target: Union[SimInfo, GameObject, CommonVector3], follow: bool=True, client: Client=None) -> bool: + """start_focus(target, follow=True, client=None) + + Focus the player camera on something. + + :param target: The Target SimInfo, Game Object, or Position to focus the camera on. + :type target: Union[Sim, GameObject, CommonVector3] + :param follow: If True, the camera will follow the object after focusing on it. If False, the camera will not follow the object after focusing on it. Default is True. + :type follow: bool, optional + :param client: The client to focus on the Sim. If None, the active client will be used. Default is None. + :type client: Client, optional + :return: True, if the camera was focused on the specified target. + """ + if CommonTypeUtils.is_sim_or_sim_info(target): + cls.start_focus_on_sim(target, follow=follow, client=client) + elif CommonTypeUtils.is_game_object(target): + cls.start_focus_on_object(target, follow=follow) + elif isinstance(target, CommonVector3): + cls.start_focus_on_position(target, client=client) + else: + return False + return True + + @classmethod + def start_focus_on_sim(cls, sim_info: SimInfo, follow: bool=True, client: Client=None) -> None: + """start_focus_on_sim(sim_info, follow=True, client=None) + + Focus the player camera on a Sim. + + :param sim_info: The SimInfo of the Sim to focus the camera on. + :type sim_info: SimInfo + :param follow: If True, the camera will follow the object after focusing on it. If False, the camera will not follow the object after focusing on it. Default is True. + :type follow: bool, optional + :param client: The client to focus on the Sim. If None, the active client will be used. Default is None. + :type client: Client, optional + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return + from camera import focus_on_sim + focus_on_sim(sim=sim, follow=follow, client=client) + + @classmethod + def start_focus_on_position(cls, position: CommonVector3, client: Client=None) -> None: + """start_focus_on_position(position, client=None) + + Focus the player camera on a position. + + :param position: The position to focus the camera on. + :type position: CommonVector3 + :param client: The client to focus on the position. If None, the active client will be used. Default is None. + :type client: Client, optional + """ + from camera import focus_on_position + focus_on_position(position, client=client) + + @classmethod + def start_focus_on_object(cls, game_object: GameObject, follow: bool=True) -> None: + """start_focus_on_object(game_object, follow=True) + + Focus the player camera on a game object. + + :param game_object: The object to focus on. + :type game_object: GameObject + :param follow: If True, the camera will follow the object after focusing on it. If False, the camera will not follow the object after focusing on it. Default is True. + :type follow: bool, optional + """ + from camera import focus_on_object + focus_on_object(object=game_object, follow=follow) + + @classmethod + def stop_focus_on_object(cls, game_object: GameObject): + """stop_focus_on_object(game_object) + + Stop focusing the player camera on a game object. + + :param game_object: The object to stop focusing on. + :type game_object: GameObject + """ + from camera import cancel_focus + cancel_focus(object=game_object) + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.focus_on_object', + 'Move the camera to focus on an object.', + command_arguments=( + CommonConsoleCommandArgument('game_object', 'Game Object Id', 'The instance id of the object to focus on.'), + ) +) +def _common_focus_on_object_command(output: CommonConsoleCommandOutput, game_object: GameObject): + if game_object is None: + return + output(f'Attempting to focus the camera on object {game_object}.') + if CommonCameraUtils.start_focus(game_object): + output(f'SUCCESS: Successfully focused the camera on object {game_object}.') + else: + output(f'FAILED: Failed to focus the camera on object {game_object}.') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.focus_on_sim', + 'Move the camera to focus on a Sim.', + command_arguments=( + CommonConsoleCommandArgument('sim_info', 'Sim Name or Id', 'The instance id of the Sim to focus on.'), + ) +) +def _common_focus_on_sim_command(output: CommonConsoleCommandOutput, sim_info: SimInfo): + if sim_info is None: + return + output(f'Attempting to focus the camera on Sim {sim_info}.') + if CommonCameraUtils.start_focus(sim_info): + output(f'SUCCESS: Successfully focused the camera on Sim {sim_info}.') + else: + output(f'FAILED: Failed to focus the camera on Sim {sim_info}.') diff --git a/Scripts/s4ap/sims4communitylib/utils/misc/common_fire_utils.py b/Scripts/s4ap/sims4communitylib/utils/misc/common_fire_utils.py new file mode 100644 index 0000000..8efe1a9 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/misc/common_fire_utils.py @@ -0,0 +1,134 @@ +""" +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 +""" +from typing import Union, Tuple + +from objects.fire.fire import Fire +from objects.game_object import GameObject +from services.fire_service import FireService +from sims4communitylib.classes.math.common_location import CommonLocation + + +class CommonFireUtils: + """Utilities for manipulating fires.""" + + @classmethod + def has_active_fires(cls) -> bool: + """has_active_fires() + + Determine if Fires are currently blazing. + + :return: True, if fires are currently blazing somewhere. False, if not. + :rtype: bool + """ + fire_service = cls.get_fire_service() + if fire_service is None: + return False + return fire_service.fire_is_active + + @classmethod + def get_all_active_fires(cls) -> Tuple[Fire]: + """get_all_active_fires() + + Retrieve an instance of all active Fires. + + :return: A collection of fires currently active. + :rtype: Tuple[Fire] + """ + fire_service = cls.get_fire_service() + if fire_service is None: + return tuple() + return fire_service.fire_is_active + + @classmethod + def spawn_scorch_marks_at_location(cls, location: CommonLocation) -> bool: + """spawn_scorch_marks_at_location(location) + + Spawn scorch marks at a location. + + :param location: The location to spawn the scorch marks at. + :type location: CommonLocation + :return: True, if scorch marks were spawned successfully. False, if not. + :rtype: bool + """ + fire_service = cls.get_fire_service() + if fire_service is None: + return False + position = location.transform.translation + surface_id = location.routing_surface.secondary_id + return fire_service.add_scorch_mark(position, surface_id) + + @classmethod + def despawn_scorch_marks_at_location(cls, location: CommonLocation) -> bool: + """despawn_scorch_marks_at_location(location) + + Despawn scorch marks at a location. + + :param location: The location to despawn the scorch marks at. + :type location: CommonLocation + :return: True, if scorch marks were despawned successfully. False, if not. + :rtype: bool + """ + fire_service = cls.get_fire_service() + if fire_service is None: + return False + position = location.transform.translation + surface_id = location.routing_surface.secondary_id + return fire_service.remove_scorch_mark(position, surface_id) + + @classmethod + def is_fire_allowed_at_location(cls, location: CommonLocation, run_placement_tests: bool = True) -> bool: + """is_fire_allowed_at_location(location, run_placement_tests=True) + + Determine if Fires are allowed to be placed at a Location. + + :param location: The location to check. + :type location: CommonLocation + :param run_placement_tests: Set True to run placement tests for the fire. Set False to exclude running placement tests for the fire. Default is True. + :type run_placement_tests: bool, optional + :return: True, if fire can be spawned as the specified location. False, if not. + :rtype: bool + """ + transform = location.transform + routing_surface = location.routing_surface + fire_service = cls.get_fire_service() + if fire_service is None: + return False + return fire_service.is_fire_allowed(transform, routing_surface, run_placement_tests=run_placement_tests) + + @classmethod + def spawn_fires_on_object(cls, game_object: GameObject, number_of_fires: int = 1) -> bool: + """spawn_fires_on_object(game_object, number_of_fires=1) + + Spawn a number of fires on an object. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :param number_of_fires: The number of fires to spawn on the Object. Must be above zero. Default is 1. + :type number_of_fires: int, optional + :return: True, if fires have been spawned successfully. False, if not. + :rtype: bool + """ + if number_of_fires <= 0: + raise AssertionError('The number of fires to spawn must be above zero.') + fire_service = cls.get_fire_service() + if fire_service is None: + return False + fire_service.spawn_fire_at_object(game_object) + return True + + @classmethod + def get_fire_service(cls) -> Union[FireService, None]: + """get_fire_service() + + Retrieve the service that manages Fires. + + :return: A service that manages fires or None if not found. + :rtype: Union[FireService, None] + """ + import services + return services.get_fire_service() diff --git a/Scripts/s4ap/sims4communitylib/utils/misc/common_game_client_utils.py b/Scripts/s4ap/sims4communitylib/utils/misc/common_game_client_utils.py new file mode 100644 index 0000000..bb10857 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/misc/common_game_client_utils.py @@ -0,0 +1,104 @@ +""" +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 +""" +from typing import Union + +import services +from server.client import Client +from server.clientmanager import ClientManager +from sims.household import Household + + +class CommonGameClientUtils: + """ Utilities for getting information about the game client. """ + + @staticmethod + def get_first_game_client() -> Union[Client, None]: + """get_first_game_client() + + Retrieve an instance of the first available Game Client. + + :return: An instance of the first available Game Client or None if not found. + :rtype: Union[Client, None] + """ + client_manager = CommonGameClientUtils.get_game_client_manager() + if client_manager is None: + return None + return client_manager.get_first_client() + + @staticmethod + def get_first_game_client_id() -> Union[int, None]: + """get_first_game_client_id() + + Retrieve the id of the first available Game Client. + + :return: The id of the first available Game Client or None if not found. + :rtype: Union[int, None] + """ + client_manager = CommonGameClientUtils.get_game_client_manager() + if client_manager is None: + return None + return client_manager.get_first_client_id() + + @staticmethod + def get_game_client_by_household(household: Household) -> Union[Client, None]: + """get_game_client_by_household(household) + + Locate a Game Client by a Household. + + :return: The Game Client that matches the specified Household or None if not found. + :rtype: Union[Client, None] + """ + if household is None: + return None + client_manager = CommonGameClientUtils.get_game_client_manager() + if client_manager is None: + return None + return client_manager.get_client_by_household(household) + + @staticmethod + def get_game_client_by_household_id(household_id: int) -> Union[Client, None]: + """get_game_client_by_household_id(household_id) + + Locate a Game Client by a Household Id. + + :return: The Game Client that matches the specified Household Id or None if not found. + :rtype: Union[Client, None] + """ + if household_id is None: + return None + client_manager = CommonGameClientUtils.get_game_client_manager() + if client_manager is None: + return None + return client_manager.get_client_by_household_id(household_id) + + @staticmethod + def get_game_client_by_account_id(account_id: int) -> Union[Client, None]: + """get_game_client_by_account_id(account_id) + + Locate a Game Client by an Account Id. + + :return: The Game Client that matches the specified Account Id or None if not found. + :rtype: Union[Client, None] + """ + if account_id is None: + return None + client_manager = CommonGameClientUtils.get_game_client_manager() + if client_manager is None: + return None + return client_manager.get_client_by_account(account_id) + + @staticmethod + def get_game_client_manager() -> ClientManager: + """get_game_client_manager() + + Retrieve the manager that manages the Game Clients for the game. + + :return: The manager that manages the Game Clients for the game. + :rtype: ClientManager + """ + return services.client_manager() diff --git a/Scripts/s4ap/sims4communitylib/utils/misc/common_mod_identity_utils.py b/Scripts/s4ap/sims4communitylib/utils/misc/common_mod_identity_utils.py new file mode 100644 index 0000000..efec4d1 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/misc/common_mod_identity_utils.py @@ -0,0 +1,37 @@ +""" +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 +""" +from typing import Union, TYPE_CHECKING + +if TYPE_CHECKING: + from sims4communitylib.mod_support.mod_identity import CommonModIdentity + + +class CommonModIdentityUtils: + """Utilities for manipulating CommonModIdentity. + + """ + @classmethod + def determine_mod_name_from_identifier(cls, identifier: Union[str, 'CommonModIdentity'], include_version: bool=True) -> str: + """determine_mod_name_from_identifier(mod_identifier, include_version=True) + + Determine the name of a Mod using a mod identifier. + + :param identifier: The identifier of a Mod. + :type identifier: Union[str, 'CommonModIdentity'] + :param include_version: If True and the identifier is a CommonModIdentity object, the version will be included in the mod name. If False, it will not be. + :return: The name of the Mod or 'Unknown_Mod' if the name could not be determined. + :rtype: str + """ + from sims4communitylib.mod_support.mod_identity import CommonModIdentity + if identifier is None: + return 'Unknown_Mod' + if isinstance(identifier, CommonModIdentity): + return identifier.name.replace(' ', '_').replace(':', '_').replace('//', '_').replace('\\', '_') + (('_' + identifier.version.replace(':', '_').replace('//', '_').replace('\\', '_')) if identifier.version is not None and include_version else '') + if isinstance(identifier, str): + return identifier.replace(' ', '_').replace(':', '_').replace('//', '_').replace('\\', '_') + return str(identifier).replace(' ', '_').replace(':', '_').replace('//', '_').replace('\\', '_') diff --git a/Scripts/s4ap/sims4communitylib/utils/misc/common_text_utils.py b/Scripts/s4ap/sims4communitylib/utils/misc/common_text_utils.py new file mode 100644 index 0000000..1681a4c --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/misc/common_text_utils.py @@ -0,0 +1,70 @@ +""" +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 +""" + + +class CommonTextUtils: + """Utilities for manipulating text.""" + @staticmethod + def capitalize(value: str) -> str: + """capitalize(value) + + Capitalize the first character of a value. + + :param value: The value to modify. + :type value: str + :return: The text, but with the first character capitalized. + :rtype: str + """ + if not value: + return value + return value[:1].upper() + value[1:] + + @staticmethod + def proper_case_hex(hex_value: str) -> str: + """proper_case_hex(hex_value) + + Modify the casing of a hex value so that everything after the "0x" portion is capitalized. + + :param hex_value: The value to modify. + :type hex_value: str + :return: The value, but with everything after the "0x" portion capitalized. + :rtype: str + """ + if not hex_value: + return hex_value + return hex_value[:2] + hex_value[2:].upper() + + @staticmethod + def convert_to_hex32_string(value: int) -> str: + """convert_to_hex32_string(value) + + Convert a value into a 32 bit hexadecimal string. This function will keep any leading or trailing zeros. + + :param value: The value to convert. + :type value: int + :return: The value as a Hexadecimal string. + :rtype: str + """ + if value is None: + raise AssertionError('value was None!') + return f'0x{value:08X}' + + @staticmethod + def to_truncated_decimal(value: float, num_of_decimal_points: int = 2) -> str: + """to_truncated_decimal(value, num_of_decimal_points=2) + + Create a string of a float value with a number of decimal points truncated. + + :param value: The value to truncate. + :type value: float + :param num_of_decimal_points: The number of decimal places to leave in the string. Default is 2. + :type num_of_decimal_points: int, optional + :return: A string representation of the value truncated to the number of decimal places. + :rtype: str + """ + return f'{value:.{num_of_decimal_points}f}' diff --git a/Scripts/s4ap/sims4communitylib/utils/objects/__init__.py b/Scripts/s4ap/sims4communitylib/utils/objects/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/objects/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_household_utils.py b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_household_utils.py new file mode 100644 index 0000000..941dad3 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_household_utils.py @@ -0,0 +1,47 @@ +""" +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 +""" +from objects.game_object import GameObject + + +class CommonObjectHouseholdUtils: + """Utilities for manipulating Household ownership of Objects. + + """ + + @staticmethod + def set_owning_household_id(game_object: GameObject, household_id: int) -> bool: + """set_owning_household_id(game_object, household_id) + + Set the Household that owns the Object. + .. note: THIS FUNCTION IS OBSOLETE PLEASE USE See :class:`.CommonObjectOwnershipUtils` for updated functions. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :param household_id: The decimal identifier of a Household. + :type household_id: int + :return: True, if the Household was successfully set as the owner. False, if not. + :rtype: bool + """ + from sims4communitylib.utils.objects.common_object_ownership_utils import CommonObjectOwnershipUtils + return CommonObjectOwnershipUtils.set_owning_household_id(game_object, household_id) + + @staticmethod + def get_owning_household_id(game_object: GameObject) -> int: + """get_owning_household_id(game_object) + + Retrieve the decimal identifier of the Household that owns the Object. + + .. note: THIS FUNCTION IS OBSOLETE PLEASE USE See :class:`.CommonObjectOwnershipUtils` for updated functions. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: The decimal identifier of the Household that owns the object. + :rtype: int + """ + from sims4communitylib.utils.objects.common_object_ownership_utils import CommonObjectOwnershipUtils + return CommonObjectOwnershipUtils.get_owning_household_id(game_object) diff --git a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_interaction_utils.py b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_interaction_utils.py new file mode 100644 index 0000000..4a3865f --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_interaction_utils.py @@ -0,0 +1,326 @@ +""" +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 +""" +from pprint import pformat +from typing import Callable, Iterator, List, Union +from interactions.base.interaction import Interaction +from objects.game_object import GameObject +from objects.script_object import ScriptObject +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.logging.has_class_log import HasClassLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + CommonConsoleCommandArgument +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.common_log_utils import CommonLogUtils +from sims4communitylib.utils.common_type_utils import CommonTypeUtils +from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils +from sims4communitylib.utils.resources.common_interaction_utils import CommonInteractionUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + + +class CommonObjectInteractionUtils(HasClassLog): + """Utilities for manipulating the interactions of Objects. + + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + return ModInfo.get_identity() + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 'common_object_interaction_utils' + + @staticmethod + def get_all_interactions_registered_to_object_gen(script_object: ScriptObject, include_interaction_callback: Callable[[Interaction], bool] = None) -> Iterator[Interaction]: + """get_all_interactions_registered_to_object_gen(script_object, include_interaction_callback=None) + + Retrieve all interactions that are registered to an object. + + :param script_object: An instance of a ScriptObject + :type script_object: ScriptObject + :param include_interaction_callback: If the result of this callback is True, the Interaction will be included in the results. If set to None, All Interactions will be included. Default is None. + :type include_interaction_callback: Callable[[Interaction], bool], optional + :return: An iterator of Interactions that pass the include callback filter. + :rtype: Iterator[Interaction] + """ + if script_object is None or not hasattr(script_object, '_super_affordances') or not script_object._super_affordances: + return tuple() + interactions = ( + *script_object._super_affordances, + ) + if hasattr(script_object, '_phone_affordances'): + interactions = ( + *interactions, + *script_object._phone_affordances + ) + if hasattr(script_object, '_relation_panel_affordances'): + interactions = ( + *interactions, + *script_object._relation_panel_affordances + ) + for interaction in interactions: + interaction: Interaction = interaction + if include_interaction_callback is not None and not include_interaction_callback(interaction): + continue + yield interaction + + @classmethod + def add_super_interaction_to_object(cls, script_object: ScriptObject, interaction_guid: int): + """add_super_interaction_to_object(script_object, interaction_guid) + + Add a super interaction to an object. + + :param script_object: The object to add the interaction to. + :type script_object: ScriptObject + :param interaction_guid: The GUID of the interaction to add. + :type interaction_guid: int + """ + return cls.add_super_interactions_to_object(script_object, (interaction_guid,)) + + @classmethod + def add_super_interactions_to_object(cls, script_object: ScriptObject, interaction_guids: Iterator[int]): + """add_super_interactions_to_object(script_object, interaction_guids) + + Add super interactions to an object. + + :param script_object: The object to add the interaction to. + :type script_object: ScriptObject + :param interaction_guids: The GUIDs of the interactions to add. + :type interaction_guids: Iterator[int] + """ + script_object_type = type(script_object) + cls.get_log().format_with_message('Adding interactions for type', script_object_type=script_object_type) + if not hasattr(script_object_type, '_super_affordances'): + cls.get_verbose_log().format_with_message('Object did not have super affordances.', script_object=script_object_type) + return + super_interactions_to_add = list() + affordance_manager = CommonInteractionUtils.get_instance_manager() + for affordance_id in interaction_guids: + affordance_instance = affordance_manager.get(affordance_id) + if affordance_instance is None: + continue + super_interactions_to_add.append(affordance_instance) + + new_super_affordances = list() + for super_interaction_instance in super_interactions_to_add: + if super_interaction_instance in new_super_affordances or super_interaction_instance in script_object_type._super_affordances: + cls.get_verbose_log().format_with_message('Interaction was already found in the interactions list.', script_object_type=script_object_type, interaction_instance=super_interaction_instance) + continue + new_super_affordances.append(super_interaction_instance) + if new_super_affordances: + cls.get_log().format_with_message('Adding super affordances to object.', script_object=script_object, script_object_type=script_object_type, new_super_affordances=new_super_affordances) + script_object_type._super_affordances += tuple(new_super_affordances) + else: + cls.get_log().format_with_message('No super affordances to add.', script_object=script_object, script_object_type=script_object_type, new_super_affordances=new_super_affordances) + + new_script_object_super_affordances = list() + for new_super_affordance in super_interactions_to_add: + if new_super_affordance in script_object._super_affordances: + continue + new_script_object_super_affordances.append(new_super_affordance) + if new_script_object_super_affordances: + script_object._super_affordances += tuple(new_script_object_super_affordances) + + @classmethod + def remove_super_interaction_from_terrain(cls, interaction_identifier: Union[int, Interaction]): + """remove_super_interaction_from_terrain(interaction_identifier) + + Remove a super interaction from the terrain. + + :param interaction_identifier: The GUID or instance of the interaction to remove. + :type interaction_identifier: Union[int, Interaction] + """ + return cls.remove_super_interactions_from_terrain((interaction_identifier,)) + + @classmethod + def remove_super_interactions_from_terrain(cls, interaction_identifiers: Iterator[Union[int, Interaction]]): + """remove_super_interactions_from_terrain(interaction_identifiers) + + Remove a super interaction from the terrain. + + :param interaction_identifiers: The GUIDs or instances of the interactions to remove. + :type interaction_identifiers: Iterator[Union[int, Interaction]] + """ + from services import get_terrain_service + terrain_service = get_terrain_service() + + interactions_to_remove = list() + for interaction_id in interaction_identifiers: + interaction = CommonInteractionUtils.load_interaction_by_id(interaction_id) + if interaction is not None: + interactions_to_remove.append(interaction) + + if not interactions_to_remove: + return None + + new_terrain_definition_class = terrain_service.TERRAIN_DEFINITION.cls + new_super_affordances = list() + current_super_affordances_list = list(new_terrain_definition_class._super_affordances) + for super_interaction in current_super_affordances_list: + if super_interaction in interactions_to_remove: + continue + new_super_affordances.append(super_interaction) + new_terrain_definition_class._super_affordances = tuple(new_super_affordances) + terrain_service.TERRAIN_DEFINITION.set_class(new_terrain_definition_class) + + @classmethod + def remove_super_interaction_from_ocean(cls, interaction_identifier: Union[int, Interaction]): + """remove_super_interaction_from_ocean(interaction_identifier) + + Remove a super interaction from the ocean. + + :param interaction_identifier: The GUID or instance of the interaction to remove. + :type interaction_identifier: Union[int, Interaction] + """ + return cls.remove_super_interactions_from_ocean((interaction_identifier,)) + + @classmethod + def remove_super_interactions_from_ocean(cls, interaction_identifiers: Iterator[Union[int, Interaction]]): + """remove_super_interactions_from_ocean(interaction_identifiers) + + Remove a super interaction from the ocean. + + :param interaction_identifiers: The GUIDs of the interactions or instances to remove. + :type interaction_identifiers: Iterator[Union[int, Interaction]] + """ + from services import get_terrain_service + terrain_service = get_terrain_service() + + interactions_to_remove = list() + for interaction_guid in interaction_identifiers: + interaction = CommonInteractionUtils.load_interaction_by_id(interaction_guid) + if interaction is not None: + interactions_to_remove.append(interaction) + + new_ocean_definition_class = terrain_service.OCEAN_DEFINITION.cls + new_super_affordances = list() + current_super_affordances_list = list(new_ocean_definition_class._super_affordances) + for super_interaction in current_super_affordances_list: + if super_interaction in interactions_to_remove: + continue + new_super_affordances.append(super_interaction) + new_ocean_definition_class._super_affordances = tuple(new_super_affordances) + terrain_service.OCEAN_DEFINITION.set_class(new_ocean_definition_class) + + @classmethod + def remove_super_interaction_from_object(cls, script_object: ScriptObject, interaction_guid: int): + """remove_super_interaction_from_object(script_object, interaction_guid) + + Remove a super interaction from an object. + + :param script_object: The object to remove the interaction from. + :type script_object: ScriptObject + :param interaction_guid: The GUID of the interaction to remove. + :type interaction_guid: int + """ + return cls.remove_super_interactions_from_object(script_object, (interaction_guid,)) + + @classmethod + def remove_super_interactions_from_object(cls, script_object: ScriptObject, interaction_guids: Iterator[int]): + """remove_super_interactions_from_object(script_object, interaction_guids) + + Remove a super interaction from an object. + + :param script_object: The object to remove the interaction from. + :type script_object: ScriptObject + :param interaction_guids: The GUIDs of the interactions to remove. + :type interaction_guids: Iterator[int] + """ + script_object_type = type(script_object) + cls.get_log().format_with_message('Removing interactions for type', script_object_type=script_object_type) + if not hasattr(script_object_type, '_super_affordances'): + cls.get_verbose_log().format_with_message('Object did not have super affordances.', script_object=script_object_type) + return + new_super_affordances = list(script_object_type._super_affordances) + current_super_affordances_list = list(script_object_type._super_affordances) + for super_interaction in current_super_affordances_list: + super_interaction_id = CommonInteractionUtils.get_interaction_id(super_interaction) + if super_interaction_id not in interaction_guids: + continue + new_super_affordances.remove(super_interaction) + script_object_type._super_affordances = tuple(new_super_affordances) + + new_object_super_affordances = list(script_object._super_affordances) + current_object_super_affordances_list = list(script_object._super_affordances) + for obj_super_interaction in current_object_super_affordances_list: + obj_super_interaction_id = CommonInteractionUtils.get_interaction_id(obj_super_interaction) + if obj_super_interaction_id not in interaction_guids: + continue + new_object_super_affordances.remove(obj_super_interaction) + script_object._super_affordances = tuple(new_object_super_affordances) + + @classmethod + def _log_all_interactions(cls, target_object: ScriptObject): + log = cls.get_log() + log.enable() + object_id = CommonObjectUtils.get_object_id(target_object) if target_object is not None else -1 + definition_id = -1 + if CommonTypeUtils.is_sim_or_sim_info(target_object): + # noinspection PyTypeChecker + object_id = CommonSimUtils.get_sim_id(target_object) + elif CommonTypeUtils.is_game_object(target_object): + # noinspection PyTypeChecker + definition = CommonObjectUtils.get_game_object_definition(target_object) + if definition is not None: + definition_id = definition.id + log.debug(f'Interactions that can be performed on \'{target_object}\' id:{object_id} def_id:{definition_id}:') + interactions = CommonObjectInteractionUtils.get_all_interactions_registered_to_object_gen(target_object) + # noinspection PyTypeChecker + target_object: GameObject = target_object + interaction_short_names: List[str] = list() + for interaction in interactions: + interaction: Interaction = interaction + try: + interaction_short_name = CommonInteractionUtils.get_interaction_short_name(interaction) + interaction_id = CommonInteractionUtils.get_interaction_id(interaction) + interaction_short_names.append(f'{interaction_short_name} ({interaction_id})') + except Exception as ex: + log.error('Problem while attempting to handle interaction {}'.format(pformat(interaction)), exception=ex) + continue + for component in target_object.components: + if not hasattr(component, 'component_super_affordances_gen'): + continue + for affordance in component.component_super_affordances_gen(): + try: + interaction_short_name = CommonInteractionUtils.get_interaction_short_name(affordance) + interaction_id = CommonInteractionUtils.get_interaction_id(affordance) + interaction_short_names.append(f'{interaction_short_name} ({interaction_id})') + except Exception as ex: + log.error(f'Problem while attempting to handle affordance {pformat(affordance)}', exception=ex) + continue + + sorted_short_names = sorted(interaction_short_names, key=lambda x: x) + log.format(interactions=sorted_short_names) + log.debug('Done Logging Available Interactions.') + log.disable() + CommonBasicNotification( + CommonStringId.S4CL_LOG_ALL_INTERACTIONS, + CommonStringId.S4CL_DONE_LOGGING_ALL_INTERACTIONS, + description_tokens=(CommonLogUtils.get_message_file_path(cls.get_mod_identity()), ) + ).show() + return True + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_testing.print_object_interactions', + 'Log all interactions an object has.', + command_arguments=( + CommonConsoleCommandArgument('game_object', 'Game Object Id', 'The instance id of the game object to check.'), + ) +) +def _s4clib_testing_print_all_interactions(output: CommonConsoleCommandOutput, game_object: GameObject): + if game_object is None: + return + output(f'Logging interactions of {game_object}') + CommonObjectInteractionUtils._log_all_interactions(game_object) diff --git a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_inventory_utils.py b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_inventory_utils.py new file mode 100644 index 0000000..cae831d --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_inventory_utils.py @@ -0,0 +1,214 @@ +""" +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 +""" +from typing import Callable, Iterator, Union +from interactions.base.create_object_interaction import ObjectDefinition +from objects.components.object_inventory_component import ObjectInventoryComponent +from objects.game_object import GameObject +from sims.sim_info import SimInfo +from sims4communitylib.classes.math.common_location import CommonLocation +from sims4communitylib.enums.types.component_types import CommonComponentType +from sims4communitylib.utils.common_component_utils import CommonComponentUtils +from sims4communitylib.utils.objects.common_object_spawn_utils import CommonObjectSpawnUtils +from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils + + +class CommonObjectInventoryUtils: + """ Utilities for manipulating the inventory of Objects. """ + @staticmethod + def has_inventory(game_object: GameObject) -> bool: + """has_inventory(game_object) + + Determine if an Object has an inventory. + + :param game_object: An instance of a Game Object. + :type game_object: GameObject + :return: True, if the Sim has an inventory. False, if not. + :rtype: bool + """ + return CommonObjectInventoryUtils._get_inventory(game_object) is not None + + @staticmethod + def get_all_objects_in_inventory_gen(game_object: GameObject, include_object_callback: Callable[[GameObject], bool]=None) -> Iterator[GameObject]: + """get_all_objects_in_inventory_gen(game_object, include_object_callback=None) + + Retrieve all Objects in the inventory of an Object. + + :param game_object: An instance of a Game Object. + :type game_object: GameObject + :param include_object_callback: If the result of this callback is True, the object will be included in the results. If set to None, All objects in the inventory will be included. + :type include_object_callback: Callable[[int], bool], optional + :return: An iterator containing the decimal identifiers for the objects in the inventory of an Object. + :rtype: Iterator[GameObject] + """ + inventory_component: ObjectInventoryComponent = CommonObjectInventoryUtils._get_inventory(game_object) + if inventory_component is None: + return tuple() + if include_object_callback is None: + for inventory_object in inventory_component: + yield inventory_object + else: + for inventory_object in inventory_component: + if include_object_callback(inventory_object): + yield inventory_object + + @staticmethod + def move_object_to_inventory(game_object_container: GameObject, game_object_to_move: GameObject) -> bool: + """move_object_to_inventory(game_object_container, game_object_to_move) + + Move an Object to the inventory of an Object container. + + :param game_object_container: The Object container to receive the moved Object. + :type game_object_container: GameObject + :param game_object_to_move: The Object to move. + :type game_object_to_move: GameObject + :return: True, if the object was successfully moved to the inventory of the specified Object container. False, if not. + :rtype: bool + """ + if game_object_container is None or game_object_to_move is None: + return False + inventory_component = CommonObjectInventoryUtils._get_inventory(game_object_container) + if inventory_component is None: + return False + from sims4communitylib.utils.objects.common_object_ownership_utils import CommonObjectOwnershipUtils + CommonObjectOwnershipUtils.set_owning_household_id(game_object_to_move, CommonObjectOwnershipUtils.get_owning_household_id(game_object_container)) + return inventory_component.player_try_add_object(game_object_to_move) + + @staticmethod + def add_to_inventory(game_object: GameObject, object_id: int, count: int=1) -> bool: + """add_to_inventory(game_object, object_definition_id, count=1) + + Add a number of Newly Created Objects to the Inventory of an Object. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :param object_id: The decimal identifier of an Object. + :type object_id: int + :param count: The number of the specified Object to add. Default is 1. + :type count: int, optional + :return: True, if the count of the specified Object were added successfully. False, it not. + :rtype: bool + """ + inventory_component: ObjectInventoryComponent = CommonObjectInventoryUtils._get_inventory(game_object) + if inventory_component is None: + return False + + def _post_create(_game_object: GameObject) -> bool: + return CommonObjectInventoryUtils.move_object_to_inventory(game_object, _game_object) + + success = True + for _ in range(count): + game_object = CommonObjectSpawnUtils.spawn_object_on_lot(object_id, CommonLocation.empty(), post_object_spawned_callback=_post_create) + if game_object is None: + success = False + return success + + @staticmethod + def remove_from_inventory_by_id(game_object: GameObject, object_id: int, count: int = 1) -> bool: + """remove_from_inventory_by_id(game_object, object_id, count=1) + + Remove a number of Objects by their Id from the inventory of an Object. + + :param game_object: The Object to remove Objects from. + :type game_object: GameObject + :param object_id: The decimal identifier of an Object. + :type object_id: int + :param count: The amount of the Object to remove. Default is 1. + :type count: int, optional + :return: True, if the count of the specified Object were removed successfully. False, if not. + """ + inventory_component: ObjectInventoryComponent = CommonObjectInventoryUtils._get_inventory(game_object) + if inventory_component is None: + return False + return inventory_component.try_remove_object_by_id(object_id, count=count) + + @staticmethod + def remove_from_inventory_by_definition(game_object: GameObject, object_definition: ObjectDefinition, count: int = 1) -> bool: + """remove_from_inventory(game_object, object_id, count=1) + + Remove a number of Objects from the inventory of an Object. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :param object_definition: The definition of an Object. + :type object_definition: ObjectDefinition + :param count: The amount of the Object to remove. Default is 1. + :type count: int, optional + :return: True, if the count of the specified Object were removed successfully. False, if not. + """ + def _include_object_callback(_game_object: GameObject) -> bool: + return _game_object.definition == object_definition + + inventory_objects = CommonObjectInventoryUtils.get_all_objects_in_inventory_gen(game_object, include_object_callback=_include_object_callback) + for inventory_object in inventory_objects: + object_id = CommonObjectUtils.get_object_id(inventory_object) + if CommonObjectInventoryUtils.remove_from_inventory_by_id(game_object, object_id, count=count): + return True + return False + + @staticmethod + def get_count_of_object_in_inventory(game_object: GameObject, object_id: int) -> int: + """get_count_of_object_in_inventory(game_object, object_id) + + Count the number of an Object in the inventory of an Object. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :param object_id: The decimal identifier of an object. + :type object_id: int + :return: The number of a particular Object found in the inventory of the specified Object. + :type: int + """ + inventory_component: ObjectInventoryComponent = CommonObjectInventoryUtils._get_inventory(game_object) + if inventory_component is None: + return 0 + object_definition = CommonObjectUtils.get_object_definition(object_id) + return inventory_component.get_count(object_definition) + + @staticmethod + def open_inventory(game_object: GameObject) -> None: + """open_inventory(game_object) + + Open the inventory of an Object. + + :param game_object: The Object to open the inventory of. + :type game_object: GameObject + """ + if game_object is None: + return + inventory_component: ObjectInventoryComponent = CommonObjectInventoryUtils._get_inventory(game_object) + if inventory_component is None: + return + inventory_component.open_ui_panel() + + @staticmethod + def set_ownership_of_all_items_in_object_inventory_to_sim(game_object: GameObject, sim_info: SimInfo) -> bool: + """set_ownership_of_all_items_in_object_inventory_to_sim(game_object, sim_info) + + Change the ownership status of all items in the inventory of an Object to be owned by the household of a Sim. + + :param game_object: The objects in the inventory of this Object will become owned by the household of the Sim + :type game_object: GameObject + :param sim_info: The household of this Sim will be the new owner for all items in the inventory of the Object. + :type sim_info: SimInfo + :return: True, if ownership was transferred successfully. False, if not. + :rtype: bool + """ + if game_object is None or sim_info is None: + return False + inventory_component: ObjectInventoryComponent = CommonObjectInventoryUtils._get_inventory(game_object) + if inventory_component is None: + return False + + from sims4communitylib.utils.objects.common_object_ownership_utils import CommonObjectOwnershipUtils + for inventory_object in inventory_component: + CommonObjectOwnershipUtils.set_owning_sim(inventory_object, sim_info) + return True + + @staticmethod + def _get_inventory(game_object: GameObject) -> Union[ObjectInventoryComponent, None]: + return CommonComponentUtils.get_component(game_object, CommonComponentType.INVENTORY) diff --git a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_location_utils.py b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_location_utils.py new file mode 100644 index 0000000..5b0184a --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_location_utils.py @@ -0,0 +1,389 @@ +""" +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 +""" +from objects.game_object import GameObject +from typing import Union +from objects.components.live_drag_component import LiveDragComponent +from sims.sim_info import SimInfo +from sims4communitylib.classes.math.common_location import CommonLocation +from sims4communitylib.classes.math.common_quaternion import CommonQuaternion +from sims4communitylib.classes.math.common_surface_identifier import CommonSurfaceIdentifier +from sims4communitylib.classes.math.common_vector3 import CommonVector3 +from sims4communitylib.enums.types.component_types import CommonComponentType +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + CommonConsoleCommandArgument +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.common_component_utils import CommonComponentUtils +from sims4communitylib.utils.location.common_location_utils import CommonLocationUtils +from sims4communitylib.utils.objects.common_object_type_utils import CommonObjectTypeUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from world.lot import Lot + + +class CommonObjectLocationUtils: + """Utilities for manipulating the location and draggability of Objects. + + """ + + @staticmethod + def enable_object_drag_in_live_mode(game_object: GameObject) -> bool: + """enable_object_drag_in_live_mode(game_object) + + Enable the draggability of an Object in Live Mode. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if successful. False, if not. + :rtype: bool + """ + if game_object is None: + return False + live_drag_component: LiveDragComponent = CommonComponentUtils.get_component(game_object, CommonComponentType.LIVE_DRAG) + if live_drag_component is None: + return False + live_drag_component._set_can_live_drag(True) + return True + + @staticmethod + def disable_object_drag_in_live_mode(game_object: GameObject) -> bool: + """disable_object_drag_in_live_mode(game_object) + + Disable the draggability an Object in Live Mode. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if successful. False, if not. + :rtype: bool + """ + if game_object is None: + return False + live_drag_component: LiveDragComponent = CommonComponentUtils.get_component(game_object, CommonComponentType.LIVE_DRAG) + if live_drag_component is None: + return False + live_drag_component._set_can_live_drag(False) + return True + + @staticmethod + def is_within_range_of_position(game_object: GameObject, position: CommonVector3, distance_in_squares: float) -> bool: + """is_within_range_of_position(game_object, position, distance_in_squares) + + Determine if a Game Object is within a certain distance of a Position. + + :param game_object: The object to check. + :type game_object: GameObject + :param position: A position. + :type position: CommonVector3 + :param distance_in_squares: A unit measured in squares. 1 square is the size of 1 square in the Build/Buy mode visual grid. For comparison, a dining chair would be 1 square by 1 square. 0.5 would be half a square, or half a dining chair. + :type distance_in_squares: float + :return: True, if the distance between the Object and the Position is less than or equal to the specified distance in squares. False, if not. + :return: bool + """ + object_position = CommonObjectLocationUtils.get_position(game_object) + if object_position is None: + return False + return CommonLocationUtils.is_position_within_range_of_position(object_position, position, distance_in_squares) + + @staticmethod + def is_within_range_of_location(game_object: GameObject, location: CommonLocation, distance_in_squares: float) -> bool: + """is_within_range_of_location(game_object, location, distance_in_squares) + + Determine if a Game Object is within a certain distance of a Location. + + :param game_object: The object to check. + :type game_object: GameObject + :param location: A location. + :type location: CommonLocation + :param distance_in_squares: A unit measured in squares. 1 square is the size of 1 square in the Build/Buy mode visual grid. For comparison, a dining chair would be 1 square by 1 square. 0.5 would be half a square, or half a dining chair. + :type distance_in_squares: float + :return: True, if the distance between the Object and the Location is less than or equal to the specified distance in squares. False, if not. + :return: bool + """ + object_location = CommonObjectLocationUtils.get_location(game_object) + if object_location is None: + return False + return CommonLocationUtils.is_location_within_range_of_location(object_location, location, distance_in_squares) + + @staticmethod + def is_on_current_lot(game_object: GameObject) -> bool: + """is_on_current_lot(game_object) + + Determine if a Sim is on the active Lot. + + :param game_object: The object to check. + :type game_object: GameObject + :return: True, if the Object is on the active Lot. False, if not. + :rtype: bool + """ + active_lot = CommonLocationUtils.get_current_lot() + return CommonObjectLocationUtils.is_on_lot(game_object, active_lot) + + @staticmethod + def is_on_lot(game_object: GameObject, lot: Lot) -> bool: + """is_on_lot(sim_info, lot) + + Determine if a Game Object is on a Lot. + + :param game_object: The object to check. + :type game_object: GameObject + :param lot: An instance of a Lot. + :type lot: Lot + :return: True, if the Object is on the specified Lot. False, if not. + :rtype: bool + """ + object_position = CommonObjectLocationUtils.get_position(game_object) + if object_position is None: + return False + return CommonLocationUtils.is_position_on_lot(object_position, lot) + + @staticmethod + def can_drag_object_in_live_mode(game_object: GameObject) -> bool: + """can_live_drag(game_object) + + Determine if an Object can be dragged in Live Mode. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if the Object can be dragged in Live Mode. False, if not. + :rtype: bool + """ + if game_object is None: + return False + live_drag_component: LiveDragComponent = CommonComponentUtils.get_component(game_object, CommonComponentType.LIVE_DRAG) + if live_drag_component is None: + return False + return live_drag_component.can_live_drag + + @staticmethod + def set_location(game_object: GameObject, location: CommonLocation) -> bool: + """set_location(game_object, location) + + Set the location of an Object. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :param location: The location to put the Object. + :type location: CommonLocation + :return: True, if successful. False, if not. + :rtype: bool + """ + if game_object is None or location is None: + return False + game_object.location = location + return True + + @staticmethod + def get_location(game_object: GameObject) -> Union[CommonLocation, None]: + """get_location(game_object) + + Retrieve the location of an Object. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: The location of the Object or None if the Object does not have a location. + :rtype: Union[CommonLocation, None] + """ + if game_object is None: + return None + return CommonLocation.from_location(game_object.location) + + @staticmethod + def get_position(game_object: GameObject) -> Union[CommonVector3, None]: + """get_position(game_object) + + Retrieve the position of an Object. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: The position of the Object or None if the Object does not have a position. + :rtype: CommonVector3 + """ + if game_object is None: + return None + # noinspection PyBroadException + try: + return CommonVector3.from_vector3(game_object.position) + except: + return None + + @staticmethod + def get_bone_position(game_object: GameObject, bone_name: str) -> Union[CommonVector3, None]: + """get_bone_position(game_object, bone_name) + + Retrieve the position of a joint bone on an Object. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :param bone_name: The name of the bone to retrieve the position of. + :type bone_name: str + :return: The position of the Object or None if the Object does not have the specified bone. + :rtype: Union[CommonVector3, None] + """ + # noinspection PyBroadException + try: + return CommonVector3.from_vector3(game_object.get_joint_transform_for_joint(bone_name).translation) + except: + return None + + @staticmethod + def get_root_position(game_object: GameObject) -> CommonVector3: + """get_root_position(game_object) + + Calculate the position of an Object based off of the position of it's Root bone. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: The position of the Object based off of the position of it's Root bone. + :rtype: CommonVector3 + """ + object_position = CommonObjectLocationUtils.get_bone_position(game_object, bone_name='b__ROOT__') or CommonObjectLocationUtils.get_position(game_object) + if object_position is not None and CommonObjectTypeUtils.is_window(game_object): + # For whatever reason, windows have a Y coordinate of -0.0. We fix it here. + object_position = CommonVector3(object_position.x, CommonLocationUtils.get_surface_height_at(object_position.x, object_position.z, CommonObjectLocationUtils.get_routing_surface(game_object)), object_position.z) + return object_position + + @staticmethod + def get_forward_vector(game_object: GameObject) -> CommonVector3: + """get_forward_vector(game_object) + + Retrieve the forward vector of an Object. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: The forward vector of the Object. + :rtype: CommonVector3 + """ + return CommonVector3.from_vector3(game_object.forward) + + @staticmethod + def get_orientation(game_object: GameObject) -> CommonQuaternion: + """get_orientation(game_object) + + Retrieve the orientation of an Object. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: The orientation of the Object. + :rtype: CommonQuaternion + """ + return CommonQuaternion.from_quaternion(game_object.orientation) + + @staticmethod + def get_orientation_degrees(game_object: GameObject) -> float: + """get_orientation_in_degrees(game_object) + + Retrieve the orientation of an Object in degrees. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: The orientation of the Object represented in degrees. + :rtype: float + """ + return CommonQuaternion.to_degrees(CommonObjectLocationUtils.get_orientation(game_object)) + + @staticmethod + def get_routing_surface(game_object: GameObject) -> Union[CommonSurfaceIdentifier, None]: + """get_routing_surface(game_object) + + Retrieve the routing surface of an Object. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: The routing surface of the object or None if a problem occurs. + :rtype: Union[CommonSurfaceIdentifier, None] + """ + if game_object is None: + return None + return CommonSurfaceIdentifier.from_surface_identifier(game_object.routing_surface) + + @staticmethod + def get_surface_level(game_object: GameObject) -> int: + """get_surface_level(game_object) + + Retrieve the surface level of an Object. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: The surface level of the object. + :rtype: int + """ + if game_object is None: + return 0 + routing_surface = CommonObjectLocationUtils.get_routing_surface(game_object) + if not routing_surface: + return 0 + return routing_surface.secondary_id + + @staticmethod + def can_be_routed_to(game_object: GameObject) -> bool: + """can_be_routed_to(game_object) + + Determine if an Object can be routed to by Sims. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if the Object can be routed to by Sims. False, it not. + :rtype: bool + """ + position = CommonObjectLocationUtils.get_position(game_object) + CommonObjectLocationUtils.get_forward_vector(game_object) + routing_surface = CommonObjectLocationUtils.get_routing_surface(game_object) + return CommonLocationUtils.can_position_be_routed_to(position, routing_surface) + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.move_object_to_sim', + 'Move a game object to the current location of a Sim.', + command_arguments=( + CommonConsoleCommandArgument('game_object', 'Game Object Instance Id', 'The instance id of a game object to move.'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to move the object to.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.moveobjecttosim', + ) +) +def _common_move_object_to_sim(output: CommonConsoleCommandOutput, game_object: GameObject, sim_info: SimInfo = None): + if sim_info is None: + output('ERROR: No Sim was specified or the specified Sim was not found!') + return + if game_object is None: + output('ERROR: No object was specified or the specified Game Object was not found.') + return + output(f'Attempting to move object {game_object} to Sim {sim_info}.') + from sims4communitylib.utils.sims.common_sim_location_utils import CommonSimLocationUtils + if CommonObjectLocationUtils.set_location(game_object, CommonSimLocationUtils.get_location(sim_info)): + output(f'SUCCESS: Object {game_object} was moved successfully to Sim {sim_info}.') + else: + output(f'FAILED: Object {game_object} failed to move to Sim {sim_info}') + output(f'Done moving object {game_object}.') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.print_bone_position_on_sim', + 'Print the position of a bone on a Sim.', + command_arguments=( + CommonConsoleCommandArgument('bone_name', 'Text', 'The name of a bone on the rig.'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of a Sim.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.printbonepositiononsim', + ) +) +def _common_print_bone_position(output: CommonConsoleCommandOutput, bone_name: str, sim_info: SimInfo = None): + if sim_info is None: + output('ERROR: No Sim was specified or the specified Sim was not found!') + return + if bone_name is None: + output('ERROR: No bone name was specified.') + return + sim = CommonSimUtils.get_sim_instance(sim_info) + bone_position = CommonObjectLocationUtils.get_bone_position(sim, bone_name) + if bone_position is None: + output(f'Bone {bone_name} not found on Sim {sim_info}.') + else: + output(f'Got bone position. X: {bone_position.x} Y: {bone_position.y} Z: {bone_position.z}') diff --git a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_lock_utils.py b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_lock_utils.py new file mode 100644 index 0000000..2779db3 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_lock_utils.py @@ -0,0 +1,198 @@ +""" +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 +""" +from typing import Union, Callable, Iterator + +from objects.components.locking_components import BaseLockingComponent +from objects.components.portal_lock_data import LockResult, IndividualSimDoorLockData +from objects.components.portal_locking_enums import LockPriority, LockSide, ClearLock +from objects.doors.door import Door +from objects.game_object import GameObject +from sims.sim_info import SimInfo +from sims4communitylib.enums.types.component_types import CommonComponentType +from sims4communitylib.utils.common_component_utils import CommonComponentUtils +from sims4communitylib.utils.common_type_utils import CommonTypeUtils +from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils + + +class CommonObjectLockUtils: + """ Utilities for manipulating the locking component of Objects, such as the ones found on Doors. """ + + @staticmethod + def is_door_locked_for_sim( + door: Door, + sim_info: SimInfo + ) -> bool: + """is_door_locked_for_sim(door, sim_info) + + Determine if a Door is locked for a Sim. + + :param door: An instance of a Door. + :type door: Door + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: True, if the Door is locked for the specified Sim. False, if not. + :rtype: bool + """ + return bool(CommonObjectLockUtils.test_door_lock_for_sim(door, sim_info)) + + @staticmethod + def test_door_lock_for_sim( + door: Door, + sim_info: SimInfo + ) -> LockResult: + """test_door_lock_for_sim(door, sim_info) + + Determine if a door is locked for a Sim. + + :param door: An instance of a Door. + :type door: Door + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of the door being locked and which side it is on. + :rtype: bool + """ + if not CommonTypeUtils.is_door(door): + return LockResult(False) + if not CommonComponentUtils.has_component(door, CommonComponentType.PORTAL_LOCKING): + return LockResult(False) + return door.test_lock(sim_info) + + @staticmethod + def lock_door( + door: Door, + sim_info_list: Iterator[SimInfo], + lock_sides: LockSide=LockSide.LOCK_BOTH, + lock_priority: LockPriority=LockPriority.PLAYER_LOCK, + clear_existing_locks: ClearLock=ClearLock.CLEAR_OTHER_LOCK_TYPES, + replace_same_lock_type: bool=False + ) -> bool: + """lock_door(\ + door,\ + sim_info_list,\ + lock_priority=LockPriority.PLAYER_LOCK,\ + lock_sides=LockSide.LOCK_BOTH,\ + clear_existing_locks=ClearLock.CLEAR_OTHER_LOCK_TYPES,\ + replace_same_lock_type=False\ + ) + + Lock a Door for Sims. + + :param door: An instance of a Door. + :type door: Door + :param sim_info_list: A collection of Sims to lock the door for. + :type sim_info_list: Iterator[SimInfo] + :param lock_priority: The priority of the lock being locked. Default is LockPriority.PLAYER_LOCK. + :type lock_priority: LockPriority, optional + :param lock_sides: The side(s) of the door to lock. Default is Both Sides. + :type lock_sides: LockSide, optional + :param clear_existing_locks: The other types of locks to clear from the door when locking it. Default is ClearLock.CLEAR_OTHER_LOCK_TYPES. + :type clear_existing_locks: ClearLock, optional + :param replace_same_lock_type: Set to True to replace lock types that are the same. Set to False to keep lock types that are the same. Default is False. + :type replace_same_lock_type: bool, optional + :return: True, if the Door was locked successfully. False, if not. + :rtype: bool + """ + if not CommonTypeUtils.is_door(door): + return False + if not CommonComponentUtils.has_component(door, CommonComponentType.PORTAL_LOCKING): + return False + for sim_info in sim_info_list: + lock_data = IndividualSimDoorLockData(lock_sim=sim_info, lock_priority=lock_priority, lock_sides=lock_sides, should_persist=True) + door.add_lock_data(lock_data, replace_same_lock_type=replace_same_lock_type, clear_existing_locks=clear_existing_locks) + + @staticmethod + def unlock_door( + door: Door, + sim_info_list: Iterator[SimInfo], + unlock_sides: LockSide=LockSide.LOCK_BOTH, + lock_priority: LockPriority=LockPriority.PLAYER_LOCK, + clear_existing_locks: ClearLock=ClearLock.CLEAR_NONE + ) -> bool: + """unlock_door(\ + door,\ + sim_info_list,\ + lock_priority=LockPriority.PLAYER_LOCK,\ + unlock_sides=LockSide.LOCK_BOTH,\ + clear_existing_locks=ClearLock.CLEAR_NONE,\ + replace_same_lock_type=False\ + ) + + Unlock a Door for Sims. + + :param door: An instance of a Door. + :type door: Door + :param sim_info_list: A collection of Sims to lock the door for. + :type sim_info_list: Iterator[SimInfo] + :param lock_priority: The priority of the lock being unlocked. Default is LockPriority.PLAYER_LOCK. + :type lock_priority: LockPriority, optional + :param unlock_sides: The side(s) of the door to unlock. Default is Both Sides. + :type unlock_sides: LockSide, optional + :param clear_existing_locks: The other types of locks to clear from the door when unlocking it. Default is ClearLock.CLEAR_NONE. + :type clear_existing_locks: ClearLock, optional + :return: True, if the Door was unlocked successfully. False, if not. + :rtype: bool + """ + if not CommonTypeUtils.is_door(door): + return False + if not CommonComponentUtils.has_component(door, CommonComponentType.PORTAL_LOCKING): + return False + for sim_info in sim_info_list: + lock_data = IndividualSimDoorLockData(unlock_sim=sim_info, lock_priority=lock_priority, lock_sides=unlock_sides, should_persist=True) + door.add_lock_data(lock_data, replace_same_lock_type=False, clear_existing_locks=clear_existing_locks) + + @staticmethod + def refresh_portal_locks_on_all_objects(include_object_callback: Callable[[GameObject], bool]= None) -> bool: + """refresh_portal_locks_on_all_objects(include_object_callback=None) + + Refresh the Portal Locks on all Objects. + + :param include_object_callback: If the result of this callback is True, the Object will be have it's locks refreshed. If set to None, All Objects will have their locks refreshed. Default is None. + :type include_object_callback: Callable[[GameObject], bool], optional + :return: True, if the locks on all Objects were successfully refreshed. False, if not. + :rtype: bool + """ + all_successful = True + for game_object in CommonObjectUtils.get_instance_for_all_game_objects_generator(include_object_callback=include_object_callback): + if not CommonObjectLockUtils.refresh_portal_locks(game_object): + all_successful = False + return all_successful + + @staticmethod + def refresh_portal_locks(game_object: GameObject) -> bool: + """refresh_portal_locks(game_object) + + Refresh the Portal Locks of an Object. + + .. note:: If an Object cannot be locked, this function will do nothing. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if locks were refreshed successfully. False, if not. + :rtype: bool + """ + locking_component: BaseLockingComponent = CommonObjectLockUtils.get_portal_locking_component(game_object) + if locking_component is None: + return False + locking_component.refresh_locks() + return True + + @staticmethod + def get_portal_locking_component(game_object: GameObject) -> Union[BaseLockingComponent, None]: + """get_portal_locking_component(game_object) + + Retrieve the Portal Locking component of an Object. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: The Portal Locking component of the Object or None if an error occurs. + :rtype: Union[BaseLockingComponent, None] + """ + if game_object is None: + return None + result: BaseLockingComponent = CommonComponentUtils.get_component(game_object, CommonComponentType.PORTAL_LOCKING) + return result diff --git a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_ownership_utils.py b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_ownership_utils.py new file mode 100644 index 0000000..89d9621 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_ownership_utils.py @@ -0,0 +1,141 @@ +""" +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 +""" +from typing import Union + +from objects.components.ownable_component import OwnableComponent +from objects.game_object import GameObject +from sims.sim_info import SimInfo +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + CommonConsoleCommandArgument +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + + +class CommonObjectOwnershipUtils: + """Utilities for manipulating the ownership of Objects. + + """ + + @staticmethod + def set_owning_household_id(game_object: GameObject, household_id: int) -> bool: + """set_owning_household_id(game_object, household_id) + + Set the Household that owns the Object. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :param household_id: The decimal identifier of a Household. + :type household_id: int + :return: True, if the Household was successfully set as the owner. False, if not. + :rtype: bool + """ + if game_object is None or household_id == -1: + return False + game_object.set_household_owner_id(household_id) + return True + + @staticmethod + def get_owning_household_id(game_object: GameObject) -> int: + """get_owning_household_id(game_object) + + Retrieve the decimal identifier of the Household that owns the Object. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: The decimal identifier of the Household that owns the object. + :rtype: int + """ + if game_object is None: + return -1 + return game_object.get_household_owner_id() + + @staticmethod + def set_owning_sim(game_object: GameObject, sim_info: SimInfo, make_sim_sole_owner: bool = True) -> bool: + """set_owning_sim(game_object, sim_info, make_sim_sole_owner=True) + + Change the ownership of an Object to become owned by the household of a Sim and optional by the Sim themselves. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param make_sim_sole_owner: If True, the Sim will become the sole owner in their household of the Object (In addition to the household owning it). If False, only the household will own the Object. Default is True. + :type make_sim_sole_owner: bool, optional + :return: True, if ownership was transferred successfully. False, if not. + :rtype: bool + """ + if game_object is None or sim_info is None: + return False + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return False + game_object.update_ownership(sim, make_sim_owner=make_sim_sole_owner) + return True + + @staticmethod + def get_owning_sim(game_object: GameObject) -> Union[SimInfo, None]: + """get_owning_sim(game_object) + + Retrieve the Sim that owns an Object, if a Sim owns the Object. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: The SimInfo of the Sim that owns the specified Object or None if no Sim owns the Object. + :rtype: Union[SimInfo, None] + """ + if game_object is None: + return None + ownable_component: OwnableComponent = CommonObjectOwnershipUtils.get_ownable_component(game_object) + if ownable_component is None: + return None + return CommonSimUtils.get_sim_info(ownable_component.get_sim_owner_id()) + + @staticmethod + def get_ownable_component(game_object: GameObject) -> Union[OwnableComponent, None]: + """get_ownable_component(game_object) + + Retrieve the Ownable Component of an Object if it has one. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: The OwnableComponent of the Object or None if no OwnableComponent was found. + :rtype: Union[OwnableComponent, None] + """ + if game_object is None: + return None + if not hasattr(game_object, 'ownable_component'): + return None + return game_object.ownable_component + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.change_ownership', + 'Change the owner of an object to a Sim.', + command_arguments=( + CommonConsoleCommandArgument('game_object', 'Game Object Instance Id', 'The instance id of a game object to change.'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to become the new owner.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.changeownership', + ) +) +def _common_change_ownership(output: CommonConsoleCommandOutput, game_object: GameObject, sim_info: SimInfo = None): + if sim_info is None: + output('ERROR: No Sim was specified or the specified Sim was not found!') + return + if game_object is None: + output('ERROR: No object was specified or the specified Game Object was not found.') + return + output(f'Attempting to change the owner of object {game_object} to Sim {sim_info}.') + if CommonObjectOwnershipUtils.set_owning_sim(game_object, sim_info, make_sim_sole_owner=True): + output(f'SUCCESS: Object {game_object} successfully owned by Sim {sim_info}.') + else: + output(f'FAILED: Object {game_object} failed to change ownership to Sim {sim_info}.') + output(f'Done changing the ownership of object {game_object}.') diff --git a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_reservation_utils.py b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_reservation_utils.py new file mode 100644 index 0000000..337ade5 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_reservation_utils.py @@ -0,0 +1,190 @@ +""" +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 +""" +from typing import Union, Tuple, List, Iterator + +from objects.components.slot_component import SlotComponent +from objects.game_object import GameObject +from objects.part import Part +from objects.prop_object import BasicPropObject +from reservation.reservation_handler import _ReservationHandler +from reservation.reservation_result import ReservationResult +from sims.sim_info import SimInfo +from sims4communitylib.enums.common_slot_type import CommonSlotType +from sims4communitylib.enums.types.component_types import CommonComponentType +from sims4communitylib.utils.common_component_utils import CommonComponentUtils +from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + + +class CommonObjectReservationUtils: + """ Utilities for object reservations. """ + @staticmethod + def is_in_use(game_object: GameObject) -> bool: + """is_in_use(game_object) + + Determine if an Object is in use. + + :param game_object: An instance of an object. + :type game_object: GameObject + :return: True, if the object is in use. False, if not. + :rtype: bool + """ + if game_object is None: + return False + return game_object.self_or_part_in_use + + @staticmethod + def is_in_use_by(game_object: GameObject, sim_info: SimInfo) -> bool: + """is_in_use_by(game_object, sim_info) + + Determine if an Object is in use by the specified Sim. + + :param game_object: An instance of an object. + :type game_object: GameObject + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: True, if the object is in use by the specified Sim. False, if not. + :rtype: bool + """ + if game_object is None: + return False + from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return False + return game_object.in_use_by(sim) + + @staticmethod + def get_sims_using_object(game_object: GameObject) -> Tuple[SimInfo]: + """get_sims_using_object(game_object) + + Retrieve a collection of Sims using the object. + + :param game_object: An instance of an object. + :type game_object: GameObject + :return: A collection of Sims using the object. + :rtype: Tuple[SimInfo] + """ + from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + if game_object is None: + return tuple() + sim_info_user_list: List[SimInfo] = [] + for sim in game_object.get_users(sims_only=True): + sim_info_user_list.append(CommonSimUtils.get_sim_info(sim)) + return tuple(sim_info_user_list) + + @staticmethod + def can_be_reserved_by(game_object: GameObject, sim_info: SimInfo) -> bool: + """can_be_reserved_by(game_object, sim_info) + + Determine if an object can be reserved by the Sim. + + :param game_object: An instance of an object. + :type game_object: GameObject + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: True, if the object can be reserved. False, if not. + :rtype: bool + """ + reservation_sim_info_list = CommonObjectReservationUtils.get_sims_using_object(game_object) + if len(reservation_sim_info_list) > 1: + return False + if len(reservation_sim_info_list) == 1 and sim_info not in reservation_sim_info_list: + return False + return True + + @staticmethod + def has_all_free_slots(game_object: GameObject, slot_types: Iterator[CommonSlotType]=()) -> bool: + """has_all_free_slots(game_object, slot_types=()) + + Determine if an Object has all of the specified slots available for use. + + :param game_object: An instance of an object. + :type game_object: GameObject + :param slot_types: A collection of CommonSlotTypes. Default is an empty collection. + :type slot_types: Tuple[CommonSlotTypes], optional + :return: True, if all of the specified slots are free on the Object. False, if not. + :rtype: bool + """ + slot_types = tuple(slot_types) + game_object = CommonObjectUtils.get_root_parent(game_object) + slot_component: SlotComponent = CommonComponentUtils.get_component(game_object, CommonComponentType.SLOT) + if slot_component is None: + return True + for runtime_slot in slot_component.get_runtime_slots_gen(): + if runtime_slot.empty: + continue + if not slot_types: + return False + if not runtime_slot.slot_types: + continue + for slot_type in runtime_slot.slot_types: + if slot_type.__name__ in slot_types: + return False + return True + + @staticmethod + def begin_reservation(reservation_handler: _ReservationHandler) -> ReservationResult: + """begin_reservation(reservation_handler) + + Begin reservation for the specified reservation handler. + + :param reservation_handler: The reservation handler to start. + :type reservation_handler: _ReservationHandler + :return: The result of beginning the reservation. + :rtype: ReservationResult + """ + if reservation_handler is None: + return ReservationResult(False, 'No reservation handler specified.') + result = reservation_handler.begin_reservation() + if isinstance(result, bool): + return ReservationResult(result, 'Failed to reserve the object for some reason.') + return result + + @staticmethod + def end_reservation(reservation_handler: _ReservationHandler) -> ReservationResult: + """end_reservation(reservation_handler) + + End reservation for the specified reservation handler. + + :param reservation_handler: The reservation handler to end. + :type reservation_handler: _ReservationHandler + :return: The result of ending the reservation. + :rtype: bool + """ + if reservation_handler is None: + return ReservationResult(False, 'No reservation handler specified.') + return reservation_handler.end_reservation() + + @staticmethod + def create_reservation_handler( + object_instance: Union[GameObject, Part, BasicPropObject], + sim_info: SimInfo, + **kwargs + ) -> Union[_ReservationHandler, None]: + """create_reservation_handler(object_instance, sim_info, **kwargs) + + Create a reservation handler for a Sim to reserve an object. + + :param object_instance: An instance of an object. + :type object_instance: Union[GameObject, Part, BasicPropObject] + :param sim_info: An instance of a Sim. This Sim will be reserving the object. + :type sim_info: SimInfo + :param kwargs: Keyword arguments used when creating the reservation handler. + :type kwargs: Any + :return: An instance of a Reservation Handler or None if a problem occurs. + :rtype: Union[_ReservationHandler, None] + """ + if object_instance is None or sim_info is None: + return None + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return None + if not hasattr(object_instance, 'get_reservation_handler'): + return None + return object_instance.get_reservation_handler(sim, **kwargs) diff --git a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_slot_utils.py b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_slot_utils.py new file mode 100644 index 0000000..8268d63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_slot_utils.py @@ -0,0 +1,197 @@ +""" +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 +""" +from typing import Tuple, Union, List, Callable, Iterator + +from objects.base_object import BaseObject +from objects.components.slot_component import SlotComponent +from objects.game_object import GameObject +from objects.script_object import ScriptObject +from objects.slots import SlotType +from sims4communitylib.dtos.common_object_containment_slot import CommonObjectContainmentSlot +from sims4communitylib.enums.common_slot_type import CommonSlotType +from sims4communitylib.enums.types.component_types import CommonComponentType +from sims4communitylib.utils.common_component_utils import CommonComponentUtils +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils + +from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils + + +class CommonObjectSlotUtils: + """Utilities for manipulating object slots.""" + @classmethod + def get_containment_slots(cls, game_object: GameObject) -> Tuple[CommonObjectContainmentSlot]: + """get_containment_slots(game_object) + + Retrieve the containment slots of an object. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: A collection of containment slots on the specified object. + :rtype: Tuple[CommonObjectContainmentSlot] + """ + # noinspection PyTypeChecker + game_object: GameObject = CommonObjectUtils.get_root_parent(game_object) + slot_component = cls.get_slot_component(game_object) + if slot_component is None: + return tuple() + containment_slot_list: List[CommonObjectContainmentSlot] = list() + for (slot_hash, slot_types) in tuple(slot_component.get_containment_slot_infos()): + containment_slot_list.append(CommonObjectContainmentSlot(slot_hash, slot_types)) + return tuple(containment_slot_list) + + @classmethod + def get_slot_component(cls, game_object: GameObject) -> Union[SlotComponent, None]: + """get_slot_component(game_object) + + Retrieve the SlotComponent of an Object. + + :param game_object: An instance of an object. + :type game_object: GameObject + :return: The SlotComponent of the object or None if not found. + :rtype: bool + """ + if not CommonComponentUtils.has_component(game_object, CommonComponentType.SLOT): + return None + # noinspection PyTypeChecker + slot_component: SlotComponent = CommonComponentUtils.get_component(game_object, CommonComponentType.SLOT) + return slot_component + + @classmethod + def get_slot_name(cls, slot: SlotType) -> str: + """get_slot_name(slot) + + Retrieve the name of a slot. + + :param slot: The slot to use. + :type slot: SlotType + :return: The name of the slot or 'No Slot Name' if a problem occurs. + :rtype: str + """ + if slot is None: + return 'No Slot Name' + return slot.__name__ + + @classmethod + def get_first_connected_object_by_slot_name( + cls, + script_object: ScriptObject, + slot_name: CommonSlotType, + include_object_callback: Callable[[ScriptObject], bool] = None + ) -> Union[ScriptObject, None]: + """get_first_connected_object_by_slot_name(script_object, slot_name, include_object_callback=None) + + Get the first connected object by slot. + + .. note:: If only the first object found matching the slot type will be returned. + + :param script_object: The Object to locate connections with. + :type script_object: ScriptObject + :param slot_name: The name of the slot to locate a connected object at. + :type slot_name: CommonSlotType + :param include_object_callback: If the result of this callback is True, the Object will be included in the results. If set to None, All Objects will be included. Default is None. + :type include_object_callback: Callable[[ScriptObject], bool], optional + :return: The object connected to the specified object at the specified slot or None if no object is found. + :rtype: Union[ScriptObject, None] + """ + for child in cls.get_connected_objects_by_slot_name_gen( + script_object, + slot_name, + include_object_callback=include_object_callback + ): + return child + return None + + @classmethod + def get_connected_objects_by_slot_name_gen( + cls, + script_object: ScriptObject, + slot_name: CommonSlotType, + include_object_callback: Callable[[ScriptObject], bool] = None + ) -> Iterator[ScriptObject]: + """get_connected_objects_by_slot_generator(script_object, slot_name, include_object_callback=None) + + Get all connected objects by slot. + + :param script_object: The Object to locate connections with. + :type script_object: ScriptObject + :param slot_name: The name of the slot to locate a connected objects at. + :type slot_name: CommonSlotType + :param include_object_callback: If the result of this callback is True, the Object will be included in the results. If set to None, All Objects will be included. Default is None. + :type include_object_callback: Callable[[ScriptObject], bool], optional + :return: An iterator of objects connected to the specified object at the specified slot. + :rtype: Iterator[ScriptObject] + """ + if script_object is None: + return tuple() + + slot_name_str = str(slot_name) + with_slot_in_front_of_name = f'slot_{slot_name}' + + def _has_slot_name(_connected_object: ScriptObject) -> bool: + if not _connected_object.parent_slot: + return False + for _connected_object_slot_type in _connected_object.parent_slot.slot_types: + if cls.get_slot_name(_connected_object_slot_type) in (slot_name_str, with_slot_in_front_of_name): + return True + return False + + if include_object_callback is not None: + include_object_callback = CommonFunctionUtils.run_predicates_as_one((_has_slot_name, include_object_callback)) + else: + include_object_callback = _has_slot_name + + for connected_object in CommonObjectSlotUtils.get_all_connected_objects_gen( + script_object, + include_object_callback=include_object_callback + ): + yield connected_object + + @classmethod + def get_all_connected_objects_gen( + cls, + script_object: ScriptObject, + include_self: bool = False, + direct_connections_only: bool = False, + include_object_callback: Callable[[ScriptObject], bool] = None + ) -> Iterator[BaseObject]: + """get_all_connected_objects_generator(\ + script_object,\ + include_self=False,\ + direct_connections_only=False,\ + include_object_callback=None\ + ) + + Retrieve all objects connected to the specified Object. + + :param script_object: The Object to locate connections with. + :type script_object: ScriptObject + :param include_self: If True, then script_object will be included in the results. If False, script_object will not be included in the results. Default is False. + :type include_self: bool, optional + :param direct_connections_only: If True, then only directly connected objects will be included in the results. If False, all connected objects as well as all objects connected to those objects recursively will be included in the results. + :type direct_connections_only: bool, optional + :param include_object_callback: If the result of this callback is True, the Object will be included in the results. If set to None, All Objects will be included. Default is None. + :type include_object_callback: Callable[[ScriptObject], bool], optional + :return: An iterator of Objects connected to the specified Object. + :rtype: Iterator[BaseObject] + """ + if direct_connections_only: + if include_self: + yield script_object + for connected_object in script_object.children: + if connected_object is None: + continue + if include_object_callback is not None and not include_object_callback(connected_object): + continue + yield connected_object + else: + for connected_object in script_object.children_recursive_gen(include_self=include_self): + if connected_object is None: + continue + if include_object_callback is not None and not include_object_callback(connected_object): + continue + yield connected_object diff --git a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_spawn_utils.py b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_spawn_utils.py new file mode 100644 index 0000000..505a3a6 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_spawn_utils.py @@ -0,0 +1,462 @@ +""" +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 +""" +import random +from objects.object_enums import ItemLocation +from sims.sim_info import SimInfo +from typing import Any, Callable, Union, Tuple, Iterator +from sims4communitylib.classes.math.common_location import CommonLocation +from sims4communitylib.classes.math.common_transform import CommonTransform +from sims4communitylib.classes.math.common_vector3 import CommonVector3 +from sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog +from sims4communitylib.modinfo import ModInfo +from carry.carry_postures import CarryingObject +from objects.game_object import GameObject +from objects.object_enums import ResetReason +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + CommonConsoleCommandArgument +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.objects.common_object_ownership_utils import CommonObjectOwnershipUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + + +class CommonObjectSpawnUtils(_HasS4CLClassLog): + """Utilities for creating, spawning, and despawning Objects. + + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 'common_object_spawn_utils' + + @classmethod + def create_object( + cls, + object_definition_id: int, + on_object_initialize_callback: Callable[[GameObject], Any] = None, + post_object_spawned_callback: Callable[[GameObject], Any] = None, + location_type: ItemLocation = ItemLocation.ON_LOT, + **kwargs + ) -> Union[GameObject, None]: + """create_object(\ + object_definition_id,\ + on_object_initialize_callback=None,\ + post_object_spawned_callback=None,\ + location_type=ItemLocation.ON_LOT,\ + **kwargs\ + ) + + Create an Object. + + :param object_definition_id: The decimal identifier of the definition of an Object. + :type object_definition_id: int + :param on_object_initialize_callback: Called when initializing the Object. + :type on_object_initialize_callback: Callable[[GameObject], Any], optional + :param post_object_spawned_callback: Called after the Object was added. + :type post_object_spawned_callback: Callable[[GameObject], Any], optional + :param location_type: The location the object is intended to be spawned at. Default is on the lot. + :type location_type: ItemLocation, optional + :return: An instance of the created Object or None if not successfully created. + :rtype: GameObject + """ + from objects.system import create_object + return create_object( + object_definition_id, + init=on_object_initialize_callback, + post_add=post_object_spawned_callback, + loc_type=location_type, + **kwargs + ) + + @classmethod + def spawn_object_on_lot( + cls, + object_definition_id: int, + location: CommonLocation, + on_object_initialize_callback: Callable[[GameObject], Any] = None, + post_object_spawned_callback: Callable[[GameObject], Any] = None, + **kwargs + ) -> Union[GameObject, None]: + """spawn_object_on_lot(\ + object_definition_id,\ + location,\ + on_object_initialize_callback=None,\ + post_object_spawned_callback=None,\ + **kwargs\ + ) + + Spawn an Object on the current lot. + + :param object_definition_id: The decimal identifier of the definition of an Object. + :type object_definition_id: int + :param location: The location to spawn the Object at. + :type location: CommonLocation + :param on_object_initialize_callback: Called when initializing the Object. + :type on_object_initialize_callback: Callable[[GameObject], Any], optional + :param post_object_spawned_callback: Called after the Object was added to the lot. + :type post_object_spawned_callback: Callable[[GameObject], Any], optional + :return: An instance of the spawned Object or None if not successfully spawned. + :rtype: GameObject + """ + from sims4communitylib.utils.objects.common_object_location_utils import CommonObjectLocationUtils + game_object = cls.create_object( + object_definition_id, + on_object_initialize_callback=on_object_initialize_callback, + post_object_spawned_callback=post_object_spawned_callback, + location_type=ItemLocation.ON_LOT, + **kwargs + ) + if game_object is None: + return None + CommonObjectLocationUtils.set_location(game_object, location) + return game_object + + @classmethod + def spawn_object_near_location( + cls, + object_definition_id: int, + location: CommonLocation, + radius: int = 1, + on_object_initialize_callback: Callable[[GameObject], Any] = None, + post_object_spawned_callback: Callable[[GameObject], Any] = None, + **kwargs + ) -> GameObject: + """spawn_object_near_location(\ + object_definition_id,\ + location,\ + radius=1,\ + on_object_initialize_callback=None,\ + post_object_spawned_callback=None,\ + **kwargs + ) + + Spawn an Object near a location. + + :param object_definition_id: The decimal identifier of the definition of an Object. + :type object_definition_id: int + :param location: The location to spawn the Object at. + :type location: CommonLocation + :param radius: The radius at which the object may spawn in with the location at the center. Default is 1 square out. + :type radius: int, optional + :param on_object_initialize_callback: Called when initializing the Object. + :type on_object_initialize_callback: Callable[[GameObject], Any], optional + :param post_object_spawned_callback: Called after the Object was added to the lot. + :type post_object_spawned_callback: Callable[[GameObject], Any], optional + :return: An instance of the spawned Object or None if not successfully spawned. + :rtype: GameObject + """ + if location is None: + raise AssertionError('location was found to be None!') + current_translation = location.transform.translation + x = int(current_translation.x) + min_x = x - radius + max_x = x + radius + new_x = random.randint(min_x, max_x) + z = int(current_translation.z) + min_z = z - radius + max_z = z + radius + new_z = random.randint(min_z, max_z) + new_translation = CommonVector3(new_x, current_translation.y, new_z) + new_transform = CommonTransform( + new_translation, + location.transform.orientation + ) + parent_ref = None + if location.parent_ref is not None and hasattr(location.parent_ref, 'provided_routing_surface'): + parent_ref = location.parent_ref + new_location = CommonLocation( + new_transform, + location.routing_surface, + parent_ref=parent_ref, + joint_name_or_hash=location.joint_name_or_hash, + slot_hash=location.slot_hash + ) + return CommonObjectSpawnUtils.spawn_object_on_lot( + object_definition_id, + new_location, + on_object_initialize_callback=on_object_initialize_callback, + post_object_spawned_callback=post_object_spawned_callback, + **kwargs + ) + + @classmethod + def destroy_object(cls, game_object: GameObject, source: Any = None, cause: str = None, **kwargs) -> bool: + """destroy_object(game_object, source=None, cause=None, **kwargs) + + Destroy an Object. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :param source: The source of the destruction. + :type source: str, optional + :param cause: The cause of the destruction. + :type cause: str, optional + :return: True, if the Object was successfully destroyed. False, if not. + :rtype: bool + """ + if game_object is None: + return False + if game_object.is_in_inventory(): + inventory = game_object.get_inventory() + if inventory is None or inventory.owner is None: + game_object.destroy(source=source, cause=cause, **kwargs) + else: + from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils + object_id = CommonObjectUtils.get_object_id(game_object) + if game_object.is_in_sim_inventory(): + sim_info = CommonSimUtils.get_sim_info(inventory.owner) + from sims4communitylib.utils.sims.common_sim_inventory_utils import CommonSimInventoryUtils + CommonSimInventoryUtils.remove_from_inventory(sim_info, object_id, count=1) + else: + inventory_game_object = CommonObjectUtils.get_game_object(inventory.owner) + from sims4communitylib.utils.objects.common_object_inventory_utils import CommonObjectInventoryUtils + CommonObjectInventoryUtils.remove_from_inventory_by_id(inventory_game_object, object_id, count=1) + else: + game_object.destroy(source=source, cause=cause, **kwargs) + return True + + @classmethod + def schedule_object_for_destroy(cls, game_object: GameObject, source: Any = None, cause: str = None, on_destroyed: Callable[[], None] = None, **kwargs) -> bool: + """schedule_object_for_destroy(game_object, source=None, cause=None, on_destroyed=None, **kwargs) + + Schedule an Object to be destroyed. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :param source: The source of the destruction. Default is None. + :type source: str, optional + :param cause: The cause of the destruction. Default is None. + :type cause: str, optional + :param on_destroyed: A callback that occurs after the Object is destroyed. Default is None. + :type on_destroyed: Callable[[], None], optional + :return: True, if the Object was successfully scheduled for destruction. False, if not. + :rtype: bool + """ + if game_object is None: + return False + if game_object.is_in_inventory(): + inventory = game_object.get_inventory() + if inventory is None or inventory.owner is None: + game_object.schedule_destroy_asap(post_delete_func=on_destroyed, source=source, cause=cause, **kwargs) + else: + from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils + object_id = CommonObjectUtils.get_object_id(game_object) + if game_object.is_in_sim_inventory(): + sim_info = CommonSimUtils.get_sim_info(inventory.owner) + from sims4communitylib.utils.sims.common_sim_inventory_utils import CommonSimInventoryUtils + CommonSimInventoryUtils.remove_from_inventory(sim_info, object_id, count=1) + else: + inventory_game_object = CommonObjectUtils.get_game_object(inventory.owner) + from sims4communitylib.utils.objects.common_object_inventory_utils import CommonObjectInventoryUtils + CommonObjectInventoryUtils.remove_from_inventory_by_id(inventory_game_object, object_id, count=1) + else: + game_object.schedule_destroy_asap(post_delete_func=on_destroyed, source=source, cause=cause, **kwargs) + return True + + @classmethod + def soft_reset( + cls, + game_object: GameObject, + reset_reason: ResetReason = ResetReason.RESET_EXPECTED, + hard_reset_on_exception: bool = False, + source: Any = None, + cause: str = 'S4CL Soft Reset' + ) -> bool: + """soft_reset(game_object, reset_reason=ResetReason.RESET_EXPECTED, hard_reset_on_exception=False, source=None, cause=None) + + Perform a soft reset on an Object. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :param reset_reason: The reason for the reset. Default is ResetReason.RESET_EXPECTED. + :type reset_reason: ResetReason, optional + :param hard_reset_on_exception: If set to True, a hard reset of the Object will be attempted upon an error occurring. If set to False, nothing will occur if the reset failed. Default is False. + :type hard_reset_on_exception: bool, optional + :param source: The source of the reset. Default is the GameObject. + :type source: Any, optional + :param cause: The cause of the reset. Default is 'S4CL Soft Reset'. + :type cause: Any, optional + :return: True, if the reset was successful. False, if not. + :rtype: bool + """ + if game_object is None: + return True + # noinspection PyBroadException + try: + if game_object.parent is not None and game_object.parent.is_sim and not game_object.parent.posture_state.is_carrying(game_object): + CarryingObject.snap_to_good_location_on_floor( + game_object, + starting_transform=game_object.parent.transform, + starting_routing_surface=game_object.parent.routing_surface + ) + location = game_object.location + game_object.on_reset_send_op(reset_reason) + game_object.location = location + game_object.resend_location() + if game_object.routing_component is not None: + game_object.routing_component.on_reset_internal_state(reset_reason) + if game_object.idle_component is not None: + game_object.idle_component._refresh_active_idle() + if game_object.linked_object_component is not None: + game_object.linked_object_component._relink(update_others=True) + return True + except: + if hard_reset_on_exception: + return CommonObjectSpawnUtils.hard_reset(game_object, reset_reason=reset_reason, source=source, cause=cause) + return False + + @classmethod + def hard_reset(cls, game_object: GameObject, reset_reason: ResetReason = ResetReason.RESET_EXPECTED, source: Any = None, cause: str = 'S4CL Hard Reset') -> bool: + """hard_reset(game_object, reset_reason=ResetReason.RESET_EXPECTED, source=None, cause=None) + + Perform a hard reset on an Object. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :param reset_reason: The reason for the reset. Default is ResetReason.RESET_EXPECTED. + :type reset_reason: ResetReason, optional + :param source: The source of the reset. Default is the GameObject. + :type source: Any, optional + :param cause: The cause of the reset. Default is 'S4CL Hard Reset'. + :type cause: Any, optional + :return: True, if the reset was successful. False, if not. + :rtype: bool + """ + if game_object is None: + return True + # noinspection PyBroadException + try: + game_object.reset(reset_reason, source=source or game_object, cause=cause) + return True + except: + return False + + @classmethod + def fade_in(cls, game_object: GameObject, fade_duration: float = 1.0, immediate: bool = False, additional_channels: Iterator[Tuple[int, int, int]] = None): + """fade_in(game_object, fade_duration=1.0, immediate=False, additional_channels=None) + + Change the opacity of an Object from invisible to visible. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :param fade_duration: The number of milliseconds the fade effect should take to complete. Default is 1.0. + :type fade_duration: float, optional + :param immediate: If set to True, fade in will occur immediately. Default is False. + :type immediate: bool, optional + :param additional_channels: A collection of additional channels. The order of the inner tuple is Manager Id, Object Id, and Mask. Default is None. + :type additional_channels: Iterator[Tuple[int, int, int]], optional + """ + if game_object is None: + return + game_object.fade_in(fade_duration=fade_duration, immediate=immediate, additional_channels=additional_channels) + + @classmethod + def fade_out(cls, game_object: GameObject, fade_duration: float = 1.0, immediate: bool = False, additional_channels: Iterator[Tuple[int, int, int]] = None): + """fade_out(game_object, fade_duration=1.0, immediate=False, additional_channels=None) + + Change the opacity of an Object from visible to invisible. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :param fade_duration: The number of milliseconds the fade effect should take to complete. Default is 1.0. + :type fade_duration: float, optional + :param immediate: If set to True, fade out will occur immediately. Default is False. + :type immediate: bool, optional + :param additional_channels: A collection of additional channels. The order of the inner tuple is Manager Id, Object Id, and Mask. Default is None. + :type additional_channels: Iterator[Tuple[int, int, int]], optional + """ + if game_object is None: + return + game_object.fade_out(fade_duration=fade_duration, immediate=immediate, additional_channels=additional_channels) + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.spawn_object', + 'Spawn a Game Object at the feet of a Sim.', + command_arguments=( + CommonConsoleCommandArgument('object_definition_id', 'Decimal Identifier', 'The decimal identifier of the Object Definition for the object to spawn.'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to spawn the object at.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.spawnobject', + ) +) +def _common_spawn_object(output: CommonConsoleCommandOutput, object_definition_id: int, sim_info: SimInfo = None): + if object_definition_id <= 0: + output('ERROR: object_definition_id must be a positive number above zero.') + return + output('Attempting to spawn object on the current lot with id \'{}\'.'.format(object_definition_id)) + from sims4communitylib.utils.sims.common_sim_location_utils import CommonSimLocationUtils + from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils + sim_location = CommonSimLocationUtils.get_location(sim_info) + game_object = CommonObjectSpawnUtils.spawn_object_on_lot(object_definition_id, sim_location) + if game_object is not None: + game_object_id = CommonObjectUtils.get_object_id(game_object) + CommonObjectSpawnUtils.get_log().enable() + CommonObjectSpawnUtils.get_log().debug(f'Object {game_object} spawned successfully. Can you see it? Object Id: {game_object_id}') + CommonObjectSpawnUtils.get_log().disable() + output(f'SUCCESS: Object {game_object} spawned successfully. Can you see it? Object Id: {game_object_id}') + from sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils + CommonObjectOwnershipUtils.set_owning_household_id(game_object, CommonHouseholdUtils.get_household_id(sim_info)) + else: + output(f'ERROR: Failed to spawn object with definition id {object_definition_id}.') + output(f'Done spawning object {game_object}.') + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.fade_in_object', + 'Fade In an object.', + command_arguments=( + CommonConsoleCommandArgument('game_object', 'Game Object Instance Id', 'The instance id of a game object to fade in.'), + ), + command_aliases=( + 's4clib.fadeinobject', + ) +) +def _common_fade_in_object(output: CommonConsoleCommandOutput, game_object: GameObject): + if game_object is None: + return + game_object_str = str(game_object) + output(f'Attempting to fade in object \'{game_object_str}\'.') + + if CommonObjectSpawnUtils.fade_in(game_object, immediate=True): + output('Successfully faded in object.') + else: + output('Failed to fade in object.') + return True + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.destroy_object', + 'Destroy/Delete a game object.', + command_arguments=( + CommonConsoleCommandArgument('game_object', 'Game Object Instance Id', 'The instance id of a game object to destroy/delete.'), + ), + command_aliases=( + 's4clib.destroyobject', + ) +) +def _common_destroy_object(output: CommonConsoleCommandOutput, game_object: GameObject): + if game_object is None: + return + game_object_str = str(game_object) + output(f'Attempting to destroy object \'{game_object_str}\'.') + + def _on_destroyed() -> None: + output(f'SUCCESS: Object {game_object_str} successfully destroyed.') + + if CommonObjectSpawnUtils.schedule_object_for_destroy(game_object, source='S4CL Command', cause='S4CL Command', on_destroyed=_on_destroyed): + output(f'Successfully scheduled object {game_object} for destruction. Please wait.') + else: + output(f'FAILED: Failed to schedule object {game_object} for destruction.') + output(f'Done destroying or scheduling the destruction of object {game_object}.') diff --git a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_state_utils.py b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_state_utils.py new file mode 100644 index 0000000..5f38374 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_state_utils.py @@ -0,0 +1,734 @@ +""" +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 +""" +from typing import Union, Tuple, Dict + +from event_testing.resolver import SingleObjectResolver +from event_testing.tests import TestSetInstance +from objects.components.state import StateComponent, ObjectStateValue, ObjectState +from objects.game_object import GameObject +from server_commands.argument_helpers import TunableInstanceParam +from sims4.resources import Types +from sims4communitylib.enums.common_object_state_ids import CommonObjectStateId +from sims4communitylib.enums.common_object_state_value_ids import CommonObjectStateValueId +from sims4communitylib.enums.common_object_quality import CommonObjectQuality +from sims4communitylib.enums.statistics_enum import CommonStatisticId +from sims4communitylib.enums.types.component_types import CommonComponentType +from sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + CommonConsoleCommandArgument +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.common_component_utils import CommonComponentUtils +from sims4communitylib.utils.common_resource_utils import CommonResourceUtils +from sims4communitylib.utils.common_type_utils import CommonTypeUtils +from statistics.commodity import Commodity +from statistics.commodity_tracker import CommodityTracker + + +class CommonObjectStateUtils(_HasS4CLClassLog): + """ Utilities for manipulating the state of Objects. """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 'common_object_state_utils' + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + return ModInfo.get_identity() + + @staticmethod + def has_poor_quality(game_object: GameObject) -> bool: + """has_poor_quality(game_object) + + Determine if an object has poor quality. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if the specified Object has poor quality. False, if not. + :rtype: bool + """ + object_state = CommonObjectStateUtils.get_current_object_state(game_object, CommonObjectStateId.QUALITY) + return CommonObjectStateUtils.get_object_state_value_guid(object_state) == CommonObjectStateValueId.QUALITY_POOR + + @staticmethod + def has_normal_quality(game_object: GameObject) -> bool: + """has_normal_quality(game_object) + + Determine if an object has normal quality. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if the specified Object has normal quality. False, if not. + :rtype: bool + """ + object_state = CommonObjectStateUtils.get_current_object_state(game_object, CommonObjectStateId.QUALITY) + return CommonObjectStateUtils.get_object_state_value_guid(object_state) == CommonObjectStateValueId.QUALITY_NORMAL + + @staticmethod + def has_outstanding_quality(game_object: GameObject) -> bool: + """has_outstanding_quality(game_object) + + Determine if an object has outstanding quality. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if the specified Object has outstanding quality. False, if not. + :rtype: bool + """ + object_state = CommonObjectStateUtils.get_current_object_state(game_object, CommonObjectStateId.QUALITY) + return CommonObjectStateUtils.get_object_state_value_guid(object_state) == CommonObjectStateValueId.QUALITY_OUTSTANDING + + @staticmethod + def get_quality(game_object: GameObject) -> Union[CommonObjectQuality, None]: + """get_quality(game_object) + + Retrieve the Quality of an Object. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: The CommonObjectQuality that represents the quality of the Object, or None if the quality could not be determined. + :rtype: Union[CommonObjectQuality, None] + """ + if CommonObjectStateUtils.has_poor_quality(game_object): + return CommonObjectQuality.POOR + if CommonObjectStateUtils.has_normal_quality(game_object): + return CommonObjectQuality.NORMAL + if CommonObjectStateUtils.has_outstanding_quality(game_object): + return CommonObjectQuality.OUTSTANDING + return None + + @staticmethod + def get_quality_state(game_object: GameObject) -> Union[ObjectStateValue, None]: + """get_quality_state(game_object) + + Retrieve the Quality State of an Object. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: The quality state of the Object or None when not found. + :rtype: Union[ObjectStateValue, None] + """ + return CommonObjectStateUtils.get_current_object_state(game_object, CommonObjectStateId.QUALITY) + + @staticmethod + def set_quality(game_object: GameObject, quality: CommonObjectQuality) -> None: + """set_quality(game_object, quality) + + Set the quality of an object. + + :param game_object: The object to modify. + :type game_object: GameObject + :param quality: The quality to set. + :type quality: CommonObjectQuality + """ + quality_state = CommonObjectStateUtils.convert_quality_to_object_state_value(quality) + if quality_state is None: + return None + CommonObjectStateUtils.set_object_state(game_object, quality_state) + + @staticmethod + def convert_quality_to_object_state_value(value: 'CommonObjectQuality') -> Union[ObjectStateValue, None]: + """convert_quality_to_object_state_value(value) + + Convert CommonObjectQuality to an ObjectStateValue. + + :param value: The value to convert. + :type value: CommonObjectQuality + :return: The value translated to an ObjectStateValue, or None if the value could not be translated. + :rtype: Union[ObjectStateValue, None] + """ + if value is None: + return None + mapping: Dict[CommonObjectQuality, CommonObjectStateValueId] = { + CommonObjectQuality.POOR: CommonObjectStateValueId.QUALITY_POOR, + CommonObjectQuality.NORMAL: CommonObjectStateValueId.QUALITY_NORMAL, + CommonObjectQuality.OUTSTANDING: CommonObjectStateValueId.QUALITY_OUTSTANDING, + } + quality_state_value_id = mapping.get(value, None) + if quality_state_value_id is None: + return None + return CommonObjectStateUtils.load_object_state_value_by_id(quality_state_value_id) + + @staticmethod + def convert_quality_from_object_state_value(value: ObjectStateValue) -> Union['CommonObjectQuality', None]: + """convert_quality_from_object_state_value(value) + + Convert an ObjectStateValue to a matching CommonObjectQuality value. + + :param value: An instance of ObjectStateValue + :type value: ObjectStateValue + :return: The specified ObjectStateValue translated to CommonObjectQuality or None if the value could not be translated. + :rtype: Union['CommonObjectQuality', None] + """ + if value is None: + return None + if isinstance(value, CommonObjectQuality): + return value + mapping: Dict[int, CommonObjectQuality] = { + CommonObjectStateValueId.QUALITY_POOR: CommonObjectQuality.POOR, + CommonObjectStateValueId.QUALITY_NORMAL: CommonObjectQuality.NORMAL, + CommonObjectStateValueId.QUALITY_OUTSTANDING: CommonObjectQuality.OUTSTANDING, + } + object_state_value_id = CommonObjectStateUtils.get_object_state_value_guid(value) + return mapping.get(object_state_value_id, None) + + @staticmethod + def can_become_broken(game_object: GameObject) -> bool: + """can_become_broken(game_object) + + Determine if an Object is able to break. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if the specified Object is able to break. False, if not. + :rtype: bool + """ + if game_object is None or not hasattr(game_object, 'commodity_tracker'): + return False + if CommonTypeUtils.is_sim_or_sim_info(game_object): + return False + commodity: Commodity = CommonResourceUtils.load_instance(Types.STATISTIC, int(CommonStatisticId.OBJECT_BROKENNESS)) + commodity_tracker: CommodityTracker = game_object.commodity_tracker + if commodity_tracker is None: + return False + return commodity_tracker.has_statistic(commodity) + + @staticmethod + def can_become_dirty(game_object: GameObject) -> bool: + """can_become_dirty(game_object) + + Determine if an Object is able to get dirty. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if the specified Object is able to get dirty. False, if not. + :rtype: bool + """ + if game_object is None or not hasattr(game_object, 'commodity_tracker'): + return False + if CommonTypeUtils.is_sim_or_sim_info(game_object): + return False + commodity: Commodity = CommonResourceUtils.load_instance(Types.STATISTIC, int(CommonStatisticId.DIRTINESS)) + commodity_tracker: CommodityTracker = game_object.commodity_tracker + if commodity_tracker is None: + return False + return commodity_tracker.has_statistic(commodity) + + @staticmethod + def is_broken(game_object: GameObject) -> bool: + """is_broken(game_object) + + Determine if an Object is broken. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if the specified Object is broken. False, if not. + :rtype: bool + """ + if game_object is None or not hasattr(game_object, 'commodity_tracker'): + return False + if CommonTypeUtils.is_sim_or_sim_info(game_object): + return False + # testSet_StateBroken + test_set_instance: TestSetInstance = CommonResourceUtils.load_instance(Types.SNIPPET, 33738) + # noinspection PyUnresolvedReferences + tests: CompoundTestList = test_set_instance.test + resolver = SingleObjectResolver(game_object) + result = tests.run_tests(resolver) + return bool(result) + + @staticmethod + def is_dirty(game_object: GameObject) -> bool: + """is_dirty(game_object) + + Determine if an Object is dirty. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if the specified Object is dirty. False, if not. + :rtype: bool + """ + if game_object is None or not hasattr(game_object, 'commodity_tracker'): + return False + commodity: Commodity = CommonResourceUtils.load_instance(Types.STATISTIC, int(CommonStatisticId.DIRTINESS)) + commodity_tracker: CommodityTracker = game_object.commodity_tracker + if commodity_tracker is None: + return False + if not commodity_tracker.has_statistic(commodity): + return False + return commodity_tracker.get_value(commodity) == commodity.min_value + + @staticmethod + def break_object(game_object: GameObject) -> bool: + """break_object(game_object) + + Break an Object. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if the specified Object has been broken. False, if not. + :rtype: bool + """ + if game_object is None or not hasattr(game_object, 'commodity_tracker'): + return False + commodity: Commodity = CommonResourceUtils.load_instance(Types.STATISTIC, int(CommonStatisticId.OBJECT_BROKENNESS)) + commodity_tracker: CommodityTracker = game_object.commodity_tracker + if commodity_tracker is None: + return False + if not commodity_tracker.has_statistic(commodity): + return False + return commodity_tracker.set_min(commodity) + + @staticmethod + def fix_object(game_object: GameObject) -> bool: + """fix_object(game_object) + + Fix an Object. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if the specified Object has been fixed. False, if not. + :rtype: bool + """ + if game_object is None or not hasattr(game_object, 'commodity_tracker'): + return False + commodity: Commodity = CommonResourceUtils.load_instance(Types.STATISTIC, int(CommonStatisticId.OBJECT_BROKENNESS)) + commodity_tracker: CommodityTracker = game_object.commodity_tracker + if commodity_tracker is None: + return False + if not commodity_tracker.has_statistic(commodity): + return False + return commodity_tracker.set_max(commodity) + + @staticmethod + def make_dirty(game_object: GameObject) -> bool: + """make_dirty(game_object) + + Make an Object dirty. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if the specified Object has been made dirty. False, if not. + :rtype: bool + """ + if game_object is None or not hasattr(game_object, 'commodity_tracker'): + return False + commodity: Commodity = CommonResourceUtils.load_instance(Types.STATISTIC, int(CommonStatisticId.DIRTINESS)) + commodity_tracker: CommodityTracker = game_object.commodity_tracker + if commodity_tracker is None: + return False + if not commodity_tracker.has_statistic(commodity): + return False + return commodity_tracker.set_min(commodity) + + @staticmethod + def make_clean(game_object: GameObject) -> bool: + """make_clean(game_object) + + Make an Object clean. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if the specified Object has been made clean. False, if not. + :rtype: bool + """ + if game_object is None or not hasattr(game_object, 'commodity_tracker'): + return False + commodity: Commodity = CommonResourceUtils.load_instance(Types.STATISTIC, int(CommonStatisticId.DIRTINESS)) + commodity_tracker: CommodityTracker = game_object.commodity_tracker + if commodity_tracker is None: + return False + if not commodity_tracker.has_statistic(commodity): + return False + return commodity_tracker.set_max(commodity) + + @classmethod + def is_object_usable(cls, game_object: GameObject) -> bool: + """is_object_usable(game_object) + + Determine if an Object is in a usable state. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if the specified Object is in a usable state. False, if not. + :rtype: bool + """ + if game_object is None: + return False + state_component: StateComponent = cls.get_object_state_component(game_object) + if state_component is None: + return False + return bool(state_component.is_object_usable) + + @classmethod + def get_object_states(cls, game_object: GameObject) -> Tuple[ObjectStateValue]: + """get_object_states(game_object) + + Retrieve the state values of an Object. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: A collection of ObjectStateValues. + :rtype: Tuple[ObjectStateValue] + """ + if game_object is None: + return tuple() + state_component: StateComponent = cls.get_object_state_component(game_object) + if state_component is None: + return tuple() + return tuple(state_component.values()) + + @classmethod + def has_any_object_states(cls, game_object: GameObject, object_state_ids: Tuple[int]) -> bool: + """has_any_object_states(game_object, object_state_ids) + + Determine if an Object has any of the specified object states. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :param object_state_ids: A collection of decimal identifiers for object states. + :type object_state_ids: Tuple[int] + :return: True, if the object has any of the specified object states. False, if not. + :rtype: bool + """ + state_component: StateComponent = cls.get_object_state_component(game_object) + if state_component is None: + return False + if not object_state_ids: + return False + for state_value in state_component.values(): + if CommonObjectStateUtils.get_object_state_value_guid(state_value) in object_state_ids: + return True + return False + + @classmethod + def has_all_object_states(cls, game_object: GameObject, object_state_ids: Tuple[int]) -> bool: + """has_all_object_states(game_object, object_state_ids) + + Determine if an Object has all of the specified object states. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :param object_state_ids: A collection of decimal identifiers for object states. + :type object_state_ids: Tuple[int] + :return: True, if the object has all of the specified object states. False, if not. + :rtype: bool + """ + state_component: StateComponent = cls.get_object_state_component(game_object) + if state_component is None: + return False + if not object_state_ids: + return False + for state_value in state_component.values(): + if CommonObjectStateUtils.get_object_state_value_guid(state_value) not in object_state_ids: + return False + return True + + @classmethod + def get_object_state_guid(cls, object_state: ObjectState) -> Union[int, None]: + """get_object_state_guid(object_state) + + Retrieve the GUID of an object state. (Not to be confused with the instance id) + + :param object_state: An instance of an object state. + :type object_state: ObjectState + :return: The GUID of the state or None if no identifier is found. + :rtype: Union[int, None] + """ + return cls.get_object_state_value_guid(object_state) + + @classmethod + def get_object_state_value_guid(cls, object_state_value: ObjectStateValue) -> Union[int, None]: + """get_object_state_value_guid(object_state_value) + + Retrieve the GUID of an object state. (Not to be confused with the instance id) + + :param object_state_value: An instance of an object state. + :type object_state_value: ObjectStateValue + :return: The GUID of the state value or None if no identifier is found. + :rtype: Union[int, None] + """ + if object_state_value is None: + return None + return getattr(object_state_value, 'guid64', None) + + @staticmethod + def get_object_state_component(game_object: GameObject) -> Union[StateComponent, None]: + """get_object_state_component(game_object) + + Retrieve the State Component of an Object. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: The State Component of the specified Object or None if no state component is found. + :rtype: Union[StateComponent, None] + """ + if game_object is None: + return None + return CommonComponentUtils.get_component(game_object, CommonComponentType.STATE) + + @classmethod + def get_object_state_items(cls, game_object: GameObject) -> Dict[ObjectState, ObjectStateValue]: + """get_object_state_items(game_object) + + Retrieve all Object States of an objects. + + :param game_object: The object to check. + :type game_object: GameObject + :return: A mapping of Object State to the current value of the object state. + :rtype: Dict[ObjectState, ObjectStateValue] + """ + # noinspection PyTypeChecker + state_component: StateComponent = CommonObjectStateUtils.get_object_state_component(game_object) + if state_component is None: + cls.get_log().format_with_message('Object did not have a state component.', script_object=game_object) + return dict() + return state_component._states + + @classmethod + def has_object_state(cls, game_object: GameObject, object_state_identifier: Union[int, CommonObjectStateId, CommonObjectStateValueId, ObjectState, ObjectStateValue]) -> bool: + """has_object_state(game_object, object_state_identifier) + + Determine if an Object has an object state available. + + :param game_object: The Object to check. + :type game_object: GameObject + :param object_state_identifier: The identifier of the state to check. + :type object_state_identifier: Union[int, CommonObjectStateId, CommonObjectStateValueId, ObjectState, ObjectStateValue] + :return: True, if the Object has the specified object state as one of its available states (Not if the specified value is what the state on the object is set to). False, if not. + :rtype: bool + """ + if object_state_identifier is None: + cls.get_log().format_with_message('Specified object state identifier was None.', game_object=game_object, object_state_identifier=object_state_identifier) + return False + object_states = cls.get_object_state_items(game_object) + object_state = cls.load_object_state_by_id(object_state_identifier) + object_state_value = cls.load_object_state_value_by_id(object_state_identifier) + if object_state is None and object_state_value is not None: + object_state = object_state_value.state + else: + object_state = object_state.state + return object_state in object_states + + @classmethod + def has_object_state_value(cls, game_object: GameObject, object_state_value_identifier: Union[int, CommonObjectStateValueId, ObjectStateValue]) -> bool: + """has_object_state_value(game_object, object_state_value_identifier) + + Determine if an Object has a state set to an Object State Value + + :param game_object: The Object to check. + :type game_object: GameObject + :param object_state_value_identifier: The identifier of the object state value to check. + :type object_state_value_identifier: Union[int, CommonObjectStateValueId, ObjectStateValue] + :return: True, if the Object has the specified object state value set. False, if not. + :rtype: bool + """ + if object_state_value_identifier is None: + cls.get_log().format_with_message('Specified object state value identifier was None.', game_object=game_object, object_state_value_identifier=object_state_value_identifier) + return False + # noinspection PyTypeChecker + state_component: StateComponent = CommonObjectStateUtils.get_object_state_component(game_object) + if state_component is None: + cls.get_log().format_with_message('Object did not have a state component.', game_object=game_object, object_state_value_identifier=object_state_value_identifier) + return False + object_state_value = cls.load_object_state_value_by_id(object_state_value_identifier) + if object_state_value is None: + cls.get_log().format_with_message('Failed to locate object state value.', game_object=game_object, object_state_identifier=object_state_value_identifier) + return False + cls.get_log().format_with_message('Checking if object has state value.', target=game_object, state=object_state_value.state, state_value=object_state_value) + state_value = cls.get_current_object_state(game_object, object_state_value.state) + return cls.get_object_state_value_guid(state_value) == cls.get_object_state_value_guid(object_state_value) + + @classmethod + def set_object_state(cls, game_object: GameObject, object_state_value: Union[int, CommonObjectStateValueId, ObjectStateValue]): + """set_object_state(script_object, object_state) + + Set the object state of an Object. + + :param game_object: The Object to modify. + :type game_object: GameObject + :param object_state_value: The state to set. + :type object_state_value: Union[int, CommonObjectStateValueId, ObjectStateValue] + """ + if not cls.has_object_state(game_object, object_state_value): + cls.get_log().format_with_message('Object did not have the required state.') + return None + # noinspection PyTypeChecker + state_component: StateComponent = CommonObjectStateUtils.get_object_state_component(game_object) + if state_component is None: + cls.get_log().format_with_message('Object did not have a state component.', script_object=game_object, object_state=object_state_value) + return + object_state_value = cls.load_object_state_value_by_id(object_state_value) + if object_state_value is None: + cls.get_log().format_with_message('Failed to locate object state.', game_object=game_object, object_state_value=object_state_value) + return + cls.get_log().format_with_message('Setting state of object to value.', target=game_object, state=object_state_value.state, state_value=object_state_value) + state_component.set_state(object_state_value.state, object_state_value) + + @classmethod + def is_object_in_state(cls, game_object: GameObject, object_state_value: Union[int, CommonObjectStateValueId, ObjectStateValue]) -> bool: + """is_object_in_state(game_object, object_state_value) + + Determine if an object is in a state. + + :param game_object: The object to check. + :type game_object: GameObject + :param object_state_value: The object state value to check. + :type object_state_value: Union[int, CommonObjectStateValueId, ObjectStateValue] + :return: True, if the state of an object has the specified object state value. False, if not. + :rtype: bool + """ + object_state_value = cls.load_object_state_value_by_id(object_state_value) + if object_state_value is None: + return False + current_object_state_value = cls.get_current_object_state(game_object, object_state_value.state) + if current_object_state_value is None: + return False + return current_object_state_value == object_state_value + + @classmethod + def get_current_object_state(cls, game_object: GameObject, object_state: Union[int, CommonObjectStateId, ObjectState]) -> Union[ObjectStateValue, None]: + """get_current_object_state(game_object, object_state) + + Get the value of a state on an Object. + + :param game_object: The Object to change. + :type game_object: GameObject + :param object_state: The state to use. + :type object_state: Union[int, CommonObjectStateId, ObjectState] + :return: The value of the specified state on an Object or None if a problem occurs. + :rtype: Union[ObjectStateValue, None] + """ + # noinspection PyTypeChecker + state_component: StateComponent = CommonObjectStateUtils.get_object_state_component(game_object) + if state_component is None: + return None + object_state = cls.load_object_state_by_id(object_state) + if object_state is None: + return None + return state_component.get_state(object_state) + + @classmethod + def load_object_state_by_id(cls, object_state: Union[int, CommonObjectStateId, ObjectState]) -> Union[ObjectState, None]: + """load_object_state_by_id(object_state_value) + + Load an instance of an Object State by its identifier. + + :param object_state: The identifier of an Object State. + :type object_state: Union[int, CommonObjectStateId, ObjectState] + :return: An instance of an Object State Value matching the decimal identifier or None if not found. + :rtype: Union[ObjectState, None] + """ + if isinstance(object_state, ObjectStateValue): + return object_state + # noinspection PyBroadException + try: + object_state: int = int(object_state) + except: + # noinspection PyTypeChecker + object_state: ObjectState = object_state + return object_state + + from sims4.resources import Types + from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + result = CommonResourceUtils.load_instance(Types.OBJECT_STATE, object_state) + return result + + @classmethod + def load_object_state_value_by_id(cls, object_state_value: Union[int, CommonObjectStateValueId, ObjectStateValue]) -> Union[ObjectStateValue, None]: + """load_object_state_value_by_id(object_state_value) + + Load an instance of an Object State Value by its identifier. + + :param object_state_value: The identifier of an Object State Value. + :type object_state_value: Union[int, CommonObjectStateValueId, ObjectStateValue] + :return: An instance of an Object State Value matching the decimal identifier or None if not found. + :rtype: Union[ObjectStateValue, None] + """ + if isinstance(object_state_value, ObjectStateValue): + return object_state_value + # noinspection PyBroadException + try: + object_state_value: int = int(object_state_value) + except: + # noinspection PyTypeChecker + object_state_value: ObjectStateValue = object_state_value + return object_state_value + + from sims4.resources import Types + from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + result = CommonResourceUtils.load_instance(Types.OBJECT_STATE, object_state_value) + return result + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_testing.print_object_states', + 'Print all states of an object.', + command_arguments=( + CommonConsoleCommandArgument('game_object', 'Obj Id', 'The object to check.'), + ) +) +def _common_print_object_states(output: CommonConsoleCommandOutput, game_object: GameObject) -> bool: + log = CommonObjectStateUtils.get_log() + try: + log.enable() + object_state_values_by_object_state = CommonObjectStateUtils.get_object_state_items(game_object) + output(f'Printing game tags of {game_object}') + log.debug(f'------------------Object states for {game_object}------------------') + for (object_state, object_state_value) in object_state_values_by_object_state.items(): + object_state_value_guid = CommonObjectStateUtils.get_object_state_value_guid(object_state_value) + log.debug(f'[{object_state}]: Current: {object_state_value} ({object_state_value_guid})') + object_state: ObjectState = object_state + log.debug(f'----------{object_state} Valid Values----------') + for obj_state_value in object_state.values: + obj_state_value_guid = CommonObjectStateUtils.get_object_state_value_guid(obj_state_value) + log.debug(f'-- {obj_state_value} ({obj_state_value_guid})') + log.debug('-------------------') + log.debug('--------------------------------------------------------------------') + output('Done') + return True + finally: + log.disable() + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.set_object_state', + 'Set the state of an object.', + command_arguments=( + CommonConsoleCommandArgument('game_object', 'Obj Id', 'The object to set the state of.'), + CommonConsoleCommandArgument('object_state', 'Object State Id Or Name', 'The state to set the object to.'), + ) +) +def _common_set_object_state(output: CommonConsoleCommandOutput, game_object: GameObject, object_state: TunableInstanceParam(Types.OBJECT_STATE)) -> bool: + output('Setting object state.') + if not CommonObjectStateUtils.has_object_state(game_object, object_state): + output(f'Object {game_object} does not have state {object_state}.') + return False + CommonObjectStateUtils.set_object_state(game_object, object_state) + output('Done setting object state.') + return True + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.modify_object_state', + 'Modify the state of an object.', + command_arguments=( + CommonConsoleCommandArgument('game_object', 'Obj Id', 'The object to set the state of.'), + ) +) +def _common_modify_object_state(output: CommonConsoleCommandOutput, game_object: GameObject) -> bool: + output(f'Opening dialog to modify object state of {game_object}.') + from sims4communitylib.debug.dialogs.common_change_object_state_dialog import CommonChangeObjectStateDialog + CommonChangeObjectStateDialog(game_object).open() + return True diff --git a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_tag_utils.py b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_tag_utils.py new file mode 100644 index 0000000..6dc7c2f --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_tag_utils.py @@ -0,0 +1,167 @@ +""" +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 +""" +from distributor.shared_messages import IconInfoData +from objects.game_object import GameObject +from typing import Tuple, Set, Union, Iterator, List + +from objects.script_object import ScriptObject +from sims4communitylib.enums.tags_enum import CommonGameTag +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + CommonConsoleCommandArgument +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.common_log_registry import CommonLogRegistry +from sims4communitylib.utils.common_resource_utils import CommonResourceUtils +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils + + +class CommonObjectTagUtils: + """Utilities for manipulating the tags of objects. + + """ + + @classmethod + def has_game_tag(cls, game_object: Union[GameObject, ScriptObject], tag: Union[int, CommonGameTag]) -> bool: + """has_game_tag(game_object, tag) + + Determine if an Object has the specified tag. + + :param game_object: An instance of an Object. + :type game_object: Union[GameObject, ScriptObject] + :param tag: A tag to locate. + :type tag: Union[int, CommonGameTag] + :return: True, if the Object has the specified tag. False, if not. + :rtype: bool + """ + return CommonObjectTagUtils.has_game_tags(game_object, (tag,)) + + @classmethod + def has_game_tags(cls, game_object: Union[GameObject, ScriptObject], tags: Iterator[Union[int, CommonGameTag]]) -> bool: + """has_game_tags(game_object, tags) + + Determine if an Object has any of the specified tags. + + :param game_object: An instance of an Object. + :type game_object: Union[GameObject, ScriptObject] + :param tags: A collection of tags to locate. + :type tags: Iterator[Union[int, CommonGameTag]] + :return: True, if the Object has any of the specified tags. False, if not. + :rtype: bool + """ + if game_object is None or not hasattr(game_object, 'has_any_tag'): + return False + return game_object.has_any_tag(tuple(tags)) + + @classmethod + def get_game_tags(cls, game_object: Union[GameObject, ScriptObject]) -> Set[int]: + """get_game_tags(game_object) + + Retrieve the tags of an Object. + + :param game_object: An instance of an Object. + :type game_object: Union[GameObject, ScriptObject] + :return: A collection of tags the Object has. + :rtype: Set[int] + """ + if game_object is None or not hasattr(game_object, 'get_tags'): + return set() + return game_object.get_tags() + + @classmethod + def add_game_tags(cls, game_object: Union[GameObject, ScriptObject], tags: Tuple[Union[int, CommonGameTag]], persist: bool = False) -> bool: + """add_game_tags(game_object, tags, persist=False) + + Add tags to an Object. + + :param game_object: An instance of an Object. + :type game_object: Union[GameObject, ScriptObject] + :param tags: A collection of Game Tags to add. + :type tags: Tuple[Union[int, CommonGameTag]] + :param persist: If True, the Tags will persist to all instances of the Object. If False, the Tags will persist only to the specified Object. Default is False. + :type persist: bool, optional + :return: True, if the Tags were successfully added. False, if not. + :rtype: bool + """ + if game_object is None or not hasattr(game_object, 'append_tags'): + return False + game_object.append_tags(set(tags), persist=persist) + return True + + @classmethod + def remove_game_tags(cls, game_object: Union[GameObject, ScriptObject], tags: Tuple[Union[int, CommonGameTag]]) -> bool: + """remove_game_tags(game_object, tags) + + Remove tags from an Object. + + :param game_object: An instance of an Object. + :type game_object: Union[GameObject, ScriptObject] + :param tags: A collection of Game Tags to remove. + :type tags: Tuple[Union[int, CommonGameTag]] + :return: True, if the Tags were successfully removed. False, if not. + :rtype: bool + """ + if game_object is None or not hasattr(game_object, 'remove_dynamic_tags'): + return False + game_object.remove_dynamic_tags(set(tags)) + return True + + @classmethod + def _print_game_tags(cls, game_object: Union[GameObject, ScriptObject]) -> None: + obj_tags_list: List[str] = list() + for obj_tag in CommonObjectTagUtils.get_game_tags(game_object): + if not isinstance(obj_tag, CommonGameTag): + # noinspection PyTypeChecker + obj_tag = CommonResourceUtils.get_enum_by_int_value(obj_tag, CommonGameTag, default_value=obj_tag) + + if hasattr(obj_tag, 'name'): + obj_tag_name = obj_tag.name + else: + obj_tag_name = 'Unknown' + + obj_tags_list.append(f'{obj_tag_name} ({int(obj_tag)})') + + obj_tags_list = sorted(obj_tags_list, key=lambda x: x) + obj_tag_list_names = ',\n'.join(obj_tags_list) + text = '' + text += f'Game Tags:\n{obj_tag_list_names}\n\n' + from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils + game_object_id = CommonObjectUtils.get_object_id(game_object) + log.debug(f'Object {game_object} Tags ({game_object_id})') + log.debug(text) + CommonBasicNotification( + CommonLocalizationUtils.create_localized_string(f'Object {game_object} Tags ({game_object_id})'), + CommonLocalizationUtils.create_localized_string(text) + ).show( + icon=IconInfoData(obj_instance=game_object) + ) + + +log = CommonLogRegistry().register_log(ModInfo.get_identity(), 's4cl_object_tag_utils') +log.enable() + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_testing.print_game_tags', + 'Print a list of Game Tags on a Game Object.', + command_arguments=( + CommonConsoleCommandArgument('game_object', 'Game Object Instance Id', 'The instance id of a game object to check.'), + ), + command_aliases=( + 's4clib_testing.printgametags', + ) +) +def _common_print_game_tags(output: CommonConsoleCommandOutput, game_object: GameObject): + if game_object is None: + return + + output(f'Printing game tags of {game_object}') + CommonObjectTagUtils._print_game_tags(game_object) + output('------------------------------------') diff --git a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_type_utils.py b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_type_utils.py new file mode 100644 index 0000000..dea34cf --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_type_utils.py @@ -0,0 +1,482 @@ +""" +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 +""" +from objects.game_object import GameObject +from objects.pools.pool import SwimmingPool +from objects.pools.pool_seat import PoolSeat +from sims4communitylib.enums.tags_enum import CommonGameTag +from sims4communitylib.utils.objects.common_object_tag_utils import CommonObjectTagUtils + + +class CommonObjectTypeUtils: + """ Utilities for determining the type of an object. """ + @staticmethod + def is_window(game_object: GameObject) -> bool: + """is_window(game_object) + + Determine if an Object is a window. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if the Object is a Window. False, if not. + :rtype: bool + """ + if not isinstance(game_object, GameObject): + return False + from sims4communitylib.enums.tags_enum import CommonGameTag + from sims4communitylib.utils.objects.common_object_tag_utils import CommonObjectTagUtils + return CommonObjectTagUtils.has_game_tags(game_object, (CommonGameTag.BUILD_WINDOW, )) + + @staticmethod + def is_toilet(game_object: GameObject) -> bool: + """is_toilet(game_object) + + Determine if an Object is a Toilet. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if the Object is a Toilet. False, if not. + :rtype: bool + """ + if not isinstance(game_object, GameObject): + return False + return CommonObjectTagUtils.has_game_tags(game_object, ( + CommonGameTag.FUNC_TOILET, + CommonGameTag.FUNC_PUBLIC_BATHROOM, + CommonGameTag.FUNC_TOILET_TALKING + )) + + @staticmethod + def is_loveseat(game_object: GameObject) -> bool: + """is_loveseat(game_object) + + Determine if an Object is a Loveseat. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if the Object is a Loveseat. False, if not. + :rtype: bool + """ + if not isinstance(game_object, GameObject): + return False + return CommonObjectTagUtils.has_game_tags(game_object, (CommonGameTag.BUY_CAT_SS_LOVE_SEAT, )) + + @staticmethod + def is_bed(game_object: GameObject) -> bool: + """is_bed(game_object) + + Determine if an Object is a Bed. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if the Object is a Bed. False, if not. + :rtype: bool + """ + if not isinstance(game_object, GameObject): + return False + return CommonObjectTagUtils.has_game_tags(game_object, ( + CommonGameTag.FUNC_BED, + CommonGameTag.FUNC_DOUBLE_BED, + CommonGameTag.FUNC_SINGLE_BED, + CommonGameTag.FUNC_TODDLER_BED, + CommonGameTag.FUNC_BED_KID, + CommonGameTag.FUNC_PET_BED, + CommonGameTag.BUY_CAT_SS_BED, + CommonGameTag.BUY_CAT_SS_BED_SINGLE, + CommonGameTag.BUY_CAT_SS_BED_DOUBLE, + CommonGameTag.BUY_CAT_SS_PET_BED, + CommonGameTag.FUNC_DOCTOR_OBJECT_EXAM_BED, + CommonGameTag.FUNC_ACTOR_CAREER_HOSPITAL_EXAM_BED + )) + + @staticmethod + def is_human_sim_bed(game_object: GameObject) -> bool: + """is_human_sim_bed(game_object) + + Determine if an Object is a Bed for Human Sims. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if the Object is a Bed for Human Sims. False, if not. + :rtype: bool + """ + if not isinstance(game_object, GameObject): + return False + return CommonObjectTagUtils.has_game_tags(game_object, ( + CommonGameTag.FUNC_BED, + CommonGameTag.FUNC_DOUBLE_BED, + CommonGameTag.FUNC_SINGLE_BED, + CommonGameTag.FUNC_TODDLER_BED, + CommonGameTag.FUNC_BED_KID + )) + + @staticmethod + def is_pet_sim_bed(game_object: GameObject) -> bool: + """is_pet_sim_bed(game_object) + + Determine if an Object is a Bed for Pet Sims. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if the Object is a Bed for Pet Sims. False, if not. + :rtype: bool + """ + if not isinstance(game_object, GameObject): + return False + return CommonObjectTagUtils.has_game_tags(game_object, ( + CommonGameTag.FUNC_BED, + CommonGameTag.FUNC_PET_BED, + CommonGameTag.BUY_CAT_SS_BED_SINGLE, + CommonGameTag.BUY_CAT_SS_BED_DOUBLE, + CommonGameTag.BUY_CAT_SS_PET_BED, + )) + + @staticmethod + def is_adult_bed(game_object: GameObject) -> bool: + """is_adult_bed(game_object) + + Determine if an Object is a Bed for Adult Sims. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if the Object is a Bed for Adult Sims. False, if not. + :rtype: bool + """ + if not isinstance(game_object, GameObject): + return False + return CommonObjectTagUtils.has_game_tags(game_object, ( + CommonGameTag.FUNC_BED, + CommonGameTag.FUNC_DOUBLE_BED, + CommonGameTag.FUNC_SINGLE_BED + )) + + @staticmethod + def is_child_bed(game_object: GameObject) -> bool: + """is_adult_bed(game_object) + + Determine if an Object is a Bed for Child Sims. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if the Object is a Bed for Child Sims. False, if not. + :rtype: bool + """ + if not isinstance(game_object, GameObject): + return False + return CommonObjectTagUtils.has_game_tags(game_object, ( + CommonGameTag.FUNC_BED, + CommonGameTag.FUNC_BED_KID, + )) + + @staticmethod + def is_toddler_bed(game_object: GameObject) -> bool: + """is_toddler_bed(game_object) + + Determine if an Object is a Bed for Toddler Sims. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if the Object is a Bed for Toddler Sims. False, if not. + :rtype: bool + """ + if not isinstance(game_object, GameObject): + return False + return CommonObjectTagUtils.has_game_tags(game_object, ( + CommonGameTag.FUNC_TODDLER_BED, + )) + + @staticmethod + def is_single_bed(game_object: GameObject) -> bool: + """is_single_bed(game_object) + + Determine if an Object is a Single Bed. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if the Object is a Single Bed. False, if not. + :rtype: bool + """ + if not isinstance(game_object, GameObject): + return False + return CommonObjectTagUtils.has_game_tags(game_object, ( + CommonGameTag.FUNC_SINGLE_BED, + CommonGameTag.BUY_CAT_SS_BED_SINGLE + )) + + @staticmethod + def is_double_bed(game_object: GameObject) -> bool: + """is_double_bed(game_object) + + Determine if an Object is a Double Bed. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if the Object is a Double Bed. False, if not. + :rtype: bool + """ + if not isinstance(game_object, GameObject): + return False + return CommonObjectTagUtils.has_game_tags(game_object, ( + CommonGameTag.FUNC_DOUBLE_BED, + CommonGameTag.BUY_CAT_SS_BED_DOUBLE + )) + + @staticmethod + def is_light(game_object: GameObject) -> bool: + """is_light(game_object) + + Determine if an Object is a Light. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if the Object is a Light. False, if not. + :rtype: bool + """ + if not isinstance(game_object, GameObject): + return False + return CommonObjectTagUtils.has_game_tags(game_object, ( + CommonGameTag.BUY_CAT_LD_WALL_LIGHT, + CommonGameTag.BUY_CAT_LD_OUTDOOR_LIGHT, + CommonGameTag.BUY_CAT_LD_CEILING_LIGHT, + CommonGameTag.BUY_CAT_LD_NIGHT_LIGHT, + CommonGameTag.BUY_CAT_LD_MISC_LIGHT, + CommonGameTag.FUNC_LIGHT_NON_ELECTRIC, + CommonGameTag.FUNC_POOL_LIGHT, + CommonGameTag.FUNC_BUSINESS_LIGHT, + CommonGameTag.FUNC_LASER_LIGHT, + CommonGameTag.FUNC_RETAIL_NEON_LIGHT, + CommonGameTag.STYLE_FESTIVAL_LIGHT, + CommonGameTag.FUNC_HOLIDAY_FESTIVE_LIGHTING + )) + + @staticmethod + def is_stair(game_object: GameObject) -> bool: + """is_stair(game_object) + + Determine if an Object is a Stair. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if the Object is a Stair. False, if not. + :rtype: bool + """ + if not isinstance(game_object, GameObject): + return False + return CommonObjectTagUtils.has_game_tags(game_object, ( + CommonGameTag.BUILD_STAIR, + )) + + @staticmethod + def is_door(game_object: GameObject) -> bool: + """is_door(game_object) + + Determine if an Object is a Door. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if the Object is a Door. False, if not. + :rtype: bool + """ + if not isinstance(game_object, GameObject): + return False + from objects.doors.door import Door + return isinstance(game_object, Door) or CommonObjectTagUtils.has_game_tags(game_object, ( + CommonGameTag.BUILD_DOOR, + CommonGameTag.BUILD_DOOR_SINGLE, + CommonGameTag.BUILD_DOOR_DOUBLE, + CommonGameTag.FUNC_GATE, + CommonGameTag.BUILD_GATE, + CommonGameTag.BUILD_GATE_SINGLE, + CommonGameTag.BUILD_GATE_DOUBLE, + CommonGameTag.FUNC_TEMPLE_GATE, + CommonGameTag.FUNC_ACTOR_CAREER_CELL_DOOR, + CommonGameTag.FUNC_LAB_DOOR, + CommonGameTag.FUNC_VAULT_DOOR, + CommonGameTag.FUNC_ACTOR_CAREER_STUDIO_DOOR_PRIVATE, + CommonGameTag.FUNC_INVESTIGATION_SEALED_DOOR_HALLWAY, + CommonGameTag.FUNC_INVESTIGATION_SEALED_DOOR_MOTHER_PLANT + )) + + @staticmethod + def is_fence(game_object: GameObject) -> bool: + """is_fence(game_object) + + Determine if an Object is a Fence. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if the Object is a Door. False, if not. + :rtype: bool + """ + if not isinstance(game_object, GameObject): + return False + return CommonObjectTypeUtils.is_door(game_object) and CommonObjectTagUtils.has_game_tags(game_object, ( + CommonGameTag.BUILD_FENCE, + )) + + @staticmethod + def is_swimming_pool(game_object: GameObject) -> bool: + """is_swimming_pool(game_object) + + Determine if an Object is a Swimming Pool. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if the Object is a Swimming Pool. False, if not. + :rtype: bool + """ + if not isinstance(game_object, GameObject): + return False + return isinstance(game_object, SwimmingPool) + + @staticmethod + def is_swimming_pool_seat(game_object: GameObject) -> bool: + """is_swimming_pool_seat(game_object) + + Determine if an Object is a Swimming Pool Seat. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if the Object is a Swimming Pool Seat. False, if not. + :rtype: bool + """ + if not isinstance(game_object, GameObject): + return False + return isinstance(game_object, PoolSeat) + + @staticmethod + def is_cow(game_object: GameObject) -> bool: + """is_cow(game_object) + + Determine if an Object is a Cow. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if the Object is a Cow. False, if not. + :rtype: bool + """ + return CommonObjectTagUtils.has_game_tags(game_object, (CommonGameTag.FUNC_COW, CommonGameTag.FUNC_ANIMAL_OBJECT_LIVESTOCK_COW)) + + @staticmethod + def is_dolphin(game_object: GameObject) -> bool: + """is_dolphin(game_object) + + Determine if an Object is a Dolphin. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if the Object is a Dolphin. False, if not. + :rtype: bool + """ + return CommonObjectTagUtils.has_game_tags(game_object, ( + CommonGameTag.FUNC_DOLPHIN_ALBINO, + CommonGameTag.FUNC_DOLPHIN_MERFOLK, + CommonGameTag.FUNC_DOLPHIN_SPAWNER, + CommonGameTag.FUNC_DOLPHIN_STANDARD + )) + + @staticmethod + def is_llama(game_object: GameObject) -> bool: + """is_llama(game_object) + + Determine if an Object is a Llama. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if the Object is a Llama. False, if not. + :rtype: bool + """ + return CommonObjectTagUtils.has_game_tags(game_object, (CommonGameTag.FUNC_LLAMA, CommonGameTag.FUNC_ANIMAL_OBJECT_LIVESTOCK_LLAMA)) + + @staticmethod + def is_livestock(game_object: GameObject) -> bool: + """is_livestock(game_object) + + Determine if an Object is considered to be Livestock. + + .. note:: Objects considered to be Livestock are Llamas and Cows. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if the Object is Livestock. False, if not. + :rtype: bool + """ + return CommonObjectTypeUtils.is_cow(game_object) or CommonObjectTypeUtils.is_llama(game_object) or CommonObjectTagUtils.has_game_tags(game_object, (CommonGameTag.FUNC_ANIMAL_OBJECT_LIVESTOCK,)) + + @staticmethod + def is_hen(game_object: GameObject) -> bool: + """is_hen(game_object) + + Determine if an Object is a Hen. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if the Object is a Hen. False, if not. + :rtype: bool + """ + return CommonObjectTagUtils.has_game_tags(game_object, (CommonGameTag.FUNC_HEN, CommonGameTag.FUNC_ANIMAL_OBJECT_LIVESTOCK_CHICKEN_HEN)) + + @staticmethod + def is_rooster(game_object: GameObject) -> bool: + """is_rooster(game_object) + + Determine if an Object is a Rooster. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if the Object is a Rooster. False, if not. + :rtype: bool + """ + return CommonObjectTagUtils.has_game_tags(game_object, (CommonGameTag.FUNC_ROOSTER, CommonGameTag.FUNC_ANIMAL_OBJECT_LIVESTOCK_CHICKEN_ROOSTER)) + + @staticmethod + def is_chicken(game_object: GameObject) -> bool: + """is_chicken(game_object) + + Determine if an Object is a Chicken. + + .. note:: A Chicken is either a Hen or Rooster. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if the Object is a Chicken. False, if not. + :rtype: bool + """ + return CommonObjectTypeUtils.is_hen(game_object) or CommonObjectTypeUtils.is_rooster(game_object) or CommonObjectTagUtils.has_game_tags(game_object, (CommonGameTag.FUNC_ANIMAL_OBJECT_LIVESTOCK_CHICKEN, )) + + @staticmethod + def is_rabbit(game_object: GameObject) -> bool: + """is_rabbit(game_object) + + Determine if an Object is a Rabbit. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if the Object is a Rabbit. False, if not. + :rtype: bool + """ + return CommonObjectTagUtils.has_game_tags(game_object, (CommonGameTag.FUNC_ANIMAL_OBJECT_WILD_RABBIT,)) + + @staticmethod + def is_vacuum_cleaner(game_object: GameObject) -> bool: + """is_vacuum_cleaner(game_object) + + Determine if an Object is a Vacuum Cleaner. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if the Object is a Vacuum Cleaner. False, if not. + :rtype: bool + """ + return CommonObjectTagUtils.has_game_tags(game_object, ( + CommonGameTag.FUNC_VACUUM_CLEANER, + CommonGameTag.FUNC_VACUUM_CLEANER_HANDHELD, + CommonGameTag.FUNC_VACUUM_CLEANER_HIGH, + CommonGameTag.FUNC_VACUUM_CLEANER_LOW, + CommonGameTag.FUNC_VACUUM_CLEANER_MED, + CommonGameTag.FUNC_VACUUM_CLEANER_UPRIGHT + )) diff --git a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_utils.py b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_utils.py new file mode 100644 index 0000000..fc50d24 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_utils.py @@ -0,0 +1,314 @@ +""" +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 +""" +from objects.base_object import BaseObject +from typing import Callable, Iterator, Union +import services +from objects.definition import Definition +from objects.game_object import GameObject +from objects.object_manager import ObjectManager +from objects.script_object import ScriptObject +from sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils + + +class CommonObjectUtils(_HasS4CLClassLog): + """Utilities for retrieving Objects in various ways. + + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 'common_object_utils' + + @classmethod + def create_unique_identifier(cls, game_object: GameObject) -> int: + """create_unique_identifier(game_object) + + Create a unique identifier for an Object. + + .. note:: The unique identifier will be the same for all objects of the same type. For Example, with two The Ambassador toilets they will have the same unique identifier. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: An identifier that uniquely identifies a specific type of Object. + :rtype: int + """ + guid64 = cls.get_object_guid(game_object) + catalog_name = cls.get_catalog_name(game_object) + hash_value = 0x09D05916 ^ min(guid64, catalog_name) + hash_value = (((0x000F4243 * hash_value) >> 4) & 0x0FFFFFFF) ^ max(guid64, catalog_name) + hash_value = abs(hash_value ^ 2) + return hash_value + + @classmethod + def get_object_id(cls, object_instance: BaseObject) -> int: + """get_object_id(object_instance) + + Retrieve the decimal identifier of an Object. + + :param object_instance: An instance of an Object. + :type object_instance: BaseObject + :return: The decimal identifier of the BaseObject or -1 if the id could not be gained. + :rtype: int + """ + if object_instance is None: + return -1 + return object_instance.id or getattr(object_instance, 'id', -1) + + @classmethod + def get_object_guid(cls, game_object: GameObject) -> int: + """get_object_guid(game_object) + + Retrieve the GUID of an Object. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: The GUID of the specified Object or -1 if it does not have one. + :rtype: int + """ + if game_object is None or not hasattr(game_object, 'guid64'): + return -1 + return getattr(game_object, 'guid64', -1) + + @classmethod + def get_object_definition(cls, game_object: Union[int, GameObject], pack_safe: bool = False, get_fallback_definition_id: bool = True) -> Definition: + """get_object_definition(game_object, pack_safe=False, get_fallback_definition_id=True) + + Retrieve the definition for an Object. + + :param game_object: The decimal identifier of an Object or a Game Object. + :type game_object: Union[int, GameObject] + :param pack_safe: If true, objects will be searched for keeping package safety in mind. Default is False. + :type pack_safe: bool, optional + :param get_fallback_definition_id: Set True, to locate a fallback definition id. Default is True. + :type get_fallback_definition_id: bool, optional + :return: The definition of the object with the id. + :rtype: Definition + """ + game_object_instance = cls.get_game_object(game_object) + if game_object_instance is not None: + if hasattr(game_object_instance, 'definition') and game_object_instance.definition is not None: + return game_object_instance.definition + if hasattr(game_object, 'definition') and game_object.definition is not None: + return game_object.definition + return services.definition_manager().get(game_object, pack_safe=pack_safe, get_fallback_definition_id=get_fallback_definition_id) + + @classmethod + def get_object_definition_id(cls, game_object: Union[int, GameObject], pack_safe: bool = False, get_fallback_definition_id: bool = True) -> Union[int, None]: + """get_object_definition_id(game_object, pack_safe=False, get_fallback_definition_id=True) + + Retrieve the definition for an Object. + + :param game_object: The decimal identifier of an Object or a Game Object. + :type game_object: Union[int, GameObject] + :param pack_safe: If true, objects will be searched for keeping package safety in mind. Default is False. + :type pack_safe: bool, optional + :param get_fallback_definition_id: Set True, to locate a fallback definition id. Default is True. + :type get_fallback_definition_id: bool, optional + :return: The id of the definition of the object with the id. + :rtype: Union[int, None] + """ + definition = cls.get_object_definition(game_object, pack_safe=pack_safe, get_fallback_definition_id=get_fallback_definition_id) + if definition is None: + return None + return definition.id + + @classmethod + def get_game_object_definition(cls, game_object: GameObject, pack_safe: bool = False, get_fallback_definition_id: bool = True) -> Union[Definition, None]: + """get_game_object_definition(game_object, pack_safe=False, get_fallback_definition_id=True) + + Retrieve the definition for an Object. + + :param game_object: An instance of a GameObject. + :type game_object: GameObject + :param pack_safe: If true, objects will be searched for keeping package safety in mind. Default is False. + :type pack_safe: bool, optional + :param get_fallback_definition_id: Set True, to locate a fallback definition id. Default is True. + :type get_fallback_definition_id: bool, optional + :return: The definition of the Game Object or None if no definition is found. + :rtype: Definition + """ + if game_object is None: + return None + if hasattr(game_object, 'definition') and game_object.definition is not None: + return game_object.definition + game_object_id = cls.get_object_id(game_object) + if game_object_id is None or game_object_id == -1: + return None + return services.definition_manager().get(game_object_id, pack_safe=pack_safe, get_fallback_definition_id=get_fallback_definition_id) + + @classmethod + def get_game_object_definition_id(cls, game_object: GameObject, pack_safe: bool = False, get_fallback_definition_id: bool = True) -> Union[int, None]: + """get_game_object_definition(game_object, pack_safe=False, get_fallback_definition_id=True) + + Retrieve the definition for an Object. + + :param game_object: An instance of a GameObject. + :type game_object: GameObject + :param pack_safe: If true, objects will be searched for keeping package safety in mind. Default is False. + :type pack_safe: bool, optional + :param get_fallback_definition_id: Set True, to locate a fallback definition id. Default is True. + :type get_fallback_definition_id: bool, optional + :return: The id of the definition of the Game Object or None if no definition is found. + :rtype: Union[int, None] + """ + definition = cls.get_game_object_definition(game_object, pack_safe=pack_safe, get_fallback_definition_id=get_fallback_definition_id) + if definition is None: + return None + return definition.id + + @classmethod + def get_catalog_name(cls, game_object: GameObject) -> int: + """get_catalog_name(game_object) + + Retrieve the catalog name identifier of an Object. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: The decimal identifier of the catalog name of an Object or -1 if no catalog name is found. + :rtype: int + """ + if game_object is None: + return -1 + return game_object.catalog_name + + @classmethod + def get_game_object(cls, game_object_id: int) -> GameObject: + """get_game_object(game_object_id) + + Retrieve an instance of an Object in the game world. + + :param game_object_id: The decimal identifier of an Object. + :type game_object_id: int + :return: An instance of an Object or None if not found. + :rtype: GameObject + """ + return cls.get_game_object_manager().get(game_object_id) + + @classmethod + def has_root_parent(cls, object_instance: ScriptObject) -> bool: + """has_root_parent(object_instance) + + Determine if an Object has a root parent. + + :param object_instance: An instance of an Object. + :type object_instance: ScriptObject + :return: True, if the Object has a root parent. False, if not. + :rtype: bool + """ + if object_instance is None: + return False + return object_instance.parent is not None + + @classmethod + def get_root_parent(cls, object_instance: ScriptObject) -> Union[ScriptObject, None]: + """get_root_parent(object_instance) + + Retrieve the root parent of an Object. + + :param object_instance: An instance of an Object. + :type object_instance: ScriptObject + :return: The root parent of the Object or None if a problem occurs. + :rtype: Union[ScriptObject, None] + """ + if object_instance is None or object_instance.parent is None: + return object_instance + return cls.get_root_parent(object_instance.parent) or object_instance + + @classmethod + def get_instance_for_all_game_objects_generator( + cls, + include_object_callback: Callable[[GameObject], bool] = None + ) -> Iterator[GameObject]: + """get_instance_for_all_objects_generator(include_object_callback=None) + + Retrieve an instance for each and every Object in the game world. + + :param include_object_callback: If the result of this callback is True, the Object will be included in the\ + results. If set to None, All Objects will be included. + :type include_object_callback: Callable[[GameObject], bool], optional + :return: An iterator of all Objects matching the `include_object_callback` filter. + :rtype: Iterator[GameObject] + """ + game_object_list = tuple(cls.get_game_object_manager().get_all()) + for game_object in game_object_list: + if game_object is None: + continue + if include_object_callback is not None and not include_object_callback(game_object): + continue + yield game_object + + @classmethod + def get_instance_for_all_visible_game_objects_generator( + cls, + include_object_callback: Callable[[GameObject], bool] = None + ) -> Iterator[GameObject]: + """get_instance_for_all_visible_objects_generator(include_object_callback=None) + + Retrieve an instance for each and every visible Object in the game world. + + :param include_object_callback: If the result of this callback is True, the Object will be included in the results. If set to None, All Objects will be included. + :type include_object_callback: Callable[[GameObject], bool], optional + :return: An iterator of all Objects matching the `include_object_callback` filter. + :rtype: Iterator[GameObject] + """ + def _is_visible(_game_object: GameObject) -> bool: + return not _game_object.is_hidden() + + include_object_callback = CommonFunctionUtils.run_predicates_as_one((_is_visible, include_object_callback)) + + for game_object in cls.get_instance_for_all_game_objects_generator( + include_object_callback=include_object_callback + ): + yield game_object + + @classmethod + def get_game_object_manager(cls) -> ObjectManager: + """get_game_object_manager() + + Retrieve the manager that manages all Game Objects in a game world. + + :return: The manager that manages all Game Objects in a game world. + :rtype: ObjectManager + """ + return services.object_manager() + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_testing.print_objects', + 'Print a list of all objects.' +) +def _s4cl_testing_log_all_objects(output: CommonConsoleCommandOutput): + log = CommonObjectUtils.get_log() + try: + log.enable() + output(f'Printing a list of all objects.') + log.debug(f'Printing a list of all objects.') + all_objects_str_list = list() + for game_object in CommonObjectUtils.get_instance_for_all_game_objects_generator(): + object_id = CommonObjectUtils.get_object_id(game_object) + from sims4communitylib.utils.objects.common_object_location_utils import CommonObjectLocationUtils + object_location = CommonObjectLocationUtils.get_location(game_object) + from sims4communitylib.utils.common_type_utils import CommonTypeUtils + if CommonTypeUtils.is_sim_or_sim_info(game_object): + all_objects_str_list.append(f'Sim {game_object} ({object_id}): Loc: {object_location}') + else: + all_objects_str_list.append(f'Object {game_object} ({object_id}): Loc: {object_location}') + + all_objects_str_list = sorted(all_objects_str_list) + for all_objects_str in all_objects_str_list: + output(all_objects_str) + log.debug(all_objects_str) + log.debug('Done printing a list of all objects.') + finally: + log.disable() diff --git a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_visibility_utils.py b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_visibility_utils.py new file mode 100644 index 0000000..8a69f56 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_visibility_utils.py @@ -0,0 +1,82 @@ +""" +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 +""" +from objects.game_object import GameObject +from objects.persistence_groups import PersistenceGroups + + +class CommonObjectVisibilityUtils: + """Utilities for manipulating the visibility and persistence of Objects. + + """ + + @staticmethod + def set_opacity(game_object: GameObject, opacity: int) -> bool: + """set_opacity(game_object, opacity) + + Set the opacity of an Object. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :param opacity: Determines how opaque the Object will be. + :type opacity: int + :return: True, if successful. False, if not. + :rtype: bool + """ + if game_object is None or opacity is None: + return False + game_object.opacity = opacity + return True + + @staticmethod + def get_opacity(game_object: GameObject) -> int: + """get_opacity(game_object) + + Retrieve the opacity of an Object. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: How opaque the Object is. + :rtype: int + """ + if game_object is None: + return 0 + # noinspection PyPropertyAccess + return game_object.opacity + + @staticmethod + def set_persistence_group(game_object: GameObject, persistence_group: PersistenceGroups) -> bool: + """set_persistence_group(game_object, persistence_group) + + Set the persistence group of an Object. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :param persistence_group: The PersistenceGroup of the Object. + :type persistence_group: PersistenceGroups + :return: True, if successful. False, if not. + :rtype: bool + """ + if game_object is None or persistence_group is None: + return False + game_object.persistence_group = persistence_group + return True + + @staticmethod + def get_persistence_group(game_object: GameObject) -> PersistenceGroups: + """get_persistence_group(game_object) + + Retrieve the persistence group of an Object. + + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: The persistence group of the Object. + :rtype: PersistenceGroups, optional + """ + if game_object is None: + return PersistenceGroups.NONE + return game_object.persistence_group diff --git a/Scripts/s4ap/sims4communitylib/utils/resources/__init__.py b/Scripts/s4ap/sims4communitylib/utils/resources/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/resources/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/utils/resources/common_club_utils.py b/Scripts/s4ap/sims4communitylib/utils/resources/common_club_utils.py new file mode 100644 index 0000000..6117f03 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/resources/common_club_utils.py @@ -0,0 +1,78 @@ +""" +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 +""" +from typing import Iterator, Callable + +import services +from clubs.club import Club +from clubs.club_tuning import ClubRule +from sims.sim_info import SimInfo +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils + + +class CommonClubUtils: + """ Utilities for manipulating Clubs. """ + + @staticmethod + def get_clubs_currently_gathering_gen(include_club_callback: Callable[[Club], bool] = CommonFunctionUtils.noop_true) -> Iterator[Club]: + """get_clubs_currently_gathering_gen(include_club_callback=CommonFunctionUtils.noop_true) + + Retrieve all Clubs that are currently hosting a gathering. + + :param include_club_callback: If the result of this callback is True, the Club will be included in the results. The default callback will allow all. + :type include_club_callback: Callable[[Club], bool], optional + :return: An iterator of all Clubs that are currently gathering and that pass the include callback filter. + :rtype: Iterator[Club] + """ + from clubs.club_service import ClubService + club_service: ClubService = services.get_club_service() + if club_service is None: + return tuple() + for club in club_service.clubs_to_gatherings_map.keys(): + if club is None or not include_club_callback(club): + continue + yield club + + @staticmethod + def get_club_members_gen(club: Club, include_club_member_callback: Callable[[SimInfo], bool] = CommonFunctionUtils.noop_true) -> Iterator[SimInfo]: + """get_club_members_gen(club, include_club_member_callback=CommonFunctionUtils.noop_true) + + Retrieve the SimInfo of all members who are a part of a Club. + + :param club: An instance of a Club. + :type club: Club + :param include_club_member_callback: If the result of this callback is True, the Club Member will be included in the results. The default callback will allow all. + :type include_club_member_callback: Callable[[SimInfo], bool], optional + :return: An iterator of all Sims in a Club that pass the include callback filter. + :rtype: Iterator[SimInfo] + """ + from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + for member_sim in club.members: + sim_info = CommonSimUtils.get_sim_info(member_sim) + if not include_club_member_callback(sim_info): + continue + yield sim_info + + @staticmethod + def get_club_rules_gen(club: Club, include_club_rule_callback: Callable[[SimInfo], bool] = CommonFunctionUtils.noop_true) -> Iterator[ClubRule]: + """get_club_rules_gen(club, include_club_rule_callback=CommonFunctionUtils.noop_true) + + Retrieve all Club Rules of a Club. + + :param club: An instance of a Club. + :type club: Club + :param include_club_rule_callback: If the result of this callback is True, the Club Rule will be included in the results. The default callback will allow all. + :type include_club_rule_callback: Callable[[ClubRule], bool], optional + :return: An iterator of all Club Rules for the specified Club that pass the include callback filter. + :rtype: Iterator[ClubRule] + """ + if club is None: + return tuple() + for club_rule in club.rules: + if club_rule is None or not include_club_rule_callback(club_rule): + continue + yield club_rule diff --git a/Scripts/s4ap/sims4communitylib/utils/resources/common_game_pack_utils.py b/Scripts/s4ap/sims4communitylib/utils/resources/common_game_pack_utils.py new file mode 100644 index 0000000..2a595f1 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/resources/common_game_pack_utils.py @@ -0,0 +1,68 @@ +""" +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 +""" +from typing import Tuple + +from sims4.common import Pack + + +class CommonGamePackUtils: + """ Utilities for checking various information about Game Packs and their availability. """ + + @staticmethod + def has_game_pack_available(game_pack: Pack) -> bool: + """has_game_pack_available(game_pack) + + Whether or not the specified Game Pack is available. + + :param game_pack: The Game Pack to check for. + :type game_pack: Pack + :return: True, if the specified Game Pack is available. False, if not. + :rtype: bool + """ + from sims4.common import is_available_pack + return is_available_pack(game_pack) + + @staticmethod + def has_game_packs_available(game_packs: Tuple[Pack]) -> bool: + """has_game_packs_available(game_packs) + + Whether or not the specified Game Pack is available. + + :param game_packs: The Game Packs to check for. + :type game_packs: Tuple[Pack] + :return: True, if all of the specified Game Packs are available. False, if any of them are not available. + :rtype: bool + """ + from sims4.common import are_packs_available + return are_packs_available(game_packs) + + @staticmethod + def get_available_game_packs() -> Tuple[Pack]: + """get_available_game_packs() + + Retrieve a collection of all available Game Packs. + + :return: A collection of all Game Packs currently available and installed. + :rtype: Tuple[Pack] + """ + from sims4.common import get_available_packs + return tuple(get_available_packs()) + + @staticmethod + def get_game_pack_name(game_pack: Pack) -> str: + """get_game_pack_name(game_pack) + + Retrieve the name of a Game Pack. + + :param game_pack: The Game Pack to retrieve the name of. + :type game_pack: Pack + :return: The name of the Game Pack or if not available. + :rtype: str + """ + from sims4.common import get_pack_name + return get_pack_name(game_pack) diff --git a/Scripts/s4ap/sims4communitylib/utils/resources/common_interaction_utils.py b/Scripts/s4ap/sims4communitylib/utils/resources/common_interaction_utils.py new file mode 100644 index 0000000..54ce385 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/resources/common_interaction_utils.py @@ -0,0 +1,434 @@ +""" +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 +""" +from typing import Union, Iterator, Any, Tuple, List + +from interactions.base.immediate_interaction import ImmediateSuperInteraction +from interactions.base.interaction import Interaction +from interactions.base.mixer_interaction import MixerInteraction +from interactions.base.super_interaction import SuperInteraction +from interactions.context import InteractionContext +from interactions.interaction_instance_manager import InteractionInstanceManager +from interactions.social.social_mixer_interaction import SocialMixerInteraction +from interactions.social.social_super_interaction import SocialSuperInteraction +from protocolbuffers.Localization_pb2 import LocalizedString +from server.pick_info import PickInfo +from sims4communitylib.classes.math.common_surface_identifier import CommonSurfaceIdentifier +from sims4communitylib.classes.math.common_vector3 import CommonVector3 +from sims4communitylib.enums.interactions_enum import CommonInteractionId +from sims4communitylib.enums.tags_enum import CommonGameTag +from sims4communitylib.utils.common_resource_utils import CommonResourceUtils +from sims4communitylib.utils.location.common_location_utils import CommonLocationUtils +from tag import Tag + + +class CommonInteractionUtils: + """Utilities for manipulating Interactions. + + """ + + @staticmethod + def has_any_static_commodities(interaction: Interaction, static_commodity_ids: Iterator[int]) -> bool: + """has_any_static_commodities(interaction, static_commodity_ids) + + Determine if an interaction has any of the specified static commodities. + + :param interaction: An instance of an interaction. + :type interaction: Interaction + :param static_commodity_ids: A collection of static commodity ids. + :type static_commodity_ids: Iterator[int], optional + :return: True, if the interaction has any of the specified static commodities. False, if not. + :rtype: bool + """ + interaction_commodities = interaction.static_commodities + if not interaction_commodities: + return False + static_commodity_ids = tuple(static_commodity_ids) + if not static_commodity_ids: + return True + for static_commodity_id in static_commodity_ids: + for interaction_commodity in interaction_commodities: + interaction_commodity_id = getattr(interaction_commodity, 'guid64', None) + if static_commodity_id == interaction_commodity_id: + return True + return False + + @staticmethod + def has_all_static_commodities(interaction: Interaction, static_commodity_ids: Iterator[int]) -> bool: + """has_all_static_commodities(interaction, static_commodity_ids) + + Determine if an interaction has all the specified static commodities. + + :param interaction: An instance of an interaction. + :type interaction: Interaction + :param static_commodity_ids: A collection of static commodity ids. + :type static_commodity_ids: Iterator[int], optional + :return: True, if the interaction has all the specified static commodities. False, if not. + :rtype: bool + """ + interaction_commodities = interaction.static_commodities + if not interaction_commodities: + return False + static_commodity_ids = tuple(static_commodity_ids) + if not static_commodity_ids: + return True + for static_commodity_id in static_commodity_ids: + has_commodity = False + for interaction_commodity in interaction_commodities: + interaction_commodity_id = getattr(interaction_commodity, 'guid64', None) + if static_commodity_id == interaction_commodity_id: + has_commodity = True + break + if not has_commodity: + return False + return True + + @staticmethod + def has_any_appropriateness_tags(interaction: Interaction, appropriateness_tags: Iterator[CommonGameTag]) -> bool: + """has_any_appropriateness_tags(interaction, appropriateness_tags) + + Determine if an interaction has Appropriateness Tags + + :param interaction: An instance of an interaction. + :type interaction: Interaction + :param appropriateness_tags: A collection of appropriateness tags. + :type appropriateness_tags: Iterator[CommonGameTag] + :return: True, if the Interaction has any of the specified appropriateness tags. False, if not. + :rtype: bool + """ + if interaction.appropriateness_tags is None: + return False + appropriateness_tags = tuple(appropriateness_tags) + if not appropriateness_tags: + return False + for appropriateness_tag in interaction.appropriateness_tags: + appropriateness_tag_converted = CommonResourceUtils.get_enum_by_int_value(int(appropriateness_tag), CommonGameTag, default_value=int(appropriateness_tag)) + if appropriateness_tag_converted is None: + continue + if appropriateness_tag_converted in appropriateness_tags: + return True + return False + + @staticmethod + def has_all_appropriateness_tags(interaction: Interaction, appropriateness_tags: Iterator[CommonGameTag]) -> bool: + """has_all_appropriateness_tags(interaction, appropriateness_tags) + + Determine if an interaction has Appropriateness Tags + + :param interaction: An instance of an interaction. + :type interaction: Interaction + :param appropriateness_tags: A collection of appropriateness tags. + :type appropriateness_tags: Iterator[CommonGameTag] + :return: True, if the Interaction has all the specified appropriateness tags. False, if not. + :rtype: bool + """ + if interaction.appropriateness_tags is None: + return False + if not appropriateness_tags: + return False + interaction_appropriateness_tags = interaction.appropriateness_tags + for appropriateness_tag in tuple(appropriateness_tags): + tag = CommonResourceUtils.get_enum_by_int_value(int(appropriateness_tag), Tag, default_value=int(appropriateness_tag)) + if tag not in interaction_appropriateness_tags: + return False + return True + + @staticmethod + def get_pick_info_from_interaction_context(interaction_context: InteractionContext) -> Union[PickInfo, None]: + """get_pick_info_from_interaction_context(interaction_context) + + Retrieve the pick info of an interaction context. + + :param interaction_context: An interaction context. + :type interaction_context: InteractionContext + :return: The pick info of the interaction context or None, if not found. + :rtype: PickInfo + """ + if interaction_context is None or interaction_context.pick is None: + return None + return interaction_context.pick + + @staticmethod + def get_picked_routing_surface_from_interaction_context(interaction_context: InteractionContext) -> Union[CommonSurfaceIdentifier, None]: + """get_picked_routing_surface_from_interaction_context(interaction_context) + + Retrieve the picked routing surface from an interaction context. + + :param interaction_context: An interaction context. + :type interaction_context: InteractionContext + :return: The picked routing surface from the interaction context or None if a problem occurs. + :rtype: Union[CommonSurfaceIdentifier, None] + """ + pick_info = CommonInteractionUtils.get_pick_info_from_interaction_context(interaction_context) + if pick_info is None: + return None + return CommonSurfaceIdentifier.from_surface_identifier(pick_info.routing_surface) + + @staticmethod + def get_picked_position_from_interaction_context(interaction_context: InteractionContext) -> Union[CommonVector3, None]: + """get_picked_position_from_interaction_context(interaction_context) + + Retrieve the picked position from an interaction context. + + :param interaction_context: An interaction context. + :type interaction_context: InteractionContext + :return: The picked position from the interaction context or None if a problem occurs. + :rtype: Union[CommonVector3, None] + """ + pick_info = CommonInteractionUtils.get_pick_info_from_interaction_context(interaction_context) + if pick_info is None: + return None + return CommonVector3.from_vector3(pick_info.location) + + @staticmethod + def get_picked_routing_position_from_interaction_context(interaction_context: InteractionContext) -> Union[CommonVector3, None]: + """get_picked_routing_position_from_interaction_context(interaction_context) + + Retrieve the picked routing position from an interaction context. + + :param interaction_context: An interaction context. + :type interaction_context: InteractionContext + :return: The picked routing position with the routing surface applied to it from the interaction context or None if a problem occurs. + :rtype: Union[CommonVector3, None] + """ + pick_info = CommonInteractionUtils.get_pick_info_from_interaction_context(interaction_context) + if pick_info is None: + return None + picked_position = CommonVector3.from_vector3(pick_info.location) + picked_routing_surface = CommonSurfaceIdentifier.from_surface_identifier(pick_info.routing_surface) + picked_position.y = CommonLocationUtils.get_surface_height_at(picked_position.x, picked_position.z, picked_routing_surface) + return picked_position + + @staticmethod + def get_picked_routing_surface_level_from_interaction_context(interaction_context: InteractionContext) -> Union[int, None]: + """get_picked_routing_surface_level_from_interaction_context(interaction_context) + + Retrieve the picked routing surface level from an interaction context. + + :param interaction_context: An interaction context. + :type interaction_context: InteractionContext + :return: The picked routing surface level from the interaction context or None if a problem occurs. + :rtype: Union[int, None] + """ + routing_surface = CommonInteractionUtils.get_picked_routing_surface_from_interaction_context(interaction_context) + if routing_surface is None: + return None + return routing_surface.secondary_id + + @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_mixer_interaction(interaction: Interaction) -> bool: + """is_mixer_interaction(interaction) + + Determine if an interaction is a Mixer interaction. + + :param interaction: An instance of an Interaction. + :type interaction: Interaction + :return: True, if the interaction is a Mixer interaction. False, if not. + """ + if interaction is None: + return False + return isinstance(interaction, MixerInteraction) + + @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 + if isinstance(interaction, SocialMixerInteraction): + return True + if not hasattr(interaction, 'is_social'): + 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 + if isinstance(interaction, SuperInteraction): + return True + if not hasattr(interaction, 'is_super'): + return False + return interaction.is_super + + @staticmethod + def is_immediate_super_interaction(interaction: Interaction) -> bool: + """is_immediate_super_interaction(interaction) + + Determine if an interaction is an Immediate Super interaction. + + :param interaction: An instance of an Interaction. + :type interaction: Interaction + :return: True, if the interaction is an Immediate Super interaction. False, if not. + """ + if interaction is None: + return False + return isinstance(interaction, ImmediateSuperInteraction) + + @staticmethod + def is_social_super_interaction(interaction: Interaction) -> bool: + """is_social_super_interaction(interaction) + + Determine if an interaction is a Social Super interaction. + + :param interaction: An instance of an Interaction. + :type interaction: Interaction + :return: True, if the interaction is a Social Super interaction. False, if not. + """ + if interaction is None: + return False + return isinstance(interaction, SocialSuperInteraction) + + @staticmethod + 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 + display_name_string_id = interaction.display_name._string_id + if not display_name_string_id: + return None + return CommonLocalizationUtils.create_localized_string(display_name_string_id, tokens=tuple(tokens)) + + @staticmethod + 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.__name__ or interaction.__class__.__name__ + except: + # noinspection PyBroadException + try: + return interaction.__name__ + except: + # noinspection PyBroadException + try: + return interaction.__class__.__name__ + except: + return '' + + @staticmethod + 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] = list() + 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 + def load_interaction_by_id(interaction_id: Union[int, CommonInteractionId, Interaction]) -> Union[Interaction, None]: + """load_interaction_by_id(interaction_id) + + Load an instance of an Interaction by its decimal identifier. + + :param interaction_id: The decimal identifier of an Interaction. + :type interaction_id: Union[int, CommonInteractionId, Interaction] + :return: An instance of an Interaction matching the decimal identifier or None if not found. + :rtype: Union[Interaction, None] + """ + if isinstance(interaction_id, Interaction): + return interaction_id + # noinspection PyBroadException + try: + # noinspection PyCallingNonCallable + interaction_instance = interaction_id() + if isinstance(interaction_instance, Interaction): + # noinspection PyTypeChecker + return interaction_id + except: + pass + # noinspection PyBroadException + try: + interaction_id: int = int(interaction_id) + except: + # noinspection PyTypeChecker + interaction_id: Interaction = interaction_id + return interaction_id + + from sims4.resources import Types + from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + return CommonResourceUtils.load_instance(Types.INTERACTION, interaction_id) + + @staticmethod + def get_instance_manager() -> InteractionInstanceManager: + """get_instance_manager() + + Retrieve the instance manager that manages all tunables for interactions. + + :return: The instance manager that manages all tunables for interactions. + :rtype: InteractionInstanceManager + """ + from sims4.resources import Types + from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + # noinspection PyTypeChecker + return CommonResourceUtils.get_instance_manager(Types.INTERACTION) diff --git a/Scripts/s4ap/sims4communitylib/utils/resources/common_loot_action_utils.py b/Scripts/s4ap/sims4communitylib/utils/resources/common_loot_action_utils.py new file mode 100644 index 0000000..8c5f573 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/resources/common_loot_action_utils.py @@ -0,0 +1,105 @@ +""" +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 +""" +from typing import Union, Tuple + +from event_testing.resolver import Resolver +from interactions.utils.loot import LootActions + + +class CommonLootActionUtils: + """Utilities for manipulating Loot Actions.""" + @staticmethod + def apply_loot_actions_using_resolver(loot_actions: LootActions, resolver: Resolver) -> bool: + """apply_loot_actions_using_resolver(loot_actions, resolver) + + Apply loot actions using a resolver. + + :param loot_actions: The loot actions to apply. + :type loot_actions: LootActions + :param resolver: A resolver used in various ways by loot actions. The resolver could be a SingleSimResolver, which will attempt to apply the loot to a single Sim, a DoubleSimResolver, which will attempt to apply to two Sims, or various other types of resolvers. + :type resolver: Resolver + :return: True, if the loot actions applied successfully. False, if not. + :rtype: bool + """ + if loot_actions is None: + return False + loot_actions.apply_to_resolver(resolver) + return True + + @staticmethod + def apply_loot_actions_by_id_using_resolver(loot_actions_id: int, resolver: Resolver) -> bool: + """apply_loot_actions_by_id_using_resolver(loot_actions_id, resolver) + + Apply loot actions by id using a resolver. + + :param loot_actions_id: The decimal identifier of a loot actions instance to apply. + :type loot_actions_id: int + :param resolver: A resolver used in various ways by loot actions. The resolver could be a SingleSimResolver, which will attempt to apply the loot to a single Sim, a DoubleSimResolver, which will attempt to apply to two Sims, or various other types of resolvers. + :type resolver: Resolver + :return: True, if the loot actions applied successfully. False, if not. + :rtype: bool + """ + loot_actions = CommonLootActionUtils.load_loot_actions_by_id(loot_actions_id) + if loot_actions is None: + return False + loot_actions.apply_to_resolver(resolver) + return True + + @staticmethod + def apply_loot_actions_by_ids_using_resolver(loot_actions_ids: Tuple[int], resolver: Resolver) -> bool: + """apply_loot_actions_by_ids_using_resolver(loot_actions_ids, resolver) + + Apply loot actions by their ids using a resolver. + + :param loot_actions_ids: A collection of decimal identifiers of LootActions instances to apply. + :type loot_actions_ids: Tuple[int] + :param resolver: A resolver used in various ways by loot actions. The resolver could be a SingleSimResolver, which will attempt to apply the loot to a single Sim, a DoubleSimResolver, which will attempt to apply to two Sims, or various other types of resolvers. + :type resolver: Resolver + :return: True, if at least one of the loot actions applied successfully. False, if not. + :rtype: bool + """ + has_applied_at_least_one = False + for loot_actions_id in loot_actions_ids: + loot_actions = CommonLootActionUtils.load_loot_actions_by_id(loot_actions_id) + if loot_actions is None: + continue + loot_actions.apply_to_resolver(resolver) + has_applied_at_least_one = True + return has_applied_at_least_one + + @staticmethod + def load_loot_actions_by_id(loot_actions_id: Union[int, LootActions]) -> Union[LootActions, None]: + """load_loot_actions_by_id(loot_actions_id) + + Load a Loot Actions instance by its decimal identifier. + + :param loot_actions_id: The decimal identifier of a LootActions instance. + :type loot_actions_id: Union[int, LootActions] + :return: An instance of a Loot Actions matching the decimal identifier or None if not found. + :rtype: Union[LootActions, None] + """ + if isinstance(loot_actions_id, LootActions): + return loot_actions_id + # noinspection PyBroadException + try: + # noinspection PyCallingNonCallable + loot_actions_instance = loot_actions_id() + if isinstance(loot_actions_instance, LootActions): + return loot_actions_id + except: + pass + # noinspection PyBroadException + try: + loot_actions_id: int = int(loot_actions_id) + except: + loot_actions_id: LootActions = loot_actions_id + return loot_actions_id + + from sims4.resources import Types + from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + return CommonResourceUtils.load_instance(Types.ACTION, loot_actions_id) diff --git a/Scripts/s4ap/sims4communitylib/utils/resources/common_recipe_utils.py b/Scripts/s4ap/sims4communitylib/utils/resources/common_recipe_utils.py new file mode 100644 index 0000000..6e67c70 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/resources/common_recipe_utils.py @@ -0,0 +1,128 @@ +""" +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 +""" +from crafting.recipe import Recipe +from typing import Callable, Iterator, Union, Tuple, List + +from sims4.resources import Types +from sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog + + +class CommonRecipeUtils(_HasS4CLClassLog): + """Utilities for manipulating Recipes in various ways. + + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 'common_recipe_utils' + + @staticmethod + def get_recipe_guid(recipe_identifier: Union[int, Recipe]) -> Union[int, None]: + """get_recipe_guid(recipe_identifier) + + Retrieve the GUID of a Recipe. + + :param recipe_identifier: The identifier or instance of a Recipe. + :type recipe_identifier: Union[int, Recipe] + :return: The decimal identifier of the Recipe or None if the Recipe does not have an id. + :rtype: Union[int, None] + """ + if isinstance(recipe_identifier, int): + return recipe_identifier + return getattr(recipe_identifier, 'guid64', None) + + @staticmethod + def get_short_name(recipe: Recipe) -> Union[str, None]: + """get_short_name(recipe) + + Retrieve the Short Name of a Recipe. + + :param recipe: An instance of a Recipe. + :type recipe: Recipe + :return: The short name of a Recipe or None if a problem occurs. + :rtype: Union[str, None] + """ + if recipe is None: + return None + # noinspection PyBroadException + try: + return recipe.__class__.__name__ + except: + return '' + + @staticmethod + def get_short_names(recipes: Iterator[Recipe]) -> Tuple[str]: + """get_short_names(recipes) + + Retrieve the Short Names of a collection of Recipes. + + :param recipes: A collection of Recipe instances. + :type recipes: Iterator[Recipe] + :return: A collection of short names of all Recipe instances. + :rtype: Tuple[str] + """ + if recipes is None or not recipes: + return tuple() + short_names: List[str] = [] + for recipe in recipes: + # noinspection PyBroadException + try: + short_name = CommonRecipeUtils.get_short_name(recipe) + if not short_name: + continue + except: + continue + short_names.append(short_name) + return tuple(short_names) + + @staticmethod + def get_all_recipes_gen(include_recipe_callback: Callable[[Recipe], bool] = None) -> Iterator[Recipe]: + """get_all_recipes_gen(include_recipe_callback=None) + + Retrieve all Recipes. + + :param include_recipe_callback: If the result of this callback is True, the Recipe will be included in the results. If set to None, All Recipes will be included. + :type include_recipe_callback: Callable[[Recipe], bool], optional + :return: An iterator of Recipes that pass the specified include_recipe_callback. + :rtype: Iterator[Recipe] + """ + from sims4communitylib.utils.resources.common_statistic_utils import CommonStatisticUtils + statistic_manager = CommonStatisticUtils.get_statistic_instance_manager() + for recipe in statistic_manager.get_ordered_types(only_subclasses_of=Recipe): + recipe: Recipe = recipe + recipe_id = CommonRecipeUtils.get_recipe_guid(recipe) + if recipe_id is None: + continue + if include_recipe_callback is not None and not include_recipe_callback(recipe): + continue + yield recipe + + @staticmethod + def load_recipe_by_guid(value_id: Union[int, Recipe]) -> Union[Recipe, None]: + """load_recipe_by_guid(recipe_id) + + Load an instance of a Recipe by a GUID. + + :param value_id: The GUID of a Recipe. + :type value_id: Union[int, Recipe] + :return: An instance of a Recipe matching the decimal identifier or None if not found. + :rtype: Union[Recipe, None] + """ + if isinstance(value_id, Recipe) or hasattr(value_id, 'is_recipe'): + return value_id + # noinspection PyBroadException + try: + value_id: int = int(value_id) + except: + # noinspection PyTypeChecker + value_id: Recipe = value_id + return value_id + + from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + return CommonResourceUtils.load_instance(Types.RECIPE, value_id) diff --git a/Scripts/s4ap/sims4communitylib/utils/resources/common_situation_utils.py b/Scripts/s4ap/sims4communitylib/utils/resources/common_situation_utils.py new file mode 100644 index 0000000..3d42d6d --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/resources/common_situation_utils.py @@ -0,0 +1,329 @@ +""" +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 +""" +from typing import Union, Iterator, Tuple, List, Type + +import services +from sims.sim_info import SimInfo +from sims4communitylib.enums.situations_enum import CommonSituationId +from sims4communitylib.enums.tags_enum import CommonGameTag +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from situations.situation import Situation +from situations.situation_job import SituationJob +from situations.situation_manager import SituationManager + + +class CommonSituationUtils: + """Utilities for manipulating Situations. + + """ + + @staticmethod + def get_situation_id(situation_identifier: Union[int, Situation]) -> Union[int, None]: + """get_situation_id(situation_identifier) + + Retrieve the decimal identifier of a Situation. + + :param situation_identifier: The identifier or instance of a Situation. + :type situation_identifier: Union[int, Situation] + :return: The decimal identifier of the Situation or None if the Situation does not have an id. + :rtype: Union[int, None] + """ + if isinstance(situation_identifier, int): + return situation_identifier + if not hasattr(situation_identifier, 'id'): + return -1 + return situation_identifier.id or getattr(situation_identifier, 'id', -1) + + @staticmethod + def get_situation_guid(situation_identifier: Union[int, Situation]) -> int: + """get_situation_guid(situation_identifier) + + Retrieve the GUID of a Situation. + + :param situation_identifier: The identifier or instance of a Situation. + :type situation_identifier: Union[int, Situation] + :return: The GUID of the specified Situation or -1 if it does not have one. + :rtype: int + """ + if situation_identifier is None: + return -1 + if isinstance(situation_identifier, int): + return situation_identifier + if not hasattr(situation_identifier, 'guid64'): + return -1 + return getattr(situation_identifier, 'guid64', -1) + + @staticmethod + def get_situation_job_guid(situation_job_identifier: Union[int, SituationJob]) -> int: + """get_situation_job_guid(situation_job_identifier) + + Retrieve the GUID of a Situation Job. + + :param situation_job_identifier: The identifier or instance of a Situation Job. + :type situation_job_identifier: Union[int, SituationJob] + :return: The GUID of the specified Situation or -1 if it does not have one. + :rtype: int + """ + if situation_job_identifier is None: + return -1 + if isinstance(situation_job_identifier, int): + return situation_job_identifier + if not hasattr(situation_job_identifier, 'guid64'): + return -1 + return getattr(situation_job_identifier, 'guid64', -1) + + @staticmethod + def get_situation_name(situation: Situation) -> Union[str, None]: + """get_situation_name(situation) + + Retrieve the Name of a Situation. + + :param situation: An instance of a Situation. + :type situation: Situation + :return: The short name of a Situation or None if a problem occurs. + :rtype: Union[str, None] + """ + if situation is None: + return None + # noinspection PyBroadException + try: + return situation.__class__.__name__ or '' + except: + return '' + + @staticmethod + def get_situation_names(situations: Iterator[Situation]) -> Tuple[str]: + """get_situation_names(situations) + + Retrieve the Names of a collection of Situation. + + :param situations: A collection of Situation instances. + :type situations: Iterator[Situation] + :return: A collection of names for all specified Situations. + :rtype: Tuple[str] + """ + if situations is None or not situations: + return tuple() + names: List[str] = [] + for situation in situations: + # noinspection PyBroadException + try: + name = CommonSituationUtils.get_situation_name(situation) + if not name: + continue + except: + continue + names.append(name) + return tuple(names) + + @staticmethod + def get_situation_manager_for_zone(zone_id: int=None) -> SituationManager: + """get_situation_manager_for_zone(zone_id=None) + + Retrieve the situation manager for a zone. + + :param zone_id: The zone to retrieve the situation manager of. Default is None, which is the current zone. + :type zone_id: int, optional + :return: The situation manager for the specified zone. + :rtype: SituationManager + """ + return services.get_zone_situation_manager(zone_id=zone_id) + + @staticmethod + def get_sim_info_for_all_sims_in_situation(situation: Situation) -> Tuple[SimInfo]: + """get_sim_info_for_all_sims_in_situation(situation) + + Retrieve a SimInfo object for all Sims in a Situation. + + :param situation: A situation + :type situation: Situation + :return: A collection of SimInfo for all Sims in the situation. + :rtype: Tuple[SimInfo] + """ + if situation is None: + return tuple() + result: Tuple[SimInfo] = tuple([CommonSimUtils.get_sim_info(_sim) for _sim in situation.all_sims_in_situation_gen()]) + return result + + @staticmethod + def get_sim_info_for_all_sims_in_running_situations_by_type(situation_type: Type[Situation]) -> Tuple[SimInfo]: + """get_sim_info_for_all_sims_in_running_situations_by_type(situation_type) + + Retrieve a SimInfo object for all Sims in a Situation. + + :param situation_type: The type of situation to locate. + :type situation_type: Type[Situation] + :return: A collection of SimInfo for all Sims in the situations that match the specified type. + :rtype: Tuple[SimInfo] + """ + sim_info_list: List[SimInfo] = list() + for situation in CommonSituationUtils.locate_running_situations_by_type(situation_type): + for sim in tuple(situation.all_sims_in_situation_gen()): + sim_info = CommonSimUtils.get_sim_info(sim) + if sim_info is None: + continue + sim_info_list.append(sim_info) + return tuple(sim_info_list) + + @staticmethod + def locate_running_situation_by_id(situation_id: Union[int, CommonSituationId, Situation], zone_id: int=None) -> Union[Situation, None]: + """locate_situation_by_id(situation_id, zone_id=None) + + Locate a running Situation from a Zone by its id. + + :param situation_id: The decimal identifier of a Situation. (Not to be confused with the instance id) + :type situation_id: Union[int, CommonSituationId, Situation] + :param zone_id: The zone to retrieve the situation from. Default is None, which is the current zone. + :type zone_id: int, optional + :return: The situation from the specified zone that matches the specified id or None if not found. + :rtype: Union[Situation, None] + """ + if isinstance(situation_id, Situation): + return situation_id + situation_manager = CommonSituationUtils.get_situation_manager_for_zone(zone_id=zone_id) + return situation_manager.get(situation_id) + + @staticmethod + def locate_first_running_situation_by_type(situation_type: Type[Situation], zone_id: int=None) -> Union[Situation, None]: + """locate_first_running_situation_by_type(situation_type, zone_id=None) + + Locate the first running Situation from a Zone by its Type. + + :param situation_type: The type of situation to search for. + :type situation_type: Type[Situation] + :param zone_id: The zone to locate the situations in. Default is None, which is the current zone. + :type zone_id: int, optional + :return: A collection of situations from the specified zone that have the specified tag. + :rtype: Tuple[Situation] + """ + situations = CommonSituationUtils.locate_running_situations_by_type(situation_type, zone_id=zone_id) + if situations: + return next(iter(situations)) + return None + + @staticmethod + def locate_first_running_situation_by_tag(tag: CommonGameTag, zone_id: int=None) -> Union[Situation, None]: + """locate_first_running_situation_by_tag(situation_type, zone_id=None) + + Locate the first running Situation from a Zone by a tag. + + :param tag: A tag to search for the situation with. + :type tag: CommonGameTag + :param zone_id: The zone to locate the situations in. Default is None, which is the current zone. + :type zone_id: int, optional + :return: A collection of situations from the specified zone that have the specified tag. + :rtype: Tuple[Situation] + """ + situations = CommonSituationUtils.locate_running_situations_by_tag(tag, zone_id=zone_id) + if situations: + return next(iter(situations)) + return None + + @staticmethod + def locate_first_running_situation_by_tags(tags: Iterator[CommonGameTag], zone_id: int=None) -> Union[Situation, None]: + """locate_first_running_situation_by_tag(situation_type, zone_id=None) + + Locate the first running Situation from a Zone by a collection of tags. + + :param tags: A list of tags to search for the situation with. + :type tags: Iterator[CommonGameTag] + :param zone_id: The zone to locate the situations in. Default is None, which is the current zone. + :type zone_id: int, optional + :return: A collection of situations from the specified zone that have the specified tag. + :rtype: Tuple[Situation] + """ + situations = CommonSituationUtils.locate_running_situations_by_tags(tags, zone_id=zone_id) + if situations: + return next(iter(situations)) + return None + + @staticmethod + def locate_running_situations_by_type(situation_type: Type[Situation], zone_id: int=None) -> Tuple[Situation]: + """locate_running_situations_by_type(situation_type, zone_id=None) + + Locate all running Situations in a Zone by Type. + + :param situation_type: The type of situation to search for. + :type situation_type: Type[Situation] + :param zone_id: The zone to locate the situations in. Default is None, which is the current zone. + :type zone_id: int, optional + :return: A collection of situations from the specified zone that have the specified tag. + :rtype: Tuple[Situation] + """ + if situation_type is None: + return tuple() + situation_manager = CommonSituationUtils.get_situation_manager_for_zone(zone_id=zone_id) + return tuple(situation_manager.get_situations_by_type(situation_type)) + + @staticmethod + def locate_running_situations_by_tag(tag: CommonGameTag, zone_id: int=None) -> Tuple[Situation]: + """locate_running_situations_by_tag(tag, zone_id=None) + + Locate all running Situations in a Zone by a tag. + + :param tag: A tag to search for situations with. + :type tag: CommonGameTag + :param zone_id: The zone to locate the situations in. Default is None, which is the current zone. + :type zone_id: int, optional + :return: A collection of situations from the specified zone that have the specified tag. + :rtype: Tuple[Situation] + """ + if tag is None: + return tuple() + return CommonSituationUtils.locate_running_situations_by_tags((tag,), zone_id=zone_id) + + @staticmethod + def locate_running_situations_by_tags(tags: Iterator[CommonGameTag], zone_id: int=None) -> Tuple[Situation]: + """locate_running_situations_by_tags(tags, zone_id=None) + + Locate all running Situations in a Zone by a collection of tags. + + :param tags: A list of tags to search for situations with. + :type tags: Iterator[CommonGameTag] + :param zone_id: The zone to locate the situations in. Default is None, which is the current zone. + :type zone_id: int, optional + :return: A collection of situations from the specified zone that have any of the specified tags. + :rtype: Tuple[Situation] + """ + tags = tuple(tags) + if not tags: + return tuple() + situation_manager: SituationManager = CommonSituationUtils.get_situation_manager_for_zone(zone_id=zone_id) + return tuple(situation_manager.get_situations_by_tags(set(tags))) + + @staticmethod + def load_situation_by_id(situation_guid: Union[int, CommonSituationId, Situation]) -> Union[Situation, None]: + """load_situation_by_id(situation_id) + + Load an instance of a Situation by its decimal identifier (GUID). + + :param situation_guid: The decimal identifier of a Situation. (Not to be confused with the instance id) + :type situation_guid: Union[int, CommonSituationId, Situation] + :return: An instance of a Situation matching the decimal identifier or None if not found. + :rtype: Union[Situation, None] + """ + if isinstance(situation_guid, Situation): + return situation_guid + # noinspection PyBroadException + try: + # noinspection PyCallingNonCallable + situation_instance = situation_guid() + if isinstance(situation_instance, Situation): + return situation_guid + except: + pass + # noinspection PyBroadException + try: + situation_guid: int = int(situation_guid) + except: + situation_guid: Situation = situation_guid + return situation_guid + + from sims4.resources import Types + from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + return CommonResourceUtils.load_instance(Types.SITUATION, situation_guid) diff --git a/Scripts/s4ap/sims4communitylib/utils/resources/common_skill_utils.py b/Scripts/s4ap/sims4communitylib/utils/resources/common_skill_utils.py new file mode 100644 index 0000000..b8b40f7 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/resources/common_skill_utils.py @@ -0,0 +1,121 @@ +""" +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 +""" +from typing import Union, Iterator, Tuple, List, Callable +from sims4communitylib.enums.skills_enum import CommonSkillId +from statistics.skill import Skill + + +class CommonSkillUtils: + """Utilities for manipulating Skills. + + """ + + @staticmethod + def get_skill_id(skill_identifier: Union[int, Skill]) -> Union[int, None]: + """get_skill_id(skill_identifier) + + Retrieve the decimal identifier of a Skill. + + :param skill_identifier: The identifier or instance of a Skill. + :type skill_identifier: Union[int, Skill] + :return: The decimal identifier of the Skill or None if the Skill does not have an id. + :rtype: Union[int, None] + """ + if isinstance(skill_identifier, int): + return skill_identifier + return getattr(skill_identifier, 'guid64', None) + + @staticmethod + def get_short_name(skill: Skill) -> Union[str, None]: + """get_short_name(skill) + + Retrieve the Short Name of a Skill. + + :param skill: An instance of a Skill. + :type skill: Skill + :return: The short name of a Skill or None if a problem occurs. + :rtype: Union[str, None] + """ + if skill is None: + return None + # noinspection PyBroadException + try: + return skill.__class__.__name__ + except: + return '' + + @staticmethod + def get_short_names(skills: Iterator[Skill]) -> Tuple[str]: + """get_short_names(skills) + + Retrieve the Short Names of a collection of Skills. + + :param skills: A collection of Skill instances. + :type skills: Iterator[Skill] + :return: A collection of short names of all Skill instances. + :rtype: Tuple[str] + """ + if skills is None or not skills: + return tuple() + short_names: List[str] = [] + for skill in skills: + # noinspection PyBroadException + try: + short_name = CommonSkillUtils.get_short_name(skill) + if not short_name: + continue + except: + continue + short_names.append(short_name) + return tuple(short_names) + + @staticmethod + def get_all_skills_gen(include_skill_callback: Callable[[Skill], bool] = None) -> Iterator[Skill]: + """get_all_skills_gen(include_skill_callback=None) + + Retrieve all Skills. + + :param include_skill_callback: If the result of this callback is True, the Skill will be included in the results. If set to None, All Skills will be included. + :type include_skill_callback: Callable[[Skill], bool], optional + :return: An iterator of Skills that pass the specified include_skill_callback. + :rtype: Iterator[Skill] + """ + from sims4communitylib.utils.resources.common_statistic_utils import CommonStatisticUtils + statistic_manager = CommonStatisticUtils.get_statistic_instance_manager() + for skill in statistic_manager.get_ordered_types(only_subclasses_of=Skill): + skill: Skill = skill + skill_id = CommonSkillUtils.get_skill_id(skill) + if skill_id is None: + continue + if include_skill_callback is not None and not include_skill_callback(skill): + continue + yield skill + + @staticmethod + def load_skill_by_id(skill_id: Union[int, CommonSkillId, Skill]) -> Union[Skill, None]: + """load_skill_by_id(skill_id) + + Load an instance of a Skill by its decimal identifier. + + :param skill_id: The decimal identifier of a Skill. + :type skill_id: Union[int, CommonSkillId, Skill] + :return: An instance of a Skill matching the decimal identifier or None if not found. + :rtype: Union[Skill, None] + """ + if isinstance(skill_id, Skill) or hasattr(skill_id, 'is_skill'): + return skill_id + # noinspection PyBroadException + try: + skill_id: int = int(skill_id) + except: + # noinspection PyTypeChecker + skill_id: Skill = skill_id + return skill_id + + from sims4communitylib.utils.resources.common_statistic_utils import CommonStatisticUtils + return CommonStatisticUtils.load_statistic_by_id(skill_id) diff --git a/Scripts/s4ap/sims4communitylib/utils/resources/common_statistic_utils.py b/Scripts/s4ap/sims4communitylib/utils/resources/common_statistic_utils.py new file mode 100644 index 0000000..902fe7c --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/resources/common_statistic_utils.py @@ -0,0 +1,131 @@ +""" +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 +""" +from typing import Union + +from sims4communitylib.enums.statistics_enum import CommonStatisticId +from statistics.base_statistic import BaseStatistic +from statistics.statistic_instance_manager import StatisticInstanceManager + + +class CommonStatisticUtils: + """Utilities for manipulating Statistics. + + """ + @staticmethod + def get_statistic_initial_value(statistic_id: Union[int, CommonStatisticId, BaseStatistic]) -> 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: Union[int, CommonStatisticId, BaseStatistic] + :return: The initial value of the statistic. + :rtype: float + """ + statistic_instance = CommonStatisticUtils.load_statistic_by_id(statistic_id) + if statistic_instance is None: + return -1.0 + if hasattr(statistic_instance, 'get_initial_value'): + return statistic_instance.get_initial_value() + return statistic_instance.default_value + + @staticmethod + def get_statistic_min_value(statistic_id: Union[int, CommonStatisticId, BaseStatistic]) -> 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: Union[int, CommonStatisticId, BaseStatistic] + :return: The minimum value of the statistic. + :rtype: float + """ + statistic_instance = CommonStatisticUtils.load_statistic_by_id(statistic_id) + if statistic_instance is None: + return -1.0 + return statistic_instance.min_value + + @staticmethod + def get_statistic_max_value(statistic_id: Union[int, CommonStatisticId, BaseStatistic]) -> 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: Union[int, CommonStatisticId, BaseStatistic] + :return: The maximum value of the statistic. + :rtype: float + """ + statistic_instance = CommonStatisticUtils.load_statistic_by_id(statistic_id) + if statistic_instance is None: + return -1.0 + return statistic_instance.max_value + + @staticmethod + def get_statistic_id(statistic_identifier: Union[int, BaseStatistic]) -> Union[int, None]: + """get_statistic_id(statistic_identifier) + + Retrieve the decimal identifier of a Statistic. + + :param statistic_identifier: The identifier or instance of a Statistic. + :type statistic_identifier: Union[int, BaseStatistic] + :return: The decimal identifier of the Statistic or None if the Statistic does not have an id. + :rtype: Union[int, None] + """ + if isinstance(statistic_identifier, int): + return statistic_identifier + if hasattr(statistic_identifier, 'id'): + return statistic_identifier.id + return getattr(statistic_identifier, 'guid64', None) + + @staticmethod + def load_statistic_by_id(statistic_id: Union[int, CommonStatisticId, BaseStatistic]) -> Union[BaseStatistic, None]: + """load_statistic_by_id(statistic_id) + + Load an instance of a Statistic by its decimal identifier. + + :param statistic_id: The decimal identifier of a Statistic. + :type statistic_id: Union[int, CommonStatisticId, BaseStatistic] + :return: An instance of a Statistic matching the decimal identifier or None if not found. + :rtype: Union[BaseStatistic, None] + """ + if isinstance(statistic_id, BaseStatistic): + return statistic_id + # noinspection PyBroadException + try: + # noinspection PyCallingNonCallable + statistic_instance = statistic_id() + if isinstance(statistic_instance, BaseStatistic): + return statistic_id + except: + pass + # noinspection PyBroadException + try: + statistic_id: int = int(statistic_id) + except: + # noinspection PyTypeChecker + statistic_id: BaseStatistic = statistic_id + return statistic_id + + from sims4.resources import Types + from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + return CommonResourceUtils.load_instance(Types.STATISTIC, statistic_id) or CommonResourceUtils.load_instance(Types.STATIC_COMMODITY, statistic_id) + + @staticmethod + def get_statistic_instance_manager() -> StatisticInstanceManager: + """get_statistic_instance_manager() + + Retrieve the manager that manages all Statistics. + + :return: The manager that manages all Statistics. + :rtype: StatisticInstanceManager + """ + from sims4.resources import Types + from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + # noinspection PyTypeChecker + return CommonResourceUtils.get_instance_manager(Types.STATISTIC) diff --git a/Scripts/s4ap/sims4communitylib/utils/save_load/__init__.py b/Scripts/s4ap/sims4communitylib/utils/save_load/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/save_load/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/utils/save_load/common_save_utils.py b/Scripts/s4ap/sims4communitylib/utils/save_load/common_save_utils.py new file mode 100644 index 0000000..a8d08a8 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/save_load/common_save_utils.py @@ -0,0 +1,56 @@ +""" +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 +""" +import services +from typing import Any + + +class CommonSaveUtils: + """ Utilities for managing save files. """ + @staticmethod + def get_save_slot_guid() -> int: + """get_save_slot_guid() + + Retrieve the guid identifier for the current save slot. + + :return: The GUID identifier for the current save slot. + :return: int + """ + return services.get_persistence_service().get_save_slot_proto_guid() + + @staticmethod + def get_save_slot() -> Any: + """get_save_slot() + + Retrieve the current save slot. + + :return: The current save slot. + :return: Any + """ + return services.get_persistence_service().get_save_slot_proto_buff() + + @staticmethod + def get_save_slot_id() -> int: + """get_save_slot_id() + + Retrieve the identifier for the current save slot. + + :return: The identifier for the current save slot. + :return: int + """ + return CommonSaveUtils.get_save_slot().slot_id + + @staticmethod + def get_save_account() -> Any: + """get_save_account() + + Retrieve the current save account. + + :return: The current save account. + :return: Any + """ + return services.get_persistence_service().get_account_proto_buff() diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/__init__.py b/Scripts/s4ap/sims4communitylib/utils/sims/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_age_species_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_age_species_utils.py new file mode 100644 index 0000000..2bdb9c3 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_age_species_utils.py @@ -0,0 +1,446 @@ +""" +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 +""" +from sims.sim_info import SimInfo +from sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils +from sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils + + +class CommonAgeSpeciesUtils: + """Utilities for checking the Age and Species of Sims. + + """ + @staticmethod + def is_baby_human(sim_info: SimInfo) -> bool: + """is_baby_human(sim_info) + + Determine if a sim is a Baby Human. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is a Baby Human. False, if the Sim is not. + :rtype: bool + """ + return CommonAgeUtils.is_baby(sim_info) and CommonSpeciesUtils.is_human(sim_info) + + @staticmethod + def is_toddler_human(sim_info: SimInfo) -> bool: + """is_toddler_human(sim_info) + + Determine if a sim is a Toddler Human. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is a Toddler Human. False, if the Sim is not. + :rtype: bool + """ + return CommonAgeUtils.is_toddler(sim_info) and CommonSpeciesUtils.is_human(sim_info) + + @staticmethod + def is_child_human(sim_info: SimInfo) -> bool: + """is_child_human(sim_info) + + Determine if a sim is a Child Human. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is a Child Human. False, if the Sim is not. + :rtype: bool + """ + return CommonAgeUtils.is_child(sim_info) and CommonSpeciesUtils.is_human(sim_info) + + @staticmethod + def is_teen_human(sim_info: SimInfo) -> bool: + """is_teen_human(sim_info) + + Determine if a sim is a Teen Human. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is a Teen Human. False, if the Sim is not. + :rtype: bool + """ + return CommonAgeUtils.is_teen(sim_info) and CommonSpeciesUtils.is_human(sim_info) + + @staticmethod + def is_young_adult_human(sim_info: SimInfo) -> bool: + """is_young_adult_human(sim_info) + + Determine if a sim is a Young Adult Human. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is a Young Adult Human. False, if the Sim is not. + :rtype: bool + """ + return CommonAgeUtils.is_young_adult(sim_info) and CommonSpeciesUtils.is_human(sim_info) + + @staticmethod + def is_mature_adult_human(sim_info: SimInfo) -> bool: + """is_mature_adult_human(sim_info) + + Determine if a sim is an Adult Human. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is an Adult Human. False, if the Sim is not. + :rtype: bool + """ + return CommonAgeUtils.is_mature_adult(sim_info) and CommonSpeciesUtils.is_human(sim_info) + + @staticmethod + def is_elder_human(sim_info: SimInfo) -> bool: + """is_elder_human(sim_info) + + Determine if a sim is an Elder Human. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is an Elder Human. False, if the Sim is not. + :rtype: bool + """ + return CommonAgeUtils.is_elder(sim_info) and CommonSpeciesUtils.is_human(sim_info) + + @staticmethod + def is_adult_human(sim_info: SimInfo) -> bool: + """is_adult_human(sim_info) + + Determine if a sim is a Young Adult or Adult Human. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is a Young Adult or Adult Human. False, if the Sim is not. + :rtype: bool + """ + return CommonAgeUtils.is_adult(sim_info) and CommonSpeciesUtils.is_human(sim_info) + + @staticmethod + def is_baby_or_toddler_human(sim_info: SimInfo) -> bool: + """is_baby_or_toddler_human(sim_info) + + Determine if a sim is a Baby or Toddler Human. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is a Baby or Toddler Human. False, if the Sim is not. + :rtype: bool + """ + return CommonAgeUtils.is_baby_or_toddler(sim_info) and CommonSpeciesUtils.is_human(sim_info) + + @staticmethod + def is_child_or_teen_human(sim_info: SimInfo) -> bool: + """is_child_or_teen_human(sim_info) + + Determine if a sim is a Child or Teen Human. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is a Child or Teen Human. False, if the Sim is not. + :rtype: bool + """ + return CommonAgeUtils.is_child_or_teen(sim_info) and CommonSpeciesUtils.is_human(sim_info) + + @staticmethod + def is_toddler_or_child_human(sim_info: SimInfo) -> bool: + """is_toddler_or_child_human(sim_info) + + Determine if a sim is a Toddler or Child Human. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is a Toddler or Child Human. False, if the Sim is not. + :rtype: bool + """ + return CommonAgeUtils.is_toddler_or_child(sim_info) and CommonSpeciesUtils.is_human(sim_info) + + @staticmethod + def is_baby_toddler_or_child_human(sim_info: SimInfo) -> bool: + """is_baby_toddler_or_child_human(sim_info) + + Determine if a sim is a Baby, Toddler, or Child Human. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is a Baby, Toddler, or Child Human. False, if the Sim is not. + :rtype: bool + """ + return CommonAgeUtils.is_baby_toddler_or_child(sim_info) and CommonSpeciesUtils.is_human(sim_info) + + @staticmethod + def is_teen_or_young_adult_human(sim_info: SimInfo) -> bool: + """is_teen_or_young_adult_human(sim_info) + + Determine if a sim is a Teen or Young Adult Human. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is a Teen or Young Adult Human. False, if the Sim is not. + :rtype: bool + """ + return CommonAgeUtils.is_teen_or_young_adult(sim_info) and CommonSpeciesUtils.is_human(sim_info) + + @staticmethod + def is_teen_or_adult_human(sim_info: SimInfo) -> bool: + """is_teen_or_adult_human(sim_info) + + Determine if a sim is a Teen, Young Adult, or Adult Human. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is a Teen, Young Adult, or Adult Human. False, if the Sim is not. + :rtype: bool + """ + return CommonAgeUtils.is_teen_or_adult(sim_info) and CommonSpeciesUtils.is_human(sim_info) + + @staticmethod + def is_mature_adult_or_elder_human(sim_info: SimInfo) -> bool: + """is_mature_adult_or_elder_human(sim_info) + + Determine if a sim is a Adult or Elder Human. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is a Adult or Elder Human. False, if the Sim is not. + :rtype: bool + """ + return CommonAgeUtils.is_mature_adult_or_elder(sim_info) and CommonSpeciesUtils.is_human(sim_info) + + @staticmethod + def is_teen_adult_or_elder_human(sim_info: SimInfo) -> bool: + """is_teen_adult_or_elder_human(sim_info) + + Determine if a sim is a Teen, Young Adult, Adult, or Elder Human. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is a Teen, Young Adult, Adult, or Elder Human. False, if the Sim is not. + :rtype: bool + """ + return CommonAgeUtils.is_teen_adult_or_elder(sim_info) and CommonSpeciesUtils.is_human(sim_info) + + @staticmethod + def is_child_pet(sim_info: SimInfo) -> bool: + """is_child_pet(sim_info) + + Determine if a sim is a Child Pet (Cat, Small Dog, Large Dog). + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is a Child Pet (Cat, Small Dog, Large Dog). False, if the Sim is not. + :rtype: bool + """ + return CommonAgeUtils.is_child(sim_info) and CommonSpeciesUtils.is_pet(sim_info) + + @staticmethod + def is_adult_pet(sim_info: SimInfo) -> bool: + """is_adult_pet(sim_info) + + Determine if a sim is an Adult Pet (Cat, Small Dog, Large Dog). + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is an Adult Pet (Cat, Small Dog, Large Dog). False, if the Sim is not. + :rtype: bool + """ + return CommonAgeUtils.is_adult(sim_info) and CommonSpeciesUtils.is_pet(sim_info) + + @staticmethod + def is_elder_pet(sim_info: SimInfo) -> bool: + """is_elder_pet(sim_info) + + Determine if a sim is an Elder Pet (Cat, Small Dog, Large Dog). + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is an Elder Pet (Cat, Small Dog, Large Dog). False, if the Sim is not. + :rtype: bool + """ + return CommonAgeUtils.is_elder(sim_info) and CommonSpeciesUtils.is_pet(sim_info) + + @staticmethod + def is_old_pet(sim_info: SimInfo) -> bool: + """is_old_pet(sim_info) + + Determine if a sim is an Adult or Elder Pet (Cat, Small Dog, Large Dog). + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is an Adult or Elder Pet (Cat, Small Dog, Large Dog). False, if the Sim is not. + :rtype: bool + """ + return CommonAgeUtils.is_adult_or_elder(sim_info) and CommonSpeciesUtils.is_pet(sim_info) + + @staticmethod + def is_child_animal(sim_info: SimInfo) -> bool: + """is_child_animal(sim_info) + + Determine if a sim is a Child Animal (Cat, Small Dog, Large Dog, Fox). + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is a Child Animal (Cat, Small Dog, Large Dog, Fox). False, if the Sim is not. + :rtype: bool + """ + return CommonAgeUtils.is_child(sim_info) and CommonSpeciesUtils.is_animal(sim_info) + + @staticmethod + def is_adult_animal(sim_info: SimInfo) -> bool: + """is_adult_animal(sim_info) + + Determine if a sim is an Adult Animal (Cat, Small Dog, Large Dog, Fox). + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is an Adult Pet (Cat, Small Dog, Large Dog, Fox). False, if the Sim is not. + :rtype: bool + """ + return CommonAgeUtils.is_adult(sim_info) and CommonSpeciesUtils.is_animal(sim_info) + + @staticmethod + def is_elder_animal(sim_info: SimInfo) -> bool: + """is_elder_animal(sim_info) + + Determine if a sim is an Elder Pet (Cat, Small Dog, Large Dog, Fox). + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is an Elder Pet (Cat, Small Dog, Large Dog, Fox). False, if the Sim is not. + :rtype: bool + """ + return CommonAgeUtils.is_elder(sim_info) and CommonSpeciesUtils.is_animal(sim_info) + + @staticmethod + def is_old_animal(sim_info: SimInfo) -> bool: + """is_old_animal(sim_info) + + Determine if a Sim is an Adult or Elder Animal (Cat, Small Dog, Large Dog, Fox). + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is an Adult or Elder Animal (Cat, Small Dog, Large Dog, Fox). False, if the Sim is not. + :rtype: bool + """ + return CommonAgeUtils.is_adult_or_elder(sim_info) and CommonSpeciesUtils.is_animal(sim_info) + + @staticmethod + def is_adult_human_or_pet(sim_info: SimInfo) -> bool: + """is_adult_human_or_pet(sim_info) + + Determine if a sim is a Young Adult, Adult, or Elder Human or an Adult Pet (Cat, Small Dog, Large Dog). + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is a Young Adult, Adult, or Elder Human or an Adult Pet (Cat, Small Dog, Large Dog). False, if the Sim is not. + :rtype: bool + """ + return CommonAgeSpeciesUtils.is_adult_human(sim_info) or CommonAgeSpeciesUtils.is_adult_pet(sim_info) + + @staticmethod + def is_elder_human_or_pet(sim_info: SimInfo) -> bool: + """is_elder_human_or_pet(sim_info) + + Determine if a sim is an Elder Human or Pet (Cat, Small Dog, Large Dog). + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is an Elder Human or Pet (Cat, Small Dog, Large Dog). False, if the Sim is not. + :rtype: bool + """ + return CommonAgeSpeciesUtils.is_elder_human(sim_info) or CommonAgeSpeciesUtils.is_elder_pet(sim_info) + + @staticmethod + def is_young_human_or_pet(sim_info: SimInfo) -> bool: + """is_young_human_or_pet(sim_info) + + Determine if a sim is a Baby, Toddler, or Child Human or a Child Pet (Cat, Small Dog, Large Dog). + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is a Baby, Toddler, or Child Human or a Child Pet (Cat, Small Dog, Large Dog). False, if the Sim is not. + :rtype: bool + """ + return CommonAgeSpeciesUtils.is_baby_toddler_or_child_human(sim_info) or CommonAgeSpeciesUtils.is_child_pet(sim_info) + + @staticmethod + def is_old_human_or_pet(sim_info: SimInfo) -> bool: + """is_old_human_or_pet(sim_info) + + Determine if a sim is a Teen, Young Adult, Adult, or Elder Human or an Adult or Elder Pet (Cat, Small Dog, Large Dog). + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is a Teen, Young Adult, Adult, or Elder Human or an Adult or Elder Pet (Cat, Small Dog, Large Dog). False, if the Sim is not. + :rtype: bool + """ + return CommonAgeSpeciesUtils.is_teen_adult_or_elder_human(sim_info) or CommonAgeSpeciesUtils.is_old_pet(sim_info) + + @staticmethod + def is_adult_human_or_animal(sim_info: SimInfo) -> bool: + """is_adult_human_or_animal(sim_info) + + Determine if a sim is a Young Adult, Adult, or Elder Human or an Adult Animal (Cat, Small Dog, Large Dog, Fox). + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is a Young Adult, Adult, or Elder Human or an Adult Animal (Cat, Small Dog, Large Dog, Fox). False, if the Sim is not. + :rtype: bool + """ + return CommonAgeSpeciesUtils.is_adult_human(sim_info) or CommonAgeSpeciesUtils.is_adult_animal(sim_info) + + @staticmethod + def is_elder_human_or_animal(sim_info: SimInfo) -> bool: + """is_elder_human_or_animal(sim_info) + + Determine if a sim is an Elder Human or Animal (Cat, Small Dog, Large Dog, Fox). + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is an Elder Human or Animal (Cat, Small Dog, Large Dog, Fox). False, if the Sim is not. + :rtype: bool + """ + return CommonAgeSpeciesUtils.is_elder_human(sim_info) or CommonAgeSpeciesUtils.is_elder_animal(sim_info) + + @staticmethod + def is_young_human_or_animal(sim_info: SimInfo) -> bool: + """is_young_human_or_animal(sim_info) + + Determine if a sim is a Baby, Toddler, or Child Human or a Child Animal (Cat, Small Dog, Large Dog, Fox). + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is a Baby, Toddler, or Child Human or a Child Animal (Cat, Small Dog, Large Dog, Fox). False, if the Sim is not. + :rtype: bool + """ + return CommonAgeSpeciesUtils.is_baby_toddler_or_child_human(sim_info) or CommonAgeSpeciesUtils.is_child_animal(sim_info) + + @staticmethod + def is_old_human_or_animal(sim_info: SimInfo) -> bool: + """is_old_human_or_animal(sim_info) + + Determine if a sim is a Teen, Young Adult, Adult, or Elder Human or an Adult or Elder Animal (Cat, Small Dog, Large Dog, Fox). + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is a Teen, Young Adult, Adult, or Elder Human or an Adult or Elder Animal (Cat, Small Dog, Large Dog, Fox). False, if the Sim is not. + :rtype: bool + """ + return CommonAgeSpeciesUtils.is_teen_adult_or_elder_human(sim_info) or CommonAgeSpeciesUtils.is_old_animal(sim_info) + + @staticmethod + def are_same_age_and_species(sim_info: SimInfo, other_sim_info: SimInfo) -> bool: + """are_same_age_and_species(sim_info, other_sim_info) + + Determine if two Sims are the same Age and the same Species. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :param other_sim_info: The other Sim to compare to. + :type other_sim_info: SimInfo + :return: True, if both Sims are the same Age and Species. False, if they are not. + :rtype: bool + """ + return CommonAgeUtils.are_same_age(sim_info, other_sim_info) and CommonSpeciesUtils.are_same_species(sim_info, other_sim_info) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_age_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_age_utils.py new file mode 100644 index 0000000..d573696 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_age_utils.py @@ -0,0 +1,1103 @@ +""" +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 +""" +import random +from typing import Union, Iterator + +import services +from event_testing.test_events import TestEvent +from sims.sim_info import SimInfo +from sims.sim_info_types import Age, Species, SpeciesExtended +from sims4communitylib.enums.common_age import CommonAge +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + CommonConsoleCommandArgument +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput + + +class CommonAgeUtils: + """Utilities for manipulating Ages of Sims. + + """ + @classmethod + def get_age(cls, sim_info: SimInfo, exact_age: bool = False) -> Union[Age, int, None]: + """get_age(sim_info, exact_age=False) + + Retrieve the Age of a Sim. + + :param sim_info: The Sim to get the Age of. + :type sim_info: SimInfo + :param exact_age: If set to True, the exact age of the Sim will be returned (Age 24 will be returned as 24). If set to False, the age of the Sim rounded to the nearest Age value will be returned. (Age 24 will be returned as Age.YOUNGADULT). Default is False. + :type exact_age: bool, optional + :return: The Age of the Sim or None if a problem occurs. + :rtype: Union[Age, None] + """ + if sim_info is None: + return None + age: Union[Age, None] = None + if hasattr(sim_info, 'age'): + # noinspection PyPropertyAccess + age = sim_info.age + elif hasattr(sim_info, 'sim_info') and hasattr(sim_info.sim_info, '_base') and hasattr(sim_info.sim_info._base, 'age') and exact_age: + age = sim_info.sim_info._base.age + elif hasattr(sim_info, '_base') and hasattr(sim_info._base, 'age'): + age = sim_info._base.age + elif hasattr(sim_info, 'sim_info') and hasattr(sim_info.sim_info, '_base') and hasattr(sim_info.sim_info._base, 'age') and exact_age: + age = sim_info.sim_info._base.age + elif hasattr(sim_info, 'sim_info') and hasattr(sim_info.sim_info, 'age'): + age = sim_info.sim_info.age + if age is None: + return None + if exact_age: + return age + return cls.convert_to_approximate_age(age) + + @classmethod + def get_birth_age(cls, sim_info: SimInfo) -> Age: + """get_birth_age(sim_info) + + Retrieve the Age that New Sims will be, if they are born from a specified Sim. + + .. note:: Human Sims start at the BABY age. Pet Sims (Large Dog, Small Dog, Cat, Horse) start at the CHILD age. Fox Sims start at the ADULT age. + + :param sim_info: The info of a Sim. + :type sim_info: SimInfo + :return: The Age that New Sims will be, if they are born from the specified Sim. + :rtype: Age + """ + return sim_info.get_birth_age() + + @classmethod + def get_birth_age_from_species(cls, species: Union[Species, SpeciesExtended, int]) -> Union[Age, None]: + """get_birth_age_from_species(species) + + Retrieve the Age that New Sims will be, if they are born with a specified Species. + + .. note:: The HUMAN species starts at the BABY age. The Pet species (Large Dog, Small Dog, Cat, Horse) start at the CHILD age. The FOX species starts at the ADULT age. + + :param species: The species to retrieve information for. + :type species: Union[Species, SpeciesExtended, int] + :return: The Age that New Sims will be, if they are born with the specified Species or None if an Age is not found for the specified Species. + :rtype: Union[Age, None] + """ + from sims.aging.aging_tuning import AgingTuning + cleaned_species = species + if cleaned_species == SpeciesExtended.SMALLDOG: + cleaned_species = Species.DOG + cleaned_species = Species(cleaned_species) + if cleaned_species in AgingTuning.AGING_DATA: + aging_data = AgingTuning.get_aging_data(cleaned_species) + return aging_data.get_birth_age() + + if species == SpeciesExtended.HUMAN: + return Age.BABY + + if species == SpeciesExtended.FOX: + return Age.ADULT + + from sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils + if CommonSpeciesUtils.is_animal_species(species) or species == SpeciesExtended.SMALLDOG: + return Age.CHILD + return None + + @classmethod + def convert_to_approximate_age(cls, age: Union[CommonAge, Age, int]) -> Age: + """convert_to_approximate_age(age) + + Convert an age to an approximate Age value. + + :param age: An Age. + :type age: Union[CommonAge, Age, int] + :return: The specified Age converted into an approximate Age value. + :rtype: Age + """ + if isinstance(age, CommonAge): + return CommonAge.convert_to_vanilla(age) + if isinstance(age, Age): + return age + age: int = int(age) + if int(age) == int(Age.INFANT): + return Age.INFANT + if int(Age.BABY) <= age < int(Age.INFANT): + return Age.BABY + if int(Age.INFANT) <= age < int(Age.TODDLER): + return Age.INFANT + if int(Age.TODDLER) <= age < int(Age.CHILD): + return Age.TODDLER + if int(Age.CHILD) <= age < int(Age.TEEN): + return Age.CHILD + if int(Age.TEEN) <= age < int(Age.YOUNGADULT): + return Age.TEEN + if int(Age.YOUNGADULT) <= age < int(Age.ADULT): + return Age.YOUNGADULT + if int(Age.ADULT) <= age < int(Age.ELDER): + return Age.ADULT + if int(Age.ELDER) <= age: + return Age.ELDER + return Age.INFANT + + @classmethod + def get_total_days_sim_has_been_in_their_current_age(cls, sim_info: SimInfo) -> float: + """get_total_days_sim_has_been_in_their_current_age(sim_info) + + Retrieve the total number of days a Sim has been in their current Age. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: A total number of days the specified Sim has been in their current Age. + :rtype: float + """ + return sim_info.age_progress + + @classmethod + def get_percentage_total_days_sim_has_been_in_their_current_age(cls, sim_info: SimInfo) -> float: + """get_percentage_total_days_sim_has_been_in_their_current_age(sim_info) + + Retrieve the percentage total days a Sim has been in their current age. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The percentage total days the specified Sim has been in their current age. + :rtype: float + """ + return sim_info.age_progress/sim_info._age_time*sim_info.AGE_PROGRESS_BAR_FACTOR + + @classmethod + def get_total_days_until_sim_ages_up(cls, sim_info: SimInfo) -> int: + """get_total_days_until_sim_ages_up(sim_info) + + Retrieve the total number of days a Sim has left until they age up. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The total number of days the specified Sim has left until they age up. + :rtype: int + """ + return sim_info.days_until_ready_to_age() + + @classmethod + def get_total_days_to_age_up(cls, sim_info: SimInfo) -> float: + """get_total_days_to_age_up(sim_info) + + Retrieve the total number of days required for the next age of a Sim to be required. (Not to be confused with the amount of days they have left) + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The total number of days required for the specified Sim to reach their next age. + :rtype: float + """ + sim_age = cls.get_age(sim_info, exact_age=False) + age_transition_data = sim_info.get_age_transition_data(sim_age) + return sim_info._age_time/age_transition_data.get_age_duration(sim_info) + + @classmethod + def set_total_days_sim_has_been_in_their_current_age(cls, sim_info: SimInfo, days: float) -> None: + """set_total_days_sim_has_been_in_their_current_age(sim_info, days) + + Set the total number of days of progress made towards the next age of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param days: The total number of days the Sim has been in their current age. + :type days: float + """ + delta_age = days + new_age_value = min(delta_age, sim_info._age_time) + sim_info._set_age_progress(new_age_value - sim_info.FILL_AGE_PROGRESS_BAR_BUFFER) + + @classmethod + def set_percentage_total_days_sim_has_been_in_their_current_age(cls, sim_info: SimInfo, percentage_progress: float) -> None: + """set_percentage_total_days_sim_has_been_in_their_current_age(sim_info, percentage_progress) + + Set the percentage total days a Sim has been in their current age. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param percentage_progress: A percentage total days a Sim has been in their current age. + :type percentage_progress: int + """ + if percentage_progress < 0: + percentage_progress *= -1 + delta_age = cls.get_total_days_to_age_up(sim_info) * (percentage_progress / 100) + new_age_value = min(delta_age, sim_info._age_time) + sim_info._set_age_progress(new_age_value - sim_info.FILL_AGE_PROGRESS_BAR_BUFFER) + + @classmethod + def set_age(cls, sim_info: SimInfo, age: Union[CommonAge, Age, int]) -> bool: + """set_age(sim_info, age) + + Set the Age of a Sim. + + :param sim_info: The Sim to set the Age of. + :type sim_info: SimInfo + :param age: The Age to set the Sim to. + :type age: Union[CommonAge, Age, int] + :return: True, if the Age was set successfully. False, if not. + :rtype: bool + """ + from sims4.resources import Types + from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + age = cls.convert_to_approximate_age(age) + if age is None: + return False + current_age = cls.get_age(sim_info, exact_age=False) + approximate_age = cls.convert_to_approximate_age(age) + if current_age is None: + return False + if current_age == approximate_age: + return True + sim_info.change_age(age, current_age) + services.get_event_manager().process_event(TestEvent.AgedUp, sim_info=sim_info) + school_data = sim_info.get_school_data() + if school_data is not None: + school_data.update_school_data(sim_info, create_homework=True) + if sim_info.is_npc: + if sim_info.is_child or sim_info.is_teen: + available_aspirations = [] + aspiration_track_manager = CommonResourceUtils.get_instance_manager(Types.ASPIRATION_TRACK) + aspiration_tracker = sim_info.aspiration_tracker + for aspiration_track in aspiration_track_manager.types.values(): + track_available = not aspiration_track.is_hidden_unlockable + if aspiration_tracker is not None: + track_available = aspiration_tracker.is_aspiration_track_visible(aspiration_track) + if track_available: + if sim_info.is_child and hasattr(aspiration_track, 'is_child_aspiration_track') and aspiration_track.is_child_aspiration_track: + available_aspirations.append(aspiration_track) + elif sim_info.is_teen: + available_aspirations.append(aspiration_track) + if available_aspirations: + sim_info.primary_aspiration = random.choice(available_aspirations) + number_of_empty_trait_slots = sim_info.trait_tracker.empty_slot_number + if number_of_empty_trait_slots: + # noinspection PyUnresolvedReferences + available_traits = [trait for trait in services.trait_manager().types.values() if trait.is_personality_trait] + while number_of_empty_trait_slots > 0 and available_traits: + trait = random.choice(available_traits) + available_traits.remove(trait) + if sim_info.trait_tracker.can_add_trait(trait) and sim_info.add_trait(trait): + number_of_empty_trait_slots -= 1 + age_transition = sim_info.get_age_transition_data(age) + age_transition.apply_aging_transition_loot(sim_info) + sim_info._create_additional_statistics() + sim_info._apply_life_skill_traits() + sim_info._relationship_tracker.update_compatibilities() + return cls.get_age(sim_info) == age or cls.get_age(sim_info, exact_age=True) == age + + @classmethod + def are_same_age(cls, sim_info: SimInfo, other_sim_info: SimInfo) -> bool: + """are_same_age(sim_info, other_sim_info) + + Determine if two Sims are the same Age. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :param other_sim_info: The other Sim to compare to. + :type other_sim_info: SimInfo + :return: True, if both Sims are the same Age. + :rtype: bool + """ + return int(cls.get_age(sim_info)) == int(cls.get_age(other_sim_info)) + + @classmethod + def is_younger_than(cls, sim_info: SimInfo, age: Union[CommonAge, Age, int], or_equal: bool = False) -> bool: + """is_younger_than(sim_info, age, or_equal=False) + + Determine if a Sim is younger than the specified Age. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :param age: The age to check with. + :type age: Union[CommonAge, Age, int] + :param or_equal: If True, the age check will be younger than or equal to. If False, the age check will be younger than. + :type or_equal: bool + :return: True, if the Sim is younger than the specified Age or equal to the specified age if `or_equal` is True. False, if not. + :rtype: bool + """ + age = int(age) + sim_age = int(cls.get_age(sim_info)) + if or_equal: + return sim_age <= age + return sim_age < age + + @classmethod + def is_older_than(cls, sim_info: SimInfo, age: Union[CommonAge, Age, int], or_equal: bool = False) -> bool: + """is_older_than(sim_info, age, or_equal=False) + + Determine if a Sim is older than the specified Age. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :param age: The age to check with. + :type age: Union[CommonAge, Age, int] + :param or_equal: If True, the age check will be older than or equal to. If False, the Age check will be older than. + :type or_equal: bool + :return: True, if the Sim is older than the specified Age or equal to the specified Age if `or_equal` is True. False, if not. + :rtype: bool + """ + age = age + sim_age = cls.get_age(sim_info) + if or_equal: + return sim_age >= age + return sim_age > age + + @classmethod + def is_baby_age(cls, age: Union[CommonAge, Age, int]) -> bool: + """is_baby_age(age) + + Determine if an Age is a Baby. + + :param age: The age to check. + :type age: Union[CommonAge, Age, int] + :return: True, if it is. False, if it is not. + :rtype: bool + """ + if age is None: + return False + if isinstance(age, CommonAge): + age = CommonAge.convert_to_vanilla(age) + return age == Age.BABY + + @classmethod + def is_infant_age(cls, age: Union[CommonAge, Age, int]) -> bool: + """is_infant_age(age) + + Determine if an Age is an Infant. + + :param age: The age to check. + :type age: Union[CommonAge, Age, int] + :return: True, if it is. False, if it is not. + :rtype: bool + """ + if age is None: + return False + if isinstance(age, CommonAge): + age = CommonAge.convert_to_vanilla(age) + return age == Age.INFANT + + @classmethod + def is_toddler_age(cls, age: Union[CommonAge, Age, int]) -> bool: + """is_toddler_age(age) + + Determine if an Age is a Toddler. + + :param age: The age to check. + :type age: Union[CommonAge, Age, int] + :return: True, if it is. False, if it is not. + :rtype: bool + """ + if age is None: + return False + if isinstance(age, CommonAge): + age = CommonAge.convert_to_vanilla(age) + return age == Age.TODDLER + + @classmethod + def is_child_age(cls, age: Union[CommonAge, Age, int]) -> bool: + """is_child_age(age) + + Determine if an Age is a Child. + + :param age: The age to check. + :type age: Union[CommonAge, Age, int] + :return: True, if it is. False, if it is not. + :rtype: bool + """ + if age is None: + return False + if isinstance(age, CommonAge): + age = CommonAge.convert_to_vanilla(age) + return age == Age.CHILD + + @classmethod + def is_teen_age(cls, age: Union[CommonAge, Age, int]) -> bool: + """is_teen_age(age) + + Determine if an Age is a Teen. + + :param age: The age to check. + :type age: Union[CommonAge, Age, int] + :return: True, if it is. False, if it is not. + :rtype: bool + """ + if age is None: + return False + if isinstance(age, CommonAge): + age = CommonAge.convert_to_vanilla(age) + return age == Age.TEEN + + @classmethod + def is_adult_age(cls, age: Union[CommonAge, Age, int]) -> bool: + """is_adult_age(age) + + Determine if an Age is a Young Adult or an Adult. + + :param age: The age to check. + :type age: Union[CommonAge, Age, int] + :return: True, if it is. False, if it is not. + :rtype: bool + """ + return cls.is_young_adult_age(age) or cls.is_mature_adult_age(age) + + @classmethod + def is_young_adult_age(cls, age: Union[CommonAge, Age, int]) -> bool: + """is_young_adult_age(age) + + Determine if an Age is a Young Adult. + + :param age: The age to check. + :type age: Union[CommonAge, Age, int] + :return: True, if it is. False, if it is not. + :rtype: bool + """ + if age is None: + return False + if isinstance(age, CommonAge): + age = CommonAge.convert_to_vanilla(age) + return age == Age.YOUNGADULT + + @classmethod + def is_mature_adult_age(cls, age: Union[CommonAge, Age, int]) -> bool: + """is_mature_adult_age(age) + + Determine if an Age is an Adult. + + :param age: The age to check. + :type age: Union[CommonAge, Age, int] + :return: True, if it is. False, if it is not. + :rtype: bool + """ + if age is None: + return False + if isinstance(age, CommonAge): + age = CommonAge.convert_to_vanilla(age) + return age == Age.ADULT + + @classmethod + def is_elder_age(cls, age: Union[CommonAge, Age, int]) -> bool: + """is_elder_age(age) + + Determine if an Age is an Elder. + + :param age: The age to check. + :type age: Union[CommonAge, Age, int] + :return: True, if it is. False, if it is not. + :rtype: bool + """ + if age is None: + return False + if isinstance(age, CommonAge): + age = CommonAge.convert_to_vanilla(age) + return age == Age.ELDER + + @classmethod + def is_baby_or_toddler_age(cls, age: Union[CommonAge, Age, int]) -> bool: + """is_baby_or_toddler_age(age) + + Determine if an age is Baby or Toddler. + + :param age: The age to check. + :type age: Union[CommonAge, Age, int] + :return: True, if it is. False, if it is not. + :rtype: bool + """ + return cls.is_baby_age(age) or cls.is_toddler_age(age) + + @classmethod + def is_baby_infant_or_toddler_age(cls, age: Union[CommonAge, Age, int]) -> bool: + """is_baby_infant_or_toddler_age(age) + + Determine if an age is Baby or Toddler. + + :param age: The age to check. + :type age: Union[CommonAge, Age, int] + :return: True, if it is. False, if it is not. + :rtype: bool + """ + return cls.is_baby_age(age) or cls.is_infant_age(age) or cls.is_toddler_age(age) + + @classmethod + def is_baby_toddler_or_child_age(cls, age: Union[CommonAge, Age, int]) -> bool: + """is_baby_toddler_or_child_age(age) + + Determine if an age is Baby, Toddler, or Child. + + :param age: The age to check. + :type age: Union[CommonAge, Age, int] + :return: True, if it is. False, if it is not. + :rtype: bool + """ + return cls.is_baby_age(age) or cls.is_toddler_age(age) or cls.is_child_age(age) + + @classmethod + def is_baby_infant_toddler_or_child_age(cls, age: Union[CommonAge, Age, int]) -> bool: + """is_baby_infant_toddler_or_child_age(age) + + Determine if an age is Baby, Infant, Toddler, or Child. + + :param age: The age to check. + :type age: Union[CommonAge, Age, int] + :return: True, if it is. False, if it is not. + :rtype: bool + """ + return cls.is_baby_age(age) or cls.is_infant_age(age) or cls.is_toddler_age(age) or cls.is_child_age(age) + + @classmethod + def is_toddler_or_child_age(cls, age: Union[CommonAge, Age, int]) -> bool: + """is_toddler_or_child_age(age) + + Determine if an age is Toddler or Child. + + :param age: The age to check. + :type age: Union[CommonAge, Age, int] + :return: True, if it is. False, if it is not. + :rtype: bool + """ + return cls.is_toddler_age(age) or cls.is_child_age(age) + + @classmethod + def is_child_or_teen_age(cls, age: Union[CommonAge, Age, int]) -> bool: + """is_child_or_teen_age(age) + + Determine if an age is Child or Teen. + + :param age: The age to check. + :type age: Union[CommonAge, Age, int] + :return: True, if it is. False, if it is not. + :rtype: bool + """ + return cls.is_child_age(age) or cls.is_teen_age(age) + + @classmethod + def is_teen_or_young_adult_age(cls, age: Union[CommonAge, Age, int]) -> bool: + """is_teen_or_young_adult_age(age) + + Determine if an age is Teen or Young Adult. + + :param age: The age to check. + :type age: Union[CommonAge, Age, int] + :return: True, if it is. False, if it is not. + :rtype: bool + """ + return cls.is_teen_age(age) or cls.is_young_adult_age(age) + + @classmethod + def is_teen_or_adult_age(cls, age: Union[CommonAge, Age, int]) -> bool: + """is_teen_or_adult_age(age) + + Determine if an age is Teen, Young Adult, or Adult. + + :param age: The age to check. + :type age: Union[CommonAge, Age, int] + :return: True, if it is. False, if it is not. + :rtype: bool + """ + return cls.is_teen_age(age) or cls.is_adult_age(age) + + @classmethod + def is_teen_adult_or_elder_age(cls, age: Union[CommonAge, Age, int]) -> bool: + """is_teen_adult_or_elder_age(age) + + Determine if an age is Teen, Young Adult, Adult, or Elder. + + :param age: The age to check. + :type age: Union[CommonAge, Age, int] + :return: True, if it is. False, if it is not. + :rtype: bool + """ + return cls.is_teen_age(age) or cls.is_adult_age(age) or cls.is_elder_age(age) + + @classmethod + def is_adult_or_elder_age(cls, age: Union[CommonAge, Age, int]) -> bool: + """is_adult_or_elder_age(age) + + Determine if an age is Young Adult, Adult, or Elder. + + :param age: The age to check. + :type age: Union[CommonAge, Age, int] + :return: True, if it is. False, if it is not. + :rtype: bool + """ + return cls.is_adult_age(age) or cls.is_elder_age(age) + + @classmethod + def is_mature_adult_or_elder_age(cls, age: Union[CommonAge, Age, int]) -> bool: + """is_mature_adult_or_elder_age(age) + + Determine if an age is Adult or Elder. + + :param age: The age to check. + :type age: Union[CommonAge, Age, int] + :return: True, if it is. False, if it is not. + :rtype: bool + """ + return cls.is_mature_adult_age(age) or cls.is_elder_age(age) + + @classmethod + def is_baby(cls, sim_info: SimInfo) -> bool: + """is_baby(sim_info) + + Determine if a Sim is a Baby. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is. False, if the Sim is not. + :rtype: bool + """ + return cls.is_baby_age(cls.get_age(sim_info)) + + @classmethod + def is_infant(cls, sim_info: SimInfo) -> bool: + """is_infant(sim_info) + + Determine if a Sim is an Infant. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is. False, if the Sim is not. + :rtype: bool + """ + return cls.is_infant_age(cls.get_age(sim_info)) + + @classmethod + def is_toddler(cls, sim_info: SimInfo) -> bool: + """is_toddler(sim_info) + + Determine if a Sim is a Toddler. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is. False, if the Sim is not. + :rtype: bool + """ + return cls.is_toddler_age(cls.get_age(sim_info)) + + @classmethod + def is_child(cls, sim_info: SimInfo) -> bool: + """is_child(sim_info) + + Determine if a Sim is a Child. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is. False, if the Sim is not. + :rtype: bool + """ + return cls.is_child_age(cls.get_age(sim_info)) + + @classmethod + def is_teen(cls, sim_info: SimInfo) -> bool: + """is_teen(sim_info) + + Determine if a Sim is a Teen. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is. False, if the Sim is not. + :rtype: bool + """ + return cls.is_teen_age(cls.get_age(sim_info)) + + @classmethod + def is_young_adult(cls, sim_info: SimInfo) -> bool: + """is_young_adult(sim_info) + + Determine if a Sim is a Young Adult. + + .. note:: This function does not determine whether they are an Adult or not. Use "is_adult" to check for both. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is. False, if the Sim is not. + :rtype: bool + """ + return cls.is_young_adult_age(cls.get_age(sim_info)) + + @classmethod + def is_mature_adult(cls, sim_info: SimInfo) -> bool: + """is_mature_adult(sim_info) + + Determine if a Sim is an Adult. + + .. note:: This function does not determine whether they are a Young Adult or not. Use 'is_adult' to check for both. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is. False, if the Sim is not. + :rtype: bool + """ + return cls.is_mature_adult_age(cls.get_age(sim_info)) + + @classmethod + def is_elder(cls, sim_info: SimInfo) -> bool: + """is_elder(sim_info) + + Determine if a Sim is an Elder. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is. False, if the Sim is not. + :rtype: bool + """ + return cls.is_elder_age(cls.get_age(sim_info)) + + @classmethod + def is_adult(cls, sim_info: SimInfo) -> bool: + """is_adult(sim_info) + + Determine if a Sim is either a Young Adult or an Adult. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is. False, if the Sim is not. + :rtype: bool + """ + return cls.is_adult_age(cls.get_age(sim_info)) + + @classmethod + def is_baby_or_toddler(cls, sim_info: SimInfo) -> bool: + """is_baby_or_toddler(sim_info) + + Determine if a Sim is a Baby or a Toddler. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is. False, if the Sim is not. + :rtype: bool + """ + return cls.is_baby_or_toddler_age(cls.get_age(sim_info)) + + @classmethod + def is_baby_infant_or_toddler(cls, sim_info: SimInfo) -> bool: + """is_baby_infant_or_toddler(sim_info) + + Determine if a Sim is a Baby, Infant, or a Toddler. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is. False, if the Sim is not. + :rtype: bool + """ + return cls.is_baby_infant_or_toddler_age(cls.get_age(sim_info)) + + @classmethod + def is_toddler_or_child(cls, sim_info: SimInfo) -> bool: + """is_toddler_or_child(sim_info) + + Determine if a Sim is a Toddler or a Child. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is. False, if the Sim is not. + :rtype: bool + """ + return cls.is_toddler_or_child_age(cls.get_age(sim_info)) + + @classmethod + def is_baby_toddler_or_child(cls, sim_info: SimInfo) -> bool: + """is_baby_toddler_or_child(sim_info) + + Determine if a Sim is a Baby, a Toddler, or a Child. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is. False, if the Sim is not. + :rtype: bool + """ + return cls.is_baby_toddler_or_child_age(cls.get_age(sim_info)) + + @classmethod + def is_baby_infant_toddler_or_child(cls, sim_info: SimInfo) -> bool: + """is_baby_infant_toddler_or_child(sim_info) + + Determine if a Sim is a Baby, Infant, a Toddler, or a Child. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is. False, if the Sim is not. + :rtype: bool + """ + return cls.is_baby_infant_toddler_or_child_age(cls.get_age(sim_info)) + + @classmethod + def is_child_or_teen(cls, sim_info: SimInfo) -> bool: + """is_child_or_teen(sim_info) + + Determine if a Sim is a Child or a Teen. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is. False, if the Sim is not. + :rtype: bool + """ + return cls.is_child_or_teen_age(cls.get_age(sim_info)) + + @classmethod + def is_teen_or_young_adult(cls, sim_info: SimInfo) -> bool: + """is_teen_or_young_adult(sim_info) + + Determine if a Sim is a Teen or a Young Adult. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is. False, if the Sim is not. + :rtype: bool + """ + return cls.is_teen_or_young_adult_age(cls.get_age(sim_info)) + + @classmethod + def is_teen_or_adult(cls, sim_info: SimInfo) -> bool: + """is_teen_or_adult(sim_info) + + Determine if a Sim is a Teen, a Young Adult, or an Adult. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is. False, if the Sim is not. + :rtype: bool + """ + return cls.is_teen_or_adult_age(cls.get_age(sim_info)) + + @classmethod + def is_teen_adult_or_elder(cls, sim_info: SimInfo) -> bool: + """is_teen_adult_or_elder(sim_info) + + Determine if a Sim is a Teen, a Young Adult, an Adult, or an Elder. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is. False, if the Sim is not. + :rtype: bool + """ + return cls.is_teen_adult_or_elder_age(cls.get_age(sim_info)) + + @classmethod + def is_adult_or_elder(cls, sim_info: SimInfo) -> bool: + """is_adult_or_elder(sim_info) + + Determine if a Sim is a Young Adult, an Adult, or an Elder. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is. False, if the Sim is not. + :rtype: bool + """ + return cls.is_adult_or_elder_age(cls.get_age(sim_info)) + + @classmethod + def is_mature_adult_or_elder(cls, sim_info: SimInfo) -> bool: + """is_mature_adult_or_elder(sim_info) + + Determine if a Sim is an Adult or an Elder. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is. False, if the Sim is not. + :rtype: bool + """ + return cls.is_mature_adult_or_elder_age(cls.get_age(sim_info)) + + # Obsolete Functionality + + @classmethod + def is_baby_child_or_toddler(cls, sim_info: SimInfo) -> bool: + """is_baby_child_or_toddler(sim_info) + + .. warning:: Obsolete: Don't use this function. Use the :func:'~is_baby_toddler_or_child' function instead. + + """ + return cls.is_baby_toddler_or_child(sim_info) + + @classmethod + def is_age_available_for_sim(cls, sim_info: SimInfo, age: CommonAge) -> bool: + """is_age_available_for_sim(sim_info, age) + + Determine if an Age is available for a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param age: The age to check. + :type age: CommonAge + :return: True, if the specified Age is available for the specified Sim. False, if not. + :rtype: bool + """ + if sim_info is None or age == CommonAge.INVALID: + return False + from sims.aging.aging_data import AgingData + aging_data: AgingData = sim_info.get_aging_data() + if aging_data is None: + return False + vanilla_age = CommonAge.convert_to_vanilla(age) + if vanilla_age is None: + return False + # noinspection PyBroadException + try: + # noinspection PyUnresolvedReferences + aging_data_ages = aging_data.ages + return vanilla_age in aging_data_ages + except: + return False + + @classmethod + def has_age(cls, sim_info: SimInfo, age: Union[CommonAge, Age, int], exact_age: bool = False) -> bool: + """has_age(sim_info, age, exact_age=False) + + Determine if a Sim has a matching Age. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param age: The age to check. + :type age: Union[CommonAge, Age, int] + :param exact_age: If True, the Sims exact age will be used. If False, the Sims approximate age will be used. In most cases, this should be False. Default is False. + :type exact_age: bool, optional + :return: True, if the age of the specified Sim matches the specified age. False, if not. + :rtype: bool + """ + current_age = cls.get_age(sim_info, exact_age=exact_age) + if current_age is None: + return False + return int(current_age) == int(age) + + @classmethod + def has_any_age(cls, sim_info: SimInfo, ages: Iterator[Union[CommonAge, Age, int]], exact_age: bool = False) -> bool: + """has_any_age(sim_info, ages, exact_age=False) + + Determine if a Sim has an Age matching any of the specified Ages. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param ages: The ages to check. + :type ages: Iterator[Union[CommonAge, Age, int]] + :param exact_age: If True, the Sims exact age will be used. If False, the Sims approximate age will be used. In most cases, this should be False. Default is False. + :type exact_age: bool, optional + :return: True, if the age of the specified Sim matches any of the specified ages. False, if not. + :rtype: bool + """ + current_age = cls.get_age(sim_info, exact_age=exact_age) + if current_age is None: + return False + for age in ages: + if int(current_age) == int(age): + return True + return False + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.set_age_progress_percentage', + 'Set the percentage of total days a Sim has been in their current age.', + command_arguments=( + CommonConsoleCommandArgument('progress_percentage', 'Decimal Percentage', 'The percentage of total days to set the Age Progress of the Sim. Values are 0.0 to 100.0'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance id or name of a Sim to change.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.setageprogresspercentage', + ) +) +def _common_set_age_progress_percentage(output: CommonConsoleCommandOutput, progress_percentage: float, sim_info: SimInfo = None): + if sim_info is None: + output('ERROR: No Sim was specified or the specified Sim was not found!') + return + output(f'Attempting to set the age progress of {sim_info} to {progress_percentage}%') + if CommonAgeUtils.set_percentage_total_days_sim_has_been_in_their_current_age(sim_info, progress_percentage): + output(f'SUCCESS: Successfully set the age progress of Sim {sim_info} to {progress_percentage}%') + else: + output(f'FAILED: Failed to set the age progress of Sim {sim_info} to {progress_percentage}%') + output(f'Done setting the age progress of Sim {sim_info} to {progress_percentage}%') + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.randomize_age_progress', + 'Randomize the progress made towards the next age of a Sim.', + command_arguments=( + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance id or name of a Sim to change.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.randomizeageprogress', + ) +) +def _common_randomize_age_progress(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): + if sim_info is None: + output('ERROR: No Sim was specified or the specified Sim was not found!') + return + progress = CommonAgeUtils.get_total_days_to_age_up(sim_info) * random.random() + percentage_progress = (progress / CommonAgeUtils.get_total_days_to_age_up(sim_info)) * 100 + output(f'Attempting to randomize the age progress of {sim_info} to {percentage_progress}%') + CommonAgeUtils.set_percentage_total_days_sim_has_been_in_their_current_age(sim_info, percentage_progress) + output(f'Done randomizing the age progress of Sim {sim_info} to {percentage_progress}%') + return True + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.set_age', + 'Set the age of a Sim.', + command_arguments=( + CommonConsoleCommandArgument('age', 'CommonAge', f'The age to set the Sim to. Valid Ages: {CommonAge.get_comma_separated_names_string()}'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance id or name of a Sim to change.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.setage', + ) +) +def _common_set_age(output: CommonConsoleCommandOutput, age: CommonAge, sim_info: SimInfo = None): + if age is None: + return + if sim_info is None: + output('ERROR: No Sim was specified or the specified Sim was not found!') + return + age_name = age.name + output(f'Setting the age of {sim_info} to {age_name}') + if CommonAgeUtils.set_age(sim_info, age): + output(f'SUCCESS: Successfully set the age of Sim {sim_info} to {age_name}') + else: + output(f'FAILED: Failed to set the age of Sim {sim_info} to {age_name}') + output(f'Done setting the age of Sim {sim_info} to {age_name}') + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.print_sim_age', + 'Print information about the Age of a Sim.', + command_arguments=( + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance id or name of a Sim to check.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.printsimage', + ) +) +def _common_print_sim_age(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): + if sim_info is None: + output('ERROR: No Sim was specified or the specified Sim was not found!') + return + output(f'Attempting to print Age Info for Sim {sim_info}.') + if hasattr(sim_info, '_base') and hasattr(sim_info._base, 'age'): + output(f'_base.age {sim_info._base.age}') + if hasattr(sim_info, 'age'): + # noinspection PyPropertyAccess + output(f'age {sim_info.age}') + if hasattr(sim_info, 'sim_info') and hasattr(sim_info.sim_info, '_base') and hasattr(sim_info.sim_info._base, 'age'): + output(f'sim_info._base.age {sim_info.sim_info._base.age}') + if hasattr(sim_info, 'sim_info') and hasattr(sim_info.sim_info, 'age'): + output(f'sim_info.age {sim_info.sim_info.age}') + get_age_result = CommonAgeUtils.get_age(sim_info) + output(f'Approximate Age: {get_age_result}') + get_age_exact_result = CommonAgeUtils.get_age(sim_info, exact_age=True) + output(f'Exact Age: {get_age_exact_result}') + total_days_has_been_in_current_age = CommonAgeUtils.get_total_days_sim_has_been_in_their_current_age(sim_info) + output(f'Age Progress: {total_days_has_been_in_current_age}') + percentage_total_days_sim_has_been_in_current_age = CommonAgeUtils.get_percentage_total_days_sim_has_been_in_their_current_age(sim_info) + output(f'Age Progress (In Days): {percentage_total_days_sim_has_been_in_current_age}') + total_days_until_sim_ages_up = CommonAgeUtils.get_total_days_until_sim_ages_up(sim_info) + output(f'Days Until Ready To Age: {total_days_until_sim_ages_up}') + total_days_to_age_up = CommonAgeUtils.get_total_days_to_age_up(sim_info) + output(f'Max Total Days To Age Up: {total_days_to_age_up}') + output(f'Done printing Age Info for Sim {sim_info}.') diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_buff_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_buff_utils.py new file mode 100644 index 0000000..1f210aa --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_buff_utils.py @@ -0,0 +1,592 @@ +""" +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 +""" +from typing import Union, List, Tuple, Iterator + +from buffs.buff import Buff +from distributor.shared_messages import IconInfoData +from objects.components.buff_component import BuffComponent +from protocolbuffers.Localization_pb2 import LocalizedString +from server_commands.argument_helpers import TunableInstanceParam +from sims.sim_info import SimInfo +from sims4.resources import Types +from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.enums.buffs_enum import CommonBuffId +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.enums.types.component_types import CommonComponentType +from sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + CommonConsoleCommandArgument +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.common_component_utils import CommonComponentUtils +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + + +class CommonBuffUtils(_HasS4CLClassLog): + """Utilities for manipulating Buffs on Sims. + + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 'common_buff_utils' + + @classmethod + def has_fertility_boosting_buff(cls, sim_info: SimInfo) -> CommonTestResult: + """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: The result of testing. True, if they have any fertility boosting buffs. False, if not. + :rtype: CommonTestResult + """ + 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 cls.has_any_buffs(sim_info, buff_ids) + + @classmethod + def has_morning_person_buff(cls, sim_info: SimInfo) -> CommonTestResult: + """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: The result of testing. True, if they have any morning person buffs. False, if not. + :rtype: CommonTestResult + """ + buff_ids = ( + CommonBuffId.TRAIT_MORNING_PERSON, + CommonBuffId.TRAIT_MORNING_PERSON_ACTIVE, + CommonBuffId.TRAIT_MORNING_PERSON_CHECK_ACTIVE + ) + return cls.has_any_buffs(sim_info, buff_ids) + + @classmethod + def has_night_owl_buff(cls, sim_info: SimInfo) -> CommonTestResult: + """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: The result of testing. True, if they have any night owl buffs. False, if not. + :rtype: CommonTestResult + """ + buff_ids = ( + CommonBuffId.TRAIT_NIGHT_OWL, + CommonBuffId.TRAIT_NIGHT_OWL_ACTIVE, + CommonBuffId.TRAIT_NIGHT_OWL_CHECK_ACTIVE + ) + return cls.has_any_buffs(sim_info, buff_ids) + + @classmethod + def has_buff(cls, sim_info: SimInfo, *buff: Union[int, CommonBuffId, Buff]) -> CommonTestResult: + """has_buff(sim_info, buff) + + Determine if the Sim has a Buff. + + :param sim_info: The Sim being checked. + :type sim_info: SimInfo + :param buff: The buff to check for. + :type buff: Union[int, CommonBuffId, Buff] + :return: The result of testing. True, if the Sim has the specified buff. False, if not. + :rtype: CommonTestResult + """ + return cls.has_any_buffs(sim_info, buff) + + @classmethod + def has_any_buffs(cls, sim_info: SimInfo, buffs: Iterator[Union[int, CommonBuffId, Buff]]) -> CommonTestResult: + """has_any_buffs(sim_info, buffs) + + Determine if the Sim has any of the specified buffs. + + :param sim_info: The Sim being checked. + :type sim_info: SimInfo + :param buffs: An iterator of buffs to check for. + :type buffs: Iterator[Union[int, CommonBuffId, Buff]] + :return: The result of testing. True, if the Sim has any of the specified buffs. False, if not. + :rtype: CommonTestResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + if not buffs: + return CommonTestResult(False, reason='No buffs were specified.') + if not CommonComponentUtils.has_component(sim_info, CommonComponentType.BUFF): + return CommonTestResult(False, reason=f'Target Sim {sim_info} did not have a Buff Component.') + from objects.components.buff_component import BuffComponent + buff_component: BuffComponent = CommonComponentUtils.get_component(sim_info, CommonComponentType.BUFF) + for buff in buffs: + _buff = cls.load_buff_by_id(buff) + cls.get_log().format_with_message('Got the buff', buff=_buff) + if _buff is None: + continue + if buff_component.has_buff(_buff): + return CommonTestResult(True, reason=f'{sim_info} has buff {_buff}.') + return CommonTestResult(False, reason=f'{sim_info} does not have any buff(s) {buffs}.') + + @classmethod + def has_all_buffs(cls, sim_info: SimInfo, buffs: Iterator[Union[int, CommonBuffId, Buff]]) -> CommonTestResult: + """has_all_buffs(sim_info, buffs) + + Determine if the Sim has all of the specified buffs. + + :param sim_info: The Sim being checked. + :type sim_info: SimInfo + :param buffs: An iterator of buffs to check for. + :type buffs: Iterator[Union[int, CommonBuffId, Buff]] + :return: The result of testing. True, if the Sim has all of the specified buffs. False, if not. + :rtype: CommonTestResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + if not buffs: + return CommonTestResult(False, reason='No buffs were specified.') + if not CommonComponentUtils.has_component(sim_info, CommonComponentType.BUFF): + return CommonTestResult(False, reason=f'Target Sim {sim_info} did not have a Buff Component.') + from objects.components.buff_component import BuffComponent + buff_component: BuffComponent = CommonComponentUtils.get_component(sim_info, CommonComponentType.BUFF, return_type=BuffComponent) + for buff in buffs: + _buff = cls.load_buff_by_id(buff) + cls.get_log().format_with_message('Got the buff', buff=_buff) + if _buff is None: + continue + if not buff_component.has_buff(_buff): + return CommonTestResult(False, reason=f'{sim_info} does not have buff {_buff}.') + return CommonTestResult(True, reason=f'{sim_info} has all buffs {buffs}.') + + @classmethod + def get_buffs(cls, 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: + raise AssertionError('Argument sim_info was None') + 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 + + @classmethod + def get_buff_ids(cls, sim_info: SimInfo) -> List[int]: + """get_buff_ids(sim_info) + + Retrieve decimal identifiers for all Buffs of a Sim. + + :param sim_info: The Sim to checked. + :type sim_info: SimInfo + :return: A collection of Buff identifiers on a Sim. + :rtype: List[int] + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + if not CommonComponentUtils.has_component(sim_info, CommonComponentType.BUFF): + return list() + buff_ids = list() + sim_buffs = cls.get_buffs(sim_info) + for buff in sim_buffs: + buff_id = cls.get_buff_id(buff) + if buff_id is None: + continue + buff_ids.append(buff_id) + return buff_ids + + @classmethod + def add_buff(cls, sim_info: SimInfo, *buff: Union[int, CommonBuffId], buff_reason: Union[int, str, LocalizedString, CommonStringId] = None) -> CommonExecutionResult: + """add_buff(sim_info, buff, buff_reason=None) + + Add a Buff to a Sim. + + :param sim_info: The Sim to add the buff to. + :type sim_info: SimInfo + :param buff: The buff being added. + :type buff: Union[int, CommonBuffId, Buff] + :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, CommonStringId], optional + :return: The result of adding the buffs. True, if the specified buff was successfully added. False, if not. + :rtype: CommonExecutionResult + """ + return cls.add_buffs(sim_info, buff, buff_reason=buff_reason) + + @classmethod + def add_buffs(cls, sim_info: SimInfo, buffs: Iterator[Union[int, CommonBuffId, Buff]], buff_reason: Union[int, str, LocalizedString, CommonStringId] = None) -> CommonExecutionResult: + """add_buffs(sim_info, buffs, buff_reason=None) + + Add Buffs to a Sim. + + :param sim_info: The Sim to add the specified buffs to. + :type sim_info: SimInfo + :param buffs: An iterator of identifiers of buffs being added. + :type buffs: Iterator[Union[int, CommonBuffId, Buff]] + :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, CommonStringId], optional + :return: The result of adding the buffs. True, if all of the specified buffs were successfully added. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + if not CommonComponentUtils.has_component(sim_info, CommonComponentType.BUFF): + cls.get_log().format_with_message('Failed to add Buff to Sim. They did not have a Buff component!', buffs=buffs, sim=sim_info, buff_reason=buff_reason) + return CommonExecutionResult(False, reason=f'Target Sim {sim_info} did not have a Buff Component.') + localized_buff_reason = None + if buff_reason is not None: + localized_buff_reason = CommonLocalizationUtils.create_localized_string(buff_reason) + has_any_loaded = False + success = True + failed_to_add_buffs = list() + for buff_id in buffs: + buff = cls.load_buff_by_id(buff_id) + if buff is None: + cls.get_log().format_with_message('No buff found using identifier.', buffs=buffs, sim=sim_info, buff_reason=buff_reason, buff_id=buff_id) + failed_to_add_buffs.append(buff_id) + continue + has_any_loaded = True + add_result = sim_info.add_buff_from_op(buff, buff_reason=localized_buff_reason) + if not add_result: + cls.get_log().format_with_message('Failed to add buff.', buff=buff, sim=sim_info, buff_reason=buff_reason, reason=add_result) + success = False + failed_to_add_buffs.append(buff) + else: + cls.get_log().format_with_message('Successfully added buff.', buff=buff, sim=sim_info, buff_reason=buff_reason) + cls.get_log().format_with_message('Finished adding buffs to Sim.', buffs=buffs, sim=sim_info, buff_reason=buff_reason, success=success, has_any_loaded=has_any_loaded, failed_to_add_buffs=failed_to_add_buffs) + if not success: + failed_to_add_buffs_str = ', '.join([cls.get_buff_name(buff) or str(buff) if isinstance(buff, Buff) else str(buff) for buff in failed_to_add_buffs]) + return CommonExecutionResult(False, reason=f'Failed to add buffs. {failed_to_add_buffs_str}') + if not has_any_loaded: + return CommonExecutionResult(True, reason='Finished "adding" buffs, but none of the specified buffs were loaded.') + return CommonExecutionResult.TRUE + + @classmethod + def remove_buff(cls, sim_info: SimInfo, *buff: Union[int, CommonBuffId, Buff]) -> CommonExecutionResult: + """remove_buff(sim_info, buff) + + Remove a Buff from a Sim. + + :param sim_info: The Sim to remove the buff from. + :type sim_info: SimInfo + :param buff: The buff being removed. + :type buff: Union[int, CommonBuffId, Buff] + :return: The result of removing the buff. True, if the buff was successfully removed. False, if not. + :rtype: CommonExecutionResult + """ + return cls.remove_buffs(sim_info, buff) + + @classmethod + def remove_buffs(cls, sim_info: SimInfo, buffs: Iterator[Union[int, CommonBuffId, Buff]]) -> CommonExecutionResult: + """remove_buffs(sim_info, buffs) + + Remove Buffs from a Sim. + + :param sim_info: The Sim to remove the specified buffs from. + :type sim_info: SimInfo + :param buffs: An iterator of identifiers of buffs being removed. + :type buffs: Iterator[Union[int, CommonBuffId, Buff]] + :return: The result of removing the buffs. True, if all of the specified buffs were successfully removed. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + if not CommonComponentUtils.has_component(sim_info, CommonComponentType.BUFF): + return CommonExecutionResult(False, reason=f'Target Sim {sim_info} did not have a Buff Component.') + has_any_loaded = False + success = True + failed_to_remove_buffs = list() + for buff_id in buffs: + buff = cls.load_buff_by_id(buff_id) + if buff is None: + failed_to_remove_buffs.append(buff_id) + continue + if not cls.has_buff(sim_info, buff_id): + continue + has_any_loaded = True + sim_info.remove_buff_by_type(buff) + if cls.has_buff(sim_info, buff): + failed_to_remove_buffs.append(buff) + success = False + + if not success: + failed_to_remove_buffs_str = ', '.join([cls.get_buff_name(buff) or str(buff) if isinstance(buff, Buff) else str(buff) for buff in failed_to_remove_buffs]) + return CommonExecutionResult(False, reason=f'Failed to remove buffs. {failed_to_remove_buffs_str}') + if not has_any_loaded: + return CommonExecutionResult(True, reason='Finished "removing" buffs, but none of the specified buffs were loaded.') + return CommonExecutionResult.TRUE + + @classmethod + def get_buff_id(cls, buff_identifier: Union[int, Buff]) -> Union[int, None]: + """get_buff_id(buff_identifier) + + Retrieve the GUID (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) + + @classmethod + def get_buff_name(cls, 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 + return str(buff) + + @classmethod + def get_buff_names(cls, 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 = cls.get_buff_name(buff) + if not name: + continue + except: + continue + names.append(name) + return tuple(names) + + @classmethod + def get_buff_component(cls, sim_info: SimInfo) -> Union[BuffComponent, None]: + """get_buff_component(sim_info) + + Retrieve the buff component of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The buff component of the Sim or None if not found. + :rtype: Union[BuffComponent, None] + """ + if not CommonComponentUtils.has_component(sim_info, CommonComponentType.BUFF): + return None + result: BuffComponent = CommonComponentUtils.get_component(sim_info, CommonComponentType.BUFF) + return result + + @classmethod + def is_buff_available(cls, buff: Union[int, CommonBuffId, Buff]) -> bool: + """is_buff_available(buff) + + Determine if a Buff is available for use. + + .. note:: If the Buff is part of a package that is not installed, it will be considered as not available. + + :param buff: The buff to check for. + :type buff: Union[int, CommonBuffId, Buff] + :return: True, if the Buff is available for use. False, if not. + :rtype: bool + """ + return cls.load_buff_by_id(buff) is not None + + @classmethod + def load_buff_by_id(cls, buff: Union[int, CommonBuffId, Buff]) -> Union[Buff, None]: + """load_buff_by_id(buff) + + Load an instance of a Buff by its identifier. + + :param buff: The identifier of a Buff. + :type buff: Union[int, CommonBuffId, Buff] + :return: An instance of a Buff matching the decimal identifier or None if not found. + :rtype: Union[Buff, None] + """ + if isinstance(buff, Buff): + return buff + # noinspection PyBroadException + try: + # noinspection PyCallingNonCallable + buff_instance = buff() + if isinstance(buff_instance, Buff): + # noinspection PyTypeChecker + return buff + except: + pass + # noinspection PyBroadException + try: + buff: int = int(buff) + except: + # noinspection PyTypeChecker + buff: Buff = buff + return buff + + from sims4.resources import Types + from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + return CommonResourceUtils.load_instance(Types.BUFF, buff) + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.add_buff', + 'Add a buff to a Sim.', + command_arguments=( + CommonConsoleCommandArgument('buff', 'Buff Id or Tuning Name', 'The decimal identifier or Tuning Name of the Buff to add.'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance id or name of a Sim to add the buff to.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.addbuff', + ) +) +def _common_add_buff(output: CommonConsoleCommandOutput, buff: TunableInstanceParam(Types.BUFF), sim_info: SimInfo = None, buff_reason: str = None): + if buff is None or isinstance(buff, str): + return + if sim_info is None: + return + output(f'Adding buff {buff} to Sim {sim_info}') + result = CommonBuffUtils.add_buff(sim_info, buff, buff_reason=buff_reason) + if result: + output(f'SUCCESS: Successfully added buff {buff} to Sim {sim_info}: {result.reason}') + else: + output(f'FAILED: Failed to add buff {buff} to Sim {sim_info}: {result.reason}') + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.remove_buff', + 'Remove a buff from a Sim.', + command_arguments=( + CommonConsoleCommandArgument('buff', 'Buff Id or Tuning Name', 'The decimal identifier or Tuning Name of the Buff to remove.'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance id or name of a Sim to remove the buff from.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.removebuff', + ) +) +def _common_remove_buff(output: CommonConsoleCommandOutput, buff: TunableInstanceParam(Types.BUFF), sim_info: SimInfo = None): + if buff is None: + return + if sim_info is None: + return + output(f'Removing buff {buff} from Sim {sim_info}') + result = CommonBuffUtils.remove_buff(sim_info, buff) + if result: + output(f'SUCCESS: Successfully removed buff {buff} from Sim {sim_info}: {result.reason}') + else: + output(f'FAILED: Failed to remove buff {buff} from Sim {sim_info}: {result.reason}') + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_testing.print_buffs', + 'Print a list of all buffs on a Sim.', + command_arguments=( + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance id or name of a Sim to check.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib_testing.printbuffs', + ) +) +def _common_print_buffs_on_sim(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): + if sim_info is None: + return + log = CommonBuffUtils.get_log() + try: + log.enable() + output(f'Attempting to print buffs on Sim {sim_info}') + buff_strings: List[str] = list() + for buff in CommonBuffUtils.get_buffs(sim_info): + buff_name = CommonBuffUtils.get_buff_name(buff) + buff_id = CommonBuffUtils.get_buff_id(buff) + buff_strings.append(f'{buff_name} ({buff_id})') + + buff_strings = sorted(buff_strings, key=lambda x: x) + sim_buffs = ', '.join(buff_strings) + text = '' + text += f'Buffs:\n{sim_buffs}\n\n' + sim_id = CommonSimUtils.get_sim_id(sim_info) + log.debug(f'{sim_info} Buffs ({sim_id})') + log.debug(text) + CommonBasicNotification( + CommonLocalizationUtils.create_localized_string(f'{sim_info} Buffs ({sim_id})'), + CommonLocalizationUtils.create_localized_string(text) + ).show( + icon=IconInfoData(obj_instance=CommonSimUtils.get_sim_instance(sim_info)) + ) + finally: + log.disable() + +# log = CommonLogRegistry().register_log(ModInfo.get_identity(), 'buff_not_properly_adding_log') +# +# @CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), BuffComponent, BuffComponent._can_add_buff_type.__name__) +# def _common_can_add_buff_type(original, self, buff_type): +# if not buff_type.can_add(self.owner): +# log.format_with_message(f'Cannot add buff {buff_type}. Can Add') +# return (False, None) +# mood = buff_type.mood_type +# if mood is not None and mood.excluding_traits is not None and self.owner.trait_tracker.has_any_trait(mood.excluding_traits): +# log.format_with_message(f'Cannot add buff {buff_type}. MOOD', mood=mood, mood_excluding_traits=mood.excluding_traits) +# return (False, None) +# if buff_type.exclusive_index is None: +# log.format_with_message(f'Can add buff {buff_type}. Exclusive Index') +# return (True, None) +# for conflicting_buff_type in self._active_buffs: +# if conflicting_buff_type is buff_type: +# pass +# elif conflicting_buff_type.exclusive_index == buff_type.exclusive_index: +# if buff_type.exclusive_weight < conflicting_buff_type.exclusive_weight: +# log.format_with_message(f'Cannot add buff {buff_type}. Conflicting buff.', buff_weight=buff_type.exclusive_weight, conflicting_buff_weight=conflicting_buff_type.exclusive_weight) +# return (False, None) +# log.format_with_message(f'Cannot add buff {buff_type}. Conflicting buff 23432.', conflicting_buff_type=conflicting_buff_type) +# return (True, conflicting_buff_type) +# log.format_with_message(f'Can add buff {buff_type}.') +# return (True, None) \ No newline at end of file diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_career_level_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_career_level_utils.py new file mode 100644 index 0000000..a01e955 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_career_level_utils.py @@ -0,0 +1,50 @@ +""" +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 +""" +from typing import Union + +from careers.career_tuning import CareerLevel + + +class CommonCareerLevelUtils: + """ Utilities for manipulating Career Levels. """ + + @staticmethod + def load_career_level_by_guid(career_level_identifier: Union[int, CareerLevel]) -> Union[CareerLevel, None]: + """load_career_level_by_guid(career_level_identifier) + + Load an instance of a CareerLevel by its identifier. + + :param career_level_identifier: The identifier of a CareerLevel. + :type career_level_identifier: Union[int, CareerLevel] + :return: An instance of a CareerLevel matching the decimal identifier or None if not found. + :rtype: Union[CareerLevel, None] + """ + if career_level_identifier is None: + return None + if isinstance(career_level_identifier, CareerLevel): + return career_level_identifier + # noinspection PyBroadException + try: + # noinspection PyCallingNonCallable + career_level_instance = career_level_identifier() + if isinstance(career_level_instance, CareerLevel): + # noinspection PyTypeChecker + return career_level_identifier + except: + pass + # noinspection PyBroadException + try: + career_level_identifier: int = int(career_level_identifier) + except: + # noinspection PyTypeChecker + career_level_identifier: CareerLevel = career_level_identifier + return career_level_identifier + + from sims4.resources import Types + from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + return CommonResourceUtils.load_instance(Types.CAREER_LEVEL, career_level_identifier) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_career_track_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_career_track_utils.py new file mode 100644 index 0000000..7fa7955 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_career_track_utils.py @@ -0,0 +1,199 @@ +""" +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 +""" +import random +from typing import Union, Iterator, Callable, Tuple, List + +from careers.career_tuning import TunableCareerTrack, CareerLevel + + +class CommonCareerTrackUtils: + """ Utilities for manipulating Career Tracks. """ + @classmethod + def get_branches(cls, career_track: TunableCareerTrack, include_sub_branches: bool=False) -> Tuple[TunableCareerTrack]: + """get_branches(career_track, include_sub_branches=True) + + Retrieve a collection of all Career Tracks that branch off of a Career Track and if specified, the branches those branches branch off to. + + :param career_track: A Career Track. + :type career_track: TunableCareerTrack + :param include_sub_branches: If True, all branches will be checked for their own branches and those branches will be included recursively. If False, only the top level branches will be included. Default is False. + :type include_sub_branches: bool, optional + :return: A collection of all Career Tracks that branch off from the specified Career Track. + :rtype: Tuple[TunableCareerTrack] + """ + if career_track is None: + return tuple() + if include_sub_branches: + # noinspection PyUnresolvedReferences + if hasattr(career_track, 'branches') and career_track.branches is not None: + career_track_branches: List[TunableCareerTrack] = list(career_track.branches) + for sub_career_track in career_track_branches: + sub_branches = cls.get_branches(sub_career_track, include_sub_branches=include_sub_branches) + if not sub_branches: + continue + career_track_branches.extend(sub_branches) + return tuple(career_track_branches) + else: + # noinspection PyUnresolvedReferences + if hasattr(career_track, 'branches') and career_track.branches is not None: + return tuple(career_track.branches) + return tuple() + + @classmethod + def get_career_levels(cls, career_track: TunableCareerTrack, include_branches: bool=False) -> Tuple[CareerLevel]: + """get_career_levels(career_track, include_branches=False) + + Retrieve a collection of all career levels under a Career Track. + + :param career_track: A Career Track. + :type career_track: TunableCareerTrack + :param include_branches: If True, all career levels from Career Track branches will be included in the result. If False, only the career levels available for the specified Career Track will be included in the result. Default is False. + :rtype: include_branches: bool, optional + :return: A collection of all Career Levels under the Career Track. + :rtype: Tuple[CareerLevel] + """ + if career_track is None: + return tuple() + if include_branches: + # noinspection PyUnresolvedReferences + if hasattr(career_track, 'career_levels') and career_track.career_levels is not None: + career_levels: List[CareerLevel] = list(career_track.career_levels) + branches = cls.get_branches(career_track) + for branch_career_track in branches: + sub_career_levels = cls.get_career_levels(branch_career_track, include_branches=include_branches) + if not sub_career_levels: + continue + career_levels.extend(sub_career_levels) + return tuple(career_levels) + else: + # noinspection PyUnresolvedReferences + if hasattr(career_track, 'career_levels') and career_track.career_levels is not None: + return tuple(career_track.career_levels) + return tuple() + + @classmethod + def get_career_level_by_index(cls, career_track: TunableCareerTrack, index: int) -> Union[CareerLevel, None]: + """get_career_level_by_index(career_track, index) + + Retrieve a Career Level within a Career Track by its index. + + :param career_track: A Career Track. + :type career_track: TunableCareerTrack + :param index: The index of the career level to retrieve. (Career Levels start at 1 instead of zero!) + :type index: int + :return: The career level found at the specified index or None if not found. + :rtype: Union[CareerLevel, None] + """ + career_levels = cls.get_career_levels(career_track) + if index > len(career_levels): + return None + return career_levels[index] + + @classmethod + def get_career_track_guid(cls, career_track: TunableCareerTrack) -> Union[int, None]: + """get_career_track_guid(career_track) + + Retrieve the Guid64 identifier of a career_track. + + :param career_track: An instance of a Career Track. + :type career_track: TunableCareerTrack + :return: The Guid64 identifier of the specified Career Track. + :rtype: Union[int, None] + """ + if career_track is None: + return None + return getattr(career_track, 'guid64', None) + + @staticmethod + def load_career_track_by_guid(career_track_identifier: Union[int, TunableCareerTrack]) -> Union[TunableCareerTrack, None]: + """load_career_track_by_guid(career_track_identifier) + + Load an instance of a CareerTrack by its identifier. + + :param career_track_identifier: The identifier of a CareerTrack. + :type career_track_identifier: Union[int, TunableCareerTrack] + :return: An instance of a Career Track matching the decimal identifier or None if not found. + :rtype: Union[TunableCareerTrack, None] + """ + if career_track_identifier is None: + return None + if isinstance(career_track_identifier, TunableCareerTrack): + return career_track_identifier + # noinspection PyBroadException + try: + # noinspection PyCallingNonCallable + career_track_instance = career_track_identifier() + if isinstance(career_track_instance, TunableCareerTrack): + # noinspection PyTypeChecker + return career_track_identifier + except: + pass + # noinspection PyBroadException + try: + career_track_identifier: int = int(career_track_identifier) + except: + # noinspection PyTypeChecker + career_track_identifier: TunableCareerTrack = career_track_identifier + return career_track_identifier + + from sims4.resources import Types + from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + return CommonResourceUtils.load_instance(Types.CAREER_TRACK, career_track_identifier) + + @staticmethod + def get_all_career_tracks_generator(include_career_track_callback: Callable[[TunableCareerTrack], bool]=None) -> Iterator[TunableCareerTrack]: + """get_all_career_tracks_generator(include_career_callback=None) + + Retrieve all Career Tracks. + + :param include_career_track_callback: If the result of this callback is True, the Career will be included in the results. If set to None, All Careers will be included. Default is None. + :type include_career_track_callback: Callable[[TunableCareerTrack], bool], optional + :return: An iterator of Careers matching `include_career_track_callback` + :rtype: Iterator[TunableCareerTrack] + """ + from sims4.resources import Types + from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + for (_, career_track) in CommonResourceUtils.load_all_instances(Types.CAREER_TRACK): + if include_career_track_callback is not None and not include_career_track_callback(career_track): + continue + yield career_track + + @classmethod + def determine_entry_level_into_career_track_by_user_level(cls, career_track: TunableCareerTrack, desired_user_level: int) -> Tuple[Union[int, None], Union[int, None], Union[TunableCareerTrack, None]]: + """determine_entry_level_into_career_track_by_user_level(career_track, desired_user_level) + + Pick a Career Track level and Career Track from a user level. + + :param career_track: The Career Track to locate a Career Level in. + :type career_track: TunableCareerTrack + :param desired_user_level: The desired user level within the Career Track. + :type desired_user_level: int + :return: The index of the Career Level for the Career Track (or branch Career Track) used, the level of the user in that Career Track, and the Career Track itself. + :rtype: Tuple[int, int, TunableCareerTrack] + """ + if career_track is None: + return None, None, None + track = career_track + track_start_level = 1 + + while True: + track_length = len(cls.get_career_levels(track)) + level = desired_user_level - track_start_level + if level < track_length: + user_level = track_start_level + level + return level, user_level, track + + branches = cls.get_branches(track) + if not branches: + # The exit path. When we run out of branches to check we'll just return the last info found. + level = track_length - 1 + user_level = track_start_level + level + return level, user_level, track + + track_start_level += track_length + track = random.choice(branches) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_career_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_career_utils.py new file mode 100644 index 0000000..295b457 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_career_utils.py @@ -0,0 +1,252 @@ +""" +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 +""" +from typing import Union, Iterator, Callable, Tuple, List + +from careers.career_location import CareerLocation +from careers.career_tuning import Career, TunableCareerTrack, CareerLevel +from sims4.tuning.instance_manager import InstanceManager + + +class CommonCareerUtils: + """ Utilities for manipulating Careers. """ + @classmethod + def get_career_levels(cls, career: Career, include_branches: bool = False) -> Tuple[CareerLevel]: + """get_career_levels(career, include_branches=False) + + Retrieve Career Levels available for a Career. + + :param career: A career. + :type career: Career + :param include_branches: If True, all career levels from Career Tracks the starting track branches into will be included in the result. If False, only the career levels available for the starting Track will be included in the result. Default is False. + :rtype: include_branches: bool, optional + :return: A collection of Career Levels available for the specified Career. + :rtype: Tuple[CareerLevel] + """ + if career is None: + return tuple() + + from sims4communitylib.utils.sims.common_career_track_utils import CommonCareerTrackUtils + return CommonCareerTrackUtils.get_career_levels(career.start_track, include_branches=include_branches) + + @classmethod + def get_starting_career_track(cls, career: Career) -> Union[TunableCareerTrack, None]: + """get_starting_career_track(career) + + Retrieve the starting Career Track of a Career. + + :param career: A career. + :type career: Career + :return: The starting Career Track of the Career or None if not found. + :rtype: Union[TunableCareerTrack, None] + """ + if career is None: + return None + return career.start_track + + @classmethod + def get_all_career_tracks(cls, career: Career) -> Tuple[TunableCareerTrack]: + """get_all_career_tracks(career) + + Retrieve all Career Tracks available for a Career, including all branching Career Tracks. + + :param career: A career. + :type career: Career + :return: A collection of Career Levels available for the specified Career. + :rtype: Tuple[CareerLevel] + """ + if career is None: + return tuple() + + career_tracks: List[TunableCareerTrack] = list() + career_tracks.append(career.start_track) + from sims4communitylib.utils.sims.common_career_track_utils import CommonCareerTrackUtils + branch_career_tracks = CommonCareerTrackUtils.get_branches(career.start_track, include_sub_branches=True) + if branch_career_tracks: + career_tracks.extend(branch_career_tracks) + return tuple(career_tracks) + + @classmethod + def get_career_id(cls, career: Career) -> int: + """get_career_id(career) + + Retrieve the instance identifier of a Career. + + :param career: An instance of a Career. + :type career: Career + :return: The instance identifier of the specified Career or -1 if a problem occurs. + :rtype: int + """ + if career is None: + return -1 + if not hasattr(career, 'id') or not isinstance(career, Career): + return -1 + return career.id or getattr(career, 'id', -1) + + @classmethod + def get_career_guid(cls, career: Career) -> Union[int, None]: + """get_career_guid(career) + + Retrieve the Guid64 identifier of a career. + + :param career: An instance of a Career. + :type career: Career + :return: The Guid64 identifier of the specified Career. + :rtype: Union[int, None] + """ + if career is None: + return None + return getattr(career, 'guid64', None) + + @classmethod + def get_career_location(cls, career: Career) -> Union[CareerLocation, None]: + """get_career_location(career) + + Retrieve the workplace location of a career. + + :param career: An instance of a Career. + :type career: Career + :return: The location the Career is set to occur at. + :rtype: Union[CareerLocation, None] + """ + if career is None: + return None + return career.get_career_location() + + @classmethod + def get_career_location_zone_id(cls, career: Career) -> int: + """get_career_location_zone_id(career) + + Retrieve the zone id of a Career where it is set to occur at. + + :param career: An instance of a Career. + :type career: Career + :return: The instance identifier of the zone the career is set to occur at. + :rtype: int + """ + if career is None: + return 0 + career_location = cls.get_career_location(career) + if career_location is None: + return 0 + return career_location.get_zone_id() + + @staticmethod + def load_career_by_guid(career: Union[int, Career]) -> Union[Career, None]: + """load_career_by_guid(career) + + Load an instance of a Career by its identifier. + + :param career: The identifier of a Career. + :type career: Union[int, Career] + :return: An instance of a Career matching the decimal identifier or None if not found. + :rtype: Union[Career, None] + """ + if career is None: + return None + if isinstance(career, Career): + return career + # noinspection PyBroadException + try: + # noinspection PyCallingNonCallable + career_instance = career() + if isinstance(career_instance, Career): + # noinspection PyTypeChecker + return career + except: + pass + # noinspection PyBroadException + try: + career: int = int(career) + except: + # noinspection PyTypeChecker + career: Career = career + return career + + from sims4.resources import Types + from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + return CommonResourceUtils.load_instance(Types.CAREER, career) + + @staticmethod + def get_all_careers_generator(include_career_callback: Callable[[Career], bool] = None) -> Iterator[Career]: + """get_all_careers_generator(include_career_callback=None) + + Retrieve all Careers. + + :param include_career_callback: If the result of this callback is True, the Career will be included in the results. If set to None, All Careers will be included. Default is None. + :type include_career_callback: Callable[[Career], bool], optional + :return: An iterator of Careers matching `include_career_callback` + :rtype: Iterator[Career] + """ + from sims4.resources import Types + from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + for (_, career) in CommonResourceUtils.load_all_instances(Types.CAREER): + if include_career_callback is not None and not include_career_callback(career): + continue + yield career + + @staticmethod + def determine_entry_level_into_career_from_user_level(career: Career, desired_user_level: int) -> Tuple[Union[int, None], Union[int, None], Union[TunableCareerTrack, None]]: + """get_career_entry_level_from_user_level(career, desired_user_level) + + Pick a career level and career track from a user level. + + :param career: The career to retrieve a career track from. + :type career: Career + :param desired_user_level: The user level desired to be given to a Sim. + :type desired_user_level: int + :return: The career level for the career track (or branch career track) used, the level of the user in that career track, and the career track itself. + :rtype: Tuple[int, int, TunableCareerTrack] + """ + if career is None: + return None, None, None + track = CommonCareerUtils.get_starting_career_track(career) + from sims4communitylib.utils.sims.common_career_track_utils import CommonCareerTrackUtils + return CommonCareerTrackUtils.determine_entry_level_into_career_track_by_user_level(track, desired_user_level) + + @staticmethod + def get_work_performance(career: Career) -> float: + """get_work_performance(career) + + Add an amount to the work performance of a career. + + :param career: The career to modify. + :type career: Career + :return: The amount of work performance acquired in the specified Career. + :rtype: float + """ + if career is None: + return 0.0 + return career.work_performance + + @staticmethod + def modify_work_performance(career: Career, amount: int): + """modify_work_performance(career, amount) + + Modify the work performance acquired in a Career. + + :param career: The career to modify. + :type career: Career + :param amount: The amount of work performance to apply to the Career. + :type amount: int + """ + if career is None: + return + career.add_work_performance(amount) + + @staticmethod + def get_instance_manager() -> InstanceManager: + """get_instance_manager() + + Retrieve the instance manager for careers. + + :return: The instance manager for careers. + :rtype: InteractionInstanceManager + """ + from sims4.resources import Types + from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + return CommonResourceUtils.get_instance_manager(Types.CAREER) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_gender_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_gender_utils.py new file mode 100644 index 0000000..dd68c73 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_gender_utils.py @@ -0,0 +1,240 @@ +""" +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 +""" +from typing import Union + +from sims.sim_info import SimInfo +from sims.sim_info_types import Gender +from sims4communitylib.enums.common_gender import CommonGender +from sims4communitylib.enums.traits_enum import CommonTraitId +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + CommonConsoleCommandArgument +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils +from sims4communitylib.utils.sims.common_sim_voice_utils import CommonSimVoiceUtils +from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils + + +class CommonGenderUtils: + """Utilities for manipulating Genders of Sims. + + """ + @staticmethod + def get_gender(sim_info: SimInfo) -> Union[Gender, None]: + """get_gender(sim_info) + + Retrieve the Gender of a Sim. + + :param sim_info: The Sim to retrieve the gender of. + :type sim_info: SimInfo + :return: The Gender of the Sim or None if a problem occurs. + :rtype: Union[Gender, None] + """ + if sim_info is None: + return None + if hasattr(sim_info, 'gender'): + # noinspection PyPropertyAccess + return sim_info.gender + if hasattr(sim_info, 'sim_info') and hasattr(sim_info.sim_info, 'gender'): + return sim_info.sim_info.gender + return None + + @staticmethod + def set_gender(sim_info: SimInfo, gender: Union[Gender, CommonGender, int]) -> bool: + """set_gender(sim_info, gender) + + Set the Gender of a Sim. + + :param sim_info: The Sim to set the Gender of. + :type sim_info: SimInfo + :param gender: The Gender to set the Sim to. + :type gender: Union[Gender, CommonGender, int] + :return: True, if the Gender of the Sim was set successfully. False, if not. + :rtype: bool + """ + gender = CommonGender.convert_to_vanilla(gender) + if gender is None: + return False + sim_info.gender = gender + if gender == Gender.MALE: + new_trait_id = CommonTraitId.GENDER_MALE + CommonTraitUtils.remove_trait(sim_info, CommonTraitId.GENDER_FEMALE) + else: + new_trait_id = CommonTraitId.GENDER_FEMALE + CommonTraitUtils.remove_trait(sim_info, CommonTraitId.GENDER_MALE) + CommonTraitUtils.add_trait(sim_info, new_trait_id) + from sims4communitylib.events.sim.common_sim_event_dispatcher import CommonSimEventDispatcherService + CommonSimEventDispatcherService()._on_sim_change_gender(sim_info) + return True + + @staticmethod + def swap_gender(sim_info: SimInfo, update_gender_options: bool=True, update_voice: bool=True, update_outfits: bool=True) -> bool: + """swap_gender(sim_info, update_gender_options=True, update_voice=True, update_outfits=True) + + Swap the Gender of a Sim to it's opposite. i.e. Change a Sim from Male to Female or from Female to Male. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param update_gender_options: If True, gender option traits such as Toilet Usage, Clothing Preference, Pregnancy, and Body Frame will be updated to reflect the vanilla settings for each gender\ + For example, if a Human Sim is swapping from Female to Male, their gender options will be updated to Toilet Standing, Cannot Be Impregnated, Can Impregnate, Mens Wear clothing preference, and Masculine Frame.\ + If False, gender option traits will not be updated.\ + Default is True. + :type update_gender_options: bool, optional + :param update_voice: If True, the voice of the Sim will be updated to a default voice for the gender being swapped to. If False, the voice of the Sim will remain unchanged. Default is True. + :type update_voice: bool, optional + :param update_outfits: If True, the outfits of the Sim will be regenerated to match the gender options of the Sim. If False, the outfits of the Sim will not be regenerated. Default is True. + :param update_outfits: bool, optional + :return: True, if the Gender of the Sim was swapped successfully. False, if not. + :rtype: bool + """ + from sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils + result = False + frame = CommonSimGenderOptionUtils.has_masculine_frame(sim_info).result + prefers_menswear = CommonSimGenderOptionUtils.prefers_menswear(sim_info).result + can_impregnate = CommonSimGenderOptionUtils.can_impregnate(sim_info).result + can_be_impregnated = CommonSimGenderOptionUtils.can_be_impregnated(sim_info).result + can_reproduce = CommonSimGenderOptionUtils.can_reproduce(sim_info).result + voice_pitch = CommonSimVoiceUtils.get_voice_pitch(sim_info) + voice_actor = CommonSimVoiceUtils.get_voice_actor(sim_info) + uses_toilet_standing = CommonSimGenderOptionUtils.uses_toilet_standing(sim_info).result + has_breasts = CommonSimGenderOptionUtils.has_breasts(sim_info).result + saved_outfits = sim_info.save_outfits() + current_outfit = CommonOutfitUtils.get_current_outfit(sim_info) + if CommonGenderUtils.is_male(sim_info): + result = CommonGenderUtils.set_gender(sim_info, CommonGender.FEMALE) + if update_voice: + CommonSimVoiceUtils.set_to_default_female_voice(sim_info) + if update_gender_options: + CommonSimGenderOptionUtils.update_gender_options_to_vanilla_female(sim_info) + if update_outfits: + CommonOutfitUtils.regenerate_all_outfits(sim_info) + elif CommonGenderUtils.is_female(sim_info): + result = CommonGenderUtils.set_gender(sim_info, CommonGender.MALE) + if update_voice: + CommonSimVoiceUtils.set_to_default_male_voice(sim_info) + if update_gender_options: + CommonSimGenderOptionUtils.update_gender_options_to_vanilla_male(sim_info) + if update_outfits: + CommonOutfitUtils.regenerate_all_outfits(sim_info) + + if not update_voice: + CommonSimVoiceUtils.set_voice_pitch(sim_info, voice_pitch) + CommonSimVoiceUtils.set_voice_actor(sim_info, voice_actor) + + if not update_gender_options: + CommonSimGenderOptionUtils.update_body_frame(sim_info, frame) + CommonSimGenderOptionUtils.update_clothing_preference(sim_info, prefers_menswear) + CommonSimGenderOptionUtils.update_can_impregnate(sim_info, can_impregnate) + CommonSimGenderOptionUtils.update_can_be_impregnated(sim_info, can_be_impregnated) + CommonSimGenderOptionUtils.update_can_reproduce(sim_info, can_reproduce) + CommonSimGenderOptionUtils.update_toilet_usage(sim_info, uses_toilet_standing) + CommonSimGenderOptionUtils.update_has_breasts(sim_info, has_breasts) + + if not update_outfits: + sim_info.load_outfits(saved_outfits) + CommonOutfitUtils.resend_outfits(sim_info) + CommonOutfitUtils.set_current_outfit(sim_info, current_outfit) + return result + + @staticmethod + def are_same_gender(sim_info: SimInfo, other_sim_info: SimInfo) -> bool: + """are_same_gender(sim_info, other_sim_info) + + Determine if two Sims are the same Gender. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :param other_sim_info: The Sim to compare to. + :type other_sim_info: SimInfo + :return: True, if both Sims are the same Gender. False, if not. + :rtype: bool + """ + gender_a = CommonGenderUtils.get_gender(sim_info) + if gender_a is None: + return False + gender_b = CommonGenderUtils.get_gender(other_sim_info) + if gender_b is None: + return False + return int(gender_a) == int(gender_b) + + @staticmethod + def is_female_gender(gender: Union[Gender, CommonGender, int]) -> bool: + """is_female_gender(gender) + + Determine if a Gender is Female. + + :param gender: The gender to check. + :type gender: Union[Gender, CommonGender, int] + :return: True, if the gender is female. False, if the gender is not female. + :rtype: bool + """ + if gender is None: + return False + return int(gender) == int(Gender.FEMALE) + + @staticmethod + def is_male_gender(gender: Union[Gender, CommonGender, int]) -> bool: + """is_male_gender(gender) + + Determine if a Gender is Male. + + :param gender: The gender to check. + :type gender: Union[Gender, CommonGender, int] + :return: True, if the gender is male. False, if the gender is not male. + :rtype: bool + """ + if gender is None: + return False + return int(gender) == int(Gender.MALE) + + @staticmethod + def is_female(sim_info: SimInfo) -> bool: + """is_female(sim_info) + + Determine if a Sim is Female. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is female. False, if the Sim is not female. + :rtype: bool + """ + return CommonGenderUtils.is_female_gender(CommonGenderUtils.get_gender(sim_info)) + + @staticmethod + def is_male(sim_info: SimInfo) -> bool: + """is_male(sim_info) + + Determine if a Sim is Male. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is male. False, if the Sim is not male. + :rtype: bool + """ + return CommonGenderUtils.is_male_gender(CommonGenderUtils.get_gender(sim_info)) + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.swap_gender', + 'Swap the gender of a Sim.', + command_arguments=( + CommonConsoleCommandArgument('update_gender_options', 'True or False', 'If True, gender options will be updated to vanilla gender options for the gender they are swapping to.', is_optional=True, default_value='True'), + CommonConsoleCommandArgument('update_voice', 'True or False', 'If True, voice of the Sim will be updated to a default voice for the gender they are swapping to.', is_optional=True, default_value='True'), + CommonConsoleCommandArgument('update_outfits', 'True or False', 'If True, outfits of the Sim will be regenerated to reflect the gender they are swapping to.', is_optional=True, default_value='True'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or decimal identifier of the Sim to use.', is_optional=True, default_value='Active Sim'), + ) +) +def _common_swap_gender(output: CommonConsoleCommandOutput, sim_info: SimInfo = None, update_gender_options: bool = True, update_voice: bool = True, update_outfits: bool = True) -> bool: + output(f'Swapping the gender of Sim {sim_info}.') + result = CommonGenderUtils.swap_gender(sim_info, update_gender_options=update_gender_options, update_voice=update_voice, update_outfits=update_outfits) + if result: + output('Success!') + else: + output('Failed!') + return True diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_household_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_household_utils.py new file mode 100644 index 0000000..2a93ba8 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_household_utils.py @@ -0,0 +1,747 @@ +""" +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 +""" +from typing import Union, Iterator + +import services +from sims.household import Household +from sims.sim_info import SimInfo +from sims.sim_spawner import SimSpawner +from sims4communitylib.logging.has_class_log import HasClassLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + CommonConsoleCommandArgument +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from world.lot import Lot +from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils +from sims4communitylib.utils.sims.common_sim_state_utils import CommonSimStateUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + + +class CommonHouseholdUtils(HasClassLog): + """Utilities for manipulating households. + + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + return ModInfo.get_identity() + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 'common_household_utils' + + @classmethod + def get_active_household(cls) -> Union[Household, None]: + """get_active_household() + + Retrieve the Household of the Active Sim. + + :return: The Household of the Active Sim or None if no household is found. + :rtype: Union[Household, None] + """ + return services.active_household() + + @classmethod + def get_active_household_id(cls) -> int: + """get_active_household_id() + + Retrieve an identifier for the Household of the Active Sim. + + :return: The identifier of the Household of the Active Sim. + :rtype: int + """ + return cls.get_id(cls.get_active_household()) + + @classmethod + def get_household_zone_id(cls, sim_info: SimInfo) -> int: + """get_household_zone_id(sim_info) + + Retrieve an zone identifier for the home Lot of the specified Sim. + + :param sim_info: The Sim to retrieve the household Lot id of. + :type sim_info: SimInfo + :return: The zone identifier of the Household the Sim belongs to. + :rtype: int + """ + household = cls.get_household(sim_info) + return cls.get_household_home_zone_id(household) + + @classmethod + def get_household_lot_id(cls, sim_info: SimInfo) -> int: + """get_household_lot_id(sim_info) + + Retrieve an identifier for the home Lot of a Sim. + + :param sim_info: The Sim to retrieve the household Lot id of. + :type sim_info: SimInfo + :return: The identifier of the Household Lot for the Sim. + :rtype: int + """ + household = cls.get_household(sim_info) + return cls.get_household_home_lot_id(household) + + @classmethod + def get_household_home_zone_id(cls, household: Household) -> int: + """get_household_home_zone_id(household) + + Retrieve the home zone identifier for a Household. + + :param household: An instance of a Household. + :type household: Household + :return: The home zone identifier of the specified Household or -1 if a problem occurs. + :rtype: int + """ + if household is None: + return -1 + # noinspection PyTypeChecker + return household.home_zone_id + + @classmethod + def get_household_home_lot_id(cls, household: Household) -> int: + """get_household_home_lot_id(household) + + Retrieve the decimal identifier of the home Lot for a Household. + + :param household: An instance of a Household. + :type household: Household + :return: The home zone identifier of the specified Household or -1 if a problem occurs. + :rtype: int + """ + from sims4communitylib.utils.location.common_location_utils import CommonLocationUtils + if household is None: + return -1 + home_zone_id = cls.get_household_home_zone_id(household) + if home_zone_id == -1: + return -1 + home_zone = CommonLocationUtils.get_zone(home_zone_id, allow_unloaded_zones=True) + if home_zone is None or not home_zone.is_instantiated: + return home_zone_id or -1 + lot = CommonLocationUtils.get_zone_lot(home_zone) + if lot is None: + return home_zone_id or -1 + return CommonLocationUtils.get_lot_id(lot) + + @classmethod + def get_sim_info_of_all_sims_in_active_household_generator(cls) -> Iterator[SimInfo]: + """get_sim_info_of_all_sims_in_active_household_generator() + + Retrieve a collection of Sims that are a part of the active household. + + :return: An iterator of Sims in the active household. + :rtype: Iterator[SimInfo] + """ + household = cls.get_active_household() + for sim_info in cls.get_sim_info_of_all_sims_in_household_generator(household): + yield sim_info + + @classmethod + def get_sim_info_of_all_sims_in_household_generator(cls, household: Household) -> Iterator[SimInfo]: + """get_sim_info_of_all_sims_in_household_generator(household) + + Retrieve a collection of Sims that are a part of the active household. + + :param household: The Household to retrieve Sims from. + :type household: Household + :return: An iterator of Sims in the specified Household. + :rtype: Iterator[SimInfo] + """ + if household is None: + return tuple() + for sim_info in list(household.sim_info_gen()): + if sim_info is None: + continue + yield sim_info + + @classmethod + def get_number_of_sims_in_household(cls, household: Household) -> int: + """get_number_of_sims_in_household(household) + + Determine the number of Sims in the specified Household. + + :param household: An instance of a Household. + :type household: Household + :return: The number of Sims in the specified Household. + :rtype: int + """ + if household is None: + return 0 + return len(tuple(cls.get_sim_info_of_all_sims_in_household_generator(household))) + + @classmethod + def get_number_of_sims_in_household_of_sim(cls, sim_info: SimInfo) -> int: + """get_number_of_sims_in_household_of_sim(sim_info) + + Determine the number of Sims in the household of the specified Sim. + + :param sim_info: An instance of a Sim. + :type: sim_info: SimInfo + :return: The number of Sims in the household of the specified Sim. + :rtype: int + """ + return cls.get_number_of_sims_in_household(cls.get_household(sim_info)) + + @classmethod + def is_part_of_active_household(cls, sim_info: SimInfo) -> bool: + """is_part_of_active_household(sim_info) + + Determine if a Sim is part of the active household. + + :return: True, if the Sim is part of the Active Household. False, if not. + :rtype: bool + """ + return sim_info in cls.get_sim_info_of_all_sims_in_active_household_generator() + + @classmethod + def is_part_of_a_single_sim_household(cls, sim_info: SimInfo) -> bool: + """is_part_of_a_single_sim_household(sim_info) + + Determine if a Sim is the only Sim in their Household (Single Sim Household). + + :param sim_info: An instance of a Sim. + :type: sim_info: SimInfo + :return: True, if specified Sim is the only Sim in their Household (Single Sim Household). False, if not. + :rtype: bool + """ + return cls.get_number_of_sims_in_household_of_sim(sim_info) == 1 + + @classmethod + def is_alone_on_home_lot(cls, sim_info: SimInfo) -> bool: + """is_alone_on_home_lot(sim_info) + + Determine if a Sim is alone on their home lot. + + :param sim_info: An instance of a Sim. + :type: sim_info: SimInfo + :return: True, if the Sim is on their home lot and alone. False, if not. + :rtype: bool + """ + from sims4communitylib.utils.sims.common_sim_location_utils import CommonSimLocationUtils + return cls.is_part_of_a_single_sim_household(sim_info) and CommonSimLocationUtils.is_at_home(sim_info) + + @classmethod + def get_all_households_generator(cls) -> Iterator[Household]: + """get_all_households_generator() + + Retrieve a collection of all households. + + :return: An iterator of all Households. + :rtype: Iterator[Household] + """ + household_list = tuple(services.household_manager().get_all()) + for household in household_list: + if household is None: + continue + yield household + + @classmethod + def locate_household_by_id(cls, household_id: int) -> Union[Household, None]: + """locate_household_by_id(household_id) + + Locate a household with the specified id. + + :param household_id: The decimal identifier of a Household. + :type household_id: int + :return: The Household with an identifier matching the specified identifier or None if no Household was found. + :rtype: Union[Household, None] + """ + # noinspection PyBroadException + try: + return services.household_manager().get(household_id) + except: + return None + + @classmethod + def locate_household_by_name(cls, name: str, allow_partial_match: bool = False, create_on_missing: bool = False, starting_funds: int = 0, as_hidden_household: bool = False) -> Union[Household, None]: + """locate_household_by_name(name, allow_partial_match=False, create_on_missing=False, starting_funds=0, as_hidden_household=False) + + Locate a household with the specified name. + + :param name: The name of a household to locate. + :type name: str + :param allow_partial_match: If True, households only need to contain the name to match. + :type allow_partial_match: bool, optional + :param create_on_missing: If True, a household will be created if one isn't found with the specified name. + :type create_on_missing: bool, optional + :param starting_funds: If a household is created, this will be the starting funds of that household. + :type starting_funds: int, optional + :param as_hidden_household: If True, the created household will be hidden. + :type as_hidden_household: bool, optional + :return: A Household with the specified name or None if no household is found. + :rtype: Union[Household, None] + """ + log = cls.get_log() + for household in cls.locate_households_by_name_generator(name, allow_partial_match=allow_partial_match): + if household is None: + continue + return household + if not create_on_missing: + log.debug('No household found matching name \'{}\'.'.format(name)) + return None + log.debug('No household found, creating one.') + return cls.create_empty_household(starting_funds=starting_funds, as_hidden_household=as_hidden_household) + + @classmethod + def locate_households_by_name_generator(cls, name: str, allow_partial_match: bool = False) -> Iterator[Household]: + """locate_households_by_name_generator(name, allow_partial_match=False) + + Locate all households with the specified name. + + :param name: The name of the households to locate. + :type name: str + :param allow_partial_match: If True, households only need to contain the name to match. + :type allow_partial_match: bool, optional + :return: An iterator of Households with the specified name. + :rtype: Iterator[Household] + """ + log = cls.get_log() + if allow_partial_match: + log.debug('Locating households containing name: \'{}\''.format(name)) + else: + log.debug('Locating households with name: \'{}\''.format(name)) + for household in cls.get_all_households_generator(): + if household is None: + continue + # noinspection PyPropertyAccess + household_name = household.name + # noinspection PyPropertyAccess + log.debug('Checking household \'{}\' for match.'.format(household_name)) + if household_name is None: + continue + if allow_partial_match: + if name not in household_name: + log.debug('Household name did not match.') + continue + elif household_name != name: + log.debug('Household name did not match.') + continue + log.debug('Located household.') + yield household + + @classmethod + def create_empty_household(cls, starting_funds: int = 0, as_hidden_household: bool = False) -> Household: + """create_empty_household(starting_funds=0, as_hidden_household=False) + + Create an empty household. + + :param starting_funds: The funds the Household will start with. + :type starting_funds: int, optional + :param as_hidden_household: If True, the created household will be hidden. + :type as_hidden_household: bool, optional + :return: The created Household + :rtype: Household + """ + household = Household(SimSpawner._get_default_account(), starting_funds=starting_funds) + if as_hidden_household: + household.set_to_hidden() + services.household_manager().add(household) + return household + + @classmethod + def add_sim_to_active_household(cls, sim_info: SimInfo, destroy_if_empty_household: bool = True) -> bool: + """add_sim_to_active_household(sim_info, destroy_if_empty_household=True) + + Add a Sim to the Active Sims household. + + :param sim_info: The Sim to add. + :type sim_info: SimInfo + :param destroy_if_empty_household: If True, if the Sim comes from a household containing only them, then it will be destroyed after they are moved. + :type destroy_if_empty_household: bool, optional + :return: True, if the Sim was added to the active household successfully. False, if not. + :rtype: bool + """ + target_sim_info = CommonSimUtils.get_active_sim_info() + return cls.add_sim_to_target_household(sim_info, target_sim_info, destroy_if_empty_household=destroy_if_empty_household) + + @classmethod + def add_sim_to_target_household(cls, sim_info: SimInfo, target_sim_info: SimInfo, destroy_if_empty_household: bool = True) -> bool: + """add_sim_to_active_household(sim_info, destroy_if_empty_household=True) + + Add a Sim to the Household of the Target Sim. + + :param sim_info: The Sim to add. + :type sim_info: SimInfo + :param target_sim_info: This Sim will receive the Sim to their Household. + :type target_sim_info: SimInfo + :param destroy_if_empty_household: If True, if the Sim comes from a household containing only them, then it will be destroyed after they are moved. + :type destroy_if_empty_household: bool, optional + :return: True, if the Sim was added to the household of the target successfully. False, if not. + :rtype: bool + """ + log = cls.get_log() + log.info('Adding Sim to target Sim household.') + destination_household = target_sim_info.household + log.format_info('Adding Sim to household of target sim', sim=CommonSimNameUtils.get_full_name(sim_info), target_sim=CommonSimNameUtils.get_full_name(target_sim_info), destination_household=destination_household) + return cls.move_sim_to_household(sim_info, household_id=destination_household.id, destroy_if_empty_household=destroy_if_empty_household) + + @classmethod + def move_sim_to_household(cls, sim_info: SimInfo, household_id: int = None, destroy_if_empty_household: bool = True) -> bool: + """move_sim_to_household(sim_info, household_id=None, destroy_if_empty_household=True) + + Move a Sim to the specified household or a new household if no Household is specified. + + :param sim_info: The Sim to add. + :type sim_info: SimInfo + :param household_id: The identifier of the Household to add the Sim to. + :type household_id: int + :param destroy_if_empty_household: If True, if the Sim comes from a household containing only them, then it will be destroyed after they are moved. + :type destroy_if_empty_household: bool, optional + :return: True, if the Sim was added to the Household successfully. False, if not. + :rtype: bool + """ + active_sim_info = CommonSimUtils.get_active_sim_info() + active_household = services.active_household() + starting_household = sim_info.household + log = cls.get_log() + log.format_info('Moving a Sim to a new household.', sim=CommonSimNameUtils.get_full_name(sim_info), household_id=household_id, starting_household=starting_household) + if household_id is None: + log.info('No destination household specified, creating a household for the sim.') + destination_household = services.household_manager().create_household(sim_info.account) + else: + log.info('Household was specified, getting household of the sim.') + destination_household = services.household_manager().get(household_id) + if destination_household is None: + raise AssertionError('Destination Household not specified!') + log.format_info('Destination household acquired', destination_household=destination_household) + if CommonSimStateUtils.is_hidden(sim_info): + log.info('Making hidden Sim visible.') + services.hidden_sim_service().unhide_sim(sim_info.id) + if starting_household is destination_household: + raise AssertionError('The Sim being moved is already in the destination household.') + log.info('Removing Sim from the starting household.') + starting_household.remove_sim_info(sim_info, destroy_if_empty_household=destroy_if_empty_household) + log.info('Adding Sim to the destination household.') + destination_household.add_sim_info_to_household(sim_info) + client = services.client_manager().get_first_client() + if destination_household is active_household: + log.info('The destination household is the active household. Changing the Sim to be selectable.') + client.add_selectable_sim_info(sim_info) + else: + log.info('The destination household is different from the active household. Removing the selectability of the sim.') + if active_sim_info is sim_info: + client.set_next_sim() + client.remove_selectable_sim_info(sim_info) + if sim_info.career_tracker is not None: + log.info('Removing invalid careers.') + sim_info.career_tracker.remove_invalid_careers() + log.info('Invalid careers removed.') + sim = sim_info.get_sim_instance() + if sim is not None: + log.info('Updating sims intended position on the active Lot.') + sim.update_intended_position_on_active_lot(update_ui=True) + situation_manager = services.get_zone_situation_manager() + log.info('Removing Sim from currently active situations.') + for situation in situation_manager.get_situations_sim_is_in(sim): + if destination_household is active_household and situation.is_user_facing: + pass + else: + log.format_info('Removing situation', situation_id=situation.id) + situation_manager.remove_sim_from_situation(sim, situation.id) + log.info('Done removing situations. Updating daycare service information.') + services.daycare_service().on_sim_spawn(sim_info) + log.info('Done moving Sim to household.') + return True + + @classmethod + def has_free_household_slots(cls, sim_info: SimInfo) -> bool: + """has_free_household_slots(sim_info) + + Determine if the Household of the specified Sim has any free Sim slots. + + .. note:: Max household slots in vanilla Sims 4 is 8 sims. + + :param sim_info: The Sim whose household will be checked. + :type sim_info: SimInfo + :return: True, if there are free slots for new Sims in the Household of the specified Sim. False, if not. + :rtype: bool + """ + return cls.get_free_household_slots(sim_info) > 0 + + @classmethod + def get_free_household_slots(cls, sim_info: SimInfo) -> int: + """get_free_household_slots(sim_info) + + Retrieve the number of free household slots in the Household of the specified Sim. + + .. note:: Max household slots in vanilla Sims 4 is 8 sims. + + :param sim_info: The Sim whose household will be checked. + :type sim_info: SimInfo + :return: The number of free household slots or -1 if no Household is found for the specified Sim. + :rtype: int + """ + household = cls.get_household(sim_info) + if household is None: + return -1 + return household.free_slot_count + + @classmethod + def get_household_members_gen(cls, sim_info: SimInfo) -> Iterator[SimInfo]: + """get_household_members_gen(sim_info) + + Retrieve the Sims within the household of a Sim. + + .. note:: The result will include the specified Sim as well. + + :param sim_info: The info of a Sim. + :type sim_info: SimInfo + :return: An iterator of Sims within the household of the specified Sim. + :rtype: Iterator[SimInfo] + """ + household = cls.get_household(sim_info) + if household is None: + yield sim_info + else: + yield from cls.get_household_members_from_household_gen(household) + + @classmethod + def get_household_members_from_household_gen(cls, household: Household) -> Iterator[SimInfo]: + """get_household_members_from_household_gen(sim_info) + + Retrieve the Sims within a Household. + + :param household: An instance of a Household + :type household: Household + :return: An iterator of Sims within the specified household. + :rtype: Iterator[SimInfo] + """ + if household is None: + return tuple() + + for household_member_sim_info in household: + yield CommonSimUtils.get_sim_info(household_member_sim_info) + + @classmethod + def get_household(cls, sim_info: SimInfo) -> Union[Household, None]: + """get_household(sim_info) + + Retrieve the household of a Sim. + + :param sim_info: The Sim whose household will be retrieved. + :type sim_info: SimInfo + :return: The Household of the specified Sim or None if no household is found. + :rtype: Union[Household, None] + """ + if not cls.has_household(sim_info): + return None + return services.household_manager().get(sim_info.household.id) + + @classmethod + def get_household_id(cls, sim_info: SimInfo) -> int: + """get_household_id(sim_info) + + Retrieve an identifier for the Household a Sim is a part of. + + :param sim_info: The Sim whose household will be retrieved. + :type sim_info: SimInfo + :return: The identifier of the Household of the specified Sim or `0` if no household is found. + :rtype: int + """ + return cls.get_id(cls.get_household(sim_info)) + + @classmethod + def get_id(cls, household: Household) -> int: + """get_id(household) + + Retrieve the decimal identifier of a Household. + + :param household: An instance of a Household. + :type: Household + :return: The identifier of the Household or `0` if an error occurs. + :rtype: int + """ + if household is None: + return 0 + return household.id + + @classmethod + def has_household(cls, sim_info: SimInfo) -> bool: + """has_household(sim_info) + + Determine if the Sim is part of a Household. + + :param sim_info: The Sim whose household will be checked. + :type sim_info: SimInfo + :return: True, if the Sim is part of a Household. False, if not. + :rtype: bool + """ + return hasattr(sim_info, 'household') and sim_info.household is not None + + @classmethod + def is_in_same_household(cls, sim_info: SimInfo, target_sim_info: SimInfo) -> bool: + """is_in_same_household(sim_info, target_sim_info) + + Determine if two Sims are in the same household. + + :param sim_info: The Sim whose household will be checked. + :type sim_info: SimInfo + :param target_sim_info: The Target whose household will be checked. + :type target_sim_info: SimInfo + :return: True, if the Sim is part of same Household as the Target Sim. False, if not. + :rtype: bool + """ + household = cls.get_household(sim_info) + if household is None: + return False + target_household = cls.get_household(target_sim_info) + if target_household is None: + return False + return household is target_household + + @classmethod + def get_household_owning_current_lot(cls) -> Union[Household, None]: + """get_household_owning_current_lot() + + Retrieve the Household that owns the current Lot. + + :return: A decimal identifier of the Household that owns the current Lot or None if no Household owns the current Lot. + :rtype: Union[Household, None] + """ + household_id = cls.get_household_id_owning_current_lot() + if household_id is None or household_id == -1: + return None + return cls.locate_household_by_id(household_id) + + @classmethod + def get_household_id_owning_current_lot(cls) -> int: + """get_household_id_owning_current_lot() + + Retrieve the decimal identifier of the Household that owns the current Lot. + + :return: A decimal identifier of the Household that owns the current Lot or -1 if a problem occurs. + :rtype: int + """ + household_id = services.owning_household_id_of_active_lot() + if household_id is None: + return -1 + return household_id + + @classmethod + def get_household_owning_lot(cls, lot: Lot) -> Union[Household, None]: + """get_household_owning_lot(lot) + + Retrieve the Household that owns a Lot. + + :param lot: An instance of a Lot. + :type lot: Lot + :return: A decimal identifier of the Household that owns the specified Lot or None if no Household owns the specified Lot. + :rtype: Union[Household, None] + """ + household_id = cls.get_household_id_owning_lot(lot) + if household_id is None or household_id == -1: + return None + return cls.locate_household_by_id(household_id) + + @classmethod + def get_household_id_owning_lot(cls, lot: Lot) -> int: + """get_household_id_owning_lot(lot) + + Retrieve the decimal identifier of the Household that owns a Lot. + + :param lot: An instance of a Lot. + :type lot: Lot + :return: A decimal identifier of the Household that owns the specified Lot or -1 if a problem occurs. + :rtype: int + """ + if lot is None: + return -1 + return lot.owner_household_id + + @classmethod + def delete_household(cls, household: Household) -> bool: + """delete_household(household) + + Delete the specified household from the game. + + :param household: The Household to delete + :type household: Household + :return: True, if the Household was deleted successfully. False, if not. + :rtype: bool + """ + services.get_persistence_service().del_household_proto_buff(household.id) + services.household_manager().remove(household) + return True + + @classmethod + def delete_households_with_name(cls, name: str, allow_partial_match: bool = False) -> bool: + """delete_households_with_name(name, allow_partial_match=False) + + Delete all households with the specified name. + + :param name: The name of the households to delete. + :type name: str + :param allow_partial_match: If True, households only need to contain the name to match. + :type allow_partial_match: bool + :return: True, if Households were deleted successfully. False, if not. + :rtype: bool + """ + log = cls.get_log() + if allow_partial_match: + log.debug('Attempting to delete households containing name \'{}\'.'.format(name)) + else: + log.debug('Attempting to delete households with name \'{}\'.'.format(name)) + all_completed = True + for household in cls.locate_households_by_name_generator(name, allow_partial_match=allow_partial_match): + if household is None: + continue + result = cls.delete_household(household) + if not result: + all_completed = False + return all_completed + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.add_to_household', + 'Add a Sim to the household of another Sim.', + command_arguments=( + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance id or name of a Sim to add to the household.'), + CommonConsoleCommandArgument('target_household_sim_info', 'Sim Id or Name', 'The instance id or name of a Sim. The other Sim (sim_info) will be added to this Sims household.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.addtohousehold', + ) +) +def _common_command_add_to_my_household(output: CommonConsoleCommandOutput, sim_info: SimInfo = None, target_household_sim_info: SimInfo = None): + if sim_info is None: + return + if target_household_sim_info is None: + return + output(f'Attempting to move {sim_info} to the household of {target_household_sim_info}.') + result = CommonHouseholdUtils.add_sim_to_active_household(sim_info) + if result: + output(f'SUCCESS: Successfully moved {sim_info} to the household of {target_household_sim_info}.') + else: + output(f'FAILED: Failed to move {sim_info} to the household of {target_household_sim_info}.') + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.remove_from_household', + 'Remove a Sim from the household they are in and put them into their own household.', + command_arguments=( + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance id or name of a Sim to remove from their household.'), + ), + command_aliases=( + 's4clib.removefromhousehold', + ) +) +def _common_command_remove_from_my_household(output: CommonConsoleCommandOutput, sim_info: SimInfo): + if sim_info is None: + return + output(f'Attempting to move {sim_info} out of their current household.') + empty_household = CommonHouseholdUtils.create_empty_household() + result = CommonHouseholdUtils.move_sim_to_household(sim_info, household_id=empty_household.id, destroy_if_empty_household=True) + if result: + output(f'SUCCESS: Successfully removed {sim_info} from their current household.') + else: + output(f'FAILED: Failed to remove {sim_info} from their current household.') diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_mood_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_mood_utils.py new file mode 100644 index 0000000..2b61ada --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_mood_utils.py @@ -0,0 +1,277 @@ +""" +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 +""" +from sims.sim_info import SimInfo +from statistics.mood import Mood +from sims4communitylib.enums.moods_enum import CommonMoodId + + +class CommonMoodUtils: + """Utilities for manipulating Sim moods. + + """ + @staticmethod + def is_angry(sim_info: SimInfo) -> bool: + """is_angry(sim_info) + + Determine if a Sim is angry. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is the Mood. False, if the Sim is not. + :rtype: bool + """ + return CommonMoodUtils.has_mood(sim_info, CommonMoodId.ANGRY) + + @staticmethod + def is_bored(sim_info: SimInfo) -> bool: + """is_bored(sim_info) + + Determine if a Sim is bored. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is the Mood. False, if the Sim is not. + :rtype: bool + """ + return CommonMoodUtils.has_mood(sim_info, CommonMoodId.BORED) + + @staticmethod + def is_confident(sim_info: SimInfo) -> bool: + """is_confident(sim_info) + + Determine if a Sim is confident. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is the Mood. False, if the Sim is not. + :rtype: bool + """ + return CommonMoodUtils.has_mood(sim_info, CommonMoodId.CONFIDENT) + + @staticmethod + def is_dazed(sim_info: SimInfo) -> bool: + """is_dazed(sim_info) + + Determine if a Sim is dazed. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is the Mood. False, if the Sim is not. + :rtype: bool + """ + return CommonMoodUtils.has_mood(sim_info, CommonMoodId.DAZED) + + @staticmethod + def is_embarrassed(sim_info: SimInfo) -> bool: + """is_embarrassed(sim_info) + + Determine if a Sim is embarrassed. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is the Mood. False, if the Sim is not. + :rtype: bool + """ + return CommonMoodUtils.has_mood(sim_info, CommonMoodId.EMBARRASSED) + + @staticmethod + def is_energized(sim_info: SimInfo) -> bool: + """is_energized(sim_info) + + Determine if a Sim is energized. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is the Mood. False, if the Sim is not. + :rtype: bool + """ + return CommonMoodUtils.has_mood(sim_info, CommonMoodId.ENERGIZED) + + @staticmethod + def is_fine(sim_info: SimInfo) -> bool: + """is_fine(sim_info) + + Determine if a Sim is fine. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is the Mood. False, if the Sim is not. + :rtype: bool + """ + return CommonMoodUtils.has_mood(sim_info, CommonMoodId.FINE) + + @staticmethod + def is_flirty(sim_info: SimInfo) -> bool: + """is_flirty(sim_info) + + Determine if a Sim is flirty. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is the Mood. False, if the Sim is not. + :rtype: bool + """ + return CommonMoodUtils.has_mood(sim_info, CommonMoodId.FLIRTY) + + @staticmethod + def is_focused(sim_info: SimInfo) -> bool: + """is_focused(sim_info) + + Determine if a Sim is focused. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is the Mood. False, if the Sim is not. + :rtype: bool + """ + return CommonMoodUtils.has_mood(sim_info, CommonMoodId.FOCUSED) + + @staticmethod + def is_happy(sim_info: SimInfo) -> bool: + """is_happy(sim_info) + + Determine if a Sim is happy. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is the Mood. False, if the Sim is not. + :rtype: bool + """ + return CommonMoodUtils.has_mood(sim_info, CommonMoodId.HAPPY) + + @staticmethod + def is_inspired(sim_info: SimInfo) -> bool: + """is_inspired(sim_info) + + Determine if a Sim is inspired. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is the Mood. False, if the Sim is not. + :rtype: bool + """ + return CommonMoodUtils.has_mood(sim_info, CommonMoodId.INSPIRED) + + @staticmethod + def is_playful(sim_info: SimInfo) -> bool: + """is_playful(sim_info) + + Determine if a Sim is playful. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is the Mood. False, if the Sim is not. + :rtype: bool + """ + return CommonMoodUtils.has_mood(sim_info, CommonMoodId.PLAYFUL) + + @staticmethod + def is_sad(sim_info: SimInfo) -> bool: + """is_sad(sim_info) + + Determine if a Sim is sad. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is the Mood. False, if the Sim is not. + :rtype: bool + """ + return CommonMoodUtils.has_mood(sim_info, CommonMoodId.SAD) + + @staticmethod + def is_stressed(sim_info: SimInfo) -> bool: + """is_stressed(sim_info) + + Determine if a Sim is stressed. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is the Mood. False, if the Sim is not. + :rtype: bool + """ + return CommonMoodUtils.has_mood(sim_info, CommonMoodId.STRESSED) + + @staticmethod + def is_uncomfortable(sim_info: SimInfo) -> bool: + """is_uncomfortable(sim_info) + + Determine if a Sim is uncomfortable. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is the Mood. False, if the Sim is not. + :rtype: bool + """ + return CommonMoodUtils.has_mood(sim_info, CommonMoodId.UNCOMFORTABLE) + + @staticmethod + def is_possessed(sim_info: SimInfo) -> bool: + """is_possessed(sim_info) + + Determine if a Sim is possessed. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is the Mood. False, if the Sim is not. + :rtype: bool + """ + return CommonMoodUtils.has_mood(sim_info, CommonMoodId.POSSESSED) + + @staticmethod + def is_sleeping(sim_info: SimInfo) -> bool: + """is_sleeping(sim_info) + + Determine if a Sim is sleeping. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is the Mood. False, if the Sim is not. + :rtype: bool + """ + return CommonMoodUtils.has_mood(sim_info, CommonMoodId.SLEEPING) + + @staticmethod + def has_mood(sim_info: SimInfo, mood_id: CommonMoodId) -> bool: + """has_mood(sim_info, mood_id) + + Determine if a Sim has the specified mood. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :param mood_id: The identifier of the Mood to check for. + :type mood_id: CommonMoodId + :return: True, if the Sim has the specified Mood. False, if the Sim does not. + :rtype: bool + """ + return CommonMoodUtils.get_current_mood_id(sim_info) == mood_id + + @staticmethod + def get_current_mood(sim_info: SimInfo) -> Mood: + """get_current_mood(sim_info) + + Retrieve the current mood for the specified Sim. + + :param sim_info: The Sim to retrieve the mood of. + :type sim_info: SimInfo + :return: The current Mood of the Sim. + :rtype: Mood + """ + return sim_info.get_mood() + + @staticmethod + def get_current_mood_id(sim_info: SimInfo) -> int: + """get_current_mood_id(sim_info) + + Retrieve an identifier of the current mood for the specified Sim. + + :param sim_info: The Sim to retrieve the mood identifier of. + :type sim_info: SimInfo + :return: The identifier of the current Mood of the Sim. + :rtype: int + """ + return getattr(CommonMoodUtils.get_current_mood(sim_info), 'guid64', -1) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_occult_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_occult_utils.py new file mode 100644 index 0000000..82a05e5 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_occult_utils.py @@ -0,0 +1,1876 @@ +""" +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 +""" +import random +from typing import Iterator, Tuple, Union + +from sims.occult.occult_enums import OccultType +from sims.sim_info import SimInfo +from sims.sim_info_base_wrapper import SimInfoBaseWrapper +from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.dtos.common_cas_part import CommonCASPart +from sims4communitylib.enums.buffs_enum import CommonBuffId +from sims4communitylib.enums.common_bucks_types import CommonBucksType +from sims4communitylib.enums.common_occult_type import CommonOccultType +from sims4communitylib.enums.traits_enum import CommonTraitId +from sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + CommonConsoleCommandArgument +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.cas.common_cas_utils import CommonCASUtils +from sims4communitylib.utils.common_type_utils import CommonTypeUtils +from sims4communitylib.utils.sims.common_buff_utils import CommonBuffUtils +from sims4communitylib.utils.sims.common_sim_appearance_modifier_utils import CommonSimAppearanceModifierUtils +from sims4communitylib.utils.sims.common_sim_bucks_utils import CommonSimBucksUtils +from sims4communitylib.utils.sims.common_sim_loot_action_utils import CommonSimLootActionUtils +from sims4communitylib.utils.sims.common_sim_spell_utils import CommonSimSpellUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils +try: + from traits.trait_type import TraitType +except ModuleNotFoundError: + from traits.traits import TraitType + + +class CommonOccultUtils(_HasS4CLClassLog): + """Utilities for manipulating the Occults of Sims. + + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 'common_occult_utils' + + @classmethod + def get_all_occult_types_for_sim_gen(cls, sim_info: SimInfo) -> Iterator[OccultType]: + """get_all_occult_types_for_sim_gen(sim_info) + + Retrieve a generator of OccultType for all Occults of a Sim. + + .. note:: Results include the occult type of the sim_info specified.\ + If they are Human by default, the Human occult type will be included. + + :param sim_info: The Sim to locate the Occults of. + :type sim_info: SimInfo + :return: An iterator of OccultType for all occults of the Sim. (Results will not include Occult Types not within the OccultTypes enum, such as Skeleton, Robot, and Ghost! Use :class:`.CommonSimOccultTypeUtils` for more accurate results.) + :rtype: Iterator[OccultType] + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + yield OccultType.HUMAN + sim_occult_types = CommonOccultUtils._get_occult_types(sim_info) + for occult_type in OccultType.values: + if occult_type == OccultType.HUMAN: + continue + if sim_occult_types & occult_type: + yield occult_type + + @classmethod + def get_sim_info_for_all_occults_gen(cls, sim_info: SimInfo, exclude_occult_types: Iterator[OccultType]) -> Iterator[SimInfo]: + """get_sim_info_for_all_occults_gen(sim_info, exclude_occult_types) + + Retrieve a generator of SimInfo objects for all Occults of a sim. + + .. note:: Results include the occult type of the sim_info specified.\ + If they are Human by default, the Human occult Sim info will be included. + + :param sim_info: The Sim to locate the Occults of. + :type sim_info: SimInfo + :param exclude_occult_types: A collection of OccultTypes to exclude from the resulting SimInfo list. + :type exclude_occult_types: Iterator[OccultType] + :return: An iterator of Sims for all occult types of the Sim. + :rtype: Iterator[SimInfo] + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + exclude_occult_types: Tuple[OccultType] = tuple(exclude_occult_types) + yield sim_info + current_occult_type = CommonOccultUtils.get_current_occult_type(sim_info) + for occult_type in OccultType.values: + if occult_type in exclude_occult_types: + continue + if occult_type == current_occult_type: + continue + occult_sim_info: SimInfo = CommonOccultUtils.get_occult_sim_info(sim_info, occult_type) + if occult_sim_info is None: + continue + yield occult_sim_info + + @classmethod + def has_any_occult(cls, sim_info: SimInfo) -> CommonTestResult: + """has_any_occult(sim_info) + + Determine if a Sim has any Occult Types. + + :param sim_info: The Sim to locate the Occults of. + :type sim_info: SimInfo + :return: The result of testing. True, if the specified Sim has any Non-Human Occult Types. False, if not. + :rtype: CommonTestResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + from sims4communitylib.utils.sims.common_sim_occult_type_utils import CommonSimOccultTypeUtils + occult_type = CommonSimOccultTypeUtils.determine_occult_type(sim_info) + if occult_type not in (CommonOccultType.NON_OCCULT, CommonOccultType.NONE): + return CommonTestResult(True, reason=f'Sim had an occult type. {occult_type}') + return CommonTestResult(False, reason=f'Sim did not have an occult type. {occult_type}') + + @classmethod + def has_occult_type(cls, sim_info: SimInfo, occult_type: OccultType) -> CommonTestResult: + """has_occult_type(sim_info, occult_type) + + Determine if a Sim has an Occult Type. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param occult_type: The Occult Type to check. + :type occult_type: OccultType + :return: The result of testing. True, if the Sim has the specified Occult Type. False, if not. + :rtype: CommonTestResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + if bool(CommonOccultUtils._get_occult_types(sim_info) & occult_type): + return CommonTestResult(True, reason=f'Sim had occult type {occult_type}.') + return CommonTestResult(False, reason=f'Sim did not have occult type {occult_type}') + + @classmethod + def has_occult_sim_info(cls, sim_info: SimInfo, occult_type: OccultType) -> CommonTestResult: + """has_occult_sim_info(sim_info, occult_type) + + Determine if a Sim has a SimInfo for an Occult. + + :param sim_info: The Sim to locate the Occults of. + :type sim_info: SimInfo + :param occult_type: The Occult Type to check. + :type occult_type: OccultType + :return: The result of testing. True, if a SimInfo is available for the specified Occult for the Sim. False, if not. + :rtype: CommonTestResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + if not hasattr(sim_info, 'occult_tracker') or sim_info.occult_tracker is None: + return CommonTestResult(False, reason='Sim did not have an occult tracker, thus they did not have any occult types.') + if sim_info.occult_tracker.has_occult_type(occult_type): + return CommonTestResult(True, reason=f'Sim had a Sim Info for {occult_type}.') + return CommonTestResult(False, reason=f'Sim did not have a Sim Info {occult_type}') + + @classmethod + def get_current_occult_sim_info(cls, sim_info: SimInfo) -> Union[SimInfo, SimInfoBaseWrapper, None]: + """get_current_occult_sim_info(sim_info) + + Retrieve the SimInfo for the Occult the Sim is currently. + + :param sim_info: The Sim to locate the Occults of. + :type sim_info: SimInfo + :return: The SimInfo of the Sim or the SimInfoBaseWrapper for the Occult they are (If they are currently an occult). + :rtype: Union[SimInfo, SimInfoBaseWrapper, None] + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + current_occult_type = CommonOccultUtils.get_current_occult_type(sim_info) + return CommonOccultUtils.get_occult_sim_info(sim_info, current_occult_type) + + @classmethod + def get_occult_sim_info(cls, sim_info: SimInfo, occult_type: OccultType) -> Union[SimInfo, SimInfoBaseWrapper]: + """get_occult_sim_info(sim_info, occult_type) + + Retrieve the SimInfo for an Occult of a Sim. + + :param sim_info: The Sim to locate the Occults of. + :type sim_info: SimInfo + :param occult_type: The Occult Type to retrieve the SimInfo of. + :type occult_type: OccultType + :return: The SimInfo of the Sim or the SimInfoBaseWrapper for the specified Occult or the original Sim Info, if the Sim did not have the occult type. + :rtype: Union[SimInfo, SimInfoBaseWrapper, None] + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + if not hasattr(sim_info, 'occult_tracker') or sim_info.occult_tracker is None: + return sim_info + occult_sim_info = sim_info.occult_tracker.get_occult_sim_info(occult_type) + return occult_sim_info + + @classmethod + def add_occult(cls, sim_info: SimInfo, occult_type: CommonOccultType) -> CommonExecutionResult: + """add_occult(sim_info, occult_type) + + Add an Occult Type to a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param occult_type: The occult type to add. + :type occult_type: CommonOccultType + :return: The result of adding the occult. True, if the specified Occult Type has been added to the Sim. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + is_occult_available_result = CommonOccultUtils.is_occult_available(occult_type) + if not is_occult_available_result: + return is_occult_available_result + occult_type_add_mappings = { + CommonOccultType.ALIEN: CommonOccultUtils.add_alien_occult, + CommonOccultType.MERMAID: CommonOccultUtils.add_mermaid_occult, + CommonOccultType.PLANT_SIM: CommonOccultUtils.add_plant_sim_occult, + CommonOccultType.ROBOT: CommonOccultUtils.add_robot_occult, + CommonOccultType.SCARECROW: CommonOccultUtils.add_scarecrow_occult, + CommonOccultType.SKELETON: CommonOccultUtils.add_skeleton_occult, + CommonOccultType.VAMPIRE: CommonOccultUtils.add_vampire_occult, + CommonOccultType.WITCH: CommonOccultUtils.add_witch_occult, + CommonOccultType.WEREWOLF: CommonOccultUtils.add_werewolf_occult + } + if occult_type not in occult_type_add_mappings: + return CommonExecutionResult(False, reason=f'The specified occult type did not have an add function. {occult_type.name}') + return occult_type_add_mappings[occult_type](sim_info) + + @classmethod + def remove_occult(cls, sim_info: SimInfo, occult_type: CommonOccultType) -> CommonExecutionResult: + """remove_occult(sim_info, occult_type) + + Remove an Occult Type from a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param occult_type: The occult type to remove. + :type occult_type: CommonOccultType + :return: The result of removing the occult. True, if the specified Occult Type has been removed from the Sim. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + is_occult_available_result = CommonOccultUtils.is_occult_available(occult_type) + if not is_occult_available_result: + return is_occult_available_result.reverse_result() + occult_type_remove_mappings = { + CommonOccultType.ALIEN: CommonOccultUtils.remove_alien_occult, + CommonOccultType.MERMAID: CommonOccultUtils.remove_mermaid_occult, + CommonOccultType.PLANT_SIM: CommonOccultUtils.remove_plant_sim_occult, + CommonOccultType.ROBOT: CommonOccultUtils.remove_robot_occult, + CommonOccultType.SCARECROW: CommonOccultUtils.remove_scarecrow_occult, + CommonOccultType.SKELETON: CommonOccultUtils.remove_skeleton_occult, + CommonOccultType.VAMPIRE: CommonOccultUtils.remove_vampire_occult, + CommonOccultType.WITCH: CommonOccultUtils.remove_witch_occult, + CommonOccultType.WEREWOLF: CommonOccultUtils.remove_werewolf_occult + } + if occult_type not in occult_type_remove_mappings: + return CommonExecutionResult(False, reason=f'The specified occult type did not have a remove function, meaning it has not been implemented yet. {occult_type.name}') + return occult_type_remove_mappings[occult_type](sim_info) + + @classmethod + def add_alien_occult(cls, sim_info: SimInfo) -> CommonExecutionResult: + """add_alien_occult(sim_info) + + Add the Alien Occult Type to a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of adding the Alien occult. True, if the Sim has successfully become an Alien. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + is_alien_available_result = CommonOccultUtils.is_alien_occult_available() + if not is_alien_available_result: + return is_alien_available_result + is_alien_result = CommonOccultUtils.is_alien(sim_info) + if is_alien_result: + return is_alien_result + loot_action_ids: Tuple[int, ...] = ( + # loot_Occult_AlienAdd + 103256, + # loot_Occult_AlienSwitch + 103254 + ) + # noinspection PyPropertyAccess + physique = sim_info.physique + # noinspection PyPropertyAccess + facial_attributes = sim_info.facial_attributes + # noinspection PyPropertyAccess + voice_pitch = sim_info.voice_pitch + # noinspection PyPropertyAccess + voice_actor = sim_info.voice_actor + # noinspection PyPropertyAccess + voice_effect = sim_info.voice_effect + # noinspection PyPropertyAccess + skin_tone = sim_info.skin_tone + flags = sim_info.flags + pelt_layers = None + if hasattr(sim_info, 'pelt_layers'): + # noinspection PyPropertyAccess + pelt_layers = sim_info.pelt_layers + base_trait_ids = None + if hasattr(sim_info, 'base_trait_ids'): + base_trait_ids = list(sim_info.base_trait_ids) + # noinspection PyPropertyAccess + genetic_data_b = sim_info.genetic_data + if hasattr(genetic_data_b, 'SerializeToString'): + genetic_data_b = genetic_data_b.SerializeToString() + result = CommonSimLootActionUtils.apply_loot_actions_by_ids_to_sim(loot_action_ids, sim_info) + human_sim_info = sim_info.occult_tracker.get_occult_sim_info(OccultType.HUMAN) + human_sim_info.physique = physique + human_sim_info.facial_attributes = facial_attributes + human_sim_info.voice_pitch = voice_pitch + human_sim_info.voice_actor = voice_actor + human_sim_info.voice_effect = voice_effect + human_sim_info.skin_tone = skin_tone + human_sim_info.flags = flags + if pelt_layers is not None: + human_sim_info.pelt_layers = pelt_layers + if base_trait_ids is not None: + human_sim_info.base_trait_ids = list(base_trait_ids) + if hasattr(human_sim_info.genetic_data, 'MergeFromString'): + human_sim_info.genetic_data.MergeFromString(genetic_data_b) + else: + human_sim_info.genetic_data = genetic_data_b + if result: + return CommonExecutionResult.TRUE + return CommonExecutionResult.FALSE + + @classmethod + def remove_alien_occult(cls, sim_info: SimInfo) -> CommonExecutionResult: + """remove_alien_occult(sim_info) + + Remove the Alien Occult Type from a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of removing the alien occult. True, if the Alien Occult Type has been successfully removed from the specified Sim. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + is_alien_available_result = CommonOccultUtils.is_alien_occult_available() + if not is_alien_available_result: + return is_alien_available_result.reverse_result() + is_alien_result = CommonOccultUtils.is_alien(sim_info) + if not is_alien_result: + return is_alien_result.reverse_result() + CommonOccultUtils.switch_to_occult_form(sim_info, OccultType.HUMAN) + sim_info.occult_tracker.remove_occult_type(OccultType.ALIEN) + return CommonExecutionResult.TRUE + + @classmethod + def add_mermaid_occult(cls, sim_info: SimInfo) -> CommonExecutionResult: + """add_mermaid_occult(sim_info) + + Add the Mermaid Occult Type to a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of adding the mermaid occult. True, if the Sim has successfully become a Mermaid. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + is_mermaid_available_result = CommonOccultUtils.is_mermaid_occult_available() + if not is_mermaid_available_result: + return is_mermaid_available_result + is_mermaid_result = CommonOccultUtils.is_mermaid(sim_info) + if is_mermaid_result: + return is_mermaid_result + # loot_Mermaid_DebugAdd + add_loot_action_id = 205399 + if CommonSimLootActionUtils.apply_loot_actions_by_id_to_sim(add_loot_action_id, sim_info): + return CommonExecutionResult.TRUE + return CommonExecutionResult.FALSE + + @classmethod + def remove_mermaid_occult(cls, sim_info: SimInfo) -> CommonExecutionResult: + """remove_mermaid_occult(sim_info) + + Remove the Mermaid Occult Type from a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of removing the mermaid occult. True, if the Mermaid Occult Type has been successfully removed from the specified Sim. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + is_mermaid_available_result = CommonOccultUtils.is_mermaid_occult_available() + if not is_mermaid_available_result: + return is_mermaid_available_result.reverse_result() + is_mermaid_result = CommonOccultUtils.is_mermaid(sim_info) + if not is_mermaid_result: + return is_mermaid_result.reverse_result() + traits: Tuple[Union[int, CommonTraitId], ...] = ( + CommonTraitId.OCCULT_MERMAID_MERMAID_FORM, + CommonTraitId.OCCULT_MERMAID_DISCOVERED, + CommonTraitId.OCCULT_MERMAID_TEMPORARY_DISCOVERED, + CommonTraitId.OCCULT_MERMAID_TYAE, + CommonTraitId.OCCULT_MERMAID, + ) + CommonOccultUtils.switch_to_occult_form(sim_info, OccultType.HUMAN) + return CommonTraitUtils.remove_traits(sim_info, traits) + + @classmethod + def add_plant_sim_occult(cls, sim_info: SimInfo) -> CommonExecutionResult: + """add_plant_sim_occult(sim_info) + + Add the Plant Sim Occult Type to a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of adding the Plant Sim occult. True, if the Sim has successfully become a Plant Sim. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + is_plant_sim_available_result = CommonOccultUtils.is_plant_sim_occult_available() + if not is_plant_sim_available_result: + return is_plant_sim_available_result + # loot_Buff_PlantSims_BecomePlantSim + add_loot_action_id = 163440 + if CommonSimLootActionUtils.apply_loot_actions_by_id_to_sim(add_loot_action_id, sim_info): + return CommonExecutionResult.TRUE + return CommonExecutionResult.FALSE + + @classmethod + def remove_plant_sim_occult(cls, sim_info: SimInfo) -> CommonExecutionResult: + """remove_plant_sim_occult(sim_info) + + Remove the Plant Sim Occult Type from a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of removing the Plant Sim occult. True, if the Plant Sim Occult Type has been successfully removed from the specified Sim. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + is_plant_sim_available_result = CommonOccultUtils.is_plant_sim_occult_available() + if not is_plant_sim_available_result: + return is_plant_sim_available_result.reverse_result() + remove_result = CommonBuffUtils.remove_buff(sim_info, CommonBuffId.PLANT_SIMS_MAIN_VISIBLE) + if not remove_result: + return remove_result + return CommonExecutionResult.TRUE + + @classmethod + def add_robot_occult(cls, sim_info: SimInfo) -> CommonExecutionResult: + """add_robot_occult(sim_info) + + Add the Robot Occult Type to a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of adding the robot occult. True, if the Sim has successfully become a Robot. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + is_robot_available_result = CommonOccultUtils.is_robot_occult_available() + if not is_robot_available_result: + return is_robot_available_result + is_robot_result = CommonOccultUtils.is_robot(sim_info) + if is_robot_result: + return is_robot_result + return CommonTraitUtils.add_trait(sim_info, CommonTraitId.OCCULT_ROBOT) + + @classmethod + def remove_robot_occult(cls, sim_info: SimInfo) -> CommonExecutionResult: + """remove_robot_occult(sim_info) + + Remove the Robot Occult Type from a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of removing the robot occult. True, if the Robot Occult Type has been successfully removed from the specified Sim. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + is_robot_available_result = CommonOccultUtils.is_robot_occult_available() + if not is_robot_available_result: + return is_robot_available_result.reverse_result() + is_robot_result = CommonOccultUtils.is_robot(sim_info) + if not is_robot_result: + return is_robot_result.reverse_result() + return CommonTraitUtils.remove_trait(sim_info, CommonTraitId.OCCULT_ROBOT) + + @classmethod + def add_scarecrow_occult(cls, sim_info: SimInfo) -> CommonExecutionResult: + """add_scarecrow_occult(sim_info) + + Add the Scarecrow Occult Type to a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of adding the Scarecrow occult. True, if the Sim has successfully become a Scarecrow. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + is_scarecrow_available_result = CommonOccultUtils.is_scarecrow_occult_available() + if not is_scarecrow_available_result: + return is_scarecrow_available_result + is_scarecrow_result = CommonOccultUtils.is_scarecrow(sim_info) + if is_scarecrow_result: + return is_scarecrow_result + + if not CommonTraitUtils.add_trait(sim_info, CommonTraitId.SCARECROW): + return CommonTestResult(False, reason=f'Failed to add scarecrow trait to {sim_info}.') + + scarecrow_cas_part_ids = ( + # yuBody_EP05ScareCrow_Gray + 198149, + # yuBody_EP05ScareCrow_Red + 198148, + # yuBody_EP05ScareCrow_Purple + 198147 + ) + chosen_id = random.choice(scarecrow_cas_part_ids) + from sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils + if CommonCASUtils.attach_cas_part_to_all_outfits_of_sim(sim_info, CommonCASPart(chosen_id)): + current_outfit_category_and_index = CommonOutfitUtils.get_current_outfit(sim_info) + CommonOutfitUtils.trigger_outfit_generated(sim_info, current_outfit_category_and_index) + CommonOutfitUtils.set_outfit_dirty(sim_info, current_outfit_category_and_index[0]) + CommonOutfitUtils.set_current_outfit(sim_info, current_outfit_category_and_index) + return CommonExecutionResult(True, reason=f'{sim_info} is now a Scarecrow.') + CommonSimAppearanceModifierUtils.evaluate_appearance_modifiers(sim_info) + return CommonExecutionResult(False, reason=f'Failed to turn {sim_info} into a Scarecrow.') + + @classmethod + def remove_scarecrow_occult(cls, sim_info: SimInfo) -> CommonExecutionResult: + """remove_scarecrow_occult(sim_info) + + Remove the Scarecrow Occult Type from a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of removing the Scarecrow occult. True, if the Scarecrow Occult Type has been successfully removed from the specified Sim. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + is_scarecrow_available_result = CommonOccultUtils.is_scarecrow_occult_available() + if not is_scarecrow_available_result: + return is_scarecrow_available_result.reverse_result() + is_scarecrow_result = CommonOccultUtils.is_scarecrow(sim_info) + if not is_scarecrow_result: + return is_scarecrow_result.reverse_result() + scarecrow_cas_parts = ( + # yuBody_EP05ScareCrow_Gray + CommonCASPart(198149), + # yuBody_EP05ScareCrow_Red + CommonCASPart(198148), + # yuBody_EP05ScareCrow_Purple + CommonCASPart(198147) + ) + + from sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils + if CommonCASUtils.detach_cas_parts_from_all_outfits_of_sim(sim_info, scarecrow_cas_parts): + current_outfit_category_and_index = CommonOutfitUtils.get_current_outfit(sim_info) + CommonOutfitUtils.trigger_outfit_generated(sim_info, current_outfit_category_and_index) + CommonOutfitUtils.set_outfit_dirty(sim_info, current_outfit_category_and_index[0]) + CommonOutfitUtils.set_current_outfit(sim_info, current_outfit_category_and_index) + return CommonTraitUtils.remove_trait(sim_info, CommonTraitId.SCARECROW) + + @classmethod + def add_skeleton_occult(cls, sim_info: SimInfo) -> CommonExecutionResult: + """add_skeleton_occult(sim_info) + + Add the Skeleton Occult Type to a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of adding the Skeleton occult. True, if the Sim has successfully become a Skeleton. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + is_skeleton_available_result = CommonOccultUtils.is_skeleton_occult_available() + if not is_skeleton_available_result: + return is_skeleton_available_result + is_skeleton_result = CommonOccultUtils.is_skeleton(sim_info) + if is_skeleton_result: + return is_skeleton_result + # loot_Skeleton_Add + add_loot_id = 175969 + if CommonSimLootActionUtils.apply_loot_actions_by_id_to_sim(add_loot_id, sim_info): + return CommonExecutionResult.TRUE + return CommonExecutionResult.FALSE + + @classmethod + def remove_skeleton_occult(cls, sim_info: SimInfo) -> CommonExecutionResult: + """remove_skeleton_occult(sim_info) + + Remove the Skeleton Occult Type from a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of removing the Skeleton occult. True, if the Skeleton Occult Type has been successfully removed from the specified Sim. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + is_skeleton_available_result = CommonOccultUtils.is_skeleton_occult_available() + if not is_skeleton_available_result: + return is_skeleton_available_result.reverse_result() + is_skeleton_result = CommonOccultUtils.is_skeleton(sim_info) + if not is_skeleton_result: + return is_skeleton_result.reverse_result() + # loot_Skeleton_Remove + remove_loot_id = 175975 + if CommonSimLootActionUtils.apply_loot_actions_by_id_to_sim(remove_loot_id, sim_info): + return CommonExecutionResult.TRUE + return CommonExecutionResult.FALSE + + @classmethod + def add_vampire_occult(cls, sim_info: SimInfo) -> CommonExecutionResult: + """add_vampire_occult(sim_info) + + Add the Vampire Occult Type to a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of adding the Vampire occult. True, if the Sim has successfully become a Vampire. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + is_vampire_available_result = CommonOccultUtils.is_vampire_occult_available() + if not is_vampire_available_result: + return is_vampire_available_result + is_vampire_result = CommonOccultUtils.is_vampire(sim_info) + if is_vampire_result: + return is_vampire_result + # loot_VampireCreation_NewVampire + add_loot_id = 149538 + if CommonSimLootActionUtils.apply_loot_actions_by_id_to_sim(add_loot_id, sim_info): + return CommonExecutionResult.TRUE + return CommonExecutionResult.FALSE + + @classmethod + def remove_vampire_occult(cls, sim_info: SimInfo) -> CommonExecutionResult: + """remove_vampire_occult(sim_info) + + Remove the Vampire Occult Type from a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of removing the Vampire occult. True, if the Vampire Occult Type has been successfully removed from the specified Sim. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + is_vampire_available_result = CommonOccultUtils.is_vampire_occult_available() + if not is_vampire_available_result: + return is_vampire_available_result.reverse_result() + is_vampire_result = CommonOccultUtils.is_vampire(sim_info) + if not is_vampire_result: + is_vampire_result.reverse_result() + loot_action_ids: Tuple[int, ...] = ( + # loot_VampireCure_RemoveVampirism + 150170, + # loot_Life_ResetProgress + 31238 + ) + result = CommonSimLootActionUtils.apply_loot_actions_by_ids_to_sim(loot_action_ids, sim_info) + if result: + CommonSimBucksUtils.remove_all_perks(sim_info, CommonBucksType.VAMPIRE_POWER, reason='Vampire removed', remove_perk_points=True) + CommonSimBucksUtils.remove_all_perks(sim_info, CommonBucksType.VAMPIRE_WEAKNESS, reason='Vampire removed', remove_perk_points=True) + return CommonExecutionResult.TRUE + return CommonExecutionResult.FALSE + + @classmethod + def add_witch_occult(cls, sim_info: SimInfo) -> CommonExecutionResult: + """add_witch_occult(sim_info) + + Add the Witch Occult Type to a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of adding the Witch occult. True, if the Sim has successfully become a Witch. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + is_witch_available_result = CommonOccultUtils.is_witch_occult_available() + if not is_witch_available_result: + return is_witch_available_result + is_witch_result = CommonOccultUtils.is_witch(sim_info) + if is_witch_result: + return is_witch_result + # loot_WitchOccult_AddOccult + add_loot_id = 215080 + if CommonSimLootActionUtils.apply_loot_actions_by_id_to_sim(add_loot_id, sim_info): + return CommonExecutionResult.TRUE + return CommonExecutionResult.FALSE + + @classmethod + def remove_witch_occult(cls, sim_info: SimInfo) -> CommonExecutionResult: + """remove_witch_occult(sim_info) + + Remove the Witch Occult Type from a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of removing the Witch occult. True, if the Witch Occult Type has been successfully removed from the specified Sim. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + is_witch_available_result = CommonOccultUtils.is_witch_occult_available() + if not is_witch_available_result: + is_witch_available_result.reverse_result() + is_witch_result = CommonOccultUtils.is_witch(sim_info) + if not is_witch_result: + return is_witch_result.reverse_result() + # loot_WitchOccult_RemoveOccult + remove_loot_id = 215274 + result = CommonSimLootActionUtils.apply_loot_actions_by_id_to_duo_sims(remove_loot_id, sim_info, sim_info) + if result: + CommonSimBucksUtils.remove_all_perks(sim_info, CommonBucksType.WITCH_PERK, reason='Witch removed', remove_perk_points=True) + CommonSimSpellUtils.remove_all_spells(sim_info) + return CommonExecutionResult.TRUE + return CommonExecutionResult.FALSE + + @classmethod + def add_werewolf_occult(cls, sim_info: SimInfo) -> CommonExecutionResult: + """add_werewolf_occult(sim_info) + + Add the Werewolf Occult Type to a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of adding the Werewolf occult. True, if the Sim has successfully become a Werewolf. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + is_werewolf_available_result = CommonOccultUtils.is_werewolf_occult_available() + if not is_werewolf_available_result: + return is_werewolf_available_result + is_werewolf_result = CommonOccultUtils.is_werewolf(sim_info) + if is_werewolf_result: + return is_werewolf_result + # loot_Werewolf_AddOccultTrait + add_loot_id = 290058 + if CommonSimLootActionUtils.apply_loot_actions_by_id_to_sim(add_loot_id, sim_info): + return CommonExecutionResult.TRUE + return CommonExecutionResult.FALSE + + @classmethod + def remove_werewolf_occult(cls, sim_info: SimInfo) -> CommonExecutionResult: + """remove_werewolf_occult(sim_info) + + Remove the Werewolf Occult Type from a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of removing the Werewolf occult. True, if the Werewolf Occult Type has been successfully removed from the specified Sim. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + is_werewolf_available_result = CommonOccultUtils.is_werewolf_occult_available() + if not is_werewolf_available_result: + return is_werewolf_available_result.reverse_result() + is_werewolf_result = CommonOccultUtils.is_werewolf(sim_info) + if not is_werewolf_result: + return is_werewolf_result.reverse_result() + # loot_WerewolfCreation_WerewolfCure + remove_loot_id = 291816 + result = CommonSimLootActionUtils.apply_loot_actions_by_id_to_sim(remove_loot_id, sim_info) + if result: + CommonSimBucksUtils.remove_all_perks(sim_info, CommonBucksType.WEREWOLF_ABILITY, reason='Werewolf removed', remove_perk_points=True) + return CommonExecutionResult.TRUE + return CommonExecutionResult.FALSE + + @classmethod + def add_all_occults(cls, sim_info: SimInfo) -> CommonExecutionResult: + """add_all_occults(sim_info) + + Add all Occult Types to a Sim. i.e. Make them an Alien, a Vampire, a Witch, etc. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of adding all occult types. True, if all Occult Types were successfully added to the specified Sim. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + switch_to_non_occult_form_result = CommonOccultUtils.switch_to_occult_form(sim_info, OccultType.HUMAN) + if not switch_to_non_occult_form_result: + return switch_to_non_occult_form_result + for occult_type in CommonOccultType.get_all(exclude_occult_types=(CommonOccultType.NON_OCCULT, CommonOccultType.GHOST, CommonOccultType.PLANT_SIM, CommonOccultType.ROBOT, CommonOccultType.SKELETON)): + if not CommonOccultUtils.is_occult_available(occult_type): + continue + add_result = CommonOccultUtils.add_occult(sim_info, occult_type) + if not add_result: + return add_result + return CommonExecutionResult.TRUE + + @classmethod + def remove_all_occults(cls, sim_info: SimInfo) -> CommonExecutionResult: + """remove_all_occults(sim_info) + + Remove all Occult Types from a Sim. i.e. Make them a Non-Occult only. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of removing all occult types. True, if all Occult Types were successfully removed from the specified Sim. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + switch_to_non_occult_form_result = CommonOccultUtils.switch_to_occult_form(sim_info, OccultType.HUMAN) + if not switch_to_non_occult_form_result: + return switch_to_non_occult_form_result + for occult_type in CommonOccultType.get_all(exclude_occult_types=(CommonOccultType.NON_OCCULT, CommonOccultType.GHOST, CommonOccultType.PLANT_SIM)): + if not CommonOccultUtils.is_occult_available(occult_type): + continue + remove_result = CommonOccultUtils.remove_occult(sim_info, occult_type) + if not remove_result: + return remove_result + + if CommonOccultUtils.is_occult_available(CommonOccultType.GHOST): + remove_result = CommonOccultUtils.remove_occult(sim_info, CommonOccultType.GHOST) + if not remove_result: + return remove_result + + if CommonOccultUtils.is_occult_available(CommonOccultType.PLANT_SIM): + remove_result = CommonOccultUtils.remove_occult(sim_info, CommonOccultType.PLANT_SIM) + if not remove_result: + return remove_result + return CommonExecutionResult.TRUE + + @classmethod + def switch_to_occult_form(cls, sim_info: SimInfo, occult_type: Union[OccultType, CommonOccultType]) -> CommonExecutionResult: + """switch_to_occult_form(sim_info, occult_type) + + Switch a Sim to an Occult Form. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param occult_type: The type of Occult to switch to. + :type occult_type: Union[OccultType, CommonOccultType] + :return: The result of switching a Sim to an occult form. True, if the Sim successfully switched to the specified Occult Type. False, if the Sim failed to switch to the specified Occult Type or if they do not have that Occult Type to switch to. + :rtype: CommonExecutionResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + if isinstance(occult_type, CommonOccultType): + vanilla_occult_type = CommonOccultType.convert_to_vanilla(occult_type) + if vanilla_occult_type is None: + return CommonExecutionResult(False, reason=f'Sim failed to switch to occult type {occult_type.name}') + else: + vanilla_occult_type = occult_type + # noinspection PyPropertyAccess + sim_info.occult_tracker.set_pending_occult_type(vanilla_occult_type) + sim_info.occult_tracker.switch_to_occult_type(vanilla_occult_type) + return CommonExecutionResult.TRUE + + @classmethod + def is_vampire(cls, sim_info: SimInfo) -> CommonTestResult: + """is_vampire(sim_info) + + Determine if a Sim is a Vampire. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim is a Vampire. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + is_vampire_available_result = CommonOccultUtils.is_vampire_occult_available() + if not is_vampire_available_result: + return is_vampire_available_result + return CommonTraitUtils.has_trait(sim_info, CommonTraitId.OCCULT_VAMPIRE) or CommonOccultUtils.has_occult_type(sim_info, OccultType.VAMPIRE) + + @classmethod + def is_alien(cls, sim_info: SimInfo) -> CommonTestResult: + """is_alien(sim_info) + + Determine if a Sim is an Alien. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim is an Alien. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + is_alien_available_result = CommonOccultUtils.is_alien_occult_available() + if not is_alien_available_result: + return is_alien_available_result + return CommonTraitUtils.has_trait(sim_info, CommonTraitId.OCCULT_ALIEN) or CommonOccultUtils.has_occult_type(sim_info, OccultType.ALIEN) + + @classmethod + def is_plant_sim(cls, sim_info: SimInfo) -> CommonTestResult: + """is_plant_sim(sim_info) + + Determine if a Sim is a Plant Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim is a Plant Sim. False, if not. + :rtype: CommonTestResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + is_plant_sim_available_result = CommonOccultUtils.is_plant_sim_occult_available() + if not is_plant_sim_available_result: + return is_plant_sim_available_result + return CommonTraitUtils.has_trait(sim_info, CommonTraitId.PLANT_SIM) + + @classmethod + def is_ghost(cls, sim_info: SimInfo) -> CommonTestResult: + """is_ghost(sim_info) + + Determine if a Sim is a Ghost. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim is a Ghost. False, if not. + :rtype: CommonTestResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + is_ghost_available_result = CommonOccultUtils.is_ghost_occult_available() + if not is_ghost_available_result: + return is_ghost_available_result + equipped_sim_traits = CommonTraitUtils.get_equipped_traits(sim_info) + for trait in equipped_sim_traits: + if CommonTraitUtils.is_ghost_trait(trait): + return CommonTestResult.TRUE + return CommonTestResult(False, reason=f'Sim is not a ghost.') + + @classmethod + def is_scarecrow(cls, sim_info: SimInfo) -> CommonTestResult: + """is_scarecrow(sim_info) + + Determine if a Sim is a Scarecrow. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim is a Scarecrow. False, if not. + :rtype: CommonTestResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + is_scarecrow_available_result = CommonOccultUtils.is_scarecrow_occult_available() + if not is_scarecrow_available_result: + return is_scarecrow_available_result + if CommonTraitUtils.has_trait(sim_info, CommonTraitId.SCARECROW): + return CommonTestResult(True, reason=f'{sim_info} is a Scarecrow.') + return CommonTestResult(False, reason=f'{sim_info} is not a Scarecrow.') + + @classmethod + def is_robot(cls, sim_info: SimInfo) -> CommonTestResult: + """is_robot(sim_info) + + Determine if a Sim is a Robot. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim is a Robot. False, if not. + :rtype: CommonTestResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + is_robot_available_result = CommonOccultUtils.is_robot_occult_available() + if not is_robot_available_result: + return is_robot_available_result + equipped_sim_traits = CommonTraitUtils.get_equipped_traits(sim_info) + for trait in equipped_sim_traits: + trait_type = getattr(trait, 'trait_type', -1) + if trait_type == TraitType.ROBOT: + return CommonTestResult.TRUE + return CommonTestResult(False, reason=f'Sim is not a robot.') + + @classmethod + def is_skeleton(cls, sim_info: SimInfo) -> CommonTestResult: + """is_skeleton(sim_info) + + Determine if a Sim is a Skeleton. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim is the a Skeleton. False, if not. + :rtype: CommonTestResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + is_skeleton_available_result = CommonOccultUtils.is_skeleton_occult_available() + if not is_skeleton_available_result: + return is_skeleton_available_result + equipped_sim_traits = CommonTraitUtils.get_equipped_traits(sim_info) + skeleton_trait_ids = { + CommonTraitId.HIDDEN_SKELETON, + CommonTraitId.HIDDEN_SKELETON_SERVICE_SKELETON, + CommonTraitId.HIDDEN_SKELETON_TEMPLE_SKELETON + } + for trait in equipped_sim_traits: + trait_id = CommonTraitUtils.get_trait_id(trait) + if trait_id in skeleton_trait_ids: + return CommonTestResult.TRUE + return CommonTestResult(False, reason=f'Sim is not a skeleton.') + + @classmethod + def is_werewolf(cls, sim_info: SimInfo) -> CommonTestResult: + """is_werewolf(sim_info) + + Determine if a Sim is a Werewolf + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim is a Werewolf. False, if not. + :rtype: CommonTestResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + is_werewolf_available_result = CommonOccultUtils.is_werewolf_occult_available() + if not is_werewolf_available_result: + return is_werewolf_available_result + if CommonOccultUtils._has_occult_trait(sim_info, CommonTraitId.OCCULT_WEREWOLF): + return CommonTestResult(True, reason=f'Sim had the Werewolf occult trait.') + if CommonOccultUtils.has_occult_type(sim_info, OccultType.WEREWOLF): + return CommonTestResult(True, reason=f'Sim had the Werewolf occult type.') + return CommonTestResult(False, reason=f'Sim ') + + @classmethod + def is_witch(cls, sim_info: SimInfo) -> CommonTestResult: + """is_witch(sim_info) + + Determine if a Sim is a Witch + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim is a Witch. False, if not. + :rtype: CommonTestResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + is_witch_available_result = CommonOccultUtils.is_witch_occult_available() + if not is_witch_available_result: + return is_witch_available_result + if CommonOccultUtils._has_occult_trait(sim_info, CommonTraitId.OCCULT_WITCH): + return CommonTestResult(True, reason=f'Sim had the Witch occult trait.') + if CommonOccultUtils.has_occult_type(sim_info, OccultType.WITCH): + return CommonTestResult(True, reason=f'Sim had the Witch occult type.') + return CommonTestResult(False, reason=f'Sim is not a Witch.') + + @classmethod + def is_mermaid(cls, sim_info: SimInfo) -> CommonTestResult: + """is_mermaid(sim_info) + + Determine if a Sim is a Mermaid + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim is a Mermaid. False, if not. + :rtype: CommonTestResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + is_mermaid_available_result = CommonOccultUtils.is_mermaid_occult_available() + if not is_mermaid_available_result: + return is_mermaid_available_result + if CommonOccultUtils._has_occult_trait(sim_info, CommonTraitId.OCCULT_MERMAID): + return CommonTestResult(True, reason=f'Sim had the Mermaid occult trait.') + if CommonOccultUtils.has_occult_type(sim_info, OccultType.MERMAID): + return CommonTestResult(True, reason=f'Sim had the Mermaid occult type.') + return CommonTestResult(False, reason=f'Sim is not a Witch.') + + @classmethod + def is_in_mermaid_form(cls, sim_info: SimInfo) -> CommonTestResult: + """is_in_mermaid_form(sim_info) + + Determine if a Sim is in Mermaid Form (The Sim has a visible Tail). + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim has their Mermaid tail out. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + is_mermaid_available_result = CommonOccultUtils.is_mermaid_occult_available() + if not is_mermaid_available_result: + return is_mermaid_available_result + if CommonOccultUtils.get_current_occult_type(sim_info) == OccultType.MERMAID: + return CommonTestResult(True, reason=f'Sim is currently in Mermaid Form.') + return CommonTestResult(False, reason=f'Sim is not in Mermaid Form.') + + @classmethod + def is_mermaid_in_mermaid_form(cls, sim_info: SimInfo) -> CommonTestResult: + """is_mermaid_in_mermaid_form(sim_info) + + Determine if a Sim is a Mermaid and is in Mermaid Form (Their Tail is visible). + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim is a Mermaid with their tail out. False, if not. + :rtype: CommonTestResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + is_mermaid_available_result = CommonOccultUtils.is_mermaid_occult_available() + if not is_mermaid_available_result: + return is_mermaid_available_result + is_mermaid_result = CommonOccultUtils.is_mermaid(sim_info) + if not is_mermaid_result: + return is_mermaid_result + is_in_mermaid_form_result = CommonOccultUtils.is_in_mermaid_form(sim_info) + if not is_in_mermaid_form_result: + return is_in_mermaid_form_result + return CommonTestResult.TRUE + + @classmethod + def is_currently_human(cls, sim_info: SimInfo) -> CommonExecutionResult: + """is_currently_human(sim_info) + + Determine if a Sim is currently in their Human form (regardless of their Occult type). + + .. note:: The Human Occult is not the same as the Human Species! This means that Pets can have a "Human" Occult as their Non-Occult. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim is currently a Human. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + return CommonOccultUtils.is_currently_a_non_occult(sim_info) + + @classmethod + def is_currently_a_non_occult(cls, sim_info: SimInfo) -> CommonExecutionResult: + """is_currently_a_non_occult(sim_info) + + Determine if a Sim is currently in a Non-Occult form (regardless of their Occult type). + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim is currently in their Non-Occult form. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + if not hasattr(OccultType, 'HUMAN'): + return CommonExecutionResult(False, reason='Humans do not exist. They are a myth! (At least in this persons game)') + current_occult = CommonOccultUtils.get_current_occult_type(sim_info) + if current_occult == OccultType.HUMAN: + return CommonExecutionResult(True, reason='Sim is currently a Human.') + return CommonExecutionResult(False, reason='Sim is not currently a Human.') + + @classmethod + def is_currently_a_mermaid(cls, sim_info: SimInfo) -> CommonTestResult: + """is_currently_a_mermaid(sim_info) + + Determine if a Sim is currently in a Mermaid form. (Not disguised) + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim is currently in their Mermaid form. False, if not. + :rtype: CommonTestResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + return CommonOccultUtils.is_in_mermaid_form(sim_info) + + @classmethod + def is_currently_a_robot(cls, sim_info: SimInfo) -> CommonTestResult: + """is_currently_a_robot(sim_info) + + Determine if a Sim is currently in their Robot form. + + .. note:: In base game, if a Sim is a Robot then they are automatically in their Robot Form, since Robots do not have an alternative form. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim is currently in their Robot form. False, if not. + :rtype: CommonTestResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + return CommonOccultUtils.is_robot(sim_info) + + @classmethod + def is_currently_a_scarecrow(cls, sim_info: SimInfo) -> CommonTestResult: + """is_currently_a_scarecrow(sim_info) + + Determine if a Sim is currently in their Scarecrow form. + + .. note:: In base game, if a Sim is a Scarecrow then they are automatically in their Scarecrow Form, since Scarecrows do not have an alternative form. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim is currently in their Scarecrow form. False, if not. + :rtype: CommonTestResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + return CommonOccultUtils.is_scarecrow(sim_info) + + @classmethod + def is_currently_a_skeleton(cls, sim_info: SimInfo) -> CommonTestResult: + """is_currently_a_skeleton(sim_info) + + Determine if a Sim is currently in their Skeleton form. + + .. note:: In base game, if a Sim is a Skeleton then they are automatically in their Skeleton Form, since Skeletons do not have an alternative form. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim is currently in their Skeleton form. False, if not. + :rtype: CommonTestResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + return CommonOccultUtils.is_skeleton(sim_info) + + @classmethod + def is_currently_a_plant_sim(cls, sim_info: SimInfo) -> CommonTestResult: + """is_currently_a_plant_sim(sim_info) + + Determine if a Sim is currently in their Plant Sim form. + + .. note:: In base game, if a Sim is a Plant Sim then they are automatically in their Plant Sim Form, since Plant Sims do not have an alternative form. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim is currently in their Plant Sim form. False, if not. + :rtype: CommonTestResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + return CommonOccultUtils.is_plant_sim(sim_info) + + @classmethod + def is_currently_a_ghost(cls, sim_info: SimInfo) -> CommonTestResult: + """is_currently_a_ghost(sim_info) + + Determine if a Sim is currently in their Ghost form. + + .. note:: In base game, if a Sim is a Ghost then they are automatically in their Ghost Form, since Ghosts do not have an alternative form. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim is currently in their Ghost form. False, if not. + :rtype: CommonTestResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + return CommonOccultUtils.is_ghost(sim_info) + + @classmethod + def is_currently_a_vampire(cls, sim_info: SimInfo) -> CommonTestResult: + """is_currently_a_vampire(sim_info) + + Determine if a Sim is currently in their Vampire form. (Not disguised) + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim is currently in their Vampire form. False, if not. + :rtype: CommonTestResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + is_vampire_available_result = CommonOccultUtils.is_vampire_occult_available() + if not is_vampire_available_result: + return is_vampire_available_result + if CommonOccultUtils.get_current_occult_type(sim_info) == OccultType.VAMPIRE: + return CommonTestResult(True, reason='Sim is currently a Vampire.') + return CommonTestResult(False, reason='Sim is not currently a Vampire.') + + @classmethod + def is_currently_an_alien(cls, sim_info: SimInfo) -> CommonTestResult: + """is_currently_an_alien(sim_info) + + Determine if a Sim is currently in their Alien form. (Not disguised) + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim is currently in their Alien form. False, if not. + :rtype: CommonTestResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + is_alien_available_result = CommonOccultUtils.is_alien_occult_available() + if not is_alien_available_result: + return is_alien_available_result + if CommonOccultUtils.get_current_occult_type(sim_info) == OccultType.ALIEN: + return CommonTestResult(True, reason='Sim is currently an Alien.') + return CommonTestResult(False, reason='Sim is not currently an Alien.') + + @classmethod + def is_currently_a_werewolf(cls, sim_info: SimInfo) -> CommonTestResult: + """is_currently_a_werewolf(sim_info) + + Determine if a Sim is currently in their Werewolf form. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim is currently in their Werewolf form. False, if not. + :rtype: CommonTestResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + return CommonTraitUtils.has_trait(sim_info, CommonTraitId.OCCULT_WEREWOLF_WEREFORM) + + @classmethod + def is_currently_a_witch(cls, sim_info: SimInfo) -> CommonTestResult: + """is_currently_a_witch(sim_info) + + Determine if a Sim is currently in their Witch form. (Not disguised) + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim is currently in their Witch form. False, if not. + :rtype: CommonTestResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + is_witch_available_result = CommonOccultUtils.is_witch_occult_available() + if not is_witch_available_result: + return is_witch_available_result + if CommonOccultUtils.get_current_occult_type(sim_info) == OccultType.WITCH: + return CommonTestResult(True, reason='Sim is currently a Witch.') + return CommonTestResult(False, reason='Sim is not currently a Witch.') + + @classmethod + def get_sim_info_of_all_occults_gen(cls, sim_info: SimInfo, *exclude_occult_types: OccultType) -> Iterator[SimInfo]: + """get_sim_info_of_all_occults_gen(sim_info, *exclude_occult_types) + + Retrieve a generator of SimInfo objects for all Occults of a sim. + + .. warning:: Obsolete, please use :func:`~get_sim_info_for_all_occults_gen` instead. + + :param sim_info: The Sim to locate the Occults of. + :type sim_info: SimInfo + :param exclude_occult_types: A collection of OccultTypes to exclude from the resulting SimInfo list. + :type exclude_occult_types: OccultType + :return: An iterator of Sims for all occult types of the Sim. + :rtype: Iterator[SimInfo] + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + return CommonOccultUtils.get_sim_info_for_all_occults_gen(sim_info, exclude_occult_types) + + @classmethod + def has_full_body_cas_part_assigned_to_current_occult_of(cls, sim_info: SimInfo) -> CommonTestResult: + """has_full_body_cas_part_assigned_to_occult(sim_info) + + Determine if the Sim is currently an occult that has a Full Body CAS Part associated with it. Such as a Skeleton (Skeleton Part) or Robot (Humanoid Bot Frame). + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of the test. True, if the Sim is currently an occult with a full body outfit. False, if not. + :rtype: CommonTestResult + """ + current_occult_type = CommonOccultType.determine_current_occult_type(sim_info) + return cls.occult_has_full_body_cas_part(current_occult_type) + + @classmethod + def occult_has_full_body_cas_part(cls, occult_type: CommonOccultType) -> CommonTestResult: + """occult_has_full_body_cas_part(occult_type) + + Determine an occult type has a Full Body CAS Part associated with it. Such as a Skeleton (Skeleton Part) or Robot (Humanoid Bot Frame). + + :param occult_type: The occult type to check. + :type occult_type: CommonOccultType + :return: The result of the test. True, if the occult type has a full body outfit associated with it. False, if not. + :rtype: CommonTestResult + """ + if occult_type in (CommonOccultType.ROBOT, CommonOccultType.SKELETON, CommonOccultType.SCARECROW): + return CommonTestResult.TRUE + return CommonTestResult.FALSE + + @classmethod + def _has_occult_trait(cls, sim_info: SimInfo, trait_id: Union[int, CommonTraitId]) -> bool: + return CommonOccultUtils._has_occult_traits(sim_info, (trait_id,)) + + @classmethod + def _has_occult_traits(cls, sim_info: SimInfo, trait_ids: Iterator[Union[int, CommonTraitId]]) -> bool: + if sim_info is None: + return False + equipped_traits = CommonTraitUtils.get_equipped_traits(sim_info) + for equipped_trait in equipped_traits: + trait_id = CommonTraitUtils.get_trait_id(equipped_trait) + if trait_id in trait_ids: + return True + return False + + @classmethod + def get_current_occult_type(cls, sim_info: SimInfo) -> Union[OccultType, None]: + """get_current_occult_type(sim_info) + + Retrieve the current occult type of the Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The current occult type of the Sim or None if the Sim does not have a current occult type. + :rtype: Union[OccultType, None] + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + if not hasattr(sim_info, 'current_occult_types'): + if not hasattr(sim_info, '_base') or not hasattr(sim_info._base, 'current_occult_types'): + return None + return OccultType(sim_info._base.current_occult_types) + # noinspection PyPropertyAccess + return OccultType(sim_info.current_occult_types) + + @classmethod + def is_occult_available(cls, occult_type: CommonOccultType) -> CommonTestResult: + """is_occult_available(occult_type) + + Determine if an Occult is available for us. + + .. note:: An Occult is available for use usually when it exists in a persons game, such as the WITCH occult existing only when someone has the Realm Of Magic DLC, but does not exist otherwise. + + :param occult_type: An occult type. + :type occult_type: CommonOccultType + :return: The result of testing. True, if the occult is available for use. False, if not. + :rtype: CommonTestResult + """ + if occult_type == CommonOccultType.NON_OCCULT: + return CommonTestResult(True, reason='Obviously the Non Occult "occult type" is available, what did you expect?') + occult_type_mappings = { + CommonOccultType.ALIEN: CommonOccultUtils.is_alien_occult_available, + CommonOccultType.MERMAID: CommonOccultUtils.is_mermaid_occult_available, + CommonOccultType.ROBOT: CommonOccultUtils.is_robot_occult_available, + CommonOccultType.SCARECROW: CommonOccultUtils.is_scarecrow_occult_available, + CommonOccultType.SKELETON: CommonOccultUtils.is_skeleton_occult_available, + CommonOccultType.VAMPIRE: CommonOccultUtils.is_vampire_occult_available, + CommonOccultType.WITCH: CommonOccultUtils.is_witch_occult_available, + CommonOccultType.PLANT_SIM: CommonOccultUtils.is_plant_sim_occult_available, + CommonOccultType.GHOST: CommonOccultUtils.is_ghost_occult_available, + CommonOccultType.WEREWOLF: CommonOccultUtils.is_werewolf_occult_available, + } + if occult_type not in occult_type_mappings: + return CommonTestResult(False, reason=f'Occult Type {occult_type} is not available because it is not a valid occult type.') + return occult_type_mappings[occult_type]() + + @classmethod + def is_alien_occult_available(cls) -> CommonTestResult: + """is_alien_occult_available() + + Determine if the Alien Occult is available. + + :return: The result of testing. True, if the Alien Occult is available. False, if not. + :rtype: CommonTestResult + """ + if not hasattr(OccultType, 'ALIEN'): + return CommonTestResult(False, reason='Aliens do not exist. They are a myth! (At least in this persons game, OccultType did not contain ALIEN)') + if not CommonTraitUtils.is_trait_available(CommonTraitId.OCCULT_ALIEN): + return CommonTestResult(False, reason='The Alien trait is not available.') + return CommonTestResult.TRUE + + @classmethod + def is_mermaid_occult_available(cls) -> CommonTestResult: + """is_mermaid_occult_available() + + Determine if the Mermaid Occult is available. + + :return: The result of testing. True, if the Mermaid Occult is available.. False, if not. + :rtype: CommonTestResult + """ + if not hasattr(OccultType, 'MERMAID'): + return CommonTestResult(False, reason='Mermaids do not exist. They are a myth! (At least in this persons game, OccultType did not contain MERMAID)') + if not CommonTraitUtils.is_trait_available(CommonTraitId.OCCULT_MERMAID): + return CommonTestResult(False, reason='The Mermaid trait is not available.') + return CommonTestResult.TRUE + + @classmethod + def is_robot_occult_available(cls) -> CommonTestResult: + """is_robot_occult_available() + + Determine if the Robot Occult is available. + + :return: The result of testing. True, if the Robot Occult is available.. False, if not. + :rtype: CommonTestResult + """ + if not hasattr(TraitType, 'ROBOT'): + return CommonTestResult(False, reason='Robots do not exist. They are a myth! (At least in this persons game, TraitType did not contain ROBOT)') + if not CommonTraitUtils.is_trait_available(CommonTraitId.OCCULT_ROBOT): + return CommonTestResult(False, reason='The Robot trait is not available.') + return CommonTestResult.TRUE + + @classmethod + def is_scarecrow_occult_available(cls) -> CommonTestResult: + """is_scarecrow_occult_available() + + Determine if the Scarecrow Occult is available. + + :return: The result of testing. True, if the Scarecrow Occult is available.. False, if not. + :rtype: CommonTestResult + """ + if not CommonTraitUtils.is_trait_available(CommonTraitId.SCARECROW): + return CommonTestResult(False, reason='The Scarecrow trait is not available.') + return CommonTestResult.TRUE + + @classmethod + def is_skeleton_occult_available(cls) -> CommonTestResult: + """is_skeleton_occult_available() + + Determine if the Skeleton Occult is available. + + :return: The result of testing. True, if the Skeleton Occult is available.. False, if not. + :rtype: CommonTestResult + """ + if not CommonTraitUtils.is_trait_available(CommonTraitId.HIDDEN_SKELETON): + return CommonTestResult(False, reason='The Skeleton trait is not available.') + return CommonTestResult.TRUE + + @classmethod + def is_vampire_occult_available(cls) -> CommonTestResult: + """is_vampire_occult_available() + + Determine if the Vampire Occult is available. + + :return: The result of testing. True, if the Vampire Occult is available.. False, if not. + :rtype: CommonTestResult + """ + if not hasattr(OccultType, 'VAMPIRE'): + return CommonTestResult(False, reason='Vampires do not exist. They are a myth! (At least in this persons game, OccultType did not contain VAMPIRE)') + if not CommonTraitUtils.is_trait_available(CommonTraitId.OCCULT_VAMPIRE): + return CommonTestResult(False, reason='The Vampire trait is not available.') + return CommonTestResult.TRUE + + @classmethod + def is_witch_occult_available(cls) -> CommonTestResult: + """is_witch_occult_available() + + Determine if the Witch Occult is available. + + :return: The result of testing. True, if the Witch Occult is available.. False, if not. + :rtype: CommonTestResult + """ + if not hasattr(OccultType, 'WITCH'): + return CommonTestResult(False, reason='Witches do not exist. They are a myth! (At least in this persons game, OccultType did not contain WITCH)') + if not CommonTraitUtils.is_trait_available(CommonTraitId.OCCULT_WITCH): + return CommonTestResult(False, reason='The Witch trait is not available.') + return CommonTestResult.TRUE + + @classmethod + def is_plant_sim_occult_available(cls) -> CommonTestResult: + """is_plant_sim_occult_available() + + Determine if the Plant Sim Occult is available. + + :return: The result of testing. True, if the Plant Sim Occult is available.. False, if not. + :rtype: CommonTestResult + """ + if not CommonTraitUtils.is_trait_available(CommonTraitId.PLANT_SIM): + return CommonTestResult(False, reason='The Plant Sim trait is not available.') + return CommonTestResult.TRUE + + @classmethod + def is_werewolf_occult_available(cls) -> CommonTestResult: + """is_werewolf_occult_available() + + Determine if the Werewolf Occult is available. + + :return: The result of testing. True, if the Werewolf Occult is available.. False, if not. + :rtype: CommonTestResult + """ + if not hasattr(OccultType, 'WEREWOLF'): + return CommonTestResult(False, reason='Werewolves do not exist. They are a myth! (At least in this persons game, OccultType did not contain WEREWOLF)') + if not CommonTraitUtils.is_trait_available(CommonTraitId.OCCULT_WEREWOLF): + return CommonTestResult(False, reason='The Werewolf trait is not available.') + return CommonTestResult.TRUE + + @classmethod + def is_ghost_occult_available(cls) -> CommonTestResult: + """is_ghost_occult_available() + + Determine if the Ghost Occult is available. + + :return: The result of testing. True, if the Ghost Occult is available.. False, if not. + :rtype: CommonTestResult + """ + if not hasattr(TraitType, 'GHOST'): + return CommonTestResult(False, reason='Ghosts do not exist. They are a myth! (At least in this persons game, TraitType did not contain GHOST)') + ghost_traits = ( + CommonTraitId.GHOST_ANGER, + CommonTraitId.GHOST_ANIMAL_OBJECTS_KILLER_CHICKEN, + CommonTraitId.GHOST_ANIMAL_OBJECTS_KILLER_RABBIT, + CommonTraitId.GHOST_BEETLE, + CommonTraitId.GHOST_CAULDRON_POTION_IMMORTALITY_FAILURE, + CommonTraitId.GHOST_CLIMBING_ROUTE, + CommonTraitId.GHOST_COW_PLANT, + CommonTraitId.GHOST_CURSES_NIGHT_STALKER_STALKER, + CommonTraitId.GHOST_DEATH_FLOWER, + CommonTraitId.GHOST_DROWN, + CommonTraitId.GHOST_ELDER_EXHAUSTION, + CommonTraitId.GHOST_ELECTROCUTION, + CommonTraitId.GHOST_EMBARRASSMENT, + CommonTraitId.GHOST_FIRE, + CommonTraitId.GHOST_FLIES, + CommonTraitId.GHOST_FROZEN, + CommonTraitId.GHOST_HUNGER, + CommonTraitId.GHOST_LAUGHTER, + CommonTraitId.GHOST_LIGHTNING, + CommonTraitId.GHOST_MOTHER_PLANT, + CommonTraitId.GHOST_MURPHY_BED, + CommonTraitId.GHOST_OLD_AGE, + CommonTraitId.GHOST_OVERHEAT, + CommonTraitId.GHOST_POISON, + CommonTraitId.GHOST_PUFFER_FISH, + CommonTraitId.GHOST_RISEN, + CommonTraitId.GHOST_RODENT_DISEASE, + CommonTraitId.GHOST_SEANCE_TABLE, + CommonTraitId.GHOST_STEAM, + CommonTraitId.GHOST_VAMPIRE_SUN, + CommonTraitId.GHOST_VENDING_MACHINE, + CommonTraitId.GHOST_WITCH_OVERLOAD + ) + for ghost_trait in ghost_traits: + if CommonTraitUtils.is_trait_available(ghost_trait): + return CommonTestResult.TRUE + return CommonTestResult(False, reason='No Ghost traits were available.') + + @classmethod + def _get_occult_types(cls, sim_info: SimInfo) -> OccultType: + if not hasattr(sim_info, 'occult_types'): + if not hasattr(sim_info, '_base') or not hasattr(sim_info._base, 'occult_types'): + return CommonOccultUtils.get_current_occult_type(sim_info) or OccultType.HUMAN + return sim_info._base.occult_types + # noinspection PyPropertyAccess + return sim_info.occult_types + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.switch_sim_to_occult', + 'Switch a Sim to an Occult form (If they have it)', + command_arguments=( + CommonConsoleCommandArgument('occult_type', 'CommonOccultType', f'The name of an Occult Type to switch the form of the Sim to. Valid Values: {CommonOccultType.get_comma_separated_names_string()}'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance Id or name of the Sim that will switch forms.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.switchsimtooccult', + 's4clib.switchoccult', + 's4clib.switch_occult', + 's4clib.switch_occult_type', + 's4clib.switchocculttype' + ) +) +def _common_switch_sim_to_occult(output: CommonConsoleCommandOutput, occult_type: CommonOccultType, sim_info: SimInfo = None): + if sim_info is None: + return + if occult_type is None: + return + occult_type_name = occult_type.name + output(f'Attempting to switch Sim {sim_info} to their {occult_type_name} form.') + result = CommonOccultUtils.switch_to_occult_form(sim_info, occult_type) + if result: + output(f'SUCCESS: Successfully switched Sim {sim_info} to their {occult_type_name} form: {result}') + else: + output(f'FAILED: Failed to switch Sim {sim_info} to their {occult_type_name} form: {result}') + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.add_all_occults_to_sim', + f'Add all Occult Types to a Sim. They will have all available Occult types added to them: {CommonOccultType.get_comma_separated_names_string(exclude_occult_types=(CommonOccultType.NON_OCCULT, CommonOccultType.GHOST, CommonOccultType.PLANT_SIM))}', + command_arguments=( + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance Id or name of the Sim to add the occults to.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.addalloccultstosim', + 's4clib.add_all_occults', + 's4clib.addalloccults', + 's4clib.add_all_occults_type', + 's4clib.addalloccultstype', + ) +) +def _common_add_all_occults_to_sim(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): + if sim_info is None: + return + output(f'Attempting to add all occults to Sim {sim_info}') + result = CommonOccultUtils.add_all_occults(sim_info) + if result: + output(f'SUCCESS: Successfully added all occults to Sim {sim_info}: {result}') + else: + output(f'FAILED: Failed to add all occults to Sim {sim_info}: {result}') + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.remove_all_occults_from_sim', + f'Remove all Occult Types from a Sim. They will have all available Occult Types removed from them: {CommonOccultType.get_comma_separated_names_string(exclude_occult_types=(CommonOccultType.NON_OCCULT, CommonOccultType.GHOST, CommonOccultType.PLANT_SIM))}', + command_arguments=( + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance Id or name of the Sim to remove the occults from.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.removealloccultsfromsim', + 's4clib.remove_all_occults', + 's4clib.removealloccults', + 's4clib.remove_all_occults_type', + 's4clib.removealloccultstype', + ) +) +def _common_remove_all_occults_from_sim(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): + if sim_info is None: + return + output(f'Attempting to remove all occults from Sim {sim_info}') + result = CommonOccultUtils.remove_all_occults(sim_info) + if result: + output(f'SUCCESS: Successfully removeed all occults from Sim {sim_info}: {result}') + else: + output(f'FAILED: Failed to remove all occults from Sim {sim_info}: {result}') + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.add_occult_to_sim', + 'Add an Occult Type to a Sim.', + command_arguments=( + CommonConsoleCommandArgument('occult_type', 'CommonOccultType', f'The name of an Occult Type to add to the Sim. Valid Values: {CommonOccultType.get_comma_separated_names_string(exclude_occult_types=(CommonOccultType.NON_OCCULT, CommonOccultType.GHOST))}'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance Id or name of the Sim to add the occult to.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.addocculttosim', + 's4clib.add_occult', + 's4clib.addoccult', + 's4clib.add_occult_type', + 's4clib.addocculttype', + ) +) +def _common_add_occult_to_sim(output: CommonConsoleCommandOutput, occult_type: CommonOccultType, sim_info: SimInfo = None): + if sim_info is None: + return + if occult_type is None: + return + occult_type_name = occult_type.name + output(f'Attempting to add occult {occult_type_name} to Sim {sim_info}') + result = CommonOccultUtils.add_occult(sim_info, occult_type) + if result: + output(f'SUCCESS: Successfully added occult {occult_type_name} to Sim {sim_info}: {result}') + else: + output(f'FAILED: Failed to add occult {occult_type_name} to Sim {sim_info}: {result}') + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.remove_occult_from_sim', + 'Remove an Occult Type from a Sim.', + command_arguments=( + CommonConsoleCommandArgument('occult_type', 'CommonOccultType', f'The name of an Occult Type to remove from the Sim. Valid Values: {CommonOccultType.get_comma_separated_names_string(exclude_occult_types=(CommonOccultType.NON_OCCULT, CommonOccultType.GHOST))}'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance Id or name of the Sim to remove the occult from.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.removeoccultfromsim', + 's4clib.remove_occult', + 's4clib.removeoccult', + 's4clib.remove_occult_type', + 's4clib.removeocculttype', + ) +) +def _common_remove_occult_from_sim(output: CommonConsoleCommandOutput, occult_type: CommonOccultType, sim_info: SimInfo = None): + if sim_info is None: + return + if occult_type is None: + return + occult_type_name = occult_type.name + output(f'Attempting to remove occult {occult_type_name} from Sim {sim_info}') + result = CommonOccultUtils.remove_occult(sim_info, occult_type) + if result: + output(f'SUCCESS: Successfully removed occult {occult_type_name} from Sim {sim_info}: {result}') + else: + output(f'FAILED: Failed to remove occult {occult_type_name} from Sim {sim_info}: {result}') + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.remove_all_occults_from_sim', + 'Remove all Occult Types from a Sim.', + command_arguments=( + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance Id or name of the Sim to remove the occult types from.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.removealloccultsfromsim', + 's4clib.remove_all_occults', + 's4clib.removealloccults', + 's4clib.remove_all_occult_types', + 's4clib.removeallocculttypes', + ) +) +def _common_remove_all_occults_from_sim(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): + if sim_info is None: + return + output(f'Attempting to remove all occult types from Sim {sim_info}.') + result = CommonOccultUtils.remove_all_occults(sim_info) + if result: + output(f'SUCCESS: Successfully removed all occult types from Sim {sim_info}: {result}') + else: + output(f'FAILED: Failed to remove all occult types from Sim {sim_info}: {result}') + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_dev.print_vanilla_occults', + 'Print a list of all vanilla OccultType values a Sim has.', + command_arguments=( + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance Id or name of the Sim to print the occult types of.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib_dev.printvanillaoccults', + ), + show_with_help_command=False +) +def _s4clib_testing_print_vanilla_occult_types_for_sim(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): + if sim_info is None: + return + occult_types_str = ', '.join([occult_type.name if hasattr(occult_type, 'name') else str(occult_type) for occult_type in CommonOccultUtils._get_occult_types(sim_info)]) + output(f'Occult Types: {occult_types_str}') + current_occult_types_str = ', '.join([occult_type.name if hasattr(occult_type, 'name') else str(occult_type) for occult_type in CommonOccultUtils.get_current_occult_type(sim_info)]) + output(f'Current Occult Types: {current_occult_types_str}') + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_testing.print_occult_sim_infos', + 'Print information about the Occult Sim Infos of a Sim for each occult type they have.', + command_arguments=( + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance Id or name of the Sim to check.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib_testing.printoccultsiminfos', + ) +) +def _common_print_occult_sim_infos(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): + if sim_info is None: + return + output(f'Attempting to print Occult Information for Sim {sim_info}') + for occult_type in OccultType.values: + occult_type_name = occult_type.name + occult_sim_info = CommonOccultUtils.get_occult_sim_info(sim_info, occult_type) + if occult_sim_info is None: + output(f'Occult Sim Info[{occult_type_name}]: None') + continue + occult_sim_id = CommonSimUtils.get_sim_id(occult_sim_info) + obj_type_acronym = 'UnknownType' + if CommonTypeUtils.is_sim_info(occult_sim_info): + obj_type_acronym = 'SI' + elif CommonTypeUtils.is_sim_instance(occult_sim_info): + obj_type_acronym = 'S' + elif CommonTypeUtils.is_sim_info_base_wrapper(occult_sim_info): + obj_type_acronym = 'SIBW' + from sims4communitylib.utils.sims.common_sim_type_utils import CommonSimTypeUtils + sim_types = tuple(CommonSimTypeUtils.get_all_sim_types_gen(occult_sim_info, combine_teen_young_adult_and_elder_age=False, combine_child_dog_types=False)) + sim_types_str = ', '.join([sim_type.name for sim_type in sim_types]) + current_sim_type = CommonSimTypeUtils.determine_sim_type(occult_sim_info, combine_teen_young_adult_and_elder_age=False, combine_child_dog_types=False, use_current_occult_type=True) + current_sim_type_name = current_sim_type.name + output(f'Occult Sim Info [{occult_type_name}]: {occult_sim_info} ({occult_sim_id}, ({sim_types_str}), C:{current_sim_type_name}) [{obj_type_acronym}]') diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_phone_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_phone_utils.py new file mode 100644 index 0000000..980084c --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_phone_utils.py @@ -0,0 +1,77 @@ +""" +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 +""" +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.location.common_location_utils import CommonLocationUtils + + +class CommonPhoneUtils: + """ Utilities for manipulating the Phone. """ + @staticmethod + def silence_phone() -> None: + """silence_phone() + + Silence the phone. + """ + CommonPhoneUtils._set_phone_is_silenced(True) + + @staticmethod + def unsilence_phone() -> None: + """unsilence_phone() + + Unsilence the phone. + """ + CommonPhoneUtils._set_phone_is_silenced(False) + + @staticmethod + def phone_is_silenced() -> bool: + """phone_is_silenced() + + Determine if the phone is silenced. + + :return: True, if the Phone is silenced. False, if not. + :rtype: bool + """ + # noinspection PyUnresolvedReferences + return CommonLocationUtils.get_current_zone().ui_dialog_service.is_phone_silenced + + @staticmethod + def _set_phone_is_silenced(is_silenced: bool): + # noinspection PyUnresolvedReferences + CommonLocationUtils.get_current_zone().ui_dialog_service._set_is_phone_silenced(is_silenced) + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.silence_phone', + 'Turn on the silent mode for the phone.', + command_aliases=( + 's4clib.silencephone', + ) +) +def _common_silence_phone(output: CommonConsoleCommandOutput): + output('Silencing Phone') + CommonPhoneUtils.silence_phone() + output('Done') + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.unsilence_phone', + 'Turn off the silent mode for the phone.', + command_aliases=( + 's4clib.unsilencephone', + ) +) +def _common_unsilence_phone(output: CommonConsoleCommandOutput): + output('Unsilencing Phone') + CommonPhoneUtils.unsilence_phone() + output('Done') diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_rabbit_hole_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_rabbit_hole_utils.py new file mode 100644 index 0000000..d3dec8d --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_rabbit_hole_utils.py @@ -0,0 +1,61 @@ +""" +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 +""" +from typing import Union + +import services +from rabbit_hole.rabbit_hole import RabbitHole +from services.rabbit_hole_service import RabbitHoleService + + +class CommonRabbitHoleUtils: + """Utilities for manipulating rabbit holes.""" + + @classmethod + def get_rabbit_hole_service(cls) -> RabbitHoleService: + """get_rabbit_hole_service() + + Retrieve an instance of the Rabbit Hole Service. + + :return: The service that manages rabbit holes. + :rtype: RabbitHoleService + """ + return services.get_rabbit_hole_service() + + @classmethod + def load_rabbit_hole_by_id(cls, rabbit_hole: Union[int, RabbitHole]) -> Union[RabbitHole, None]: + """load_rabbit_hole_by_id(rabbit_hole) + + Load an instance of a Rabbit Hole by its identifier. + + :param rabbit_hole: The identifier of a Rabbit Hole. + :type rabbit_hole: Union[int, RabbitHole] + :return: An instance of a Rabbit Hole matching the decimal identifier or None if not found. + :rtype: Union[RabbitHole, None] + """ + if isinstance(rabbit_hole, RabbitHole): + return rabbit_hole + # noinspection PyBroadException + try: + # noinspection PyCallingNonCallable + rabbit_hole_instance = rabbit_hole() + if isinstance(rabbit_hole_instance, RabbitHole): + # noinspection PyTypeChecker + return rabbit_hole + except: + pass + # noinspection PyBroadException + try: + rabbit_hole: int = int(rabbit_hole) + except: + # noinspection PyTypeChecker + rabbit_hole: RabbitHole = rabbit_hole + return rabbit_hole + + from sims4.resources import Types + from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + return CommonResourceUtils.load_instance(Types.RABBIT_HOLE, rabbit_hole) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_relationship_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_relationship_utils.py new file mode 100644 index 0000000..05fe72f --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_relationship_utils.py @@ -0,0 +1,1128 @@ +""" +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 +""" +from typing import Iterator, Union, Tuple + +from relationships.relationship_objects.relationship import Relationship +from relationships.relationship_bit import RelationshipBit +from relationships.relationship_track import RelationshipTrack +from server_commands.argument_helpers import TunableInstanceParam +from sims.sim_info import SimInfo +from sims4.resources import Types +from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.enums.relationship_bits_enum import CommonRelationshipBitId +from sims4communitylib.enums.relationship_tracks_enum import CommonRelationshipTrackId +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + CommonConsoleCommandArgument +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.common_log_registry import CommonLogRegistry +from sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils + + +class CommonRelationshipUtils: + """Utilities for manipulating relationship bits, tracks, etc. + + """ + @classmethod + def has_met(cls, sim_info: SimInfo, target_sim_info: SimInfo) -> bool: + """has_met(sim_info, target_sim_info) + + Determine if a Sim has met the Target Sim. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :param target_sim_info: The Target Sim to check. + :type target_sim_info: SimInfo + :return: True, if both Sims have met each other. False, if not. + :rtype: bool + """ + return cls.has_relationship_bit_with_sim(sim_info, target_sim_info, CommonRelationshipBitId.HAS_MET) + + @classmethod + def are_blood_relatives(cls, sim_info_a: SimInfo, sim_info_b: SimInfo) -> bool: + """are_blood_relatives(sim_info_a, sim_info_b) + + Determine if two Sims are blood relatives. + + :param sim_info_a: An instance of a Sim. + :type sim_info_a: SimInfo + :param sim_info_b: An instance of a Sim. + :type sim_info_b: SimInfo + :return: True, if Sim A is blood relative of Sim B. False, if not. + :rtype: bool + """ + if sim_info_a is None or sim_info_b is None: + return False + return not sim_info_a.incest_prevention_test(sim_info_b) + + @classmethod + def is_romantically_committed_to_any_sims(cls, sim_info: SimInfo) -> bool: + """is_romantically_committed_to_any_sims(sim_info) + + Determine if the Sim is romantically committed to any Sims. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is romantically committed to any Sims. False, if not. + :rtype: bool + """ + return any(cls.get_sim_info_of_all_sims_romantically_committed_to_generator(sim_info)) + + @classmethod + def is_friendly_with(cls, sim_info: SimInfo, target_sim_info: SimInfo) -> bool: + """is_friendly_with(sim_info, target_sim_info) + + Determine if a Sim is friendly with a Target Sim. + + .. note:: By default, a Sim is friendly with another Sim when their Friendship relationship is at or above 30. If both Sims are Animals, they are friendly with each other if they have the Friendly relationship bit. + + :param sim_info: The info of a Sim. + :type sim_info: SimInfo + :param target_sim_info: The info of a Sim. + :type target_sim_info: SimInfo + :return: True, if the Sim is friendly with the Target Sim. False, if not. + :rtype: bool + """ + if CommonSpeciesUtils.is_animal(sim_info) and CommonSpeciesUtils.is_animal(target_sim_info): + return cls.has_relationship_bit_with_sim(sim_info, target_sim_info, CommonRelationshipBitId.PET_TO_PET_FRIENDLY)\ + or cls.has_relationship_bit_with_sim(target_sim_info, sim_info, CommonRelationshipBitId.PET_TO_PET_FRIENDLY) + return cls.get_friendship_level(sim_info, target_sim_info) >= 30 + + @classmethod + def is_romantic_with(cls, sim_info: SimInfo, target_sim_info: SimInfo) -> bool: + """is_romantic_with(sim_info, target_sim_info) + + Determine if a Sim is romantic with a Target Sim. + + .. note:: By default, a Sim is romantic with another Sim when their Romance relationship is at or above 30. + + :param sim_info: The info of a Sim. + :type sim_info: SimInfo + :param target_sim_info: The info of a Sim. + :type target_sim_info: SimInfo + :return: True, if the Sim is romantic with the Target Sim. False, if not. + :rtype: bool + """ + return cls.get_romance_level(sim_info, target_sim_info) >= 30 + + @classmethod + def get_romantically_committed_relationship_bits(cls) -> Tuple[CommonRelationshipBitId]: + """get_romantically_committed_relationship_bits() + + Retrieve a collection of relationship bits that signify two Sims are in a committed relationship. + + :return: A collection of relationship bits. + :rtype: Tuple[CommonRelationshipBitId] + """ + result: Tuple[CommonRelationshipBitId, ...] = ( + CommonRelationshipBitId.ROMANTIC_ENGAGED, + CommonRelationshipBitId.ROMANTIC_GETTING_MARRIED, + CommonRelationshipBitId.ROMANTIC_MARRIED, + CommonRelationshipBitId.ROMANTIC_PROMISED, + CommonRelationshipBitId.ROMANTIC_SIGNIFICANT_OTHER, + CommonRelationshipBitId.SEXUAL_ORIENTATION_WOOHOO_PARTNERS + ) + return result + + @classmethod + def is_romantically_committed_to(cls, sim_info: SimInfo, target_sim_info: SimInfo) -> bool: + """is_romantically_committed_to(sim_info, target_sim_info) + + Determine if a Sim is romantically committed to the Target Sim. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :param target_sim_info: The Target Sim to check. + :type target_sim_info: SimInfo + :return: True, if the Sim is romantically committed to the Target Sim. False, if not. + :rtype: bool + """ + return target_sim_info in cls.get_sim_info_of_all_sims_romantically_committed_to_generator(sim_info) + + @classmethod + def get_friendship_level(cls, sim_info: SimInfo, target_sim_info: SimInfo) -> float: + """get_friendship_level(sim_info, target_sim_info) + + Retrieve the level of Friendship between two Sims. + + .. note:: The return will be "0.0" if a friendship relationship track is not found. + + :param sim_info: The Sim to use. + :type sim_info: SimInfo + :param target_sim_info: The Target Sim to use. + :type target_sim_info: SimInfo + :return: The current level of friendship between two Sims. + :rtype: float + """ + track_id = cls.get_friendship_relationship_track(sim_info, target_sim_info) + if track_id is None: + return 0.0 + return cls.get_relationship_level_of_sims(sim_info, target_sim_info, track_id) + + @classmethod + def set_friendship_level(cls, sim_info: SimInfo, target_sim_info: SimInfo, level: float): + """set_friendship_level(sim_info, target_sim_info, level) + + Set the level of Friendship between two Sims. + + :param sim_info: The Sim to use. + :type sim_info: SimInfo + :param target_sim_info: The Target Sim to use. + :type target_sim_info: SimInfo + :param level: The new level of relationship between the Sims. + :type level: float + """ + track_id = cls.get_friendship_relationship_track(sim_info, target_sim_info) + if track_id is None: + return + cls.set_relationship_level_of_sims(sim_info, target_sim_info, track_id, level) + + @classmethod + def get_romance_level(cls, sim_info: SimInfo, target_sim_info: SimInfo) -> float: + """get_romance_level(sim_info, target_sim_info) + + Retrieve the level of Romance between two Sims. + + .. note:: The return will be "0.0" if a romance relationship track is not found. + + :param sim_info: The Sim to use. + :type sim_info: SimInfo + :param target_sim_info: The Target Sim to use. + :type target_sim_info: SimInfo + :return: The current level of romance between two Sims. + :rtype: float + """ + track_id = cls.get_romance_relationship_track(sim_info, target_sim_info) + if track_id is None: + return 0.0 + return cls.get_relationship_level_of_sims(sim_info, target_sim_info, track_id) + + @classmethod + def set_romance_level(cls, sim_info: SimInfo, target_sim_info: SimInfo, level: float): + """set_romance_level(sim_info, target_sim_info, level) + + Set the level of Romance between two Sims. + + :param sim_info: The Sim to use. + :type sim_info: SimInfo + :param target_sim_info: The Target Sim to use. + :type target_sim_info: SimInfo + :param level: The new level of relationship between the Sims. + :type level: float + """ + track_id = cls.get_romance_relationship_track(sim_info, target_sim_info) + if track_id is None: + return + cls.set_relationship_level_of_sims(sim_info, target_sim_info, track_id, level) + + @classmethod + def calculate_average_relationship_level(cls, sim_info: SimInfo, target_sim_info: SimInfo) -> float: + """calculate_average_relationship_level(sim_info, target_sim_info) + + Calculate an average level for Friendship and Romance between two Sims. + + .. note:: Math: (Friendship Level + Romance Level)/2 + + .. note:: + + Example Levels: + Friendship Level: 10 + Romance Level: 20 + Average: 15 + + :param sim_info: The Sim to use. + :type sim_info: SimInfo + :param target_sim_info: The Target Sim to use. + :type target_sim_info: SimInfo + :return: The average level of friendship and romance between two Sims. + :rtype: float + """ + return (cls.get_friendship_level(sim_info, target_sim_info) + cls.get_romance_level(sim_info, target_sim_info)) / 2 + + @classmethod + def has_permission_for_romantic_relationships(cls, sim_info: SimInfo) -> CommonTestResult: + """has_permission_for_romantic_relationships(sim_info) + + Determine if a Sim has permission to have romantic relationships with other Sims. + + .. note:: In the vanilla game, only Teen, Adult, and Elder Sims have permission for romantic relationships. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of the test. True, if the test passes. False, if the test fails. + :rtype: CommonTestResult + """ + if not CommonAgeUtils.is_teen_adult_or_elder(sim_info): + return CommonTestResult(False, reason=f'{sim_info} does not have permission for romantic relationships. They are neither a Teen, Adult, nor Elder Sim.') + return CommonTestResult(True, reason=f'{sim_info} has permission for romantic relationships.') + + @classmethod + def has_permission_for_romantic_relationship_with(cls, sim_info_a: SimInfo, sim_info_b: SimInfo) -> CommonTestResult: + """Determine if two Sims are allowed to have a Romantic relationship together.""" + sim_a_permission_result = cls.has_permission_for_romantic_relationships(sim_info_a) + if not sim_a_permission_result: + return CommonTestResult(False, reason=f'{sim_info_a} does not have permission for a romantic relationship with {sim_info_b}. {sim_a_permission_result}') + sim_b_permission_result = cls.has_permission_for_romantic_relationships(sim_info_b) + if not sim_b_permission_result: + return CommonTestResult(False, reason=f'{sim_info_a} does not have permission for a romantic relationship with {sim_info_b}. {sim_b_permission_result}') + if cls.are_blood_relatives(sim_info_a, sim_info_b): + return CommonTestResult(False, reason=f'{sim_info_a} does not have permission for a romantic relationship with {sim_info_b}. {sim_info_a} is a blood relative of {sim_info_b}.') + if not CommonSpeciesUtils.are_same_species(sim_info_a, sim_info_b): + return CommonTestResult(False, reason=f'{sim_info_a} does not have permission for a romantic relationship with {sim_info_b}. {sim_info_a} and {sim_info_b} are not the same species.') + if CommonAgeUtils.is_teen(sim_info_a) and CommonAgeUtils.is_teen(sim_info_b): + return CommonTestResult(True, reason=f'{sim_info_a} has permission for a romantic relationship with {sim_info_b}.') + if CommonAgeUtils.is_teen(sim_info_a): + if not CommonAgeUtils.is_teen(sim_info_b): + return CommonTestResult(False, reason=f'{sim_info_a} does not have permission for a romantic relationship with {sim_info_b}. {sim_info_a} is a Teen Sim and {sim_info_b} is an Adult or Elder Sim.') + elif CommonAgeUtils.is_teen(sim_info_b): + return CommonTestResult(False, reason=f'{sim_info_a} does not have permission for a romantic relationship with {sim_info_b}. {sim_info_a} is an Adult or Elder Sim and {sim_info_b} is a Teen Sim.') + return CommonTestResult(True, reason=f'{sim_info_a} has permission for a romantic relationship with {sim_info_b}.') + + @classmethod + def has_permission_to_be_blood_relative_of(cls, sim_info_a: SimInfo, sim_info_b: SimInfo) -> CommonTestResult: + """has_permission_to_be_blood_relative_of(sim_info_a, sim_info_b) + + Determine if Sim A has permission to be a Blood Relative of Sim B. (Such as Mother, Daughter, etc.) + + .. note:: In the vanilla game, only Sims of the same species have permission to be Blood Relatives. + + :param sim_info_a: An instance of a Sim. + :type sim_info_a: SimInfo + :param sim_info_b: An instance of a Sim. + :type sim_info_b: SimInfo + :return: The result of the test. True, if the test passes. False, if the test fails. + :rtype: CommonTestResult + """ + if not CommonSpeciesUtils.are_same_species(sim_info_a, sim_info_b): + return CommonTestResult(False, reason=f'{sim_info_a} does not have permission to be a Blood Relative of {sim_info_b}. {sim_info_a} and {sim_info_b} are not the same species.') + return CommonTestResult(True, reason=f'{sim_info_a} has permission to be a Blood Relative of {sim_info_b}.') + + @classmethod + def has_relationship_bit_with_any_sims( + cls, + sim_info: SimInfo, + relationship_bit_id: Union[int, CommonRelationshipBitId], + instanced_only: bool = True + ) -> bool: + """has_relationship_bit_with_any_sims(sim_info, relationship_bit_id, instance_only=True) + + Determine if a Sim has the specified relationship bit with any Sims. + + :param sim_info: The Sim to use. + :type sim_info: SimInfo + :param relationship_bit_id: The identifier of the Relationship Bit to check for. + :type relationship_bit_id: Union[int, CommonRelationshipBitId] + :param instanced_only: If True, only Sims that are currently loaded will be valid. + :type instanced_only: bool, optional + :return: True, if the Sim has the specified Relationship Bit with any Sims. False, if not. + :rtype: bool + """ + return any(cls.get_sim_info_of_all_sims_with_relationship_bit_generator(sim_info, relationship_bit_id, instanced_only=instanced_only)) + + @classmethod + def has_relationship_bits_with_any_sims( + cls, + sim_info: SimInfo, + relationship_bit_ids: Iterator[int], + instanced_only: bool = True + ) -> bool: + """has_relationship_bits_with_any_sims(sim_info, relationship_bit_ids, instanced_only=True) + + Determine if a Sim has the specified relationship bits with any Sims. + + :param sim_info: The Sim to use. + :type sim_info: SimInfo + :param relationship_bit_ids: A collection of identifier of Relationship Bits to check for. + :type relationship_bit_ids: int + :param instanced_only: If True, only Sims that are currently loaded will be valid. + :type instanced_only: bool, optional + :return: True, if the Sim has any of the specified Relationship Bits with any Sims. False, if not. + :rtype: bool + """ + return any(cls.get_sim_info_of_all_sims_with_relationship_bits_generator(sim_info, relationship_bit_ids, instanced_only=instanced_only)) + + @classmethod + def has_relationship_bit_with_sim( + cls, + sim_info: SimInfo, + target_sim_info: SimInfo, + relationship_bit_id: Union[int, CommonRelationshipBitId], + ) -> bool: + """has_relationship_bit_with_sim(sim_info, target_sim_info, relationship_bit_id) + + Determine if two Sims have the specified relationship bit with each other. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :param target_sim_info: The Target Sim of the relationship bit (The target is especially important for Unidirectional/One Way Relationship Bits). + :type target_sim_info: SimInfo + :param relationship_bit_id: The identifier of the Relationship Bit to check for. + :type relationship_bit_id: Union[int, CommonRelationshipBitId] + :return: True, if the Sim has the specified Relationship Bit with the Target Sim. False, if not. + :rtype: bool + """ + return cls.has_relationship_bits_with_sim(sim_info, target_sim_info, (relationship_bit_id,)) + + @classmethod + def has_relationship_bits_with_sim( + cls, + sim_info: SimInfo, + target_sim_info: SimInfo, + relationship_bit_ids: Iterator[Union[int, CommonRelationshipBitId]], + ) -> bool: + """has_relationship_bits_with_sim(sim_info, target_sim_info, relationship_bit_ids) + + Determine if two sims have any of the specified relationship bits with each other. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :param target_sim_info: The Target Sim of the relationship bit (The target is especially important for Unidirectional/One Way Relationship Bits). + :type target_sim_info: SimInfo + :param relationship_bit_ids: A collection of identifier of Relationship Bits to check for. + :type relationship_bit_ids: Iterator[Union[int, CommonRelationshipBitId]] + :return: True, if the Sim has any of the specified Relationship Bits with the Target Sim. False, if not. + :rtype: bool + """ + target_sim_id = CommonSimUtils.get_sim_id(target_sim_info) + relationship_bits = sim_info.relationship_tracker.get_all_bits(target_sim_id) + for relationship_bit in relationship_bits: + relationship_bit_id = getattr(relationship_bit, 'guid64', None) + if relationship_bit_id in relationship_bit_ids: + return True + return False + + @classmethod + def get_relationship_level_of_sims( + cls, + sim_info: SimInfo, + target_sim_info: SimInfo, + relationship_track_id: Union[int, CommonRelationshipTrackId] + ) -> float: + """get_relationship_level_of_sims(sim_info, target_sim_info, relationship_track_id) + + Retrieve the level of a relationship track between two sims. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :param target_sim_info: The Target Sim of the relationship track. + :type target_sim_info: SimInfo + :param relationship_track_id: An identifier for a Relationship Track to retrieve. + :type relationship_track_id: Union[int, CommonRelationshipTrackId] + :return: The current level between two Sims for the specified Relationship Track. + :rtype: float + """ + relationship_track = cls.load_relationship_track_by_id(relationship_track_id) + if relationship_track is None: + return 0.0 + target_sim_id = CommonSimUtils.get_sim_id(target_sim_info) + return sim_info.relationship_tracker.get_relationship_score(target_sim_id, relationship_track) + + @classmethod + def change_relationship_level_of_sims( + cls, + sim_info: SimInfo, + target_sim_info: SimInfo, + relationship_track_id: Union[int, CommonRelationshipTrackId], + level: float + ) -> bool: + """change_relationship_level_of_sims(sim_info, target_sim_info, relationship_track_id, level) + + Change the level of a relationship track between two Sims. + + :param sim_info: The sim that owns the relationship track. + :type sim_info: SimInfo + :param target_sim_info: The target of the relationship track. + :type target_sim_info: SimInfo + :param relationship_track_id: The identifier of the Relationship Track to change. + :type relationship_track_id: : Union[int, CommonRelationshipTrackId] + :param level: The amount to add to the relationship track (Can be positive or negative). + :type level: float + :return: True, if the relationship track was changed successfully. False, if not. + :rtype: bool + """ + relationship_track = cls.load_relationship_track_by_id(relationship_track_id) + if relationship_track is None: + return False + target_sim_id = CommonSimUtils.get_sim_id(target_sim_info) + sim_info.relationship_tracker.add_relationship_score(target_sim_id, level, relationship_track) + return True + + @classmethod + def set_relationship_level_of_sims( + cls, + sim_info: SimInfo, + target_sim_info: SimInfo, + relationship_track_id: Union[int, CommonRelationshipTrackId], + level: float + ) -> bool: + """set_relationship_level_of_sims(sim_info, target_sim_info, relationship_track_id, level) + + Set the level of a relationship track between two Sims. + + :param sim_info: The sim that owns the relationship track. + :type sim_info: SimInfo + :param target_sim_info: The target of the relationship track. + :type target_sim_info: SimInfo + :param relationship_track_id: The identifier of the Relationship Track to set. + :type relationship_track_id: : Union[int, CommonRelationshipTrackId] + :param level: The amount to set the relationship track to (Can be positive or negative). + :type level: float + :return: True, if the relationship track was set successfully. False, if not. + :rtype: bool + """ + relationship_track = cls.load_relationship_track_by_id(relationship_track_id) + if relationship_track is None: + return False + target_sim_id = CommonSimUtils.get_sim_id(target_sim_info) + sim_info.relationship_tracker.set_relationship_score(target_sim_id, level, relationship_track) + return True + + @classmethod + def get_relationships_gen(cls, sim_info: SimInfo) -> Iterator[Relationship]: + """get_relationships_gen(sim_info) + + Retrieve all relationships a Sim has with other Sims. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: An iterator of Relationships a Sim has with other Sims. + :rtype: Iterator[Relationship] + """ + if not hasattr(sim_info, 'relationship_tracker') or not sim_info.relationship_tracker: + return tuple() + for relationship in sim_info.relationship_tracker: + yield relationship + + @classmethod + def add_relationship_bit( + cls, + sim_info: SimInfo, + target_sim_info: SimInfo, + relationship_bit_id: Union[int, CommonRelationshipBitId] + ) -> CommonExecutionResult: + """add_relationship_bit(sim_info, target_sim_info, relationship_bit_id) + + Add a relationship bit between two sims. + + .. note:: + + If the relationship bit is UNIDIRECTIONAL, it will only be added to sim_info in the direction of the Target. + i.e. Sim will have relationship bit towards Target, but Target will not have relationship bit towards Sim. + + One example is the Caregiver relationship: + + - Sim is caregiver of Target. + - Target is being cared for by Sim. + + :param sim_info: The source Sim of the Relationship Bit. + :type sim_info: SimInfo + :param target_sim_info: The target Sim of the Relationship Bit. + :type target_sim_info: SimInfo + :param relationship_bit_id: The identifier of the Relationship Bit to add. + :type relationship_bit_id: Union[int, CommonRelationshipBitId] + :return: True, if the relationship bit was added successfully. False, if not. + :rtype: CommonExecutionResult + """ + relationship_bit_instance = cls.load_relationship_bit_by_id(relationship_bit_id) + if relationship_bit_instance is None: + return CommonExecutionResult(False, f'Failed to locate relationship bit {relationship_bit_id}') + target_sim_id = CommonSimUtils.get_sim_id(target_sim_info) + relationship_tracker = sim_info.relationship_tracker + if relationship_tracker is None: + return CommonExecutionResult(False, f'{sim_info} did not have a relationship tracker.') + relationship_tracker.add_relationship_bit(target_sim_id, relationship_bit_instance) + return CommonExecutionResult.TRUE + + @classmethod + def remove_relationship_bit( + cls, + sim_info: SimInfo, + target_sim_info: SimInfo, + relationship_bit_id: Union[int, CommonRelationshipBitId] + ) -> CommonExecutionResult: + """remove_relationship_bit(sim_info, target_sim_info, relationship_bit_id) + + Remove a relationship bit between two sims. + + .. note:: + + If the relationship bit is UNIDIRECTIONAL, it will only be removed from sim_info in the direction of the Target. + i.e. Sim will have no longer have relationship bit towards Target, but Target will still have relationship bit towards Sim. + + One example is the Caregiver relationship: + + - Sim is caregiver of Target. + - Target is being cared for by Sim. + + :param sim_info: The source Sim of the Relationship Bit. + :type sim_info: SimInfo + :param target_sim_info: The target Sim of the Relationship Bit. + :type target_sim_info: SimInfo + :param relationship_bit_id: The identifier of the Relationship Bit to remove. + :type relationship_bit_id: Union[int, CommonRelationshipBitId] + :return: True, if the relationship bit was removed successfully. False, if not. + :rtype: CommonExecutionResult + """ + relationship_bit_instance = cls.load_relationship_bit_by_id(relationship_bit_id) + if relationship_bit_instance is None: + return CommonExecutionResult(False, f'Failed to locate relationship bit {relationship_bit_id}') + target_sim_id = CommonSimUtils.get_sim_id(target_sim_info) + relationship_tracker = sim_info.relationship_tracker + if relationship_tracker is None: + return CommonExecutionResult(False, f'{sim_info} did not have a relationship tracker.') + relationship_tracker.remove_relationship_bit(target_sim_id, relationship_bit_instance) + return CommonExecutionResult.TRUE + + @classmethod + def remove_relationship_bit_from_all( + cls, + sim_info: SimInfo, + relationship_bit_id: Union[int, CommonRelationshipBitId] + ) -> bool: + """remove_relationship_bit_from_all(sim_info, relationship_bit_id) + + Remove a relationship bit between a Sim and all other Sims. + + .. note:: + + If the relationship bit is UNIDIRECTIONAL, it will only be removed from sim_info in the direction of the Target. + i.e. Sim will have no longer have relationship bit towards Target, but Target will still have relationship bit towards Sim. + + One example is the Caregiver relationship: + + - Sim is caregiver of Target. + - Target is being cared for by Sim. + + :param sim_info: The source Sim of the Relationship Bit. + :type sim_info: SimInfo + :param relationship_bit_id: The identifier of the Relationship Bit to remove. + :type relationship_bit_id: Union[int, CommonRelationshipBitId] + :return: True, if the relationship bit was removed successfully. False, if not. + :rtype: bool + """ + relationship_bit_instance = cls.load_relationship_bit_by_id(relationship_bit_id) + if relationship_bit_instance is None: + return False + sim_id_a = CommonSimUtils.get_sim_id(sim_info) + for relationship in cls.get_relationships_gen(sim_info): + sim_id_b = relationship.get_other_sim_id(sim_id_a) + if relationship.has_bit(sim_id_a, relationship_bit_instance): + relationship.remove_bit(sim_id_a, sim_id_b, relationship_bit_instance) + return True + + @classmethod + def get_sim_info_of_all_sims_with_relationship_bit_generator(cls, sim_info: SimInfo, relationship_bit_id: Union[int, CommonRelationshipBitId], instanced_only: bool = True) -> Iterator[SimInfo]: + """get_sim_info_of_all_sims_with_relationship_bit_generator(sim_info, relationship_bit_id, instanced_only=True) + + Retrieve an Iterator of SimInfo for all Sims that have the specified relationship bit with the specified Sim. + + .. note:: + + For UNIDIRECTIONAL relationship bits, the direction is sim_info has relationship bit with target_sim_info + + Caregiver example: + + - The Caregiver has a relationship bit pointed at Toddler (The Caregiver would show "caregiving ward" when hovering over the Toddler in the relationships panel) + - The Toddler would NOT have the relationship bit. + - Sim is Caregiver of Toddler. + + :param sim_info: The Sim to locate the relationship bit on. + :type sim_info: SimInfo + :param relationship_bit_id: The identifier of the relationship bit to locate connections with. + :type relationship_bit_id: Union[int, CommonRelationshipBitId] + :param instanced_only: If True, only Sims that are currently loaded will be returned. + :type instanced_only: bool, optional + :return: An iterator of Sims that have the specified relationship bit with the specified Sim. + :rtype: Iterator[SimInfo] + """ + return cls.get_sim_info_of_all_sims_with_relationship_bits_generator(sim_info, (relationship_bit_id, ), instanced_only=instanced_only) + + @classmethod + def get_sim_info_of_all_sims_with_relationship_bits_generator(cls, sim_info: SimInfo, relationship_bit_ids: Iterator[Union[int, CommonRelationshipBitId]], instanced_only: bool = True) -> Iterator[SimInfo]: + """get_sim_info_of_all_sims_with_relationship_bits_generator(sim_info, relationship_bit_ids, instanced_only=True) + + Retrieve an Iterator of SimInfo for all Sims that have the specified relationship bits with the specified Sim. + + .. note:: + + For UNIDIRECTIONAL relationship bits, the direction is sim_info has relationship bit with target_sim_info + Caregiver example: + + - The Caregiver has a relationship bit pointed at Toddler (The Caregiver would show "caregiving ward" when hovering over the toddler in the relationships panel) + - The toddler would NOT have the relationship bit. + - Sim is Caregiver of Toddler. + + :param sim_info: The Sim to locate relationship bits on. + :type sim_info: SimInfo + :param relationship_bit_ids: A collection of identifiers for relationship bits to locate connections with. + :type relationship_bit_ids: Iterator[Union[int, CommonRelationshipBitId]] + :param instanced_only: If True, only Sims that are currently loaded will be returned. + :type instanced_only: bool, optional + :return: An iterator of Sims that have any of the specified relationship bits with the specified Sim. + :rtype: Iterator[SimInfo] + """ + if sim_info is None: + return tuple() + sim_id = CommonSimUtils.get_sim_id(sim_info) + for relationship in sim_info.relationship_tracker: + if relationship.sim_id_a != sim_id: + target_sim_id = relationship.sim_id_a + else: + target_sim_id = relationship.sim_id_b + target_sim_info = CommonSimUtils.get_sim_info(target_sim_id) + if target_sim_info is None: + continue + if instanced_only and CommonSimUtils.get_sim_instance(target_sim_info) is None: + continue + for relationship_bit_id in relationship_bit_ids: + relationship_bit_instance = cls.load_relationship_bit_by_id(relationship_bit_id) + if relationship_bit_instance is None: + continue + if relationship.has_bit(sim_id, relationship_bit_instance): + yield target_sim_info + break + + @classmethod + def has_positive_romantic_combo_relationship_bit_with(cls, sim_info: SimInfo, target_sim_info: SimInfo) -> bool: + """has_positive_romantic_combo_relationship_bit_with(sim_info, target_sim_info) + + Determine if a Sim has a positive romantic combo with the Target Sim. + + .. note:: + + Positive Romantic Combo Relationship Bits: + + - Soul Mates + - Lovers + - Sweethearts + - Love Birds + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :param target_sim_info: The Target Sim to check. + :type target_sim_info: SimInfo + :return: True, if the Sims have positive romantic combo relationship bits with each other. False, if not. + :rtype: bool + """ + return cls.has_relationship_bits_with_sim(sim_info, target_sim_info, ( + CommonRelationshipBitId.ROMANTIC_COMBO_SOUL_MATES, + CommonRelationshipBitId.ROMANTIC_COMBO_LOVERS, + CommonRelationshipBitId.ROMANTIC_COMBO_SWEETHEARTS, + CommonRelationshipBitId.ROMANTIC_COMBO_LOVEBIRDS + )) + + @classmethod + def get_sim_info_of_all_sims_romantically_committed_to_generator(cls, sim_info: SimInfo, instanced_only: bool = True) -> Iterator[SimInfo]: + """get_sim_info_of_all_sims_romantically_committed_to_generator(sim_info, instanced_only=True) + + Retrieve a SimInfo object for all Sims romantically committed with the specified Sim. + + .. note:: + + Romantic Commitments: + + - Married + - Getting Married + - Engaged + - Significant Other + - Promised + + + :param sim_info: The Sim to locate romantically involved Sims with. + :type sim_info: SimInfo + :param instanced_only: If True, only Sims that are currently loaded will be returned. + :type instanced_only: bool, optional + :return: An iterator of Sims the specified Sim is romantically committed to. + :rtype: Iterator[SimInfo] + """ + romance_relationship_ids = cls.get_romantically_committed_relationship_bits() + for target_sim_info in cls.get_sim_info_of_all_sims_with_relationship_bits_generator(sim_info, romance_relationship_ids, instanced_only=instanced_only): + yield target_sim_info + + @classmethod + def get_friendship_relationship_track(cls, sim_info_a: SimInfo, sim_info_b: SimInfo) -> Union[CommonRelationshipTrackId, None]: + """get_friendship_relationship_track(sim_info_a, sim_info_b) + + Get an appropriate Friendship Relationship track between Sim A and Sim B. + + :param sim_info_a: An instance of a Sim. + :type sim_info_a: SimInfo + :param sim_info_b: An instance of a Sim. + :type sim_info_b: SimInfo + :return: The decimal identifier of the Friendship Relationship Track appropriate for Sim A to have with Sim B or None if not found. + :rtype: Union[CommonRelationshipTrackId, None] + """ + if CommonSpeciesUtils.is_human(sim_info_a): + if CommonSpeciesUtils.is_animal(sim_info_b): + return CommonRelationshipTrackId.SIM_TO_PET_FRIENDSHIP + elif CommonSpeciesUtils.is_human(sim_info_b): + return CommonRelationshipTrackId.FRIENDSHIP + elif CommonSpeciesUtils.is_animal(sim_info_a): + if CommonSpeciesUtils.is_animal(sim_info_b): + return None + elif CommonSpeciesUtils.is_human(sim_info_b): + return CommonRelationshipTrackId.SIM_TO_PET_FRIENDSHIP + return None + + @classmethod + def get_romance_relationship_track(cls, sim_info_a: SimInfo, sim_info_b: SimInfo) -> Union[CommonRelationshipTrackId, None]: + """get_romance_relationship_track(sim_info_a, sim_info_b) + + Get an appropriate Romance Relationship track between Sim A and Sim B. + + :param sim_info_a: An instance of a Sim. + :type sim_info_a: SimInfo + :param sim_info_b: An instance of a Sim. + :type sim_info_b: SimInfo + :return: The decimal identifier of the Romance Relationship Track appropriate for Sim A to have with Sim B or None if not found. + :rtype: Union[CommonRelationshipTrackId, None] + """ + if CommonSpeciesUtils.is_human(sim_info_a) and CommonSpeciesUtils.is_human(sim_info_b): + return CommonRelationshipTrackId.ROMANCE + return None + + @classmethod + def load_relationship_bit_by_id(cls, relationship_bit: Union[int, CommonRelationshipBitId, RelationshipBit]) -> Union[RelationshipBit, None]: + """load_relationship_bit_by_id(relationship_bit) + + Load an instance of a Relationship Bit by its identifier. + + :param relationship_bit: The identifier of a Relationship Bit. + :type relationship_bit: Union[int, CommonRelationshipBitId, RelationshipBit] + :return: An instance of a Relationship Bit matching the decimal identifier or None if not found. + :rtype: Union[RelationshipBit, None] + """ + if isinstance(relationship_bit, RelationshipBit): + return relationship_bit + # noinspection PyBroadException + try: + # noinspection PyCallingNonCallable + relationship_bit_instance = relationship_bit() + if isinstance(relationship_bit_instance, RelationshipBit): + # noinspection PyTypeChecker + return relationship_bit + except: + pass + # noinspection PyBroadException + try: + relationship_bit: int = int(relationship_bit) + except: + # noinspection PyTypeChecker + relationship_bit: RelationshipBit = relationship_bit + return relationship_bit + + from sims4.resources import Types + from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + return CommonResourceUtils.load_instance(Types.RELATIONSHIP_BIT, relationship_bit) + + @classmethod + def load_relationship_track_by_id(cls, relationship_track: Union[int, CommonRelationshipTrackId, RelationshipTrack]) -> Union[RelationshipTrack, None]: + """load_relationship_track_by_id(relationship_track) + + Load an instance of a Relationship Track by its identifier. + + :param relationship_track: The identifier of a Relationship Track. + :type relationship_track: Union[int, CommonRelationshipTrackId, RelationshipTrack] + :return: An instance of a Relationship Track matching the decimal identifier or None if not found. + :rtype: Union[RelationshipTrack, None] + """ + if isinstance(relationship_track, RelationshipTrack): + return relationship_track + # noinspection PyBroadException + try: + # noinspection PyCallingNonCallable + relationship_track_instance = relationship_track() + if isinstance(relationship_track_instance, RelationshipTrack): + # noinspection PyTypeChecker + return relationship_track + except: + pass + # noinspection PyBroadException + try: + relationship_track: int = int(relationship_track) + except: + # noinspection PyTypeChecker + relationship_track: RelationshipTrack = relationship_track + return relationship_track + + from sims4.resources import Types + from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + return CommonResourceUtils.load_instance(Types.STATISTIC, relationship_track) + + @classmethod + def get_relationship_bit_guid(cls, relationship_bit: Union[int, RelationshipBit]) -> Union[int, None]: + """get_relationship_bit_guid(relationship_bit) + + Retrieve the GUID (Decimal Identifier) of a RelationshipBit. + + :param relationship_bit: The identifier or instance of a RelationshipBit. + :type relationship_bit: Union[int, RelationshipBit] + :return: The decimal identifier of the RelationshipBit or None if the RelationshipBit does not have an id. + :rtype: Union[int, None] + """ + if isinstance(relationship_bit, int): + return relationship_bit + return getattr(relationship_bit, 'guid64', None) + + +log = CommonLogRegistry().register_log(ModInfo.get_identity(), 'common_relationship_commands') +log.enable() + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.remove_relationship_bit', + 'Remove a relationship bit from a Sim.', + command_arguments=( + CommonConsoleCommandArgument('relationship_bit', 'Relationship Bit Id or Tuning Name', 'The decimal identifier or Tuning Name of the Relationship Bit to remove.'), + CommonConsoleCommandArgument('source_sim_info', 'Sim Id or Name', 'The instance id or name of the Sim to remove the relationship bit from as the source.', is_optional=True, default_value='Active Sim'), + CommonConsoleCommandArgument('target_sim_info', 'Sim Id or Name', 'The instance id or name of the Sim to remove the relationship bit from as the target of the relationship bit. If not specified, the relationship bit will be removed regardless of target.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.remove_rel_bit', + ) +) +def _common_remove_relationship_bit( + output: CommonConsoleCommandOutput, + relationship_bit: TunableInstanceParam(Types.RELATIONSHIP_BIT), + source_sim_info: SimInfo = None, + target_sim_info: SimInfo = None, +): + if isinstance(relationship_bit, str): + output(f'ERROR: Invalid relationship bit specified \'{relationship_bit}\' or it was not found.') + return False + if target_sim_info is None: + output('ERROR: No Target was specified!') + return False + if source_sim_info is target_sim_info: + output(f'Attempting to remove relationship bit {relationship_bit} between {source_sim_info} for all other Sims.') + if not CommonRelationshipUtils.remove_relationship_bit_from_all(source_sim_info, relationship_bit): + output(f'FAILURE: Failed to remove relationship bit {relationship_bit} between {source_sim_info} for all other Sims.') + return False + else: + output(f'Attempting to remove relationship bit {relationship_bit} between {source_sim_info} and {target_sim_info}') + if not CommonRelationshipUtils.remove_relationship_bit(source_sim_info, target_sim_info, relationship_bit): + output(f'FAILURE: Failed to remove relationship bit {relationship_bit} between {source_sim_info} and {target_sim_info}.') + return False + output(f'SUCCESS: Successfully removed relationship bit {relationship_bit} between {source_sim_info} and {target_sim_info}.') + return True + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_testing.print_relationship_bits', + 'Print a list of all relationship bits a Sim has with other Sims.', + command_arguments=( + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance id or name of the Sim to check.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib_testing.printrelationshipbits', + 's4clib_testing.print_rel_bits', + 's4clib_testing.printrelbits' + ) +) +def _common_print_relationship_bits(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): + if sim_info is None: + return + output(f'Printing relationship bits of Sim {sim_info} with other Sims.') + log.debug(f'Printing relationship bits of Sim {sim_info} with other Sims.') + sim_id_a = CommonSimUtils.get_sim_id(sim_info) + text = '' + for relationship in sim_info.relationship_tracker: + sim_info_b = relationship.get_other_sim_info(sim_id_a) + try: + bi_direction_bits = relationship._bi_directional_relationship_data._bits + inner_text = f'\n---------------------Relationship ({sim_info} to {sim_info_b})---------------------' + if bi_direction_bits: + inner_text += '\n Bi-Directional Bits:' + for (key, value) in bi_direction_bits.items(): + bit_type = type(value) + inner_text += f'\n - {key.__name__} ({bit_type.__mro__[1].__name__})' + inner_text += '\n' + + sim_a_relationship_bits = relationship._sim_a_relationship_data._bits + if sim_a_relationship_bits: + inner_text += f'\n Unidirectional Bits Sim A (What {sim_info_b} is to {sim_info}):' + for (key, value) in sim_a_relationship_bits.items(): + bit_type = type(value) + inner_text += f'\n - {key.__name__} ({bit_type.__mro__[1].__name__})' + inner_text += '\n' + + sim_b_relationship_bits = relationship._sim_b_relationship_data._bits + if sim_b_relationship_bits: + inner_text += f'\n Unidirectional Bits Sim B (What {sim_info} is to {sim_info_b}):' + for (key, value) in sim_b_relationship_bits.items(): + bit_type = type(value) + inner_text += f'\n - {key.__name__} ({bit_type.__mro__[1].__name__})' + inner_text += '\n' + output(inner_text) + text += inner_text + except Exception as ex: + output(f'An error occurred when handling relationship bits for Sims {sim_info} to {sim_info_b} for relationship {relationship}: {ex}') + log.format_error_with_message('Failed to print relationships', sim_info=sim_info, sim_info_b=sim_info_b, relationship=relationship, exception=ex) + log.debug(text) + output('Done') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.meet_everyone', + 'Add the Has Met Relationship Bit between all Sim.' +) +def _common_meet_everyone(output: CommonConsoleCommandOutput): + output('Attempting to make everyone meet everyone.') + sim_pair_count = 0 + for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): + for target_sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): + if sim_info is target_sim_info: + continue + if CommonRelationshipUtils.has_met(sim_info, target_sim_info): + continue + sim_pair_count += 1 + CommonRelationshipUtils.add_relationship_bit(sim_info, target_sim_info, CommonRelationshipBitId.HAS_MET) + CommonRelationshipUtils.add_relationship_bit(target_sim_info, sim_info, CommonRelationshipBitId.HAS_MET) + output(f'Done adding the Has Met relationship bit to {sim_pair_count} Sim pair(s).') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.unmeet_everyone', + 'Remove the Has Met Relationship Bit between all Sims.', +) +def _common_unmeet_everyone(output: CommonConsoleCommandOutput): + output('Attempting to make everyone unmeet everyone.') + sim_pair_count = 0 + for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): + for target_sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): + if sim_info is target_sim_info: + continue + if not CommonRelationshipUtils.has_met(sim_info, target_sim_info): + continue + sim_pair_count += 1 + CommonRelationshipUtils.remove_relationship_bit(sim_info, target_sim_info, CommonRelationshipBitId.HAS_MET) + CommonRelationshipUtils.remove_relationship_bit(target_sim_info, sim_info, CommonRelationshipBitId.HAS_MET) + output(f'Done removing the Has Met relationship from {sim_pair_count} Sim pair(s).') + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.add_relationship_bit', + 'Add a relationship bit from Sim A to Sim B.', + command_arguments=( + CommonConsoleCommandArgument('relationship_bit', 'Name or Id', 'The name or id of a relationship bit to add.'), + CommonConsoleCommandArgument('sim_a', 'Name or Id', 'The name of the first Sim. The relationship bit will be added from Sim A to Sim B.'), + CommonConsoleCommandArgument('sim_b', 'Name or Id', 'The name of the second Sim. The relationship bit will be added from Sim A to Sim B.') + ), + command_aliases=( + 's4clib.add_rel_bit', + 's4clib.addrelationshipbit', + 's4clib.addrelbit' + ) +) +def _common_add_relationship_bit(output: CommonConsoleCommandOutput, relationship_bit: TunableInstanceParam(Types.RELATIONSHIP_BIT), sim_info_a: SimInfo, sim_info_b: SimInfo): + if isinstance(relationship_bit, str): + output(f'ERROR: Invalid relationship bit specified \'{relationship_bit}\' or it was not found.') + return False + if sim_info_b is None: + output('ERROR: No Target was specified!') + return False + if sim_info_a is sim_info_b: + output('ERROR: Cannot add a relationship bit to the same Sim.') + return False + output(f'Attempting to add relationship bit {relationship_bit} from {sim_info_a} to {sim_info_b}.') + result = CommonRelationshipUtils.add_relationship_bit(sim_info_a, sim_info_b, relationship_bit) + if result: + output(f'SUCCESS: Successfully added relationship bit {relationship_bit} between {sim_info_a} and {sim_info_b}.') + else: + output(f'FAILURE: Failed to add relationship bit {relationship_bit} between {sim_info_a} and {sim_info_b}. {result}') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.reset_relationships', + 'Reset the relationships of a Sim to all other Sims that they have met. Both Friendship and Romance will be set to zero.', + command_arguments=( + CommonConsoleCommandArgument('sim_info', 'Name or Id', 'The name or ID of a Sim. Default is the Active Sim.', is_optional=True, default_value='Active Sim'), + ), +) +def _common_reset_relationships(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): + output(f'Attempting to reset the relationships of {sim_info}.') + sim_pair_count = 0 + for target_sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): + if sim_info is target_sim_info: + continue + if not CommonRelationshipUtils.has_met(sim_info, target_sim_info): + continue + sim_pair_count += 1 + CommonRelationshipUtils.set_friendship_level(sim_info, target_sim_info, 0) + CommonRelationshipUtils.set_romance_level(sim_info, target_sim_info, 0) + output(f'Done resetting the relationships of {sim_pair_count} Sim pair(s).') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.reset_all_relationships', + 'Set the relationships of all Sims to zero with all other Sims that they have already met. Both Friendship and Romance will be set to zero.' +) +def _common_reset_all_relationships(output: CommonConsoleCommandOutput): + output('Attempting to reset the relationships between all Sims.') + sim_pair_count = 0 + for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): + for target_sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): + if sim_info is target_sim_info: + continue + if not CommonRelationshipUtils.has_met(sim_info, target_sim_info): + continue + sim_pair_count += 1 + CommonRelationshipUtils.set_friendship_level(sim_info, target_sim_info, 0) + CommonRelationshipUtils.set_romance_level(sim_info, target_sim_info, 0) + output(f'Done resetting the relationships of {sim_pair_count} Sim pair(s).') + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.set_relationship_level', + 'Set the level of a relationship from Sim A to Sim B.', + command_arguments=( + CommonConsoleCommandArgument('relationship_track', 'Name or Id', 'The name or id of a relationship track to modify.'), + CommonConsoleCommandArgument('sim_a', 'Name or Id', 'The name of the first Sim. The relationship track will be modified from Sim A to Sim B.'), + CommonConsoleCommandArgument('sim_b', 'Name or Id', 'The name of the second Sim. The relationship track will be modified from Sim A to Sim B.'), + CommonConsoleCommandArgument('amount', 'Number', 'The amount of value to set.') + ), + command_aliases=( + 's4clib.setrelationshiplevel', + ) +) +def _common_set_relationship_level( + output: CommonConsoleCommandOutput, + relationship_track: TunableInstanceParam(Types.STATISTIC), + sim_info_a: SimInfo, + sim_info_b: SimInfo, + amount: float +): + if isinstance(relationship_track, str): + output(f'ERROR: Invalid relationship track specified \'{relationship_track}\' or it was not found.') + return False + if sim_info_b is None: + output('ERROR: No Target was specified!') + return False + if sim_info_a is sim_info_b: + output('ERROR: Cannot modify relationship level to the same Sim.') + return False + output(f'Attempting to modify relationship level of {relationship_track} from {sim_info_a} to {sim_info_b} to level {amount}.') + result = CommonRelationshipUtils.set_relationship_level_of_sims(sim_info_a, sim_info_b, relationship_track, amount) + if result: + output(f'SUCCESS: Successfully modified relationship level of {relationship_track} between {sim_info_a} and {sim_info_b}.') + else: + output(f'FAILURE: Failed to modify relationship level of {relationship_track} between {sim_info_a} and {sim_info_b}. {result}') diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_appearance_modifier_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_appearance_modifier_utils.py new file mode 100644 index 0000000..629b645 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_appearance_modifier_utils.py @@ -0,0 +1,219 @@ +""" +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 +""" +from typing import Union, Type, Iterator, Any, Callable + +from buffs.appearance_modifier.appearance_modifier import AppearanceModifier +from buffs.appearance_modifier.appearance_tracker import AppearanceTracker, ModifierInfo +from cas.cas import OutfitOverrideOptionFlags +from sims.sim_info import SimInfo +from sims4communitylib.enums.common_appearance_modifier_priority import CommonAppearanceModifierPriority +from sims4communitylib.enums.common_appearance_modifier_type import CommonAppearanceModifierType + + +class CommonSimAppearanceModifierUtils: + """Utilities for manipulating the appearance modifiers of Sims. + + """ + @staticmethod + def get_appearance_tracker(sim_info: SimInfo) -> Union[AppearanceTracker, None]: + """get_appearance_tracker(sim_info) + + Retrieve the appearance tracker of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The appearance tracker for the Sim or None if not found. + :rtype: Union[AppearanceTracker, None] + """ + if sim_info is None: + return None + if sim_info.appearance_tracker is None: + return None + return sim_info.appearance_tracker + + @staticmethod + def has_any_appearance_modifiers(sim_info: SimInfo) -> bool: + """has_any_appearance_modifiers(sim_info) + + Determine if a Sim has any appearance modifiers applied to them. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: True, if the Sim has any appearance modifiers applied to them. False, if not. + :rtype: bool + """ + return any(CommonSimAppearanceModifierUtils.get_appearance_modifiers_gen(sim_info)) + + @staticmethod + def has_any_appearance_modifiers_with_guid(sim_info: SimInfo, modifier_guid: int) -> bool: + """has_any_appearance_modifiers_with_guid(sim_info, modifier_guid) + + Determine if a Sim has any appearance modifiers applied to them with a specified GUID. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param modifier_guid: The GUID of the modifier to search for. + :type modifier_guid: int + :return: True, if the Sim has any appearance modifiers applied to them with the specified GUID. False, if not. + :rtype: bool + """ + return any(CommonSimAppearanceModifierUtils.get_appearance_modifiers_by_guid_gen(sim_info, modifier_guid)) + + @staticmethod + def has_any_appearance_modifiers_of_type(sim_info: SimInfo, modifier_type: Type[AppearanceModifier.BaseAppearanceModification]) -> bool: + """has_any_appearance_modifiers_of_type(sim_info, modifier_type) + + Determine if a Sim has any appearance modifiers applied to them of a specified type. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param modifier_type: The type of modifier to search for. + :type modifier_type: Type[AppearanceModifier.BaseAppearanceModification] + :return: True, if the Sim has any appearance modifiers applied to them of the specified type. False, if not. + :rtype: bool + """ + return any(CommonSimAppearanceModifierUtils.get_appearance_modifiers_by_type_gen(sim_info, modifier_type)) + + @staticmethod + def get_appearance_modifiers_by_guid_gen(sim_info: SimInfo, modifier_guid: int) -> Iterator[ModifierInfo]: + """get_appearance_modifiers_by_guid_gen(sim_info, modifier_guid) + + Retrieve the appearance modifiers applied to a Sim that have the specified GUID. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param modifier_guid: The GUID of the modifiers to search for. + :type modifier_guid: int + :return: An iterator of Appearance Modifiers that have the specified GUID. + :rtype: Iterator[ModifierInfo] + """ + def _matches(_modifier_type: Any, _appearance_modifier: ModifierInfo) -> bool: + return _appearance_modifier.guid == modifier_guid + + yield from CommonSimAppearanceModifierUtils.get_appearance_modifiers_gen(sim_info, include_appearance_modifier=_matches) + + @staticmethod + def get_appearance_modifiers_by_type_gen(sim_info: SimInfo, modifier_type: Type[AppearanceModifier.BaseAppearanceModification]) -> Iterator[ModifierInfo]: + """get_appearance_modifiers_by_type_gen(sim_info, modifier_type) + + Retrieve the appearance modifiers applied to a Sim that match a specified type. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param modifier_type: The type of the modifiers to search for. + :type modifier_type: Type[AppearanceModifier.BaseAppearanceModification] + :return: An iterator of Appearance Modifiers that match the specified type. + :rtype: Iterator[ModifierInfo] + """ + def _matches(_modifier_type: Any, _appearance_modifier: ModifierInfo) -> bool: + return isinstance(_appearance_modifier.modifier, modifier_type) + + yield from CommonSimAppearanceModifierUtils.get_appearance_modifiers_gen(sim_info, include_appearance_modifier=_matches) + + @staticmethod + def get_appearance_modifiers_gen(sim_info: SimInfo, include_appearance_modifier: Callable[[CommonAppearanceModifierType, ModifierInfo], bool] = None) -> Iterator[ModifierInfo]: + """get_appearance_modifiers_gen(sim_info, include_appearance_modifier=None) + + Retrieve the appearance modifiers applied to a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param include_appearance_modifier: If the result of this callback is True, the Appearance Modifier will be included in the results. If set to None, All Appearance Modifiers will be included. Default is None. + :type include_appearance_modifier: Callable[[CommonAppearanceModifierType, ModifierInfo], bool], optional + :return: An iterator of all Appearance Modifiers applied to the Sim that match the `include_appearance_modifier` filter. + :rtype: Iterator[ModifierInfo] + """ + appearance_tracker = CommonSimAppearanceModifierUtils.get_appearance_tracker(sim_info) + if appearance_tracker is None: + return tuple() + if appearance_tracker._active_appearance_modifier_infos is None: + return tuple() + for (modifier_type, appearance_modifiers) in appearance_tracker._active_appearance_modifier_infos.items(): + for appearance_modifier in appearance_modifiers: + if include_appearance_modifier is not None and not include_appearance_modifier(modifier_type, appearance_modifier): + continue + yield appearance_modifier + return tuple() + + @staticmethod + def add_appearance_modifier( + sim_info: SimInfo, + modifier: AppearanceModifier.BaseAppearanceModification, + modifier_guid: int, + priority: CommonAppearanceModifierPriority = CommonAppearanceModifierPriority.TRANSFORMED, + apply_to_all_outfits: bool = True, + additional_flags: OutfitOverrideOptionFlags = OutfitOverrideOptionFlags.DEFAULT, + source: Any = None + ) -> None: + """add_appearance_modifier(\ + sim_info,\ + modifier,\ + modifier_guid,\ + priority=CommonAppearanceModifierPriority.TRANSFORMED,\ + apply_to_all_outfits=True,\ + additional_flags=OutfitOverrideOptionFlags.DEFAULT,\ + source=None\ + ) + + Determine if a Sim has any appearance modifiers applied to them of a specified type. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param modifier: The Appearance Modifier to apply. + :type modifier: AppearanceModifier.BaseAppearanceModification + :param modifier_guid: The GUID of the appearance modifier being applied. + :type modifier_guid: int + :param priority: The priority of the appearance modifier. This determines which types of appearance modifiers can override this modifier and which ones this modifier overrides. Default is CommonAppearanceModifierPriority.TRANSFORMED. + :type priority: CommonAppearanceModifierPriority, optional + :param apply_to_all_outfits: If True, the appearance modifier will apply to all outfits. If False, the appearance modifier will only apply the current outfit of the Sim. Default is True. + :type apply_to_all_outfits: bool, optional + :param additional_flags: Additional flags for overriding outfit parts. Default is OutfitOverrideOptionFlags.DEFAULT. + :type additional_flags: OutfitOverrideOptionFlags, optional + :param source: The source of the appearance modifier. Default is None. + :type source: Any, optional + """ + appearance_tracker = sim_info.appearance_tracker + if isinstance(modifier, tuple): + if len(modifier) > 1: + modifier = appearance_tracker._choose_modifier(modifier) + else: + modifier = modifier[0].modifier + vanilla_priority = CommonAppearanceModifierPriority.convert_to_vanilla(priority) + appearance_tracker.add_appearance_modifier(modifier, modifier_guid, vanilla_priority, apply_to_all_outfits, source=source, additional_flags=additional_flags) + + @staticmethod + def remove_appearance_modifiers_by_guid(sim_info: SimInfo, modifier_guid: int, source: str = 'S4CL Removal') -> None: + """remove_appearance_modifiers_by_guid(sim_info, modifier_guid, source='S4CL Removal') + + Remove appearance modifiers from a Sim by their GUID. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param modifier_guid: The GUID of the modifiers to remove. + :type modifier_guid: int + :param source: The source of the removal. Default is "S4CL Removal". + :type source: str, optional + """ + appearance_tracker = CommonSimAppearanceModifierUtils.get_appearance_tracker(sim_info) + if appearance_tracker is None: + return + appearance_tracker.remove_appearance_modifiers(modifier_guid, source=source) + + @staticmethod + def evaluate_appearance_modifiers(sim_info: SimInfo) -> None: + """evaluate_appearance_modifiers(sim_info) + + Force evaluate the appearance modifiers of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + """ + appearance_tracker = CommonSimAppearanceModifierUtils.get_appearance_tracker(sim_info) + if appearance_tracker is None: + return + appearance_tracker.evaluate_appearance_modifiers() diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_autonomy_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_autonomy_utils.py new file mode 100644 index 0000000..5066522 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_autonomy_utils.py @@ -0,0 +1,143 @@ +""" +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 +""" +from autonomy.settings import AutonomyState +from objects.game_object import GameObject +from sims.sim_info import SimInfo +from sims4communitylib.enums.common_object_preference_tag import CommonObjectPreferenceTag +from sims4communitylib.enums.types.component_types import CommonComponentType +from sims4communitylib.utils.common_component_utils import CommonComponentUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + + +class CommonSimAutonomyUtils: + """ Utilities for manipulating the autonomy of Sims. """ + + @staticmethod + def get_autonomy_state(sim_info: SimInfo) -> AutonomyState: + """get_autonomy_state_setting(sim_info) + + Retrieve the current autonomy state of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + """ + from autonomy.autonomy_component import AutonomyComponent + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return AutonomyState.UNDEFINED + autonomy_component: AutonomyComponent = CommonComponentUtils.get_component(sim, CommonComponentType.AUTONOMY) + if autonomy_component is None or not hasattr(autonomy_component, 'get_autonomy_state_setting'): + return AutonomyState.UNDEFINED + return autonomy_component.get_autonomy_state_setting() + + @staticmethod + def has_disabled_autonomy(sim_info: SimInfo) -> bool: + """has_disabled_autonomy(sim_info) + + Determine if the autonomy state of a Sim is set to Disabled. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: True, if the autonomy state of the Sim is set to Disabled. False, if not. + :rtype: bool + """ + return CommonSimAutonomyUtils.has_autonomy_state(sim_info, AutonomyState.DISABLED) + + @staticmethod + def has_limited_autonomy(sim_info: SimInfo) -> bool: + """has_limited_autonomy(sim_info) + + Determine if the autonomy state of a Sim is set to Limited Only. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: True, if the autonomy state of the Sim is set to Limited Only. False, if not. + :rtype: bool + """ + return CommonSimAutonomyUtils.has_autonomy_state(sim_info, AutonomyState.LIMITED_ONLY) + + @staticmethod + def has_medium_autonomy(sim_info: SimInfo) -> bool: + """has_medium_autonomy(sim_info) + + Determine if the autonomy state of a Sim is set to Medium. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: True, if the autonomy state of the Sim is set to Medium. False, if not. + :rtype: bool + """ + return CommonSimAutonomyUtils.has_autonomy_state(sim_info, AutonomyState.MEDIUM) + + @staticmethod + def has_full_autonomy(sim_info: SimInfo) -> bool: + """has_full_autonomy(sim_info) + + Determine if the autonomy state of a Sim is set to Full. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: True, if the autonomy state of the Sim is set to Full. False, if not. + :rtype: bool + """ + return CommonSimAutonomyUtils.has_autonomy_state(sim_info, AutonomyState.FULL) + + @staticmethod + def has_autonomy_state(sim_info: SimInfo, autonomy_state: AutonomyState) -> bool: + """has_autonomy_state(sim_info, autonomy_state) + + Determine if the autonomy state of a Sim matches an autonomy state. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param autonomy_state: An autonomy state. + :type autonomy_state: AutonomyState + :return: True, if the autonomy state of the Sim matches the specified autonomy state. False, if not. + :rtype: bool + """ + return CommonSimAutonomyUtils.get_autonomy_state(sim_info) == autonomy_state + + @staticmethod + def has_scoring_preference_for_object(sim_info: SimInfo, preference_tag: CommonObjectPreferenceTag, game_object: GameObject) -> bool: + """has_scoring_preference_for_object(sim_info, preference_tag, game_object) + + Determine if a Sim will have a scoring preference for an Object when searching for Objects to use with a Tag. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param preference_tag: The tag to look for preference with. + :type preference_tag: CommonObjectPreferenceTag + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if the Sim will have a scoring preference to use the specified Object when searching for Objects to use with the specified Tag. False, if not. + :rtype: bool + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None or game_object is None: + return False + return sim.is_object_scoring_preferred(preference_tag, game_object) + + @staticmethod + def has_use_preference_for_object(sim_info: SimInfo, preference_tag: CommonObjectPreferenceTag, game_object: GameObject) -> bool: + """has_use_preference_for_object(sim_info, preference_tag, game_object) + + Determine if a Sim will have a preference for an Object when searching for Objects to use with a Tag. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param preference_tag: The tag to look for preference with. + :type preference_tag: CommonObjectPreferenceTag + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if the Sim will prefer to use the specified Object when searching for Objects to use with the specified Tag. False, if not. + :rtype: bool + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None or game_object is None: + return False + return sim.is_object_use_preferred(preference_tag, game_object) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_body_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_body_utils.py new file mode 100644 index 0000000..4c499ad --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_body_utils.py @@ -0,0 +1,190 @@ +""" +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 +""" +from typing import Tuple + +from sims.sim_info import SimInfo +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + CommonConsoleCommandArgument +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + + +class CommonSimBodyUtils: + """Utilities for manipulating the body of Sims. + + """ + + @staticmethod + def get_wading_size(sim_info: SimInfo) -> Tuple[int, int]: + """get_wading_size(sim_info) + + Retrieve the size of a Sim if they were to wade in an Ocean of water. + + .. note:: This function is obsolete. Please use :func:`~get_ocean_wading_size` instead. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: A tuple indicating the x and y wading size of a Sim from their origin point. + :rtype: Tuple[int, int] + """ + return CommonSimBodyUtils.get_ocean_wading_size(sim_info) + + @staticmethod + def get_ocean_wading_size(sim_info: SimInfo) -> Tuple[int, int]: + """get_ocean_wading_size(sim_info) + + Retrieve the size of a Sim if they were to wade in an Ocean of water. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: A tuple indicating the x and y Ocean wading size of a Sim from their origin point. + :rtype: Tuple[int, int] + """ + # noinspection PyBroadException + try: + from world.ocean_tuning import OceanTuning + except: + return 0, 0 + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return 0, 0 + wading_interval = OceanTuning.get_actor_wading_interval(sim) + if wading_interval is None: + return 0, 0 + return wading_interval.lower_bound, wading_interval.upper_bound + + @staticmethod + def get_pond_wading_size(sim_info: SimInfo) -> Tuple[int, int]: + """get_wading_size(sim_info) + + Retrieve the size of a Sim if they were to wade in a pond of water. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: A tuple indicating the x and y Pond wading size of a Sim from their origin point. + :rtype: Tuple[int, int] + """ + # noinspection PyBroadException + try: + from objects.pools.pond_utils import PondUtils + except: + return 0, 0 + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return 0, 0 + wading_interval = PondUtils.get_actor_wading_interval(sim) + if wading_interval is None: + return 0, 0 + return wading_interval.lower_bound, wading_interval.upper_bound + + @classmethod + def set_fit_level(cls, sim_info: SimInfo, level: float): + """set_fit_level(sim_info, level) + + Set the Fit level of a Sim. + + :param sim_info: The Sim to modify. + :type sim_info: SimInfo + :param level: The Fit level to set the Sim to. + :type level: float + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + from objects.components.consumable_component import ConsumableComponent + sim.commodity_tracker.set_value(ConsumableComponent.FIT_COMMODITY, level) + sim_info._sim_ref().needs_fitness_update = True + sim_info.update_fitness_state() + + @classmethod + def get_fit_level(cls, sim_info: SimInfo) -> float: + """get_fit_level(sim_info) + + Get the Fit level of a Sim. + + :param sim_info: The Sim to modify. + :type sim_info: SimInfo + :return: The Fit level of the Sim. + :rtype: float + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + from objects.components.consumable_component import ConsumableComponent + return sim.commodity_tracker.get_value(ConsumableComponent.FIT_COMMODITY) + + @classmethod + def set_fat_level(cls, sim_info: SimInfo, level: float): + """set_fat_level(sim_info, level) + + Set the Fat level of a Sim. + + :param sim_info: The Sim to modify. + :type sim_info: SimInfo + :param level: The Fat level to set the Sim to. + :type level: float + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + from objects.components.consumable_component import ConsumableComponent + sim.commodity_tracker.set_value(ConsumableComponent.FAT_COMMODITY, level) + sim_info._sim_ref().needs_fitness_update = True + sim_info.update_fitness_state() + + @classmethod + def get_fat_level(cls, sim_info: SimInfo) -> float: + """get_fat_level(sim_info) + + Get the Fat level of a Sim. + + :param sim_info: The Sim to modify. + :type sim_info: SimInfo + :return: The Fat level of the Sim. + :rtype: float + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + from objects.components.consumable_component import ConsumableComponent + return sim.commodity_tracker.get_value(ConsumableComponent.FAT_COMMODITY) + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4cl.set_fit', + 'Set the Fit level of a Sim.', + command_arguments=( + CommonConsoleCommandArgument('level', 'Number', 'The Fit level to set the Sim to.', is_optional=False), + CommonConsoleCommandArgument('sim_info', 'Name or ID', 'The name or ID of the Sim to modify.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4cl.set_fit_level', + ) +) +def _common_set_fit_level(output: CommonConsoleCommandOutput, level: float, sim_info: SimInfo = None): + if sim_info is None: + output(f'No Sim found with {sim_info}') + return + output(f'Setting Fit level of {sim_info} to {level}.') + CommonSimBodyUtils.set_fit_level(sim_info, level) + output('Done') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4cl.set_fat', + 'Set the Fat level of a Sim.', + command_arguments=( + CommonConsoleCommandArgument('level', 'Number', 'The Fat level to set the Sim to.', is_optional=False), + CommonConsoleCommandArgument('sim_info', 'Name or ID', 'The name or ID of the Sim to modify.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4cl.set_fat_level', + ) +) +def _common_set_fat_level(output: CommonConsoleCommandOutput, level: float, sim_info: SimInfo = None): + if sim_info is None: + output(f'No Sim found with {sim_info}') + return + output(f'Setting Fat level of {sim_info} to {level}.') + CommonSimBodyUtils.set_fat_level(sim_info, level) + output('Done') diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_bucks_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_bucks_utils.py new file mode 100644 index 0000000..5ed8969 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_bucks_utils.py @@ -0,0 +1,785 @@ +""" +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 +""" +from typing import Union, Iterator + +from bucks.bucks_enums import BucksType +from bucks.bucks_perk import BucksPerk +from bucks.bucks_tracker import BucksTrackerBase +from bucks.bucks_utils import BucksUtils +from server_commands.argument_helpers import TunableInstanceParam +from sims.sim_info import SimInfo +from sims4.resources import Types +from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.enums.common_bucks_types import CommonBucksType +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + CommonConsoleCommandArgument +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + + +class CommonSimBucksUtils: + """Utilities for bucks. """ + @classmethod + def add_all_perks(cls, sim_info: SimInfo, bucks_type: Union[CommonBucksType, BucksType], no_cost: bool = True, **__) -> CommonExecutionResult: + """remove_all_perks(sim_info, bucks_type, refund_cost=True, **__) + + Add all Perks of a specified Bucks type to a Sim. + + .. note:: A Sim needs to be spawned before their perks can be added. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param bucks_type: The Bucks associated with the perks being added. + :type bucks_type: Union[CommonBucksType, BucksType] + :param no_cost: Set True to unlock the perk without spending perk points. Set False to spend perk points to unlock the perk.. Default is False + :type no_cost: bool, optional + :return: The result of executing the function. True, if successful. False, if not. + :rtype: CommonExecutionResult + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return CommonExecutionResult(False, reason=f'{sim_info} is not currently spawned. They need to be spawned before all of their perks can be locked.') + bucks_tracker: BucksTrackerBase = cls.get_bucks_tracker(sim_info, bucks_type, add_if_none=True) + if bucks_tracker is None: + return CommonExecutionResult(False, reason=f'{sim_info} does not have a tracker for the specified bucks. {bucks_type}') + for perk in cls.get_locked_perks_gen(sim_info, bucks_type): + if cls.has_perk_unlocked(sim_info, perk): + return CommonExecutionResult(True, reason=f'Perk {perk} is already unlocked.') + perk = cls.load_perk_by_guid(perk) + if perk is None: + return CommonExecutionResult(False, reason=f'Failed to locate perk by id {perk}') + modified_for_cost = False + if no_cost: + if not cls.can_afford_perk(sim_info, perk): + unlock_cost = cls.get_perk_unlock_cost(perk) + modify_result = cls.modify_bucks(sim_info, bucks_type, unlock_cost, reason='Perk being unlocked at no cost.') + if not modify_result: + return modify_result + modified_for_cost = True + elif not cls.can_afford_perk(sim_info, perk): + continue + if bucks_tracker.pay_for_and_unlock_perk(perk): + if not modified_for_cost: + unlock_cost = cls.get_perk_unlock_cost(perk) + modify_result = cls.modify_bucks(sim_info, bucks_type, unlock_cost, reason='Perk being unlocked at no cost.') + if not modify_result: + return modify_result + return CommonExecutionResult.TRUE + + @classmethod + def remove_all_perks(cls, sim_info: SimInfo, bucks_type: Union[CommonBucksType, BucksType], refund_cost: bool = True, reason: str = None, remove_perk_points: bool = False, **__) -> CommonExecutionResult: + """remove_all_perks(sim_info, bucks_type, refund_cost=True, reason=None, remove_perk_points=False, **__) + + Remove all Perks of a specified Bucks type from a Sim. + + .. note:: A Sim needs to be spawned before their perks can be removed. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param bucks_type: The Bucks associated with the perks being removed. + :type bucks_type: Union[CommonBucksType, BucksType] + :param refund_cost: Set True to refund the cost of all unlocked perks. Set False to give no perk points back. Default is True + :type refund_cost: bool, optional + :param reason: The reason the perks are being removed. Default is None. + :type reason: str, optional + :param remove_perk_points: Set True to remove all perk points in addition to all the perks. Set False to remove only the perks. If this is True, refund_cost will be ignored. Default is False. + :type remove_perk_points: bool, optional + :return: The result of executing the function. True, if successful. False, if not. + :rtype: CommonExecutionResult + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return CommonExecutionResult(False, reason=f'{sim_info} is not currently spawned. They need to be spawned before all of their perks can be removed.') + vanilla_bucks_type = CommonBucksType.convert_to_vanilla(bucks_type) + if vanilla_bucks_type is None: + return CommonExecutionResult(False, reason=f'Bucks Type {bucks_type} was not valid.') + bucks_tracker: BucksTrackerBase = cls.get_bucks_tracker(sim_info, bucks_type, add_if_none=False) + if bucks_tracker is None: + return CommonExecutionResult(False, reason=f'{sim_info} does not have a tracker for the specified bucks. {bucks_type}') + bucks_tracker.lock_all_perks(vanilla_bucks_type, refund_cost=refund_cost or remove_perk_points) + if remove_perk_points: + cls.set_bucks(sim_info, bucks_type, 0, reason=reason, **__) + return CommonExecutionResult.TRUE + + @classmethod + def lock_all_perks(cls, sim_info: SimInfo, bucks_type: Union[CommonBucksType, BucksType], refund_cost: bool = True) -> CommonExecutionResult: + """lock_all_perks(sim_info, bucks_type, refund_cost=True) + + Lock all perks of a specific Bucks type for a Sim. + + .. note:: A Sim needs to be spawned before their perks can be locked. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param bucks_type: The Bucks associated with the perks being locked. + :type bucks_type: Union[CommonBucksType, BucksType] + :param refund_cost: Set True to refund the cost of all unlocked perks. Set False to give no perk points back. Default is True + :type refund_cost: bool, optional + :return: The result of executing the function. True, if successful. False, if not. + :rtype: CommonExecutionResult + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return CommonExecutionResult(False, reason=f'{sim_info} is not currently spawned. They need to be spawned before all of their perks can be locked.') + vanilla_bucks_type = CommonBucksType.convert_to_vanilla(bucks_type) + if vanilla_bucks_type is None: + return CommonExecutionResult(False, reason=f'Bucks Type {bucks_type} was not valid.') + bucks_tracker: BucksTrackerBase = cls.get_bucks_tracker(sim_info, bucks_type, add_if_none=True) + if bucks_tracker is None: + return CommonExecutionResult(False, reason=f'{sim_info} does not have a tracker for the specified bucks. {bucks_type}') + bucks_tracker.lock_all_perks(vanilla_bucks_type, refund_cost=refund_cost) + return CommonExecutionResult.TRUE + + @classmethod + def has_perk_unlocked(cls, sim_info: SimInfo, perk: Union[BucksPerk, int]) -> CommonTestResult: + """has_perk_unlocked(sim_info, perk) + + Determine if a Sim has a perk unlocked. + + .. note:: A Sim needs to be spawned to check this. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param perk: The perk to lock. + :type perk: Union[BucksPerk, int] + :return: The result of the test. True, if the test passed. False, if the test failed. + :rtype: CommonTestResult + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return CommonTestResult(False, reason=f'{sim_info} is not currently spawned. They need to be spawned before all of their perks can be locked.') + perk = cls.load_perk_by_guid(perk) + if perk is None: + return CommonTestResult(False, reason=f'Failed to locate perk by id {perk}') + bucks_type = cls.get_perk_bucks_type(perk) + if bucks_type is None: + return CommonTestResult(False, reason=f'Bucks Type {bucks_type} was not valid.') + bucks_tracker: BucksTrackerBase = cls.get_bucks_tracker(sim_info, bucks_type, add_if_none=True) + if bucks_tracker is None: + return CommonTestResult(False, reason=f'{sim_info} does not have a tracker for the specified bucks. {bucks_type}') + if bucks_tracker.is_perk_unlocked(perk): + return CommonTestResult(True, reason=f'{sim_info} has perk {perk} unlocked.') + return CommonTestResult(False, reason=f'{sim_info} does not have perk {perk} unlocked.') + + @classmethod + def has_perk_locked(cls, sim_info: SimInfo, perk: Union[BucksPerk, int]) -> CommonTestResult: + """has_perk_locked(sim_info, perk) + + Determine if a Sim has a perk locked. + + .. note:: The Sim being checked needs to be spawned. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param perk: The perk to check. + :type perk: Union[BucksPerk, int] + :return: The result of the test. True, if the test passed. False, if the test failed. + :rtype: CommonTestResult + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return CommonTestResult(False, reason=f'{sim_info} is not currently spawned. They need to be spawned before all of their perks can be locked.') + perk = cls.load_perk_by_guid(perk) + if perk is None: + return CommonTestResult(False, reason=f'Failed to locate perk by id {perk}') + bucks_type = cls.get_perk_bucks_type(perk) + if bucks_type is None: + return CommonTestResult(False, reason=f'Bucks Type {bucks_type} was not valid.') + bucks_tracker: BucksTrackerBase = cls.get_bucks_tracker(sim_info, bucks_type, add_if_none=True) + if bucks_tracker is None: + return CommonTestResult(False, reason=f'{sim_info} does not have a tracker for the specified bucks. {bucks_type}') + if not bucks_tracker.is_perk_unlocked(perk): + return CommonTestResult(True, reason=f'{sim_info} has perk {perk} locked.') + return CommonTestResult(False, reason=f'{sim_info} does not have perk {perk} locked.') + + @classmethod + def lock_perk(cls, sim_info: SimInfo, perk: Union[BucksPerk, int], refund_cost: bool = True) -> CommonExecutionResult: + """lock_perk(sim_info, perk, refund_cost=True) + + Lock a perk for a Sim. + + .. note:: A Sim needs to be spawned before their perks can be locked. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param perk: The perk to lock. + :type perk: Union[BucksPerk, int] + :param refund_cost: Set True to refund the cost of the perk. Set False to give no perk points back. Default is True + :type refund_cost: bool, optional + :return: The result of executing the function. True, if successful. False, if not. + :rtype: CommonExecutionResult + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return CommonExecutionResult(False, reason=f'{sim_info} is not currently spawned. They need to be spawned before all of their perks can be locked.') + perk = cls.load_perk_by_guid(perk) + if perk is None: + return CommonExecutionResult(False, reason=f'Failed to locate perk by id {perk}') + bucks_type = cls.get_perk_bucks_type(perk) + if bucks_type is None: + return CommonExecutionResult(False, reason=f'Bucks Type {bucks_type} was not valid.') + bucks_tracker: BucksTrackerBase = cls.get_bucks_tracker(sim_info, bucks_type, add_if_none=True) + if bucks_tracker is None: + return CommonExecutionResult(False, reason=f'{sim_info} does not have a tracker for the specified bucks. {bucks_type}') + bucks_tracker.lock_perk(perk, refund_cost=refund_cost) + return CommonExecutionResult.TRUE + + @classmethod + def unlock_perk(cls, sim_info: SimInfo, perk: Union[BucksPerk, int], no_cost: bool = False) -> CommonExecutionResult: + """unlock_perk(sim_info, perk, no_cost=True) + + Unlock a perk. + + .. note:: A Sim needs to be spawned before their perks can be unlocked. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param perk: The perk to lock. + :type perk: Union[BucksPerk, int] + :param no_cost: Set True to unlock the perk without spending perk points. Set False to spend perk points to unlock the perk.. Default is False + :type no_cost: bool, optional + :return: The result of executing the function. True, if successful. False, if not. + :rtype: CommonExecutionResult + """ + if cls.has_perk_unlocked(sim_info, perk): + return CommonExecutionResult(True, reason=f'Perk {perk} is already unlocked.') + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return CommonExecutionResult(False, reason=f'{sim_info} is not currently spawned. They need to be spawned before all of their perks can be locked.') + perk = cls.load_perk_by_guid(perk) + if perk is None: + return CommonExecutionResult(False, reason=f'Failed to locate perk by id {perk}') + bucks_type = cls.get_perk_bucks_type(perk) + if bucks_type is None: + return CommonExecutionResult(False, reason=f'Bucks Type {bucks_type} was not valid.') + bucks_tracker: BucksTrackerBase = cls.get_bucks_tracker(sim_info, bucks_type, add_if_none=True) + if bucks_tracker is None: + return CommonExecutionResult(False, reason=f'{sim_info} does not have a tracker for the specified bucks. {bucks_type}') + if cls.has_perk_unlocked(sim_info, perk): + return CommonExecutionResult(True, reason=f'Perk {perk} is already unlocked.') + modified_for_cost = False + if no_cost: + if not cls.can_afford_perk(sim_info, perk): + unlock_cost = cls.get_perk_unlock_cost(perk) + modify_result = cls.modify_bucks(sim_info, bucks_type, unlock_cost, reason='Perk being unlocked at no cost.') + if not modify_result: + return modify_result + modified_for_cost = True + elif not cls.can_afford_perk(sim_info, perk): + return CommonExecutionResult(False, reason=f'{sim_info} cannot afford perk {perk}.') + if bucks_tracker.pay_for_and_unlock_perk(perk): + if not modified_for_cost: + unlock_cost = cls.get_perk_unlock_cost(perk) + modify_result = cls.modify_bucks(sim_info, bucks_type, unlock_cost, reason='Perk being unlocked at no cost.') + if not modify_result: + return modify_result + return CommonExecutionResult.TRUE + + @classmethod + def can_afford_perk(cls, sim_info: SimInfo, perk: Union[BucksPerk, int]) -> CommonTestResult: + """can_afford_perk(sim_info, perk) + + Determine if a Sim can afford to purchase a perk. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param perk: The perk to check. + :type perk: Union[BucksPerk, int] + :return: The result of the test. True, if the perk can be afforded by the Sim. False, if not. + :rtype: CommonTestResult + """ + perk = cls.load_perk_by_guid(perk) + if perk is None: + return CommonTestResult(False, reason=f'Failed to locate perk by id {perk}') + bucks_type = cls.get_perk_bucks_type(perk) + if bucks_type == CommonBucksType.INVALID: + return CommonTestResult(False, reason=f'Failed to determine the bucks type of the perk {perk}') + bucks_tracker: BucksTrackerBase = cls.get_bucks_tracker(sim_info, bucks_type, add_if_none=False) + if bucks_tracker is None: + return CommonTestResult(False, reason=f'{sim_info} does not have a tracker for the specified bucks. {bucks_type}') + bucks_amount = cls.get_bucks_amount(sim_info, bucks_type) + perk_cost = cls.get_perk_unlock_cost(perk) + if bucks_amount < perk_cost: + return CommonTestResult(False, reason=f'{sim_info} cannot afford perk {perk}.') + return CommonTestResult(True, reason=f'{sim_info} can afford perk {perk}.') + + @classmethod + def get_available_perks_gen(cls, sim_info: SimInfo, bucks_type: Union[CommonBucksType, BucksType]) -> Iterator[BucksPerk]: + """get_available_perks_gen(sim_info, bucks_type) + + Retrieve all available Perks for the specified Bucks Type and Sim. + + .. note:: A Sim needs to be spawned before perks can be checked. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param bucks_type: The Bucks associated with the perks being returned. + :type bucks_type: Union[CommonBucksType, BucksType] + :return: An iterator of Bucks Perks available to a Sim, regardless of locked status. + :rtype: Iterator[BucksPerk] + """ + vanilla_bucks_type = CommonBucksType.convert_to_vanilla(bucks_type) + if vanilla_bucks_type is None: + return tuple() + bucks_tracker: BucksTrackerBase = cls.get_bucks_tracker(sim_info, bucks_type, add_if_none=True) + if bucks_tracker is None: + return tuple() + yield from bucks_tracker.all_perks_of_type_gen(vanilla_bucks_type) + + @classmethod + def get_locked_perks_gen(cls, sim_info: SimInfo, bucks_type: Union[CommonBucksType, BucksType]) -> Iterator[BucksPerk]: + """get_locked_perks_gen(sim_info, bucks_type) + + Retrieve all Perks for the specified Bucks Type a Sim has locked. + + .. note:: A Sim needs to be spawned before perks can be checked. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param bucks_type: The Bucks associated with the perks being returned. + :type bucks_type: Union[CommonBucksType, BucksType] + :return: An iterator of Bucks Perks that are locked for a Sim. + :rtype: Iterator[BucksPerk] + """ + vanilla_bucks_type = CommonBucksType.convert_to_vanilla(bucks_type) + if vanilla_bucks_type is None: + return tuple() + bucks_tracker: BucksTrackerBase = cls.get_bucks_tracker(sim_info, bucks_type, add_if_none=True) + if bucks_tracker is None: + return tuple() + yield from bucks_tracker.all_perks_of_type_with_lock_state_gen(vanilla_bucks_type, True) + + @classmethod + def get_unlocked_perks_gen(cls, sim_info: SimInfo, bucks_type: Union[CommonBucksType, BucksType]) -> Iterator[BucksPerk]: + """get_unlocked_perks_gen(sim_info, bucks_type) + + Retrieve all Perks for the specified Bucks Type a Sim has unlocked. + + .. note:: A Sim needs to be spawned before perks can be checked. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param bucks_type: The Bucks associated with the perks being returned. + :type bucks_type: Union[CommonBucksType, BucksType] + :return: An iterator of Bucks Perks that are unlocked for a Sim. + :rtype: Iterator[BucksPerk] + """ + vanilla_bucks_type = CommonBucksType.convert_to_vanilla(bucks_type) + if vanilla_bucks_type is None: + return tuple() + bucks_tracker: BucksTrackerBase = cls.get_bucks_tracker(sim_info, bucks_type, add_if_none=True) + if bucks_tracker is None: + return tuple() + yield from bucks_tracker.all_perks_of_type_with_lock_state_gen(vanilla_bucks_type, False) + + @classmethod + def get_bucks_amount(cls, sim_info: SimInfo, bucks_type: Union[CommonBucksType, BucksType]) -> int: + """get_bucks_amount(sim_info, bucks_type) + + Retrieve the number of available bucks to a Sim. + + .. note:: A Sim needs to be spawned before bucks can be checked. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param bucks_type: The Bucks associated with the amount to return. + :type bucks_type: Union[CommonBucksType, BucksType] + :return: The number of available bucks to a Sim for the specified Bucks Type or 0 if the Sim is not spawned, the bucks type does not exist, or a bucks tracker is not found. + :rtype: int + """ + vanilla_bucks_type = CommonBucksType.convert_to_vanilla(bucks_type) + if vanilla_bucks_type is None: + return 0 + bucks_tracker: BucksTrackerBase = cls.get_bucks_tracker(sim_info, bucks_type, add_if_none=False) + if bucks_tracker is None: + return 0 + return bucks_tracker.get_bucks_amount_for_type(vanilla_bucks_type) + + @classmethod + def modify_bucks(cls, sim_info: SimInfo, bucks_type: Union[CommonBucksType, BucksType], amount: int, reason: str = None, **__) -> CommonExecutionResult: + """modify_bucks(sim_info, bucks_type, amount, reason=None, **__) + + Modify the number of points available for a specific Bucks Type. + + .. note:: A Sim needs to be spawned before their Bucks can be modified. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param bucks_type: The Bucks associated with the perk points. + :type bucks_type: Union[CommonBucksType, BucksType] + :param amount: The amount of points that will be added/removed from the Sim. + :type amount: int + :param reason: The reason the perk points are being modified. Default is None. + :type reason: str, optional + :return: The result of executing the function. True, if successful. False, if not. + :rtype: CommonExecutionResult + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return CommonExecutionResult(False, reason=f'{sim_info} is not currently spawned. They need to be spawned before their perk points can be modified.') + vanilla_bucks_type = CommonBucksType.convert_to_vanilla(bucks_type) + if vanilla_bucks_type is None: + return CommonExecutionResult(False, reason=f'Bucks Type {bucks_type} was not valid.') + bucks_tracker: BucksTrackerBase = cls.get_bucks_tracker(sim_info, bucks_type, add_if_none=True) + if bucks_tracker is None: + return CommonExecutionResult(False, reason=f'{sim_info} does not have a tracker for the specified bucks. {bucks_type}') + current_bucks_count = cls.get_bucks_amount(sim_info, bucks_type) + if amount < 0 and ((amount * -1) > current_bucks_count): + amount = -current_bucks_count + bucks_tracker.try_modify_bucks(vanilla_bucks_type, amount, reason=reason, **__) + return CommonExecutionResult.TRUE + + @classmethod + def set_bucks(cls, sim_info: SimInfo, bucks_type: Union[CommonBucksType, BucksType], amount: int, reason: str = None, **__) -> CommonExecutionResult: + """set_bucks(sim_info, bucks_type, amount, reason=None, **__) + + Set the amount of Bucks available to a Sim. + + .. note:: A Sim needs to be spawned before their Bucks can be modified. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param bucks_type: The Bucks associated with the perk points. + :type bucks_type: Union[CommonBucksType, BucksType] + :param amount: The amount of points that will be available to the Sim. The value should be at or above zero. + :type amount: int + :param reason: The reason the perk points are being modified. Default is None. + :type reason: str, optional + :return: The result of executing the function. True, if successful. False, if not. + :rtype: CommonExecutionResult + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return CommonExecutionResult(False, reason=f'{sim_info} is not currently spawned. They need to be spawned before their perk points can be modified.') + vanilla_bucks_type = CommonBucksType.convert_to_vanilla(bucks_type) + if vanilla_bucks_type is None: + return CommonExecutionResult(False, reason=f'Bucks Type {bucks_type} was not valid.') + bucks_tracker: BucksTrackerBase = cls.get_bucks_tracker(sim_info, bucks_type, add_if_none=True) + if bucks_tracker is None: + return CommonExecutionResult(False, reason=f'{sim_info} does not have a tracker for the specified bucks. {bucks_type}') + if amount < 0: + amount = 0 + current_bucks_amount = cls.get_bucks_amount(sim_info, bucks_type) + if current_bucks_amount > 0: + bucks_tracker.try_modify_bucks(vanilla_bucks_type, -current_bucks_amount, reason=reason) + bucks_tracker.try_modify_bucks(vanilla_bucks_type, amount, reason=reason, **__) + return CommonExecutionResult.TRUE + + @classmethod + def get_perk_unlock_cost(cls, perk: Union[BucksPerk, int]) -> int: + """get_perk_unlock_cost(sim_info, perk) + + Retrieve the amount of points a perk costs to unlock. + + :param perk: The identifier or instance of a Perk. + :type perk: Union[BucksPerk, int] + :return: The amount of points the perk costs to unlock. + :rtype: int + """ + perk = cls.load_perk_by_guid(perk) + if perk is None: + return 0 + if hasattr(perk, 'unlock_cost'): + return perk.unlock_cost + return 0 + + @classmethod + def get_perk_bucks_type(cls, perk: Union[BucksPerk, int]) -> CommonBucksType: + """get_perk_bucks_type(sim_info, perk) + + Retrieve the Bucks Type associated with a Perk. + + :param perk: The identifier or instance of a Perk. + :type perk: Union[BucksPerk, int] + :return: The type of bucks the perk is associated to. + :rtype: CommonBucksType + """ + perk = cls.load_perk_by_guid(perk) + if perk is None: + return CommonBucksType.INVALID + if hasattr(perk, 'associated_bucks_type'): + return CommonBucksType.convert_from_vanilla(perk.associated_bucks_type) + return CommonBucksType.INVALID + + @classmethod + def get_bucks_tracker(cls, sim_info: SimInfo, bucks_type: Union[CommonBucksType, BucksType], add_if_none: bool = False) -> Union[BucksTrackerBase, None]: + """get_bucks_tracker(sim_info, bucks_type, add_if_none=False) + + Retrieve the tracker on a Sim for a specified bucks type. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param bucks_type: The type of tracker to retrieve. + :type bucks_type: Union[CommonBucksType, BucksType] + :param add_if_none: Set True, to add the tracker to the Sim when it does not exist. Set False to only return the tracker if it exists. Default is False. + :type add_if_none: bool, optional + :return: The tracker on the Sim associated with the specified Bucks Type or None when not found. + :rtype: Union[BucksTrackerBase, None] + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return None + vanilla_bucks_type = CommonBucksType.convert_to_vanilla(bucks_type) + if vanilla_bucks_type is None: + return None + return BucksUtils.get_tracker_for_bucks_type(vanilla_bucks_type, owner_id=sim.id, add_if_none=add_if_none) + + @classmethod + def load_perk_by_guid(cls, perk: Union[int, BucksPerk]) -> Union[BucksPerk, None]: + """load_perk_by_guid(perk) + + Load an instance of a Bucks Perk by its GUID. + + :param perk: The decimal identifier of a Bucks Perk. + :type perk: Union[int, BucksPerk] + :return: An instance of a Bucks Perk matching the decimal identifier or None if not found. + :rtype: Union[BucksPerk, None] + """ + if isinstance(perk, BucksPerk): + return perk + # noinspection PyBroadException + try: + # noinspection PyCallingNonCallable + perk_instance = perk() + if isinstance(perk_instance, BucksPerk): + # noinspection PyTypeChecker + return perk + except: + pass + # noinspection PyBroadException + try: + perk: int = int(perk) + except: + # noinspection PyTypeChecker + perk: BucksPerk = perk + return perk + + from sims4.resources import Types + from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + return CommonResourceUtils.load_instance(Types.BUCKS_PERK, perk) + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.set_bucks', + 'Set the number of Bucks a Sim has.', + command_arguments=( + CommonConsoleCommandArgument('bucks_type', 'CommonBucksType', 'The type of bucks to modify.'), + CommonConsoleCommandArgument('amount', 'Number', 'The number of Bucks to set. If below zero, this value will become zero.'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Id or Name of a Sim to modify.', + is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.set_perk_points', + ) +) +def _common_set_bucks( + output: CommonConsoleCommandOutput, + bucks_type: CommonBucksType, + amount: int, + sim_info: SimInfo = None +): + output(f'Setting {bucks_type.name} Bucks to {amount} for Sim {sim_info}') + result = CommonSimBucksUtils.set_bucks(sim_info, bucks_type, amount, reason='S4CL Console Command') + if result: + output(f'Successfully set {bucks_type.name} Bucks to {amount} for Sim {sim_info}') + else: + output(f'Failed to set {bucks_type.name} Bucks {amount} for Sim {sim_info}. Reason: {result.reason}') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.add_bucks', + 'Add Bucks to a Sim.', + command_arguments=( + CommonConsoleCommandArgument('bucks_type', 'CommonBucksType', 'The type of bucks to modify.'), + CommonConsoleCommandArgument('amount', 'Number', 'The number of Bucks to add.'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Id or Name of a Sim to modify.', + is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.add_perk_points', + ) +) +def _common_add_bucks( + output: CommonConsoleCommandOutput, + bucks_type: CommonBucksType, + amount: int, + sim_info: SimInfo = None +): + if bucks_type is None: + return False + output(f'Adding {amount} {bucks_type.name} Bucks to Sim {sim_info}') + result = CommonSimBucksUtils.modify_bucks(sim_info, bucks_type, amount, reason='S4CL Console Command') + if result: + output(f'Successfully added {amount} {bucks_type.name} Bucks to Sim {sim_info}') + else: + output(f'Failed to add {amount} {bucks_type.name} Bucks to Sim {sim_info}. Reason: {result.reason}') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.remove_bucks', + 'Add Bucks from a Sim.', + command_arguments=( + CommonConsoleCommandArgument('bucks_type', 'CommonBucksType', 'The type of bucks to modify.'), + CommonConsoleCommandArgument('amount', 'Number', 'The number of Bucks to remove.'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Id or Name of a Sim to modify.', + is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.remove_perk_points', + ) +) +def _common_remove_bucks( + output: CommonConsoleCommandOutput, + bucks_type: CommonBucksType, + amount: int, + sim_info: SimInfo = None +): + if bucks_type is None: + return False + output(f'Removing {amount} {bucks_type.name} Bucks from Sim {sim_info}') + result = CommonSimBucksUtils.modify_bucks(sim_info, bucks_type, -amount, reason='S4CL Console Command') + if result: + output(f'Successfully removed {amount} {bucks_type.name} Bucks from Sim {sim_info}') + else: + output(f'Failed to remove {amount} {bucks_type.name} Bucks from Sim {sim_info}. Reason: {result.reason}') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.unlock_perk', + 'Unlock a Bucks perk for a Sim.', + command_arguments=( + CommonConsoleCommandArgument('perk', 'Perk Id or Tuning Name', 'The decimal identifier or name of a perk to unlock.'), + CommonConsoleCommandArgument('no_cost', 'True or False', 'If True, the perk will be unlocked for free. If False, the perk will be unlocked using points (The Sim must have enough points).', is_optional=True, default_value=True), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Id or Name of a Sim to modify.', + is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.add_perk', + ) +) +def _common_add_perks( + output: CommonConsoleCommandOutput, + perk: TunableInstanceParam(Types.BUCKS_PERK), + no_cost: bool = True, + sim_info: SimInfo = None +): + if isinstance(perk, str): + output(f'No perk found for {perk}') + return False + cost_text = ' at No Cost' if no_cost else '' + output(f'Unlocking perk {perk} for Sim {sim_info}{cost_text}.') + result = CommonSimBucksUtils.unlock_perk(sim_info, perk, no_cost=no_cost) + if result: + output(f'Successfully unlocked perk {perk} for Sim {sim_info}.') + else: + output(f'Failed to unlock perk {perk} for Sim {sim_info}. Reason: {result.reason}') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.lock_perk', + 'Lock a Bucks Perk for a Sim.', + command_arguments=( + CommonConsoleCommandArgument('perk', 'Perk Id or Tuning Name', + 'The decimal identifier or name of a perk to lock.'), + CommonConsoleCommandArgument('refund_cost', 'True or False', + 'If True, the cost to unlock the perk will be refunded to the Sim. If False, the cost of to unlock the perk will not be refunded.', + is_optional=True, default_value=True), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Id or Name of a Sim to modify.', + is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.remove_perk', + ) +) +def _common_remove_perk( + output: CommonConsoleCommandOutput, + perk: TunableInstanceParam(Types.BUCKS_PERK), + refund_cost: bool = True, + sim_info: SimInfo = None +): + if isinstance(perk, str): + output(f'No perk found for {perk}') + return False + cost_text = ' at No Cost' if refund_cost else '' + output(f'Unlocking perk {perk} for Sim {sim_info}{cost_text}.') + result = CommonSimBucksUtils.lock_perk(sim_info, perk, refund_cost=refund_cost) + if result: + output(f'Successfully unlocked perk {perk} for Sim {sim_info}.') + else: + output(f'Failed to unlock perk {perk} for Sim {sim_info}. Reason: {result.reason}') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.lock_all_perks', + 'Lock all Bucks Perk for a Sim.', + command_arguments=( + CommonConsoleCommandArgument('bucks_type', 'CommonBucksType', 'The type of bucks to remove the perks of.'), + CommonConsoleCommandArgument('refund_cost', 'True or False', + 'If True, the cost to unlock the perks will be refunded to the Sim. If False, the cost of to unlock the perks will not be refunded.', + is_optional=True, default_value=True), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Id or Name of a Sim to modify.', + is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.remove_all_perks', + ) +) +def _common_remove_all_perks( + output: CommonConsoleCommandOutput, + bucks_type: CommonBucksType, + refund_cost: bool = True, + sim_info: SimInfo = None +): + if bucks_type is None: + return False + cost_text = ' and refunding the Cost' if refund_cost else '' + output(f'Locking all perks for Sim {sim_info}{cost_text}.') + result = CommonSimBucksUtils.remove_all_perks(sim_info, bucks_type, refund_cost=refund_cost) + if result: + output(f'Successfully locked all {bucks_type.name} perk for Sim {sim_info}.') + else: + output(f'Failed to lock all {bucks_type.name} perks for Sim {sim_info}. Reason: {result.reason}') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.unlock_all_perks', + 'Unlock all Bucks Perk for a Sim.', + command_arguments=( + CommonConsoleCommandArgument('bucks_type', 'CommonBucksType', 'The type of bucks to add the perks of.'), + CommonConsoleCommandArgument('no_cost', 'True or False', 'If True, the perk will be unlocked for free. If False, the perk will be unlocked using points (The Sim must have enough points).', is_optional=True, default_value=True), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Id or Name of a Sim to modify.', + is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.add_all_perks', + ) +) +def _common_add_all_perks( + output: CommonConsoleCommandOutput, + bucks_type: CommonBucksType, + no_cost: bool = True, + sim_info: SimInfo = None +): + if bucks_type is None: + return False + cost_text = ' at No Cost' if no_cost else '' + output(f'Unlocking all {bucks_type.name} perks for Sim {sim_info}{cost_text}.') + result = CommonSimBucksUtils.add_all_perks(sim_info, bucks_type, no_cost=no_cost) + if result: + output(f'Successfully unlocked all {bucks_type.name} perks for Sim {sim_info}.') + else: + output(f'Failed to unlock all {bucks_type.name} perks for Sim {sim_info}. Reason: {result.reason}') diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_career_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_career_utils.py new file mode 100644 index 0000000..64cacec --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_career_utils.py @@ -0,0 +1,965 @@ +""" +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 +""" +import random +from typing import Union, Callable, Iterator, Tuple + +import services +from careers.career_enums import CareerShiftType, CareerCategory +from careers.career_event import CareerEvent +from careers.career_history import CareerHistory +from careers.career_tracker import CareerTracker +from careers.career_tuning import Career, CareerLevel, TunableCareerTrack +from event_testing.resolver import SingleSimResolver +from rewards.reward_enums import RewardType +from server_commands.argument_helpers import TunableInstanceParam +from sims.sim_info import SimInfo +from sims4.resources import Types +from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + CommonConsoleCommandArgument +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.common_time_utils import CommonTimeUtils +from sims4communitylib.utils.location.common_location_utils import CommonLocationUtils +from sims4communitylib.utils.sims.common_career_track_utils import CommonCareerTrackUtils +from sims4communitylib.utils.sims.common_career_utils import CommonCareerUtils +from sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils +from sims4communitylib.utils.sims.common_sim_type_utils import CommonSimTypeUtils +from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils +from singletons import DEFAULT + + +class CommonSimCareerUtils(_HasS4CLClassLog): + """ Utilities for manipulating the Careers of Sims. """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 'common_sim_career_utils' + + @classmethod + def get_career_by_category(cls, sim_info: SimInfo, career_category: CareerCategory) -> Union[Career, None]: + """get_career_by_category(sim_info, career_category) + + Retrieve the career of a Sim by its career category. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param career_category: The category to retrieve the career of. + :type career_category: CareerCategory + :return: A career matching the career category specified or None if not found. + :rtype: Union[Career, None] + """ + career_tracker = cls.get_career_tracker(sim_info) + if career_tracker is None: + return None + return next(career_tracker.get_careers_by_category_gen(career_category)) + + @classmethod + def get_all_careers_for_sim_gen(cls, sim_info: SimInfo, include_career_callback: Callable[[Career], bool]=None) -> Iterator[Career]: + """get_all_careers_for_sim_gen(sim_info, include_career_callback=None) + + Retrieve all Careers of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param include_career_callback: If the result of this callback is True, the Career of the Sim will be included in the results. If set to None, All Careers of the Sim will be included. Default is None. + :type include_career_callback: Callable[[Career], bool], optional + :return: An iterator of all Careers matching the `include_career_callback` filter. + :rtype: Iterator[Career] + """ + if sim_info is None: + return tuple() + career_tracker = cls.get_career_tracker(sim_info) + if career_tracker is None: + return tuple() + for career in career_tracker.careers.values(): + if include_career_callback is not None and not include_career_callback(career): + continue + yield career + + @classmethod + def has_career(cls, sim_info: SimInfo, career_identifier: Union[int, Career]) -> bool: + """has_career_by_guid(sim_info, career) + + Determine if a Sim has a Career. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param career_identifier: The Guid64 identifier of a Career, the decimal identifier of a Career, or a Career instance. + :type career_identifier: Union[int, Career] + :return: True, if the Sim has the specified Career. False, if not. + :rtype: bool + """ + return cls.get_career(sim_info, career_identifier) is not None + + @classmethod + def get_career(cls, sim_info: SimInfo, career_identifier: Union[int, Career]) -> Union[Career, None]: + """get_career(sim_info, career_identifier) + + Retrieve the Career of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param career_identifier: The Guid64 identifier of a Career, the decimal identifier of a Career, or a Career instance. + :type career_identifier: Union[int, Career] + :return: The career of the Sim that matches the identifier or None if not found. + :rtype: Union[Career, None] + """ + if sim_info is None or career_identifier is None: + return None + if not isinstance(career_identifier, Career): + cls.get_log().format_with_message('Identifier was not a Career instance. Attempting to load it now.', career_identifier=career_identifier) + career_identifier = CommonCareerUtils.load_career_by_guid(career_identifier) + career_guid = CommonCareerUtils.get_career_guid(career_identifier) + career_id = CommonCareerUtils.get_career_id(career_identifier) + if career_guid is None and career_id is None: + return None + cls.get_log().format_with_message('Checking for career info.', career_identifier=career_identifier, career_guid=career_guid, career_id=career_id) + career_tracker = cls.get_career_tracker(sim_info) + if career_tracker is None: + return None + for career in cls.get_all_careers_for_sim_gen(sim_info): + if (career_guid is not None and career_guid != -1 and CommonCareerUtils.get_career_guid(career) == career_guid)\ + or (career_id is not None and career_id != -1 and CommonCareerUtils.get_career_id(career) == career_id)\ + or career is career_identifier: + cls.get_log().format_with_message('Successfully found career.', career=career, career_identifier=career_identifier, career_guid=career_guid, career_id=career_id, checked_career_guid=CommonCareerUtils.get_career_guid(career), checked_career_id=CommonCareerUtils.get_career_id(career)) + return career + cls.get_log().format_with_message('Failed to locate career.', career_identifier=career_identifier, career_guid=career_guid, career_id=career_id) + return None + + @classmethod + def has_career_at_current_zone(cls, sim_info: SimInfo) -> bool: + """has_career_at_current_zone(sim_info) + + Determine if a Sim has a Career at the current zone. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: True, if the Sim has a Career at the current zone. False, if not. + :rtype: bool + """ + return cls.get_career_at_current_zone(sim_info) + + @classmethod + def get_career_at_current_zone(cls, sim_info: SimInfo) -> Union[Career, None]: + """get_career_at_current_zone(sim_info) + + Retrieve the Career of a Sim that has its location set to the current zone. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: True, if the Sim works at the current zone. False, if not. + :rtype: bool + """ + if sim_info is None: + return None + current_zone_id = CommonLocationUtils.get_current_zone_id() + for career in cls.get_all_careers_for_sim_gen(sim_info): + career_zone_id = CommonCareerUtils.get_career_location_zone_id(career) + if career_zone_id == 0: + continue + if career_zone_id == current_zone_id: + return career + return None + + @classmethod + def is_at_work(cls, sim_info: SimInfo) -> bool: + """is_at_work(sim_info) + + Determine if a Sim is currently at work. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: True, if the Sim is currently at work for any of their careers. False, if not. + :rtype: bool + """ + for career in cls.get_all_careers_for_sim_gen(sim_info): + if career.currently_at_work: + return True + return False + + @classmethod + def has_career_tracker(cls, sim_info: SimInfo) -> bool: + """has_career_tracker(sim_info) + + Determine if a Sim has a career tracker or not. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: True, if the Sim has a career tracker. False, if not. + :rtype: bool + """ + return cls.get_career_tracker(sim_info) is not None + + @classmethod + def get_career_tracker(cls, sim_info: SimInfo) -> Union[CareerTracker, None]: + """get_career_tracker(sim_info) + + Retrieve a career tracker for a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The career tracker of the Sim or None if not found. + :rtype: Union[CareerTracker, None] + """ + if sim_info is None: + return None + # noinspection PyTypeChecker + return sim_info.career_tracker + + @classmethod + def is_taking_part_in_active_career_event(cls, sim_info: SimInfo) -> bool: + """is_taking_part_in_active_career_event(sim_info) + + Determine if a Sim is taking part in an active career event. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: True, if the Sim is taking part in an active career event. False, if not. + :rtype: bool + """ + if sim_info is None: + return False + return any(career.is_at_active_event for career in sim_info.careers.values()) + + @classmethod + def is_sim_household_part_of_active_career_event(cls, sim_info: SimInfo) -> bool: + """is_household_part_of_active_career_event(sim_info) + + Determine if any members of a Sims Household are part of an active career event. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: True, if any members of the Sims Household are taking part in an active career event. False, if not. + :rtype: bool + """ + if sim_info is None: + return False + household = CommonHouseholdUtils.get_household(sim_info) + for sim_info in CommonHouseholdUtils.get_sim_info_of_all_sims_in_household_generator(household): + if cls.is_taking_part_in_active_career_event(sim_info): + return True + return False + + @classmethod + def attend_career(cls, career: Career, allow_career_events: bool=True) -> CommonExecutionResult: + """attend_career(career, allow_career_events=True) + + Start a career without running any career events (If they are an active career). + + :param career: The career to mark. + :type career: Career + :param allow_career_events: If True, a career event will be started for active careers. If False, a career event will not be started for active careers. No effect on non active careers. Default is True. + :rtype: allow_career_events: bool, optional + :return: Tbe result of the action. + :rtype: CommonExecutionResult + """ + if allow_career_events and career.is_active: + return cls.start_active_career_on_current_lot(career) + + if services.get_persistence_service().is_save_locked(): + return CommonExecutionResult(False, reason='Currently save locked.') + if not services.get_career_service().enabled: + return CommonExecutionResult(False, reason='Career service is not enabled.') + from date_and_time import create_time_span + start_time = CommonTimeUtils.get_current_date_and_time() + end_time = start_time + create_time_span(hours=10) + + if start_time > end_time: + return CommonExecutionResult(False, reason='Start time is greater than end time.') + + career._at_work = False + career._career_session_extended = False + gig = career.get_current_gig() + if gig is not None: + gig.prep_time_end() + + career._current_work_start = start_time + career._current_work_end = end_time + career._current_work_duration = career._current_work_end - career._current_work_start + career._create_work_session_alarms() + career.resend_at_work_info() + if gig is None or gig.odd_job_tuning is None: + tracker = career._sim_info.get_tracker(career.WORK_SESSION_PERFORMANCE_CHANGE) + if tracker is not None: + career._sim_info.add_statistic(career.WORK_SESSION_PERFORMANCE_CHANGE, career.WORK_SESSION_PERFORMANCE_CHANGE.initial_value) + + if career.is_school_career and not career._sim_info.is_npc: + career.reset_homework_help() + + career.active_days_worked_statistic.add_value(1) + career.resend_at_work_info() + career.attend_work(start_tones=False) + from careers.career_base import TELEMETRY_WORKDAY_TYPE_ACTIVE + career._send_workday_info_telemetry(TELEMETRY_WORKDAY_TYPE_ACTIVE) + return CommonExecutionResult.TRUE + + @classmethod + def start_active_career_on_current_lot(cls, career: Career, career_event: CareerEvent=None) -> CommonExecutionResult: + """start_active_career_on_current_lot(career, career_event=None) + + Start a career event on the current lot for an Active career. + + .. note:: This function only works if the Career is flagged as an Active Career (is_active in the Tuning). + + :param career: The career to begin. + :type career: Career + :param career_event: The career event to trigger. If set to None, a random career event will be chosen from the career. Default is None. + :type career_event: CareerEvent, optional + :return: Tbe result of the action. + :rtype: CommonExecutionResult + """ + if career is None: + raise AssertionError('career was None.') + if not career.is_active: + return CommonExecutionResult(False, reason='Career is not an active career.') + if services.get_persistence_service().is_save_locked(): + return CommonExecutionResult(False, reason='Currently save locked.') + if not services.get_career_service().enabled: + return CommonExecutionResult(False, reason='Career service is not enabled.') + from date_and_time import create_time_span + start_time = CommonTimeUtils.get_current_date_and_time() + end_time = start_time + create_time_span(hours=10) + + if start_time > end_time: + return CommonExecutionResult(False, reason='Start time is greater than end time.') + + career._at_work = False + career._career_session_extended = False + gig = career.get_current_gig() + if gig is not None: + gig.prep_time_end() + + career._current_work_start = start_time + career._current_work_end = end_time + career._current_work_duration = career._current_work_end - career._current_work_start + career._create_work_session_alarms() + career.resend_at_work_info() + if gig is None or gig.odd_job_tuning is None: + tracker = career._sim_info.get_tracker(career.WORK_SESSION_PERFORMANCE_CHANGE) + if tracker is not None: + career._sim_info.add_statistic(career.WORK_SESSION_PERFORMANCE_CHANGE, career.WORK_SESSION_PERFORMANCE_CHANGE.initial_value) + if career.is_school_career and not career._sim_info.is_npc: + career.reset_homework_help() + + if career._sim_info.is_npc: + return CommonExecutionResult(False, reason='Sim is an NPC, NPCs are not allowed to start active careers.') + + import careers.career_base + current_gig = career.get_current_gig() + if career_event is None: + if career._sim_info in careers.career_base._career_event_overrides: + career_event = careers.career_base._career_event_overrides.pop(career._sim_info) + elif current_gig is not None and current_gig.career_events: + career_event = current_gig.get_random_gig_event() + else: + career._prune_stale_career_event_cooldowns() + resolver = SingleSimResolver(career._sim_info) + available_events = tuple(event for event in career.career_events if career.is_career_event_on_cooldown(event) or event.tests.run_tests(resolver)) + if not available_events: + return CommonExecutionResult(False, reason='No events were available.') + household = career._sim_info.household + for sim_info in household.sim_info_gen(): + if cls.is_taking_part_in_active_career_event(sim_info): + return CommonExecutionResult(False, reason='Sim is already at the active event.') + career_event = random.choice(available_events) + + career.on_career_event_accepted(career_event) + return CommonExecutionResult.TRUE + + @classmethod + def randomize_career( + cls, + sim_info: SimInfo, + randomize_career_level: bool = True, + remove_all_existing_careers: bool = True, + randomize_agency: bool = True, + use_career_history: bool = True, + force_out_of_retirement: bool = True, + force_quit_previous_jobs: bool = True, + check_availability: bool = True + ) -> CommonExecutionResult: + """set_random_career(\ + sim_info,\ + choose_random_career_level=True,\ + remove_all_existing_careers=True,\ + randomize_agent=True,\ + use_career_history=True,\ + force_out_of_retirement=False,\ + force_quit_previous_jobs=False,\ + check_availability=True\ + ) + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param randomize_career_level: If True, a random Career Level will be chosen in addition to the Career. If False, the Career Level will be dictated by the Sim that is joining. Default is True. + :type randomize_career_level: bool, optional + :param remove_all_existing_careers: If True, all careers the Sim is currently a part of will be removed. If False, the existing careers of the Sim will not be removed. Default is False. + :type remove_all_existing_careers: bool, optional + :param randomize_agency: If True, a random agency from available agencies will be randomly chosen for a Career that has agencies upon being added. If False, the "Select An Agency" dialog will appear. Default is True. + :type randomize_agency: bool, optional + :param force_out_of_retirement: If True, the Sim will be forced out of retirement without prompting the player. If False, a dialog will prompt the player to choose whether or not to come out of retirement. Default is False. + :type force_out_of_retirement: bool, optional + :param force_quit_previous_jobs: If True, the Sim will be forced to quit all of their previous jobs. If False, a confirmation will display that will prompt the player whether this should happen or not. Default is False. + :type force_quit_previous_jobs: bool, optional + :param use_career_history: If True, then the career history of the Sim will be used when adding the Career. If False, then the career history of the Sim will not be used when adding the Career. Default is True. + :type use_career_history: bool, optional + :param check_availability: If True, every career will be checked for availability before becoming available. If False, every career regardless of availability will be selectable. Default is True. WARNING: A Career that is not allowed for a Sim may be chosen if this is set to False! + :type check_availability: bool, optional + :return: The result of setting their career. + :rtype: CommonExecutionResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + if remove_all_existing_careers: + cls.remove_careers(sim_info) + + def _career_is_available(_career: Career) -> bool: + if not check_availability: + return True + return bool(cls.is_career_available_for_sim(sim_info, _career, from_join=True)) + + all_careers = tuple(CommonCareerUtils.get_all_careers_generator(include_career_callback=_career_is_available)) + if not all_careers: + return CommonExecutionResult(False, reason='No careers found to be available for Sim.') + cls.get_log().format_with_message('Found all available careers.', careers=sorted([f'{career.__name__} ({CommonCareerUtils.get_career_guid(career)})' for career in all_careers], key=lambda x: x)) + chosen_career = random.choice(all_careers) + career_level = None + if randomize_career_level: + career_levels = CommonCareerUtils.get_career_levels(chosen_career) + if career_levels: + career_level = random.choice(career_levels) + result = cls.add_career(sim_info, chosen_career, randomize_agency=randomize_agency, career_level=career_level, use_career_history=use_career_history, force_out_of_retirement=force_out_of_retirement, force_quit_previous_jobs=force_quit_previous_jobs) + if not result: + return result + return CommonExecutionResult(True, reason=f'{chosen_career.__name__}') + + @classmethod + def is_career_available_for_sim(cls, sim_info: SimInfo, career: Career, from_join: bool=False) -> CommonTestResult: + """is_career_available_for_sim(sim_info, career, from_join=False) + + Determine if a Career is available for a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param career: A career. + :type career: Career + :param from_join: Use to flag whether the career is planned to be tested as though the Sim is joining it. Default is False. + :type from_join: bool, optional + :return: The result of testing for availability. True, if the Career is available for the specified Sim. False, if not. + :rtype: CommonTestResult + """ + # noinspection PyTypeChecker + non_playable_career_ids: Tuple[int] = ( + 223698, # University_BaseCareer + 231099, # career_Batuu + 207004, # career_OddJob + 209979, # university_CourseSlot_A + 209984, # university_CourseSlot_B + 209988, # university_CourseSlot_C + 209989, # university_CourseSlot_D + 260893, # careers_VillagerHelp + 206791, # careers_Adult_Freelancer_No_Agency + ) + # noinspection PyTypeChecker + allowed_non_displayed_career_ids: Tuple[int] = ( + 205686, # career_Adult_Freelancer_Artist + 207568, # careers_Adult_Freelancer_Agency_Programmer + 207579, # careers_Adult_Freelancer_Agency_Writer + 214782, # careers_Adult_Freelancer_Agency_Fashion_Photographer + 232809, # careers_Adult_Freelancer_Agency_Maker + 252593, # careers_Adult_Freelancer_Agency_ParanormalInvestigator + ) + if not CommonSimTypeUtils.is_non_player_sim(sim_info): + if 'npc' in career.__name__.lower(): + return CommonTestResult(False, reason='The Career is an NPC career and the Sim is not an NPC.') + career_guid = CommonCareerUtils.get_career_guid(career) + if career_guid in non_playable_career_ids: + return CommonTestResult(False, reason='Career is non playable.') + valid_result = career.is_valid_career(sim_info=sim_info, from_join=from_join) + if not valid_result: + return valid_result + if career_guid not in allowed_non_displayed_career_ids: + if from_join and not career.show_career_in_join_career_picker: + return CommonTestResult(False, reason='Career is not joinable through normal means.') + return CommonTestResult.TRUE + + @classmethod + def add_career( + cls, + sim_info: SimInfo, + career_identifier: Union[int, Career], + remove_all_existing_careers: bool = False, + randomize_agency: bool = True, + use_career_history: bool = True, + force_out_of_retirement: bool = False, + force_quit_previous_jobs: bool = False, + show_confirmation_dialog: bool = False, + user_level: int = None, + career_level: CareerLevel = None, + give_skipped_rewards: bool = True, + defer_rewards: bool = False, + show_post_quit_message: bool = True, + schedule_shift_override: CareerShiftType = CareerShiftType.ALL_DAY, + show_join_message: bool = True, + disallowed_reward_types: Tuple[RewardType] = (), + force_rewards_to_sim_info_inventory: bool = False, + defer_first_assignment: bool = False, + schedule_init_only: bool = False, + allow_outfit_generation: bool = True + ) -> CommonExecutionResult: + """add_career(\ + sim_info,\ + career_identifier,\ + remove_all_existing_careers=False,\ + randomize_agency=True,\ + use_career_history=True,\ + force_out_of_retirement=False,\ + force_quit_previous_jobs=False,\ + show_confirmation_dialog=False,\ + user_level=None,\ + career_level=None,\ + give_skipped_rewards=True,\ + defer_rewards=False,\ + show_post_quit_message=True,\ + schedule_shift_override=CareerShiftType.ALL_DAY,\ + show_join_message=True,\ + disallowed_reward_types=(),\ + force_rewards_to_sim_info_inventory=False,\ + defer_first_assignment=False,\ + schedule_init_only=False,\ + allow_outfit_generation=True\ + ) + + Add a Career to a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param career_identifier: The Guid64 identifier of a Career, the decimal identifier of a Career, or a Career instance. + :type career_identifier: Union[int, Career] + :param remove_all_existing_careers: If True, all careers the Sim is currently a part of will be removed. If False, the existing careers of the Sim will not be removed. Default is False. + :type remove_all_existing_careers: bool, optional + :param randomize_agency: If True, a random agency from available agencies will be randomly chosen for a Career that has agencies upon being added. If False, the "Select An Agency" dialog will appear. Default is True. + :type randomize_agency: bool, optional + :param use_career_history: If True, then the career history of the Sim will be used when adding the Career. If False, then the career history of the Sim will not be used when adding the Career. Default is True. + :type use_career_history: bool, optional + :param force_out_of_retirement: If True, the Sim will be forced out of retirement without prompting the player. If False, a dialog will prompt the player to choose whether or not to come out of retirement. Default is False. + :type force_out_of_retirement: bool, optional + :param force_quit_previous_jobs: If True, the Sim will be forced to quit all of their previous jobs. If False, a confirmation will display that will prompt the player whether this should happen or not. Default is False. + :type force_quit_previous_jobs: bool, optional + :param show_confirmation_dialog: Show Confirmation Dialog. Default is False. + :type show_confirmation_dialog: bool, optional + :param user_level: The level of the career track to assign to the Sim upon joining the career. Default is None. + :type user_level: int, optional + :param career_level: The Career Level to set the Sim to upon joining the career. Default is None. + :type career_level: CareerLevel, optional + :param give_skipped_rewards: If True, any rewards skipped due to the career level skips will be given to the Sim upon joining the career. If False, no rewards will be given for career levels before the one they join into. Default is True. + :type give_skipped_rewards: bool, optional + :param defer_rewards: If True, rewards will be deferred until later. If False, rewards will be given immediately. Default is False. + :type defer_rewards: bool, optional + :param show_post_quit_message: If True, the quit message for their existing career before switching will be displayed. If False, the quit message will not be displayed. Default is True. + :type show_post_quit_message: bool, optional + :param schedule_shift_override: An override for the Sims shift schedule. Default is CareerShiftType.ALL_DAY. + :type schedule_shift_override: CareerShiftType, optional + :param show_join_message: If True, the joined career message will be displayed after joining the career. If False, the join message will not be displayed. Default is True. + :type show_join_message: bool, optional + :param disallowed_reward_types: A collection of rewards types not allowed to be collected by the Sim that is joining. If empty, all rewards will be allowed to be rewarded. Default is empty. + :type disallowed_reward_types: Tuple[RewardType], optional + :param force_rewards_to_sim_info_inventory: If True, rewards will be forced in the inventory of the joining Sim. If False, rewards will be sent to their intended locations as specified by the career. Default is False. + :type force_rewards_to_sim_info_inventory: bool, optional + :param defer_first_assignment: If True, the first assignment upon joining the career will be delayed until later. If False, the first assignment will not be delayed. Default is False. + :type defer_first_assignment: bool, optional + :param schedule_init_only: If True, Shift schedule will only be initialized. If False, Shift schedule will be setup fully. Default is False. + :type schedule_init_only: bool, optional + :param allow_outfit_generation: If True, an outfit for the career will be generated upon join. If False, an outfit will not be generated. Default is True. + :type allow_outfit_generation: bool, optional + :return: The result of adding the Career or the reason why it was not properly added. + :rtype: CommonExecutionResult + """ + if sim_info is None or career_identifier is None: + return CommonExecutionResult(False, reason=f'Sim or Career Identifier was None Sim: {sim_info} ID: {career_identifier}.') + if remove_all_existing_careers: + cls.remove_careers(sim_info) + career = CommonCareerUtils.load_career_by_guid(career_identifier) + career_tracker = cls.get_career_tracker(sim_info) + if career_tracker is None: + return CommonExecutionResult(False, reason=f'The Sim did not have a career tracker. {sim_info}') + if career_tracker.has_career_by_uid(CommonCareerUtils.get_career_guid(career)): + cls.get_log().format_with_message('Sim already had the specified career.', sim=sim_info, career=career) + return CommonExecutionResult.TRUE + + picked_track: Union[TunableCareerTrack, None] = None + if career_level is None and user_level is not None: + (career_level_index, _, picked_track) = CommonCareerUtils.determine_entry_level_into_career_from_user_level(career, user_level) + picked_track: TunableCareerTrack = picked_track + career_level = CommonCareerTrackUtils.get_career_level_by_index(picked_track, career_level_index) + elif career_level is None: + entry_level_values = tuple(cls.determine_entry_level_into_career_for_sim(sim_info, career, use_career_history=use_career_history)) + cls.get_log().format_with_message('Got entry level values', entry_level_values=entry_level_values) + if len(entry_level_values) == 1: + entry_level_values = entry_level_values[0] + (career_level_index, _, picked_track) = entry_level_values + picked_track: TunableCareerTrack = picked_track + career_level = CommonCareerTrackUtils.get_career_level_by_index(picked_track, career_level_index) + cls.get_log().format_with_message('Got career level.', career_level=career_level_index, returned_user_level=_, picked_track=picked_track) + + if career_level is None: + cls.get_log().format_with_message('No career level found.', sim=sim_info, career_history=career_tracker.career_history, career=career) + return CommonExecutionResult(False, reason=f'Failed to locate career level for Sim {sim_info}, Career {career}, and Career History {career_tracker.career_history}.') + + cls.get_log().format_with_message('Adding new career.', picked_track=picked_track, career_level=career_level, sim=sim_info, career=career) + new_career = career_level.career(sim_info) + return cls._add_career( + career_tracker, + new_career, + randomize_agency=randomize_agency, + use_career_history=use_career_history, + force_out_of_retirement=force_out_of_retirement, + force_quit_previous_jobs=force_quit_previous_jobs, + show_confirmation_dialog=show_confirmation_dialog, + user_level_override=user_level, + career_level_override=career_level, + give_skipped_rewards=give_skipped_rewards, + defer_rewards=defer_rewards, + post_quit_msg=show_post_quit_message, + schedule_shift_override=schedule_shift_override, + show_join_msg=show_join_message, + disallowed_reward_types=disallowed_reward_types, + force_rewards_to_sim_info_inventory=force_rewards_to_sim_info_inventory, + defer_first_assignment=defer_first_assignment, + schedule_init_only=schedule_init_only, + allow_outfit_generation=allow_outfit_generation + ) + + @classmethod + def _add_career( + cls, + career_tracker: CareerTracker, + new_career: Career, + randomize_agency: bool = True, + use_career_history: bool = True, + force_out_of_retirement: bool = False, + force_quit_previous_jobs: bool = False, + show_confirmation_dialog = False, + user_level_override: int = None, + career_level_override: CareerLevel = None, + give_skipped_rewards: bool = True, + defer_rewards: bool = False, + post_quit_msg: bool = True, + schedule_shift_override = CareerShiftType.ALL_DAY, + show_join_msg: bool = True, + disallowed_reward_types: Tuple[RewardType] = (), + force_rewards_to_sim_info_inventory: bool = False, + defer_first_assignment: bool = False, + schedule_init_only: bool = False, + allow_outfit_generation: bool = True + ) -> CommonExecutionResult: + if show_confirmation_dialog: + (level, _, track) = new_career.get_career_entry_data(career_history=career_tracker._career_history, user_level_override=user_level_override, career_level_override=career_level_override) + career_level_tuning = CommonCareerTrackUtils.get_career_level_by_index(track, level) + if career_tracker._retirement is not None: + def _on_unretire_confirmation_dialog_response(dialog, _disallowed_reward_types: Tuple[RewardType]=disallowed_reward_types) -> None: + if not dialog.accepted: + return + cls._add_career( + career_tracker, + new_career, + randomize_agency=randomize_agency, + use_career_history=use_career_history, + force_out_of_retirement=True, + force_quit_previous_jobs=force_quit_previous_jobs, + show_confirmation_dialog=show_confirmation_dialog, + user_level_override=user_level_override, + career_level_override=career_level_override, + give_skipped_rewards=give_skipped_rewards, + defer_rewards=defer_rewards, + post_quit_msg=post_quit_msg, + schedule_shift_override=schedule_shift_override, + show_join_msg=show_join_msg, + disallowed_reward_types=_disallowed_reward_types, + force_rewards_to_sim_info_inventory=force_rewards_to_sim_info_inventory, + defer_first_assignment=defer_first_assignment, + schedule_init_only=schedule_init_only, + allow_outfit_generation=allow_outfit_generation + ) + + if not force_out_of_retirement: + career_tracker._retirement.send_dialog(Career.UNRETIRE_DIALOG, career_level_tuning.get_title(career_tracker._sim_info), icon_override=DEFAULT, on_response=lambda dialog: _on_unretire_confirmation_dialog_response(dialog)) + cls.get_log().format_with_message('Sim is retired.') + return CommonExecutionResult(False, reason='Sim was retired.') + + if new_career.can_quit: + def _on_quit_confirmation_dialog_response(dialog, _disallowed_reward_types: Tuple[RewardType]=disallowed_reward_types) -> None: + if not dialog.accepted: + return + cls._add_career( + career_tracker, + new_career, + randomize_agency=randomize_agency, + use_career_history=use_career_history, + force_out_of_retirement=force_out_of_retirement, + force_quit_previous_jobs=True, + show_confirmation_dialog=show_confirmation_dialog, + user_level_override=user_level_override, + career_level_override=career_level_override, + give_skipped_rewards=give_skipped_rewards, + defer_rewards=defer_rewards, + post_quit_msg=post_quit_msg, + schedule_shift_override=schedule_shift_override, + show_join_msg=show_join_msg, + disallowed_reward_types=_disallowed_reward_types, + force_rewards_to_sim_info_inventory=force_rewards_to_sim_info_inventory, + defer_first_assignment=defer_first_assignment, + schedule_init_only=schedule_init_only, + allow_outfit_generation=allow_outfit_generation + ) + + quittable_careers = career_tracker.get_quittable_careers(schedule_shift_type=schedule_shift_override) + if quittable_careers and not force_quit_previous_jobs: + career = next(iter(quittable_careers.values())) + switch_jobs_dialog = Career.SWITCH_JOBS_DIALOG + if len(quittable_careers) > 1: + switch_jobs_dialog = Career.SWITCH_MANY_JOBS_DIALOG + career.send_career_message(switch_jobs_dialog, career_level_tuning.get_title(career_tracker._sim_info), icon_override=DEFAULT, on_response=lambda dialog: _on_quit_confirmation_dialog_response(dialog, _disallowed_reward_types=(RewardType.MONEY,))) + cls.get_log().format_with_message('Sim has quittable careers. Too many jobs!') + return CommonExecutionResult(False, reason='Sim had existing jobs, they need to be quit before.') + + cls.get_log().format_with_message('Doing end retirement.') + career_tracker.end_retirement() + career_tracker.remove_custom_career_data(send_update=False) + if new_career.guid64 in career_tracker._careers: + cls.get_log().format_with_message('Attempting to add career that Sim is already in.', career=new_career, sim=career_tracker._sim_info) + return CommonExecutionResult(False, reason='Sim already had the career.') + if new_career.can_quit: + career_tracker.quit_quittable_careers(post_quit_msg=post_quit_msg, schedule_shift_type=schedule_shift_override) + career_tracker._careers[new_career.guid64] = new_career + result = cls._join_career( + new_career, + randomize_agency=randomize_agency, + career_history=career_tracker._career_history if use_career_history else None, + user_level_override=user_level_override, + career_level_override=career_level_override, + give_skipped_rewards=give_skipped_rewards, + defer_rewards=defer_rewards, + schedule_shift_override=schedule_shift_override, + show_join_msg=show_join_msg, + disallowed_reward_types=disallowed_reward_types, + force_rewards_to_sim_info_inventory=force_rewards_to_sim_info_inventory, + defer_first_assignment=defer_first_assignment, + schedule_init_only=schedule_init_only, + allow_outfit_generation=allow_outfit_generation + ) + if not result: + return result + career_tracker.resend_career_data() + career_tracker.update_affordance_caches() + if career_tracker._on_promoted not in new_career.on_promoted: + new_career.on_promoted.append(career_tracker._on_promoted) + if career_tracker._on_demoted not in new_career.on_demoted: + new_career.on_demoted.append(career_tracker._on_demoted) + return CommonExecutionResult.TRUE + + @classmethod + def remove_careers( + cls, + sim_info: SimInfo, + show_post_quit_message: bool = False, + update_ui_after_remove: bool = True, + include_career_callback: Callable[[Career], bool] = None + ) -> None: + """remove_careers(\ + sim_info,\ + show_post_quit_message=False,\ + update_ui_after_remove=True,\ + include_career_callback=None\ + ) + + Remove Careers of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param show_post_quit_message: If True, the post quit message will show for each removed Career. If False, no post quit message will show for each removed Career. Default is False. + :type show_post_quit_message: bool, optional + :param update_ui_after_remove: If True, the UI will be updated after the Career is removed. If False, the UI will not be updated. Default is True. + :type update_ui_after_remove: bool, optional + :param include_career_callback: If the result of this callback is True, the Career of the Sim will be removed. If set to None, All Careers of the Sim will be removed. Default is None. + :type include_career_callback: Callable[[Career], bool], optional + """ + career_tracker = cls.get_career_tracker(sim_info) + if career_tracker is None: + return + to_remove_career_uids = list() + for (career_uid, career) in career_tracker.careers.items(): + if include_career_callback is not None and not include_career_callback(career): + continue + to_remove_career_uids.append(career_uid) + + for career_uid in to_remove_career_uids: + career_tracker.remove_career(career_uid, post_quit_msg=show_post_quit_message, update_ui=update_ui_after_remove) + + @classmethod + def _join_career( + cls, + career: Career, + randomize_agency: bool = True, + career_history: CareerHistory = None, + user_level_override: int = None, + career_level_override: int = None, + give_skipped_rewards: bool = True, + defer_rewards: bool = False, + schedule_shift_override: CareerShiftType = CareerShiftType.ALL_DAY, + show_join_msg: bool = True, + disallowed_reward_types: Tuple[RewardType] = (), + force_rewards_to_sim_info_inventory: bool = False, + defer_first_assignment: bool = False, + schedule_init_only: bool = False, + allow_outfit_generation: bool = True + ) -> CommonExecutionResult: + (new_level, new_user_level, current_track) = career.get_career_entry_data(career_history=career_history, user_level_override=user_level_override, career_level_override=career_level_override) + if defer_rewards: + career.defer_player_rewards() + career._current_track = current_track + career._join_time = services.time_service().sim_now + career._level = new_level + career._user_level = new_user_level + career._current_shift_type = schedule_shift_override + if career_history is not None: + career._load_days_worked_commodities(career_history, current_track) + career._reset_career_objectives(career._current_track, new_level) + starting_level = career._sim_info.career_tracker.get_highest_level_reached(career.guid64) + career._sim_info.career_tracker.update_history(career) + career.career_start(schedule_init_only=schedule_init_only, allow_outfit_generation=allow_outfit_generation) + career._setup_assignments_for_career_joined(defer_assignment=defer_first_assignment) + resolver = SingleSimResolver(career._sim_info) + for loot in career.current_level_tuning.loot_on_join: + if randomize_agency: + loot_guid = getattr(loot, 'guid64', None) + if loot_guid is None: + continue + # loot_Buff_ActorCareer_NewJob + if loot_guid == 192996: + agents_available = tuple(career.current_level_tuning.agents_available) + if agents_available: + chosen_agent = random.choice(agents_available) + if CommonTraitUtils.add_trait(career.sim_info, CommonTraitUtils.get_trait_id(chosen_agent)): + continue + loot.apply_to_resolver(resolver) + if give_skipped_rewards: + career._give_rewards_for_skipped_levels(starting_level=starting_level, disallowed_reward_types=disallowed_reward_types, force_rewards_to_sim_info_inventory=force_rewards_to_sim_info_inventory) + from careers.career_base import TELEMETRY_HOOK_CAREER_START + career._send_telemetry(TELEMETRY_HOOK_CAREER_START) + join_career_notification = career.career_messages.join_career_notification + if show_join_msg and career.display_career_info and join_career_notification is not None: + (_, first_work_time, _) = career.get_next_work_time() + career.send_career_message(join_career_notification, first_work_time) + career.add_coworker_relationship_bit() + career._add_career_knowledge() + return CommonExecutionResult.TRUE + + @classmethod + def determine_entry_level_into_career_for_sim( + cls, + sim_info: SimInfo, + career: Career, + use_career_history: bool = True + ) -> Tuple[Union[int, None], Union[int, None], Union[TunableCareerTrack, None]]: + """determine_entry_level_into_career_for_sim(sim_info, career, use_career_history=True) + + Determine the entry level into a Career for a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param career: The career to retrieve an entry level of. + :type career: Career + :param use_career_history: If True, then the career history of the Sim will be used when adding the Career. If False, then the career history of the Sim will not be used when adding the Career. Default is True. + :type use_career_history: bool, optional + :return: The career level for the career track (or branch career track) used, the level of the user in that career track, and the career track itself. + :rtype: Tuple[int, int, TunableCareerTrack] + """ + if sim_info is None: + return None, None, None + if use_career_history: + career_tracker = cls.get_career_tracker(sim_info) + if career_tracker is None: + return None, None, None + career_history = career_tracker.career_history + else: + career_history = None + return career.get_career_entry_level(career_history=career_history, resolver=SingleSimResolver(sim_info)) + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.has_career', + 'Check if a Sim has a career.', + command_arguments=( + CommonConsoleCommandArgument('career', 'Name or Decimal Id', 'The name or id of a career to check.'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of a Sim.', is_optional=True, default_value='Active Sim'), + ) +) +def _common_has_career(output: CommonConsoleCommandOutput, career: TunableInstanceParam(Types.CAREER), sim_info: SimInfo=None): + if sim_info is None: + return + output(f'Checking {sim_info} to see if they have career {career}') + if career is None: + output(f'Failed, Career does not exist.') + return False + if CommonSimCareerUtils.has_career(sim_info, career): + output(f'SUCCESS: Sim has the career.') + else: + output(f'FAILED: Sim does not have the career.') + return True + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.add_career', + 'Add a career to a Sim.', + command_arguments=( + CommonConsoleCommandArgument('career', 'Name or Decimal Id', 'The name or id of a career to add.'), + CommonConsoleCommandArgument('user_level', 'Number', 'The Career Level to put the Sim into for the Career.', is_optional=True, default_value='Starting Level'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of a Sim.', is_optional=True, default_value='Active Sim'), + ) +) +def _common_add_career(output: CommonConsoleCommandOutput, career: TunableInstanceParam(Types.CAREER), user_level: int=None, sim_info: SimInfo=None): + if sim_info is None: + return + output(f'Attempting to add career {career}') + if career is None: + output(f'Failed, Career does not exist.') + return False + output('Adding career') + result = CommonSimCareerUtils.add_career(sim_info, career, user_level=user_level, randomize_agency=True, use_career_history=False, show_confirmation_dialog=False) + if result: + output(f'SUCCESS: Career added.') + else: + output(f'FAILED: Failed to add career. {result.reason}') + return True + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.randomize_career', + 'Give a random career to a Sim.', + command_arguments=( + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of a Sim.', is_optional=True, default_value='Active Sim'), + ) +) +def _common_randomize_career(output: CommonConsoleCommandOutput, sim_info: SimInfo=None): + if sim_info is None: + return + output(f'Attempting to randomize career for Sim {sim_info}') + result = CommonSimCareerUtils.randomize_career(sim_info, remove_all_existing_careers=True, randomize_agency=True, use_career_history=False) + if result: + output(f'SUCCESS: Career randomized to {result.reason}') + else: + output(f'FAILED: Failed to randomize career. {result.reason}') + return True diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_club_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_club_utils.py new file mode 100644 index 0000000..711f2f2 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_club_utils.py @@ -0,0 +1,126 @@ +""" +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 +""" +from typing import Iterator, Callable, Union + +import services +from clubs.club import Club +from clubs.club_gathering_situation import ClubGatheringSituation +from sims.sim_info import SimInfo +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + + +class CommonSimClubUtils: + """ Utilities for manipulating the Clubs of Sims. """ + + @staticmethod + def is_engaged_in_club_gathering(sim_info: SimInfo) -> bool: + """is_engaged_in_club_gathering(sim_info) + + Determine if a Sim is engaged in a Club Gathering. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: True, if the Sim is engaged in a Club Gathering. False, if not. + :rtype: bool + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return False + club_service = services.get_club_service() + if club_service is None: + return False + return sim in club_service.sims_to_gatherings_map + + @staticmethod + def get_current_club_gathering(sim_info: SimInfo) -> Union[ClubGatheringSituation, None]: + """get_current_club_gathering(sim_info) + + Retrieve the Club Gathering a Sim is currently taking part in. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The Club Gathering the specified Sim is a part of or None if the Sim is not a part of any Club Gathering. + :rtype: Union[ClubGatheringSituation, None] + """ + if sim_info is None: + return None + club_service = services.get_club_service() + if club_service is None: + return None + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return None + return club_service.sims_to_gatherings_map.get(sim) + + @staticmethod + def get_clubs_gen(sim_info: SimInfo, include_club_callback: Callable[[Club], bool] = CommonFunctionUtils.noop_true) -> Iterator[Club]: + """get_clubs_gen(sim_info, include_club_callback=CommonFunctionUtils.noop_true) + + Retrieve all Clubs a Sim is a part of. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param include_club_callback: If the result of this callback is True, the Club will be included in the results. The default callback will allow all. + :type include_club_callback: Callable[[Club], bool], optional + :return: An iterator of all Clubs the specified Sim is a part of and that pass the include callback filter. + :rtype: Iterator[Club] + """ + if sim_info is None: + return tuple() + club_service = services.get_club_service() + if club_service is None: + return tuple() + for club in club_service.get_clubs_for_sim_info(sim_info): + if club is None or not include_club_callback(club): + continue + yield club + + @staticmethod + def get_clubs_currently_gathering_gen(sim_info: SimInfo, include_club_callback: Callable[[Club], bool] = CommonFunctionUtils.noop_true) -> Iterator[Club]: + """get_clubs_currently_gathering_gen(include_club_callback=CommonFunctionUtils.noop_true) + + Retrieve all Clubs the Sim is in that are currently hosting a gathering. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param include_club_callback: If the result of this callback is True, the Club will be included in the results. The default callback will allow all. + :type include_club_callback: Callable[[Club], bool], optional + :return: An iterator of all Clubs the Sim is in that are currently gathering and that pass the include_club_callback filter. + :rtype: Iterator[Club] + """ + if sim_info is None: + return tuple() + club_service = services.get_club_service() + if club_service is None: + return tuple() + sim_clubs = club_service.get_clubs_for_sim_info(sim_info) + for club in sim_clubs: + club_gathering = club_service.clubs_to_gatherings_map.get(club) + if club_gathering is None or not include_club_callback(club): + continue + yield club + + @staticmethod + def are_part_of_same_club_gathering(sim_info_a: SimInfo, sim_info_b: SimInfo) -> bool: + """are_part_of_same_club_gathering(sim_info_a, sim_info_b) + + Determine if two Sims are at the same Club Gathering + + :param sim_info_a: An instance of a Sim. + :type sim_info_a: SimInfo + :param sim_info_b: An instance of a Sim. + :type sim_info_b: SimInfo + :return: True, if Sim A is taking part in the same Club Gathering as Sim B. False, if not. + :rtype: bool + """ + sim_a_club_gathering = CommonSimClubUtils.get_current_club_gathering(sim_info_a) + sim_b_club_gathering = CommonSimClubUtils.get_current_club_gathering(sim_info_b) + if sim_a_club_gathering is None or sim_b_club_gathering is None: + return False + return sim_a_club_gathering == sim_b_club_gathering diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_crafting_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_crafting_utils.py new file mode 100644 index 0000000..34ba5fb --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_crafting_utils.py @@ -0,0 +1,104 @@ +""" +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 +""" +from random import Random +from typing import Union, Callable + +from objects.game_object import GameObject +from sims.sim import Sim +from sims.sim_info import SimInfo +from sims4communitylib.enums.common_object_quality import CommonObjectQuality +from sims4communitylib.utils.common_type_utils import CommonTypeUtils +from sims4communitylib.utils.objects.common_object_state_utils import CommonObjectStateUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + + +class CommonSimCraftingUtils: + """ Utilities for crafting various things. """ + @staticmethod + def create_from_recipe( + crafting_sim_info: SimInfo, + recipe_id: int, + inventory_target: Union[GameObject, Sim] = None, + set_target_as_owner: bool = True, + quality: CommonObjectQuality = None, + owning_household_id_override: int = None, + post_add: Callable[[GameObject], None] = None, + seeded_random: Random = None + ) -> Union[GameObject, None]: + """create_from_recipe(\ + crafting_sim_info,\ + recipe_id,\ + inventory_target=None,\ + set_target_as_owner=True,\ + owning_household_id_override=None,\ + post_add=None,\ + seeded_random=None,\ + ) + + Craft an item made by a Sim using a recipe and placing it in the inventory of an object or a Sim. + + .. note:: inventory_target must have an inventory_component attribute. + + :param crafting_sim_info: The name of this Sim will appear on the crafted object as being the crafter. + :type crafting_sim_info: SimInfo + :param recipe_id: The decimal identifier of a recipe for the object being created. + :type recipe_id: int + :param inventory_target: If set, the crafted object will be placed in the inventory of this object. If not set, the crafted object will be placed in the inventory of the Sim that crafted it. Default is None. + :type inventory_target: Union[GameObject, Sim] + :param set_target_as_owner: If True, the inventory where the crafted item will be placed will become the owner of the crafted item. If False, the crafted item will be owned by the one who created it. Default is True. + :type set_target_as_owner: bool, optional + :param owning_household_id_override: An override for which household to set as the owner of the crafted object. If not specified, then the crafting Sim will be the owner. If set_target_as_owner is True, then the target will be the owner regardless of what this argument is set to. Default is None. + :type owning_household_id_override: int, optional + :param post_add: A callback invoked when the object is created. Default is None. + :type post_add: Callable[[GameObject], None], optional + :param seeded_random: An instance of Random that will be used in various aspects of the created object. Default is None. + :type seeded_random: Random, optional + :param quality: The quality of the output object. Default is None. + :type quality: CommonObjectQuality, optional + :return: The crafted item, created from the specified recipe by the specified Sim, or None if an error occurs. + :rtype: Union[GameObject, None] + """ + if inventory_target is not None and not hasattr(inventory_target, 'inventory_component'): + raise AttributeError('The specified inventory_target did not have an inventory component.') + crafting_sim = CommonSimUtils.get_sim_instance(crafting_sim_info) + if crafting_sim is None: + return None + from sims4communitylib.utils.resources.common_recipe_utils import CommonRecipeUtils + recipe = CommonRecipeUtils.load_recipe_by_guid(recipe_id) + try: + from crafting.crafting_interactions import create_craftable + from sims4communitylib.utils.objects.common_object_ownership_utils import CommonObjectOwnershipUtils + from sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils + quality_state = CommonObjectStateUtils.convert_quality_to_object_state_value(quality) + if set_target_as_owner: + if CommonTypeUtils.is_sim_or_sim_info(inventory_target): + owning_sim_info = CommonSimUtils.get_sim_info(inventory_target) if inventory_target is not None else crafting_sim_info + owning_household_id_override = CommonHouseholdUtils.get_household_id(owning_sim_info) + elif inventory_target is not None: + owning_household_id_override = CommonObjectOwnershipUtils.get_owning_household_id(inventory_target) + crafted_item = create_craftable( + recipe, + crafting_sim, + inventory_owner=inventory_target, + place_in_inventory=True, + quality=quality_state, + owning_household_id_override=owning_household_id_override, + post_add=post_add, + seeded_random=seeded_random + ) + if crafted_item is not None: + if set_target_as_owner: + if CommonTypeUtils.is_sim_or_sim_info(inventory_target): + owning_sim_info = CommonSimUtils.get_sim_info(inventory_target) if inventory_target is not None else crafting_sim_info + CommonObjectOwnershipUtils.set_owning_sim(crafted_item, owning_sim_info) + elif inventory_target is not None: + owning_household_id = CommonObjectOwnershipUtils.get_owning_household_id(inventory_target) + CommonObjectOwnershipUtils.set_owning_household_id(crafted_item, owning_household_id) + return crafted_item + except ImportError: + return None diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_currency_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_currency_utils.py new file mode 100644 index 0000000..6d906e6 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_currency_utils.py @@ -0,0 +1,140 @@ +""" +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 +""" +from typing import Union + +from sims.funds import FamilyFunds +from sims.sim_info import SimInfo +from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from sims4communitylib.enums.common_currency_modify_reasons import CommonCurrencyModifyReason +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + CommonConsoleCommandArgument +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput + + +class CommonSimCurrencyUtils: + """Utilities for modifying various currency types of Sims. + + """ + @classmethod + def can_afford_simoleons(cls, sim_info: SimInfo, amount: int) -> bool: + """can_afford_simoleons(sim_info, amount) + + Determine if a Sim can afford an amount of simoleons. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param amount: The amount of simoleons to check. + :type amount: int + :return: True, if the household of the Sim can afford the simoleon amount. False, if not. + :rtype: bool + """ + household_funds = cls.get_household_funds(sim_info) + if household_funds is None: + return False + return household_funds.can_afford(amount) + + @classmethod + def add_simoleons_to_household(cls, sim_info: SimInfo, amount: int, reason: CommonCurrencyModifyReason, **kwargs) -> CommonExecutionResult: + """add_simoleons_to_household(sim_info, amount, reason, **kwargs) + + Add an amount of simoleons to the Household of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param amount: The amount of simoleons to add. + :type amount: int + :param reason: The reason the simoleons are being added. + :type reason: CommonCurrencyModifyReason + :return: True, if simoleons were added successfully. False, if not. + :rtype: bool + """ + household_funds = cls.get_household_funds(sim_info) + if household_funds is None: + return CommonExecutionResult(False, reason='The Sim was not a part of a household that has funds.') + household_funds.add(amount, reason, **kwargs) + return CommonExecutionResult.TRUE + + @classmethod + def remove_simoleons_from_household(cls, sim_info: SimInfo, amount: int, reason: CommonCurrencyModifyReason, require_full_amount: bool=True, **kwargs) -> float: + """remove_simoleons_from_household(sim_info, amount, reason, require_full_amount=True, **kwargs) + + Remove an amount of simoleons from the Household of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param amount: The amount of simoleons to add. + :type amount: int + :param reason: The reason the simoleons are being removed. + :type reason: CommonCurrencyModifyReason + :param require_full_amount: If True, then the Sim must have the full amount for the removal to be successful. If False, the Sim does not require the full amount. Default is True. + :type require_full_amount: bool, optional + :return: The amount of simoleons removed from the household of the specified Sim. This amount may be lower than the specified amount, if the Sim did not have enough simoleons for removal. + :rtype: float + """ + household_funds = cls.get_household_funds(sim_info) + if household_funds is None: + return 0.0 + return household_funds.try_remove_amount(amount, reason, require_full_amount=require_full_amount, **kwargs) + + @classmethod + def get_household_funds(cls, sim_info: SimInfo) -> Union[FamilyFunds, None]: + """get_household_funds(sim_info) + + Retrieve the Funds object that manages the Household Simoleons for the Household of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The FamilyFunds object of the Household of the specified Sim or None if the Sim did not have a Household. + :rtype: Union[FamilyFunds, None] + """ + from sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils + household = CommonHouseholdUtils.get_household(sim_info) + if household is None: + return None + return household.funds + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.add_simoleons', + 'Add simoleons to a household.', + command_arguments=( + CommonConsoleCommandArgument('amount', 'Number', 'The amount of money to add to the household.'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of a Sim.', is_optional=True, default_value='Active Sim'), + ) +) +def _common_add_simoleons(output: CommonConsoleCommandOutput, amount: int, sim_info: SimInfo=None): + if sim_info is None: + return False + result = CommonSimCurrencyUtils.add_simoleons_to_household(sim_info, amount, CommonCurrencyModifyReason.CHEAT) + if result: + output(f'SUCCESS: Successfully added currency to Sim {sim_info}') + return True + output(f'FAILED: Failed to add currency to Sim {sim_info}. {result.reason}') + return False + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.remove_simoleons', + 'Remove simoleons from a household.', + command_arguments=( + CommonConsoleCommandArgument('amount', 'Number', 'The amount of money to remove from the household.'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of a Sim.', is_optional=True, default_value='Active Sim'), + ) +) +def _common_add_simoleons(output: CommonConsoleCommandOutput, amount: int, sim_info: SimInfo=None): + if sim_info is None: + return False + result = CommonSimCurrencyUtils.add_simoleons_to_household(sim_info, amount, CommonCurrencyModifyReason.CHEAT) + if result: + output(f'SUCCESS: Successfully removed currency from Sim {sim_info}') + return True + output(f'FAILED: Failed to remove currency from Sim {sim_info}. {result.reason}') + return False diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_death_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_death_utils.py new file mode 100644 index 0000000..8e6f015 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_death_utils.py @@ -0,0 +1,472 @@ +""" +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 +""" +import random +from typing import Union, Callable, Iterator, Dict + +from interactions.utils.death import DeathType, DeathTracker +from objects.game_object import GameObject +from sims.ghost import Ghost +from sims.sim_info import SimInfo +from sims4communitylib.classes.math.common_location import CommonLocation +from sims4communitylib.classes.math.common_transform import CommonTransform +from sims4communitylib.classes.math.common_vector3 import CommonVector3 +from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.enums.common_death_types import CommonDeathType +from sims4communitylib.enums.common_region_id import CommonRegionId +from sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + CommonConsoleCommandArgument +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from sims4communitylib.utils.common_time_utils import CommonTimeUtils +from sims4communitylib.utils.location.common_location_utils import CommonLocationUtils +from sims4communitylib.utils.objects.common_object_spawn_utils import CommonObjectSpawnUtils +from sims4communitylib.utils.objects.common_object_state_utils import CommonObjectStateUtils +from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils +from sims4communitylib.utils.resources.common_interaction_utils import CommonInteractionUtils +from sims4communitylib.utils.sims.common_buff_utils import CommonBuffUtils +from sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils +from sims4communitylib.utils.sims.common_occult_utils import CommonOccultUtils +from sims4communitylib.utils.sims.common_sim_interaction_utils import CommonSimInteractionUtils +from sims4communitylib.utils.sims.common_sim_location_utils import CommonSimLocationUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils +from sims4communitylib.utils.time.common_alarm_utils import CommonAlarmUtils + + +class CommonSimDeathUtils(_HasS4CLClassLog): + """Utilities for manipulating the body of Sims. + + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 'common_sim_death_utils' + + @classmethod + def is_dead(cls, sim_info: SimInfo) -> CommonTestResult: + """is_dead(sim_info) + + Determine if a Sim is dead. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of the test. True, if it passes. False, if it fails. + :rtype: CommonTestResult + """ + if cls.get_death_type(sim_info) != CommonDeathType.NONE: + return CommonTestResult(True, reason=f'{sim_info} is dead.') + return CommonTestResult(False, reason=f'{sim_info} is not dead.') + + @classmethod + def get_sim_info_for_all_dead_sims_generator( + cls, + death_type: Union[CommonDeathType, DeathType] = None, + include_sim_callback: Callable[[SimInfo], Union[bool, CommonExecutionResult, CommonTestResult]] = None + ) -> Iterator[SimInfo]: + """get_sim_info_for_all_dead_sims_generator(death_type=None, include_sim_callback=None) + + Retrieve a SimInfo object for each and every Dead Sim. + + :param death_type: If specified, only Sims with this type of death will be returned, otherwise all Sims will be returned. + :type death_type: Union[CommonDeathType, DeathType], optional + :param include_sim_callback: If the result of this callback is True, the sim will be included in the results. If set to None, All sims will be included. + :type include_sim_callback: Callable[[SimInfo], bool], optional + :return: An iterator of all Sims matching the `include_sim_callback` filter. + :rtype: Iterator[SimInfo] + """ + if death_type is not None: + death_type = CommonDeathType.convert_from_vanilla(death_type) + + for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(include_sim_callback=include_sim_callback): + if sim_info is None: + continue + is_dead_result = cls.is_dead(sim_info) + if not is_dead_result: + continue + death_tracker = cls.get_death_tracker(sim_info) + if death_tracker is None: + _death_type = None + else: + _death_type = death_tracker.death_type + if death_type is not None and death_type != CommonDeathType.NONE: + sim_death_type = cls.get_death_type(sim_info) + if sim_death_type == CommonDeathType.NONE: + continue + if sim_death_type != death_type: + continue + yield sim_info + + @classmethod + def kill_sim( + cls, + sim_info: SimInfo, + death_type: Union[CommonDeathType, DeathType] + ) -> CommonExecutionResult: + """kill_sim(sim_info, death_type) + + Kill a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param death_type: The type of death to invoke upon the Sim. + :type death_type: Union[CommonDeathType, DeathType] + :return: The result of executing the function. True, if successful. False, if not. + :rtype: CommonExecutionResult + """ + if CommonSimUtils.get_sim_instance(sim_info) is None: + is_off_lot_death = True + else: + is_off_lot_death = False + death_tracker = cls.get_death_tracker(sim_info) + if death_tracker is None: + return CommonExecutionResult(False, reason=f'{sim_info} did not have a death tracker.') + if cls.is_dead(sim_info): + return CommonExecutionResult(True, reason=f'{sim_info} is already dead.') + if death_tracker.is_ghost: + return CommonExecutionResult(False, reason=f'{sim_info} is already a ghost.') + death_type = CommonDeathType.convert_from_vanilla(death_type) + if not is_off_lot_death: + def _on_object_spawned(_death_object: Union[GameObject, None]) -> None: + if _death_object is None: + return + death_interaction_id = cls.get_death_interaction(sim_info, death_type) + if death_interaction_id: + enqueue_result = CommonSimInteractionUtils.queue_interaction(sim_info, death_interaction_id, target=_death_object) + if not enqueue_result: + cls.get_log().format_error_with_message(f'Failed to kill {sim_info} via {death_type.name}.', result=enqueue_result) + else: + cls.get_log().format_with_message('Successfully queued death interaction.', result=enqueue_result) + + death_object = cls._spawn_death_related_object(sim_info, death_type, _on_object_spawned) + if death_object is not None: + def _on_destroy_alarm_triggered(_) -> None: + CommonObjectSpawnUtils.schedule_object_for_destroy(death_object) + + time_until_object_destroy = CommonTimeUtils.create_time_span(hours=1) + CommonAlarmUtils.schedule_alarm(CommonSimDeathUtils, time_until_first_occurrence=time_until_object_destroy, on_alarm_triggered_callback=_on_destroy_alarm_triggered) + return CommonExecutionResult.TRUE + + sim_household = CommonHouseholdUtils.get_household(sim_info) + death_tracker.set_death_type(CommonDeathType.convert_to_vanilla(death_type), is_off_lot_death=is_off_lot_death) + Ghost.make_ghost_if_needed(sim_info) + if sim_household is not None: + CommonHouseholdUtils.move_sim_to_household(sim_info, household_id=CommonHouseholdUtils.get_id(sim_household)) + return CommonExecutionResult.TRUE + + @classmethod + def _spawn_death_related_object(cls, sim_info: SimInfo, death_type: CommonDeathType, on_object_spawned: Callable[[Union[GameObject, None]], None]) -> Union[GameObject, None]: + mapping: Dict[CommonDeathType, int] = { + CommonDeathType.COW_PLANT: 22481, # cowplantGEN_01 + CommonDeathType.MURPHY_BED: 235916, # bedMurphy_SP16GEN_set1 + CommonDeathType.MOTHER_PLANT: 208953, # motherPlant_GP07GEN + } + + chosen_object_definition_id = mapping.get(death_type, None) + + vending_machine_ids = ( + 293171, # object_VendingMachine_HighSchool + 256973, # object_VendingMachine_Gachapon_Default + 256971, # vendingMachine_ColdDrinkAndSnack + 256970, # vendingMachine_HotFoodAndDrink + ) + + if death_type == CommonDeathType.VENDING_MACHINE: + chosen_object_definition_id = random.choice(vending_machine_ids) + + if chosen_object_definition_id is None or chosen_object_definition_id == 0: + on_object_spawned(None) + return None + + def _on_spawned(_game_object: GameObject): + if _game_object is None: + on_object_spawned(None) + return + + if death_type == CommonDeathType.MURPHY_BED: + murphy_bed_open_state = 228113 # murphy_Bed_Values_Open + CommonObjectStateUtils.set_object_state(_game_object, murphy_bed_open_state) + + if death_type == CommonDeathType.COW_PLANT: + cow_plant_mature_state = 32491 # Cowplant_GrowthState_Mature + CommonObjectStateUtils.set_object_state(_game_object, cow_plant_mature_state) + cow_plant_hungry_state = 15231 # Hunger_3_Hungry + CommonObjectStateUtils.set_object_state(_game_object, cow_plant_hungry_state) + CommonBuffUtils.add_buff(sim_info, 12396) # Buff_Drained + on_object_spawned(_game_object) + + location = CommonSimLocationUtils.get_location(sim_info) + loc_transform = location.transform + loc_translation = loc_transform.translation + new_transform = CommonVector3(loc_translation.x + 1, loc_translation.y, loc_translation.z) + spawn_location = CommonLocation(CommonTransform(new_transform, loc_transform.orientation), location.routing_surface) + + spawned_object = CommonObjectSpawnUtils.spawn_object_on_lot(chosen_object_definition_id, spawn_location, post_object_spawned_callback=_on_spawned) + if spawned_object is None: + on_object_spawned(None) + return None + return spawned_object + + @classmethod + def get_death_interaction(cls, sim_info: SimInfo, death_type: CommonDeathType) -> Union[int, None]: + """get_death_interaction(sim_info, death_type) + + Retrieve an appropriate death interaction for the Sim to die by. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param death_type: The type of death slated for the Sim. + :type death_type: CommonDeathType + :return: The decimal identifier of the interaction appropriate for the Sim to play a death animation with or None if not found. + :rtype: int + """ + mapping: Dict[CommonDeathType, int] = { + CommonDeathType.ANGER: 9252, # death_Anger + CommonDeathType.CLIMBING_ROUTE: 250185, # death_ClimbingRoute + CommonDeathType.DEATH_FLOWER_ARRANGEMENT: 190745, # death_ElderExhaustion_DeathFlower + CommonDeathType.ELDER_EXHAUSTION: 9316, # death_ElderExhaustion + CommonDeathType.EMBARRASSMENT: 32314, # death_Embarrassment + CommonDeathType.FIRE: 77372, # death_Fire + CommonDeathType.FLIES: 231091, # death_Flies + CommonDeathType.FROZEN: 182162, # death_Frozen + CommonDeathType.HUNGER: 13299, # death_Hunger + CommonDeathType.KILLER_CHICKEN: 267938, # death_AnimalObjects_Chicken_DeadOnGround + CommonDeathType.KILLER_RABBIT: 259988, # death_AnimalObjects_KillerRabbit + CommonDeathType.LAUGHTER: 9297, # death_Laughter + CommonDeathType.LIGHTNING: 186301, # death_Electrocution_Lightning + CommonDeathType.METEORITE: 286935, # death_Meteorite + CommonDeathType.MOTHER_PLANT: 204098, # death_MotherPlant + CommonDeathType.MURPHY_BED: 231080, # death_MurphyBed_NoLoveseat + CommonDeathType.OVERHEAT: 183022, # death_Overheat + CommonDeathType.POISON: 176190, # death_Poison + CommonDeathType.PUFFERFISH: 143418, # death_Initiator_Pufferfish + CommonDeathType.RODENT_DISEASE: 181916, # death_RodentDisease + CommonDeathType.STEAM: 119504, # death_SteamRoom + # Stink Bomb does not have an associated interaction. + # CommonDeathType.STINK_BOMB: 0, + CommonDeathType.SUN: 151542, # death_Vampire_Sun + # Urban Myth is reserved for Sims that are already a ghost. + # CommonDeathType.URBAN_MYTH: 0, + CommonDeathType.VENDING_MACHINE: 249705, # death_VendingMachine + CommonDeathType.WITCH_OVERLOAD: 216969, # death_WitchOverload + } + + if death_type == CommonDeathType.OLD_AGE: + if CommonSpeciesUtils.is_human(sim_info): + if CommonOccultUtils.is_robot(sim_info): + return 220401 # death_Solo_HumanoidRobot + return 13300 # death_OldAge + elif CommonSpeciesUtils.is_cat(sim_info): + return 159835 # death_OldAge_Cat + elif CommonSpeciesUtils.is_dog(sim_info): + return 159868 # death_OldAge_Dog + elif CommonSpeciesUtils.is_horse(sim_info): + return 321074 # death_OldAge_Horse + else: + return 265869 # death_OldAge_Fox + + if death_type == CommonDeathType.COW_PLANT: + if CommonOccultUtils.is_robot(sim_info): + return 229340 # death_Cowplant_HumanoidRobot + return 13298 # death_Cowplant + + # 220401, # death_Solo_HumanoidRobot + # 132535, # death_Pufferfish_SeatedAtSurface + # 132534, # death_Pufferfish + # 132609, # Death_Pufferfish_Seated + + ocean_drown_id = 211504 # Death_Drowning_Ocean + drown_interaction_ids = ( + 103463, # death_Drown + ocean_drown_id, + ) + if death_type == CommonDeathType.DROWN: + if CommonInteractionUtils.load_interaction_by_id(ocean_drown_id) is None: + return 103463 # death_Drown + return random.choice(drown_interaction_ids) + + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is not None: + if death_type == CommonDeathType.ELECTROCUTION: + if CommonLocationUtils.is_current_region(CommonRegionId.JUNGLE): + return 182673 # death_Electrocution_Jungle + if sim.is_outside: + return 186301 # death_Electrocution_Lightning + if CommonOccultUtils.is_robot(sim_info): + return 228257 # humanoid_Robots_ElectricOverload_Death + return 8650 # death_Electrocution + + # 284361 + # 284362 + # + # 98476 # rescueNeglectedChild + # 155605 # rescueNeglectedToddler + # 103810 # death_Netherworld + return mapping.get(death_type, None) + + @classmethod + def revive_sim(cls, sim_info: SimInfo) -> CommonExecutionResult: + """revive_sim(sim_info) + + Revive a Dead Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of executing the function. True, if successful. False, if not. + :rtype: CommonExecutionResult + """ + death_tracker = cls.get_death_tracker(sim_info) + if death_tracker is None: + return CommonExecutionResult(False, reason=f'{sim_info} did not have a death tracker.') + if death_tracker.death_type is None: + return CommonExecutionResult(True, reason=f'{sim_info} is not dead.') + urn_object_id = Ghost.get_urnstone_for_sim_id(CommonSimUtils.get_sim_id(sim_info)) + death_tracker.clear_death_type() + Ghost.remove_ghost_from_sim(sim_info) + game_object = CommonObjectUtils.get_game_object(urn_object_id) + CommonObjectSpawnUtils.schedule_object_for_destroy(game_object) + return CommonExecutionResult.TRUE + + @classmethod + def get_death_type(cls, sim_info: SimInfo) -> CommonDeathType: + """get_death_type(sim_info) + + Retrieve the type of Death the Sim was faced with. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The type of death the Sim succumbed to or NONE if the Sim is not dead. + :rtype: CommonDeathType + """ + death_tracker = cls.get_death_tracker(sim_info) + if death_tracker is None: + return CommonDeathType.NONE + return CommonDeathType.convert_from_vanilla(death_tracker.death_type) + + @classmethod + def get_death_tracker(cls, sim_info: SimInfo) -> Union[DeathTracker, None]: + """get_death_tracker(sim_info) + + Retrieve the death tracker for a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The death tracker for the Sim or None if not found. + :rtype: Union[DeathTracker, None] + """ + if sim_info is None: + return None + return sim_info.death_tracker + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.print_death', + 'Print information about a Sim and their death.', + command_arguments=( + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to modify.', is_optional=True, default_value='Active Sim'), + ) +) +def _common_print_death(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): + if not CommonSimDeathUtils.is_dead(sim_info): + output(f'Sim {sim_info} is not dead.') + return + death_type = CommonSimDeathUtils.get_death_type(sim_info) + if death_type == CommonDeathType.NONE: + output(f'Sim {sim_info} died in an unknown way.') + return + output(f'Sim {sim_info} died via {death_type.name}') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.kill_sim', + 'Greet a Sim with the Kiss of Death.', + command_arguments=( + CommonConsoleCommandArgument('death_type', 'Name of Death Type', 'The type of death to bring upon a Sim.', is_optional=True, default_value='Random'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to modify.', is_optional=True, default_value='Active Sim'), + ) +) +def _common_kill_all_sims(output: CommonConsoleCommandOutput, death_type: CommonDeathType = CommonDeathType.NONE, sim_info: SimInfo = None): + if death_type == CommonDeathType.NONE: + death_type = CommonDeathType.convert_from_vanilla(DeathType.get_random_death_type()) + household_count = CommonHouseholdUtils.get_number_of_sims_in_household_of_sim(sim_info) + if household_count == 1: + output('Bad things can happen when you kill the only member of a Household!') + return False + output(f'Killing Sim {sim_info} with death {death_type.name}.') + result = CommonSimDeathUtils.kill_sim(sim_info, death_type) + if result: + output(f'Successfully killed {sim_info} with death {death_type.name}.') + else: + output(f'Failed to kill {sim_info} with death {death_type.name}. Reason: {result}') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.kill_all_sims', + 'Greet all Sims with the Kiss of Death.', + command_arguments=( + CommonConsoleCommandArgument('death_type', 'Name of Death Type', 'The type of death to bring upon the Sims.', is_optional=True, default_value='Random'), + ) +) +def _common_kill_sim(output: CommonConsoleCommandOutput, death_type: CommonDeathType = CommonDeathType.NONE): + output(f'Killing Sims.') + kill_count = 0 + saved_count = 0 + for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(include_sim_callback=CommonFunctionUtils.run_predicate_with_reversed_result(CommonSimDeathUtils.is_dead)): + household_count = CommonHouseholdUtils.get_number_of_sims_in_household_of_sim(sim_info) + if household_count == 1: + saved_count += 1 + continue + if death_type == CommonDeathType.NONE: + death_type_override = CommonDeathType.convert_from_vanilla(DeathType.get_random_death_type()) + else: + death_type_override = death_type + result = CommonSimDeathUtils.kill_sim(sim_info, death_type_override) + if result: + kill_count += 1 + else: + saved_count += 1 + output(f'{kill_count} Sim(s) have met with a terrible fate.') + output(f'{saved_count} Sim(s) were spared a terrible fate.') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.revive_sim', + 'Revive a Sim and stop them being a ghost.', + command_arguments=( + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to modify.', is_optional=True, default_value='Active Sim'), + ) +) +def _common_revive_sim(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): + output(f'Reviving Sim {sim_info}.') + result = CommonSimDeathUtils.revive_sim(sim_info) + if result: + output(f'Successfully revived {sim_info}.') + else: + output(f'Failed to revive {sim_info}. Reason: {result}') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.revive_all_sims', + 'Revive all Sims and stop them from being spooky.' +) +def _common_revive_sim(output: CommonConsoleCommandOutput): + output(f'Reviving All Sims.') + revive_count = 0 + for sim_info in CommonSimDeathUtils.get_sim_info_for_all_dead_sims_generator(): + result = CommonSimDeathUtils.revive_sim(sim_info) + if result: + revive_count += 1 + output(f'{revive_count} Sim(s) have been blessed with life anew.') diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_demographic_type_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_demographic_type_utils.py new file mode 100644 index 0000000..c8f827b --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_demographic_type_utils.py @@ -0,0 +1,407 @@ +""" +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 +""" +from typing import Tuple, TYPE_CHECKING, Dict, List, Callable, Union, Iterator + +from sims.sim_info import SimInfo +from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog +from sims4communitylib.utils.math.common_bitwise_utils import CommonBitwiseUtils +from sims4communitylib.utils.sims.common_sim_occult_type_utils import CommonSimOccultTypeUtils +from sims4communitylib.utils.sims.common_sim_type_utils import CommonSimTypeUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + +if TYPE_CHECKING: + from sims4communitylib.enums.common_age import CommonAge + from sims4communitylib.enums.common_gender import CommonGender + from sims4communitylib.enums.common_species import CommonSpecies + from sims4communitylib.enums.common_occult_type import CommonOccultType + from sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType + + +class CommonSimDemographicTypeUtils(_HasS4CLClassLog): + """ Utilities for Sim Demographic types. """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 'common_sim_demographic_type_utils' + + @classmethod + def determine_sim_demographic_flags(cls, sim_info: SimInfo) -> 'CommonSimDemographicType': + """Determine the demographics of a Sim as flags.""" + from sims4communitylib.enums.common_age import CommonAge + from sims4communitylib.enums.common_gender import CommonGender + from sims4communitylib.enums.common_species import CommonSpecies + value: 'CommonSimDemographicType' = cls.convert_from_age(CommonAge.get_age(sim_info)) + value = CommonBitwiseUtils.add_flags(value, cls.convert_from_species(CommonSpecies.get_species(sim_info))) + value = CommonBitwiseUtils.add_flags(value, cls.convert_from_gender(CommonGender.get_gender(sim_info))) + value = CommonBitwiseUtils.add_flags(value, cls.convert_from_occult_type(CommonSimOccultTypeUtils.determine_current_occult_type(sim_info))) + return value + + @classmethod + def determine_sim_demographics(cls, sim_info: SimInfo) -> Tuple['CommonSimDemographicType']: + """Determine the demographics of a Sim as a collection.""" + from sims4communitylib.enums.common_age import CommonAge + from sims4communitylib.enums.common_gender import CommonGender + from sims4communitylib.enums.common_species import CommonSpecies + from sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType + values: List['CommonSimDemographicType'] = list() + values.append(cls.convert_from_species(CommonSpecies.get_species(sim_info))) + values.append(cls.convert_from_age(CommonAge.get_age(sim_info))) + values.append(cls.convert_from_gender(CommonGender.get_gender(sim_info))) + values.append(cls.convert_from_occult_type(CommonSimOccultTypeUtils.determine_current_occult_type(sim_info))) + if CommonSimUtils.is_active_sim(sim_info): + values.append(CommonSimDemographicType.CURRENTLY_CONTROLLED) + if CommonSimTypeUtils.is_non_player_sim(sim_info): + values.append(CommonSimDemographicType.NON_HOUSEHOLD) + if CommonSimTypeUtils.is_player_sim(sim_info): + values.append(CommonSimDemographicType.HOUSEHOLD) + return tuple(values) + + @classmethod + def is_sim_contained_in_demographic_flags(cls, sim_info: SimInfo, demographic_flags: 'CommonSimDemographicType', match_all: bool = True) -> bool: + """is_sim_contained_in_demographic_flags(sim_info, demographic_flags, match_all=True) + + Determine if a Sim is contained in demographic flags. + + :param sim_info: The info of a Sim. + :type sim_info: SimInfo + :param demographic_flags: The flags of Sim Demographics to match. + :type demographic_flags: CommonSimDemographicType + :param match_all: If True, the Sim must be a match for all specified demographic flags. If False, the Sim can match any of the demographic flags. Default is True. + :type match_all: bool, optional + :return: True, if the Sim matches all (or any) of the Demographic Flags. False, if not. + :rtype: bool + """ + sim_demographic_flags = cls.determine_sim_demographic_flags(sim_info) + # from sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType + # if CommonBitwiseUtils.contains_any_flags(demographic_flags, CommonSimDemographicType.get_all_flags(exclude_values=(CommonSimDemographicType.CURRENTLY_CONTROLLED, CommonSimDemographicType.CONTROLLED, CommonSimDemographicType.HOUSEHOLD, CommonSimDemographicType.NON_HOUSEHOLD))): + # demographic_flags must contain all the values from sim_demographic_flags. If WEREWOLF was not in demographic_flags but was in sim_demographic_flags, then this would return False. + if match_all: + if not CommonBitwiseUtils.contains_all_flags(demographic_flags, sim_demographic_flags): + cls.get_log().format_with_message('Sim failed to match all flags', sim=sim_info, demographic_flags=demographic_flags, sim_demographic_flags=sim_demographic_flags) + return False + else: + if not CommonBitwiseUtils.contains_any_flags(demographic_flags, sim_demographic_flags): + cls.get_log().format_with_message('Sim failed to match any flags', sim=sim_info, demographic_flags=demographic_flags, sim_demographic_flags=sim_demographic_flags) + return False + + # # Handle the non mutually exclusive flags. + # from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + # if CommonBitwiseUtils.contains_all_flags(demographic_flags, CommonSimDemographicType.CURRENTLY_CONTROLLED) and CommonSimUtils.is_active_sim(sim_info): + # cls.get_log().format_with_message('Sim passed controlled flags', sim=sim_info, demographic_flags=demographic_flags, sim_demographic_flags=sim_demographic_flags) + # return True + # if CommonBitwiseUtils.contains_all_flags(demographic_flags, CommonSimDemographicType.CONTROLLED) and CommonSimUtils.is_active_sim(sim_info): + # cls.get_log().format_with_message('Sim passed controlled flags', sim=sim_info, demographic_flags=demographic_flags, sim_demographic_flags=sim_demographic_flags) + # return True + # if CommonBitwiseUtils.contains_all_flags(demographic_flags, CommonSimDemographicType.HOUSEHOLD) and CommonSimTypeUtils.is_player_sim(sim_info): + # cls.get_log().format_with_message('Sim passed household flags', sim=sim_info, demographic_flags=demographic_flags, sim_demographic_flags=sim_demographic_flags) + # return True + # if CommonBitwiseUtils.contains_all_flags(demographic_flags, CommonSimDemographicType.NON_HOUSEHOLD) and CommonSimTypeUtils.is_non_player_sim(sim_info): + # cls.get_log().format_with_message('Sim passed non household flags', sim=sim_info, demographic_flags=demographic_flags, sim_demographic_flags=sim_demographic_flags) + # return True + cls.get_log().format_with_message('Sim passed all flags', sim=sim_info, demographic_flags=demographic_flags, sim_demographic_flags=sim_demographic_flags) + return True + + @classmethod + def is_sim_contained_in_demographics(cls, sim_info: SimInfo, demographics: Tuple['CommonSimDemographicType'], match_all: bool = True) -> bool: + """is_sim_contained_in_demographic_flags(sim_info, demographics, match_all=True) + + Determine if a Sim is contained in a collection of Sim demographics. + + :param sim_info: The info of a Sim. + :type sim_info: SimInfo + :param demographics: A collection of Sim Demographics to match. + :type demographics: Tuple[CommonSimDemographicType] + :param match_all: If True, the Sim must be a match for all specified demographics. If False, the Sim can match any of the demographics. Default is True. + :type match_all: bool, optional + :return: True, if the Sim matches all (or any) of the Demographics. False, if not. + :rtype: bool + """ + sim_demographics = cls.determine_sim_demographics(sim_info) + + # # Handle the non mutually exclusive flags. + # from sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType + # from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + # if CommonSimDemographicType.CURRENTLY_CONTROLLED in demographics and CommonSimUtils.is_active_sim(sim_info): + # cls.get_log().format_with_message('Sim passed controlled flags', sim=sim_info, demographics=demographics, sim_demographics=sim_demographics) + # return True + # if CommonSimDemographicType.CONTROLLED in demographics and CommonSimUtils.is_active_sim(sim_info): + # cls.get_log().format_with_message('Sim passed controlled flags', sim=sim_info, demographics=demographics, sim_demographics=sim_demographics) + # return True + # if CommonSimDemographicType.NON_HOUSEHOLD in demographics and CommonSimTypeUtils.is_non_player_sim(sim_info): + # cls.get_log().format_with_message('Sim passed non household flags', sim=sim_info, demographics=demographics, sim_demographics=sim_demographics) + # return True + # if CommonSimDemographicType.HOUSEHOLD in demographics and CommonSimTypeUtils.is_player_sim(sim_info): + # cls.get_log().format_with_message('Sim passed household flags', sim=sim_info, demographics=demographics, sim_demographics=sim_demographics) + # return True + + # demographics must contain all the values from sim_demographics. If WEREWOLF was not in demographics but was in sim_demographics, then this would return False. + if match_all: + for sim_demographic in sim_demographics: + if sim_demographic not in demographics: + cls.get_log().format_with_message('Sim failed all flags', sim=sim_info, demographics=demographics, sim_demographics=sim_demographics, missing_sim_demographic=sim_demographic) + return False + cls.get_log().format_with_message('Sim passed all flags', sim=sim_info, demographics=demographics, sim_demographics=sim_demographics) + return True + else: + for sim_demographic in sim_demographics: + if sim_demographic in demographics: + cls.get_log().format_with_message('Sim passed flags', sim=sim_info, demographics=demographics, sim_demographics=sim_demographics, matching_sim_demographic=sim_demographic) + return True + cls.get_log().format_with_message('Sim failed all flags', sim=sim_info, demographics=demographics, sim_demographics=sim_demographics) + return False + + @classmethod + def convert_to_age(cls, value: 'CommonSimDemographicType') -> 'CommonAge': + """Convert a value to an Age value.""" + from sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType + from sims4communitylib.enums.common_age import CommonAge + mapping: Dict[CommonSimDemographicType, CommonAge] = { + CommonSimDemographicType.BABY: CommonAge.BABY, + CommonSimDemographicType.INFANT: CommonAge.INFANT, + CommonSimDemographicType.TODDLER: CommonAge.TODDLER, + CommonSimDemographicType.CHILD: CommonAge.CHILD, + CommonSimDemographicType.TEEN: CommonAge.TEEN, + CommonSimDemographicType.YOUNG_ADULT: CommonAge.YOUNGADULT, + CommonSimDemographicType.ADULT: CommonAge.ADULT, + CommonSimDemographicType.ELDER: CommonAge.ELDER + } + return mapping.get(value, CommonAge.INVALID) + + @classmethod + def convert_from_age(cls, value: 'CommonAge') -> 'CommonSimDemographicType': + """Convert a value to a Sim demographic value.""" + from sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType + from sims4communitylib.enums.common_age import CommonAge + mapping: Dict[CommonAge, CommonSimDemographicType] = { + CommonAge.BABY: CommonSimDemographicType.BABY, + CommonAge.INFANT: CommonSimDemographicType.INFANT, + CommonAge.TODDLER: CommonSimDemographicType.TODDLER, + CommonAge.CHILD: CommonSimDemographicType.CHILD, + CommonAge.TEEN: CommonSimDemographicType.TEEN, + CommonAge.YOUNGADULT: CommonSimDemographicType.YOUNG_ADULT, + CommonAge.ADULT: CommonSimDemographicType.ADULT, + CommonAge.ELDER: CommonSimDemographicType.ELDER + } + return mapping.get(value, CommonSimDemographicType.NONE) + + @classmethod + def convert_to_gender(cls, value: 'CommonSimDemographicType') -> 'CommonGender': + """Convert a value to a Gender value.""" + from sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType + from sims4communitylib.enums.common_gender import CommonGender + mapping: Dict[CommonSimDemographicType, CommonGender] = { + CommonSimDemographicType.MALE: CommonGender.MALE, + CommonSimDemographicType.FEMALE: CommonGender.FEMALE + } + return mapping.get(value, CommonGender.INVALID) + + @classmethod + def convert_from_gender(cls, value: 'CommonGender') -> 'CommonSimDemographicType': + """Convert a value to a Sim demographic value.""" + from sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType + from sims4communitylib.enums.common_gender import CommonGender + mapping: Dict[CommonGender, CommonSimDemographicType] = { + CommonGender.MALE: CommonSimDemographicType.MALE, + CommonGender.FEMALE: CommonSimDemographicType.FEMALE + } + return mapping.get(value, CommonSimDemographicType.NONE) + + @classmethod + def convert_to_species(cls, value: 'CommonSimDemographicType') -> 'CommonSpecies': + """Convert a value to a Species value.""" + from sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType + from sims4communitylib.enums.common_species import CommonSpecies + mapping: Dict[CommonSimDemographicType, CommonSpecies] = { + CommonSimDemographicType.HUMAN: CommonSpecies.HUMAN, + CommonSimDemographicType.SMALL_DOG: CommonSpecies.SMALL_DOG, + CommonSimDemographicType.LARGE_DOG: CommonSpecies.LARGE_DOG, + CommonSimDemographicType.CAT: CommonSpecies.CAT, + CommonSimDemographicType.FOX: CommonSpecies.FOX, + CommonSimDemographicType.HORSE: CommonSpecies.HORSE, + } + return mapping.get(value, CommonSpecies.INVALID) + + @classmethod + def convert_from_species(cls, value: 'CommonSpecies') -> 'CommonSimDemographicType': + """Convert a value to a Sim demographic value.""" + from sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType + from sims4communitylib.enums.common_species import CommonSpecies + mapping: Dict[CommonSpecies, CommonSimDemographicType] = { + CommonSpecies.HUMAN: CommonSimDemographicType.HUMAN, + CommonSpecies.SMALL_DOG: CommonSimDemographicType.SMALL_DOG, + CommonSpecies.LARGE_DOG: CommonSimDemographicType.LARGE_DOG, + CommonSpecies.CAT: CommonSimDemographicType.CAT, + CommonSpecies.FOX: CommonSimDemographicType.FOX, + CommonSpecies.HORSE: CommonSimDemographicType.HORSE, + } + return mapping.get(value, CommonSimDemographicType.NONE) + + @classmethod + def convert_to_occult_type(cls, value: 'CommonSimDemographicType') -> 'CommonOccultType': + """Convert a value to an Occult Type value.""" + from sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType + from sims4communitylib.enums.common_occult_type import CommonOccultType + mapping: Dict[CommonSimDemographicType, CommonOccultType] = { + CommonSimDemographicType.ALIEN: CommonOccultType.ALIEN, + CommonSimDemographicType.MERMAID: CommonOccultType.MERMAID, + CommonSimDemographicType.ROBOT: CommonOccultType.ROBOT, + CommonSimDemographicType.SKELETON: CommonOccultType.SKELETON, + CommonSimDemographicType.VAMPIRE: CommonOccultType.VAMPIRE, + CommonSimDemographicType.WITCH: CommonOccultType.WITCH, + CommonSimDemographicType.PLANT: CommonOccultType.PLANT_SIM, + CommonSimDemographicType.GHOST: CommonOccultType.GHOST, + CommonSimDemographicType.WEREWOLF: CommonOccultType.WEREWOLF, + CommonSimDemographicType.NON_OCCULT: CommonOccultType.NON_OCCULT, + } + return mapping.get(value, CommonOccultType.NONE) + + @classmethod + def convert_from_occult_type(cls, value: 'CommonOccultType') -> 'CommonSimDemographicType': + """Convert a value to a Sim demographic value.""" + from sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType + from sims4communitylib.enums.common_occult_type import CommonOccultType + mapping: Dict[CommonOccultType, CommonSimDemographicType] = { + CommonOccultType.ALIEN: CommonSimDemographicType.ALIEN, + CommonOccultType.MERMAID: CommonSimDemographicType.MERMAID, + CommonOccultType.ROBOT: CommonSimDemographicType.ROBOT, + CommonOccultType.SKELETON: CommonSimDemographicType.SKELETON, + CommonOccultType.VAMPIRE: CommonSimDemographicType.VAMPIRE, + CommonOccultType.WITCH: CommonSimDemographicType.WITCH, + CommonOccultType.PLANT_SIM: CommonSimDemographicType.PLANT, + CommonOccultType.GHOST: CommonSimDemographicType.GHOST, + CommonOccultType.WEREWOLF: CommonSimDemographicType.WEREWOLF, + CommonOccultType.NON_OCCULT: CommonSimDemographicType.NON_OCCULT, + } + return mapping.get(value, CommonSimDemographicType.NONE) + + @classmethod + def get_all_sims_matching_demographics( + cls, + sim_demographics: Tuple['CommonSimDemographicType'], + include_sim_callback: Callable[[SimInfo], Union[bool, CommonExecutionResult, CommonTestResult]] = None, + instanced_only: bool = True + ) -> Iterator[SimInfo]: + """get_all_sims_matching_demographics(\ + sim_demographics,\ + include_sim_callback=None,\ + instanced_only=True\ + ) + + Get all Sims matching a collection of Sim Demographics. + + :param sim_demographics: A collection of Sim demographics to match on. + :type sim_demographics: Tuple[CommonSimDemographicType] + :param include_sim_callback: If the result of this callback is True, the Sim will be available in the results. If set to None, All Sims will be available in the results. + :type include_sim_callback: Callable[[SimInfo], bool], optional + :param instanced_only: If True, only Sims that are currently loaded will be available in the results. Default is True. + :type instanced_only: bool, optional + :return: A generator of Sims matching the specified demographics. + :rtype: Iterator[SimInfo] + """ + if instanced_only: + sim_info_gen = CommonSimUtils.get_instanced_sim_info_for_all_sims_generator(include_sim_callback=include_sim_callback) + else: + sim_info_gen = CommonSimUtils.get_sim_info_for_all_sims_generator(include_sim_callback=include_sim_callback) + for sim_info in sim_info_gen: + if cls.is_sim_contained_in_demographics(sim_info, sim_demographics): + yield sim_info + + @classmethod + def get_all_sims_matching_demographic_flags( + cls, + sim_demographic_flags: 'CommonSimDemographicType', + include_sim_callback: Callable[[SimInfo], Union[bool, CommonExecutionResult, CommonTestResult]] = None, + instanced_only: bool = True + ) -> Iterator[SimInfo]: + """get_all_sims_matching_demographic_flags(\ + sim_demographic_flags,\ + include_sim_callback=None,\ + instanced_only=True\ + ) + + Get all Sims matching Sim Demographics Flags. + + :param sim_demographic_flags: Flags of Sim Demographics to match on. + :type sim_demographic_flags: CommonSimDemographicType + :param include_sim_callback: If the result of this callback is True, the Sim will be available in the results. If set to None, All Sims will be available in the results. + :type include_sim_callback: Callable[[SimInfo], bool], optional + :param instanced_only: If True, only Sims that are currently loaded will be available in the results. Default is True. + :type instanced_only: bool, optional + :return: A generator of Sims matching the specified demographics. + :rtype: Iterator[SimInfo] + """ + if instanced_only: + sim_info_gen = CommonSimUtils.get_instanced_sim_info_for_all_sims_generator(include_sim_callback=include_sim_callback) + else: + sim_info_gen = CommonSimUtils.get_sim_info_for_all_sims_generator(include_sim_callback=include_sim_callback) + for sim_info in sim_info_gen: + if cls.is_sim_contained_in_demographic_flags(sim_info, sim_demographic_flags): + yield sim_info + + @classmethod + def perform_action_on_sims_matching_demographics( + cls, + sim_demographics: Tuple['CommonSimDemographicType'], + action: Callable[[SimInfo], None], + include_sim_callback: Callable[[SimInfo], Union[bool, CommonExecutionResult, CommonTestResult]] = None, + instanced_only: bool = True + ): + """perform_action_on_sims_matching_demographics(\ + sim_demographics,\ + action,\ + include_sim_callback=None,\ + instanced_only=True\ + ) + + Perform an action on all Sims matching a collection of Sim Demographics. + + :param sim_demographics: A collection of Sim demographics to match on. + :type sim_demographics: Tuple[CommonSimDemographicType] + :param action: A function invoked on each matching Sim. + :type action: Callable[[SimInfo], None] + :param include_sim_callback: If the result of this callback is True, the Sim will be available to have the action performed on them. If set to None, All Sims will be available to have the action performed on them. + :type include_sim_callback: Callable[[SimInfo], bool], optional + :param instanced_only: If True, only Sims that are currently loaded will be available. Default is True. + :type instanced_only: bool, optional + """ + for sim_info in cls.get_all_sims_matching_demographics(sim_demographics, include_sim_callback=include_sim_callback, instanced_only=instanced_only): + if cls.is_sim_contained_in_demographics(sim_info, sim_demographics): + action(sim_info) + + @classmethod + def perform_action_on_sims_matching_demographic_flags( + cls, + sim_demographic_flags: 'CommonSimDemographicType', + action: Callable[[SimInfo], None], + include_sim_callback: Callable[[SimInfo], Union[bool, CommonExecutionResult, CommonTestResult]] = None, + instanced_only: bool = True + ): + """perform_action_on_sims_matching_demographic_flags(\ + sim_demographic_flags,\ + action,\ + include_sim_callback=None,\ + instanced_only=True\ + ) + + Perform an action on all Sims matching Sim Demographics Flags. + + :param sim_demographic_flags: Flags of Sim Demographics to match on. + :type sim_demographic_flags: CommonSimDemographicType + :param action: A function invoked on each matching Sim. + :type action: Callable[[SimInfo], None] + :param include_sim_callback: If the result of this callback is True, the Sim will be available to have the action performed on them. If set to None, All Sims will be available to have the action performed on them. + :type include_sim_callback: Callable[[SimInfo], bool], optional + :param instanced_only: If True, only Sims that are currently loaded will be available to have the action performed on them. Default is True. + :type instanced_only: bool, optional + """ + for sim_info in cls.get_all_sims_matching_demographic_flags(sim_demographic_flags, include_sim_callback=include_sim_callback, instanced_only=instanced_only): + if cls.is_sim_contained_in_demographic_flags(sim_info, sim_demographic_flags): + action(sim_info) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_gender_option_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_gender_option_utils.py new file mode 100644 index 0000000..9ce1d84 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_gender_option_utils.py @@ -0,0 +1,879 @@ +""" +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 +""" +from typing import Union + +from sims.global_gender_preference_tuning import ExploringOptionsStatus, GlobalGenderPreferenceTuning +from sims.sim_info import SimInfo +from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.enums.traits_enum import CommonTraitId +from sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog +from sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils +from sims4communitylib.utils.sims.common_sim_voice_utils import CommonSimVoiceUtils +from sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils +from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils +from traits.traits import Trait + + +class CommonSimGenderOptionUtils(_HasS4CLClassLog): + """Utilities for manipulating the Gender Options of Sims. + + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 'common_sim_gender_option_utils' + + @staticmethod + def has_masculine_frame(sim_info: SimInfo) -> CommonTestResult: + """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: The result of testing. True, if the Sim does. False, if the Sim does not. + :rtype: CommonTestResult + """ + return CommonTraitUtils.has_trait(sim_info, CommonTraitId.GENDER_OPTIONS_FRAME_MASCULINE) + + @staticmethod + def has_feminine_frame(sim_info: SimInfo) -> CommonTestResult: + """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: The result of testing. True, if the Sim does. False, if the Sim does not. + :rtype: CommonTestResult + """ + return CommonTraitUtils.has_trait(sim_info, CommonTraitId.GENDER_OPTIONS_FRAME_FEMININE) + + @staticmethod + def prefers_menswear(sim_info: SimInfo) -> CommonTestResult: + """prefers_menswear(sim_info) + + Determine if a sim prefers Mens Clothing. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim does. False, if the Sim does not. + :rtype: CommonTestResult + """ + return CommonTraitUtils.has_trait(sim_info, CommonTraitId.GENDER_OPTIONS_CLOTHING_MENS_WEAR) + + @staticmethod + def prefers_womenswear(sim_info: SimInfo) -> CommonTestResult: + """prefers_womenswear(sim_info) + + Determine if a sim prefers Womens Clothing. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim does. False, if the Sim does not. + :rtype: CommonTestResult + """ + return CommonTraitUtils.has_trait(sim_info, CommonTraitId.GENDER_OPTIONS_CLOTHING_WOMENS_WEAR) + + @staticmethod + def can_impregnate(sim_info: SimInfo) -> CommonTestResult: + """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: The result of testing. True, if the Sim can impregnate other Sims. False, if the Sim can not impregnate other Sims. + :rtype: CommonTestResult + """ + from sims4communitylib.utils.sims.common_sim_pregnancy_utils import CommonSimPregnancyUtils + return CommonSimPregnancyUtils.can_impregnate(sim_info) + + @staticmethod + def can_not_impregnate(sim_info: SimInfo) -> CommonTestResult: + """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: The result of testing. True, if the Sim can not impregnate other Sims. False, if the Sim can impregnate other Sims. + :rtype: CommonTestResult + """ + can_impregnate_result = CommonSimGenderOptionUtils.can_impregnate(sim_info) + return can_impregnate_result.reverse_result() + + @staticmethod + def can_be_impregnated(sim_info: SimInfo) -> CommonTestResult: + """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: The result of testing. True, if the Sim can be impregnated. False, if the Sim can not be impregnated. + :rtype: CommonTestResult + """ + from sims4communitylib.utils.sims.common_sim_pregnancy_utils import CommonSimPregnancyUtils + return CommonSimPregnancyUtils.can_be_impregnated(sim_info) + + @staticmethod + def can_not_be_impregnated(sim_info: SimInfo) -> CommonTestResult: + """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: The result of testing. True, if the Sim can not be impregnated. False, if the Sim can be impregnated. + :rtype: CommonTestResult + """ + can_be_impregnated_result = CommonSimGenderOptionUtils.can_be_impregnated(sim_info) + return can_be_impregnated_result.reverse_result() + + @staticmethod + def can_create_pregnancy(sim_info: SimInfo) -> CommonTestResult: + """can_create_pregnancy(sim_info) + + Determine if a Sim can either impregnate, be impregnated, or can reproduce. + + .. note:: Will return False if the Sim can both impregnate and not impregnate,\ + if the Sim can both be impregnated and not be impregnated\ + or if the Sim can both reproduce and not reproduce. + + .. note:: A Sim can impregnate when they can either impregnate other Sims, can be impregnated by other Sims, or if they are a Pet, can reproduce. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim can create pregnancies. False, if the Sim can not create pregnancies. + :rtype: CommonTestResult + """ + return CommonTraitUtils.can_impregnate(sim_info) or CommonTraitUtils.can_be_impregnated(sim_info) or CommonTraitUtils.can_reproduce(sim_info) + + @staticmethod + def can_reproduce(sim_info: SimInfo) -> CommonTestResult: + """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: The result of testing. True, if the Sim can reproduce. False, if the Sim can not reproduce. + :rtype: CommonTestResult + """ + if CommonTraitUtils.has_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_NOT_REPRODUCE): + return CommonTestResult(False, reason=f'Sim has the Cannot Reproduce trait.') + if CommonSimGenderOptionUtils.can_not_impregnate(sim_info) and CommonSimGenderOptionUtils.can_not_be_impregnated(sim_info): + return CommonTestResult(False, reason=f'Sim can neither impregnate nor be impregnated.') + if CommonTraitUtils.has_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_REPRODUCE): + return CommonTestResult(True, reason=f'Sim has the Can Reproduce trait.') + can_impregnate_result = CommonSimGenderOptionUtils.can_impregnate(sim_info) + if can_impregnate_result: + return can_impregnate_result + can_be_impregnated_result = CommonSimGenderOptionUtils.can_be_impregnated(sim_info) + if can_be_impregnated_result: + return can_be_impregnated_result + return CommonTestResult(False, reason=f'Sim can neither impregnate nor be impregnated.') + + @staticmethod + def can_not_reproduce(sim_info: SimInfo) -> CommonTestResult: + """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: The result of testing. True, if the Sim can not reproduce. False, if the Sim can reproduce. + :rtype: CommonTestResult + """ + can_reproduce_result = CommonSimGenderOptionUtils.can_reproduce(sim_info) + return can_reproduce_result.reverse_result() + + @staticmethod + def uses_toilet_standing(sim_info: SimInfo) -> CommonTestResult: + """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: The result of testing. True, if the Sim uses toilets while standing. False, if the Sim does not use toilets while standing. + :rtype: CommonTestResult + """ + toilet_standing_trait = CommonSimGenderOptionUtils.determine_toilet_standing_trait(sim_info) + if toilet_standing_trait is None: + return CommonTestResult(False, reason='No toilet standing trait was found for Sim.') + return CommonTraitUtils.has_trait(sim_info, toilet_standing_trait) + + @staticmethod + def uses_toilet_sitting(sim_info: SimInfo) -> CommonTestResult: + """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: The result of testing. True, if the Sim uses toilets while sitting. False, if the Sim does not use toilets while sitting. + :rtype: CommonTestResult + """ + toilet_sitting_trait = CommonSimGenderOptionUtils.determine_toilet_sitting_trait(sim_info) + if toilet_sitting_trait is None: + return CommonTestResult(False, reason='No toilet sitting trait was found for Sim.') + return CommonTraitUtils.has_trait(sim_info, toilet_sitting_trait) + + @staticmethod + def has_breasts(sim_info: SimInfo) -> CommonTestResult: + """has_breasts(sim_info) + + Determine if a Sim has breasts. + + .. note:: This will True if breasts are being forced on the Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim has breasts. False, if not. + :rtype: CommonTestResult + """ + if CommonGenderUtils.is_female(sim_info): + if CommonTraitUtils.has_trait(sim_info, CommonTraitId.BREASTS_FORCE_OFF): + return CommonTestResult(False, reason=f'Sim does not have breasts. They are Female and have the Breasts Force Off trait.') + else: + return CommonTestResult(True, reason=f'Sim has breasts. They are Female and they do not have the Breasts Force Off trait.') + if CommonGenderUtils.is_male(sim_info): + if CommonTraitUtils.has_trait(sim_info, CommonTraitId.BREASTS_FORCE_ON): + return CommonTestResult(True, reason=f'Sim has breasts. They are Male and they have the Breasts Force On trait.') + else: + return CommonTestResult(False, reason=f'Sim does not have breasts. They are Male and they do not have the Breasts Force On trait.') + return CommonTestResult(False, reason=f'Sim does not have breasts. They are neither Male nor Female.') + + @staticmethod + def update_gender_options_to_vanilla_male(sim_info: SimInfo, return_on_failure: bool = False) -> CommonExecutionResult: + """update_gender_options_to_vanilla_male(sim_info, return_on_failure=False) + + Update a Sim to the vanilla Sims 4 default gender options for Male Sims. (Masculine, Menswear Preference, etc.) + + .. note:: This will change the following things: Body Frame (Masculine), Clothing Preference (Masculine), Can Be Impregnated (False), Can Impregnate (True), Can Reproduce (True), Toilet Usage Posture (Standing), Voice Actor (MALE). + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param return_on_failure: If True, if any update attempt fails, the function will return that result. If False, any failures will be ignored. Default is False. + :type return_on_failure: bool, optional + :return: The result of updating. True, if successful. False, if not. + :rtype: CommonExecutionResult + """ + update_body_frame_result = CommonSimGenderOptionUtils.update_body_frame(sim_info, True) + if return_on_failure and not update_body_frame_result: + return update_body_frame_result + update_clothing_preference_result = CommonSimGenderOptionUtils.update_clothing_preference(sim_info, True) + if return_on_failure and not update_clothing_preference_result: + return update_clothing_preference_result + update_can_be_impregnated_result = CommonSimGenderOptionUtils.update_can_be_impregnated(sim_info, False) + if return_on_failure and not update_can_be_impregnated_result: + return update_can_be_impregnated_result + update_can_impregnate_result = CommonSimGenderOptionUtils.update_can_impregnate(sim_info, True) + if return_on_failure and not update_can_impregnate_result: + return update_can_impregnate_result + update_can_reproduce_result = CommonSimGenderOptionUtils.update_can_reproduce(sim_info, True) + if return_on_failure and not update_can_reproduce_result: + return update_can_reproduce_result + update_toilet_usage_result = CommonSimGenderOptionUtils.update_toilet_usage(sim_info, True) + if return_on_failure and not update_toilet_usage_result: + return update_toilet_usage_result + set_male_voice_result = CommonSimVoiceUtils.set_to_default_male_voice(sim_info) + if return_on_failure and not set_male_voice_result: + return set_male_voice_result + return CommonExecutionResult.TRUE + + @staticmethod + def update_gender_options_to_vanilla_female(sim_info: SimInfo, return_on_failure: bool = False) -> CommonExecutionResult: + """update_gender_options_to_vanilla_female(sim_info, return_on_failure=False) + + Update a Sim to the vanilla Sims 4 default gender options for Female Sims. (Feminine, Womenswear Preference, etc.) + + .. note:: This will change the following things: Body Frame (Feminine), Clothing Preference (Feminine), Can Be Impregnated (True), Can Impregnate (False), Can Reproduce (True), Toilet Usage Posture (Sitting), Voice Actor (FEMALE). + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param return_on_failure: If True, if any update attempt fails, the function will return that result. If False, any failures will be ignored. Default is False. + :type return_on_failure: bool, optional + :return: The result of updating. True, if successful. False, if not. + :rtype: CommonExecutionResult + """ + update_body_frame_result = CommonSimGenderOptionUtils.update_body_frame(sim_info, False) + if return_on_failure and not update_body_frame_result: + return update_body_frame_result + update_clothing_preference_result = CommonSimGenderOptionUtils.update_clothing_preference(sim_info, False) + if return_on_failure and not update_clothing_preference_result: + return update_clothing_preference_result + update_can_be_impregnated_result = CommonSimGenderOptionUtils.update_can_be_impregnated(sim_info, True) + if return_on_failure and not update_can_be_impregnated_result: + return update_can_be_impregnated_result + update_can_impregnate_result = CommonSimGenderOptionUtils.update_can_impregnate(sim_info, False) + if return_on_failure and not update_can_impregnate_result: + return update_can_impregnate_result + update_can_reproduce_result = CommonSimGenderOptionUtils.update_can_reproduce(sim_info, True) + if return_on_failure and not update_can_reproduce_result: + return update_can_reproduce_result + update_toilet_usage_result = CommonSimGenderOptionUtils.update_toilet_usage(sim_info, False) + if return_on_failure and not update_toilet_usage_result: + return update_toilet_usage_result + set_female_voice_result = CommonSimVoiceUtils.set_to_default_female_voice(sim_info) + if return_on_failure and not set_female_voice_result: + return set_female_voice_result + return CommonExecutionResult.TRUE + + @staticmethod + def update_has_breasts(sim_info: SimInfo, has_breasts: bool) -> CommonExecutionResult: + """update_has_breasts(sim_info, has_breasts) + + Give or Take Away the breasts of a Sim. + + .. note:: Will only update Human Sims. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param has_breasts: If True, the Sim will be given breasts.\ + If False, the Sim will not longer have breasts. + :type has_breasts: bool + :return: The result of updating. True, if the state of a Sim having breasts or not was changed. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + from sims4communitylib.events.sim.common_sim_event_dispatcher import CommonSimEventDispatcherService + CommonTraitUtils.remove_trait(sim_info, CommonTraitId.BREASTS_FORCE_OFF) + CommonTraitUtils.remove_trait(sim_info, CommonTraitId.BREASTS_FORCE_ON) + if has_breasts: + if CommonGenderUtils.is_male(sim_info): + add_trait_result = CommonTraitUtils.add_trait(sim_info, CommonTraitId.BREASTS_FORCE_ON) + if not add_trait_result: + return add_trait_result + CommonSimEventDispatcherService()._on_sim_change_gender_options_breasts(sim_info) + else: + if CommonGenderUtils.is_female(sim_info): + add_trait_result = CommonTraitUtils.add_trait(sim_info, CommonTraitId.BREASTS_FORCE_OFF) + if not add_trait_result: + return add_trait_result + CommonSimEventDispatcherService()._on_sim_change_gender_options_breasts(sim_info) + return CommonExecutionResult.TRUE + + @staticmethod + def update_body_frame(sim_info: SimInfo, masculine: bool) -> CommonExecutionResult: + """update_body_frame(sim_info, masculine) + + Update the Body Frame of a Sim. + + .. note:: Will only update Human Sims. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param masculine: If True, the Sim will get a Masculine frame.\ + If False, the Sim will get a Feminine frame. + :type masculine: bool + :return: The result of updating. True, if successful. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + if not CommonSpeciesUtils.is_human(sim_info): + return CommonExecutionResult(False, reason=f'Sim is not Human.') + if masculine: + CommonTraitUtils.remove_trait(sim_info, CommonTraitId.GENDER_OPTIONS_FRAME_FEMININE) + add_trait_result = CommonTraitUtils.add_trait(sim_info, CommonTraitId.GENDER_OPTIONS_FRAME_MASCULINE) + if not add_trait_result: + return add_trait_result + else: + CommonTraitUtils.remove_trait(sim_info, CommonTraitId.GENDER_OPTIONS_FRAME_MASCULINE) + add_trait_result = CommonTraitUtils.add_trait(sim_info, CommonTraitId.GENDER_OPTIONS_FRAME_FEMININE) + if not add_trait_result: + return add_trait_result + from sims4communitylib.events.sim.common_sim_event_dispatcher import CommonSimEventDispatcherService + CommonSimEventDispatcherService()._on_sim_change_gender_options_body_frame(sim_info) + return CommonExecutionResult.TRUE + + @staticmethod + def update_clothing_preference(sim_info: SimInfo, prefer_menswear: bool) -> CommonExecutionResult: + """update_clothing_preference(sim_info, prefer_menswear) + + Update the Clothing Preference of a Sim. + + .. note:: Will only update Human Sims. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param prefer_menswear: If True, the Sim will prefer Menswear.\ + If False, the Sim will prefer Womenswear. + :type prefer_menswear: bool + :return: The result of updating. True, if successful. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + if not CommonSpeciesUtils.is_human(sim_info): + return CommonExecutionResult(False, reason=f'Sim is not Human.') + if prefer_menswear: + CommonTraitUtils.remove_trait(sim_info, CommonTraitId.GENDER_OPTIONS_CLOTHING_WOMENS_WEAR) + add_trait_result = CommonTraitUtils.add_trait(sim_info, CommonTraitId.GENDER_OPTIONS_CLOTHING_MENS_WEAR) + if not add_trait_result: + return add_trait_result + else: + CommonTraitUtils.remove_trait(sim_info, CommonTraitId.GENDER_OPTIONS_CLOTHING_MENS_WEAR) + add_trait_result = CommonTraitUtils.add_trait(sim_info, CommonTraitId.GENDER_OPTIONS_CLOTHING_WOMENS_WEAR) + if not add_trait_result: + return add_trait_result + from sims4communitylib.events.sim.common_sim_event_dispatcher import CommonSimEventDispatcherService + CommonSimEventDispatcherService()._on_sim_change_gender_options_clothing_preference(sim_info) + return CommonExecutionResult.TRUE + + @staticmethod + def update_can_be_impregnated(sim_info: SimInfo, can_be_impregnated: bool) -> CommonExecutionResult: + """update_can_be_impregnated(sim_info, can_be_impregnated) + + Update a Sims ability to be impregnated by other Sims. + + .. note:: Will only update Human Sims. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param can_be_impregnated: If True, the Sim will have the ability to be impregnated.\ + If False, the Sim will not have the ability to be impregnated. + :type can_be_impregnated: bool + :return: The result of updating. True, if successful. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + from sims4communitylib.utils.sims.common_sim_pregnancy_utils import CommonSimPregnancyUtils + can_be_impregnated_trait = CommonSimPregnancyUtils.determine_can_be_impregnated_trait(sim_info) + can_not_be_impregnated_trait = CommonSimPregnancyUtils.determine_can_not_be_impregnated_trait(sim_info) + if can_be_impregnated_trait is None: + return CommonExecutionResult(False, reason=f'No Can Be Impregnated trait was found for Sim {sim_info}') + if can_not_be_impregnated_trait is None: + return CommonExecutionResult(False, reason=f'No Can Not Be Impregnated trait was found for Sim {sim_info}') + if can_be_impregnated: + CommonTraitUtils.remove_trait(sim_info, can_not_be_impregnated_trait) + add_trait_result = CommonTraitUtils.add_trait(sim_info, can_be_impregnated_trait) + if not add_trait_result: + return add_trait_result + if not CommonSpeciesUtils.is_horse(sim_info): + CommonTraitUtils.remove_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_NOT_REPRODUCE) + add_trait_result = CommonTraitUtils.add_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_REPRODUCE) + if not add_trait_result: + return add_trait_result + else: + CommonTraitUtils.remove_trait(sim_info, can_be_impregnated_trait) + add_trait_result = CommonTraitUtils.add_trait(sim_info, can_not_be_impregnated_trait) + if not add_trait_result: + return add_trait_result + if not CommonSimPregnancyUtils.can_impregnate(sim_info): + if not CommonSpeciesUtils.is_horse(sim_info): + CommonTraitUtils.remove_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_REPRODUCE) + add_trait_result = CommonTraitUtils.add_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_NOT_REPRODUCE) + if not add_trait_result: + return add_trait_result + from sims4communitylib.events.sim.common_sim_event_dispatcher import CommonSimEventDispatcherService + CommonSimEventDispatcherService()._on_sim_change_gender_options_can_be_impregnated(sim_info) + return CommonExecutionResult.TRUE + + @staticmethod + def update_can_impregnate(sim_info: SimInfo, can_impregnate: bool) -> CommonExecutionResult: + """update_can_impregnate(sim_info, can_impregnate) + + Update a Sims ability to impregnate other Sims. + + .. note:: Will only update Human Sims. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param can_impregnate: If True, the Sim will have the ability to impregnate other Sims.\ + If False, the Sim will not have the ability to impregnate other Sims. + :type can_impregnate: bool + :return: The result of updating. True, if successful. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + from sims4communitylib.utils.sims.common_sim_pregnancy_utils import CommonSimPregnancyUtils + can_impregnate_trait = CommonSimPregnancyUtils.determine_can_impregnate_trait(sim_info) + can_not_impregnate_trait = CommonSimPregnancyUtils.determine_can_not_impregnate_trait(sim_info) + if can_impregnate_trait is None: + return CommonExecutionResult(False, reason=f'No Can Impregnate trait was found for Sim {sim_info}') + if can_not_impregnate_trait is None: + return CommonExecutionResult(False, reason=f'No Can Not Impregnate trait was found for Sim {sim_info}') + if can_impregnate: + CommonTraitUtils.remove_trait(sim_info, can_not_impregnate_trait) + add_trait_result = CommonTraitUtils.add_trait(sim_info, can_impregnate_trait) + if not add_trait_result: + return add_trait_result + if not CommonSpeciesUtils.is_horse(sim_info): + CommonTraitUtils.remove_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_NOT_REPRODUCE) + add_trait_result = CommonTraitUtils.add_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_REPRODUCE) + if not add_trait_result: + return add_trait_result + else: + CommonTraitUtils.remove_trait(sim_info, can_impregnate_trait) + add_trait_result = CommonTraitUtils.add_trait(sim_info, can_not_impregnate_trait) + if not add_trait_result: + return add_trait_result + if not CommonSimPregnancyUtils.can_be_impregnated(sim_info): + if not CommonSpeciesUtils.is_horse(sim_info): + CommonTraitUtils.remove_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_REPRODUCE) + add_trait_result = CommonTraitUtils.add_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_NOT_REPRODUCE) + if not add_trait_result: + return add_trait_result + from sims4communitylib.events.sim.common_sim_event_dispatcher import CommonSimEventDispatcherService + CommonSimEventDispatcherService()._on_sim_change_gender_options_can_impregnate(sim_info) + return CommonExecutionResult.TRUE + + @staticmethod + def update_can_reproduce(sim_info: SimInfo, can_reproduce: bool) -> CommonExecutionResult: + """update_can_reproduce(sim_info, can_reproduce) + + Update a Sims ability to reproduce. + + .. note:: Will only update Pet Sims. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param can_reproduce: If True, the Sim will have the ability to reproduce.\ + If False, the Sim will not have the ability to reproduce. + :type can_reproduce: bool + :return: The result of updating. True, if successful. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + if not CommonSpeciesUtils.is_animal(sim_info): + return CommonExecutionResult(False, reason=f'Sim is not an Animal.') + if can_reproduce: + if not CommonSpeciesUtils.is_horse(sim_info): + CommonTraitUtils.remove_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_NOT_REPRODUCE) + add_trait_result = CommonTraitUtils.add_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_REPRODUCE) + if not add_trait_result: + return add_trait_result + if CommonGenderUtils.is_male(sim_info): + update_can_impregnate_result = CommonSimGenderOptionUtils.update_can_impregnate(sim_info, True) + if not update_can_impregnate_result: + return update_can_impregnate_result + update_can_be_impregnated_result = CommonSimGenderOptionUtils.update_can_be_impregnated(sim_info, False) + if not update_can_be_impregnated_result: + return update_can_be_impregnated_result + else: + update_can_impregnate_result = CommonSimGenderOptionUtils.update_can_impregnate(sim_info, False) + if not update_can_impregnate_result: + return update_can_impregnate_result + update_can_be_impregnated_result = CommonSimGenderOptionUtils.update_can_be_impregnated(sim_info, True) + if not update_can_be_impregnated_result: + return update_can_be_impregnated_result + else: + CommonTraitUtils.remove_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_REPRODUCE) + if not CommonSpeciesUtils.is_horse(sim_info): + add_trait_result = CommonTraitUtils.add_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_NOT_REPRODUCE) + if not add_trait_result: + return add_trait_result + if CommonGenderUtils.is_male(sim_info): + update_can_impregnate_result = CommonSimGenderOptionUtils.update_can_impregnate(sim_info, False) + if not update_can_impregnate_result: + return update_can_impregnate_result + update_can_be_impregnated_result = CommonSimGenderOptionUtils.update_can_be_impregnated(sim_info, False) + if not update_can_be_impregnated_result: + return update_can_be_impregnated_result + else: + update_can_impregnate_result = CommonSimGenderOptionUtils.update_can_impregnate(sim_info, False) + if not update_can_impregnate_result: + return update_can_impregnate_result + update_can_be_impregnated_result = CommonSimGenderOptionUtils.update_can_be_impregnated(sim_info, False) + if not update_can_be_impregnated_result: + return update_can_be_impregnated_result + from sims4communitylib.events.sim.common_sim_event_dispatcher import CommonSimEventDispatcherService + CommonSimEventDispatcherService()._on_sim_change_gender_options_can_reproduce(sim_info) + return CommonExecutionResult.TRUE + + @staticmethod + def update_toilet_usage(sim_info: SimInfo, uses_toilet_standing: bool) -> CommonExecutionResult: + """update_toilet_usage(sim_info, uses_toilet_standing) + + Update how a Sim uses the toilet. i.e. Toilet Standing or Toilet Sitting. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param uses_toilet_standing: If True, the Sim will use toilets while standing and will not use toilets while sitting.\ + If False, the Sim will use toilets while sitting and will not use toilets while standing. + :type uses_toilet_standing: bool + :return: The result of updating toilet use posture. True, if successful. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + toilet_standing = CommonSimGenderOptionUtils.determine_toilet_standing_trait(sim_info) + toilet_sitting = CommonSimGenderOptionUtils.determine_toilet_sitting_trait(sim_info) + + if toilet_standing is None: + return CommonExecutionResult(False, reason='No toilet standing trait was found for Sim.') + + if toilet_sitting is None: + return CommonExecutionResult(False, reason='No toilet sitting trait was found for Sim.') + + CommonTraitUtils.remove_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_UNKNOWN) + if uses_toilet_standing: + CommonTraitUtils.remove_trait(sim_info, toilet_sitting) + add_trait_result = CommonTraitUtils.add_trait(sim_info, toilet_standing) + if not add_trait_result: + return add_trait_result + else: + CommonTraitUtils.remove_trait(sim_info, toilet_standing) + add_trait_result = CommonTraitUtils.add_trait(sim_info, toilet_sitting) + if not add_trait_result: + return add_trait_result + from sims4communitylib.events.sim.common_sim_event_dispatcher import CommonSimEventDispatcherService + CommonSimEventDispatcherService()._on_sim_change_gender_options_toilet_usage(sim_info) + return CommonExecutionResult.TRUE + + @staticmethod + def set_can_use_toilet_standing(sim_info: SimInfo, can_use_toilet_standing: bool) -> CommonExecutionResult: + """set_can_use_toilet_standing(sim_info, can_use_toilet_standing) + + Set whether a Sim can use a toilet while standing or not. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param can_use_toilet_standing: Whether or not the Sim will be able to use a toilet while standing. + :type can_use_toilet_standing: bool + :return: The result of setting toilet use posture. True, if successful set. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + toilet_standing = CommonSimGenderOptionUtils.determine_toilet_standing_trait(sim_info) + + if toilet_standing is None: + return CommonExecutionResult(False, reason='No toilet standing trait was found for Sim.') + + if can_use_toilet_standing and not CommonTraitUtils.has_trait(sim_info, toilet_standing): + CommonTraitUtils.remove_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_UNKNOWN) + add_trait_result = CommonTraitUtils.add_trait(sim_info, toilet_standing) + if not add_trait_result: + return add_trait_result + elif CommonTraitUtils.has_trait(sim_info, toilet_standing): + CommonTraitUtils.remove_trait(sim_info, toilet_standing) + if not CommonSimGenderOptionUtils.uses_toilet_sitting(sim_info): + add_trait_result = CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_UNKNOWN) + if not add_trait_result: + return add_trait_result + + from sims4communitylib.events.sim.common_sim_event_dispatcher import CommonSimEventDispatcherService + CommonSimEventDispatcherService()._on_sim_change_gender_options_toilet_usage(sim_info) + return CommonExecutionResult.TRUE + + @staticmethod + def set_can_use_toilet_sitting(sim_info: SimInfo, can_use_toilet_sitting: bool) -> CommonExecutionResult: + """set_can_use_toilet_sitting(sim_info, can_use_toilet_sitting) + + Set whether a Sim can use a toilet while sitting or not. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param can_use_toilet_sitting: Whether or not the Sim will be able to use a toilet while sitting. + :type can_use_toilet_sitting: bool + :return: The result of setting toilet use posture. True, if successful set. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + toilet_sitting = CommonSimGenderOptionUtils.determine_toilet_sitting_trait(sim_info) + + if toilet_sitting is None: + return CommonExecutionResult(False, reason='No toilet sitting trait was found for Sim.') + + if can_use_toilet_sitting and not CommonTraitUtils.has_trait(sim_info, toilet_sitting): + CommonTraitUtils.remove_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_UNKNOWN) + add_trait_result = CommonTraitUtils.add_trait(sim_info, toilet_sitting) + if not add_trait_result: + return add_trait_result + elif CommonTraitUtils.has_trait(sim_info, toilet_sitting): + CommonTraitUtils.remove_trait(sim_info, toilet_sitting) + if not CommonSimGenderOptionUtils.uses_toilet_standing(sim_info): + add_trait_result = CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_UNKNOWN) + if not add_trait_result: + return add_trait_result + + from sims4communitylib.events.sim.common_sim_event_dispatcher import CommonSimEventDispatcherService + CommonSimEventDispatcherService()._on_sim_change_gender_options_toilet_usage(sim_info) + return CommonExecutionResult.TRUE + + @staticmethod + def determine_toilet_standing_trait(sim_info: SimInfo) -> Union[CommonTraitId, None]: + """determine_toilet_standing_trait(sim_info) + + Determine the trait that would indicate a Sim uses the toilet while standing. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The trait that would indicate the Sim uses the toilet while standing or None if no trait is found. + :rtype: Union[CommonTraitId, None] + """ + if CommonSpeciesUtils.is_human(sim_info): + return CommonTraitId.GENDER_OPTIONS_TOILET_STANDING + elif CommonSpeciesUtils.is_large_dog(sim_info): + return CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_LARGE_DOG + elif CommonSpeciesUtils.is_small_dog(sim_info): + return CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_SMALL_DOG + elif CommonSpeciesUtils.is_cat(sim_info): + return CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_CAT + elif CommonSpeciesUtils.is_fox(sim_info): + return CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_FOX + elif CommonSpeciesUtils.is_horse(sim_info): + return CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_HORSE + return None + + @staticmethod + def determine_toilet_sitting_trait(sim_info: SimInfo) -> Union[CommonTraitId, None]: + """determine_toilet_sitting_trait(sim_info) + + Determine the trait that would indicate a Sim uses the toilet while sitting. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The trait that would indicate the Sim uses the toilet while sitting or None if no trait is found. + :rtype: Union[CommonTraitId, None] + """ + if CommonSpeciesUtils.is_human(sim_info): + return CommonTraitId.GENDER_OPTIONS_TOILET_SITTING + elif CommonSpeciesUtils.is_large_dog(sim_info): + return CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_LARGE_DOG + elif CommonSpeciesUtils.is_small_dog(sim_info): + return CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_SMALL_DOG + elif CommonSpeciesUtils.is_cat(sim_info): + return CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_CAT + elif CommonSpeciesUtils.is_fox(sim_info): + return CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_FOX + elif CommonSpeciesUtils.is_horse(sim_info): + return CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_HORSE + return None + + @classmethod + def is_exploring_sexuality(cls, sim_info: SimInfo) -> CommonTestResult: + """is_exploring_sexuality(sim_info) + + Determine if a Sim is open to exploring their sexuality. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of the test. True, if the test passes. False, if not. + :rtype: CommonTestResult + """ + return cls.has_sexuality_exploration_status(sim_info, ExploringOptionsStatus.EXPLORING) + + @classmethod + def is_not_exploring_sexuality(cls, sim_info: SimInfo) -> CommonTestResult: + """is_not_exploring_sexuality(sim_info) + + Determine if a Sim is not open to exploring their sexuality. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of the test. True, if the test passes. False, if not. + :rtype: CommonTestResult + """ + return cls.has_sexuality_exploration_status(sim_info, ExploringOptionsStatus.NOT_EXPLORING) + + @classmethod + def has_sexuality_exploration_status(cls, sim_info: SimInfo, sexuality_status: ExploringOptionsStatus) -> CommonTestResult: + """has_sexuality_exploration_status(sim_info, sexuality_status) + + Determine if a Sim has the specified exploration status for their sexuality. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param sexuality_status: The exploration status to check for. + :type sexuality_status: ExploringOptionsStatus + :return: The result of the test. True, if the test passes. False, if not. + :rtype: CommonTestResult + """ + if sim_info is None: + return CommonTestResult(False, reason=f'{sim_info} is None!') + exploring_sexuality_trait = cls.get_sexuality_status_trait(sim_info, sexuality_status) + if CommonTraitUtils.has_trait(sim_info, exploring_sexuality_trait): + if sexuality_status == ExploringOptionsStatus.EXPLORING: + return CommonTestResult(True, reason=f'{sim_info} is open to exploring their sexuality.') + else: + return CommonTestResult(True, reason=f'{sim_info} is not open to exploring their sexuality.') + if sexuality_status == ExploringOptionsStatus.EXPLORING: + return CommonTestResult(False, reason=f'{sim_info} is not open to exploring their sexuality.') + else: + return CommonTestResult(False, reason=f'{sim_info} is open to exploring their sexuality.') + + @classmethod + def set_is_exploring_sexuality(cls, sim_info: SimInfo, is_exploring: bool) -> CommonExecutionResult: + """set_is_exploring_sexuality(sim_info, is_exploring) + + Set whether a Sim is open to explore their sexuality or not. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param is_exploring: Set True if the Sim should be set to Exploring. Set False if the Sim should be set to Not Exploring. + :type is_exploring: bool + """ + if sim_info is None: + return CommonTestResult(False, reason=f'{sim_info} is None!') + + if is_exploring: + cls.get_log().format_with_message('Setting Sim to exploring sexuality.', sim=sim_info, is_exploring=is_exploring) + sexuality_status = ExploringOptionsStatus.EXPLORING + opposite_sexuality_status = ExploringOptionsStatus.NOT_EXPLORING + else: + cls.get_log().format_with_message('Setting Sim to not exploring sexuality.', sim=sim_info, is_exploring=is_exploring) + sexuality_status = ExploringOptionsStatus.NOT_EXPLORING + opposite_sexuality_status = ExploringOptionsStatus.EXPLORING + + to_remove_trait = cls.get_sexuality_status_trait(sim_info, opposite_sexuality_status) + to_add_trait = cls.get_sexuality_status_trait(sim_info, sexuality_status) + cls.get_log().format_with_message('Got exploring sexuality traits.', sim=sim_info, to_remove_trait=to_remove_trait, to_add_trait=to_add_trait) + remove_result = CommonTraitUtils.remove_trait(sim_info, to_remove_trait) + if not remove_result: + cls.get_log().format_with_message('Failed to remove exploring sexuality trait.', sim=sim_info, to_remove_trait=to_remove_trait, remove_result=remove_result) + return remove_result + add_result = CommonTraitUtils.add_trait(sim_info, to_add_trait) + cls.get_log().format_with_message('Finished adding exploring sexuality trait.', sim=sim_info, to_add_trait=to_add_trait, add_result=add_result) + return add_result + + # noinspection PyUnusedLocal + @classmethod + def get_sexuality_status_trait(cls, sim_info: SimInfo, sexuality_status: ExploringOptionsStatus) -> Union[Trait, None]: + """get_sexuality_status_trait(sim_info, sexuality_status) + + Retrieve the trait associated with a sexuality status. + + :param sim_info: An instance of the Sim to receive or be checked for the trait. + :type sim_info: SimInfo + :param sexuality_status: The sexuality status to look for. + :type sexuality_status: ExploringOptionsStatus + :return: The trait associated with the specified sexuality status or None if not found. + :rtype: Union[Trait, None] + """ + return GlobalGenderPreferenceTuning.EXPLORING_SEXUALITY_TRAITS_MAPPING.get(sexuality_status, None) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_gender_preference_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_gender_preference_utils.py new file mode 100644 index 0000000..2fed5f6 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_gender_preference_utils.py @@ -0,0 +1,485 @@ +""" +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 +""" +from typing import Tuple, Union + +from sims.global_gender_preference_tuning import GlobalGenderPreferenceTuning, GenderPreferenceType +from sims.sim_info import SimInfo +from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from sims4communitylib.enums.common_gender import CommonGender +from sims4communitylib.enums.common_gender_preference_type import CommonGenderPreferenceType +from sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + CommonConsoleCommandArgument +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils + + +class CommonSimGenderPreferenceUtils: + """ Utilities for Sim gender preferences. """ + LOW_PREFERENCE_THRESHOLD = 20 + HIGH_PREFERENCE_THRESHOLD = 80 + + @classmethod + def set_preference_for_gender(cls, sim_info: SimInfo, gender: CommonGender, is_attracted_to_gender: Union[bool, None], preference_type: Union[CommonGenderPreferenceType, GenderPreferenceType] = CommonGenderPreferenceType.ROMANTIC) -> CommonExecutionResult: + """set_preference_for_gender(sim_info, gender, is_attracted_to_gender, preference_type=CommonGenderPreferenceType.ROMANTIC) + + Set the preference a Sim has for a gender. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param gender: An instance of a gender. + :type gender: CommonGender + :param is_attracted_to_gender: True, if you want the Sim to be attracted to the gender. False, if you want the Sim to NOT be attracted to the gender. None, if you want the Sim to have no preferences. + :type is_attracted_to_gender: Union[bool, None] + :param preference_type: The type of preference to use. Default is CommonGenderPreferenceType.ROMANTIC. + :type preference_type: Union[CommonGenderPreferenceType, GenderPreferenceType], optional + :return: True, if successfully set. False, it not. + :rtype: CommonExecutionResult + """ + if preference_type == CommonGenderPreferenceType.ROMANTIC or preference_type == GenderPreferenceType.ROMANTIC: + attraction_traits_map = GlobalGenderPreferenceTuning.ROMANTIC_PREFERENCE_TRAITS_MAPPING + else: + attraction_traits_map = GlobalGenderPreferenceTuning.WOOHOO_PREFERENCE_TRAITS_MAPPING + vanilla_gender = CommonGender.convert_to_vanilla(gender) + if is_attracted_to_gender is None: + traits_to_remove = ( + attraction_traits_map[vanilla_gender].not_attracted_trait, + attraction_traits_map[vanilla_gender].is_attracted_trait + ) + return CommonTraitUtils.remove_traits(sim_info, traits_to_remove) + + if is_attracted_to_gender: + trait_to_remove = attraction_traits_map[vanilla_gender].not_attracted_trait + trait_to_add = attraction_traits_map[vanilla_gender].is_attracted_trait + else: + trait_to_remove = attraction_traits_map[vanilla_gender].is_attracted_trait + trait_to_add = attraction_traits_map[vanilla_gender].not_attracted_trait + remove_result = CommonTraitUtils.remove_trait(sim_info, trait_to_remove) + if not remove_result: + return remove_result + add_result = CommonTraitUtils.add_trait(sim_info, trait_to_add) + if not add_result: + return add_result + gender_preference_stat_type = GlobalGenderPreferenceTuning.GENDER_PREFERENCE.get(vanilla_gender) + if is_attracted_to_gender: + new_value = gender_preference_stat_type.max_value + else: + new_value = gender_preference_stat_type.min_value + sim_info.set_stat_value(gender_preference_stat_type, new_value) + return CommonExecutionResult.TRUE + + @classmethod + def set_gender_preference_amount(cls, sim_info: SimInfo, gender: CommonGender, amount: int, preference_type: Union[CommonGenderPreferenceType, GenderPreferenceType] = CommonGenderPreferenceType.ROMANTIC) -> bool: + """set_gender_preference_amount(sim_info, gender, amount, preference_type=CommonGenderPreferenceType.ROMANTIC) + + Set the amount a Sim prefers the specified gender. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param gender: An instance of a gender. + :type gender: CommonGender + :param amount: The amount the Sim prefers the specified gender. + :type amount: int + :param preference_type: The type of preference to use. Default is CommonGenderPreferenceType.ROMANTIC. + :type preference_type: Union[CommonGenderPreferenceType, GenderPreferenceType], optional + :return: True, if successfully set. False, it not. + :rtype: bool + """ + if amount > 0: + is_attracted_to_gender = True + elif amount < 0: + is_attracted_to_gender = False + else: + is_attracted_to_gender = None + if cls.set_preference_for_gender(sim_info, gender, is_attracted_to_gender, preference_type=preference_type): + return True + return False + + @classmethod + def get_gender_preference_amount(cls, sim_info: SimInfo, gender: CommonGender, preference_type: Union[CommonGenderPreferenceType, GenderPreferenceType] = CommonGenderPreferenceType.ROMANTIC) -> int: + """get_gender_preference_value(sim_info, gender, preference_type=CommonGenderPreferenceType.ROMANTIC) + + Retrieve the amount a Sim prefers the specified gender. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param gender: An instance of a gender. + :type gender: CommonGender + :param preference_type: The type of preference to use. Default is CommonGenderPreferenceType.ROMANTIC. + :type preference_type: Union[CommonGenderPreferenceType, GenderPreferenceType], optional + :return: The amount the Sim prefers the specified gender. + :rtype: int + """ + if cls.has_preference_for_gender(sim_info, gender, preference_type=preference_type): + return 100 + return 0 + + @classmethod + def get_default_preferred_genders(cls, sim_info: SimInfo) -> Tuple[CommonGender]: + """get_default_preferred_genders(sim_info) + + Retrieve a collection of default gender preferences. + + .. note:: By default Male Sims prefer Female Sims and Female Sims prefer Male Sims. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: A collection of the default preferred genders. + :rtype: Tuple[CommonGender] + """ + from sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils + if CommonGenderUtils.is_male(sim_info): + return CommonGender.FEMALE, + return CommonGender.MALE, + + @classmethod + def has_preference_for_gender(cls, sim_info: SimInfo, gender: CommonGender, like_threshold: int = None, love_threshold: int = None, preference_type: Union[CommonGenderPreferenceType, GenderPreferenceType] = CommonGenderPreferenceType.ROMANTIC) -> bool: + """has_preference_for_gender(sim_info, gender, like_threshold=None, love_threshold=None, preference_type=CommonGenderPreferenceType.ROMANTIC) + + Determine if a Sim has a preference for the specified gender. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param gender: An instance of a CommonGender. + :type gender: CommonGender + :param like_threshold: A value indicating a low amount of preference. Default is CommonSimGenderPreferenceUtils.LOW_PREFERENCE_THRESHOLD. (This argument is obsolete, do not use) + :type like_threshold: int, optional + :param love_threshold: A value indicating a high amount of preference. Default is CommonSimGenderPreferenceUtils.HIGH_PREFERENCE_THRESHOLD. (This argument is obsolete, do not use) + :type love_threshold: int, optional + :param preference_type: The type of preference to use. Default is CommonGenderPreferenceType.ROMANTIC. + :type preference_type: Union[CommonGenderPreferenceType, GenderPreferenceType], optional + :return: True, if the Sim has a preference for the specified gender. False, if not. + :rtype: bool + """ + preferences = cls.determine_preferred_genders( + sim_info, + like_threshold=like_threshold, + love_threshold=love_threshold, + preference_type=preference_type, + ) + return gender in preferences + + @classmethod + def has_preference_for(cls, sim_info: SimInfo, target_sim_info: SimInfo, like_threshold: int = None, love_threshold: int = None, preference_type: Union[CommonGenderPreferenceType, GenderPreferenceType] = CommonGenderPreferenceType.ROMANTIC) -> bool: + """has_preference_for(sim_info, target_sim_info, like_threshold=None, love_threshold=None, preference_type=CommonGenderPreferenceType.ROMANTIC) + + Determine if a Sim has a preference for another Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param target_sim_info: An instance of a Sim. + :type target_sim_info: SimInfo + :param like_threshold: A value indicating a low amount of preference. Default is CommonSimGenderPreferenceUtils.LOW_PREFERENCE_THRESHOLD. (This argument is obsolete, do not use) + :type like_threshold: int, optional + :param love_threshold: A value indicating a high amount of preference. Default is CommonSimGenderPreferenceUtils.HIGH_PREFERENCE_THRESHOLD. (This argument is obsolete, do not use) + :type love_threshold: int, optional + :param preference_type: The type of preference to use. Default is CommonGenderPreferenceType.ROMANTIC. + :type preference_type: Union[CommonGenderPreferenceType, GenderPreferenceType], optional + :return: True, if the Source Sim has a preference for the Target Sim. False, if not. + :rtype: bool + """ + return cls.has_preference_for_gender( + sim_info, + CommonGender.get_gender(target_sim_info), + like_threshold=like_threshold, + love_threshold=love_threshold, + preference_type=preference_type, + ) + + # noinspection PyUnusedLocal + @classmethod + def determine_preferred_genders(cls, sim_info: SimInfo, like_threshold: int = None, love_threshold: int = None, preference_type: Union[CommonGenderPreferenceType, GenderPreferenceType] = CommonGenderPreferenceType.ROMANTIC) -> Tuple[CommonGender]: + """determine_preferred_genders(sim_info, like_threshold=None, love_threshold=None, preference_type=CommonGenderPreferenceType.ROMANTIC) + + Determine which genders a Sim prefers. + + .. note:: + + The math is as follows (The first match will return): + + - Default Gender Preferences = MALE_PREF < like_threshold and FEMALE_PREF < like_threshold + - Prefers both Genders = absolute(MALE_PREF - FEMALE_PREF) <= love_threshold + - Prefers Male = MALE_PREF > FEMALE_PREF + - Prefers Female = FEMALE_PREF > MALE_PREF + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param like_threshold: A value indicating a low amount of preference. Default is cls.LOW_PREFERENCE_THRESHOLD. (This argument is obsolete, do not use) + :type like_threshold: int, optional + :param love_threshold: A value indicating a high amount of preference. Default is cls.HIGH_PREFERENCE_THRESHOLD. (This argument is obsolete, do not use) + :type love_threshold: int, optional + :param preference_type: The type of preference to use. Default is CommonGenderPreferenceType.ROMANTIC. + :type preference_type: Union[CommonGenderPreferenceType, GenderPreferenceType], optional + :return: A collection of CommonGenders the specified Sim prefers. + :rtype: Tuple[CommonGender] + """ + preferred_genders = list() + vanilla_preference_type = CommonGenderPreferenceType.convert_to_vanilla(preference_type) + for gender in sim_info.get_attracted_genders(vanilla_preference_type): + preferred_genders.append(CommonGender.convert_from_vanilla(gender)) + return tuple(preferred_genders) + + @classmethod + def set_to_default_gender_preferences(cls, sim_info: SimInfo) -> None: + """set_to_default_gender_preferences(sim_info) + + Set a Sim to the default gender preferences. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + """ + default_attracted_to_genders = cls.get_default_preferred_genders(sim_info) + for gender in CommonGender.get_all(): + if gender in default_attracted_to_genders: + cls.set_preference_for_gender(sim_info, gender, True, preference_type=CommonGenderPreferenceType.ROMANTIC) + cls.set_preference_for_gender(sim_info, gender, True, preference_type=CommonGenderPreferenceType.WOOHOO) + else: + cls.set_preference_for_gender(sim_info, gender, False, preference_type=CommonGenderPreferenceType.ROMANTIC) + cls.set_preference_for_gender(sim_info, gender, False, preference_type=CommonGenderPreferenceType.WOOHOO) + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.set_world_sexually_exploring', + 'Set all Sims to be sexually exploring in their Sexual Orientation.', + command_arguments=( + CommonConsoleCommandArgument('is_sexually_exploring', 'True or False', 'If True, all Sims will be sexually exploring. If False, all Sims will NOT be sexually exploring.'), + ) +) +def _common_set_world_sexually_exploring(output: CommonConsoleCommandOutput, is_sexually_exploring: bool): + if is_sexually_exploring: + output('Attempting to set all Sims to be Sexually Exporing in their Sexual Orientation.') + else: + output('Attempting to set all Sims to be Not Sexually Exporing in their Sexual Orientation.') + for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): + from sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils + CommonSimGenderOptionUtils.set_is_exploring_sexuality(sim_info, is_sexually_exploring) + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.set_gender_pref', + 'Set the gender preference amount of a Sim towards a Gender.', + command_arguments=( + CommonConsoleCommandArgument('gender', 'CommonGender', f'The gender to change the preference of the Sim for. Valid Values: {CommonGender.get_comma_separated_names_string()}'), + CommonConsoleCommandArgument('is_attracted_to_gender', 'True or False', 'If True, the Sim will be attracted to the specified Gender. If False, the Sim will no longer be attracted to the gender.'), + CommonConsoleCommandArgument('preference_type', 'ROMANTIC or WOOHOO', 'The type of preference being updated.', is_optional=True, default_value='ROMANTIC'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance id or name of the Sim to change.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.setgenderpref', + 's4clib.set_gender_preference', + 's4clib.setgenderpreference', + ) +) +def _common_set_gender_pref(output: CommonConsoleCommandOutput, gender: CommonGender, is_attracted_to_gender: bool, preference_type: CommonGenderPreferenceType = CommonGenderPreferenceType.ROMANTIC, sim_info: SimInfo = None): + if gender is None: + return + if sim_info is None: + return + gender_name = gender.name + output(f'Attempting to set the {preference_type.name} gender preference of Sim {sim_info} for gender {gender_name} to {is_attracted_to_gender}') + if CommonSimGenderPreferenceUtils.set_preference_for_gender(sim_info, gender, is_attracted_to_gender, preference_type=preference_type): + output(f'SUCCESS: Successfully set the {preference_type.name} gender preference of Sim {sim_info} for gender {gender_name} to {is_attracted_to_gender}') + else: + output(f'FAILED: Failed to set the {preference_type.name} gender preference of Sim {sim_info} for gender {gender_name} to {is_attracted_to_gender}') + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.set_gender_pref_of_all_sims', + 'Set the gender preference amount of all Sims towards a Gender.', + command_arguments=( + CommonConsoleCommandArgument('gender', 'CommonGender', f'The gender to change the preferences of the Sims for. Valid Values: {CommonGender.get_comma_separated_names_string()}'), + CommonConsoleCommandArgument('is_attracted_to_gender', 'True or False', 'If True, all Female Sims will be attracted to the specified Gender. If False, all Female Sims will no longer be attracted to the gender.'), + CommonConsoleCommandArgument('preference_type', 'ROMANTIC or WOOHOO', 'The type of preference being updated.', is_optional=True, default_value='ROMANTIC') + ), + command_aliases=( + 's4clib.setgenderprefofallsims', + 's4clib.setgenderpreferenceofallsims', + 's4clib.set_gender_preference_of_all_sims', + 's4clib.set_all_gender_preferences', + 's4clib.setallgenderpreferences', + ) +) +def _common_set_gender_pref_of_all_sims(output: CommonConsoleCommandOutput, gender: CommonGender, is_attracted_to_gender: bool, preference_type: CommonGenderPreferenceType = CommonGenderPreferenceType.ROMANTIC): + if gender is None: + return + gender_name = gender.name + count_of_sims_changed = 0 + output(f'Setting {preference_type.name} gender preference of all Sims for gender {gender_name} to {is_attracted_to_gender}') + for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): + try: + if CommonSimGenderPreferenceUtils.set_preference_for_gender(sim_info, gender, is_attracted_to_gender, preference_type=preference_type): + count_of_sims_changed += 1 + except Exception as ex: + CommonExceptionHandler.log_exception(ModInfo.get_identity(), f'Failed to set {preference_type.name} gender preference of Sim {sim_info} for gender {gender_name} to {is_attracted_to_gender}', exception=ex) + output(f'ERROR: Failed to set {preference_type.name} gender preference of Sim {sim_info} for gender {gender} to {is_attracted_to_gender}. Exception: {ex}') + output(f'Updated the Gender Preferences of {count_of_sims_changed} Sims.') + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.set_gender_pref_of_all_female_sims', + 'Set the gender preference amount of all Female Sims towards a Gender.', + command_arguments=( + CommonConsoleCommandArgument('gender', 'CommonGender', f'The gender to change the preferences of the Sims for. Valid Values: {CommonGender.get_comma_separated_names_string()}'), + CommonConsoleCommandArgument('is_attracted_to_gender', 'True or False', 'If True, all Female Sims will be attracted to the specified Gender. If False, all Female Sims will no longer be attracted to the gender.'), + CommonConsoleCommandArgument('preference_type', 'ROMANTIC or WOOHOO', 'The type of preference being updated.', is_optional=True, default_value='ROMANTIC') + ), + command_aliases=( + 's4clib.setgenderprefofallfemalesims', + 's4clib.setgenderpreferenceofallfemalesims', + 's4clib.set_gender_preference_of_all_female_sims', + 's4clib.set_all_female_gender_preferences', + 's4clib.setallfemalegenderpreferences', + ) +) +def _common_set_gender_pref_of_all_female_sims(output: CommonConsoleCommandOutput, gender: CommonGender, is_attracted_to_gender: bool, preference_type: CommonGenderPreferenceType = CommonGenderPreferenceType.ROMANTIC): + if gender is None: + return + gender_name = gender.name + sim_count = 0 + output(f'Setting {preference_type.name} gender preference of all Female Sims for gender {gender_name} to {is_attracted_to_gender}') + from sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils + for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(include_sim_callback=CommonGenderUtils.is_female): + try: + if CommonSimGenderPreferenceUtils.set_preference_for_gender(sim_info, gender, is_attracted_to_gender, preference_type=preference_type): + sim_count += 1 + except Exception as ex: + CommonExceptionHandler.log_exception(ModInfo.get_identity(), f'Failed to set {preference_type.name} gender preference of Sim {sim_info} for gender {gender_name} to {is_attracted_to_gender}.', exception=ex) + output(f'Failed to set {preference_type.name} gender preference of Sim {sim_info} for gender {gender_name} to {is_attracted_to_gender}. Exception: {ex}') + output(f'Updated Gender Preferences of {sim_count} Sims.') + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.set_gender_pref_of_all_male_sims', + 'Set the gender preference of all Male Sims towards a Gender.', + command_arguments=( + CommonConsoleCommandArgument('gender', 'CommonGender', f'The gender to change the preferences of the Sims for. Valid Values: {CommonGender.get_comma_separated_names_string()}'), + CommonConsoleCommandArgument('is_attracted_to_gender', 'True or False', 'If True, all Male Sims will be attracted to the specified Gender. If False, all Male Sims will no longer be attracted to the gender.'), + CommonConsoleCommandArgument('preference_type', 'ROMANTIC or WOOHOO', 'The type of preference being updated.', is_optional=True, default_value='ROMANTIC') + ), + command_aliases=( + 's4clib.setgenderprefofallmalesims', + 's4clib.setgenderpreferenceofallmalesims', + 's4clib.set_gender_preference_of_all_male_sims', + 's4clib.set_all_male_gender_preferences', + 's4clib.setallmalegenderpreferences', + ) +) +def _common_set_gender_pref_of_all_male_sims(output: CommonConsoleCommandOutput, gender: CommonGender, is_attracted_to_gender: bool, preference_type: CommonGenderPreferenceType = CommonGenderPreferenceType.ROMANTIC): + if gender is None: + return + gender_name = gender.name + sim_count = 0 + output(f'Setting {preference_type.name} gender preference of all Male Sims for gender {gender_name} to {is_attracted_to_gender}') + from sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils + for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(include_sim_callback=CommonGenderUtils.is_male): + try: + if CommonSimGenderPreferenceUtils.set_preference_for_gender(sim_info, gender, is_attracted_to_gender, preference_type=preference_type): + sim_count += 1 + except Exception as ex: + CommonExceptionHandler.log_exception(ModInfo.get_identity(), f'Failed to set {preference_type.name} gender preference of Sim {sim_info} for gender {gender_name} to {is_attracted_to_gender}.', exception=ex) + output(f'Failed to set {preference_type.name} gender preference of Sim {sim_info} for gender {gender_name} to {is_attracted_to_gender}. Exception: {ex}') + output(f'Updated Gender Preferences of {sim_count} Sims.') + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.print_gender_pref', + 'Print the gender preference amount a Sim has towards a Gender.', + command_arguments=( + CommonConsoleCommandArgument('gender', 'CommonGender', f'The gender to change the preference of the Sim for. Valid Values: {CommonGender.get_comma_separated_names_string()}'), + CommonConsoleCommandArgument('preference_type', 'ROMANTIC or WOOHOO', 'The type of preference being checked.', is_optional=True, default_value='ROMANTIC'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance id or name of the Sim to change.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.printgenderpref', + 's4clib.print_gender_preference', + 's4clib.printgenderpreference', + ) +) +def _common_get_gender_pref(output: CommonConsoleCommandOutput, gender: CommonGender, preference_type: CommonGenderPreferenceType = CommonGenderPreferenceType.ROMANTIC, sim_info: SimInfo = None): + if gender is None: + return + if sim_info is None: + return + gender_name = gender.name + preference_percentage_amount = CommonSimGenderPreferenceUtils.get_gender_preference_amount(sim_info, gender, preference_type=preference_type) + output(f'{sim_info} has a {preference_percentage_amount}% preference for gender {gender_name}') + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.print_preferred_genders', + 'Print preferred genders a Sim is attracted to.', + command_arguments=( + CommonConsoleCommandArgument('preference_type', 'ROMANTIC or WOOHOO', 'The type of preference being checked.', is_optional=True, default_value='ROMANTIC'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance id or name of the Sim to change.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.printpreferredgenders', + ) +) +def _common_get_gender_pref(output: CommonConsoleCommandOutput, preference_type: CommonGenderPreferenceType = CommonGenderPreferenceType.ROMANTIC, sim_info: SimInfo = None): + if sim_info is None: + return + preferred_genders = CommonSimGenderPreferenceUtils.determine_preferred_genders(sim_info, preference_type=preference_type) + output(f'{sim_info} has a {preference_type.name} gender preference for genders {preferred_genders}') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.apply_default_gender_pref', + 'Apply the default Gender preferences for ROMANTIC and WOOHOO preference types to a Sim.', + command_arguments=( + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance id or name of the Sim to change.', is_optional=True, default_value='Active Sim'), + ), +) +def _s4clib_apply_default_gender_pref_to_sim(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): + if sim_info is None: + return + output(f'Attempting to update the gender preferences to their default values for {sim_info}.') + # noinspection PyBroadException + try: + CommonSimGenderPreferenceUtils.set_to_default_gender_preferences(sim_info) + except: + output(f'Failed to update Sim {sim_info}. They were most likely culled out or unavailable.') + return True + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.apply_default_gender_pref_to_all_sims', + 'Apply the default Gender preference for ROMANTIC and WOOHOO preference types to all Sims using their Gender.' +) +def _s4clib_apply_default_gender_pref_to_all_sims(output: CommonConsoleCommandOutput): + output('Attempting to update the gender preferences to their default values for all Sims.') + sim_count = 0 + for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): + # noinspection PyBroadException + try: + if sim_info is None: + continue + CommonSimGenderPreferenceUtils.set_to_default_gender_preferences(sim_info) + sim_count += 1 + except: + output(f'Failed to update Sim {sim_info}. They were most likely culled out or unavailable.') + output(f'Updated Gender Preferences of {sim_count} Sim(s).') + return True diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_genealogy_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_genealogy_utils.py new file mode 100644 index 0000000..bab5daa --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_genealogy_utils.py @@ -0,0 +1,572 @@ +""" +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 +""" +from typing import Union, Tuple + +from sims.genealogy_tracker import GenealogyTracker, FamilyRelationshipIndex +from sims.sim_info import SimInfo +from sims4communitylib.enums.relationship_bits_enum import CommonRelationshipBitId +from sims4communitylib.utils.sims.common_relationship_utils import CommonRelationshipUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + + +class CommonSimGenealogyUtils: + """Utilities for managing and manipulating the Genealogy of Sims.""" + @staticmethod + def get_genealogy_tracker(sim_info: SimInfo) -> Union[GenealogyTracker, None]: + """get_genealogy_tracker(sim_info) + + Retrieve the Genealogy Tracker for a Sim. + + .. note: A Genealogy Tracker is essentially just the Family Tree Tracker of the Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The genealogy tracker of the Sim or None if not found. + :rtype: Union[GenealogyTracker, None] + """ + if sim_info is None: + return None + return sim_info._genealogy_tracker + + @staticmethod + def set_as_father_of(sim_info: SimInfo, new_child_sim_info: SimInfo, propagate: bool=False) -> bool: + """set_as_father_of(sim_info, new_child_sim_info, propagate=False) + + Set a Sim to be the Father of another Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param new_child_sim_info: The new child of Sim A. + :type new_child_sim_info: SimInfo + :param propagate: If set to True, the grandparent relations will also be updated. Default is False. + :type propagate: bool, optional + :return: True, if the relation was set successfully. False, if not. + :rtype: bool + """ + genealogy_tracker = CommonSimGenealogyUtils.get_genealogy_tracker(new_child_sim_info) + if genealogy_tracker is None: + return False + if propagate: + genealogy_tracker.set_and_propagate_family_relation(FamilyRelationshipIndex.FATHER, sim_info) + else: + genealogy_tracker.set_family_relation(FamilyRelationshipIndex.FATHER, CommonSimUtils.get_sim_id(sim_info)) + return True + + @staticmethod + def set_as_mother_of(sim_info: SimInfo, new_child_sim_info: SimInfo, propagate: bool=False) -> bool: + """set_as_mother_of(sim_info, new_child_sim_info, propagate=False) + + Set a Sim to be the Mother of another Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param new_child_sim_info: The new child of Sim A. + :type new_child_sim_info: SimInfo + :param propagate: If set to True, the grandparent relations will also be updated. Default is False. + :type propagate: bool, optional + :return: True, if the relation was set successfully. False, if not. + :rtype: bool + """ + genealogy_tracker = CommonSimGenealogyUtils.get_genealogy_tracker(new_child_sim_info) + if genealogy_tracker is None: + return False + if propagate: + genealogy_tracker.set_and_propagate_family_relation(FamilyRelationshipIndex.MOTHER, sim_info) + else: + genealogy_tracker.set_family_relation(FamilyRelationshipIndex.MOTHER, CommonSimUtils.get_sim_id(sim_info)) + return True + + @staticmethod + def set_as_fathers_father_of(sim_info: SimInfo, new_grandchild_sim_info: SimInfo) -> bool: + """set_as_fathers_father_of(sim_info, new_fathers_father_sim_info) + + Set a Sim to be the Fathers Father of another Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param new_grandchild_sim_info: The new grandchild of Sim A. + :type new_grandchild_sim_info: SimInfo + :return: True, if the relation was set successfully. False, if not. + :rtype: bool + """ + genealogy_tracker = CommonSimGenealogyUtils.get_genealogy_tracker(new_grandchild_sim_info) + if genealogy_tracker is None: + return False + genealogy_tracker.set_and_propagate_family_relation(FamilyRelationshipIndex.FATHERS_FATHER, sim_info) + return True + + @staticmethod + def set_as_fathers_mother_of(sim_info: SimInfo, new_grandchild_sim_info: SimInfo) -> bool: + """set_as_fathers_mother_of(sim_info, new_grandchild_sim_info) + + Retrieve the Father of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param new_grandchild_sim_info: The new grandchild of Sim A. + :type new_grandchild_sim_info: SimInfo + :return: True, if the relation was set successfully. False, if not. + :rtype: bool + """ + genealogy_tracker = CommonSimGenealogyUtils.get_genealogy_tracker(new_grandchild_sim_info) + if genealogy_tracker is None: + return False + genealogy_tracker.set_family_relation(FamilyRelationshipIndex.FATHERS_MOM, sim_info) + return True + + @staticmethod + def set_as_mothers_father_of(sim_info: SimInfo, new_grandchild_sim_info: SimInfo) -> bool: + """set_as_mothers_father_of(sim_info, new_grandchild_sim_info) + + Retrieve the Father of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param new_grandchild_sim_info: The new grandchild of Sim A. + :type new_grandchild_sim_info: SimInfo + :return: True, if the relation was set successfully. False, if not. + :rtype: bool + """ + genealogy_tracker = CommonSimGenealogyUtils.get_genealogy_tracker(new_grandchild_sim_info) + if genealogy_tracker is None: + return False + genealogy_tracker.set_and_propagate_family_relation(FamilyRelationshipIndex.MOTHERS_FATHER, sim_info) + return True + + @staticmethod + def set_as_mothers_mother_of(sim_info: SimInfo, new_grandchild_sim_info: SimInfo) -> bool: + """set_as_mothers_mother_of(sim_info, new_grandchild_sim_info) + + Retrieve the Father of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param new_grandchild_sim_info: The new grandchild of Sim A. + :type new_grandchild_sim_info: SimInfo + :return: True, if the relation was set successfully. False, if not. + :rtype: bool + """ + genealogy_tracker = CommonSimGenealogyUtils.get_genealogy_tracker(new_grandchild_sim_info) + if genealogy_tracker is None: + return False + genealogy_tracker.set_and_propagate_family_relation(FamilyRelationshipIndex.MOTHERS_MOM, sim_info) + return True + + @staticmethod + def get_father_sim_info(sim_info: SimInfo) -> Union[SimInfo, None]: + """get_father_sim_info(sim_info) + + Retrieve the Father of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The father of the Sim or None if the Sim does not have a father. + :rtype: Union[SimInfo, None] + """ + return CommonSimGenealogyUtils._retrieve_relation_sim_info(sim_info, FamilyRelationshipIndex.FATHER) + + @staticmethod + def get_mother_sim_info(sim_info: SimInfo) -> Union[SimInfo, None]: + """get_mother_sim_info(sim_info) + + Retrieve the Mother of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The mother of the Sim or None if the Sim does not have a mother. + :rtype: Union[SimInfo, None] + """ + return CommonSimGenealogyUtils._retrieve_relation_sim_info(sim_info, FamilyRelationshipIndex.MOTHER) + + @staticmethod + def get_mothers_mother_sim_info(sim_info: SimInfo) -> Union[SimInfo, None]: + """get_mothers_mother_sim_info(sim_info) + + Retrieve the Grandmother of a Sim on their mothers side. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The grandmother of the Sim on their mothers side or None if the Sim does not have a mother or their mother does not have a mother. + :rtype: Union[SimInfo, None] + """ + return CommonSimGenealogyUtils._retrieve_relation_sim_info(sim_info, FamilyRelationshipIndex.MOTHERS_MOM) + + @staticmethod + def get_mothers_father_sim_info(sim_info: SimInfo) -> Union[SimInfo, None]: + """get_mothers_father_sim_info(sim_info) + + Retrieve the Grandfather of a Sim on their mothers side. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The grandfather of the Sim on their mothers side or None if the Sim does not have a mother or their mother does not have a father. + :rtype: Union[SimInfo, None] + """ + return CommonSimGenealogyUtils._retrieve_relation_sim_info(sim_info, FamilyRelationshipIndex.MOTHERS_FATHER) + + @staticmethod + def get_fathers_mother_sim_info(sim_info: SimInfo) -> Union[SimInfo, None]: + """get_fathers_mother_sim_info(sim_info) + + Retrieve the Grandmother of a Sim on their fathers side. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The grandmother of the Sim on their fathers side or None if the Sim does not have a father or their father does not have a mother. + :rtype: Union[SimInfo, None] + """ + return CommonSimGenealogyUtils._retrieve_relation_sim_info(sim_info, FamilyRelationshipIndex.FATHERS_MOM) + + @staticmethod + def get_fathers_father_sim_info(sim_info: SimInfo) -> Union[SimInfo, None]: + """get_fathers_father_sim_info(sim_info) + + Retrieve the Grandfather of a Sim on their fathers side. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The grandfather of the Sim on their fathers side or None if the Sim does not have a father or their father does not have a mother. + :rtype: Union[SimInfo, None] + """ + return CommonSimGenealogyUtils._retrieve_relation_sim_info(sim_info, FamilyRelationshipIndex.FATHERS_FATHER) + + @staticmethod + def remove_family_relations_with(sim_info_a: SimInfo, sim_info_b: SimInfo, remove_from_family_tree: bool=True) -> bool: + """remove_family_relations_with(sim_info_a, sim_info_b, remove_from_family_tree=True) + + Remove the family relations Sim A has with Sim B and the family relations Sim B has with Sim A. + + :param sim_info_a: An instance of a Sim. + :type sim_info_a: SimInfo + :param sim_info_b: The Sim to remove from the family of Sim A. + :type sim_info_b: SimInfo + :param remove_from_family_tree: If True, Sim A will remove Sim B from their family tree as well. If False, the family tree of Sim A will not be modified. Default is True. + :type remove_from_family_tree: bool, optional + :return: True, if the family relations between the Sims was removed successfully. False, if not. + :rtype: bool + """ + if remove_from_family_tree: + if CommonSimGenealogyUtils.is_father_of(sim_info_a, sim_info_b): + CommonSimGenealogyUtils.remove_father_relation(sim_info_b) + if CommonSimGenealogyUtils.is_mother_of(sim_info_a, sim_info_b): + CommonSimGenealogyUtils.remove_mother_relation(sim_info_b) + if CommonSimGenealogyUtils.is_fathers_father_of(sim_info_a, sim_info_b): + CommonSimGenealogyUtils.remove_fathers_father_relation(sim_info_b) + if CommonSimGenealogyUtils.is_fathers_mother_of(sim_info_a, sim_info_b): + CommonSimGenealogyUtils.remove_fathers_mother_relation(sim_info_b) + if CommonSimGenealogyUtils.is_mothers_father_of(sim_info_a, sim_info_b): + CommonSimGenealogyUtils.remove_mothers_father_relation(sim_info_b) + if CommonSimGenealogyUtils.is_mothers_mother_of(sim_info_a, sim_info_b): + CommonSimGenealogyUtils.remove_mothers_mother_relation(sim_info_b) + + # noinspection PyTypeChecker + relationship_bit_ids: Tuple[CommonRelationshipBitId] = ( + CommonRelationshipBitId.FAMILY_AUNT_UNCLE, + CommonRelationshipBitId.FAMILY_SON_DAUGHTER, + CommonRelationshipBitId.FAMILY_COUSIN, + CommonRelationshipBitId.FAMILY_PARENT, + CommonRelationshipBitId.FAMILY_GRANDCHILD, + CommonRelationshipBitId.FAMILY_GRANDPARENT, + CommonRelationshipBitId.FAMILY_HUSBAND_WIFE, + CommonRelationshipBitId.FAMILY_NIECE_NEPHEW, + CommonRelationshipBitId.FAMILY_BROTHER_SISTER, + CommonRelationshipBitId.FAMILY_STEP_SIBLING + ) + + for relationship_bit_id in relationship_bit_ids: + CommonRelationshipUtils.remove_relationship_bit(sim_info_a, sim_info_b, relationship_bit_id) + return True + + @staticmethod + def remove_father_relation(sim_info: SimInfo) -> bool: + """remove_father_relation(sim_info) + + Remove the Father of a Sim from their Family Tree. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: True, if the father of the Sim has been removed. False, if not. + :rtype: bool + """ + genealogy_tracker = CommonSimGenealogyUtils.get_genealogy_tracker(sim_info) + if genealogy_tracker is None: + return False + genealogy_tracker.clear_family_relation(FamilyRelationshipIndex.FATHER) + return True + + @staticmethod + def remove_mother_relation(sim_info: SimInfo) -> bool: + """remove_mother_relation(sim_info) + + Remove the Mother of a Sim from their Family Tree. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: True, if the mother of the Sim has been removed. False, if not. + :rtype: bool + """ + genealogy_tracker = CommonSimGenealogyUtils.get_genealogy_tracker(sim_info) + if genealogy_tracker is None: + return False + genealogy_tracker.clear_family_relation(FamilyRelationshipIndex.MOTHER) + return True + + @staticmethod + def remove_fathers_father_relation(sim_info: SimInfo) -> bool: + """remove_fathers_father_relation(sim_info) + + Remove the relation of a Sim to their Grandfather on their fathers side from their Family Tree. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: True, if the grandfather of the Sim has been removed. False, if not. + :rtype: bool + """ + genealogy_tracker = CommonSimGenealogyUtils.get_genealogy_tracker(sim_info) + if genealogy_tracker is None: + return False + genealogy_tracker.clear_family_relation(FamilyRelationshipIndex.FATHERS_FATHER) + return True + + @staticmethod + def remove_fathers_mother_relation(sim_info: SimInfo) -> bool: + """remove_fathers_mother_relation(sim_info) + + Remove the relation of a Sim to their Grandmother on their fathers side from their Family Tree. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: True, if the grandmother of the Sim has been removed. False, if not. + :rtype: bool + """ + genealogy_tracker = CommonSimGenealogyUtils.get_genealogy_tracker(sim_info) + if genealogy_tracker is None: + return False + genealogy_tracker.clear_family_relation(FamilyRelationshipIndex.FATHERS_MOM) + return True + + @staticmethod + def remove_mothers_father_relation(sim_info: SimInfo) -> bool: + """remove_mothers_father_relation(sim_info) + + Remove the Father of the Mother of a Sim from their Family Tree. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: True, if the father of the mother of the Sim has been removed. False, if not. + :rtype: bool + """ + genealogy_tracker = CommonSimGenealogyUtils.get_genealogy_tracker(sim_info) + if genealogy_tracker is None: + return False + genealogy_tracker.clear_family_relation(FamilyRelationshipIndex.MOTHERS_FATHER) + return True + + @staticmethod + def remove_mothers_mother_relation(sim_info: SimInfo) -> bool: + """remove_mothers_mother_relation(sim_info) + + Remove the relation of a Sim to their Grandmother on their mothers side from their Family Tree. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: True, if the grandmother of the Sim has been removed. False, if not. + :rtype: bool + """ + genealogy_tracker = CommonSimGenealogyUtils.get_genealogy_tracker(sim_info) + if genealogy_tracker is None: + return False + genealogy_tracker.clear_family_relation(FamilyRelationshipIndex.MOTHERS_MOM) + return True + + @staticmethod + def is_father_of(sim_info_a: SimInfo, sim_info_b: SimInfo) -> bool: + """is_father_of(sim_info_a, sim_info_b) + + Determine if Sim A is the father of Sim B. + + :param sim_info_a: An instance of a Sim. + :type sim_info_a: SimInfo + :param sim_info_b: An instance of a Sim. + :type sim_info_b: SimInfo + :return: True, if Sim A is the father of Sim B. False, if not. + :rtype: bool + """ + parent_sim_info_b = CommonSimGenealogyUtils.get_father_sim_info(sim_info_b) + return sim_info_a is parent_sim_info_b + + @staticmethod + def is_mother_of(sim_info_a: SimInfo, sim_info_b: SimInfo) -> bool: + """is_mother_of(sim_info_a, sim_info_b) + + Determine if Sim A is the mother of Sim B. + + :param sim_info_a: An instance of a Sim. + :type sim_info_a: SimInfo + :param sim_info_b: An instance of a Sim. + :type sim_info_b: SimInfo + :return: True, if Sim A is the mother of Sim B. False, if not. + :rtype: bool + """ + parent_sim_info_b = CommonSimGenealogyUtils.get_mother_sim_info(sim_info_b) + return sim_info_a is parent_sim_info_b + + @staticmethod + def is_fathers_father_of(sim_info_a: SimInfo, sim_info_b: SimInfo) -> bool: + """is_fathers_father_of(sim_info_a, sim_info_b) + + Determine if Sim A is the grandfather of Sim B on the fathers side of Sim B. + + :param sim_info_a: An instance of a Sim. + :type sim_info_a: SimInfo + :param sim_info_b: An instance of a Sim. + :type sim_info_b: SimInfo + :return: True, if Sim A is the grandfather of Sim B on their fathers side. False, if not. + :rtype: bool + """ + grand_parent_sim_info_b = CommonSimGenealogyUtils.get_fathers_father_sim_info(sim_info_b) + return sim_info_a is grand_parent_sim_info_b + + @staticmethod + def is_fathers_mother_of(sim_info_a: SimInfo, sim_info_b: SimInfo) -> bool: + """is_fathers_mother_of(sim_info_a, sim_info_b) + + Determine if Sim A is the grandmother of Sim B on the fathers side of Sim B. + + :param sim_info_a: An instance of a Sim. + :type sim_info_a: SimInfo + :param sim_info_b: An instance of a Sim. + :type sim_info_b: SimInfo + :return: True, if Sim A is the grandmother of Sim B on their fathers side. False, if not. + :rtype: bool + """ + grand_parent_sim_info_b = CommonSimGenealogyUtils.get_fathers_mother_sim_info(sim_info_b) + return sim_info_a is grand_parent_sim_info_b + + @staticmethod + def is_mothers_father_of(sim_info_a: SimInfo, sim_info_b: SimInfo) -> bool: + """is_mothers_father_of(sim_info_a, sim_info_b) + + Determine if Sim A is the grandfather of Sim B on the mothers side of Sim B. + + :param sim_info_a: An instance of a Sim. + :type sim_info_a: SimInfo + :param sim_info_b: An instance of a Sim. + :type sim_info_b: SimInfo + :return: True, if Sim A is the grandfather of Sim B on their mothers side. False, if not. + :rtype: bool + """ + grand_parent_sim_info_b = CommonSimGenealogyUtils.get_mothers_father_sim_info(sim_info_b) + return sim_info_a is grand_parent_sim_info_b + + @staticmethod + def is_mothers_mother_of(sim_info_a: SimInfo, sim_info_b: SimInfo) -> bool: + """is_mothers_mother_of(sim_info_a, sim_info_b) + + Determine if Sim A is the grandmother of Sim B on the mothers side of Sim B. + + :param sim_info_a: An instance of a Sim. + :type sim_info_a: SimInfo + :param sim_info_b: An instance of a Sim. + :type sim_info_b: SimInfo + :return: True, if Sim A is the grandmother of Sim B on their mothers side. False, if not. + :rtype: bool + """ + grand_parent_sim_info_b = CommonSimGenealogyUtils.get_mothers_mother_sim_info(sim_info_b) + return sim_info_a is grand_parent_sim_info_b + + @staticmethod + def has_father(sim_info: SimInfo) -> bool: + """has_father(sim_info) + + Determine if a Sim has a father. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: True, if the Sim has a father. False, if not. + :rtype: bool + """ + return CommonSimGenealogyUtils.get_father_sim_info(sim_info) is not None + + @staticmethod + def has_mother(sim_info: SimInfo) -> bool: + """has_mother(sim_info) + + Determine if Sim A is the mother of Sim B. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: True, if the Sim has a mother. False, if not. + :rtype: bool + """ + return CommonSimGenealogyUtils.get_mother_sim_info(sim_info) is not None + + @staticmethod + def has_grandfather_on_fathers_side(sim_info: SimInfo) -> bool: + """has_grandfather_on_fathers_side(sim_info) + + Determine if a Sim has a grandfather on the fathers side. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: True, if the Sim has a grandfather on the fathers side. False, if not. + :rtype: bool + """ + return CommonSimGenealogyUtils.get_fathers_father_sim_info(sim_info) is not None + + @staticmethod + def has_grandmother_on_fathers_side(sim_info: SimInfo) -> bool: + """has_grandmother_on_fathers_side(sim_info) + + Determine if a Sim has a grandmother on the fathers side. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: True, if the Sim has a grandmother on the fathers side. False, if not. + :rtype: bool + """ + return CommonSimGenealogyUtils.get_fathers_mother_sim_info(sim_info) is not None + + @staticmethod + def has_grandfather_on_mothers_side(sim_info: SimInfo) -> bool: + """has_grandfather_on_mothers_side(sim_info) + + Determine if a Sim has a grandfather on the mothers side. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: True, if the Sim has a grandfather on the mothers side. False, if not. + :rtype: bool + """ + return CommonSimGenealogyUtils.get_mothers_father_sim_info(sim_info) is not None + + @staticmethod + def has_grandmother_on_mothers_side(sim_info: SimInfo) -> bool: + """has_grandmother_on_mothers_side(sim_info) + + Determine if a Sim has a grandmother on the mothers side. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: True, if the Sim has a grandmother on the mothers side. False, if not. + :rtype: bool + """ + return CommonSimGenealogyUtils.get_mothers_mother_sim_info(sim_info) is not None + + @staticmethod + def _retrieve_relation_sim_info(sim_info: SimInfo, relationship_index: FamilyRelationshipIndex) -> Union[SimInfo, None]: + return CommonSimUtils.get_sim_info(CommonSimGenealogyUtils._retrieve_relation_sim_id(sim_info, relationship_index)) + + @staticmethod + def _retrieve_relation_sim_id(sim_info: SimInfo, relationship_index: FamilyRelationshipIndex) -> Union[SimInfo, None]: + genealogy_tracker = CommonSimGenealogyUtils.get_genealogy_tracker(sim_info) + if genealogy_tracker is None: + return None + if relationship_index not in genealogy_tracker._family_relations: + return None + return genealogy_tracker.get_relation(relationship_index) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_interaction_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_interaction_utils.py new file mode 100644 index 0000000..c4c7f65 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_interaction_utils.py @@ -0,0 +1,1419 @@ +""" +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 +""" +from typing import Iterator, Union, Any, Callable, List + +from distributor.shared_messages import IconInfoData +from interactions.aop import AffordanceObjectPair +from interactions.base.interaction import Interaction +from interactions.base.super_interaction import SuperInteraction +from interactions.context import InteractionSource, InteractionContext, QueueInsertStrategy +from interactions.interaction_finisher import FinishingType +from interactions.priority import Priority +from sims.sim_info import SimInfo +from sims4communitylib.classes.testing.common_enqueue_result import CommonEnqueueResult +from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.enums.interactions_enum import CommonInteractionId +from sims4communitylib.logging.has_class_log import HasClassLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + CommonConsoleCommandArgument +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.common_type_utils import CommonTypeUtils +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from sims4communitylib.utils.resources.common_interaction_utils import CommonInteractionUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils + + +class CommonSimInteractionUtils(HasClassLog): + """Utilities for manipulating the interactions of Sims. + + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + return ModInfo.get_identity() + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 'common_sim_interaction_utils' + + @classmethod + def is_sitting(cls, sim_info: SimInfo) -> bool: + """is_sitting(sim_info) + + Determine if a Sim is currently sitting. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is sitting. False, if not. + :rtype: bool + """ + interactions = ( + CommonInteractionId.SIT_PASSIVE, + CommonInteractionId.SEATING_SIT, + CommonInteractionId.SEATING_SIT_CTYAE, + CommonInteractionId.SEATING_SIT_RESTAURANT_RALLY_ONLY, + CommonInteractionId.SEATING_SIT_SINGLE, + CommonInteractionId.SEATING_SIT_TODDLER_BED, + CommonInteractionId.SEATING_SIT_POST_GRAND_MEAL_WAIT_ENJOY_COMPANY, + CommonInteractionId.SEATING_SIT_DIRECTOR_CHAIR, + CommonInteractionId.SEATING_SIT_HAIR_MAKE_UP_CHAIR, + ) + return cls.has_interactions_running_or_queued(sim_info, interactions) + + @classmethod + def is_standing(cls, sim_info: SimInfo) -> bool: + """is_standing(sim_info) + + Determine if a Sim is standing. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is standing. False, if not. + :rtype: bool + """ + interactions = ( + CommonInteractionId.STAND_PASSIVE, + CommonInteractionId.SIM_STAND, + CommonInteractionId.SIM_STAND_EXCLUSIVE, + CommonInteractionId.DOG_STAND, + CommonInteractionId.DOG_STAND_PASSIVE, + CommonInteractionId.CAT_STAND, + CommonInteractionId.CAT_STAND_PASSIVE + ) + return cls.has_interactions_running_or_queued(sim_info, interactions) + + @classmethod + def is_swimming(cls, sim_info: SimInfo) -> bool: + """is_swimming(sim_info) + + Determine if a Sim is swimming. + + .. note: Cats cannot swim. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is swimming. False, if not. + :rtype: bool + """ + interactions = ( + CommonInteractionId.SIM_SWIM, + CommonInteractionId.DOG_SWIM, + CommonInteractionId.DOG_SWIM_PASSIVE + ) + return cls.has_interactions_running_or_queued(sim_info, interactions) + + @staticmethod + def apply_pressure_to_next_interaction_of(sim_info: SimInfo): + """apply_pressure_to_next_interaction_of(sim_info) + + Apply pressure to the interaction queue of a Sim for their next interaction. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None or sim.queue is None: + return + sim.queue._apply_next_pressure() + + @classmethod + def get_swim_interaction(cls, sim_info: SimInfo) -> Union[int, CommonInteractionId]: + """get_swim_interaction(sim_info) + + Retrieve a Swim interaction appropriate for a Sim. + + .. note:: Cats do not have an appropriate Swim interaction. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The decimal identifier of an interaction appropriate for the Sim or -1 if no interaction was found to be appropriate. + :rtype: Union[int, CommonInteractionId] + """ + if CommonSpeciesUtils.is_human(sim_info): + return CommonInteractionId.SIM_SWIM + elif CommonSpeciesUtils.is_dog(sim_info): + return CommonInteractionId.DOG_SWIM + # Cats don't have a swim interaction. Because they cannot swim. + return -1 + + @classmethod + def get_stand_interaction(cls, sim_info: SimInfo) -> Union[int, CommonInteractionId]: + """get_stand_interaction(sim_info) + + Retrieve a Stand interaction appropriate for a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The decimal identifier of a Stand interaction appropriate for the Sim or -1 if no Stand interaction was found to be appropriate. + :rtype: Union[int, CommonInteractionId] + """ + from sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils + if CommonSpeciesUtils.is_human(sim_info): + return CommonInteractionId.SIM_STAND + elif CommonSpeciesUtils.is_dog(sim_info): + return CommonInteractionId.DOG_STAND + elif CommonSpeciesUtils.is_cat(sim_info): + return CommonInteractionId.CAT_STAND + elif CommonSpeciesUtils.is_fox(sim_info): + return CommonInteractionId.FOX_STAND + elif CommonSpeciesUtils.is_horse(sim_info): + return CommonInteractionId.HORSE_STAND + return -1 + + @classmethod + def get_stand_passive_interaction(cls, sim_info: SimInfo) -> Union[int, CommonInteractionId]: + """get_stand_passive_interaction(sim_info) + + Retrieve a Stand Passive interaction appropriate for a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The decimal identifier of a Stand Passive interaction appropriate for the Sim or -1 if no Stand interaction was found to be appropriate. + :rtype: Union[int, CommonInteractionId] + """ + from sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils + if CommonSpeciesUtils.is_human(sim_info): + return CommonInteractionId.STAND_PASSIVE + elif CommonSpeciesUtils.is_dog(sim_info): + return CommonInteractionId.DOG_STAND_PASSIVE + elif CommonSpeciesUtils.is_cat(sim_info): + return CommonInteractionId.CAT_STAND_PASSIVE + elif CommonSpeciesUtils.is_fox(sim_info): + return CommonInteractionId.FOX_STAND_PASSIVE + elif CommonSpeciesUtils.is_horse(sim_info): + return CommonInteractionId.HORSE_STAND_PASSIVE + return -1 + + @classmethod + def lock_interaction_queue(cls, sim_info: SimInfo): + """lock_interaction_queue(sim_info) + + Lock the interaction queue of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None or sim.queue is None: + return + sim.queue.lock() + + @classmethod + def unlock_interaction_queue(cls, sim_info: SimInfo): + """unlock_interaction_queue(sim_info) + + Unlock the interaction queue of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None or sim.queue is None: + return + sim.queue.unlock() + + @classmethod + def has_interaction_running_or_queued(cls, sim_info: SimInfo, interaction_id: Union[int, CommonInteractionId]) -> bool: + """has_interaction_running_or_queued(sim_info, interaction_id) + + Determine if a Sim has the specified interaction running or in their interaction queue. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :param interaction_id: The identifier of the interaction to check for. + :type interaction_id: Union[int, CommonInteractionId] + :return: True, if the Sim has the specified interaction running or queued. False, if not. + :rtype: bool + """ + return cls.has_interactions_running_or_queued(sim_info, (interaction_id, )) + + @classmethod + def has_interaction_running(cls, sim_info: SimInfo, interaction_id: Union[int, CommonInteractionId]) -> bool: + """has_interaction_running(sim_info, interaction_id) + + Determine if a Sim is running the specified interaction. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :param interaction_id: The identifier of the interaction to check for. + :type interaction_id: Union[int, CommonInteractionId] + :return: True, if the Sim has the specified interaction running. False, if not. + :rtype: bool + """ + return cls.has_interactions_running(sim_info, (interaction_id, )) + + @classmethod + def has_interaction_queued(cls, sim_info: SimInfo, interaction_id: Union[int, CommonInteractionId]) -> bool: + """has_interaction_queued(sim_info, interaction_id) + + Determine if a Sim is running the specified interaction. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :param interaction_id: The identifier of the interaction to check for. + :type interaction_id: Union[int, CommonInteractionId] + :return: True, if the Sim has the specified interaction queued. False, if not. + :rtype: bool + """ + return cls.has_interactions_queued(sim_info, (interaction_id, )) + + @classmethod + def has_interactions_running_or_queued(cls, sim_info: SimInfo, interaction_ids: Iterator[Union[int, CommonInteractionId]]) -> bool: + """has_interactions_running_or_queued(sim_info, interaction_ids) + + Determine if a Sim has any of the specified interactions running or in their interaction queue. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :param interaction_ids: An iterator of identifiers of the interactions to check for. + :type interaction_ids: Union[int, CommonInteractionId] + :return: True, if the Sim has any of the specified interactions running or queued. False, if not. + :rtype: bool + """ + for interaction in cls.get_queued_or_running_interactions_gen(sim_info): + interaction_id = CommonInteractionUtils.get_interaction_id(interaction) + if interaction_id in interaction_ids: + return True + return False + + @classmethod + def has_interactions_running(cls, sim_info: SimInfo, interaction_ids: Iterator[int]) -> bool: + """has_interactions_running(sim_info, interaction_ids) + + Determine if a Sim is running any of the specified interactions. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :param interaction_ids: An iterator of identifiers of the interactions to check for. + :type interaction_ids: Union[int, CommonInteractionId] + :return: True, if the Sim has any of the specified interactions running. False, if not. + :rtype: bool + """ + for interaction in cls.get_running_interactions_gen(sim_info): + interaction_id = CommonInteractionUtils.get_interaction_id(interaction) + if interaction_id in interaction_ids: + return True + return False + + @classmethod + def has_interactions_queued(cls, sim_info: SimInfo, interaction_ids: Iterator[int]) -> bool: + """has_interactions_queued(sim_info, interaction_ids) + + Determine if a Sim has any of the specified interactions in their interaction queue. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :param interaction_ids: An iterator of identifiers of the interactions to check for. + :type interaction_ids: Union[int, CommonInteractionId] + :return: True, if the Sim has any of the specified interactions queued. False, if not. + :rtype: bool + """ + for interaction in cls.get_queued_interactions_gen(sim_info): + interaction_id = CommonInteractionUtils.get_interaction_id(interaction) + if interaction_id in interaction_ids: + return True + return False + + @classmethod + def cancel_all_queued_or_running_interactions( + cls, + sim_info: SimInfo, + cancel_reason: str, + finishing_type: FinishingType = FinishingType.USER_CANCEL, + include_interaction_callback: Callable[[Interaction], bool] = None, + **kwargs + ) -> bool: + """cancel_all_queued_or_running_interactions(\ + sim_info,\ + cancel_reason,\ + finishing_type=FinishingType.USER_CANCEL,\ + include_interaction_callback=None,\ + source=None,\ + **kwargs\ + ) + + Cancel all interactions that a Sim currently has queued or is currently running. + + :param sim_info: An instance of a Sim + :type sim_info: SimInfo + :param cancel_reason: The reason for the cancellation. + :type cancel_reason: str + :param finishing_type: The type of finish to finish the interaction with. Default is FinishingType.USER_CANCEL. + :type finishing_type: FinishingType, optional + :param include_interaction_callback: If the result of this callback is True, the Interaction will be cancelled. If set to None, All interactions will be cancelled. Default is None. + :type include_interaction_callback: Callable[[Interaction], bool], optional + :return: True, if all queued and running Interactions that pass the "include" callback were successfully cancelled. False, if not. + :rtype: bool + """ + queued_result = cls.cancel_all_queued_interactions( + sim_info, + cancel_reason, + finishing_type=finishing_type, + include_interaction_callback=include_interaction_callback, + **kwargs + ) + if not queued_result: + return False + running_result = cls.cancel_all_running_interactions( + sim_info, + cancel_reason, + finishing_type=finishing_type, + include_interaction_callback=include_interaction_callback, + **kwargs + ) + if not running_result: + return False + return True + + @classmethod + def cancel_all_running_interactions( + cls, + sim_info: SimInfo, + cancel_reason: str, + finishing_type: FinishingType = FinishingType.USER_CANCEL, + include_interaction_callback: Callable[[Interaction], bool] = None, + **kwargs + ) -> bool: + """cancel_all_running_interactions(\ + sim_info,\ + cancel_reason,\ + finishing_type=FinishingType.USER_CANCEL,\ + include_interaction_callback=None,\ + source=None,\ + **kwargs\ + ) + + Cancel all interactions that a Sim is currently running. + + :param sim_info: An instance of a Sim + :type sim_info: SimInfo + :param cancel_reason: The reason for the cancellation. + :type cancel_reason: str + :param finishing_type: The type of finish to finish the interaction with. Default is FinishingType.USER_CANCEL. + :type finishing_type: FinishingType, optional + :param include_interaction_callback: If the result of this callback is True, the Interaction will be cancelled. If set to None, all interactions will be cancelled. Default is None. + :type include_interaction_callback: Callable[[Interaction], bool], optional + :return: True, if all running interactions were successfully cancelled. False, if not. + :rtype: bool + """ + for interaction in tuple(cls.get_running_interactions_gen(sim_info, include_interaction_callback=include_interaction_callback)): + cls.cancel_interaction(interaction, cancel_reason, finishing_type=finishing_type, **kwargs) + return True + + @classmethod + def cancel_all_queued_interactions( + cls, + sim_info: SimInfo, + cancel_reason: str, + finishing_type: FinishingType = FinishingType.USER_CANCEL, + include_interaction_callback: Callable[[Interaction], bool] = None, + **kwargs + ) -> bool: + """cancel_all_queued_interactions(\ + sim_info,\ + cancel_reason,\ + finishing_type=FinishingType.USER_CANCEL,\ + include_interaction_callback=None,\ + **kwargs\ + ) + + Cancel all interactions that a Sim currently has queued. + + :param sim_info: An instance of a Sim + :type sim_info: SimInfo + :param cancel_reason: The reason for the cancellation. + :type cancel_reason: str + :param finishing_type: The type of finish to finish the interaction with. Default is FinishingType.USER_CANCEL. + :type finishing_type: FinishingType, optional + :param include_interaction_callback: If the result of this callback is True, the Interaction will be cancelled. If set to None, all interactions will be cancelled. Default is None. + :type include_interaction_callback: Callable[[Interaction], bool], optional + :return: True, if all queued interactions were successfully cancelled. False, if not. + :rtype: bool + """ + for interaction in tuple(cls.get_queued_interactions_gen(sim_info, include_interaction_callback=include_interaction_callback)): + cls.cancel_interaction(interaction, cancel_reason, finishing_type=finishing_type, **kwargs) + return True + + @classmethod + def cancel_interaction( + cls, + interaction: Interaction, + cancel_reason: str, + finishing_type: FinishingType = FinishingType.USER_CANCEL, + **kwargs + ) -> bool: + """cancel_interaction(\ + interaction,\ + cancel_reason,\ + finishing_type=FinishingType.USER_CANCEL,\ + **kwargs\ + ) + + Cancel an interaction. + + :param interaction: The interaction to cancel. + :type interaction: Interaction + :param cancel_reason: The reason for the cancellation. + :type cancel_reason: str + :param finishing_type: The type of finish to finish the interaction with. Default is FinishingType.USER_CANCEL. + :type finishing_type: FinishingType, optional + :return: True, if the interaction was cancelled successfully. False, if not. + :rtype: bool + """ + if isinstance(interaction, SuperInteraction): + immediate = kwargs.get('immediate', False) + ignore_must_run = kwargs.get('ignore_must_run', False) + carry_cancel_override = kwargs.get('carry_cancel_override', None) + return interaction.cancel( + finishing_type, + cancel_reason, + immediate=immediate, + ignore_must_run=ignore_must_run, + carry_cancel_override=carry_cancel_override + ) + return interaction.cancel(finishing_type, cancel_reason, **kwargs) + + @classmethod + def get_queued_or_running_interactions_gen(cls, sim_info: SimInfo, include_interaction_callback: Callable[[Interaction], bool] = None) -> Iterator[Interaction]: + """get_queued_or_running_interactions_gen(sim_info, include_interaction_callback=None) + + Retrieve all interactions that a Sim has queued or is currently running. + + :param sim_info: An instance of a Sim + :type sim_info: SimInfo + :param include_interaction_callback: If the result of this callback is True, the Interaction will be included in the results. If set to None, all interactions will be included. Default is None. + :type include_interaction_callback: Callable[[Interaction], bool], optional + :return: An iterator of all queued or running Interactions that pass the include callback filter. + :rtype: Iterator[Interaction] + """ + yield from cls.get_queued_interactions_gen(sim_info, include_interaction_callback=include_interaction_callback) + yield from cls.get_running_interactions_gen(sim_info, include_interaction_callback=include_interaction_callback) + + @classmethod + def get_running_interactions_gen(cls, sim_info: SimInfo, include_interaction_callback: Callable[[Interaction], bool] = None) -> Iterator[Interaction]: + """get_running_interactions_gen(sim_info, include_interaction_callback=None) + + Retrieve all interactions that a Sim is currently running. + + :param sim_info: An instance of a Sim + :type sim_info: SimInfo + :param include_interaction_callback: If the result of this callback is True, the Interaction will be included in the results. If set to None, all interactions will be included. Default is None. + :type include_interaction_callback: Callable[[Interaction], bool], optional + :return: An iterator of all running Interactions that pass the include callback filter. + :rtype: Iterator[Interaction] + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return tuple() + if sim.si_state is None: + return tuple() + for interaction in tuple(sim.si_state): + if include_interaction_callback is not None and not include_interaction_callback(interaction): + continue + yield interaction + + @classmethod + def get_queued_interactions_gen(cls, sim_info: SimInfo, include_interaction_callback: Callable[[Interaction], bool] = None) -> Iterator[Interaction]: + """get_queued_interactions_gen(sim_info, include_interaction_callback=None) + + Retrieve all interactions that a Sim currently has queued. + + :param sim_info: An instance of a Sim + :type sim_info: SimInfo + :param include_interaction_callback: If the result of this callback is True, the Interaction will be included in the results. If set to None, All interactions will be included. Default is None. + :type include_interaction_callback: Callable[[Interaction], bool], optional + :return: An iterator of all queued Interactions that pass the include callback filter. + :rtype: Iterator[Interaction] + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return tuple() + if sim.queue is None: + return tuple() + for interaction in tuple(sim.queue): + if include_interaction_callback is not None and not include_interaction_callback(interaction): + continue + yield interaction + + @classmethod + def queue_interaction( + cls, + sim_info: SimInfo, + interaction_id: Union[int, CommonInteractionId], + social_super_interaction_id: Union[int, CommonInteractionId] = None, + target: Any = None, + picked_object: Any = None, + interaction_context: InteractionContext = None, + skip_if_running: bool = False, + **kwargs + ) -> CommonEnqueueResult: + """queue_interaction(\ + sim_info,\ + interaction_id,\ + social_super_interaction_id=None,\ + target=None,\ + picked_object=None,\ + interaction_context=None,\ + skip_if_running=False,\ + **kwargs\ + ) + + Push an Interaction into the queue of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param interaction_id: The decimal identifier of an interaction. + :type interaction_id: Union[int, CommonInteractionId] + :param social_super_interaction_id: The decimal identifier of a social super interaction to queue the interaction under. Default is None + :type social_super_interaction_id: Union[int, CommonInteractionId], optional + :param target: The target of the interaction. Default is None. + :type target: Any, optional + :param interaction_context: The context to queue the interaction with. See also :func:`~create_interaction_context`. Default is None. + :type interaction_context: InteractionContext, optional + :param picked_object: The picked object of the interaction. Default is None. + :type picked_object: Any, optional + :param skip_if_running: If True, the interaction will not be queued, if it is already queued or running. If False, the interaction will be queued, even if it is already queued or running. + :return: The result of pushing the interaction to the queue of a Sim. + :rtype: CommonEnqueueResult + """ + log = cls.get_log() + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + log.format_with_message('No Sim instance for Sim.', sim=sim_info) + return CommonEnqueueResult(CommonTestResult(False, reason=f'No Sim instance for Sim {sim_info}'), CommonExecutionResult.NONE) + if sim.si_state is None: + log.format_with_message('No Super Interaction State available for Sim.', sim=sim_info) + return CommonEnqueueResult(CommonTestResult(False, reason=f'No Super Interaction State available for Sim {sim_info}'), CommonExecutionResult.NONE) + if sim.queue is None: + log.format_with_message('No Queue found for Sim.', sim=sim_info) + return CommonEnqueueResult(CommonTestResult(False, reason=f'No Queue found for Sim {sim_info}'), CommonExecutionResult.NONE) + # noinspection PyPropertyAccess + if sim.posture_state is None: + log.format_with_message('No Posture State found for Sim.', sim=sim_info) + return CommonEnqueueResult(CommonTestResult(False, reason=f'No Posture State found for Sim {sim_info}'), CommonExecutionResult.NONE) + if sim.posture is None: + log.format_with_message('No Posture found for Sim.', sim=sim_info) + return CommonEnqueueResult(CommonTestResult(False, reason=f'No Posture found for Sim {sim_info}'), CommonExecutionResult.NONE) + + interaction_instance = CommonInteractionUtils.load_interaction_by_id(interaction_id) + if interaction_instance is None: + log.format_with_message('No interaction found with id.', id=interaction_id) + return CommonEnqueueResult(CommonTestResult.TRUE, CommonExecutionResult(False, reason=f'No interaction was found with id {interaction_id}.')) + + if skip_if_running and cls.has_interaction_running_or_queued(sim_info, interaction_id): + log.debug('Skipping queue because it is already running.') + return CommonEnqueueResult(CommonTestResult.TRUE, CommonExecutionResult(False, reason=f'Interaction was already running or queued {interaction_id}.')) + + interaction_context = interaction_context or cls.create_interaction_context( + sim_info, + insert_strategy=QueueInsertStrategy.LAST + ) + + if CommonInteractionUtils.is_super_interaction(interaction_instance): + log.debug('Is super.') + return cls.queue_super_interaction( + sim_info, + interaction_id, + target=target, + picked_object=picked_object, + interaction_context=interaction_context, + **kwargs + ) + + if CommonInteractionUtils.is_social_mixer_interaction(interaction_instance): + log.debug('Is social mixer') + return cls.queue_social_mixer_interaction( + sim_info, + interaction_id, + social_super_interaction_id, + target=target, + picked_object=picked_object, + interaction_context=interaction_context, + **kwargs + ) + + log.debug('Is mixer') + return cls.queue_mixer_interaction( + sim_info, + interaction_id, + target=target, + interaction_context=interaction_context + ) + + @classmethod + def queue_super_interaction( + cls, + sim_info: SimInfo, + super_interaction_id: Union[int, CommonInteractionId], + target: Any = None, + picked_object: Any = None, + interaction_context: InteractionContext = None, + **kwargs + ) -> CommonEnqueueResult: + """queue_super_interaction(\ + sim_info,\ + super_interaction_id,\ + target=None,\ + picked_object=None,\ + interaction_context=None,\ + **kwargs\ + ) + + Push a Super Interaction into the queue of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param super_interaction_id: The decimal identifier of a super interaction. + :type super_interaction_id: Union[int, CommonInteractionId] + :param target: The target of the interaction. Default is None. + :type target: Any, optional + :param picked_object: The picked object of the interaction. Default is None. + :type picked_object: Any, optional + :param interaction_context: The context to queue the interaction with. See also :func:`~create_interaction_context`. Default is None. + :type interaction_context: InteractionContext, optional + :return: The result of pushing the interaction to the queue of a Sim. + :rtype: CommonEnqueueResult + """ + log = cls.get_log() + log.format_with_message('Pushing super interaction', sim=sim_info, interaction_id=super_interaction_id, target=target, interaction_context=interaction_context) + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + log.format_with_message('No sim instance for super interaction.', sim=sim_info) + return CommonEnqueueResult(CommonTestResult(False, reason=f'No Sim instance for Sim {sim_info}'), CommonExecutionResult.NONE) + + if target is not None and CommonTypeUtils.is_sim_or_sim_info(target): + target = CommonSimUtils.get_sim_instance(target) + + interaction_context = interaction_context or cls.create_interaction_context(sim_info) + super_interaction_instance = CommonInteractionUtils.load_interaction_by_id(super_interaction_id) + if super_interaction_instance is None: + log.format_with_message('No super interaction instance found for id.', super_interaction_id=super_interaction_id) + return CommonEnqueueResult(CommonTestResult.TRUE, CommonExecutionResult(False, reason=f'No super interaction was found with id {super_interaction_id}.')) + + result = sim.push_super_affordance( + super_interaction_instance, + target, + interaction_context, + picked_object=picked_object or target, + **kwargs + ) + if not result: + log.format_with_message('Failed to push super interaction.', result=result) + return result + + @classmethod + def queue_social_mixer_interaction( + cls, + sim_info: SimInfo, + social_mixer_interaction_id: Union[int, CommonInteractionId], + social_super_interaction_id: Union[int, CommonInteractionId], + target: SimInfo = None, + picked_object: Any = None, + interaction_context: InteractionContext = None, + **kwargs + ) -> CommonEnqueueResult: + """queue_social_mixer_interaction(\ + sim_info,\ + social_mixer_interaction_id,\ + social_super_interaction_id,\ + target=None,\ + picked_object=None,\ + interaction_context=None,\ + **kwargs\ + ) + + Push a Social Mixer Interaction into the queue of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param social_mixer_interaction_id: The decimal identifier of a social mixer interaction. + :type social_mixer_interaction_id: Union[int, CommonInteractionId] + :param social_super_interaction_id: The decimal identifier of a social super interaction to queue the social mixer interaction under. + :type social_super_interaction_id: Union[int, CommonInteractionId] + :param target: The target of the interaction. Default is None. + :type target: Any, optional + :param picked_object: The picked object of the interaction. Default is None. + :type picked_object: Any, optional + :param interaction_context: The context to queue the interaction with. See also :func:`~create_interaction_context`. Default is None. + :type interaction_context: InteractionContext, optional + :return: The result of pushing the interaction to the queue of a Sim. + :rtype: CommonEnqueueResult + """ + log = cls.get_log() + if social_super_interaction_id is not None and social_mixer_interaction_id is None: + log.format_with_message('Interaction was actually a Super interaction!', sim=sim_info, super_interaction_id=social_super_interaction_id) + return cls.queue_super_interaction( + sim_info, + social_super_interaction_id, + target=target, + picked_object=picked_object, + interaction_context=interaction_context, + **kwargs + ) + + social_super_interaction_id: Union[int, CommonInteractionId, None] = social_super_interaction_id + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + log.format_with_message('No sim instance for super interaction.', sim=sim_info) + return CommonEnqueueResult(CommonTestResult(False, reason=f'No Sim instance for Sim {sim_info}'), CommonExecutionResult.NONE) + + social_mixer_affordance_instance = CommonInteractionUtils.load_interaction_by_id(social_mixer_interaction_id) + if social_mixer_affordance_instance is None: + log.format_with_message('No social mixer affordance instance found with id.', interaction_id=social_mixer_interaction_id) + return CommonEnqueueResult(CommonTestResult.TRUE, CommonExecutionResult(False, reason=f'No social mixer interaction was found with id {social_mixer_interaction_id}.')) + + interaction_context = interaction_context or cls.create_interaction_context(sim_info) + # noinspection PyTypeChecker + super_affordance_instance = CommonInteractionUtils.load_interaction_by_id(social_super_interaction_id) + if super_affordance_instance is None: + def _get_existing_social_super_interaction(si_iter) -> Interaction: + for si in si_iter: + if si.super_affordance != super_affordance_instance: + continue + if si.social_group is None: + continue + target_sim = CommonSimUtils.get_sim_instance(target) + if target_sim is not None and target_sim not in si.social_group: + continue + log.format_with_message('Got existing super', existing_super=si.super_interaction) + return si.super_interaction + + log.debug('No super affordance found with id.') + super_interaction = _get_existing_social_super_interaction(sim.si_state) or _get_existing_social_super_interaction(sim.queue) + if super_interaction is None: + si_result = cls.queue_interaction( + sim_info, + social_super_interaction_id, + target=target, + picked_object=picked_object or target, + interaction_context=interaction_context, + **kwargs + ) + if not si_result: + log.format_with_message('Failed to locate existing super interaction.', super_interaction=super_interaction) + return CommonEnqueueResult(CommonTestResult.TRUE, CommonExecutionResult(False, reason='No Existing Super Interaction was found.')) + log.format_with_message('Found si result', si_result=si_result) + super_interaction = si_result.interaction + log.format_with_message('Found si interaction', si_interaction=super_interaction) + else: + log.format_with_message('Located existing super interaction.', existing_super=super_interaction) + + pick = interaction_context.pick if interaction_context.pick is not None else super_interaction.context.pick + log.format_with_message('Found pick', pick=pick) + interaction_context = super_interaction.context.clone_for_continuation( + super_interaction, + insert_strategy=interaction_context.insert_strategy, + source_interaction_id=super_interaction.id, + source_interaction_sim_id=CommonSimUtils.get_sim_id(sim_info), + pick=pick, + picked_object=picked_object, + must_run_next=interaction_context.must_run_next, + **kwargs + ) + else: + super_interaction = None + + aop = AffordanceObjectPair( + social_mixer_affordance_instance, + target, + super_affordance_instance, + super_interaction, + picked_object=picked_object or target, + push_super_on_prepare=True, + **kwargs + ) + result = aop.test_and_execute(interaction_context) + if not result: + log.format_with_message('Failed to queue social mixer interaction', result=result) + return result + + @classmethod + def queue_mixer_interaction( + cls, + sim_info: SimInfo, + mixer_interaction_id: Union[int, CommonInteractionId], + target: Any = None, + interaction_context: InteractionContext = None, + **kwargs + ) -> CommonEnqueueResult: + """queue_mixer_interaction(\ + sim_info,\ + mixer_interaction_id,\ + target=None,\ + interaction_context=None,\ + **kwargs\ + ) + + Push a Mixer Interaction into the Queue of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param mixer_interaction_id: The decimal identifier of a mixer interaction. + :type mixer_interaction_id: Union[int, CommonInteractionId] + :param target: The target of the interaction. Default is None. + :type target: Any, optional + :param interaction_context: The context to queue the interaction with. See also :func:`~create_interaction_context`. Default is None. + :type interaction_context: InteractionContext, optional + :return: The result of pushing the interaction to the queue of a Sim. + :rtype: CommonEnqueueResult + """ + log = cls.get_log() + log.format_with_message( + 'Attempting to queue mixer interaction.', + sim=sim_info, + target=target, + mixer_interaction_id=mixer_interaction_id, + interaction_context=interaction_context + ) + from autonomy.content_sets import get_valid_aops_gen + + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + log.format_with_message('No sim instance for mixer interaction.', sim=sim_info) + return CommonEnqueueResult(CommonTestResult(False, reason=f'No Sim instance for Sim {sim_info}'), CommonExecutionResult.NONE) + if sim.si_state is None: + log.format_with_message('No Super Interaction State available for Sim.', sim=sim_info) + return CommonEnqueueResult(CommonTestResult(False, reason=f'No Super Interaction State available for Sim {sim_info}'), CommonExecutionResult.NONE) + if sim.queue is None: + log.format_with_message('No Queue found for Sim.', sim=sim_info) + return CommonEnqueueResult(CommonTestResult(False, reason=f'No Queue found for Sim {sim_info}'), CommonExecutionResult.NONE) + # noinspection PyPropertyAccess + if sim.posture_state is None: + log.format_with_message('No Posture State found for Sim.', sim=sim_info) + return CommonEnqueueResult(CommonTestResult(False, reason=f'No Posture State found for Sim {sim_info}'), CommonExecutionResult.NONE) + if sim.posture is None: + log.format_with_message('No Posture found for Sim.', sim=sim_info) + return CommonEnqueueResult(CommonTestResult(False, reason=f'No Posture found for Sim {sim_info}'), CommonExecutionResult.NONE) + mixer_interaction_instance = CommonInteractionUtils.load_interaction_by_id(mixer_interaction_id) + if mixer_interaction_instance is None: + log.debug('No mixer interaction instance found.') + return CommonEnqueueResult(CommonTestResult.TRUE, CommonExecutionResult(False, reason=f'No mixer interaction found {mixer_interaction_id}')) + if target is not None and CommonTypeUtils.is_sim_or_sim_info(target): + target = CommonSimUtils.get_sim_instance(target) + source_interaction = sim.posture.source_interaction + if source_interaction is None: + log.debug('Sim did not have a source interaction.') + return CommonEnqueueResult(CommonTestResult.TRUE, CommonExecutionResult(False, reason=f'No source interaction found on Sim {sim_info}')) + + if hasattr(mixer_interaction_instance, 'lock_out_time') and mixer_interaction_instance.lock_out_time: + log.debug('Using Sim specific lock out time.') + sim_specific_lockout = mixer_interaction_instance.lock_out_time.target_based_lock_out + else: + log.debug('Not using Sim specific lock out time.') + sim_specific_lockout = False + + if sim_specific_lockout and sim.is_sub_action_locked_out(mixer_interaction_instance): + log.debug('Sim was locked out of performing the mixer interaction.') + return CommonEnqueueResult(CommonTestResult(False, reason=f'{sim_info} is currently locked out of doing the mixer interaction, they must wait before they can do it again.'), CommonExecutionResult.NONE) + + super_interaction_instance = source_interaction.super_affordance + interaction_context = interaction_context or cls.create_interaction_context(sim_info) + for (aop, test_result) in get_valid_aops_gen( + target, + mixer_interaction_instance, + super_interaction_instance, + source_interaction, + interaction_context, + False, + push_super_on_prepare=False + ): + test_result: CommonTestResult = CommonTestResult.convert_from_vanilla(test_result) + if test_result is None or test_result.result: + log.format_with_message('Failed to queue using affordance.', aop=aop, affordance=aop.affordance) + continue + interaction_constraint = aop.constraint_intersection(sim=sim, posture_state=None) + # noinspection PyPropertyAccess + posture_constraint = sim.posture_state.posture_constraint_strict + constraint_intersection = interaction_constraint.intersect(posture_constraint) + if not constraint_intersection.valid: + log.format_with_message('Constraint interaction was invalid.', constraint_intersection=constraint_intersection) + continue + log.format_with_message('Executing interaction using Aop.', aop=aop, affordance=aop.affordance) + return aop.execute(interaction_context, **kwargs) + + @classmethod + def test_interaction( + cls, + sim_info: SimInfo, + interaction_id: Union[int, CommonInteractionId], + social_super_interaction_id: Union[int, CommonInteractionId] = None, + target: Any = None, + picked_object: Any = None, + interaction_context: InteractionContext = None, + **kwargs + ) -> CommonTestResult: + """test_interaction(\ + sim_info,\ + interaction_id,\ + social_super_interaction_id=None,\ + target=None,\ + picked_object=None,\ + interaction_context,\ + skip_if_running=False,\ + **kwargs\ + ) + + Test to see if an Interaction can be pushed into the queue of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param interaction_id: The decimal identifier of an interaction. + :type interaction_id: Union[int, CommonInteractionId] + :param social_super_interaction_id: The decimal identifier of a social super interaction to queue the interaction under. Default is None + :type social_super_interaction_id: Union[int, CommonInteractionId], optional + :param target: The target of the interaction. Default is None. + :type target: Any, optional + :param picked_object: The picked object of the interaction. Default is None. + :type picked_object: Any, optional + :param interaction_context: The context to queue the interaction with. See also :func:`~create_interaction_context`. Default is None. + :type interaction_context: InteractionContext, optional + :return: The result of testing a push of the interaction to the queue of a Sim. + :rtype: CommonTestResult + """ + log = cls.get_log() + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + log.format_with_message('No Sim instance for Sim.', sim=sim_info) + return CommonTestResult(False, reason=f'No Sim instance for Sim {sim_info}') + if sim.si_state is None: + log.format_with_message('No Super Interaction State available for Sim.', sim=sim_info) + return CommonTestResult(False, reason=f'No Super Interaction State available for Sim {sim_info}') + if sim.queue is None: + log.format_with_message('No Queue found for Sim.', sim=sim_info) + return CommonTestResult(False, reason=f'No Queue found for Sim {sim_info}') + # noinspection PyPropertyAccess + if sim.posture_state is None: + log.format_with_message('No Posture State found for Sim.', sim=sim_info) + return CommonTestResult(False, reason=f'No Posture State found for Sim {sim_info}') + if sim.posture is None: + log.format_with_message('No Posture found for Sim.', sim=sim_info) + return CommonTestResult(False, reason=f'No Posture found for Sim {sim_info}') + + interaction_instance = CommonInteractionUtils.load_interaction_by_id(interaction_id) + if interaction_instance is None: + log.format_with_message('No interaction found with id.', id=interaction_id) + return CommonTestResult(False, reason=f'No mixer interaction found {interaction_id}') + + interaction_context = interaction_context or cls.create_interaction_context( + sim_info, + insert_strategy=QueueInsertStrategy.LAST + ) + + if CommonInteractionUtils.is_super_interaction(interaction_instance): + log.debug('Is super.') + return cls.test_super_interaction( + sim_info, + interaction_id, + target=target, + picked_object=picked_object, + interaction_context=interaction_context, + **kwargs + ) + + if CommonInteractionUtils.is_social_mixer_interaction(interaction_instance): + log.debug('Is social mixer') + return cls.test_social_mixer_interaction( + sim_info, + interaction_id, + social_super_interaction_id, + target=target, + picked_object=picked_object, + interaction_context=interaction_context, + **kwargs + ) + + log.debug('Is mixer') + return cls.test_mixer_interaction( + sim_info, + interaction_id, + target=target, + interaction_context=interaction_context + ) + + @classmethod + def test_super_interaction( + cls, + sim_info: SimInfo, + super_interaction_id: Union[int, CommonInteractionId], + target: Any = None, + picked_object: Any = None, + interaction_context: InteractionContext = None, + **kwargs + ) -> CommonTestResult: + """test_super_interaction(\ + sim_info,\ + super_interaction_id,\ + target=None,\ + picked_object=None,\ + interaction_context=None,\ + **kwargs\ + ) + + Test to see if a Super Interaction can be pushed into the queue of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param super_interaction_id: The decimal identifier of a super interaction. + :type super_interaction_id: Union[int, CommonInteractionId] + :param target: The target of the interaction. Default is None. + :type target: Any, optional + :param picked_object: The picked object of the interaction. Default is None. + :type picked_object: Any, optional + :param interaction_context: The context to queue the interaction with. See also :func:`~create_interaction_context`. Default is None. + :type interaction_context: InteractionContext, optional + :return: The result of testing a push of the interaction to the queue of a Sim. + :rtype: CommonTestResult + """ + log = cls.get_log() + log.format_with_message('Testing super interaction', sim=sim_info, interaction_id=super_interaction_id, target=target, interaction_context=interaction_context) + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + log.debug('No sim instance for super interaction.') + return CommonTestResult(False, reason=f'No Sim instance for Sim {sim_info}') + + super_interaction_instance = CommonInteractionUtils.load_interaction_by_id(super_interaction_id) + if super_interaction_instance is None: + log.format_with_message('No super interaction instance found for id.', super_interaction_id=super_interaction_id) + return CommonTestResult(False, reason=f'No super interaction found {super_interaction_id}') + + if target is not None and CommonTypeUtils.is_sim_or_sim_info(target): + target = CommonSimUtils.get_sim_instance(target) + + interaction_context = interaction_context or cls.create_interaction_context(sim_info) + + return CommonTestResult.convert_from_vanilla(sim.test_super_affordance( + super_interaction_instance, + target, + interaction_context, + picked_object=picked_object or target, + **kwargs + )) + + @classmethod + def test_social_mixer_interaction( + cls, + sim_info: SimInfo, + social_mixer_interaction_id: Union[int, CommonInteractionId], + social_super_interaction_id: Union[int, CommonInteractionId], + target: SimInfo = None, + picked_object: Any = None, + interaction_context: InteractionContext = None, + **kwargs + ) -> CommonTestResult: + """test_social_mixer_interaction(\ + sim_info,\ + social_mixer_interaction_id,\ + social_super_interaction_id,\ + target=None,\ + picked_object=None,\ + interaction_context=None,\ + **kwargs\ + ) + + Test to see if a Social Mixer Interaction can be pushed into the queue of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param social_mixer_interaction_id: The decimal identifier of a social mixer interaction. + :type social_mixer_interaction_id: Union[int, CommonInteractionId] + :param social_super_interaction_id: The decimal identifier of a social super interaction to queue the social mixer interaction under. + :type social_super_interaction_id: Union[int, CommonInteractionId] + :param target: The target of the interaction. Default is None. + :type target: Any, optional + :param picked_object: The picked object of the interaction. Default is None. + :type picked_object: Any, optional + :param interaction_context: The context to queue the interaction with. See also :func:`~create_interaction_context`. Default is None. + :type interaction_context: InteractionContext, optional + :return: The result of testing a push of the interaction to the queue of a Sim. + :rtype: CommonTestResult + """ + log = cls.get_log() + if social_super_interaction_id is not None and social_mixer_interaction_id is None: + log.format_with_message('Interaction was actually a Super interaction!', sim=sim_info, super_interaction_id=social_super_interaction_id) + return cls.queue_super_interaction( + sim_info, + social_super_interaction_id, + target=target, + picked_object=picked_object, + interaction_context=interaction_context, + **kwargs + ) + + social_super_interaction_id: Union[int, CommonInteractionId, None] = social_super_interaction_id + sim = CommonSimUtils.get_sim_instance(sim_info) + social_mixer_affordance_instance = CommonInteractionUtils.load_interaction_by_id(social_mixer_interaction_id) + if social_mixer_affordance_instance is None: + log.debug('No social mixer affordance instance found with id.') + return CommonEnqueueResult(CommonTestResult.TRUE, CommonExecutionResult(False, reason=f'No social mixer interaction found {social_mixer_interaction_id}')) + + interaction_context = interaction_context or cls.create_interaction_context(sim_info) + # noinspection PyTypeChecker + super_affordance_instance = CommonInteractionUtils.load_interaction_by_id(social_super_interaction_id) + if super_affordance_instance is None: + def _get_existing_social_super_interaction(si_iter) -> Interaction: + for si in si_iter: + if si.super_affordance != super_affordance_instance: + continue + if si.social_group is None: + continue + target_sim = CommonSimUtils.get_sim_instance(target) + if target_sim is not None and target_sim not in si.social_group: + continue + log.format_with_message('Got existing super', existing_super=si.super_interaction) + return si.super_interaction + + log.debug('No super affordance found with id.') + super_interaction = _get_existing_social_super_interaction(sim.si_state) or _get_existing_social_super_interaction(sim.queue) + if super_interaction is None: + si_result = cls.queue_interaction( + sim_info, + social_super_interaction_id, + target=target, + picked_object=picked_object or target, + interaction_context=interaction_context, + **kwargs + ) + if not si_result: + log.format_with_message('Failed to locate existing super interaction.', super_interaction=super_interaction) + return CommonEnqueueResult(CommonTestResult.TRUE, CommonExecutionResult(False, reason='No Existing Super Interaction was found.')) + log.format_with_message('Found si result', si_result=si_result) + super_interaction = si_result.interaction + log.format_with_message('Found si interaction', si_interaction=super_interaction) + else: + log.format_with_message('Located existing super interaction.', existing_super=super_interaction) + + pick = interaction_context.pick if interaction_context.pick is not None else super_interaction.context.pick + log.format_with_message('Found pick', pick=pick) + interaction_context = super_interaction.context.clone_for_continuation( + super_interaction, + insert_strategy=interaction_context.insert_strategy, + source_interaction_id=super_interaction.id, + source_interaction_sim_id=CommonSimUtils.get_sim_id(sim_info), + pick=pick, + picked_object=picked_object, + must_run_next=interaction_context.must_run_next, + **kwargs + ) + else: + super_interaction = None + + aop = AffordanceObjectPair( + social_mixer_affordance_instance, + target, + super_affordance_instance, + super_interaction, + picked_object=picked_object or target, + push_super_on_prepare=True, + **kwargs + ) + return CommonTestResult.convert_from_vanilla(aop.test(interaction_context)) + + @classmethod + def test_mixer_interaction( + cls, + sim_info: SimInfo, + mixer_interaction_id: Union[int, CommonInteractionId], + target: Any = None, + interaction_context: InteractionContext = None, + **kwargs + ) -> CommonTestResult: + """test_mixer_interaction(\ + sim_info,\ + mixer_interaction_id,\ + target=None,\ + interaction_context=None,\ + **kwargs\ + ) + + Test to see if a Mixer Interaction can be pushed into the Queue of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param mixer_interaction_id: The decimal identifier of a mixer interaction. + :type mixer_interaction_id: Union[int, CommonInteractionId] + :param target: The target of the interaction. Default is None. + :type target: Any, optional + :param interaction_context: The context to queue the interaction with. See also :func:`~create_interaction_context`. Default is None. + :type interaction_context: InteractionContext, optional + :return: The result of testing a push of the interaction to the queue of a Sim. + :rtype: CommonTestResult + """ + log = cls.get_log() + log.format_with_message( + 'Attempting to test mixer interaction.', + sim=sim_info, + target=target, + mixer_interaction_id=mixer_interaction_id, + interaction_context=interaction_context + ) + from autonomy.content_sets import get_valid_aops_gen + + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + log.format_with_message('No Sim instance for Sim.', sim=sim_info) + return CommonTestResult(False, reason=f'No Sim instance for Sim {sim_info}') + if sim.posture is None: + log.format_with_message('No Posture found for Sim.', sim=sim_info) + return CommonTestResult(False, reason=f'No Posture found for Sim {sim_info}') + + if target is not None and CommonTypeUtils.is_sim_or_sim_info(target): + target = CommonSimUtils.get_sim_instance(target) + mixer_interaction_instance = CommonInteractionUtils.load_interaction_by_id(mixer_interaction_id) + if mixer_interaction_instance is None: + log.format_with_message('No mixer interaction instance found.', mixer_interaction_id=mixer_interaction_id) + return CommonTestResult(False, reason=f'No mixer interaction found {mixer_interaction_id}') + source_interaction = sim.posture.source_interaction + if source_interaction is None: + log.debug('Sim did not have a source interaction.') + return CommonTestResult(False, reason=f'No source interaction found on Sim {sim_info}') + if hasattr(mixer_interaction_instance, 'lock_out_time') and mixer_interaction_instance.lock_out_time: + log.debug('Using Sim specific lock out time.') + sim_specific_lockout = mixer_interaction_instance.lock_out_time.target_based_lock_out + else: + log.debug('Not using Sim specific lock out time.') + sim_specific_lockout = False + + if sim_specific_lockout and sim.is_sub_action_locked_out(mixer_interaction_instance): + log.debug('Sim was locked out of performing the mixer interaction.') + return CommonTestResult(False, reason=f'{sim_info} is currently locked out of doing the mixer interaction, they must wait before they can do it again.') + + super_interaction_instance = source_interaction.super_affordance + interaction_context = interaction_context or cls.create_interaction_context(sim_info) + for (aop, test_result) in get_valid_aops_gen( + target, + mixer_interaction_instance, + super_interaction_instance, + source_interaction, + interaction_context, + False, + push_super_on_prepare=False + ): + test_result = CommonTestResult.convert_from_vanilla(test_result) + if test_result is None or test_result.result: + log.format_with_message('Failed to queue using affordance.', aop=aop, affordance=aop.affordance) + continue + interaction_constraint = aop.constraint_intersection(sim=sim, posture_state=None) + # noinspection PyPropertyAccess + posture_constraint = sim.posture_state.posture_constraint_strict + constraint_intersection = interaction_constraint.intersect(posture_constraint) + if not constraint_intersection.valid: + log.format_with_message('Constraint interaction was invalid.', constraint_intersection=constraint_intersection) + continue + log.format_with_message('Executing interaction using Aop.', aop=aop, affordance=aop.affordance) + return aop.test(interaction_context, **kwargs) + + @classmethod + def create_interaction_context( + cls, + sim_info: SimInfo, + interaction_source: InteractionSource = InteractionContext.SOURCE_SCRIPT_WITH_USER_INTENT, + priority: Priority = Priority.High, + run_priority: Union[Priority, None] = Priority.High, + insert_strategy: QueueInsertStrategy = QueueInsertStrategy.NEXT, + must_run_next: bool = False, + **kwargs + ) -> Union[InteractionContext, None]: + """create_interaction_context(\ + sim_info,\ + interaction_source=InteractionContext.SOURCE_SCRIPT_WITH_USER_INTENT,\ + priority=Priority.High,\ + run_priority=Priority.High,\ + insert_strategy=QueueInsertStrategy.NEXT,\ + must_run_next=False,\ + **kwargs\ + ) + + Create an InteractionContext. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param interaction_source: The source of the interaction. Default is InteractionContext.SOURCE_SCRIPT_WITH_USER_INTENT. + :type interaction_source: InteractionSource, optional + :param priority: The priority of the interaction. Default is Priority.High. + :type priority: Priority, optional + :param run_priority: The priority of running the interaction. Default is Priority.High. + :type run_priority: Union[Priority, None], optional + :param insert_strategy: The insert strategy for the interaction. Default is QueueInsertStrategy.NEXT. + :type insert_strategy: QueueInsertStrategy, optional + :param must_run_next: If True, the interaction will run next. Default is False. + :type must_run_next: bool, optional + :return: An interaction context for use with interactions or None if a problem occurs. + :rtype: Union[InteractionContext, None] + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return None + return InteractionContext( + sim, + interaction_source, + priority, + run_priority=run_priority, + insert_strategy=insert_strategy, + must_run_next=must_run_next, + **kwargs + ) + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_testing.print_running_interactions', + 'Print a list of all interactions a Sim is running.', + command_arguments=( + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance Id or name of the Sim to check.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib_testing.printrunninginteractions', + ) +) +def _common_show_running_interactions(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): + if sim_info is None: + return + log = CommonSimInteractionUtils.get_log() + try: + log.enable() + output(f'Attempting to print all running and queued interactions of Sim {sim_info}') + from sims4communitylib.utils.resources.common_interaction_utils import CommonInteractionUtils + running_interaction_strings: List[str] = list() + for interaction in CommonSimInteractionUtils.get_running_interactions_gen(sim_info): + interaction_name = CommonInteractionUtils.get_interaction_short_name(interaction) or interaction.__class__.__name__ + interaction_id = CommonInteractionUtils.get_interaction_id(interaction) + running_interaction_strings.append(f'{interaction_name} ({interaction_id})') + + running_interaction_strings = sorted(running_interaction_strings, key=lambda x: x) + running_interaction_names = ', '.join(running_interaction_strings) + + queued_interaction_strings: List[str] = list() + for interaction in CommonSimInteractionUtils.get_queued_interactions_gen(sim_info): + interaction_name = CommonInteractionUtils.get_interaction_short_name(interaction) or interaction.__class__.__name__ + interaction_id = CommonInteractionUtils.get_interaction_id(interaction) + queued_interaction_strings.append(f'{interaction_name} ({interaction_id})') + + queued_interaction_strings = sorted(queued_interaction_strings, key=lambda x: x) + queued_interaction_names = ', '.join(queued_interaction_strings) + text = '' + text += f'Running Interactions:\n{running_interaction_names}\n\n' + text += f'Queued Interactions:\n{queued_interaction_names}\n\n' + sim_id = CommonSimUtils.get_sim_id(sim_info) + log.debug(f'{sim_info} Interactions ({sim_id})') + log.debug(text) + CommonBasicNotification( + CommonLocalizationUtils.create_localized_string(f'{sim_info} Interactions ({sim_id})'), + CommonLocalizationUtils.create_localized_string(text) + ).show( + icon=IconInfoData(obj_instance=CommonSimUtils.get_sim_instance(sim_info)) + ) + finally: + log.disable() diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_inventory_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_inventory_utils.py new file mode 100644 index 0000000..980e5a6 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_inventory_utils.py @@ -0,0 +1,396 @@ +""" +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 +""" +from typing import Callable, Iterator, Union, Tuple +from interactions.base.create_object_interaction import ObjectDefinition +from objects.components.sim_inventory_component import SimInventoryComponent +from objects.game_object import GameObject +from sims.sim_info import SimInfo +from sims4communitylib.classes.math.common_location import CommonLocation +from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from sims4communitylib.enums.types.component_types import CommonComponentType +from sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + CommonConsoleCommandArgument +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.common_component_utils import CommonComponentUtils +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from sims4communitylib.utils.objects.common_object_spawn_utils import CommonObjectSpawnUtils +from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + + +class CommonSimInventoryUtils(_HasS4CLClassLog): + """ Utilities for manipulating the inventory of Sims. """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 's4cl_sim_inventory_utils' + + @classmethod + def has_inventory(cls, sim_info: SimInfo) -> bool: + """has_inventory(sim_info) + + Determine if a Sim has an inventory. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: True, if the Sim has an inventory. False, if not. + :rtype: bool + """ + return cls.get_inventory(sim_info) is not None + + @classmethod + def get_inventory(cls, sim_info: SimInfo) -> Union[SimInventoryComponent, None]: + """get_inventory(sim_info) + + Retrieve the inventory of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The inventory component of the Sim or None if not found. + :rtype: Union[SimInventoryComponent, None] + """ + return cls._get_inventory(sim_info) + + @classmethod + def get_objects_in_inventory_by_definition_ids_gen(cls, sim_info: SimInfo, object_definition_ids: Tuple[int], include_object_callback: Callable[[GameObject], bool] = None) -> Iterator[GameObject]: + """get_objects_in_inventory_by_definition_id_gen(sim_info, object_definition_ids, include_object_callback=None) + + Retrieve all Objects in the inventory of a Sim that match the definition ids. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param object_definition_ids: The Definition IDs of the objects to locate. + :type object_definition_ids: Tuple[int] + :param include_object_callback: If the result of this callback is True, the object will be included in the results. If set to None, All objects in the inventory will be included. + :type include_object_callback: Callable[[int], bool], optional + :return: An iterator containing the decimal identifiers for the objects in the inventory of a Sim. + :rtype: Iterator[GameObject] + """ + log = cls.get_log() + log.format_with_message('Getting objects in inventory', sim=sim_info, object_definition_ids=object_definition_ids) + for game_object in cls.get_all_objects_in_inventory_gen(sim_info, include_object_callback=include_object_callback): + definition_id = CommonObjectUtils.get_object_definition_id(game_object) + log.format_with_message('Got definition id.', definition_id=definition_id, game_object=game_object) + if definition_id in object_definition_ids: + log.format_with_message('Definition found in objects.', definition_id=definition_id) + yield game_object + else: + log.format_with_message('Definition not found.', definition_id=definition_id) + + @classmethod + def get_objects_in_inventory_by_definition_id_gen(cls, sim_info: SimInfo, object_definition_id: int, include_object_callback: Callable[[GameObject], bool] = None) -> Iterator[GameObject]: + """get_objects_in_inventory_by_definition_id_gen(sim_info, object_definition_id, include_object_callback=None) + + Retrieve all Objects in the inventory of a Sim that match the definition id. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param object_definition_id: The Definition ID of the objects to locate. + :type object_definition_id: int + :param include_object_callback: If the result of this callback is True, the object will be included in the results. If set to None, All objects in the inventory will be included. + :type include_object_callback: Callable[[int], bool], optional + :return: An iterator containing the decimal identifiers for the objects in the inventory of a Sim. + :rtype: Iterator[GameObject] + """ + yield from cls.get_objects_in_inventory_by_definition_ids_gen(sim_info, (object_definition_id,), include_object_callback=include_object_callback) + + @classmethod + def get_all_objects_in_inventory_gen(cls, sim_info: SimInfo, include_object_callback: Callable[[GameObject], bool] = None) -> Iterator[GameObject]: + """get_all_objects_in_inventory_gen(sim_info, include_object_callback=None) + + Retrieve all Objects in the inventory of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param include_object_callback: If the result of this callback is True, the object will be included in the results. If set to None, All objects in the inventory will be included. + :type include_object_callback: Callable[[int], bool], optional + :return: An iterator containing the decimal identifiers for the objects in the inventory of a Sim. + :rtype: Iterator[GameObject] + """ + inventory_component: SimInventoryComponent = cls.get_inventory(sim_info) + if inventory_component is None: + return tuple() + if include_object_callback is None: + for inventory_object in inventory_component: + yield inventory_object + else: + for inventory_object in inventory_component: + if include_object_callback(inventory_object): + yield inventory_object + + @classmethod + def add_to_inventory(cls, sim_info: SimInfo, object_definition_id: int, count: int = 1, on_added: Callable[[GameObject], None] = CommonFunctionUtils.noop) -> CommonExecutionResult: + """add_to_inventory(sim_info, object_definition_id, count=1, on_added=CommonFunctionUtils.noop) + + Add a number of Newly Created Objects to the Inventory of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param object_definition_id: The decimal identifier of an Object. + :type object_definition_id: int + :param count: The number of the specified Object to add. Default is 1. + :type count: int, optional + :param on_added: A callback invoked when the object is added to the inventory. + :type on_added: Callable[[GameObject], None] + :return: True, if the count of the specified Object were added successfully. False, it not. + :rtype: CommonExecutionResult + """ + if not CommonSimInventoryUtils.has_inventory(sim_info): + return CommonExecutionResult(False, reason=f'{sim_info} has no inventory.') + + def _post_create(_game_object: GameObject) -> bool: + move_result = CommonSimInventoryUtils.move_object_to_inventory(sim_info, _game_object) + on_added(_game_object) + return move_result + + success = CommonExecutionResult.TRUE + count = int(count) + for _ in range(count): + game_object = CommonObjectSpawnUtils.spawn_object_on_lot(object_definition_id, CommonLocation.empty(), post_object_spawned_callback=_post_create) + if game_object is None: + success = CommonExecutionResult(False, reason=f'Failed to create object {object_definition_id}') + return success + + @classmethod + def remove_from_inventory(cls, sim_info: SimInfo, object_id: int, count: int = 1) -> bool: + """remove_from_inventory(sim_info, object_id, count=1) + + Remove a number of Objects from the inventory of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param object_id: The decimal identifier of an Object. + :type object_id: int + :param count: The amount of the Object to remove. Default is 1. + :type count: int, optional + :return: True, if the count of the specified Object were removed successfully. False, if not. + """ + inventory_component: SimInventoryComponent = cls.get_inventory(sim_info) + if inventory_component is None: + return False + return inventory_component.try_remove_object_by_id(object_id, count=count) + + @classmethod + def remove_from_inventory_by_definition(cls, sim_info: SimInfo, object_definition: ObjectDefinition, count: int = 1) -> bool: + """remove_from_inventory(sim_info, object_id, count=1) + + Remove a number of Objects from the inventory of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param object_definition: The definition of an Object. + :type object_definition: ObjectDefinition + :param count: The amount of the Object to remove. Default is 1. + :type count: int, optional + :return: True, if the count of the specified Object were removed successfully. False, if not. + """ + def _include_object_callback(_game_object: GameObject) -> bool: + return _game_object.definition == object_definition + + inventory_objects = CommonSimInventoryUtils.get_all_objects_in_inventory_gen(sim_info, include_object_callback=_include_object_callback) + for inventory_object in inventory_objects: + object_id = CommonObjectUtils.get_object_id(inventory_object) + if CommonSimInventoryUtils.remove_from_inventory(sim_info, object_id, count=count): + return True + return False + + @classmethod + def move_object_to_inventory(cls, sim_info: SimInfo, game_object: GameObject) -> bool: + """move_object_to_inventory(sim_info, game_object) + + Move an Object to the inventory of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param game_object: An instance of an Object. + :type game_object: GameObject + :return: True, if the object was successfully moved to the inventory of the specified Sim. False, if not. + :rtype: bool + """ + inventory_component: SimInventoryComponent = cls.get_inventory(sim_info) + if inventory_component is None: + return False + from sims4communitylib.utils.objects.common_object_ownership_utils import CommonObjectOwnershipUtils + CommonObjectOwnershipUtils.set_owning_sim(game_object, sim_info) + return inventory_component.player_try_add_object(game_object) + + @classmethod + def move_objects_to_inventory(cls, sim_info: SimInfo, game_objects: Tuple[GameObject]) -> bool: + """move_objects_to_inventory(sim_info, game_objects) + + Move Objects to the inventory of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param game_objects: A collection of Object instances. + :type game_objects: GameObject + :return: True, if all objects were successfully moved to the inventory of the specified Sim. False, if not. + :rtype: bool + """ + if not game_objects: + return False + successfully_moved_all = True + for game_object in game_objects: + if not CommonSimInventoryUtils.move_object_to_inventory(sim_info, game_object): + successfully_moved_all = False + return successfully_moved_all + + @classmethod + def get_count_of_object_in_inventory(cls, sim_info: SimInfo, object_id: int) -> int: + """get_count_of_object_in_inventory(sim_info, object_id) + + Count the number of an Object in the inventory of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param object_id: The decimal identifier of an object. + :type object_id: int + :return: The number of the specified Object in the inventory of the specified Sim. + :type: int + """ + inventory_component: SimInventoryComponent = cls.get_inventory(sim_info) + if inventory_component is None: + return 0 + object_definition = CommonObjectUtils.get_object_definition(object_id) + return inventory_component.get_count(object_definition) + + @classmethod + def make_inventory_visible(cls, sim_info: SimInfo) -> bool: + """make_inventory_visible(sim_info) + + Change the flags of the inventory of a Sim so that it becomes visible to the player. + + .. note:: A Sim needs to be Instances in order to have an inventory to make visible. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: True, if the inventory of the specified Sim was made visible. False, if not. + :rtype: bool + """ + if sim_info is None: + return False + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return False + inventory_component: SimInventoryComponent = cls.get_inventory(sim_info) + if inventory_component is None: + return False + if inventory_component.visible_storage is None: + return False + inventory_component.visible_storage.allow_ui = True + inventory_component.publish_inventory_items() + sim.ui_manager.refresh_ui_data() + return True + + @classmethod + def make_inventory_hidden(cls, sim_info: SimInfo) -> bool: + """make_inventory_hidden(sim_info) + + Change the flags of the inventory of a Sim so that it becomes hidden to the player. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: True, if the inventory of the specified Sim was made hidden. False, if not. + :rtype: bool + """ + if sim_info is None: + return False + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return True + inventory_component: SimInventoryComponent = cls.get_inventory(sim_info) + if inventory_component is None: + return True + if inventory_component.visible_storage is None: + return True + inventory_component.visible_storage.allow_ui = False + inventory_component.publish_inventory_items() + sim.ui_manager.refresh_ui_data() + return True + + @classmethod + def open_inventory(cls, sim_info: SimInfo) -> None: + """open_inventory(sim_info) + + Open the inventory of a Sim. + + :param sim_info: The Sim to open the inventory of. + :type sim_info: SimInfo + """ + if sim_info is None: + return + inventory_component: SimInventoryComponent = cls.get_inventory(sim_info) + if inventory_component is None: + return + if not CommonSimInventoryUtils.make_inventory_visible(sim_info): + return + inventory_component.open_ui_panel() + + @classmethod + def set_ownership_of_all_items_in_sim_inventory_to_sim(cls, sim_info_a: SimInfo, sim_info_b: SimInfo) -> bool: + """set_ownership_of_all_items_in_sim_inventory_to_sim(sim_info_a, sim_info_b) + + Change the ownership status of all items in the inventory of Sim A to be owned by the household of Sim B + + :param sim_info_a: The objects in the inventory of this Sim will become owned by the household of Sim B + :type sim_info_a: SimInfo + :param sim_info_b: The household of this Sim will be the new owner for all items in the inventory of Sim A. + :type sim_info_b: SimInfo + :return: True, if ownership was transferred successfully. False, if not. + :rtype: bool + """ + if sim_info_a is None or sim_info_b is None: + return False + if not CommonSimInventoryUtils.make_inventory_visible(sim_info_a): + return False + inventory_component: SimInventoryComponent = cls.get_inventory(sim_info_a) + if inventory_component is None: + return False + from sims4communitylib.utils.objects.common_object_ownership_utils import CommonObjectOwnershipUtils + for inventory_object in inventory_component: + inventory_object: GameObject = inventory_object + CommonObjectOwnershipUtils.set_owning_sim(inventory_object, sim_info_b) + return True + + @classmethod + def _get_inventory(cls, sim_info: SimInfo) -> Union[SimInventoryComponent, None]: + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return None + return CommonComponentUtils.get_component(sim, CommonComponentType.INVENTORY) + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.add_object_to_inventory', + 'Add an Object to the inventory of a Sim.', + command_arguments=( + CommonConsoleCommandArgument('object_definition_id', 'Decimal Identifier', 'The decimal identifier of the Object Definition for the object to add.'), + CommonConsoleCommandArgument('count', 'Positive Number', 'The number of objects to add.', is_optional=True, default_value=1), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to add the object to.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.addtosim', + ) +) +def _s4clib_testing_add_object_to_inventory(output: CommonConsoleCommandOutput, object_definition_id: int, count: int = 1, sim_info: SimInfo = None): + if object_definition_id < 0: + output('ERROR: Object Definition Id must be a positive number.') + return + if count <= 0: + output('ERROR: count must be greater than zero.') + return + output(f'Attempting to add object with definition id \'{object_definition_id}\' to the inventory of Sim {sim_info}.') + if CommonSimInventoryUtils.add_to_inventory(sim_info, object_definition_id, count): + output(f'SUCCESS: Successfully added object with definition id {object_definition_id} to Sim {sim_info}') + else: + output(f'FAILED: Failed to add object with definition id {object_definition_id} to Sim {sim_info}') + output('Done adding object to the inventory of the Sim.') diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_location_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_location_utils.py new file mode 100644 index 0000000..044396d --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_location_utils.py @@ -0,0 +1,770 @@ +""" +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 +""" +import os + +from typing import Union + +from objects.script_object import ScriptObject +from sims4communitylib.classes.math.common_location import CommonLocation +from sims4communitylib.classes.math.common_quaternion import CommonQuaternion +from sims4communitylib.classes.math.common_routing_location import CommonRoutingLocation +from sims4communitylib.classes.math.common_surface_identifier import CommonSurfaceIdentifier +from sims4communitylib.classes.math.common_transform import CommonTransform +from sims4communitylib.classes.math.common_vector3 import CommonVector3 +from sims4communitylib.classes.testing.common_enqueue_result import CommonEnqueueResult +from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + CommonConsoleCommandArgument +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.location.common_location_utils import CommonLocationUtils +from sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils +from sims4communitylib.utils.sims.common_sim_interaction_utils import CommonSimInteractionUtils +from sims4communitylib.utils.sims.common_sim_type_utils import CommonSimTypeUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + + +ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' + +if ON_RTD: + # noinspection PyMissingOrEmptyDocstring + class AutonomyComponent: + pass + + # noinspection PyMissingOrEmptyDocstring + class TestResult: + pass + + # noinspection PyMissingOrEmptyDocstring + class RoutingContext: + pass + + # noinspection PyMissingOrEmptyDocstring + class PickType: + pass + + # noinspection PyMissingOrEmptyDocstring + class FGLSearchFlagsDefault: + pass + + # noinspection PyMissingOrEmptyDocstring + class FGLSearchFlag: + STAY_IN_CURRENT_BLOCK = 0 + + # noinspection PyMissingOrEmptyDocstring + class Lot: + pass + + # noinspection PyMissingOrEmptyDocstring + class SimInfo: + pass + +if not ON_RTD: + from autonomy.autonomy_component import AutonomyComponent + import routing + from routing import RoutingContext + import objects.terrain + from server.pick_info import PickType + from placement import FGLSearchFlagsDefault, FGLSearchFlag + from world.lot import Lot + from sims.sim_info import SimInfo + + +class CommonSimLocationUtils: + """Utilities for manipulating the locations of Sims. + + """ + @staticmethod + def get_position(sim_info: SimInfo) -> Union[CommonVector3, None]: + """get_position(sim_info) + + Retrieve the current position of a Sim. + + :param sim_info: The Sim to get the position of. + :type sim_info: SimInfo + :return: The current position of the Sim or None if the Sim does not have a position. + :rtype: Union[CommonVector3, None] + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return None + # noinspection PyBroadException + try: + return CommonVector3.from_vector3(sim.position) + except: + return None + + @staticmethod + def set_location(sim_info: SimInfo, location: CommonLocation) -> bool: + """set_location(sim_info, location) + + Set the location of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param location: The location to put the Sim. + :type location: CommonLocation + :return: True, if the location of the Sim is successfully set. False, if not. + :rtype: bool + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None or location is None: + return False + # noinspection PyBroadException + try: + sim.location = location + except: + return False + return True + + @staticmethod + def get_location(sim_info: SimInfo) -> Union[CommonLocation, None]: + """get_location(sim_info) + + Retrieve the current location of a Sim. + + :param sim_info: The Sim to get the location of. + :type sim_info: SimInfo + :return: The current location of the Sim or None if the Sim does not have a location. + :rtype: Union[CommonLocation, None] + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return None + # noinspection PyBroadException + try: + return CommonLocation.from_location(sim.location) + except: + return None + + @staticmethod + def get_routing_location(sim_info: SimInfo) -> Union[CommonRoutingLocation, None]: + """get_routing_location(sim_info) + + Retrieve a routing location for the current location of a Sim. + + :param sim_info: The Sim to get the location of. + :type sim_info: SimInfo + :return: The routing location for the current location of the Sim or None if the Sim does not have a location. + :rtype: Union[CommonRoutingLocation, None] + """ + sim_location = CommonSimLocationUtils.get_location(sim_info) + if sim_location is None: + return None + return CommonRoutingLocation(sim_location.transform.translation, orientation=sim_location.transform.orientation, routing_surface=sim_location.routing_surface) + + @staticmethod + def get_orientation(sim_info: SimInfo) -> CommonQuaternion: + """get_orientation(sim_info) + + Retrieve the orientation of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The orientation of the Sim. + :rtype: CommonQuaternion + """ + if sim_info is None: + return CommonQuaternion.empty() + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return CommonQuaternion.empty() + return CommonQuaternion.from_quaternion(sim.orientation) + + @staticmethod + def get_orientation_degrees(sim_info: SimInfo) -> float: + """get_orientation_degrees(sim_info) + + Retrieve the orientation of a Sim represented in degrees. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The orientation of the Sim represented in degrees. + :rtype: float + """ + return CommonQuaternion.to_degrees(CommonSimLocationUtils.get_orientation(sim_info)) + + @staticmethod + def get_routing_surface(sim_info: SimInfo) -> Union[CommonSurfaceIdentifier, None]: + """get_routing_surface(sim_info) + + Retrieve the Routing Surface Identifier of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The Routing Surface Identifier of the specified Sim or None if a problem occurs. + :rtype: Union[CommonSurfaceIdentifier, None] + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return None + + return CommonSurfaceIdentifier.from_surface_identifier(sim.routing_surface) + + @staticmethod + def get_surface_level(sim_info: SimInfo) -> int: + """get_surface_level(sim_info) + + Retrieve the Surface Level of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The Surface Level of the specified Sim or 0 if a problem occurs. + :rtype: int + """ + routing_surface = CommonSimLocationUtils.get_routing_surface(sim_info) + if routing_surface is None: + return 0 + return routing_surface.secondary_id + + @staticmethod + def get_forward_vector(sim_info: SimInfo) -> CommonVector3: + """get_forward_vector(sim_info) + + Retrieve the forward vector of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The forward vector of the Sim. + :rtype: CommonVector3 + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return CommonVector3.empty() + return CommonVector3.from_vector3(sim.forward) + + @staticmethod + def get_routing_context(sim_info: SimInfo) -> Union[RoutingContext, None]: + """get_routing_context(sim_info) + + Retrieve the routing context of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The routing context of the specified Sim or None if an error occurs. + :rtype: Union[RoutingContext, None] + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return None + return sim.routing_context + + @staticmethod + def can_swim_at_location(sim_info: SimInfo, location: CommonLocation) -> bool: + """can_swim_at_location(sim_info, location) + + Determine if a Sim can swim at the specified location. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :param location: The Location to check. + :type location: CommonLocation + :return: True, if the Sim can swim at the specified location. False, if not. + :rtype: bool + """ + if location is None: + return False + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return False + return sim.should_be_swimming_at_position(location.transform.translation, location.routing_surface.secondary_id) + + @staticmethod + def can_swim_at_current_location(sim_info: SimInfo) -> bool: + """can_swim_at_current_location(sim_info) + + Determine if a Sim can swim at their current location. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim can swim at their current location. False, if not. + :rtype: bool + """ + location = CommonSimLocationUtils.get_location(sim_info) + return CommonSimLocationUtils.can_swim_at_location(sim_info, location) + + @staticmethod + def can_route_to_location(sim_info: SimInfo, location: CommonLocation) -> bool: + """can_route_to_location(sim_info, location) + + Determine if a Sim can route to a Location. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param location: The location to route to. + :type location: CommonLocation + :return: True, if the Sim can route to the specified Location. False, if not. + :rtype: bool + """ + sim_routing_location = CommonSimLocationUtils.get_routing_location(sim_info) + if sim_routing_location is None: + return False + sim_routing_context = CommonSimLocationUtils.get_routing_context(sim_info) + if sim_routing_context is None: + return False + return routing.test_connectivity_pt_pt(sim_routing_location, CommonRoutingLocation.from_location(location), sim_routing_context) + + @staticmethod + def can_route_to_position(sim_info: SimInfo, position: CommonVector3, routing_surface: CommonSurfaceIdentifier, orientation: CommonQuaternion = CommonQuaternion.empty()) -> bool: + """can_route_to_position(sim_info, position, routing_surface) + + Determine if a Sim can route to a Location. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param position: The position to route to. + :type position: CommonVector3 + :param routing_surface: The routing surface of the target. + :type routing_surface: CommonSurfaceIdentifier + :param orientation: The orientation of the position. Default is CommonQuaternion.empty(). + :type orientation: CommonQuaternion, optional + :return: True, if the Sim can route to the specified Position. False, if not. + :rtype: bool + """ + location = CommonLocation( + CommonTransform( + position, + orientation or CommonQuaternion.empty() + ), + routing_surface + ) + return CommonSimLocationUtils.can_route_to_location(sim_info, location) + + @staticmethod + def can_route_to_object(sim_info: SimInfo, script_object: ScriptObject) -> bool: + """can_route_to_object(sim_info, game_object) + + Determine if a Sim can route to an Object. + + .. note:: This function will account for locked doors as well. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param script_object: The Object to check. + :type script_object: ScriptObject + :return: True, if the Sim can route to the Object. False, if not. + :rtype: bool + """ + if sim_info is None or script_object is None: + return False + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return False + if sim.posture is None: + return False + return script_object.is_connected(sim) + + # noinspection PyUnusedLocal + @staticmethod + def can_route_to_sim(sim_info_a: SimInfo, sim_info_b: SimInfo) -> bool: + """can_route_to_sim(sim_info, game_object) + + Determine if Sim A can route to Sim B. + + :param sim_info_a: The Sim that would be routing to Sim B. + :type sim_info_a: SimInfo + :param sim_info_b: The Sim that Sim A would be routing to. + :type sim_info_b: SimInfo + :return: True, if Sim A can route to Sim B. False, if not. + :rtype: bool + """ + if sim_info_a is None or sim_info_b is None: + return False + sim_b = CommonSimUtils.get_sim_instance(sim_info_b) + if sim_b is None: + return False + return CommonSimLocationUtils.can_route_to_object(sim_info_a, sim_b) + + @staticmethod + def is_within_range_of_position(sim_info: SimInfo, position: CommonVector3, distance_in_squares: float) -> bool: + """is_within_range_of_position(sim_info, position, distance_in_squares) + + Determine if a Sim is within a certain distance of a Position. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :param position: A position. + :type position: CommonVector3 + :param distance_in_squares: A unit measured in squares. 1 square is the size of 1 square in the Build/Buy mode visual grid. For comparison, a dining chair would be 1 square by 1 square. 0.5 would be half a square, or half a dining chair. + :type distance_in_squares: float + :return: True, if the distance between the Sim and the Position is less than or equal to the specified distance in squares. False, if not. + :return: bool + """ + sim_position = CommonSimLocationUtils.get_position(sim_info) + if sim_position is None: + return False + return CommonLocationUtils.is_position_within_range_of_position(sim_position, position, distance_in_squares) + + @staticmethod + def is_within_range_of_location(sim_info: SimInfo, location: CommonLocation, distance_in_squares: float) -> bool: + """is_within_range_of_location(sim_info, location, distance_in_squares) + + Determine if a Sim is within a certain distance of a Location. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :param location: A location. + :type location: CommonLocation + :param distance_in_squares: A unit measured in squares. 1 square is the size of 1 square in the Build/Buy mode visual grid. For comparison, a dining chair would be 1 square by 1 square. 0.5 would be half a square, or half a dining chair. + :type distance_in_squares: float + :return: True, if the distance between the Sim and the Location is less than or equal to the specified distance in squares. False, if not. + :return: bool + """ + sim_location = CommonSimLocationUtils.get_location(sim_info) + if sim_location is None: + return False + return CommonLocationUtils.is_location_within_range_of_location(sim_location, location, distance_in_squares) + + @staticmethod + def is_on_current_lot(sim_info: SimInfo) -> bool: + """is_on_current_lot(sim_info) + + Determine if a Sim is on the active Lot. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is on the active Lot. False, if not. + :rtype: bool + """ + active_lot = CommonLocationUtils.get_current_lot() + return CommonSimLocationUtils.is_on_lot(sim_info, active_lot) + + @staticmethod + def is_on_lot(sim_info: SimInfo, lot: Lot) -> bool: + """is_on_lot(sim_info, lot) + + Determine if a Sim is on a Lot. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param lot: An instance of a Lot. + :type lot: Lot + :return: True, if the Sim is on the specified Lot. False, if not. + :rtype: bool + """ + sim_position = CommonSimLocationUtils.get_position(sim_info) + if sim_position is None: + return False + return CommonLocationUtils.is_position_on_lot(sim_position, lot) + + @staticmethod + def is_renting_current_lot(sim_info: SimInfo) -> bool: + """is_renting_current_lot(sim_info) + + Determine if a Sim is renting the current lot. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is renting the active lot. False, if not. + :rtype: bool + """ + return sim_info.is_renting_zone(CommonLocationUtils.get_current_zone_id()) + + @staticmethod + def is_at_home(sim_info: SimInfo) -> bool: + """is_at_home(sim_info) + + Determine if a Sim is on their home Lot. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is on their home Lot. False, if not. + :rtype: bool + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None or not CommonHouseholdUtils.has_household(sim_info): + return False + return sim.on_home_lot or (CommonLocationUtils.get_current_zone_id() == CommonHouseholdUtils.get_household_zone_id(sim_info) and CommonSimLocationUtils.is_on_current_lot(sim_info)) + + @staticmethod + def is_outside(sim_info: SimInfo) -> bool: + """is_outside(sim_info) + + Determine if a Sim is currently outside. + + :param sim_info: The info of a Sim. + :type sim_info: SimInfo + :return: True, if the Sim is outside. False, if not. + :rtype: bool + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return False + return sim.is_outside + + @classmethod + def is_inside(cls, sim_info: SimInfo) -> bool: + """is_inside(sim_info) + + Determine if a Sim is currently inside. + + :param sim_info: The info of a Sim. + :type sim_info: SimInfo + :return: True, if the Sim is inside. False, if not. + :rtype: bool + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return False + return not sim.is_outside + + @classmethod + def is_inside_building(cls, sim_info: SimInfo) -> bool: + """is_inside_building(sim_info) + + Determine if a Sim is currently inside a building. + + :param sim_info: The info of a Sim. + :type sim_info: SimInfo + :return: True, if the Sim is inside a building. False, if not. + :rtype: bool + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return False + return not sim.is_inside_building + + @classmethod + def is_in_shade(cls, sim_info: SimInfo) -> bool: + """is_in_shade(sim_info) + + Determine if a Sim is currently in the shade. + + :param sim_info: The info of a Sim. + :type sim_info: SimInfo + :return: True, if the Sim is in the shade. False, if not. + :rtype: bool + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return False + return not sim.is_in_shade + + @staticmethod + def send_to_position(sim_info: SimInfo, position: CommonVector3, level: int, go_here_interaction_id: int = None) -> CommonEnqueueResult: + """send_to_position(sim_info, position, level, go_here_interaction_id=None) + + Send a Sim to the specified position. + + :param sim_info: The Sim to send. + :type sim_info: SimInfo + :param position: The position to send the sim to. + :type position: CommonVector3 + :param level: The level at which the position is located. + :type level: int + :param go_here_interaction_id: If supplied, this interaction will be used instead of the vanilla Go Here interaction. Default is None. + :type go_here_interaction_id: int, optional + :return: The result of sending the Sim to the specified position. + :rtype: CommonEnqueueResult + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return CommonEnqueueResult(CommonTestResult(False, reason='No Sim was specified to be sent.'), CommonExecutionResult.NONE) + from server_commands.sim_commands import _build_terrain_interaction_target_and_context, CommandTuning + if position is None: + return CommonEnqueueResult(CommonTestResult(False, reason='No Position specified to send the Sim to!'), CommonExecutionResult.NONE) + routing_surface = CommonSurfaceIdentifier.empty(secondary_id=level) + (target, context) = _build_terrain_interaction_target_and_context(sim, position, routing_surface, PickType.PICK_TERRAIN, objects.terrain.TerrainPoint) + if go_here_interaction_id is not None: + return CommonSimInteractionUtils.queue_interaction(sim_info, go_here_interaction_id, target=target, interaction_context=context) + return sim.push_super_affordance(CommandTuning.TERRAIN_GOHERE_AFFORDANCE, target, context) + + @staticmethod + def send_near_position(sim_info: SimInfo, position: CommonVector3, level: int, go_here_interaction_id: int = None, position_search_flags: FGLSearchFlag = FGLSearchFlag.STAY_IN_CURRENT_BLOCK) -> CommonEnqueueResult: + """send_near_position(sim_info, position, level, go_here_interaction_id=None, position_search_flags=FGLSearchFlag.STAY_IN_CURRENT_BLOCK) + + Send a Sim near the specified position. + + :param sim_info: The Sim to send. + :type sim_info: SimInfo + :param position: The position to send the sim to. + :type position: CommonVector3 + :param level: The level at which the position is located. + :type level: int + :param go_here_interaction_id: If supplied, this interaction will be used instead of the vanilla Go Here interaction. Default is None. + :type go_here_interaction_id: int, optional + :param position_search_flags: Flags used when locating a nearby position. Default is FGLSearchFlag.STAY_IN_CURRENT_BLOCK, which will limit the search to the current Room. + :type position_search_flags: FGLSearchFlag, optional + :return: The result of sending the Sim near the specified position. + :rtype: CommonEnqueueResult + """ + if position is None: + return CommonEnqueueResult(CommonTestResult(False, reason='No Position specified to send the Sim to!'), CommonExecutionResult.NONE) + + transform = CommonTransform(position, CommonQuaternion.empty()) + location = CommonLocation(transform, CommonSurfaceIdentifier.empty(secondary_id=level)) + return CommonSimLocationUtils.send_near_location(sim_info, location, go_here_interaction_id=go_here_interaction_id, location_search_flags=position_search_flags) + + @staticmethod + def send_to_location(sim_info: SimInfo, location: CommonLocation, go_here_interaction_id: int = None) -> CommonEnqueueResult: + """send_to_location(sim_info, location, go_here_interaction_id=None) + + Send a Sim to the specified location. + + :param sim_info: The Sim to send. + :type sim_info: SimInfo + :param location: The location to send the sim near to. + :type location: CommonLocation + :param go_here_interaction_id: If supplied, this interaction will be used instead of the vanilla Go Here interaction. Default is None. + :type go_here_interaction_id: int, optional + :return: The result of sending the Sim to the specified location. + :rtype: CommonEnqueueResult + """ + if location is None: + return CommonEnqueueResult(CommonTestResult(False, reason='No Location specified to send the Sim to!'), CommonExecutionResult.NONE) + + position = location.transform.translation + level = location.routing_surface.secondary_id + return CommonSimLocationUtils.send_to_position(sim_info, position, level, go_here_interaction_id=go_here_interaction_id) + + @staticmethod + def send_near_location(sim_info: SimInfo, location: CommonLocation, go_here_interaction_id: int = None, location_search_flags: FGLSearchFlag = FGLSearchFlag.STAY_IN_CURRENT_BLOCK) -> CommonEnqueueResult: + """send_near_location(sim_info, location, go_here_interaction_id=None, location_search_flags=FGLSearchFlag.STAY_IN_CURRENT_BLOCK) + + Send a Sim near the specified location. + + :param sim_info: The Sim to send. + :type sim_info: SimInfo + :param location: The location to send the sim near to. + :type location: CommonLocation + :param go_here_interaction_id: If supplied, this interaction will be used instead of the vanilla Go Here interaction. Default is None. + :type go_here_interaction_id: int, optional + :param location_search_flags: Flags used when locating a nearby location. Default is FGLSearchFlag.STAY_IN_CURRENT_BLOCK, which will limit the search to the current Room. + :type location_search_flags: FGLSearchFlag, optional + :return: The result of sending the Sim near the specified location. + :rtype: CommonEnqueueResult + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return CommonEnqueueResult(CommonTestResult(False, reason='No Sim was specified to be sent.'), CommonExecutionResult.NONE) + if location is None: + return CommonEnqueueResult(CommonTestResult(False, reason='No Location specified to send the Sim to!'), CommonExecutionResult.NONE) + from placement import find_good_location, create_starting_location, create_fgl_context_for_sim + routing_surface = location.routing_surface + starting_location = create_starting_location(transform=location.transform, routing_surface=routing_surface) + fgl_context = create_fgl_context_for_sim(starting_location, sim, search_flags=(FGLSearchFlagsDefault | location_search_flags) if location_search_flags is not None and location_search_flags != FGLSearchFlag.NONE else FGLSearchFlagsDefault) + (position, orientation) = find_good_location(fgl_context) + if position is None or orientation is None: + fgl_context = create_fgl_context_for_sim(starting_location, sim) + (position, orientation) = find_good_location(fgl_context) + if position is not None and orientation is not None: + transform = CommonTransform(position, orientation) + location = CommonLocation(transform, starting_location.routing_surface) + + position = location.transform.translation + level = location.routing_surface.secondary_id + return CommonSimLocationUtils.send_to_position(sim_info, position, level, go_here_interaction_id=go_here_interaction_id) + + @staticmethod + def is_allowed_on_current_lot(sim_info: SimInfo) -> bool: + """is_allowed_on_current_lot(sim_info) + + Determine if a Sim is allowed on the current lot. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is allowed on the current lot. False, if not. + :rtype: bool + """ + from sims4communitylib.utils.common_component_utils import CommonComponentUtils + from sims4communitylib.enums.types.component_types import CommonComponentType + from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + if CommonSimLocationUtils.is_at_home(sim_info): + return True + if CommonSimLocationUtils.is_renting_current_lot(sim_info): + return True + if CommonSimTypeUtils.is_player_sim(sim_info) and (CommonLocationUtils.current_venue_allows_role_state_routing() or not CommonLocationUtils.current_venue_requires_player_greeting()): + return True + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return False + # noinspection PyTypeChecker + autonomy_component: AutonomyComponent = CommonComponentUtils.get_component(sim, CommonComponentType.AUTONOMY) + if autonomy_component is None or not hasattr(autonomy_component, 'active_roles'): + return False + for role_state_instance in autonomy_component.active_roles(): + if CommonSimTypeUtils.is_non_player_sim(sim_info): + if role_state_instance._portal_disallowance_tags or not role_state_instance._allow_npc_routing_on_active_lot: + return False + elif role_state_instance._portal_disallowance_tags: + return False + return True + + @classmethod + def get_current_room_id(cls, sim_info: SimInfo) -> int: + """get_current_room_id(sim_info) + + Retrieve the id of the room a Sim is currently in. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The id of the room the Sim is currently in or -1 if their room is not found. + :rtype: int + """ + if sim_info is None: + return -1 + return CommonLocationUtils.get_block_id_in_current_zone( + CommonSimLocationUtils.get_position(sim_info), + CommonSimLocationUtils.get_surface_level(sim_info) + ) + + @classmethod + def are_in_same_room(cls, sim_info_a: SimInfo, sim_info_b: SimInfo) -> bool: + """are_in_same_room(sim_info_a, sim_info_b) + + Determine if two Sims are in the same room. + + .. note:: The entirety of "Outside" is considered the same "Room", so if both Sims are outside, this function will return True. + + :param sim_info_a: An instance of a Sim. + :type sim_info_a: SimInfo + :param sim_info_b: An instance of a Sim. + :type sim_info_b: SimInfo + :return: True, if Sim A is in the same room as Sim B. False, if not. + :rtype: bool + """ + if sim_info_a is None or sim_info_b is None: + return False + source_block_id = cls.get_current_room_id(sim_info_a) + target_block_id = cls.get_current_room_id(sim_info_b) + return source_block_id == target_block_id + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_testing.print_room_id', + 'Print the id of the room the Sim is currently in.', + command_arguments=( + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to check.', is_optional=True, default_value='Active Sim'), + ), + show_with_help_command=False +) +def _common_print_room_id(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): + room_id = CommonSimLocationUtils.get_current_room_id(sim_info) + output(f'The current room id of {sim_info} is: {room_id}') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_testing.print_is_inside', + 'Print whether a Sim is considered as being inside or not.', + command_arguments=( + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to check.', is_optional=True, default_value='Active Sim'), + ), + show_with_help_command=False +) +def _common_print_room_id(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): + output(f'Printing whether {sim_info} is inside building or not.') + if sim_info is None: + return + sim = CommonSimUtils.get_sim_instance(sim_info) + is_inside_building = sim.is_inside_building + output(f'{sim_info} is Inside Building? {is_inside_building}') + interaction_counts_as_inside = sim._is_running_interaction_counts_as_inside() + output(f'{sim_info} has interaction counts as inside? {interaction_counts_as_inside}.') diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_loot_action_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_loot_action_utils.py new file mode 100644 index 0000000..692fe48 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_loot_action_utils.py @@ -0,0 +1,124 @@ +""" +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 +""" +from typing import Tuple + +from event_testing.resolver import SingleSimResolver, DoubleSimResolver +from interactions.utils.loot import LootActions +from sims.sim_info import SimInfo +from sims4communitylib.utils.resources.common_loot_action_utils import CommonLootActionUtils + + +class CommonSimLootActionUtils: + """Utilities for manipulating Loot Actions for Sims.""" + @staticmethod + def apply_loot_actions_to_sim(loot_actions: LootActions, sim_info: SimInfo) -> bool: + """apply_loot_actions_to_sim(loot_actions, sim_info) + + Apply loot actions to a Sim. + + :param loot_actions: The loot actions to apply. + :type loot_actions: LootActions + :param sim_info: The Sim to apply the loot actions to. + :type sim_info: SimInfo + :return: True, if the loot actions applied successfully. False, if not. + :rtype: bool + """ + if sim_info is None: + return False + return CommonLootActionUtils.apply_loot_actions_using_resolver(loot_actions, SingleSimResolver(sim_info)) + + @staticmethod + def apply_loot_actions_by_id_to_sim(loot_actions_id: int, sim_info: SimInfo) -> bool: + """apply_loot_actions_by_id_to_sim(loot_actions_id, sim_info) + + Apply loot actions to a Sim. + + :param loot_actions_id: The decimal identifier of a loot actions instance to apply. + :type loot_actions_id: int + :param sim_info: The Sim to apply the loot actions to. + :type sim_info: SimInfo + :return: True, if the loot actions applied successfully. False, if not. + :rtype: bool + """ + if sim_info is None: + return False + return CommonLootActionUtils.apply_loot_actions_by_id_using_resolver(loot_actions_id, SingleSimResolver(sim_info)) + + @staticmethod + def apply_loot_actions_by_ids_to_sim(loot_actions_ids: Tuple[int], sim_info: SimInfo) -> bool: + """apply_loot_actions_by_ids_to_sim(loot_actions_ids, sim_info) + + Apply loot actions to a Sim. + + :param loot_actions_ids: The decimal identifiers of the loot actions to apply. + :type loot_actions_ids: Tuple[int] + :param sim_info: The Sim to apply the loot actions to. + :type sim_info: SimInfo + :return: True, if the loot actions applied successfully. False, if not. + :rtype: bool + """ + if sim_info is None: + return False + return CommonLootActionUtils.apply_loot_actions_by_ids_using_resolver(loot_actions_ids, SingleSimResolver(sim_info)) + + @staticmethod + def apply_loot_actions_to_duo_sims(loot_actions: LootActions, sim_info_actor: SimInfo, sim_info_target: SimInfo) -> bool: + """apply_loot_actions_to_duo_sims(loot_actions, sim_info_actor, sim_info_target) + + Apply loot actions to two Sims at once. + + :param loot_actions: The loot actions to apply. + :type loot_actions: LootActions + :param sim_info_actor: The Actor Sim to apply the loot actions to. + :type sim_info_actor: SimInfo + :param sim_info_target: The Target Sim to apply the loot actions to. + :type sim_info_target: SimInfo + :return: True, if the loot actions applied successfully. False, if not. + :rtype: bool + """ + if sim_info_actor is None or sim_info_target is None: + return False + return CommonLootActionUtils.apply_loot_actions_using_resolver(loot_actions, DoubleSimResolver(sim_info_actor, sim_info_target)) + + @staticmethod + def apply_loot_actions_by_id_to_duo_sims(loot_actions_id: int, sim_info_actor: SimInfo, sim_info_target: SimInfo) -> bool: + """apply_loot_actions_by_id_to_duo_sims(loot_actions_id, sim_info_actor, sim_info_target) + + Apply loot actions by decimal identifier to two Sims at once. + + :param loot_actions_id: The decimal identifier of a loot actions instance to apply. + :type loot_actions_id: int + :param sim_info_actor: The Actor Sim to apply the loot actions to. + :type sim_info_actor: SimInfo + :param sim_info_target: The Target Sim to apply the loot actions to. + :type sim_info_target: SimInfo + :return: True, if the loot actions applied successfully. False, if not. + :rtype: bool + """ + if sim_info_actor is None or sim_info_target is None: + return False + return CommonLootActionUtils.apply_loot_actions_by_id_using_resolver(loot_actions_id, DoubleSimResolver(sim_info_actor, sim_info_target)) + + @staticmethod + def apply_loot_actions_by_ids_to_duo_sims(loot_actions_ids: Tuple[int], sim_info_actor: SimInfo, sim_info_target: SimInfo) -> bool: + """apply_loot_actions_by_id_to_duo_sims(loot_actions_ids, sim_info_actor, sim_info_target) + + Apply loot actions by decimal identifiers to two Sims at once. + + :param loot_actions_ids: The decimal identifiers of the loot actions to apply. + :type loot_actions_ids: Tuple[int] + :param sim_info_actor: The Actor Sim to apply the loot actions to. + :type sim_info_actor: SimInfo + :param sim_info_target: The Target Sim to apply the loot actions to. + :type sim_info_target: SimInfo + :return: True, if the loot actions applied successfully. False, if not. + :rtype: bool + """ + if sim_info_actor is None or sim_info_target is None: + return False + return CommonLootActionUtils.apply_loot_actions_by_ids_using_resolver(loot_actions_ids, DoubleSimResolver(sim_info_actor, sim_info_target)) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_motive_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_motive_utils.py new file mode 100644 index 0000000..0636d5c --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_motive_utils.py @@ -0,0 +1,646 @@ +""" +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 +""" +from typing import Dict, Union + +import services +from server_commands.argument_helpers import TunableInstanceParam +from sims.sim_info import SimInfo +from sims4 import commands +from sims4.resources import Types +from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.enums.common_species import CommonSpecies +from sims4communitylib.enums.enumtypes.common_int import CommonInt +from sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + CommonConsoleCommandArgument +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.sims.common_occult_utils import CommonOccultUtils +from sims4communitylib.utils.sims.common_sim_statistic_utils import CommonSimStatisticUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils +from sims4communitylib.enums.motives_enum import CommonMotiveId + + +class CommonSimMotiveUtils(_HasS4CLClassLog): + """Utilities for Sim motives. + + .. note:: Motives are just another name for Sim Needs (Bladder, Hunger, Energy, etc.) + + """ + _MOTIVE_MAPPINGS: Dict[Union[CommonMotiveId, CommonInt, int], Dict[CommonSpecies, Union[CommonMotiveId, CommonInt, int]]] = None + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 'common_sim_motive_utils' + + @classmethod + def has_motive(cls, sim_info: SimInfo, motive_id: Union[CommonMotiveId, CommonInt, int]) -> CommonTestResult: + """has_motive(sim_info, motive_id) + + Determine if a Sim has the specified Motive. + + .. note:: For example, you could use this to determine if a Sim has a vampire power level. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :param motive_id: The identifier of the Motive to look for. + :type motive_id: Union[CommonMotiveId, CommonInt, int] + :return: The result of testing if the Sim has the motive. True, if the Sim has the specified Motive. False, if not. + :rtype: CommonTestResult + """ + if sim_info is None: + cls.get_log().format_with_message('sim_info was None!', motive_id=motive_id, sim=sim_info) + return CommonTestResult(False, reason='sim_info was None.') + mapped_motive_id: int = cls._map_motive_id(sim_info, motive_id) + if mapped_motive_id == -1: + cls.get_log().format_with_message('Failed to map motive id!', motive_id=motive_id, sim=sim_info) + return CommonTestResult(False, reason=f'Sim did not have a mapped motive {motive_id}') + cls.get_log().format_with_message('Mapped motive id, checking if Sim has the motive.', motive_id=motive_id, mapped_motive_id=mapped_motive_id, sim=sim_info) + return CommonSimStatisticUtils.has_statistic(sim_info, mapped_motive_id) + + @classmethod + def set_motive_level(cls, sim_info: SimInfo, motive_id: Union[CommonMotiveId, CommonInt, int], level: float) -> CommonExecutionResult: + """set_motive_level(sim_info, motive_id, level) + + Set the current level of a Motive on a Sim. + + :param sim_info: The Sim to modify. + :type sim_info: SimInfo + :param motive_id: The identifier of the Motive to change. + :type motive_id: Union[CommonMotiveId, CommonInt, int] + :param level: The amount to set the motive level to. + :type level: float + :return: The result of setting the motive level. True, if the specified Motive was changed successfully. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + cls.get_log().format_with_message('sim_info was None!', motive_id=motive_id, sim=sim_info) + return CommonExecutionResult(False, reason='sim_info was None.') + mapped_motive_id: int = cls._map_motive_id(sim_info, motive_id) + if mapped_motive_id == -1: + cls.get_log().format_with_message('Failed to map motive id!', motive_id=motive_id, sim=sim_info) + return CommonExecutionResult(False, reason=f'Sim did not have motive {motive_id}') + cls.get_log().format_with_message('Mapped motive id, setting the level for it on Sim.', motive_id=motive_id, mapped_motive_id=mapped_motive_id, level=level, sim=sim_info) + return CommonSimStatisticUtils.set_statistic_value(sim_info, mapped_motive_id, level, add=True) + + @classmethod + def get_motive_level(cls, sim_info: SimInfo, motive_id: Union[CommonMotiveId, CommonInt, int]) -> float: + """get_motive_level(sim_info, motive_id, amount) + + Retrieve the current level of a Motive of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param motive_id: The identifier of the Motive to get the value of. + :type motive_id: Union[CommonMotiveId, CommonInt, int] + :return: The current level of the motive for the specified Sim. + :rtype: float + """ + return cls._get_motive_level(sim_info, motive_id) + + @classmethod + def increase_motive_level(cls, sim_info: SimInfo, motive_id: Union[CommonMotiveId, CommonInt, int], amount: float) -> CommonExecutionResult: + """increase_motive_level(sim_info, motive_id, amount) + + Increase the current level of a Motive of a Sim. + + :param sim_info: The Sim to modify. + :type sim_info: SimInfo + :param motive_id: The identifier of the Motive to change. + :type motive_id: Union[CommonMotiveId, CommonInt, int] + :param amount: The amount to increase the motive by. + :type amount: float + :return: The result of increasing motive level. True, if the specified Motive was changed successfully. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + cls.get_log().format_with_message('sim_info was None!', motive_id=motive_id, sim=sim_info) + return CommonExecutionResult(False, reason='sim_info was None.') + mapped_motive_id: int = cls._map_motive_id(sim_info, motive_id) + if mapped_motive_id == -1: + cls.get_log().format_with_message('Failed to map motive id!', motive_id=motive_id, sim=sim_info) + return CommonExecutionResult(False, reason=f'The motive {motive_id} did not map to any known motive for the Sim {sim_info}.') + cls.get_log().format_with_message('Mapped motive id, Adding to it for Sim.', motive_id=motive_id, mapped_motive_id=mapped_motive_id, amount=amount, sim=sim_info) + return CommonSimStatisticUtils.add_statistic_value(sim_info, mapped_motive_id, amount, add=True) + + @classmethod + def decrease_motive_level(cls, sim_info: SimInfo, motive_id: Union[CommonMotiveId, CommonInt, int], amount: float) -> CommonExecutionResult: + """decrease_motive_level(sim_info, motive_id, amount) + + Decrease the current level of a Motive of a Sim. + + :param sim_info: The Sim to modify. + :type sim_info: SimInfo + :param motive_id: The identifier of the Motive to change. + :type motive_id: Union[CommonMotiveId, CommonInt, int] + :param amount: The amount to decrease the motive by. + :type amount: float + :return: The result of decreasing motive level. True, if the specified Motive was changed successfully. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + cls.get_log().format_with_message('sim_info was None!', motive_id=motive_id, sim=sim_info) + return CommonExecutionResult(False, reason='sim_info was None.') + mapped_motive_id: int = cls._map_motive_id(sim_info, motive_id) + if mapped_motive_id == -1: + cls.get_log().format_with_message('Failed to map motive id!', motive_id=motive_id, sim=sim_info) + return CommonExecutionResult(False, reason=f'The motive {motive_id} did not map to any known motive for the Sim {sim_info}.') + cls.get_log().format_with_message('Mapped motive id, Subtracting from it for Sim.', motive_id=motive_id, mapped_motive_id=mapped_motive_id, amount=amount, sim=sim_info) + return CommonSimStatisticUtils.add_statistic_value(sim_info, mapped_motive_id, amount * -1.0, add=True) + + @classmethod + def get_hunger_level(cls, sim_info: SimInfo) -> float: + """get_hunger_level(sim_info) + + Retrieve the hunger level of a Sim. + + :param sim_info: The Sim to get the level of. + :type sim_info: SimInfo + :return: The current level of the Motive of the Sim. + :rtype: float + """ + if sim_info is None: + cls.get_log().format_with_message('sim_info was None!', sim=sim_info) + return False + motive_level = cls._get_motive_level(sim_info, CommonMotiveId.HUNGER) + if motive_level is None: + cls.get_log().format_with_message('Sim did not have motive HUNGER.', sim=sim_info) + return 0.0 + return motive_level + + @classmethod + def get_hygiene_level(cls, sim_info: SimInfo) -> float: + """get_hygiene_level(sim_info) + + Retrieve the hygiene level of a Sim. + + :param sim_info: The Sim to get the level of. + :type sim_info: SimInfo + :return: The current level of the Motive of the Sim. + :rtype: float + """ + if sim_info is None: + cls.get_log().format_with_message('sim_info was None!', sim=sim_info) + return False + motive_level = cls._get_motive_level(sim_info, CommonMotiveId.HYGIENE) + if motive_level is None: + cls.get_log().format_with_message('Sim did not have motive HYGIENE.', sim=sim_info) + return 0.0 + return motive_level + + @classmethod + def get_energy_level(cls, sim_info: SimInfo) -> float: + """get_energy_level(sim_info) + + Retrieve the energy level of a Sim. + + :param sim_info: The Sim to get the level of. + :type sim_info: SimInfo + :return: The current level of the Motive of the Sim. + :rtype: float + """ + if sim_info is None: + cls.get_log().format_with_message('sim_info was None!', sim=sim_info) + return False + motive_level = cls._get_motive_level(sim_info, CommonMotiveId.ENERGY) + if motive_level is None: + cls.get_log().format_with_message('Sim did not have motive ENERGY.', sim=sim_info) + return 0.0 + return motive_level + + @classmethod + def get_bladder_level(cls, sim_info: SimInfo) -> float: + """get_bladder_level(sim_info) + + Retrieve the bladder level of a Sim. + + :param sim_info: The Sim to get the level of. + :type sim_info: SimInfo + :return: The current level of the Motive of the Sim. + :rtype: float + """ + if sim_info is None: + cls.get_log().format_with_message('sim_info was None!', sim=sim_info) + return False + motive_level = cls._get_motive_level(sim_info, CommonMotiveId.BLADDER) + if motive_level is None: + return 0.0 + return motive_level + + @classmethod + def has_bowels(cls, sim_info: SimInfo) -> CommonTestResult: + """has_bowels(sim_info) + + Determine if a Sim has bowels. + + .. note:: Human Sims do not have Bowels. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of the test. True, if the Sim has bowels. False, if not. + :rtype: CommonTestResult + """ + return cls.has_motive(sim_info, CommonMotiveId.BOWEL) + + @classmethod + def get_bowels_level(cls, sim_info: SimInfo) -> float: + """get_bowels_level(sim_info) + + Retrieve the bowel level of a Sim. + + .. note:: Human Sims do not have Bowels. (As hard as that is to believe) + + :param sim_info: The Sim to get the level of. + :type sim_info: SimInfo + :return: The current level of the Motive of the Sim. + :rtype: float + """ + if CommonSpeciesUtils.is_human(sim_info): + cls.get_log().format_with_message('Sim did not have motive BOWELS.', sim=sim_info) + return 0.0 + return cls._get_motive_level(sim_info, CommonMotiveId.BOWEL) + + @classmethod + def get_social_level(cls, sim_info: SimInfo) -> float: + """get_social_level(sim_info) + + Retrieve the social level of a Sim. + + :param sim_info: The Sim to get the level of. + :type sim_info: SimInfo + :return: The current level of the Motive of the Sim. + :rtype: float + """ + motive_level = cls._get_motive_level(sim_info, CommonMotiveId.SOCIAL) + if motive_level is None: + cls.get_log().format_with_message('Sim did not have motive SOCIAL.', sim=sim_info) + return 0.0 + return motive_level + + @classmethod + def get_fun_level(cls, sim_info: SimInfo) -> float: + """get_fun_level(sim_info) + + Retrieve the fun level of a Sim. + + :param sim_info: The Sim to get the level of. + :type sim_info: SimInfo + :return: The current level of the Motive of the Sim. + :rtype: float + """ + motive_level = cls._get_motive_level(sim_info, CommonMotiveId.FUN) + if motive_level is None: + cls.get_log().format_with_message('Sim did not have motive FUN.', sim=sim_info) + return 0.0 + return motive_level + + @classmethod + def get_robot_charge_level(cls, sim_info: SimInfo) -> float: + """get_robot_charge_level(sim_info) + + Retrieve the charge level of a Sim. + + :param sim_info: The Sim to get the level of. + :type sim_info: SimInfo + :return: The current level of the Motive of the Sim or `0.0` if the Sim is not a Robot. + :rtype: float + """ + if not CommonOccultUtils.is_robot(sim_info): + cls.get_log().format_with_message('Sim is not a Robot.', sim=sim_info) + return 0.0 + return cls._get_motive_level(sim_info, CommonMotiveId.SERVO_CHARGE) + + @classmethod + def get_robot_durability_level(cls, sim_info: SimInfo) -> float: + """get_robot_durability_level(sim_info) + + Retrieve the durability level of a Sim. + + :param sim_info: The Sim to get the level of. + :type sim_info: SimInfo + :return: The current level of the Motive of the Sim or `0.0` if the Sim is not a Robot. + :rtype: float + """ + if not CommonOccultUtils.is_robot(sim_info): + cls.get_log().format_with_message('Sim is not a Robot.', sim=sim_info) + return 0.0 + return cls._get_motive_level(sim_info, CommonMotiveId.SERVO_DURABILITY) + + @classmethod + def get_vampire_power_level(cls, sim_info: SimInfo) -> float: + """get_vampire_power_level(sim_info) + + Retrieve the vampire power level of a Sim. + + :param sim_info: The Sim to get the level of. + :type sim_info: SimInfo + :return: The current level of the Motive of the Sim or `0.0` if the Sim is not a Vampire. + :rtype: float + """ + if not CommonOccultUtils.is_vampire(sim_info): + cls.get_log().format_with_message('Sim is not a Vampire.', sim=sim_info) + return 0.0 + return cls._get_motive_level(sim_info, CommonMotiveId.VAMPIRE_POWER) + + @classmethod + def get_vampire_thirst_level(cls, sim_info: SimInfo) -> float: + """get_vampire_thirst_level(sim_info) + + Retrieve the vampire thirst level of a Sim. + + :param sim_info: The Sim to get the level of. + :type sim_info: SimInfo + :return: The current level of the Motive of the Sim or `0.0` if the Sim is not a Vampire. + :rtype: float + """ + if not CommonOccultUtils.is_vampire(sim_info): + cls.get_log().format_with_message('Sim is not a Vampire.', sim=sim_info) + return 0.0 + return cls._get_motive_level(sim_info, CommonMotiveId.VAMPIRE_THIRST) + + @classmethod + def get_plant_sim_water_level(cls, sim_info: SimInfo) -> float: + """get_plant_sim_water_level(sim_info) + + Retrieve the plant sim water level of a Sim. + + :param sim_info: The Sim to get the level of. + :type sim_info: SimInfo + :return: The current level of the Motive of the Sim or `0.0` if the Sim is not a Plant Sim. + :rtype: float + """ + if not CommonOccultUtils.is_plant_sim(sim_info): + cls.get_log().format_with_message('Sim is not a Plant Sim.', sim=sim_info) + return 0.0 + return cls._get_motive_level(sim_info, CommonMotiveId.PLANT_SIM_WATER) + + @classmethod + def get_mermaid_hydration_level(cls, sim_info: SimInfo) -> float: + """get_mermaid_hydration_level(sim_info) + + Retrieve the hydration level of a Sim. + + .. note:: This level is basically the Hygiene motive. + + :param sim_info: The Sim to get the level of. + :type sim_info: SimInfo + :return: The current level of the Motive of the Sim or `0.0` if the Sim is not a Mermaid. + :rtype: float + """ + if not CommonOccultUtils.is_mermaid(sim_info): + cls.get_log().format_with_message('Sim is not a Mermaid.', sim=sim_info) + return 0.0 + return cls._get_motive_level(sim_info, CommonMotiveId.MERMAID_HYDRATION) + + @classmethod + def get_witch_magic_level(cls, sim_info: SimInfo) -> float: + """get_witch_magic_level(sim_info) + + Retrieve the magic level of a Sim. + + :param sim_info: The Sim to get the level of. + :type sim_info: SimInfo + :return: The current level of the Motive of the Sim or `0.0` if the Sim is not a Witch. + :rtype: float + """ + if sim_info is None: + cls.get_log().format_with_message('sim_info was None!', sim=sim_info) + return 0.0 + if not CommonOccultUtils.is_witch(sim_info): + cls.get_log().format_with_message('Sim is not a Witch.', sim=sim_info) + return 0.0 + return cls._get_motive_level(sim_info, CommonMotiveId.WITCH_MAGIC) + + @classmethod + def is_motive_locked(cls, sim_info: SimInfo, motive_id: Union[CommonMotiveId, CommonInt, int]) -> CommonTestResult: + """is_motive_locked(sim_info, motive_id) + + Determine if a Motive is locked for a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param motive_id: The identifier of the motive to check. + :type motive_id: Union[CommonMotiveId, CommonInt, int] + :return: The result of the test. True, if the specified Motive is locked for the Sim. False, if not. + :rtype: CommonTestResult + """ + mapped_motive_id: int = cls._map_motive_id(sim_info, motive_id) + if mapped_motive_id == -1: + cls.get_log().format_with_message('Failed to map motive id!', motive_id=motive_id, sim=sim_info) + return CommonTestResult(False, reason=f'The motive {motive_id} did not map to any known motive for the Sim {sim_info}.') + motive_instance = CommonSimStatisticUtils.get_statistic(sim_info, mapped_motive_id) + if motive_instance is None: + return CommonTestResult(False, reason=f'No motive found for id {mapped_motive_id}.') + if sim_info.is_locked(motive_instance): + return CommonTestResult(True, reason=f'Motive {mapped_motive_id} is locked for Sim {sim_info}') + return CommonTestResult(False, reason=f'Motive {mapped_motive_id} is not locked for Sim {sim_info}') + + @classmethod + def set_all_motives_max(cls, sim_info: SimInfo) -> CommonExecutionResult: + """set_all_motives_max(sim_info) + + Set all Motives for a Sim to their maximum values. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of setting all motives to max. True, if successful. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + return CommonExecutionResult(False, reason='sim_info was None.') + client_id = services.client_manager().get_first_client_id() + commands.execute('stats.fill_commodities {}'.format(CommonSimUtils.get_sim_id(sim_info)), client_id) + return CommonExecutionResult(True, reason=f'Successfully set all motives to their max levels for Sim {sim_info}') + + @classmethod + def _get_motive_level(cls, sim_info: SimInfo, motive_id: Union[CommonMotiveId, CommonInt, int]) -> float: + if sim_info is None: + cls.get_log().format_with_message('sim_info was None!', motive_id=motive_id, sim=sim_info) + return 0.0 + mapped_motive_id: int = cls._map_motive_id(sim_info, motive_id) + if mapped_motive_id == -1: + cls.get_log().format_with_message('Failed to map the motive id.', motive_id=motive_id, sim=sim_info) + return 0.0 + cls.get_log().format_with_message('Mapped motive id, attempting to get motive value.', motive_id=motive_id, mapped_motive_id=mapped_motive_id, sim=sim_info) + return CommonSimStatisticUtils.get_statistic_value(sim_info, mapped_motive_id) + + @classmethod + def get_motive_id_for_sim(cls, sim_info: SimInfo, motive_id: Union[CommonMotiveId, CommonInt, int]) -> Union[CommonMotiveId, CommonInt, int]: + """get_motive_id_for_sim(sim_info, motive_id) + + Translate a motive ID to one that the Sim would have. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param motive_id: The motive to translate. + :type motive_id: Union[CommonMotiveId, CommonInt, int] + :return: The mapped motive id. + :rtype: Union[CommonMotiveId, CommonInt, int] + """ + result = cls._map_motive_id(sim_info, motive_id) + if result == -1: + return motive_id + return result + + @classmethod + def _map_motive_id(cls, sim_info: SimInfo, motive_id: Union[CommonMotiveId, CommonInt, int]) -> Union[CommonMotiveId, CommonInt, int]: + motive_mappings = cls._get_motive_mappings() + if motive_id not in motive_mappings: + return motive_id + motive_species_mapping: Dict[CommonSpecies, CommonMotiveId] = motive_mappings[motive_id] + + species = CommonSpecies.get_species(sim_info) + return motive_species_mapping.get(species, motive_id) + + @classmethod + def _get_motive_mappings(cls) -> Dict[Union[CommonMotiveId, CommonInt, int], Dict[CommonSpecies, Union[CommonMotiveId, CommonInt, int]]]: + if CommonSimMotiveUtils._MOTIVE_MAPPINGS is not None: + return CommonSimMotiveUtils._MOTIVE_MAPPINGS + + CommonSimMotiveUtils._MOTIVE_MAPPINGS = { + CommonMotiveId.HUNGER: { + CommonSpecies.HUMAN: CommonMotiveId.HUNGER, + CommonSpecies.CAT: CommonMotiveId.PET_CAT_HUNGER, + CommonSpecies.LARGE_DOG: CommonMotiveId.PET_DOG_HUNGER, + CommonSpecies.SMALL_DOG: CommonMotiveId.PET_DOG_HUNGER, + CommonSpecies.FOX: CommonMotiveId.HUNGER, + CommonSpecies.HORSE: CommonMotiveId.PET_HORSE_HUNGER + }, + CommonMotiveId.HYGIENE: { + CommonSpecies.HUMAN: CommonMotiveId.HYGIENE, + CommonSpecies.CAT: CommonMotiveId.PET_CAT_HYGIENE, + CommonSpecies.LARGE_DOG: CommonMotiveId.PET_DOG_HYGIENE, + CommonSpecies.SMALL_DOG: CommonMotiveId.PET_DOG_HYGIENE, + CommonSpecies.FOX: CommonMotiveId.ANIMAL_FOX_HYGIENE, + CommonSpecies.HORSE: CommonMotiveId.PET_HORSE_HYGIENE + }, + CommonMotiveId.MERMAID_HYDRATION: { + CommonSpecies.HUMAN: CommonMotiveId.HYGIENE, + CommonSpecies.CAT: CommonMotiveId.PET_CAT_HYGIENE, + CommonSpecies.LARGE_DOG: CommonMotiveId.PET_DOG_HYGIENE, + CommonSpecies.SMALL_DOG: CommonMotiveId.PET_DOG_HYGIENE, + CommonSpecies.FOX: CommonMotiveId.HYGIENE, + CommonSpecies.HORSE: CommonMotiveId.PET_HORSE_HYGIENE + }, + CommonMotiveId.ENERGY: { + CommonSpecies.HUMAN: CommonMotiveId.ENERGY, + CommonSpecies.CAT: CommonMotiveId.PET_CAT_ENERGY, + CommonSpecies.LARGE_DOG: CommonMotiveId.PET_DOG_ENERGY, + CommonSpecies.SMALL_DOG: CommonMotiveId.PET_DOG_ENERGY, + CommonSpecies.FOX: CommonMotiveId.ENERGY, + CommonSpecies.HORSE: CommonMotiveId.PET_HORSE_ENERGY + }, + CommonMotiveId.BLADDER: { + CommonSpecies.HUMAN: CommonMotiveId.BLADDER, + CommonSpecies.CAT: CommonMotiveId.PET_CAT_BLADDER, + CommonSpecies.LARGE_DOG: CommonMotiveId.PET_DOG_BLADDER, + CommonSpecies.SMALL_DOG: CommonMotiveId.PET_DOG_BLADDER, + CommonSpecies.FOX: CommonMotiveId.ANIMAL_FOX_BLADDER, + CommonSpecies.HORSE: CommonMotiveId.PET_HORSE_BLADDER + }, + CommonMotiveId.BOWEL: { + CommonSpecies.HUMAN: CommonMotiveId.BOWEL, + CommonSpecies.CAT: CommonMotiveId.PET_CAT_BOWEL, + CommonSpecies.LARGE_DOG: CommonMotiveId.PET_DOG_BOWEL, + CommonSpecies.SMALL_DOG: CommonMotiveId.PET_DOG_BOWEL, + CommonSpecies.FOX: CommonMotiveId.BOWEL, + CommonSpecies.HORSE: CommonMotiveId.BOWEL + }, + CommonMotiveId.SOCIAL: { + CommonSpecies.HUMAN: CommonMotiveId.SOCIAL, + CommonSpecies.CAT: CommonMotiveId.PET_CAT_AFFECTION, + CommonSpecies.LARGE_DOG: CommonMotiveId.PET_DOG_AFFECTION, + CommonSpecies.SMALL_DOG: CommonMotiveId.PET_DOG_AFFECTION, + CommonSpecies.FOX: CommonMotiveId.SOCIAL, + CommonSpecies.HORSE: CommonMotiveId.PET_HORSE_SOCIAL + }, + CommonMotiveId.FUN: { + CommonSpecies.HUMAN: CommonMotiveId.FUN, + CommonSpecies.CAT: CommonMotiveId.PET_CAT_PLAY, + CommonSpecies.LARGE_DOG: CommonMotiveId.PET_DOG_PLAY, + CommonSpecies.SMALL_DOG: CommonMotiveId.PET_DOG_PLAY, + CommonSpecies.FOX: CommonMotiveId.FUN, + CommonSpecies.HORSE: CommonMotiveId.PET_HORSE_FUN + } + } + return CommonSimMotiveUtils._MOTIVE_MAPPINGS + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.print_motive_level', + 'Print the current level of a Motive for a Sim.', + command_arguments=( + CommonConsoleCommandArgument('motive', 'Motive Id or Tuning Name', 'The tuning name or decimal identifier of a Motive.'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to check.', is_optional=True, default_value='Active Sim'), + ) +) +def _common_print_motive_level(output: CommonConsoleCommandOutput, motive: TunableInstanceParam(Types.STATISTIC), sim_info: SimInfo = None): + if motive is None: + output('ERROR: No Motive specified or Motive did not exist!') + return + if sim_info is None: + output('Failed, no Sim was specified or the specified Sim was not found!') + return + output(f'Printing motive level of Motive {motive} for Sim {sim_info}') + motive_level = CommonSimMotiveUtils.get_motive_level(sim_info, motive) + output(f'Motive Level of {motive}: {motive_level}') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.set_motive_level', + 'Set the current level of a Motive for a Sim.', + command_arguments=( + CommonConsoleCommandArgument('motive', 'Motive Id or Tuning Name', 'The tuning name or decimal identifier of a Motive.'), + CommonConsoleCommandArgument('level', 'Decimal Number', 'The amount to set the motive level to between -100 and 100.'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to change.', is_optional=True, default_value='Active Sim'), + ) +) +def _common_set_motive_level(output: CommonConsoleCommandOutput, motive: TunableInstanceParam(Types.STATISTIC), level: float, sim_info: SimInfo = None): + if motive is None: + output('ERROR: Failed, Motive not specified or Motive did not exist! s4clib.set_motive_level [opt_sim=None]') + return + if sim_info is None: + return + output(f'Attempting to set motive {motive} for Sim {sim_info} to {level}') + if CommonSimMotiveUtils.set_motive_level(sim_info, motive, level): + output(f'SUCCESS: Successfully set the motive level of motive {motive} for Sim {sim_info} to {level}.') + else: + output(f'FAILED: Failed to set motive level of motive {motive} for Sim {sim_info} to {level}.') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.max_all_motives', + 'Set all Motive Levels to their maximum for a Sim.', + command_arguments=( + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to change.', is_optional=True, default_value='Active Sim'), + ) +) +def _common_max_all_motives(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): + if sim_info is None: + return + CommonSimMotiveUtils.set_all_motives_max(sim_info) + output(f'SUCCESS: Maxed the motives of {sim_info}.') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.max_world_motives', + 'Set all Motive Levels to their maximum for all Sims.' +) +def _common_max_world_motives(output: CommonConsoleCommandOutput): + sim_count = 0 + for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): + CommonSimMotiveUtils.set_all_motives_max(sim_info) + sim_count += 1 + output('Maxed the motives of {} Sim(s).'.format(sim_count)) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_name_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_name_utils.py new file mode 100644 index 0000000..777d356 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_name_utils.py @@ -0,0 +1,284 @@ +""" +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 +""" +from typing import Tuple + +from sims.sim_info import SimInfo +from sims.sim_spawner import SimSpawner +from sims.sim_spawner_enums import SimNameType +from sims4communitylib.enums.common_gender import CommonGender +from sims4communitylib.enums.common_sim_name_type import CommonSimNameType +from sims4communitylib.enums.common_species import CommonSpecies +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + CommonConsoleCommandArgument +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.misc.common_text_utils import CommonTextUtils + + +class CommonSimNameUtils: + """Utilities for manipulating the name of Sims. + + """ + @staticmethod + def has_name(sim_info: SimInfo) -> bool: + """has_name(sim_info) + + Determine if a Sim has a name. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: True, if the specified Sim has a name. False, if not. + :rtype: bool + """ + if sim_info is None: + return False + return CommonSimNameUtils.get_full_name(sim_info) != '' + + @staticmethod + def set_first_name(sim_info: SimInfo, first_name: str): + """set_first_name(sim_info, first_name) + + Retrieve the First Name of a Sim. + + :param sim_info: The Sim to set the first name of. + :type sim_info: SimInfo + :param first_name: The first name you want the Sim to have. + :type first_name: str + """ + if sim_info is None or not hasattr(sim_info, 'first_name'): + return + sim_info.first_name = first_name + + @staticmethod + def set_last_name(sim_info: SimInfo, last_name: str): + """set_last_name(sim_info, last_name) + + Retrieve the Last Name of a Sim. + + :param sim_info: The Sim to set the last name of. + :type sim_info: SimInfo + :param last_name: The last name you want the Sim to have. + :type last_name: str + """ + if sim_info is None or not hasattr(sim_info, 'last_name'): + return + sim_info.last_name = last_name + + @staticmethod + def get_first_name(sim_info: SimInfo) -> str: + """get_first_name(sim_info) + + Retrieve the First Name of a Sim. + + :param sim_info: The Sim to retrieve the first name of. + :type sim_info: SimInfo + :return: The first name of the specified Sim. + :rtype: str + """ + if sim_info is None or not hasattr(sim_info, 'first_name'): + return '' + return getattr(sim_info, 'first_name') + + @staticmethod + def get_last_name(sim_info: SimInfo) -> str: + """get_last_name(sim_info) + + Retrieve the Last Name of a Sim. + + :param sim_info: The Sim to retrieve the last name of. + :type sim_info: SimInfo + :return: The last name of the specified Sim. + :rtype: str + """ + if sim_info is None or not hasattr(sim_info, 'last_name'): + return '' + return getattr(sim_info, 'last_name') + + @staticmethod + def get_full_name(sim_info: SimInfo) -> str: + """get_full_name(sim_info) + + Retrieve the full name of a Sim. + + .. note:: Resulting Full Name: '{First} {Last}' + + :param sim_info: The Sim to retrieve the full name of. + :type sim_info: SimInfo + :return: The full name of the specified Sim. + :rtype: str + """ + full_name = '{} {}'.format(CommonSimNameUtils.get_first_name(sim_info), CommonSimNameUtils.get_last_name(sim_info)).strip() + if full_name == '': + full_name = 'No Name' + return full_name + + @staticmethod + def get_full_names(sim_info_list: Tuple[SimInfo]) -> Tuple[str]: + """get_full_names(sim_info_list) + + Retrieve a collection of full names for the specified Sims. + + .. note:: Resulting Full Names: ('{First} {Last}', '{First} {Last}', '{First} {Last}', ...) + + :param sim_info_list: A collection of Sims + :type sim_info_list: Tuple[SimInfo] + :return: A collection of full names of the specified Sims. + :rtype: Tuple[str] + """ + result: Tuple[str] = tuple([CommonSimNameUtils.get_full_name(sim_info) for sim_info in sim_info_list]) + return result + + @staticmethod + def create_random_first_name(gender: CommonGender, species: CommonSpecies=CommonSpecies.HUMAN, sim_name_type: CommonSimNameType=CommonSimNameType.DEFAULT) -> str: + """create_random_first_name(gender, species=CommonSpecies.HUMAN, sim_name_type=CommonSimNameType.DEFAULT) + + Create a random first name. + + :param gender: A gender. + :type gender: CommonGender + :param species: A species. Default is HUMAN. + :type species: CommonSpecies, optional + :param sim_name_type: The Sim Name Type determines from which list of names to randomize the name from. Default is CommonSimNameType.DEFAULT. + :type sim_name_type: CommonSimNameType, optional + :return: A random first name. + :rtype: str + """ + vanilla_gender = CommonGender.convert_to_vanilla(gender) + vanilla_species = CommonSpecies.convert_to_vanilla(species) + vanilla_sim_name_type = CommonSimNameType.convert_to_vanilla(sim_name_type) + return SimSpawner.get_random_first_name(vanilla_gender, species=vanilla_species, sim_name_type_override=vanilla_sim_name_type) + + @staticmethod + def create_random_last_name(gender: CommonGender, species: CommonSpecies=CommonSpecies.HUMAN, sim_name_type: CommonSimNameType=CommonSimNameType.DEFAULT) -> str: + """create_random_last_name(gender, species=CommonSpecies.HUMAN, sim_name_type=CommonSimNameType.DEFAULT) + + Create a random last name. + + :param gender: A gender. + :type gender: CommonGender + :param species: A species. Default is HUMAN. + :type species: CommonSpecies, optional + :param sim_name_type: The Sim Name Type determines from which list of names to randomize the name from. Default is CommonSimNameType.DEFAULT. + :type sim_name_type: CommonSimNameType, optional + :return: A random last name. + :rtype: str + """ + account = SimSpawner._get_default_account() + vanilla_gender = CommonGender.convert_to_vanilla(gender) + vanilla_species = CommonSpecies.convert_to_vanilla(species) + vanilla_sim_name_type = CommonSimNameType.convert_to_vanilla(sim_name_type) + language = SimSpawner._get_language_for_locale(account.locale) + family_name = SimSpawner._get_random_last_name(language, sim_name_type=vanilla_sim_name_type) + if sim_name_type == SimNameType.DEFAULT: + last_name = SimSpawner.get_last_name(family_name, vanilla_gender, species=vanilla_species) + else: + from sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils + last_name = SimSpawner._get_family_name_for_gender(language, family_name, CommonGenderUtils.is_female_gender(gender), sim_name_type=vanilla_sim_name_type) + return last_name + + +@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.randomize_name', 'Randomize the first and last names of a Sim.', command_arguments=( + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to change the first and last names of.'), + CommonConsoleCommandArgument('sim_name_type', 'CommonSimNameType', f'Determines from which list of names to randomize the name from. Valid Values: {CommonSimNameType.get_comma_separated_names_string()}'), +)) +def _common_randomize_name(output: CommonConsoleCommandOutput, sim_info: SimInfo=None, sim_name_type: CommonSimNameType=CommonSimNameType.DEFAULT): + if sim_info is None: + return + gender = CommonGender.get_gender(sim_info) + species = CommonSpecies.get_species(sim_info) + first_name = CommonSimNameUtils.create_random_first_name(gender, species=species, sim_name_type=sim_name_type) + first_name = CommonTextUtils.capitalize(first_name) + output(f'Setting the first name of Sim {sim_info} to {first_name}') + CommonSimNameUtils.set_first_name(sim_info, first_name) + last_name = CommonSimNameUtils.create_random_last_name(gender, species=species, sim_name_type=sim_name_type) + last_name = CommonTextUtils.capitalize(last_name) + output(f'Setting the last name of Sim {sim_info} to {last_name}') + CommonSimNameUtils.set_last_name(sim_info, last_name) + + +@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.set_first_name', 'Set the first name of a Sim.', command_arguments=( + CommonConsoleCommandArgument('first_name', 'Text', 'The first name to give to the Sim.'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to change the first name of.'), +)) +def _common_set_first_name(output: CommonConsoleCommandOutput, first_name: str, sim_info: SimInfo=None): + if sim_info is None: + output('Failed, no Sim was specified or the specified Sim was not found!') + return + if not first_name: + output(f'Failed, \'{first_name}\' is not a valid first name.') + return + first_name = CommonTextUtils.capitalize(first_name) + output(f'Setting the first name of Sim {sim_info} to {first_name}') + CommonSimNameUtils.set_first_name(sim_info, first_name) + + +@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.randomize_first_name', 'Randomize the first name of a Sim.', command_arguments=( + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to change the first name of.'), + CommonConsoleCommandArgument('sim_name_type', 'CommonSimNameType', f'Determines from which list of names to randomize the name from. Valid Values: {CommonSimNameType.get_comma_separated_names_string()}'), +)) +def _common_randomize_first_name(output: CommonConsoleCommandOutput, sim_info: SimInfo=None, sim_name_type: CommonSimNameType=CommonSimNameType.DEFAULT): + if sim_info is None: + output('Failed, no Sim was specified or the specified Sim was not found!') + return + gender = CommonGender.get_gender(sim_info) + species = CommonSpecies.get_species(sim_info) + first_name = CommonSimNameUtils.create_random_first_name(gender, species=species, sim_name_type=sim_name_type) + first_name = CommonTextUtils.capitalize(first_name) + output(f'Setting the first name of Sim {sim_info} to {first_name}') + CommonSimNameUtils.set_first_name(sim_info, first_name) + + +@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.set_last_name', 'Set the last name of a Sim.', command_arguments=( + CommonConsoleCommandArgument('last_name', 'Text', 'The last name to give to the Sim.'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to change the last name of.'), +)) +def _common_set_last_name(output: CommonConsoleCommandOutput, last_name: str, sim_info: SimInfo=None): + if sim_info is None: + output('Failed, no Sim was specified or the specified Sim was not found!') + return + last_name = CommonTextUtils.capitalize(last_name) + output(f'Setting the last name of Sim {sim_info} to {last_name}') + CommonSimNameUtils.set_last_name(sim_info, last_name) + + +@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.randomize_last_name', 'Randomize the last name of a Sim.', command_arguments=( + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to change the last name of.'), + CommonConsoleCommandArgument('sim_name_type', 'CommonSimNameType', f'Determines from which list of names to randomize the name from. Valid Values: {CommonSimNameType.get_comma_separated_names_string()}'), +)) +def _common_randomize_last_name(output: CommonConsoleCommandOutput, sim_info: SimInfo=None, sim_name_type: CommonSimNameType=CommonSimNameType.DEFAULT): + if sim_info is None: + output('Failed, no Sim was specified or the specified Sim was not found!') + return + gender = CommonGender.get_gender(sim_info) + species = CommonSpecies.get_species(sim_info) + last_name = CommonSimNameUtils.create_random_last_name(gender, species=species, sim_name_type=sim_name_type) + last_name = CommonTextUtils.capitalize(last_name) + output(f'Setting the last name of Sim {sim_info} to {last_name}') + CommonSimNameUtils.set_last_name(sim_info, last_name) + + +@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.set_name', 'Set the full name of a Sim.', command_arguments=( + CommonConsoleCommandArgument('first_name', 'Text', 'The first name to give to the Sim.'), + CommonConsoleCommandArgument('last_name', 'Text', 'The last name to give to the Sim.'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to change the first and last name of.'), +)) +def _common_set_name(output: CommonConsoleCommandOutput, first_name: str, last_name: str, sim_info: SimInfo=None): + if sim_info is None: + output('Failed, no Sim was specified or the specified Sim was not found!') + return + if not first_name: + output(f'Failed, \'{first_name}\' is not a valid first name.') + return + if not last_name: + output(f'Failed, \'{last_name}\' is not a valid last name.') + return + first_name = CommonTextUtils.capitalize(first_name) + last_name = CommonTextUtils.capitalize(last_name) + output(f'Setting the name of Sim {sim_info} to {first_name} {last_name}') + CommonSimNameUtils.set_first_name(sim_info, first_name) + CommonSimNameUtils.set_last_name(sim_info, last_name) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_occult_type_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_occult_type_utils.py new file mode 100644 index 0000000..384a42a --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_occult_type_utils.py @@ -0,0 +1,265 @@ +""" +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 +""" +from typing import Iterator, Union, Dict, Callable + +from sims.occult.occult_enums import OccultType +from sims.sim_info import SimInfo +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.enums.common_occult_type import CommonOccultType +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + CommonConsoleCommandArgument +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils + + +class CommonSimOccultTypeUtils: + """Utilities for determining the type of Occult a Sim is. i.e. Alien, Vampire, Ghost, etc. + + """ + @staticmethod + def get_all_occult_types_for_sim_gen(sim_info: SimInfo) -> Iterator[CommonOccultType]: + """get_all_occult_types_for_sim_gen(sim_info) + + Retrieve a generator of CommonOccultType for all Occults of a Sim. + + .. note:: Results include the occult type of the sim_info specified.\ + If they are Human by default, the Human occult type will be included. + + :param sim_info: The Sim to locate the Occults of. + :type sim_info: SimInfo + :return: An iterator of Occult Types for all occults of the Sim. + :rtype: Iterator[CommonOccultType] + """ + if sim_info is None: + return tuple() + yield CommonOccultType.NON_OCCULT + for occult_type in CommonOccultType.get_all(exclude_occult_types=(CommonOccultType.NONE, CommonOccultType.NON_OCCULT)): + if CommonSimOccultTypeUtils.is_occult_type(sim_info, occult_type): + yield occult_type + + @staticmethod + def has_any_occult(sim_info: SimInfo) -> bool: + """has_any_occult(sim_info) + + Determine if a Sim has any Occult Types. (Not including NON_OCCULT) + + :param sim_info: The Sim to locate the Occults of. + :type sim_info: SimInfo + :return: True, if the specified Sim has any Non-Human Occult Types. False, if not. + :rtype: bool + """ + for occult_type in CommonSimOccultTypeUtils.get_all_occult_types_for_sim_gen(sim_info): + if occult_type in (CommonOccultType.NONE, CommonOccultType.NON_OCCULT): + continue + return True + return False + + @staticmethod + def is_occult_type(sim_info: SimInfo, occult_type: CommonOccultType) -> CommonTestResult: + """is_occult_type(sim_info, occult_type) + + Determine if a Sim is an Occult Type. + + .. note:: To check if a Sim is currently an occult type use :func:`~is_currently_occult_type` instead. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param occult_type: The Occult Type to check. + :type occult_type: OccultType + :return: The result of the test. True, if the Sim is the specified Occult Type. False, if not. + :rtype: CommonTestResult + """ + if occult_type == CommonOccultType.NONE: + raise AssertionError('Cannot check if Sim is a NONE occult!'.format(CommonSimNameUtils.get_full_name(sim_info))) + if occult_type == CommonOccultType.NON_OCCULT: + # Every Sim is always a Non-Occult + return CommonTestResult.TRUE + from sims4communitylib.utils.sims.common_occult_utils import CommonOccultUtils + occult_type_mappings: Dict[CommonOccultType, Callable[[SimInfo], CommonTestResult]] = { + CommonOccultType.ALIEN: CommonOccultUtils.is_alien, + CommonOccultType.MERMAID: CommonOccultUtils.is_mermaid, + CommonOccultType.ROBOT: CommonOccultUtils.is_robot, + CommonOccultType.SCARECROW: CommonOccultUtils.is_scarecrow, + CommonOccultType.SKELETON: CommonOccultUtils.is_skeleton, + CommonOccultType.VAMPIRE: CommonOccultUtils.is_vampire, + CommonOccultType.WITCH: CommonOccultUtils.is_witch, + CommonOccultType.PLANT_SIM: CommonOccultUtils.is_plant_sim, + CommonOccultType.GHOST: CommonOccultUtils.is_ghost, + CommonOccultType.WEREWOLF: CommonOccultUtils.is_werewolf + } + if occult_type not in occult_type_mappings: + return CommonTestResult(False, reason=f'A check for the specified occult type was not found. {occult_type}.') + return occult_type_mappings[occult_type](sim_info) + + @staticmethod + def is_currently_occult_type(sim_info: SimInfo, occult_type: CommonOccultType) -> CommonTestResult: + """is_currently_occult_type(sim_info, occult_type) + + Determine if a Sim is currently an Occult Type. + + .. note:: To check if a Sim is an occult type (Whether current or not) use :func:`~is_occult_type` instead. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param occult_type: The Occult Type to check. + :type occult_type: OccultType + :return: True, if the Sim is currently the specified Occult Type. False, if not. + :rtype: bool + """ + if occult_type == CommonOccultType.NONE: + raise AssertionError('Cannot check if Sim is currently a NONE occult!'.format(CommonSimNameUtils.get_full_name(sim_info))) + from sims4communitylib.utils.sims.common_occult_utils import CommonOccultUtils + occult_type_mappings: Dict[CommonOccultType, Callable[[SimInfo], CommonTestResult]] = { + CommonOccultType.ALIEN: CommonOccultUtils.is_currently_an_alien, + CommonOccultType.MERMAID: CommonOccultUtils.is_currently_a_mermaid, + CommonOccultType.ROBOT: CommonOccultUtils.is_currently_a_robot, + CommonOccultType.SCARECROW: CommonOccultUtils.is_currently_a_scarecrow, + CommonOccultType.SKELETON: CommonOccultUtils.is_currently_a_skeleton, + CommonOccultType.VAMPIRE: CommonOccultUtils.is_currently_a_vampire, + CommonOccultType.WITCH: CommonOccultUtils.is_currently_a_witch, + CommonOccultType.PLANT_SIM: CommonOccultUtils.is_currently_a_plant_sim, + CommonOccultType.GHOST: CommonOccultUtils.is_currently_a_ghost, + CommonOccultType.WEREWOLF: CommonOccultUtils.is_currently_a_werewolf + } + if occult_type not in occult_type_mappings: + return CommonTestResult(False, reason=f'A check for the specified occult type was not found. {occult_type}.') + return occult_type_mappings[occult_type](sim_info) + + @staticmethod + def determine_occult_type(sim_info: SimInfo) -> CommonOccultType: + """determine_occult_type(sim_info) + + Determine the type of Occult a Sim is. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The CommonOccultType that represents what a Sim is. + :rtype: CommonOccultType + """ + from sims4communitylib.utils.sims.common_occult_utils import CommonOccultUtils + if CommonOccultUtils.is_robot(sim_info): + return CommonOccultType.ROBOT + elif CommonOccultUtils.is_scarecrow(sim_info): + return CommonOccultType.SCARECROW + elif CommonOccultUtils.is_skeleton(sim_info): + return CommonOccultType.SKELETON + elif CommonOccultUtils.is_alien(sim_info): + return CommonOccultType.ALIEN + elif CommonOccultUtils.is_ghost(sim_info): + return CommonOccultType.GHOST + elif CommonOccultUtils.is_mermaid(sim_info): + return CommonOccultType.MERMAID + elif CommonOccultUtils.is_plant_sim(sim_info): + return CommonOccultType.PLANT_SIM + elif CommonOccultUtils.is_vampire(sim_info): + return CommonOccultType.VAMPIRE + elif CommonOccultUtils.is_witch(sim_info): + return CommonOccultType.WITCH + elif CommonOccultUtils.is_werewolf(sim_info): + return CommonOccultType.WEREWOLF + return CommonOccultType.NON_OCCULT + + @staticmethod + def determine_current_occult_type(sim_info: SimInfo) -> CommonOccultType: + """determine_current_occult_type(sim_info) + + Determine the type of Occult a Sim is currently appearing as. + i.e. A mermaid with their tail out would currently be a MERMAID. But a Mermaid Sim with no tail out would currently be a CommonOccultType.NONE + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The CommonOccultType the Sim is currently appearing as, or CommonOccultType.NONE if they are not appearing as any Occult or are appearing as their HUMAN disguise/occult. + :rtype: CommonOccultType + """ + from sims4communitylib.utils.sims.common_occult_utils import CommonOccultUtils + if CommonOccultUtils.is_currently_a_mermaid(sim_info) or CommonOccultUtils.is_mermaid_in_mermaid_form(sim_info): + return CommonOccultType.MERMAID + elif CommonOccultUtils.is_robot(sim_info): + return CommonOccultType.ROBOT + elif CommonOccultUtils.is_currently_a_scarecrow(sim_info): + return CommonOccultType.SCARECROW + elif CommonOccultUtils.is_currently_a_vampire(sim_info): + return CommonOccultType.VAMPIRE + elif CommonOccultUtils.is_currently_a_werewolf(sim_info): + return CommonOccultType.WEREWOLF + elif CommonOccultUtils.is_currently_a_witch(sim_info): + return CommonOccultType.WITCH + elif CommonOccultUtils.is_currently_an_alien(sim_info): + return CommonOccultType.ALIEN + elif CommonOccultUtils.is_plant_sim(sim_info): + return CommonOccultType.PLANT_SIM + elif CommonOccultUtils.is_ghost(sim_info): + return CommonOccultType.GHOST + elif CommonOccultUtils.is_skeleton(sim_info): + return CommonOccultType.SKELETON + return CommonOccultType.NON_OCCULT + + @staticmethod + def convert_to_vanilla(occult_type: 'CommonOccultType') -> Union[OccultType, None]: + """convert_to_vanilla(occult_type) + + Convert CommonOccultType into OccultType. + + .. note:: Not all CommonOccultTypes have an OccultType to convert to! They will return None in those cases! (Ghost, Plant Sim, Robot, Skeleton) + + :param occult_type: An instance of a CommonOccultType + :type occult_type: CommonOccultType + :return: The specified CommonOccultType translated to OccultType, or None if the value could not be translated. + :rtype: Union[OccultType, None] + """ + return CommonSimOccultTypeUtils.convert_custom_type_to_vanilla(occult_type) + + @staticmethod + def convert_custom_type_to_vanilla(occult_type: 'CommonOccultType') -> Union[OccultType, None]: + """convert_custom_type_to_vanilla(occult_type) + + Convert a CommonOccultType into OccultType. + + .. note:: Not all CommonOccultType values have a matching OccultType! None will be returned in these cases! (Ghost, Plant Sim, Robot, Skeleton) + + :param occult_type: An instance of a CommonOccultType + :type occult_type: CommonOccultType + :return: The specified CommonOccultType translated to OccultType, or None if the value could not be translated. + :rtype: Union[OccultType, None] + """ + if occult_type is None or occult_type == CommonOccultType.NONE: + return None + if isinstance(occult_type, OccultType): + return occult_type + conversion_mapping: Dict[CommonOccultType, OccultType] = { + CommonOccultType.NON_OCCULT: OccultType.HUMAN, + CommonOccultType.ALIEN: OccultType.ALIEN if hasattr(OccultType, 'ALIEN') else None, + CommonOccultType.MERMAID: OccultType.MERMAID if hasattr(OccultType, 'MERMAID') else None, + CommonOccultType.VAMPIRE: OccultType.VAMPIRE if hasattr(OccultType, 'VAMPIRE') else None, + CommonOccultType.WITCH: OccultType.WITCH if hasattr(OccultType, 'WITCH') else None, + CommonOccultType.WEREWOLF: OccultType.WEREWOLF if hasattr(OccultType, 'WEREWOLF') else None + } + return conversion_mapping.get(occult_type, None) + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.print_custom_occults', + 'Print a list of all custom CommonOccultTypes a Sim has.', + command_arguments=( + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance Id or name of the Sim to print the occult types of.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.printcustomoccults', + ) +) +def _common_print_custom_occult_types_for_sim(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): + if sim_info is None: + return + occult_types_str = ', '.join([occult_type.name if hasattr(occult_type, 'name') else str(occult_type) for occult_type in CommonSimOccultTypeUtils.get_all_occult_types_for_sim_gen(sim_info)]) + output(f'Occult Types: {occult_types_str}') + current_occult_type = CommonSimOccultTypeUtils.determine_current_occult_type(sim_info) + current_occult_type_str = current_occult_type.name if hasattr(current_occult_type, 'name') else str(current_occult_type) + output(f'Current Occult Type: {current_occult_type_str}') diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_plumbob_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_plumbob_utils.py new file mode 100644 index 0000000..7cdb2d5 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_plumbob_utils.py @@ -0,0 +1,143 @@ +""" +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 +""" +from interactions.utils.plumbbob import unslot_plumbbob, reslot_plumbbob +from sims.sim_info import SimInfo +from sims4communitylib.classes.math.common_vector3 import CommonVector3 +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + CommonConsoleCommandArgument +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + + +class CommonSimPlumbobSlot: + """CommonSimPlumbobSlot(offset_position, bone_name='b__ROOT__', balloon_offset_position=CommonVector3.empty()) + + Used to place a Plumbob. + + :param offset_position: The position of the plumbob. + :type offset_position: CommonVector3 + :param bone_name: The name of the bone to slot the Plumbob to. Default is 'b__ROOT__' + :type bone_name: str, optional + :param balloon_offset_position: The position of the Balloon above Sims heads. Default is CommonVector3.empty(). + :type balloon_offset_position: CommonVector3, optional + """ + def __init__(self, offset_position: CommonVector3, bone_name: str='b__ROOT__', balloon_offset_position: CommonVector3=CommonVector3.empty()): + self._offset_position = offset_position + self._bone_name = bone_name + self._balloon_offset_position = balloon_offset_position + + @property + def bone_name(self) -> str: + """ The name of a Bone. + + :return: The name of a Bone. + :rtype: str + """ + return self._bone_name + + @property + def offset(self) -> CommonVector3: + """ The offset position of the Plumbob. + + :return: The offset of the Plumbob + :rtype: CommonVector3 + """ + return self._offset_position + + @property + def balloon_offset(self) -> CommonVector3: + """ The offset position of the Balloon. + + :return: The offset of the Balloon + :rtype: CommonVector3 + """ + return self._balloon_offset_position + + +class CommonSimPlumbobUtils: + """ Utilities for manipulating the Plumbob of a Sim. """ + @staticmethod + def hide_plumbob(sim_info: SimInfo): + """hide_plumbob(sim_info) + + Hide the plumbob of a Sim. + + .. note:: If the plumbob of the Sim is already hidden, this function will do nothing. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + """ + CommonSimPlumbobUtils.set_plumbob_position(sim_info, CommonVector3(-1000, -1000, -1000)) + + @staticmethod + def show_plumbob(sim_info: SimInfo): + """show_plumbob(sim_info) + + Show the plumbob of a Sim. + + .. note:: If the plumbob of the Sim is already shown, this function will do nothing. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + """ + CommonSimPlumbobUtils.reset_plumbob_position(sim_info) + + @staticmethod + def set_plumbob_position(sim_info: SimInfo, position: CommonVector3, bone_name: str='b__ROOT__', balloon_position: CommonVector3=CommonVector3.empty()): + """set_plumbob_position(sim_info, position, bone_name='b__ROOT__', balloon_position=CommonVector3.empty()) + + Set the position of the Plumbob for a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param position: The position to set the plumbob to. + :type position: CommonVector3 + :param bone_name: The name of the bone to slot the Plumbob to. Default is 'b__ROOT__' + :type bone_name: str, optional + :param balloon_position: The position of the Balloon above Sims heads. Default is CommonVector3.empty(). + :type balloon_position: CommonVector3, optional + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return + reslot_plumbbob(sim, CommonSimPlumbobSlot(position, bone_name=bone_name, balloon_offset_position=balloon_position)) + + @staticmethod + def reset_plumbob_position(sim_info: SimInfo): + """reset_plumbob_position(sim_info) + + Reset the position of the Plumbob for a Sim to it's original position. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return + unslot_plumbbob(sim) + + +@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.hide_plumbob', 'Hide the plumbob above a Sim.', command_arguments=( + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to hide the plumbob of.', is_optional=True, default_value='Active Sim'), +)) +def _common_hide_plumbob(output: CommonConsoleCommandOutput, sim_info: SimInfo=None): + if sim_info is None: + return + output(f'Hiding plumbob for Sim {sim_info}') + CommonSimPlumbobUtils().hide_plumbob(sim_info) + + +@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.show_plumbob', 'Show the plumbob above a Sim.', command_arguments=( + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to show the plumbob of.', is_optional=True, default_value='Active Sim'), +)) +def _common_show_plumbob(output: CommonConsoleCommandOutput, sim_info: SimInfo=None): + if sim_info is None: + return + output(f'Showing plumbob for Sim {sim_info}') + CommonSimPlumbobUtils().show_plumbob(sim_info) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_posture_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_posture_utils.py new file mode 100644 index 0000000..0a7db1d --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_posture_utils.py @@ -0,0 +1,266 @@ +""" +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 +""" +from typing import Tuple, Union, Any + +from postures.posture import Posture +from postures.posture_state import PostureState +from sims.sim_info import SimInfo +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.enums.common_posture_id import CommonPostureId +from sims4communitylib.enums.enumtypes.common_int import CommonInt +from sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + + +class CommonSimPostureUtils(_HasS4CLClassLog): + """Utilities for managing the posture of Sims.""" + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 'common_sim_posture_utils' + + @classmethod + def has_posture(cls, sim_info: SimInfo, posture: Union[int, CommonPostureId, Posture, CommonInt]) -> CommonTestResult: + """has_posture(sim_info, posture) + + Determine if a Sim has a posture. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param posture: The identifier of the posture to check. + :type posture: Union[int, CommonPostureId, Posture, CommonInt] + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return CommonTestResult(False, reason=f'Posture test failed because the {sim_info} is non-instantiated.') + posture_instance = cls.load_posture_by_id(posture) + if posture_instance is None: + return CommonTestResult(False, reason=f'No posture was found with id.') + for aspect in cls.get_posture_aspects(sim_info): + if not posture_instance.multi_sim and aspect.posture_type is posture_instance: + return CommonTestResult.TRUE + return CommonTestResult(False, reason=f'{sim_info} does not have posture {posture_instance}.') + + @classmethod + def has_posture_with_sim(cls, sim_info: SimInfo, target_sim_info: SimInfo, posture: Union[int, CommonPostureId, Posture, CommonInt]) -> CommonTestResult: + """has_posture_with_sim(sim_info, target_sim_info, posture) + + Determine if a Sim has a posture with another Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param target_sim_info: An instance of another Sim. + :type target_sim_info: SimInfo + :param posture: The identifier of the posture to check. + :type posture: Union[int, CommonPostureId, Posture, CommonInt] + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return CommonTestResult(False, reason=f'Posture test failed because the {sim_info} is non-instantiated.') + target_sim = CommonSimUtils.get_sim_instance(target_sim_info) + if target_sim is None: + return CommonTestResult(False, reason=f'Posture test failed because the {target_sim_info} is non-instantiated.') + posture_instance = cls.load_posture_by_id(posture) + if posture_instance is None: + return CommonTestResult(False, reason=f'No posture was found with id.') + for aspect in cls.get_posture_aspects(sim_info): + if aspect.posture_type is posture_instance and (not posture_instance.multi_sim or aspect.linked_sim is target_sim): + break + return CommonTestResult(False, reason=f'{sim_info} does not have posture {posture_instance}.') + + @classmethod + def can_sim_be_picked_up(cls, sim_info: SimInfo) -> CommonTestResult: + """can_be_picked_up(sim_info) + + Determine if a Sim can be picked up. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: True, if the Sim can be picked up. False, it not. + :rtype: bool + """ + from sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils + from sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils + if CommonSpeciesUtils.is_fox(sim_info) or CommonSpeciesUtils.is_small_dog(sim_info) or CommonSpeciesUtils.is_cat(sim_info): + cls.get_log().format_with_message('Success, Sim is a fox, small dog, or cat and thus may be picked up.', sim=sim_info) + return CommonTestResult.TRUE + if CommonSpeciesUtils.is_animal(sim_info) and CommonAgeUtils.is_child(sim_info): + cls.get_log().format_with_message('Success, Sim is a child animal and thus may be picked up.', sim=sim_info) + return CommonTestResult.TRUE + if CommonSpeciesUtils.is_human(sim_info) and (CommonAgeUtils.is_toddler(sim_info) or CommonAgeUtils.is_baby(sim_info)): + cls.get_log().format_with_message('Success, Sim is a toddler or baby human and thus may be picked up.', sim=sim_info) + return CommonTestResult.TRUE + from sims4communitylib.enums.strings_enum import CommonStringId + return CommonTestResult(False, reason=f'{sim_info} cannot be picked up.', tooltip_text=CommonStringId.S4CL_SIM_CANNOT_BE_PICKED_UP, tooltip_tokens=(sim_info,)) + + @classmethod + def is_on_container_supporting_posture(cls, sim_info: SimInfo, posture: Union[int, CommonPostureId, Posture, CommonInt]) -> CommonTestResult: + """is_on_container_supporting_posture(sim_info, posture) + + Determine if the container a Sim is interacting with has a posture. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param posture: The identifier of the posture to check. + :type posture: Union[int, CommonPostureId, Posture, CommonInt] + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return CommonTestResult(False, reason=f'Posture test failed because the {sim_info} is non-instantiated.') + posture_instance = cls.load_posture_by_id(posture) + if posture_instance is None: + return CommonTestResult(False, reason=f'No posture was found with id.') + container = cls.get_posture_target(sim_info) + if container is None or not container.is_part: + sim_posture = cls.get_posture(sim_info) + return CommonTestResult(False, reason=f'Posture container for {sim_posture} is None or not a part') + parts = {container} + parts.update(container.get_overlapping_parts()) + for container_part in parts: + if container_part.supports_posture_type(posture_instance): + return CommonTestResult.TRUE + return CommonTestResult(False, reason=f'Posture container {container} does not support {posture_instance}') + + @classmethod + def is_on_container_supporting_posture_with_sim(cls, sim_info: SimInfo, target_sim_info: SimInfo, posture: Union[int, CommonPostureId, Posture, CommonInt]) -> CommonTestResult: + """is_on_container_supporting_posture(sim_info, target_sim_info, posture) + + Determine if the container a Sim is interacting with has a posture that supports another Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param target_sim_info: An instance of another Sim. + :type target_sim_info: SimInfo + :param posture: The identifier of the posture to check. + :type posture: Union[int, CommonPostureId, Posture, CommonInt] + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return CommonTestResult(False, reason=f'Posture test failed because the {sim_info} is non-instantiated.') + target_sim = CommonSimUtils.get_sim_instance(target_sim_info) + if target_sim is None: + return CommonTestResult(False, reason=f'Posture test failed because the {target_sim_info} is non-instantiated.') + posture_instance = cls.load_posture_by_id(posture) + if posture_instance is None: + return CommonTestResult(False, reason=f'No posture was found with id.') + container = cls.get_posture_target(sim_info) + if container is None or not container.is_part: + sim_posture = cls.get_posture(sim_info) + return CommonTestResult(False, reason=f'Posture container for {sim_posture} is None or not a part') + parts = {container} + parts.update(container.get_overlapping_parts()) + if not any(container_parts.supports_posture_type(posture_instance) for container_parts in parts): + return CommonTestResult(False, reason=f'Posture container {container} does not support {posture_instance}') + if posture_instance.multi_sim: + if target_sim is None: + return CommonTestResult(False, reason=f'Posture test failed because the target is None') + if target_sim is None: + return CommonTestResult(False, reason=f'Posture test failed because the target is non-instantiated.') + if not container.has_adjacent_part(target_sim): + return CommonTestResult(False, reason=f'Posture container {container} requires an adjacent part for {target_sim} since {posture_instance} is multi-Sim') + return CommonTestResult.TRUE + + @classmethod + def get_posture_target(cls, sim_info: SimInfo) -> Union[Any, None]: + """get_posture_target(sim_info) + + Retrieve the target of the posture of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The target of the posture of a Sim. + :rtype: Union[Any, None] + """ + posture = cls.get_posture(sim_info) + if posture is None: + return None + return posture.target + + @classmethod + def get_posture(cls, sim_info: SimInfo) -> Union[Posture, None]: + """get_posture(sim_info) + + Retrieve the posture of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The posture of a Sim. + :rtype: Union[Posture, None] + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return None + return sim.posture + + @classmethod + def get_posture_aspects(cls, sim_info: SimInfo) -> Tuple[Posture]: + """get_posture_aspects(sim_info) + + Retrieve the posture aspects of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The aspects of the posture of the Sim. + :rtype: Tuple[Posture] + """ + posture_state = cls.get_posture_state(sim_info) + if posture_state is None: + return tuple() + return posture_state.aspects + + @classmethod + def get_posture_state(cls, sim_info: SimInfo) -> Union[PostureState, None]: + """get_posture_state(sim_info) + + Retrieve the posture aspects of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The posture state of a Sim. + :rtype: Union[PostureState, None] + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return None + # noinspection PyPropertyAccess + return sim.posture_state + + @classmethod + def load_posture_by_id(cls, posture: Union[int, CommonPostureId, Posture, CommonInt]) -> Union[Posture, None]: + """load_posture_by_id(posture) + + Load an instance of a Posture by its identifier. + + :param posture: The identifier of a Posture. + :type posture: Union[int, CommonPostureId, Posture, CommonInt] + :return: An instance of a Posture matching the decimal identifier or None if not found. + :rtype: Union[Posture, None] + """ + if isinstance(posture, Posture): + return posture + # noinspection PyBroadException + try: + # noinspection PyCallingNonCallable + posture_instance = posture() + if isinstance(posture_instance, Posture): + # noinspection PyTypeChecker + return posture + except: + pass + # noinspection PyBroadException + try: + posture: int = int(posture) + except: + # noinspection PyTypeChecker + posture: Posture = posture + return posture + + from sims4.resources import Types + from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + return CommonResourceUtils.load_instance(Types.POSTURE, posture) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_pregnancy_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_pregnancy_utils.py new file mode 100644 index 0000000..4198a3b --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_pregnancy_utils.py @@ -0,0 +1,622 @@ +""" +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 +""" +from typing import Union +from sims.pregnancy.pregnancy_enums import PregnancyOrigin +from sims.pregnancy.pregnancy_tracker import PregnancyTracker +from sims.sim_info import SimInfo +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.enums.buffs_enum import CommonBuffId +from sims4communitylib.enums.common_object_state_value_ids import CommonObjectStateValueId +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.enums.traits_enum import CommonTraitId +from sims4communitylib.logging.has_class_log import HasClassLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + CommonConsoleCommandArgument +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.objects.common_object_state_utils import CommonObjectStateUtils +from sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils +from sims4communitylib.utils.sims.common_buff_utils import CommonBuffUtils +from sims4communitylib.utils.sims.common_relationship_utils import CommonRelationshipUtils +from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils +from sims4communitylib.enums.statistics_enum import CommonStatisticId +from sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils +from sims4communitylib.utils.sims.common_sim_statistic_utils import CommonSimStatisticUtils +from statistics.commodity import Commodity + + +class CommonSimPregnancyUtils(HasClassLog): + """Utilities for manipulating the pregnancy status of Sims. + + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + return ModInfo.get_identity() + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 'common_sim_pregnancy_utils' + + @classmethod + def is_pregnant(cls, sim_info: SimInfo) -> bool: + """is_pregnant(sim_info) + + Determine if the a Sim is pregnant. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the specified Sim is pregnant. False, if not. + :rtype: bool + """ + pregnancy_tracker = cls._get_pregnancy_tracker(sim_info) + if pregnancy_tracker is None: + return False + return pregnancy_tracker.is_pregnant + + @classmethod + def has_permission_for_pregnancies(cls, sim_info: SimInfo) -> CommonTestResult: + """has_permission_for_pregnancies(sim_info) + + Determine if a Sim has the permissions to cause a Pregnancy or to become Pregnant. (Regardless of traits) + + .. note:: In the vanilla game, only Adult and Elder Sims have permission for pregnancies. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of the test. True, if the test passes. False, if the test fails. + :rtype: CommonTestResult + """ + if CommonAgeUtils.is_adult_or_elder(sim_info): + return CommonTestResult(True, reason=f'{sim_info} has permission to engage in pregnancy. They are either an Adult or an Elder Sim.') + return CommonTestResult(False, reason=f'{sim_info} does not have permission to engage in pregnancy. They are neither an Adult nor an Elder Sim.') + + @classmethod + def has_permission_for_pregnancies_with(cls, sim_info_a: SimInfo, sim_info_b: SimInfo) -> CommonTestResult: + """has_permission_for_pregnancies_with(sim_info_a, sim_info_b) + + Determine if Sim A has the permissions to cause a Pregnancy with Sim B or to become pregnant from Sim B. + + .. note:: In the vanilla game, only Adult and Elder Sims of the same species have permission for pregnancies with each other. + + :param sim_info_a: An instance of a Sim. (Sim A) + :type sim_info_a: SimInfo + :param sim_info_b: An instance of a Sim. (Sim B) + :type sim_info_b: SimInfo + :return: The result of the test. True, if the test passes. False, if the test fails. + :rtype: CommonTestResult + """ + sim_a_has_permission = cls.has_permission_for_pregnancies(sim_info_a) + if not sim_a_has_permission: + return CommonTestResult(False, reason=f'{sim_info_a} does not have permission for pregnancies with {sim_info_b}. {sim_a_has_permission}') + sim_b_has_permission = cls.has_permission_for_pregnancies(sim_info_b) + if not sim_b_has_permission: + return CommonTestResult(False, reason=f'{sim_info_a} does not have permission for pregnancies with {sim_info_b}. {sim_b_has_permission}') + if not CommonSpeciesUtils.are_same_species(sim_info_a, sim_info_b): + # If both Sims are dogs, that is an ok combination, even though their species do not match. + if not CommonSpeciesUtils.is_dog(sim_info_a) or not CommonSpeciesUtils.is_dog(sim_info_b): + return CommonTestResult(False, reason=f'{sim_info_a} does not have permission for pregnancies with {sim_info_b}. {sim_info_a} and {sim_info_b} are not the same species.') + romantic_relationships_result = CommonRelationshipUtils.has_permission_for_romantic_relationship_with(sim_info_a, sim_info_b) + if not romantic_relationships_result: + return CommonTestResult(False, reason=f'{sim_info_a} does not have permission for pregnancies with {sim_info_b}. {romantic_relationships_result}') + return CommonTestResult(True, reason=f'{sim_info_a} has permission for pregnancies with {sim_info_b}.') + + @classmethod + def get_pregnancy_partner(cls, sim_info: SimInfo) -> Union[SimInfo, None]: + """get_pregnancy_partner(sim_info) + + Retrieve the Sim that caused a Sim to become pregnant. + + :param sim_info: The Sim to get the partner of. + :type sim_info: SimInfo + :return: The Sim that impregnated the specified Sim or None if not found. + :rtype: Union[SimInfo, None] + """ + pregnancy_tracker = cls._get_pregnancy_tracker(sim_info) + if pregnancy_tracker is None: + return None + partner_sim = pregnancy_tracker.get_partner() + if partner_sim is None: + return None + return CommonSimUtils.get_sim_info(partner_sim) + + @classmethod + def start_pregnancy(cls, 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 = cls._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, single_sim_is_allowed=sim_info is partner_sim_info) + pregnancy_tracker.clear_pregnancy_visuals() + pregnancy_stat = cls.determine_pregnancy_statistic(sim_info) + if pregnancy_stat is not None: + CommonSimStatisticUtils.set_statistic_value(sim_info, pregnancy_stat, 1.0) + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is not None: + CommonObjectStateUtils.set_object_state(sim, CommonObjectStateValueId.PREGNANT_NOT_SHOWING) + return True + + @classmethod + def induce_labor_in_sim(cls, sim_info: SimInfo) -> bool: + """induce_labor(sim_info) + + Induce Labor in a pregnant Sim. + + :param sim_info: The Sim to go into labor. + :type sim_info: SimInfo + :return: True, if labor was induced successfully. False, if not. + """ + if sim_info is None or not cls.is_pregnant(sim_info): + return False + pregnancy_stat = cls.determine_pregnancy_statistic(sim_info) + if pregnancy_stat is not None: + CommonSimStatisticUtils.set_statistic_value(sim_info, pregnancy_stat, 100.0) + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is not None: + CommonObjectStateUtils.set_object_state(sim, CommonObjectStateValueId.PREGNANT_IN_LABOR) + buff_id = cls.get_in_labor_buff(sim_info) + if buff_id != -1: + result = CommonBuffUtils.add_buff(sim_info, buff_id, buff_reason=CommonStringId.S4CL_BUFF_REASON_FROM_DEBUG) + return result.result + return True + + @classmethod + def clear_pregnancy(cls, 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 = cls._get_pregnancy_tracker(sim_info) + if pregnancy_tracker is None: + return False + sim_info.pregnancy_tracker.clear_pregnancy() + pregnancy_stat = cls.determine_pregnancy_statistic(sim_info) + if pregnancy_stat is not None: + CommonSimStatisticUtils.remove_statistic(sim_info, pregnancy_stat) + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is not None: + CommonObjectStateUtils.set_object_state(sim, CommonObjectStateValueId.PREGNANT_NOT_PREGNANT) + return True + + @classmethod + def can_be_impregnated(cls, sim_info: SimInfo) -> CommonTestResult: + """can_be_impregnated(sim_info) + + Determine if a Sim can be impregnated. + + :param sim_info: The Sim being checked. + :type sim_info: SimInfo + :return: The result of testing. True, if they can. False, if they cannot. + :rtype: CommonTestResult + """ + from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils + from sims4communitylib.enums.traits_enum import CommonTraitId + can_be_impregnated_trait = cls.determine_can_be_impregnated_trait(sim_info) + can_not_be_impregnated_trait = cls.determine_can_not_be_impregnated_trait(sim_info) + if can_be_impregnated_trait is None: + return CommonTestResult(False, reason=f'No Can Be Impregnated trait was found for Sim {sim_info}.') + if can_not_be_impregnated_trait is None: + return CommonTestResult(False, reason=f'No Cannot Be Impregnated trait was found for Sim {sim_info}.') + if CommonSpeciesUtils.is_animal(sim_info): + if not CommonSpeciesUtils.is_horse(sim_info): + if CommonTraitUtils.has_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_NOT_REPRODUCE): + return CommonTestResult(False, reason=f'Animal Sim {sim_info} had the Cannot Reproduce trait.') + if not CommonTraitUtils.has_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_REPRODUCE): + return CommonTestResult(False, reason=f'Animal Sim {sim_info} did not have the Can Reproduce trait.') + + if CommonTraitUtils.has_trait(sim_info, can_not_be_impregnated_trait): + return CommonTestResult(False, reason=f'Sim had the Cannot Be Impregnated trait.') + if not CommonTraitUtils.has_trait(sim_info, can_be_impregnated_trait): + return CommonTestResult(False, reason=f'Sim did not have the Can Be Impregnated trait.') + return CommonTestResult(True, reason=f'Sim can be impregnated by other Sims.') + + @classmethod + def can_impregnate(cls, sim_info: SimInfo) -> CommonTestResult: + """can_impregnate(sim_info) + + Determine if a Sim can impregnate other sims. + + :param sim_info: The Sim being checked. + :type sim_info: SimInfo + :return: The result of testing. True, if they can. False, if they cannot. + :rtype: CommonTestResult + """ + from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils + from sims4communitylib.enums.traits_enum import CommonTraitId + can_impregnate_trait = cls.determine_can_impregnate_trait(sim_info) + can_not_impregnate_trait = cls.determine_can_not_impregnate_trait(sim_info) + if can_impregnate_trait is None: + return CommonTestResult(False, reason=f'No Can Impregnate trait was found for Sim {sim_info}.') + if can_not_impregnate_trait is None: + return CommonTestResult(False, reason=f'No Cannot Impregnate trait was found for Sim {sim_info}.') + if CommonSpeciesUtils.is_animal(sim_info): + if not CommonSpeciesUtils.is_horse(sim_info): + if CommonTraitUtils.has_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_NOT_REPRODUCE): + return CommonTestResult(False, reason=f'Sim had the Cannot Reproduce trait.') + if not CommonTraitUtils.has_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_REPRODUCE): + return CommonTestResult(False, reason=f'Sim did not have the Can Reproduce trait.') + + if CommonTraitUtils.has_trait(sim_info, can_not_impregnate_trait): + return CommonTestResult(False, reason=f'Sim had the Cannot Impregnate trait.') + if not CommonTraitUtils.has_trait(sim_info, can_impregnate_trait): + return CommonTestResult(False, reason=f'Sim did not have the Can Impregnate trait') + return CommonTestResult(True, reason=f'Sim can impregnate other Sims.') + + @classmethod + def get_partner_of_pregnant_sim(cls, 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 = cls._get_pregnancy_tracker(sim_info) + if pregnancy_tracker is None: + return None + return pregnancy_tracker.get_partner() + + @classmethod + def set_pregnancy_progress(cls, sim_info: SimInfo, value: float): + """set_pregnancy_progress(sim_info, value) + + Set the pregnancy progress of a Sim. + + :param sim_info: The Sim being checked. + :type sim_info: SimInfo + :param value: The value to set the progress to. + :type value: float + :return: The current progress of the pregnancy of a Sim. + :rtype: float + """ + if value > 100.0: + value = 100.0 + if value < 0.0: + value = 0.0 + pregnancy_tracker = cls._get_pregnancy_tracker(sim_info) + if pregnancy_tracker is None or not cls.is_pregnant(sim_info): + return + 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: Commodity = statistic_tracker.get_statistic(pregnancy_commodity_type, add=False) + if not pregnancy_commodity: + return + pregnancy_commodity.set_value(value) + + @classmethod + def get_pregnancy_progress(cls, 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 = cls._get_pregnancy_tracker(sim_info) + if pregnancy_tracker is None or not cls.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() + + @classmethod + def get_pregnancy_rate(cls, 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 = cls._get_pregnancy_tracker(sim_info) + if pregnancy_tracker is None: + return 0.0 + return pregnancy_tracker.PREGNANCY_RATE + + @classmethod + def get_in_labor_buff(cls, 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] + """ + log = cls.get_log() + 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 + elif CommonSpeciesUtils.is_horse(sim_info): + log.debug('\'{}\' is a Horse.'.format(sim_name)) + if is_female: + log.debug('\'{}\' is Female.'.format(sim_name)) + return CommonBuffId.PREGNANCY_IN_LABOR_PET_HORSE + log.debug('No appropriate Buff located to induce labor in \'{}\'.'.format(sim_name)) + return -1 + + @classmethod + def get_pregnancy_tracker(cls, sim_info: SimInfo) -> Union[PregnancyTracker, None]: + """get_pregnancy_tracker(sim_info) + + Retrieve the tracker for tracking pregnancy of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The pregnancy tracker for the Sim or None if the Sim does not have a pregnancy tracker. + :rtype: Union[PregnancyTracker, None] + """ + return cls._get_pregnancy_tracker(sim_info) + + @classmethod + def _get_pregnancy_tracker(cls, sim_info: SimInfo) -> Union[PregnancyTracker, None]: + if sim_info is None: + return None + return sim_info.pregnancy_tracker + + @classmethod + def determine_pregnancy_statistic(cls, sim_info: SimInfo) -> Union[CommonStatisticId, None]: + """determine_pregnancy_statistic(sim_info) + + Determine the statistic that would indicate the pregnancy progress of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The statistic that would indicate the pregnancy progress of the Sim or None if no trait is found. + :rtype: Union[CommonStatisticId, None] + """ + if CommonSpeciesUtils.is_human(sim_info): + return CommonStatisticId.PREGNANCY + elif CommonSpeciesUtils.is_large_dog(sim_info): + return CommonStatisticId.PREGNANCY_DOG + elif CommonSpeciesUtils.is_small_dog(sim_info): + return CommonStatisticId.PREGNANCY_DOG + elif CommonSpeciesUtils.is_cat(sim_info): + return CommonStatisticId.PREGNANCY_CAT + elif CommonSpeciesUtils.is_fox(sim_info): + return CommonStatisticId.PREGNANCY + elif CommonSpeciesUtils.is_horse(sim_info): + return CommonStatisticId.PREGNANCY_HORSE + return None + + @classmethod + def determine_can_impregnate_trait(cls, sim_info: SimInfo) -> Union[CommonTraitId, None]: + """determine_can_impregnate_trait(sim_info) + + Determine the trait that would indicate a Sim can impregnate other Sims. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The trait that would indicate the Sim can impregnate other Sims or None if no trait is found. + :rtype: Union[CommonTraitId, None] + """ + if CommonSpeciesUtils.is_human(sim_info): + return CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE + elif CommonSpeciesUtils.is_large_dog(sim_info): + return CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_LARGE_DOG + elif CommonSpeciesUtils.is_small_dog(sim_info): + return CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_SMALL_DOG + elif CommonSpeciesUtils.is_cat(sim_info): + return CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_CAT + elif CommonSpeciesUtils.is_fox(sim_info): + return CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_FOX + elif CommonSpeciesUtils.is_horse(sim_info): + return CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_HORSE + return None + + @classmethod + def determine_can_not_impregnate_trait(cls, sim_info: SimInfo) -> Union[CommonTraitId, None]: + """determine_can_not_impregnate_trait(sim_info) + + Determine the trait that would indicate a Sim can not impregnate other Sims. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The trait that would indicate the Sim can not impregnate other Sims or None if no trait is found. + :rtype: Union[CommonTraitId, None] + """ + if CommonSpeciesUtils.is_human(sim_info): + return CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE + elif CommonSpeciesUtils.is_large_dog(sim_info): + return CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_LARGE_DOG + elif CommonSpeciesUtils.is_small_dog(sim_info): + return CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_SMALL_DOG + elif CommonSpeciesUtils.is_cat(sim_info): + return CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_CAT + elif CommonSpeciesUtils.is_fox(sim_info): + return CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_FOX + elif CommonSpeciesUtils.is_horse(sim_info): + return CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_HORSE + return None + + @classmethod + def determine_can_be_impregnated_trait(cls, sim_info: SimInfo) -> Union[CommonTraitId, None]: + """determine_can_be_impregnated_trait(sim_info) + + Determine the trait that would indicate a Sim can be impregnated by other Sims. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The trait that would indicate the Sim can be impregnated by other Sims or None if no trait is found. + :rtype: Union[CommonTraitId, None] + """ + if CommonSpeciesUtils.is_human(sim_info): + return CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED + elif CommonSpeciesUtils.is_large_dog(sim_info): + return CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_LARGE_DOG + elif CommonSpeciesUtils.is_small_dog(sim_info): + return CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_SMALL_DOG + elif CommonSpeciesUtils.is_cat(sim_info): + return CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_CAT + elif CommonSpeciesUtils.is_fox(sim_info): + return CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_FOX + elif CommonSpeciesUtils.is_horse(sim_info): + return CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_HORSE + return None + + @classmethod + def determine_can_not_be_impregnated_trait(cls, sim_info: SimInfo) -> Union[CommonTraitId, None]: + """determine_can_not_be_impregnated_trait(sim_info) + + Determine the trait that would indicate a Sim can not be impregnated by other Sims. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The trait that would indicate the Sim can not be impregnated by other Sims or None if no trait is found. + :rtype: Union[CommonTraitId, None] + """ + if CommonSpeciesUtils.is_human(sim_info): + return CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED + elif CommonSpeciesUtils.is_large_dog(sim_info): + return CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_LARGE_DOG + elif CommonSpeciesUtils.is_small_dog(sim_info): + return CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_SMALL_DOG + elif CommonSpeciesUtils.is_cat(sim_info): + return CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_CAT + elif CommonSpeciesUtils.is_fox(sim_info): + return CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_FOX + elif CommonSpeciesUtils.is_horse(sim_info): + return CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_HORSE + return None + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.print_pregnancy_partner', + 'Print the Sim that got a Sim pregnant. If they are pregnant.', + command_arguments=( + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to change.', is_optional=True, default_value='Active Sim'), + ), +) +def _common_print_pregnancy_partner(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): + if sim_info is None: + return + output(f'Attempting to print the pregnancy partner of {sim_info}.') + partner_sim_info = CommonSimPregnancyUtils.get_pregnancy_partner(sim_info) + if partner_sim_info is None: + output(f'No Sim found to have impregnated {sim_info}.') + else: + output(f'{partner_sim_info} is the Sim that impregnated {sim_info}.') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.stop_pregnancy', + 'End the pregnancy of a Sim. Does your Sim have trouble with pregnancy? Then Stop It!', + command_arguments=( + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to change.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.pregnancy_begone', + ) +) +def _common_command_stop_pregnancy(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): + if sim_info is None: + return + output(f'Attempting to stop the pregnancy of {sim_info}.') + result = CommonSimPregnancyUtils.clear_pregnancy(sim_info) + if result: + output(f'SUCCESS: Successfully stopped the pregnancy of {sim_info}.') + else: + output(f'FAILED: Failed to stop the pregnancy of {sim_info}.') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.set_pregnancy_progress', + 'Set the progress of a Sims pregnancy.', + command_arguments=( + CommonConsoleCommandArgument('value', 'Percentage', 'The percentage of progress.'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to change.', is_optional=True, default_value='Active Sim'), + ), +) +def _common_command_set_pregnancy_progress(output: CommonConsoleCommandOutput, value: float, sim_info: SimInfo = None): + if sim_info is None: + return + output(f'Attempting to set pregnancy progress of {sim_info} to {value}.') + if not CommonSimPregnancyUtils.is_pregnant(sim_info): + output(f'{sim_info} is not pregnant.') + return + CommonSimPregnancyUtils.set_pregnancy_progress(sim_info, value) + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.stop_all_pregnancies', + 'End the pregnancy of all Sims. Wipe away those pregnancies like they never happened.', + command_aliases=( + 's4clib.pregnancies_begone', + ) +) +def _common_command_stop_all_pregnancies(output: CommonConsoleCommandOutput): + output('Attempting to stop the pregnancies of all available Sims. This may take awhile.') + sim_count = 0 + for sim_info in CommonSimUtils.get_instanced_sim_info_for_all_sims_generator(include_sim_callback=CommonSimPregnancyUtils.is_pregnant): + # noinspection PyBroadException + try: + if not CommonSimPregnancyUtils.clear_pregnancy(sim_info): + output(f'FAILED: Failed to stop pregnancy of {sim_info}') + continue + output(f'SUCCESS: Successfully stopped pregnancy of {sim_info}') + sim_count += 1 + except Exception as ex: + output(f'ERROR: Failed to stop the pregnancy of {sim_info}. {ex}') + output(f'Stopped the pregnancies of {sim_count} Sim(s)') diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_rabbit_hole_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_rabbit_hole_utils.py new file mode 100644 index 0000000..677173d --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_rabbit_hole_utils.py @@ -0,0 +1,102 @@ +""" +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 +""" +from typing import Callable, Union + +from rabbit_hole.rabbit_hole import RabbitHole +from services.rabbit_hole_service import RabbitHoleService +from sims.sim_info import SimInfo +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.utils.sims.common_rabbit_hole_utils import CommonRabbitHoleUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + + +class CommonSimRabbitHoleUtils: + """Utilities for manipulating Rabbit Holes for Sims.""" + @classmethod + def get_first_rabbit_hole_id_for_sim(cls, sim_info: SimInfo) -> Union[int, None]: + """get_rabbit_hole_id(sim_info) + + Retrieve the id of the rabbit hole a Sim is in. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The id of the first rabbit hole the Sim is in or None if not found. + :rtype: Union[int, None] + """ + sim_id = CommonSimUtils.get_sim_id(sim_info) + rabbit_hole_service = CommonRabbitHoleUtils.get_rabbit_hole_service() + rabbit_hole_id = rabbit_hole_service.get_head_rabbit_hole_id(sim_id) + if rabbit_hole_id is None or rabbit_hole_id < 0: + return None + return rabbit_hole_id + + @classmethod + def put_sim_into_rabbit_hole(cls, sim_info: SimInfo, rabbit_hole: Union[RabbitHole, int], on_exit_rabbit_hole_callback: Callable[[SimInfo, bool], None] = None) -> CommonTestResult: + """put_sim_into_rabbit_hole(sim_info, rabbit_hole_identifier, on_exit_rabbit_hole_callback=None) + + Put a Sim into a Rabbit Hole. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param rabbit_hole: The identifier of a rabbit hole to put the Sim into. + :type rabbit_hole: Union[RabbitHole, int] + :param on_exit_rabbit_hole_callback: A callback invoked upon the Sim leaving the rabbit hole. Default is None. + :type on_exit_rabbit_hole_callback: Callable[[SimInfo, bool], None] + :return: A result indicating the success of putting the Sim into the rabbit hole. + :rtype: CommonTestResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + rabbit_hole = CommonRabbitHoleUtils.load_rabbit_hole_by_id(rabbit_hole) + if rabbit_hole is None: + return CommonTestResult(False, reason='RabbitHole was None.') + + sim_id = CommonSimUtils.get_sim_id(sim_info) + existing_rabbit_hole_id = cls.get_first_rabbit_hole_id_for_sim(sim_info) + if existing_rabbit_hole_id is not None: + return CommonTestResult(False, reason='Sim is already in a rabbit hole.') + rabbit_hole_service = CommonRabbitHoleUtils.get_rabbit_hole_service() + rabbit_hole_id = rabbit_hole_service.put_sim_in_managed_rabbithole(sim_info, rabbit_hole_type=rabbit_hole) + + if rabbit_hole_id is not None: + if on_exit_rabbit_hole_callback is not None: + def _on_exit_rabbit_hole(canceled: bool = False): + on_exit_rabbit_hole_callback(sim_info, canceled) + rabbit_hole_service.remove_rabbit_hole_expiration_callback(sim_id, rabbit_hole_id, _on_exit_rabbit_hole) + + rabbit_hole_service.set_rabbit_hole_expiration_callback(sim_id, rabbit_hole_id, _on_exit_rabbit_hole) + return CommonTestResult.TRUE + return CommonTestResult(False, reason='Failed to put the Sim into the rabbit hole.') + + @classmethod + def try_remove_sim_from_rabbit_hole(cls, sim_info: SimInfo, on_remove_from_rabbit_hole_result_callback: Callable[[SimInfo, bool], None] = None) -> CommonTestResult: + """try_remove_sim_from_rabbit_hole(sim_info, on_remove_from_rabbit_hole_result_callback=None) + + Remove a Sim from a rabbit hole. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param on_remove_from_rabbit_hole_result_callback: A callback invoked upon the Sim being removed from the rabbit hole. Default is None. + :type on_remove_from_rabbit_hole_result_callback: Callable[[SimInfo, bool], None] + :return: A result indicating the success of the removal. + :rtype: CommonTestResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + existing_rabbit_hold_id = cls.get_first_rabbit_hole_id_for_sim(sim_info) + if existing_rabbit_hold_id is None: + return CommonTestResult.TRUE + rabbit_hole_service: RabbitHoleService = CommonRabbitHoleUtils.get_rabbit_hole_service() + + def _remove_from_rabbit_hole_callback(result: bool): + if on_remove_from_rabbit_hole_result_callback is not None: + on_remove_from_rabbit_hole_result_callback(sim_info, result) + + sim_id = CommonSimUtils.get_sim_id(sim_info) + rabbit_hole_service.try_remove_sim_from_rabbit_hole(sim_id, existing_rabbit_hold_id, callback=_remove_from_rabbit_hole_callback) + return CommonTestResult.TRUE diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_relationship_expectation_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_relationship_expectation_utils.py new file mode 100644 index 0000000..fb38787 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_relationship_expectation_utils.py @@ -0,0 +1,223 @@ +""" +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 +""" +from sims.sim_info import SimInfo +from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.enums.traits_enum import CommonTraitId +from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils + + +class CommonSimRelationshipExpectationUtils: + """ Utilities for Sim relationship expectations. """ + @classmethod + def is_open_to_change(cls, sim_info: SimInfo) -> CommonTestResult: + """is_open_to_change(sim_info) + + Determine if the jealousy triggers of a Sim can be changed through talking. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of the test. True, if the test passes. False, if not. + :rtype: CommonTestResult + """ + if CommonTraitUtils.has_trait(sim_info, CommonTraitId.RELATIONSHIP_EXPECTATIONS_OPEN_TO_CHANGE_NO): + return CommonTestResult(False, reason=f'{sim_info} is not open to relationship expectation changes.') + return CommonTraitUtils.has_trait(sim_info, CommonTraitId.RELATIONSHIP_EXPECTATIONS_OPEN_TO_CHANGE_YES) + + @classmethod + def is_not_open_to_change(cls, sim_info: SimInfo) -> CommonTestResult: + """is_not_open_to_change(sim_info) + + Determine if the jealousy triggers of a Sim can not be changed through talking. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of the test. True, if the test passes. False, if not. + :rtype: CommonTestResult + """ + if CommonTraitUtils.has_trait(sim_info, CommonTraitId.RELATIONSHIP_EXPECTATIONS_OPEN_TO_CHANGE_YES): + return CommonTestResult(False, reason=f'{sim_info} is open to relationship expectation changes.') + return CommonTraitUtils.has_trait(sim_info, CommonTraitId.RELATIONSHIP_EXPECTATIONS_OPEN_TO_CHANGE_NO) + + @classmethod + def set_open_to_change(cls, sim_info: SimInfo, is_open_to_change: bool) -> CommonExecutionResult: + """set_open_to_change(sim_info, is_open_to_change) + + Set if the jealousy triggers of a Sim can be changed through talking. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param is_open_to_change: Set True to indicate a Sim is open to change. Set False, if not. + :type is_open_to_change: bool + :return: The result of the test. True, if the test passes. False, if not. + :rtype: CommonTestResult + """ + if is_open_to_change: + to_remove_trait = CommonTraitId.RELATIONSHIP_EXPECTATIONS_OPEN_TO_CHANGE_NO + to_add_trait = CommonTraitId.RELATIONSHIP_EXPECTATIONS_OPEN_TO_CHANGE_YES + else: + to_remove_trait = CommonTraitId.RELATIONSHIP_EXPECTATIONS_OPEN_TO_CHANGE_YES + to_add_trait = CommonTraitId.RELATIONSHIP_EXPECTATIONS_OPEN_TO_CHANGE_NO + CommonTraitUtils.remove_trait(sim_info, to_remove_trait) + return CommonTraitUtils.add_trait(sim_info, to_add_trait) + + @classmethod + def has_emotional_exclusivity(cls, sim_info: SimInfo) -> CommonTestResult: + """has_emotional_exclusivity(sim_info) + + Determine if the Sim has emotional exclusivity. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of the test. True, if the test passes. False, if not. + :rtype: CommonTestResult + """ + if CommonTraitUtils.has_trait(sim_info, CommonTraitId.RELATIONSHIP_EXPECTATIONS_EMOTIONAL_EXCLUSIVITY_NO): + return CommonTestResult(False, reason=f'{sim_info} does not have emotional exclusivity.') + return CommonTraitUtils.has_trait(sim_info, CommonTraitId.RELATIONSHIP_EXPECTATIONS_EMOTIONAL_EXCLUSIVITY_YES) + + @classmethod + def does_not_have_emotional_exclusivity(cls, sim_info: SimInfo) -> CommonTestResult: + """does_not_have_emotional_exclusivity(sim_info) + + Determine if the Sim does not have emotional exclusivity. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of the test. True, if the test passes. False, if not. + :rtype: CommonTestResult + """ + if CommonTraitUtils.has_trait(sim_info, CommonTraitId.RELATIONSHIP_EXPECTATIONS_EMOTIONAL_EXCLUSIVITY_YES): + return CommonTestResult(False, reason=f'{sim_info} has emotional exclusivity.') + return CommonTraitUtils.has_trait(sim_info, CommonTraitId.RELATIONSHIP_EXPECTATIONS_EMOTIONAL_EXCLUSIVITY_NO) + + @classmethod + def set_emotional_exclusivity(cls, sim_info: SimInfo, has_emotional_exclusivity: bool) -> CommonExecutionResult: + """set_emotional_exclusivity(sim_info, has_emotional_exclusivity) + + Set if a Sim has emotional exclusivity with their partner. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param has_emotional_exclusivity: Set True to indicate a Sim has emotional exclusivity with their partner. Set False, if not. + :type has_emotional_exclusivity: bool + :return: The result of the test. True, if the test passes. False, if not. + :rtype: CommonTestResult + """ + if has_emotional_exclusivity: + to_remove_trait = CommonTraitId.RELATIONSHIP_EXPECTATIONS_EMOTIONAL_EXCLUSIVITY_NO + to_add_trait = CommonTraitId.RELATIONSHIP_EXPECTATIONS_EMOTIONAL_EXCLUSIVITY_YES + else: + to_remove_trait = CommonTraitId.RELATIONSHIP_EXPECTATIONS_EMOTIONAL_EXCLUSIVITY_YES + to_add_trait = CommonTraitId.RELATIONSHIP_EXPECTATIONS_EMOTIONAL_EXCLUSIVITY_NO + CommonTraitUtils.remove_trait(sim_info, to_remove_trait) + return CommonTraitUtils.add_trait(sim_info, to_add_trait) + + @classmethod + def has_physical_exclusivity(cls, sim_info: SimInfo) -> CommonTestResult: + """has_physical_exclusivity(sim_info) + + Determine if the Sim has physical exclusivity. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of the test. True, if the test passes. False, if not. + :rtype: CommonTestResult + """ + if CommonTraitUtils.has_trait(sim_info, CommonTraitId.RELATIONSHIP_EXPECTATIONS_PHYSICAL_EXCLUSIVITY_NO): + return CommonTestResult(False, reason=f'{sim_info} does not have physical exclusivity.') + return CommonTraitUtils.has_trait(sim_info, CommonTraitId.RELATIONSHIP_EXPECTATIONS_PHYSICAL_EXCLUSIVITY_YES) + + @classmethod + def does_not_have_physical_exclusivity(cls, sim_info: SimInfo) -> CommonTestResult: + """does_not_have_physical_exclusivity(sim_info) + + Determine if the Sim does not have physical exclusivity. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of the test. True, if the test passes. False, if not. + :rtype: CommonTestResult + """ + if CommonTraitUtils.has_trait(sim_info, CommonTraitId.RELATIONSHIP_EXPECTATIONS_PHYSICAL_EXCLUSIVITY_YES): + return CommonTestResult(False, reason=f'{sim_info} has physical exclusivity.') + return CommonTraitUtils.has_trait(sim_info, CommonTraitId.RELATIONSHIP_EXPECTATIONS_PHYSICAL_EXCLUSIVITY_NO) + + @classmethod + def set_physical_exclusivity(cls, sim_info: SimInfo, has_physical_exclusivity: bool) -> CommonExecutionResult: + """set_physical_exclusivity(sim_info, has_physical_exclusivity) + + Set if a Sim has physical exclusivity with their partner. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param has_physical_exclusivity: Set True to indicate a Sim has physical exclusivity with their partner. Set False, if not. + :type has_physical_exclusivity: bool + :return: The result of the test. True, if the test passes. False, if not. + :rtype: CommonTestResult + """ + if has_physical_exclusivity: + to_remove_trait = CommonTraitId.RELATIONSHIP_EXPECTATIONS_PHYSICAL_EXCLUSIVITY_NO + to_add_trait = CommonTraitId.RELATIONSHIP_EXPECTATIONS_PHYSICAL_EXCLUSIVITY_YES + else: + to_remove_trait = CommonTraitId.RELATIONSHIP_EXPECTATIONS_PHYSICAL_EXCLUSIVITY_YES + to_add_trait = CommonTraitId.RELATIONSHIP_EXPECTATIONS_PHYSICAL_EXCLUSIVITY_NO + CommonTraitUtils.remove_trait(sim_info, to_remove_trait) + return CommonTraitUtils.add_trait(sim_info, to_add_trait) + + @classmethod + def has_woohoo_exclusivity(cls, sim_info: SimInfo) -> CommonTestResult: + """has_woohoo_exclusivity(sim_info) + + Determine if the Sim has woohoo exclusivity. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of the test. True, if the test passes. False, if not. + :rtype: CommonTestResult + """ + if CommonTraitUtils.has_trait(sim_info, CommonTraitId.RELATIONSHIP_EXPECTATIONS_WOOHOO_EXCLUSIVITY_NO): + return CommonTestResult(False, reason=f'{sim_info} does not have woohoo exclusivity.') + return CommonTraitUtils.has_trait(sim_info, CommonTraitId.RELATIONSHIP_EXPECTATIONS_WOOHOO_EXCLUSIVITY_YES) + + @classmethod + def does_not_have_woohoo_exclusivity(cls, sim_info: SimInfo) -> CommonTestResult: + """does_not_have_woohoo_exclusivity(sim_info) + + Determine if the Sim does not have woohoo exclusivity. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of the test. True, if the test passes. False, if not. + :rtype: CommonTestResult + """ + if CommonTraitUtils.has_trait(sim_info, CommonTraitId.RELATIONSHIP_EXPECTATIONS_WOOHOO_EXCLUSIVITY_YES): + return CommonTestResult(False, reason=f'{sim_info} has woohoo exclusivity.') + return CommonTraitUtils.has_trait(sim_info, CommonTraitId.RELATIONSHIP_EXPECTATIONS_WOOHOO_EXCLUSIVITY_NO) + + @classmethod + def set_woohoo_exclusivity(cls, sim_info: SimInfo, has_woohoo_exclusivity: bool) -> CommonExecutionResult: + """set_woohoo_exclusivity(sim_info, has_woohoo_exclusivity) + + Set if a Sim has woohoo exclusivity with their partner. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param has_woohoo_exclusivity: Set True to indicate a Sim has woohoo exclusivity with their partner. Set False, if not. + :type has_woohoo_exclusivity: bool + :return: The result of the test. True, if the test passes. False, if not. + :rtype: CommonTestResult + """ + if has_woohoo_exclusivity: + to_remove_trait = CommonTraitId.RELATIONSHIP_EXPECTATIONS_WOOHOO_EXCLUSIVITY_NO + to_add_trait = CommonTraitId.RELATIONSHIP_EXPECTATIONS_WOOHOO_EXCLUSIVITY_YES + else: + to_remove_trait = CommonTraitId.RELATIONSHIP_EXPECTATIONS_WOOHOO_EXCLUSIVITY_YES + to_add_trait = CommonTraitId.RELATIONSHIP_EXPECTATIONS_WOOHOO_EXCLUSIVITY_NO + CommonTraitUtils.remove_trait(sim_info, to_remove_trait) + return CommonTraitUtils.add_trait(sim_info, to_add_trait) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_routing_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_routing_utils.py new file mode 100644 index 0000000..4d6ace9 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_routing_utils.py @@ -0,0 +1,123 @@ +""" +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 +""" +from interactions.context import InteractionContext +from objects.terrain import Terrain +from server.pick_info import PickType +from sims.sim_info import SimInfo +from sims4communitylib.classes.math.common_surface_identifier import CommonSurfaceIdentifier +from sims4communitylib.classes.math.common_vector3 import CommonVector3 + +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.utils.common_type_utils import CommonTypeUtils +from sims4communitylib.utils.location.common_location_utils import CommonLocationUtils +from sims4communitylib.utils.location.common_terrain_utils import CommonTerrainUtils +from sims4communitylib.utils.resources.common_interaction_utils import CommonInteractionUtils +from sims4communitylib.utils.sims.common_sim_body_utils import CommonSimBodyUtils +from sims4communitylib.utils.terrain.common_terrain_location_utils import CommonTerrainLocationUtils + + +class CommonSimRoutingUtils: + """ Utilities for manipulating the Routing of Sims. """ + + @staticmethod + def can_route_to_pick_target_of_interaction_context(sim_info: SimInfo, interaction_context: InteractionContext) -> CommonTestResult: + """can_route_to_pick_target_of_interaction_context(sim_info, interaction_context) + + Determine whether a Sim can route to a the picked target of an interaction context or not. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param interaction_context: An interaction context. + :type interaction_context: InteractionContext + :return: The result of running the test. True, if the Sim can route. False, if they cannot route. + :rtype: CommonTestResult + """ + pick_info = CommonInteractionUtils.get_pick_info_from_interaction_context(interaction_context) + if pick_info is None: + return CommonTestResult(False, reason='Missing PickInfo') + if not isinstance(pick_info.pick_type, PickType): + return CommonTestResult(False, reason=f'PickInfo {pick_info} did not have a pick type of type PickType {pick_info.pick_type}') + + pick_target = pick_info.target + if pick_target is None: + position = CommonVector3.from_vector3(pick_info.location) + routing_surface = CommonSurfaceIdentifier.from_surface_identifier(pick_info.routing_surface) + else: + position = CommonVector3.from_vector3(pick_info.location) + routing_surface = CommonSurfaceIdentifier.from_surface_identifier(pick_info.routing_surface) + + if CommonTypeUtils.is_water(pick_target): + swim_at_position_test_result = CommonSimRoutingUtils.can_swim_at_position(sim_info, position, routing_surface) + if not swim_at_position_test_result: + return swim_at_position_test_result + + if position is None or routing_surface is None: + return CommonTestResult(False, reason=f'Failed to locate positional data for pick info {pick_info}.') + + if not CommonLocationUtils.can_position_be_routed_to(position, routing_surface): + return CommonTestResult(False, reason=f'Pick Target cannot be routed to by Sim {sim_info}.') + return CommonTestResult(True, reason=f'Pick Target can be routed to by Sim {sim_info}.') + + @staticmethod + def can_route_to_terrain(sim_info: SimInfo, terrain_object: Terrain) -> CommonTestResult: + """can_route_to_terrain(sim_info, terrain_object) + + Determine whether a Sim can route to a terrain object or not. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param terrain_object: The terrain object to check. + :type terrain_object: Terrain + :return: The result of running the test. True, if the Sim can route. False, if they cannot route. + :rtype: CommonTestResult + """ + position = CommonTerrainLocationUtils.get_position(terrain_object) + routing_surface = CommonTerrainLocationUtils.get_routing_surface(terrain_object) + if position is None or routing_surface is None: + return CommonTestResult(False, reason=f'No position or routing surface found for terrain. {terrain_object}') + + if CommonTypeUtils.is_water(terrain_object): + swim_at_position_test_result = CommonSimRoutingUtils.can_swim_at_position(sim_info, position, routing_surface) + if not swim_at_position_test_result: + return swim_at_position_test_result + if not CommonLocationUtils.can_position_be_routed_to(position, routing_surface): + return CommonTestResult(False, reason=f'Terrain {terrain_object} cannot be routed to by Sim {sim_info}.') + return CommonTestResult(True, reason=f'Terrain {terrain_object} can be routed to by Sim {sim_info}.') + + @staticmethod + def can_swim_at_position(sim_info: SimInfo, position: CommonVector3, routing_surface: CommonSurfaceIdentifier) -> CommonTestResult: + """can_swim_at_position(sim_info, position, routing_surface) + + Determine whether a Sim can swim to a target position or not. + + .. note:: This function assumes the target position is Ocean, a Pond, or a Swimming Pool. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param position: The position to check. + :type position: CommonVector3 + :param routing_surface: The routing surface to check. + :type routing_surface: CommonSurfaceIdentifier + :return: The result of running the test. True, if the Sim can swim at the position. False, if they cannot. + :rtype: CommonTestResult + """ + if position is None or routing_surface is None: + from routing.walkstyle.wading_tests import WadingIntervalTest + water_height = WadingIntervalTest.WATER_DEPTH_ON_LAND + else: + water_height = CommonTerrainUtils.get_water_depth_at(position.x, position.z, surface_level=routing_surface.secondary_id) + + import build_buy + if bool(build_buy.get_pond_id(position)): + (lower_bound, upper_bound) = CommonSimBodyUtils.get_pond_wading_size(sim_info) + else: + (lower_bound, upper_bound) = CommonSimBodyUtils.get_ocean_wading_size(sim_info) + + if water_height <= upper_bound: + return CommonTestResult(False, reason=f'Water is too shallow ({water_height}) for Sim {sim_info} ({lower_bound}, {upper_bound})') + return CommonTestResult(True, reason=f'Sim can swim at position.') diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_situation_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_situation_utils.py new file mode 100644 index 0000000..14b4df9 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_situation_utils.py @@ -0,0 +1,607 @@ +""" +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 +""" +import services +from typing import Callable, Iterator, Union, List, Tuple, Type + +from distributor.shared_messages import IconInfoData +from sims.sim_info import SimInfo +from sims4communitylib.enums.situations_enum import CommonSituationId +from sims4communitylib.enums.tags_enum import CommonGameTag +from sims4communitylib.logging.has_class_log import HasClassLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + CommonConsoleCommandArgument +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from sims4communitylib.utils.resources.common_situation_utils import CommonSituationUtils +from situations.dynamic_situation_goal_tracker import DynamicSituationGoalTracker +from situations.situation import Situation +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from situations.situation_goal import SituationGoal +from situations.situation_goal_targeted_sim import SituationGoalTargetedSim +from situations.situation_goal_tracker import SituationGoalTracker +from situations.situation_guest_list import SituationInvitationPurpose, SituationGuestList, SituationGuestInfo +from situations.situation_job import SituationJob +from whims.whim_set import WhimSetBaseMixin + + +class CommonSimSituationUtils(HasClassLog): + """Utilities for manipulating the Situations of Sims. + + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + return ModInfo.get_identity() + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 'common_sim_situation_utils' + + @staticmethod + def has_situation(sim_info: SimInfo, situation_guid: Union[int, CommonSituationId]) -> bool: + """has_situation(sim_info, situation_guid) + + Determine if a Sim is involved in the specified Situation. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param situation_guid: The GUID of a Situation. + :type situation_guid: Union[int, CommonSituationId] + :return: True, if the Sim is involved in the specified Situation. False, if not. + :rtype: bool + """ + if sim_info is None: + return False + return situation_guid in CommonSimSituationUtils.get_situation_guids(sim_info) + + # noinspection SpellCheckingInspection + @staticmethod + def has_situations(sim_info: SimInfo, situation_guids: Iterator[Union[int, CommonSituationId]]) -> bool: + """has_situations(sim_info, situation_guids) + + Determine if a Sim is involved in any of the specified Situations. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param situation_guids: The GUID of Situations. + :type situation_guids: Iterator[Union[int, CommonSituationId]] + :return: True, if the Sim has any of the specified situations. False, if not. + :rtype: bool + """ + if sim_info is None: + return False + for situation_guid in CommonSimSituationUtils.get_situation_guids(sim_info): + if situation_guid in situation_guids: + return True + return False + + @staticmethod + def has_situation_job(sim_info: SimInfo, situation_job_id: int) -> bool: + """has_situation_job(sim_info, situation_job_id) + + Determine if a Sim has been assigned a situation job. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param situation_job_id: The situation job to check for. + :type situation_job_id: int + :return: True, if the Sim has the specified situation job. False, if not. + :rtype: bool + """ + return CommonSimSituationUtils.has_situation_jobs(sim_info, (situation_job_id,)) + + @staticmethod + def has_situation_jobs(sim_info: SimInfo, situation_job_ids: Tuple[int]) -> bool: + """has_situation_jobs(sim_info, situation_job_ids) + + Determine if a Sim has been assigned any specified situation jobs. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param situation_job_ids: The situation jobs to check for. + :type situation_job_ids: Tuple[int] + :return: True, if the Sim has any of the specified situation jobs. False, if not. + :rtype: bool + """ + sim_situations = CommonSimSituationUtils.get_situations(sim_info) + for situation in sim_situations: + for situation_job in situation.all_jobs_gen(): + situation_job_id = CommonSituationUtils.get_situation_job_guid(situation_job) + if situation_job_id < 0: + continue + if situation_job_id in situation_job_ids: + return True + return False + + @staticmethod + def has_leave_situation(sim_info: SimInfo) -> bool: + """has_situation_jobs(sim_info, situation_job_ids) + + Determine if a Sim is currently involved in a leaving situation. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: True, if the Sim is currently involved in a leaving situation. False, if not. + :rtype: bool + """ + leave_tags: Tuple[CommonGameTag] = (CommonGameTag.ROLE_LEAVE,) + return CommonSimSituationUtils.has_situations(sim_info, (CommonSituationId.LEAVE, )) or CommonSimSituationUtils.is_in_situations_with_any_tags(sim_info, leave_tags) + + @staticmethod + def is_assigned_situation_job(sim_info: SimInfo, situation_job_id: int) -> bool: + """is_assigned_situation_job(sim_info, situation_job_id) + + Determine if a Sim is currently assigned a situation job. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param situation_job_id: The decimal identifier of a Situation Job. + :type situation_job_id: int + :return: True, if the Sim is assigned the specified situation job. False, if not. + :rtype: bool + """ + return CommonSimSituationUtils.is_assigned_situation_jobs(sim_info, (situation_job_id, )) + + @staticmethod + def is_assigned_situation_jobs(sim_info: SimInfo, situation_job_ids: Tuple[int]) -> bool: + """is_assigned_situation_jobs(sim_info, situation_job_ids) + + Determine if a Sim is currently assigned any of the specified situation jobs. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param situation_job_ids: A collection of decimal identifier for Situation Jobs. + :type situation_job_ids: Tuple[int] + :return: True, if the Sim is assigned any of the specified situation jobs. False, if not. + :rtype: bool + """ + sim_situations = CommonSimSituationUtils.get_situations(sim_info) + for situation in sim_situations: + for situation_job in situation.all_jobs_gen(): + situation_job_id = getattr(situation_job, 'guid64', None) + if situation_job_id in situation_job_ids: + return True + return False + + @staticmethod + def is_in_situations_with_tag(sim_info: SimInfo, tag: CommonGameTag) -> bool: + """is_in_situations_with_tag(sim_info, tag) + + Determine if a Sim is currently in a situation with a tag. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param tag: A tag to check for. + :type tag: CommonGameTag + :return: True, if the Sim is involved in any situations with any of the specified tags. False, if not. + :rtype: bool + """ + return CommonSimSituationUtils.is_in_situations_with_any_tags(sim_info, (tag,)) + + @staticmethod + def is_in_situations_with_any_tags(sim_info: SimInfo, tags: Tuple[CommonGameTag]) -> bool: + """is_in_situations_with_any_tags(sim_info, tags) + + Determine if a Sim is currently in a situation with any of the specified tags. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param tags: A collection of game tags. + :type tags: Tuple[CommonGameTag] + :return: True, if the Sim is involved in any situations with any of the specified tags. False, if not. + :rtype: bool + """ + tags = set(tags) + situations = CommonSimSituationUtils.get_situations(sim_info) + for tag in tags: + for situation in situations: + if tag in getattr(situation, 'tags', tuple()): + return True + for situation_job in situation.all_jobs_gen(): + if tag in getattr(situation_job, 'tags', tuple()): + return True + return False + + @staticmethod + def is_in_situations_of_type(sim_info: SimInfo, situation_type: Type[Situation]) -> bool: + """is_in_situations_of_type(sim_info, situation_type) + + Determine if a Sim is currently in a situation that is of the a specific type. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param situation_type: The type of situation to check. + :type situation_type: Type[Situation] + :return: True, if the Sim is involved in any situations with any of the specified tags. False, if not. + :rtype: bool + """ + return any(CommonSimSituationUtils.get_running_situations_sim_is_in_by_type(sim_info, situation_type)) + + @staticmethod + def make_sim_leave(sim_info: SimInfo): + """make_sim_leave(sim_info) + + Make a Sim leave the current lot. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + """ + if sim_info is None: + return + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return + services.get_zone_situation_manager().make_sim_leave(sim) + + @staticmethod + def remove_sim_from_situation(sim_info: SimInfo, situation_id: int) -> bool: + """remove_sim_from_situation(sim_info, situation_id) + + Remove a Sim from a Situation. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param situation_id: The instance identifier of the Situation to remove the Sim from. + :type situation_id: int + :return: True, if the Sim was successfully removed from the situation. False, if not. + :rtype: bool + """ + situation_manager = services.get_zone_situation_manager() + if sim_info is None or situation_id is None: + return False + situation_manager.remove_sim_from_situation(sim_info, situation_id) + return True + + @staticmethod + def create_visit_situation(sim_info: SimInfo, duration_override_in_sim_seconds: int = None, visit_situation_override: Situation = None): + """create_visit_situation(sim_info, duration_override_in_sim_seconds=None, visit_situation_override=None) + + Create a visit situation for a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param duration_override_in_sim_seconds: An override in Sim seconds for the visit to last. Default is None. + :type duration_override_in_sim_seconds: int, optional + :param visit_situation_override: An instance of a Situation to use for the Visit. If not specified, the default visit situation will be used. Default is None. + :type visit_situation_override: Situation, optional + """ + if sim_info is None: + return + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return + services.get_zone_situation_manager().create_visit_situation(sim, duration_override=duration_override_in_sim_seconds, visit_type_override=visit_situation_override) + + @staticmethod + def create_situation_for_sim( + sim_info: SimInfo, + situation_type: Type[Situation], + creation_source: str, + invite_only: bool = True, + user_facing: bool = False, + situation_job: SituationJob = None, + purpose: SituationInvitationPurpose = SituationInvitationPurpose.INVITED, + **__ + ) -> int: + """create_situation_for_sim(\ + sim_info,\ + situation_type,\ + creation_source,\ + invite_only=True,\ + user_facing=False,\ + situation_job=None,\ + purpose=SituationInvitationPurpose.INVITED,\ + **__\ + ) + + Create a situation and put a Sim in it. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param situation_type: The type of situation to create. + :type situation_type: Type[Situation] + :param invite_only: If True, the situation will be invitation only. Default is True. + :type invite_only: bool, optional + :param user_facing: If True, the situation will be visible to the player (Like an Active Situation would be). If False, it will not be visible. Default is False. + :type user_facing: bool, optional + :param situation_job: The Situation Job to assign to the Sim upon situation creation. Default is whatever the situation specifies as the default job. + :type situation_job: SituationJob, optional + :param creation_source: The source of creation. + :type creation_source: str + :param purpose: The purpose of the situation. Default is SituationInvitationPurpose.INVITED. + :type purpose: SituationInvitationPurpose, optional + :return: The identifier of the situation that was created or 0 if an error occurs. + :rtype: int + """ + if sim_info is None: + raise AssertionError('sim_info was None!') + from sims4communitylib.utils.resources.common_situation_utils import CommonSituationUtils + situation_manager = CommonSituationUtils.get_situation_manager_for_zone() + guest_list = SituationGuestList(invite_only=invite_only) + guest_info = SituationGuestInfo.construct_from_purpose(CommonSimUtils.get_sim_id(sim_info), situation_job or situation_type.default_job(), purpose) + guest_list.add_guest_info(guest_info) + situation_id = situation_manager.create_situation(situation_type, guest_list=guest_list, user_facing=user_facing, creation_source=creation_source, **__) + if not situation_id: + return 0 + return situation_id + + @staticmethod + def complete_situation_goal(sim_info: SimInfo, situation_goal_id: int, target_sim_info: SimInfo = None, score_override: int = None, start_cooldown: bool = True): + """complete_situation_goal(sim_info, situation_goal_id, target_sim_info=None, score_override=None, start_cooldown=True) + + Complete a situation goal for a Sim using the specified Target Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param situation_goal_id: The decimal identifier of a Situation Goal to mark as completed. + :type situation_goal_id: int + :param target_sim_info: A target used in the completion of the situation goal. Default is None. + :type target_sim_info: SimInfo, optional + :param score_override: An alternative score to award to the Sim instead of the score specified by the goal. Default is None. + :type score_override: int, optional + :param start_cooldown: Whether or not to start a cooldown for the situation. Default is True. + :type start_cooldown: bool, optional + """ + from sims4communitylib.utils.sims.common_whim_utils import CommonWhimUtils + if target_sim_info is not None: + if CommonSimUtils.get_sim_instance(target_sim_info) is None: + return + goal_instances: List[Union[SituationGoal, SituationGoalTargetedSim, WhimSetBaseMixin]] = [] + goal_instances.extend(CommonSimSituationUtils.get_situation_goals(sim_info)) + goal_instances.extend(CommonWhimUtils.get_current_whims(sim_info)) + for goal_instance in goal_instances: + if goal_instance.guid64 != situation_goal_id: + continue + goal_instance.force_complete(target_sim=CommonSimUtils.get_sim_instance(target_sim_info), score_override=score_override, start_cooldown=start_cooldown) + + # noinspection SpellCheckingInspection + @staticmethod + def get_guids_of_all_running_situations_for_sim(sim_info: SimInfo) -> Tuple[int]: + """get_guids_of_all_running_situations_for_sim(sim_info) + + Retrieve GUIDs for all Situations a Sim is involved in. + + :param sim_info: The sim to check. + :type sim_info: SimInfo + :return: A collection of Situation GUIDs the specified Sim is involved in. + :rtype: Tuple[int] + """ + situation_guids = [] + for situation in CommonSimSituationUtils.get_situations(sim_info): + situation_guid = CommonSituationUtils.get_situation_guid(situation) + if situation_guid is None and situation_guid != -1: + continue + situation_guids.append(situation_guid) + return tuple(situation_guids) + + @staticmethod + def get_situations(sim_info: SimInfo, include_situation_callback: Callable[[Situation], bool] = None) -> Iterator[Situation]: + """get_situations(sim_info, include_situation_callback=None) + + Retrieve all Situations that a Sim is currently involved in. + + :param sim_info: An instance of a Sim + :type sim_info: SimInfo + :param include_situation_callback: If the result of this callback is True, the Situation will be included in the results. If set to None, All situations will be included. Default is None. + :type include_situation_callback: Callable[[Situation], bool], optional + :return: An iterator of Situations that pass the include callback filter. + :rtype: Iterator[Situation] + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return + situations = tuple(services.get_zone_situation_manager().get_situations_sim_is_in(sim)) + if sim is None or not situations: + return tuple() + for situation in situations: + if include_situation_callback is not None and not include_situation_callback(situation): + continue + yield situation + + @staticmethod + def get_first_running_situation_sim_is_in_by_type(sim_info: SimInfo, situation_type: Type[Situation]) -> Union[Situation, None]: + """get_first_running_situation_sim_is_in_by_type(sim_info, situation_type) + + Retrieve the first Situation that a Sim is currently involved in that is a specific type. + + :param sim_info: An instance of a Sim + :type sim_info: SimInfo + :param situation_type: A situation type to locate a situation with. + :type situation_type: Type[Situation] + :return: A situation the Sim is involved in that is of the specified type or None if not found. + :rtype: Union[Situation, None] + """ + for situation in CommonSimSituationUtils.get_running_situations_sim_is_in_by_type(sim_info, situation_type): + return situation + return None + + @staticmethod + def get_first_running_situation_sim_is_in_by_tag(sim_info: SimInfo, tag: CommonGameTag) -> Union[Situation, None]: + """get_first_running_situation_sim_is_in_by_tag(sim_info, tag) + + Retrieve the first Situation that a Sim is currently involved in that has a tag. + + :param sim_info: An instance of a Sim + :type sim_info: SimInfo + :param tag: The tag to locate a situation with. + :type tag: CommonGameTag + :return: A situation the Sim is involved in that has the specified tag or None if not found. + :rtype: Union[Situation, None] + """ + for situation in CommonSimSituationUtils.get_running_situations_sim_is_in_by_tag(sim_info, tag): + return situation + return None + + @staticmethod + def get_running_situations_sim_is_in_by_tag(sim_info: SimInfo, tag: CommonGameTag) -> Tuple[Situation]: + """get_running_situations_sim_is_in_by_tag(sim_info, tag) + + Retrieve all Situations that a Sim is currently involved in that have the specified tag. + + :param sim_info: An instance of a Sim + :type sim_info: SimInfo + :param tag: The tag to locate situations with. + :type tag: CommonGameTag + :return: An iterator of Situations the Sim is running that have the specified tag. + :rtype: Iterator[Situation] + """ + def _situation_has_tag(_situation: Situation) -> bool: + if hasattr(_situation, 'tags'): + return tag in _situation.tags + return False + + return tuple(CommonSimSituationUtils.get_situations(sim_info, include_situation_callback=_situation_has_tag)) + + @staticmethod + def get_running_situations_sim_is_in_by_tags(sim_info: SimInfo, tags: Tuple[CommonGameTag]) -> Tuple[Situation]: + """get_running_situations_sim_is_in_by_tag(sim_info, tags) + + Retrieve all Situations that a Sim is currently involved in that have the specified tag. + + :param sim_info: An instance of a Sim + :type sim_info: SimInfo + :param tags: A collection of tags to locate situations with. Matching situations will have at least one of these tags. + :type tags: Iterator[CommonGameTag] + :return: An iterator of Situations the Sim is running that have any of the specified tags. + :rtype: Iterator[Situation] + """ + matching_situations: List[Situation] = list() + for tag in tags: + for situation in CommonSimSituationUtils.get_running_situations_sim_is_in_by_tag(sim_info, tag): + if situation not in matching_situations: + matching_situations.append(situation) + return tuple(matching_situations) + + @staticmethod + def get_running_situations_sim_is_in_by_type(sim_info: SimInfo, situation_type: Type[Situation]) -> Tuple[Situation]: + """get_running_situations_sim_is_in_by_type(sim_info, situation_type) + + Retrieve all Situations that a Sim is currently involved in that match the specified type. + + :param sim_info: An instance of a Sim + :type sim_info: SimInfo + :param situation_type: A situation type to locate situations with. + :type situation_type: Type[Situation] + :return: An iterator of Situations the Sim is running that are of the specified type. + :rtype: Iterator[Situation] + """ + def _situation_is_of_type(_situation: Situation) -> bool: + return isinstance(_situation, situation_type) + + return tuple(CommonSimSituationUtils.get_situations(sim_info, include_situation_callback=_situation_is_of_type)) + + @staticmethod + def get_situation_ids(sim_info: SimInfo) -> List[int]: + """get_situation_ids(sim_info) + + Retrieve decimal identifiers for all Situations a Sim is involved in. + + :param sim_info: The sim to check. + :type sim_info: SimInfo + :return: A collection of Situation decimal identifiers the specified Sim is involved in. + :rtype: List[int] + """ + situation_ids = [] + for situation in CommonSimSituationUtils.get_situations(sim_info): + situation_id = CommonSituationUtils.get_situation_id(situation) + if situation_id is None and situation_id != -1: + continue + situation_ids.append(situation_id) + return situation_ids + + # noinspection SpellCheckingInspection + @staticmethod + def get_situation_guids(sim_info: SimInfo) -> List[int]: + """get_situation_guids(sim_info) + + Retrieve GUIDs for all Situations a Sim is involved in. + + :param sim_info: The sim to check. + :type sim_info: SimInfo + :return: A collection of Situation GUIDs the specified Sim is involved in. + :rtype: List[int] + """ + situation_guids = [] + for situation in CommonSimSituationUtils.get_situations(sim_info): + situation_guid = CommonSituationUtils.get_situation_guid(situation) + if situation_guid is None and situation_guid != -1: + continue + situation_guids.append(situation_guid) + return situation_guids + + @staticmethod + def get_situation_goals(sim_info: SimInfo) -> Tuple[Union[SituationGoal, SituationGoalTargetedSim]]: + """get_situation_goals(sim_info) + + Retrieve the goals of all situations a Sim is currently in. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The situation goals of all Situations the Sim is currently involved in. + :rtype: Tuple[Union[SituationGoal, SituationGoalTargetedSim]] + """ + goal_instances: List[Union[SituationGoal, SituationGoalTargetedSim]] = [] + for situation in CommonSimSituationUtils.get_situations(sim_info): + goal_tracker = situation._get_goal_tracker() + if goal_tracker is None: + continue + if isinstance(goal_tracker, SituationGoalTracker): + if goal_tracker._realized_minor_goals is not None: + goal_instances.extend(goal_tracker._realized_minor_goals.keys()) + if goal_tracker._realized_main_goal is not None: + goal_instances.insert(0, goal_tracker._realized_main_goal) + elif isinstance(goal_tracker, DynamicSituationGoalTracker): + goal_instances.extend(goal_tracker.goals) + return tuple(goal_instances) + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_testing.print_situations', + 'Print a list of all situations a Sim is in.', + command_arguments=( + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to check.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib_testing.printsituations', + ) +) +def _common_show_running_situations(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): + if sim_info is None: + return + log = CommonSimSituationUtils.get_log() + try: + log.enable() + output(f'Attempting to print all running situations of Sim {sim_info}') + situation_strings: List[str] = list() + for situation in CommonSimSituationUtils.get_situations(sim_info): + situation_name = CommonSituationUtils.get_situation_name(situation) + situation_id = CommonSituationUtils.get_situation_id(situation) + situation_strings.append(f'{situation_name} ({situation_id})') + + situation_strings = sorted(situation_strings, key=lambda x: x) + sim_situations = ', '.join(situation_strings) + text = '' + text += f'Situations:\n{sim_situations}\n\n' + sim_id = CommonSimUtils.get_sim_id(sim_info) + log.debug(f'{sim_info} Situations ({sim_id})') + log.debug(text) + CommonBasicNotification( + CommonLocalizationUtils.create_localized_string(f'{sim_info} Situations ({sim_id})'), + CommonLocalizationUtils.create_localized_string(text) + ).show( + icon=IconInfoData(obj_instance=CommonSimUtils.get_sim_instance(sim_info)) + ) + finally: + log.disable() diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_skill_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_skill_utils.py new file mode 100644 index 0000000..f121632 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_skill_utils.py @@ -0,0 +1,409 @@ +""" +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 +""" +from typing import Union, Iterator + +from server_commands.argument_helpers import TunableInstanceParam +from sims.sim_info import SimInfo +from sims4.resources import Types +from sims4communitylib.enums.skills_enum import CommonSkillId +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + CommonConsoleCommandArgument +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.resources.common_skill_utils import CommonSkillUtils +from statistics.skill import Skill + + +class CommonSimSkillUtils: + """Utilities for manipulating the Skills of Sims. + + """ + @staticmethod + def has_skill(sim_info: SimInfo, skill: Union[int, CommonSkillId, Skill]) -> bool: + """has_skill(sim_info, skill) + + Determine if a Sim has a Skill. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :param skill: The identifier of the Skill to check. + :type skill: Union[int, CommonSkillId, Skill] + :return: True, if the Sim has the skill. False, if the Sim does not. + :rtype: bool + """ + return CommonSimSkillUtils.get_skill(sim_info, skill, add=False) is not None + + # noinspection PyUnusedLocal + @staticmethod + def set_current_skill_level(sim_info: SimInfo, skill: Union[int, CommonSkillId, Skill], level: float, add: bool = True) -> bool: + """set_current_skill_level(sim_info, skill, level, add=True) + + Set the current skill level of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param skill: The decimal identifier of a Skill. + :type skill: Union[int, CommonSkillId, Skill] + :param level: The level to set the skill to. + :type skill: Union[int, CommonSkillId, Skill] + :param add: OBSOLETE AND IGNORED ARGUMENT! When setting the skill level for a Sim, the Skill will always be added first. + :type add: bool, optional + :return: True, if successful. False, if not successful, the skill does not exist, or the skill is not valid for the Sim. + :rtype: bool + """ + sim_skill: Skill = CommonSimSkillUtils.get_skill(sim_info, skill, add=add) + if sim_skill is None: + return False + new_skill_experience = sim_skill.convert_from_user_value(level) + sim_skill.set_value(new_skill_experience) + return True + + @staticmethod + def set_current_skill_level_to_max(sim_info: SimInfo, skill: Union[int, CommonSkillId, Skill]) -> bool: + """set_current_skill_level_to_max(sim_info, skill, add=True) + + Set the current skill level of a Sim to its maximum value. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param skill: The decimal identifier of a Skill. + :type skill: Union[int, CommonSkillId, Skill] + :return: True, if successful. False, if not successful, the skill does not exist, or the skill is not valid for the Sim. + :rtype: bool + """ + skill: Skill = CommonSkillUtils.load_skill_by_id(skill) + if skill is None: + return False + return CommonSimSkillUtils.set_current_skill_level(sim_info, skill, skill.max_level) + + @staticmethod + def get_current_skill_level(sim_info: SimInfo, skill: Union[int, CommonSkillId, Skill], use_effective_skill_level: bool = True) -> float: + """get_current_skill_level(\ + sim_info,\ + skill,\ + use_effective_skill_level=True\ + ) + + Retrieve the current skill level of a Sim for a Skill. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param skill: The decimal identifier of a Skill. + :type skill: Union[int, CommonSkillId, Skill] + :param use_effective_skill_level: If True, any skill modifiers will be taken into account, such as buffs, traits, etc. If False, the skill level without modifiers will be returned. True only works if the Sim is instanced. Default is True. + :type use_effective_skill_level: bool, optional + :return: The current level the Sim is at for the specified Skill or 0.0 if the Skill is either not available or the Sim does not have it. + :rtype: float + """ + skill: Skill = CommonSkillUtils.load_skill_by_id(skill) + if skill is None: + return 0.0 + skill_or_skill_type = sim_info.get_statistic(skill, add=False) or skill + if use_effective_skill_level and sim_info.is_instanced(): + skill_level: float = sim_info.get_effective_skill_level(skill_or_skill_type) + else: + skill_level: float = skill_or_skill_type.get_user_value() + return skill_level + + @staticmethod + def is_at_max_skill_level(sim_info: SimInfo, skill: Union[int, CommonSkillId, Skill], use_effective_skill_level: bool = True) -> bool: + """is_at_max_skill_level(\ + sim_info,\ + skill,\ + use_effective_skill_level=True\ + ) + + Determine if a Sim has reached the Maximum Level of a Skill. + + .. note:: Max level depends on the skill itself. Each skill can have a different max level. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :param skill: The identifier of the Skill to check. + :type skill: Union[int, CommonSkillId, Skill] + :param use_effective_skill_level: If True, any skill modifiers will be taken into account, such as buffs, traits, etc. If False, the skill level without modifiers will be returned. True only works if the Sim is instanced. Default is True. + :type use_effective_skill_level: bool, optional + :return: True, if the Sim has the skill at the maximum level. False, if the Sim does not. + :rtype: bool + """ + skill: Skill = CommonSkillUtils.load_skill_by_id(skill) + if skill is None: + return False + sim_skill_level = CommonSimSkillUtils.get_current_skill_level( + sim_info, + skill, + use_effective_skill_level=use_effective_skill_level + ) + return sim_skill_level >= skill.max_level + + @staticmethod + def remove_skill(sim_info: SimInfo, skill: Union[int, CommonSkillId, Skill]) -> bool: + """remove_skill(sim_info, skill) + + Remove a Skill from the specified Sim. + + :param sim_info: The Sim to modify. + :type sim_info: SimInfo + :param skill: The identifier of the Skill to remove. + :type skill: Union[int, CommonSkillId, Skill] + :return: True, if the skill was removed successfully. False, if not. + :rtype: bool + """ + skill: Skill = CommonSkillUtils.load_skill_by_id(skill) + if skill is None: + return False + sim_info.remove_statistic(skill) + return True + + @staticmethod + def set_progress_toward_max_skill_level(sim_info: SimInfo, skill: Union[int, CommonSkillId, Skill], value: float, add: bool = True) -> bool: + """set_progress_toward_max_skill_level(sim_info, skill, value, add=True) + + Set the amount of progress a Sim has made toward the max level of a Skill. + + :param sim_info: The Sim to modify. + :type sim_info: SimInfo + :param skill: The identifier of the Skill to set. + :type skill: Union[int, CommonSkillId, Skill] + :param value: The amount to add. + :type value: Union[int, CommonSkillId, Skill] + :param add: If True, the skill will be added to the Sim before it is modified. + :type add: bool, optional + :return: True, if successful. False, if not. + :rtype: bool + """ + sim_skill: Skill = CommonSimSkillUtils.get_skill(sim_info, skill, add=add) + if sim_skill is None: + return False + sim_skill.set_value(value) + return True + + @staticmethod + def get_progress_toward_max_skill_level(sim_info: SimInfo, skill: Union[int, CommonSkillId, Skill], add: bool = True) -> float: + """get_progress_toward_max_skill_level(sim_info, skill, add=True) + + Retrieve the amount of progress a Sim has made toward the max level of a Skill. + + :param sim_info: The Sim to modify. + :type sim_info: SimInfo + :param skill: The identifier of the Skill to modify. + :type skill: Union[int, CommonSkillId, Skill] + :param add: If True, the skill will be added to the Sim before it is modified. + :type add: bool, optional + :return: True, if successful. False, if not. + :rtype: bool + """ + sim_skill: Skill = CommonSimSkillUtils.get_skill(sim_info, skill, add=add) + if sim_skill is None: + return False + sim_skill.get_value() + return True + + @staticmethod + def change_progress_toward_max_skill_level(sim_info: SimInfo, skill: Union[int, CommonSkillId, Skill], value: float, add: bool = True) -> bool: + """change_progress_toward_max_skill_level(sim_info, skill, value, add=True) + + Modify the amount of progress a Sim has made toward the max level of a Skill. + + :param sim_info: The Sim to modify. + :type sim_info: SimInfo + :param skill: The identifier of the Skill to modify. + :type skill: Union[int, CommonSkillId, Skill] + :param value: The level to add or subtract to/from the skill. + :type value: Union[int, CommonSkillId, Skill] + :param add: If True, the skill will be added to the Sim before it is modified. + :type add: bool, optional + :return: True, if successful. False, if not. + :rtype: bool + """ + sim_skill: Skill = CommonSimSkillUtils.get_skill(sim_info, skill, add=add) + if sim_skill is None: + return False + sim_skill.add_value(value) + return True + + @staticmethod + def change_progress_toward_next_skill_level(sim_info: SimInfo, skill: Union[int, CommonSkillId, Skill], value: float, add: bool = True) -> bool: + """change_progress_toward_next_skill_level(sim_info, skill, value, add=True) + + Modify the amount of progress a Sim has made toward the next level of a Skill. + + :param sim_info: The Sim to modify. + :type sim_info: SimInfo + :param skill: The identifier of the Skill to modify. + :type skill: Union[int, CommonSkillId, Skill] + :param value: The level to add or subtract to/from the skill. + :type value: Union[int, CommonSkillId, Skill] + :param add: If True, the skill will be added to the Sim before it is modified. + :type add: bool, optional + :return: True, if successful. False, if not. + :rtype: bool + """ + return CommonSimSkillUtils.change_progress_toward_max_skill_level(sim_info, skill, value, add=add) + + @staticmethod + def get_progress_toward_next_skill_level(sim_info: SimInfo, skill: Union[int, CommonSkillId, Skill], add: bool = False) -> float: + """get_progress_toward_next_skill_level(sim_info, skill, add=False) + + Retrieve the amount of progress a Sim has made toward the next level of a Skill. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :param skill: The identifier of the Skill to use. + :type skill: Union[int, CommonSkillId, Skill] + :param add: If True, the skill will be added to the Sim before it is checked. + :type add: bool, optional + :return: The progress to the next level of the specified Skill or `-1.0` if a problem occurs. + :rtype: float + """ + skill = CommonSimSkillUtils.get_skill(sim_info, skill, add=add) + if skill is None: + return -1.0 + current_skill_level = skill.get_user_value() + current_skill_experience = skill.get_value() + experience_for_level = skill.get_skill_value_for_level(current_skill_level) + experience_for_next_level = skill.get_skill_value_for_level(current_skill_level + 1) - experience_for_level + if experience_for_level > 0.0 and experience_for_next_level > 0.0: + return (current_skill_experience - experience_for_level) / experience_for_next_level + return 0.0 + + @staticmethod + def translate_skill_progress(sim_info: SimInfo, skill_from: Union[int, CommonSkillId, Skill], skill_to: Union[int, CommonSkillId, Skill], add: bool = True) -> bool: + """translate_skill_progress(sim_info, skill_from, skill_to, add=True) + + Translate the total progress of one Skill to the total progress of another Skill for the specified Sim. + + :param sim_info: The Sim to modify. + :type sim_info: SimInfo + :param skill_from: The identifier of the Skill being changed. + :type skill_from: Union[int, CommonSkillId, Skill] + :param skill_to: The identifier of the Skill being translated to. + :type skill_to: Union[int, CommonSkillId, Skill] + :param add: If True, the skill will be added to the Sim before it is modified. + :type add: bool, optional + :return: True, if successful. False, if not. + :rtype: bool + """ + skill_level_value_from = CommonSimSkillUtils.get_progress_toward_next_skill_level(sim_info, skill_from) + skill_to = CommonSimSkillUtils.get_skill(sim_info, skill_to, add=add) + if skill_to is None: + return False + level = skill_to.get_user_value() + value_for_level = skill_to.get_skill_value_for_level(level) + value_for_next_level = skill_to.get_skill_value_for_level(level + 1) - value_for_level + level_of_new_skill = value_for_level + value_for_next_level * skill_level_value_from + return CommonSimSkillUtils.set_progress_toward_max_skill_level(sim_info, skill_to, level_of_new_skill) + + @staticmethod + def get_skill(sim_info: SimInfo, skill: Union[int, CommonSkillId, Skill], add: bool = True) -> Union[Skill, None]: + """get_skill(sim_info, skill, add=True) + + Retrieve a Skill for the specified Sim. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :param skill: The identifier of the Skill to use. + :type skill: Union[int, CommonSkillId, Skill] + :param add: If True, the skill will be added to the Sim before it is checked. + :type add: bool, optional + :return: An instance of a Skill of the Sim or None if the Skill does not exist. + :rtype: Union[Skill, None] + """ + skill: Skill = CommonSkillUtils.load_skill_by_id(skill) + if skill is None: + return None + return sim_info.get_statistic(skill, add=add) + + @staticmethod + def get_all_skills_available_for_sim_gen(sim_info: SimInfo) -> Iterator[Skill]: + """get_all_skills_available_for_sim_gen(sim_info) + + Retrieve all Skills available to a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: An iterator of Skills that are available for the specified Sim. + :rtype: Iterator[Skill] + """ + from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return tuple() + + def _is_skill_available_for_sim(skill: Skill) -> bool: + return skill.can_add(sim) + + yield from CommonSkillUtils.get_all_skills_gen(include_skill_callback=_is_skill_available_for_sim) + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.print_skill_level', + 'Print information about the skill level of a Sim for a Skill.', + command_arguments=( + CommonConsoleCommandArgument('skill', 'Skill Id or Tuning Name', 'The tuning name or decimal identifier of a skill.'), + CommonConsoleCommandArgument('use_effective_skill_level', 'True or False', 'If True, the skill level of the Sim will take into account any modifiers that are applied to them. If False, the skill level will be determined without modifiers.', is_optional=True, default_value=True), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to check.', is_optional=True, default_value='Active Sim'), + ) +) +def _common_get_skill_level(output: CommonConsoleCommandOutput, skill: TunableInstanceParam(Types.STATISTIC), use_effective_skill_level: bool = True, sim_info: SimInfo = None): + if skill is None: + output('ERROR: Failed, Skill not specified or Skill did not exist!') + return + if sim_info is None: + return + output(f'Attempting to print skill level for skill {skill} with use_effective_skill_level {use_effective_skill_level} for Sim {sim_info}') + skill_value = CommonSimSkillUtils.get_current_skill_level(sim_info, skill, use_effective_skill_level=use_effective_skill_level) + output(f'Skill Level: {skill_value}') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.set_skill_level', + 'Set the current skill level of a Skill for a Sim.', + command_arguments=( + CommonConsoleCommandArgument('skill', 'Skill Id or Tuning Name', 'The tuning name or decimal identifier of a skill.'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to change.', is_optional=True, default_value='Active Sim'), + ) +) +def _common_set_skill_level(output: CommonConsoleCommandOutput, skill: TunableInstanceParam(Types.STATISTIC), level: int, sim_info: SimInfo = None): + if sim_info is None: + return + if skill is None: + output('ERROR: Skill not specified or the specified Skill did not exist!') + return + if level < 0: + output('ERROR: level must be a positive number or zero.') + return + output(f'Attempting to set the skill level for skill {skill} to level {level} for Sim {sim_info}') + if CommonSimSkillUtils.set_current_skill_level(sim_info, skill, level): + output(f'SUCCESS: Successfully set the skill level of skill {skill} for Sim {sim_info}.') + else: + output(f'FAILED: Failed to set the skill level of skill {skill} for Sim {sim_info}.') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.remove_skill', + 'Remove a skill from a Sim (effectively set it to zero)', + command_arguments=( + CommonConsoleCommandArgument('skill', 'Skill Id or Tuning Name', 'The tuning name or decimal identifier of a skill.'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to change.', is_optional=True, default_value='Active Sim'), + ) +) +def _common_remove_skill(output: CommonConsoleCommandOutput, skill: TunableInstanceParam(Types.STATISTIC), sim_info: SimInfo = None): + if skill is None: + output('ERROR: Skill not specified or the specified Skill did not exist!') + return + if sim_info is None: + return + output(f'Removing skill {skill} from Sim {sim_info}') + if CommonSimSkillUtils.remove_skill(sim_info, skill): + output(f'SUCCESS: Successfully removed skill {skill} from Sim {sim_info}.') + else: + output(f'FAILED: Failed to remove skill {skill} from Sim {sim_info}.') diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_spawn_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_spawn_utils.py new file mode 100644 index 0000000..3db1793 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_spawn_utils.py @@ -0,0 +1,3082 @@ +""" +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 +""" +import os +import random +import time + +from typing import Union, Tuple, Callable, Any, Iterator, Dict, List + +import indexed_manager +from bucks.bucks_tracker import PerkData +from protocolbuffers import Outfits_pb2, S4Common_pb2 +from protocolbuffers.S4Common_pb2 import SimPronoun +from sims.ghost import Ghost +from sims.occult.occult_enums import OccultType +from sims.outfits.outfit_enums import OutfitCategory, BodyType, SpecialOutfitIndex +from sims.outfits.outfit_tuning import OutfitTuning +from sims.sim_info_lod import SimInfoLODLevel +from sims.sim_info_types import SpeciesExtended, SimSerializationOption +from sims4.resources import Types +from sims4communitylib.classes.math.common_surface_identifier import CommonSurfaceIdentifier +from sims4communitylib.enums.common_age import CommonAge +from sims4communitylib.enums.common_bucks_types import CommonBucksType +from sims4communitylib.enums.common_death_types import CommonDeathType +from sims4communitylib.enums.common_gender import CommonGender +from sims4communitylib.enums.common_species import CommonSpecies +from sims4communitylib.enums.strings_enum import CommonStringId +from sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + CommonConsoleCommandArgument +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.cas.common_cas_utils import CommonCASUtils +from sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils +from sims4communitylib.utils.common_date_utils import CommonRealDateUtils +from sims4communitylib.utils.common_log_registry import CommonLogRegistry +from sims4communitylib.utils.common_resource_utils import CommonResourceUtils +from sims4communitylib.utils.common_time_utils import CommonTimeUtils +from sims4communitylib.utils.math.common_bitwise_utils import CommonBitwiseUtils +from sims4communitylib.utils.resources.common_game_pack_utils import CommonGamePackUtils +from sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils +from sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils +from sims4communitylib.utils.sims.common_sim_death_utils import CommonSimDeathUtils +from sims4communitylib.utils.sims.common_sim_location_utils import CommonSimLocationUtils +from sims4communitylib.classes.math.common_location import CommonLocation +from sims4communitylib.classes.math.common_vector3 import CommonVector3 +from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils +from statistics.commodity import Commodity +from statistics.life_skill_statistic import LifeSkillStatistic +from statistics.ranked_statistic import RankedStatistic +from statistics.skill import Skill +from statistics.trait_statistic import TraitStatisticStates, TraitStatistic + +ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' + +if not ON_RTD: + import build_buy + try: + import _buildbuy + except ImportError: + # noinspection SpellCheckingInspection + _buildbuy = build_buy + import services + from interactions.interaction_finisher import FinishingType + from sims.household import Household + from sims.sim_info import SimInfo + from sims.sim_spawner import SimCreator, SimSpawner + from animation.posture_manifest import Hand + from interactions.si_state import SIState + from objects.object_enums import ResetReason + from postures import posture_graph + from postures.posture_specs import PostureSpecVariable + from postures.posture_state import PostureState +else: + # noinspection PyMissingOrEmptyDocstring + class FinishingType: + pass + + # noinspection PyMissingOrEmptyDocstring + class Household: + pass + + # noinspection PyMissingOrEmptyDocstring + class SimInfo: + pass + + # noinspection PyMissingOrEmptyDocstring + class SimCreator: + pass + + # noinspection PyMissingOrEmptyDocstring + class SimSpawner: + pass + + # noinspection PyMissingOrEmptyDocstring + class Command: + pass + + # noinspection PyMissingOrEmptyDocstring + class CommandType: + pass + + # noinspection PyMissingOrEmptyDocstring + class CheatOutput: + pass + + # noinspection PyMissingOrEmptyDocstring + class Hand: + pass + + # noinspection PyMissingOrEmptyDocstring + class SIState: + pass + + # noinspection PyMissingOrEmptyDocstring + class ResetReason: + RESET_EXPECTED = 0 + + # noinspection PyMissingOrEmptyDocstring,PyMissingTypeHints + def posture_graph(*_, **__): + pass + + # noinspection PyMissingOrEmptyDocstring,PyMissingTypeHints + def get_origin_spec(*_, **__): + pass + + # noinspection PyMissingOrEmptyDocstring + class PostureSpecVariable: + pass + + # noinspection PyMissingOrEmptyDocstring + class PostureState: + pass + +log = CommonLogRegistry().register_log(ModInfo.get_identity(), 's4cl_spawn_utils') + + +class CommonSimSpawnUtils: + """Utilities for creating, spawning, despawning, and resetting Sims. + + """ + + @classmethod + def create_sim_info( + cls, + species: CommonSpecies, + gender: CommonGender = None, + age: CommonAge = None, + first_name: str = None, + last_name: str = None, + trait_ids: Tuple[int] = (), + household: Household = None, + source: str = 'testing' + ) -> Union[SimInfo, None]: + """create_sim_info(\ + species,\ + gender=None,\ + age=None,\ + first_name=None,\ + last_name=None,\ + trait_ids=(),\ + household=None,\ + source='testing'\ + ) + + Create SimInfo for a Sim. + + :param species: The species to create a SimInfo for. + :type species: CommonSpecies + :param gender: The gender of the created Sim. Default is None. + :type gender: CommonGender, optional + :param age: The age of the created Sim. Default is None. + :type age: CommonAge, optional + :param first_name: The First Name of the created Sim. Default is random name. + :type first_name: str, optional + :param last_name: The Last Name of the created Sim. Default is random name. + :type last_name: str, optional + :param trait_ids: The decimal identifiers of the Traits to add to the created Sim. Default is an empty collection. + :type trait_ids: Tuple[int], optional + :param household: The household to place the created Sim in. If None, the Sim will be placed in a hidden household. Default is None. + :type household: Household, optional + :param source: The reason for the Sims creation. Default is 'testing'. + :type source: str, optional + :return: The SimInfo of the created Sim or None if the Sim failed to be created. + :rtype: SimInfo + """ + return cls._create_sim_info( + species, + gender=gender, + age=age, + first_name=first_name, + last_name=last_name, + trait_ids=trait_ids, + household=household, + source=source + ) + + @classmethod + def create_human_sim_info( + cls, + gender: CommonGender = None, + age: CommonAge = None, + first_name: str = None, + last_name: str = None, + trait_ids: Tuple[int] = (), + household: Household = None, + source: str = 'testing' + ) -> Union[SimInfo, None]: + """create_human_sim_info(\ + gender=None,\ + age=None,\ + first_name=None,\ + last_name=None,\ + trait_ids=(),\ + household=None,\ + source='testing'\ + ) + + Create SimInfo for a Human Sim. + + :param gender: The gender of the created Sim. Default is None. + :type gender: CommonGender, optional + :param age: The age of the created Sim. Default is None. + :type age: CommonAge, optional + :param first_name: The First Name of the created Sim. Default is random name. + :type first_name: str, optional + :param last_name: The Last Name of the created Sim. Default is random name. + :type last_name: str, optional + :param trait_ids: The decimal identifiers of the Traits to add to the created Sim. Default is an empty collection. + :type trait_ids: Tuple[int], optional + :param household: The household to place the created Sim in. If None, the Sim will be placed in a hidden household. Default is None. + :type household: Household, optional + :param source: The reason for the Sims creation. Default is 'testing'. + :type source: str, optional + :return: The SimInfo of the created Sim or None if the Sim failed to be created. + :rtype: SimInfo + """ + return cls._create_sim_info( + CommonSpecies.HUMAN, + gender=gender, + age=age, + first_name=first_name, + last_name=last_name, + trait_ids=trait_ids, + household=household, + source=source + ) + + @classmethod + def create_large_dog_sim_info( + cls, + gender: CommonGender = None, + age: CommonAge = None, + first_name: str = None, + last_name: str = None, + trait_ids: Tuple[int] = (), + household: Household = None, + source: str = 'testing' + ) -> Union[SimInfo, None]: + """create_large_dog_sim_info(\ + gender=None,\ + age=None,\ + first_name=None,\ + last_name=None,\ + trait_ids=(),\ + household=None,\ + source='testing'\ + ) + + Create SimInfo for a Large Dog Sim. + + :param gender: The gender of the created Sim. Default is None. + :type gender: CommonGender, optional + :param age: The age of the created Sim. Default is None. + :type age: CommonAge, optional + :param first_name: The First Name of the created Sim. Default is random name. + :type first_name: str, optional + :param last_name: The Last Name of the created Sim. Default is random name. + :type last_name: str, optional + :param trait_ids: The decimal identifiers of the Traits to add to the created Sim. Default is an empty collection. + :type trait_ids: Tuple[int], optional + :param household: The household to place the created Sim in. If None, the Sim will be placed in a hidden household. Default is None. + :type household: Household, optional + :param source: The reason for the Sims creation. Default is 'testing'. + :type source: str, optional + :return: The SimInfo of the created Sim or None if the Sim failed to be created. + :rtype: SimInfo + """ + return cls._create_sim_info( + CommonSpecies.LARGE_DOG, + gender=gender, + age=age, + first_name=first_name, + last_name=last_name, + trait_ids=trait_ids, + household=household, + source=source + ) + + @classmethod + def create_small_dog_sim_info( + cls, + gender: CommonGender = None, + age: CommonAge = None, + first_name: str = None, + last_name: str = None, + trait_ids: Tuple[int] = (), + household: Household = None, + source: str = 'testing' + ) -> Union[SimInfo, None]: + """create_small_dog_sim_info(\ + gender=None,\ + age=None,\ + first_name='',\ + last_name='',\ + trait_ids=(),\ + household=None,\ + source='testing'\ + ) + + Create SimInfo for a Small Dog Sim. + + :param gender: The gender of the created Sim. Default is None. + :type gender: CommonGender, optional + :param age: The age of the created Sim. Default is None. + :type age: CommonAge, optional + :param first_name: The First Name of the created Sim. Default is random name. + :type first_name: str, optional + :param last_name: The Last Name of the created Sim. Default is random name. + :type last_name: str, optional + :param trait_ids: The decimal identifiers of the Traits to add to the created Sim. Default is an empty collection. + :type trait_ids: Tuple[int], optional + :param household: The household to place the created Sim in. If None, the Sim will be placed in a hidden household. Default is None. + :type household: Household, optional + :param source: The reason for the Sims creation. Default is 'testing'. + :type source: str, optional + :return: The SimInfo of the created Sim or None if the Sim failed to be created. + :rtype: SimInfo + """ + return cls._create_sim_info( + CommonSpecies.SMALL_DOG, + gender=gender, + age=age, + first_name=first_name, + last_name=last_name, + trait_ids=trait_ids, + household=household, + source=source + ) + + @classmethod + def create_cat_sim_info( + cls, + gender: CommonGender = None, + age: CommonAge = None, + first_name: str = None, + last_name: str = None, + trait_ids: Tuple[int] = (), + household: Household = None, + source: str = 'testing' + ) -> Union[SimInfo, None]: + """create_cat_sim_info(\ + gender=None,\ + age=None,\ + first_name='',\ + last_name='',\ + trait_ids=(),\ + household=None,\ + source='testing'\ + ) + + Create SimInfo for a Cat Sim. + + :param gender: The gender of the created Sim. Default is None. + :type gender: CommonGender, optional + :param age: The age of the created Sim. Default is None. + :type age: CommonAge, optional + :param first_name: The First Name of the created Sim. Default is random name. + :type first_name: str, optional + :param last_name: The Last Name of the created Sim. Default is random name. + :type last_name: str, optional + :param trait_ids: The decimal identifiers of the Traits to add to the created Sim. Default is an empty collection. + :type trait_ids: Tuple[int], optional + :param household: The household to place the created Sim in. If None, the Sim will be placed in a hidden household. Default is None. + :type household: Household, optional + :param source: The reason for the Sims creation. Default is 'testing'. + :type source: str, optional + :return: The SimInfo of the created Sim or None if the Sim failed to be created. + :rtype: SimInfo + """ + return cls._create_sim_info( + CommonSpecies.CAT, + gender=gender, + age=age, + first_name=first_name, + last_name=last_name, + trait_ids=trait_ids, + household=household, + source=source + ) + + @classmethod + def create_fox_sim_info( + cls, + gender: CommonGender = None, + age: CommonAge = None, + first_name: str = None, + last_name: str = None, + trait_ids: Tuple[int] = (), + household: Household = None, + source: str = 'testing' + ) -> Union[SimInfo, None]: + """create_fox_sim_info(\ + gender=None,\ + age=None,\ + first_name='',\ + last_name='',\ + trait_ids=(),\ + household=None,\ + source='testing'\ + ) + + Create SimInfo for a Fox Sim. + + :param gender: The gender of the created Sim. Default is None. + :type gender: CommonGender, optional + :param age: The age of the created Sim. Default is None. + :type age: CommonAge, optional + :param first_name: The First Name of the created Sim. Default is random name. + :type first_name: str, optional + :param last_name: The Last Name of the created Sim. Default is random name. + :type last_name: str, optional + :param trait_ids: The decimal identifiers of the Traits to add to the created Sim. Default is an empty collection. + :type trait_ids: Tuple[int], optional + :param household: The household to place the created Sim in. If None, the Sim will be placed in a hidden household. Default is None. + :type household: Household, optional + :param source: The reason for the Sims creation. Default is 'testing'. + :type source: str, optional + :return: The SimInfo of the created Sim or None if the Sim failed to be created. + :rtype: SimInfo + """ + return cls._create_sim_info( + CommonSpecies.FOX, + gender=gender, + age=age, + first_name=first_name, + last_name=last_name, + trait_ids=trait_ids, + household=household, + source=source + ) + + @classmethod + def create_horse_sim_info( + cls, + gender: CommonGender = None, + age: CommonAge = None, + first_name: str = None, + last_name: str = None, + trait_ids: Tuple[int] = (), + household: Household = None, + source: str = 'testing' + ) -> Union[SimInfo, None]: + """create_horse_sim_info(\ + gender=None,\ + age=None,\ + first_name='',\ + last_name='',\ + trait_ids=(),\ + household=None,\ + source='testing'\ + ) + + Create SimInfo for a Horse Sim. + + :param gender: The gender of the created Sim. Default is None. + :type gender: CommonGender, optional + :param age: The age of the created Sim. Default is None. + :type age: CommonAge, optional + :param first_name: The First Name of the created Sim. Default is random name. + :type first_name: str, optional + :param last_name: The Last Name of the created Sim. Default is random name. + :type last_name: str, optional + :param trait_ids: The decimal identifiers of the Traits to add to the created Sim. Default is an empty collection. + :type trait_ids: Tuple[int], optional + :param household: The household to place the created Sim in. If None, the Sim will be placed in a hidden household. Default is None. + :type household: Household, optional + :param source: The reason for the Sims creation. Default is 'testing'. + :type source: str, optional + :return: The SimInfo of the created Sim or None if the Sim failed to be created. + :rtype: SimInfo + """ + return cls._create_sim_info( + CommonSpecies.HORSE, + gender=gender, + age=age, + first_name=first_name, + last_name=last_name, + trait_ids=trait_ids, + household=household, + source=source + ) + + @classmethod + def _create_sim_info( + cls, + species: CommonSpecies, + gender: CommonGender = None, + age: CommonAge = None, + first_name: str = None, + first_name_key: int = 0, + last_name: str = None, + last_name_key: int = 0, + full_name_key: int = 0, + breed_name: str = '', + breed_name_key: int = 0, + trait_ids: Iterator[int] = (), + household: Household = None, + source: str = 'testing' + ) -> Union[SimInfo, None]: + from sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils + household = household or CommonHouseholdUtils.create_empty_household(as_hidden_household=True) + vanilla_gender = CommonGender.convert_to_vanilla(gender) + vanilla_age = CommonAge.convert_to_vanilla(age) + vanilla_species = CommonSpecies.convert_to_vanilla(species) + if vanilla_species is None or vanilla_species == SpeciesExtended.INVALID: + raise AssertionError(f'Invalid species specified for SimInfo creation! {species}') + first_name = first_name or CommonSimNameUtils.create_random_first_name(gender, species=species) + last_name = last_name or CommonSimNameUtils.create_random_last_name(gender, species=species) + traits = tuple([CommonTraitUtils.load_trait_by_id(trait_id) for trait_id in trait_ids if CommonTraitUtils.load_trait_by_id(trait_id) is not None]) + from sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils + sim_creator = SimCreator( + gender=vanilla_gender, + age=vanilla_age, + species=vanilla_species, + first_name=first_name, + first_name_key=first_name_key, + last_name=last_name, + last_name_key=last_name_key, + full_name_key=full_name_key, + traits=traits, + breed_name=breed_name if breed_name else 'Custom Breed' if CommonSpeciesUtils.is_animal_species(vanilla_species) else '', + breed_name_key=breed_name_key if breed_name_key else CommonStringId.S4CL_CUSTOM_BREED if CommonSpeciesUtils.is_animal_species(vanilla_species) else 0, + ) + (sim_info_list, _) = SimSpawner.create_sim_infos((sim_creator,), household=household, generate_deterministic_sim=True, creation_source=source) + if not sim_info_list: + return None + return sim_info_list[0] + + @classmethod + def spawn_sim( + cls, + sim_info: SimInfo, + location: CommonLocation = None, + position: CommonVector3 = None, + **kwargs + ) -> bool: + """spawn_sim(sim_info, location=None, position=None, **kwargs) + + Spawn a Sim. + + ..note:: Do not provide sim_position or sim_location in kwargs as they are already specified as location and position. + + :param sim_info: The Sim to Spawn. + :type sim_info: SimInfo + :param location: The location to spawn the Sim at. Default is None. + :type location: CommonLocation, optional + :param position: The position to spawn the Sim at. Default is None. + :type position: CommonVector3, optional + :return: True, if the Sim was spawned successfully. False, if not. + :rtype: bool + """ + if sim_info is None: + return False + if CommonSimUtils.get_sim_instance(sim_info) is not None: + return True + from sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils + if CommonAgeUtils.is_baby(sim_info): + # Sim is baby, they spawn differently. + from sims.baby.baby_utils import create_and_place_baby + position_to_spawn_at = None + routing_surface_to_spawn = None + if position is not None: + position_to_spawn_at = position + routing_surface_to_spawn = CommonSurfaceIdentifier.empty() + if location is not None: + position_to_spawn_at = location.transform.translation + routing_surface_to_spawn = location.routing_surface + if position_to_spawn_at is None or routing_surface_to_spawn is None: + return False + create_and_place_baby(sim_info, position=position_to_spawn_at, routing_surface=routing_surface_to_spawn) + else: + SimSpawner.spawn_sim(sim_info, sim_location=location, sim_position=position, **kwargs) + + household = CommonHouseholdUtils.get_household(sim_info) + if household and CommonSimUtils.get_sim_instance(sim_info) is None: + sim_info.inject_into_inactive_zone(household.home_zone_id) + return True + + @classmethod + def spawn_sim_at_active_sim_location( + cls, + sim_info: SimInfo, + **kwargs + ) -> bool: + """spawn_sim_at_active_sim_location(sim_info, **kwargs) + + Spawn a Sim at the location of the Active Sim. + + :param sim_info: The Sim to Spawn. + :type sim_info: SimInfo + :return: True, if the Sim was spawned successfully. False, if not. + :rtype: bool + """ + from sims4communitylib.utils.sims.common_sim_location_utils import CommonSimLocationUtils + from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + active_sim_info = CommonSimUtils.get_active_sim_info() + active_location = CommonSimLocationUtils.get_location(active_sim_info) + active_position = None + if active_location is None: + active_position = CommonSimLocationUtils.get_position(active_sim_info) + return cls.spawn_sim(sim_info, location=active_location, position=active_position, **kwargs) + + @classmethod + def clone_sim( + cls, + source_sim_info: SimInfo, + add_to_household: bool = True, + household_override: Household = None + ) -> Union[SimInfo, None]: + """clone_sim(source_sim_info, add_to_household=True, household_override=None) + + Clone a Sim and add them to the household of source_sim_info. + + :param source_sim_info: The Sim to clone. + :type source_sim_info: SimInfo + :param add_to_household: If True, the Sim will be added to the household of "source_sim_info". If False, the Sim will be cloned into their own household. Default is True. + :type add_to_household: bool, optional + :param household_override: If specified, this household will be the one the cloned Sim will be added to. Default is None. + :type household_override: Household, optional + :return: The cloned Sim Info or None if cloning failed. + :rtype: Union[SimInfo, None] + """ + from sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils + if household_override is not None: + household = household_override + else: + if add_to_household: + household = CommonHouseholdUtils.get_household(source_sim_info) + if household is None: + raise Exception(f'No household was specified from source Sim {source_sim_info} with household {household}!') + else: + household = CommonHouseholdUtils.create_empty_household() + household_id = CommonHouseholdUtils.get_id(household) + species = CommonSpecies.get_species(source_sim_info) + gender = CommonGender.get_gender(source_sim_info) + vanilla_gender = CommonGender.convert_to_vanilla(gender) + clone_sim_data = cls._build_sim_data(source_sim_info) + clone_sim_info = cls._load_sim_data(clone_sim_data, trait_ids=tuple(source_sim_info.trait_tracker.equipped_traits), household=household, source='cloning sim') + # clone_sim_info = cls.create_sim_info( + # species=species, + # gender=gender, + # age=CommonAge.get_age(source_sim_info), + # first_name=SimSpawner.get_random_first_name(vanilla_gender, source_sim_info.species), + # last_name=source_sim_info._base.last_name, + # trait_ids=tuple(source_sim_info.trait_tracker.equipped_traits), + # household=household, + # source='cloning' + # ) + if clone_sim_info is None: + return None + # try: + # source_sim_proto = source_sim_info.save_sim(for_cloning=True) + # clone_sim_id = clone_sim_info.sim_id + # source_first_name = source_sim_info._base.first_name + # source_last_name = source_sim_info._base.last_name + # source_breed_name = source_sim_info._base.breed_name + # source_first_name_key = source_sim_info._base.first_name_key + # source_last_name_key = source_sim_info._base.last_name_key + # source_full_name_key = source_sim_info._base.full_name_key + # source_breed_name_key = source_sim_info._base.breed_name_key + # clone_first_name = clone_sim_info._base.first_name + # clone_last_name = clone_sim_info._base.last_name + # clone_breed_name = clone_sim_info._base.breed_name + # clone_first_name_key = clone_sim_info._base.first_name_key + # clone_last_name_key = clone_sim_info._base.last_name_key + # clone_full_name_key = clone_sim_info._base.full_name_key + # clone_breed_name_key = clone_sim_info._base.breed_name_key + # clone_sim_info.load_sim_info(source_sim_proto, is_clone=True, default_lod=SimInfoLODLevel.FULL) + # clone_sim_info.sim_id = clone_sim_id + # clone_sim_info._base.first_name = clone_first_name or source_first_name + # clone_sim_info._base.last_name = clone_last_name or source_last_name + # clone_sim_info._base.breed_name = clone_breed_name or source_breed_name + # clone_sim_info._base.first_name_key = clone_first_name_key or source_first_name_key + # clone_sim_info._base.last_name_key = clone_last_name_key or source_last_name_key + # clone_sim_info._base.full_name_key = clone_full_name_key or source_full_name_key + # clone_sim_info._base.breed_name_key = clone_breed_name_key or source_breed_name_key + # clone_sim_info._household_id = household_id + # source_trait_tracker = source_sim_info.trait_tracker + # clone_trait_tracker = clone_sim_info.trait_tracker + # for trait in clone_trait_tracker.personality_traits: + # if not source_trait_tracker.has_trait(trait): + # clone_sim_info.remove_trait(trait) + # for trait in clone_trait_tracker.gender_option_traits: + # if not source_trait_tracker.has_trait(trait): + # clone_sim_info.remove_trait(trait) + # CommonSimUtils.get_sim_info_manager().set_default_genealogy(sim_infos=(clone_sim_info,)) + # clone_sim_info.set_default_data() + # clone_sim_info.save_sim() + # household.save_data() + # if not household.is_active_household: + # clone_sim_info.request_lod(SimInfoLODLevel.BASE) + # clone_sim_info.resend_physical_attributes() + # except Exception as ex: + # cls.delete_sim(clone_sim_info) + # raise ex + return clone_sim_info + + # Load + @classmethod + def _load_sim_data( + cls, + sim_save_data: Dict[str, Any], + trait_ids: Tuple[int] = (), + household: Household = None, + source: str = 'testing' + ) -> Union[SimInfo, None]: + """load_sim_data(\ + sim_save_data,\ + trait_ids=(),\ + household=None,\ + source='testing'\ + ) + + Create a Sim Info from a dictionary of data. + + :param sim_save_data: + :param trait_ids: + :param household: + :param source: + :return: + """ + species_str: str = sim_save_data.get('species', None) + if species_str is None: + return None + species = CommonResourceUtils.get_enum_by_name(species_str, CommonSpecies, default_value=None) + if species is None: + return None + gender_str = sim_save_data.get('gender', None) + if gender_str is None: + return None + gender = CommonResourceUtils.get_enum_by_name(gender_str, CommonGender, default_value=None) + if gender is None: + return None + age_str = sim_save_data.get('age', None) + if age_str is None: + return None + age = CommonResourceUtils.get_enum_by_name(age_str, CommonAge, default_value=None) + if age is None: + return None + first_name: str = sim_save_data.get('first_name', None) + last_name: str = sim_save_data.get('last_name', None) + from sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils + household = household or CommonHouseholdUtils.create_empty_household(as_hidden_household=True) + vanilla_gender = CommonGender.convert_to_vanilla(gender) + vanilla_age = CommonAge.convert_to_vanilla(age) + vanilla_species = CommonSpecies.convert_to_vanilla(species) + if vanilla_species is None or vanilla_species == SpeciesExtended.INVALID: + log.format_with_message('The required pack for Sim was not available.', species=species) + return None + first_name = first_name or CommonSimNameUtils.create_random_first_name(gender, species=species) + last_name = last_name or CommonSimNameUtils.create_random_last_name(gender, species=species) + traits = tuple([CommonTraitUtils.load_trait_by_id(trait_id) for trait_id in trait_ids if CommonTraitUtils.load_trait_by_id(trait_id) is not None]) + from sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils + breed_name = sim_save_data.get('breed_name', '') + first_name_key = sim_save_data.get('first_name_key', 0) + last_name_key = sim_save_data.get('last_name_key', 0) + full_name_key = sim_save_data.get('full_name_key', 0) + breed_name_key = sim_save_data.get('breed_name_key', 0) + sim_creator = SimCreator( + gender=vanilla_gender, + age=vanilla_age, + species=vanilla_species, + first_name=first_name, + first_name_key=first_name_key, + last_name=last_name, + last_name_key=last_name_key, + full_name_key=full_name_key, + traits=traits, + breed_name=breed_name if breed_name else 'Custom Breed' if CommonSpeciesUtils.is_animal_species(vanilla_species) else '', + breed_name_key=breed_name_key if breed_name_key else 0x599432EA if CommonSpeciesUtils.is_animal_species(vanilla_species) else 0 + ) + (sim_info_list, _) = SimSpawner.create_sim_infos((sim_creator,), household=household, generate_deterministic_sim=True, creation_source=source) + if not sim_info_list: + return None + sim_info: SimInfo = sim_info_list[0] + + time_stamp = time.time() + sim_info._base.species = vanilla_species + # noinspection PyPropertyAccess + extended_species = sim_info.extended_species + sim_info._species = SpeciesExtended.get_species(extended_species) + required_pack = SpeciesExtended.get_required_pack(extended_species) + if required_pack is not None and not CommonGamePackUtils.has_game_pack_available(required_pack): + log.format_with_message('The required pack for Sim was not available.', species=extended_species) + return None + species_def = None + if indexed_manager.capture_load_times: + species_def = sim_info.get_sim_definition(sim_info.species) + if species_def not in indexed_manager.object_load_times: + indexed_manager.object_load_times[species_def] = indexed_manager.ObjectLoadData() + + lod_str = sim_save_data.get('lod', None) + if lod_str is not None: + lod = CommonResourceUtils.get_enum_by_name(lod_str, SimInfoLODLevel, default_value=SimInfoLODLevel.BACKGROUND) + else: + lod = SimInfoLODLevel.BACKGROUND + sim_info._lod = lod + sim_info._initialize_sim_info_trackers(sim_info._lod) + skip_load = False + if gender == CommonGender.MALE or gender == CommonGender.FEMALE: + sim_info._base.gender = vanilla_gender + sim_info._base.age = vanilla_age + from sims.sim_info import lod_logger + from sims.sim_info import INJECT_LOD_NAME_IN_CALLSTACK + if not INJECT_LOD_NAME_IN_CALLSTACK: + cls._load_sim_info(sim_info, sim_save_data, skip_load, household) + time_elapsed = time.time() - time_stamp + if indexed_manager.capture_load_times: + indexed_manager.object_load_times[species_def].time_spent_loading += time_elapsed + indexed_manager.object_load_times[species_def].loads += 1 + lod_logger.info('Loaded {} with lod {} in {} seconds.', sim_info.full_name, sim_info._lod.name, time_elapsed) + from sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils + current_outfit = CommonOutfitUtils.get_current_outfit(sim_info) + sim_info.outfit_type_and_index = current_outfit + sim_info.resend_outfits() + return sim_info + from sims4.profiler_utils import create_custom_named_profiler_function + name_f = create_custom_named_profiler_function('Load LOD {} SimInfo'.format(sim_info._lod.name)) + name_f(lambda: cls._load_sim_info(sim_info, sim_save_data, skip_load, household)) + if indexed_manager.capture_load_times: + time_elapsed = time.time() - time_stamp + indexed_manager.object_load_times[species_def].time_spent_loading += time_elapsed + indexed_manager.object_load_times[species_def].loads += 1 + lod_logger.info('Loaded {} with lod {} in {} seconds.', sim_info.full_name, sim_info._lod.name, time_elapsed) + from sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils + current_outfit = CommonOutfitUtils.get_current_outfit(sim_info) + sim_info._base.outfit_type_and_index = current_outfit + sim_info.resend_outfits() + sim_info.on_outfit_generated(*current_outfit) + sim_info.set_outfit_dirty(current_outfit[0]) + sim_info.set_current_outfit(current_outfit) + sim_info._set_fit_fat() + return sim_info + + @classmethod + def _load_sim_info( + cls, + sim_info: SimInfo, + sim_save_data: Dict[str, Any], + skip_load: bool, + household: Household + ) -> None: + species_str: str = sim_save_data.get('species', None) + if species_str is None: + return None + species = CommonResourceUtils.get_enum_by_name(species_str, CommonSpecies, default_value=None) + if species is None: + return None + gender_str = sim_save_data.get('gender', None) + if gender_str is None: + return None + gender = CommonResourceUtils.get_enum_by_name(gender_str, CommonGender, default_value=None) + if gender is None: + return None + age_str = sim_save_data.get('age', None) + if age_str is None: + return None + age = CommonResourceUtils.get_enum_by_name(age_str, CommonAge, default_value=None) + if age is None: + return None + first_name: str = sim_save_data.get('first_name', None) + last_name: str = sim_save_data.get('last_name', None) + vanilla_species = CommonSpecies.convert_to_vanilla(species) + if vanilla_species is None or vanilla_species == SpeciesExtended.INVALID: + log.format_with_message('The required pack for Sim was not available.', species=species) + return None + first_name = first_name or CommonSimNameUtils.create_random_first_name(gender, species=species) + last_name = last_name or CommonSimNameUtils.create_random_last_name(gender, species=species) + breed_name = sim_save_data.get('breed_name', '') + first_name_key = sim_save_data.get('first_name_key', 0) + last_name_key = sim_save_data.get('last_name_key', 0) + full_name_key = sim_save_data.get('full_name_key', 0) + breed_name_key = sim_save_data.get('breed_name_key', 0) + + sim_info._base.first_name = first_name + sim_info._base.last_name = last_name + sim_info._base.breed_name = breed_name + sim_info._base.first_name_key = first_name_key + sim_info._base.last_name_key = last_name_key + sim_info._base.full_name_key = full_name_key + sim_info._base.breed_name_key = breed_name_key + + pronouns = sim_save_data.get('pronouns_data', None) + if pronouns is not None: + cls._load_pronouns_data(sim_info._base, pronouns) + + from objects.components.consumable_component import ConsumableComponent + sim_info.commodity_tracker.set_value(ConsumableComponent.FAT_COMMODITY, sim_save_data.get('fat')) + sim_info.commodity_tracker.set_value(ConsumableComponent.FIT_COMMODITY, sim_save_data.get('fit')) + + sim_info._household_id = CommonHouseholdUtils.get_id(household) + sim_info._serialization_option = SimSerializationOption.UNDECLARED + physical_attributes = sim_save_data.get('physical_attributes', None) + if physical_attributes is not None: + cls._load_physical_attributes(sim_info, physical_attributes) + sim_info.custom_texture = sim_save_data.get('custom_texture', 0) + + # noinspection SpellCheckingInspection + sim_info.do_first_sim_info_load_fixups = True + sim_info._get_fit_fat() + + # if sim_attribute_data is not None: + # sim_info.set_trait_ids_on_base(trait_ids_override=list(set(itertools.chain(sim_attribute_data.trait_tracker.trait_ids, sim_info.trait_ids)))) + + age_progress = sim_save_data.get('age_progress', 0) + sim_info._age_progress.set_value(age_progress) + + primary_aspiration_id = sim_save_data.get('primary_aspiration', 0) + primary_aspiration = CommonResourceUtils.load_instance(Types.ASPIRATION_TRACK, primary_aspiration_id) + if primary_aspiration is not None: + sim_info._primary_aspiration = primary_aspiration + + outfit_data = sim_save_data.get('outfit_data', None) + if outfit_data is not None: + cls._load_outfit_data(sim_info._base, outfit_data) + + initial_fitness_value = sim_save_data.get('initial_fitness_value', None) + if initial_fitness_value is not None: + sim_info._initial_fitness_value = initial_fitness_value + + # if sim_attribute_data is not None: + # sim_info._relationship_tracker.load(sim_attribute_data.relationship_tracker.relationships) + # sim_info._genealogy_tracker.load_genealogy(sim_attribute_data.genealogy_tracker) + + death_data = sim_save_data.get('death_data', None) + if death_data is not None: + cls._load_death_data(sim_info, death_data) + + sim_occult_data = sim_save_data.get('occult_data', None) + if sim_occult_data is not None: + cls._load_occult_data(sim_info, sim_occult_data) + # if sim_proto.significant_other != 0: + # sim_info.update_spouse_sim_id(sim_proto.significant_other) + # if sim_proto.fiance != 0: + # sim_info.update_fiance_sim_id(sim_proto.fiance) + Ghost.make_ghost_if_needed(sim_info) + + # sim_info._build_buy_unlocks = set() + # old_unlocks = set(list(sim_proto.gameplay_data.build_buy_unlocks)) + # for unlock in old_unlocks: + # if isinstance(unlock, int): + # key = sims4.resources.Key(Types.OBJCATALOG, unlock, 0) + # sim_info._build_buy_unlocks.add(key) + # if hasattr(sim_proto.gameplay_data, 'build_buy_unlock_list'): + # for key_proto in sim_proto.gameplay_data.build_buy_unlock_list.resource_keys: + # key = sims4.resources.Key(key_proto.type, key_proto.instance, key_proto.group) + # sim_info._build_buy_unlocks.add(key) + if not CommonAgeUtils.is_baby_or_toddler(sim_info): + available_aspirations = list() + aspiration_track_manager = CommonResourceUtils.get_instance_manager(Types.ASPIRATION_TRACK) + for aspiration_track in aspiration_track_manager.types.values(): + if aspiration_track.is_hidden_unlockable or aspiration_track.is_valid_for_sim(sim_info): + available_aspirations.append(aspiration_track) + sim_info._primary_aspiration = random.choice(available_aspirations) + + # sim_info._cached_inventory_value = sim_proto.gameplay_data.inventory_value + # if sim_info._primary_aspiration is None or sim_info._primary_aspiration.is_available() or sim_info.is_human and skip_load or sim_info._away_action_tracker is not None: + # sim_info._away_action_tracker.load_away_action_info_from_proto(sim_proto.gameplay_data.away_action_tracker) + # sim_info.spawn_point_id = sim_proto.gameplay_data.spawn_point_id if sim_proto.gameplay_data.HasField('spawn_point_id') else None + # sim_info.spawn_point_option = SpawnPointOption(sim_proto.gameplay_data.spawn_point_option) if sim_proto.gameplay_data.HasField('spawn_point_option') else SpawnPointOption.SPAWN_ANY_POINT_WITH_CONSTRAINT_TAGS + # sim_info.spawner_tags = [] + # if sim_proto.gameplay_data.HasField('time_alive'): + # time_alive = TimeSpan(sim_proto.gameplay_data.time_alive) + # else: + # time_alive = None + sim_info.load_time_alive(None) + # for spawner_tag in sim_proto.gameplay_data.spawner_tags: + # sim_info.spawner_tags.append(tag.Tag(spawner_tag)) + try: + sim_info.Buffs.load_in_progress = True + sim_info.commodity_tracker.load_in_progress = True + sim_info.on_base_characteristic_changed() + with services.relationship_service().suppress_client_updates_context_manager(): + trait_data = sim_save_data.get('trait_data', None) + if trait_data: + cls._load_trait_data(sim_info, trait_data, skip_load) + finally: + sim_info.Buffs.load_in_progress = False + sim_info.commodity_tracker.load_in_progress = False + + sim_info._create_additional_statistics() + # if sim_info._whim_tracker is not None: + # sim_info._whim_tracker.cache_whim_goal_proto(sim_proto.gameplay_data.whim_tracker, skip_load=skip_load) + # if sim_info._satisfaction_tracker is not None: + # sim_info._satisfaction_tracker.set_satisfaction_points(sim_proto.gameplay_data.whim_bucks, SetWhimBucks.LOAD) + current_outfit_info = sim_save_data.get('current_outfit_info', None) + if current_outfit_info is not None: + current_outfit_category_str = current_outfit_info.get('outfit_category', 'EVERYDAY') + current_outfit_category = CommonResourceUtils.get_enum_by_name(current_outfit_category_str, OutfitCategory, default_value=OutfitCategory.EVERYDAY) + current_outfit_index = current_outfit_info.get('outfit_index', 0) + sim_info._set_current_outfit_without_distribution((current_outfit_category, current_outfit_index)) + + # sim_info._load_inventory(sim_proto, skip_load) + additional_bonus_days = sim_save_data.get('additional_bonus_days', 0) + sim_info._additional_bonus_days = additional_bonus_days + + favorite_recipe_ids = sim_save_data.get('favorite_recipe_ids', None) + if favorite_recipe_ids is not None: + recipe_manager = CommonResourceUtils.get_instance_manager(Types.RECIPE) + for recipe_id in favorite_recipe_ids: + recipe = recipe_manager.get(recipe_id) + if recipe is not None: + sim_info.set_favorite_recipe(recipe) + + # if sim_proto.gameplay_data.zone_time_stamp.HasField('time_sim_was_saved'): + # sim_info._time_sim_was_saved = DateAndTime(sim_proto.gameplay_data.zone_time_stamp.time_sim_was_saved) + # if skip_load or sim_proto.gameplay_data.zone_time_stamp.game_time_expire != 0: + # sim_info.game_time_bring_home = sim_proto.gameplay_data.zone_time_stamp.game_time_expire + + try: + sim_info.Buffs.load_in_progress = True + sim_info._blacklisted_statistics_cache = sim_info.get_blacklisted_statistics() + + sim_statistic_data = sim_save_data.get('statistics_data', None) + if sim_statistic_data is not None: + cls._load_statistic_data(sim_info, sim_statistic_data, skip_load) + + sim_commodity_data = sim_save_data.get('commodity_data', None) + if sim_commodity_data is not None: + cls._load_commodity_data(sim_info, sim_commodity_data, skip_load) + + if sim_info.is_human: + trait_statistic_data = sim_save_data.get('trait_statistic_data', None) + if trait_statistic_data is not None: + cls._load_trait_statistic_data(sim_info, trait_statistic_data) + + if sim_commodity_data is not None: + skill_data = sim_commodity_data.get('skills', None) + if skill_data: + skills_to_check_for_unlocks = [commodity for commodity in sim_info.commodity_tracker.get_all_commodities() if commodity.unlocks_skills_on_max() and len(commodity.skill_unlocks_on_max) > 0] + if skills_to_check_for_unlocks: + cls._update_unlock_skills(sim_info, skills_to_check_for_unlocks, skill_data) + + suntan_data = sim_save_data.get('suntan_data', None) + if suntan_data is not None: + cls._load_suntan_data(sim_info, suntan_data) + + # sim_info._pregnancy_tracker.load(sim_attribute_data.pregnancy_tracker) + appearance_data = sim_save_data.get('appearance_data', None) + if appearance_data is not None: + cls._load_appearance_data(sim_info, appearance_data) + + # if sim_attribute_data.HasField('sickness_tracker'): + # sim_info.sickness_tracker.load_sickness_tracker_data(sim_attribute_data.sickness_tracker) + # if sim_info.has_sickness_tracking(): + # sim_info.current_sickness.on_sim_info_loaded(sim_info) + # if sim_attribute_data.HasField('stored_object_info_component'): + # component_def = objects.components.types.STORED_OBJECT_INFO_COMPONENT + # if sim_info.add_dynamic_component(component_def): + # stored_object_info_component = sim_info.get_component(component_def) + # stored_object_info_component.load_stored_object_info(sim_attribute_data.stored_object_info_component) + # for entry in sim_attribute_data.object_preferences.preferences: + # sim_info._autonomy_scoring_preferences[entry.tag] = entry.object_id + # for entry in sim_attribute_data.object_ownership.owned_object: + # sim_info._autonomy_use_preferences[entry.tag] = entry.object_id + # sim_info._career_tracker.load(sim_attribute_data.sim_careers, skip_load=skip_load) + # if sim_info._adventure_tracker is not None: + # sim_info._adventure_tracker.load(sim_attribute_data.adventure_tracker) + # if sim_info._notebook_tracker is not None: + # sim_info._notebook_tracker.load_notebook(sim_attribute_data.notebook_tracker) + # if sim_info._royalty_tracker is not None and not skip_load: + # sim_info._royalty_tracker.load(sim_attribute_data.royalty_tracker) + # if sim_info._unlock_tracker is not None: + # skip_load = skip_load and not is_clone + # sim_info._unlock_tracker.load_unlock(sim_attribute_data.unlock_tracker, skip_load=skip_load) + # if sim_info._relic_tracker is not None and not skip_load: + # sim_info._relic_tracker.load(sim_attribute_data.relic_tracker) + # if sim_info._lifestyle_brand_tracker is not None and not skip_load: + # sim_info._lifestyle_brand_tracker.load(sim_attribute_data.lifestyle_brand_tracker) + # if sim_info._favorites_tracker is not None and not skip_load: + # sim_info._favorites_tracker.load(sim_attribute_data.favorites_tracker) + # if sim_info._degree_tracker is not None: + # sim_info.degree_tracker.load(sim_attribute_data.degree_tracker) + # if sim_info._organization_tracker is not None and not skip_load: + # sim_info._organization_tracker.load(sim_attribute_data.organization_tracker) + # if sim_info._fixup_tracker is not None and not skip_load: + # sim_info._fixup_tracker.load(sim_attribute_data.fixup_tracker) + # if sim_info._story_progression_tracker is not None and not skip_load: + # sim_info._story_progression_tracker.load(sim_attribute_data.story_progression_tracker) + # if sim_info._lunar_effect_tracker is not None and not skip_load: + # sim_info._lunar_effect_tracker.load_lunar_effects(sim_attribute_data.lunar_effect_tracker) + except Exception as ex: + log.error(f'Failed to load attributes for sim {sim_info._base.first_name}.', exception=ex, throw=False) + finally: + sim_info._blacklisted_statistics_cache = None + sim_info.Buffs.load_in_progress = False + + sim_info._setup_fitness_commodities() + sim_info._trait_tracker.fixup_gender_preference_statistics() + sim_info._add_gender_preference_listeners() + + # if sim_info._serialization_option != SimSerializationOption.UNDECLARED: + # world_coord = sims4.math.Transform() + # location = sim_proto.gameplay_data.location + # world_coord.translation = sims4.math.Vector3(location.x, location.y, location.z) + # world_coord.orientation = sims4.math.Quaternion(location.rot_x, location.rot_y, location.rot_z, location.rot_w) + # sim_info._transform_on_load = world_coord + # sim_info._level_on_load = location.level + # sim_info._surface_id_on_load = location.surface_id + + # sim_info._si_state = gameplay_serialization.SuperInteractionSaveState() + # if skip_load or sim_proto.gameplay_data.HasField('location') and sim_proto.gameplay_data.HasField('interaction_state'): + # sim_info._has_loaded_si_state = True + # sim_info._si_state.MergeFrom(sim_proto.gameplay_data.interaction_state) + + services.sim_info_manager().add_sim_info_if_not_in_manager(sim_info) + + bucks_data = sim_save_data.get('bucks_data', None) + if bucks_data is not None: + cls._load_bucks_data(sim_info, bucks_data) + + # if sim_proto.gameplay_data.HasField('gameplay_options'): + # sim_info._gameplay_options = sim_proto.gameplay_data.gameplay_options + # if sim_info.get_gameplay_option(SimInfoGameplayOptions.FORCE_CURRENT_ALLOW_FAME_SETTING) and not sim_info.get_gameplay_option(SimInfoGameplayOptions.ALLOW_FAME): + # sim_info.allow_fame = False + # elif sim_info.get_gameplay_option(SimInfoGameplayOptions.FREEZE_FAME): + # sim_info.set_freeze_fame(True, force=True) + # for squad_member_id in sim_proto.gameplay_data.squad_members: + # sim_info.add_sim_info_id_to_squad(squad_member_id) + # if sim_proto.gameplay_data.HasField('vehicle_id'): + # sim_info._vehicle_id = sim_proto.gameplay_data.vehicle_id + sim_info._post_load() + + @classmethod + def _load_bucks_data( + cls, + sim_info: SimInfo, + sim_bucks_data: Dict[str, Any], + ): + bucks_tracker = sim_info.get_bucks_tracker(add_if_none=True) + + bucks_perk_manager = CommonResourceUtils.get_instance_manager(Types.BUCKS_PERK) + for bucks_data in sim_bucks_data.get('bucks', tuple()): + bucks_type_str = bucks_data.get('bucks_type', None) + if bucks_type_str is None: + continue + bucks_type = CommonResourceUtils.get_enum_by_name(bucks_type_str, CommonBucksType, default_value=None) + if bucks_type is None: + continue + bucks_amount = bucks_data.get('amount', 0) + + if bucks_amount >= 0: + vanilla_bucks_type = CommonBucksType.convert_to_vanilla(bucks_type) + bucks_tracker.try_modify_bucks(vanilla_bucks_type, bucks_amount, allow_distribute=False, from_load=True) + + for perk_data in bucks_data.get('perk_data', tuple()): + perk_id = perk_data.get('perk_id', None) + if perk_id is None: + continue + perk_ref = bucks_perk_manager.get(perk_id) + if perk_ref is None: + log.format_with_message('Trying to load unavailable BUCKS_PERK resource', perk_id=perk_id) + continue + unlock_reason = perk_data.get('unlock_reason', None) + if unlock_reason is not None: + unlocked_by = bucks_perk_manager.get(unlock_reason) + else: + unlocked_by = None + timestamp = CommonTimeUtils.get_current_date_and_time() + currently_unlocked = perk_data.get('currently_unlocked', False) + bucks_tracker._unlocked_perks[perk_ref.associated_bucks_type][perk_ref] = PerkData(unlocked_by, timestamp, currently_unlocked) + if currently_unlocked: + bucks_tracker._award_buffs(perk_ref) + bucks_tracker._award_traits(perk_ref) + time_left = perk_data.get('time_left', None) + if time_left is not None: + bucks_tracker._set_up_temporary_perk_timer(perk_ref, time_left) + + @classmethod + def _load_trait_data( + cls, + sim_info: SimInfo, + sim_trait_data: Dict[str, Any], + skip_load: bool + ): + from traits.trait_quirks import add_quirks + trait_tracker = sim_info._trait_tracker + saved_trait_ids = sim_trait_data.get('trait_ids', tuple()) + trait_manager = CommonResourceUtils.get_instance_manager(Types.TRAIT) + try: + trait_tracker._load_in_progress = True + trait_tracker._sim_info._update_age_trait(trait_tracker._sim_info.age) + pre_made_sim_needing_fixup = bool(trait_tracker._sim_info.sim_template_id) + for trait_instance_id in saved_trait_ids: + trait = trait_manager.get(trait_instance_id, None) + if trait is None: + continue + if not trait_tracker._has_valid_lod(trait): + if trait.min_lod_value == SimInfoLODLevel.ACTIVE: + if trait_tracker._delayed_active_lod_traits is None: + trait_tracker._delayed_active_lod_traits = list() + trait_tracker._delayed_active_lod_traits.append(trait) + if skip_load and not (pre_made_sim_needing_fixup or trait.allow_from_gallery): + continue + else: + trait_tracker._sim_info.add_trait(trait) + elif skip_load and not (pre_made_sim_needing_fixup or trait.allow_from_gallery): + continue + else: + trait_tracker._sim_info.add_trait(trait) + if trait_tracker.personality_traits or not trait_tracker._sim_info.is_baby: + possible_traits = [trait for trait in trait_manager.types.values() if trait.is_personality_trait and trait_tracker.can_add_trait(trait)] + if possible_traits: + chosen_trait = random.choice(possible_traits) + trait_tracker._add_trait(chosen_trait) + trait_tracker._add_default_gender_option_traits() + add_quirks(trait_tracker._sim_info) + trait_tracker._sim_info.on_all_traits_loaded() + finally: + trait_tracker._load_in_progress = False + + @classmethod + def _load_outfit_data( + cls, + sim_info: SimInfo, + outfit_data_external: Dict[str, Any] + ): + outfits_msg = Outfits_pb2.OutfitList() + parsed_outfits = list() + for (outfit_category_name, outfit_data_list) in outfit_data_external.items(): + outfit_category = CommonResourceUtils.get_enum_by_name(outfit_category_name, OutfitCategory, default_value=None) + if outfit_category is None: + continue + for outfit_data in outfit_data_list: + outfit = Outfits_pb2.OutfitData() + outfit.category = int(outfit_category) + part_data_list = outfit_data.get('part_data_list', None) + if part_data_list is None: + continue + body_types = list() + part_ids = list() + part_color_shifts = list() + added_parts = False + for part_data in part_data_list: + body_type = part_data.get('body_type', None) + part_id = part_data.get('part_id', None) + part_color_shift = part_data.get('part_color_shift', None) + if body_type is None or part_id is None or part_color_shift is None: + continue + if not CommonCASUtils.is_cas_part_loaded(part_id)\ + and int(body_type) in ( + int(BodyType.LOWER_BODY), + int(BodyType.UPPER_BODY), + int(BodyType.FULL_BODY), + int(BodyType.SHOES) + ): + added_parts = False + break + added_parts = True + body_types.append(body_type) + part_ids.append(part_id) + part_color_shifts.append(part_color_shift) + + if not added_parts: + continue + + outfit.body_types_list = Outfits_pb2.BodyTypesList() + # noinspection PyUnresolvedReferences + outfit.body_types_list.body_types.extend(body_types) + outfit.parts = S4Common_pb2.IdList() + # noinspection PyUnresolvedReferences + outfit.parts.ids.extend(part_ids) + outfit.part_shifts = Outfits_pb2.ColorShiftList() + # noinspection PyUnresolvedReferences + outfit.part_shifts.color_shift.extend(part_color_shifts) + + # noinspection PyUnresolvedReferences + outfit.outfit_id = outfit_data.get('outfit_id') + # noinspection PyUnresolvedReferences + outfit.outfit_flags = outfit_data.get('outfit_flags') + # noinspection PyUnresolvedReferences + outfit.outfit_flags_high = outfit_data.get('outfit_flags_high') + outfit.title = outfit_data.get('title') + outfit.match_hair_style = outfit_data.get('match_hair_style') + outfit.created = outfit_data.get('created') + parsed_outfits.append(outfit) + + # noinspection PyUnresolvedReferences + outfits_msg.outfits.extend(parsed_outfits) + + try: + sim_info.outfits = outfits_msg.SerializeToString() + except Exception as ex: + log.format_error_with_message('An error occurred when attempting to load outfit data for Slave.', outfit_data_external=outfit_data_external, exception=ex) + + @classmethod + def _update_unlock_skills( + cls, + sim_info: SimInfo, + skills: Iterator[Skill], + sim_loading_skills: List[Dict[str, Any]] + ): + open_set = set(skills) + closed_set = set() + while open_set: + current_skill = open_set.pop() + closed_set.add(current_skill) + if not current_skill.reached_max_level: + continue + + for skill_to_unlock in current_skill.skill_unlocks_on_max: + if skill_to_unlock not in closed_set: + sim_info.commodity_tracker.add_statistic(skill_to_unlock, force_add=True) + skill_data_objects = [sdo for sdo in sim_loading_skills if sdo.get('stat_id', 0) == skill_to_unlock.guid64] + cls._load_commodity_tracker_data(sim_info, skill_data_objects) + open_set.add(skill_to_unlock) + + @classmethod + def _load_commodity_tracker_data( + cls, + sim_info: SimInfo, + statistics_data: List[Dict[str, Any]], + skip_load=False, + update_affordance_cache=True + ): + commodity_tracker = sim_info.commodity_tracker + statistic_manager = CommonResourceUtils.get_instance_manager(Types.STATISTIC) + try: + commodity_tracker.load_in_progress = True + owner_lod = commodity_tracker._owner.lod if isinstance(commodity_tracker._owner, SimInfo) else None + for statistic_data in statistics_data: + stat_id = statistic_data.get('stat_id', 0) + if stat_id == 0: + continue + stat_value = statistic_data.get('stat_value', 0) + commodity_class = statistic_manager.get(stat_id) + if commodity_class is None: + log.format_with_message('Trying to load unavailable STATISTIC resource', skill_id=stat_id) + continue + elif not commodity_class.persisted: + log.format_with_message('Trying to load unavailable STATISTIC resource', skill_id=stat_id) + continue + elif commodity_tracker.statistics_to_skip_load is not None and commodity_class in commodity_tracker.statistics_to_skip_load: + continue + elif commodity_class.is_skill and stat_value == commodity_class.initial_value: + continue + elif skip_load and commodity_class.remove_on_convergence: + log.format_with_message('Not loading skill because load is not required.', commodity_class=commodity_class) + continue + elif not commodity_tracker._should_add_commodity_from_gallery(commodity_class, skip_load): + continue + elif owner_lod is not None and owner_lod < commodity_class.min_lod_value: + if commodity_class.min_lod_value >= SimInfoLODLevel.ACTIVE: + if commodity_tracker._delayed_active_lod_statistics is None: + commodity_tracker._delayed_active_lod_statistics = list() + commodity_tracker._delayed_active_lod_statistics.append((stat_id, stat_value)) + commodity_tracker.set_value(commodity_class, stat_value, from_load=True) + # if commodity_class.is_commodity: + # stat = commodity_tracker.get_statistic(commodity_class) + # if stat is not None: + # stat.force_apply_buff_on_start_up = data.apply_buff_on_start_up + # if data.buff_reason.hash: + # stat.force_buff_reason = Localization_pb2.LocalizedString() + # stat.force_buff_reason.MergeFrom(data.buff_reason) + # stat.load_time_of_last_value_change(data) + # elif commodity_class.is_ranked: + # stat = commodity_tracker.get_statistic(commodity_class) + # if stat is not None: + # stat._initial_loots_awarded = data.initial_loots_awarded + # stat._inclusive_rank_threshold = data.inclusive_rank_threshold + # stat.set_level_and_rank() + # stat.highest_level = data.highest_level + # stat.load_time_of_last_value_change(data) + # stat.fixup_callbacks_during_load() + continue + else: + commodity_tracker.set_value(commodity_class, stat_value, from_load=True) + # if commodity_class.is_commodity: + # stat = commodity_tracker.get_statistic(commodity_class) + # if stat is not None: + # stat.force_apply_buff_on_start_up = data.apply_buff_on_start_up + # if data.buff_reason.hash: + # stat.force_buff_reason = Localization_pb2.LocalizedString() + # stat.force_buff_reason.MergeFrom(data.buff_reason) + # stat.load_time_of_last_value_change(data) + # elif commodity_class.is_ranked: + # stat = commodity_tracker.get_statistic(commodity_class) + # if stat is not None: + # stat._initial_loots_awarded = data.initial_loots_awarded + # stat._inclusive_rank_threshold = data.inclusive_rank_threshold + # stat.set_level_and_rank() + # stat.highest_level = data.highest_level + # stat.load_time_of_last_value_change(data) + # stat.fixup_callbacks_during_load() + continue + finally: + commodity_tracker.statistics_to_skip_load = None + commodity_tracker.load_in_progress = False + if update_affordance_cache: + commodity_tracker.update_affordance_caches() + + @classmethod + def _load_appearance_data( + cls, + sim_info: SimInfo, + sim_appearance_data: Dict[str, Any] + ): + appearance_tracker = sim_info.appearance_tracker + for appearance_item_data in sim_appearance_data.get('appearance_items', tuple()): + guid = appearance_item_data.get('guid', None) + if guid is None: + continue + seed = appearance_item_data.get('seed', None) + if seed is None: + continue + appearance_tracker.add_persistent_appearance_modifier_data(guid, seed) + + @classmethod + def _load_suntan_data( + cls, + sim_info: SimInfo, + sim_suntan_data: Dict[str, Any] + ): + suntan_tracker = sim_info._suntan_tracker + suntan_tracker._tan_level = sim_suntan_data.get('tan_level', 0) + + suntan_parts = sim_suntan_data.get('suntan_parts', tuple()) + if suntan_parts: + if suntan_tracker._outfit_part_data_list is None: + suntan_tracker._outfit_part_data_list = [] + else: + suntan_tracker._outfit_part_data_list.clear() + + for part_data in suntan_parts: + part_id = part_data.get('part_id', None) + if part_id is None: + continue + body_type_value = part_data.get('body_type', None) + if body_type_value is None: + continue + body_type = CommonCASUtils.convert_value_to_body_type(body_type_value) + suntan_tracker._outfit_part_data_list.append((part_id, body_type)) + + @classmethod + def _load_trait_statistic_data( + cls, + sim_info: SimInfo, + sim_statistic_data: Dict[str, Any] + ): + trait_statistic_tracker = sim_info.trait_statistic_tracker + if trait_statistic_tracker._statistics is None: + return None + trait_statistic_data = dict() + trait_statistics = list() + for statistic in sorted(list(trait_statistic_tracker._statistics.values()), key=lambda x: x.guid64 if x is not None and hasattr(x, 'guid64') else 0): + stat_data = dict() + stat_id = statistic.guid64 + if stat_id is None or stat_id == 0: + continue + stat_data['stat_id'] = stat_id + stat_data['stat_value'] = statistic.get_value() + stat_data['stat_state'] = statistic._state.name + if statistic._neglect_buff_index is not None: + stat_data['neglect_buff_index'] = statistic._neglect_buff_index + stat_data['value_added'] = statistic._value_added + if statistic._max_daily_cap is not None: + stat_data['max_daily_cap'] = statistic._max_daily_cap + if statistic._min_daily_cap is not None: + stat_data['min_daily_cap'] = statistic._min_daily_cap + trait_statistics.append(stat_data) + if trait_statistics: + trait_statistic_data['trait_statistics'] = trait_statistics + if not trait_statistic_data: + return None + + statistic_manager = CommonResourceUtils.get_instance_manager(Types.STATISTIC) + for trait_statistic_data in sim_statistic_data.get('trait_statistics', tuple()): + stat_id = trait_statistic_data.get('stat_id', None) + if stat_id is None: + continue + stat_value = trait_statistic_data.get('stat_value', None) + if stat_value is None: + continue + statistic_type = statistic_manager.get(stat_id) + if statistic_type is None: + continue + trait_state_name = trait_statistic_data.get('stat_state', None) + if trait_state_name is None: + continue + trait_state = CommonResourceUtils.get_enum_by_name(trait_state_name, TraitStatisticStates, default_value=None) + if trait_state is None: + continue + if trait_statistic_tracker.owner.lod >= statistic_type.min_lod_value: + stat: TraitStatistic = trait_statistic_tracker.add_statistic(statistic_type, from_load=True) + if stat is None: + continue + stat.set_value(stat_value, ignore_caps=True) + stat._state = trait_state + neglect_buff_index = trait_statistic_data.get('neglect_buff_index', None) + if neglect_buff_index is not None: + stat._neglect_buff_index = neglect_buff_index + if stat._state >= TraitStatisticStates.UNLOCKED: + # noinspection PyUnresolvedReferences + trait_data = stat.trait_data + else: + # noinspection PyUnresolvedReferences + trait_data = stat.opposing_trait_data + try: + neglect_buff_data = trait_data.neglect_buffs[stat._neglect_buff_index] + stat._neglect_buff_handle = stat.tracker.owner.add_buff(neglect_buff_data.buff_type, buff_reason=neglect_buff_data.buff_reason) + except Exception as ex: + log.format_error_with_message(f'Stat: {stat} Current State: {stat._state} should not have neglect buff index set: {stat._neglect_buff_index}', exception=ex, throw=False) + stat._neglect_buff_index = None + stat._value_added = trait_statistic_data.get('value_added', 0) + max_daily_cap = trait_statistic_data.get('max_daily_cap', None) + if max_daily_cap is not None: + stat._max_daily_cap = max_daily_cap + min_daily_cap = trait_statistic_data.get('min_daily_cap', None) + if min_daily_cap is not None: + stat._min_daily_cap = min_daily_cap + + stat.startup_statistic(from_load=True) + # noinspection PyUnresolvedReferences + if stat._state >= TraitStatisticStates.UNLOCKED: + # noinspection PyUnresolvedReferences + if not stat.tracker.owner.has_trait(stat.trait_data.trait): + # noinspection PyUnresolvedReferences + stat.tracker.owner.add_trait(stat.trait_data.trait) + # noinspection PyUnresolvedReferences + elif stat._state <= TraitStatisticStates.OPPOSING_UNLOCKED and not stat.tracker.owner.has_trait(stat.opposing_trait_data.trait): + # noinspection PyUnresolvedReferences + stat.tracker.owner.add_trait(stat.opposing_trait_data.trait) + + if statistic_type.min_lod_value == SimInfoLODLevel.ACTIVE: + if trait_statistic_tracker._delayed_active_lod_statistics is None: + trait_statistic_tracker._delayed_active_lod_statistics = list() + trait_statistic_tracker._delayed_active_lod_statistics.append((stat_id, stat_value)) + + elif statistic_type.min_lod_value == SimInfoLODLevel.ACTIVE: + if trait_statistic_tracker._delayed_active_lod_statistics is None: + trait_statistic_tracker._delayed_active_lod_statistics = list() + trait_statistic_tracker._delayed_active_lod_statistics.append((stat_id, stat_value)) + + @classmethod + def _load_statistic_data( + cls, + sim_info: SimInfo, + sim_statistic_data: Dict[str, Any], + skip_load: bool + ): + statistic_tracker = sim_info.statistic_tracker + try: + statistics_manager = CommonResourceUtils.get_instance_manager(Types.STATISTIC) + owner_lod = statistic_tracker._owner.lod if isinstance(statistic_tracker._owner, SimInfo) else None + for statistics_data in sim_statistic_data.get('statistics', tuple()): + stat_id = statistics_data.get('stat_id', None) + if stat_id is None: + continue + stat_value = statistics_data.get('stat_value', None) + stat_cls = statistics_manager.get(stat_id) + if stat_cls is not None: + if not statistic_tracker._should_add_commodity_from_gallery(stat_cls, skip_load): + continue + elif not stat_cls.persisted: + continue + elif statistic_tracker.statistics_to_skip_load is not None and stat_cls in statistic_tracker.statistics_to_skip_load: + continue + elif owner_lod is not None and owner_lod < stat_cls.min_lod_value: + if stat_cls.min_lod_value == SimInfoLODLevel.ACTIVE: + if statistic_tracker._delayed_active_lod_statistics is None: + statistic_tracker._delayed_active_lod_statistics = list() + statistic_tracker._delayed_active_lod_statistics.append((stat_id, stat_value)) + if stat_value is not None: + statistic_tracker.set_value(stat_cls, stat_value, from_load=True) + else: + if statistic_tracker._statistics is None: + statistic_tracker._statistics = {} + if stat_cls not in statistic_tracker._statistics: + statistic_tracker._statistics[stat_cls] = None + log.format_with_message('Trying to load unavailable STATISTIC resource', stat_id=stat_id) + else: + if stat_value is not None: + statistic_tracker.set_value(stat_cls, stat_value, from_load=True) + else: + if statistic_tracker._statistics is None: + statistic_tracker._statistics = {} + if stat_cls not in statistic_tracker._statistics: + statistic_tracker._statistics[stat_cls] = None + log.format_with_message('Trying to load unavailable STATISTIC resource', stat_id=stat_id) + else: + log.format_with_message('Trying to load unavailable STATISTIC resource', stat_id=stat_id) + finally: + statistic_tracker.statistics_to_skip_load = None + statistic_tracker.check_for_unneeded_initial_statistics() + + @classmethod + def _load_commodity_data( + cls, + sim_info: SimInfo, + sim_commodity_data: Dict[str, Any], + skip_load: bool + ): + commodity_tracker = sim_info.commodity_tracker + + cls._load_commodity_tracker_data(sim_info, sim_commodity_data.get('commodities', tuple()), skip_load=skip_load, update_affordance_cache=False) + if sim_info.lod > SimInfoLODLevel.BASE: + for commodity in tuple(commodity_tracker): + if commodity.has_auto_satisfy_value(): + commodity.set_to_auto_satisfy_value() + cls._load_commodity_tracker_data(sim_info, sim_commodity_data.get('other_statistics', tuple()), update_affordance_cache=False) + cls._load_commodity_tracker_data(sim_info, sim_commodity_data.get('skills', tuple()), update_affordance_cache=False) + cls._load_commodity_tracker_data(sim_info, sim_commodity_data.get('ranked_statistics', tuple()), update_affordance_cache=True) + + @classmethod + def _load_occult_data( + cls, + sim_info: SimInfo, + sim_occult_data: Dict[str, Any] + ): + occult_tracker = sim_info._occult_tracker + occult_types_list = sim_occult_data.get('occult_types', tuple()) + occult_types = None + for occult_type_value in occult_types_list: + vanilla_occult_type = cls._to_occult_type(occult_type_value) + if vanilla_occult_type is None: + continue + if occult_types is None: + occult_types = vanilla_occult_type + else: + occult_types = CommonBitwiseUtils.add_flags(occult_types, vanilla_occult_type) + + occult_tracker._sim_info.occult_types = occult_types or OccultType.HUMAN + + current_occult_types_list = sim_occult_data.get('current_occult_types', tuple()) + current_occult_types = None + for current_occult_type_value in current_occult_types_list: + vanilla_current_occult_type = cls._to_occult_type(current_occult_type_value) + if vanilla_current_occult_type is None: + continue + if current_occult_types is None: + current_occult_types = vanilla_current_occult_type + else: + current_occult_types = CommonBitwiseUtils.add_flags(occult_types, vanilla_current_occult_type) + + occult_tracker._sim_info.current_occult_types = current_occult_types or OccultType.HUMAN + + pending_occult_type_value = sim_occult_data.get('pending_occult_type', None) + + if pending_occult_type_value is not None: + pending_occult_type = cls._to_occult_type(pending_occult_type_value) + if pending_occult_type is not None: + occult_tracker._pending_occult_type = pending_occult_type + + occult_tracker._occult_form_available = sim_occult_data.get('occult_form_available', True) + + occult_data_map = dict() + for (occult_type_str, occult_type_data) in sim_occult_data.get('occult_info_by_occult_type', dict()).items(): + if occult_type_str is None: + continue + occult_type = cls._to_occult_type(occult_type_str) + if occult_type is None: + continue + + occult_type_data['occult_type'] = occult_type + + occult_data_map[occult_type] = occult_type_data + + for occult_type in OccultType: + if occult_type != OccultType.HUMAN and occult_type not in occult_tracker.OCCULT_DATA: + occult_tracker._sim_info.occult_types &= ~occult_type + if occult_tracker._sim_info.current_occult_types == occult_type: + occult_tracker._sim_info.current_occult_types = OccultType.HUMAN + if occult_tracker._pending_occult_type == occult_type: + occult_tracker._pending_occult_type = None + elif occult_type in occult_data_map: + sim_info_occult_data = occult_data_map[occult_type] + occult_tracker_sim_info = occult_tracker._generate_sim_info(sim_info_occult_data.get('occult_type'), generate_new=False) + outfits_data = sim_info_occult_data.get('occult_outfit_data', None) + physical_attributes = sim_info_occult_data.get('occult_physical_attributes', None) + if occult_type == occult_tracker._sim_info.current_occult_types: + if outfits_data is not None: + cls._load_outfit_data(sim_info, outfits_data) + if physical_attributes is not None: + cls._load_physical_attributes(sim_info, physical_attributes) + else: + if outfits_data is not None: + cls._load_outfit_data(occult_tracker_sim_info._base, outfits_data) + if physical_attributes is not None: + cls._load_physical_attributes(occult_tracker_sim_info._base, physical_attributes) + elif occult_type != OccultType.HUMAN and occult_tracker.has_occult_type(occult_type) and occult_type == occult_tracker._sim_info.current_occult_types: + occult_tracker._generate_sim_info(occult_type, generate_new=False) + + @classmethod + def _to_occult_type(cls, value: Union[str, int]) -> Union[OccultType, None]: + if isinstance(value, str): + return CommonResourceUtils.get_enum_by_name(value, OccultType, default_value=None) + elif isinstance(value, int): + return CommonResourceUtils.get_enum_by_int_value(value, OccultType, default_value=None) + return None + + @classmethod + def _load_death_data( + cls, + sim_info: SimInfo, + sim_death_data: Dict[str, Any] + ): + death_type_str = sim_death_data.get('death_type', None) + if death_type_str is None: + return + death_type = CommonResourceUtils.get_enum_by_name(death_type_str, CommonDeathType, default_value=None) + if death_type is None: + return + death_tracker = CommonSimDeathUtils.get_death_tracker(sim_info) + death_tracker._death_type = CommonDeathType.convert_to_vanilla(death_type) + death_tracker._death_time = CommonTimeUtils.get_current_date_and_time() + + @classmethod + def _load_physical_attributes( + cls, + sim_info: SimInfo, + physical_attributes_data: Dict[str, Any] + ): + try: + physique = physical_attributes_data.get('physique', None) + if physique is not None: + sim_info.physique = physique + + facial_attributes = physical_attributes_data.get('facial_attributes', None) + if facial_attributes is not None: + cls._load_facial_attribute_data(sim_info, facial_attributes) + + sim_info.voice_pitch = physical_attributes_data.get('voice_pitch', 0) + sim_info.voice_actor = physical_attributes_data.get('voice_actor', 0) + sim_info.voice_effect = physical_attributes_data.get('voice_effect', 0) + sim_info.skin_tone = physical_attributes_data.get('skin_tone', 0) + sim_info.skin_tone_val_shift = physical_attributes_data.get('skin_tone_val_shift', 0) + + sim_info.flags = physical_attributes_data.get('flags', 0) + + pelt_layers = physical_attributes_data.get('pelt_layers', None) + if pelt_layers is not None: + cls._load_pelt_layer_data(sim_info, pelt_layers) + + base_trait_ids = physical_attributes_data.get('base_trait_ids', None) + if base_trait_ids is not None: + sim_info.base_trait_ids = list(base_trait_ids) + + genetic_data = physical_attributes_data.get('genetics_data', None) + if genetic_data is not None: + cls._load_genetics_data(sim_info, genetic_data) + except Exception as ex: + log.error('Failed to save physical attributes', exception=ex, throw=False) + + @classmethod + def _load_pelt_layer_data(cls, sim_info: SimInfo, sim_pelt_layers_data: Dict[str, Any]): + pelt_layer_data = Outfits_pb2.PeltLayerDataList() + layers = list() + for layer_data in sim_pelt_layers_data.get('layers', tuple()): + layer = Outfits_pb2.PeltLayerData() + layer.color = layer_data.get('color') + layer.layer_id = layer_data.get('layer_id') + layers.append(layer) + # noinspection PyUnresolvedReferences + pelt_layer_data.layers.extend(layers) + sim_info.pelt_layers = pelt_layer_data.SerializeToString() + + @classmethod + def _load_facial_attribute_data(cls, sim_info: SimInfo, facial_attributes_data: Dict[str, Any]): + from protocolbuffers.PersistenceBlobs_pb2 import BlobSimFacialCustomizationData + facial_attributes = BlobSimFacialCustomizationData() + + face_modifiers = list() + for face_modifier in facial_attributes_data.get('face_modifiers', tuple()): + modifier = BlobSimFacialCustomizationData().Modifier() + modifier.key = face_modifier.get('modifier_key') + modifier.amount = face_modifier.get('modifier_value') + face_modifiers.append(modifier) + + # noinspection PyUnresolvedReferences + facial_attributes.face_modifiers.extend(face_modifiers) + + body_modifiers = list() + for body_modifier in facial_attributes_data.get('body_modifiers', tuple()): + modifier = BlobSimFacialCustomizationData().Modifier() + modifier.key = body_modifier.get('modifier_key') + modifier.amount = body_modifier.get('modifier_value') + body_modifiers.append(modifier) + + # noinspection PyUnresolvedReferences + facial_attributes.body_modifiers.extend(body_modifiers) + + sculpts = list() + for sculpt in facial_attributes_data.get('sculpts', tuple()): + sculpt: int = sculpt + sculpts.append(sculpt) + + # noinspection PyUnresolvedReferences + facial_attributes.sculpts.extend(sculpts) + + sim_info.facial_attributes = facial_attributes.SerializeToString() + + @classmethod + def _load_genetics_data(cls, sim_info: SimInfo, sim_genetics_data: Dict[str, Any]): + genetic_data = Outfits_pb2.GeneticData() + + genetic_data.physique = sim_genetics_data.get('physique') + genetic_data.voice_actor = sim_genetics_data.get('voice_actor') + genetic_data.voice_pitch = sim_genetics_data.get('voice_pitch') + + from protocolbuffers.PersistenceBlobs_pb2 import BlobSimFacialCustomizationData + facial_attributes = BlobSimFacialCustomizationData() + + sculpt_and_modifiers_data = sim_genetics_data.get('sculpts_and_modifiers', dict()) + + face_modifiers = list() + # noinspection PyUnresolvedReferences + for face_modifier in sculpt_and_modifiers_data.get('face_modifiers', tuple()): + modifier = BlobSimFacialCustomizationData().Modifier() + modifier.key = face_modifier.get('modifier_key') + modifier.amount = face_modifier.get('modifier_value') + face_modifiers.append(modifier) + + # noinspection PyUnresolvedReferences + facial_attributes.face_modifiers.extend(face_modifiers) + + body_modifiers = list() + # noinspection PyUnresolvedReferences + for body_modifier in sculpt_and_modifiers_data.get('body_modifiers', tuple()): + modifier = BlobSimFacialCustomizationData().Modifier() + modifier.key = body_modifier.get('modifier_key') + modifier.amount = body_modifier.get('modifier_value') + body_modifiers.append(modifier) + + # noinspection PyUnresolvedReferences + facial_attributes.body_modifiers.extend(body_modifiers) + + sculpts = list() + # noinspection PyUnresolvedReferences + for sculpt in sculpt_and_modifiers_data.get('sculpts', tuple()): + sculpt: int = sculpt + sculpts.append(sculpt) + + # noinspection PyUnresolvedReferences + facial_attributes.sculpts.extend(sculpts) + + genetic_data.sculpts_and_mods_attr = facial_attributes.SerializeToString() + + growth_parts_items = list() + # noinspection PyUnresolvedReferences + for part in sim_genetics_data.get('growth_parts_items', tuple()): # RepeatedCompositeContainer + # noinspection PyUnresolvedReferences + part_id = part.get('part_id', None) + # noinspection PyUnresolvedReferences + part_body_type = part.get('part_body_type', None) + # noinspection PyUnresolvedReferences + part_color_shift = part.get('part_color_shift', None) + if part_id is None or part_body_type is None or part_color_shift is None: + continue + + part_item = Outfits_pb2.PartData() + part_item.id = part_id + part_item.body_type = part_body_type + part_item.color_shift = part_color_shift + growth_parts_items.append(part_item) + + genetic_data.growth_parts_list = Outfits_pb2.PartDataList() + if growth_parts_items: + # noinspection PyUnresolvedReferences + genetic_data.growth_parts_list.parts.extend(growth_parts_items) + + parts_items = list() + # noinspection PyUnresolvedReferences + for part in sim_genetics_data.get('parts_items', tuple()): # RepeatedCompositeContainer + # noinspection PyUnresolvedReferences + part_id = part.get('part_id', None) + # noinspection PyUnresolvedReferences + part_body_type = part.get('part_body_type', None) + # noinspection PyUnresolvedReferences + part_color_shift = part.get('part_color_shift', None) + if part_id is None or part_body_type is None or part_color_shift is None: + continue + + part_item = Outfits_pb2.PartData() + part_item.id = part_id + part_item.body_type = part_body_type + part_item.color_shift = part_color_shift + parts_items.append(part_item) + + genetic_data.parts_list = Outfits_pb2.PartDataList() + # noinspection PyUnresolvedReferences + genetic_data.parts_list.parts.extend(parts_items) + + sim_info.genetic_data = genetic_data.SerializeToString() + + @classmethod + def _load_pronouns_data(cls, sim_info: SimInfo, sim_pronouns_data: Dict[str, Any]): + from protocolbuffers import S4Common_pb2 + pronouns_list = S4Common_pb2.SimPronounList() + pronouns = list() + # noinspection PyUnresolvedReferences + for sim_pronoun in sim_pronouns_data.get('pronouns'): # RepeatedCompositeContainer + pronoun = SimPronoun() + pronoun.pronoun = sim_pronoun.get('pronoun') + pronoun.case = sim_pronoun.get('pronoun_case') + pronouns.append(pronoun) + + # noinspection PyUnresolvedReferences + pronouns_list.pronouns.extend(pronouns) + sim_info.pronouns = pronouns_list.SerializeToString() + + # Save + @classmethod + def _build_sim_data(cls, sim_info: SimInfo) -> Dict[str, Any]: + """build_sim_data(sim_info) + + Convert a SimInfo object into a serializable dictionary of data. + + :param sim_info: + :return: + """ + sim_save_data = dict() + sim_info._set_fit_fat() + sim_save_data['physical_attributes'] = cls._build_physical_attributes(sim_info) + + sim_save_data['first_name'] = sim_info._base.first_name + sim_save_data['last_name'] = sim_info._base.last_name + sim_save_data['breed_name'] = sim_info._base.breed_name + sim_save_data['first_name_key'] = sim_info._base.first_name_key + sim_save_data['last_name_key'] = sim_info._base.last_name_key + sim_save_data['full_name_key'] = sim_info._base.full_name_key + sim_save_data['breed_name_key'] = sim_info._base.breed_name_key + sim_save_data['gender'] = CommonGender.get_gender(sim_info).name + sim_save_data['species'] = CommonSpecies.get_species(sim_info).name + sim_save_data['age'] = CommonAge.get_age(sim_info).name + sim_save_data['custom_texture'] = sim_info._base.custom_texture + sim_save_data['pronouns_data'] = cls._build_pronouns(sim_info._base) + from objects.components.consumable_component import ConsumableComponent + sim_save_data['fat'] = sim_info.commodity_tracker.get_value(ConsumableComponent.FAT_COMMODITY) + sim_save_data['fit'] = sim_info.commodity_tracker.get_value(ConsumableComponent.FIT_COMMODITY) + + sim_save_data['lod'] = sim_info._get_persisted_lod().name + + sim_save_data['outfit_data'] = cls._build_outfit_data(sim_info._base) + + sim_save_data['occult_data'] = cls._build_occult_data(sim_info) + death_data = cls._build_death_data(sim_info) + if death_data is not None: + sim_save_data['death_data'] = death_data + + # attributes_save.genealogy_tracker = sim_info._genealogy_tracker.save_genealogy() + # attributes_save.pregnancy_tracker = sim_info._pregnancy_tracker.save() + # attributes_save.sim_careers = sim_info._career_tracker.save() + sim_save_data['trait_data'] = cls._build_trait_data(sim_info) + # for (tag, obj_id) in sim_info._autonomy_scoring_preferences.items(): + # with ProtocolBufferRollback(attributes_save.object_preferences.preferences) as entry: + # entry.tag = tag + # entry.object_id = obj_id + # for (tag, obj_id) in sim_info._autonomy_use_preferences.items(): + # with ProtocolBufferRollback(attributes_save.object_ownership.owned_object) as entry: + # entry.tag = tag + # entry.object_id = obj_id + # stored_object_info_component = cls.get_component(objects.components.types.STORED_OBJECT_INFO_COMPONENT) + # if stored_object_info_component is not None: + # attributes_save.stored_object_info_component = stored_object_info_component.get_save_data() + commodity_data = cls._build_commodity_data(sim_info) + if commodity_data is not None: + sim_save_data['commodity_data'] = commodity_data + statistics_data = cls._build_statistics_data(sim_info) + if statistics_data is not None: + sim_save_data['statistics_data'] = statistics_data + + if sim_info.is_human: + trait_statistic_data = cls._build_trait_statistic_data(sim_info) + if trait_statistic_data is not None: + sim_save_data['trait_statistic_data'] = trait_statistic_data + sim_save_data['suntan_data'] = cls._build_suntan_data(sim_info) + + # if sim_info._familiar_tracker is not None: + # attributes_save.familiar_tracker = sim_info._familiar_tracker.save() + # if sim_info._favorites_tracker is not None: + # favorites_save = sim_info._favorites_tracker.save() + # if sim_info.get_sim_instance() is None and old_attributes_save is not None: + # favorites_save.stack_favorites.extend(old_attributes_save.favorites_tracker.stack_favorites) + # attributes_save.favorites_tracker = favorites_save + # if sim_info._aspiration_tracker is not None: + # sim_info._aspiration_tracker.save(attributes_save.event_data_tracker) + # if sim_info._unlock_tracker is not None: + # attributes_save.unlock_tracker = sim_info._unlock_tracker.save_unlock() + # if sim_info._notebook_tracker is not None: + # attributes_save.notebook_tracker = sim_info._notebook_tracker.save_notebook() + # if sim_info._adventure_tracker is not None: + # attributes_save.adventure_tracker = sim_info._adventure_tracker.save() + # if sim_info._royalty_tracker is not None: + # attributes_save.royalty_tracker = sim_info._royalty_tracker.save() + # if sim_info._relic_tracker is not None: + # attributes_save.relic_tracker = sim_info._relic_tracker.save() + # if sim_info._sickness_tracker is not None: + # if sim_info._sickness_tracker.should_persist_data(): + # attributes_save.sickness_tracker = sim_info._sickness_tracker.sickness_tracker_save_data() + # if sim_info._lifestyle_brand_tracker is not None: + # attributes_save.lifestyle_brand_tracker = sim_info._lifestyle_brand_tracker.save() + # if sim_info._degree_tracker is not None: + # attributes_save.degree_tracker = sim_info._degree_tracker.save() + # if sim_info._organization_tracker is not None: + # attributes_save.organization_tracker = sim_info._organization_tracker.save() + # if sim_info._fixup_tracker is not None: + # attributes_save.fixup_tracker = sim_info._fixup_tracker.save() + + sim_save_data['appearance_data'] = cls._build_appearance_data(sim_info) + + # if sim_info._story_progression_tracker is not None: + # story_progression_data = SimObjectAttributes_pb2.PersistableStoryProgressionTracker() + # sim_info._story_progression_tracker.save(story_progression_data) + # attributes_save.story_progression_tracker = story_progression_data + # if sim_info._lunar_effect_tracker is not None and sim_info._lunar_effect_tracker.has_data_to_save: + # lunar_effect_data = SimObjectAttributes_pb2.PersistableLunarEffectTracker() + # sim_info._lunar_effect_tracker.save_lunar_effects(lunar_effect_data) + # attributes_save.lunar_effect_tracker = lunar_effect_data + + sim_save_data['age_progress'] = sim_info._age_progress.get_value() + sim_save_data['primary_aspiration'] = sim_info._primary_aspiration.guid64 if sim_info._primary_aspiration is not None else 0 + + current_outfit_info = dict() + # noinspection PyPropertyAccess + current_outfit = sim_info.get_current_outfit() + if current_outfit is None: + (outfit_type, outfit_index) = (OutfitCategory.EVERYDAY, 0) + else: + (outfit_type, outfit_index) = current_outfit + if outfit_index == SpecialOutfitIndex.DEFAULT: + previous_outfit = sim_info.get_previous_outfit() + if previous_outfit is None: + (outfit_type, outfit_index) = (OutfitCategory.EVERYDAY, 0) + else: + (outfit_type, outfit_index) = previous_outfit + if outfit_type == OutfitCategory.SPECIAL and outfit_type == OutfitCategory.BATHING: + outfit_type = OutfitCategory.EVERYDAY + outfit_index = 0 + outfit_category_tuning = OutfitTuning.OUTFIT_CATEGORY_TUNING.get(outfit_type) + outfit_type = CommonOutfitUtils.convert_value_to_outfit_category(outfit_type) + if outfit_category_tuning.save_outfit_category is None: + current_outfit_info['outfit_category'] = outfit_type.name + else: + current_outfit_info['outfit_category'] = outfit_category_tuning.save_outfit_category.name + current_outfit_info['outfit_index'] = outfit_index + sim_save_data['current_outfit_info'] = current_outfit_info + + sim_save_data['additional_bonus_days'] = sim_info._additional_bonus_days + sim_save_data['saved_at_time'] = CommonRealDateUtils.get_current_date_string() + + if sim_info._initial_fitness_value is not None: + sim_save_data['initial_fitness_value'] = sim_info._initial_fitness_value + + favorite_recipe_ids = list() + for recipe in sim_info._favorite_recipes: + favorite_recipe_ids.append(recipe.guid64) + if favorite_recipe_ids: + sim_save_data['favorite_recipe_ids'] = favorite_recipe_ids + + if sim_info._bucks_tracker is not None: + sim_save_data['bucks_data'] = cls._build_bucks_data(sim_info) + return sim_save_data + + @classmethod + def _build_facial_attributes(cls, sim_info: SimInfo) -> Dict[str, Any]: + facial_attributes_data = dict() + from protocolbuffers.PersistenceBlobs_pb2 import BlobSimFacialCustomizationData + facial_attributes = BlobSimFacialCustomizationData() + # noinspection PyPropertyAccess + facial_attributes.MergeFromString(sim_info.facial_attributes) + + face_modifiers = list() + # noinspection PyUnresolvedReferences + for face_modifier in facial_attributes.face_modifiers: + face_modifier_key = face_modifier.key + face_modifier_value = face_modifier.amount + face_modifier_data = dict() + face_modifier_data['modifier_key'] = face_modifier_key + face_modifier_data['modifier_value'] = face_modifier_value + face_modifiers.append(face_modifier_data) + facial_attributes_data['face_modifiers'] = face_modifiers + + body_modifiers = list() + # noinspection PyUnresolvedReferences + for body_modifier in facial_attributes.body_modifiers: + body_modifier_key = body_modifier.key + body_modifier_value = body_modifier.amount + body_modifier_data = dict() + body_modifier_data['modifier_key'] = body_modifier_key + body_modifier_data['modifier_value'] = body_modifier_value + body_modifiers.append(body_modifier_data) + facial_attributes_data['body_modifiers'] = body_modifiers + + sculpts = list() + # noinspection PyUnresolvedReferences + for sculpt in facial_attributes.sculpts: + sculpt: int = sculpt + sculpts.append(sculpt) + facial_attributes_data['sculpts'] = sculpts + return facial_attributes_data + + @classmethod + def _build_pronouns(cls, sim_info: SimInfo) -> Dict[str, Any]: + sim_pronouns_data = dict() + from protocolbuffers import S4Common_pb2 + pronouns_list = S4Common_pb2.SimPronounList() + pronouns_list.MergeFromString(sim_info.pronouns) + pronouns_data = list() + # noinspection PyUnresolvedReferences + for sim_pronoun in pronouns_list.pronouns: # RepeatedCompositeContainer + sim_pronoun: SimPronoun = sim_pronoun + # noinspection PyUnresolvedReferences + pronoun = sim_pronoun.pronoun + # noinspection PyUnresolvedReferences + case = sim_pronoun.case + pronoun_info = dict() + pronoun_info['pronoun'] = pronoun + pronoun_info['pronoun_case'] = case + pronouns_data.append(pronoun_info) + sim_pronouns_data['pronouns'] = pronouns_data + return sim_pronouns_data + + @classmethod + def _build_pelt_layers(cls, sim_info: SimInfo) -> Dict[str, Any]: + sim_pelt_layers_data = dict() + pelt_layer_data = Outfits_pb2.PeltLayerDataList() + # noinspection PyPropertyAccess + pelt_layer_data.MergeFromString(sim_info.pelt_layers) + pelt_layers = list() + # noinspection PyUnresolvedReferences + for layer in pelt_layer_data.layers: + layer: Outfits_pb2.PeltLayerData = layer + layer_data = dict() + # noinspection PyUnresolvedReferences + color = layer.color + # noinspection PyUnresolvedReferences + layer_id = layer.layer_id + layer_data['color'] = color + layer_data['layer_id'] = layer_id + pelt_layers.append(layer_data) + + sim_pelt_layers_data['layers'] = pelt_layers + return sim_pelt_layers_data + + @classmethod + def _build_bucks_data(cls, sim_info: SimInfo) -> Dict[str, Any]: + bucks_tracker = sim_info._bucks_tracker + sim_bucks_data = dict() + bucks_list = list() + for bucks_type in CommonBucksType.get_all(): + vanilla_bucks_type = CommonBucksType.convert_to_vanilla(bucks_type) + bucks_data = dict() + bucks_data['bucks_type'] = bucks_type.name + bucks_data['amount'] = bucks_tracker._bucks.get(vanilla_bucks_type, 0) + bucks_perk_data = list() + for (perk, perk_data) in bucks_tracker._unlocked_perks[vanilla_bucks_type].items(): + unlocked_perks_data = dict() + unlocked_perks_data['perk_id'] = perk.guid64 + unlocked_perks_data['currently_unlocked'] = perk_data.currently_unlocked + if perk_data.unlocked_by is not None: + unlocked_perks_data['unlock_reason'] = perk_data.unlocked_by.guid64 + if perk in bucks_tracker._inactive_perk_timers[vanilla_bucks_type]: + unlocked_perks_data['time_left'] = bucks_tracker._inactive_perk_timers[vanilla_bucks_type][perk] + bucks_perk_data.append(unlocked_perks_data) + bucks_data['perk_data'] = bucks_perk_data + bucks_list.append(bucks_data) + sim_bucks_data['bucks'] = bucks_list + return sim_bucks_data + + @classmethod + def _build_appearance_data(cls, sim_info: SimInfo) -> Dict[str, Any]: + appearance_tracker = sim_info.appearance_tracker + appearance_data = dict() + appearance_items = list() + for (guid, seed) in sorted(list(appearance_tracker._persisted_appearance_data.items()), key=lambda x: x[0]): + appearance_item_data = dict() + appearance_item_data['guid'] = guid + appearance_item_data['seed'] = seed + appearance_items.append(appearance_item_data) + appearance_data['appearance_items'] = appearance_items + return appearance_data + + @classmethod + def _build_suntan_data(cls, sim_info: SimInfo) -> Dict[str, Any]: + suntan_tracker = sim_info._suntan_tracker + suntan_data = dict() + suntan_parts = list() + suntan_data['tan_level'] = suntan_tracker._tan_level + if suntan_tracker._outfit_part_data_list is not None: + for (part_id, body_type) in suntan_tracker._outfit_part_data_list: + part_tan_data = dict() + part_tan_data['part_id'] = part_id + part_tan_data['body_type'] = int(body_type) + suntan_parts.append(part_tan_data) + suntan_data['suntan_parts'] = suntan_parts + return suntan_data + + @classmethod + def _build_trait_statistic_data(cls, sim_info: SimInfo) -> Union[Dict[str, Any], None]: + trait_statistic_tracker = sim_info.trait_statistic_tracker + if trait_statistic_tracker._statistics is None: + return None + trait_statistic_data = dict() + trait_statistics = list() + for statistic in sorted(list(trait_statistic_tracker._statistics.values()), key=lambda x: x.guid64 if x is not None and hasattr(x, 'guid64') else 0): + stat_data = dict() + stat_id = statistic.guid64 + if stat_id is None or stat_id == 0: + continue + stat_data['stat_id'] = stat_id + stat_data['stat_value'] = statistic.get_value() + stat_data['stat_state'] = statistic._state.name + if statistic._neglect_buff_index is not None: + stat_data['neglect_buff_index'] = statistic._neglect_buff_index + stat_data['value_added'] = statistic._value_added + if statistic._max_daily_cap is not None: + stat_data['max_daily_cap'] = statistic._max_daily_cap + if statistic._min_daily_cap is not None: + stat_data['min_daily_cap'] = statistic._min_daily_cap + trait_statistics.append(stat_data) + if trait_statistics: + trait_statistic_data['trait_statistics'] = trait_statistics + if not trait_statistic_data: + return None + return trait_statistic_data + + @classmethod + def _build_statistics_data(cls, sim_info: SimInfo) -> Union[Dict[str, Any], None]: + statistics_tracker = sim_info.statistic_tracker + statistics_tracker.check_for_unneeded_initial_statistics() + if statistics_tracker._statistics is None: + return None + statistics_data = dict() + stat_list = list() + for (stat_type, stat) in sorted(list(statistics_tracker._statistics.items()), key=lambda x: x[0].guid64 if x[0] is not None and hasattr(x[0], 'guid64') else 0): + if not stat_type.persisted: + continue + try: + if stat is None or not hasattr(stat_type, 'guid64'): + continue + stat_id = stat_type.guid64 + if stat_id is None or stat_id == 0: + continue + current_value = stat.get_saved_value() + stat_data = dict() + stat_data['stat_id'] = stat_id + stat_data['stat_value'] = current_value + stat_list.append(stat_data) + except Exception as ex: + log.error(f'thrown while trying to save stat {stat}', exception=ex, throw=False) + continue + if not stat_list: + return None + statistics_data['statistics'] = stat_list + return statistics_data + + @classmethod + def _build_commodity_data(cls, sim_info: SimInfo) -> Union[Dict[str, Any], None]: + sim_commodity_data = dict() + commodities = list() + skills = list() + ranked_statistics = list() + other_statistics = list() + commodity_tracker = sim_info.commodity_tracker + + for stat in sorted(list(commodity_tracker._statistics_values_gen()), key=lambda x: x.guid64 if x is not None and hasattr(x, 'guid64') else 0): + if not stat.persisted: + continue + + stat_id = stat.guid64 + if stat_id is None or stat_id == 0: + continue + current_value = stat.get_saved_value() + statistic_data = dict() + statistic_data['stat_id'] = stat_id + statistic_data['stat_value'] = current_value + + if stat.is_skill or isinstance(stat, Skill) or isinstance(stat, LifeSkillStatistic): + # noinspection PyUnresolvedReferences + if hasattr(stat, 'initial_value') and current_value == stat.initial_value: + continue + skills.append(statistic_data) + continue + + if stat.is_commodity or isinstance(stat, Commodity): + commodities.append(statistic_data) + continue + + if stat.is_ranked or isinstance(stat, RankedStatistic): + ranked_statistics.append(statistic_data) + continue + + other_statistics.append(statistic_data) + + if commodities: + sim_commodity_data['commodities'] = commodities + if skills: + sim_commodity_data['skills'] = skills + if ranked_statistics: + sim_commodity_data['ranked_statistics'] = ranked_statistics + if other_statistics: + sim_commodity_data['other_statistics'] = other_statistics + + if not sim_commodity_data: + return None + return sim_commodity_data + + @classmethod + def _build_trait_data(cls, sim_info: SimInfo) -> Union[Dict[str, Any], None]: + trait_tracker = sim_info._trait_tracker + trait_ids = [trait.guid64 for trait in trait_tracker._equipped_traits if trait.persistable] + if trait_tracker._delayed_active_lod_traits is not None: + trait_ids.extend(trait.guid64 for trait in trait_tracker._delayed_active_lod_traits) + trait_data = dict() + trait_data['trait_ids'] = trait_ids + return trait_data + + @classmethod + def _build_death_data(cls, sim_info: SimInfo) -> Union[Dict[str, Any], None]: + death_type = CommonSimDeathUtils.get_death_type(sim_info) + if death_type == CommonDeathType.NONE: + return None + sim_death_data = dict() + sim_death_data['death_type'] = death_type.name + return sim_death_data + + @classmethod + def _build_occult_data(cls, sim_info: SimInfo) -> Dict[str, Any]: + sim_occult_data = dict() + occult_tracker = sim_info._occult_tracker + occult_tracker_sim_info = occult_tracker._sim_info + sim_occult_types = occult_tracker_sim_info.occult_types + occult_types = list() + for occult_type_val in OccultType.list_values_from_flags(sim_occult_types): + occult_type_type = CommonResourceUtils.get_enum_by_int_value(int(occult_type_val), OccultType, default_value=None) + if occult_type_type is None or not hasattr(occult_type_type, 'name'): + continue + occult_types.append(occult_type_type.name) + sim_occult_data['occult_types'] = occult_types + current_occult_types = list() + for current_occult_type_val in OccultType.list_values_from_flags(occult_tracker_sim_info.current_occult_types): + current_occult_type_type = CommonResourceUtils.get_enum_by_int_value(int(current_occult_type_val), OccultType, default_value=None) + if current_occult_type_type is None or not hasattr(current_occult_type_type, 'name'): + continue + current_occult_types.append(current_occult_type_type.name) + sim_occult_data['current_occult_types'] = current_occult_types + occult_form_available = occult_tracker._occult_form_available + sim_occult_data['occult_form_available'] = occult_form_available + if occult_tracker._pending_occult_type is not None: + pending_occult_type = occult_tracker._pending_occult_type + if pending_occult_type is not None and pending_occult_type != 0: + pending_occult_type_type = CommonResourceUtils.get_enum_by_int_value(int(pending_occult_type), OccultType, default_value=None) + if pending_occult_type_type is not None and hasattr(pending_occult_type_type, 'name'): + sim_occult_data['pending_occult_type'] = pending_occult_type_type.name + + sim_occult_types_data = dict() + for (occult_type, occult_sim_info) in occult_tracker._sim_info_map.items(): + occult_type_type = CommonResourceUtils.get_enum_by_int_value(int(occult_type), OccultType, default_value=None) + if occult_type_type is None or not hasattr(occult_type_type, 'name'): + continue + occult_type_data = dict() + occult_tracker._copy_shared_attributes(sim_info, occult_type, occult_tracker._sim_info, occult_tracker._sim_info.current_occult_types) + occult_type_data['occult_type'] = occult_type_type.name + occult_type_data['occult_outfit_data'] = cls._build_outfit_data(occult_sim_info._base) + occult_type_data['occult_physical_attributes'] = cls._build_physical_attributes(occult_sim_info) + sim_occult_types_data[occult_type_type.name] = occult_type_data + sim_occult_data['occult_info_by_occult_type'] = sim_occult_types_data + return sim_occult_data + + @classmethod + def _build_outfit_data(cls, sim_info: SimInfo) -> Dict[str, Any]: + outfits_msg = Outfits_pb2.OutfitList() + outfits_msg.ParseFromString(sim_info.outfits) + + outfits_by_category = dict() + # noinspection PyUnresolvedReferences + for outfit in outfits_msg.outfits: # RepeatedCompositeContainer + outfit: Outfits_pb2.OutfitData = outfit + # noinspection PyUnresolvedReferences + category: OutfitCategory = CommonOutfitUtils.convert_value_to_outfit_category(outfit.category) + if not isinstance(category, OutfitCategory): + continue + if category.name not in outfits_by_category: + outfits_by_category[category.name] = list() + outfits_list = outfits_by_category[category.name] + outfit_data = dict() + # noinspection PyUnresolvedReferences + body_types_list: Outfits_pb2.BodyTypesList = outfit.body_types_list + # noinspection PyUnresolvedReferences + body_types = body_types_list.body_types + # noinspection PyUnresolvedReferences + parts: S4Common_pb2.IdList = outfit.parts + # noinspection PyUnresolvedReferences + part_ids = parts.ids + part_data_list = list() + # noinspection PyUnresolvedReferences + part_shifts: Outfits_pb2.ColorShiftList = outfit.part_shifts + # noinspection PyUnresolvedReferences + part_shift_colors = part_shifts.color_shift + parts_info = zip(body_types, part_ids, part_shift_colors) + for (body_type, part_id, part_color_shift) in parts_info: + part_data = dict() + part_data['body_type'] = body_type + part_data['part_id'] = part_id + part_data['part_color_shift'] = part_color_shift + part_data_list.append(part_data) + + outfit_data['part_data_list'] = part_data_list + # noinspection PyUnresolvedReferences + outfit_id: int = outfit.outfit_id + # noinspection PyUnresolvedReferences + outfit_flags: int = outfit.outfit_flags + # noinspection PyUnresolvedReferences + outfit_flags_high: int = outfit.outfit_flags_high + # noinspection PyUnresolvedReferences + title: str = outfit.title + # noinspection PyUnresolvedReferences + match_hair_style: bool = outfit.match_hair_style + # noinspection PyUnresolvedReferences + created: int = outfit.created + outfit_data['outfit_id'] = outfit_id + outfit_data['category'] = category.name + outfit_data['outfit_flags'] = outfit_flags + outfit_data['outfit_flags_high'] = outfit_flags_high + outfit_data['title'] = title + outfit_data['match_hair_style'] = match_hair_style + outfit_data['created'] = created + outfit_data['outfit_index'] = len(outfits_list) + outfits_list.append(outfit_data) + outfits_by_category[category.name] = outfits_list + return outfits_by_category + + @classmethod + def _build_physical_attributes(cls, sim_info: SimInfo) -> Dict[str, Any]: + physical_attributes_data = dict() + # noinspection PyPropertyAccess + physical_attributes_data['physique'] = sim_info.physique + + # noinspection PyPropertyAccess + physical_attributes_data['voice_pitch'] = sim_info.voice_pitch + # noinspection PyPropertyAccess + physical_attributes_data['voice_actor'] = sim_info.voice_actor + # noinspection PyPropertyAccess + physical_attributes_data['voice_effect'] = sim_info.voice_effect + # noinspection PyPropertyAccess + physical_attributes_data['skin_tone'] = sim_info.skin_tone + # noinspection PyPropertyAccess + physical_attributes_data['skin_tone_val_shift'] = sim_info.skin_tone_val_shift + + physical_attributes_data['facial_attributes'] = cls._build_facial_attributes(sim_info) + + physical_attributes_data['flags'] = sim_info.flags + if hasattr(sim_info, 'pelt_layers'): + physical_attributes_data['pelt_layers'] = cls._build_pelt_layers(sim_info) + + if hasattr(sim_info, 'base_trait_ids'): + # originally a tuple, convert it to a tuple when setting it! + physical_attributes_data['base_trait_ids'] = sorted(list(sim_info.base_trait_ids), key=lambda x: x) + + physical_attributes_data['genetics_data'] = cls._build_genetics_data(sim_info) + return physical_attributes_data + + @classmethod + def _build_genetics_data(cls, sim_info: SimInfo) -> Dict[str, Any]: + sim_genetics_data = dict() + genetic_data = Outfits_pb2.GeneticData() + # noinspection PyPropertyAccess + genetic_data.MergeFromString(sim_info.genetic_data) + # noinspection PyUnresolvedReferences + growth_parts_list: Outfits_pb2.PartDataList = genetic_data.growth_parts_list + # noinspection PyUnresolvedReferences + parts_list: Outfits_pb2.PartDataList = genetic_data.parts_list + # noinspection PyUnresolvedReferences + physique: str = genetic_data.physique + sculpts_and_modifier_data = dict() + from protocolbuffers.PersistenceBlobs_pb2 import BlobSimFacialCustomizationData + facial_attributes = BlobSimFacialCustomizationData() + # noinspection PyUnresolvedReferences + facial_attributes.MergeFromString(genetic_data.sculpts_and_mods_attr) + + face_modifiers = list() + # noinspection PyUnresolvedReferences + for face_modifier in facial_attributes.face_modifiers: + face_modifier_key = face_modifier.key + face_modifier_value = face_modifier.amount + face_modifier_data = dict() + face_modifier_data['modifier_key'] = face_modifier_key + face_modifier_data['modifier_value'] = face_modifier_value + face_modifiers.append(face_modifier_data) + sculpts_and_modifier_data['face_modifiers'] = face_modifiers + + body_modifiers = list() + # noinspection PyUnresolvedReferences + for body_modifier in facial_attributes.body_modifiers: + body_modifier_key = body_modifier.key + body_modifier_value = body_modifier.amount + body_modifier_data = dict() + body_modifier_data['modifier_key'] = body_modifier_key + body_modifier_data['modifier_value'] = body_modifier_value + body_modifiers.append(body_modifier_data) + sculpts_and_modifier_data['body_modifiers'] = body_modifiers + + sculpts = list() + # noinspection PyUnresolvedReferences + for sculpt in facial_attributes.sculpts: + sculpt: int = sculpt + sculpts.append(sculpt) + sculpts_and_modifier_data['sculpts'] = sculpts + + sim_genetics_data['sculpts_and_modifiers'] = sculpts_and_modifier_data + + # noinspection PyUnresolvedReferences + voice_actor: int = genetic_data.voice_actor + # noinspection PyUnresolvedReferences + voice_pitch: float = genetic_data.voice_pitch + growth_parts_items = list() + # noinspection PyUnresolvedReferences + for part in growth_parts_list.parts: # RepeatedCompositeContainer + part: Outfits_pb2.PartData = part + # noinspection PyUnresolvedReferences + part_id = part.id + # noinspection PyUnresolvedReferences + part_body_type = part.body_type + # noinspection PyUnresolvedReferences + part_color_shift = part.color_shift + growth_part_item = dict() + growth_part_item['part_id'] = part_id + growth_part_item['part_body_type'] = part_body_type + growth_part_item['part_color_shift'] = part_color_shift + growth_parts_items.append(growth_part_item) + + sim_genetics_data['growth_parts_items'] = growth_parts_items + + parts_items = list() + # noinspection PyUnresolvedReferences + for part in parts_list.parts: # RepeatedCompositeContainer + part: Outfits_pb2.PartData = part + # noinspection PyUnresolvedReferences + part_id = part.id + # noinspection PyUnresolvedReferences + part_body_type = part.body_type + # noinspection PyUnresolvedReferences + part_color_shift = part.color_shift + part_item = dict() + part_item['part_id'] = part_id + part_item['part_body_type'] = part_body_type + part_item['part_color_shift'] = part_color_shift + parts_items.append(part_item) + sim_genetics_data['parts_items'] = parts_items + + sim_genetics_data['physique'] = physique + sim_genetics_data['voice_actor'] = voice_actor + sim_genetics_data['voice_pitch'] = voice_pitch + return sim_genetics_data + + @classmethod + def despawn_sim( + cls, + sim_info: SimInfo, + source: str = None, + cause: str = None, + **kwargs + ) -> bool: + """despawn_sim(sim_info, source=None, cause=None, **kwargs) + + Despawn a Sim. + + :param sim_info: The Sim to despawn. + :type sim_info: SimInfo + :param source: The source of the destruction. Default is None. + :type source: str, optional + :param cause: The cause of the destruction. Default is None. + :type cause: str, optional + :return: True, if the Sim was despawn successfully. False, if not. + :rtype: bool + """ + if sim_info is None: + return False + from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return True + cause = cause or 'Sim despawned.' + if cls.hard_reset(sim_info, reset_reason=ResetReason.BEING_DESTROYED, source=cls, cause='S4CL Despawn'): + sim.destroy(source=source, cause=cause, **kwargs) + return True + + @classmethod + def schedule_sim_for_despawn( + cls, + sim_info: SimInfo, + source: str = None, + cause: str = None, + on_despawn: Callable[[], None] = None, + **kwargs + ) -> bool: + """schedule_sim_for_despawn(sim_info, source=None, cause=None, on_despawn=None, **kwargs) + + Schedule a Sim to be despawned. + + :param sim_info: The Sim to despawn. + :type sim_info: SimInfo + :param source: The source of the destruction. Default is None. + :type source: str, optional + :param cause: The cause of the destruction. Default is None. + :type cause: str, optional + :param on_despawn: A callback that occurs after the Sim is despawned. Default is None. + :type on_despawn: Callable[[], None], optional + :return: True, if the Object was successfully scheduled for destruction. False, if not. + :rtype: bool + """ + if sim_info is None: + return False + from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + if on_despawn is not None: + on_despawn() + return True + cause = cause or 'Sim despawned.' + sim.schedule_destroy_asap(post_delete_func=on_despawn, source=source, cause=cause, **kwargs) + return True + + @classmethod + def delete_sim(cls, sim_info: SimInfo, source: str = None, cause: str = None, **kwargs) -> bool: + """delete_sim(sim_info, source=None, cause=None, **kwargs) + + Delete a Sim. + + :param sim_info: The Sim to delete. + :type sim_info: SimInfo + :param source: The source of the destruction. Default is None. + :type source: str, optional + :param cause: The cause of the destruction. Default is None. + :type cause: str, optional + :return: True, if the Sim was deleted successfully. False, if not. + :rtype: bool + """ + if not cls.despawn_sim(sim_info, source=source, cause=cause, **kwargs): + return False + client = services.client_manager().get_first_client() + if sim_info.household is not None and hasattr(sim_info.household, 'refresh_aging_updates'): + client.remove_selectable_sim_info(sim_info) + household = sim_info.household or CommonHouseholdUtils.create_empty_household() + sim_info.remove_permanently(household=household) + return True + + @classmethod + def soft_reset( + cls, + sim_info: SimInfo, + reset_reason: ResetReason = ResetReason.RESET_EXPECTED, + hard_reset_on_exception: bool = False, + source: Any = None, + cause: str = 'S4CL Soft Reset' + ) -> bool: + """soft_reset(\ + sim_info,\ + reset_reason=ResetReason.RESET_EXPECTED,\ + hard_reset_on_exception=False,\ + source=None,\ + cause='S4CL Soft Reset'\ + ) + + Perform a soft reset on a Sim. + + :param sim_info: An instance of an Sim. + :type sim_info: SimInfo + :param reset_reason: The reason for the reset. Default is ResetReason.RESET_EXPECTED. + :type reset_reason: ResetReason, optional + :param hard_reset_on_exception: If set to True, a hard reset of the Object will be attempted upon an error occurring.\ + If set to False, nothing will occur if the reset failed. Default is False. + :type hard_reset_on_exception: bool, optional + :param source: The source of the reset. Default is the GameObject. + :type source: Any, optional + :param cause: Text indicating the cause of the reset. Default is 'S4CL Hard Reset'. + :type cause: str, optional + :return: True, if the reset was successful. False, if not. + :rtype: bool + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return True + # noinspection PyBroadException + try: + # noinspection PyArgumentList + if sim._should_be_swimming() or _buildbuy.is_location_pool(services.current_zone_id(), sim.position, sim.location.level): + posture_type = posture_graph.SIM_SWIM_POSTURE_TYPE + else: + posture_type = posture_graph.SIM_DEFAULT_POSTURE_TYPE + + if sim.queue is not None: + for interaction in sim.queue: + interaction.cancel(FinishingType.KILLED, '{} sim.queue'.format(cause)) + sim.queue.on_reset() + sim.queue.unlock() + + if sim.si_state is not None: + for interaction in sim.si_state: + interaction.cancel(FinishingType.KILLED, '{} sim.si_state'.format(cause)) + # noinspection PyBroadException + try: + sim.si_state.on_reset() + except: + sim._si_state = SIState(sim) + sim.si_state.on_reset() + else: + sim._si_state = SIState(sim) + sim.si_state.on_reset() + + if sim.ui_manager is not None: + sim.ui_manager.remove_all_interactions() + + sim.socials_locked = False + sim.last_affordance = None + sim.two_person_social_transforms.clear() + sim.on_reset_send_op(reset_reason) + # noinspection PyPropertyAccess + if sim.posture_state is not None: + # noinspection PyPropertyAccess + posture_state = sim.posture_state + if posture_state._primitive is not None: + # noinspection PyPropertyAccess + posture_state._primitive._prev_posture = None + # noinspection PyPropertyAccess + posture_state.on_reset(reset_reason) + + sim._stop_animation_interaction() + sim.asm_auto_exit.clear() + sim._start_animation_interaction() + from postures.posture_specs import get_origin_spec + # noinspection PyBroadException + try: + sim.posture_state = PostureState(sim, None, get_origin_spec(posture_type), {PostureSpecVariable.HAND: (Hand.LEFT,)}) + except: + sim.posture_state = PostureState(sim, None, get_origin_spec(posture_graph.SIM_DEFAULT_POSTURE_TYPE), {PostureSpecVariable.HAND: (Hand.LEFT,)}) + + sim._posture_target_refs.clear() + sim.run_full_autonomy_next_ping() + return True + except: + if hard_reset_on_exception: + return cls.hard_reset(sim_info, reset_reason, source=source, cause=cause) + return False + + @classmethod + def hard_reset( + cls, + sim_info: SimInfo, + reset_reason: ResetReason = ResetReason.RESET_EXPECTED, + source: Any = None, + cause: str = 'S4CL Hard Reset' + ) -> bool: + """hard_reset( + sim_info,\ + reset_reason=ResetReason.RESET_EXPECTED,\ + source=None,\ + cause='S4CL Hard Reset'\ + ) + + Perform a hard reset on a SimInfo. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param reset_reason: The reason for the reset. Default is ResetReason.RESET_EXPECTED. + :type reset_reason: ResetReason, optional + :param source: The source of the reset. Default is None. + :type source: Any, optional + :param cause: Text indicating the cause of the reset. Default is 'S4CL Hard Reset'. + :type cause: str, optional + :return: True, if the reset was successful. False, if not. + :rtype: bool + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return True + + # noinspection PyBroadException + try: + sim.reset(reset_reason, source=source or sim_info, cause=cause) + return True + except: + return False + + @classmethod + def fade_in( + cls, + sim_info: SimInfo, + fade_duration: float = 1.0, + immediate: bool = False, + additional_channels: Iterator[Tuple[int, int, int]] = None + ): + """fade_in(sim_info, fade_duration=1.0, immediate=False, additional_channels=None) + + Fade a Sim to become visible. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param fade_duration: The number of milliseconds the fade effect should take to complete. Default is 1.0. + :type fade_duration: float, optional + :param immediate: If set to True, fade in will occur immediately. Default is False. + :type immediate: bool, optional + :param additional_channels: A collection of additional channels. The order of the inner tuple is Manager Id, Sim Id, and Mask. Default is None. + :type additional_channels: Iterator[Tuple[int, int, int]], optional + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return + sim.fade_in(fade_duration=fade_duration, immediate=immediate, additional_channels=additional_channels) + + @classmethod + def fade_out( + cls, + sim_info: SimInfo, + fade_duration: float = 1.0, + immediate: bool = False, + additional_channels: Iterator[Tuple[int, int, int]] = None + ): + """fade_out(sim_info, fade_duration=1.0, immediate=False, additional_channels=None) + + Fade a Sim to become invisible. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param fade_duration: The number of milliseconds the fade effect should take to complete. Default is 1.0. + :type fade_duration: float, optional + :param immediate: If set to True, fade out will occur immediately. Default is False. + :type immediate: bool, optional + :param additional_channels: A collection of additional channels. The order of the inner tuple is Manager Id, Sim Id, and Mask. Default is None. + :type additional_channels: Iterator[Tuple[int, int, int]], optional + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return + sim.fade_out(fade_duration=fade_duration, immediate=immediate, additional_channels=additional_channels) + + +@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.spawn_sims', 'Spawn Sims of a certain species, gender, and age.', command_arguments=( + CommonConsoleCommandArgument('species', 'CommonSpecies', + f'The spawned Sims will have this species. Valid species include: {CommonSpecies.get_comma_separated_names_string()}', is_optional=False), + CommonConsoleCommandArgument('count', 'Number', 'The number of Sims to spawn.', is_optional=True, default_value=1), + CommonConsoleCommandArgument('gender', 'CommonGender', + f'The spawned Sims will have this gender. Valid genders include: {CommonGender.get_comma_separated_names_string()}', is_optional=True, default_value=CommonGender.MALE.name if hasattr(CommonGender.MALE, 'name') else CommonGender.MALE), + CommonConsoleCommandArgument('age', 'CommonAge', + f'The spawned Sims will have this age. Valid ages include: {CommonAge.get_comma_separated_names_string()}', is_optional=True, default_value=CommonAge.ADULT.name if hasattr(CommonAge.ADULT, 'name') else CommonAge.ADULT) +)) +def _s4cl_spawn_sims(output: CommonConsoleCommandOutput, species: CommonSpecies, count: int = 1, gender: CommonGender = CommonGender.MALE, age: CommonAge = CommonAge.ADULT): + if species is None: + return + if gender == CommonGender.INVALID or not isinstance(gender, CommonGender): + output(f'ERROR: {gender} is not a valid gender. Valid Genders: ({CommonGender.get_comma_separated_names_string()})') + return + if age == CommonAge.INVALID or not isinstance(age, CommonAge): + output(f'ERROR: {age} is not a valid age. Valid Ages: ({CommonAge.get_comma_separated_names_string()})') + return + if count <= 0: + output('ERROR: Please enter a count above zero.') + return + output(f'Spawning {count} {species.name} Sim(s) of Gender: {gender.name} and Age: {age.name}.') + try: + active_sim_info = CommonSimUtils.get_active_sim_info() + active_sim_location = CommonSimLocationUtils.get_location(active_sim_info) + for x in range(count): + created_sim_info = CommonSimSpawnUtils.create_sim_info(species, gender=gender, age=age) + CommonSimSpawnUtils.spawn_sim(created_sim_info, location=active_sim_location) + except Exception as ex: + CommonExceptionHandler.log_exception(ModInfo.get_identity(), f'Error spawning Sims {count} Sim(s) of Species: {species.name}, Gender: {gender.name}, and Age: {age.name}.', exception=ex) + output('An error occurred while spawning Sim(s).') + output(f'Done Spawning {count} {species.name} Sim(s) of Gender: {gender.name} and Age: {age.name}.') + output('If the space around your Sim was too crowded for a new Sim to spawn, you may locate the spawned Sim(s) in front of the lot.') + + +@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.spawn_human_sims', 'Spawn Human Sims of a certain gender and age.', command_arguments=( + CommonConsoleCommandArgument('count', 'Number', 'The number of Sims to spawn.', is_optional=True, default_value=1), + CommonConsoleCommandArgument('gender', 'CommonGender', + f'The spawned Sims will have this gender. Valid genders include: {CommonGender.get_comma_separated_names_string()}', is_optional=True, default_value=CommonGender.MALE.name if hasattr(CommonGender.MALE, 'name') else CommonGender.MALE), + CommonConsoleCommandArgument('age', 'CommonAge', + f'The spawned Sims will have this age. Valid ages include: {CommonAge.get_comma_separated_names_string()}', is_optional=True, default_value=CommonAge.ADULT.name if hasattr(CommonAge.ADULT, 'name') else CommonAge.ADULT) +)) +def _s4cl_spawn_human_sims(output: CommonConsoleCommandOutput, count: int = 1, gender: CommonGender = CommonGender.MALE, age: CommonAge = CommonAge.ADULT): + return _s4cl_spawn_sims(output, CommonSpecies.HUMAN, count=count, gender=gender, age=age) + + +@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.spawn_large_dog_sims', 'Spawn Large Dog Sims of a certain gender and age.', command_arguments=( + CommonConsoleCommandArgument('count', 'Number', 'The number of Sims to spawn.', is_optional=True, default_value=1), + CommonConsoleCommandArgument('gender', 'CommonGender', + f'The spawned Sims will have this gender. Valid genders include: {CommonGender.get_comma_separated_names_string()}', is_optional=True, default_value=CommonGender.MALE.name if hasattr(CommonGender.MALE, 'name') else CommonGender.MALE), + CommonConsoleCommandArgument('age', 'CommonAge', + f'The spawned Sims will have this age. Valid ages include: {CommonAge.get_comma_separated_names_string()}', is_optional=True, default_value=CommonAge.ADULT.name if hasattr(CommonAge.ADULT, 'name') else CommonAge.ADULT) +)) +def _s4cl_spawn_large_dog_sims(output: CommonConsoleCommandOutput, count: int = 1, gender: CommonGender = CommonGender.MALE, age: CommonAge = CommonAge.ADULT): + return _s4cl_spawn_sims(output, CommonSpecies.LARGE_DOG, count=count, gender=gender, age=age) + + +@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.spawn_small_dog_sims', 'Spawn Small Dog Sims of a certain gender and age.', command_arguments=( + CommonConsoleCommandArgument('count', 'Number', 'The number of Sims to spawn.', is_optional=True, default_value=1), + CommonConsoleCommandArgument('gender', 'CommonGender', + f'The spawned Sims will have this gender. Valid genders include: {CommonGender.get_comma_separated_names_string()}', is_optional=True, default_value=CommonGender.MALE.name if hasattr(CommonGender.MALE, 'name') else CommonGender.MALE), + CommonConsoleCommandArgument('age', 'CommonAge', + f'The spawned Sims will have this age. Valid ages include: {CommonAge.get_comma_separated_names_string()}', is_optional=True, default_value=CommonAge.ADULT.name if hasattr(CommonAge.ADULT, 'name') else CommonAge.ADULT) +)) +def _s4cl_spawn_small_dog_sims(output: CommonConsoleCommandOutput, count: int = 1, gender: CommonGender = CommonGender.MALE, age: CommonAge = CommonAge.ADULT): + return _s4cl_spawn_sims(output, CommonSpecies.SMALL_DOG, count=count, gender=gender, age=age) + + +@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.spawn_cat_sims', 'Spawn Cat Sims of a certain gender and age.', command_arguments=( + CommonConsoleCommandArgument('count', 'Number', 'The number of Sims to spawn.', is_optional=True, default_value=1), + CommonConsoleCommandArgument('gender', 'CommonGender', + f'The spawned Sims will have this gender. Valid genders include: {CommonGender.get_comma_separated_names_string()}', is_optional=True, default_value=CommonGender.MALE.name if hasattr(CommonGender.MALE, 'name') else CommonGender.MALE), + CommonConsoleCommandArgument('age', 'CommonAge', + f'The spawned Sims will have this age. Valid ages include: {CommonAge.get_comma_separated_names_string()}', is_optional=True, default_value=CommonAge.ADULT.name if hasattr(CommonAge.ADULT, 'name') else CommonAge.ADULT) +)) +def _s4cl_spawn_cat_sims(output: CommonConsoleCommandOutput, count: int = 1, gender: CommonGender = CommonGender.MALE, age: CommonAge = CommonAge.ADULT): + return _s4cl_spawn_sims(output, CommonSpecies.CAT, count=count, gender=gender, age=age) + + +@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.spawn_fox_sims', 'Spawn Fox Sims of a certain gender and age.', command_arguments=( + CommonConsoleCommandArgument('count', 'Number', 'The number of Sims to spawn.', is_optional=True, default_value=1), + CommonConsoleCommandArgument('gender', 'CommonGender', + f'The spawned Sims will have this gender. Valid genders include: {CommonGender.get_comma_separated_names_string()}', is_optional=True, default_value=CommonGender.MALE.name if hasattr(CommonGender.MALE, 'name') else CommonGender.MALE), + CommonConsoleCommandArgument('age', 'CommonAge', + f'The spawned Sims will have this age. Valid ages include: {CommonAge.get_comma_separated_names_string()}', is_optional=True, default_value=CommonAge.ADULT.name if hasattr(CommonAge.ADULT, 'name') else CommonAge.ADULT) +)) +def _s4cl_spawn_fox_sims(output: CommonConsoleCommandOutput, count: int = 1, gender: CommonGender = CommonGender.MALE, age: CommonAge = CommonAge.ADULT): + return _s4cl_spawn_sims(output, CommonSpecies.FOX, count=count, gender=gender, age=age) + + +@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.spawn_horse_sims', 'Spawn Horse Sims of a certain gender and age.', command_arguments=( + CommonConsoleCommandArgument('count', 'Number', 'The number of Sims to spawn.', is_optional=True, default_value=1), + CommonConsoleCommandArgument('gender', 'CommonGender', + f'The spawned Sims will have this gender. Valid genders include: {CommonGender.get_comma_separated_names_string()}', is_optional=True, default_value=CommonGender.MALE.name if hasattr(CommonGender.MALE, 'name') else CommonGender.MALE), + CommonConsoleCommandArgument('age', 'CommonAge', + f'The spawned Sims will have this age. Valid ages include: {CommonAge.get_comma_separated_names_string()}', is_optional=True, default_value=CommonAge.ADULT.name if hasattr(CommonAge.ADULT, 'name') else CommonAge.ADULT) +)) +def _s4cl_spawn_horse_sims(output: CommonConsoleCommandOutput, count: int = 1, gender: CommonGender = CommonGender.MALE, age: CommonAge = CommonAge.ADULT): + return _s4cl_spawn_sims(output, CommonSpecies.HORSE, count=count, gender=gender, age=age) + + +@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.spawn_random_sims', 'Spawn a random number of Sims.', command_arguments=( + CommonConsoleCommandArgument('count', 'Number', 'The number of Sims to spawn.', is_optional=True, default_value=5), +)) +def _s4clib_spawn_random_sims(output: CommonConsoleCommandOutput, count: int = 5): + _s4cl_spawn_human_sims(output, count=count, gender=CommonGender.MALE, age=CommonAge.TODDLER) + _s4cl_spawn_human_sims(output, count=count, gender=CommonGender.MALE, age=CommonAge.CHILD) + _s4cl_spawn_human_sims(output, count=count, gender=CommonGender.MALE, age=CommonAge.ADULT) + + _s4cl_spawn_human_sims(output, count=count, gender=CommonGender.FEMALE, age=CommonAge.TODDLER) + _s4cl_spawn_human_sims(output, count=count, gender=CommonGender.FEMALE, age=CommonAge.CHILD) + _s4cl_spawn_human_sims(output, count=count, gender=CommonGender.FEMALE, age=CommonAge.ADULT) + + _s4cl_spawn_large_dog_sims(output, count=count, gender=CommonGender.MALE, age=CommonAge.CHILD) + _s4cl_spawn_large_dog_sims(output, count=count, gender=CommonGender.MALE, age=CommonAge.ADULT) + + _s4cl_spawn_large_dog_sims(output, count=count, gender=CommonGender.FEMALE, age=CommonAge.CHILD) + _s4cl_spawn_large_dog_sims(output, count=count, gender=CommonGender.FEMALE, age=CommonAge.ADULT) + + _s4cl_spawn_small_dog_sims(output, count=count, gender=CommonGender.MALE, age=CommonAge.CHILD) + _s4cl_spawn_small_dog_sims(output, count=count, gender=CommonGender.MALE, age=CommonAge.ADULT) + + _s4cl_spawn_small_dog_sims(output, count=count, gender=CommonGender.FEMALE, age=CommonAge.CHILD) + _s4cl_spawn_small_dog_sims(output, count=count, gender=CommonGender.FEMALE, age=CommonAge.ADULT) + + _s4cl_spawn_cat_sims(output, count=count, gender=CommonGender.MALE, age=CommonAge.CHILD) + _s4cl_spawn_cat_sims(output, count=count, gender=CommonGender.MALE, age=CommonAge.ADULT) + + _s4cl_spawn_cat_sims(output, count=count, gender=CommonGender.FEMALE, age=CommonAge.CHILD) + _s4cl_spawn_cat_sims(output, count=count, gender=CommonGender.FEMALE, age=CommonAge.ADULT) + + _s4cl_spawn_fox_sims(output, count=count, gender=CommonGender.MALE, age=CommonAge.ADULT) + _s4cl_spawn_fox_sims(output, count=count, gender=CommonGender.FEMALE, age=CommonAge.ADULT) + + _s4cl_spawn_horse_sims(output, count=count, gender=CommonGender.MALE, age=CommonAge.CHILD) + _s4cl_spawn_horse_sims(output, count=count, gender=CommonGender.FEMALE, age=CommonAge.ADULT) + + +@CommonConsoleCommand(ModInfo.get_identity(), 's4clib_testing.spawn_sims', 'Spawn a number of Sims of each species.', command_arguments=( + CommonConsoleCommandArgument('count', 'Number', 'The number of Sims to spawn.', is_optional=True, default_value=1), + CommonConsoleCommandArgument('gender', 'CommonGender', + f'The spawned Sims will have this gender. Valid genders include: {CommonGender.get_comma_separated_names_string()}', is_optional=True, default_value=CommonGender.MALE.name if hasattr(CommonGender.MALE, 'name') else CommonGender.MALE), + CommonConsoleCommandArgument('age', 'CommonAge', + f'The spawned Sims will have this age. Valid ages include: {CommonAge.get_comma_separated_names_string()}', is_optional=True, default_value=CommonAge.ADULT.name if hasattr(CommonAge.ADULT, 'name') else CommonAge.ADULT) +)) +def _s4clib_spawn_random_sims(output: CommonConsoleCommandOutput, count: int = 1, gender: CommonGender = CommonGender.MALE, age: CommonAge = CommonAge.ADULT): + for species in CommonSpecies.get_all(): + _s4cl_spawn_sims(output, species=species, count=count, gender=gender, age=age) + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.purge_self', + 'Delete the active Sim. WARNING: Not recommended in single Sim households, since you cannot do interactions without an active Sim!' +) +def _s4cl_purge_self(output: CommonConsoleCommandOutput): + active_sim_info = CommonSimUtils.get_active_sim_info() + output(f'Purging the active Sim ({active_sim_info}) from existence.') + return CommonSimSpawnUtils.delete_sim(active_sim_info) + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.purge_sim', + 'Purge a Sim, essentially deleting them.', + command_arguments=( + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to purge.', is_optional=False), + ) +) +def _s4cl_purge_sim(output: CommonConsoleCommandOutput, sim_info: SimInfo): + if sim_info is None: + return + if sim_info is CommonSimUtils.get_active_sim_info(): + output('Failed, If you want to purge the active Sim, use "s4clib.purge_self" instead.') + return + output(f'Purging Sim from existence {sim_info}') + CommonSimSpawnUtils.delete_sim(sim_info, source='Player', cause='Command Purged') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.be_alone', + 'Purge all Sims except the active Sim from the neighborhood.' +) +def _s4cl_be_alone(output: CommonConsoleCommandOutput): + active_sim_info = CommonSimUtils.get_active_sim_info() + output('Purging everyone but your active Sim.') + sim_count = 0 + sim_info_list = tuple(CommonSimUtils.get_sim_info_for_all_sims_generator()) + for sim_info in sim_info_list: + if sim_info is active_sim_info: + continue + CommonSimSpawnUtils.delete_sim(sim_info, source='Player', cause='Command Purged') + sim_count += 1 + output(f'Purged {sim_count} Sims') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.purge_neighborhood', + 'Purge all Sims including the active Sim from the neighborhood, essentially making your neighborhood a ghost town. WARNING: Only use this for fun, since you cannot do interactions without an active Sim!' +) +def _s4cl_purge_neighborhood(output: CommonConsoleCommandOutput): + output('Purging all Sims') + sim_count = 0 + sim_info_list = tuple(CommonSimUtils.get_sim_info_for_all_sims_generator()) + for sim_info in sim_info_list: + CommonSimSpawnUtils.delete_sim(sim_info, source='Player', cause='Command Purged') + sim_count += 1 + output(f'Purged {sim_count} Sims') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.purge_non_household', + 'Purge all Sims outside of the active household.' +) +def _s4cl_purge_non_household(output: CommonConsoleCommandOutput): + output('Purging all Sims outside of the Active Household.') + sim_count = 0 + sim_info_list = tuple(CommonSimUtils.get_sim_info_for_all_sims_generator()) + from sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils + for sim_info in sim_info_list: + if CommonHouseholdUtils.is_part_of_active_household(sim_info): + continue + CommonSimSpawnUtils.delete_sim(sim_info, source='Player', cause='Command Purged') + sim_count += 1 + output(f'Purged {sim_count} Sims') diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_spell_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_spell_utils.py new file mode 100644 index 0000000..a997863 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_spell_utils.py @@ -0,0 +1,302 @@ +""" +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 +""" +from typing import Union, Tuple + +from server_commands.argument_helpers import TunableInstanceParam +from sims.sim_info import SimInfo +from sims4.resources import Types +from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + CommonConsoleCommandArgument +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.common_resource_utils import CommonResourceUtils +from spells.spells import Spell + + +class CommonSimSpellUtils: + """Utilities for unlocking and locking things, usually learned things such as Spells. """ + @classmethod + def add_spell(cls, sim_info: SimInfo, spell: Union[int, Spell], mark_as_new: bool = True) -> CommonExecutionResult: + """add_spell(sim_info, spell, mark_as_new=True) + + Make a Sim learn a Spell. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param spell: The spell to add. + :type spell: Union[int, Spell] + :param mark_as_new: Set True to mark the Spell as being new. Set False to refrain from marking the spell as new. Default is True. + :type mark_as_new: bool, optional + :return: The result of executing the function. True, if successful. False, if not. + :rtype: CommonExecutionResult + """ + return cls.add_spells(sim_info, (spell,), mark_as_new=mark_as_new) + + @classmethod + def add_spells(cls, sim_info: SimInfo, spells: Tuple[Union[int, Spell]], mark_as_new: bool = True) -> CommonExecutionResult: + """add_spells(sim_info, spells, mark_as_new=True) + + Make a Sim learn Spells. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param spells: A collection of spells to add. + :type spells: Tuple[Union[int, Spell]] + :param mark_as_new: Set True to mark the Spells as being new. Set False to refrain from marking the spells as new. Default is True. + :type mark_as_new: bool, optional + :return: The result of executing the function. True, if successful. False, if not. + :rtype: CommonExecutionResult + """ + from sims4communitylib.utils.sims.common_sim_unlock_utils import CommonSimUnlockUtils + unlock_tracker = CommonSimUnlockUtils.get_unlock_tracker(sim_info) + if unlock_tracker is None: + return CommonExecutionResult(False, reason=f'Failed to locate the unlock tracker for {sim_info}') + for spell in spells: + spell_id = spell + spell = cls.load_spell_by_id(spell) + if spell is None: + return CommonExecutionResult(False, reason=f'Spell not found by id {spell_id}.') + unlock_tracker.add_unlock(spell, None, mark_as_new=mark_as_new) + return CommonExecutionResult.TRUE + + @classmethod + def add_all_spells(cls, sim_info: SimInfo) -> CommonExecutionResult: + """add_all_spells(sim_info) + + Make a Sim learn all Spells. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of executing the function. True, if successful. False, if not. + :rtype: CommonExecutionResult + """ + from sims4communitylib.utils.sims.common_sim_unlock_utils import CommonSimUnlockUtils + unlock_tracker = CommonSimUnlockUtils.get_unlock_tracker(sim_info) + if unlock_tracker is None: + return CommonExecutionResult(False, reason=f'Failed to locate the unlock tracker for {sim_info}') + spells: Tuple[Spell] = tuple(CommonResourceUtils.load_all_instance_values(Types.SPELL, return_type=Spell)) + return cls.add_spells(sim_info, spells) + + @classmethod + def remove_spell(cls, sim_info: SimInfo, spell: Union[int, Spell]) -> CommonExecutionResult: + """remove_spell(sim_info, spell) + + Make a Sim unlearn a Spell. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param spell: The spell to remove. + :type spell: Union[int, Spell] + :return: The result of executing the function. True, if successful. False, if not. + :rtype: CommonExecutionResult + """ + return cls.remove_spells(sim_info, (spell,)) + + @classmethod + def remove_spells(cls, sim_info: SimInfo, spells: Tuple[Union[int, Spell]]) -> CommonExecutionResult: + """remove_spells(sim_info, spells) + + Make a Sim unlearn Spells. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param spells: A collection of spells to remove. + :type spells: Tuple[Union[int, Spell]] + :return: The result of executing the function. True, if successful. False, if not. + :rtype: CommonExecutionResult + """ + from sims4communitylib.utils.sims.common_sim_unlock_utils import CommonSimUnlockUtils + unlock_tracker = CommonSimUnlockUtils.get_unlock_tracker(sim_info) + if unlock_tracker is None: + return CommonExecutionResult(False, reason=f'Failed to locate the unlock tracker for {sim_info}') + for spell in spells: + spell_id = spell + spell = cls.load_spell_by_id(spell) + if spell is None: + return CommonExecutionResult(False, reason=f'Spell not found by id {spell_id}.') + found_unlock = None + for unlock in unlock_tracker._unlocks: + if unlock.tuning_class == spell: + found_unlock = unlock + break + if not found_unlock: + return CommonExecutionResult(False, reason=f'Sim did not have spell {spell} unlocked.') + unlock_tracker._unlocks.remove(found_unlock) + if spell in unlock_tracker._marked_new_unlocks: + unlock_tracker._marked_new_unlocks.remove(spell) + (provided_super_affordances, provided_target_affordances) = unlock_tracker._get_provided_super_affordances_from_unlock(spell) + if provided_super_affordances: + if unlock_tracker._super_affordances_cache is not None: + for provided_super_affordance in provided_super_affordances: + if provided_super_affordance in unlock_tracker._super_affordances_cache: + unlock_tracker._super_affordances_cache.remove(provided_super_affordance) + if provided_target_affordances: + if unlock_tracker._target_provided_affordances_cache is not None: + for provided_target_affordance in provided_target_affordances: + if provided_target_affordance in unlock_tracker._target_provided_affordances_cache: + unlock_tracker._target_provided_affordances_cache.remove(provided_target_affordance) + return CommonExecutionResult.TRUE + + @classmethod + def remove_all_spells(cls, sim_info: SimInfo) -> CommonExecutionResult: + """remove_all_spells(sim_info) + + Make a Sim unlearn all Spells. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of executing the function. True, if successful. False, if not. + :rtype: CommonExecutionResult + """ + from sims4communitylib.utils.sims.common_sim_unlock_utils import CommonSimUnlockUtils + unlock_tracker = CommonSimUnlockUtils.get_unlock_tracker(sim_info) + if unlock_tracker is None: + return CommonExecutionResult(False, reason=f'Failed to locate the unlock tracker for {sim_info}') + spells: Tuple[Spell] = tuple(CommonResourceUtils.load_all_instance_values(Types.SPELL, return_type=Spell)) + return cls.remove_spells(sim_info, spells) + + @classmethod + def load_spell_by_id(cls, spell: Union[int, Spell]) -> Union[Spell, None]: + """load_spell_by_id(spell) + + Load an instance of a Spell by its decimal identifier. + + :param spell: The identifier of a Spell. + :type spell: Union[int, CommonSpellId, Spell] + :return: An instance of a Spell matching the decimal identifier or None if not found. + :rtype: Union[Spell, None] + """ + if isinstance(spell, Spell): + return spell + # noinspection PyBroadException + try: + # noinspection PyCallingNonCallable + spell_instance = spell() + if isinstance(spell_instance, Spell): + # noinspection PyTypeChecker + return spell + except: + pass + # noinspection PyBroadException + try: + spell: int = int(spell) + except: + # noinspection PyTypeChecker + spell: Spell = spell + return spell + + from sims4.resources import Types + from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + return CommonResourceUtils.load_instance(Types.SPELL, spell) + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.add_spell', + 'Add a Spell to a Sim.', + command_arguments=( + CommonConsoleCommandArgument('spell', 'Spell Id or Tuning Name', 'The decimal identifier or name of a spell to add.'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Id or Name of a Sim to modify.', + is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.unlock_spell', + 's4clib.learn_spell', + ) +) +def _common_add_spell( + output: CommonConsoleCommandOutput, + spell: TunableInstanceParam(Types.SPELL), + sim_info: SimInfo = None +): + output(f'Adding spell {spell} to Sim {sim_info}') + result = CommonSimSpellUtils.add_spell(sim_info, spell) + if result: + output(f'Successfully added spell {spell} to Sim {sim_info}') + else: + output(f'Failed to add spell {spell} to Sim {sim_info}. Reason: {result.reason}') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.remove_spell', + 'Remove a Spell from a Sim.', + command_arguments=( + CommonConsoleCommandArgument('spell', 'Spell Id or Tuning Name', 'The decimal identifier or name of a spell to remove.'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Id or Name of a Sim to modify.', + is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.lock_spell', + 's4clib.unlearn_spell', + ) +) +def _common_add_spell( + output: CommonConsoleCommandOutput, + spell: TunableInstanceParam(Types.SPELL), + sim_info: SimInfo = None +): + output(f'Removing spell {spell} from Sim {sim_info}') + result = CommonSimSpellUtils.remove_spell(sim_info, spell) + if result: + output(f'Successfully removed spell {spell} from Sim {sim_info}') + else: + output(f'Failed to remove spell {spell} from Sim {sim_info}. Reason: {result.reason}') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.add_all_spells', + 'Add all Spells to a Sim.', + command_arguments=( + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Id or Name of a Sim to modify.', + is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.add_spells', + 's4clib.unlock_all_spells', + 's4clib.learn_spells', + ) +) +def _common_add_all_spells( + output: CommonConsoleCommandOutput, + sim_info: SimInfo = None +): + output(f'Removing all spells to Sim {sim_info}') + result = CommonSimSpellUtils.add_all_spells(sim_info) + if result: + output(f'Successfully added all spells to Sim {sim_info}') + else: + output(f'Failed to add all spells to Sim {sim_info}. Reason: {result.reason}') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.remove_all_spells', + 'Remove all Spells from a Sim.', + command_arguments=( + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Id or Name of a Sim to modify.', + is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.remove_spells', + 's4clib.lock_all_spells', + 's4clib.unlearn_all_spells', + ) +) +def _common_remove_all_spells( + output: CommonConsoleCommandOutput, + sim_info: SimInfo = None +): + output(f'Removing all spells from Sim {sim_info}') + result = CommonSimSpellUtils.remove_all_spells(sim_info) + if result: + output(f'Successfully removed all spells from Sim {sim_info}') + else: + output(f'Failed to remove all spells from Sim {sim_info}. Reason: {result.reason}') diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_state_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_state_utils.py new file mode 100644 index 0000000..3f76308 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_state_utils.py @@ -0,0 +1,104 @@ +""" +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 +""" +import services +from sims.sim_info import SimInfo +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.enums.buffs_enum import CommonBuffId +from sims4communitylib.utils.sims.common_buff_utils import CommonBuffUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + + +class CommonSimStateUtils: + """Utilities for checking the state of a sim. + + """ + @staticmethod + def is_dying(sim_info: SimInfo) -> CommonTestResult: + """is_dying(sim_info) + + Determine if a Sim is currently dying. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim is dying. False, if the Sim is not dying. + :rtype: CommonTestResult + """ + return CommonBuffUtils.has_buff(sim_info, CommonBuffId.SIM_IS_DYING) + + @staticmethod + def is_wearing_towel(sim_info: SimInfo) -> CommonTestResult: + """is_wearing_towel(sim_info) + + Determine if a Sim is wearing a towel. + + ..warning:: Obsolete: Use :func:`~is_wearing_towel` in :class:`.CommonOutfitUtils` instead. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the sim is wearing a towel. False, if not. + :rtype: CommonTestResult + """ + from sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils + return CommonOutfitUtils.is_wearing_towel(sim_info) + + @staticmethod + def is_in_sunlight(sim_info: SimInfo) -> bool: + """is_in_sunlight(sim_info) + + Determine if a Sim is in sunlight. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is in sunlight. False, if the Sim is not in sunlight. + :rtype: bool + """ + from sims4communitylib.utils.common_time_utils import CommonTimeUtils + sim = CommonSimUtils.get_sim_instance(sim_info) + return CommonTimeUtils.get_time_service().is_in_sunlight(sim) + + @staticmethod + def is_leaving_zone(sim_info: SimInfo) -> bool: + """is_leaving_zone(sim_info) + + Determine if a Sim is currently leaving the zone. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is leaving the zone. False, if the Sim is not leaving the zone. + :rtype: bool + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + return sim is not None and services.sim_spawner_service().sim_is_leaving(sim) + + @staticmethod + def is_hidden(sim_info: SimInfo) -> bool: + """is_hidden(sim_info) + + Determine if a Sim is hidden. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is hidden. False, if the Sim is not hidden. + :rtype: bool + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + sim_id = CommonSimUtils.get_sim_id(sim_info) + return sim_id is None or sim is None or services.hidden_sim_service().is_hidden(sim_id) or sim.is_hidden() or sim.opacity == 0 + + @staticmethod + def is_visible(sim_info: SimInfo) -> bool: + """is_visible(sim_info) + + Determine if a Sim is visible. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is visible. False, if the Sim is not visible. + :rtype: bool + """ + return not CommonSimStateUtils.is_hidden(sim_info) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_statistic_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_statistic_utils.py new file mode 100644 index 0000000..613c6e8 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_statistic_utils.py @@ -0,0 +1,621 @@ +""" +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 +""" +from typing import Union, Iterator + +from distributor.shared_messages import IconInfoData +from objects.components.statistic_component import StatisticComponent +from server_commands.argument_helpers import TunableInstanceParam +from sims.sim_info import SimInfo +from sims4.resources import Types +from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.enums.statistics_enum import CommonStatisticId +from sims4communitylib.enums.types.component_types import CommonComponentType +from sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + CommonConsoleCommandArgument +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.common_component_utils import CommonComponentUtils +from sims4communitylib.utils.common_log_registry import CommonLogRegistry +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from sims4communitylib.utils.resources.common_statistic_utils import CommonStatisticUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from statistics.base_statistic import BaseStatistic + + +class CommonSimStatisticUtils(_HasS4CLClassLog): + """Utilities for manipulating the Statistics of Sims. + + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 'common_sim_statistic_utils' + + @classmethod + def has_statistic(cls, sim_info: SimInfo, statistic: Union[int, CommonStatisticId, BaseStatistic]) -> CommonTestResult: + """has_statistic(sim_info, statistic) + + Determine if a Sim has any of the specified Statistics. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :param statistic: The identifier of the statistic to check. + :type statistic: Union[int, CommonStatisticId, BaseStatistic] + :return: True, if the Sim has any of the statistics. False, if not. + :rtype: bool + """ + statistic = cls.get_statistic(sim_info, statistic, add=False) + if statistic is not None: + return CommonTestResult(True, reason=f'Sim had statistic {statistic}.') + return CommonTestResult(False, reason=f'Sim did not have statistic {statistic}.') + + @classmethod + def has_statistics(cls, sim_info: SimInfo, statistics: Iterator[Union[int, CommonStatisticId, BaseStatistic]]) -> CommonTestResult: + """has_statistics(sim_info, statistics) + + Determine if a Sim has any of the specified Statistics. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :param statistics: An iterator of identifiers for statistics to check. + :type statistics: Iterator[Union[int, CommonStatisticId, BaseStatistic]] + :return: True, if the Sim has any of the specified statistics. False, if not. + :rtype: bool + """ + for statistic in statistics: + result = cls.has_statistic(sim_info, statistic) + if result: + return result + return CommonTestResult(False, reason=f'Sim did not have any of the specified statistics.') + + # noinspection PyUnusedLocal + @classmethod + def is_statistic_locked(cls, sim_info: SimInfo, statistic: Union[int, CommonStatisticId, BaseStatistic], add_dynamic: bool=False, add: bool= False) -> CommonTestResult: + """is_statistic_locked(sim_info, statistic, add_dynamic=False, 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: The identifier of the statistic to check. + :type statistic: Union[int, CommonStatisticId, BaseStatistic] + :param add_dynamic: OBSOLETE: Add the statistic component to the Sim. This argument is no longer used and will be ignored. + :type add_dynamic: bool, optional + :param add: Whether or not to add the statistic to the Sim. + :type add: bool, optional + :return: The result of checking if the statistic is locked or not. True, if the statistic is locked. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + cls.get_log().format_with_message('sim_info was None!', statistic=statistic, sim=sim_info) + return CommonTestResult(False, reason='sim_info was None.') + statistic_id = CommonStatisticUtils.get_statistic_id(statistic) + if statistic_id is None: + cls.get_log().format_with_message('No statistic found when checking locked.', statistic=statistic, sim=sim_info) + return CommonTestResult(False, reason='The specified statistic did not exist.') + statistic_instance = cls.get_statistic(sim_info, statistic_id, add=add) + if statistic_instance is None: + cls.get_log().format_with_message('No statistic found on Sim when checking locked.', statistic=statistic, statistic_id=statistic_id, sim=sim_info) + return CommonTestResult(False, reason=f'Sim did not have statistic {statistic}.') + if sim_info.is_locked(statistic_instance): + return CommonTestResult(True, reason='Statistic is locked.') + return CommonTestResult(False, reason='Statistic is not locked.') + + @classmethod + def get_statistic_level(cls, sim_info: SimInfo, statistic: Union[int, CommonStatisticId, BaseStatistic]) -> float: + """get_statistic_level(sim_info, statistic) + + Retrieve the User Value of a Statistic for the specified Sim. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :param statistic: The identifier of the statistic to retrieve the user value of. + :type statistic: Union[int, CommonStatisticId, BaseStatistic] + :return: The value of the statistic, `-1.0` if the statistic is not found. + :rtype: float + """ + statistic_instance = cls.get_statistic(sim_info, statistic) + if statistic_instance is None: + cls.get_log().format_with_message('No statistic found on Sim when getting level.', statistic=statistic, sim=sim_info) + return -1.0 + return statistic_instance.get_user_value() + + # noinspection PyUnusedLocal + @classmethod + def get_statistic(cls, sim_info: SimInfo, statistic: Union[int, CommonStatisticId, BaseStatistic], add_dynamic: bool=False, add: bool=False) -> Union[BaseStatistic, None]: + """get_statistic(sim_info, statistic, statistic, add_dynamic=False, add=False) + + Retrieve a Statistic for the specified Sim. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :param statistic: The identifier of the statistic to retrieve of. + :type statistic: Union[int, CommonStatisticId, BaseStatistic] + :param add_dynamic: OBSOLETE: Add the statistic component to the Sim. This argument is no longer used and will be ignored. + :type add_dynamic: bool, optional + :param add: Whether or not to 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: + cls.get_log().format_with_message('sim_info was None!', statistic=statistic, sim=sim_info) + return None + statistic_instance = CommonStatisticUtils.load_statistic_by_id(statistic) + if statistic_instance is None: + cls.get_log().format_with_message('No statistic found when loading statistic by id.', statistic=statistic, sim=sim_info) + return None + if sim_info.get_tracker(statistic_instance) is None: + return None + return sim_info.get_statistic(statistic_instance, add=add) + + # noinspection PyUnusedLocal + @classmethod + def get_statistic_value(cls, sim_info: SimInfo, statistic: Union[int, CommonStatisticId, BaseStatistic], add_dynamic: bool=False, add: bool=False) -> float: + """get_statistic_value(sim_info, statistic, add_dynamic=False, 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: The identifier of the statistic to retrieve the value of. + :type statistic: Union[int, CommonStatisticId, BaseStatistic] + :param add_dynamic: OBSOLETE: Add the statistic component to the Sim. This argument is no longer used and will be ignored. + :type add_dynamic: bool, optional + :param add: Whether or not to add the statistic to the Sim. This argument is no longer used and will be ignored. + :type add: bool, optional + :return: The value of the statistic, `-1.0` if the statistic is not found. + :rtype: float + """ + if sim_info is None: + cls.get_log().format_with_message('sim_info was None!', statistic=statistic, sim=sim_info) + return -1.0 + statistic_instance = CommonStatisticUtils.load_statistic_by_id(statistic) + if statistic_instance is None: + cls.get_log().format_with_message('No statistic found on Sim when getting statistic value.', statistic=statistic, sim=sim_info) + return -1.0 + try: + if not CommonComponentUtils.has_component(sim_info, CommonComponentType.STATISTIC): + if not add: + return -1.0 + else: + CommonComponentUtils.add_dynamic_component(sim_info, CommonComponentType.STATISTIC) + statistic_component: StatisticComponent = CommonComponentUtils.get_component(sim_info, CommonComponentType.STATISTIC, add_dynamic=add_dynamic) + if statistic_component is None: + return -1.0 + return statistic_component.get_stat_value(statistic_instance) + except Exception as ex: + cls.get_log().format_error_with_message('An error occurred while getting statistic value.', sim_info=sim_info, sim_type=type(sim_info), has_get_stat_value=hasattr(sim_info, 'get_stat_value'), get_stat_value=sim_info.get_stat_value, exception=ex, update_tokens=False) + + # noinspection PyUnusedLocal + @classmethod + def set_statistic_value(cls, sim_info: SimInfo, statistic: Union[int, CommonStatisticId, BaseStatistic], value: float, add_dynamic: bool=True, add: bool=True) -> CommonExecutionResult: + """set_statistic_value(sim_info, statistic, 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: The identifier of the statistic to add a value to. + :type statistic: Union[int, CommonStatisticId, BaseStatistic] + :param value: The amount to add. + :type value: float + :param add_dynamic: OBSOLETE: Add the statistic component to the Sim. This argument is no longer used and will be ignored. + :type add_dynamic: bool, optional + :param add: Whether or not to add the statistic to the Sim. + :type add: bool, optional + :return: The result of setting the statistic value. True, if successful. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + cls.get_log().format_with_message('sim_info was None!', statistic=statistic, sim=sim_info) + return CommonExecutionResult(False, reason='sim_info was None.') + result = cls.is_statistic_locked(sim_info, statistic, add=add) + if result: + cls.get_log().format_with_message('Statistic is locked and thus cannot be set.', statistic=statistic, sim=sim_info) + return result + statistic_instance = CommonStatisticUtils.load_statistic_by_id(statistic) + if statistic_instance is None: + cls.get_log().format_with_message('No statistic found when setting value.', statistic=statistic, sim=sim_info) + return CommonExecutionResult(False, reason='The specified statistic did not exist.') + sim_info.set_stat_value(statistic_instance, value) + return CommonExecutionResult.TRUE + + # noinspection PyUnusedLocal + @classmethod + def set_statistic_level(cls, sim_info: SimInfo, statistic: Union[int, CommonStatisticId, BaseStatistic], value: float, add: bool=True) -> CommonExecutionResult: + """set_statistic_level(sim_info, statistic, value, add_dynamic=True, add=True) + + Set the Level of a Statistic for the specified Sim. + + :param sim_info: The Sim to modify. + :type sim_info: SimInfo + :param statistic: The identifier of the statistic to add a user value to. + :type statistic: Union[int, CommonStatisticId, BaseStatistic] + :param value: The level to set the statistic to. + :type value: float + :param add: Whether or not to add the statistic to the Sim. + :type add: bool, optional + :return: The result of setting the statistic level. True, if successful. False, if not successful. + :rtype: CommonExecutionResult + """ + return cls.set_statistic_user_value(sim_info, statistic, value, add=add) + + # noinspection PyUnusedLocal + @classmethod + def set_statistic_user_value(cls, sim_info: SimInfo, statistic: Union[int, CommonStatisticId, BaseStatistic], value: float, add_dynamic: bool=True, add: bool=True) -> CommonExecutionResult: + """set_statistic_user_value(sim_info, statistic, 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: The identifier of the statistic to add a user value to. + :type statistic: Union[int, CommonStatisticId, BaseStatistic] + :param value: The user value to set the statistic to. + :type value: float + :param add_dynamic: OBSOLETE: Add the statistic component to the Sim. This argument is no longer used and will be ignored. + :type add_dynamic: bool, optional + :param add: Whether or not to 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: + cls.get_log().format_with_message('sim_info was None!', statistic=statistic, sim=sim_info) + return CommonExecutionResult(False, reason='sim_info was None.') + result = cls.is_statistic_locked(sim_info, statistic, add=add) + if result: + cls.get_log().format_with_message('Statistic is locked and thus cannot be set.', statistic=statistic, sim=sim_info) + return result + statistic_instance = cls.get_statistic(sim_info, statistic, add=add) + if statistic_instance is None: + cls.get_log().format_with_message('No statistic found on Sim when setting statistic user value.', statistic=statistic, sim=sim_info) + return CommonExecutionResult(False, reason='The specified statistic did not exist.') + statistic_instance.set_user_value(value) + return CommonExecutionResult(True, reason=f'Statistic {statistic} level successfully set on Sim {sim_info}.') + + # noinspection PyUnusedLocal + @classmethod + def add_statistic_value(cls, sim_info: SimInfo, statistic: Union[int, CommonStatisticId, BaseStatistic], value: float, add_dynamic: bool=True, add: bool=True) -> CommonExecutionResult: + """add_statistic_value(sim_info, statistic, 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: The identifier of the statistic to add a value to. + :type statistic: Union[int, CommonStatisticId, BaseStatistic] + :param value: The amount to add. + :type value: float + :param add_dynamic: OBSOLETE: Add the statistic component to the Sim. This argument is no longer used and will be ignored. + :type add_dynamic: bool, optional + :param add: Whether or not to add the statistic to the Sim. + :type add: bool, optional + :return: The result of setting the statistic value. True, if successful. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + return cls.set_statistic_value(sim_info, statistic, cls.get_statistic_value(sim_info, statistic) + value, add=add) + + @classmethod + def remove_statistic(cls, sim_info: SimInfo, statistic: Union[int, CommonStatisticId, BaseStatistic]) -> bool: + """remove_statistic(sim_info, statistic) + + Remove a Statistic from the specified Sim. + + :param sim_info: The Sim to modify. + :type sim_info: SimInfo + :param statistic: The identifier of the statistic to remove. + :type statistic: Union[int, CommonStatisticId, BaseStatistic] + :return: True, if successful. False, if not successful. + :rtype: bool + """ + if sim_info is None: + cls.get_log().format_with_message('sim_info was None!', statistic=statistic, sim=sim_info) + return False + statistic = CommonStatisticUtils.load_statistic_by_id(statistic) + if statistic is None: + cls.get_log().format_with_message('No statistic found on Sim when removing statistic.', statistic=statistic, sim=sim_info) + return True + sim_info.remove_statistic(statistic) + return True + + # noinspection PyUnusedLocal + @classmethod + def add_statistic_modifier(cls, sim_info: SimInfo, statistic: Union[int, CommonStatisticId, BaseStatistic], value: float, add_dynamic: bool=True, add: bool=True): + """add_statistic_modifier(sim_info, statistic, 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: The identifier of the statistic containing the modifier. + :type statistic: Union[int, CommonStatisticId, BaseStatistic] + :param value: The modifier to add. + :type value: float + :param add_dynamic: OBSOLETE: Add the statistic component to the Sim. This argument is no longer used and will be ignored. + :type add_dynamic: bool, optional + :param add: Whether or not to add the statistic to the Sim. + :type add: bool, optional + """ + if sim_info is None: + cls.get_log().format_with_message('sim_info was None!', statistic=statistic, sim=sim_info) + return None + statistic = CommonStatisticUtils.load_statistic_by_id(statistic) + if statistic is None: + cls.get_log().format_with_message('No statistic found on Sim.', statistic=statistic, sim=sim_info) + return None + stat = sim_info.get_statistic(statistic) + if stat is None: + return + stat.add_statistic_modifier(value) + return None + + # noinspection PyUnusedLocal + @classmethod + def remove_statistic_modifier(cls, sim_info: SimInfo, statistic: Union[int, CommonStatisticId, BaseStatistic], value: float, add_dynamic: bool=True, add: bool=True) -> bool: + """remove_statistic_modifier(sim_info, statistic, value, add_dynamic=True, add=True) + + Remove a Modifier from a Sim by value. + + :param sim_info: The Sim to modify. + :type sim_info: SimInfo + :param statistic: The identifier of the statistic to remove the modifier from. + :type statistic: Union[int, CommonStatisticId, BaseStatistic] + :param value: The modifier to remove. + :type value: float + :param add_dynamic: OBSOLETE: Add the statistic component to the Sim. This argument is no longer used and will be ignored. + :type add_dynamic: bool, optional + :param add: Whether or not to 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: + cls.get_log().format_with_message('sim_info was None!', statistic=statistic, sim=sim_info) + return False + statistic_instance = cls.get_statistic(sim_info, statistic, add=add) + if statistic_instance is None: + cls.get_log().format_with_message('No statistic found on Sim.', statistic=statistic, sim=sim_info) + return False + statistic_instance.remove_statistic_modifier(value) + return True + + @classmethod + def remove_statistic_modifier_by_handle_id(cls, sim_info: SimInfo, modifier_handle_id: int) -> bool: + """remove_statistic_modifier_by_handle_id(sim_info, modifier_handle_id) + + Remove a Statistic Modifier from a Sim by a handle id. + + :param sim_info: The Sim to modify. + :type sim_info: SimInfo + :param modifier_handle_id: The handle id for the statistic modifier being removed. + :type modifier_handle_id: int + :return: True, if the modifier was removed successfully. False, if not. + :rtype: bool + """ + if sim_info is None: + cls.get_log().format_with_message('sim_info was None!', modifier_handle=modifier_handle_id, sim=sim_info) + return False + return sim_info.remove_statistic_modifier(modifier_handle_id) + + # noinspection PyUnusedLocal + @classmethod + def remove_all_statistic_modifiers_for_statistic(cls, sim_info: SimInfo, statistic: Union[int, CommonStatisticId, BaseStatistic], add_dynamic: bool=True, add: bool=True) -> bool: + """remove_all_statistic_modifiers_for_statistic(sim_info, statistic, 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: The identifier of the statistic to remove modifiers from. + :type statistic: Union[int, CommonStatisticId, BaseStatistic] + :param add_dynamic: OBSOLETE: Add the statistic component to the Sim. This argument is no longer used and will be ignored. + :type add_dynamic: bool, optional + :param add: Whether or not to 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: + cls.get_log().format_with_message('sim_info was None!', statistic=statistic, sim=sim_info) + return False + statistic_instance = cls.get_statistic(sim_info, statistic, add=add) + if statistic_instance is None: + cls.get_log().format_with_message('No statistic found on Sim.', statistic=statistic, sim=sim_info) + return False + if not hasattr(statistic_instance, '_statistic_modifiers') or statistic_instance._statistic_modifiers is None: + return False + for value in list(statistic_instance._statistic_modifiers): + statistic_instance.remove_statistic_modifier(value) + return True + + +commands_log = CommonLogRegistry().register_log(ModInfo.get_identity(), 's4cl_statistic_commands') +commands_log.enable() + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.print_statistic_value', + 'Print the value of a statistic on a Sim.', + command_arguments=( + CommonConsoleCommandArgument('statistic', 'Statistic Id or Tuning Name', 'The tuning name or decimal identifier of a Statistic.'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to check.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.print_stat_value', + 's4clib.printstatvalue', + 's4clib.printstatisticvalue' + ) +) +def _common_print_statistic_value(output: CommonConsoleCommandOutput, statistic: TunableInstanceParam(Types.STATISTIC), sim_info: SimInfo=None): + if statistic is None: + output('ERROR: No Statistic specified or the specified Statistic did not exist!') + return + if sim_info is None: + return + output(f'Attempting to get statistic {statistic} on Sim {sim_info}.') + statistic_value = CommonSimStatisticUtils.get_statistic_value(sim_info, CommonStatisticUtils.get_statistic_id(statistic)) + output(f'Got statistic value of {statistic_value} of {statistic} on Sim {sim_info}.') + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.set_statistic_value', + 'Set the value of a statistic on a Sim.', + command_arguments=( + CommonConsoleCommandArgument('statistic', 'Statistic Id or Tuning Name', 'The tuning name or decimal identifier of a Statistic.'), + CommonConsoleCommandArgument('value', 'Decimal Number', 'The value to set the statistic to.'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to change.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.set_stat_value', + 's4clib.setstatvalue', + 's4clib.setstatisticvalue' + ) +) +def _common_set_statistic_value(output: CommonConsoleCommandOutput, statistic: TunableInstanceParam(Types.STATISTIC), value: float, sim_info: SimInfo=None): + if statistic is None: + output('ERROR: No Statistic specified or the specified Statistic did not exist!') + return + if sim_info is None: + return + output(f'Attempting to set statistic {statistic} on Sim {sim_info} to value {value}.') + if CommonSimStatisticUtils.set_statistic_value(sim_info, CommonStatisticUtils.get_statistic_id(statistic), value): + output(f'SUCCESS: Successfully set statistic {statistic} of Sim {sim_info} to value {value}.') + else: + output(f'FAILED: Failed to set statistic {statistic} of Sim {sim_info} to value {value}') + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.set_statistic_level', + 'Set the user level of a statistic on a Sim (User level should be set instead of setting value for statistics that belong to a Sim, such as Motives or Skills).', + command_arguments=( + CommonConsoleCommandArgument('statistic', 'Statistic Id or Tuning Name', 'The tuning name or decimal identifier of a Statistic.'), + CommonConsoleCommandArgument('level', 'Decimal Number', 'The level to set the statistic to.'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to change.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.set_statistic_user_value', + 's4clib.set_stat_level', + 's4clib.setstatlevel', + 's4clib.setstatisticlevel' + ) +) +def _common_set_statistic_user_value(output: CommonConsoleCommandOutput, statistic: TunableInstanceParam(Types.STATISTIC), level: float, sim_info: SimInfo=None): + if statistic is None: + output('ERROR: No Statistic specified or the specified Statistic did not exist!') + return + if sim_info is None: + return + output(f'Attempting to set statistic {statistic} on Sim {sim_info} to user level {level}.') + if CommonSimStatisticUtils.set_statistic_user_value(sim_info, statistic, level): + output(f'SUCCESS: Successfully set statistic {statistic} on Sim {sim_info} to user level {level}.') + else: + output(f'FAILED: Failed to set statistic {statistic} on Sim {sim_info} to user level {level}.') + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.print_statistic_level', + 'Print the user level of a statistic on a Sim (User level should be printed instead of the value for statistics that belong to a Sim, such as Motives or Skills).', + command_arguments=( + CommonConsoleCommandArgument('statistic', 'Statistic Id or Tuning Name', 'The tuning name or decimal identifier of a Statistic.'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to check.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.print_statistic_user_value', + 's4clib.print_stat_level', + 's4clib.printstatlevel', + 's4clib.printstatisticlevel' + ) +) +def _common_print_statistic_user_value(output: CommonConsoleCommandOutput, statistic: TunableInstanceParam(Types.STATISTIC), sim_info: SimInfo=None): + if statistic is None: + output('ERROR: No Statistic specified or the specified Statistic did not exist!') + return + if sim_info is None: + return + output(f'Attempting to print statistic {statistic} on Sim {sim_info}.') + level = CommonSimStatisticUtils.get_statistic_level(sim_info, CommonStatisticUtils.get_statistic_id(statistic)) + output(f'Got statistic level of {level} of {statistic} on Sim {sim_info}.') + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.remove_statistic', + 'Remove a Statistic or Commodity from a Sim.', + command_arguments=( + CommonConsoleCommandArgument('statistic', 'Statistic Id or Tuning Name', 'The tuning name or decimal identifier of a Statistic or Commodity.'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to change.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.remove_commodity', + 's4clib.remove_stat', + 's4clib.removestat', + 's4clib.removestatistic' + ) +) +def _common_remove_statistic(output: CommonConsoleCommandOutput, statistic: TunableInstanceParam(Types.STATISTIC), sim_info: SimInfo=None): + if statistic is None: + output('ERROR: No Statistic specified or the specified Statistic did not exist!') + return + if sim_info is None: + return + output(f'Attempting to remove statistic {statistic} from Sim {sim_info}.') + if CommonSimStatisticUtils.remove_statistic(sim_info, CommonStatisticUtils.get_statistic_id(statistic)): + output(f'SUCCESS: Successfully removed statistic {statistic} from Sim {sim_info}.') + else: + output(f'FAILED: Failed to remove statistic {statistic} from Sim {sim_info}.') + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_testing.print_static_commodities', + 'Print a list of a Static Commodities on a Sim.', + command_arguments=( + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to check.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib_testing.printstaticcommodities', + ) +) +def _common_print_static_commodities(output: CommonConsoleCommandOutput, sim_info: SimInfo=None): + log = CommonSimStatisticUtils.get_log() + try: + log.enable() + output(f'Printing static commodities of Sim {sim_info}') + text = '' + for stat in list(sim_info.static_commodity_tracker): + statistic_id = CommonStatisticUtils.get_statistic_id(stat) + text += f'{stat} ({statistic_id})\n' + sim_id = CommonSimUtils.get_sim_id(sim_info) + log.debug(f'{sim_info} Static Commodities ({sim_id})') + log.debug(text) + CommonBasicNotification( + CommonLocalizationUtils.create_localized_string(f'{sim_info} Static Commodities ({sim_id})'), + CommonLocalizationUtils.create_localized_string(text) + ).show( + icon=IconInfoData(obj_instance=CommonSimUtils.get_sim_instance(sim_info)) + ) + finally: + log.disable() diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_type_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_type_utils.py new file mode 100644 index 0000000..32ec646 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_type_utils.py @@ -0,0 +1,2603 @@ +""" +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 +""" +from typing import Dict, Iterator +from sims.sim_info import SimInfo +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.enums.common_age import CommonAge +from sims4communitylib.enums.common_occult_type import CommonOccultType +from sims4communitylib.enums.common_species import CommonSpecies +from sims4communitylib.enums.sim_type import CommonSimType +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + CommonConsoleCommandArgument +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.sims.common_occult_utils import CommonOccultUtils + + +class CommonSimTypeUtils: + """Utilities for determining the type of a Sim. i.e. Player, NPC, Service, etc. + + """ + _CHILD_DOG_SIM_TYPE_MAPPING: Dict[CommonSimType, CommonSimType] = { + CommonSimType.CHILD_SMALL_DOG: CommonSimType.CHILD_DOG, + CommonSimType.CHILD_SMALL_DOG_VAMPIRE: CommonSimType.CHILD_DOG_VAMPIRE, + CommonSimType.CHILD_SMALL_DOG_GHOST: CommonSimType.CHILD_DOG_GHOST, + CommonSimType.CHILD_SMALL_DOG_ALIEN: CommonSimType.CHILD_DOG_ALIEN, + CommonSimType.CHILD_SMALL_DOG_MERMAID: CommonSimType.CHILD_DOG_MERMAID, + CommonSimType.CHILD_SMALL_DOG_WITCH: CommonSimType.CHILD_DOG_WITCH, + CommonSimType.CHILD_SMALL_DOG_ROBOT: CommonSimType.CHILD_DOG_ROBOT, + CommonSimType.CHILD_SMALL_DOG_SCARECROW: CommonSimType.CHILD_DOG_SCARECROW, + CommonSimType.CHILD_SMALL_DOG_SKELETON: CommonSimType.CHILD_DOG_SKELETON, + CommonSimType.CHILD_SMALL_DOG_PLANT_SIM: CommonSimType.CHILD_DOG_PLANT_SIM, + CommonSimType.CHILD_SMALL_DOG_WEREWOLF: CommonSimType.CHILD_DOG_WEREWOLF, + + CommonSimType.CHILD_LARGE_DOG: CommonSimType.CHILD_DOG, + CommonSimType.CHILD_LARGE_DOG_VAMPIRE: CommonSimType.CHILD_DOG_VAMPIRE, + CommonSimType.CHILD_LARGE_DOG_GHOST: CommonSimType.CHILD_DOG_GHOST, + CommonSimType.CHILD_LARGE_DOG_ALIEN: CommonSimType.CHILD_DOG_ALIEN, + CommonSimType.CHILD_LARGE_DOG_MERMAID: CommonSimType.CHILD_DOG_MERMAID, + CommonSimType.CHILD_LARGE_DOG_WITCH: CommonSimType.CHILD_DOG_WITCH, + CommonSimType.CHILD_LARGE_DOG_ROBOT: CommonSimType.CHILD_DOG_ROBOT, + CommonSimType.CHILD_LARGE_DOG_SCARECROW: CommonSimType.CHILD_DOG_SCARECROW, + CommonSimType.CHILD_LARGE_DOG_SKELETON: CommonSimType.CHILD_DOG_SKELETON, + CommonSimType.CHILD_LARGE_DOG_PLANT_SIM: CommonSimType.CHILD_DOG_PLANT_SIM, + CommonSimType.CHILD_LARGE_DOG_WEREWOLF: CommonSimType.CHILD_DOG_WEREWOLF, + } + + _SIM_TO_SIM_TYPE_MAPPING: Dict[CommonSpecies, Dict[CommonAge, Dict[CommonOccultType, CommonSimType]]] = { + CommonSpecies.HUMAN: { + CommonAge.ELDER: { + CommonOccultType.NON_OCCULT: CommonSimType.ELDER_HUMAN, + CommonOccultType.VAMPIRE: CommonSimType.ELDER_HUMAN_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.ELDER_HUMAN_GHOST, + CommonOccultType.ALIEN: CommonSimType.ELDER_HUMAN_ALIEN, + CommonOccultType.MERMAID: CommonSimType.ELDER_HUMAN_MERMAID, + CommonOccultType.WITCH: CommonSimType.ELDER_HUMAN_WITCH, + CommonOccultType.ROBOT: CommonSimType.ELDER_HUMAN_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.ELDER_HUMAN_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.ELDER_HUMAN_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.ELDER_HUMAN_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.ELDER_HUMAN_WEREWOLF, + }, + CommonAge.ADULT: { + CommonOccultType.NON_OCCULT: CommonSimType.ADULT_HUMAN, + CommonOccultType.VAMPIRE: CommonSimType.ADULT_HUMAN_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.ADULT_HUMAN_GHOST, + CommonOccultType.ALIEN: CommonSimType.ADULT_HUMAN_ALIEN, + CommonOccultType.MERMAID: CommonSimType.ADULT_HUMAN_MERMAID, + CommonOccultType.WITCH: CommonSimType.ADULT_HUMAN_WITCH, + CommonOccultType.ROBOT: CommonSimType.ADULT_HUMAN_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.ADULT_HUMAN_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.ADULT_HUMAN_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.ADULT_HUMAN_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.ADULT_HUMAN_WEREWOLF, + }, + CommonAge.YOUNGADULT: { + CommonOccultType.NON_OCCULT: CommonSimType.YOUNG_ADULT_HUMAN, + CommonOccultType.VAMPIRE: CommonSimType.YOUNG_ADULT_HUMAN_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.YOUNG_ADULT_HUMAN_GHOST, + CommonOccultType.ALIEN: CommonSimType.YOUNG_ADULT_HUMAN_ALIEN, + CommonOccultType.MERMAID: CommonSimType.YOUNG_ADULT_HUMAN_MERMAID, + CommonOccultType.WITCH: CommonSimType.YOUNG_ADULT_HUMAN_WITCH, + CommonOccultType.ROBOT: CommonSimType.YOUNG_ADULT_HUMAN_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.YOUNG_ADULT_HUMAN_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.YOUNG_ADULT_HUMAN_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.YOUNG_ADULT_HUMAN_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.YOUNG_ADULT_HUMAN_WEREWOLF, + }, + CommonAge.TEEN: { + CommonOccultType.NON_OCCULT: CommonSimType.TEEN_HUMAN, + CommonOccultType.VAMPIRE: CommonSimType.TEEN_HUMAN_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.TEEN_HUMAN_GHOST, + CommonOccultType.ALIEN: CommonSimType.TEEN_HUMAN_ALIEN, + CommonOccultType.MERMAID: CommonSimType.TEEN_HUMAN_MERMAID, + CommonOccultType.WITCH: CommonSimType.TEEN_HUMAN_WITCH, + CommonOccultType.ROBOT: CommonSimType.TEEN_HUMAN_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.TEEN_HUMAN_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.TEEN_HUMAN_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.TEEN_HUMAN_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.TEEN_HUMAN_WEREWOLF, + }, + CommonAge.CHILD: { + CommonOccultType.NON_OCCULT: CommonSimType.CHILD_HUMAN, + CommonOccultType.VAMPIRE: CommonSimType.CHILD_HUMAN_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.CHILD_HUMAN_GHOST, + CommonOccultType.ALIEN: CommonSimType.CHILD_HUMAN_ALIEN, + CommonOccultType.MERMAID: CommonSimType.CHILD_HUMAN_MERMAID, + CommonOccultType.WITCH: CommonSimType.CHILD_HUMAN_WITCH, + CommonOccultType.ROBOT: CommonSimType.CHILD_HUMAN_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.CHILD_HUMAN_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.CHILD_HUMAN_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.CHILD_HUMAN_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.CHILD_HUMAN_WEREWOLF, + }, + CommonAge.TODDLER: { + CommonOccultType.NON_OCCULT: CommonSimType.TODDLER_HUMAN, + CommonOccultType.VAMPIRE: CommonSimType.TODDLER_HUMAN_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.TODDLER_HUMAN_GHOST, + CommonOccultType.ALIEN: CommonSimType.TODDLER_HUMAN_ALIEN, + CommonOccultType.MERMAID: CommonSimType.TODDLER_HUMAN_MERMAID, + CommonOccultType.WITCH: CommonSimType.TODDLER_HUMAN_WITCH, + CommonOccultType.ROBOT: CommonSimType.TODDLER_HUMAN_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.TODDLER_HUMAN_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.TODDLER_HUMAN_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.TODDLER_HUMAN_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.TODDLER_HUMAN_WEREWOLF, + }, + CommonAge.INFANT: { + CommonOccultType.NON_OCCULT: CommonSimType.INFANT_HUMAN, + CommonOccultType.VAMPIRE: CommonSimType.INFANT_HUMAN_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.INFANT_HUMAN_GHOST, + CommonOccultType.ALIEN: CommonSimType.INFANT_HUMAN_ALIEN, + CommonOccultType.MERMAID: CommonSimType.INFANT_HUMAN_MERMAID, + CommonOccultType.WITCH: CommonSimType.INFANT_HUMAN_WITCH, + CommonOccultType.ROBOT: CommonSimType.INFANT_HUMAN_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.INFANT_HUMAN_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.INFANT_HUMAN_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.INFANT_HUMAN_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.INFANT_HUMAN_WEREWOLF, + }, + CommonAge.BABY: { + CommonOccultType.NON_OCCULT: CommonSimType.BABY_HUMAN, + CommonOccultType.VAMPIRE: CommonSimType.BABY_HUMAN_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.BABY_HUMAN_GHOST, + CommonOccultType.ALIEN: CommonSimType.BABY_HUMAN_ALIEN, + CommonOccultType.MERMAID: CommonSimType.BABY_HUMAN_MERMAID, + CommonOccultType.WITCH: CommonSimType.BABY_HUMAN_WITCH, + CommonOccultType.ROBOT: CommonSimType.BABY_HUMAN_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.BABY_HUMAN_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.BABY_HUMAN_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.BABY_HUMAN_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.BABY_HUMAN_WEREWOLF, + } + }, + CommonSpecies.SMALL_DOG: { + CommonAge.ELDER: { + CommonOccultType.NON_OCCULT: CommonSimType.ELDER_SMALL_DOG, + CommonOccultType.VAMPIRE: CommonSimType.ELDER_SMALL_DOG_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.ELDER_SMALL_DOG_GHOST, + CommonOccultType.ALIEN: CommonSimType.ELDER_SMALL_DOG_ALIEN, + CommonOccultType.MERMAID: CommonSimType.ELDER_SMALL_DOG_MERMAID, + CommonOccultType.WITCH: CommonSimType.ELDER_SMALL_DOG_WITCH, + CommonOccultType.ROBOT: CommonSimType.ELDER_SMALL_DOG_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.ELDER_SMALL_DOG_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.ELDER_SMALL_DOG_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.ELDER_SMALL_DOG_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.ELDER_SMALL_DOG_WEREWOLF, + }, + CommonAge.ADULT: { + CommonOccultType.NON_OCCULT: CommonSimType.ADULT_SMALL_DOG, + CommonOccultType.VAMPIRE: CommonSimType.ADULT_SMALL_DOG_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.ADULT_SMALL_DOG_GHOST, + CommonOccultType.ALIEN: CommonSimType.ADULT_SMALL_DOG_ALIEN, + CommonOccultType.MERMAID: CommonSimType.ADULT_SMALL_DOG_MERMAID, + CommonOccultType.WITCH: CommonSimType.ADULT_SMALL_DOG_WITCH, + CommonOccultType.ROBOT: CommonSimType.ADULT_SMALL_DOG_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.ADULT_SMALL_DOG_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.ADULT_SMALL_DOG_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.ADULT_SMALL_DOG_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.ADULT_SMALL_DOG_WEREWOLF, + }, + CommonAge.YOUNGADULT: { + CommonOccultType.NON_OCCULT: CommonSimType.ADULT_SMALL_DOG, + CommonOccultType.VAMPIRE: CommonSimType.ADULT_SMALL_DOG_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.ADULT_SMALL_DOG_GHOST, + CommonOccultType.ALIEN: CommonSimType.ADULT_SMALL_DOG_ALIEN, + CommonOccultType.MERMAID: CommonSimType.ADULT_SMALL_DOG_MERMAID, + CommonOccultType.WITCH: CommonSimType.ADULT_SMALL_DOG_WITCH, + CommonOccultType.ROBOT: CommonSimType.ADULT_SMALL_DOG_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.ADULT_SMALL_DOG_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.ADULT_SMALL_DOG_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.ADULT_SMALL_DOG_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.ADULT_SMALL_DOG_WEREWOLF, + }, + CommonAge.TEEN: { + CommonOccultType.NON_OCCULT: CommonSimType.ADULT_SMALL_DOG, + CommonOccultType.VAMPIRE: CommonSimType.ADULT_SMALL_DOG_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.ADULT_SMALL_DOG_GHOST, + CommonOccultType.ALIEN: CommonSimType.ADULT_SMALL_DOG_ALIEN, + CommonOccultType.MERMAID: CommonSimType.ADULT_SMALL_DOG_MERMAID, + CommonOccultType.WITCH: CommonSimType.ADULT_SMALL_DOG_WITCH, + CommonOccultType.ROBOT: CommonSimType.ADULT_SMALL_DOG_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.ADULT_SMALL_DOG_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.ADULT_SMALL_DOG_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.ADULT_SMALL_DOG_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.ADULT_SMALL_DOG_WEREWOLF, + }, + CommonAge.CHILD: { + CommonOccultType.NON_OCCULT: CommonSimType.CHILD_SMALL_DOG, + CommonOccultType.VAMPIRE: CommonSimType.CHILD_SMALL_DOG_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.CHILD_SMALL_DOG_GHOST, + CommonOccultType.ALIEN: CommonSimType.CHILD_SMALL_DOG_ALIEN, + CommonOccultType.MERMAID: CommonSimType.CHILD_SMALL_DOG_MERMAID, + CommonOccultType.WITCH: CommonSimType.CHILD_SMALL_DOG_WITCH, + CommonOccultType.ROBOT: CommonSimType.CHILD_SMALL_DOG_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.CHILD_SMALL_DOG_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.CHILD_SMALL_DOG_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.CHILD_SMALL_DOG_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.CHILD_SMALL_DOG_WEREWOLF, + }, + CommonAge.TODDLER: { + CommonOccultType.NON_OCCULT: CommonSimType.CHILD_SMALL_DOG, + CommonOccultType.VAMPIRE: CommonSimType.CHILD_SMALL_DOG_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.CHILD_SMALL_DOG_GHOST, + CommonOccultType.ALIEN: CommonSimType.CHILD_SMALL_DOG_ALIEN, + CommonOccultType.MERMAID: CommonSimType.CHILD_SMALL_DOG_MERMAID, + CommonOccultType.WITCH: CommonSimType.CHILD_SMALL_DOG_WITCH, + CommonOccultType.ROBOT: CommonSimType.CHILD_SMALL_DOG_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.CHILD_SMALL_DOG_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.CHILD_SMALL_DOG_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.CHILD_SMALL_DOG_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.CHILD_SMALL_DOG_WEREWOLF, + }, + CommonAge.INFANT: { + CommonOccultType.NON_OCCULT: CommonSimType.CHILD_SMALL_DOG, + CommonOccultType.VAMPIRE: CommonSimType.CHILD_SMALL_DOG_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.CHILD_SMALL_DOG_GHOST, + CommonOccultType.ALIEN: CommonSimType.CHILD_SMALL_DOG_ALIEN, + CommonOccultType.MERMAID: CommonSimType.CHILD_SMALL_DOG_MERMAID, + CommonOccultType.WITCH: CommonSimType.CHILD_SMALL_DOG_WITCH, + CommonOccultType.ROBOT: CommonSimType.CHILD_SMALL_DOG_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.CHILD_SMALL_DOG_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.CHILD_SMALL_DOG_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.CHILD_SMALL_DOG_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.CHILD_SMALL_DOG_WEREWOLF, + }, + CommonAge.BABY: { + CommonOccultType.NON_OCCULT: CommonSimType.CHILD_SMALL_DOG, + CommonOccultType.VAMPIRE: CommonSimType.CHILD_SMALL_DOG_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.CHILD_SMALL_DOG_GHOST, + CommonOccultType.ALIEN: CommonSimType.CHILD_SMALL_DOG_ALIEN, + CommonOccultType.MERMAID: CommonSimType.CHILD_SMALL_DOG_MERMAID, + CommonOccultType.WITCH: CommonSimType.CHILD_SMALL_DOG_WITCH, + CommonOccultType.ROBOT: CommonSimType.CHILD_SMALL_DOG_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.CHILD_SMALL_DOG_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.CHILD_SMALL_DOG_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.CHILD_SMALL_DOG_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.CHILD_SMALL_DOG_WEREWOLF, + } + }, + CommonSpecies.LARGE_DOG: { + CommonAge.ELDER: { + CommonOccultType.NON_OCCULT: CommonSimType.ELDER_LARGE_DOG, + CommonOccultType.VAMPIRE: CommonSimType.ELDER_LARGE_DOG_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.ELDER_LARGE_DOG_GHOST, + CommonOccultType.ALIEN: CommonSimType.ELDER_LARGE_DOG_ALIEN, + CommonOccultType.MERMAID: CommonSimType.ELDER_LARGE_DOG_MERMAID, + CommonOccultType.WITCH: CommonSimType.ELDER_LARGE_DOG_WITCH, + CommonOccultType.ROBOT: CommonSimType.ELDER_LARGE_DOG_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.ELDER_LARGE_DOG_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.ELDER_LARGE_DOG_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.ELDER_LARGE_DOG_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.ELDER_LARGE_DOG_WEREWOLF, + }, + CommonAge.ADULT: { + CommonOccultType.NON_OCCULT: CommonSimType.ADULT_LARGE_DOG, + CommonOccultType.VAMPIRE: CommonSimType.ADULT_LARGE_DOG_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.ADULT_LARGE_DOG_GHOST, + CommonOccultType.ALIEN: CommonSimType.ADULT_LARGE_DOG_ALIEN, + CommonOccultType.MERMAID: CommonSimType.ADULT_LARGE_DOG_MERMAID, + CommonOccultType.WITCH: CommonSimType.ADULT_LARGE_DOG_WITCH, + CommonOccultType.ROBOT: CommonSimType.ADULT_LARGE_DOG_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.ADULT_LARGE_DOG_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.ADULT_LARGE_DOG_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.ADULT_LARGE_DOG_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.ADULT_LARGE_DOG_WEREWOLF, + }, + CommonAge.YOUNGADULT: { + CommonOccultType.NON_OCCULT: CommonSimType.ADULT_LARGE_DOG, + CommonOccultType.VAMPIRE: CommonSimType.ADULT_LARGE_DOG_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.ADULT_LARGE_DOG_GHOST, + CommonOccultType.ALIEN: CommonSimType.ADULT_LARGE_DOG_ALIEN, + CommonOccultType.MERMAID: CommonSimType.ADULT_LARGE_DOG_MERMAID, + CommonOccultType.WITCH: CommonSimType.ADULT_LARGE_DOG_WITCH, + CommonOccultType.ROBOT: CommonSimType.ADULT_LARGE_DOG_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.ADULT_LARGE_DOG_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.ADULT_LARGE_DOG_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.ADULT_LARGE_DOG_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.ADULT_LARGE_DOG_WEREWOLF, + }, + CommonAge.TEEN: { + CommonOccultType.NON_OCCULT: CommonSimType.ADULT_LARGE_DOG, + CommonOccultType.VAMPIRE: CommonSimType.ADULT_LARGE_DOG_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.ADULT_LARGE_DOG_GHOST, + CommonOccultType.ALIEN: CommonSimType.ADULT_LARGE_DOG_ALIEN, + CommonOccultType.MERMAID: CommonSimType.ADULT_LARGE_DOG_MERMAID, + CommonOccultType.WITCH: CommonSimType.ADULT_LARGE_DOG_WITCH, + CommonOccultType.ROBOT: CommonSimType.ADULT_LARGE_DOG_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.ADULT_LARGE_DOG_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.ADULT_LARGE_DOG_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.ADULT_LARGE_DOG_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.ADULT_LARGE_DOG_WEREWOLF, + }, + CommonAge.CHILD: { + CommonOccultType.NON_OCCULT: CommonSimType.CHILD_LARGE_DOG, + CommonOccultType.VAMPIRE: CommonSimType.CHILD_LARGE_DOG_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.CHILD_LARGE_DOG_GHOST, + CommonOccultType.ALIEN: CommonSimType.CHILD_LARGE_DOG_ALIEN, + CommonOccultType.MERMAID: CommonSimType.CHILD_LARGE_DOG_MERMAID, + CommonOccultType.WITCH: CommonSimType.CHILD_LARGE_DOG_WITCH, + CommonOccultType.ROBOT: CommonSimType.CHILD_LARGE_DOG_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.CHILD_LARGE_DOG_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.CHILD_LARGE_DOG_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.CHILD_LARGE_DOG_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.CHILD_LARGE_DOG_WEREWOLF, + }, + CommonAge.TODDLER: { + CommonOccultType.NON_OCCULT: CommonSimType.CHILD_LARGE_DOG, + CommonOccultType.VAMPIRE: CommonSimType.CHILD_LARGE_DOG_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.CHILD_LARGE_DOG_GHOST, + CommonOccultType.ALIEN: CommonSimType.CHILD_LARGE_DOG_ALIEN, + CommonOccultType.MERMAID: CommonSimType.CHILD_LARGE_DOG_MERMAID, + CommonOccultType.WITCH: CommonSimType.CHILD_LARGE_DOG_WITCH, + CommonOccultType.ROBOT: CommonSimType.CHILD_LARGE_DOG_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.CHILD_LARGE_DOG_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.CHILD_LARGE_DOG_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.CHILD_LARGE_DOG_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.CHILD_LARGE_DOG_WEREWOLF, + }, + CommonAge.INFANT: { + CommonOccultType.NON_OCCULT: CommonSimType.CHILD_LARGE_DOG, + CommonOccultType.VAMPIRE: CommonSimType.CHILD_LARGE_DOG_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.CHILD_LARGE_DOG_GHOST, + CommonOccultType.ALIEN: CommonSimType.CHILD_LARGE_DOG_ALIEN, + CommonOccultType.MERMAID: CommonSimType.CHILD_LARGE_DOG_MERMAID, + CommonOccultType.WITCH: CommonSimType.CHILD_LARGE_DOG_WITCH, + CommonOccultType.ROBOT: CommonSimType.CHILD_LARGE_DOG_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.CHILD_LARGE_DOG_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.CHILD_LARGE_DOG_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.CHILD_LARGE_DOG_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.CHILD_LARGE_DOG_WEREWOLF, + }, + CommonAge.BABY: { + CommonOccultType.NON_OCCULT: CommonSimType.CHILD_LARGE_DOG, + CommonOccultType.VAMPIRE: CommonSimType.CHILD_LARGE_DOG_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.CHILD_LARGE_DOG_GHOST, + CommonOccultType.ALIEN: CommonSimType.CHILD_LARGE_DOG_ALIEN, + CommonOccultType.MERMAID: CommonSimType.CHILD_LARGE_DOG_MERMAID, + CommonOccultType.WITCH: CommonSimType.CHILD_LARGE_DOG_WITCH, + CommonOccultType.ROBOT: CommonSimType.CHILD_LARGE_DOG_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.CHILD_LARGE_DOG_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.CHILD_LARGE_DOG_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.CHILD_LARGE_DOG_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.CHILD_LARGE_DOG_WEREWOLF, + } + }, + CommonSpecies.CAT: { + CommonAge.ELDER: { + CommonOccultType.NON_OCCULT: CommonSimType.ELDER_CAT, + CommonOccultType.VAMPIRE: CommonSimType.ELDER_CAT_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.ELDER_CAT_GHOST, + CommonOccultType.ALIEN: CommonSimType.ELDER_CAT_ALIEN, + CommonOccultType.MERMAID: CommonSimType.ELDER_CAT_MERMAID, + CommonOccultType.WITCH: CommonSimType.ELDER_CAT_WITCH, + CommonOccultType.ROBOT: CommonSimType.ELDER_CAT_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.ELDER_CAT_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.ELDER_CAT_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.ELDER_CAT_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.ELDER_CAT_WEREWOLF, + }, + CommonAge.ADULT: { + CommonOccultType.NON_OCCULT: CommonSimType.ADULT_CAT, + CommonOccultType.VAMPIRE: CommonSimType.ADULT_CAT_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.ADULT_CAT_GHOST, + CommonOccultType.ALIEN: CommonSimType.ADULT_CAT_ALIEN, + CommonOccultType.MERMAID: CommonSimType.ADULT_CAT_MERMAID, + CommonOccultType.WITCH: CommonSimType.ADULT_CAT_WITCH, + CommonOccultType.ROBOT: CommonSimType.ADULT_CAT_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.ADULT_CAT_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.ADULT_CAT_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.ADULT_CAT_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.ADULT_CAT_WEREWOLF, + }, + CommonAge.YOUNGADULT: { + CommonOccultType.NON_OCCULT: CommonSimType.ADULT_CAT, + CommonOccultType.VAMPIRE: CommonSimType.ADULT_CAT_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.ADULT_CAT_GHOST, + CommonOccultType.ALIEN: CommonSimType.ADULT_CAT_ALIEN, + CommonOccultType.MERMAID: CommonSimType.ADULT_CAT_MERMAID, + CommonOccultType.WITCH: CommonSimType.ADULT_CAT_WITCH, + CommonOccultType.ROBOT: CommonSimType.ADULT_CAT_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.ADULT_CAT_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.ADULT_CAT_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.ADULT_CAT_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.ADULT_CAT_WEREWOLF, + }, + CommonAge.TEEN: { + CommonOccultType.NON_OCCULT: CommonSimType.ADULT_CAT, + CommonOccultType.VAMPIRE: CommonSimType.ADULT_CAT_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.ADULT_CAT_GHOST, + CommonOccultType.ALIEN: CommonSimType.ADULT_CAT_ALIEN, + CommonOccultType.MERMAID: CommonSimType.ADULT_CAT_MERMAID, + CommonOccultType.WITCH: CommonSimType.ADULT_CAT_WITCH, + CommonOccultType.ROBOT: CommonSimType.ADULT_CAT_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.ADULT_CAT_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.ADULT_CAT_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.ADULT_CAT_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.ADULT_CAT_WEREWOLF, + }, + CommonAge.CHILD: { + CommonOccultType.NON_OCCULT: CommonSimType.CHILD_CAT, + CommonOccultType.VAMPIRE: CommonSimType.CHILD_CAT_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.CHILD_CAT_GHOST, + CommonOccultType.ALIEN: CommonSimType.CHILD_CAT_ALIEN, + CommonOccultType.MERMAID: CommonSimType.CHILD_CAT_MERMAID, + CommonOccultType.WITCH: CommonSimType.CHILD_CAT_WITCH, + CommonOccultType.ROBOT: CommonSimType.CHILD_CAT_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.CHILD_CAT_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.CHILD_CAT_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.CHILD_CAT_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.CHILD_CAT_WEREWOLF, + }, + CommonAge.TODDLER: { + CommonOccultType.NON_OCCULT: CommonSimType.CHILD_CAT, + CommonOccultType.VAMPIRE: CommonSimType.CHILD_CAT_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.CHILD_CAT_GHOST, + CommonOccultType.ALIEN: CommonSimType.CHILD_CAT_ALIEN, + CommonOccultType.MERMAID: CommonSimType.CHILD_CAT_MERMAID, + CommonOccultType.WITCH: CommonSimType.CHILD_CAT_WITCH, + CommonOccultType.ROBOT: CommonSimType.CHILD_CAT_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.CHILD_CAT_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.CHILD_CAT_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.CHILD_CAT_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.CHILD_CAT_WEREWOLF, + }, + CommonAge.INFANT: { + CommonOccultType.NON_OCCULT: CommonSimType.CHILD_CAT, + CommonOccultType.VAMPIRE: CommonSimType.CHILD_CAT_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.CHILD_CAT_GHOST, + CommonOccultType.ALIEN: CommonSimType.CHILD_CAT_ALIEN, + CommonOccultType.MERMAID: CommonSimType.CHILD_CAT_MERMAID, + CommonOccultType.WITCH: CommonSimType.CHILD_CAT_WITCH, + CommonOccultType.ROBOT: CommonSimType.CHILD_CAT_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.CHILD_CAT_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.CHILD_CAT_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.CHILD_CAT_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.CHILD_CAT_WEREWOLF, + }, + CommonAge.BABY: { + CommonOccultType.NON_OCCULT: CommonSimType.CHILD_CAT, + CommonOccultType.VAMPIRE: CommonSimType.CHILD_CAT_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.CHILD_CAT_GHOST, + CommonOccultType.ALIEN: CommonSimType.CHILD_CAT_ALIEN, + CommonOccultType.MERMAID: CommonSimType.CHILD_CAT_MERMAID, + CommonOccultType.WITCH: CommonSimType.CHILD_CAT_WITCH, + CommonOccultType.ROBOT: CommonSimType.CHILD_CAT_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.CHILD_CAT_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.CHILD_CAT_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.CHILD_CAT_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.CHILD_CAT_WEREWOLF, + } + }, + CommonSpecies.FOX: { + CommonAge.ELDER: { + CommonOccultType.NON_OCCULT: CommonSimType.ELDER_FOX, + CommonOccultType.VAMPIRE: CommonSimType.ELDER_FOX_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.ELDER_FOX_GHOST, + CommonOccultType.ALIEN: CommonSimType.ELDER_FOX_ALIEN, + CommonOccultType.MERMAID: CommonSimType.ELDER_FOX_MERMAID, + CommonOccultType.WITCH: CommonSimType.ELDER_FOX_WITCH, + CommonOccultType.ROBOT: CommonSimType.ELDER_FOX_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.ELDER_FOX_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.ELDER_FOX_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.ELDER_FOX_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.ELDER_FOX_WEREWOLF, + }, + CommonAge.ADULT: { + CommonOccultType.NON_OCCULT: CommonSimType.ADULT_FOX, + CommonOccultType.VAMPIRE: CommonSimType.ADULT_FOX_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.ADULT_FOX_GHOST, + CommonOccultType.ALIEN: CommonSimType.ADULT_FOX_ALIEN, + CommonOccultType.MERMAID: CommonSimType.ADULT_FOX_MERMAID, + CommonOccultType.WITCH: CommonSimType.ADULT_FOX_WITCH, + CommonOccultType.ROBOT: CommonSimType.ADULT_FOX_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.ADULT_FOX_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.ADULT_FOX_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.ADULT_FOX_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.ADULT_FOX_WEREWOLF, + }, + CommonAge.YOUNGADULT: { + CommonOccultType.NON_OCCULT: CommonSimType.ADULT_FOX, + CommonOccultType.VAMPIRE: CommonSimType.ADULT_FOX_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.ADULT_FOX_GHOST, + CommonOccultType.ALIEN: CommonSimType.ADULT_FOX_ALIEN, + CommonOccultType.MERMAID: CommonSimType.ADULT_FOX_MERMAID, + CommonOccultType.WITCH: CommonSimType.ADULT_FOX_WITCH, + CommonOccultType.ROBOT: CommonSimType.ADULT_FOX_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.ADULT_FOX_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.ADULT_FOX_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.ADULT_FOX_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.ADULT_FOX_WEREWOLF, + }, + CommonAge.TEEN: { + CommonOccultType.NON_OCCULT: CommonSimType.ADULT_FOX, + CommonOccultType.VAMPIRE: CommonSimType.ADULT_FOX_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.ADULT_FOX_GHOST, + CommonOccultType.ALIEN: CommonSimType.ADULT_FOX_ALIEN, + CommonOccultType.MERMAID: CommonSimType.ADULT_FOX_MERMAID, + CommonOccultType.WITCH: CommonSimType.ADULT_FOX_WITCH, + CommonOccultType.ROBOT: CommonSimType.ADULT_FOX_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.ADULT_FOX_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.ADULT_FOX_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.ADULT_FOX_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.ADULT_FOX_WEREWOLF, + }, + CommonAge.CHILD: { + CommonOccultType.NON_OCCULT: CommonSimType.CHILD_FOX, + CommonOccultType.VAMPIRE: CommonSimType.CHILD_FOX_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.CHILD_FOX_GHOST, + CommonOccultType.ALIEN: CommonSimType.CHILD_FOX_ALIEN, + CommonOccultType.MERMAID: CommonSimType.CHILD_FOX_MERMAID, + CommonOccultType.WITCH: CommonSimType.CHILD_FOX_WITCH, + CommonOccultType.ROBOT: CommonSimType.CHILD_FOX_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.CHILD_FOX_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.CHILD_FOX_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.CHILD_FOX_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.CHILD_FOX_WEREWOLF, + }, + CommonAge.TODDLER: { + CommonOccultType.NON_OCCULT: CommonSimType.CHILD_FOX, + CommonOccultType.VAMPIRE: CommonSimType.CHILD_FOX_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.CHILD_FOX_GHOST, + CommonOccultType.ALIEN: CommonSimType.CHILD_FOX_ALIEN, + CommonOccultType.MERMAID: CommonSimType.CHILD_FOX_MERMAID, + CommonOccultType.WITCH: CommonSimType.CHILD_FOX_WITCH, + CommonOccultType.ROBOT: CommonSimType.CHILD_FOX_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.CHILD_FOX_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.CHILD_FOX_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.CHILD_FOX_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.CHILD_FOX_WEREWOLF, + }, + CommonAge.INFANT: { + CommonOccultType.NON_OCCULT: CommonSimType.CHILD_FOX, + CommonOccultType.VAMPIRE: CommonSimType.CHILD_FOX_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.CHILD_FOX_GHOST, + CommonOccultType.ALIEN: CommonSimType.CHILD_FOX_ALIEN, + CommonOccultType.MERMAID: CommonSimType.CHILD_FOX_MERMAID, + CommonOccultType.WITCH: CommonSimType.CHILD_FOX_WITCH, + CommonOccultType.ROBOT: CommonSimType.CHILD_FOX_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.CHILD_FOX_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.CHILD_FOX_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.CHILD_FOX_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.CHILD_FOX_WEREWOLF, + }, + CommonAge.BABY: { + CommonOccultType.NON_OCCULT: CommonSimType.CHILD_FOX, + CommonOccultType.VAMPIRE: CommonSimType.CHILD_FOX_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.CHILD_FOX_GHOST, + CommonOccultType.ALIEN: CommonSimType.CHILD_FOX_ALIEN, + CommonOccultType.MERMAID: CommonSimType.CHILD_FOX_MERMAID, + CommonOccultType.WITCH: CommonSimType.CHILD_FOX_WITCH, + CommonOccultType.ROBOT: CommonSimType.CHILD_FOX_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.CHILD_FOX_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.CHILD_FOX_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.CHILD_FOX_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.CHILD_FOX_WEREWOLF, + } + }, + CommonSpecies.HORSE: { + CommonAge.ELDER: { + CommonOccultType.NON_OCCULT: CommonSimType.ELDER_HORSE, + CommonOccultType.VAMPIRE: CommonSimType.ELDER_HORSE_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.ELDER_HORSE_GHOST, + CommonOccultType.ALIEN: CommonSimType.ELDER_HORSE_ALIEN, + CommonOccultType.MERMAID: CommonSimType.ELDER_HORSE_MERMAID, + CommonOccultType.WITCH: CommonSimType.ELDER_HORSE_WITCH, + CommonOccultType.ROBOT: CommonSimType.ELDER_HORSE_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.ELDER_HORSE_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.ELDER_HORSE_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.ELDER_HORSE_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.ELDER_HORSE_WEREWOLF, + }, + CommonAge.ADULT: { + CommonOccultType.NON_OCCULT: CommonSimType.ADULT_HORSE, + CommonOccultType.VAMPIRE: CommonSimType.ADULT_HORSE_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.ADULT_HORSE_GHOST, + CommonOccultType.ALIEN: CommonSimType.ADULT_HORSE_ALIEN, + CommonOccultType.MERMAID: CommonSimType.ADULT_HORSE_MERMAID, + CommonOccultType.WITCH: CommonSimType.ADULT_HORSE_WITCH, + CommonOccultType.ROBOT: CommonSimType.ADULT_HORSE_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.ADULT_HORSE_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.ADULT_HORSE_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.ADULT_HORSE_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.ADULT_HORSE_WEREWOLF, + }, + CommonAge.YOUNGADULT: { + CommonOccultType.NON_OCCULT: CommonSimType.ADULT_HORSE, + CommonOccultType.VAMPIRE: CommonSimType.ADULT_HORSE_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.ADULT_HORSE_GHOST, + CommonOccultType.ALIEN: CommonSimType.ADULT_HORSE_ALIEN, + CommonOccultType.MERMAID: CommonSimType.ADULT_HORSE_MERMAID, + CommonOccultType.WITCH: CommonSimType.ADULT_HORSE_WITCH, + CommonOccultType.ROBOT: CommonSimType.ADULT_HORSE_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.ADULT_HORSE_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.ADULT_HORSE_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.ADULT_HORSE_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.ADULT_HORSE_WEREWOLF, + }, + CommonAge.TEEN: { + CommonOccultType.NON_OCCULT: CommonSimType.ADULT_HORSE, + CommonOccultType.VAMPIRE: CommonSimType.ADULT_HORSE_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.ADULT_HORSE_GHOST, + CommonOccultType.ALIEN: CommonSimType.ADULT_HORSE_ALIEN, + CommonOccultType.MERMAID: CommonSimType.ADULT_HORSE_MERMAID, + CommonOccultType.WITCH: CommonSimType.ADULT_HORSE_WITCH, + CommonOccultType.ROBOT: CommonSimType.ADULT_HORSE_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.ADULT_HORSE_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.ADULT_HORSE_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.ADULT_HORSE_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.ADULT_HORSE_WEREWOLF, + }, + CommonAge.CHILD: { + CommonOccultType.NON_OCCULT: CommonSimType.CHILD_HORSE, + CommonOccultType.VAMPIRE: CommonSimType.CHILD_HORSE_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.CHILD_HORSE_GHOST, + CommonOccultType.ALIEN: CommonSimType.CHILD_HORSE_ALIEN, + CommonOccultType.MERMAID: CommonSimType.CHILD_HORSE_MERMAID, + CommonOccultType.WITCH: CommonSimType.CHILD_HORSE_WITCH, + CommonOccultType.ROBOT: CommonSimType.CHILD_HORSE_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.CHILD_HORSE_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.CHILD_HORSE_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.CHILD_HORSE_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.CHILD_HORSE_WEREWOLF, + }, + CommonAge.TODDLER: { + CommonOccultType.NON_OCCULT: CommonSimType.CHILD_HORSE, + CommonOccultType.VAMPIRE: CommonSimType.CHILD_HORSE_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.CHILD_HORSE_GHOST, + CommonOccultType.ALIEN: CommonSimType.CHILD_HORSE_ALIEN, + CommonOccultType.MERMAID: CommonSimType.CHILD_HORSE_MERMAID, + CommonOccultType.WITCH: CommonSimType.CHILD_HORSE_WITCH, + CommonOccultType.ROBOT: CommonSimType.CHILD_HORSE_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.CHILD_HORSE_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.CHILD_HORSE_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.CHILD_HORSE_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.CHILD_HORSE_WEREWOLF, + }, + CommonAge.INFANT: { + CommonOccultType.NON_OCCULT: CommonSimType.CHILD_HORSE, + CommonOccultType.VAMPIRE: CommonSimType.CHILD_HORSE_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.CHILD_HORSE_GHOST, + CommonOccultType.ALIEN: CommonSimType.CHILD_HORSE_ALIEN, + CommonOccultType.MERMAID: CommonSimType.CHILD_HORSE_MERMAID, + CommonOccultType.WITCH: CommonSimType.CHILD_HORSE_WITCH, + CommonOccultType.ROBOT: CommonSimType.CHILD_HORSE_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.CHILD_HORSE_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.CHILD_HORSE_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.CHILD_HORSE_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.CHILD_HORSE_WEREWOLF, + }, + CommonAge.BABY: { + CommonOccultType.NON_OCCULT: CommonSimType.CHILD_HORSE, + CommonOccultType.VAMPIRE: CommonSimType.CHILD_HORSE_VAMPIRE, + CommonOccultType.GHOST: CommonSimType.CHILD_HORSE_GHOST, + CommonOccultType.ALIEN: CommonSimType.CHILD_HORSE_ALIEN, + CommonOccultType.MERMAID: CommonSimType.CHILD_HORSE_MERMAID, + CommonOccultType.WITCH: CommonSimType.CHILD_HORSE_WITCH, + CommonOccultType.ROBOT: CommonSimType.CHILD_HORSE_ROBOT, + CommonOccultType.SCARECROW: CommonSimType.CHILD_HORSE_SCARECROW, + CommonOccultType.SKELETON: CommonSimType.CHILD_HORSE_SKELETON, + CommonOccultType.PLANT_SIM: CommonSimType.CHILD_HORSE_PLANT_SIM, + CommonOccultType.WEREWOLF: CommonSimType.CHILD_HORSE_WEREWOLF, + } + } + } + _SIM_TYPE_TO_SIGNATURE_MAPPING: Dict[CommonSimType, str] = { + # Human + # Elder + CommonSimType.ELDER_HUMAN: 'ElHu', + CommonSimType.ELDER_HUMAN_VAMPIRE: 'ElHuVa', + CommonSimType.ELDER_HUMAN_GHOST: 'ElHuGh', + CommonSimType.ELDER_HUMAN_ALIEN: 'ElHuAl', + CommonSimType.ELDER_HUMAN_MERMAID: 'ElHuMer', + CommonSimType.ELDER_HUMAN_WITCH: 'ElHuWi', + CommonSimType.ELDER_HUMAN_ROBOT: 'ElHuRo', + CommonSimType.ELDER_HUMAN_SCARECROW: 'ElHuScrw', + CommonSimType.ELDER_HUMAN_SKELETON: 'ElHuSk', + CommonSimType.ELDER_HUMAN_PLANT_SIM: 'ElHuPls', + CommonSimType.ELDER_HUMAN_WEREWOLF: 'ElHuWerWlf', + # Adult + CommonSimType.ADULT_HUMAN: 'AdHu', + CommonSimType.ADULT_HUMAN_VAMPIRE: 'AdHuVa', + CommonSimType.ADULT_HUMAN_GHOST: 'AdHuGh', + CommonSimType.ADULT_HUMAN_ALIEN: 'AdHuAl', + CommonSimType.ADULT_HUMAN_MERMAID: 'AdHuMer', + CommonSimType.ADULT_HUMAN_WITCH: 'AdHuWi', + CommonSimType.ADULT_HUMAN_ROBOT: 'AdHuRo', + CommonSimType.ADULT_HUMAN_SCARECROW: 'AdHuScrw', + CommonSimType.ADULT_HUMAN_SKELETON: 'AdHuSk', + CommonSimType.ADULT_HUMAN_PLANT_SIM: 'AdHuPls', + CommonSimType.ADULT_HUMAN_WEREWOLF: 'AdHuWerWlf', + # Young Adult + CommonSimType.YOUNG_ADULT_HUMAN: 'YadHu', + CommonSimType.YOUNG_ADULT_HUMAN_VAMPIRE: 'YadHuVa', + CommonSimType.YOUNG_ADULT_HUMAN_GHOST: 'YadHuGh', + CommonSimType.YOUNG_ADULT_HUMAN_ALIEN: 'YadHuAl', + CommonSimType.YOUNG_ADULT_HUMAN_MERMAID: 'YadHuMer', + CommonSimType.YOUNG_ADULT_HUMAN_WITCH: 'YadHuWi', + CommonSimType.YOUNG_ADULT_HUMAN_ROBOT: 'YadHuRo', + CommonSimType.YOUNG_ADULT_HUMAN_SCARECROW: 'YadHuScrw', + CommonSimType.YOUNG_ADULT_HUMAN_SKELETON: 'YadHuSk', + CommonSimType.YOUNG_ADULT_HUMAN_PLANT_SIM: 'YadHuPls', + CommonSimType.YOUNG_ADULT_HUMAN_WEREWOLF: 'YadHuWerWlf', + # Teen + CommonSimType.TEEN_HUMAN: 'TnHu', + CommonSimType.TEEN_HUMAN_VAMPIRE: 'TnHuVa', + CommonSimType.TEEN_HUMAN_GHOST: 'TnHuGh', + CommonSimType.TEEN_HUMAN_ALIEN: 'TnHuAl', + CommonSimType.TEEN_HUMAN_MERMAID: 'TnHuMer', + CommonSimType.TEEN_HUMAN_WITCH: 'TnHuWi', + CommonSimType.TEEN_HUMAN_ROBOT: 'TnHuRo', + CommonSimType.TEEN_HUMAN_SCARECROW: 'TnHuScrw', + CommonSimType.TEEN_HUMAN_SKELETON: 'TnHuSk', + CommonSimType.TEEN_HUMAN_PLANT_SIM: 'TnHuPls', + CommonSimType.TEEN_HUMAN_WEREWOLF: 'TnHuWerWlf', + # Child + CommonSimType.CHILD_HUMAN: 'ChldHu', + CommonSimType.CHILD_HUMAN_VAMPIRE: 'ChldHuVa', + CommonSimType.CHILD_HUMAN_GHOST: 'ChldHuGh', + CommonSimType.CHILD_HUMAN_ALIEN: 'ChldHuAl', + CommonSimType.CHILD_HUMAN_MERMAID: 'ChldHuMer', + CommonSimType.CHILD_HUMAN_WITCH: 'ChldHuWi', + CommonSimType.CHILD_HUMAN_ROBOT: 'ChldHuRo', + CommonSimType.CHILD_HUMAN_SCARECROW: 'ChldHuScrw', + CommonSimType.CHILD_HUMAN_SKELETON: 'ChldHuSk', + CommonSimType.CHILD_HUMAN_PLANT_SIM: 'ChldHuPls', + CommonSimType.CHILD_HUMAN_WEREWOLF: 'ChldHuWerWlf', + # Toddler + CommonSimType.TODDLER_HUMAN: 'TdlrHu', + CommonSimType.TODDLER_HUMAN_VAMPIRE: 'TdlrHuVa', + CommonSimType.TODDLER_HUMAN_GHOST: 'TdlrHuGh', + CommonSimType.TODDLER_HUMAN_ALIEN: 'TdlrHuAl', + CommonSimType.TODDLER_HUMAN_MERMAID: 'TdlrHuMer', + CommonSimType.TODDLER_HUMAN_WITCH: 'TdlrHuWi', + CommonSimType.TODDLER_HUMAN_ROBOT: 'TdlrHuRo', + CommonSimType.TODDLER_HUMAN_SCARECROW: 'TdlrHuScrw', + CommonSimType.TODDLER_HUMAN_SKELETON: 'TdlrHuSk', + CommonSimType.TODDLER_HUMAN_PLANT_SIM: 'TdlrHuPls', + CommonSimType.TODDLER_HUMAN_WEREWOLF: 'TdlrHuWerWlf', + # Infant + CommonSimType.INFANT_HUMAN: 'InfntHu', + CommonSimType.INFANT_HUMAN_VAMPIRE: 'InfntHuVa', + CommonSimType.INFANT_HUMAN_GHOST: 'InfntHuGh', + CommonSimType.INFANT_HUMAN_ALIEN: 'InfntHuAl', + CommonSimType.INFANT_HUMAN_MERMAID: 'InfntHuMer', + CommonSimType.INFANT_HUMAN_WITCH: 'InfntHuWi', + CommonSimType.INFANT_HUMAN_ROBOT: 'InfntHuRo', + CommonSimType.INFANT_HUMAN_SCARECROW: 'InfntHuScrw', + CommonSimType.INFANT_HUMAN_SKELETON: 'InfntHuSk', + CommonSimType.INFANT_HUMAN_PLANT_SIM: 'InfntHuPls', + CommonSimType.INFANT_HUMAN_WEREWOLF: 'InfntHuWerWlf', + # Baby + CommonSimType.BABY_HUMAN: 'BbyHu', + CommonSimType.BABY_HUMAN_VAMPIRE: 'BbyHuVa', + CommonSimType.BABY_HUMAN_GHOST: 'BbyHuGh', + CommonSimType.BABY_HUMAN_ALIEN: 'BbyHuAl', + CommonSimType.BABY_HUMAN_MERMAID: 'BbyHuMer', + CommonSimType.BABY_HUMAN_WITCH: 'BbyHuWi', + CommonSimType.BABY_HUMAN_ROBOT: 'BbyHuRo', + CommonSimType.BABY_HUMAN_SCARECROW: 'BbyHuScrw', + CommonSimType.BABY_HUMAN_SKELETON: 'BbyHuSk', + CommonSimType.BABY_HUMAN_PLANT_SIM: 'BbyHuPls', + CommonSimType.BABY_HUMAN_WEREWOLF: 'BbyHuWerWlf', + + # Child Dog + CommonSimType.CHILD_DOG: 'ChldDg', + CommonSimType.CHILD_DOG_VAMPIRE: 'ChldDgVa', + CommonSimType.CHILD_DOG_GHOST: 'ChldDgGh', + CommonSimType.CHILD_DOG_ALIEN: 'ChldDgAl', + CommonSimType.CHILD_DOG_MERMAID: 'ChldDgMer', + CommonSimType.CHILD_DOG_WITCH: 'ChldDgWi', + CommonSimType.CHILD_DOG_ROBOT: 'ChldDgRo', + CommonSimType.CHILD_DOG_SCARECROW: 'ChldDgScrw', + CommonSimType.CHILD_DOG_SKELETON: 'ChldDgSk', + CommonSimType.CHILD_DOG_PLANT_SIM: 'ChldDgPls', + CommonSimType.CHILD_DOG_WEREWOLF: 'ChldDgWerWlf', + + # Small Dog + # Elder + CommonSimType.ELDER_SMALL_DOG: 'ElSd', + CommonSimType.ELDER_SMALL_DOG_VAMPIRE: 'ElSdVa', + CommonSimType.ELDER_SMALL_DOG_GHOST: 'ElSdGh', + CommonSimType.ELDER_SMALL_DOG_ALIEN: 'ElSdAl', + CommonSimType.ELDER_SMALL_DOG_MERMAID: 'ElSdMer', + CommonSimType.ELDER_SMALL_DOG_WITCH: 'ElSdWi', + CommonSimType.ELDER_SMALL_DOG_ROBOT: 'ElSdRo', + CommonSimType.ELDER_SMALL_DOG_SCARECROW: 'ElSdScrw', + CommonSimType.ELDER_SMALL_DOG_SKELETON: 'ElSdSk', + CommonSimType.ELDER_SMALL_DOG_PLANT_SIM: 'ElSdPls', + CommonSimType.ELDER_SMALL_DOG_WEREWOLF: 'ElSdWerWlf', + # Adult + CommonSimType.ADULT_SMALL_DOG: 'AdSd', + CommonSimType.ADULT_SMALL_DOG_VAMPIRE: 'AdSdVa', + CommonSimType.ADULT_SMALL_DOG_GHOST: 'AdSdGh', + CommonSimType.ADULT_SMALL_DOG_ALIEN: 'AdSdAl', + CommonSimType.ADULT_SMALL_DOG_MERMAID: 'AdSdMer', + CommonSimType.ADULT_SMALL_DOG_WITCH: 'AdSdWi', + CommonSimType.ADULT_SMALL_DOG_ROBOT: 'AdSdRo', + CommonSimType.ADULT_SMALL_DOG_SCARECROW: 'AdSdScrw', + CommonSimType.ADULT_SMALL_DOG_SKELETON: 'AdSdSk', + CommonSimType.ADULT_SMALL_DOG_PLANT_SIM: 'AdSdPls', + CommonSimType.ADULT_SMALL_DOG_WEREWOLF: 'AdSdWerWlf', + # Child + CommonSimType.CHILD_SMALL_DOG: 'ChldSd', + CommonSimType.CHILD_SMALL_DOG_VAMPIRE: 'ChldSdVa', + CommonSimType.CHILD_SMALL_DOG_GHOST: 'ChldSdGh', + CommonSimType.CHILD_SMALL_DOG_ALIEN: 'ChldSdAl', + CommonSimType.CHILD_SMALL_DOG_MERMAID: 'ChldSdMer', + CommonSimType.CHILD_SMALL_DOG_WITCH: 'ChldSdWi', + CommonSimType.CHILD_SMALL_DOG_ROBOT: 'ChldSdRo', + CommonSimType.CHILD_SMALL_DOG_SCARECROW: 'ChldSdScrw', + CommonSimType.CHILD_SMALL_DOG_SKELETON: 'ChldSdSk', + CommonSimType.CHILD_SMALL_DOG_PLANT_SIM: 'ChldSdPls', + CommonSimType.CHILD_SMALL_DOG_WEREWOLF: 'ChldSdWerWlf', + + # Large Dog + # Elder + CommonSimType.ELDER_LARGE_DOG: 'ElLd', + CommonSimType.ELDER_LARGE_DOG_VAMPIRE: 'ElLdVa', + CommonSimType.ELDER_LARGE_DOG_GHOST: 'ElLdGh', + CommonSimType.ELDER_LARGE_DOG_ALIEN: 'ElLdAl', + CommonSimType.ELDER_LARGE_DOG_MERMAID: 'ElLdMer', + CommonSimType.ELDER_LARGE_DOG_WITCH: 'ElLdWi', + CommonSimType.ELDER_LARGE_DOG_ROBOT: 'ElLdRo', + CommonSimType.ELDER_LARGE_DOG_SCARECROW: 'ElLdScrw', + CommonSimType.ELDER_LARGE_DOG_SKELETON: 'ElLdSk', + CommonSimType.ELDER_LARGE_DOG_PLANT_SIM: 'ElLdPls', + CommonSimType.ELDER_LARGE_DOG_WEREWOLF: 'ElLdWerWlf', + # Adult + CommonSimType.ADULT_LARGE_DOG: 'AdLd', + CommonSimType.ADULT_LARGE_DOG_VAMPIRE: 'AdLdVa', + CommonSimType.ADULT_LARGE_DOG_GHOST: 'AdLdGh', + CommonSimType.ADULT_LARGE_DOG_ALIEN: 'AdLdAl', + CommonSimType.ADULT_LARGE_DOG_MERMAID: 'AdLdMer', + CommonSimType.ADULT_LARGE_DOG_WITCH: 'AdLdWi', + CommonSimType.ADULT_LARGE_DOG_ROBOT: 'AdLdRo', + CommonSimType.ADULT_LARGE_DOG_SCARECROW: 'AdLdScrw', + CommonSimType.ADULT_LARGE_DOG_SKELETON: 'AdLdSk', + CommonSimType.ADULT_LARGE_DOG_PLANT_SIM: 'AdLdPls', + CommonSimType.ADULT_LARGE_DOG_WEREWOLF: 'AdLdWerWlf', + # Child + CommonSimType.CHILD_LARGE_DOG: 'ChldLd', + CommonSimType.CHILD_LARGE_DOG_VAMPIRE: 'ChldLdVa', + CommonSimType.CHILD_LARGE_DOG_GHOST: 'ChldLdGh', + CommonSimType.CHILD_LARGE_DOG_ALIEN: 'ChldLdAl', + CommonSimType.CHILD_LARGE_DOG_MERMAID: 'ChldLdMer', + CommonSimType.CHILD_LARGE_DOG_WITCH: 'ChldLdWi', + CommonSimType.CHILD_LARGE_DOG_ROBOT: 'ChldLdRo', + CommonSimType.CHILD_LARGE_DOG_SCARECROW: 'ChldLdScrw', + CommonSimType.CHILD_LARGE_DOG_SKELETON: 'ChldLdSk', + CommonSimType.CHILD_LARGE_DOG_PLANT_SIM: 'ChldLdPls', + CommonSimType.CHILD_LARGE_DOG_WEREWOLF: 'ChldLdWerWlf', + + # Cat + # Elder + CommonSimType.ELDER_CAT: 'ElCat', + CommonSimType.ELDER_CAT_VAMPIRE: 'ElCatVa', + CommonSimType.ELDER_CAT_GHOST: 'ElCatGh', + CommonSimType.ELDER_CAT_ALIEN: 'ElCatAl', + CommonSimType.ELDER_CAT_MERMAID: 'ElCatMer', + CommonSimType.ELDER_CAT_WITCH: 'ElCatWi', + CommonSimType.ELDER_CAT_ROBOT: 'ElCatRo', + CommonSimType.ELDER_CAT_SCARECROW: 'ElCatScrw', + CommonSimType.ELDER_CAT_SKELETON: 'ElCatSk', + CommonSimType.ELDER_CAT_PLANT_SIM: 'ElCatPls', + CommonSimType.ELDER_CAT_WEREWOLF: 'ElCatWerWlf', + # Adult + CommonSimType.ADULT_CAT: 'AdCat', + CommonSimType.ADULT_CAT_VAMPIRE: 'AdCatVa', + CommonSimType.ADULT_CAT_GHOST: 'AdCatGh', + CommonSimType.ADULT_CAT_ALIEN: 'AdCatAl', + CommonSimType.ADULT_CAT_MERMAID: 'AdCatMer', + CommonSimType.ADULT_CAT_WITCH: 'AdCatWi', + CommonSimType.ADULT_CAT_ROBOT: 'AdCatRo', + CommonSimType.ADULT_CAT_SCARECROW: 'AdCatScrw', + CommonSimType.ADULT_CAT_SKELETON: 'AdCatSk', + CommonSimType.ADULT_CAT_PLANT_SIM: 'AdCatPls', + CommonSimType.ADULT_CAT_WEREWOLF: 'AdCatWerWlf', + # Child + CommonSimType.CHILD_CAT: 'ChldCat', + CommonSimType.CHILD_CAT_VAMPIRE: 'ChldCatVa', + CommonSimType.CHILD_CAT_GHOST: 'ChldCatGh', + CommonSimType.CHILD_CAT_ALIEN: 'ChldCatAl', + CommonSimType.CHILD_CAT_MERMAID: 'ChldCatMer', + CommonSimType.CHILD_CAT_WITCH: 'ChldCatWi', + CommonSimType.CHILD_CAT_ROBOT: 'ChldCatRo', + CommonSimType.CHILD_CAT_SCARECROW: 'ChldCatScrw', + CommonSimType.CHILD_CAT_SKELETON: 'ChldCatSk', + CommonSimType.CHILD_CAT_PLANT_SIM: 'ChldCatPls', + CommonSimType.CHILD_CAT_WEREWOLF: 'ChldCatWerWlf', + + # Fox + # Elder + CommonSimType.ELDER_FOX: 'ElFox', + CommonSimType.ELDER_FOX_VAMPIRE: 'ElFoxVa', + CommonSimType.ELDER_FOX_GHOST: 'ElFoxGh', + CommonSimType.ELDER_FOX_ALIEN: 'ElFoxAl', + CommonSimType.ELDER_FOX_MERMAID: 'ElFoxMer', + CommonSimType.ELDER_FOX_WITCH: 'ElFoxWi', + CommonSimType.ELDER_FOX_ROBOT: 'ElFoxRo', + CommonSimType.ELDER_FOX_SCARECROW: 'ElFoxScrw', + CommonSimType.ELDER_FOX_SKELETON: 'ElFoxSk', + CommonSimType.ELDER_FOX_PLANT_SIM: 'ElFoxPls', + CommonSimType.ELDER_FOX_WEREWOLF: 'ElFoxWerWlf', + # Adult + CommonSimType.ADULT_FOX: 'AdFox', + CommonSimType.ADULT_FOX_VAMPIRE: 'AdFoxVa', + CommonSimType.ADULT_FOX_GHOST: 'AdFoxGh', + CommonSimType.ADULT_FOX_ALIEN: 'AdFoxAl', + CommonSimType.ADULT_FOX_MERMAID: 'AdFoxMer', + CommonSimType.ADULT_FOX_WITCH: 'AdFoxWi', + CommonSimType.ADULT_FOX_ROBOT: 'AdFoxRo', + CommonSimType.ADULT_FOX_SCARECROW: 'AdFoxScrw', + CommonSimType.ADULT_FOX_SKELETON: 'AdFoxSk', + CommonSimType.ADULT_FOX_PLANT_SIM: 'AdFoxPls', + CommonSimType.ADULT_FOX_WEREWOLF: 'AdFoxWerWlf', + # Child + CommonSimType.CHILD_FOX: 'ChldFox', + CommonSimType.CHILD_FOX_VAMPIRE: 'ChldFoxVa', + CommonSimType.CHILD_FOX_GHOST: 'ChldFoxGh', + CommonSimType.CHILD_FOX_ALIEN: 'ChldFoxAl', + CommonSimType.CHILD_FOX_MERMAID: 'ChldFoxMer', + CommonSimType.CHILD_FOX_WITCH: 'ChldFoxWi', + CommonSimType.CHILD_FOX_ROBOT: 'ChldFoxRo', + CommonSimType.CHILD_FOX_SCARECROW: 'ChldFoxScrw', + CommonSimType.CHILD_FOX_SKELETON: 'ChldFoxSk', + CommonSimType.CHILD_FOX_PLANT_SIM: 'ChldFoxPls', + CommonSimType.CHILD_FOX_WEREWOLF: 'ChldFoxWerWlf', + + # Horse + # Elder + CommonSimType.ELDER_HORSE: 'ElHrs', + CommonSimType.ELDER_HORSE_VAMPIRE: 'ElHrsVa', + CommonSimType.ELDER_HORSE_GHOST: 'ElHrsGh', + CommonSimType.ELDER_HORSE_ALIEN: 'ElHrsAl', + CommonSimType.ELDER_HORSE_MERMAID: 'ElHrsMer', + CommonSimType.ELDER_HORSE_WITCH: 'ElHrsWi', + CommonSimType.ELDER_HORSE_ROBOT: 'ElHrsRo', + CommonSimType.ELDER_HORSE_SCARECROW: 'ElHrsScrw', + CommonSimType.ELDER_HORSE_SKELETON: 'ElHrsSk', + CommonSimType.ELDER_HORSE_PLANT_SIM: 'ElHrsPls', + CommonSimType.ELDER_HORSE_WEREWOLF: 'ElHrsWerWlf', + # Adult + CommonSimType.ADULT_HORSE: 'AdHrs', + CommonSimType.ADULT_HORSE_VAMPIRE: 'AdHrsVa', + CommonSimType.ADULT_HORSE_GHOST: 'AdHrsGh', + CommonSimType.ADULT_HORSE_ALIEN: 'AdHrsAl', + CommonSimType.ADULT_HORSE_MERMAID: 'AdHrsMer', + CommonSimType.ADULT_HORSE_WITCH: 'AdHrsWi', + CommonSimType.ADULT_HORSE_ROBOT: 'AdHrsRo', + CommonSimType.ADULT_HORSE_SCARECROW: 'AdHrsScrw', + CommonSimType.ADULT_HORSE_SKELETON: 'AdHrsSk', + CommonSimType.ADULT_HORSE_PLANT_SIM: 'AdHrsPls', + CommonSimType.ADULT_HORSE_WEREWOLF: 'AdHrsWerWlf', + # Child + CommonSimType.CHILD_HORSE: 'ChldHrs', + CommonSimType.CHILD_HORSE_VAMPIRE: 'ChldHrsVa', + CommonSimType.CHILD_HORSE_GHOST: 'ChldHrsGh', + CommonSimType.CHILD_HORSE_ALIEN: 'ChldHrsAl', + CommonSimType.CHILD_HORSE_MERMAID: 'ChldHrsMer', + CommonSimType.CHILD_HORSE_WITCH: 'ChldHrsWi', + CommonSimType.CHILD_HORSE_ROBOT: 'ChldHrsRo', + CommonSimType.CHILD_HORSE_SCARECROW: 'ChldHrsScrw', + CommonSimType.CHILD_HORSE_SKELETON: 'ChldHrsSk', + CommonSimType.CHILD_HORSE_PLANT_SIM: 'ChldHrsPls', + CommonSimType.CHILD_HORSE_WEREWOLF: 'ChldHrsWerWlf', + } + + _OCCULT_SIM_TYPE_TO_NON_OCCULT_SIM_TYPE_MAPPING: Dict[CommonSimType, CommonSimType] = { + # Human + # Elder + CommonSimType.ELDER_HUMAN: CommonSimType.ELDER_HUMAN, + CommonSimType.ELDER_HUMAN_VAMPIRE: CommonSimType.ELDER_HUMAN, + CommonSimType.ELDER_HUMAN_GHOST: CommonSimType.ELDER_HUMAN, + CommonSimType.ELDER_HUMAN_ALIEN: CommonSimType.ELDER_HUMAN, + CommonSimType.ELDER_HUMAN_MERMAID: CommonSimType.ELDER_HUMAN, + CommonSimType.ELDER_HUMAN_WITCH: CommonSimType.ELDER_HUMAN, + CommonSimType.ELDER_HUMAN_ROBOT: CommonSimType.ELDER_HUMAN, + CommonSimType.ELDER_HUMAN_SCARECROW: CommonSimType.ELDER_HUMAN, + CommonSimType.ELDER_HUMAN_SKELETON: CommonSimType.ELDER_HUMAN, + CommonSimType.ELDER_HUMAN_PLANT_SIM: CommonSimType.ELDER_HUMAN, + CommonSimType.ELDER_HUMAN_WEREWOLF: CommonSimType.ELDER_HUMAN, + # Adult + CommonSimType.ADULT_HUMAN: CommonSimType.ADULT_HUMAN, + CommonSimType.ADULT_HUMAN_VAMPIRE: CommonSimType.ADULT_HUMAN, + CommonSimType.ADULT_HUMAN_GHOST: CommonSimType.ADULT_HUMAN, + CommonSimType.ADULT_HUMAN_ALIEN: CommonSimType.ADULT_HUMAN, + CommonSimType.ADULT_HUMAN_MERMAID: CommonSimType.ADULT_HUMAN, + CommonSimType.ADULT_HUMAN_WITCH: CommonSimType.ADULT_HUMAN, + CommonSimType.ADULT_HUMAN_ROBOT: CommonSimType.ADULT_HUMAN, + CommonSimType.ADULT_HUMAN_SCARECROW: CommonSimType.ADULT_HUMAN, + CommonSimType.ADULT_HUMAN_SKELETON: CommonSimType.ADULT_HUMAN, + CommonSimType.ADULT_HUMAN_PLANT_SIM: CommonSimType.ADULT_HUMAN, + CommonSimType.ADULT_HUMAN_WEREWOLF: CommonSimType.ADULT_HUMAN, + # Young Adult + CommonSimType.YOUNG_ADULT_HUMAN: CommonSimType.YOUNG_ADULT_HUMAN, + CommonSimType.YOUNG_ADULT_HUMAN_VAMPIRE: CommonSimType.YOUNG_ADULT_HUMAN, + CommonSimType.YOUNG_ADULT_HUMAN_GHOST: CommonSimType.YOUNG_ADULT_HUMAN, + CommonSimType.YOUNG_ADULT_HUMAN_ALIEN: CommonSimType.YOUNG_ADULT_HUMAN, + CommonSimType.YOUNG_ADULT_HUMAN_MERMAID: CommonSimType.YOUNG_ADULT_HUMAN, + CommonSimType.YOUNG_ADULT_HUMAN_WITCH: CommonSimType.YOUNG_ADULT_HUMAN, + CommonSimType.YOUNG_ADULT_HUMAN_ROBOT: CommonSimType.YOUNG_ADULT_HUMAN, + CommonSimType.YOUNG_ADULT_HUMAN_SCARECROW: CommonSimType.YOUNG_ADULT_HUMAN, + CommonSimType.YOUNG_ADULT_HUMAN_SKELETON: CommonSimType.YOUNG_ADULT_HUMAN, + CommonSimType.YOUNG_ADULT_HUMAN_PLANT_SIM: CommonSimType.YOUNG_ADULT_HUMAN, + CommonSimType.YOUNG_ADULT_HUMAN_WEREWOLF: CommonSimType.YOUNG_ADULT_HUMAN, + # Teen + CommonSimType.TEEN_HUMAN: CommonSimType.TEEN_HUMAN, + CommonSimType.TEEN_HUMAN_VAMPIRE: CommonSimType.TEEN_HUMAN, + CommonSimType.TEEN_HUMAN_GHOST: CommonSimType.TEEN_HUMAN, + CommonSimType.TEEN_HUMAN_ALIEN: CommonSimType.TEEN_HUMAN, + CommonSimType.TEEN_HUMAN_MERMAID: CommonSimType.TEEN_HUMAN, + CommonSimType.TEEN_HUMAN_WITCH: CommonSimType.TEEN_HUMAN, + CommonSimType.TEEN_HUMAN_ROBOT: CommonSimType.TEEN_HUMAN, + CommonSimType.TEEN_HUMAN_SCARECROW: CommonSimType.TEEN_HUMAN, + CommonSimType.TEEN_HUMAN_SKELETON: CommonSimType.TEEN_HUMAN, + CommonSimType.TEEN_HUMAN_PLANT_SIM: CommonSimType.TEEN_HUMAN, + CommonSimType.TEEN_HUMAN_WEREWOLF: CommonSimType.TEEN_HUMAN, + # Child + CommonSimType.CHILD_HUMAN: CommonSimType.CHILD_HUMAN, + CommonSimType.CHILD_HUMAN_VAMPIRE: CommonSimType.CHILD_HUMAN, + CommonSimType.CHILD_HUMAN_GHOST: CommonSimType.CHILD_HUMAN, + CommonSimType.CHILD_HUMAN_ALIEN: CommonSimType.CHILD_HUMAN, + CommonSimType.CHILD_HUMAN_MERMAID: CommonSimType.CHILD_HUMAN, + CommonSimType.CHILD_HUMAN_WITCH: CommonSimType.CHILD_HUMAN, + CommonSimType.CHILD_HUMAN_ROBOT: CommonSimType.CHILD_HUMAN, + CommonSimType.CHILD_HUMAN_SCARECROW: CommonSimType.CHILD_HUMAN, + CommonSimType.CHILD_HUMAN_SKELETON: CommonSimType.CHILD_HUMAN, + CommonSimType.CHILD_HUMAN_PLANT_SIM: CommonSimType.CHILD_HUMAN, + CommonSimType.CHILD_HUMAN_WEREWOLF: CommonSimType.CHILD_HUMAN, + # Toddler + CommonSimType.TODDLER_HUMAN: CommonSimType.TODDLER_HUMAN, + CommonSimType.TODDLER_HUMAN_VAMPIRE: CommonSimType.TODDLER_HUMAN, + CommonSimType.TODDLER_HUMAN_GHOST: CommonSimType.TODDLER_HUMAN, + CommonSimType.TODDLER_HUMAN_ALIEN: CommonSimType.TODDLER_HUMAN, + CommonSimType.TODDLER_HUMAN_MERMAID: CommonSimType.TODDLER_HUMAN, + CommonSimType.TODDLER_HUMAN_WITCH: CommonSimType.TODDLER_HUMAN, + CommonSimType.TODDLER_HUMAN_ROBOT: CommonSimType.TODDLER_HUMAN, + CommonSimType.TODDLER_HUMAN_SCARECROW: CommonSimType.TODDLER_HUMAN, + CommonSimType.TODDLER_HUMAN_SKELETON: CommonSimType.TODDLER_HUMAN, + CommonSimType.TODDLER_HUMAN_PLANT_SIM: CommonSimType.TODDLER_HUMAN, + CommonSimType.TODDLER_HUMAN_WEREWOLF: CommonSimType.TODDLER_HUMAN, + # Infant + CommonSimType.INFANT_HUMAN: CommonSimType.INFANT_HUMAN, + CommonSimType.INFANT_HUMAN_VAMPIRE: CommonSimType.INFANT_HUMAN, + CommonSimType.INFANT_HUMAN_GHOST: CommonSimType.INFANT_HUMAN, + CommonSimType.INFANT_HUMAN_ALIEN: CommonSimType.INFANT_HUMAN, + CommonSimType.INFANT_HUMAN_MERMAID: CommonSimType.INFANT_HUMAN, + CommonSimType.INFANT_HUMAN_WITCH: CommonSimType.INFANT_HUMAN, + CommonSimType.INFANT_HUMAN_ROBOT: CommonSimType.INFANT_HUMAN, + CommonSimType.INFANT_HUMAN_SCARECROW: CommonSimType.INFANT_HUMAN, + CommonSimType.INFANT_HUMAN_SKELETON: CommonSimType.INFANT_HUMAN, + CommonSimType.INFANT_HUMAN_PLANT_SIM: CommonSimType.INFANT_HUMAN, + CommonSimType.INFANT_HUMAN_WEREWOLF: CommonSimType.INFANT_HUMAN, + + # Baby + CommonSimType.BABY_HUMAN: CommonSimType.BABY_HUMAN, + CommonSimType.BABY_HUMAN_VAMPIRE: CommonSimType.BABY_HUMAN, + CommonSimType.BABY_HUMAN_GHOST: CommonSimType.BABY_HUMAN, + CommonSimType.BABY_HUMAN_ALIEN: CommonSimType.BABY_HUMAN, + CommonSimType.BABY_HUMAN_MERMAID: CommonSimType.BABY_HUMAN, + CommonSimType.BABY_HUMAN_WITCH: CommonSimType.BABY_HUMAN, + CommonSimType.BABY_HUMAN_ROBOT: CommonSimType.BABY_HUMAN, + CommonSimType.BABY_HUMAN_SCARECROW: CommonSimType.BABY_HUMAN, + CommonSimType.BABY_HUMAN_SKELETON: CommonSimType.BABY_HUMAN, + CommonSimType.BABY_HUMAN_PLANT_SIM: CommonSimType.BABY_HUMAN, + CommonSimType.BABY_HUMAN_WEREWOLF: CommonSimType.BABY_HUMAN, + + # Dog + # Child + CommonSimType.CHILD_DOG: CommonSimType.CHILD_DOG, + CommonSimType.CHILD_DOG_VAMPIRE: CommonSimType.CHILD_DOG, + CommonSimType.CHILD_DOG_GHOST: CommonSimType.CHILD_DOG, + CommonSimType.CHILD_DOG_ALIEN: CommonSimType.CHILD_DOG, + CommonSimType.CHILD_DOG_MERMAID: CommonSimType.CHILD_DOG, + CommonSimType.CHILD_DOG_WITCH: CommonSimType.CHILD_DOG, + CommonSimType.CHILD_DOG_ROBOT: CommonSimType.CHILD_DOG, + CommonSimType.CHILD_DOG_SCARECROW: CommonSimType.CHILD_DOG, + CommonSimType.CHILD_DOG_SKELETON: CommonSimType.CHILD_DOG, + CommonSimType.CHILD_DOG_PLANT_SIM: CommonSimType.CHILD_DOG, + CommonSimType.CHILD_DOG_WEREWOLF: CommonSimType.CHILD_DOG, + + # Small Dog + # Elder + CommonSimType.ELDER_SMALL_DOG: CommonSimType.ELDER_SMALL_DOG, + CommonSimType.ELDER_SMALL_DOG_VAMPIRE: CommonSimType.ELDER_SMALL_DOG, + CommonSimType.ELDER_SMALL_DOG_GHOST: CommonSimType.ELDER_SMALL_DOG, + CommonSimType.ELDER_SMALL_DOG_ALIEN: CommonSimType.ELDER_SMALL_DOG, + CommonSimType.ELDER_SMALL_DOG_MERMAID: CommonSimType.ELDER_SMALL_DOG, + CommonSimType.ELDER_SMALL_DOG_WITCH: CommonSimType.ELDER_SMALL_DOG, + CommonSimType.ELDER_SMALL_DOG_ROBOT: CommonSimType.ELDER_SMALL_DOG, + CommonSimType.ELDER_SMALL_DOG_SCARECROW: CommonSimType.ELDER_SMALL_DOG, + CommonSimType.ELDER_SMALL_DOG_SKELETON: CommonSimType.ELDER_SMALL_DOG, + CommonSimType.ELDER_SMALL_DOG_PLANT_SIM: CommonSimType.ELDER_SMALL_DOG, + CommonSimType.ELDER_SMALL_DOG_WEREWOLF: CommonSimType.ELDER_SMALL_DOG, + # Adult + CommonSimType.ADULT_SMALL_DOG: CommonSimType.ADULT_SMALL_DOG, + CommonSimType.ADULT_SMALL_DOG_VAMPIRE: CommonSimType.ADULT_SMALL_DOG, + CommonSimType.ADULT_SMALL_DOG_GHOST: CommonSimType.ADULT_SMALL_DOG, + CommonSimType.ADULT_SMALL_DOG_ALIEN: CommonSimType.ADULT_SMALL_DOG, + CommonSimType.ADULT_SMALL_DOG_MERMAID: CommonSimType.ADULT_SMALL_DOG, + CommonSimType.ADULT_SMALL_DOG_WITCH: CommonSimType.ADULT_SMALL_DOG, + CommonSimType.ADULT_SMALL_DOG_ROBOT: CommonSimType.ADULT_SMALL_DOG, + CommonSimType.ADULT_SMALL_DOG_SCARECROW: CommonSimType.ADULT_SMALL_DOG, + CommonSimType.ADULT_SMALL_DOG_SKELETON: CommonSimType.ADULT_SMALL_DOG, + CommonSimType.ADULT_SMALL_DOG_PLANT_SIM: CommonSimType.ADULT_SMALL_DOG, + CommonSimType.ADULT_SMALL_DOG_WEREWOLF: CommonSimType.ADULT_SMALL_DOG, + # Child + CommonSimType.CHILD_SMALL_DOG: CommonSimType.CHILD_SMALL_DOG, + CommonSimType.CHILD_SMALL_DOG_VAMPIRE: CommonSimType.CHILD_SMALL_DOG, + CommonSimType.CHILD_SMALL_DOG_GHOST: CommonSimType.CHILD_SMALL_DOG, + CommonSimType.CHILD_SMALL_DOG_ALIEN: CommonSimType.CHILD_SMALL_DOG, + CommonSimType.CHILD_SMALL_DOG_MERMAID: CommonSimType.CHILD_SMALL_DOG, + CommonSimType.CHILD_SMALL_DOG_WITCH: CommonSimType.CHILD_SMALL_DOG, + CommonSimType.CHILD_SMALL_DOG_ROBOT: CommonSimType.CHILD_SMALL_DOG, + CommonSimType.CHILD_SMALL_DOG_SCARECROW: CommonSimType.CHILD_SMALL_DOG, + CommonSimType.CHILD_SMALL_DOG_SKELETON: CommonSimType.CHILD_SMALL_DOG, + CommonSimType.CHILD_SMALL_DOG_PLANT_SIM: CommonSimType.CHILD_SMALL_DOG, + CommonSimType.CHILD_SMALL_DOG_WEREWOLF: CommonSimType.CHILD_SMALL_DOG, + + # Large Dog + # Elder + CommonSimType.ELDER_LARGE_DOG: CommonSimType.ELDER_LARGE_DOG, + CommonSimType.ELDER_LARGE_DOG_VAMPIRE: CommonSimType.ELDER_LARGE_DOG, + CommonSimType.ELDER_LARGE_DOG_GHOST: CommonSimType.ELDER_LARGE_DOG, + CommonSimType.ELDER_LARGE_DOG_ALIEN: CommonSimType.ELDER_LARGE_DOG, + CommonSimType.ELDER_LARGE_DOG_MERMAID: CommonSimType.ELDER_LARGE_DOG, + CommonSimType.ELDER_LARGE_DOG_WITCH: CommonSimType.ELDER_LARGE_DOG, + CommonSimType.ELDER_LARGE_DOG_ROBOT: CommonSimType.ELDER_LARGE_DOG, + CommonSimType.ELDER_LARGE_DOG_SCARECROW: CommonSimType.ELDER_LARGE_DOG, + CommonSimType.ELDER_LARGE_DOG_SKELETON: CommonSimType.ELDER_LARGE_DOG, + CommonSimType.ELDER_LARGE_DOG_PLANT_SIM: CommonSimType.ELDER_LARGE_DOG, + CommonSimType.ELDER_LARGE_DOG_WEREWOLF: CommonSimType.ELDER_LARGE_DOG, + # Adult + CommonSimType.ADULT_LARGE_DOG: CommonSimType.ADULT_LARGE_DOG, + CommonSimType.ADULT_LARGE_DOG_VAMPIRE: CommonSimType.ADULT_LARGE_DOG, + CommonSimType.ADULT_LARGE_DOG_GHOST: CommonSimType.ADULT_LARGE_DOG, + CommonSimType.ADULT_LARGE_DOG_ALIEN: CommonSimType.ADULT_LARGE_DOG, + CommonSimType.ADULT_LARGE_DOG_MERMAID: CommonSimType.ADULT_LARGE_DOG, + CommonSimType.ADULT_LARGE_DOG_WITCH: CommonSimType.ADULT_LARGE_DOG, + CommonSimType.ADULT_LARGE_DOG_ROBOT: CommonSimType.ADULT_LARGE_DOG, + CommonSimType.ADULT_LARGE_DOG_SCARECROW: CommonSimType.ADULT_LARGE_DOG, + CommonSimType.ADULT_LARGE_DOG_SKELETON: CommonSimType.ADULT_LARGE_DOG, + CommonSimType.ADULT_LARGE_DOG_PLANT_SIM: CommonSimType.ADULT_LARGE_DOG, + CommonSimType.ADULT_LARGE_DOG_WEREWOLF: CommonSimType.ADULT_LARGE_DOG, + # Child + CommonSimType.CHILD_LARGE_DOG: CommonSimType.CHILD_LARGE_DOG, + CommonSimType.CHILD_LARGE_DOG_VAMPIRE: CommonSimType.CHILD_LARGE_DOG, + CommonSimType.CHILD_LARGE_DOG_GHOST: CommonSimType.CHILD_LARGE_DOG, + CommonSimType.CHILD_LARGE_DOG_ALIEN: CommonSimType.CHILD_LARGE_DOG, + CommonSimType.CHILD_LARGE_DOG_MERMAID: CommonSimType.CHILD_LARGE_DOG, + CommonSimType.CHILD_LARGE_DOG_WITCH: CommonSimType.CHILD_LARGE_DOG, + CommonSimType.CHILD_LARGE_DOG_ROBOT: CommonSimType.CHILD_LARGE_DOG, + CommonSimType.CHILD_LARGE_DOG_SCARECROW: CommonSimType.CHILD_LARGE_DOG, + CommonSimType.CHILD_LARGE_DOG_SKELETON: CommonSimType.CHILD_LARGE_DOG, + CommonSimType.CHILD_LARGE_DOG_PLANT_SIM: CommonSimType.CHILD_LARGE_DOG, + CommonSimType.CHILD_LARGE_DOG_WEREWOLF: CommonSimType.CHILD_LARGE_DOG, + + # Cat + # Elder + CommonSimType.ELDER_CAT: CommonSimType.ELDER_CAT, + CommonSimType.ELDER_CAT_VAMPIRE: CommonSimType.ELDER_CAT, + CommonSimType.ELDER_CAT_GHOST: CommonSimType.ELDER_CAT, + CommonSimType.ELDER_CAT_ALIEN: CommonSimType.ELDER_CAT, + CommonSimType.ELDER_CAT_MERMAID: CommonSimType.ELDER_CAT, + CommonSimType.ELDER_CAT_WITCH: CommonSimType.ELDER_CAT, + CommonSimType.ELDER_CAT_ROBOT: CommonSimType.ELDER_CAT, + CommonSimType.ELDER_CAT_SCARECROW: CommonSimType.ELDER_CAT, + CommonSimType.ELDER_CAT_SKELETON: CommonSimType.ELDER_CAT, + CommonSimType.ELDER_CAT_PLANT_SIM: CommonSimType.ELDER_CAT, + CommonSimType.ELDER_CAT_WEREWOLF: CommonSimType.ELDER_CAT, + # Adult + CommonSimType.ADULT_CAT: CommonSimType.ADULT_CAT, + CommonSimType.ADULT_CAT_VAMPIRE: CommonSimType.ADULT_CAT, + CommonSimType.ADULT_CAT_GHOST: CommonSimType.ADULT_CAT, + CommonSimType.ADULT_CAT_ALIEN: CommonSimType.ADULT_CAT, + CommonSimType.ADULT_CAT_MERMAID: CommonSimType.ADULT_CAT, + CommonSimType.ADULT_CAT_WITCH: CommonSimType.ADULT_CAT, + CommonSimType.ADULT_CAT_ROBOT: CommonSimType.ADULT_CAT, + CommonSimType.ADULT_CAT_SCARECROW: CommonSimType.ADULT_CAT, + CommonSimType.ADULT_CAT_SKELETON: CommonSimType.ADULT_CAT, + CommonSimType.ADULT_CAT_PLANT_SIM: CommonSimType.ADULT_CAT, + CommonSimType.ADULT_CAT_WEREWOLF: CommonSimType.ADULT_CAT, + # Child + CommonSimType.CHILD_CAT: CommonSimType.CHILD_CAT, + CommonSimType.CHILD_CAT_VAMPIRE: CommonSimType.CHILD_CAT, + CommonSimType.CHILD_CAT_GHOST: CommonSimType.CHILD_CAT, + CommonSimType.CHILD_CAT_ALIEN: CommonSimType.CHILD_CAT, + CommonSimType.CHILD_CAT_MERMAID: CommonSimType.CHILD_CAT, + CommonSimType.CHILD_CAT_WITCH: CommonSimType.CHILD_CAT, + CommonSimType.CHILD_CAT_ROBOT: CommonSimType.CHILD_CAT, + CommonSimType.CHILD_CAT_SCARECROW: CommonSimType.CHILD_CAT, + CommonSimType.CHILD_CAT_SKELETON: CommonSimType.CHILD_CAT, + CommonSimType.CHILD_CAT_PLANT_SIM: CommonSimType.CHILD_CAT, + CommonSimType.CHILD_CAT_WEREWOLF: CommonSimType.CHILD_CAT, + + # Fox + # Elder + CommonSimType.ELDER_FOX: CommonSimType.ELDER_FOX, + CommonSimType.ELDER_FOX_VAMPIRE: CommonSimType.ELDER_FOX, + CommonSimType.ELDER_FOX_GHOST: CommonSimType.ELDER_FOX, + CommonSimType.ELDER_FOX_ALIEN: CommonSimType.ELDER_FOX, + CommonSimType.ELDER_FOX_MERMAID: CommonSimType.ELDER_FOX, + CommonSimType.ELDER_FOX_WITCH: CommonSimType.ELDER_FOX, + CommonSimType.ELDER_FOX_ROBOT: CommonSimType.ELDER_FOX, + CommonSimType.ELDER_FOX_SCARECROW: CommonSimType.ELDER_FOX, + CommonSimType.ELDER_FOX_SKELETON: CommonSimType.ELDER_FOX, + CommonSimType.ELDER_FOX_PLANT_SIM: CommonSimType.ELDER_FOX, + CommonSimType.ELDER_FOX_WEREWOLF: CommonSimType.ELDER_FOX, + # Adult + CommonSimType.ADULT_FOX: CommonSimType.ADULT_FOX, + CommonSimType.ADULT_FOX_VAMPIRE: CommonSimType.ADULT_FOX, + CommonSimType.ADULT_FOX_GHOST: CommonSimType.ADULT_FOX, + CommonSimType.ADULT_FOX_ALIEN: CommonSimType.ADULT_FOX, + CommonSimType.ADULT_FOX_MERMAID: CommonSimType.ADULT_FOX, + CommonSimType.ADULT_FOX_WITCH: CommonSimType.ADULT_FOX, + CommonSimType.ADULT_FOX_ROBOT: CommonSimType.ADULT_FOX, + CommonSimType.ADULT_FOX_SCARECROW: CommonSimType.ADULT_FOX, + CommonSimType.ADULT_FOX_SKELETON: CommonSimType.ADULT_FOX, + CommonSimType.ADULT_FOX_PLANT_SIM: CommonSimType.ADULT_FOX, + CommonSimType.ADULT_FOX_WEREWOLF: CommonSimType.ADULT_FOX, + # Child + CommonSimType.CHILD_FOX: CommonSimType.CHILD_FOX, + CommonSimType.CHILD_FOX_VAMPIRE: CommonSimType.CHILD_FOX, + CommonSimType.CHILD_FOX_GHOST: CommonSimType.CHILD_FOX, + CommonSimType.CHILD_FOX_ALIEN: CommonSimType.CHILD_FOX, + CommonSimType.CHILD_FOX_MERMAID: CommonSimType.CHILD_FOX, + CommonSimType.CHILD_FOX_WITCH: CommonSimType.CHILD_FOX, + CommonSimType.CHILD_FOX_ROBOT: CommonSimType.CHILD_FOX, + CommonSimType.CHILD_FOX_SCARECROW: CommonSimType.CHILD_FOX, + CommonSimType.CHILD_FOX_SKELETON: CommonSimType.CHILD_FOX, + CommonSimType.CHILD_FOX_PLANT_SIM: CommonSimType.CHILD_FOX, + CommonSimType.CHILD_FOX_WEREWOLF: CommonSimType.CHILD_FOX, + + # Horse + # Elder + CommonSimType.ELDER_HORSE: CommonSimType.ELDER_HORSE, + CommonSimType.ELDER_HORSE_VAMPIRE: CommonSimType.ELDER_HORSE, + CommonSimType.ELDER_HORSE_GHOST: CommonSimType.ELDER_HORSE, + CommonSimType.ELDER_HORSE_ALIEN: CommonSimType.ELDER_HORSE, + CommonSimType.ELDER_HORSE_MERMAID: CommonSimType.ELDER_HORSE, + CommonSimType.ELDER_HORSE_WITCH: CommonSimType.ELDER_HORSE, + CommonSimType.ELDER_HORSE_ROBOT: CommonSimType.ELDER_HORSE, + CommonSimType.ELDER_HORSE_SCARECROW: CommonSimType.ELDER_HORSE, + CommonSimType.ELDER_HORSE_SKELETON: CommonSimType.ELDER_HORSE, + CommonSimType.ELDER_HORSE_PLANT_SIM: CommonSimType.ELDER_HORSE, + CommonSimType.ELDER_HORSE_WEREWOLF: CommonSimType.ELDER_HORSE, + # Adult + CommonSimType.ADULT_HORSE: CommonSimType.ADULT_HORSE, + CommonSimType.ADULT_HORSE_VAMPIRE: CommonSimType.ADULT_HORSE, + CommonSimType.ADULT_HORSE_GHOST: CommonSimType.ADULT_HORSE, + CommonSimType.ADULT_HORSE_ALIEN: CommonSimType.ADULT_HORSE, + CommonSimType.ADULT_HORSE_MERMAID: CommonSimType.ADULT_HORSE, + CommonSimType.ADULT_HORSE_WITCH: CommonSimType.ADULT_HORSE, + CommonSimType.ADULT_HORSE_ROBOT: CommonSimType.ADULT_HORSE, + CommonSimType.ADULT_HORSE_SCARECROW: CommonSimType.ADULT_HORSE, + CommonSimType.ADULT_HORSE_SKELETON: CommonSimType.ADULT_HORSE, + CommonSimType.ADULT_HORSE_PLANT_SIM: CommonSimType.ADULT_HORSE, + CommonSimType.ADULT_HORSE_WEREWOLF: CommonSimType.ADULT_HORSE, + # Child + CommonSimType.CHILD_HORSE: CommonSimType.CHILD_HORSE, + CommonSimType.CHILD_HORSE_VAMPIRE: CommonSimType.CHILD_HORSE, + CommonSimType.CHILD_HORSE_GHOST: CommonSimType.CHILD_HORSE, + CommonSimType.CHILD_HORSE_ALIEN: CommonSimType.CHILD_HORSE, + CommonSimType.CHILD_HORSE_MERMAID: CommonSimType.CHILD_HORSE, + CommonSimType.CHILD_HORSE_WITCH: CommonSimType.CHILD_HORSE, + CommonSimType.CHILD_HORSE_ROBOT: CommonSimType.CHILD_HORSE, + CommonSimType.CHILD_HORSE_SCARECROW: CommonSimType.CHILD_HORSE, + CommonSimType.CHILD_HORSE_SKELETON: CommonSimType.CHILD_HORSE, + CommonSimType.CHILD_HORSE_PLANT_SIM: CommonSimType.CHILD_HORSE, + CommonSimType.CHILD_HORSE_WEREWOLF: CommonSimType.CHILD_HORSE, + } + + _OCCULT_SIM_TYPE_TO_OCCULT_TYPE_MAPPING: Dict[CommonSimType, CommonOccultType] = { + # Human + # Elder + CommonSimType.ELDER_HUMAN: CommonOccultType.NON_OCCULT, + CommonSimType.ELDER_HUMAN_VAMPIRE: CommonOccultType.VAMPIRE, + CommonSimType.ELDER_HUMAN_GHOST: CommonOccultType.GHOST, + CommonSimType.ELDER_HUMAN_ALIEN: CommonOccultType.ALIEN, + CommonSimType.ELDER_HUMAN_MERMAID: CommonOccultType.MERMAID, + CommonSimType.ELDER_HUMAN_WITCH: CommonOccultType.WITCH, + CommonSimType.ELDER_HUMAN_ROBOT: CommonOccultType.ROBOT, + CommonSimType.ELDER_HUMAN_SCARECROW: CommonOccultType.SCARECROW, + CommonSimType.ELDER_HUMAN_SKELETON: CommonOccultType.SKELETON, + CommonSimType.ELDER_HUMAN_PLANT_SIM: CommonOccultType.PLANT_SIM, + CommonSimType.ELDER_HUMAN_WEREWOLF: CommonOccultType.WEREWOLF, + # Adult + CommonSimType.ADULT_HUMAN: CommonOccultType.NON_OCCULT, + CommonSimType.ADULT_HUMAN_VAMPIRE: CommonOccultType.VAMPIRE, + CommonSimType.ADULT_HUMAN_GHOST: CommonOccultType.GHOST, + CommonSimType.ADULT_HUMAN_ALIEN: CommonOccultType.ALIEN, + CommonSimType.ADULT_HUMAN_MERMAID: CommonOccultType.MERMAID, + CommonSimType.ADULT_HUMAN_WITCH: CommonOccultType.WITCH, + CommonSimType.ADULT_HUMAN_ROBOT: CommonOccultType.ROBOT, + CommonSimType.ADULT_HUMAN_SCARECROW: CommonOccultType.SCARECROW, + CommonSimType.ADULT_HUMAN_SKELETON: CommonOccultType.SKELETON, + CommonSimType.ADULT_HUMAN_PLANT_SIM: CommonOccultType.PLANT_SIM, + CommonSimType.ADULT_HUMAN_WEREWOLF: CommonOccultType.WEREWOLF, + # Young Adult + CommonSimType.YOUNG_ADULT_HUMAN: CommonOccultType.NON_OCCULT, + CommonSimType.YOUNG_ADULT_HUMAN_VAMPIRE: CommonOccultType.VAMPIRE, + CommonSimType.YOUNG_ADULT_HUMAN_GHOST: CommonOccultType.GHOST, + CommonSimType.YOUNG_ADULT_HUMAN_ALIEN: CommonOccultType.ALIEN, + CommonSimType.YOUNG_ADULT_HUMAN_MERMAID: CommonOccultType.MERMAID, + CommonSimType.YOUNG_ADULT_HUMAN_WITCH: CommonOccultType.WITCH, + CommonSimType.YOUNG_ADULT_HUMAN_ROBOT: CommonOccultType.ROBOT, + CommonSimType.YOUNG_ADULT_HUMAN_SCARECROW: CommonOccultType.SCARECROW, + CommonSimType.YOUNG_ADULT_HUMAN_SKELETON: CommonOccultType.SKELETON, + CommonSimType.YOUNG_ADULT_HUMAN_PLANT_SIM: CommonOccultType.PLANT_SIM, + CommonSimType.YOUNG_ADULT_HUMAN_WEREWOLF: CommonOccultType.WEREWOLF, + # Teen + CommonSimType.TEEN_HUMAN: CommonOccultType.NON_OCCULT, + CommonSimType.TEEN_HUMAN_VAMPIRE: CommonOccultType.VAMPIRE, + CommonSimType.TEEN_HUMAN_GHOST: CommonOccultType.GHOST, + CommonSimType.TEEN_HUMAN_ALIEN: CommonOccultType.ALIEN, + CommonSimType.TEEN_HUMAN_MERMAID: CommonOccultType.MERMAID, + CommonSimType.TEEN_HUMAN_WITCH: CommonOccultType.WITCH, + CommonSimType.TEEN_HUMAN_ROBOT: CommonOccultType.ROBOT, + CommonSimType.TEEN_HUMAN_SCARECROW: CommonOccultType.SCARECROW, + CommonSimType.TEEN_HUMAN_SKELETON: CommonOccultType.SKELETON, + CommonSimType.TEEN_HUMAN_PLANT_SIM: CommonOccultType.PLANT_SIM, + CommonSimType.TEEN_HUMAN_WEREWOLF: CommonOccultType.WEREWOLF, + # Child + CommonSimType.CHILD_HUMAN: CommonOccultType.NON_OCCULT, + CommonSimType.CHILD_HUMAN_VAMPIRE: CommonOccultType.VAMPIRE, + CommonSimType.CHILD_HUMAN_GHOST: CommonOccultType.GHOST, + CommonSimType.CHILD_HUMAN_ALIEN: CommonOccultType.ALIEN, + CommonSimType.CHILD_HUMAN_MERMAID: CommonOccultType.MERMAID, + CommonSimType.CHILD_HUMAN_WITCH: CommonOccultType.WITCH, + CommonSimType.CHILD_HUMAN_ROBOT: CommonOccultType.ROBOT, + CommonSimType.CHILD_HUMAN_SCARECROW: CommonOccultType.SCARECROW, + CommonSimType.CHILD_HUMAN_SKELETON: CommonOccultType.SKELETON, + CommonSimType.CHILD_HUMAN_PLANT_SIM: CommonOccultType.PLANT_SIM, + CommonSimType.CHILD_HUMAN_WEREWOLF: CommonOccultType.WEREWOLF, + # Toddler + CommonSimType.TODDLER_HUMAN: CommonOccultType.NON_OCCULT, + CommonSimType.TODDLER_HUMAN_VAMPIRE: CommonOccultType.VAMPIRE, + CommonSimType.TODDLER_HUMAN_GHOST: CommonOccultType.GHOST, + CommonSimType.TODDLER_HUMAN_ALIEN: CommonOccultType.ALIEN, + CommonSimType.TODDLER_HUMAN_MERMAID: CommonOccultType.MERMAID, + CommonSimType.TODDLER_HUMAN_WITCH: CommonOccultType.WITCH, + CommonSimType.TODDLER_HUMAN_ROBOT: CommonOccultType.ROBOT, + CommonSimType.TODDLER_HUMAN_SCARECROW: CommonOccultType.SCARECROW, + CommonSimType.TODDLER_HUMAN_SKELETON: CommonOccultType.SKELETON, + CommonSimType.TODDLER_HUMAN_PLANT_SIM: CommonOccultType.PLANT_SIM, + CommonSimType.TODDLER_HUMAN_WEREWOLF: CommonOccultType.WEREWOLF, + # Infant + CommonSimType.INFANT_HUMAN: CommonOccultType.NON_OCCULT, + CommonSimType.INFANT_HUMAN_VAMPIRE: CommonOccultType.VAMPIRE, + CommonSimType.INFANT_HUMAN_GHOST: CommonOccultType.GHOST, + CommonSimType.INFANT_HUMAN_ALIEN: CommonOccultType.ALIEN, + CommonSimType.INFANT_HUMAN_MERMAID: CommonOccultType.MERMAID, + CommonSimType.INFANT_HUMAN_WITCH: CommonOccultType.WITCH, + CommonSimType.INFANT_HUMAN_ROBOT: CommonOccultType.ROBOT, + CommonSimType.INFANT_HUMAN_SCARECROW: CommonOccultType.SCARECROW, + CommonSimType.INFANT_HUMAN_SKELETON: CommonOccultType.SKELETON, + CommonSimType.INFANT_HUMAN_PLANT_SIM: CommonOccultType.PLANT_SIM, + CommonSimType.INFANT_HUMAN_WEREWOLF: CommonOccultType.WEREWOLF, + # Baby + CommonSimType.BABY_HUMAN: CommonOccultType.NON_OCCULT, + CommonSimType.BABY_HUMAN_VAMPIRE: CommonOccultType.VAMPIRE, + CommonSimType.BABY_HUMAN_GHOST: CommonOccultType.GHOST, + CommonSimType.BABY_HUMAN_ALIEN: CommonOccultType.ALIEN, + CommonSimType.BABY_HUMAN_MERMAID: CommonOccultType.MERMAID, + CommonSimType.BABY_HUMAN_WITCH: CommonOccultType.WITCH, + CommonSimType.BABY_HUMAN_ROBOT: CommonOccultType.ROBOT, + CommonSimType.BABY_HUMAN_SCARECROW: CommonOccultType.SCARECROW, + CommonSimType.BABY_HUMAN_SKELETON: CommonOccultType.SKELETON, + CommonSimType.BABY_HUMAN_PLANT_SIM: CommonOccultType.PLANT_SIM, + CommonSimType.BABY_HUMAN_WEREWOLF: CommonOccultType.WEREWOLF, + + # Dog + # Child + CommonSimType.CHILD_DOG: CommonOccultType.NON_OCCULT, + CommonSimType.CHILD_DOG_VAMPIRE: CommonOccultType.VAMPIRE, + CommonSimType.CHILD_DOG_GHOST: CommonOccultType.GHOST, + CommonSimType.CHILD_DOG_ALIEN: CommonOccultType.ALIEN, + CommonSimType.CHILD_DOG_MERMAID: CommonOccultType.MERMAID, + CommonSimType.CHILD_DOG_WITCH: CommonOccultType.WITCH, + CommonSimType.CHILD_DOG_ROBOT: CommonOccultType.ROBOT, + CommonSimType.CHILD_DOG_SCARECROW: CommonOccultType.SCARECROW, + CommonSimType.CHILD_DOG_SKELETON: CommonOccultType.SKELETON, + CommonSimType.CHILD_DOG_PLANT_SIM: CommonOccultType.PLANT_SIM, + CommonSimType.CHILD_DOG_WEREWOLF: CommonOccultType.WEREWOLF, + + # Small Dog + # Elder + CommonSimType.ELDER_SMALL_DOG: CommonOccultType.NON_OCCULT, + CommonSimType.ELDER_SMALL_DOG_VAMPIRE: CommonOccultType.VAMPIRE, + CommonSimType.ELDER_SMALL_DOG_GHOST: CommonOccultType.GHOST, + CommonSimType.ELDER_SMALL_DOG_ALIEN: CommonOccultType.ALIEN, + CommonSimType.ELDER_SMALL_DOG_MERMAID: CommonOccultType.MERMAID, + CommonSimType.ELDER_SMALL_DOG_WITCH: CommonOccultType.WITCH, + CommonSimType.ELDER_SMALL_DOG_ROBOT: CommonOccultType.ROBOT, + CommonSimType.ELDER_SMALL_DOG_SCARECROW: CommonOccultType.SCARECROW, + CommonSimType.ELDER_SMALL_DOG_SKELETON: CommonOccultType.SKELETON, + CommonSimType.ELDER_SMALL_DOG_PLANT_SIM: CommonOccultType.PLANT_SIM, + CommonSimType.ELDER_SMALL_DOG_WEREWOLF: CommonOccultType.WEREWOLF, + # Adult + CommonSimType.ADULT_SMALL_DOG: CommonOccultType.NON_OCCULT, + CommonSimType.ADULT_SMALL_DOG_VAMPIRE: CommonOccultType.VAMPIRE, + CommonSimType.ADULT_SMALL_DOG_GHOST: CommonOccultType.GHOST, + CommonSimType.ADULT_SMALL_DOG_ALIEN: CommonOccultType.ALIEN, + CommonSimType.ADULT_SMALL_DOG_MERMAID: CommonOccultType.MERMAID, + CommonSimType.ADULT_SMALL_DOG_WITCH: CommonOccultType.WITCH, + CommonSimType.ADULT_SMALL_DOG_ROBOT: CommonOccultType.ROBOT, + CommonSimType.ADULT_SMALL_DOG_SCARECROW: CommonOccultType.SCARECROW, + CommonSimType.ADULT_SMALL_DOG_SKELETON: CommonOccultType.SKELETON, + CommonSimType.ADULT_SMALL_DOG_PLANT_SIM: CommonOccultType.PLANT_SIM, + CommonSimType.ADULT_SMALL_DOG_WEREWOLF: CommonOccultType.WEREWOLF, + # Child + CommonSimType.CHILD_SMALL_DOG: CommonOccultType.NON_OCCULT, + CommonSimType.CHILD_SMALL_DOG_VAMPIRE: CommonOccultType.VAMPIRE, + CommonSimType.CHILD_SMALL_DOG_GHOST: CommonOccultType.GHOST, + CommonSimType.CHILD_SMALL_DOG_ALIEN: CommonOccultType.ALIEN, + CommonSimType.CHILD_SMALL_DOG_MERMAID: CommonOccultType.MERMAID, + CommonSimType.CHILD_SMALL_DOG_WITCH: CommonOccultType.WITCH, + CommonSimType.CHILD_SMALL_DOG_ROBOT: CommonOccultType.ROBOT, + CommonSimType.CHILD_SMALL_DOG_SCARECROW: CommonOccultType.SCARECROW, + CommonSimType.CHILD_SMALL_DOG_SKELETON: CommonOccultType.SKELETON, + CommonSimType.CHILD_SMALL_DOG_PLANT_SIM: CommonOccultType.PLANT_SIM, + CommonSimType.CHILD_SMALL_DOG_WEREWOLF: CommonOccultType.WEREWOLF, + + # Large Dog + # Elder + CommonSimType.ELDER_LARGE_DOG: CommonOccultType.NON_OCCULT, + CommonSimType.ELDER_LARGE_DOG_VAMPIRE: CommonOccultType.VAMPIRE, + CommonSimType.ELDER_LARGE_DOG_GHOST: CommonOccultType.GHOST, + CommonSimType.ELDER_LARGE_DOG_ALIEN: CommonOccultType.ALIEN, + CommonSimType.ELDER_LARGE_DOG_MERMAID: CommonOccultType.MERMAID, + CommonSimType.ELDER_LARGE_DOG_WITCH: CommonOccultType.WITCH, + CommonSimType.ELDER_LARGE_DOG_ROBOT: CommonOccultType.ROBOT, + CommonSimType.ELDER_LARGE_DOG_SCARECROW: CommonOccultType.SCARECROW, + CommonSimType.ELDER_LARGE_DOG_SKELETON: CommonOccultType.SKELETON, + CommonSimType.ELDER_LARGE_DOG_PLANT_SIM: CommonOccultType.PLANT_SIM, + CommonSimType.ELDER_LARGE_DOG_WEREWOLF: CommonOccultType.WEREWOLF, + # Adult + CommonSimType.ADULT_LARGE_DOG: CommonOccultType.NON_OCCULT, + CommonSimType.ADULT_LARGE_DOG_VAMPIRE: CommonOccultType.VAMPIRE, + CommonSimType.ADULT_LARGE_DOG_GHOST: CommonOccultType.GHOST, + CommonSimType.ADULT_LARGE_DOG_ALIEN: CommonOccultType.ALIEN, + CommonSimType.ADULT_LARGE_DOG_MERMAID: CommonOccultType.MERMAID, + CommonSimType.ADULT_LARGE_DOG_WITCH: CommonOccultType.WITCH, + CommonSimType.ADULT_LARGE_DOG_ROBOT: CommonOccultType.ROBOT, + CommonSimType.ADULT_LARGE_DOG_SCARECROW: CommonOccultType.SCARECROW, + CommonSimType.ADULT_LARGE_DOG_SKELETON: CommonOccultType.SKELETON, + CommonSimType.ADULT_LARGE_DOG_PLANT_SIM: CommonOccultType.PLANT_SIM, + CommonSimType.ADULT_LARGE_DOG_WEREWOLF: CommonOccultType.WEREWOLF, + # Child + CommonSimType.CHILD_LARGE_DOG: CommonOccultType.NON_OCCULT, + CommonSimType.CHILD_LARGE_DOG_VAMPIRE: CommonOccultType.VAMPIRE, + CommonSimType.CHILD_LARGE_DOG_GHOST: CommonOccultType.GHOST, + CommonSimType.CHILD_LARGE_DOG_ALIEN: CommonOccultType.ALIEN, + CommonSimType.CHILD_LARGE_DOG_MERMAID: CommonOccultType.MERMAID, + CommonSimType.CHILD_LARGE_DOG_WITCH: CommonOccultType.WITCH, + CommonSimType.CHILD_LARGE_DOG_ROBOT: CommonOccultType.ROBOT, + CommonSimType.CHILD_LARGE_DOG_SCARECROW: CommonOccultType.SCARECROW, + CommonSimType.CHILD_LARGE_DOG_SKELETON: CommonOccultType.SKELETON, + CommonSimType.CHILD_LARGE_DOG_PLANT_SIM: CommonOccultType.PLANT_SIM, + CommonSimType.CHILD_LARGE_DOG_WEREWOLF: CommonOccultType.WEREWOLF, + + # Cat + # Elder + CommonSimType.ELDER_CAT: CommonOccultType.NON_OCCULT, + CommonSimType.ELDER_CAT_VAMPIRE: CommonOccultType.VAMPIRE, + CommonSimType.ELDER_CAT_GHOST: CommonOccultType.GHOST, + CommonSimType.ELDER_CAT_ALIEN: CommonOccultType.ALIEN, + CommonSimType.ELDER_CAT_MERMAID: CommonOccultType.MERMAID, + CommonSimType.ELDER_CAT_WITCH: CommonOccultType.WITCH, + CommonSimType.ELDER_CAT_ROBOT: CommonOccultType.ROBOT, + CommonSimType.ELDER_CAT_SCARECROW: CommonOccultType.SCARECROW, + CommonSimType.ELDER_CAT_SKELETON: CommonOccultType.SKELETON, + CommonSimType.ELDER_CAT_PLANT_SIM: CommonOccultType.PLANT_SIM, + CommonSimType.ELDER_CAT_WEREWOLF: CommonOccultType.WEREWOLF, + # Adult + CommonSimType.ADULT_CAT: CommonOccultType.NON_OCCULT, + CommonSimType.ADULT_CAT_VAMPIRE: CommonOccultType.VAMPIRE, + CommonSimType.ADULT_CAT_GHOST: CommonOccultType.GHOST, + CommonSimType.ADULT_CAT_ALIEN: CommonOccultType.ALIEN, + CommonSimType.ADULT_CAT_MERMAID: CommonOccultType.MERMAID, + CommonSimType.ADULT_CAT_WITCH: CommonOccultType.WITCH, + CommonSimType.ADULT_CAT_ROBOT: CommonOccultType.ROBOT, + CommonSimType.ADULT_CAT_SCARECROW: CommonOccultType.SCARECROW, + CommonSimType.ADULT_CAT_SKELETON: CommonOccultType.SKELETON, + CommonSimType.ADULT_CAT_PLANT_SIM: CommonOccultType.PLANT_SIM, + CommonSimType.ADULT_CAT_WEREWOLF: CommonOccultType.WEREWOLF, + # Child + CommonSimType.CHILD_CAT: CommonOccultType.NON_OCCULT, + CommonSimType.CHILD_CAT_VAMPIRE: CommonOccultType.VAMPIRE, + CommonSimType.CHILD_CAT_GHOST: CommonOccultType.GHOST, + CommonSimType.CHILD_CAT_ALIEN: CommonOccultType.ALIEN, + CommonSimType.CHILD_CAT_MERMAID: CommonOccultType.MERMAID, + CommonSimType.CHILD_CAT_WITCH: CommonOccultType.WITCH, + CommonSimType.CHILD_CAT_ROBOT: CommonOccultType.ROBOT, + CommonSimType.CHILD_CAT_SCARECROW: CommonOccultType.SCARECROW, + CommonSimType.CHILD_CAT_SKELETON: CommonOccultType.SKELETON, + CommonSimType.CHILD_CAT_PLANT_SIM: CommonOccultType.PLANT_SIM, + CommonSimType.CHILD_CAT_WEREWOLF: CommonOccultType.WEREWOLF, + + # Fox + # Elder + CommonSimType.ELDER_FOX: CommonOccultType.NON_OCCULT, + CommonSimType.ELDER_FOX_VAMPIRE: CommonOccultType.VAMPIRE, + CommonSimType.ELDER_FOX_GHOST: CommonOccultType.GHOST, + CommonSimType.ELDER_FOX_ALIEN: CommonOccultType.ALIEN, + CommonSimType.ELDER_FOX_MERMAID: CommonOccultType.MERMAID, + CommonSimType.ELDER_FOX_WITCH: CommonOccultType.WITCH, + CommonSimType.ELDER_FOX_ROBOT: CommonOccultType.ROBOT, + CommonSimType.ELDER_FOX_SCARECROW: CommonOccultType.SCARECROW, + CommonSimType.ELDER_FOX_SKELETON: CommonOccultType.SKELETON, + CommonSimType.ELDER_FOX_PLANT_SIM: CommonOccultType.PLANT_SIM, + CommonSimType.ELDER_FOX_WEREWOLF: CommonOccultType.WEREWOLF, + # Adult + CommonSimType.ADULT_FOX: CommonOccultType.NON_OCCULT, + CommonSimType.ADULT_FOX_VAMPIRE: CommonOccultType.VAMPIRE, + CommonSimType.ADULT_FOX_GHOST: CommonOccultType.GHOST, + CommonSimType.ADULT_FOX_ALIEN: CommonOccultType.ALIEN, + CommonSimType.ADULT_FOX_MERMAID: CommonOccultType.MERMAID, + CommonSimType.ADULT_FOX_WITCH: CommonOccultType.WITCH, + CommonSimType.ADULT_FOX_ROBOT: CommonOccultType.ROBOT, + CommonSimType.ADULT_FOX_SCARECROW: CommonOccultType.SCARECROW, + CommonSimType.ADULT_FOX_SKELETON: CommonOccultType.SKELETON, + CommonSimType.ADULT_FOX_PLANT_SIM: CommonOccultType.PLANT_SIM, + CommonSimType.ADULT_FOX_WEREWOLF: CommonOccultType.WEREWOLF, + # Child + CommonSimType.CHILD_FOX: CommonOccultType.NON_OCCULT, + CommonSimType.CHILD_FOX_VAMPIRE: CommonOccultType.VAMPIRE, + CommonSimType.CHILD_FOX_GHOST: CommonOccultType.GHOST, + CommonSimType.CHILD_FOX_ALIEN: CommonOccultType.ALIEN, + CommonSimType.CHILD_FOX_MERMAID: CommonOccultType.MERMAID, + CommonSimType.CHILD_FOX_WITCH: CommonOccultType.WITCH, + CommonSimType.CHILD_FOX_ROBOT: CommonOccultType.ROBOT, + CommonSimType.CHILD_FOX_SCARECROW: CommonOccultType.SCARECROW, + CommonSimType.CHILD_FOX_SKELETON: CommonOccultType.SKELETON, + CommonSimType.CHILD_FOX_PLANT_SIM: CommonOccultType.PLANT_SIM, + CommonSimType.CHILD_FOX_WEREWOLF: CommonOccultType.WEREWOLF, + + # Horse + # Elder + CommonSimType.ELDER_HORSE: CommonOccultType.NON_OCCULT, + CommonSimType.ELDER_HORSE_VAMPIRE: CommonOccultType.VAMPIRE, + CommonSimType.ELDER_HORSE_GHOST: CommonOccultType.GHOST, + CommonSimType.ELDER_HORSE_ALIEN: CommonOccultType.ALIEN, + CommonSimType.ELDER_HORSE_MERMAID: CommonOccultType.MERMAID, + CommonSimType.ELDER_HORSE_WITCH: CommonOccultType.WITCH, + CommonSimType.ELDER_HORSE_ROBOT: CommonOccultType.ROBOT, + CommonSimType.ELDER_HORSE_SCARECROW: CommonOccultType.SCARECROW, + CommonSimType.ELDER_HORSE_SKELETON: CommonOccultType.SKELETON, + CommonSimType.ELDER_HORSE_PLANT_SIM: CommonOccultType.PLANT_SIM, + CommonSimType.ELDER_HORSE_WEREWOLF: CommonOccultType.WEREWOLF, + # Adult + CommonSimType.ADULT_HORSE: CommonOccultType.NON_OCCULT, + CommonSimType.ADULT_HORSE_VAMPIRE: CommonOccultType.VAMPIRE, + CommonSimType.ADULT_HORSE_GHOST: CommonOccultType.GHOST, + CommonSimType.ADULT_HORSE_ALIEN: CommonOccultType.ALIEN, + CommonSimType.ADULT_HORSE_MERMAID: CommonOccultType.MERMAID, + CommonSimType.ADULT_HORSE_WITCH: CommonOccultType.WITCH, + CommonSimType.ADULT_HORSE_ROBOT: CommonOccultType.ROBOT, + CommonSimType.ADULT_HORSE_SCARECROW: CommonOccultType.SCARECROW, + CommonSimType.ADULT_HORSE_SKELETON: CommonOccultType.SKELETON, + CommonSimType.ADULT_HORSE_PLANT_SIM: CommonOccultType.PLANT_SIM, + CommonSimType.ADULT_HORSE_WEREWOLF: CommonOccultType.WEREWOLF, + # Child + CommonSimType.CHILD_HORSE: CommonOccultType.NON_OCCULT, + CommonSimType.CHILD_HORSE_VAMPIRE: CommonOccultType.VAMPIRE, + CommonSimType.CHILD_HORSE_GHOST: CommonOccultType.GHOST, + CommonSimType.CHILD_HORSE_ALIEN: CommonOccultType.ALIEN, + CommonSimType.CHILD_HORSE_MERMAID: CommonOccultType.MERMAID, + CommonSimType.CHILD_HORSE_WITCH: CommonOccultType.WITCH, + CommonSimType.CHILD_HORSE_ROBOT: CommonOccultType.ROBOT, + CommonSimType.CHILD_HORSE_SCARECROW: CommonOccultType.SCARECROW, + CommonSimType.CHILD_HORSE_SKELETON: CommonOccultType.SKELETON, + CommonSimType.CHILD_HORSE_PLANT_SIM: CommonOccultType.PLANT_SIM, + CommonSimType.CHILD_HORSE_WEREWOLF: CommonOccultType.WEREWOLF, + } + + _OCCULT_SIM_TYPE_TO_AGE_MAPPING: Dict[CommonSimType, CommonAge] = { + # Human + # Elder + CommonSimType.ELDER_HUMAN: CommonAge.ELDER, + CommonSimType.ELDER_HUMAN_VAMPIRE: CommonAge.ELDER, + CommonSimType.ELDER_HUMAN_GHOST: CommonAge.ELDER, + CommonSimType.ELDER_HUMAN_ALIEN: CommonAge.ELDER, + CommonSimType.ELDER_HUMAN_MERMAID: CommonAge.ELDER, + CommonSimType.ELDER_HUMAN_WITCH: CommonAge.ELDER, + CommonSimType.ELDER_HUMAN_ROBOT: CommonAge.ELDER, + CommonSimType.ELDER_HUMAN_SCARECROW: CommonAge.ELDER, + CommonSimType.ELDER_HUMAN_SKELETON: CommonAge.ELDER, + CommonSimType.ELDER_HUMAN_PLANT_SIM: CommonAge.ELDER, + CommonSimType.ELDER_HUMAN_WEREWOLF: CommonAge.ELDER, + # Adult + CommonSimType.ADULT_HUMAN: CommonAge.ADULT, + CommonSimType.ADULT_HUMAN_VAMPIRE: CommonAge.ADULT, + CommonSimType.ADULT_HUMAN_GHOST: CommonAge.ADULT, + CommonSimType.ADULT_HUMAN_ALIEN: CommonAge.ADULT, + CommonSimType.ADULT_HUMAN_MERMAID: CommonAge.ADULT, + CommonSimType.ADULT_HUMAN_WITCH: CommonAge.ADULT, + CommonSimType.ADULT_HUMAN_ROBOT: CommonAge.ADULT, + CommonSimType.ADULT_HUMAN_SCARECROW: CommonAge.ADULT, + CommonSimType.ADULT_HUMAN_SKELETON: CommonAge.ADULT, + CommonSimType.ADULT_HUMAN_PLANT_SIM: CommonAge.ADULT, + CommonSimType.ADULT_HUMAN_WEREWOLF: CommonAge.ADULT, + # Young Adult + CommonSimType.YOUNG_ADULT_HUMAN: CommonAge.YOUNGADULT, + CommonSimType.YOUNG_ADULT_HUMAN_VAMPIRE: CommonAge.YOUNGADULT, + CommonSimType.YOUNG_ADULT_HUMAN_GHOST: CommonAge.YOUNGADULT, + CommonSimType.YOUNG_ADULT_HUMAN_ALIEN: CommonAge.YOUNGADULT, + CommonSimType.YOUNG_ADULT_HUMAN_MERMAID: CommonAge.YOUNGADULT, + CommonSimType.YOUNG_ADULT_HUMAN_WITCH: CommonAge.YOUNGADULT, + CommonSimType.YOUNG_ADULT_HUMAN_ROBOT: CommonAge.YOUNGADULT, + CommonSimType.YOUNG_ADULT_HUMAN_SCARECROW: CommonAge.YOUNGADULT, + CommonSimType.YOUNG_ADULT_HUMAN_SKELETON: CommonAge.YOUNGADULT, + CommonSimType.YOUNG_ADULT_HUMAN_PLANT_SIM: CommonAge.YOUNGADULT, + CommonSimType.YOUNG_ADULT_HUMAN_WEREWOLF: CommonAge.YOUNGADULT, + # Teen + CommonSimType.TEEN_HUMAN: CommonAge.TEEN, + CommonSimType.TEEN_HUMAN_VAMPIRE: CommonAge.TEEN, + CommonSimType.TEEN_HUMAN_GHOST: CommonAge.TEEN, + CommonSimType.TEEN_HUMAN_ALIEN: CommonAge.TEEN, + CommonSimType.TEEN_HUMAN_MERMAID: CommonAge.TEEN, + CommonSimType.TEEN_HUMAN_WITCH: CommonAge.TEEN, + CommonSimType.TEEN_HUMAN_ROBOT: CommonAge.TEEN, + CommonSimType.TEEN_HUMAN_SCARECROW: CommonAge.TEEN, + CommonSimType.TEEN_HUMAN_SKELETON: CommonAge.TEEN, + CommonSimType.TEEN_HUMAN_PLANT_SIM: CommonAge.TEEN, + CommonSimType.TEEN_HUMAN_WEREWOLF: CommonAge.TEEN, + # Child + CommonSimType.CHILD_HUMAN: CommonAge.CHILD, + CommonSimType.CHILD_HUMAN_VAMPIRE: CommonAge.CHILD, + CommonSimType.CHILD_HUMAN_GHOST: CommonAge.CHILD, + CommonSimType.CHILD_HUMAN_ALIEN: CommonAge.CHILD, + CommonSimType.CHILD_HUMAN_MERMAID: CommonAge.CHILD, + CommonSimType.CHILD_HUMAN_WITCH: CommonAge.CHILD, + CommonSimType.CHILD_HUMAN_ROBOT: CommonAge.CHILD, + CommonSimType.CHILD_HUMAN_SCARECROW: CommonAge.CHILD, + CommonSimType.CHILD_HUMAN_SKELETON: CommonAge.CHILD, + CommonSimType.CHILD_HUMAN_PLANT_SIM: CommonAge.CHILD, + CommonSimType.CHILD_HUMAN_WEREWOLF: CommonAge.CHILD, + # Toddler + CommonSimType.TODDLER_HUMAN: CommonAge.TODDLER, + CommonSimType.TODDLER_HUMAN_VAMPIRE: CommonAge.TODDLER, + CommonSimType.TODDLER_HUMAN_GHOST: CommonAge.TODDLER, + CommonSimType.TODDLER_HUMAN_ALIEN: CommonAge.TODDLER, + CommonSimType.TODDLER_HUMAN_MERMAID: CommonAge.TODDLER, + CommonSimType.TODDLER_HUMAN_WITCH: CommonAge.TODDLER, + CommonSimType.TODDLER_HUMAN_ROBOT: CommonAge.TODDLER, + CommonSimType.TODDLER_HUMAN_SCARECROW: CommonAge.TODDLER, + CommonSimType.TODDLER_HUMAN_SKELETON: CommonAge.TODDLER, + CommonSimType.TODDLER_HUMAN_PLANT_SIM: CommonAge.TODDLER, + CommonSimType.TODDLER_HUMAN_WEREWOLF: CommonAge.TODDLER, + # Infant + CommonSimType.INFANT_HUMAN: CommonAge.INFANT, + CommonSimType.INFANT_HUMAN_VAMPIRE: CommonAge.INFANT, + CommonSimType.INFANT_HUMAN_GHOST: CommonAge.INFANT, + CommonSimType.INFANT_HUMAN_ALIEN: CommonAge.INFANT, + CommonSimType.INFANT_HUMAN_MERMAID: CommonAge.INFANT, + CommonSimType.INFANT_HUMAN_WITCH: CommonAge.INFANT, + CommonSimType.INFANT_HUMAN_ROBOT: CommonAge.INFANT, + CommonSimType.INFANT_HUMAN_SCARECROW: CommonAge.INFANT, + CommonSimType.INFANT_HUMAN_SKELETON: CommonAge.INFANT, + CommonSimType.INFANT_HUMAN_PLANT_SIM: CommonAge.INFANT, + CommonSimType.INFANT_HUMAN_WEREWOLF: CommonAge.INFANT, + # Baby + CommonSimType.BABY_HUMAN: CommonAge.BABY, + CommonSimType.BABY_HUMAN_VAMPIRE: CommonAge.BABY, + CommonSimType.BABY_HUMAN_GHOST: CommonAge.BABY, + CommonSimType.BABY_HUMAN_ALIEN: CommonAge.BABY, + CommonSimType.BABY_HUMAN_MERMAID: CommonAge.BABY, + CommonSimType.BABY_HUMAN_WITCH: CommonAge.BABY, + CommonSimType.BABY_HUMAN_ROBOT: CommonAge.BABY, + CommonSimType.BABY_HUMAN_SCARECROW: CommonAge.BABY, + CommonSimType.BABY_HUMAN_SKELETON: CommonAge.BABY, + CommonSimType.BABY_HUMAN_PLANT_SIM: CommonAge.BABY, + CommonSimType.BABY_HUMAN_WEREWOLF: CommonAge.BABY, + + # Dog + # Child + CommonSimType.CHILD_DOG: CommonAge.CHILD, + CommonSimType.CHILD_DOG_VAMPIRE: CommonAge.CHILD, + CommonSimType.CHILD_DOG_GHOST: CommonAge.CHILD, + CommonSimType.CHILD_DOG_ALIEN: CommonAge.CHILD, + CommonSimType.CHILD_DOG_MERMAID: CommonAge.CHILD, + CommonSimType.CHILD_DOG_WITCH: CommonAge.CHILD, + CommonSimType.CHILD_DOG_ROBOT: CommonAge.CHILD, + CommonSimType.CHILD_DOG_SCARECROW: CommonAge.CHILD, + CommonSimType.CHILD_DOG_SKELETON: CommonAge.CHILD, + CommonSimType.CHILD_DOG_PLANT_SIM: CommonAge.CHILD, + CommonSimType.CHILD_DOG_WEREWOLF: CommonAge.CHILD, + + # Small Dog + # Elder + CommonSimType.ELDER_SMALL_DOG: CommonAge.ELDER, + CommonSimType.ELDER_SMALL_DOG_VAMPIRE: CommonAge.ELDER, + CommonSimType.ELDER_SMALL_DOG_GHOST: CommonAge.ELDER, + CommonSimType.ELDER_SMALL_DOG_ALIEN: CommonAge.ELDER, + CommonSimType.ELDER_SMALL_DOG_MERMAID: CommonAge.ELDER, + CommonSimType.ELDER_SMALL_DOG_WITCH: CommonAge.ELDER, + CommonSimType.ELDER_SMALL_DOG_ROBOT: CommonAge.ELDER, + CommonSimType.ELDER_SMALL_DOG_SCARECROW: CommonAge.ELDER, + CommonSimType.ELDER_SMALL_DOG_SKELETON: CommonAge.ELDER, + CommonSimType.ELDER_SMALL_DOG_PLANT_SIM: CommonAge.ELDER, + CommonSimType.ELDER_SMALL_DOG_WEREWOLF: CommonAge.ELDER, + # Adult + CommonSimType.ADULT_SMALL_DOG: CommonAge.ADULT, + CommonSimType.ADULT_SMALL_DOG_VAMPIRE: CommonAge.ADULT, + CommonSimType.ADULT_SMALL_DOG_GHOST: CommonAge.ADULT, + CommonSimType.ADULT_SMALL_DOG_ALIEN: CommonAge.ADULT, + CommonSimType.ADULT_SMALL_DOG_MERMAID: CommonAge.ADULT, + CommonSimType.ADULT_SMALL_DOG_WITCH: CommonAge.ADULT, + CommonSimType.ADULT_SMALL_DOG_ROBOT: CommonAge.ADULT, + CommonSimType.ADULT_SMALL_DOG_SCARECROW: CommonAge.ADULT, + CommonSimType.ADULT_SMALL_DOG_SKELETON: CommonAge.ADULT, + CommonSimType.ADULT_SMALL_DOG_PLANT_SIM: CommonAge.ADULT, + CommonSimType.ADULT_SMALL_DOG_WEREWOLF: CommonAge.ADULT, + # Child + CommonSimType.CHILD_SMALL_DOG: CommonAge.CHILD, + CommonSimType.CHILD_SMALL_DOG_VAMPIRE: CommonAge.CHILD, + CommonSimType.CHILD_SMALL_DOG_GHOST: CommonAge.CHILD, + CommonSimType.CHILD_SMALL_DOG_ALIEN: CommonAge.CHILD, + CommonSimType.CHILD_SMALL_DOG_MERMAID: CommonAge.CHILD, + CommonSimType.CHILD_SMALL_DOG_WITCH: CommonAge.CHILD, + CommonSimType.CHILD_SMALL_DOG_ROBOT: CommonAge.CHILD, + CommonSimType.CHILD_SMALL_DOG_SCARECROW: CommonAge.CHILD, + CommonSimType.CHILD_SMALL_DOG_SKELETON: CommonAge.CHILD, + CommonSimType.CHILD_SMALL_DOG_PLANT_SIM: CommonAge.CHILD, + CommonSimType.CHILD_SMALL_DOG_WEREWOLF: CommonAge.CHILD, + + # Large Dog + # Elder + CommonSimType.ELDER_LARGE_DOG: CommonAge.ELDER, + CommonSimType.ELDER_LARGE_DOG_VAMPIRE: CommonAge.ELDER, + CommonSimType.ELDER_LARGE_DOG_GHOST: CommonAge.ELDER, + CommonSimType.ELDER_LARGE_DOG_ALIEN: CommonAge.ELDER, + CommonSimType.ELDER_LARGE_DOG_MERMAID: CommonAge.ELDER, + CommonSimType.ELDER_LARGE_DOG_WITCH: CommonAge.ELDER, + CommonSimType.ELDER_LARGE_DOG_ROBOT: CommonAge.ELDER, + CommonSimType.ELDER_LARGE_DOG_SCARECROW: CommonAge.ELDER, + CommonSimType.ELDER_LARGE_DOG_SKELETON: CommonAge.ELDER, + CommonSimType.ELDER_LARGE_DOG_PLANT_SIM: CommonAge.ELDER, + CommonSimType.ELDER_LARGE_DOG_WEREWOLF: CommonAge.ELDER, + # Adult + CommonSimType.ADULT_LARGE_DOG: CommonAge.ADULT, + CommonSimType.ADULT_LARGE_DOG_VAMPIRE: CommonAge.ADULT, + CommonSimType.ADULT_LARGE_DOG_GHOST: CommonAge.ADULT, + CommonSimType.ADULT_LARGE_DOG_ALIEN: CommonAge.ADULT, + CommonSimType.ADULT_LARGE_DOG_MERMAID: CommonAge.ADULT, + CommonSimType.ADULT_LARGE_DOG_WITCH: CommonAge.ADULT, + CommonSimType.ADULT_LARGE_DOG_ROBOT: CommonAge.ADULT, + CommonSimType.ADULT_LARGE_DOG_SCARECROW: CommonAge.ADULT, + CommonSimType.ADULT_LARGE_DOG_SKELETON: CommonAge.ADULT, + CommonSimType.ADULT_LARGE_DOG_PLANT_SIM: CommonAge.ADULT, + CommonSimType.ADULT_LARGE_DOG_WEREWOLF: CommonAge.ADULT, + # Child + CommonSimType.CHILD_LARGE_DOG: CommonAge.CHILD, + CommonSimType.CHILD_LARGE_DOG_VAMPIRE: CommonAge.CHILD, + CommonSimType.CHILD_LARGE_DOG_GHOST: CommonAge.CHILD, + CommonSimType.CHILD_LARGE_DOG_ALIEN: CommonAge.CHILD, + CommonSimType.CHILD_LARGE_DOG_MERMAID: CommonAge.CHILD, + CommonSimType.CHILD_LARGE_DOG_WITCH: CommonAge.CHILD, + CommonSimType.CHILD_LARGE_DOG_ROBOT: CommonAge.CHILD, + CommonSimType.CHILD_LARGE_DOG_SCARECROW: CommonAge.CHILD, + CommonSimType.CHILD_LARGE_DOG_SKELETON: CommonAge.CHILD, + CommonSimType.CHILD_LARGE_DOG_PLANT_SIM: CommonAge.CHILD, + CommonSimType.CHILD_LARGE_DOG_WEREWOLF: CommonAge.CHILD, + + # Cat + # Elder + CommonSimType.ELDER_CAT: CommonAge.ELDER, + CommonSimType.ELDER_CAT_VAMPIRE: CommonAge.ELDER, + CommonSimType.ELDER_CAT_GHOST: CommonAge.ELDER, + CommonSimType.ELDER_CAT_ALIEN: CommonAge.ELDER, + CommonSimType.ELDER_CAT_MERMAID: CommonAge.ELDER, + CommonSimType.ELDER_CAT_WITCH: CommonAge.ELDER, + CommonSimType.ELDER_CAT_ROBOT: CommonAge.ELDER, + CommonSimType.ELDER_CAT_SCARECROW: CommonAge.ELDER, + CommonSimType.ELDER_CAT_SKELETON: CommonAge.ELDER, + CommonSimType.ELDER_CAT_PLANT_SIM: CommonAge.ELDER, + CommonSimType.ELDER_CAT_WEREWOLF: CommonAge.ELDER, + # Adult + CommonSimType.ADULT_CAT: CommonAge.ADULT, + CommonSimType.ADULT_CAT_VAMPIRE: CommonAge.ADULT, + CommonSimType.ADULT_CAT_GHOST: CommonAge.ADULT, + CommonSimType.ADULT_CAT_ALIEN: CommonAge.ADULT, + CommonSimType.ADULT_CAT_MERMAID: CommonAge.ADULT, + CommonSimType.ADULT_CAT_WITCH: CommonAge.ADULT, + CommonSimType.ADULT_CAT_ROBOT: CommonAge.ADULT, + CommonSimType.ADULT_CAT_SCARECROW: CommonAge.ADULT, + CommonSimType.ADULT_CAT_SKELETON: CommonAge.ADULT, + CommonSimType.ADULT_CAT_PLANT_SIM: CommonAge.ADULT, + CommonSimType.ADULT_CAT_WEREWOLF: CommonAge.ADULT, + # Child + CommonSimType.CHILD_CAT: CommonAge.CHILD, + CommonSimType.CHILD_CAT_VAMPIRE: CommonAge.CHILD, + CommonSimType.CHILD_CAT_GHOST: CommonAge.CHILD, + CommonSimType.CHILD_CAT_ALIEN: CommonAge.CHILD, + CommonSimType.CHILD_CAT_MERMAID: CommonAge.CHILD, + CommonSimType.CHILD_CAT_WITCH: CommonAge.CHILD, + CommonSimType.CHILD_CAT_ROBOT: CommonAge.CHILD, + CommonSimType.CHILD_CAT_SCARECROW: CommonAge.CHILD, + CommonSimType.CHILD_CAT_SKELETON: CommonAge.CHILD, + CommonSimType.CHILD_CAT_PLANT_SIM: CommonAge.CHILD, + CommonSimType.CHILD_CAT_WEREWOLF: CommonAge.CHILD, + + # Fox + # Elder + CommonSimType.ELDER_FOX: CommonAge.ELDER, + CommonSimType.ELDER_FOX_VAMPIRE: CommonAge.ELDER, + CommonSimType.ELDER_FOX_GHOST: CommonAge.ELDER, + CommonSimType.ELDER_FOX_ALIEN: CommonAge.ELDER, + CommonSimType.ELDER_FOX_MERMAID: CommonAge.ELDER, + CommonSimType.ELDER_FOX_WITCH: CommonAge.ELDER, + CommonSimType.ELDER_FOX_ROBOT: CommonAge.ELDER, + CommonSimType.ELDER_FOX_SCARECROW: CommonAge.ELDER, + CommonSimType.ELDER_FOX_SKELETON: CommonAge.ELDER, + CommonSimType.ELDER_FOX_PLANT_SIM: CommonAge.ELDER, + CommonSimType.ELDER_FOX_WEREWOLF: CommonAge.ELDER, + # Adult + CommonSimType.ADULT_FOX: CommonAge.ADULT, + CommonSimType.ADULT_FOX_VAMPIRE: CommonAge.ADULT, + CommonSimType.ADULT_FOX_GHOST: CommonAge.ADULT, + CommonSimType.ADULT_FOX_ALIEN: CommonAge.ADULT, + CommonSimType.ADULT_FOX_MERMAID: CommonAge.ADULT, + CommonSimType.ADULT_FOX_WITCH: CommonAge.ADULT, + CommonSimType.ADULT_FOX_ROBOT: CommonAge.ADULT, + CommonSimType.ADULT_FOX_SCARECROW: CommonAge.ADULT, + CommonSimType.ADULT_FOX_SKELETON: CommonAge.ADULT, + CommonSimType.ADULT_FOX_PLANT_SIM: CommonAge.ADULT, + CommonSimType.ADULT_FOX_WEREWOLF: CommonAge.ADULT, + # Child + CommonSimType.CHILD_FOX: CommonAge.CHILD, + CommonSimType.CHILD_FOX_VAMPIRE: CommonAge.CHILD, + CommonSimType.CHILD_FOX_GHOST: CommonAge.CHILD, + CommonSimType.CHILD_FOX_ALIEN: CommonAge.CHILD, + CommonSimType.CHILD_FOX_MERMAID: CommonAge.CHILD, + CommonSimType.CHILD_FOX_WITCH: CommonAge.CHILD, + CommonSimType.CHILD_FOX_ROBOT: CommonAge.CHILD, + CommonSimType.CHILD_FOX_SCARECROW: CommonAge.CHILD, + CommonSimType.CHILD_FOX_SKELETON: CommonAge.CHILD, + CommonSimType.CHILD_FOX_PLANT_SIM: CommonAge.CHILD, + CommonSimType.CHILD_FOX_WEREWOLF: CommonAge.CHILD, + + # Horse + # Elder + CommonSimType.ELDER_HORSE: CommonAge.ELDER, + CommonSimType.ELDER_HORSE_VAMPIRE: CommonAge.ELDER, + CommonSimType.ELDER_HORSE_GHOST: CommonAge.ELDER, + CommonSimType.ELDER_HORSE_ALIEN: CommonAge.ELDER, + CommonSimType.ELDER_HORSE_MERMAID: CommonAge.ELDER, + CommonSimType.ELDER_HORSE_WITCH: CommonAge.ELDER, + CommonSimType.ELDER_HORSE_ROBOT: CommonAge.ELDER, + CommonSimType.ELDER_HORSE_SCARECROW: CommonAge.ELDER, + CommonSimType.ELDER_HORSE_SKELETON: CommonAge.ELDER, + CommonSimType.ELDER_HORSE_PLANT_SIM: CommonAge.ELDER, + CommonSimType.ELDER_HORSE_WEREWOLF: CommonAge.ELDER, + # Adult + CommonSimType.ADULT_HORSE: CommonAge.ADULT, + CommonSimType.ADULT_HORSE_VAMPIRE: CommonAge.ADULT, + CommonSimType.ADULT_HORSE_GHOST: CommonAge.ADULT, + CommonSimType.ADULT_HORSE_ALIEN: CommonAge.ADULT, + CommonSimType.ADULT_HORSE_MERMAID: CommonAge.ADULT, + CommonSimType.ADULT_HORSE_WITCH: CommonAge.ADULT, + CommonSimType.ADULT_HORSE_ROBOT: CommonAge.ADULT, + CommonSimType.ADULT_HORSE_SCARECROW: CommonAge.ADULT, + CommonSimType.ADULT_HORSE_SKELETON: CommonAge.ADULT, + CommonSimType.ADULT_HORSE_PLANT_SIM: CommonAge.ADULT, + CommonSimType.ADULT_HORSE_WEREWOLF: CommonAge.ADULT, + # Child + CommonSimType.CHILD_HORSE: CommonAge.CHILD, + CommonSimType.CHILD_HORSE_VAMPIRE: CommonAge.CHILD, + CommonSimType.CHILD_HORSE_GHOST: CommonAge.CHILD, + CommonSimType.CHILD_HORSE_ALIEN: CommonAge.CHILD, + CommonSimType.CHILD_HORSE_MERMAID: CommonAge.CHILD, + CommonSimType.CHILD_HORSE_WITCH: CommonAge.CHILD, + CommonSimType.CHILD_HORSE_ROBOT: CommonAge.CHILD, + CommonSimType.CHILD_HORSE_SCARECROW: CommonAge.CHILD, + CommonSimType.CHILD_HORSE_SKELETON: CommonAge.CHILD, + CommonSimType.CHILD_HORSE_PLANT_SIM: CommonAge.CHILD, + CommonSimType.CHILD_HORSE_WEREWOLF: CommonAge.CHILD, + } + + _OCCULT_SIM_TYPE_TO_SPECIES_MAPPING: Dict[CommonSimType, CommonSpecies] = { + # Human + # Elder + CommonSimType.ELDER_HUMAN: CommonSpecies.HUMAN, + CommonSimType.ELDER_HUMAN_VAMPIRE: CommonSpecies.HUMAN, + CommonSimType.ELDER_HUMAN_GHOST: CommonSpecies.HUMAN, + CommonSimType.ELDER_HUMAN_ALIEN: CommonSpecies.HUMAN, + CommonSimType.ELDER_HUMAN_MERMAID: CommonSpecies.HUMAN, + CommonSimType.ELDER_HUMAN_WITCH: CommonSpecies.HUMAN, + CommonSimType.ELDER_HUMAN_ROBOT: CommonSpecies.HUMAN, + CommonSimType.ELDER_HUMAN_SCARECROW: CommonSpecies.HUMAN, + CommonSimType.ELDER_HUMAN_SKELETON: CommonSpecies.HUMAN, + CommonSimType.ELDER_HUMAN_PLANT_SIM: CommonSpecies.HUMAN, + CommonSimType.ELDER_HUMAN_WEREWOLF: CommonSpecies.HUMAN, + # Adult + CommonSimType.ADULT_HUMAN: CommonSpecies.HUMAN, + CommonSimType.ADULT_HUMAN_VAMPIRE: CommonSpecies.HUMAN, + CommonSimType.ADULT_HUMAN_GHOST: CommonSpecies.HUMAN, + CommonSimType.ADULT_HUMAN_ALIEN: CommonSpecies.HUMAN, + CommonSimType.ADULT_HUMAN_MERMAID: CommonSpecies.HUMAN, + CommonSimType.ADULT_HUMAN_WITCH: CommonSpecies.HUMAN, + CommonSimType.ADULT_HUMAN_ROBOT: CommonSpecies.HUMAN, + CommonSimType.ADULT_HUMAN_SCARECROW: CommonSpecies.HUMAN, + CommonSimType.ADULT_HUMAN_SKELETON: CommonSpecies.HUMAN, + CommonSimType.ADULT_HUMAN_PLANT_SIM: CommonSpecies.HUMAN, + CommonSimType.ADULT_HUMAN_WEREWOLF: CommonSpecies.HUMAN, + # Young Adult + CommonSimType.YOUNG_ADULT_HUMAN: CommonSpecies.HUMAN, + CommonSimType.YOUNG_ADULT_HUMAN_VAMPIRE: CommonSpecies.HUMAN, + CommonSimType.YOUNG_ADULT_HUMAN_GHOST: CommonSpecies.HUMAN, + CommonSimType.YOUNG_ADULT_HUMAN_ALIEN: CommonSpecies.HUMAN, + CommonSimType.YOUNG_ADULT_HUMAN_MERMAID: CommonSpecies.HUMAN, + CommonSimType.YOUNG_ADULT_HUMAN_WITCH: CommonSpecies.HUMAN, + CommonSimType.YOUNG_ADULT_HUMAN_ROBOT: CommonSpecies.HUMAN, + CommonSimType.YOUNG_ADULT_HUMAN_SCARECROW: CommonSpecies.HUMAN, + CommonSimType.YOUNG_ADULT_HUMAN_SKELETON: CommonSpecies.HUMAN, + CommonSimType.YOUNG_ADULT_HUMAN_PLANT_SIM: CommonSpecies.HUMAN, + CommonSimType.YOUNG_ADULT_HUMAN_WEREWOLF: CommonSpecies.HUMAN, + # Teen + CommonSimType.TEEN_HUMAN: CommonSpecies.HUMAN, + CommonSimType.TEEN_HUMAN_VAMPIRE: CommonSpecies.HUMAN, + CommonSimType.TEEN_HUMAN_GHOST: CommonSpecies.HUMAN, + CommonSimType.TEEN_HUMAN_ALIEN: CommonSpecies.HUMAN, + CommonSimType.TEEN_HUMAN_MERMAID: CommonSpecies.HUMAN, + CommonSimType.TEEN_HUMAN_WITCH: CommonSpecies.HUMAN, + CommonSimType.TEEN_HUMAN_ROBOT: CommonSpecies.HUMAN, + CommonSimType.TEEN_HUMAN_SCARECROW: CommonSpecies.HUMAN, + CommonSimType.TEEN_HUMAN_SKELETON: CommonSpecies.HUMAN, + CommonSimType.TEEN_HUMAN_PLANT_SIM: CommonSpecies.HUMAN, + CommonSimType.TEEN_HUMAN_WEREWOLF: CommonSpecies.HUMAN, + # Child + CommonSimType.CHILD_HUMAN: CommonSpecies.HUMAN, + CommonSimType.CHILD_HUMAN_VAMPIRE: CommonSpecies.HUMAN, + CommonSimType.CHILD_HUMAN_GHOST: CommonSpecies.HUMAN, + CommonSimType.CHILD_HUMAN_ALIEN: CommonSpecies.HUMAN, + CommonSimType.CHILD_HUMAN_MERMAID: CommonSpecies.HUMAN, + CommonSimType.CHILD_HUMAN_WITCH: CommonSpecies.HUMAN, + CommonSimType.CHILD_HUMAN_ROBOT: CommonSpecies.HUMAN, + CommonSimType.CHILD_HUMAN_SCARECROW: CommonSpecies.HUMAN, + CommonSimType.CHILD_HUMAN_SKELETON: CommonSpecies.HUMAN, + CommonSimType.CHILD_HUMAN_PLANT_SIM: CommonSpecies.HUMAN, + CommonSimType.CHILD_HUMAN_WEREWOLF: CommonSpecies.HUMAN, + # Toddler + CommonSimType.TODDLER_HUMAN: CommonSpecies.HUMAN, + CommonSimType.TODDLER_HUMAN_VAMPIRE: CommonSpecies.HUMAN, + CommonSimType.TODDLER_HUMAN_GHOST: CommonSpecies.HUMAN, + CommonSimType.TODDLER_HUMAN_ALIEN: CommonSpecies.HUMAN, + CommonSimType.TODDLER_HUMAN_MERMAID: CommonSpecies.HUMAN, + CommonSimType.TODDLER_HUMAN_WITCH: CommonSpecies.HUMAN, + CommonSimType.TODDLER_HUMAN_ROBOT: CommonSpecies.HUMAN, + CommonSimType.TODDLER_HUMAN_SCARECROW: CommonSpecies.HUMAN, + CommonSimType.TODDLER_HUMAN_SKELETON: CommonSpecies.HUMAN, + CommonSimType.TODDLER_HUMAN_PLANT_SIM: CommonSpecies.HUMAN, + CommonSimType.TODDLER_HUMAN_WEREWOLF: CommonSpecies.HUMAN, + # Infant + CommonSimType.INFANT_HUMAN: CommonSpecies.HUMAN, + CommonSimType.INFANT_HUMAN_VAMPIRE: CommonSpecies.HUMAN, + CommonSimType.INFANT_HUMAN_GHOST: CommonSpecies.HUMAN, + CommonSimType.INFANT_HUMAN_ALIEN: CommonSpecies.HUMAN, + CommonSimType.INFANT_HUMAN_MERMAID: CommonSpecies.HUMAN, + CommonSimType.INFANT_HUMAN_WITCH: CommonSpecies.HUMAN, + CommonSimType.INFANT_HUMAN_ROBOT: CommonSpecies.HUMAN, + CommonSimType.INFANT_HUMAN_SCARECROW: CommonSpecies.HUMAN, + CommonSimType.INFANT_HUMAN_SKELETON: CommonSpecies.HUMAN, + CommonSimType.INFANT_HUMAN_PLANT_SIM: CommonSpecies.HUMAN, + CommonSimType.INFANT_HUMAN_WEREWOLF: CommonSpecies.HUMAN, + # Baby + CommonSimType.BABY_HUMAN: CommonSpecies.HUMAN, + CommonSimType.BABY_HUMAN_VAMPIRE: CommonSpecies.HUMAN, + CommonSimType.BABY_HUMAN_GHOST: CommonSpecies.HUMAN, + CommonSimType.BABY_HUMAN_ALIEN: CommonSpecies.HUMAN, + CommonSimType.BABY_HUMAN_MERMAID: CommonSpecies.HUMAN, + CommonSimType.BABY_HUMAN_WITCH: CommonSpecies.HUMAN, + CommonSimType.BABY_HUMAN_ROBOT: CommonSpecies.HUMAN, + CommonSimType.BABY_HUMAN_SCARECROW: CommonSpecies.HUMAN, + CommonSimType.BABY_HUMAN_SKELETON: CommonSpecies.HUMAN, + CommonSimType.BABY_HUMAN_PLANT_SIM: CommonSpecies.HUMAN, + CommonSimType.BABY_HUMAN_WEREWOLF: CommonSpecies.HUMAN, + + # Dog + # Small Dog + # Elder + CommonSimType.ELDER_SMALL_DOG: CommonSpecies.SMALL_DOG, + CommonSimType.ELDER_SMALL_DOG_VAMPIRE: CommonSpecies.SMALL_DOG, + CommonSimType.ELDER_SMALL_DOG_GHOST: CommonSpecies.SMALL_DOG, + CommonSimType.ELDER_SMALL_DOG_ALIEN: CommonSpecies.SMALL_DOG, + CommonSimType.ELDER_SMALL_DOG_MERMAID: CommonSpecies.SMALL_DOG, + CommonSimType.ELDER_SMALL_DOG_WITCH: CommonSpecies.SMALL_DOG, + CommonSimType.ELDER_SMALL_DOG_ROBOT: CommonSpecies.SMALL_DOG, + CommonSimType.ELDER_SMALL_DOG_SCARECROW: CommonSpecies.SMALL_DOG, + CommonSimType.ELDER_SMALL_DOG_SKELETON: CommonSpecies.SMALL_DOG, + CommonSimType.ELDER_SMALL_DOG_PLANT_SIM: CommonSpecies.SMALL_DOG, + CommonSimType.ELDER_SMALL_DOG_WEREWOLF: CommonSpecies.SMALL_DOG, + # Adult + CommonSimType.ADULT_SMALL_DOG: CommonSpecies.SMALL_DOG, + CommonSimType.ADULT_SMALL_DOG_VAMPIRE: CommonSpecies.SMALL_DOG, + CommonSimType.ADULT_SMALL_DOG_GHOST: CommonSpecies.SMALL_DOG, + CommonSimType.ADULT_SMALL_DOG_ALIEN: CommonSpecies.SMALL_DOG, + CommonSimType.ADULT_SMALL_DOG_MERMAID: CommonSpecies.SMALL_DOG, + CommonSimType.ADULT_SMALL_DOG_WITCH: CommonSpecies.SMALL_DOG, + CommonSimType.ADULT_SMALL_DOG_ROBOT: CommonSpecies.SMALL_DOG, + CommonSimType.ADULT_SMALL_DOG_SCARECROW: CommonSpecies.SMALL_DOG, + CommonSimType.ADULT_SMALL_DOG_SKELETON: CommonSpecies.SMALL_DOG, + CommonSimType.ADULT_SMALL_DOG_PLANT_SIM: CommonSpecies.SMALL_DOG, + CommonSimType.ADULT_SMALL_DOG_WEREWOLF: CommonSpecies.SMALL_DOG, + # Child + CommonSimType.CHILD_SMALL_DOG: CommonSpecies.SMALL_DOG, + CommonSimType.CHILD_SMALL_DOG_VAMPIRE: CommonSpecies.SMALL_DOG, + CommonSimType.CHILD_SMALL_DOG_GHOST: CommonSpecies.SMALL_DOG, + CommonSimType.CHILD_SMALL_DOG_ALIEN: CommonSpecies.SMALL_DOG, + CommonSimType.CHILD_SMALL_DOG_MERMAID: CommonSpecies.SMALL_DOG, + CommonSimType.CHILD_SMALL_DOG_WITCH: CommonSpecies.SMALL_DOG, + CommonSimType.CHILD_SMALL_DOG_ROBOT: CommonSpecies.SMALL_DOG, + CommonSimType.CHILD_SMALL_DOG_SCARECROW: CommonSpecies.SMALL_DOG, + CommonSimType.CHILD_SMALL_DOG_SKELETON: CommonSpecies.SMALL_DOG, + CommonSimType.CHILD_SMALL_DOG_PLANT_SIM: CommonSpecies.SMALL_DOG, + CommonSimType.CHILD_SMALL_DOG_WEREWOLF: CommonSpecies.SMALL_DOG, + + # Child + CommonSimType.CHILD_DOG: CommonSpecies.LARGE_DOG, + CommonSimType.CHILD_DOG_VAMPIRE: CommonSpecies.LARGE_DOG, + CommonSimType.CHILD_DOG_GHOST: CommonSpecies.LARGE_DOG, + CommonSimType.CHILD_DOG_ALIEN: CommonSpecies.LARGE_DOG, + CommonSimType.CHILD_DOG_MERMAID: CommonSpecies.LARGE_DOG, + CommonSimType.CHILD_DOG_WITCH: CommonSpecies.LARGE_DOG, + CommonSimType.CHILD_DOG_ROBOT: CommonSpecies.LARGE_DOG, + CommonSimType.CHILD_DOG_SCARECROW: CommonSpecies.LARGE_DOG, + CommonSimType.CHILD_DOG_SKELETON: CommonSpecies.LARGE_DOG, + CommonSimType.CHILD_DOG_PLANT_SIM: CommonSpecies.LARGE_DOG, + CommonSimType.CHILD_DOG_WEREWOLF: CommonSpecies.LARGE_DOG, + + # Large Dog + # Elder + CommonSimType.ELDER_LARGE_DOG: CommonSpecies.LARGE_DOG, + CommonSimType.ELDER_LARGE_DOG_VAMPIRE: CommonSpecies.LARGE_DOG, + CommonSimType.ELDER_LARGE_DOG_GHOST: CommonSpecies.LARGE_DOG, + CommonSimType.ELDER_LARGE_DOG_ALIEN: CommonSpecies.LARGE_DOG, + CommonSimType.ELDER_LARGE_DOG_MERMAID: CommonSpecies.LARGE_DOG, + CommonSimType.ELDER_LARGE_DOG_WITCH: CommonSpecies.LARGE_DOG, + CommonSimType.ELDER_LARGE_DOG_ROBOT: CommonSpecies.LARGE_DOG, + CommonSimType.ELDER_LARGE_DOG_SCARECROW: CommonSpecies.LARGE_DOG, + CommonSimType.ELDER_LARGE_DOG_SKELETON: CommonSpecies.LARGE_DOG, + CommonSimType.ELDER_LARGE_DOG_PLANT_SIM: CommonSpecies.LARGE_DOG, + CommonSimType.ELDER_LARGE_DOG_WEREWOLF: CommonSpecies.LARGE_DOG, + # Adult + CommonSimType.ADULT_LARGE_DOG: CommonSpecies.LARGE_DOG, + CommonSimType.ADULT_LARGE_DOG_VAMPIRE: CommonSpecies.LARGE_DOG, + CommonSimType.ADULT_LARGE_DOG_GHOST: CommonSpecies.LARGE_DOG, + CommonSimType.ADULT_LARGE_DOG_ALIEN: CommonSpecies.LARGE_DOG, + CommonSimType.ADULT_LARGE_DOG_MERMAID: CommonSpecies.LARGE_DOG, + CommonSimType.ADULT_LARGE_DOG_WITCH: CommonSpecies.LARGE_DOG, + CommonSimType.ADULT_LARGE_DOG_ROBOT: CommonSpecies.LARGE_DOG, + CommonSimType.ADULT_LARGE_DOG_SCARECROW: CommonSpecies.LARGE_DOG, + CommonSimType.ADULT_LARGE_DOG_SKELETON: CommonSpecies.LARGE_DOG, + CommonSimType.ADULT_LARGE_DOG_PLANT_SIM: CommonSpecies.LARGE_DOG, + CommonSimType.ADULT_LARGE_DOG_WEREWOLF: CommonSpecies.LARGE_DOG, + # Child + CommonSimType.CHILD_LARGE_DOG: CommonSpecies.LARGE_DOG, + CommonSimType.CHILD_LARGE_DOG_VAMPIRE: CommonSpecies.LARGE_DOG, + CommonSimType.CHILD_LARGE_DOG_GHOST: CommonSpecies.LARGE_DOG, + CommonSimType.CHILD_LARGE_DOG_ALIEN: CommonSpecies.LARGE_DOG, + CommonSimType.CHILD_LARGE_DOG_MERMAID: CommonSpecies.LARGE_DOG, + CommonSimType.CHILD_LARGE_DOG_WITCH: CommonSpecies.LARGE_DOG, + CommonSimType.CHILD_LARGE_DOG_ROBOT: CommonSpecies.LARGE_DOG, + CommonSimType.CHILD_LARGE_DOG_SCARECROW: CommonSpecies.LARGE_DOG, + CommonSimType.CHILD_LARGE_DOG_SKELETON: CommonSpecies.LARGE_DOG, + CommonSimType.CHILD_LARGE_DOG_PLANT_SIM: CommonSpecies.LARGE_DOG, + CommonSimType.CHILD_LARGE_DOG_WEREWOLF: CommonSpecies.LARGE_DOG, + + # Cat + # Elder + CommonSimType.ELDER_CAT: CommonSpecies.CAT, + CommonSimType.ELDER_CAT_VAMPIRE: CommonSpecies.CAT, + CommonSimType.ELDER_CAT_GHOST: CommonSpecies.CAT, + CommonSimType.ELDER_CAT_ALIEN: CommonSpecies.CAT, + CommonSimType.ELDER_CAT_MERMAID: CommonSpecies.CAT, + CommonSimType.ELDER_CAT_WITCH: CommonSpecies.CAT, + CommonSimType.ELDER_CAT_ROBOT: CommonSpecies.CAT, + CommonSimType.ELDER_CAT_SCARECROW: CommonSpecies.CAT, + CommonSimType.ELDER_CAT_SKELETON: CommonSpecies.CAT, + CommonSimType.ELDER_CAT_PLANT_SIM: CommonSpecies.CAT, + CommonSimType.ELDER_CAT_WEREWOLF: CommonSpecies.CAT, + # Adult + CommonSimType.ADULT_CAT: CommonSpecies.CAT, + CommonSimType.ADULT_CAT_VAMPIRE: CommonSpecies.CAT, + CommonSimType.ADULT_CAT_GHOST: CommonSpecies.CAT, + CommonSimType.ADULT_CAT_ALIEN: CommonSpecies.CAT, + CommonSimType.ADULT_CAT_MERMAID: CommonSpecies.CAT, + CommonSimType.ADULT_CAT_WITCH: CommonSpecies.CAT, + CommonSimType.ADULT_CAT_ROBOT: CommonSpecies.CAT, + CommonSimType.ADULT_CAT_SCARECROW: CommonSpecies.CAT, + CommonSimType.ADULT_CAT_SKELETON: CommonSpecies.CAT, + CommonSimType.ADULT_CAT_PLANT_SIM: CommonSpecies.CAT, + CommonSimType.ADULT_CAT_WEREWOLF: CommonSpecies.CAT, + # Child + CommonSimType.CHILD_CAT: CommonSpecies.CAT, + CommonSimType.CHILD_CAT_VAMPIRE: CommonSpecies.CAT, + CommonSimType.CHILD_CAT_GHOST: CommonSpecies.CAT, + CommonSimType.CHILD_CAT_ALIEN: CommonSpecies.CAT, + CommonSimType.CHILD_CAT_MERMAID: CommonSpecies.CAT, + CommonSimType.CHILD_CAT_WITCH: CommonSpecies.CAT, + CommonSimType.CHILD_CAT_ROBOT: CommonSpecies.CAT, + CommonSimType.CHILD_CAT_SCARECROW: CommonSpecies.CAT, + CommonSimType.CHILD_CAT_SKELETON: CommonSpecies.CAT, + CommonSimType.CHILD_CAT_PLANT_SIM: CommonSpecies.CAT, + CommonSimType.CHILD_CAT_WEREWOLF: CommonSpecies.CAT, + + # Fox + # Elder + CommonSimType.ELDER_FOX: CommonSpecies.FOX, + CommonSimType.ELDER_FOX_VAMPIRE: CommonSpecies.FOX, + CommonSimType.ELDER_FOX_GHOST: CommonSpecies.FOX, + CommonSimType.ELDER_FOX_ALIEN: CommonSpecies.FOX, + CommonSimType.ELDER_FOX_MERMAID: CommonSpecies.FOX, + CommonSimType.ELDER_FOX_WITCH: CommonSpecies.FOX, + CommonSimType.ELDER_FOX_ROBOT: CommonSpecies.FOX, + CommonSimType.ELDER_FOX_SCARECROW: CommonSpecies.FOX, + CommonSimType.ELDER_FOX_SKELETON: CommonSpecies.FOX, + CommonSimType.ELDER_FOX_PLANT_SIM: CommonSpecies.FOX, + CommonSimType.ELDER_FOX_WEREWOLF: CommonSpecies.FOX, + # Adult + CommonSimType.ADULT_FOX: CommonSpecies.FOX, + CommonSimType.ADULT_FOX_VAMPIRE: CommonSpecies.FOX, + CommonSimType.ADULT_FOX_GHOST: CommonSpecies.FOX, + CommonSimType.ADULT_FOX_ALIEN: CommonSpecies.FOX, + CommonSimType.ADULT_FOX_MERMAID: CommonSpecies.FOX, + CommonSimType.ADULT_FOX_WITCH: CommonSpecies.FOX, + CommonSimType.ADULT_FOX_ROBOT: CommonSpecies.FOX, + CommonSimType.ADULT_FOX_SCARECROW: CommonSpecies.FOX, + CommonSimType.ADULT_FOX_SKELETON: CommonSpecies.FOX, + CommonSimType.ADULT_FOX_PLANT_SIM: CommonSpecies.FOX, + CommonSimType.ADULT_FOX_WEREWOLF: CommonSpecies.FOX, + # Child + CommonSimType.CHILD_FOX: CommonSpecies.FOX, + CommonSimType.CHILD_FOX_VAMPIRE: CommonSpecies.FOX, + CommonSimType.CHILD_FOX_GHOST: CommonSpecies.FOX, + CommonSimType.CHILD_FOX_ALIEN: CommonSpecies.FOX, + CommonSimType.CHILD_FOX_MERMAID: CommonSpecies.FOX, + CommonSimType.CHILD_FOX_WITCH: CommonSpecies.FOX, + CommonSimType.CHILD_FOX_ROBOT: CommonSpecies.FOX, + CommonSimType.CHILD_FOX_SCARECROW: CommonSpecies.FOX, + CommonSimType.CHILD_FOX_SKELETON: CommonSpecies.FOX, + CommonSimType.CHILD_FOX_PLANT_SIM: CommonSpecies.FOX, + CommonSimType.CHILD_FOX_WEREWOLF: CommonSpecies.FOX, + + # Horse + # Elder + CommonSimType.ELDER_HORSE: CommonSpecies.HORSE, + CommonSimType.ELDER_HORSE_VAMPIRE: CommonSpecies.HORSE, + CommonSimType.ELDER_HORSE_GHOST: CommonSpecies.HORSE, + CommonSimType.ELDER_HORSE_ALIEN: CommonSpecies.HORSE, + CommonSimType.ELDER_HORSE_MERMAID: CommonSpecies.HORSE, + CommonSimType.ELDER_HORSE_WITCH: CommonSpecies.HORSE, + CommonSimType.ELDER_HORSE_ROBOT: CommonSpecies.HORSE, + CommonSimType.ELDER_HORSE_SCARECROW: CommonSpecies.HORSE, + CommonSimType.ELDER_HORSE_SKELETON: CommonSpecies.HORSE, + CommonSimType.ELDER_HORSE_PLANT_SIM: CommonSpecies.HORSE, + CommonSimType.ELDER_HORSE_WEREWOLF: CommonSpecies.HORSE, + # Adult + CommonSimType.ADULT_HORSE: CommonSpecies.HORSE, + CommonSimType.ADULT_HORSE_VAMPIRE: CommonSpecies.HORSE, + CommonSimType.ADULT_HORSE_GHOST: CommonSpecies.HORSE, + CommonSimType.ADULT_HORSE_ALIEN: CommonSpecies.HORSE, + CommonSimType.ADULT_HORSE_MERMAID: CommonSpecies.HORSE, + CommonSimType.ADULT_HORSE_WITCH: CommonSpecies.HORSE, + CommonSimType.ADULT_HORSE_ROBOT: CommonSpecies.HORSE, + CommonSimType.ADULT_HORSE_SCARECROW: CommonSpecies.HORSE, + CommonSimType.ADULT_HORSE_SKELETON: CommonSpecies.HORSE, + CommonSimType.ADULT_HORSE_PLANT_SIM: CommonSpecies.HORSE, + CommonSimType.ADULT_HORSE_WEREWOLF: CommonSpecies.HORSE, + # Child + CommonSimType.CHILD_HORSE: CommonSpecies.HORSE, + CommonSimType.CHILD_HORSE_VAMPIRE: CommonSpecies.HORSE, + CommonSimType.CHILD_HORSE_GHOST: CommonSpecies.HORSE, + CommonSimType.CHILD_HORSE_ALIEN: CommonSpecies.HORSE, + CommonSimType.CHILD_HORSE_MERMAID: CommonSpecies.HORSE, + CommonSimType.CHILD_HORSE_WITCH: CommonSpecies.HORSE, + CommonSimType.CHILD_HORSE_ROBOT: CommonSpecies.HORSE, + CommonSimType.CHILD_HORSE_SCARECROW: CommonSpecies.HORSE, + CommonSimType.CHILD_HORSE_SKELETON: CommonSpecies.HORSE, + CommonSimType.CHILD_HORSE_PLANT_SIM: CommonSpecies.HORSE, + CommonSimType.CHILD_HORSE_WEREWOLF: CommonSpecies.HORSE, + } + + @staticmethod + def is_non_player_sim(sim_info: SimInfo) -> bool: + """is_non_player_sim(sim_info) + + Determine if a Sim is a Non Player Sim. + + .. note:: An NPC Sim is a sim that is not a part of the active household. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is an NPC. False, if not. + :rtype: bool + """ + if sim_info is None: + raise AssertionError('Sim Info was None!') + # noinspection PyTypeChecker + return sim_info.is_npc + + @staticmethod + def is_player_sim(sim_info: SimInfo) -> bool: + """is_player_sim(sim_info) + + Determine if a Sim is a Player Sim. + + .. note:: A Player Sim is a Sim that is a part of the active household. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is a Player Sim. False, if not. + :rtype: bool + """ + if sim_info is None: + raise AssertionError('Sim Info was None!') + return not CommonSimTypeUtils.is_non_player_sim(sim_info) + + @staticmethod + def is_played_sim(sim_info: SimInfo) -> bool: + """is_played_sim(sim_info) + + Determine if a Sim is a Played Sim. + + .. note:: This does not indicate if a Sim is a Player Sim or Non Player Sim. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is a Played Sim. False, if not. + :rtype: bool + """ + if sim_info is None: + raise AssertionError('Sim Info was None!') + return sim_info.is_played_sim + + @staticmethod + def is_service_sim(sim_info: SimInfo) -> CommonTestResult: + """Determine if a Sim is a Service Sim. + + .. note:: + + Service Sims: + + - Butler + - Chalet + - City Repair + - Forest Ranger + - Gardener + - Grim Reaper + - Maid + - Mailman + - Massage Therapist + - Master Fisherman + - Master Gardener + - Master Herbalist + - Nanny + - Pizza Delivery + - Repairman + - Restaurant Critic + - Statue Busker + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim is a Service Sim. False, if not. + :rtype: CommonTestResult + """ + if sim_info is None: + raise AssertionError('Sim Info was None!') + from sims4communitylib.enums.traits_enum import CommonTraitId + from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils + trait_ids = ( + CommonTraitId.IS_BUTLER, + CommonTraitId.IS_CHALET_GARDENS_GHOST, + CommonTraitId.IS_CITY_REPAIR, + CommonTraitId.IS_FOREST_RANGER, + CommonTraitId.IS_GARDENER, + CommonTraitId.IS_GARDENER_SERVICE, + CommonTraitId.IS_GRIM_REAPER, + CommonTraitId.IS_MAID, + CommonTraitId.IS_MAILMAN, + CommonTraitId.IS_MASSAGE_THERAPIST, + CommonTraitId.IS_MASTER_FISHERMAN, + CommonTraitId.IS_MASTER_GARDENER, + CommonTraitId.IS_MASTER_HERBALIST, + CommonTraitId.IS_NANNY, + CommonTraitId.IS_PIZZA_DELIVERY, + CommonTraitId.IS_REPAIR, + CommonTraitId.IS_RESTAURANT_CRITIC, + CommonTraitId.IS_STATUE_BUSKER + ) + return CommonTraitUtils.has_any_traits(sim_info, trait_ids) + + @staticmethod + def is_batuu_alien(sim_info: SimInfo) -> CommonTestResult: + """Determine if a Sim is a Batuu Alien. + + .. note:: + + Alien Sims: + + - Bith + - Twilek + - Weequay + - Abednedo + - Mirialan + - Zabrak + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim is a Batuu Alien. False, if not. + :rtype: CommonTestResult + """ + if sim_info is None: + raise AssertionError('Sim Info was None!') + from sims4communitylib.enums.traits_enum import CommonTraitId + from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils + trait_ids = ( + CommonTraitId.BATUU_ALIEN_BITH, # trait_Batuu_Alien_Bith + CommonTraitId.BATUU_ALIEN_TWILEK, # trait_Batuu_Alien_Twilek + CommonTraitId.BATUU_ALIEN_WEEQUAY, # trait_Batuu_Alien_Weequay + CommonTraitId.BATUU_ALIEN_ABEDNEDO, # trait_Batuu_Alien_Abednedo + CommonTraitId.BATUU_ALIEN_MIRIALAN, # trait_Batuu_Alien_Mirialan + CommonTraitId.BATUU_ALIEN_ZABRAK, # trait_Batuu_Alien_Zabrak + ) + return CommonTraitUtils.has_any_traits(sim_info, trait_ids) + + @staticmethod + def is_occult(sim_info: SimInfo, combine_teen_young_adult_and_elder_age: bool = True, combine_child_dog_types: bool = True) -> bool: + """is_occult(sim_info, combine_teen_young_adult_and_elder_age=True, combine_child_dog_types=True) + + Determine if a Sim has an Occult Sim Type. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param combine_teen_young_adult_and_elder_age: See description of CommonSimTypeUtils.determine_sim_type. Default is True. + :type combine_teen_young_adult_and_elder_age: bool, optional + :param combine_child_dog_types: See description of CommonSimTypeUtils.determine_sim_type. Default is True. + :type combine_child_dog_types: bool, optional + :return: True, if the specified Sim has an Occult Sim Type. False, if not. + :rtype: bool + """ + if sim_info is None: + raise AssertionError('Sim Info was None!') + sim_type = CommonSimTypeUtils.determine_sim_type( + sim_info, + combine_teen_young_adult_and_elder_age=combine_teen_young_adult_and_elder_age, + combine_child_dog_types=combine_child_dog_types + ) + return CommonSimTypeUtils.is_occult_type(sim_type) + + @staticmethod + def is_occult_type(sim_type: CommonSimType) -> bool: + """is_occult_type(sim_type) + + Determine if a Sim Type is for an Occult Sim. + + :param sim_type: A Sim Type. + :type sim_type: CommonSimType + :return: True, if the Sim Type is for an Occult Sim. False, if not. + :rtype: bool + """ + # If the sim_type is an Occult, it will change to its Human variant, thus making them not equal and proving it was an occult. If the sim type is Human, it will not change. + return CommonSimTypeUtils.convert_to_non_occult_variant(sim_type) != sim_type + + @staticmethod + def get_all_sim_types_gen(sim_info: SimInfo, combine_teen_young_adult_and_elder_age: bool = True, combine_child_dog_types: bool = True) -> Iterator[CommonSimType]: + """get_all_sim_types_gen(sim_info, combine_teen_young_adult_and_elder_age=True, combine_child_dog_types=True) + + Determine all types a Sim is based on their Age, Species, and Occult Types. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param combine_teen_young_adult_and_elder_age: If set to True, Teen, Young Adult, Adult, and Elder, will all receive an ADULT denoted Sim Type instead of TEEN, YOUNG_ADULT, ADULT, and ELDER respectively. i.e. A Human Teen Sim would be denoted as ADULT_HUMAN. + If set to False, they will receive their own Sim Types. i.e. A Human Teen Sim would be denoted as TEEN_HUMAN. Default is True. + :type combine_teen_young_adult_and_elder_age: bool, optional + :param combine_child_dog_types: If set to True, the Child Dog Sim Types will be combined into a single Sim Type, i.e. CHILD_DOG. If set to False, the Child Dog Sim Types will be returned as their more specific values. i.e. CHILD_LARGE_DOG, CHILD_SMALL_DOG, etc. Default is True. + :type combine_child_dog_types: bool, optional + :return: An iterator of all types the Sim is. + :rtype: Iterator[CommonSimType] + """ + if sim_info is None: + raise AssertionError('Sim Info was None!') + species = CommonSpecies.get_species(sim_info) + age = CommonAge.get_age(sim_info) + from sims4communitylib.utils.sims.common_sim_occult_type_utils import CommonSimOccultTypeUtils + for occult_type in CommonSimOccultTypeUtils.get_all_occult_types_for_sim_gen(sim_info): + if CommonOccultUtils.is_robot(sim_info) and occult_type == CommonOccultType.NON_OCCULT: + continue + yield CommonSimTypeUtils.determine_sim_type_for_species_age_occult(species, age, occult_type, combine_teen_young_adult_and_elder_age=combine_teen_young_adult_and_elder_age, combine_child_dog_types=combine_child_dog_types) + + @staticmethod + def determine_sim_type( + sim_info: SimInfo, + combine_teen_young_adult_and_elder_age: bool = True, + combine_child_dog_types: bool = True, + use_current_occult_type: bool = False + ) -> CommonSimType: + """determine_sim_type(sim_info, combine_teen_young_adult_and_elder_age=True, combine_child_dog_types=True, use_current_occult_type=False) + + Determine the type of Sim a Sim is based on their Age, Species, and Occult Type. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param combine_teen_young_adult_and_elder_age: If set to True, Teen, Young Adult, Adult, and Elder, will all receive an ADULT denoted Sim Type instead of TEEN, YOUNG_ADULT, ADULT, and ELDER respectively. i.e. A Human Teen Sim would be denoted as ADULT_HUMAN. + If set to False, they will receive their own Sim Types. i.e. A Human Teen Sim would be denoted as TEEN_HUMAN. Default is True. + :type combine_teen_young_adult_and_elder_age: bool, optional + :param combine_child_dog_types: If set to True, the Child Dog Sim Types will be combined into a single Sim Type, i.e. CHILD_DOG. If set to False, the Child Dog Sim Types will be returned as their more specific values. i.e. CHILD_LARGE_DOG, CHILD_SMALL_DOG, etc. Default is True. + :type combine_child_dog_types: bool, optional + :param use_current_occult_type: If set to True, the Sims current occult type will be used, for example an Adult Human Mermaid with no tail would return ADULT_HUMAN instead of ADULT_HUMAN_MERMAID. If set to False, the Sims occult type will be used (whether current or not), for example an Adult Human Mermaid wearing or not wearing their tail would return ADULT_HUMAN_MERMAID. Default is False. + :param use_current_occult_type: bool, optional + :return: The type of Sim the Sim is or NONE if no type was found for the Sim. + :rtype: CommonSimType + """ + if sim_info is None: + raise AssertionError('Sim Info was None!') + species = CommonSpecies.get_species(sim_info) + age = CommonAge.get_age(sim_info) + if use_current_occult_type: + occult_type = CommonOccultType.determine_current_occult_type(sim_info) + else: + occult_type = CommonOccultType.determine_occult_type(sim_info) + sim_type = CommonSimTypeUtils.determine_sim_type_for_species_age_occult(species, age, occult_type, combine_teen_young_adult_and_elder_age=combine_teen_young_adult_and_elder_age, combine_child_dog_types=combine_child_dog_types) + return sim_type + + @staticmethod + def determine_sim_type_for_species_age_occult( + species: CommonSpecies, + age: CommonAge, + occult_type: CommonOccultType, + combine_teen_young_adult_and_elder_age: bool = True, + combine_child_dog_types: bool = True + ) -> CommonSimType: + """determine_sim_type_for_species_age_occult(\ + species,\ + age,\ + occult_type,\ + combine_teen_young_adult_and_elder_age=True,\ + combine_child_dog_types=True,\ + use_current_occult_type=False\ + ) + + Determine the type of Sim a Sim is based on their Age, Species, and Occult Type. + + :param species: A CommonSpecies. + :type species: CommonSpecies + :param age: An Age. + :type age: CommonAge + :param occult_type: An Occult Type. + :type occult_type: CommonOccultType + :param combine_teen_young_adult_and_elder_age: If set to True, Teen, Young Adult, Adult, and Elder, will all receive an ADULT denoted Sim Type instead of TEEN, YOUNG_ADULT, ADULT, and ELDER respectively. i.e. If True, a Human Teen Sim would be denoted as ADULT_HUMAN. + If set to False, they will receive their own Sim Types. i.e. If False, a Human Teen Sim would be denoted as TEEN_HUMAN. Default is True. + :type combine_teen_young_adult_and_elder_age: bool, optional + :param combine_child_dog_types: If set to True, the Child Dog Sim Types will be combined into a single Sim Type, i.e. CHILD_DOG. If set to False, the Child Dog Sim Types will be returned as their more specific values. i.e. CHILD_LARGE_DOG, CHILD_SMALL_DOG, etc. Default is True. + :type combine_child_dog_types: bool, optional + :return: The type of Sim the Sim is or CommonSimType.NONE if no type was found for the Sim. + :rtype: CommonSimType + """ + if age is None or species is None or occult_type is None: + return CommonSimType.NONE + + if combine_teen_young_adult_and_elder_age and age in (CommonAge.TEEN, CommonAge.YOUNGADULT, CommonAge.ADULT, CommonAge.ELDER): + age = CommonAge.ADULT + + if species not in CommonSimTypeUtils._SIM_TO_SIM_TYPE_MAPPING\ + or age not in CommonSimTypeUtils._SIM_TO_SIM_TYPE_MAPPING[species]\ + or occult_type not in CommonSimTypeUtils._SIM_TO_SIM_TYPE_MAPPING[species][age]: + return CommonSimType.NONE + + sim_type = CommonSimTypeUtils._SIM_TO_SIM_TYPE_MAPPING[species][age][occult_type] + if combine_child_dog_types and sim_type in CommonSimTypeUtils._CHILD_DOG_SIM_TYPE_MAPPING: + return CommonSimTypeUtils._CHILD_DOG_SIM_TYPE_MAPPING[sim_type] + return sim_type + + @staticmethod + def convert_sim_type_to_occult_type(sim_type: CommonSimType) -> CommonOccultType: + """convert_sim_type_to_occult_type(sim_type) + + Break down a Sim Type and return the resulting Occult Type associated with it. + + :param sim_type: A Sim Type. + :type sim_type: CommonSimType + :return: The occult type associated with the Sim Type. + :rtype: CommonOccultType + """ + return CommonSimTypeUtils._OCCULT_SIM_TYPE_TO_OCCULT_TYPE_MAPPING.get(sim_type, CommonOccultType.NONE) + + @staticmethod + def convert_sim_type_to_age(sim_type: CommonSimType) -> CommonAge: + """convert_sim_type_to_age(sim_type) + + Break down a Sim Type and return the resulting Age associated with it. + + :param sim_type: A Sim Type. + :type sim_type: CommonSimType + :return: The age associated with the Sim Type. + :rtype: CommonAge + """ + return CommonSimTypeUtils._OCCULT_SIM_TYPE_TO_AGE_MAPPING.get(sim_type, CommonAge.INVALID) + + @staticmethod + def convert_sim_type_to_species(sim_type: CommonSimType) -> CommonSpecies: + """convert_sim_type_to_species(sim_type) + + Break down a Sim Type and return the resulting Species associated with it. + + :param sim_type: A Sim Type. + :type sim_type: CommonSimType + :return: The species associated with the Sim Type. + :rtype: CommonSpecies + """ + return CommonSimTypeUtils._OCCULT_SIM_TYPE_TO_SPECIES_MAPPING.get(sim_type, CommonSpecies.INVALID) + + @staticmethod + def are_same_age_and_species(sim_type_one: CommonSimType, sim_type_two: CommonSimType) -> bool: + """are_same_age_and_species(sim_type_one, sim_type_two) + + Determine if two Sim Types are comprised of the same Age and Species. + + :param sim_type_one: An instance of a Sim Type. + :type sim_type_one: CommonSimType + :param sim_type_two: An instance of a Sim Type. + :type sim_type_two: CommonSimType + :return: True, if both Sim types are the same Age and Species, ignoring Occult Types. False, if not. + :rtype: bool + """ + if sim_type_one == sim_type_two: + return True + return CommonSimTypeUtils.convert_to_non_occult_variant(sim_type_one) == CommonSimTypeUtils.convert_to_non_occult_variant(sim_type_two) + + @staticmethod + def convert_to_signature(sim_type: CommonSimType) -> str: + """convert_to_signature(sim_type) + + Convert a Sim Type to a unique signature. + + :param sim_type: The sim type to convert. + :type sim_type: CommonSimType + :return: A string signature that uniquely represents the Sim Type or the name of the Sim Type, if no unique signature is found. + :rtype: str + """ + if sim_type not in CommonSimTypeUtils._SIM_TYPE_TO_SIGNATURE_MAPPING: + return sim_type.name + return CommonSimTypeUtils._SIM_TYPE_TO_SIGNATURE_MAPPING[sim_type] + + @staticmethod + def convert_to_non_occult_variant(sim_type: CommonSimType) -> CommonSimType: + """convert_sim_type_to_non_occult_variant(sim_type) + + Convert an Occult sim type to a Non-Occult Sim Type. + + :param sim_type: The Sim Type to convert. + :type sim_type: CommonSimType + :return: The Non-Occult variant of the Sim Type or itself, if no Non-Occult variant is found. + :rtype: CommonSimType + """ + if sim_type not in CommonSimTypeUtils._OCCULT_SIM_TYPE_TO_NON_OCCULT_SIM_TYPE_MAPPING: + return sim_type + return CommonSimTypeUtils._OCCULT_SIM_TYPE_TO_NON_OCCULT_SIM_TYPE_MAPPING[sim_type] + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.print_sim_types', + 'Print a list of all Sim Types a Sim matches to.', + command_arguments=( + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to check.', is_optional=True, default_value='Active Sim'), + CommonConsoleCommandArgument('combine_teen_young_adult_and_elder_age', 'True or False', 'If True, Teen, Young Adult, and Elder will come out with the same Sim Type as an Adult Sim would. (No effect on Sims that do not fall into these ages)', is_optional=True, default_value=False), + CommonConsoleCommandArgument('combine_child_dog_types', 'True or False', 'If True, Child Small Dog and Child Large Dog will come out as a singular Sim Type of Child Dog. (No effect on Sims that are not Child Dogs)', is_optional=True, default_value=False), + ), +) +def _common_print_sim_types_for_sim(output: CommonConsoleCommandOutput, sim_info: SimInfo = None, combine_teen_young_adult_and_elder_age: bool = False, combine_child_dog_types: bool = False): + if sim_info is None: + return + output(f'Printing all Sim Types of Sim {sim_info}:') + for sim_type in CommonSimTypeUtils.get_all_sim_types_gen(sim_info, combine_teen_young_adult_and_elder_age=combine_teen_young_adult_and_elder_age, combine_child_dog_types=combine_child_dog_types): + sim_type_name = sim_type.name + output(f'- {sim_type_name}') diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_unlock_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_unlock_utils.py new file mode 100644 index 0000000..a9c4b3c --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_unlock_utils.py @@ -0,0 +1,28 @@ +""" +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 +""" +from typing import Union +from sims.sim_info import SimInfo +from sims.unlock_tracker import UnlockTracker + + +class CommonSimUnlockUtils: + """Utilities for unlocks. """ + @classmethod + def get_unlock_tracker(cls, sim_info: SimInfo) -> Union[UnlockTracker, None]: + """get_unlock_tracker(sim_info) + + Retrieve tracker for unlocks for a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The tracker for unlocks for the Sim or None if not found. + :rtype: Union[UnlockTracker, None] + """ + if sim_info is None: + return None + return sim_info.unlock_tracker diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_utils.py new file mode 100644 index 0000000..8a0c3e0 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_utils.py @@ -0,0 +1,362 @@ +""" +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 +""" +import services +from typing import Iterator, Callable, Union + +from objects import HiddenReasonFlag, ALL_HIDDEN_REASONS +from sims.sim import Sim +from sims.sim_info import SimInfo +from sims.sim_info_base_wrapper import SimInfoBaseWrapper +from sims.sim_info_manager import SimInfoManager +from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + CommonConsoleCommandArgument +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from sims4communitylib.utils.misc.common_game_client_utils import CommonGameClientUtils + + +class CommonSimUtils: + """Utilities for retrieving Sims in different ways. + + .. note:: + + Available commands: + + - `s4clib_testing.display_name_of_currently_active_sim` + - `s4clib_testing.display_names_of_all_sims` + + """ + @classmethod + def get_active_sim(cls) -> Union[Sim, None]: + """get_active_sim() + + Retrieve a Sim object of the Currently Active Sim. + + .. note:: The Active Sim is the Sim with the Plumbob above their head. + + :return: An instance of the Active Sim or None if not found. + :rtype: Union[Sim, None] + """ + client = CommonGameClientUtils.get_first_game_client() + if client is None: + return None + return client.active_sim + + @classmethod + def get_active_sim_id(cls) -> int: + """get_active_sim_id() + + Retrieve the decimal identifier for the Currently Active Sim. + + .. note:: The Active Sim is the Sim with the Plumbob above their head. + + :return: The decimal identifier of the active Sim or -1 if the active Sim does not have an id or if no active Sim was found. + :rtype: int + """ + active_sim_info = cls.get_active_sim_info() + if active_sim_info is None: + return -1 + return cls.get_sim_id(active_sim_info) + + @classmethod + def get_active_sim_info(cls) -> Union[SimInfo, None]: + """get_active_sim_info() + + Retrieve a SimInfo object of the Currently Active Sim. + + :return: The SimInfo of the Active Sim or None if not found. + :rtype: Union[SimInfo, None] + """ + client = CommonGameClientUtils.get_first_game_client() + if client is None: + return None + # noinspection PyPropertyAccess + return client.active_sim_info + + @classmethod + def is_active_sim(cls, sim_info: SimInfo) -> bool: + """is_active_sim(sim_info) + + Determine if a Sim is the active Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: True, if the specified Sim is the active Sim. False, if not. + :rtype: bool + """ + return cls.get_active_sim_info() is sim_info + + @classmethod + def get_sim_info_of_sim_with_name(cls, first_name: str, last_name: str) -> Union[SimInfo, None]: + """get_sim_info_of_sim_with_name(first_name, last_name) + + Retrieve a SimInfo object for the first Sim with the specified First and Last Name. + + :param first_name: A first name to look for. + :type first_name: str + :param last_name: A last name to look for. + :type last_name: str + :return: The first Sim found with the specified first and last name or None if no Sim is found. + :rtype: Union[SimInfo, None] + """ + for sim_info in cls.get_sim_info_for_all_sims_with_name_generator(first_name, last_name): + return sim_info + return None + + @classmethod + def get_sim_info_for_all_sims_with_last_name_generator(cls, last_name: str) -> Iterator[SimInfo]: + """get_sim_info_for_all_sims_with_last_name_generator(last_name) + + Retrieve a SimInfo object for each and every Sim with the specified Last Name. + + :param last_name: A last name to look for. + :type last_name: str + :return: An iterator of Sims found with the specified last name. + :rtype: Iterator[SimInfo] + """ + from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils + last_name = last_name.lower() + + def _has_last_name(sim_info: SimInfo) -> bool: + return CommonSimNameUtils.get_last_name(sim_info).lower() == last_name + + return cls.get_sim_info_for_all_sims_generator(include_sim_callback=_has_last_name) + + @classmethod + def get_sim_info_for_all_sims_with_first_name_generator(cls, first_name: str) -> Iterator[SimInfo]: + """get_sim_info_for_all_sims_with_first_name_generator(first_name) + + Retrieve a SimInfo object for each and every Sim with the specified First Name. + + :param first_name: A first name to look for. + :type first_name: str + :return: An iterator of Sims found with the specified first name. + :rtype: Iterator[SimInfo] + """ + from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils + first_name = first_name.lower() + + def _has_first_name(sim_info: SimInfo) -> bool: + return CommonSimNameUtils.get_first_name(sim_info).lower() == first_name + + return cls.get_sim_info_for_all_sims_generator(include_sim_callback=_has_first_name) + + @classmethod + def get_sim_info_for_all_sims_with_name_generator(cls, first_name: str, last_name: str) -> Iterator[SimInfo]: + """get_sim_info_for_all_sims_with_name_generator(first_name, last_name) + + Retrieve a SimInfo object for each and every Sim with the specified First and Last Name. + + :param first_name: A first name to look for. + :type first_name: str + :param last_name: A last name to look for. + :type last_name: str + :return: An iterator of Sims found with the specified first and last name. + :rtype: Iterator[SimInfo] + """ + from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils + first_name = first_name.lower() + last_name = last_name.lower() + + def _has_first_and_last_name(sim_info: SimInfo) -> bool: + return CommonSimNameUtils.get_first_name(sim_info).lower() == first_name and CommonSimNameUtils.get_last_name(sim_info).lower() == last_name + + return cls.get_sim_info_for_all_sims_generator(include_sim_callback=_has_first_and_last_name) + + @classmethod + def get_all_sims_generator( + cls, + include_sim_callback: Callable[[SimInfo], Union[bool, CommonExecutionResult, CommonTestResult]] = None, + allow_hidden_flags: HiddenReasonFlag = ALL_HIDDEN_REASONS + ) -> Iterator[Sim]: + """get_all_sims_generator(include_sim_callback=None, allow_hidden_flags=ALL_HIDDEN_REASONS) + + Retrieve a Sim object for each and every Sim (including hidden Sims). + + :param include_sim_callback: If the result of this callback is True, the Sim will be included in the results. If set to None, All Sims will be included. + :type include_sim_callback: Callable[[SimInfo], bool], optional + :param allow_hidden_flags: Flags to indicate the types of hidden Sims to consider as being instanced. Default is ALL_HIDDEN_REASONS + :type allow_hidden_flags: HiddenReasonFlag, optional + :return: An iterator of all Sims matching the `include_sim_callback` filter. + :rtype: Iterator[Sim] + """ + for sim_info in cls.get_sim_info_for_all_sims_generator(include_sim_callback=include_sim_callback): + sim_instance = sim_info.get_sim_instance(allow_hidden_flags=allow_hidden_flags) + if sim_instance is None: + continue + yield sim_instance + + @classmethod + def get_sim_info_for_all_sims_generator( + cls, + include_sim_callback: Callable[[SimInfo], Union[bool, CommonExecutionResult, CommonTestResult]] = None + ) -> Iterator[SimInfo]: + """get_sim_info_for_all_sims_generator(include_sim_callback=None) + + Retrieve a SimInfo object for each and every Sim. + + :param include_sim_callback: If the result of this callback is True, the Sim will be included in the results. If set to None, All Sims will be included. + :type include_sim_callback: Callable[[SimInfo], bool], optional + :return: An iterator of all Sims matching the `include_sim_callback` filter. + :rtype: Iterator[SimInfo] + """ + sim_info_list = tuple(cls.get_sim_info_manager().get_all()) + for sim_info in sim_info_list: + if sim_info is None: + continue + if include_sim_callback is not None and not include_sim_callback(sim_info): + continue + yield sim_info + + @classmethod + def get_instanced_sim_info_for_all_sims_generator( + cls, + include_sim_callback: Callable[[SimInfo], Union[bool, CommonExecutionResult, CommonTestResult]] = None, + allow_hidden_flags: HiddenReasonFlag = ALL_HIDDEN_REASONS + ) -> Iterator[SimInfo]: + """get_instanced_sim_info_for_all_sims_generator(\ + include_sim_callback=None,\ + allow_hidden_flags=HiddenReasonFlag.NONE\ + ) + + Retrieve a SimInfo object for each and every Sim. + + .. note:: Only SimInfo with a Sim instance (:func:`~get_sim_instance`) will be returned. + + :param include_sim_callback: If the result of this callback is True, the Sim will be included in the results. If set to None, All Sims will be included. + :type include_sim_callback: Callable[[SimInfo], bool], optional + :param allow_hidden_flags: Flags to indicate the types of hidden Sims to consider as being instanced. Default is ALL_HIDDEN_REASONS + :type allow_hidden_flags: HiddenReasonFlag, optional + :return: An iterator of all Sims matching the `include_sim_callback` filter. + :rtype: Iterator[SimInfo] + """ + def _is_instanced(_sim_info: SimInfo) -> bool: + return _sim_info.get_sim_instance(allow_hidden_flags=allow_hidden_flags) is not None + + include_sim_callback = CommonFunctionUtils.run_predicates_as_one((_is_instanced, include_sim_callback)) + for sim_info in cls.get_sim_info_for_all_sims_generator(include_sim_callback=include_sim_callback): + yield sim_info + + @classmethod + def get_sim_id(cls, sim_identifier: Union[int, Sim, SimInfo, SimInfoBaseWrapper]) -> int: + """get_sim_id(sim_identifier) + + Retrieve a SimId (int) from a Sim identifier. + + :param sim_identifier: The identifier or instance of a Sim. + :type sim_identifier: Union[int, Sim, SimInfo, SimInfoBaseWrapper] + :return: The decimal identifier for the Sim instance or 0 if a problem occurs. + :rtype: int + """ + if sim_identifier is None: + return 0 + if isinstance(sim_identifier, int): + return sim_identifier + if isinstance(sim_identifier, Sim): + return sim_identifier.sim_id + if isinstance(sim_identifier, SimInfo): + return sim_identifier.id + if isinstance(sim_identifier, SimInfoBaseWrapper): + return sim_identifier.id + return 0 + + @classmethod + def get_sim_info( + cls, + sim_identifier: Union[int, Sim, SimInfo, SimInfoBaseWrapper] + ) -> Union[SimInfo, SimInfoBaseWrapper, None]: + """get_sim_info(sim_identifier) + + Retrieve a SimInfo instance from a Sim identifier. + + :param sim_identifier: The identifier or instance of a Sim to use. + :type sim_identifier: Union[int, Sim, SimInfo, SimInfoBaseWrapper] + :return: The SimInfo of the specified Sim instance or None if SimInfo is not found. + :rtype: Union[SimInfo, SimInfoBaseWrapper, None] + """ + if sim_identifier is None or isinstance(sim_identifier, SimInfo): + return sim_identifier + if isinstance(sim_identifier, SimInfoBaseWrapper): + return sim_identifier.get_sim_info() + if isinstance(sim_identifier, Sim): + return sim_identifier.sim_info + if isinstance(sim_identifier, int): + return cls.get_sim_info_manager().get(sim_identifier) + return sim_identifier + + @classmethod + def get_sim_instance( + cls, + sim_identifier: Union[int, Sim, SimInfo], + allow_hidden_flags: HiddenReasonFlag = ALL_HIDDEN_REASONS + ) -> Union[Sim, None]: + """get_sim_instance(sim_identifier, allow_hidden_flags=HiddenReasonFlag.NONE) + + Retrieve a Sim instance from a Sim identifier. + + :param sim_identifier: The identifier or instance of a Sim to use. + :type sim_identifier: Union[int, Sim, SimInfo] + :param allow_hidden_flags: Flags to indicate the types of hidden Sims to consider as being instanced. Default is ALL_HIDDEN_REASONS + :type allow_hidden_flags: HiddenReasonFlag, optional + :return: The instance of the specified Sim or None if no instance was found. + :rtype: Union[Sim, None] + """ + if sim_identifier is None or isinstance(sim_identifier, Sim): + return sim_identifier + if isinstance(sim_identifier, SimInfo): + return sim_identifier.get_sim_instance(allow_hidden_flags=allow_hidden_flags) + if isinstance(sim_identifier, int): + sim_info = cls.get_sim_info_manager().get(sim_identifier) + if sim_info is None: + return None + return cls.get_sim_instance(sim_info, allow_hidden_flags=allow_hidden_flags) + if isinstance(sim_identifier, SimInfoBaseWrapper): + return sim_identifier.get_sim_instance(allow_hidden_flags=allow_hidden_flags) + return sim_identifier + + @classmethod + def get_sim_info_manager(cls) -> SimInfoManager: + """get_sim_info_manager() + + Retrieve the manager that manages the Sim Info of all Sims in a game world. + + :return: The manager that manages the Sim Info of all Sims in a game world. + :rtype: SimInfoManager + """ + return services.sim_info_manager() + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_testing.print_name_of_sim', + 'Print the first and last name of a Sim.', + command_arguments=( + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance identifier of a Sim.', is_optional=True, default_value='Active Sim'), + ) +) +def _s4clib_testing_print_name_of_sim(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): + # noinspection PyPropertyAccess + output(f'First Name: {sim_info.first_name} Last Name: \'{sim_info.last_name}\'') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_testing.print_names_of_all_sims', + 'Print a list of the first and last names of all Sims.' +) +def _s4clib_testing_print_names_of_all_sims(output: CommonConsoleCommandOutput): + output('Printing the names of all Sims (This may take awhile).') + current_count = 1 + for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): + # noinspection PyPropertyAccess + output(f'{current_count}: First: \'{sim_info.first_name}\' Last: \'{sim_info.last_name}\'') + current_count += 1 + output('Done showing the names of all Sims.') diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_voice_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_voice_utils.py new file mode 100644 index 0000000..5efd458 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_voice_utils.py @@ -0,0 +1,462 @@ +""" +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 +""" +from typing import Union, Dict, List, Tuple +from sims.sim_info import SimInfo +from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.enums.common_age import CommonAge +from sims4communitylib.enums.common_gender import CommonGender +from sims4communitylib.enums.common_species import CommonSpecies +from sims4communitylib.enums.common_voice_actor_type import CommonVoiceActorType +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + CommonConsoleCommandArgument +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.common_log_registry import CommonLogRegistry +from sims4communitylib.utils.common_resource_utils import CommonResourceUtils +from sims4communitylib.utils.sims.common_sim_type_utils import CommonSimTypeUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + + +class CommonSimVoiceUtils: + """Utilities for manipulating the Voice of Sims. + + """ + + @staticmethod + def has_voice_actor(sim_info: SimInfo, voice_actor: Union[int, CommonVoiceActorType]) -> CommonTestResult: + """has_voice_actor(sim_info, voice_actor) + + Determine if a Sim has a specified voice actor. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param voice_actor: The voice actor to check. + :type voice_actor: Union[int, CommonVoiceActorType] + :return: The result of testing. True, if the Sim has the specified voice actor. False, if not. + :rtype: CommonTestResult + """ + if CommonSimVoiceUtils.get_voice_actor(sim_info): + return CommonTestResult.TRUE + voice_actor_str = voice_actor.name if hasattr(voice_actor, 'name') else str(voice_actor) + return CommonTestResult(False, reason=f'Sim did not have voice actor {voice_actor_str}') + + @staticmethod + def has_voice_pitch(sim_info: SimInfo, voice_pitch: float) -> CommonTestResult: + """has_voice_pitch(sim_info, voice_pitch) + + Determine if a Sim has a specified voice pitch. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param voice_pitch: The voice pitch to check. + :type voice_pitch: float + :return: The result of testing. True, if the Sim has the specified voice pitch. False, if not. + :rtype: CommonTestResult + """ + if CommonSimVoiceUtils.get_voice_pitch(sim_info) == voice_pitch: + return CommonTestResult.TRUE + return CommonTestResult(False, reason=f'Sim did not have voice pitch {voice_pitch}') + + @staticmethod + def get_voice_pitch(sim_info: SimInfo) -> float: + """get_voice_pitch(sim_info) + + Retrieve the Pitch of the Voice of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: A value that represents the pitch of the voice of a Sim. The value can range from -1.0 to 1.0 + :rtype: float + """ + # noinspection PyPropertyAccess + return sim_info.voice_pitch + + @staticmethod + def set_voice_pitch(sim_info: SimInfo, voice_pitch: float) -> CommonExecutionResult: + """set_voice_pitch(sim_info, voice_pitch) + + Set the Pitch of the Voice of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param voice_pitch: The value to set the voice pitch to, from -1.0 to 1.0. + :type voice_pitch: float + :return: The result of setting the voice pitch of the Sim. True, if successful. False, if not. + :rtype: CommonExecutionResult + """ + sim_info.voice_pitch = voice_pitch + return CommonExecutionResult.TRUE + + @staticmethod + def get_voice_actor(sim_info: SimInfo) -> Union[int, CommonVoiceActorType]: + """get_voice_actor(sim_info) + + Retrieve the Actor of the Voice of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: A value that represents the voice actor of a Sim. + :rtype: int + """ + # noinspection PyPropertyAccess + voice_actor = sim_info.voice_actor + if voice_actor not in CommonVoiceActorType.value_to_name: + return voice_actor + + return CommonResourceUtils.get_enum_by_name(CommonVoiceActorType.value_to_name[voice_actor].upper(), CommonVoiceActorType, default_value=voice_actor) + + @staticmethod + def set_voice_actor(sim_info: SimInfo, voice_actor: Union[int, CommonVoiceActorType]) -> CommonExecutionResult: + """set_voice_actor(sim_info, voice_actor) + + Set the Voice Actor of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param voice_actor: The voice actor to set the Sim to have. + :type voice_actor: Union[int, CommonVoiceActorType] + :return: The result of setting the voice actor. True, if successful. False, if not. + :rtype: CommonExecutionResult + """ + sim_info.voice_actor = int(voice_actor) + return CommonExecutionResult.TRUE + + @staticmethod + def set_to_default_voice(sim_info: SimInfo) -> CommonExecutionResult: + """set_to_default_voice(sim_info) + + Set the voice of a Sim to the default for their Age, Gender, and Species. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of setting the voice of the Sim to their default voice. True, if successful. False, if not. + :rtype: CommonExecutionResult + """ + from sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils + if CommonGenderUtils.is_male(sim_info): + return CommonSimVoiceUtils.set_to_default_male_voice(sim_info) + else: + return CommonSimVoiceUtils.set_to_default_female_voice(sim_info) + + @staticmethod + def set_to_default_male_voice(sim_info: SimInfo) -> CommonExecutionResult: + """set_to_default_male_voice(sim_info) + + Set the voice of a Sim to the default male voice for their Age and Species. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of setting the voice of the Sim to the default male voice. True, if successful. False, if not. + :rtype: CommonExecutionResult + """ + from sims4communitylib.utils.sims.common_age_species_utils import CommonAgeSpeciesUtils + from sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils + from sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils + if CommonAgeSpeciesUtils.is_teen_adult_or_elder_human(sim_info): + return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.ADULT_HUMAN_MASCULINE_1) + elif CommonAgeSpeciesUtils.is_child_human(sim_info): + return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.CHILD_HUMAN_AMBIGUOUS_1) + elif CommonAgeSpeciesUtils.is_toddler_human(sim_info): + return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.TODDLER_HUMAN_AMBIGUOUS_1) + elif CommonSpeciesUtils.is_large_dog(sim_info) and CommonAgeUtils.is_teen_adult_or_elder(sim_info): + return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.ADULT_DOG_AMBIGUOUS_1) + elif CommonSpeciesUtils.is_large_dog(sim_info) and CommonAgeUtils.is_child(sim_info): + return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.CHILD_DOG_AMBIGUOUS_1) + elif CommonSpeciesUtils.is_small_dog(sim_info) and CommonAgeUtils.is_teen_adult_or_elder(sim_info): + return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.ADULT_DOG_AMBIGUOUS_1) + elif CommonSpeciesUtils.is_small_dog(sim_info) and CommonAgeUtils.is_child(sim_info): + return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.CHILD_DOG_AMBIGUOUS_1) + elif CommonSpeciesUtils.is_cat(sim_info) and CommonAgeUtils.is_teen_adult_or_elder(sim_info): + return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.ADULT_CAT_AMBIGUOUS_1) + elif CommonSpeciesUtils.is_cat(sim_info) and CommonAgeUtils.is_child(sim_info): + return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.CHILD_CAT_AMBIGUOUS_1) + elif CommonSpeciesUtils.is_fox(sim_info) and CommonAgeUtils.is_teen_adult_or_elder(sim_info): + return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.ADULT_FOX_AMBIGUOUS_1) + elif CommonSpeciesUtils.is_horse(sim_info) and CommonAgeUtils.is_teen_adult_or_elder(sim_info): + return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.ADULT_HORSE_AMBIGUOUS_1) + elif CommonSpeciesUtils.is_horse(sim_info) and CommonAgeUtils.is_child(sim_info): + return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.CHILD_HORSE_AMBIGUOUS_1) + return CommonExecutionResult(False, reason=f'Failed to locate a default male voice actor for Sim {sim_info}') + + @staticmethod + def set_to_default_female_voice(sim_info: SimInfo) -> CommonExecutionResult: + """set_to_default_female_voice(sim_info) + + Set the voice of a Sim to the default female voice for their Age and Species. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The result of setting the voice of the Sim to the default female voice. True, if successful. False, if not. + :rtype: CommonExecutionResult + """ + from sims4communitylib.utils.sims.common_age_species_utils import CommonAgeSpeciesUtils + from sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils + from sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils + if CommonAgeSpeciesUtils.is_teen_adult_or_elder_human(sim_info): + return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.ADULT_HUMAN_FEMININE_1) + elif CommonAgeSpeciesUtils.is_child_human(sim_info): + return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.CHILD_HUMAN_AMBIGUOUS_1) + elif CommonAgeSpeciesUtils.is_toddler_human(sim_info): + return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.TODDLER_HUMAN_AMBIGUOUS_1) + elif CommonSpeciesUtils.is_large_dog(sim_info) and CommonAgeUtils.is_teen_adult_or_elder(sim_info): + return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.ADULT_DOG_AMBIGUOUS_1) + elif CommonSpeciesUtils.is_large_dog(sim_info) and CommonAgeUtils.is_child(sim_info): + return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.CHILD_DOG_AMBIGUOUS_1) + elif CommonSpeciesUtils.is_small_dog(sim_info) and CommonAgeUtils.is_teen_adult_or_elder(sim_info): + return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.ADULT_DOG_AMBIGUOUS_1) + elif CommonSpeciesUtils.is_small_dog(sim_info) and CommonAgeUtils.is_child(sim_info): + return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.CHILD_DOG_AMBIGUOUS_1) + elif CommonSpeciesUtils.is_cat(sim_info) and CommonAgeUtils.is_teen_adult_or_elder(sim_info): + return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.ADULT_CAT_AMBIGUOUS_1) + elif CommonSpeciesUtils.is_cat(sim_info) and CommonAgeUtils.is_child(sim_info): + return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.CHILD_CAT_AMBIGUOUS_1) + elif CommonSpeciesUtils.is_fox(sim_info) and CommonAgeUtils.is_teen_adult_or_elder(sim_info): + return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.ADULT_FOX_AMBIGUOUS_1) + elif CommonSpeciesUtils.is_horse(sim_info) and CommonAgeUtils.is_teen_adult_or_elder(sim_info): + return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.ADULT_HORSE_AMBIGUOUS_1) + elif CommonSpeciesUtils.is_horse(sim_info) and CommonAgeUtils.is_child(sim_info): + return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.CHILD_HORSE_AMBIGUOUS_1) + return CommonExecutionResult(False, reason=f'Failed to locate a default female voice actor for Sim {sim_info}') + + @staticmethod + def determine_available_voice_types(sim_info: SimInfo) -> Tuple[CommonVoiceActorType]: + """determine_available_voice_types(sim_info) + + Retrieve a collection of Voice Actor Types that are available for a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: A collection of voice actor types available for the Sim. + :rtype: Tuple[CommonVoiceActorType] + """ + from sims4communitylib.utils.sims.common_age_species_utils import CommonAgeSpeciesUtils + from sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils + from sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils + if CommonAgeSpeciesUtils.is_teen_adult_or_elder_human(sim_info): + # noinspection PyTypeChecker + result: Tuple[CommonVoiceActorType] = ( + CommonVoiceActorType.MUTE, + CommonVoiceActorType.ADULT_HUMAN_AMBIGUOUS_1, + CommonVoiceActorType.ADULT_HUMAN_FEMININE_1, + CommonVoiceActorType.ADULT_HUMAN_FEMININE_2, + CommonVoiceActorType.ADULT_HUMAN_MASCULINE_1, + CommonVoiceActorType.ADULT_HUMAN_MASCULINE_2, + CommonVoiceActorType.ADULT_HUMAN_MASCULINE_3, + CommonVoiceActorType.KYLO_REN_1, + CommonVoiceActorType.REY_1, + CommonVoiceActorType.HONDO_OHNAKA_1, + ) + elif CommonAgeSpeciesUtils.is_child_human(sim_info): + # noinspection PyTypeChecker + result: Tuple[CommonVoiceActorType] = ( + CommonVoiceActorType.MUTE, + CommonVoiceActorType.CHILD_HUMAN_AMBIGUOUS_1, + CommonVoiceActorType.CHILD_HUMAN_AMBIGUOUS_2, + CommonVoiceActorType.KYLO_REN_1, + CommonVoiceActorType.REY_1, + CommonVoiceActorType.HONDO_OHNAKA_1, + ) + elif CommonAgeSpeciesUtils.is_toddler_human(sim_info): + # noinspection PyTypeChecker + result: Tuple[CommonVoiceActorType] = ( + CommonVoiceActorType.MUTE, + CommonVoiceActorType.TODDLER_HUMAN_AMBIGUOUS_1, + ) + elif CommonSpeciesUtils.is_large_dog(sim_info) and CommonAgeUtils.is_teen_adult_or_elder(sim_info): + # noinspection PyTypeChecker + result: Tuple[CommonVoiceActorType] = ( + CommonVoiceActorType.MUTE, + CommonVoiceActorType.ADULT_DOG_AMBIGUOUS_1, + CommonVoiceActorType.ADULT_DOG_AMBIGUOUS_2, + CommonVoiceActorType.ADULT_DOG_AMBIGUOUS_3, + CommonVoiceActorType.ADULT_DOG_AMBIGUOUS_4 + ) + elif CommonSpeciesUtils.is_large_dog(sim_info) and CommonAgeUtils.is_child(sim_info): + # noinspection PyTypeChecker + result: Tuple[CommonVoiceActorType] = ( + CommonVoiceActorType.MUTE, + CommonVoiceActorType.CHILD_DOG_AMBIGUOUS_1, + ) + elif CommonSpeciesUtils.is_small_dog(sim_info) and CommonAgeUtils.is_teen_adult_or_elder(sim_info): + # noinspection PyTypeChecker + result: Tuple[CommonVoiceActorType] = ( + CommonVoiceActorType.MUTE, + CommonVoiceActorType.ADULT_DOG_AMBIGUOUS_1, + CommonVoiceActorType.ADULT_DOG_AMBIGUOUS_2, + CommonVoiceActorType.ADULT_DOG_AMBIGUOUS_3, + CommonVoiceActorType.ADULT_DOG_AMBIGUOUS_4 + ) + elif CommonSpeciesUtils.is_small_dog(sim_info) and CommonAgeUtils.is_child(sim_info): + # noinspection PyTypeChecker + result: Tuple[CommonVoiceActorType] = ( + CommonVoiceActorType.MUTE, + CommonVoiceActorType.CHILD_DOG_AMBIGUOUS_1, + ) + elif CommonSpeciesUtils.is_cat(sim_info) and CommonAgeUtils.is_teen_adult_or_elder(sim_info): + # noinspection PyTypeChecker + result: Tuple[CommonVoiceActorType] = ( + CommonVoiceActorType.MUTE, + CommonVoiceActorType.ADULT_CAT_AMBIGUOUS_1, + CommonVoiceActorType.ADULT_CAT_AMBIGUOUS_2, + ) + elif CommonSpeciesUtils.is_cat(sim_info) and CommonAgeUtils.is_child(sim_info): + # noinspection PyTypeChecker + result: Tuple[CommonVoiceActorType] = ( + CommonVoiceActorType.MUTE, + CommonVoiceActorType.CHILD_CAT_AMBIGUOUS_1, + ) + elif CommonSpeciesUtils.is_fox(sim_info) and CommonAgeUtils.is_teen_adult_or_elder(sim_info): + # noinspection PyTypeChecker + result: Tuple[CommonVoiceActorType] = ( + CommonVoiceActorType.MUTE, + CommonVoiceActorType.ADULT_FOX_AMBIGUOUS_1, + ) + elif CommonSpeciesUtils.is_horse(sim_info) and CommonAgeUtils.is_teen_adult_or_elder(sim_info): + # noinspection PyTypeChecker + result: Tuple[CommonVoiceActorType] = ( + CommonVoiceActorType.MUTE, + CommonVoiceActorType.ADULT_HORSE_AMBIGUOUS_1, + ) + elif CommonSpeciesUtils.is_horse(sim_info) and CommonAgeUtils.is_child(sim_info): + # noinspection PyTypeChecker + result: Tuple[CommonVoiceActorType] = ( + CommonVoiceActorType.MUTE, + CommonVoiceActorType.CHILD_HORSE_AMBIGUOUS_1, + ) + else: + result: Tuple[CommonVoiceActorType] = ( + CommonVoiceActorType.MUTE, + ) + return result + + +log = CommonLogRegistry().register_log(ModInfo.get_identity(), 'common_voice_actor_log') +log.enable() + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.print_voice', + 'Print information about the voice of a Sim.', + command_arguments=( + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to check.', is_optional=True, default_value='Active Sim'), + ), +) +def _common_print_voice_pitch(output: CommonConsoleCommandOutput, sim_info: SimInfo=None): + if sim_info is None: + return + voice_pitch = CommonSimVoiceUtils.get_voice_pitch(sim_info) + voice_actor = CommonSimVoiceUtils.get_voice_actor(sim_info) + voice_actor_name = voice_actor.name if hasattr(voice_actor, 'name') else voice_actor + log.debug(f'Voice info about {sim_info}') + log.debug(f'Voice Pitch: {voice_pitch}') + log.debug(f'Voice Actor: {voice_actor_name}') + output(f'Voice info about {sim_info}') + output(f'Voice Pitch: {voice_pitch}') + output(f'Voice Actor: {voice_actor_name}') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.set_voice_pitch', + 'Set the pitch of a Sims voice.', + command_arguments=( + CommonConsoleCommandArgument('voice_pitch', 'Decimal Identifier', 'The voice pitch to set the voice of the Sim to.'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to change.', is_optional=True, default_value='Active Sim'), + ) +) +def _common_set_voice_pitch(output: CommonConsoleCommandOutput, voice_pitch: float, sim_info: SimInfo=None): + if sim_info is None: + return + if voice_pitch is None: + return + result = CommonSimVoiceUtils.set_voice_pitch(sim_info, voice_pitch) + if result: + log.format_with_message('Set voice pitch', sim=sim_info, voice_pitch=voice_pitch, result=result) + output(f'SUCCESS: Successfully set the voice pitch of Sim {sim_info} to {voice_pitch}: {result}') + else: + log.format_with_message('Set voice pitch', sim=sim_info, voice_pitch=voice_pitch, result=result) + output(f'FAILED: Failed to set the voice pitch of Sim {sim_info} to {voice_pitch}: {result}') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.set_voice_actor', + 'Set the voice actor of a Sims voice.', + command_arguments=( + CommonConsoleCommandArgument('voice_actor', 'CommonVoiceActorType', f'The voice actor to change the Sim to. Valid Voice Actors: ({CommonVoiceActorType.get_comma_separated_names_string()})'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to change.', is_optional=True, default_value='Active Sim'), + ) +) +def _common_set_voice_actor(output: CommonConsoleCommandOutput, voice_actor: CommonVoiceActorType, sim_info: SimInfo=None): + if voice_actor is None: + return + if sim_info is None: + return + voice_actor_name = voice_actor.name + output(f'Attempting to set the voice actor of {sim_info} to {voice_actor_name}.') + result = CommonSimVoiceUtils.set_voice_actor(sim_info, voice_actor) + if result: + output(f'SUCCESS: Successfully set the voice actor of {sim_info} to {voice_actor_name}: {result}') + else: + output(f'FAILED: Failed to set the voice actor of {sim_info} to {voice_actor_name}: {result}') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.set_voice_actor_custom', + 'Set the voice actor of a Sims voice to a custom voice. NOTE: Success does not mean that it truly succeeded, much of the time the Sim will become Mute instead.', + command_arguments=( + CommonConsoleCommandArgument('voice_actor_id', 'int', 'The id of the voice actor to change the Sim to.'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to change.', is_optional=True, default_value='Active Sim'), + ) +) +def _common_set_voice_actor_custom(output: CommonConsoleCommandOutput, voice_actor_id: int, sim_info: SimInfo=None): + if voice_actor_id is None: + return + if sim_info is None: + return + output(f'Attempting to set the voice actor of {sim_info} to {voice_actor_id}.') + result = CommonSimVoiceUtils.set_voice_actor(sim_info, voice_actor_id) + if result: + output(f'SUCCESS: Successfully set the voice actor of {sim_info} to {voice_actor_id}: {result}') + else: + output(f'FAILED: Failed to set the voice actor of {sim_info} to {voice_actor_id}: {result}') + + +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_dev.print_all_voice_actors', + 'Print a list of all available Voice Actors (It entirely depends on all of the Sims available in the game though)', + show_with_help_command=False +) +def _common_get_all_voice_actors(output: CommonConsoleCommandOutput): + output('Printing all voice actors.') + sim_count = 0 + duplicate_count = 0 + voice_actor_by_age: Dict[(CommonAge, CommonSpecies, CommonGender), List[Union[int, CommonVoiceActorType]]] = dict() + for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): + sim_type = CommonSimTypeUtils.determine_sim_type(sim_info) + gender = CommonGender.get_gender(sim_info) + key = (sim_type.name, gender.name) + if key not in voice_actor_by_age: + voice_actor_by_age[key] = list() + voice_actor_list = voice_actor_by_age[key] + voice_actor = CommonSimVoiceUtils.get_voice_actor(sim_info) + sim_count += 1 + if voice_actor in voice_actor_list: + duplicate_count += 1 + continue + log.format_with_message('Adding voice actor from Sim', sim=sim_info, voice_actor=voice_actor.name if isinstance(voice_actor, CommonVoiceActorType) else voice_actor) + voice_actor_list.append(voice_actor) + voice_actor_by_age[key] = voice_actor_list + log.format_with_message('Voice Actor', voice_actors=voice_actor_by_age, sim_count=sim_count, duplicate_count=duplicate_count) + for (_key, _voice_actor) in voice_actor_by_age.items(): + voice_actor_name = _voice_actor.name if isinstance(_voice_actor, CommonVoiceActorType) else _voice_actor + output(f'Voice Actor {_key} = {voice_actor_name}') diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_walkstyle_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_walkstyle_utils.py new file mode 100644 index 0000000..4aaaeed --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_walkstyle_utils.py @@ -0,0 +1,62 @@ +""" +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 +""" +from typing import Union +from routing.walkstyle.walkstyle_tuning import Walkstyle +from sims.sim_info import SimInfo +from sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + + +class CommonSimWalkstyleUtils(_HasS4CLClassLog): + """Utilities for manipulating the Walkstyle of Sims. + + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 'common_sim_walkstyle_utils' + + @classmethod + def get_default_walkstyle(cls, sim_info: SimInfo) -> Union[Walkstyle, None]: + """get_default_walkstyle(sim_info) + + Retrieve the default walkstyle of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The default walkstyle of a Sim or None if the Sim is not available or has no default walk style. + :rtype: Union[Walkstyle, None] + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return None + return sim.routing_component.get_default_walkstyle() + + @classmethod + def get_current_walkstyle(cls, sim_info: SimInfo) -> Union[Walkstyle, None]: + """get_current_walkstyle(sim_info) + + Retrieve the current walkstyle of a Sim. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :return: The current walkstyle of the Sim or None when not found. + :rtype: Union[Walkstyle, None] + """ + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return None + routing_component = sim.routing_component + if routing_component is None: + return None + path = routing_component.current_path + if path: + return routing_component.get_walkstyle_for_path(routing_component.current_path) + + return cls.get_default_walkstyle(sim_info) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_species_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_species_utils.py new file mode 100644 index 0000000..2dc90df --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_species_utils.py @@ -0,0 +1,336 @@ +""" +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 +""" +from typing import Union + +from sims.sim_info import SimInfo +from sims.sim_info_types import Species, SpeciesExtended +from sims4communitylib.enums.traits_enum import CommonTraitId +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.utils.common_log_registry import CommonLogRegistry +from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils + +log = CommonLogRegistry.get().register_log(ModInfo.get_identity(), 'common_species_utils') + + +class CommonSpeciesUtils: + """Utilities for manipulating and checking the Species of Sims. + + """ + @classmethod + def get_species(cls, sim_info: SimInfo) -> Union[Species, SpeciesExtended, None]: + """get_species(sim_info) + + Retrieve the Species of a sim. + + :param sim_info: The Sim to get the Species of. + :type sim_info: SimInfo + :return: The Species of the Sim or None if the Sim does not have a Species. + :rtype: Union[Species, SpeciesExtended, None] + """ + if sim_info is None: + return None + if hasattr(sim_info, 'species'): + return sim_info.species + if hasattr(sim_info, 'sim_info') and hasattr(sim_info.sim_info, 'species'): + return sim_info.sim_info.species + return None + + @classmethod + def set_species(cls, sim_info: SimInfo, species: Union[Species, SpeciesExtended, int]) -> bool: + """set_species(sim_info, species) + + Set the Species of a sim. + + :param sim_info: The Sim to set the Species of. + :type sim_info: SimInfo + :param species: The Species to set the Sim to. + :type species: Union[Species, SpeciesExtended, int] + :return: True, if successful. False, if not. + :rtype: bool + """ + sim_info.species = species + return True + + @classmethod + def are_same_species(cls, sim_info: SimInfo, other_sim_info: SimInfo) -> bool: + """are_same_species(sim_info, other_sim_info) + + Determine if two sims are of the same species. + + .. note:: Extended Species are also compared (Large Dog, Small Dog, etc.) + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :param other_sim_info: The Sim to compare to. + :type other_sim_info: SimInfo + :return: True, if both Sims are the same species. False, if not. + :rtype: bool + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + if other_sim_info is None: + raise AssertionError('Argument other_sim_info was None') + from sims4communitylib.enums.common_species import CommonSpecies + species_one = CommonSpecies.get_species(sim_info) + species_two = CommonSpecies.get_species(other_sim_info) + log.format(species_one=species_one, species_two=species_two, sim_one=sim_info, other_sim_info=other_sim_info) + return species_one == species_two + + @classmethod + def is_human_species(cls, species: Union[Species, SpeciesExtended, int]) -> bool: + """is_human_species(species) + + Determine if a Species is a Human. + + :param species: The Species to check. + :type species: Union[Species, SpeciesExtended, int] + :return: True, if the Species is Human. False, if not. + :rtype: bool + """ + if not hasattr(Species, 'HUMAN'): + return False + return species == Species.HUMAN or species == SpeciesExtended.HUMAN + + @classmethod + def is_pet_species(cls, species: Union[Species, SpeciesExtended, int]) -> bool: + """is_pet_species(species) + + Determine if a Species is a Pet. + + :param species: The Species to check. + :type species: Union[Species, SpeciesExtended, int] + :return: True, if the Species is a Pet Species (Large Dog, Small Dog, Cat). False, if not. + :rtype: bool + """ + return cls.is_dog_species(species) or cls.is_cat_species(species) or cls.is_horse_species(species) + + @classmethod + def is_animal_species(cls, species: Union[Species, SpeciesExtended, int]) -> bool: + """is_animal_species(species) + + Determine if a Species is an Animal. + + :param species: The Species to check. + :type species: Union[Species, SpeciesExtended, int] + :return: True, if the Species is an Animal Species (Large Dog, Small Dog, Cat, or Fox). False, if not. + :rtype: bool + """ + return cls.is_pet_species(species) or cls.is_fox_species(species) + + @classmethod + def is_dog_species(cls, species: Union[Species, SpeciesExtended, int]) -> bool: + """is_dog_species(species) + + Determine if a Species is a Dog. + + :param species: The Species to check. + :type species: Union[Species, SpeciesExtended, int] + :return: True, if the Species is a Dog Species (Large Dog, Small Dog). False, if not. + :rtype: bool + """ + return cls.is_large_dog_species(species) or cls.is_small_dog_species(species) + + @classmethod + def is_large_dog_species(cls, species: Union[Species, SpeciesExtended, int]) -> bool: + """is_large_dog_species(species) + + Determine if a Species is a Large Dog. + + :param species: The Species to check. + :type species: Union[Species, SpeciesExtended, int] + :return: True, if the Species is a Large Dog Species. False, if not. + :rtype: bool + """ + if hasattr(Species, 'DOG'): + if species == Species.DOG or species == SpeciesExtended.DOG: + return True + return False + + @classmethod + def is_small_dog_species(cls, species: Union[Species, SpeciesExtended, int]) -> bool: + """is_small_dog_species(species) + + Determine if a Species is a Small Dog. + + :param species: The Species to check. + :type species: Union[Species, SpeciesExtended, int] + :return: True, if the Species is a Small Dog Species. False, if not. + :rtype: bool + """ + if hasattr(SpeciesExtended, 'SMALLDOG'): + if species == SpeciesExtended.SMALLDOG: + return True + return False + + @classmethod + def is_cat_species(cls, species: Union[Species, SpeciesExtended, int]) -> bool: + """is_cat_species(species) + + Determine if a Species is a Cat. + + :param species: The Species to check. + :type species: Union[Species, SpeciesExtended, int] + :return: True, if the Species is a Cat Species. False, if not. + :rtype: bool + """ + if not hasattr(Species, 'CAT'): + return False + return species == Species.CAT or species == SpeciesExtended.CAT + + @classmethod + def is_fox_species(cls, species: Union[Species, SpeciesExtended, int]) -> bool: + """is_fox_species(species) + + Determine if a Species is a Fox. + + :param species: The Species to check. + :type species: Union[Species, SpeciesExtended, int] + :return: True, if the Species is a Fox Species. False, if not. + :rtype: bool + """ + if not hasattr(Species, 'FOX'): + return False + return species == Species.FOX or species == SpeciesExtended.FOX + + @classmethod + def is_horse_species(cls, species: Union[Species, SpeciesExtended, int]) -> bool: + """is_horse_species(species) + + Determine if a Species is a Horse. + + :param species: The Species to check. + :type species: Union[Species, SpeciesExtended, int] + :return: True, if the Species is a Horse Species. False, if not. + :rtype: bool + """ + if not hasattr(Species, 'HORSE'): + return False + return species == Species.HORSE or species == SpeciesExtended.HORSE + + @classmethod + def is_dog(cls, sim_info: SimInfo) -> bool: + """is_dog(sim_info) + + Determine if a Sim is a Dog. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is a Dog (Large Dog, Small Dog). False, if not. + :rtype: bool + """ + return cls.is_dog_species(cls.get_species(sim_info)) + + @classmethod + def is_human(cls, sim_info: SimInfo) -> bool: + """is_human(sim_info) + + Determine if a Sim is a Human. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is a Human. False, if not. + :rtype: bool + """ + return cls.is_human_species(cls.get_species(sim_info)) + + @classmethod + def is_pet(cls, sim_info: SimInfo) -> bool: + """is_pet(sim_info) + + Determine if a Sim is a Pet. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is a Pet (Large Dog, Small Dog, Cat). False, if not. + :rtype: bool + """ + return cls.is_pet_species(cls.get_species(sim_info)) + + @classmethod + def is_animal(cls, sim_info: SimInfo) -> bool: + """is_animal(sim_info) + + Determine if a Sim is an Animal. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is an Animal (Large Dog, Small Dog, Cat, Fox). False, if not. + :rtype: bool + """ + return cls.is_animal_species(cls.get_species(sim_info)) + + @classmethod + def is_large_dog(cls, sim_info: SimInfo) -> bool: + """is_large_dog(sim_info) + + Determine if a Sim is a Large Dog. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is a Large Dog. False, if not. + :rtype: bool + """ + from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils + from sims4communitylib.enums.traits_enum import CommonTraitId + return cls.is_dog_species(cls.get_species(sim_info)) and CommonTraitUtils.has_trait(sim_info, CommonTraitId.SPECIES_EXTENDED_LARGE_DOGS) + + @classmethod + def is_small_dog(cls, sim_info: SimInfo) -> bool: + """is_small_dog(sim_info) + + Determine if a Sim is a Small Dog. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is a Small Dog. False, if not. + :rtype: bool + """ + from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils + from sims4communitylib.enums.traits_enum import CommonTraitId + return cls.is_dog_species(cls.get_species(sim_info)) and CommonTraitUtils.has_trait(sim_info, CommonTraitId.SPECIES_EXTENDED_SMALL_DOGS) + + @classmethod + def is_cat(cls, sim_info: SimInfo) -> bool: + """is_cat(sim_info) + + Determine if a Sim is a Cat. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is a Cat. False, if not. + :rtype: bool + """ + from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils + from sims4communitylib.enums.traits_enum import CommonTraitId + return cls.is_cat_species(cls.get_species(sim_info)) or CommonTraitUtils.has_trait(sim_info, CommonTraitId.SPECIES_CAT) + + @classmethod + def is_fox(cls, sim_info: SimInfo) -> bool: + """is_fox(sim_info) + + Determine if a Sim is a Fox. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is a Fox. False, if not. + :rtype: bool + """ + return cls.is_fox_species(cls.get_species(sim_info)) or CommonTraitUtils.has_trait(sim_info, CommonTraitId.SPECIES_FOX) + + @classmethod + def is_horse(cls, sim_info: SimInfo) -> bool: + """is_horse(sim_info) + + Determine if a Sim is a Horse. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: True, if the Sim is a Horse. False, if not. + :rtype: bool + """ + return cls.is_horse_species(cls.get_species(sim_info)) or CommonTraitUtils.has_trait(sim_info, CommonTraitId.SPECIES_HORSE) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_trait_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_trait_utils.py new file mode 100644 index 0000000..a73b593 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_trait_utils.py @@ -0,0 +1,1655 @@ +""" +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 +""" +from typing import List, Union, Callable, Iterator, Tuple + +from distributor.shared_messages import IconInfoData +from relationships.relationship_tracker import RelationshipTracker +from relationships.sim_knowledge import SimKnowledge +from server_commands.argument_helpers import TunableInstanceParam +from sims.pregnancy.pregnancy_offspring_data import PregnancyOffspringData +from sims.sim_info import SimInfo +from sims.sim_info_base_wrapper import SimInfoBaseWrapper +from sims4.resources import Types +from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from sims4communitylib.enums.traits_enum import CommonTraitId +from sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification +from sims4communitylib.services.commands.common_console_command import CommonConsoleCommandArgument, \ + CommonConsoleCommand +from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from traits.traits import Trait + + +class CommonTraitUtils(_HasS4CLClassLog): + """Utilities for manipulating Traits on Sims. + + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 'common_trait_utils' + + @classmethod + def is_player(cls, sim_info: SimInfo) -> CommonTestResult: + """is_player(sim_info) + + Determine if a Sim has the Player trait. + + .. note:: This does not indicate whether the Sim is one of the Players Sims, it simply indicates if they have the trait that makes other Sims less jealous. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + return cls.has_trait(sim_info, CommonTraitId.PLAYER) + + @classmethod + def is_special_npc(cls, sim_info: SimInfo) -> CommonTestResult: + """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: The result of testing. True, if the Sim is a special NPC. False, if the Sim is not a Special NPC. + :rtype: CommonTestResult + """ + traits = ( + CommonTraitId.HIDDEN_IS_EVENT_NPC_CHALLENGE, + CommonTraitId.IS_GRIM_REAPER, + CommonTraitId.SCARECROW, + CommonTraitId.FLOWER_BUNNY + ) + return cls.has_any_traits(sim_info, traits) + + @classmethod + def is_active(cls, sim_info: SimInfo) -> CommonTestResult: + """is_active(sim_info) + + Determine if a Sim is active. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + return cls.has_trait(sim_info, CommonTraitId.ACTIVE) + + @classmethod + def is_aggressive_pet(cls, sim_info: SimInfo) -> CommonTestResult: + """is_aggressive_pet(sim_info) + + Determine if a pet Sim is Aggressive. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + traits = ( + CommonTraitId.PET_AGGRESSIVE_DOG, + CommonTraitId.PET_AGGRESSIVE_CAT + ) + return cls.has_any_traits(sim_info, traits) + + @classmethod + def is_alluring(cls, sim_info: SimInfo) -> CommonTestResult: + """is_alluring(sim_info) + + Determine if a Sim is Alluring. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + return cls.has_trait(sim_info, CommonTraitId.ALLURING) + + @classmethod + def is_antiseptic(cls, sim_info: SimInfo) -> CommonTestResult: + """is_antiseptic(sim_info) + + Determine if a Sim is Antiseptic. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + return cls.has_trait(sim_info, CommonTraitId.ANTISEPTIC) + + @classmethod + def is_bro(cls, sim_info: SimInfo) -> CommonTestResult: + """is_bro(sim_info) + + Determine if a Sim is a Bro. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + return cls.has_trait(sim_info, CommonTraitId.BRO) + + @classmethod + def is_carefree(cls, sim_info: SimInfo) -> CommonTestResult: + """is_carefree(sim_info) + + Determine if a Sim is Care Free. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + return cls.has_trait(sim_info, CommonTraitId.CAREFREE) + + @classmethod + def is_cat_lover(cls, sim_info: SimInfo) -> CommonTestResult: + """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: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + return cls.has_trait(sim_info, CommonTraitId.CAT_LOVER) + + @classmethod + def is_dog_lover(cls, sim_info: SimInfo) -> CommonTestResult: + """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: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + return cls.has_trait(sim_info, CommonTraitId.DOG_LOVER) + + @classmethod + def is_clumsy(cls, sim_info: SimInfo) -> CommonTestResult: + """is_clumsy(sim_info) + + Determine if a Sim is Clumsy. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + return cls.has_trait(sim_info, CommonTraitId.CLUMSY) + + @classmethod + def is_dastardly(cls, sim_info: SimInfo) -> CommonTestResult: + """is_dastardly(sim_info) + + Determine if a Sim is Dastardly. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + return cls.has_trait(sim_info, CommonTraitId.DASTARDLY) + + @classmethod + def is_criminal(cls, sim_info: SimInfo) -> CommonTestResult: + """is_criminal(sim_info) + + Determine if a Sim is a Criminal. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + traits = ( + CommonTraitId.DETECTIVE_CAREER_CRIMINAL, + CommonTraitId.DETECTIVE_CAREER_POLICE_STATION_CRIMINAL_NPC + ) + return cls.has_any_traits(sim_info, traits) + + @classmethod + def is_evil(cls, sim_info: SimInfo) -> CommonTestResult: + """is_evil(sim_info) + + Determine if a Sim is Evil. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + traits = ( + CommonTraitId.EVIL, + CommonTraitId.EVIL_BEGONIA_SCENT + ) + return cls.has_any_traits(sim_info, traits) + + @classmethod + def is_fertile(cls, sim_info: SimInfo) -> CommonTestResult: + """is_fertile(sim_info) + + Determine if a Sim is Fertile. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + return cls.has_trait(sim_info, CommonTraitId.FERTILE) + + @classmethod + def is_friendly_pet(cls, sim_info: SimInfo) -> CommonTestResult: + """is_friendly_pet(sim_info) + + Determine if a pet Sim is Friendly. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + traits = ( + CommonTraitId.PET_FRIENDLY_DOG, + CommonTraitId.PET_FRIENDLY_CAT + ) + return cls.has_any_traits(sim_info, traits) + + @classmethod + def is_geek(cls, sim_info: SimInfo) -> CommonTestResult: + """is_geek(sim_info) + + Determine if a Sim is a geek. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + return cls.has_trait(sim_info, CommonTraitId.GEEK) + + @classmethod + def is_genius(cls, sim_info: SimInfo) -> CommonTestResult: + """is_genius(sim_info) + + Determine if a Sim is a Genius. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + return cls.has_trait(sim_info, CommonTraitId.GENIUS) + + @classmethod + def is_good(cls, sim_info: SimInfo) -> CommonTestResult: + """is_good(sim_info) + + Determine if a Sim is Good. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + return cls.has_trait(sim_info, CommonTraitId.GOOD) + + @classmethod + def is_glutton(cls, sim_info: SimInfo) -> CommonTestResult: + """is_glutton(sim_info) + + Determine if a Sim is a Glutton. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + return cls.is_glutton_human(sim_info) or cls.is_glutton_pet(sim_info) + + @classmethod + def is_glutton_human(cls, sim_info: SimInfo) -> CommonTestResult: + """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: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + return cls.has_trait(sim_info, CommonTraitId.GLUTTON) + + @classmethod + def is_glutton_pet(cls, sim_info: SimInfo) -> CommonTestResult: + """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: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + traits = ( + CommonTraitId.PET_GLUTTON_DOG, + CommonTraitId.PET_GLUTTON_CAT + ) + return cls.has_any_traits(sim_info, traits) + + @classmethod + def is_gregarious(cls, sim_info: SimInfo) -> CommonTestResult: + """is_gregarious(sim_info) + + Determine if a Sim is Gregarious. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + return cls.has_trait(sim_info, CommonTraitId.GREGARIOUS) + + @classmethod + def is_hot_headed(cls, sim_info: SimInfo) -> CommonTestResult: + """is_hot_headed(sim_info) + + Determine if a Sim is Hot Headed. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + return cls.has_trait(sim_info, CommonTraitId.HOT_HEADED) + + @classmethod + def is_hunter_pet(cls, sim_info: SimInfo) -> CommonTestResult: + """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: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + traits = ( + CommonTraitId.PET_HUNTER_DOG, + CommonTraitId.PET_HUNTER_CAT + ) + return cls.has_any_traits(sim_info, traits) + + @classmethod + def is_incredibly_friendly(cls, sim_info: SimInfo) -> CommonTestResult: + """is_incredibly_friendly(sim_info) + + Determine if a Sim is Incredibly Friendly. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + return cls.has_trait(sim_info, CommonTraitId.INCREDIBLY_FRIENDLY) + + @classmethod + def is_insane(cls, sim_info: SimInfo) -> CommonTestResult: + """is_insane(sim_info) + + Determine if a Sim is Insane. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + return cls.has_trait(sim_info, CommonTraitId.INSANE) + + @classmethod + def is_insider(cls, sim_info: SimInfo) -> CommonTestResult: + """is_insider(sim_info) + + Determine if a Sim is an Insider. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + return cls.has_trait(sim_info, CommonTraitId.INSIDER) + + @classmethod + def is_loyal_pet(cls, sim_info: SimInfo) -> CommonTestResult: + """is_loyal_pet(sim_info) + + Determine if a pet Sim is Loyal. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + traits = ( + CommonTraitId.PET_LOYAL_DOG, + CommonTraitId.PET_LOYAL_CAT + ) + return cls.has_any_traits(sim_info, traits) + + @classmethod + def is_mean(cls, sim_info: SimInfo) -> CommonTestResult: + """is_mean(sim_info) + + Determine if a Sim is Mean. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + return cls.has_trait(sim_info, CommonTraitId.MEAN) + + @classmethod + def is_mentor(cls, sim_info: SimInfo) -> CommonTestResult: + """is_mentor(sim_info) + + Determine if a Sim is a Mentor. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + return cls.has_trait(sim_info, CommonTraitId.MENTOR) + + @classmethod + def is_morning_person(cls, sim_info: SimInfo) -> CommonTestResult: + """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: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + return cls.has_trait(sim_info, CommonTraitId.MORNING_PERSON) + + @classmethod + def is_naughty_pet(cls, sim_info: SimInfo) -> CommonTestResult: + """is_naughty_pet(sim_info) + + Determine if a pet Sim is Naughty. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + traits = ( + CommonTraitId.PET_NAUGHTY_DOG, + CommonTraitId.PET_NAUGHTY_CAT + ) + return cls.has_any_traits(sim_info, traits) + + @classmethod + def is_neat(cls, sim_info: SimInfo) -> CommonTestResult: + """is_neat(sim_info) + + Determine if a Sim is neat. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + return cls.has_trait(sim_info, CommonTraitId.NEAT) + + @classmethod + def is_night_owl(cls, sim_info: SimInfo) -> CommonTestResult: + """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: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + traits = ( + CommonTraitId.NIGHT_OWL, + CommonTraitId.NIGHT_OWL_CRYSTAL_HELMET + ) + return cls.has_any_traits(sim_info, traits) + + @classmethod + def is_lazy(cls, sim_info: SimInfo) -> CommonTestResult: + """is_lazy(sim_info) + + Determine if a Sim is Lazy. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + return cls.has_trait(sim_info, CommonTraitId.LAZY) + + @classmethod + def is_loner(cls, sim_info: SimInfo) -> CommonTestResult: + """is_loner(sim_info) + + Determine if a Sim is a Loner. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + return cls.has_trait(sim_info, CommonTraitId.LONER) + + @classmethod + def is_love_guru(cls, sim_info: SimInfo) -> CommonTestResult: + """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: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + return cls.has_trait(sim_info, CommonTraitId.LOVE_GURU) + + @classmethod + def is_self_absorbed(cls, sim_info: SimInfo) -> CommonTestResult: + """is_self_absorbed(sim_info) + + Determine if a Sim is Self Absorbed. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + return cls.has_trait(sim_info, CommonTraitId.SELF_ABSORBED) + + @classmethod + def is_self_assured(cls, sim_info: SimInfo) -> CommonTestResult: + """is_self_assured(sim_info) + + Determine if a Sim is Self Assured. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + return cls.has_trait(sim_info, CommonTraitId.SELF_ASSURED) + + @classmethod + def is_service_sim(cls, sim_info: SimInfo) -> CommonTestResult: + """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) + + @classmethod + def is_shameless(cls, sim_info: SimInfo) -> CommonTestResult: + """is_shameless(sim_info) + + Determine if a Sim is Shameless. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + return cls.has_trait(sim_info, CommonTraitId.SHAMELESS) + + @classmethod + def is_sincere(cls, sim_info: SimInfo) -> CommonTestResult: + """is_sincere(sim_info) + + Determine if a Sim is Sincere. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + return cls.has_trait(sim_info, CommonTraitId.SINCERE) + + @classmethod + def is_skittish_pet(cls, sim_info: SimInfo) -> CommonTestResult: + """is_skittish_pet(sim_info) + + Determine if a pet Sim is Skittish. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + traits = ( + CommonTraitId.PET_SKITTISH_DOG, + CommonTraitId.PET_SKITTISH_CAT + ) + return cls.has_any_traits(sim_info, traits) + + @classmethod + def is_slob(cls, sim_info: SimInfo) -> CommonTestResult: + """is_slob(sim_info) + + Determine if a Sim is a Slob. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + return cls.has_trait(sim_info, CommonTraitId.SLOB) + + @classmethod + def is_snob(cls, sim_info: SimInfo) -> CommonTestResult: + """is_snob(sim_info) + + Determine if a Sim is a Snob. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + return cls.has_trait(sim_info, CommonTraitId.SNOB) + + @classmethod + def is_squeamish(cls, sim_info: SimInfo) -> CommonTestResult: + """is_squeamish(sim_info) + + Determine if a Sim is Squeamish. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + return cls.has_trait(sim_info, CommonTraitId.SQUEAMISH) + + @classmethod + def is_survivalist(cls, sim_info: SimInfo) -> CommonTestResult: + """is_survivalist(sim_info) + + Determine if a Sim is a Survivalist. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + return cls.has_trait(sim_info, CommonTraitId.SURVIVALIST) + + @classmethod + def is_unflirty(cls, sim_info: SimInfo) -> CommonTestResult: + """is_unflirty(sim_info) + + Determine if a Sim is Unflirty. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. + :rtype: CommonTestResult + """ + return cls.has_trait(sim_info, CommonTraitId.UNFLIRTY) + + @classmethod + def hates_children(cls, sim_info: SimInfo) -> CommonTestResult: + """hates_children(sim_info) + + Determine if a Sim Hates Children. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim has the Hates Children trait. False, if not. + :rtype: CommonTestResult + """ + return cls.has_trait(sim_info, CommonTraitId.HATES_CHILDREN) + + @classmethod + def has_animal_attraction(cls, sim_info: SimInfo) -> CommonTestResult: + """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: The result of testing. True, if the Sim has the Trait. False, if not. + :rtype: CommonTestResult + """ + return cls.has_trait(sim_info, CommonTraitId.ANIMAL_ATTRACTION) + + @classmethod + def has_animal_whisperer(cls, sim_info: SimInfo) -> CommonTestResult: + """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: The result of testing. True, if the Sim has the Trait. False, if not. + :rtype: CommonTestResult + """ + return cls.has_trait(sim_info, CommonTraitId.ANIMAL_WHISPERER) + + @classmethod + def has_challenge_kindness_ambassador(cls, sim_info: SimInfo) -> CommonTestResult: + """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: The result of testing. True, if the Sim has challenged the kindness ambassador. False, if not. + :rtype: CommonTestResult + """ + return cls.has_trait(sim_info, CommonTraitId.CHALLENGE_KINDNESS_AMBASSADOR) + + @classmethod + def has_commitment_issues(cls, sim_info: SimInfo) -> CommonTestResult: + """has_commitment_issues(sim_info) + + Determine if a Sim has Commitment Issues. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim has the Trait. False, if not. + :rtype: CommonTestResult + """ + return cls.has_trait(sim_info, CommonTraitId.COMMITMENT_ISSUES) + + @classmethod + def has_masculine_frame(cls, sim_info: SimInfo) -> CommonTestResult: + """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: The result of testing. True, if the Sim has a masculine frame. False, if not. + :rtype: CommonTestResult + """ + from sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils + return CommonSimGenderOptionUtils.has_masculine_frame(sim_info) + + @classmethod + def has_feminine_frame(cls, sim_info: SimInfo) -> CommonTestResult: + """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: The result of testing. True, if the Sim has a feminine frame. False, if not. + :rtype: CommonTestResult + """ + from sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils + return CommonSimGenderOptionUtils.has_feminine_frame(sim_info) + + @classmethod + def prefers_menswear(cls, sim_info: SimInfo) -> CommonTestResult: + """prefers_menswear(sim_info) + + Determine if a Sim prefers Mens Clothing. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim prefers menswear. False, if not. + :rtype: CommonTestResult + """ + from sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils + return CommonSimGenderOptionUtils.prefers_menswear(sim_info) + + @classmethod + def prefers_womenswear(cls, sim_info: SimInfo) -> CommonTestResult: + """prefers_womenswear(sim_info) + + Determine if a Sim prefers Womens Clothing. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim prefers womenswear. False, if not. + :rtype: CommonTestResult + """ + from sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils + return CommonSimGenderOptionUtils.prefers_womenswear(sim_info) + + @classmethod + def can_impregnate(cls, sim_info: SimInfo) -> CommonTestResult: + """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: The result of testing. True, if the Sim can impregnate other Sims. False, if not. + :rtype: CommonTestResult + """ + from sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils + return CommonSimGenderOptionUtils.can_impregnate(sim_info) + + @classmethod + def can_not_impregnate(cls, sim_info: SimInfo) -> CommonTestResult: + """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: The result of testing. True, if the Sim can not impregnate other Sims. False, if not. + :rtype: CommonTestResult + """ + from sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils + return CommonSimGenderOptionUtils.can_not_impregnate(sim_info) + + @classmethod + def can_be_impregnated(cls, sim_info: SimInfo) -> CommonTestResult: + """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: The result of testing. True, if the Sim can be impregnated. False, if not. + :rtype: CommonTestResult + """ + from sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils + return CommonSimGenderOptionUtils.can_be_impregnated(sim_info) + + @classmethod + def can_not_be_impregnated(cls, sim_info: SimInfo) -> CommonTestResult: + """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: The result of testing. True, if the Sim can not be impregnated. False, if not. + :rtype: CommonTestResult + """ + from sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils + return CommonSimGenderOptionUtils.can_not_be_impregnated(sim_info) + + @classmethod + def can_create_pregnancy(cls, sim_info: SimInfo) -> CommonTestResult: + """can_create_pregnancy(sim_info) + + Determine if a Sim can either impregnate, be impregnated, or can reproduce. + + .. note:: Will return False if the Sim can both impregnate and not impregnate,\ + if the Sim can both be impregnated and not be impregnated\ + or if the Sim can both reproduce and not reproduce. + + .. note:: A Sim can impregnate when they can either impregnate other Sims, can be impregnated by other Sims, or if they are a Pet, can reproduce. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :return: The result of testing. True, if the Sim can create pregnancies. False, if not. + :rtype: CommonTestResult + """ + from sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils + return CommonSimGenderOptionUtils.can_create_pregnancy(sim_info) + + @classmethod + def can_reproduce(cls, sim_info: SimInfo) -> CommonTestResult: + """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: The result of testing. True, if the Sim can reproduce. False, if not. + :rtype: CommonTestResult + """ + from sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils + return CommonSimGenderOptionUtils.can_reproduce(sim_info) + + @classmethod + def can_not_reproduce(cls, sim_info: SimInfo) -> CommonTestResult: + """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: The result of testing. True, if the Sim can not reproduce. False, if not. + :rtype: CommonTestResult + """ + from sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils + return CommonSimGenderOptionUtils.can_not_reproduce(sim_info) + + @classmethod + def uses_toilet_standing(cls, sim_info: SimInfo) -> CommonTestResult: + """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: The result of testing. True, if the Sim uses toilets while standing. False, if not. + :rtype: CommonTestResult + """ + from sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils + return CommonSimGenderOptionUtils.uses_toilet_standing(sim_info) + + @classmethod + def uses_toilet_sitting(cls, sim_info: SimInfo) -> CommonTestResult: + """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: The result of testing. True, if the Sim uses toilets while sitting. False, if not. + :rtype: CommonTestResult + """ + from sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils + return CommonSimGenderOptionUtils.uses_toilet_sitting(sim_info) + + @classmethod + def is_ghost_trait(cls, trait_identifier: Union[int, CommonTraitId, Trait]) -> bool: + """is_ghost_trait(trait_identifier) + + Determine if a trait is a Ghost trait. + + :param trait_identifier: An identifier of a trait. + :type trait_identifier: Union[int, CommonTraitId, Trait] + :return: True, if the specified trait is a ghost trait. False, if not. + """ + trait = cls.load_trait_by_id(trait_identifier) + if trait is None: + return False + return getattr(trait, 'is_ghost_trait', None) is True + + @classmethod + def has_trait(cls, sim_info: SimInfo, *trait: Union[int, CommonTraitId, Trait]) -> CommonTestResult: + """has_trait(sim_info, trait) + + Determine if a Sim has a Trait. + + :param sim_info: The Sim to check. + :type sim_info: SimInfo + :param trait: The trait to check for. + :type trait: Union[int, CommonTraitId, Trait] + :return: The result of testing. True, if the Sim has the specified trait. False, if not. + :rtype: CommonTestResult + """ + if isinstance(sim_info, SimInfo): + for _trait in trait: + __trait = cls.load_trait_by_id(_trait) + if __trait is None: + continue + if sim_info.has_trait(__trait): + return CommonTestResult(True, reason=f'{sim_info} has trait {__trait}.') + elif isinstance(sim_info, SimInfoBaseWrapper): + sim_info: SimInfoBaseWrapper = sim_info + any_traits = cls.get_trait_ids(sim_info) + if not any_traits: + return CommonTestResult(False, reason=f'{sim_info} does not have any traits.') + for _trait in trait: + __trait = cls.get_trait_id(_trait) + if __trait is None: + continue + if _trait in any_traits: + return CommonTestResult(True, reason=f'{sim_info} has trait {__trait}.') + elif isinstance(sim_info, PregnancyOffspringData): + sim_info: PregnancyOffspringData = sim_info + any_traits = [cls.get_trait_id(trait) for trait in sim_info.traits] + if not any_traits: + return CommonTestResult(False, reason=f'{sim_info} does not have any traits.') + for _trait in trait: + __trait = cls.get_trait_id(_trait) + if __trait is None: + continue + if _trait in any_traits: + return CommonTestResult(True, reason=f'{sim_info} has trait {__trait}.') + return CommonTestResult(False, reason=f'{sim_info} does not have trait(s) {trait}') + + @classmethod + def has_any_traits(cls, sim_info: SimInfo, traits: Iterator[Union[int, CommonTraitId, Trait]]) -> CommonTestResult: + """has_any_traits(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 traits: An iterator of identifiers of Traits. + :type traits: Iterator[Union[int, CommonTraitId, Trait]] + :return: The result of testing. True, if the Sim has any of the specified traits. False, if not. + :rtype: CommonTestResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + if not traits: + return CommonTestResult(False, reason='No traits were specified.') + if isinstance(sim_info, SimInfo): + for trait in traits: + _trait = cls.load_trait_by_id(trait) + if _trait is None: + continue + if sim_info.has_trait(_trait): + return CommonTestResult(True, reason=f'{sim_info} has trait {_trait}.') + elif isinstance(sim_info, SimInfoBaseWrapper): + sim_info: SimInfoBaseWrapper = sim_info + any_traits = cls.get_trait_ids(sim_info) + if not any_traits: + return CommonTestResult(False, reason=f'{sim_info} does not have any traits.') + for _trait in traits: + __trait = cls.get_trait_id(_trait) + if __trait is None: + continue + if _trait in any_traits: + return CommonTestResult(True, reason=f'{sim_info} has trait {__trait}.') + elif isinstance(sim_info, PregnancyOffspringData): + sim_info: PregnancyOffspringData = sim_info + any_traits = [cls.get_trait_id(trait) for trait in sim_info.traits] + if not any_traits: + return CommonTestResult(False, reason=f'{sim_info} does not have any traits.') + for _trait in traits: + __trait = cls.get_trait_id(_trait) + if __trait is None: + continue + if _trait in any_traits: + return CommonTestResult(True, reason=f'{sim_info} has trait {__trait}.') + return CommonTestResult(False, reason=f'{sim_info} does not have any trait(s) {traits}.') + + @classmethod + def has_all_traits(cls, sim_info: SimInfo, traits: Iterator[Union[int, CommonTraitId, Trait]]) -> CommonTestResult: + """has_all_traits(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 traits: An iterator of identifiers of Traits. + :type traits: Iterator[Union[int, CommonTraitId, Trait]] + :return: The result of testing. True, if the Sim has any of the specified traits. False, if not. + :rtype: CommonTestResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + if not traits: + return CommonTestResult(False, reason='No traits were specified.') + if isinstance(sim_info, SimInfo): + for trait in traits: + _trait = cls.load_trait_by_id(trait) + if _trait is None: + continue + if not sim_info.has_trait(_trait): + return CommonTestResult(False, reason=f'{sim_info} does not have trait {_trait}.') + elif isinstance(sim_info, SimInfoBaseWrapper): + sim_info: SimInfoBaseWrapper = sim_info + any_traits = cls.get_trait_ids(sim_info) + if not any_traits: + return CommonTestResult(False, reason=f'{sim_info} does not have any traits.') + for _trait in traits: + __trait = cls.get_trait_id(_trait) + if __trait is None: + continue + if _trait not in any_traits: + return CommonTestResult(False, reason=f'{sim_info} does not have trait {_trait}.') + elif isinstance(sim_info, PregnancyOffspringData): + sim_info: PregnancyOffspringData = sim_info + any_traits = cls.get_trait_ids(sim_info) + if not any_traits: + return CommonTestResult(False, reason=f'{sim_info} does not have any traits.') + for _trait in traits: + __trait = cls.get_trait_id(_trait) + if __trait is None: + continue + if _trait not in any_traits: + return CommonTestResult(False, reason=f'{sim_info} does not have trait {_trait}.') + return CommonTestResult(True, reason=f'{sim_info} has all traits {traits}.') + + @classmethod + def is_conflicting_trait(cls, sim_info: SimInfo, trait_id: Union[int, CommonTraitId, Trait]) -> CommonTestResult: + """is_conflicting_trait(sim_info, trait_id) + + Determine if a Trait conflicts with any of the Sims current Traits. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param trait_id: The identifier of the trait to check. + :type trait_id: int + :return: The result of testing. True, if the specified Trait conflicts with any Traits the Sim currently has. False, if not. + :rtype: CommonTestResult + """ + trait_to_check = cls.load_trait_by_id(trait_id) + if trait_to_check is None: + return CommonTestResult(False, reason=f'Trait {trait_id} did not exist, thus it cannot conflict.') + from traits.trait_tracker import TraitTracker + trait_tracker: TraitTracker = sim_info.trait_tracker + return trait_tracker.is_conflicting(trait_to_check) + + @classmethod + def get_trait_ids(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper, PregnancyOffspringData]) -> 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: Union[SimInfo, SimInfoBaseWrapper, PregnancyOffspringData] + :return: A collection of Trait identifiers on a Sim. + :rtype: List[int] + """ + trait_ids = list() + if isinstance(sim_info, SimInfo) or isinstance(sim_info, PregnancyOffspringData): + for trait in cls.get_traits(sim_info): + trait_id = cls.get_trait_id(trait) + if trait_id is None: + continue + trait_ids.append(trait_id) + elif isinstance(sim_info, SimInfoBaseWrapper): + return list(sim_info._get_trait_ids()) + return trait_ids + + @classmethod + def get_traits(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper, PregnancyOffspringData]) -> List[Trait]: + """get_traits(sim_info) + + Retrieve all Traits of a Sim. + + :param sim_info: The Sim to check. + :type sim_info: Union[SimInfo, SimInfoBaseWrapper, PregnancyOffspringData] + :return: A collection of Traits on a Sim. + :rtype: List[int] + """ + if isinstance(sim_info, SimInfo): + if not hasattr(sim_info, 'get_traits'): + return list() + traits = list(sim_info.get_traits()) + if traits: + return traits + if not hasattr(sim_info, '_base'): + return traits + return list([cls.load_trait_by_id(trait_id) for trait_id in (*sim_info._base.trait_ids, *sim_info._base.base_trait_ids) if cls.load_trait_by_id(trait_id) is not None]) + elif isinstance(sim_info, PregnancyOffspringData): + return sim_info.traits + elif isinstance(sim_info, SimInfoBaseWrapper): + return [cls.load_trait_by_id(trait_id) for trait_id in cls.get_trait_ids(sim_info)] + return list() + + @classmethod + def get_trait_name(cls, 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 trait.__class__.__name__ + except: + # noinspection PyBroadException + try: + return trait.__class__.__name__ + except: + return '' + + @classmethod + def get_trait_names(cls, 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 = cls.get_trait_name(trait) + if not name: + continue + except: + continue + names.append(name) + return tuple(names) + + @classmethod + def get_equipped_traits(cls, 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'): + if hasattr(sim_info, '_base'): + return list([cls.load_trait_by_id(trait_id) for trait_id in (*sim_info._base.trait_ids, *sim_info._base.base_trait_ids) if cls.load_trait_by_id(trait_id) is not None]) + return list() + return list(sim_info.trait_tracker.equipped_traits) + + @classmethod + def add_trait(cls, sim_info: SimInfo, *trait: Union[int, CommonTraitId, Trait]) -> CommonExecutionResult: + """add_trait(sim_info, trait) + + Add a Trait to a Sim. + + :param sim_info: The Sim to add the specified traits to. + :type sim_info: SimInfo + :param trait: The trait being added. + :type trait: Union[int, CommonTraitId, Trait] + :return: The result of adding the trait. True, if the trait was successfully added to the Sim. False, if not. + :rtype: CommonExecutionResult + """ + return cls.add_traits(sim_info, trait) + + @classmethod + def add_traits(cls, sim_info: SimInfo, traits: Iterator[Union[int, CommonTraitId, Trait]]) -> CommonExecutionResult: + """add_traits(sim_info, traits) + + Add Traits to a Sim. + + :param sim_info: The Sim to add the specified traits to. + :type sim_info: SimInfo + :param traits: An iterator of identifiers of traits being added. + :type traits: Iterator[Union[int, CommonTraitId, Trait]] + :return: The result of adding the traits. True, if all specified traits were successfully added to the Sim. False, if not. + :rtype: CommonExecutionResult + """ + if sim_info is None: + raise AssertionError('Argument sim_info was None') + has_any = False + success = True + failed_to_add_traits = list() + for trait_id in traits: + trait = cls.load_trait_by_id(trait_id) + if trait is None: + cls.get_log().format_with_message('Failed to load trait by its id.', sim=sim_info, trait_id=trait_id) + failed_to_add_traits.append(trait_id) + continue + has_any = True + if cls.has_trait(sim_info, trait): + cls.get_log().format_with_message('Sim already had trait.', sim=sim_info, trait=trait) + continue + cls.get_log().format_with_message('Attempting to add trait', sim=sim_info, trait=trait, trait_id=trait_id) + add_result = sim_info.add_trait(trait) + if not add_result: + cls.get_log().format_with_message('Failed to add trait.', sim=sim_info, trait=trait, trait_id=trait_id, reason=add_result) + success = False + failed_to_add_traits.append(trait) + else: + cls.get_log().format_with_message('Successfully added trait.', sim=sim_info, trait=trait, trait_id=trait_id) + if not success: + failed_to_add_traits_str = ', '.join([cls.get_trait_name(trait) or str(trait) if isinstance(trait, Trait) else str(trait) for trait in failed_to_add_traits]) + return CommonExecutionResult(False, reason=f'Failed to add traits to {sim_info}. {failed_to_add_traits_str}') + if not has_any: + return CommonExecutionResult(True, reason=f'Finished "adding" traits to {sim_info}, but none of the specified traits were loaded.') + return CommonExecutionResult.TRUE + + @classmethod + def remove_trait(cls, sim_info: SimInfo, *trait: Union[int, CommonTraitId, Trait]) -> CommonExecutionResult: + """remove_trait(sim_info, trait) + + Remove a Trait from a Sim. + + :param sim_info: The Sim to remove the specified traits from. + :type sim_info: SimInfo + :param trait: The trait being removed. + :type trait: Union[int, CommonTraitId, Trait] + :return: The result of removing the trait. True, if the trait was successfully removed from the Sim. False, if not. + :rtype: CommonExecutionResult + """ + return cls.remove_traits(sim_info, trait) + + @classmethod + def remove_traits(cls, sim_info: SimInfo, traits: Iterator[Union[int, CommonTraitId, Trait]]) -> CommonExecutionResult: + """remove_traits(sim_info, traits) + + Remove Traits from a Sim. + + :param sim_info: The Sim to remove the specified traits from. + :type sim_info: SimInfo + :param traits: An iterator of Trait identifiers of traits being removed. + :type traits: Iterator[Union[int, CommonTraitId, Trait]] + :return: The result of removing the traits. True, if all specified traits were successfully removed from the Sim. False, if not. + :rtype: CommonExecutionResult + """ + has_any_loaded = False + success = True + failed_to_remove_traits = list() + for trait_id in traits: + trait = cls.load_trait_by_id(trait_id) + if trait is None: + failed_to_remove_traits.append(trait_id) + continue + # If the Sim does not have the trait, the remove_trait function will return False. We check if they have it before attempting, so we don't run into this. + if not cls.has_trait(sim_info, trait): + continue + has_any_loaded = True + if not sim_info.remove_trait(trait): + failed_to_remove_traits.append(trait) + success = False + + if not success: + failed_to_remove_traits_str = ', '.join([cls.get_trait_name(trait) or str(trait) if isinstance(trait, Trait) else str(trait) for trait in failed_to_remove_traits]) + return CommonExecutionResult(False, reason=f'Failed to remove traits. {failed_to_remove_traits_str}') + if not has_any_loaded: + return CommonExecutionResult(True, reason='Finished "removing" traits, but none of the specified traits were loaded.') + return CommonExecutionResult.TRUE + + @classmethod + def swap_traits(cls, sim_info: SimInfo, trait_id_one: Union[int, CommonTraitId, Trait], trait_id_two: Union[int, CommonTraitId, Trait]) -> CommonExecutionResult: + """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: Union[int, CommonTraitId, Trait] + :param trait_id_two: The second trait to remove/add + :type trait_id_two: Union[int, CommonTraitId, Trait] + :return: The result of swapping traits. True, if the Traits were swapped successfully. False, if neither Trait exists on a Sim or the traits were not swapped successfully. + :rtype: CommonExecutionResult + """ + # Has Trait One + if cls.has_trait(sim_info, trait_id_one): + cls.remove_trait(sim_info, trait_id_one) + if not cls.has_trait(sim_info, trait_id_two): + return cls.add_trait(sim_info, trait_id_two) + return CommonExecutionResult.TRUE + # Has Trait Two + elif cls.has_trait(sim_info, trait_id_two): + cls.remove_trait(sim_info, trait_id_two) + if not cls.has_trait(sim_info, trait_id_one): + return cls.add_trait(sim_info, trait_id_one) + return CommonExecutionResult.TRUE + return CommonExecutionResult(False, reason=f'Sim had neither Trait One {trait_id_one} nor Trait Two {trait_id_two}.') + + @classmethod + def add_trait_to_all_sims(cls, trait_id: Union[int, CommonTraitId, Trait], 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: Union[int, CommonTraitId, Trait] + :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 cls.has_trait(sim_info, trait_id): + continue + cls.add_trait(sim_info, trait_id) + + @classmethod + def remove_trait_from_all_sims(cls, trait_id: Union[int, CommonTraitId, Trait], 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: Union[int, CommonTraitId, Trait] + :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 cls.has_trait(sim_info, trait_id): + continue + cls.remove_trait(sim_info, trait_id) + + @classmethod + def get_trait_id(cls, 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) + + @classmethod + def is_trait_available(cls, trait: Union[int, CommonTraitId, Trait]) -> bool: + """is_trait_available(trait) + + Determine if a Trait is available for use. + + .. note:: If the Trait is part of a package that is not installed, it will be considered as not available. + + :param trait: The trait to check for. + :type trait: Union[int, CommonTraitId, Trait] + :return: True, if the Trait is available for use. False, if not. + :rtype: bool + """ + return cls.load_trait_by_id(trait) is not None + + @classmethod + def load_trait_by_id(cls, trait: Union[int, CommonTraitId, Trait]) -> Union[Trait, None]: + """load_trait_by_id(trait) + + Load an instance of a Trait by its identifier. + + :param trait: The identifier of a Trait. + :type trait: Union[int, CommonTraitId, Trait] + :return: An instance of a Trait matching the decimal identifier or None if not found. + :rtype: Union[Trait, None] + """ + if isinstance(trait, Trait): + return trait + # noinspection PyBroadException + try: + # noinspection PyCallingNonCallable + trait_instance = trait() + if isinstance(trait_instance, Trait): + # noinspection PyTypeChecker + return trait + except: + pass + # noinspection PyBroadException + try: + trait: int = int(trait) + except: + # noinspection PyTypeChecker + trait: Trait = trait + return trait + + from sims4.resources import Types + from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + return CommonResourceUtils.load_instance(Types.TRAIT, trait) + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.print_known_traits', + 'Print a list of all personality, occult, and other types of traits Sim A knows about Sim B. (For example Sim A could know that Sim B is Childish)', + command_arguments=( + CommonConsoleCommandArgument('sim_info_a', 'Sim Id or Name', 'The instance id or name of a Sim to check.', is_optional=True, default_value='Active Sim'), + CommonConsoleCommandArgument('sim_info_b', 'Sim Id or Name', 'The instance id or name of a Sim to check.', is_optional=True, default_value='Active Sim'), + ) +) +def _common_print_known_traits(output: CommonConsoleCommandOutput, sim_info_a: SimInfo = None, sim_info_b: SimInfo = None): + if sim_info_a is None: + return + if sim_info_b is None: + return + if sim_info_a is sim_info_b: + output('ERROR: Sim A knows all traits about Sim B, because Sim A IS Sim B. Please specify at least one other Sim for either Sim A or Sim B when running this command!') + return + output(f'Attempting to print the traits that Sim A knows about Sim B.') + sim_id_b = CommonSimUtils.get_sim_id(sim_info_b) + relationship_tracker: RelationshipTracker = sim_info_a.relationship_tracker + knowledge: SimKnowledge = relationship_tracker.get_knowledge(sim_id_b, initialize=False) + if knowledge.known_traits is None and knowledge.known_traits: + output('SUCCESS: Sim A knows zero traits about Sim B.') + return + output(f'Traits that Sim A {sim_info_a} knows about Sim B {sim_info_b}:') + for trait in knowledge.known_traits: + output(f'- {trait}') + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.add_trait', + 'Add a trait to a Sim.', + command_arguments=( + CommonConsoleCommandArgument('trait', 'Trait Id or Tuning Name', 'The decimal identifier or Tuning Name of the Trait to add.'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance id or name of a Sim to add the trait to.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.addtrait', + ) +) +def _common_add_trait(output: CommonConsoleCommandOutput, trait: TunableInstanceParam(Types.TRAIT), sim_info: SimInfo = None): + if trait is None: + return + if sim_info is None: + return + output(f'Adding trait {trait} to Sim {sim_info}') + result = CommonTraitUtils.add_trait(sim_info, trait) + if result: + output(f'SUCCESS: Successfully added trait {trait} to Sim {sim_info}: {result.reason}') + else: + output(f'FAILED: Failed to add trait {trait} to Sim {sim_info}. {result.reason}') + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib.remove_trait', + 'Remove a trait from a Sim.', + command_arguments=( + CommonConsoleCommandArgument('trait', 'Trait Id or Tuning Name', 'The decimal identifier or Tuning Name of the Trait to remove.'), + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance id or name of a Sim to remove the trait from.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib.removetrait', + ) +) +def _common_remove_trait(output: CommonConsoleCommandOutput, trait: TunableInstanceParam(Types.TRAIT), sim_info: SimInfo = None): + if trait is None: + return + if sim_info is None: + return + output(f'Removing trait {trait} from Sim {sim_info}') + result = CommonTraitUtils.remove_trait(sim_info, trait) + if result: + output(f'SUCCESS: Successfully removed trait {trait} from Sim {sim_info}: {result.reason}') + else: + output(f'FAILED: Failed to remove trait {trait} from Sim {sim_info}: {result.reason}') + + +# noinspection SpellCheckingInspection +@CommonConsoleCommand( + ModInfo.get_identity(), + 's4clib_testing.print_traits', + 'Print a list of all traits on a Sim.', + command_arguments=( + CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance id or name of a Sim to check.', is_optional=True, default_value='Active Sim'), + ), + command_aliases=( + 's4clib_testing.printtraits', + ) +) +def _common_show_traits(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): + if sim_info is None: + return + log = CommonTraitUtils.get_log() + try: + log.enable() + output(f'Showing traits of Sim {sim_info}') + trait_strings: List[str] = list() + for trait in CommonTraitUtils.get_traits(sim_info): + trait_name = CommonTraitUtils.get_trait_name(trait) + trait_id = CommonTraitUtils.get_trait_id(trait) + trait_strings.append(f'{trait_name} ({trait_id})') + + trait_strings = sorted(trait_strings, key=lambda x: x) + sim_traits = ', '.join(trait_strings) + text = '' + text += f'Traits:\n{sim_traits}\n\n' + sim_id = CommonSimUtils.get_sim_id(sim_info) + log.debug(f'{sim_info} Traits ({sim_id})') + log.debug(text) + CommonBasicNotification( + CommonLocalizationUtils.create_localized_string(f'{sim_info} Traits ({sim_id})'), + CommonLocalizationUtils.create_localized_string(text) + ).show( + icon=IconInfoData(obj_instance=CommonSimUtils.get_sim_instance(sim_info)) + ) + finally: + log.disable() diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_whim_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_whim_utils.py new file mode 100644 index 0000000..0053d15 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_whim_utils.py @@ -0,0 +1,36 @@ +""" +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 +""" +from typing import Tuple, List + +from sims.sim_info import SimInfo +from whims.whim_set import WhimSetBaseMixin + + +class CommonWhimUtils: + """Utilities for manipulating the Whims of Sims. + + """ + @staticmethod + def get_current_whims(sim_info: SimInfo) -> Tuple[WhimSetBaseMixin]: + """get_current_whims(sim_info) + + Retrieve the current Whims of the specified Sim. + + :param sim_info: The Sim to get the Whim Sets of. + :type sim_info: SimInfo + :return: A collection of Whims Sets for the specified Sim. + :rtype: Tuple[WhimSetBaseMixin] + """ + whims_tracker = sim_info.whim_tracker + if whims_tracker is None: + return tuple() + goal_instances: List[WhimSetBaseMixin] = [] + for whim_data in whims_tracker.get_active_whim_data(): + if whim_data.whim is not None: + goal_instances.append(whim_data.whim) + return tuple(goal_instances) diff --git a/Scripts/s4ap/sims4communitylib/utils/terrain/__init__.py b/Scripts/s4ap/sims4communitylib/utils/terrain/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/terrain/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/utils/terrain/common_terrain_interaction_utils.py b/Scripts/s4ap/sims4communitylib/utils/terrain/common_terrain_interaction_utils.py new file mode 100644 index 0000000..7ebbaab --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/terrain/common_terrain_interaction_utils.py @@ -0,0 +1,58 @@ +""" +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 +""" +from typing import Tuple, Union +from interactions.context import InteractionContext +from objects.terrain import TerrainPoint +from routing import SurfaceType +from server.pick_info import PickType +from sims.sim_info import SimInfo +from sims4communitylib.classes.math.common_surface_identifier import CommonSurfaceIdentifier +from sims4communitylib.classes.math.common_vector3 import CommonVector3 +from sims4communitylib.logging.has_class_log import HasClassLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + + +class CommonTerrainInteractionUtils(HasClassLog): + """Utilities for manipulating the interactions of Terrain. + + """ + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + return ModInfo.get_identity() + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 'common_terrain_interaction_utils' + + @staticmethod + def build_terrain_point_and_interaction_context_from_sim_and_position(sim_info: SimInfo, target_position: CommonVector3, target_surface_level: int) -> Tuple[Union[TerrainPoint, None], Union[InteractionContext, None]]: + """build_terrain_point_and_interaction_context_from_sim_and_position(sim_info, position, target_surface_level) + + Build a target and a context for the terrain. + + :param sim_info: An instance of a Sim. + :type sim_info: SimInfo + :param target_position: The target position. + :type target_position: CommonVector3 + :param target_surface_level: The surface level at the target position. + :type target_surface_level: int + :return: A tuple of the terrain point and the interaction context created from the position and surface level for the Sim or (None, None) if an error occurs. + :rtype: Tuple[Union[TerrainPoint, None], Union[InteractionContext, None]] + """ + from sims4communitylib.utils.location.common_location_utils import CommonLocationUtils + from server_commands.sim_commands import _build_terrain_interaction_target_and_context + sim = CommonSimUtils.get_sim_instance(sim_info) + if sim is None: + return None, None + routing_surface = CommonSurfaceIdentifier(CommonLocationUtils.get_current_zone_id(), secondary_id=target_surface_level, surface_type=SurfaceType.SURFACETYPE_WORLD) + return _build_terrain_interaction_target_and_context(sim, target_position, routing_surface, PickType.PICK_TERRAIN, TerrainPoint) diff --git a/Scripts/s4ap/sims4communitylib/utils/terrain/common_terrain_location_utils.py b/Scripts/s4ap/sims4communitylib/utils/terrain/common_terrain_location_utils.py new file mode 100644 index 0000000..0bd7d17 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/terrain/common_terrain_location_utils.py @@ -0,0 +1,68 @@ +""" +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 +""" +from typing import Union + +from objects.terrain import Terrain +from sims4communitylib.classes.math.common_surface_identifier import CommonSurfaceIdentifier +from sims4communitylib.classes.math.common_vector3 import CommonVector3 + + +class CommonTerrainLocationUtils: + """Utilities for manipulating the locational data of Terrain.""" + + @staticmethod + def get_water_depth_at(x: float, z: float, surface_level: int=0) -> float: + """get_water_depth_at(x, z, surface_level=0) + + Determine the water depth at the specified coordinates. + + :param x: The X coordinate. + :type x: float + :param z: The Z coordinate. + :type z: float + :param surface_level: The surface level. Default is 0. + :type surface_level: int, optional + :return: The depth of the water at the specified coordinates. + :rtype: float + """ + from terrain import get_water_depth + return get_water_depth(x, z, level=surface_level) + + @staticmethod + def get_position(terrain_object: Terrain) -> Union[CommonVector3, None]: + """get_position(terrain_object) + + Retrieve the position of a Terrain Object. + + :param terrain_object: An instance of a Terrain object. + :type terrain_object: Terrain + :return: The position of the Object or None if the Object does not have a position. + :rtype: CommonVector3 + """ + if terrain_object is None: + return None + # noinspection PyBroadException + try: + return CommonVector3.from_vector3(terrain_object.position) + except: + return None + + @staticmethod + def get_routing_surface(terrain_object: Terrain) -> Union[CommonSurfaceIdentifier, None]: + """get_routing_surface(game_object) + + Retrieve the routing surface of a Terrain Object. + + :param terrain_object: An instance of a Terrain Object. + :type terrain_object: Terrain + :return: The routing surface of the object or None if a problem occurs. + :rtype: Union[CommonSurfaceIdentifier, None] + """ + if terrain_object is None: + return None + return CommonSurfaceIdentifier.from_surface_identifier(terrain_object.routing_surface) diff --git a/Scripts/s4ap/sims4communitylib/utils/terrain/common_terrain_utils.py b/Scripts/s4ap/sims4communitylib/utils/terrain/common_terrain_utils.py new file mode 100644 index 0000000..8a5b438 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/terrain/common_terrain_utils.py @@ -0,0 +1,12 @@ +""" +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 +""" + + +class CommonTerrainUtils: + """ Utilities for manipulating the Terrain. """ + pass diff --git a/Scripts/s4ap/sims4communitylib/utils/time/__init__.py b/Scripts/s4ap/sims4communitylib/utils/time/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/time/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/utils/time/common_alarm_utils.py b/Scripts/s4ap/sims4communitylib/utils/time/common_alarm_utils.py new file mode 100644 index 0000000..a80df26 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/time/common_alarm_utils.py @@ -0,0 +1,181 @@ +""" +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 +""" +import os +from typing import Callable, Any, Union +from sims4communitylib.classes.time.common_alarm_handle import CommonAlarmHandle +from sims4communitylib.logging.has_class_log import HasClassLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.modinfo import ModInfo +from sims4communitylib.utils.common_time_utils import CommonTimeUtils + +ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' + +if ON_RTD: + # noinspection PyMissingOrEmptyDocstring + class Timeline: + pass + + # noinspection PyMissingOrEmptyDocstring + class TimeSpan: + pass + +if not ON_RTD: + from scheduling import Timeline + from date_and_time import TimeSpan + + +class CommonAlarmUtils(HasClassLog): + """Utilities for manipulating alarms.""" + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_mod_identity(cls) -> CommonModIdentity: + return ModInfo.get_identity() + + # noinspection PyMissingOrEmptyDocstring + @classmethod + def get_log_identifier(cls) -> str: + return 'common_alarm_utils' + + @classmethod + def schedule_alarm( + cls, + alarm_owner: Any, + time_until_first_occurrence: TimeSpan, + on_alarm_triggered_callback: Callable[['CommonAlarmHandle'], None], + should_repeat: bool = False, + time_until_repeat: TimeSpan = None, + accurate_repeat: bool = True, + persist_across_zone_loads: bool = False, + timeline: Timeline = None + ) -> Union['CommonAlarmHandle', None]: + """schedule_alarm(\ + alarm_owner,\ + time_until_next_occurrence,\ + callback,\ + should_repeat=False,\ + time_until_repeat=None,\ + accurate_repeat=True,\ + persist_across_zone_loads=False,\ + timeline=None\ + ) + + Schedule an alarm that will trigger a callback after a set amount of time. + + :param alarm_owner: The owner of the alarm. + :type alarm_owner: Any + :param time_until_first_occurrence: The time until the alarm triggers. + :type time_until_first_occurrence: TimeSpan + :param on_alarm_triggered_callback: When the alarm is triggered at the specified time, this callback will be invoked with the alarm handle. + :type on_alarm_triggered_callback: Callable[['CommonAlarmHandle'], None] + :param should_repeat: If True, the alarm will repeat on the specified interval. If False, the alarm will only trigger once. Default is False. + :type should_repeat: bool, optional + :param time_until_repeat: The amount of time that must pass before the alarm will trigger again. This only comes into play after being triggered once. Default is None. + :type time_until_repeat: TimeSpan, optional + :param accurate_repeat: Whether or not the initial time should be based on the now time or the future time. Default is the Now time. + :type accurate_repeat: bool, optional + :param persist_across_zone_loads: If True, the alarm will persist when loading a new zone. If False, the alarm will be canceled upon changing zones. Default is False. + :type persist_across_zone_loads: bool, optional + :param timeline: The timeline to use when determining the alarm trigger time as well as the initial time of the alarm. Default is Sim Timeline. + :type timeline: Timeline, optional + :return: The created alarm handle or None if the Time service is not currently available or a problem occurs. + :rtype: Union[CommonAlarmHandle, None] + """ + if timeline is None: + time_service = CommonTimeUtils.get_time_service() + if time_service.sim_timeline is None: + return None + timeline = time_service.sim_timeline + + if accurate_repeat: + initial_time = timeline.now + else: + initial_time = timeline.future + + def _on_alarm_triggered(handle: CommonAlarmHandle): + try: + on_alarm_triggered_callback(handle) + except Exception as ex: + cls.get_log().format_error(f'An exception occurred when triggering alarm callback for {alarm_owner}.', alarm_owner=alarm_owner, exception=ex) + + return CommonAlarmHandle( + alarm_owner, + _on_alarm_triggered, + timeline, + initial_time + time_until_first_occurrence, + should_repeat=should_repeat, + time_until_repeat=time_until_repeat or time_until_first_occurrence, + accurate_repeat=accurate_repeat, + persist_across_zone_loads=persist_across_zone_loads + ) + + @classmethod + def schedule_daily_alarm( + cls, + alarm_owner: Any, + hour: int, + minute: int, + on_alarm_triggered: Callable[[CommonAlarmHandle], None], + persist_across_zone_loads: bool = False + ) -> CommonAlarmHandle: + """schedule_daily_alarm(\ + alarm_owner,\ + hour,\ + minute,\ + on_alarm_triggered,\ + persist_across_zone_loads=False\ + ) + + Schedule an alarm that will repeat once a day, every day. + + :param alarm_owner: The owner of the alarm. + :type alarm_owner: Any + :param hour: The hour of the day to trigger the alarm at. + :type hour: int + :param minute: The minute of the hour to trigger the alarm at. + :type minute: int + :param on_alarm_triggered: A callback invoked when the alarm is triggered. + :type on_alarm_triggered: Callable[[CommonAlarmHandle], None] + :param persist_across_zone_loads: If True, the alarm will persist when loading a new zone. If False, the alarm will be canceled upon changing zones. Default is False. + :type persist_across_zone_loads: bool, optional + :return: The scheduled alarm or None if a problem occurs. + :rtype: CommonAlarmHandle + """ + from date_and_time import create_date_and_time, sim_ticks_per_day + now = CommonTimeUtils.get_current_date_and_time() + alarm_time_of_day = create_date_and_time(hours=hour, minutes=minute) + alarm_next_trigger_time = now.time_till_next_day_time(alarm_time_of_day) + if alarm_next_trigger_time.in_ticks() == 0: + alarm_next_trigger_time += TimeSpan(sim_ticks_per_day()) + + repeat_interval = TimeSpan(sim_ticks_per_day()) + + return cls.schedule_alarm( + alarm_owner, + alarm_next_trigger_time, + on_alarm_triggered, + time_until_repeat=repeat_interval, + should_repeat=True, + persist_across_zone_loads=persist_across_zone_loads + ) + + @classmethod + def cancel_alarm(cls, alarm_handle: CommonAlarmHandle) -> bool: + """cancel_alarm(alarm_handle) + + Cancel an alarm so that it will no longer occur. + + :param alarm_handle: The handle of the alarm to cancel. + :type alarm_handle: CommonAlarmHandle + :return: True, if the alarm was cancelled successfully. False, if not. + :rtype: bool + """ + if alarm_handle is None: + return False + alarm_handle.cancel() + return True diff --git a/Scripts/s4ap/sims4communitylib/utils/whims/__init__.py b/Scripts/s4ap/sims4communitylib/utils/whims/__init__.py new file mode 100644 index 0000000..cbf2b63 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/whims/__init__.py @@ -0,0 +1,7 @@ +""" +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 +""" diff --git a/Scripts/s4ap/sims4communitylib/utils/whims/common_satisfaction_reward_store_item.py b/Scripts/s4ap/sims4communitylib/utils/whims/common_satisfaction_reward_store_item.py new file mode 100644 index 0000000..b4e3c79 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/whims/common_satisfaction_reward_store_item.py @@ -0,0 +1,35 @@ +""" +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 +""" +from rewards.reward import Reward + +try: + from satisfaction.satisfaction_tracker import SatisfactionTracker +except: + from whims.whims_tracker import WhimsTracker + + SatisfactionTracker = WhimsTracker + # noinspection PyUnresolvedReferences + setattr(SatisfactionTracker, 'SatisfactionAwardTypes', WhimsTracker.WhimAwardTypes) + + +class CommonSatisfactionRewardStoreItem: + """CommonSatisfactionRewardStoreItem(reward, reward_cost, reward_type) + + A wrapper for Reward Store Items. + + :param reward: An instance of a Reward. + :type reward: Reward + :param reward_cost: The amount of Satisfaction Reward Points the Reward costs. + :type reward_cost: int + :param reward_type: The type of the Reward. + :type reward_type: SatisfactionTracker.SatisfactionAwardTypes + """ + def __init__(self, reward: Reward, reward_cost: int, reward_type: SatisfactionTracker.SatisfactionAwardTypes): + self.reward = reward + self.reward_cost = reward_cost + self.reward_type = reward_type diff --git a/Scripts/s4ap/sims4communitylib/utils/whims/common_satisfaction_reward_store_utils.py b/Scripts/s4ap/sims4communitylib/utils/whims/common_satisfaction_reward_store_utils.py new file mode 100644 index 0000000..60f3e59 --- /dev/null +++ b/Scripts/s4ap/sims4communitylib/utils/whims/common_satisfaction_reward_store_utils.py @@ -0,0 +1,172 @@ +""" +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 +""" +from typing import Tuple, Dict, Callable, Iterator + +import sims4.collections +from rewards.reward import Reward +from sims4communitylib.utils.common_resource_utils import CommonResourceUtils +from sims4communitylib.utils.whims.common_satisfaction_reward_store_item import CommonSatisfactionRewardStoreItem + +# noinspection PyBroadException +try: + from satisfaction.satisfaction_tracker import SatisfactionTracker +except: + from whims.whims_tracker import WhimsTracker + + SatisfactionTracker = WhimsTracker + # noinspection PyUnresolvedReferences + SatisfactionTracker.SatisfactionAwardTypes = WhimsTracker.WhimAwardTypes + + +class CommonSatisfactionRewardStoreUtils: + """Utilities for manipulating the Satisfaction Rewards Store. + + """ + @staticmethod + def add_reward_trait_to_rewards_store(reward_trait_definition_id: int, reward_point_cost: int) -> bool: + """add_reward_trait_to_rewards_store(reward_trait_definition_id, reward_point_cost) + + Add a Reward Trait to the Satisfaction Rewards Store. + + :param reward_trait_definition_id: The decimal identifier of a Reward Trait. + :type reward_trait_definition_id: int + :param reward_point_cost: The amount of Satisfaction Reward Points the Reward Trait will cost the Sim to receive. + :type reward_point_cost: int + :return: True, if the Trait was added to the Rewards Store successfully. False, if not. + :rtype: bool + """ + return CommonSatisfactionRewardStoreUtils._add_reward_to_rewards_store(reward_trait_definition_id, reward_point_cost, SatisfactionTracker.SatisfactionAwardTypes.TRAIT) + + @staticmethod + def add_reward_buff_to_rewards_store(reward_buff_definition_id: int, reward_point_cost: int) -> bool: + """add_reward_buff_to_rewards_store(reward_buff_definition_id, reward_point_cost) + + Add a Reward Buff to the Satisfaction Rewards Store. + + :param reward_buff_definition_id: The decimal identifier of a Reward Buff. + :type reward_buff_definition_id: int + :param reward_point_cost: The amount of Satisfaction Reward Points the Reward Buff will cost the Sim to receive. + :type reward_point_cost: int + :return: True, if the Reward Buff was added to the Rewards Store successfully. False, if not. + :rtype: bool + """ + return CommonSatisfactionRewardStoreUtils._add_reward_to_rewards_store(reward_buff_definition_id, reward_point_cost, SatisfactionTracker.SatisfactionAwardTypes.BUFF) + + @staticmethod + def add_reward_object_to_rewards_store(reward_object_definition_id: int, reward_point_cost: int) -> bool: + """add_reward_object_to_rewards_store(reward_object_definition_id, reward_point_cost) + + Add a Reward Object to the Satisfaction Rewards Store. + + :param reward_object_definition_id: The decimal identifier of a Reward Object. + :type reward_object_definition_id: int + :param reward_point_cost: The amount of Satisfaction Reward Points the Reward Object will cost the Sim to receive. + :type reward_point_cost: int + :return: True, if the Reward Object was added to the Rewards Store successfully. False, if not. + :rtype: bool + """ + return CommonSatisfactionRewardStoreUtils._add_reward_to_rewards_store(reward_object_definition_id, reward_point_cost, SatisfactionTracker.SatisfactionAwardTypes.OBJECT) + + @staticmethod + def add_reward_cas_part_to_rewards_store(reward_cas_part_definition_id: int, reward_point_cost: int) -> bool: + """add_reward_cas_part_to_rewards_store(reward_cas_part_definition_id, reward_point_cost) + + Add a Reward CAS Part to the Satisfaction Rewards Store. + + :param reward_cas_part_definition_id: The decimal identifier of a Reward CAS Part. + :type reward_cas_part_definition_id: int + :param reward_point_cost: The amount of Satisfaction Reward Points the Reward CAS Part will cost the Sim to receive. + :type reward_point_cost: int + :return: True, if the Reward CAS Part was added to the Rewards Store successfully. False, if not. + :rtype: bool + """ + return CommonSatisfactionRewardStoreUtils._add_reward_to_rewards_store(reward_cas_part_definition_id, reward_point_cost, SatisfactionTracker.SatisfactionAwardTypes.CASPART) + + @staticmethod + def remove_reward_from_rewards_store(reward_item_definition_id: int) -> bool: + """remove_reward_from_rewards_store(reward_item_definition_id) + + Remove a Reward Item from the Satisfaction Rewards Store. + + :param reward_item_definition_id: The decimal identifier of a Reward Item. + :type reward_item_definition_id: int + :return: True, if the Reward Item was removed from the Rewards Store successfully. False, if not. + :rtype: bool + """ + return CommonSatisfactionRewardStoreUtils._remove_reward_from_rewards_store(reward_item_definition_id) + + @staticmethod + def get_all_satisfaction_reward_store_items_generator( + include_satisfaction_reward_callback: Callable[[CommonSatisfactionRewardStoreItem], bool]=None + ) -> Iterator[CommonSatisfactionRewardStoreItem]: + """get_all_satisfaction_reward_store_items_generator(include_satisfaction_reward_callback=None) + + Retrieve all Satisfaction Rewards in the Satisfaction Rewards Store. + + :param include_satisfaction_reward_callback: If the result of this callback is True, the Satisfaction Reward\ + and Satisfaction Reward Data (Cost, Award Type), will be included in the results. If set to None, All Satisfaction Rewards will be included. + :type include_satisfaction_reward_callback: Callable[[CommonRewardStoreItem]], bool], optional + :return: All items from the satisfaction reward store. + :rtype: Iterator[CommonSatisfactionRewardStoreItem] + """ + satisfaction_reward_store_items: Dict[Reward, Tuple[int, SatisfactionTracker.SatisfactionAwardTypes]] = dict(SatisfactionTracker.SATISFACTION_STORE_ITEMS) + for (reward, data) in satisfaction_reward_store_items.items(): + reward_cost = data.cost + reward_type = CommonResourceUtils.get_enum_by_int_value(int(data.award_type), SatisfactionTracker.SatisfactionAwardTypes, default_value=None) + reward_store_item = CommonSatisfactionRewardStoreItem(reward, reward_cost, reward_type) + if include_satisfaction_reward_callback is not None and not include_satisfaction_reward_callback(reward_store_item): + continue + yield reward_store_item + + @staticmethod + def _add_reward_to_rewards_store(reward_definition_id: int, reward_point_cost: int, reward_type: SatisfactionTracker.SatisfactionAwardTypes) -> bool: + sim_reward_instance = CommonSatisfactionRewardStoreUtils._load_reward_instance(reward_definition_id) + if sim_reward_instance is None: + return False + sim_reward_data_immutable_slots_cls = sims4.collections.make_immutable_slots_class(['cost', 'award_type']) + reward_data = sim_reward_data_immutable_slots_cls(dict(cost=reward_point_cost, award_type=reward_type)) + store_items = dict(SatisfactionTracker.SATISFACTION_STORE_ITEMS) + store_items[sim_reward_instance] = reward_data + SatisfactionTracker.SATISFACTION_STORE_ITEMS = sims4.collections.FrozenAttributeDict(store_items) + return True + + @staticmethod + def _remove_reward_from_rewards_store(reward_definition_id: int) -> bool: + sim_reward_instance = CommonSatisfactionRewardStoreUtils._load_reward_instance(reward_definition_id) + if sim_reward_instance is None: + return False + store_items = dict(SatisfactionTracker.SATISFACTION_STORE_ITEMS) + if sim_reward_instance in store_items: + del store_items[sim_reward_instance] + SatisfactionTracker.SATISFACTION_STORE_ITEMS = sims4.collections.FrozenAttributeDict(store_items) + return True + + @staticmethod + def _load_reward_instance(reward_definition_id: int) -> Reward: + if isinstance(reward_definition_id, Reward): + return reward_definition_id + # noinspection PyBroadException + try: + # noinspection PyCallingNonCallable + reward_definition_id_instance = reward_definition_id() + if isinstance(reward_definition_id_instance, Reward): + # noinspection PyTypeChecker + return reward_definition_id + except: + pass + # noinspection PyBroadException + try: + reward_definition_id: int = int(reward_definition_id) + except: + # noinspection PyTypeChecker + reward_definition_id: Reward = reward_definition_id + return reward_definition_id + + from sims4.resources import Types + from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + return CommonResourceUtils.load_instance(Types.REWARD, reward_definition_id) diff --git a/Scripts/s4ap/utils/s4ap_generic_utils.py b/Scripts/s4ap/utils/s4ap_generic_utils.py index c6bd3db..4e170f7 100644 --- a/Scripts/s4ap/utils/s4ap_generic_utils.py +++ b/Scripts/s4ap/utils/s4ap_generic_utils.py @@ -3,8 +3,8 @@ from s4ap.modinfo import ModInfo from services.persistence_service import SaveGameData from sims4.resources import Types -from sims4communitylib.events.zone_spin.common_zone_spin_event_dispatcher import CommonZoneSpinEventDispatcher -from sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler +from s4ap.sims4communitylib.events.zone_spin.common_zone_spin_event_dispatcher import CommonZoneSpinEventDispatcher +from s4ap.sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler from s4ap.utils.s4ap_save_utils import S4APSaveUtils from sims4.localization import LocalizationHelperTuning from ui.ui_dialog_notification import UiDialogNotification diff --git a/Scripts/s4ap/utils/s4ap_phone_utils.py b/Scripts/s4ap/utils/s4ap_phone_utils.py index 9179fde..bda9552 100644 --- a/Scripts/s4ap/utils/s4ap_phone_utils.py +++ b/Scripts/s4ap/utils/s4ap_phone_utils.py @@ -14,8 +14,8 @@ from services import get_instance_manager from sims4.localization import LocalizationHelperTuning from sims4.resources import Types -from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from sims4communitylib.events.sim.events.sim_trait_added import S4CLSimTraitAddedEvent +from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry +from s4ap.sims4communitylib.events.sim.events.sim_trait_added import S4CLSimTraitAddedEvent from ui.ui_dialog_notification import UiDialogNotification from ui.ui_dialog_picker import ObjectPickerRow, UiObjectPicker diff --git a/Scripts/s4ap/utils/s4ap_reset_utils.py b/Scripts/s4ap/utils/s4ap_reset_utils.py index a3057c4..bd65d87 100644 --- a/Scripts/s4ap/utils/s4ap_reset_utils.py +++ b/Scripts/s4ap/utils/s4ap_reset_utils.py @@ -6,7 +6,7 @@ from server_commands.argument_helpers import TunableInstanceParam from sims4.localization import LocalizationHelperTuning from sims4.resources import Types -from sims4communitylib.enums.traits_enum import CommonTraitId +from s4ap.sims4communitylib.enums.traits_enum import CommonTraitId from ui.ui_dialog_notification import UiDialogNotification logger = S4APLogger.get_log() diff --git a/Scripts/s4ap/utils/s4ap_skill_utils.py b/Scripts/s4ap/utils/s4ap_skill_utils.py index 8d7a7a0..8779b04 100644 --- a/Scripts/s4ap/utils/s4ap_skill_utils.py +++ b/Scripts/s4ap/utils/s4ap_skill_utils.py @@ -12,7 +12,7 @@ from server_commands.argument_helpers import TunableInstanceParam from sims.sim_info import SimInfo from sims4.resources import Types -from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry +from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry from statistics.skill import Skill logger = S4APLogger.get_log() diff --git a/custom_scripts_for_decompile/generated/key b/custom_scripts_for_decompile/generated/key new file mode 100644 index 0000000000000000000000000000000000000000..91e5fddf6e42d699a7a9284262cdcc928ccd4662 GIT binary patch literal 256 zcmV+b0ssDbX$%=XmK_*X85n*;FMwLKhiXAf1IGKL425sTwZrWiZoNvm_>Q(7MU^mw zboUtqanJ>40)q@n(>PkA)>qON?Qq4cPxdb`(3b3J!5o%geUuWB<1yBrpyg#*ivcUK znx0R>OfwYyiB%v`I@V^s@~l65T+w(TA1P*-Tbzp1;)CTDh~%w6_+^nY!+43i!{=C( zi4GxYS2 Date: Fri, 5 Sep 2025 14:45:51 -0600 Subject: [PATCH 053/134] new new version name --- Scripts/s4ap/modinfo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/s4ap/modinfo.py b/Scripts/s4ap/modinfo.py index f632f05..d54d234 100644 --- a/Scripts/s4ap/modinfo.py +++ b/Scripts/s4ap/modinfo.py @@ -14,7 +14,7 @@ def _name(self) -> str: @property def _version(self) -> str: # Mod version - return '0.3.0-rc2' + return '0.3.0-rc2-experimental' @property def _author(self) -> str: From de3a38935ef62e037481a069b3cde06cdc965b65 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 14:58:18 -0600 Subject: [PATCH 054/134] remove lib. --- Scripts/s4ap/ModConstructor/Cactus_S4AP.py | 2 +- Scripts/s4ap/events/items/receive_item_event.py | 2 +- Scripts/s4ap/persistance/ap_data_manager.py | 2 +- Scripts/s4ap/persistance/ap_data_store.py | 2 +- Scripts/s4ap/persistance/ap_data_utils.py | 2 +- Scripts/s4ap/persistance/ap_session_data_store.py | 2 +- Scripts/s4ap/utils/s4ap_career_utils.py | 4 ++-- Scripts/s4ap/utils/s4ap_generic_utils.py | 2 +- Scripts/s4ap/utils/s4ap_household_utils.py | 2 +- Scripts/s4ap/utils/s4ap_localization_utils.py | 2 +- Scripts/s4ap/utils/s4ap_sim_utils.py | 2 +- Scripts/s4ap/utils/s4ap_skill_utils.py | 2 +- Scripts/s4ap/utils/s4ap_trait_utils.py | 2 +- 13 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Scripts/s4ap/ModConstructor/Cactus_S4AP.py b/Scripts/s4ap/ModConstructor/Cactus_S4AP.py index 5721f28..e97ec39 100644 --- a/Scripts/s4ap/ModConstructor/Cactus_S4AP.py +++ b/Scripts/s4ap/ModConstructor/Cactus_S4AP.py @@ -1,4 +1,4 @@ -from lib.functools import wraps +from functools import wraps import services import sims4.resources from sims4.tuning.instance_manager import InstanceManager diff --git a/Scripts/s4ap/events/items/receive_item_event.py b/Scripts/s4ap/events/items/receive_item_event.py index 2f47cb0..7a62d7f 100644 --- a/Scripts/s4ap/events/items/receive_item_event.py +++ b/Scripts/s4ap/events/items/receive_item_event.py @@ -16,7 +16,7 @@ from sims4.resources import Types from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from lib.collections import Counter +from collections import Counter log = S4APLogger.get_log() log.enable() diff --git a/Scripts/s4ap/persistance/ap_data_manager.py b/Scripts/s4ap/persistance/ap_data_manager.py index 523260e..b9efe43 100644 --- a/Scripts/s4ap/persistance/ap_data_manager.py +++ b/Scripts/s4ap/persistance/ap_data_manager.py @@ -1,4 +1,4 @@ -from lib.typing import Tuple +from typing import Tuple from s4ap.modinfo import ModInfo from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity diff --git a/Scripts/s4ap/persistance/ap_data_store.py b/Scripts/s4ap/persistance/ap_data_store.py index e17d3cb..9cec1b3 100644 --- a/Scripts/s4ap/persistance/ap_data_store.py +++ b/Scripts/s4ap/persistance/ap_data_store.py @@ -1,4 +1,4 @@ -from lib.typing import Any, Dict +from typing import Any, Dict from s4ap.sims4communitylib.persistence.data_stores.common_data_store import CommonDataStore diff --git a/Scripts/s4ap/persistance/ap_data_utils.py b/Scripts/s4ap/persistance/ap_data_utils.py index ecce855..def0fd2 100644 --- a/Scripts/s4ap/persistance/ap_data_utils.py +++ b/Scripts/s4ap/persistance/ap_data_utils.py @@ -1,4 +1,4 @@ -from lib.typing import Type, Union, Dict, Any +from typing import Type, Union, Dict, Any from s4ap.modinfo import ModInfo from s4ap.persistance.ap_data_manager import S4APDataManager diff --git a/Scripts/s4ap/persistance/ap_session_data_store.py b/Scripts/s4ap/persistance/ap_session_data_store.py index 99f5820..b7dda0f 100644 --- a/Scripts/s4ap/persistance/ap_session_data_store.py +++ b/Scripts/s4ap/persistance/ap_session_data_store.py @@ -1,4 +1,4 @@ -from lib.typing import Any +from typing import Any from s4ap.jsonio.s4ap_json import print_json from s4ap.events.Utils.allow_read_items import AllowReceiveItems from s4ap.logging.s4ap_logger import S4APLogger diff --git a/Scripts/s4ap/utils/s4ap_career_utils.py b/Scripts/s4ap/utils/s4ap_career_utils.py index 6aed926..7ed14a5 100644 --- a/Scripts/s4ap/utils/s4ap_career_utils.py +++ b/Scripts/s4ap/utils/s4ap_career_utils.py @@ -1,6 +1,6 @@ from careers.career_tuning import Career, CareerLevel, TunableCareerTrack -from lib.random import random -from lib.typing import Callable, Iterator, Tuple, Union +from random import random +from typing import Callable, Iterator, Tuple, Union from services import get_instance_manager from sims.sim_info import SimInfo from sims4.resources import Types diff --git a/Scripts/s4ap/utils/s4ap_generic_utils.py b/Scripts/s4ap/utils/s4ap_generic_utils.py index 4e170f7..1989ef5 100644 --- a/Scripts/s4ap/utils/s4ap_generic_utils.py +++ b/Scripts/s4ap/utils/s4ap_generic_utils.py @@ -1,5 +1,5 @@ import services -from lib.typing import Union +from typing import Union from s4ap.modinfo import ModInfo from services.persistence_service import SaveGameData from sims4.resources import Types diff --git a/Scripts/s4ap/utils/s4ap_household_utils.py b/Scripts/s4ap/utils/s4ap_household_utils.py index 857d2fa..1f0171d 100644 --- a/Scripts/s4ap/utils/s4ap_household_utils.py +++ b/Scripts/s4ap/utils/s4ap_household_utils.py @@ -1,6 +1,6 @@ import services from services import active_household -from lib.typing import Iterator, Union +from typing import Iterator, Union from sims.household import Household from sims.sim_info import SimInfo diff --git a/Scripts/s4ap/utils/s4ap_localization_utils.py b/Scripts/s4ap/utils/s4ap_localization_utils.py index 1d035bb..6691bab 100644 --- a/Scripts/s4ap/utils/s4ap_localization_utils.py +++ b/Scripts/s4ap/utils/s4ap_localization_utils.py @@ -1,6 +1,6 @@ from protocolbuffers.Localization_pb2 import LocalizedString -from lib.typing import Any +from typing import Any from sims4.localization import LocalizationHelperTuning, _create_localized_string, create_tokens class S4APLocalizationUtils: diff --git a/Scripts/s4ap/utils/s4ap_sim_utils.py b/Scripts/s4ap/utils/s4ap_sim_utils.py index 181d363..68b9a10 100644 --- a/Scripts/s4ap/utils/s4ap_sim_utils.py +++ b/Scripts/s4ap/utils/s4ap_sim_utils.py @@ -1,5 +1,5 @@ import services -from lib.typing import Union +from typing import Union from s4ap.utils.s4ap_game_client_utils import S4APGameClientUtils from sims.sim import Sim from sims.sim_info import SimInfo diff --git a/Scripts/s4ap/utils/s4ap_skill_utils.py b/Scripts/s4ap/utils/s4ap_skill_utils.py index 8779b04..9d59fe5 100644 --- a/Scripts/s4ap/utils/s4ap_skill_utils.py +++ b/Scripts/s4ap/utils/s4ap_skill_utils.py @@ -1,7 +1,7 @@ import re import services -from lib.typing import Callable, Iterator, Union +from typing import Callable, Iterator, Union from s4ap.enums.S4APLocalization import S4APTraitId from s4ap.events.skill_event_dispatcher import SimSkillLeveledUpEvent from s4ap.logging.s4ap_logger import S4APLogger diff --git a/Scripts/s4ap/utils/s4ap_trait_utils.py b/Scripts/s4ap/utils/s4ap_trait_utils.py index cf5d54f..7b71c88 100644 --- a/Scripts/s4ap/utils/s4ap_trait_utils.py +++ b/Scripts/s4ap/utils/s4ap_trait_utils.py @@ -1,4 +1,4 @@ -from lib.typing import Iterator, Optional, Union +from typing import Iterator, Optional, Union from s4ap.utils.s4ap_generic_utils import S4APUtils from sims.sim_info import SimInfo from sims4.resources import Types From d98f3b027e7c4da55b7065684bd7b1252f77c5c0 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 15:01:40 -0600 Subject: [PATCH 055/134] remove faulty lib imports stopping loading --- Scripts/s4ap/ModConstructor/Cactus_S4AP.py | 2 +- Scripts/s4ap/events/items/receive_item_event.py | 2 +- Scripts/s4ap/persistance/ap_data_manager.py | 2 +- Scripts/s4ap/persistance/ap_data_store.py | 2 +- Scripts/s4ap/persistance/ap_data_utils.py | 2 +- Scripts/s4ap/persistance/ap_session_data_store.py | 2 +- Scripts/s4ap/utils/s4ap_career_utils.py | 4 ++-- Scripts/s4ap/utils/s4ap_generic_utils.py | 2 +- Scripts/s4ap/utils/s4ap_household_utils.py | 2 +- Scripts/s4ap/utils/s4ap_localization_utils.py | 2 +- Scripts/s4ap/utils/s4ap_sim_utils.py | 2 +- Scripts/s4ap/utils/s4ap_skill_utils.py | 2 +- Scripts/s4ap/utils/s4ap_trait_utils.py | 2 +- 13 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Scripts/s4ap/ModConstructor/Cactus_S4AP.py b/Scripts/s4ap/ModConstructor/Cactus_S4AP.py index 5721f28..e97ec39 100644 --- a/Scripts/s4ap/ModConstructor/Cactus_S4AP.py +++ b/Scripts/s4ap/ModConstructor/Cactus_S4AP.py @@ -1,4 +1,4 @@ -from lib.functools import wraps +from functools import wraps import services import sims4.resources from sims4.tuning.instance_manager import InstanceManager diff --git a/Scripts/s4ap/events/items/receive_item_event.py b/Scripts/s4ap/events/items/receive_item_event.py index 6fc51f4..42e376c 100644 --- a/Scripts/s4ap/events/items/receive_item_event.py +++ b/Scripts/s4ap/events/items/receive_item_event.py @@ -16,7 +16,7 @@ from sims4.resources import Types from sims4communitylib.events.event_handling.common_event import CommonEvent from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from lib.collections import Counter +from collections import Counter log = S4APLogger.get_log() log.enable() diff --git a/Scripts/s4ap/persistance/ap_data_manager.py b/Scripts/s4ap/persistance/ap_data_manager.py index 2361b9b..be7a3bd 100644 --- a/Scripts/s4ap/persistance/ap_data_manager.py +++ b/Scripts/s4ap/persistance/ap_data_manager.py @@ -1,4 +1,4 @@ -from lib.typing import Tuple +from typing import Tuple from s4ap.modinfo import ModInfo from sims4communitylib.mod_support.mod_identity import CommonModIdentity diff --git a/Scripts/s4ap/persistance/ap_data_store.py b/Scripts/s4ap/persistance/ap_data_store.py index a04bc63..9a5f6c5 100644 --- a/Scripts/s4ap/persistance/ap_data_store.py +++ b/Scripts/s4ap/persistance/ap_data_store.py @@ -1,4 +1,4 @@ -from lib.typing import Any, Dict +from typing import Any, Dict from sims4communitylib.persistence.data_stores.common_data_store import CommonDataStore diff --git a/Scripts/s4ap/persistance/ap_data_utils.py b/Scripts/s4ap/persistance/ap_data_utils.py index 22d5e97..4c59ceb 100644 --- a/Scripts/s4ap/persistance/ap_data_utils.py +++ b/Scripts/s4ap/persistance/ap_data_utils.py @@ -1,4 +1,4 @@ -from lib.typing import Type, Union, Dict, Any +from typing import Type, Union, Dict, Any from s4ap.modinfo import ModInfo from s4ap.persistance.ap_data_manager import S4APDataManager diff --git a/Scripts/s4ap/persistance/ap_session_data_store.py b/Scripts/s4ap/persistance/ap_session_data_store.py index 844d4af..1097a4f 100644 --- a/Scripts/s4ap/persistance/ap_session_data_store.py +++ b/Scripts/s4ap/persistance/ap_session_data_store.py @@ -1,4 +1,4 @@ -from lib.typing import Any +from typing import Any from s4ap.jsonio.s4ap_json import print_json from s4ap.events.Utils.allow_read_items import AllowReceiveItems from s4ap.logging.s4ap_logger import S4APLogger diff --git a/Scripts/s4ap/utils/s4ap_career_utils.py b/Scripts/s4ap/utils/s4ap_career_utils.py index 6aed926..7ed14a5 100644 --- a/Scripts/s4ap/utils/s4ap_career_utils.py +++ b/Scripts/s4ap/utils/s4ap_career_utils.py @@ -1,6 +1,6 @@ from careers.career_tuning import Career, CareerLevel, TunableCareerTrack -from lib.random import random -from lib.typing import Callable, Iterator, Tuple, Union +from random import random +from typing import Callable, Iterator, Tuple, Union from services import get_instance_manager from sims.sim_info import SimInfo from sims4.resources import Types diff --git a/Scripts/s4ap/utils/s4ap_generic_utils.py b/Scripts/s4ap/utils/s4ap_generic_utils.py index c6bd3db..846761a 100644 --- a/Scripts/s4ap/utils/s4ap_generic_utils.py +++ b/Scripts/s4ap/utils/s4ap_generic_utils.py @@ -1,5 +1,5 @@ import services -from lib.typing import Union +from typing import Union from s4ap.modinfo import ModInfo from services.persistence_service import SaveGameData from sims4.resources import Types diff --git a/Scripts/s4ap/utils/s4ap_household_utils.py b/Scripts/s4ap/utils/s4ap_household_utils.py index 857d2fa..1f0171d 100644 --- a/Scripts/s4ap/utils/s4ap_household_utils.py +++ b/Scripts/s4ap/utils/s4ap_household_utils.py @@ -1,6 +1,6 @@ import services from services import active_household -from lib.typing import Iterator, Union +from typing import Iterator, Union from sims.household import Household from sims.sim_info import SimInfo diff --git a/Scripts/s4ap/utils/s4ap_localization_utils.py b/Scripts/s4ap/utils/s4ap_localization_utils.py index 1d035bb..6691bab 100644 --- a/Scripts/s4ap/utils/s4ap_localization_utils.py +++ b/Scripts/s4ap/utils/s4ap_localization_utils.py @@ -1,6 +1,6 @@ from protocolbuffers.Localization_pb2 import LocalizedString -from lib.typing import Any +from typing import Any from sims4.localization import LocalizationHelperTuning, _create_localized_string, create_tokens class S4APLocalizationUtils: diff --git a/Scripts/s4ap/utils/s4ap_sim_utils.py b/Scripts/s4ap/utils/s4ap_sim_utils.py index 181d363..68b9a10 100644 --- a/Scripts/s4ap/utils/s4ap_sim_utils.py +++ b/Scripts/s4ap/utils/s4ap_sim_utils.py @@ -1,5 +1,5 @@ import services -from lib.typing import Union +from typing import Union from s4ap.utils.s4ap_game_client_utils import S4APGameClientUtils from sims.sim import Sim from sims.sim_info import SimInfo diff --git a/Scripts/s4ap/utils/s4ap_skill_utils.py b/Scripts/s4ap/utils/s4ap_skill_utils.py index 8d7a7a0..e392816 100644 --- a/Scripts/s4ap/utils/s4ap_skill_utils.py +++ b/Scripts/s4ap/utils/s4ap_skill_utils.py @@ -1,7 +1,7 @@ import re import services -from lib.typing import Callable, Iterator, Union +from typing import Callable, Iterator, Union from s4ap.enums.S4APLocalization import S4APTraitId from s4ap.events.skill_event_dispatcher import SimSkillLeveledUpEvent from s4ap.logging.s4ap_logger import S4APLogger diff --git a/Scripts/s4ap/utils/s4ap_trait_utils.py b/Scripts/s4ap/utils/s4ap_trait_utils.py index cf5d54f..7b71c88 100644 --- a/Scripts/s4ap/utils/s4ap_trait_utils.py +++ b/Scripts/s4ap/utils/s4ap_trait_utils.py @@ -1,4 +1,4 @@ -from lib.typing import Iterator, Optional, Union +from typing import Iterator, Optional, Union from s4ap.utils.s4ap_generic_utils import S4APUtils from sims.sim_info import SimInfo from sims4.resources import Types From ded70cfdbc764a7659934aab516380f30b1f0a6e Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 15:07:10 -0600 Subject: [PATCH 056/134] fix the imports in bundled s4cl?? --- ...on_attach_cas_parts_appearance_modifier.py | 22 ++--- .../classes/buffs/common_buff.py | 6 +- .../calculations/common_available_for_sim.py | 10 +-- .../classes/commodities/common_commodity.py | 4 +- .../classes/common_resource_key.py | 2 +- .../classes/effects/common_visual_effect.py | 4 +- .../common_versioned_enum_value_collection.py | 8 +- ...rsioned_sim_demographic_type_collection.py | 4 +- ...common_match_all_non_sims_object_filter.py | 4 +- .../common_match_all_sims_object_filter.py | 4 +- .../filters/common_match_object_filter.py | 2 +- .../_common_interaction_custom_mixin.py | 4 +- .../_common_interaction_hooks_mixin.py | 4 +- .../common_immediate_super_interaction.py | 20 ++--- .../interactions/common_interaction.py | 18 ++-- .../common_interaction_override_name.py | 4 +- .../interactions/common_mixer_interaction.py | 18 ++-- .../interactions/common_object_interaction.py | 6 +- .../common_social_mixer_interaction.py | 18 ++-- .../common_social_super_interaction.py | 18 ++-- .../interactions/common_super_interaction.py | 20 ++--- .../common_terrain_interaction.py | 6 +- .../classes/math/common_location.py | 4 +- .../classes/math/common_polygon.py | 2 +- .../classes/math/common_quaternion.py | 8 +- .../classes/math/common_routing_location.py | 10 +-- .../classes/math/common_surface_identifier.py | 2 +- .../classes/math/common_transform.py | 4 +- .../math/common_weighted_value_tally.py | 2 +- .../mixins/common_interactions_mixin.py | 2 +- .../resolvers/common_double_sim_resolver.py | 2 +- .../classes/runnables/common_runnable.py | 22 ++--- .../runnables/common_runnable_with_sims.py | 14 +-- .../contexts/common_runnable_context.py | 12 +-- .../common_runnable_context_with_sims.py | 12 +-- .../common_runnable_object_context.py | 12 +-- .../contexts/common_runnable_sim_context.py | 16 ++-- .../common_serializable_location.py | 12 +-- .../common_sim_to_sim_test_based_score.py | 8 +- .../common_single_sim_test_based_score.py | 8 +- .../common_test_based_score.py | 4 +- .../classes/testing/common_enqueue_result.py | 4 +- .../testing/common_execution_result.py | 6 +- .../classes/testing/common_test_result.py | 8 +- .../classes/time/common_alarm_handle.py | 8 +- .../classes/time/common_stop_watch.py | 4 +- .../conditionals/common_conditional_action.py | 4 +- .../common_change_object_state_dialog.py | 16 ++-- .../interactions/_register_interactions.py | 16 ++-- .../interactions/change_object_states.py | 16 ++-- .../debug/interactions/induce_labor.py | 20 ++--- .../debug/interactions/log_all_game_tags.py | 16 ++-- .../interactions/log_all_interactions.py | 26 +++--- .../debug/interactions/object_break.py | 12 +-- .../debug/interactions/object_fix.py | 12 +-- .../debug/interactions/object_make_clean.py | 12 +-- .../debug/interactions/object_make_dirty.py | 12 +-- .../debug/interactions/show_active_buffs.py | 20 ++--- .../show_running_and_queued_interactions.py | 22 ++--- .../interactions/show_running_situations.py | 22 ++--- .../debug/interactions/show_traits.py | 20 ++--- .../debug/traits/_auto_apply_traits.py | 14 +-- ...on_ui_dialog_multi_text_input_ok_cancel.py | 8 +- .../_common_ui_dialog_text_input_ok_cancel.py | 4 +- .../dialogs/choose_item_dialog.py | 24 ++--- .../dialogs/choose_object_dialog.py | 36 ++++---- .../dialogs/choose_objects_dialog.py | 32 +++---- .../dialogs/common_choice_outcome.py | 2 +- .../dialogs/common_choose_dialog.py | 8 +- .../dialogs/common_choose_outfit_dialog.py | 28 +++--- .../dialogs/common_choose_response_dialog.py | 28 +++--- .../dialogs/common_choose_sim_dialog.py | 28 +++--- .../dialogs/common_choose_sims_dialog.py | 30 +++---- .../dialogs/common_dialog.py | 8 +- .../dialogs/common_input_float_dialog.py | 28 +++--- .../dialogs/common_input_integer_dialog.py | 28 +++--- .../dialogs/common_input_multi_text_dialog.py | 32 +++---- .../dialogs/common_input_text_dialog.py | 28 +++--- .../dialogs/common_input_text_field.py | 6 +- .../common_multi_pane_choose_dialog.py | 34 +++---- .../dialogs/common_ok_dialog.py | 20 ++--- .../dialogs/common_purchase_objects_dialog.py | 36 ++++---- .../common_targeted_question_dialog.py | 22 ++--- .../dialogs/common_ui_dialog_response.py | 4 +- .../dialogs/common_ui_response_dialog.py | 20 ++--- .../picker_dialogs/common_ui_multi_picker.py | 2 +- .../dialogs/ok_cancel_dialog.py | 20 ++--- .../common_choose_button_option_dialog.py | 28 +++--- .../common_choose_object_option_dialog.py | 32 +++---- .../common_choose_objects_option_dialog.py | 32 +++---- .../common_choose_option_dialog.py | 10 +-- .../common_choose_options_dialog.py | 12 +-- .../common_choose_response_option_dialog.py | 12 +-- .../common_choose_sim_option_dialog.py | 28 +++--- .../common_choose_sims_option_dialog.py | 28 +++--- .../common_multi_pane_choose_option_dialog.py | 36 ++++---- .../option_dialogs/common_option_dialog.py | 8 +- .../options/common_dialog_option.py | 6 +- .../options/common_dialog_option_context.py | 4 +- .../objects/common_dialog_action_option.py | 6 +- .../objects/common_dialog_branch_option.py | 8 +- .../common_dialog_input_integer_option.py | 18 ++-- .../common_dialog_input_multi_text_option.py | 20 ++--- .../objects/common_dialog_input_option.py | 16 ++-- .../common_dialog_input_text_option.py | 18 ++-- .../objects/common_dialog_object_option.py | 6 +- .../objects/common_dialog_option_category.py | 4 +- .../objects/common_dialog_select_option.py | 8 +- .../objects/common_dialog_toggle_option.py | 10 +-- .../response/common_dialog_button_option.py | 8 +- .../response/common_dialog_response_option.py | 6 +- .../common_dialog_response_option_context.py | 4 +- .../options/sims/common_dialog_sim_option.py | 8 +- .../sims/common_dialog_sim_option_context.py | 2 +- ...mon_choose_sim_demographic_types_dialog.py | 22 ++--- ...common_premade_choose_sim_option_dialog.py | 28 +++--- ...ommon_premade_choose_sims_option_dialog.py | 28 +++--- .../sims4communitylib/dtos/common_cas_part.py | 4 +- .../sims4communitylib/dtos/common_outfit.py | 10 +-- .../enums/affordance_list_ids.py | 2 +- .../enums/animation_state_machines_enum.py | 2 +- .../sims4communitylib/enums/buffs_enum.py | 2 +- .../sims4communitylib/enums/clubs_enum.py | 2 +- .../sims4communitylib/enums/common_age.py | 6 +- .../common_appearance_modifier_priority.py | 2 +- .../enums/common_appearance_modifier_type.py | 2 +- .../enums/common_body_frame.py | 8 +- .../enums/common_body_slot.py | 2 +- .../enums/common_bucks_types.py | 2 +- .../enums/common_business_advertising_type.py | 2 +- ...mmon_business_customer_star_rating_type.py | 2 +- .../enums/common_business_employee_type.py | 2 +- .../enums/common_business_quality_type.py | 2 +- .../enums/common_career_ids.py | 2 +- .../enums/common_character_restrictions.py | 2 +- .../enums/common_civic_policy_status_type.py | 2 +- .../enums/common_civic_policy_type.py | 2 +- .../enums/common_cloud_type.py | 2 +- .../enums/common_combined_species.py | 2 +- .../enums/common_currency_modify_reasons.py | 2 +- .../enums/common_death_types.py | 2 +- .../sims4communitylib/enums/common_enum.py | 2 +- .../enums/common_fund_types.py | 2 +- .../enums/common_funds_sources.py | 2 +- .../enums/common_game_tag_category.py | 2 +- .../sims4communitylib/enums/common_gender.py | 6 +- .../enums/common_gender_preference_type.py | 2 +- .../enums/common_ground_cover_type.py | 2 +- .../sims4communitylib/enums/common_key.py | 2 +- .../enums/common_object_delivery_method.py | 2 +- .../enums/common_object_filter_type.py | 2 +- .../enums/common_object_preference_tag.py | 2 +- .../enums/common_object_quality.py | 2 +- .../enums/common_object_slot_name_ids.py | 2 +- .../enums/common_object_state_ids.py | 2 +- .../enums/common_object_state_value_ids.py | 2 +- .../enums/common_occult_type.py | 10 +-- .../enums/common_posture_id.py | 2 +- .../enums/common_precipitation_type.py | 2 +- .../enums/common_pregnancy_origin.py | 2 +- .../enums/common_puddle_liquid.py | 2 +- .../enums/common_puddle_size.py | 2 +- .../enums/common_region_id.py | 2 +- .../enums/common_runnable_state.py | 2 +- .../enums/common_runnable_state_type.py | 2 +- .../sims4communitylib/enums/common_side.py | 4 +- .../enums/common_sim_demographic_types.py | 6 +- .../enums/common_sim_name_type.py | 2 +- .../enums/common_skill_effectiveness.py | 2 +- .../sims4communitylib/enums/common_species.py | 8 +- .../enums/common_statistic_category.py | 4 +- .../enums/common_street_civic_policy_ids.py | 2 +- .../enums/common_temperature.py | 2 +- .../enums/common_venue_civic_policy_ids.py | 2 +- .../enums/common_voice_actor_type.py | 2 +- .../enums/common_weather_effect_type.py | 2 +- .../enums/common_weather_event_ids.py | 2 +- .../enums/common_weather_type.py | 4 +- .../enums/enumtypes/common_versioned_int.py | 4 +- .../enumtypes/common_versioned_int_flags.py | 4 +- .../enums/enumtypes/float_enum.py | 2 +- .../enums/enumtypes/int_enum.py | 2 +- .../enums/enumtypes/object_enum.py | 2 +- .../enums/enumtypes/string_enum.py | 2 +- .../enums/furniture_objects_enum.py | 2 +- .../sims4communitylib/enums/icons_enum.py | 2 +- .../enums/interactions_enum.py | 2 +- .../enums/long_term_sentiments_enum.py | 2 +- .../enums/lot_traits_enum.py | 2 +- .../sims4communitylib/enums/moods_enum.py | 2 +- .../sims4communitylib/enums/motives_enum.py | 2 +- .../relationship_bit_collection_uids_enum.py | 2 +- .../relationship_bit_collections_enum.py | 2 +- .../enums/relationship_bits_enum.py | 2 +- .../enums/relationship_tracks_enum.py | 2 +- .../enums/relationship_types_enum.py | 2 +- .../short_term_relationship_tracks_enum.py | 2 +- .../enums/short_term_sentiments_enum.py | 2 +- .../s4ap/sims4communitylib/enums/sim_type.py | 2 +- .../enums/situation_jobs_enum.py | 2 +- .../enums/situations_enum.py | 2 +- .../sims4communitylib/enums/skills_enum.py | 2 +- .../enums/statistics_enum.py | 2 +- .../sims4communitylib/enums/strings_enum.py | 2 +- .../s4ap/sims4communitylib/enums/tags_enum.py | 2 +- .../sims4communitylib/enums/traits_enum.py | 2 +- .../sims4communitylib/enums/venues_enum.py | 2 +- .../sims4communitylib/enums/whims_enum.py | 2 +- .../enums/world_types_enum.py | 2 +- .../common_build_buy_event_dispatcher.py | 16 ++-- .../build_buy/events/build_buy_enter.py | 6 +- .../events/build_buy/events/build_buy_exit.py | 6 +- .../event_handling/common_event_handler.py | 6 +- .../event_handling/common_event_registry.py | 12 +-- .../common_game_object_event_dispatcher.py | 28 +++--- ...e_object_added_to_game_object_inventory.py | 8 +- .../events/game_object_added_to_inventory.py | 6 +- .../events/game_object_initialized.py | 6 +- .../game_object/events/game_object_loaded.py | 6 +- .../events/game_object_pre_deleted.py | 6 +- .../events/game_object_pre_despawned.py | 6 +- ..._pre_removed_from_game_object_inventory.py | 8 +- .../game_object_pre_removed_from_inventory.py | 6 +- .../game_object/events/game_object_spawned.py | 6 +- .../common_interaction_event_dispatcher.py | 38 ++++---- .../events/interaction_cancelled.py | 6 +- .../interaction/events/interaction_outcome.py | 6 +- .../events/interaction_post_queued.py | 8 +- .../interaction/events/interaction_pre_run.py | 6 +- .../interaction/events/interaction_queued.py | 8 +- .../interaction/events/interaction_run.py | 6 +- .../interaction/events/interaction_started.py | 6 +- .../events/mixer_interaction_cancelled.py | 6 +- .../events/super_interaction_cancelled.py | 6 +- .../interval/common_interval_event_service.py | 16 ++-- .../save/common_save_event_dispatcher.py | 14 +-- .../events/save/events/save_loaded.py | 6 +- .../events/save/events/save_saved.py | 6 +- .../events/sim/common_sim_event_dispatcher.py | 90 +++++++++---------- .../game_object_added_to_sim_inventory.py | 8 +- ...e_object_pre_removed_from_sim_inventory.py | 8 +- .../sim/events/sim_added_occult_type.py | 6 +- .../events/sim_after_set_current_outfit.py | 6 +- .../events/sim/events/sim_buff_added.py | 8 +- .../events/sim/events/sim_buff_removed.py | 8 +- .../events/sim/events/sim_changed_age.py | 8 +- .../events/sim/events/sim_changed_gender.py | 8 +- .../sim_changed_gender_options_body_frame.py | 6 +- .../sim_changed_gender_options_breasts.py | 6 +- ...anged_gender_options_can_be_impregnated.py | 6 +- ...m_changed_gender_options_can_impregnate.py | 6 +- ...im_changed_gender_options_can_reproduce.py | 6 +- ...nged_gender_options_clothing_preference.py | 6 +- ...sim_changed_gender_options_toilet_usage.py | 6 +- .../sim/events/sim_changed_occult_type.py | 6 +- .../sim/events/sim_changing_occult_type.py | 6 +- .../events/sim/events/sim_died.py | 8 +- .../events/sim/events/sim_initialized.py | 6 +- .../events/sim/events/sim_loaded.py | 6 +- .../events/sim/events/sim_pre_despawned.py | 6 +- .../sim/events/sim_relationship_bit_added.py | 8 +- .../events/sim_relationship_bit_removed.py | 8 +- .../sim/events/sim_removed_occult_type.py | 6 +- .../events/sim/events/sim_revived.py | 8 +- .../sim/events/sim_set_current_outfit.py | 6 +- .../events/sim/events/sim_skill_leveled_up.py | 8 +- .../events/sim/events/sim_spawned.py | 6 +- .../events/sim/events/sim_trait_added.py | 8 +- .../events/sim/events/sim_trait_removed.py | 8 +- .../common_zone_spin_event_dispatcher.py | 20 ++--- .../zone_spin/events/zone_early_load.py | 6 +- .../events/zone_spin/events/zone_late_load.py | 6 +- .../events/zone_manager_start_event.py | 6 +- .../events/zone_spin/events/zone_post_load.py | 6 +- .../events/zone_spin/events/zone_save.py | 6 +- .../events/zone_spin/events/zone_teardown.py | 6 +- .../common_zone_update_event_dispatcher.py | 16 ++-- .../zone_update/events/zone_update_event.py | 6 +- .../common_example_apply_bare_feet_buff.py | 16 ++-- .../exceptions/common_exceptions_handler.py | 24 ++--- .../exceptions/common_stacktrace_utils.py | 2 +- .../exceptions/generic_error_handling.py | 8 +- .../logging/_has_s4cl_class_log.py | 6 +- .../logging/_has_s4cl_log.py | 6 +- .../logging/_logging_commands.py | 8 +- .../logging/has_class_log.py | 12 +-- .../s4ap/sims4communitylib/logging/has_log.py | 10 +-- .../logging/vanilla_logging.py | 18 ++-- .../mod_support/common_mod_info.py | 6 +- .../mod_support/has_class_mod_identity.py | 4 +- .../mod_support/has_mod_identity.py | 2 +- .../mod_support/mod_identity.py | 2 +- Scripts/s4ap/sims4communitylib/modinfo.py | 2 +- .../common_basic_notification.py | 14 +-- .../common_game_object_data_storage.py | 14 +-- ...mmon_persisted_game_object_data_storage.py | 16 ++-- .../common_persisted_sim_data_storage.py | 16 ++-- .../persistence/common_sim_data_storage.py | 16 ++-- .../data_management/common_data_manager.py | 8 +- .../common_data_manager_registry.py | 36 ++++---- .../data_stores/common_data_store.py | 2 +- .../common_game_object_data_store.py | 2 +- .../data_stores/common_sim_data_store.py | 2 +- .../common_file_persistence_service.py | 14 +-- .../common_folder_persistence_service.py | 14 +-- ...on_hidden_household_persistence_service.py | 6 +- ...n_individual_folder_persistence_service.py | 10 +-- .../common_persistence_service.py | 6 +- .../s4ap/sims4communitylib/s4cl_commands.py | 20 ++--- .../sims4communitylib/s4cl_configuration.py | 16 ++-- .../commands/common_console_command.py | 24 ++--- .../commands/common_console_command_output.py | 2 +- .../common_console_command_parameters.py | 18 ++-- .../interaction_registration_service.py | 18 ++-- ..._instance_manager_modification_registry.py | 10 +-- .../common_posture_constraint_service.py | 2 +- ...nteractions_to_affordance_lists_handler.py | 6 +- .../services/sim/cas/common_sim_outfit_io.py | 14 +-- ...mmon_temporary_sim_clone_in_cas_service.py | 34 +++---- .../common_serializable_object_cache.py | 2 +- ...ommon_serializable_object_cache_service.py | 16 ++-- .../common_loaded_item_query_registry.py | 30 +++---- .../item_query/common_loaded_item_registry.py | 16 ++-- .../item_query/dtos/common_loaded_item.py | 10 +-- .../enums/common_query_method_type.py | 2 +- .../item_loaders/common_base_item_loader.py | 10 +-- .../common_loaded_item_is_available_test.py | 10 +-- ...ommon_loaded_item_is_not_available_test.py | 10 +-- .../item_tests/common_loaded_item_test.py | 8 +- .../persistence/common_loaded_item_cache.py | 4 +- .../common_loaded_item_cache_service.py | 8 +- .../query/common_loaded_item_filter.py | 10 +-- .../common_loaded_item_filter_request.py | 8 +- .../query/common_loaded_item_key.py | 4 +- .../query/common_loaded_item_organizer.py | 6 +- .../query/common_loaded_item_query_utils.py | 20 ++--- .../systems/settings/common_setting_utils.py | 14 +-- .../settings/common_settings_data_manager.py | 8 +- .../common_settings_data_manager_utils.py | 12 +-- .../settings/common_settings_data_store.py | 2 +- .../testing/common_assertion_utils.py | 6 +- .../testing/common_test_service.py | 22 ++--- .../utils/cas/common_cas_utils.py | 30 +++---- .../utils/cas/common_outfit_utils.py | 34 +++---- .../utils/common_component_utils.py | 2 +- .../utils/common_function_utils.py | 12 +-- .../utils/common_icon_utils.py | 6 +- .../utils/common_injection_utils.py | 14 +-- .../utils/common_json_io_utils.py | 4 +- .../utils/common_keyboard_utils.py | 8 +- .../utils/common_log_registry.py | 46 +++++----- .../utils/common_log_utils.py | 10 +-- .../utils/common_math_utils.py | 2 +- .../utils/common_resource_utils.py | 8 +- .../utils/common_time_utils.py | 6 +- .../utils/common_type_utils.py | 8 +- .../utils/common_weather_utils.py | 20 ++--- .../effects/common_visual_effect_commands.py | 20 ++--- .../environment/common_business_utils.py | 4 +- .../environment/common_civic_policy_utils.py | 18 ++-- .../localization/common_localization_utils.py | 6 +- .../common_localized_string_colors.py | 4 +- .../common_localized_string_separators.py | 4 +- .../utils/location/common_location_utils.py | 16 ++-- .../utils/location/common_terrain_utils.py | 4 +- .../utils/location/common_travel_utils.py | 2 +- .../utils/math/common_bitwise_utils.py | 4 +- .../utils/misc/common_camera_utils.py | 12 +-- .../utils/misc/common_fire_utils.py | 2 +- .../utils/misc/common_mod_identity_utils.py | 4 +- .../objects/common_object_household_utils.py | 4 +- .../common_object_interaction_utils.py | 24 ++--- .../objects/common_object_inventory_utils.py | 14 +-- .../objects/common_object_location_utils.py | 26 +++--- .../utils/objects/common_object_lock_utils.py | 8 +- .../objects/common_object_ownership_utils.py | 8 +- .../common_object_reservation_utils.py | 14 +-- .../utils/objects/common_object_slot_utils.py | 12 +-- .../objects/common_object_spawn_utils.py | 38 ++++---- .../objects/common_object_state_utils.py | 32 +++---- .../utils/objects/common_object_tag_utils.py | 18 ++-- .../utils/objects/common_object_type_utils.py | 8 +- .../utils/objects/common_object_utils.py | 14 +-- .../utils/resources/common_club_utils.py | 4 +- .../resources/common_interaction_utils.py | 18 ++-- .../resources/common_loot_action_utils.py | 2 +- .../utils/resources/common_recipe_utils.py | 6 +- .../utils/resources/common_situation_utils.py | 8 +- .../utils/resources/common_skill_utils.py | 6 +- .../utils/resources/common_statistic_utils.py | 6 +- .../utils/sims/common_age_species_utils.py | 4 +- .../utils/sims/common_age_utils.py | 12 +-- .../utils/sims/common_buff_utils.py | 28 +++--- .../utils/sims/common_career_level_utils.py | 2 +- .../utils/sims/common_career_track_utils.py | 4 +- .../utils/sims/common_career_utils.py | 12 +-- .../utils/sims/common_gender_utils.py | 20 ++--- .../utils/sims/common_household_utils.py | 20 ++--- .../utils/sims/common_mood_utils.py | 2 +- .../utils/sims/common_occult_utils.py | 48 +++++----- .../utils/sims/common_phone_utils.py | 8 +- .../utils/sims/common_rabbit_hole_utils.py | 2 +- .../utils/sims/common_relationship_utils.py | 26 +++--- .../common_sim_appearance_modifier_utils.py | 4 +- .../utils/sims/common_sim_autonomy_utils.py | 8 +- .../utils/sims/common_sim_body_utils.py | 8 +- .../utils/sims/common_sim_bucks_utils.py | 16 ++-- .../utils/sims/common_sim_career_utils.py | 26 +++--- .../utils/sims/common_sim_club_utils.py | 4 +- .../utils/sims/common_sim_crafting_utils.py | 14 +-- .../utils/sims/common_sim_currency_utils.py | 12 +-- .../utils/sims/common_sim_death_utils.py | 52 +++++------ .../sims/common_sim_demographic_type_utils.py | 78 ++++++++-------- .../sims/common_sim_gender_option_utils.py | 42 ++++----- .../common_sim_gender_preference_utils.py | 26 +++--- .../utils/sims/common_sim_genealogy_utils.py | 6 +- .../sims/common_sim_interaction_utils.py | 36 ++++---- .../utils/sims/common_sim_inventory_utils.py | 28 +++--- .../utils/sims/common_sim_location_utils.py | 40 ++++----- .../sims/common_sim_loot_action_utils.py | 2 +- .../utils/sims/common_sim_motive_utils.py | 26 +++--- .../utils/sims/common_sim_name_utils.py | 16 ++-- .../sims/common_sim_occult_type_utils.py | 20 ++--- .../utils/sims/common_sim_plumbob_utils.py | 10 +-- .../utils/sims/common_sim_posture_utils.py | 18 ++-- .../utils/sims/common_sim_pregnancy_utils.py | 50 +++++------ .../sims/common_sim_rabbit_hole_utils.py | 6 +- ...mmon_sim_relationship_expectation_utils.py | 8 +- .../utils/sims/common_sim_routing_utils.py | 20 ++--- .../utils/sims/common_sim_situation_utils.py | 26 +++--- .../utils/sims/common_sim_skill_utils.py | 12 +-- .../utils/sims/common_sim_spawn_utils.py | 82 ++++++++--------- .../utils/sims/common_sim_spell_utils.py | 20 ++--- .../utils/sims/common_sim_state_utils.py | 12 +-- .../utils/sims/common_sim_statistic_utils.py | 28 +++--- .../utils/sims/common_sim_type_utils.py | 28 +++--- .../utils/sims/common_sim_utils.py | 20 ++--- .../utils/sims/common_sim_voice_utils.py | 46 +++++----- .../utils/sims/common_sim_walkstyle_utils.py | 4 +- .../utils/sims/common_species_utils.py | 22 ++--- .../utils/sims/common_trait_utils.py | 50 +++++------ .../common_terrain_interaction_utils.py | 14 +-- .../terrain/common_terrain_location_utils.py | 4 +- .../utils/time/common_alarm_utils.py | 10 +-- .../common_satisfaction_reward_store_utils.py | 6 +- 445 files changed, 2468 insertions(+), 2468 deletions(-) diff --git a/Scripts/s4ap/sims4communitylib/classes/appearance_modifiers/common_attach_cas_parts_appearance_modifier.py b/Scripts/s4ap/sims4communitylib/classes/appearance_modifiers/common_attach_cas_parts_appearance_modifier.py index eed56c5..cf64de3 100644 --- a/Scripts/s4ap/sims4communitylib/classes/appearance_modifiers/common_attach_cas_parts_appearance_modifier.py +++ b/Scripts/s4ap/sims4communitylib/classes/appearance_modifiers/common_attach_cas_parts_appearance_modifier.py @@ -10,16 +10,16 @@ from sims.outfits.outfit_enums import OutfitCategory, BodyTypeFlag, BodyType from sims.sim_info import SimInfo -from sims4communitylib.dtos.common_cas_part import CommonCASPart -from sims4communitylib.enums.buffs_enum import CommonBuffId -from sims4communitylib.enums.common_appearance_modifier_type import CommonAppearanceModifierType -from sims4communitylib.enums.common_body_slot import CommonBodySlot -from sims4communitylib.logging.has_log import HasLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ +from s4ap.sims4communitylib.dtos.common_cas_part import CommonCASPart +from s4ap.sims4communitylib.enums.buffs_enum import CommonBuffId +from s4ap.sims4communitylib.enums.common_appearance_modifier_type import CommonAppearanceModifierType +from s4ap.sims4communitylib.enums.common_body_slot import CommonBodySlot +from s4ap.sims4communitylib.logging.has_log import HasLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ CommonConsoleCommandArgument -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' @@ -296,7 +296,7 @@ def _apply_cas_parts(self, cas_parts: Tuple[CommonCASPart], source_sim_info: Sim self.log.format_with_message('Applying CAS Parts with ids', sim=original_unmodified_sim_info, cas_part_ids_and_body_types=cas_parts) - from sims4communitylib.utils.cas.common_cas_utils import CommonCASUtils + from s4ap.sims4communitylib.utils.cas.common_cas_utils import CommonCASUtils CommonCASUtils.attach_cas_parts_to_all_outfits_of_sim(modified_sim_info, cas_parts) body_types: Tuple[Union[CommonBodySlot, BodyType, int], ...] = tuple([cas_part.body_type for cas_part in cas_parts]) @@ -349,7 +349,7 @@ def _s4cl_testing_apply_example_bare_feet_buff(output: CommonConsoleCommandOutpu if sim_info is None: return False output(f'Toggling bare feet example buff on Sim {sim_info}.') - from sims4communitylib.utils.sims.common_buff_utils import CommonBuffUtils + from s4ap.sims4communitylib.utils.sims.common_buff_utils import CommonBuffUtils if CommonBuffUtils.has_buff(sim_info, CommonBuffId.S4CL_EXAMPLE_APPLY_BARE_FEET): output(f'Removing bare feet example buff from Sim {sim_info}') CommonBuffUtils.remove_buff(sim_info, CommonBuffId.S4CL_EXAMPLE_APPLY_BARE_FEET) diff --git a/Scripts/s4ap/sims4communitylib/classes/buffs/common_buff.py b/Scripts/s4ap/sims4communitylib/classes/buffs/common_buff.py index a462016..2a2e1af 100644 --- a/Scripts/s4ap/sims4communitylib/classes/buffs/common_buff.py +++ b/Scripts/s4ap/sims4communitylib/classes/buffs/common_buff.py @@ -8,9 +8,9 @@ from typing import Union from buffs.buff import Buff from sims.sim import Sim -from sims4communitylib.logging.has_class_log import HasClassLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.logging.has_class_log import HasClassLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils class CommonBuff(Buff, HasClassLog): diff --git a/Scripts/s4ap/sims4communitylib/classes/calculations/common_available_for_sim.py b/Scripts/s4ap/sims4communitylib/classes/calculations/common_available_for_sim.py index 949829b..213e20a 100644 --- a/Scripts/s4ap/sims4communitylib/classes/calculations/common_available_for_sim.py +++ b/Scripts/s4ap/sims4communitylib/classes/calculations/common_available_for_sim.py @@ -9,10 +9,10 @@ from typing import Tuple, Iterator from sims.sim_info import SimInfo -from sims4communitylib.enums.common_age import CommonAge -from sims4communitylib.enums.common_gender import CommonGender -from sims4communitylib.enums.common_occult_type import CommonOccultType -from sims4communitylib.enums.common_species import CommonSpecies +from s4ap.sims4communitylib.enums.common_age import CommonAge +from s4ap.sims4communitylib.enums.common_gender import CommonGender +from s4ap.sims4communitylib.enums.common_occult_type import CommonOccultType +from s4ap.sims4communitylib.enums.common_species import CommonSpecies class CommonAvailableForSim: @@ -126,7 +126,7 @@ def generate_for_sim(sim_info: SimInfo) -> 'CommonAvailableForSim': :return: An available for matching the specified Sim. :rtype: CommonAvailableForSim """ - from sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils + from s4ap.sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils gender = CommonGender.get_gender(sim_info) if gender == CommonGender.INVALID: genders = tuple() diff --git a/Scripts/s4ap/sims4communitylib/classes/commodities/common_commodity.py b/Scripts/s4ap/sims4communitylib/classes/commodities/common_commodity.py index 7c013c4..fb2119f 100644 --- a/Scripts/s4ap/sims4communitylib/classes/commodities/common_commodity.py +++ b/Scripts/s4ap/sims4communitylib/classes/commodities/common_commodity.py @@ -5,8 +5,8 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.logging.has_class_log import HasClassLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.logging.has_class_log import HasClassLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity from statistics.commodity import Commodity diff --git a/Scripts/s4ap/sims4communitylib/classes/common_resource_key.py b/Scripts/s4ap/sims4communitylib/classes/common_resource_key.py index e5abb81..c6e5939 100644 --- a/Scripts/s4ap/sims4communitylib/classes/common_resource_key.py +++ b/Scripts/s4ap/sims4communitylib/classes/common_resource_key.py @@ -7,7 +7,7 @@ """ import os from typing import Union -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' diff --git a/Scripts/s4ap/sims4communitylib/classes/effects/common_visual_effect.py b/Scripts/s4ap/sims4communitylib/classes/effects/common_visual_effect.py index 780a72c..78fc3cb 100644 --- a/Scripts/s4ap/sims4communitylib/classes/effects/common_visual_effect.py +++ b/Scripts/s4ap/sims4communitylib/classes/effects/common_visual_effect.py @@ -10,8 +10,8 @@ import alarms from date_and_time import TimeSpan from sims.sim import Sim -from sims4communitylib.logging.has_log import HasLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.logging.has_log import HasLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity from vfx import PlayEffect from objects.game_object import GameObject diff --git a/Scripts/s4ap/sims4communitylib/classes/enums/common_versioned_enum_value_collection.py b/Scripts/s4ap/sims4communitylib/classes/enums/common_versioned_enum_value_collection.py index 6e69a1b..e52548d 100644 --- a/Scripts/s4ap/sims4communitylib/classes/enums/common_versioned_enum_value_collection.py +++ b/Scripts/s4ap/sims4communitylib/classes/enums/common_versioned_enum_value_collection.py @@ -7,10 +7,10 @@ """ from typing import Tuple, Union, Dict, Any, Iterator, TypeVar, Generic, Type -from sims4communitylib.enums.enumtypes.common_versioned_int import CommonVersionedInt -from sims4communitylib.enums.enumtypes.common_versioned_int_flags import CommonVersionedIntFlags -from sims4communitylib.classes.serialization.common_serializable import CommonSerializable -from sims4communitylib.utils.common_resource_utils import CommonResourceUtils +from s4ap.sims4communitylib.enums.enumtypes.common_versioned_int import CommonVersionedInt +from s4ap.sims4communitylib.enums.enumtypes.common_versioned_int_flags import CommonVersionedIntFlags +from s4ap.sims4communitylib.classes.serialization.common_serializable import CommonSerializable +from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils CommonEnumType = TypeVar('CommonEnumType', CommonVersionedIntFlags, CommonVersionedInt) diff --git a/Scripts/s4ap/sims4communitylib/classes/enums/common_versioned_sim_demographic_type_collection.py b/Scripts/s4ap/sims4communitylib/classes/enums/common_versioned_sim_demographic_type_collection.py index d3bbcf3..6b997e7 100644 --- a/Scripts/s4ap/sims4communitylib/classes/enums/common_versioned_sim_demographic_type_collection.py +++ b/Scripts/s4ap/sims4communitylib/classes/enums/common_versioned_sim_demographic_type_collection.py @@ -7,8 +7,8 @@ """ from typing import Tuple, Type, Iterator -from sims4communitylib.classes.enums.common_versioned_enum_value_collection import CommonVersionedEnumValueCollection -from sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType +from s4ap.sims4communitylib.classes.enums.common_versioned_enum_value_collection import CommonVersionedEnumValueCollection +from s4ap.sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType class CommonVersionedSimDemographicTypeCollection(CommonVersionedEnumValueCollection[CommonSimDemographicType]): diff --git a/Scripts/s4ap/sims4communitylib/classes/filters/common_match_all_non_sims_object_filter.py b/Scripts/s4ap/sims4communitylib/classes/filters/common_match_all_non_sims_object_filter.py index 16504f5..1ad5751 100644 --- a/Scripts/s4ap/sims4communitylib/classes/filters/common_match_all_non_sims_object_filter.py +++ b/Scripts/s4ap/sims4communitylib/classes/filters/common_match_all_non_sims_object_filter.py @@ -7,8 +7,8 @@ """ from objects.proxy import ProxyObject from objects.script_object import ScriptObject -from sims4communitylib.classes.filters.common_match_object_filter import CommonMatchObjectFilterBase -from sims4communitylib.utils.common_type_utils import CommonTypeUtils +from s4ap.sims4communitylib.classes.filters.common_match_object_filter import CommonMatchObjectFilterBase +from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils class CommonMatchAllNonSimsObjectFilter(CommonMatchObjectFilterBase): diff --git a/Scripts/s4ap/sims4communitylib/classes/filters/common_match_all_sims_object_filter.py b/Scripts/s4ap/sims4communitylib/classes/filters/common_match_all_sims_object_filter.py index 224bc92..c03bdbf 100644 --- a/Scripts/s4ap/sims4communitylib/classes/filters/common_match_all_sims_object_filter.py +++ b/Scripts/s4ap/sims4communitylib/classes/filters/common_match_all_sims_object_filter.py @@ -5,8 +5,8 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.classes.filters.common_match_object_filter import CommonMatchObjectFilterBase -from sims4communitylib.utils.common_type_utils import CommonTypeUtils +from s4ap.sims4communitylib.classes.filters.common_match_object_filter import CommonMatchObjectFilterBase +from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils class CommonMatchAllSimsObjectFilter(CommonMatchObjectFilterBase): diff --git a/Scripts/s4ap/sims4communitylib/classes/filters/common_match_object_filter.py b/Scripts/s4ap/sims4communitylib/classes/filters/common_match_object_filter.py index 037558b..2505a0a 100644 --- a/Scripts/s4ap/sims4communitylib/classes/filters/common_match_object_filter.py +++ b/Scripts/s4ap/sims4communitylib/classes/filters/common_match_object_filter.py @@ -7,7 +7,7 @@ """ from interactions.utils.object_definition_or_tags import TunableObjectFilter from objects.script_object import ScriptObject -from sims4communitylib.enums.common_object_filter_type import CommonObjectFilterType +from s4ap.sims4communitylib.enums.common_object_filter_type import CommonObjectFilterType class CommonMatchObjectFilterBase(TunableObjectFilter): diff --git a/Scripts/s4ap/sims4communitylib/classes/interactions/_common_interaction_custom_mixin.py b/Scripts/s4ap/sims4communitylib/classes/interactions/_common_interaction_custom_mixin.py index 10f4edd..8e89f3e 100644 --- a/Scripts/s4ap/sims4communitylib/classes/interactions/_common_interaction_custom_mixin.py +++ b/Scripts/s4ap/sims4communitylib/classes/interactions/_common_interaction_custom_mixin.py @@ -8,8 +8,8 @@ from typing import Union, Any, Iterator, Tuple, List, Set from interactions.base.interaction import Interaction -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils class _CommonInteractionCustomMixin: diff --git a/Scripts/s4ap/sims4communitylib/classes/interactions/_common_interaction_hooks_mixin.py b/Scripts/s4ap/sims4communitylib/classes/interactions/_common_interaction_hooks_mixin.py index 09e4006..a3d9c9f 100644 --- a/Scripts/s4ap/sims4communitylib/classes/interactions/_common_interaction_hooks_mixin.py +++ b/Scripts/s4ap/sims4communitylib/classes/interactions/_common_interaction_hooks_mixin.py @@ -17,8 +17,8 @@ from protocolbuffers.Localization_pb2 import LocalizedString from scheduling import Timeline from sims.sim import Sim -from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult from singletons import DEFAULT diff --git a/Scripts/s4ap/sims4communitylib/classes/interactions/common_immediate_super_interaction.py b/Scripts/s4ap/sims4communitylib/classes/interactions/common_immediate_super_interaction.py index 5966cb6..b2b6494 100644 --- a/Scripts/s4ap/sims4communitylib/classes/interactions/common_immediate_super_interaction.py +++ b/Scripts/s4ap/sims4communitylib/classes/interactions/common_immediate_super_interaction.py @@ -20,15 +20,15 @@ from scheduling import Timeline from sims.sim import Sim from sims4.utils import flexmethod -from sims4communitylib.classes.interactions._common_interaction_custom_mixin import _CommonInteractionCustomMixin -from sims4communitylib.classes.interactions._common_interaction_hooks_mixin import _CommonInteractionHooksMixin -from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult - -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.logging.has_class_log import HasClassLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.misc.common_text_utils import CommonTextUtils +from s4ap.sims4communitylib.classes.interactions._common_interaction_custom_mixin import _CommonInteractionCustomMixin +from s4ap.sims4communitylib.classes.interactions._common_interaction_hooks_mixin import _CommonInteractionHooksMixin +from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult + +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.logging.has_class_log import HasClassLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.misc.common_text_utils import CommonTextUtils from singletons import DEFAULT from interactions.base.immediate_interaction import ImmediateSuperInteraction @@ -58,7 +58,7 @@ def __init__(self, *_: Any, **__: Any): @classmethod def _test(cls, target: Any, context: InteractionContext, super_interaction: 'Interaction'=None, skip_safe_tests: bool=False, **kwargs) -> CommonTestResult: from event_testing.results import TestResult - from sims4communitylib.classes.time.common_stop_watch import CommonStopWatch + from s4ap.sims4communitylib.classes.time.common_stop_watch import CommonStopWatch log = cls.get_log() verbose_log = cls.get_verbose_log() stop_watch = CommonStopWatch() diff --git a/Scripts/s4ap/sims4communitylib/classes/interactions/common_interaction.py b/Scripts/s4ap/sims4communitylib/classes/interactions/common_interaction.py index c0b1d75..47d8f01 100644 --- a/Scripts/s4ap/sims4communitylib/classes/interactions/common_interaction.py +++ b/Scripts/s4ap/sims4communitylib/classes/interactions/common_interaction.py @@ -19,14 +19,14 @@ from scheduling import Timeline from sims.sim import Sim from sims4.utils import flexmethod -from sims4communitylib.classes.interactions._common_interaction_custom_mixin import _CommonInteractionCustomMixin -from sims4communitylib.classes.interactions._common_interaction_hooks_mixin import _CommonInteractionHooksMixin -from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.logging.has_class_log import HasClassLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.misc.common_text_utils import CommonTextUtils +from s4ap.sims4communitylib.classes.interactions._common_interaction_custom_mixin import _CommonInteractionCustomMixin +from s4ap.sims4communitylib.classes.interactions._common_interaction_hooks_mixin import _CommonInteractionHooksMixin +from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.logging.has_class_log import HasClassLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.misc.common_text_utils import CommonTextUtils from singletons import DEFAULT from interactions.base.interaction import Interaction @@ -63,7 +63,7 @@ def __init__(self, *_: Any, **__: Any): @classmethod def _test(cls, inst, target: Any=DEFAULT, context: InteractionContext=DEFAULT, super_interaction: 'Interaction'=None, skip_safe_tests: bool=False, **kwargs) -> CommonTestResult: from event_testing.results import TestResult - from sims4communitylib.classes.time.common_stop_watch import CommonStopWatch + from s4ap.sims4communitylib.classes.time.common_stop_watch import CommonStopWatch log = cls.get_log() verbose_log = cls.get_verbose_log() stop_watch = CommonStopWatch() diff --git a/Scripts/s4ap/sims4communitylib/classes/interactions/common_interaction_override_name.py b/Scripts/s4ap/sims4communitylib/classes/interactions/common_interaction_override_name.py index 3ac174c..c833425 100644 --- a/Scripts/s4ap/sims4communitylib/classes/interactions/common_interaction_override_name.py +++ b/Scripts/s4ap/sims4communitylib/classes/interactions/common_interaction_override_name.py @@ -12,8 +12,8 @@ from protocolbuffers.Localization_pb2 import LocalizedString from sims.sim import Sim from sims4.utils import flexmethod -from sims4communitylib.logging.has_class_log import HasClassLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.logging.has_class_log import HasClassLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity class CommonInteractionOverrideName(HasClassLog): diff --git a/Scripts/s4ap/sims4communitylib/classes/interactions/common_mixer_interaction.py b/Scripts/s4ap/sims4communitylib/classes/interactions/common_mixer_interaction.py index 07bac74..e651dbc 100644 --- a/Scripts/s4ap/sims4communitylib/classes/interactions/common_mixer_interaction.py +++ b/Scripts/s4ap/sims4communitylib/classes/interactions/common_mixer_interaction.py @@ -20,14 +20,14 @@ from scheduling import Timeline from sims.sim import Sim from sims4.utils import flexmethod -from sims4communitylib.classes.interactions._common_interaction_custom_mixin import _CommonInteractionCustomMixin -from sims4communitylib.classes.interactions._common_interaction_hooks_mixin import _CommonInteractionHooksMixin -from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.logging.has_class_log import HasClassLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.misc.common_text_utils import CommonTextUtils +from s4ap.sims4communitylib.classes.interactions._common_interaction_custom_mixin import _CommonInteractionCustomMixin +from s4ap.sims4communitylib.classes.interactions._common_interaction_hooks_mixin import _CommonInteractionHooksMixin +from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.logging.has_class_log import HasClassLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.misc.common_text_utils import CommonTextUtils from singletons import DEFAULT from interactions.base.mixer_interaction import MixerInteraction @@ -88,7 +88,7 @@ def __init__(self, *_: Any, **__: Any): @classmethod def _test(cls, target: Any, context: InteractionContext, super_interaction: 'Interaction'=None, skip_safe_tests: bool=False, **kwargs) -> CommonTestResult: from event_testing.results import TestResult - from sims4communitylib.classes.time.common_stop_watch import CommonStopWatch + from s4ap.sims4communitylib.classes.time.common_stop_watch import CommonStopWatch log = cls.get_log() verbose_log = cls.get_verbose_log() stop_watch = CommonStopWatch() diff --git a/Scripts/s4ap/sims4communitylib/classes/interactions/common_object_interaction.py b/Scripts/s4ap/sims4communitylib/classes/interactions/common_object_interaction.py index 22dfcab..e31f012 100644 --- a/Scripts/s4ap/sims4communitylib/classes/interactions/common_object_interaction.py +++ b/Scripts/s4ap/sims4communitylib/classes/interactions/common_object_interaction.py @@ -9,9 +9,9 @@ from interactions.context import InteractionContext from sims.sim import Sim -from sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction -from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction +from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult class CommonObjectInteraction(CommonImmediateSuperInteraction): diff --git a/Scripts/s4ap/sims4communitylib/classes/interactions/common_social_mixer_interaction.py b/Scripts/s4ap/sims4communitylib/classes/interactions/common_social_mixer_interaction.py index f329184..bf6cf0f 100644 --- a/Scripts/s4ap/sims4communitylib/classes/interactions/common_social_mixer_interaction.py +++ b/Scripts/s4ap/sims4communitylib/classes/interactions/common_social_mixer_interaction.py @@ -10,9 +10,9 @@ from event_testing.tests import TestList from interactions.base.interaction import Interaction from postures.posture_state import PostureState -from sims4communitylib.classes.interactions._common_interaction_custom_mixin import _CommonInteractionCustomMixin -from sims4communitylib.classes.interactions._common_interaction_hooks_mixin import _CommonInteractionHooksMixin -from sims4communitylib.utils.misc.common_text_utils import CommonTextUtils +from s4ap.sims4communitylib.classes.interactions._common_interaction_custom_mixin import _CommonInteractionCustomMixin +from s4ap.sims4communitylib.classes.interactions._common_interaction_hooks_mixin import _CommonInteractionHooksMixin +from s4ap.sims4communitylib.utils.misc.common_text_utils import CommonTextUtils from singletons import DEFAULT from typing import Any, Union, Tuple, Set @@ -25,11 +25,11 @@ from scheduling import Timeline from sims.sim import Sim from sims4.utils import flexmethod -from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.logging.has_class_log import HasClassLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.logging.has_class_log import HasClassLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils from interactions.social.social_mixer_interaction import SocialMixerInteraction @@ -92,7 +92,7 @@ def __init__(self, *_: Any, **__: Any): @classmethod def _test(cls, target: Any, context: InteractionContext, *args, super_interaction: 'Interaction'=None, skip_safe_tests: bool=False, **kwargs) -> CommonTestResult: from event_testing.results import TestResult - from sims4communitylib.classes.time.common_stop_watch import CommonStopWatch + from s4ap.sims4communitylib.classes.time.common_stop_watch import CommonStopWatch log = cls.get_log() verbose_log = cls.get_verbose_log() stop_watch = CommonStopWatch() diff --git a/Scripts/s4ap/sims4communitylib/classes/interactions/common_social_super_interaction.py b/Scripts/s4ap/sims4communitylib/classes/interactions/common_social_super_interaction.py index 921b3f8..2793651 100644 --- a/Scripts/s4ap/sims4communitylib/classes/interactions/common_social_super_interaction.py +++ b/Scripts/s4ap/sims4communitylib/classes/interactions/common_social_super_interaction.py @@ -10,9 +10,9 @@ from event_testing.tests import TestList from interactions.base.interaction import Interaction -from sims4communitylib.classes.interactions._common_interaction_custom_mixin import _CommonInteractionCustomMixin -from sims4communitylib.classes.interactions._common_interaction_hooks_mixin import _CommonInteractionHooksMixin -from sims4communitylib.utils.misc.common_text_utils import CommonTextUtils +from s4ap.sims4communitylib.classes.interactions._common_interaction_custom_mixin import _CommonInteractionCustomMixin +from s4ap.sims4communitylib.classes.interactions._common_interaction_hooks_mixin import _CommonInteractionHooksMixin +from s4ap.sims4communitylib.utils.misc.common_text_utils import CommonTextUtils from singletons import DEFAULT from interactions import ParticipantType @@ -20,11 +20,11 @@ from interactions.interaction_finisher import FinishingType from postures.posture_state import PostureState from protocolbuffers.Localization_pb2 import LocalizedString -from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.logging.has_class_log import HasClassLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.logging.has_class_log import HasClassLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils from interactions.social.social_super_interaction import SocialSuperInteraction from interactions.context import InteractionContext from native.animation import NativeAsm @@ -96,7 +96,7 @@ def __init__(self, *_: Any, **__: Any): @flexmethod def _test(cls, inst: 'CommonSocialSuperInteraction', target: Any, context: InteractionContext, super_interaction: 'Interaction'=None, skip_safe_tests: bool=False, **kwargs): from event_testing.results import TestResult - from sims4communitylib.classes.time.common_stop_watch import CommonStopWatch + from s4ap.sims4communitylib.classes.time.common_stop_watch import CommonStopWatch inst_or_cls = inst or cls log = cls.get_log() verbose_log = cls.get_verbose_log() diff --git a/Scripts/s4ap/sims4communitylib/classes/interactions/common_super_interaction.py b/Scripts/s4ap/sims4communitylib/classes/interactions/common_super_interaction.py index f6548af..b5f2198 100644 --- a/Scripts/s4ap/sims4communitylib/classes/interactions/common_super_interaction.py +++ b/Scripts/s4ap/sims4communitylib/classes/interactions/common_super_interaction.py @@ -17,14 +17,14 @@ from native.animation import NativeAsm from postures.posture_state import PostureState from protocolbuffers.Localization_pb2 import LocalizedString -from sims4communitylib.classes.interactions._common_interaction_custom_mixin import _CommonInteractionCustomMixin -from sims4communitylib.classes.interactions._common_interaction_hooks_mixin import _CommonInteractionHooksMixin -from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.logging.has_class_log import HasClassLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.misc.common_text_utils import CommonTextUtils +from s4ap.sims4communitylib.classes.interactions._common_interaction_custom_mixin import _CommonInteractionCustomMixin +from s4ap.sims4communitylib.classes.interactions._common_interaction_hooks_mixin import _CommonInteractionHooksMixin +from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.logging.has_class_log import HasClassLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.misc.common_text_utils import CommonTextUtils from singletons import DEFAULT from interactions.base.super_interaction import SuperInteraction from scheduling import Timeline @@ -124,7 +124,7 @@ def on_run(self, interaction_sim: Sim, interaction_target: Any: timeline: Timeli @classmethod def _test(cls, target: Any, context: InteractionContext, super_interaction: 'Interaction'=None, skip_safe_tests: bool=False, **kwargs) -> CommonTestResult: from event_testing.results import TestResult - from sims4communitylib.classes.time.common_stop_watch import CommonStopWatch + from s4ap.sims4communitylib.classes.time.common_stop_watch import CommonStopWatch log = cls.get_log() verbose_log = cls.get_verbose_log() stop_watch = CommonStopWatch() @@ -523,7 +523,7 @@ def __init__(self, *_: Any, **__: Any): @classmethod def _test(cls, target: Any, context: InteractionContext, super_interaction: 'Interaction'=None, skip_safe_tests: bool=False, **kwargs) -> CommonTestResult: from event_testing.results import TestResult - from sims4communitylib.classes.time.common_stop_watch import CommonStopWatch + from s4ap.sims4communitylib.classes.time.common_stop_watch import CommonStopWatch log = cls.get_log() verbose_log = cls.get_verbose_log() stop_watch = CommonStopWatch() diff --git a/Scripts/s4ap/sims4communitylib/classes/interactions/common_terrain_interaction.py b/Scripts/s4ap/sims4communitylib/classes/interactions/common_terrain_interaction.py index d8a0567..daf1a0c 100644 --- a/Scripts/s4ap/sims4communitylib/classes/interactions/common_terrain_interaction.py +++ b/Scripts/s4ap/sims4communitylib/classes/interactions/common_terrain_interaction.py @@ -10,9 +10,9 @@ from interactions.context import InteractionContext from sims.sim import Sim -from sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction -from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction +from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' diff --git a/Scripts/s4ap/sims4communitylib/classes/math/common_location.py b/Scripts/s4ap/sims4communitylib/classes/math/common_location.py index 9b7ef73..6a863e0 100644 --- a/Scripts/s4ap/sims4communitylib/classes/math/common_location.py +++ b/Scripts/s4ap/sims4communitylib/classes/math/common_location.py @@ -7,8 +7,8 @@ """ from typing import Any, Union from sims4.math import Location -from sims4communitylib.classes.math.common_surface_identifier import CommonSurfaceIdentifier -from sims4communitylib.classes.math.common_transform import CommonTransform +from s4ap.sims4communitylib.classes.math.common_surface_identifier import CommonSurfaceIdentifier +from s4ap.sims4communitylib.classes.math.common_transform import CommonTransform class CommonLocation: diff --git a/Scripts/s4ap/sims4communitylib/classes/math/common_polygon.py b/Scripts/s4ap/sims4communitylib/classes/math/common_polygon.py index 6749f5a..34417ac 100644 --- a/Scripts/s4ap/sims4communitylib/classes/math/common_polygon.py +++ b/Scripts/s4ap/sims4communitylib/classes/math/common_polygon.py @@ -9,7 +9,7 @@ from interactions.constraints import Constraint from sims4.geometry import Polygon -from sims4communitylib.classes.math.common_vector3 import CommonVector3 +from s4ap.sims4communitylib.classes.math.common_vector3 import CommonVector3 class CommonPolygon: diff --git a/Scripts/s4ap/sims4communitylib/classes/math/common_quaternion.py b/Scripts/s4ap/sims4communitylib/classes/math/common_quaternion.py index 42f2138..d8e7583 100644 --- a/Scripts/s4ap/sims4communitylib/classes/math/common_quaternion.py +++ b/Scripts/s4ap/sims4communitylib/classes/math/common_quaternion.py @@ -9,7 +9,7 @@ from protocolbuffers.Math_pb2 import Quaternion as MathPb2Quaternion if TYPE_CHECKING: - from sims4communitylib.classes.math.common_vector3 import CommonVector3 + from s4ap.sims4communitylib.classes.math.common_vector3 import CommonVector3 # noinspection PyBroadException try: @@ -253,7 +253,7 @@ def from_degrees(degrees: float) -> 'CommonQuaternion': :return: An instance of a CommonQuaternion. :rtype: CommonQuaternion """ - from sims4communitylib.utils.common_math_utils import CommonMathUtils + from s4ap.sims4communitylib.utils.common_math_utils import CommonMathUtils return CommonQuaternion.from_radian(CommonMathUtils.degrees_to_radian(degrees)) @staticmethod @@ -285,7 +285,7 @@ def to_degrees(quaternion: Union[Quaternion, MathPb2Quaternion, 'CommonQuaternio """ if quaternion is None: return 0.0 - from sims4communitylib.utils.common_math_utils import CommonMathUtils + from s4ap.sims4communitylib.utils.common_math_utils import CommonMathUtils return CommonMathUtils.radian_to_degrees(CommonQuaternion.to_radian(quaternion)) def __add__(self, other: Union[Quaternion, MathPb2Quaternion, 'CommonQuaternion', float]) -> 'CommonQuaternion': @@ -309,7 +309,7 @@ def rotate_vector(quaternion: Union[Quaternion, MathPb2Quaternion, 'CommonQuater :return: A normalized Quaternion. :rtype: CommonQuaternion """ - from sims4communitylib.classes.math.common_vector3 import CommonVector3 + from s4ap.sims4communitylib.classes.math.common_vector3 import CommonVector3 q = CommonQuaternion.multiply(CommonQuaternion.multiply(quaternion, CommonQuaternion(vector.x, vector.y, vector.z, 0.0)), CommonQuaternion.conjugate(quaternion)) # q.w will be zero. return CommonVector3(q.x, q.y, q.z) diff --git a/Scripts/s4ap/sims4communitylib/classes/math/common_routing_location.py b/Scripts/s4ap/sims4communitylib/classes/math/common_routing_location.py index e7fc160..299edd2 100644 --- a/Scripts/s4ap/sims4communitylib/classes/math/common_routing_location.py +++ b/Scripts/s4ap/sims4communitylib/classes/math/common_routing_location.py @@ -8,12 +8,12 @@ from typing import Union, TYPE_CHECKING from sims4.math import Location as Math_Location from routing import Location -from sims4communitylib.classes.math.common_quaternion import CommonQuaternion -from sims4communitylib.classes.math.common_surface_identifier import CommonSurfaceIdentifier -from sims4communitylib.classes.math.common_vector3 import CommonVector3 +from s4ap.sims4communitylib.classes.math.common_quaternion import CommonQuaternion +from s4ap.sims4communitylib.classes.math.common_surface_identifier import CommonSurfaceIdentifier +from s4ap.sims4communitylib.classes.math.common_vector3 import CommonVector3 if TYPE_CHECKING: - from sims4communitylib.classes.math.common_location import CommonLocation + from s4ap.sims4communitylib.classes.math.common_location import CommonLocation class CommonRoutingLocation: @@ -87,7 +87,7 @@ def from_location(location: Union[Location, Math_Location, 'CommonLocation', 'Co :return: An instance of a CommonRoutingLocation or None if the object failed to convert. :rtype: Union[CommonRoutingLocation, None] """ - from sims4communitylib.classes.math.common_location import CommonLocation + from s4ap.sims4communitylib.classes.math.common_location import CommonLocation if location is None: return None if isinstance(location, CommonRoutingLocation): diff --git a/Scripts/s4ap/sims4communitylib/classes/math/common_surface_identifier.py b/Scripts/s4ap/sims4communitylib/classes/math/common_surface_identifier.py index eac34e8..2c0a4f8 100644 --- a/Scripts/s4ap/sims4communitylib/classes/math/common_surface_identifier.py +++ b/Scripts/s4ap/sims4communitylib/classes/math/common_surface_identifier.py @@ -71,7 +71,7 @@ def empty(secondary_id: int=0) -> 'CommonSurfaceIdentifier': :return: An empty surface identifier. :rtype: CommonSurfaceIdentifier """ - from sims4communitylib.utils.location.common_location_utils import CommonLocationUtils + from s4ap.sims4communitylib.utils.location.common_location_utils import CommonLocationUtils return CommonSurfaceIdentifier(CommonLocationUtils.get_current_zone_id(), secondary_id=secondary_id) @staticmethod diff --git a/Scripts/s4ap/sims4communitylib/classes/math/common_transform.py b/Scripts/s4ap/sims4communitylib/classes/math/common_transform.py index 4357aae..d20dcee 100644 --- a/Scripts/s4ap/sims4communitylib/classes/math/common_transform.py +++ b/Scripts/s4ap/sims4communitylib/classes/math/common_transform.py @@ -8,8 +8,8 @@ from typing import Union, Any from protocolbuffers.Math_pb2 import Transform as MathPb2Transform -from sims4communitylib.classes.math.common_quaternion import CommonQuaternion -from sims4communitylib.classes.math.common_vector3 import CommonVector3 +from s4ap.sims4communitylib.classes.math.common_quaternion import CommonQuaternion +from s4ap.sims4communitylib.classes.math.common_vector3 import CommonVector3 # noinspection PyBroadException try: diff --git a/Scripts/s4ap/sims4communitylib/classes/math/common_weighted_value_tally.py b/Scripts/s4ap/sims4communitylib/classes/math/common_weighted_value_tally.py index 215d860..e1f4188 100644 --- a/Scripts/s4ap/sims4communitylib/classes/math/common_weighted_value_tally.py +++ b/Scripts/s4ap/sims4communitylib/classes/math/common_weighted_value_tally.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.classes.math.common_weighted_value import CommonWeightedValue +from s4ap.sims4communitylib.classes.math.common_weighted_value import CommonWeightedValue class CommonWeightedValueTally: diff --git a/Scripts/s4ap/sims4communitylib/classes/mixins/common_interactions_mixin.py b/Scripts/s4ap/sims4communitylib/classes/mixins/common_interactions_mixin.py index a29a45c..49c40bf 100644 --- a/Scripts/s4ap/sims4communitylib/classes/mixins/common_interactions_mixin.py +++ b/Scripts/s4ap/sims4communitylib/classes/mixins/common_interactions_mixin.py @@ -30,7 +30,7 @@ def _interaction_instances_gen(self) -> Iterator[Interaction]: yield from self._cached_interactions else: cached_interactions = list() - from sims4communitylib.utils.resources.common_interaction_utils import CommonInteractionUtils + from s4ap.sims4communitylib.utils.resources.common_interaction_utils import CommonInteractionUtils for interaction_id in self.interaction_ids: interaction = CommonInteractionUtils.load_interaction_by_id(interaction_id) if interaction is None: diff --git a/Scripts/s4ap/sims4communitylib/classes/resolvers/common_double_sim_resolver.py b/Scripts/s4ap/sims4communitylib/classes/resolvers/common_double_sim_resolver.py index bd3e30c..be3fd8f 100644 --- a/Scripts/s4ap/sims4communitylib/classes/resolvers/common_double_sim_resolver.py +++ b/Scripts/s4ap/sims4communitylib/classes/resolvers/common_double_sim_resolver.py @@ -9,7 +9,7 @@ from event_testing.resolver import DoubleSimResolver from interactions import ParticipantType, ParticipantTypeSituationSims -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils class CommonDoubleSimResolver(DoubleSimResolver): diff --git a/Scripts/s4ap/sims4communitylib/classes/runnables/common_runnable.py b/Scripts/s4ap/sims4communitylib/classes/runnables/common_runnable.py index b9166ba..750badf 100644 --- a/Scripts/s4ap/sims4communitylib/classes/runnables/common_runnable.py +++ b/Scripts/s4ap/sims4communitylib/classes/runnables/common_runnable.py @@ -8,18 +8,18 @@ from typing import Union, Any, TypeVar, Generic -from sims4communitylib.classes.runnables.contexts.common_runnable_context import CommonRunnableContext -from sims4communitylib.enums.common_runnable_state_type import CommonRunnableStateType -from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from sims4communitylib.classes.time.common_alarm_handle import CommonAlarmHandle -from sims4communitylib.enums.enumtypes.common_int import CommonInt -from sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags -from sims4communitylib.events.interval.common_interval_event_service import CommonIntervalEventRegistry, \ +from s4ap.sims4communitylib.classes.runnables.contexts.common_runnable_context import CommonRunnableContext +from s4ap.sims4communitylib.enums.common_runnable_state_type import CommonRunnableStateType +from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from s4ap.sims4communitylib.classes.time.common_alarm_handle import CommonAlarmHandle +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags +from s4ap.sims4communitylib.events.interval.common_interval_event_service import CommonIntervalEventRegistry, \ CommonIntervalDispatcher -from sims4communitylib.logging.has_class_log import HasClassLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.utils.common_time_utils import CommonTimeUtils -from sims4communitylib.utils.time.common_alarm_utils import CommonAlarmUtils +from s4ap.sims4communitylib.logging.has_class_log import HasClassLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.utils.common_time_utils import CommonTimeUtils +from s4ap.sims4communitylib.utils.time.common_alarm_utils import CommonAlarmUtils CommonRunnableContextType = TypeVar('CommonRunnableContextType', bound=CommonRunnableContext) diff --git a/Scripts/s4ap/sims4communitylib/classes/runnables/common_runnable_with_sims.py b/Scripts/s4ap/sims4communitylib/classes/runnables/common_runnable_with_sims.py index da59534..de46296 100644 --- a/Scripts/s4ap/sims4communitylib/classes/runnables/common_runnable_with_sims.py +++ b/Scripts/s4ap/sims4communitylib/classes/runnables/common_runnable_with_sims.py @@ -9,14 +9,14 @@ from typing import Union, List, Tuple, TypeVar, Generic from sims.sim import Sim -from sims4communitylib.classes.runnables.common_runnable import CommonRunnable -from sims4communitylib.classes.runnables.contexts.common_runnable_context_with_sims import CommonRunnableContextWithSims -from sims4communitylib.classes.runnables.contexts.common_runnable_sim_context import CommonRunnableSimContext +from s4ap.sims4communitylib.classes.runnables.common_runnable import CommonRunnable +from s4ap.sims4communitylib.classes.runnables.contexts.common_runnable_context_with_sims import CommonRunnableContextWithSims +from s4ap.sims4communitylib.classes.runnables.contexts.common_runnable_sim_context import CommonRunnableSimContext from sims.sim_info import SimInfo -from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from sims4communitylib.enums.enumtypes.common_int import CommonInt -from sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags -from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity CommonRunnableContextWithSimsType = TypeVar('CommonRunnableContextWithSimsType', bound=CommonRunnableContextWithSims) CommonRunnableSimContextType = TypeVar('CommonRunnableSimContextType', bound=CommonRunnableSimContext) diff --git a/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_context.py b/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_context.py index 0ecf3c6..ef31130 100644 --- a/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_context.py +++ b/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_context.py @@ -8,12 +8,12 @@ from typing import Union, Dict, Any, Tuple, TypeVar, Type -from sims4communitylib.classes.serialization.common_serializable import CommonSerializable -from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from sims4communitylib.enums.enumtypes.common_int import CommonInt -from sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags -from sims4communitylib.logging.has_class_log import HasClassLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.classes.serialization.common_serializable import CommonSerializable +from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags +from s4ap.sims4communitylib.logging.has_class_log import HasClassLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity CommonRunnableContextType = TypeVar('CommonRunnableContextType', bound="CommonRunnableContext") diff --git a/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_context_with_sims.py b/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_context_with_sims.py index f114217..ffcc760 100644 --- a/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_context_with_sims.py +++ b/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_context_with_sims.py @@ -9,13 +9,13 @@ from typing import Union, Iterator, List, Tuple, Any, Dict, Type, TypeVar, Generic from sims.sim import Sim -from sims4communitylib.classes.runnables.contexts.common_runnable_context import CommonRunnableContext -from sims4communitylib.classes.runnables.contexts.common_runnable_sim_context import CommonRunnableSimContext +from s4ap.sims4communitylib.classes.runnables.contexts.common_runnable_context import CommonRunnableContext +from s4ap.sims4communitylib.classes.runnables.contexts.common_runnable_sim_context import CommonRunnableSimContext from sims.sim_info import SimInfo -from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from sims4communitylib.enums.enumtypes.common_int import CommonInt -from sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags -from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity CommonRunnableSimContextType = TypeVar('CommonRunnableSimContextType', bound=CommonRunnableSimContext) diff --git a/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_object_context.py b/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_object_context.py index ef0dd90..db13f34 100644 --- a/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_object_context.py +++ b/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_object_context.py @@ -8,13 +8,13 @@ from typing import Union, Tuple, Any, Dict -from sims4communitylib.classes.runnables.contexts.common_runnable_context import CommonRunnableContext +from s4ap.sims4communitylib.classes.runnables.contexts.common_runnable_context import CommonRunnableContext from objects.game_object import GameObject -from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from sims4communitylib.enums.enumtypes.common_int import CommonInt -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.utils.common_type_utils import CommonTypeUtils -from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils +from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils +from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils class CommonRunnableObjectContext(CommonRunnableContext): diff --git a/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_sim_context.py b/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_sim_context.py index e076529..f1e205a 100644 --- a/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_sim_context.py +++ b/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_sim_context.py @@ -8,16 +8,16 @@ from typing import Union, Dict, Any, Tuple -from sims4communitylib.classes.runnables.contexts.common_runnable_context import CommonRunnableContext +from s4ap.sims4communitylib.classes.runnables.contexts.common_runnable_context import CommonRunnableContext from sims.sim import Sim from sims.sim_info import SimInfo -from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from sims4communitylib.enums.enumtypes.common_int import CommonInt -from sims4communitylib.enums.sim_type import CommonSimType -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils -from sims4communitylib.utils.sims.common_sim_type_utils import CommonSimTypeUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.sim_type import CommonSimType +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils +from s4ap.sims4communitylib.utils.sims.common_sim_type_utils import CommonSimTypeUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils class CommonRunnableSimContext(CommonRunnableContext): diff --git a/Scripts/s4ap/sims4communitylib/classes/serialization/common_serializable_location.py b/Scripts/s4ap/sims4communitylib/classes/serialization/common_serializable_location.py index 254b7f4..49ddc4c 100644 --- a/Scripts/s4ap/sims4communitylib/classes/serialization/common_serializable_location.py +++ b/Scripts/s4ap/sims4communitylib/classes/serialization/common_serializable_location.py @@ -7,12 +7,12 @@ """ from typing import Dict, Any, Union -from sims4communitylib.classes.math.common_location import CommonLocation -from sims4communitylib.classes.math.common_quaternion import CommonQuaternion -from sims4communitylib.classes.math.common_surface_identifier import CommonSurfaceIdentifier -from sims4communitylib.classes.math.common_transform import CommonTransform -from sims4communitylib.classes.math.common_vector3 import CommonVector3 -from sims4communitylib.classes.serialization.common_serializable import CommonSerializable +from s4ap.sims4communitylib.classes.math.common_location import CommonLocation +from s4ap.sims4communitylib.classes.math.common_quaternion import CommonQuaternion +from s4ap.sims4communitylib.classes.math.common_surface_identifier import CommonSurfaceIdentifier +from s4ap.sims4communitylib.classes.math.common_transform import CommonTransform +from s4ap.sims4communitylib.classes.math.common_vector3 import CommonVector3 +from s4ap.sims4communitylib.classes.serialization.common_serializable import CommonSerializable class CommonSerializableLocation(CommonSerializable): diff --git a/Scripts/s4ap/sims4communitylib/classes/test_based_scores/common_sim_to_sim_test_based_score.py b/Scripts/s4ap/sims4communitylib/classes/test_based_scores/common_sim_to_sim_test_based_score.py index 01d4ccb..6a0727c 100644 --- a/Scripts/s4ap/sims4communitylib/classes/test_based_scores/common_sim_to_sim_test_based_score.py +++ b/Scripts/s4ap/sims4communitylib/classes/test_based_scores/common_sim_to_sim_test_based_score.py @@ -10,10 +10,10 @@ from interactions.base.interaction import Interaction from sims.sim_info import SimInfo from sims4.sim_irq_service import yield_to_irq -from sims4communitylib.classes.test_based_scores.common_test_based_score import CommonTestBasedScore -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.utils.common_type_utils import CommonTypeUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.classes.test_based_scores.common_test_based_score import CommonTestBasedScore +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils class CommonSimToSimTestBasedScore(CommonTestBasedScore): diff --git a/Scripts/s4ap/sims4communitylib/classes/test_based_scores/common_single_sim_test_based_score.py b/Scripts/s4ap/sims4communitylib/classes/test_based_scores/common_single_sim_test_based_score.py index cf32680..e3f05cc 100644 --- a/Scripts/s4ap/sims4communitylib/classes/test_based_scores/common_single_sim_test_based_score.py +++ b/Scripts/s4ap/sims4communitylib/classes/test_based_scores/common_single_sim_test_based_score.py @@ -10,10 +10,10 @@ from interactions.base.interaction import Interaction from sims.sim_info import SimInfo from sims4.sim_irq_service import yield_to_irq -from sims4communitylib.classes.test_based_scores.common_test_based_score import CommonTestBasedScore -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.utils.common_type_utils import CommonTypeUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.classes.test_based_scores.common_test_based_score import CommonTestBasedScore +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils class CommonSingleSimTestBasedScore(CommonTestBasedScore): diff --git a/Scripts/s4ap/sims4communitylib/classes/test_based_scores/common_test_based_score.py b/Scripts/s4ap/sims4communitylib/classes/test_based_scores/common_test_based_score.py index ca3a98a..b64ce8a 100644 --- a/Scripts/s4ap/sims4communitylib/classes/test_based_scores/common_test_based_score.py +++ b/Scripts/s4ap/sims4communitylib/classes/test_based_scores/common_test_based_score.py @@ -8,8 +8,8 @@ from event_testing.resolver import Resolver from event_testing.test_based_score import TestBasedScore from sims4.math import Threshold -from sims4communitylib.logging.has_class_log import HasClassLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.logging.has_class_log import HasClassLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity class CommonTestBasedScore(TestBasedScore, HasClassLog): diff --git a/Scripts/s4ap/sims4communitylib/classes/testing/common_enqueue_result.py b/Scripts/s4ap/sims4communitylib/classes/testing/common_enqueue_result.py index 7797c51..9da8c53 100644 --- a/Scripts/s4ap/sims4communitylib/classes/testing/common_enqueue_result.py +++ b/Scripts/s4ap/sims4communitylib/classes/testing/common_enqueue_result.py @@ -6,8 +6,8 @@ Copyright (c) COLONOLNUTTY """ from event_testing.results import TestResult, EnqueueResult -from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult class CommonEnqueueResult(EnqueueResult): diff --git a/Scripts/s4ap/sims4communitylib/classes/testing/common_execution_result.py b/Scripts/s4ap/sims4communitylib/classes/testing/common_execution_result.py index 1c24919..6af356d 100644 --- a/Scripts/s4ap/sims4communitylib/classes/testing/common_execution_result.py +++ b/Scripts/s4ap/sims4communitylib/classes/testing/common_execution_result.py @@ -9,9 +9,9 @@ from event_testing.results import TestResult from protocolbuffers.Localization_pb2 import LocalizedString -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.localization.common_localized_string_separators import CommonLocalizedStringSeparator +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.localization.common_localized_string_separators import CommonLocalizedStringSeparator class CommonExecutionResult(TestResult): diff --git a/Scripts/s4ap/sims4communitylib/classes/testing/common_test_result.py b/Scripts/s4ap/sims4communitylib/classes/testing/common_test_result.py index f5bc333..75d29cc 100644 --- a/Scripts/s4ap/sims4communitylib/classes/testing/common_test_result.py +++ b/Scripts/s4ap/sims4communitylib/classes/testing/common_test_result.py @@ -9,10 +9,10 @@ from event_testing.results import TestResult from protocolbuffers.Localization_pb2 import LocalizedString -from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.localization.common_localized_string_separators import CommonLocalizedStringSeparator +from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.localization.common_localized_string_separators import CommonLocalizedStringSeparator class CommonTestResult(CommonExecutionResult): diff --git a/Scripts/s4ap/sims4communitylib/classes/time/common_alarm_handle.py b/Scripts/s4ap/sims4communitylib/classes/time/common_alarm_handle.py index eb94c21..65ee7c6 100644 --- a/Scripts/s4ap/sims4communitylib/classes/time/common_alarm_handle.py +++ b/Scripts/s4ap/sims4communitylib/classes/time/common_alarm_handle.py @@ -6,10 +6,10 @@ Copyright (c) COLONOLNUTTY """ import os -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.common_time_utils import CommonTimeUtils +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.common_time_utils import CommonTimeUtils from typing import Any, Callable diff --git a/Scripts/s4ap/sims4communitylib/classes/time/common_stop_watch.py b/Scripts/s4ap/sims4communitylib/classes/time/common_stop_watch.py index 1c1201b..63b921a 100644 --- a/Scripts/s4ap/sims4communitylib/classes/time/common_stop_watch.py +++ b/Scripts/s4ap/sims4communitylib/classes/time/common_stop_watch.py @@ -50,7 +50,7 @@ def interval_milliseconds(self) -> float: :return: The number of milliseconds that occurred since the stop watch was started. :rtype: float """ - from sims4communitylib.utils.common_time_utils import CommonTimeUtils + from s4ap.sims4communitylib.utils.common_time_utils import CommonTimeUtils return CommonTimeUtils.convert_seconds_to_milliseconds(self.interval()) def stop(self) -> float: @@ -78,5 +78,5 @@ def stop_milliseconds(self) -> float: :return: The number of milliseconds that occurred since starting the stop watch. :rtype: float """ - from sims4communitylib.utils.common_time_utils import CommonTimeUtils + from s4ap.sims4communitylib.utils.common_time_utils import CommonTimeUtils return CommonTimeUtils.convert_seconds_to_milliseconds(self.stop()) diff --git a/Scripts/s4ap/sims4communitylib/conditionals/common_conditional_action.py b/Scripts/s4ap/sims4communitylib/conditionals/common_conditional_action.py index e902348..3827485 100644 --- a/Scripts/s4ap/sims4communitylib/conditionals/common_conditional_action.py +++ b/Scripts/s4ap/sims4communitylib/conditionals/common_conditional_action.py @@ -7,8 +7,8 @@ """ from typing import Union -from sims4communitylib.logging.has_log import HasLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.logging.has_log import HasLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity class CommonConditionalAction(HasLog): diff --git a/Scripts/s4ap/sims4communitylib/debug/dialogs/common_change_object_state_dialog.py b/Scripts/s4ap/sims4communitylib/debug/dialogs/common_change_object_state_dialog.py index e42607b..9659db9 100644 --- a/Scripts/s4ap/sims4communitylib/debug/dialogs/common_change_object_state_dialog.py +++ b/Scripts/s4ap/sims4communitylib/debug/dialogs/common_change_object_state_dialog.py @@ -9,15 +9,15 @@ from objects.components.state import ObjectState from objects.game_object import GameObject -from sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext -from sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_select_option import \ +from s4ap.sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext +from s4ap.sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_select_option import \ CommonDialogSelectOption -from sims4communitylib.dialogs.option_dialogs.common_choose_object_option_dialog import CommonChooseObjectOptionDialog -from sims4communitylib.logging._has_s4cl_log import _HasS4CLLog -from sims4communitylib.utils.common_icon_utils import CommonIconUtils -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.objects.common_object_state_utils import CommonObjectStateUtils -from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils +from s4ap.sims4communitylib.dialogs.option_dialogs.common_choose_object_option_dialog import CommonChooseObjectOptionDialog +from s4ap.sims4communitylib.logging._has_s4cl_log import _HasS4CLLog +from s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.objects.common_object_state_utils import CommonObjectStateUtils +from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils class CommonChangeObjectStateDialog(_HasS4CLLog): diff --git a/Scripts/s4ap/sims4communitylib/debug/interactions/_register_interactions.py b/Scripts/s4ap/sims4communitylib/debug/interactions/_register_interactions.py index f8c5364..aae463a 100644 --- a/Scripts/s4ap/sims4communitylib/debug/interactions/_register_interactions.py +++ b/Scripts/s4ap/sims4communitylib/debug/interactions/_register_interactions.py @@ -10,17 +10,17 @@ from objects.game_object import GameObject from objects.script_object import ScriptObject from sims.sim import Sim -from sims4communitylib.enums.affordance_list_ids import CommonAffordanceListId -from sims4communitylib.enums.enumtypes.common_int import CommonInt -from sims4communitylib.enums.interactions_enum import CommonInteractionId -from sims4communitylib.services.interactions.interaction_registration_service import CommonInteractionRegistry, \ +from s4ap.sims4communitylib.enums.affordance_list_ids import CommonAffordanceListId +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.interactions_enum import CommonInteractionId +from s4ap.sims4communitylib.services.interactions.interaction_registration_service import CommonInteractionRegistry, \ CommonInteractionType, CommonScriptObjectInteractionHandler, CommonInteractionHandler -from sims4communitylib.services.resources.common_instance_manager_modification_registry import \ +from s4ap.sims4communitylib.services.resources.common_instance_manager_modification_registry import \ CommonInstanceManagerModificationRegistry -from sims4communitylib.services.resources.modification_handlers.common_add_interactions_to_affordance_lists_handler import \ +from s4ap.sims4communitylib.services.resources.modification_handlers.common_add_interactions_to_affordance_lists_handler import \ CommonAddInteractionsToAffordanceListsModificationHandler -from sims4communitylib.utils.common_type_utils import CommonTypeUtils -from sims4communitylib.utils.objects.common_object_state_utils import CommonObjectStateUtils +from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils +from s4ap.sims4communitylib.utils.objects.common_object_state_utils import CommonObjectStateUtils @CommonInteractionRegistry.register_interaction_handler(CommonInteractionType.ON_SCRIPT_OBJECT_LOAD) diff --git a/Scripts/s4ap/sims4communitylib/debug/interactions/change_object_states.py b/Scripts/s4ap/sims4communitylib/debug/interactions/change_object_states.py index 3d13dff..5ea3ecf 100644 --- a/Scripts/s4ap/sims4communitylib/debug/interactions/change_object_states.py +++ b/Scripts/s4ap/sims4communitylib/debug/interactions/change_object_states.py @@ -10,13 +10,13 @@ from interactions import ParticipantType from interactions.context import InteractionContext from sims.sim import Sim -from sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction -from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction +from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils class S4CLDebugChangeObjectStatesInteraction(CommonImmediateSuperInteraction): @@ -65,6 +65,6 @@ def on_started(self, interaction_sim: Sim, interaction_target: Any) -> CommonExe self.log.format_with_message('Had Sim Instance.', new_target=new_target) interaction_target = new_target - from sims4communitylib.debug.dialogs.common_change_object_state_dialog import CommonChangeObjectStateDialog + from s4ap.sims4communitylib.debug.dialogs.common_change_object_state_dialog import CommonChangeObjectStateDialog CommonChangeObjectStateDialog(interaction_target).open() return CommonExecutionResult.TRUE diff --git a/Scripts/s4ap/sims4communitylib/debug/interactions/induce_labor.py b/Scripts/s4ap/sims4communitylib/debug/interactions/induce_labor.py index bb931aa..a42e727 100644 --- a/Scripts/s4ap/sims4communitylib/debug/interactions/induce_labor.py +++ b/Scripts/s4ap/sims4communitylib/debug/interactions/induce_labor.py @@ -9,16 +9,16 @@ from interactions.context import InteractionContext from sims.sim import Sim -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils -from sims4communitylib.utils.sims.common_sim_pregnancy_utils import CommonSimPregnancyUtils -from sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from sims4communitylib.utils.common_type_utils import CommonTypeUtils +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils +from s4ap.sims4communitylib.utils.sims.common_sim_pregnancy_utils import CommonSimPregnancyUtils +from s4ap.sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils class S4CLDebugInduceLaborInteraction(CommonImmediateSuperInteraction): diff --git a/Scripts/s4ap/sims4communitylib/debug/interactions/log_all_game_tags.py b/Scripts/s4ap/sims4communitylib/debug/interactions/log_all_game_tags.py index 24c55db..a36bd18 100644 --- a/Scripts/s4ap/sims4communitylib/debug/interactions/log_all_game_tags.py +++ b/Scripts/s4ap/sims4communitylib/debug/interactions/log_all_game_tags.py @@ -10,14 +10,14 @@ from interactions import ParticipantType from interactions.context import InteractionContext from sims.sim import Sim -from sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction -from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.utils.objects.common_object_tag_utils import CommonObjectTagUtils -from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction +from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.utils.objects.common_object_tag_utils import CommonObjectTagUtils +from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils class S4CLDebugLogAllGameTagsInteraction(CommonImmediateSuperInteraction): diff --git a/Scripts/s4ap/sims4communitylib/debug/interactions/log_all_interactions.py b/Scripts/s4ap/sims4communitylib/debug/interactions/log_all_interactions.py index 4e0f581..93c893d 100644 --- a/Scripts/s4ap/sims4communitylib/debug/interactions/log_all_interactions.py +++ b/Scripts/s4ap/sims4communitylib/debug/interactions/log_all_interactions.py @@ -12,19 +12,19 @@ from interactions.context import InteractionContext from objects.game_object import GameObject from sims.sim import Sim -from sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction -from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification -from sims4communitylib.utils.common_log_utils import CommonLogUtils -from sims4communitylib.utils.common_type_utils import CommonTypeUtils -from sims4communitylib.utils.objects.common_object_interaction_utils import CommonObjectInteractionUtils -from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils -from sims4communitylib.utils.resources.common_interaction_utils import CommonInteractionUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction +from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.notifications.common_basic_notification import CommonBasicNotification +from s4ap.sims4communitylib.utils.common_log_utils import CommonLogUtils +from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils +from s4ap.sims4communitylib.utils.objects.common_object_interaction_utils import CommonObjectInteractionUtils +from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils +from s4ap.sims4communitylib.utils.resources.common_interaction_utils import CommonInteractionUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils class S4CLDebugLogAllInteractionsInteraction(CommonImmediateSuperInteraction): diff --git a/Scripts/s4ap/sims4communitylib/debug/interactions/object_break.py b/Scripts/s4ap/sims4communitylib/debug/interactions/object_break.py index 906c33f..4a788c9 100644 --- a/Scripts/s4ap/sims4communitylib/debug/interactions/object_break.py +++ b/Scripts/s4ap/sims4communitylib/debug/interactions/object_break.py @@ -9,12 +9,12 @@ from interactions.context import InteractionContext from objects.game_object import GameObject from sims.sim import Sim -from sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.utils.common_type_utils import CommonTypeUtils -from sims4communitylib.utils.objects.common_object_state_utils import CommonObjectStateUtils +from s4ap.sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils +from s4ap.sims4communitylib.utils.objects.common_object_state_utils import CommonObjectStateUtils class S4CLDebugObjectBreakInteraction(CommonImmediateSuperInteraction): diff --git a/Scripts/s4ap/sims4communitylib/debug/interactions/object_fix.py b/Scripts/s4ap/sims4communitylib/debug/interactions/object_fix.py index b675fb1..aab7251 100644 --- a/Scripts/s4ap/sims4communitylib/debug/interactions/object_fix.py +++ b/Scripts/s4ap/sims4communitylib/debug/interactions/object_fix.py @@ -9,12 +9,12 @@ from interactions.context import InteractionContext from objects.game_object import GameObject from sims.sim import Sim -from sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.utils.common_type_utils import CommonTypeUtils -from sims4communitylib.utils.objects.common_object_state_utils import CommonObjectStateUtils +from s4ap.sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils +from s4ap.sims4communitylib.utils.objects.common_object_state_utils import CommonObjectStateUtils class S4CLDebugObjectFixInteraction(CommonImmediateSuperInteraction): diff --git a/Scripts/s4ap/sims4communitylib/debug/interactions/object_make_clean.py b/Scripts/s4ap/sims4communitylib/debug/interactions/object_make_clean.py index af3bccf..b9f348a 100644 --- a/Scripts/s4ap/sims4communitylib/debug/interactions/object_make_clean.py +++ b/Scripts/s4ap/sims4communitylib/debug/interactions/object_make_clean.py @@ -9,12 +9,12 @@ from interactions.context import InteractionContext from objects.game_object import GameObject from sims.sim import Sim -from sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.utils.common_type_utils import CommonTypeUtils -from sims4communitylib.utils.objects.common_object_state_utils import CommonObjectStateUtils +from s4ap.sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils +from s4ap.sims4communitylib.utils.objects.common_object_state_utils import CommonObjectStateUtils class S4CLDebugObjectMakeCleanInteraction(CommonImmediateSuperInteraction): diff --git a/Scripts/s4ap/sims4communitylib/debug/interactions/object_make_dirty.py b/Scripts/s4ap/sims4communitylib/debug/interactions/object_make_dirty.py index ed24d56..f8ce293 100644 --- a/Scripts/s4ap/sims4communitylib/debug/interactions/object_make_dirty.py +++ b/Scripts/s4ap/sims4communitylib/debug/interactions/object_make_dirty.py @@ -9,12 +9,12 @@ from interactions.context import InteractionContext from objects.game_object import GameObject from sims.sim import Sim -from sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.utils.common_type_utils import CommonTypeUtils -from sims4communitylib.utils.objects.common_object_state_utils import CommonObjectStateUtils +from s4ap.sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils +from s4ap.sims4communitylib.utils.objects.common_object_state_utils import CommonObjectStateUtils class S4CLDebugObjectMakeDirtyInteraction(CommonImmediateSuperInteraction): diff --git a/Scripts/s4ap/sims4communitylib/debug/interactions/show_active_buffs.py b/Scripts/s4ap/sims4communitylib/debug/interactions/show_active_buffs.py index 52baf57..ebea254 100644 --- a/Scripts/s4ap/sims4communitylib/debug/interactions/show_active_buffs.py +++ b/Scripts/s4ap/sims4communitylib/debug/interactions/show_active_buffs.py @@ -10,16 +10,16 @@ from distributor.shared_messages import IconInfoData from interactions.context import InteractionContext from sims.sim import Sim -from sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification -from sims4communitylib.utils.common_type_utils import CommonTypeUtils -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.sims.common_buff_utils import CommonBuffUtils -from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.notifications.common_basic_notification import CommonBasicNotification +from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.sims.common_buff_utils import CommonBuffUtils +from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils class S4CLDebugShowActiveBuffsInteraction(CommonImmediateSuperInteraction): diff --git a/Scripts/s4ap/sims4communitylib/debug/interactions/show_running_and_queued_interactions.py b/Scripts/s4ap/sims4communitylib/debug/interactions/show_running_and_queued_interactions.py index 65ed00d..3caf959 100644 --- a/Scripts/s4ap/sims4communitylib/debug/interactions/show_running_and_queued_interactions.py +++ b/Scripts/s4ap/sims4communitylib/debug/interactions/show_running_and_queued_interactions.py @@ -10,15 +10,15 @@ from distributor.shared_messages import IconInfoData from interactions.context import InteractionContext from sims.sim import Sim -from sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification -from sims4communitylib.utils.common_type_utils import CommonTypeUtils -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.notifications.common_basic_notification import CommonBasicNotification +from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils class S4CLDebugShowRunningAndQueuedInteractionsInteraction(CommonImmediateSuperInteraction): @@ -50,8 +50,8 @@ def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_cont def on_started(self, interaction_sim: Sim, interaction_target: Sim) -> bool: target_sim_info = CommonSimUtils.get_sim_info(interaction_target) target_sim_name = CommonSimNameUtils.get_full_name(target_sim_info) - from sims4communitylib.utils.sims.common_sim_interaction_utils import CommonSimInteractionUtils - from sims4communitylib.utils.resources.common_interaction_utils import CommonInteractionUtils + from s4ap.sims4communitylib.utils.sims.common_sim_interaction_utils import CommonSimInteractionUtils + from s4ap.sims4communitylib.utils.resources.common_interaction_utils import CommonInteractionUtils running_interaction_strings: List[str] = list() for interaction in CommonSimInteractionUtils.get_running_interactions_gen(target_sim_info): interaction_name = CommonInteractionUtils.get_interaction_short_name(interaction) diff --git a/Scripts/s4ap/sims4communitylib/debug/interactions/show_running_situations.py b/Scripts/s4ap/sims4communitylib/debug/interactions/show_running_situations.py index d111895..efeecf1 100644 --- a/Scripts/s4ap/sims4communitylib/debug/interactions/show_running_situations.py +++ b/Scripts/s4ap/sims4communitylib/debug/interactions/show_running_situations.py @@ -10,17 +10,17 @@ from distributor.shared_messages import IconInfoData from interactions.context import InteractionContext from sims.sim import Sim -from sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification -from sims4communitylib.utils.common_type_utils import CommonTypeUtils -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from sims4communitylib.utils.resources.common_situation_utils import CommonSituationUtils -from sims4communitylib.utils.sims.common_sim_situation_utils import CommonSimSituationUtils +from s4ap.sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.notifications.common_basic_notification import CommonBasicNotification +from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.utils.resources.common_situation_utils import CommonSituationUtils +from s4ap.sims4communitylib.utils.sims.common_sim_situation_utils import CommonSimSituationUtils class S4CLDebugShowRunningSituationsInteraction(CommonImmediateSuperInteraction): diff --git a/Scripts/s4ap/sims4communitylib/debug/interactions/show_traits.py b/Scripts/s4ap/sims4communitylib/debug/interactions/show_traits.py index c6199c8..7d67717 100644 --- a/Scripts/s4ap/sims4communitylib/debug/interactions/show_traits.py +++ b/Scripts/s4ap/sims4communitylib/debug/interactions/show_traits.py @@ -10,16 +10,16 @@ from distributor.shared_messages import IconInfoData from interactions.context import InteractionContext from sims.sim import Sim -from sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification -from sims4communitylib.utils.common_type_utils import CommonTypeUtils -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils +from s4ap.sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.notifications.common_basic_notification import CommonBasicNotification +from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils class S4CLDebugShowTraitsInteraction(CommonImmediateSuperInteraction): diff --git a/Scripts/s4ap/sims4communitylib/debug/traits/_auto_apply_traits.py b/Scripts/s4ap/sims4communitylib/debug/traits/_auto_apply_traits.py index a0fb3e1..29756a8 100644 --- a/Scripts/s4ap/sims4communitylib/debug/traits/_auto_apply_traits.py +++ b/Scripts/s4ap/sims4communitylib/debug/traits/_auto_apply_traits.py @@ -6,13 +6,13 @@ Copyright (c) COLONOLNUTTY """ from sims.sim_info import SimInfo -from sims4communitylib.enums.traits_enum import CommonTraitId -from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from sims4communitylib.events.sim.events.sim_spawned import S4CLSimSpawnedEvent -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils -from sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils -from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils +from s4ap.sims4communitylib.enums.traits_enum import CommonTraitId +from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry +from s4ap.sims4communitylib.events.sim.events.sim_spawned import S4CLSimSpawnedEvent +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils +from s4ap.sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils +from s4ap.sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils class _S4CLAutoApplyTraits: diff --git a/Scripts/s4ap/sims4communitylib/dialogs/_common_ui_dialog_multi_text_input_ok_cancel.py b/Scripts/s4ap/sims4communitylib/dialogs/_common_ui_dialog_multi_text_input_ok_cancel.py index 70ba055..b97f652 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/_common_ui_dialog_multi_text_input_ok_cancel.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/_common_ui_dialog_multi_text_input_ok_cancel.py @@ -8,10 +8,10 @@ from typing import Tuple, Any, Callable, Iterator from protocolbuffers.Localization_pb2 import LocalizedString from sims.sim_info import SimInfo -from sims4communitylib.dialogs.common_input_text_field import CommonInputTextField -from sims4communitylib.enums.common_character_restrictions import CommonCharacterRestriction -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.dialogs.common_input_text_field import CommonInputTextField +from s4ap.sims4communitylib.enums.common_character_restrictions import CommonCharacterRestriction +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils from ui.ui_dialog_generic import UiDialogTextInputOkCancel diff --git a/Scripts/s4ap/sims4communitylib/dialogs/_common_ui_dialog_text_input_ok_cancel.py b/Scripts/s4ap/sims4communitylib/dialogs/_common_ui_dialog_text_input_ok_cancel.py index afecd18..b5efa1b 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/_common_ui_dialog_text_input_ok_cancel.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/_common_ui_dialog_text_input_ok_cancel.py @@ -8,7 +8,7 @@ from typing import Tuple, Any, Callable from protocolbuffers.Localization_pb2 import LocalizedString from sims.sim_info import SimInfo -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils from ui.ui_dialog_generic import UiDialogTextInputOkCancel @@ -41,7 +41,7 @@ def build_msg(self, text_input_overrides=None, additional_tokens: Tuple[Any]=(), """Build the message. """ - from sims4communitylib.dialogs.utils.common_dialog_utils import CommonDialogUtils + from s4ap.sims4communitylib.dialogs.utils.common_dialog_utils import CommonDialogUtils msg = super().build_msg(additional_tokens=(), **kwargs) text_input_msg = msg.text_input.add() text_input_msg.text_input_name = CommonDialogUtils.TEXT_INPUT_NAME diff --git a/Scripts/s4ap/sims4communitylib/dialogs/choose_item_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/choose_item_dialog.py index 15f8fd5..6ef9d91 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/choose_item_dialog.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/choose_item_dialog.py @@ -9,16 +9,16 @@ from pprint import pformat from protocolbuffers.Localization_pb2 import LocalizedString -from sims4communitylib.dialogs.utils.common_dialog_utils import CommonDialogUtils -from sims4communitylib.enums.enumtypes.common_int import CommonInt -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.dialogs.utils.common_dialog_utils import CommonDialogUtils +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils from ui.ui_dialog_picker import UiObjectPicker, ObjectPickerRow @@ -71,7 +71,7 @@ def _item_chosen(chosen_item: str, result: CommonChooseItemResult): # 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 + from s4ap.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, @@ -179,7 +179,7 @@ def _item_chosen(chosen_item: str, result: CommonChooseItemResult): # 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 + from s4ap.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, diff --git a/Scripts/s4ap/sims4communitylib/dialogs/choose_object_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/choose_object_dialog.py index 0697779..6c14b2b 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/choose_object_dialog.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/choose_object_dialog.py @@ -14,25 +14,25 @@ from distributor.shared_messages import IconInfoData from protocolbuffers.Localization_pb2 import LocalizedString from sims.sim_info import SimInfo -from sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome -from sims4communitylib.dialogs.common_choose_dialog import CommonChooseDialog -from sims4communitylib.dialogs.common_dialog_navigation_button_tag import CommonDialogNavigationButtonTag -from sims4communitylib.dialogs.custom_dialogs.picker_dialogs.common_ui_object_category_picker import \ +from s4ap.sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome +from s4ap.sims4communitylib.dialogs.common_choose_dialog import CommonChooseDialog +from s4ap.sims4communitylib.dialogs.common_dialog_navigation_button_tag import CommonDialogNavigationButtonTag +from s4ap.sims4communitylib.dialogs.custom_dialogs.picker_dialogs.common_ui_object_category_picker import \ CommonUiObjectCategoryPicker -from sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_option_category import \ +from s4ap.sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_option_category import \ CommonDialogObjectOptionCategory -from sims4communitylib.dialogs.utils.common_dialog_utils import CommonDialogUtils -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from sims4communitylib.utils.common_icon_utils import CommonIconUtils -from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.dialogs.utils.common_dialog_utils import CommonDialogUtils +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils +from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils from ui.ui_dialog_picker import UiObjectPicker, ObjectPickerRow @@ -64,7 +64,7 @@ def _on_chosen(choice: str, outcome: CommonChoiceOutcome): # 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 + from s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils options = [ ObjectPickerRow( option_id=1, @@ -480,7 +480,7 @@ def _on_chosen(choice: str, outcome: CommonChoiceOutcome): # 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 + from s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils options = [ ObjectPickerRow( option_id=1, diff --git a/Scripts/s4ap/sims4communitylib/dialogs/choose_objects_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/choose_objects_dialog.py index 41a17f9..3c1cd4d 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/choose_objects_dialog.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/choose_objects_dialog.py @@ -10,21 +10,21 @@ from pprint import pformat from protocolbuffers.Localization_pb2 import LocalizedString from sims.sim_info import SimInfo -from sims4communitylib.dialogs.choose_object_dialog import CommonChooseObjectDialog -from sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome -from sims4communitylib.dialogs.common_dialog_navigation_button_tag import CommonDialogNavigationButtonTag -from sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_option_category import \ +from s4ap.sims4communitylib.dialogs.choose_object_dialog import CommonChooseObjectDialog +from s4ap.sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome +from s4ap.sims4communitylib.dialogs.common_dialog_navigation_button_tag import CommonDialogNavigationButtonTag +from s4ap.sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_option_category import \ CommonDialogObjectOptionCategory -from sims4communitylib.dialogs.utils.common_dialog_utils import CommonDialogUtils -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.dialogs.utils.common_dialog_utils import CommonDialogUtils +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils from ui.ui_dialog_picker import UiObjectPicker, ObjectPickerRow @@ -56,7 +56,7 @@ def _on_chosen(choices: Tuple[str], outcome: CommonChoiceOutcome): # 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 + from s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils options = [ ObjectPickerRow( option_id=1, @@ -391,7 +391,7 @@ def _on_chosen(choices: Tuple[str], outcome: CommonChoiceOutcome): # 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 + from s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils options = [ ObjectPickerRow( option_id=1, diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_choice_outcome.py b/Scripts/s4ap/sims4communitylib/dialogs/common_choice_outcome.py index 36410bf..700939c 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/common_choice_outcome.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/common_choice_outcome.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonChoiceOutcome(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_choose_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/common_choose_dialog.py index 896ed4a..da748ca 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/common_choose_dialog.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/common_choose_dialog.py @@ -8,10 +8,10 @@ from abc import ABC from typing import Tuple, Any, Union, Iterator from protocolbuffers.Localization_pb2 import LocalizedString -from sims4communitylib.dialogs.common_dialog import CommonDialog -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.dialogs.common_dialog import CommonDialog +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils from ui.ui_dialog_picker import BasePickerRow diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_choose_outfit_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/common_choose_outfit_dialog.py index 63ae20d..febac04 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/common_choose_outfit_dialog.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/common_choose_outfit_dialog.py @@ -12,19 +12,19 @@ from protocolbuffers.Localization_pb2 import LocalizedString from sims.outfits.outfit_enums import OutfitCategory, HIDDEN_OUTFIT_CATEGORIES from sims.sim_info import SimInfo -from sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome -from sims4communitylib.dialogs.common_choose_dialog import CommonChooseDialog -from sims4communitylib.dialogs.utils.common_dialog_utils import CommonDialogUtils -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome +from s4ap.sims4communitylib.dialogs.common_choose_dialog import CommonChooseDialog +from s4ap.sims4communitylib.dialogs.utils.common_dialog_utils import CommonDialogUtils +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils from ui.ui_dialog_picker import OutfitPickerRow, UiOutfitPicker @@ -55,7 +55,7 @@ def _on_chosen(choice: Tuple[OutfitCategory, int], outcome: CommonChoiceOutcome) # 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=(sim_info,), text_color=CommonLocalizedStringColor.BLUE),) - from sims4communitylib.utils.common_icon_utils import CommonIconUtils + from s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils dialog = CommonChooseOutfitDialog( ModInfo.get_identity(), CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_choose_response_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/common_choose_response_dialog.py index b512352..9a1450d 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/common_choose_response_dialog.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/common_choose_response_dialog.py @@ -15,20 +15,20 @@ from event_testing.resolver import DoubleSimResolver from protocolbuffers.Localization_pb2 import LocalizedString from sims.sim_info import SimInfo -from sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome -from sims4communitylib.dialogs.common_dialog import CommonDialog -from sims4communitylib.dialogs.common_dialog_navigation_button_tag import CommonDialogNavigationButtonTag -from sims4communitylib.dialogs.common_ui_dialog_response import CommonUiDialogResponse -from sims4communitylib.dialogs.common_ui_response_dialog import CommonUiResponseDialog -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome +from s4ap.sims4communitylib.dialogs.common_dialog import CommonDialog +from s4ap.sims4communitylib.dialogs.common_dialog_navigation_button_tag import CommonDialogNavigationButtonTag +from s4ap.sims4communitylib.dialogs.common_ui_dialog_response import CommonUiDialogResponse +from s4ap.sims4communitylib.dialogs.common_ui_response_dialog import CommonUiResponseDialog +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils from ui.ui_dialog import UiDialogOption, ButtonType ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_choose_sim_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/common_choose_sim_dialog.py index c280c31..f25aa7b 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/common_choose_sim_dialog.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/common_choose_sim_dialog.py @@ -12,19 +12,19 @@ import random from protocolbuffers.Localization_pb2 import LocalizedString from sims.sim_info import SimInfo -from sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome -from sims4communitylib.dialogs.common_choose_dialog import CommonChooseDialog -from sims4communitylib.dialogs.utils.common_dialog_utils import CommonDialogUtils -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome +from s4ap.sims4communitylib.dialogs.common_choose_dialog import CommonChooseDialog +from s4ap.sims4communitylib.dialogs.utils.common_dialog_utils import CommonDialogUtils +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils from ui.ui_dialog_picker import UiSimPicker, SimPickerRow @@ -55,7 +55,7 @@ def _on_chosen(choice: Union[SimInfo, None], outcome: CommonChoiceOutcome): # 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 + from s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils current_count = 0 count = 25 options = [] diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_choose_sims_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/common_choose_sims_dialog.py index e5d1c1d..722e797 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/common_choose_sims_dialog.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/common_choose_sims_dialog.py @@ -13,20 +13,20 @@ from protocolbuffers.Localization_pb2 import LocalizedString from sims.sim_info import SimInfo -from sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome -from sims4communitylib.dialogs.common_choose_sim_dialog import CommonChooseSimDialog -from sims4communitylib.dialogs.option_dialogs.options.sims.common_dialog_sim_option import CommonDialogSimOption -from sims4communitylib.dialogs.utils.common_dialog_utils import CommonDialogUtils -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome +from s4ap.sims4communitylib.dialogs.common_choose_sim_dialog import CommonChooseSimDialog +from s4ap.sims4communitylib.dialogs.option_dialogs.options.sims.common_dialog_sim_option import CommonDialogSimOption +from s4ap.sims4communitylib.dialogs.utils.common_dialog_utils import CommonDialogUtils +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils from ui.ui_dialog_picker import UiSimPicker, SimPickerRow @@ -57,7 +57,7 @@ def _on_chosen(choice: Union[Tuple[SimInfo], None], outcome: CommonChoiceOutcome # 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 + from s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils current_count = 0 count = 25 options = [] diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/common_dialog.py index c53d266..ce74a44 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/common_dialog.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/common_dialog.py @@ -7,10 +7,10 @@ """ from typing import Any, Union, Iterator from protocolbuffers.Localization_pb2 import LocalizedString -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.logging.has_log import HasLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.logging.has_log import HasLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils from ui.ui_dialog import UiDialogBase diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_input_float_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/common_input_float_dialog.py index 6eb458a..74edfeb 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/common_input_float_dialog.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/common_input_float_dialog.py @@ -10,20 +10,20 @@ from pprint import pformat from protocolbuffers.Localization_pb2 import LocalizedString from sims.sim_info import SimInfo -from sims4communitylib.dialogs._common_ui_dialog_text_input_ok_cancel import _CommonUiDialogTextInputOkCancel -from sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome -from sims4communitylib.dialogs.common_dialog import CommonDialog -from sims4communitylib.dialogs.utils.common_dialog_utils import CommonDialogUtils -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.dialogs._common_ui_dialog_text_input_ok_cancel import _CommonUiDialogTextInputOkCancel +from s4ap.sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome +from s4ap.sims4communitylib.dialogs.common_dialog import CommonDialog +from s4ap.sims4communitylib.dialogs.utils.common_dialog_utils import CommonDialogUtils +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils from ui.ui_dialog_generic import UiDialogTextInput -from sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.modinfo import ModInfo class CommonInputFloatDialog(CommonDialog): @@ -53,7 +53,7 @@ def _on_submit(input_value: float, outcome: CommonChoiceOutcome): # 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 + from s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils dialog = CommonInputFloatDialog( CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_input_integer_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/common_input_integer_dialog.py index 419eeea..9cf5931 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/common_input_integer_dialog.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/common_input_integer_dialog.py @@ -10,20 +10,20 @@ from pprint import pformat from protocolbuffers.Localization_pb2 import LocalizedString from sims.sim_info import SimInfo -from sims4communitylib.dialogs._common_ui_dialog_text_input_ok_cancel import _CommonUiDialogTextInputOkCancel -from sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome -from sims4communitylib.dialogs.common_dialog import CommonDialog -from sims4communitylib.dialogs.utils.common_dialog_utils import CommonDialogUtils -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.dialogs._common_ui_dialog_text_input_ok_cancel import _CommonUiDialogTextInputOkCancel +from s4ap.sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome +from s4ap.sims4communitylib.dialogs.common_dialog import CommonDialog +from s4ap.sims4communitylib.dialogs.utils.common_dialog_utils import CommonDialogUtils +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils from ui.ui_dialog_generic import UiDialogTextInput -from sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.modinfo import ModInfo class CommonInputIntegerDialog(CommonDialog): @@ -53,7 +53,7 @@ def _on_submit(input_value: integer, outcome: CommonChoiceOutcome): # 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 + from s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils dialog = CommonInputIntegerDialog( CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_input_multi_text_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/common_input_multi_text_dialog.py index f3000be..23b0c17 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/common_input_multi_text_dialog.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/common_input_multi_text_dialog.py @@ -10,21 +10,21 @@ from pprint import pformat from protocolbuffers.Localization_pb2 import LocalizedString from sims.sim_info import SimInfo -from sims4communitylib.dialogs._common_ui_dialog_multi_text_input_ok_cancel import _CommonUiDialogMultiTextInputOkCancel -from sims4communitylib.dialogs._common_ui_dialog_text_input_ok_cancel import _CommonUiDialogTextInputOkCancel -from sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome -from sims4communitylib.dialogs.common_dialog import CommonDialog -from sims4communitylib.dialogs.common_input_text_field import CommonInputTextField -from sims4communitylib.enums.common_character_restrictions import CommonCharacterRestriction -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.dialogs._common_ui_dialog_multi_text_input_ok_cancel import _CommonUiDialogMultiTextInputOkCancel +from s4ap.sims4communitylib.dialogs._common_ui_dialog_text_input_ok_cancel import _CommonUiDialogTextInputOkCancel +from s4ap.sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome +from s4ap.sims4communitylib.dialogs.common_dialog import CommonDialog +from s4ap.sims4communitylib.dialogs.common_input_text_field import CommonInputTextField +from s4ap.sims4communitylib.enums.common_character_restrictions import CommonCharacterRestriction +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils from ui.ui_dialog_generic import UiDialogTextInput @@ -53,7 +53,7 @@ def _on_submit(input_value: str, outcome: CommonChoiceOutcome): # 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 + from s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils dialog = CommonInputMultiTextDialog( ModInfo.get_identity(), CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_input_text_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/common_input_text_dialog.py index 81645fb..9d20a2c 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/common_input_text_dialog.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/common_input_text_dialog.py @@ -10,19 +10,19 @@ from pprint import pformat from protocolbuffers.Localization_pb2 import LocalizedString from sims.sim_info import SimInfo -from sims4communitylib.dialogs._common_ui_dialog_text_input_ok_cancel import _CommonUiDialogTextInputOkCancel -from sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome -from sims4communitylib.dialogs.common_dialog import CommonDialog -from sims4communitylib.dialogs.utils.common_dialog_utils import CommonDialogUtils -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.dialogs._common_ui_dialog_text_input_ok_cancel import _CommonUiDialogTextInputOkCancel +from s4ap.sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome +from s4ap.sims4communitylib.dialogs.common_dialog import CommonDialog +from s4ap.sims4communitylib.dialogs.utils.common_dialog_utils import CommonDialogUtils +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils from ui.ui_dialog_generic import UiDialogTextInput @@ -51,7 +51,7 @@ def _on_submit(input_value: str, outcome: CommonChoiceOutcome): # 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 + from s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils dialog = CommonInputTextDialog( ModInfo.get_identity(), CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_input_text_field.py b/Scripts/s4ap/sims4communitylib/dialogs/common_input_text_field.py index 83add6e..4f4cbe2 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/common_input_text_field.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/common_input_text_field.py @@ -8,9 +8,9 @@ from typing import Union from protocolbuffers.Localization_pb2 import LocalizedString -from sims4communitylib.enums.common_character_restrictions import CommonCharacterRestriction -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.utils.localization.common_localized_string_separators import CommonLocalizedStringSeparator +from s4ap.sims4communitylib.enums.common_character_restrictions import CommonCharacterRestriction +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.utils.localization.common_localized_string_separators import CommonLocalizedStringSeparator class CommonInputTextField: diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_multi_pane_choose_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/common_multi_pane_choose_dialog.py index 1f2b499..1a9a36d 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/common_multi_pane_choose_dialog.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/common_multi_pane_choose_dialog.py @@ -10,21 +10,21 @@ from typing import Tuple, Any, Callable, Union, Iterator, List, Dict from protocolbuffers.Localization_pb2 import LocalizedString from sims.sim_info import SimInfo -from sims4communitylib.dialogs.choose_object_dialog import CommonChooseObjectDialog -from sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome -from sims4communitylib.dialogs.common_choose_dialog import CommonChooseDialog -from sims4communitylib.dialogs.common_dialog import CommonDialog -from sims4communitylib.dialogs.custom_dialogs.picker_dialogs.common_ui_multi_picker import CommonUiMultiPicker -from sims4communitylib.dialogs.utils.common_dialog_utils import CommonDialogUtils -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.dialogs.choose_object_dialog import CommonChooseObjectDialog +from s4ap.sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome +from s4ap.sims4communitylib.dialogs.common_choose_dialog import CommonChooseDialog +from s4ap.sims4communitylib.dialogs.common_dialog import CommonDialog +from s4ap.sims4communitylib.dialogs.custom_dialogs.picker_dialogs.common_ui_multi_picker import CommonUiMultiPicker +from s4ap.sims4communitylib.dialogs.utils.common_dialog_utils import CommonDialogUtils +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils from ui.ui_dialog import UiDialogBase from ui.ui_dialog_picker import ObjectPickerRow @@ -61,7 +61,7 @@ def _on_sub_dialog_two_chosen(choice: Any, outcome: CommonChoiceOutcome) -> None # 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 + from s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils # Create the dialog. dialog = CommonMultiPaneChooseDialog( ModInfo.get_identity(), @@ -341,7 +341,7 @@ def _on_sub_dialog_two_chosen(choice: Any, outcome: CommonChoiceOutcome) -> None # 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 + from s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils # Create the dialog. dialog = CommonMultiPaneChooseDialog( ModInfo.get_identity(), diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_ok_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/common_ok_dialog.py index eca8a6c..e2f4a13 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/common_ok_dialog.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/common_ok_dialog.py @@ -8,16 +8,16 @@ from typing import Any, Callable, Union, Iterator from protocolbuffers.Localization_pb2 import LocalizedString -from sims4communitylib.dialogs.common_dialog import CommonDialog -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.dialogs.common_dialog import CommonDialog +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils from ui.ui_dialog import UiDialogOk diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_purchase_objects_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/common_purchase_objects_dialog.py index f8d625e..173f289 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/common_purchase_objects_dialog.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/common_purchase_objects_dialog.py @@ -14,24 +14,24 @@ from interactions.base.picker_interaction import PurchasePickerData from protocolbuffers.Localization_pb2 import LocalizedString from sims.sim_info import SimInfo -from sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome -from sims4communitylib.dialogs.common_choose_dialog import CommonChooseDialog -from sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_option_category import \ +from s4ap.sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome +from s4ap.sims4communitylib.dialogs.common_choose_dialog import CommonChooseDialog +from s4ap.sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_option_category import \ CommonDialogObjectOptionCategory -from sims4communitylib.enums.common_object_delivery_method import CommonObjectDeliveryMethod -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.enums.tags_enum import CommonGameTag -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from sims4communitylib.utils.common_icon_utils import CommonIconUtils -from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils -from sims4communitylib.utils.sims.common_sim_inventory_utils import CommonSimInventoryUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.enums.common_object_delivery_method import CommonObjectDeliveryMethod +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.enums.tags_enum import CommonGameTag +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils +from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils +from s4ap.sims4communitylib.utils.sims.common_sim_inventory_utils import CommonSimInventoryUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils from ui.ui_dialog_picker import UiObjectPicker, UiPurchasePicker, PurchasePickerRow, UiDialogObjectPicker @@ -62,7 +62,7 @@ def _on_chosen(choices: Any, outcome: CommonChoiceOutcome): 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),) show_discount = True - from sims4communitylib.utils.common_icon_utils import CommonIconUtils + from s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils active_sim_info = CommonSimUtils.get_active_sim_info() obj_id = 20359 obj_definition = CommonObjectUtils.get_object_definition(obj_id) diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_targeted_question_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/common_targeted_question_dialog.py index 6d44f6f..e4a860a 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/common_targeted_question_dialog.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/common_targeted_question_dialog.py @@ -10,17 +10,17 @@ from event_testing.resolver import DoubleSimResolver from protocolbuffers.Localization_pb2 import LocalizedString from sims.sim_info import SimInfo -from sims4communitylib.dialogs.common_dialog import CommonDialog -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.dialogs.common_dialog import CommonDialog +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils from ui.ui_dialog import UiDialogOkCancel diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_ui_dialog_response.py b/Scripts/s4ap/sims4communitylib/dialogs/common_ui_dialog_response.py index 7bfb7d9..cd909d8 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/common_ui_dialog_response.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/common_ui_dialog_response.py @@ -7,8 +7,8 @@ """ from typing import Any, Union from protocolbuffers.Localization_pb2 import LocalizedString -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils from ui.ui_dialog import UiDialogResponse diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_ui_response_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/common_ui_response_dialog.py index c4b08b5..bfabc23 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/common_ui_response_dialog.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/common_ui_response_dialog.py @@ -5,20 +5,20 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.dialogs.common_ui_dialog_response import CommonUiDialogResponse -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.dialogs.common_ui_dialog_response import CommonUiDialogResponse +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput from ui.ui_dialog import UiDialog, UiDialogOption from typing import Tuple, Any, Iterator from event_testing.resolver import Resolver -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.logging.has_class_log import HasClassLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.logging.has_class_log import HasClassLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils class CommonUiResponseDialog(UiDialog, HasClassLog): diff --git a/Scripts/s4ap/sims4communitylib/dialogs/custom_dialogs/picker_dialogs/common_ui_multi_picker.py b/Scripts/s4ap/sims4communitylib/dialogs/custom_dialogs/picker_dialogs/common_ui_multi_picker.py index b9a7b79..42539eb 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/custom_dialogs/picker_dialogs/common_ui_multi_picker.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/custom_dialogs/picker_dialogs/common_ui_multi_picker.py @@ -7,7 +7,7 @@ """ from typing import Any, Dict from protocolbuffers.Localization_pb2 import LocalizedString -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils from protocolbuffers.Dialog_pb2 import UiDialogMessage, UiDialogMultiPicker from ui.ui_dialog_multi_picker import UiMultiPicker diff --git a/Scripts/s4ap/sims4communitylib/dialogs/ok_cancel_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/ok_cancel_dialog.py index cd34a2e..228e434 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/ok_cancel_dialog.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/ok_cancel_dialog.py @@ -8,16 +8,16 @@ from typing import Any, Callable, Union, Iterator from protocolbuffers.Localization_pb2 import LocalizedString -from sims4communitylib.dialogs.common_dialog import CommonDialog -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.dialogs.common_dialog import CommonDialog +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils from ui.ui_dialog import UiDialogOkCancel diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_button_option_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_button_option_dialog.py index 299df27..a9d3a4b 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_button_option_dialog.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_button_option_dialog.py @@ -11,25 +11,25 @@ from protocolbuffers.Localization_pb2 import LocalizedString from sims.sim_info import SimInfo -from sims4communitylib.dialogs.common_choose_response_dialog import CommonChooseResponseDialog -from sims4communitylib.dialogs.option_dialogs.common_choose_response_option_dialog import \ +from s4ap.sims4communitylib.dialogs.common_choose_response_dialog import CommonChooseResponseDialog +from s4ap.sims4communitylib.dialogs.option_dialogs.common_choose_response_option_dialog import \ CommonChooseResponseOptionDialog -from sims4communitylib.dialogs.option_dialogs.options.response.common_dialog_button_option import \ +from s4ap.sims4communitylib.dialogs.option_dialogs.options.response.common_dialog_button_option import \ CommonDialogButtonOption -from sims4communitylib.dialogs.option_dialogs.options.response.common_dialog_response_option_context import \ +from s4ap.sims4communitylib.dialogs.option_dialogs.options.response.common_dialog_response_option_context import \ CommonDialogResponseOptionContext -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ CommonConsoleCommandArgument -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.services.commands.common_console_command_parameters import \ +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.services.commands.common_console_command_parameters import \ CommonOptionalSimInfoConsoleCommandParameter -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils from ui.ui_dialog import UiDialogBase, UiDialogOption diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_object_option_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_object_option_dialog.py index b5ecd69..0a48228 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_object_option_dialog.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_object_option_dialog.py @@ -11,21 +11,21 @@ from protocolbuffers.Localization_pb2 import LocalizedString from sims.sim_info import SimInfo -from sims4communitylib.dialogs.choose_object_dialog import CommonChooseObjectDialog -from sims4communitylib.dialogs.option_dialogs.common_choose_option_dialog import CommonChooseOptionDialog -from sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext -from sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_option_category import \ +from s4ap.sims4communitylib.dialogs.choose_object_dialog import CommonChooseObjectDialog +from s4ap.sims4communitylib.dialogs.option_dialogs.common_choose_option_dialog import CommonChooseOptionDialog +from s4ap.sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext +from s4ap.sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_option_category import \ CommonDialogObjectOptionCategory -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_object_option import CommonDialogObjectOption -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_object_option import CommonDialogObjectOption +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils from ui.ui_dialog import UiDialogBase from ui.ui_dialog_picker import UiObjectPicker @@ -79,7 +79,7 @@ def _on_option_chosen(option_identifier: DialogOptionIdentifierType, choice: Dia per_page=2 ) - from sims4communitylib.utils.common_icon_utils import CommonIconUtils + from s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils # We add the options, in this case we have three options. option_dialog.add_option( @@ -310,7 +310,7 @@ def _on_option_chosen(option_identifier: str, choice: str): per_page=2 ) - from sims4communitylib.utils.common_icon_utils import CommonIconUtils + from s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils option_dialog.add_option( CommonDialogObjectOption( diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_objects_option_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_objects_option_dialog.py index 8c4a341..1cd0aa2 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_objects_option_dialog.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_objects_option_dialog.py @@ -11,22 +11,22 @@ from protocolbuffers.Localization_pb2 import LocalizedString from sims.sim_info import SimInfo -from sims4communitylib.dialogs.choose_objects_dialog import CommonChooseObjectsDialog -from sims4communitylib.dialogs.option_dialogs.common_choose_options_dialog import CommonChooseOptionsDialog -from sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext, \ +from s4ap.sims4communitylib.dialogs.choose_objects_dialog import CommonChooseObjectsDialog +from s4ap.sims4communitylib.dialogs.option_dialogs.common_choose_options_dialog import CommonChooseOptionsDialog +from s4ap.sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext, \ DialogOptionValueType -from sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_option_category import \ +from s4ap.sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_option_category import \ CommonDialogObjectOptionCategory -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_object_option import CommonDialogObjectOption -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_object_option import CommonDialogObjectOption +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils from ui.ui_dialog import UiDialogBase from ui.ui_dialog_picker import UiObjectPicker @@ -85,7 +85,7 @@ def _on_submit(choices: Tuple[str]): per_page=2 ) - from sims4communitylib.utils.common_icon_utils import CommonIconUtils + from s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils # We add the options, in this case we have three options. option_dialog.add_option( @@ -364,7 +364,7 @@ def _on_submit(choices: Tuple[str]): per_page=2 ) - from sims4communitylib.utils.common_icon_utils import CommonIconUtils + from s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils option_dialog.add_option( CommonDialogObjectOption( diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_option_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_option_dialog.py index b5c68c7..7d99997 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_option_dialog.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_option_dialog.py @@ -6,11 +6,11 @@ Copyright (c) COLONOLNUTTY """ from typing import Any, Callable, Union -from sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome -from sims4communitylib.dialogs.common_choose_dialog import CommonChooseDialog -from sims4communitylib.dialogs.option_dialogs.common_option_dialog import CommonOptionDialog -from sims4communitylib.dialogs.option_dialogs.options.common_dialog_option import CommonDialogOption -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome +from s4ap.sims4communitylib.dialogs.common_choose_dialog import CommonChooseDialog +from s4ap.sims4communitylib.dialogs.option_dialogs.common_option_dialog import CommonOptionDialog +from s4ap.sims4communitylib.dialogs.option_dialogs.options.common_dialog_option import CommonDialogOption +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils from ui.ui_dialog import UiDialogBase diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_options_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_options_dialog.py index 6857237..6f80ff2 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_options_dialog.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_options_dialog.py @@ -7,12 +7,12 @@ """ from typing import Union, Tuple, Any, Callable, List -from sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome -from sims4communitylib.dialogs.common_choose_dialog import CommonChooseDialog -from sims4communitylib.dialogs.option_dialogs.common_choose_option_dialog import CommonChooseOptionDialog -from sims4communitylib.dialogs.option_dialogs.options.common_dialog_option import CommonDialogOption -from sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import DialogOptionValueType -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome +from s4ap.sims4communitylib.dialogs.common_choose_dialog import CommonChooseDialog +from s4ap.sims4communitylib.dialogs.option_dialogs.common_choose_option_dialog import CommonChooseOptionDialog +from s4ap.sims4communitylib.dialogs.option_dialogs.options.common_dialog_option import CommonDialogOption +from s4ap.sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import DialogOptionValueType +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils # noinspection PyMissingOrEmptyDocstring diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_response_option_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_response_option_dialog.py index 2a7ff3d..46f2d44 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_response_option_dialog.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_response_option_dialog.py @@ -6,13 +6,13 @@ Copyright (c) COLONOLNUTTY """ from typing import Any, Callable, Union -from sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome -from sims4communitylib.dialogs.common_choose_response_dialog import CommonChooseResponseDialog -from sims4communitylib.dialogs.common_ui_response_dialog import CommonUiResponseDialog -from sims4communitylib.dialogs.option_dialogs.common_option_dialog import CommonOptionDialog -from sims4communitylib.dialogs.option_dialogs.options.response.common_dialog_response_option import \ +from s4ap.sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome +from s4ap.sims4communitylib.dialogs.common_choose_response_dialog import CommonChooseResponseDialog +from s4ap.sims4communitylib.dialogs.common_ui_response_dialog import CommonUiResponseDialog +from s4ap.sims4communitylib.dialogs.option_dialogs.common_option_dialog import CommonOptionDialog +from s4ap.sims4communitylib.dialogs.option_dialogs.options.response.common_dialog_response_option import \ CommonDialogResponseOption -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils class CommonChooseResponseOptionDialog(CommonOptionDialog): diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_sim_option_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_sim_option_dialog.py index f4bdc77..7e03e23 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_sim_option_dialog.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_sim_option_dialog.py @@ -10,21 +10,21 @@ from protocolbuffers.Localization_pb2 import LocalizedString from sims.sim_info import SimInfo -from sims4communitylib.dialogs.common_choose_sim_dialog import CommonChooseSimDialog -from sims4communitylib.dialogs.option_dialogs.common_choose_option_dialog import CommonChooseOptionDialog -from sims4communitylib.dialogs.option_dialogs.options.sims.common_dialog_sim_option_context import \ +from s4ap.sims4communitylib.dialogs.common_choose_sim_dialog import CommonChooseSimDialog +from s4ap.sims4communitylib.dialogs.option_dialogs.common_choose_option_dialog import CommonChooseOptionDialog +from s4ap.sims4communitylib.dialogs.option_dialogs.options.sims.common_dialog_sim_option_context import \ CommonDialogSimOptionContext -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from sims4communitylib.dialogs.option_dialogs.options.sims.common_dialog_sim_option import CommonDialogSimOption -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.dialogs.option_dialogs.options.sims.common_dialog_sim_option import CommonDialogSimOption +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils from ui.ui_dialog import UiDialogBase diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_sims_option_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_sims_option_dialog.py index d6f2e1c..77a3a88 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_sims_option_dialog.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_sims_option_dialog.py @@ -10,21 +10,21 @@ from protocolbuffers.Localization_pb2 import LocalizedString from sims.sim_info import SimInfo -from sims4communitylib.dialogs.common_choose_sims_dialog import CommonChooseSimsDialog -from sims4communitylib.dialogs.option_dialogs.common_choose_options_dialog import CommonChooseOptionsDialog -from sims4communitylib.dialogs.option_dialogs.options.sims.common_dialog_sim_option_context import \ +from s4ap.sims4communitylib.dialogs.common_choose_sims_dialog import CommonChooseSimsDialog +from s4ap.sims4communitylib.dialogs.option_dialogs.common_choose_options_dialog import CommonChooseOptionsDialog +from s4ap.sims4communitylib.dialogs.option_dialogs.options.sims.common_dialog_sim_option_context import \ CommonDialogSimOptionContext -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from sims4communitylib.dialogs.option_dialogs.options.sims.common_dialog_sim_option import CommonDialogSimOption -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.dialogs.option_dialogs.options.sims.common_dialog_sim_option import CommonDialogSimOption +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils from ui.ui_dialog import UiDialogBase diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_multi_pane_choose_option_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_multi_pane_choose_option_dialog.py index 61ded52..9872b9d 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_multi_pane_choose_option_dialog.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_multi_pane_choose_option_dialog.py @@ -11,25 +11,25 @@ from protocolbuffers.Localization_pb2 import LocalizedString from sims.sim_info import SimInfo -from sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome -from sims4communitylib.dialogs.common_multi_pane_choose_dialog import CommonMultiPaneChooseDialog -from sims4communitylib.dialogs.option_dialogs.common_choose_object_option_dialog import CommonChooseObjectOptionDialog -from sims4communitylib.dialogs.option_dialogs.common_choose_option_dialog import CommonChooseOptionDialog -from sims4communitylib.dialogs.option_dialogs.common_option_dialog import CommonOptionDialog -from sims4communitylib.dialogs.option_dialogs.options.common_dialog_option import CommonDialogOption -from sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext, \ +from s4ap.sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome +from s4ap.sims4communitylib.dialogs.common_multi_pane_choose_dialog import CommonMultiPaneChooseDialog +from s4ap.sims4communitylib.dialogs.option_dialogs.common_choose_object_option_dialog import CommonChooseObjectOptionDialog +from s4ap.sims4communitylib.dialogs.option_dialogs.common_choose_option_dialog import CommonChooseOptionDialog +from s4ap.sims4communitylib.dialogs.option_dialogs.common_option_dialog import CommonOptionDialog +from s4ap.sims4communitylib.dialogs.option_dialogs.options.common_dialog_option import CommonDialogOption +from s4ap.sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext, \ DialogOptionValueType -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_object_option import CommonDialogObjectOption -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from sims4communitylib.utils.common_icon_utils import CommonIconUtils +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_object_option import CommonDialogObjectOption +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils from ui.ui_dialog import UiDialogBase diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_option_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_option_dialog.py index d421539..1e80b7f 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_option_dialog.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_option_dialog.py @@ -7,10 +7,10 @@ """ from typing import Any, Callable, Union from protocolbuffers.Localization_pb2 import LocalizedString -from sims4communitylib.dialogs.common_dialog import CommonDialog -from sims4communitylib.logging.has_log import HasLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.dialogs.common_dialog import CommonDialog +from s4ap.sims4communitylib.logging.has_log import HasLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils from ui.ui_dialog import UiDialogBase diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/common_dialog_option.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/common_dialog_option.py index 9673631..3766639 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/common_dialog_option.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/common_dialog_option.py @@ -8,10 +8,10 @@ from typing import Any, Callable, Union, Tuple from protocolbuffers.Localization_pb2 import LocalizedString -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils from ui.ui_dialog_picker import BasePickerRow -from sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext, \ +from s4ap.sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext, \ DialogOptionValueType diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/common_dialog_option_context.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/common_dialog_option_context.py index bb6e497..20e6207 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/common_dialog_option_context.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/common_dialog_option_context.py @@ -7,8 +7,8 @@ """ from typing import Union, Any, TypeVar, Iterator, Tuple, List from protocolbuffers.Localization_pb2 import LocalizedString -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils DialogOptionValueType = TypeVar('DialogOptionValueType') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_action_option.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_action_option.py index 85f4894..a7c4e3b 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_action_option.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_action_option.py @@ -7,9 +7,9 @@ """ from typing import Any, Callable -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext -from sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_select_option import CommonDialogSelectOption +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext +from s4ap.sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_select_option import CommonDialogSelectOption class CommonDialogActionOption(CommonDialogSelectOption): diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_branch_option.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_branch_option.py index 9b884ed..7b6618e 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_branch_option.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_branch_option.py @@ -6,10 +6,10 @@ Copyright (c) COLONOLNUTTY """ from typing import Any, Callable -from sims4communitylib.dialogs.option_dialogs.common_option_dialog import CommonOptionDialog -from sims4communitylib.utils.common_icon_utils import CommonIconUtils -from sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_object_option import CommonDialogObjectOption -from sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext +from s4ap.sims4communitylib.dialogs.option_dialogs.common_option_dialog import CommonOptionDialog +from s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils +from s4ap.sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_object_option import CommonDialogObjectOption +from s4ap.sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext class CommonDialogOpenDialogOption(CommonDialogObjectOption): diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_integer_option.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_integer_option.py index ea9af84..3e1df43 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_integer_option.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_integer_option.py @@ -8,16 +8,16 @@ from typing import Any, Callable, Union, Iterator from protocolbuffers.Localization_pb2 import LocalizedString -from sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome -from sims4communitylib.dialogs.common_input_integer_dialog import CommonInputIntegerDialog -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from sims4communitylib.utils.common_icon_utils import CommonIconUtils -from sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_object_option import \ +from s4ap.sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome +from s4ap.sims4communitylib.dialogs.common_input_integer_dialog import CommonInputIntegerDialog +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils +from s4ap.sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_object_option import \ CommonDialogObjectOption, DialogOptionIdentifierType -from sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils class CommonDialogInputIntegerOption(CommonDialogObjectOption): diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_multi_text_option.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_multi_text_option.py index 890d1bf..12bc6ef 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_multi_text_option.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_multi_text_option.py @@ -8,17 +8,17 @@ from typing import Any, Callable, Union, Iterator, Dict from protocolbuffers.Localization_pb2 import LocalizedString -from sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome -from sims4communitylib.dialogs.common_input_multi_text_dialog import CommonInputMultiTextDialog -from sims4communitylib.dialogs.common_input_text_field import CommonInputTextField -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from sims4communitylib.utils.common_icon_utils import CommonIconUtils -from sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_object_option import \ +from s4ap.sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome +from s4ap.sims4communitylib.dialogs.common_input_multi_text_dialog import CommonInputMultiTextDialog +from s4ap.sims4communitylib.dialogs.common_input_text_field import CommonInputTextField +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils +from s4ap.sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_object_option import \ CommonDialogObjectOption, DialogOptionIdentifierType -from sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils class CommonDialogInputMultiTextOption(CommonDialogObjectOption): diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_option.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_option.py index 55a2cc0..e775189 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_option.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_option.py @@ -8,15 +8,15 @@ from typing import Any, Callable, Union, Iterator from protocolbuffers.Localization_pb2 import LocalizedString -from sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from sims4communitylib.utils.common_icon_utils import CommonIconUtils -from sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_object_option import \ +from s4ap.sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils +from s4ap.sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_object_option import \ CommonDialogObjectOption, DialogOptionIdentifierType -from sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext -from sims4communitylib.dialogs.common_input_float_dialog import CommonInputFloatDialog -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext +from s4ap.sims4communitylib.dialogs.common_input_float_dialog import CommonInputFloatDialog +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils class CommonDialogInputFloatOption(CommonDialogObjectOption): diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_text_option.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_text_option.py index 6ed167e..995e643 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_text_option.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_text_option.py @@ -8,16 +8,16 @@ from typing import Any, Callable, Union, Iterator from protocolbuffers.Localization_pb2 import LocalizedString -from sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome -from sims4communitylib.dialogs.common_input_text_dialog import CommonInputTextDialog -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from sims4communitylib.utils.common_icon_utils import CommonIconUtils -from sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_object_option import \ +from s4ap.sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome +from s4ap.sims4communitylib.dialogs.common_input_text_dialog import CommonInputTextDialog +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils +from s4ap.sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_object_option import \ CommonDialogObjectOption, DialogOptionIdentifierType -from sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils class CommonDialogInputTextOption(CommonDialogObjectOption): diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_object_option.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_object_option.py index 963d975..9d5b880 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_object_option.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_object_option.py @@ -6,10 +6,10 @@ Copyright (c) COLONOLNUTTY """ from typing import Any, Callable, TypeVar -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils from ui.ui_dialog_picker import ObjectPickerRow -from sims4communitylib.dialogs.option_dialogs.options.common_dialog_option import CommonDialogOption -from sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext, \ +from s4ap.sims4communitylib.dialogs.option_dialogs.options.common_dialog_option import CommonDialogOption +from s4ap.sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext, \ DialogOptionValueType DialogOptionIdentifierType = TypeVar('DialogOptionIdentifierType') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_option_category.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_option_category.py index c653647..813dd29 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_option_category.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_option_category.py @@ -8,8 +8,8 @@ from typing import Union from protocolbuffers.Localization_pb2 import LocalizedString -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils class CommonDialogObjectOptionCategory: diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_select_option.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_select_option.py index f2ba2cb..93eaa0a 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_select_option.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_select_option.py @@ -7,11 +7,11 @@ """ from typing import Any, Callable -from sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import DialogOptionValueType, \ +from s4ap.sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import DialogOptionValueType, \ CommonDialogOptionContext -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from sims4communitylib.utils.common_icon_utils import CommonIconUtils -from sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_object_option import \ +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils +from s4ap.sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_object_option import \ CommonDialogObjectOption, DialogOptionIdentifierType diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_toggle_option.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_toggle_option.py index 77b402d..886fe79 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_toggle_option.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_toggle_option.py @@ -7,11 +7,11 @@ """ from typing import Any, Callable, Union -from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from sims4communitylib.utils.common_icon_utils import CommonIconUtils -from sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_object_option import \ +from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from s4ap.sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils +from s4ap.sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_object_option import \ CommonDialogObjectOption, DialogOptionIdentifierType diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/response/common_dialog_button_option.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/response/common_dialog_button_option.py index 738d044..972c70c 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/response/common_dialog_button_option.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/response/common_dialog_button_option.py @@ -7,12 +7,12 @@ """ from typing import Any, Callable, TypeVar -from sims4communitylib.dialogs.common_ui_dialog_response import CommonUiDialogResponse -from sims4communitylib.dialogs.option_dialogs.options.response.common_dialog_response_option import \ +from s4ap.sims4communitylib.dialogs.common_ui_dialog_response import CommonUiDialogResponse +from s4ap.sims4communitylib.dialogs.option_dialogs.options.response.common_dialog_response_option import \ CommonDialogResponseOption -from sims4communitylib.dialogs.option_dialogs.options.response.common_dialog_response_option_context import \ +from s4ap.sims4communitylib.dialogs.option_dialogs.options.response.common_dialog_response_option_context import \ DialogResponseOptionValueType, CommonDialogResponseOptionContext -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils DialogResponseOptionIdentifierType = TypeVar('DialogResponseOptionIdentifierType') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/response/common_dialog_response_option.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/response/common_dialog_response_option.py index 1efc5df..feabfa0 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/response/common_dialog_response_option.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/response/common_dialog_response_option.py @@ -8,10 +8,10 @@ from typing import Any, Callable, Union from protocolbuffers.Localization_pb2 import LocalizedString -from sims4communitylib.dialogs.common_ui_dialog_response import CommonUiDialogResponse -from sims4communitylib.dialogs.option_dialogs.options.response.common_dialog_response_option_context import \ +from s4ap.sims4communitylib.dialogs.common_ui_dialog_response import CommonUiDialogResponse +from s4ap.sims4communitylib.dialogs.option_dialogs.options.response.common_dialog_response_option_context import \ DialogResponseOptionValueType, CommonDialogResponseOptionContext -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils class CommonDialogResponseOption: diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/response/common_dialog_response_option_context.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/response/common_dialog_response_option_context.py index b7f5783..1ddcc58 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/response/common_dialog_response_option_context.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/response/common_dialog_response_option_context.py @@ -7,8 +7,8 @@ """ from typing import Union, Any, TypeVar, Iterator from protocolbuffers.Localization_pb2 import LocalizedString -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils DialogResponseOptionValueType = TypeVar('DialogResponseOptionValueType') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/sims/common_dialog_sim_option.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/sims/common_dialog_sim_option.py index ef0674e..d8f5cd7 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/sims/common_dialog_sim_option.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/sims/common_dialog_sim_option.py @@ -7,11 +7,11 @@ """ from typing import Any, Callable from sims.sim_info import SimInfo -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils from ui.ui_dialog_picker import SimPickerRow -from sims4communitylib.dialogs.option_dialogs.options.common_dialog_option import CommonDialogOption -from sims4communitylib.dialogs.option_dialogs.options.sims.common_dialog_sim_option_context import CommonDialogSimOptionContext +from s4ap.sims4communitylib.dialogs.option_dialogs.options.common_dialog_option import CommonDialogOption +from s4ap.sims4communitylib.dialogs.option_dialogs.options.sims.common_dialog_sim_option_context import CommonDialogSimOptionContext class CommonDialogSimOption(CommonDialogOption): diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/sims/common_dialog_sim_option_context.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/sims/common_dialog_sim_option_context.py index 0ff3351..ff7a1cf 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/sims/common_dialog_sim_option_context.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/sims/common_dialog_sim_option_context.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext +from s4ap.sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext class CommonDialogSimOptionContext(CommonDialogOptionContext): diff --git a/Scripts/s4ap/sims4communitylib/dialogs/premade_dialogs/common_choose_sim_demographic_types_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/premade_dialogs/common_choose_sim_demographic_types_dialog.py index 33d8e5a..37be716 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/premade_dialogs/common_choose_sim_demographic_types_dialog.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/premade_dialogs/common_choose_sim_demographic_types_dialog.py @@ -8,19 +8,19 @@ from typing import Callable, Tuple, Union, Iterator from protocolbuffers.Localization_pb2 import LocalizedString -from sims4communitylib.dialogs.option_dialogs.common_choose_objects_option_dialog import CommonChooseObjectsOptionDialog -from sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext -from sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_action_option import \ +from s4ap.sims4communitylib.dialogs.option_dialogs.common_choose_objects_option_dialog import CommonChooseObjectsOptionDialog +from s4ap.sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext +from s4ap.sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_action_option import \ CommonDialogActionOption -from sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_select_option import \ +from s4ap.sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_select_option import \ CommonDialogSelectOption -from sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.logging._has_s4cl_log import _HasS4CLLog -from sims4communitylib.utils.common_collection_utils import CommonCollectionUtils -from sims4communitylib.utils.common_icon_utils import CommonIconUtils -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from s4ap.sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.logging._has_s4cl_log import _HasS4CLLog +from s4ap.sims4communitylib.utils.common_collection_utils import CommonCollectionUtils +from s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor class CommonChooseSimDemographicTypesDialog(_HasS4CLLog): diff --git a/Scripts/s4ap/sims4communitylib/dialogs/premade_dialogs/common_premade_choose_sim_option_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/premade_dialogs/common_premade_choose_sim_option_dialog.py index d182c6a..e673050 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/premade_dialogs/common_premade_choose_sim_option_dialog.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/premade_dialogs/common_premade_choose_sim_option_dialog.py @@ -8,21 +8,21 @@ from typing import Union, Any, Iterator, Callable from protocolbuffers.Localization_pb2 import LocalizedString from sims.sim_info import SimInfo -from sims4communitylib.dialogs.option_dialogs.common_choose_sim_option_dialog import CommonChooseSimOptionDialog -from sims4communitylib.dialogs.option_dialogs.options.sims.common_dialog_sim_option import CommonDialogSimOption -from sims4communitylib.dialogs.option_dialogs.options.sims.common_dialog_sim_option_context import \ +from s4ap.sims4communitylib.dialogs.option_dialogs.common_choose_sim_option_dialog import CommonChooseSimOptionDialog +from s4ap.sims4communitylib.dialogs.option_dialogs.options.sims.common_dialog_sim_option import CommonDialogSimOption +from s4ap.sims4communitylib.dialogs.option_dialogs.options.sims.common_dialog_sim_option_context import \ CommonDialogSimOptionContext -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils -from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from s4ap.sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils +from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils class CommonPremadeChooseSimOptionDialog(CommonChooseSimOptionDialog): diff --git a/Scripts/s4ap/sims4communitylib/dialogs/premade_dialogs/common_premade_choose_sims_option_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/premade_dialogs/common_premade_choose_sims_option_dialog.py index bbe6b1d..9ae0cbd 100644 --- a/Scripts/s4ap/sims4communitylib/dialogs/premade_dialogs/common_premade_choose_sims_option_dialog.py +++ b/Scripts/s4ap/sims4communitylib/dialogs/premade_dialogs/common_premade_choose_sims_option_dialog.py @@ -10,21 +10,21 @@ from typing import Union, Any, Iterator, Callable, Tuple from protocolbuffers.Localization_pb2 import LocalizedString from sims.sim_info import SimInfo -from sims4communitylib.dialogs.option_dialogs.common_choose_sims_option_dialog import CommonChooseSimsOptionDialog -from sims4communitylib.dialogs.option_dialogs.options.sims.common_dialog_sim_option import CommonDialogSimOption -from sims4communitylib.dialogs.option_dialogs.options.sims.common_dialog_sim_option_context import \ +from s4ap.sims4communitylib.dialogs.option_dialogs.common_choose_sims_option_dialog import CommonChooseSimsOptionDialog +from s4ap.sims4communitylib.dialogs.option_dialogs.options.sims.common_dialog_sim_option import CommonDialogSimOption +from s4ap.sims4communitylib.dialogs.option_dialogs.options.sims.common_dialog_sim_option_context import \ CommonDialogSimOptionContext -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils -from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from s4ap.sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils +from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils class CommonPremadeChooseSimsOptionDialog(CommonChooseSimsOptionDialog): diff --git a/Scripts/s4ap/sims4communitylib/dtos/common_cas_part.py b/Scripts/s4ap/sims4communitylib/dtos/common_cas_part.py index 39e2514..4825b66 100644 --- a/Scripts/s4ap/sims4communitylib/dtos/common_cas_part.py +++ b/Scripts/s4ap/sims4communitylib/dtos/common_cas_part.py @@ -8,7 +8,7 @@ from typing import Union from sims.outfits.outfit_enums import BodyType -from sims4communitylib.enums.common_body_slot import CommonBodySlot +from s4ap.sims4communitylib.enums.common_body_slot import CommonBodySlot class CommonCASPart: @@ -27,7 +27,7 @@ class CommonCASPart: def __init__(self, cas_part_id: int, body_type: Union[CommonBodySlot, BodyType, int, None] = None) -> None: self._cas_part_id = cas_part_id - from sims4communitylib.utils.cas.common_cas_utils import CommonCASUtils + from s4ap.sims4communitylib.utils.cas.common_cas_utils import CommonCASUtils self._body_type = body_type or CommonCASUtils.get_body_type_of_cas_part(cas_part_id) @property diff --git a/Scripts/s4ap/sims4communitylib/dtos/common_outfit.py b/Scripts/s4ap/sims4communitylib/dtos/common_outfit.py index 4b30b78..52e3c12 100644 --- a/Scripts/s4ap/sims4communitylib/dtos/common_outfit.py +++ b/Scripts/s4ap/sims4communitylib/dtos/common_outfit.py @@ -9,11 +9,11 @@ from sims.outfits.outfit_enums import BodyType, OutfitCategory from sims.sim_info import SimInfo -from sims4communitylib.classes.serialization.common_serializable import CommonSerializable -from sims4communitylib.enums.common_body_slot import CommonBodySlot -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.services.sim.cas.common_sim_outfit_io import CommonSimOutfitIO -from sims4communitylib.utils.common_resource_utils import CommonResourceUtils +from s4ap.sims4communitylib.classes.serialization.common_serializable import CommonSerializable +from s4ap.sims4communitylib.enums.common_body_slot import CommonBodySlot +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.services.sim.cas.common_sim_outfit_io import CommonSimOutfitIO +from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils class CommonOutfit(CommonSerializable): diff --git a/Scripts/s4ap/sims4communitylib/enums/affordance_list_ids.py b/Scripts/s4ap/sims4communitylib/enums/affordance_list_ids.py index 36723f6..cdc6676 100644 --- a/Scripts/s4ap/sims4communitylib/enums/affordance_list_ids.py +++ b/Scripts/s4ap/sims4communitylib/enums/affordance_list_ids.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonAffordanceListId(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/animation_state_machines_enum.py b/Scripts/s4ap/sims4communitylib/enums/animation_state_machines_enum.py index 2385a8a..d9a4ebe 100644 --- a/Scripts/s4ap/sims4communitylib/enums/animation_state_machines_enum.py +++ b/Scripts/s4ap/sims4communitylib/enums/animation_state_machines_enum.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonAnimationStateMachineId(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/buffs_enum.py b/Scripts/s4ap/sims4communitylib/enums/buffs_enum.py index 01a6f3a..b8b1ae2 100644 --- a/Scripts/s4ap/sims4communitylib/enums/buffs_enum.py +++ b/Scripts/s4ap/sims4communitylib/enums/buffs_enum.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonBuffId(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/clubs_enum.py b/Scripts/s4ap/sims4communitylib/enums/clubs_enum.py index 245ca17..1073e3e 100644 --- a/Scripts/s4ap/sims4communitylib/enums/clubs_enum.py +++ b/Scripts/s4ap/sims4communitylib/enums/clubs_enum.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonClubInteractionGroupId(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/common_age.py b/Scripts/s4ap/sims4communitylib/enums/common_age.py index 723ac8a..b54cdfc 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_age.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_age.py @@ -9,7 +9,7 @@ from sims.sim_info import SimInfo from sims.sim_info_types import Age -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonAge(CommonInt): @@ -81,7 +81,7 @@ def get_age(sim_info: SimInfo) -> 'CommonAge': :return: The CommonAge that represents what age a Sim is or INVALID if their age cannot be determined. :rtype: CommonAge """ - from sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils + from s4ap.sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils if CommonAgeUtils.is_baby(sim_info): return CommonAge.BABY elif CommonAgeUtils.is_infant(sim_info): @@ -168,7 +168,7 @@ def convert_to_localized_string_id(value: Union[int, 'CommonAge']) -> Union[int, :return: The specified CommonAge translated to a localized string identifier. If no localized string id is found, the name property of the value will be used instead. :rtype: Union[int, str] """ - from sims4communitylib.enums.strings_enum import CommonStringId + from s4ap.sims4communitylib.enums.strings_enum import CommonStringId display_name_mapping = { CommonAge.BABY: CommonStringId.BABY, CommonAge.INFANT: CommonStringId.INFANT, diff --git a/Scripts/s4ap/sims4communitylib/enums/common_appearance_modifier_priority.py b/Scripts/s4ap/sims4communitylib/enums/common_appearance_modifier_priority.py index ef36d68..635c854 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_appearance_modifier_priority.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_appearance_modifier_priority.py @@ -8,7 +8,7 @@ from typing import Union, Iterator, Tuple from buffs.appearance_modifier.appearance_modifier import AppearanceModifierPriority -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonAppearanceModifierPriority(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/common_appearance_modifier_type.py b/Scripts/s4ap/sims4communitylib/enums/common_appearance_modifier_type.py index ac16208..f42f145 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_appearance_modifier_type.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_appearance_modifier_type.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonAppearanceModifierType(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/common_body_frame.py b/Scripts/s4ap/sims4communitylib/enums/common_body_frame.py index 8e60f1c..3a2918f 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_body_frame.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_body_frame.py @@ -8,9 +8,9 @@ from typing import Tuple, Iterator from sims.sim_info import SimInfo -from sims4communitylib.enums.enumtypes.common_int import CommonInt -from sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils -from sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils +from s4ap.sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils class CommonBodyFrame(CommonInt): @@ -63,7 +63,7 @@ def get_body_frame(sim_info: SimInfo) -> 'CommonBodyFrame': :return: The body frame of the Sim or INVALID if their current body frame cannot be determined. :rtype: CommonBodyFrame """ - from sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils + from s4ap.sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils if CommonSpeciesUtils.is_animal(sim_info): if CommonGenderUtils.is_male(sim_info): return CommonBodyFrame.MASCULINE diff --git a/Scripts/s4ap/sims4communitylib/enums/common_body_slot.py b/Scripts/s4ap/sims4communitylib/enums/common_body_slot.py index 8df89ac..2c77d75 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_body_slot.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_body_slot.py @@ -8,7 +8,7 @@ from typing import Union, Iterator, Tuple from sims.outfits.outfit_enums import BodyType -from sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags +from s4ap.sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags class CommonBodySlot(CommonIntFlags): diff --git a/Scripts/s4ap/sims4communitylib/enums/common_bucks_types.py b/Scripts/s4ap/sims4communitylib/enums/common_bucks_types.py index 007863f..504420d 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_bucks_types.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_bucks_types.py @@ -8,7 +8,7 @@ from typing import Iterator, Tuple, Union from bucks.bucks_enums import BucksType -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonBucksType(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/common_business_advertising_type.py b/Scripts/s4ap/sims4communitylib/enums/common_business_advertising_type.py index 2f5387e..037c3d3 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_business_advertising_type.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_business_advertising_type.py @@ -8,7 +8,7 @@ from typing import Iterator, Tuple, Union from business.business_enums import BusinessAdvertisingType -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonBusinessAdvertisingType(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/common_business_customer_star_rating_type.py b/Scripts/s4ap/sims4communitylib/enums/common_business_customer_star_rating_type.py index d547c38..ba0522f 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_business_customer_star_rating_type.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_business_customer_star_rating_type.py @@ -8,7 +8,7 @@ from typing import Iterator, Tuple, Union from business.business_enums import BusinessCustomerStarRatingBuffBuckets -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonBusinessCustomerStarRatingType(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/common_business_employee_type.py b/Scripts/s4ap/sims4communitylib/enums/common_business_employee_type.py index 3b15b97..d94130f 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_business_employee_type.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_business_employee_type.py @@ -8,7 +8,7 @@ from typing import Iterator, Tuple, Union from business.business_enums import BusinessEmployeeType -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonBusinessEmployeeType(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/common_business_quality_type.py b/Scripts/s4ap/sims4communitylib/enums/common_business_quality_type.py index 1b31fd0..3f950ff 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_business_quality_type.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_business_quality_type.py @@ -8,7 +8,7 @@ from typing import Iterator, Tuple, Union from business.business_enums import BusinessQualityType -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonBusinessQualityType(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/common_career_ids.py b/Scripts/s4ap/sims4communitylib/enums/common_career_ids.py index 5122c93..e1cb913 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_career_ids.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_career_ids.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonCareerId(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/common_character_restrictions.py b/Scripts/s4ap/sims4communitylib/enums/common_character_restrictions.py index f49406c..a9b4449 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_character_restrictions.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_character_restrictions.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonCharacterRestriction(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/common_civic_policy_status_type.py b/Scripts/s4ap/sims4communitylib/enums/common_civic_policy_status_type.py index b5c727e..ebf0453 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_civic_policy_status_type.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_civic_policy_status_type.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonCivicPolicyStatusType(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/common_civic_policy_type.py b/Scripts/s4ap/sims4communitylib/enums/common_civic_policy_type.py index d0483de..8ad717e 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_civic_policy_type.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_civic_policy_type.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonCivicPolicyType(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/common_cloud_type.py b/Scripts/s4ap/sims4communitylib/enums/common_cloud_type.py index f0c8f14..8737c64 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_cloud_type.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_cloud_type.py @@ -7,7 +7,7 @@ """ from typing import Tuple, Union, Iterator -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt # noinspection PyBroadException try: diff --git a/Scripts/s4ap/sims4communitylib/enums/common_combined_species.py b/Scripts/s4ap/sims4communitylib/enums/common_combined_species.py index 3ff58b7..0ff5439 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_combined_species.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_combined_species.py @@ -7,7 +7,7 @@ """ from typing import Tuple -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonCombinedSpecies(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/common_currency_modify_reasons.py b/Scripts/s4ap/sims4communitylib/enums/common_currency_modify_reasons.py index f973802..22f95a3 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_currency_modify_reasons.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_currency_modify_reasons.py @@ -6,7 +6,7 @@ Copyright (c) COLONOLNUTTY """ from protocolbuffers import Consts_pb2 -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonCurrencyModifyReason(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/common_death_types.py b/Scripts/s4ap/sims4communitylib/enums/common_death_types.py index d37c420..73f1df1 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_death_types.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_death_types.py @@ -8,7 +8,7 @@ from typing import Union from interactions.utils.death import DeathType -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonDeathType(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/common_enum.py b/Scripts/s4ap/sims4communitylib/enums/common_enum.py index 48774f6..96bc2b1 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_enum.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_enum.py @@ -41,7 +41,7 @@ def __call__(cls, val: Any): @classmethod def _get_common_enum(mcs, enum_name: str, enum_value: Any, class_name: str): - from sims4communitylib.enums.enumtypes.object_enum import CommonEnumObject + from s4ap.sims4communitylib.enums.enumtypes.object_enum import CommonEnumObject return CommonEnumObject(enum_name, enum_value, class_name) @classmethod diff --git a/Scripts/s4ap/sims4communitylib/enums/common_fund_types.py b/Scripts/s4ap/sims4communitylib/enums/common_fund_types.py index e3343ab..551ce57 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_fund_types.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_fund_types.py @@ -7,7 +7,7 @@ """ # This class is obsolete, please use CommonFundsSource from common_funds_sources instead. -from sims4communitylib.enums.common_funds_sources import CommonFundsSource +from s4ap.sims4communitylib.enums.common_funds_sources import CommonFundsSource CommonFundType = CommonFundsSource diff --git a/Scripts/s4ap/sims4communitylib/enums/common_funds_sources.py b/Scripts/s4ap/sims4communitylib/enums/common_funds_sources.py index b752318..4885025 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_funds_sources.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_funds_sources.py @@ -8,7 +8,7 @@ from typing import Dict from sims.funds import FundsSource -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonFundsSource(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/common_game_tag_category.py b/Scripts/s4ap/sims4communitylib/enums/common_game_tag_category.py index 00d0fab..1ce15fe 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_game_tag_category.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_game_tag_category.py @@ -7,7 +7,7 @@ """ from typing import Union, Tuple, Iterator -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt from tag import TagCategory diff --git a/Scripts/s4ap/sims4communitylib/enums/common_gender.py b/Scripts/s4ap/sims4communitylib/enums/common_gender.py index 21ffb27..ed6d641 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_gender.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_gender.py @@ -9,7 +9,7 @@ from sims.sim_info import SimInfo from sims.sim_info_types import Gender -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonGender(CommonInt): @@ -75,7 +75,7 @@ def get_gender(sim_info: SimInfo) -> 'CommonGender': :return: The CommonGender that represents what gender a Sim is or CommonGender.INVALID if their gender cannot be determined. :rtype: CommonGender """ - from sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils + from s4ap.sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils if CommonGenderUtils.is_male(sim_info): return CommonGender.MALE elif CommonGenderUtils.is_female(sim_info): @@ -138,7 +138,7 @@ def convert_to_localized_string_id(value: 'CommonGender') -> Union[int, str]: :return: The specified CommonGender translated to a localized string identifier. If no localized string id is found, the name property of the value will be used instead. :rtype: Union[int, str] """ - from sims4communitylib.enums.strings_enum import CommonStringId + from s4ap.sims4communitylib.enums.strings_enum import CommonStringId mapping = { CommonGender.MALE: CommonStringId.MALE, CommonGender.FEMALE: CommonStringId.FEMALE diff --git a/Scripts/s4ap/sims4communitylib/enums/common_gender_preference_type.py b/Scripts/s4ap/sims4communitylib/enums/common_gender_preference_type.py index d2426ef..0864ed1 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_gender_preference_type.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_gender_preference_type.py @@ -8,7 +8,7 @@ from typing import Dict, Union from sims.global_gender_preference_tuning import GenderPreferenceType -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonGenderPreferenceType(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/common_ground_cover_type.py b/Scripts/s4ap/sims4communitylib/enums/common_ground_cover_type.py index 47e8b26..1b37bae 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_ground_cover_type.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_ground_cover_type.py @@ -7,7 +7,7 @@ """ from typing import Tuple, Union, Iterator -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt # noinspection PyBroadException try: diff --git a/Scripts/s4ap/sims4communitylib/enums/common_key.py b/Scripts/s4ap/sims4communitylib/enums/common_key.py index 4969b46..f55e98e 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_key.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_key.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonKey(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/common_object_delivery_method.py b/Scripts/s4ap/sims4communitylib/enums/common_object_delivery_method.py index d0df384..45e48c9 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_object_delivery_method.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_object_delivery_method.py @@ -8,7 +8,7 @@ from typing import Iterator, Tuple from interactions.base.picker_interaction import PickerInteractionDeliveryMethod -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonObjectDeliveryMethod(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/common_object_filter_type.py b/Scripts/s4ap/sims4communitylib/enums/common_object_filter_type.py index 34f64b0..e505cea 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_object_filter_type.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_object_filter_type.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonObjectFilterType(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/common_object_preference_tag.py b/Scripts/s4ap/sims4communitylib/enums/common_object_preference_tag.py index ae33e75..0c5d814 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_object_preference_tag.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_object_preference_tag.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonObjectPreferenceTag(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/common_object_quality.py b/Scripts/s4ap/sims4communitylib/enums/common_object_quality.py index 77e9bf7..6807474 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_object_quality.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_object_quality.py @@ -7,7 +7,7 @@ """ from typing import Tuple, Iterator -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonObjectQuality(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/common_object_slot_name_ids.py b/Scripts/s4ap/sims4communitylib/enums/common_object_slot_name_ids.py index b038d4d..cb5e4f1 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_object_slot_name_ids.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_object_slot_name_ids.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonObjectSlotNameId(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/common_object_state_ids.py b/Scripts/s4ap/sims4communitylib/enums/common_object_state_ids.py index 4137836..21d1eaf 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_object_state_ids.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_object_state_ids.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonObjectStateId(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/common_object_state_value_ids.py b/Scripts/s4ap/sims4communitylib/enums/common_object_state_value_ids.py index b24a99c..0d72113 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_object_state_value_ids.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_object_state_value_ids.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonObjectStateValueId(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/common_occult_type.py b/Scripts/s4ap/sims4communitylib/enums/common_occult_type.py index 29c0071..4e5aabf 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_occult_type.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_occult_type.py @@ -10,8 +10,8 @@ from protocolbuffers.Localization_pb2 import LocalizedString from sims.occult.occult_enums import OccultType from sims.sim_info import SimInfo -from sims4communitylib.enums.enumtypes.common_int import CommonInt -from sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId class CommonOccultType(CommonInt): @@ -86,7 +86,7 @@ def determine_occult_type(sim_info: SimInfo) -> 'CommonOccultType': :return: The CommonOccultType that represents what a Sim is. :rtype: CommonOccultType """ - from sims4communitylib.utils.sims.common_sim_occult_type_utils import CommonSimOccultTypeUtils + from s4ap.sims4communitylib.utils.sims.common_sim_occult_type_utils import CommonSimOccultTypeUtils return CommonSimOccultTypeUtils.determine_occult_type(sim_info) @staticmethod @@ -101,7 +101,7 @@ def determine_current_occult_type(sim_info: SimInfo) -> 'CommonOccultType': :return: The CommonOccultType the Sim is currently appearing as, or CommonOccultType.NONE if they are not appearing as any Occult or are appearing as their HUMAN disguise/occult. :rtype: CommonOccultType """ - from sims4communitylib.utils.sims.common_sim_occult_type_utils import CommonSimOccultTypeUtils + from s4ap.sims4communitylib.utils.sims.common_sim_occult_type_utils import CommonSimOccultTypeUtils return CommonSimOccultTypeUtils.determine_current_occult_type(sim_info) @staticmethod @@ -117,7 +117,7 @@ def convert_to_vanilla(occult_type: 'CommonOccultType') -> Union[OccultType, Non :return: The specified CommonOccultType translated to OccultType, or None if the value could not be translated. :rtype: Union[OccultType, None] """ - from sims4communitylib.utils.sims.common_sim_occult_type_utils import CommonSimOccultTypeUtils + from s4ap.sims4communitylib.utils.sims.common_sim_occult_type_utils import CommonSimOccultTypeUtils return CommonSimOccultTypeUtils.convert_custom_type_to_vanilla(occult_type) @staticmethod diff --git a/Scripts/s4ap/sims4communitylib/enums/common_posture_id.py b/Scripts/s4ap/sims4communitylib/enums/common_posture_id.py index bb7806f..b8481e1 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_posture_id.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_posture_id.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonPostureId(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/common_precipitation_type.py b/Scripts/s4ap/sims4communitylib/enums/common_precipitation_type.py index 8e6d17a..257350b 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_precipitation_type.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_precipitation_type.py @@ -7,7 +7,7 @@ """ from typing import Tuple, Union, Iterator -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt # noinspection PyBroadException try: diff --git a/Scripts/s4ap/sims4communitylib/enums/common_pregnancy_origin.py b/Scripts/s4ap/sims4communitylib/enums/common_pregnancy_origin.py index c541cab..23c020a 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_pregnancy_origin.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_pregnancy_origin.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonPregnancyOrigin(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/common_puddle_liquid.py b/Scripts/s4ap/sims4communitylib/enums/common_puddle_liquid.py index 65e6856..d9ae245 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_puddle_liquid.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_puddle_liquid.py @@ -8,7 +8,7 @@ from typing import Union from objects.puddles import PuddleLiquid -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonPuddleLiquid(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/common_puddle_size.py b/Scripts/s4ap/sims4communitylib/enums/common_puddle_size.py index 0a915eb..396bfbc 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_puddle_size.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_puddle_size.py @@ -6,7 +6,7 @@ Copyright (c) COLONOLNUTTY """ from objects.puddles import PuddleSize -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonPuddleSize(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/common_region_id.py b/Scripts/s4ap/sims4communitylib/enums/common_region_id.py index 72334a3..6627b81 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_region_id.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_region_id.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonRegionId(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/common_runnable_state.py b/Scripts/s4ap/sims4communitylib/enums/common_runnable_state.py index d3bc9ad..09fc968 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_runnable_state.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_runnable_state.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonRunnableState(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/common_runnable_state_type.py b/Scripts/s4ap/sims4communitylib/enums/common_runnable_state_type.py index 45d7ae3..f7dee88 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_runnable_state_type.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_runnable_state_type.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonRunnableStateType(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/common_side.py b/Scripts/s4ap/sims4communitylib/enums/common_side.py index 28e70fd..147d8bd 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_side.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_side.py @@ -7,7 +7,7 @@ """ from typing import Iterator, Tuple, Union -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonSide(CommonInt): @@ -96,7 +96,7 @@ def convert_to_localized_string_id(cls, value: Union[int, 'CommonSide']) -> Unio :return: The specified value translated to a localized string identifier. If no localized string id is found, the name property of the value will be used instead. :rtype: Union[int, str] """ - from sims4communitylib.enums.strings_enum import CommonStringId + from s4ap.sims4communitylib.enums.strings_enum import CommonStringId mapping = { CommonSide.LEFT: CommonStringId.S4CL_LEFT, CommonSide.RIGHT: CommonStringId.S4CL_RIGHT, diff --git a/Scripts/s4ap/sims4communitylib/enums/common_sim_demographic_types.py b/Scripts/s4ap/sims4communitylib/enums/common_sim_demographic_types.py index 3e7a4d6..fbe101f 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_sim_demographic_types.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_sim_demographic_types.py @@ -8,9 +8,9 @@ from typing import Union, Tuple, Iterator, Dict, Set from protocolbuffers.Localization_pb2 import LocalizedString -from sims4communitylib.enums.enumtypes.common_versioned_int_flags import CommonVersionedIntFlags -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.utils.math.common_bitwise_utils import CommonBitwiseUtils +from s4ap.sims4communitylib.enums.enumtypes.common_versioned_int_flags import CommonVersionedIntFlags +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.utils.math.common_bitwise_utils import CommonBitwiseUtils class CommonSimDemographicType(CommonVersionedIntFlags): diff --git a/Scripts/s4ap/sims4communitylib/enums/common_sim_name_type.py b/Scripts/s4ap/sims4communitylib/enums/common_sim_name_type.py index 4a01e18..6d0c9a7 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_sim_name_type.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_sim_name_type.py @@ -8,7 +8,7 @@ from typing import Tuple, Iterator from sims.sim_spawner_enums import SimNameType -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonSimNameType(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/common_skill_effectiveness.py b/Scripts/s4ap/sims4communitylib/enums/common_skill_effectiveness.py index 9f102a2..f283a35 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_skill_effectiveness.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_skill_effectiveness.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt from statistics.skill import SkillEffectiveness diff --git a/Scripts/s4ap/sims4communitylib/enums/common_species.py b/Scripts/s4ap/sims4communitylib/enums/common_species.py index f101809..fe36b1e 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_species.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_species.py @@ -9,7 +9,7 @@ from sims.sim_info import SimInfo from sims.sim_info_types import Species, SpeciesExtended -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonSpecies(CommonInt): @@ -79,7 +79,7 @@ def get_species(sim_info: SimInfo) -> 'CommonSpecies': :return: A species matching the Sim or INVALID if no matching species is found. :rtype: CommonSpecies """ - from sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils + from s4ap.sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils if CommonSpeciesUtils.is_human(sim_info): return CommonSpecies.HUMAN elif CommonSpeciesUtils.is_fox(sim_info): @@ -167,7 +167,7 @@ def convert_to_localized_string_id(value: 'CommonSpecies') -> Union[int, str]: :return: The specified value translated to a localized string identifier. If no localized string id is found, the name property of the value will be used instead. :rtype: Union[int, str] """ - from sims4communitylib.enums.strings_enum import CommonStringId + from s4ap.sims4communitylib.enums.strings_enum import CommonStringId display_name_mapping = { CommonSpecies.HUMAN: CommonStringId.HUMAN, CommonSpecies.LARGE_DOG: CommonStringId.LARGE_DOG, @@ -177,7 +177,7 @@ def convert_to_localized_string_id(value: 'CommonSpecies') -> Union[int, str]: CommonSpecies.HORSE: CommonStringId.HORSE, } if isinstance(value, int) and not isinstance(value, CommonSpecies): - from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils # noinspection PyTypeChecker converted_value = CommonResourceUtils.get_enum_by_int_value(value, SpeciesExtended, default_value=None) if converted_value is None: diff --git a/Scripts/s4ap/sims4communitylib/enums/common_statistic_category.py b/Scripts/s4ap/sims4communitylib/enums/common_statistic_category.py index 6b47d73..fed6184 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_statistic_category.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_statistic_category.py @@ -7,8 +7,8 @@ """ from typing import Union -from sims4communitylib.enums.enumtypes.common_int import CommonInt -from sims4communitylib.utils.common_resource_utils import CommonResourceUtils +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils from statistics.statistic_categories import StatisticCategory diff --git a/Scripts/s4ap/sims4communitylib/enums/common_street_civic_policy_ids.py b/Scripts/s4ap/sims4communitylib/enums/common_street_civic_policy_ids.py index 7d8b174..fb38568 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_street_civic_policy_ids.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_street_civic_policy_ids.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonStreetCivicPolicyId(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/common_temperature.py b/Scripts/s4ap/sims4communitylib/enums/common_temperature.py index cf21d03..e93e569 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_temperature.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_temperature.py @@ -7,7 +7,7 @@ """ from typing import Tuple, Union, Iterator -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt # noinspection PyBroadException try: diff --git a/Scripts/s4ap/sims4communitylib/enums/common_venue_civic_policy_ids.py b/Scripts/s4ap/sims4communitylib/enums/common_venue_civic_policy_ids.py index dffeba5..410909d 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_venue_civic_policy_ids.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_venue_civic_policy_ids.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonVenueCivicPolicyId(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/common_voice_actor_type.py b/Scripts/s4ap/sims4communitylib/enums/common_voice_actor_type.py index c9b7299..2f0dade 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_voice_actor_type.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_voice_actor_type.py @@ -7,7 +7,7 @@ """ from typing import Tuple, Iterator -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonVoiceActorType(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/common_weather_effect_type.py b/Scripts/s4ap/sims4communitylib/enums/common_weather_effect_type.py index c2e4ad5..d784e2d 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_weather_effect_type.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_weather_effect_type.py @@ -7,7 +7,7 @@ """ from typing import Tuple, Union, Iterator -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt # noinspection PyBroadException try: diff --git a/Scripts/s4ap/sims4communitylib/enums/common_weather_event_ids.py b/Scripts/s4ap/sims4communitylib/enums/common_weather_event_ids.py index 710d9e1..5174ab6 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_weather_event_ids.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_weather_event_ids.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonWeatherEventId(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/common_weather_type.py b/Scripts/s4ap/sims4communitylib/enums/common_weather_type.py index ade427b..f4a2cce 100644 --- a/Scripts/s4ap/sims4communitylib/enums/common_weather_type.py +++ b/Scripts/s4ap/sims4communitylib/enums/common_weather_type.py @@ -7,8 +7,8 @@ """ from typing import Tuple, Union, Iterator -from sims4communitylib.enums.common_temperature import Temperature -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.common_temperature import Temperature +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt # noinspection PyBroadException try: diff --git a/Scripts/s4ap/sims4communitylib/enums/enumtypes/common_versioned_int.py b/Scripts/s4ap/sims4communitylib/enums/enumtypes/common_versioned_int.py index 4e11232..95c1871 100644 --- a/Scripts/s4ap/sims4communitylib/enums/enumtypes/common_versioned_int.py +++ b/Scripts/s4ap/sims4communitylib/enums/enumtypes/common_versioned_int.py @@ -7,8 +7,8 @@ """ from typing import Set, Dict -from sims4communitylib.enums.enumtypes.common_int import CommonInt -from sims4communitylib.enums.enumtypes.common_versioned_values_mixin import CommonVersionedValuesMixin +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_versioned_values_mixin import CommonVersionedValuesMixin class CommonVersionedInt(CommonInt, CommonVersionedValuesMixin): diff --git a/Scripts/s4ap/sims4communitylib/enums/enumtypes/common_versioned_int_flags.py b/Scripts/s4ap/sims4communitylib/enums/enumtypes/common_versioned_int_flags.py index 0d75253..8a238f1 100644 --- a/Scripts/s4ap/sims4communitylib/enums/enumtypes/common_versioned_int_flags.py +++ b/Scripts/s4ap/sims4communitylib/enums/enumtypes/common_versioned_int_flags.py @@ -7,8 +7,8 @@ """ from typing import Set, Dict -from sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags -from sims4communitylib.enums.enumtypes.common_versioned_values_mixin import CommonVersionedValuesMixin +from s4ap.sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags +from s4ap.sims4communitylib.enums.enumtypes.common_versioned_values_mixin import CommonVersionedValuesMixin class CommonVersionedIntFlags(CommonIntFlags, CommonVersionedValuesMixin): diff --git a/Scripts/s4ap/sims4communitylib/enums/enumtypes/float_enum.py b/Scripts/s4ap/sims4communitylib/enums/enumtypes/float_enum.py index de488e0..8e56576 100644 --- a/Scripts/s4ap/sims4communitylib/enums/enumtypes/float_enum.py +++ b/Scripts/s4ap/sims4communitylib/enums/enumtypes/float_enum.py @@ -6,7 +6,7 @@ Copyright (c) COLONOLNUTTY """ from typing import Any -from sims4communitylib.enums.common_enum import CommonEnumMetaclass +from s4ap.sims4communitylib.enums.common_enum import CommonEnumMetaclass class CommonEnumFloat(float): diff --git a/Scripts/s4ap/sims4communitylib/enums/enumtypes/int_enum.py b/Scripts/s4ap/sims4communitylib/enums/enumtypes/int_enum.py index ab8a0f6..eae7837 100644 --- a/Scripts/s4ap/sims4communitylib/enums/enumtypes/int_enum.py +++ b/Scripts/s4ap/sims4communitylib/enums/enumtypes/int_enum.py @@ -7,7 +7,7 @@ """ from typing import Any -from sims4communitylib.enums.common_enum import CommonEnumMetaclass +from s4ap.sims4communitylib.enums.common_enum import CommonEnumMetaclass class CommonEnumInt(int): diff --git a/Scripts/s4ap/sims4communitylib/enums/enumtypes/object_enum.py b/Scripts/s4ap/sims4communitylib/enums/enumtypes/object_enum.py index 5ccfdaa..7c943dc 100644 --- a/Scripts/s4ap/sims4communitylib/enums/enumtypes/object_enum.py +++ b/Scripts/s4ap/sims4communitylib/enums/enumtypes/object_enum.py @@ -6,7 +6,7 @@ Copyright (c) COLONOLNUTTY """ from typing import Any -from sims4communitylib.enums.common_enum import CommonEnumMetaclass +from s4ap.sims4communitylib.enums.common_enum import CommonEnumMetaclass class CommonEnumObject(object): diff --git a/Scripts/s4ap/sims4communitylib/enums/enumtypes/string_enum.py b/Scripts/s4ap/sims4communitylib/enums/enumtypes/string_enum.py index 57645ce..d133e16 100644 --- a/Scripts/s4ap/sims4communitylib/enums/enumtypes/string_enum.py +++ b/Scripts/s4ap/sims4communitylib/enums/enumtypes/string_enum.py @@ -6,7 +6,7 @@ Copyright (c) COLONOLNUTTY """ from typing import Any -from sims4communitylib.enums.common_enum import CommonEnumMetaclass +from s4ap.sims4communitylib.enums.common_enum import CommonEnumMetaclass class CommonEnumString(str): diff --git a/Scripts/s4ap/sims4communitylib/enums/furniture_objects_enum.py b/Scripts/s4ap/sims4communitylib/enums/furniture_objects_enum.py index 534ade9..4c0f435 100644 --- a/Scripts/s4ap/sims4communitylib/enums/furniture_objects_enum.py +++ b/Scripts/s4ap/sims4communitylib/enums/furniture_objects_enum.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonFurnitureObjectId(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/icons_enum.py b/Scripts/s4ap/sims4communitylib/enums/icons_enum.py index 6ac4974..ffa89b2 100644 --- a/Scripts/s4ap/sims4communitylib/enums/icons_enum.py +++ b/Scripts/s4ap/sims4communitylib/enums/icons_enum.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonIconId(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/interactions_enum.py b/Scripts/s4ap/sims4communitylib/enums/interactions_enum.py index 1e903a1..5ef9c64 100644 --- a/Scripts/s4ap/sims4communitylib/enums/interactions_enum.py +++ b/Scripts/s4ap/sims4communitylib/enums/interactions_enum.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonInteractionId(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/long_term_sentiments_enum.py b/Scripts/s4ap/sims4communitylib/enums/long_term_sentiments_enum.py index bbec778..6200d94 100644 --- a/Scripts/s4ap/sims4communitylib/enums/long_term_sentiments_enum.py +++ b/Scripts/s4ap/sims4communitylib/enums/long_term_sentiments_enum.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonLongTermSentimentId(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/lot_traits_enum.py b/Scripts/s4ap/sims4communitylib/enums/lot_traits_enum.py index 158a5bf..52a7dd6 100644 --- a/Scripts/s4ap/sims4communitylib/enums/lot_traits_enum.py +++ b/Scripts/s4ap/sims4communitylib/enums/lot_traits_enum.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonLotTraitId(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/moods_enum.py b/Scripts/s4ap/sims4communitylib/enums/moods_enum.py index 4ffcf8d..ddb804a 100644 --- a/Scripts/s4ap/sims4communitylib/enums/moods_enum.py +++ b/Scripts/s4ap/sims4communitylib/enums/moods_enum.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonMoodId(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/motives_enum.py b/Scripts/s4ap/sims4communitylib/enums/motives_enum.py index d4a9e0d..1212500 100644 --- a/Scripts/s4ap/sims4communitylib/enums/motives_enum.py +++ b/Scripts/s4ap/sims4communitylib/enums/motives_enum.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonMotiveId(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/relationship_bit_collection_uids_enum.py b/Scripts/s4ap/sims4communitylib/enums/relationship_bit_collection_uids_enum.py index 2ad7743..e512326 100644 --- a/Scripts/s4ap/sims4communitylib/enums/relationship_bit_collection_uids_enum.py +++ b/Scripts/s4ap/sims4communitylib/enums/relationship_bit_collection_uids_enum.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonRelationshipBitCollectionUid(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/relationship_bit_collections_enum.py b/Scripts/s4ap/sims4communitylib/enums/relationship_bit_collections_enum.py index d854669..4ec86f5 100644 --- a/Scripts/s4ap/sims4communitylib/enums/relationship_bit_collections_enum.py +++ b/Scripts/s4ap/sims4communitylib/enums/relationship_bit_collections_enum.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonRelationshipBitCollectionId(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/relationship_bits_enum.py b/Scripts/s4ap/sims4communitylib/enums/relationship_bits_enum.py index f3f5219..be54a50 100644 --- a/Scripts/s4ap/sims4communitylib/enums/relationship_bits_enum.py +++ b/Scripts/s4ap/sims4communitylib/enums/relationship_bits_enum.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonRelationshipBitId(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/relationship_tracks_enum.py b/Scripts/s4ap/sims4communitylib/enums/relationship_tracks_enum.py index 3d26d72..fc1d67a 100644 --- a/Scripts/s4ap/sims4communitylib/enums/relationship_tracks_enum.py +++ b/Scripts/s4ap/sims4communitylib/enums/relationship_tracks_enum.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonRelationshipTrackId(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/relationship_types_enum.py b/Scripts/s4ap/sims4communitylib/enums/relationship_types_enum.py index c6d0c34..fb6d96c 100644 --- a/Scripts/s4ap/sims4communitylib/enums/relationship_types_enum.py +++ b/Scripts/s4ap/sims4communitylib/enums/relationship_types_enum.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonRelationshipTypeId(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/short_term_relationship_tracks_enum.py b/Scripts/s4ap/sims4communitylib/enums/short_term_relationship_tracks_enum.py index d401670..a04bf75 100644 --- a/Scripts/s4ap/sims4communitylib/enums/short_term_relationship_tracks_enum.py +++ b/Scripts/s4ap/sims4communitylib/enums/short_term_relationship_tracks_enum.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonShortTermRelationshipTrackId(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/short_term_sentiments_enum.py b/Scripts/s4ap/sims4communitylib/enums/short_term_sentiments_enum.py index fb96606..6354553 100644 --- a/Scripts/s4ap/sims4communitylib/enums/short_term_sentiments_enum.py +++ b/Scripts/s4ap/sims4communitylib/enums/short_term_sentiments_enum.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonShortTermSentimentId(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/sim_type.py b/Scripts/s4ap/sims4communitylib/enums/sim_type.py index 3907e1d..c625c90 100644 --- a/Scripts/s4ap/sims4communitylib/enums/sim_type.py +++ b/Scripts/s4ap/sims4communitylib/enums/sim_type.py @@ -7,7 +7,7 @@ """ from typing import Tuple, Iterator -from sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags +from s4ap.sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags class CommonSimType(CommonIntFlags): diff --git a/Scripts/s4ap/sims4communitylib/enums/situation_jobs_enum.py b/Scripts/s4ap/sims4communitylib/enums/situation_jobs_enum.py index b396ea7..6859772 100644 --- a/Scripts/s4ap/sims4communitylib/enums/situation_jobs_enum.py +++ b/Scripts/s4ap/sims4communitylib/enums/situation_jobs_enum.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonSituationJobId(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/situations_enum.py b/Scripts/s4ap/sims4communitylib/enums/situations_enum.py index 74ac7fa..71247b7 100644 --- a/Scripts/s4ap/sims4communitylib/enums/situations_enum.py +++ b/Scripts/s4ap/sims4communitylib/enums/situations_enum.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonSituationId(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/skills_enum.py b/Scripts/s4ap/sims4communitylib/enums/skills_enum.py index e40eba6..c050041 100644 --- a/Scripts/s4ap/sims4communitylib/enums/skills_enum.py +++ b/Scripts/s4ap/sims4communitylib/enums/skills_enum.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonSkillId(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/statistics_enum.py b/Scripts/s4ap/sims4communitylib/enums/statistics_enum.py index f0cfd0d..c83c171 100644 --- a/Scripts/s4ap/sims4communitylib/enums/statistics_enum.py +++ b/Scripts/s4ap/sims4communitylib/enums/statistics_enum.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonStatisticId(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/strings_enum.py b/Scripts/s4ap/sims4communitylib/enums/strings_enum.py index af3295d..ec01668 100644 --- a/Scripts/s4ap/sims4communitylib/enums/strings_enum.py +++ b/Scripts/s4ap/sims4communitylib/enums/strings_enum.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonStringId(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/tags_enum.py b/Scripts/s4ap/sims4communitylib/enums/tags_enum.py index 40c3e56..75a03bb 100644 --- a/Scripts/s4ap/sims4communitylib/enums/tags_enum.py +++ b/Scripts/s4ap/sims4communitylib/enums/tags_enum.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt # noinspection SpellCheckingInspection diff --git a/Scripts/s4ap/sims4communitylib/enums/traits_enum.py b/Scripts/s4ap/sims4communitylib/enums/traits_enum.py index 78349d4..79acb97 100644 --- a/Scripts/s4ap/sims4communitylib/enums/traits_enum.py +++ b/Scripts/s4ap/sims4communitylib/enums/traits_enum.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt # noinspection SpellCheckingInspection diff --git a/Scripts/s4ap/sims4communitylib/enums/venues_enum.py b/Scripts/s4ap/sims4communitylib/enums/venues_enum.py index c96836f..4fadb89 100644 --- a/Scripts/s4ap/sims4communitylib/enums/venues_enum.py +++ b/Scripts/s4ap/sims4communitylib/enums/venues_enum.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonVenueType(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/whims_enum.py b/Scripts/s4ap/sims4communitylib/enums/whims_enum.py index 904b313..518ee8d 100644 --- a/Scripts/s4ap/sims4communitylib/enums/whims_enum.py +++ b/Scripts/s4ap/sims4communitylib/enums/whims_enum.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonWhimSetId(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/enums/world_types_enum.py b/Scripts/s4ap/sims4communitylib/enums/world_types_enum.py index d29959b..8a21283 100644 --- a/Scripts/s4ap/sims4communitylib/enums/world_types_enum.py +++ b/Scripts/s4ap/sims4communitylib/enums/world_types_enum.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonWorldTypeId(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/events/build_buy/common_build_buy_event_dispatcher.py b/Scripts/s4ap/sims4communitylib/events/build_buy/common_build_buy_event_dispatcher.py index b3eb1ad..1960616 100644 --- a/Scripts/s4ap/sims4communitylib/events/build_buy/common_build_buy_event_dispatcher.py +++ b/Scripts/s4ap/sims4communitylib/events/build_buy/common_build_buy_event_dispatcher.py @@ -7,14 +7,14 @@ """ from typing import Any -from sims4communitylib.events.build_buy.events.build_buy_enter import S4CLBuildBuyEnterEvent -from sims4communitylib.events.build_buy.events.build_buy_exit import S4CLBuildBuyExitEvent -from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from sims4communitylib.logging.has_class_log import HasClassLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.common_service import CommonService -from sims4communitylib.utils.common_injection_utils import CommonInjectionUtils +from s4ap.sims4communitylib.events.build_buy.events.build_buy_enter import S4CLBuildBuyEnterEvent +from s4ap.sims4communitylib.events.build_buy.events.build_buy_exit import S4CLBuildBuyExitEvent +from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry +from s4ap.sims4communitylib.logging.has_class_log import HasClassLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.common_service import CommonService +from s4ap.sims4communitylib.utils.common_injection_utils import CommonInjectionUtils from zone import Zone diff --git a/Scripts/s4ap/sims4communitylib/events/build_buy/events/build_buy_enter.py b/Scripts/s4ap/sims4communitylib/events/build_buy/events/build_buy_enter.py index fb29387..20e46d2 100644 --- a/Scripts/s4ap/sims4communitylib/events/build_buy/events/build_buy_enter.py +++ b/Scripts/s4ap/sims4communitylib/events/build_buy/events/build_buy_enter.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent from zone import Zone @@ -19,8 +19,8 @@ class S4CLBuildBuyEnterEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/build_buy/events/build_buy_exit.py b/Scripts/s4ap/sims4communitylib/events/build_buy/events/build_buy_exit.py index 5931f3b..b175337 100644 --- a/Scripts/s4ap/sims4communitylib/events/build_buy/events/build_buy_exit.py +++ b/Scripts/s4ap/sims4communitylib/events/build_buy/events/build_buy_exit.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent from zone import Zone @@ -19,8 +19,8 @@ class S4CLBuildBuyExitEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/event_handling/common_event_handler.py b/Scripts/s4ap/sims4communitylib/events/event_handling/common_event_handler.py index bdc11ce..f9a073d 100644 --- a/Scripts/s4ap/sims4communitylib/events/event_handling/common_event_handler.py +++ b/Scripts/s4ap/sims4communitylib/events/event_handling/common_event_handler.py @@ -8,8 +8,8 @@ import inspect from typing import Callable, Any, Union -from sims4communitylib.events.event_handling.common_event import CommonEvent -from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity class CommonEventHandler: @@ -37,7 +37,7 @@ def __init__(self, mod_identifier: Union[str, CommonModIdentity], event_function raise AssertionError('Event Function \'{}\' is missing the required argument with name \'event_data\'') if 'self' in function_signature.parameters or 'cls' in function_signature.parameters: raise AssertionError('Event functions must be static methods. Mod Name: \'{}\', Function: \'{}\''.format(repr(mod_identifier), event_function.__name__)) - from sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils + from s4ap.sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils self._mod_name = CommonModIdentityUtils.determine_mod_name_from_identifier(mod_identifier) self._event_function = event_function self._event_type = function_signature.parameters['event_data'].annotation diff --git a/Scripts/s4ap/sims4communitylib/events/event_handling/common_event_registry.py b/Scripts/s4ap/sims4communitylib/events/event_handling/common_event_registry.py index ef2b88d..135aaa4 100644 --- a/Scripts/s4ap/sims4communitylib/events/event_handling/common_event_registry.py +++ b/Scripts/s4ap/sims4communitylib/events/event_handling/common_event_registry.py @@ -6,12 +6,12 @@ Copyright (c) COLONOLNUTTY """ from typing import List, Callable, Any, Union -from sims4communitylib.events.event_handling.common_event import CommonEvent -from sims4communitylib.events.event_handling.common_event_handler import CommonEventHandler -from sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.common_service import CommonService +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event_handler import CommonEventHandler +from s4ap.sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.common_service import CommonService class CommonEventRegistry(CommonService): diff --git a/Scripts/s4ap/sims4communitylib/events/game_object/common_game_object_event_dispatcher.py b/Scripts/s4ap/sims4communitylib/events/game_object/common_game_object_event_dispatcher.py index cc5284e..92a6aed 100644 --- a/Scripts/s4ap/sims4communitylib/events/game_object/common_game_object_event_dispatcher.py +++ b/Scripts/s4ap/sims4communitylib/events/game_object/common_game_object_event_dispatcher.py @@ -9,22 +9,22 @@ from objects.game_object import GameObject from objects.script_object import ScriptObject -from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from sims4communitylib.events.game_object.events.game_object_added_to_inventory import S4CLGameObjectAddedToInventoryEvent -from sims4communitylib.events.game_object.events.game_object_pre_despawned import S4CLGameObjectPreDespawnedEvent -from sims4communitylib.events.game_object.events.game_object_pre_deleted import S4CLGameObjectPreDeletedEvent -from sims4communitylib.events.game_object.events.game_object_initialized import S4CLGameObjectInitializedEvent -from sims4communitylib.events.game_object.events.game_object_loaded import S4CLGameObjectLoadedEvent -from sims4communitylib.events.game_object.events.game_object_pre_removed_from_inventory import \ +from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry +from s4ap.sims4communitylib.events.game_object.events.game_object_added_to_inventory import S4CLGameObjectAddedToInventoryEvent +from s4ap.sims4communitylib.events.game_object.events.game_object_pre_despawned import S4CLGameObjectPreDespawnedEvent +from s4ap.sims4communitylib.events.game_object.events.game_object_pre_deleted import S4CLGameObjectPreDeletedEvent +from s4ap.sims4communitylib.events.game_object.events.game_object_initialized import S4CLGameObjectInitializedEvent +from s4ap.sims4communitylib.events.game_object.events.game_object_loaded import S4CLGameObjectLoadedEvent +from s4ap.sims4communitylib.events.game_object.events.game_object_pre_removed_from_inventory import \ S4CLGameObjectPreRemovedFromInventoryEvent -from sims4communitylib.events.game_object.events.game_object_spawned import S4CLGameObjectSpawnedEvent -from sims4communitylib.events.game_object.events.game_object_added_to_game_object_inventory import \ +from s4ap.sims4communitylib.events.game_object.events.game_object_spawned import S4CLGameObjectSpawnedEvent +from s4ap.sims4communitylib.events.game_object.events.game_object_added_to_game_object_inventory import \ S4CLGameObjectAddedToGameObjectInventoryEvent -from sims4communitylib.events.game_object.events.game_object_pre_removed_from_game_object_inventory import \ +from s4ap.sims4communitylib.events.game_object.events.game_object_pre_removed_from_game_object_inventory import \ S4CLGameObjectPreRemovedFromGameObjectInventoryEvent -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.common_service import CommonService -from sims4communitylib.utils.common_injection_utils import CommonInjectionUtils +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.common_service import CommonService +from s4ap.sims4communitylib.utils.common_injection_utils import CommonInjectionUtils class CommonGameObjectEventDispatcherService(CommonService): @@ -39,7 +39,7 @@ def _on_game_object_init(self, game_object: GameObject, *_, **__) -> bool: return CommonEventRegistry.get().dispatch(S4CLGameObjectInitializedEvent(game_object)) def _on_game_object_load(self, game_object: GameObject, *_, **__) -> bool: - from sims4communitylib.events.zone_spin.common_zone_spin_event_dispatcher import CommonZoneSpinEventDispatcher + from s4ap.sims4communitylib.events.zone_spin.common_zone_spin_event_dispatcher import CommonZoneSpinEventDispatcher if CommonZoneSpinEventDispatcher.get().game_loading: return False return CommonEventRegistry.get().dispatch(S4CLGameObjectLoadedEvent(game_object)) diff --git a/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_added_to_game_object_inventory.py b/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_added_to_game_object_inventory.py index 9419f66..d91b1b6 100644 --- a/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_added_to_game_object_inventory.py +++ b/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_added_to_game_object_inventory.py @@ -6,8 +6,8 @@ Copyright (c) COLONOLNUTTY """ from objects.game_object import GameObject -from sims4communitylib.events.event_handling.common_event import CommonEvent -from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils class S4CLGameObjectAddedToGameObjectInventoryEvent(CommonEvent): @@ -20,8 +20,8 @@ class S4CLGameObjectAddedToGameObjectInventoryEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_added_to_inventory.py b/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_added_to_inventory.py index d6e68e6..a77d052 100644 --- a/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_added_to_inventory.py +++ b/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_added_to_inventory.py @@ -6,7 +6,7 @@ Copyright (c) COLONOLNUTTY """ from objects.game_object import GameObject -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent class S4CLGameObjectAddedToInventoryEvent(CommonEvent): @@ -19,8 +19,8 @@ class S4CLGameObjectAddedToInventoryEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_initialized.py b/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_initialized.py index 2001c19..ebffa40 100644 --- a/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_initialized.py +++ b/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_initialized.py @@ -6,7 +6,7 @@ Copyright (c) COLONOLNUTTY """ from objects.game_object import GameObject -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent class S4CLGameObjectInitializedEvent(CommonEvent): @@ -19,8 +19,8 @@ class S4CLGameObjectInitializedEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_loaded.py b/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_loaded.py index 9eb0120..1dcc216 100644 --- a/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_loaded.py +++ b/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_loaded.py @@ -6,7 +6,7 @@ Copyright (c) COLONOLNUTTY """ from objects.game_object import GameObject -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent class S4CLGameObjectLoadedEvent(CommonEvent): @@ -19,8 +19,8 @@ class S4CLGameObjectLoadedEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_deleted.py b/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_deleted.py index 3fd8d8f..d10db85 100644 --- a/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_deleted.py +++ b/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_deleted.py @@ -6,7 +6,7 @@ Copyright (c) COLONOLNUTTY """ from objects.game_object import GameObject -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent class S4CLGameObjectPreDeletedEvent(CommonEvent): @@ -19,8 +19,8 @@ class S4CLGameObjectPreDeletedEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_despawned.py b/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_despawned.py index c0b9eb4..b68ba51 100644 --- a/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_despawned.py +++ b/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_despawned.py @@ -6,7 +6,7 @@ Copyright (c) COLONOLNUTTY """ from objects.game_object import GameObject -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent class S4CLGameObjectPreDespawnedEvent(CommonEvent): @@ -19,8 +19,8 @@ class S4CLGameObjectPreDespawnedEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_removed_from_game_object_inventory.py b/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_removed_from_game_object_inventory.py index 0f7fe7f..e066a41 100644 --- a/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_removed_from_game_object_inventory.py +++ b/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_removed_from_game_object_inventory.py @@ -6,8 +6,8 @@ Copyright (c) COLONOLNUTTY """ from objects.game_object import GameObject -from sims4communitylib.events.event_handling.common_event import CommonEvent -from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils class S4CLGameObjectPreRemovedFromGameObjectInventoryEvent(CommonEvent): @@ -20,8 +20,8 @@ class S4CLGameObjectPreRemovedFromGameObjectInventoryEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_removed_from_inventory.py b/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_removed_from_inventory.py index e15fb56..beefe98 100644 --- a/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_removed_from_inventory.py +++ b/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_removed_from_inventory.py @@ -6,7 +6,7 @@ Copyright (c) COLONOLNUTTY """ from objects.game_object import GameObject -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent class S4CLGameObjectPreRemovedFromInventoryEvent(CommonEvent): @@ -19,8 +19,8 @@ class S4CLGameObjectPreRemovedFromInventoryEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_spawned.py b/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_spawned.py index 2290cee..f7c3191 100644 --- a/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_spawned.py +++ b/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_spawned.py @@ -6,7 +6,7 @@ Copyright (c) COLONOLNUTTY """ from objects.game_object import GameObject -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent class S4CLGameObjectSpawnedEvent(CommonEvent): @@ -19,8 +19,8 @@ class S4CLGameObjectSpawnedEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/interaction/common_interaction_event_dispatcher.py b/Scripts/s4ap/sims4communitylib/events/interaction/common_interaction_event_dispatcher.py index f5c82d1..7d645e8 100644 --- a/Scripts/s4ap/sims4communitylib/events/interaction/common_interaction_event_dispatcher.py +++ b/Scripts/s4ap/sims4communitylib/events/interaction/common_interaction_event_dispatcher.py @@ -15,25 +15,25 @@ from interactions.interaction_queue import InteractionQueue from interactions.utils.outcome import InteractionOutcome from interactions.utils.outcome_enums import OutcomeResult -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from sims4communitylib.events.interaction.events.interaction_cancelled import S4CLInteractionCancelledEvent -from sims4communitylib.events.interaction.events.interaction_outcome import S4CLInteractionOutcomeEvent -from sims4communitylib.events.interaction.events.interaction_post_queued import S4CLInteractionPostQueuedEvent -from sims4communitylib.events.interaction.events.interaction_pre_run import S4CLInteractionPreRunEvent -from sims4communitylib.events.interaction.events.interaction_queued import S4CLInteractionQueuedEvent -from sims4communitylib.events.interaction.events.interaction_run import S4CLInteractionRunEvent -from sims4communitylib.events.interaction.events.interaction_started import S4CLInteractionStartedEvent -from sims4communitylib.events.interaction.events.mixer_interaction_cancelled import S4CLMixerInteractionCancelledEvent -from sims4communitylib.events.interaction.events.super_interaction_cancelled import S4CLSuperInteractionCancelledEvent -from sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler -from sims4communitylib.logging.has_log import HasLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.common_service import CommonService -from sims4communitylib.utils.common_injection_utils import CommonInjectionUtils -from sims4communitylib.utils.resources.common_interaction_utils import CommonInteractionUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry +from s4ap.sims4communitylib.events.interaction.events.interaction_cancelled import S4CLInteractionCancelledEvent +from s4ap.sims4communitylib.events.interaction.events.interaction_outcome import S4CLInteractionOutcomeEvent +from s4ap.sims4communitylib.events.interaction.events.interaction_post_queued import S4CLInteractionPostQueuedEvent +from s4ap.sims4communitylib.events.interaction.events.interaction_pre_run import S4CLInteractionPreRunEvent +from s4ap.sims4communitylib.events.interaction.events.interaction_queued import S4CLInteractionQueuedEvent +from s4ap.sims4communitylib.events.interaction.events.interaction_run import S4CLInteractionRunEvent +from s4ap.sims4communitylib.events.interaction.events.interaction_started import S4CLInteractionStartedEvent +from s4ap.sims4communitylib.events.interaction.events.mixer_interaction_cancelled import S4CLMixerInteractionCancelledEvent +from s4ap.sims4communitylib.events.interaction.events.super_interaction_cancelled import S4CLSuperInteractionCancelledEvent +from s4ap.sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler +from s4ap.sims4communitylib.logging.has_log import HasLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.common_service import CommonService +from s4ap.sims4communitylib.utils.common_injection_utils import CommonInjectionUtils +from s4ap.sims4communitylib.utils.resources.common_interaction_utils import CommonInteractionUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' diff --git a/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_cancelled.py b/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_cancelled.py index 7c47e60..5996a07 100644 --- a/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_cancelled.py +++ b/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_cancelled.py @@ -8,7 +8,7 @@ from typing import Any, Dict from interactions.base.interaction import Interaction from interactions.interaction_finisher import FinishingType -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent class S4CLInteractionCancelledEvent(CommonEvent): @@ -23,8 +23,8 @@ class S4CLInteractionCancelledEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_outcome.py b/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_outcome.py index 3628c53..2bf3382 100644 --- a/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_outcome.py +++ b/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_outcome.py @@ -8,7 +8,7 @@ from interactions.base.interaction import Interaction from interactions.utils.outcome import InteractionOutcome from interactions.utils.outcome_enums import OutcomeResult -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent class S4CLInteractionOutcomeEvent(CommonEvent): @@ -21,8 +21,8 @@ class S4CLInteractionOutcomeEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_post_queued.py b/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_post_queued.py index 3c8e541..58ea8eb 100644 --- a/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_post_queued.py +++ b/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_post_queued.py @@ -7,8 +7,8 @@ """ from interactions.base.interaction import Interaction from interactions.interaction_queue import InteractionQueue -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent class S4CLInteractionPostQueuedEvent(CommonEvent): @@ -23,8 +23,8 @@ class S4CLInteractionPostQueuedEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_pre_run.py b/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_pre_run.py index bcdf0f4..cb4b165 100644 --- a/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_pre_run.py +++ b/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_pre_run.py @@ -8,7 +8,7 @@ import os from interactions.base.interaction import Interaction from interactions.interaction_queue import InteractionQueue -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' @@ -34,8 +34,8 @@ class S4CLInteractionPreRunEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_queued.py b/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_queued.py index dc2cebf..db84024 100644 --- a/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_queued.py +++ b/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_queued.py @@ -11,8 +11,8 @@ from interactions.interaction_queue import InteractionQueue from sims.sim import Sim from sims.sim_info import SimInfo -from sims4communitylib.events.event_handling.common_event import CommonEvent -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils class S4CLInteractionQueuedEvent(CommonEvent): @@ -27,8 +27,8 @@ class S4CLInteractionQueuedEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_run.py b/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_run.py index e767e3d..b6fff56 100644 --- a/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_run.py +++ b/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_run.py @@ -7,7 +7,7 @@ """ from interactions.base.interaction import Interaction from interactions.interaction_queue import InteractionQueue -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent class S4CLInteractionRunEvent(CommonEvent): @@ -22,8 +22,8 @@ class S4CLInteractionRunEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_started.py b/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_started.py index 794227e..77ce0a5 100644 --- a/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_started.py +++ b/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_started.py @@ -9,7 +9,7 @@ from interactions.base.interaction import Interaction from sims.sim_info import SimInfo -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent class S4CLInteractionStartedEvent(CommonEvent): @@ -22,8 +22,8 @@ class S4CLInteractionStartedEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/interaction/events/mixer_interaction_cancelled.py b/Scripts/s4ap/sims4communitylib/events/interaction/events/mixer_interaction_cancelled.py index d941604..d585335 100644 --- a/Scripts/s4ap/sims4communitylib/events/interaction/events/mixer_interaction_cancelled.py +++ b/Scripts/s4ap/sims4communitylib/events/interaction/events/mixer_interaction_cancelled.py @@ -8,7 +8,7 @@ from typing import Any, Dict from interactions.base.mixer_interaction import MixerInteraction from interactions.interaction_finisher import FinishingType -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent class S4CLMixerInteractionCancelledEvent(CommonEvent): @@ -23,8 +23,8 @@ class S4CLMixerInteractionCancelledEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/interaction/events/super_interaction_cancelled.py b/Scripts/s4ap/sims4communitylib/events/interaction/events/super_interaction_cancelled.py index edc317c..2228482 100644 --- a/Scripts/s4ap/sims4communitylib/events/interaction/events/super_interaction_cancelled.py +++ b/Scripts/s4ap/sims4communitylib/events/interaction/events/super_interaction_cancelled.py @@ -8,7 +8,7 @@ from typing import Any, Dict from interactions.base.super_interaction import SuperInteraction from interactions.interaction_finisher import FinishingType -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent class S4CLSuperInteractionCancelledEvent(CommonEvent): @@ -23,8 +23,8 @@ class S4CLSuperInteractionCancelledEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/interval/common_interval_event_service.py b/Scripts/s4ap/sims4communitylib/events/interval/common_interval_event_service.py index 20c9926..200a063 100644 --- a/Scripts/s4ap/sims4communitylib/events/interval/common_interval_event_service.py +++ b/Scripts/s4ap/sims4communitylib/events/interval/common_interval_event_service.py @@ -6,12 +6,12 @@ Copyright (c) COLONOLNUTTY """ from typing import Callable, Any, List, Union -from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from sims4communitylib.events.zone_update.events.zone_update_event import S4CLZoneUpdateEvent -from sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.common_service import CommonService +from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry +from s4ap.sims4communitylib.events.zone_update.events.zone_update_event import S4CLZoneUpdateEvent +from s4ap.sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.common_service import CommonService class CommonIntervalDispatcher: @@ -33,7 +33,7 @@ class CommonIntervalDispatcher: :type run_once: bool """ def __init__(self, mod_identifier: Union[str, CommonModIdentity], milliseconds: int, listening_func: Callable[..., Any], run_once: bool=False): - from sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils + from s4ap.sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils self._mod_name = CommonModIdentityUtils.determine_mod_name_from_identifier(mod_identifier) self._minimum_milliseconds_to_dispatch = milliseconds self._listening_func = listening_func @@ -219,7 +219,7 @@ def _attempt_to_dispatch(self, milliseconds_since_last_update: int): @staticmethod @CommonEventRegistry.handle_events(ModInfo.get_identity()) def _update_game_tick_on_zone_update(event_data: S4CLZoneUpdateEvent) -> bool: - from sims4communitylib.events.zone_spin.common_zone_spin_event_dispatcher import CommonZoneSpinEventDispatcher + from s4ap.sims4communitylib.events.zone_spin.common_zone_spin_event_dispatcher import CommonZoneSpinEventDispatcher if event_data.is_paused or CommonZoneSpinEventDispatcher().game_loading: return False CommonIntervalEventRegistry.get()._attempt_to_dispatch(event_data.ticks_since_last_update) diff --git a/Scripts/s4ap/sims4communitylib/events/save/common_save_event_dispatcher.py b/Scripts/s4ap/sims4communitylib/events/save/common_save_event_dispatcher.py index 9531a5d..121643f 100644 --- a/Scripts/s4ap/sims4communitylib/events/save/common_save_event_dispatcher.py +++ b/Scripts/s4ap/sims4communitylib/events/save/common_save_event_dispatcher.py @@ -7,12 +7,12 @@ """ import os -from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from sims4communitylib.events.save.events.save_loaded import S4CLSaveLoadedEvent -from sims4communitylib.events.save.events.save_saved import S4CLSaveSavedEvent -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.common_service import CommonService -from sims4communitylib.utils.common_injection_utils import CommonInjectionUtils +from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry +from s4ap.sims4communitylib.events.save.events.save_loaded import S4CLSaveLoadedEvent +from s4ap.sims4communitylib.events.save.events.save_saved import S4CLSaveSavedEvent +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.common_service import CommonService +from s4ap.sims4communitylib.utils.common_injection_utils import CommonInjectionUtils ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' @@ -39,7 +39,7 @@ def _on_game_save(self, save_game_data: SaveGameData): CommonEventRegistry.get().dispatch(S4CLSaveSavedEvent(save_game_data)) def _on_save_loaded(self) -> None: - from sims4communitylib.utils.save_load.common_save_utils import CommonSaveUtils + from s4ap.sims4communitylib.utils.save_load.common_save_utils import CommonSaveUtils current_save_slot_guid = CommonSaveUtils().get_save_slot_guid() if self._current_save_slot_guid is None: self._current_save_slot_guid = current_save_slot_guid diff --git a/Scripts/s4ap/sims4communitylib/events/save/events/save_loaded.py b/Scripts/s4ap/sims4communitylib/events/save/events/save_loaded.py index afe976f..5ed0b9b 100644 --- a/Scripts/s4ap/sims4communitylib/events/save/events/save_loaded.py +++ b/Scripts/s4ap/sims4communitylib/events/save/events/save_loaded.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent class S4CLSaveLoadedEvent(CommonEvent): @@ -18,8 +18,8 @@ class S4CLSaveLoadedEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/save/events/save_saved.py b/Scripts/s4ap/sims4communitylib/events/save/events/save_saved.py index aedeac0..f2ba969 100644 --- a/Scripts/s4ap/sims4communitylib/events/save/events/save_saved.py +++ b/Scripts/s4ap/sims4communitylib/events/save/events/save_saved.py @@ -8,7 +8,7 @@ from typing import Any from services.persistence_service import SaveGameData -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent class S4CLSaveSavedEvent(CommonEvent): @@ -23,8 +23,8 @@ class S4CLSaveSavedEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/sim/common_sim_event_dispatcher.py b/Scripts/s4ap/sims4communitylib/events/sim/common_sim_event_dispatcher.py index 0e48070..cf321cf 100644 --- a/Scripts/s4ap/sims4communitylib/events/sim/common_sim_event_dispatcher.py +++ b/Scripts/s4ap/sims4communitylib/events/sim/common_sim_event_dispatcher.py @@ -23,48 +23,48 @@ from sims.sim_info import SimInfo from sims.sim_info_types import Age from sims.sim_spawner import SimSpawner -from sims4communitylib.enums.common_age import CommonAge -from sims4communitylib.enums.common_death_types import CommonDeathType -from sims4communitylib.enums.common_gender import CommonGender -from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from sims4communitylib.events.sim.events.sim_added_occult_type import S4CLSimAddedOccultTypeEvent -from sims4communitylib.events.sim.events.sim_after_set_current_outfit import S4CLSimAfterSetCurrentOutfitEvent -from sims4communitylib.events.sim.events.sim_buff_added import S4CLSimBuffAddedEvent -from sims4communitylib.events.sim.events.sim_buff_removed import S4CLSimBuffRemovedEvent -from sims4communitylib.events.sim.events.sim_changed_age import S4CLSimChangedAgeEvent -from sims4communitylib.events.sim.events.sim_changed_gender_options_body_frame import S4CLSimChangedGenderOptionsBodyFrameEvent -from sims4communitylib.events.sim.events.sim_changed_gender_options_breasts import \ +from s4ap.sims4communitylib.enums.common_age import CommonAge +from s4ap.sims4communitylib.enums.common_death_types import CommonDeathType +from s4ap.sims4communitylib.enums.common_gender import CommonGender +from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry +from s4ap.sims4communitylib.events.sim.events.sim_added_occult_type import S4CLSimAddedOccultTypeEvent +from s4ap.sims4communitylib.events.sim.events.sim_after_set_current_outfit import S4CLSimAfterSetCurrentOutfitEvent +from s4ap.sims4communitylib.events.sim.events.sim_buff_added import S4CLSimBuffAddedEvent +from s4ap.sims4communitylib.events.sim.events.sim_buff_removed import S4CLSimBuffRemovedEvent +from s4ap.sims4communitylib.events.sim.events.sim_changed_age import S4CLSimChangedAgeEvent +from s4ap.sims4communitylib.events.sim.events.sim_changed_gender_options_body_frame import S4CLSimChangedGenderOptionsBodyFrameEvent +from s4ap.sims4communitylib.events.sim.events.sim_changed_gender_options_breasts import \ S4CLSimChangedGenderOptionsBreastsEvent -from sims4communitylib.events.sim.events.sim_changed_gender_options_can_impregnate import \ +from s4ap.sims4communitylib.events.sim.events.sim_changed_gender_options_can_impregnate import \ S4CLSimChangedGenderOptionsCanImpregnateEvent -from sims4communitylib.events.sim.events.sim_changed_gender_options_can_reproduce import \ +from s4ap.sims4communitylib.events.sim.events.sim_changed_gender_options_can_reproduce import \ S4CLSimChangedGenderOptionsCanReproduceEvent -from sims4communitylib.events.sim.events.sim_changed_gender_options_clothing_preference import S4CLSimChangedGenderOptionsClothingPreferenceEvent -from sims4communitylib.events.sim.events.sim_changed_gender import S4CLSimChangedGenderEvent -from sims4communitylib.events.sim.events.sim_changed_occult_type import S4CLSimChangedOccultTypeEvent -from sims4communitylib.events.sim.events.sim_changed_gender_options_can_be_impregnated import S4CLSimChangedGenderOptionsCanBeImpregnatedEvent -from sims4communitylib.events.sim.events.sim_changed_gender_options_toilet_usage import S4CLSimChangedGenderOptionsToiletUsageEvent -from sims4communitylib.events.sim.events.sim_changing_occult_type import S4CLSimChangingOccultTypeEvent -from sims4communitylib.events.sim.events.sim_died import S4CLSimDiedEvent -from sims4communitylib.events.sim.events.sim_pre_despawned import S4CLSimPreDespawnedEvent -from sims4communitylib.events.sim.events.sim_initialized import S4CLSimInitializedEvent -from sims4communitylib.events.sim.events.sim_loaded import S4CLSimLoadedEvent -from sims4communitylib.events.sim.events.game_object_added_to_sim_inventory import S4CLGameObjectAddedToSimInventoryEvent -from sims4communitylib.events.sim.events.game_object_pre_removed_from_sim_inventory import S4CLGameObjectPreRemovedFromSimInventoryEvent -from sims4communitylib.events.sim.events.sim_relationship_bit_added import S4CLSimRelationshipBitAddedEvent -from sims4communitylib.events.sim.events.sim_relationship_bit_removed import S4CLSimRelationshipBitRemovedEvent -from sims4communitylib.events.sim.events.sim_removed_occult_type import S4CLSimRemovedOccultTypeEvent -from sims4communitylib.events.sim.events.sim_revived import S4CLSimRevivedEvent -from sims4communitylib.events.sim.events.sim_set_current_outfit import S4CLSimSetCurrentOutfitEvent -from sims4communitylib.events.sim.events.sim_skill_leveled_up import S4CLSimSkillLeveledUpEvent -from sims4communitylib.events.sim.events.sim_spawned import S4CLSimSpawnedEvent -from sims4communitylib.events.sim.events.sim_trait_added import S4CLSimTraitAddedEvent -from sims4communitylib.events.sim.events.sim_trait_removed import S4CLSimTraitRemovedEvent -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.common_service import CommonService -from sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils -from sims4communitylib.utils.common_injection_utils import CommonInjectionUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.events.sim.events.sim_changed_gender_options_clothing_preference import S4CLSimChangedGenderOptionsClothingPreferenceEvent +from s4ap.sims4communitylib.events.sim.events.sim_changed_gender import S4CLSimChangedGenderEvent +from s4ap.sims4communitylib.events.sim.events.sim_changed_occult_type import S4CLSimChangedOccultTypeEvent +from s4ap.sims4communitylib.events.sim.events.sim_changed_gender_options_can_be_impregnated import S4CLSimChangedGenderOptionsCanBeImpregnatedEvent +from s4ap.sims4communitylib.events.sim.events.sim_changed_gender_options_toilet_usage import S4CLSimChangedGenderOptionsToiletUsageEvent +from s4ap.sims4communitylib.events.sim.events.sim_changing_occult_type import S4CLSimChangingOccultTypeEvent +from s4ap.sims4communitylib.events.sim.events.sim_died import S4CLSimDiedEvent +from s4ap.sims4communitylib.events.sim.events.sim_pre_despawned import S4CLSimPreDespawnedEvent +from s4ap.sims4communitylib.events.sim.events.sim_initialized import S4CLSimInitializedEvent +from s4ap.sims4communitylib.events.sim.events.sim_loaded import S4CLSimLoadedEvent +from s4ap.sims4communitylib.events.sim.events.game_object_added_to_sim_inventory import S4CLGameObjectAddedToSimInventoryEvent +from s4ap.sims4communitylib.events.sim.events.game_object_pre_removed_from_sim_inventory import S4CLGameObjectPreRemovedFromSimInventoryEvent +from s4ap.sims4communitylib.events.sim.events.sim_relationship_bit_added import S4CLSimRelationshipBitAddedEvent +from s4ap.sims4communitylib.events.sim.events.sim_relationship_bit_removed import S4CLSimRelationshipBitRemovedEvent +from s4ap.sims4communitylib.events.sim.events.sim_removed_occult_type import S4CLSimRemovedOccultTypeEvent +from s4ap.sims4communitylib.events.sim.events.sim_revived import S4CLSimRevivedEvent +from s4ap.sims4communitylib.events.sim.events.sim_set_current_outfit import S4CLSimSetCurrentOutfitEvent +from s4ap.sims4communitylib.events.sim.events.sim_skill_leveled_up import S4CLSimSkillLeveledUpEvent +from s4ap.sims4communitylib.events.sim.events.sim_spawned import S4CLSimSpawnedEvent +from s4ap.sims4communitylib.events.sim.events.sim_trait_added import S4CLSimTraitAddedEvent +from s4ap.sims4communitylib.events.sim.events.sim_trait_removed import S4CLSimTraitRemovedEvent +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.common_service import CommonService +from s4ap.sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils +from s4ap.sims4communitylib.utils.common_injection_utils import CommonInjectionUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils from statistics.skill import Skill from traits.trait_tracker import TraitTracker from traits.traits import Trait @@ -79,7 +79,7 @@ class CommonSimEventDispatcherService(CommonService): """ def _on_sim_change_gender(self, sim_info: SimInfo) -> bool: - from sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils + from s4ap.sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils new_gender = CommonGender.get_gender(sim_info) if CommonGenderUtils.is_male_gender(new_gender): # If they are now Male, it means they used to be Female. @@ -114,13 +114,13 @@ def _on_sim_init(self, sim_info: SimInfo, *_, **__) -> bool: return CommonEventRegistry.get().dispatch(S4CLSimInitializedEvent(sim_info)) def _on_sim_load(self, sim_info: SimInfo, *_, **__) -> bool: - from sims4communitylib.events.zone_spin.common_zone_spin_event_dispatcher import CommonZoneSpinEventDispatcher + from s4ap.sims4communitylib.events.zone_spin.common_zone_spin_event_dispatcher import CommonZoneSpinEventDispatcher if CommonZoneSpinEventDispatcher.get().game_loading: return False return CommonEventRegistry.get().dispatch(S4CLSimLoadedEvent(sim_info)) def _on_sim_spawned(self, sim_info: SimInfo, *_, **__) -> bool: - from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils return CommonEventRegistry.get().dispatch(S4CLSimSpawnedEvent(CommonSimUtils.get_sim_info(sim_info))) def _on_sim_died(self, sim_info: SimInfo, death_type: CommonDeathType, is_off_lot_death: bool, *_, **__) -> bool: @@ -133,7 +133,7 @@ def _pre_sim_despawned(self, sim_info: SimInfo, *_, **__) -> bool: return CommonEventRegistry.get().dispatch(S4CLSimPreDespawnedEvent(sim_info)) def _on_sim_change_age(self, sim_info: SimInfo, new_age: Age, current_age: Age) -> bool: - from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils return CommonEventRegistry.get().dispatch(S4CLSimChangedAgeEvent(CommonSimUtils.get_sim_info(sim_info), CommonAge.convert_from_vanilla(current_age), CommonAge.convert_from_vanilla(new_age))) def _on_sim_add_occult_type(self, occult_tracker: OccultTracker, occult_type: OccultType) -> bool: @@ -177,7 +177,7 @@ def _on_sim_buff_removed(self, buff: Buff, sim_id: int) -> None: CommonEventRegistry.get().dispatch(S4CLSimBuffRemovedEvent(sim_info, buff)) def _on_sim_set_current_outfit(self, sim_info: SimInfo, outfit_category_and_index: Tuple[OutfitCategory, int]) -> None: - from sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils + from s4ap.sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils CommonEventRegistry.get().dispatch(S4CLSimSetCurrentOutfitEvent(sim_info, CommonOutfitUtils.get_current_outfit(sim_info), outfit_category_and_index)) def _after_sim_set_current_outfit(self, sim_info: SimInfo, previous_outfit_category_and_index: Tuple[OutfitCategory, int], outfit_category_and_index: Tuple[OutfitCategory, int]) -> None: @@ -340,7 +340,7 @@ def _common_on_sim_trait_removed(original, self: TraitTracker, *args, **kwargs): @CommonEventRegistry.handle_events(ModInfo.get_identity()) def _common_register_buff_added_or_removed_on_sim_spawned(event_data: S4CLSimSpawnedEvent) -> bool: - from sims4communitylib.utils.sims.common_buff_utils import CommonBuffUtils + from s4ap.sims4communitylib.utils.sims.common_buff_utils import CommonBuffUtils buff_component: BuffComponent = CommonBuffUtils.get_buff_component(event_data.sim_info) if not buff_component: return False diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/game_object_added_to_sim_inventory.py b/Scripts/s4ap/sims4communitylib/events/sim/events/game_object_added_to_sim_inventory.py index 1a411d4..e47747e 100644 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/game_object_added_to_sim_inventory.py +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/game_object_added_to_sim_inventory.py @@ -7,8 +7,8 @@ """ from objects.game_object import GameObject from sims.sim_info import SimInfo -from sims4communitylib.events.event_handling.common_event import CommonEvent -from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils class S4CLGameObjectAddedToSimInventoryEvent(CommonEvent): @@ -21,8 +21,8 @@ class S4CLGameObjectAddedToSimInventoryEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/game_object_pre_removed_from_sim_inventory.py b/Scripts/s4ap/sims4communitylib/events/sim/events/game_object_pre_removed_from_sim_inventory.py index 05e4fe3..2f1a405 100644 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/game_object_pre_removed_from_sim_inventory.py +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/game_object_pre_removed_from_sim_inventory.py @@ -7,8 +7,8 @@ """ from objects.game_object import GameObject from sims.sim_info import SimInfo -from sims4communitylib.events.event_handling.common_event import CommonEvent -from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils class S4CLGameObjectPreRemovedFromSimInventoryEvent(CommonEvent): @@ -21,8 +21,8 @@ class S4CLGameObjectPreRemovedFromSimInventoryEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_added_occult_type.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_added_occult_type.py index b36e7e0..0b225b3 100644 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_added_occult_type.py +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_added_occult_type.py @@ -8,7 +8,7 @@ from sims.occult.occult_enums import OccultType from sims.occult.occult_tracker import OccultTracker from sims.sim_info import SimInfo -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent class S4CLSimAddedOccultTypeEvent(CommonEvent): @@ -21,8 +21,8 @@ class S4CLSimAddedOccultTypeEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_after_set_current_outfit.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_after_set_current_outfit.py index bea89cf..7f7cf59 100644 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_after_set_current_outfit.py +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_after_set_current_outfit.py @@ -9,7 +9,7 @@ from sims.outfits.outfit_enums import OutfitCategory from sims.sim_info import SimInfo -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent class S4CLSimAfterSetCurrentOutfitEvent(CommonEvent): @@ -22,8 +22,8 @@ class S4CLSimAfterSetCurrentOutfitEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_buff_added.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_buff_added.py index 4f13d68..9901792 100644 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_buff_added.py +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_buff_added.py @@ -7,8 +7,8 @@ """ from buffs.buff import Buff from sims.sim_info import SimInfo -from sims4communitylib.events.event_handling.common_event import CommonEvent -from sims4communitylib.utils.sims.common_buff_utils import CommonBuffUtils +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.utils.sims.common_buff_utils import CommonBuffUtils class S4CLSimBuffAddedEvent(CommonEvent): @@ -21,8 +21,8 @@ class S4CLSimBuffAddedEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_buff_removed.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_buff_removed.py index 59a199a..ba54d93 100644 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_buff_removed.py +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_buff_removed.py @@ -7,8 +7,8 @@ """ from buffs.buff import Buff from sims.sim_info import SimInfo -from sims4communitylib.events.event_handling.common_event import CommonEvent -from sims4communitylib.utils.sims.common_buff_utils import CommonBuffUtils +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.utils.sims.common_buff_utils import CommonBuffUtils class S4CLSimBuffRemovedEvent(CommonEvent): @@ -21,8 +21,8 @@ class S4CLSimBuffRemovedEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_age.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_age.py index 8533d5b..e13f8e1 100644 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_age.py +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_age.py @@ -6,8 +6,8 @@ Copyright (c) COLONOLNUTTY """ from sims.sim_info import SimInfo -from sims4communitylib.enums.common_age import CommonAge -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.enums.common_age import CommonAge +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent class S4CLSimChangedAgeEvent(CommonEvent): @@ -22,8 +22,8 @@ class S4CLSimChangedAgeEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender.py index 7c74da2..939695b 100644 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender.py +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender.py @@ -6,8 +6,8 @@ Copyright (c) COLONOLNUTTY """ from sims.sim_info import SimInfo -from sims4communitylib.enums.common_gender import CommonGender -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.enums.common_gender import CommonGender +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent class S4CLSimChangedGenderEvent(CommonEvent): @@ -20,8 +20,8 @@ class S4CLSimChangedGenderEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_body_frame.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_body_frame.py index d82986d..75d51ca 100644 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_body_frame.py +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_body_frame.py @@ -6,7 +6,7 @@ Copyright (c) COLONOLNUTTY """ from sims.sim_info import SimInfo -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent class S4CLSimChangedGenderOptionsBodyFrameEvent(CommonEvent): @@ -19,8 +19,8 @@ class S4CLSimChangedGenderOptionsBodyFrameEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_breasts.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_breasts.py index 07eb92c..69199a4 100644 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_breasts.py +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_breasts.py @@ -6,7 +6,7 @@ Copyright (c) COLONOLNUTTY """ from sims.sim_info import SimInfo -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent class S4CLSimChangedGenderOptionsBreastsEvent(CommonEvent): @@ -19,8 +19,8 @@ class S4CLSimChangedGenderOptionsBreastsEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_can_be_impregnated.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_can_be_impregnated.py index 5e6d211..dada074 100644 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_can_be_impregnated.py +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_can_be_impregnated.py @@ -6,7 +6,7 @@ Copyright (c) COLONOLNUTTY """ from sims.sim_info import SimInfo -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent class S4CLSimChangedGenderOptionsCanBeImpregnatedEvent(CommonEvent): @@ -19,8 +19,8 @@ class S4CLSimChangedGenderOptionsCanBeImpregnatedEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_can_impregnate.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_can_impregnate.py index 0bd47fd..b9043fc 100644 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_can_impregnate.py +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_can_impregnate.py @@ -6,7 +6,7 @@ Copyright (c) COLONOLNUTTY """ from sims.sim_info import SimInfo -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent class S4CLSimChangedGenderOptionsCanImpregnateEvent(CommonEvent): @@ -19,8 +19,8 @@ class S4CLSimChangedGenderOptionsCanImpregnateEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_can_reproduce.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_can_reproduce.py index 36dabcc..1853ab9 100644 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_can_reproduce.py +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_can_reproduce.py @@ -6,7 +6,7 @@ Copyright (c) COLONOLNUTTY """ from sims.sim_info import SimInfo -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent class S4CLSimChangedGenderOptionsCanReproduceEvent(CommonEvent): @@ -19,8 +19,8 @@ class S4CLSimChangedGenderOptionsCanReproduceEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_clothing_preference.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_clothing_preference.py index 4b83a1a..a78b66d 100644 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_clothing_preference.py +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_clothing_preference.py @@ -6,7 +6,7 @@ Copyright (c) COLONOLNUTTY """ from sims.sim_info import SimInfo -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent class S4CLSimChangedGenderOptionsClothingPreferenceEvent(CommonEvent): @@ -19,8 +19,8 @@ class S4CLSimChangedGenderOptionsClothingPreferenceEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_toilet_usage.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_toilet_usage.py index bb8c3f6..dc48691 100644 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_toilet_usage.py +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_toilet_usage.py @@ -6,7 +6,7 @@ Copyright (c) COLONOLNUTTY """ from sims.sim_info import SimInfo -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent class S4CLSimChangedGenderOptionsToiletUsageEvent(CommonEvent): @@ -19,8 +19,8 @@ class S4CLSimChangedGenderOptionsToiletUsageEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_occult_type.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_occult_type.py index 03cf473..666223a 100644 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_occult_type.py +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_occult_type.py @@ -8,7 +8,7 @@ from sims.occult.occult_enums import OccultType from sims.occult.occult_tracker import OccultTracker from sims.sim_info import SimInfo -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent class S4CLSimChangedOccultTypeEvent(CommonEvent): @@ -23,8 +23,8 @@ class S4CLSimChangedOccultTypeEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changing_occult_type.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changing_occult_type.py index 8c0d504..76169ea 100644 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changing_occult_type.py +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changing_occult_type.py @@ -8,7 +8,7 @@ from sims.occult.occult_enums import OccultType from sims.occult.occult_tracker import OccultTracker from sims.sim_info import SimInfo -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent class S4CLSimChangingOccultTypeEvent(CommonEvent): @@ -23,8 +23,8 @@ class S4CLSimChangingOccultTypeEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_died.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_died.py index f26c726..864e071 100644 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_died.py +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_died.py @@ -6,8 +6,8 @@ Copyright (c) COLONOLNUTTY """ from sims.sim_info import SimInfo -from sims4communitylib.enums.common_death_types import CommonDeathType -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.enums.common_death_types import CommonDeathType +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent class S4CLSimDiedEvent(CommonEvent): @@ -20,8 +20,8 @@ class S4CLSimDiedEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_initialized.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_initialized.py index 84c0d77..1783e3b 100644 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_initialized.py +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_initialized.py @@ -6,7 +6,7 @@ Copyright (c) COLONOLNUTTY """ from sims.sim_info import SimInfo -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent class S4CLSimInitializedEvent(CommonEvent): @@ -19,8 +19,8 @@ class S4CLSimInitializedEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_loaded.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_loaded.py index 1617792..95d2dd9 100644 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_loaded.py +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_loaded.py @@ -6,7 +6,7 @@ Copyright (c) COLONOLNUTTY """ from sims.sim_info import SimInfo -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent class S4CLSimLoadedEvent(CommonEvent): @@ -19,8 +19,8 @@ class S4CLSimLoadedEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_pre_despawned.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_pre_despawned.py index f89282a..e24ee14 100644 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_pre_despawned.py +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_pre_despawned.py @@ -6,7 +6,7 @@ Copyright (c) COLONOLNUTTY """ from sims.sim_info import SimInfo -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent class S4CLSimPreDespawnedEvent(CommonEvent): @@ -19,8 +19,8 @@ class S4CLSimPreDespawnedEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_relationship_bit_added.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_relationship_bit_added.py index 757a5e4..cc07e81 100644 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_relationship_bit_added.py +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_relationship_bit_added.py @@ -7,7 +7,7 @@ """ from relationships.relationship_bit import RelationshipBit from sims.sim_info import SimInfo -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent class S4CLSimRelationshipBitAddedEvent(CommonEvent): @@ -20,8 +20,8 @@ class S4CLSimRelationshipBitAddedEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: @@ -82,5 +82,5 @@ def relationship_bit_id(self) -> int: :return: The decimal identifier of the RelationshipBit. :rtype: int """ - from sims4communitylib.utils.sims.common_relationship_utils import CommonRelationshipUtils + from s4ap.sims4communitylib.utils.sims.common_relationship_utils import CommonRelationshipUtils return CommonRelationshipUtils.get_relationship_bit_guid(self.relationship_bit) diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_relationship_bit_removed.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_relationship_bit_removed.py index ba02788..41e33fa 100644 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_relationship_bit_removed.py +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_relationship_bit_removed.py @@ -7,7 +7,7 @@ """ from relationships.relationship_bit import RelationshipBit from sims.sim_info import SimInfo -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent class S4CLSimRelationshipBitRemovedEvent(CommonEvent): @@ -20,8 +20,8 @@ class S4CLSimRelationshipBitRemovedEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: @@ -82,5 +82,5 @@ def relationship_bit_id(self) -> int: :return: The decimal identifier of the RelationshipBit. :rtype: int """ - from sims4communitylib.utils.sims.common_relationship_utils import CommonRelationshipUtils + from s4ap.sims4communitylib.utils.sims.common_relationship_utils import CommonRelationshipUtils return CommonRelationshipUtils.get_relationship_bit_guid(self.relationship_bit) diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_removed_occult_type.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_removed_occult_type.py index bc868a7..8977712 100644 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_removed_occult_type.py +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_removed_occult_type.py @@ -8,7 +8,7 @@ from sims.occult.occult_enums import OccultType from sims.occult.occult_tracker import OccultTracker from sims.sim_info import SimInfo -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent class S4CLSimRemovedOccultTypeEvent(CommonEvent): @@ -21,8 +21,8 @@ class S4CLSimRemovedOccultTypeEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_revived.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_revived.py index c9c3aef..bb6a3b7 100644 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_revived.py +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_revived.py @@ -6,8 +6,8 @@ Copyright (c) COLONOLNUTTY """ from sims.sim_info import SimInfo -from sims4communitylib.enums.common_death_types import CommonDeathType -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.enums.common_death_types import CommonDeathType +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent class S4CLSimRevivedEvent(CommonEvent): @@ -20,8 +20,8 @@ class S4CLSimRevivedEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_set_current_outfit.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_set_current_outfit.py index d7804f1..6c3a67b 100644 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_set_current_outfit.py +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_set_current_outfit.py @@ -9,7 +9,7 @@ from sims.outfits.outfit_enums import OutfitCategory from sims.sim_info import SimInfo -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent class S4CLSimSetCurrentOutfitEvent(CommonEvent): @@ -22,8 +22,8 @@ class S4CLSimSetCurrentOutfitEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_skill_leveled_up.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_skill_leveled_up.py index fc1d6e3..f4f6c3e 100644 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_skill_leveled_up.py +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_skill_leveled_up.py @@ -6,8 +6,8 @@ Copyright (c) COLONOLNUTTY """ from sims.sim_info import SimInfo -from sims4communitylib.events.event_handling.common_event import CommonEvent -from sims4communitylib.utils.resources.common_skill_utils import CommonSkillUtils +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.utils.resources.common_skill_utils import CommonSkillUtils from statistics.skill import Skill @@ -21,8 +21,8 @@ class S4CLSimSkillLeveledUpEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_spawned.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_spawned.py index 6da5c6b..2afdd58 100644 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_spawned.py +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_spawned.py @@ -6,7 +6,7 @@ Copyright (c) COLONOLNUTTY """ from sims.sim_info import SimInfo -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent class S4CLSimSpawnedEvent(CommonEvent): @@ -19,8 +19,8 @@ class S4CLSimSpawnedEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_trait_added.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_trait_added.py index c5a67ad..1aa584e 100644 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_trait_added.py +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_trait_added.py @@ -6,8 +6,8 @@ Copyright (c) COLONOLNUTTY """ from sims.sim_info import SimInfo -from sims4communitylib.events.event_handling.common_event import CommonEvent -from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils from traits.trait_tracker import TraitTracker from traits.traits import Trait @@ -22,8 +22,8 @@ class S4CLSimTraitAddedEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_trait_removed.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_trait_removed.py index 30a1d4e..6080bb2 100644 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_trait_removed.py +++ b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_trait_removed.py @@ -6,8 +6,8 @@ Copyright (c) COLONOLNUTTY """ from sims.sim_info import SimInfo -from sims4communitylib.events.event_handling.common_event import CommonEvent -from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils from traits.trait_tracker import TraitTracker from traits.traits import Trait @@ -22,8 +22,8 @@ class S4CLSimTraitRemovedEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/zone_spin/common_zone_spin_event_dispatcher.py b/Scripts/s4ap/sims4communitylib/events/zone_spin/common_zone_spin_event_dispatcher.py index 6ccbaeb..2d7ecd9 100644 --- a/Scripts/s4ap/sims4communitylib/events/zone_spin/common_zone_spin_event_dispatcher.py +++ b/Scripts/s4ap/sims4communitylib/events/zone_spin/common_zone_spin_event_dispatcher.py @@ -8,17 +8,17 @@ from typing import Any from server.client import Client -from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from sims4communitylib.events.zone_spin.events.zone_early_load import S4CLZoneEarlyLoadEvent -from sims4communitylib.events.zone_spin.events.zone_late_load import S4CLZoneLateLoadEvent -from sims4communitylib.events.zone_spin.events.zone_manager_start_event import S4CLZoneManagerStartEvent -from sims4communitylib.events.zone_spin.events.zone_post_load import \ +from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry +from s4ap.sims4communitylib.events.zone_spin.events.zone_early_load import S4CLZoneEarlyLoadEvent +from s4ap.sims4communitylib.events.zone_spin.events.zone_late_load import S4CLZoneLateLoadEvent +from s4ap.sims4communitylib.events.zone_spin.events.zone_manager_start_event import S4CLZoneManagerStartEvent +from s4ap.sims4communitylib.events.zone_spin.events.zone_post_load import \ S4CLZonePostLoadEvent -from sims4communitylib.events.zone_spin.events.zone_save import S4CLZoneSaveEvent -from sims4communitylib.events.zone_spin.events.zone_teardown import S4CLZoneTeardownEvent -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.common_service import CommonService -from sims4communitylib.utils.common_injection_utils import CommonInjectionUtils +from s4ap.sims4communitylib.events.zone_spin.events.zone_save import S4CLZoneSaveEvent +from s4ap.sims4communitylib.events.zone_spin.events.zone_teardown import S4CLZoneTeardownEvent +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.common_service import CommonService +from s4ap.sims4communitylib.utils.common_injection_utils import CommonInjectionUtils from zone import Zone from zone_manager import ZoneManager diff --git a/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_early_load.py b/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_early_load.py index 633d747..736ac45 100644 --- a/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_early_load.py +++ b/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_early_load.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent from zone import Zone @@ -21,8 +21,8 @@ class S4CLZoneEarlyLoadEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_late_load.py b/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_late_load.py index b49f44f..9d4a330 100644 --- a/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_late_load.py +++ b/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_late_load.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent from zone import Zone @@ -21,8 +21,8 @@ class S4CLZoneLateLoadEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_manager_start_event.py b/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_manager_start_event.py index fa6768c..6998352 100644 --- a/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_manager_start_event.py +++ b/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_manager_start_event.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent from zone_manager import ZoneManager @@ -19,8 +19,8 @@ class S4CLZoneManagerStartEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_post_load.py b/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_post_load.py index 0317910..9157efa 100644 --- a/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_post_load.py +++ b/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_post_load.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent from zone import Zone @@ -19,8 +19,8 @@ class S4CLZonePostLoadEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_save.py b/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_save.py index 29eab47..6c70938 100644 --- a/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_save.py +++ b/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_save.py @@ -7,7 +7,7 @@ """ from typing import Any -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent from zone import Zone @@ -25,8 +25,8 @@ class S4CLZoneSaveEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_teardown.py b/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_teardown.py index d365ef0..32faa73 100644 --- a/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_teardown.py +++ b/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_teardown.py @@ -6,7 +6,7 @@ Copyright (c) COLONOLNUTTY """ from server.client import Client -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent from zone import Zone @@ -24,8 +24,8 @@ class S4CLZoneTeardownEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/events/zone_update/common_zone_update_event_dispatcher.py b/Scripts/s4ap/sims4communitylib/events/zone_update/common_zone_update_event_dispatcher.py index ac2ce52..83001be 100644 --- a/Scripts/s4ap/sims4communitylib/events/zone_update/common_zone_update_event_dispatcher.py +++ b/Scripts/s4ap/sims4communitylib/events/zone_update/common_zone_update_event_dispatcher.py @@ -6,14 +6,14 @@ Copyright (c) COLONOLNUTTY """ import math -from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from sims4communitylib.events.zone_update.events.zone_update_event import S4CLZoneUpdateEvent -from sims4communitylib.logging.has_log import HasLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.common_service import CommonService -from sims4communitylib.utils.common_injection_utils import CommonInjectionUtils -from sims4communitylib.utils.common_time_utils import CommonTimeUtils +from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry +from s4ap.sims4communitylib.events.zone_update.events.zone_update_event import S4CLZoneUpdateEvent +from s4ap.sims4communitylib.logging.has_log import HasLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.common_service import CommonService +from s4ap.sims4communitylib.utils.common_injection_utils import CommonInjectionUtils +from s4ap.sims4communitylib.utils.common_time_utils import CommonTimeUtils from zone import Zone diff --git a/Scripts/s4ap/sims4communitylib/events/zone_update/events/zone_update_event.py b/Scripts/s4ap/sims4communitylib/events/zone_update/events/zone_update_event.py index b1fbfd7..6897aa8 100644 --- a/Scripts/s4ap/sims4communitylib/events/zone_update/events/zone_update_event.py +++ b/Scripts/s4ap/sims4communitylib/events/zone_update/events/zone_update_event.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.events.event_handling.common_event import CommonEvent +from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent from zone import Zone @@ -21,8 +21,8 @@ class S4CLZoneUpdateEvent(CommonEvent): .. highlight:: python .. code-block:: python - from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry + from s4ap.sims4communitylib.modinfo import ModInfo class ExampleEventListener: diff --git a/Scripts/s4ap/sims4communitylib/examples/common_example_apply_bare_feet_buff.py b/Scripts/s4ap/sims4communitylib/examples/common_example_apply_bare_feet_buff.py index fd8255a..c85713b 100644 --- a/Scripts/s4ap/sims4communitylib/examples/common_example_apply_bare_feet_buff.py +++ b/Scripts/s4ap/sims4communitylib/examples/common_example_apply_bare_feet_buff.py @@ -11,15 +11,15 @@ from buffs.buff import Buff from sims.sim_info import SimInfo from sims4.tuning.tunable import TunableList, TunableTuple, TunableVariant, OptionalTunable -from sims4communitylib.classes.appearance_modifiers.common_attach_cas_parts_appearance_modifier import \ +from s4ap.sims4communitylib.classes.appearance_modifiers.common_attach_cas_parts_appearance_modifier import \ CommonAttachCASPartsAppearanceModifier -from sims4communitylib.dtos.common_cas_part import CommonCASPart -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.utils.cas.common_cas_utils import CommonCASUtils -from sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils -from sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils -from sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils +from s4ap.sims4communitylib.dtos.common_cas_part import CommonCASPart +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.utils.cas.common_cas_utils import CommonCASUtils +from s4ap.sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils +from s4ap.sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils +from s4ap.sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils from tunable_multiplier import TunableMultiplier diff --git a/Scripts/s4ap/sims4communitylib/exceptions/common_exceptions_handler.py b/Scripts/s4ap/sims4communitylib/exceptions/common_exceptions_handler.py index edb78d9..f56c56a 100644 --- a/Scripts/s4ap/sims4communitylib/exceptions/common_exceptions_handler.py +++ b/Scripts/s4ap/sims4communitylib/exceptions/common_exceptions_handler.py @@ -7,10 +7,10 @@ """ from functools import wraps from typing import Any, Callable, Union -from sims4communitylib.exceptions.common_stacktrace_utils import CommonStacktraceUtil -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.utils.common_date_utils import CommonRealDateUtils -from sims4communitylib.utils.common_io_utils import CommonIOUtils +from s4ap.sims4communitylib.exceptions.common_stacktrace_utils import CommonStacktraceUtil +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.utils.common_date_utils import CommonRealDateUtils +from s4ap.sims4communitylib.utils.common_io_utils import CommonIOUtils class CommonExceptionHandler: @@ -35,11 +35,11 @@ def log_exception(mod_identifier: Union[str, CommonModIdentity, None], exception :return: True, if the message was successfully logged. False, if the message was not successfully logged. :rtype: bool """ - from sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils + from s4ap.sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils mod_identifier = CommonModIdentityUtils.determine_mod_name_from_identifier(mod_identifier) exceptions = CommonStacktraceUtil.get_full_stack_trace() stack_trace = '{}{} -> {}: {}\n'.format(''.join(exceptions), exception_message, type(exception).__name__, exception) - from sims4communitylib.utils.common_log_registry import CommonLogUtils + from s4ap.sims4communitylib.utils.common_log_registry import CommonLogUtils file_path = CommonLogUtils.get_exceptions_file_path(mod_identifier, custom_file_path=custom_file_path) result = CommonExceptionHandler._log_stacktrace(mod_identifier, stack_trace, file_path) if result: @@ -61,7 +61,7 @@ def catch_exceptions(mod_identifier: Union[str, CommonModIdentity], fallback_ret :return: A function wrapped to catch and log exceptions. :rtype: Callable[..., Any] """ - from sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils + from s4ap.sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils mod_identifier = CommonModIdentityUtils.determine_mod_name_from_identifier(mod_identifier) def _catch_exception(exception_function: Callable[..., Any]): @@ -77,7 +77,7 @@ def _wrapper(*args, **kwargs) -> Any: @staticmethod def _log_stacktrace(mod_identifier: Union[str, CommonModIdentity], _traceback: str, file_path: str) -> bool: - from sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils + from s4ap.sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils mod_identifier = CommonModIdentityUtils.determine_mod_name_from_identifier(mod_identifier) exception_traceback_text = '[{}] {} {}\n'.format(mod_identifier, CommonRealDateUtils.get_current_date_string(), _traceback) return CommonIOUtils.write_to_file(file_path, exception_traceback_text, ignore_errors=True) @@ -85,12 +85,12 @@ def _log_stacktrace(mod_identifier: Union[str, CommonModIdentity], _traceback: s @staticmethod def _notify_exception_occurred(file_path: str, mod_identifier: Union[str, CommonModIdentity]=None): from ui.ui_dialog_notification import UiDialogNotification - from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification - from sims4communitylib.enums.strings_enum import CommonStringId - from sims4communitylib.events.zone_spin.common_zone_spin_event_dispatcher import CommonZoneSpinEventDispatcher + from s4ap.sims4communitylib.notifications.common_basic_notification import CommonBasicNotification + from s4ap.sims4communitylib.enums.strings_enum import CommonStringId + from s4ap.sims4communitylib.events.zone_spin.common_zone_spin_event_dispatcher import CommonZoneSpinEventDispatcher if not CommonZoneSpinEventDispatcher.get().game_loaded: return - from sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils + from s4ap.sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils mod_identifier = CommonModIdentityUtils.determine_mod_name_from_identifier(mod_identifier) basic_notification = CommonBasicNotification( CommonStringId.EXCEPTION_OCCURRED_TITLE_FOR_MOD, diff --git a/Scripts/s4ap/sims4communitylib/exceptions/common_stacktrace_utils.py b/Scripts/s4ap/sims4communitylib/exceptions/common_stacktrace_utils.py index 32bc3fe..68483f7 100644 --- a/Scripts/s4ap/sims4communitylib/exceptions/common_stacktrace_utils.py +++ b/Scripts/s4ap/sims4communitylib/exceptions/common_stacktrace_utils.py @@ -11,7 +11,7 @@ from typing import Union, Any, List # The following was tweaked slightly from the publicly made available, copyright free code here: https://stackoverflow.com/questions/13210436/get-full-traceback -from sims4communitylib.utils.common_collection_utils import CommonCollectionUtils +from s4ap.sims4communitylib.utils.common_collection_utils import CommonCollectionUtils FullTraceback = namedtuple('FullTraceback', ('tb_frame', 'tb_lineno', 'tb_next')) diff --git a/Scripts/s4ap/sims4communitylib/exceptions/generic_error_handling.py b/Scripts/s4ap/sims4communitylib/exceptions/generic_error_handling.py index 74278f0..07419df 100644 --- a/Scripts/s4ap/sims4communitylib/exceptions/generic_error_handling.py +++ b/Scripts/s4ap/sims4communitylib/exceptions/generic_error_handling.py @@ -8,10 +8,10 @@ from pprint import pformat from broadcasters.broadcaster import Broadcaster -from sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.utils.common_injection_utils import CommonInjectionUtils -from sims4communitylib.utils.resources.common_interaction_utils import CommonInteractionUtils +from s4ap.sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.utils.common_injection_utils import CommonInjectionUtils +from s4ap.sims4communitylib.utils.resources.common_interaction_utils import CommonInteractionUtils # Some interactions cause an error in this function, this is here to catch those errors and provide more information about them. diff --git a/Scripts/s4ap/sims4communitylib/logging/_has_s4cl_class_log.py b/Scripts/s4ap/sims4communitylib/logging/_has_s4cl_class_log.py index 05cdf19..36ea009 100644 --- a/Scripts/s4ap/sims4communitylib/logging/_has_s4cl_class_log.py +++ b/Scripts/s4ap/sims4communitylib/logging/_has_s4cl_class_log.py @@ -5,9 +5,9 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.logging.has_class_log import HasClassLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.logging.has_class_log import HasClassLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo class _HasS4CLClassLog(HasClassLog): diff --git a/Scripts/s4ap/sims4communitylib/logging/_has_s4cl_log.py b/Scripts/s4ap/sims4communitylib/logging/_has_s4cl_log.py index d88bf1b..ad77de9 100644 --- a/Scripts/s4ap/sims4communitylib/logging/_has_s4cl_log.py +++ b/Scripts/s4ap/sims4communitylib/logging/_has_s4cl_log.py @@ -5,9 +5,9 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.logging.has_log import HasLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.logging.has_log import HasLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo class _HasS4CLLog(HasLog): diff --git a/Scripts/s4ap/sims4communitylib/logging/_logging_commands.py b/Scripts/s4ap/sims4communitylib/logging/_logging_commands.py index 29e2bb5..67ca379 100644 --- a/Scripts/s4ap/sims4communitylib/logging/_logging_commands.py +++ b/Scripts/s4ap/sims4communitylib/logging/_logging_commands.py @@ -5,11 +5,11 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ CommonConsoleCommandArgument -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.common_log_registry import CommonLogRegistry +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.common_log_registry import CommonLogRegistry @CommonConsoleCommand( diff --git a/Scripts/s4ap/sims4communitylib/logging/has_class_log.py b/Scripts/s4ap/sims4communitylib/logging/has_class_log.py index 8181883..daed666 100644 --- a/Scripts/s4ap/sims4communitylib/logging/has_class_log.py +++ b/Scripts/s4ap/sims4communitylib/logging/has_class_log.py @@ -7,12 +7,12 @@ """ from typing import TYPE_CHECKING -from sims4communitylib.logging.has_log import HasLog -from sims4communitylib.mod_support.has_class_mod_identity import HasClassModIdentity -from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.logging.has_log import HasLog +from s4ap.sims4communitylib.mod_support.has_class_mod_identity import HasClassModIdentity +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity if TYPE_CHECKING: - from sims4communitylib.utils.common_log_registry import CommonLog, CommonLogRegistry + from s4ap.sims4communitylib.utils.common_log_registry import CommonLog, CommonLogRegistry class HasClassLog(HasClassModIdentity, HasLog): @@ -79,7 +79,7 @@ def get_log(cls) -> 'CommonLog': :return: An instance of CommonLog :rtype: CommonLog """ - from sims4communitylib.utils.common_log_registry import CommonLogRegistry + from s4ap.sims4communitylib.utils.common_log_registry import CommonLogRegistry if not hasattr(cls, '_log') or getattr(cls, '_log', None) is None: setattr(cls, '_log', CommonLogRegistry().register_log(cls.get_mod_identity(), cls.get_log_identifier())) if not hasattr(cls, '_verbose_log') or getattr(cls, '_verbose_log', None) is None: @@ -99,7 +99,7 @@ def get_verbose_log(cls) -> 'CommonLog': :return: An instance of CommonLog :rtype: CommonLog """ - from sims4communitylib.utils.common_log_registry import CommonLogRegistry + from s4ap.sims4communitylib.utils.common_log_registry import CommonLogRegistry if not hasattr(cls, '_verbose_log') or getattr(cls, '_verbose_log', None) is None: setattr(cls, '_verbose_log', CommonLogRegistry().register_log(cls.get_mod_identity(), cls.get_verbose_log_identifier())) return getattr(cls, '_verbose_log', None) diff --git a/Scripts/s4ap/sims4communitylib/logging/has_log.py b/Scripts/s4ap/sims4communitylib/logging/has_log.py index f6ac1c0..d5f3525 100644 --- a/Scripts/s4ap/sims4communitylib/logging/has_log.py +++ b/Scripts/s4ap/sims4communitylib/logging/has_log.py @@ -6,11 +6,11 @@ Copyright (c) COLONOLNUTTY """ from typing import TYPE_CHECKING, Union -from sims4communitylib.mod_support.has_mod_identity import HasModIdentity -from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.mod_support.has_mod_identity import HasModIdentity +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity if TYPE_CHECKING: - from sims4communitylib.utils.common_log_registry import CommonLog, CommonLogRegistry + from s4ap.sims4communitylib.utils.common_log_registry import CommonLog, CommonLogRegistry class HasLog(HasModIdentity): @@ -50,7 +50,7 @@ def verbose_log(self) -> 'CommonLog': :rtype: CommonLog """ if self._verbose_log is None: - from sims4communitylib.utils.common_log_registry import CommonLogRegistry + from s4ap.sims4communitylib.utils.common_log_registry import CommonLogRegistry self._verbose_log = CommonLogRegistry.get().register_log(self.mod_identity, self.verbose_log_identifier) return self._verbose_log @@ -64,7 +64,7 @@ def log(self) -> 'CommonLog': :rtype: CommonLog """ if self._log is None: - from sims4communitylib.utils.common_log_registry import CommonLogRegistry + from s4ap.sims4communitylib.utils.common_log_registry import CommonLogRegistry self._log = CommonLogRegistry.get().register_log(self.mod_identity, self.log_identifier) if self._verbose_log is None: self._verbose_log = CommonLogRegistry.get().register_log(self.mod_identity, self.verbose_log_identifier) diff --git a/Scripts/s4ap/sims4communitylib/logging/vanilla_logging.py b/Scripts/s4ap/sims4communitylib/logging/vanilla_logging.py index 4baa404..a2e754a 100644 --- a/Scripts/s4ap/sims4communitylib/logging/vanilla_logging.py +++ b/Scripts/s4ap/sims4communitylib/logging/vanilla_logging.py @@ -8,15 +8,15 @@ from typing import Any from sims4.log import Logger -from sims4communitylib.classes.time.common_stop_watch import CommonStopWatch -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.s4cl_configuration import S4CLConfiguration -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.services.common_service import CommonService -from sims4communitylib.utils.common_injection_utils import CommonInjectionUtils -from sims4communitylib.utils.common_log_registry import CommonLogRegistry, CommonLog -from sims4communitylib.utils.misc.common_text_utils import CommonTextUtils +from s4ap.sims4communitylib.classes.time.common_stop_watch import CommonStopWatch +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.s4cl_configuration import S4CLConfiguration +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.services.common_service import CommonService +from s4ap.sims4communitylib.utils.common_injection_utils import CommonInjectionUtils +from s4ap.sims4communitylib.utils.common_log_registry import CommonLogRegistry, CommonLog +from s4ap.sims4communitylib.utils.misc.common_text_utils import CommonTextUtils class _CommonVanillaLogOverride(CommonService): diff --git a/Scripts/s4ap/sims4communitylib/mod_support/common_mod_info.py b/Scripts/s4ap/sims4communitylib/mod_support/common_mod_info.py index b6aab9c..70e7458 100644 --- a/Scripts/s4ap/sims4communitylib/mod_support/common_mod_info.py +++ b/Scripts/s4ap/sims4communitylib/mod_support/common_mod_info.py @@ -5,8 +5,8 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.services.common_service import CommonService +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.services.common_service import CommonService class CommonModInfo(CommonService): @@ -19,7 +19,7 @@ class CommonModInfo(CommonService): .. highlight:: python .. code-block:: python - from sims4communitylib.mod_support.common_mod_info import CommonModInfo + from s4ap.sims4communitylib.mod_support.common_mod_info import CommonModInfo # This is how the sims4communitylib.modinfo.ModInfo implementation works. class ModInfo(CommonModInfo): diff --git a/Scripts/s4ap/sims4communitylib/mod_support/has_class_mod_identity.py b/Scripts/s4ap/sims4communitylib/mod_support/has_class_mod_identity.py index dffff25..8804a1b 100644 --- a/Scripts/s4ap/sims4communitylib/mod_support/has_class_mod_identity.py +++ b/Scripts/s4ap/sims4communitylib/mod_support/has_class_mod_identity.py @@ -5,8 +5,8 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.mod_support.has_mod_identity import HasModIdentity -from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.mod_support.has_mod_identity import HasModIdentity +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity class HasClassModIdentity(HasModIdentity): diff --git a/Scripts/s4ap/sims4communitylib/mod_support/has_mod_identity.py b/Scripts/s4ap/sims4communitylib/mod_support/has_mod_identity.py index b9454cd..9fabb88 100644 --- a/Scripts/s4ap/sims4communitylib/mod_support/has_mod_identity.py +++ b/Scripts/s4ap/sims4communitylib/mod_support/has_mod_identity.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity class HasModIdentity: diff --git a/Scripts/s4ap/sims4communitylib/mod_support/mod_identity.py b/Scripts/s4ap/sims4communitylib/mod_support/mod_identity.py index 2f43ecd..a95be05 100644 --- a/Scripts/s4ap/sims4communitylib/mod_support/mod_identity.py +++ b/Scripts/s4ap/sims4communitylib/mod_support/mod_identity.py @@ -88,7 +88,7 @@ def version(self) -> str: @staticmethod def _get_mod_name(mod_identifier: Union[str, 'CommonModIdentity']) -> Union[str, None]: - from sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils + from s4ap.sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils return CommonModIdentityUtils.determine_mod_name_from_identifier(mod_identifier) def __eq__(self, other: 'CommonModIdentity') -> bool: diff --git a/Scripts/s4ap/sims4communitylib/modinfo.py b/Scripts/s4ap/sims4communitylib/modinfo.py index 59ae16d..b9c9819 100644 --- a/Scripts/s4ap/sims4communitylib/modinfo.py +++ b/Scripts/s4ap/sims4communitylib/modinfo.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.mod_support.common_mod_info import CommonModInfo +from s4ap.sims4communitylib.mod_support.common_mod_info import CommonModInfo class ModInfo(CommonModInfo): diff --git a/Scripts/s4ap/sims4communitylib/notifications/common_basic_notification.py b/Scripts/s4ap/sims4communitylib/notifications/common_basic_notification.py index c4e3278..71ff3b2 100644 --- a/Scripts/s4ap/sims4communitylib/notifications/common_basic_notification.py +++ b/Scripts/s4ap/sims4communitylib/notifications/common_basic_notification.py @@ -8,13 +8,13 @@ from typing import Any, Union, Tuple, Iterator from distributor.shared_messages import IconInfoData from protocolbuffers.Localization_pb2 import LocalizedString -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils from ui.ui_dialog import UiDialogResponse from ui.ui_dialog_notification import UiDialogNotification diff --git a/Scripts/s4ap/sims4communitylib/persistence/common_game_object_data_storage.py b/Scripts/s4ap/sims4communitylib/persistence/common_game_object_data_storage.py index 6e2276b..bfef0f8 100644 --- a/Scripts/s4ap/sims4communitylib/persistence/common_game_object_data_storage.py +++ b/Scripts/s4ap/sims4communitylib/persistence/common_game_object_data_storage.py @@ -10,11 +10,11 @@ from typing import Dict, Any, Callable from typing import Union from objects.game_object import GameObject -from sims4communitylib.classes.serialization.common_serializable import CommonSerializable -from sims4communitylib.logging.has_class_log import HasClassLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.utils.common_type_utils import CommonTypeUtils -from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils +from s4ap.sims4communitylib.classes.serialization.common_serializable import CommonSerializable +from s4ap.sims4communitylib.logging.has_class_log import HasClassLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils +from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils class _CommonGameObjectDataStorageMetaclass(type): @@ -182,7 +182,7 @@ class _ExampleGameObjectDataStorage(CommonGameObjectDataStorage): @classmethod def get_mod_identity(cls) -> CommonModIdentity: # !!!Override with the CommonModIdentity of your own mod!!! - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.modinfo import ModInfo return ModInfo.get_identity() @property @@ -216,7 +216,7 @@ class _ExampleGameObjectDataStorage(CommonGameObjectDataStorage): @classmethod def get_mod_identity(cls) -> CommonModIdentity: # !!!Override with the CommonModIdentity of your own mod!!! - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.modinfo import ModInfo return ModInfo.get_identity() @property diff --git a/Scripts/s4ap/sims4communitylib/persistence/common_persisted_game_object_data_storage.py b/Scripts/s4ap/sims4communitylib/persistence/common_persisted_game_object_data_storage.py index 6f84199..48093f2 100644 --- a/Scripts/s4ap/sims4communitylib/persistence/common_persisted_game_object_data_storage.py +++ b/Scripts/s4ap/sims4communitylib/persistence/common_persisted_game_object_data_storage.py @@ -8,12 +8,12 @@ from typing import Dict, Any, Tuple, Type from objects.game_object import GameObject -from sims4communitylib.classes.serialization.common_serializable import CommonSerializable -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.persistence.data_management.common_data_manager import CommonDataManager -from sims4communitylib.persistence.data_stores.common_data_store import CommonDataStore -from sims4communitylib.persistence.common_game_object_data_storage import CommonGameObjectDataStorage -from sims4communitylib.persistence.data_stores.common_game_object_data_store import CommonGameObjectDataStore +from s4ap.sims4communitylib.classes.serialization.common_serializable import CommonSerializable +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.persistence.data_management.common_data_manager import CommonDataManager +from s4ap.sims4communitylib.persistence.data_stores.common_data_store import CommonDataStore +from s4ap.sims4communitylib.persistence.common_game_object_data_storage import CommonGameObjectDataStorage +from s4ap.sims4communitylib.persistence.data_stores.common_game_object_data_store import CommonGameObjectDataStore class CommonPersistedGameObjectDataStorage(CommonGameObjectDataStorage): @@ -34,7 +34,7 @@ class ExamplePersistedGameObjectDataStorage(CommonPersistedGameObjectDataStorage @classmethod def get_mod_identity(cls) -> CommonModIdentity: # !!!Override with the CommonModIdentity of your own mod!!! - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.modinfo import ModInfo return ModInfo.get_identity() @property @@ -54,7 +54,7 @@ def __init__(self, game_object: GameObject): super().__init__(game_object) if self.__class__.__name__ is CommonPersistedGameObjectDataStorage.__name__: raise RuntimeError('{} cannot be created directly. You must inherit from it to create an instance of it.'.format(self.__class__.__name__)) - from sims4communitylib.persistence.data_management.common_data_manager_registry import CommonDataManagerRegistry + from s4ap.sims4communitylib.persistence.data_management.common_data_manager_registry import CommonDataManagerRegistry self._data_manager_registry = CommonDataManagerRegistry() self.__data_manager: CommonDataManager = None self._data = self._load_persisted_data() diff --git a/Scripts/s4ap/sims4communitylib/persistence/common_persisted_sim_data_storage.py b/Scripts/s4ap/sims4communitylib/persistence/common_persisted_sim_data_storage.py index f9a21e0..3f99f1c 100644 --- a/Scripts/s4ap/sims4communitylib/persistence/common_persisted_sim_data_storage.py +++ b/Scripts/s4ap/sims4communitylib/persistence/common_persisted_sim_data_storage.py @@ -8,12 +8,12 @@ from typing import Dict, Any, Tuple, Type from sims.sim_info import SimInfo -from sims4communitylib.classes.serialization.common_serializable import CommonSerializable -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.persistence.data_management.common_data_manager import CommonDataManager -from sims4communitylib.persistence.data_stores.common_data_store import CommonDataStore -from sims4communitylib.persistence.common_sim_data_storage import CommonSimDataStorage -from sims4communitylib.persistence.data_stores.common_sim_data_store import CommonSimDataStore +from s4ap.sims4communitylib.classes.serialization.common_serializable import CommonSerializable +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.persistence.data_management.common_data_manager import CommonDataManager +from s4ap.sims4communitylib.persistence.data_stores.common_data_store import CommonDataStore +from s4ap.sims4communitylib.persistence.common_sim_data_storage import CommonSimDataStorage +from s4ap.sims4communitylib.persistence.data_stores.common_sim_data_store import CommonSimDataStore class CommonPersistedSimDataStorage(CommonSimDataStorage): @@ -34,7 +34,7 @@ class ExamplePersistedSimDataStorage(CommonPersistedSimDataStorage): @classmethod def get_mod_identity(cls) -> CommonModIdentity: # !!!Override with the CommonModIdentity of your own mod!!! - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.modinfo import ModInfo return ModInfo.get_identity() @property @@ -60,7 +60,7 @@ def __init__(self, sim_info: SimInfo): super().__init__(sim_info) if self.__class__.__name__ is CommonPersistedSimDataStorage.__name__: raise RuntimeError('{} cannot be created directly. You must inherit from it to create an instance of it.'.format(self.__class__.__name__)) - from sims4communitylib.persistence.data_management.common_data_manager_registry import CommonDataManagerRegistry + from s4ap.sims4communitylib.persistence.data_management.common_data_manager_registry import CommonDataManagerRegistry self._data_manager_registry = CommonDataManagerRegistry() self.__data_manager: CommonDataManager = None self._data = self._load_persisted_data() diff --git a/Scripts/s4ap/sims4communitylib/persistence/common_sim_data_storage.py b/Scripts/s4ap/sims4communitylib/persistence/common_sim_data_storage.py index e8e1273..5b53447 100644 --- a/Scripts/s4ap/sims4communitylib/persistence/common_sim_data_storage.py +++ b/Scripts/s4ap/sims4communitylib/persistence/common_sim_data_storage.py @@ -10,11 +10,11 @@ from typing import Dict, Any, Callable from typing import Union from sims.sim_info import SimInfo -from sims4communitylib.classes.serialization.common_serializable import CommonSerializable -from sims4communitylib.logging.has_class_log import HasClassLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.utils.common_type_utils import CommonTypeUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.classes.serialization.common_serializable import CommonSerializable +from s4ap.sims4communitylib.logging.has_class_log import HasClassLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils class _CommonSimDataStorageMetaclass(type): @@ -61,7 +61,7 @@ def __init__(self, sim_info: SimInfo): self._sim_info = sim_info self._data: Dict[str, Any] = dict() if sim_info is not None: - from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils + from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils sim_name = CommonSimNameUtils.get_full_name(sim_info) if sim_name is not None: self._data['sim_name'] = sim_name @@ -186,7 +186,7 @@ class _ExampleSimDataStorage(CommonSimDataStorage): @classmethod def get_mod_identity(cls) -> CommonModIdentity: # !!!Override with the CommonModIdentity of your own mod!!! - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.modinfo import ModInfo return ModInfo.get_identity() @property @@ -220,7 +220,7 @@ class _ExampleSimDataStorage(CommonSimDataStorage): @classmethod def get_mod_identity(cls) -> CommonModIdentity: # !!!Override with the CommonModIdentity of your own mod!!! - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.modinfo import ModInfo return ModInfo.get_identity() @property diff --git a/Scripts/s4ap/sims4communitylib/persistence/data_management/common_data_manager.py b/Scripts/s4ap/sims4communitylib/persistence/data_management/common_data_manager.py index e239187..3d18877 100644 --- a/Scripts/s4ap/sims4communitylib/persistence/data_management/common_data_manager.py +++ b/Scripts/s4ap/sims4communitylib/persistence/data_management/common_data_manager.py @@ -7,10 +7,10 @@ """ from typing import Dict, Any, Type, Tuple -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.logging.has_log import HasLog -from sims4communitylib.persistence.data_stores.common_data_store import CommonDataStore -from sims4communitylib.persistence.persistence_services.common_persistence_service import CommonPersistenceService +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.logging.has_log import HasLog +from s4ap.sims4communitylib.persistence.data_stores.common_data_store import CommonDataStore +from s4ap.sims4communitylib.persistence.persistence_services.common_persistence_service import CommonPersistenceService class CommonDataManager(HasLog): diff --git a/Scripts/s4ap/sims4communitylib/persistence/data_management/common_data_manager_registry.py b/Scripts/s4ap/sims4communitylib/persistence/data_management/common_data_manager_registry.py index b085afa..1e01291 100644 --- a/Scripts/s4ap/sims4communitylib/persistence/data_management/common_data_manager_registry.py +++ b/Scripts/s4ap/sims4communitylib/persistence/data_management/common_data_manager_registry.py @@ -7,14 +7,14 @@ """ from typing import Union, Dict, Any, Type, Callable -from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from sims4communitylib.events.save.events.save_loaded import S4CLSaveLoadedEvent -from sims4communitylib.events.save.events.save_saved import S4CLSaveSavedEvent -from sims4communitylib.logging.has_class_log import HasClassLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.persistence.data_management.common_data_manager import CommonDataManager -from sims4communitylib.services.common_service import CommonService +from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry +from s4ap.sims4communitylib.events.save.events.save_loaded import S4CLSaveLoadedEvent +from s4ap.sims4communitylib.events.save.events.save_saved import S4CLSaveSavedEvent +from s4ap.sims4communitylib.logging.has_class_log import HasClassLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.persistence.data_management.common_data_manager import CommonDataManager +from s4ap.sims4communitylib.services.common_service import CommonService class CommonDataManagerRegistry(CommonService, HasClassLog): @@ -28,10 +28,10 @@ class CommonDataManagerRegistry(CommonService, HasClassLog): .. code-block:: python from typing import Tuple - from sims4communitylib.mod_support.mod_identity import CommonModIdentity - from sims4communitylib.persistence.data_management.common_data_manager import CommonDataManager - from sims4communitylib.persistence.data_management.common_data_manager_registry import CommonDataManagerRegistry - from sims4communitylib.persistence.persistence_services.common_persistence_service import CommonPersistenceService + from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity + from s4ap.sims4communitylib.persistence.data_management.common_data_manager import CommonDataManager + from s4ap.sims4communitylib.persistence.data_management.common_data_manager_registry import CommonDataManagerRegistry + from s4ap.sims4communitylib.persistence.persistence_services.common_persistence_service import CommonPersistenceService # This attribute will register the data manager to the registry. @@ -53,9 +53,9 @@ def log_identifier(self) -> str: # noinspection PyMissingOrEmptyDocstring @property def persistence_services(self) -> Tuple[CommonPersistenceService]: - from sims4communitylib.persistence.persistence_services.common_hidden_household_persistence_service import \ + from s4ap.sims4communitylib.persistence.persistence_services.common_hidden_household_persistence_service import \ CommonHiddenHouseholdPersistenceService - from sims4communitylib.persistence.persistence_services.common_file_persistence_service import \ + from s4ap.sims4communitylib.persistence.persistence_services.common_file_persistence_service import \ CommonFilePersistenceService # The order matters. The later services will override data loaded from the earlier services. In the follow, any data loaded from the file will override any matching data that was loaded from the hidden household. result: Tuple[CommonPersistenceService] = ( @@ -113,13 +113,13 @@ def save_data(self) -> None: """ self.log.debug('Saving data managers.') - from sims4communitylib.persistence.common_game_object_data_storage import _CommonGameObjectDataStorageMetaclass + from s4ap.sims4communitylib.persistence.common_game_object_data_storage import _CommonGameObjectDataStorageMetaclass for (mod_name, data_storage_library) in _CommonGameObjectDataStorageMetaclass._game_object_storage_instances.items(): data_storage_library: Dict[int, '_CommonGameObjectDataStorageMetaclass'] = data_storage_library for data_storage in data_storage_library.values(): if hasattr(data_storage, '_save_persisted_data'): data_storage._save_persisted_data() - from sims4communitylib.persistence.common_sim_data_storage import _CommonSimDataStorageMetaclass + from s4ap.sims4communitylib.persistence.common_sim_data_storage import _CommonSimDataStorageMetaclass for (mod_name, data_storage_library) in _CommonSimDataStorageMetaclass._sim_storage_instances.items(): data_storage_library: Dict[int, '_CommonSimDataStorageMetaclass'] = data_storage_library for data_storage in data_storage_library.values(): @@ -136,9 +136,9 @@ def clear_data(self) -> None: Clear all data managers in the registry. """ self.log.debug('Clearing data managers.') - from sims4communitylib.persistence.common_game_object_data_storage import _CommonGameObjectDataStorageMetaclass + from s4ap.sims4communitylib.persistence.common_game_object_data_storage import _CommonGameObjectDataStorageMetaclass _CommonGameObjectDataStorageMetaclass._game_object_storage_instances = dict() - from sims4communitylib.persistence.common_sim_data_storage import _CommonSimDataStorageMetaclass + from s4ap.sims4communitylib.persistence.common_sim_data_storage import _CommonSimDataStorageMetaclass _CommonSimDataStorageMetaclass._sim_storage_instances = dict() for data_manager in self._data_managers.values(): try: diff --git a/Scripts/s4ap/sims4communitylib/persistence/data_stores/common_data_store.py b/Scripts/s4ap/sims4communitylib/persistence/data_stores/common_data_store.py index a52e42c..b622125 100644 --- a/Scripts/s4ap/sims4communitylib/persistence/data_stores/common_data_store.py +++ b/Scripts/s4ap/sims4communitylib/persistence/data_stores/common_data_store.py @@ -7,7 +7,7 @@ """ from typing import Dict, Any, Callable, Tuple -from sims4communitylib.classes.serialization.common_serializable import CommonSerializable +from s4ap.sims4communitylib.classes.serialization.common_serializable import CommonSerializable class CommonDataStore: diff --git a/Scripts/s4ap/sims4communitylib/persistence/data_stores/common_game_object_data_store.py b/Scripts/s4ap/sims4communitylib/persistence/data_stores/common_game_object_data_store.py index f26891d..37f9200 100644 --- a/Scripts/s4ap/sims4communitylib/persistence/data_stores/common_game_object_data_store.py +++ b/Scripts/s4ap/sims4communitylib/persistence/data_stores/common_game_object_data_store.py @@ -6,7 +6,7 @@ Copyright (c) COLONOLNUTTY """ from typing import Dict, Any -from sims4communitylib.persistence.data_stores.common_data_store import CommonDataStore +from s4ap.sims4communitylib.persistence.data_stores.common_data_store import CommonDataStore class CommonGameObjectDataStore(CommonDataStore): diff --git a/Scripts/s4ap/sims4communitylib/persistence/data_stores/common_sim_data_store.py b/Scripts/s4ap/sims4communitylib/persistence/data_stores/common_sim_data_store.py index 581799c..f38adb6 100644 --- a/Scripts/s4ap/sims4communitylib/persistence/data_stores/common_sim_data_store.py +++ b/Scripts/s4ap/sims4communitylib/persistence/data_stores/common_sim_data_store.py @@ -6,7 +6,7 @@ Copyright (c) COLONOLNUTTY """ from typing import Dict, Any -from sims4communitylib.persistence.data_stores.common_data_store import CommonDataStore +from s4ap.sims4communitylib.persistence.data_stores.common_data_store import CommonDataStore class CommonSimDataStore(CommonDataStore): diff --git a/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_file_persistence_service.py b/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_file_persistence_service.py index 6586623..1191d63 100644 --- a/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_file_persistence_service.py +++ b/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_file_persistence_service.py @@ -8,11 +8,11 @@ import os from typing import Dict, Any -from sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.persistence.persistence_services.common_persistence_service import CommonPersistenceService -from sims4communitylib.utils.common_json_io_utils import CommonJSONIOUtils -from sims4communitylib.utils.save_load.common_save_utils import CommonSaveUtils +from s4ap.sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.persistence.persistence_services.common_persistence_service import CommonPersistenceService +from s4ap.sims4communitylib.utils.common_json_io_utils import CommonJSONIOUtils +from s4ap.sims4communitylib.utils.save_load.common_save_utils import CommonSaveUtils class CommonFilePersistenceService(CommonPersistenceService): @@ -38,7 +38,7 @@ def __init__(self, per_save: bool=True, per_save_slot: bool=False, folder_name: self._per_save_slot = per_save_slot self._folder_name = folder_name self._custom_file_name = custom_file_name - from sims4communitylib.utils.common_log_utils import CommonLogUtils + from s4ap.sims4communitylib.utils.common_log_utils import CommonLogUtils self._data_folder_path = data_folder_path or CommonLogUtils.get_mod_data_location_path() # noinspection PyMissingOrEmptyDocstring @@ -108,7 +108,7 @@ def _file_path(self, mod_identity: CommonModIdentity, identifier: str=None) -> s return os.path.join(folder_path, self._custom_file_name) if self._per_save: save_slot_guid = CommonSaveUtils.get_save_slot_guid() - from sims4communitylib.s4cl_configuration import S4CLConfiguration + from s4ap.sims4communitylib.s4cl_configuration import S4CLConfiguration if self._per_save_slot or S4CLConfiguration().persist_mod_data_per_save_slot: save_slot_id = CommonSaveUtils.get_save_slot_id() if save_slot_id == 0: diff --git a/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_folder_persistence_service.py b/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_folder_persistence_service.py index 8b9e212..d5f5142 100644 --- a/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_folder_persistence_service.py +++ b/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_folder_persistence_service.py @@ -8,11 +8,11 @@ import os from typing import Dict, Any -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.persistence.persistence_services.common_persistence_service import CommonPersistenceService -from sims4communitylib.utils.common_collection_utils import CommonCollectionUtils -from sims4communitylib.utils.common_json_io_utils import CommonJSONIOUtils -from sims4communitylib.utils.common_log_registry import CommonLogRegistry +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.persistence.persistence_services.common_persistence_service import CommonPersistenceService +from s4ap.sims4communitylib.utils.common_collection_utils import CommonCollectionUtils +from s4ap.sims4communitylib.utils.common_json_io_utils import CommonJSONIOUtils +from s4ap.sims4communitylib.utils.common_log_registry import CommonLogRegistry class CommonFolderPersistenceService(CommonPersistenceService): @@ -49,9 +49,9 @@ def __init__( self._main_file_name = main_file_name self._combined_file_name = combined_file_name self._allow_duplicates_in_collections = allow_duplicates_in_collections - from sims4communitylib.utils.common_log_utils import CommonLogUtils + from s4ap.sims4communitylib.utils.common_log_utils import CommonLogUtils self._data_folder_path = data_folder_path or CommonLogUtils.get_mod_data_location_path() - from sims4communitylib.s4cl_configuration import S4CLConfiguration + from s4ap.sims4communitylib.s4cl_configuration import S4CLConfiguration self._create_combined_file = create_combined_file or S4CLConfiguration().create_combined_json # noinspection PyMissingOrEmptyDocstring diff --git a/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_hidden_household_persistence_service.py b/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_hidden_household_persistence_service.py index 0f5b1af..3266275 100644 --- a/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_hidden_household_persistence_service.py +++ b/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_hidden_household_persistence_service.py @@ -9,9 +9,9 @@ from typing import Dict, Any from sims.household import Household -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.persistence.persistence_services.common_persistence_service import CommonPersistenceService -from sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.persistence.persistence_services.common_persistence_service import CommonPersistenceService +from s4ap.sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils class CommonHiddenHouseholdPersistenceService(CommonPersistenceService): diff --git a/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_individual_folder_persistence_service.py b/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_individual_folder_persistence_service.py index ebe9455..574ab5a 100644 --- a/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_individual_folder_persistence_service.py +++ b/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_individual_folder_persistence_service.py @@ -8,10 +8,10 @@ import os from typing import Dict, Any -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.persistence.persistence_services.common_persistence_service import CommonPersistenceService -from sims4communitylib.utils.common_json_io_utils import CommonJSONIOUtils -from sims4communitylib.utils.common_log_registry import CommonLogRegistry +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.persistence.persistence_services.common_persistence_service import CommonPersistenceService +from s4ap.sims4communitylib.utils.common_json_io_utils import CommonJSONIOUtils +from s4ap.sims4communitylib.utils.common_log_registry import CommonLogRegistry class CommonIndividualFolderPersistenceService(CommonPersistenceService): @@ -37,7 +37,7 @@ def __init__( ) -> None: super().__init__() self._main_file_name = main_file_name - from sims4communitylib.utils.common_log_utils import CommonLogUtils + from s4ap.sims4communitylib.utils.common_log_utils import CommonLogUtils self._data_folder_path = data_folder_path or CommonLogUtils.get_mod_data_location_path() # noinspection PyMissingOrEmptyDocstring diff --git a/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_persistence_service.py b/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_persistence_service.py index 4103134..490c262 100644 --- a/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_persistence_service.py +++ b/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_persistence_service.py @@ -7,9 +7,9 @@ """ from typing import Dict, Any -from sims4communitylib.logging.has_log import HasLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.logging.has_log import HasLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo class CommonPersistenceService(HasLog): diff --git a/Scripts/s4ap/sims4communitylib/s4cl_commands.py b/Scripts/s4ap/sims4communitylib/s4cl_commands.py index e78da68..5ce92ee 100644 --- a/Scripts/s4ap/sims4communitylib/s4cl_commands.py +++ b/Scripts/s4ap/sims4communitylib/s4cl_commands.py @@ -6,17 +6,17 @@ Copyright (c) COLONOLNUTTY """ from objects.game_object import GameObject -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ CommonConsoleCommandArgument -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.common_log_registry import CommonLogRegistry -from sims4communitylib.utils.misc.common_fire_utils import CommonFireUtils -from sims4communitylib.utils.objects.common_object_location_utils import CommonObjectLocationUtils -from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils -from sims4communitylib.utils.sims.common_sim_location_utils import CommonSimLocationUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.common_log_registry import CommonLogRegistry +from s4ap.sims4communitylib.utils.misc.common_fire_utils import CommonFireUtils +from s4ap.sims4communitylib.utils.objects.common_object_location_utils import CommonObjectLocationUtils +from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils +from s4ap.sims4communitylib.utils.sims.common_sim_location_utils import CommonSimLocationUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils log = CommonLogRegistry().register_log(ModInfo.get_identity(), 's4cl_commands') log.enable() diff --git a/Scripts/s4ap/sims4communitylib/s4cl_configuration.py b/Scripts/s4ap/sims4communitylib/s4cl_configuration.py index 81f7799..e73a007 100644 --- a/Scripts/s4ap/sims4communitylib/s4cl_configuration.py +++ b/Scripts/s4ap/sims4communitylib/s4cl_configuration.py @@ -8,14 +8,14 @@ import os from typing import Tuple, Dict, List, Any -from sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler -from sims4communitylib.logging.has_log import HasLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.common_service import CommonService -from sims4communitylib.utils.common_json_io_utils import CommonJSONIOUtils -from sims4communitylib.utils.common_log_registry import CommonMessageType -from sims4communitylib.utils.common_resource_utils import CommonResourceUtils +from s4ap.sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler +from s4ap.sims4communitylib.logging.has_log import HasLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.common_service import CommonService +from s4ap.sims4communitylib.utils.common_json_io_utils import CommonJSONIOUtils +from s4ap.sims4communitylib.utils.common_log_registry import CommonMessageType +from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' diff --git a/Scripts/s4ap/sims4communitylib/services/commands/common_console_command.py b/Scripts/s4ap/sims4communitylib/services/commands/common_console_command.py index f469bcd..5d3785a 100644 --- a/Scripts/s4ap/sims4communitylib/services/commands/common_console_command.py +++ b/Scripts/s4ap/sims4communitylib/services/commands/common_console_command.py @@ -13,15 +13,15 @@ from sims.sim_info import SimInfo from sims4.commands import CommandType, CommandRestrictionFlags, Output, CustomParam from sims4.common import Pack -from sims4communitylib.logging.has_class_log import HasClassLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.services.common_service import CommonService +from s4ap.sims4communitylib.logging.has_class_log import HasClassLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.services.common_service import CommonService from singletons import UNSET if TYPE_CHECKING: - from sims4communitylib.utils.common_log_registry import CommonLog + from s4ap.sims4communitylib.utils.common_log_registry import CommonLog class CommonConsoleCommandArgument: @@ -275,7 +275,7 @@ def _help_command_name(self, mod_identity: CommonModIdentity) -> str: return f'{mod_name}.help' def _create_help_command(self, mod_identity: CommonModIdentity) -> None: - from sims4communitylib.utils.common_log_registry import CommonLogRegistry + from s4ap.sims4communitylib.utils.common_log_registry import CommonLogRegistry help_log = CommonLogRegistry().register_log(mod_identity, f'{mod_identity.name}_help') mod_name = CommonModIdentity._get_mod_name(mod_identity.name).lower() if mod_name not in self._commands_by_mod_name: @@ -348,7 +348,7 @@ def get_command_by_mod_and_name(self, mod_identity: CommonModIdentity, command_n @classmethod def command(cls, mod_identity: CommonModIdentity, *command_aliases: str, command_type: CommandType=CommandType.Live, command_restriction_flags: CommandRestrictionFlags=CommandRestrictionFlags.UNRESTRICTED, required_pack_flags: Pack=None, console_type: CommandType=None) -> Any: """Create a command.""" - from sims4communitylib.utils.common_log_registry import CommonLogRegistry + from s4ap.sims4communitylib.utils.common_log_registry import CommonLogRegistry log = CommonLogRegistry().register_log(mod_identity, f'{mod_identity.name}_command_log') _command = cls._command(log, *command_aliases, command_type=command_type, command_restrictions=command_restriction_flags, pack=required_pack_flags, console_type=console_type) @@ -516,7 +516,7 @@ def _add_cleaned_arg_value(_cleaned_arg) -> None: def _parse_arguments(cls, full_arg_spec: inspect.FullArgSpec, args: Tuple[str], arg_names: Tuple[str], kwargs_by_name, kwargs: Dict[str, Any], output: Union[CommonConsoleCommandOutput, Output]): (cleaned_args, cleaned_kwargs) = cls._clean_arguments(args) - from sims4communitylib.services.commands.common_console_command_parameters import CommonConsoleCommandParameter,\ + from s4ap.sims4communitylib.services.commands.common_console_command_parameters import CommonConsoleCommandParameter,\ CommonOptionalSimInfoConsoleCommandParameter, CommonRequiredGameObjectConsoleCommandParameter, \ CommonRequiredSimInfoConsoleCommandParameter arg_length = len(cleaned_args) @@ -609,11 +609,11 @@ def _parse_arg(cls, arg_type: Type, arg_value: Any, name: str, default_value: An output(f'ERROR: Invalid entry specified for bool {name}: {arg_value} (Expected one of {BOOL_TRUE} for True, or one of {BOOL_FALSE} for False.)') raise ValueError('invalid literal for boolean parameter') else: - from sims4communitylib.enums.enumtypes.common_int import CommonInt - from sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags + from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt + from s4ap.sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags if inspect.isclass(arg_type) and (arg_type is CommonInt or arg_type is CommonIntFlags or issubclass(arg_type, CommonInt) or issubclass(arg_type, CommonIntFlags)): if arg_value is not None: - from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils result = CommonResourceUtils.get_enum_by_name(arg_value.upper(), arg_type, default_value=default_value) if result is None: # noinspection PyUnresolvedReferences,PyTypeChecker diff --git a/Scripts/s4ap/sims4communitylib/services/commands/common_console_command_output.py b/Scripts/s4ap/sims4communitylib/services/commands/common_console_command_output.py index 6acfc91..7f61bfc 100644 --- a/Scripts/s4ap/sims4communitylib/services/commands/common_console_command_output.py +++ b/Scripts/s4ap/sims4communitylib/services/commands/common_console_command_output.py @@ -30,7 +30,7 @@ def get_sim(self, target: Union[OptionalTargetParam, RequiredTargetParam]) -> Un :return: An instance of the Sim that matches the target or None if not found. :rtype: Union[Sim, None] """ - from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils from server_commands.argument_helpers import get_optional_target sim = get_optional_target(target, self.connection) sim_info = CommonSimUtils.get_sim_info(sim) diff --git a/Scripts/s4ap/sims4communitylib/services/commands/common_console_command_parameters.py b/Scripts/s4ap/sims4communitylib/services/commands/common_console_command_parameters.py index 0801eda..3fb7e88 100644 --- a/Scripts/s4ap/sims4communitylib/services/commands/common_console_command_parameters.py +++ b/Scripts/s4ap/sims4communitylib/services/commands/common_console_command_parameters.py @@ -10,7 +10,7 @@ from objects.game_object import GameObject from sims.sim_info import SimInfo from sims4.commands import CustomParam -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput class CommonConsoleCommandParameter(CustomParam): @@ -41,8 +41,8 @@ def _get_target_id(cls, arg) -> Union[int, None]: def get_value(cls, output: CommonConsoleCommandOutput, *args: str) -> SimInfo: """Retrieve the number of arguments taken and the value returned.""" from singletons import UNSET - from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils + from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils if len(args) == 0: return UNSET sim_id = cls._get_target_id(args[0]) @@ -73,8 +73,8 @@ def get_value(cls, output: CommonConsoleCommandOutput, *args: str) -> SimInfo: return super().get_value(output, *args) def __new__(cls, output: CommonConsoleCommandOutput, *args: str) -> Union[SimInfo, None]: - from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils + from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils if len(args) == 0: return None int_val = cls._get_target_id(args[0]) @@ -100,7 +100,7 @@ class CommonOptionalSimInfoConsoleCommandParameter(CommonRequiredSimInfoConsoleC @classmethod def get_value(cls, output: CommonConsoleCommandOutput, *args: str) -> SimInfo: """Retrieve the number of arguments taken and the value returned.""" - from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils sim_info = super().get_value(output, *args) from singletons import UNSET if sim_info is UNSET: @@ -108,7 +108,7 @@ def get_value(cls, output: CommonConsoleCommandOutput, *args: str) -> SimInfo: return sim_info def __new__(cls, output: CommonConsoleCommandOutput, *args: str) -> Union[SimInfo, None]: - from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils return super().__new__(cls, output, *args) or CommonSimUtils.get_active_sim_info() @@ -126,7 +126,7 @@ def _get_target_id(cls, arg: str) -> Union[int, None]: @classmethod def get_value(cls, output: CommonConsoleCommandOutput, *args: str) -> GameObject: """Retrieve the number of arguments taken and the value returned.""" - from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils + from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils from singletons import UNSET if len(args) == 0: return UNSET @@ -139,7 +139,7 @@ def get_value(cls, output: CommonConsoleCommandOutput, *args: str) -> GameObject return super().get_value(output, *args) def __new__(cls, output: CommonConsoleCommandOutput, *args: str) -> Union[GameObject, None]: - from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils + from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils from singletons import UNSET if len(args) == 0: return UNSET diff --git a/Scripts/s4ap/sims4communitylib/services/interactions/interaction_registration_service.py b/Scripts/s4ap/sims4communitylib/services/interactions/interaction_registration_service.py index ad43ecc..f84c12d 100644 --- a/Scripts/s4ap/sims4communitylib/services/interactions/interaction_registration_service.py +++ b/Scripts/s4ap/sims4communitylib/services/interactions/interaction_registration_service.py @@ -10,12 +10,12 @@ from objects.script_object import ScriptObject from services.terrain_service import TerrainService from sims.sim import Sim -from sims4communitylib.enums.enumtypes.common_int import CommonInt -from sims4communitylib.logging._has_s4cl_log import _HasS4CLLog -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.common_service import CommonService -from sims4communitylib.utils.common_injection_utils import CommonInjectionUtils -from sims4communitylib.utils.common_type_utils import CommonTypeUtils +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.logging._has_s4cl_log import _HasS4CLLog +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.common_service import CommonService +from s4ap.sims4communitylib.utils.common_injection_utils import CommonInjectionUtils +from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils class CommonInteractionType(CommonInt): @@ -51,7 +51,7 @@ def _interactions_to_add_gen(self) -> Iterator[Interaction]: yield from self._cached_interactions_to_add else: cached_interactions = list() - from sims4communitylib.utils.resources.common_interaction_utils import CommonInteractionUtils + from s4ap.sims4communitylib.utils.resources.common_interaction_utils import CommonInteractionUtils affordance_manager = CommonInteractionUtils.get_instance_manager() for affordance_id in self.interactions_to_add: affordance_instance = affordance_manager.get(affordance_id) @@ -79,7 +79,7 @@ class ExampleInteractionHandler(CommonScriptObjectInteractionHandler): def interactions_to_add(self) -> Tuple[int]: # Interaction Ids # These are the decimal identifiers of the interactions from a package file. - from sims4communitylib.enums.interactions_enum import CommonInteractionId + from s4ap.sims4communitylib.enums.interactions_enum import CommonInteractionId return tuple([int(CommonInteractionId.SIM_CHAT), 2]) def should_add(self, script_object: ScriptObject, *args, **kwargs) -> bool: @@ -326,7 +326,7 @@ class ExampleInteractionHandler(CommonScriptObjectInteractionHandler): def interactions_to_add(self) -> Tuple[int]: # Interaction Ids # These are the decimal identifiers of the interactions from a package file. - from sims4communitylib.enums.interactions_enum import CommonInteractionId + from s4ap.sims4communitylib.enums.interactions_enum import CommonInteractionId # noinspection PyTypeChecker return tuple([int(CommonInteractionId.SIM_CHAT), 2]) diff --git a/Scripts/s4ap/sims4communitylib/services/resources/common_instance_manager_modification_registry.py b/Scripts/s4ap/sims4communitylib/services/resources/common_instance_manager_modification_registry.py index 78a1c8e..b0b46fb 100644 --- a/Scripts/s4ap/sims4communitylib/services/resources/common_instance_manager_modification_registry.py +++ b/Scripts/s4ap/sims4communitylib/services/resources/common_instance_manager_modification_registry.py @@ -8,12 +8,12 @@ from typing import Callable, Any, Type, List from sims4.tuning.instance_manager import InstanceManager -from sims4communitylib.logging._has_s4cl_log import _HasS4CLLog -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.common_service import CommonService -from sims4communitylib.services.resources.modification_handlers.common_instance_manager_modification_handler import \ +from s4ap.sims4communitylib.logging._has_s4cl_log import _HasS4CLLog +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.common_service import CommonService +from s4ap.sims4communitylib.services.resources.modification_handlers.common_instance_manager_modification_handler import \ CommonInstanceManagerModificationHandler -from sims4communitylib.utils.common_injection_utils import CommonInjectionUtils +from s4ap.sims4communitylib.utils.common_injection_utils import CommonInjectionUtils class CommonInstanceManagerModificationRegistry(CommonService, _HasS4CLLog): diff --git a/Scripts/s4ap/sims4communitylib/services/resources/common_posture_constraint_service.py b/Scripts/s4ap/sims4communitylib/services/resources/common_posture_constraint_service.py index 96dbfdf..a4fc3f6 100644 --- a/Scripts/s4ap/sims4communitylib/services/resources/common_posture_constraint_service.py +++ b/Scripts/s4ap/sims4communitylib/services/resources/common_posture_constraint_service.py @@ -8,7 +8,7 @@ from typing import Iterator, Union from interactions.constraints import Constraint, _ConstraintSet, Nowhere -from sims4communitylib.services.common_service import CommonService +from s4ap.sims4communitylib.services.common_service import CommonService class CommonPostureConstraintService(CommonService): diff --git a/Scripts/s4ap/sims4communitylib/services/resources/modification_handlers/common_add_interactions_to_affordance_lists_handler.py b/Scripts/s4ap/sims4communitylib/services/resources/modification_handlers/common_add_interactions_to_affordance_lists_handler.py index 2de05eb..bf0e80c 100644 --- a/Scripts/s4ap/sims4communitylib/services/resources/modification_handlers/common_add_interactions_to_affordance_lists_handler.py +++ b/Scripts/s4ap/sims4communitylib/services/resources/modification_handlers/common_add_interactions_to_affordance_lists_handler.py @@ -9,11 +9,11 @@ from sims4.tuning.instance_manager import InstanceManager from typing import Tuple -from sims4communitylib.classes.mixins.common_affordance_lists_mixin import \ +from s4ap.sims4communitylib.classes.mixins.common_affordance_lists_mixin import \ CommonAffordanceListsMixin -from sims4communitylib.classes.mixins.common_interactions_mixin import \ +from s4ap.sims4communitylib.classes.mixins.common_interactions_mixin import \ CommonInteractionsMixin -from sims4communitylib.services.resources.modification_handlers.common_instance_manager_modification_handler import \ +from s4ap.sims4communitylib.services.resources.modification_handlers.common_instance_manager_modification_handler import \ CommonInstanceManagerModificationHandler diff --git a/Scripts/s4ap/sims4communitylib/services/sim/cas/common_sim_outfit_io.py b/Scripts/s4ap/sims4communitylib/services/sim/cas/common_sim_outfit_io.py index 4fb9db8..aad2d7a 100644 --- a/Scripts/s4ap/sims4communitylib/services/sim/cas/common_sim_outfit_io.py +++ b/Scripts/s4ap/sims4communitylib/services/sim/cas/common_sim_outfit_io.py @@ -12,12 +12,12 @@ from sims.outfits.outfit_enums import OutfitCategory, BodyType from sims.sim_info import SimInfo from sims.sim_info_base_wrapper import SimInfoBaseWrapper -from sims4communitylib.enums.common_body_slot import CommonBodySlot -from sims4communitylib.logging.has_log import HasLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils -from sims4communitylib.utils.common_resource_utils import CommonResourceUtils -from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils +from s4ap.sims4communitylib.enums.common_body_slot import CommonBodySlot +from s4ap.sims4communitylib.logging.has_log import HasLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils +from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils +from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils class CommonSimOutfitIO(HasLog): @@ -199,7 +199,7 @@ def attach_cas_part(self, cas_part_id: int, body_type: Union[BodyType, int]=Body :return: True, if the CAS Part was attached successfully. False, if not. :rtype: bool """ - from sims4communitylib.utils.cas.common_cas_utils import CommonCASUtils + from s4ap.sims4communitylib.utils.cas.common_cas_utils import CommonCASUtils if cas_part_id == -1 or cas_part_id is None: self.log.format_error_with_message('Attempted to attach a negative or None CAS Part to the outfit of a Sim!', sim=self.sim_info, body_type=body_type, cas_part_id=cas_part_id, outfit_category_and_index=self._outfit_category_and_index) return False diff --git a/Scripts/s4ap/sims4communitylib/services/sim/cas/common_temporary_sim_clone_in_cas_service.py b/Scripts/s4ap/sims4communitylib/services/sim/cas/common_temporary_sim_clone_in_cas_service.py index 97d6cf9..6adc3fb 100644 --- a/Scripts/s4ap/sims4communitylib/services/sim/cas/common_temporary_sim_clone_in_cas_service.py +++ b/Scripts/s4ap/sims4communitylib/services/sim/cas/common_temporary_sim_clone_in_cas_service.py @@ -9,23 +9,23 @@ from typing import List, Callable, Dict, Tuple from sims.outfits.outfit_enums import OutfitCategory, BodyType from sims.sim_info import SimInfo -from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from sims4communitylib.events.sim.events.sim_set_current_outfit import S4CLSimSetCurrentOutfitEvent -from sims4communitylib.events.zone_spin.events.zone_late_load import S4CLZoneLateLoadEvent -from sims4communitylib.logging.has_log import HasLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ +from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry +from s4ap.sims4communitylib.events.sim.events.sim_set_current_outfit import S4CLSimSetCurrentOutfitEvent +from s4ap.sims4communitylib.events.zone_spin.events.zone_late_load import S4CLZoneLateLoadEvent +from s4ap.sims4communitylib.logging.has_log import HasLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ CommonConsoleCommandArgument -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.services.common_service import CommonService -from sims4communitylib.services.sim.cas.common_sim_outfit_io import CommonSimOutfitIO -from sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils -from sims4communitylib.utils.sims.common_sim_location_utils import CommonSimLocationUtils -from sims4communitylib.utils.sims.common_sim_spawn_utils import CommonSimSpawnUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.services.common_service import CommonService +from s4ap.sims4communitylib.services.sim.cas.common_sim_outfit_io import CommonSimOutfitIO +from s4ap.sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils +from s4ap.sims4communitylib.utils.sims.common_sim_location_utils import CommonSimLocationUtils +from s4ap.sims4communitylib.utils.sims.common_sim_spawn_utils import CommonSimSpawnUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils class CommonEditSimCloneInCASResponseHandle: @@ -157,7 +157,7 @@ def _setup_sim_clone_outfit( if setup_outfit is not None: setup_outfit(outfit_io) - # from sims4communitylib.utils.sims.common_occult_utils import CommonOccultUtils + # from s4ap.sims4communitylib.utils.sims.common_occult_utils import CommonOccultUtils # if CommonOccultUtils.has_any_occult(clone_sim_info): # CommonOccultUtils.switch_to_occult_form(clone_sim_info, OccultType.HUMAN) if outfit_io.apply(apply_to_all_outfits_in_same_category=True, apply_to_outfit_category_and_index=self._outfit_category_and_index): diff --git a/Scripts/s4ap/sims4communitylib/systems/caching/common_serializable_object_cache.py b/Scripts/s4ap/sims4communitylib/systems/caching/common_serializable_object_cache.py index b966920..df3a0b3 100644 --- a/Scripts/s4ap/sims4communitylib/systems/caching/common_serializable_object_cache.py +++ b/Scripts/s4ap/sims4communitylib/systems/caching/common_serializable_object_cache.py @@ -7,7 +7,7 @@ """ from typing import Union, Dict, Any, Type, Tuple, TypeVar, Generic, List -from sims4communitylib.classes.serialization.common_serializable import CommonSerializable +from s4ap.sims4communitylib.classes.serialization.common_serializable import CommonSerializable CommonSerializableObjectCacheType = TypeVar('CommonSerializableObjectCacheType', bound=CommonSerializable) diff --git a/Scripts/s4ap/sims4communitylib/systems/caching/common_serializable_object_cache_service.py b/Scripts/s4ap/sims4communitylib/systems/caching/common_serializable_object_cache_service.py index 07c0f7c..56c3654 100644 --- a/Scripts/s4ap/sims4communitylib/systems/caching/common_serializable_object_cache_service.py +++ b/Scripts/s4ap/sims4communitylib/systems/caching/common_serializable_object_cache_service.py @@ -8,14 +8,14 @@ import os from typing import Union, Generic, TypeVar, Tuple, Dict, Any -from sims4communitylib.systems.caching.common_serializable_object_cache import CommonSerializableObjectCache -from sims4communitylib.classes.serialization.common_serializable import CommonSerializable -from sims4communitylib.logging.has_log import HasLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.services.common_service import CommonService -from sims4communitylib.utils.common_io_utils import CommonIOUtils -from sims4communitylib.utils.common_json_io_utils import CommonJSONIOUtils -from sims4communitylib.utils.common_log_utils import CommonLogUtils +from s4ap.sims4communitylib.systems.caching.common_serializable_object_cache import CommonSerializableObjectCache +from s4ap.sims4communitylib.classes.serialization.common_serializable import CommonSerializable +from s4ap.sims4communitylib.logging.has_log import HasLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.services.common_service import CommonService +from s4ap.sims4communitylib.utils.common_io_utils import CommonIOUtils +from s4ap.sims4communitylib.utils.common_json_io_utils import CommonJSONIOUtils +from s4ap.sims4communitylib.utils.common_log_utils import CommonLogUtils CommonSerializableObjectCacheType = TypeVar('CommonSerializableObjectCacheType', bound=CommonSerializableObjectCache[CommonSerializable]) diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/common_loaded_item_query_registry.py b/Scripts/s4ap/sims4communitylib/systems/item_query/common_loaded_item_query_registry.py index 5e8b6a6..0e6fb8b 100644 --- a/Scripts/s4ap/sims4communitylib/systems/item_query/common_loaded_item_query_registry.py +++ b/Scripts/s4ap/sims4communitylib/systems/item_query/common_loaded_item_query_registry.py @@ -8,21 +8,21 @@ import collections from typing import List, Dict, Any, Tuple, Set, Callable, Union, Iterator, TypeVar, Generic -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.systems.item_query.item_tests.common_loaded_item_test import CommonLoadedItemTest -from sims4communitylib.systems.item_query.query.common_loaded_item_filter_request import CommonLoadedItemFilterRequest -from sims4communitylib.systems.item_query.query.common_loaded_item_organizer import CommonLoadedItemOrganizer -from sims4communitylib.systems.item_query.dtos.common_loaded_item import CommonLoadedItem -from sims4communitylib.systems.item_query.common_loaded_item_registry import CommonLoadedItemRegistry -from sims4communitylib.classes.time.common_stop_watch import CommonStopWatch -from sims4communitylib.events.zone_spin.events.zone_early_load import S4CLZoneEarlyLoadEvent -from sims4communitylib.events.zone_spin.events.zone_late_load import S4CLZoneLateLoadEvent -from sims4communitylib.logging.has_log import HasLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification -from sims4communitylib.services.common_service import CommonService -from sims4communitylib.systems.item_query.enums.common_query_method_type import CommonQueryMethodType -from sims4communitylib.utils.misc.common_text_utils import CommonTextUtils +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.systems.item_query.item_tests.common_loaded_item_test import CommonLoadedItemTest +from s4ap.sims4communitylib.systems.item_query.query.common_loaded_item_filter_request import CommonLoadedItemFilterRequest +from s4ap.sims4communitylib.systems.item_query.query.common_loaded_item_organizer import CommonLoadedItemOrganizer +from s4ap.sims4communitylib.systems.item_query.dtos.common_loaded_item import CommonLoadedItem +from s4ap.sims4communitylib.systems.item_query.common_loaded_item_registry import CommonLoadedItemRegistry +from s4ap.sims4communitylib.classes.time.common_stop_watch import CommonStopWatch +from s4ap.sims4communitylib.events.zone_spin.events.zone_early_load import S4CLZoneEarlyLoadEvent +from s4ap.sims4communitylib.events.zone_spin.events.zone_late_load import S4CLZoneLateLoadEvent +from s4ap.sims4communitylib.logging.has_log import HasLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.notifications.common_basic_notification import CommonBasicNotification +from s4ap.sims4communitylib.services.common_service import CommonService +from s4ap.sims4communitylib.systems.item_query.enums.common_query_method_type import CommonQueryMethodType +from s4ap.sims4communitylib.utils.misc.common_text_utils import CommonTextUtils CommonLoadedItemType = TypeVar('CommonLoadedItemType', bound=CommonLoadedItem) diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/common_loaded_item_registry.py b/Scripts/s4ap/sims4communitylib/systems/item_query/common_loaded_item_registry.py index 5112b9a..9caf626 100644 --- a/Scripts/s4ap/sims4communitylib/systems/item_query/common_loaded_item_registry.py +++ b/Scripts/s4ap/sims4communitylib/systems/item_query/common_loaded_item_registry.py @@ -8,16 +8,16 @@ from threading import Thread from typing import Iterator, Dict, List, Union, TypeVar, Generic, Tuple, Any -from sims4communitylib.systems.item_query.persistence.common_loaded_item_cache import CommonLoadedItemCache -from sims4communitylib.systems.item_query.persistence.common_loaded_item_cache_service import \ +from s4ap.sims4communitylib.systems.item_query.persistence.common_loaded_item_cache import CommonLoadedItemCache +from s4ap.sims4communitylib.systems.item_query.persistence.common_loaded_item_cache_service import \ CommonLoadedItemCacheService -from sims4communitylib.systems.item_query.item_loaders.common_base_item_loader import CommonBaseItemLoader -from sims4communitylib.systems.item_query.dtos.common_loaded_item import CommonLoadedItem +from s4ap.sims4communitylib.systems.item_query.item_loaders.common_base_item_loader import CommonBaseItemLoader +from s4ap.sims4communitylib.systems.item_query.dtos.common_loaded_item import CommonLoadedItem from sims4.callback_utils import CallableList -from sims4communitylib.classes.time.common_stop_watch import CommonStopWatch -from sims4communitylib.logging.has_log import HasLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.services.common_service import CommonService +from s4ap.sims4communitylib.classes.time.common_stop_watch import CommonStopWatch +from s4ap.sims4communitylib.logging.has_log import HasLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.services.common_service import CommonService CommonLoadedItemType = TypeVar('CommonLoadedItemType', bound=CommonLoadedItem) diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/dtos/common_loaded_item.py b/Scripts/s4ap/sims4communitylib/systems/item_query/dtos/common_loaded_item.py index 5b7767c..4ca9ac9 100644 --- a/Scripts/s4ap/sims4communitylib/systems/item_query/dtos/common_loaded_item.py +++ b/Scripts/s4ap/sims4communitylib/systems/item_query/dtos/common_loaded_item.py @@ -7,11 +7,11 @@ """ from typing import Union, Tuple, Any, Set, Iterator, Dict, Type -from sims4communitylib.classes.serialization.common_serializable import CommonSerializable -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.logging.has_class_log import HasClassLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.utils.common_log_registry import CommonLog +from s4ap.sims4communitylib.classes.serialization.common_serializable import CommonSerializable +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.logging.has_class_log import HasClassLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.utils.common_log_registry import CommonLog class CommonLoadedItem(CommonSerializable, HasClassLog): diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/enums/common_query_method_type.py b/Scripts/s4ap/sims4communitylib/systems/item_query/enums/common_query_method_type.py index 3837ae6..aa770af 100644 --- a/Scripts/s4ap/sims4communitylib/systems/item_query/enums/common_query_method_type.py +++ b/Scripts/s4ap/sims4communitylib/systems/item_query/enums/common_query_method_type.py @@ -5,7 +5,7 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt class CommonQueryMethodType(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/item_loaders/common_base_item_loader.py b/Scripts/s4ap/sims4communitylib/systems/item_query/item_loaders/common_base_item_loader.py index 5491f12..72efc0c 100644 --- a/Scripts/s4ap/sims4communitylib/systems/item_query/item_loaders/common_base_item_loader.py +++ b/Scripts/s4ap/sims4communitylib/systems/item_query/item_loaders/common_base_item_loader.py @@ -7,12 +7,12 @@ """ from typing import Tuple, Iterator, Any, Union, TypeVar, Generic -from sims4communitylib.systems.item_query.dtos.common_loaded_item import CommonLoadedItem +from s4ap.sims4communitylib.systems.item_query.dtos.common_loaded_item import CommonLoadedItem from sims4.resources import Types -from sims4communitylib.logging.has_log import HasLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.services.common_service import CommonService -from sims4communitylib.utils.common_resource_utils import CommonResourceUtils +from s4ap.sims4communitylib.logging.has_log import HasLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.services.common_service import CommonService +from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils CommonLoadedItemType = TypeVar('CommonLoadedItemType', bound=CommonLoadedItem) diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/item_tests/common_loaded_item_is_available_test.py b/Scripts/s4ap/sims4communitylib/systems/item_query/item_tests/common_loaded_item_is_available_test.py index 0fbd09d..cebe621 100644 --- a/Scripts/s4ap/sims4communitylib/systems/item_query/item_tests/common_loaded_item_is_available_test.py +++ b/Scripts/s4ap/sims4communitylib/systems/item_query/item_tests/common_loaded_item_is_available_test.py @@ -5,11 +5,11 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.systems.item_query.dtos.common_loaded_item import CommonLoadedItem -from sims4communitylib.systems.item_query.item_tests.common_loaded_item_test import CommonLoadedItemTest -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.systems.item_query.dtos.common_loaded_item import CommonLoadedItem +from s4ap.sims4communitylib.systems.item_query.item_tests.common_loaded_item_test import CommonLoadedItemTest +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo class CommonLoadedItemIsAvailableTest(CommonLoadedItemTest[CommonLoadedItem]): diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/item_tests/common_loaded_item_is_not_available_test.py b/Scripts/s4ap/sims4communitylib/systems/item_query/item_tests/common_loaded_item_is_not_available_test.py index cc606f3..41467b3 100644 --- a/Scripts/s4ap/sims4communitylib/systems/item_query/item_tests/common_loaded_item_is_not_available_test.py +++ b/Scripts/s4ap/sims4communitylib/systems/item_query/item_tests/common_loaded_item_is_not_available_test.py @@ -5,11 +5,11 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.systems.item_query.dtos.common_loaded_item import CommonLoadedItem -from sims4communitylib.systems.item_query.item_tests.common_loaded_item_test import CommonLoadedItemTest -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.systems.item_query.dtos.common_loaded_item import CommonLoadedItem +from s4ap.sims4communitylib.systems.item_query.item_tests.common_loaded_item_test import CommonLoadedItemTest +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo class CommonLoadedItemIsNotAvailableTest(CommonLoadedItemTest[CommonLoadedItem]): diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/item_tests/common_loaded_item_test.py b/Scripts/s4ap/sims4communitylib/systems/item_query/item_tests/common_loaded_item_test.py index 2d9594e..aecfd22 100644 --- a/Scripts/s4ap/sims4communitylib/systems/item_query/item_tests/common_loaded_item_test.py +++ b/Scripts/s4ap/sims4communitylib/systems/item_query/item_tests/common_loaded_item_test.py @@ -7,10 +7,10 @@ """ from typing import TypeVar, Generic -from sims4communitylib.systems.item_query.dtos.common_loaded_item import CommonLoadedItem -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.logging.has_class_log import HasClassLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.systems.item_query.dtos.common_loaded_item import CommonLoadedItem +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.logging.has_class_log import HasClassLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity CommonLoadedItemType = TypeVar('CommonLoadedItemType', bound=CommonLoadedItem) diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/persistence/common_loaded_item_cache.py b/Scripts/s4ap/sims4communitylib/systems/item_query/persistence/common_loaded_item_cache.py index f5ef1b9..ee4b9f4 100644 --- a/Scripts/s4ap/sims4communitylib/systems/item_query/persistence/common_loaded_item_cache.py +++ b/Scripts/s4ap/sims4communitylib/systems/item_query/persistence/common_loaded_item_cache.py @@ -7,8 +7,8 @@ """ from typing import TypeVar, Generic -from sims4communitylib.systems.item_query.dtos.common_loaded_item import CommonLoadedItem -from sims4communitylib.systems.caching.common_serializable_object_cache import CommonSerializableObjectCache +from s4ap.sims4communitylib.systems.item_query.dtos.common_loaded_item import CommonLoadedItem +from s4ap.sims4communitylib.systems.caching.common_serializable_object_cache import CommonSerializableObjectCache CommonLoadedItemCacheType = TypeVar('CommonLoadedItemCacheType', bound=CommonLoadedItem) diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/persistence/common_loaded_item_cache_service.py b/Scripts/s4ap/sims4communitylib/systems/item_query/persistence/common_loaded_item_cache_service.py index 0d4565b..8bdd353 100644 --- a/Scripts/s4ap/sims4communitylib/systems/item_query/persistence/common_loaded_item_cache_service.py +++ b/Scripts/s4ap/sims4communitylib/systems/item_query/persistence/common_loaded_item_cache_service.py @@ -7,11 +7,11 @@ """ from typing import Generic, TypeVar, Tuple, Union, Dict, Any -from sims4communitylib.systems.item_query.dtos.common_loaded_item import CommonLoadedItem -from sims4communitylib.systems.item_query.persistence.common_loaded_item_cache import CommonLoadedItemCache -from sims4communitylib.systems.caching.common_serializable_object_cache_service import \ +from s4ap.sims4communitylib.systems.item_query.dtos.common_loaded_item import CommonLoadedItem +from s4ap.sims4communitylib.systems.item_query.persistence.common_loaded_item_cache import CommonLoadedItemCache +from s4ap.sims4communitylib.systems.caching.common_serializable_object_cache_service import \ CommonSerializableObjectCacheService -from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity CommonLoadedItemCacheType = TypeVar('CommonLoadedItemCacheType', bound=CommonLoadedItemCache[CommonLoadedItem]) diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_filter.py b/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_filter.py index 67fdca6..6d0c32c 100644 --- a/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_filter.py +++ b/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_filter.py @@ -7,11 +7,11 @@ """ from typing import Tuple, Union, TypeVar, Generic -from sims4communitylib.enums.enumtypes.common_int import CommonInt -from sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags -from sims4communitylib.systems.item_query.query.common_loaded_item_key import CommonLoadedItemKey -from sims4communitylib.logging.has_log import HasLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags +from s4ap.sims4communitylib.systems.item_query.query.common_loaded_item_key import CommonLoadedItemKey +from s4ap.sims4communitylib.logging.has_log import HasLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity ItemKeyType = TypeVar('ItemKeyType', int, CommonInt, CommonIntFlags) diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_filter_request.py b/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_filter_request.py index d4b41c2..388105e 100644 --- a/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_filter_request.py +++ b/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_filter_request.py @@ -8,10 +8,10 @@ from pprint import pformat from typing import Tuple, Callable, List, TypeVar, Generic, Iterator -from sims4communitylib.systems.item_query.enums.common_query_method_type import CommonQueryMethodType -from sims4communitylib.systems.item_query.item_tests.common_loaded_item_test import CommonLoadedItemTest -from sims4communitylib.systems.item_query.query.common_loaded_item_key import CommonLoadedItemKey -from sims4communitylib.systems.item_query.query.common_loaded_item_filter import CommonLoadedItemFilter +from s4ap.sims4communitylib.systems.item_query.enums.common_query_method_type import CommonQueryMethodType +from s4ap.sims4communitylib.systems.item_query.item_tests.common_loaded_item_test import CommonLoadedItemTest +from s4ap.sims4communitylib.systems.item_query.query.common_loaded_item_key import CommonLoadedItemKey +from s4ap.sims4communitylib.systems.item_query.query.common_loaded_item_filter import CommonLoadedItemFilter CommonLoadedItemFilterType = TypeVar('CommonLoadedItemFilterType', bound=CommonLoadedItemFilter) CommonLoadedItemTestType = TypeVar('CommonLoadedItemTestType', bound=CommonLoadedItemTest) diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_key.py b/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_key.py index 3bddcaf..a0e4b9d 100644 --- a/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_key.py +++ b/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_key.py @@ -7,8 +7,8 @@ """ from typing import Any, Tuple, TypeVar, Generic -from sims4communitylib.enums.enumtypes.common_int import CommonInt -from sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags ItemKeyType = TypeVar('ItemKeyType', int, CommonInt, CommonIntFlags) diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_organizer.py b/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_organizer.py index f6fd7f8..3cd0fd1 100644 --- a/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_organizer.py +++ b/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_organizer.py @@ -7,9 +7,9 @@ """ from typing import Any, Tuple, Generic, TypeVar -from sims4communitylib.enums.enumtypes.common_int import CommonInt -from sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags -from sims4communitylib.systems.item_query.dtos.common_loaded_item import CommonLoadedItem +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags +from s4ap.sims4communitylib.systems.item_query.dtos.common_loaded_item import CommonLoadedItem CommonLoadedItemKeyType = TypeVar('CommonLoadedItemKeyType', int, CommonInt, CommonIntFlags) CommonLoadedItemType = TypeVar('CommonLoadedItemType', bound=CommonLoadedItem) diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_query_utils.py b/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_query_utils.py index ecdf2ca..0d23f04 100644 --- a/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_query_utils.py +++ b/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_query_utils.py @@ -8,17 +8,17 @@ import random from typing import Tuple, Iterator, Union, Generic, TypeVar -from sims4communitylib.systems.item_query.item_tests.common_loaded_item_test import CommonLoadedItemTest -from sims4communitylib.systems.item_query.item_tests.common_loaded_item_is_available_test import \ +from s4ap.sims4communitylib.systems.item_query.item_tests.common_loaded_item_test import CommonLoadedItemTest +from s4ap.sims4communitylib.systems.item_query.item_tests.common_loaded_item_is_available_test import \ CommonLoadedItemIsAvailableTest -from sims4communitylib.systems.item_query.query.common_loaded_item_filter import CommonLoadedItemFilter - -from sims4communitylib.systems.item_query.enums.common_query_method_type import CommonQueryMethodType -from sims4communitylib.systems.item_query.dtos.common_loaded_item import CommonLoadedItem -from sims4communitylib.systems.item_query.common_loaded_item_query_registry import CommonLoadedItemQueryRegistry -from sims4communitylib.logging.has_log import HasLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.systems.item_query.query.common_loaded_item_filter_request import CommonLoadedItemFilterRequest +from s4ap.sims4communitylib.systems.item_query.query.common_loaded_item_filter import CommonLoadedItemFilter + +from s4ap.sims4communitylib.systems.item_query.enums.common_query_method_type import CommonQueryMethodType +from s4ap.sims4communitylib.systems.item_query.dtos.common_loaded_item import CommonLoadedItem +from s4ap.sims4communitylib.systems.item_query.common_loaded_item_query_registry import CommonLoadedItemQueryRegistry +from s4ap.sims4communitylib.logging.has_log import HasLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.systems.item_query.query.common_loaded_item_filter_request import CommonLoadedItemFilterRequest CommonLoadedItemType = TypeVar('CommonLoadedItemType', bound=CommonLoadedItem) diff --git a/Scripts/s4ap/sims4communitylib/systems/settings/common_setting_utils.py b/Scripts/s4ap/sims4communitylib/systems/settings/common_setting_utils.py index 07aef38..c912548 100644 --- a/Scripts/s4ap/sims4communitylib/systems/settings/common_setting_utils.py +++ b/Scripts/s4ap/sims4communitylib/systems/settings/common_setting_utils.py @@ -7,13 +7,13 @@ """ from typing import Any, Tuple, Callable, TypeVar, Type, Generic -from sims4communitylib.classes.enums.common_versioned_enum_value_collection import CommonVersionedEnumValueCollection -from sims4communitylib.enums.enumtypes.common_int import CommonInt -from sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags -from sims4communitylib.enums.enumtypes.common_versioned_int import CommonVersionedInt -from sims4communitylib.enums.enumtypes.common_versioned_int_flags import CommonVersionedIntFlags -from sims4communitylib.systems.settings.common_settings_data_store import CommonSettingsDataStore -from sims4communitylib.utils.common_resource_utils import CommonResourceUtils +from s4ap.sims4communitylib.classes.enums.common_versioned_enum_value_collection import CommonVersionedEnumValueCollection +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags +from s4ap.sims4communitylib.enums.enumtypes.common_versioned_int import CommonVersionedInt +from s4ap.sims4communitylib.enums.enumtypes.common_versioned_int_flags import CommonVersionedIntFlags +from s4ap.sims4communitylib.systems.settings.common_settings_data_store import CommonSettingsDataStore +from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils SettingEnumType = TypeVar('SettingEnumType', CommonInt, CommonIntFlags, CommonVersionedInt, CommonVersionedIntFlags) SettingDataStoreType = TypeVar('SettingDataStoreType', bound=CommonSettingsDataStore) diff --git a/Scripts/s4ap/sims4communitylib/systems/settings/common_settings_data_manager.py b/Scripts/s4ap/sims4communitylib/systems/settings/common_settings_data_manager.py index 13c5ec3..60b4df5 100644 --- a/Scripts/s4ap/sims4communitylib/systems/settings/common_settings_data_manager.py +++ b/Scripts/s4ap/sims4communitylib/systems/settings/common_settings_data_manager.py @@ -6,9 +6,9 @@ Copyright (c) COLONOLNUTTY """ from typing import Tuple -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.persistence.data_management.common_data_manager import CommonDataManager -from sims4communitylib.persistence.persistence_services.common_persistence_service import CommonPersistenceService +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.persistence.data_management.common_data_manager import CommonDataManager +from s4ap.sims4communitylib.persistence.persistence_services.common_persistence_service import CommonPersistenceService class CommonSettingsDataManager(CommonDataManager): @@ -33,7 +33,7 @@ def log_identifier(self) -> str: # noinspection PyMissingOrEmptyDocstring @property def persistence_services(self) -> Tuple[CommonPersistenceService]: - from sims4communitylib.persistence.persistence_services.common_file_persistence_service import \ + from s4ap.sims4communitylib.persistence.persistence_services.common_file_persistence_service import \ CommonFilePersistenceService result: Tuple[CommonPersistenceService] = ( CommonFilePersistenceService(per_save=False), diff --git a/Scripts/s4ap/sims4communitylib/systems/settings/common_settings_data_manager_utils.py b/Scripts/s4ap/sims4communitylib/systems/settings/common_settings_data_manager_utils.py index 2553c43..1620f13 100644 --- a/Scripts/s4ap/sims4communitylib/systems/settings/common_settings_data_manager_utils.py +++ b/Scripts/s4ap/sims4communitylib/systems/settings/common_settings_data_manager_utils.py @@ -7,12 +7,12 @@ """ from typing import Type, Union, Dict, Any, TypeVar -from sims4communitylib.logging.has_log import HasLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.persistence.data_management.common_data_manager_registry import CommonDataManagerRegistry -from sims4communitylib.persistence.data_stores.common_data_store import CommonDataStore -from sims4communitylib.services.common_service import CommonService -from sims4communitylib.systems.settings.common_settings_data_manager import CommonSettingsDataManager +from s4ap.sims4communitylib.logging.has_log import HasLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.persistence.data_management.common_data_manager_registry import CommonDataManagerRegistry +from s4ap.sims4communitylib.persistence.data_stores.common_data_store import CommonDataStore +from s4ap.sims4communitylib.services.common_service import CommonService +from s4ap.sims4communitylib.systems.settings.common_settings_data_manager import CommonSettingsDataManager CommonDataStoreType = TypeVar('CommonDataStoreType', bound=CommonDataStore) diff --git a/Scripts/s4ap/sims4communitylib/systems/settings/common_settings_data_store.py b/Scripts/s4ap/sims4communitylib/systems/settings/common_settings_data_store.py index 1442338..9de1ec3 100644 --- a/Scripts/s4ap/sims4communitylib/systems/settings/common_settings_data_store.py +++ b/Scripts/s4ap/sims4communitylib/systems/settings/common_settings_data_store.py @@ -7,7 +7,7 @@ """ from typing import Any, Dict -from sims4communitylib.persistence.data_stores.common_data_store import CommonDataStore +from s4ap.sims4communitylib.persistence.data_stores.common_data_store import CommonDataStore class CommonSettingsDataStore(CommonDataStore): diff --git a/Scripts/s4ap/sims4communitylib/testing/common_assertion_utils.py b/Scripts/s4ap/sims4communitylib/testing/common_assertion_utils.py index e9cdd91..6b7bd64 100644 --- a/Scripts/s4ap/sims4communitylib/testing/common_assertion_utils.py +++ b/Scripts/s4ap/sims4communitylib/testing/common_assertion_utils.py @@ -7,9 +7,9 @@ """ from typing import Any, List, Union, Tuple, Callable, Dict -from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.utils.common_collection_utils import CommonCollectionUtils +from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.utils.common_collection_utils import CommonCollectionUtils class CommonAssertionUtils: diff --git a/Scripts/s4ap/sims4communitylib/testing/common_test_service.py b/Scripts/s4ap/sims4communitylib/testing/common_test_service.py index 558f741..9c752e0 100644 --- a/Scripts/s4ap/sims4communitylib/testing/common_test_service.py +++ b/Scripts/s4ap/sims4communitylib/testing/common_test_service.py @@ -8,13 +8,13 @@ from typing import Callable, Any, Dict, List, Union, Tuple from functools import wraps from traceback import format_exc -from sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.common_service import CommonService +from s4ap.sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.common_service import CommonService # This try catch is here for when tests are being run via PyCharm rather than from in-game. try: - from sims4communitylib.utils.common_log_registry import CommonLogRegistry + from s4ap.sims4communitylib.utils.common_log_registry import CommonLogRegistry community_test_log_log = CommonLogRegistry().register_log(ModInfo.get_identity(), 'community_test_log') community_test_log_log.enable() @@ -135,7 +135,7 @@ def get_test_library_by_mod(self, mod_identifier: Union[str, CommonModIdentity]) :return: A library of tests for the specified Mod organized by class name. :rtype: Dict[str, Any] """ - from sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils + from s4ap.sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils mod_name = CommonModIdentityUtils.determine_mod_name_from_identifier(mod_identifier, include_version=False).lower() for (mod_identity, tests_by_class_name) in self._tests_by_mod_identity.items(): lower_mod_name = CommonModIdentityUtils.determine_mod_name_from_identifier(mod_identity, include_version=False).lower() @@ -153,7 +153,7 @@ def get_tests_by_mod_name(self, mod_identifier: Union[str, CommonModIdentity]) - :return: A collection of tests for the specified Mod. :rtype: Tuple[Any] """ - from sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils + from s4ap.sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils mod_name = CommonModIdentityUtils.determine_mod_name_from_identifier(mod_identifier, include_version=False).lower() class_tests_by_class_name = self._tests_by_mod_identity.get(mod_name, dict()) all_tests: List[Any] = list() @@ -270,7 +270,7 @@ def run_tests_by_mod_name(self, mod_identifier: Union[str, CommonModIdentity], c def _run_tests(self, mod_identifier: Union[str, CommonModIdentity]=None, class_names: Tuple[str]=tuple(), callback: Callable[..., Any]=print): total_run_test_count = 0 total_failed_test_count = 0 - from sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils + from s4ap.sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils if mod_identifier: to_run_mod_name = CommonModIdentityUtils.determine_mod_name_from_identifier(mod_identifier, include_version=False).lower() else: @@ -278,7 +278,7 @@ def _run_tests(self, mod_identifier: Union[str, CommonModIdentity]=None, class_n for (mod_identity, class_tests_by_class_name) in self.all_tests.items(): mod_name = mod_identity.name if to_run_mod_name: - from sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils + from s4ap.sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils cleaned_mod_name = CommonModIdentityUtils.determine_mod_name_from_identifier(mod_identity, include_version=False).lower() if cleaned_mod_name != to_run_mod_name: continue @@ -320,9 +320,9 @@ def _run_tests(self, mod_identifier: Union[str, CommonModIdentity]=None, class_n try: - from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ + from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ CommonConsoleCommandArgument - from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput + from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput @CommonConsoleCommand( ModInfo.get_identity(), diff --git a/Scripts/s4ap/sims4communitylib/utils/cas/common_cas_utils.py b/Scripts/s4ap/sims4communitylib/utils/cas/common_cas_utils.py index 3637e36..dbd2fa6 100644 --- a/Scripts/s4ap/sims4communitylib/utils/cas/common_cas_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/cas/common_cas_utils.py @@ -9,17 +9,17 @@ from typing import Tuple, Union, Iterator, Dict, List from sims4.utils import classproperty -from sims4communitylib.classes.time.common_stop_watch import CommonStopWatch -from sims4communitylib.dtos.common_cas_part import CommonCASPart -from sims4communitylib.enums.common_body_slot import CommonBodySlot -from sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ +from s4ap.sims4communitylib.classes.time.common_stop_watch import CommonStopWatch +from s4ap.sims4communitylib.dtos.common_cas_part import CommonCASPart +from s4ap.sims4communitylib.enums.common_body_slot import CommonBodySlot +from s4ap.sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ CommonConsoleCommandArgument -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.services.sim.cas.common_sim_outfit_io import CommonSimOutfitIO -from sims4communitylib.utils.common_resource_utils import CommonResourceUtils +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.services.sim.cas.common_sim_outfit_io import CommonSimOutfitIO +from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' @@ -190,7 +190,7 @@ def attach_cas_parts_to_all_outfits_of_sim(cls, sim_info: SimInfo, cas_parts: It for cas_part in cas_parts: cas_parts_by_body_type[int(CommonBodySlot.convert_to_vanilla(cas_part.body_type))] = cas_part cas_part_body_types = [int(CommonBodySlot.convert_to_vanilla(cas_part.body_type)) for cas_part in cas_parts] - from sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils + from s4ap.sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils current_outfit = CommonOutfitUtils.get_current_outfit(sim_info) from protocolbuffers import S4Common_pb2, Outfits_pb2 saved_outfits = sim_info.save_outfits() @@ -277,7 +277,7 @@ def attach_cas_parts_to_outfit_of_sim(cls, sim_info: SimInfo, cas_parts: Iterato stop_watch = CommonStopWatch() try: stop_watch.start() - from sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils + from s4ap.sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils current_outfit = CommonOutfitUtils.get_current_outfit(sim_info) if outfit_category_and_index is None: outfit_category_and_index = current_outfit @@ -353,7 +353,7 @@ def detach_cas_parts_from_all_outfits_of_sim(cls, sim_info: SimInfo, cas_parts: """ _log = cls.get_log() cas_part_ids = tuple([cas_part.cas_part_id for cas_part in cas_parts]) - from sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils + from s4ap.sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils current_outfit = CommonOutfitUtils.get_current_outfit(sim_info) from protocolbuffers import S4Common_pb2, Outfits_pb2 saved_outfits = sim_info.save_outfits() @@ -420,7 +420,7 @@ def detach_cas_parts_from_outfit_of_sim(cls, sim_info: SimInfo, cas_parts: Itera :return: True, if the CAS parts were successfully detached from the outfit of the Sim. False, if not. :rtype: bool """ - from sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils + from s4ap.sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils current_outfit = CommonOutfitUtils.get_current_outfit(sim_info) if outfit_category_and_index is None: outfit_category_and_index = current_outfit @@ -561,7 +561,7 @@ def detach_body_types_from_outfit_of_sim(cls, sim_info: SimInfo, body_types_to_r :return: True, if the body types were successfully detached from the outfit of the Sim. False, if not. :rtype: bool """ - from sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils + from s4ap.sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils current_outfit = CommonOutfitUtils.get_current_outfit(sim_info) if outfit_category_and_index is None: outfit_category_and_index = current_outfit diff --git a/Scripts/s4ap/sims4communitylib/utils/cas/common_outfit_utils.py b/Scripts/s4ap/sims4communitylib/utils/cas/common_outfit_utils.py index e4f85e1..387682d 100644 --- a/Scripts/s4ap/sims4communitylib/utils/cas/common_outfit_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/cas/common_outfit_utils.py @@ -16,19 +16,19 @@ from sims.sim_info import SimInfo from sims.sim_info_base_wrapper import SimInfoBaseWrapper from sims4.utils import classproperty -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.enums.buffs_enum import CommonBuffId -from sims4communitylib.enums.tags_enum import CommonGameTag -from sims4communitylib.logging.has_class_log import HasClassLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.enums.buffs_enum import CommonBuffId +from s4ap.sims4communitylib.enums.tags_enum import CommonGameTag +from s4ap.sims4communitylib.logging.has_class_log import HasClassLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ CommonConsoleCommandArgument -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.common_log_registry import CommonLogRegistry -from sims4communitylib.utils.common_resource_utils import CommonResourceUtils -from sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils -from sims4communitylib.utils.sims.common_buff_utils import CommonBuffUtils +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.common_log_registry import CommonLogRegistry +from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils +from s4ap.sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils +from s4ap.sims4communitylib.utils.sims.common_buff_utils import CommonBuffUtils from singletons import DEFAULT from typing import Tuple, Union, Dict, Callable, Iterator, Set @@ -817,7 +817,7 @@ def copy_outfit(cls, mod_identity: CommonModIdentity, sim_info: SimInfo, from_ou :return: True, if CAS Parts were copied successfully. False, if not. :rtype: bool """ - from sims4communitylib.services.sim.cas.common_sim_outfit_io import CommonSimOutfitIO + from s4ap.sims4communitylib.services.sim.cas.common_sim_outfit_io import CommonSimOutfitIO outfit_io = CommonSimOutfitIO(sim_info, outfit_category_and_index=from_outfit_category_and_index, mod_identity=mod_identity) return outfit_io.apply(change_sim_to_outfit_after_apply=change_sim_to_outfit_after_apply, apply_to_all_outfits_in_same_category=False, apply_to_outfit_category_and_index=to_outfit_category_and_index) @@ -837,7 +837,7 @@ def regenerate_outfit(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper], outfit_ current_outfit = CommonOutfitUtils.get_current_outfit(sim_info) outfit_flags = OutfitFilterFlag.USE_EXISTING_IF_APPROPRIATE & OutfitFilterFlag.USE_VALID_FOR_LIVE_RANDOM tags = tuple() - from sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils + from s4ap.sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils if CommonSimGenderOptionUtils.prefers_menswear(sim_info): tags = (CommonGameTag.GENDER_APPROPRIATE_MALE,) elif CommonSimGenderOptionUtils.prefers_womenswear(sim_info): @@ -862,7 +862,7 @@ def regenerate_all_outfits(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper]) -> current_outfit = CommonOutfitUtils.get_current_outfit(sim_info) outfit_flags = OutfitFilterFlag.USE_EXISTING_IF_APPROPRIATE & OutfitFilterFlag.USE_VALID_FOR_LIVE_RANDOM tags = tuple() - from sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils + from s4ap.sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils if CommonSimGenderOptionUtils.prefers_menswear(sim_info): tags = (CommonGameTag.GENDER_APPROPRIATE_MALE,) elif CommonSimGenderOptionUtils.prefers_womenswear(sim_info): @@ -1105,7 +1105,7 @@ def get_outfit_tags_by_cas_part_id(cls, sim_info: Union[SimInfo, SimInfoBaseWrap @classmethod def _print_outfit(cls, sim_info: SimInfo, outfit_category: OutfitCategory, outfit_index: int, output: CommonConsoleCommandOutput): - from sims4communitylib.services.sim.cas.common_sim_outfit_io import CommonSimOutfitIO + from s4ap.sims4communitylib.services.sim.cas.common_sim_outfit_io import CommonSimOutfitIO if not isinstance(outfit_category, OutfitCategory): # noinspection PyBroadException try: @@ -1249,7 +1249,7 @@ def _s4clib_testing_print_outfit_tags(output: CommonConsoleCommandOutput, outfit ) ) def _s4clib_testing_print_outfit_tags_by_cas_part(output: CommonConsoleCommandOutput, outfit_category: str = None, outfit_index: int = 1, sim_info: SimInfo = None): - from sims4communitylib.utils.cas.common_cas_utils import CommonCASUtils + from s4ap.sims4communitylib.utils.cas.common_cas_utils import CommonCASUtils if sim_info is None: return outfit_category_and_index = CommonOutfitUtils._parse_outfit_category_and_index_from_str(output, outfit_category=outfit_category, outfit_index=outfit_index, sim_info=sim_info) diff --git a/Scripts/s4ap/sims4communitylib/utils/common_component_utils.py b/Scripts/s4ap/sims4communitylib/utils/common_component_utils.py index 5296100..4a6317c 100644 --- a/Scripts/s4ap/sims4communitylib/utils/common_component_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/common_component_utils.py @@ -8,7 +8,7 @@ from typing import Union, TypeVar, Type from objects.components import ComponentContainer, Component -from sims4communitylib.enums.types.component_types import CommonComponentType +from s4ap.sims4communitylib.enums.types.component_types import CommonComponentType CommonExpectedReturnType = TypeVar('CommonExpectedReturnType', bound=Component) diff --git a/Scripts/s4ap/sims4communitylib/utils/common_function_utils.py b/Scripts/s4ap/sims4communitylib/utils/common_function_utils.py index 5bf8ee1..d472345 100644 --- a/Scripts/s4ap/sims4communitylib/utils/common_function_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/common_function_utils.py @@ -7,11 +7,11 @@ """ from typing import Any, Callable, Iterator, Union -from sims4communitylib.classes.testing.common_enqueue_result import CommonEnqueueResult -from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.utils.common_log_registry import CommonLog +from s4ap.sims4communitylib.classes.testing.common_enqueue_result import CommonEnqueueResult +from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.utils.common_log_registry import CommonLog class CommonFunctionUtils: @@ -144,7 +144,7 @@ def safe_run(mod_identity: CommonModIdentity, primary_function: Callable[..., An except Exception as ex: # noinspection PyBroadException try: - from sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler + from s4ap.sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler CommonExceptionHandler.log_exception( mod_identity, f'Error occurred while running \'{primary_function.__name__}\'', diff --git a/Scripts/s4ap/sims4communitylib/utils/common_icon_utils.py b/Scripts/s4ap/sims4communitylib/utils/common_icon_utils.py index a9b5e66..bed6755 100644 --- a/Scripts/s4ap/sims4communitylib/utils/common_icon_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/common_icon_utils.py @@ -7,9 +7,9 @@ """ from typing import Any, Union from sims4.resources import Types -from sims4communitylib.enums.enumtypes.common_int import CommonInt -from sims4communitylib.enums.icons_enum import CommonIconId -from sims4communitylib.utils.common_resource_utils import CommonResourceUtils +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.icons_enum import CommonIconId +from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils class CommonIconUtils: diff --git a/Scripts/s4ap/sims4communitylib/utils/common_injection_utils.py b/Scripts/s4ap/sims4communitylib/utils/common_injection_utils.py index ea5582b..594924a 100644 --- a/Scripts/s4ap/sims4communitylib/utils/common_injection_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/common_injection_utils.py @@ -9,10 +9,10 @@ from functools import wraps from typing import Any, Callable, TYPE_CHECKING -from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity if TYPE_CHECKING: - from sims4communitylib.utils.common_log_registry import CommonLog + from s4ap.sims4communitylib.utils.common_log_registry import CommonLog ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' @@ -137,7 +137,7 @@ def _do_original(*_, **__): except Exception as ex: # noinspection PyBroadException try: - from sims4communitylib.exceptions.common_exceptions_handler import \ + from s4ap.sims4communitylib.exceptions.common_exceptions_handler import \ CommonExceptionHandler CommonExceptionHandler.log_exception(mod_identity, 'Error occurred while injecting into function \'{}\' of class \'{}\''.format(new_function.__name__, target_object.__name__), exception=ex) except Exception: @@ -153,7 +153,7 @@ def _wrapped_self_function(self, *args, **kwargs) -> Any: except Exception as ex: # noinspection PyBroadException try: - from sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler + from s4ap.sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler CommonExceptionHandler.log_exception(mod_identity, 'Error occurred while injecting into function \'{}\' of class \'{}\''.format(new_function.__name__, target_object.__name__), exception=ex) except Exception: pass @@ -170,7 +170,7 @@ def _wrapped_property_function(self, *args, **kwargs) -> Any: except Exception as ex: # noinspection PyBroadException try: - from sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler + from s4ap.sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler CommonExceptionHandler.log_exception(mod_identity, 'Error occurred while injecting into function \'{}\' of class \'{}\''.format(new_function.__name__, target_object.__name__), exception=ex) except Exception: pass @@ -193,7 +193,7 @@ def _do_original(*_, **__): except Exception as ex: # noinspection PyBroadException try: - from sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler + from s4ap.sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler CommonExceptionHandler.log_exception(mod_identity, 'Error occurred while injecting into function \'{}\' of class \'{}\''.format(new_function.__name__, target_object.__name__), exception=ex) except Exception: pass @@ -208,7 +208,7 @@ def _wrapped_other_function(*args, **kwargs) -> Any: except Exception as ex: # noinspection PyBroadException try: - from sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler + from s4ap.sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler CommonExceptionHandler.log_exception(mod_identity, 'Error occurred while injecting into function \'{}\' of class \'{}\''.format(new_function.__name__, target_object.__name__), exception=ex) except Exception: pass diff --git a/Scripts/s4ap/sims4communitylib/utils/common_json_io_utils.py b/Scripts/s4ap/sims4communitylib/utils/common_json_io_utils.py index 91e31e4..fb207b1 100644 --- a/Scripts/s4ap/sims4communitylib/utils/common_json_io_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/common_json_io_utils.py @@ -11,8 +11,8 @@ from os import DirEntry from typing import Union, Any, Iterator, Dict, Type, Callable -from sims4communitylib.classes.serialization.common_serializable import CommonSerializable -from sims4communitylib.utils.common_io_utils import CommonIOUtils +from s4ap.sims4communitylib.classes.serialization.common_serializable import CommonSerializable +from s4ap.sims4communitylib.utils.common_io_utils import CommonIOUtils class CommonJSONIOUtils: diff --git a/Scripts/s4ap/sims4communitylib/utils/common_keyboard_utils.py b/Scripts/s4ap/sims4communitylib/utils/common_keyboard_utils.py index 69877e8..213413b 100644 --- a/Scripts/s4ap/sims4communitylib/utils/common_keyboard_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/common_keyboard_utils.py @@ -7,10 +7,10 @@ """ import os -from sims4communitylib.enums.common_key import CommonKey -from sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.utils.common_log_registry import CommonLogRegistry +from s4ap.sims4communitylib.enums.common_key import CommonKey +from s4ap.sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.utils.common_log_registry import CommonLogRegistry log = CommonLogRegistry().register_log(ModInfo.get_identity(), 'common_keyboard_utils') # noinspection PyBroadException diff --git a/Scripts/s4ap/sims4communitylib/utils/common_log_registry.py b/Scripts/s4ap/sims4communitylib/utils/common_log_registry.py index e70cd7e..13682b9 100644 --- a/Scripts/s4ap/sims4communitylib/utils/common_log_registry.py +++ b/Scripts/s4ap/sims4communitylib/utils/common_log_registry.py @@ -9,13 +9,13 @@ from typing import List, Dict, Any, Union, Tuple, Iterator from pprint import pformat -from sims4communitylib.enums.enumtypes.common_int import CommonInt -from sims4communitylib.exceptions.common_stacktrace_utils import CommonStacktraceUtil -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.common_service import CommonService -from sims4communitylib.utils.common_io_utils import CommonIOUtils -from sims4communitylib.utils.common_log_utils import CommonLogUtils +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.exceptions.common_stacktrace_utils import CommonStacktraceUtil +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.common_service import CommonService +from s4ap.sims4communitylib.utils.common_io_utils import CommonIOUtils +from s4ap.sims4communitylib.utils.common_log_utils import CommonLogUtils _log = None @@ -45,7 +45,7 @@ class CommonLog: """ def __init__(self, mod_identifier: Union[str, CommonModIdentity], log_name: str, custom_file_path: str = None): self._log_name = log_name - from sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils + from s4ap.sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils self._mod_name = CommonModIdentityUtils.determine_mod_name_from_identifier(mod_identifier) self._custom_file_path = custom_file_path self._enabled_message_types = tuple() @@ -451,12 +451,12 @@ def is_enabled(self, message_type: CommonMessageType) -> bool: return message_type in self._enabled_message_types def _log_message(self, message_type: CommonMessageType, message: str): - from sims4communitylib.utils.common_date_utils import CommonRealDateUtils - from sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler + from s4ap.sims4communitylib.utils.common_date_utils import CommonRealDateUtils + from s4ap.sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler current_date_time = CommonRealDateUtils.get_current_date_string() new_message = '{} {}: [{}]: {}\n'.format(current_date_time, getattr(message_type, 'name', str(message_type)), self.name, message) try: - from sims4communitylib.utils.common_io_utils import CommonIOUtils + from s4ap.sims4communitylib.utils.common_io_utils import CommonIOUtils file_path = self.messages_file_path os.makedirs(os.path.dirname(file_path), exist_ok=True) CommonIOUtils.write_to_file(file_path, new_message, ignore_errors=True) @@ -464,8 +464,8 @@ def _log_message(self, message_type: CommonMessageType, message: str): CommonExceptionHandler.log_exception(self.mod_name, 'Error occurred while attempting to log message: {}'.format(pformat(message)), exception=ex, custom_file_path=self._custom_file_path) def _log_error(self, message: str, exception: Exception = None, stack_trace: List[str] = None): - from sims4communitylib.utils.common_date_utils import CommonRealDateUtils - from sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler + from s4ap.sims4communitylib.utils.common_date_utils import CommonRealDateUtils + from s4ap.sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler try: exceptions = stack_trace or CommonStacktraceUtil.get_full_stack_trace() if exception is not None: @@ -484,9 +484,9 @@ def _log_error(self, message: str, exception: Exception = None, stack_trace: Lis def _update_args(self, *args: Any) -> Tuple[Any]: if not args: return args - from sims4communitylib.utils.common_type_utils import CommonTypeUtils - from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils - from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils + from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils + from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils new_args: List[Any] = list() for arg in args: if CommonTypeUtils.is_sim_or_sim_info(arg) or CommonTypeUtils.is_sim_info_base_wrapper(arg): @@ -498,7 +498,7 @@ def _update_args(self, *args: Any) -> Tuple[Any]: elif CommonTypeUtils.is_sim_info_base_wrapper(arg): obj_type_acronym = 'SIBW' if self._should_log_extra_sim_details: - from sims4communitylib.utils.sims.common_sim_type_utils import CommonSimTypeUtils + from s4ap.sims4communitylib.utils.sims.common_sim_type_utils import CommonSimTypeUtils sim_info = CommonSimUtils.get_sim_info(arg) sim_types = tuple(CommonSimTypeUtils.get_all_sim_types_gen(sim_info, combine_teen_young_adult_and_elder_age=False, combine_child_dog_types=False)) current_sim_type = CommonSimTypeUtils.determine_sim_type(sim_info, combine_teen_young_adult_and_elder_age=False, combine_child_dog_types=False, use_current_occult_type=True) @@ -513,9 +513,9 @@ def _update_kwargs(self, **kwargs: Any) -> Dict[str, Any]: if not kwargs: return kwargs new_kwargs: Dict[str, Any] = dict() - from sims4communitylib.utils.common_type_utils import CommonTypeUtils - from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils - from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils + from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils + from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils for (key, val) in kwargs.items(): if CommonTypeUtils.is_sim_or_sim_info(val) or CommonTypeUtils.is_sim_info_base_wrapper(val): obj_type_acronym = 'UnknownType' @@ -527,7 +527,7 @@ def _update_kwargs(self, **kwargs: Any) -> Dict[str, Any]: obj_type_acronym = 'SIBW' if self._should_log_extra_sim_details: - from sims4communitylib.utils.sims.common_sim_type_utils import CommonSimTypeUtils + from s4ap.sims4communitylib.utils.sims.common_sim_type_utils import CommonSimTypeUtils sim_info = CommonSimUtils.get_sim_info(val) sim_types = tuple(CommonSimTypeUtils.get_all_sim_types_gen(sim_info, combine_teen_young_adult_and_elder_age=False, combine_child_dog_types=False)) current_sim_type = CommonSimTypeUtils.determine_sim_type(sim_info, combine_teen_young_adult_and_elder_age=False, combine_child_dog_types=False, use_current_occult_type=True) @@ -631,7 +631,7 @@ def register_log(self, mod_identifier: Union[str, CommonModIdentity], log_name: if log_name in self._registered_logs[mod_name]: return self._registered_logs[mod_name][log_name] log = CommonLog(mod_identifier, log_name, custom_file_path=custom_file_path) - from sims4communitylib.s4cl_configuration import S4CLConfiguration + from s4ap.sims4communitylib.s4cl_configuration import S4CLConfiguration if log_name in S4CLConfiguration().enable_logs: log.enable(message_types=S4CLConfiguration().enable_logs[log_name]) self._registered_logs[mod_name][log_name] = log @@ -656,7 +656,7 @@ def register_log(self, mod_identifier: Union[str, CommonModIdentity], log_name: return log def _delete_old_log_files(self) -> None: - from sims4communitylib.utils.common_io_utils import CommonIOUtils + from s4ap.sims4communitylib.utils.common_io_utils import CommonIOUtils files_to_delete = ( os.path.join(CommonLogUtils.get_sims_documents_location_path(), 'mod_logs'), ) diff --git a/Scripts/s4ap/sims4communitylib/utils/common_log_utils.py b/Scripts/s4ap/sims4communitylib/utils/common_log_utils.py index 2ee2307..253385a 100644 --- a/Scripts/s4ap/sims4communitylib/utils/common_log_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/common_log_utils.py @@ -8,7 +8,7 @@ import os from typing import Union -from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity class CommonLogUtils: @@ -106,7 +106,7 @@ def get_sims_documents_location_path() -> str: documents_path = os.path.dirname(CommonLogUtils.get_mods_location_path()) if os.path.exists(documents_path): return documents_path - from sims4communitylib.modinfo import ModInfo + from s4ap.sims4communitylib.modinfo import ModInfo root_file = os.path.normpath(os.path.dirname(os.path.realpath(ModInfo.get_identity().file_path))).replace(os.sep, '/') root_file_split = root_file.split('/') if 'Mods' not in root_file_split: @@ -161,7 +161,7 @@ def get_mod_data_location_path() -> str: @staticmethod def _get_file_name(mod_identifier: Union[str, CommonModIdentity], file_name: str, custom_file_path: str=None) -> str: - from sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils + from s4ap.sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils mod_identifier = CommonModIdentityUtils.determine_mod_name_from_identifier(mod_identifier) file_path = CommonLogUtils.get_mod_logs_location_path() file_name = '{}_{}.txt'.format(mod_identifier, file_name) @@ -190,7 +190,7 @@ def _get_file_name(mod_identifier: Union[str, CommonModIdentity], file_name: str @staticmethod def _get_old_file_path_name(mod_identifier: Union[str, CommonModIdentity], file_name: str, custom_file_path: str=None) -> str: - from sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils + from s4ap.sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils mod_identifier = CommonModIdentityUtils.determine_mod_name_from_identifier(mod_identifier) file_path = CommonLogUtils.get_mod_logs_location_path() old_file_name = 'Old_{}_{}.txt'.format(mod_identifier, file_name) @@ -202,5 +202,5 @@ def _get_old_file_path_name(mod_identifier: Union[str, CommonModIdentity], file_ @staticmethod def _file_is_too_big(file_path: str) -> bool: - from sims4communitylib.s4cl_configuration import S4CLConfiguration + from s4ap.sims4communitylib.s4cl_configuration import S4CLConfiguration return os.path.getsize(file_path) > S4CLConfiguration().max_output_file_size_in_bytes diff --git a/Scripts/s4ap/sims4communitylib/utils/common_math_utils.py b/Scripts/s4ap/sims4communitylib/utils/common_math_utils.py index c7c91fb..59f63dc 100644 --- a/Scripts/s4ap/sims4communitylib/utils/common_math_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/common_math_utils.py @@ -8,7 +8,7 @@ import math import sims4.math as sims_math -from sims4communitylib.classes.math.common_vector3 import CommonVector3 +from s4ap.sims4communitylib.classes.math.common_vector3 import CommonVector3 class CommonMathUtils: diff --git a/Scripts/s4ap/sims4communitylib/utils/common_resource_utils.py b/Scripts/s4ap/sims4communitylib/utils/common_resource_utils.py index 792aee2..03d48db 100644 --- a/Scripts/s4ap/sims4communitylib/utils/common_resource_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/common_resource_utils.py @@ -49,10 +49,10 @@ class ETreeTuningLoader: class LoadingTags: pass -from sims4communitylib.classes.common_resource_key import CommonResourceKey -from sims4communitylib.enums.enumtypes.common_int import Int, CommonInt -from sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags -from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.classes.common_resource_key import CommonResourceKey +from s4ap.sims4communitylib.enums.enumtypes.common_int import Int, CommonInt +from s4ap.sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity CommonEnumTypeValueType = TypeVar('CommonEnumTypeValueType', int, CommonInt, CommonIntFlags, Int, DynamicEnum, DynamicEnumLocked) diff --git a/Scripts/s4ap/sims4communitylib/utils/common_time_utils.py b/Scripts/s4ap/sims4communitylib/utils/common_time_utils.py index 27dd17f..3703bf1 100644 --- a/Scripts/s4ap/sims4communitylib/utils/common_time_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/common_time_utils.py @@ -10,10 +10,10 @@ import services from clock import ClockSpeedMode, GameClock, ClockSpeedMultiplierType from date_and_time import DateAndTime, TimeSpan -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ CommonConsoleCommandArgument -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput from time_service import TimeService diff --git a/Scripts/s4ap/sims4communitylib/utils/common_type_utils.py b/Scripts/s4ap/sims4communitylib/utils/common_type_utils.py index d0e3427..cb1fc17 100644 --- a/Scripts/s4ap/sims4communitylib/utils/common_type_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/common_type_utils.py @@ -166,7 +166,7 @@ def is_swimming_pool(obj: Any) -> bool: :return: True, if it is. False, if it is not. :rtype: bool """ - from sims4communitylib.utils.objects.common_object_type_utils import CommonObjectTypeUtils + from s4ap.sims4communitylib.utils.objects.common_object_type_utils import CommonObjectTypeUtils return CommonObjectTypeUtils.is_swimming_pool(obj) @staticmethod @@ -180,7 +180,7 @@ def is_door(obj: Any) -> bool: :return: True, if it is. False, if it is not. :rtype: bool """ - from sims4communitylib.utils.objects.common_object_type_utils import CommonObjectTypeUtils + from s4ap.sims4communitylib.utils.objects.common_object_type_utils import CommonObjectTypeUtils return CommonObjectTypeUtils.is_door(obj) @staticmethod @@ -194,7 +194,7 @@ def is_location(obj: Any) -> bool: :return: True, if it is. False, if it is not. :rtype: bool """ - from sims4communitylib.classes.math.common_location import CommonLocation + from s4ap.sims4communitylib.classes.math.common_location import CommonLocation return isinstance(obj, Location) or isinstance(obj, CommonLocation) @staticmethod @@ -267,5 +267,5 @@ def is_pool_seat(obj: Any) -> bool: :return: True, if the Object is a Pool Seat. False, if not. :rtype: bool """ - from sims4communitylib.utils.objects.common_object_type_utils import CommonObjectTypeUtils + from s4ap.sims4communitylib.utils.objects.common_object_type_utils import CommonObjectTypeUtils return CommonObjectTypeUtils.is_swimming_pool_seat(obj) diff --git a/Scripts/s4ap/sims4communitylib/utils/common_weather_utils.py b/Scripts/s4ap/sims4communitylib/utils/common_weather_utils.py index 5baf403..71758e1 100644 --- a/Scripts/s4ap/sims4communitylib/utils/common_weather_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/common_weather_utils.py @@ -11,16 +11,16 @@ from server_commands.argument_helpers import TunableInstanceParam from sims.sim_info import SimInfo from sims4.resources import Types -from sims4communitylib.enums.common_cloud_type import CommonCloudType -from sims4communitylib.enums.common_temperature import CommonTemperature -from sims4communitylib.enums.common_weather_effect_type import CommonWeatherEffectType -from sims4communitylib.enums.common_weather_event_ids import CommonWeatherEventId -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ +from s4ap.sims4communitylib.enums.common_cloud_type import CommonCloudType +from s4ap.sims4communitylib.enums.common_temperature import CommonTemperature +from s4ap.sims4communitylib.enums.common_weather_effect_type import CommonWeatherEffectType +from s4ap.sims4communitylib.enums.common_weather_event_ids import CommonWeatherEventId +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ CommonConsoleCommandArgument -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.common_time_utils import CommonTimeUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.common_time_utils import CommonTimeUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils from weather.weather_enums import PrecipitationType, WeatherEffectType from weather.weather_event import WeatherEvent from weather.weather_service import WeatherService @@ -217,7 +217,7 @@ def load_weather_event_by_id(cls, weather_event: Union[int, CommonWeatherEventId return weather_event from sims4.resources import Types - from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils return CommonResourceUtils.load_instance(Types.WEATHER_EVENT, weather_event) diff --git a/Scripts/s4ap/sims4communitylib/utils/effects/common_visual_effect_commands.py b/Scripts/s4ap/sims4communitylib/utils/effects/common_visual_effect_commands.py index a4d048a..53824ce 100644 --- a/Scripts/s4ap/sims4communitylib/utils/effects/common_visual_effect_commands.py +++ b/Scripts/s4ap/sims4communitylib/utils/effects/common_visual_effect_commands.py @@ -11,17 +11,17 @@ from date_and_time import TimeSpan from objects.game_object import GameObject from sims.sim_info import SimInfo -from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from sims4communitylib.events.zone_spin.events.zone_teardown import S4CLZoneTeardownEvent -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommandArgument, \ +from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry +from s4ap.sims4communitylib.events.zone_spin.events.zone_teardown import S4CLZoneTeardownEvent +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommandArgument, \ CommonConsoleCommand -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.services.common_service import CommonService -from sims4communitylib.classes.effects.common_visual_effect import CommonVisualEffect -from sims4communitylib.utils.common_type_utils import CommonTypeUtils -from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.services.common_service import CommonService +from s4ap.sims4communitylib.classes.effects.common_visual_effect import CommonVisualEffect +from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils +from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils class _CommonVisualEffectCommandService(CommonService): diff --git a/Scripts/s4ap/sims4communitylib/utils/environment/common_business_utils.py b/Scripts/s4ap/sims4communitylib/utils/environment/common_business_utils.py index a4e77c9..1fe034b 100644 --- a/Scripts/s4ap/sims4communitylib/utils/environment/common_business_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/environment/common_business_utils.py @@ -23,7 +23,7 @@ def get_business_manager_for_current_zone(cls) -> BusinessManager: :return: A Business Manager for the current zone. :rtype: BusinessManager """ - from sims4communitylib.utils.location.common_location_utils import CommonLocationUtils + from s4ap.sims4communitylib.utils.location.common_location_utils import CommonLocationUtils return cls.get_business_manager_by_zone_id(CommonLocationUtils.get_current_zone_id()) @classmethod @@ -48,7 +48,7 @@ def get_business_funds_for_current_zone(cls) -> Union[BusinessFunds, None]: :return: The BusinessFunds object of the Business at the current Zone or None if the current Zone did not have a Business. :rtype: Union[BusinessFunds, None] """ - from sims4communitylib.utils.location.common_location_utils import CommonLocationUtils + from s4ap.sims4communitylib.utils.location.common_location_utils import CommonLocationUtils return cls.get_business_funds_by_zone_id(CommonLocationUtils.get_current_zone_id()) @classmethod diff --git a/Scripts/s4ap/sims4communitylib/utils/environment/common_civic_policy_utils.py b/Scripts/s4ap/sims4communitylib/utils/environment/common_civic_policy_utils.py index d408b68..083e537 100644 --- a/Scripts/s4ap/sims4communitylib/utils/environment/common_civic_policy_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/environment/common_civic_policy_utils.py @@ -10,14 +10,14 @@ from civic_policies.base_civic_policy import BaseCivicPolicy from civic_policies.street_civic_policy import StreetCivicPolicy from civic_policies.street_civic_policy_provider import StreetProvider -from sims4communitylib.enums.common_civic_policy_status_type import CommonCivicPolicyStatusType -from sims4communitylib.enums.common_street_civic_policy_ids import CommonStreetCivicPolicyId -from sims4communitylib.enums.common_venue_civic_policy_ids import CommonVenueCivicPolicyId -from sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.location.common_location_utils import CommonLocationUtils +from s4ap.sims4communitylib.enums.common_civic_policy_status_type import CommonCivicPolicyStatusType +from s4ap.sims4communitylib.enums.common_street_civic_policy_ids import CommonStreetCivicPolicyId +from s4ap.sims4communitylib.enums.common_venue_civic_policy_ids import CommonVenueCivicPolicyId +from s4ap.sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.location.common_location_utils import CommonLocationUtils from venues.civic_policies.venue_civic_policy import VenueCivicPolicy from venues.civic_policies.venue_civic_policy_provider import VenueCivicPolicyProvider @@ -379,7 +379,7 @@ def load_civic_policy_by_id(cls, policy: Union[int, CommonVenueCivicPolicyId, Co return policy from sims4.resources import Types - from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils return CommonResourceUtils.load_instance(Types.SNIPPET, policy) diff --git a/Scripts/s4ap/sims4communitylib/utils/localization/common_localization_utils.py b/Scripts/s4ap/sims4communitylib/utils/localization/common_localization_utils.py index 36dbc32..c1ac40e 100644 --- a/Scripts/s4ap/sims4communitylib/utils/localization/common_localization_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/localization/common_localization_utils.py @@ -10,9 +10,9 @@ from protocolbuffers.Localization_pb2 import LocalizedString from sims4.localization import LocalizationHelperTuning, _create_localized_string, create_tokens, \ TunableLocalizedStringFactory -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from sims4communitylib.utils.localization.common_localized_string_separators import CommonLocalizedStringSeparator +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor +from s4ap.sims4communitylib.utils.localization.common_localized_string_separators import CommonLocalizedStringSeparator class CommonLocalizationUtils: diff --git a/Scripts/s4ap/sims4communitylib/utils/localization/common_localized_string_colors.py b/Scripts/s4ap/sims4communitylib/utils/localization/common_localized_string_colors.py index ba8fd99..76bab68 100644 --- a/Scripts/s4ap/sims4communitylib/utils/localization/common_localized_string_colors.py +++ b/Scripts/s4ap/sims4communitylib/utils/localization/common_localized_string_colors.py @@ -5,8 +5,8 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt -from sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId class CommonLocalizedStringColor(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/utils/localization/common_localized_string_separators.py b/Scripts/s4ap/sims4communitylib/utils/localization/common_localized_string_separators.py index aa7ae18..dab62d5 100644 --- a/Scripts/s4ap/sims4communitylib/utils/localization/common_localized_string_separators.py +++ b/Scripts/s4ap/sims4communitylib/utils/localization/common_localized_string_separators.py @@ -5,8 +5,8 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.enums.enumtypes.common_int import CommonInt -from sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId class CommonLocalizedStringSeparator(CommonInt): diff --git a/Scripts/s4ap/sims4communitylib/utils/location/common_location_utils.py b/Scripts/s4ap/sims4communitylib/utils/location/common_location_utils.py index b46521a..ad43342 100644 --- a/Scripts/s4ap/sims4communitylib/utils/location/common_location_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/location/common_location_utils.py @@ -11,10 +11,10 @@ import build_buy from civic_policies.street_civic_policy_service import StreetService -from sims4communitylib.classes.math.common_location import CommonLocation -from sims4communitylib.classes.math.common_surface_identifier import CommonSurfaceIdentifier -from sims4communitylib.classes.math.common_vector3 import CommonVector3 -from sims4communitylib.enums.common_region_id import CommonRegionId +from s4ap.sims4communitylib.classes.math.common_location import CommonLocation +from s4ap.sims4communitylib.classes.math.common_surface_identifier import CommonSurfaceIdentifier +from s4ap.sims4communitylib.classes.math.common_vector3 import CommonVector3 +from s4ap.sims4communitylib.enums.common_region_id import CommonRegionId from world.region import Region from world.street import Street @@ -24,7 +24,7 @@ # noinspection SpellCheckingInspection _buildbuy = build_buy from sims4.resources import Types -from sims4communitylib.utils.common_resource_utils import CommonResourceUtils +from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils from venues.venue_tuning import Venue, VenueTypes from world.lot import Lot from zone import Zone @@ -124,7 +124,7 @@ def load_region_by_id(cls, region: Union[int, CommonRegionId, Region]) -> Union[ return region from sims4.resources import Types - from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils return CommonResourceUtils.load_instance(Types.REGION, region) @staticmethod @@ -472,7 +472,7 @@ def is_position_within_range_of_position(position_a: CommonVector3, position_b: :return: True, if the distance between Position A and Position B is less than or equal to the specified distance in squares. False, if not. :return: bool """ - from sims4communitylib.utils.common_math_utils import CommonMathUtils + from s4ap.sims4communitylib.utils.common_math_utils import CommonMathUtils distance_between_positions = CommonMathUtils.calculate_distance(position_a, position_b, flatten_positions=False) return distance_between_positions <= distance_in_squares @@ -683,7 +683,7 @@ def load_venue_by_guid(cls, venue: Union[int, Venue]) -> Union[Venue, None]: return venue from sims4.resources import Types - from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils return CommonResourceUtils.load_instance(Types.VENUE, venue) @classmethod diff --git a/Scripts/s4ap/sims4communitylib/utils/location/common_terrain_utils.py b/Scripts/s4ap/sims4communitylib/utils/location/common_terrain_utils.py index a3fe36e..e103846 100644 --- a/Scripts/s4ap/sims4communitylib/utils/location/common_terrain_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/location/common_terrain_utils.py @@ -6,9 +6,9 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.utils.terrain.common_terrain_location_utils import CommonTerrainLocationUtils as NewCommonTerrainLocationUtils +from s4ap.sims4communitylib.utils.terrain.common_terrain_location_utils import CommonTerrainLocationUtils as NewCommonTerrainLocationUtils class CommonTerrainUtils(NewCommonTerrainLocationUtils): - """An obsolete utility for manipulating terrain location. Use CommonTerrainLocationUtils from sims4communitylib.utils.terrain.common_terrain_location_utils instead.""" + """An obsolete utility for manipulating terrain location. Use CommonTerrainLocationUtils from s4ap.sims4communitylib.utils.terrain.common_terrain_location_utils instead.""" pass diff --git a/Scripts/s4ap/sims4communitylib/utils/location/common_travel_utils.py b/Scripts/s4ap/sims4communitylib/utils/location/common_travel_utils.py index e021320..987fa61 100644 --- a/Scripts/s4ap/sims4communitylib/utils/location/common_travel_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/location/common_travel_utils.py @@ -6,7 +6,7 @@ Copyright (c) COLONOLNUTTY """ from sims.sim_info import SimInfo -from sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils +from s4ap.sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils class CommonTravelUtils: diff --git a/Scripts/s4ap/sims4communitylib/utils/math/common_bitwise_utils.py b/Scripts/s4ap/sims4communitylib/utils/math/common_bitwise_utils.py index e3d9c89..162e2b7 100644 --- a/Scripts/s4ap/sims4communitylib/utils/math/common_bitwise_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/math/common_bitwise_utils.py @@ -7,8 +7,8 @@ """ from typing import Union, Tuple, TypeVar -from sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags -from sims4communitylib.utils.common_collection_utils import CommonCollectionUtils +from s4ap.sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags +from s4ap.sims4communitylib.utils.common_collection_utils import CommonCollectionUtils CommonEnumFlagsTypeValueType = TypeVar('CommonEnumFlagsTypeValueType', int, CommonIntFlags) diff --git a/Scripts/s4ap/sims4communitylib/utils/misc/common_camera_utils.py b/Scripts/s4ap/sims4communitylib/utils/misc/common_camera_utils.py index 3a8a606..7c04438 100644 --- a/Scripts/s4ap/sims4communitylib/utils/misc/common_camera_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/misc/common_camera_utils.py @@ -10,13 +10,13 @@ from objects.game_object import GameObject from server.client import Client from sims.sim_info import SimInfo -from sims4communitylib.classes.math.common_vector3 import CommonVector3 -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ +from s4ap.sims4communitylib.classes.math.common_vector3 import CommonVector3 +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ CommonConsoleCommandArgument -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.common_type_utils import CommonTypeUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils class CommonCameraUtils: diff --git a/Scripts/s4ap/sims4communitylib/utils/misc/common_fire_utils.py b/Scripts/s4ap/sims4communitylib/utils/misc/common_fire_utils.py index 8efe1a9..78bed94 100644 --- a/Scripts/s4ap/sims4communitylib/utils/misc/common_fire_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/misc/common_fire_utils.py @@ -10,7 +10,7 @@ from objects.fire.fire import Fire from objects.game_object import GameObject from services.fire_service import FireService -from sims4communitylib.classes.math.common_location import CommonLocation +from s4ap.sims4communitylib.classes.math.common_location import CommonLocation class CommonFireUtils: diff --git a/Scripts/s4ap/sims4communitylib/utils/misc/common_mod_identity_utils.py b/Scripts/s4ap/sims4communitylib/utils/misc/common_mod_identity_utils.py index efec4d1..f7f18eb 100644 --- a/Scripts/s4ap/sims4communitylib/utils/misc/common_mod_identity_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/misc/common_mod_identity_utils.py @@ -8,7 +8,7 @@ from typing import Union, TYPE_CHECKING if TYPE_CHECKING: - from sims4communitylib.mod_support.mod_identity import CommonModIdentity + from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity class CommonModIdentityUtils: @@ -27,7 +27,7 @@ def determine_mod_name_from_identifier(cls, identifier: Union[str, 'CommonModIde :return: The name of the Mod or 'Unknown_Mod' if the name could not be determined. :rtype: str """ - from sims4communitylib.mod_support.mod_identity import CommonModIdentity + from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity if identifier is None: return 'Unknown_Mod' if isinstance(identifier, CommonModIdentity): diff --git a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_household_utils.py b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_household_utils.py index 941dad3..dea711d 100644 --- a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_household_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_household_utils.py @@ -27,7 +27,7 @@ def set_owning_household_id(game_object: GameObject, household_id: int) -> bool: :return: True, if the Household was successfully set as the owner. False, if not. :rtype: bool """ - from sims4communitylib.utils.objects.common_object_ownership_utils import CommonObjectOwnershipUtils + from s4ap.sims4communitylib.utils.objects.common_object_ownership_utils import CommonObjectOwnershipUtils return CommonObjectOwnershipUtils.set_owning_household_id(game_object, household_id) @staticmethod @@ -43,5 +43,5 @@ def get_owning_household_id(game_object: GameObject) -> int: :return: The decimal identifier of the Household that owns the object. :rtype: int """ - from sims4communitylib.utils.objects.common_object_ownership_utils import CommonObjectOwnershipUtils + from s4ap.sims4communitylib.utils.objects.common_object_ownership_utils import CommonObjectOwnershipUtils return CommonObjectOwnershipUtils.get_owning_household_id(game_object) diff --git a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_interaction_utils.py b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_interaction_utils.py index 4a3865f..bebcd60 100644 --- a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_interaction_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_interaction_utils.py @@ -10,19 +10,19 @@ from interactions.base.interaction import Interaction from objects.game_object import GameObject from objects.script_object import ScriptObject -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.logging.has_class_log import HasClassLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.logging.has_class_log import HasClassLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.notifications.common_basic_notification import CommonBasicNotification +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ CommonConsoleCommandArgument -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.common_log_utils import CommonLogUtils -from sims4communitylib.utils.common_type_utils import CommonTypeUtils -from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils -from sims4communitylib.utils.resources.common_interaction_utils import CommonInteractionUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.common_log_utils import CommonLogUtils +from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils +from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils +from s4ap.sims4communitylib.utils.resources.common_interaction_utils import CommonInteractionUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils class CommonObjectInteractionUtils(HasClassLog): diff --git a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_inventory_utils.py b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_inventory_utils.py index cae831d..b66c87b 100644 --- a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_inventory_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_inventory_utils.py @@ -10,11 +10,11 @@ from objects.components.object_inventory_component import ObjectInventoryComponent from objects.game_object import GameObject from sims.sim_info import SimInfo -from sims4communitylib.classes.math.common_location import CommonLocation -from sims4communitylib.enums.types.component_types import CommonComponentType -from sims4communitylib.utils.common_component_utils import CommonComponentUtils -from sims4communitylib.utils.objects.common_object_spawn_utils import CommonObjectSpawnUtils -from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils +from s4ap.sims4communitylib.classes.math.common_location import CommonLocation +from s4ap.sims4communitylib.enums.types.component_types import CommonComponentType +from s4ap.sims4communitylib.utils.common_component_utils import CommonComponentUtils +from s4ap.sims4communitylib.utils.objects.common_object_spawn_utils import CommonObjectSpawnUtils +from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils class CommonObjectInventoryUtils: @@ -74,7 +74,7 @@ def move_object_to_inventory(game_object_container: GameObject, game_object_to_m inventory_component = CommonObjectInventoryUtils._get_inventory(game_object_container) if inventory_component is None: return False - from sims4communitylib.utils.objects.common_object_ownership_utils import CommonObjectOwnershipUtils + from s4ap.sims4communitylib.utils.objects.common_object_ownership_utils import CommonObjectOwnershipUtils CommonObjectOwnershipUtils.set_owning_household_id(game_object_to_move, CommonObjectOwnershipUtils.get_owning_household_id(game_object_container)) return inventory_component.player_try_add_object(game_object_to_move) @@ -204,7 +204,7 @@ def set_ownership_of_all_items_in_object_inventory_to_sim(game_object: GameObjec if inventory_component is None: return False - from sims4communitylib.utils.objects.common_object_ownership_utils import CommonObjectOwnershipUtils + from s4ap.sims4communitylib.utils.objects.common_object_ownership_utils import CommonObjectOwnershipUtils for inventory_object in inventory_component: CommonObjectOwnershipUtils.set_owning_sim(inventory_object, sim_info) return True diff --git a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_location_utils.py b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_location_utils.py index 5b0184a..536e582 100644 --- a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_location_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_location_utils.py @@ -9,19 +9,19 @@ from typing import Union from objects.components.live_drag_component import LiveDragComponent from sims.sim_info import SimInfo -from sims4communitylib.classes.math.common_location import CommonLocation -from sims4communitylib.classes.math.common_quaternion import CommonQuaternion -from sims4communitylib.classes.math.common_surface_identifier import CommonSurfaceIdentifier -from sims4communitylib.classes.math.common_vector3 import CommonVector3 -from sims4communitylib.enums.types.component_types import CommonComponentType -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ +from s4ap.sims4communitylib.classes.math.common_location import CommonLocation +from s4ap.sims4communitylib.classes.math.common_quaternion import CommonQuaternion +from s4ap.sims4communitylib.classes.math.common_surface_identifier import CommonSurfaceIdentifier +from s4ap.sims4communitylib.classes.math.common_vector3 import CommonVector3 +from s4ap.sims4communitylib.enums.types.component_types import CommonComponentType +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ CommonConsoleCommandArgument -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.common_component_utils import CommonComponentUtils -from sims4communitylib.utils.location.common_location_utils import CommonLocationUtils -from sims4communitylib.utils.objects.common_object_type_utils import CommonObjectTypeUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.common_component_utils import CommonComponentUtils +from s4ap.sims4communitylib.utils.location.common_location_utils import CommonLocationUtils +from s4ap.sims4communitylib.utils.objects.common_object_type_utils import CommonObjectTypeUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils from world.lot import Lot @@ -354,7 +354,7 @@ def _common_move_object_to_sim(output: CommonConsoleCommandOutput, game_object: output('ERROR: No object was specified or the specified Game Object was not found.') return output(f'Attempting to move object {game_object} to Sim {sim_info}.') - from sims4communitylib.utils.sims.common_sim_location_utils import CommonSimLocationUtils + from s4ap.sims4communitylib.utils.sims.common_sim_location_utils import CommonSimLocationUtils if CommonObjectLocationUtils.set_location(game_object, CommonSimLocationUtils.get_location(sim_info)): output(f'SUCCESS: Object {game_object} was moved successfully to Sim {sim_info}.') else: diff --git a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_lock_utils.py b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_lock_utils.py index 2779db3..1c5f685 100644 --- a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_lock_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_lock_utils.py @@ -13,10 +13,10 @@ from objects.doors.door import Door from objects.game_object import GameObject from sims.sim_info import SimInfo -from sims4communitylib.enums.types.component_types import CommonComponentType -from sims4communitylib.utils.common_component_utils import CommonComponentUtils -from sims4communitylib.utils.common_type_utils import CommonTypeUtils -from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils +from s4ap.sims4communitylib.enums.types.component_types import CommonComponentType +from s4ap.sims4communitylib.utils.common_component_utils import CommonComponentUtils +from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils +from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils class CommonObjectLockUtils: diff --git a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_ownership_utils.py b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_ownership_utils.py index 89d9621..10bbedf 100644 --- a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_ownership_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_ownership_utils.py @@ -10,11 +10,11 @@ from objects.components.ownable_component import OwnableComponent from objects.game_object import GameObject from sims.sim_info import SimInfo -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ CommonConsoleCommandArgument -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils class CommonObjectOwnershipUtils: diff --git a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_reservation_utils.py b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_reservation_utils.py index 337ade5..2803658 100644 --- a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_reservation_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_reservation_utils.py @@ -14,11 +14,11 @@ from reservation.reservation_handler import _ReservationHandler from reservation.reservation_result import ReservationResult from sims.sim_info import SimInfo -from sims4communitylib.enums.common_slot_type import CommonSlotType -from sims4communitylib.enums.types.component_types import CommonComponentType -from sims4communitylib.utils.common_component_utils import CommonComponentUtils -from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.enums.common_slot_type import CommonSlotType +from s4ap.sims4communitylib.enums.types.component_types import CommonComponentType +from s4ap.sims4communitylib.utils.common_component_utils import CommonComponentUtils +from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils class CommonObjectReservationUtils: @@ -53,7 +53,7 @@ def is_in_use_by(game_object: GameObject, sim_info: SimInfo) -> bool: """ if game_object is None: return False - from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils sim = CommonSimUtils.get_sim_instance(sim_info) if sim is None: return False @@ -70,7 +70,7 @@ def get_sims_using_object(game_object: GameObject) -> Tuple[SimInfo]: :return: A collection of Sims using the object. :rtype: Tuple[SimInfo] """ - from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils if game_object is None: return tuple() sim_info_user_list: List[SimInfo] = [] diff --git a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_slot_utils.py b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_slot_utils.py index 8268d63..823f2e2 100644 --- a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_slot_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_slot_utils.py @@ -12,13 +12,13 @@ from objects.game_object import GameObject from objects.script_object import ScriptObject from objects.slots import SlotType -from sims4communitylib.dtos.common_object_containment_slot import CommonObjectContainmentSlot -from sims4communitylib.enums.common_slot_type import CommonSlotType -from sims4communitylib.enums.types.component_types import CommonComponentType -from sims4communitylib.utils.common_component_utils import CommonComponentUtils -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.dtos.common_object_containment_slot import CommonObjectContainmentSlot +from s4ap.sims4communitylib.enums.common_slot_type import CommonSlotType +from s4ap.sims4communitylib.enums.types.component_types import CommonComponentType +from s4ap.sims4communitylib.utils.common_component_utils import CommonComponentUtils +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils +from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils class CommonObjectSlotUtils: diff --git a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_spawn_utils.py b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_spawn_utils.py index 505a3a6..8de2aa2 100644 --- a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_spawn_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_spawn_utils.py @@ -9,19 +9,19 @@ from objects.object_enums import ItemLocation from sims.sim_info import SimInfo from typing import Any, Callable, Union, Tuple, Iterator -from sims4communitylib.classes.math.common_location import CommonLocation -from sims4communitylib.classes.math.common_transform import CommonTransform -from sims4communitylib.classes.math.common_vector3 import CommonVector3 -from sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog -from sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.classes.math.common_location import CommonLocation +from s4ap.sims4communitylib.classes.math.common_transform import CommonTransform +from s4ap.sims4communitylib.classes.math.common_vector3 import CommonVector3 +from s4ap.sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog +from s4ap.sims4communitylib.modinfo import ModInfo from carry.carry_postures import CarryingObject from objects.game_object import GameObject from objects.object_enums import ResetReason -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ CommonConsoleCommandArgument -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.objects.common_object_ownership_utils import CommonObjectOwnershipUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.objects.common_object_ownership_utils import CommonObjectOwnershipUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils class CommonObjectSpawnUtils(_HasS4CLClassLog): @@ -103,7 +103,7 @@ def spawn_object_on_lot( :return: An instance of the spawned Object or None if not successfully spawned. :rtype: GameObject """ - from sims4communitylib.utils.objects.common_object_location_utils import CommonObjectLocationUtils + from s4ap.sims4communitylib.utils.objects.common_object_location_utils import CommonObjectLocationUtils game_object = cls.create_object( object_definition_id, on_object_initialize_callback=on_object_initialize_callback, @@ -206,15 +206,15 @@ def destroy_object(cls, game_object: GameObject, source: Any = None, cause: str if inventory is None or inventory.owner is None: game_object.destroy(source=source, cause=cause, **kwargs) else: - from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils + from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils object_id = CommonObjectUtils.get_object_id(game_object) if game_object.is_in_sim_inventory(): sim_info = CommonSimUtils.get_sim_info(inventory.owner) - from sims4communitylib.utils.sims.common_sim_inventory_utils import CommonSimInventoryUtils + from s4ap.sims4communitylib.utils.sims.common_sim_inventory_utils import CommonSimInventoryUtils CommonSimInventoryUtils.remove_from_inventory(sim_info, object_id, count=1) else: inventory_game_object = CommonObjectUtils.get_game_object(inventory.owner) - from sims4communitylib.utils.objects.common_object_inventory_utils import CommonObjectInventoryUtils + from s4ap.sims4communitylib.utils.objects.common_object_inventory_utils import CommonObjectInventoryUtils CommonObjectInventoryUtils.remove_from_inventory_by_id(inventory_game_object, object_id, count=1) else: game_object.destroy(source=source, cause=cause, **kwargs) @@ -244,15 +244,15 @@ def schedule_object_for_destroy(cls, game_object: GameObject, source: Any = None if inventory is None or inventory.owner is None: game_object.schedule_destroy_asap(post_delete_func=on_destroyed, source=source, cause=cause, **kwargs) else: - from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils + from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils object_id = CommonObjectUtils.get_object_id(game_object) if game_object.is_in_sim_inventory(): sim_info = CommonSimUtils.get_sim_info(inventory.owner) - from sims4communitylib.utils.sims.common_sim_inventory_utils import CommonSimInventoryUtils + from s4ap.sims4communitylib.utils.sims.common_sim_inventory_utils import CommonSimInventoryUtils CommonSimInventoryUtils.remove_from_inventory(sim_info, object_id, count=1) else: inventory_game_object = CommonObjectUtils.get_game_object(inventory.owner) - from sims4communitylib.utils.objects.common_object_inventory_utils import CommonObjectInventoryUtils + from s4ap.sims4communitylib.utils.objects.common_object_inventory_utils import CommonObjectInventoryUtils CommonObjectInventoryUtils.remove_from_inventory_by_id(inventory_game_object, object_id, count=1) else: game_object.schedule_destroy_asap(post_delete_func=on_destroyed, source=source, cause=cause, **kwargs) @@ -392,8 +392,8 @@ def _common_spawn_object(output: CommonConsoleCommandOutput, object_definition_i output('ERROR: object_definition_id must be a positive number above zero.') return output('Attempting to spawn object on the current lot with id \'{}\'.'.format(object_definition_id)) - from sims4communitylib.utils.sims.common_sim_location_utils import CommonSimLocationUtils - from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils + from s4ap.sims4communitylib.utils.sims.common_sim_location_utils import CommonSimLocationUtils + from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils sim_location = CommonSimLocationUtils.get_location(sim_info) game_object = CommonObjectSpawnUtils.spawn_object_on_lot(object_definition_id, sim_location) if game_object is not None: @@ -402,7 +402,7 @@ def _common_spawn_object(output: CommonConsoleCommandOutput, object_definition_i CommonObjectSpawnUtils.get_log().debug(f'Object {game_object} spawned successfully. Can you see it? Object Id: {game_object_id}') CommonObjectSpawnUtils.get_log().disable() output(f'SUCCESS: Object {game_object} spawned successfully. Can you see it? Object Id: {game_object_id}') - from sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils + from s4ap.sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils CommonObjectOwnershipUtils.set_owning_household_id(game_object, CommonHouseholdUtils.get_household_id(sim_info)) else: output(f'ERROR: Failed to spawn object with definition id {object_definition_id}.') diff --git a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_state_utils.py b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_state_utils.py index 5f38374..b8b1e5e 100644 --- a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_state_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_state_utils.py @@ -13,20 +13,20 @@ from objects.game_object import GameObject from server_commands.argument_helpers import TunableInstanceParam from sims4.resources import Types -from sims4communitylib.enums.common_object_state_ids import CommonObjectStateId -from sims4communitylib.enums.common_object_state_value_ids import CommonObjectStateValueId -from sims4communitylib.enums.common_object_quality import CommonObjectQuality -from sims4communitylib.enums.statistics_enum import CommonStatisticId -from sims4communitylib.enums.types.component_types import CommonComponentType -from sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ +from s4ap.sims4communitylib.enums.common_object_state_ids import CommonObjectStateId +from s4ap.sims4communitylib.enums.common_object_state_value_ids import CommonObjectStateValueId +from s4ap.sims4communitylib.enums.common_object_quality import CommonObjectQuality +from s4ap.sims4communitylib.enums.statistics_enum import CommonStatisticId +from s4ap.sims4communitylib.enums.types.component_types import CommonComponentType +from s4ap.sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ CommonConsoleCommandArgument -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.common_component_utils import CommonComponentUtils -from sims4communitylib.utils.common_resource_utils import CommonResourceUtils -from sims4communitylib.utils.common_type_utils import CommonTypeUtils +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.common_component_utils import CommonComponentUtils +from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils +from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils from statistics.commodity import Commodity from statistics.commodity_tracker import CommodityTracker @@ -638,7 +638,7 @@ def load_object_state_by_id(cls, object_state: Union[int, CommonObjectStateId, O return object_state from sims4.resources import Types - from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils result = CommonResourceUtils.load_instance(Types.OBJECT_STATE, object_state) return result @@ -664,7 +664,7 @@ def load_object_state_value_by_id(cls, object_state_value: Union[int, CommonObje return object_state_value from sims4.resources import Types - from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils result = CommonResourceUtils.load_instance(Types.OBJECT_STATE, object_state_value) return result @@ -729,6 +729,6 @@ def _common_set_object_state(output: CommonConsoleCommandOutput, game_object: Ga ) def _common_modify_object_state(output: CommonConsoleCommandOutput, game_object: GameObject) -> bool: output(f'Opening dialog to modify object state of {game_object}.') - from sims4communitylib.debug.dialogs.common_change_object_state_dialog import CommonChangeObjectStateDialog + from s4ap.sims4communitylib.debug.dialogs.common_change_object_state_dialog import CommonChangeObjectStateDialog CommonChangeObjectStateDialog(game_object).open() return True diff --git a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_tag_utils.py b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_tag_utils.py index 6dc7c2f..d96e832 100644 --- a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_tag_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_tag_utils.py @@ -10,15 +10,15 @@ from typing import Tuple, Set, Union, Iterator, List from objects.script_object import ScriptObject -from sims4communitylib.enums.tags_enum import CommonGameTag -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ +from s4ap.sims4communitylib.enums.tags_enum import CommonGameTag +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.notifications.common_basic_notification import CommonBasicNotification +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ CommonConsoleCommandArgument -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.common_log_registry import CommonLogRegistry -from sims4communitylib.utils.common_resource_utils import CommonResourceUtils -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.common_log_registry import CommonLogRegistry +from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils class CommonObjectTagUtils: @@ -130,7 +130,7 @@ def _print_game_tags(cls, game_object: Union[GameObject, ScriptObject]) -> None: obj_tag_list_names = ',\n'.join(obj_tags_list) text = '' text += f'Game Tags:\n{obj_tag_list_names}\n\n' - from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils + from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils game_object_id = CommonObjectUtils.get_object_id(game_object) log.debug(f'Object {game_object} Tags ({game_object_id})') log.debug(text) diff --git a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_type_utils.py b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_type_utils.py index dea34cf..d053a5a 100644 --- a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_type_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_type_utils.py @@ -8,8 +8,8 @@ from objects.game_object import GameObject from objects.pools.pool import SwimmingPool from objects.pools.pool_seat import PoolSeat -from sims4communitylib.enums.tags_enum import CommonGameTag -from sims4communitylib.utils.objects.common_object_tag_utils import CommonObjectTagUtils +from s4ap.sims4communitylib.enums.tags_enum import CommonGameTag +from s4ap.sims4communitylib.utils.objects.common_object_tag_utils import CommonObjectTagUtils class CommonObjectTypeUtils: @@ -27,8 +27,8 @@ def is_window(game_object: GameObject) -> bool: """ if not isinstance(game_object, GameObject): return False - from sims4communitylib.enums.tags_enum import CommonGameTag - from sims4communitylib.utils.objects.common_object_tag_utils import CommonObjectTagUtils + from s4ap.sims4communitylib.enums.tags_enum import CommonGameTag + from s4ap.sims4communitylib.utils.objects.common_object_tag_utils import CommonObjectTagUtils return CommonObjectTagUtils.has_game_tags(game_object, (CommonGameTag.BUILD_WINDOW, )) @staticmethod diff --git a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_utils.py b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_utils.py index fc50d24..a14c3ee 100644 --- a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_utils.py @@ -12,11 +12,11 @@ from objects.game_object import GameObject from objects.object_manager import ObjectManager from objects.script_object import ScriptObject -from sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils class CommonObjectUtils(_HasS4CLClassLog): @@ -297,9 +297,9 @@ def _s4cl_testing_log_all_objects(output: CommonConsoleCommandOutput): all_objects_str_list = list() for game_object in CommonObjectUtils.get_instance_for_all_game_objects_generator(): object_id = CommonObjectUtils.get_object_id(game_object) - from sims4communitylib.utils.objects.common_object_location_utils import CommonObjectLocationUtils + from s4ap.sims4communitylib.utils.objects.common_object_location_utils import CommonObjectLocationUtils object_location = CommonObjectLocationUtils.get_location(game_object) - from sims4communitylib.utils.common_type_utils import CommonTypeUtils + from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils if CommonTypeUtils.is_sim_or_sim_info(game_object): all_objects_str_list.append(f'Sim {game_object} ({object_id}): Loc: {object_location}') else: diff --git a/Scripts/s4ap/sims4communitylib/utils/resources/common_club_utils.py b/Scripts/s4ap/sims4communitylib/utils/resources/common_club_utils.py index 6117f03..8acc828 100644 --- a/Scripts/s4ap/sims4communitylib/utils/resources/common_club_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/resources/common_club_utils.py @@ -11,7 +11,7 @@ from clubs.club import Club from clubs.club_tuning import ClubRule from sims.sim_info import SimInfo -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils class CommonClubUtils: @@ -50,7 +50,7 @@ def get_club_members_gen(club: Club, include_club_member_callback: Callable[[Sim :return: An iterator of all Sims in a Club that pass the include callback filter. :rtype: Iterator[SimInfo] """ - from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils for member_sim in club.members: sim_info = CommonSimUtils.get_sim_info(member_sim) if not include_club_member_callback(sim_info): diff --git a/Scripts/s4ap/sims4communitylib/utils/resources/common_interaction_utils.py b/Scripts/s4ap/sims4communitylib/utils/resources/common_interaction_utils.py index 54ce385..2e69c45 100644 --- a/Scripts/s4ap/sims4communitylib/utils/resources/common_interaction_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/resources/common_interaction_utils.py @@ -17,12 +17,12 @@ from interactions.social.social_super_interaction import SocialSuperInteraction from protocolbuffers.Localization_pb2 import LocalizedString from server.pick_info import PickInfo -from sims4communitylib.classes.math.common_surface_identifier import CommonSurfaceIdentifier -from sims4communitylib.classes.math.common_vector3 import CommonVector3 -from sims4communitylib.enums.interactions_enum import CommonInteractionId -from sims4communitylib.enums.tags_enum import CommonGameTag -from sims4communitylib.utils.common_resource_utils import CommonResourceUtils -from sims4communitylib.utils.location.common_location_utils import CommonLocationUtils +from s4ap.sims4communitylib.classes.math.common_surface_identifier import CommonSurfaceIdentifier +from s4ap.sims4communitylib.classes.math.common_vector3 import CommonVector3 +from s4ap.sims4communitylib.enums.interactions_enum import CommonInteractionId +from s4ap.sims4communitylib.enums.tags_enum import CommonGameTag +from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils +from s4ap.sims4communitylib.utils.location.common_location_utils import CommonLocationUtils from tag import Tag @@ -325,7 +325,7 @@ def get_interaction_display_name(interaction: Interaction, 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 + from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils if interaction is None or interaction.display_name is None: return None display_name_string_id = interaction.display_name._string_id @@ -416,7 +416,7 @@ def load_interaction_by_id(interaction_id: Union[int, CommonInteractionId, Inter return interaction_id from sims4.resources import Types - from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils return CommonResourceUtils.load_instance(Types.INTERACTION, interaction_id) @staticmethod @@ -429,6 +429,6 @@ def get_instance_manager() -> InteractionInstanceManager: :rtype: InteractionInstanceManager """ from sims4.resources import Types - from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils # noinspection PyTypeChecker return CommonResourceUtils.get_instance_manager(Types.INTERACTION) diff --git a/Scripts/s4ap/sims4communitylib/utils/resources/common_loot_action_utils.py b/Scripts/s4ap/sims4communitylib/utils/resources/common_loot_action_utils.py index 8c5f573..e75cb3a 100644 --- a/Scripts/s4ap/sims4communitylib/utils/resources/common_loot_action_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/resources/common_loot_action_utils.py @@ -101,5 +101,5 @@ def load_loot_actions_by_id(loot_actions_id: Union[int, LootActions]) -> Union[L return loot_actions_id from sims4.resources import Types - from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils return CommonResourceUtils.load_instance(Types.ACTION, loot_actions_id) diff --git a/Scripts/s4ap/sims4communitylib/utils/resources/common_recipe_utils.py b/Scripts/s4ap/sims4communitylib/utils/resources/common_recipe_utils.py index 6e67c70..0648982 100644 --- a/Scripts/s4ap/sims4communitylib/utils/resources/common_recipe_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/resources/common_recipe_utils.py @@ -9,7 +9,7 @@ from typing import Callable, Iterator, Union, Tuple, List from sims4.resources import Types -from sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog +from s4ap.sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog class CommonRecipeUtils(_HasS4CLClassLog): @@ -92,7 +92,7 @@ def get_all_recipes_gen(include_recipe_callback: Callable[[Recipe], bool] = None :return: An iterator of Recipes that pass the specified include_recipe_callback. :rtype: Iterator[Recipe] """ - from sims4communitylib.utils.resources.common_statistic_utils import CommonStatisticUtils + from s4ap.sims4communitylib.utils.resources.common_statistic_utils import CommonStatisticUtils statistic_manager = CommonStatisticUtils.get_statistic_instance_manager() for recipe in statistic_manager.get_ordered_types(only_subclasses_of=Recipe): recipe: Recipe = recipe @@ -124,5 +124,5 @@ def load_recipe_by_guid(value_id: Union[int, Recipe]) -> Union[Recipe, None]: value_id: Recipe = value_id return value_id - from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils return CommonResourceUtils.load_instance(Types.RECIPE, value_id) diff --git a/Scripts/s4ap/sims4communitylib/utils/resources/common_situation_utils.py b/Scripts/s4ap/sims4communitylib/utils/resources/common_situation_utils.py index 3d42d6d..b808191 100644 --- a/Scripts/s4ap/sims4communitylib/utils/resources/common_situation_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/resources/common_situation_utils.py @@ -9,9 +9,9 @@ import services from sims.sim_info import SimInfo -from sims4communitylib.enums.situations_enum import CommonSituationId -from sims4communitylib.enums.tags_enum import CommonGameTag -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.enums.situations_enum import CommonSituationId +from s4ap.sims4communitylib.enums.tags_enum import CommonGameTag +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils from situations.situation import Situation from situations.situation_job import SituationJob from situations.situation_manager import SituationManager @@ -325,5 +325,5 @@ def load_situation_by_id(situation_guid: Union[int, CommonSituationId, Situation return situation_guid from sims4.resources import Types - from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils return CommonResourceUtils.load_instance(Types.SITUATION, situation_guid) diff --git a/Scripts/s4ap/sims4communitylib/utils/resources/common_skill_utils.py b/Scripts/s4ap/sims4communitylib/utils/resources/common_skill_utils.py index b8b40f7..41e1574 100644 --- a/Scripts/s4ap/sims4communitylib/utils/resources/common_skill_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/resources/common_skill_utils.py @@ -6,7 +6,7 @@ Copyright (c) COLONOLNUTTY """ from typing import Union, Iterator, Tuple, List, Callable -from sims4communitylib.enums.skills_enum import CommonSkillId +from s4ap.sims4communitylib.enums.skills_enum import CommonSkillId from statistics.skill import Skill @@ -85,7 +85,7 @@ def get_all_skills_gen(include_skill_callback: Callable[[Skill], bool] = None) - :return: An iterator of Skills that pass the specified include_skill_callback. :rtype: Iterator[Skill] """ - from sims4communitylib.utils.resources.common_statistic_utils import CommonStatisticUtils + from s4ap.sims4communitylib.utils.resources.common_statistic_utils import CommonStatisticUtils statistic_manager = CommonStatisticUtils.get_statistic_instance_manager() for skill in statistic_manager.get_ordered_types(only_subclasses_of=Skill): skill: Skill = skill @@ -117,5 +117,5 @@ def load_skill_by_id(skill_id: Union[int, CommonSkillId, Skill]) -> Union[Skill, skill_id: Skill = skill_id return skill_id - from sims4communitylib.utils.resources.common_statistic_utils import CommonStatisticUtils + from s4ap.sims4communitylib.utils.resources.common_statistic_utils import CommonStatisticUtils return CommonStatisticUtils.load_statistic_by_id(skill_id) diff --git a/Scripts/s4ap/sims4communitylib/utils/resources/common_statistic_utils.py b/Scripts/s4ap/sims4communitylib/utils/resources/common_statistic_utils.py index 902fe7c..52c8bba 100644 --- a/Scripts/s4ap/sims4communitylib/utils/resources/common_statistic_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/resources/common_statistic_utils.py @@ -7,7 +7,7 @@ """ from typing import Union -from sims4communitylib.enums.statistics_enum import CommonStatisticId +from s4ap.sims4communitylib.enums.statistics_enum import CommonStatisticId from statistics.base_statistic import BaseStatistic from statistics.statistic_instance_manager import StatisticInstanceManager @@ -113,7 +113,7 @@ def load_statistic_by_id(statistic_id: Union[int, CommonStatisticId, BaseStatist return statistic_id from sims4.resources import Types - from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils return CommonResourceUtils.load_instance(Types.STATISTIC, statistic_id) or CommonResourceUtils.load_instance(Types.STATIC_COMMODITY, statistic_id) @staticmethod @@ -126,6 +126,6 @@ def get_statistic_instance_manager() -> StatisticInstanceManager: :rtype: StatisticInstanceManager """ from sims4.resources import Types - from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils # noinspection PyTypeChecker return CommonResourceUtils.get_instance_manager(Types.STATISTIC) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_age_species_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_age_species_utils.py index 2bdb9c3..c975355 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_age_species_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_age_species_utils.py @@ -6,8 +6,8 @@ Copyright (c) COLONOLNUTTY """ from sims.sim_info import SimInfo -from sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils -from sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils +from s4ap.sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils +from s4ap.sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils class CommonAgeSpeciesUtils: diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_age_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_age_utils.py index d573696..76a797e 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_age_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_age_utils.py @@ -12,11 +12,11 @@ from event_testing.test_events import TestEvent from sims.sim_info import SimInfo from sims.sim_info_types import Age, Species, SpeciesExtended -from sims4communitylib.enums.common_age import CommonAge -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ +from s4ap.sims4communitylib.enums.common_age import CommonAge +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ CommonConsoleCommandArgument -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput class CommonAgeUtils: @@ -99,7 +99,7 @@ def get_birth_age_from_species(cls, species: Union[Species, SpeciesExtended, int if species == SpeciesExtended.FOX: return Age.ADULT - from sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils + from s4ap.sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils if CommonSpeciesUtils.is_animal_species(species) or species == SpeciesExtended.SMALLDOG: return Age.CHILD return None @@ -240,7 +240,7 @@ def set_age(cls, sim_info: SimInfo, age: Union[CommonAge, Age, int]) -> bool: :rtype: bool """ from sims4.resources import Types - from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils age = cls.convert_to_approximate_age(age) if age is None: return False diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_buff_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_buff_utils.py index 1f210aa..076eea4 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_buff_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_buff_utils.py @@ -14,20 +14,20 @@ from server_commands.argument_helpers import TunableInstanceParam from sims.sim_info import SimInfo from sims4.resources import Types -from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.enums.buffs_enum import CommonBuffId -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.enums.types.component_types import CommonComponentType -from sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ +from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.enums.buffs_enum import CommonBuffId +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.enums.types.component_types import CommonComponentType +from s4ap.sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.notifications.common_basic_notification import CommonBasicNotification +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ CommonConsoleCommandArgument -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.common_component_utils import CommonComponentUtils -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.common_component_utils import CommonComponentUtils +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils class CommonBuffUtils(_HasS4CLClassLog): @@ -468,7 +468,7 @@ def load_buff_by_id(cls, buff: Union[int, CommonBuffId, Buff]) -> Union[Buff, No return buff from sims4.resources import Types - from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils return CommonResourceUtils.load_instance(Types.BUFF, buff) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_career_level_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_career_level_utils.py index a01e955..22f87de 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_career_level_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_career_level_utils.py @@ -46,5 +46,5 @@ def load_career_level_by_guid(career_level_identifier: Union[int, CareerLevel]) return career_level_identifier from sims4.resources import Types - from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils return CommonResourceUtils.load_instance(Types.CAREER_LEVEL, career_level_identifier) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_career_track_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_career_track_utils.py index 7fa7955..cb58cb5 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_career_track_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_career_track_utils.py @@ -142,7 +142,7 @@ def load_career_track_by_guid(career_track_identifier: Union[int, TunableCareerT return career_track_identifier from sims4.resources import Types - from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils return CommonResourceUtils.load_instance(Types.CAREER_TRACK, career_track_identifier) @staticmethod @@ -157,7 +157,7 @@ def get_all_career_tracks_generator(include_career_track_callback: Callable[[Tun :rtype: Iterator[TunableCareerTrack] """ from sims4.resources import Types - from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils for (_, career_track) in CommonResourceUtils.load_all_instances(Types.CAREER_TRACK): if include_career_track_callback is not None and not include_career_track_callback(career_track): continue diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_career_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_career_utils.py index 295b457..2a419df 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_career_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_career_utils.py @@ -30,7 +30,7 @@ def get_career_levels(cls, career: Career, include_branches: bool = False) -> Tu if career is None: return tuple() - from sims4communitylib.utils.sims.common_career_track_utils import CommonCareerTrackUtils + from s4ap.sims4communitylib.utils.sims.common_career_track_utils import CommonCareerTrackUtils return CommonCareerTrackUtils.get_career_levels(career.start_track, include_branches=include_branches) @classmethod @@ -64,7 +64,7 @@ def get_all_career_tracks(cls, career: Career) -> Tuple[TunableCareerTrack]: career_tracks: List[TunableCareerTrack] = list() career_tracks.append(career.start_track) - from sims4communitylib.utils.sims.common_career_track_utils import CommonCareerTrackUtils + from s4ap.sims4communitylib.utils.sims.common_career_track_utils import CommonCareerTrackUtils branch_career_tracks = CommonCareerTrackUtils.get_branches(career.start_track, include_sub_branches=True) if branch_career_tracks: career_tracks.extend(branch_career_tracks) @@ -168,7 +168,7 @@ def load_career_by_guid(career: Union[int, Career]) -> Union[Career, None]: return career from sims4.resources import Types - from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils return CommonResourceUtils.load_instance(Types.CAREER, career) @staticmethod @@ -183,7 +183,7 @@ def get_all_careers_generator(include_career_callback: Callable[[Career], bool] :rtype: Iterator[Career] """ from sims4.resources import Types - from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils for (_, career) in CommonResourceUtils.load_all_instances(Types.CAREER): if include_career_callback is not None and not include_career_callback(career): continue @@ -205,7 +205,7 @@ def determine_entry_level_into_career_from_user_level(career: Career, desired_us if career is None: return None, None, None track = CommonCareerUtils.get_starting_career_track(career) - from sims4communitylib.utils.sims.common_career_track_utils import CommonCareerTrackUtils + from s4ap.sims4communitylib.utils.sims.common_career_track_utils import CommonCareerTrackUtils return CommonCareerTrackUtils.determine_entry_level_into_career_track_by_user_level(track, desired_user_level) @staticmethod @@ -248,5 +248,5 @@ def get_instance_manager() -> InstanceManager: :rtype: InteractionInstanceManager """ from sims4.resources import Types - from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils return CommonResourceUtils.get_instance_manager(Types.CAREER) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_gender_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_gender_utils.py index dd68c73..0a1a033 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_gender_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_gender_utils.py @@ -9,15 +9,15 @@ from sims.sim_info import SimInfo from sims.sim_info_types import Gender -from sims4communitylib.enums.common_gender import CommonGender -from sims4communitylib.enums.traits_enum import CommonTraitId -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ +from s4ap.sims4communitylib.enums.common_gender import CommonGender +from s4ap.sims4communitylib.enums.traits_enum import CommonTraitId +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ CommonConsoleCommandArgument -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils -from sims4communitylib.utils.sims.common_sim_voice_utils import CommonSimVoiceUtils -from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils +from s4ap.sims4communitylib.utils.sims.common_sim_voice_utils import CommonSimVoiceUtils +from s4ap.sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils class CommonGenderUtils: @@ -68,7 +68,7 @@ def set_gender(sim_info: SimInfo, gender: Union[Gender, CommonGender, int]) -> b new_trait_id = CommonTraitId.GENDER_FEMALE CommonTraitUtils.remove_trait(sim_info, CommonTraitId.GENDER_MALE) CommonTraitUtils.add_trait(sim_info, new_trait_id) - from sims4communitylib.events.sim.common_sim_event_dispatcher import CommonSimEventDispatcherService + from s4ap.sims4communitylib.events.sim.common_sim_event_dispatcher import CommonSimEventDispatcherService CommonSimEventDispatcherService()._on_sim_change_gender(sim_info) return True @@ -92,7 +92,7 @@ def swap_gender(sim_info: SimInfo, update_gender_options: bool=True, update_voic :return: True, if the Gender of the Sim was swapped successfully. False, if not. :rtype: bool """ - from sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils + from s4ap.sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils result = False frame = CommonSimGenderOptionUtils.has_masculine_frame(sim_info).result prefers_menswear = CommonSimGenderOptionUtils.prefers_menswear(sim_info).result diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_household_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_household_utils.py index 2a93ba8..d8d3110 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_household_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_household_utils.py @@ -11,16 +11,16 @@ from sims.household import Household from sims.sim_info import SimInfo from sims.sim_spawner import SimSpawner -from sims4communitylib.logging.has_class_log import HasClassLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ +from s4ap.sims4communitylib.logging.has_class_log import HasClassLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ CommonConsoleCommandArgument -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput from world.lot import Lot -from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils -from sims4communitylib.utils.sims.common_sim_state_utils import CommonSimStateUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils +from s4ap.sims4communitylib.utils.sims.common_sim_state_utils import CommonSimStateUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils class CommonHouseholdUtils(HasClassLog): @@ -115,7 +115,7 @@ def get_household_home_lot_id(cls, household: Household) -> int: :return: The home zone identifier of the specified Household or -1 if a problem occurs. :rtype: int """ - from sims4communitylib.utils.location.common_location_utils import CommonLocationUtils + from s4ap.sims4communitylib.utils.location.common_location_utils import CommonLocationUtils if household is None: return -1 home_zone_id = cls.get_household_home_zone_id(household) @@ -223,7 +223,7 @@ def is_alone_on_home_lot(cls, sim_info: SimInfo) -> bool: :return: True, if the Sim is on their home lot and alone. False, if not. :rtype: bool """ - from sims4communitylib.utils.sims.common_sim_location_utils import CommonSimLocationUtils + from s4ap.sims4communitylib.utils.sims.common_sim_location_utils import CommonSimLocationUtils return cls.is_part_of_a_single_sim_household(sim_info) and CommonSimLocationUtils.is_at_home(sim_info) @classmethod diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_mood_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_mood_utils.py index 2b61ada..1b204a9 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_mood_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_mood_utils.py @@ -7,7 +7,7 @@ """ from sims.sim_info import SimInfo from statistics.mood import Mood -from sims4communitylib.enums.moods_enum import CommonMoodId +from s4ap.sims4communitylib.enums.moods_enum import CommonMoodId class CommonMoodUtils: diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_occult_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_occult_utils.py index 82a05e5..4073be8 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_occult_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_occult_utils.py @@ -11,27 +11,27 @@ from sims.occult.occult_enums import OccultType from sims.sim_info import SimInfo from sims.sim_info_base_wrapper import SimInfoBaseWrapper -from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.dtos.common_cas_part import CommonCASPart -from sims4communitylib.enums.buffs_enum import CommonBuffId -from sims4communitylib.enums.common_bucks_types import CommonBucksType -from sims4communitylib.enums.common_occult_type import CommonOccultType -from sims4communitylib.enums.traits_enum import CommonTraitId -from sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ +from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.dtos.common_cas_part import CommonCASPart +from s4ap.sims4communitylib.enums.buffs_enum import CommonBuffId +from s4ap.sims4communitylib.enums.common_bucks_types import CommonBucksType +from s4ap.sims4communitylib.enums.common_occult_type import CommonOccultType +from s4ap.sims4communitylib.enums.traits_enum import CommonTraitId +from s4ap.sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ CommonConsoleCommandArgument -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.cas.common_cas_utils import CommonCASUtils -from sims4communitylib.utils.common_type_utils import CommonTypeUtils -from sims4communitylib.utils.sims.common_buff_utils import CommonBuffUtils -from sims4communitylib.utils.sims.common_sim_appearance_modifier_utils import CommonSimAppearanceModifierUtils -from sims4communitylib.utils.sims.common_sim_bucks_utils import CommonSimBucksUtils -from sims4communitylib.utils.sims.common_sim_loot_action_utils import CommonSimLootActionUtils -from sims4communitylib.utils.sims.common_sim_spell_utils import CommonSimSpellUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.cas.common_cas_utils import CommonCASUtils +from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils +from s4ap.sims4communitylib.utils.sims.common_buff_utils import CommonBuffUtils +from s4ap.sims4communitylib.utils.sims.common_sim_appearance_modifier_utils import CommonSimAppearanceModifierUtils +from s4ap.sims4communitylib.utils.sims.common_sim_bucks_utils import CommonSimBucksUtils +from s4ap.sims4communitylib.utils.sims.common_sim_loot_action_utils import CommonSimLootActionUtils +from s4ap.sims4communitylib.utils.sims.common_sim_spell_utils import CommonSimSpellUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils try: from traits.trait_type import TraitType except ModuleNotFoundError: @@ -116,7 +116,7 @@ def has_any_occult(cls, sim_info: SimInfo) -> CommonTestResult: """ if sim_info is None: raise AssertionError('Argument sim_info was None') - from sims4communitylib.utils.sims.common_sim_occult_type_utils import CommonSimOccultTypeUtils + from s4ap.sims4communitylib.utils.sims.common_sim_occult_type_utils import CommonSimOccultTypeUtils occult_type = CommonSimOccultTypeUtils.determine_occult_type(sim_info) if occult_type not in (CommonOccultType.NON_OCCULT, CommonOccultType.NONE): return CommonTestResult(True, reason=f'Sim had an occult type. {occult_type}') @@ -528,7 +528,7 @@ def add_scarecrow_occult(cls, sim_info: SimInfo) -> CommonExecutionResult: 198147 ) chosen_id = random.choice(scarecrow_cas_part_ids) - from sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils + from s4ap.sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils if CommonCASUtils.attach_cas_part_to_all_outfits_of_sim(sim_info, CommonCASPart(chosen_id)): current_outfit_category_and_index = CommonOutfitUtils.get_current_outfit(sim_info) CommonOutfitUtils.trigger_outfit_generated(sim_info, current_outfit_category_and_index) @@ -566,7 +566,7 @@ def remove_scarecrow_occult(cls, sim_info: SimInfo) -> CommonExecutionResult: CommonCASPart(198147) ) - from sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils + from s4ap.sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils if CommonCASUtils.detach_cas_parts_from_all_outfits_of_sim(sim_info, scarecrow_cas_parts): current_outfit_category_and_index = CommonOutfitUtils.get_current_outfit(sim_info) CommonOutfitUtils.trigger_outfit_generated(sim_info, current_outfit_category_and_index) @@ -1868,7 +1868,7 @@ def _common_print_occult_sim_infos(output: CommonConsoleCommandOutput, sim_info: obj_type_acronym = 'S' elif CommonTypeUtils.is_sim_info_base_wrapper(occult_sim_info): obj_type_acronym = 'SIBW' - from sims4communitylib.utils.sims.common_sim_type_utils import CommonSimTypeUtils + from s4ap.sims4communitylib.utils.sims.common_sim_type_utils import CommonSimTypeUtils sim_types = tuple(CommonSimTypeUtils.get_all_sim_types_gen(occult_sim_info, combine_teen_young_adult_and_elder_age=False, combine_child_dog_types=False)) sim_types_str = ', '.join([sim_type.name for sim_type in sim_types]) current_sim_type = CommonSimTypeUtils.determine_sim_type(occult_sim_info, combine_teen_young_adult_and_elder_age=False, combine_child_dog_types=False, use_current_occult_type=True) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_phone_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_phone_utils.py index 980084c..4014522 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_phone_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_phone_utils.py @@ -5,10 +5,10 @@ Copyright (c) COLONOLNUTTY """ -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.location.common_location_utils import CommonLocationUtils +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.location.common_location_utils import CommonLocationUtils class CommonPhoneUtils: diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_rabbit_hole_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_rabbit_hole_utils.py index d3dec8d..7648acf 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_rabbit_hole_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_rabbit_hole_utils.py @@ -57,5 +57,5 @@ def load_rabbit_hole_by_id(cls, rabbit_hole: Union[int, RabbitHole]) -> Union[Ra return rabbit_hole from sims4.resources import Types - from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils return CommonResourceUtils.load_instance(Types.RABBIT_HOLE, rabbit_hole) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_relationship_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_relationship_utils.py index 05fe72f..f1bb60a 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_relationship_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_relationship_utils.py @@ -13,18 +13,18 @@ from server_commands.argument_helpers import TunableInstanceParam from sims.sim_info import SimInfo from sims4.resources import Types -from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.enums.relationship_bits_enum import CommonRelationshipBitId -from sims4communitylib.enums.relationship_tracks_enum import CommonRelationshipTrackId -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ +from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.enums.relationship_bits_enum import CommonRelationshipBitId +from s4ap.sims4communitylib.enums.relationship_tracks_enum import CommonRelationshipTrackId +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ CommonConsoleCommandArgument -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.common_log_registry import CommonLogRegistry -from sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.common_log_registry import CommonLogRegistry +from s4ap.sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils class CommonRelationshipUtils: @@ -820,7 +820,7 @@ def load_relationship_bit_by_id(cls, relationship_bit: Union[int, CommonRelation return relationship_bit from sims4.resources import Types - from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils return CommonResourceUtils.load_instance(Types.RELATIONSHIP_BIT, relationship_bit) @classmethod @@ -854,7 +854,7 @@ def load_relationship_track_by_id(cls, relationship_track: Union[int, CommonRela return relationship_track from sims4.resources import Types - from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils return CommonResourceUtils.load_instance(Types.STATISTIC, relationship_track) @classmethod diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_appearance_modifier_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_appearance_modifier_utils.py index 629b645..f69afc9 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_appearance_modifier_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_appearance_modifier_utils.py @@ -11,8 +11,8 @@ from buffs.appearance_modifier.appearance_tracker import AppearanceTracker, ModifierInfo from cas.cas import OutfitOverrideOptionFlags from sims.sim_info import SimInfo -from sims4communitylib.enums.common_appearance_modifier_priority import CommonAppearanceModifierPriority -from sims4communitylib.enums.common_appearance_modifier_type import CommonAppearanceModifierType +from s4ap.sims4communitylib.enums.common_appearance_modifier_priority import CommonAppearanceModifierPriority +from s4ap.sims4communitylib.enums.common_appearance_modifier_type import CommonAppearanceModifierType class CommonSimAppearanceModifierUtils: diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_autonomy_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_autonomy_utils.py index 5066522..ec2f329 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_autonomy_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_autonomy_utils.py @@ -8,10 +8,10 @@ from autonomy.settings import AutonomyState from objects.game_object import GameObject from sims.sim_info import SimInfo -from sims4communitylib.enums.common_object_preference_tag import CommonObjectPreferenceTag -from sims4communitylib.enums.types.component_types import CommonComponentType -from sims4communitylib.utils.common_component_utils import CommonComponentUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.enums.common_object_preference_tag import CommonObjectPreferenceTag +from s4ap.sims4communitylib.enums.types.component_types import CommonComponentType +from s4ap.sims4communitylib.utils.common_component_utils import CommonComponentUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils class CommonSimAutonomyUtils: diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_body_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_body_utils.py index 4c499ad..e59d8a3 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_body_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_body_utils.py @@ -8,11 +8,11 @@ from typing import Tuple from sims.sim_info import SimInfo -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ CommonConsoleCommandArgument -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils class CommonSimBodyUtils: diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_bucks_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_bucks_utils.py index 5ed8969..f42ea61 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_bucks_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_bucks_utils.py @@ -14,14 +14,14 @@ from server_commands.argument_helpers import TunableInstanceParam from sims.sim_info import SimInfo from sims4.resources import Types -from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.enums.common_bucks_types import CommonBucksType -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ +from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.enums.common_bucks_types import CommonBucksType +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ CommonConsoleCommandArgument -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils class CommonSimBucksUtils: @@ -562,7 +562,7 @@ def load_perk_by_guid(cls, perk: Union[int, BucksPerk]) -> Union[BucksPerk, None return perk from sims4.resources import Types - from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils return CommonResourceUtils.load_instance(Types.BUCKS_PERK, perk) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_career_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_career_utils.py index 64cacec..93c4567 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_career_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_career_utils.py @@ -19,20 +19,20 @@ from server_commands.argument_helpers import TunableInstanceParam from sims.sim_info import SimInfo from sims4.resources import Types -from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ +from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ CommonConsoleCommandArgument -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.common_time_utils import CommonTimeUtils -from sims4communitylib.utils.location.common_location_utils import CommonLocationUtils -from sims4communitylib.utils.sims.common_career_track_utils import CommonCareerTrackUtils -from sims4communitylib.utils.sims.common_career_utils import CommonCareerUtils -from sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils -from sims4communitylib.utils.sims.common_sim_type_utils import CommonSimTypeUtils -from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.common_time_utils import CommonTimeUtils +from s4ap.sims4communitylib.utils.location.common_location_utils import CommonLocationUtils +from s4ap.sims4communitylib.utils.sims.common_career_track_utils import CommonCareerTrackUtils +from s4ap.sims4communitylib.utils.sims.common_career_utils import CommonCareerUtils +from s4ap.sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils +from s4ap.sims4communitylib.utils.sims.common_sim_type_utils import CommonSimTypeUtils +from s4ap.sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils from singletons import DEFAULT diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_club_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_club_utils.py index 711f2f2..6c5fead 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_club_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_club_utils.py @@ -11,8 +11,8 @@ from clubs.club import Club from clubs.club_gathering_situation import ClubGatheringSituation from sims.sim_info import SimInfo -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils class CommonSimClubUtils: diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_crafting_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_crafting_utils.py index 34ba5fb..bd20294 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_crafting_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_crafting_utils.py @@ -11,10 +11,10 @@ from objects.game_object import GameObject from sims.sim import Sim from sims.sim_info import SimInfo -from sims4communitylib.enums.common_object_quality import CommonObjectQuality -from sims4communitylib.utils.common_type_utils import CommonTypeUtils -from sims4communitylib.utils.objects.common_object_state_utils import CommonObjectStateUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.enums.common_object_quality import CommonObjectQuality +from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils +from s4ap.sims4communitylib.utils.objects.common_object_state_utils import CommonObjectStateUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils class CommonSimCraftingUtils: @@ -68,12 +68,12 @@ def create_from_recipe( crafting_sim = CommonSimUtils.get_sim_instance(crafting_sim_info) if crafting_sim is None: return None - from sims4communitylib.utils.resources.common_recipe_utils import CommonRecipeUtils + from s4ap.sims4communitylib.utils.resources.common_recipe_utils import CommonRecipeUtils recipe = CommonRecipeUtils.load_recipe_by_guid(recipe_id) try: from crafting.crafting_interactions import create_craftable - from sims4communitylib.utils.objects.common_object_ownership_utils import CommonObjectOwnershipUtils - from sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils + from s4ap.sims4communitylib.utils.objects.common_object_ownership_utils import CommonObjectOwnershipUtils + from s4ap.sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils quality_state = CommonObjectStateUtils.convert_quality_to_object_state_value(quality) if set_target_as_owner: if CommonTypeUtils.is_sim_or_sim_info(inventory_target): diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_currency_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_currency_utils.py index 6d906e6..d53965c 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_currency_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_currency_utils.py @@ -9,12 +9,12 @@ from sims.funds import FamilyFunds from sims.sim_info import SimInfo -from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from sims4communitylib.enums.common_currency_modify_reasons import CommonCurrencyModifyReason -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ +from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from s4ap.sims4communitylib.enums.common_currency_modify_reasons import CommonCurrencyModifyReason +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ CommonConsoleCommandArgument -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput class CommonSimCurrencyUtils: @@ -93,7 +93,7 @@ def get_household_funds(cls, sim_info: SimInfo) -> Union[FamilyFunds, None]: :return: The FamilyFunds object of the Household of the specified Sim or None if the Sim did not have a Household. :rtype: Union[FamilyFunds, None] """ - from sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils + from s4ap.sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils household = CommonHouseholdUtils.get_household(sim_info) if household is None: return None diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_death_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_death_utils.py index 8e6f015..48b2d83 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_death_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_death_utils.py @@ -12,33 +12,33 @@ from objects.game_object import GameObject from sims.ghost import Ghost from sims.sim_info import SimInfo -from sims4communitylib.classes.math.common_location import CommonLocation -from sims4communitylib.classes.math.common_transform import CommonTransform -from sims4communitylib.classes.math.common_vector3 import CommonVector3 -from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.enums.common_death_types import CommonDeathType -from sims4communitylib.enums.common_region_id import CommonRegionId -from sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ +from s4ap.sims4communitylib.classes.math.common_location import CommonLocation +from s4ap.sims4communitylib.classes.math.common_transform import CommonTransform +from s4ap.sims4communitylib.classes.math.common_vector3 import CommonVector3 +from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.enums.common_death_types import CommonDeathType +from s4ap.sims4communitylib.enums.common_region_id import CommonRegionId +from s4ap.sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ CommonConsoleCommandArgument -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from sims4communitylib.utils.common_time_utils import CommonTimeUtils -from sims4communitylib.utils.location.common_location_utils import CommonLocationUtils -from sims4communitylib.utils.objects.common_object_spawn_utils import CommonObjectSpawnUtils -from sims4communitylib.utils.objects.common_object_state_utils import CommonObjectStateUtils -from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils -from sims4communitylib.utils.resources.common_interaction_utils import CommonInteractionUtils -from sims4communitylib.utils.sims.common_buff_utils import CommonBuffUtils -from sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils -from sims4communitylib.utils.sims.common_occult_utils import CommonOccultUtils -from sims4communitylib.utils.sims.common_sim_interaction_utils import CommonSimInteractionUtils -from sims4communitylib.utils.sims.common_sim_location_utils import CommonSimLocationUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils -from sims4communitylib.utils.time.common_alarm_utils import CommonAlarmUtils +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.utils.common_time_utils import CommonTimeUtils +from s4ap.sims4communitylib.utils.location.common_location_utils import CommonLocationUtils +from s4ap.sims4communitylib.utils.objects.common_object_spawn_utils import CommonObjectSpawnUtils +from s4ap.sims4communitylib.utils.objects.common_object_state_utils import CommonObjectStateUtils +from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils +from s4ap.sims4communitylib.utils.resources.common_interaction_utils import CommonInteractionUtils +from s4ap.sims4communitylib.utils.sims.common_buff_utils import CommonBuffUtils +from s4ap.sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils +from s4ap.sims4communitylib.utils.sims.common_occult_utils import CommonOccultUtils +from s4ap.sims4communitylib.utils.sims.common_sim_interaction_utils import CommonSimInteractionUtils +from s4ap.sims4communitylib.utils.sims.common_sim_location_utils import CommonSimLocationUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils +from s4ap.sims4communitylib.utils.time.common_alarm_utils import CommonAlarmUtils class CommonSimDeathUtils(_HasS4CLClassLog): diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_demographic_type_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_demographic_type_utils.py index c8f827b..a74a9f6 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_demographic_type_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_demographic_type_utils.py @@ -8,20 +8,20 @@ from typing import Tuple, TYPE_CHECKING, Dict, List, Callable, Union, Iterator from sims.sim_info import SimInfo -from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog -from sims4communitylib.utils.math.common_bitwise_utils import CommonBitwiseUtils -from sims4communitylib.utils.sims.common_sim_occult_type_utils import CommonSimOccultTypeUtils -from sims4communitylib.utils.sims.common_sim_type_utils import CommonSimTypeUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog +from s4ap.sims4communitylib.utils.math.common_bitwise_utils import CommonBitwiseUtils +from s4ap.sims4communitylib.utils.sims.common_sim_occult_type_utils import CommonSimOccultTypeUtils +from s4ap.sims4communitylib.utils.sims.common_sim_type_utils import CommonSimTypeUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils if TYPE_CHECKING: - from sims4communitylib.enums.common_age import CommonAge - from sims4communitylib.enums.common_gender import CommonGender - from sims4communitylib.enums.common_species import CommonSpecies - from sims4communitylib.enums.common_occult_type import CommonOccultType - from sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType + from s4ap.sims4communitylib.enums.common_age import CommonAge + from s4ap.sims4communitylib.enums.common_gender import CommonGender + from s4ap.sims4communitylib.enums.common_species import CommonSpecies + from s4ap.sims4communitylib.enums.common_occult_type import CommonOccultType + from s4ap.sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType class CommonSimDemographicTypeUtils(_HasS4CLClassLog): @@ -35,9 +35,9 @@ def get_log_identifier(cls) -> str: @classmethod def determine_sim_demographic_flags(cls, sim_info: SimInfo) -> 'CommonSimDemographicType': """Determine the demographics of a Sim as flags.""" - from sims4communitylib.enums.common_age import CommonAge - from sims4communitylib.enums.common_gender import CommonGender - from sims4communitylib.enums.common_species import CommonSpecies + from s4ap.sims4communitylib.enums.common_age import CommonAge + from s4ap.sims4communitylib.enums.common_gender import CommonGender + from s4ap.sims4communitylib.enums.common_species import CommonSpecies value: 'CommonSimDemographicType' = cls.convert_from_age(CommonAge.get_age(sim_info)) value = CommonBitwiseUtils.add_flags(value, cls.convert_from_species(CommonSpecies.get_species(sim_info))) value = CommonBitwiseUtils.add_flags(value, cls.convert_from_gender(CommonGender.get_gender(sim_info))) @@ -47,10 +47,10 @@ def determine_sim_demographic_flags(cls, sim_info: SimInfo) -> 'CommonSimDemogra @classmethod def determine_sim_demographics(cls, sim_info: SimInfo) -> Tuple['CommonSimDemographicType']: """Determine the demographics of a Sim as a collection.""" - from sims4communitylib.enums.common_age import CommonAge - from sims4communitylib.enums.common_gender import CommonGender - from sims4communitylib.enums.common_species import CommonSpecies - from sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType + from s4ap.sims4communitylib.enums.common_age import CommonAge + from s4ap.sims4communitylib.enums.common_gender import CommonGender + from s4ap.sims4communitylib.enums.common_species import CommonSpecies + from s4ap.sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType values: List['CommonSimDemographicType'] = list() values.append(cls.convert_from_species(CommonSpecies.get_species(sim_info))) values.append(cls.convert_from_age(CommonAge.get_age(sim_info))) @@ -80,7 +80,7 @@ def is_sim_contained_in_demographic_flags(cls, sim_info: SimInfo, demographic_fl :rtype: bool """ sim_demographic_flags = cls.determine_sim_demographic_flags(sim_info) - # from sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType + # from s4ap.sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType # if CommonBitwiseUtils.contains_any_flags(demographic_flags, CommonSimDemographicType.get_all_flags(exclude_values=(CommonSimDemographicType.CURRENTLY_CONTROLLED, CommonSimDemographicType.CONTROLLED, CommonSimDemographicType.HOUSEHOLD, CommonSimDemographicType.NON_HOUSEHOLD))): # demographic_flags must contain all the values from sim_demographic_flags. If WEREWOLF was not in demographic_flags but was in sim_demographic_flags, then this would return False. if match_all: @@ -93,7 +93,7 @@ def is_sim_contained_in_demographic_flags(cls, sim_info: SimInfo, demographic_fl return False # # Handle the non mutually exclusive flags. - # from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + # from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils # if CommonBitwiseUtils.contains_all_flags(demographic_flags, CommonSimDemographicType.CURRENTLY_CONTROLLED) and CommonSimUtils.is_active_sim(sim_info): # cls.get_log().format_with_message('Sim passed controlled flags', sim=sim_info, demographic_flags=demographic_flags, sim_demographic_flags=sim_demographic_flags) # return True @@ -127,8 +127,8 @@ def is_sim_contained_in_demographics(cls, sim_info: SimInfo, demographics: Tuple sim_demographics = cls.determine_sim_demographics(sim_info) # # Handle the non mutually exclusive flags. - # from sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType - # from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + # from s4ap.sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType + # from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils # if CommonSimDemographicType.CURRENTLY_CONTROLLED in demographics and CommonSimUtils.is_active_sim(sim_info): # cls.get_log().format_with_message('Sim passed controlled flags', sim=sim_info, demographics=demographics, sim_demographics=sim_demographics) # return True @@ -161,8 +161,8 @@ def is_sim_contained_in_demographics(cls, sim_info: SimInfo, demographics: Tuple @classmethod def convert_to_age(cls, value: 'CommonSimDemographicType') -> 'CommonAge': """Convert a value to an Age value.""" - from sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType - from sims4communitylib.enums.common_age import CommonAge + from s4ap.sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType + from s4ap.sims4communitylib.enums.common_age import CommonAge mapping: Dict[CommonSimDemographicType, CommonAge] = { CommonSimDemographicType.BABY: CommonAge.BABY, CommonSimDemographicType.INFANT: CommonAge.INFANT, @@ -178,8 +178,8 @@ def convert_to_age(cls, value: 'CommonSimDemographicType') -> 'CommonAge': @classmethod def convert_from_age(cls, value: 'CommonAge') -> 'CommonSimDemographicType': """Convert a value to a Sim demographic value.""" - from sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType - from sims4communitylib.enums.common_age import CommonAge + from s4ap.sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType + from s4ap.sims4communitylib.enums.common_age import CommonAge mapping: Dict[CommonAge, CommonSimDemographicType] = { CommonAge.BABY: CommonSimDemographicType.BABY, CommonAge.INFANT: CommonSimDemographicType.INFANT, @@ -195,8 +195,8 @@ def convert_from_age(cls, value: 'CommonAge') -> 'CommonSimDemographicType': @classmethod def convert_to_gender(cls, value: 'CommonSimDemographicType') -> 'CommonGender': """Convert a value to a Gender value.""" - from sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType - from sims4communitylib.enums.common_gender import CommonGender + from s4ap.sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType + from s4ap.sims4communitylib.enums.common_gender import CommonGender mapping: Dict[CommonSimDemographicType, CommonGender] = { CommonSimDemographicType.MALE: CommonGender.MALE, CommonSimDemographicType.FEMALE: CommonGender.FEMALE @@ -206,8 +206,8 @@ def convert_to_gender(cls, value: 'CommonSimDemographicType') -> 'CommonGender': @classmethod def convert_from_gender(cls, value: 'CommonGender') -> 'CommonSimDemographicType': """Convert a value to a Sim demographic value.""" - from sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType - from sims4communitylib.enums.common_gender import CommonGender + from s4ap.sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType + from s4ap.sims4communitylib.enums.common_gender import CommonGender mapping: Dict[CommonGender, CommonSimDemographicType] = { CommonGender.MALE: CommonSimDemographicType.MALE, CommonGender.FEMALE: CommonSimDemographicType.FEMALE @@ -217,8 +217,8 @@ def convert_from_gender(cls, value: 'CommonGender') -> 'CommonSimDemographicType @classmethod def convert_to_species(cls, value: 'CommonSimDemographicType') -> 'CommonSpecies': """Convert a value to a Species value.""" - from sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType - from sims4communitylib.enums.common_species import CommonSpecies + from s4ap.sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType + from s4ap.sims4communitylib.enums.common_species import CommonSpecies mapping: Dict[CommonSimDemographicType, CommonSpecies] = { CommonSimDemographicType.HUMAN: CommonSpecies.HUMAN, CommonSimDemographicType.SMALL_DOG: CommonSpecies.SMALL_DOG, @@ -232,8 +232,8 @@ def convert_to_species(cls, value: 'CommonSimDemographicType') -> 'CommonSpecies @classmethod def convert_from_species(cls, value: 'CommonSpecies') -> 'CommonSimDemographicType': """Convert a value to a Sim demographic value.""" - from sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType - from sims4communitylib.enums.common_species import CommonSpecies + from s4ap.sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType + from s4ap.sims4communitylib.enums.common_species import CommonSpecies mapping: Dict[CommonSpecies, CommonSimDemographicType] = { CommonSpecies.HUMAN: CommonSimDemographicType.HUMAN, CommonSpecies.SMALL_DOG: CommonSimDemographicType.SMALL_DOG, @@ -247,8 +247,8 @@ def convert_from_species(cls, value: 'CommonSpecies') -> 'CommonSimDemographicTy @classmethod def convert_to_occult_type(cls, value: 'CommonSimDemographicType') -> 'CommonOccultType': """Convert a value to an Occult Type value.""" - from sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType - from sims4communitylib.enums.common_occult_type import CommonOccultType + from s4ap.sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType + from s4ap.sims4communitylib.enums.common_occult_type import CommonOccultType mapping: Dict[CommonSimDemographicType, CommonOccultType] = { CommonSimDemographicType.ALIEN: CommonOccultType.ALIEN, CommonSimDemographicType.MERMAID: CommonOccultType.MERMAID, @@ -266,8 +266,8 @@ def convert_to_occult_type(cls, value: 'CommonSimDemographicType') -> 'CommonOcc @classmethod def convert_from_occult_type(cls, value: 'CommonOccultType') -> 'CommonSimDemographicType': """Convert a value to a Sim demographic value.""" - from sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType - from sims4communitylib.enums.common_occult_type import CommonOccultType + from s4ap.sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType + from s4ap.sims4communitylib.enums.common_occult_type import CommonOccultType mapping: Dict[CommonOccultType, CommonSimDemographicType] = { CommonOccultType.ALIEN: CommonSimDemographicType.ALIEN, CommonOccultType.MERMAID: CommonSimDemographicType.MERMAID, diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_gender_option_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_gender_option_utils.py index 9ce1d84..560b3b0 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_gender_option_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_gender_option_utils.py @@ -9,14 +9,14 @@ from sims.global_gender_preference_tuning import ExploringOptionsStatus, GlobalGenderPreferenceTuning from sims.sim_info import SimInfo -from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.enums.traits_enum import CommonTraitId -from sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog -from sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils -from sims4communitylib.utils.sims.common_sim_voice_utils import CommonSimVoiceUtils -from sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils -from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils +from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.enums.traits_enum import CommonTraitId +from s4ap.sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog +from s4ap.sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils +from s4ap.sims4communitylib.utils.sims.common_sim_voice_utils import CommonSimVoiceUtils +from s4ap.sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils +from s4ap.sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils from traits.traits import Trait @@ -96,7 +96,7 @@ def can_impregnate(sim_info: SimInfo) -> CommonTestResult: :return: The result of testing. True, if the Sim can impregnate other Sims. False, if the Sim can not impregnate other Sims. :rtype: CommonTestResult """ - from sims4communitylib.utils.sims.common_sim_pregnancy_utils import CommonSimPregnancyUtils + from s4ap.sims4communitylib.utils.sims.common_sim_pregnancy_utils import CommonSimPregnancyUtils return CommonSimPregnancyUtils.can_impregnate(sim_info) @staticmethod @@ -130,7 +130,7 @@ def can_be_impregnated(sim_info: SimInfo) -> CommonTestResult: :return: The result of testing. True, if the Sim can be impregnated. False, if the Sim can not be impregnated. :rtype: CommonTestResult """ - from sims4communitylib.utils.sims.common_sim_pregnancy_utils import CommonSimPregnancyUtils + from s4ap.sims4communitylib.utils.sims.common_sim_pregnancy_utils import CommonSimPregnancyUtils return CommonSimPregnancyUtils.can_be_impregnated(sim_info) @staticmethod @@ -365,7 +365,7 @@ def update_has_breasts(sim_info: SimInfo, has_breasts: bool) -> CommonExecutionR """ if sim_info is None: raise AssertionError('Argument sim_info was None') - from sims4communitylib.events.sim.common_sim_event_dispatcher import CommonSimEventDispatcherService + from s4ap.sims4communitylib.events.sim.common_sim_event_dispatcher import CommonSimEventDispatcherService CommonTraitUtils.remove_trait(sim_info, CommonTraitId.BREASTS_FORCE_OFF) CommonTraitUtils.remove_trait(sim_info, CommonTraitId.BREASTS_FORCE_ON) if has_breasts: @@ -412,7 +412,7 @@ def update_body_frame(sim_info: SimInfo, masculine: bool) -> CommonExecutionResu add_trait_result = CommonTraitUtils.add_trait(sim_info, CommonTraitId.GENDER_OPTIONS_FRAME_FEMININE) if not add_trait_result: return add_trait_result - from sims4communitylib.events.sim.common_sim_event_dispatcher import CommonSimEventDispatcherService + from s4ap.sims4communitylib.events.sim.common_sim_event_dispatcher import CommonSimEventDispatcherService CommonSimEventDispatcherService()._on_sim_change_gender_options_body_frame(sim_info) return CommonExecutionResult.TRUE @@ -446,7 +446,7 @@ def update_clothing_preference(sim_info: SimInfo, prefer_menswear: bool) -> Comm add_trait_result = CommonTraitUtils.add_trait(sim_info, CommonTraitId.GENDER_OPTIONS_CLOTHING_WOMENS_WEAR) if not add_trait_result: return add_trait_result - from sims4communitylib.events.sim.common_sim_event_dispatcher import CommonSimEventDispatcherService + from s4ap.sims4communitylib.events.sim.common_sim_event_dispatcher import CommonSimEventDispatcherService CommonSimEventDispatcherService()._on_sim_change_gender_options_clothing_preference(sim_info) return CommonExecutionResult.TRUE @@ -468,7 +468,7 @@ def update_can_be_impregnated(sim_info: SimInfo, can_be_impregnated: bool) -> Co """ if sim_info is None: raise AssertionError('Argument sim_info was None') - from sims4communitylib.utils.sims.common_sim_pregnancy_utils import CommonSimPregnancyUtils + from s4ap.sims4communitylib.utils.sims.common_sim_pregnancy_utils import CommonSimPregnancyUtils can_be_impregnated_trait = CommonSimPregnancyUtils.determine_can_be_impregnated_trait(sim_info) can_not_be_impregnated_trait = CommonSimPregnancyUtils.determine_can_not_be_impregnated_trait(sim_info) if can_be_impregnated_trait is None: @@ -496,7 +496,7 @@ def update_can_be_impregnated(sim_info: SimInfo, can_be_impregnated: bool) -> Co add_trait_result = CommonTraitUtils.add_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_NOT_REPRODUCE) if not add_trait_result: return add_trait_result - from sims4communitylib.events.sim.common_sim_event_dispatcher import CommonSimEventDispatcherService + from s4ap.sims4communitylib.events.sim.common_sim_event_dispatcher import CommonSimEventDispatcherService CommonSimEventDispatcherService()._on_sim_change_gender_options_can_be_impregnated(sim_info) return CommonExecutionResult.TRUE @@ -518,7 +518,7 @@ def update_can_impregnate(sim_info: SimInfo, can_impregnate: bool) -> CommonExec """ if sim_info is None: raise AssertionError('Argument sim_info was None') - from sims4communitylib.utils.sims.common_sim_pregnancy_utils import CommonSimPregnancyUtils + from s4ap.sims4communitylib.utils.sims.common_sim_pregnancy_utils import CommonSimPregnancyUtils can_impregnate_trait = CommonSimPregnancyUtils.determine_can_impregnate_trait(sim_info) can_not_impregnate_trait = CommonSimPregnancyUtils.determine_can_not_impregnate_trait(sim_info) if can_impregnate_trait is None: @@ -546,7 +546,7 @@ def update_can_impregnate(sim_info: SimInfo, can_impregnate: bool) -> CommonExec add_trait_result = CommonTraitUtils.add_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_NOT_REPRODUCE) if not add_trait_result: return add_trait_result - from sims4communitylib.events.sim.common_sim_event_dispatcher import CommonSimEventDispatcherService + from s4ap.sims4communitylib.events.sim.common_sim_event_dispatcher import CommonSimEventDispatcherService CommonSimEventDispatcherService()._on_sim_change_gender_options_can_impregnate(sim_info) return CommonExecutionResult.TRUE @@ -610,7 +610,7 @@ def update_can_reproduce(sim_info: SimInfo, can_reproduce: bool) -> CommonExecut update_can_be_impregnated_result = CommonSimGenderOptionUtils.update_can_be_impregnated(sim_info, False) if not update_can_be_impregnated_result: return update_can_be_impregnated_result - from sims4communitylib.events.sim.common_sim_event_dispatcher import CommonSimEventDispatcherService + from s4ap.sims4communitylib.events.sim.common_sim_event_dispatcher import CommonSimEventDispatcherService CommonSimEventDispatcherService()._on_sim_change_gender_options_can_reproduce(sim_info) return CommonExecutionResult.TRUE @@ -650,7 +650,7 @@ def update_toilet_usage(sim_info: SimInfo, uses_toilet_standing: bool) -> Common add_trait_result = CommonTraitUtils.add_trait(sim_info, toilet_sitting) if not add_trait_result: return add_trait_result - from sims4communitylib.events.sim.common_sim_event_dispatcher import CommonSimEventDispatcherService + from s4ap.sims4communitylib.events.sim.common_sim_event_dispatcher import CommonSimEventDispatcherService CommonSimEventDispatcherService()._on_sim_change_gender_options_toilet_usage(sim_info) return CommonExecutionResult.TRUE @@ -686,7 +686,7 @@ def set_can_use_toilet_standing(sim_info: SimInfo, can_use_toilet_standing: bool if not add_trait_result: return add_trait_result - from sims4communitylib.events.sim.common_sim_event_dispatcher import CommonSimEventDispatcherService + from s4ap.sims4communitylib.events.sim.common_sim_event_dispatcher import CommonSimEventDispatcherService CommonSimEventDispatcherService()._on_sim_change_gender_options_toilet_usage(sim_info) return CommonExecutionResult.TRUE @@ -722,7 +722,7 @@ def set_can_use_toilet_sitting(sim_info: SimInfo, can_use_toilet_sitting: bool) if not add_trait_result: return add_trait_result - from sims4communitylib.events.sim.common_sim_event_dispatcher import CommonSimEventDispatcherService + from s4ap.sims4communitylib.events.sim.common_sim_event_dispatcher import CommonSimEventDispatcherService CommonSimEventDispatcherService()._on_sim_change_gender_options_toilet_usage(sim_info) return CommonExecutionResult.TRUE diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_gender_preference_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_gender_preference_utils.py index 2fed5f6..a4ee140 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_gender_preference_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_gender_preference_utils.py @@ -9,16 +9,16 @@ from sims.global_gender_preference_tuning import GlobalGenderPreferenceTuning, GenderPreferenceType from sims.sim_info import SimInfo -from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from sims4communitylib.enums.common_gender import CommonGender -from sims4communitylib.enums.common_gender_preference_type import CommonGenderPreferenceType -from sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ +from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from s4ap.sims4communitylib.enums.common_gender import CommonGender +from s4ap.sims4communitylib.enums.common_gender_preference_type import CommonGenderPreferenceType +from s4ap.sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ CommonConsoleCommandArgument -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils class CommonSimGenderPreferenceUtils: @@ -134,7 +134,7 @@ def get_default_preferred_genders(cls, sim_info: SimInfo) -> Tuple[CommonGender] :return: A collection of the default preferred genders. :rtype: Tuple[CommonGender] """ - from sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils + from s4ap.sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils if CommonGenderUtils.is_male(sim_info): return CommonGender.FEMALE, return CommonGender.MALE, @@ -260,7 +260,7 @@ def _common_set_world_sexually_exploring(output: CommonConsoleCommandOutput, is_ else: output('Attempting to set all Sims to be Not Sexually Exporing in their Sexual Orientation.') for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): - from sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils + from s4ap.sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils CommonSimGenderOptionUtils.set_is_exploring_sexuality(sim_info, is_sexually_exploring) @@ -352,7 +352,7 @@ def _common_set_gender_pref_of_all_female_sims(output: CommonConsoleCommandOutpu gender_name = gender.name sim_count = 0 output(f'Setting {preference_type.name} gender preference of all Female Sims for gender {gender_name} to {is_attracted_to_gender}') - from sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils + from s4ap.sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(include_sim_callback=CommonGenderUtils.is_female): try: if CommonSimGenderPreferenceUtils.set_preference_for_gender(sim_info, gender, is_attracted_to_gender, preference_type=preference_type): @@ -387,7 +387,7 @@ def _common_set_gender_pref_of_all_male_sims(output: CommonConsoleCommandOutput, gender_name = gender.name sim_count = 0 output(f'Setting {preference_type.name} gender preference of all Male Sims for gender {gender_name} to {is_attracted_to_gender}') - from sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils + from s4ap.sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(include_sim_callback=CommonGenderUtils.is_male): try: if CommonSimGenderPreferenceUtils.set_preference_for_gender(sim_info, gender, is_attracted_to_gender, preference_type=preference_type): diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_genealogy_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_genealogy_utils.py index bab5daa..12d8733 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_genealogy_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_genealogy_utils.py @@ -9,9 +9,9 @@ from sims.genealogy_tracker import GenealogyTracker, FamilyRelationshipIndex from sims.sim_info import SimInfo -from sims4communitylib.enums.relationship_bits_enum import CommonRelationshipBitId -from sims4communitylib.utils.sims.common_relationship_utils import CommonRelationshipUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.enums.relationship_bits_enum import CommonRelationshipBitId +from s4ap.sims4communitylib.utils.sims.common_relationship_utils import CommonRelationshipUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils class CommonSimGenealogyUtils: diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_interaction_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_interaction_utils.py index c4c7f65..7394928 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_interaction_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_interaction_utils.py @@ -15,22 +15,22 @@ from interactions.interaction_finisher import FinishingType from interactions.priority import Priority from sims.sim_info import SimInfo -from sims4communitylib.classes.testing.common_enqueue_result import CommonEnqueueResult -from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.enums.interactions_enum import CommonInteractionId -from sims4communitylib.logging.has_class_log import HasClassLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ +from s4ap.sims4communitylib.classes.testing.common_enqueue_result import CommonEnqueueResult +from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.enums.interactions_enum import CommonInteractionId +from s4ap.sims4communitylib.logging.has_class_log import HasClassLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.notifications.common_basic_notification import CommonBasicNotification +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ CommonConsoleCommandArgument -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.common_type_utils import CommonTypeUtils -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.resources.common_interaction_utils import CommonInteractionUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.resources.common_interaction_utils import CommonInteractionUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils class CommonSimInteractionUtils(HasClassLog): @@ -159,7 +159,7 @@ def get_stand_interaction(cls, sim_info: SimInfo) -> Union[int, CommonInteractio :return: The decimal identifier of a Stand interaction appropriate for the Sim or -1 if no Stand interaction was found to be appropriate. :rtype: Union[int, CommonInteractionId] """ - from sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils + from s4ap.sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils if CommonSpeciesUtils.is_human(sim_info): return CommonInteractionId.SIM_STAND elif CommonSpeciesUtils.is_dog(sim_info): @@ -183,7 +183,7 @@ def get_stand_passive_interaction(cls, sim_info: SimInfo) -> Union[int, CommonIn :return: The decimal identifier of a Stand Passive interaction appropriate for the Sim or -1 if no Stand interaction was found to be appropriate. :rtype: Union[int, CommonInteractionId] """ - from sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils + from s4ap.sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils if CommonSpeciesUtils.is_human(sim_info): return CommonInteractionId.STAND_PASSIVE elif CommonSpeciesUtils.is_dog(sim_info): @@ -1385,7 +1385,7 @@ def _common_show_running_interactions(output: CommonConsoleCommandOutput, sim_in try: log.enable() output(f'Attempting to print all running and queued interactions of Sim {sim_info}') - from sims4communitylib.utils.resources.common_interaction_utils import CommonInteractionUtils + from s4ap.sims4communitylib.utils.resources.common_interaction_utils import CommonInteractionUtils running_interaction_strings: List[str] = list() for interaction in CommonSimInteractionUtils.get_running_interactions_gen(sim_info): interaction_name = CommonInteractionUtils.get_interaction_short_name(interaction) or interaction.__class__.__name__ diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_inventory_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_inventory_utils.py index 980e5a6..deb4fc8 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_inventory_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_inventory_utils.py @@ -10,19 +10,19 @@ from objects.components.sim_inventory_component import SimInventoryComponent from objects.game_object import GameObject from sims.sim_info import SimInfo -from sims4communitylib.classes.math.common_location import CommonLocation -from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from sims4communitylib.enums.types.component_types import CommonComponentType -from sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ +from s4ap.sims4communitylib.classes.math.common_location import CommonLocation +from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from s4ap.sims4communitylib.enums.types.component_types import CommonComponentType +from s4ap.sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ CommonConsoleCommandArgument -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.common_component_utils import CommonComponentUtils -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from sims4communitylib.utils.objects.common_object_spawn_utils import CommonObjectSpawnUtils -from sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.common_component_utils import CommonComponentUtils +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.utils.objects.common_object_spawn_utils import CommonObjectSpawnUtils +from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils class CommonSimInventoryUtils(_HasS4CLClassLog): @@ -218,7 +218,7 @@ def move_object_to_inventory(cls, sim_info: SimInfo, game_object: GameObject) -> inventory_component: SimInventoryComponent = cls.get_inventory(sim_info) if inventory_component is None: return False - from sims4communitylib.utils.objects.common_object_ownership_utils import CommonObjectOwnershipUtils + from s4ap.sims4communitylib.utils.objects.common_object_ownership_utils import CommonObjectOwnershipUtils CommonObjectOwnershipUtils.set_owning_sim(game_object, sim_info) return inventory_component.player_try_add_object(game_object) @@ -354,7 +354,7 @@ def set_ownership_of_all_items_in_sim_inventory_to_sim(cls, sim_info_a: SimInfo, inventory_component: SimInventoryComponent = cls.get_inventory(sim_info_a) if inventory_component is None: return False - from sims4communitylib.utils.objects.common_object_ownership_utils import CommonObjectOwnershipUtils + from s4ap.sims4communitylib.utils.objects.common_object_ownership_utils import CommonObjectOwnershipUtils for inventory_object in inventory_component: inventory_object: GameObject = inventory_object CommonObjectOwnershipUtils.set_owning_sim(inventory_object, sim_info_b) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_location_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_location_utils.py index 044396d..ab3d750 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_location_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_location_utils.py @@ -10,24 +10,24 @@ from typing import Union from objects.script_object import ScriptObject -from sims4communitylib.classes.math.common_location import CommonLocation -from sims4communitylib.classes.math.common_quaternion import CommonQuaternion -from sims4communitylib.classes.math.common_routing_location import CommonRoutingLocation -from sims4communitylib.classes.math.common_surface_identifier import CommonSurfaceIdentifier -from sims4communitylib.classes.math.common_transform import CommonTransform -from sims4communitylib.classes.math.common_vector3 import CommonVector3 -from sims4communitylib.classes.testing.common_enqueue_result import CommonEnqueueResult -from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ +from s4ap.sims4communitylib.classes.math.common_location import CommonLocation +from s4ap.sims4communitylib.classes.math.common_quaternion import CommonQuaternion +from s4ap.sims4communitylib.classes.math.common_routing_location import CommonRoutingLocation +from s4ap.sims4communitylib.classes.math.common_surface_identifier import CommonSurfaceIdentifier +from s4ap.sims4communitylib.classes.math.common_transform import CommonTransform +from s4ap.sims4communitylib.classes.math.common_vector3 import CommonVector3 +from s4ap.sims4communitylib.classes.testing.common_enqueue_result import CommonEnqueueResult +from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ CommonConsoleCommandArgument -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.location.common_location_utils import CommonLocationUtils -from sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils -from sims4communitylib.utils.sims.common_sim_interaction_utils import CommonSimInteractionUtils -from sims4communitylib.utils.sims.common_sim_type_utils import CommonSimTypeUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.location.common_location_utils import CommonLocationUtils +from s4ap.sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils +from s4ap.sims4communitylib.utils.sims.common_sim_interaction_utils import CommonSimInteractionUtils +from s4ap.sims4communitylib.utils.sims.common_sim_type_utils import CommonSimTypeUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' @@ -672,9 +672,9 @@ def is_allowed_on_current_lot(sim_info: SimInfo) -> bool: :return: True, if the Sim is allowed on the current lot. False, if not. :rtype: bool """ - from sims4communitylib.utils.common_component_utils import CommonComponentUtils - from sims4communitylib.enums.types.component_types import CommonComponentType - from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + from s4ap.sims4communitylib.utils.common_component_utils import CommonComponentUtils + from s4ap.sims4communitylib.enums.types.component_types import CommonComponentType + from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils if CommonSimLocationUtils.is_at_home(sim_info): return True if CommonSimLocationUtils.is_renting_current_lot(sim_info): diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_loot_action_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_loot_action_utils.py index 692fe48..4f93806 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_loot_action_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_loot_action_utils.py @@ -10,7 +10,7 @@ from event_testing.resolver import SingleSimResolver, DoubleSimResolver from interactions.utils.loot import LootActions from sims.sim_info import SimInfo -from sims4communitylib.utils.resources.common_loot_action_utils import CommonLootActionUtils +from s4ap.sims4communitylib.utils.resources.common_loot_action_utils import CommonLootActionUtils class CommonSimLootActionUtils: diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_motive_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_motive_utils.py index 0636d5c..baadb57 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_motive_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_motive_utils.py @@ -12,20 +12,20 @@ from sims.sim_info import SimInfo from sims4 import commands from sims4.resources import Types -from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.enums.common_species import CommonSpecies -from sims4communitylib.enums.enumtypes.common_int import CommonInt -from sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ +from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.enums.common_species import CommonSpecies +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ CommonConsoleCommandArgument -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.sims.common_occult_utils import CommonOccultUtils -from sims4communitylib.utils.sims.common_sim_statistic_utils import CommonSimStatisticUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils -from sims4communitylib.enums.motives_enum import CommonMotiveId +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.sims.common_occult_utils import CommonOccultUtils +from s4ap.sims4communitylib.utils.sims.common_sim_statistic_utils import CommonSimStatisticUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils +from s4ap.sims4communitylib.enums.motives_enum import CommonMotiveId class CommonSimMotiveUtils(_HasS4CLClassLog): diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_name_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_name_utils.py index 777d356..a7e1ab6 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_name_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_name_utils.py @@ -10,14 +10,14 @@ from sims.sim_info import SimInfo from sims.sim_spawner import SimSpawner from sims.sim_spawner_enums import SimNameType -from sims4communitylib.enums.common_gender import CommonGender -from sims4communitylib.enums.common_sim_name_type import CommonSimNameType -from sims4communitylib.enums.common_species import CommonSpecies -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ +from s4ap.sims4communitylib.enums.common_gender import CommonGender +from s4ap.sims4communitylib.enums.common_sim_name_type import CommonSimNameType +from s4ap.sims4communitylib.enums.common_species import CommonSpecies +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ CommonConsoleCommandArgument -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.misc.common_text_utils import CommonTextUtils +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.misc.common_text_utils import CommonTextUtils class CommonSimNameUtils: @@ -177,7 +177,7 @@ def create_random_last_name(gender: CommonGender, species: CommonSpecies=CommonS if sim_name_type == SimNameType.DEFAULT: last_name = SimSpawner.get_last_name(family_name, vanilla_gender, species=vanilla_species) else: - from sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils + from s4ap.sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils last_name = SimSpawner._get_family_name_for_gender(language, family_name, CommonGenderUtils.is_female_gender(gender), sim_name_type=vanilla_sim_name_type) return last_name diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_occult_type_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_occult_type_utils.py index 384a42a..6babbe9 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_occult_type_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_occult_type_utils.py @@ -9,13 +9,13 @@ from sims.occult.occult_enums import OccultType from sims.sim_info import SimInfo -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.enums.common_occult_type import CommonOccultType -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.enums.common_occult_type import CommonOccultType +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ CommonConsoleCommandArgument -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils class CommonSimOccultTypeUtils: @@ -80,7 +80,7 @@ def is_occult_type(sim_info: SimInfo, occult_type: CommonOccultType) -> CommonTe if occult_type == CommonOccultType.NON_OCCULT: # Every Sim is always a Non-Occult return CommonTestResult.TRUE - from sims4communitylib.utils.sims.common_occult_utils import CommonOccultUtils + from s4ap.sims4communitylib.utils.sims.common_occult_utils import CommonOccultUtils occult_type_mappings: Dict[CommonOccultType, Callable[[SimInfo], CommonTestResult]] = { CommonOccultType.ALIEN: CommonOccultUtils.is_alien, CommonOccultType.MERMAID: CommonOccultUtils.is_mermaid, @@ -114,7 +114,7 @@ def is_currently_occult_type(sim_info: SimInfo, occult_type: CommonOccultType) - """ if occult_type == CommonOccultType.NONE: raise AssertionError('Cannot check if Sim is currently a NONE occult!'.format(CommonSimNameUtils.get_full_name(sim_info))) - from sims4communitylib.utils.sims.common_occult_utils import CommonOccultUtils + from s4ap.sims4communitylib.utils.sims.common_occult_utils import CommonOccultUtils occult_type_mappings: Dict[CommonOccultType, Callable[[SimInfo], CommonTestResult]] = { CommonOccultType.ALIEN: CommonOccultUtils.is_currently_an_alien, CommonOccultType.MERMAID: CommonOccultUtils.is_currently_a_mermaid, @@ -142,7 +142,7 @@ def determine_occult_type(sim_info: SimInfo) -> CommonOccultType: :return: The CommonOccultType that represents what a Sim is. :rtype: CommonOccultType """ - from sims4communitylib.utils.sims.common_occult_utils import CommonOccultUtils + from s4ap.sims4communitylib.utils.sims.common_occult_utils import CommonOccultUtils if CommonOccultUtils.is_robot(sim_info): return CommonOccultType.ROBOT elif CommonOccultUtils.is_scarecrow(sim_info): @@ -177,7 +177,7 @@ def determine_current_occult_type(sim_info: SimInfo) -> CommonOccultType: :return: The CommonOccultType the Sim is currently appearing as, or CommonOccultType.NONE if they are not appearing as any Occult or are appearing as their HUMAN disguise/occult. :rtype: CommonOccultType """ - from sims4communitylib.utils.sims.common_occult_utils import CommonOccultUtils + from s4ap.sims4communitylib.utils.sims.common_occult_utils import CommonOccultUtils if CommonOccultUtils.is_currently_a_mermaid(sim_info) or CommonOccultUtils.is_mermaid_in_mermaid_form(sim_info): return CommonOccultType.MERMAID elif CommonOccultUtils.is_robot(sim_info): diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_plumbob_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_plumbob_utils.py index 7cdb2d5..0a9b923 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_plumbob_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_plumbob_utils.py @@ -7,12 +7,12 @@ """ from interactions.utils.plumbbob import unslot_plumbbob, reslot_plumbbob from sims.sim_info import SimInfo -from sims4communitylib.classes.math.common_vector3 import CommonVector3 -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ +from s4ap.sims4communitylib.classes.math.common_vector3 import CommonVector3 +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ CommonConsoleCommandArgument -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils class CommonSimPlumbobSlot: diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_posture_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_posture_utils.py index 0a7db1d..da738e5 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_posture_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_posture_utils.py @@ -10,11 +10,11 @@ from postures.posture import Posture from postures.posture_state import PostureState from sims.sim_info import SimInfo -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.enums.common_posture_id import CommonPostureId -from sims4communitylib.enums.enumtypes.common_int import CommonInt -from sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.enums.common_posture_id import CommonPostureId +from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt +from s4ap.sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils class CommonSimPostureUtils(_HasS4CLClassLog): @@ -85,8 +85,8 @@ def can_sim_be_picked_up(cls, sim_info: SimInfo) -> CommonTestResult: :return: True, if the Sim can be picked up. False, it not. :rtype: bool """ - from sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils - from sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils + from s4ap.sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils + from s4ap.sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils if CommonSpeciesUtils.is_fox(sim_info) or CommonSpeciesUtils.is_small_dog(sim_info) or CommonSpeciesUtils.is_cat(sim_info): cls.get_log().format_with_message('Success, Sim is a fox, small dog, or cat and thus may be picked up.', sim=sim_info) return CommonTestResult.TRUE @@ -96,7 +96,7 @@ def can_sim_be_picked_up(cls, sim_info: SimInfo) -> CommonTestResult: if CommonSpeciesUtils.is_human(sim_info) and (CommonAgeUtils.is_toddler(sim_info) or CommonAgeUtils.is_baby(sim_info)): cls.get_log().format_with_message('Success, Sim is a toddler or baby human and thus may be picked up.', sim=sim_info) return CommonTestResult.TRUE - from sims4communitylib.enums.strings_enum import CommonStringId + from s4ap.sims4communitylib.enums.strings_enum import CommonStringId return CommonTestResult(False, reason=f'{sim_info} cannot be picked up.', tooltip_text=CommonStringId.S4CL_SIM_CANNOT_BE_PICKED_UP, tooltip_tokens=(sim_info,)) @classmethod @@ -262,5 +262,5 @@ def load_posture_by_id(cls, posture: Union[int, CommonPostureId, Posture, Common return posture from sims4.resources import Types - from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils return CommonResourceUtils.load_instance(Types.POSTURE, posture) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_pregnancy_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_pregnancy_utils.py index 4198a3b..44ca51d 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_pregnancy_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_pregnancy_utils.py @@ -9,27 +9,27 @@ from sims.pregnancy.pregnancy_enums import PregnancyOrigin from sims.pregnancy.pregnancy_tracker import PregnancyTracker from sims.sim_info import SimInfo -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.enums.buffs_enum import CommonBuffId -from sims4communitylib.enums.common_object_state_value_ids import CommonObjectStateValueId -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.enums.traits_enum import CommonTraitId -from sims4communitylib.logging.has_class_log import HasClassLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.enums.buffs_enum import CommonBuffId +from s4ap.sims4communitylib.enums.common_object_state_value_ids import CommonObjectStateValueId +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.enums.traits_enum import CommonTraitId +from s4ap.sims4communitylib.logging.has_class_log import HasClassLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ CommonConsoleCommandArgument -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.objects.common_object_state_utils import CommonObjectStateUtils -from sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils -from sims4communitylib.utils.sims.common_buff_utils import CommonBuffUtils -from sims4communitylib.utils.sims.common_relationship_utils import CommonRelationshipUtils -from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils -from sims4communitylib.enums.statistics_enum import CommonStatisticId -from sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils -from sims4communitylib.utils.sims.common_sim_statistic_utils import CommonSimStatisticUtils +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.objects.common_object_state_utils import CommonObjectStateUtils +from s4ap.sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils +from s4ap.sims4communitylib.utils.sims.common_buff_utils import CommonBuffUtils +from s4ap.sims4communitylib.utils.sims.common_relationship_utils import CommonRelationshipUtils +from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils +from s4ap.sims4communitylib.enums.statistics_enum import CommonStatisticId +from s4ap.sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils +from s4ap.sims4communitylib.utils.sims.common_sim_statistic_utils import CommonSimStatisticUtils from statistics.commodity import Commodity @@ -218,8 +218,8 @@ def can_be_impregnated(cls, sim_info: SimInfo) -> CommonTestResult: :return: The result of testing. True, if they can. False, if they cannot. :rtype: CommonTestResult """ - from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils - from sims4communitylib.enums.traits_enum import CommonTraitId + from s4ap.sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils + from s4ap.sims4communitylib.enums.traits_enum import CommonTraitId can_be_impregnated_trait = cls.determine_can_be_impregnated_trait(sim_info) can_not_be_impregnated_trait = cls.determine_can_not_be_impregnated_trait(sim_info) if can_be_impregnated_trait is None: @@ -250,8 +250,8 @@ def can_impregnate(cls, sim_info: SimInfo) -> CommonTestResult: :return: The result of testing. True, if they can. False, if they cannot. :rtype: CommonTestResult """ - from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils - from sims4communitylib.enums.traits_enum import CommonTraitId + from s4ap.sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils + from s4ap.sims4communitylib.enums.traits_enum import CommonTraitId can_impregnate_trait = cls.determine_can_impregnate_trait(sim_info) can_not_impregnate_trait = cls.determine_can_not_impregnate_trait(sim_info) if can_impregnate_trait is None: @@ -363,7 +363,7 @@ def get_in_labor_buff(cls, sim_info: SimInfo) -> Union[int, CommonBuffId]: :rtype: Union[int, CommonBuffId] """ log = cls.get_log() - from sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils + from s4ap.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) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_rabbit_hole_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_rabbit_hole_utils.py index 677173d..84a17b6 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_rabbit_hole_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_rabbit_hole_utils.py @@ -10,9 +10,9 @@ from rabbit_hole.rabbit_hole import RabbitHole from services.rabbit_hole_service import RabbitHoleService from sims.sim_info import SimInfo -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.utils.sims.common_rabbit_hole_utils import CommonRabbitHoleUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.utils.sims.common_rabbit_hole_utils import CommonRabbitHoleUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils class CommonSimRabbitHoleUtils: diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_relationship_expectation_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_relationship_expectation_utils.py index fb38787..0fd37ab 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_relationship_expectation_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_relationship_expectation_utils.py @@ -6,10 +6,10 @@ Copyright (c) COLONOLNUTTY """ from sims.sim_info import SimInfo -from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.enums.traits_enum import CommonTraitId -from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils +from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.enums.traits_enum import CommonTraitId +from s4ap.sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils class CommonSimRelationshipExpectationUtils: diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_routing_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_routing_utils.py index 4d6ace9..142a385 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_routing_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_routing_utils.py @@ -9,16 +9,16 @@ from objects.terrain import Terrain from server.pick_info import PickType from sims.sim_info import SimInfo -from sims4communitylib.classes.math.common_surface_identifier import CommonSurfaceIdentifier -from sims4communitylib.classes.math.common_vector3 import CommonVector3 - -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.utils.common_type_utils import CommonTypeUtils -from sims4communitylib.utils.location.common_location_utils import CommonLocationUtils -from sims4communitylib.utils.location.common_terrain_utils import CommonTerrainUtils -from sims4communitylib.utils.resources.common_interaction_utils import CommonInteractionUtils -from sims4communitylib.utils.sims.common_sim_body_utils import CommonSimBodyUtils -from sims4communitylib.utils.terrain.common_terrain_location_utils import CommonTerrainLocationUtils +from s4ap.sims4communitylib.classes.math.common_surface_identifier import CommonSurfaceIdentifier +from s4ap.sims4communitylib.classes.math.common_vector3 import CommonVector3 + +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils +from s4ap.sims4communitylib.utils.location.common_location_utils import CommonLocationUtils +from s4ap.sims4communitylib.utils.location.common_terrain_utils import CommonTerrainUtils +from s4ap.sims4communitylib.utils.resources.common_interaction_utils import CommonInteractionUtils +from s4ap.sims4communitylib.utils.sims.common_sim_body_utils import CommonSimBodyUtils +from s4ap.sims4communitylib.utils.terrain.common_terrain_location_utils import CommonTerrainLocationUtils class CommonSimRoutingUtils: diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_situation_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_situation_utils.py index 14b4df9..e156636 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_situation_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_situation_utils.py @@ -10,20 +10,20 @@ from distributor.shared_messages import IconInfoData from sims.sim_info import SimInfo -from sims4communitylib.enums.situations_enum import CommonSituationId -from sims4communitylib.enums.tags_enum import CommonGameTag -from sims4communitylib.logging.has_class_log import HasClassLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ +from s4ap.sims4communitylib.enums.situations_enum import CommonSituationId +from s4ap.sims4communitylib.enums.tags_enum import CommonGameTag +from s4ap.sims4communitylib.logging.has_class_log import HasClassLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.notifications.common_basic_notification import CommonBasicNotification +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ CommonConsoleCommandArgument -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.resources.common_situation_utils import CommonSituationUtils +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.resources.common_situation_utils import CommonSituationUtils from situations.dynamic_situation_goal_tracker import DynamicSituationGoalTracker from situations.situation import Situation -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils from situations.situation_goal import SituationGoal from situations.situation_goal_targeted_sim import SituationGoalTargetedSim from situations.situation_goal_tracker import SituationGoalTracker @@ -325,7 +325,7 @@ def create_situation_for_sim( """ if sim_info is None: raise AssertionError('sim_info was None!') - from sims4communitylib.utils.resources.common_situation_utils import CommonSituationUtils + from s4ap.sims4communitylib.utils.resources.common_situation_utils import CommonSituationUtils situation_manager = CommonSituationUtils.get_situation_manager_for_zone() guest_list = SituationGuestList(invite_only=invite_only) guest_info = SituationGuestInfo.construct_from_purpose(CommonSimUtils.get_sim_id(sim_info), situation_job or situation_type.default_job(), purpose) @@ -352,7 +352,7 @@ def complete_situation_goal(sim_info: SimInfo, situation_goal_id: int, target_si :param start_cooldown: Whether or not to start a cooldown for the situation. Default is True. :type start_cooldown: bool, optional """ - from sims4communitylib.utils.sims.common_whim_utils import CommonWhimUtils + from s4ap.sims4communitylib.utils.sims.common_whim_utils import CommonWhimUtils if target_sim_info is not None: if CommonSimUtils.get_sim_instance(target_sim_info) is None: return diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_skill_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_skill_utils.py index f121632..d43dccf 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_skill_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_skill_utils.py @@ -10,12 +10,12 @@ from server_commands.argument_helpers import TunableInstanceParam from sims.sim_info import SimInfo from sims4.resources import Types -from sims4communitylib.enums.skills_enum import CommonSkillId -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ +from s4ap.sims4communitylib.enums.skills_enum import CommonSkillId +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ CommonConsoleCommandArgument -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.resources.common_skill_utils import CommonSkillUtils +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.resources.common_skill_utils import CommonSkillUtils from statistics.skill import Skill @@ -330,7 +330,7 @@ def get_all_skills_available_for_sim_gen(sim_info: SimInfo) -> Iterator[Skill]: :return: An iterator of Skills that are available for the specified Sim. :rtype: Iterator[Skill] """ - from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils sim = CommonSimUtils.get_sim_instance(sim_info) if sim is None: return tuple() diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_spawn_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_spawn_utils.py index 3db1793..ec556d8 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_spawn_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_spawn_utils.py @@ -22,35 +22,35 @@ from sims.sim_info_lod import SimInfoLODLevel from sims.sim_info_types import SpeciesExtended, SimSerializationOption from sims4.resources import Types -from sims4communitylib.classes.math.common_surface_identifier import CommonSurfaceIdentifier -from sims4communitylib.enums.common_age import CommonAge -from sims4communitylib.enums.common_bucks_types import CommonBucksType -from sims4communitylib.enums.common_death_types import CommonDeathType -from sims4communitylib.enums.common_gender import CommonGender -from sims4communitylib.enums.common_species import CommonSpecies -from sims4communitylib.enums.strings_enum import CommonStringId -from sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ +from s4ap.sims4communitylib.classes.math.common_surface_identifier import CommonSurfaceIdentifier +from s4ap.sims4communitylib.enums.common_age import CommonAge +from s4ap.sims4communitylib.enums.common_bucks_types import CommonBucksType +from s4ap.sims4communitylib.enums.common_death_types import CommonDeathType +from s4ap.sims4communitylib.enums.common_gender import CommonGender +from s4ap.sims4communitylib.enums.common_species import CommonSpecies +from s4ap.sims4communitylib.enums.strings_enum import CommonStringId +from s4ap.sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ CommonConsoleCommandArgument -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.cas.common_cas_utils import CommonCASUtils -from sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils -from sims4communitylib.utils.common_date_utils import CommonRealDateUtils -from sims4communitylib.utils.common_log_registry import CommonLogRegistry -from sims4communitylib.utils.common_resource_utils import CommonResourceUtils -from sims4communitylib.utils.common_time_utils import CommonTimeUtils -from sims4communitylib.utils.math.common_bitwise_utils import CommonBitwiseUtils -from sims4communitylib.utils.resources.common_game_pack_utils import CommonGamePackUtils -from sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils -from sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils -from sims4communitylib.utils.sims.common_sim_death_utils import CommonSimDeathUtils -from sims4communitylib.utils.sims.common_sim_location_utils import CommonSimLocationUtils -from sims4communitylib.classes.math.common_location import CommonLocation -from sims4communitylib.classes.math.common_vector3 import CommonVector3 -from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.cas.common_cas_utils import CommonCASUtils +from s4ap.sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils +from s4ap.sims4communitylib.utils.common_date_utils import CommonRealDateUtils +from s4ap.sims4communitylib.utils.common_log_registry import CommonLogRegistry +from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils +from s4ap.sims4communitylib.utils.common_time_utils import CommonTimeUtils +from s4ap.sims4communitylib.utils.math.common_bitwise_utils import CommonBitwiseUtils +from s4ap.sims4communitylib.utils.resources.common_game_pack_utils import CommonGamePackUtils +from s4ap.sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils +from s4ap.sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils +from s4ap.sims4communitylib.utils.sims.common_sim_death_utils import CommonSimDeathUtils +from s4ap.sims4communitylib.utils.sims.common_sim_location_utils import CommonSimLocationUtils +from s4ap.sims4communitylib.classes.math.common_location import CommonLocation +from s4ap.sims4communitylib.classes.math.common_vector3 import CommonVector3 +from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils from statistics.commodity import Commodity from statistics.life_skill_statistic import LifeSkillStatistic from statistics.ranked_statistic import RankedStatistic @@ -524,7 +524,7 @@ def _create_sim_info( household: Household = None, source: str = 'testing' ) -> Union[SimInfo, None]: - from sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils + from s4ap.sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils household = household or CommonHouseholdUtils.create_empty_household(as_hidden_household=True) vanilla_gender = CommonGender.convert_to_vanilla(gender) vanilla_age = CommonAge.convert_to_vanilla(age) @@ -534,7 +534,7 @@ def _create_sim_info( first_name = first_name or CommonSimNameUtils.create_random_first_name(gender, species=species) last_name = last_name or CommonSimNameUtils.create_random_last_name(gender, species=species) traits = tuple([CommonTraitUtils.load_trait_by_id(trait_id) for trait_id in trait_ids if CommonTraitUtils.load_trait_by_id(trait_id) is not None]) - from sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils + from s4ap.sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils sim_creator = SimCreator( gender=vanilla_gender, age=vanilla_age, @@ -580,7 +580,7 @@ def spawn_sim( return False if CommonSimUtils.get_sim_instance(sim_info) is not None: return True - from sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils + from s4ap.sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils if CommonAgeUtils.is_baby(sim_info): # Sim is baby, they spawn differently. from sims.baby.baby_utils import create_and_place_baby @@ -618,8 +618,8 @@ def spawn_sim_at_active_sim_location( :return: True, if the Sim was spawned successfully. False, if not. :rtype: bool """ - from sims4communitylib.utils.sims.common_sim_location_utils import CommonSimLocationUtils - from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + from s4ap.sims4communitylib.utils.sims.common_sim_location_utils import CommonSimLocationUtils + from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils active_sim_info = CommonSimUtils.get_active_sim_info() active_location = CommonSimLocationUtils.get_location(active_sim_info) active_position = None @@ -647,7 +647,7 @@ def clone_sim( :return: The cloned Sim Info or None if cloning failed. :rtype: Union[SimInfo, None] """ - from sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils + from s4ap.sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils if household_override is not None: household = household_override else: @@ -766,7 +766,7 @@ def _load_sim_data( return None first_name: str = sim_save_data.get('first_name', None) last_name: str = sim_save_data.get('last_name', None) - from sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils + from s4ap.sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils household = household or CommonHouseholdUtils.create_empty_household(as_hidden_household=True) vanilla_gender = CommonGender.convert_to_vanilla(gender) vanilla_age = CommonAge.convert_to_vanilla(age) @@ -777,7 +777,7 @@ def _load_sim_data( first_name = first_name or CommonSimNameUtils.create_random_first_name(gender, species=species) last_name = last_name or CommonSimNameUtils.create_random_last_name(gender, species=species) traits = tuple([CommonTraitUtils.load_trait_by_id(trait_id) for trait_id in trait_ids if CommonTraitUtils.load_trait_by_id(trait_id) is not None]) - from sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils + from s4ap.sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils breed_name = sim_save_data.get('breed_name', '') first_name_key = sim_save_data.get('first_name_key', 0) last_name_key = sim_save_data.get('last_name_key', 0) @@ -836,7 +836,7 @@ def _load_sim_data( indexed_manager.object_load_times[species_def].time_spent_loading += time_elapsed indexed_manager.object_load_times[species_def].loads += 1 lod_logger.info('Loaded {} with lod {} in {} seconds.', sim_info.full_name, sim_info._lod.name, time_elapsed) - from sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils + from s4ap.sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils current_outfit = CommonOutfitUtils.get_current_outfit(sim_info) sim_info.outfit_type_and_index = current_outfit sim_info.resend_outfits() @@ -849,7 +849,7 @@ def _load_sim_data( indexed_manager.object_load_times[species_def].time_spent_loading += time_elapsed indexed_manager.object_load_times[species_def].loads += 1 lod_logger.info('Loaded {} with lod {} in {} seconds.', sim_info.full_name, sim_info._lod.name, time_elapsed) - from sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils + from s4ap.sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils current_outfit = CommonOutfitUtils.get_current_outfit(sim_info) sim_info._base.outfit_type_and_index = current_outfit sim_info.resend_outfits() @@ -2593,7 +2593,7 @@ def despawn_sim( """ if sim_info is None: return False - from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils sim = CommonSimUtils.get_sim_instance(sim_info) if sim is None: return True @@ -2628,7 +2628,7 @@ def schedule_sim_for_despawn( """ if sim_info is None: return False - from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils + from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils sim = CommonSimUtils.get_sim_instance(sim_info) if sim is None: if on_despawn is not None: @@ -3073,7 +3073,7 @@ def _s4cl_purge_non_household(output: CommonConsoleCommandOutput): output('Purging all Sims outside of the Active Household.') sim_count = 0 sim_info_list = tuple(CommonSimUtils.get_sim_info_for_all_sims_generator()) - from sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils + from s4ap.sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils for sim_info in sim_info_list: if CommonHouseholdUtils.is_part_of_active_household(sim_info): continue diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_spell_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_spell_utils.py index a997863..6e37472 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_spell_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_spell_utils.py @@ -10,12 +10,12 @@ from server_commands.argument_helpers import TunableInstanceParam from sims.sim_info import SimInfo from sims4.resources import Types -from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ +from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ CommonConsoleCommandArgument -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.common_resource_utils import CommonResourceUtils +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils from spells.spells import Spell @@ -53,7 +53,7 @@ def add_spells(cls, sim_info: SimInfo, spells: Tuple[Union[int, Spell]], mark_as :return: The result of executing the function. True, if successful. False, if not. :rtype: CommonExecutionResult """ - from sims4communitylib.utils.sims.common_sim_unlock_utils import CommonSimUnlockUtils + from s4ap.sims4communitylib.utils.sims.common_sim_unlock_utils import CommonSimUnlockUtils unlock_tracker = CommonSimUnlockUtils.get_unlock_tracker(sim_info) if unlock_tracker is None: return CommonExecutionResult(False, reason=f'Failed to locate the unlock tracker for {sim_info}') @@ -76,7 +76,7 @@ def add_all_spells(cls, sim_info: SimInfo) -> CommonExecutionResult: :return: The result of executing the function. True, if successful. False, if not. :rtype: CommonExecutionResult """ - from sims4communitylib.utils.sims.common_sim_unlock_utils import CommonSimUnlockUtils + from s4ap.sims4communitylib.utils.sims.common_sim_unlock_utils import CommonSimUnlockUtils unlock_tracker = CommonSimUnlockUtils.get_unlock_tracker(sim_info) if unlock_tracker is None: return CommonExecutionResult(False, reason=f'Failed to locate the unlock tracker for {sim_info}') @@ -111,7 +111,7 @@ def remove_spells(cls, sim_info: SimInfo, spells: Tuple[Union[int, Spell]]) -> C :return: The result of executing the function. True, if successful. False, if not. :rtype: CommonExecutionResult """ - from sims4communitylib.utils.sims.common_sim_unlock_utils import CommonSimUnlockUtils + from s4ap.sims4communitylib.utils.sims.common_sim_unlock_utils import CommonSimUnlockUtils unlock_tracker = CommonSimUnlockUtils.get_unlock_tracker(sim_info) if unlock_tracker is None: return CommonExecutionResult(False, reason=f'Failed to locate the unlock tracker for {sim_info}') @@ -154,7 +154,7 @@ def remove_all_spells(cls, sim_info: SimInfo) -> CommonExecutionResult: :return: The result of executing the function. True, if successful. False, if not. :rtype: CommonExecutionResult """ - from sims4communitylib.utils.sims.common_sim_unlock_utils import CommonSimUnlockUtils + from s4ap.sims4communitylib.utils.sims.common_sim_unlock_utils import CommonSimUnlockUtils unlock_tracker = CommonSimUnlockUtils.get_unlock_tracker(sim_info) if unlock_tracker is None: return CommonExecutionResult(False, reason=f'Failed to locate the unlock tracker for {sim_info}') @@ -192,7 +192,7 @@ def load_spell_by_id(cls, spell: Union[int, Spell]) -> Union[Spell, None]: return spell from sims4.resources import Types - from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils return CommonResourceUtils.load_instance(Types.SPELL, spell) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_state_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_state_utils.py index 3f76308..8ab7670 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_state_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_state_utils.py @@ -7,10 +7,10 @@ """ import services from sims.sim_info import SimInfo -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.enums.buffs_enum import CommonBuffId -from sims4communitylib.utils.sims.common_buff_utils import CommonBuffUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.enums.buffs_enum import CommonBuffId +from s4ap.sims4communitylib.utils.sims.common_buff_utils import CommonBuffUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils class CommonSimStateUtils: @@ -43,7 +43,7 @@ def is_wearing_towel(sim_info: SimInfo) -> CommonTestResult: :return: The result of testing. True, if the sim is wearing a towel. False, if not. :rtype: CommonTestResult """ - from sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils + from s4ap.sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils return CommonOutfitUtils.is_wearing_towel(sim_info) @staticmethod @@ -57,7 +57,7 @@ def is_in_sunlight(sim_info: SimInfo) -> bool: :return: True, if the Sim is in sunlight. False, if the Sim is not in sunlight. :rtype: bool """ - from sims4communitylib.utils.common_time_utils import CommonTimeUtils + from s4ap.sims4communitylib.utils.common_time_utils import CommonTimeUtils sim = CommonSimUtils.get_sim_instance(sim_info) return CommonTimeUtils.get_time_service().is_in_sunlight(sim) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_statistic_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_statistic_utils.py index 613c6e8..f166e7e 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_statistic_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_statistic_utils.py @@ -12,21 +12,21 @@ from server_commands.argument_helpers import TunableInstanceParam from sims.sim_info import SimInfo from sims4.resources import Types -from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.enums.statistics_enum import CommonStatisticId -from sims4communitylib.enums.types.component_types import CommonComponentType -from sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ +from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.enums.statistics_enum import CommonStatisticId +from s4ap.sims4communitylib.enums.types.component_types import CommonComponentType +from s4ap.sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.notifications.common_basic_notification import CommonBasicNotification +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ CommonConsoleCommandArgument -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.common_component_utils import CommonComponentUtils -from sims4communitylib.utils.common_log_registry import CommonLogRegistry -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.resources.common_statistic_utils import CommonStatisticUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.common_component_utils import CommonComponentUtils +from s4ap.sims4communitylib.utils.common_log_registry import CommonLogRegistry +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.resources.common_statistic_utils import CommonStatisticUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils from statistics.base_statistic import BaseStatistic diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_type_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_type_utils.py index 32ec646..1ca927c 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_type_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_type_utils.py @@ -7,16 +7,16 @@ """ from typing import Dict, Iterator from sims.sim_info import SimInfo -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.enums.common_age import CommonAge -from sims4communitylib.enums.common_occult_type import CommonOccultType -from sims4communitylib.enums.common_species import CommonSpecies -from sims4communitylib.enums.sim_type import CommonSimType -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.enums.common_age import CommonAge +from s4ap.sims4communitylib.enums.common_occult_type import CommonOccultType +from s4ap.sims4communitylib.enums.common_species import CommonSpecies +from s4ap.sims4communitylib.enums.sim_type import CommonSimType +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ CommonConsoleCommandArgument -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.sims.common_occult_utils import CommonOccultUtils +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.sims.common_occult_utils import CommonOccultUtils class CommonSimTypeUtils: @@ -2292,8 +2292,8 @@ def is_service_sim(sim_info: SimInfo) -> CommonTestResult: """ if sim_info is None: raise AssertionError('Sim Info was None!') - from sims4communitylib.enums.traits_enum import CommonTraitId - from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils + from s4ap.sims4communitylib.enums.traits_enum import CommonTraitId + from s4ap.sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils trait_ids = ( CommonTraitId.IS_BUTLER, CommonTraitId.IS_CHALET_GARDENS_GHOST, @@ -2338,8 +2338,8 @@ def is_batuu_alien(sim_info: SimInfo) -> CommonTestResult: """ if sim_info is None: raise AssertionError('Sim Info was None!') - from sims4communitylib.enums.traits_enum import CommonTraitId - from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils + from s4ap.sims4communitylib.enums.traits_enum import CommonTraitId + from s4ap.sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils trait_ids = ( CommonTraitId.BATUU_ALIEN_BITH, # trait_Batuu_Alien_Bith CommonTraitId.BATUU_ALIEN_TWILEK, # trait_Batuu_Alien_Twilek @@ -2408,7 +2408,7 @@ def get_all_sim_types_gen(sim_info: SimInfo, combine_teen_young_adult_and_elder_ raise AssertionError('Sim Info was None!') species = CommonSpecies.get_species(sim_info) age = CommonAge.get_age(sim_info) - from sims4communitylib.utils.sims.common_sim_occult_type_utils import CommonSimOccultTypeUtils + from s4ap.sims4communitylib.utils.sims.common_sim_occult_type_utils import CommonSimOccultTypeUtils for occult_type in CommonSimOccultTypeUtils.get_all_occult_types_for_sim_gen(sim_info): if CommonOccultUtils.is_robot(sim_info) and occult_type == CommonOccultType.NON_OCCULT: continue diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_utils.py index 8a0c3e0..def8317 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_utils.py @@ -13,14 +13,14 @@ from sims.sim_info import SimInfo from sims.sim_info_base_wrapper import SimInfoBaseWrapper from sims.sim_info_manager import SimInfoManager -from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ +from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ CommonConsoleCommandArgument -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from sims4communitylib.utils.misc.common_game_client_utils import CommonGameClientUtils +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils +from s4ap.sims4communitylib.utils.misc.common_game_client_utils import CommonGameClientUtils class CommonSimUtils: @@ -122,7 +122,7 @@ def get_sim_info_for_all_sims_with_last_name_generator(cls, last_name: str) -> I :return: An iterator of Sims found with the specified last name. :rtype: Iterator[SimInfo] """ - from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils + from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils last_name = last_name.lower() def _has_last_name(sim_info: SimInfo) -> bool: @@ -141,7 +141,7 @@ def get_sim_info_for_all_sims_with_first_name_generator(cls, first_name: str) -> :return: An iterator of Sims found with the specified first name. :rtype: Iterator[SimInfo] """ - from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils + from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils first_name = first_name.lower() def _has_first_name(sim_info: SimInfo) -> bool: @@ -162,7 +162,7 @@ def get_sim_info_for_all_sims_with_name_generator(cls, first_name: str, last_nam :return: An iterator of Sims found with the specified first and last name. :rtype: Iterator[SimInfo] """ - from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils + from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils first_name = first_name.lower() last_name = last_name.lower() diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_voice_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_voice_utils.py index 5efd458..2251602 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_voice_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_voice_utils.py @@ -7,20 +7,20 @@ """ from typing import Union, Dict, List, Tuple from sims.sim_info import SimInfo -from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.enums.common_age import CommonAge -from sims4communitylib.enums.common_gender import CommonGender -from sims4communitylib.enums.common_species import CommonSpecies -from sims4communitylib.enums.common_voice_actor_type import CommonVoiceActorType -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ +from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.enums.common_age import CommonAge +from s4ap.sims4communitylib.enums.common_gender import CommonGender +from s4ap.sims4communitylib.enums.common_species import CommonSpecies +from s4ap.sims4communitylib.enums.common_voice_actor_type import CommonVoiceActorType +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ CommonConsoleCommandArgument -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.common_log_registry import CommonLogRegistry -from sims4communitylib.utils.common_resource_utils import CommonResourceUtils -from sims4communitylib.utils.sims.common_sim_type_utils import CommonSimTypeUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.common_log_registry import CommonLogRegistry +from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils +from s4ap.sims4communitylib.utils.sims.common_sim_type_utils import CommonSimTypeUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils class CommonSimVoiceUtils: @@ -138,7 +138,7 @@ def set_to_default_voice(sim_info: SimInfo) -> CommonExecutionResult: :return: The result of setting the voice of the Sim to their default voice. True, if successful. False, if not. :rtype: CommonExecutionResult """ - from sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils + from s4ap.sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils if CommonGenderUtils.is_male(sim_info): return CommonSimVoiceUtils.set_to_default_male_voice(sim_info) else: @@ -155,9 +155,9 @@ def set_to_default_male_voice(sim_info: SimInfo) -> CommonExecutionResult: :return: The result of setting the voice of the Sim to the default male voice. True, if successful. False, if not. :rtype: CommonExecutionResult """ - from sims4communitylib.utils.sims.common_age_species_utils import CommonAgeSpeciesUtils - from sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils - from sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils + from s4ap.sims4communitylib.utils.sims.common_age_species_utils import CommonAgeSpeciesUtils + from s4ap.sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils + from s4ap.sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils if CommonAgeSpeciesUtils.is_teen_adult_or_elder_human(sim_info): return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.ADULT_HUMAN_MASCULINE_1) elif CommonAgeSpeciesUtils.is_child_human(sim_info): @@ -195,9 +195,9 @@ def set_to_default_female_voice(sim_info: SimInfo) -> CommonExecutionResult: :return: The result of setting the voice of the Sim to the default female voice. True, if successful. False, if not. :rtype: CommonExecutionResult """ - from sims4communitylib.utils.sims.common_age_species_utils import CommonAgeSpeciesUtils - from sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils - from sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils + from s4ap.sims4communitylib.utils.sims.common_age_species_utils import CommonAgeSpeciesUtils + from s4ap.sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils + from s4ap.sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils if CommonAgeSpeciesUtils.is_teen_adult_or_elder_human(sim_info): return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.ADULT_HUMAN_FEMININE_1) elif CommonAgeSpeciesUtils.is_child_human(sim_info): @@ -235,9 +235,9 @@ def determine_available_voice_types(sim_info: SimInfo) -> Tuple[CommonVoiceActor :return: A collection of voice actor types available for the Sim. :rtype: Tuple[CommonVoiceActorType] """ - from sims4communitylib.utils.sims.common_age_species_utils import CommonAgeSpeciesUtils - from sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils - from sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils + from s4ap.sims4communitylib.utils.sims.common_age_species_utils import CommonAgeSpeciesUtils + from s4ap.sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils + from s4ap.sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils if CommonAgeSpeciesUtils.is_teen_adult_or_elder_human(sim_info): # noinspection PyTypeChecker result: Tuple[CommonVoiceActorType] = ( diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_walkstyle_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_walkstyle_utils.py index 4aaaeed..c9ed591 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_walkstyle_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_walkstyle_utils.py @@ -8,8 +8,8 @@ from typing import Union from routing.walkstyle.walkstyle_tuning import Walkstyle from sims.sim_info import SimInfo -from sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils class CommonSimWalkstyleUtils(_HasS4CLClassLog): diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_species_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_species_utils.py index 2dc90df..995fd81 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_species_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_species_utils.py @@ -9,10 +9,10 @@ from sims.sim_info import SimInfo from sims.sim_info_types import Species, SpeciesExtended -from sims4communitylib.enums.traits_enum import CommonTraitId -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.utils.common_log_registry import CommonLogRegistry -from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils +from s4ap.sims4communitylib.enums.traits_enum import CommonTraitId +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.utils.common_log_registry import CommonLogRegistry +from s4ap.sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils log = CommonLogRegistry.get().register_log(ModInfo.get_identity(), 'common_species_utils') @@ -75,7 +75,7 @@ def are_same_species(cls, sim_info: SimInfo, other_sim_info: SimInfo) -> bool: raise AssertionError('Argument sim_info was None') if other_sim_info is None: raise AssertionError('Argument other_sim_info was None') - from sims4communitylib.enums.common_species import CommonSpecies + from s4ap.sims4communitylib.enums.common_species import CommonSpecies species_one = CommonSpecies.get_species(sim_info) species_two = CommonSpecies.get_species(other_sim_info) log.format(species_one=species_one, species_two=species_two, sim_one=sim_info, other_sim_info=other_sim_info) @@ -275,8 +275,8 @@ def is_large_dog(cls, sim_info: SimInfo) -> bool: :return: True, if the Sim is a Large Dog. False, if not. :rtype: bool """ - from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils - from sims4communitylib.enums.traits_enum import CommonTraitId + from s4ap.sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils + from s4ap.sims4communitylib.enums.traits_enum import CommonTraitId return cls.is_dog_species(cls.get_species(sim_info)) and CommonTraitUtils.has_trait(sim_info, CommonTraitId.SPECIES_EXTENDED_LARGE_DOGS) @classmethod @@ -290,8 +290,8 @@ def is_small_dog(cls, sim_info: SimInfo) -> bool: :return: True, if the Sim is a Small Dog. False, if not. :rtype: bool """ - from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils - from sims4communitylib.enums.traits_enum import CommonTraitId + from s4ap.sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils + from s4ap.sims4communitylib.enums.traits_enum import CommonTraitId return cls.is_dog_species(cls.get_species(sim_info)) and CommonTraitUtils.has_trait(sim_info, CommonTraitId.SPECIES_EXTENDED_SMALL_DOGS) @classmethod @@ -305,8 +305,8 @@ def is_cat(cls, sim_info: SimInfo) -> bool: :return: True, if the Sim is a Cat. False, if not. :rtype: bool """ - from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils - from sims4communitylib.enums.traits_enum import CommonTraitId + from s4ap.sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils + from s4ap.sims4communitylib.enums.traits_enum import CommonTraitId return cls.is_cat_species(cls.get_species(sim_info)) or CommonTraitUtils.has_trait(sim_info, CommonTraitId.SPECIES_CAT) @classmethod diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_trait_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_trait_utils.py index a73b593..0acc1eb 100644 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_trait_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/sims/common_trait_utils.py @@ -15,17 +15,17 @@ from sims.sim_info import SimInfo from sims.sim_info_base_wrapper import SimInfoBaseWrapper from sims4.resources import Types -from sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from sims4communitylib.classes.testing.common_test_result import CommonTestResult -from sims4communitylib.enums.traits_enum import CommonTraitId -from sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.notifications.common_basic_notification import CommonBasicNotification -from sims4communitylib.services.commands.common_console_command import CommonConsoleCommandArgument, \ +from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult +from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult +from s4ap.sims4communitylib.enums.traits_enum import CommonTraitId +from s4ap.sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.notifications.common_basic_notification import CommonBasicNotification +from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommandArgument, \ CommonConsoleCommand -from sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput +from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils from traits.traits import Trait @@ -621,7 +621,7 @@ def is_service_sim(cls, sim_info: SimInfo) -> CommonTestResult: ..warning:: Obsolete: Use :func:`~is_service_sim` in :class:`.CommonSimTypeUtils` instead. """ - from sims4communitylib.utils.sims.common_sim_type_utils import CommonSimTypeUtils + from s4ap.sims4communitylib.utils.sims.common_sim_type_utils import CommonSimTypeUtils return CommonSimTypeUtils.is_service_sim(sim_info) @classmethod @@ -808,7 +808,7 @@ def has_masculine_frame(cls, sim_info: SimInfo) -> CommonTestResult: :return: The result of testing. True, if the Sim has a masculine frame. False, if not. :rtype: CommonTestResult """ - from sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils + from s4ap.sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils return CommonSimGenderOptionUtils.has_masculine_frame(sim_info) @classmethod @@ -822,7 +822,7 @@ def has_feminine_frame(cls, sim_info: SimInfo) -> CommonTestResult: :return: The result of testing. True, if the Sim has a feminine frame. False, if not. :rtype: CommonTestResult """ - from sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils + from s4ap.sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils return CommonSimGenderOptionUtils.has_feminine_frame(sim_info) @classmethod @@ -836,7 +836,7 @@ def prefers_menswear(cls, sim_info: SimInfo) -> CommonTestResult: :return: The result of testing. True, if the Sim prefers menswear. False, if not. :rtype: CommonTestResult """ - from sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils + from s4ap.sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils return CommonSimGenderOptionUtils.prefers_menswear(sim_info) @classmethod @@ -850,7 +850,7 @@ def prefers_womenswear(cls, sim_info: SimInfo) -> CommonTestResult: :return: The result of testing. True, if the Sim prefers womenswear. False, if not. :rtype: CommonTestResult """ - from sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils + from s4ap.sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils return CommonSimGenderOptionUtils.prefers_womenswear(sim_info) @classmethod @@ -867,7 +867,7 @@ def can_impregnate(cls, sim_info: SimInfo) -> CommonTestResult: :return: The result of testing. True, if the Sim can impregnate other Sims. False, if not. :rtype: CommonTestResult """ - from sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils + from s4ap.sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils return CommonSimGenderOptionUtils.can_impregnate(sim_info) @classmethod @@ -884,7 +884,7 @@ def can_not_impregnate(cls, sim_info: SimInfo) -> CommonTestResult: :return: The result of testing. True, if the Sim can not impregnate other Sims. False, if not. :rtype: CommonTestResult """ - from sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils + from s4ap.sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils return CommonSimGenderOptionUtils.can_not_impregnate(sim_info) @classmethod @@ -901,7 +901,7 @@ def can_be_impregnated(cls, sim_info: SimInfo) -> CommonTestResult: :return: The result of testing. True, if the Sim can be impregnated. False, if not. :rtype: CommonTestResult """ - from sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils + from s4ap.sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils return CommonSimGenderOptionUtils.can_be_impregnated(sim_info) @classmethod @@ -918,7 +918,7 @@ def can_not_be_impregnated(cls, sim_info: SimInfo) -> CommonTestResult: :return: The result of testing. True, if the Sim can not be impregnated. False, if not. :rtype: CommonTestResult """ - from sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils + from s4ap.sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils return CommonSimGenderOptionUtils.can_not_be_impregnated(sim_info) @classmethod @@ -938,7 +938,7 @@ def can_create_pregnancy(cls, sim_info: SimInfo) -> CommonTestResult: :return: The result of testing. True, if the Sim can create pregnancies. False, if not. :rtype: CommonTestResult """ - from sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils + from s4ap.sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils return CommonSimGenderOptionUtils.can_create_pregnancy(sim_info) @classmethod @@ -955,7 +955,7 @@ def can_reproduce(cls, sim_info: SimInfo) -> CommonTestResult: :return: The result of testing. True, if the Sim can reproduce. False, if not. :rtype: CommonTestResult """ - from sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils + from s4ap.sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils return CommonSimGenderOptionUtils.can_reproduce(sim_info) @classmethod @@ -972,7 +972,7 @@ def can_not_reproduce(cls, sim_info: SimInfo) -> CommonTestResult: :return: The result of testing. True, if the Sim can not reproduce. False, if not. :rtype: CommonTestResult """ - from sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils + from s4ap.sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils return CommonSimGenderOptionUtils.can_not_reproduce(sim_info) @classmethod @@ -986,7 +986,7 @@ def uses_toilet_standing(cls, sim_info: SimInfo) -> CommonTestResult: :return: The result of testing. True, if the Sim uses toilets while standing. False, if not. :rtype: CommonTestResult """ - from sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils + from s4ap.sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils return CommonSimGenderOptionUtils.uses_toilet_standing(sim_info) @classmethod @@ -1000,7 +1000,7 @@ def uses_toilet_sitting(cls, sim_info: SimInfo) -> CommonTestResult: :return: The result of testing. True, if the Sim uses toilets while sitting. False, if not. :rtype: CommonTestResult """ - from sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils + from s4ap.sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils return CommonSimGenderOptionUtils.uses_toilet_sitting(sim_info) @classmethod @@ -1527,7 +1527,7 @@ def load_trait_by_id(cls, trait: Union[int, CommonTraitId, Trait]) -> Union[Trai return trait from sims4.resources import Types - from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils return CommonResourceUtils.load_instance(Types.TRAIT, trait) diff --git a/Scripts/s4ap/sims4communitylib/utils/terrain/common_terrain_interaction_utils.py b/Scripts/s4ap/sims4communitylib/utils/terrain/common_terrain_interaction_utils.py index 7ebbaab..fb24aa0 100644 --- a/Scripts/s4ap/sims4communitylib/utils/terrain/common_terrain_interaction_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/terrain/common_terrain_interaction_utils.py @@ -11,12 +11,12 @@ from routing import SurfaceType from server.pick_info import PickType from sims.sim_info import SimInfo -from sims4communitylib.classes.math.common_surface_identifier import CommonSurfaceIdentifier -from sims4communitylib.classes.math.common_vector3 import CommonVector3 -from sims4communitylib.logging.has_class_log import HasClassLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils +from s4ap.sims4communitylib.classes.math.common_surface_identifier import CommonSurfaceIdentifier +from s4ap.sims4communitylib.classes.math.common_vector3 import CommonVector3 +from s4ap.sims4communitylib.logging.has_class_log import HasClassLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils class CommonTerrainInteractionUtils(HasClassLog): @@ -49,7 +49,7 @@ def build_terrain_point_and_interaction_context_from_sim_and_position(sim_info: :return: A tuple of the terrain point and the interaction context created from the position and surface level for the Sim or (None, None) if an error occurs. :rtype: Tuple[Union[TerrainPoint, None], Union[InteractionContext, None]] """ - from sims4communitylib.utils.location.common_location_utils import CommonLocationUtils + from s4ap.sims4communitylib.utils.location.common_location_utils import CommonLocationUtils from server_commands.sim_commands import _build_terrain_interaction_target_and_context sim = CommonSimUtils.get_sim_instance(sim_info) if sim is None: diff --git a/Scripts/s4ap/sims4communitylib/utils/terrain/common_terrain_location_utils.py b/Scripts/s4ap/sims4communitylib/utils/terrain/common_terrain_location_utils.py index 0bd7d17..6844cd1 100644 --- a/Scripts/s4ap/sims4communitylib/utils/terrain/common_terrain_location_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/terrain/common_terrain_location_utils.py @@ -8,8 +8,8 @@ from typing import Union from objects.terrain import Terrain -from sims4communitylib.classes.math.common_surface_identifier import CommonSurfaceIdentifier -from sims4communitylib.classes.math.common_vector3 import CommonVector3 +from s4ap.sims4communitylib.classes.math.common_surface_identifier import CommonSurfaceIdentifier +from s4ap.sims4communitylib.classes.math.common_vector3 import CommonVector3 class CommonTerrainLocationUtils: diff --git a/Scripts/s4ap/sims4communitylib/utils/time/common_alarm_utils.py b/Scripts/s4ap/sims4communitylib/utils/time/common_alarm_utils.py index a80df26..edf3c01 100644 --- a/Scripts/s4ap/sims4communitylib/utils/time/common_alarm_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/time/common_alarm_utils.py @@ -7,11 +7,11 @@ """ import os from typing import Callable, Any, Union -from sims4communitylib.classes.time.common_alarm_handle import CommonAlarmHandle -from sims4communitylib.logging.has_class_log import HasClassLog -from sims4communitylib.mod_support.mod_identity import CommonModIdentity -from sims4communitylib.modinfo import ModInfo -from sims4communitylib.utils.common_time_utils import CommonTimeUtils +from s4ap.sims4communitylib.classes.time.common_alarm_handle import CommonAlarmHandle +from s4ap.sims4communitylib.logging.has_class_log import HasClassLog +from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity +from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.sims4communitylib.utils.common_time_utils import CommonTimeUtils ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' diff --git a/Scripts/s4ap/sims4communitylib/utils/whims/common_satisfaction_reward_store_utils.py b/Scripts/s4ap/sims4communitylib/utils/whims/common_satisfaction_reward_store_utils.py index 60f3e59..2aa7a96 100644 --- a/Scripts/s4ap/sims4communitylib/utils/whims/common_satisfaction_reward_store_utils.py +++ b/Scripts/s4ap/sims4communitylib/utils/whims/common_satisfaction_reward_store_utils.py @@ -9,8 +9,8 @@ import sims4.collections from rewards.reward import Reward -from sims4communitylib.utils.common_resource_utils import CommonResourceUtils -from sims4communitylib.utils.whims.common_satisfaction_reward_store_item import CommonSatisfactionRewardStoreItem +from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils +from s4ap.sims4communitylib.utils.whims.common_satisfaction_reward_store_item import CommonSatisfactionRewardStoreItem # noinspection PyBroadException try: @@ -168,5 +168,5 @@ def _load_reward_instance(reward_definition_id: int) -> Reward: return reward_definition_id from sims4.resources import Types - from sims4communitylib.utils.common_resource_utils import CommonResourceUtils + from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils return CommonResourceUtils.load_instance(Types.REWARD, reward_definition_id) From 81a3bde8f1efb728e7271f51c5e71a8ede21a491 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 15:10:59 -0600 Subject: [PATCH 057/134] oops bad import again --- Scripts/s4ap/utils/s4ap_save_utils.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Scripts/s4ap/utils/s4ap_save_utils.py b/Scripts/s4ap/utils/s4ap_save_utils.py index 3c68133..007cf4b 100644 --- a/Scripts/s4ap/utils/s4ap_save_utils.py +++ b/Scripts/s4ap/utils/s4ap_save_utils.py @@ -1,3 +1,5 @@ +from typing import Any + import services class S4APSaveUtils: From b99a823078053abd4409165b1973588196dd9221 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 15:11:23 -0600 Subject: [PATCH 058/134] oops forgot an import lol --- Scripts/s4ap/utils/s4ap_save_utils.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Scripts/s4ap/utils/s4ap_save_utils.py b/Scripts/s4ap/utils/s4ap_save_utils.py index 3c68133..007cf4b 100644 --- a/Scripts/s4ap/utils/s4ap_save_utils.py +++ b/Scripts/s4ap/utils/s4ap_save_utils.py @@ -1,3 +1,5 @@ +from typing import Any + import services class S4APSaveUtils: From 9f606db5e4faa30ce5bfcb810b80095dcfe8e0f2 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 15:18:47 -0600 Subject: [PATCH 059/134] maybe this will fix it? --- Scripts/s4ap/sims4communitylib/s4cl_configuration.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/s4ap/sims4communitylib/s4cl_configuration.py b/Scripts/s4ap/sims4communitylib/s4cl_configuration.py index e73a007..45cf240 100644 --- a/Scripts/s4ap/sims4communitylib/s4cl_configuration.py +++ b/Scripts/s4ap/sims4communitylib/s4cl_configuration.py @@ -11,7 +11,7 @@ from s4ap.sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler from s4ap.sims4communitylib.logging.has_log import HasLog from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo +from s4ap.modinfo import ModInfo from s4ap.sims4communitylib.services.common_service import CommonService from s4ap.sims4communitylib.utils.common_json_io_utils import CommonJSONIOUtils from s4ap.sims4communitylib.utils.common_log_registry import CommonMessageType From 261cdb3015e9f7be7be366bc88f454307aef18bc Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 15:21:32 -0600 Subject: [PATCH 060/134] this should be the last import fix for this branch (please) --- Scripts/s4ap/utils/s4ap_game_client_utils.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Scripts/s4ap/utils/s4ap_game_client_utils.py b/Scripts/s4ap/utils/s4ap_game_client_utils.py index 9f993d3..548ed95 100644 --- a/Scripts/s4ap/utils/s4ap_game_client_utils.py +++ b/Scripts/s4ap/utils/s4ap_game_client_utils.py @@ -1,4 +1,7 @@ +from typing import Union + import services +from server.client import Client from server.clientmanager import ClientManager class S4APGameClientUtils: From 871803a58faee4ee2b6de671dbf4bb4d0053b751 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 15:29:42 -0600 Subject: [PATCH 061/134] move the skillutils class up??? it's not working for whatever reason and idk why and i want to cry --- Scripts/s4ap/utils/s4ap_skill_utils.py | 115 ++++++++++++------------- 1 file changed, 57 insertions(+), 58 deletions(-) diff --git a/Scripts/s4ap/utils/s4ap_skill_utils.py b/Scripts/s4ap/utils/s4ap_skill_utils.py index e392816..b7abda4 100644 --- a/Scripts/s4ap/utils/s4ap_skill_utils.py +++ b/Scripts/s4ap/utils/s4ap_skill_utils.py @@ -18,6 +18,62 @@ logger = S4APLogger.get_log() logger.enable() +class S4APSkillUtils: + + @staticmethod + def get_current_skill_level(self, sim_info: SimInfo, skill: TunableInstanceParam(Types.STATISTIC)) -> float: + skill_stat = sim_info.get_statistic(skill, add=False) + if skill_stat is None: + return 0.0 + skill_level: float = skill_stat.get_user_value() + return skill_level + + @staticmethod + def set_current_skill_level(self, sim_info: SimInfo, skill: TunableInstanceParam(Types.STATISTIC), level: float) -> bool: + skill_stat = sim_info.get_statistic(skill, add=False) + if skill_stat is None: + return False + exp = skill_stat.convert_from_user_value(level) + skill_stat.set_value(exp) + return True + + @staticmethod + def get_all_skills_available_for_sim_gen(sim_info: SimInfo) -> Iterator[Skill]: + sim = S4APSimUtils.get_sim_instance(sim_info) + if sim is None: + return tuple() + + def _is_skill_available_for_sim(skill: Skill) -> bool: + return skill.can_add(sim) + + yield from S4APSkillUtils.get_all_skills_gen(include_skill_callback=_is_skill_available_for_sim) + + @staticmethod + def get_all_skills_gen(include_skill_callback: Callable[[Skill], bool] = None) -> Iterator[Skill]: + statistic_manager = services.get_instance_manager(Types.STATISTIC) + for skill in statistic_manager.get_ordered_types(only_subclasses_of=Skill): + skill: Skill = skill + skill_id = S4APSkillUtils.get_skill_id(skill) + if skill_id is None: + continue + if include_skill_callback is not None and not include_skill_callback(skill): + continue + yield skill + + @staticmethod + def get_skill_id(skill_identifier: Union[int, Skill]) -> Union[int, None]: + """get_skill_id(skill_identifier) + + Retrieve the decimal identifier of a Skill. + + :param skill_identifier: The identifier or instance of a Skill. + :type skill_identifier: Union[int, Skill] + :return: The decimal identifier of the Skill or None if the Skill does not have an id. + :rtype: Union[int, None] + """ + if isinstance(skill_identifier, int): + return skill_identifier + return getattr(skill_identifier, 'guid64', None) def lock_skills(skillcap: int, skill_name, from_level_up: bool): try: @@ -98,61 +154,4 @@ def remove_lock_trait(sim_info, trait): @CommonEventRegistry.handle_events(ModInfo.get_identity()) def _lock_on_level_up(event_data: SimSkillLeveledUpEvent): skill_name = event_data.skill.skill_type.__name__ - lock_skills(event_data.new_skill_level, skill_name, True) - -class S4APSkillUtils: - - @staticmethod - def get_current_skill_level(self, sim_info: SimInfo, skill: TunableInstanceParam(Types.STATISTIC)) -> float: - skill_stat = sim_info.get_statistic(skill, add=False) - if skill_stat is None: - return 0.0 - skill_level: float = skill_stat.get_user_value() - return skill_level - - @staticmethod - def set_current_skill_level(self, sim_info: SimInfo, skill: TunableInstanceParam(Types.STATISTIC), level: float) -> bool: - skill_stat = sim_info.get_statistic(skill, add=False) - if skill_stat is None: - return False - exp = skill_stat.convert_from_user_value(level) - skill_stat.set_value(exp) - return True - - @staticmethod - def get_all_skills_available_for_sim_gen(sim_info: SimInfo) -> Iterator[Skill]: - sim = S4APSimUtils.get_sim_instance(sim_info) - if sim is None: - return tuple() - - def _is_skill_available_for_sim(skill: Skill) -> bool: - return skill.can_add(sim) - - yield from S4APSkillUtils.get_all_skills_gen(include_skill_callback=_is_skill_available_for_sim) - - @staticmethod - def get_all_skills_gen(include_skill_callback: Callable[[Skill], bool] = None) -> Iterator[Skill]: - statistic_manager = services.get_instance_manager(Types.STATISTIC) - for skill in statistic_manager.get_ordered_types(only_subclasses_of=Skill): - skill: Skill = skill - skill_id = S4APSkillUtils.get_skill_id(skill) - if skill_id is None: - continue - if include_skill_callback is not None and not include_skill_callback(skill): - continue - yield skill - - @staticmethod - def get_skill_id(skill_identifier: Union[int, Skill]) -> Union[int, None]: - """get_skill_id(skill_identifier) - - Retrieve the decimal identifier of a Skill. - - :param skill_identifier: The identifier or instance of a Skill. - :type skill_identifier: Union[int, Skill] - :return: The decimal identifier of the Skill or None if the Skill does not have an id. - :rtype: Union[int, None] - """ - if isinstance(skill_identifier, int): - return skill_identifier - return getattr(skill_identifier, 'guid64', None) \ No newline at end of file + lock_skills(event_data.new_skill_level, skill_name, True) \ No newline at end of file From 66d94ea8db4f30cb89a5b26c67d39b314251c984 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 16:17:51 -0600 Subject: [PATCH 062/134] try cursor for debugging- --- Scripts/s4ap/events/skill_event_dispatcher.py | 30 +---------------- Scripts/s4ap/events/skill_events.py | 32 +++++++++++++++++++ Scripts/s4ap/utils/s4ap_skill_utils.py | 2 +- 3 files changed, 34 insertions(+), 30 deletions(-) create mode 100644 Scripts/s4ap/events/skill_events.py diff --git a/Scripts/s4ap/events/skill_event_dispatcher.py b/Scripts/s4ap/events/skill_event_dispatcher.py index 1312520..a3f4be3 100644 --- a/Scripts/s4ap/events/skill_event_dispatcher.py +++ b/Scripts/s4ap/events/skill_event_dispatcher.py @@ -1,12 +1,12 @@ import re from s4ap.events.checks.send_check_event import SendLocationEvent +from s4ap.events.skill_events import SimSkillLeveledUpEvent from s4ap.logging.s4ap_logger import S4APLogger from s4ap.modinfo import ModInfo from s4ap.utils.s4ap_sim_utils import S4APSimUtils from s4ap.utils.s4ap_skill_utils import S4APSkillUtils from sims.sim_info import SimInfo -from sims4communitylib.events.event_handling.common_event import CommonEvent from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry from sims4communitylib.services.common_service import CommonService from lot51_core.utils.injection import inject_to @@ -15,34 +15,6 @@ logger = S4APLogger.get_log() -class SimSkillLeveledUpEvent(CommonEvent): - - def __init__(self, sim_info: SimInfo, skill: Skill, new_skill_level: int): - self._sim_info = sim_info - self._skill = skill - self._new_skill_level = new_skill_level - - @property - def new_skill_level(self) -> int: - """The level the Sim will be after leveling up.""" - return self._new_skill_level - - @property - def sim_info(self) -> SimInfo: - """The Sim that leveled up in a Skill.""" - return self._sim_info - - @property - def skill(self) -> Skill: - """The Skill that was leveled up.""" - return self._skill - - @property - def skill_id(self) -> int: - """The decimal identifier of the Skill.""" - return S4APSkillUtils.get_skill_id(self.skill) - - class HandleSkillLevelUp(CommonService): def _on_skill_updated(self, skill: Skill, new_skill_level: int) -> None: if skill.tracker is None or skill.tracker._owner is None: diff --git a/Scripts/s4ap/events/skill_events.py b/Scripts/s4ap/events/skill_events.py new file mode 100644 index 0000000..bced09c --- /dev/null +++ b/Scripts/s4ap/events/skill_events.py @@ -0,0 +1,32 @@ +from sims.sim_info import SimInfo +from sims4communitylib.events.event_handling.common_event import CommonEvent +from statistics.skill import Skill + + +class SimSkillLeveledUpEvent(CommonEvent): + + def __init__(self, sim_info: SimInfo, skill: Skill, new_skill_level: int): + self._sim_info = sim_info + self._skill = skill + self._new_skill_level = new_skill_level + + @property + def new_skill_level(self) -> int: + """The level the Sim will be after leveling up.""" + return self._new_skill_level + + @property + def sim_info(self) -> SimInfo: + """The Sim that leveled up in a Skill.""" + return self._sim_info + + @property + def skill(self) -> Skill: + """The Skill that was leveled up.""" + return self._skill + + @property + def skill_id(self) -> int: + """The decimal identifier of the Skill.""" + from s4ap.utils.s4ap_skill_utils import S4APSkillUtils + return S4APSkillUtils.get_skill_id(self.skill) diff --git a/Scripts/s4ap/utils/s4ap_skill_utils.py b/Scripts/s4ap/utils/s4ap_skill_utils.py index b7abda4..0f69cf1 100644 --- a/Scripts/s4ap/utils/s4ap_skill_utils.py +++ b/Scripts/s4ap/utils/s4ap_skill_utils.py @@ -3,7 +3,7 @@ import services from typing import Callable, Iterator, Union from s4ap.enums.S4APLocalization import S4APTraitId -from s4ap.events.skill_event_dispatcher import SimSkillLeveledUpEvent +from s4ap.events.skill_events import SimSkillLeveledUpEvent from s4ap.logging.s4ap_logger import S4APLogger from s4ap.modinfo import ModInfo from s4ap.persistance.ap_session_data_store import S4APSessionStoreUtils From 948f3cd801a535eaff09552d28036a1bc4e0ad64 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 16:33:02 -0600 Subject: [PATCH 063/134] maybe another circular import issue fixed --- Scripts/s4ap/utils/s4ap_reset_utils.py | 2 +- Scripts/s4ap/utils/s4ap_skill_utils.py | 62 +------------------ Scripts/s4ap/utils/s4ap_skill_utils_class.py | 64 ++++++++++++++++++++ 3 files changed, 66 insertions(+), 62 deletions(-) create mode 100644 Scripts/s4ap/utils/s4ap_skill_utils_class.py diff --git a/Scripts/s4ap/utils/s4ap_reset_utils.py b/Scripts/s4ap/utils/s4ap_reset_utils.py index a3057c4..6da2ca9 100644 --- a/Scripts/s4ap/utils/s4ap_reset_utils.py +++ b/Scripts/s4ap/utils/s4ap_reset_utils.py @@ -2,7 +2,7 @@ from s4ap.logging.s4ap_logger import S4APLogger from s4ap.utils.s4ap_generic_utils import S4APUtils from s4ap.utils.s4ap_household_utils import S4APHouseholdUtils -from s4ap.utils.s4ap_skill_utils import S4APSkillUtils +from s4ap.utils.s4ap_skill_utils_class import S4APSkillUtils from server_commands.argument_helpers import TunableInstanceParam from sims4.localization import LocalizationHelperTuning from sims4.resources import Types diff --git a/Scripts/s4ap/utils/s4ap_skill_utils.py b/Scripts/s4ap/utils/s4ap_skill_utils.py index 0f69cf1..3a61544 100644 --- a/Scripts/s4ap/utils/s4ap_skill_utils.py +++ b/Scripts/s4ap/utils/s4ap_skill_utils.py @@ -1,7 +1,5 @@ import re -import services -from typing import Callable, Iterator, Union from s4ap.enums.S4APLocalization import S4APTraitId from s4ap.events.skill_events import SimSkillLeveledUpEvent from s4ap.logging.s4ap_logger import S4APLogger @@ -10,71 +8,13 @@ from s4ap.utils.s4ap_household_utils import S4APHouseholdUtils from s4ap.utils.s4ap_sim_utils import S4APSimUtils from server_commands.argument_helpers import TunableInstanceParam -from sims.sim_info import SimInfo from sims4.resources import Types from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from statistics.skill import Skill +from s4ap.utils.s4ap_skill_utils_class import S4APSkillUtils logger = S4APLogger.get_log() logger.enable() -class S4APSkillUtils: - - @staticmethod - def get_current_skill_level(self, sim_info: SimInfo, skill: TunableInstanceParam(Types.STATISTIC)) -> float: - skill_stat = sim_info.get_statistic(skill, add=False) - if skill_stat is None: - return 0.0 - skill_level: float = skill_stat.get_user_value() - return skill_level - - @staticmethod - def set_current_skill_level(self, sim_info: SimInfo, skill: TunableInstanceParam(Types.STATISTIC), level: float) -> bool: - skill_stat = sim_info.get_statistic(skill, add=False) - if skill_stat is None: - return False - exp = skill_stat.convert_from_user_value(level) - skill_stat.set_value(exp) - return True - - @staticmethod - def get_all_skills_available_for_sim_gen(sim_info: SimInfo) -> Iterator[Skill]: - sim = S4APSimUtils.get_sim_instance(sim_info) - if sim is None: - return tuple() - - def _is_skill_available_for_sim(skill: Skill) -> bool: - return skill.can_add(sim) - - yield from S4APSkillUtils.get_all_skills_gen(include_skill_callback=_is_skill_available_for_sim) - - @staticmethod - def get_all_skills_gen(include_skill_callback: Callable[[Skill], bool] = None) -> Iterator[Skill]: - statistic_manager = services.get_instance_manager(Types.STATISTIC) - for skill in statistic_manager.get_ordered_types(only_subclasses_of=Skill): - skill: Skill = skill - skill_id = S4APSkillUtils.get_skill_id(skill) - if skill_id is None: - continue - if include_skill_callback is not None and not include_skill_callback(skill): - continue - yield skill - - @staticmethod - def get_skill_id(skill_identifier: Union[int, Skill]) -> Union[int, None]: - """get_skill_id(skill_identifier) - - Retrieve the decimal identifier of a Skill. - - :param skill_identifier: The identifier or instance of a Skill. - :type skill_identifier: Union[int, Skill] - :return: The decimal identifier of the Skill or None if the Skill does not have an id. - :rtype: Union[int, None] - """ - if isinstance(skill_identifier, int): - return skill_identifier - return getattr(skill_identifier, 'guid64', None) - def lock_skills(skillcap: int, skill_name, from_level_up: bool): try: logger.debug(f"Processing level up for {skill_name}") diff --git a/Scripts/s4ap/utils/s4ap_skill_utils_class.py b/Scripts/s4ap/utils/s4ap_skill_utils_class.py new file mode 100644 index 0000000..5deeefd --- /dev/null +++ b/Scripts/s4ap/utils/s4ap_skill_utils_class.py @@ -0,0 +1,64 @@ +import services +from typing import Callable, Iterator +from s4ap.utils.s4ap_sim_utils import S4APSimUtils +from server_commands.argument_helpers import TunableInstanceParam +from sims.sim_info import SimInfo +from sims4.resources import Types +from statistics.skill import Skill + +class S4APSkillUtils: + + @staticmethod + def get_current_skill_level(sim_info: SimInfo, skill: TunableInstanceParam(Types.STATISTIC)) -> float: + skill_stat = sim_info.get_statistic(skill, add=False) + if skill_stat is None: + return 0.0 + skill_level: float = skill_stat.get_user_value() + return skill_level + + @staticmethod + def set_current_skill_level(sim_info: SimInfo, skill: TunableInstanceParam(Types.STATISTIC), level: float) -> bool: + skill_stat = sim_info.get_statistic(skill, add=False) + if skill_stat is None: + return False + exp = skill_stat.convert_from_user_value(level) + skill_stat.set_value(exp) + return True + + @staticmethod + def get_all_skills_available_for_sim_gen(sim_info: SimInfo) -> Iterator[Skill]: + sim = S4APSimUtils.get_sim_instance(sim_info) + if sim is None: + return tuple() + + def _is_skill_available_for_sim(skill: Skill) -> bool: + return skill.can_add(sim) + + yield from S4APSkillUtils.get_all_skills_gen(include_skill_callback=_is_skill_available_for_sim) + + @staticmethod + def get_all_skills_gen(include_skill_callback: Callable[[Skill], bool] = None) -> Iterator[Skill]: + statistic_manager = services.get_instance_manager(Types.STATISTIC) + for skill in statistic_manager.get_ordered_types(only_subclasses_of=Skill): + skill: Skill = skill + skill_id = S4APSkillUtils.get_skill_id(skill) + if skill_id is None: + continue + if include_skill_callback is not None and not include_skill_callback(skill): + continue + yield skill + + @staticmethod + def get_skill_id(skill_identifier: Union[int, Skill]) -> Union[int, None]: + """get_skill_id(skill_identifier) + + Retrieve the decimal identifier of a Skill. + + :param skill_identifier: The identifier or instance of a Skill. + :type skill_identifier: Union[int, Skill] + :return: The decimal identifier of the Skill or None if the Skill does not have an id. + :rtype: Union[int, None] + """ + if isinstance(skill_identifier, int): + return skill_identifier + return getattr(skill_identifier, 'guid64', None) \ No newline at end of file From fb73f148861d7e4179491ef4f1c58b3f05525ecb Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 16:35:49 -0600 Subject: [PATCH 064/134] more import issues --- Scripts/s4ap/events/skill_event_dispatcher.py | 2 +- Scripts/s4ap/events/skill_events.py | 2 +- Scripts/s4ap/utils/s4ap_phone_utils.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Scripts/s4ap/events/skill_event_dispatcher.py b/Scripts/s4ap/events/skill_event_dispatcher.py index a3f4be3..3a534cf 100644 --- a/Scripts/s4ap/events/skill_event_dispatcher.py +++ b/Scripts/s4ap/events/skill_event_dispatcher.py @@ -5,7 +5,7 @@ from s4ap.logging.s4ap_logger import S4APLogger from s4ap.modinfo import ModInfo from s4ap.utils.s4ap_sim_utils import S4APSimUtils -from s4ap.utils.s4ap_skill_utils import S4APSkillUtils +from s4ap.utils.s4ap_skill_utils_class import S4APSkillUtils from sims.sim_info import SimInfo from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry from sims4communitylib.services.common_service import CommonService diff --git a/Scripts/s4ap/events/skill_events.py b/Scripts/s4ap/events/skill_events.py index bced09c..93a1cf1 100644 --- a/Scripts/s4ap/events/skill_events.py +++ b/Scripts/s4ap/events/skill_events.py @@ -28,5 +28,5 @@ def skill(self) -> Skill: @property def skill_id(self) -> int: """The decimal identifier of the Skill.""" - from s4ap.utils.s4ap_skill_utils import S4APSkillUtils + from s4ap.utils.s4ap_skill_utils_class import S4APSkillUtils return S4APSkillUtils.get_skill_id(self.skill) diff --git a/Scripts/s4ap/utils/s4ap_phone_utils.py b/Scripts/s4ap/utils/s4ap_phone_utils.py index 9179fde..07f1fc5 100644 --- a/Scripts/s4ap/utils/s4ap_phone_utils.py +++ b/Scripts/s4ap/utils/s4ap_phone_utils.py @@ -9,7 +9,7 @@ from s4ap.utils.s4ap_career_utils import S4APCareerUtils from s4ap.utils.s4ap_generic_utils import S4APUtils from s4ap.utils.s4ap_household_utils import S4APHouseholdUtils -from s4ap.utils.s4ap_skill_utils import S4APSkillUtils +from s4ap.utils.s4ap_skill_utils_class import S4APSkillUtils from server_commands.argument_helpers import TunableInstanceParam from services import get_instance_manager from sims4.localization import LocalizationHelperTuning From 68f22306f4e03b986403740530cf2d8dd727bfd1 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 16:41:45 -0600 Subject: [PATCH 065/134] aaaaa the dreaded missing import --- Scripts/s4ap/utils/s4ap_skill_utils_class.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/s4ap/utils/s4ap_skill_utils_class.py b/Scripts/s4ap/utils/s4ap_skill_utils_class.py index 5deeefd..101df7e 100644 --- a/Scripts/s4ap/utils/s4ap_skill_utils_class.py +++ b/Scripts/s4ap/utils/s4ap_skill_utils_class.py @@ -1,5 +1,5 @@ import services -from typing import Callable, Iterator +from typing import Callable, Iterator, Union from s4ap.utils.s4ap_sim_utils import S4APSimUtils from server_commands.argument_helpers import TunableInstanceParam from sims.sim_info import SimInfo From 38769e85db7f0809d9c181683964e1f83af0ff3a Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 16:58:31 -0600 Subject: [PATCH 066/134] fix missing 'owner' issue --- Scripts/s4ap/persistance/ap_session_data_store.py | 1 + Scripts/s4ap/utils/s4ap_generic_utils.py | 1 + 2 files changed, 2 insertions(+) diff --git a/Scripts/s4ap/persistance/ap_session_data_store.py b/Scripts/s4ap/persistance/ap_session_data_store.py index 1097a4f..065dea5 100644 --- a/Scripts/s4ap/persistance/ap_session_data_store.py +++ b/Scripts/s4ap/persistance/ap_session_data_store.py @@ -91,6 +91,7 @@ def _cancel_chosen(_: UiDialogOkCancel): # Prompt the user to either overwrite the previous session_data, or stop parsing the data packet and wait for the connection_status.json to update dialog = UiDialogOkCancel.TunableFactory().default( + None, title = S4APLocalizationUtils.create_from_string("Warning!"), description=S4APLocalizationUtils.create_from_string("Pressing 'Connect' will reset your Sims' skill levels and will sync the game to the client. If you don't want to use this save, click 'Cancel' and switch to a different one."), ok_text=S4APLocalizationUtils.create_from_string('Connect'), diff --git a/Scripts/s4ap/utils/s4ap_generic_utils.py b/Scripts/s4ap/utils/s4ap_generic_utils.py index 846761a..a2e27c3 100644 --- a/Scripts/s4ap/utils/s4ap_generic_utils.py +++ b/Scripts/s4ap/utils/s4ap_generic_utils.py @@ -52,6 +52,7 @@ def show_basic_notification(title_text: Union[int, str], description_text: Union description = LocalizationHelperTuning.get_raw_text(description_text) dialog = UiDialogNotification.TunableFactory().default( + None, title=title, text=description ) From 387bdff04b5694d7cb2964586dc1cbc95e5e464a Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 17:03:27 -0600 Subject: [PATCH 067/134] use boilerplate to fix other 'owner' issue --- .../s4ap/persistance/ap_session_data_store.py | 50 ++++++++----------- Scripts/s4ap/utils/s4ap_generic_utils.py | 47 ++++++++++++++++- 2 files changed, 66 insertions(+), 31 deletions(-) diff --git a/Scripts/s4ap/persistance/ap_session_data_store.py b/Scripts/s4ap/persistance/ap_session_data_store.py index 065dea5..24e7651 100644 --- a/Scripts/s4ap/persistance/ap_session_data_store.py +++ b/Scripts/s4ap/persistance/ap_session_data_store.py @@ -51,21 +51,18 @@ def _ok_chosen(_: UiDialogOkCancel): return False # if okay is chosen then save seed values and resync items # Prompt the user to either overwrite the previous session_data, or stop parsing the data packet and wait for the connection_status.json to update - dialog = UiDialogOkCancel.TunableFactory().default( - title = S4APLocalizationUtils.create_from_string("Warning!"), - description=S4APLocalizationUtils.create_from_string("There's a mismatch with your AP session data. If you press 'Overwrite,' all previous items will be resynced, and your Sims' skill levels will reset. If you'd rather keep your current progress, select 'Cancel' and switch to a different save file so you can come back to this session later."), - ok_text=S4APLocalizationUtils.create_from_string('Overwrite'), - cancel_text=S4APLocalizationUtils.create_from_string('Cancel'), + S4APUtils.show_ok_cancel_dialog( + title=S4APLocalizationUtils.create_from_string("Warning!"), + text=S4APLocalizationUtils.create_from_string( + "There's a mismatch with your AP session data. If you press 'Overwrite,' all previous " + "items will be resynced, and your Sims' skill levels will reset. If you'd rather keep your " + "current progress, select 'Cancel' and switch to a different save file so you can come back later." + ), + ok_text=S4APLocalizationUtils.create_from_string("Overwrite"), + cancel_text=S4APLocalizationUtils.create_from_string("Cancel"), + on_ok=lambda d: _ok_chosen(d) or None, + on_cancel=lambda d: _cancel_chosen(d) or None ) - # Wrap the callbacks manually - def on_option_selected(dialog_instance: UiDialogOkCancel): - if dialog_instance.accepted: - _ok_chosen(dialog_instance) - else: - _cancel_chosen(dialog_instance) - - dialog.add_listener(on_option_selected) - dialog.show_dialog() return True else: # Settings exist and match logger.debug("AP session data matched") @@ -90,22 +87,17 @@ def _cancel_chosen(_: UiDialogOkCancel): return True # Prompt the user to either overwrite the previous session_data, or stop parsing the data packet and wait for the connection_status.json to update - dialog = UiDialogOkCancel.TunableFactory().default( - None, - title = S4APLocalizationUtils.create_from_string("Warning!"), - description=S4APLocalizationUtils.create_from_string("Pressing 'Connect' will reset your Sims' skill levels and will sync the game to the client. If you don't want to use this save, click 'Cancel' and switch to a different one."), - ok_text=S4APLocalizationUtils.create_from_string('Connect'), - cancel_text=S4APLocalizationUtils.create_from_string('Cancel'), + S4APUtils.show_ok_cancel_dialog( + title=S4APLocalizationUtils.create_from_string("Warning!"), + text=S4APLocalizationUtils.create_from_string( + "Pressing 'Connect' will reset your Sims' skill levels and will sync the game to the client. " + "If you don't want to use this save, click 'Cancel' and switch to a different one." + ), + ok_text=S4APLocalizationUtils.create_from_string("Connect"), + cancel_text=S4APLocalizationUtils.create_from_string("Cancel"), + on_ok=lambda d: _ok_chosen(d) or None, + on_cancel=lambda d: _cancel_chosen(d) or None ) - - def on_option_selected(dialog_instance: UiDialogOkCancel): - if dialog_instance.accepted: - _ok_chosen(dialog_instance) - else: - _cancel_chosen(dialog_instance) - - dialog.add_listener(on_option_selected) - dialog.show_dialog() return True def check_index_value(self, index: str) -> bool: diff --git a/Scripts/s4ap/utils/s4ap_generic_utils.py b/Scripts/s4ap/utils/s4ap_generic_utils.py index a2e27c3..570c518 100644 --- a/Scripts/s4ap/utils/s4ap_generic_utils.py +++ b/Scripts/s4ap/utils/s4ap_generic_utils.py @@ -1,12 +1,14 @@ import services -from typing import Union +from typing import Callable, Optional, Union from s4ap.modinfo import ModInfo from services.persistence_service import SaveGameData +from sims.sim_info import SimInfo from sims4.resources import Types from sims4communitylib.events.zone_spin.common_zone_spin_event_dispatcher import CommonZoneSpinEventDispatcher from sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler from s4ap.utils.s4ap_save_utils import S4APSaveUtils from sims4.localization import LocalizationHelperTuning +from ui.ui_dialog import UiDialogOkCancel from ui.ui_dialog_notification import UiDialogNotification class S4APUtils: @@ -56,4 +58,45 @@ def show_basic_notification(title_text: Union[int, str], description_text: Union title=title, text=description ) - dialog.show_dialog() \ No newline at end of file + dialog.show_dialog() + + @classmethod + def show_ok_cancel_dialog( + cls, + title, + text, + ok_text, + cancel_text, + on_ok: Optional[Callable[[UiDialogOkCancel], None]] = None, + on_cancel: Optional[Callable[[UiDialogOkCancel], None]] = None, + owner: Optional[SimInfo] = None + ): + """Show an Ok/Cancel dialog with optional handlers for each response. + + :param title: LocalizedString for the title. + :param text: LocalizedString for the body text. + :param ok_text: LocalizedString for the OK button. + :param cancel_text: LocalizedString for the Cancel button. + :param on_ok: Callback if the user presses OK. + :param on_cancel: Callback if the user presses Cancel. + :param owner: SimInfo or None (defaults to None). + """ + dialog = UiDialogOkCancel.TunableFactory().default( + owner, + title=title, + text=text, + ok_text=ok_text, + cancel_text=cancel_text + ) + + def _on_response(dialog_instance: UiDialogOkCancel): + if dialog_instance.accepted: + if on_ok is not None: + on_ok(dialog_instance) + else: + if on_cancel is not None: + on_cancel(dialog_instance) + + dialog.add_listener(_on_response) + dialog.show_dialog() + return dialog \ No newline at end of file From ad657b6ab955fae809a6bc6612d3b624e4a72433 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 17:16:52 -0600 Subject: [PATCH 068/134] fix fucking dumb owner issue aaaaa --- Scripts/s4ap/utils/s4ap_generic_utils.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Scripts/s4ap/utils/s4ap_generic_utils.py b/Scripts/s4ap/utils/s4ap_generic_utils.py index 570c518..0f34f35 100644 --- a/Scripts/s4ap/utils/s4ap_generic_utils.py +++ b/Scripts/s4ap/utils/s4ap_generic_utils.py @@ -1,6 +1,7 @@ import services from typing import Callable, Optional, Union from s4ap.modinfo import ModInfo +from s4ap.utils.s4ap_sim_utils import S4APSimUtils from services.persistence_service import SaveGameData from sims.sim_info import SimInfo from sims4.resources import Types @@ -54,7 +55,7 @@ def show_basic_notification(title_text: Union[int, str], description_text: Union description = LocalizationHelperTuning.get_raw_text(description_text) dialog = UiDialogNotification.TunableFactory().default( - None, + owner=type(self), title=title, text=description ) @@ -82,7 +83,7 @@ def show_ok_cancel_dialog( :param owner: SimInfo or None (defaults to None). """ dialog = UiDialogOkCancel.TunableFactory().default( - owner, + S4APSimUtils.get_active_sim_info(), title=title, text=text, ok_text=ok_text, From aae9fecd0b89bff55980b8785f19bb032afbeed9 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 17:20:26 -0600 Subject: [PATCH 069/134] maybe fuck me --- Scripts/s4ap/utils/s4ap_generic_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/s4ap/utils/s4ap_generic_utils.py b/Scripts/s4ap/utils/s4ap_generic_utils.py index 0f34f35..20fac3b 100644 --- a/Scripts/s4ap/utils/s4ap_generic_utils.py +++ b/Scripts/s4ap/utils/s4ap_generic_utils.py @@ -55,7 +55,7 @@ def show_basic_notification(title_text: Union[int, str], description_text: Union description = LocalizationHelperTuning.get_raw_text(description_text) dialog = UiDialogNotification.TunableFactory().default( - owner=type(self), + owner=None, title=title, text=description ) From 443cc7b7f0fc286e2cae9e57696766937d6e0a92 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 17:23:17 -0600 Subject: [PATCH 070/134] fuck me --- Scripts/s4ap/utils/s4ap_generic_utils.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Scripts/s4ap/utils/s4ap_generic_utils.py b/Scripts/s4ap/utils/s4ap_generic_utils.py index 20fac3b..70cfa91 100644 --- a/Scripts/s4ap/utils/s4ap_generic_utils.py +++ b/Scripts/s4ap/utils/s4ap_generic_utils.py @@ -82,8 +82,14 @@ def show_ok_cancel_dialog( :param on_cancel: Callback if the user presses Cancel. :param owner: SimInfo or None (defaults to None). """ + + active_sim = S4APSimUtils.get_active_sim_info() + if active_sim is None: + # Skip showing the dialog if no active sim yet + return + dialog = UiDialogOkCancel.TunableFactory().default( - S4APSimUtils.get_active_sim_info(), + active_sim, title=title, text=text, ok_text=ok_text, From ca6739595e887ca36d2461aa91613a6f2272d507 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 18:22:24 -0600 Subject: [PATCH 071/134] okay now i think we're okay (use core library for notifications?) --- Scripts/s4ap/logging/s4ap_logger.py | 7 +++- .../s4ap/persistance/ap_session_data_store.py | 14 ++++---- Scripts/s4ap/utils/s4ap_generic_utils.py | 36 ++++++++++++------- 3 files changed, 37 insertions(+), 20 deletions(-) diff --git a/Scripts/s4ap/logging/s4ap_logger.py b/Scripts/s4ap/logging/s4ap_logger.py index a84a8b0..79853d5 100644 --- a/Scripts/s4ap/logging/s4ap_logger.py +++ b/Scripts/s4ap/logging/s4ap_logger.py @@ -7,6 +7,7 @@ from sims4communitylib.logging.has_class_log import HasClassLog from sims4communitylib.mod_support.mod_identity import CommonModIdentity from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils +from lot51_core.utils import DialogHelper class S4APLogger(HasClassLog): @@ -21,10 +22,14 @@ def get_log_identifier(cls) -> str: @staticmethod def show_loaded_notification() -> None: """ Show that the mod has loaded. """ - S4APUtils.show_basic_notification( + DialogHelper.create_notification( S4APLocalizationUtils.localize(S4APStringId.S4AP_LOADED), 'Loaded Sims 4 Archipelago Mod (' + ModInfo.get_identity().version + ')' ) + # S4APUtils.show_basic_notification( + # S4APLocalizationUtils.localize(S4APStringId.S4AP_LOADED), + # 'Loaded Sims 4 Archipelago Mod (' + ModInfo.get_identity().version + ')' + # ) @staticmethod @CommonEventRegistry.handle_events('s4ap_loaded') diff --git a/Scripts/s4ap/persistance/ap_session_data_store.py b/Scripts/s4ap/persistance/ap_session_data_store.py index 24e7651..83cd917 100644 --- a/Scripts/s4ap/persistance/ap_session_data_store.py +++ b/Scripts/s4ap/persistance/ap_session_data_store.py @@ -51,7 +51,7 @@ def _ok_chosen(_: UiDialogOkCancel): return False # if okay is chosen then save seed values and resync items # Prompt the user to either overwrite the previous session_data, or stop parsing the data packet and wait for the connection_status.json to update - S4APUtils.show_ok_cancel_dialog( + dialog = S4APUtils.show_ok_cancel_dialog( title=S4APLocalizationUtils.create_from_string("Warning!"), text=S4APLocalizationUtils.create_from_string( "There's a mismatch with your AP session data. If you press 'Overwrite,' all previous " @@ -60,9 +60,10 @@ def _ok_chosen(_: UiDialogOkCancel): ), ok_text=S4APLocalizationUtils.create_from_string("Overwrite"), cancel_text=S4APLocalizationUtils.create_from_string("Cancel"), - on_ok=lambda d: _ok_chosen(d) or None, - on_cancel=lambda d: _cancel_chosen(d) or None + on_ok=_ok_chosen, + on_cancel=_cancel_chosen ) + dialog.show() return True else: # Settings exist and match logger.debug("AP session data matched") @@ -87,7 +88,7 @@ def _cancel_chosen(_: UiDialogOkCancel): return True # Prompt the user to either overwrite the previous session_data, or stop parsing the data packet and wait for the connection_status.json to update - S4APUtils.show_ok_cancel_dialog( + dialog = S4APUtils.show_ok_cancel_dialog( title=S4APLocalizationUtils.create_from_string("Warning!"), text=S4APLocalizationUtils.create_from_string( "Pressing 'Connect' will reset your Sims' skill levels and will sync the game to the client. " @@ -95,9 +96,10 @@ def _cancel_chosen(_: UiDialogOkCancel): ), ok_text=S4APLocalizationUtils.create_from_string("Connect"), cancel_text=S4APLocalizationUtils.create_from_string("Cancel"), - on_ok=lambda d: _ok_chosen(d) or None, - on_cancel=lambda d: _cancel_chosen(d) or None + on_ok=_ok_chosen, + on_cancel=_cancel_chosen ) + dialog.show() return True def check_index_value(self, index: str) -> bool: diff --git a/Scripts/s4ap/utils/s4ap_generic_utils.py b/Scripts/s4ap/utils/s4ap_generic_utils.py index 70cfa91..70a6878 100644 --- a/Scripts/s4ap/utils/s4ap_generic_utils.py +++ b/Scripts/s4ap/utils/s4ap_generic_utils.py @@ -1,5 +1,7 @@ import services -from typing import Callable, Optional, Union +from typing import Any, Callable, Optional, Union + +from lot51_core.utils.dialog import DialogHelper from s4ap.modinfo import ModInfo from s4ap.utils.s4ap_sim_utils import S4APSimUtils from services.persistence_service import SaveGameData @@ -68,8 +70,8 @@ def show_ok_cancel_dialog( text, ok_text, cancel_text, - on_ok: Optional[Callable[[UiDialogOkCancel], None]] = None, - on_cancel: Optional[Callable[[UiDialogOkCancel], None]] = None, + on_ok: Optional[Callable[[UiDialogOkCancel], Any]] = None, + on_cancel: Optional[Callable[[UiDialogOkCancel], Any]] = None, owner: Optional[SimInfo] = None ): """Show an Ok/Cancel dialog with optional handlers for each response. @@ -88,14 +90,6 @@ def show_ok_cancel_dialog( # Skip showing the dialog if no active sim yet return - dialog = UiDialogOkCancel.TunableFactory().default( - active_sim, - title=title, - text=text, - ok_text=ok_text, - cancel_text=cancel_text - ) - def _on_response(dialog_instance: UiDialogOkCancel): if dialog_instance.accepted: if on_ok is not None: @@ -104,6 +98,22 @@ def _on_response(dialog_instance: UiDialogOkCancel): if on_cancel is not None: on_cancel(dialog_instance) - dialog.add_listener(_on_response) - dialog.show_dialog() + dialog = DialogHelper.create_dialog( + title, + text, + ok_text, + callback=_on_response + ) + # dialog = UiDialogOkCancel.TunableFactory().default( + # active_sim, + # title=title, + # text=text, + # ok_text=ok_text, + # cancel_text=cancel_text + # ) + + + + # dialog.add_listener(_on_response) + # dialog.show_dialog() return dialog \ No newline at end of file From 4a7cdccee8b74ecd8e52f6e81afae3d7c8aa42c1 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 21:17:39 -0600 Subject: [PATCH 072/134] oops --- Scripts/s4ap/logging/s4ap_logger.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/s4ap/logging/s4ap_logger.py b/Scripts/s4ap/logging/s4ap_logger.py index 79853d5..b98178b 100644 --- a/Scripts/s4ap/logging/s4ap_logger.py +++ b/Scripts/s4ap/logging/s4ap_logger.py @@ -7,7 +7,7 @@ from sims4communitylib.logging.has_class_log import HasClassLog from sims4communitylib.mod_support.mod_identity import CommonModIdentity from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from lot51_core.utils import DialogHelper +from lot51_core.utils.dialog import DialogHelper class S4APLogger(HasClassLog): From 83fcdac680a10e694188a3fd37e780ee918cf496 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 5 Sep 2025 21:23:42 -0600 Subject: [PATCH 073/134] another oops --- Scripts/s4ap/persistance/ap_session_data_store.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Scripts/s4ap/persistance/ap_session_data_store.py b/Scripts/s4ap/persistance/ap_session_data_store.py index 83cd917..b82ca1f 100644 --- a/Scripts/s4ap/persistance/ap_session_data_store.py +++ b/Scripts/s4ap/persistance/ap_session_data_store.py @@ -63,7 +63,7 @@ def _ok_chosen(_: UiDialogOkCancel): on_ok=_ok_chosen, on_cancel=_cancel_chosen ) - dialog.show() + dialog.show_dialog() return True else: # Settings exist and match logger.debug("AP session data matched") @@ -99,7 +99,7 @@ def _cancel_chosen(_: UiDialogOkCancel): on_ok=_ok_chosen, on_cancel=_cancel_chosen ) - dialog.show() + dialog.show_dialog() return True def check_index_value(self, index: str) -> bool: From 1f5c8541dadb5cbfdf39cf5d8aab2d632e56fa9f Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Sat, 6 Sep 2025 16:29:47 -0600 Subject: [PATCH 074/134] update package to package from release --- Package/Cactus_S4AP.package | Bin 37968 -> 65263 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/Package/Cactus_S4AP.package b/Package/Cactus_S4AP.package index 83d9da141fecb62e9a9cad785db0f6ee1f603b20..c11878c604c297dbe09e6639907af9e09d9bdcae 100644 GIT binary patch delta 34857 zcmc$mbySr7_V(%SR*<1XQBn|zp+ibQI;BBEq-$_SMSXV#5)vw;^6HjJi()h>%%Dw_p$iRg-qbin9IW0;`nsr||lmaRl1eNEoqa3T! zE&`$>A|i^8@_Bz?3&IDt22)OuPiWf3l)B|>WR}Slj{D#mt~bl69}Q5vP`}?SeE)Ox z7bfoUuvZv0GGqQXqLY`q*<{eon72EBEEq)}J!yXhG(ER!yKfH~Y|vcsXhbTQ0iukpqj`91wH1wOmAb#dVMLTb zCYJT)klZ(ZsC8TU|q?i2vw~L?TvE=`HwE`5R~>)sIJ2mRM$LpONIfEMiWt!Q>l) zg;fdJI^uIw*s)>mzLzI7`xu}-RK0D8G4}k6T%<^SOtp$&wSi6) z#r?!oLDTVm?~G@3?%#>mNuwYKN8liP>lz6qO^Olw&t96S9*3sZzL>Z7$7LQ8i`(#) zpAX}xG#n_rxg5EKP79$F0wJN_O)59kB4zx^X6!U0w1n1=mYiIUiP=vMFCIkDkVYDe z%(w$ndaeqC!jFm?QBN2O`go)G0zJLco#ISfg88Vzc9J*2LU3FqY27iZsEQ#r=0?@# z-6H$<4=7q?T*m=u&Sr>X%UYk`{K1Mu_&r|hpn09*gU0>#OmlslSW+Rm2vXNO2PAPv z?XJf3ek*+(fiFOfez^>{B^rQ0B8$86+n<2$d6Sk`mqwSa3Dy0mEJ3dmw!gC->nP1WP2}pG}$-2KTf%|S)xh2J~(^jzFR^UfLdeT{Vj49>KCI!mvh@Vb;GBENgeHuDMQZ-<~&NP}IN zS+w^~<1KafsUB}(W=pfN57anWI**-Rd8ZG(m9V3drs{>+Qv`<>?qRaNBL6Z?7xE%i zK}jey_>~M>@Mo(^vAP@I(@boBF6dI}MM#&EYuRPL*JbPLtnde{sc?9yBvwB zF)wT}OX*m5fG$Sb0lRw~E1ph>^$Z|T6hR*hUw#vXb3OMZ}lFb50<1b2ZZo6PqaPZd1gjQ6^vKu*h1e z8ko`srjmqU@w*RHrj87Qc;9dM1=uyl&1w4McpxSk6m4Kd)|Q_kj5quoh5>33UxniZ zch{b;Vs`H$OTE2IbU&AJm@10Y%}PnZ&ts1Y%W_Ay#IkKKdD1fO}JeL=B2odOl`V>%#3m!8;bn_-*Cz^s_UA6T8FQoAMX6}0fM z70QbLm|WG!z@01w&o`6yFM9Z#5>YIV?v1~uR@uq-#%3; zhntFxOOAr!sV8SoF;CBht7)jq;`(J9EXORG|WuRI&%mp@ye6 zUNJ3%kZMWK`N8uRRI86*Q>SdM>^mYUTr{D@4@);e)1(o^LYRY@&v?t2zlZNpGMF)q zy_e6*0znJm!tTCA7A#G7lKIc<-Ai_Xcaj=Ll~M0qoy)ty&8ULyjDjE+QilytiS59) zd(94joSD_E`_Dv%YAmqEBV!8oRWd>0AKJrR1RXrqfQu$344#wc>LK1LLcq; zZrz)4eW`C}x#>E%^sN(o@7FtTB*zz%?KYWo}`Fx*17G_prQ*7`GV5n92L`oad zlAiwRC4SY~Zea0%Gomr+B%tv$rnkmZuf-NS;q?mo7caN;)lr6=hvT7<^shs#`Akl- z>kQ?$v#s-pF;({QR}wH^e7$L{D!f4?>KxnoOx|Zqfb9-%s^jBm5WPQL)tH}IY&p&m zahzM}^WnU8*`es=Q8VvIA7Fu3)~`=&WgFBtmwOjtCht6hOsh;>pheeOq9mv5uf65h z@k#*ARQX(1K|YAWR#ucD(0k3MTIL>J#nY-mx& zpeSl(sTj&koE+R6FD$b2!}qUt^cq>hITgmUF{Etvhrdp0dNGIhSui+K?>@wnvf0PK zr!!$8;38j)vhbM1dP4d6I)Fp!=Ro$F z8C{5q=JGsfA~;>5~t-29>6*S#w}s_eLwXU~r6+VFzVj`D3%p}&6$Q+M;>UZO8s(%Oyxprv{6 zs5(Om-NfA*z@qP&oY!J!P?FYotsz6ga;xKe4J|ga&h$&iBgn!K8IAX*W!TH8TQ+S| zM()!?)gLIt4Tj>~uubk(X}u&f&Dp!_k-!{0)Wy;mF*t}soN+EdBlN)@U^*A)WM`Wl zzj-SsC4a{%$JY$e-Ij{5TYafEl=0?jIv~O`x-o4Apy*_q)ScGv8)pn@0jCDC;@!$mefmHHg?GN^7s88Nh2x zhbQIb3Z!nz%RYl&yM6TS1?n z@;OdBS-~n_+IxOf_pBTKh^hA=v}v(HUu(x)yF^hfA(KN97839DfViR89eh-w$Cw8si;_~7 z#UxzH^0?UT-GLKMukODwx5!qOhe5u44Fu{{hA+3hls>Om2tACPDO#6fR`ccSgF-)3 zBvRQ#Cj|0@I(}6d&syXfK;tH8ic8xzkKbOe1ANwQ4orrufv$sg5`=plw8D4Y78HQL zM6KzcL93%u?sXlswSNSydSXMX(pAt(UIi`Vb=ME0L%ae*N^#)F z>m)I^tDrsai(6PShyiV3m2HDwh_HLpqt<%5)=K0JYQ|e_+iR#zDBA}vK!@ADG2ZEJ zu0*a@R#xU!O+I>}N9hc89pfhBePu`*O@#*qF#;Z=asaFsVJ>h}5eR zs}dZTf>%nxik$Z?f0$RIHG5`d)yGochI^#f(cLF0P?1T&r^%=LLE_x2AgVKDalyCF zUhDeBGy1|jO~i+KlzW?+d}(o1{ov=5E?R@`{I|F|`9(>I>%Ku4O~CV7HH?@19W~F{ zurawMKiE*MkuN$obKx~`Y=8EI`@Hy6UTkYa zfaZujZlw9S%|gM#@GBZ?70`mjKXGBu|-_3bp%t4^2$xn8-+D4P0uHYQu_ zjR!p*e^PBJjE0CmCmeWSd@u*vxantc9mU}59;N4x9wk|hRUuAJ$ifyh_;^B*OXg#o8_Thw?Q<$_uohcuGePgbvT)!nCV;%9`{Hb8v>)SM}ea1H2 zHk8h%rm6|=jk}8i2@Ek-DT;H+Q>HFT}=pm;ZT+tspb=Jtj;W*LVj)IzWJv z#uI+R@)AFKF?dIry+3Im`vRj0s|j|UA;w-`RrRpzsy>XlvMpp(y(%X!Jt{xySZ7gn z^Q|!7Lrs^gWwt@x%?u=53>N!#ZNko-JW=PzyAJpQW`V(VS%1%0mVZ^&iJ(1eY`56g zu;Ox_<2BfmdXAc29tG2u0=16G!?iqR^)Hn7Z!yfjB0IHDVHF9+=ayeg;RX_)Otmr_M&QF=eltvDJQy|B@;S@z`xEvV3kWVuL)`+7Cbz0>B4*; zR#gybq63=GLip(XL7U*07lAh|9ULQ)a675ds=_K z{erf(Aqo2=siuDdpX*v(BAVU#RGff8ekDz!qgV*W!_{>|n!t@ zk|9XLE4a!IZ1y=Ba(&sl%JDt%(Uv!X5KLCgtJaJYZL>$S^FE}Ul%i=AgAZuUZ4P?Q z+oR#?A1oI_(*i&?Gc#w$*2ZEZHe-x?Rtv{!+ELbL;#++J!9N@NihvU!dlAHs$TKuU z*@@|S7Cvh^7NN0hXJb2Vs)DFAMwK47cpJs4X_UhTIS0R!0(FDn{pUl+`he_%MnZFh z;HmzHL&wRT98ASmp{-Gp&JuWiv!j2m9QE?$EmBh zJJ~9$6m`#D&=KAAr2SUM^E8$C{;Kmx^WkBuWta!6QIRQ+?f8KrXcW;bc|TrdhpRET zab{}5pvC1|xvLd;Bx+>M%}^eZIVRDRo;8I~ziE>@kTqYl@})SUc1+^?c*`dP^Jz?X zn2OOrBh<8WKAYaOxOuEmxicoGDSJOnR0&4wk@7MEUu&V%B3OyKQB6uyF<72`v33A2 zQT|0_yq|y`xq?ubN-Jj~mq9=6E@7=}3ul!RgAWZ5*M42?<&T3=Wb?Q}4qHsJTCO;_ zShT@c)jmTmI3kpT`tn>^8`IF*vo8Rip(68BFLzA-tFDeM!Lk+Bf&T-hJ5RJu9R85# zxto^aX=-1n{)pu@65+K{$az|FX@#ShiKD)z+mC`Q>BUgIHztt`4dkjy+>d%y5zfVV z6doeSU5)J1VqFS7+I}lsyFEJa{_m!2==eIQYl)t4RqdCrs{IDGq+x9nr)!8mJr-dJ zzG>?V`2mx9XRMWYHrD#pfxW7X1;nx}V*%FAGI;LYgO)n3Vv?ETi|0=AQ*yhvQJ8Oj z_?rF^%YWARt}a&=S-Ic|rtE5m#nE{Ab~z;}7Dk=@<4~zb|G&nIB#XZ#>k zotucL7rW7zT9f~L#Hd4FtVL5~e|n>K0kGJxsF=_*Dm|6x+fZ86)M-(Q#2fI$7=fqK zy_uUwq~o)QD>iG8nZ4@7I`Jna;ibG=>O-nKzWT)cStgGq8s8*e^Zg*K6zN=cRw}#7 zvpwy|P`n-S7TkyFB~TcFBicfc1_?4jQ80&7A2CG*pV|Y-Jex z(GzkoHNY|uXNHD{)C*=T|wKabFI`rGX{3MTq|{hKb1N_=oBSx zFNyV+*j^|piD9J^7v3bkitTOjsCMd3-8Uuk8?V2a{1MyWqaS>90-IMF-k?LMNw=^` z@N#DSJm%(P^yb``?ia!mz#+EDNXN%DV_(HF>#sUc-qz7;r7nAPJ~$mEsrO{##$1)k zse#E(-gS{*8&ZCBUE~Spas%cLu8O>b+;LU4XxaJ3{Y}cojXR0Qh9Xa=`Q1fyAQHH1 z=Q$+te3I$}-*r^UKFZXgbFC|te_;FWc_X`0$+;>%!{N~_=Io9@=?F@~CO3cbj`AM9 zRX?qWxB33)v(H6ZYO0n6)_H)5Cu7cOd{hBh)z=dkDJC|1`42fYiE%lehLomvd%w$> zqO;Dr_ra!8Qc~<@OpgRi`HmT28-CmEeVrd~w~&&(-SZ7Ch)0viGlR0dQ`F-szRg9a zxjQM$RB0H*^u(TJe}!PE<5a+~r;1OG(TMqH$Hc0U`jK46%Wv-9T@!#cbj{<=-mK&0 zEfkth=~|e!MQx)FqFtQ#o2Qr%f#SVkF5=`xNB-#Grlu~~QB<>~xw2&7rixUiVRmqz zvkB9P*MnxA1U(7a%CirBI1?wOoxS|@EkYi|&&)iYq)~C;|bjte)HoT|4@e&-!arX9}H(E{E+WajY%b}GH_i$kKAL*s`t<(u zl#sR~G0?jg@F*5k);VzB8X1ii61oYs+EnX*i|WYJY5qy=@?$Hut_4B=C}dm!lBp2e z{`|%vWIUNISHB6+B>M)_j>yW-8h#w;a&0!xU75{9p*y&KxVgA?=~)j=T(xFqKB13C z-))&r#E;O%h%j1muXZsjT!VBJ&_}SYEi1XZIy)SGG}ON3j^$bL!DnjzI6jCZ&w~ zkG2!4qnOM+8c041POJS-k_mdHjmliKX#3}$uwX6y*CktCBppLoHegp zbM&_P;#0@#(aQ%NjJG}RGcVhyxxe=Rk@0qO5fukE^E;QvLupSH!W6;z22GK| z3;;9D*+Wn0DIc4Q?D16SjI4;)!x)R_BjxZ9%gv`JU@3g!W9W6plfTM%CE{QH;!PZ$ zX#eR=gwyUv{>5jW7cBWB8qoE!8!j&Nl=%Z#5P_OPn$kvDfEpq`wV) z_qW~zHF{lqjf6hg6HB@yiH~x9TCIU*1{f{)RRd<<$N;BdX@U+uGVIZoguhYl z>+6OzR9|9ssl2~oZQm?69Hft*alZ&(VU5&*O z`wuC{gaI@r4wdTvGacg0&CSuYh_D|U2BKpS1g8J^8B9$sCCp1^gvL+$gqSGr!=Phm zMcplm)XVpa)4c`sX>`v6ai|za-wQsY23$a@I_4PfhS0kx8RntkQeV{vpT2>dTFD(Ng@2fhp9r9iP_}XHG{9ig}6YlER-F5A)4&6&Jf5We~5vDrl!p!2Yy*8n<5tn z(~p9xGos+K`n(T94Q$X?=x8MHC$!foX^h~HnQ+Mb;&aBfA#1I2?lE~RQ!G)J?yr%d z9Q8LOAiaZl>n~8pmtwZ@d%1wqg6Z+3yGUqjFMmuDq0dXLr(Zmr^&Ya&wBI(4c)T0v zmc>dJ+D*t@O)xYxap_(=zo2T_64sCB4$s_g{|Ptu>aQ8bqAlK%Cd}hU6S$E$HUvX( zbG{AIUOnp|D=HG@c;DL(lH$5#ih7CX--NKQYwH`>kHrQ zd%LGG&F_m5GW}TV>O5kHNP_vuUhZ(TcG`dfwO+Rc$-LrJrM!P(jIT+mMn+*66}!Wd zLmMjw8yt2{m)yA}?wmU&%lk&`UO}HHCH(oD4`J;#v?^UpbP>Vf&UD`56nKUf=L&dU z5sh_quJ57+4d!kX=JH_xTi@d)-xcguX)jaD+zQ_Gf5NCmEcMA|VADx*Po7gNB+;%{ zm$K1R@14|rMI@Tc589_Jp6Tb=^bt%pKX`|VY62$)@KuLERpLJAocW4**SA3W`q1T% zIp&`V;J(-5X|&^ah@vn^!K-I`#pCe!>dc(L_ z+xF*7vRqUO9!~I3b_=p7nR^`HDNEtLc!p1ra(J|%XAT1eVEV$EMgetsYpg~$WuIr2 zm)@-dG%_suy~xGOgVP(6UcL_!iP*C8mxG zTdnqDt!9=RcmSnb+{vLjW`ljxp#00XJnP7pq3xLAF^_ex&g89z6165(kA{44j!=yq zWfd9Q2c{C^n#XZOnN%%?^+f}N0fOOP@cG4gv7MnnBUS>#>b}=;&u3XMbK7RB`-c^ux$Vb@kx4pDeVde{;oYl9Wk^76+;6d^LSR!{GduMC%yJraYz&EAd)AFa~9 z@xV>;4dpR-bMk&1mKhw?#w^yoB0WXo(^OGIqIfsqXTD*BQiDp#1L#GGwdXhuX1wlN zf~MXp--^JYDcq?A{UoCF^AreFtnySK5weuYZ22UbIAH2Om zv8HM2J$JUh>~|0ArJueh(Y#ngdRb{uFmv7E)EZPJzlDGxxp%F{6H<=j`{X3AIbZu( zK)+Zjg-4KCNlA6T*liIh!>aEfV}E?yN@x${ed-34icda0S;TF&+RA4~9U1A0Hn{n2 z2zy{h1`>^jPfO$563Y?26(=lG zzm)*sItlzn0)Xoz@EZvLu9LuTBmlTh0>6;};LkGf+Xw*uECaud0N~Fu@Y@Ig{wxE( zjR4@ULf|(M0Q^-5{3Zf`zY2lhL;&ztA@G|B0RB%3{uTm&|C55hg@C`2g1?0T;QyrH zZy^Bq+h*W55CHsbGw>S-0RFZa_zeUAf7=ZF1_FS;ZwG%l0l?q4gTI^r;P2bPUrqq< z_wC>>Cjj_IL*N$^aMl0(Rsw*3Gz5Mz0l+^R0>795;GZp_UrGS*&z8_H%>lqaTSC8- z0N|f3p@UKk4Uq}G(uS~&TNC5D!Ou=7B0PwF&!Cy!K@ULy*Uq%4%uWjL9MgZ`y zZQ)-=0PwGE;a^4o@b3l#zlZ?f-wg(S5dpxz8w~s+0)T%v82Cj50RMh8^h*c;{{3j^ zmk;q7Ied$Oe%rn6 zrXl&)Nfn#IQHCFUEEwMmI-ais`Kxlb?xLJ#UgI%=L*}vEO)0{+1jCdh{L^_wwG>v$y-nRW#pRF1~WoN&c|)y;>Sr^P+#E)cS6zbpvr3 z%gXZyhY_6Iw5g)>WBQ~|;etSlpbVYCR9YPI+wh9K47mqUq<|K(-#BtdQ%Mf zLHPufFOv;>qG1GlTov?jwkbT#*M7}74mR;C=u#vD^@@3YQOxTF^oNWkPc;3QEUTrE z_m{Fp6d23s-1F=Fznb!FMsPT2=wE%}3nF#9$*k>Xb=o4J84pQ*YV6x{5vY? zaqURDR}r8z0^7g!IMGxw&1|!n&W3j|S!^_}rEQ7$&JWp(GsC!axiT-`$QLbJO4iHh zbXVI0;dg7AfJYtMp#%bx_(HrT36mTwE*eXB9PCpCngSGh-U zz4MFilutWp3K})c*~cx6qkap_&XP3g;Ln%k%!Q)k@mNP_e0+T6we@zR9m3rUI1(%_)|_eHUV9XxpE#HW4y*e6kk8&8JK6TU^wR=+bG!;Ciuqft}Gj-23`c0K4GDD8Zlmlgsx%LCkoA zproIiG9Q-vPK>FJ%#x8_UjPz?HE77?CGPxIvG({GF_FJ$6erWEPr^c(hMF1C9@_Q) zJqy*;F3Ij|Fzegd@FE@6sqArM*!jBROG?D>StH##g-!nm`2hY|qs)164~>2me0>x4 z@7M6U0)5`=EMsSo+)ien-KQfd>~)$P;4$cWZZX$1Zrl2Tt#=bXwAHresXyRpNC+yU z@%zb*(eGV5eTyWo@)YOl(tM(xyk+vFR>45y&HQ59VK`+*eei-BB zpyd+CI-o7Kc3fJ4?u!Bm{&Wo}#3)m7*5~M6W8`q=;QfRX76vF{h|=Yr?%<0={{~Ags1VZdzI>32rBOY z&yCmGJxnTjS6N~ipVR&Rt zp#mvA%=&ffx(_f@g2&GRh!xH1*l_>@MAodQeg~i)k1=aoz1Ue3jaKC1ojvSI{VbVo zxH$DzP!ui7SP>k)pgE^APuzcA#XRW(FS+QKLn80?`>YkOcw8L3S@R{V;!I5(DQkcf z5`Xxp`)S9QbpWJ4`UL*K`f`djagFl1ooExOSHRXxQ(EFhv)Vngtz)>;%|ifA>{W^2 z(i_v3NGqF=r?AD(KQkUk8a{a1Ls49pA$@M6RS@g#!+cIV_h3iCH=yy%TROzt^-`wW zh1kjyYd^8|?xwg+`$s2YBd8+d+IbagEz&)eXl?WI?F7yZzqO&6hgpDRlLa)djw=ha z&K<-XIl?Dl27bMfrunv|)Ed}e+~*IlI^g{HoFE``bOc>IHiMV;-lZ=6a@ln7CawS& zDo*L@7c@LYUijJHc=`VBhOMm9kK?9MadCi&H`&xvl4G6tP5&X`$&z^Bw~IN(1sEqy z!lod8iw5Z9_DM?u-DWKOaf={l=F;FrEpk)$juiQ2I6BJ9Gn} z4IaDC5Pr`F8zEay%cs0-&3&8L?DJP)Dx2;$jJCmP#&p>7Jg$wo8_aoztjff6)Zbcn zZQ9tdG#il}n!~(k7HZccEk)dXu4nH5w8cLEd#Ubun>kS}Zsq)H+1}v20c=0>Lfu12 zL>O92GQ~v6v7@Ar1P>q>AfOdchU6Os)57(dTr)Wk4`(hqDaDc8-tI=S!>z9w8O_R> z5)R3yaVxs;ReZ!%BQ&bKr*k6288r}>W1geOcKf|f?MLVe2P-TIQ7;3Yzb*|YEZRT0 zj70h~fY-E_Fy&dy(2k_4->nAhAIi_}ht3z5NS1|kQ)bZ*A%JeKHN&9|bzdLgYuFN`G>GKUENv2T zkn=URW@cujpPYL{Uv(c~>=SaTvhN#s0w3EMxAr`<24GojT*~+UyaM?txI-sRB7^PjYQ$b>a6FoxZ1j9v)c=l)rg2IZPgUd3bJ1^6*l;- zcMClY`=c?)GJ5U8a29H8ffRpd=H*BFb?m&lxOc0xtSnZnCCWo`mS5bI&usWvf{K1~ zTkz;K{&z{eB?ih64*tEsp1Rt4@l47DJhz%&E&#bRmaeV| zwU3kufMkn40BcO&|60?lScpp49yiHra_Z|bqHhEGYIkogX z6uO7k0zT!>GHdevzI}FfRzEJgVBWK;*?^bN{FHPslitJ+EjKx1`O`@C{$-f&@_FHE zQ%O6}yEmLNy8Qe=m-ll1zN-?7)@dM%_iRJ1)vUFerM?wOQr2*|(*BU=P;$l>i@^lB zwc|Pp!LcB9900VvQsJaLcpr_;CVD2(rvk=pz(1z0$|+~*`bH3MEd21(k+5zxEur5+ zSdQH+W(3Zub-t-ouy4?aMMz=Ja$8KgO+Elq?>bI?bX;+^ke28#f!L|Cx_m5QT8+Tb zpHtnue0tP|QI31BL%BqCCqQOLUShD6v977LRdV}~@IkfeGNvHLK6c~E=NU{b+2;_n z!ZElMxTEa^g5S?Ywij?(O8e#V^a8KzSkaa=7OrQzhOu-yHc4sjbdW`2N(P#?ybZi@ zdAx~EsP&F9JWWu{ctE%D(MY6kOJVax^OT8%vsXYs!1t@<M| zj+OWF-*zw1nVKKi$9yZfy^PLXC@7(*JF);@mRl4TuVe&Uav2Y=BMzVJ>J)(5D!S|G z`e=l{mIWe2Qt!a`&d}3{yHn;-nZOR9{P<{ggMG)(PvVkp=PIO^rGdbSZVh4!U8tZH zslG;vbMh%f*6(D)r;r+JhckT=2GD`Hj=KktK`%qejn4xAemD4m{v1QQLzjc{V8yb~^u z<3@0G=`9bHCa5ae#`cuQF_o-+k)nr?%cBCrNmSzW)Y(tVtJh4DSPJP4*Y$k@=iS9P zZD2buhhT`>QG5aDM_rq>D z%vOJ#2Km?g#Fc|OxH1lZ4feT0;MZ zV^TBTwt-m&?u%7EW!(Bxv zu^U_x)te!S)=O(CQ~^HDn9^Y}qud)}x~|JgrJVG0woSAf3p z_6#)o{FvlYviabyTiUZeo2h{1QzTk$MWj=q=7yOWoo@UXB1{Xfs%fYw1m**ehfi+9fUy zQV6ok*`3+hJr7oV4i1d3Z|idyLveb3{q*o`v&hDD2Lwc%EjxxJSjW{PSw9@(;*c!d zp%t%KUv+kI`*4Vw0iqkekSWCcpwr2(9TGS{F%%AN;?jYEq03E9H1f&%2-f<^?d^u zPj6PB0M%Ia9@W-{igIa6n_l)PmMK7am6>Ty5?;OW;^V~xP`29~EkQm3B;;gXpvHk$ zpO90GONiJw)D<^z9YfeFh{u~A6c8}6a%4bo}| zfaWwwX#!;iU5^$X1A{PH`0A&@41h^YIb|_6?tc7R#f`_N{$QVH=`U+?N_xTJo8R=6p8-bc7;> z-vf2BwWIbq&jKvM%p2$5i=3xO#_`T}>75>z2p(FJ~p8Zqej?RGt>%zWSG$J!a*0liaRmbHxdNo(g>$rVqUVZ9QEenZjD z>4kmgRw-3YCph6Tti^879FQFH7Id@IV_G}J>na6R)MtVpejepp zfxY1k(Oa#Ger{c7rm+8+i%$NNq)>Mt#c8;JNBh>pn;E6oU6^Fb~Mw* zQKzdu?(+qMX1KGoc+`@2OJghIGEp;TZp(k%5y>M2ES&M9z|frSRkR?H0BKH#p)WWE z8Gr7|=;TVE;OhxaLP_&AfMYk=A`4$+GW`e(@Ry*u*idNABt$}?T^>PEYbm5B$CA=6 z&W8Y$@y3Ez?lFXAnj&Z~=1pQoI2rFHuuFZYtw)2sUiV{ALlxck@{20eRE$AvRKXKW z7k|#oE?kaywHAak#X4u@_R$+<1S|Q1=zRd3U3}L2Duyd&{DhSlmgX|9Q0sfhd9b4B~pD@ah!{)umt^3Hk zFVzGw4=>K`PJOezXo!cC?W)A1NAzfTS*CawGh}~2DULA6dHPf~d*xM}wM(Ip4IfFc z7s5_9Q32{n^}?qC?bu&!ft{khz-%Wgu5URe<2j z0levD<}AO1cq;E<+O(c!&od)v?odQc+36Op1Ft0;y#VGWb^)#eoV6d3?A`2^))!sF zpZWQGq@H5U`SH^Ir?F7>+R6i^ri23^$CPyR5T}zVpzZ;9_k2Ur>bz|SI%AIf5Din5 zuUSGWb!BRZ2Os;I-nmt_awp0Q2}IAEBBpVd{QaJSSrSb~ye-q;S7oz>?8?dEkq?cw(j{tcSl4PA_W!Vi5ndXr9a{l z`ANQyS@SDLK^EH8-|*H!bGk?kE~!`j2KPQ3uv|5hbJYFyR@d4fS3z@bKs;c<wb_-a{%Yc@d({ci~fkywTykF7dE~?QY!ufUGId?6GYaCFbPR%ita2 z(}O8v(o?SmfOi=46_4cWmJeOLoY@h>V`f68ftt&y+yiy*Sg3bUgNP$)x3xzC*ol`x zF=8<5qZr`Q@$%Kkm5>*zFki!G2fI{6o+at;!37yTuRe|1a(v!=LBsmuAk9W8oxRKZ zj!aY^Ox@=@!iu>;>gwr6Og%ESu>1|5dNt%7vS}Nz%yrJCeGx?}s^%`vl`bCTQFy1W zHSeM&`eLqRr0InK1~Op(ETiDcZaJgrf@#zZcfde0te#`XS@A{9z{@9)7G9s`Gs%0r ze1PId#jj$!w+;(s_lg%!IihI#PTe%P5SPNc$2!B7jkd`i?^Hyp5V~a|rsWXz_al!| z?&$;jHj}NDiV<)_i!z8CZw72~I0|-a>Ag zYmOT~qOI zpX~I#$U8gdW)}b~nsWe!g4oGkEzu3l8O~B`l#kMwb|o5nhOlD~y6^XmMSRP4i`HkM zdk4`1EhNFc2wfi_@D!ep99oeEEWm$Q{ox78HBP+d33ha2hwjC1!F&aoJV(NlbK{?A z0F+zQ)cZ5Eyvk#d^s3=Fk!O$#wkckT8gN}+zwyYLHZWf7Bta_Tg}|OAtaPakAJ*`_ zRTs@ALQh0AtoPCv<$=4}GHLK#qY+XB>_OCpus512!ljmq z8G97)^C7!4(y=*SU!inuZUzBQRd(pq)_v+v!QfAJq*hThPpGry*fz1}%swMbm(`Z1 zW($J$2u}+K7Wo+;LbvbW?ZQOz*TW7k4><#9Cqx!T1r$j8amk=an!IV;JJt|jQ~0HY z;{`eU*_qwG56mO4@>n|6G)I$ZVK!ateL2nxZ%%xX(TEJIsQhk6F z15IKyXu+I8G--C^HMnodGFI)b`I!aVNVk`D1-v0P`b(Z^&qEN(T)#DFxVK-(6SeBE zdX8VLXs5efMr`ljjL|F1xmCFAu_sgtQjjo+Ev0+Yc5v1IvFy%a&cyWgK3raFKMh+^ zpKAU&mwEo}l8x}~y?4F5iQdt->>d3bGGHsGC-|?y8b9?A<1YfiASVe-lDo9tWe9&_ zFKjsF_J`E$uk?WdBn&z~5iORA&jC|j<#~CR$3SboR}=?=^kgY&?2!-7BSbG@o~?b= zX1Wc#DH?!Oe)X;Q5E3ulH=-g!Iy}F%20#7L=Kbz`noDh+em9>#)0Erj@neZ4{Bf;Q zoX;RM#o+v8<48dAoI5Ft^F{2V7Ton!KF76Nxylllt>OjeA?mqUHl+HWPwMv=rZJN{ z@kg4jJhSB5N<_LU-={RkY_J!IK3};7gM=5nUJTgrl9*eNZVD#u`eKOPAJq|V4XWw3 z$2Ey`!#qR+W}zn%yI|XAW(A!1UQeHrrWYbN{6#^VK^k!BZCLEGuglkvc}z2svKuy} zN+DM*1Y}*JZ4+H=g)oqJxY6u!3mC3_XzIJ?_5QfcEWON`uof3Nyg|4;$rvYGewJeV z27scpuKIj&(^qiJaBj0WJ#M4XIEjz5TaR1}TGl_j2qrEYww|RLJ=JLl2@lW>YSS#tQzg?W~<+LC% zdqtq9!@Cfy$$)|%`&5&>-wIm%t&bFFU{HgI9eUSCG)_%er~c+T`*+H)fn(5U%M_pN z3hrhcXjD8NaoFHj{Qv4Y_jsniKaPL2B%wtYicG0=M% zNJYpsR8(%!P1w?fqHnGlkqNoRjLq0=`<+j|-|tV~d_I57!{d2A=e*wU^FH_U*iJ`y z5=fc}tUzx<4yB>JIB`i6Y4sqcI&%}@VXaL47a}wERL!;cpM}bJ-JAo@n=u$tsP?Ja zxpzYqqHsBCSJpppXMb)W&FD{yJKygS=9Dv&-z#zY)dGdml?!yjHO58)dy9>zrqBlCk}Z#zm^L z9ETV6x}MHdF42aQ^v5tBGvmXhRPsV^Zg*e0>+u|}#7!PA)4Csg1rlA=fSFQ6z+eI+ zESoi$EA?nwOASYJm3*FUG+q$(MCh+47mowG?4F-~FydH_?7c;Hte8r8Pd_7husgCl zJGICTynCzS(o~kBen1BKPKVW_5p|{ewaY?0=u_EL`?IbTS3}Hp_9qC~Sm(^N3 z%71LKZXc9Ta#X&zMA;vv`n*2U5=`J1m8%^h9;$M8kz=?Xf3k7e?rA>Z8d2wTqh|;< zoA+U0PJLc5E%CW#pKH=5V3y_dQ^5LW`rBf0f(Gymhyh zr<}yi$;xnlm4z6#Ti86v$6Lksoj+=B)yh@Po$#tOB2FDf|U%LZ>U51u>uWB1xB zhO}nS8-J&@YGeBflHi)cE5^^`rn=|A=2YK2xiC1M)?6pcrg#_KVPv>``eJ03zfwO* z&9mrEn%%0RkVeccc6!{*Hw&7o4VNwBOg&`X^hMDIdt=|no(Stmif?(Hcuscydd7iE zS6Qsf6k^MVb&0!;kG{F>e-RUyU_88>?Il;obiCdnaGF!J{@4RJ+sX2Zou#Pl(R6>dPoo>hRXWOhFiNidCXFOB z>RIQ>`0|$wCEw?$1DD^sN2Z-V!)x)P0Kuv7h02$J?LYA>CV|dyHe)Msu?df`Atx;Uw<)41eX-Hv5+Zy|+Z@i8NzSy{*FODN-Ef-YUh$Om* zF3Xijrm*psy_<-AnmyHmeQj$)E3$oxQ$|<{Zy1hwoufH=9G$xP;oA&kX5?bcVq!1S zTiFZOlY(Orx-Jd^4lYQ(JS63xkx@-=$LEPPSYX!By_aXy`Ya8(&)i`b8@Mju@8 zHkc|jzI}SIe{T=_?DO>O(tM{oMB*NHCs*l!vLpO$FAe{dKh4_{49@w}m*xpfK1oE5 zY19#g)9K7A7Bi^oxYLoEn#^57-zTYoH0N}UsiI@vw=+w;+>E<8;@I4|j<$G5u!BVU z#5BG=f5Vz@>ODiLwB{2DOFkFnbCy_(!Mz0yvlE>M5OZWl20i>(M=BUD(R9K-e&#B; z=tpVu4n5VMRYbDwAT6;w&X%yJfz(1GTT@C;T7-i`XeGRb<13%I75n+DEmobYd#`%s zijKO1+55wa7!un^&^LlCQ zG7;?1=*eHHTko?wjz3l9NTRXe{`W1gF!5;4CA*NWaPkXd6IPyEhH7}15L*Za`lKWo zViq#5SeIz9C%jB2#SvRc?aj-u-aY1xNp0&?-Q6qcV#ynG8)t=Y5Pvq{i*ZJ54_y~uQ=loVwd+f)05tNK|S zYzP)KOP8O0)dFAH-qhUQ`TZ)9mNcrD$tch~SljDU<62l!Q^8|yDN=Q*?~~a7&@fEl zW;$+X#tH6~GSL*T`rgC$zjattB^@HW>1TC;jVFvis`YlBS4dH|6Xp6!p;+BTM0!@U z*VZs3L5$)0o-bv{ogiFt1MB6TUsyw;Tt5NZBG=792KMkF%=NzAjdAhT#=~c4RO?<7 zO5VIK73yqwp!w9=3P*wTQv5qiYpC{-m7PqQd95J82XEHYbtJd?*~{$@rCjuV-ibI{ z@tZT&)oH^_I*IgZMXrdjqi&6RTJ4}W%}!IU#Z$h|T}IYh`AK}Z@ z$PJ*|!S;g@#a#b@%d@aSjwPh~=hJFU{AZKp$TYEzP^Y4J0kQEC1OB=)CJO$>4W44#1ZykkIbM)%#1Mwy=>4(~-vhoSJ!oXYR@u!DAukCGR zL+RKc-I8<*TJpZ=(m|no5D!k|*GkugWx~hc7U+QxTX~?o3FZp_~@+Yci(u85rm8|E>21RM)m@a6=|MQOmn4RkIlqWkBSa% z3=hgGO>(Ptmk>xkEh7sPzHckG<9tx98RPCMWU6vS&K8S_xQHJZ6;9z9Tj?^Z9vFie ze*7xj*+|@)puN@k;Now4#zcqT(Cn5rTpbl0J`C2*ehvXcf@?)4FBv%OPTc$k4`_$< z(&go9Mq=n}u4rLX+!cJ-m?!|o)5h3!?eX^CPAaf{dFEB-5?qNR-y;)0m0qv=0XlIX z`E-qE1f50q_3j7+6eQnRM;08yThGWcc=QhQhCtupJ$TNu_u8OdI<|HivC*9FJ}UIV z9iau5kmkZnzx`Qa#Vi&jZGXE;X06m~s>E&f;dv}vPel^HOlIiF@I6q*@bnRl0J9Yz zr*X$#pD%Vkdk5KkUjpVM{WdQ<8PKm2tCys9OiCvCwW8BkO;~t!`+?C@A6cYfsvmJk z_-M7Ny_^0?{6<}Aq(Z`lz@$8h)-^IE`F3iC1$^mO&|bM)%S z_ATY#C7sS2FYF&23WBA{V&5mTJ*ZKA*t??*UVA0_n03{LJ0kc>r$ayDS3dmo(uBjR z5_`Gzj)L$WZOM^kS`kOjMmCM7h|8f$Ffx@ z^0eX+OP1o&gNKpl+%f35%g$p^aG)8zV6S9qAvL}|| z6*8?&5S@@@;PtBT%K?faOCx>5aJ8szujVYcm_iKMFm4q;R|N@IcPzfFaJ<_4%ESetCi5 zErGxiF=<8hmVrKp;(B$pT$XPf^4>1k)?};A5e$4LHngpbJF)gJNg-B_MLss2f?HH_ zGDF9*fwZ&FZ=D^no0_&%SNVMnxCywE!eS<+)PR4&74YExUZy3veTiCo03?m zT@=z3!6>gV5+|EG#hN#q`}Wkz#f~kb^X8$r=1kW6Rkqk~t2xB4y=$~`;MkE&*ZpEC zAwS#n{QVbWRt?x$S4T(c^EhKsf|8-3DVxQ_kQ%&_;z1=|FyA{gmieGFe1L)nI~Zm9 z-GLnzH;I*b)GO(>xrDP8e5{g~ge`i^R@PMG)6Zve=hH<_=F3Fz+t8eDdYdYv^{=d@ zabRNLr`dkp?l~^UYyh5a^!CddO}lSzc$h0xLKObfXR@_4zhcyE0kOo^L9&-WaQC~j zU6Qd*N?wLsIauMT+~pl{((G~X=atID`0VvHh!@=U@T2meg_2KB<6MNyr?vyp*&3~4 z3$uET_yO#?X7qBeh>e^vDPAyD?*AI%rNI}9YZd#QJwca$hA(!}4J*aFxE6MaU+Kt3 zTy5n}KR{zRTJXESHtsV?VPTUhsoy4ABq1#P(W{oo?EjJ1mVhW(Sk?BAzC?mpwzYOK8e_S~!a~25+4~x7#iL z$bEE)SHM<7F8=uxJ}}7TGXpb}6*4{x;S>>093-k8kV{VTE~<}ETw6pa;}^74`DZ(^ zc?T`0mKU`**4{g@lzA?-w=?^;h_}B&>SpmOPW)Y?q#0~a`@VqzVVJ?=qrvtRwR-nN zoZ>t3;s)m#LB=~-){aZ4=82V|mD9wmH8V>e;aSmBMM8zA>7T`3e9A{}npROb{KmVO z;v;=_OUK*Z_4&V6fWb6Jn}+3zdjrutk&Xy*KcUo?bh%5`n{E`n`f6biy70vIijpeUeooA z&t92vM;bFoMvap~LvSt*p3Cy7OVajt?QUc5 ztH(hZXU#m)QiLuKI;SgF>;*^F;3}@U=c7`aR}EmE@(z=jEZnT73T4Qbh_@P_Z(UOS z%Kc!)N#_<=n0*E;{=oyEGgH}A*^yvN2pcuu3v#^hptHC+rJX0=&O^$hYdK}PubHpO zmr`Chb9J)G@+vjKfWe*~jLVrPM`yWzIpC%;i#w)6ZWHPrrsDXG5+KjO&>#H`KWZX} zrYZ&)QH_R3R#{Q9ynJKIt4oFz*sj~u zt>i7lMJ+c5?p(S$TT+8&4SIWi&pbzQ;=+e#2oT7>R3>C7^4+Mvw4hLz*5H_5CXz^3 zglJ2wK9@K3^LX;R3Y@#G!R;618u3P_FzM$~>#)NNkJqXY?IpM`UMXmY{S~&ef?G_3 z$5YiUPIHuO#3*&k=03YbKZaE@>=td6vdR$9$X9nmI*g-vqLPx zA!>8s)9nv&E-j7S=HEB@ANn3|$?;;;FDfEul*Q5Qs=U$}7$9I;2kF%}new{j>?y}) z>T3zVZ%eanV8W8Z=?6;Q4sk!?m00*QhAB;&)?3Yo-Q>lKE?_B$Ph`jPJ=`w2h&B%| zTuHAQOGx(EqTm^s@DS-(_z!{ErnCd0jT*y^4*TyIxE9|aCf%4aid?+6Zy9jy!E{(8 zZ=hI_Hit^|&bv?DZ7!I*=$p+4scUGcz9+ zv_8I7NgkwHJQrqc>)J2{v_>mkG5jp+lr{1LzM9qkUC3YL;oNq=YY+a)PJw(=Bq3<) z5ecaD8>t*&$OEt678!763It7&fPCX6#uHFVj_jBHM*5Wi;pf2b0WSd=I8XgEgPBJo zuiOF|qrH#t$Y~I?bi(@+1j3NEtn>T)>EjCT|E(~pOVR#U>ENU4Exqpj3<#PF1nvSt z5epE3!(EEMk|6x63HycUNl2LC`$FJO3~c{IoHW06+70g%bt56g&$$ z27VwJ$-s0H0SNbyM;9f_PUF^K?#XD&e(prein zu3iQ~eGugPeZu?yL>t2C8Ylul`Oq+^OxYDEwf#3&Ux_Z@nDNhyovR^e00?NCL;%9| z*Gw(|DIa130Rd~#1t2_L6Fmk#9-jN~)h0_*FhM016n>8Lxsr8yv6< zaCu#H0YCSyh}7MH9s>wB(VtAfc=?b!sN<-O!qt zou!})K)AoxKLSAi_g@bv0}Cs>(FGv9!{>Ja6Q-xo_2Z{RGQJQbgED{S00ZXvLy!QB zmXRR-{+*uwGk-=B$X`ZxvA%6tw{8G>kRjaU>OU6#X`m~Jp{T%d1L4V{97&KFgf3v$ z$>N-`d{AqYvZ>-z65o;cjLrbE}sH^v1_HrgTl%1v|u z=YfG$w~)aOhI}XU0Ft0H;&%bZ8@e%|6a4jrL-)V@J>Uvp zQu@ylNn@?M?D*RdR91TK4I>(YNmwp2eMmcOdA) zg!jK5lmzo!2x>iT1&w`G`U@8eK_VbP9>_+5d;*_>@P+YUF^7@>gCtN+M9p9-!sp*b z<&p?jOhM(-5I*-F1fwaGLK4h=fSSQ{gv+O+av6kUAE9ztgv(_B|D$+74oM)Bh013l zTsjApV-YTui^^vqToQhYnm`^&fO(F}6%a1*5|z(JxEMqzih*+xzE@cAdjkJ@AQ?Pq ri%;F?(k?d_6#e?w_tz&R0sX^Ud`sBR-zdZ(JVy)i^@XPX3bOwJ@TfmU delta 7289 zcmc(jdr(wW9LMjy3koX&iXjiZuquXum^caIi(N#ChiUSXG+CRV0vX9?iu||)OjIN6 z{D{&tU30XdtZ8T_O&RCrI7x<@hACOL>i8H_V(ftd*6)UY=q%UW!!B@VXFj|0J#%;W zGrx1sIltB}&8d%s>T%+7uKSwfasSPIXowzfn1=b7f?epPe5^mJ^&V9p9ktfCe*B_q z;q_7FKYBw-_2eYYWWS0ta>@^Np#`3$ZZZ3>M?||7G|NrZNt1#ak~WW9(E!0;O{)y{ z{M0ihRNLH8`g(9^&HVVIo68OHt|vb`a3r?&T4TrfyV}68o0_t>adq0NviuVn8{D-c z!s4^;ZmrNIT&xLpyZv$D%rwLK+5VM&Y1hic>KS$3Yaw-K=d5MZkN<2kUP&&$aP!R3 z=JSE`x*{{{OmFUO8R>7>dPUM5x>daPn2TY1e!);pg#Wz7c{8JqjYu?o5g0gl+k~{l zpbH1Zd~Ccov+k3)f`5N%Shq1@?kQh6vB2ZfnSFPXB3rx`-YVSk!NuaDjfI8>t4P#H&ez?Emaz!Rz6}BVi&i06@;*wo;@}Bm(u9jmtdGB%0 z&ne!Lk@C%!odL-SrmCgkw_?PF)r+68tlx9{Y9RlP)-tK8q%mdvHddYBWS^`$!O1>Z zb%K+9vg!mI^~vg!RVUb}Pgb9-I-!53yOmDp-|23p6Z&_$Ta_m`_V~2&$*L0^dwg2? zWYr0dJwB~`vg(9~mm`OLvg(9~mm`OLvg(9BUEOW#gg#x}ZR>Iv)I(MWiI2ug&{J_%#6N|4!jh?IBuLRH5o)HPnP7=Qnb1BR zEd+5E@_*AGn2kC@Ni6CK@9NP=I2eZ#;p7}N6GqKNnJ{@CS_tV+Bi~LxJ`r_bEiu_$s*qw$tLR&iO32vEaBuvagiC}mR&4j8Y zC=>Q9{oiTy(r<4ZUxvniMB!pKN`&y`XePwHfHEQXMYIr#a**#3g~nXe5q^CM^#s>E zG!g>xQ6l87Ky!x(n+iBCMBqwZcHuZf7SFY0xQq=BT&+65Rk^|0HLCd_B_F#^H6N_xE7z;$Zk;XQ*VOQu>VP52 z4YV6oa}OoYC{oRbD*5hBs<~$;(15mL)d6104Q7?7=H5#FmZX{wQ}T1As`>C#Wk5)o U>Hr@lf3;jSe@w{_S3I2m2MipGtN;K2 From 7357c3d62c001178e3b2720cd9b967e6b4a32bef Mon Sep 17 00:00:00 2001 From: Benny D <78334662+benny-dreamly@users.noreply.github.com> Date: Sat, 6 Sep 2025 16:32:00 -0600 Subject: [PATCH 075/134] Revert "Bundle needed s4cl code" --- Release/S4CLSampleMod/s4cl_sample_mod.package | Bin 3228 -> 0 bytes Scripts/s4ap/events/Utils/allow_read_items.py | 2 +- .../s4ap/events/Utils/send_location_event.py | 2 +- .../events/aspiration_event_dispatcher.py | 6 +- .../s4ap/events/career_event_dispatcher.py | 6 +- .../s4ap/events/checks/send_check_event.py | 2 +- .../s4ap/events/items/receive_item_event.py | 4 +- Scripts/s4ap/events/skill_event_dispatcher.py | 5 +- Scripts/s4ap/jsonio/auto_parse_json.py | 8 +- Scripts/s4ap/jsonio/s4ap_json.py | 4 +- Scripts/s4ap/logging/s4ap_logger.py | 9 +- Scripts/s4ap/modinfo.py | 4 +- Scripts/s4ap/persistance/ap_data_manager.py | 8 +- Scripts/s4ap/persistance/ap_data_store.py | 2 +- Scripts/s4ap/persistance/ap_data_utils.py | 6 +- .../s4ap/persistance/ap_session_data_store.py | 4 +- Scripts/s4ap/sims4communitylib/__init__.py | 7 - .../sims4communitylib/classes/__init__.py | 7 - .../classes/appearance_modifiers/__init__.py | 7 - ...on_attach_cas_parts_appearance_modifier.py | 359 - .../classes/buffs/__init__.py | 7 - .../classes/buffs/common_buff.py | 99 - .../classes/calculations/__init__.py | 7 - .../calculations/common_available_for_sim.py | 174 - .../classes/commodities/__init__.py | 7 - .../classes/commodities/common_commodity.py | 28 - .../classes/common_resource_key.py | 133 - .../classes/effects/__init__.py | 7 - .../classes/effects/common_visual_effect.py | 217 - .../classes/enums/__init__.py | 7 - .../common_versioned_enum_value_collection.py | 81 - ...rsioned_sim_demographic_type_collection.py | 39 - .../classes/filters/__init__.py | 7 - ...common_match_all_non_sims_object_filter.py | 19 - .../common_match_all_sims_object_filter.py | 16 - .../filters/common_match_object_filter.py | 36 - .../classes/interactions/__init__.py | 7 - .../_common_interaction_custom_mixin.py | 81 - .../_common_interaction_hooks_mixin.py | 325 - .../common_immediate_super_interaction.py | 427 - .../interactions/common_interaction.py | 462 - .../common_interaction_override_name.py | 89 - .../interactions/common_mixer_interaction.py | 460 - .../interactions/common_object_interaction.py | 77 - .../common_social_mixer_interaction.py | 466 - .../common_social_super_interaction.py | 518 - .../interactions/common_super_interaction.py | 894 - .../common_terrain_interaction.py | 108 - .../classes/math/__init__.py | 7 - .../classes/math/common_comparison.py | 55 - .../classes/math/common_float_range.py | 69 - .../classes/math/common_integer_range.py | 69 - .../classes/math/common_location.py | 112 - .../classes/math/common_polygon.py | 101 - .../classes/math/common_quaternion.py | 415 - .../classes/math/common_routing_location.py | 110 - .../classes/math/common_surface_identifier.py | 94 - .../classes/math/common_transform.py | 102 - .../classes/math/common_vector3.py | 298 - .../classes/math/common_weighted_value.py | 56 - .../math/common_weighted_value_tally.py | 38 - .../classes/mixins/__init__.py | 7 - .../mixins/common_affordance_lists_mixin.py | 21 - .../mixins/common_interactions_mixin.py | 40 - .../s4ap/sims4communitylib/classes/options.py | 117 - .../classes/resolvers/__init__.py | 7 - .../resolvers/common_double_sim_resolver.py | 99 - .../classes/runnables/__init__.py | 7 - .../classes/runnables/common_runnable.py | 433 - .../runnables/common_runnable_with_sims.py | 187 - .../classes/runnables/contexts/__init__.py | 7 - .../contexts/common_runnable_context.py | 250 - .../common_runnable_context_with_sims.py | 279 - .../common_runnable_object_context.py | 133 - .../contexts/common_runnable_sim_context.py | 140 - .../classes/serialization/__init__.py | 7 - .../serialization/common_serializable.py | 34 - .../common_serializable_location.py | 98 - .../classes/test_based_scores/__init__.py | 7 - .../common_sim_to_sim_test_based_score.py | 73 - .../common_single_sim_test_based_score.py | 69 - .../common_test_based_score.py | 60 - .../classes/testing/__init__.py | 7 - .../classes/testing/common_enqueue_result.py | 201 - .../testing/common_execution_result.py | 197 - .../classes/testing/common_test_result.py | 149 - .../classes/time/__init__.py | 7 - .../classes/time/common_alarm_handle.py | 81 - .../classes/time/common_stop_watch.py | 82 - .../conditionals/__init__.py | 7 - .../conditionals/common_conditional_action.py | 66 - .../s4ap/sims4communitylib/debug/__init__.py | 7 - .../debug/dialogs/__init__.py | 7 - .../common_change_object_state_dialog.py | 114 - .../debug/interactions/__init__.py | 7 - .../interactions/_register_interactions.py | 163 - .../interactions/change_object_states.py | 70 - .../debug/interactions/induce_labor.py | 62 - .../debug/interactions/log_all_game_tags.py | 69 - .../interactions/log_all_interactions.py | 134 - .../debug/interactions/object_break.py | 51 - .../debug/interactions/object_fix.py | 51 - .../debug/interactions/object_make_clean.py | 51 - .../debug/interactions/object_make_dirty.py | 51 - .../debug/interactions/show_active_buffs.py | 74 - .../show_running_and_queued_interactions.py | 86 - .../interactions/show_running_situations.py | 90 - .../debug/interactions/show_traits.py | 75 - .../debug/traits/__init__.py | 7 - .../debug/traits/_auto_apply_traits.py | 442 - .../sims4communitylib/dialogs/__init__.py | 7 - ...on_ui_dialog_multi_text_input_ok_cancel.py | 66 - .../_common_ui_dialog_text_input_ok_cancel.py | 50 - .../dialogs/choose_item_dialog.py | 199 - .../dialogs/choose_object_dialog.py | 519 - .../dialogs/choose_objects_dialog.py | 434 - .../dialogs/common_choice_outcome.py | 32 - .../dialogs/common_choose_dialog.py | 102 - .../dialogs/common_choose_outfit_dialog.py | 372 - .../dialogs/common_choose_response_dialog.py | 513 - .../dialogs/common_choose_sim_dialog.py | 318 - .../dialogs/common_choose_sims_dialog.py | 309 - .../dialogs/common_dialog.py | 92 - .../common_dialog_navigation_button_tag.py | 13 - .../dialogs/common_input_float_dialog.py | 216 - .../dialogs/common_input_integer_dialog.py | 216 - .../dialogs/common_input_multi_text_dialog.py | 209 - .../dialogs/common_input_text_dialog.py | 196 - .../dialogs/common_input_text_field.py | 94 - .../common_multi_pane_choose_dialog.py | 431 - .../dialogs/common_ok_dialog.py | 174 - .../dialogs/common_purchase_objects_dialog.py | 393 - .../common_targeted_question_dialog.py | 223 - .../dialogs/common_ui_dialog_response.py | 38 - .../dialogs/common_ui_response_dialog.py | 157 - .../dialogs/custom_dialogs/__init__.py | 7 - .../custom_dialogs/picker_dialogs/__init__.py | 7 - .../picker_dialogs/common_ui_multi_picker.py | 48 - .../common_ui_object_category_picker.py | 51 - .../dialogs/ok_cancel_dialog.py | 199 - .../dialogs/option_dialogs/__init__.py | 7 - .../common_choose_button_option_dialog.py | 349 - .../common_choose_object_option_dialog.py | 357 - .../common_choose_objects_option_dialog.py | 414 - .../common_choose_option_dialog.py | 129 - .../common_choose_options_dialog.py | 160 - .../common_choose_response_option_dialog.py | 140 - .../common_choose_sim_option_dialog.py | 275 - .../common_choose_sims_option_dialog.py | 306 - .../common_multi_pane_choose_option_dialog.py | 468 - .../option_dialogs/common_option_dialog.py | 95 - .../option_dialogs/options/__init__.py | 7 - .../options/common_dialog_option.py | 146 - .../options/common_dialog_option_context.py | 144 - .../options/objects/__init__.py | 7 - .../objects/common_dialog_action_option.py | 43 - .../objects/common_dialog_branch_option.py | 50 - .../common_dialog_input_integer_option.py | 107 - .../common_dialog_input_multi_text_option.py | 98 - .../objects/common_dialog_input_option.py | 101 - .../common_dialog_input_text_option.py | 97 - .../objects/common_dialog_object_option.py | 102 - .../objects/common_dialog_option_category.py | 32 - .../objects/common_dialog_select_option.py | 50 - .../objects/common_dialog_toggle_option.py | 78 - .../options/response/__init__.py | 7 - .../response/common_dialog_button_option.py | 77 - .../response/common_dialog_response_option.py | 94 - .../common_dialog_response_option_context.py | 67 - .../option_dialogs/options/sims/__init__.py | 7 - .../options/sims/common_dialog_sim_option.py | 71 - .../sims/common_dialog_sim_option_context.py | 31 - .../dialogs/premade_dialogs/__init__.py | 7 - ...mon_choose_sim_demographic_types_dialog.py | 251 - ...common_premade_choose_sim_option_dialog.py | 187 - ...ommon_premade_choose_sims_option_dialog.py | 186 - .../dialogs/utils/__init__.py | 7 - .../dialogs/utils/common_dialog_utils.py | 58 - .../s4ap/sims4communitylib/dtos/__init__.py | 7 - .../sims4communitylib/dtos/common_cas_part.py | 47 - .../dtos/common_object_containment_slot.py | 37 - .../sims4communitylib/dtos/common_outfit.py | 274 - .../s4ap/sims4communitylib/enums/__init__.py | 7 - .../enums/affordance_list_ids.py | 21 - .../enums/animation_state_machines_enum.py | 16 - .../sims4communitylib/enums/buffs_enum.py | 14677 ---------------- .../sims4communitylib/enums/clubs_enum.py | 108 - .../sims4communitylib/enums/common_age.py | 184 - .../common_appearance_modifier_priority.py | 121 - .../enums/common_appearance_modifier_type.py | 18 - .../enums/common_body_frame.py | 78 - .../enums/common_body_slot.py | 728 - .../enums/common_bucks_types.py | 203 - .../enums/common_business_advertising_type.py | 141 - ...mmon_business_customer_star_rating_type.py | 148 - .../enums/common_business_employee_type.py | 122 - .../enums/common_business_quality_type.py | 111 - .../enums/common_career_ids.py | 145 - .../enums/common_character_restrictions.py | 16 - .../enums/common_civic_policy_status_type.py | 16 - .../enums/common_civic_policy_type.py | 14 - .../enums/common_cloud_type.py | 116 - .../enums/common_combined_species.py | 96 - .../enums/common_currency_modify_reasons.py | 54 - .../enums/common_death_types.py | 213 - .../sims4communitylib/enums/common_enum.py | 90 - .../enums/common_fund_types.py | 13 - .../enums/common_funds_sources.py | 63 - .../enums/common_game_tag_category.py | 431 - .../sims4communitylib/enums/common_gender.py | 148 - .../enums/common_gender_preference_type.py | 67 - .../enums/common_ground_cover_type.py | 78 - .../sims4communitylib/enums/common_key.py | 230 - .../enums/common_object_delivery_method.py | 109 - .../enums/common_object_filter_type.py | 15 - .../enums/common_object_preference_tag.py | 23 - .../enums/common_object_quality.py | 55 - .../enums/common_object_slot_name_ids.py | 13 - .../enums/common_object_state_ids.py | 14 - .../enums/common_object_state_value_ids.py | 33 - .../enums/common_occult_type.py | 175 - .../enums/common_posture_id.py | 186 - .../enums/common_precipitation_type.py | 78 - .../enums/common_pregnancy_origin.py | 21 - .../enums/common_puddle_liquid.py | 82 - .../enums/common_puddle_size.py | 61 - .../enums/common_region_id.py | 53 - .../enums/common_runnable_state.py | 17 - .../enums/common_runnable_state_type.py | 17 - .../sims4communitylib/enums/common_side.py | 108 - .../enums/common_sim_demographic_types.py | 172 - .../enums/common_sim_name_type.py | 236 - .../enums/common_skill_effectiveness.py | 107 - .../enums/common_slot_type.py | 116 - .../sims4communitylib/enums/common_species.py | 189 - .../enums/common_statistic_category.py | 75 - .../enums/common_street_civic_policy_ids.py | 37 - .../enums/common_temperature.py | 98 - .../enums/common_venue_civic_policy_ids.py | 16 - .../enums/common_voice_actor_type.py | 102 - .../enums/common_weather_effect_type.py | 124 - .../enums/common_weather_event_ids.py | 58 - .../enums/common_weather_type.py | 280 - .../enums/enumtypes/__init__.py | 7 - .../enums/enumtypes/common_int.py | 130 - .../enums/enumtypes/common_int_flags.py | 160 - .../enums/enumtypes/common_versioned_int.py | 55 - .../enumtypes/common_versioned_int_flags.py | 55 - .../common_versioned_values_mixin.py | 52 - .../enums/enumtypes/float_enum.py | 87 - .../enums/enumtypes/int_enum.py | 90 - .../enums/enumtypes/object_enum.py | 87 - .../enums/enumtypes/string_enum.py | 87 - .../enums/furniture_objects_enum.py | 16 - .../sims4communitylib/enums/icons_enum.py | 31 - .../enums/interactions_enum.py | 145 - .../enums/long_term_sentiments_enum.py | 38 - .../enums/lot_traits_enum.py | 67 - .../sims4communitylib/enums/moods_enum.py | 35 - .../sims4communitylib/enums/motives_enum.py | 53 - .../relationship_bit_collection_uids_enum.py | 38 - .../relationship_bit_collections_enum.py | 34 - .../enums/relationship_bits_enum.py | 514 - .../enums/relationship_tracks_enum.py | 23 - .../enums/relationship_types_enum.py | 21 - .../short_term_relationship_tracks_enum.py | 30 - .../enums/short_term_sentiments_enum.py | 107 - .../s4ap/sims4communitylib/enums/sim_type.py | 629 - .../enums/situation_jobs_enum.py | 1083 -- .../enums/situations_enum.py | 1217 -- .../sims4communitylib/enums/skills_enum.py | 154 - .../enums/statistics_enum.py | 1698 -- .../sims4communitylib/enums/strings_enum.py | 269 - .../s4ap/sims4communitylib/enums/tags_enum.py | 4867 ----- .../sims4communitylib/enums/traits_enum.py | 2715 --- .../sims4communitylib/enums/types/__init__.py | 7 - .../enums/types/component_types.py | 94 - .../sims4communitylib/enums/venues_enum.py | 56 - .../sims4communitylib/enums/whims_enum.py | 242 - .../enums/world_types_enum.py | 84 - .../s4ap/sims4communitylib/events/__init__.py | 7 - .../events/build_buy/__init__.py | 7 - .../common_build_buy_event_dispatcher.py | 65 - .../events/build_buy/events/__init__.py | 7 - .../build_buy/events/build_buy_enter.py | 51 - .../events/build_buy/events/build_buy_exit.py | 51 - .../events/event_handling/__init__.py | 7 - .../events/event_handling/common_event.py | 25 - .../event_handling/common_event_handler.py | 100 - .../event_handling/common_event_registry.py | 78 - .../events/game_object/__init__.py | 7 - .../common_game_object_event_dispatcher.py | 131 - .../events/game_object/events/__init__.py | 7 - ...e_object_added_to_game_object_inventory.py | 83 - .../events/game_object_added_to_inventory.py | 51 - .../events/game_object_initialized.py | 51 - .../game_object/events/game_object_loaded.py | 51 - .../events/game_object_pre_deleted.py | 51 - .../events/game_object_pre_despawned.py | 51 - ..._pre_removed_from_game_object_inventory.py | 83 - .../game_object_pre_removed_from_inventory.py | 51 - .../game_object/events/game_object_spawned.py | 51 - .../events/interaction/__init__.py | 7 - .../common_interaction_event_dispatcher.py | 497 - .../events/interaction/events/__init__.py | 7 - .../events/interaction_cancelled.py | 102 - .../interaction/events/interaction_outcome.py | 94 - .../events/interaction_post_queued.py | 80 - .../interaction/events/interaction_pre_run.py | 91 - .../interaction/events/interaction_queued.py | 84 - .../interaction/events/interaction_run.py | 79 - .../interaction/events/interaction_started.py | 71 - .../events/mixer_interaction_cancelled.py | 90 - .../events/super_interaction_cancelled.py | 90 - .../events/interval/__init__.py | 7 - .../interval/common_interval_event_service.py | 241 - .../sims4communitylib/events/save/__init__.py | 7 - .../save/common_save_event_dispatcher.py | 66 - .../events/save/events/__init__.py | 7 - .../events/save/events/save_loaded.py | 37 - .../events/save/events/save_saved.py | 61 - .../sims4communitylib/events/sim/__init__.py | 7 - .../events/sim/common_sim_event_dispatcher.py | 385 - .../events/sim/events/__init__.py | 7 - .../game_object_added_to_sim_inventory.py | 83 - ...e_object_pre_removed_from_sim_inventory.py | 84 - .../sim/events/sim_added_occult_type.py | 77 - .../events/sim_after_set_current_outfit.py | 66 - .../events/sim/events/sim_buff_added.py | 74 - .../events/sim/events/sim_buff_removed.py | 74 - .../events/sim/events/sim_changed_age.py | 66 - .../events/sim/events/sim_changed_gender.py | 64 - .../sim_changed_gender_options_body_frame.py | 51 - .../sim_changed_gender_options_breasts.py | 51 - ...anged_gender_options_can_be_impregnated.py | 51 - ...m_changed_gender_options_can_impregnate.py | 51 - ...im_changed_gender_options_can_reproduce.py | 51 - ...nged_gender_options_clothing_preference.py | 51 - ...sim_changed_gender_options_toilet_usage.py | 51 - .../sim/events/sim_changed_occult_type.py | 79 - .../sim/events/sim_changing_occult_type.py | 79 - .../events/sim/events/sim_died.py | 68 - .../events/sim/events/sim_initialized.py | 51 - .../events/sim/events/sim_loaded.py | 51 - .../events/sim/events/sim_pre_despawned.py | 51 - .../sim/events/sim_relationship_bit_added.py | 86 - .../events/sim_relationship_bit_removed.py | 86 - .../sim/events/sim_removed_occult_type.py | 77 - .../events/sim/events/sim_revived.py | 56 - .../sim/events/sim_set_current_outfit.py | 66 - .../events/sim/events/sim_skill_leveled_up.py | 78 - .../events/sim/events/sim_spawned.py | 51 - .../events/sim/events/sim_trait_added.py | 87 - .../events/sim/events/sim_trait_removed.py | 87 - .../events/zone_spin/__init__.py | 7 - .../common_zone_spin_event_dispatcher.py | 114 - .../events/zone_spin/events/__init__.py | 7 - .../zone_spin/events/zone_early_load.py | 77 - .../events/zone_spin/events/zone_late_load.py | 101 - .../events/zone_manager_start_event.py | 51 - .../events/zone_spin/events/zone_post_load.py | 75 - .../events/zone_spin/events/zone_save.py | 93 - .../events/zone_spin/events/zone_teardown.py | 92 - .../events/zone_update/__init__.py | 7 - .../common_zone_update_event_dispatcher.py | 81 - .../events/zone_update/events/__init__.py | 7 - .../zone_update/events/zone_update_event.py | 77 - .../sims4communitylib/examples/__init__.py | 7 - .../common_example_apply_bare_feet_buff.py | 140 - .../sims4communitylib/exceptions/__init__.py | 7 - .../exceptions/common_exceptions_handler.py | 102 - .../exceptions/common_stacktrace_utils.py | 73 - .../exceptions/generic_error_handling.py | 34 - .../sims4communitylib/logging/__init__.py | 7 - .../logging/_has_s4cl_class_log.py | 28 - .../logging/_has_s4cl_log.py | 28 - .../logging/_logging_commands.py | 156 - .../logging/has_class_log.py | 132 - .../s4ap/sims4communitylib/logging/has_log.py | 93 - .../logging/vanilla_logging.py | 211 - .../sims4communitylib/mod_support/__init__.py | 7 - .../mod_support/common_mod_info.py | 85 - .../mod_support/has_class_mod_identity.py | 33 - .../mod_support/has_mod_identity.py | 26 - .../mod_support/mod_identity.py | 108 - Scripts/s4ap/sims4communitylib/modinfo.py | 35 - .../notifications/__init__.py | 7 - .../common_basic_notification.py | 177 - .../sims4communitylib/persistence/__init__.py | 7 - .../common_game_object_data_storage.py | 230 - ...mmon_persisted_game_object_data_storage.py | 156 - .../common_persisted_sim_data_storage.py | 157 - .../persistence/common_sim_data_storage.py | 234 - .../persistence/data_management/__init__.py | 7 - .../data_management/common_data_manager.py | 232 - .../common_data_manager_registry.py | 189 - .../persistence/data_stores/__init__.py | 7 - .../data_stores/common_data_store.py | 223 - .../common_game_object_data_store.py | 30 - .../data_stores/common_sim_data_store.py | 30 - .../persistence_services/__init__.py | 7 - .../common_file_persistence_service.py | 120 - .../common_folder_persistence_service.py | 152 - ...on_hidden_household_persistence_service.py | 118 - ...n_individual_folder_persistence_service.py | 114 - .../common_persistence_service.py | 85 - .../s4ap/sims4communitylib/s4cl_commands.py | 87 - .../sims4communitylib/s4cl_configuration.py | 130 - .../sims4communitylib/services/__init__.py | 7 - .../services/commands/__init__.py | 7 - .../commands/common_console_command.py | 664 - .../commands/common_console_command_output.py | 60 - .../common_console_command_parameters.py | 151 - .../services/common_service.py | 52 - .../services/interactions/__init__.py | 7 - .../interaction_registration_service.py | 337 - .../services/resources/__init__.py | 7 - ..._instance_manager_modification_registry.py | 75 - .../common_posture_constraint_service.py | 80 - .../modification_handlers/__init__.py | 7 - ...nteractions_to_affordance_lists_handler.py | 54 - ...n_instance_manager_modification_handler.py | 50 - .../services/sim/__init__.py | 7 - .../services/sim/cas/__init__.py | 7 - .../services/sim/cas/common_sim_outfit_io.py | 396 - ...mmon_temporary_sim_clone_in_cas_service.py | 283 - .../sims4communitylib/systems/__init__.py | 7 - .../systems/caching/__init__.py | 7 - .../common_serializable_object_cache.py | 69 - ...ommon_serializable_object_cache_service.py | 104 - .../systems/item_query/__init__.py | 7 - .../common_loaded_item_query_registry.py | 545 - .../item_query/common_loaded_item_registry.py | 269 - .../systems/item_query/dtos/__init__.py | 7 - .../item_query/dtos/common_loaded_item.py | 198 - .../systems/item_query/enums/__init__.py | 7 - .../enums/common_query_method_type.py | 16 - .../item_query/item_loaders/__init__.py | 7 - .../item_loaders/common_base_item_loader.py | 106 - .../systems/item_query/item_tests/__init__.py | 7 - .../common_loaded_item_is_available_test.py | 32 - ...ommon_loaded_item_is_not_available_test.py | 32 - .../item_tests/common_loaded_item_test.py | 34 - .../item_query/persistence/__init__.py | 7 - .../persistence/common_loaded_item_cache.py | 18 - .../common_loaded_item_cache_service.py | 45 - .../systems/item_query/query/__init__.py | 7 - .../query/common_loaded_item_filter.py | 93 - .../common_loaded_item_filter_request.py | 131 - .../query/common_loaded_item_key.py | 42 - .../query/common_loaded_item_organizer.py | 35 - .../query/common_loaded_item_query_utils.py | 160 - .../systems/settings/__init__.py | 7 - .../systems/settings/common_setting_utils.py | 112 - .../settings/common_settings_data_manager.py | 41 - .../common_settings_data_manager_utils.py | 61 - .../settings/common_settings_data_store.py | 35 - .../sims4communitylib/testing/__init__.py | 7 - .../testing/common_assertion_utils.py | 282 - .../testing/common_test_service.py | 345 - .../s4ap/sims4communitylib/utils/__init__.py | 7 - .../sims4communitylib/utils/cas/__init__.py | 7 - .../utils/cas/common_cas_utils.py | 975 - .../utils/cas/common_outfit_utils.py | 1466 -- .../utils/common_collection_utils.py | 260 - .../utils/common_component_utils.py | 79 - .../utils/common_date_utils.py | 37 - .../utils/common_function_utils.py | 245 - .../utils/common_icon_utils.py | 189 - .../utils/common_injection_utils.py | 417 - .../utils/common_io_utils.py | 119 - .../utils/common_json_io_utils.py | 155 - .../utils/common_keyboard_utils.py | 161 - .../utils/common_log_registry.py | 818 - .../utils/common_log_utils.py | 206 - .../utils/common_math_utils.py | 97 - .../utils/common_resource_utils.py | 437 - .../utils/common_time_utils.py | 592 - .../utils/common_type_utils.py | 271 - .../utils/common_weather_utils.py | 308 - .../utils/effects/__init__.py | 7 - .../effects/common_visual_effect_commands.py | 192 - .../utils/environment/__init__.py | 7 - .../environment/common_business_utils.py | 80 - .../environment/common_civic_policy_utils.py | 455 - .../utils/localization/__init__.py | 7 - .../localization/common_localization_utils.py | 245 - .../common_localized_string_colors.py | 23 - .../common_localized_string_separators.py | 65 - .../utils/location/__init__.py | 7 - .../utils/location/common_location_utils.py | 979 -- .../utils/location/common_terrain_utils.py | 14 - .../utils/location/common_travel_utils.py | 80 - .../sims4communitylib/utils/math/__init__.py | 7 - .../utils/math/common_bitwise_utils.py | 110 - .../sims4communitylib/utils/misc/__init__.py | 7 - .../utils/misc/common_camera_utils.py | 141 - .../utils/misc/common_fire_utils.py | 134 - .../utils/misc/common_game_client_utils.py | 104 - .../utils/misc/common_mod_identity_utils.py | 37 - .../utils/misc/common_text_utils.py | 70 - .../utils/objects/__init__.py | 7 - .../objects/common_object_household_utils.py | 47 - .../common_object_interaction_utils.py | 326 - .../objects/common_object_inventory_utils.py | 214 - .../objects/common_object_location_utils.py | 389 - .../utils/objects/common_object_lock_utils.py | 198 - .../objects/common_object_ownership_utils.py | 141 - .../common_object_reservation_utils.py | 190 - .../utils/objects/common_object_slot_utils.py | 197 - .../objects/common_object_spawn_utils.py | 462 - .../objects/common_object_state_utils.py | 734 - .../utils/objects/common_object_tag_utils.py | 167 - .../utils/objects/common_object_type_utils.py | 482 - .../utils/objects/common_object_utils.py | 314 - .../objects/common_object_visibility_utils.py | 82 - .../utils/resources/__init__.py | 7 - .../utils/resources/common_club_utils.py | 78 - .../utils/resources/common_game_pack_utils.py | 68 - .../resources/common_interaction_utils.py | 434 - .../resources/common_loot_action_utils.py | 105 - .../utils/resources/common_recipe_utils.py | 128 - .../utils/resources/common_situation_utils.py | 329 - .../utils/resources/common_skill_utils.py | 121 - .../utils/resources/common_statistic_utils.py | 131 - .../utils/save_load/__init__.py | 7 - .../utils/save_load/common_save_utils.py | 56 - .../sims4communitylib/utils/sims/__init__.py | 7 - .../utils/sims/common_age_species_utils.py | 446 - .../utils/sims/common_age_utils.py | 1103 -- .../utils/sims/common_buff_utils.py | 592 - .../utils/sims/common_career_level_utils.py | 50 - .../utils/sims/common_career_track_utils.py | 199 - .../utils/sims/common_career_utils.py | 252 - .../utils/sims/common_gender_utils.py | 240 - .../utils/sims/common_household_utils.py | 747 - .../utils/sims/common_mood_utils.py | 277 - .../utils/sims/common_occult_utils.py | 1876 -- .../utils/sims/common_phone_utils.py | 77 - .../utils/sims/common_rabbit_hole_utils.py | 61 - .../utils/sims/common_relationship_utils.py | 1128 -- .../common_sim_appearance_modifier_utils.py | 219 - .../utils/sims/common_sim_autonomy_utils.py | 143 - .../utils/sims/common_sim_body_utils.py | 190 - .../utils/sims/common_sim_bucks_utils.py | 785 - .../utils/sims/common_sim_career_utils.py | 965 - .../utils/sims/common_sim_club_utils.py | 126 - .../utils/sims/common_sim_crafting_utils.py | 104 - .../utils/sims/common_sim_currency_utils.py | 140 - .../utils/sims/common_sim_death_utils.py | 472 - .../sims/common_sim_demographic_type_utils.py | 407 - .../sims/common_sim_gender_option_utils.py | 879 - .../common_sim_gender_preference_utils.py | 485 - .../utils/sims/common_sim_genealogy_utils.py | 572 - .../sims/common_sim_interaction_utils.py | 1419 -- .../utils/sims/common_sim_inventory_utils.py | 396 - .../utils/sims/common_sim_location_utils.py | 770 - .../sims/common_sim_loot_action_utils.py | 124 - .../utils/sims/common_sim_motive_utils.py | 646 - .../utils/sims/common_sim_name_utils.py | 284 - .../sims/common_sim_occult_type_utils.py | 265 - .../utils/sims/common_sim_plumbob_utils.py | 143 - .../utils/sims/common_sim_posture_utils.py | 266 - .../utils/sims/common_sim_pregnancy_utils.py | 622 - .../sims/common_sim_rabbit_hole_utils.py | 102 - ...mmon_sim_relationship_expectation_utils.py | 223 - .../utils/sims/common_sim_routing_utils.py | 123 - .../utils/sims/common_sim_situation_utils.py | 607 - .../utils/sims/common_sim_skill_utils.py | 409 - .../utils/sims/common_sim_spawn_utils.py | 3082 ---- .../utils/sims/common_sim_spell_utils.py | 302 - .../utils/sims/common_sim_state_utils.py | 104 - .../utils/sims/common_sim_statistic_utils.py | 621 - .../utils/sims/common_sim_type_utils.py | 2603 --- .../utils/sims/common_sim_unlock_utils.py | 28 - .../utils/sims/common_sim_utils.py | 362 - .../utils/sims/common_sim_voice_utils.py | 462 - .../utils/sims/common_sim_walkstyle_utils.py | 62 - .../utils/sims/common_species_utils.py | 336 - .../utils/sims/common_trait_utils.py | 1655 -- .../utils/sims/common_whim_utils.py | 36 - .../utils/terrain/__init__.py | 7 - .../common_terrain_interaction_utils.py | 58 - .../terrain/common_terrain_location_utils.py | 68 - .../utils/terrain/common_terrain_utils.py | 12 - .../sims4communitylib/utils/time/__init__.py | 7 - .../utils/time/common_alarm_utils.py | 181 - .../sims4communitylib/utils/whims/__init__.py | 7 - .../common_satisfaction_reward_store_item.py | 35 - .../common_satisfaction_reward_store_utils.py | 172 - Scripts/s4ap/utils/s4ap_generic_utils.py | 5 +- Scripts/s4ap/utils/s4ap_phone_utils.py | 4 +- Scripts/s4ap/utils/s4ap_reset_utils.py | 2 +- Scripts/s4ap/utils/s4ap_skill_utils.py | 5 +- custom_scripts_for_decompile/generated/key | Bin 256 -> 0 bytes 595 files changed, 43 insertions(+), 117400 deletions(-) delete mode 100644 Release/S4CLSampleMod/s4cl_sample_mod.package delete mode 100644 Scripts/s4ap/sims4communitylib/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/appearance_modifiers/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/appearance_modifiers/common_attach_cas_parts_appearance_modifier.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/buffs/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/buffs/common_buff.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/calculations/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/calculations/common_available_for_sim.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/commodities/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/commodities/common_commodity.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/common_resource_key.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/effects/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/effects/common_visual_effect.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/enums/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/enums/common_versioned_enum_value_collection.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/enums/common_versioned_sim_demographic_type_collection.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/filters/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/filters/common_match_all_non_sims_object_filter.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/filters/common_match_all_sims_object_filter.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/filters/common_match_object_filter.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/interactions/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/interactions/_common_interaction_custom_mixin.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/interactions/_common_interaction_hooks_mixin.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/interactions/common_immediate_super_interaction.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/interactions/common_interaction.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/interactions/common_interaction_override_name.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/interactions/common_mixer_interaction.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/interactions/common_object_interaction.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/interactions/common_social_mixer_interaction.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/interactions/common_social_super_interaction.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/interactions/common_super_interaction.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/interactions/common_terrain_interaction.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/math/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/math/common_comparison.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/math/common_float_range.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/math/common_integer_range.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/math/common_location.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/math/common_polygon.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/math/common_quaternion.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/math/common_routing_location.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/math/common_surface_identifier.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/math/common_transform.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/math/common_vector3.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/math/common_weighted_value.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/math/common_weighted_value_tally.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/mixins/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/mixins/common_affordance_lists_mixin.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/mixins/common_interactions_mixin.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/options.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/resolvers/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/resolvers/common_double_sim_resolver.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/runnables/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/runnables/common_runnable.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/runnables/common_runnable_with_sims.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/runnables/contexts/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_context.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_context_with_sims.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_object_context.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_sim_context.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/serialization/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/serialization/common_serializable.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/serialization/common_serializable_location.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/test_based_scores/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/test_based_scores/common_sim_to_sim_test_based_score.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/test_based_scores/common_single_sim_test_based_score.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/test_based_scores/common_test_based_score.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/testing/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/testing/common_enqueue_result.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/testing/common_execution_result.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/testing/common_test_result.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/time/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/time/common_alarm_handle.py delete mode 100644 Scripts/s4ap/sims4communitylib/classes/time/common_stop_watch.py delete mode 100644 Scripts/s4ap/sims4communitylib/conditionals/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/conditionals/common_conditional_action.py delete mode 100644 Scripts/s4ap/sims4communitylib/debug/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/debug/dialogs/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/debug/dialogs/common_change_object_state_dialog.py delete mode 100644 Scripts/s4ap/sims4communitylib/debug/interactions/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/debug/interactions/_register_interactions.py delete mode 100644 Scripts/s4ap/sims4communitylib/debug/interactions/change_object_states.py delete mode 100644 Scripts/s4ap/sims4communitylib/debug/interactions/induce_labor.py delete mode 100644 Scripts/s4ap/sims4communitylib/debug/interactions/log_all_game_tags.py delete mode 100644 Scripts/s4ap/sims4communitylib/debug/interactions/log_all_interactions.py delete mode 100644 Scripts/s4ap/sims4communitylib/debug/interactions/object_break.py delete mode 100644 Scripts/s4ap/sims4communitylib/debug/interactions/object_fix.py delete mode 100644 Scripts/s4ap/sims4communitylib/debug/interactions/object_make_clean.py delete mode 100644 Scripts/s4ap/sims4communitylib/debug/interactions/object_make_dirty.py delete mode 100644 Scripts/s4ap/sims4communitylib/debug/interactions/show_active_buffs.py delete mode 100644 Scripts/s4ap/sims4communitylib/debug/interactions/show_running_and_queued_interactions.py delete mode 100644 Scripts/s4ap/sims4communitylib/debug/interactions/show_running_situations.py delete mode 100644 Scripts/s4ap/sims4communitylib/debug/interactions/show_traits.py delete mode 100644 Scripts/s4ap/sims4communitylib/debug/traits/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/debug/traits/_auto_apply_traits.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/_common_ui_dialog_multi_text_input_ok_cancel.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/_common_ui_dialog_text_input_ok_cancel.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/choose_item_dialog.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/choose_object_dialog.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/choose_objects_dialog.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/common_choice_outcome.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/common_choose_dialog.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/common_choose_outfit_dialog.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/common_choose_response_dialog.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/common_choose_sim_dialog.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/common_choose_sims_dialog.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/common_dialog.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/common_dialog_navigation_button_tag.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/common_input_float_dialog.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/common_input_integer_dialog.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/common_input_multi_text_dialog.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/common_input_text_dialog.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/common_input_text_field.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/common_multi_pane_choose_dialog.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/common_ok_dialog.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/common_purchase_objects_dialog.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/common_targeted_question_dialog.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/common_ui_dialog_response.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/common_ui_response_dialog.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/custom_dialogs/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/custom_dialogs/picker_dialogs/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/custom_dialogs/picker_dialogs/common_ui_multi_picker.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/custom_dialogs/picker_dialogs/common_ui_object_category_picker.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/ok_cancel_dialog.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_button_option_dialog.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_object_option_dialog.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_objects_option_dialog.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_option_dialog.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_options_dialog.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_response_option_dialog.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_sim_option_dialog.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_sims_option_dialog.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_multi_pane_choose_option_dialog.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_option_dialog.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/common_dialog_option.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/common_dialog_option_context.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_action_option.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_branch_option.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_integer_option.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_multi_text_option.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_option.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_text_option.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_object_option.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_option_category.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_select_option.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_toggle_option.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/response/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/response/common_dialog_button_option.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/response/common_dialog_response_option.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/response/common_dialog_response_option_context.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/sims/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/sims/common_dialog_sim_option.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/sims/common_dialog_sim_option_context.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/premade_dialogs/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/premade_dialogs/common_choose_sim_demographic_types_dialog.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/premade_dialogs/common_premade_choose_sim_option_dialog.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/premade_dialogs/common_premade_choose_sims_option_dialog.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/utils/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/dialogs/utils/common_dialog_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/dtos/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/dtos/common_cas_part.py delete mode 100644 Scripts/s4ap/sims4communitylib/dtos/common_object_containment_slot.py delete mode 100644 Scripts/s4ap/sims4communitylib/dtos/common_outfit.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/affordance_list_ids.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/animation_state_machines_enum.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/buffs_enum.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/clubs_enum.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_age.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_appearance_modifier_priority.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_appearance_modifier_type.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_body_frame.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_body_slot.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_bucks_types.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_business_advertising_type.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_business_customer_star_rating_type.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_business_employee_type.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_business_quality_type.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_career_ids.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_character_restrictions.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_civic_policy_status_type.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_civic_policy_type.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_cloud_type.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_combined_species.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_currency_modify_reasons.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_death_types.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_enum.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_fund_types.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_funds_sources.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_game_tag_category.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_gender.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_gender_preference_type.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_ground_cover_type.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_key.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_object_delivery_method.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_object_filter_type.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_object_preference_tag.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_object_quality.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_object_slot_name_ids.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_object_state_ids.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_object_state_value_ids.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_occult_type.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_posture_id.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_precipitation_type.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_pregnancy_origin.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_puddle_liquid.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_puddle_size.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_region_id.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_runnable_state.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_runnable_state_type.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_side.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_sim_demographic_types.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_sim_name_type.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_skill_effectiveness.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_slot_type.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_species.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_statistic_category.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_street_civic_policy_ids.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_temperature.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_venue_civic_policy_ids.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_voice_actor_type.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_weather_effect_type.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_weather_event_ids.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/common_weather_type.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/enumtypes/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/enumtypes/common_int.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/enumtypes/common_int_flags.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/enumtypes/common_versioned_int.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/enumtypes/common_versioned_int_flags.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/enumtypes/common_versioned_values_mixin.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/enumtypes/float_enum.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/enumtypes/int_enum.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/enumtypes/object_enum.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/enumtypes/string_enum.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/furniture_objects_enum.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/icons_enum.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/interactions_enum.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/long_term_sentiments_enum.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/lot_traits_enum.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/moods_enum.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/motives_enum.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/relationship_bit_collection_uids_enum.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/relationship_bit_collections_enum.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/relationship_bits_enum.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/relationship_tracks_enum.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/relationship_types_enum.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/short_term_relationship_tracks_enum.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/short_term_sentiments_enum.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/sim_type.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/situation_jobs_enum.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/situations_enum.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/skills_enum.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/statistics_enum.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/strings_enum.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/tags_enum.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/traits_enum.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/types/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/types/component_types.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/venues_enum.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/whims_enum.py delete mode 100644 Scripts/s4ap/sims4communitylib/enums/world_types_enum.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/build_buy/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/build_buy/common_build_buy_event_dispatcher.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/build_buy/events/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/build_buy/events/build_buy_enter.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/build_buy/events/build_buy_exit.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/event_handling/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/event_handling/common_event.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/event_handling/common_event_handler.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/event_handling/common_event_registry.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/game_object/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/game_object/common_game_object_event_dispatcher.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/game_object/events/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_added_to_game_object_inventory.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_added_to_inventory.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_initialized.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_loaded.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_deleted.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_despawned.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_removed_from_game_object_inventory.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_removed_from_inventory.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_spawned.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/interaction/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/interaction/common_interaction_event_dispatcher.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/interaction/events/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_cancelled.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_outcome.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_post_queued.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_pre_run.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_queued.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_run.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_started.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/interaction/events/mixer_interaction_cancelled.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/interaction/events/super_interaction_cancelled.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/interval/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/interval/common_interval_event_service.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/save/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/save/common_save_event_dispatcher.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/save/events/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/save/events/save_loaded.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/save/events/save_saved.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/sim/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/sim/common_sim_event_dispatcher.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/game_object_added_to_sim_inventory.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/game_object_pre_removed_from_sim_inventory.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_added_occult_type.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_after_set_current_outfit.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_buff_added.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_buff_removed.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_age.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_body_frame.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_breasts.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_can_be_impregnated.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_can_impregnate.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_can_reproduce.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_clothing_preference.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_toilet_usage.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_occult_type.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_changing_occult_type.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_died.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_initialized.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_loaded.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_pre_despawned.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_relationship_bit_added.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_relationship_bit_removed.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_removed_occult_type.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_revived.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_set_current_outfit.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_skill_leveled_up.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_spawned.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_trait_added.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/sim/events/sim_trait_removed.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/zone_spin/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/zone_spin/common_zone_spin_event_dispatcher.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/zone_spin/events/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_early_load.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_late_load.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_manager_start_event.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_post_load.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_save.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_teardown.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/zone_update/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/zone_update/common_zone_update_event_dispatcher.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/zone_update/events/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/events/zone_update/events/zone_update_event.py delete mode 100644 Scripts/s4ap/sims4communitylib/examples/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/examples/common_example_apply_bare_feet_buff.py delete mode 100644 Scripts/s4ap/sims4communitylib/exceptions/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/exceptions/common_exceptions_handler.py delete mode 100644 Scripts/s4ap/sims4communitylib/exceptions/common_stacktrace_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/exceptions/generic_error_handling.py delete mode 100644 Scripts/s4ap/sims4communitylib/logging/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/logging/_has_s4cl_class_log.py delete mode 100644 Scripts/s4ap/sims4communitylib/logging/_has_s4cl_log.py delete mode 100644 Scripts/s4ap/sims4communitylib/logging/_logging_commands.py delete mode 100644 Scripts/s4ap/sims4communitylib/logging/has_class_log.py delete mode 100644 Scripts/s4ap/sims4communitylib/logging/has_log.py delete mode 100644 Scripts/s4ap/sims4communitylib/logging/vanilla_logging.py delete mode 100644 Scripts/s4ap/sims4communitylib/mod_support/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/mod_support/common_mod_info.py delete mode 100644 Scripts/s4ap/sims4communitylib/mod_support/has_class_mod_identity.py delete mode 100644 Scripts/s4ap/sims4communitylib/mod_support/has_mod_identity.py delete mode 100644 Scripts/s4ap/sims4communitylib/mod_support/mod_identity.py delete mode 100644 Scripts/s4ap/sims4communitylib/modinfo.py delete mode 100644 Scripts/s4ap/sims4communitylib/notifications/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/notifications/common_basic_notification.py delete mode 100644 Scripts/s4ap/sims4communitylib/persistence/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/persistence/common_game_object_data_storage.py delete mode 100644 Scripts/s4ap/sims4communitylib/persistence/common_persisted_game_object_data_storage.py delete mode 100644 Scripts/s4ap/sims4communitylib/persistence/common_persisted_sim_data_storage.py delete mode 100644 Scripts/s4ap/sims4communitylib/persistence/common_sim_data_storage.py delete mode 100644 Scripts/s4ap/sims4communitylib/persistence/data_management/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/persistence/data_management/common_data_manager.py delete mode 100644 Scripts/s4ap/sims4communitylib/persistence/data_management/common_data_manager_registry.py delete mode 100644 Scripts/s4ap/sims4communitylib/persistence/data_stores/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/persistence/data_stores/common_data_store.py delete mode 100644 Scripts/s4ap/sims4communitylib/persistence/data_stores/common_game_object_data_store.py delete mode 100644 Scripts/s4ap/sims4communitylib/persistence/data_stores/common_sim_data_store.py delete mode 100644 Scripts/s4ap/sims4communitylib/persistence/persistence_services/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_file_persistence_service.py delete mode 100644 Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_folder_persistence_service.py delete mode 100644 Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_hidden_household_persistence_service.py delete mode 100644 Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_individual_folder_persistence_service.py delete mode 100644 Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_persistence_service.py delete mode 100644 Scripts/s4ap/sims4communitylib/s4cl_commands.py delete mode 100644 Scripts/s4ap/sims4communitylib/s4cl_configuration.py delete mode 100644 Scripts/s4ap/sims4communitylib/services/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/services/commands/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/services/commands/common_console_command.py delete mode 100644 Scripts/s4ap/sims4communitylib/services/commands/common_console_command_output.py delete mode 100644 Scripts/s4ap/sims4communitylib/services/commands/common_console_command_parameters.py delete mode 100644 Scripts/s4ap/sims4communitylib/services/common_service.py delete mode 100644 Scripts/s4ap/sims4communitylib/services/interactions/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/services/interactions/interaction_registration_service.py delete mode 100644 Scripts/s4ap/sims4communitylib/services/resources/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/services/resources/common_instance_manager_modification_registry.py delete mode 100644 Scripts/s4ap/sims4communitylib/services/resources/common_posture_constraint_service.py delete mode 100644 Scripts/s4ap/sims4communitylib/services/resources/modification_handlers/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/services/resources/modification_handlers/common_add_interactions_to_affordance_lists_handler.py delete mode 100644 Scripts/s4ap/sims4communitylib/services/resources/modification_handlers/common_instance_manager_modification_handler.py delete mode 100644 Scripts/s4ap/sims4communitylib/services/sim/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/services/sim/cas/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/services/sim/cas/common_sim_outfit_io.py delete mode 100644 Scripts/s4ap/sims4communitylib/services/sim/cas/common_temporary_sim_clone_in_cas_service.py delete mode 100644 Scripts/s4ap/sims4communitylib/systems/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/systems/caching/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/systems/caching/common_serializable_object_cache.py delete mode 100644 Scripts/s4ap/sims4communitylib/systems/caching/common_serializable_object_cache_service.py delete mode 100644 Scripts/s4ap/sims4communitylib/systems/item_query/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/systems/item_query/common_loaded_item_query_registry.py delete mode 100644 Scripts/s4ap/sims4communitylib/systems/item_query/common_loaded_item_registry.py delete mode 100644 Scripts/s4ap/sims4communitylib/systems/item_query/dtos/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/systems/item_query/dtos/common_loaded_item.py delete mode 100644 Scripts/s4ap/sims4communitylib/systems/item_query/enums/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/systems/item_query/enums/common_query_method_type.py delete mode 100644 Scripts/s4ap/sims4communitylib/systems/item_query/item_loaders/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/systems/item_query/item_loaders/common_base_item_loader.py delete mode 100644 Scripts/s4ap/sims4communitylib/systems/item_query/item_tests/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/systems/item_query/item_tests/common_loaded_item_is_available_test.py delete mode 100644 Scripts/s4ap/sims4communitylib/systems/item_query/item_tests/common_loaded_item_is_not_available_test.py delete mode 100644 Scripts/s4ap/sims4communitylib/systems/item_query/item_tests/common_loaded_item_test.py delete mode 100644 Scripts/s4ap/sims4communitylib/systems/item_query/persistence/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/systems/item_query/persistence/common_loaded_item_cache.py delete mode 100644 Scripts/s4ap/sims4communitylib/systems/item_query/persistence/common_loaded_item_cache_service.py delete mode 100644 Scripts/s4ap/sims4communitylib/systems/item_query/query/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_filter.py delete mode 100644 Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_filter_request.py delete mode 100644 Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_key.py delete mode 100644 Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_organizer.py delete mode 100644 Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_query_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/systems/settings/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/systems/settings/common_setting_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/systems/settings/common_settings_data_manager.py delete mode 100644 Scripts/s4ap/sims4communitylib/systems/settings/common_settings_data_manager_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/systems/settings/common_settings_data_store.py delete mode 100644 Scripts/s4ap/sims4communitylib/testing/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/testing/common_assertion_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/testing/common_test_service.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/cas/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/cas/common_cas_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/cas/common_outfit_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/common_collection_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/common_component_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/common_date_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/common_function_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/common_icon_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/common_injection_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/common_io_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/common_json_io_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/common_keyboard_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/common_log_registry.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/common_log_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/common_math_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/common_resource_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/common_time_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/common_type_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/common_weather_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/effects/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/effects/common_visual_effect_commands.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/environment/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/environment/common_business_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/environment/common_civic_policy_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/localization/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/localization/common_localization_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/localization/common_localized_string_colors.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/localization/common_localized_string_separators.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/location/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/location/common_location_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/location/common_terrain_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/location/common_travel_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/math/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/math/common_bitwise_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/misc/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/misc/common_camera_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/misc/common_fire_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/misc/common_game_client_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/misc/common_mod_identity_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/misc/common_text_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/objects/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/objects/common_object_household_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/objects/common_object_interaction_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/objects/common_object_inventory_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/objects/common_object_location_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/objects/common_object_lock_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/objects/common_object_ownership_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/objects/common_object_reservation_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/objects/common_object_slot_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/objects/common_object_spawn_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/objects/common_object_state_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/objects/common_object_tag_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/objects/common_object_type_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/objects/common_object_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/objects/common_object_visibility_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/resources/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/resources/common_club_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/resources/common_game_pack_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/resources/common_interaction_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/resources/common_loot_action_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/resources/common_recipe_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/resources/common_situation_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/resources/common_skill_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/resources/common_statistic_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/save_load/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/save_load/common_save_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_age_species_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_age_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_buff_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_career_level_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_career_track_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_career_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_gender_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_household_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_mood_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_occult_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_phone_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_rabbit_hole_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_relationship_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_appearance_modifier_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_autonomy_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_body_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_bucks_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_career_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_club_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_crafting_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_currency_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_death_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_demographic_type_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_gender_option_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_gender_preference_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_genealogy_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_interaction_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_inventory_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_location_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_loot_action_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_motive_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_name_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_occult_type_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_plumbob_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_posture_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_pregnancy_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_rabbit_hole_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_relationship_expectation_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_routing_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_situation_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_skill_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_spawn_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_spell_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_state_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_statistic_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_type_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_unlock_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_voice_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_sim_walkstyle_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_species_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_trait_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/sims/common_whim_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/terrain/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/terrain/common_terrain_interaction_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/terrain/common_terrain_location_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/terrain/common_terrain_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/time/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/time/common_alarm_utils.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/whims/__init__.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/whims/common_satisfaction_reward_store_item.py delete mode 100644 Scripts/s4ap/sims4communitylib/utils/whims/common_satisfaction_reward_store_utils.py delete mode 100644 custom_scripts_for_decompile/generated/key diff --git a/Release/S4CLSampleMod/s4cl_sample_mod.package b/Release/S4CLSampleMod/s4cl_sample_mod.package deleted file mode 100644 index 307462cea06c3676ee61341e234e69c024d73cb3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3228 zcmZ>93UFg$U|?VbVq8EFDxm^Why<8{>lE%ikl)qn zI7`vOaJzzf=s|OP*MrI%BMxesn))A9w>MNZb=Ch{dCII!iS4{e>#09Mt&gsRv`*?d zlhk_W%A-d|zJ$oOo)J>8He4^EF=v%P&Z9Sr8&V?JE^K)6=T6g^IafqlA6X>=_IU4I6;8Qxqdiz5yuD1d{)OTb>yt zKLOZ?#i5@CB(DK%zv7T*1<4=4Ezbs$j{r7!ap-3U$$!8t&jFI}V8N-M8zis5ic_8k zB)K6scKR}ZQ E0E?zaVE_OC diff --git a/Scripts/s4ap/events/Utils/allow_read_items.py b/Scripts/s4ap/events/Utils/allow_read_items.py index c667011..cb5461d 100644 --- a/Scripts/s4ap/events/Utils/allow_read_items.py +++ b/Scripts/s4ap/events/Utils/allow_read_items.py @@ -1,4 +1,4 @@ -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent +from sims4communitylib.events.event_handling.common_event import CommonEvent class AllowReceiveItems(CommonEvent): diff --git a/Scripts/s4ap/events/Utils/send_location_event.py b/Scripts/s4ap/events/Utils/send_location_event.py index fff2115..9ef0861 100644 --- a/Scripts/s4ap/events/Utils/send_location_event.py +++ b/Scripts/s4ap/events/Utils/send_location_event.py @@ -1,4 +1,4 @@ -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent +from sims4communitylib.events.event_handling.common_event import CommonEvent class SendLocationEvent(CommonEvent): diff --git a/Scripts/s4ap/events/aspiration_event_dispatcher.py b/Scripts/s4ap/events/aspiration_event_dispatcher.py index 0a6591e..8cb0f07 100644 --- a/Scripts/s4ap/events/aspiration_event_dispatcher.py +++ b/Scripts/s4ap/events/aspiration_event_dispatcher.py @@ -4,9 +4,9 @@ from s4ap.events.checks.send_check_event import SendLocationEvent from s4ap.modinfo import ModInfo from s4ap.utils.s4ap_sim_utils import S4APSimUtils -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent -from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from s4ap.sims4communitylib.services.common_service import CommonService +from sims4communitylib.events.event_handling.common_event import CommonEvent +from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry +from sims4communitylib.services.common_service import CommonService from lot51_core.utils.injection import inject_to diff --git a/Scripts/s4ap/events/career_event_dispatcher.py b/Scripts/s4ap/events/career_event_dispatcher.py index c9ccca9..640dbee 100644 --- a/Scripts/s4ap/events/career_event_dispatcher.py +++ b/Scripts/s4ap/events/career_event_dispatcher.py @@ -5,9 +5,9 @@ from s4ap.modinfo import ModInfo from s4ap.utils.s4ap_household_utils import S4APHouseholdUtils from s4ap.utils.s4ap_sim_utils import S4APSimUtils -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent -from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from s4ap.sims4communitylib.services.common_service import CommonService +from sims4communitylib.events.event_handling.common_event import CommonEvent +from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry +from sims4communitylib.services.common_service import CommonService from lot51_core.utils.injection import inject_to log = S4APLogger.get_log() diff --git a/Scripts/s4ap/events/checks/send_check_event.py b/Scripts/s4ap/events/checks/send_check_event.py index 568d20d..3ec4fb6 100644 --- a/Scripts/s4ap/events/checks/send_check_event.py +++ b/Scripts/s4ap/events/checks/send_check_event.py @@ -3,7 +3,7 @@ from s4ap.logging.s4ap_logger import S4APLogger from s4ap.modinfo import ModInfo from s4ap.utils.s4ap_generic_utils import S4APUtils -from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry +from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry logger = S4APLogger.get_log() logger.enable() diff --git a/Scripts/s4ap/events/items/receive_item_event.py b/Scripts/s4ap/events/items/receive_item_event.py index 7a62d7f..42e376c 100644 --- a/Scripts/s4ap/events/items/receive_item_event.py +++ b/Scripts/s4ap/events/items/receive_item_event.py @@ -14,8 +14,8 @@ from s4ap.utils.s4ap_skill_utils import lock_skills from s4ap.utils.s4ap_trait_utils import S4APTraitUtils from sims4.resources import Types -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent -from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry +from sims4communitylib.events.event_handling.common_event import CommonEvent +from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry from collections import Counter log = S4APLogger.get_log() log.enable() diff --git a/Scripts/s4ap/events/skill_event_dispatcher.py b/Scripts/s4ap/events/skill_event_dispatcher.py index d2f393f..3a534cf 100644 --- a/Scripts/s4ap/events/skill_event_dispatcher.py +++ b/Scripts/s4ap/events/skill_event_dispatcher.py @@ -7,9 +7,8 @@ from s4ap.utils.s4ap_sim_utils import S4APSimUtils from s4ap.utils.s4ap_skill_utils_class import S4APSkillUtils from sims.sim_info import SimInfo -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent -from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from s4ap.sims4communitylib.services.common_service import CommonService +from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry +from sims4communitylib.services.common_service import CommonService from lot51_core.utils.injection import inject_to from statistics.skill import Skill diff --git a/Scripts/s4ap/jsonio/auto_parse_json.py b/Scripts/s4ap/jsonio/auto_parse_json.py index 5e6a39f..e610c45 100644 --- a/Scripts/s4ap/jsonio/auto_parse_json.py +++ b/Scripts/s4ap/jsonio/auto_parse_json.py @@ -7,10 +7,10 @@ from s4ap.logging.s4ap_logger import S4APLogger from s4ap.modinfo import ModInfo from s4ap.persistance.ap_session_data_store import S4APSessionStoreUtils -from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from s4ap.sims4communitylib.events.interval.common_interval_event_service import CommonIntervalEventRegistry -from s4ap.sims4communitylib.events.save.events.save_loaded import S4CLSaveLoadedEvent -from s4ap.sims4communitylib.utils.common_log_utils import CommonLogUtils +from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry +from sims4communitylib.events.interval.common_interval_event_service import CommonIntervalEventRegistry +from sims4communitylib.events.save.events.save_loaded import S4CLSaveLoadedEvent +from sims4communitylib.utils.common_log_utils import CommonLogUtils logger = S4APLogger.get_log() logger.enable() diff --git a/Scripts/s4ap/jsonio/s4ap_json.py b/Scripts/s4ap/jsonio/s4ap_json.py index b5fc5ef..2043197 100644 --- a/Scripts/s4ap/jsonio/s4ap_json.py +++ b/Scripts/s4ap/jsonio/s4ap_json.py @@ -1,8 +1,8 @@ import os from s4ap.logging.s4ap_logger import S4APLogger -from s4ap.sims4communitylib.utils.common_json_io_utils import CommonJSONIOUtils -from s4ap.sims4communitylib.utils.common_log_utils import CommonLogUtils +from sims4communitylib.utils.common_json_io_utils import CommonJSONIOUtils +from sims4communitylib.utils.common_log_utils import CommonLogUtils log = S4APLogger.get_log() log.enable() diff --git a/Scripts/s4ap/logging/s4ap_logger.py b/Scripts/s4ap/logging/s4ap_logger.py index 308836d..79853d5 100644 --- a/Scripts/s4ap/logging/s4ap_logger.py +++ b/Scripts/s4ap/logging/s4ap_logger.py @@ -2,13 +2,14 @@ from s4ap.modinfo import ModInfo from s4ap.utils.s4ap_generic_utils import S4APUtils from s4ap.utils.s4ap_localization_utils import S4APLocalizationUtils +from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry +from sims4communitylib.events.zone_spin.events.zone_late_load import S4CLZoneLateLoadEvent +from sims4communitylib.logging.has_class_log import HasClassLog +from sims4communitylib.mod_support.mod_identity import CommonModIdentity from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from s4ap.sims4communitylib.events.zone_spin.events.zone_late_load import S4CLZoneLateLoadEvent -from s4ap.sims4communitylib.logging.has_class_log import HasClassLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity from lot51_core.utils import DialogHelper + class S4APLogger(HasClassLog): @classmethod def get_mod_identity(cls) -> CommonModIdentity: diff --git a/Scripts/s4ap/modinfo.py b/Scripts/s4ap/modinfo.py index d54d234..09ebe7c 100644 --- a/Scripts/s4ap/modinfo.py +++ b/Scripts/s4ap/modinfo.py @@ -1,4 +1,4 @@ -from s4ap.sims4communitylib.mod_support.common_mod_info import CommonModInfo +from sims4communitylib.mod_support.common_mod_info import CommonModInfo class ModInfo(CommonModInfo): @@ -14,7 +14,7 @@ def _name(self) -> str: @property def _version(self) -> str: # Mod version - return '0.3.0-rc2-experimental' + return '0.3.0-rc2' @property def _author(self) -> str: diff --git a/Scripts/s4ap/persistance/ap_data_manager.py b/Scripts/s4ap/persistance/ap_data_manager.py index b9efe43..be7a3bd 100644 --- a/Scripts/s4ap/persistance/ap_data_manager.py +++ b/Scripts/s4ap/persistance/ap_data_manager.py @@ -1,10 +1,10 @@ from typing import Tuple from s4ap.modinfo import ModInfo -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.persistence.data_management.common_data_manager import CommonDataManager -from s4ap.sims4communitylib.persistence.data_management.common_data_manager_registry import CommonDataManagerRegistry -from s4ap.sims4communitylib.persistence.persistence_services.common_persistence_service import CommonPersistenceService +from sims4communitylib.mod_support.mod_identity import CommonModIdentity +from sims4communitylib.persistence.data_management.common_data_manager import CommonDataManager +from sims4communitylib.persistence.data_management.common_data_manager_registry import CommonDataManagerRegistry +from sims4communitylib.persistence.persistence_services.common_persistence_service import CommonPersistenceService @CommonDataManagerRegistry.common_data_manager() diff --git a/Scripts/s4ap/persistance/ap_data_store.py b/Scripts/s4ap/persistance/ap_data_store.py index 9cec1b3..9a5f6c5 100644 --- a/Scripts/s4ap/persistance/ap_data_store.py +++ b/Scripts/s4ap/persistance/ap_data_store.py @@ -1,6 +1,6 @@ from typing import Any, Dict -from s4ap.sims4communitylib.persistence.data_stores.common_data_store import CommonDataStore +from sims4communitylib.persistence.data_stores.common_data_store import CommonDataStore class S4APSettings: diff --git a/Scripts/s4ap/persistance/ap_data_utils.py b/Scripts/s4ap/persistance/ap_data_utils.py index def0fd2..4c59ceb 100644 --- a/Scripts/s4ap/persistance/ap_data_utils.py +++ b/Scripts/s4ap/persistance/ap_data_utils.py @@ -3,9 +3,9 @@ from s4ap.modinfo import ModInfo from s4ap.persistance.ap_data_manager import S4APDataManager from s4ap.persistance.ap_data_store import S4APGenericDataStore -from s4ap.sims4communitylib.persistence.data_management.common_data_manager_registry import CommonDataManagerRegistry -from s4ap.sims4communitylib.persistence.data_stores.common_data_store import CommonDataStore -from s4ap.sims4communitylib.services.common_service import CommonService +from sims4communitylib.persistence.data_management.common_data_manager_registry import CommonDataManagerRegistry +from sims4communitylib.persistence.data_stores.common_data_store import CommonDataStore +from sims4communitylib.services.common_service import CommonService class S4APDataManagerUtils(CommonService): diff --git a/Scripts/s4ap/persistance/ap_session_data_store.py b/Scripts/s4ap/persistance/ap_session_data_store.py index c5c3006..83cd917 100644 --- a/Scripts/s4ap/persistance/ap_session_data_store.py +++ b/Scripts/s4ap/persistance/ap_session_data_store.py @@ -7,8 +7,8 @@ from s4ap.utils.s4ap_generic_utils import S4APUtils from s4ap.utils.s4ap_localization_utils import S4APLocalizationUtils from s4ap.utils.s4ap_reset_utils import ResetSimData -from s4ap.sims4communitylib.dialogs.ok_cancel_dialog import CommonOkCancelDialog -from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry +from sims4communitylib.dialogs.ok_cancel_dialog import CommonOkCancelDialog +from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry from ui.ui_dialog import UiDialogOkCancel logger = S4APLogger.get_log() diff --git a/Scripts/s4ap/sims4communitylib/__init__.py b/Scripts/s4ap/sims4communitylib/__init__.py deleted file mode 100644 index 3251898..0000000 --- a/Scripts/s4ap/sims4communitylib/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" \ No newline at end of file diff --git a/Scripts/s4ap/sims4communitylib/classes/__init__.py b/Scripts/s4ap/sims4communitylib/classes/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/classes/appearance_modifiers/__init__.py b/Scripts/s4ap/sims4communitylib/classes/appearance_modifiers/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/appearance_modifiers/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/classes/appearance_modifiers/common_attach_cas_parts_appearance_modifier.py b/Scripts/s4ap/sims4communitylib/classes/appearance_modifiers/common_attach_cas_parts_appearance_modifier.py deleted file mode 100644 index cf64de3..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/appearance_modifiers/common_attach_cas_parts_appearance_modifier.py +++ /dev/null @@ -1,359 +0,0 @@ -""" -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 -""" -import os -from typing import Any, Tuple, Union, List - -from sims.outfits.outfit_enums import OutfitCategory, BodyTypeFlag, BodyType -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.dtos.common_cas_part import CommonCASPart -from s4ap.sims4communitylib.enums.buffs_enum import CommonBuffId -from s4ap.sims4communitylib.enums.common_appearance_modifier_type import CommonAppearanceModifierType -from s4ap.sims4communitylib.enums.common_body_slot import CommonBodySlot -from s4ap.sims4communitylib.logging.has_log import HasLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ - CommonConsoleCommandArgument -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput - -ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' - -# If on Read The Docs, create fake versions of extended objects to fix the error of inheriting from multiple MockObjects. -if ON_RTD: - # noinspection PyMissingOrEmptyDocstring - class AppearanceModifier: - # noinspection PyMissingOrEmptyDocstring - class BaseAppearanceModification: - # noinspection PyPep8Naming - @classmethod - def TunableFactory(cls) -> Any: - pass - -if not ON_RTD: - from buffs.appearance_modifier.appearance_modifier import AppearanceModifier - - -class CommonAttachCASPartsAppearanceModifier(AppearanceModifier.BaseAppearanceModification, HasLog): - """CommonAttachCASPartsAppearanceModifier() - - Attach CAS Parts to a Sim by utilizing Appearance Modifiers. - - .. note:: Appearance Modifiers will apply to any outfit a Sim wears, when switching outfits ALL of their outfits will APPEAR to have the attached CAS Part. However, appearance modifiers are only temporary. - - .. note:: To see an example of this appearance modifier in action, run the command `s4clib_testing.toggle_example_appearance_modifier_buff` in the console. (The Sim will have bare feet) - - :Example usage: - - .. highlight:: python - .. code-block:: python - - class CommonExampleApplyBareFeetAppearanceModifier(AppearanceModifier): - - class CommonAttachBareFeetModifier(CommonAttachCASPartsAppearanceModifier): - # noinspection PyMissingOrEmptyDocstring - @property - def mod_identity(self) -> CommonModIdentity: - return ModInfo.get_identity() - - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - return 'common_example_apply_bare_feet' - - def _get_cas_parts( - self, - source_sim_info: SimInfo, - modified_sim_info: SimInfo, - original_unmodified_sim_info: SimInfo, - random_seed: int - ) -> Tuple[CommonCASPart]: - # Human - # yfShoes_Nude - adult_human_female_bare_feet_id = 6543 - # ymShoes_Nude - adult_human_male_bare_feet_id = 6563 - # cuShoes_Nude - child_human_bare_feet_id = 22018 - # puShoes_Nude - toddler_human_bare_feet_id = 132818 - - # Dog - # adShoes_Nude - adult_large_dog_bare_feet_id = 125251 - # alShoes_Nude - adult_small_dog_bare_feet_id = 148839 - # cdShoes_Nude - child_dog_bare_feet_id = 158046 - - # Cat - # acShoes_Nude - adult_cat_bare_feet_id = 150367 - # ccShoes_Nude - child_cat_bare_feet_id = 164111 - - # Fox - adult_fox_bare_feet_id = 277492 - - bare_feet_cas_part_id = None - if CommonAgeUtils.is_teen_adult_or_elder(original_unmodified_sim_info): - if CommonSpeciesUtils.is_human(original_unmodified_sim_info): - if CommonGenderUtils.is_female(original_unmodified_sim_info): - bare_feet_cas_part_id = adult_human_female_bare_feet_id - elif CommonGenderUtils.is_male(original_unmodified_sim_info): - bare_feet_cas_part_id = adult_human_male_bare_feet_id - elif CommonSpeciesUtils.is_large_dog(original_unmodified_sim_info): - bare_feet_cas_part_id = adult_large_dog_bare_feet_id - elif CommonSpeciesUtils.is_small_dog(original_unmodified_sim_info): - bare_feet_cas_part_id = adult_small_dog_bare_feet_id - elif CommonSpeciesUtils.is_cat(original_unmodified_sim_info): - bare_feet_cas_part_id = adult_cat_bare_feet_id - elif CommonSpeciesUtils.is_fox(original_unmodified_sim_info): - bare_feet_cas_part_id = adult_fox_bare_feet_id - elif CommonAgeUtils.is_child(original_unmodified_sim_info): - if CommonSpeciesUtils.is_human(original_unmodified_sim_info): - bare_feet_cas_part_id = child_human_bare_feet_id - elif CommonSpeciesUtils.is_large_dog(original_unmodified_sim_info) or CommonSpeciesUtils.is_small_dog(original_unmodified_sim_info): - bare_feet_cas_part_id = child_dog_bare_feet_id - elif CommonSpeciesUtils.is_cat(original_unmodified_sim_info): - bare_feet_cas_part_id = child_cat_bare_feet_id - elif CommonAgeUtils.is_toddler(original_unmodified_sim_info): - bare_feet_cas_part_id = toddler_human_bare_feet_id - - if bare_feet_cas_part_id is None: - return tuple() - - return CommonCASPart(bare_feet_cas_part_id, CommonCASUtils.get_body_type_of_cas_part(bare_feet_cas_part_id)), - - # We override the original "appearance_modifiers" to so we can insert our custom appearance modifier. - FACTORY_TUNABLES = { - 'appearance_modifiers': TunableList( - description=' The specific appearance modifiers to use for this buff. ', - tunable=TunableList( - description=' A tunable list of weighted modifiers. When applying modifiers one of the modifiers in this list will be applied. The weight will be used to run a weighted random selection. ', - tunable=TunableTuple( - description=' A Modifier to apply and weight for the weighted random selection. ', - modifier=TunableVariant( - custom_bare_feet_modifier=CommonAttachBareFeetModifier.TunableFactory(), - ), - weight=TunableMultiplier.TunableFactory( - description=' A weight with testable multipliers that is used to determine how likely this entry is to be picked when selecting randomly. ' - ) - ) - ) - ) - } - - - # We use this buff in a Buff tuning and then apply the buff to the Sim. - class CommonExampleApplyBareFeetBuff(Buff): - - # We override the original "appearance_modifier" to so we can insert our custom appearance modifier. - INSTANCE_TUNABLES = { - 'appearance_modifier': OptionalTunable(CommonExampleApplyBareFeetAppearanceModifier.TunableFactory()), - } - - - :Example Tuning: - - Buff Tuning: - - .. highlight:: xml - .. code-block:: xml - - - - - - - - - - - - - - - - - 39b2aa4a:00000000:8af8b916cf64c646 - 39b2aa4a:00000000:3bf33216a25546ea - 2f7d0004:00000000:30f0846c783606f9 - False - - - Sim Data: - - .. highlight:: xml - .. code-block:: xml - - - - - - FD04E3BE-001407EC-8AF8B916CF64C646 - FD04E3BE-001407EC-3BF33216A25546EA - 0x00000000 - 0x00000000 - 00B2D882-00000000-30F0846C783606F9 - 0 - 0 - 0x00000000 - 0x00000000 - 1 - - - - - - - - - - - - - - - - - - - - - """ - - # noinspection PyMissingOrEmptyDocstring - @property - def mod_identity(self) -> CommonModIdentity: - raise NotImplementedError() - - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - raise NotImplementedError() - - # noinspection PyMissingOrEmptyDocstring - def modify_sim_info(self, source_sim_info: SimInfo, modified_sim_info: SimInfo, random_seed: int) -> Tuple[BodyTypeFlag, Union[List[int], None]]: - try: - if not hasattr(modified_sim_info, 'original_unmodified_sim_info'): - self.log.format_with_message('No Based On Sim Info found, using current source Sim!', original_unmodified_sim=source_sim_info) - original_unmodified_sim_info = source_sim_info - else: - original_unmodified_sim_info = getattr(modified_sim_info, 'original_unmodified_sim_info') - self.log.format_with_message('Based On Sim Info found, using Based On Sim Info!', original_unmodified_sim=original_unmodified_sim_info) - - self.log.format_with_message('Copying the base attributes of Sim to the modified Sim.', sim=source_sim_info, original_unmodified_sim=original_unmodified_sim_info, modified_sim=modified_sim_info) - if source_sim_info is not modified_sim_info: - from sims.sim_info_base_wrapper import SimInfoBaseWrapper - SimInfoBaseWrapper.copy_base_attributes(modified_sim_info, source_sim_info) - SimInfoBaseWrapper.copy_physical_attributes(modified_sim_info, source_sim_info) - modified_sim_info.skin_tone = source_sim_info._base.skin_tone - modified_sim_info.skin_tone_val_shift = source_sim_info._base.skin_tone_val_shift - modified_sim_info.load_outfits(source_sim_info.save_outfits()) - - cas_parts = self._get_cas_parts(source_sim_info, modified_sim_info, original_unmodified_sim_info, random_seed) - body_types = self._apply_cas_parts(cas_parts, source_sim_info, modified_sim_info, original_unmodified_sim_info, random_seed) - - if not body_types: - self.log.format_with_message('No body types were returned. Assuming BodyTypeFlag is NONE', sim=original_unmodified_sim_info, cas_part_ids_and_body_types=cas_parts) - return BodyTypeFlag.NONE, None - body_types = [CommonBodySlot.convert_to_vanilla(body_type) for body_type in body_types] - body_type_flags = BodyTypeFlag.make_body_type_flag(*body_types) - self.log.format_with_message('Done applying CAS Parts!', sim=original_unmodified_sim_info, cas_part_ids_and_body_types=cas_parts, body_type_flags=body_type_flags, body_types=body_types) - return body_type_flags, None - except Exception as ex: - self.log.error('An error occurred while applying selected part.', exception=ex) - return BodyTypeFlag.NONE, None - - def _get_cas_parts(self, source_sim_info: SimInfo, modified_sim_info: SimInfo, original_unmodified_sim_info: SimInfo, random_seed: int) -> Tuple[CommonCASPart]: - """_get_cas_parts(source_sim_info, modified_sim_info, original_unmodified_sim_info, random_seed) - - Retrieve a collection of CAS Parts being applied to the Sim. - - :param source_sim_info: The Sim the parts are being applied to. (This Sim is replaced with "modified_sim_info" after the first appearance modifier modification) - :type source_sim_info: SimInfo - :param modified_sim_info: A cloned instance of "source_sim_info" that the parts are applied to. (The value of this property replaces "source_sim_info" after the first appearance modifier modification) - :type modified_sim_info: SimInfo - :param original_unmodified_sim_info: The original unmodified Sim, from before any modifications were made to them. This value will never be replaced and keeps the original information about the Sim, especially their Sim Id. - :type original_unmodified_sim_info: SimInfo - :param random_seed: The seed used to assign the appearance modifier. - :type random_seed: int - :return: A collection of CAS Parts that will be applied to the Sim. - :rtype: Tuple[CommonCASPart] - """ - raise NotImplementedError() - - # noinspection PyUnusedLocal - def _apply_cas_parts(self, cas_parts: Tuple[CommonCASPart], source_sim_info: SimInfo, modified_sim_info: SimInfo, original_unmodified_sim_info: SimInfo, random_seed: int) -> Tuple[Union[CommonBodySlot, BodyType, int]]: - if not cas_parts: - self.log.format_with_message('No CAS Parts were found to apply.', sim=original_unmodified_sim_info) - return tuple() - - self.log.format_with_message('Applying CAS Parts with ids', sim=original_unmodified_sim_info, cas_part_ids_and_body_types=cas_parts) - - from s4ap.sims4communitylib.utils.cas.common_cas_utils import CommonCASUtils - CommonCASUtils.attach_cas_parts_to_all_outfits_of_sim(modified_sim_info, cas_parts) - - body_types: Tuple[Union[CommonBodySlot, BodyType, int], ...] = tuple([cas_part.body_type for cas_part in cas_parts]) - return body_types - - @property - def modifier_type(self) -> CommonAppearanceModifierType: - """The type of modifier being applied.""" - return CommonAppearanceModifierType.CUSTOM - - @property - def is_permanent_modification(self) -> bool: - """Whether the modification is permanent or not.""" - return False - - @property - def combinable_sorting_key(self) -> str: - """A key used to combine this appearance modifiers with other appearance modifiers.""" - return self.__class__.__name__ - - # noinspection PyUnusedLocal - def is_compatible_with_outfit(self, outfit_category: OutfitCategory) -> bool: - """is_compatible_with_outfit(outfit_category) - - Whether or not the appearance modifier is compatible with the specified outfit category. - - .. note:: If the appearance modifier is not compatible, then the buff that applies it will be removed. - - :param outfit_category: The outfit category being checked. - :type outfit_category: OutfitCategory - :return: True, if the appearance modifier is compatible with the specified outfit category. False, if not. - :rtype: bool - """ - return True - - def __repr__(self) -> str: - return self.__class__.__name__ - - -if not ON_RTD: - @CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_testing.toggle_example_appearance_modifier_buff', - 'Apply an example S4CL buff that will make the feet of the Sims with it bare.', - command_arguments=( - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of a Sim to attach the buff to.', is_optional=True, default_value='Active Sim'), - ) - ) - def _s4cl_testing_apply_example_bare_feet_buff(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): - if sim_info is None: - return False - output(f'Toggling bare feet example buff on Sim {sim_info}.') - from s4ap.sims4communitylib.utils.sims.common_buff_utils import CommonBuffUtils - if CommonBuffUtils.has_buff(sim_info, CommonBuffId.S4CL_EXAMPLE_APPLY_BARE_FEET): - output(f'Removing bare feet example buff from Sim {sim_info}') - CommonBuffUtils.remove_buff(sim_info, CommonBuffId.S4CL_EXAMPLE_APPLY_BARE_FEET) - else: - output(f'Adding bare feet example buff on Sim {sim_info}') - CommonBuffUtils.add_buff(sim_info, CommonBuffId.S4CL_EXAMPLE_APPLY_BARE_FEET) - output(f'Done toggling bare feet example buff on Sim {sim_info}') diff --git a/Scripts/s4ap/sims4communitylib/classes/buffs/__init__.py b/Scripts/s4ap/sims4communitylib/classes/buffs/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/buffs/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/classes/buffs/common_buff.py b/Scripts/s4ap/sims4communitylib/classes/buffs/common_buff.py deleted file mode 100644 index 2a2e1af..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/buffs/common_buff.py +++ /dev/null @@ -1,99 +0,0 @@ -""" -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 -""" -from typing import Union -from buffs.buff import Buff -from sims.sim import Sim -from s4ap.sims4communitylib.logging.has_class_log import HasClassLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - - -class CommonBuff(Buff, HasClassLog): - """CommonBuff(...) - - An inheritable class that provides a way to create Custom Buffs. - - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 'common_buff' - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - raise NotImplementedError('Missing \'{}\'.'.format(cls.get_mod_identity.__name__)) - - @property - def sim(self) -> Union[Sim, None]: - """Retrieve the Sim that owns the Buff. - - :return: An instance of the Sim that owns the Buff - :rtype: Sim - """ - return CommonSimUtils.get_sim_instance(self._owner) - - # noinspection PyMissingOrEmptyDocstring - def on_add(self, from_load: bool=False, apply_buff_loot: bool=True): - """on_add(from_load=False, apply_buff_loot=True) - - A function that occurs upon a Buff being added to a Sim. - - :param from_load: True, if the Buff is being added from a load. Default is False. - :type from_load: bool, optional - :param apply_buff_loot: If True, Loot will be applied when the Buff is added. Default is True. - :type apply_buff_loot: bool, optional - """ - super().on_add(from_load=from_load, apply_buff_loot=apply_buff_loot) - try: - self.on_added(self.sim, from_load=from_load, apply_buff_loot=apply_buff_loot) - except Exception as ex: - self.log.error('Error occurred while running buff \'{}\' on_added.'.format(self.__class__.__name__), exception=ex) - - def on_remove(self, apply_loot_on_remove: bool=True): - """on_remove(apply_loot_on_remove=True) - - A function that occurs upon a Buff being removed from a Sim. - - :param apply_loot_on_remove: If True, Loot will be applied after the Buff is removed. If False, it won't. Default is True. - :type apply_loot_on_remove: bool, optional - """ - super().on_remove(apply_loot_on_remove=apply_loot_on_remove) - try: - self.on_removed(self.sim, apply_loot_on_remove=apply_loot_on_remove) - except Exception as ex: - self.log.error('Error occurred while running buff \'{}\' on_removed.'.format(self.__class__.__name__), exception=ex) - - # The following functions are hooks into various parts of a buff, override them in your own buff to provide custom functionality. - - def on_added(self, owner: Sim, from_load: bool=False, apply_buff_loot: bool=True): - """on_added(owner, from_load=False, apply_buff_loot=True) - - A hook that occurs upon the Buff being added to the Sim. - - :param owner: The Sim that owns the Buff. - :type owner: Sim - :param from_load: True, if the Buff was added from a load. Default is False. - :type from_load: bool, optional - :param apply_buff_loot: If True, Loot was applied when the Buff was added. Default is True. - :type apply_buff_loot: bool, optional - """ - pass - - def on_removed(self, owner: Sim, apply_loot_on_remove: bool=True): - """on_removed(owner, apply_loot_on_remove=True) - - A hook that occurs upon the Buff being removed from the Sim. - - :param owner: The Sim that owns the Buff. - :type owner: Sim - :param apply_loot_on_remove: If True, Loot will be applied after the Buff is removed. If False, it won't. Default is True. - :type apply_loot_on_remove: bool, optional - """ - pass diff --git a/Scripts/s4ap/sims4communitylib/classes/calculations/__init__.py b/Scripts/s4ap/sims4communitylib/classes/calculations/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/calculations/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/classes/calculations/common_available_for_sim.py b/Scripts/s4ap/sims4communitylib/classes/calculations/common_available_for_sim.py deleted file mode 100644 index 213e20a..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/calculations/common_available_for_sim.py +++ /dev/null @@ -1,174 +0,0 @@ -""" -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 -""" -from pprint import pformat -from typing import Tuple, Iterator - -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.enums.common_age import CommonAge -from s4ap.sims4communitylib.enums.common_gender import CommonGender -from s4ap.sims4communitylib.enums.common_occult_type import CommonOccultType -from s4ap.sims4communitylib.enums.common_species import CommonSpecies - - -class CommonAvailableForSim: - """CommonAvailableForSim(\ - genders=(),\ - ages=(),\ - species=(),\ - occult_types=()\ - ) - - Holds information for what types of Sims this is available for. - - .. note:: At least one argument must be supplied with values. - - :param genders: An iterator of CommonGender. Default is an empty collection. - :type genders: Iterator[CommonGender], optional - :param ages: An iterator of CommonAge. Default is an empty collection. - :type ages: Iterator[CommonAge], optional - :param species: An iterator of CommonSpecies. Default is an empty collection. - :type species: Iterator[CommonSpecies], optional - :param occult_types: An iterator of CommonOccultType. Default is an empty collection. - :type occult_types: Iterator[CommonOccultType], optional - """ - def __init__( - self, - genders: Iterator[CommonGender]=(), - ages: Iterator[CommonAge]=(), - species: Iterator[CommonSpecies]=(), - occult_types: Iterator[CommonOccultType]=() - ): - self._genders = tuple(genders) - self._ages = tuple(ages) - self._species = tuple(species) - self._occult_types = tuple(occult_types) - if not self._genders and not self._ages and not self._species and not self._occult_types: - raise AssertionError('No Genders, Ages, Species, nor Occult Types were specified!') - - @property - def genders(self) -> Tuple[CommonGender]: - """Genders this is available for.""" - return self._genders - - @property - def ages(self) -> Tuple[CommonAge]: - """Ages this is available for.""" - return self._ages - - @property - def species(self) -> Tuple[CommonSpecies]: - """Species this is available for.""" - return self._species - - @property - def occult_types(self) -> Tuple[CommonOccultType]: - """Occult Types this is available for.""" - return self._occult_types - - def is_available_for(self, sim_info: SimInfo) -> bool: - """is_available_for(sim_info) - - Determine if available for a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: True, if is available for the specified Sim. False, if not. - :rtype: bool - """ - age = CommonAge.get_age(sim_info) - if self.ages and age not in self.ages: - return False - gender = CommonGender.get_gender(sim_info) - if self.genders and gender not in self.genders: - return False - common_species = CommonSpecies.get_species(sim_info) - if self.species and common_species not in self.species: - return False - common_occult_type = CommonOccultType.determine_occult_type(sim_info) - if self.occult_types and common_occult_type not in self.occult_types: - return False - return True - - def is_valid(self) -> Tuple[bool, str]: - """is_valid() - - Determine if the Available For is valid. - - :return: If the Available For is valid, the return will be True and a Success message. If the Available For is not valid, the return will be False and an error message. - :rtype: Tuple[bool, str] - """ - if len(self.genders) == 0 and len(self.ages) == 0 and len(self.species) == 0 and len(self.occult_types) == 0: - return False, 'No Genders, Ages, Species, nor Occult Types were specified!' - return True, 'Success' - - def clone(self) -> 'CommonAvailableForSim': - """Clone the available for.""" - return CommonAvailableForSim( - genders=tuple(self.genders), - ages=tuple(self.ages), - species=tuple(self.species), - occult_types=tuple(self.occult_types) - ) - - @staticmethod - def generate_for_sim(sim_info: SimInfo) -> 'CommonAvailableForSim': - """generate_for_sim(sim_info) - - Generate an available for, for a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: An available for matching the specified Sim. - :rtype: CommonAvailableForSim - """ - from s4ap.sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils - gender = CommonGender.get_gender(sim_info) - if gender == CommonGender.INVALID: - genders = tuple() - else: - genders = (gender,) - age = CommonAge.get_age(sim_info) - if age == CommonAge.INVALID: - ages = tuple() - elif CommonAgeUtils.is_teen_adult_or_elder_age(age): - ages = (CommonAge.TEEN, CommonAge.YOUNGADULT, CommonAge.ADULT, CommonAge.ELDER) - else: - ages = (age,) - sim_species = CommonSpecies.get_species(sim_info) - if sim_species == CommonSpecies.INVALID: - species = tuple() - else: - species = (sim_species,) - occult_type = CommonOccultType.determine_occult_type(sim_info) - if occult_type == CommonOccultType.NON_OCCULT: - occult_types = (occult_type,) - else: - occult_types = (CommonOccultType.NON_OCCULT, occult_type) - return CommonAvailableForSim( - genders=genders, - ages=ages, - species=species, - occult_types=occult_types - ) - - @staticmethod - def everything() -> 'CommonAvailableForSim': - """ Create an Available For instance that applies to everything. """ - return CommonAvailableForSim( - genders=CommonGender.get_all(), - ages=CommonAge.get_all(), - species=CommonSpecies.get_all(), - occult_types=CommonOccultType.get_all() - ) - - def __repr__(self) -> str: - return ''\ - .format(pformat(self.genders), pformat(self.ages), pformat(self.species), pformat(self.occult_types)) - - def __str__(self) -> str: - return self.__repr__() diff --git a/Scripts/s4ap/sims4communitylib/classes/commodities/__init__.py b/Scripts/s4ap/sims4communitylib/classes/commodities/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/commodities/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/classes/commodities/common_commodity.py b/Scripts/s4ap/sims4communitylib/classes/commodities/common_commodity.py deleted file mode 100644 index fb2119f..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/commodities/common_commodity.py +++ /dev/null @@ -1,28 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.logging.has_class_log import HasClassLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from statistics.commodity import Commodity - - -class CommonCommodity(Commodity, HasClassLog): - """CommonCommodity() - - A commodity override with additional functionality. - - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - raise NotImplementedError() - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - raise NotImplementedError() diff --git a/Scripts/s4ap/sims4communitylib/classes/common_resource_key.py b/Scripts/s4ap/sims4communitylib/classes/common_resource_key.py deleted file mode 100644 index c6e5939..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/common_resource_key.py +++ /dev/null @@ -1,133 +0,0 @@ -""" -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 -""" -import os -from typing import Union -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - -ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' - -if ON_RTD: - # noinspection PyMissingOrEmptyDocstring - class Types(CommonInt): - pass - - # noinspection PyMissingOrEmptyDocstring - class Groups(CommonInt): - pass - - # noinspection PyMissingOrEmptyDocstring - class Key: - # noinspection PyPropertyDefinition - @property - def type(self) -> str: - pass - - # noinspection PyPropertyDefinition - @property - def instance(self) -> str: - pass - - # noinspection PyPropertyDefinition - @property - def group(self) -> str: - pass - - # noinspection PyUnusedLocal - def __init__(self, res_type: int, res_instance: int, *args, **kwargs): - pass - -if not ON_RTD: - try: - # noinspection PyUnresolvedReferences - from _resourceman import Key - from sims4.resources import Types, Groups - except: - class Key: - pass - - class Types: - pass - - class Groups: - pass - - -class CommonResourceKey: - """CommonResourceKey(resource_key_type, resource_key_instance, resource_key_group) - - A wrapper for a resource key. - - :param resource_key_type: An identifier that indicates the tuning type of the resource. - :type resource_key_type: Union[int, str, Types] - :param resource_key_instance: An identifier that indicates what tuning instance the resource key is for. - :type resource_key_instance: Union[int, str] - :param resource_key_group: An identifier that indicates what tuning group the resource key is for. In most cases a group of "0" is sufficient. - :type resource_key_group: Union[int, str, Group] - """ - - @property - def type(self) -> Union[int, str, Types]: - """ The type identifier of the resource. """ - return self._resource_key_type - - @property - def instance(self) -> Union[int, str]: - """ The instance identifier of the resource. """ - return self._resource_key_instance - - @property - def group(self) -> Union[int, str, Groups]: - """ The group identifier of the resource. """ - return self._resource_key_group - - def __init__(self, resource_key_type: Union[int, str, Types], resource_key_instance: Union[int, str], resource_key_group: Union[int, str, Groups]): - self._resource_key_type = resource_key_type - self._resource_key_instance = resource_key_instance - self._resource_key_group = resource_key_group - - def __new__(cls, resource_key_type: Union[int, str, Types], resource_key_instance: Union[int, str], resource_key_group: Union[int, str, Groups]) -> 'CommonResourceKey': - # noinspection PyTypeChecker - return Key(resource_key_type, resource_key_instance, resource_key_group) - - @staticmethod - def empty() -> 'CommonResourceKey': - """empty() - - Create an empty resource key. - - :return: An empty resource key. - :rtype: CommonResourceKey - """ - return CommonResourceKey(0, 0, 0) - - @staticmethod - def from_resource_key(resource_key: Union[Key, 'CommonResourceKey']) -> Union['CommonResourceKey', None]: - """from_resource_key(resource_key) - - Convert a vanilla Key object into a CommonResourceKey. - - :param resource_key: An instance of a Resource Key. - :type resource_key: Union[Key, CommonResourceKey] - :return: An instance of a CommonResourceKey or None if the object failed to convert. - :rtype: Union[CommonResourceKey, None] - """ - if resource_key is None: - return None - if isinstance(resource_key, CommonResourceKey): - return resource_key - if not isinstance(resource_key, Key): - raise Exception('Failed to convert {} with type {}, it was not of type {}.'.format(resource_key, type(resource_key), type(Key))) - return CommonResourceKey(resource_key.type, resource_key.instance, resource_key.group) - - def __repr__(self) -> str: - if not self.group or self.group == 0: - return '{}!{}'.format(self.type, self.instance) - return '{}!{}!{}'.format(self.type, self.instance, self.group) - - def __str__(self) -> str: - return self.__repr__() diff --git a/Scripts/s4ap/sims4communitylib/classes/effects/__init__.py b/Scripts/s4ap/sims4communitylib/classes/effects/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/effects/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/classes/effects/common_visual_effect.py b/Scripts/s4ap/sims4communitylib/classes/effects/common_visual_effect.py deleted file mode 100644 index 78fc3cb..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/effects/common_visual_effect.py +++ /dev/null @@ -1,217 +0,0 @@ -""" -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 -""" -from typing import Callable, Union - -import alarms -from date_and_time import TimeSpan -from sims.sim import Sim -from s4ap.sims4communitylib.logging.has_log import HasLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from vfx import PlayEffect -from objects.game_object import GameObject - - -class CommonVisualEffect(HasLog): - """CommonVisualEffect(\ - mod_identity,\ - target,\ - effect_name,\ - joint_bone_name='b__Root__',\ - target_actor_id=0,\ - target_joint_bone_name=None,\ - **kwargs\ - ) - - A visual effect that will play while attached to an object or Sim. - - :param mod_identity: The identity of the mod that owns this visual effect. - :type mod_identity: CommonModIdentity - :param source: An instance of an object or Sim. They will be the source of the effect. - :type source: Union[GameObject, Sim] - :param effect_name: The name of the effect to play. - :type effect_name: str - :param joint_bone_name: The name of the joint to play the effect attached to. Default is the root bone 'b__Root__'. - :type joint_bone_name: str, optional - :param target_actor_id: The id of the target actor. Default will be the id of the target. - :type target_actor_id: int, optional - :param target_joint_bone_name: The name of the joint to play the effect attached to on the target. Default is the value of joint_bone_name. - :type target_joint_bone_name: str, optional - """ - - # noinspection PyMissingOrEmptyDocstring - @property - def mod_identity(self) -> CommonModIdentity: - return self._mod_identity - - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - return 'common_game_object_effect' - - def __init__( - self, - mod_identity: CommonModIdentity, - source: Union[GameObject, Sim], - effect_name: str, - joint_bone_name: str = 'b__Root__', - target_actor_id: int = 0, - target_joint_bone_name: str = None, - **kwargs - ): - from sims4.hash_util import hash32 - super().__init__() - self._source = source - self._mod_identity = mod_identity - self._effect_name = effect_name - self._joint_bone_name = joint_bone_name - self._target_actor_id = target_actor_id - self._target_joint_bone_name = target_joint_bone_name - if joint_bone_name is None: - joint_bone_hash = 0 - else: - joint_bone_hash = hash32(joint_bone_name) - if target_joint_bone_name is None: - target_joint_bone_hash = 0 - else: - target_joint_bone_hash = hash32(target_joint_bone_name) - self._effect_instance = PlayEffect( - source, - effect_name=effect_name, - joint_name=joint_bone_hash, - target_actor_id=target_actor_id, - target_joint_name_hash=target_joint_bone_hash, - **kwargs - ) - self._alarm_handle = None - - def start(self, time_span: TimeSpan = None, on_end: Callable[['CommonVisualEffect'], None] = None) -> bool: - """start(time_span=None, on_end=None) - - Start the effect. - - :param time_span: A span of time indicating how long to run the effect for. Default is however long the vfx itself runs. - :type time_span: TimeSpan, optional - :param on_end: A callback invoked when the effect ends. This is only used when sim_minutes_until_end is specified. Default is None. - :type on_end: Callable[['CommonVisualEffect'], None], optional - :return: True, if the effect was started successfully. False, if not. - :rtype: bool - """ - try: - self.log.format_with_message('Running effect.', source=self._source, effect_name=self._effect_name, time_span=time_span) - self._effect_instance.start() - if time_span is not None: - self._create_stop_alarm(time_span, on_end=on_end) - return True - except Exception as ex: - self.log.format_error_with_message( - 'Error occurred while trying to start visual effect.', - effect_instance=self._effect_instance, - source=self._source, - effect_name=self._effect_name, - joint_bone_name=self._joint_bone_name, - target_actor_id=self._target_actor_id, - target_joint_bone_name=self._target_joint_bone_name, - exception=ex - ) - return False - - def start_run_once(self, time_span: TimeSpan = None, on_end: Callable[['CommonVisualEffect'], None] = None) -> bool: - """start_run_once(time_span=None, on_end=None) - - Start the effect and have it run only once. - - :param time_span: A span of time indicating how long to run the effect for. Default is however long the vfx itself runs. - :type time_span: TimeSpan, optional - :param on_end: A callback invoked when the effect ends. This is only used when sim_minutes_until_end is specified. Default is None. - :type on_end: Callable[['CommonVisualEffect'], None], optional - :return: True, if the effect was started successfully. False, if not. - :rtype: bool - """ - try: - self.log.format_with_message('Running effect once.', source=self._source, effect_name=self._effect_name, time_span=time_span) - self._effect_instance.start_one_shot() - if time_span is not None: - self._create_stop_alarm(time_span, on_end=on_end) - return True - except Exception as ex: - self.log.format_error_with_message( - 'Error occurred while trying to start visual effect via one shot.', - effect_instance=self._effect_instance, - source=self._source, - effect_name=self._effect_name, - joint_bone_name=self._joint_bone_name, - target_actor_id=self._target_actor_id, - target_joint_bone_name=self._target_joint_bone_name, - exception=ex - ) - return False - - def _create_stop_alarm(self, time_span: TimeSpan, on_end: Callable[['CommonVisualEffect'], None] = None) -> None: - def _on_end(_) -> None: - if on_end is not None: - on_end(self) - self.stop() - - self._alarm_handle = alarms.add_alarm(self, time_span, _on_end, repeating=False, use_sleep_time=False) - - def _destroy_stop_alarm(self) -> None: - if self._alarm_handle is not None: - alarms.cancel_alarm(self._alarm_handle) - self._alarm_handle = None - - def stop(self) -> bool: - """stop() - - Stop the effect. - - :return: True, if the effect was stopped successfully. False, if not. - :rtype: bool - """ - try: - self.log.format_with_message('Stopping effect.', source=self._source, effect_name=self._effect_name) - self._destroy_stop_alarm() - self._effect_instance.stop() - return True - except Exception as ex: - self.log.format_error_with_message( - 'Error occurred while trying to stop visual effect.', - effect_instance=self._effect_instance, - source=self._source, - effect_name=self._effect_name, - joint_bone_name=self._joint_bone_name, - target_actor_id=self._target_actor_id, - target_joint_bone_name=self._target_joint_bone_name, - exception=ex - ) - return False - - def stop_immediate(self) -> bool: - """stop_immediate() - - Kill the effect. - - :return: True, if the effect was stopped successfully. False, if not. - :rtype: bool - """ - try: - self.log.format_with_message('Stopping effect immediate.', source=self._source, effect_name=self._effect_name) - self._destroy_stop_alarm() - self._effect_instance.stop(immediate=True) - return True - except Exception as ex: - self.log.format_error_with_message( - 'Error occurred while trying to stop visual effect immediately.', - effect_instance=self._effect_instance, - source=self._source, - effect_name=self._effect_name, - joint_bone_name=self._joint_bone_name, - target_actor_id=self._target_actor_id, - target_joint_bone_name=self._target_joint_bone_name, - exception=ex - ) - return False diff --git a/Scripts/s4ap/sims4communitylib/classes/enums/__init__.py b/Scripts/s4ap/sims4communitylib/classes/enums/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/enums/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/classes/enums/common_versioned_enum_value_collection.py b/Scripts/s4ap/sims4communitylib/classes/enums/common_versioned_enum_value_collection.py deleted file mode 100644 index e52548d..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/enums/common_versioned_enum_value_collection.py +++ /dev/null @@ -1,81 +0,0 @@ -""" -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 -""" -from typing import Tuple, Union, Dict, Any, Iterator, TypeVar, Generic, Type - -from s4ap.sims4communitylib.enums.enumtypes.common_versioned_int import CommonVersionedInt -from s4ap.sims4communitylib.enums.enumtypes.common_versioned_int_flags import CommonVersionedIntFlags -from s4ap.sims4communitylib.classes.serialization.common_serializable import CommonSerializable -from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils - -CommonEnumType = TypeVar('CommonEnumType', CommonVersionedIntFlags, CommonVersionedInt) - -CommonVersionedEnumValueCollectionType = TypeVar('CommonVersionedEnumValueCollectionType', bound="CommonVersionedEnumValueCollection") - - -class CommonVersionedEnumValueCollection(CommonSerializable, Generic[CommonEnumType]): - """CommonVersionedEnumValueCollection(\ - enum_values,\ - version=None\ - ) - - A collection of enum values with a version. - - :param enum_values: A collection of enum values. - :type enum_values: Iterator[CommonEnumType] - :param version: The version of the data. Default is the version of the enum. - :type version: str, optional - """ - - def __init__(self: CommonVersionedEnumValueCollectionType, enum_values: Iterator[CommonEnumType], version: str = None): - self._enum_values = tuple(enum_values) - self._version = version or self.get_enum_type().get_version() - - @property - def enum_values(self: CommonVersionedEnumValueCollectionType) -> Tuple[CommonEnumType]: - """A collection of enum values.""" - # noinspection PyTypeChecker - return self._enum_values - - @property - def version(self: CommonVersionedEnumValueCollectionType) -> str: - """The version of the enum values.""" - return self._version - - @classmethod - def get_enum_type(cls: Type[CommonVersionedEnumValueCollectionType]) -> Type[CommonEnumType]: - """The type of enum.""" - raise NotImplementedError() - - # noinspection PyMissingOrEmptyDocstring - def serialize(self: CommonVersionedEnumValueCollectionType) -> Union[str, Dict[str, Any]]: - data = dict() - data['enum_values'] = [enum_value.name for enum_value in self.enum_values] - data['version'] = self.version - return data - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def deserialize(cls: Type[CommonVersionedEnumValueCollectionType], data: Union[str, Dict[str, Any]]) -> Union[CommonVersionedEnumValueCollectionType, None]: - if not hasattr(data, 'get'): - return None - enum_value_names = data.get('enum_values', None) - if enum_value_names is None: - return None - - enum_values = list() - for enum_value_name in enum_value_names: - enum_value = CommonResourceUtils.get_enum_by_name(enum_value_name, cls.get_enum_type(), default_value=None) - if enum_value is None: - continue - enum_value = cls.get_enum_type().convert_obsolete_value(enum_value) - enum_values.append(enum_value) - - version = data.get('version', None) - if version is None or version != cls.get_enum_type().get_version(): - return None - return cls(enum_values, version=version) diff --git a/Scripts/s4ap/sims4communitylib/classes/enums/common_versioned_sim_demographic_type_collection.py b/Scripts/s4ap/sims4communitylib/classes/enums/common_versioned_sim_demographic_type_collection.py deleted file mode 100644 index 6b997e7..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/enums/common_versioned_sim_demographic_type_collection.py +++ /dev/null @@ -1,39 +0,0 @@ -""" -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 -""" -from typing import Tuple, Type, Iterator - -from s4ap.sims4communitylib.classes.enums.common_versioned_enum_value_collection import CommonVersionedEnumValueCollection -from s4ap.sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType - - -class CommonVersionedSimDemographicTypeCollection(CommonVersionedEnumValueCollection[CommonSimDemographicType]): - """CommonVersionedSimDemographicTypeCollection(\ - demographic_types,\ - version=None\ - ) - - A collection of demographic types with a version. - - :param demographic_types: A collection of demographic types. - :type demographic_types: Iterator[CommonSimDemographicType] - :param version: The version of the data. Default is the version of CommonSimDemographicType. - :type version: str, optional - """ - - def __init__(self, demographic_types: Iterator[CommonSimDemographicType], version: str = None): - super().__init__(demographic_types, version=version) - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_enum_type(cls) -> Type[CommonSimDemographicType]: - return CommonSimDemographicType - - @property - def demographic_types(self) -> Tuple[CommonSimDemographicType]: - """Types of demographics.""" - return self.enum_values diff --git a/Scripts/s4ap/sims4communitylib/classes/filters/__init__.py b/Scripts/s4ap/sims4communitylib/classes/filters/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/filters/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/classes/filters/common_match_all_non_sims_object_filter.py b/Scripts/s4ap/sims4communitylib/classes/filters/common_match_all_non_sims_object_filter.py deleted file mode 100644 index 1ad5751..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/filters/common_match_all_non_sims_object_filter.py +++ /dev/null @@ -1,19 +0,0 @@ -""" -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 -""" -from objects.proxy import ProxyObject -from objects.script_object import ScriptObject -from s4ap.sims4communitylib.classes.filters.common_match_object_filter import CommonMatchObjectFilterBase -from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils - - -class CommonMatchAllNonSimsObjectFilter(CommonMatchObjectFilterBase): - """An object filter that will match on all non-Sim objects.""" - - # noinspection PyMissingOrEmptyDocstring - def matches(self, obj: ScriptObject) -> bool: - return not CommonTypeUtils.is_sim_or_sim_info(obj) and CommonTypeUtils.is_game_object(obj) and not isinstance(obj, ProxyObject) diff --git a/Scripts/s4ap/sims4communitylib/classes/filters/common_match_all_sims_object_filter.py b/Scripts/s4ap/sims4communitylib/classes/filters/common_match_all_sims_object_filter.py deleted file mode 100644 index c03bdbf..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/filters/common_match_all_sims_object_filter.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.classes.filters.common_match_object_filter import CommonMatchObjectFilterBase -from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils - - -class CommonMatchAllSimsObjectFilter(CommonMatchObjectFilterBase): - """A filter that will match on all Sims.""" - # noinspection PyMissingOrEmptyDocstring - def matches(self, obj) -> bool: - return CommonTypeUtils.is_sim_or_sim_info(obj) diff --git a/Scripts/s4ap/sims4communitylib/classes/filters/common_match_object_filter.py b/Scripts/s4ap/sims4communitylib/classes/filters/common_match_object_filter.py deleted file mode 100644 index 2505a0a..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/filters/common_match_object_filter.py +++ /dev/null @@ -1,36 +0,0 @@ -""" -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 -""" -from interactions.utils.object_definition_or_tags import TunableObjectFilter -from objects.script_object import ScriptObject -from s4ap.sims4communitylib.enums.common_object_filter_type import CommonObjectFilterType - - -class CommonMatchObjectFilterBase(TunableObjectFilter): - """A filter that will match on objects.""" - - def get_filter_type(self) -> CommonObjectFilterType: - """Indicates the type of filter.""" - return CommonObjectFilterType.CUSTOM - - def _intersect_dissimilar(self, other) -> TunableObjectFilter: - return self - - def _intersect_similar(self, other) -> TunableObjectFilter: - return self - - def matches(self, obj: ScriptObject) -> bool: - """matches(obj) - - Whether or not the specified object matches this filter. - - :param obj: An instance of an object. - :type obj: ScriptObject - :return: True, if the object matches the filter. False, if not. - :rtype: bool - """ - raise NotImplementedError() diff --git a/Scripts/s4ap/sims4communitylib/classes/interactions/__init__.py b/Scripts/s4ap/sims4communitylib/classes/interactions/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/interactions/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/classes/interactions/_common_interaction_custom_mixin.py b/Scripts/s4ap/sims4communitylib/classes/interactions/_common_interaction_custom_mixin.py deleted file mode 100644 index 8e89f3e..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/interactions/_common_interaction_custom_mixin.py +++ /dev/null @@ -1,81 +0,0 @@ -""" -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 -""" -from typing import Union, Any, Iterator, Tuple, List, Set - -from interactions.base.interaction import Interaction -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils - - -class _CommonInteractionCustomMixin: - """Custom functionality for interactions.""" - - @classmethod - def create_test_result( - cls, - result: bool, - reason: str=None, - text_tokens: Union[Tuple[Any], List[Any], Set[Any]]=(), - tooltip: Union[int, str, CommonLocalizationUtils.LocalizedTooltip]=None, - tooltip_tokens: Iterator[Any]=(), - icon=None, - influence_by_active_mood: bool=False - ) -> CommonTestResult: - """create_test_result(\ - result,\ - reason=None,\ - text_tokens=(),\ - tooltip=None,\ - tooltip_tokens=(),\ - icon=None,\ - influence_by_active_mood=False\ - ) - - Create a CommonTestResult with the specified information. - - .. note:: CommonTestResult 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 tooltip_tokens: A collection of objects to format into the localized tooltip. (They can be anything. LocalizedString, str, int, SimInfo, just to name a few) Default is an empty collection. - :type tooltip_tokens: Iterator[Any], optional - :param icon: The icon of the outcome. - :type icon: CommonResourceKey, 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`. - :rtype: CommonTestResult - """ - return CommonTestResult( - result, - reason=reason.format(*text_tokens) if reason is not None else reason, - tooltip_text=tooltip, - tooltip_tokens=tooltip_tokens, - icon=icon, - influenced_by_active_mood=influence_by_active_mood - ) - - def set_current_progress_bar(self: Interaction, 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 - """ - self._send_progress_bar_update_msg(percent, rate_change, start_msg=start_message) diff --git a/Scripts/s4ap/sims4communitylib/classes/interactions/_common_interaction_hooks_mixin.py b/Scripts/s4ap/sims4communitylib/classes/interactions/_common_interaction_hooks_mixin.py deleted file mode 100644 index a3d9c9f..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/interactions/_common_interaction_hooks_mixin.py +++ /dev/null @@ -1,325 +0,0 @@ -""" -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 -""" -from typing import Union, Any, Iterator, Tuple - -from interactions import ParticipantType -from interactions.base.interaction import Interaction -from interactions.constraints import Constraint -from interactions.context import InteractionContext -from interactions.interaction_finisher import FinishingType -from native.animation import NativeAsm -from postures.posture_state import PostureState -from protocolbuffers.Localization_pb2 import LocalizedString -from scheduling import Timeline -from sims.sim import Sim -from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from singletons import DEFAULT - - -class _CommonInteractionHooksMixin: - """Hooks that are called from the various custom interactions.""" - - # The following functions are hooks into various parts of an interaction override them in your own interaction to provide custom functionality. - - # noinspection PyUnusedLocal - @classmethod - def on_replacement_constraints_gen(cls, inst_or_cls: 'Interaction', sim: Sim, target: Any) -> Union[Iterator[Constraint], None]: - """on_replacement_constraints_gen(inst_or_cls, sim, target) - - A hook that occurs before the normal constraints of an interaction, these constraints will replace the normal constraints of the interaction. - - .. note:: If None is returned, the normal constraints will be used. (Plus any additional constraints from on_constraint_gen) - - :param inst_or_cls: An instance or the class of the interaction. - :type inst_or_cls: Interaction - :param sim: The source Sim of the interaction. - :type sim: Sim - :param target: The target Object of the interaction. - :type target: Any - :return: An iterator of constraints to replace the normal constraints of the interaction or None if replacement constraints are not wanted. - :rtype: Union[Iterator[Constraint], None] - """ - return None - - # noinspection PyUnusedLocal - @classmethod - def on_constraint_gen(cls, inst_or_cls: 'Interaction', sim: Sim, target: Any) -> Union[Iterator[Constraint], Constraint, None]: - """on_constraint_gen(inst_or_cls, sim, target) - - A hook that occurs after generating the constraints of an interaction, this constraint will be returned in addition to the normal constraints of the interaction. - - .. note:: Return None from this function to exclude any custom constraints. - - :param inst_or_cls: An instance or the class of the interaction. - :type inst_or_cls: Interaction - :param sim: The source Sim of the interaction. - :type sim: Sim - :param target: The target Object of the interaction. - :type target: Any - :return: A constraint or an iterator of constraints to return in addition to the normal constraints or None if no additional constraints should be added. - :rtype: Union[Iterator[Constraint], Constraint, None] - """ - return None - - # noinspection PyUnusedLocal - @classmethod - def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, *args, **kwargs) -> CommonTestResult: - """on_test(interaction_sim, interaction_target, interaction_context, *args, **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: CommonTestResult - """ - return CommonTestResult.TRUE - - # noinspection PyUnusedLocal - @classmethod - def on_post_super_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, *args, **kwargs) -> CommonTestResult: - """on_post_super_test(interaction_sim, interaction_target, interaction_context, *args, **kwargs) - - A hook that occurs after the interaction being tested for availability by on_test and the super _test functions. - - .. note:: This will only run if both on_test and _test returns CommonTestResult.TRUE or similar. - - :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: CommonTestResult - """ - return CommonTestResult.TRUE - - # noinspection PyUnusedLocal - def on_started(self, interaction_sim: Sim, interaction_target: Any) -> CommonExecutionResult: - """on_started(interaction_sim, interaction_target) - - A hook that occurs upon the interaction being started. - - .. note:: If CommonExecutionResult.FALSE, CommonExecutionResult.NONE, or False is returned from here, then the interaction will be cancelled instead of starting. - - :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: The result of running the start function. True, if the interaction hook was executed successfully. False, if the interaction hook was not executed successfully. - :rtype: CommonExecutionResult - """ - return CommonExecutionResult.TRUE - - # noinspection PyUnusedLocal - def on_killed(self, interaction_sim: Sim, interaction_target: Any) -> None: - """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 - """ - pass - - def on_cancelled(self, interaction_sim: Sim, interaction_target: Any, finishing_type: FinishingType, cancel_reason_msg: str, *args, **kwargs) -> None: - """on_cancelled(interaction_sim, interaction_target, finishing_type, cancel_reason_msg, *args, **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 - - # noinspection PyUnusedLocal - @classmethod - def get_custom_replacement_participants(cls, participant_type: ParticipantType, sim: Union[Sim, None], target: Union[Sim, None], carry_target: Union[Any, None], interaction: 'Interaction'=None, **kwargs) -> Union[Tuple[Any], None]: - """get_custom_replacement_participants(participant_type, sim=None, target=None, carry_target=None, interaction=None, **kwargs) - - A hook used to replace the result of the get_participants function with custom participants. - - :param participant_type: The type of participant being searched for. - :type participant_type: ParticipantType - :param sim: The Source of the interaction. - :type sim: Union[Sim, None] - :param target: The Target of the interaction. - :type sim: Union[Sim, None] - :param carry_target: The target being carried while the interaction is being run. - :type carry_target: Union[Any, None] - :param interaction: An instance of the interaction, if get_participants was invoked using an instance or None if get_participants was invoked using the class. Default is None. - :type interaction: Interaction, optional - :return: A collection of custom participants to use as replacements for the normal result of get_participants. Return None to keep the original participants. Default return is None. - :rtype: Union[Tuple[Any], None] - """ - return None - - # noinspection PyUnusedLocal - @classmethod - def get_custom_participants(cls, participant_type: ParticipantType, sim: Union[Sim, None], target: Union[Sim, None], carry_target: Union[Any, None], interaction: 'Interaction'=None, **kwargs) -> Tuple[Any]: - """get_custom_participants(participant_type, sim=None, target=None, carry_target=None, interaction=None, **kwargs) - - A hook used to add custom participants to the result of the get_participants function. - - :param participant_type: The type of participant being searched for. - :type participant_type: ParticipantType - :param sim: The Source of the interaction. - :type sim: Union[Sim, None] - :param target: The Target of the interaction. - :type sim: Union[Sim, None] - :param carry_target: The target being carried while the interaction is being run. - :type carry_target: Union[Any, None] - :param interaction: An instance of the interaction, if get_participants was invoked using an instance or None if get_participants was invoked using the class. Default is None. - :type interaction: Interaction, optional - :return: A collection of custom participants to add to the normal result of get_participants. - :rtype: Tuple[Any] - """ - return tuple() - - 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 - - @classmethod - def _create_override_display_name( - cls, - interaction_sim: Sim, - interaction_target: Any, - interaction: 'Interaction'=None, - interaction_context: InteractionContext=None, - **interaction_parameters - ) -> Union[LocalizedString, None]: - """_create_override_display_name(\ - interaction_sim,\ - interaction_target,\ - interaction=None,\ - interaction_context=None,\ - **interaction_parameters\ - ) - - If overridden you may supply a custom name for the interaction to display. - - .. 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: The interaction being performed or None. - :type interaction: Interaction - :param interaction_context: The context of the interaction being performed or None. - :type interaction_context: InteractionContext - :param interaction_parameters: Parameters for the interaction. - :type interaction_parameters: Iterator[Any] - :return: The name to use in place of the original name of the interaction or None if you want the original name to be used. - :rtype: Union[LocalizedString, None] - """ - pass - - # 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 - - # noinspection PyUnusedLocal - def on_run(self, interaction_sim: Sim, interaction_target: Any, timeline: Timeline): - """on_run(interaction_sim, interaction_target, timeline) - - A hook that occurs upon the interaction being run. - - :param interaction_sim: The sim performing the interaction. - :type interaction_sim: Sim - :param interaction_target: The target of the interaction. - :type interaction_target: Any - :param timeline: The timeline the interaction is running on. - :type timeline: Timeline - """ - pass diff --git a/Scripts/s4ap/sims4communitylib/classes/interactions/common_immediate_super_interaction.py b/Scripts/s4ap/sims4communitylib/classes/interactions/common_immediate_super_interaction.py deleted file mode 100644 index b2b6494..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/interactions/common_immediate_super_interaction.py +++ /dev/null @@ -1,427 +0,0 @@ -""" -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 -""" -import inspect -from typing import Union, Any, Set - -from event_testing.tests import TestList -from interactions import ParticipantType -from interactions.base.interaction import Interaction -from interactions.constraints import Constraint -from interactions.context import InteractionContext -from interactions.interaction_finisher import FinishingType -from native.animation import NativeAsm -from postures.posture_state import PostureState -from protocolbuffers.Localization_pb2 import LocalizedString -from scheduling import Timeline -from sims.sim import Sim -from sims4.utils import flexmethod -from s4ap.sims4communitylib.classes.interactions._common_interaction_custom_mixin import _CommonInteractionCustomMixin -from s4ap.sims4communitylib.classes.interactions._common_interaction_hooks_mixin import _CommonInteractionHooksMixin -from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult - -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.logging.has_class_log import HasClassLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from s4ap.sims4communitylib.utils.misc.common_text_utils import CommonTextUtils -from singletons import DEFAULT -from interactions.base.immediate_interaction import ImmediateSuperInteraction - - -class CommonImmediateSuperInteraction(ImmediateSuperInteraction, HasClassLog, _CommonInteractionHooksMixin, _CommonInteractionCustomMixin): - """CommonImmediateSuperInteraction(*_, **__) - - An inheritable class that provides a way to create Custom Immediate Super Interactions. - - .. note:: - - The main use for this class is to create interactions that do something upon starting the interaction, without the Sim needing to queue the interaction. - One example would be the `Replace` interaction to replace objects that were destroyed in a fire. - - .. 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) -> Union[CommonModIdentity, None]: - return None - - def __init__(self, *_: Any, **__: Any): - super().__init__(*_, **__) - HasClassLog.__init__(self) - - @classmethod - def _test(cls, target: Any, context: InteractionContext, super_interaction: 'Interaction'=None, skip_safe_tests: bool=False, **kwargs) -> CommonTestResult: - from event_testing.results import TestResult - from s4ap.sims4communitylib.classes.time.common_stop_watch import CommonStopWatch - log = cls.get_log() - verbose_log = cls.get_verbose_log() - stop_watch = CommonStopWatch() - if verbose_log.enabled: - stop_watch.start() - try: - try: - verbose_log.format_with_message( - 'Running on_test.', - class_name=cls.__name__, - interaction_sim=context.sim, - interaction_target=target, - interaction_context=context, - super_interaction=super_interaction, - skip_safe_tests=skip_safe_tests, - kwargles=kwargs - ) - test_result = cls.on_test(context.sim, target, context, super_interaction=super_interaction, skip_safe_tests=skip_safe_tests, **kwargs) - verbose_log.format_with_message('Test Result (CommonImmediateSuperInteraction)', test_result=test_result) - except Exception as ex: - log.error('Error occurred while running CommonImmediateSuperInteraction \'{}\' on_test.'.format(cls.__name__), exception=ex) - return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') - - if test_result is not None: - if isinstance(test_result, CommonTestResult): - if test_result.is_success is False: - return test_result - elif isinstance(test_result, TestResult) and 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, icon=test_result.icon, influence_by_active_mood=test_result.influence_by_active_mood) - - try: - verbose_log.format_with_message( - 'Running super()._test.', - class_name=cls.__name__, - interaction_sim=context.sim, - interaction_target=target, - interaction_context=context, - super_interaction=super_interaction, - skip_safe_tests=skip_safe_tests, - kwargles=kwargs - ) - super_test_result: TestResult = super()._test(target, context, super_interaction=super_interaction, skip_safe_tests=skip_safe_tests, **kwargs) - if verbose_log.enabled: - search_for_tooltip = context.source == context.SOURCE_PIE_MENU - resolver = cls.get_resolver(target=target, context=context, super_interaction=super_interaction, search_for_tooltip=search_for_tooltip, **kwargs) - global_result = cls.test_globals.run_tests(resolver, skip_safe_tests, search_for_tooltip=search_for_tooltip) - local_result = cls.tests.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=search_for_tooltip) - if cls._additional_tests: - additional_tests = TestList(cls._additional_tests) - additional_local_result = additional_tests.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=search_for_tooltip) - else: - additional_local_result = None - if cls.test_autonomous: - autonomous_result = cls.test_autonomous.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=False) - else: - autonomous_result = None - if target is not None: - tests = target.get_affordance_tests(cls) - if tests is not None: - target_result = tests.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=search_for_tooltip) - else: - target_result = None - else: - target_result = None - verbose_log.format_with_message('Super Test Result (CommonImmediateSuperInteraction)', super_test_result=super_test_result, global_result=global_result, local_result=local_result, additional_local_result=additional_local_result, autonomous_result=autonomous_result, target_result=target_result) - except Exception as ex: - log.error('Error occurred while running CommonImmediateSuperInteraction \'{}\' super()._test.'.format(cls.__name__), exception=ex) - return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') - - if super_test_result is not None and isinstance(test_result, TestResult) and not super_test_result.result: - return CommonTestResult.convert_from_vanilla(test_result) - - try: - verbose_log.format_with_message( - 'Running on_post_super_test.', - class_name=cls.__name__, - interaction_sim=context.sim, - interaction_target=target, - interaction_context=context, - super_interaction=super_interaction, - skip_safe_tests=skip_safe_tests, - kwargles=kwargs - ) - post_super_test_result = cls.on_post_super_test(context.sim, target, context, super_interaction=super_interaction, skip_safe_tests=skip_safe_tests, **kwargs) - verbose_log.format_with_message('Post Test Result (CommonImmediateSuperInteraction)', post_super_test_result=post_super_test_result) - except Exception as ex: - log.error('Error occurred while running CommonImmediateSuperInteraction \'{}\' on_post_super_test.'.format(cls.__name__), exception=ex) - return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') - - if post_super_test_result is not None: - if isinstance(post_super_test_result, CommonTestResult): - if post_super_test_result.is_success is False: - return post_super_test_result - elif isinstance(post_super_test_result, TestResult) and post_super_test_result.result is False: - if post_super_test_result.tooltip is not None: - post_super_test_result_tooltip = CommonLocalizationUtils.create_localized_tooltip(post_super_test_result.tooltip) - elif post_super_test_result.reason is not None: - post_super_test_result_tooltip = CommonLocalizationUtils.create_localized_tooltip(post_super_test_result.reason) - else: - post_super_test_result_tooltip = None - return cls.create_test_result(post_super_test_result.result, post_super_test_result.reason, tooltip=post_super_test_result_tooltip, icon=post_super_test_result.icon, influence_by_active_mood=post_super_test_result.influence_by_active_mood) - - return cls.create_test_result(True) - except Exception as ex: - log.error('Error occurred while running _test of CommonImmediateSuperInteraction \'{}\''.format(cls.__name__), exception=ex) - return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') - finally: - if verbose_log.enabled: - time_taken = CommonTextUtils.to_truncated_decimal(stop_watch.stop_milliseconds()) - verbose_log.format_with_message(f'Took {time_taken}ms to return result from CommonImmediateSuperInteraction.', class_name=cls.__name__) - else: - stop_watch.stop() - - # noinspection PyMissingOrEmptyDocstring,PyMethodParameters - @flexmethod - def get_participants(cls, inst, participant_type: ParticipantType, sim=DEFAULT, target=DEFAULT, carry_target=DEFAULT, **kwargs): - inst_or_cls = inst or cls - log = cls.get_log() - try: - custom_participants = cls.get_custom_replacement_participants(participant_type, sim, target, carry_target, interaction=inst, **kwargs) - if custom_participants is not None: - return tuple(custom_participants) - except Exception as ex: - log.error('Error occurred while running CommonImmediateSuperInteraction \'{}\' get_custom_replacement_participants.'.format(cls.__name__), exception=ex) - - result: Set[Any] = super(CommonImmediateSuperInteraction, inst_or_cls).get_participants(participant_type, sim=sim, target=target, carry_target=carry_target, **kwargs) - - result = set(result) - try: - custom_participants = cls.get_custom_participants(participant_type, sim, target, carry_target, interaction=inst, **kwargs) - result.update(custom_participants) - except Exception as ex: - log.error('Error occurred while running CommonImmediateSuperInteraction \'{}\' get_custom_participants.'.format(cls.__name__), exception=ex) - return tuple(result) - - # noinspection PyMethodParameters,PyMissingOrEmptyDocstring - @flexmethod - def get_name(cls, inst: 'CommonImmediateSuperInteraction', target: Any=DEFAULT, context: InteractionContext=DEFAULT, **interaction_parameters) -> LocalizedString: - inst_or_cls = inst or cls - try: - context_inst_or_cls = context or inst_or_cls - interaction_sim = context_inst_or_cls.sim - interaction_target = target or context_inst_or_cls.target - - cls.get_verbose_log().format_with_message( - 'Running get_name.', - class_name=cls.__name__, - interaction_sim=interaction_sim, - interaction_target=interaction_target, - interaction=inst, - interaction_context=context - ) - override_name = cls._create_override_display_name( - interaction_sim, - interaction_target, - interaction=inst, - interaction_context=context, - **interaction_parameters - ) - if override_name is not None: - return override_name - except Exception as ex: - cls.get_log().error('An error occurred while running get_name of CommonImmediateSuperInteraction {}'.format(cls.__name__), exception=ex) - result = super(CommonImmediateSuperInteraction, inst_or_cls).get_name(target=target, context=context, **interaction_parameters) - if result is None: - cls.get_log().error(f'Missing a name for interaction {cls.__name__}', throw=True) - return result - - def _trigger_interaction_start_event(self: 'CommonImmediateSuperInteraction'): - try: - self.verbose_log.format_with_message( - 'Running on_started.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target - ) - result = self.on_started(self.sim, self.target) - if result is not None and ((isinstance(result, CommonExecutionResult) and not result.is_success) or (isinstance(result, bool) and not result)): - self.cancel(FinishingType.CONDITIONAL_EXIT, str(result)) - return False - return super()._trigger_interaction_start_event() - except Exception as ex: - self.log.error('Error occurred while running CommonImmediateSuperInteraction \'{}\' 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: - self.verbose_log.format_with_message( - 'Running modify_posture_state.', - class_name=self.__class__.__name__, - posture_state=posture_state, - participant_type=participant_type, - sim=sim - ) - (new_posture_state, new_participant_type, new_sim) = self.modify_posture_state(posture_state, participant_type=participant_type, sim=sim) - except Exception as ex: - self.log.error('Error occurred while running CommonImmediateSuperInteraction \'{}\' 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.verbose_log.format_with_message( - 'Running on_killed.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target - ) - self.on_killed(self.sim, self.target) - except Exception as ex: - self.log.error('Error occurred while running CommonImmediateSuperInteraction \'{}\' 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.verbose_log.format_with_message( - 'Running on_cancelled.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target, - finishing_type=finishing_type, - cancel_reason_msg=cancel_reason_msg, - kwargles=kwargs - ) - self.on_cancelled(self.sim, self.target, finishing_type, cancel_reason_msg, **kwargs) - except Exception as ex: - self.log.error('Error occurred while running CommonImmediateSuperInteraction \'{}\' _cancel.'.format(self.__class__.__name__), exception=ex) - return super()._cancel(finishing_type, cancel_reason_msg, **kwargs) - - def on_reset(self: 'CommonImmediateSuperInteraction'): - """on_reset() - - A function that occurs upon an interaction being reset. - - """ - try: - self.verbose_log.format_with_message( - 'Running on_reset.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target - ) - self._on_reset(self.sim, self.target) - except Exception as ex: - self.log.error('Error occurred while running CommonImmediateSuperInteraction \'{}\' on_reset.'.format(self.__class__.__name__), exception=ex) - return super().on_reset() - - def _post_perform(self: 'CommonImmediateSuperInteraction'): - super_result = super()._post_perform() - try: - self.verbose_log.format_with_message( - 'Running on_performed.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target - ) - self.on_performed(self.sim, self.target) - except Exception as ex: - self.log.error('Error occurred while running CommonImmediateSuperInteraction \'{}\' _post_perform.'.format(self.__class__.__name__), exception=ex) - return super_result - - def send_current_progress(self, *args: Any, **kwargs: Any): - """send_current_progress(*args, **kwargs) - - A function that occurs upon a progress bar update. - - """ - try: - self.verbose_log.format_with_message( - 'Running _send_current_progress.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target, - argles=args, - kwargles=kwargs - ) - result = self._send_current_progress(self.sim, self.target, *args, **kwargs) - if result is not None: - return result - except Exception as ex: - self.log.error('Error occurred while running CommonImmediateSuperInteraction \'{}\' 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: - self.verbose_log.format_with_message( - 'Running _setup_asm_default.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target, - asm=asm, - argles=args, - kwargles=kwargs - ) - result = self._setup_asm_default(self.sim, self.target, asm, *args, **kwargs) - if result is not None: - return result - except Exception as ex: - self.log.error('Error occurred while running CommonImmediateSuperInteraction \'{}\' setup_asm_default.'.format(self.__class__.__name__), exception=ex) - return super().setup_asm_default(asm, *args, **kwargs) - - def _run_interaction_gen(self, timeline: Timeline): - try: - self.verbose_log.format_with_message( - 'Running on_run.', - class_name=self.__class__.__name__, - interaction_sim=self.sim, - interaction_target=self.target, - timeline=timeline - ) - self.on_run(self.sim, self.target, timeline) - except Exception as ex: - self.log.error('Error occurred while running CommonImmediateSuperInteraction \'{}\' on_run.'.format(self.__class__.__name__), exception=ex) - yield from super()._run_interaction_gen(timeline) - - # noinspection PyMethodParameters - @flexmethod - def _constraint_gen(cls, inst: 'CommonImmediateSuperInteraction', sim: Sim, target: Any, participant_type: ParticipantType=ParticipantType.Actor, **kwargs) -> Constraint: - inst_or_cls = inst if inst is not None else cls - try: - replacement_results = cls.on_replacement_constraints_gen(inst_or_cls, sim or inst_or_cls.sim, inst_or_cls.get_constraint_target(target) or target or inst_or_cls.target) - if replacement_results is not None: - yield from replacement_results - else: - yield from super(CommonImmediateSuperInteraction, inst_or_cls)._constraint_gen(sim, target, participant_type=participant_type, **kwargs) - result = cls.on_constraint_gen(inst_or_cls, sim or inst_or_cls.sim, inst_or_cls.get_constraint_target(target) or target or inst_or_cls.target) - if result is not None: - if inspect.isgenerator(result): - yield from result - else: - yield result - except Exception as ex: - cls.get_log().error('Error occurred while running CommonImmediateSuperInteraction \'{}\' _on_constraint_gen.'.format(cls.__name__), exception=ex) diff --git a/Scripts/s4ap/sims4communitylib/classes/interactions/common_interaction.py b/Scripts/s4ap/sims4communitylib/classes/interactions/common_interaction.py deleted file mode 100644 index 47d8f01..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/interactions/common_interaction.py +++ /dev/null @@ -1,462 +0,0 @@ -""" -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 -""" -import inspect -from typing import Any, Union, Set - -from event_testing.tests import TestList -from interactions import ParticipantType -from interactions.constraints import Constraint -from interactions.context import InteractionContext -from interactions.interaction_finisher import FinishingType -from native.animation import NativeAsm -from postures.posture_state import PostureState -from protocolbuffers.Localization_pb2 import LocalizedString -from scheduling import Timeline -from sims.sim import Sim -from sims4.utils import flexmethod -from s4ap.sims4communitylib.classes.interactions._common_interaction_custom_mixin import _CommonInteractionCustomMixin -from s4ap.sims4communitylib.classes.interactions._common_interaction_hooks_mixin import _CommonInteractionHooksMixin -from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.logging.has_class_log import HasClassLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from s4ap.sims4communitylib.utils.misc.common_text_utils import CommonTextUtils -from singletons import DEFAULT -from interactions.base.interaction import Interaction - - -class CommonInteraction(Interaction, HasClassLog, _CommonInteractionHooksMixin, _CommonInteractionCustomMixin): - """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:`CommonInteraction` - * :class:`CommonSocialMixerInteraction` - * :class:`CommonSocialSuperInteraction` - * :class:`CommonSuperInteraction` - * :class:`CommonObjectInteraction` - * :class:`CommonTerrainInteraction` - - .. warning:: Due to an issue with how Read The Docs functions, the base classes of this class will have different namespaces in the docs than they do in the source code! - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> Union[CommonModIdentity, None]: - return None - - def __init__(self, *_: Any, **__: Any): - super().__init__(*_, **__) - HasClassLog.__init__(self) - - @classmethod - def _test(cls, inst, target: Any=DEFAULT, context: InteractionContext=DEFAULT, super_interaction: 'Interaction'=None, skip_safe_tests: bool=False, **kwargs) -> CommonTestResult: - from event_testing.results import TestResult - from s4ap.sims4communitylib.classes.time.common_stop_watch import CommonStopWatch - log = cls.get_log() - verbose_log = cls.get_verbose_log() - stop_watch = CommonStopWatch() - if verbose_log.enabled: - stop_watch.start() - try: - inst_or_cls = inst if inst is not None else cls - try: - verbose_log.format_with_message( - 'Running on_test.', - class_name=cls.__name__, - interaction_sim=context.sim, - interaction_target=target, - interaction_context=context, - super_interaction=super_interaction, - skip_safe_tests=skip_safe_tests, - kwargles=kwargs - ) - test_result = cls.on_test(context.sim, target, context, super_interaction=super_interaction, skip_safe_tests=skip_safe_tests, **kwargs) - verbose_log.format_with_message('Test Result (CommonInteraction)', test_result=test_result) - except Exception as ex: - log.error('Error occurred while running CommonInteraction \'{}\' on_test.'.format(cls.__name__), exception=ex) - return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') - - if test_result is not None: - if isinstance(test_result, CommonTestResult): - if test_result.is_success is False: - return test_result - elif isinstance(test_result, TestResult) and 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, icon=test_result.icon, influence_by_active_mood=test_result.influence_by_active_mood) - - try: - verbose_log.format_with_message( - 'Running super()._test.', - class_name=cls.__name__, - interaction_sim=context.sim, - interaction_target=target, - interaction_context=context, - super_interaction=super_interaction, - skip_safe_tests=skip_safe_tests, - kwargles=kwargs - ) - super_test_result: TestResult = super()._test(target, context, super_interaction=super_interaction, skip_safe_tests=skip_safe_tests, **kwargs) - - if verbose_log.enabled: - search_for_tooltip = context.source == context.SOURCE_PIE_MENU - resolver = inst_or_cls.get_resolver(target=target, context=context, super_interaction=super_interaction, search_for_tooltip=search_for_tooltip, **kwargs) - global_result = cls.test_globals.run_tests(resolver, skip_safe_tests, search_for_tooltip=search_for_tooltip) - local_result = cls.tests.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=search_for_tooltip) - if inst_or_cls._additional_tests: - additional_tests = TestList(inst_or_cls._additional_tests) - additional_local_result = additional_tests.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=search_for_tooltip) - else: - additional_local_result = None - if inst_or_cls.test_autonomous: - autonomous_result = cls.test_autonomous.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=False) - else: - autonomous_result = None - if target is not None: - tests = target.get_affordance_tests(inst_or_cls) - if tests is not None: - target_result = tests.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=search_for_tooltip) - else: - target_result = None - else: - target_result = None - verbose_log.format_with_message('Super Test Result (CommonInteraction)', super_test_result=super_test_result, global_result=global_result, local_result=local_result, additional_local_result=additional_local_result, autonomous_result=autonomous_result, target_result=target_result) - - if super_test_result is not None and (isinstance(test_result, TestResult) and not super_test_result.result): - return CommonTestResult.convert_from_vanilla(super_test_result) - except Exception as ex: - log.error('Error occurred while running CommonInteraction \'{}\' super()._test.'.format(cls.__name__), exception=ex) - return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') - - try: - verbose_log.format_with_message( - 'Running on_post_super_test.', - class_name=cls.__name__, - interaction_sim=context.sim, - interaction_target=target, - interaction_context=context, - super_interaction=super_interaction, - skip_safe_tests=skip_safe_tests, - kwargles=kwargs - ) - post_super_test_result = cls.on_post_super_test(context.sim, target, context, super_interaction=super_interaction, skip_safe_tests=skip_safe_tests, **kwargs) - verbose_log.format_with_message('Post Test Result (CommonInteraction)', post_super_test_result=post_super_test_result) - except Exception as ex: - log.error('Error occurred while running CommonInteraction \'{}\' on_post_super_test.'.format(cls.__name__), exception=ex) - return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') - - if post_super_test_result is not None: - if isinstance(post_super_test_result, CommonTestResult): - if post_super_test_result.is_success is False: - return post_super_test_result - elif isinstance(post_super_test_result, TestResult) and post_super_test_result.result is False: - if post_super_test_result.tooltip is not None: - post_super_test_result_tooltip = CommonLocalizationUtils.create_localized_tooltip(post_super_test_result.tooltip) - elif post_super_test_result.reason is not None: - post_super_test_result_tooltip = CommonLocalizationUtils.create_localized_tooltip(post_super_test_result.reason) - else: - post_super_test_result_tooltip = None - return cls.create_test_result(post_super_test_result.result, post_super_test_result.reason, tooltip=post_super_test_result_tooltip, icon=post_super_test_result.icon, influence_by_active_mood=post_super_test_result.influence_by_active_mood) - - return cls.create_test_result(True) - except Exception as ex: - log.error('Error occurred while running _test of CommonInteraction \'{}\''.format(cls.__name__), exception=ex) - return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') - finally: - if verbose_log.enabled: - time_taken = CommonTextUtils.to_truncated_decimal(stop_watch.stop_milliseconds()) - verbose_log.format_with_message(f'Took {time_taken}ms to return result from CommonInteraction.', class_name=cls.__name__) - else: - stop_watch.stop() - - # noinspection PyMissingOrEmptyDocstring,PyMethodParameters - @flexmethod - def get_participants(cls, inst, participant_type: ParticipantType, sim: Sim=DEFAULT, target: Any=DEFAULT, carry_target: Any=DEFAULT, **kwargs): - inst_or_cls = inst or cls - log = cls.get_log() - try: - custom_participants = cls.get_custom_replacement_participants(participant_type, sim, target, carry_target, interaction=inst, **kwargs) - if custom_participants is not None: - return tuple(custom_participants) - except Exception as ex: - log.error('Error occurred while running CommonInteraction \'{}\' get_custom_replacement_participants.'.format(cls.__name__), exception=ex) - - result: Set[Any] = super(CommonInteraction, inst_or_cls).get_participants(participant_type, sim=sim, target=target, carry_target=carry_target, **kwargs) - - result = set(result) - try: - custom_participants = cls.get_custom_participants(participant_type, sim, target, carry_target, interaction=inst, **kwargs) - result.update(custom_participants) - except Exception as ex: - log.error('Error occurred while running CommonInteraction \'{}\' get_custom_participants.'.format(cls.__name__), exception=ex) - return tuple(result) - - # noinspection PyMethodParameters,PyMissingOrEmptyDocstring - @flexmethod - def get_name(cls, inst: 'CommonInteraction', target: Any=DEFAULT, context: InteractionContext=DEFAULT, **interaction_parameters) -> LocalizedString: - inst_or_cls = inst or cls - try: - context_inst_or_cls = context or inst_or_cls - interaction_sim = context_inst_or_cls.sim - interaction_target = target or context_inst_or_cls.target - - cls.get_verbose_log().format_with_message( - 'Running get_name.', - class_name=cls.__name__, - interaction_sim=interaction_sim, - interaction_target=interaction_target, - interaction=inst, - interaction_context=context - ) - override_name = cls._create_override_display_name( - interaction_sim, - interaction_target, - interaction=inst, - interaction_context=context, - **interaction_parameters - ) - if override_name is not None: - return override_name - except Exception as ex: - cls.get_log().error('An error occurred while running get_name of CommonInteraction {}'.format(cls.__name__), exception=ex) - result = super(CommonInteraction, inst_or_cls).get_name(target=target, context=context, **interaction_parameters) - if result is None: - cls.get_log().error(f'Missing a name for interaction {cls.__name__}', throw=True) - return result - - def _trigger_interaction_start_event(self: 'CommonInteraction'): - try: - self.verbose_log.format_with_message( - 'Running on_started.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target - ) - result = self.on_started(self.sim, self.target) - if result is not None and ((isinstance(result, CommonExecutionResult) and not result.is_success) or (isinstance(result, bool) and not result)): - self.cancel(FinishingType.CONDITIONAL_EXIT, str(result)) - return False - return super()._trigger_interaction_start_event() - except Exception as ex: - self.log.error('Error occurred while running CommonInteraction \'{}\' 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: - self.verbose_log.format_with_message( - 'Running modify_posture_state.', - class_name=self.__class__.__name__, - posture_state=posture_state, - participant_type=participant_type, - sim=sim - ) - (new_posture_state, new_participant_type, new_sim) = self.modify_posture_state(posture_state, participant_type=participant_type, sim=sim) - except Exception as ex: - self.log.error('Error occurred while running CommonInteraction \'{}\' 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.verbose_log.format_with_message( - 'Running on_killed.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target - ) - self.on_killed(self.sim, self.target) - except Exception as ex: - self.log.error('Error occurred while running CommonInteraction \'{}\' 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.verbose_log.format_with_message( - 'Running on_cancelled.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target, - finishing_type=finishing_type, - cancel_reason_msg=cancel_reason_msg, - kwargles=kwargs - ) - self.on_cancelled(self.sim, self.target, finishing_type, cancel_reason_msg, **kwargs) - except Exception as ex: - self.log.error('Error occurred while running CommonInteraction \'{}\' cancel.'.format(self.__class__.__name__), exception=ex) - return super().cancel(finishing_type, cancel_reason_msg, **kwargs) - - def on_reset(self: 'CommonInteraction'): - """on_reset() - - A function that occurs upon an interaction being reset. - - """ - try: - self.verbose_log.format_with_message( - 'Running on_reset.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target - ) - self._on_reset(self.sim, self.target) - except Exception as ex: - self.log.error('Error occurred while running CommonInteraction \'{}\' on_reset.'.format(self.__class__.__name__), exception=ex) - return super().on_reset() - - def _post_perform(self: 'CommonInteraction'): - super_result = super()._post_perform() - try: - self.verbose_log.format_with_message( - 'Running on_performed.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target - ) - self.on_performed(self.sim, self.target) - except Exception as ex: - self.log.error('Error occurred while running CommonInteraction \'{}\' _post_perform.'.format(self.__class__.__name__), exception=ex) - return super_result - - def send_current_progress(self, *args: Any, **kwargs: Any): - """send_current_progress(*args, **kwargs) - - A function that occurs upon a progress bar update. - - """ - try: - self.verbose_log.format_with_message( - 'Running _send_current_progress.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target, - argles=args, - kwargles=kwargs - ) - result = self._send_current_progress(self.sim, self.target, *args, **kwargs) - if result is not None: - return result - except Exception as ex: - self.log.error('Error occurred while running CommonInteraction \'{}\' 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: - self.verbose_log.format_with_message( - 'Running _setup_asm_default.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target, - asm=asm, - argles=args, - kwargles=kwargs - ) - result = self._setup_asm_default(self.sim, self.target, asm, *args, **kwargs) - if result is not None: - return result - except Exception as ex: - self.log.error('Error occurred while running CommonInteraction \'{}\' setup_asm_default.'.format(self.__class__.__name__), exception=ex) - return super().setup_asm_default(asm, *args, **kwargs) - - def _run_interaction_gen(self, timeline: Timeline): - try: - self.verbose_log.format_with_message( - 'Running on_run.', - class_name=self.__class__.__name__, - interaction_sim=self.sim, - interaction_target=self.target, - timeline=timeline - ) - self.on_run(self.sim, self.target, timeline) - except Exception as ex: - self.log.error('Error occurred while running CommonInteraction \'{}\' on_run.'.format(self.__class__.__name__), exception=ex) - yield from super()._run_interaction_gen(timeline) - - @classmethod - def _constraint_gen(cls, sim: Sim, target: Any, participant_type: ParticipantType=ParticipantType.Actor, interaction: 'CommonInteraction'=None) -> Constraint: - inst_or_cls = interaction if interaction is not None else cls - try: - replacement_results = cls.on_replacement_constraints_gen(inst_or_cls, sim or inst_or_cls.sim, inst_or_cls.get_constraint_target(target) or target or inst_or_cls.target) - if replacement_results is not None: - if inspect.isgenerator(replacement_results): - yield from replacement_results - else: - yield replacement_results - else: - yield from super()._constraint_gen(sim, target, participant_type=participant_type, interaction=interaction) - result = cls.on_constraint_gen(inst_or_cls, sim or inst_or_cls.sim, inst_or_cls.get_constraint_target(target) or target or inst_or_cls.target) - if result is not None: - if inspect.isgenerator(result): - yield from result - else: - yield result - except Exception as ex: - cls.get_log().error('Error occurred while running CommonInteraction \'{}\' _on_constraint_gen.'.format(cls.__name__), exception=ex) - - -# The following is an example interaction that varies when it will display, when it will be hidden, and when it will be disabled with a tooltip. -class _ExampleInteraction(CommonInteraction): - # noinspection PyMissingOrEmptyDocstring - @classmethod - def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, *args, **kwargs) -> CommonTestResult: - result = 1 + 1 - if result == 2: - # Interaction will be displayed, but disabled, it will also have a tooltip that displays on hover with the text "Test Tooltip" - return cls.create_test_result(False, reason="Test Tooltip") - # Alternative way to specify a tooltip with the text "Test Tooltip" - # return cls.create_test_result(False, reason="No Reason", tooltip=CommonLocalizationUtils.create_localized_tooltip("Test Tooltip")) - if result == 3: - # Interaction will be hidden completely. - return CommonTestResult.NONE - # Interaction will display and be enabled. - return CommonTestResult.TRUE - - # noinspection PyMissingOrEmptyDocstring - def on_started(self, interaction_sim: Sim, interaction_target: Any) -> CommonExecutionResult: - result = True - if not result: - return CommonExecutionResult.FALSE - # Put here what you want the interaction to do as soon as the player clicks it while it is enabled. - return CommonExecutionResult.TRUE diff --git a/Scripts/s4ap/sims4communitylib/classes/interactions/common_interaction_override_name.py b/Scripts/s4ap/sims4communitylib/classes/interactions/common_interaction_override_name.py deleted file mode 100644 index c833425..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/interactions/common_interaction_override_name.py +++ /dev/null @@ -1,89 +0,0 @@ -""" -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 -""" -from typing import Any, Union - -from interactions.base.interaction import Interaction -from interactions.context import InteractionContext -from protocolbuffers.Localization_pb2 import LocalizedString -from sims.sim import Sim -from sims4.utils import flexmethod -from s4ap.sims4communitylib.logging.has_class_log import HasClassLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity - - -class CommonInteractionOverrideName(HasClassLog): - """CommonInteractionOverrideName() - - An inheritable class that provides a way to override the :func:`~get_name` function of :class:`.CommonInteraction`. - - .. warning:: This class is obsolete. All interaction types come with their own :func:`~get_name` function. This class is to be used in conjunction with :class:`.CommonInteraction`. Inheriting from this class will do nothing for class that does not also inherit from :class:`.CommonInteraction`. - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> Union[CommonModIdentity, None]: - return None - - def __init__(self) -> None: - super().__init__() - HasClassLog.__init__(self) - - # noinspection PyMethodParameters,PyMissingOrEmptyDocstring - @flexmethod - def get_name(cls, inst: Interaction, target: Any=None, context: InteractionContext=None, **interaction_parameters) -> LocalizedString: - inst_or_cls = inst or cls - try: - context_inst_or_cls = context or inst_or_cls - interaction_sim = context_inst_or_cls.sim - interaction_target = target or context_inst_or_cls.target - - cls.get_verbose_log().format_with_message( - 'Creating display name.', - class_name=cls.__name__, - interaction_sim=interaction_sim, - interaction_target=interaction_target, - interaction=inst, - interaction_context=context - ) - override_name = cls._create_display_name( - interaction_sim, - interaction_target, - interaction=inst, - interaction_context=context, - **interaction_parameters - ) - if override_name is not None: - return override_name - except Exception as ex: - cls.get_log().error('An error occurred while running get_name of CommonInteractionOverrideName {}'.format(cls.__name__), exception=ex) - result = super(Interaction, inst_or_cls).get_name(target=target, context=context, **interaction_parameters) - if result is None: - cls.get_log().error(f'Missing a name for interaction {cls.__name__}', throw=True) - return result - - # noinspection PyUnusedLocal - @classmethod - def _create_display_name(cls, interaction_sim: Sim, interaction_target: Any, interaction: Union[Interaction, None]=None, interaction_context: Union[InteractionContext, None]=None, **interaction_parameters) -> Union[LocalizedString, None]: - """_create_display_name(interaction_sim, interaction_target, interaction=None, interaction_context=None, **interaction_parameters) - - A hook that allows using a custom display name for an Interaction. - - :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: An instance of an interaction or None if no instance of the interaction is available. Default is None. - :type interaction: Union[Interaction, None], optional - :param interaction_context: The context of the interaction or None if no interaction context is available. Default is None. - :type interaction_context: Union[InteractionContext, None], optional - :param interaction_parameters: Extra interaction parameters. - :type interaction_parameters: Any - :return: A Localized String to display for the interaction or None if the original display name should be used. - :rtype: Union[LocalizedString, None] - """ - raise NotImplementedError() diff --git a/Scripts/s4ap/sims4communitylib/classes/interactions/common_mixer_interaction.py b/Scripts/s4ap/sims4communitylib/classes/interactions/common_mixer_interaction.py deleted file mode 100644 index e651dbc..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/interactions/common_mixer_interaction.py +++ /dev/null @@ -1,460 +0,0 @@ -""" -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 -""" -import inspect -from typing import Union, Any, Set - -from event_testing.tests import TestList -from interactions import ParticipantType -from interactions.base.interaction import Interaction -from interactions.constraints import Constraint -from interactions.context import InteractionContext -from interactions.interaction_finisher import FinishingType -from native.animation import NativeAsm -from postures.posture_state import PostureState -from protocolbuffers.Localization_pb2 import LocalizedString -from scheduling import Timeline -from sims.sim import Sim -from sims4.utils import flexmethod -from s4ap.sims4communitylib.classes.interactions._common_interaction_custom_mixin import _CommonInteractionCustomMixin -from s4ap.sims4communitylib.classes.interactions._common_interaction_hooks_mixin import _CommonInteractionHooksMixin -from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.logging.has_class_log import HasClassLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from s4ap.sims4communitylib.utils.misc.common_text_utils import CommonTextUtils -from singletons import DEFAULT -from interactions.base.mixer_interaction import MixerInteraction - - -class CommonMixerInteraction(MixerInteraction, HasClassLog, _CommonInteractionHooksMixin, _CommonInteractionCustomMixin): - """CommonMixerInteraction(*_, **__) - - An inheritable class that provides a way to create Custom Mixer Interactions. - - .. 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! - - :Example: - - .. highlight:: python - .. code-block:: python - - # The following is an example interaction that varies when it will display, when it will be hidden, and when it will be disabled with a tooltip. - class _ExampleInteraction(CommonMixerInteraction): - @classmethod - def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, **kwargs) -> CommonTestResult: - result = 1 + 1 - if result == 2: - # Interaction will be displayed, but disabled, it will also have a tooltip that displays on hover with the text "Test Tooltip" - return cls.create_test_result(False, reason="Test Tooltip") - # Alternative way to specify a tooltip with the text "Test Tooltip" - # return cls.create_test_result(False, reason="No Reason", tooltip=CommonLocalizationUtils.create_localized_tooltip("Test Tooltip")) - if result == 3: - # Interaction will be hidden completely. - return CommonTestResult.NONE - # Interaction will display and be enabled. - return CommonTestResult.TRUE - - def on_started(self, interaction_sim: Sim, interaction_target: Any) -> CommonExecutionResult: - result = True - if not result: - return CommonExecutionResult.FALSE - # Put here what you want the interaction to do as soon as the player clicks it while it is enabled. - return CommonExecutionResult.TRUE - - def on_cancelled(self, interaction_sim: Sim, interaction_target: Any, finishing_type: FinishingType, cancel_reason_msg: str, **kwargs): - result = True - if not result: - return False - # Put here what you want the interaction to do as soon as the player clicks it while it is enabled. - return True - - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> Union[CommonModIdentity, None]: - return None - - def __init__(self, *_: Any, **__: Any): - super().__init__(*_, **__) - HasClassLog.__init__(self) - - @classmethod - def _test(cls, target: Any, context: InteractionContext, super_interaction: 'Interaction'=None, skip_safe_tests: bool=False, **kwargs) -> CommonTestResult: - from event_testing.results import TestResult - from s4ap.sims4communitylib.classes.time.common_stop_watch import CommonStopWatch - log = cls.get_log() - verbose_log = cls.get_verbose_log() - stop_watch = CommonStopWatch() - if verbose_log.enabled: - stop_watch.start() - try: - try: - verbose_log.format_with_message( - 'Running on_test.', - class_name=cls.__name__, - interaction_sim=context.sim, - interaction_target=target, - interaction_context=context, - super_interaction=super_interaction, - skip_safe_tests=skip_safe_tests, - kwargles=kwargs - ) - test_result = cls.on_test(context.sim, target, context, super_interaction=super_interaction, skip_safe_tests=skip_safe_tests, **kwargs) - verbose_log.format_with_message('Test Result (CommonMixerInteraction)', test_result=test_result) - except Exception as ex: - log.error('Error occurred while running CommonMixerInteraction \'{}\' on_test.'.format(cls.__name__), exception=ex) - return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') - - if test_result is not None: - if isinstance(test_result, CommonTestResult): - if test_result.is_success is False: - return test_result - elif isinstance(test_result, TestResult) and 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, icon=test_result.icon, influence_by_active_mood=test_result.influence_by_active_mood) - - try: - verbose_log.format_with_message( - 'Running super()._test.', - class_name=cls.__name__, - interaction_sim=context.sim, - interaction_target=target, - interaction_context=context, - super_interaction=super_interaction, - skip_safe_tests=skip_safe_tests, - kwargles=kwargs - ) - super_test_result: TestResult = super()._test(target, context, super_interaction=super_interaction, skip_safe_tests=skip_safe_tests, **kwargs) - - if verbose_log.enabled: - search_for_tooltip = context.source == context.SOURCE_PIE_MENU - resolver = cls.get_resolver(target=target, context=context, super_interaction=super_interaction, search_for_tooltip=search_for_tooltip, **kwargs) - global_result = cls.test_globals.run_tests(resolver, skip_safe_tests, search_for_tooltip=search_for_tooltip) - local_result = cls.tests.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=search_for_tooltip) - if cls._additional_tests: - additional_tests = TestList(cls._additional_tests) - additional_local_result = additional_tests.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=search_for_tooltip) - else: - additional_local_result = None - if cls.test_autonomous: - autonomous_result = cls.test_autonomous.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=False) - else: - autonomous_result = None - if target is not None: - tests = target.get_affordance_tests(cls) - if tests is not None: - target_result = tests.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=search_for_tooltip) - else: - target_result = None - else: - target_result = None - verbose_log.format_with_message('Super Test Result (CommonMixerInteraction)', super_test_result=super_test_result, global_result=global_result, local_result=local_result, additional_local_result=additional_local_result, autonomous_result=autonomous_result, target_result=target_result) - - if super_test_result is not None and (isinstance(test_result, TestResult) and not super_test_result.result): - return CommonTestResult.convert_from_vanilla(super_test_result) - except Exception as ex: - log.error('Error occurred while running CommonMixerInteraction \'{}\' super()._test.'.format(cls.__name__), exception=ex) - return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') - - try: - verbose_log.format_with_message( - 'Running on_post_super_test.', - class_name=cls.__name__, - interaction_sim=context.sim, - interaction_target=target, - interaction_context=context, - super_interaction=super_interaction, - skip_safe_tests=skip_safe_tests, - kwargles=kwargs - ) - post_super_test_result = cls.on_post_super_test(context.sim, target, context, super_interaction=super_interaction, skip_safe_tests=skip_safe_tests, **kwargs) - verbose_log.format_with_message('Post Test Result (CommonMixerInteraction)', post_super_test_result=post_super_test_result) - except Exception as ex: - log.error('Error occurred while running CommonMixerInteraction \'{}\' on_post_super_test.'.format(cls.__name__), exception=ex) - return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') - - if post_super_test_result is not None: - if isinstance(post_super_test_result, CommonTestResult): - if post_super_test_result.is_success is False: - return post_super_test_result - elif isinstance(post_super_test_result, TestResult) and post_super_test_result.result is False: - if post_super_test_result.tooltip is not None: - post_super_test_result_tooltip = CommonLocalizationUtils.create_localized_tooltip(post_super_test_result.tooltip) - elif post_super_test_result.reason is not None: - post_super_test_result_tooltip = CommonLocalizationUtils.create_localized_tooltip(post_super_test_result.reason) - else: - post_super_test_result_tooltip = None - return cls.create_test_result(post_super_test_result.result, post_super_test_result.reason, tooltip=post_super_test_result_tooltip, icon=post_super_test_result.icon, influence_by_active_mood=post_super_test_result.influence_by_active_mood) - - return cls.create_test_result(True) - except Exception as ex: - log.error('Error occurred while running _test of CommonMixerInteraction \'{}\''.format(cls.__name__), exception=ex) - return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') - finally: - if verbose_log.enabled: - time_taken = CommonTextUtils.to_truncated_decimal(stop_watch.stop_milliseconds()) - verbose_log.format_with_message(f'Took {time_taken}ms to return result from CommonMixerInteraction.', class_name=cls.__name__) - else: - stop_watch.stop() - - # noinspection PyMissingOrEmptyDocstring,PyMethodParameters - @flexmethod - def get_participants(cls, inst, participant_type:ParticipantType, sim=DEFAULT, target=DEFAULT, carry_target=DEFAULT, **kwargs): - inst_or_cls = inst or cls - log = cls.get_log() - try: - custom_participants = cls.get_custom_replacement_participants(participant_type, sim, target, carry_target, interaction=inst, **kwargs) - if custom_participants is not None: - return tuple(custom_participants) - except Exception as ex: - log.error('Error occurred while running CommonMixerInteraction \'{}\' get_custom_replacement_participants.'.format(cls.__name__), exception=ex) - - result: Set[Any] = super(CommonMixerInteraction, inst_or_cls).get_participants(participant_type, sim=sim, target=target, carry_target=carry_target, **kwargs) - - result = set(result) - try: - custom_participants = cls.get_custom_participants(participant_type, sim, target, carry_target, interaction=inst, **kwargs) - result.update(custom_participants) - except Exception as ex: - log.error('Error occurred while running CommonMixerInteraction \'{}\' get_custom_participants.'.format(cls.__name__), exception=ex) - return tuple(result) - - # noinspection PyMethodParameters,PyMissingOrEmptyDocstring - @flexmethod - def get_name(cls, inst: 'CommonMixerInteraction', target: Any=DEFAULT, context: InteractionContext=DEFAULT, **interaction_parameters) -> LocalizedString: - inst_or_cls = inst or cls - try: - context_inst_or_cls = context or inst_or_cls - interaction_sim = context_inst_or_cls.sim - interaction_target = target or context_inst_or_cls.target - - cls.get_verbose_log().format_with_message( - 'Running get_name.', - class_name=cls.__name__, - interaction_sim=interaction_sim, - interaction_target=interaction_target, - interaction=inst, - interaction_context=context - ) - override_name = cls._create_override_display_name( - interaction_sim, - interaction_target, - interaction=inst, - interaction_context=context, - **interaction_parameters - ) - if override_name is not None: - return override_name - except Exception as ex: - cls.get_log().error('An error occurred while running get_name of CommonMixerInteraction {}'.format(cls.__name__), exception=ex) - result = super(CommonMixerInteraction, inst_or_cls).get_name(target=target, context=context, **interaction_parameters) - if result is None: - cls.get_log().error(f'Missing a name for interaction {cls.__name__}', throw=True) - return result - - def _trigger_interaction_start_event(self: 'CommonMixerInteraction'): - try: - self.verbose_log.format_with_message( - 'Running on_started.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target - ) - result = self.on_started(self.sim, self.target) - if result is not None and ((isinstance(result, CommonExecutionResult) and not result.is_success) or (isinstance(result, bool) and not result)): - self.cancel(FinishingType.CONDITIONAL_EXIT, str(result)) - return False - return super()._trigger_interaction_start_event() - except Exception as ex: - self.log.error('Error occurred while running CommonMixerInteraction \'{}\' 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: - self.verbose_log.format_with_message( - 'Running modify_posture_state.', - class_name=self.__class__.__name__, - posture_state=posture_state, - participant_type=participant_type, - sim=sim - ) - (new_posture_state, new_participant_type, new_sim) = self.modify_posture_state(posture_state, participant_type=participant_type, sim=sim) - except Exception as ex: - self.log.error('Error occurred while running CommonMixerInteraction \'{}\' 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.verbose_log.format_with_message( - 'Running on_killed.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target - ) - self.on_killed(self.sim, self.target) - except Exception as ex: - self.log.error('Error occurred while running CommonMixerInteraction \'{}\' 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.verbose_log.format_with_message( - 'Running on_cancelled.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target, - finishing_type=finishing_type, - cancel_reason_msg=cancel_reason_msg, - kwargles=kwargs - ) - self.on_cancelled(self.sim, self.target, finishing_type, cancel_reason_msg, **kwargs) - except Exception as ex: - self.log.error('Error occurred while running CommonMixerInteraction \'{}\' cancel.'.format(self.__class__.__name__), exception=ex) - return super().cancel(finishing_type, cancel_reason_msg, **kwargs) - - def on_reset(self: 'CommonMixerInteraction'): - """on_reset() - - A function that occurs upon an interaction being reset. - - """ - try: - self.verbose_log.format_with_message( - 'Running on_reset.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target - ) - self._on_reset(self.sim, self.target) - except Exception as ex: - self.log.error('Error occurred while running CommonMixerInteraction \'{}\' on_reset.'.format(self.__class__.__name__), exception=ex) - return super().on_reset() - - def _post_perform(self: 'CommonMixerInteraction'): - super_result = super()._post_perform() - try: - self.verbose_log.format_with_message( - 'Running on_performed.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target - ) - self.on_performed(self.sim, self.target) - except Exception as ex: - self.log.error('Error occurred while running CommonMixerInteraction \'{}\' _post_perform.'.format(self.__class__.__name__), exception=ex) - return super_result - - def send_current_progress(self, *args: Any, **kwargs: Any): - """send_current_progress(*args, **kwargs) - - A function that occurs upon a progress bar update. - - """ - try: - self.verbose_log.format_with_message( - 'Running _send_current_progress.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target, - argles=args, - kwargles=kwargs - ) - result = self._send_current_progress(self.sim, self.target, *args, **kwargs) - if result is not None: - return result - except Exception as ex: - self.log.error('Error occurred while running CommonMixerInteraction \'{}\' 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: - self.verbose_log.format_with_message( - 'Running _setup_asm_default.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target, - asm=asm, - argles=args, - kwargles=kwargs - ) - result = self._setup_asm_default(self.sim, self.target, asm, *args, **kwargs) - if result is not None: - return result - except Exception as ex: - self.log.error('Error occurred while running CommonMixerInteraction \'{}\' setup_asm_default.'.format(self.__class__.__name__), exception=ex) - return super().setup_asm_default(asm, *args, **kwargs) - - def _run_interaction_gen(self, timeline: Timeline): - try: - self.verbose_log.format_with_message( - 'Running on_run.', - class_name=self.__class__.__name__, - interaction_sim=self.sim, - interaction_target=self.target, - timeline=timeline - ) - self.on_run(self.sim, self.target, timeline) - except Exception as ex: - self.log.error('Error occurred while running CommonMixerInteraction \'{}\' on_run.'.format(self.__class__.__name__), exception=ex) - yield from super()._run_interaction_gen(timeline) - - @classmethod - def _constraint_gen(cls, sim: Sim, target: Any, participant_type: ParticipantType=ParticipantType.Actor, interaction: 'CommonMixerInteraction'=None) -> Constraint: - inst_or_cls = interaction if interaction is not None else cls - try: - replacement_results = cls.on_replacement_constraints_gen(inst_or_cls, sim or inst_or_cls.sim, inst_or_cls.get_constraint_target(target) or target or inst_or_cls.target) - if replacement_results is not None: - if inspect.isgenerator(replacement_results): - yield from replacement_results - else: - yield replacement_results - else: - yield from super()._constraint_gen(sim, target, participant_type=participant_type, interaction=interaction) - result = cls.on_constraint_gen(inst_or_cls, sim or inst_or_cls.sim, inst_or_cls.get_constraint_target(target) or target or inst_or_cls.target) - if result is not None: - if inspect.isgenerator(result): - yield from result - else: - yield result - except Exception as ex: - cls.get_log().error('Error occurred while running CommonMixerInteraction \'{}\' _on_constraint_gen.'.format(cls.__name__), exception=ex) diff --git a/Scripts/s4ap/sims4communitylib/classes/interactions/common_object_interaction.py b/Scripts/s4ap/sims4communitylib/classes/interactions/common_object_interaction.py deleted file mode 100644 index e31f012..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/interactions/common_object_interaction.py +++ /dev/null @@ -1,77 +0,0 @@ -""" -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 -""" -from typing import Any - -from interactions.context import InteractionContext -from sims.sim import Sim -from s4ap.sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction -from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult - - -class CommonObjectInteraction(CommonImmediateSuperInteraction): - """CommonObjectInteraction(*_, **__) - - An inheritable class that provides a way to create custom Object Interactions. - - .. 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! - - :Example: - - .. highlight:: python - .. code-block:: python - - class _ExampleObjectInteraction(CommonObjectInteraction): - @classmethod - def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, **kwargs) -> CommonTestResult: - result = 1 + 1 - if result == 2: - # Interaction will be displayed, but disabled, it will also have a tooltip that displays on hover with the text "Test Tooltip" - return cls.create_test_result(False, reason="Test Tooltip") - # Alternative way to specify a tooltip with the text "Test Tooltip" - # return cls.create_test_result(False, reason="No Reason", tooltip=CommonLocalizationUtils.create_localized_tooltip("Test Tooltip")) - if result == 3: - # Interaction will be hidden completely. - return CommonTestResult.NONE - # Interaction will display and be enabled. - return CommonTestResult.TRUE - - def on_started(self, interaction_sim: Sim, interaction_target: Any) -> CommonExecutionResult: - result = True - if not result: - return CommonExecutionResult.FALSE - # Put here what you want the interaction to do as soon as the player clicks it while it is enabled. - return CommonExecutionResult.TRUE - """ - pass - - -# The following is an example interaction that varies when it will display, when it will be hidden, and when it will be disabled with a tooltip. -class _ExampleObjectInteraction(CommonObjectInteraction): - # noinspection PyMissingOrEmptyDocstring - @classmethod - def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, **kwargs) -> CommonTestResult: - result = 1 + 1 - if result == 2: - # Interaction will be displayed, but disabled, it will also have a tooltip that displays on hover with the text "Test Tooltip" - return cls.create_test_result(False, reason="Test Tooltip") - # Alternative way to specify a tooltip with the text "Test Tooltip" - # return cls.create_test_result(False, reason="No Reason", tooltip=CommonLocalizationUtils.create_localized_tooltip("Test Tooltip")) - if result == 3: - # Interaction will be hidden completely. - return CommonTestResult.NONE - # Interaction will display and be enabled. - return CommonTestResult.TRUE - - # noinspection PyMissingOrEmptyDocstring - def on_started(self, interaction_sim: Sim, interaction_target: Any) -> CommonExecutionResult: - result = True - if not result: - return CommonExecutionResult.FALSE - # Put here what you want the interaction to do as soon as the player clicks it while it is enabled. - return CommonExecutionResult.TRUE diff --git a/Scripts/s4ap/sims4communitylib/classes/interactions/common_social_mixer_interaction.py b/Scripts/s4ap/sims4communitylib/classes/interactions/common_social_mixer_interaction.py deleted file mode 100644 index bf6cf0f..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/interactions/common_social_mixer_interaction.py +++ /dev/null @@ -1,466 +0,0 @@ -""" -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 -""" -import inspect - -from event_testing.tests import TestList -from interactions.base.interaction import Interaction -from postures.posture_state import PostureState -from s4ap.sims4communitylib.classes.interactions._common_interaction_custom_mixin import _CommonInteractionCustomMixin -from s4ap.sims4communitylib.classes.interactions._common_interaction_hooks_mixin import _CommonInteractionHooksMixin -from s4ap.sims4communitylib.utils.misc.common_text_utils import CommonTextUtils -from singletons import DEFAULT -from typing import Any, Union, Tuple, Set - -from interactions import ParticipantType -from interactions.constraints import Constraint -from interactions.context import InteractionContext -from interactions.interaction_finisher import FinishingType -from native.animation import NativeAsm -from protocolbuffers.Localization_pb2 import LocalizedString -from scheduling import Timeline -from sims.sim import Sim -from sims4.utils import flexmethod -from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.logging.has_class_log import HasClassLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from interactions.social.social_mixer_interaction import SocialMixerInteraction - - -class CommonSocialMixerInteraction(SocialMixerInteraction, HasClassLog, _CommonInteractionHooksMixin, _CommonInteractionCustomMixin): - """CommonSocialMixerInteraction(*_, **__) - - An inheritable class that provides a way to create Custom Social Mixer Interactions. - - .. note:: The main use for this class is to create interactions that involve two or more Sims interacting with each other. - - .. 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! - - :Example: - - .. highlight:: python - .. code-block:: python - - # The following is an example interaction that varies when it will display, when it will be hidden, and when it will be disabled with a tooltip. - class _ExampleInteraction(CommonSocialMixerInteraction): - @classmethod - def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, *args, **kwargs) -> TestResult: - result = 1 + 1 - if result == 2: - # Interaction will be displayed, but disabled, it will also have a tooltip that displays on hover with the text "Test Tooltip" - return cls.create_test_result(False, reason="Test Tooltip") - # Alternative way to specify a tooltip with the text "Test Tooltip" - # return cls.create_test_result(False, reason="No Reason", tooltip=CommonLocalizationUtils.create_localized_tooltip("Test Tooltip")) - if result == 3: - # Interaction will be hidden completely. - return CommonTestResult.NONE - # Interaction will display and be enabled. - return CommonTestResult.TRUE - - def on_started(self, interaction_sim: Sim, interaction_target: Any) -> CommonExecutionResult: - result = True - if not result: - return CommonExecutionResult.FALSE - # Put here what you want the interaction to do as soon as the player clicks it while it is enabled. - return CommonExecutionResult.TRUE - - def on_cancelled(self, interaction_sim: Sim, interaction_target: Any, finishing_type: FinishingType, cancel_reason_msg: str, **kwargs): - result = True - if not result: - return False - # Put here what you want the interaction to do as soon as the player clicks it while it is enabled. - return True - - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> Union[CommonModIdentity, None]: - return None - - def __init__(self, *_: Any, **__: Any): - super().__init__(*_, **__) - HasClassLog.__init__(self) - - # SocialMixerInteraction has a different signature for its _test function, so we override it in here. - @classmethod - def _test(cls, target: Any, context: InteractionContext, *args, super_interaction: 'Interaction'=None, skip_safe_tests: bool=False, **kwargs) -> CommonTestResult: - from event_testing.results import TestResult - from s4ap.sims4communitylib.classes.time.common_stop_watch import CommonStopWatch - log = cls.get_log() - verbose_log = cls.get_verbose_log() - stop_watch = CommonStopWatch() - stop_watch.start() - try: - try: - verbose_log.format_with_message( - 'Running on_test.', - class_name=cls.__name__, - interaction_sim=context.sim, - interaction_target=target, - interaction_context=context, - super_interaction=super_interaction, - skip_safe_tests=skip_safe_tests, - argles=args, - kwargles=kwargs - ) - test_result = cls.on_test(context.sim, target, context, *args, super_interaction=super_interaction, skip_safe_tests=skip_safe_tests, **kwargs) - verbose_log.format_with_message('Test Result (CommonSocialMixerInteraction)', test_result=test_result) - except Exception as ex: - log.error('Error occurred while running CommonSocialMixerInteraction \'{}\' on_test.'.format(cls.__name__), exception=ex) - return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') - - if test_result is not None: - if isinstance(test_result, CommonTestResult): - if test_result.is_success is False: - return test_result - elif isinstance(test_result, TestResult) and 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, icon=test_result.icon, influence_by_active_mood=test_result.influence_by_active_mood) - - try: - verbose_log.format_with_message( - 'Running super()._test.', - class_name=cls.__name__, - interaction_sim=context.sim, - interaction_target=target, - interaction_context=context, - super_interaction=super_interaction, - skip_safe_tests=skip_safe_tests, - argles=args, - kwargles=kwargs - ) - super_test_result: TestResult = super()._test(target, context, *args, super_interaction=super_interaction, skip_safe_tests=skip_safe_tests, **kwargs) - - if verbose_log.enabled: - search_for_tooltip = context.source == context.SOURCE_PIE_MENU - resolver = cls.get_resolver(target=target, context=context, super_interaction=super_interaction, search_for_tooltip=search_for_tooltip, **kwargs) - global_result = cls.test_globals.run_tests(resolver, skip_safe_tests, search_for_tooltip=search_for_tooltip) - local_result = cls.tests.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=search_for_tooltip) - if cls._additional_tests: - additional_tests = TestList(cls._additional_tests) - additional_local_result = additional_tests.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=search_for_tooltip) - else: - additional_local_result = None - if cls.test_autonomous: - autonomous_result = cls.test_autonomous.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=False) - else: - autonomous_result = None - if target is not None: - tests = target.get_affordance_tests(cls) - if tests is not None: - target_result = tests.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=search_for_tooltip) - else: - target_result = None - else: - target_result = None - verbose_log.format_with_message('Super Test Result (CommonSocialMixerInteraction)', super_test_result=super_test_result, global_result=global_result, local_result=local_result, additional_local_result=additional_local_result, autonomous_result=autonomous_result, target_result=target_result) - - if super_test_result is not None and (isinstance(test_result, TestResult) and not super_test_result.result): - return CommonTestResult.convert_from_vanilla(super_test_result) - except Exception as ex: - log.error('Error occurred while running CommonSocialMixerInteraction \'{}\' super()._test.'.format(cls.__name__), exception=ex) - return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') - - try: - verbose_log.format_with_message( - 'Running on_post_super_test.', - class_name=cls.__name__, - interaction_sim=context.sim, - interaction_target=target, - interaction_context=context, - super_interaction=super_interaction, - skip_safe_tests=skip_safe_tests, - argles=args, - kwargles=kwargs - ) - post_super_test_result = cls.on_post_super_test(context.sim, target, context, *args, super_interaction=super_interaction, skip_safe_tests=skip_safe_tests, **kwargs) - verbose_log.format_with_message('Post Test Result (CommonSocialMixerInteraction)', post_super_test_result=post_super_test_result) - except Exception as ex: - log.error('Error occurred while running CommonSocialMixerInteraction \'{}\' on_post_super_test.'.format(cls.__name__), exception=ex) - return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') - - if post_super_test_result is not None: - if isinstance(post_super_test_result, CommonTestResult): - if post_super_test_result.is_success is False: - return post_super_test_result - elif isinstance(post_super_test_result, TestResult) and post_super_test_result.result is False: - if post_super_test_result.tooltip is not None: - post_super_test_result_tooltip = CommonLocalizationUtils.create_localized_tooltip(post_super_test_result.tooltip) - elif post_super_test_result.reason is not None: - post_super_test_result_tooltip = CommonLocalizationUtils.create_localized_tooltip(post_super_test_result.reason) - else: - post_super_test_result_tooltip = None - return cls.create_test_result(post_super_test_result.result, post_super_test_result.reason, tooltip=post_super_test_result_tooltip, icon=post_super_test_result.icon, influence_by_active_mood=post_super_test_result.influence_by_active_mood) - - return cls.create_test_result(True) - except Exception as ex: - log.error('Error occurred while running _test of CommonSocialMixerInteraction \'{}\''.format(cls.__name__), exception=ex) - return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') - finally: - if verbose_log.enabled: - time_taken = CommonTextUtils.to_truncated_decimal(stop_watch.stop_milliseconds()) - verbose_log.format_with_message(f'Took {time_taken}ms to return result from CommonSocialMixerInteraction.', class_name=cls.__name__) - else: - stop_watch.stop() - - # noinspection PyMissingOrEmptyDocstring,PyMethodParameters - @flexmethod - def get_participants(cls, inst, participant_type: ParticipantType, sim=DEFAULT, target=DEFAULT, carry_target=DEFAULT, **kwargs) -> Union[Tuple[Any], Set[Any]]: - inst_or_cls = inst or cls - log = cls.get_log() - try: - custom_participants = cls.get_custom_replacement_participants(participant_type, sim, target, carry_target, interaction=inst, **kwargs) - if custom_participants is not None: - return tuple(custom_participants) - except Exception as ex: - log.error('Error occurred while running CommonSocialMixerInteraction \'{}\' get_custom_replacement_participants.'.format(cls.__name__), exception=ex) - - result: Set[Any] = super(CommonSocialMixerInteraction, inst_or_cls).get_participants(participant_type, sim=sim, target=target, carry_target=carry_target, **kwargs) - - result = set(result) - try: - custom_participants = cls.get_custom_participants(participant_type, sim, target, carry_target, interaction=inst, **kwargs) - result.update(custom_participants) - except Exception as ex: - log.error('Error occurred while running CommonSocialMixerInteraction \'{}\' get_custom_participants.'.format(cls.__name__), exception=ex) - return tuple(result) - - # noinspection PyMethodParameters,PyMissingOrEmptyDocstring - @flexmethod - def get_name(cls, inst: 'CommonSocialMixerInteraction', target: Any=DEFAULT, context: InteractionContext=DEFAULT, **interaction_parameters) -> LocalizedString: - inst_or_cls = inst or cls - try: - context_inst_or_cls = context or inst_or_cls - interaction_sim = context_inst_or_cls.sim - interaction_target = target or context_inst_or_cls.target - - cls.get_verbose_log().format_with_message( - 'Running get_name.', - class_name=cls.__name__, - interaction_sim=interaction_sim, - interaction_target=interaction_target, - interaction=inst, - interaction_context=context - ) - override_name = cls._create_override_display_name( - interaction_sim, - interaction_target, - interaction=inst, - interaction_context=context, - **interaction_parameters - ) - if override_name is not None: - return override_name - except Exception as ex: - cls.get_log().error('An error occurred while running get_name of CommonSocialMixerInteraction {}'.format(cls.__name__), exception=ex) - result = super(CommonSocialMixerInteraction, inst_or_cls).get_name(target=target, context=context, **interaction_parameters) - if result is None: - cls.get_log().error(f'Missing a name for interaction {cls.__name__}', throw=True) - return result - - def _trigger_interaction_start_event(self: 'CommonSocialMixerInteraction'): - try: - self.verbose_log.format_with_message( - 'Running on_started.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target - ) - result = self.on_started(self.sim, self.target) - if result is not None and ((isinstance(result, CommonExecutionResult) and not result.is_success) or (isinstance(result, bool) and not result)): - self.cancel(FinishingType.CONDITIONAL_EXIT, str(result)) - return False - return super()._trigger_interaction_start_event() - except Exception as ex: - self.log.error('Error occurred while running CommonSocialMixerInteraction \'{}\' 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: - self.verbose_log.format_with_message( - 'Running modify_posture_state.', - class_name=self.__class__.__name__, - posture_state=posture_state, - participant_type=participant_type, - sim=sim - ) - (new_posture_state, new_participant_type, new_sim) = self.modify_posture_state(posture_state, participant_type=participant_type, sim=sim) - except Exception as ex: - self.log.error('Error occurred while running CommonSocialMixerInteraction \'{}\' 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.verbose_log.format_with_message( - 'Running on_killed.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target - ) - self.on_killed(self.sim, self.target) - except Exception as ex: - self.log.error('Error occurred while running CommonSocialMixerInteraction \'{}\' 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.verbose_log.format_with_message( - 'Running on_cancelled.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target, - finishing_type=finishing_type, - cancel_reason_msg=cancel_reason_msg, - kwargles=kwargs - ) - self.on_cancelled(self.sim, self.target, finishing_type, cancel_reason_msg, **kwargs) - except Exception as ex: - self.log.error('Error occurred while running CommonSocialMixerInteraction \'{}\' cancel.'.format(self.__class__.__name__), exception=ex) - return super().cancel(finishing_type, cancel_reason_msg, **kwargs) - - def on_reset(self: 'CommonSocialMixerInteraction'): - """on_reset() - - A function that occurs upon an interaction being reset. - - """ - try: - self.verbose_log.format_with_message( - 'Running on_reset.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target - ) - self._on_reset(self.sim, self.target) - except Exception as ex: - self.log.error('Error occurred while running CommonSocialMixerInteraction \'{}\' on_reset.'.format(self.__class__.__name__), exception=ex) - return super().on_reset() - - def _post_perform(self: 'CommonSocialMixerInteraction'): - super_result = super()._post_perform() - try: - self.verbose_log.format_with_message( - 'Running on_performed.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target - ) - self.on_performed(self.sim, self.target) - except Exception as ex: - self.log.error('Error occurred while running CommonSocialMixerInteraction \'{}\' _post_perform.'.format(self.__class__.__name__), exception=ex) - return super_result - - def send_current_progress(self, *args: Any, **kwargs: Any): - """send_current_progress(*args, **kwargs) - - A function that occurs upon a progress bar update. - - """ - try: - self.verbose_log.format_with_message( - 'Running _send_current_progress.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target, - argles=args, - kwargles=kwargs - ) - result = self._send_current_progress(self.sim, self.target, *args, **kwargs) - if result is not None: - return result - except Exception as ex: - self.log.error('Error occurred while running CommonSocialMixerInteraction \'{}\' 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: - self.verbose_log.format_with_message( - 'Running _setup_asm_default.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target, - asm=asm, - argles=args, - kwargles=kwargs - ) - result = self._setup_asm_default(self.sim, self.target, asm, *args, **kwargs) - if result is not None: - return result - except Exception as ex: - self.log.error('Error occurred while running CommonSocialMixerInteraction \'{}\' setup_asm_default.'.format(self.__class__.__name__), exception=ex) - return super().setup_asm_default(asm, *args, **kwargs) - - def _run_interaction_gen(self, timeline: Timeline): - try: - self.verbose_log.format_with_message( - 'Running on_run.', - class_name=self.__class__.__name__, - interaction_sim=self.sim, - interaction_target=self.target, - timeline=timeline - ) - self.on_run(self.sim, self.target, timeline) - except Exception as ex: - self.log.error('Error occurred while running CommonSocialMixerInteraction \'{}\' on_run.'.format(self.__class__.__name__), exception=ex) - yield from super()._run_interaction_gen(timeline) - - @classmethod - def _constraint_gen(cls, sim: Sim, target: Any, participant_type: ParticipantType=ParticipantType.Actor, interaction: 'CommonSocialMixerInteraction'=None) -> Constraint: - inst_or_cls = interaction if interaction is not None else cls - try: - replacement_results = cls.on_replacement_constraints_gen(inst_or_cls, sim or inst_or_cls.sim, inst_or_cls.get_constraint_target(target) or target or inst_or_cls.target) - if replacement_results is not None: - if inspect.isgenerator(replacement_results): - yield from replacement_results - else: - yield replacement_results - else: - yield from super()._constraint_gen(sim, target, participant_type=participant_type, interaction=interaction) - result = cls.on_constraint_gen(inst_or_cls, sim or inst_or_cls.sim, inst_or_cls.get_constraint_target(target) or target or inst_or_cls.target) - if result is not None: - if inspect.isgenerator(result): - yield from result - else: - yield result - except Exception as ex: - cls.get_log().error('Error occurred while running CommonSocialMixerInteraction \'{}\' _on_constraint_gen.'.format(cls.__name__), exception=ex) diff --git a/Scripts/s4ap/sims4communitylib/classes/interactions/common_social_super_interaction.py b/Scripts/s4ap/sims4communitylib/classes/interactions/common_social_super_interaction.py deleted file mode 100644 index 2793651..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/interactions/common_social_super_interaction.py +++ /dev/null @@ -1,518 +0,0 @@ -""" -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 -""" -import inspect -from typing import Any, Union, Set - -from event_testing.tests import TestList -from interactions.base.interaction import Interaction -from s4ap.sims4communitylib.classes.interactions._common_interaction_custom_mixin import _CommonInteractionCustomMixin -from s4ap.sims4communitylib.classes.interactions._common_interaction_hooks_mixin import _CommonInteractionHooksMixin -from s4ap.sims4communitylib.utils.misc.common_text_utils import CommonTextUtils -from singletons import DEFAULT - -from interactions import ParticipantType -from interactions.constraints import Constraint -from interactions.interaction_finisher import FinishingType -from postures.posture_state import PostureState -from protocolbuffers.Localization_pb2 import LocalizedString -from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.logging.has_class_log import HasClassLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from interactions.social.social_super_interaction import SocialSuperInteraction -from interactions.context import InteractionContext -from native.animation import NativeAsm -from scheduling import Timeline -from sims.sim import Sim -from sims4.utils import flexmethod - - -# If on Read The Docs, create fake versions of extended objects to fix the error of inheriting from multiple MockObjects. -class CommonSocialSuperInteraction(SocialSuperInteraction, HasClassLog, _CommonInteractionHooksMixin, _CommonInteractionCustomMixin): - """CommonSocialSuperInteraction(*_, **__) - - An inheritable class that provides a way to create Custom Social Super Interactions. - - .. note:: - - The main use for this class is to create interactions that wrap sub interactions. - - .. 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! - - :Example: - - .. highlight:: python - .. code-block:: python - - # The following is an example interaction that varies when it will display, when it will be hidden, and when it will be disabled with a tooltip. - class _ExampleInteraction(CommonSocialSuperInteraction): - @classmethod - def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, interaction=None, **kwargs) -> TestResult: - result = 1 + 1 - if result == 2: - # Interaction will be displayed, but disabled, it will also have a tooltip that displays on hover with the text "Test Tooltip" - return cls.create_test_result(False, reason="Test Tooltip") - # Alternative way to specify a tooltip with the text "Test Tooltip" - # return cls.create_test_result(False, reason="No Reason", tooltip=CommonLocalizationUtils.create_localized_tooltip("Test Tooltip")) - if result == 3: - # Interaction will be hidden completely. - return CommonTestResult.NONE - # Interaction will display and be enabled. - return CommonTestResult.TRUE - - # Instead of on_started, SocialSuperInteractions use on_run. - def on_run(self, interaction_sim: Sim, interaction_target: Any, timeline: Timeline) -> bool: - result = True - if not result: - return False - # Put here what you want the interaction to do as soon as the player clicks it while it is enabled. - return True - - def on_cancelled(self, interaction_sim: Sim, interaction_target: Any, finishing_type: FinishingType, cancel_reason_msg: str, **kwargs): - result = True - if not result: - return False - # Put here what you want the interaction to do as soon as the player clicks it while it is enabled. - return True - - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> Union[CommonModIdentity, None]: - return None - - def __init__(self, *_: Any, **__: Any): - super().__init__(*_, **__) - HasClassLog.__init__(self) - - # noinspection PyMethodParameters - @flexmethod - def _test(cls, inst: 'CommonSocialSuperInteraction', target: Any, context: InteractionContext, super_interaction: 'Interaction'=None, skip_safe_tests: bool=False, **kwargs): - from event_testing.results import TestResult - from s4ap.sims4communitylib.classes.time.common_stop_watch import CommonStopWatch - inst_or_cls = inst or cls - log = cls.get_log() - verbose_log = cls.get_verbose_log() - stop_watch = CommonStopWatch() - if verbose_log.enabled: - stop_watch.start() - try: - try: - verbose_log.format_with_message( - 'Running on_test.', - class_name=cls.__name__, - inst=inst, - interaction_sim=context.sim, - interaction_target=target, - interaction_context=context, - super_interaction=super_interaction, - skip_safe_tests=skip_safe_tests, - kwargles=kwargs - ) - test_result = cls.on_test(context.sim, target, context, interaction=inst, super_interaction=super_interaction, skip_safe_tests=skip_safe_tests, **kwargs) - verbose_log.format_with_message('Test Result (CommonSocialSuperInteraction)', test_result=test_result) - except Exception as ex: - log.error('Error occurred while running CommonSocialSuperInteraction \'{}\' on_test.'.format(cls.__name__), exception=ex) - return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') - - if test_result is not None: - if isinstance(test_result, CommonTestResult): - if test_result.is_success is False: - return test_result - elif isinstance(test_result, TestResult) and 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, icon=test_result.icon, influence_by_active_mood=test_result.influence_by_active_mood) - - try: - verbose_log.format_with_message( - 'Running super()._test.', - class_name=cls.__name__, - inst=inst, - interaction_sim=context.sim, - interaction_target=target, - interaction_context=context, - super_interaction=super_interaction, - skip_safe_tests=skip_safe_tests, - kwargles=kwargs - ) - super_test_result: TestResult = super(CommonSocialSuperInteraction, inst_or_cls)._test(target, context, super_interaction=super_interaction, skip_safe_tests=skip_safe_tests, **kwargs) - - if verbose_log.enabled: - search_for_tooltip = context.source == context.SOURCE_PIE_MENU - resolver = inst_or_cls.get_resolver(target=target, context=context, super_interaction=super_interaction, search_for_tooltip=search_for_tooltip, **kwargs) - global_result = cls.test_globals.run_tests(resolver, skip_safe_tests, search_for_tooltip=search_for_tooltip) - local_result = cls.tests.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=search_for_tooltip) - if inst_or_cls._additional_tests: - additional_tests = TestList(inst_or_cls._additional_tests) - additional_local_result = additional_tests.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=search_for_tooltip) - else: - additional_local_result = None - if inst_or_cls.test_autonomous: - autonomous_result = cls.test_autonomous.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=False) - else: - autonomous_result = None - if target is not None: - tests = target.get_affordance_tests(inst_or_cls) - if tests is not None: - target_result = tests.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=search_for_tooltip) - else: - target_result = None - else: - target_result = None - verbose_log.format_with_message('Super Test Result (CommonSocialSuperInteraction)', super_test_result=super_test_result, global_result=global_result, local_result=local_result, additional_local_result=additional_local_result, autonomous_result=autonomous_result, target_result=target_result) - - if super_test_result is not None and (isinstance(test_result, TestResult) and not super_test_result.result): - return CommonTestResult.convert_from_vanilla(super_test_result) - except Exception as ex: - log.error('Error occurred while running CommonSocialSuperInteraction \'{}\' super()._test.'.format(cls.__name__), exception=ex) - return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') - - try: - verbose_log.format_with_message( - 'Running on_post_super_test.', - class_name=cls.__name__, - inst=inst, - interaction_sim=context.sim, - interaction_target=target, - interaction_context=context, - super_interaction=super_interaction, - skip_safe_tests=skip_safe_tests, - kwargles=kwargs - ) - post_super_test_result = cls.on_post_super_test(context.sim, target, context, interaction=inst, super_interaction=super_interaction, skip_safe_tests=skip_safe_tests, **kwargs) - verbose_log.format_with_message('Post Test Result (CommonSocialSuperInteraction)', post_super_test_result=post_super_test_result) - except Exception as ex: - log.error('Error occurred while running CommonSocialSuperInteraction \'{}\' on_post_super_test.'.format(cls.__name__), exception=ex) - return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') - - if post_super_test_result is not None: - if isinstance(post_super_test_result, CommonTestResult): - if post_super_test_result.is_success is False: - return post_super_test_result - elif isinstance(post_super_test_result, TestResult) and post_super_test_result.result is False: - if post_super_test_result.tooltip is not None: - post_super_test_result_tooltip = CommonLocalizationUtils.create_localized_tooltip(post_super_test_result.tooltip) - elif post_super_test_result.reason is not None: - post_super_test_result_tooltip = CommonLocalizationUtils.create_localized_tooltip(post_super_test_result.reason) - else: - post_super_test_result_tooltip = None - return cls.create_test_result(post_super_test_result.result, post_super_test_result.reason, tooltip=post_super_test_result_tooltip, icon=post_super_test_result.icon, influence_by_active_mood=post_super_test_result.influence_by_active_mood) - - return cls.create_test_result(True) - except Exception as ex: - log.error('Error occurred while running _test of CommonSocialSuperInteraction \'{}\''.format(cls.__name__), exception=ex) - return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') - finally: - if verbose_log.enabled: - time_taken = CommonTextUtils.to_truncated_decimal(stop_watch.stop_milliseconds()) - verbose_log.format_with_message(f'Took {time_taken}ms to return result from CommonSocialSuperInteraction.', class_name=cls.__name__) - else: - stop_watch.stop() - - # noinspection PyMissingOrEmptyDocstring,PyMethodParameters - @flexmethod - def get_participants(cls, inst, participant_type: ParticipantType, sim=DEFAULT, target=DEFAULT, carry_target=DEFAULT, **kwargs): - inst_or_cls = inst or cls - log = cls.get_log() - try: - custom_participants = cls.get_custom_replacement_participants(participant_type, sim, target, carry_target, interaction=inst, **kwargs) - if custom_participants is not None: - return tuple(custom_participants) - except Exception as ex: - log.error('Error occurred while running CommonSocialSuperInteraction \'{}\' get_custom_replacement_participants.'.format(cls.__name__), exception=ex) - - result: Set[Any] = super(CommonSocialSuperInteraction, inst_or_cls).get_participants(participant_type, sim=sim, target=target, carry_target=carry_target, **kwargs) - - result = set(result) - try: - custom_participants = cls.get_custom_participants(participant_type, sim, target, carry_target, interaction=inst, **kwargs) - result.update(custom_participants) - except Exception as ex: - log.error('Error occurred while running CommonSocialSuperInteraction \'{}\' get_custom_participants.'.format(cls.__name__), exception=ex) - return tuple(result) - - # noinspection PyMethodParameters,PyMissingOrEmptyDocstring - @flexmethod - def get_name(cls, inst: 'CommonSocialSuperInteraction', target: Any=DEFAULT, context: InteractionContext=DEFAULT, **interaction_parameters) -> LocalizedString: - inst_or_cls = inst or cls - try: - context_inst_or_cls = context or inst_or_cls - interaction_sim = context_inst_or_cls.sim - interaction_target = target or context_inst_or_cls.target - - cls.get_verbose_log().format_with_message( - 'Running get_name.', - class_name=cls.__name__, - interaction_sim=interaction_sim, - interaction_target=interaction_target, - interaction=inst, - interaction_context=context - ) - override_name = cls._create_override_display_name( - interaction_sim, - interaction_target, - interaction=inst, - interaction_context=context, - **interaction_parameters - ) - if override_name is not None: - return override_name - except Exception as ex: - cls.get_log().error('An error occurred while running get_name of CommonSocialSuperInteraction {}'.format(cls.__name__), exception=ex) - result = super(CommonSocialSuperInteraction, inst_or_cls).get_name(target=target, context=context, **interaction_parameters) - if result is None: - cls.get_log().error(f'Missing a name for interaction {cls.__name__}', throw=True) - return result - - def _trigger_interaction_start_event(self: 'CommonSocialSuperInteraction'): - try: - self.verbose_log.format_with_message( - 'Running on_started.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target - ) - result = self.on_started(self.sim, self.target) - if result is not None and ((isinstance(result, CommonExecutionResult) and not result.is_success) or (isinstance(result, bool) and not result)): - self.cancel(FinishingType.CONDITIONAL_EXIT, str(result)) - return False - return super()._trigger_interaction_start_event() - except Exception as ex: - self.log.error('Error occurred while running CommonSocialSuperInteraction \'{}\' 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: - self.verbose_log.format_with_message( - 'Running modify_posture_state.', - class_name=self.__class__.__name__, - posture_state=posture_state, - participant_type=participant_type, - sim=sim - ) - (new_posture_state, new_participant_type, new_sim) = self.modify_posture_state(posture_state, participant_type=participant_type, sim=sim) - except Exception as ex: - self.log.error('Error occurred while running CommonSocialSuperInteraction \'{}\' 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.verbose_log.format_with_message( - 'Running on_killed.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target - ) - self.on_killed(self.sim, self.target) - except Exception as ex: - self.log.error('Error occurred while running CommonSocialSuperInteraction \'{}\' on_killed.'.format(self.__class__.__name__), exception=ex) - return super().kill() - - # noinspection PyMethodOverriding - 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.verbose_log.format_with_message( - 'Running on_cancelled.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target, - finishing_type=finishing_type, - cancel_reason_msg=cancel_reason_msg, - kwargles=kwargs - ) - self.on_cancelled(self.sim, self.target, finishing_type, cancel_reason_msg, **kwargs) - except Exception as ex: - self.log.error('Error occurred while running CommonSocialSuperInteraction \'{}\' cancel.'.format(self.__class__.__name__), exception=ex) - return super()._cancel(finishing_type, cancel_reason_msg, **kwargs) - - def on_reset(self: 'CommonSocialSuperInteraction'): - """on_reset() - - A function that occurs upon an interaction being reset. - - """ - try: - self.verbose_log.format_with_message( - 'Running on_reset.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target - ) - self._on_reset(self.sim, self.target) - except Exception as ex: - self.log.error('Error occurred while running CommonSocialSuperInteraction \'{}\' on_reset.'.format(self.__class__.__name__), exception=ex) - return super().on_reset() - - def _post_perform(self: 'CommonSocialSuperInteraction'): - super_result = super()._post_perform() - try: - self.verbose_log.format_with_message( - 'Running on_performed.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target - ) - self.on_performed(self.sim, self.target) - except Exception as ex: - self.log.error('Error occurred while running CommonSocialSuperInteraction \'{}\' _post_perform.'.format(self.__class__.__name__), exception=ex) - return super_result - - def send_current_progress(self, *args: Any, **kwargs: Any): - """send_current_progress(*args, **kwargs) - - A function that occurs upon a progress bar update. - - """ - try: - self.verbose_log.format_with_message( - 'Running _send_current_progress.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target, - argles=args, - kwargles=kwargs - ) - result = self._send_current_progress(self.sim, self.target, *args, **kwargs) - if result is not None: - return result - except Exception as ex: - self.log.error('Error occurred while running CommonSocialSuperInteraction \'{}\' 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: - self.verbose_log.format_with_message( - 'Running _setup_asm_default.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target, - asm=asm, - argles=args, - kwargles=kwargs - ) - result = self._setup_asm_default(self.sim, self.target, asm, *args, **kwargs) - if result is not None: - return result - except Exception as ex: - self.log.error('Error occurred while running CommonSocialSuperInteraction \'{}\' setup_asm_default.'.format(self.__class__.__name__), exception=ex) - return super().setup_asm_default(asm, *args, **kwargs) - - def _run_interaction_gen(self, timeline: Timeline): - try: - self.verbose_log.format_with_message( - 'Running on_run.', - class_name=self.__class__.__name__, - interaction_sim=self.sim, - interaction_target=self.target, - timeline=timeline - ) - self.on_run(self.sim, self.target, timeline) - except Exception as ex: - self.log.error('Error occurred while running CommonSocialSuperInteraction \'{}\' on_run.'.format(self.__class__.__name__), exception=ex) - yield from super()._run_interaction_gen(timeline) - - # noinspection PyMethodParameters - @flexmethod - def _constraint_gen(cls, inst: 'CommonSocialSuperInteraction', sim: Sim, target: Any, participant_type: ParticipantType=ParticipantType.Actor, **kwargs) -> Constraint: - inst_or_cls = inst if inst is not None else cls - try: - replacement_results = cls.on_replacement_constraints_gen(inst_or_cls, sim or inst_or_cls.sim, inst_or_cls.get_constraint_target(target) or target or inst_or_cls.target) - if replacement_results is not None: - if inspect.isgenerator(replacement_results): - yield from replacement_results - else: - yield replacement_results - else: - yield from super(CommonSocialSuperInteraction, inst_or_cls)._constraint_gen(sim, target, participant_type=participant_type, **kwargs) - result = cls.on_constraint_gen(inst_or_cls, sim or inst_or_cls.sim, inst_or_cls.get_constraint_target(target) or target or inst_or_cls.target) - if result is not None: - if inspect.isgenerator(result): - yield from result - else: - yield result - except Exception as ex: - cls.get_log().error('Error occurred while running CommonSocialSuperInteraction \'{}\' _on_constraint_gen.'.format(cls.__name__), exception=ex) - - # The following functions are hooks into various parts of an interaction override them in your own interaction to provide custom functionality. - - # noinspection PyUnusedLocal - @classmethod - def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, *args, interaction: 'Interaction'=None, **kwargs) -> CommonTestResult: - """on_test(interaction_sim, interaction_target, interaction_context, *args, interaction=None, **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 - :param interaction: The interaction being tested or None. Default is None. - :type interaction: Interaction, optional - :return: The outcome of testing the availability of the interaction - :rtype: CommonTestResult - """ - return super().on_test(interaction_sim, interaction_target, interaction_context, *args, interaction=interaction, **kwargs) - - # noinspection PyUnusedLocal - @classmethod - def on_post_super_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, *args, interaction: 'Interaction'=None, **kwargs) -> CommonTestResult: - """on_post_super_test(interaction_sim, interaction_target, interaction_context, *args, interaction=None, **kwargs) - - A hook that occurs after the interaction being tested for availability by on_test and the super _test functions. - - .. note:: This will only run if both on_test and _test returns CommonTestResult.TRUE or similar. - - :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 - :param interaction: The interaction being tested or None. Default is None. - :type interaction: Interaction, optional - :return: The outcome of testing the availability of the interaction - :rtype: CommonTestResult - """ - return super().on_post_super_test(interaction_sim, interaction_target, interaction_context, *args, interaction=interaction, **kwargs) diff --git a/Scripts/s4ap/sims4communitylib/classes/interactions/common_super_interaction.py b/Scripts/s4ap/sims4communitylib/classes/interactions/common_super_interaction.py deleted file mode 100644 index b5f2198..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/interactions/common_super_interaction.py +++ /dev/null @@ -1,894 +0,0 @@ -""" -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 -""" -import inspect -from typing import Any, Union, Set - -from event_testing.tests import TestList -from interactions import ParticipantType -from interactions.base.interaction import Interaction -from interactions.constraints import Constraint -from interactions.context import InteractionContext -from interactions.interaction_finisher import FinishingType -from native.animation import NativeAsm -from postures.posture_state import PostureState -from protocolbuffers.Localization_pb2 import LocalizedString -from s4ap.sims4communitylib.classes.interactions._common_interaction_custom_mixin import _CommonInteractionCustomMixin -from s4ap.sims4communitylib.classes.interactions._common_interaction_hooks_mixin import _CommonInteractionHooksMixin -from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.logging.has_class_log import HasClassLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from s4ap.sims4communitylib.utils.misc.common_text_utils import CommonTextUtils -from singletons import DEFAULT -from interactions.base.super_interaction import SuperInteraction -from scheduling import Timeline -from sims4.utils import flexmethod -from sims.sim import Sim - - -class CommonBaseSuperInteraction(SuperInteraction, HasClassLog, _CommonInteractionHooksMixin, _CommonInteractionCustomMixin): - """CommonBaseSuperInteraction(*_, **__) - - An inheritable class that provides a way to create custom Super Interactions. - - .. note:: Use this Base class when you don't wish _run_interaction_gen to be overridden. - - .. note:: - - The main use for this class is to create interactions that wrap sub interactions. - One example Super interaction is the `sim-chat` interaction, where other interactions (Such as the `Get To Know` interaction), run as sub interactions of `sim-chat` - - .. 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! - - :Example: - - .. highlight:: python - .. code-block:: python - - # The following is an example interaction that varies when it will display, when it will be hidden, and when it will be disabled with a tooltip. - class _ExampleInteraction(CommonBaseSuperInteraction): - @classmethod - def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, **kwargs) -> CommonTestResult: - result = 1 + 1 - if result == 2: - # Interaction will be displayed, but disabled, it will also have a tooltip that displays on hover with the text "Test Tooltip" - return cls.create_test_result(False, reason="Test Tooltip") - # Alternative way to specify a tooltip with the text "Test Tooltip" - # return cls.create_test_result(False, reason="No Reason", tooltip=CommonLocalizationUtils.create_localized_tooltip("Test Tooltip")) - if result == 3: - # Interaction will be hidden completely. - return CommonTestResult.NONE - # Interaction will display and be enabled. - return CommonTestResult.TRUE - - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> Union[CommonModIdentity, None]: - return None - - def __init__(self, *_: Any, **__: Any): - super().__init__(*_, **__) - HasClassLog.__init__(self) - - -class CommonSuperInteraction(CommonBaseSuperInteraction): - """CommonSuperInteraction(*_, **__) - - An inheritable class that provides a way to create custom Super Interactions. - - .. note:: - - The main use for this class is to create interactions that wrap sub interactions. - One example Super interaction is the `sim-chat` interaction, where other interactions (Such as the `Get To Know` interaction), run as sub interactions of `sim-chat` - - .. 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! - - :Example: - - .. highlight:: python - .. code-block:: python - - # The following is an example interaction that varies when it will display, when it will be hidden, and when it will be disabled with a tooltip. - class _ExampleInteraction(CommonSuperInteraction): - @classmethod - def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, **kwargs) -> CommonTestResult: - result = 1 + 1 - if result == 2: - # Interaction will be displayed, but disabled, it will also have a tooltip that displays on hover with the text "Test Tooltip" - return cls.create_test_result(False, reason="Test Tooltip") - # Alternative way to specify a tooltip with the text "Test Tooltip" - # return cls.create_test_result(False, reason="No Reason", tooltip=CommonLocalizationUtils.create_localized_tooltip("Test Tooltip")) - if result == 3: - # Interaction will be hidden completely. - return CommonTestResult.NONE - # Interaction will display and be enabled. - return CommonTestResult.TRUE - - # Instead of on_started, SuperInteractions use on_run. - def on_run(self, interaction_sim: Sim, interaction_target: Any: timeline: Timeline) -> bool: - result = True - if not result: - return False - # Put here what you want the interaction to do as soon as the player clicks it while it is enabled. - return True - """ - - @classmethod - def _test(cls, target: Any, context: InteractionContext, super_interaction: 'Interaction'=None, skip_safe_tests: bool=False, **kwargs) -> CommonTestResult: - from event_testing.results import TestResult - from s4ap.sims4communitylib.classes.time.common_stop_watch import CommonStopWatch - log = cls.get_log() - verbose_log = cls.get_verbose_log() - stop_watch = CommonStopWatch() - if verbose_log.enabled: - stop_watch.start() - try: - try: - verbose_log.format_with_message( - 'Running on_test.', - class_name=cls.__name__, - interaction_sim=context.sim, - interaction_target=target, - interaction_context=context, - super_interaction=super_interaction, - skip_safe_tests=skip_safe_tests, - kwargles=kwargs - ) - test_result = cls.on_test(context.sim, target, context, super_interaction=super_interaction, skip_safe_tests=skip_safe_tests, **kwargs) - verbose_log.format_with_message('Test Result (CommonSuperInteraction)', test_result=test_result) - except Exception as ex: - log.error('Error occurred while running CommonSuperInteraction \'{}\' on_test.'.format(cls.__name__), exception=ex) - return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') - - if test_result is not None: - if isinstance(test_result, CommonTestResult): - if test_result.is_success is False: - return test_result - elif isinstance(test_result, TestResult) and 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, icon=test_result.icon, influence_by_active_mood=test_result.influence_by_active_mood) - - try: - verbose_log.format_with_message( - 'Running super()._test.', - class_name=cls.__name__, - interaction_sim=context.sim, - interaction_target=target, - interaction_context=context, - super_interaction=super_interaction, - skip_safe_tests=skip_safe_tests, - kwargles=kwargs - ) - super_test_result: TestResult = super()._test(target, context, super_interaction=super_interaction, skip_safe_tests=skip_safe_tests, **kwargs) - - if verbose_log.enabled: - search_for_tooltip = context.source == context.SOURCE_PIE_MENU - resolver = cls.get_resolver(target=target, context=context, super_interaction=super_interaction, search_for_tooltip=search_for_tooltip, **kwargs) - global_result = cls.test_globals.run_tests(resolver, skip_safe_tests, search_for_tooltip=search_for_tooltip) - local_result = cls.tests.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=search_for_tooltip) - if cls._additional_tests: - additional_tests = TestList(cls._additional_tests) - additional_local_result = additional_tests.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=search_for_tooltip) - else: - additional_local_result = None - if cls.test_autonomous: - autonomous_result = cls.test_autonomous.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=False) - else: - autonomous_result = None - if target is not None: - tests = target.get_affordance_tests(cls) - if tests is not None: - target_result = tests.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=search_for_tooltip) - else: - target_result = None - else: - target_result = None - verbose_log.format_with_message('Super Test Result (CommonSuperInteraction)', super_test_result=super_test_result, global_result=global_result, local_result=local_result, additional_local_result=additional_local_result, autonomous_result=autonomous_result, target_result=target_result) - - if super_test_result is not None and (isinstance(test_result, TestResult) and not super_test_result.result): - return CommonTestResult.convert_from_vanilla(super_test_result) - except Exception as ex: - log.error('Error occurred while running CommonSuperInteraction \'{}\' super()._test.'.format(cls.__name__), exception=ex) - return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') - - try: - verbose_log.format_with_message( - 'Running on_post_super_test.', - class_name=cls.__name__, - interaction_sim=context.sim, - interaction_target=target, - interaction_context=context, - super_interaction=super_interaction, - skip_safe_tests=skip_safe_tests, - kwargles=kwargs - ) - post_super_test_result = cls.on_post_super_test(context.sim, target, context, super_interaction=super_interaction, skip_safe_tests=skip_safe_tests, **kwargs) - verbose_log.format_with_message('Post Test Result (CommonSuperInteraction)', post_super_test_result=post_super_test_result) - except Exception as ex: - log.error('Error occurred while running CommonSuperInteraction \'{}\' on_post_super_test.'.format(cls.__name__), exception=ex) - return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') - - if post_super_test_result is not None: - if isinstance(post_super_test_result, CommonTestResult): - if post_super_test_result.is_success is False: - return post_super_test_result - elif isinstance(post_super_test_result, TestResult) and post_super_test_result.result is False: - if post_super_test_result.tooltip is not None: - post_super_test_result_tooltip = CommonLocalizationUtils.create_localized_tooltip(post_super_test_result.tooltip) - elif post_super_test_result.reason is not None: - post_super_test_result_tooltip = CommonLocalizationUtils.create_localized_tooltip(post_super_test_result.reason) - else: - post_super_test_result_tooltip = None - return cls.create_test_result(post_super_test_result.result, post_super_test_result.reason, tooltip=post_super_test_result_tooltip, icon=post_super_test_result.icon, influence_by_active_mood=post_super_test_result.influence_by_active_mood) - - return cls.create_test_result(True) - except Exception as ex: - log.error('Error occurred while running _test of CommonSuperInteraction \'{}\''.format(cls.__name__), exception=ex) - return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') - finally: - if verbose_log.enabled: - time_taken = CommonTextUtils.to_truncated_decimal(stop_watch.stop_milliseconds()) - verbose_log.format_with_message(f'Took {time_taken}ms to return result from CommonSuperInteraction.', class_name=cls.__name__) - else: - stop_watch.stop() - - # noinspection PyMissingOrEmptyDocstring,PyMethodParameters - @flexmethod - def get_participants(cls, inst, participant_type: ParticipantType, sim=DEFAULT, target=DEFAULT, carry_target=DEFAULT, **kwargs): - inst_or_cls = inst or cls - log = cls.get_log() - try: - custom_participants = cls.get_custom_replacement_participants(participant_type, sim, target, carry_target, interaction=inst, **kwargs) - if custom_participants is not None: - return tuple(custom_participants) - except Exception as ex: - log.error('Error occurred while running CommonSuperInteraction \'{}\' get_custom_replacement_participants.'.format(cls.__name__), exception=ex) - - result: Set[Any] = super(CommonSuperInteraction, inst_or_cls).get_participants(participant_type, sim=sim, target=target, carry_target=carry_target, **kwargs) - - result = set(result) - try: - custom_participants = cls.get_custom_participants(participant_type, sim, target, carry_target, interaction=inst, **kwargs) - result.update(custom_participants) - except Exception as ex: - log.error('Error occurred while running CommonSuperInteraction \'{}\' get_custom_participants.'.format(cls.__name__), exception=ex) - return tuple(result) - - # noinspection PyMethodParameters,PyMissingOrEmptyDocstring - @flexmethod - def get_name(cls, inst: 'CommonSuperInteraction', target: Any=DEFAULT, context: InteractionContext=DEFAULT, **interaction_parameters) -> LocalizedString: - inst_or_cls = inst or cls - try: - context_inst_or_cls = context or inst_or_cls - interaction_sim = context_inst_or_cls.sim - interaction_target = target or context_inst_or_cls.target - - cls.get_verbose_log().format_with_message( - 'Running get_name.', - class_name=cls.__name__, - interaction_sim=interaction_sim, - interaction_target=interaction_target, - interaction=inst, - interaction_context=context - ) - override_name = cls._create_override_display_name( - interaction_sim, - interaction_target, - interaction=inst, - interaction_context=context, - **interaction_parameters - ) - if override_name is not None: - return override_name - except Exception as ex: - cls.get_log().error('An error occurred while running get_name of CommonSuperInteraction {}'.format(cls.__name__), exception=ex) - result = super(CommonSuperInteraction, inst_or_cls).get_name(target=target, context=context, **interaction_parameters) - if result is None: - cls.get_log().error(f'Missing a name for interaction {cls.__name__}', throw=True) - return result - - def _trigger_interaction_start_event(self: 'CommonSuperInteraction'): - try: - self.verbose_log.format_with_message( - 'Running on_started.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target - ) - result = self.on_started(self.sim, self.target) - if result is not None and ((isinstance(result, CommonExecutionResult) and not result.is_success) or (isinstance(result, bool) and not result)): - self.cancel(FinishingType.CONDITIONAL_EXIT, str(result)) - return False - return super()._trigger_interaction_start_event() - except Exception as ex: - self.log.error('Error occurred while running CommonSuperInteraction \'{}\' 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: - self.verbose_log.format_with_message( - 'Running modify_posture_state.', - class_name=self.__class__.__name__, - posture_state=posture_state, - participant_type=participant_type, - sim=sim - ) - (new_posture_state, new_participant_type, new_sim) = self.modify_posture_state(posture_state, participant_type=participant_type, sim=sim) - except Exception as ex: - self.log.error('Error occurred while running CommonSuperInteraction \'{}\' 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.verbose_log.format_with_message( - 'Running on_killed.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target - ) - self.on_killed(self.sim, self.target) - except Exception as ex: - self.log.error('Error occurred while running CommonSuperInteraction \'{}\' 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.verbose_log.format_with_message( - 'Running on_cancelled.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target, - finishing_type=finishing_type, - cancel_reason_msg=cancel_reason_msg, - kwargles=kwargs - ) - self.on_cancelled(self.sim, self.target, finishing_type, cancel_reason_msg, **kwargs) - except Exception as ex: - self.log.error('Error occurred while running CommonSuperInteraction \'{}\' _cancel.'.format(self.__class__.__name__), exception=ex) - return super()._cancel(finishing_type, cancel_reason_msg, **kwargs) - - def on_reset(self: 'CommonSuperInteraction'): - """on_reset() - - A function that occurs upon an interaction being reset. - - """ - try: - self.verbose_log.format_with_message( - 'Running on_reset.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target - ) - self._on_reset(self.sim, self.target) - except Exception as ex: - self.log.error('Error occurred while running CommonSuperInteraction \'{}\' on_reset.'.format(self.__class__.__name__), exception=ex) - return super().on_reset() - - def _post_perform(self: 'CommonSuperInteraction'): - super_result = super()._post_perform() - try: - self.verbose_log.format_with_message( - 'Running on_performed.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target - ) - self.on_performed(self.sim, self.target) - except Exception as ex: - self.log.error('Error occurred while running CommonSuperInteraction \'{}\' _post_perform.'.format(self.__class__.__name__), exception=ex) - return super_result - - def send_current_progress(self, *args: Any, **kwargs: Any): - """send_current_progress(*args, **kwargs) - - A function that occurs upon a progress bar update. - - """ - try: - self.verbose_log.format_with_message( - 'Running _send_current_progress.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target, - argles=args, - kwargles=kwargs - ) - result = self._send_current_progress(self.sim, self.target, *args, **kwargs) - if result is not None: - return result - except Exception as ex: - self.log.error('Error occurred while running CommonSuperInteraction \'{}\' 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: - self.verbose_log.format_with_message( - 'Running _setup_asm_default.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target, - asm=asm, - argles=args, - kwargles=kwargs - ) - result = self._setup_asm_default(self.sim, self.target, asm, *args, **kwargs) - if result is not None: - return result - except Exception as ex: - self.log.error('Error occurred while running CommonSuperInteraction \'{}\' setup_asm_default.'.format(self.__class__.__name__), exception=ex) - return super().setup_asm_default(asm, *args, **kwargs) - - def _run_interaction_gen(self, timeline: Timeline): - try: - self.verbose_log.format_with_message( - 'Running on_run.', - class_name=self.__class__.__name__, - interaction_sim=self.sim, - interaction_target=self.target, - timeline=timeline - ) - self.on_run(self.sim, self.target, timeline) - except Exception as ex: - self.log.error('Error occurred while running CommonSuperInteraction \'{}\' on_run.'.format(self.__class__.__name__), exception=ex) - yield from super()._run_interaction_gen(timeline) - - @classmethod - def _tuning_loaded_callback(cls) -> Any: - if isinstance(cls.basic_content, str): - from interactions.base.basic import NoContent - cls.basic_content = NoContent(allow_holster=None, allow_with_unholsterable_object=False, route_to_location=None) - return super()._tuning_loaded_callback() - - # noinspection PyMethodParameters - @flexmethod - def _constraint_gen(cls, inst: 'CommonSuperInteraction', sim: Sim, target: Any, participant_type: ParticipantType=ParticipantType.Actor, **kwargs) -> Constraint: - inst_or_cls = inst if inst is not None else cls - try: - replacement_results = cls.on_replacement_constraints_gen(inst_or_cls, sim or inst_or_cls.sim, inst_or_cls.get_constraint_target(target) or target or inst_or_cls.target) - if replacement_results is not None: - if inspect.isgenerator(replacement_results): - yield from replacement_results - else: - yield replacement_results - else: - yield from super(CommonSuperInteraction, inst_or_cls)._constraint_gen(sim, target, participant_type=participant_type, **kwargs) - result = cls.on_constraint_gen(inst_or_cls, sim or inst_or_cls.sim, inst_or_cls.get_constraint_target(target) or target or inst_or_cls.target) - if result is not None: - if inspect.isgenerator(result): - yield from result - else: - yield result - except Exception as ex: - cls.get_log().error('Error occurred while running CommonSuperInteraction \'{}\' _on_constraint_gen.'.format(cls.__name__), exception=ex) - - -class CommonConstrainedSuperInteraction(SuperInteraction, HasClassLog): - """An inheritable class that provides a way to create custom Super Interactions that provide custom constraints. - - .. warning:: This class is obsolete. All interaction types come with their own :func:`~on_replacement_constraints_gen` and :func:`~on_constraint_gen` functions. 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) -> Union[CommonModIdentity, None]: - return None - - def __init__(self, *_: Any, **__: Any): - super().__init__(*_, **__) - HasClassLog.__init__(self) - - @classmethod - def _test(cls, target: Any, context: InteractionContext, super_interaction: 'Interaction'=None, skip_safe_tests: bool=False, **kwargs) -> CommonTestResult: - from event_testing.results import TestResult - from s4ap.sims4communitylib.classes.time.common_stop_watch import CommonStopWatch - log = cls.get_log() - verbose_log = cls.get_verbose_log() - stop_watch = CommonStopWatch() - stop_watch.start() - try: - try: - verbose_log.format_with_message( - 'Running on_test.', - class_name=cls.__name__, - interaction_sim=context.sim, - interaction_target=target, - interaction_context=context, - super_interaction=super_interaction, - skip_safe_tests=skip_safe_tests, - kwargles=kwargs - ) - test_result = cls.on_test(context.sim, target, context, super_interaction=super_interaction, skip_safe_tests=skip_safe_tests, **kwargs) - verbose_log.format_with_message('Test Result (CommonConstrainedSuperInteraction)', test_result=test_result) - except Exception as ex: - log.error('Error occurred while running CommonConstrainedSuperInteraction \'{}\' on_test.'.format(cls.__name__), exception=ex) - return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') - - if test_result is not None: - if isinstance(test_result, CommonTestResult): - if test_result.is_success is False: - return test_result - elif isinstance(test_result, TestResult) and 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, icon=test_result.icon, influence_by_active_mood=test_result.influence_by_active_mood) - - try: - verbose_log.format_with_message( - 'Running super()._test.', - class_name=cls.__name__, - interaction_sim=context.sim, - interaction_target=target, - interaction_context=context, - super_interaction=super_interaction, - skip_safe_tests=skip_safe_tests, - kwargles=kwargs - ) - super_test_result: TestResult = super()._test(target, context, super_interaction=super_interaction, skip_safe_tests=skip_safe_tests, **kwargs) - if verbose_log.enabled: - search_for_tooltip = context.source == context.SOURCE_PIE_MENU - resolver = cls.get_resolver(target=target, context=context, super_interaction=super_interaction, search_for_tooltip=search_for_tooltip, **kwargs) - global_result = cls.test_globals.run_tests(resolver, skip_safe_tests, search_for_tooltip=search_for_tooltip) - local_result = cls.tests.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=search_for_tooltip) - if cls._additional_tests: - additional_tests = TestList(cls._additional_tests) - additional_local_result = additional_tests.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=search_for_tooltip) - else: - additional_local_result = None - if cls.test_autonomous: - autonomous_result = cls.test_autonomous.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=False) - else: - autonomous_result = None - if target is not None: - tests = target.get_affordance_tests(cls) - if tests is not None: - target_result = tests.run_tests(resolver, skip_safe_tests=skip_safe_tests, search_for_tooltip=search_for_tooltip) - else: - target_result = None - else: - target_result = None - verbose_log.format_with_message('Super Test Result (CommonConstrainedSuperInteraction)', super_test_result=super_test_result, global_result=global_result, local_result=local_result, additional_local_result=additional_local_result, autonomous_result=autonomous_result, target_result=target_result) - - if super_test_result is not None and (isinstance(test_result, TestResult) and not super_test_result.result): - return CommonTestResult.convert_from_vanilla(super_test_result) - except Exception as ex: - log.error('Error occurred while running CommonConstrainedSuperInteraction \'{}\' super()._test.'.format(cls.__name__), exception=ex) - return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') - - try: - verbose_log.format_with_message( - 'Running on_post_super_test.', - class_name=cls.__name__, - interaction_sim=context.sim, - interaction_target=target, - interaction_context=context, - super_interaction=super_interaction, - skip_safe_tests=skip_safe_tests, - kwargles=kwargs - ) - post_super_test_result = cls.on_post_super_test(context.sim, target, context, super_interaction=super_interaction, skip_safe_tests=skip_safe_tests, **kwargs) - verbose_log.format_with_message('Post Test Result (CommonConstrainedSuperInteraction)', post_super_test_result=post_super_test_result) - except Exception as ex: - log.error('Error occurred while running CommonConstrainedSuperInteraction \'{}\' on_post_super_test.'.format(cls.__name__), exception=ex) - return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') - - if post_super_test_result is not None: - if isinstance(post_super_test_result, CommonTestResult): - if post_super_test_result.is_success is False: - return post_super_test_result - elif isinstance(post_super_test_result, TestResult) and post_super_test_result.result is False: - if post_super_test_result.tooltip is not None: - post_super_test_result_tooltip = CommonLocalizationUtils.create_localized_tooltip(post_super_test_result.tooltip) - elif post_super_test_result.reason is not None: - post_super_test_result_tooltip = CommonLocalizationUtils.create_localized_tooltip(post_super_test_result.reason) - else: - post_super_test_result_tooltip = None - return cls.create_test_result(post_super_test_result.result, post_super_test_result.reason, tooltip=post_super_test_result_tooltip, icon=post_super_test_result.icon, influence_by_active_mood=post_super_test_result.influence_by_active_mood) - - return cls.create_test_result(True) - except Exception as ex: - log.error('Error occurred while running _test of CommonConstrainedSuperInteraction \'{}\''.format(cls.__name__), exception=ex) - return cls.create_test_result(False, f'An error occurred {ex}. See the log for more details. "The Sims 4/mod_logs/_Exceptions.txt"') - finally: - if verbose_log.enabled: - time_taken = CommonTextUtils.to_truncated_decimal(stop_watch.stop_milliseconds()) - verbose_log.format_with_message(f'Took {time_taken}ms to return result from CommonConstrainedSuperInteraction.', class_name=cls.__name__) - else: - stop_watch.stop() - - # noinspection PyMissingOrEmptyDocstring,PyMethodParameters - @flexmethod - def get_participants(cls, inst, participant_type: ParticipantType, sim=DEFAULT, target=DEFAULT, carry_target=DEFAULT, **kwargs): - inst_or_cls = inst or cls - log = cls.get_log() - try: - custom_participants = cls.get_custom_replacement_participants(participant_type, sim, target, carry_target, interaction=inst, **kwargs) - if custom_participants is not None: - return tuple(custom_participants) - except Exception as ex: - log.error('Error occurred while running CommonConstrainedSuperInteraction \'{}\' get_custom_replacement_participants.'.format(cls.__name__), exception=ex) - - result: Set[Any] = super(CommonConstrainedSuperInteraction, inst_or_cls).get_participants(participant_type, sim=sim, target=target, carry_target=carry_target, **kwargs) - - result = set(result) - try: - custom_participants = cls.get_custom_participants(participant_type, sim, target, carry_target, interaction=inst, **kwargs) - result.update(custom_participants) - except Exception as ex: - log.error('Error occurred while running CommonConstrainedSuperInteraction \'{}\' get_custom_participants.'.format(cls.__name__), exception=ex) - return tuple(result) - - # noinspection PyMethodParameters,PyMissingOrEmptyDocstring - @flexmethod - def get_name(cls, inst: 'CommonConstrainedSuperInteraction', target: Any=DEFAULT, context: InteractionContext=DEFAULT, **interaction_parameters) -> LocalizedString: - inst_or_cls = inst or cls - try: - context_inst_or_cls = context or inst_or_cls - interaction_sim = context_inst_or_cls.sim - interaction_target = target or context_inst_or_cls.target - - cls.get_verbose_log().format_with_message( - 'Running get_name.', - class_name=cls.__name__, - interaction_sim=interaction_sim, - interaction_target=interaction_target, - interaction=inst, - interaction_context=context - ) - override_name = cls._create_override_display_name( - interaction_sim, - interaction_target, - interaction=inst, - interaction_context=context, - **interaction_parameters - ) - if override_name is not None: - return override_name - except Exception as ex: - cls.get_log().error('An error occurred while running get_name of CommonConstrainedSuperInteraction {}'.format(cls.__name__), exception=ex) - result = super(CommonConstrainedSuperInteraction, inst_or_cls).get_name(target=target, context=context, **interaction_parameters) - if result is None: - cls.get_log().error(f'Missing a name for interaction {cls.__name__}', throw=True) - return result - - def _trigger_interaction_start_event(self: 'CommonConstrainedSuperInteraction'): - try: - self.verbose_log.format_with_message( - 'Running on_started.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target - ) - result = self.on_started(self.sim, self.target) - if result is not None and ((isinstance(result, CommonExecutionResult) and not result.is_success) or (isinstance(result, bool) and not result)): - self.cancel(FinishingType.CONDITIONAL_EXIT, str(result)) - return False - return super()._trigger_interaction_start_event() - except Exception as ex: - self.log.error('Error occurred while running CommonConstrainedSuperInteraction \'{}\' 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: - self.verbose_log.format_with_message( - 'Running modify_posture_state.', - class_name=self.__class__.__name__, - posture_state=posture_state, - participant_type=participant_type, - sim=sim - ) - (new_posture_state, new_participant_type, new_sim) = self.modify_posture_state(posture_state, participant_type=participant_type, sim=sim) - except Exception as ex: - self.log.error('Error occurred while running CommonConstrainedSuperInteraction \'{}\' 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.verbose_log.format_with_message( - 'Running on_killed.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target - ) - self.on_killed(self.sim, self.target) - except Exception as ex: - self.log.error('Error occurred while running CommonConstrainedSuperInteraction \'{}\' 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.verbose_log.format_with_message( - 'Running on_cancelled.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target, - finishing_type=finishing_type, - cancel_reason_msg=cancel_reason_msg, - kwargles=kwargs - ) - self.on_cancelled(self.sim, self.target, finishing_type, cancel_reason_msg, **kwargs) - except Exception as ex: - self.log.error('Error occurred while running CommonConstrainedSuperInteraction \'{}\' _cancel.'.format(self.__class__.__name__), exception=ex) - return super()._cancel(finishing_type, cancel_reason_msg, **kwargs) - - def on_reset(self: 'CommonConstrainedSuperInteraction'): - """on_reset() - - A function that occurs upon an interaction being reset. - - """ - try: - self.verbose_log.format_with_message( - 'Running on_reset.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target - ) - self._on_reset(self.sim, self.target) - except Exception as ex: - self.log.error('Error occurred while running CommonConstrainedSuperInteraction \'{}\' on_reset.'.format(self.__class__.__name__), exception=ex) - return super().on_reset() - - def _post_perform(self: 'CommonConstrainedSuperInteraction'): - super_result = super()._post_perform() - try: - self.verbose_log.format_with_message( - 'Running on_performed.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target - ) - self.on_performed(self.sim, self.target) - except Exception as ex: - self.log.error('Error occurred while running CommonConstrainedSuperInteraction \'{}\' _post_perform.'.format(self.__class__.__name__), exception=ex) - return super_result - - def send_current_progress(self, *args: Any, **kwargs: Any): - """send_current_progress(*args, **kwargs) - - A function that occurs upon a progress bar update. - - """ - try: - self.verbose_log.format_with_message( - 'Running _send_current_progress.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target, - argles=args, - kwargles=kwargs - ) - result = self._send_current_progress(self.sim, self.target, *args, **kwargs) - if result is not None: - return result - except Exception as ex: - self.log.error('Error occurred while running CommonConstrainedSuperInteraction \'{}\' 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: - self.verbose_log.format_with_message( - 'Running _setup_asm_default.', - class_name=self.__class__.__name__, - sim=self.sim, - target=self.target, - asm=asm, - argles=args, - kwargles=kwargs - ) - result = self._setup_asm_default(self.sim, self.target, asm, *args, **kwargs) - if result is not None: - return result - except Exception as ex: - self.log.error('Error occurred while running CommonConstrainedSuperInteraction \'{}\' setup_asm_default.'.format(self.__class__.__name__), exception=ex) - return super().setup_asm_default(asm, *args, **kwargs) - - def _run_interaction_gen(self, timeline: Timeline): - try: - self.verbose_log.format_with_message( - 'Running on_run.', - class_name=self.__class__.__name__, - interaction_sim=self.sim, - interaction_target=self.target, - timeline=timeline - ) - self.on_run(self.sim, self.target, timeline) - except Exception as ex: - self.log.error('Error occurred while running CommonConstrainedSuperInteraction \'{}\' on_run.'.format(self.__class__.__name__), exception=ex) - yield from super()._run_interaction_gen(timeline) - - # noinspection PyMethodParameters - @flexmethod - def _constraint_gen(cls, inst: 'CommonConstrainedSuperInteraction', sim: Sim, target: Any, participant_type: ParticipantType=ParticipantType.Actor, **kwargs) -> Constraint: - inst_or_cls = inst if inst is not None else cls - try: - replacement_results = cls.on_replacement_constraints_gen(inst_or_cls, sim or inst_or_cls.sim, inst_or_cls.get_constraint_target(target) or target or inst_or_cls.target) - if replacement_results is not None: - if inspect.isgenerator(replacement_results): - yield from replacement_results - else: - yield replacement_results - else: - yield from super(CommonConstrainedSuperInteraction, inst_or_cls)._constraint_gen(sim, target, participant_type=participant_type, **kwargs) - result = cls.on_constraint_gen(inst_or_cls, sim or inst_or_cls.sim, inst_or_cls.get_constraint_target(target) or target or inst_or_cls.target) - if result is not None: - if inspect.isgenerator(result): - yield from result - else: - yield result - except Exception as ex: - cls.get_log().error('Error occurred while running CommonConstrainedSuperInteraction \'{}\' _on_constraint_gen.'.format(cls.__name__), exception=ex) diff --git a/Scripts/s4ap/sims4communitylib/classes/interactions/common_terrain_interaction.py b/Scripts/s4ap/sims4communitylib/classes/interactions/common_terrain_interaction.py deleted file mode 100644 index daf1a0c..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/interactions/common_terrain_interaction.py +++ /dev/null @@ -1,108 +0,0 @@ -""" -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 -""" -import os -from typing import Any - -from interactions.context import InteractionContext -from sims.sim import Sim -from s4ap.sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction -from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult - -ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' - -# If on Read The Docs, create fake versions of extended objects to fix the error of inheriting from multiple MockObjects. -if ON_RTD: - # noinspection PyMissingOrEmptyDocstring - class MockClass(object): - # noinspection PyMissingTypeHints,PyUnusedLocal - def __init__(self, *args, **kwargs): - super(MockClass, self).__init__() - - # noinspection PyMissingTypeHints - def __call__(self, *args, **kwargs): - return None - - # noinspection PyMissingOrEmptyDocstring - class TravelMixin(MockClass): - pass - - # noinspection PyMissingOrEmptyDocstring - class TerrainInteractionMixin(MockClass): - pass - -if not ON_RTD: - from objects.terrain import TravelMixin, TerrainInteractionMixin - - -class CommonTerrainInteraction(TravelMixin, TerrainInteractionMixin, CommonImmediateSuperInteraction): - """CommonTerrainInteraction(*_, **__) - - An inheritable class that provides a way to create custom Terrain Interactions. - - .. note:: - - The main use for this class is to create interactions that appear when clicking on the ground.\ - It CAN be used for interactions that appear when clicking on Sims and Objects, but it is not recommended. - - .. 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! - - :Example: - - .. highlight:: python - .. code-block:: python - - class _ExampleTerrainInteraction(CommonTerrainInteraction): - @classmethod - def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, **kwargs) -> CommonTestResult: - result = 1 + 1 - if result == 2: - # Interaction will be displayed, but disabled, it will also have a tooltip that displays on hover with the text "Test Tooltip" - return cls.create_test_result(False, reason="Test Tooltip") - # Alternative way to specify a tooltip with the text "Test Tooltip" - # return cls.create_test_result(False, reason="No Reason", tooltip=CommonLocalizationUtils.create_localized_tooltip("Test Tooltip")) - if result == 3: - # Interaction will be hidden completely. - return CommonTestResult.NONE - # Interaction will display and be enabled. - return CommonTestResult.TRUE - - def on_started(self, interaction_sim: Sim, interaction_target: Any) -> CommonExecutionResult: - result = True - if not result: - return CommonExecutionResult.FALSE - # Put here what you want the interaction to do as soon as the player clicks it while it is enabled. - return CommonExecutionResult.TRUE - """ - pass - - -# The following is an example interaction that varies when it will display, when it will be hidden, and when it will be disabled with a tooltip. -class _ExampleTerrainInteraction(CommonTerrainInteraction): - # noinspection PyMissingOrEmptyDocstring - @classmethod - def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, **kwargs) -> CommonTestResult: - result = 1 + 1 - if result == 2: - # Interaction will be displayed, but disabled, it will also have a tooltip that displays on hover with the text "Test Tooltip" - return cls.create_test_result(False, reason="Test Tooltip") - # Alternative way to specify a tooltip with the text "Test Tooltip" - # return cls.create_test_result(False, reason="No Reason", tooltip=CommonLocalizationUtils.create_localized_tooltip("Test Tooltip")) - if result == 3: - # Interaction will be hidden completely. - return CommonTestResult.NONE - # Interaction will display and be enabled. - return CommonTestResult.TRUE - - # noinspection PyMissingOrEmptyDocstring - def on_started(self, interaction_sim: Sim, interaction_target: Any) -> CommonExecutionResult: - result = True - if not result: - return CommonExecutionResult.FALSE - # Put here what you want the interaction to do as soon as the player clicks it while it is enabled. - return CommonExecutionResult.TRUE diff --git a/Scripts/s4ap/sims4communitylib/classes/math/__init__.py b/Scripts/s4ap/sims4communitylib/classes/math/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/math/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/classes/math/common_comparison.py b/Scripts/s4ap/sims4communitylib/classes/math/common_comparison.py deleted file mode 100644 index d910023..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/math/common_comparison.py +++ /dev/null @@ -1,55 +0,0 @@ -""" -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 -""" -from typing import Any - - -class CommonComparison: - """A comparison that may be used in functions that require a CommonComparison object.""" - def compare(self, value_a: Any, value_b: Any) -> bool: - """Compare two values.""" - raise NotImplementedError() - - -class CommonComparisonEqualTo(CommonComparison): - """Check if A is equal to B.""" - - # noinspection PyMissingOrEmptyDocstring - def compare(self, value_a: Any, value_b: Any) -> bool: - return value_a == value_b - - -class CommonComparisonGreaterThan(CommonComparison): - """Check if A is greater than B.""" - - # noinspection PyMissingOrEmptyDocstring - def compare(self, value_a: Any, value_b: Any) -> bool: - return value_a > value_b - - -class CommonComparisonLessThan(CommonComparison): - """Check if A is less than B.""" - - # noinspection PyMissingOrEmptyDocstring - def compare(self, value_a: Any, value_b: Any) -> bool: - return value_a < value_b - - -class CommonComparisonGreaterThanOrEqualTo(CommonComparison): - """Check if A is greater than or equal to B.""" - - # noinspection PyMissingOrEmptyDocstring - def compare(self, value_a: Any, value_b: Any) -> bool: - return value_a >= value_b - - -class CommonComparisonLessThanOrEqualTo(CommonComparison): - """Check if A is less than or equal to B.""" - - # noinspection PyMissingOrEmptyDocstring - def compare(self, value_a: Any, value_b: Any) -> bool: - return value_a <= value_b diff --git a/Scripts/s4ap/sims4communitylib/classes/math/common_float_range.py b/Scripts/s4ap/sims4communitylib/classes/math/common_float_range.py deleted file mode 100644 index 80e79b1..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/math/common_float_range.py +++ /dev/null @@ -1,69 +0,0 @@ -""" -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 -""" -from typing import Union - - -class CommonFloatRange: - """CommonFloatRange(min_value=None, max_value=None) - - A range with a minimum and maximum for use in calculations. - - :param min_value: The minimum threshold. Set to None if there is no minimum. Default is None. - :type min_value: float, optional - :param max_value: The maximum threshold. Set to None if there is no maximum. Default is None. - :type max_value: float, optional - """ - def __init__(self, min_value: float=None, max_value: float=None): - self._min_value = min_value - self._max_value = max_value - - @property - def min_value(self) -> Union[float, None]: - """The minimum threshold of this range. - - :return: The minimum threshold of this range. - :rtype: Union[float, None] - """ - return self._min_value - - @property - def max_value(self) -> Union[float, None]: - """The maximum threshold of this range. - - :return: The maximum threshold of this range. - :rtype: Union[float, None] - """ - return self._max_value - - def in_range(self, value: float, or_equal: bool=True) -> bool: - """in_range(value, or_equal=True) - - If a Minimum and Maximum value are specified, determine if the specified value is between or equal to the Minimum and Maximum values. - If a Maximum value is not specified, determine if the specified value is greater than or equal to the Minimum value. - If a Minimum value is not specified, determine if the specified value is less than or equal to the Maximum value. - - :param value: The value to check. - :type value: float - :param or_equal: If True, the value may equal the minimum or maximum values to pass. Default is True. - :type or_equal: bool, optional - :return: True, if the value is within range of the Minimum and Maximum values. False, it not. - :rtype: bool - """ - if self.min_value is None and self.max_value is None: - return False - if self.min_value is None: - if or_equal: - return value <= self.max_value - return value < self.max_value - if self.max_value is None: - if or_equal: - return value >= self.min_value - return value > self.min_value - if or_equal: - return self.min_value <= value <= self.max_value - return self.min_value < value < self.max_value diff --git a/Scripts/s4ap/sims4communitylib/classes/math/common_integer_range.py b/Scripts/s4ap/sims4communitylib/classes/math/common_integer_range.py deleted file mode 100644 index 9accf6f..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/math/common_integer_range.py +++ /dev/null @@ -1,69 +0,0 @@ -""" -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 -""" -from typing import Union - - -class CommonIntegerRange: - """CommonIntegerRange(min_value=None, max_value=None) - - A range with a minimum and maximum for use in calculations. - - :param min_value: The minimum threshold. Set to None if there is no minimum. Default is None. - :type min_value: int, optional - :param max_value: The maximum threshold. Set to None if there is no maximum. Default is None. - :type max_value: int, optional - """ - def __init__(self, min_value: int=None, max_value: int=None): - self._min_value = min_value - self._max_value = max_value - - @property - def min_value(self) -> Union[int, None]: - """The minimum threshold of this range. - - :return: The minimum threshold of this range. - :rtype: Union[int, None] - """ - return self._min_value - - @property - def max_value(self) -> Union[int, None]: - """The maximum threshold of this range. - - :return: The maximum threshold of this range. - :rtype: Union[int, None] - """ - return self._max_value - - def in_range(self, value: int, or_equal: bool=True) -> bool: - """in_range(value, or_equal=True) - - If a Minimum and Maximum value are specified, determine if the specified value is between or equal to the Minimum and Maximum values. - If a Maximum value is not specified, determine if the specified value is greater than or equal to the Minimum value. - If a Minimum value is not specified, determine if the specified value is less than or equal to the Maximum value. - - :param value: The value to check. - :type value: int - :param or_equal: If True, the value may equal the minimum or maximum values to pass. Default is True. - :type or_equal: bool, optional - :return: True, if the value is within range of the Minimum and Maximum values. False, it not. - :rtype: bool - """ - if self.min_value is None and self.max_value is None: - return False - if self.min_value is None: - if or_equal: - return value <= self.max_value - return value < self.max_value - if self.max_value is None: - if or_equal: - return value >= self.min_value - return value > self.min_value - if or_equal: - return self.min_value <= value <= self.max_value - return self.min_value < value < self.max_value diff --git a/Scripts/s4ap/sims4communitylib/classes/math/common_location.py b/Scripts/s4ap/sims4communitylib/classes/math/common_location.py deleted file mode 100644 index 6a863e0..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/math/common_location.py +++ /dev/null @@ -1,112 +0,0 @@ -""" -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 -""" -from typing import Any, Union -from sims4.math import Location -from s4ap.sims4communitylib.classes.math.common_surface_identifier import CommonSurfaceIdentifier -from s4ap.sims4communitylib.classes.math.common_transform import CommonTransform - - -class CommonLocation: - """ A class that contains locational data. """ - - def __init__(self, transform: CommonTransform, routing_surface: CommonSurfaceIdentifier, parent_ref: Any=None, joint_name_or_hash: Any=None, slot_hash: int=0): - self._transform = transform - self._routing_surface = routing_surface - self._parent_ref = parent_ref - self._joint_name_or_hash = joint_name_or_hash - self._slot_hash = slot_hash - - @property - def transform(self) -> CommonTransform: - """ The translation and orientation of the location. - - :return: The translation and orientation of the location. - :rtype: CommonTransform - """ - return self._transform - - @property - def routing_surface(self) -> CommonSurfaceIdentifier: - """ The routing surface the location is located on. - - :return: The routing surface the location is located on. - :rtype: CommonSurfaceIdentifier - """ - return self._routing_surface - - @property - def parent_ref(self) -> Any: - """ The parent reference of the location. - - :return: The parent reference of the location. - :rtype: Any - """ - return self._parent_ref - - @property - def joint_name_or_hash(self) -> Union[str, int]: - """ The name or hash identifier of the joint the location is located at. - - :return: The name or hash identifier of the joint the location is located at. - :rtype: Union[str, int] - """ - return self._joint_name_or_hash - - @property - def slot_hash(self) -> int: - """ The hash identifier of the Slot the location is located at. - - :return: The hash identifier of the Slot the location is located at. - :rtype: int - """ - return self._slot_hash - - def __new__(cls, transform: CommonTransform, routing_surface: CommonSurfaceIdentifier, parent_ref: Any=None, joint_name_or_hash: Any=None, slot_hash: int=0) -> 'CommonLocation': - # noinspection PyTypeChecker, PyArgumentList - return Location(transform, routing_surface, parent_ref, joint_name_or_hash, slot_hash) - - @staticmethod - def empty() -> 'CommonLocation': - """empty() - - Create an empty location. - - :return: An empty location. - :rtype: CommonLocation - """ - return CommonLocation(CommonTransform.empty(), CommonSurfaceIdentifier.empty()) - - @staticmethod - def from_location(location: Union[Location, 'CommonLocation']) -> Union['CommonLocation', None]: - """from_location(location) - - Convert a vanilla Location object into a CommonLocation. - - :param location: An instance of a Location. - :type location: Union[Location, CommonLocation] - :return: An instance of a CommonLocation or None if the object failed to convert. - :rtype: Union[CommonLocation, None] - """ - if location is None: - return None - if isinstance(location, CommonLocation): - return location - if not isinstance(location, Location): - raise Exception('Failed to convert {} with type {} was not of type {}.'.format(location, type(location), type(Location))) - routing_surface = location.routing_surface if location.routing_surface is not None else CommonSurfaceIdentifier.empty( - secondary_id=location.level) - parent_ref = None - if location.parent_ref is not None and hasattr(location.parent_ref, 'provided_routing_surface'): - parent_ref = location.parent_ref - return CommonLocation( - CommonTransform.from_transform(location.transform), - CommonSurfaceIdentifier.from_surface_identifier(routing_surface), - parent_ref=parent_ref, - joint_name_or_hash=location.joint_name_or_hash, - slot_hash=location.slot_hash - ) diff --git a/Scripts/s4ap/sims4communitylib/classes/math/common_polygon.py b/Scripts/s4ap/sims4communitylib/classes/math/common_polygon.py deleted file mode 100644 index 34417ac..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/math/common_polygon.py +++ /dev/null @@ -1,101 +0,0 @@ -""" -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 -""" -from typing import Tuple, Iterator, List, Union - -from interactions.constraints import Constraint -from sims4.geometry import Polygon -from s4ap.sims4communitylib.classes.math.common_vector3 import CommonVector3 - - -class CommonPolygon: - """ A class that contains polygonal data. """ - - def __init__(self, polygon_vertices: Tuple[CommonVector3]): - self._polygon_vertices = polygon_vertices - - def __new__(cls, corners: Tuple[CommonVector3]) -> 'CommonPolygon': - return Polygon(corners) - - def __iter__(self) -> Iterator[CommonVector3]: - pass - - def __len__(self) -> int: - pass - - def __getitem__(self, item: int) -> CommonVector3: - pass - - # noinspection PyMissingOrEmptyDocstring - def normalize(self) -> None: - pass - - # noinspection PyMissingOrEmptyDocstring - def centroid(self) -> 'CommonVector3': - pass - - # noinspection PyMissingOrEmptyDocstring - def radius(self) -> float: - pass - - # noinspection PyMissingOrEmptyDocstring - def area(self) -> float: - pass - - # noinspection PyMissingOrEmptyDocstring - def bounds(self) -> Tuple[CommonVector3, CommonVector3]: - pass - - # noinspection PyMissingOrEmptyDocstring - def contains(self, point: CommonVector3) -> bool: - pass - - # noinspection PyMissingOrEmptyDocstring - def intersect(self, polygon: 'CommonPolygon') -> Constraint: - pass - - # noinspection PyMissingOrEmptyDocstring - def union(self, polygon: 'CommonPolygon') -> Constraint: - pass - - # noinspection PyMissingOrEmptyDocstring - def subtract(self, polygon: 'CommonPolygon') -> List[CommonVector3]: - pass - - # noinspection PyMissingOrEmptyDocstring - def get_convex_hull(self) -> 'CommonPolygon': - pass - - @staticmethod - def empty() -> 'CommonPolygon': - """empty() - - Create an empty Polygon. - - :return: An empty Polygon. - :rtype: CommonPolygon - """ - return CommonPolygon(tuple()) - - @staticmethod - def from_polygon(polygon: Union[Polygon, 'CommonPolygon']) -> Union['CommonPolygon', None]: - """from_polygon(polygon) - - Convert a vanilla Polygon object into a CommonPolygon. - - :param polygon: An instance of a Polygon - :type polygon: Union[Polygon, CommonPolygon] - :return: An instance of a CommonPolygon or None if the object failed to convert. - :rtype: Union[CommonLocation, None] - """ - if polygon is None: - return None - if isinstance(polygon, CommonPolygon): - return polygon - if not isinstance(polygon, Polygon): - raise Exception('Failed to convert {} with type {} was not of type {}.'.format(polygon, type(polygon), type(Polygon))) - return CommonPolygon(tuple(polygon)) diff --git a/Scripts/s4ap/sims4communitylib/classes/math/common_quaternion.py b/Scripts/s4ap/sims4communitylib/classes/math/common_quaternion.py deleted file mode 100644 index d8e7583..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/math/common_quaternion.py +++ /dev/null @@ -1,415 +0,0 @@ -""" -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 -""" -from typing import Union, Any, TYPE_CHECKING, Dict, Type -from protocolbuffers.Math_pb2 import Quaternion as MathPb2Quaternion - -if TYPE_CHECKING: - from s4ap.sims4communitylib.classes.math.common_vector3 import CommonVector3 - -# noinspection PyBroadException -try: - # noinspection PyUnresolvedReferences - from sims4.math import Quaternion, QuaternionImmutable -except: - # noinspection PyMissingOrEmptyDocstring - class QuaternionImmutable: - # noinspection PyUnusedLocal - def __init__(self, x: float, y: float, z: float, w: float): - pass - - # noinspection PyPropertyDefinition - @property - def x(self) -> float: - pass - - # noinspection PyPropertyDefinition - @property - def y(self) -> float: - pass - - # noinspection PyPropertyDefinition - @property - def z(self) -> float: - pass - - # noinspection PyPropertyDefinition - @property - def w(self) -> float: - pass - - # noinspection PyMissingOrEmptyDocstring - def transform_vector(self, vector: 'CommonVector3') -> 'CommonVector3': - pass - - # noinspection PyMissingOrEmptyDocstring - class Quaternion: - # noinspection PyUnusedLocal - def __init__(self, x: float, y: float, z: float, w: float): - pass - - # noinspection PyPropertyDefinition - @property - def x(self) -> float: - pass - - @x.setter - def x(self, value: float): - pass - - # noinspection PyPropertyDefinition - @property - def y(self) -> float: - pass - - @y.setter - def y(self, value: float): - pass - - # noinspection PyPropertyDefinition - @property - def z(self) -> float: - pass - - @z.setter - def z(self, value: float): - pass - - # noinspection PyPropertyDefinition - @property - def w(self) -> float: - pass - - @w.setter - def w(self, value: float): - pass - - # noinspection PyMissingOrEmptyDocstring - def transform_vector(self, vector: 'CommonVector3') -> 'CommonVector3': - pass - - -class CommonQuaternion: - """ A class that contains orientation data. """ - - def __init__(self, x: float, y: float, z: float, w: float) -> None: - if x is None: - x = 0.0 - if y is None: - y = 0.0 - if z is None: - z = 0.0 - if w is None: - w = 1.0 - self._x = x - self._y = y - self._z = z - self._w = w - - @property - def x(self) -> float: - """ The x position. - - :return: The x position. - :rtype: float - """ - return self._x - - @x.setter - def x(self, value: float): - self._x = value - - @property - def y(self) -> float: - """ The y position. - - :return: The y position. - :rtype: float - """ - return self._y - - @y.setter - def y(self, value: float): - self._y = value - - @property - def z(self) -> float: - """ The z position. - - :return: The z position. - :rtype: float - """ - return self._z - - @property - def w(self) -> Any: - """ The rotation. - - :return: The rotation. - :rtype: Any - """ - return self._w - - @w.setter - def w(self, value: float): - self._w = value - - def __new__(cls, x: float, y: float, z: float, w: float) -> 'CommonQuaternion': - if x is None: - x = 0.0 - if y is None: - y = 0.0 - if z is None: - z = 0.0 - if w is None: - w = 1.0 - # noinspection PyTypeChecker - return Quaternion(x, y, z, w) - - @staticmethod - def empty() -> 'CommonQuaternion': - """empty() - - Deprecated, use "identity" instead. - - Create an empty quaternion. - - :return: An empty quaternion. - :rtype: CommonQuaternion - """ - return CommonQuaternion.identity() - - @staticmethod - def identity() -> 'CommonQuaternion': - """identity() - - Create an identity quaternion. - - :return: An identity quaternion. - :rtype: CommonQuaternion - """ - return CommonQuaternion(0.0, 0.0, 0.0, 1.0) - - @staticmethod - def is_empty(quaternion: Union[Quaternion, MathPb2Quaternion, 'CommonQuaternion']) -> bool: - """is_empty(quaternion) - - Determine if a quaternion is empty or not. - - :param quaternion: The quaternion to check. - :type quaternion: Union[Quaternion, MathPb2Quaternion, CommonQuaternion] - :return: True, if the quaternion is empty. False, if not. - :rtype: bool - """ - quaternion_identity = CommonQuaternion.empty() - return quaternion.x == quaternion_identity.x and quaternion.y == quaternion_identity.y and quaternion.z == quaternion_identity.z and quaternion.w == quaternion_identity.w - - @staticmethod - def from_quaternion(quaternion: Union[Quaternion, MathPb2Quaternion, 'CommonQuaternion']) -> Union['CommonQuaternion', None]: - """from_quaternion(quaternion) - - Convert a Quaternion into a CommonQuaternion. - - :param quaternion: An instance of a Quaternion. - :type quaternion: Union[Quaternion, MathPb2Quaternion, CommonQuaternion] - :return: An instance of a CommonQuaternion or None if the object failed to convert. - :rtype: Union[CommonQuaternion, None] - """ - if quaternion is None: - return None - if isinstance(quaternion, CommonQuaternion): - return quaternion - if not isinstance(quaternion, Quaternion) and not isinstance(quaternion, QuaternionImmutable): - raise Exception('Failed to convert {} with type {} was not of type {}.'.format(quaternion, type(quaternion), type(Quaternion))) - # noinspection PyUnresolvedReferences - return CommonQuaternion(quaternion.x, quaternion.y, quaternion.z, quaternion.w) - - @staticmethod - def from_radian(radian: float) -> 'CommonQuaternion': - """from_radian(radian) - - Convert a radian value into a CommonQuaternion. - - :param radian: An angle in radians - :type radian: float - :return: An instance of a CommonQuaternion. - :rtype: CommonQuaternion - """ - from sims4.math import angle_to_yaw_quaternion - return CommonQuaternion.from_quaternion(angle_to_yaw_quaternion(radian)) - - @staticmethod - def from_degrees(degrees: float) -> 'CommonQuaternion': - """from_degrees(degrees) - - Convert an angle in degrees into a CommonQuaternion. - - :param degrees: An angle in degrees - :type degrees: float - :return: An instance of a CommonQuaternion. - :rtype: CommonQuaternion - """ - from s4ap.sims4communitylib.utils.common_math_utils import CommonMathUtils - return CommonQuaternion.from_radian(CommonMathUtils.degrees_to_radian(degrees)) - - @staticmethod - def to_radian(quaternion: Union[Quaternion, MathPb2Quaternion, 'CommonQuaternion']) -> float: - """to_radian(quaternion) - - Convert a Quaternion into radians. - - :param quaternion: An instance of a Quaternion. - :type quaternion: Union[Quaternion, MathPb2Quaternion, CommonQuaternion] - :return: The quaternion represented in radians. - :rtype: float - """ - if quaternion is None: - return 0.0 - from sims4.math import yaw_quaternion_to_angle - return yaw_quaternion_to_angle(quaternion) - - @staticmethod - def to_degrees(quaternion: Union[Quaternion, MathPb2Quaternion, 'CommonQuaternion']) -> float: - """to_degrees(quaternion) - - Convert a Quaternion into degrees. - - :param quaternion: An instance of a Quaternion. - :type quaternion: Union[Quaternion, MathPb2Quaternion, CommonQuaternion] - :return: The quaternion represented in degrees. - :rtype: float - """ - if quaternion is None: - return 0.0 - from s4ap.sims4communitylib.utils.common_math_utils import CommonMathUtils - return CommonMathUtils.radian_to_degrees(CommonQuaternion.to_radian(quaternion)) - - def __add__(self, other: Union[Quaternion, MathPb2Quaternion, 'CommonQuaternion', float]) -> 'CommonQuaternion': - # The functionality lies inside Quaternion - pass - - def __sub__(self, other: Union[Quaternion, MathPb2Quaternion, 'CommonQuaternion', float]) -> 'CommonQuaternion': - # The functionality lies inside Quaternion - pass - - @staticmethod - def rotate_vector(quaternion: Union[Quaternion, MathPb2Quaternion, 'CommonQuaternion'], vector: 'CommonVector3') -> Any: - """rotate_vector(quaternion, vector) - - Rotate a vector with a quaternion. - - :param quaternion: The quaternion to use for rotation. - :type quaternion: Union[Quaternion, MathPb2Quaternion, CommonQuaternion] - :param vector: The vector to rotate. - :type vector: CommonVector3 - :return: A normalized Quaternion. - :rtype: CommonQuaternion - """ - from s4ap.sims4communitylib.classes.math.common_vector3 import CommonVector3 - q = CommonQuaternion.multiply(CommonQuaternion.multiply(quaternion, CommonQuaternion(vector.x, vector.y, vector.z, 0.0)), CommonQuaternion.conjugate(quaternion)) # q.w will be zero. - return CommonVector3(q.x, q.y, q.z) - - @staticmethod - def normalize(quaternion: Union[Quaternion, MathPb2Quaternion, 'CommonQuaternion'], tolerance: float = 0.00001) -> 'CommonQuaternion': - """normalize(quaternion, tolerance=0.00001) - - Normalize a quaternion. - - :param quaternion: The quaternion to normalize. - :type quaternion: Union[Quaternion, MathPb2Quaternion, CommonQuaternion] - :param tolerance: The tolerance level for normalization. Default is 0.00001. - :type tolerance: float, optional - :return: A normalized Quaternion. - :rtype: CommonQuaternion - """ - import math - mag2 = (quaternion.x * quaternion.x) + (quaternion.y * quaternion.y) + (quaternion.z * quaternion.z) + (quaternion.w * quaternion.w) - if mag2 == 0: - return quaternion - mag3 = abs(1 - mag2) - if mag3 > tolerance: - mag = math.sqrt(mag2) - new_x = (quaternion.x / mag) - new_y = (quaternion.y / mag) - new_z = (quaternion.z / mag) - new_w = (quaternion.w / mag) - return CommonQuaternion(new_x, new_y, new_z, new_w) - return quaternion - - @staticmethod - def conjugate(quaternion: Union[Quaternion, MathPb2Quaternion, 'CommonQuaternion']) -> 'CommonQuaternion': - """conjugate(quaternion) - - Conjugate a quaternion. - - :param quaternion: The quaternion to conjugate. - :type quaternion: Union[Quaternion, MathPb2Quaternion, CommonQuaternion] - :return: A conjugated Quaternion. - :rtype: CommonQuaternion - """ - return CommonQuaternion(-quaternion.x, -quaternion.y, -quaternion.z, quaternion.w) - - @staticmethod - def __truediv__(quaternion: Union[Quaternion, MathPb2Quaternion, 'CommonQuaternion'], quaternion_other: Union[Quaternion, MathPb2Quaternion, 'CommonQuaternion']) -> 'CommonQuaternion': - return CommonQuaternion.normalize(CommonQuaternion.divide(quaternion, quaternion_other)) - - @staticmethod - def __mul__(quaternion: Union[Quaternion, MathPb2Quaternion, 'CommonQuaternion'], quaternion_other: Union[Quaternion, MathPb2Quaternion, 'CommonQuaternion']) -> 'CommonQuaternion': - return CommonQuaternion.normalize(CommonQuaternion.multiply(quaternion, quaternion_other)) - - @staticmethod - def divide(quaternion: Union[Quaternion, MathPb2Quaternion, 'CommonQuaternion'], quaternion_other: Union[Quaternion, MathPb2Quaternion, 'CommonQuaternion']): - """divide(quaternion, quaternion_other) - - Divides two quaternions without normalizing the result. Use `q = q1 / q2` for a normalized result. - - :param quaternion: The quaternion to be divided. - :type quaternion: Union[Quaternion, MathPb2Quaternion, CommonQuaternion] - :param quaternion_other: The quaternion to divide with. - :type quaternion_other: Union[Quaternion, MathPb2Quaternion, CommonQuaternion] - :return: A divided Quaternion. - :rtype: CommonQuaternion - """ - return CommonQuaternion.multiply(quaternion, CommonQuaternion.conjugate(quaternion_other)) - - @staticmethod - def multiply(quaternion: Union[Quaternion, MathPb2Quaternion, 'CommonQuaternion'], quaternion_other: Union[Quaternion, MathPb2Quaternion, 'CommonQuaternion']) -> 'CommonQuaternion': - """multiply(quaternion, quaternion_other) - - Multiplies two quaternions without normalizing the result. Use `q = q1 * q2` for a normalized result. - - :param quaternion: The quaternion to be multiplied. - :type quaternion: Union[Quaternion, MathPb2Quaternion, CommonQuaternion] - :param quaternion_other: The quaternion to multiply with. - :type quaternion_other: Union[Quaternion, MathPb2Quaternion, CommonQuaternion] - :return: A divided Quaternion. - :rtype: CommonQuaternion - """ - x = (quaternion.w * quaternion_other.x) + (quaternion.x * quaternion_other.w) + (quaternion.y * quaternion_other.z) - (quaternion.z * quaternion_other.y) - y = (quaternion.w * quaternion_other.y) - (quaternion.x * quaternion_other.z) + (quaternion.y * quaternion_other.w) + (quaternion.z * quaternion_other.x) - z = (quaternion.w * quaternion_other.z) + (quaternion.x * quaternion_other.y) - (quaternion.y * quaternion_other.x) + (quaternion.z * quaternion_other.w) - w = (quaternion.w * quaternion_other.w) - (quaternion.x * quaternion_other.x) - (quaternion.y * quaternion_other.y) - (quaternion.z * quaternion_other.z) - return CommonQuaternion(x, y, z, w) - - # noinspection PyMissingOrEmptyDocstring - @staticmethod - def serialize(quaternion: Union[Quaternion, MathPb2Quaternion, 'CommonQuaternion']) -> Union[str, Dict[str, Any]]: - data = dict() - data['x'] = quaternion.x - data['y'] = quaternion.y - data['z'] = quaternion.z - data['w'] = quaternion.w - return data - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def deserialize(cls: Type['CommonQuaternion'], data: Union[str, Dict[str, Any]]) -> Union['CommonQuaternion', None]: - x = data.get('x', 0.0) - y = data.get('y', 0.0) - z = data.get('z', 0.0) - w = data.get('w', 1.0) - return CommonQuaternion(x, y, z, w) diff --git a/Scripts/s4ap/sims4communitylib/classes/math/common_routing_location.py b/Scripts/s4ap/sims4communitylib/classes/math/common_routing_location.py deleted file mode 100644 index 299edd2..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/math/common_routing_location.py +++ /dev/null @@ -1,110 +0,0 @@ -""" -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 -""" -from typing import Union, TYPE_CHECKING -from sims4.math import Location as Math_Location -from routing import Location -from s4ap.sims4communitylib.classes.math.common_quaternion import CommonQuaternion -from s4ap.sims4communitylib.classes.math.common_surface_identifier import CommonSurfaceIdentifier -from s4ap.sims4communitylib.classes.math.common_vector3 import CommonVector3 - -if TYPE_CHECKING: - from s4ap.sims4communitylib.classes.math.common_location import CommonLocation - - -class CommonRoutingLocation: - """CommonRoutingLocation(position, orientation=None, routing_surface=None) - - A Location used for routing. - - :param position: The position of the location. - :type position: CommonVector3 - :param orientation: The orientation of the location. Default is None. - :type orientation: CommonQuaternion, optional - :param routing_surface: The routing surface of the location. Default is None. - :type routing_surface: CommonSurfaceIdentifier, optional - """ - def __init__(self, position: CommonVector3, orientation: CommonQuaternion=None, routing_surface: CommonSurfaceIdentifier=None): - super().__init__(position, orientation, routing_surface) - self._position = position - self._orientation = orientation - self._routing_surface = routing_surface - - @property - def position(self) -> CommonVector3: - """The translation and orientation of the location. - - :return: The translation and orientation of the location. - :rtype: CommonTransform - """ - return self._position - - @property - def orientation(self) -> CommonQuaternion: - """The orientation of the location. - - :return: The orientation of the Location. - :rtype: CommonQuaternion - """ - return self._orientation - - @property - def routing_surface(self) -> CommonSurfaceIdentifier: - """The routing surface the location is located on. - - :return: The routing surface the location is located on. - :rtype: CommonSurfaceIdentifier - """ - return self._routing_surface - - def __new__(cls, position: CommonVector3, orientation: CommonQuaternion=None, routing_surface: CommonSurfaceIdentifier=None) -> 'CommonRoutingLocation': - # noinspection PyTypeChecker - return Location(position, orientation, routing_surface) - - @staticmethod - def empty() -> 'CommonRoutingLocation': - """empty() - - Create an empty location. - - :return: An empty location. - :rtype: CommonRoutingLocation - """ - return CommonRoutingLocation(CommonVector3.empty(), orientation=CommonQuaternion.empty(), routing_surface=CommonSurfaceIdentifier.empty()) - - @staticmethod - def from_location(location: Union[Location, Math_Location, 'CommonLocation', 'CommonRoutingLocation']) -> Union['CommonRoutingLocation', None]: - """from_location(location) - - Convert a vanilla Location object into a CommonRoutingLocation. - - :param location: An instance of a Location. - :type location: Union[routing.Location, sims4.math.Location, CommonLocation, CommonRoutingLocation] - :return: An instance of a CommonRoutingLocation or None if the object failed to convert. - :rtype: Union[CommonRoutingLocation, None] - """ - from s4ap.sims4communitylib.classes.math.common_location import CommonLocation - if location is None: - return None - if isinstance(location, CommonRoutingLocation): - return location - if isinstance(location, Location): - return CommonRoutingLocation(location.position, location.orientation, location.routing_surface) - if not isinstance(location, Math_Location) and not isinstance(location, CommonLocation): - raise Exception('Failed to convert {} with type {} was not of type {}.'.format(location, type(location), type(Math_Location))) - routing_surface = location.routing_surface if location.routing_surface is not None else CommonSurfaceIdentifier.empty() - return CommonRoutingLocation(CommonVector3.from_vector3(location.transform.translation), orientation=CommonQuaternion.from_quaternion(location.transform.orientation), routing_surface=CommonSurfaceIdentifier.from_surface_identifier(routing_surface)) - - def get_world_surface_location(self) -> 'CommonRoutingLocation': - """get_world_surface_location(self) - - Retrieve the Location as a world surface location. - - :return: A world surface location. - :rtype: CommonRoutingLocation - """ - pass diff --git a/Scripts/s4ap/sims4communitylib/classes/math/common_surface_identifier.py b/Scripts/s4ap/sims4communitylib/classes/math/common_surface_identifier.py deleted file mode 100644 index 2c0a4f8..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/math/common_surface_identifier.py +++ /dev/null @@ -1,94 +0,0 @@ -""" -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 -""" -from typing import Union -from routing import SurfaceType, SurfaceIdentifier - - -class CommonSurfaceIdentifier: - """ A class that contains surface data. """ - - def __init__(self, primary_id: int, secondary_id: int=None, surface_type: SurfaceType=SurfaceType.SURFACETYPE_WORLD): - self._primary_id = primary_id - self._secondary_id = secondary_id - self._surface_type = surface_type - - @property - def primary_id(self) -> int: - """ The primary identifier for the surface. This value is usually the identifier of a Zone. - - :return: The primary identifier. - :rtype: int - """ - return self._primary_id - - @primary_id.setter - def primary_id(self, value: int): - self._primary_id = value - - @property - def secondary_id(self) -> Union[int, None]: - """ The secondary identifier for the surface. This value is usually the level at which the surface is. - - :return: The secondary identifier. - :rtype: Union[int, None] - """ - return self._secondary_id - - @secondary_id.setter - def secondary_id(self, value: Union[int, None]): - self._secondary_id = value - - @property - def type(self) -> Union[SurfaceType, None]: - """ The type of surface. - - :return: The type of surface. - :rtype: Union[SurfaceType, None] - """ - return self._surface_type - - @type.setter - def type(self, value: Union[SurfaceType, None]): - self._surface_type = value - - def __new__(cls, primary_id: int, secondary_id: int=None, surface_type: SurfaceType=SurfaceType.SURFACETYPE_WORLD) -> 'CommonSurfaceIdentifier': - # noinspection PyTypeChecker - return SurfaceIdentifier(primary_id, secondary_id, surface_type) - - @staticmethod - def empty(secondary_id: int=0) -> 'CommonSurfaceIdentifier': - """empty(secondary_id=0) - - Create an empty surface identifier for the current zone. - - :param secondary_id: The secondary id to give to the surface identifier. Default is 0. - :type secondary_id: int, optional - :return: An empty surface identifier. - :rtype: CommonSurfaceIdentifier - """ - from s4ap.sims4communitylib.utils.location.common_location_utils import CommonLocationUtils - return CommonSurfaceIdentifier(CommonLocationUtils.get_current_zone_id(), secondary_id=secondary_id) - - @staticmethod - def from_surface_identifier(surface_identifier: Union[SurfaceIdentifier, 'CommonSurfaceIdentifier']) -> Union['CommonSurfaceIdentifier', None]: - """from_surface_identifier(surface_identifier) - - Convert a SurfaceIdentifier into a CommonSurfaceIdentifier. - - :param surface_identifier: An instance of a surface identifier. - :type surface_identifier: Union[SurfaceIdentifier, CommonSurfaceIdentifier] - :return: An instance of a CommonSurfaceIdentifier or None if it failed to convert. - :rtype: Union[CommonSurfaceIdentifier, None] - """ - if surface_identifier is None: - return None - if isinstance(surface_identifier, CommonSurfaceIdentifier): - return surface_identifier - if not isinstance(surface_identifier, SurfaceIdentifier): - raise Exception('Failed to convert {} with type {} was not of type {}.'.format(surface_identifier, type(surface_identifier), type(SurfaceIdentifier))) - return CommonSurfaceIdentifier(surface_identifier.primary_id, secondary_id=surface_identifier.secondary_id, surface_type=surface_identifier.type) diff --git a/Scripts/s4ap/sims4communitylib/classes/math/common_transform.py b/Scripts/s4ap/sims4communitylib/classes/math/common_transform.py deleted file mode 100644 index d20dcee..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/math/common_transform.py +++ /dev/null @@ -1,102 +0,0 @@ -""" -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 -""" -from typing import Union, Any -from protocolbuffers.Math_pb2 import Transform as MathPb2Transform - -from s4ap.sims4communitylib.classes.math.common_quaternion import CommonQuaternion -from s4ap.sims4communitylib.classes.math.common_vector3 import CommonVector3 - -# noinspection PyBroadException -try: - # noinspection PyUnresolvedReferences - from sims4.math import Transform -except: - # noinspection PyMissingOrEmptyDocstring - class Transform: - # noinspection PyUnusedLocal - def __init__(self, translation: Any, orientation: Any): - pass - - # noinspection PyPropertyDefinition - @property - def translation(self) -> Any: - pass - - # noinspection PyPropertyDefinition - @property - def orientation(self) -> Any: - pass - - -class CommonTransform: - """ A class that contains transformational data. """ - - def __init__(self, translation: CommonVector3, orientation: CommonQuaternion): - self._translation = translation - self._orientation = orientation - - @property - def translation(self) -> CommonVector3: - """ The translation. - - :return: The translation. - :rtype: CommonVector3 - """ - return self._translation - - @translation.setter - def translation(self, value: CommonVector3): - self._translation = value - - @property - def orientation(self) -> CommonQuaternion: - """ The orientation. - - :return: The orientation. - :rtype: CommonQuaternion - """ - return self._orientation - - @orientation.setter - def orientation(self, value: CommonQuaternion): - self._orientation = value - - def __new__(cls, translation: CommonVector3, orientation: CommonQuaternion) -> 'CommonTransform': - # noinspection PyTypeChecker - return Transform(translation, orientation) - - @staticmethod - def empty() -> 'CommonTransform': - """empty() - - Create an empty transform. - - :return: An empty transform. - :rtype: CommonTransform - """ - return CommonTransform(CommonVector3.empty(), CommonQuaternion.empty()) - - @staticmethod - def from_transform(transform: Union[Transform, MathPb2Transform, 'CommonTransform']) -> Union['CommonTransform', None]: - """from_transform(transform) - - Convert a Transform into a CommonTransform. - - :param transform: An instance of a transform. - :type transform: Union[Transform, MathPb2Transform, CommonTransform] - :return: An instance of a CommonTransform or None if it failed to convert. - :rtype: Union[CommonTransform, None] - """ - if transform is None: - return None - if isinstance(transform, CommonTransform): - return transform - if not isinstance(transform, Transform) and not isinstance(transform, MathPb2Transform): - raise Exception('Failed to convert {} with type {} was not of type {}.'.format(transform, type(transform), type(Transform))) - # noinspection PyUnresolvedReferences - return CommonTransform(CommonVector3.from_vector3(transform.translation), CommonQuaternion.from_quaternion(transform.orientation)) diff --git a/Scripts/s4ap/sims4communitylib/classes/math/common_vector3.py b/Scripts/s4ap/sims4communitylib/classes/math/common_vector3.py deleted file mode 100644 index 91de528..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/math/common_vector3.py +++ /dev/null @@ -1,298 +0,0 @@ -""" -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 -""" -from typing import Union, Type, Dict, Any -from protocolbuffers.Math_pb2 import Vector3 as MathPb2Vector3 - -# noinspection PyBroadException -try: - # noinspection PyUnresolvedReferences - from sims4.math import Vector3, Vector3Immutable -except: - # noinspection PyMissingOrEmptyDocstring - class Vector3Immutable: - # noinspection PyUnusedLocal - def __init__(self, x: float, y: float, z: float): - pass - - # noinspection PyPropertyDefinition - @property - def x(self) -> float: - pass - - # noinspection PyPropertyDefinition - @property - def y(self) -> float: - pass - - # noinspection PyPropertyDefinition - @property - def z(self) -> float: - pass - - # noinspection PyMissingOrEmptyDocstring - class Vector3: - # noinspection PyUnusedLocal - def __init__(self, x: float, y: float, z: float): - pass - - # noinspection PyPropertyDefinition - @property - def x(self) -> float: - pass - - @x.setter - def x(self, value: float): - pass - - # noinspection PyPropertyDefinition - @property - def y(self) -> float: - pass - - @y.setter - def y(self, value: float): - pass - - # noinspection PyPropertyDefinition - @property - def z(self) -> float: - pass - - @z.setter - def z(self, value: float): - pass - - -class CommonVector3: - """ A class that contains positional data with three coordinates. """ - def __init__(self, x: float, y: float, z: float): - if x is None: - x = 0.0 - if y is None: - y = 0.0 - if z is None: - z = 0.0 - self._x = x - self._y = y - self._z = z - - @property - def x(self) -> float: - """ The x position. - - :return: The x position. - :rtype: float - """ - return self._x - - @x.setter - def x(self, value: float): - self._x = value - - @property - def y(self) -> float: - """ The y position. - - :return: The y position. - :rtype: float - """ - return self._y - - @y.setter - def y(self, value: float): - self._y = value - - @property - def z(self) -> float: - """ The z position. - - :return: The z position. - :rtype: float - """ - return self._z - - @z.setter - def z(self, value: float): - self._z = value - - def __new__(cls, x: float, y: float, z: float) -> 'CommonVector3': - if x is None: - x = 0.0 - if y is None: - y = 0.0 - if z is None: - z = 0.0 - # noinspection PyTypeChecker - return Vector3(x, y, z) - - @staticmethod - def empty() -> 'CommonVector3': - """empty() - - Create an empty vector. - - :return: An empty vector. - :rtype: CommonVector3 - """ - return CommonVector3(0.0, 0.0, 0.0) - - @staticmethod - def is_empty(vector: Union[Vector3, Vector3Immutable, MathPb2Vector3, 'CommonVector3']) -> bool: - """is_empty(vector) - - Determine if a vector is empty or not. - - :param vector: The vector to check. - :type vector: Union[Vector3, Vector3Immutable, MathPb2Vector3, CommonVector3] - :return: True, if the vector is empty. False, if not. - :rtype: bool - """ - empty_vector = CommonVector3.empty() - return vector.x == empty_vector.x and vector.y == empty_vector.y and vector.z == empty_vector.z - - @staticmethod - def from_vector3(vector: Union[Vector3, Vector3Immutable, MathPb2Vector3, 'CommonVector3']) -> Union['CommonVector3', None]: - """from_vector3(vector) - - Convert a Vector into a CommonVector3. - - :param vector: An instance of a vector. - :type vector: Union[Vector3, Vector3Immutable, MathPb2Vector3, CommonVector3] - :return: An instance of a CommonVector3 or None if it failed to convert. - :rtype: Union[CommonVector3, None] - """ - if vector is None: - raise ValueError('Cannot convert {} to {}.'.format(vector, CommonVector3.__name__)) - if isinstance(vector, CommonVector3): - return vector - if not isinstance(vector, Vector3) and not isinstance(vector, Vector3Immutable) and not isinstance(vector, MathPb2Vector3): - raise Exception('Failed to convert {} with type {} was not of type {}.'.format(vector, type(vector), type(Vector3))) - # noinspection PyUnresolvedReferences - return CommonVector3(vector.x, vector.y, vector.z) - - @staticmethod - def flatten(vector: Union[Vector3, Vector3Immutable, MathPb2Vector3, 'CommonVector3']) -> 'CommonVector3': - """flatten(vector) - - Flatten a Vector. - - :param vector: An instance of a vector. - :type vector: Union[Vector3, Vector3Immutable, MathPb2Vector3, CommonVector3] - :return: An instance of a flattened CommonVector3. - :rtype: CommonVector3 - """ - if vector is None: - raise AttributeError('{} was called with vector as None!'.format(CommonVector3.flatten.__name__)) - from sims4.math import vector_flatten - return CommonVector3.from_vector3(vector_flatten(vector)) - - @staticmethod - def normalize(vector: 'CommonVector3') -> float: - """normalize(vector) - - Normalize a Vector. - - :param vector: An instance of a vector. - :type vector: Union[Vector3, Vector3Immutable, MathPb2Vector3, CommonVector3] - :return: An instance of a normalized CommonVector3. - :rtype: float - """ - from sims4.math import vector_normalize - return vector_normalize(vector) - - @staticmethod - def distance_between( - position_one: Union[Vector3, Vector3Immutable, MathPb2Vector3, 'CommonVector3'], - position_two: Union[Vector3, Vector3Immutable, MathPb2Vector3, 'CommonVector3'] - ) -> float: - """distance_between(position_one, position_two) - - Calculate the distance between two vectors. - - :param position_one: An instance of a Vector. - :type position_one: CommonVector3 - :param position_two: An instance of a Vector. - :type position_two: CommonVector3 - :return: The distance between the two specified vectors. - :rtype: float - """ - if position_one is None: - raise AttributeError('{} was called with position_one as None!'.format(CommonVector3.distance_between.__name__)) - if position_two is None: - raise AttributeError('{} was called with position_two as None!'.format(CommonVector3.distance_between.__name__)) - from math import sqrt - return sqrt((position_one - position_two).magnitude_squared()) - - # noinspection PyMissingOrEmptyDocstring - def magnitude_squared(self) -> float: - # The functionality lies inside Vector3 - pass - - def __add__(self, other: Union[Vector3, Vector3Immutable, MathPb2Vector3, 'CommonVector3', float]) -> 'CommonVector3': - # The functionality lies inside Vector3 - pass - - def __sub__(self, other: Union[Vector3, Vector3Immutable, MathPb2Vector3, 'CommonVector3', float]) -> 'CommonVector3': - # The functionality lies inside Vector3 - pass - - def __mul__(self, other: Union[Vector3, Vector3Immutable, MathPb2Vector3, 'CommonVector3', float]) -> 'CommonVector3': - # The functionality lies inside Vector3 - pass - - def __le__(self, other: Union[Vector3, Vector3Immutable, MathPb2Vector3, 'CommonVector3']) -> bool: - # The functionality lies inside Vector3 - pass - - def __lt__(self, other: Union[Vector3, Vector3Immutable, MathPb2Vector3, 'CommonVector3']) -> bool: - # The functionality lies inside Vector3 - pass - - def __ge__(self, other: Union[Vector3, Vector3Immutable, MathPb2Vector3, 'CommonVector3']) -> bool: - # The functionality lies inside Vector3 - pass - - def __gt__(self, other: Union[Vector3, Vector3Immutable, MathPb2Vector3, 'CommonVector3']) -> bool: - # The functionality lies inside Vector3 - pass - - def __hash__(self) -> int: - # The functionality lies inside Vector3 - pass - - def __ne__(self, other: Union[Vector3, Vector3Immutable, MathPb2Vector3, 'CommonVector3']) -> bool: - # The functionality lies inside Vector3 - pass - - def __eq__(self, other: Union[Vector3, Vector3Immutable, MathPb2Vector3, 'CommonVector3']) -> bool: - # The functionality lies inside Vector3 - pass - - def __repr__(self) -> str: - # The functionality lies inside Vector3 - pass - - def __str__(self) -> str: - pass - - # noinspection PyMissingOrEmptyDocstring - @staticmethod - def serialize(vector: Union[Vector3, Vector3Immutable, MathPb2Vector3, 'CommonVector3']) -> Union[str, Dict[str, Any]]: - data = dict() - data['x'] = vector.x - data['y'] = vector.y - data['z'] = vector.z - return data - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def deserialize(cls: Type['CommonVector3'], data: Union[str, Dict[str, Any]]) -> Union['CommonVector3', None]: - x = data.get('x', 0.0) - y = data.get('y', 0.0) - z = data.get('z', 0.0) - return CommonVector3(x, y, z) diff --git a/Scripts/s4ap/sims4communitylib/classes/math/common_weighted_value.py b/Scripts/s4ap/sims4communitylib/classes/math/common_weighted_value.py deleted file mode 100644 index 8cddd8c..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/math/common_weighted_value.py +++ /dev/null @@ -1,56 +0,0 @@ -""" -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 -""" - - -class CommonWeightedValue: - """ A value with a weight. To be used in conjunction with other CommonWeightedValueTally. """ - def __init__(self, value: float=0.0, weight: float=1.0): - if value is None: - raise AssertionError('Value is None') - if weight is None: - raise AssertionError('Weight is None') - self._value = value - self._weight = weight - - @property - def value(self) -> float: - """ The value. """ - return self._value - - @property - def weight(self) -> float: - """ The weight. """ - return self._weight - - def __add__(self, other: 'CommonWeightedValue') -> 'CommonWeightedValue': - return CommonWeightedValue(value=self.value + other.value, weight=self.weight + other.weight) - - def __sub__(self, other: 'CommonWeightedValue') -> 'CommonWeightedValue': - return CommonWeightedValue(value=self.value - other.value, weight=self.weight - other.weight) - - def __mul__(self, other: 'CommonWeightedValue') -> 'CommonWeightedValue': - return CommonWeightedValue(value=self.value * other.value, weight=self.weight * other.weight) - - def has_value(self) -> bool: - """ Determine if this weighted value has a value. """ - return self.value != 0.0 - - def has_weight(self) -> bool: - """ Determine if this weighted value has a weight. """ - return self.weight > 0.0 - - @staticmethod - def create_empty() -> 'CommonWeightedValue': - """ Create an empty CommonWeightedValue. """ - return CommonWeightedValue(value=0.0, weight=1.0) - - def __str__(self) -> str: - return 'Weighted Value:\n Value: {}\n Weight: {}'.format(self.value, self.weight) - - def __repr__(self) -> str: - return 'value_{}_weight_{}'.format(repr(self.value), repr(self.weight)) diff --git a/Scripts/s4ap/sims4communitylib/classes/math/common_weighted_value_tally.py b/Scripts/s4ap/sims4communitylib/classes/math/common_weighted_value_tally.py deleted file mode 100644 index e1f4188..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/math/common_weighted_value_tally.py +++ /dev/null @@ -1,38 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.classes.math.common_weighted_value import CommonWeightedValue - - -class CommonWeightedValueTally: - """ A tally that keeps track of weighted values. """ - def __init__(self) -> None: - self._value: CommonWeightedValue = CommonWeightedValue(value=0.0, weight=0.0) - self._value_count: int = 0 - self._weight_count: int = 0 - - def add_value(self, common_weighted_value: CommonWeightedValue): - """ Add to the tally. """ - if common_weighted_value is None: - return - if common_weighted_value.has_value(): - self._value_count += 1 - if common_weighted_value.has_weight(): - self._weight_count += 1 - self._value += common_weighted_value - - def get_total_value(self) -> float: - """ Tally up all weighted values and calculate the total. """ - total_value = self._value.value / max(1, self._value_count) - total_weight = self._value.weight / max(1, self._weight_count) - return total_value * total_weight - - def __str__(self) -> str: - return 'Tally:\n Value: {}\n Weight: {}\n Value Count: {}\n Weight Count: {}'.format(self._value.value, self._value.weight, self._value_count, self._weight_count) - - def __repr__(self) -> str: - return 'tally_{}_value_count_{}_weight_count_{}'.format(repr(self._value), self._value_count, self._weight_count) diff --git a/Scripts/s4ap/sims4communitylib/classes/mixins/__init__.py b/Scripts/s4ap/sims4communitylib/classes/mixins/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/mixins/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/classes/mixins/common_affordance_lists_mixin.py b/Scripts/s4ap/sims4communitylib/classes/mixins/common_affordance_lists_mixin.py deleted file mode 100644 index 73c17b2..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/mixins/common_affordance_lists_mixin.py +++ /dev/null @@ -1,21 +0,0 @@ -""" -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 -""" -from typing import Tuple - - -class CommonAffordanceListsMixin: - """A mixin that will do something with affordance lists.""" - - @property - def affordance_list_ids(self) -> Tuple[int]: - """A collection of identifiers for affordance lists. - - :return: A collection of identifiers for affordance lists. - :rtype: Tuple[int] - """ - raise NotImplementedError() diff --git a/Scripts/s4ap/sims4communitylib/classes/mixins/common_interactions_mixin.py b/Scripts/s4ap/sims4communitylib/classes/mixins/common_interactions_mixin.py deleted file mode 100644 index 49c40bf..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/mixins/common_interactions_mixin.py +++ /dev/null @@ -1,40 +0,0 @@ -""" -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 -""" -from typing import Tuple, Iterator - -from interactions.base.interaction import Interaction - - -class CommonInteractionsMixin: - """A mixin that will do something with interactions.""" - - def __init__(self) -> None: - self._cached_interactions = None - - @property - def interaction_ids(self) -> Tuple[int]: - """A collection of interaction identifiers. - - :return: A collection of interaction identifiers. - :rtype: Tuple[int] - """ - raise NotImplementedError() - - def _interaction_instances_gen(self) -> Iterator[Interaction]: - if self._cached_interactions is not None: - yield from self._cached_interactions - else: - cached_interactions = list() - from s4ap.sims4communitylib.utils.resources.common_interaction_utils import CommonInteractionUtils - for interaction_id in self.interaction_ids: - interaction = CommonInteractionUtils.load_interaction_by_id(interaction_id) - if interaction is None: - continue - yield interaction - cached_interactions.append(interaction) - self._cached_interactions = cached_interactions diff --git a/Scripts/s4ap/sims4communitylib/classes/options.py b/Scripts/s4ap/sims4communitylib/classes/options.py deleted file mode 100644 index dde1ffb..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/options.py +++ /dev/null @@ -1,117 +0,0 @@ -""" -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 -""" -from typing import Dict, Any - - -class CommonOption: - """CommonOption(name) - - Useful for giving a type to arguments when str just won't cut it. - - :param name: The name of the option. It is also considered as the value of the option. - :type name: str - """ - def __init__(self, name: str): - self._name = name - - @property - def name(self) -> str: - """The name and string value of the option. - - :return: The name of the option. - :rtype: str - """ - return self._name - - def __hash__(self) -> int: - return hash((self.name,)) - - def __eq__(self, other) -> bool: - return self.name == other.name - - def __ne__(self, other) -> bool: - return not(self == other) - - def __repr__(self) -> str: - return self._name - - def __str__(self) -> str: - return self.__repr__() - - -class HasCommonOptions: - """HasCommonOptions(options) - - An inheritable class that provides a dictionary of custom options. - - :param options: The options contained within the class. - :type options: Dict[CommonOption, Any] - """ - def __init__(self, options: Dict[CommonOption, Any]): - self._options = dict() - if options is not None: - for key, val in options.items(): - self.set_option(key, val) - - @property - def options(self) -> Dict[str, Any]: - """Retrieve all options. - - :return: A dictionary of options. - :rtype: Dict[str, Any] - """ - if self._options is None: - self._options = dict() - return self._options - - @options.setter - def options(self, options: Dict[str, Any]): - self._options = options - - def set_option(self, option: CommonOption, value: Any): - """set_option(option, value) - - Set an option to have the specified value. - - :param option: The option to set the value of. - :type option: CommonOption - :param value: The value to set an option to. - :type value: Any - """ - self._options[str(option)] = value - - def remove_option(self, option: CommonOption): - """remove_option(option) - - Remove an option. - - :param option: The option to delete. - :type option: CommonOption - """ - del self._options[str(option)] - - def get_option(self, option: CommonOption, default_value: Any=None) -> Any: - """get_option(option, default_value=None) - - Retrieve the value of an option. - - :param option: The option to retrieve. - :type option: CommonOption - :param default_value: A default value to return when an option does not exist. Default is None. - :type default_value: Any - :return: An option or the default value if not found. - :rtype: Any - """ - if str(option) not in self.options and default_value is not None: - self.set_option(option, default_value) - return self.options[str(option)] - - -class _DefaultCommonOption(CommonOption): - def __init__(self, name: str): - super().__init__(name or 'Default') diff --git a/Scripts/s4ap/sims4communitylib/classes/resolvers/__init__.py b/Scripts/s4ap/sims4communitylib/classes/resolvers/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/resolvers/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/classes/resolvers/common_double_sim_resolver.py b/Scripts/s4ap/sims4communitylib/classes/resolvers/common_double_sim_resolver.py deleted file mode 100644 index be3fd8f..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/resolvers/common_double_sim_resolver.py +++ /dev/null @@ -1,99 +0,0 @@ -""" -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 -""" -from typing import Any - -from event_testing.resolver import DoubleSimResolver -from interactions import ParticipantType, ParticipantTypeSituationSims -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - - -class CommonDoubleSimResolver(DoubleSimResolver): - """A double Sim resolver that is able to handle many more participant types.""" - - # noinspection PyMissingOrEmptyDocstring - def get_participants(self, participant_type, **kwargs) -> Any: - from event_testing.test_constants import SIM_INSTANCE, FROM_DATA_OBJECT, OBJECTIVE_GUID64, FROM_EVENT_DATA - if participant_type == SIM_INSTANCE: - participant_type = ParticipantType.Actor - - if participant_type in ( - # Participants Shared - ParticipantType.Lot, - ParticipantType.LotOwners, - ParticipantType.LotOwnersOrRenters, - ParticipantType.LotOwnerSingleAndInstanced, - ParticipantType.ActiveHousehold, - ParticipantType.AllInstancedActiveHouseholdSims, - ParticipantType.CareerEventSim, - ParticipantType.AllInstancedSims, - ParticipantType.Street, - ParticipantType.VenuePolicyProvider, - ParticipantType.CurrentRegion, - # Single Sim Resolver - ParticipantType.Actor, - ParticipantType.CustomSim, - ParticipantType.SignificantOtherActor, - ParticipantType.PregnancyPartnerActor, - ParticipantType.AllRelationships, - ParticipantType.ActorFeudTarget, - ParticipantType.InteractionContext, - ParticipantType.Affordance, - ParticipantType.Familiar, - ParticipantType.PickedZoneId, - ParticipantType.ActorLot, - ParticipantType.RoutingSlaves, - ParticipantType.StoredCASPartsOnObject, - ParticipantType.ActorLotLevel, - # Double Sim Resolver - ParticipantType.TargetSim, - ParticipantType.TargetHouseholdMembers, - ParticipantType.SignificantOtherTargetSim, - ParticipantType.FamiliarOfTarget - ): - return super().get_participants(participant_type, **kwargs) - - sim = CommonSimUtils.get_sim_instance(self.sim_info_to_test) - target_sim = CommonSimUtils.get_sim_instance(self.target_sim_info) - if participant_type == ParticipantType.Object: - return (self.target_sim_info,) - elif participant_type == ParticipantType.ObjectIngredients: - if target_sim is not None and hasattr(target_sim, 'crafting_component') and target_sim.crafting_component and hasattr(target_sim, 'get_crafting_process'): - target_crafting_process = target_sim.get_crafting_process() - if target_crafting_process is not None: - return tuple(target_crafting_process.get_ingredients_object_definitions()) - return () - - if participant_type == ParticipantType.ActorPostureTarget: - return (self.target_sim_info, ) - elif participant_type == ParticipantType.AssociatedClub or participant_type == ParticipantType.AssociatedClubLeader or participant_type == ParticipantType.AssociatedClubMembers: - return () - if participant_type == ParticipantType.ObjectCrafter: - return (self.sim_info_to_test, ) - if participant_type in ParticipantTypeSituationSims: - return self.sim_info_to_test, self.target_sim_info - else: - if participant_type == ParticipantType.ObjectLotLevel: - return self._get_lot_level_from_object(target_sim) - if participant_type == ParticipantType.ActorLotLevel: - return self._get_lot_level_from_object(sim) - if participant_type == 0: - return () - result = self._get_participants_base(participant_type, **kwargs) - if result is not None: - return result - if participant_type == FROM_DATA_OBJECT: - return () - if participant_type == OBJECTIVE_GUID64: - return () - if participant_type == FROM_EVENT_DATA: - return () - if participant_type == ParticipantType.PickedItemId: - return (self.target_sim_info, ) - if participant_type == ParticipantType.Listeners: - return (self.target_sim_info, ) - return self.sim_info_to_test, self.target_sim_info diff --git a/Scripts/s4ap/sims4communitylib/classes/runnables/__init__.py b/Scripts/s4ap/sims4communitylib/classes/runnables/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/runnables/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/classes/runnables/common_runnable.py b/Scripts/s4ap/sims4communitylib/classes/runnables/common_runnable.py deleted file mode 100644 index 750badf..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/runnables/common_runnable.py +++ /dev/null @@ -1,433 +0,0 @@ -""" -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 -""" - -from typing import Union, Any, TypeVar, Generic - -from s4ap.sims4communitylib.classes.runnables.contexts.common_runnable_context import CommonRunnableContext -from s4ap.sims4communitylib.enums.common_runnable_state_type import CommonRunnableStateType -from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from s4ap.sims4communitylib.classes.time.common_alarm_handle import CommonAlarmHandle -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt -from s4ap.sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags -from s4ap.sims4communitylib.events.interval.common_interval_event_service import CommonIntervalEventRegistry, \ - CommonIntervalDispatcher -from s4ap.sims4communitylib.logging.has_class_log import HasClassLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.utils.common_time_utils import CommonTimeUtils -from s4ap.sims4communitylib.utils.time.common_alarm_utils import CommonAlarmUtils - -CommonRunnableContextType = TypeVar('CommonRunnableContextType', bound=CommonRunnableContext) - - -class CommonRunnable(HasClassLog, Generic[CommonRunnableContextType]): - """CommonRunnable() - - This class is used when you want to have something reoccurring again and again. - - :param context: A context containing information about the runnable as well as actions the runnable should perform. - :type context: CommonRunnableContext - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - raise NotImplementedError() - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - raise NotImplementedError() - - def __init__(self, context: CommonRunnableContextType) -> None: - self._update_alarm: Union[CommonAlarmHandle, None] = None - self._update_dispatcher: Union[CommonIntervalDispatcher, None] = None - self._context = context - self._has_initial_started = False - self._change_state(CommonRunnableStateType.STOPPED) - self.milliseconds_per_update = 1000 - # This is used when we are expecting a reset to happen, and we don't want to cancel the runnable. - self._expect_reset = False - self._is_ended = False - self._await_stop = False - self._await_stop_reason = self.unknown_stop_reason - self._updating = False - super().__init__() - - @property - def context(self) -> CommonRunnableContextType: - """A context containing information about the runnable as well as actions the runnable should perform.""" - return self._context - - @context.setter - def context(self, value: CommonRunnableContextType): - self._context = value - - @property - def is_running(self) -> bool: - """The runnable is running.""" - return self._current_state == CommonRunnableStateType.RUNNING - - @property - def is_starting(self) -> bool: - """The runnable is starting.""" - return self._current_state == CommonRunnableStateType.STARTING - - @property - def is_waiting_for_start(self) -> bool: - """The runnable is waiting to start.""" - return self._current_state == CommonRunnableStateType.WAITING_TO_START - - @property - def is_stopping(self) -> bool: - """The runnable is stopping.""" - return self._current_state == CommonRunnableStateType.STOPPING - - @property - def is_stopped(self) -> bool: - """The runnable is stopped.""" - return self._current_state == CommonRunnableStateType.STOPPED - - def _start_updater(self, milliseconds_per_update: int) -> None: - self._stop_updater() - self._updating = False - - def _start_update(_: Any) -> None: - if self._updating: - return - self._updating = True - - def _run_update() -> None: - try: - self.update(milliseconds_per_update) - finally: - self._updating = False - - _run_update() - - if self.context.should_run_on_game_time: - sim_minutes = int(CommonTimeUtils.convert_milliseconds_to_seconds(milliseconds_per_update)) - time_until_update = CommonTimeUtils.create_interval_from_sim_minutes(sim_minutes) - self._update_alarm = CommonAlarmUtils.schedule_alarm( - self, - time_until_update, - _start_update, - should_repeat=True, - time_until_repeat=time_until_update - ) - else: - self._update_dispatcher = CommonIntervalEventRegistry()._add_tracker( - self.mod_identity, - milliseconds_per_update, - lambda *_, **__: _start_update(None) - ) - - def _stop_updater(self) -> None: - if self._update_dispatcher is not None: - if self._update_dispatcher in CommonIntervalEventRegistry()._registered_interval_trackers: - self.log.format_with_message('Removing update dispatcher from interval trackers.') - CommonIntervalEventRegistry()._registered_interval_trackers.remove(self._update_dispatcher) - self._update_dispatcher = None - - if self._update_alarm is not None: - CommonAlarmUtils.cancel_alarm(self._update_alarm) - self._update_alarm = None - - @property - def milliseconds_per_update(self) -> int: - """The number of milliseconds between updates.""" - return self._milliseconds_per_update - - @milliseconds_per_update.setter - def milliseconds_per_update(self, value: int): - self._milliseconds_per_update = value - self._start_updater(value) - - def _change_state(self, new_state: CommonRunnableStateType): - self._current_state = new_state - - def start(self, *_, **__) -> CommonExecutionResult: - """start(*_, **__) - - Start the runnable. - - :return: True, if the runnable has successfully been started. False, if not. - :rtype: CommonExecutionResult - """ - try: - self._is_ended = False - if self.is_starting: - self.log.debug('Failed to start runnable, Already starting!') - return CommonExecutionResult(True, reason='Runnable Is Already starting') - - on_initialize_result = self._on_initialize(*_, **__) - if not on_initialize_result: - self.log.format_error_with_message('On Initialize Failed.', runnable=self, result=on_initialize_result) - self.stop(self.invalid_stop_reason, force_stop=True) - return on_initialize_result - - self.log.debug('Attempting to start runnable.') - if self.is_running: - self.log.debug('Success, runnable has already been started.') - return CommonExecutionResult.TRUE - - is_waiting_to_start = self.is_waiting_for_start - self._change_state(CommonRunnableStateType.STARTING) - - on_setup_result = self._on_setup(*_, is_waiting_to_start=is_waiting_to_start, **__) - if not on_setup_result: - self.log.format_error_with_message('On Setup Failed', runnable=self, context=self.context, result=on_setup_result) - self.stop(self.invalid_stop_reason, force_stop=True) - return on_setup_result - - if self.is_waiting_for_start: - self.log.format_with_message('Runnable is waiting to start.') - return CommonExecutionResult.TRUE - - self._start_updater(self.milliseconds_per_update) - - if not self._has_initial_started: - on_initial_start_result = self._on_initial_start(*_, **__) - if not on_initial_start_result: - self.log.format_error_with_message('On Initial Start Failed.', result=on_initial_start_result) - self.stop(self.invalid_stop_reason, force_stop=True) - return on_initial_start_result - - on_start_result = self._on_start() - if not on_start_result: - self.log.format_error_with_message('On Start Failed.', result=on_start_result) - return on_start_result - - self.log.debug('Finished starting runnable.') - self._change_state(CommonRunnableStateType.RUNNING) - self._has_initial_started = True - return CommonExecutionResult.TRUE - except Exception as ex: - self.log.error('Error occurred while starting runnable.', exception=ex) - self._expect_reset = False - self.stop(self.invalid_stop_reason, force_stop=True) - return CommonExecutionResult(False, reason=f'An error occurred while starting {ex}.') - - # noinspection PyUnusedLocal - def should_update(self, milliseconds_since_last_update: int) -> CommonExecutionResult: - """should_update(milliseconds_since_last_update) - - Determine if the runnable should update. - - :param milliseconds_since_last_update: The number of milliseconds since the last update. - :type milliseconds_since_last_update: int - :return: True, if the update should continue. False, if not. - :rtype: CommonExecutionResult - """ - return CommonExecutionResult.TRUE - - def update(self, milliseconds_since_last_update: int, *_, **__) -> CommonExecutionResult: - """update(milliseconds_since_last_update, *_, **__) - - Update the runnable. - - .. note:: This function is invoked automatically by the runnable itself. - - :param milliseconds_since_last_update: The number of milliseconds since the last update. - :type milliseconds_since_last_update: int - :return: True, if the update is successful. False, if not. - :rtype: CommonExecutionResult - """ - try: - if self._is_ended: - self.verbose_log.debug('Failed to update runnable, it has already ended.') - return CommonExecutionResult(False, reason='Has already ended.') - - if self._await_stop: - self.verbose_log.debug('Failed to update runnable, it is awaiting a stop.') - self.stop(self._await_stop_reason) - return CommonExecutionResult(False, reason='Runnable is waiting to stop.') - - if self.is_waiting_for_start: - if self._has_finished_waiting_to_start(milliseconds_since_last_update, *_, **__): - self.log.format_with_message('Finished waiting to start. Attempting to start runnable now.') - self.restart(self.start_after_wait_reason) - return CommonExecutionResult(True, reason='Finished Waiting for runnable to begin. We still do not want to update.') - - on_continue_waiting_result = self._on_continue_waiting_to_start() - if not on_continue_waiting_result: - self.log.format_error_with_message('On Continue Waiting To Start Failed.', result=on_continue_waiting_result) - self.stop(self.invalid_stop_reason, force_stop=True) - return on_continue_waiting_result - - self.log.format_with_message('Waiting for runnable to start.') - return CommonExecutionResult(True, reason='Waiting for runnable to start.') - - if not self.is_running or self.is_stopping or self.is_stopped: - self.verbose_log.format_with_message('Failed to update runnable, it is either not running, it is stopping, or it is stopped.', running=self.is_running, stopping=self.is_stopping) - return CommonExecutionResult(False, reason='Runnable is not running.') - - self.verbose_log.format_with_message( - 'Updating Runnable', - class_name=self.__class__.__name__, - milliseconds_since_last_update=milliseconds_since_last_update - ) - should_update_result = self.should_update(milliseconds_since_last_update) - if not should_update_result: - self.verbose_log.format_with_message('Skipping update due to request to skip update.', result=should_update_result) - return CommonExecutionResult.TRUE - - on_update_result = self._on_update(milliseconds_since_last_update) - if not on_update_result: - self.log.format_error_with_message('On Update Failed', result=on_update_result) - self.stop(self.invalid_stop_reason, force_stop=True) - - return on_update_result - except Exception as ex: - self.log.error('Error occurred while updating runnable.', exception=ex) - self._expect_reset = False - self.stop(self.invalid_stop_reason, force_stop=True) - return CommonExecutionResult(False, reason=f'An error occurred while updating {ex}.') - - def stop(self, stop_reason: Union[int, CommonInt, CommonIntFlags], *_, force_stop: bool = False, **__) -> CommonExecutionResult: - """stop(stop_reason, force_stop=False) - - Stop the runnable. - - :param stop_reason: The reason the runnable is being stopped for. - :type stop_reason: Union[int, CommonInt, CommonIntFlags] - :param force_stop: If True, the is_stopping state will not be checked and the runner will be forced to stop. Default is False. - :type force_stop: bool, optional - :return: True, if the runnable has been stopped successfully. False, if not. - :rtype: CommonExecutionResult - """ - try: - if not force_stop and self.is_stopping: - self.log.format_with_message('Failed to stop, runnable is already stopping.', stop_reason=stop_reason) - return CommonExecutionResult(True, reason='Already stopping.') - - if self._expect_reset: - self.log.format_with_message('Failed to stop, runnable is expected to be restarting.', stop_reason=stop_reason) - return CommonExecutionResult.TRUE - - if stop_reason == self.invalid_stop_reason and not self._has_initial_started: - stop_reason = self.cancel_stop_reason - - self._change_state(CommonRunnableStateType.STOPPING) - self.log.format_with_message('Stopping runnable', stop_reason=stop_reason) - - on_stop_result = self._on_stop(stop_reason, *_, force_stop=force_stop, **__) - if not on_stop_result: - self.log.format_error_with_message('On Stop Failed.', result=on_stop_result) - return on_stop_result - - if self._is_restart_stop_reason(stop_reason): - self.log.format_with_message('Stopping due to a restart.', stop_reason=stop_reason) - on_restart_result = self._on_restart(stop_reason) - if not on_restart_result: - self.log.format_error_with_message('On Restart Failed.', result=on_restart_result) - return CommonExecutionResult.TRUE - - self._stop_updater() - - self._is_ended = True - - on_end_result = self._on_end(stop_reason, *_, force_stop=force_stop, **__) - if not on_end_result: - self.log.format_with_message('On End Failed.', result=on_end_result) - return on_end_result - - self.log.format_with_message('Done ending runnable.', stop_reason=stop_reason) - return on_end_result - except Exception as ex: - self.log.error('Error occurred while stopping runnable.', exception=ex) - self._expect_reset = False - if stop_reason != self.invalid_stop_reason: - self.stop(self.invalid_stop_reason, force_stop=True) - return CommonExecutionResult(False, reason=f'An error occurred while stopping {ex}.') - finally: - self._change_state(CommonRunnableStateType.STOPPED) - self._expect_reset = False - - def restart(self, restart_reason: Union[int, CommonInt, CommonIntFlags], *_, **__) -> CommonExecutionResult: - """restart(restart_reason, *_, **__) - - Restart the runnable. - - :param restart_reason: The reason for the restart. - :type restart_reason: Union[int, CommonInt, CommonIntFlags] - :return: True, if the runnable has been restarted successfully. False, if not. - :rtype: CommonExecutionResult - """ - self.log.format_with_message('Restarting runnable', restart_reason=restart_reason) - self.stop(restart_reason) - return self.start() - - @property - def invalid_stop_reason(self) -> Union[int, CommonInt, CommonIntFlags]: - """A reason for the runnable to be stopped for invalid reasons.""" - raise NotImplementedError() - - @property - def unknown_stop_reason(self) -> Union[int, CommonInt, CommonIntFlags]: - """A reason for the runnable to be stopped for unknown reasons.""" - raise NotImplementedError() - - @property - def cancel_stop_reason(self) -> Union[int, CommonInt, CommonIntFlags]: - """A reason for the runnable to be stopped for a cancel reasons.""" - raise NotImplementedError() - - @property - def start_after_wait_reason(self) -> Union[int, CommonInt, CommonIntFlags]: - """A reason for the runnable to be stopped after waiting for it to start.""" - raise NotImplementedError() - - def _is_restart_stop_reason(self, stop_reason: Union[int, CommonInt, CommonIntFlags]) -> bool: - raise NotImplementedError() - - def _is_end_stop_reason(self, stop_reason: Union[int, CommonInt, CommonIntFlags]) -> bool: - raise NotImplementedError() - - def _on_start(self, *_, **__) -> CommonExecutionResult: - return CommonExecutionResult.TRUE - - def _on_update(self, milliseconds_since_last_update: int, *_, **__) -> CommonExecutionResult: - return self.context.update(milliseconds_since_last_update, *_, **__) - - # noinspection PyUnusedLocal - def _on_restart(self, restart_reason: Union[int, CommonInt, CommonIntFlags], *_, **__) -> CommonExecutionResult: - return self.context.restart(restart_reason, *_, **__) - - # noinspection PyUnusedLocal - def _on_stop(self, stop_reason: Union[int, CommonInt, CommonIntFlags], *_, force_stop: bool = False, **__) -> CommonExecutionResult: - return CommonExecutionResult.TRUE - - def _on_end(self, stop_reason: Union[int, CommonInt, CommonIntFlags], *_, force_stop: bool = False, **__) -> CommonExecutionResult: - return self.context.teardown(stop_reason, *_, force_stop, **__) - - # noinspection PyUnusedLocal - def _has_finished_waiting_to_start(self, milliseconds_since_last_update: int, *_, **__) -> bool: - return True - - def _on_continue_waiting_to_start(self, *_, **__) -> CommonExecutionResult: - return CommonExecutionResult.TRUE - - def _on_initialize(self, *_, **__) -> CommonExecutionResult: - return self.context.initialize(*_, **__) - - def _on_initial_start(self, *_, **__) -> CommonExecutionResult: - return CommonExecutionResult.TRUE - - def _on_setup(self, *_, is_waiting_to_start: bool = False, **__) -> CommonExecutionResult: - return self.context.setup(*_, is_waiting_to_start=is_waiting_to_start, **__) - - def __eq__(self, other: 'CommonRunnable') -> bool: - if not isinstance(other, CommonRunnable): - return False - return self.context.__eq__(other.context) - - def __repr__(self) -> str: - return repr(self.context) - - def __str__(self) -> str: - return str(self.context) diff --git a/Scripts/s4ap/sims4communitylib/classes/runnables/common_runnable_with_sims.py b/Scripts/s4ap/sims4communitylib/classes/runnables/common_runnable_with_sims.py deleted file mode 100644 index de46296..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/runnables/common_runnable_with_sims.py +++ /dev/null @@ -1,187 +0,0 @@ -""" -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 -""" - -from typing import Union, List, Tuple, TypeVar, Generic - -from sims.sim import Sim -from s4ap.sims4communitylib.classes.runnables.common_runnable import CommonRunnable -from s4ap.sims4communitylib.classes.runnables.contexts.common_runnable_context_with_sims import CommonRunnableContextWithSims -from s4ap.sims4communitylib.classes.runnables.contexts.common_runnable_sim_context import CommonRunnableSimContext -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt -from s4ap.sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity - -CommonRunnableContextWithSimsType = TypeVar('CommonRunnableContextWithSimsType', bound=CommonRunnableContextWithSims) -CommonRunnableSimContextType = TypeVar('CommonRunnableSimContextType', bound=CommonRunnableSimContext) - - -class CommonRunnableWithSims(CommonRunnable[CommonRunnableContextWithSimsType], Generic[CommonRunnableContextWithSimsType, CommonRunnableSimContextType]): - """CommonRunnableWithSims() - - This class is used when you want to have something reoccurring again and again. Specifically when it involves something reoccurring for Sims again and again. - - :param context: A context containing information about the runnable as well as actions the runnable should perform, including which Sims to perform the actions with. - :type context: CommonRunnableContextWithSims - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - raise NotImplementedError() - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - raise NotImplementedError() - - # noinspection PyMissingOrEmptyDocstring - @property - def invalid_stop_reason(self) -> Union[int, CommonInt, CommonIntFlags]: - raise NotImplementedError() - - # noinspection PyMissingOrEmptyDocstring - @property - def unknown_stop_reason(self) -> Union[int, CommonInt, CommonIntFlags]: - raise NotImplementedError() - - # noinspection PyMissingOrEmptyDocstring - @property - def cancel_stop_reason(self) -> Union[int, CommonInt, CommonIntFlags]: - raise NotImplementedError() - - # noinspection PyMissingOrEmptyDocstring - @property - def start_after_wait_reason(self) -> Union[int, CommonInt, CommonIntFlags]: - raise NotImplementedError() - - def _is_restart_stop_reason(self, stop_reason: Union[int, CommonInt, CommonIntFlags]) -> bool: - raise NotImplementedError() - - def _is_end_stop_reason(self, stop_reason: Union[int, CommonInt, CommonIntFlags]) -> bool: - raise NotImplementedError() - - def __init__(self, context: CommonRunnableContextWithSimsType) -> None: - super().__init__(context) - - # noinspection PyMissingOrEmptyDocstring - @property - def context(self) -> CommonRunnableContextWithSimsType: - return self._context - - @context.setter - def context(self, value: CommonRunnableContextWithSimsType): - self._context = value - - @property - def sim_contexts(self) -> List[CommonRunnableSimContextType]: - """A collection of Sim Contexts within the context.""" - return self.context.sim_contexts - - @property - def sims_as_sim_id(self) -> Tuple[int]: - """Retrieves a collection of decimal identifiers for the Sims.""" - return self.context.sims_as_sim_id - - @property - def sims_as_sim_info(self) -> Tuple[SimInfo]: - """Retrieves a collection of Sim Info for the Sims.""" - return self.context.sims_as_sim_info - - @property - def sims_as_sim(self) -> Tuple[Sim]: - """Retrieves a collection of Sim Instances for the Sims.""" - return self.context.sims_as_sim - - def has_sim_context(self, sim_info: SimInfo) -> bool: - """has_sim_context(sim_info) - - Determine if a Sim Context exists for a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: True, if a Sim Context exists for the Sim. False, if not. - :rtype: bool - """ - return self.context.has_sim_context(sim_info) - - def get_sim_context(self, sim_info: SimInfo) -> Union[CommonRunnableSimContextType, None]: - """get_sim_context(sim_info) - - Retrieve the Sim Context for a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The Sim Context matching the Sim or None if no context matches. - :rtype: Union[CommonRunnableSimContext, None] - """ - return self.context.get_sim_context(sim_info) - - def add_sim_context(self, sim_context: CommonRunnableSimContextType, add_reason: Union[int, CommonInt, CommonIntFlags], restart_after_add: bool = True) -> CommonExecutionResult: - """add_sim_context(sim_context, add_reason, restart_after_add=True) - - Add a Sim Context to the context. - - :param sim_context: A Sim Context. - :type sim_context: CommonRunnableSimContextType - :param add_reason: The reason the Sim Context is being added. - :type add_reason: Union[int, CommonInt, CommonIntFlags] - :param restart_after_add: If True, the Runnable will be restarted after the Sim is added. If False, the Runnable will not be restarted after add. Default is True. - :type restart_after_add: bool, optional - :return: True, if the context was added successfully. False, if not. - :rtype: CommonExecutionResult - """ - if self.has_sim_context(sim_context.sim_info): - return CommonExecutionResult(False, reason=f'Sim {sim_context.sim_info} is already a part of the runnable.') - add_result = self.context.add_sim_context(sim_context) - if not add_result: - return add_result - if restart_after_add: - return self.restart(add_reason) - return CommonExecutionResult.TRUE - - def remove_sim_context(self, sim_context: CommonRunnableSimContextType, remove_reason: Union[int, CommonInt, CommonIntFlags], *_, restart_after_remove: bool = True, **__) -> CommonExecutionResult: - """remove_sim_context(sim_context, remove_reason, restart_after_remove=True) - - Remove a Sim Context from the context. - - :param sim_context: A Sim Context. - :type sim_context: CommonRunnableSimContextType - :param remove_reason: The reason the context is being removed. - :type remove_reason: Union[int, CommonInt, CommonIntFlags] - :param restart_after_remove: If True, the Runnable will be restarted after the Sim is removed. If False, the Runnable will not be restarted after remove. Default is True. - :type restart_after_remove: bool, optional - :return: True, if the Sim Context was removed from the context successfully. False, if not. - :rtype: CommonExecutionResult - """ - remove_result = self.context.remove_sim_context(sim_context, remove_reason, *_, restart_after_remove=restart_after_remove, **__) - if not remove_result: - return remove_result - if restart_after_remove: - return self.restart(remove_reason) - return CommonExecutionResult.TRUE - - def remove_sim(self, sim_info: SimInfo, remove_reason: Union[int, CommonInt, CommonIntFlags], *_, restart_after_remove: bool = False, **__) -> CommonExecutionResult: - """remove_sim(sim_info, remove_reason) - - Remove a Sim from the context. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param remove_reason: The reason the Sim is being removed. - :type remove_reason: Union[int, CommonInt, CommonIntFlags] - :param restart_after_remove: If True, the Runnable will be restarted after the Sim is removed. If False, the Runnable will not be restarted after remove. Default is True. - :type restart_after_remove: bool, optional - :return: True, if the sim was removed from the context successfully. False, if not. - :rtype: CommonExecutionResult - """ - sim_context = self.get_sim_context(sim_info) - if sim_context is None: - return CommonExecutionResult(False, reason=f'Sim {sim_info} did not have a Sim context!') - return self.remove_sim_context(sim_context, remove_reason, *_, restart_after_remove=restart_after_remove, **__) diff --git a/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/__init__.py b/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/__init__.py deleted file mode 100644 index 3251898..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" \ No newline at end of file diff --git a/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_context.py b/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_context.py deleted file mode 100644 index ef31130..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_context.py +++ /dev/null @@ -1,250 +0,0 @@ -""" -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 -""" - -from typing import Union, Dict, Any, Tuple, TypeVar, Type - -from s4ap.sims4communitylib.classes.serialization.common_serializable import CommonSerializable -from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt -from s4ap.sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags -from s4ap.sims4communitylib.logging.has_class_log import HasClassLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity - -CommonRunnableContextType = TypeVar('CommonRunnableContextType', bound="CommonRunnableContext") - - -class CommonRunnableContext(CommonSerializable, HasClassLog): - """CommonRunnableContext() - - A context used by a runnable. - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - raise NotImplementedError() - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - raise NotImplementedError() - - def __init__(self: CommonRunnableContextType) -> None: - super().__init__() - self._initialized = False - self._total_milliseconds = 0 - - @property - def should_run_on_game_time(self) -> bool: - """Determine if the context should be run using game time or if it should be run using real time.""" - return True - - @property - def should_track_total_time(self) -> bool: - """Determine if the total time in milliseconds should be tracked. Default is False.""" - return False - - @property - def total_milliseconds(self) -> int: - """A counter for the total number of milliseconds the context has been running for.""" - return self._total_milliseconds - - def clear_total_milliseconds(self) -> None: - """clear_time_since_setup() - - Clear the total time passed since the context was set up. - """ - self._total_milliseconds = 0 - - def initialize(self, *_, **__) -> CommonExecutionResult: - """initialize(*_, **__) - - Initialize the context. - - :return: True, if successful. False, if not. - :rtype: CommonExecutionResult - """ - self.log.format_with_message('Attempting to initialize runnable context.') - if self._initialized: - self.log.format_with_message('Failed to initialize context. It was already initialized.') - return CommonExecutionResult.TRUE - initialize_result = self._initialize(*_, **__) - if not initialize_result: - self.log.format_with_message('Failed to initialize context.') - return initialize_result - self._initialized = True - self.log.debug('Finished initializing context.') - return CommonExecutionResult.TRUE - - def setup(self, *_, **__) -> CommonExecutionResult: - """setup(*_, **__) - - Setup the context. - - :return: True, if successful. False, if not. - :rtype: CommonExecutionResult - """ - self.log.format_with_message('Setting up context.') - self.clear_total_milliseconds() - return self._setup(*_, **__) - - # noinspection PyUnusedLocal - def should_update(self, milliseconds_since_last_update: int, *_, **__) -> CommonExecutionResult: - """should_update(milliseconds_since_last_update, *_, **__) - - Determine if the context should update. - - :param milliseconds_since_last_update: The number of milliseconds since the last update. - :type milliseconds_since_last_update: int - :return: True, if the context should update. False, if not. - :rtype: CommonExecutionResult - """ - return CommonExecutionResult.TRUE - - def update(self, milliseconds_since_last_update: int, *_, **__) -> CommonExecutionResult: - """update(milliseconds_since_last_update, *_, **__) - - Update the context. - - :param milliseconds_since_last_update: The number of milliseconds since the last update. - :type milliseconds_since_last_update: int - :return: True, if successful. False, if not. - :rtype: CommonExecutionResult - """ - should_update_result = self.should_update(milliseconds_since_last_update, *_, **__) - if not should_update_result: - return should_update_result.reverse_result() - pre_update_result = self._pre_update(milliseconds_since_last_update, *_, **__) - if not pre_update_result: - return pre_update_result - if self.should_track_total_time: - self._total_milliseconds += milliseconds_since_last_update - update_result = self._update(milliseconds_since_last_update, *_, **__) - if not update_result: - return update_result - return self._post_update(milliseconds_since_last_update, *_, **__) - - def restart(self, restart_reason: Union[int, CommonInt, CommonIntFlags], *_, **__) -> CommonExecutionResult: - """restart(restart_reason, *_, **__) - - Restart the context. - - :param restart_reason: The reason the context to be restarted. - :type restart_reason: Union[int, CommonInt, CommonIntFlags] - :return: True, if successful. False, if not. - :rtype: CommonExecutionResult - """ - self.log.format_with_message('Restarting context.', reason=restart_reason) - return self._restart(restart_reason, *_, **__) - - def teardown(self, teardown_reason: Union[int, CommonInt, CommonIntFlags], *_, **__) -> CommonExecutionResult: - """teardown(teardown_reason, *_, **__) - - Teardown the context. - - :param teardown_reason: The reason the context to be torn down. - :type teardown_reason: Union[int, CommonInt, CommonIntFlags] - :return: True, if successful. False, if not. - :rtype: CommonExecutionResult - """ - self.log.format_with_message('Tearing down context.', reason=teardown_reason) - return self._teardown(teardown_reason, *_, **__) - - # -------------------------Hooks Start------------------------- - - def _initialize(self, *_, **__) -> CommonExecutionResult: - raise NotImplementedError() - - def _setup(self, *_, **__) -> CommonExecutionResult: - raise NotImplementedError() - - # noinspection PyUnusedLocal - def _pre_update(self, milliseconds_since_last_update: int, *_, **__) -> CommonExecutionResult: - return CommonExecutionResult.TRUE - - def _update(self, milliseconds_since_last_update: int, *_, **__) -> CommonExecutionResult: - raise NotImplementedError() - - # noinspection PyUnusedLocal - def _post_update(self, milliseconds_since_last_update: int, *_, **__) -> CommonExecutionResult: - return CommonExecutionResult.TRUE - - def _restart(self, restart_reason: Union[int, CommonInt, CommonIntFlags], *_, **__) -> CommonExecutionResult: - return CommonExecutionResult.TRUE - - def _teardown(self, teardown_reason: Union[int, CommonInt, CommonIntFlags], *_, **__) -> CommonExecutionResult: - raise NotImplementedError() - - # -------------------------Hooks End------------------------- - - def clone(self: CommonRunnableContextType, *_, **__) -> CommonRunnableContextType: - """clone(*_, **__) - - Create a clone of the context. - - :return: A cloned version of this context. - :rtype: CommonRunnableContext - """ - clone_args = self._clone_args(*_, **__) - clone_kwargs = self._clone_kwargs(*_, **__) - - # noinspection PyArgumentList - return self.__class__( - *clone_args, - **clone_kwargs - ) - - def _clone_args(self, *_, **__) -> Tuple[Any]: - return tuple() - - def _clone_kwargs(self, *_, **__) -> Dict[str, Any]: - return dict() - - # noinspection PyMissingOrEmptyDocstring - def serialize(self) -> Union[str, Dict[str, Any]]: - data = dict() - self._serialize_data(data) - return data - - def _serialize_data(self, data: Dict[str, Any]): - pass - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def deserialize(cls: Type[CommonRunnableContextType], data: Union[str, Dict[str, Any]]) -> Union[CommonRunnableContextType, None]: - deserialized_args = cls._deserialize_args(data) - if deserialized_args is None: - return None - deserialized_kwargs = cls._deserialize_kwargs(data) - if deserialized_kwargs is None: - return None - - # noinspection PyArgumentList - return cls( - *deserialized_args, - **deserialized_kwargs - ) - - @classmethod - def _deserialize_args(cls, data: Union[str, Dict[str, Any]]) -> Union[Tuple[Any], None]: - return tuple() - - # noinspection PyUnusedLocal - @classmethod - def _deserialize_kwargs(cls, data: Union[str, Dict[str, Any]]) -> Union[Dict[str, Any], None]: - return dict() - - def __repr__(self) -> str: - return self.__str__() - - def __str__(self) -> str: - str_extras = self._get_str() - return f'<[CRC] {str_extras}>' - - def _get_str(self) -> str: - return '' diff --git a/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_context_with_sims.py b/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_context_with_sims.py deleted file mode 100644 index ffcc760..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_context_with_sims.py +++ /dev/null @@ -1,279 +0,0 @@ -""" -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 -""" - -from typing import Union, Iterator, List, Tuple, Any, Dict, Type, TypeVar, Generic - -from sims.sim import Sim -from s4ap.sims4communitylib.classes.runnables.contexts.common_runnable_context import CommonRunnableContext -from s4ap.sims4communitylib.classes.runnables.contexts.common_runnable_sim_context import CommonRunnableSimContext -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt -from s4ap.sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity - -CommonRunnableSimContextType = TypeVar('CommonRunnableSimContextType', bound=CommonRunnableSimContext) - - -class CommonRunnableContextWithSims(CommonRunnableContext, Generic[CommonRunnableSimContextType]): - """CommonRunnableContextWithSims() - - A context used by a runnable. - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - raise NotImplementedError() - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - raise NotImplementedError() - - def __init__(self, sim_contexts: Iterator[CommonRunnableSimContextType]) -> None: - super().__init__() - self._sim_contexts = list(sim_contexts) - - @property - def sim_contexts(self) -> List[CommonRunnableSimContextType]: - """A collection of Sim Contexts within the context.""" - return self._sim_contexts - - @classmethod - def sim_context_type(cls) -> Type['CommonRunnableSimContextType']: - """The context type for Sim info.""" - raise NotImplementedError() - - @property - def sims_as_sim_id(self) -> Tuple[int]: - """Retrieves a collection of decimal identifiers for the Sims.""" - result: Tuple[int, ...] = tuple([context.sim_id for context in self.sim_contexts]) - return result - - @property - def sims_as_sim_info(self) -> Tuple[SimInfo]: - """Retrieves a collection of Sim Info for the Sims.""" - result: Tuple[SimInfo, ...] = tuple([context.sim_info for context in self.sim_contexts]) - return result - - @property - def sims_as_sim(self) -> Tuple[Sim]: - """Retrieves a collection of Sim Instances for the Sims.""" - result: Tuple[Sim, ...] = tuple([context.sim for context in self.sim_contexts]) - return result - - def has_sim_context(self, sim_info: SimInfo) -> bool: - """has_sim_context(sim_info) - - Determine if a Sim Context exists for a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: True, if a Sim Context exists for the Sim. False, if not. - :rtype: bool - """ - return self.get_sim_context(sim_info) is not None - - def get_sim_context(self, sim_info: SimInfo) -> Union[CommonRunnableSimContextType, None]: - """get_sim_context(sim_info) - - Retrieve the Sim Context for a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The Sim Context matching the Sim or None if no context matches. - :rtype: Union[CommonRunnableSimContextType, None] - """ - self.verbose_log.format_with_message('Retrieving Sim Context.', sim=sim_info) - for sim_context in self.sim_contexts: - if sim_context.sim_info is sim_info: - self.verbose_log.format_with_message('Found Sim Context.', sim=sim_info) - return sim_context - self.verbose_log.format_with_message('Failed to locate Sim Context.', sim=sim_info) - return None - - def add_sim_context(self, sim_context: CommonRunnableSimContextType, *_, **__) -> CommonExecutionResult: - """add_sim_context(sim_context, *_, **__) - - Add a Sim Context to the context. - - :param sim_context: A Sim Context. - :type sim_context: CommonRunnableSimContextType - :return: True, if the context was added successfully. False, if not. - :rtype: CommonExecutionResult - """ - self.log.format_with_message('Adding Sim Context.', sim_context=sim_context) - if self.has_sim_context(sim_context.sim_info): - self.log.format_with_message('Failed, the Sim was already a part of the context.', sim_context=sim_context) - return CommonExecutionResult.TRUE - - result = sim_context.initialize(self, *_, **__) - if not result: - self.log.format_error_with_message('Failed to initialize Sim Context', context=sim_context, result=result) - return result - - if sim_context not in self._sim_contexts: - self._sim_contexts.append(sim_context) - self.log.format_with_message('Finished adding Sim Context.', sim=sim_context) - return CommonExecutionResult.TRUE - - def remove_sim_context(self, sim_context: CommonRunnableSimContextType, remove_reason: Union[int, CommonInt, CommonIntFlags], *_, **__) -> CommonExecutionResult: - """remove_sim_context(sim_context, remove_reason, *_, **__) - - Remove a Sim Context from the context. - - :param sim_context: A Sim Context. - :type sim_context: CommonRunnableSimContextType - :param remove_reason: The reason the context is being removed. - :type remove_reason: Union[int, CommonInt, CommonIntFlags] - :return: True, if the Sim Context was removed from the context successfully. False, if not. - :rtype: CommonExecutionResult - """ - if sim_context is None: - self.log.format_with_message('Sim Context was None.', sim_context=sim_context) - return CommonExecutionResult.FALSE - self.log.format_with_message('Removing Sim Context.', sim_context=sim_context) - result = sim_context.teardown(remove_reason, self, *_, **__) - if not result: - self.log.format_error_with_message('Failed to tear down Sim Context', context=sim_context, result=result) - return result - if sim_context in self._sim_contexts: - self.log.format_with_message('Found Sim Context, removing it now.', sim_context=sim_context) - self._sim_contexts.remove(sim_context) - self.log.format_with_message('Removed Sim Context.', sim_context=sim_context) - return CommonExecutionResult.TRUE - - def remove_sim(self, sim_info: SimInfo, remove_reason: Union[int, CommonInt, CommonIntFlags], *_, **__) -> CommonExecutionResult: - """remove_sim(sim_info, remove_reason, *_, **__) - - Remove a Sim from the context. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param remove_reason: The reason the Sim is being removed. - :type remove_reason: Union[int, CommonInt, CommonIntFlags] - :return: True, if the sim was removed from the context successfully. False, if not. - :rtype: CommonExecutionResult - """ - sim_context = self.get_sim_context(sim_info) - if sim_context is None: - self.log.format_with_message('No Sim Context found for Sim.', sim=sim_info) - return CommonExecutionResult.FALSE - remove_result = self.remove_sim_context(sim_context, remove_reason, *_, **__) - if not remove_result: - self.log.format_with_message('Failed to remove Sim Context.', sim=sim_info, result=remove_result) - return remove_result - return CommonExecutionResult.TRUE - - def _initialize(self, *_, **__) -> CommonExecutionResult: - self.log.format_with_message('Initializing Sim Contexts.') - for sim_context in self.sim_contexts: - result = sim_context.initialize(self, *_, **__) - if not result: - self.log.format_error_with_message('Failed to initialize Sim Context.', sim_context=sim_context, result=result) - return result - self.log.format_with_message('Finished initializing Sim Context.') - return CommonExecutionResult.TRUE - - def _setup(self, *_, **__) -> CommonExecutionResult: - self.log.format_with_message('Setting Up Sim Contexts.') - for sim_context in self.sim_contexts: - result = sim_context.setup(self, *_, **__) - if not result: - self.log.format_error_with_message('Failed to setup Sim Context', sim_context=sim_context, result=result) - return result - self.log.format_with_message('Finished setting up Sim Contexts.') - return CommonExecutionResult.TRUE - - def _update(self, milliseconds_since_last_update: int, *_, **__) -> CommonExecutionResult: - self.log.format_with_message('Updating Sim Contexts.') - for sim_context in self.sim_contexts: - result = sim_context.update(milliseconds_since_last_update, self, *_, **__) - if not result: - self.log.format_error_with_message('Failed to update Sim Context.', sim_context=sim_context, result=result) - return result - self.log.format_with_message('Finished updating Sim Contexts.') - return CommonExecutionResult.TRUE - - def _restart(self, restart_reason: Union[int, CommonInt, CommonIntFlags], *_, **__) -> CommonExecutionResult: - self.log.format_with_message('Restarting Sim Contexts.', restart_reason=restart_reason) - for sim_context in self.sim_contexts: - result = sim_context.restart(restart_reason, self, *_, **__) - if not result: - self.log.format_error_with_message('Failed to restart Sim Context.', sim_context=sim_context, result=result) - return result - self.log.format_with_message('Finished restarting Sim Contexts.', restart_reason=restart_reason) - return CommonExecutionResult.TRUE - - def _teardown(self, teardown_reason: Union[int, CommonInt, CommonIntFlags], *_, **__) -> CommonExecutionResult: - self.log.format_with_message('Tearing Down Sim Contexts.', teardown_reason=teardown_reason) - for sim_context in self.sim_contexts: - try: - result = sim_context.teardown(teardown_reason, self, *_, **__) - if not result: - self.log.format_error_with_message('Failed to tear down Sim Context.', sim_context=sim_context, result=result) - return result - except Exception as ex: - self.log.format_error_with_message('An error occurred while tearing down Sim Context.', sim_context=sim_context, exception=ex) - continue - self.log.format_with_message('Finished Tearing Down Sim Contexts.') - return CommonExecutionResult.TRUE - - def _clone_args(self, *_, **__) -> Tuple[Any]: - sim_context_clones = [sim_context.clone(*_, **__) for sim_context in self.sim_contexts] - result: Tuple[Any, ...] = ( - sim_context_clones, - *super()._clone_args(*_, **__) - ) - return result - - def _serialize_data(self, data: Dict[str, Any]): - super()._serialize_data(data) - data['sim_contexts'] = [sim_context.serialize() for sim_context in self.sim_contexts] - - @classmethod - def _deserialize_args(cls, data: Union[str, Dict[str, Any]]) -> Union[Tuple[Any], None]: - sim_contexts_data = data.get('sim_contexts', None) - if sim_contexts_data is None: - return None - - sim_contexts: List[CommonRunnableSimContextType] = list() - for sim_context_data in sim_contexts_data: - sim_context = cls.sim_context_type().deserialize(sim_context_data) - if sim_context is None: - return None - sim_contexts.append(sim_context) - if not sim_contexts: - return None - - deserialized_args = super()._deserialize_args(data) - if deserialized_args is None: - return None - - result: Tuple[Any, ...] = ( - sim_contexts, - *deserialized_args - ) - return result - - def __eq__(self, other: 'CommonRunnableContextWithSims') -> bool: - if not isinstance(other, CommonRunnableContextWithSims): - return False - if len(self.sim_contexts) != len(other.sim_contexts): - return False - for (self_sim_context, other_sim_context) in zip(self.sim_contexts, other.sim_contexts): - if not self_sim_context.__eq__(other_sim_context): - return False - return True - - def __repr__(self) -> str: - return 'Runnable Context:\n'\ - 'Sims: [{}]\n'.format( - self.sim_contexts, - ) diff --git a/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_object_context.py b/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_object_context.py deleted file mode 100644 index db13f34..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_object_context.py +++ /dev/null @@ -1,133 +0,0 @@ -""" -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 -""" - -from typing import Union, Tuple, Any, Dict - -from s4ap.sims4communitylib.classes.runnables.contexts.common_runnable_context import CommonRunnableContext -from objects.game_object import GameObject -from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils -from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils - - -class CommonRunnableObjectContext(CommonRunnableContext): - """CommonRunnableObjectContext(game_object) - - A context used by a runnable that contains information about an Object. - - :param game_object: The game object the context is for. - :type game_object: Union[GameObject, None] - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - raise NotImplementedError() - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - raise NotImplementedError() - - def __init__( - self, - game_object: Union[GameObject, None] - ): - super().__init__() - - if game_object is not None and CommonTypeUtils.is_game_object(game_object): - self._game_object = game_object - else: - self._game_object = None - - self._game_object_id = -1 - if self._game_object is not None: - self._game_object_id = CommonObjectUtils.get_object_id(self._game_object) - - @property - def game_object(self) -> Union[GameObject, None]: - """The Game Object this context is for.""" - return self._game_object - - @property - def game_object_id(self) -> int: - """The decimal identifier of the Game Object this context is for.""" - return self._game_object_id - - def _initialize(self, *_, **__) -> CommonExecutionResult: - return CommonExecutionResult.TRUE - - def _setup(self, *_, **__) -> CommonExecutionResult: - raise NotImplementedError() - - def _update(self, milliseconds_since_last_update: int, *_, **__) -> CommonExecutionResult: - raise NotImplementedError() - - def _teardown(self, teardown_reason: Union[int, CommonInt], *_, **__) -> CommonExecutionResult: - raise NotImplementedError() - - def _clone_args(self, *_, **__) -> Tuple[Any]: - result: Tuple[Any, ...] = ( - self.game_object, - *super()._clone_args(*_, **__) - ) - return result - - def _serialize_data(self, data: Dict[str, Any]): - super()._serialize_data(data) - if self.game_object_id != -1: - data['object_id'] = self.game_object_id - - @classmethod - def _deserialize_args(cls, data: Union[str, Dict[str, Any]]) -> Union[Tuple[Any], None]: - object_id = data.get('object_id', None) - if object_id is None: - return None - - game_object = CommonObjectUtils.get_game_object(object_id) - if game_object is None: - return None - - deserialized_args = super()._deserialize_args(data) - if deserialized_args is None: - return None - - result: Tuple[Any, ...] = ( - game_object, - *deserialized_args - ) - return result - - def __gt__(self, other: 'CommonRunnableObjectContext') -> bool: - if self.game_object is None: - return False - return self.game_object_id > other.game_object_id - - def __lt__(self, other: 'CommonRunnableObjectContext') -> bool: - if self.game_object is None: - return False - return self.game_object_id < other.game_object_id - - def __eq__(self, other: 'CommonRunnableObjectContext') -> bool: - if self.game_object is None: - return False - return self.game_object is other.game_object - - def __hash__(self) -> int: - if self.game_object is None: - return 0 - return self.game_object_id - - def __repr__(self) -> str: - return self.__str__() - - def __str__(self) -> str: - extra_str = self._get_str() - return f'<[CROC] {self.game_object} ({self.game_object_id}) {extra_str}>' diff --git a/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_sim_context.py b/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_sim_context.py deleted file mode 100644 index f1e205a..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/runnables/contexts/common_runnable_sim_context.py +++ /dev/null @@ -1,140 +0,0 @@ -""" -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 -""" - -from typing import Union, Dict, Any, Tuple - -from s4ap.sims4communitylib.classes.runnables.contexts.common_runnable_context import CommonRunnableContext -from sims.sim import Sim -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt -from s4ap.sims4communitylib.enums.sim_type import CommonSimType -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils -from s4ap.sims4communitylib.utils.sims.common_sim_type_utils import CommonSimTypeUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - - -class CommonRunnableSimContext(CommonRunnableContext): - """CommonRunnableSimContext(sim_info) - - A context used by a runnable that contains information about a Sim. - - :param sim_info: The Sim the context is for. - :type sim_info: SimInfo - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - raise NotImplementedError() - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - raise NotImplementedError() - - def __init__(self, sim_info: SimInfo): - super().__init__() - self._sim_info = sim_info - self._sim_full_name = CommonSimNameUtils.get_full_name(self._sim_info) - self._sim_type = CommonSimTypeUtils.determine_sim_type(self._sim_info) - - @property - def sim_info(self) -> SimInfo: - """The Sim this context is for.""" - return self._sim_info - - @property - def sim_full_name(self) -> str: - """The full name of the Sim this context is for.""" - return self._sim_full_name - - @property - def sim_id(self) -> int: - """The decimal identifier of the Sim this context is for.""" - return CommonSimUtils.get_sim_id(self._sim_info) - - @property - def sim(self) -> Sim: - """The instance of the Sim this context is for.""" - return CommonSimUtils.get_sim_instance(self._sim_info) - - @property - def sim_type(self) -> CommonSimType: - """The type of Sim.""" - return self._sim_type - - def _initialize(self, *_, **__) -> CommonExecutionResult: - raise NotImplementedError() - - def _setup(self, *_, **__) -> CommonExecutionResult: - raise NotImplementedError() - - def _update(self, milliseconds_since_last_update: int, *_, **__) -> CommonExecutionResult: - raise NotImplementedError() - - def _teardown(self, teardown_reason: Union[int, CommonInt], *_, **__) -> CommonExecutionResult: - raise NotImplementedError() - - def _clone_args(self, *_, **__) -> Tuple[Any]: - result: Tuple[Any, ...] = ( - self.sim_info, - *super()._clone_args(*_, **__) - ) - return result - - def _serialize_data(self, data: Dict[str, Any]): - super()._serialize_data(data) - data['sim_id'] = self.sim_id - - @classmethod - def _deserialize_args(cls, data: Union[str, Dict[str, Any]]) -> Union[Tuple[Any], None]: - sim_id = data.get('sim_id', None) - if sim_id is None: - return None - - deserialized_args = super()._deserialize_args(data) - if deserialized_args is None: - return None - - sim_info = CommonSimUtils.get_sim_info(sim_id) - if sim_info is None: - return None - - result: Tuple[Any, ...] = ( - sim_info, - *deserialized_args, - ) - return result - - def __gt__(self, other: 'CommonRunnableSimContext') -> bool: - if not isinstance(other, self.__class__): - return False - return self.sim_id > other.sim_id - - def __lt__(self, other: 'CommonRunnableSimContext') -> bool: - if not isinstance(other, self.__class__): - return False - return self.sim_id < other.sim_id - - def __eq__(self, other: 'CommonRunnableSimContext') -> bool: - if not isinstance(other, self.__class__): - return False - return self.sim_info is other.sim_info - - def __hash__(self) -> int: - return self.sim_id - - def __repr__(self) -> str: - return self.__str__() - - def __str__(self) -> str: - sim_type_name = self.sim_type.name - str_extras = self._get_str() - return f'<[CRSC] {self.sim_info} ST: {sim_type_name} {str_extras}>' diff --git a/Scripts/s4ap/sims4communitylib/classes/serialization/__init__.py b/Scripts/s4ap/sims4communitylib/classes/serialization/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/serialization/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/classes/serialization/common_serializable.py b/Scripts/s4ap/sims4communitylib/classes/serialization/common_serializable.py deleted file mode 100644 index c0e6db6..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/serialization/common_serializable.py +++ /dev/null @@ -1,34 +0,0 @@ -""" -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 -""" -from typing import Union, Any, Dict, TypeVar, Type - -CommonSerializableType = TypeVar('CommonSerializableType', bound="CommonSerializable") - - -class CommonSerializable: - """Indicates an object can be serialized and deserialized.""" - def serialize(self: CommonSerializableType) -> Union[str, Dict[str, Any]]: - """serialize() - - Serialize the object into a JSON Serializable form. - - :return: A serializable representation of the object. - :rtype: Union[str, Dict[str, Any]] - """ - raise NotImplementedError() - - @classmethod - def deserialize(cls: Type[CommonSerializableType], data: Union[str, Dict[str, Any]]) -> Union[CommonSerializableType, None]: - """deserialize(data) - - Deserialize the object from a JSON Serializable form. - - :return: The deserialized form of the object or None if it fails to deserialize. - :rtype: Union[CommonSerializableType, None] - """ - raise NotImplementedError() diff --git a/Scripts/s4ap/sims4communitylib/classes/serialization/common_serializable_location.py b/Scripts/s4ap/sims4communitylib/classes/serialization/common_serializable_location.py deleted file mode 100644 index 49ddc4c..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/serialization/common_serializable_location.py +++ /dev/null @@ -1,98 +0,0 @@ -""" -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 -""" -from typing import Dict, Any, Union - -from s4ap.sims4communitylib.classes.math.common_location import CommonLocation -from s4ap.sims4communitylib.classes.math.common_quaternion import CommonQuaternion -from s4ap.sims4communitylib.classes.math.common_surface_identifier import CommonSurfaceIdentifier -from s4ap.sims4communitylib.classes.math.common_transform import CommonTransform -from s4ap.sims4communitylib.classes.math.common_vector3 import CommonVector3 -from s4ap.sims4communitylib.classes.serialization.common_serializable import CommonSerializable - - -class CommonSerializableLocation(CommonSerializable): - """A wrapper to serialize/deserialize a CommonLocation.""" - def __init__(self, location: CommonLocation): - self.location = location - if isinstance(location, CommonSerializableLocation): - self.location = location.location - - # noinspection PyMissingOrEmptyDocstring - def serialize(self) -> Union[str, Dict[str, Any]]: - if self.location is None: - return dict() - transform = self.location.transform - translation = transform.translation - x = translation.x - y = translation.y - z = translation.z - orientation = transform.orientation - or_x = orientation.x - or_y = orientation.y - or_z = orientation.z - or_w = orientation.w - routing_surface = self.location.routing_surface - primary_id = routing_surface.primary_id - secondary_id = routing_surface.secondary_id - joint_name_or_hash = self.location.joint_name_or_hash - slot_hash = self.location.slot_hash - parent_ref = self.location.parent_ref - - return { - 'transform': { - 'translation': { - 'x': x, - 'y': y, - 'z': z - }, - 'orientation': { - 'x': or_x, - 'y': or_y, - 'z': or_z, - 'w': or_w - } - }, - 'routing_surface': { - 'primary_id': primary_id, - 'secondary_id': secondary_id - }, - 'joint_name_or_hash': joint_name_or_hash, - 'slot_hash': slot_hash, - 'parent_ref': parent_ref - } - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def deserialize(cls, data: Union[str, Dict[str, Any]]) -> Union['CommonSerializableLocation', None]: - if not data: - return None - if isinstance(data, CommonSerializableLocation): - return data - data: Dict[str, Any] = data - transform_data = data['transform'] - translation_data = transform_data['translation'] - x = translation_data['x'] - y = translation_data['y'] - z = translation_data['z'] - orientation_data = transform_data['orientation'] - or_x = orientation_data['x'] - or_y = orientation_data['y'] - or_z = orientation_data['z'] - or_w = orientation_data['w'] - routing_surface = data['routing_surface'] - primary_id = routing_surface['primary_id'] - secondary_id = routing_surface['secondary_id'] - joint_name_or_hash = data['joint_name_or_hash'] - slot_hash = data['slot_hash'] - parent_ref = data['parent_ref'] - - translation = CommonVector3(x, y, z) - orientation = CommonQuaternion(or_x, or_y, or_z, or_w) - transform = CommonTransform(translation, orientation) - routing_surface = CommonSurfaceIdentifier(primary_id, secondary_id=secondary_id) - return cls(CommonLocation(transform, routing_surface, parent_ref=parent_ref, joint_name_or_hash=joint_name_or_hash, slot_hash=slot_hash)) diff --git a/Scripts/s4ap/sims4communitylib/classes/test_based_scores/__init__.py b/Scripts/s4ap/sims4communitylib/classes/test_based_scores/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/test_based_scores/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/classes/test_based_scores/common_sim_to_sim_test_based_score.py b/Scripts/s4ap/sims4communitylib/classes/test_based_scores/common_sim_to_sim_test_based_score.py deleted file mode 100644 index 6a0727c..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/test_based_scores/common_sim_to_sim_test_based_score.py +++ /dev/null @@ -1,73 +0,0 @@ -""" -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 -""" -from event_testing.resolver import Resolver -from interactions import ParticipantType -from interactions.base.interaction import Interaction -from sims.sim_info import SimInfo -from sims4.sim_irq_service import yield_to_irq -from s4ap.sims4communitylib.classes.test_based_scores.common_test_based_score import CommonTestBasedScore -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - - -class CommonSimToSimTestBasedScore(CommonTestBasedScore): - """ A test based score used when testing a resolver involving two Sims. """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - raise NotImplementedError() - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - raise NotImplementedError() - - @classmethod - def get_score(cls, resolver: Resolver) -> int: - """get_score(resolver) - - Calculate the score. - """ - try: - yield_to_irq() - cls.get_verbose_log().format_with_message('Retrieving score.', class_name=cls.__name__) - source_sim = resolver.get_participant(ParticipantType.Actor) - target_sim = resolver.get_participant(ParticipantType.TargetSim) or resolver.get_participant(ParticipantType.Listeners) - if source_sim is None or target_sim is None or not CommonTypeUtils.is_sim_or_sim_info(source_sim) or not CommonTypeUtils.is_sim_or_sim_info(target_sim): - cls.get_verbose_log().format_with_message('Failed, the Source or the Target were not Sims.', source=source_sim, target=target_sim) - return cls.get_default_score() - source_sim_info = CommonSimUtils.get_sim_info(source_sim) - target_sim_info = CommonSimUtils.get_sim_info(target_sim) - interaction_instance = resolver.interaction or getattr(resolver, 'affordance', None) - score = cls.calculate_score(resolver, source_sim_info, target_sim_info, interaction_instance) - cls.get_verbose_log().format_with_message('Retrieved score for Sims.', source_sim=source_sim_info, target_sim=target_sim_info, score=score) - return score - except Exception as ex: - cls.get_verbose_log().error('Error occurred while retrieving score.', exception=ex) - return cls.get_default_score() - - @classmethod - def calculate_score(cls, resolver: Resolver, source_sim_info: SimInfo, target_sim_info: SimInfo, interaction: Interaction) -> int: - """calculate_score(resolver, source_sim_info, target_sim_info, interaction) - - Calculate a score involving two Sims. - - :param resolver: A resolver containing information about what is being tested. - :type resolver: Resolver - :param source_sim_info: The Source or Actor Sim of the test, also known as Sim A. - :type source_sim_info: SimInfo - :param target_sim_info: The Target or Listener Sim of the test, also known as Sim B. - :type target_sim_info: SimInfo - :param interaction: The interaction or affordance, if available, that Sim A is attempting to perform with the Sim B. If no interaction or affordance is present, this value will be None. - :type interaction: Interaction - :return: The calculated Score. - :rtype: int - """ - raise NotImplementedError() diff --git a/Scripts/s4ap/sims4communitylib/classes/test_based_scores/common_single_sim_test_based_score.py b/Scripts/s4ap/sims4communitylib/classes/test_based_scores/common_single_sim_test_based_score.py deleted file mode 100644 index e3f05cc..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/test_based_scores/common_single_sim_test_based_score.py +++ /dev/null @@ -1,69 +0,0 @@ -""" -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 -""" -from event_testing.resolver import Resolver -from interactions import ParticipantType -from interactions.base.interaction import Interaction -from sims.sim_info import SimInfo -from sims4.sim_irq_service import yield_to_irq -from s4ap.sims4communitylib.classes.test_based_scores.common_test_based_score import CommonTestBasedScore -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - - -class CommonSingleSimTestBasedScore(CommonTestBasedScore): - """ A test based score used when testing a resolver involving one Sim. """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - raise NotImplementedError() - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - raise NotImplementedError() - - @classmethod - def get_score(cls, resolver: Resolver) -> int: - """get_score(resolver) - - Calculate the score. - """ - try: - yield_to_irq() - cls.get_verbose_log().format_with_message('Retrieving score.', class_name=cls.__name__) - source_sim = resolver.get_participant(ParticipantType.Actor) - if source_sim is None or not CommonTypeUtils.is_sim_or_sim_info(source_sim): - cls.get_verbose_log().format_with_message('Failed, the Source was not a Sim.', source=source_sim) - return cls.get_default_score() - source_sim_info = CommonSimUtils.get_sim_info(source_sim) - interaction_instance = resolver.interaction or getattr(resolver, 'affordance', None) - score = cls.calculate_score(resolver, source_sim_info, interaction_instance) - cls.get_verbose_log().format_with_message('Retrieved score for Sim.', source_sim=source_sim_info, score=score) - return score - except Exception as ex: - cls.get_verbose_log().error('Error occurred while retrieving score.', exception=ex) - return cls.get_default_score() - - @classmethod - def calculate_score(cls, resolver: Resolver, source_sim_info: SimInfo, interaction: Interaction) -> int: - """calculate_score(resolver, source_sim_info, interaction) - - Calculate a score involving one Sim. - - :param resolver: A resolver containing information about what is being tested. - :type resolver: Resolver - :param source_sim_info: The Source or Actor Sim of the test. - :type source_sim_info: SimInfo - :param interaction: The interaction or affordance, if available, that the Source Sim is attempting to perform. If no interaction or affordance is present, this value will be None. - :type interaction: Interaction - :return: The calculated Score. - :rtype: int - """ - raise NotImplementedError() diff --git a/Scripts/s4ap/sims4communitylib/classes/test_based_scores/common_test_based_score.py b/Scripts/s4ap/sims4communitylib/classes/test_based_scores/common_test_based_score.py deleted file mode 100644 index b64ce8a..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/test_based_scores/common_test_based_score.py +++ /dev/null @@ -1,60 +0,0 @@ -""" -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 -""" -from event_testing.resolver import Resolver -from event_testing.test_based_score import TestBasedScore -from sims4.math import Threshold -from s4ap.sims4communitylib.logging.has_class_log import HasClassLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity - - -class CommonTestBasedScore(TestBasedScore, HasClassLog): - """ A test based score used when testing a resolver. """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - raise NotImplementedError() - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - raise NotImplementedError() - - def __init__(self, *_, **__) -> None: - super().__init__(*_, **__) - HasClassLog.__init__(self) - - @classmethod - def get_default_score(cls) -> int: - """The default score used when no other score is found or when an error occurs.""" - return 0 - - @classmethod - def passes_threshold(cls, resolver: Resolver, threshold: Threshold) -> bool: - """ True if the threshold is passed. """ - if resolver is not None: - cls.get_verbose_log().format( - resolver_type=type(resolver), - resolver_class=resolver.__class__, - resolver_class_name=resolver.__class__.__name__ - ) - if threshold is not None: - cls.get_verbose_log().format( - threshold_type=type(threshold), - threshold_class=threshold.__class__ - ) - return threshold.compare(cls.get_score(resolver)) - - @classmethod - def _verify_tuning_callback(cls) -> None: - pass - - @classmethod - def _tuning_loaded_callback(cls) -> None: - pass - diff --git a/Scripts/s4ap/sims4communitylib/classes/testing/__init__.py b/Scripts/s4ap/sims4communitylib/classes/testing/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/testing/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/classes/testing/common_enqueue_result.py b/Scripts/s4ap/sims4communitylib/classes/testing/common_enqueue_result.py deleted file mode 100644 index 9da8c53..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/testing/common_enqueue_result.py +++ /dev/null @@ -1,201 +0,0 @@ -""" -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 -""" -from event_testing.results import TestResult, EnqueueResult -from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult - - -class CommonEnqueueResult(EnqueueResult): - """CommonEnqueueResult(\ - test_result,\ - execute_result,\ - ) - - The result of enqueuing an interaction. - """ - TRUE = None - FALSE = None - NONE = None - test_result: CommonTestResult - execute_result: CommonExecutionResult - - def __new__(cls, test_result: CommonTestResult, execute_result: CommonExecutionResult): - return super(CommonEnqueueResult, cls).__new__(cls, test_result, execute_result) - - def reverse_result(self) -> 'CommonExecutionResult': - """reverse_result() - - Create a CommonExecutionResult that has a reversed result of this one, but with the same reason and tooltip information. - - .. note:: This function works best when the result value has an opposite, such as a boolean. - - :return: This CommonExecutionResult, but with a reversed result value. - :rtype: CommonExecutionResult - """ - return CommonEnqueueResult( - self.test_result.reverse_result(), - self.execute_result.reverse_result() - ) - - @property - def is_success(self) -> bool: - """True, if the result of enqueue is successful. False, if not.""" - return bool(self) - - @property - def is_failure(self) -> bool: - """False, if the result of enqueue is a failure. False, if not.""" - return not self.is_success - - def __repr__(self) -> str: - return f'<{self.__class__.__name__}: {repr(self.test_result)} {repr(self.execute_result)}>' - - def __str__(self) -> str: - return f'<{self.__class__.__name__}: {str(self.test_result)} {str(self.execute_result)}>' - - def __eq__(self, other) -> bool: - if isinstance(other, bool): - return self.is_success is other - if isinstance(other, CommonEnqueueResult): - return self.test_result == other.test_result and self.execute_result == other.execute_result - if isinstance(other, CommonExecutionResult): - return self.execute_result == other - if isinstance(other, CommonTestResult): - return self.test_result == other - if isinstance(other, TestResult): - return self.is_success == other.result - if isinstance(other, EnqueueResult): - return self.test_result == other.test_result and self.execute_result == other.execute_result - return self.test_result == other and self.execute_result == other - - def __ne__(self, other) -> bool: - return not self == other - - def __bool__(self) -> bool: - return bool(self.test_result) and bool(self.execute_result) - - def __or__(self, other) -> 'CommonExecutionResult': - if isinstance(other, CommonEnqueueResult): - test_result = self.test_result or other.test_result - execute_result = self.execute_result or other.execute_result - elif isinstance(other, EnqueueResult): - test_result = self.test_result or other.test_result - execute_result = self.execute_result or other.execute_result - elif isinstance(other, CommonExecutionResult): - test_result = self.test_result or CommonTestResult( - other.result, - reason=other.reason, - tooltip_text=other._tooltip_text, - tooltip_tokens=other._tooltip_tokens, - icon=other.icon, - influenced_by_active_mood=other.influence_by_active_mood, - hide_tooltip=other._hide_tooltip - ) - execute_result = self.execute_result or other - elif isinstance(other, CommonTestResult): - test_result = self.test_result or other - execute_result = self.execute_result or CommonExecutionResult( - other.result, - success_override=other._success_override, - reason=other.reason, - tooltip_text=other._tooltip_text, - tooltip_tokens=other._tooltip_tokens, - icon=other.icon, - influenced_by_active_mood=other.influence_by_active_mood, - hide_tooltip=other._hide_tooltip - ) - elif isinstance(other, bool): - test_result = self.test_result or CommonTestResult( - other, - reason=self.test_result.reason, - tooltip_text=self.test_result._tooltip_text, - tooltip_tokens=self.test_result._tooltip_tokens, - icon=self.test_result.icon, - influenced_by_active_mood=self.test_result.influence_by_active_mood, - hide_tooltip=self.test_result._hide_tooltip - ) - execute_result = self.execute_result or CommonExecutionResult( - other, - success_override=other, - reason=self.execute_result.reason, - tooltip_text=self.execute_result._tooltip_text, - tooltip_tokens=self.execute_result._tooltip_tokens, - icon=self.execute_result.icon, - influenced_by_active_mood=self.execute_result.influence_by_active_mood, - hide_tooltip=self.execute_result._hide_tooltip - ) - else: - return self - - return CommonEnqueueResult( - test_result, - execute_result - ) - - def __and__(self, other: 'CommonExecutionResult') -> 'CommonExecutionResult': - if isinstance(other, CommonEnqueueResult): - test_result = self.test_result and other.test_result - execute_result = self.execute_result and other.execute_result - elif isinstance(other, EnqueueResult): - test_result = self.test_result and other.test_result - execute_result = self.execute_result and other.execute_result - elif isinstance(other, CommonExecutionResult): - test_result = self.test_result and CommonTestResult( - other.result, - reason=other.reason, - tooltip_text=other._tooltip_text, - tooltip_tokens=other._tooltip_tokens, - icon=other.icon, - influenced_by_active_mood=other.influence_by_active_mood, - hide_tooltip=other._hide_tooltip - ) - execute_result = self.execute_result and other - elif isinstance(other, CommonTestResult): - test_result = self.test_result and other - execute_result = self.execute_result and CommonExecutionResult( - other.result, - success_override=other._success_override, - reason=other.reason, - tooltip_text=other._tooltip_text, - tooltip_tokens=other._tooltip_tokens, - icon=other.icon, - influenced_by_active_mood=other.influence_by_active_mood, - hide_tooltip=other._hide_tooltip - ) - elif isinstance(other, bool): - test_result = self.test_result and CommonTestResult( - other, - reason=self.test_result.reason, - tooltip_text=self.test_result._tooltip_text, - tooltip_tokens=self.test_result._tooltip_tokens, - icon=self.test_result.icon, - influenced_by_active_mood=self.test_result.influence_by_active_mood, - hide_tooltip=self.test_result._hide_tooltip - ) - execute_result = self.execute_result and CommonExecutionResult( - other, - success_override=other, - reason=self.execute_result.reason, - tooltip_text=self.execute_result._tooltip_text, - tooltip_tokens=self.execute_result._tooltip_tokens, - icon=self.execute_result.icon, - influenced_by_active_mood=self.execute_result.influence_by_active_mood, - hide_tooltip=self.execute_result._hide_tooltip - ) - else: - return self - - return CommonEnqueueResult( - test_result, - execute_result - ) - - -CommonEnqueueResult.TRUE = CommonEnqueueResult(CommonTestResult.TRUE, CommonExecutionResult.TRUE) -CommonEnqueueResult.FALSE = CommonEnqueueResult(CommonTestResult.FALSE, CommonExecutionResult.FALSE) -CommonEnqueueResult.NONE = CommonEnqueueResult(CommonTestResult.NONE, CommonExecutionResult.NONE) diff --git a/Scripts/s4ap/sims4communitylib/classes/testing/common_execution_result.py b/Scripts/s4ap/sims4communitylib/classes/testing/common_execution_result.py deleted file mode 100644 index 6af356d..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/testing/common_execution_result.py +++ /dev/null @@ -1,197 +0,0 @@ -""" -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 -""" -from typing import Any, Union, Iterator - -from event_testing.results import TestResult -from protocolbuffers.Localization_pb2 import LocalizedString -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from s4ap.sims4communitylib.utils.localization.common_localized_string_separators import CommonLocalizedStringSeparator - - -class CommonExecutionResult(TestResult): - """CommonExecutionResult(\ - result,\ - reason=None,\ - success_override=None,\ - tooltip_text=None,\ - tooltip_tokens=(),\ - icon=None,\ - influenced_by_active_mood=False,\ - hide_tooltip=False,\ - ) - - The result of executing something. - - .. note:: This class can be used in place of TestResult - - :param result: The result of execution. This value can be any type. - :type result: Any - :param reason: The reason for the success or failure of the execution result. Default is None. - :type reason: Union[str, None], optional - :param success_override: If True, the execution will be indicated as being a success. If False, the execution will be indicated as being a failure. If None, the execution success will be indicated by whether result is set or not, if result is a bool, success is True and failure is False. Default is None. - :type success_override: bool - :param tooltip_text: The text that will be displayed. If not specified, then no tooltip will be displayed. Default is None. - :type tooltip_text: Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator], optional - :param tooltip_tokens: A collection of objects to format into the localized tooltip. (They can be anything. LocalizedString, str, int, SimInfo, just to name a few). Default is an empty collection. - :type tooltip_tokens: Iterator[Any], optional - :param icon: The icon to display. Default is None. - :type icon: Any, optional - :param influenced_by_active_mood: Indicate whether or not the result was influenced by a Sims active mood. Default is False. - :type influenced_by_active_mood: bool, optional - :param hide_tooltip: If True, no tooltip will be shown to the Player, even if a tooltip is specified. If False, a tooltip will be shown to the Player and if not specified, will be created from the reason (Assuming a reason is specified). Default is False. - :type hide_tooltip: bool, optional - """ - TRUE = None - FALSE = None - NONE = None - - def __init__( - self, - result: Any, - reason: Union[str, None] = None, - success_override: bool = None, - tooltip_text: Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator, CommonLocalizationUtils.LocalizedTooltip] = None, - tooltip_tokens: Iterator[Any] = (), - icon: Any = None, - influenced_by_active_mood: bool = False, - hide_tooltip: bool = False - ) -> None: - self._tooltip_text = None - self._tooltip_tokens = None - self._hide_tooltip = hide_tooltip - tooltip = None - if not hide_tooltip: - self._tooltip_text = tooltip_text - self._tooltip_tokens = tooltip_tokens - if tooltip_text is not None: - tooltip = CommonLocalizationUtils.create_localized_tooltip(tooltip_text, tooltip_tokens=tooltip_tokens) - elif reason is not None: - tooltip = CommonLocalizationUtils.create_localized_tooltip(reason, tooltip_tokens=tooltip_tokens) - super().__init__(result, reason, tooltip=tooltip, icon=icon, influence_by_active_mood=influenced_by_active_mood) - self._success_override = success_override - if success_override is None: - if result: - success_override = True - else: - success_override = False - self._success = success_override - - @property - def tooltip_text(self) -> Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator, CommonLocalizationUtils.LocalizedTooltip]: - """The text of the tooltip.""" - return self._tooltip_text - - @property - def tooltip_tokens(self) -> Iterator[Any]: - """The tokens of the tooltip.""" - return self._tooltip_tokens - - def reverse_result(self) -> 'CommonExecutionResult': - """reverse_result() - - Create a CommonExecutionResult that has a reversed result of this one, but with the same reason and tooltip information. - - .. note:: This function works best when the result value has an opposite, such as a boolean. - - :return: This CommonExecutionResult, but with a reversed result value. - :rtype: CommonExecutionResult - """ - return CommonExecutionResult(not self.result, reason=self.reason, success_override=self._success, tooltip_text=self._tooltip_text, tooltip_tokens=self._tooltip_tokens, icon=self.icon, influenced_by_active_mood=self.influence_by_active_mood, hide_tooltip=self._hide_tooltip) - - @property - def is_success(self) -> bool: - """True, if the result of execution is successful. False, if not.""" - return self._success - - @property - def is_failure(self) -> bool: - """False, if the result of execution is a failure. False, if not.""" - return not self.is_success - - def __repr__(self) -> str: - if self.reason: - return f'<{self.__class__.__name__}: {bool(self.result)} ({self.reason})>' - return f'<{self.__class__.__name__}: {bool(self.result)}>' - - def __str__(self) -> str: - if self.reason: - return self.reason - return str(self.result) - - def __eq__(self, other) -> bool: - if isinstance(other, bool): - return self.is_success is other - if isinstance(other, CommonExecutionResult): - return self.result == other.result and self.is_success == other.is_success - if isinstance(other, TestResult): - return self.is_success == other.result - return self.result == other - - def __ne__(self, other) -> bool: - return not self == other - - def __bool__(self) -> bool: - return self._success - - def __or__(self, other) -> 'CommonExecutionResult': - if isinstance(other, CommonExecutionResult): - is_success = self.is_success or other.is_success - result = self.result or other.result - tooltip_text = self._tooltip_text or other._tooltip_text - tooltip_tokens = self._tooltip_tokens or other._tooltip_tokens - elif isinstance(other, TestResult): - is_success = self.is_success or other.result - result = self.result or other.result - if self._tooltip_text: - tooltip_text = self._tooltip_text - tooltip_tokens = self._tooltip_tokens - else: - tooltip_text = other.tooltip - tooltip_tokens = tuple() - else: - return self - - if self._reason: - reason = self._reason - else: - reason = other._reason - icon = self.icon or other.icon - influence_by_active_mood = self.influence_by_active_mood or other.influence_by_active_mood - return CommonExecutionResult(result, reason=reason, success_override=is_success, tooltip_text=tooltip_text, tooltip_tokens=tooltip_tokens, icon=icon, influenced_by_active_mood=influence_by_active_mood) - - def __and__(self, other: 'CommonExecutionResult') -> 'CommonExecutionResult': - if isinstance(other, CommonExecutionResult): - is_success = self.is_success and other.is_success - result = self.result or other.result - tooltip_text = self._tooltip_text or other._tooltip_text - tooltip_tokens = self._tooltip_tokens or other._tooltip_tokens - elif isinstance(other, TestResult): - is_success = self.is_success and other.result - result = self.result or other.result - if self._tooltip_text: - tooltip_text = self._tooltip_text - tooltip_tokens = self._tooltip_tokens - else: - tooltip_text = other.tooltip - tooltip_tokens = tuple() - else: - return self - - if self._reason: - reason = self._reason - else: - reason = other._reason - icon = self.icon or other.icon - influence_by_active_mood = self.influence_by_active_mood or other.influence_by_active_mood - return CommonExecutionResult(result, reason=reason, success_override=is_success, tooltip_text=tooltip_text, tooltip_tokens=tooltip_tokens, icon=icon, influenced_by_active_mood=influence_by_active_mood) - - -CommonExecutionResult.TRUE = CommonExecutionResult(True, hide_tooltip=True) -CommonExecutionResult.FALSE = CommonExecutionResult(False, reason='Failure Unknown', hide_tooltip=True) -CommonExecutionResult.NONE = CommonExecutionResult(False, hide_tooltip=True) diff --git a/Scripts/s4ap/sims4communitylib/classes/testing/common_test_result.py b/Scripts/s4ap/sims4communitylib/classes/testing/common_test_result.py deleted file mode 100644 index 75d29cc..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/testing/common_test_result.py +++ /dev/null @@ -1,149 +0,0 @@ -""" -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 -""" -from typing import Any, Union, Iterator - -from event_testing.results import TestResult -from protocolbuffers.Localization_pb2 import LocalizedString -from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from s4ap.sims4communitylib.utils.localization.common_localized_string_separators import CommonLocalizedStringSeparator - - -class CommonTestResult(CommonExecutionResult): - """CommonTestResult(\ - result,\ - reason=None,\ - tooltip_text=None,\ - tooltip_tokens=(),\ - icon=None,\ - influenced_by_active_mood=False,\ - hide_tooltip=False,\ - ) - - The result of testing something. - - .. note:: This class can be used in place of TestResult and CommonExecutionResult - - :param result: A value that indicates whether the test was successful or not. If True, the test was successful. If False, the test was not successful. - :type result: bool - :param reason: The reason for the success or failure of the test result. Default is None. - :type reason: Union[str, None], optional - :param tooltip_text: The text that will be displayed. If not specified, then no tooltip will be displayed. Default is None. - :type tooltip_text: Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator], optional - :param tooltip_tokens: A collection of objects to format into the localized tooltip. (They can be anything. LocalizedString, str, int, SimInfo, just to name a few). Default is an empty collection. - :type tooltip_tokens: Iterator[Any], optional - :param icon: The icon to display. Default is None. - :type icon: Any, optional - :param influenced_by_active_mood: Indicate whether or not the result was influenced by a Sims active mood. Default is False. - :type influenced_by_active_mood: bool, optional - :param hide_tooltip: If True, no tooltip will be shown to the Player, even if a tooltip is specified. If False, a tooltip will be shown to the Player and if not specified, will be created from the reason (Assuming a reason is specified). Default is False. - :type hide_tooltip: bool, optional - """ - TRUE = None - FALSE = None - NONE = None - - def __init__( - self, - result: bool, - reason: Union[str, None] = None, - tooltip_text: Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator, CommonLocalizationUtils.LocalizedTooltip] = None, - tooltip_tokens: Iterator[Any] = (), - icon: Any = None, - influenced_by_active_mood: bool = False, - hide_tooltip: bool = False - ) -> None: - super().__init__(result, reason=reason, success_override=result, tooltip_text=tooltip_text, tooltip_tokens=tooltip_tokens, icon=icon, influenced_by_active_mood=influenced_by_active_mood, hide_tooltip=hide_tooltip) - - @classmethod - def convert_from_vanilla(cls, test_result: TestResult) -> 'CommonTestResult': - """convert_from_vanilla(test_result) - - Convert a vanilla TestResult into a CommonTestResult. - - :param test_result: An instance of TestResult - :type test_result: TestResult - :return: The specified TestResult translated to CommonTestResult. - :rtype: CommonTestResult - """ - return CommonTestResult(test_result.result, reason=test_result.reason, tooltip_text=test_result.tooltip, icon=test_result.icon, influenced_by_active_mood=test_result.influence_by_active_mood) - - def reverse_result(self) -> 'CommonTestResult': - """reverse_result() - - Create a CommonTestResult that has a reversed result of this one, but with the same reason and tooltip information. - - .. note:: This function works best when the result value has an opposite, such as a boolean. - - :return: This CommonTestResult, but with a reversed result value. - :rtype: CommonTestResult - """ - return self.__class__(not self.result, self.reason, tooltip_text=self._tooltip_text, tooltip_tokens=self._tooltip_tokens) - - def __eq__(self, other) -> bool: - if isinstance(other, bool): - return self.is_success is other - if isinstance(other, CommonTestResult): - return self.result == other.result and self.is_success == other.is_success - if isinstance(other, TestResult): - return self.is_success == other.result - return self.result == other - - def __or__(self, other) -> 'CommonTestResult': - if isinstance(other, CommonTestResult): - result = self.result or other.result - tooltip_text = self._tooltip_text or other._tooltip_text - tooltip_tokens = self._tooltip_tokens or other._tooltip_tokens - elif isinstance(other, TestResult): - result = self.result or other.result - if self._tooltip_text: - tooltip_text = self._tooltip_text - tooltip_tokens = self._tooltip_tokens - else: - tooltip_text = other.tooltip - tooltip_tokens = tuple() - else: - return self - - if self._reason: - reason = self._reason - else: - reason = other._reason - icon = self.icon or other.icon - influence_by_active_mood = self.influence_by_active_mood or other.influence_by_active_mood - return self.__class__(result, reason, tooltip_text=tooltip_text, tooltip_tokens=tooltip_tokens, icon=icon, influenced_by_active_mood=influence_by_active_mood) - - def __and__(self, other: 'CommonTestResult') -> 'CommonTestResult': - if isinstance(other, CommonTestResult): - result = self.result and other.result - tooltip_text = self._tooltip_text or other._tooltip_text - tooltip_tokens = self._tooltip_tokens or other._tooltip_tokens - elif isinstance(other, TestResult): - result = self.result and other.result - if self._tooltip_text: - tooltip_text = self._tooltip_text - tooltip_tokens = self._tooltip_tokens - else: - tooltip_text = other.tooltip - tooltip_tokens = tuple() - else: - return self - - if self._reason: - reason = self._reason - else: - reason = other._reason - icon = self.icon or other.icon - influence_by_active_mood = self.influence_by_active_mood or other.influence_by_active_mood - return self.__class__(result, reason, tooltip_text=tooltip_text, tooltip_tokens=tooltip_tokens, icon=icon, influenced_by_active_mood=influence_by_active_mood) - - -CommonTestResult.TRUE = CommonTestResult(True, hide_tooltip=True) -CommonTestResult.FALSE = CommonTestResult(False, reason='Failure Unknown', hide_tooltip=True) -CommonTestResult.NONE = CommonTestResult(False, hide_tooltip=True) diff --git a/Scripts/s4ap/sims4communitylib/classes/time/__init__.py b/Scripts/s4ap/sims4communitylib/classes/time/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/time/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/classes/time/common_alarm_handle.py b/Scripts/s4ap/sims4communitylib/classes/time/common_alarm_handle.py deleted file mode 100644 index 65ee7c6..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/time/common_alarm_handle.py +++ /dev/null @@ -1,81 +0,0 @@ -""" -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 -""" -import os -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.common_time_utils import CommonTimeUtils -from typing import Any, Callable - - -ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' - -if ON_RTD: - # noinspection PyMissingOrEmptyDocstring - class AlarmHandle: - def cancel(self) -> Any: - pass - - # noinspection PyMissingOrEmptyDocstring - class DateAndTime: - pass - - # noinspection PyMissingOrEmptyDocstring - class TimeSpan: - pass - - # noinspection PyMissingOrEmptyDocstring - class Timeline: - pass - -if not ON_RTD: - from scheduling import Timeline, ElementHandle - from alarms import AlarmHandle - from date_and_time import DateAndTime, TimeSpan - - -class CommonAlarmHandle(AlarmHandle): - """A custom alarm handle that keeps track of when it is slated to trigger for the first time.""" - def __init__( - self, - owner: Any, - on_alarm_triggered_callback: Callable[['CommonAlarmHandle'], None], - timeline: Timeline, - when: DateAndTime, - should_repeat: bool=False, - time_until_repeat: TimeSpan=None, - accurate_repeat: bool=True, - persist_across_zone_loads: bool=False - ): - self.started_at_date_and_time = when - super().__init__( - owner, - on_alarm_triggered_callback, - timeline, - when, - repeating=should_repeat, - repeat_interval=time_until_repeat, - accurate_repeat=accurate_repeat, - cross_zone=persist_across_zone_loads - ) - - @property - def is_active(self) -> bool: - """True, if the Alarm Handle is currently active and scheduled. False, if not.""" - if self._element_handle is None: - return False - element_handle: ElementHandle = self._element_handle - # noinspection PyPropertyAccess - return element_handle.is_active and element_handle.is_scheduled - - -@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.print_current_time', 'Prints the current time.') -def _s4clib_print_current_time(output: CommonConsoleCommandOutput): - output('Current time') - output('Hour {} Minute {}'.format(CommonTimeUtils.get_current_date_and_time().hour(), CommonTimeUtils.get_current_date_and_time().minute())) - output('Abs Hour {} Abs Minute {}'.format(CommonTimeUtils.get_current_date_and_time().absolute_hours(), CommonTimeUtils.get_current_date_and_time().absolute_minutes())) diff --git a/Scripts/s4ap/sims4communitylib/classes/time/common_stop_watch.py b/Scripts/s4ap/sims4communitylib/classes/time/common_stop_watch.py deleted file mode 100644 index 63b921a..0000000 --- a/Scripts/s4ap/sims4communitylib/classes/time/common_stop_watch.py +++ /dev/null @@ -1,82 +0,0 @@ -""" -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 -""" -from time import perf_counter - - -class CommonStopWatch: - """CommonStopWatch() - - A class used to see how long things take. - - """ - def __init__(self) -> None: - self._start_time = None - self._started: bool = False - - def start(self) -> None: - """start() - - Start the stop watch. - """ - if self._started: - return - self._start_time = perf_counter() - self._started = True - - def interval(self) -> float: - """interval() - - Retrieve a time stamp for how long the watch has been running for without ending it. - - :return: The number of seconds that occurred since the stop watch was started. - :rtype: float - """ - if not self._started or self._start_time is None: - return -1.0 - interval_time = perf_counter() - fractional_seconds = (interval_time - self._start_time) - return fractional_seconds - - def interval_milliseconds(self) -> float: - """interval_milliseconds() - - Retrieve a time stamp for how long the watch has been running for without ending it, but in milliseconds. - - :return: The number of milliseconds that occurred since the stop watch was started. - :rtype: float - """ - from s4ap.sims4communitylib.utils.common_time_utils import CommonTimeUtils - return CommonTimeUtils.convert_seconds_to_milliseconds(self.interval()) - - def stop(self) -> float: - """stop() - - Stop the stop watch. - - .. warning:: This will also reset the start time of the stop watch. It will also stop the stop watch. - - :return: The number of seconds that occurred since starting the stop watch. - :rtype: float - """ - stopped_time = self.interval() - self._start_time = None - self._started = False - return stopped_time - - def stop_milliseconds(self) -> float: - """stop_milliseconds() - - Stop the stop watch, but return milliseconds rather than seconds. - - .. warning:: This will also reset the start time of the stop watch. It will also stop the stop watch. - - :return: The number of milliseconds that occurred since starting the stop watch. - :rtype: float - """ - from s4ap.sims4communitylib.utils.common_time_utils import CommonTimeUtils - return CommonTimeUtils.convert_seconds_to_milliseconds(self.stop()) diff --git a/Scripts/s4ap/sims4communitylib/conditionals/__init__.py b/Scripts/s4ap/sims4communitylib/conditionals/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/conditionals/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/conditionals/common_conditional_action.py b/Scripts/s4ap/sims4communitylib/conditionals/common_conditional_action.py deleted file mode 100644 index 3827485..0000000 --- a/Scripts/s4ap/sims4communitylib/conditionals/common_conditional_action.py +++ /dev/null @@ -1,66 +0,0 @@ -""" -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 -""" -from typing import Union - -from s4ap.sims4communitylib.logging.has_log import HasLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity - - -class CommonConditionalAction(HasLog): - """CommonConditionalAction() - - An inheritable class that Performs an action when a condition is met. - - .. note:: A common usage would be in a factory pattern with a collection of :class:`CommonConditionalAction` objects. - - """ - # noinspection PyMissingOrEmptyDocstring - @property - def mod_identity(self) -> Union[CommonModIdentity, None]: - return None - - def _should_apply(self, *_, **__) -> bool: - """_should_apply(*_, **__) - - Determine if the action should apply based on the given arguments. - - .. warning:: The arguments must match the :func:`~try_apply` method. - - :return: True, if the action should be applied. False, if not. - :rtype: bool - """ - return True - - def try_apply(self, *_, **__) -> bool: - """try_apply(*_, **__) - - Attempt to apply the action. - - .. note:: Override this method with any arguments you want to. - - :return: True, if the action was applied. False, if not. - :rtype: bool - """ - if self._should_apply(*_, **__): - self.log.debug('Applying action \'{}\'.'.format(self.__class__.__name__)) - return self._apply(*_, **__) - else: - self.log.debug('Skipping action \'{}\'.'.format(self.__class__.__name__)) - return False - - def _apply(self, *_, **__) -> bool: - """_apply(*_, **__) - - Apply the action. - - .. warning:: The arguments must match the :func:`~try_apply` arguments. - - :return: True, if the action was applied. False, if not. - :rtype: bool - """ - raise NotImplementedError('\'{}\' not implemented'.format(self.__class__._apply.__name__)) diff --git a/Scripts/s4ap/sims4communitylib/debug/__init__.py b/Scripts/s4ap/sims4communitylib/debug/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/debug/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/debug/dialogs/__init__.py b/Scripts/s4ap/sims4communitylib/debug/dialogs/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/debug/dialogs/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/debug/dialogs/common_change_object_state_dialog.py b/Scripts/s4ap/sims4communitylib/debug/dialogs/common_change_object_state_dialog.py deleted file mode 100644 index 9659db9..0000000 --- a/Scripts/s4ap/sims4communitylib/debug/dialogs/common_change_object_state_dialog.py +++ /dev/null @@ -1,114 +0,0 @@ -""" -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 -""" -from typing import Callable - -from objects.components.state import ObjectState -from objects.game_object import GameObject -from s4ap.sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext -from s4ap.sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_select_option import \ - CommonDialogSelectOption -from s4ap.sims4communitylib.dialogs.option_dialogs.common_choose_object_option_dialog import CommonChooseObjectOptionDialog -from s4ap.sims4communitylib.logging._has_s4cl_log import _HasS4CLLog -from s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from s4ap.sims4communitylib.utils.objects.common_object_state_utils import CommonObjectStateUtils -from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils - - -class CommonChangeObjectStateDialog(_HasS4CLLog): - """ Open a dialog that allows changing the states of objects. """ - - def __init__(self, game_object: GameObject, on_close: Callable[[], None] = None): - super().__init__() - self._game_object = game_object - self._on_close = on_close - - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - return 'common_change_object_state_dialog' - - def open(self) -> None: - """ Open Dialog. """ - def _reopen() -> None: - self.open() - - def _on_close() -> None: - if self._on_close is not None: - self._on_close() - - option_dialog = CommonChooseObjectOptionDialog( - CommonObjectUtils.get_catalog_name(self._game_object), - 0, - on_close=_on_close, - mod_identity=self.mod_identity, - per_page=500 - ) - - def _on_state_chosen(_: str, _chosen_state: ObjectState): - if _chosen_state is None: - _on_close() - return - self._modify_object_state_dialog(_chosen_state, on_close=_reopen) - - for (object_state, object_state_value) in CommonObjectStateUtils.get_object_state_items(self._game_object).items(): - display_name = CommonLocalizationUtils.create_localized_string(f'{object_state}: {object_state_value}') - option_dialog.add_option( - CommonDialogSelectOption( - str(object_state), - object_state, - CommonDialogOptionContext( - display_name, - 0, - icon=CommonIconUtils.load_arrow_right_icon() - ), - on_chosen=_on_state_chosen - ) - ) - - option_dialog.show(sort_options=True) - - def _modify_object_state_dialog(self, object_state: ObjectState, on_close: Callable[[], None]): - def _on_close() -> None: - on_close() - - option_dialog = CommonChooseObjectOptionDialog( - CommonObjectUtils.get_catalog_name(self._game_object), - 0, - on_close=_on_close, - mod_identity=self.mod_identity, - per_page=500 - ) - - def _on_state_chosen(_: str, _chosen_state: ObjectState): - if _chosen_state is None: - _on_close() - return - CommonObjectStateUtils.set_object_state(self._game_object, _chosen_state) - _on_close() - - current_object_state_value = CommonObjectStateUtils.get_current_object_state(self._game_object, object_state) - for object_state_value in object_state.values: - display_name = CommonLocalizationUtils.create_localized_string(str(object_state_value)) - icon = CommonIconUtils.load_unfilled_circle_icon() - if object_state_value == current_object_state_value: - icon = CommonIconUtils.load_filled_circle_icon() - option_dialog.add_option( - CommonDialogSelectOption( - str(object_state_value), - object_state_value, - CommonDialogOptionContext( - display_name, - 0, - icon=icon - ), - on_chosen=_on_state_chosen - ) - ) - - option_dialog.show(sort_options=True) diff --git a/Scripts/s4ap/sims4communitylib/debug/interactions/__init__.py b/Scripts/s4ap/sims4communitylib/debug/interactions/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/debug/interactions/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/debug/interactions/_register_interactions.py b/Scripts/s4ap/sims4communitylib/debug/interactions/_register_interactions.py deleted file mode 100644 index aae463a..0000000 --- a/Scripts/s4ap/sims4communitylib/debug/interactions/_register_interactions.py +++ /dev/null @@ -1,163 +0,0 @@ -""" -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 -""" -from typing import Tuple - -from objects.game_object import GameObject -from objects.script_object import ScriptObject -from sims.sim import Sim -from s4ap.sims4communitylib.enums.affordance_list_ids import CommonAffordanceListId -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt -from s4ap.sims4communitylib.enums.interactions_enum import CommonInteractionId -from s4ap.sims4communitylib.services.interactions.interaction_registration_service import CommonInteractionRegistry, \ - CommonInteractionType, CommonScriptObjectInteractionHandler, CommonInteractionHandler -from s4ap.sims4communitylib.services.resources.common_instance_manager_modification_registry import \ - CommonInstanceManagerModificationRegistry -from s4ap.sims4communitylib.services.resources.modification_handlers.common_add_interactions_to_affordance_lists_handler import \ - CommonAddInteractionsToAffordanceListsModificationHandler -from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils -from s4ap.sims4communitylib.utils.objects.common_object_state_utils import CommonObjectStateUtils - - -@CommonInteractionRegistry.register_interaction_handler(CommonInteractionType.ON_SCRIPT_OBJECT_LOAD) -class _S4CLObjectBrokennessDebugInteractionHandler(CommonScriptObjectInteractionHandler): - # noinspection PyMissingOrEmptyDocstring - @property - def interactions_to_add(self) -> Tuple[CommonInt]: - result: Tuple[CommonInt, ...] = ( - CommonInteractionId.S4CL_DEBUG_OBJECT_BREAK, - CommonInteractionId.S4CL_DEBUG_OBJECT_FIX - ) - return result - - # noinspection PyMissingOrEmptyDocstring - def should_add(self, script_object: ScriptObject, *args, **kwargs) -> bool: - if not isinstance(script_object, GameObject): - return False - script_object: GameObject = script_object - return CommonObjectStateUtils.can_become_broken(script_object) - - -@CommonInteractionRegistry.register_interaction_handler(CommonInteractionType.ON_SCRIPT_OBJECT_LOAD) -class _S4CLObjectDirtinessDebugInteractionHandler(CommonScriptObjectInteractionHandler): - # noinspection PyMissingOrEmptyDocstring - @property - def interactions_to_add(self) -> Tuple[CommonInt]: - result: Tuple[CommonInt, ...] = ( - CommonInteractionId.S4CL_DEBUG_OBJECT_MAKE_DIRTY, - CommonInteractionId.S4CL_DEBUG_OBJECT_MAKE_CLEAN - ) - return result - - # noinspection PyMissingOrEmptyDocstring - def should_add(self, script_object: ScriptObject, *args, **kwargs) -> bool: - if not isinstance(script_object, GameObject): - return False - script_object: GameObject = script_object - return CommonObjectStateUtils.can_become_dirty(script_object) - - -@CommonInteractionRegistry.register_interaction_handler(CommonInteractionType.ON_SCRIPT_OBJECT_LOAD) -class _S4CLDebugEverywhereObjectInteractionHandler(CommonScriptObjectInteractionHandler): - # noinspection PyMissingOrEmptyDocstring - @property - def interactions_to_add(self) -> Tuple[CommonInt]: - result: Tuple[CommonInt, ...] = ( - CommonInteractionId.S4CL_DEBUG_LOG_ALL_INTERACTIONS, - CommonInteractionId.S4CL_DEBUG_LOG_ALL_GAME_TAGS, - CommonInteractionId.S4CL_DEBUG_CHANGE_OBJECT_STATES, - ) - return result - - # noinspection PyMissingOrEmptyDocstring - def should_add(self, script_object: ScriptObject, *args, **kwargs) -> bool: - return not CommonTypeUtils.is_sim_or_sim_info(script_object) - - -@CommonInteractionRegistry.register_interaction_handler(CommonInteractionType.ON_TERRAIN_LOAD) -class _S4CLDebugEverywhereTerrainInteractionHandler(CommonInteractionHandler): - # noinspection PyMissingOrEmptyDocstring - @property - def interactions_to_add(self) -> Tuple[CommonInt]: - result: Tuple[CommonInt, ...] = ( - CommonInteractionId.S4CL_DEBUG_LOG_ALL_INTERACTIONS, - ) - return result - - -@CommonInteractionRegistry.register_interaction_handler(CommonInteractionType.ON_OCEAN_LOAD) -class _S4CLDebugEverywhereOceanInteractionHandler(CommonInteractionHandler): - # noinspection PyMissingOrEmptyDocstring - @property - def interactions_to_add(self) -> Tuple[CommonInt]: - result: Tuple[CommonInt, ...] = ( - CommonInteractionId.S4CL_DEBUG_LOG_ALL_INTERACTIONS, - CommonInteractionId.S4CL_DEBUG_LOG_ALL_GAME_TAGS, - CommonInteractionId.S4CL_DEBUG_CHANGE_OBJECT_STATES, - ) - return result - - -@CommonInteractionRegistry.register_interaction_handler(CommonInteractionType.ADD_TO_SIM_RELATIONSHIP_PANEL_INTERACTIONS) -class _S4CLDebugSimRelationshipPanelInteractionHandler(CommonScriptObjectInteractionHandler): - # noinspection PyMissingOrEmptyDocstring - @property - def interactions_to_add(self) -> Tuple[CommonInt]: - result: Tuple[CommonInt, ...] = ( - CommonInteractionId.S4CL_DEBUG_LOG_ALL_INTERACTIONS, - ) - return result - - # noinspection PyMissingOrEmptyDocstring - def should_add(self, script_object: Sim, *args, **kwargs) -> bool: - return CommonTypeUtils.is_sim_or_sim_info(script_object) - - -@CommonInteractionRegistry.register_interaction_handler(CommonInteractionType.ADD_TO_SIM_PHONE_INTERACTIONS) -class _S4CLDebugSimPhoneInteractionHandler(CommonScriptObjectInteractionHandler): - # noinspection PyMissingOrEmptyDocstring - @property - def interactions_to_add(self) -> Tuple[CommonInt]: - result: Tuple[CommonInt, ...] = ( - CommonInteractionId.S4CL_DEBUG_LOG_ALL_INTERACTIONS_PHONE, - ) - return result - - # noinspection PyMissingOrEmptyDocstring - def should_add(self, script_object: ScriptObject, *args, **kwargs) -> bool: - return CommonTypeUtils.is_sim_or_sim_info(script_object) - - -@CommonInstanceManagerModificationRegistry.register_modification_handler() -class _S4CLAddDebugInteractionsToAffordanceWhitelist(CommonAddInteractionsToAffordanceListsModificationHandler): - # noinspection PyMissingOrEmptyDocstring - @property - def interaction_ids(self) -> Tuple[CommonInt]: - result: Tuple[CommonInt, ...] = ( - CommonInteractionId.S4CL_DEBUG_SHOW_RUNNING_AND_QUEUED_INTERACTIONS, - CommonInteractionId.S4CL_DEBUG_SHOW_ACTIVE_BUFFS, - CommonInteractionId.S4CL_DEBUG_SHOW_TRAITS, - CommonInteractionId.S4CL_DEBUG_SHOW_RUNNING_SITUATIONS, - CommonInteractionId.S4CL_DEBUG_LOG_ALL_INTERACTIONS, - CommonInteractionId.S4CL_DEBUG_LOG_ALL_INTERACTIONS_PHONE, - CommonInteractionId.S4CL_DEBUG_INDUCE_LABOR, - CommonInteractionId.S4CL_DEBUG_OBJECT_BREAK, - CommonInteractionId.S4CL_DEBUG_OBJECT_FIX, - CommonInteractionId.S4CL_DEBUG_OBJECT_MAKE_DIRTY, - CommonInteractionId.S4CL_DEBUG_OBJECT_MAKE_CLEAN, - CommonInteractionId.S4CL_DEBUG_LOG_ALL_GAME_TAGS, - CommonInteractionId.S4CL_DEBUG_CHANGE_OBJECT_STATES, - ) - return result - - # noinspection PyMissingOrEmptyDocstring - @property - def affordance_list_ids(self) -> Tuple[int]: - result: Tuple[int, ...] = ( - CommonAffordanceListId.DEBUG_AFFORDANCES, - ) - return result diff --git a/Scripts/s4ap/sims4communitylib/debug/interactions/change_object_states.py b/Scripts/s4ap/sims4communitylib/debug/interactions/change_object_states.py deleted file mode 100644 index 5ea3ecf..0000000 --- a/Scripts/s4ap/sims4communitylib/debug/interactions/change_object_states.py +++ /dev/null @@ -1,70 +0,0 @@ -""" -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 -""" -from typing import Any, Tuple - -from interactions import ParticipantType -from interactions.context import InteractionContext -from sims.sim import Sim -from s4ap.sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction -from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - - -class S4CLDebugChangeObjectStatesInteraction(CommonImmediateSuperInteraction): - """ Change States of an Object. """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - return ModInfo.get_identity() - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 's4cl_debug_change_object_states' - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, picked_item_ids: Tuple[int] = (), **kwargs) -> CommonTestResult: - if interaction_target is None and not picked_item_ids: - cls.get_log().debug('Failed, Target is not valid.') - return CommonTestResult.NONE - cls.get_log().debug('Success, can show active Buffs.') - return CommonTestResult.TRUE - - # noinspection PyMissingOrEmptyDocstring - def on_started(self, interaction_sim: Sim, interaction_target: Any) -> CommonExecutionResult: - picked_item_id = self.get_participant(ParticipantType.PickedItemId) - self.log.format_with_message('Got picked item ids', picked_item_id=picked_item_id) - if picked_item_id is not None: - new_target = CommonSimUtils.get_sim_info(picked_item_id) - if new_target is None: - self.log.format_with_message('No Sim with the identifier found.', picked_item_id=picked_item_id) - new_target = CommonObjectUtils.get_game_object(picked_item_id) - if new_target is None: - self.log.format_with_message('No object with the identifier found.', picked_item_id=picked_item_id) - return CommonExecutionResult(False, reason=f'Picked Item {picked_item_id} was not found.') - else: - self.log.format_with_message('Found object target using picked item id.', new_target=new_target) - interaction_target = new_target - else: - self.log.format_with_message('Found Sim target using picked item id.', new_target=new_target) - new_target = CommonSimUtils.get_sim_instance(new_target) - if new_target is None: - self.log.format_with_message('Had Sim Info, but did not have Sim instance.', new_target=new_target) - else: - self.log.format_with_message('Had Sim Instance.', new_target=new_target) - interaction_target = new_target - - from s4ap.sims4communitylib.debug.dialogs.common_change_object_state_dialog import CommonChangeObjectStateDialog - CommonChangeObjectStateDialog(interaction_target).open() - return CommonExecutionResult.TRUE diff --git a/Scripts/s4ap/sims4communitylib/debug/interactions/induce_labor.py b/Scripts/s4ap/sims4communitylib/debug/interactions/induce_labor.py deleted file mode 100644 index a42e727..0000000 --- a/Scripts/s4ap/sims4communitylib/debug/interactions/induce_labor.py +++ /dev/null @@ -1,62 +0,0 @@ -""" -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 -""" -from typing import Any - -from interactions.context import InteractionContext -from sims.sim import Sim -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils -from s4ap.sims4communitylib.utils.sims.common_sim_pregnancy_utils import CommonSimPregnancyUtils -from s4ap.sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils - - -class S4CLDebugInduceLaborInteraction(CommonImmediateSuperInteraction): - """ Handle the interaction to Induce Labor. """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - return ModInfo.get_identity() - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 's4cl_debug_induce_labor' - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, **kwargs) -> CommonTestResult: - if interaction_target is None or not CommonTypeUtils.is_sim_or_sim_info(interaction_target): - cls.get_log().debug('Target is not a Sim.') - return CommonTestResult.NONE - target_sim_info = CommonSimUtils.get_sim_info(interaction_target) - if not CommonSimPregnancyUtils.can_be_impregnated(target_sim_info): - cls.get_log().format_with_message('Sim cannot be impregnated and thus cannot be pregnant.', target_sim=target_sim_info) - return CommonTestResult.NONE - if not hasattr(target_sim_info, 'pregnancy_tracker'): - cls.get_log().format_with_message('Target does not have a pregnancy tracker.', target_sim=target_sim_info) - return CommonTestResult.NONE - cls.get_log().format_with_message('Checking if Sim is pregnant.', target_sim=target_sim_info) - if not CommonSimPregnancyUtils.is_pregnant(target_sim_info): - cls.get_log().format_with_message('Sim is not pregnant.', sim=target_sim_info) - return cls.create_test_result(False, reason='\'{}\' is not pregnant.'.format(CommonSimNameUtils.get_full_name(target_sim_info)), tooltip=CommonLocalizationUtils.create_localized_tooltip(CommonStringId.S4CL_SIM_IS_NOT_PREGNANT, tooltip_tokens=(target_sim_info, ))) - cls.get_log().debug('Success.') - return CommonTestResult.TRUE - - # noinspection PyMissingOrEmptyDocstring - def on_started(self, interaction_sim: Sim, interaction_target: Sim) -> bool: - target_sim_info = CommonSimUtils.get_sim_info(interaction_target) - self.log.format_with_message('The baby wants out now! Labor induced in Sim.', target_sim=target_sim_info) - CommonSimPregnancyUtils.induce_labor_in_sim(target_sim_info) - return True diff --git a/Scripts/s4ap/sims4communitylib/debug/interactions/log_all_game_tags.py b/Scripts/s4ap/sims4communitylib/debug/interactions/log_all_game_tags.py deleted file mode 100644 index a36bd18..0000000 --- a/Scripts/s4ap/sims4communitylib/debug/interactions/log_all_game_tags.py +++ /dev/null @@ -1,69 +0,0 @@ -""" -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 -""" -from typing import Any, Tuple - -from interactions import ParticipantType -from interactions.context import InteractionContext -from sims.sim import Sim -from s4ap.sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction -from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.utils.objects.common_object_tag_utils import CommonObjectTagUtils -from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - - -class S4CLDebugLogAllGameTagsInteraction(CommonImmediateSuperInteraction): - """ Log All Game Tags of a Target. """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - return ModInfo.get_identity() - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 's4cl_debug_log_all_game_tags' - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, picked_item_ids: Tuple[int] = (), **kwargs) -> CommonTestResult: - if interaction_target is None and not picked_item_ids: - cls.get_log().debug('Failed, Target is not valid.') - return CommonTestResult.NONE - cls.get_log().debug('Success, can show active Buffs.') - return CommonTestResult.TRUE - - # noinspection PyMissingOrEmptyDocstring - def on_started(self, interaction_sim: Sim, interaction_target: Any) -> CommonExecutionResult: - picked_item_id = self.get_participant(ParticipantType.PickedItemId) - self.log.format_with_message('Got picked item ids', picked_item_id=picked_item_id) - if picked_item_id is not None: - new_target = CommonSimUtils.get_sim_info(picked_item_id) - if new_target is None: - self.log.format_with_message('No Sim with the identifier found.', picked_item_id=picked_item_id) - new_target = CommonObjectUtils.get_game_object(picked_item_id) - if new_target is None: - self.log.format_with_message('No object with the identifier found.', picked_item_id=picked_item_id) - return CommonExecutionResult(False, reason=f'Picked Item {picked_item_id} was not found.') - else: - self.log.format_with_message('Found object target using picked item id.', new_target=new_target) - interaction_target = new_target - else: - self.log.format_with_message('Found Sim target using picked item id.', new_target=new_target) - new_target = CommonSimUtils.get_sim_instance(new_target) - if new_target is None: - self.log.format_with_message('Had Sim Info, but did not have Sim instance.', new_target=new_target) - else: - self.log.format_with_message('Had Sim Instance.', new_target=new_target) - interaction_target = new_target - CommonObjectTagUtils._print_game_tags(interaction_target) - return CommonExecutionResult.TRUE diff --git a/Scripts/s4ap/sims4communitylib/debug/interactions/log_all_interactions.py b/Scripts/s4ap/sims4communitylib/debug/interactions/log_all_interactions.py deleted file mode 100644 index 93c893d..0000000 --- a/Scripts/s4ap/sims4communitylib/debug/interactions/log_all_interactions.py +++ /dev/null @@ -1,134 +0,0 @@ -""" -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 -""" -from pprint import pformat -from typing import Any, List, Tuple -from interactions import ParticipantType -from interactions.base.interaction import Interaction -from interactions.context import InteractionContext -from objects.game_object import GameObject -from sims.sim import Sim -from s4ap.sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction -from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.notifications.common_basic_notification import CommonBasicNotification -from s4ap.sims4communitylib.utils.common_log_utils import CommonLogUtils -from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils -from s4ap.sims4communitylib.utils.objects.common_object_interaction_utils import CommonObjectInteractionUtils -from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils -from s4ap.sims4communitylib.utils.resources.common_interaction_utils import CommonInteractionUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - - -class S4CLDebugLogAllInteractionsInteraction(CommonImmediateSuperInteraction): - """ Log All Interactions of an object. """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - return ModInfo.get_identity() - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 's4cl_debug_log_all_interactions' - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, picked_item_ids: Tuple[int] = (), **kwargs) -> CommonTestResult: - if interaction_target is None and not picked_item_ids: - cls.get_log().debug('Failed, No Target was found.') - return cls.create_test_result(False) - cls.get_log().format_with_message( - 'Success, can show Log All Interactions interaction.', - interaction_sim=interaction_sim, - interaction_target=interaction_target, - picked_item_ids=picked_item_ids - ) - return cls.create_test_result(True) - - # noinspection PyMissingOrEmptyDocstring - def on_started(self, interaction_sim: Sim, interaction_target: Any) -> CommonExecutionResult: - self.log.enable() - # noinspection PyUnresolvedReferences - picked_item_id = self.get_participant(ParticipantType.PickedItemId) - self.log.format_with_message('Got picked item ids', picked_item_id=picked_item_id) - if picked_item_id is not None: - new_target = CommonSimUtils.get_sim_info(picked_item_id) - if new_target is None: - self.log.format_with_message('No Sim with the identifier found.', picked_item_id=picked_item_id) - new_target = CommonObjectUtils.get_game_object(picked_item_id) - if new_target is None: - self.log.format_with_message('No object with the identifier found.', picked_item_id=picked_item_id) - return CommonExecutionResult(False, reason=f'Picked Item {picked_item_id} was not found.') - else: - self.log.format_with_message('Found object target using picked item id.', new_target=new_target) - interaction_target = new_target - else: - self.log.format_with_message('Found Sim target using picked item id.', new_target=new_target) - new_target = CommonSimUtils.get_sim_instance(new_target) - if new_target is None: - self.log.format_with_message('Had Sim Info, but did not have Sim instance.', new_target=new_target) - else: - self.log.format_with_message('Had Sim Instance.', new_target=new_target) - interaction_target = new_target - object_id = CommonObjectUtils.get_object_id(interaction_target) if interaction_target is not None else -1 - object_tuning_name = None - definition_id = -1 - if CommonTypeUtils.is_sim_or_sim_info(interaction_target): - target_sim_info = CommonSimUtils.get_sim_info(interaction_target) - object_id = CommonSimUtils.get_sim_id(interaction_target) - target_sim = CommonSimUtils.get_sim_instance(interaction_target) - object_tuning_name = target_sim.__name__ if hasattr(target_sim, '__name__') else target_sim.__class__.__name__ - rig_hash64 = target_sim.rig.hash64 - rig_instance = target_sim.rig.instance - self.log.format_with_message('All things on rig', rig64=rig_hash64, rig_instance=rig_instance, target_rig_key=target_sim_info.rig_key) - definition = CommonObjectUtils.get_game_object_definition(target_sim) - if definition is not None: - definition_id = definition.id - elif CommonTypeUtils.is_game_object(interaction_target): - object_tuning_name = interaction_target.__name__ if hasattr(interaction_target, '__name__') else interaction_target.__class__.__name__ - rig_hash64 = interaction_target.rig.hash64 - rig_instance = interaction_target.rig.instance - self.log.format_with_message('All things on rig', rig64=rig_hash64, rig_instance=rig_instance) - definition = CommonObjectUtils.get_game_object_definition(interaction_target) - if definition is not None: - definition_id = definition.id - self.log.debug(f'Interactions that can be performed on \'{interaction_target}\' id:{object_id} def_id:{definition_id} tuning_name:{object_tuning_name}:') - interactions = CommonObjectInteractionUtils.get_all_interactions_registered_to_object_gen(interaction_target) - interaction_target: GameObject = interaction_target - interaction_short_names: List[str] = list() - for interaction in interactions: - interaction: Interaction = interaction - try: - interaction_short_names.append('{} ({})'.format(CommonInteractionUtils.get_interaction_short_name(interaction), CommonInteractionUtils.get_interaction_id(interaction))) - except Exception as ex: - self.log.error('Problem while attempting to handle interaction {}'.format(pformat(interaction)), exception=ex) - continue - for component in interaction_target.components: - if not hasattr(component, 'component_super_affordances_gen'): - continue - for affordance in component.component_super_affordances_gen(): - try: - interaction_short_names.append('{} ({})'.format(CommonInteractionUtils.get_interaction_short_name(affordance), CommonInteractionUtils.get_interaction_id(affordance))) - except Exception as ex: - self.log.error('Problem while attempting to handle affordance {}'.format(pformat(affordance)), exception=ex) - continue - - sorted_short_names = sorted(interaction_short_names, key=lambda x: x) - self.log.format(interactions=sorted_short_names) - self.log.debug('Done Logging Available Interactions.') - self.log.disable() - CommonBasicNotification( - CommonStringId.S4CL_LOG_ALL_INTERACTIONS, - CommonStringId.S4CL_DONE_LOGGING_ALL_INTERACTIONS, - description_tokens=(CommonLogUtils.get_message_file_path(self.mod_identity), ) - ).show() - return CommonExecutionResult.TRUE diff --git a/Scripts/s4ap/sims4communitylib/debug/interactions/object_break.py b/Scripts/s4ap/sims4communitylib/debug/interactions/object_break.py deleted file mode 100644 index 4a788c9..0000000 --- a/Scripts/s4ap/sims4communitylib/debug/interactions/object_break.py +++ /dev/null @@ -1,51 +0,0 @@ -""" -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 -""" -from typing import Any -from interactions.context import InteractionContext -from objects.game_object import GameObject -from sims.sim import Sim -from s4ap.sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils -from s4ap.sims4communitylib.utils.objects.common_object_state_utils import CommonObjectStateUtils - - -class S4CLDebugObjectBreakInteraction(CommonImmediateSuperInteraction): - """S4CLDebugObjectBreakInteraction(*_, **__) - - Set the target Object to a broken state. - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - return ModInfo.get_identity() - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 's4cl_debug_break_object' - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, **kwargs) -> CommonTestResult: - if interaction_target is None or CommonTypeUtils.is_sim_or_sim_info(interaction_target): - cls.get_log().debug('Failed, Target is None.') - return CommonTestResult.NONE - interaction_target: GameObject = interaction_target - if CommonObjectStateUtils.is_broken(interaction_target): - cls.get_log().debug('Failed, the Object is already broken.') - return CommonTestResult.NONE - cls.get_log().debug('Success, can break object.') - return CommonTestResult.TRUE - - # noinspection PyMissingOrEmptyDocstring - def on_started(self, interaction_sim: Sim, interaction_target: GameObject) -> bool: - return CommonObjectStateUtils.break_object(interaction_target) diff --git a/Scripts/s4ap/sims4communitylib/debug/interactions/object_fix.py b/Scripts/s4ap/sims4communitylib/debug/interactions/object_fix.py deleted file mode 100644 index aab7251..0000000 --- a/Scripts/s4ap/sims4communitylib/debug/interactions/object_fix.py +++ /dev/null @@ -1,51 +0,0 @@ -""" -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 -""" -from typing import Any -from interactions.context import InteractionContext -from objects.game_object import GameObject -from sims.sim import Sim -from s4ap.sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils -from s4ap.sims4communitylib.utils.objects.common_object_state_utils import CommonObjectStateUtils - - -class S4CLDebugObjectFixInteraction(CommonImmediateSuperInteraction): - """S4CLDebugObjectFixInteraction(*_, **__) - - Set the target Object to a fixed state. - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - return ModInfo.get_identity() - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 's4cl_debug_fix_object' - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, **kwargs) -> CommonTestResult: - if interaction_target is None or CommonTypeUtils.is_sim_or_sim_info(interaction_target): - cls.get_log().debug('Failed, Target is None.') - return CommonTestResult.NONE - interaction_target: GameObject = interaction_target - if not CommonObjectStateUtils.is_broken(interaction_target): - cls.get_log().debug('Failed, the Object is not broken.') - return CommonTestResult.NONE - cls.get_log().debug('Success, can fix object.') - return CommonTestResult.TRUE - - # noinspection PyMissingOrEmptyDocstring - def on_started(self, interaction_sim: Sim, interaction_target: GameObject) -> bool: - return CommonObjectStateUtils.fix_object(interaction_target) diff --git a/Scripts/s4ap/sims4communitylib/debug/interactions/object_make_clean.py b/Scripts/s4ap/sims4communitylib/debug/interactions/object_make_clean.py deleted file mode 100644 index b9f348a..0000000 --- a/Scripts/s4ap/sims4communitylib/debug/interactions/object_make_clean.py +++ /dev/null @@ -1,51 +0,0 @@ -""" -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 -""" -from typing import Any -from interactions.context import InteractionContext -from objects.game_object import GameObject -from sims.sim import Sim -from s4ap.sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils -from s4ap.sims4communitylib.utils.objects.common_object_state_utils import CommonObjectStateUtils - - -class S4CLDebugObjectMakeCleanInteraction(CommonImmediateSuperInteraction): - """S4CLDebugObjectMakeCleanInteraction(*_, **__) - - Set the target Object to a clean state. - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - return ModInfo.get_identity() - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 's4cl_debug_make_object_clean' - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, **kwargs) -> CommonTestResult: - if interaction_target is None or CommonTypeUtils.is_sim_or_sim_info(interaction_target): - cls.get_log().debug('Failed, Target is None.') - return CommonTestResult.NONE - interaction_target: GameObject = interaction_target - if not CommonObjectStateUtils.is_dirty(interaction_target): - cls.get_log().debug('Failed, the Object is not dirty.') - return CommonTestResult.NONE - cls.get_log().debug('Success, can make object clean.') - return CommonTestResult.TRUE - - # noinspection PyMissingOrEmptyDocstring - def on_started(self, interaction_sim: Sim, interaction_target: GameObject) -> bool: - return CommonObjectStateUtils.make_clean(interaction_target) diff --git a/Scripts/s4ap/sims4communitylib/debug/interactions/object_make_dirty.py b/Scripts/s4ap/sims4communitylib/debug/interactions/object_make_dirty.py deleted file mode 100644 index f8ce293..0000000 --- a/Scripts/s4ap/sims4communitylib/debug/interactions/object_make_dirty.py +++ /dev/null @@ -1,51 +0,0 @@ -""" -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 -""" -from typing import Any -from interactions.context import InteractionContext -from objects.game_object import GameObject -from sims.sim import Sim -from s4ap.sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils -from s4ap.sims4communitylib.utils.objects.common_object_state_utils import CommonObjectStateUtils - - -class S4CLDebugObjectMakeDirtyInteraction(CommonImmediateSuperInteraction): - """S4CLDebugObjectMakeDirtyInteraction(*_, **__) - - Set the target Object to a dirty state. - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - return ModInfo.get_identity() - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 's4cl_debug_make_object_dirty' - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, **kwargs) -> CommonTestResult: - if interaction_target is None or CommonTypeUtils.is_sim_or_sim_info(interaction_target): - cls.get_log().debug('Failed, Target is None.') - return CommonTestResult.NONE - interaction_target: GameObject = interaction_target - if CommonObjectStateUtils.is_dirty(interaction_target): - cls.get_log().debug('Failed, the Object is already dirty.') - return CommonTestResult.NONE - cls.get_log().debug('Success, can make object dirty.') - return CommonTestResult.TRUE - - # noinspection PyMissingOrEmptyDocstring - def on_started(self, interaction_sim: Sim, interaction_target: GameObject) -> bool: - return CommonObjectStateUtils.make_dirty(interaction_target) diff --git a/Scripts/s4ap/sims4communitylib/debug/interactions/show_active_buffs.py b/Scripts/s4ap/sims4communitylib/debug/interactions/show_active_buffs.py deleted file mode 100644 index ebea254..0000000 --- a/Scripts/s4ap/sims4communitylib/debug/interactions/show_active_buffs.py +++ /dev/null @@ -1,74 +0,0 @@ -""" -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 -""" -from typing import Any, List - -from distributor.shared_messages import IconInfoData -from interactions.context import InteractionContext -from sims.sim import Sim -from s4ap.sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.notifications.common_basic_notification import CommonBasicNotification -from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from s4ap.sims4communitylib.utils.sims.common_buff_utils import CommonBuffUtils -from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - - -class S4CLDebugShowActiveBuffsInteraction(CommonImmediateSuperInteraction): - """S4CLDebugShowActiveBuffsInteraction(*_, **__) - - Show the currently active Buffs of a Sim. - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - return ModInfo.get_identity() - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 's4cl_debug_show_active_buffs' - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, **kwargs) -> CommonTestResult: - if interaction_target is None or not CommonTypeUtils.is_sim_or_sim_info(interaction_target): - cls.get_log().debug('Failed, Target is not a Sim.') - return CommonTestResult.NONE - cls.get_log().debug('Success, can show active Buffs.') - return CommonTestResult.TRUE - - # noinspection PyMissingOrEmptyDocstring - def on_started(self, interaction_sim: Sim, interaction_target: Sim) -> bool: - target_sim_info = CommonSimUtils.get_sim_info(interaction_target) - target_sim_name = CommonSimNameUtils.get_full_name(target_sim_info) - sim_buff_strings: List[str] = list() - for buff in CommonBuffUtils.get_buffs(target_sim_info): - buff_name = CommonBuffUtils.get_buff_name(buff) - buff_id = CommonBuffUtils.get_buff_id(buff) - sim_buff_strings.append('{} ({})'.format(buff_name, buff_id)) - sim_buff_strings = sorted(sim_buff_strings, key=lambda x: x) - sim_buffs = ', '.join(sim_buff_strings) - text = '' - text += 'Active Buffs:\n{}\n\n'.format(sim_buffs) - self.log.enable() - sim_buffs_for_log = ',\n'.join(sim_buff_strings) - for_log_text = 'Active Buffs:\n{}\n\n'.format(sim_buffs_for_log) - self.log.debug(f'{target_sim_name} ({CommonSimUtils.get_sim_id(target_sim_info)}): {for_log_text}') - self.log.disable() - CommonBasicNotification( - CommonLocalizationUtils.create_localized_string('{} Active Buffs ({})'.format(target_sim_name, CommonSimUtils.get_sim_id(target_sim_info))), - CommonLocalizationUtils.create_localized_string(text) - ).show( - icon=IconInfoData(obj_instance=interaction_target) - ) - return True diff --git a/Scripts/s4ap/sims4communitylib/debug/interactions/show_running_and_queued_interactions.py b/Scripts/s4ap/sims4communitylib/debug/interactions/show_running_and_queued_interactions.py deleted file mode 100644 index 3caf959..0000000 --- a/Scripts/s4ap/sims4communitylib/debug/interactions/show_running_and_queued_interactions.py +++ /dev/null @@ -1,86 +0,0 @@ -""" -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 -""" -from typing import Any, List - -from distributor.shared_messages import IconInfoData -from interactions.context import InteractionContext -from sims.sim import Sim -from s4ap.sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.notifications.common_basic_notification import CommonBasicNotification -from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - - -class S4CLDebugShowRunningAndQueuedInteractionsInteraction(CommonImmediateSuperInteraction): - """S4CLDebugShowRunningAndQueuedInteractionsInteraction(*_, **__) - - Show the currently running and queued interactions of a Sim. - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - return ModInfo.get_identity() - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 's4cl_debug_show_running_and_queued_interactions' - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, **kwargs) -> CommonTestResult: - if interaction_target is None or not CommonTypeUtils.is_sim_or_sim_info(interaction_target): - cls.get_log().debug('Failed, Target is not a Sim.') - return CommonTestResult.NONE - cls.get_log().debug('Success, can show running and queued interactions.') - return CommonTestResult.TRUE - - # noinspection PyMissingOrEmptyDocstring - def on_started(self, interaction_sim: Sim, interaction_target: Sim) -> bool: - target_sim_info = CommonSimUtils.get_sim_info(interaction_target) - target_sim_name = CommonSimNameUtils.get_full_name(target_sim_info) - from s4ap.sims4communitylib.utils.sims.common_sim_interaction_utils import CommonSimInteractionUtils - from s4ap.sims4communitylib.utils.resources.common_interaction_utils import CommonInteractionUtils - running_interaction_strings: List[str] = list() - for interaction in CommonSimInteractionUtils.get_running_interactions_gen(target_sim_info): - interaction_name = CommonInteractionUtils.get_interaction_short_name(interaction) - interaction_id = CommonInteractionUtils.get_interaction_id(interaction) - running_interaction_strings.append('{} ({})'.format(interaction_name, interaction_id)) - running_interaction_strings = sorted(running_interaction_strings, key=lambda x: x) - running_interaction_names = ', '.join(running_interaction_strings) - - queued_interaction_strings: List[str] = list() - for interaction in CommonSimInteractionUtils.get_queued_interactions_gen(target_sim_info): - interaction_name = CommonInteractionUtils.get_interaction_short_name(interaction) - interaction_id = CommonInteractionUtils.get_interaction_id(interaction) - queued_interaction_strings.append('{} ({})'.format(interaction_name, interaction_id)) - queued_interaction_strings = sorted(queued_interaction_strings, key=lambda x: x) - queued_interaction_names = ', '.join(queued_interaction_strings) - text = '' - text += 'Running Interactions:\n{}\n\n'.format(running_interaction_names) - text += 'Queued Interactions:\n{}\n\n'.format(queued_interaction_names) - self.log.enable() - sim_running_interactions_for_log = ',\n'.join(running_interaction_strings) - for_log_text = 'Running Interactions:\n{}\n\n'.format(sim_running_interactions_for_log) - sim_queued_interactions_for_log = ',\n'.join(queued_interaction_strings) - for_log_text += 'Queued Interactions:\n{}\n\n'.format(sim_queued_interactions_for_log) - self.log.debug(f'{target_sim_name} ({CommonSimUtils.get_sim_id(target_sim_info)}): {for_log_text}') - self.log.disable() - CommonBasicNotification( - CommonLocalizationUtils.create_localized_string('{} Running and Queued Interactions ({})'.format(target_sim_name, CommonSimUtils.get_sim_id(target_sim_info))), - CommonLocalizationUtils.create_localized_string(text) - ).show( - icon=IconInfoData(obj_instance=interaction_target) - ) - return True diff --git a/Scripts/s4ap/sims4communitylib/debug/interactions/show_running_situations.py b/Scripts/s4ap/sims4communitylib/debug/interactions/show_running_situations.py deleted file mode 100644 index efeecf1..0000000 --- a/Scripts/s4ap/sims4communitylib/debug/interactions/show_running_situations.py +++ /dev/null @@ -1,90 +0,0 @@ -""" -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 -""" -from typing import Any, List - -from distributor.shared_messages import IconInfoData -from interactions.context import InteractionContext -from sims.sim import Sim -from s4ap.sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.notifications.common_basic_notification import CommonBasicNotification -from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from s4ap.sims4communitylib.utils.resources.common_situation_utils import CommonSituationUtils -from s4ap.sims4communitylib.utils.sims.common_sim_situation_utils import CommonSimSituationUtils - - -class S4CLDebugShowRunningSituationsInteraction(CommonImmediateSuperInteraction): - """S4CLDebugShowRunningSituationsInteraction(*_, **__) - - Show the currently running Situations of a Sim. - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - return ModInfo.get_identity() - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 's4cl_debug_show_running_situations' - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, **kwargs) -> CommonTestResult: - if interaction_target is None or not CommonTypeUtils.is_sim_or_sim_info(interaction_target): - cls.get_log().debug('Failed, Target is not a Sim.') - return CommonTestResult.NONE - cls.get_log().debug('Success, can show active Buffs.') - return CommonTestResult.TRUE - - # noinspection PyMissingOrEmptyDocstring - def on_started(self, interaction_sim: Sim, interaction_target: Sim) -> bool: - target_sim_info = CommonSimUtils.get_sim_info(interaction_target) - target_sim_name = CommonSimNameUtils.get_full_name(target_sim_info) - situation_strings: List[str] = list() - for situation in CommonSimSituationUtils.get_situations(target_sim_info): - from situations.situation import Situation - situation: Situation = situation - situation_name = CommonSituationUtils.get_situation_name(situation) - situation_id = CommonSituationUtils.get_situation_id(situation) - current_job = situation.get_current_job_for_sim(interaction_target) - # noinspection PyBroadException - try: - job_name = current_job.__name__ or 'No Job' - except: - job_name = 'No Job' - current_role = situation.get_current_role_state_for_sim(interaction_target) - # noinspection PyBroadException - try: - role_name = current_role.__name__ or 'No Role' - except: - role_name = 'No Role' - situation_strings.append('S:{} ({})\n Job: {}\n Role: {}'.format(situation_name, situation_id, job_name, role_name)) - - situation_strings = sorted(situation_strings, key=lambda x: x) - sim_situations = '\n\n'.join(situation_strings) - text = '' - text += 'Running Situations:\n{}'.format(sim_situations) - self.log.enable() - sim_buffs_for_log = '\n\n'.join(situation_strings) - for_log_text = 'Running Situations:\n{}\n\n'.format(sim_buffs_for_log) - self.log.debug(f'{target_sim_name} ({CommonSimUtils.get_sim_id(target_sim_info)}): {for_log_text}') - self.log.disable() - CommonBasicNotification( - CommonLocalizationUtils.create_localized_string('{} Running Situations ({})'.format(target_sim_name, CommonSimUtils.get_sim_id(target_sim_info))), - CommonLocalizationUtils.create_localized_string(text) - ).show( - icon=IconInfoData(obj_instance=interaction_target) - ) - return True diff --git a/Scripts/s4ap/sims4communitylib/debug/interactions/show_traits.py b/Scripts/s4ap/sims4communitylib/debug/interactions/show_traits.py deleted file mode 100644 index 7d67717..0000000 --- a/Scripts/s4ap/sims4communitylib/debug/interactions/show_traits.py +++ /dev/null @@ -1,75 +0,0 @@ -""" -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 -""" -from typing import Any, List - -from distributor.shared_messages import IconInfoData -from interactions.context import InteractionContext -from sims.sim import Sim -from s4ap.sims4communitylib.classes.interactions.common_immediate_super_interaction import CommonImmediateSuperInteraction -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.notifications.common_basic_notification import CommonBasicNotification -from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from s4ap.sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils - - -class S4CLDebugShowTraitsInteraction(CommonImmediateSuperInteraction): - """S4CLDebugShowTraitsInteraction(*_, **__) - - Show the current Traits of a Sim. - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - return ModInfo.get_identity() - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 's4cl_debug_show_traits' - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def on_test(cls, interaction_sim: Sim, interaction_target: Any, interaction_context: InteractionContext, **kwargs) -> CommonTestResult: - if interaction_target is None or not CommonTypeUtils.is_sim_or_sim_info(interaction_target): - cls.get_log().debug('Failed, Target is not a Sim.') - return CommonTestResult.NONE - cls.get_log().debug('Success, can show active Buffs.') - return CommonTestResult.TRUE - - # noinspection PyMissingOrEmptyDocstring - def on_started(self, interaction_sim: Sim, interaction_target: Sim) -> bool: - target_sim_info = CommonSimUtils.get_sim_info(interaction_target) - target_sim_name = CommonSimNameUtils.get_full_name(target_sim_info) - trait_strings: List[str] = list() - for trait in CommonTraitUtils.get_traits(target_sim_info): - trait_name = CommonTraitUtils.get_trait_name(trait) - trait_id = CommonTraitUtils.get_trait_id(trait) - trait_strings.append('{} ({})'.format(trait_name, trait_id)) - - trait_strings = sorted(trait_strings, key=lambda x: x) - sim_traits = ', '.join(trait_strings) - text = '' - text += 'Traits:\n{}\n\n'.format(sim_traits) - self.log.enable() - sim_traits_for_log = ',\n'.join(trait_strings) - for_log_text = 'Traits:\n{}\n\n'.format(sim_traits_for_log) - self.log.debug(f'{target_sim_name} ({CommonSimUtils.get_sim_id(target_sim_info)}): {for_log_text}') - self.log.disable() - CommonBasicNotification( - CommonLocalizationUtils.create_localized_string('{} Traits ({})'.format(target_sim_name, CommonSimUtils.get_sim_id(target_sim_info))), - CommonLocalizationUtils.create_localized_string(text) - ).show( - icon=IconInfoData(obj_instance=interaction_target) - ) - return True diff --git a/Scripts/s4ap/sims4communitylib/debug/traits/__init__.py b/Scripts/s4ap/sims4communitylib/debug/traits/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/debug/traits/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/debug/traits/_auto_apply_traits.py b/Scripts/s4ap/sims4communitylib/debug/traits/_auto_apply_traits.py deleted file mode 100644 index 29756a8..0000000 --- a/Scripts/s4ap/sims4communitylib/debug/traits/_auto_apply_traits.py +++ /dev/null @@ -1,442 +0,0 @@ -""" -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 -""" -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.enums.traits_enum import CommonTraitId -from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from s4ap.sims4communitylib.events.sim.events.sim_spawned import S4CLSimSpawnedEvent -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils -from s4ap.sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils -from s4ap.sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils - - -class _S4CLAutoApplyTraits: - """ Auto apply the S4CL main traits. """ - - def _try_apply_traits(self, sim_info: SimInfo): - # Main Trait - if not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_MAIN_TRAIT): - CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_MAIN_TRAIT) - - if CommonSpeciesUtils.is_human(sim_info): - # Main Trait - CommonTraitUtils.remove_trait( - sim_info, - CommonTraitId.S4CL_MAIN_TRAIT_LARGE_DOG, - CommonTraitId.S4CL_MAIN_TRAIT_SMALL_DOG, - CommonTraitId.S4CL_MAIN_TRAIT_CAT, - CommonTraitId.S4CL_MAIN_TRAIT_FOX, - CommonTraitId.S4CL_MAIN_TRAIT_HORSE, - ) - if not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_MAIN_TRAIT_HUMAN): - CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_MAIN_TRAIT_HUMAN) - elif CommonSpeciesUtils.is_large_dog(sim_info): - # Main Trait - CommonTraitUtils.remove_trait( - sim_info, - CommonTraitId.S4CL_MAIN_TRAIT_HUMAN, - CommonTraitId.S4CL_MAIN_TRAIT_SMALL_DOG, - CommonTraitId.S4CL_MAIN_TRAIT_CAT, - CommonTraitId.S4CL_MAIN_TRAIT_FOX, - CommonTraitId.S4CL_MAIN_TRAIT_HORSE, - ) - if not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_MAIN_TRAIT_LARGE_DOG): - CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_MAIN_TRAIT_LARGE_DOG) - # Toilet Standing/Sitting/Unknown - if not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_LARGE_DOG)\ - and not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_LARGE_DOG)\ - and not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_UNKNOWN): - CommonTraitUtils.remove_trait( - sim_info, - CommonTraitId.GENDER_OPTIONS_TOILET_STANDING, - CommonTraitId.GENDER_OPTIONS_TOILET_SITTING, - CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_SMALL_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_SMALL_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_CAT, - CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_CAT, - CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_FOX, - CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_FOX, - CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_HORSE, - CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_HORSE, - ) - if CommonGenderUtils.is_male(sim_info): - CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_LARGE_DOG) - else: - CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_LARGE_DOG) - - # Can Impregnate - CommonTraitUtils.remove_trait( - sim_info, - CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE, - CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_SMALL_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_SMALL_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_CAT, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_CAT, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_FOX, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_FOX, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_HORSE, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_HORSE, - ) - if not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_LARGE_DOG)\ - and not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_LARGE_DOG): - if CommonGenderUtils.is_male(sim_info): - if CommonTraitUtils.has_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_REPRODUCE): - CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_LARGE_DOG) - else: - CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_LARGE_DOG) - else: - CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_LARGE_DOG) - # Can Be Impregnated - CommonTraitUtils.remove_trait( - sim_info, - CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED, - CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_SMALL_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_SMALL_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_CAT, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_CAT, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_FOX, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_FOX, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_HORSE, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_HORSE, - ) - if not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_LARGE_DOG)\ - and not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_LARGE_DOG): - if CommonGenderUtils.is_male(sim_info): - CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_LARGE_DOG) - else: - if CommonTraitUtils.has_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_REPRODUCE): - CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_LARGE_DOG) - else: - CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_LARGE_DOG) - elif CommonSpeciesUtils.is_small_dog(sim_info): - # Main Trait - CommonTraitUtils.remove_trait( - sim_info, - CommonTraitId.S4CL_MAIN_TRAIT_HUMAN, - CommonTraitId.S4CL_MAIN_TRAIT_LARGE_DOG, - CommonTraitId.S4CL_MAIN_TRAIT_CAT, - CommonTraitId.S4CL_MAIN_TRAIT_FOX, - CommonTraitId.S4CL_MAIN_TRAIT_HORSE, - ) - if not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_MAIN_TRAIT_SMALL_DOG): - CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_MAIN_TRAIT_SMALL_DOG) - # Toilet Standing/Sitting/Unknown - CommonTraitUtils.remove_trait( - sim_info, - CommonTraitId.GENDER_OPTIONS_TOILET_STANDING, - CommonTraitId.GENDER_OPTIONS_TOILET_SITTING, - CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_LARGE_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_LARGE_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_CAT, - CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_CAT, - CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_FOX, - CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_FOX, - CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_HORSE, - CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_HORSE, - ) - if not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_SMALL_DOG)\ - and not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_SMALL_DOG)\ - and not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_UNKNOWN): - if CommonGenderUtils.is_male(sim_info): - CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_SMALL_DOG) - else: - CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_SMALL_DOG) - # Can Impregnate - CommonTraitUtils.remove_trait( - sim_info, - CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE, - CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_LARGE_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_LARGE_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_CAT, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_CAT, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_FOX, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_FOX, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_HORSE, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_HORSE, - ) - if not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_SMALL_DOG)\ - and not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_SMALL_DOG): - if CommonGenderUtils.is_male(sim_info): - if CommonTraitUtils.has_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_REPRODUCE): - CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_SMALL_DOG) - else: - CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_SMALL_DOG) - else: - CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_SMALL_DOG) - # Can Be Impregnated - CommonTraitUtils.remove_trait( - sim_info, - CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED, - CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_LARGE_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_LARGE_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_CAT, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_CAT, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_FOX, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_FOX, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_HORSE, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_HORSE, - ) - if not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_SMALL_DOG)\ - and not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_SMALL_DOG): - if CommonGenderUtils.is_male(sim_info): - CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_SMALL_DOG) - else: - if CommonTraitUtils.has_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_REPRODUCE): - CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_SMALL_DOG) - else: - CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_SMALL_DOG) - elif CommonSpeciesUtils.is_cat(sim_info): - # Main Trait - CommonTraitUtils.remove_trait( - sim_info, - CommonTraitId.S4CL_MAIN_TRAIT_HUMAN, - CommonTraitId.S4CL_MAIN_TRAIT_LARGE_DOG, - CommonTraitId.S4CL_MAIN_TRAIT_SMALL_DOG, - CommonTraitId.S4CL_MAIN_TRAIT_FOX, - CommonTraitId.S4CL_MAIN_TRAIT_HORSE, - ) - if not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_MAIN_TRAIT_CAT): - CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_MAIN_TRAIT_CAT) - # Toilet Standing/Sitting/Unknown - CommonTraitUtils.remove_trait( - sim_info, - CommonTraitId.GENDER_OPTIONS_TOILET_STANDING, - CommonTraitId.GENDER_OPTIONS_TOILET_SITTING, - CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_LARGE_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_LARGE_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_SMALL_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_SMALL_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_FOX, - CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_FOX, - CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_HORSE, - CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_HORSE, - ) - if not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_CAT)\ - and not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_CAT)\ - and not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_UNKNOWN): - if CommonGenderUtils.is_male(sim_info): - CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_CAT) - else: - CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_CAT) - # Can Impregnate - CommonTraitUtils.remove_trait( - sim_info, - CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE, - CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_LARGE_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_LARGE_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_SMALL_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_SMALL_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_FOX, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_FOX, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_HORSE, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_HORSE, - ) - if not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_CAT)\ - and not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_CAT): - if CommonGenderUtils.is_male(sim_info): - if CommonTraitUtils.has_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_REPRODUCE): - CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_CAT) - else: - CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_CAT) - else: - CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_CAT) - # Can Be Impregnated - CommonTraitUtils.remove_trait( - sim_info, - CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED, - CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_LARGE_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_LARGE_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_SMALL_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_SMALL_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_FOX, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_FOX, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_HORSE, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_HORSE, - ) - if not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_CAT)\ - and not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_CAT): - if CommonGenderUtils.is_male(sim_info): - CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_CAT) - else: - if CommonTraitUtils.has_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_REPRODUCE): - CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_CAT) - else: - CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_CAT) - elif CommonSpeciesUtils.is_fox(sim_info): - # Main Trait - CommonTraitUtils.remove_trait( - sim_info, - CommonTraitId.S4CL_MAIN_TRAIT_HUMAN, - CommonTraitId.S4CL_MAIN_TRAIT_LARGE_DOG, - CommonTraitId.S4CL_MAIN_TRAIT_SMALL_DOG, - CommonTraitId.S4CL_MAIN_TRAIT_CAT, - CommonTraitId.S4CL_MAIN_TRAIT_HORSE, - ) - if not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_MAIN_TRAIT_FOX): - CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_MAIN_TRAIT_FOX) - # Toilet Standing/Sitting/Unknown - CommonTraitUtils.remove_trait( - sim_info, - CommonTraitId.GENDER_OPTIONS_TOILET_STANDING, - CommonTraitId.GENDER_OPTIONS_TOILET_SITTING, - CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_LARGE_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_LARGE_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_SMALL_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_SMALL_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_CAT, - CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_CAT, - CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_HORSE, - CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_HORSE, - ) - if not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_FOX)\ - and not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_FOX)\ - and not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_UNKNOWN): - if CommonGenderUtils.is_male(sim_info): - CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_FOX) - else: - CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_FOX) - # Can Impregnate - CommonTraitUtils.remove_trait( - sim_info, - CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE, - CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_LARGE_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_LARGE_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_SMALL_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_SMALL_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_CAT, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_CAT, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_HORSE, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_HORSE, - ) - if not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_FOX)\ - and not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_FOX): - if CommonGenderUtils.is_male(sim_info): - if CommonTraitUtils.has_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_REPRODUCE): - CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_FOX) - else: - CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_FOX) - else: - CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_FOX) - # Can Be Impregnated - CommonTraitUtils.remove_trait( - sim_info, - CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED, - CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_LARGE_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_LARGE_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_SMALL_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_SMALL_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_CAT, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_CAT, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_HORSE, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_HORSE, - ) - if not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_FOX)\ - and not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_FOX): - if CommonGenderUtils.is_male(sim_info): - CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_FOX) - else: - if CommonTraitUtils.has_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_REPRODUCE): - CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_FOX) - else: - CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_FOX) - elif CommonSpeciesUtils.is_horse(sim_info): - # Main Trait - CommonTraitUtils.remove_trait( - sim_info, - CommonTraitId.S4CL_MAIN_TRAIT_HUMAN, - CommonTraitId.S4CL_MAIN_TRAIT_LARGE_DOG, - CommonTraitId.S4CL_MAIN_TRAIT_SMALL_DOG, - CommonTraitId.S4CL_MAIN_TRAIT_CAT, - CommonTraitId.S4CL_MAIN_TRAIT_FOX, - ) - if not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_MAIN_TRAIT_HORSE): - CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_MAIN_TRAIT_HORSE) - # Toilet Standing/Sitting/Unknown - CommonTraitUtils.remove_trait( - sim_info, - CommonTraitId.GENDER_OPTIONS_TOILET_STANDING, - CommonTraitId.GENDER_OPTIONS_TOILET_SITTING, - CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_LARGE_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_LARGE_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_SMALL_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_SMALL_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_CAT, - CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_CAT, - CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_FOX, - CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_FOX, - ) - if not CommonTraitUtils.has_trait(sim_info, - CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_HORSE) \ - and not CommonTraitUtils.has_trait(sim_info, - CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_HORSE) \ - and not CommonTraitUtils.has_trait(sim_info, - CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_UNKNOWN): - if CommonGenderUtils.is_male(sim_info): - CommonTraitUtils.add_trait(sim_info, - CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_HORSE) - else: - CommonTraitUtils.add_trait(sim_info, - CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_HORSE) - # Can Impregnate - CommonTraitUtils.remove_trait( - sim_info, - CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE, - CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_LARGE_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_LARGE_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_SMALL_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_SMALL_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_CAT, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_CAT, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_FOX, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_FOX, - ) - if not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_HORSE) \ - and not CommonTraitUtils.has_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_HORSE): - if CommonGenderUtils.is_male(sim_info): - CommonTraitUtils.add_trait(sim_info, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_HORSE) - else: - CommonTraitUtils.add_trait(sim_info, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_HORSE) - # Can Be Impregnated - CommonTraitUtils.remove_trait( - sim_info, - CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED, - CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_LARGE_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_LARGE_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_SMALL_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_SMALL_DOG, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_CAT, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_CAT, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_FOX, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_FOX, - ) - if not CommonTraitUtils.has_trait(sim_info, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_HORSE) \ - and not CommonTraitUtils.has_trait(sim_info, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_HORSE): - if CommonGenderUtils.is_male(sim_info): - CommonTraitUtils.add_trait(sim_info, - CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_HORSE) - else: - CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_HORSE) - - -@CommonEventRegistry.handle_events(ModInfo.get_identity()) -def _common_auto_apply_traits_on_sim_spawned(event_data: S4CLSimSpawnedEvent): - _S4CLAutoApplyTraits()._try_apply_traits(event_data.sim_info) diff --git a/Scripts/s4ap/sims4communitylib/dialogs/__init__.py b/Scripts/s4ap/sims4communitylib/dialogs/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/dialogs/_common_ui_dialog_multi_text_input_ok_cancel.py b/Scripts/s4ap/sims4communitylib/dialogs/_common_ui_dialog_multi_text_input_ok_cancel.py deleted file mode 100644 index b97f652..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/_common_ui_dialog_multi_text_input_ok_cancel.py +++ /dev/null @@ -1,66 +0,0 @@ -""" -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 -""" -from typing import Tuple, Any, Callable, Iterator -from protocolbuffers.Localization_pb2 import LocalizedString -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.dialogs.common_input_text_field import CommonInputTextField -from s4ap.sims4communitylib.enums.common_character_restrictions import CommonCharacterRestriction -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from ui.ui_dialog_generic import UiDialogTextInputOkCancel - - -class _CommonUiDialogMultiTextInputOkCancel(UiDialogTextInputOkCancel): - def __init__( - self, - sim_info: SimInfo, - input_fields: Iterator[CommonInputTextField], - *args, - title: Callable[..., LocalizedString] = None, - text: Callable[..., LocalizedString] = None, - **kwargs - ): - super().__init__( - sim_info, - *args, - title=title, - text=text, - **kwargs - ) - self.input_fields = input_fields - self.text_input_responses = {} - - def on_text_input(self, text_input_name: str = '', text_input: str = '') -> bool: - """A callback that occurs upon text being entered. - - """ - self.text_input_responses[text_input_name] = text_input - return False - - def build_msg(self, text_input_overrides=None, additional_tokens: Tuple[Any] = (), **kwargs): - """Build the message. - - """ - msg = super().build_msg(additional_tokens=(), **kwargs) - for input_field in self.input_fields: - if input_field.initial_value is not None: - self.text_input_responses[input_field.identifier] = str(input_field.initial_value) - text_input_msg = msg.text_input.add() - text_input_msg.text_input_name = input_field.identifier - if input_field.default_text is not None: - text_input_msg.default_text = CommonLocalizationUtils.create_localized_string(input_field.default_text) - if input_field.initial_value is not None: - text_input_msg.initial_value = CommonLocalizationUtils.create_localized_string(str(input_field.initial_value)) - if input_field.title is not None: - text_input_msg.title = CommonLocalizationUtils.create_localized_string(input_field.title) - if input_field.character_restriction is not None and input_field.character_restriction != CommonCharacterRestriction.NONE: - character_restriction_mapping = { - CommonCharacterRestriction.NUMBERS_ONLY: CommonStringId.ZERO_THROUGH_NINE, - } - text_input_msg.restricted_characters = CommonLocalizationUtils.create_localized_string(character_restriction_mapping.get(input_field.character_restriction)) - return msg diff --git a/Scripts/s4ap/sims4communitylib/dialogs/_common_ui_dialog_text_input_ok_cancel.py b/Scripts/s4ap/sims4communitylib/dialogs/_common_ui_dialog_text_input_ok_cancel.py deleted file mode 100644 index b5efa1b..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/_common_ui_dialog_text_input_ok_cancel.py +++ /dev/null @@ -1,50 +0,0 @@ -""" -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 -""" -from typing import Tuple, Any, Callable -from protocolbuffers.Localization_pb2 import LocalizedString -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from ui.ui_dialog_generic import UiDialogTextInputOkCancel - - -class _CommonUiDialogTextInputOkCancel(UiDialogTextInputOkCancel): - def __init__( - self, - sim_info: SimInfo, - *args, - title: Callable[..., LocalizedString]=None, - text: Callable[..., LocalizedString]=None, - **kwargs - ): - super().__init__( - sim_info, - *args, - title=title, - text=text, - **kwargs - ) - self.text_input_responses = {} - - def on_text_input(self, text_input_name: str='', text_input: str='') -> bool: - """A callback that occurs upon text being entered. - - """ - self.text_input_responses[text_input_name] = text_input - return False - - def build_msg(self, text_input_overrides=None, additional_tokens: Tuple[Any]=(), **kwargs): - """Build the message. - - """ - from s4ap.sims4communitylib.dialogs.utils.common_dialog_utils import CommonDialogUtils - msg = super().build_msg(additional_tokens=(), **kwargs) - text_input_msg = msg.text_input.add() - text_input_msg.text_input_name = CommonDialogUtils.TEXT_INPUT_NAME - if additional_tokens and additional_tokens[0] is not None: - text_input_msg.initial_value = CommonLocalizationUtils.create_localized_string(str(additional_tokens[0])) - return msg diff --git a/Scripts/s4ap/sims4communitylib/dialogs/choose_item_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/choose_item_dialog.py deleted file mode 100644 index 6ef9d91..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/choose_item_dialog.py +++ /dev/null @@ -1,199 +0,0 @@ -""" -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 -""" -from typing import Tuple, Any, Callable, Union - -from pprint import pformat -from protocolbuffers.Localization_pb2 import LocalizedString -from s4ap.sims4communitylib.dialogs.utils.common_dialog_utils import CommonDialogUtils -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from ui.ui_dialog_picker import UiObjectPicker, ObjectPickerRow - - -class CommonChooseItemResult(CommonInt): - """Different outcomes upon the player choosing or not choosing items in the dialog. - - """ - DIALOG_CANCELLED: 'CommonChooseItemResult' = 0 - ITEM_CHOSEN: 'CommonChooseItemResult' = 1 - ITEM_CHOSEN_WITH_ERROR: 'CommonChooseItemResult' = 2 - - @staticmethod - def is_error(result: 'CommonChooseItemResult') -> bool: - """is_error(result) - - Determine if a result is an error or cancel. - - :param result: The result to check - :type result: CommonChooseItemResult - :return: True, if the result is an error or cancelled. False, if not. - :rtype: bool - """ - return result == CommonChooseItemResult.DIALOG_CANCELLED or result == CommonChooseItemResult.ITEM_CHOSEN_WITH_ERROR - - -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 s4ap.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, str, LocalizedString, CommonStringId] - :param description_identifier: A decimal identifier of the description text. - :type description_identifier: Union[int, str, LocalizedString, CommonStringId] - :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, str, LocalizedString, CommonStringId], - description_identifier: Union[int, str, LocalizedString, CommonStringId], - 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 - - 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,) - - 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.DIALOG_CANCELLED) - chosen_item = CommonDialogUtils.get_chosen_item(dialog) - return on_item_chosen(chosen_item, CommonChooseItemResult.ITEM_CHOSEN) - - for list_item in self.list_items: - _dialog.add_row(list_item) - - _dialog.add_listener(_on_item_chosen) - _dialog.show_dialog() - - 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) - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_testing.show_choose_item_dialog', - 'Show an example of CommonChooseItemDialog.', - show_with_help_command=False -) -def _common_testing_show_choose_item_dialog(output: CommonConsoleCommandOutput): - output('Showing test choose item dialog.') - - def _item_chosen(chosen_item: str, result: CommonChooseItemResult): - output('Item chosen {} with result: {}.'.format(pformat(chosen_item), pformat(result))) - - # 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 s4ap.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) - output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/choose_object_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/choose_object_dialog.py deleted file mode 100644 index 6c14b2b..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/choose_object_dialog.py +++ /dev/null @@ -1,519 +0,0 @@ -""" -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 -""" -import math - -from typing import Tuple, Any, Callable, Union, Iterator - -from pprint import pformat - -from distributor.shared_messages import IconInfoData -from protocolbuffers.Localization_pb2 import LocalizedString -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome -from s4ap.sims4communitylib.dialogs.common_choose_dialog import CommonChooseDialog -from s4ap.sims4communitylib.dialogs.common_dialog_navigation_button_tag import CommonDialogNavigationButtonTag -from s4ap.sims4communitylib.dialogs.custom_dialogs.picker_dialogs.common_ui_object_category_picker import \ - CommonUiObjectCategoryPicker - -from s4ap.sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_option_category import \ - CommonDialogObjectOptionCategory -from s4ap.sims4communitylib.dialogs.utils.common_dialog_utils import CommonDialogUtils -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils -from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from ui.ui_dialog_picker import UiObjectPicker, ObjectPickerRow - - -class CommonChooseObjectDialog(CommonChooseDialog): - """CommonChooseObjectDialog(\ - title_identifier,\ - description_identifier,\ - choices,\ - title_tokens=(),\ - description_tokens=(),\ - per_page=25,\ - mod_identity=None,\ - required_tooltip=None,\ - required_tooltip_tokens=()\ - ) - - Create a dialog that prompts the player to choose an object. - - .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_choose_object_dialog` in the in-game console. - - .. highlight:: python - .. code-block:: python - - def _common_testing_show_choose_object_dialog(): - - def _on_chosen(choice: str, outcome: CommonChoiceOutcome): - 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 s4ap.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) - - :param title_identifier: The title to display in the dialog. - :type title_identifier: Union[int, str, LocalizedString, CommonStringId] - :param description_identifier: The description to display in the dialog. - :type description_identifier: Union[int, str, LocalizedString, CommonStringId] - :param choices: The choices that can be chosen. - :type choices: Iterator[ObjectPickerRow] - :param title_tokens: Tokens to format into the title. - :type title_tokens: Iterator[Any], optional - :param description_tokens: Tokens to format into the description. - :type description_tokens: Iterator[Any], optional - :param per_page: The number of rows to display per page. If the number of rows (including rows added after creation) exceeds this value, pagination will be added. - :type per_page: int - :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. - :type mod_identity: CommonModIdentity, optional - :param required_tooltip: If provided, this text will display when the dialog requires at least one choice and a choice has not been made. Default is None. - :type required_tooltip: Union[int, str, LocalizedString, CommonStringId], optional - :param required_tooltip_tokens: Tokens to format into the required tooltip. Default is an empty collection. - :type required_tooltip_tokens: Iterator[Any], optional - """ - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - return 's4cl_choose_object_dialog' - - def __init__( - self, - title_identifier: Union[int, str, LocalizedString, CommonStringId], - description_identifier: Union[int, str, LocalizedString, CommonStringId], - choices: Iterator[ObjectPickerRow], - title_tokens: Iterator[Any]=(), - description_tokens: Iterator[Any]=(), - per_page: int=25, - mod_identity: CommonModIdentity=None, - required_tooltip: Union[int, str, LocalizedString, CommonStringId]=None, - required_tooltip_tokens: Iterator[Any]=() - ): - super().__init__( - title_identifier, - description_identifier, - choices, - title_tokens=title_tokens, - description_tokens=description_tokens, - mod_identity=mod_identity, - required_tooltip=required_tooltip, - required_tooltip_tokens=required_tooltip_tokens - ) - if per_page <= 0: - raise AssertionError('\'per_page\' must be greater than zero.') - self._per_page = per_page - self._always_visible_rows = tuple() - self._current_page = 1 - - @property - def current_page(self) -> int: - """Retrieve the current page. - - :return: A number indicating the current page. - :rtype: int - """ - return self._current_page - - # noinspection PyMissingOrEmptyDocstring - @property - def rows(self) -> Tuple[ObjectPickerRow]: - result: Tuple[ObjectPickerRow] = super().rows - return result - - @property - def always_visible_rows(self) -> Tuple[ObjectPickerRow]: - """A collection of rows that will always appear in the dialog no matter which page. - - .. note:: These rows are added to the dialog before the normal rows are added to the dialog. - - :return: A collection of rows added to the dialog that will always appear. - :rtype: Tuple[ObjectPickerRow] - """ - return self._always_visible_rows - - # noinspection PyMissingOrEmptyDocstring - def add_row(self, choice: ObjectPickerRow, *_, always_visible: bool=False, **__): - """add_row(row, *_, always_on_visible=False, **__) - - Add a row to the dialog. - - :param choice: The row to add. - :type choice: ObjectPickerRow - :param always_visible: If set to True, the row will always appear in the dialog no matter which page. If False, the row will act as normal. Default is False. - :type always_visible: bool, optional - """ - if not always_visible: - super().add_row(choice, *_, **__) - return - try: - self._always_visible_rows += (choice,) - except Exception as ex: - self.log.error('An error occurred while running \'{}\''.format(CommonChooseObjectDialog.add_row.__name__), exception=ex) - - def show( - self, - on_chosen: Callable[[Any, CommonChoiceOutcome], Any]=CommonFunctionUtils.noop, - picker_type: UiObjectPicker.UiObjectPickerObjectPickerType=UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT, - page: int=1, - sim_info: SimInfo=None, - categories: Iterator[CommonDialogObjectOptionCategory]=(), - include_pagination: bool=True, - sort_rows: bool=False - ): - """show(\ - on_chosen=CommonFunctionUtils.noop,\ - picker_type=UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT,\ - page=1,\ - sim_info=None,\ - categories=(),\ - include_pagination=True,\ - sort_rows=True\ - ) - - Show the dialog and invoke the callbacks upon the player making a choice. - - :param on_chosen: A callback invoked upon the player choosing something from the list. Default is CommonFunctionUtils.noop. - :type on_chosen: Callable[[Any, CommonChoiceOutcome], optional - :param picker_type: The layout of the dialog. Default is UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT. - :type picker_type: UiObjectPicker.UiObjectPickerObjectPickerType, optional - :param page: The page to display. Ignored if there is only one page of choices. Default is 1. - :type page: int, optional - :param sim_info: The Sim that will appear in the dialog image. The default Sim is the Active Sim. Default is None. - :type sim_info: SimInfo, optional - :param categories: A collection of categories to display in the dialog. They will appear in a drop down above the rows. Default is an empty collection. - :type categories: Iterator[CommonDialogObjectOptionCategory], optional - :param include_pagination: If True, pagination will be applied. If False, no pagination will be applied. Default is True. - :type include_pagination: bool, optional - :param sort_rows: If True, rows will be sorted by display name, with the selected rows on top. If False, rows will not be sorted. Default is False. - :type sort_rows: bool, optional - """ - self._current_page = page - try: - return self._show( - on_chosen=on_chosen, - picker_type=picker_type, - page=page, - sim_info=sim_info, - categories=categories, - include_pagination=include_pagination, - sort_rows=sort_rows - ) - except Exception as ex: - self.log.error('An error occurred while running \'{}\''.format(CommonChooseObjectDialog.show.__name__), exception=ex) - - def _show( - self, - on_chosen: Callable[[Any, CommonChoiceOutcome], bool]=CommonFunctionUtils.noop, - picker_type: UiObjectPicker.UiObjectPickerObjectPickerType=UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT, - page: int=1, - sim_info: SimInfo=None, - categories: Iterator[CommonDialogObjectOptionCategory]=(), - include_pagination: bool=True, - sort_rows: bool=False - ): - def _on_chosen(choice: Any, outcome: CommonChoiceOutcome) -> bool: - try: - self.log.debug('Choice made.') - if choice == CommonDialogNavigationButtonTag.NEXT: - self.log.debug('Next chosen.') - self.show(on_chosen=on_chosen, picker_type=picker_type, page=page + 1, sim_info=sim_info, categories=categories, sort_rows=sort_rows) - return True - elif choice == CommonDialogNavigationButtonTag.PREVIOUS: - self.log.debug('Previous chosen.') - self.show(on_chosen=on_chosen, picker_type=picker_type, page=page - 1, sim_info=sim_info, categories=categories, sort_rows=sort_rows) - return True - self.log.format_with_message('Choose Object Choice made.', choice=choice) - result = on_chosen(choice, outcome) - self.log.format_with_message('Finished handling choose object _show.', result=result) - return result - except Exception as ex: - self.log.error('Error occurred on choosing a value.', exception=ex) - return False - - _dialog = self.build_dialog( - on_chosen=_on_chosen, - picker_type=picker_type, - page=page, - sim_info=sim_info, - categories=categories, - include_pagination=include_pagination, - sort_rows=sort_rows - ) - self.log.debug('Showing dialog.') - _dialog.show_dialog() - - # noinspection PyMissingOrEmptyDocstring - def build_dialog( - self, - on_chosen: Callable[[Any, CommonChoiceOutcome], bool]=CommonFunctionUtils.noop, - picker_type: UiObjectPicker.UiObjectPickerObjectPickerType=UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT, - page: int=1, - sim_info: SimInfo=None, - categories: Iterator[CommonDialogObjectOptionCategory]=(), - include_pagination: bool=True, - sort_rows: bool=False - ) -> Union[UiObjectPicker, None]: - self.log.format_with_message('Attempting to build dialog.', page=page, categories=categories) - - _dialog = self._create_dialog( - picker_type=picker_type, - categories=categories, - sim_info=sim_info, - sort_rows=sort_rows - ) - if _dialog is None: - self.log.error('_dialog was None for some reason.') - return - - if on_chosen is None: - raise ValueError('on_chosen was None.') - - if len(self.always_visible_rows) == 0 and len(self.rows) == 0: - raise AssertionError('No rows have been provided. Add rows to the dialog before attempting to display it.') - - def _on_chosen(dialog: UiObjectPicker) -> bool: - try: - self.log.debug('Choice made.') - if not dialog.accepted: - self.log.debug('Dialog cancelled.') - return on_chosen(None, CommonChoiceOutcome.CANCEL) - self.log.debug('Choice not made.') - choice = CommonDialogUtils.get_chosen_item(dialog) - self.log.format_with_message('Choose Object Choice made.', choice=pformat(choice)) - result = on_chosen(choice, CommonChoiceOutcome.CHOICE_MADE) - self.log.format_with_message('Finished handling choose object _on_chosen.', result=result) - return result - except Exception as ex: - self.log.error('Error occurred on choosing a value.', exception=ex) - return False - - if include_pagination: - self._setup_dialog_rows( - _dialog, - page=page, - categories=categories - ) - else: - self.log.debug('Adding always visible rows.') - for always_visible_rows in self.always_visible_rows: - _dialog.add_row(always_visible_rows) - self.log.debug('Adding rows.') - for row in self.rows: - _dialog.add_row(row) - - self.log.debug('Adding listener.') - _dialog.add_listener(_on_chosen) - return _dialog - - def _setup_dialog_rows( - self, - _dialog: UiObjectPicker, - page: int=1, - categories: Iterator[CommonDialogObjectOptionCategory]=() - ): - if page < 0: - raise AssertionError('page cannot be less than zero.') - - number_of_rows = len(self.rows) - self.log.format(number_of_rows=number_of_rows, per_page=self._per_page) - if number_of_rows > self._per_page: - number_of_pages = math.ceil(number_of_rows / self._per_page) - - if page > number_of_pages: - raise AssertionError('page was out of range. Number of Pages: {}, Requested Page: {}'.format(str(number_of_pages), str(page))) - # Add the rows that are always visible. - for always_visible_row in self.always_visible_rows: - _dialog.add_row(always_visible_row) - - # Add the rows that should show on the current page. - start_index = (page - 1) * self._per_page - end_index = page * self._per_page - self.log.format(start_index=start_index, end_index=end_index) - current_choices = self.rows[start_index:end_index] - self.log.format(current_rows=current_choices) - for row in current_choices: - _dialog.add_row(row) - - tag_list = [(abs(hash(category.object_category)) % (10 ** 8)) for category in categories] - self.log.format_with_message('Found tags.', tag_list=tag_list) - - if page > 1: - self.log.format_with_message('Adding Previous row.', page=page, number_of_pages=number_of_pages) - previous_choice = ObjectPickerRow( - option_id=len(self.rows) + 2, - name=CommonLocalizationUtils.create_localized_string(CommonStringId.S4CL_EXCLAMATION_EXCLAMATION_STRING, tokens=(CommonStringId.PREVIOUS,)), - row_description=None, - row_tooltip=CommonLocalizationUtils.create_localized_tooltip(CommonStringId.PREVIOUS), - icon=CommonIconUtils.load_arrow_left_icon(), - tag_list=tag_list, - tag=CommonDialogNavigationButtonTag.PREVIOUS - ) - _dialog.add_row(previous_choice) - else: - self.log.format_with_message('Not adding Previous row.', page=page) - if page < number_of_pages: - self.log.format_with_message('Adding Next row.', page=page, number_of_pages=number_of_pages) - next_choice = ObjectPickerRow( - option_id=len(self.rows) + 1, - name=CommonLocalizationUtils.create_localized_string(CommonStringId.S4CL_EXCLAMATION_EXCLAMATION_STRING, tokens=(CommonStringId.NEXT,)), - row_description=None, - row_tooltip=CommonLocalizationUtils.create_localized_tooltip(CommonStringId.NEXT), - icon=CommonIconUtils.load_arrow_right_icon(), - tag_list=tag_list, - tag=CommonDialogNavigationButtonTag.NEXT - ) - _dialog.add_row(next_choice) - else: - self.log.format_with_message('Not adding Next.', page=page, number_of_pages=number_of_pages) - else: - self.log.debug('Adding always visible rows.') - for always_visible_row in self.always_visible_rows: - _dialog.add_row(always_visible_row) - self.log.debug('Adding rows.') - for row in self.rows: - _dialog.add_row(row) - - def _create_dialog( - self, - picker_type: UiObjectPicker.UiObjectPickerObjectPickerType=UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT, - sim_info: SimInfo=None, - categories: Iterator[CommonDialogObjectOptionCategory]=(), - min_selectable: int=1, - max_selectable: int=1, - sort_rows: bool=False - ) -> Union[UiObjectPicker, None]: - try: - from collections import namedtuple - object_category_type = namedtuple('object_category_type', ('object_category', 'icon', 'category_name')) - object_categories = list() - for category in tuple(categories): - object_categories.append(object_category_type(category.object_category, lambda *_, **__: IconInfoData(icon_resource=CommonIconUtils._load_icon(category.icon)), CommonLocalizationUtils.create_localized_string(category.category_name))) - - if len(object_categories) > 0: - self.log.debug('Building dialog with categories.') - return CommonUiObjectCategoryPicker.TunableFactory().default( - sim_info or CommonSimUtils.get_active_sim_info(), - text=lambda *_, **__: self.description, - title=lambda *_, **__: self.title, - picker_type=picker_type, - use_dropdown_filter=True, - is_sortable=sort_rows, - object_categories=tuple(object_categories), - min_selectable=min_selectable, - max_selectable=max_selectable - ) - else: - self.log.debug('Building dialog without categories.') - return UiObjectPicker.TunableFactory().default( - sim_info or CommonSimUtils.get_active_sim_info(), - text=lambda *_, **__: self.description, - title=lambda *_, **__: self.title, - picker_type=picker_type, - is_sortable=sort_rows, - min_selectable=min_selectable, - max_selectable=max_selectable - ) - except Exception as ex: - self.log.error('_create_dialog', exception=ex) - return None - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_testing.show_choose_object_dialog', - 'Show an example of CommonChooseObjectDialog.' -) -def _common_testing_show_choose_object_dialog(output: CommonConsoleCommandOutput): - output('Showing test choose object dialog.') - - def _on_chosen(choice: str, outcome: CommonChoiceOutcome): - output('Chose {} with result: {}.'.format(pformat(choice), pformat(outcome))) - - # 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 s4ap.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) - output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/choose_objects_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/choose_objects_dialog.py deleted file mode 100644 index 3c1cd4d..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/choose_objects_dialog.py +++ /dev/null @@ -1,434 +0,0 @@ -""" -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 -""" -from typing import Tuple, Any, Callable, Union, Iterator - -from pprint import pformat -from protocolbuffers.Localization_pb2 import LocalizedString -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.dialogs.choose_object_dialog import CommonChooseObjectDialog -from s4ap.sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome -from s4ap.sims4communitylib.dialogs.common_dialog_navigation_button_tag import CommonDialogNavigationButtonTag -from s4ap.sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_option_category import \ - CommonDialogObjectOptionCategory -from s4ap.sims4communitylib.dialogs.utils.common_dialog_utils import CommonDialogUtils -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from ui.ui_dialog_picker import UiObjectPicker, ObjectPickerRow - - -class CommonChooseObjectsDialog(CommonChooseObjectDialog): - """CommonChooseObjectsDialog(\ - title_identifier,\ - description_identifier,\ - choices,\ - title_tokens=(),\ - description_tokens=(),\ - per_page=25,\ - mod_identity=None,\ - required_tooltip=None,\ - required_tooltip_tokens=()\ - ) - - Create a dialog that prompts the player to choose multiple objects. - - .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_choose_objects_dialog` in the in-game console. - - .. highlight:: python - .. code-block:: python - - def _common_testing_show_choose_objects_dialog(): - - def _on_chosen(choices: Tuple[str], outcome: CommonChoiceOutcome): - 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 s4ap.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 = CommonChooseObjectsDialog( - 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, min_selectable=1, max_selectable=2) - - :param title_identifier: The title to display in the dialog. - :type title_identifier: Union[int, str, LocalizedString, CommonStringId] - :param description_identifier: The description to display in the dialog. - :type description_identifier: Union[int, str, LocalizedString, CommonStringId] - :param choices: The choices that can be chosen. - :type choices: Iterator[ObjectPickerRow] - :param title_tokens: Tokens to format into the title. - :type title_tokens: Iterator[Any], optional - :param description_tokens: Tokens to format into the description. - :type description_tokens: Iterator[Any], optional - :param per_page: The number of rows to display per page. If the number of rows (including rows added after creation) exceeds this value, pagination will be added. - :type per_page: int - :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. - :type mod_identity: CommonModIdentity, optional - :param required_tooltip: If provided, this text will display when the dialog requires at least one choice and a choice has not been made. Default is None. - :type required_tooltip: Union[int, str, LocalizedString, CommonStringId], optional - :param required_tooltip_tokens: Tokens to format into the required tooltip. Default is an empty collection. - :type required_tooltip_tokens: Iterator[Any], optional - """ - def __init__( - self, - title_identifier: Union[int, str, LocalizedString, CommonStringId], - description_identifier: Union[int, str, LocalizedString, CommonStringId], - choices: Iterator[ObjectPickerRow], - title_tokens: Iterator[Any]=(), - description_tokens: Iterator[Any]=(), - per_page: int=25, - mod_identity: CommonModIdentity=None, - required_tooltip: Union[int, str, LocalizedString, CommonStringId]=None, - required_tooltip_tokens: Iterator[Any]=() - ): - super().__init__( - title_identifier, - description_identifier, - choices, - title_tokens=title_tokens, - description_tokens=description_tokens, - mod_identity=mod_identity, - required_tooltip=required_tooltip, - required_tooltip_tokens=required_tooltip_tokens - ) - if per_page <= 0: - raise AssertionError('\'per_page\' must be greater than zero.') - self._per_page = per_page - self._always_visible_rows = tuple() - self._current_page = 1 - - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - return 's4cl_choose_object_dialog' - - @property - def current_page(self) -> int: - """Retrieve the current page. - - :return: A number indicating the current page. - :rtype: int - """ - return self._current_page - - # noinspection PyMissingOrEmptyDocstring - @property - def rows(self) -> Tuple[ObjectPickerRow]: - result: Tuple[ObjectPickerRow] = super().rows - return result - - @property - def always_visible_rows(self) -> Tuple[ObjectPickerRow]: - """A collection of rows that will always appear in the dialog no matter which page. - - .. note:: These rows are added to the dialog before the normal rows are added to the dialog. - - :return: A collection of rows added to the dialog that will always appear. - :rtype: Tuple[ObjectPickerRow] - """ - return self._always_visible_rows - - # noinspection PyMissingOrEmptyDocstring - def add_row(self, choice: ObjectPickerRow, *_, always_visible: bool=False, **__): - """add_row(row, *_, always_on_visible=False, **__) - - Add a row to the dialog. - - :param choice: The row to add. - :type choice: ObjectPickerRow - :param always_visible: If set to True, the row will always appear in the dialog no matter which page. If False, the row will act as normal. - :type always_visible: bool, optional - """ - if not always_visible: - super().add_row(choice, *_, **__) - return - try: - self._always_visible_rows += (choice,) - except Exception as ex: - self.log.error('An error occurred while running \'{}\''.format(CommonChooseObjectsDialog.add_row.__name__), exception=ex) - - def show( - self, - on_chosen: Callable[[Tuple[Any], CommonChoiceOutcome], Any]=CommonFunctionUtils.noop, - picker_type: UiObjectPicker.UiObjectPickerObjectPickerType=UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT, - page: int=1, - sim_info: SimInfo=None, - categories: Iterator[CommonDialogObjectOptionCategory]=(), - include_pagination: bool=True, - min_selectable: int=1, - max_selectable: int=1, - sort_rows: bool=False - ): - """show(\ - on_chosen=CommonFunctionUtils.noop,\ - picker_type=UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT,\ - page=1,\ - sim_info=None,\ - categories=(),\ - min_selectable=1,\ - max_selectable=1,\ - sort_rows=True\ - ) - - Show the dialog and invoke the callbacks upon the player choosing objects. - - :param on_chosen: A callback invoked upon the player choosing something from the list. Default is CommonFunctionUtils.noop. - :type on_chosen: Callable[[Tuple[Any], CommonChoiceOutcome], optional - :param picker_type: The layout of the dialog. Default is UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT. - :type picker_type: UiObjectPicker.UiObjectPickerObjectPickerType, optional - :param page: The page to display. Ignored if there is only one page of choices. Default is 1. - :type page: int, optional - :param sim_info: The Sim that will appear in the dialog image. The default Sim is the Active Sim. Default is None. - :type sim_info: SimInfo, optional - :param categories: A collection of categories to display in the dialog. They will appear in a drop down above the rows. Default is an empty collection. - :type categories: Iterator[CommonDialogObjectOptionCategory], optional - :param include_pagination: If True, pagination will be applied. If False, no pagination will be applied. Default is True. - :type include_pagination: bool, optional - :param min_selectable: The minimum number of items required to be selected. Default is 1. - :type min_selectable: int, optional - :param max_selectable: The maximum number of items allowed to be selected. Default is 1. - :type max_selectable: int, optional - :param sort_rows: If True, rows will be sorted by display name, with the selected rows on top. If False, rows will not be sorted. Default is False. - :type sort_rows: bool, optional - """ - self._current_page = page - try: - return self._show( - on_chosen=on_chosen, - picker_type=picker_type, - page=page, - sim_info=sim_info, - categories=categories, - include_pagination=include_pagination, - min_selectable=min_selectable, - max_selectable=max_selectable, - sort_rows=sort_rows - ) - except Exception as ex: - self.log.error('An error occurred while running \'{}\''.format(CommonChooseObjectsDialog.show.__name__), exception=ex) - - def _show( - self, - on_chosen: Callable[[Tuple[Any], CommonChoiceOutcome], bool]=CommonFunctionUtils.noop, - picker_type: UiObjectPicker.UiObjectPickerObjectPickerType=UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT, - page: int=1, - sim_info: SimInfo=None, - categories: Iterator[CommonDialogObjectOptionCategory]=(), - include_pagination: bool=True, - min_selectable: int=1, - max_selectable: int=1, - sort_rows: bool=False - ): - def _on_chosen(choices: Tuple[Any], outcome: CommonChoiceOutcome) -> bool: - try: - self.log.debug('Choices made {}.'.format(pformat(choices))) - if CommonDialogNavigationButtonTag.NEXT in choices: - self.log.debug('Next chosen.') - self.show( - on_chosen=on_chosen, - picker_type=picker_type, - page=page + 1, - sim_info=sim_info, - categories=categories, - min_selectable=min_selectable, - max_selectable=max_selectable - ) - return True - elif CommonDialogNavigationButtonTag.PREVIOUS in choices: - self.log.debug('Previous chosen.') - self.show( - on_chosen=on_chosen, - picker_type=picker_type, - page=page - 1, - sim_info=sim_info, - categories=categories, - min_selectable=min_selectable, - max_selectable=max_selectable - ) - return True - self.log.format_with_message('Choose Objects Choices made.', choices=pformat(choices)) - result = on_chosen(choices, outcome) - self.log.format_with_message('Finished handling choose objects _show._on_chosen.', result=result) - return result - except Exception as ex: - self.log.error('Error occurred on choosing a value.', exception=ex) - return False - - _dialog = self.build_dialog( - on_chosen=_on_chosen, - picker_type=picker_type, - page=page, - sim_info=sim_info, - categories=categories, - min_selectable=min_selectable, - max_selectable=max_selectable, - sort_rows=sort_rows - ) - self.log.debug('Showing dialog.') - _dialog.show_dialog() - - # noinspection PyMissingOrEmptyDocstring - def build_dialog( - self, - on_chosen: Callable[[Tuple[Any], CommonChoiceOutcome], bool]=CommonFunctionUtils.noop, - picker_type: UiObjectPicker.UiObjectPickerObjectPickerType=UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT, - page: int=1, - sim_info: SimInfo=None, - categories: Iterator[CommonDialogObjectOptionCategory]=(), - include_pagination: bool=True, - min_selectable: int=1, - max_selectable: int=1, - sort_rows: bool=False - ) -> Union[UiObjectPicker, None]: - self.log.format_with_message('Attempting to build dialog.', page=page, categories=categories) - - _dialog = self._create_dialog( - picker_type=picker_type, - categories=categories, - sim_info=sim_info, - min_selectable=min_selectable, - max_selectable=max_selectable, - sort_rows=sort_rows - ) - if _dialog is None: - self.log.error('_dialog was None for some reason.') - return - - if on_chosen is None: - raise ValueError('on_chosen was None.') - - if len(self.always_visible_rows) == 0 and len(self.rows) == 0: - raise AssertionError('No rows have been provided. Add rows to the dialog before attempting to display it.') - - def _on_chosen(dialog: UiObjectPicker) -> bool: - try: - if not dialog.accepted: - self.log.debug('Dialog cancelled.') - return on_chosen(tuple(), CommonChoiceOutcome.CANCEL) - self.log.debug('Choices not made.') - choices = CommonDialogUtils.get_chosen_items(dialog) - self.log.format_with_message('Choose Object Choice made.', choice=pformat(choices)) - result = on_chosen(choices, CommonChoiceOutcome.CHOICE_MADE) - self.log.format_with_message('Finished handling choose objects _build_dialog._on_chosen.', result=result) - return result - except Exception as ex: - self.log.error('Error occurred on choosing a value.', exception=ex) - return False - - if include_pagination: - self._setup_dialog_rows( - _dialog, - page=page, - categories=categories - ) - else: - self.log.debug('Adding always visible rows.') - for always_visible_rows in self.always_visible_rows: - _dialog.add_row(always_visible_rows) - self.log.debug('Adding rows.') - for row in self.rows: - _dialog.add_row(row) - - self.log.debug('Adding listener.') - _dialog.add_listener(_on_chosen) - return _dialog - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_testing.show_choose_objects_dialog', - 'Show an example of CommonChooseObjectsDialog.' -) -def _common_testing_show_choose_objects_dialog(output: CommonConsoleCommandOutput): - output('Showing test choose objects dialog.') - - def _on_chosen(choices: Tuple[str], outcome: CommonChoiceOutcome): - output('Chose {} with result: {}.'.format(pformat(choices), pformat(outcome))) - - # 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 s4ap.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 = CommonChooseObjectsDialog( - 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, - min_selectable=1, - max_selectable=2 - ) - output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_choice_outcome.py b/Scripts/s4ap/sims4communitylib/dialogs/common_choice_outcome.py deleted file mode 100644 index 700939c..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/common_choice_outcome.py +++ /dev/null @@ -1,32 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonChoiceOutcome(CommonInt): - """The outcome of the player being given a choice. - - """ - CANCEL = 0 - CHOICE_MADE = 1 - ERROR = 2 - NEXT = 3 - PREVIOUS = 4 - - @staticmethod - def is_error_or_cancel(result: 'CommonChoiceOutcome') -> bool: - """is_error_or_cancel(result) - - Determine if an outcome is either :py:attr:`~ERROR` or :py:attr:`~CANCEL`. - - :param result: The result to check. - :type result: CommonChoiceOutcome - :return: True, if result is either an Error or Cancel. False, if not. - :rtype: bool - """ - return result == CommonChoiceOutcome.ERROR or result == CommonChoiceOutcome.CANCEL diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_choose_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/common_choose_dialog.py deleted file mode 100644 index da748ca..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/common_choose_dialog.py +++ /dev/null @@ -1,102 +0,0 @@ -""" -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 -""" -from abc import ABC -from typing import Tuple, Any, Union, Iterator -from protocolbuffers.Localization_pb2 import LocalizedString -from s4ap.sims4communitylib.dialogs.common_dialog import CommonDialog -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from ui.ui_dialog_picker import BasePickerRow - - -class CommonChooseDialog(CommonDialog, ABC): - """CommonChooseDialog(\ - title_identifier,\ - description_identifier,\ - rows,\ - title_tokens=(),\ - description_tokens=(),\ - mod_identity=None,\ - required_tooltip=None,\ - required_tooltip_tokens=()\ - ) - - A dialog that prompts the player to choose something. - - :param title_identifier: The title to display in the dialog. - :type title_identifier: Union[int, str, LocalizedString, CommonStringId] - :param description_identifier: The description to display in the dialog. - :type description_identifier: Union[int, str, LocalizedString, CommonStringId] - :param rows: The rows to display in the dialog. - :type rows: Iterator[BasePickerRow] - :param title_tokens: Tokens to format into the title. Default is an empty collection. - :type title_tokens: Iterator[Any], optional - :param description_tokens: Tokens to format into the description. Default is an empty collection. - :type description_tokens: Iterator[Any], optional - :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. Default is None. - :type mod_identity: CommonModIdentity, optional - :param required_tooltip: If provided, this text will display when the dialog requires at least one choice and a choice has not been made. Default is None. - :type required_tooltip: Union[int, str, LocalizedString, CommonStringId], optional - :param required_tooltip_tokens: Tokens to format into the required tooltip. Default is an empty collection. - :type required_tooltip_tokens: Iterator[Any], optional - """ - def __init__( - self, - title_identifier: Union[int, str, LocalizedString, CommonStringId], - description_identifier: Union[int, str, LocalizedString, CommonStringId], - rows: Iterator[BasePickerRow], - title_tokens: Iterator[Any]=(), - description_tokens: Iterator[Any]=(), - mod_identity: CommonModIdentity=None, - required_tooltip: Union[int, str, LocalizedString, CommonStringId]=None, - required_tooltip_tokens: Iterator[Any]=() - ): - super().__init__( - title_identifier, - description_identifier, - title_tokens=title_tokens, - description_tokens=description_tokens, - mod_identity=mod_identity - ) - self._rows = tuple(rows) - if required_tooltip is None: - self._required_tooltip = None - else: - self._required_tooltip = CommonLocalizationUtils.create_localized_string(required_tooltip, tokens=tuple(required_tooltip_tokens)) - - @property - def required_tooltip(self) -> Union[LocalizedString, None]: - """A tooltip that will display when the dialog requires at least one choice and a choice has not been made. - - :return: A localized string or None if no value provided. - :rtype: Union[LocalizedString, None] - """ - return self._required_tooltip - - @property - def rows(self) -> Tuple[BasePickerRow]: - """The rows to display in the dialog. - - :return: A collection of rows added to the dialog. - :rtype: Tuple[BasePickerRow] - """ - return self._rows - - def add_row(self, row: BasePickerRow, *_, **__): - """add_row(row, *_, **__) - - Add a row to the dialog. - - :param row: The row to add. - :type row: BasePickerRow - """ - try: - self._rows += (row,) - except Exception as ex: - self.log.error('add_row', exception=ex) diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_choose_outfit_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/common_choose_outfit_dialog.py deleted file mode 100644 index febac04..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/common_choose_outfit_dialog.py +++ /dev/null @@ -1,372 +0,0 @@ -""" -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 -""" -from typing import Tuple, Any, Callable, Union, Iterator, List - -from pprint import pformat - -from protocolbuffers.Localization_pb2 import LocalizedString -from sims.outfits.outfit_enums import OutfitCategory, HIDDEN_OUTFIT_CATEGORIES -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome -from s4ap.sims4communitylib.dialogs.common_choose_dialog import CommonChooseDialog -from s4ap.sims4communitylib.dialogs.utils.common_dialog_utils import CommonDialogUtils -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from ui.ui_dialog_picker import OutfitPickerRow, UiOutfitPicker - - -class CommonChooseOutfitDialog(CommonChooseDialog): - """CommonChooseOutfitDialog(\ - mod_identity,\ - title_identifier,\ - description_identifier,\ - title_tokens=(),\ - description_tokens=(),\ - required_tooltip=None,\ - required_tooltip_tokens=()\ - ) - - Create a dialog that allows the player to choose an outfit from a Sims currently available outfits. - - .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_choose_outfit_dialog` in the in-game console. - - .. highlight:: python - .. code-block:: python - - def _common_testing_show_choose_outfit_dialog(): - def _on_chosen(choice: Tuple[OutfitCategory, int], outcome: CommonChoiceOutcome): - output('Chose {} with result: {}.'.format(pformat(choice), pformat(outcome))) - - try: - sim_info = CommonSimUtils.get_active_sim_info() - # 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=(sim_info,), text_color=CommonLocalizedStringColor.BLUE),) - from s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils - dialog = CommonChooseOutfitDialog( - ModInfo.get_identity(), - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - title_tokens=title_tokens, - description_tokens=description_tokens - ) - outfit_list = (OutfitCategory.EVERYDAY, 0) - dialog.show(sim_info, outfit_list=outfit_list, on_chosen=_on_chosen) - 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.') - - :param title_identifier: The title to display in the dialog. - :type title_identifier: Union[int, str, LocalizedString, CommonStringId] - :param description_identifier: The description to display in the dialog. - :type description_identifier: Union[int, str, LocalizedString, CommonStringId] - :param title_tokens: Tokens to format into the title. - :type title_tokens: Iterator[Any], optional - :param description_tokens: Tokens to format into the description. - :type description_tokens: Iterator[Any], optional - :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. - :type mod_identity: CommonModIdentity, optional - :param required_tooltip: If provided, this text will display when the dialog requires at least one choice and a choice has not been made. Default is None. - :type required_tooltip: Union[int, str, LocalizedString, CommonStringId], optional - :param required_tooltip_tokens: Tokens to format into the required tooltip. Default is an empty collection. - :type required_tooltip_tokens: Iterator[Any], optional - """ - - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - return 'common_choose_outfit_dialog' - - def __init__( - self, - mod_identity: CommonModIdentity, - title_identifier: Union[int, str, LocalizedString, CommonStringId], - description_identifier: Union[int, str, LocalizedString, CommonStringId], - title_tokens: Iterator[Any]=(), - description_tokens: Iterator[Any]=(), - required_tooltip: Union[int, str, LocalizedString, CommonStringId]=None, - required_tooltip_tokens: Iterator[Any]=() - ): - super().__init__( - title_identifier, - description_identifier, - tuple(), - title_tokens=title_tokens, - description_tokens=description_tokens, - mod_identity=mod_identity, - required_tooltip=required_tooltip, - required_tooltip_tokens=required_tooltip_tokens - ) - - # noinspection PyMissingOrEmptyDocstring - @property - def rows(self) -> Tuple[OutfitPickerRow]: - result: Tuple[OutfitPickerRow] = super().rows - return result - - # noinspection PyMissingOrEmptyDocstring - def add_row(self, choice: OutfitPickerRow, *_, **__): - """add_row(row, *_, **__) - - Add a row to the dialog. - - :param choice: The row to add. - :type choice: OutfitPickerRow - """ - super().add_row(choice, *_, **__) - - def show( - self, - sim_info: SimInfo, - outfit_list: Iterator[Tuple[OutfitCategory, int]]=(), - thumbnail_type: UiOutfitPicker._OutftiPickerThumbnailType=UiOutfitPicker._OutftiPickerThumbnailType.SIM_INFO, - on_chosen: Callable[[Union[Tuple[OutfitCategory, int], None], CommonChoiceOutcome], None]=CommonFunctionUtils.noop, - exclude_outfit_categories: Tuple[OutfitCategory]=(OutfitCategory.CURRENT_OUTFIT, OutfitCategory.BATHING, *HIDDEN_OUTFIT_CATEGORIES), - show_filter: bool=True, - allow_choose_current_outfit: bool=False - ): - """show(\ - sim_info, - outfit_list=(),\ - thumbnail_type=UiOutfitPicker._OutftiPickerThumbnailType.SIM_INFO,\ - on_chosen=CommonFunctionUtils.noop,\ - exclude_outfit_categories=(OutfitCategory.CURRENT_OUTFIT, OutfitCategory.BATHING, OutfitCategory.SPECIAL, OutfitCategory.CAREER, OutfitCategory.SITUATION, OutfitCategory.BATUU),\ - show_filter=True,\ - allow_choose_current_outfit=False\ - ) - - Show the dialog and invoke the callbacks upon the player making a choice. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param outfit_list: A collection of outfits. Default is all Outfits. - :type outfit_list: Iterator[Tuple[OutfitCategory, int]], optional - :param thumbnail_type: Determines how the thumbnails of the outfits should be displayed. Default is UiOutfitPicker._OutftiPickerThumbnailType.SIM_INFO - :type thumbnail_type: UiObjectPicker._OutftiPickerThumbnailType, optional - :param on_chosen: A callback invoked upon the player choosing something from the list. Default is CommonFunctionUtils.noop. - :type on_chosen: Callable[[Union[Tuple[OutfitCategory, int], None], CommonChoiceOutcome], None], optional - :param exclude_outfit_categories: A collection of Outfit Categories to exclude from display. Default is CURRENT_OUTFIT, BATHING, SPECIAL, CAREER, SITUATION, BATUU - :type exclude_outfit_categories: Tuple[OutfitCategory], optional - :param show_filter: Whether or not to show the Outfit Category filters in the dialogue. Default is True. - :type show_filter: bool, optional - :param allow_choose_current_outfit: If True, then the Outfit that is currently being worn will be allowed to be chosen. If False, the current outfit cannot be chosen. Default is False. - :type allow_choose_current_outfit: bool, optional - """ - try: - outfit_list = self._setup_outfit_list(outfit_list, exclude_outfit_categories) - return self._show( - sim_info, - outfit_list=outfit_list, - thumbnail_type=thumbnail_type, - on_chosen=on_chosen, - show_filter=show_filter, - allow_choose_current_outfit=allow_choose_current_outfit, - ) - except Exception as ex: - self.log.error('An error occurred while running \'{}\''.format(self.show.__name__), exception=ex) - - def _setup_outfit_list( - self, - outfit_list: Iterator[Tuple[OutfitCategory, int]], - exclude_outfit_categories: Tuple[OutfitCategory] - ) -> Tuple[Tuple[OutfitCategory, int]]: - if outfit_list: - return tuple(outfit_list) - outfit_list: List[Tuple[OutfitCategory, int]] = list() - for outfit_category in OutfitCategory.values: - if outfit_category in exclude_outfit_categories: - continue - outfit_index = 0 - while outfit_index < CommonOutfitUtils.get_maximum_number_of_outfits_for_category(outfit_category): - outfit_list.append((outfit_category, outfit_index)) - outfit_index += 1 - return tuple(outfit_list) - - def _show( - self, - sim_info: SimInfo, - outfit_list: Iterator[Tuple[OutfitCategory, int]]=(), - thumbnail_type: UiOutfitPicker._OutftiPickerThumbnailType=UiOutfitPicker._OutftiPickerThumbnailType.SIM_INFO, - on_chosen: Callable[[Union[Tuple[OutfitCategory, int], None], CommonChoiceOutcome], None]=CommonFunctionUtils.noop, - show_filter: bool=True, - allow_choose_current_outfit: bool=False - ): - def _on_chosen(choice: Tuple[OutfitCategory, int], outcome: CommonChoiceOutcome) -> None: - try: - self.log.format_with_message('Choose Outfit Choice made.', choice=choice) - on_chosen(choice, outcome) - self.log.debug('Finished handling choose object _show.') - return - except Exception as ex: - self.log.error('Error occurred on choosing a value.', exception=ex) - - _dialog = self.build_dialog( - sim_info, - outfit_list=outfit_list, - thumbnail_type=thumbnail_type, - on_chosen=_on_chosen, - show_filter=show_filter, - allow_choose_current_outfit=allow_choose_current_outfit - ) - self.log.debug('Showing dialog.') - _dialog.show_dialog() - - # noinspection PyMissingOrEmptyDocstring - def build_dialog( - self, - sim_info: SimInfo, - outfit_list: Iterator[Tuple[OutfitCategory, int]]=(), - thumbnail_type: UiOutfitPicker._OutftiPickerThumbnailType=UiOutfitPicker._OutftiPickerThumbnailType.SIM_INFO, - on_chosen: Callable[[Union[Tuple[OutfitCategory, int], None], CommonChoiceOutcome], None]=CommonFunctionUtils.noop, - show_filter: bool=True, - allow_choose_current_outfit: bool=False - ) -> Union[UiOutfitPicker, None]: - self.log.format_with_message( - 'Attempting to build dialog.', - sim=sim_info, - outfit_list=outfit_list, - thumbnail_type=thumbnail_type - ) - - _dialog = self._create_dialog( - sim_info, - outfit_list=outfit_list, - thumbnail_type=thumbnail_type, - show_filter=show_filter - ) - if _dialog is None: - self.log.error('_dialog was None for some reason.') - return - - if on_chosen is None: - raise ValueError('on_chosen was None.') - - def _on_chosen(dialog: UiOutfitPicker) -> None: - try: - self.log.format_with_message('Choice made.', picked_results=dialog.picked_results) - if not dialog.accepted: - self.log.debug('Dialog cancelled.') - on_chosen(None, CommonChoiceOutcome.CANCEL) - return - self.log.format_with_message('Dialog accepted, checking if choices were made.') - choice = CommonDialogUtils.get_chosen_item(dialog) - self.log.format_with_message('Outfit choice made.', choice=choice) - on_chosen(choice, CommonChoiceOutcome.CHOICE_MADE) - self.log.debug('Finished handling outfit items _on_chosen.') - return - except Exception as ex: - self.log.error('Error occurred on choosing a value.', exception=ex) - - self._setup_dialog_rows( - sim_info, - _dialog, - outfit_list=outfit_list, - allow_choose_current_outfit=allow_choose_current_outfit - ) - - self.log.debug('Adding listener.') - _dialog.add_listener(_on_chosen) - return _dialog - - def _setup_dialog_rows( - self, - sim_info: SimInfo, - _dialog: UiOutfitPicker, - outfit_list: Iterator[Tuple[OutfitCategory, int]]=(), - allow_choose_current_outfit: bool=False - ): - self.log.debug('Adding rows.') - sim_id = CommonSimUtils.get_sim_id(sim_info) - added_rows = False - current_outfit = CommonOutfitUtils.get_current_outfit(sim_info) - for (outfit_category, outfit_index) in outfit_list: - # noinspection PyTypeChecker - if not CommonOutfitUtils.has_outfit(sim_info, (outfit_category, outfit_index)) and not CommonOutfitUtils.has_outfit(sim_info, (int(outfit_category), outfit_index)): - self.log.format_with_message('Sim does not have outfit.', sim=sim_info, outfit_category_and_index=(outfit_category, outfit_index)) - continue - added_rows = True - _dialog.add_row( - OutfitPickerRow( - sim_id, - outfit_category, - outfit_index, - # For some reason the Outfit Picker uses "is_enable" to determine which outfit is currently selected, instead of the expected "is_selected". - is_enable=(outfit_category, outfit_index) != current_outfit if not allow_choose_current_outfit else True, - tag=(outfit_category, outfit_index) - ) - ) - - for row in self.rows: - _dialog.add_row(row) - - if not added_rows and len(self.rows) == 0: - raise AssertionError('No rows have been provided. Add rows to the dialog before attempting to display it.') - - def _create_dialog( - self, - target_sim_info: SimInfo, - outfit_list: Iterator[Tuple[OutfitCategory, int]], - thumbnail_type: UiOutfitPicker._OutftiPickerThumbnailType=UiOutfitPicker._OutftiPickerThumbnailType.SIM_INFO, - show_filter: bool=True - ) -> Union[UiOutfitPicker, None]: - try: - outfit_categories: List[OutfitCategory] = list() - for (outfit_category, outfit_index) in outfit_list: - if outfit_category not in outfit_categories: - outfit_categories.append(outfit_category) - - dialog = UiOutfitPicker.TunableFactory()\ - .default( - target_sim_info or CommonSimUtils.get_active_sim_info(), - text=lambda *_, **__: self.description, - title=lambda *_, **__: self.title, - outfit_categories=set([outfit[0] for outfit in outfit_list]), - thumbnail_type=thumbnail_type, - show_filter=show_filter - ) - dialog.outfit_category_filters = outfit_categories - return dialog - except Exception as ex: - self.log.error('_create_dialog', exception=ex) - return None - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_testing.show_choose_outfit_dialog', - 'Show an example of CommonChooseResponseDialog.' -) -def _common_testing_show_choose_outfit_dialog(output: CommonConsoleCommandOutput): - output('Showing test choose outfit dialog.') - - def _on_chosen(choice: Tuple[OutfitCategory, int], outcome: CommonChoiceOutcome): - output('Chose {} with result: {}.'.format(pformat(choice), pformat(outcome))) - - sim_info = CommonSimUtils.get_active_sim_info() - # 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=(sim_info,), text_color=CommonLocalizedStringColor.BLUE),) - dialog = CommonChooseOutfitDialog( - ModInfo.get_identity(), - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - title_tokens=title_tokens, - description_tokens=description_tokens - ) - outfit_list = ((OutfitCategory.EVERYDAY, 0),) - dialog.show(sim_info, outfit_list=outfit_list, on_chosen=_on_chosen) - output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_choose_response_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/common_choose_response_dialog.py deleted file mode 100644 index 9a1450d..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/common_choose_response_dialog.py +++ /dev/null @@ -1,513 +0,0 @@ -""" -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 -""" -import math -import os - -from typing import Tuple, Any, Callable, Union, Iterator - -from pprint import pformat - -from event_testing.resolver import DoubleSimResolver -from protocolbuffers.Localization_pb2 import LocalizedString -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome -from s4ap.sims4communitylib.dialogs.common_dialog import CommonDialog -from s4ap.sims4communitylib.dialogs.common_dialog_navigation_button_tag import CommonDialogNavigationButtonTag -from s4ap.sims4communitylib.dialogs.common_ui_dialog_response import CommonUiDialogResponse -from s4ap.sims4communitylib.dialogs.common_ui_response_dialog import CommonUiResponseDialog -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from ui.ui_dialog import UiDialogOption, ButtonType - -ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' - - -class CommonChooseResponseDialog(CommonDialog): - """CommonChooseResponseDialog(\ - mod_identity,\ - title_identifier,\ - description_identifier,\ - responses,\ - title_tokens=(),\ - description_tokens=(),\ - next_button_text=CommonStringId.NEXT,\ - previous_button_text=CommonStringId.PREVIOUS,\ - ) - - Create a dialog that prompts the player to choose a response. - - .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_choose_response_dialog` in the in-game console. - - .. highlight:: python - .. code-block:: python - - def _common_testing_show_choose_response_dialog(): - - def _on_chosen(choice: str, outcome: CommonChoiceOutcome): - pass - - responses: Tuple[CommonUiDialogResponse] = ( - CommonUiDialogResponse( - 1, - 'Value 1', - text=CommonLocalizationUtils.create_localized_string(CommonStringId.TESTING_TEST_BUTTON_ONE) - ), - CommonUiDialogResponse( - 2, - 'Value 2', - text=CommonLocalizationUtils.create_localized_string(CommonStringId.TESTING_TEST_BUTTON_TWO) - ), - CommonUiDialogResponse( - 3, - 'Value 3', - text=CommonLocalizationUtils.create_localized_string('Test Button 3') - ) - ) - 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),) - - active_sim_info = CommonSimUtils.get_active_sim_info() - dialog = CommonChooseResponseDialog( - ModInfo.get_identity(), - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - responses, - title_tokens=title_tokens, - description_tokens=description_tokens, - per_page=2 - ) - dialog.show( - on_chosen=_on_chosen, - sim_info=active_sim_info, - include_previous_button=False - ) - - :param title_identifier: The title to display in the dialog. - :type title_identifier: Union[int, str, LocalizedString, CommonStringId] - :param description_identifier: The description to display in the dialog. - :type description_identifier: Union[int, str, LocalizedString, CommonStringId] - :param responses: The choices that can be chosen. - :type responses: Iterator[CommonUiDialogResponse] - :param title_tokens: Tokens to format into the title. Default is no tokens. - :type title_tokens: Iterator[Any], optional - :param description_tokens: Tokens to format into the description. Default is no tokens. - :type description_tokens: Iterator[Any], optional - :param next_button_text: The text the Next button will display, if the Next button is added. Default is Next. - :type next_button_text: Union[int, str, LocalizedString, CommonStringId], optional - :param previous_button_text: The text the Previous button will display, if the Previous button is added. Default is Previous. - :type previous_button_text: Union[int, str, LocalizedString, CommonStringId], optional - :param per_page: The number of responses to display per page of the dialog. Default is 10. - :type per_page: int, optional - :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. - :type mod_identity: CommonModIdentity, optional - """ - # If on Read The Docs, create fake versions of extended objects to fix the error of inheriting from multiple MockObjects. - if ON_RTD: - _NEXT_BUTTON_ID = 10001 - _PREVIOUS_BUTTON_ID = 10002 - - if not ON_RTD: - _NEXT_BUTTON_ID: int = int(ButtonType.DIALOG_RESPONSE_OK) - _PREVIOUS_BUTTON_ID: int = int(ButtonType.DIALOG_RESPONSE_CANCEL) - - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - return 's4cl_choose_response_dialog' - - def __init__( - self, - mod_identity: CommonModIdentity, - title_identifier: Union[int, str, LocalizedString, CommonStringId], - description_identifier: Union[int, str, LocalizedString, CommonStringId], - responses: Iterator[CommonUiDialogResponse], - title_tokens: Iterator[Any]=(), - description_tokens: Iterator[Any]=(), - next_button_text: Union[int, str, LocalizedString, CommonStringId]=CommonStringId.NEXT, - previous_button_text: Union[int, str, LocalizedString, CommonStringId]=CommonStringId.PREVIOUS, - per_page: int=10 - ): - super().__init__( - title_identifier, - description_identifier, - title_tokens=title_tokens, - description_tokens=description_tokens, - mod_identity=mod_identity - ) - if per_page <= 0: - raise AssertionError('\'per_page\' must be greater than zero.') - self._responses = tuple(responses) - self._per_page = per_page - self._current_page = 1 - self._next_button_text = CommonLocalizationUtils.create_localized_string(next_button_text) - self._previous_button_text = CommonLocalizationUtils.create_localized_string(previous_button_text) - self._always_visible_responses = tuple() - - @property - def current_page(self) -> int: - """The current page shown of the dialog.""" - return self._current_page - - @property - def responses(self) -> Tuple[CommonUiDialogResponse]: - """The responses to display in the dialog.""" - return self._responses - - @property - def always_visible_responses(self) -> Tuple[CommonUiDialogResponse]: - """A collection of responses that will always appear in the dialog no matter which page. - - .. note:: These responses are added to the dialog before the normal responses are added to the dialog. - - :return: A collection of responses added to the dialog that will always appear. - :rtype: Tuple[CommonUiDialogResponse] - """ - return self._always_visible_responses - - def add_response(self, response: CommonUiDialogResponse, *_, always_visible: bool=False, **__): - """add_response(response, *_, always_visible=False, **__) - - Add a response to the dialog. - - :param response: The response to add. - :type response: CommonUiDialogResponse - :param always_visible: If set to True, the response will always appear in the dialog no matter which page. If False, the response will act as normal. Default is False. - :type always_visible: bool, optional - """ - if not always_visible: - self._responses += (response,) - return - try: - self._always_visible_responses += (response,) - except Exception as ex: - self.log.error('An error occurred while running \'{}\''.format(self.add_response.__name__), exception=ex) - - def show( - self, - sim_info: SimInfo=None, - target_sim_info: SimInfo=None, - on_chosen: Callable[[Any, CommonChoiceOutcome], None]=CommonFunctionUtils.noop, - on_previous: Callable[[], None]=CommonFunctionUtils.noop, - dialog_options: UiDialogOption=0, - include_previous_button: bool=True, - include_pagination: bool=True, - page: int=1 - ): - """show(\ - sim_info=None,\ - target_sim_info=None,\ - on_chosen=CommonFunctionUtils.noop,\ - on_previous=CommonFunctionUtils.noop,\ - dialog_options=0,\ - include_previous_button=True,\ - include_pagination=True,\ - page=1\ - ) - - Show the dialog and invoke the callbacks upon the player making a choice. - - :param sim_info: The Sim that will appear in the dialog image. The default Sim is the Active Sim. Default is None. - :type sim_info: SimInfo, optional - :param target_sim_info: If provided, the dialog will appear as if it were a conversation instead of the normal view. Default is None. - :type target_sim_info: SimInfo, optional - :param on_chosen: A callback invoked upon the player choosing something from the list. Default is CommonFunctionUtils.noop. - :type on_chosen: Callable[[Any, CommonChoiceOutcome], optional - :param on_previous: A callback performed when the previous response is chosen. Default is no operation. - :type on_previous: Callable[[], None], optional - :param dialog_options: Options to apply to the dialog, such as removing the close button. Default is no options. - :type dialog_options: UiDialogOption, optional - :param include_previous_button: If True, the Previous button will be appended to the end of the dialog, if False, the Previous button will not be shown unless the current page is greater than 1. Default is True. - :type include_previous_button: bool, optional - :param include_pagination: If True, pagination will be applied. If False, no pagination will be applied. Default is True. The `include_previous_button` argument will override this setting! - :type include_pagination: bool, optional - :param page: The page to show the dialog on. Default is the first page. - :type page: int, optional - """ - self._current_page = page - try: - return self._show( - sim_info=sim_info, - target_sim_info=target_sim_info, - on_chosen=on_chosen, - on_previous=on_previous, - dialog_options=dialog_options, - include_previous_button=include_previous_button, - include_pagination=include_pagination, - page=page - ) - except Exception as ex: - self.log.error('An error occurred while running \'{}\''.format(self.__class__.show.__name__), exception=ex) - - def _show( - self, - sim_info: SimInfo=None, - target_sim_info: SimInfo=None, - on_chosen: Callable[[Any, CommonChoiceOutcome], None]=CommonFunctionUtils.noop, - on_previous: Callable[[], None]=CommonFunctionUtils.noop, - dialog_options: UiDialogOption=0, - include_previous_button: bool=True, - include_pagination: bool=True, - page: int=1 - ): - def _on_chosen(choice: Any, outcome: CommonChoiceOutcome) -> None: - try: - self.log.debug('Choice made.') - if choice == CommonDialogNavigationButtonTag.NEXT: - self.log.debug('Next chosen.') - self.show(on_chosen=on_chosen, on_previous=on_previous, dialog_options=dialog_options, include_previous_button=include_previous_button, sim_info=sim_info, target_sim_info=target_sim_info, page=page + 1) - return - elif choice == CommonDialogNavigationButtonTag.PREVIOUS: - self.log.debug('Previous chosen.') - if page == 1: - on_previous() - else: - self.show(on_chosen=on_chosen, on_previous=on_previous, dialog_options=dialog_options, include_previous_button=include_previous_button, sim_info=sim_info, target_sim_info=target_sim_info, page=page - 1) - return - self.log.format_with_message('Choice made.', choice=choice) - on_chosen(choice, outcome) - self.log.debug('Finished handling _show.') - except Exception as ex: - self.log.error('Error occurred on choosing a value.', exception=ex) - - _dialog = self.build_dialog( - sim_info=sim_info, - target_sim_info=target_sim_info, - on_chosen=_on_chosen, - on_previous=on_previous, - dialog_options=dialog_options, - include_previous_button=include_previous_button, - include_pagination=include_pagination, - page=page - ) - if _dialog is None: - self.log.error('An error occurred when building the dialog!') - return - self.log.debug('Showing dialog.') - _dialog.show_dialog() - - def build_dialog( - self, - sim_info: SimInfo=None, - target_sim_info: SimInfo=None, - on_chosen: Callable[[Any, CommonChoiceOutcome], None]=CommonFunctionUtils.noop, - on_previous: Callable[[], None]=CommonFunctionUtils.noop, - dialog_options: Union[UiDialogOption, int]=0, - include_previous_button: bool=True, - include_pagination: bool=True, - page: int=1 - ) -> Union[CommonUiResponseDialog, None]: - """build_dialog(\ - sim_info=None,\ - target_sim_info=None,\ - on_chosen=CommonFunctionUtils.noop,\ - on_previous=CommonFunctionUtils.noop,\ - dialog_options=0,\ - include_previous_button=True,\ - include_pagination=True,\ - page=1\ - ) - - Build the dialog. - - :param sim_info: A Sim that will appear in the top left image when the dialog is shown. If set to None, the active Sim will be used. Default is None. - :type sim_info: SimInfo, optional - :param target_sim_info: If provided, the dialog will appear as if it were a conversation instead of the normal view. Default is None. - :type target_sim_info: SimInfo, optional - :param on_chosen: A callback performed when a choice is made. Default is no operation. - :type on_chosen: Callable[[Any, CommonChoiceOutcome], None], optional - :param on_previous: A callback performed when the Previous response is chosen. Default is no operation. - :type on_previous: Callable[[], None], optional - :param dialog_options: Display options for the dialog, such as hiding the close button. Default is no display options. - :type dialog_options: UiDialogOption, optional - :param include_previous_button: If True, the Previous button will be appended to the end of the dialog. Default is True. - :type include_previous_button: bool, optional - :param include_pagination: If True, pagination will be applied. If False, no pagination will be applied. Default is True. The `include_previous_button` argument will override this setting! - :type include_pagination: bool, optional - :param page: The page to build the dialog on. Default is the first page. - :type page: int, optional - :return: The built dialog or None if a problem occurs. - :rtype: Union[CommonUiResponseDialog, None] - """ - self.log.format_with_message('Attempting to build dialog.', dialog_options=dialog_options) - - _dialog = self._create_dialog( - dialog_options=dialog_options, - sim_info=sim_info, - target_sim_info=target_sim_info - ) - if _dialog is None: - self.log.error('_dialog was None for some reason.') - return - - if on_chosen is None: - raise ValueError('on_chosen was None.') - - if len(self.always_visible_responses) == 0 and len(self.responses) == 0: - raise AssertionError('No responses have been provided. Add responses to the dialog before attempting to display it.') - - def _on_chosen(dialog: CommonUiResponseDialog) -> None: - try: - if dialog.cancelled: - self.log.debug('Dialog cancelled.') - on_chosen(None, CommonChoiceOutcome.CANCEL) - return - choice = dialog.get_response_value() - self.log.format_with_message('Choice made.', choice=choice) - on_chosen(choice, CommonChoiceOutcome.CHOICE_MADE) - self.log.debug('Finished handling _on_chosen.') - except Exception as ex: - self.log.error('Error occurred on choosing a value.', exception=ex) - - if include_pagination: - self._setup_responses( - _dialog, - include_previous_button=include_previous_button, - page=page - ) - else: - self.log.debug('Adding always visible responses.') - for always_visible_response in self.always_visible_responses: - _dialog.add_response(always_visible_response) - self.log.debug('Adding responses.') - for response in self.responses: - _dialog.add_response(response) - - self.log.debug('Adding listener.') - _dialog.add_listener(_on_chosen) - return _dialog - - def _setup_responses( - self, - _dialog: CommonUiResponseDialog, - include_previous_button: bool=True, - page: int=1 - ): - if page < 0: - raise AssertionError('page cannot be less than zero.') - - added_previous_button = False - number_of_responses = len(self.responses) - self.log.format(number_of_responses=number_of_responses, per_page=self._per_page) - if number_of_responses > self._per_page: - number_of_pages = math.ceil(number_of_responses / self._per_page) - - if page > number_of_pages: - raise AssertionError('page was out of range. Number of Pages: {}, Requested Page: {}'.format(str(number_of_pages), str(page))) - # Add the responses that are always visible. - for always_visible_response in self.always_visible_responses: - _dialog.add_response(always_visible_response) - - # Add the responses that should show on the current page. - start_index = (page - 1) * self._per_page - end_index = page * self._per_page - self.log.format(start_index=start_index, end_index=end_index) - current_choices = self.responses[start_index:end_index] - self.log.format(current_responses=current_choices) - for response in current_choices: - _dialog.add_response(response) - - if page < number_of_pages: - self.log.format_with_message('Adding Next response.', page=page, number_of_pages=number_of_pages) - _dialog.add_response(CommonUiDialogResponse(len(self.responses) + 1, CommonDialogNavigationButtonTag.NEXT, text=self._next_button_text)) - else: - self.log.format_with_message('Not adding Next.', page=page, number_of_pages=number_of_pages) - - if page > 1: - self.log.format_with_message('Adding Previous response.', page=page, number_of_pages=number_of_pages) - added_previous_button = True - _dialog.add_response(CommonUiDialogResponse(len(self.responses) + 2, CommonDialogNavigationButtonTag.PREVIOUS, text=self._previous_button_text)) - else: - self.log.format_with_message('Not adding Previous response.', page=page) - else: - self.log.debug('Adding always visible responses.') - for always_visible_response in self.always_visible_responses: - _dialog.add_response(always_visible_response) - self.log.debug('Adding responses.') - for response in self.responses: - _dialog.add_response(response) - - if not added_previous_button and include_previous_button: - self.log.format_with_message('Adding Previous response.', page=page) - _dialog.add_response(CommonUiDialogResponse(len(self.responses) + 2, CommonDialogNavigationButtonTag.PREVIOUS, text=self._previous_button_text)) - - def _create_dialog( - self, - dialog_options: UiDialogOption=0, - sim_info: SimInfo=None, - target_sim_info: SimInfo=None - ) -> Union[CommonUiResponseDialog, None]: - try: - self.log.debug('Creating dialog.') - return CommonUiResponseDialog.TunableFactory().default( - sim_info or CommonSimUtils.get_active_sim_info(), - tuple(), - dialog_options=dialog_options, - text=lambda *_, **__: self.description, - title=lambda *_, **__: self.title, - target_sim_id=CommonSimUtils.get_sim_id(target_sim_info) if target_sim_info is not None else None, - resolver=DoubleSimResolver(sim_info, target_sim_info) if sim_info is not None and target_sim_info is not None else None - ) - except Exception as ex: - self.log.error('_create_dialog', exception=ex) - return None - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_testing.show_choose_response_dialog', - 'Show an example of CommonChooseResponseDialog.' -) -def _common_testing_show_choose_response_dialog(output: CommonConsoleCommandOutput): - output('Showing test choose response dialog.') - - def _on_chosen(choice: str, outcome: CommonChoiceOutcome): - output('Chose {} with result: {}.'.format(pformat(choice), pformat(outcome))) - - responses: Tuple[CommonUiDialogResponse] = ( - CommonUiDialogResponse( - 1, - 'Value 1', - text=CommonLocalizationUtils.create_localized_string(CommonStringId.TESTING_TEST_BUTTON_ONE) - ), - CommonUiDialogResponse( - 2, - 'Value 2', - text=CommonLocalizationUtils.create_localized_string(CommonStringId.TESTING_TEST_BUTTON_TWO) - ), - CommonUiDialogResponse( - 3, - 'Value 3', - text=CommonLocalizationUtils.create_localized_string('Test Button 3') - ) - ) - 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),) - - active_sim_info = CommonSimUtils.get_active_sim_info() - dialog = CommonChooseResponseDialog( - ModInfo.get_identity(), - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - responses, - title_tokens=title_tokens, - description_tokens=description_tokens, - per_page=2 - ) - dialog.show( - sim_info=active_sim_info, - on_chosen=_on_chosen, - include_previous_button=False - ) - output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_choose_sim_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/common_choose_sim_dialog.py deleted file mode 100644 index f25aa7b..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/common_choose_sim_dialog.py +++ /dev/null @@ -1,318 +0,0 @@ -""" -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 -""" -from typing import Any, Callable, Union, Iterator, Tuple - -from pprint import pformat - -import random -from protocolbuffers.Localization_pb2 import LocalizedString -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome -from s4ap.sims4communitylib.dialogs.common_choose_dialog import CommonChooseDialog -from s4ap.sims4communitylib.dialogs.utils.common_dialog_utils import CommonDialogUtils -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from ui.ui_dialog_picker import UiSimPicker, SimPickerRow - - -class CommonChooseSimDialog(CommonChooseDialog): - """CommonChooseSimDialog(\ - title_identifier,\ - description_identifier,\ - choices,\ - title_tokens=(),\ - description_tokens=(),\ - mod_identity=None,\ - required_tooltip=None,\ - required_tooltip_tokens=()\ - ) - - Create a dialog to display a list of Sims to choose. - - .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_choose_sim_dialog` in the in-game console. - - .. highlight:: python - .. code-block:: python - - def _common_testing_show_choose_sim_dialog(): - - def _on_chosen(choice: Union[SimInfo, None], outcome: CommonChoiceOutcome): - 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 s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils - current_count = 0 - count = 25 - options = [] - for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): - if current_count >= count: - break - sim_id = CommonSimUtils.get_sim_id(sim_info) - should_select = random.choice((True, False)) - is_enabled = random.choice((True, False)) - options.append( - SimPickerRow( - sim_id, - select_default=should_select, - tag=sim_info, - is_enable=is_enabled - ) - ) - current_count += 1 - - dialog = CommonChooseSimDialog( - 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_chosen=_on_chosen, column_count=5) - - :param title_identifier: A decimal identifier of the title text. - :type title_identifier: Union[int, str, LocalizedString, CommonStringId] - :param description_identifier: A decimal identifier of the description text. - :type description_identifier: Union[int, str, LocalizedString, CommonStringId] - :param choices: The choices to display in the dialog. - :type choices: Iterator[SimPickerRow] - :param title_tokens: Tokens to format into the title. - :type title_tokens: Iterator[Any], optional - :param description_tokens: Tokens to format into the description. - :type description_tokens: Iterator[Any], optional - :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. - :type mod_identity: CommonModIdentity, optional - :param required_tooltip: If provided, this text will display when the dialog requires at least one choice and a choice has not been made. Default is None. - :type required_tooltip: Union[int, str, LocalizedString, CommonStringId], optional - :param required_tooltip_tokens: Tokens to format into the required tooltip. Default is an empty collection. - :type required_tooltip_tokens: Iterator[Any], optional - """ - def __init__( - self, - title_identifier: Union[int, str, LocalizedString, CommonStringId], - description_identifier: Union[int, str, LocalizedString, CommonStringId], - choices: Iterator[SimPickerRow], - title_tokens: Iterator[Any]=(), - description_tokens: Iterator[Any]=(), - mod_identity: CommonModIdentity=None, - required_tooltip: Union[int, str, LocalizedString, CommonStringId]=None, - required_tooltip_tokens: Iterator[Any]=() - ): - super().__init__( - title_identifier, - description_identifier, - choices, - title_tokens=title_tokens, - description_tokens=description_tokens, - mod_identity=mod_identity, - required_tooltip=required_tooltip, - required_tooltip_tokens=required_tooltip_tokens - ) - - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - return 's4cl_choose_sim_dialog' - - # noinspection PyMissingOrEmptyDocstring - @property - def rows(self) -> Tuple[SimPickerRow]: - result: Tuple[SimPickerRow] = super().rows - return result - - # noinspection PyMissingOrEmptyDocstring - def add_row(self, choice: SimPickerRow, *_, **__): - return super().add_row(choice, *_, **__) - - def show( - self, - on_chosen: Callable[[Any, CommonChoiceOutcome], Any]=CommonFunctionUtils.noop, - sim_info: SimInfo=None, - should_show_names: bool=True, - hide_row_descriptions: bool=False, - column_count: int=3 - ): - """show(\ - on_chosen=CommonFunctionUtils.noop,\ - sim_info=None,\ - should_show_names=True,\ - hide_row_descriptions=False,\ - column_count=3\ - ) - - Show the dialog and invoke the callbacks upon the player making a choice. - - :param on_chosen: A callback invoked upon the player choosing a Sim from the list. Cannot be None. - :type on_chosen: Callable[[Any, CommonChoiceOutcome], Any], optional - :param sim_info: The SimInfo of the Sim that will appear in the dialog image. The default Sim is the active Sim. - :type sim_info: SimInfo, optional - :param should_show_names: If True, then the names of the Sims will display in the dialog. - :type should_show_names: bool, optional - :param hide_row_descriptions: A flag to hide the row descriptions. - :type hide_row_descriptions: bool, optional - :param column_count: The number of columns to display Sims in. Minimum: 3, Maximum: 8 - :type column_count: int, optional - :exception AssertionError: when something is wrong with the arguments or no rows were added to the dialog. - """ - try: - self._rows = tuple(sorted(self._rows, key=lambda row: CommonSimNameUtils.get_full_name(CommonSimUtils.get_sim_info(row.sim_id)))) - return self._show( - on_chosen=on_chosen, - sim_info=sim_info, - should_show_names=should_show_names, - hide_row_descriptions=hide_row_descriptions, - column_count=column_count - ) - except Exception as ex: - self.log.error('show', exception=ex) - - def _show( - self, - on_chosen: Callable[[Any, CommonChoiceOutcome], Any]=CommonFunctionUtils.noop, - sim_info: SimInfo=None, - should_show_names: bool=True, - hide_row_descriptions: bool=False, - column_count: int=3 - ): - _dialog = self.build_dialog( - on_chosen=on_chosen, - sim_info=sim_info, - should_show_names=should_show_names, - hide_row_descriptions=hide_row_descriptions, - column_count=column_count - ) - self.log.debug('Showing dialog.') - _dialog.show_dialog() - - # noinspection PyMissingOrEmptyDocstring - def build_dialog( - self, - on_chosen: Callable[[Any, CommonChoiceOutcome], bool]=CommonFunctionUtils.noop, - sim_info: SimInfo=None, - should_show_names: bool=True, - hide_row_descriptions: bool=False, - column_count: int=3 - ) -> Union[UiSimPicker, None]: - self.log.format_with_message('Attempting to display choices.') - _dialog = self._create_dialog( - sim_info=sim_info, - should_show_names=should_show_names, - hide_row_descriptions=hide_row_descriptions, - column_count=column_count - ) - if _dialog is None: - self.log.error('_dialog was None for some reason.') - return - - if on_chosen is None: - raise AssertionError('\'on_chosen\' was None.') - - if len(self.rows) == 0: - raise AssertionError('No rows have been provided. Add rows to the dialog before attempting to display it.') - - def _on_chosen(dialog: UiSimPicker) -> bool: - try: - if not dialog.accepted: - self.log.debug('Dialog cancelled.') - return on_chosen(None, CommonChoiceOutcome.CANCEL) - choice = CommonDialogUtils.get_chosen_item(dialog) - self.log.format_with_message('Choice made.', choice=choice) - result = on_chosen(choice, CommonChoiceOutcome.CHOICE_MADE) - self.log.format_with_message('Finished handling choice.', result=result) - return result - except Exception as ex: - self.log.error('Error occurred on choosing a value.', exception=ex) - return False - - self.log.debug('Adding all choices') - for row in self.rows: - _dialog.add_row(row) - - _dialog.add_listener(_on_chosen) - return _dialog - - def _create_dialog( - self, - sim_info: SimInfo=None, - should_show_names: bool=True, - hide_row_descriptions: bool=False, - column_count: int=3, - min_selectable: int=1, - max_selectable: int=1 - ) -> Union[UiSimPicker, None]: - if column_count < 3: - raise AttributeError('\'column_count\' must be at least 3 columns.') - if column_count > 8: - raise AttributeError('\'column_count\' can be no more than 8 columns.') - try: - return UiSimPicker.TunableFactory().default( - sim_info or CommonSimUtils.get_active_sim_info(), - title=lambda *_, **__: self.title, - text=lambda *_, **__: self.description, - min_selectable=min_selectable, - max_selectable=max_selectable, - should_show_names=should_show_names, - hide_row_description=hide_row_descriptions, - column_count=column_count - ) - except Exception as ex: - self.log.error('_create_dialog', exception=ex) - return None - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_testing.show_choose_sim_dialog', - 'Show an example of CommonChooseSimDialog.' -) -def _common_testing_show_choose_sim_dialog(output: CommonConsoleCommandOutput): - output('Showing test choose sim dialog.') - - def _on_chosen(choice: Union[SimInfo, None], outcome: CommonChoiceOutcome): - output('Chose {} with result: {}.'.format(CommonSimNameUtils.get_full_name(choice), pformat(outcome))) - - # 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),) - current_count = 0 - count = 25 - options = [] - for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): - if current_count >= count: - break - sim_id = CommonSimUtils.get_sim_id(sim_info) - should_select = random.choice((True, False)) - is_enabled = random.choice((True, False)) - options.append( - SimPickerRow( - sim_id, - select_default=should_select, - tag=sim_info, - is_enable=is_enabled - ) - ) - current_count += 1 - - dialog = CommonChooseSimDialog( - 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_chosen=_on_chosen, column_count=5) - output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_choose_sims_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/common_choose_sims_dialog.py deleted file mode 100644 index 722e797..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/common_choose_sims_dialog.py +++ /dev/null @@ -1,309 +0,0 @@ -""" -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 -""" -from typing import Any, Callable, Union, Tuple, Iterator - -from pprint import pformat - -import random - -from protocolbuffers.Localization_pb2 import LocalizedString -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome -from s4ap.sims4communitylib.dialogs.common_choose_sim_dialog import CommonChooseSimDialog -from s4ap.sims4communitylib.dialogs.option_dialogs.options.sims.common_dialog_sim_option import CommonDialogSimOption -from s4ap.sims4communitylib.dialogs.utils.common_dialog_utils import CommonDialogUtils -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from ui.ui_dialog_picker import UiSimPicker, SimPickerRow - - -class CommonChooseSimsDialog(CommonChooseSimDialog): - """CommonChooseSimsDialog(\ - title_identifier,\ - description_identifier,\ - choices,\ - title_tokens=(),\ - description_tokens=(),\ - mod_identity=None,\ - required_tooltip=None,\ - required_tooltip_tokens=()\ - ) - - Create a dialog that prompts the player to choose a number of Sims. - - .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_choose_sims_dialog` in the in-game console. - - .. highlight:: python - .. code-block:: python - - def _common_testing_show_choose_sims_dialog(): - - def _on_chosen(choice: Union[Tuple[SimInfo], None], outcome: CommonChoiceOutcome): - 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 s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils - current_count = 0 - count = 25 - options = [] - for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): - if current_count >= count: - break - sim_id = CommonSimUtils.get_sim_id(sim_info) - is_enabled = random.choice((True, False)) - options.append( - SimPickerRow( - sim_id, - select_default=False, - tag=sim_info, - is_enable=is_enabled - ) - ) - current_count += 1 - - dialog = CommonChooseSimsDialog( - 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_chosen=_on_chosen, - column_count=5, - min_selectable=2, - max_selectable=6 - ) - - :param title_identifier: A decimal identifier of the title text. - :type title_identifier: Union[int, str, LocalizedString, CommonStringId] - :param description_identifier: A decimal identifier of the description text. - :type description_identifier: Union[int, str, LocalizedString, CommonStringId] - :param choices: The choices to display in the dialog. - :type choices: Iterator[SimPickerRow] - :param title_tokens: Tokens to format into the title. - :type title_tokens: Iterator[Any], optional - :param description_tokens: Tokens to format into the description. - :type description_tokens: Iterator[Any], optional - :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. - :type mod_identity: CommonModIdentity, optional - :param required_tooltip: If provided, this text will display when the dialog requires at least one choice and a choice has not been made. Default is None. - :type required_tooltip: Union[int, str, LocalizedString, CommonStringId], optional - :param required_tooltip_tokens: Tokens to format into the required tooltip. Default is an empty collection. - :type required_tooltip_tokens: Iterator[Any], optional - """ - def __init__( - self, - title_identifier: Union[int, str, LocalizedString, CommonStringId], - description_identifier: Union[int, str, LocalizedString, CommonStringId], - choices: Iterator[SimPickerRow], - title_tokens: Iterator[Any]=(), - description_tokens: Iterator[Any]=(), - mod_identity: CommonModIdentity=None, - required_tooltip: Union[int, str, LocalizedString, CommonStringId]=None, - required_tooltip_tokens: Iterator[Any]=() - ): - super().__init__( - title_identifier, - description_identifier, - choices, - title_tokens=title_tokens, - description_tokens=description_tokens, - mod_identity=mod_identity, - required_tooltip=required_tooltip, - required_tooltip_tokens=required_tooltip_tokens - ) - - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - return 's4cl_choose_sims_dialog' - - def show( - self, - on_chosen: Callable[[Union[Tuple[Any], None], CommonChoiceOutcome], Any]=CommonFunctionUtils.noop, - sim_info: SimInfo=None, - should_show_names: bool=True, - hide_row_descriptions: bool=False, - column_count: int=3, - min_selectable: int=1, - max_selectable: int=1 - ): - """show(\ - on_chosen=CommonFunctionUtils.noop,\ - sim_info=None,\ - should_show_names=True,\ - hide_row_descriptions=False,\ - column_count=3,\ - min_selectable=1,\ - max_selectable=1\ - ) - - Show the dialog and invoke the callbacks upon the player submitting their selection. - - :param on_chosen: A callback invoked upon the player submitting their chosen Sims from the list. Default is CommonFunctionUtils.noop. - :type on_chosen: Callable[[Union[Tuple[Any], None], CommonChoiceOutcome], Any], optional - :param sim_info: The SimInfo of the Sim that will appear in the dialog image. The default Sim is the active Sim. Default is None. - :type sim_info: SimInfo, optional - :param should_show_names: If True, then the names of the Sims will display in the dialog. Default is True. - :type should_show_names: bool, optional - :param hide_row_descriptions: A flag to hide the row descriptions. Default is False. - :type hide_row_descriptions: bool, optional - :param column_count: The number of columns to display Sims in. Default is 3. - :type column_count: int, optional - :param min_selectable: The minimum number of Sims that must be chosen. Default is 1. - :type min_selectable: int, optional - :param max_selectable: The maximum number of Sims that can be chosen. Default is 1. - :type max_selectable: int, optional - :exception AssertionError: When something is wrong with the arguments or no rows were added to the dialog. - :exception AttributeError: When Min or Max Selectable are invalid. - """ - try: - self._rows = tuple(sorted(self._rows, key=lambda row: CommonSimNameUtils.get_full_name(CommonSimUtils.get_sim_info(row.sim_id)))) - return self._show( - on_chosen=on_chosen, - sim_info=sim_info, - should_show_names=should_show_names, - hide_row_descriptions=hide_row_descriptions, - column_count=column_count, - min_selectable=min_selectable, - max_selectable=max_selectable - ) - except Exception as ex: - self.log.error('show', exception=ex) - - def _show( - self, - on_chosen: Callable[[Union[Tuple[CommonDialogSimOption], None], CommonChoiceOutcome], Any]=CommonFunctionUtils.noop, - sim_info: SimInfo=None, - should_show_names: bool=True, - hide_row_descriptions: bool=False, - column_count: int=3, - min_selectable: int=1, - max_selectable: int=1 - ): - _dialog = self.build_dialog( - on_chosen=on_chosen, - sim_info=sim_info, - should_show_names=should_show_names, - hide_row_descriptions=hide_row_descriptions, - column_count=column_count, - min_selectable=min_selectable, - max_selectable=max_selectable - ) - self.log.debug('Showing dialog.') - _dialog.show_dialog() - - # noinspection PyMissingOrEmptyDocstring - def build_dialog( - self, - on_chosen: Callable[[Union[Tuple[CommonDialogSimOption], None], CommonChoiceOutcome], Any]=CommonFunctionUtils.noop, - sim_info: SimInfo=None, - should_show_names: bool=True, - hide_row_descriptions: bool=False, - column_count: int=3, - min_selectable: int=1, - max_selectable: int=1 - ): - if min_selectable < 1: - raise AttributeError('\'min_selectable\' must be at least 1.') - if max_selectable < min_selectable: - raise AttributeError('\'max_selectable\' must be greater than \'min_selectable\'.') - self.log.format_with_message('Attempting to display Sims choices.') - _dialog = self._create_dialog( - sim_info=sim_info, - should_show_names=should_show_names, - hide_row_descriptions=hide_row_descriptions, - column_count=column_count, - min_selectable=min_selectable, - max_selectable=max_selectable - ) - if _dialog is None: - self.log.error('_dialog was None for some reason.') - return - - if on_chosen is None: - raise AssertionError('on_chosen was None.') - - if len(self.rows) == 0: - raise AssertionError('No rows have been provided. Add rows to the dialog before attempting to display it.') - - def _on_chosen(dialog: UiSimPicker): - if not dialog.accepted: - self.log.debug('Dialog cancelled.') - return on_chosen(None, CommonChoiceOutcome.CANCEL) - choices = tuple(CommonDialogUtils.get_chosen_items(dialog)) - self.log.format_with_message('Choice made.', choice=choices) - result = on_chosen(choices, CommonChoiceOutcome.CHOICE_MADE) - self.log.format_with_message('Finished handling choice.', result=result) - return result - - self.log.debug('Adding all choices') - for row in self.rows: - _dialog.add_row(row) - - _dialog.add_listener(_on_chosen) - return _dialog - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_testing.show_choose_sims_dialog', - 'Show an example of CommonChooseSimsDialog.' -) -def _common_testing_show_choose_sims_dialog(output: CommonConsoleCommandOutput): - output('Showing test choose sims dialog.') - - def _on_chosen(choice: Union[Tuple[SimInfo], None], outcome: CommonChoiceOutcome): - output('Chose {} with result: {}.'.format(CommonSimNameUtils.get_full_names(choice), pformat(outcome))) - - # 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),) - current_count = 0 - count = 25 - options = [] - for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): - if current_count >= count: - break - sim_id = CommonSimUtils.get_sim_id(sim_info) - is_enabled = random.choice((True, False)) - options.append( - SimPickerRow( - sim_id, - select_default=False, - tag=sim_info, - is_enable=is_enabled - ) - ) - current_count += 1 - - dialog = CommonChooseSimsDialog( - 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_chosen=_on_chosen, - column_count=5, - min_selectable=2, - max_selectable=6 - ) - output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/common_dialog.py deleted file mode 100644 index ce74a44..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/common_dialog.py +++ /dev/null @@ -1,92 +0,0 @@ -""" -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 -""" -from typing import Any, Union, Iterator -from protocolbuffers.Localization_pb2 import LocalizedString -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.logging.has_log import HasLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from ui.ui_dialog import UiDialogBase - - -class CommonDialog(HasLog): - """CommonDialog(\ - title_identifier,\ - description_identifier,\ - title_tokens=(),\ - description_tokens=(),\ - mod_identity=None\ - ) - - An inheritable class for creating a dialog. - - .. note:: It is recommended to utilize one of the ready made dialogs, instead of creating a custom :class:`CommonDialog` - - :param title_identifier: The title to display in the dialog. - :type title_identifier: Union[int, str, LocalizedString, CommonStringId] - :param description_identifier: The description to display in the dialog. - :type description_identifier: Union[int, str, LocalizedString, CommonStringId] - :param title_tokens: Tokens to format into the title. Default is an empty collection. - :type title_tokens: Iterator[Any], optional - :param description_tokens: Tokens to format into the description. Default is an empty collection. - :type description_tokens: Iterator[Any], optional - :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. Default is None. - :type mod_identity: CommonModIdentity, optional - """ - - def __init__( - self, - title_identifier: Union[int, str, LocalizedString, CommonStringId], - description_identifier: Union[int, str, LocalizedString, CommonStringId], - title_tokens: Iterator[Any]=(), - description_tokens: Iterator[Any]=(), - mod_identity: CommonModIdentity=None - ): - super().__init__() - self.title = CommonLocalizationUtils.create_localized_string(title_identifier, tokens=tuple(title_tokens)) - self.description = CommonLocalizationUtils.create_localized_string(description_identifier, tokens=tuple(description_tokens)) - self._mod_identity = mod_identity - - # noinspection PyMissingOrEmptyDocstring - @property - def mod_identity(self) -> CommonModIdentity: - return self._mod_identity - - def show(self, *_: Any, **__: Any): - """show(*_, **__) - - Display the dialog to the player. - - .. note:: Override this method with any arguments you want to. - - """ - raise NotImplementedError('\'{}\' not implemented.'.format(self.__class__.show.__name__)) - - def build_dialog(self, *_: Any, **__: Any) -> Union[UiDialogBase, None]: - """build_dialog(*_, **__) - - Build the dialog. - - .. note:: Override this method with any arguments you want to. - - :return: The built dialog or None if a problem occurs. - :rtype: Union[UiDialogBase, None] - """ - return self._create_dialog(*_, **__) - - def _create_dialog(self, *_: Any, **__: Any) -> Union[UiDialogBase, None]: - """_create_dialog(*_, **__) - - Create a dialog for use in :func:``show`. - - .. note:: Override this method with any arguments you want to. - - :return: An instance of the dialog being shown or None if a problem occurs. - :rtype: Union[UiDialogBase, None] - """ - raise NotImplementedError('\'{}\' not implemented.'.format(self.__class__._create_dialog.__name__)) diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_dialog_navigation_button_tag.py b/Scripts/s4ap/sims4communitylib/dialogs/common_dialog_navigation_button_tag.py deleted file mode 100644 index cbdc265..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/common_dialog_navigation_button_tag.py +++ /dev/null @@ -1,13 +0,0 @@ -""" -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 -""" - - -class CommonDialogNavigationButtonTag: - """ Tags applied to the navigation buttons of a dialog. """ - PREVIOUS = 'S4CL_PREVIOUS' - NEXT = 'S4CL_NEXT' diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_input_float_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/common_input_float_dialog.py deleted file mode 100644 index 74edfeb..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/common_input_float_dialog.py +++ /dev/null @@ -1,216 +0,0 @@ -""" -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 -""" -from typing import Any, Callable, Union, Iterator - -from pprint import pformat -from protocolbuffers.Localization_pb2 import LocalizedString -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.dialogs._common_ui_dialog_text_input_ok_cancel import _CommonUiDialogTextInputOkCancel -from s4ap.sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome -from s4ap.sims4communitylib.dialogs.common_dialog import CommonDialog -from s4ap.sims4communitylib.dialogs.utils.common_dialog_utils import CommonDialogUtils -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from ui.ui_dialog_generic import UiDialogTextInput -from s4ap.sims4communitylib.modinfo import ModInfo - - -class CommonInputFloatDialog(CommonDialog): - """CommonInputFloatDialog(\ - title_identifier,\ - description_identifier,\ - initial_value,\ - min_value=0.0,\ - max_value=2147483647.0,\ - title_tokens=(),\ - description_tokens=(),\ - mod_identity=None\ - ) - - Create a dialog that prompts the player to enter a float value. - - .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_input_float_dialog` in the in-game console. - - .. highlight:: python - .. code-block:: python - - def _common_testing_show_input_float_dialog(): - - def _on_submit(input_value: float, outcome: CommonChoiceOutcome): - 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 s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils - dialog = CommonInputFloatDialog( - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - 2.0, - title_tokens=title_tokens, - description_tokens=description_tokens - ) - dialog.show(on_submit=_on_submit) - - :param title_identifier: A decimal identifier of the title text. - :type title_identifier: Union[int, str, LocalizedString, CommonStringId] - :param description_identifier: A decimal identifier of the description text. - :type description_identifier: Union[int, str, LocalizedString, CommonStringId] - :param initial_value: The initial value that will appear in the input box. - :type initial_value: float - :param min_value: The minimum value allowed to be entered by the player. Default is 0.0 - :type min_value: float, optional - :param max_value: The maximum value allowed to be entered by the player. Default is Max Int. - :type max_value: float, optional - :param title_tokens: Tokens to format into the title. - :type title_tokens: Iterator[Any], optional - :param description_tokens: Tokens to format into the description. - :type description_tokens: Iterator[Any], optional - :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. - :type mod_identity: CommonModIdentity, optional - """ - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - return 's4cl_input_float_dialog' - - def __init__( - self, - title_identifier: Union[int, str, LocalizedString, CommonStringId], - description_identifier: Union[int, str, LocalizedString, CommonStringId], - initial_value: float, - min_value: float=0.0, - max_value: float=2147483647.0, - title_tokens: Iterator[Any]=(), - description_tokens: Iterator[Any]=(), - mod_identity: CommonModIdentity=None - ): - super().__init__( - title_identifier, - description_identifier, - title_tokens=title_tokens, - description_tokens=description_tokens, - mod_identity=mod_identity - ) - self.initial_value = initial_value - self.min_value = min_value - self.max_value = max_value - - def show( - self, - sim_info: SimInfo=None, - on_submit: Callable[[Union[float, None], CommonChoiceOutcome], Any]=CommonFunctionUtils.noop - ): - """show(\ - sim_info=None,\ - on_submit=CommonFunctionUtils.noop\ - ) - - Show the dialog and invoke the callbacks upon the player submitting a value. - - :param sim_info: The Sim that owns the dialog. Set to None to use the Active Sim. Default is None. - :type sim_info: SimInfo, optional - :param on_submit: A callback invoked upon the player submitting a value. Default is CommonFunctionUtils.noop. - :type on_submit: Callable[[Union[float, None], CommonChoiceOutcome], Any], optional - """ - try: - return self._show( - sim_info=sim_info, - on_submit=on_submit - ) - except Exception as ex: - self.log.error('show', exception=ex) - - def _show( - self, - sim_info: SimInfo=None, - on_submit: Callable[[Union[float, None], CommonChoiceOutcome], bool]=CommonFunctionUtils.noop - ): - self.log.debug('Attempting to display input float dialog.') - - if on_submit is None: - raise ValueError('\'on_submit\' was None.') - - _dialog = self._create_dialog(sim_info=sim_info) - if _dialog is None: - self.log.error('_dialog was None for some reason.') - return - - # noinspection PyBroadException - def _on_submit(dialog: UiDialogTextInput) -> bool: - try: - input_value = CommonDialogUtils.get_input_value(dialog) - if not input_value or not dialog.accepted: - self.log.debug('Dialog cancelled.') - return on_submit(None, CommonChoiceOutcome.CANCEL) - self.log.format_with_message('Value entered, attempting to convert it to a float.', value=input_value) - - try: - input_value = float(input_value) - self.log.debug('Conversion successful.') - input_value = max(self.min_value, input_value) - input_value = min(self.max_value, input_value) - except: - self.log.format_with_message('Failed to convert value', value=input_value) - return on_submit(None, CommonChoiceOutcome.ERROR) - - self.log.format_with_message('Value entered.', input_value=input_value) - result = on_submit(input_value, CommonChoiceOutcome.CHOICE_MADE) - self.log.format_with_message('Finished handling input.', result=result) - return result - except Exception as ex: - self.log.error('Error occurred on submitting a value.', exception=ex) - return False - - _dialog.add_listener(_on_submit) - if self.initial_value is not None: - _dialog.show_dialog(additional_tokens=(self.initial_value,)) - else: - _dialog.show_dialog() - - def _create_dialog(self, sim_info: SimInfo=None) -> Union[_CommonUiDialogTextInputOkCancel, None]: - try: - return _CommonUiDialogTextInputOkCancel.TunableFactory().default( - sim_info or CommonSimUtils.get_active_sim_info(), - text=lambda *_, **__: self.description, - title=lambda *_, **__: self.title - ) - except Exception as ex: - self.log.error('_create_dialog', exception=ex) - return None - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_testing.show_input_float_dialog', - 'Show an example of CommonInputFloatDialog.' -) -def _common_testing_show_input_float_dialog(output: CommonConsoleCommandOutput): - output('Showing test input float dialog.') - - def _on_submit(input_value: float, outcome: CommonChoiceOutcome): - output('Input {} with result: {}.'.format(pformat(input_value), pformat(outcome))) - - # 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),) - dialog = CommonInputFloatDialog( - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - 2.0, - title_tokens=title_tokens, - description_tokens=description_tokens - ) - dialog.show(on_submit=_on_submit) - output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_input_integer_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/common_input_integer_dialog.py deleted file mode 100644 index 9cf5931..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/common_input_integer_dialog.py +++ /dev/null @@ -1,216 +0,0 @@ -""" -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 -""" -from typing import Any, Callable, Union, Iterator - -from pprint import pformat -from protocolbuffers.Localization_pb2 import LocalizedString -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.dialogs._common_ui_dialog_text_input_ok_cancel import _CommonUiDialogTextInputOkCancel -from s4ap.sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome -from s4ap.sims4communitylib.dialogs.common_dialog import CommonDialog -from s4ap.sims4communitylib.dialogs.utils.common_dialog_utils import CommonDialogUtils -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from ui.ui_dialog_generic import UiDialogTextInput -from s4ap.sims4communitylib.modinfo import ModInfo - - -class CommonInputIntegerDialog(CommonDialog): - """CommonInputIntegerDialog(\ - title_identifier,\ - description_identifier,\ - initial_value,\ - min_value=0,\ - max_value=2147483647,\ - title_tokens=(),\ - description_tokens=(),\ - mod_identity=None\ - ) - - Create a dialog that prompts the player to enter an integer value. - - .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_input_integer_dialog` in the in-game console. - - .. highlight:: python - .. code-block:: python - - def _common_testing_show_input_integer_dialog(): - - def _on_submit(input_value: integer, outcome: CommonChoiceOutcome): - 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 s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils - dialog = CommonInputIntegerDialog( - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - 2, - title_tokens=title_tokens, - description_tokens=description_tokens - ) - dialog.show(on_submit=_on_submit) - - :param title_identifier: A decimal identifier of the title text. - :type title_identifier: Union[int, str, LocalizedString, CommonStringId] - :param description_identifier: A decimal identifier of the description text. - :type description_identifier: Union[int, str, LocalizedString, CommonStringId] - :param initial_value: The initial value that will appear in the input box. - :type initial_value: int - :param min_value: The minimum value allowed to be entered by the player. Default is 0.0 - :type min_value: int, optional - :param max_value: The maximum value allowed to be entered by the player. Default is Max Int. - :type max_value: int, optional - :param title_tokens: Tokens to format into the title. - :type title_tokens: Iterator[Any], optional - :param description_tokens: Tokens to format into the description. - :type description_tokens: Iterator[Any], optional - :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. - :type mod_identity: CommonModIdentity, optional - """ - def __init__( - self, - title_identifier: Union[int, str, LocalizedString, CommonStringId], - description_identifier: Union[int, str, LocalizedString, CommonStringId], - initial_value: int, - min_value: int=0, - max_value: int=2147483647, - title_tokens: Iterator[Any]=(), - description_tokens: Iterator[Any]=(), - mod_identity: CommonModIdentity=None - ): - super().__init__( - title_identifier, - description_identifier, - title_tokens=title_tokens, - description_tokens=description_tokens, - mod_identity=mod_identity - ) - self.initial_value = initial_value - self.min_value = min_value - self.max_value = max_value - - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - return 's4cl_input_integer_dialog' - - def show( - self, - sim_info: SimInfo=None, - on_submit: Callable[[Union[int, None], CommonChoiceOutcome], Any]=CommonFunctionUtils.noop - ): - """show(\ - sim_info=None,\ - on_submit=CommonFunctionUtils.noop\ - ) - - Show the dialog and invoke the callbacks upon the player submitting a value. - - :param sim_info: The Sim that owns the dialog. Set to None to use the Active Sim. Default is None. - :type sim_info: SimInfo, optional - :param on_submit: A callback invoked upon the player submitting a value. Default is CommonFunctionUtils.noop. - :type on_submit: Callable[[Union[int, None], CommonChoiceOutcome], Any], optional - """ - try: - return self._show( - sim_info=sim_info, - on_submit=on_submit - ) - except Exception as ex: - self.log.error('show', exception=ex) - - def _show( - self, - sim_info: SimInfo=None, - on_submit: Callable[[Union[int, None], CommonChoiceOutcome], bool]=CommonFunctionUtils.noop - ): - self.log.debug('Attempting to display input integer dialog.') - - if on_submit is None: - raise ValueError('\'on_submit\' was None.') - - _dialog = self._create_dialog(sim_info=sim_info) - if _dialog is None: - self.log.error('_dialog was None for some reason.') - return - - # noinspection PyBroadException - def _on_submit(dialog: UiDialogTextInput) -> bool: - try: - input_value = CommonDialogUtils.get_input_value(dialog) - if not input_value or not dialog.accepted: - self.log.debug('Dialog cancelled.') - return on_submit(None, CommonChoiceOutcome.CANCEL) - self.log.format_with_message('Value entered, attempting to convert it to an integer.', value=input_value) - - try: - input_value = int(input_value) - self.log.debug('Conversion successful.') - input_value = max(self.min_value, input_value) - input_value = min(self.max_value, input_value) - except: - self.log.format_with_message('Failed to convert value', value=input_value) - return on_submit(None, CommonChoiceOutcome.ERROR) - - self.log.format_with_message('Value entered.', input_value=input_value) - result = on_submit(input_value, CommonChoiceOutcome.CHOICE_MADE) - self.log.format_with_message('Finished handling input.', result=result) - return result - except Exception as ex: - self.log.error('Error occurred on submitting a value.', exception=ex) - return False - - _dialog.add_listener(_on_submit) - if self.initial_value is not None: - _dialog.show_dialog(additional_tokens=(self.initial_value,)) - else: - _dialog.show_dialog() - - def _create_dialog(self, sim_info: SimInfo=None) -> Union[_CommonUiDialogTextInputOkCancel, None]: - try: - return _CommonUiDialogTextInputOkCancel.TunableFactory().default( - sim_info or CommonSimUtils.get_active_sim_info(), - text=lambda *_, **__: self.description, - title=lambda *_, **__: self.title - ) - except Exception as ex: - self.log.error('_create_dialog', exception=ex) - return None - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_testing.show_input_integer_dialog', - 'Show an example of CommonInputIntegerDialog.' -) -def _common_testing_show_input_integer_dialog(output: CommonConsoleCommandOutput): - output('Showing test input integer dialog.') - - def _on_submit(input_value: int, outcome: CommonChoiceOutcome): - output('Input {} with result: {}.'.format(pformat(input_value), pformat(outcome))) - - # 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),) - dialog = CommonInputIntegerDialog( - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - 2, - title_tokens=title_tokens, - description_tokens=description_tokens - ) - dialog.show(on_submit=_on_submit) - output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_input_multi_text_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/common_input_multi_text_dialog.py deleted file mode 100644 index 23b0c17..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/common_input_multi_text_dialog.py +++ /dev/null @@ -1,209 +0,0 @@ -""" -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 -""" -from typing import Any, Callable, Union, Iterator, Dict - -from pprint import pformat -from protocolbuffers.Localization_pb2 import LocalizedString -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.dialogs._common_ui_dialog_multi_text_input_ok_cancel import _CommonUiDialogMultiTextInputOkCancel -from s4ap.sims4communitylib.dialogs._common_ui_dialog_text_input_ok_cancel import _CommonUiDialogTextInputOkCancel -from s4ap.sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome -from s4ap.sims4communitylib.dialogs.common_dialog import CommonDialog -from s4ap.sims4communitylib.dialogs.common_input_text_field import CommonInputTextField -from s4ap.sims4communitylib.enums.common_character_restrictions import CommonCharacterRestriction -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from ui.ui_dialog_generic import UiDialogTextInput - - -class CommonInputMultiTextDialog(CommonDialog): - """CommonInputMultiTextDialog(\ - mod_identity,\ - title_identifier,\ - description_identifier,\ - input_fields,\ - title_tokens=(),\ - description_tokens=()\ - ) - - Create a dialog that prompts the player to enter a text value. - - .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_input_multi_text_dialog` in the in-game console. - - .. highlight:: python - .. code-block:: python - - def _common_testing_show_input_text_dialog(): - - def _on_submit(input_value: str, outcome: CommonChoiceOutcome): - 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 s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils - dialog = CommonInputMultiTextDialog( - ModInfo.get_identity(), - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - ( - CommonInputTextField('first_input_field', 'initial_text', title='First Input', default_text='default text stuff'), - CommonInputTextField('input_box_two', 'initial_text_two', default_text=CommonStringId.TESTING_TEST_TEXT_NO_TOKENS), - CommonInputTextField('input_box_three', 'initial_text_three', title='Numbers Only', character_restriction=CommonCharacterRestriction.NUMBERS_ONLY) - ), - title_tokens=title_tokens, - description_tokens=description_tokens - ) - dialog.show(on_submit=_on_submit) - - :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. - :type mod_identity: CommonModIdentity - :param title_identifier: A decimal identifier of the title text. - :type title_identifier: Union[int, str, LocalizedString, CommonStringId] - :param description_identifier: A decimal identifier of the description text. - :type description_identifier: Union[int, str, LocalizedString, CommonStringId] - :param input_fields: An iterator of input fields to display in the dialog. - :type input_fields: Iterator[CommonInputTextField] - :param title_tokens: Tokens to format into the title. - :type title_tokens: Iterator[Any], optional - :param description_tokens: Tokens to format into the description. - :type description_tokens: Iterator[Any], optional - """ - def __init__( - self, - mod_identity: CommonModIdentity, - title_identifier: Union[int, str, LocalizedString, CommonStringId], - description_identifier: Union[int, str, LocalizedString, CommonStringId], - input_fields: Iterator[CommonInputTextField], - title_tokens: Iterator[Any] = (), - description_tokens: Iterator[Any] = () - ): - super().__init__( - title_identifier, - description_identifier, - title_tokens=title_tokens, - description_tokens=description_tokens, - mod_identity=mod_identity - ) - self.input_fields = input_fields - - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - return 's4cl_input_text_dialog' - - def show( - self, - sim_info: SimInfo = None, - on_submit: Callable[[Dict[str, str], CommonChoiceOutcome], Any] = CommonFunctionUtils.noop - ) -> None: - """show(\ - sim_info=None,\ - on_submit=CommonFunctionUtils.noop\ - ) - - Show the dialog and invoke the callbacks upon the player submitting a value. - - :param sim_info: The Sim that owns the dialog. Set to None to use the Active Sim. Default is None. - :type sim_info: SimInfo, optional - :param on_submit: A callback invoked upon the player submitting a value. Default is CommonFunctionUtils.noop. - :type on_submit: Callable[[Union[str, None], CommonChoiceOutcome], Any], optional - """ - try: - return self._show( - sim_info=sim_info, - on_submit=on_submit - ) - except Exception as ex: - self.log.error('show', exception=ex) - - def _show( - self, - sim_info: SimInfo = None, - on_submit: Callable[[Dict[str, str], CommonChoiceOutcome], bool] = CommonFunctionUtils.noop - ) -> None: - self.log.debug('Attempting to display input text dialog.') - - if on_submit is None: - raise ValueError('\'on_submit\' was None.') - - _dialog = self._create_dialog(sim_info=sim_info) - if _dialog is None: - self.log.error('_dialog was None for some reason.') - return - - # noinspection PyBroadException - def _on_submit(dialog: UiDialogTextInput) -> None: - try: - input_values = dict(dialog.text_input_responses) - if not input_values or not dialog.accepted: - self.log.debug('Dialog cancelled.') - on_submit(dict(), CommonChoiceOutcome.CANCEL) - return - self.log.format_with_message('Values entered.', input_values=input_values) - result = on_submit(input_values, CommonChoiceOutcome.CHOICE_MADE) - self.log.format_with_message('Finished handling input.', result=result) - except Exception as ex: - self.log.error('Error occurred on submitting values.', exception=ex) - - _dialog.add_listener(_on_submit) - if self.input_fields is not None: - _dialog.show_dialog(additional_tokens=tuple([input_field.initial_value for input_field in self.input_fields])) - else: - _dialog.show_dialog() - - def _create_dialog(self, sim_info: SimInfo = None) -> Union[_CommonUiDialogTextInputOkCancel, None]: - try: - return _CommonUiDialogMultiTextInputOkCancel.TunableFactory().default( - sim_info or CommonSimUtils.get_active_sim_info(), - self.input_fields, - text=lambda *_, **__: self.description, - title=lambda *_, **__: self.title - ) - except Exception as ex: - self.log.error('_create_dialog', exception=ex) - return None - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_testing.show_input_multi_text_dialog', - 'Show an example of CommonInputMultiTextDialog.' -) -def _common_testing_show_input_multi_text_dialog(output: CommonConsoleCommandOutput): - output('Showing test input multi text dialog.') - - def _on_chosen(input_values: Dict[str, str], outcome: CommonChoiceOutcome): - for (input_name, input_value) in input_values.items(): - output('Input {} Value {} with result: {}.'.format(pformat(input_name), pformat(input_value), pformat(outcome))) - output('Done printing inputs.') - - # 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),) - dialog = CommonInputMultiTextDialog( - ModInfo.get_identity(), - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - ( - CommonInputTextField('first_input_field', 'initial_text', title='First Input', default_text='default text stuff'), - CommonInputTextField('input_box_two', 'initial_text_two', default_text=CommonStringId.TESTING_TEST_TEXT_NO_TOKENS), - CommonInputTextField('input_box_three', 'initial_text_three', title='Numbers Only', character_restriction=CommonCharacterRestriction.NUMBERS_ONLY) - ), - title_tokens=title_tokens, - description_tokens=description_tokens - ) - dialog.show(on_submit=_on_chosen) - output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_input_text_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/common_input_text_dialog.py deleted file mode 100644 index 9d20a2c..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/common_input_text_dialog.py +++ /dev/null @@ -1,196 +0,0 @@ -""" -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 -""" -from typing import Any, Callable, Union, Iterator - -from pprint import pformat -from protocolbuffers.Localization_pb2 import LocalizedString -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.dialogs._common_ui_dialog_text_input_ok_cancel import _CommonUiDialogTextInputOkCancel -from s4ap.sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome -from s4ap.sims4communitylib.dialogs.common_dialog import CommonDialog -from s4ap.sims4communitylib.dialogs.utils.common_dialog_utils import CommonDialogUtils -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from ui.ui_dialog_generic import UiDialogTextInput - - -class CommonInputTextDialog(CommonDialog): - """CommonInputTextDialog(\ - mod_identity,\ - title_identifier,\ - description_identifier,\ - initial_value,\ - title_tokens=(),\ - description_tokens=()\ - ) - - Create a dialog that prompts the player to enter a text value. - - .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_input_text_dialog` in the in-game console. - - .. highlight:: python - .. code-block:: python - - def _common_testing_show_input_text_dialog(): - - def _on_submit(input_value: str, outcome: CommonChoiceOutcome): - 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 s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils - dialog = CommonInputTextDialog( - ModInfo.get_identity(), - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - 'default_text', - title_tokens=title_tokens, - description_tokens=description_tokens - ) - dialog.show(on_submit=_on_submit) - - :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. - :type mod_identity: CommonModIdentity - :param title_identifier: A decimal identifier of the title text. - :type title_identifier: Union[int, str, LocalizedString, CommonStringId] - :param description_identifier: A decimal identifier of the description text. - :type description_identifier: Union[int, str, LocalizedString, CommonStringId] - :param initial_value: The initial value that will appear in the input box. - :type initial_value: str - :param title_tokens: Tokens to format into the title. - :type title_tokens: Iterator[Any], optional - :param description_tokens: Tokens to format into the description. - :type description_tokens: Iterator[Any], optional - """ - def __init__( - self, - mod_identity: CommonModIdentity, - title_identifier: Union[int, str, LocalizedString, CommonStringId], - description_identifier: Union[int, str, LocalizedString, CommonStringId], - initial_value: str, - title_tokens: Iterator[Any]=(), - description_tokens: Iterator[Any]=() - ): - super().__init__( - title_identifier, - description_identifier, - title_tokens=title_tokens, - description_tokens=description_tokens, - mod_identity=mod_identity - ) - self.initial_value = initial_value - - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - return 's4cl_input_text_dialog' - - def show( - self, - sim_info: SimInfo=None, - on_submit: Callable[[Union[str, None], CommonChoiceOutcome], Any]=CommonFunctionUtils.noop - ) -> None: - """show(\ - sim_info=None,\ - on_submit=CommonFunctionUtils.noop\ - ) - - Show the dialog and invoke the callbacks upon the player submitting a value. - - :param sim_info: The Sim that owns the dialog. Set to None to use the Active Sim. Default is None. - :type sim_info: SimInfo, optional - :param on_submit: A callback invoked upon the player submitting a value. Default is CommonFunctionUtils.noop. - :type on_submit: Callable[[Union[str, None], CommonChoiceOutcome], Any], optional - """ - try: - return self._show( - sim_info=sim_info, - on_submit=on_submit - ) - except Exception as ex: - self.log.error('show', exception=ex) - - def _show( - self, - sim_info: SimInfo=None, - on_submit: Callable[[Union[str, None], CommonChoiceOutcome], bool]=CommonFunctionUtils.noop - ) -> None: - self.log.debug('Attempting to display input text dialog.') - - if on_submit is None: - raise ValueError('\'on_submit\' was None.') - - _dialog = self._create_dialog(sim_info=sim_info) - if _dialog is None: - self.log.error('_dialog was None for some reason.') - return - - # noinspection PyBroadException - def _on_submit(dialog: UiDialogTextInput) -> None: - try: - input_value = CommonDialogUtils.get_input_value(dialog) - if not input_value or not dialog.accepted: - self.log.debug('Dialog cancelled.') - on_submit(None, CommonChoiceOutcome.CANCEL) - return - self.log.format_with_message('Value entered.', input_value=input_value) - result = on_submit(input_value, CommonChoiceOutcome.CHOICE_MADE) - self.log.format_with_message('Finished handling input.', result=result) - except Exception as ex: - self.log.error('Error occurred on submitting a value.', exception=ex) - - _dialog.add_listener(_on_submit) - if self.initial_value is not None: - _dialog.show_dialog(additional_tokens=(self.initial_value,)) - else: - _dialog.show_dialog() - - def _create_dialog(self, sim_info: SimInfo=None) -> Union[_CommonUiDialogTextInputOkCancel, None]: - try: - return _CommonUiDialogTextInputOkCancel.TunableFactory().default( - sim_info or CommonSimUtils.get_active_sim_info(), - text=lambda *_, **__: self.description, - title=lambda *_, **__: self.title - ) - except Exception as ex: - self.log.error('_create_dialog', exception=ex) - return None - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_testing.show_input_text_dialog', - 'Show an example of CommonInputTextDialog.' -) -def _common_testing_show_input_text_dialog(output: CommonConsoleCommandOutput): - output('Showing test input text dialog.') - - def _on_chosen(input_value: str, outcome: CommonChoiceOutcome): - output('Input {} with result: {}.'.format(pformat(input_value), pformat(outcome))) - - # 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),) - dialog = CommonInputTextDialog( - ModInfo.get_identity(), - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - 'default_text', - title_tokens=title_tokens, - description_tokens=description_tokens - ) - dialog.show(on_submit=_on_chosen) - output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_input_text_field.py b/Scripts/s4ap/sims4communitylib/dialogs/common_input_text_field.py deleted file mode 100644 index 4f4cbe2..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/common_input_text_field.py +++ /dev/null @@ -1,94 +0,0 @@ -""" -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 -""" -from typing import Union - -from protocolbuffers.Localization_pb2 import LocalizedString -from s4ap.sims4communitylib.enums.common_character_restrictions import CommonCharacterRestriction -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.utils.localization.common_localized_string_separators import CommonLocalizedStringSeparator - - -class CommonInputTextField: - """CommonInputTextField(\ - identifier,\ - initial_value,\ - title=None,\ - character_restriction=CommonCharacterRestriction.NONE,\ - default_text=None\ - ) - - A field intended for use with an input text dialog. It allows entering of text. - - :param identifier: The identifier of the input. - :type identifier: str - :param initial_value: The initial value of the text input. - :type initial_value: str - :param title: A title to display above the input. Default is None. - :type title: Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator], optional - :param character_restriction: A character restriction to enforce what can be entered or not. Default is NONE. - :type character_restriction: CommonCharacterRestriction, optional - :param default_text: The default text shown when nothing is entered into the field. Default is None. - :type default_text: Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator], optional - """ - def __init__( - self, - identifier: str, - initial_value: str, - title: Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator, None] = None, - character_restriction: CommonCharacterRestriction = CommonCharacterRestriction.NONE, - default_text: Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator, None] = None - ): - self._identifier = identifier - self._initial_value = initial_value - self._title = title - self._character_restriction = character_restriction - self._default_text = default_text - - # 'default_text', - # 'height', - # 'initial_value', - # 'input_invalid_max_tooltip', - # 'input_invalid_min_tooltip', - # 'input_too_short_tooltip', - # 'max_length', - # 'max_value', - # 'message_descriptor', - # 'min_length', - # 'min_value', - # 'restricted_characters', - # 'text_input_name', - # 'title' - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - return 's4cl_input_text_dialog' - - @property - def identifier(self) -> str: - """The identifier of the input.""" - return self._identifier - - @property - def initial_value(self) -> str: - """The initial value the field will have entered.""" - return self._initial_value - - @property - def default_text(self) -> Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator, None]: - """The default text that will show in the field when nothing is entered.""" - return self._default_text - - @property - def title(self) -> Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator, None]: - """The title to display above the text field.""" - return self._title - - @property - def character_restriction(self) -> CommonCharacterRestriction: - """A character restriction to enforce what can be entered or not.""" - return self._character_restriction diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_multi_pane_choose_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/common_multi_pane_choose_dialog.py deleted file mode 100644 index 1a9a36d..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/common_multi_pane_choose_dialog.py +++ /dev/null @@ -1,431 +0,0 @@ -""" -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 -""" -from pprint import pformat - -from typing import Tuple, Any, Callable, Union, Iterator, List, Dict -from protocolbuffers.Localization_pb2 import LocalizedString -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.dialogs.choose_object_dialog import CommonChooseObjectDialog -from s4ap.sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome -from s4ap.sims4communitylib.dialogs.common_choose_dialog import CommonChooseDialog -from s4ap.sims4communitylib.dialogs.common_dialog import CommonDialog -from s4ap.sims4communitylib.dialogs.custom_dialogs.picker_dialogs.common_ui_multi_picker import CommonUiMultiPicker -from s4ap.sims4communitylib.dialogs.utils.common_dialog_utils import CommonDialogUtils -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from ui.ui_dialog import UiDialogBase -from ui.ui_dialog_picker import ObjectPickerRow - - -class CommonMultiPaneChooseDialog(CommonDialog): - """CommonMultiPaneChooseDialog(\ - mod_identity,\ - title_identifier,\ - description_identifier,\ - title_tokens=(),\ - description_tokens=()\ - ) - - Create a multi-pane dialog that prompts the player to choose from multiple dialogs and submit their choices. - - .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_multi_pane_choose_dialog` in the in-game console. - - .. warning:: This dialog does not currently work with `CommonChooseSimDialog` or `CommonChooseSimsDialog`. - - .. highlight:: python - .. code-block:: python - - def _common_testing_show_multi_pane_choose_dialog(): - - def _on_submit(choices_made: Tuple[Any], outcome: CommonChoiceOutcome) -> None: - pass - - def _on_sub_dialog_one_chosen(choice: Any, outcome: CommonChoiceOutcome) -> None: - pass - - def _on_sub_dialog_two_chosen(choice: Any, outcome: CommonChoiceOutcome) -> None: - 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 s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils - # Create the dialog. - dialog = CommonMultiPaneChooseDialog( - ModInfo.get_identity(), - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - title_tokens=title_tokens, - description_tokens=description_tokens - ) - - sub_dialog_one_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' - ) - ] - - # Add sub dialog one. - sub_dialog_one = CommonChooseObjectDialog( - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - tuple(sub_dialog_one_options), - title_tokens=title_tokens, - description_tokens=description_tokens - ) - dialog.add_sub_dialog(sub_dialog_one, on_chosen=_on_sub_dialog_one_chosen) - - # Add sub dialog two. - sub_dialog_two_options = [ - ObjectPickerRow( - option_id=4, - name=CommonLocalizationUtils.create_localized_string('Value 4'), - row_description=CommonLocalizationUtils.create_localized_string(CommonStringId.TESTING_TEST_BUTTON_ONE), - row_tooltip=None, - icon=CommonIconUtils.load_checked_square_icon(), - tag='Value 4' - ), - ObjectPickerRow( - option_id=5, - name=CommonLocalizationUtils.create_localized_string('Value 5'), - row_description=CommonLocalizationUtils.create_localized_string(CommonStringId.TESTING_TEST_BUTTON_TWO), - row_tooltip=None, - icon=CommonIconUtils.load_arrow_navigate_into_icon(), - tag='Value 5' - ), - ObjectPickerRow( - option_id=6, - name=CommonLocalizationUtils.create_localized_string('Value 6'), - row_description=CommonLocalizationUtils.create_localized_string(CommonStringId.TESTING_TEST_BUTTON_TWO), - row_tooltip=None, - icon=CommonIconUtils.load_arrow_navigate_into_icon(), - tag='Value 6' - ) - ] - - sub_dialog_two = CommonChooseObjectDialog( - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - tuple(sub_dialog_two_options), - title_tokens=title_tokens, - description_tokens=description_tokens - ) - - dialog.add_sub_dialog(sub_dialog_two, on_chosen=_on_sub_dialog_two_chosen) - - # Show the dialog. - dialog.show(on_submit=_on_submit) - - :param title_identifier: The title to display in the dialog. - :type title_identifier: Union[int, str, LocalizedString, CommonStringId] - :param description_identifier: The description to display in the dialog. - :type description_identifier: Union[int, str, LocalizedString, CommonStringId] - :param title_tokens: Tokens to format into the title. - :type title_tokens: Iterator[Any], optional - :param description_tokens: Tokens to format into the description. - :type description_tokens: Iterator[Any], optional - :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. - :type mod_identity: CommonModIdentity, optional - """ - def __init__( - self, - mod_identity: CommonModIdentity, - title_identifier: Union[int, str, LocalizedString, CommonStringId], - description_identifier: Union[int, str, LocalizedString, CommonStringId], - title_tokens: Iterator[Any]=(), - description_tokens: Iterator[Any]=(), - ): - super().__init__( - title_identifier, - description_identifier, - title_tokens=title_tokens, - description_tokens=description_tokens, - mod_identity=mod_identity - ) - self._sub_dialogs: Tuple[Tuple[CommonChooseDialog, Tuple[Any], Dict[str, Any]]] = tuple() - - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - return 's4cl_multi_pane_choose_dialog' - - def add_sub_dialog(self, sub_dialog: CommonChooseDialog, *dialog_arguments: Any, **dialog_keyword_arguments: Any): - """add_sub_dialog(sub_dialog, *dialog_arguments, **dialog_keyword_arguments) - - Add a sub dialog to the dialog. - - :param sub_dialog: An instance of a choose dialog. - :type sub_dialog: CommonChooseDialog - :param dialog_arguments: Arguments to pass to the sub dialog when building it. - :type dialog_arguments: Any - :param dialog_keyword_arguments: Keyword arguments to pass to the sub dialog when building it. - :type dialog_keyword_arguments: Any - """ - self._sub_dialogs += ((sub_dialog, dialog_arguments, dialog_keyword_arguments), ) - - def show( - self, - on_submit: Callable[[Dict[int, Tuple[Any]], CommonChoiceOutcome], Any]=CommonFunctionUtils.noop, - sim_info: SimInfo=None - ): - """show(\ - on_submit=CommonFunctionUtils.noop,\ - sim_info=None\ - ) - - Show the dialog and invoke the callbacks upon the player making a choice. - - :param on_submit: A callback invoked upon the player submitting the dialog and the choices within it.\ - Default is CommonFunctionUtils.noop. Each choice is mapped as follows The key is the dialog index starting at 0. The value is the choice made within that sub dialog. - :type on_submit: Callable[[Dict[int, Tuple[Any]], CommonChoiceOutcome], Any], optional - :param sim_info: The Sim that will appear in the dialog image. The default Sim is the Active Sim. Default is None. - :type sim_info: SimInfo, optional - """ - try: - return self._show( - on_submit=on_submit, - sim_info=sim_info - ) - except Exception as ex: - self.log.error('An error occurred while running \'{}\''.format(CommonMultiPaneChooseDialog.show.__name__), exception=ex) - - def _show( - self, - on_submit: Callable[[Dict[int, Tuple[Any]], CommonChoiceOutcome], Any]=CommonFunctionUtils.noop, - sim_info: SimInfo=None - ): - self.log.debug('Attempting to display multi choose dialog.') - dialog = self.build_dialog( - on_submit=on_submit, - sim_info=sim_info - ) - dialog.show_dialog() - - # noinspection PyMissingOrEmptyDocstring - def build_dialog( - self, - on_submit: Callable[[Dict[int, Tuple[Any]], CommonChoiceOutcome], bool]=CommonFunctionUtils.noop, - sim_info: SimInfo=None - ): - dialog = self._create_dialog(sim_info=sim_info) - if dialog is None: - self.log.error('dialog was None for some reason.') - return - - if on_submit is None: - raise AssertionError('on_submit was None.') - - if len(self._sub_dialogs) == 0: - raise AssertionError('No dialogs have been added to the container. Add dialogs before attempting to display the multi pane dialog.') - - def _on_submit(_dialog: CommonUiMultiPicker) -> bool: - try: - if not _dialog.accepted: - self.log.debug('Dialog cancelled.') - return on_submit(dict(), CommonChoiceOutcome.CANCEL) - self.log.debug('Choices made, combining choices.') - index = 0 - dialog_choices: Dict[int, Tuple[Any]] = dict() - for _sub_dialog_submit_id in _dialog._picker_dialogs: - _sub_dialog_submit = _dialog._picker_dialogs[_sub_dialog_submit_id] - sub_dialog_choices: List[Any] = list() - for choice in CommonDialogUtils.get_chosen_items(_sub_dialog_submit): - sub_dialog_choices.append(choice) - dialog_choices[index] = tuple(sub_dialog_choices) - index += 1 - if not dialog_choices: - self.log.debug('No choices made. Cancelling dialog.') - return on_submit(dict(), CommonChoiceOutcome.CANCEL) - - self.log.format_with_message('Choices were made, submitting.', choice=dialog_choices) - result = on_submit(dialog_choices, CommonChoiceOutcome.CHOICE_MADE) - self.log.format_with_message('Finished handling choice.', result=result) - return result - except Exception as ex: - self.log.error('Error occurred on submitting a value.', exception=ex) - return False - - for (sub_dialog, sub_dialog_arguments, sub_dialog_keyword_arguments) in self._sub_dialogs: - sub_dialog: CommonChooseDialog = sub_dialog - # noinspection PyBroadException - try: - # Delete to prevent duplicate keyword arguments. - if 'include_pagination' in sub_dialog_keyword_arguments: - del sub_dialog_keyword_arguments['include_pagination'] - - _sub_dialog: UiDialogBase = sub_dialog.build_dialog( - *sub_dialog_arguments, - include_pagination=False, - **sub_dialog_keyword_arguments - ) - except: - _sub_dialog: UiDialogBase = sub_dialog.build_dialog( - *sub_dialog_arguments, - **sub_dialog_keyword_arguments - ) - if _sub_dialog is None: - continue - dialog.required_tooltips[_sub_dialog.dialog_id] = sub_dialog.required_tooltip - dialog._picker_dialogs[_sub_dialog.dialog_id] = _sub_dialog - - self.log.debug('Showing dialog.') - dialog.add_listener(_on_submit) - return dialog - - def _create_dialog(self, sim_info: SimInfo=None) -> Union[CommonUiMultiPicker, None]: - try: - return CommonUiMultiPicker.TunableFactory().default( - sim_info or CommonSimUtils.get_active_sim_info(), - text=lambda *args, **kwargs: self.description, - title=lambda *args, **kwargs: self.title, - text_input=None, - pickers=() - ) - except Exception as ex: - self.log.error('multi_pane_choose._create_dialog', exception=ex) - return None - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_testing.show_multi_pane_choose_dialog', - 'Show an example of CommonMultiPaneChooseDialog.' -) -def _common_testing_show_multi_pane_choose_dialog(output: CommonConsoleCommandOutput): - output('Showing test multi-pane choose dialog.') - - def _on_submit(choices_made: Dict[int, Any], outcome: CommonChoiceOutcome) -> None: - output('On Submit choices_made: {} and outcome: {}'.format(pformat(choices_made), pformat(outcome))) - - def _on_sub_dialog_one_chosen(choice: Any, outcome: CommonChoiceOutcome) -> None: - output('Sub Dialog one choice made: {} outcome: {}'.format(pformat(choice), pformat(outcome))) - - def _on_sub_dialog_two_chosen(choice: Any, outcome: CommonChoiceOutcome) -> None: - output('Sub Dialog two choice made: {} outcome: {}'.format(pformat(choice), pformat(outcome))) - - sim_info = CommonSimUtils.get_active_sim_info() - - # 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 s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils - # Create the dialog. - dialog = CommonMultiPaneChooseDialog( - ModInfo.get_identity(), - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - title_tokens=title_tokens, - description_tokens=description_tokens - ) - - sub_dialog_one_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' - ) - ] - - # Add sub dialog one. - sub_dialog_one = CommonChooseObjectDialog( - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - tuple(sub_dialog_one_options), - title_tokens=title_tokens, - description_tokens=description_tokens - ) - dialog.add_sub_dialog(sub_dialog_one, on_chosen=_on_sub_dialog_one_chosen, sim_info=sim_info) - - # Add sub dialog two. - sub_dialog_two_options = [ - ObjectPickerRow( - option_id=4, - name=CommonLocalizationUtils.create_localized_string('Value 4'), - row_description=CommonLocalizationUtils.create_localized_string(CommonStringId.TESTING_TEST_BUTTON_ONE), - row_tooltip=None, - icon=CommonIconUtils.load_checked_square_icon(), - tag='Value 4' - ), - ObjectPickerRow( - option_id=5, - name=CommonLocalizationUtils.create_localized_string('Value 5'), - row_description=CommonLocalizationUtils.create_localized_string(CommonStringId.TESTING_TEST_BUTTON_TWO), - row_tooltip=None, - icon=CommonIconUtils.load_arrow_navigate_into_icon(), - tag='Value 5' - ), - ObjectPickerRow( - option_id=6, - name=CommonLocalizationUtils.create_localized_string('Value 6'), - row_description=CommonLocalizationUtils.create_localized_string(CommonStringId.TESTING_TEST_BUTTON_TWO), - row_tooltip=None, - icon=CommonIconUtils.load_arrow_navigate_into_icon(), - tag='Value 6' - ) - ] - - sub_dialog_two = CommonChooseObjectDialog( - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - tuple(sub_dialog_two_options), - title_tokens=title_tokens, - description_tokens=description_tokens - ) - - dialog.add_sub_dialog(sub_dialog_two, on_chosen=_on_sub_dialog_two_chosen, include_pagination=True) - - # Show the dialog. - dialog.show(on_submit=_on_submit) - output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_ok_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/common_ok_dialog.py deleted file mode 100644 index e2f4a13..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/common_ok_dialog.py +++ /dev/null @@ -1,174 +0,0 @@ -""" -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 -""" -from typing import Any, Callable, Union, Iterator - -from protocolbuffers.Localization_pb2 import LocalizedString -from s4ap.sims4communitylib.dialogs.common_dialog import CommonDialog -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from ui.ui_dialog import UiDialogOk - - -class CommonOkDialog(CommonDialog): - """CommonOkDialog(\ - title_identifier,\ - description_identifier,\ - title_tokens=(),\ - description_tokens=(),\ - ok_text_identifier=CommonStringId.OK,\ - ok_text_tokens=(), - mod_identity=None\ - ) - - Use to create an acknowledgement dialog. - - .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_ok_dialog` in the in-game console. - - .. highlight:: python - .. code-block:: python - - def _common_testing_show_ok_dialog(): - - def _on_acknowledged(_dialog: UiDialogOk): - if _dialog.accepted: - pass - else: - 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),) - dialog = CommonOkDialog( - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - title_tokens=title_tokens, - description_tokens=description_tokens, - ok_text_identifier=CommonLocalizationUtils.create_localized_string(CommonStringId.TESTING_TEST_BUTTON_ONE, text_color=CommonLocalizedStringColor.RED) - ) - dialog.show(on_acknowledged=_on_acknowledged) - - - :param title_identifier: A decimal identifier of the title text. - :type title_identifier: Union[int, str, LocalizedString, CommonStringId] - :param description_identifier: A decimal identifier of the description text. - :type description_identifier: Union[int, str, LocalizedString, CommonStringId] - :param title_tokens: Tokens to format into the title. - :type title_tokens: Iterator[Any], optional - :param description_tokens: Tokens to format into the description. - :type description_tokens: Iterator[Any], optional - :param ok_text_identifier: A decimal identifier for the Ok button text. - :type ok_text_identifier: Union[int, str, LocalizedString, CommonStringId], optional - :param ok_text_tokens: Tokens to format into the Ok button text. - :type ok_text_tokens: Iterator[Any], optional - :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. - :type mod_identity: CommonModIdentity, optional - """ - def __init__( - self, - title_identifier: Union[int, str, LocalizedString, CommonStringId], - description_identifier: Union[int, str, LocalizedString, CommonStringId], - title_tokens: Iterator[Any]=(), - description_tokens: Iterator[Any]=(), - ok_text_identifier: Union[int, str, LocalizedString, CommonStringId]=CommonStringId.OK, - ok_text_tokens: Iterator[Any]=(), - mod_identity: CommonModIdentity=None - ): - super().__init__( - title_identifier, - description_identifier, - title_tokens=title_tokens, - description_tokens=description_tokens, - mod_identity=mod_identity - ) - self.ok_text = CommonLocalizationUtils.create_localized_string(ok_text_identifier, tokens=tuple(ok_text_tokens)) - - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - return 's4cl_ok_dialog' - - def show( - self, - on_acknowledged: Callable[[UiDialogOk], Any]=CommonFunctionUtils.noop - ): - """show(\ - on_acknowledged=CommonFunctionUtils.noop\ - ) - - Show the dialog and invoke the callback upon the player acknowledging the dialog. - - :param on_acknowledged: Invoked upon the player acknowledging (Hitting Ok) or closing the dialog. - :type on_acknowledged: Callable[[UiDialogOk], Any], optional - """ - try: - return self._show( - on_acknowledged=on_acknowledged - ) - except Exception as ex: - self.log.error('show', exception=ex) - - def _show( - self, - on_acknowledged: Callable[[UiDialogOk], Any]=CommonFunctionUtils.noop - ): - self.log.format_with_message('Attempting to display dialog.') - _dialog = self._create_dialog() - if _dialog is None: - self.log.debug('Failed to create dialog.') - return - - _dialog.add_listener(on_acknowledged) - self.log.debug('Displaying dialog.') - _dialog.show_dialog() - - def _create_dialog(self) -> Union[UiDialogOk, None]: - try: - return UiDialogOk.TunableFactory().default( - CommonSimUtils.get_active_sim_info(), - text=lambda *_, **__: self.description, - title=lambda *_, **__: self.title, - text_ok=lambda *_, **__: self.ok_text - ) - except Exception as ex: - self.log.error('_create_dialog', exception=ex) - return None - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_testing.show_ok_dialog', - 'Show an example of CommonPurchaseObjectsDialog.' -) -def _common_testing_show_ok_dialog(output: CommonConsoleCommandOutput): - output('Showing test ok dialog.') - - def _on_acknowledged(_dialog: UiDialogOk): - if _dialog.accepted: - output('Ok option chosen.') - else: - output('Dialog closed.') - - # 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),) - dialog = CommonOkDialog( - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - title_tokens=title_tokens, - description_tokens=description_tokens, - ok_text_identifier=CommonLocalizationUtils.create_localized_string(CommonStringId.TESTING_TEST_BUTTON_ONE, text_color=CommonLocalizedStringColor.RED) - ) - dialog.show(on_acknowledged=_on_acknowledged) - output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_purchase_objects_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/common_purchase_objects_dialog.py deleted file mode 100644 index 173f289..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/common_purchase_objects_dialog.py +++ /dev/null @@ -1,393 +0,0 @@ -""" -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 -""" -from collections import namedtuple - -from typing import Tuple, Any, Callable, Union, Iterator, List - -from pprint import pformat - -from interactions.base.picker_interaction import PurchasePickerData -from protocolbuffers.Localization_pb2 import LocalizedString -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome -from s4ap.sims4communitylib.dialogs.common_choose_dialog import CommonChooseDialog -from s4ap.sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_option_category import \ - CommonDialogObjectOptionCategory -from s4ap.sims4communitylib.enums.common_object_delivery_method import CommonObjectDeliveryMethod -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.enums.tags_enum import CommonGameTag -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils -from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils -from s4ap.sims4communitylib.utils.sims.common_sim_inventory_utils import CommonSimInventoryUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from ui.ui_dialog_picker import UiObjectPicker, UiPurchasePicker, PurchasePickerRow, UiDialogObjectPicker - - -class CommonPurchaseObjectsDialog(CommonChooseDialog): - """CommonPurchaseObjectsDialog(\ - mod_identity,\ - title_identifier,\ - description_identifier,\ - purchasable_object_rows,\ - title_tokens=(),\ - description_tokens=(),\ - required_tooltip=None,\ - required_tooltip_tokens=()\ - ) - - Create a dialog that allows the player to purchase some objects. - - .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_purchase_objects_dialog` in the in-game console. - - .. highlight:: python - .. code-block:: python - - def _common_testing_show_purchase_objects_dialog(): - def _on_chosen(choices: Any, outcome: CommonChoiceOutcome): - output('Chose {} with result: {}.'.format(pformat(choices), pformat(outcome))) - - # 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),) - show_discount = True - from s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils - active_sim_info = CommonSimUtils.get_active_sim_info() - obj_id = 20359 - obj_definition = CommonObjectUtils.get_object_definition(obj_id) - tags = obj_definition.build_buy_tags - options = [ - PurchasePickerRow( - def_id=obj_definition.id, - num_owned=CommonSimInventoryUtils.get_count_of_object_in_inventory(active_sim_info, obj_id), - tags=obj_definition.build_buy_tags, - num_available=2000, - custom_price=50, - objects=tuple(), - show_discount=show_discount, - icon_info_data_override=None, # Should be an instance of IconInfoData - is_enable=True, - row_tooltip=None, - row_description=None - ), - ] - categories = list() - for tag in tags: - tag_name = CommonGameTag.value_to_name.get(tag, None) - if tag_name is None: - continue - categories.append(CommonDialogObjectOptionCategory(tag, obj_definition.icon, category_name=tag_name)) - dialog = CommonPurchaseObjectsDialog( - ModInfo.get_identity(), - 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_chosen=_on_chosen, categories=categories) - - :param title_identifier: The title to display in the dialog. - :type title_identifier: Union[int, str, LocalizedString, CommonStringId] - :param description_identifier: The description to display in the dialog. - :type description_identifier: Union[int, str, LocalizedString, CommonStringId] - :param purchasable_objects: The objects that may be purchased - :type purchasable_objects: Iterator[PurchasePickerRow] - :param title_tokens: Tokens to format into the title. - :type title_tokens: Iterator[Any], optional - :param description_tokens: Tokens to format into the description. - :type description_tokens: Iterator[Any], optional - :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. - :type mod_identity: CommonModIdentity, optional - :param required_tooltip: If provided, this text will display when the dialog requires at least one choice and a choice has not been made. Default is None. - :type required_tooltip: Union[int, str, LocalizedString, CommonStringId], optional - :param required_tooltip_tokens: Tokens to format into the required tooltip. Default is an empty collection. - :type required_tooltip_tokens: Iterator[Any], optional - """ - def __init__( - self, - mod_identity: CommonModIdentity, - title_identifier: Union[int, str, LocalizedString, CommonStringId], - description_identifier: Union[int, str, LocalizedString, CommonStringId], - purchasable_objects: Iterator[PurchasePickerRow], - title_tokens: Iterator[Any] = (), - description_tokens: Iterator[Any] = (), - required_tooltip: Union[int, str, LocalizedString, CommonStringId] = None, - required_tooltip_tokens: Iterator[Any] = () - ): - super().__init__( - title_identifier, - description_identifier, - purchasable_objects, - title_tokens=title_tokens, - description_tokens=description_tokens, - mod_identity=mod_identity, - required_tooltip=required_tooltip, - required_tooltip_tokens=required_tooltip_tokens - ) - - # noinspection PyMissingOrEmptyDocstring - @property - def rows(self) -> Tuple[PurchasePickerRow]: - # noinspection PyTypeChecker - result: Tuple[PurchasePickerRow] = super().rows - return result - - # noinspection PyMissingOrEmptyDocstring - def add_row(self, choice: PurchasePickerRow, *_, **__): - """add_row(row, *_, **__) - - Add a row to the dialog. - - :param choice: The row to add. - :type choice: PurchasePickerRow - """ - super().add_row(choice, *_, **__) - - def show( - self, - on_chosen: Callable[[Any, CommonChoiceOutcome], Any] = CommonFunctionUtils.noop, - target_sim_info_to_receive_objects: SimInfo = None, - categories: Iterator[CommonDialogObjectOptionCategory] = (), - object_delivery_method: CommonObjectDeliveryMethod = CommonObjectDeliveryMethod.INVENTORY - ): - """show(\ - on_chosen=CommonFunctionUtils.noop,\ - target_sim_info_to_receive_objects=None,\ - categories=(),\ - object_delivery_method=CommonObjectDeliveryMethod.INVENTORY,\ - ) - - Show the dialog and invoke the callbacks upon the player making a choice. - - :param on_chosen: A callback invoked upon the player choosing something from the list. Default is CommonFunctionUtils.noop. - :type on_chosen: Callable[[Any, CommonChoiceOutcome], optional - :param target_sim_info_to_receive_objects: The Sim that will appear in the dialog image. They will also be the receiver of purchased objects if object_delivery_method is set to INVENTORY. The default Sim is the Active Sim. Default is None. - :type target_sim_info_to_receive_objects: SimInfo, optional - :param categories: A collection of categories to display in the dialog. They will appear in a drop down above the rows. Default is an empty collection. - :type categories: Iterator[CommonDialogObjectOptionCategory], optional - :param object_delivery_method: The method of delivery for purchased objects. If set to INVENTORY, objects that are purchased will be immediately available within the inventory of the specified Sim or the Active Sim if no Sim is specified.\ - If set to MAIL, objects that are purchased will be delivered via the Mail Man. They may also appear within the Household Inventory upon the mail being delivered. Default is INVENTORY. - :type object_delivery_method: CommonObjectDeliveryMethod, optional - """ - try: - if object_delivery_method is CommonObjectDeliveryMethod.NONE: - raise AssertionError('object_delivery_method was set to NONE.') - return self._show( - on_chosen=on_chosen, - target_sim_info_to_receive_objects=target_sim_info_to_receive_objects, - categories=categories, - object_delivery_method=object_delivery_method - ) - except Exception as ex: - self.log.error('An error occurred while running \'{}\''.format(CommonPurchaseObjectsDialog.show.__name__), exception=ex) - - def _show( - self, - on_chosen: Callable[[Any, CommonChoiceOutcome], bool] = CommonFunctionUtils.noop, - target_sim_info_to_receive_objects: SimInfo = None, - categories: Iterator[CommonDialogObjectOptionCategory] = (), - object_delivery_method: CommonObjectDeliveryMethod = CommonObjectDeliveryMethod.INVENTORY - ): - def _on_chosen(choice: Any, outcome: CommonChoiceOutcome) -> bool: - try: - self.log.debug('Choice made.') - self.log.format_with_message('Choose Object Choice made.', choice=choice) - result = on_chosen(choice, outcome) - self.log.format_with_message('Finished handling choose object _show.', result=result) - return result - except Exception as ex: - self.log.error('Error occurred on choosing a value.', exception=ex) - return False - - _dialog = self.build_dialog( - on_chosen=_on_chosen, - target_sim_info_to_receive_objects=target_sim_info_to_receive_objects, - categories=categories, - object_delivery_method=object_delivery_method - ) - if not _dialog: - raise AssertionError('Failed to create the purchase objects dialog.') - self.log.debug('Showing dialog.') - _dialog.show_dialog() - - # noinspection PyMissingOrEmptyDocstring - def build_dialog( - self, - on_chosen: Callable[[Any, CommonChoiceOutcome], bool] = CommonFunctionUtils.noop, - target_sim_info_to_receive_objects: SimInfo = None, - categories: Iterator[CommonDialogObjectOptionCategory] = (), - object_delivery_method: CommonObjectDeliveryMethod = CommonObjectDeliveryMethod.INVENTORY - ) -> Union[UiPurchasePicker, None]: - self.log.format_with_message('Attempting to build dialog.', categories=categories) - - _dialog = self._create_dialog( - categories=categories, - target_sim_info_to_receive_objects=target_sim_info_to_receive_objects, - object_delivery_method=object_delivery_method - ) - if _dialog is None: - self.log.error('_dialog was None for some reason.') - return - - if on_chosen is None: - raise ValueError('on_chosen was None.') - - if len(self.rows) == 0: - raise AssertionError('No rows have been provided. Add rows to the dialog before attempting to display it.') - - def _on_chosen(dialog: UiPurchasePicker) -> bool: - try: - self.log.format_with_message('Choice made.', picked_results=dialog.picked_results) - if not dialog.accepted: - self.log.debug('Dialog cancelled.') - return on_chosen(None, CommonChoiceOutcome.CANCEL) - self.log.debug('Dialog accepted, checking if choices were made.') - choices = dialog.get_result_definitions_and_counts() - zipped_choices = zip(choices[0], choices[1]) - self.log.format_with_message('Purchase Objects choice made.', choice=zipped_choices) - outcome = CommonChoiceOutcome.CHOICE_MADE - if not choices: - outcome = CommonChoiceOutcome.CANCEL - result = on_chosen(zipped_choices, outcome) - self.log.format_with_message('Finished handling purchase objects _on_chosen.', result=result) - return result - except Exception as ex: - self.log.error('Error occurred on choosing a value.', exception=ex) - return False - - self._setup_dialog_rows( - _dialog - ) - - self.log.debug('Adding listener.') - _dialog.add_listener(_on_chosen) - return _dialog - - def _setup_dialog_rows( - self, - _dialog: UiPurchasePicker - ): - self.log.debug('Adding rows.') - for row in self.rows: - _dialog.add_row(row) - - def _create_dialog( - self, - picker_type: UiObjectPicker.UiObjectPickerObjectPickerType = UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT, - target_sim_info_to_receive_objects: SimInfo = None, - categories: Iterator[CommonDialogObjectOptionCategory] = (), - object_delivery_method: CommonObjectDeliveryMethod = CommonObjectDeliveryMethod.INVENTORY - ) -> Union[UiPurchasePicker, None]: - try: - category_type = namedtuple('category_type', ('tag', 'icon', 'tooltip')) - dialog_categories = list() - for category in tuple(categories): - dialog_categories.append( - category_type( - category.object_category, - CommonIconUtils._load_icon(category.icon), - CommonLocalizationUtils.create_localized_string(category.category_name) - ) - ) - - target_to_receive_sim_info = target_sim_info_to_receive_objects or CommonSimUtils.get_active_sim_info() - inventory_target_id = CommonSimUtils.get_sim_id(target_to_receive_sim_info) - purchase_objects: List[int] = list() - dialog = UiPurchasePicker.TunableFactory().default( - target_to_receive_sim_info, - text=lambda *_, **__: self.description, - title=lambda *_, **__: self.title, - categories=dialog_categories, - max_selectable=UiDialogObjectPicker._MaxSelectableUnlimited() - ) - purchase_picker_data = PurchasePickerData() - if object_delivery_method == CommonObjectDeliveryMethod.INVENTORY: - purchase_picker_data.inventory_owner_id_to_purchase_to = inventory_target_id - if object_delivery_method == CommonObjectDeliveryMethod.MAIL: - purchase_picker_data.delivery_method = CommonObjectDeliveryMethod.convert_to_vanilla(object_delivery_method) - if object_delivery_method == CommonObjectDeliveryMethod.DELIVERY_SERVICE: - purchase_picker_data.delivery_method = CommonObjectDeliveryMethod.convert_to_vanilla(object_delivery_method) - for purchase_object in purchase_objects: - purchase_picker_data.add_definition_to_purchase(purchase_object) - dialog.set_target_sim(CommonSimUtils.get_sim_instance(target_to_receive_sim_info)) - dialog.object_id = purchase_picker_data.inventory_owner_id_to_purchase_to - dialog.inventory_object_id = purchase_picker_data.inventory_owner_id_to_purchase_from - dialog.purchase_by_object_ids = purchase_picker_data.use_obj_ids_in_response - dialog.delivery_method = purchase_picker_data.delivery_method - dialog.show_description = 1 - dialog.show_description_tooltip = 1 - dialog.use_dialog_pick_response = True - dialog.max_selectable_num = len(self.rows) - dialog.use_dropdown_filter = len(dialog_categories) > 0 - right_custom_text = None - if right_custom_text is not None: - dialog.right_custom_text = right_custom_text - return dialog - except Exception as ex: - self.log.error('_create_dialog', exception=ex) - return None - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_testing.show_purchase_objects_dialog', - 'Show an example of CommonPurchaseObjectsDialog.' -) -def _common_testing_show_purchase_objects_dialog(output: CommonConsoleCommandOutput): - output('Showing test purchase object dialog.') - - def _on_chosen(choices: str, outcome: CommonChoiceOutcome): - output('Chose {} with result: {}.'.format(pformat(choices), pformat(outcome))) - - # 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),) - show_discount = True - active_sim_info = CommonSimUtils.get_active_sim_info() - obj_id = 20359 - obj_definition = CommonObjectUtils.get_object_definition(obj_id) - tags = obj_definition.build_buy_tags - options = [ - PurchasePickerRow( - def_id=obj_definition.id, - num_owned=CommonSimInventoryUtils.get_count_of_object_in_inventory(active_sim_info, obj_id), - tags=obj_definition.build_buy_tags, - num_available=2000, - custom_price=50, - objects=tuple(), - show_discount=show_discount, - icon_info_data_override=None, # Should be an instance of IconInfoData - is_enable=True, - row_tooltip=None, - row_description=None - ), - ] - categories = list() - for tag in tags: - tag_name = CommonGameTag.value_to_name.get(tag, None) - if tag_name is None: - continue - categories.append(CommonDialogObjectOptionCategory(tag, obj_definition.icon, category_name=tag_name)) - dialog = CommonPurchaseObjectsDialog( - ModInfo.get_identity(), - 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.log.enable() - dialog.show(on_chosen=_on_chosen, categories=categories) - output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_targeted_question_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/common_targeted_question_dialog.py deleted file mode 100644 index e4a860a..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/common_targeted_question_dialog.py +++ /dev/null @@ -1,223 +0,0 @@ -""" -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 -""" -from typing import Any, Callable, Union, Iterator - -from event_testing.resolver import DoubleSimResolver -from protocolbuffers.Localization_pb2 import LocalizedString -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.dialogs.common_dialog import CommonDialog -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from ui.ui_dialog import UiDialogOkCancel - - -class CommonTargetedQuestionDialog(CommonDialog): - """CommonTargetedQuestionDialog(\ - question_text,\ - question_tokens=(),\ - ok_text_identifier=CommonStringId.OK,\ - ok_text_tokens=(),\ - cancel_text_identifier=CommonStringId.CANCEL,\ - cancel_text_tokens=(),\ - mod_identity=None\ - ) - - A Sim to Sim question dialog. - - .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_targeted_question_dialog` in the in-game console. - - .. highlight:: python - .. code-block:: python - - def _common_testing_show_targeted_question_dialog(): - - def _ok_chosen(_: UiDialogOkCancel): - pass - - def _cancel_chosen(_: UiDialogOkCancel): - pass - - # LocalizedStrings within other LocalizedStrings - 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),) - dialog = CommonTargetedQuestionDialog( - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - question_tokens=description_tokens, - ok_text_identifier=CommonLocalizationUtils.create_localized_string(CommonStringId.TESTING_TEST_BUTTON_ONE, text_color=CommonLocalizedStringColor.RED), - cancel_text_identifier=CommonStringId.TESTING_TEST_BUTTON_TWO - ) - dialog.show( - CommonSimUtils.get_active_sim_info(), - tuple(CommonSimUtils.get_sim_info_for_all_sims_generator())[0], - on_ok_selected=_ok_chosen, - on_cancel_selected=_cancel_chosen - ) - - - :param question_text: A decimal identifier of the question text. - :type question_text: Union[int, str, LocalizedString, CommonStringId] - :param question_tokens: Tokens to format into the question text. - :type question_tokens: Iterator[Any], optional - :param ok_text_identifier: A decimal identifier for the Ok text. - :type ok_text_identifier: Union[int, str, LocalizedString, CommonStringId], optional - :param ok_text_tokens: Tokens to format into the Ok text. - :type ok_text_tokens: Iterator[Any], optional - :param cancel_text_identifier: A decimal identifier for the Cancel text. - :type cancel_text_identifier: Union[int, str, LocalizedString, CommonStringId], optional - :param cancel_text_tokens: Tokens to format into the Cancel text. - :type cancel_text_tokens: Iterator[Any], optional - :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. - :type mod_identity: CommonModIdentity, optional - """ - def __init__( - self, - question_text: Union[int, str, LocalizedString, CommonStringId], - question_tokens: Iterator[Any]=(), - ok_text_identifier: Union[int, str, LocalizedString, CommonStringId]=CommonStringId.OK, - ok_text_tokens: Iterator[Any]=(), - cancel_text_identifier: Union[int, str, LocalizedString, CommonStringId]=CommonStringId.CANCEL, - cancel_text_tokens: Iterator[Any]=(), - mod_identity: CommonModIdentity=None - ): - super().__init__( - 0, - question_text, - description_tokens=question_tokens, - mod_identity=mod_identity - ) - self.ok_text = CommonLocalizationUtils.create_localized_string(ok_text_identifier, tokens=tuple(ok_text_tokens)) - self.cancel_text = CommonLocalizationUtils.create_localized_string(cancel_text_identifier, tokens=tuple(cancel_text_tokens)) - - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - return 's4cl_targeted_question_dialog' - - def show( - self, - sim_info: SimInfo, - target_sim_info: SimInfo, - on_ok_selected: Callable[[UiDialogOkCancel], Any]=CommonFunctionUtils.noop, - on_cancel_selected: Callable[[UiDialogOkCancel], Any]=CommonFunctionUtils.noop - ): - """show(\ - sim_info,\ - target_sim_info,\ - on_ok_selected=CommonFunctionUtils.noop,\ - on_cancel_selected=CommonFunctionUtils.noop\ - ) - - Show the dialog and invoke the callbacks upon the player making a choice. - - :param sim_info: The Sim that is the source of the question. - :type sim_info: SimInfo - :param target_sim_info: The Sim that is the target of the question. - :type target_sim_info: SimInfo - :param on_ok_selected: Invoked upon the player clicking the Ok button in the dialog. - :type on_ok_selected: Callable[[UiDialogOkCancel], Any], optional - :param on_cancel_selected: Invoked upon the player clicking the Cancel button in the dialog. - :type on_cancel_selected: Callable[[UiDialogOkCancel], Any], optional - """ - try: - return self._show( - sim_info, - target_sim_info, - on_ok_selected=on_ok_selected, - on_cancel_selected=on_cancel_selected - ) - except Exception as ex: - self.log.error('show', exception=ex) - - def _show( - self, - sim_info: SimInfo, - target_sim_info: SimInfo, - on_ok_selected: Callable[[UiDialogOkCancel], bool]=CommonFunctionUtils.noop, - on_cancel_selected: Callable[[UiDialogOkCancel], bool]=CommonFunctionUtils.noop - ): - self.log.format_with_message( - 'Attempting to display dialog.', - sim=CommonSimNameUtils.get_full_name(sim_info), - target=CommonSimNameUtils.get_full_name(target_sim_info) - ) - _dialog = self._create_dialog(sim_info, target_sim_info) - if _dialog is None: - self.log.debug('Failed to create dialog.') - return - - def _on_option_selected(dialog: UiDialogOkCancel) -> bool: - try: - self.log.debug('Option selected.') - if dialog.accepted: - self.log.debug('Ok chosen.') - return on_ok_selected(dialog) - self.log.debug('Cancel chosen.') - return on_cancel_selected(dialog) - except Exception as ex: - self.log.error('Error occurred on choosing an option.', exception=ex) - return False - - _dialog.add_listener(_on_option_selected) - self.log.debug('Displaying dialog.') - _dialog.show_dialog() - - def _create_dialog( - self, - sim_info: SimInfo, - target_sim_info: SimInfo - ) -> Union[UiDialogOkCancel, None]: - try: - return UiDialogOkCancel.TunableFactory().default( - sim_info, - text=lambda *_, **__: self.description, - text_ok=lambda *_, **__: self.ok_text, - text_cancel=lambda *_, **__: self.cancel_text, - target_sim_id=CommonSimUtils.get_sim_id(target_sim_info), - resolver=DoubleSimResolver(sim_info, target_sim_info) - ) - except Exception as ex: - self.log.error('_create_dialog', exception=ex) - return None - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_testing.show_targeted_question_dialog', - 'Show an example of CommonTargetedQuestionDialog.' -) -def _common_testing_show_targeted_question_dialog(output: CommonConsoleCommandOutput): - output('Showing test targeted question dialog.') - - def _ok_chosen(_: UiDialogOkCancel): - output('Ok option chosen.') - - def _cancel_chosen(_: UiDialogOkCancel): - output('Cancel option chosen.') - - # LocalizedStrings within other LocalizedStrings - 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),) - dialog = CommonTargetedQuestionDialog( - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - question_tokens=description_tokens, - ok_text_identifier=CommonLocalizationUtils.create_localized_string(CommonStringId.TESTING_TEST_BUTTON_ONE, text_color=CommonLocalizedStringColor.RED), - cancel_text_identifier=CommonStringId.TESTING_TEST_BUTTON_TWO - ) - dialog.show( - CommonSimUtils.get_active_sim_info(), - tuple(CommonSimUtils.get_sim_info_for_all_sims_generator())[0], - on_ok_selected=_ok_chosen, - on_cancel_selected=_cancel_chosen - ) - output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_ui_dialog_response.py b/Scripts/s4ap/sims4communitylib/dialogs/common_ui_dialog_response.py deleted file mode 100644 index cd909d8..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/common_ui_dialog_response.py +++ /dev/null @@ -1,38 +0,0 @@ -""" -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 -""" -from typing import Any, Union -from protocolbuffers.Localization_pb2 import LocalizedString -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from ui.ui_dialog import UiDialogResponse - - -class CommonUiDialogResponse(UiDialogResponse): - """ A dialog response. """ - def __init__( - self, - dialog_response_id: int, - value: Any, - sort_order: int=0, - text: Union[int, str, LocalizedString, CommonStringId]=None, - subtext: Union[int, str, LocalizedString, CommonStringId]=None, - ui_request: UiDialogResponse.UiDialogUiRequest=UiDialogResponse.UiDialogUiRequest.NO_REQUEST, - response_command: Any=None, - disabled_text: Union[int, str, LocalizedString, CommonStringId]=None - ): - super().__init__( - sort_order=sort_order, - dialog_response_id=dialog_response_id, - text=lambda *_, **__: CommonLocalizationUtils.create_localized_string(text) if text is not None else None, - subtext=CommonLocalizationUtils.create_localized_string(subtext) if subtext is not None else None, - ui_request=ui_request, - response_command=response_command, - disabled_text=CommonLocalizationUtils.create_localized_string(disabled_text) if disabled_text is not None else None - ) - self.response_id = int(dialog_response_id) - self.value = value diff --git a/Scripts/s4ap/sims4communitylib/dialogs/common_ui_response_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/common_ui_response_dialog.py deleted file mode 100644 index bfabc23..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/common_ui_response_dialog.py +++ /dev/null @@ -1,157 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.dialogs.common_ui_dialog_response import CommonUiDialogResponse -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from ui.ui_dialog import UiDialog, UiDialogOption -from typing import Tuple, Any, Iterator - -from event_testing.resolver import Resolver -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.logging.has_class_log import HasClassLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - - -class CommonUiResponseDialog(UiDialog, HasClassLog): - """CommonUiResponseDialog(owner, responses, *args, resolver=None, target_sim_id=None, dialog_options=UiDialogOption.DISABLE_CLOSE_BUTTON, **kwargs) - - A dialog that displays various responses for the player to choose from. - - :param owner: The owner of the dialog. - :type owner: Any - :param responses: An iteration of responses the player may choose. - :type responses: Iterator[CommonUiDialogResponse] - :param resolver: A resolver used to determine the display name of responses. Default is None. - :type resolver: Resolver, optional - :param target_sim_id: The Sim Id of the Target the response is directed at. Default is None. - :type target_sim_id: int, optional - :param dialog_options: Flags used to change how the dialog appears or functions. Default is UiDialogOption.DISABLE_CLOSE_BUTTON. - :type dialog_options: UiDialogOption, optional - """ - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - return ModInfo.get_identity() - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 'common_ui_response_dialog' - - def __init__( - self, - owner: Any, - responses: Iterator[CommonUiDialogResponse], - *args, - resolver: Resolver=None, - target_sim_id: int=None, - dialog_options: UiDialogOption=UiDialogOption.DISABLE_CLOSE_BUTTON, - **kwargs - ): - super().__init__( - owner, - *args, - resolver=resolver, - target_sim_id=target_sim_id, - dialog_options=dialog_options, - **kwargs - ) - HasClassLog.__init__(self) - self._response_value = None - self._responses = tuple(responses) - - @property - def accepted(self) -> bool: - """Whether or not a response was chosen.""" - return self.response != CommonUiResponseDialog._PREVIOUS_BUTTON_ID and self.response != CommonUiResponseDialog._NEXT_BUTTON_ID - - @property - def cancelled(self) -> bool: - """Whether not the dialog was cancelled.""" - return self.response < 0 - - def add_response(self, response: CommonUiDialogResponse): - """add_response(response) - - Add a response to the dialog. - - :param response: The response to add. - :type response: CommonUiDialogResponse - """ - self._responses += (response,) - - def get_response(self) -> Any: - """Retrieve the chosen response. If there is one.""" - return self.response - - def get_response_value(self) -> Any: - """Retrieve the chosen response value. If there is one.""" - return self._response_value - - def respond(self, chosen_response: int) -> bool: - """When the player makes a choice, this function is invoked.""" - try: - self.log.format_with_message('Chosen response', response=chosen_response) - self.response = chosen_response - if chosen_response < 0: - self._response_value = None - else: - self._response_value = None - for response in self._get_responses_gen(): - if response.response_id == chosen_response: - self._response_value = response.value - self._listeners(self) - return True - except Exception as ex: - self.log.error('Error occurred while attempting to respond.', exception=ex) - return False - finally: - self.on_response_received() - - def _get_responses_gen(self) -> Iterator[CommonUiDialogResponse]: - yield from super()._get_responses_gen() - - @property - def responses(self) -> Tuple[CommonUiDialogResponse]: - """The responses of the dialog.""" - result: Tuple[CommonUiDialogResponse] = ( - *self._responses, - ) - return result - - -@CommonConsoleCommand(ModInfo.get_identity(), 's4clib_testing.show_ui_response_dialog', 'Show an example of UI Response Dialog.', show_with_help_command=False) -def _common_testing_show_ui_response_dialog(output: CommonConsoleCommandOutput): - output('Showing test ui response dialog.') - - def _on_chosen(_: CommonUiResponseDialog): - response_value = _.get_response_value() - output('Chosen value {}'.format(response_value if response_value is not None else 'No value chosen.')) - - responses: Tuple[CommonUiDialogResponse] = ( - CommonUiDialogResponse(0, 'one', text='Button one'), - CommonUiDialogResponse(1, 'two', text='Button two') - ) - title = CommonLocalizationUtils.create_localized_string(CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, tokens=(CommonLocalizationUtils.create_localized_string(CommonStringId.TESTING_SOME_TEXT_FOR_TESTING, text_color=CommonLocalizedStringColor.GREEN), )) - description = CommonLocalizationUtils.create_localized_string(CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, 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), )) - - active_sim_info = CommonSimUtils.get_active_sim_info() - dialog = CommonUiResponseDialog.TunableFactory().default( - active_sim_info, - responses, - # Having a value of 0 means that we want to display the Close button with no other dialog options. - dialog_options=0, - text=lambda *_, **__: description, - title=lambda *_, **__: title - ) - dialog.add_listener(_on_chosen) - dialog.show_dialog() diff --git a/Scripts/s4ap/sims4communitylib/dialogs/custom_dialogs/__init__.py b/Scripts/s4ap/sims4communitylib/dialogs/custom_dialogs/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/custom_dialogs/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/dialogs/custom_dialogs/picker_dialogs/__init__.py b/Scripts/s4ap/sims4communitylib/dialogs/custom_dialogs/picker_dialogs/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/custom_dialogs/picker_dialogs/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/dialogs/custom_dialogs/picker_dialogs/common_ui_multi_picker.py b/Scripts/s4ap/sims4communitylib/dialogs/custom_dialogs/picker_dialogs/common_ui_multi_picker.py deleted file mode 100644 index 42539eb..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/custom_dialogs/picker_dialogs/common_ui_multi_picker.py +++ /dev/null @@ -1,48 +0,0 @@ -""" -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 -""" -from typing import Any, Dict -from protocolbuffers.Localization_pb2 import LocalizedString -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from protocolbuffers.Dialog_pb2 import UiDialogMessage, UiDialogMultiPicker -from ui.ui_dialog_multi_picker import UiMultiPicker - - -class CommonUiMultiPicker(UiMultiPicker): - """CommonUiMultiPicker(\ - *args,\ - **kwargs\ - ) - - A custom multi picker dialog that enables programmatic creation. - - """ - def __init__(self, *args, **kwargs) -> None: - super().__init__(*args, **kwargs) - self.required_tooltips: Dict[Any, LocalizedString] = dict() - - def build_msg(self, **kwargs) -> Any: - """build_msg(**kwargs) - - Build the message for display. - - :return: Unknown. - :rtype: Any - """ - message = super().build_msg(**kwargs) - # noinspection PyUnresolvedReferences - message.dialog_type = UiDialogMessage.MULTI_PICKER - multi_picker_msg = UiDialogMultiPicker() - for dialog in self._picker_dialogs.values(): - new_message = dialog.build_msg() - # noinspection PyUnresolvedReferences - multi_picker_item = multi_picker_msg.multi_picker_items.add() - multi_picker_item.picker_data = new_message.picker_data - multi_picker_item.picker_id = new_message.dialog_id - multi_picker_item.disabled_tooltip = self.required_tooltips.get(new_message.dialog_id, None) or CommonLocalizationUtils.create_localized_string('') - message.multi_picker_data = multi_picker_msg - return message diff --git a/Scripts/s4ap/sims4communitylib/dialogs/custom_dialogs/picker_dialogs/common_ui_object_category_picker.py b/Scripts/s4ap/sims4communitylib/dialogs/custom_dialogs/picker_dialogs/common_ui_object_category_picker.py deleted file mode 100644 index 406e9c5..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/custom_dialogs/picker_dialogs/common_ui_object_category_picker.py +++ /dev/null @@ -1,51 +0,0 @@ -""" -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 -""" -from distributor.rollback import ProtocolBufferRollback -from interactions.utils.tunable_icon import TunableIconFactory -from sims4.localization import TunableLocalizedString -from sims4.tuning.tunable import TunableTuple, TunableList, Tunable -from ui.ui_dialog_picker import UiObjectPicker -from distributor.shared_messages import build_icon_info_msg - - -class CommonUiObjectCategoryPicker(UiObjectPicker): - """An ObjectPicker with categories listed in a drop down. - - """ - FACTORY_TUNABLES = { - 'object_categories': TunableList( - description='\n The categories to display in the drop down for this picker.\n ', - tunable=TunableTuple( - object_category=Tunable( - tunable_type=str, - default='ALL' - ), - icon=TunableIconFactory(), - category_name=TunableLocalizedString() - ) - ) - } - - def _build_customize_picker(self, picker_data) -> None: - # noinspection PyBroadException - try: - with ProtocolBufferRollback(picker_data.filter_data) as filter_data_list: - for category in self.object_categories: - with ProtocolBufferRollback(filter_data_list.filter_data) as category_data: - category_data.tag_type = abs(hash(category.object_category)) % (10 ** 8) - build_icon_info_msg(category.icon(None), None, category_data.icon_info) - category_data.description = category.category_name - filter_data_list.use_dropdown_filter = self.use_dropdown_filter - super()._build_customize_picker(picker_data) - except: - with ProtocolBufferRollback(picker_data.filter_data) as category_data: - for category in self.object_categories: - category_data.tag_type = abs(hash(category.object_category)) % (10 ** 8) - build_icon_info_msg(category.icon(None), None, category_data.icon_info) - category_data.description = category.category_name - super()._build_customize_picker(picker_data) diff --git a/Scripts/s4ap/sims4communitylib/dialogs/ok_cancel_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/ok_cancel_dialog.py deleted file mode 100644 index 228e434..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/ok_cancel_dialog.py +++ /dev/null @@ -1,199 +0,0 @@ -""" -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 -""" -from typing import Any, Callable, Union, Iterator - -from protocolbuffers.Localization_pb2 import LocalizedString -from s4ap.sims4communitylib.dialogs.common_dialog import CommonDialog -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from ui.ui_dialog import UiDialogOkCancel - - -class CommonOkCancelDialog(CommonDialog): - """CommonOkCancelDialog(\ - title_identifier,\ - description_identifier,\ - title_tokens=(),\ - description_tokens=(),\ - ok_text_identifier=CommonStringId.OK,\ - ok_text_tokens=(),\ - cancel_text_identifier=CommonStringId.CANCEL,\ - cancel_text_tokens=(),\ - mod_identity=None\ - ) - - Use to create a prompt dialog. - - .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_ok_cancel_dialog` in the in-game console. - - .. highlight:: python - .. code-block:: python - - def _common_testing_show_ok_cancel_dialog(): - - def _ok_chosen(_: UiDialogOkCancel): - pass - - def _cancel_chosen(_: UiDialogOkCancel): - 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),) - dialog = CommonOkCancelDialog( - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - title_tokens=title_tokens, - description_tokens=description_tokens, - ok_text_identifier=CommonLocalizationUtils.create_localized_string(CommonStringId.TESTING_TEST_BUTTON_ONE, text_color=CommonLocalizedStringColor.RED), - cancel_text_identifier=CommonStringId.TESTING_TEST_BUTTON_TWO - ) - dialog.show(on_ok_selected=_ok_chosen, on_cancel_selected=_cancel_chosen) - - :param title_identifier: A decimal identifier of the title text. - :type title_identifier: Union[int, str, LocalizedString, CommonStringId] - :param description_identifier: A decimal identifier of the description text. - :type description_identifier: Union[int, str, LocalizedString, CommonStringId] - :param title_tokens: Tokens to format into the title. - :type title_tokens: Iterator[Any], optional - :param description_tokens: Tokens to format into the description. - :type description_tokens: Iterator[Any], optional - :param ok_text_identifier: A decimal identifier for the Ok text. - :type ok_text_identifier: Union[int, str, LocalizedString, CommonStringId], optional - :param ok_text_tokens: Tokens to format into the Ok text. - :type ok_text_tokens: Iterator[Any], optional - :param cancel_text_identifier: A decimal identifier for the Cancel text. - :type cancel_text_identifier: Union[int, str, LocalizedString, CommonStringId], optional - :param cancel_text_tokens: Tokens to format into the Cancel text. - :type cancel_text_tokens: Iterator[Any], optional - :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. - :type mod_identity: CommonModIdentity, optional - """ - def __init__( - self, - title_identifier: Union[int, str, LocalizedString, CommonStringId], - description_identifier: Union[int, str, LocalizedString, CommonStringId], - title_tokens: Iterator[Any]=(), - description_tokens: Iterator[Any]=(), - ok_text_identifier: Union[int, str, LocalizedString, CommonStringId]=CommonStringId.OK, - ok_text_tokens: Iterator[Any]=(), - cancel_text_identifier: Union[int, str, LocalizedString, CommonStringId]=CommonStringId.CANCEL, - cancel_text_tokens: Iterator[Any]=(), - mod_identity: CommonModIdentity=None - ): - super().__init__( - title_identifier, - description_identifier, - title_tokens=title_tokens, - description_tokens=description_tokens, - mod_identity=mod_identity - ) - self.ok_text = CommonLocalizationUtils.create_localized_string(ok_text_identifier, tokens=tuple(ok_text_tokens)) - self.cancel_text = CommonLocalizationUtils.create_localized_string(cancel_text_identifier, tokens=tuple(cancel_text_tokens)) - - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - return 's4cl_ok_cancel_dialog' - - def show( - self, - on_ok_selected: Callable[[UiDialogOkCancel], Any]=CommonFunctionUtils.noop, - on_cancel_selected: Callable[[UiDialogOkCancel], Any]=CommonFunctionUtils.noop - ): - """show(\ - on_ok_selected=CommonFunctionUtils.noop,\ - on_cancel_selected=CommonFunctionUtils.noop\ - ) - - Show the dialog and invoke the callbacks upon the player selecting an option. - - :param on_ok_selected: Invoked upon the player selecting Ok in the dialog. - :type on_ok_selected: Callable[[UiDialogOkCancel], Any], optional - :param on_cancel_selected: Invoked upon the player selecting Cancel in the dialog. - :type on_cancel_selected: Callable[[UiDialogOkCancel], Any], optional - """ - try: - return self._show( - on_ok_selected=on_ok_selected, - on_cancel_selected=on_cancel_selected - ) - except Exception as ex: - self.log.error('show', exception=ex) - - def _show( - self, - on_ok_selected: Callable[[UiDialogOkCancel], Any]=CommonFunctionUtils.noop, - on_cancel_selected: Callable[[UiDialogOkCancel], Any]=CommonFunctionUtils.noop - ): - self.log.format_with_message('Attempting to display dialog.') - _dialog = self._create_dialog() - if _dialog is None: - self.log.debug('Failed to create dialog.') - return - - def _on_option_selected(dialog: UiDialogOkCancel): - self.log.debug('Option selected.') - if dialog.accepted: - self.log.debug('Ok chosen.') - return on_ok_selected(dialog) - self.log.debug('Cancel chosen.') - return on_cancel_selected(dialog) - - _dialog.add_listener(_on_option_selected) - self.log.debug('Displaying dialog.') - _dialog.show_dialog() - - def _create_dialog(self) -> Union[UiDialogOkCancel, None]: - try: - return UiDialogOkCancel.TunableFactory().default( - CommonSimUtils.get_active_sim_info(), - text=lambda *_, **__: self.description, - title=lambda *_, **__: self.title, - text_ok=lambda *_, **__: self.ok_text, - text_cancel=lambda *_, **__: self.cancel_text - ) - except Exception as ex: - self.log.error('_create_dialog', exception=ex) - return None - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_testing.show_ok_cancel_dialog', - 'Show an example of CommonOkCancelDialog.' -) -def _common_testing_show_ok_cancel_dialog(output: CommonConsoleCommandOutput): - output('Showing test ok cancel dialog.') - - def _ok_chosen(_: UiDialogOkCancel): - output('Ok option chosen.') - - def _cancel_chosen(_: UiDialogOkCancel): - output('Cancel option chosen.') - - # 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),) - dialog = CommonOkCancelDialog( - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - title_tokens=title_tokens, - description_tokens=description_tokens, - ok_text_identifier=CommonLocalizationUtils.create_localized_string(CommonStringId.TESTING_TEST_BUTTON_ONE, text_color=CommonLocalizedStringColor.RED), - cancel_text_identifier=CommonStringId.TESTING_TEST_BUTTON_TWO - ) - dialog.show(on_ok_selected=_ok_chosen, on_cancel_selected=_cancel_chosen) - output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/__init__.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_button_option_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_button_option_dialog.py deleted file mode 100644 index a9d3a4b..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_button_option_dialog.py +++ /dev/null @@ -1,349 +0,0 @@ -""" -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 -""" -from pprint import pformat - -from typing import Any, Union, Callable, Iterator - -from protocolbuffers.Localization_pb2 import LocalizedString -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.dialogs.common_choose_response_dialog import CommonChooseResponseDialog -from s4ap.sims4communitylib.dialogs.option_dialogs.common_choose_response_option_dialog import \ - CommonChooseResponseOptionDialog -from s4ap.sims4communitylib.dialogs.option_dialogs.options.response.common_dialog_button_option import \ - CommonDialogButtonOption -from s4ap.sims4communitylib.dialogs.option_dialogs.options.response.common_dialog_response_option_context import \ - CommonDialogResponseOptionContext -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ - CommonConsoleCommandArgument -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.services.commands.common_console_command_parameters import \ - CommonOptionalSimInfoConsoleCommandParameter -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from ui.ui_dialog import UiDialogBase, UiDialogOption - - -class CommonChooseButtonOptionDialog(CommonChooseResponseOptionDialog): - """CommonChooseButtonOptionDialog(\ - mod_identity,\ - title_identifier,\ - description_identifier,\ - title_tokens=(),\ - description_tokens=(),\ - include_previous_button=True,\ - on_previous=CommonFunctionUtils.noop,\ - on_close=CommonFunctionUtils.noop\ - ) - - A dialog that displays a list of options. - - .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_choose_button_option_dialog` in the in-game console. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - def _on_option_chosen(option_identifier: DialogOptionIdentifierType, choice: DialogOptionValueType): - pass - - def _on_previous_chosen() -> None: - pass - - def _on_close() -> None: - 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 - ), - ) - option_dialog = CommonChooseButtonOptionDialog( - ModInfo.get_identity(), - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - title_tokens=title_tokens, - description_tokens=description_tokens, - on_previous=_on_previous_chosen, - on_close=_on_close - ) - - # We add the options, in this case we have three options. - option_dialog.add_option( - CommonDialogButtonOption( - 'Option 1', - 'Value 1', - CommonDialogResponseOptionContext( - CommonStringId.TESTING_SOME_TEXT_FOR_TESTING, - subtext_identifier=CommonStringId.TESTING_TEST_BUTTON_ONE - ), - on_chosen=_on_option_chosen - ) - ) - - option_dialog.add_option( - CommonDialogButtonOption( - 'Option 2', - 'Value 2', - CommonDialogResponseOptionContext( - CommonStringId.TESTING_SOME_TEXT_FOR_TESTING, - subtext_identifier=CommonStringId.TESTING_TEST_BUTTON_TWO, - ), - on_chosen=_on_option_chosen - ) - ) - - option_dialog.add_option( - CommonDialogButtonOption( - 'Option 3', - 'Value 3', - CommonDialogResponseOptionContext( - CommonLocalizationUtils.create_localized_string('Value 3'), - subtext_identifier=CommonStringId.TESTING_TEST_BUTTON_TWO - ), - on_chosen=_on_option_chosen - ) - ) - - option_dialog.show( - sim_info=CommonSimUtils.get_active_sim_info() - ) - - :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. - :type mod_identity: CommonModIdentity - :param title_identifier: A decimal identifier of the title text. - :type title_identifier: Union[int, str, LocalizedString, CommonStringId] - :param description_identifier: A decimal identifier of the description text. - :type description_identifier: Union[int, str, LocalizedString, CommonStringId] - :param title_tokens: An iterator of Tokens to format into the title. Default is an empty collection. - :type title_tokens: Iterator[Any], optional - :param description_tokens: An iterator of Tokens to format into the description. Default is an empty collection. - :type description_tokens: Iterator[Any], optional - :param include_previous_button: If True, the Previous button will be appended to the end of the dialog. Default is True. - :type include_previous_button: bool, optional - :param on_previous: A callback invoked upon the the Previous option being chosen. Default is CommonFunctionUtils.noop. - :type on_previous: Callable[[], None], optional - :param on_close: A callback invoked upon the dialog closing. Default is CommonFunctionUtils.noop. - :type on_close: Callable[[], None], optional - """ - - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - return 's4cl_choose_button_option_dialog' - - def __init__( - self, - mod_identity: CommonModIdentity, - title_identifier: Union[int, str, LocalizedString, CommonStringId], - description_identifier: Union[int, str, LocalizedString, CommonStringId], - title_tokens: Iterator[Any]=(), - description_tokens: Iterator[Any]=(), - include_previous_button: bool=True, - next_button_text: Union[int, str, LocalizedString, CommonStringId]=CommonStringId.NEXT, - previous_button_text: Union[int, str, LocalizedString, CommonStringId]=CommonStringId.PREVIOUS, - on_previous: Callable[[], None]=CommonFunctionUtils.noop, - on_close: Callable[[], None]=CommonFunctionUtils.noop, - per_page: int=10 - ): - super().__init__( - CommonChooseResponseDialog( - mod_identity, - title_identifier, - description_identifier, - tuple(), - next_button_text=next_button_text, - previous_button_text=previous_button_text, - title_tokens=title_tokens, - description_tokens=description_tokens, - per_page=per_page - ), - include_previous_button=include_previous_button, - on_previous=on_previous, - on_close=on_close - ) - - def add_option(self, option: CommonDialogButtonOption): - """add_option(option) - - Add an option to the dialog. - - :param option: The option to add. - :type option: CommonDialogObjectOption - """ - return super().add_option(option) - - def _add_response(self, option: CommonDialogButtonOption): - self._internal_dialog.add_response(option.as_response(len(self._options))) - - def show( - self, - dialog_options: UiDialogOption=0, - sim_info: SimInfo=None, - target_sim_info: SimInfo=None, - page: int=1 - ): - """show(\ - dialog_options=0,\ - sim_info=None,\ - target_sim_info=None,\ - page=1\ - ) - - Show the dialog and invoke the callbacks upon the player making a choice. - - :param dialog_options: Options to apply to the dialog, such as removing the close button. Default is no options. - :type dialog_options: UiDialogOption, optional - :param sim_info: The SimInfo of the Sim that will appear in the dialog image. The default Sim is the active Sim. Default is None. - :type sim_info: SimInfo, optional - :param target_sim_info: If provided, the dialog will appear as if it were a conversation instead of the normal view. Default is None. - :type target_sim_info: SimInfo, optional - :param page: The page to show the dialog on. Default is the first page. - :type page: int, optional - """ - return super().show( - dialog_options=dialog_options, - sim_info=sim_info, - target_sim_info=target_sim_info, - page=page - ) - - def build_dialog( - self, - dialog_options: UiDialogOption=0, - sim_info: SimInfo=None, - target_sim_info: SimInfo=None, - page: int=1 - ) -> Union[UiDialogBase, None]: - """build_dialog(\ - dialog_options=0,\ - sim_info=None,\ - target_sim_info=None,\ - page=1\ - ) - - Build the dialog and invoke the callbacks upon the player making a choice. - - :param dialog_options: Options to apply to the dialog, such as removing the close button. Default is no options. - :type dialog_options: UiDialogOption, optional - :param sim_info: The SimInfo of the Sim that will appear in the dialog image. The default Sim is the active Sim. Default is None. - :type sim_info: SimInfo, optional - :param target_sim_info: If provided, the dialog will appear as if it were a conversation instead of the normal view. Default is None. - :type target_sim_info: SimInfo, optional - :param page: The page to build the dialog on. Default is the first page. - :type page: int, optional - :return: The built dialog or None if a problem occurs. - :rtype: Union[UiDialogBase, None] - """ - return super().build_dialog( - dialog_options=dialog_options, - sim_info=sim_info, - page=page - ) - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_testing.show_choose_button_option_dialog', - 'Show an example of CommonChooseButtonOptionDialog.', - command_arguments=( - CommonConsoleCommandArgument('target_sim_info', 'Sim Id or Name', 'The name or instance id of a Sim that will be the target of the dialog.', is_optional=True, default_value='No Sim'), - ) -) -def _common_testing_show_choose_button_option_dialog(output: CommonConsoleCommandOutput, target_sim_info: CommonOptionalSimInfoConsoleCommandParameter=None): - output('Showing test choose button option dialog.') - - def _on_option_chosen(option_identifier: str, choice: str): - output('Chose option {} with value: {}.'.format(pformat(option_identifier), pformat(choice))) - - def _on_previous_chosen() -> None: - output('Chose previous option.') - - def _on_close() -> None: - output('Closed dialog.') - - # 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 = CommonChooseButtonOptionDialog( - ModInfo.get_identity(), - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - title_tokens=title_tokens, - description_tokens=description_tokens, - on_previous=_on_previous_chosen, - on_close=_on_close, - per_page=2 - ) - - option_dialog.add_option( - CommonDialogButtonOption( - 'Option 1', - 'Value 1', - CommonDialogResponseOptionContext( - CommonStringId.TESTING_SOME_TEXT_FOR_TESTING, - subtext_identifier=CommonStringId.TESTING_TEST_BUTTON_ONE - ), - on_chosen=_on_option_chosen - ) - ) - - option_dialog.add_option( - CommonDialogButtonOption( - 'Option 2', - 'Value 2', - CommonDialogResponseOptionContext( - CommonStringId.TESTING_SOME_TEXT_FOR_TESTING, - subtext_identifier=CommonStringId.TESTING_TEST_BUTTON_TWO, - ), - on_chosen=_on_option_chosen - ) - ) - - option_dialog.add_option( - CommonDialogButtonOption( - 'Option 3', - 'Value 3', - CommonDialogResponseOptionContext( - CommonLocalizationUtils.create_localized_string('Value 3'), - subtext_identifier=CommonStringId.TESTING_TEST_BUTTON_TWO - ), - on_chosen=_on_option_chosen - ) - ) - - option_dialog.show( - sim_info=CommonSimUtils.get_active_sim_info(), - target_sim_info=target_sim_info if target_sim_info is not CommonSimUtils.get_active_sim_info() else None - ) - output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_object_option_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_object_option_dialog.py deleted file mode 100644 index 0a48228..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_object_option_dialog.py +++ /dev/null @@ -1,357 +0,0 @@ -""" -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 -""" -from pprint import pformat - -from typing import Any, Union, Callable, Iterator - -from protocolbuffers.Localization_pb2 import LocalizedString -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.dialogs.choose_object_dialog import CommonChooseObjectDialog -from s4ap.sims4communitylib.dialogs.option_dialogs.common_choose_option_dialog import CommonChooseOptionDialog -from s4ap.sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext -from s4ap.sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_option_category import \ - CommonDialogObjectOptionCategory -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from s4ap.sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_object_option import CommonDialogObjectOption -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from ui.ui_dialog import UiDialogBase -from ui.ui_dialog_picker import UiObjectPicker - - -class CommonChooseObjectOptionDialog(CommonChooseOptionDialog): - """CommonChooseObjectOptionDialog(\ - title_identifier,\ - description_identifier,\ - title_tokens=(),\ - description_tokens=(),\ - on_close=CommonFunctionUtils.noop,\ - mod_identity=None,\ - per_page=25,\ - required_tooltip=None,\ - required_tooltip_tokens=()\ - ) - - A dialog that displays a list of options. - - .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_choose_object_option_dialog` in the in-game console. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - def _on_option_chosen(option_identifier: DialogOptionIdentifierType, choice: DialogOptionValueType): - 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 - ), - ) - - # Create the dialog and only showing 2 options per page. - 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 s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils - - # We add the options, in this case we have three options. - 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() - ) - - - :param title_identifier: A decimal identifier of the title text. - :type title_identifier: Union[int, str, LocalizedString, CommonStringId] - :param description_identifier: A decimal identifier of the description text. - :type description_identifier: Union[int, str, LocalizedString, CommonStringId] - :param title_tokens: An iterator of Tokens to format into the title. Default is an empty collection. - :type title_tokens: Iterator[Any], optional - :param description_tokens: An iterator of Tokens to format into the description. Default is an empty collection. - :type description_tokens: Iterator[Any], optional - :param on_close: A callback invoked upon the dialog closing. Default is CommonFunctionUtils.noop. - :type on_close: Callable[[], None], optional - :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. Default is None. - :type mod_identity: CommonModIdentity, optional - :param per_page: The number of rows to display per page. If the number of rows (including rows added after creation) exceeds this value, pagination will be added. Default is 25. - :type per_page: int, optional - :param required_tooltip: If provided, this text will display when the dialog requires at least one choice and a choice has not been made. Default is None. - :type required_tooltip: Union[int, str, LocalizedString, CommonStringId], optional - :param required_tooltip_tokens: Tokens to format into the required tooltip. Default is an empty collection. - :type required_tooltip_tokens: Iterator[Any], optional - """ - - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - return 's4cl_choose_object_option_dialog' - - def __init__( - self, - title_identifier: Union[int, str, LocalizedString, CommonStringId], - description_identifier: Union[int, str, LocalizedString, CommonStringId], - title_tokens: Iterator[Any]=(), - description_tokens: Iterator[Any]=(), - on_close: Callable[[], None]=CommonFunctionUtils.noop, - mod_identity: CommonModIdentity=None, - per_page: int=25, - required_tooltip: Union[int, str, LocalizedString, CommonStringId]=None, - required_tooltip_tokens: Iterator[Any]=() - ): - super().__init__( - CommonChooseObjectDialog( - title_identifier, - description_identifier, - tuple(), - title_tokens=title_tokens, - description_tokens=description_tokens, - per_page=per_page, - mod_identity=mod_identity, - required_tooltip=required_tooltip, - required_tooltip_tokens=required_tooltip_tokens - ), - on_close=on_close - ) - - @property - def current_page(self) -> int: - """Retrieve the current page. - - :return: A number indicating the current page. - :rtype: int - """ - dialog: CommonChooseObjectDialog = self._internal_dialog - return dialog.current_page - - def add_option(self, option: CommonDialogObjectOption): - """add_option(option) - - Add an option to the dialog. - - :param option: The option to add. - :type option: CommonDialogObjectOption - """ - return super().add_option(option) - - def _add_row(self, option: CommonDialogObjectOption): - self._internal_dialog.add_row(option.as_row(len(self._options)), always_visible=option.always_visible) - - def show( - self, - picker_type: UiObjectPicker.UiObjectPickerObjectPickerType=UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT, - page: int=1, - sim_info: SimInfo=None, - categories: Iterator[CommonDialogObjectOptionCategory]=(), - sort_options: bool=False - ): - """show(\ - picker_type=UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT,\ - page=1,\ - sim_info=None,\ - categories=()\ - ) - - Show the dialog and invoke the callbacks upon the player making a choice. - - :param picker_type: The layout of the dialog. Default is UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT. - :type picker_type: UiObjectPicker.UiObjectPickerObjectPickerType, optional - :param page: The page to display. Ignored if there is only one page of choices. Default is 1. - :type page: int, optional - :param sim_info: The SimInfo of the Sim that will appear in the dialog image. The default Sim is the active Sim. Default is None. - :type sim_info: SimInfo, optional - :param categories: A collection of categories do display in the dialog. Default is an empty collection. - :type categories: Iterator[CommonDialogObjectOptionCategory], optional - :param sort_options: If True, options will be sorted by display name, with the selected options on top. If False, options will not be sorted. Default is False. - :type sort_options: bool, optional - """ - return super().show( - picker_type=picker_type, - page=page, - sim_info=sim_info, - categories=categories, - sort_rows=sort_options - ) - - def build_dialog( - self, - picker_type: UiObjectPicker.UiObjectPickerObjectPickerType=UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT, - page: int=1, - sim_info: SimInfo=None, - categories: Iterator[CommonDialogObjectOptionCategory]=(), - sort_options: bool=False - ) -> Union[UiDialogBase, None]: - """build_dialog(\ - picker_type=UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT,\ - page=1,\ - sim_info=None,\ - categories=(),\ - sort_options=False\ - ) - - Build the dialog and invoke the callbacks upon the player making a choice. - - :param picker_type: The layout of the dialog. Default is UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT. - :type picker_type: UiObjectPicker.UiObjectPickerObjectPickerType, optional - :param page: The page to display. Ignored if there is only one page of choices. Default is 1. - :type page: int, optional - :param sim_info: The SimInfo of the Sim that will appear in the dialog image. The default Sim is the active Sim. Default is None. - :type sim_info: SimInfo, optional - :param categories: A collection of categories do display in the dialog. Default is an empty collection. - :type categories: Iterator[CommonDialogObjectOptionCategory], optional - :param sort_options: If True, options will be sorted by display name, with the selected options on top. If False, options will not be sorted. Default is False. - :type sort_options: bool, optional - :return: The built dialog or None if a problem occurs. - :rtype: Union[UiDialogBase, None] - """ - return super().build_dialog( - picker_type=picker_type, - page=page, - sim_info=sim_info, - categories=categories, - sort_rows=sort_options - ) - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_testing.show_choose_object_option_dialog', - 'Show an example of CommonChooseObjectOptionDialog.' -) -def _common_testing_show_choose_object_option_dialog(output: CommonConsoleCommandOutput): - 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))) - - # 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 s4ap.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() - ) - output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_objects_option_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_objects_option_dialog.py deleted file mode 100644 index 1cd0aa2..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_objects_option_dialog.py +++ /dev/null @@ -1,414 +0,0 @@ -""" -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 -""" -from pprint import pformat - -from typing import Any, Union, Callable, Iterator, Tuple - -from protocolbuffers.Localization_pb2 import LocalizedString -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.dialogs.choose_objects_dialog import CommonChooseObjectsDialog -from s4ap.sims4communitylib.dialogs.option_dialogs.common_choose_options_dialog import CommonChooseOptionsDialog -from s4ap.sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext, \ - DialogOptionValueType -from s4ap.sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_option_category import \ - CommonDialogObjectOptionCategory -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from s4ap.sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_object_option import CommonDialogObjectOption -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from ui.ui_dialog import UiDialogBase -from ui.ui_dialog_picker import UiObjectPicker - - -class CommonChooseObjectsOptionDialog(CommonChooseOptionsDialog): - """CommonChooseObjectsOptionDialog(\ - mod_identity,\ - title_identifier,\ - description_identifier,\ - title_tokens=(),\ - description_tokens=(),\ - on_close=CommonFunctionUtils.noop,\ - per_page=25,\ - required_tooltip=None,\ - required_tooltip_tokens=()\ - ) - - A dialog that displays a list of options and prompts to select multiple options. - - .. note:: This dialog allows selection of multiple Options. - - .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_choose_objects_option_dialog` in the in-game console. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - def _on_option_chosen(option_identifier: str, choice: str): - pass - - def _on_submit(choices: Tuple[str]): - 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 - ), - ) - - # Create the dialog and only showing 2 options per page. - option_dialog = CommonChooseObjectsOptionDialog( - 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 s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils - - # We add the options, in this case we have three options. - 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( - on_submit=_on_submit, - sim_info=CommonSimUtils.get_active_sim_info() - ) - - - :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. - :type mod_identity: CommonModIdentity - :param title_identifier: A decimal identifier of the title text. - :type title_identifier: Union[int, str, LocalizedString, CommonStringId] - :param description_identifier: A decimal identifier of the description text. - :type description_identifier: Union[int, str, LocalizedString, CommonStringId] - :param title_tokens: An iterator of Tokens to format into the title. Default is an empty collection. - :type title_tokens: Iterator[Any], optional - :param description_tokens: An iterator of Tokens to format into the description. Default is an empty collection. - :type description_tokens: Iterator[Any], optional - :param on_close: A callback invoked upon the dialog closing. Default is CommonFunctionUtils.noop. - :type on_close: Callable[[], None], optional - :param per_page: The number of rows to display per page. If the number of rows (including rows added after creation) exceeds this value, pagination will be added. Default is 25. - :type per_page: int, optional - :param required_tooltip: If provided, this text will display when the dialog requires at least one choice and a choice has not been made. Default is None. - :type required_tooltip: Union[int, str, LocalizedString, CommonStringId], optional - :param required_tooltip_tokens: Tokens to format into the required tooltip. Default is an empty collection. - :type required_tooltip_tokens: Iterator[Any], optional - """ - - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - return 's4cl_choose_objects_option_dialog' - - def __init__( - self, - title_identifier: Union[int, str, LocalizedString, CommonStringId], - description_identifier: Union[int, str, LocalizedString, CommonStringId], - title_tokens: Iterator[Any]=(), - description_tokens: Iterator[Any]=(), - on_close: Callable[[], None]=CommonFunctionUtils.noop, - mod_identity: CommonModIdentity=None, - per_page: int=25, - required_tooltip: Union[int, str, LocalizedString, CommonStringId]=None, - required_tooltip_tokens: Iterator[Any]=() - ): - super().__init__( - CommonChooseObjectsDialog( - title_identifier, - description_identifier, - tuple(), - title_tokens=title_tokens, - description_tokens=description_tokens, - per_page=per_page, - mod_identity=mod_identity, - required_tooltip=required_tooltip, - required_tooltip_tokens=required_tooltip_tokens - ), - on_close=on_close - ) - - @property - def current_page(self) -> int: - """Retrieve the current page. - - :return: A number indicating the current page. - :rtype: int - """ - return self._internal_dialog.current_page - - @property - def _internal_dialog(self) -> CommonChooseObjectsDialog: - result: CommonChooseObjectsDialog = super()._internal_dialog - return result - - def add_option(self, option: CommonDialogObjectOption): - """add_option(option) - - Add an option to the dialog. - - :param option: The option to add. - :type option: CommonDialogObjectOption - """ - return super().add_option(option) - - def _add_row(self, option: CommonDialogObjectOption): - self._internal_dialog.add_row(option.as_row(len(self._options)), always_visible=option.always_visible) - - def show( - self, - on_submit: Callable[[Tuple[DialogOptionValueType]], Any]=CommonFunctionUtils.noop, - picker_type: UiObjectPicker.UiObjectPickerObjectPickerType=UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT, - page: int=1, - sim_info: SimInfo=None, - categories: Iterator[CommonDialogObjectOptionCategory]=(), - min_selectable: int=1, - max_selectable: int=1, - sort_options: bool=False, - allow_no_selection: bool=False - ): - """show(\ - on_submit=CommonFunctionUtils.noop,\ - picker_type=UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT,\ - page=1,\ - sim_info=None,\ - categories=(),\ - min_selectable=1,\ - max_selectable=1,\ - allow_no_selection=False\ - ) - - Show the dialog and invoke the callbacks upon the player submitting their selection. - - :param on_submit: When the dialog is submitted, this callback will be invoked with the chosen options. - :type on_submit: Callable[[Tuple[DialogOptionValueType]], Any], optional - :param picker_type: The layout of the dialog. Default is UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT. - :type picker_type: UiObjectPicker.UiObjectPickerObjectPickerType, optional - :param page: The page to display. Ignored if there is only one page of choices. Default is 1. - :type page: int, optional - :param sim_info: The SimInfo of the Sim that will appear in the dialog image. If None, it will be the active Sim. Default is None. - :type sim_info: SimInfo, optional - :param categories: A collection of categories do display in the dialog. Default is an empty collection. - :type categories: Iterator[CommonDialogObjectOptionCategory], optional - :param min_selectable: The minimum number of options that can be chosen. - :type min_selectable: int, optional - :param max_selectable: The maximum number of options that can be chosen. - :type max_selectable: int, optional - :param sort_options: If True, options will be sorted by display name, with the selected options on top. If False, options will not be sorted. Default is False. - :type sort_options: bool, optional - :param allow_no_selection: If True, the player may select no options. If False, the dialog will close with no options selected. Default is False. - :type allow_no_selection: bool, optional - """ - return super().show( - picker_type=picker_type, - page=page, - sim_info=sim_info, - categories=categories, - on_submit=on_submit, - min_selectable=min_selectable, - max_selectable=max_selectable, - sort_rows=sort_options, - allow_no_selection=allow_no_selection - ) - - def build_dialog( - self, - on_submit: Callable[[Tuple[DialogOptionValueType]], Any]=CommonFunctionUtils.noop, - picker_type: UiObjectPicker.UiObjectPickerObjectPickerType=UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT, - page: int=1, - sim_info: SimInfo=None, - categories: Iterator[CommonDialogObjectOptionCategory]=(), - min_selectable: int=1, - max_selectable: int=1, - sort_options: bool=False, - allow_no_selection: bool=False - ) -> Union[UiDialogBase, None]: - """build_dialog(\ - on_submit=CommonFunctionUtils.noop,\ - picker_type=UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT,\ - page=1,\ - sim_info=None,\ - categories=(),\ - min_selectable=1,\ - max_selectable=1,\ - sort_options=False,\ - allow_no_selection=False\ - ) - - Build the dialog and invoke the callbacks upon the player submitting their selection. - - :param on_submit: When the dialog is submitted, this callback will be invoked with the chosen options. - :type on_submit: Callable[[Tuple[DialogOptionValueType]], Any], optional - :param picker_type: The layout of the dialog. Default is UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT. - :type picker_type: UiObjectPicker.UiObjectPickerObjectPickerType, optional - :param page: The page to display. Ignored if there is only one page of choices. Default is 1. - :type page: int, optional - :param sim_info: The SimInfo of the Sim that will appear in the dialog image. If None, it will be the active Sim. Default is None. - :type sim_info: SimInfo, optional - :param categories: A collection of categories do display in the dialog. Default is an empty collection. - :type categories: Iterator[CommonDialogObjectOptionCategory], optional - :param min_selectable: The minimum number of options that can be chosen. - :type min_selectable: int, optional - :param max_selectable: The maximum number of options that can be chosen. - :type max_selectable: int, optional - :param sort_options: If True, options will be sorted by display name, with the selected options on top. If False, options will not be sorted. Default is False. - :type sort_options: bool, optional - :param allow_no_selection: If True, the player may select no options. If False, the dialog will close with no options selected. Default is False. - :type allow_no_selection: bool, optional - :return: The built dialog or None if a problem occurs. - :rtype: Union[UiDialogBase, None] - """ - return super().build_dialog( - picker_type=picker_type, - page=page, - sim_info=sim_info, - categories=categories, - on_submit=on_submit, - min_selectable=min_selectable, - max_selectable=max_selectable, - sort_rows=sort_options, - allow_no_selection=allow_no_selection - ) - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_testing.show_choose_objects_option_dialog', - 'Show an example of CommonChooseObjectsOptionDialog.' -) -def _common_testing_show_choose_objects_option_dialog(output: CommonConsoleCommandOutput): - output('Showing test choose objects option dialog.') - - def _on_option_chosen(option_identifier: str, choice: str): - output('Chose option {} with value: {}.'.format(pformat(option_identifier), pformat(choice))) - - def _on_submit(choices: Tuple[str]): - output('Chose options {}.'.format(pformat(choices))) - - # 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 = CommonChooseObjectsOptionDialog( - 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 s4ap.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( - on_submit=_on_submit, - sim_info=CommonSimUtils.get_active_sim_info(), - min_selectable=1, - max_selectable=2 - ) - output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_option_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_option_dialog.py deleted file mode 100644 index 7d99997..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_option_dialog.py +++ /dev/null @@ -1,129 +0,0 @@ -""" -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 -""" -from typing import Any, Callable, Union -from s4ap.sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome -from s4ap.sims4communitylib.dialogs.common_choose_dialog import CommonChooseDialog -from s4ap.sims4communitylib.dialogs.option_dialogs.common_option_dialog import CommonOptionDialog -from s4ap.sims4communitylib.dialogs.option_dialogs.options.common_dialog_option import CommonDialogOption -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from ui.ui_dialog import UiDialogBase - - -class CommonChooseOptionDialog(CommonOptionDialog): - """CommonChooseOptionDialog(\ - internal_dialog,\ - on_close=CommonFunctionUtils.noop\ - ) - - A dialog that displays a list of options. - - .. warning:: Unless you know what you are doing, do not create an instance of this class directly! - - :param internal_dialog: The dialog this option dialog wraps. - :type internal_dialog: CommonChooseDialog - :param on_close: A callback invoked upon the dialog closing. - :type on_close: Callable[[], None], optional - """ - def __init__( - self, - internal_dialog: CommonChooseDialog, - on_close: Callable[[], None]=CommonFunctionUtils.noop - ): - super().__init__( - internal_dialog, - on_close=on_close - ) - self._options = [] - - @property - def option_count(self) -> int: - """The number of options within the dialog. - - :return: The number of options within the dialog. - :rtype: int - """ - return len(self._options) - - @property - def _internal_dialog(self) -> CommonChooseDialog: - result: CommonChooseDialog = super()._internal_dialog - return result - - def has_options(self) -> bool: - """has_options() - - Determine if the dialog has selectable options. - - :return: True, if the dialog has any options in it. False, if not. - :rtype: bool - """ - try: - return self.option_count > 0 - except Exception as ex: - self.log.error('has_options', exception=ex) - return False - - def add_option(self, option: CommonDialogOption): - """add_option(option) - - Add an option to the dialog. - - :param option: The option to add. - :type option: CommonDialogOption - """ - try: - if self._internal_dialog is None or not hasattr(self._internal_dialog, 'add_row'): - return - self._options.append(option) - self._add_row(option) - except Exception as ex: - self.log.error('add_option', exception=ex) - - def _add_row(self, option: CommonDialogOption): - self._internal_dialog.add_row(option.as_row(len(self._options))) - - def show(self, *_: Any, **__: Any): - """show(*_, **__) - - Show the dialog. - - .. note:: Override this function to provide your own arguments. - - """ - try: - return self._internal_dialog.show(*_, on_chosen=self._on_chosen(), **__) - except Exception as ex: - self.log.error('choose_option.show', exception=ex) - - def build_dialog(self, *_: Any, **__: Any) -> Union[UiDialogBase, None]: - """build_dialog(*_, **__) - - Build the dialog. - - .. note:: Override this function to provide your own arguments. - - :return: The built dialog or None if a problem occurs. - :rtype: Union[UiDialogBase, None] - """ - try: - return self._internal_dialog.build_dialog(*_, on_chosen=self._on_chosen(), **__) - except Exception as ex: - self.log.error('choose_option.build_dialog', exception=ex) - return None - - def _on_chosen(self) -> Callable[[CommonDialogOption, CommonChoiceOutcome], bool]: - def _on_chosen(chosen_option: CommonDialogOption, outcome: CommonChoiceOutcome) -> bool: - try: - if chosen_option is None or CommonChoiceOutcome.is_error_or_cancel(outcome): - self.close() - return False - return chosen_option.choose() - except Exception as ex: - self.log.error('Error occurred on choosing a value.', exception=ex) - return False - return _on_chosen diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_options_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_options_dialog.py deleted file mode 100644 index 6f80ff2..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_options_dialog.py +++ /dev/null @@ -1,160 +0,0 @@ -""" -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 -""" -from typing import Union, Tuple, Any, Callable, List - -from s4ap.sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome -from s4ap.sims4communitylib.dialogs.common_choose_dialog import CommonChooseDialog -from s4ap.sims4communitylib.dialogs.option_dialogs.common_choose_option_dialog import CommonChooseOptionDialog -from s4ap.sims4communitylib.dialogs.option_dialogs.options.common_dialog_option import CommonDialogOption -from s4ap.sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import DialogOptionValueType -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils - - -# noinspection PyMissingOrEmptyDocstring -from ui.ui_dialog import UiDialogBase - - -class CommonChooseOptionsDialog(CommonChooseOptionDialog): - """CommonChooseOptionsDialog(\ - internal_dialog,\ - on_close=CommonFunctionUtils.noop\ - ) - - A dialog that displays a list of options and prompts to select multiple items. - - .. warning:: Unless you know what you are doing, do not create an instance of this class directly! - - :param internal_dialog: The dialog this option dialog wraps. - :type internal_dialog: CommonChooseDialog - :param on_close: A callback invoked upon the dialog closing. - :type on_close: Callable[[], None], optional - """ - def __init__( - self, - internal_dialog: CommonChooseDialog, - on_close: Callable[[], None]=CommonFunctionUtils.noop - ): - super().__init__( - internal_dialog, - on_close=on_close - ) - - def show( - self, - *_, - on_submit: Callable[[Tuple[DialogOptionValueType]], Any]=CommonFunctionUtils.noop, - min_selectable: int=1, - max_selectable: int=1, - allow_no_selection: bool=False, - **__ - ): - """show(\ - *_,\ - on_submit=CommonFunctionUtils.noop,\ - min_selectable=1,\ - max_selectable=1,\ - allow_no_selection=False,\ - **__\ - ) - - Show the dialog. - - .. note:: Override this function to provide your own arguments. - - :param on_submit: When the dialog is submitted, this callback will be invoked with the chosen options. - :type on_submit: Callable[[Tuple[DialogOptionValueType]], Any], optional - :param min_selectable: The minimum number of options that can be chosen. - :type min_selectable: int, optional - :param max_selectable: The maximum number of options that can be chosen. - :type max_selectable: int, optional - :param allow_no_selection: If True, the player may select no options. If False, the dialog will close with no options selected. Default is False. - :type allow_no_selection: bool, optional - """ - try: - return self._internal_dialog.show( - *_, - on_chosen=self._on_submit(on_submit, allow_no_selection=allow_no_selection), - min_selectable=min_selectable, - max_selectable=max_selectable, - **__ - ) - except Exception as ex: - self.log.error('choose_options.show', exception=ex) - - def build_dialog( - self, - *_: Any, - on_submit: Callable[[Tuple[DialogOptionValueType]], Any]=CommonFunctionUtils.noop, - min_selectable: int=1, - max_selectable: int=1, - allow_no_selection: bool=False, - **__: Any - ) -> Union[UiDialogBase, None]: - """build_dialog(\ - *_,\ - on_submit=CommonFunctionUtils.noop,\ - min_selectable=1,\ - max_selectable=1,\ - allow_no_selection=False,\ - **__\ - ) - - Build the dialog. - - .. note:: Override this function to provide your own arguments. - - :param on_submit: When the dialog is submitted, this callback will be invoked with the chosen options. - :type on_submit: Callable[[Tuple[DialogOptionValueType]], Any], optional - :param min_selectable: The minimum number of options that can be chosen. - :type min_selectable: int, optional - :param max_selectable: The maximum number of options that can be chosen. - :type max_selectable: int, optional - :param allow_no_selection: If True, the player may select no options. If False, the dialog will close with no options selected. Default is False. - :type allow_no_selection: bool, optional - :return: The built dialog or None if a problem occurs. - :rtype: Union[UiDialogBase, None] - """ - try: - - return self._internal_dialog.build_dialog( - *_, - on_chosen=self._on_submit(on_submit, allow_no_selection=allow_no_selection), - min_selectable=min_selectable, - max_selectable=max_selectable, - **__ - ) - except Exception as ex: - self.log.error('choose_options.build_dialog', exception=ex) - return None - - def _on_chosen(self) -> Callable[[Union[Tuple[CommonDialogOption], None], CommonChoiceOutcome], bool]: - return self._on_submit() - - def _on_submit( - self, - on_submit: Callable[[Tuple[DialogOptionValueType]], Any]=CommonFunctionUtils.noop, - allow_no_selection: bool=False - ) -> Callable[[Union[Tuple[CommonDialogOption], None], CommonChoiceOutcome], bool]: - def _on_submit(chosen_options: Union[Tuple[CommonDialogOption], None], outcome: CommonChoiceOutcome) -> bool: - try: - if chosen_options is None or CommonChoiceOutcome.is_error_or_cancel(outcome): - self.close() - return True - if not allow_no_selection: - if len(chosen_options) == 0: - self.close() - return True - chosen_values: List[DialogOptionValueType] = list() - for chosen_option in chosen_options: - chosen_values.append(chosen_option.value) - chosen_option.choose() - return on_submit(tuple(chosen_values)) - except Exception as ex: - self.log.error('Error occurred on submitting a value.', exception=ex) - return False - return _on_submit diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_response_option_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_response_option_dialog.py deleted file mode 100644 index 46f2d44..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_response_option_dialog.py +++ /dev/null @@ -1,140 +0,0 @@ -""" -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 -""" -from typing import Any, Callable, Union -from s4ap.sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome -from s4ap.sims4communitylib.dialogs.common_choose_response_dialog import CommonChooseResponseDialog -from s4ap.sims4communitylib.dialogs.common_ui_response_dialog import CommonUiResponseDialog -from s4ap.sims4communitylib.dialogs.option_dialogs.common_option_dialog import CommonOptionDialog -from s4ap.sims4communitylib.dialogs.option_dialogs.options.response.common_dialog_response_option import \ - CommonDialogResponseOption -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils - - -class CommonChooseResponseOptionDialog(CommonOptionDialog): - """CommonChooseResponseOptionDialog(\ - internal_dialog,\ - include_previous_button=True,\ - on_previous=CommonFunctionUtils.noop\ - on_close=CommonFunctionUtils.noop\ - ) - - A dialog that displays a list of options. - - .. warning:: Unless you know what you are doing, do not create an instance of this class directly! - - :param internal_dialog: The dialog this option dialog wraps. - :type internal_dialog: CommonChooseResponseDialog - :param include_previous_button: If True, the Previous button will be appended to the end of the dialog. Default is True. - :type include_previous_button: bool, optional - :param on_previous: A callback invoked upon the Previous response being chosen. Default is no operation. - :type on_previous: Callable[[], None], optional - :param on_close: A callback invoked upon the dialog closing. - :type on_close: Callable[[], None], optional - """ - def __init__( - self, - internal_dialog: CommonChooseResponseDialog, - include_previous_button: bool=True, - on_previous: Callable[[], None]=CommonFunctionUtils.noop, - on_close: Callable[[], None]=CommonFunctionUtils.noop - ): - super().__init__( - internal_dialog, - on_close=on_close - ) - self._include_previous_button = include_previous_button - self._on_previous = on_previous - self._options = [] - - @property - def option_count(self) -> int: - """The number of options within the dialog. - - :return: The number of options within the dialog. - :rtype: int - """ - return len(self._options) - - @property - def _internal_dialog(self) -> CommonChooseResponseDialog: - result: CommonChooseResponseDialog = super()._internal_dialog - return result - - def has_options(self) -> bool: - """has_options() - - Determine if the dialog has selectable options. - - :return: True, if the dialog has any options in it. False, if not. - :rtype: bool - """ - try: - return self.option_count > 0 - except Exception as ex: - self.log.error('has_options', exception=ex) - return False - - def add_option(self, option: CommonDialogResponseOption): - """add_option(option) - - Add an option to the dialog. - - :param option: The option to add. - :type option: CommonDialogResponseOption - """ - try: - if self._internal_dialog is None or not hasattr(self._internal_dialog, 'add_response'): - return - self._options.append(option) - self._add_response(option) - except Exception as ex: - self.log.error('add_option', exception=ex) - - def _add_response(self, option: CommonDialogResponseOption): - self._internal_dialog.add_response(option.as_response(len(self._options))) - - def show(self, *_: Any, **__: Any): - """show(*_, **__) - - Show the dialog. - - .. note:: Override this function to provide your own arguments. - - """ - try: - return self._internal_dialog.show(*_, on_chosen=self._on_chosen(), include_previous_button=self._include_previous_button, on_previous=self._on_previous, **__) - except Exception as ex: - self.log.error('choose_response_option.show', exception=ex) - - def build_dialog(self, *_: Any, **__: Any) -> Union[CommonUiResponseDialog, None]: - """build_dialog(*_, **__) - - Build the dialog. - - .. note:: Override this function to provide your own arguments. - - :return: The built dialog or None if a problem occurs. - :rtype: Union[CommonUiResponseDialog, None] - """ - try: - return self._internal_dialog.build_dialog(*_, on_chosen=self._on_chosen(), include_previous_button=self._include_previous_button, on_previous=self._on_previous, **__) - except Exception as ex: - self.log.error('choose_response_option.build_dialog', exception=ex) - return None - - def _on_chosen(self) -> Callable[[CommonDialogResponseOption, CommonChoiceOutcome], None]: - def _on_chosen(chosen_option: CommonDialogResponseOption, outcome: CommonChoiceOutcome) -> None: - try: - if chosen_option is None or CommonChoiceOutcome.is_error_or_cancel(outcome): - self.close() - return - chosen_option.choose() - return - except Exception as ex: - self.log.error('Error occurred on choosing a value.', exception=ex) - return _on_chosen diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_sim_option_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_sim_option_dialog.py deleted file mode 100644 index 7e03e23..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_sim_option_dialog.py +++ /dev/null @@ -1,275 +0,0 @@ -""" -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 -""" -import random -from typing import Any, Union, Callable, Iterator - -from protocolbuffers.Localization_pb2 import LocalizedString -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.dialogs.common_choose_sim_dialog import CommonChooseSimDialog -from s4ap.sims4communitylib.dialogs.option_dialogs.common_choose_option_dialog import CommonChooseOptionDialog -from s4ap.sims4communitylib.dialogs.option_dialogs.options.sims.common_dialog_sim_option_context import \ - CommonDialogSimOptionContext -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from s4ap.sims4communitylib.dialogs.option_dialogs.options.sims.common_dialog_sim_option import CommonDialogSimOption -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from ui.ui_dialog import UiDialogBase - - -class CommonChooseSimOptionDialog(CommonChooseOptionDialog): - """CommonChooseSimOptionDialog(\ - title_identifier,\ - description_identifier,\ - title_tokens=(),\ - description_tokens=(),\ - on_close=CommonFunctionUtils.noop,\ - mod_identity=None,\ - required_tooltip=None,\ - required_tooltip_tokens=()\ - ) - - A dialog that displays a list of Sims for selection. - - .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_choose_sim_option_dialog` in the in-game console. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - def _on_chosen(_sim_info: SimInfo): - 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 - ), - ) - - # Create the dialog and show a number of Sims in 4 columns. - option_dialog = CommonChooseSimOptionDialog( - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - title_tokens=title_tokens, - description_tokens=description_tokens, - mod_identity=ModInfo.get_identity() - ) - - current_count = 0 - count = 25 - - for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): - if current_count >= count: - break - should_select = random.choice((True, False)) - is_enabled = random.choice((True, False)) - option_dialog.add_option( - CommonDialogSimOption( - sim_info, - CommonDialogSimOptionContext( - is_enabled=is_enabled, - is_selected=should_select - ), - on_chosen=_on_chosen - ) - ) - - option_dialog.show( - sim_info=CommonSimUtils.get_active_sim_info(), - column_count=4 - ) - - :param title_identifier: A decimal identifier of the title text. - :type title_identifier: Union[int, str, LocalizedString, CommonStringId] - :param description_identifier: A decimal identifier of the description text. - :type description_identifier: Union[int, str, LocalizedString, CommonStringId] - :param title_tokens: An iterator of Tokens to format into the title. - :type title_tokens: Iterator[Any], optional - :param description_tokens: An iterator of Tokens to format into the description. - :type description_tokens: Iterator[Any], optional - :param on_close: A callback invoked upon the dialog closing. - :type on_close: Callable[[], None], optional - :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. - :type mod_identity: CommonModIdentity, optional - :param required_tooltip: If provided, this text will display when the dialog requires at least one choice and a choice has not been made. Default is None. - :type required_tooltip: Union[int, str, LocalizedString, CommonStringId], optional - :param required_tooltip_tokens: Tokens to format into the required tooltip. Default is an empty collection. - :type required_tooltip_tokens: Iterator[Any], optional - """ - def __init__( - self, - title_identifier: Union[int, str, LocalizedString, CommonStringId], - description_identifier: Union[int, str, LocalizedString, CommonStringId], - title_tokens: Iterator[Any]=(), - description_tokens: Iterator[Any]=(), - on_close: Callable[[], None]=CommonFunctionUtils.noop, - mod_identity: CommonModIdentity=None, - required_tooltip: Union[int, str, LocalizedString, CommonStringId]=None, - required_tooltip_tokens: Iterator[Any]=() - ): - super().__init__( - CommonChooseSimDialog( - title_identifier, - description_identifier, - tuple(), - title_tokens=title_tokens, - description_tokens=description_tokens, - mod_identity=mod_identity, - required_tooltip=required_tooltip, - required_tooltip_tokens=required_tooltip_tokens - ), - on_close=on_close - ) - - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - return 's4cl_choose_sim_option_dialog' - - def add_option(self, option: CommonDialogSimOption): - """add_option(option) - - Add an option to the dialog. - - :param option: The option to add. - :type option: CommonDialogSimOption - """ - return super().add_option(option) - - def show( - self, - sim_info: SimInfo=None, - should_show_names: bool=True, - hide_row_descriptions: bool=False, - column_count: int=3 - ): - """show(sim_info=None, should_show_names=True, hide_row_descriptions=False, column_count=3) - - Show the dialog. - - :param sim_info: The SimInfo of the Sim that will appear in the dialog image. The default Sim is the active Sim. - :type sim_info: SimInfo, optional - :param should_show_names: If True, then the names of the Sims will display in the dialog. - :type should_show_names: bool, optional - :param hide_row_descriptions: A flag to hide the row descriptions. - :type hide_row_descriptions: bool, optional - :param column_count: The number of columns to display Sims in. - :type column_count: int, optional - """ - return super().show( - sim_info=sim_info, - should_show_names=should_show_names, - hide_row_descriptions=hide_row_descriptions, - column_count=column_count - ) - - def build_dialog( - self, - sim_info: SimInfo=None, - should_show_names: bool=True, - hide_row_descriptions: bool=False, - column_count: int=3 - ) -> Union[UiDialogBase, None]: - """build_dialog(sim_info=None, should_show_names=True, hide_row_descriptions=False, column_count=3) - - Build the dialog. - - :param sim_info: The SimInfo of the Sim that will appear in the dialog image. The default Sim is the active Sim. Default is None. - :type sim_info: SimInfo, optional - :param should_show_names: If True, then the names of the Sims will display in the dialog. Default is True. - :type should_show_names: bool, optional - :param hide_row_descriptions: A flag to hide the row descriptions. Default is False. - :type hide_row_descriptions: bool, optional - :param column_count: The number of columns to display Sims in. Default is 3. - :type column_count: int, optional - :return: The built dialog or None if a problem occurs. - :rtype: Union[UiDialogBase, None] - """ - return super().build_dialog( - sim_info=sim_info, - should_show_names=should_show_names, - hide_row_descriptions=hide_row_descriptions, - column_count=column_count - ) - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_testing.show_choose_sim_option_dialog', - 'Show an example of CommonChooseSimOptionDialog.' -) -def _common_testing_show_choose_sim_option_dialog(output: CommonConsoleCommandOutput): - output('Showing test choose sim option dialog.') - - def _on_chosen(_sim_info: SimInfo): - output('Chose Sim with name \'{}\''.format(CommonSimNameUtils.get_full_name(_sim_info))) - - # 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 - ), - ) - - # Create the dialog and show a number of Sims in 4 columns. - option_dialog = CommonChooseSimOptionDialog( - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - title_tokens=title_tokens, - description_tokens=description_tokens, - mod_identity=ModInfo.get_identity() - ) - - current_count = 0 - count = 25 - - for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): - if current_count >= count: - break - should_select = random.choice((True, False)) - is_enabled = random.choice((True, False)) - option_dialog.add_option( - CommonDialogSimOption( - sim_info, - CommonDialogSimOptionContext( - is_enabled=is_enabled, - is_selected=should_select - ), - on_chosen=_on_chosen - ) - ) - - option_dialog.show( - sim_info=CommonSimUtils.get_active_sim_info(), - column_count=4 - ) - output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_sims_option_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_sims_option_dialog.py deleted file mode 100644 index 77a3a88..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_choose_sims_option_dialog.py +++ /dev/null @@ -1,306 +0,0 @@ -""" -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 -""" -import random -from typing import Any, Tuple, Union, Callable, Iterator - -from protocolbuffers.Localization_pb2 import LocalizedString -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.dialogs.common_choose_sims_dialog import CommonChooseSimsDialog -from s4ap.sims4communitylib.dialogs.option_dialogs.common_choose_options_dialog import CommonChooseOptionsDialog -from s4ap.sims4communitylib.dialogs.option_dialogs.options.sims.common_dialog_sim_option_context import \ - CommonDialogSimOptionContext -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from s4ap.sims4communitylib.dialogs.option_dialogs.options.sims.common_dialog_sim_option import CommonDialogSimOption -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from ui.ui_dialog import UiDialogBase - - -class CommonChooseSimsOptionDialog(CommonChooseOptionsDialog): - """CommonChooseSimsOptionDialog(\ - title_identifier,\ - description_identifier,\ - title_tokens=(),\ - description_tokens=(),\ - on_close=CommonFunctionUtils.noop,\ - mod_identity=None,\ - required_tooltip=None,\ - required_tooltip_tokens=()\ - ) - - A dialog that displays a list of Sims for selection and prompts to select multiple Sims. - - .. note:: This dialog allows selection of multiple Sims. - - .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_choose_sims_option_dialog` in the in-game console. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - def _on_submit(sim_info_list: Tuple[SimInfo]): - 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 - ), - ) - - # Create the dialog and show a number of Sims in 4 columns and being able to select up to 5 Sims. - option_dialog = CommonChooseSimsOptionDialog( - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - title_tokens=title_tokens, - description_tokens=description_tokens, - mod_identity=ModInfo.get_identity() - ) - - current_count = 0 - count = 25 - - for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): - if current_count >= count: - break - should_select = random.choice((True, False)) - is_enabled = random.choice((True, False)) - option_dialog.add_option( - CommonDialogSimOption( - sim_info, - CommonDialogSimOptionContext( - is_enabled=is_enabled, - is_selected=should_select - ) - ) - ) - - option_dialog.show( - sim_info=CommonSimUtils.get_active_sim_info(), - column_count=4, - max_selectable=5, - on_submit=_on_submit - ) - - :param title_identifier: A decimal identifier of the title text. - :type title_identifier: Union[int, str, LocalizedString, CommonStringId] - :param description_identifier: A decimal identifier of the description text. - :type description_identifier: Union[int, str, LocalizedString, CommonStringId] - :param title_tokens: An iterator of Tokens to format into the title. - :type title_tokens: Iterator[Any], optional - :param description_tokens: An iterator of Tokens to format into the description. - :type description_tokens: Iterator[Any], optional - :param on_close: A callback invoked upon the dialog closing. - :type on_close: Callable[[], None], optional - :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. - :type mod_identity: CommonModIdentity, optional - :param required_tooltip: If provided, this text will display when the dialog requires at least one choice and a choice has not been made. Default is None. - :type required_tooltip: Union[int, str, LocalizedString, CommonStringId], optional - :param required_tooltip_tokens: Tokens to format into the required tooltip. Default is an empty collection. - :type required_tooltip_tokens: Iterator[Any], optional - """ - def __init__( - self, - title_identifier: Union[int, str, LocalizedString, CommonStringId], - description_identifier: Union[int, str, LocalizedString, CommonStringId], - title_tokens: Iterator[Any]=(), - description_tokens: Iterator[Any]=(), - on_close: Callable[[], None]=CommonFunctionUtils.noop, - mod_identity: CommonModIdentity=None, - required_tooltip: Union[int, str, LocalizedString, CommonStringId]=None, - required_tooltip_tokens: Iterator[Any]=() - ): - super().__init__( - CommonChooseSimsDialog( - title_identifier, - description_identifier, - tuple(), - title_tokens=title_tokens, - description_tokens=description_tokens, - mod_identity=mod_identity, - required_tooltip=required_tooltip, - required_tooltip_tokens=required_tooltip_tokens - ), - on_close=on_close - ) - - # noinspection PyMissingOrEmptyDocstring - def add_option(self, option: CommonDialogSimOption): - return super().add_option(option) - - def show( - self, - on_submit: Callable[[Tuple[SimInfo]], Any]=CommonFunctionUtils.noop, - sim_info: SimInfo=None, - should_show_names: bool=True, - hide_row_descriptions: bool=False, - column_count: int=3, - min_selectable: int=1, - max_selectable: int=1 - ): - """show(\ - on_submit=CommonFunctionUtils.noop,\ - sim_info=None,\ - should_show_names=True,\ - hide_row_descriptions=False,\ - column_count=3,\ - min_selectable=1,\ - max_selectable=1,\ - ) - - Show the dialog and invoke the callbacks upon the player submitting their selection. - - :param on_submit: A callback invoked upon the player choosing Sims. Default is CommonFunctionUtils.noop. - :type on_submit: Callable[[Tuple[SimInfo]], Any], optional - :param sim_info: The SimInfo of the Sim that will appear in the dialog image. If None, it will be the active Sim. Default is None. - :type sim_info: SimInfo, optional - :param should_show_names: If True, then the names of the Sims will display in the dialog. Default is True. - :type should_show_names: bool, optional - :param hide_row_descriptions: A flag to hide the row descriptions. Default is False. - :type hide_row_descriptions: bool, optional - :param column_count: The number of columns to display Sims in. Default is 3. - :type column_count: int, optional - :param min_selectable: The minimum number of Sims that must be chosen. Default is 1. - :type min_selectable: int, optional - :param max_selectable: The maximum number of Sims that can be chosen. Default is 1. - :type max_selectable: int, optional - """ - return super().show( - on_submit=on_submit, - sim_info=sim_info, - should_show_names=should_show_names, - hide_row_descriptions=hide_row_descriptions, - column_count=column_count, - min_selectable=min_selectable, - max_selectable=max_selectable - ) - - def build_dialog( - self, - on_submit: Callable[[Tuple[SimInfo]], Any]=CommonFunctionUtils.noop, - sim_info: SimInfo=None, - should_show_names: bool=True, - hide_row_descriptions: bool=False, - column_count: int=3, - min_selectable: int=1, - max_selectable: int=1 - ) -> Union[UiDialogBase, None]: - """build_dialog(\ - on_submit=CommonFunctionUtils.noop,\ - sim_info=None,\ - should_show_names=True,\ - hide_row_descriptions=False,\ - column_count=3,\ - min_selectable=1,\ - max_selectable=1,\ - ) - - Show the dialog and invoke the callbacks upon the player submitting their selection. - - :param on_submit: A callback invoked upon the player choosing Sims. Default is CommonFunctionUtils.noop. - :type on_submit: Callable[[Tuple[SimInfo]], Any], optional - :param sim_info: The SimInfo of the Sim that will appear in the dialog image. If None, it will be the active Sim. Default is None. - :type sim_info: SimInfo, optional - :param should_show_names: If True, then the names of the Sims will display in the dialog. Default is True. - :type should_show_names: bool, optional - :param hide_row_descriptions: A flag to hide the row descriptions. Default is False. - :type hide_row_descriptions: bool, optional - :param column_count: The number of columns to display Sims in. Default is 3. - :type column_count: int, optional - :param min_selectable: The minimum number of Sims that must be chosen. Default is 1. - :type min_selectable: int, optional - :param max_selectable: The maximum number of Sims that can be chosen. Default is 1. - :type max_selectable: int, optional - :return: The built dialog or None if a problem occurs. - :rtype: Union[UiDialogBase, None] - """ - return super().build_dialog( - on_submit=on_submit, - sim_info=sim_info, - should_show_names=should_show_names, - hide_row_descriptions=hide_row_descriptions, - column_count=column_count, - min_selectable=min_selectable, - max_selectable=max_selectable - ) - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_testing.show_choose_sims_option_dialog', - 'Show an example of CommonChooseSimsOptionDialog.' -) -def _common_testing_show_choose_sims_option_dialog(output: CommonConsoleCommandOutput): - output('Showing test choose sims option dialog.') - - def _on_submit(sim_info_list: Tuple[SimInfo]): - output('Chose Sims with names {}'.format(CommonSimNameUtils.get_full_names(sim_info_list))) - - # 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 - ), - ) - - # Create the dialog and show a number of Sims in 4 columns and being able to select up to 5 Sims. - option_dialog = CommonChooseSimsOptionDialog( - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - title_tokens=title_tokens, - description_tokens=description_tokens, - mod_identity=ModInfo.get_identity() - ) - - current_count = 0 - count = 25 - - for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): - if current_count >= count: - break - is_enabled = random.choice((True, False)) - option_dialog.add_option( - CommonDialogSimOption( - sim_info, - CommonDialogSimOptionContext( - is_enabled=is_enabled - ) - ) - ) - - option_dialog.show( - sim_info=CommonSimUtils.get_active_sim_info(), - column_count=4, - max_selectable=5, - on_submit=_on_submit - ) - output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_multi_pane_choose_option_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_multi_pane_choose_option_dialog.py deleted file mode 100644 index 9872b9d..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_multi_pane_choose_option_dialog.py +++ /dev/null @@ -1,468 +0,0 @@ -""" -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 -""" -from pprint import pformat - -from typing import Any, Union, Callable, Iterator, Dict, Tuple, List - -from protocolbuffers.Localization_pb2 import LocalizedString -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome -from s4ap.sims4communitylib.dialogs.common_multi_pane_choose_dialog import CommonMultiPaneChooseDialog -from s4ap.sims4communitylib.dialogs.option_dialogs.common_choose_object_option_dialog import CommonChooseObjectOptionDialog -from s4ap.sims4communitylib.dialogs.option_dialogs.common_choose_option_dialog import CommonChooseOptionDialog -from s4ap.sims4communitylib.dialogs.option_dialogs.common_option_dialog import CommonOptionDialog -from s4ap.sims4communitylib.dialogs.option_dialogs.options.common_dialog_option import CommonDialogOption -from s4ap.sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext, \ - DialogOptionValueType -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from s4ap.sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_object_option import CommonDialogObjectOption -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils -from ui.ui_dialog import UiDialogBase - - -class CommonMultiPaneChooseOptionDialog(CommonOptionDialog): - """CommonMultiPaneChooseOptionDialog(\ - mod_identity,\ - title_identifier,\ - description_identifier,\ - title_tokens=(),\ - description_tokens=(),\ - on_close=CommonFunctionUtils.noop\ - ) - - A container for multiple choose option dialogs. - - .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_multi_pane_choose_option_dialog` in the in-game console. - - .. warning:: This dialog does not currently work with `CommonChooseSimOptionDialog` or `CommonChooseSimsOptionDialog`. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - def _on_option_chosen_in_dialog_one(option_identifier: str, choice: str): - pass - - def _on_option_chosen_in_dialog_two(option_identifier: str, choice: str): - pass - - def _on_submit(chosen_options: Dict[int, Any]): - 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 - ), - ) - - sub_dialog_one = 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 - ) - - sub_dialog_one.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_in_dialog_one - ) - ) - - sub_dialog_one.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_in_dialog_one - ) - ) - - sub_dialog_one.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_in_dialog_one - ) - ) - - sub_dialog_two = 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 - ) - - sub_dialog_two.add_option( - CommonDialogObjectOption( - 'Option 4', - 'Value 4', - CommonDialogOptionContext( - CommonStringId.TESTING_SOME_TEXT_FOR_TESTING, - CommonStringId.TESTING_TEST_BUTTON_ONE, - icon=CommonIconUtils.load_checked_square_icon() - ), - on_chosen=_on_option_chosen_in_dialog_two - ) - ) - - sub_dialog_two.add_option( - CommonDialogObjectOption( - 'Option 5', - 'Value 5', - CommonDialogOptionContext( - CommonStringId.TESTING_SOME_TEXT_FOR_TESTING, - CommonStringId.TESTING_TEST_BUTTON_TWO, - icon=CommonIconUtils.load_arrow_navigate_into_icon() - ), - on_chosen=_on_option_chosen_in_dialog_two - ) - ) - - sub_dialog_two.add_option( - CommonDialogObjectOption( - 'Option 6', - 'Value 6', - CommonDialogOptionContext( - CommonLocalizationUtils.create_localized_string('Value 3'), - CommonStringId.TESTING_TEST_BUTTON_TWO, - icon=CommonIconUtils.load_arrow_navigate_into_icon() - ), - on_chosen=_on_option_chosen_in_dialog_two - ) - ) - - option_dialog = CommonMultiPaneChooseOptionDialog( - ModInfo.get_identity(), - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - title_tokens=title_tokens, - description_tokens=description_tokens - ) - - option_dialog.add_sub_dialog(sub_dialog_one) - option_dialog.add_sub_dialog(sub_dialog_two) - - option_dialog.show( - on_submit=_on_submit, - sim_info=CommonSimUtils.get_active_sim_info() - ) - - - :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. - :type mod_identity: CommonModIdentity - :param title_identifier: A decimal identifier of the title text. - :type title_identifier: Union[int, str, LocalizedString, CommonStringId] - :param description_identifier: A decimal identifier of the description text. - :type description_identifier: Union[int, str, LocalizedString, CommonStringId] - :param title_tokens: An iterator of Tokens to format into the title. Default is an empty collection. - :type title_tokens: Iterator[Any], optional - :param description_tokens: An iterator of Tokens to format into the description. Default is an empty collection. - :type description_tokens: Iterator[Any], optional - :param on_close: A callback invoked upon the dialog closing. Default is CommonFunctionUtils.noop. - :type on_close: Callable[[], None], optional - """ - def __init__( - self, - mod_identity: CommonModIdentity, - title_identifier: Union[int, str, LocalizedString, CommonStringId], - description_identifier: Union[int, str, LocalizedString, CommonStringId], - title_tokens: Iterator[Any]=(), - description_tokens: Iterator[Any]=(), - on_close: Callable[[], None]=CommonFunctionUtils.noop - ): - super().__init__( - CommonMultiPaneChooseDialog( - mod_identity, - title_identifier, - description_identifier, - title_tokens=title_tokens, - description_tokens=description_tokens - ), - on_close=on_close - ) - - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - return 's4cl_multi_pane_choose_option_dialog' - - @property - def _internal_dialog(self) -> CommonMultiPaneChooseDialog: - result: CommonMultiPaneChooseDialog = super()._internal_dialog - return result - - def add_sub_dialog(self, sub_dialog: CommonChooseOptionDialog, *dialog_arguments: Any, **dialog_keyword_arguments: Any): - """add_sub_dialog(sub_dialog, *dialog_arguments, **dialog_keyword_arguments) - - Add a sub dialog. - - :param sub_dialog: An instance of a choose option dialog. - :type sub_dialog: CommonChooseOptionDialog - :param dialog_arguments: Arguments to pass to the sub dialog when building it. - :type dialog_arguments: Any, optional - :param dialog_keyword_arguments: Keyword arguments to pass to the sub dialog when building it. - :type dialog_keyword_arguments: Any, optional - """ - self._internal_dialog.add_sub_dialog(sub_dialog._internal_dialog, *dialog_arguments, **dialog_keyword_arguments) - - def show( - self, - on_submit: Callable[[Dict[int, Tuple[Any]]], Any]=CommonFunctionUtils.noop, - sim_info: SimInfo=None - ): - """show(\ - on_submit=CommonFunctionUtils.noop,\ - sim_info=None\ - ) - - Show the dialog and invoke the callbacks upon the player submitting their selections. - - :param on_submit: A callback invoked upon the player submitting the dialog and the choices within it.\ - Each choice is mapped as follows: The key is the index of the dialog a value belongs to, starting at 0. The value is the choice made within that dialog. Default is CommonFunctionUtils.noop. - :type on_submit: Callable[[Dict[int, Tuple[Any]]], Any], optional - :param sim_info: The SimInfo of the Sim that will appear in the dialog image. The default Sim is the active Sim. Default is None. - :type sim_info: SimInfo, optional - """ - try: - return self._internal_dialog.show(on_submit=self._on_submit(on_submit=on_submit), sim_info=sim_info) - except Exception as ex: - self.log.error('multi_pane_choose_option.show', exception=ex) - - def build_dialog( - self, - on_submit: Callable[[Dict[int, Tuple[Any]]], bool]=CommonFunctionUtils.noop, - sim_info: SimInfo=None - ) -> Union[UiDialogBase, None]: - """build_dialog(\ - on_submit=CommonFunctionUtils.noop,\ - sim_info=None\ - ) - - Build the dialog and invoke the callbacks upon the player submitting their selections. - - :param on_submit: A callback invoked upon the player submitting the dialog and the choices within it.\ - Default is CommonFunctionUtils.noop. Each choice is mapped as follows The key is the dialog index starting at 0. The value is the choice made within that sub dialog. Default is CommonFunctionUtils.noop. - :type on_submit: Callable[[Dict[int, Tuple[Any]]], Any], optional - :param sim_info: The SimInfo of the Sim that will appear in the dialog image. The default Sim is the active Sim. Default is None. - :type sim_info: SimInfo, optional - """ - try: - return self._internal_dialog.build_dialog(on_submit=self._on_submit(on_submit=on_submit), sim_info=sim_info) - except Exception as ex: - self.log.error('multi_pane_choose_option.build_dialog', exception=ex) - return None - - def _on_submit( - self, - on_submit: Callable[[Dict[int, Tuple[Any]]], Any]=CommonFunctionUtils.noop - ) -> Callable[[Dict[int, Tuple[CommonDialogOption]], CommonChoiceOutcome], bool]: - def _on_submit(chosen_options: Dict[int, Tuple[CommonDialogOption]], outcome: CommonChoiceOutcome) -> bool: - try: - if chosen_options is None or not chosen_options or CommonChoiceOutcome.is_error_or_cancel(outcome): - self.log.debug('No options chosen.') - self.close() - return False - - self.log.debug('Chose options: {} with outcome: {}'.format(pformat(chosen_options), pformat(outcome))) - chosen_values: Dict[int, DialogOptionValueType] = dict() - for chosen_option_index in chosen_options: - self.log.debug('Chosen option index: {}'.format(chosen_option_index)) - chosen_option_options = chosen_options[chosen_option_index] - chosen_option_values: List[Any] = list() - for chosen_option_option in chosen_option_options: - chosen_option_values.append(chosen_option_option.value) - self.log.debug('Chose value for option: {}'.format(chosen_option_option.value)) - chosen_option_option.choose() - chosen_values[chosen_option_index] = tuple(chosen_option_values) - - self.log.debug('Submitting choices: {}'.format(pformat(chosen_values))) - return on_submit(chosen_values) - except Exception as ex: - self.log.error('Error occurred on submitting a value.', exception=ex) - return False - return _on_submit - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_testing.show_multi_pane_choose_option_dialog', - 'Show an example of CommonMultiPaneChooseOptionDialog.' -) -def _common_testing_show_multi_pane_choose_option_dialog(output: CommonConsoleCommandOutput): - output('Showing test multi pane choose option dialog.') - - def _on_option_chosen_in_dialog_one(option_identifier: str, choice: str): - output('Chose option in dialog one {} with value: {}.'.format(pformat(option_identifier), pformat(choice))) - - def _on_option_chosen_in_dialog_two(option_identifier: str, choice: str): - output('Chose option in dialog two {} with value: {}.'.format(pformat(option_identifier), pformat(choice))) - - def _on_submit(chosen_options: Dict[int, Any]): - output('Chosen options from all dialogs {}.'.format(pformat(chosen_options))) - - # 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 - ), - ) - - sub_dialog_one = 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 - ) - - sub_dialog_one.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_in_dialog_one - ) - ) - - sub_dialog_one.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_in_dialog_one - ) - ) - - sub_dialog_one.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_in_dialog_one - ) - ) - - sub_dialog_two = 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 - ) - - sub_dialog_two.add_option( - CommonDialogObjectOption( - 'Option 4', - 'Value 4', - CommonDialogOptionContext( - CommonStringId.TESTING_SOME_TEXT_FOR_TESTING, - CommonStringId.TESTING_TEST_BUTTON_ONE, - icon=CommonIconUtils.load_checked_square_icon() - ), - on_chosen=_on_option_chosen_in_dialog_two - ) - ) - - sub_dialog_two.add_option( - CommonDialogObjectOption( - 'Option 5', - 'Value 5', - CommonDialogOptionContext( - CommonStringId.TESTING_SOME_TEXT_FOR_TESTING, - CommonStringId.TESTING_TEST_BUTTON_TWO, - icon=CommonIconUtils.load_arrow_navigate_into_icon() - ), - on_chosen=_on_option_chosen_in_dialog_two - ) - ) - - sub_dialog_two.add_option( - CommonDialogObjectOption( - 'Option 6', - 'Value 6', - CommonDialogOptionContext( - CommonLocalizationUtils.create_localized_string('Value 3'), - CommonStringId.TESTING_TEST_BUTTON_TWO, - icon=CommonIconUtils.load_arrow_navigate_into_icon() - ), - on_chosen=_on_option_chosen_in_dialog_two - ) - ) - - option_dialog = CommonMultiPaneChooseOptionDialog( - ModInfo.get_identity(), - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - title_tokens=title_tokens, - description_tokens=description_tokens - ) - - option_dialog.add_sub_dialog(sub_dialog_one) - option_dialog.add_sub_dialog(sub_dialog_two) - - option_dialog.show( - on_submit=_on_submit, - sim_info=CommonSimUtils.get_active_sim_info() - ) - output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_option_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_option_dialog.py deleted file mode 100644 index 1e80b7f..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/common_option_dialog.py +++ /dev/null @@ -1,95 +0,0 @@ -""" -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 -""" -from typing import Any, Callable, Union -from protocolbuffers.Localization_pb2 import LocalizedString -from s4ap.sims4communitylib.dialogs.common_dialog import CommonDialog -from s4ap.sims4communitylib.logging.has_log import HasLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from ui.ui_dialog import UiDialogBase - - -class CommonOptionDialog(HasLog): - """CommonOptionDialog(\ - internal_dialog,\ - on_close=CommonFunctionUtils.noop\ - ) - - A dialog that displays that displays options. - - .. warning:: Unless you know what you are doing, do not create an instance of this class directly! - - :param internal_dialog: The dialog this option dialog wraps. - :type internal_dialog: CommonDialog - :param on_close: A callback invoked upon the dialog closing. Default is CommonFunctionUtils.noop. - :type on_close: Callable[[], None], optional - """ - def __init__( - self, - internal_dialog: CommonDialog, - on_close: Callable[[], None]=CommonFunctionUtils.noop - ): - super().__init__() - self._on_close = on_close - self.__internal_dialog = internal_dialog - - # noinspection PyMissingOrEmptyDocstring - @property - def mod_identity(self) -> CommonModIdentity: - return self._internal_dialog.mod_identity - - @property - def title(self) -> LocalizedString: - """The title of the dialog. - - :return: The title of the dialog. - :rtype: LocalizedString - """ - return self._internal_dialog.title - - @property - def description(self) -> LocalizedString: - """The description of the dialog. - - :return: The description of the dialog. - :rtype: LocalizedString - """ - return self._internal_dialog.description - - @property - def _internal_dialog(self) -> CommonDialog: - return self.__internal_dialog - - def show(self, *_: Any, **__: Any): - """show(*_, **__) - - Show the dialog. - - .. note:: Override this function to provide your own arguments. - - """ - raise NotImplementedError('\'{}\' not implemented.'.format(self.__class__.show.__name__)) - - def build_dialog(self, *_: Any, **__: Any) -> Union[UiDialogBase, None]: - """build_dialog(*_, **__) - - Build the dialog. - - .. note:: Override this function to provide your own arguments. - - :return: The built dialog or None if a problem occurs. - :rtype: Union[UiDialogBase, None] - """ - raise NotImplementedError('\'{}\' not implemented.'.format(self.__class__.build_dialog.__name__)) - - def close(self) -> None: - """close() - - Close the dialog. - """ - return self._on_close() diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/__init__.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/common_dialog_option.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/common_dialog_option.py deleted file mode 100644 index 3766639..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/common_dialog_option.py +++ /dev/null @@ -1,146 +0,0 @@ -""" -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 -""" -from typing import Any, Callable, Union, Tuple - -from protocolbuffers.Localization_pb2 import LocalizedString -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from ui.ui_dialog_picker import BasePickerRow -from s4ap.sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext, \ - DialogOptionValueType - - -class CommonDialogOption: - """CommonDialogOption(value, context, on_chosen=CommonFunctionUtils.noop) - - An option the player can choose within a dialog. - - :param value: The value of the option. - :type value: DialogOptionValueType - :param context: A context to customize the dialog option. - :type context: CommonDialogOptionContext - :param on_chosen: A callback invoked when the dialog option is chosen. - :type on_chosen: Callable[[DialogOptionValueType], Any], optional - """ - def __init__( - self, - value: DialogOptionValueType, - context: CommonDialogOptionContext, - on_chosen: Callable[[DialogOptionValueType], Any]=CommonFunctionUtils.noop - ): - if context is None: - raise AttributeError('Missing required argument \'context\'') - - self._value = value - self._option_context = context - self._on_chosen = on_chosen - - @property - def title(self) -> LocalizedString: - """The title of the option. - - :return: The title of the option. - :rtype: LocalizedString - """ - return self.context.title - - @property - def description(self) -> LocalizedString: - """The description of the option. - - :return: The description of the option. - :rtype: LocalizedString - """ - return self.context.description - - @property - def tooltip(self) -> Union[CommonLocalizationUtils.LocalizedTooltip, None]: - """The tooltip displayed to the player on hover. - - :return: The tooltip displayed when hovering the option or None if no tooltip specified. - :rtype: Union[CommonLocalizationUtils.LocalizedTooltip, None] - """ - return self.context.tooltip - - @property - def icon(self) -> Any: - """The icon of the option. - - :return: The icon of the option. - :rtype: Any - """ - return self.context.icon - - @property - def tag_list(self) -> Tuple[str]: - """A collection of tags used to filter the option. - - :return: A collection of tags used to filter the option. - :rtype: Tuple[str] - """ - return self.context.tag_list - - @property - def hashed_tag_list(self) -> Tuple[int]: - """Same as tag_list, but the values are hashed. - - :return: Same as tag_list, but the values are hashed. - :rtype: Tuple[str] - """ - return self.context.hashed_tag_list - - @property - def context(self) -> CommonDialogOptionContext: - """The context of the option. - - :return: The context of the option. - :rtype: CommonDialogOptionContext - """ - return self._option_context - - @property - def value(self) -> DialogOptionValueType: - """The value of the option. - - :return: The value of the option. - :rtype: DialogOptionValueType - """ - return self._value - - @property - def on_chosen(self) -> Callable[[DialogOptionValueType], Any]: - """The action to perform upon choosing this option. - - :return: The action to perform upon choosing this option. - :rtype: Callable[[DialogOptionValueType], Any] - """ - return self._on_chosen - - def choose(self) -> Any: - """choose() - - Choose the option. - - :return: The result of choosing the option. - :rtype: Any - """ - if self.on_chosen is None: - return None - return self.on_chosen(self.value) - - def as_row(self, option_id: int) -> BasePickerRow: - """as_row(option_id) - - Convert the option into a picker row. - - :param option_id: The index of the option. - :type option_id: int - :return: The option as a Picker Row - :rtype: BasePickerRow - """ - raise NotImplementedError('\'{}\' not implemented.'.format(self.__class__.as_row.__name__)) diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/common_dialog_option_context.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/common_dialog_option_context.py deleted file mode 100644 index 20e6207..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/common_dialog_option_context.py +++ /dev/null @@ -1,144 +0,0 @@ -""" -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 -""" -from typing import Union, Any, TypeVar, Iterator, Tuple, List -from protocolbuffers.Localization_pb2 import LocalizedString -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils - -DialogOptionValueType = TypeVar('DialogOptionValueType') - - -class CommonDialogOptionContext: - """CommonDialogOptionContext(\ - title_identifier,\ - description_identifier,\ - description_tokens=(),\ - tooltip_text_identifier=None,\ - tooltip_tokens=(),\ - icon=None,\ - is_enabled=True,\ - is_selected=False,\ - tag_list=()\ - ) - - A context used by :class:`.CommonDialogOption` that provides customization of options. - - :param title_identifier: The title of the option. - :type title_identifier: Union[int, str, LocalizedString, CommonStringId] - :param description_identifier: The description of the option. - :type description_identifier: Union[int, str, LocalizedString, CommonStringId] - :param title_tokens: An iterator of Tokens that will be formatted into the title. - :type title_tokens: Iterator[Any], optional - :param description_tokens: An iterator of Tokens that will be formatted into the description. - :type description_tokens: Iterator[Any], optional - :param tooltip_text_identifier: Text that will be displayed upon hovering the option. - :type tooltip_text_identifier: Union[int, str, LocalizedString, CommonStringId], optional - :param tooltip_tokens: An iterator of Tokens that will be formatted into the tooltip text. - :type tooltip_tokens: Tuple[Any], optional - :param icon: The icon to display for the option. - :type icon: Any, optional - :param is_enabled: If True, the dialog option will be selectable in the dialog. If False, the dialog option will be disabled in the dialog. - :type is_enabled: bool, optional - :param is_selected: If True, the dialog option will already be selected in the dialog. If False, the dialog option will not be selected in the dialog. - :type is_selected: bool, optional - """ - def __init__( - self, - title_identifier: Union[int, str, LocalizedString, CommonStringId], - description_identifier: Union[int, str, LocalizedString, CommonStringId], - title_tokens: Iterator[Any]=(), - description_tokens: Iterator[Any]=(), - tooltip_text_identifier: Union[int, str, LocalizedString, CommonStringId]=None, - tooltip_tokens: Iterator[Any]=(), - icon: Any=None, - is_enabled: bool=True, - is_selected: bool=False, - tag_list: Iterator[str]=() - ): - self._title = CommonLocalizationUtils.create_localized_string(title_identifier, tokens=tuple(title_tokens)) - self._description = CommonLocalizationUtils.create_localized_string(description_identifier, tokens=tuple(description_tokens)) - self._tooltip = CommonLocalizationUtils.create_localized_tooltip(tooltip_text_identifier, tooltip_tokens=tuple(tooltip_tokens)) - self._icon = icon - self._is_enabled = is_enabled - self._is_selected = is_selected - self._tag_list = tuple(tag_list) - - @property - def is_enabled(self) -> bool: - """Determine if the dialog option is enabled. - - :return: True, if the dialog option is enabled. False, if not. - :rtype: bool - """ - return self._is_enabled - - @property - def is_selected(self) -> bool: - """Determine if the dialog option is selected. - - :return: True, if the dialog option is selected. False, if not. - :rtype: bool - """ - return self._is_selected - - @property - def title(self) -> LocalizedString: - """The title of the dialog option. - - :return: The title of the dialog option. - :rtype: LocalizedString - """ - return self._title - - @property - def description(self) -> LocalizedString: - """A description of what the dialog option does. - - :return: A description of what the dialog option does. - :rtype: LocalizedString - """ - return self._description - - @property - def tooltip(self) -> Union[CommonLocalizationUtils.LocalizedTooltip, None]: - """The tooltip displayed to the player on hover. - - :return: The tooltip displayed to the player on hover or None if no tooltip was specified. - :rtype: Union[CommonLocalizationUtils.LocalizedTooltip, None] - """ - return self._tooltip - - @property - def tag_list(self) -> Tuple[str]: - """A collection of tags used to filter the option. - - :return: A collection of tags used to filter the option. - :rtype: Tuple[str] - """ - return self._tag_list - - @property - def hashed_tag_list(self) -> Tuple[int]: - """Same as tag_list, but the values are hashed. - - :return: Same as :py:attr:`~tag_list`, but the values are hashed. - :rtype: Tuple[str] - """ - hashed_tag_list: List[int] = list() - for tag in self.tag_list: - hashed_tag_list.append((abs(hash(tag)) % (10 ** 8))) - return tuple(hashed_tag_list) - - @property - def icon(self) -> Any: - """The icon displayed for this dialog option. - - :return: The icon displayed for this dialog option. - :rtype: Any - """ - return self._icon diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/__init__.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_action_option.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_action_option.py deleted file mode 100644 index a7c4e3b..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_action_option.py +++ /dev/null @@ -1,43 +0,0 @@ -""" -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 -""" -from typing import Any, Callable - -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from s4ap.sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext -from s4ap.sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_select_option import CommonDialogSelectOption - - -class CommonDialogActionOption(CommonDialogSelectOption): - """CommonDialogActionOption(context, on_chosen=CommonFunctionUtils.noop, always_visible=False) - - An option that invokes a callback upon being chosen. - - :param context: A context to customize the dialog option. - :type context: CommonDialogOptionContext - :param on_chosen: A callback invoked when the dialog option is chosen. - :type on_chosen: Callable[..., Any], optional - :param always_visible: If set to True, the option will always appear in the dialog no matter which page.\ - If False, the option will act as normal. Default is False. - :type always_visible: bool, optional - """ - def __init__( - self, - context: CommonDialogOptionContext, - on_chosen: Callable[..., Any]=CommonFunctionUtils.noop, - always_visible: bool=False - ): - def _on_chosen(_, __) -> None: - on_chosen() - - super().__init__( - 'Dialog Action', - None, - context, - on_chosen=_on_chosen, - always_visible=always_visible - ) diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_branch_option.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_branch_option.py deleted file mode 100644 index 7b6618e..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_branch_option.py +++ /dev/null @@ -1,50 +0,0 @@ -""" -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 -""" -from typing import Any, Callable -from s4ap.sims4communitylib.dialogs.option_dialogs.common_option_dialog import CommonOptionDialog -from s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils -from s4ap.sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_object_option import CommonDialogObjectOption -from s4ap.sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext - - -class CommonDialogOpenDialogOption(CommonDialogObjectOption): - """CommonDialogOpenDialogOption(create_dialog_callback, context, always_visible=False) - - An option that branches into other options. - - :param create_dialog_callback: A callback invoked when the dialog option is chosen. It should open a dialog. - :type create_dialog_callback: Callable[..., CommonOptionDialog] - :param context: A context to customize the dialog option. - :type context: CommonDialogOptionContext - :param always_visible: If set to True, the option will always appear in the dialog no matter which page.\ - If False, the option will act as normal. Default is False. - :type always_visible: bool, optional - """ - def __init__( - self, - create_dialog_callback: Callable[..., CommonOptionDialog], - context: CommonDialogOptionContext, - always_visible: bool=False - ): - def _on_chosen(_, __) -> None: - create_dialog_callback().show() - - super().__init__( - 'Dialog Branch', - None, - context, - on_chosen=_on_chosen, - always_visible=always_visible - ) - - # noinspection PyMissingOrEmptyDocstring - @property - def icon(self) -> Any: - if super().icon is not None: - return super().icon - return CommonIconUtils.load_arrow_navigate_into_icon() diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_integer_option.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_integer_option.py deleted file mode 100644 index 3e1df43..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_integer_option.py +++ /dev/null @@ -1,107 +0,0 @@ -""" -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 -""" -from typing import Any, Callable, Union, Iterator - -from protocolbuffers.Localization_pb2 import LocalizedString -from s4ap.sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome -from s4ap.sims4communitylib.dialogs.common_input_integer_dialog import CommonInputIntegerDialog -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils -from s4ap.sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_object_option import \ - CommonDialogObjectOption, DialogOptionIdentifierType -from s4ap.sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils - - -class CommonDialogInputIntegerOption(CommonDialogObjectOption): - """CommonDialogInputIntegerOption(\ - mod_identity,\ - option_identifier,\ - initial_value,\ - context,\ - min_value=0,\ - max_value=2147483647,\ - on_chosen=CommonFunctionUtils.noop,\ - always_visible=False,\ - dialog_description_identifier=None,\ - dialog_description_tokens=()\ - ) - - An option to open a dialog to input an integer value. - - :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. - :type mod_identity: CommonModIdentity - :param option_identifier: A string that identifies the option from other options. - :type option_identifier: DialogOptionIdentifierType - :param initial_value: The value the option will have initially - :type initial_value: int - :param context: A context to customize the dialog option. - :type context: CommonDialogOptionContext - :param min_value: The minimum value allowed to be entered. - :type min_value: int, optional - :param max_value: The maximum value allowed to be entered. - :type max_value: int, optional - :param on_chosen: A callback invoked when the dialog option is chosen. args: (option_identifier, entered value, outcome) - :type on_chosen: Callable[[DialogOptionIdentifierType, int, CommonChoiceOutcome], None], optional - :param always_visible: If set to True, the option will always appear in the dialog no matter which page.\ - If False, the option will act as normal. Default is False. - :type always_visible: bool, optional - :param dialog_description_identifier: The description that will display in the input dialog separately from the option.\ - If not provided the description from the provided context will be used instead. - :type dialog_description_identifier: Union[int, str, LocalizedString, CommonStringId], optional - :param dialog_description_tokens: An iterator of Tokens that will be formatted into the dialog description. - :type dialog_description_tokens: Iterator[Any], optional - """ - def __init__( - self, - mod_identity: CommonModIdentity, - option_identifier: DialogOptionIdentifierType, - initial_value: int, - context: CommonDialogOptionContext, - min_value: int=0, - max_value: int=2147483647, - on_chosen: Callable[[DialogOptionIdentifierType, int, CommonChoiceOutcome], None]=CommonFunctionUtils.noop, - always_visible: bool=False, - dialog_description_identifier: Union[int, str, LocalizedString, CommonStringId]=None, - dialog_description_tokens: Iterator[Any]=() - ): - if dialog_description_identifier is not None: - dialog_description = CommonLocalizationUtils.create_localized_string(dialog_description_identifier, tokens=tuple(dialog_description_tokens)) - else: - dialog_description = context.description - self._dialog = CommonInputIntegerDialog( - context.title, - dialog_description, - initial_value, - min_value=min_value, - max_value=max_value, - mod_identity=mod_identity - ) - - def _on_submit(_: int, __: CommonChoiceOutcome): - on_chosen(self.option_identifier, _, __) - - def _on_chosen(_, __) -> None: - self._dialog.show(on_submit=_on_submit) - - super().__init__( - option_identifier, - None, - context, - on_chosen=_on_chosen, - always_visible=always_visible - ) - - # noinspection PyMissingOrEmptyDocstring - @property - def icon(self) -> Any: - if super().icon is not None: - return super().icon - return CommonIconUtils.load_arrow_right_icon() diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_multi_text_option.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_multi_text_option.py deleted file mode 100644 index 12bc6ef..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_multi_text_option.py +++ /dev/null @@ -1,98 +0,0 @@ -""" -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 -""" -from typing import Any, Callable, Union, Iterator, Dict - -from protocolbuffers.Localization_pb2 import LocalizedString -from s4ap.sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome -from s4ap.sims4communitylib.dialogs.common_input_multi_text_dialog import CommonInputMultiTextDialog -from s4ap.sims4communitylib.dialogs.common_input_text_field import CommonInputTextField -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils -from s4ap.sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_object_option import \ - CommonDialogObjectOption, DialogOptionIdentifierType -from s4ap.sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils - - -class CommonDialogInputMultiTextOption(CommonDialogObjectOption): - """CommonDialogInputMultiTextOption(\ - mod_identity,\ - option_identifier,\ - input_fields,\ - context,\ - on_chosen=CommonFunctionUtils.noop,\ - always_visible=False,\ - dialog_description_identifier=None,\ - dialog_description_tokens=()\ - ) - - An option to open a dialog to input a text value. - - :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. - :type mod_identity: CommonModIdentity - :param option_identifier: A string that identifies the option from other options. - :type option_identifier: DialogOptionIdentifierType - :param input_fields: An iterator of input fields to display in the dialog when the option is chosen. - :type input_fields: Iterator[CommonInputTextField] - :param context: A context to customize the dialog option. - :type context: CommonDialogOptionContext - :param on_chosen: A callback invoked when the dialog option is chosen. args: (option_identifier, entered value, outcome) - :type on_chosen: Callable[[DialogOptionIdentifierType, int, CommonChoiceOutcome], None], optional - :param always_visible: If set to True, the option will always appear in the dialog no matter which page.\ - If False, the option will act as normal. Default is False. - :type always_visible: bool, optional - :param dialog_description_identifier: The description that will display in the input dialog separately from the option.\ - If not provided the description from the provided context will be used instead. - :type dialog_description_identifier: Union[int, str, LocalizedString, CommonStringId], optional - :param dialog_description_tokens: An iterator of Tokens that will be formatted into the dialog description. - :type dialog_description_tokens: Iterator[Any], optional - """ - def __init__( - self, - mod_identity: CommonModIdentity, - option_identifier: DialogOptionIdentifierType, - input_fields: Iterator[CommonInputTextField], - context: CommonDialogOptionContext, - on_chosen: Callable[[DialogOptionIdentifierType, Dict[str, str], CommonChoiceOutcome], None]=CommonFunctionUtils.noop, - always_visible: bool=False, - dialog_description_identifier: Union[int, str, LocalizedString, CommonStringId]=None, - dialog_description_tokens: Iterator[Any]=() - ): - if dialog_description_identifier is not None: - dialog_description = CommonLocalizationUtils.create_localized_string(dialog_description_identifier, tokens=tuple(dialog_description_tokens)) - else: - dialog_description = context.description - self._dialog = CommonInputMultiTextDialog( - mod_identity, - context.title, - dialog_description, - input_fields - ) - - def _on_submit(_: Dict[str, str], __: CommonChoiceOutcome): - on_chosen(self.option_identifier, _, __) - - def _on_chosen(_, __) -> None: - self._dialog.show(on_submit=_on_submit) - - super().__init__( - option_identifier, - None, - context, - on_chosen=_on_chosen, - always_visible=always_visible - ) - - # noinspection PyMissingOrEmptyDocstring - @property - def icon(self) -> Any: - if super().icon is not None: - return super().icon - return CommonIconUtils.load_arrow_right_icon() diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_option.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_option.py deleted file mode 100644 index e775189..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_option.py +++ /dev/null @@ -1,101 +0,0 @@ -""" -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 -""" -from typing import Any, Callable, Union, Iterator - -from protocolbuffers.Localization_pb2 import LocalizedString -from s4ap.sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils -from s4ap.sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_object_option import \ - CommonDialogObjectOption, DialogOptionIdentifierType -from s4ap.sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext -from s4ap.sims4communitylib.dialogs.common_input_float_dialog import CommonInputFloatDialog -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils - - -class CommonDialogInputFloatOption(CommonDialogObjectOption): - """CommonDialogInputFloatOption(\ - option_identifier,\ - initial_value,\ - context,\ - min_value=0.0,\ - max_value=2147483647.0,\ - on_chosen=CommonFunctionUtils.noop,\ - always_visible=False,\ - dialog_description_identifier=None,\ - dialog_description_tokens=()\ - ) - - An option to open a dialog to input a float value. - - :param option_identifier: A string that identifies the option from other options. - :type option_identifier: DialogOptionIdentifierType - :param initial_value: The value the option will have initially - :type initial_value: float - :param context: A context to customize the dialog option. - :type context: CommonDialogOptionContext - :param min_value: The minimum value allowed to be entered. - :type min_value: float, optional - :param max_value: The maximum value allowed to be entered. - :type max_value: float, optional - :param on_chosen: A callback invoked when the dialog option is chosen. args: (option_identifier, entered value, outcome) - :type on_chosen: Callable[[DialogOptionIdentifierType, float, CommonChoiceOutcome], None], optional - :param always_visible: If set to True, the option will always appear in the dialog no matter which page.\ - If False, the option will act as normal. Default is False. - :type always_visible: bool, optional - :param dialog_description_identifier: The description that will display in the input dialog separately from the option.\ - If not provided the description from the provided context will be used instead. - :type dialog_description_identifier: Union[int, str, LocalizedString, CommonStringId], optional - :param dialog_description_tokens: An iterator of Tokens that will be formatted into the dialog description. - :type dialog_description_tokens: Iterator[Any], optional - """ - def __init__( - self, - option_identifier: DialogOptionIdentifierType, - initial_value: float, - context: CommonDialogOptionContext, - min_value: float=0.0, - max_value: float=2147483647.0, - on_chosen: Callable[[DialogOptionIdentifierType, float, CommonChoiceOutcome], None]=CommonFunctionUtils.noop, - always_visible: bool=False, - dialog_description_identifier: Union[int, str, LocalizedString, CommonStringId]=None, - dialog_description_tokens: Iterator[Any]=() - ): - if dialog_description_identifier is not None: - dialog_description = CommonLocalizationUtils.create_localized_string(dialog_description_identifier, tokens=tuple(dialog_description_tokens)) - else: - dialog_description = context.description - self._dialog = CommonInputFloatDialog( - context.title, - dialog_description, - initial_value, - min_value=min_value, - max_value=max_value - ) - - def _on_submit(_: float, __: CommonChoiceOutcome): - on_chosen(self.option_identifier, _, __) - - def _on_chosen(_, __) -> None: - self._dialog.show(on_submit=_on_submit) - - super().__init__( - option_identifier, - None, - context, - on_chosen=_on_chosen, - always_visible=always_visible - ) - - # noinspection PyMissingOrEmptyDocstring - @property - def icon(self) -> Any: - if super().icon is not None: - return super().icon - return CommonIconUtils.load_arrow_right_icon() diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_text_option.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_text_option.py deleted file mode 100644 index 995e643..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_input_text_option.py +++ /dev/null @@ -1,97 +0,0 @@ -""" -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 -""" -from typing import Any, Callable, Union, Iterator - -from protocolbuffers.Localization_pb2 import LocalizedString -from s4ap.sims4communitylib.dialogs.common_choice_outcome import CommonChoiceOutcome -from s4ap.sims4communitylib.dialogs.common_input_text_dialog import CommonInputTextDialog -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils -from s4ap.sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_object_option import \ - CommonDialogObjectOption, DialogOptionIdentifierType -from s4ap.sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils - - -class CommonDialogInputTextOption(CommonDialogObjectOption): - """CommonDialogInputTextOption(\ - mod_identity,\ - option_identifier,\ - initial_value,\ - context,\ - on_chosen=CommonFunctionUtils.noop,\ - always_visible=False,\ - dialog_description_identifier=None,\ - dialog_description_tokens=()\ - ) - - An option to open a dialog to input a text value. - - :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. - :type mod_identity: CommonModIdentity - :param option_identifier: A string that identifies the option from other options. - :type option_identifier: DialogOptionIdentifierType - :param initial_value: The value the option will have initially - :type initial_value: str - :param context: A context to customize the dialog option. - :type context: CommonDialogOptionContext - :param on_chosen: A callback invoked when the dialog option is chosen. args: (option_identifier, entered value, outcome) - :type on_chosen: Callable[[DialogOptionIdentifierType, int, CommonChoiceOutcome], None], optional - :param always_visible: If set to True, the option will always appear in the dialog no matter which page.\ - If False, the option will act as normal. Default is False. - :type always_visible: bool, optional - :param dialog_description_identifier: The description that will display in the input dialog separately from the option.\ - If not provided the description from the provided context will be used instead. - :type dialog_description_identifier: Union[int, str, LocalizedString, CommonStringId], optional - :param dialog_description_tokens: An iterator of Tokens that will be formatted into the dialog description. - :type dialog_description_tokens: Iterator[Any], optional - """ - def __init__( - self, - mod_identity: CommonModIdentity, - option_identifier: DialogOptionIdentifierType, - initial_value: str, - context: CommonDialogOptionContext, - on_chosen: Callable[[DialogOptionIdentifierType, str, CommonChoiceOutcome], None]=CommonFunctionUtils.noop, - always_visible: bool=False, - dialog_description_identifier: Union[int, str, LocalizedString, CommonStringId]=None, - dialog_description_tokens: Iterator[Any]=() - ): - if dialog_description_identifier is not None: - dialog_description = CommonLocalizationUtils.create_localized_string(dialog_description_identifier, tokens=tuple(dialog_description_tokens)) - else: - dialog_description = context.description - self._dialog = CommonInputTextDialog( - mod_identity, - context.title, - dialog_description, - initial_value - ) - - def _on_submit(_: str, __: CommonChoiceOutcome): - on_chosen(self.option_identifier, _, __) - - def _on_chosen(_, __) -> None: - self._dialog.show(on_submit=_on_submit) - - super().__init__( - option_identifier, - None, - context, - on_chosen=_on_chosen, - always_visible=always_visible - ) - - # noinspection PyMissingOrEmptyDocstring - @property - def icon(self) -> Any: - if super().icon is not None: - return super().icon - return CommonIconUtils.load_arrow_right_icon() diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_object_option.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_object_option.py deleted file mode 100644 index 9d5b880..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_object_option.py +++ /dev/null @@ -1,102 +0,0 @@ -""" -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 -""" -from typing import Any, Callable, TypeVar -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from ui.ui_dialog_picker import ObjectPickerRow -from s4ap.sims4communitylib.dialogs.option_dialogs.options.common_dialog_option import CommonDialogOption -from s4ap.sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext, \ - DialogOptionValueType - -DialogOptionIdentifierType = TypeVar('DialogOptionIdentifierType') - - -class CommonDialogObjectOption(CommonDialogOption): - """CommonDialogObjectOption(option_identifier, value, context, on_chosen=CommonFunctionUtils.noop) - - An option the player can choose within a dialog. - - :param option_identifier: A string that identifies the option from other options. - :type option_identifier: DialogOptionIdentifierType - :param value: The value of the option. - :type value: DialogOptionValueType - :param context: A context to customize the dialog option. - :type context: CommonDialogOptionContext - :param on_chosen: A callback invoked when the dialog option is chosen. The values are as follows: (option_identifier, value) - :type on_chosen: Callable[[DialogOptionIdentifierType, DialogOptionValueType], None], optional - :param always_visible: If set to True, the option will always appear in the dialog no matter which page.\ - If False, the option will act as normal. Default is False. - :type always_visible: bool, optional - """ - def __init__( - self, - option_identifier: DialogOptionIdentifierType, - value: DialogOptionValueType, - context: CommonDialogOptionContext, - on_chosen: Callable[[DialogOptionIdentifierType, DialogOptionValueType], None]=CommonFunctionUtils.noop, - always_visible: bool=False - ): - if option_identifier is None: - raise AttributeError('Missing required argument \'option_identifier\'') - - self._option_identifier = option_identifier - self._always_visible = always_visible - - def _on_chosen(val: DialogOptionValueType) -> Any: - return on_chosen(self.option_identifier, val) - - super().__init__(value, context, on_chosen=_on_chosen) - - @property - def option_identifier(self) -> DialogOptionIdentifierType: - """Used to identify the option. - - :return: The identity of the option. - :rtype: str - """ - return self._option_identifier - - @property - def value(self) -> DialogOptionValueType: - """The value of the option. - - :return: The value of the option. - :rtype: DialogOptionValueType - """ - return self._value - - @property - def always_visible(self) -> bool: - """Determine if the option will always be visible. - - :return: If set to True, the option will always appear in the dialog no matter which page.\ - If False, the option will act as normal. - :rtype: bool - """ - return self._always_visible - - def as_row(self, option_id: int) -> ObjectPickerRow: - """as_row(option_id) - - Convert the option into a picker row. - - :param option_id: The index of the option. - :type option_id: int - :return: The option as a Picker Row - :rtype: ObjectPickerRow - """ - return ObjectPickerRow( - option_id=option_id, - name=self.title, - row_description=self.description, - row_tooltip=self.tooltip, - icon=self.icon, - is_enable=self.context.is_enabled, - is_selected=self.context.is_selected, - tag_list=self.hashed_tag_list, - tag=self - ) diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_option_category.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_option_category.py deleted file mode 100644 index 813dd29..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_option_category.py +++ /dev/null @@ -1,32 +0,0 @@ -""" -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 -""" -from typing import Union - -from protocolbuffers.Localization_pb2 import LocalizedString -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils - - -class CommonDialogObjectOptionCategory: - """CommonDialogObjectOptionCategory(object_category, icon, category_name=None) - - An option category. - - :param object_category: The category of the option. - :type object_category: str - :param icon: The decimal identifier of the icon for the category. - :type icon: int - :param category_name: The name of the category. Default is the object_category value. - :type category_name: LocalizedString - """ - def __init__(self, object_category: str, icon: int, category_name: Union[int, str, LocalizedString, CommonStringId, None] = None): - self.object_category = object_category - self.icon = icon - if category_name is None: - category_name = object_category - self.category_name = CommonLocalizationUtils.create_localized_string(category_name) diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_select_option.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_select_option.py deleted file mode 100644 index 93eaa0a..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_select_option.py +++ /dev/null @@ -1,50 +0,0 @@ -""" -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 -""" -from typing import Any, Callable - -from s4ap.sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import DialogOptionValueType, \ - CommonDialogOptionContext -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils -from s4ap.sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_object_option import \ - CommonDialogObjectOption, DialogOptionIdentifierType - - -class CommonDialogSelectOption(CommonDialogObjectOption): - """CommonDialogSelectOption(option_identifier, value, context, on_chosen=CommonFunctionUtils.noop, always_visible=False) - - An option that invokes a callback, passing in its value. - - :param option_identifier: A string that identifies the option from other options. - :type option_identifier: DialogOptionIdentifierType - :param value: The value of the option. - :type value: DialogOptionValueType - :param context: A context to customize the dialog option. - :type context: CommonDialogOptionContext - :param on_chosen: A callback invoked when the dialog option is chosen. - :type on_chosen: Callable[[DialogOptionIdentifierType, DialogOptionValueType], None], optional - :param always_visible: If set to True, the option will always appear in the dialog no matter which page.\ - If False, the option will act as normal. Default is False. - :type always_visible: bool, optional - """ - def __init__( - self, - option_identifier: DialogOptionIdentifierType, - value: DialogOptionValueType, - context: CommonDialogOptionContext, - on_chosen: Callable[[DialogOptionIdentifierType, DialogOptionValueType], None]=CommonFunctionUtils.noop, - always_visible: bool=False - ): - super().__init__(option_identifier, value, context, on_chosen=on_chosen, always_visible=always_visible) - - # noinspection PyMissingOrEmptyDocstring - @property - def icon(self) -> Any: - if super().icon is not None: - return super().icon - return CommonIconUtils.load_arrow_right_icon() diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_toggle_option.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_toggle_option.py deleted file mode 100644 index 886fe79..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/objects/common_dialog_toggle_option.py +++ /dev/null @@ -1,78 +0,0 @@ -""" -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 -""" -from typing import Any, Callable, Union - -from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from s4ap.sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils -from s4ap.sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_object_option import \ - CommonDialogObjectOption, DialogOptionIdentifierType - - -class CommonDialogToggleOption(CommonDialogObjectOption): - """CommonDialogObjectOption(option_identifier, value, context, on_chosen=CommonFunctionUtils.noop, always_visible=False) - - An option with two states, on or off. - - :param option_identifier: A string that identifies the option from other options. - :type option_identifier: DialogOptionIdentifierType - :param value: The value of the option. - :type value: bool - :param context: A context to customize the dialog option. - :type context: CommonDialogOptionContext - :param on_chosen: A callback invoked when the dialog option is chosen. The values are as follows: (option_identifier, not value) - :type on_chosen: Callable[[DialogOptionIdentifierType, bool], None], optional - :param always_visible: If set to True, the option will always appear in the dialog no matter which page.\ - If False, the option will act as normal. Default is False. - :type always_visible: bool, optional - """ - def __init__( - self, - option_identifier: DialogOptionIdentifierType, - value: Union[bool, CommonExecutionResult], - context: CommonDialogOptionContext, - on_chosen: Callable[[DialogOptionIdentifierType, bool], None]=CommonFunctionUtils.noop, - always_visible: bool=False - ): - if isinstance(value, CommonExecutionResult): - value = bool(value.result) - super().__init__(option_identifier, value, context, on_chosen=on_chosen, always_visible=always_visible) - - # noinspection PyMissingOrEmptyDocstring - @property - def icon(self) -> Any: - if super().icon is not None: - return super().icon - if self.value: - return CommonIconUtils.load_checked_square_icon() - return CommonIconUtils.load_unchecked_square_icon() - - @property - def value(self) -> bool: - """The value of the option. - - :return: The value of the option. - :rtype: bool - """ - return self._value - - @property - def on_chosen(self) -> Callable[[bool], Any]: - """The action to perform upon choosing this option. - - :return: The action to perform upon choosing this option. - :rtype: Callable[[bool], Any] - """ - return super().on_chosen - - # noinspection PyMissingOrEmptyDocstring - def choose(self) -> None: - if self.on_chosen is None: - return None - return self.on_chosen(not bool(self.value)) diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/response/__init__.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/response/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/response/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/response/common_dialog_button_option.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/response/common_dialog_button_option.py deleted file mode 100644 index 972c70c..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/response/common_dialog_button_option.py +++ /dev/null @@ -1,77 +0,0 @@ -""" -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 -""" -from typing import Any, Callable, TypeVar - -from s4ap.sims4communitylib.dialogs.common_ui_dialog_response import CommonUiDialogResponse -from s4ap.sims4communitylib.dialogs.option_dialogs.options.response.common_dialog_response_option import \ - CommonDialogResponseOption -from s4ap.sims4communitylib.dialogs.option_dialogs.options.response.common_dialog_response_option_context import \ - DialogResponseOptionValueType, CommonDialogResponseOptionContext -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils - -DialogResponseOptionIdentifierType = TypeVar('DialogResponseOptionIdentifierType') - - -class CommonDialogButtonOption(CommonDialogResponseOption): - """CommonDialogButtonOption(option_identifier, value, context, on_chosen=CommonFunctionUtils.noop) - - An option the player can choose within a dialog. - - :param option_identifier: A string that identifies the option from other options. - :type option_identifier: DialogOptionIdentifierType - :param value: The value of the option. - :type value: DialogResponseOptionValueType - :param context: A context to customize the dialog option. - :type context: CommonDialogOptionContext - :param on_chosen: A callback invoked when the dialog option is chosen. The values are as follows: (option_identifier, value) - :type on_chosen: Callable[[DialogOptionIdentifierType, DialogResponseOptionValueType], None], optional - """ - def __init__( - self, - option_identifier: DialogResponseOptionIdentifierType, - value: DialogResponseOptionValueType, - context: CommonDialogResponseOptionContext, - on_chosen: Callable[[DialogResponseOptionIdentifierType, DialogResponseOptionValueType], None]=CommonFunctionUtils.noop - ): - if option_identifier is None: - raise AttributeError('Missing required argument \'option_identifier\'') - - self._option_identifier = option_identifier - - def _on_chosen(val: DialogResponseOptionValueType) -> Any: - return on_chosen(self.option_identifier, val) - - super().__init__(value, context, on_chosen=_on_chosen) - - @property - def option_identifier(self) -> DialogResponseOptionIdentifierType: - """Used to identify the option.""" - return self._option_identifier - - @property - def value(self) -> DialogResponseOptionValueType: - """The value of the option.""" - return self._value - - def as_response(self, option_id: int) -> CommonUiDialogResponse: - """as_response(option_id) - - Convert the option into a response. - - :param option_id: The index of the option. - :type option_id: int - :return: The option as a Response - :rtype: CommonUiDialogResponse - """ - return CommonUiDialogResponse( - option_id, - self, - text=self.context.text, - subtext=self.context.subtext, - disabled_text=self.context.disabled_text - ) diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/response/common_dialog_response_option.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/response/common_dialog_response_option.py deleted file mode 100644 index feabfa0..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/response/common_dialog_response_option.py +++ /dev/null @@ -1,94 +0,0 @@ -""" -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 -""" -from typing import Any, Callable, Union - -from protocolbuffers.Localization_pb2 import LocalizedString -from s4ap.sims4communitylib.dialogs.common_ui_dialog_response import CommonUiDialogResponse -from s4ap.sims4communitylib.dialogs.option_dialogs.options.response.common_dialog_response_option_context import \ - DialogResponseOptionValueType, CommonDialogResponseOptionContext -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils - - -class CommonDialogResponseOption: - """CommonDialogResponseOption(value, context, on_chosen=CommonFunctionUtils.noop) - - An option the player can choose within a dialog. - - :param value: The value of the option. - :type value: DialogOptionValueType - :param context: A context to customize the dialog option. - :type context: CommonDialogResponseOptionContext - :param on_chosen: A callback invoked when the dialog option is chosen. - :type on_chosen: Callable[[DialogOptionValueType], Any], optional - """ - def __init__( - self, - value: DialogResponseOptionValueType, - context: CommonDialogResponseOptionContext, - on_chosen: Callable[[DialogResponseOptionValueType], Any]=CommonFunctionUtils.noop - ): - if context is None: - raise AttributeError('Missing required argument \'context\'') - - self._value = value - self._option_context = context - self._on_chosen = on_chosen - - @property - def text(self) -> LocalizedString: - """The text of the dialog option.""" - return self.context.text - - @property - def subtext(self) -> Union[LocalizedString, None]: - """The subtext that displays under the option.""" - return self.context.subtext - - @property - def disabled_text(self) -> Union[LocalizedString, None]: - """The text that displays on the option as a tooltip. If provided, the option will also be disabled.""" - return self.context.disabled_text - - @property - def context(self) -> CommonDialogResponseOptionContext: - """The context of the option.""" - return self._option_context - - @property - def value(self) -> DialogResponseOptionValueType: - """The value of the option.""" - return self._value - - @property - def on_chosen(self) -> Callable[[DialogResponseOptionValueType], Any]: - """The action to perform upon choosing this option.""" - return self._on_chosen - - def choose(self) -> Any: - """choose() - - Choose the option. - - :return: The result of choosing the option. - :rtype: Any - """ - if self.on_chosen is None: - return None - return self.on_chosen(self.value) - - def as_response(self, option_id: int) -> CommonUiDialogResponse: - """as_response(option_id) - - Convert the option into a response. - - :param option_id: The index of the option. - :type option_id: int - :return: The option as a Response - :rtype: CommonUiDialogResponse - """ - raise NotImplementedError('\'{}\' not implemented.'.format(self.__class__.as_response.__name__)) diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/response/common_dialog_response_option_context.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/response/common_dialog_response_option_context.py deleted file mode 100644 index 1ddcc58..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/response/common_dialog_response_option_context.py +++ /dev/null @@ -1,67 +0,0 @@ -""" -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 -""" -from typing import Union, Any, TypeVar, Iterator -from protocolbuffers.Localization_pb2 import LocalizedString -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils - -DialogResponseOptionValueType = TypeVar('DialogResponseOptionValueType') - - -class CommonDialogResponseOptionContext: - """CommonDialogResponseOptionContext(\ - text_identifier,\ - text_tokens=(),\ - subtext_identifier=None,\ - subtext_tokens=(),\ - disabled_text_identifier=None,\ - disabled_text_tokens=(),\ - ) - - A context used by :class:`.CommonDialogResponseOption` that provides customization of options. - - :param text_identifier: The text of the option. - :type text_identifier: Union[int, str, LocalizedString, CommonStringId] - :param text_tokens: An iterator of Tokens that will be formatted into the text. - :type text_tokens: Iterator[Any], optional - :param subtext_identifier: The subtext of the option. Default is None. - :type subtext_identifier: Union[int, str, LocalizedString, CommonStringId], optional - :param subtext_tokens: An iterator of Tokens that will be formatted into the description. - :type subtext_tokens: Iterator[Any], optional - :param disabled_text_identifier: The text that displays on the option as a tooltip. Setting this value will also disable the option. Default is None. - :type disabled_text_identifier: Union[int, str, LocalizedString, CommonStringId], optional - :param disabled_text_tokens: An iterator of Tokens that will be formatted into the description. - :type disabled_text_tokens: Iterator[Any], optional - """ - def __init__( - self, - text_identifier: Union[int, str, LocalizedString, CommonStringId], - text_tokens: Iterator[Any]=(), - subtext_identifier: Union[int, str, LocalizedString, CommonStringId]=None, - subtext_tokens: Iterator[Any]=(), - disabled_text_identifier: Union[int, str, LocalizedString, CommonStringId]=None, - disabled_text_tokens: Iterator[Any]=() - ): - self._text = CommonLocalizationUtils.create_localized_string(text_identifier, tokens=tuple(text_tokens)) - self._subtext = CommonLocalizationUtils.create_localized_string(subtext_identifier, tokens=tuple(subtext_tokens)) if subtext_identifier is not None else None - self._disabled_text = CommonLocalizationUtils.create_localized_string(disabled_text_identifier, tokens=tuple(disabled_text_tokens)) if disabled_text_identifier is not None else None - - @property - def text(self) -> LocalizedString: - """The text of the dialog option.""" - return self._text - - @property - def subtext(self) -> Union[LocalizedString, None]: - """The subtext that displays under the option.""" - return self._subtext - - @property - def disabled_text(self) -> Union[LocalizedString, None]: - """The text that displays on the option as a tooltip. If provided, the option will also be disabled.""" - return self._disabled_text diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/sims/__init__.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/sims/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/sims/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/sims/common_dialog_sim_option.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/sims/common_dialog_sim_option.py deleted file mode 100644 index d8f5cd7..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/sims/common_dialog_sim_option.py +++ /dev/null @@ -1,71 +0,0 @@ -""" -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 -""" -from typing import Any, Callable -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from ui.ui_dialog_picker import SimPickerRow -from s4ap.sims4communitylib.dialogs.option_dialogs.options.common_dialog_option import CommonDialogOption -from s4ap.sims4communitylib.dialogs.option_dialogs.options.sims.common_dialog_sim_option_context import CommonDialogSimOptionContext - - -class CommonDialogSimOption(CommonDialogOption): - """CommonDialogSimOption(sim_info, context, on_chosen=CommonFunctionUtils.noop) - - An option the player can choose within a dialog. - - :param sim_info: The Sim that will be chosen when the option is chosen. - :type sim_info: SimInfo - :param context: A context to customize the dialog option. - :type context: CommonDialogOptionContext - :param on_chosen: A callback invoked when the dialog option is chosen. args: (sim_info) - :type on_chosen: Callable[[SimInfo], Any], optional - """ - - def __init__( - self, - sim_info: SimInfo, - context: CommonDialogSimOptionContext, - on_chosen: Callable[[SimInfo], Any]=CommonFunctionUtils.noop - ): - super().__init__( - sim_info, - context, - on_chosen=on_chosen - ) - - # noinspection PyMissingOrEmptyDocstring - @property - def value(self) -> SimInfo: - return self._value - - @property - def sim_id(self) -> int: - """The id of the Sim in this option. - - :return: The id of the Sim within the option. - :rtype: int - """ - return CommonSimUtils.get_sim_id(self.value) - - def as_row(self, option_id: int) -> SimPickerRow: - """as_row(option_id) - - Convert the option into a picker row. - - :param option_id: The index of the option. - :type option_id: int - :return: The option as a Picker Row - :rtype: SimPickerRow - """ - return SimPickerRow( - self.sim_id, - select_default=self.context.is_selected, - is_enable=self.context.is_enabled, - tag=self - ) diff --git a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/sims/common_dialog_sim_option_context.py b/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/sims/common_dialog_sim_option_context.py deleted file mode 100644 index ff7a1cf..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/option_dialogs/options/sims/common_dialog_sim_option_context.py +++ /dev/null @@ -1,31 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext - - -class CommonDialogSimOptionContext(CommonDialogOptionContext): - """CommonDialogSimOptionContext(is_enabled=True, is_selected=False) - - A context used by CommonDialogSimOption that contains customization of the option. - - :param is_enabled: If True, the Sim will be selectable in the dialog. If False, the Sim will be disabled in the dialog. - :type is_enabled: bool, optional - :param is_selected: If True, the Sim will already be selected in the dialog. If False, the Sim will not be selected in the dialog. - :type is_selected: bool, optional - """ - def __init__( - self, - is_enabled: bool=True, - is_selected: bool=False - ): - super().__init__( - 0, - 0, - is_enabled=is_enabled, - is_selected=is_selected - ) diff --git a/Scripts/s4ap/sims4communitylib/dialogs/premade_dialogs/__init__.py b/Scripts/s4ap/sims4communitylib/dialogs/premade_dialogs/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/premade_dialogs/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/dialogs/premade_dialogs/common_choose_sim_demographic_types_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/premade_dialogs/common_choose_sim_demographic_types_dialog.py deleted file mode 100644 index 37be716..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/premade_dialogs/common_choose_sim_demographic_types_dialog.py +++ /dev/null @@ -1,251 +0,0 @@ -""" -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 -""" -from typing import Callable, Tuple, Union, Iterator - -from protocolbuffers.Localization_pb2 import LocalizedString -from s4ap.sims4communitylib.dialogs.option_dialogs.common_choose_objects_option_dialog import CommonChooseObjectsOptionDialog -from s4ap.sims4communitylib.dialogs.option_dialogs.options.common_dialog_option_context import CommonDialogOptionContext -from s4ap.sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_action_option import \ - CommonDialogActionOption -from s4ap.sims4communitylib.dialogs.option_dialogs.options.objects.common_dialog_select_option import \ - CommonDialogSelectOption -from s4ap.sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.logging._has_s4cl_log import _HasS4CLLog -from s4ap.sims4communitylib.utils.common_collection_utils import CommonCollectionUtils -from s4ap.sims4communitylib.utils.common_icon_utils import CommonIconUtils -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor - - -class CommonChooseSimDemographicTypesDialog(_HasS4CLLog): - """CommonChooseSimDemographicTypesDialog(\ - on_close,\ - available_values=None,\ - exclude_values=None\ - ) - - Open a dialog that prompts the player to choose from Sim Demographic Types. - - :param on_close: A callback invoked upon the dialog closing. - :type on_close: Callable[[], None] - :param available_values: The available values shown in the dialog. Default is all Values. - :type available_values: Iterator[CommonSimDemographicType], optional - :param exclude_values: The demographics to not display in the dialog. Default is all Values will be available. - :type exclude_values: Iterator[CommonSimDemographicType], optional - """ - def __init__( - self, - on_close: Callable[[], None], - available_values: Iterator[CommonSimDemographicType] = None, - exclude_values: Iterator[CommonSimDemographicType] = None - ): - super().__init__() - self._on_close = on_close - self._exclude_values = tuple(exclude_values) if exclude_values else None - self._available_values = tuple(available_values or CommonSimDemographicType.get_all(exclude_values=self._exclude_values)) - - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - return 'common_choose_sim_demographic_types_dialog' - - def open( - self, - title: Union[int, CommonStringId, LocalizedString], - description: Union[int, CommonStringId, LocalizedString], - current_selections: Tuple[CommonSimDemographicType], - on_submit: Callable[[Tuple[CommonSimDemographicType]], None], - include_all_choice: bool = True, - include_none_choice: bool = True, - reopen_on_submit: bool = True - ) -> None: - """open(\ - title,\ - description,\ - current_selections,\ - on_submit,\ - include_all_choice=True,\ - include_none_choice=True,\ - reopen_on_submit=True\ - ) - - Open the dialog. - - :param title: The title to show at the top of the dialog. - :type title: Union[int, CommonStringId, LocalizedString] - :param description: The description to show at the top of the dialog. - :type description: Union[int, CommonStringId, LocalizedString] - :param current_selections: The currently selected options in the dialog. - :type current_selections: Tuple[CommonSimDemographicType] - :param on_submit: A callback invoked upon submitting the dialog. - :type on_submit: Callable[[Tuple[CommonSimDemographicType]], None] - :param include_all_choice: If True, the "All Sims" choice will be shown to players. If False, the "All Sims" choice will not be shown. Default is True. - :type include_all_choice: bool, optional - :param include_none_choice: If True, the "No Sims" choice will be shown to players. If False, the "No Sims" choice will not be shown. Default is True. - :type include_none_choice: bool, optional - :param reopen_on_submit: If True, the dialog will reopen on submit. If False, the dialog will not reopen on submit. Default is True. - :type reopen_on_submit: bool, optional - """ - def _on_close() -> None: - if self._on_close is not None: - self._on_close() - - def _reopen(_current_selections: Tuple[CommonSimDemographicType] = None) -> None: - if _current_selections is None: - _current_selections = current_selections - self.open( - title, - description, - _current_selections, - on_submit, - include_all_choice=include_all_choice, - include_none_choice=include_none_choice, - reopen_on_submit=reopen_on_submit - ) - - self.log.format_with_message('Choosing Sim demographic types.', current_selections=current_selections) - - if not current_selections: - current_val_localized_string = CommonStringId.S4CL_NO_SIMS - else: - current_val_localized_string = None - for current_value in current_selections: - _display_name = CommonSimDemographicType.to_display_name(current_value) - if current_val_localized_string is None: - current_val_localized_string = _display_name - continue - current_val_localized_string = CommonLocalizationUtils.create_localized_string(CommonStringId.STRING_COMMA_SPACE_STRING, tokens=( - current_val_localized_string, - _display_name - )) - - option_dialog = CommonChooseObjectsOptionDialog( - title, - description, - title_tokens=( - CommonLocalizationUtils.colorize(current_val_localized_string, text_color=CommonLocalizedStringColor.GREEN), - ), - on_close=_on_close, - mod_identity=self.mod_identity, - per_page=500 - ) - - def _on_submit(_types: Tuple[CommonSimDemographicType]): - if _types is None: - _on_close() - return - if CommonStringId.S4CL_ALL_SIMS.name in _types: - on_submit(self._available_values) - if reopen_on_submit: - _reopen(_current_selections=self._available_values) - return - if CommonStringId.S4CL_NO_SIMS.name in _types: - on_submit(tuple()) - if reopen_on_submit: - _reopen(_current_selections=tuple()) - return - on_submit(_types) - if reopen_on_submit: - _reopen(_current_selections=_types) - - if include_all_choice: - option_dialog.add_option( - CommonDialogSelectOption( - 'ChooseAllSims', - CommonStringId.S4CL_ALL_SIMS.name, - CommonDialogOptionContext( - CommonStringId.S4CL_ALL_SIMS, - CommonStringId.S4CL_ALL_OPTIONS_WILL_BE_INCLUDED, - icon=CommonIconUtils.load_arrow_right_icon() - ) - ) - ) - - if include_none_choice: - option_dialog.add_option( - CommonDialogSelectOption( - 'ChooseNoSims', - CommonStringId.S4CL_NO_SIMS.name, - CommonDialogOptionContext( - CommonStringId.S4CL_NO_SIMS, - CommonStringId.S4CL_NO_OPTIONS_WILL_BE_INCLUDED, - icon=CommonIconUtils.load_arrow_right_icon() - ) - ) - ) - - for setting_type in self._available_values: - display_name = CommonLocalizationUtils.create_localized_string(CommonSimDemographicType.to_display_name(setting_type)) - icon = CommonIconUtils.load_unchecked_square_icon() - is_selected = setting_type in current_selections - if is_selected: - icon = CommonIconUtils.load_checked_square_icon() - option_dialog.add_option( - CommonDialogSelectOption( - setting_type.name, - setting_type, - CommonDialogOptionContext( - display_name, - CommonSimDemographicType.to_display_description(setting_type), - icon=icon, - is_selected=is_selected - ) - ) - ) - - if not option_dialog.has_options(): - _on_close() - return - - option_dialog.show( - min_selectable=0, - max_selectable=option_dialog.option_count, - allow_no_selection=True, - on_submit=_on_submit - ) - - def create_dialog_option( - self, - option_id: str, - title: Union[int, CommonStringId, LocalizedString], - description: Union[int, CommonStringId, LocalizedString], - current_values: Tuple[CommonSimDemographicType], - on_chosen: Callable[[str, Tuple[CommonSimDemographicType]], None] - ): - """Create a dialog option.""" - def _open_choose_sim_demographics_dialog() -> None: - self.open(title, description, current_values, lambda val: on_chosen(option_id, val)) - - if not current_values: - current_val_localized_string = CommonStringId.S4CL_NO_SIMS - else: - if CommonCollectionUtils.lists_are_equal(sorted(current_values), sorted(self._available_values)): - current_val_localized_string = CommonStringId.S4CL_ALL_SIMS - else: - current_val_localized_string = None - for current_value in current_values: - display_name = CommonSimDemographicType.to_display_name(current_value) - if current_val_localized_string is None: - current_val_localized_string = display_name - continue - current_val_localized_string = CommonLocalizationUtils.create_localized_string(CommonStringId.STRING_COMMA_SPACE_STRING, tokens=( - current_val_localized_string, - display_name - )) - - return CommonDialogActionOption( - CommonDialogOptionContext( - title, - description, - title_tokens=( - CommonLocalizationUtils.colorize(CommonLocalizationUtils.create_localized_string(current_val_localized_string), text_color=CommonLocalizedStringColor.GREEN), - ) - ), - on_chosen=_open_choose_sim_demographics_dialog - ) diff --git a/Scripts/s4ap/sims4communitylib/dialogs/premade_dialogs/common_premade_choose_sim_option_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/premade_dialogs/common_premade_choose_sim_option_dialog.py deleted file mode 100644 index e673050..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/premade_dialogs/common_premade_choose_sim_option_dialog.py +++ /dev/null @@ -1,187 +0,0 @@ -""" -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 -""" -from typing import Union, Any, Iterator, Callable -from protocolbuffers.Localization_pb2 import LocalizedString -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.dialogs.option_dialogs.common_choose_sim_option_dialog import CommonChooseSimOptionDialog -from s4ap.sims4communitylib.dialogs.option_dialogs.options.sims.common_dialog_sim_option import CommonDialogSimOption -from s4ap.sims4communitylib.dialogs.option_dialogs.options.sims.common_dialog_sim_option_context import \ - CommonDialogSimOptionContext -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from s4ap.sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils -from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - - -class CommonPremadeChooseSimOptionDialog(CommonChooseSimOptionDialog): - """CommonPremadeChooseSimOptionDialog(\ - title_identifier,\ - description_identifier,\ - title_tokens=(),\ - description_tokens=(),\ - on_close=CommonFunctionUtils.noop,\ - mod_identity=None,\ - include_sim_callback=None,\ - instanced_sims_only=True,\ - on_sim_chosen=CommonFunctionUtils.noop\ - ) - - A premade dialog that will display a list of Sims based on a filter and will prompt the player to choose a single Sim. - - .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_premade_choose_sim_option_dialog` in the in-game console. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - def _on_chosen(_sim_info: SimInfo): - 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 - ), - ) - - # Create the dialog that will only show adult Sims in the current area. - option_dialog = CommonPremadeChooseSimOptionDialog( - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - title_tokens=title_tokens, - description_tokens=description_tokens, - mod_identity=ModInfo.get_identity(), - include_sim_callback=CommonAgeUtils.is_adult, - instanced_sims_only=True, - on_sim_chosen=_on_chosen - ) - - option_dialog.show( - sim_info=CommonSimUtils.get_active_sim_info(), - column_count=4 - ) - - :param title_identifier: A decimal identifier of the title text. - :type title_identifier: Union[int, str, LocalizedString, CommonStringId] - :param description_identifier: A decimal identifier of the description text. - :type description_identifier: Union[int, str, LocalizedString, CommonStringId] - :param title_tokens: An iterator of Tokens to format into the title. - :type title_tokens: Iterator[Any], optional - :param description_tokens: An iterator of Tokens to format into the description. - :type description_tokens: Iterator[Any], optional - :param on_close: A callback invoked upon the dialog closing. - :type on_close: Callable[[], None], optional - :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. - :type mod_identity: CommonModIdentity, optional - :param include_sim_callback: If the result of this callback is True, the sim will be included in the results. If set to None, All sims will be included. - :type include_sim_callback: Callable[[SimInfo], bool], optional - :param instanced_sims_only: If True, only Sims that are currently spawned will be shown. If False, all Sims will be shown. Default is True. - :type instanced_sims_only: bool, optional - :param on_sim_chosen: Called upon a Sim being chosen. Default is :func:`~CommonFunctionUtils.noop`. - :type on_sim_chosen: Callable[[SimInfo], Any], optional - """ - def __init__( - self, - title_identifier: Union[int, str, LocalizedString, CommonStringId], - description_identifier: Union[int, str, LocalizedString, CommonStringId], - title_tokens: Iterator[Any]=(), - description_tokens: Iterator[Any]=(), - on_close: Callable[[], None]=CommonFunctionUtils.noop, - mod_identity: CommonModIdentity=None, - include_sim_callback: Callable[[SimInfo], bool]=None, - instanced_sims_only: bool=True, - on_sim_chosen: Callable[[SimInfo], Any]=CommonFunctionUtils.noop - ): - super().__init__( - title_identifier, - description_identifier, - title_tokens=title_tokens, - description_tokens=description_tokens, - on_close=on_close, - mod_identity=mod_identity - ) - - if instanced_sims_only: - _sim_info_list = CommonSimUtils.get_instanced_sim_info_for_all_sims_generator(include_sim_callback=include_sim_callback) - else: - _sim_info_list = CommonSimUtils.get_sim_info_for_all_sims_generator(include_sim_callback=include_sim_callback) - - for _sim_info in _sim_info_list: - self.add_option( - CommonDialogSimOption( - _sim_info, - CommonDialogSimOptionContext(), - on_chosen=on_sim_chosen - ) - ) - - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - return 's4cl_premade_choose_sim_option_dialog' - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_testing.show_premade_choose_sim_option_dialog', - 'Show an example of CommonPremadeChooseSimOptionDialog.' -) -def _common_testing_show_premade_choose_sim_option_dialog(output: CommonConsoleCommandOutput): - output('Showing test premade choose sim option dialog.') - - def _on_chosen(_sim_info: SimInfo): - output('Chose Sim with name \'{}\''.format(CommonSimNameUtils.get_full_name(_sim_info))) - - # 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 - ), - ) - - # Create the dialog that will only show adult Sims in the current area. - option_dialog = CommonPremadeChooseSimOptionDialog( - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - title_tokens=title_tokens, - description_tokens=description_tokens, - mod_identity=ModInfo.get_identity(), - include_sim_callback=CommonAgeUtils.is_adult, - instanced_sims_only=True, - on_sim_chosen=_on_chosen - ) - - option_dialog.show( - sim_info=CommonSimUtils.get_active_sim_info(), - column_count=4 - ) - output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/premade_dialogs/common_premade_choose_sims_option_dialog.py b/Scripts/s4ap/sims4communitylib/dialogs/premade_dialogs/common_premade_choose_sims_option_dialog.py deleted file mode 100644 index 9ae0cbd..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/premade_dialogs/common_premade_choose_sims_option_dialog.py +++ /dev/null @@ -1,186 +0,0 @@ -""" -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 -""" -from pprint import pformat - -from typing import Union, Any, Iterator, Callable, Tuple -from protocolbuffers.Localization_pb2 import LocalizedString -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.dialogs.option_dialogs.common_choose_sims_option_dialog import CommonChooseSimsOptionDialog -from s4ap.sims4communitylib.dialogs.option_dialogs.options.sims.common_dialog_sim_option import CommonDialogSimOption -from s4ap.sims4communitylib.dialogs.option_dialogs.options.sims.common_dialog_sim_option_context import \ - CommonDialogSimOptionContext -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from s4ap.sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils -from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - - -class CommonPremadeChooseSimsOptionDialog(CommonChooseSimsOptionDialog): - """CommonPremadeChooseSimsOptionDialog(\ - title_identifier,\ - description_identifier,\ - title_tokens=(),\ - description_tokens=(),\ - on_close=CommonFunctionUtils.noop,\ - mod_identity=None,\ - include_sim_callback=None,\ - instanced_sims_only=True\ - ) - - A premade dialog that will display a list of Sims based on a filter and will prompt the player to choose one or more Sims. - - .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_premade_choose_sims_option_dialog` in the in-game console. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - def _on_submit(_chosen_sim_info_list: Tuple[SimInfo]): - 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 - ), - ) - - # Create the dialog that will only show adult (include_sim_callback=CommonAgeUtils.is_adult) Sims in the current area (instanced_sims_only=True). - option_dialog = CommonPremadeChooseSimsOptionDialog( - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - title_tokens=title_tokens, - description_tokens=description_tokens, - mod_identity=ModInfo.get_identity(), - include_sim_callback=CommonAgeUtils.is_adult, - instanced_sims_only=True - ) - - option_dialog.show( - sim_info=CommonSimUtils.get_active_sim_info(), - column_count=4, - max_selectable=5, - on_submit=_on_submit - ) - - :param title_identifier: A decimal identifier of the title text. - :type title_identifier: Union[int, str, LocalizedString, CommonStringId] - :param description_identifier: A decimal identifier of the description text. - :type description_identifier: Union[int, str, LocalizedString, CommonStringId] - :param title_tokens: An iterator of Tokens to format into the title. - :type title_tokens: Iterator[Any], optional - :param description_tokens: An iterator of Tokens to format into the description. - :type description_tokens: Iterator[Any], optional - :param on_close: A callback invoked upon the dialog closing. - :type on_close: Callable[[], None], optional - :param mod_identity: The identity of the mod creating the dialog. See :class:`.CommonModIdentity` for more information. - :type mod_identity: CommonModIdentity, optional - :param include_sim_callback: If the result of this callback is True, the sim will be included in the results. If set to None, All sims will be included. - :type include_sim_callback: Callable[[SimInfo], bool], optional - :param instanced_sims_only: If True, only Sims that are currently spawned will be shown. If False, all Sims will be shown. Default is True. - :type instanced_sims_only: bool, optional - """ - def __init__( - self, - title_identifier: Union[int, str, LocalizedString, CommonStringId], - description_identifier: Union[int, str, LocalizedString, CommonStringId], - title_tokens: Iterator[Any]=(), - description_tokens: Iterator[Any]=(), - on_close: Callable[[], None]=CommonFunctionUtils.noop, - mod_identity: CommonModIdentity=None, - include_sim_callback: Callable[[SimInfo], bool]=None, - instanced_sims_only: bool=True - ): - super().__init__( - title_identifier, - description_identifier, - title_tokens=title_tokens, - description_tokens=description_tokens, - on_close=on_close, - mod_identity=mod_identity - ) - - if instanced_sims_only: - sim_info_list = CommonSimUtils.get_instanced_sim_info_for_all_sims_generator(include_sim_callback=include_sim_callback) - else: - sim_info_list = CommonSimUtils.get_sim_info_for_all_sims_generator(include_sim_callback=include_sim_callback) - - for sim_info in sim_info_list: - self.add_option( - CommonDialogSimOption( - sim_info, - CommonDialogSimOptionContext() - ) - ) - - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - return 's4cl_premade_choose_sims_option_dialog' - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_testing.show_premade_choose_sims_option_dialog', - 'Show an example of CommonPremadeChooseSimsOptionDialog.' -) -def _common_testing_show_premade_choose_sims_option_dialog(output: CommonConsoleCommandOutput): - output('Showing test premade choose Sims option dialog.') - - def _on_submit(_chosen_sim_info_list: Tuple[SimInfo]): - output('Chose Sims with names \'{}\''.format(pformat(CommonSimNameUtils.get_full_names(_chosen_sim_info_list)))) - - # 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 - ), - ) - - # Create the dialog that will only show adult (include_sim_callback=CommonAgeUtils.is_adult) Sims in the current area (instanced_sims_only=True). - option_dialog = CommonPremadeChooseSimsOptionDialog( - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - title_tokens=title_tokens, - description_tokens=description_tokens, - mod_identity=ModInfo.get_identity(), - include_sim_callback=CommonAgeUtils.is_adult, - instanced_sims_only=True - ) - - option_dialog.show( - sim_info=CommonSimUtils.get_active_sim_info(), - column_count=4, - max_selectable=5, - on_submit=_on_submit - ) - output('Done showing.') diff --git a/Scripts/s4ap/sims4communitylib/dialogs/utils/__init__.py b/Scripts/s4ap/sims4communitylib/dialogs/utils/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/utils/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/dialogs/utils/common_dialog_utils.py b/Scripts/s4ap/sims4communitylib/dialogs/utils/common_dialog_utils.py deleted file mode 100644 index c19e7f5..0000000 --- a/Scripts/s4ap/sims4communitylib/dialogs/utils/common_dialog_utils.py +++ /dev/null @@ -1,58 +0,0 @@ -""" -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 -""" -from typing import Any, Union, Tuple - -from ui.ui_dialog_generic import UiDialogTextInput -from ui.ui_dialog_multi_picker import UiMultiPicker -from ui.ui_dialog_picker import UiDialogObjectPicker - - -class CommonDialogUtils: - """Utilities for use with dialogs. - - """ - TEXT_INPUT_NAME = 'text_input' - - @staticmethod - def get_chosen_item(dialog: Union[UiDialogObjectPicker, UiMultiPicker]) -> Any: - """get_chosen_item(dialog) - - Retrieves the item chosen by the player from a dialog. - - :param dialog: The dialog to get the chosen item of. - :type dialog: Union[UiDialogObjectPicker, UiMultiPicker] - :return: The value of the chosen item. - :rtype: Any - """ - return dialog.get_result_tags()[-1] or dialog.get_result_tags()[0] - - @staticmethod - def get_chosen_items(dialog: Union[UiDialogObjectPicker, UiMultiPicker]) -> Tuple[Any]: - """get_chosen_items(dialog) - - Retrieves the items chosen by the player from a dialog. - - :param dialog: The dialog to get the chosen items of. - :type dialog: Union[UiDialogObjectPicker, UiMultiPicker] - :return: A collection of chosen items. - :rtype: Tuple[Any] - """ - return dialog.get_result_tags() - - @staticmethod - def get_input_value(dialog: UiDialogTextInput) -> Union[str, None]: - """get_input_value(dialog) - - Retrieve the value entered by the player from an input dialog. - - :param dialog: The dialog to get the chosen items of. - :type dialog: UiDialogTextInput - :return: The value of the entered input. - :rtype: Union[str, None] - """ - return str(dialog.text_input_responses.get(CommonDialogUtils.TEXT_INPUT_NAME)) diff --git a/Scripts/s4ap/sims4communitylib/dtos/__init__.py b/Scripts/s4ap/sims4communitylib/dtos/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/dtos/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/dtos/common_cas_part.py b/Scripts/s4ap/sims4communitylib/dtos/common_cas_part.py deleted file mode 100644 index 4825b66..0000000 --- a/Scripts/s4ap/sims4communitylib/dtos/common_cas_part.py +++ /dev/null @@ -1,47 +0,0 @@ -""" -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 -""" -from typing import Union - -from sims.outfits.outfit_enums import BodyType -from s4ap.sims4communitylib.enums.common_body_slot import CommonBodySlot - - -class CommonCASPart: - """CommonCASPart(\ - cas_part_id,\ - body_type=None,\ - ) - - A class that contains information about a CAS Part. - - :param cas_part_id: The decimal identifier of a CAS Part. - :type cas_part_id: int - :param body_type: The place on a Sims person the CAS Part gets applied to. If not specified, then the Body Type of the CAS Part itself will be used. Default is None. - :type body_type: Union[CommonBodySlot, BodyType, int, None], optional - """ - - def __init__(self, cas_part_id: int, body_type: Union[CommonBodySlot, BodyType, int, None] = None) -> None: - self._cas_part_id = cas_part_id - from s4ap.sims4communitylib.utils.cas.common_cas_utils import CommonCASUtils - self._body_type = body_type or CommonCASUtils.get_body_type_of_cas_part(cas_part_id) - - @property - def cas_part_id(self) -> int: - """The decimal identifier of a CAS Part.""" - return self._cas_part_id - - @property - def body_type(self) -> Union[CommonBodySlot, BodyType, int]: - """The place on a Sims person the CAS Part gets applied to.""" - return self._body_type - - def __repr__(self) -> str: - return self.__str__() - - def __str__(self) -> str: - return f'' diff --git a/Scripts/s4ap/sims4communitylib/dtos/common_object_containment_slot.py b/Scripts/s4ap/sims4communitylib/dtos/common_object_containment_slot.py deleted file mode 100644 index ad51724..0000000 --- a/Scripts/s4ap/sims4communitylib/dtos/common_object_containment_slot.py +++ /dev/null @@ -1,37 +0,0 @@ -""" -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 -""" -from typing import Tuple - -from objects.slots import SlotType - - -class CommonObjectContainmentSlot: - """CommonObjectContainmentSlot(slot_name_hash, slot_types) - - A slot used for containing other objects within an object. - - .. note:: A place that other objects can be placed at on an object. - - :param slot_name_hash: The hashed name of the slot. - :type slot_name_hash: int - :param slot_types: A collection of slot types within this containment slot. - :type slot_types: Tuple[SlotType] - """ - def __init__(self, slot_name_hash: int, slot_types: Tuple[SlotType]): - self._slot_name_hash = slot_name_hash - self._slot_types = slot_types - - @property - def slot_name_hash(self) -> int: - """The hashed name of the slot.""" - return self._slot_name_hash - - @property - def slot_types(self) -> Tuple[SlotType]: - """The types of slots.""" - return self._slot_types diff --git a/Scripts/s4ap/sims4communitylib/dtos/common_outfit.py b/Scripts/s4ap/sims4communitylib/dtos/common_outfit.py deleted file mode 100644 index 52e3c12..0000000 --- a/Scripts/s4ap/sims4communitylib/dtos/common_outfit.py +++ /dev/null @@ -1,274 +0,0 @@ -""" -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 -""" -from typing import Union, Dict, Any, List, Tuple - -from sims.outfits.outfit_enums import BodyType, OutfitCategory -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.classes.serialization.common_serializable import CommonSerializable -from s4ap.sims4communitylib.enums.common_body_slot import CommonBodySlot -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.services.sim.cas.common_sim_outfit_io import CommonSimOutfitIO -from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils - - -class CommonOutfit(CommonSerializable): - """CommonOutfit(outfit_parts) - - Contains information on the CAS Parts that make up an outfit. - - :param outfit_parts: A mapping of CAS Parts organized by Body Slot. - :type outfit_parts: Dict[Union[CommonBodySlot, BodyType, int], int] - """ - - def __init__(self, outfit_parts: Dict[Union[CommonBodySlot, BodyType, int], int]): - self._outfit_parts = outfit_parts - - @property - def outfit_parts(self) -> Dict[Union[CommonBodySlot, BodyType, int], int]: - """A library of Body Slots to CAS Part Ids""" - return self._outfit_parts - - def has_body_slot(self, body_slot: Union[CommonBodySlot, BodyType, int]) -> bool: - """has_body_slot(body_slot) - - Determine if the Outfit has a Body Slot. - - :param body_slot: A body slot. - :type body_slot: Union[CommonBodySlot, BodyType, int] - :return: True, if the outfit has the specified body slot. False, if not. - :rtype: bool - """ - return body_slot in self.outfit_parts - - def has_cas_part(self, cas_part: int) -> bool: - """has_cas_part(cas_part) - - Determine if the Outfit has a CAS Part. - - :param cas_part: The decimal identifier of a CAS Part. - :type cas_part: int - :return: True, if the outfit contains the specified CAS Part. False, if not. - :rtype: bool - """ - return any(self.get_all_by_cas_part(cas_part)) - - def set_outfit_part(self, body_slot: Union[CommonBodySlot, BodyType, int], cas_part: int): - """set_outfit_part(body_slot, cas_part) - - Set the CAS Part id at a Body Slot. - - :param body_slot: A body slot. - :type body_slot: Union[CommonBodySlot, BodyType, int] - :param cas_part: The decimal identifier of a CAS Part. - :type cas_part: int - """ - self.outfit_parts[body_slot] = cas_part - - def get_by_body_slot(self, body_slot: Union[CommonBodySlot, BodyType, int]) -> int: - """get_by_body_slot(body_slot) - - Retrieve the CAS Part ID at a Body Slot. - - :param body_slot: A body slot. - :type body_slot: Union[CommonBodySlot, BodyType, int] - :return: The decimal identifier of the CAS Part located at the body slot on the outfit or -1 if the body slot is not found. - :rtype: int - """ - return self.outfit_parts.get(body_slot, -1) - - def get_all_by_cas_part(self, cas_part: int) -> Tuple[Union[CommonBodySlot, BodyType, int]]: - """get_all_by_cas_part(cas_part) - - Retrieve the Body Slots a CAS Part is attached to. - - :param cas_part: The CAS Part to look for. - :type cas_part: Union[CommonBodySlot, BodyType, int] - :return: A collection of body slots the CAS Part is attached to or an empty collection if the CAS Part is not attached to the outfit. - :rtype: Tuple[Union[CommonBodySlot, BodyType, int]] - """ - body_slots: List[Union[CommonBodySlot, BodyType, int]] = list() - for (body_slot, _cas_part) in self.outfit_parts.items(): - if _cas_part == cas_part: - body_slots.append(body_slot) - return tuple(body_slots) - - def remove_by_body_slot(self, body_slot: Union[CommonBodySlot, BodyType, int]): - """remove_by_body_slot(body_slot) - - Remove a CAS Part by a Body Slot. - - :param body_slot: A body slot. - :type body_slot: Union[CommonBodySlot, BodyType, int] - """ - if body_slot not in self.outfit_parts: - return - del self.outfit_parts[body_slot] - - def remove_by_cas_part(self, cas_part: int): - """remove_by_cas_part(cas_part) - - Remove all Body Slots containing a CAS Part. - - :param cas_part: The decimal identifier of a CAS Part. - :type cas_part: int - """ - body_slots = self.get_all_by_cas_part(cas_part) - for body_slot in body_slots: - self.remove_by_body_slot(body_slot) - - def clone(self) -> 'CommonOutfit': - """clone() - - Create a clone of the outfit. - - :return: A clone of the outfit. - :rtype: CommonOutfit - """ - return CommonOutfit(dict(self.outfit_parts)) - - # noinspection PyMissingOrEmptyDocstring - def serialize(self) -> Union[str, Dict[str, Any]]: - data = dict() - if not self.outfit_parts: - return data - outfit_parts_list = list() - for (body_slot, cas_part) in self.outfit_parts.items(): - outfit_parts_list.append((body_slot.name if hasattr(body_slot, 'name') else str(int(body_slot)), cas_part)) - if outfit_parts_list: - data['outfit_parts'] = outfit_parts_list - return data - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def deserialize(cls, data: Union[str, Dict[str, Any]]) -> 'CommonOutfit': - if not data: - return CommonOutfit(dict()) - if isinstance(data, CommonOutfit): - return data - outfit_parts_list: List[Union[CommonBodySlot, BodyType, int], int] = data.get('outfit_parts', None) - outfit_parts = dict() - for (body_slot_str, cas_part) in outfit_parts_list: - if isinstance(body_slot_str, int): - body_slot = CommonResourceUtils.get_enum_by_int_value(int(body_slot_str), CommonBodySlot, default_value=CommonBodySlot.NONE) - if body_slot == CommonBodySlot.NONE: - body_slot = CommonResourceUtils.get_enum_by_int_value(int(body_slot_str), BodyType, default_value=BodyType.NONE) - if body_slot == BodyType.NONE: - body_slot = body_slot_str - else: - body_slot = CommonBodySlot.convert_from_vanilla(body_slot) - elif isinstance(body_slot_str, str) and body_slot_str.isnumeric(): - body_slot = CommonResourceUtils.get_enum_by_int_value(int(body_slot_str), CommonBodySlot, default_value=CommonBodySlot.NONE) - if body_slot == CommonBodySlot.NONE: - body_slot = CommonResourceUtils.get_enum_by_int_value(int(body_slot_str), BodyType, default_value=BodyType.NONE) - if body_slot == BodyType.NONE: - body_slot = body_slot_str - else: - body_slot = CommonBodySlot.convert_from_vanilla(body_slot) - else: - body_slot = CommonResourceUtils.get_enum_by_name(body_slot_str, CommonBodySlot, default_value=CommonBodySlot.NONE) - if body_slot == CommonBodySlot.NONE: - body_slot = CommonResourceUtils.get_enum_by_name(body_slot_str, BodyType, default_value=BodyType.NONE) - if body_slot == BodyType.NONE: - continue - body_slot = CommonBodySlot.convert_from_vanilla(body_slot) - outfit_parts[body_slot] = cas_part - return CommonOutfit(outfit_parts) - - @classmethod - def from_sim(cls, mod_identity: CommonModIdentity, sim_info: SimInfo, outfit_category_and_index: Union[Tuple[OutfitCategory, int], None] = None, include_body_slots: Tuple[Union[CommonBodySlot, BodyType, int]] = None) -> 'CommonOutfit': - """from_sim(mod_identity, sim_info, outfit_category_and_index, include_body_slots=None) - - Create an outfit from the outfit of a Sim. - - :param mod_identity: The identity of the mod making the change. - :type mod_identity: CommonModIdentity - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param outfit_category_and_index: The Category and Index of the outfit to copy from. Default is the current outfit of the Sim. - :type outfit_category_and_index: Union[Tuple[OutfitCategory, int], None], optional - :param include_body_slots: A collection of body slots to include. If set to None, all body slots will be included. Default is None. - :type include_body_slots: Tuple[Union[CommonBodySlot, BodyType, int]], optional - :return: An Outfit created from the Sim. - :rtype: CommonOutfit - """ - if include_body_slots is not None: - include_body_slots = tuple([int(body_type) for body_type in include_body_slots]) - outfit_io = CommonSimOutfitIO(sim_info, outfit_category_and_index=outfit_category_and_index, mod_identity=mod_identity) - return cls.from_outfit_io(outfit_io, include_body_slots=include_body_slots) - - def apply_to_sim(self, mod_identity: CommonModIdentity, sim_info: SimInfo, outfit_category_and_index: Union[Tuple[OutfitCategory, int], None] = None, override_all: bool = False) -> None: - """apply_to_sim(mod_identity, sim_info, outfit_category_and_index=None, override_all=False) - - Apply the outfit parts to the outfit of a Sim. - - :param mod_identity: The identity of the mod making the change. - :type mod_identity: CommonModIdentity - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param outfit_category_and_index: The Category and Index of the outfit to copy to. Default is the current outfit of the Sim. - :type outfit_category_and_index: Union[Tuple[OutfitCategory, int], None], optional - :param override_all: If True, then all outfit parts on the outfit of th Sim will be removed before applying the parts from this outfit. If False, no parts will be removed. Default is True. - :type override_all: bool, optional - """ - outfit_io = CommonSimOutfitIO(sim_info, outfit_category_and_index=outfit_category_and_index, mod_identity=mod_identity) - self.apply_to_outfit_io(outfit_io, override_all=override_all) - outfit_io.apply(apply_to_outfit_category_and_index=outfit_category_and_index) - - @classmethod - def from_outfit_io(cls, outfit_io: CommonSimOutfitIO, include_body_slots: Tuple[Union[CommonBodySlot, BodyType, int]] = None) -> 'CommonOutfit': - """from_outfit_io(outfit_io, include_body_slots=None) - - Create an outfit from an Outfit IO. - - :param outfit_io: An instance of an Outfit IO. - :type outfit_io: CommonSimOutfitIO - :param include_body_slots: A collection of body slots to include. If set to None, all body slots will be included. Default is None. - :type include_body_slots: Tuple[Union[CommonBodySlot, BodyType, int]], optional - :return: An Outfit created from the outfit io. - :rtype: CommonOutfit - """ - if include_body_slots is not None: - include_body_slots = tuple([int(body_slot) for body_slot in include_body_slots]) - outfit_parts: Dict[Union[CommonBodySlot, BodyType, int], int] = dict() - for (body_slot_val, cas_part) in zip(outfit_io.body_types, outfit_io.cas_part_ids): - if include_body_slots is not None and int(body_slot_val) not in include_body_slots: - continue - if isinstance(body_slot_val, int): - body_slot = CommonResourceUtils.get_enum_by_int_value(body_slot_val, CommonBodySlot, default_value=CommonBodySlot.NONE) - if body_slot == CommonBodySlot.NONE: - body_slot = body_slot_val - elif isinstance(body_slot_val, BodyType) or isinstance(body_slot_val, CommonBodySlot): - body_slot = CommonBodySlot.convert_from_vanilla(body_slot_val) - else: - body_slot = CommonResourceUtils.get_enum_by_name(body_slot_val, CommonBodySlot, default_value=CommonBodySlot.NONE) - - outfit_parts[body_slot] = cas_part - return cls(outfit_parts) - - def apply_to_outfit_io(self, outfit_io: CommonSimOutfitIO, override_all: bool = False) -> None: - """apply_to_outfit_io(outfit_io, override_all=False) - - Apply the outfit parts of this outfit to an outfit io. - - :param outfit_io: An instance of an Outfit IO. - :type outfit_io: CommonSimOutfitIO - :param override_all: If True, then all outfit parts on the outfit io will be removed before applying the parts from this outfit. If False, no parts will be removed. Default is True. - :type override_all: bool, optional - """ - if override_all: - for body_slot in tuple(outfit_io.body_types): - outfit_io.detach_body_type(body_slot) - for (body_slot_val, cas_part) in self.outfit_parts.items(): - outfit_io.attach_cas_part(cas_part, body_type=CommonBodySlot.convert_to_vanilla(body_slot_val)) - - def __repr__(self) -> str: - return self.__str__() - - def __str__(self) -> str: - result = ', '.join(['{} ({}): {}'.format(body_slot.name if hasattr(body_slot, 'name') else body_slot, int(body_slot), cas_part) for (body_slot, cas_part) in self.outfit_parts.items()]) - return result diff --git a/Scripts/s4ap/sims4communitylib/enums/__init__.py b/Scripts/s4ap/sims4communitylib/enums/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/enums/affordance_list_ids.py b/Scripts/s4ap/sims4communitylib/enums/affordance_list_ids.py deleted file mode 100644 index cdc6676..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/affordance_list_ids.py +++ /dev/null @@ -1,21 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonAffordanceListId(CommonInt): - """Identifiers for affordance lists. - - """ - INVALID: 'CommonAffordanceListId' = 0 - DEBUG_AFFORDANCES = 26870 # debug_affordances - SOCIAL_MIXERS_FRIENDLY_NON_TOUCHING = 24508 # social_Mixers_Friendly_NonTouching - SOCIAL_MIXERS_FRIENDLY_NON_TOUCHING_FOR_REFERENCE = 163702 # social_Mixers_Friendly_NonTouching_ForReference - SOCIAL_MIXERS_ROMANCE_NON_TOUCHING = 24510 # social_Mixers_Romance_NonTouching - SOCIAL_MIXERS_ROMANCE_NON_TOUCHING_FOR_REFERENCE = 163713 # social_Mixers_Romance_NonTouching_ForReference - SOCIAL_MIXERS_MISCHIEF_NON_TOUCHING_FOR_REFERENCE = 163708 # social_Mixers_Mischief_NonTouching_ForReference diff --git a/Scripts/s4ap/sims4communitylib/enums/animation_state_machines_enum.py b/Scripts/s4ap/sims4communitylib/enums/animation_state_machines_enum.py deleted file mode 100644 index d9a4ebe..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/animation_state_machines_enum.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonAnimationStateMachineId(CommonInt): - """Identifiers for vanilla animation state machines (ASM). - - """ - INVALID: 'CommonAnimationStateMachineId' = 0 - STAND_POSTURE: 'CommonAnimationStateMachineId' = 15425961973529743787 diff --git a/Scripts/s4ap/sims4communitylib/enums/buffs_enum.py b/Scripts/s4ap/sims4communitylib/enums/buffs_enum.py deleted file mode 100644 index b8b1ae2..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/buffs_enum.py +++ /dev/null @@ -1,14677 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonBuffId(CommonInt): - """Identifiers for vanilla buffs - - """ - # APM = Apartment Problem - # CDG = Core Dating Gameplay - S4CL_EXAMPLE_APPLY_BARE_FEET: 'CommonBuffId' = 16461769487103204847 - - INVALID: 'CommonBuffId' = 0 - ACTING_SKILL_MOOD_ENERGIZED_ACTION: 'CommonBuffId' = 195825 - ACTING_SKILL_MOOD_ENERGIZED_HORROR: 'CommonBuffId' = 195827 - ACTING_SKILL_MOOD_ENERGIZED_SCI_FI: 'CommonBuffId' = 195826 - ACTING_SKILL_MOOD_FLIRTY: 'CommonBuffId' = 195811 - ACTING_SKILL_MOOD_HAPPY: 'CommonBuffId' = 195824 - ACTING_SKILL_MOOD_INSPIRED: 'CommonBuffId' = 195823 - ACTING_SKILL_MOOD_INSPIRED_DRAMATIC_MONOLOGUE: 'CommonBuffId' = 199388 - ACTING_SKILL_MOOD_PLAYFUL: 'CommonBuffId' = 195822 - ACTING_SKILL_PERFORMING_ROUTINE: 'CommonBuffId' = 195118 - ACTING_SKILL_PERFORMING_ROUTINE_FOR_TIPS: 'CommonBuffId' = 195550 - ACTING_SKILL_SKILL_FROM_CAS_REWARD: 'CommonBuffId' = 197822 - ACTING_SKILL_SUCCESSFUL_ROUTINE_ENERGIZED_ACTION: 'CommonBuffId' = 195855 - ACTING_SKILL_SUCCESSFUL_ROUTINE_ENERGIZED_HORROR: 'CommonBuffId' = 195856 - ACTING_SKILL_SUCCESSFUL_ROUTINE_ENERGIZED_SCI_FI: 'CommonBuffId' = 195857 - ACTING_SKILL_SUCCESSFUL_ROUTINE_FLIRTY: 'CommonBuffId' = 195858 - ACTING_SKILL_SUCCESSFUL_ROUTINE_HAPPY: 'CommonBuffId' = 195859 - ACTING_SKILL_SUCCESSFUL_ROUTINE_INSPIRED: 'CommonBuffId' = 195551 - ACTING_SKILL_SUCCESSFUL_ROUTINE_INSPIRED_DRAMATIC_MONOLOGUE: 'CommonBuffId' = 199383 - ACTING_SKILL_SUCCESSFUL_ROUTINE_PLAYFUL: 'CommonBuffId' = 195860 - ACTING_SKILL_THESPIAN_TRAINING: 'CommonBuffId' = 199560 - ACTIVITY_TABLE_HOLIDAY_CRAFT: 'CommonBuffId' = 186344 - ACTIVITY_TABLE_SEASONAL_CRAFT: 'CommonBuffId' = 186345 - ACTOR_CAREER_AGENCY_WELL_SUITED_AMATEUR_FAIL: 'CommonBuffId' = 199369 - ACTOR_CAREER_GOT_INTO_COSTUME: 'CommonBuffId' = 189356 - ACTOR_CAREER_GOT_INTO_HAIR_MAKE_UP: 'CommonBuffId' = 189354 - ACTOR_CAREER_HAIR_COMMERCIAL_HOSPITAL: 'CommonBuffId' = 197526 - ACTOR_CAREER_HAIR_COMMERCIAL_HOUSE_NICE: 'CommonBuffId' = 197516 - ACTOR_CAREER_HAIR_COMMERCIAL_KIDS: 'CommonBuffId' = 197519 - ACTOR_CAREER_HAIR_COMMERCIAL_PIRATE: 'CommonBuffId' = 197514 - ACTOR_CAREER_HAIR_COMMERCIAL_WESTERN: 'CommonBuffId' = 197530 - ACTOR_CAREER_HAIR_FAIL: 'CommonBuffId' = 197855 - ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR1_COMMERCIAL_HOSPITAL: 'CommonBuffId' = 201797 - ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR1_COMMERCIAL_HOUSE_NICE: 'CommonBuffId' = 201798 - ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR1_MOVIE_CITY: 'CommonBuffId' = 201821 - ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR1_MOVIE_MEDIEVAL: 'CommonBuffId' = 201817 - ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR1_MOVIE_PIRATE: 'CommonBuffId' = 201816 - ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR1_MOVIE_SUPERHERO: 'CommonBuffId' = 201820 - ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR1_MOVIE_VICTORIAN: 'CommonBuffId' = 201819 - ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR1_MOVIE_WESTERN: 'CommonBuffId' = 201818 - ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR1_TV_HIGH_APOCALYPSE: 'CommonBuffId' = 201804 - ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR1_TV_HIGH_HOSPITAL: 'CommonBuffId' = 201805 - ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR1_TV_HIGH_POLICE: 'CommonBuffId' = 201808 - ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR1_TV_HIGH_VICTORIAN: 'CommonBuffId' = 201807 - ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR1_TV_HIGH_WESTERN: 'CommonBuffId' = 201806 - ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR1_TV_LOW_HOUSE_LOW: 'CommonBuffId' = 201802 - ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR1_TV_LOW_HOUSE_NICE: 'CommonBuffId' = 201800 - ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR1_TV_LOW_PIRATE: 'CommonBuffId' = 201799 - ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR1_TV_LOW_WESTERN: 'CommonBuffId' = 201801 - ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR2_MOVIE_CITY: 'CommonBuffId' = 201832 - ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR2_MOVIE_MEDIEVAL: 'CommonBuffId' = 201828 - ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR2_MOVIE_PIRATE: 'CommonBuffId' = 201827 - ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR2_MOVIE_SUPERHERO: 'CommonBuffId' = 201831 - ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR2_MOVIE_VICTORIAN: 'CommonBuffId' = 201830 - ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR2_MOVIE_WESTERN: 'CommonBuffId' = 201829 - ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR2_TV_HIGH_APOCALYPSE: 'CommonBuffId' = 201809 - ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR2_TV_HIGH_HOSPITAL: 'CommonBuffId' = 201811 - ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR2_TV_HIGH_POLICE: 'CommonBuffId' = 201812 - ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR2_TV_HIGH_VICTORIAN: 'CommonBuffId' = 201810 - ACTOR_CAREER_HAIR_MAKE_UP_CO_STAR2_TV_LOW_PIRATE: 'CommonBuffId' = 201803 - ACTOR_CAREER_HAIR_MOVIE_CITY: 'CommonBuffId' = 197523 - ACTOR_CAREER_HAIR_MOVIE_MEDIEVAL: 'CommonBuffId' = 197529 - ACTOR_CAREER_HAIR_MOVIE_PIRATE: 'CommonBuffId' = 197525 - ACTOR_CAREER_HAIR_MOVIE_SUPERHERO: 'CommonBuffId' = 197522 - ACTOR_CAREER_HAIR_MOVIE_VICTORIAN: 'CommonBuffId' = 197518 - ACTOR_CAREER_HAIR_MOVIE_WESTERN: 'CommonBuffId' = 197533 - ACTOR_CAREER_HAIR_TV_HIGH_APOCALYPSE: 'CommonBuffId' = 197524 - ACTOR_CAREER_HAIR_TV_HIGH_HOSPITAL: 'CommonBuffId' = 197528 - ACTOR_CAREER_HAIR_TV_HIGH_POLICE: 'CommonBuffId' = 197521 - ACTOR_CAREER_HAIR_TV_HIGH_VICTORIAN: 'CommonBuffId' = 197517 - ACTOR_CAREER_HAIR_TV_HIGH_WESTERN: 'CommonBuffId' = 197532 - ACTOR_CAREER_HAIR_TV_LOW_HOUSE_LOW: 'CommonBuffId' = 197534 - ACTOR_CAREER_HAIR_TV_LOW_HOUSE_NICE: 'CommonBuffId' = 197527 - ACTOR_CAREER_HAIR_TV_LOW_KIDS: 'CommonBuffId' = 197520 - ACTOR_CAREER_HAIR_TV_LOW_PIRATE: 'CommonBuffId' = 197515 - ACTOR_CAREER_HAIR_TV_LOW_WESTERN: 'CommonBuffId' = 197531 - ACTOR_CAREER_MAIN_GOAL: 'CommonBuffId' = 197926 - ACTOR_CAREER_MAKEUP_COMMERCIAL_HOSPITAL: 'CommonBuffId' = 197494 - ACTOR_CAREER_MAKEUP_COMMERCIAL_HOUSE_NICE: 'CommonBuffId' = 197484 - ACTOR_CAREER_MAKEUP_COMMERCIAL_KIDS: 'CommonBuffId' = 197487 - ACTOR_CAREER_MAKEUP_COMMERCIAL_PIRATE: 'CommonBuffId' = 197482 - ACTOR_CAREER_MAKEUP_COMMERCIAL_WESTERN: 'CommonBuffId' = 197498 - ACTOR_CAREER_MAKEUP_GENDER_FAIL_0: 'CommonBuffId' = 202357 - ACTOR_CAREER_MAKEUP_GENDER_FAIL_1: 'CommonBuffId' = 202358 - ACTOR_CAREER_MAKEUP_GENDER_FAIL_2: 'CommonBuffId' = 202359 - ACTOR_CAREER_MAKEUP_GENDER_FAIL_3: 'CommonBuffId' = 202360 - ACTOR_CAREER_MAKEUP_GENDER_FAIL_4: 'CommonBuffId' = 202361 - ACTOR_CAREER_MAKEUP_MOVIE_CITY: 'CommonBuffId' = 197489 - ACTOR_CAREER_MAKEUP_MOVIE_MEDIEVAL: 'CommonBuffId' = 197497 - ACTOR_CAREER_MAKEUP_MOVIE_PIRATE: 'CommonBuffId' = 197493 - ACTOR_CAREER_MAKEUP_MOVIE_SUPERHERO: 'CommonBuffId' = 197490 - ACTOR_CAREER_MAKEUP_MOVIE_VICTORIAN: 'CommonBuffId' = 197486 - ACTOR_CAREER_MAKEUP_MOVIE_WESTERN: 'CommonBuffId' = 197501 - ACTOR_CAREER_MAKEUP_TV_HIGH_APOCALYPSE: 'CommonBuffId' = 197492 - ACTOR_CAREER_MAKEUP_TV_HIGH_HOSPITAL: 'CommonBuffId' = 197496 - ACTOR_CAREER_MAKEUP_TV_HIGH_POLICE: 'CommonBuffId' = 197491 - ACTOR_CAREER_MAKEUP_TV_HIGH_VICTORIAN: 'CommonBuffId' = 197485 - ACTOR_CAREER_MAKEUP_TV_HIGH_WESTERN: 'CommonBuffId' = 197500 - ACTOR_CAREER_MAKEUP_TV_LOW_HOUSE_LOW: 'CommonBuffId' = 197502 - ACTOR_CAREER_MAKEUP_TV_LOW_HOUSE_NICE: 'CommonBuffId' = 197495 - ACTOR_CAREER_MAKEUP_TV_LOW_KIDS: 'CommonBuffId' = 197488 - ACTOR_CAREER_MAKEUP_TV_LOW_PIRATE: 'CommonBuffId' = 197483 - ACTOR_CAREER_MAKEUP_TV_LOW_WESTERN: 'CommonBuffId' = 197499 - ACTOR_CAREER_MAKEUP_UNISEX_FAIL_0: 'CommonBuffId' = 202363 - ACTOR_CAREER_MAKEUP_UNISEX_FAIL_1: 'CommonBuffId' = 202364 - ACTOR_CAREER_MAKEUP_UNISEX_FAIL_2: 'CommonBuffId' = 202365 - ACTOR_CAREER_PRACTICED_SCENE: 'CommonBuffId' = 189338 - ACTOR_CAREER_PREP_TASKS_RESEARCH_MOOD_ANGRY: 'CommonBuffId' = 200801 - ACTOR_CAREER_PREP_TASKS_RESEARCH_MOOD_FLIRTY: 'CommonBuffId' = 200800 - ACTOR_CAREER_PREP_TASKS_RESEARCH_MOOD_PLAY_FUL: 'CommonBuffId' = 200802 - ACTOR_CAREER_READY_TO_PERFORM: 'CommonBuffId' = 191351 - ACTOR_CAREER_ROLE_GO_TO_MARK_BACKGROUND_PRODUCER: 'CommonBuffId' = 191196 - ACTOR_CAREER_ROLE_GO_TO_MARK_COSTAR2: 'CommonBuffId' = 190125 - ACTOR_CAREER_ROLE_GO_TO_MARK_CO_STAR1: 'CommonBuffId' = 189282 - ACTOR_CAREER_ROLE_GO_TO_MARK_DIRECTOR: 'CommonBuffId' = 190126 - ACTOR_CAREER_ROLE_GO_TO_MARK_DOLLY_CAMERA_OPERATOR: 'CommonBuffId' = 190530 - ACTOR_CAREER_ROLE_GO_TO_MARK_SPECIAL_EFFECTS_OPERATOR: 'CommonBuffId' = 192119 - ACTOR_CAREER_ROLE_GO_TO_MARK_STATIONARY_CAMERA_OPERATOR: 'CommonBuffId' = 191276 - ACTOR_CAREER_ROLE_PLAYER: 'CommonBuffId' = 197344 - ACTOR_CAREER_ROLE_PRE_PERFORMANCE_BACKGROUND_ACTOR: 'CommonBuffId' = 193211 - ACTOR_CAREER_ROLE_PRE_PERFORMANCE_BACKGROUND_PRODUCER: 'CommonBuffId' = 192799 - ACTOR_CAREER_ROLE_PRE_PERFORMANCE_DIRECTOR: 'CommonBuffId' = 191096 - ACTOR_CAREER_ROLE_PRE_PERFORMANCE_DOLLY_CAMERA_OPERATOR: 'CommonBuffId' = 191075 - ACTOR_CAREER_ROLE_PRE_PERFORMANCE_SPECIAL_EFFECTS: 'CommonBuffId' = 199288 - ACTOR_CAREER_ROLE_PRE_PERFORMANCE_STATIONARY_CAMERA_OPERATOR: 'CommonBuffId' = 191279 - ADOPTION: 'CommonBuffId' = 40069 - ADULT_MOOD_SWING_ANGRY: 'CommonBuffId' = 164632 - ADULT_MOOD_SWING_EMBARRASSED: 'CommonBuffId' = 164634 - ADULT_MOOD_SWING_SAD: 'CommonBuffId' = 164636 - ADULT_MOOD_SWING_STRESSED: 'CommonBuffId' = 164638 - ADVENTUROUS_ATE_QUICK_MEAL: 'CommonBuffId' = 252229 - ADVENTUROUS_DID_WOOHOO: 'CommonBuffId' = 252180 - ADVENTUROUS_DID_WOOHOO_FLAG_BAT: 'CommonBuffId' = 252252 - ADVENTUROUS_DID_WOOHOO_FLAG_BUSH: 'CommonBuffId' = 252253 - ADVENTUROUS_DID_WOOHOO_FLAG_CLOSET: 'CommonBuffId' = 252262 - ADVENTUROUS_DID_WOOHOO_FLAG_COFFIN: 'CommonBuffId' = 252263 - ADVENTUROUS_DID_WOOHOO_FLAG_DUMPSTER: 'CommonBuffId' = 252264 - ADVENTUROUS_DID_WOOHOO_FLAG_DWELLING: 'CommonBuffId' = 252265 - ADVENTUROUS_DID_WOOHOO_FLAG_HOT_SPRINGS: 'CommonBuffId' = 252266 - ADVENTUROUS_DID_WOOHOO_FLAG_HOT_TUB: 'CommonBuffId' = 252254 - ADVENTUROUS_DID_WOOHOO_FLAG_ISLAND_WATERFALL: 'CommonBuffId' = 252255 - ADVENTUROUS_DID_WOOHOO_FLAG_LEAF_PILE: 'CommonBuffId' = 252256 - ADVENTUROUS_DID_WOOHOO_FLAG_LIGHTHOUSE: 'CommonBuffId' = 252257 - ADVENTUROUS_DID_WOOHOO_FLAG_LIVESTOCK_PEN: 'CommonBuffId' = 257640 - ADVENTUROUS_DID_WOOHOO_FLAG_ROCKET_SHIP: 'CommonBuffId' = 252258 - ADVENTUROUS_DID_WOOHOO_FLAG_ROMANTIC_BLANKET: 'CommonBuffId' = 359659 - ADVENTUROUS_DID_WOOHOO_FLAG_SLEEPING_POD: 'CommonBuffId' = 252259 - ADVENTUROUS_DID_WOOHOO_FLAG_STEAM_ROOM: 'CommonBuffId' = 252260 - ADVENTUROUS_DID_WOOHOO_FLAG_TELESCOPE: 'CommonBuffId' = 252261 - ADVENTUROUS_DID_WOOHOO_FLAG_TENT: 'CommonBuffId' = 252267 - ADVENTUROUS_DID_WOOHOO_FLAG_TREEHOUSE: 'CommonBuffId' = 310670 - ADVENTUROUS_DID_WOOHOO_FLAG_WALK_IN_SAFE: 'CommonBuffId' = 252268 - ADVENTUROUS_HIGH_SKILL_BORED: 'CommonBuffId' = 252512 - ADVENTUROUS_HIGH_SKILL_BORED_GAIN: 'CommonBuffId' = 252510 - ADVENTUROUS_INSPIRED_MEAL: 'CommonBuffId' = 252306 - ADVENTUROUS_LOW_SKILL_BONUS_SKILL: 'CommonBuffId' = 252507 - ADVENTUROUS_ON_AN_ADVENTURE: 'CommonBuffId' = 252221 - ADVENTUROUS_TALE: 'CommonBuffId' = 103144 - ADVENTUROUS_TALE_GREAT_STORY: 'CommonBuffId' = 109730 - ALIEN_ABDUCTION_HIGH: 'CommonBuffId' = 102868 - ALIEN_ABDUCTION_HIGH_SATELLITE_CALLED: 'CommonBuffId' = 107162 - ALIEN_ABDUCTION_LOW: 'CommonBuffId' = 115180 - ALIEN_ABDUCTION_MEDIUM: 'CommonBuffId' = 115181 - ALIEN_ABDUCTION_NO_CHANCE: 'CommonBuffId' = 107158 - ALIEN_ABDUCTION_VERY_HIGH: 'CommonBuffId' = 115182 - ALIEN_ABDUCTION_VERY_LOW: 'CommonBuffId' = 115179 - ALIEN_ALIEN_CONTACT_FROM_SATELLITE: 'CommonBuffId' = 107166 - ALIEN_DETECT_AURA: 'CommonBuffId' = 108874 - ALIEN_DISCOVERY_ANGRY_REACTION: 'CommonBuffId' = 111529 - ALIEN_DISCOVERY_CONFIDENT_REACTION: 'CommonBuffId' = 111530 - ALIEN_DISCOVERY_EMBARRASSED_ALIEN: 'CommonBuffId' = 111528 - ALIEN_DISCOVERY_SUBJECT_OF_ALIEN_BRAINPOWER_INTERACTION: 'CommonBuffId' = 116577 - ALIEN_EMPATHY_COOLDOWN_TIMER: 'CommonBuffId' = 103559 - ALIEN_EMPATHY_EMOTION_ANGRY: 'CommonBuffId' = 103474 - ALIEN_EMPATHY_EMOTION_BORED: 'CommonBuffId' = 103475 - ALIEN_EMPATHY_EMOTION_CONFIDENT: 'CommonBuffId' = 103487 - ALIEN_EMPATHY_EMOTION_DAZED: 'CommonBuffId' = 103486 - ALIEN_EMPATHY_EMOTION_EMBARRASSED: 'CommonBuffId' = 103485 - ALIEN_EMPATHY_EMOTION_ENERGIZED: 'CommonBuffId' = 103484 - ALIEN_EMPATHY_EMOTION_FLIRTY: 'CommonBuffId' = 103483 - ALIEN_EMPATHY_EMOTION_FOCUSED: 'CommonBuffId' = 103482 - ALIEN_EMPATHY_EMOTION_HAPPY: 'CommonBuffId' = 103481 - ALIEN_EMPATHY_EMOTION_INSPIRED: 'CommonBuffId' = 103480 - ALIEN_EMPATHY_EMOTION_PLAYFUL: 'CommonBuffId' = 103479 - ALIEN_EMPATHY_EMOTION_SAD: 'CommonBuffId' = 103478 - ALIEN_EMPATHY_EMOTION_STRESSED: 'CommonBuffId' = 103477 - ALIEN_EMPATHY_EMOTION_UNCOMFORTABLE: 'CommonBuffId' = 103476 - ALIEN_HOMESICK: 'CommonBuffId' = 103361 - ALIEN_IS_ALIEN: 'CommonBuffId' = 103358 - ALIEN_LOW_BRAIN_POWER: 'CommonBuffId' = 103333 - ALIEN_MEMORY_ERASE: 'CommonBuffId' = 103576 - ALIEN_MOOD_AURA_ANGRY: 'CommonBuffId' = 108933 - ALIEN_MOOD_AURA_BORED: 'CommonBuffId' = 108943 - ALIEN_MOOD_AURA_CHILD_ANGRY: 'CommonBuffId' = 114644 - ALIEN_MOOD_AURA_CHILD_BORED: 'CommonBuffId' = 114645 - ALIEN_MOOD_AURA_CHILD_CONFIDENT: 'CommonBuffId' = 114654 - ALIEN_MOOD_AURA_CHILD_EMBARRASSED: 'CommonBuffId' = 114646 - ALIEN_MOOD_AURA_CHILD_ENERGISED: 'CommonBuffId' = 114647 - ALIEN_MOOD_AURA_CHILD_FOCUSED: 'CommonBuffId' = 114649 - ALIEN_MOOD_AURA_CHILD_HAPPY: 'CommonBuffId' = 114648 - ALIEN_MOOD_AURA_CHILD_INSPIRED: 'CommonBuffId' = 114650 - ALIEN_MOOD_AURA_CHILD_PLAYFUL: 'CommonBuffId' = 114651 - ALIEN_MOOD_AURA_CHILD_SAD: 'CommonBuffId' = 114652 - ALIEN_MOOD_AURA_CHILD_STRESSED: 'CommonBuffId' = 114653 - ALIEN_MOOD_AURA_CHILD_UNCOMFORTABLE: 'CommonBuffId' = 114655 - ALIEN_MOOD_AURA_CONFIDENT: 'CommonBuffId' = 108944 - ALIEN_MOOD_AURA_DAZED: 'CommonBuffId' = 108945 - ALIEN_MOOD_AURA_EMBARRASSED: 'CommonBuffId' = 108935 - ALIEN_MOOD_AURA_ENERGISED: 'CommonBuffId' = 108936 - ALIEN_MOOD_AURA_FLIRTY: 'CommonBuffId' = 108937 - ALIEN_MOOD_AURA_FOCUSED: 'CommonBuffId' = 108938 - ALIEN_MOOD_AURA_HAPPY: 'CommonBuffId' = 108939 - ALIEN_MOOD_AURA_INSPIRED: 'CommonBuffId' = 108940 - ALIEN_MOOD_AURA_PLAYFUL: 'CommonBuffId' = 108941 - ALIEN_MOOD_AURA_REMOVED_MOOD_AURA_BUFFS: 'CommonBuffId' = 114656 - ALIEN_MOOD_AURA_SAD: 'CommonBuffId' = 108934 - ALIEN_MOOD_AURA_STRESSED: 'CommonBuffId' = 108942 - ALIEN_MOOD_AURA_UNCOMFORTABLE: 'CommonBuffId' = 108946 - ALIEN_REMINDED_OF_HOME: 'CommonBuffId' = 103362 - ALIEN_SATELLITE_DETECT_ALIENS_COOL_DOWN: 'CommonBuffId' = 115021 - ALIEN_SATELLITE_DISH_HIVE_MIND_ANGRY: 'CommonBuffId' = 107525 - ALIEN_SATELLITE_DISH_HIVE_MIND_DANCE: 'CommonBuffId' = 107524 - ALIEN_SATELLITE_DISH_HIVE_MIND_HAPPY: 'CommonBuffId' = 107526 - ALIEN_SATELLITE_DISH_HIVE_MIND_KNOCKED_OUT: 'CommonBuffId' = 107533 - ALIEN_SATELLITE_DISH_HIVE_MIND_KNOCKOUT_DAZED: 'CommonBuffId' = 107534 - ALIEN_SCARE_WITH_PROBE: 'CommonBuffId' = 115015 - ALIEN_VISIT_ALIEN: 'CommonBuffId' = 113541 - ALLOW_SLEEP_DESIRE: 'CommonBuffId' = 36123 - ALMOST_ALWAYS_RUN: 'CommonBuffId' = 207314 - ANGRY_ABOUT_VICIOUS_RUMOR: 'CommonBuffId' = 35130 - ANIMAL_OBJECTS_BIRD_HOME_SINGING_SKILL_EXISTS: 'CommonBuffId' = 269176 - ANIMAL_OBJECTS_CHEATS_FORCE_OUTCOME_SOCIAL_FAIL: 'CommonBuffId' = 257699 - ANIMAL_OBJECTS_CHEATS_FORCE_OUTCOME_SOCIAL_SUCCESS: 'CommonBuffId' = 257698 - ANIMAL_OBJECTS_CHICKEN_GRIM_DEFEATED: 'CommonBuffId' = 268695 - ANIMAL_OBJECTS_COWS_COWBELL_COOLDOWN: 'CommonBuffId' = 268471 - ANIMAL_OBJECTS_GOAT_SHEEP_SAW_TRICK_HIDDEN: 'CommonBuffId' = 331883 - ANIMAL_OBJECTS_MOODLETS_DEATH_RABBIT: 'CommonBuffId' = 257724 - ANIMAL_OBJECTS_MOODLETS_EGG_DARK_CHICKEN: 'CommonBuffId' = 267396 - ANIMAL_OBJECTS_MOODLETS_EGG_GOLDEN_CHICKEN: 'CommonBuffId' = 267395 - ANIMAL_OBJECTS_MOODLETS_EGG_MMM_CHOCOLATE: 'CommonBuffId' = 267386 - ANIMAL_OBJECTS_MOODLETS_GHOST_KILLER_CHICKEN_ANGRY: 'CommonBuffId' = 268000 - ANIMAL_OBJECTS_MOODLETS_GHOST_KILLER_CHICKEN_SCARED: 'CommonBuffId' = 268001 - ANIMAL_OBJECTS_MOODLETS_GHOST_KILLER_CHICKEN_TENSE: 'CommonBuffId' = 268002 - ANIMAL_OBJECTS_MOODLETS_GHOST_KILLER_RABBIT_ANGRY: 'CommonBuffId' = 260124 - ANIMAL_OBJECTS_MOODLETS_GHOST_KILLER_RABBIT_SCARED: 'CommonBuffId' = 260122 - ANIMAL_OBJECTS_MOODLETS_GHOST_KILLER_RABBIT_TENSE: 'CommonBuffId' = 260123 - ANIMAL_OBJECTS_MOODLETS_GOAT_SHEEP_IMPROVE_MOOD_COOLDOWN: 'CommonBuffId' = 327758 - ANIMAL_OBJECTS_MOODLETS_GOAT_SHEEP_PLACE_DOWN_COOLDOWN: 'CommonBuffId' = 351539 - ANIMAL_OBJECTS_MOODLETS_NEW_FRIEND_BIRD_HOME: 'CommonBuffId' = 257727 - ANIMAL_OBJECTS_MOODLETS_NEW_FRIEND_RABBIT: 'CommonBuffId' = 257726 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_ANGRY_BIRD_HOME_SHOW_AFFECTION: 'CommonBuffId' = 268821 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_ANGRY_BIRD_HOME_TALK: 'CommonBuffId' = 257766 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_CONFIDENT_BIRD_HOME_SCARE: 'CommonBuffId' = 257776 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_CONFIDENT_CHICKEN_ATTACKED: 'CommonBuffId' = 268039 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_CONFIDENT_RABBIT_ATTACKED: 'CommonBuffId' = 257751 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_DAZED_CHICKEN_ATTACKED: 'CommonBuffId' = 268040 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_DAZED_RABBIT_ATTACKED: 'CommonBuffId' = 257753 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_EMBARRASSED_BIRD_HOME_QUESTION: 'CommonBuffId' = 257769 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_EMBARRASSED_BIRD_HOME_SING: 'CommonBuffId' = 257780 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_EMBARRASSED_GOAT_JOKE: 'CommonBuffId' = 326070 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_EMBARRASSED_LIVESTOCK_PEN_SCARE_ANIMAL_ENTHUSIAST: 'CommonBuffId' = 263700 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_EMBARRASSED_RABBIT_JOKE: 'CommonBuffId' = 257738 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_EMBARRASSED_SHEEP_JOKE: 'CommonBuffId' = 326071 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_ENERGIZED_BIRD_HOME_WATCH: 'CommonBuffId' = 257756 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_ENERGIZED_COWBELL: 'CommonBuffId' = 268477 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_ENERGIZED_SHEEP_COUNT: 'CommonBuffId' = 325648 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_HAPPY_BIRD_HOME_QUESTION: 'CommonBuffId' = 257767 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_HAPPY_BIRD_HOME_SCARE: 'CommonBuffId' = 257772 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_HAPPY_BIRD_HOME_SHOW_AFFECTION: 'CommonBuffId' = 268820 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_HAPPY_BIRD_HOME_TALK: 'CommonBuffId' = 257761 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_HAPPY_CHICKEN_HUG: 'CommonBuffId' = 261286 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_HAPPY_COW_HUG: 'CommonBuffId' = 263671 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_HAPPY_COW_HUG_ANIMAL_ENTHUSIAST: 'CommonBuffId' = 263672 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_HAPPY_GOAT_HUG: 'CommonBuffId' = 326075 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_HAPPY_GOAT_PET: 'CommonBuffId' = 326077 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_HAPPY_GOAT_TALK: 'CommonBuffId' = 326072 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_HAPPY_LLAMA_HUG: 'CommonBuffId' = 263673 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_HAPPY_LLAMA_HUG_ANIMAL_ENTHUSIAST: 'CommonBuffId' = 263674 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_HAPPY_RABBIT_HUG: 'CommonBuffId' = 257747 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_HAPPY_RABBIT_JOKE: 'CommonBuffId' = 257733 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_HAPPY_RABBIT_TALK: 'CommonBuffId' = 257729 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_HAPPY_ROOSTER_HUG: 'CommonBuffId' = 271329 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_HAPPY_SHEEP_HUG: 'CommonBuffId' = 326074 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_HAPPY_SHEEP_PET: 'CommonBuffId' = 326076 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_HAPPY_SHEEP_TALK: 'CommonBuffId' = 326073 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_INSPIRED_BIRD_HOME_QUESTION: 'CommonBuffId' = 257768 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_INSPIRED_BIRD_HOME_SING: 'CommonBuffId' = 257778 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_INSPIRED_BIRD_HOME_TALK: 'CommonBuffId' = 257762 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_INSPIRED_BIRD_HOME_WATCH: 'CommonBuffId' = 257757 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_INSPIRED_RABBIT_QUESTION: 'CommonBuffId' = 257732 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_PLAYFUL_GOAT_BE_MEAN: 'CommonBuffId' = 326078 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_PLAYFUL_GOAT_JOKE: 'CommonBuffId' = 326092 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_PLAYFUL_GOAT_PLAY_WITH: 'CommonBuffId' = 326094 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_PLAYFUL_GOAT_SCARE: 'CommonBuffId' = 326091 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_PLAYFUL_RABBIT_BE_MEAN: 'CommonBuffId' = 257742 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_PLAYFUL_RABBIT_JOKE: 'CommonBuffId' = 257735 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_PLAYFUL_RABBIT_SCARE: 'CommonBuffId' = 257741 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_PLAYFUL_SHEEP_BE_MEAN: 'CommonBuffId' = 326079 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_PLAYFUL_SHEEP_JOKE: 'CommonBuffId' = 326093 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_PLAYFUL_SHEEP_PLAY_WITH: 'CommonBuffId' = 326095 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_PLAYFUL_SHEEP_SCARE: 'CommonBuffId' = 326090 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_PLAYFUL_SHEEP_TRICK: 'CommonBuffId' = 325223 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_BIRD_HOME_QUESTION: 'CommonBuffId' = 257770 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_BIRD_HOME_SHOW_AFFECTION: 'CommonBuffId' = 268825 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_BIRD_HOME_SING: 'CommonBuffId' = 257779 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_CHICKEN_DEATH: 'CommonBuffId' = 261284 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_CHICKEN_MISSING: 'CommonBuffId' = 261285 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_CHICKEN_SOLD: 'CommonBuffId' = 261287 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_COWBELL: 'CommonBuffId' = 268484 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_COW_DEATH: 'CommonBuffId' = 263656 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_COW_HUG: 'CommonBuffId' = 263713 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_COW_HUG_ANIMAL_ENTHUSIAST: 'CommonBuffId' = 263714 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_COW_SOLD: 'CommonBuffId' = 263676 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_GOAT_DEATH: 'CommonBuffId' = 330927 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_GOAT_MISSING: 'CommonBuffId' = 336493 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_GOAT_TALK: 'CommonBuffId' = 326096 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_LIVESTOCK_PEN_GO_MISSING: 'CommonBuffId' = 268063 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_LLAMA_DEATH: 'CommonBuffId' = 263657 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_LLAMA_SOLD: 'CommonBuffId' = 263677 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_PET_TODDLER: 'CommonBuffId' = 339929 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_RABBIT_HUG: 'CommonBuffId' = 257749 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_SHEEP_DEATH: 'CommonBuffId' = 330928 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_SHEEP_HUG: 'CommonBuffId' = 326098 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_SHEEP_MISSING: 'CommonBuffId' = 336494 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_SHEEP_PET: 'CommonBuffId' = 326099 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_SHEEP_PLAY_WITH: 'CommonBuffId' = 326100 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_SAD_SHEEP_TALK: 'CommonBuffId' = 326097 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_SCARED_CHICKEN_PECKED_AT: 'CommonBuffId' = 261271 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_SCARED_CHICKEN_PECKED_AT_TODDLERS: 'CommonBuffId' = 264978 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_SCARED_LLAMA_HUG: 'CommonBuffId' = 263716 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_SCARED_RABBIT_ATTACKED: 'CommonBuffId' = 257754 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_SCARED_RABBIT_PET: 'CommonBuffId' = 257744 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_SCARED_ROOSTER_PECKED_AT: 'CommonBuffId' = 271331 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_SCARED_ROOSTER_PECKED_AT_TODDLERS: 'CommonBuffId' = 271332 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_TENSE_COW_MILK_FAIL: 'CommonBuffId' = 263084 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_TENSE_COW_MILK_FAIL_ANIMAL_ENTHUSIAST: 'CommonBuffId' = 267015 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_TENSE_LIVESTOCK_PEN_BE_MEAN_ANIMAL_ENTHUSIAST: 'CommonBuffId' = 263699 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_TENSE_LLAMA_SHEAR_FAIL: 'CommonBuffId' = 263085 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_TENSE_LLAMA_SHEAR_FAIL_ANIMAL_ENTHUSIAST: 'CommonBuffId' = 267016 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_TENSE_RABBIT_JOKE: 'CommonBuffId' = 257745 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_TENSE_RABBIT_PET: 'CommonBuffId' = 257746 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_UNCOMFORTABLE_BIRD_HOME_SING: 'CommonBuffId' = 257781 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_UNCOMFORTABLE_BIRD_HOME_TALK: 'CommonBuffId' = 257764 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_UNCOMFORTABLE_GOAT_HEADBUTT: 'CommonBuffId' = 326101 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_UNCOMFORTABLE_GOAT_YELLING: 'CommonBuffId' = 325100 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_UNCOMFORTABLE_LIVESTOCK_PEN_SMELLY: 'CommonBuffId' = 263698 - ANIMAL_OBJECTS_MOODLETS_SOCIALS_UNCOMFORTABLE_LLAMA_HUG: 'CommonBuffId' = 263715 - ANIMAL_OBJECTS_MOODLETS_TRAIT_SQUEAMISH_BIRD_HOME_GARDENING_HELP: 'CommonBuffId' = 257785 - ANIMAL_OBJECTS_MOODLETS_TRAIT_SQUEAMISH_BIRD_HOME_POOPED_ON: 'CommonBuffId' = 257784 - ANIMAL_OBJECTS_RABBIT_SIM_ABOUT_TO_DIE: 'CommonBuffId' = 264515 - ANIMAL_OBJECTS_SOLD_MY_FRIEND_TRACKER: 'CommonBuffId' = 339253 - APM_ANNOYING_FREELOADERS: 'CommonBuffId' = 347766 - APM_CONTRACT_BROKEN: 'CommonBuffId' = 347767 - APM_DELIVER_FINE_COOLDOWN: 'CommonBuffId' = 359216 - APM_DELIVER_RENT_COOLDOWN: 'CommonBuffId' = 359214 - APM_GETTING_AWAY_WITH_IT: 'CommonBuffId' = 347764 - APM_POST_COOLDOWN: 'CommonBuffId' = 357722 - APM_POST_FINE_COOLDOWN: 'CommonBuffId' = 359215 - APM_POST_RENT_COOLDOWN: 'CommonBuffId' = 359213 - APM_POWER_OUTAGE_ANGRY_WAIT_COOLDOWN: 'CommonBuffId' = 358727 - APM_POWER_OUTAGE_AT_OWNED_RENTABLE_RESIDENTIAL: 'CommonBuffId' = 351431 - APM_PROSECUTE_FINE_COOLDOWN: 'CommonBuffId' = 359461 - APM_RELIABLE_SUPPORT: 'CommonBuffId' = 347761 - APM_SHODDY_SUPPORT: 'CommonBuffId' = 347762 - APM_SITUATION_ARRIVAL: 'CommonBuffId' = 355966 - APM_TAKING_THE_HIT: 'CommonBuffId' = 347763 - APM_TREACHEROUS_TENANTS: 'CommonBuffId' = 347765 - APPLY_FROZEN_ADULT: 'CommonBuffId' = 116188 - APPLY_FROZEN_CHILD: 'CommonBuffId' = 116189 - ARCADE_MACHINE_GAME_WIN: 'CommonBuffId' = 129185 - ARCADE_MACHINE_LEVEL_WIN: 'CommonBuffId' = 129184 - ARCADE_MACHINE_LOSE_GAME_HIDDEN: 'CommonBuffId' = 127480 - ARCADE_MACHINE_PLAYER_1: 'CommonBuffId' = 128521 - ARCADE_MACHINE_PLAYER_2: 'CommonBuffId' = 128522 - ARCADE_MACHINE_PLAYER_3: 'CommonBuffId' = 128523 - ARCADE_MACHINE_PLAYER_4: 'CommonBuffId' = 128520 - ARCADE_MACHINE_WIN_GAME_HIDDEN: 'CommonBuffId' = 129284 - ARCADE_MACHINE_WIN_GAME_WALK_AWAY_HIDDEN: 'CommonBuffId' = 129550 - ARCHAEOLOGY_SKILL_GIVE_ARCHAEOLOGY_LECTURE_ACTOR_FAILURE: 'CommonBuffId' = 174886 - ARCHAEOLOGY_SKILL_GIVE_ARCHAEOLOGY_LECTURE_ACTOR_SUCCESS: 'CommonBuffId' = 174855 - ARCHAEOLOGY_SKILL_GIVE_ARCHAEOLOGY_LECTURE_LISTENERS_SUCCESS: 'CommonBuffId' = 174889 - ARCHAEOLOGY_SKILL_STUDY_FOR_HISTORICAL_INSIGHTS_FOCUSED: 'CommonBuffId' = 174307 - ARCHAEOLOGY_TABLE_ANALYZE_COLLECTIBLE_FOCUSED: 'CommonBuffId' = 175740 - ARCHAEOLOGY_TABLE_AUTHENTICATE_ARTIFACT_FOCUSED: 'CommonBuffId' = 176077 - ARCHAEOLOGY_TABLE_UNCOVER_ARTIFACT_FOCUSED: 'CommonBuffId' = 176078 - ASKED_TO_STAY_NIGHT_INVISIBLE: 'CommonBuffId' = 101209 - ASK_FOR_RECYCLING_MATERIALS_COOLDOWN: 'CommonBuffId' = 234365 - ASK_SIM_TO_PURSUE_DREAM_JOB_AMATEUR_CAREER_CONSULTANT: 'CommonBuffId' = 274864 - ASK_SIM_TO_PURSUE_DREAM_JOB_EXPERT_CAREER_CONSULTANT: 'CommonBuffId' = 274862 - ASK_SIM_TO_PURSUE_DREAM_JOB_HIDDEN_COOLDOWN_FAILURE: 'CommonBuffId' = 274796 - ASK_SIM_TO_PURSUE_DREAM_JOB_HIDDEN_COOLDOWN_SUCCESS: 'CommonBuffId' = 274821 - ASK_SIM_TO_PURSUE_DREAM_JOB_ONLY_TRYING_TO_HELP: 'CommonBuffId' = 274822 - ASK_SIM_TO_PURSUE_DREAM_JOB_SERIOUS_LIFE_CHANGES: 'CommonBuffId' = 274863 - ASPIRATION_COMPLETE_INVISIBLE: 'CommonBuffId' = 325690 - ASPIRATION_MIND_AND_BODY_NO_BAD_MOOD: 'CommonBuffId' = 313715 - ASPIRATION_MIND_AND_BODY_NO_BAD_MOOD_COMPLETE: 'CommonBuffId' = 313716 - ASPIRATION_SUPER_PARENT_IN_LIFE_SKILL_RANGE: 'CommonBuffId' = 167467 - ATMOSPHERIC_CONDENSER_WATER_PRESSURE_UNCOMFORTABLE: 'CommonBuffId' = 233300 - ATTRACTION_CAN_LEARN_ATTRACTION_REQUIRED_STUFF: 'CommonBuffId' = 380149 - ATTRACTION_CONVERSATION_EMBARRASSED: 'CommonBuffId' = 362281 - ATTRACTION_CONVERSATION_HAPPY: 'CommonBuffId' = 362282 - ATTRACTION_FOUND_ATTRACTIVE: 'CommonBuffId' = 365137 - ATTRACTION_HAS_TURN_OFF: 'CommonBuffId' = 365341 - ATTRACTION_HAS_TURN_ON: 'CommonBuffId' = 365340 - ATTRACTION_LEARN_ABOUT_IDLE_CHAT_COOLDOWN: 'CommonBuffId' = 364915 - ATTRACTOR_POINT_BEACH_COOLDOWN: 'CommonBuffId' = 209673 - AT_MAGIC_HQ: 'CommonBuffId' = 216284 - AUTONOMOUS_GRILL_COOLDOWN: 'CommonBuffId' = 351701 - AUTONOMY_MOD_ACTIVITY_TABLE: 'CommonBuffId' = 143507 - AUTONOMY_MOD_ADD_CANDLES_TO_CAKE: 'CommonBuffId' = 39354 - AUTONOMY_MOD_APM_ANGRY_VISIBLE: 'CommonBuffId' = 357312 - AUTONOMY_MOD_APM_CHECK_RULES_FOR_VISIT_COOLDOWN: 'CommonBuffId' = 359443 - AUTONOMY_MOD_APM_DELIVER_FINE: 'CommonBuffId' = 358859 - AUTONOMY_MOD_APM_DOMAIN_TENANCE: 'CommonBuffId' = 358084 - AUTONOMY_MOD_APM_PRIMARY_REMEDY: 'CommonBuffId' = 345513 - AUTONOMY_MOD_APM_SECONDARY_REMEDY: 'CommonBuffId' = 345675 - AUTONOMY_MOD_APM_TRIGGER_EVICTION: 'CommonBuffId' = 351126 - AUTONOMY_MOD_ARTS_CENTER_ORDER_DRINK: 'CommonBuffId' = 154445 - AUTONOMY_MOD_BABY_SHOWER_BARTENDER: 'CommonBuffId' = 309657 - AUTONOMY_MOD_BAKE_ONE_CAKE: 'CommonBuffId' = 31036 - AUTONOMY_MOD_BARTENDER: 'CommonBuffId' = 128325 - AUTONOMY_MOD_BEAR: 'CommonBuffId' = 104743 - AUTONOMY_MOD_BEHAVIOR_BOMB_ENERGY: 'CommonBuffId' = 224372 - AUTONOMY_MOD_BEHAVIOR_BOMB_PARTY: 'CommonBuffId' = 218932 - AUTONOMY_MOD_BEHAVIOR_BOMB_STUDY: 'CommonBuffId' = 219266 - AUTONOMY_MOD_BEHAVIOR_BOMB_TIDY: 'CommonBuffId' = 219250 - AUTONOMY_MOD_BIRTHDAY_BLOW_OUT_CANDLES: 'CommonBuffId' = 117435 - AUTONOMY_MOD_BIRTHDAY_GUEST_CELEBRATE: 'CommonBuffId' = 32209 - AUTONOMY_MOD_BREAK_THINGS: 'CommonBuffId' = 12617 - AUTONOMY_MOD_BROWSE_BOOKS: 'CommonBuffId' = 96922 - AUTONOMY_MOD_CAFE_BARISTA_ACTIVE: 'CommonBuffId' = 124621 - AUTONOMY_MOD_CAFE_BUSINESS_PARTNER: 'CommonBuffId' = 125186 - AUTONOMY_MOD_CAFE_CUSTOMER: 'CommonBuffId' = 122234 - AUTONOMY_MOD_CAFE_FRIENDS: 'CommonBuffId' = 125048 - AUTONOMY_MOD_CAFE_MEDIA_USER: 'CommonBuffId' = 122744 - AUTONOMY_MOD_CAFE_ORDER_DRINK: 'CommonBuffId' = 122674 - AUTONOMY_MOD_CAFE_ORDER_DRINK_TO_GO: 'CommonBuffId' = 124308 - AUTONOMY_MOD_CAFE_ORDER_FOOD: 'CommonBuffId' = 130063 - AUTONOMY_MOD_CAREER_ACTIVIST_ATTRACT_TO_PROTEST_HIDDEN: 'CommonBuffId' = 149923 - AUTONOMY_MOD_CAREER_ACTIVIST_ATTRACT_TO_PROTEST_PLAYER_HIDDEN: 'CommonBuffId' = 155277 - AUTONOMY_MOD_CARVE_PUMPKINS: 'CommonBuffId' = 127118 - AUTONOMY_MOD_CELEBRITY_AT_VENUE: 'CommonBuffId' = 196537 - AUTONOMY_MOD_CELEBRITY_HANG_OUT_BAR: 'CommonBuffId' = 191731 - AUTONOMY_MOD_CELEBRITY_HANG_OUT_GYM: 'CommonBuffId' = 191732 - AUTONOMY_MOD_CELEBRITY_HANG_OUT_LIBRARY: 'CommonBuffId' = 191729 - AUTONOMY_MOD_CELEBRITY_HANG_OUT_MUSEUM: 'CommonBuffId' = 191727 - AUTONOMY_MOD_CELEBRITY_HANG_OUT_PARK: 'CommonBuffId' = 191730 - AUTONOMY_MOD_CELEBRITY_HANG_OUT_POOL: 'CommonBuffId' = 191728 - AUTONOMY_MOD_CELEBRITY_NEARBY_SIMS: 'CommonBuffId' = 196650 - AUTONOMY_MOD_CELEBRITY_NEARBY_SIMS_ARRIVE_AT_VENUE: 'CommonBuffId' = 262049 - AUTONOMY_MOD_CHALET_GARDENS_WANDER_MAZE: 'CommonBuffId' = 126240 - AUTONOMY_MOD_CHALET_GHOST_GARDEN: 'CommonBuffId' = 127075 - AUTONOMY_MOD_CHALET_GHOST_PAINTER: 'CommonBuffId' = 126030 - AUTONOMY_MOD_CHALET_GHOST_THINGS: 'CommonBuffId' = 127062 - AUTONOMY_MOD_CITY_LIFE_BASKET_BALLER: 'CommonBuffId' = 149964 - AUTONOMY_MOD_CITY_LIFE_BUSKER_WATCH_BROADCAST: 'CommonBuffId' = 151112 - AUTONOMY_MOD_CITY_LIFE_CITY_REPAIR: 'CommonBuffId' = 144299 - AUTONOMY_MOD_CITY_LIFE_LIVES_ON_STREET_ADULT: 'CommonBuffId' = 151046 - AUTONOMY_MOD_CITY_LIFE_LIVES_ON_STREET_CHILD: 'CommonBuffId' = 153512 - AUTONOMY_MOD_CITY_LIFE_LIVING_STATUE_BUSKER: 'CommonBuffId' = 134322 - AUTONOMY_MOD_CITY_LIFE_MURAL_PAINTER: 'CommonBuffId' = 149974 - AUTONOMY_MOD_CITY_LIFE_MYSHUNO_MEADOWS_TOURIST_BARFLY: 'CommonBuffId' = 152983 - AUTONOMY_MOD_CITY_LIFE_PHONE_CHATTER_COOLDOWN: 'CommonBuffId' = 155329 - AUTONOMY_MOD_CITY_LIFE_PROTESTERS: 'CommonBuffId' = 153087 - AUTONOMY_MOD_CITY_LIFE_READ_GUIDE_COOLDOWN: 'CommonBuffId' = 155331 - AUTONOMY_MOD_CITY_LIFE_TOURIST: 'CommonBuffId' = 134323 - AUTONOMY_MOD_CITY_LIFE_VIEW_COOLDOWN: 'CommonBuffId' = 155708 - AUTONOMY_MOD_CITY_LIFE_WEIRDO: 'CommonBuffId' = 134321 - AUTONOMY_MOD_CITY_LIFE_WEIRDO_BATHROBE_ELDER: 'CommonBuffId' = 145016 - AUTONOMY_MOD_CITY_LIFE_WEIRDO_RACCOON: 'CommonBuffId' = 145018 - AUTONOMY_MOD_CITY_LIFE_WEIRDO_TALK_TO_SELF_COOLDOWN: 'CommonBuffId' = 155649 - AUTONOMY_MOD_CITY_LIFE_WEIRDO_TOWELS: 'CommonBuffId' = 145019 - AUTONOMY_MOD_CLEAN_BAR: 'CommonBuffId' = 27058 - AUTONOMY_MOD_CLEAN_GLASSES: 'CommonBuffId' = 27370 - AUTONOMY_MOD_CLEAN_PLATES: 'CommonBuffId' = 27371 - AUTONOMY_MOD_CLEAR_EASEL: 'CommonBuffId' = 145080 - AUTONOMY_MOD_CLEAR_MURAL: 'CommonBuffId' = 148096 - AUTONOMY_MOD_CLUB_DANCER: 'CommonBuffId' = 123144 - AUTONOMY_MOD_CLUB_DJ: 'CommonBuffId' = 122822 - AUTONOMY_MOD_CLUB_DJ_AUDIENCE: 'CommonBuffId' = 123011 - AUTONOMY_MOD_CLUB_GO_DANCING_PARTY_GOER: 'CommonBuffId' = 123413 - AUTONOMY_MOD_CLUB_GO_DANCING_PARTY_POOPER: 'CommonBuffId' = 126289 - AUTONOMY_MOD_COMPLIMENT_MORE: 'CommonBuffId' = 34849 - AUTONOMY_MOD_CONGRATULATE_MORE: 'CommonBuffId' = 34963 - AUTONOMY_MOD_CONSERVATIONIST: 'CommonBuffId' = 211667 - AUTONOMY_MOD_CRIME_SCENE_DETECTIVE_NPC: 'CommonBuffId' = 115759 - AUTONOMY_MOD_DANCE_FLOOR_GROUP_DANCE_NO_SOCIAL: 'CommonBuffId' = 129081 - AUTONOMY_MOD_DANCE_STEREO: 'CommonBuffId' = 26276 - AUTONOMY_MOD_DEBTOR_REPO: 'CommonBuffId' = 228339 - AUTONOMY_MOD_DEBTOR_REPO_BILLS: 'CommonBuffId' = 241175 - AUTONOMY_MOD_DJ_BOOTH_AUDIENCE_0_COOLDOWN: 'CommonBuffId' = 125705 - AUTONOMY_MOD_DJ_BOOTH_AUDIENCE_1_WATCH: 'CommonBuffId' = 124603 - AUTONOMY_MOD_DJ_BOOTH_AUDIENCE_2_DANCE: 'CommonBuffId' = 124602 - AUTONOMY_MOD_DJ_BOOTH_AUDIENCE_DANCE_DECAY_HIGH: 'CommonBuffId' = 128031 - AUTONOMY_MOD_DJ_BOOTH_AUDIENCE_DANCE_DECAY_LOW: 'CommonBuffId' = 128030 - AUTONOMY_MOD_DJ_BOOTH_AUDIENCE_POSITIVE_BUFF: 'CommonBuffId' = 128378 - AUTONOMY_MOD_DJ_BOOTH_AUDIENCE_WATCH_DECAY_HIGH: 'CommonBuffId' = 128033 - AUTONOMY_MOD_DJ_BOOTH_AUDIENCE_WATCH_DECAY_LOW: 'CommonBuffId' = 128029 - AUTONOMY_MOD_DJ_BOOTH_AUDIENCE_X_ANTI: 'CommonBuffId' = 125704 - AUTONOMY_MOD_DOCTOR_CAREER_AUTONOMOUS_COOLDOWN: 'CommonBuffId' = 116628 - AUTONOMY_MOD_DOCTOR_CAREER_PATIENT_ADMITTED_EXAM_BED: 'CommonBuffId' = 113884 - AUTONOMY_MOD_DOCTOR_CAREER_PATIENT_ADMITTED_EXAM_BED_RECLINE: 'CommonBuffId' = 115264 - AUTONOMY_MOD_DOCTOR_CAREER_PATIENT_ARRIVAL_WAIT_TO_CHECK_IN: 'CommonBuffId' = 113885 - AUTONOMY_MOD_DO_BULLETIN_BOARD_INTERACTIONS: 'CommonBuffId' = 145899 - AUTONOMY_MOD_DO_WOODWORKING: 'CommonBuffId' = 144775 - AUTONOMY_MOD_DUMPSTER_WOOHOO: 'CommonBuffId' = 231207 - AUTONOMY_MOD_EASEL_MENTOR: 'CommonBuffId' = 28374 - AUTONOMY_MOD_EASEL_PAINT: 'CommonBuffId' = 28373 - AUTONOMY_MOD_EAT_ONE_SLICE_OF_CAKE: 'CommonBuffId' = 34440 - AUTONOMY_MOD_EP14_WORLD_NPC_HORSE_TRAINER_ADVERTISE_EQUESTRIAN_CENTER_SITUATION: 'CommonBuffId' = 329804 - AUTONOMY_MOD_EP14_WORLD_NPC_MYSTERIOUS_RANCHER_SELL_NECTAR_SITUATION: 'CommonBuffId' = 327886 - AUTONOMY_MOD_EP16_NPC_VENUE_DATE: 'CommonBuffId' = 369786 - AUTONOMY_MOD_EP16_WORLD_SHELL_VISITORS_FLOWER_SHOP: 'CommonBuffId' = 376280 - AUTONOMY_MOD_EP16_WORLD_SHELL_VISITORS_MOTEL: 'CommonBuffId' = 376279 - AUTONOMY_MOD_ESPRESSO_WAIT_FOR_WORK: 'CommonBuffId' = 129328 - AUTONOMY_MOD_EUROPE_WALK_BYS_BRAWL: 'CommonBuffId' = 123436 - AUTONOMY_MOD_EXERCISE: 'CommonBuffId' = 27527 - AUTONOMY_MOD_EXTRA_HOMEWORK_PRANK: 'CommonBuffId' = 36133 - AUTONOMY_MOD_FAN_STAN_CAN_TARGET_CELEBRITIES: 'CommonBuffId' = 194436 - AUTONOMY_MOD_FITNESS_MENTOR: 'CommonBuffId' = 40333 - AUTONOMY_MOD_FOREST_GHOST: 'CommonBuffId' = 108335 - AUTONOMY_MOD_FOREST_GHOST_GLOOMY: 'CommonBuffId' = 108322 - AUTONOMY_MOD_FOREST_GHOST_GOOFY: 'CommonBuffId' = 108323 - AUTONOMY_MOD_FOREST_GHOST_MEAN: 'CommonBuffId' = 108324 - AUTONOMY_MOD_FOREST_RANGER: 'CommonBuffId' = 108777 - AUTONOMY_MOD_FOREST_RANGER_VACATION_ARRIVAL: 'CommonBuffId' = 109032 - AUTONOMY_MOD_FREEGAN_ACTIVE_CAREER: 'CommonBuffId' = 238020 - AUTONOMY_MOD_FRIENDLY_SOCIALS_MORE: 'CommonBuffId' = 136764 - AUTONOMY_MOD_FUN_INCREASE: 'CommonBuffId' = 33299 - AUTONOMY_MOD_GHOST_HAUNT: 'CommonBuffId' = 102777 - AUTONOMY_MOD_GRAB_COFFEE_TEA: 'CommonBuffId' = 26249 - AUTONOMY_MOD_GRAB_COOLER_DRINK: 'CommonBuffId' = 105831 - AUTONOMY_MOD_GRAB_DESSERT: 'CommonBuffId' = 26252 - AUTONOMY_MOD_GRAB_DRINK: 'CommonBuffId' = 26247 - AUTONOMY_MOD_GRAB_FOOD: 'CommonBuffId' = 26286 - AUTONOMY_MOD_GRILL_MEALS: 'CommonBuffId' = 105828 - AUTONOMY_MOD_GYM_RELAXER: 'CommonBuffId' = 120594 - AUTONOMY_MOD_HANG_OUT_BAR: 'CommonBuffId' = 225524 - AUTONOMY_MOD_HANG_OUT_GYM: 'CommonBuffId' = 225527 - AUTONOMY_MOD_HANG_OUT_LIBRARY: 'CommonBuffId' = 225530 - AUTONOMY_MOD_HANG_OUT_MUSEUM: 'CommonBuffId' = 225532 - AUTONOMY_MOD_HANG_OUT_PARK: 'CommonBuffId' = 225534 - AUTONOMY_MOD_HANG_OUT_POOL: 'CommonBuffId' = 225535 - AUTONOMY_MOD_HIGH_SCHOOL_FILL_FOUNTAIN_PUNCH: 'CommonBuffId' = 287395 - AUTONOMY_MOD_HIGH_SCHOOL_SERVE_FOOD: 'CommonBuffId' = 290312 - AUTONOMY_MOD_HIGH_SCHOOL_TEAM_VICTORY_DANCE_CHAIN: 'CommonBuffId' = 279073 - AUTONOMY_MOD_IN_ROMANTIC_STC: 'CommonBuffId' = 101235 - AUTONOMY_MOD_ISLAND_CANOE_WALK_BY: 'CommonBuffId' = 214038 - AUTONOMY_MOD_IS_HERMIT: 'CommonBuffId' = 104054 - AUTONOMY_MOD_KEG_PARTY_FOOD: 'CommonBuffId' = 222496 - AUTONOMY_MOD_LAMPOON_HOST: 'CommonBuffId' = 202599 - AUTONOMY_MOD_LAMPOON_PARTY_GUEST_OF_HONOR: 'CommonBuffId' = 200817 - AUTONOMY_MOD_LANDLORD_FIX_THINGS: 'CommonBuffId' = 135330 - AUTONOMY_MOD_LEAVE: 'CommonBuffId' = 156116 - AUTONOMY_MOD_LESS_FUN: 'CommonBuffId' = 96800 - AUTONOMY_MOD_LISTEN_TO_MUSIC: 'CommonBuffId' = 34445 - AUTONOMY_MOD_LISTEN_TO_SPOOKY: 'CommonBuffId' = 126270 - AUTONOMY_MOD_LOCKED_MOTIVES: 'CommonBuffId' = 228865 - AUTONOMY_MOD_LOUNGE_EVENT_ACCEPT_AWARD: 'CommonBuffId' = 192739 - AUTONOMY_MOD_LOUNGE_EVENT_AWARD_ATTENDEE_WATCH: 'CommonBuffId' = 200984 - AUTONOMY_MOD_LOUNGE_EVENT_AWARD_DRINKS: 'CommonBuffId' = 193066 - AUTONOMY_MOD_LOUNGE_EVENT_AWARD_HOST: 'CommonBuffId' = 192696 - AUTONOMY_MOD_LOUNGE_EVENT_NO_MORE_AWARD: 'CommonBuffId' = 192746 - AUTONOMY_MOD_LOUNGE_EVENT_OPEN_MIC: 'CommonBuffId' = 192697 - AUTONOMY_MOD_LOUNGE_EVENT_OPEN_MIC_PLAYER: 'CommonBuffId' = 197905 - AUTONOMY_MOD_LOUNGE_EVENT_OPEN_MIC_PLAYER_EVENT: 'CommonBuffId' = 197909 - AUTONOMY_MOD_LOUNGE_EVENT_OPEN_MIC_TURN: 'CommonBuffId' = 193096 - AUTONOMY_MOD_LOUNGE_EVENT_OPEN_MIC_WATCH: 'CommonBuffId' = 201425 - AUTONOMY_MOD_LOWER_FAT_GAIN: 'CommonBuffId' = 137029 - AUTONOMY_MOD_MAGIC_DUELIST_CHALLENGE: 'CommonBuffId' = 218445 - AUTONOMY_MOD_MAGIC_DUELIST_DUEL: 'CommonBuffId' = 216813 - AUTONOMY_MOD_MAGIC_DUELIST_GO_TO_DUEL: 'CommonBuffId' = 216882 - AUTONOMY_MOD_MAKE_BIRTHDAY_CAKE: 'CommonBuffId' = 32210 - AUTONOMY_MOD_MAKE_BLACK_AND_WHITE_PARTY_DRINKS: 'CommonBuffId' = 37400 - AUTONOMY_MOD_MAKE_BLACK_AND_WHITE_PARTY_FOOD: 'CommonBuffId' = 37402 - AUTONOMY_MOD_MAKE_COFFEE_TEA: 'CommonBuffId' = 26289 - AUTONOMY_MOD_MAKE_COSTUME_PARTY_DRINKS: 'CommonBuffId' = 37399 - AUTONOMY_MOD_MAKE_COSTUME_PARTY_FOOD: 'CommonBuffId' = 37401 - AUTONOMY_MOD_MAKE_DESSERT: 'CommonBuffId' = 26287 - AUTONOMY_MOD_MAKE_DRINK: 'CommonBuffId' = 26278 - AUTONOMY_MOD_MAKE_GROUP_MEAL: 'CommonBuffId' = 26280 - AUTONOMY_MOD_MAKE_GROUP_MEAL_VEGETARIAN: 'CommonBuffId' = 152515 - AUTONOMY_MOD_MAKE_ONE_DESSERT: 'CommonBuffId' = 34116 - AUTONOMY_MOD_MAKE_ONE_GROUP_MEAL: 'CommonBuffId' = 34125 - AUTONOMY_MOD_MAKE_SPOOKY_FOOD: 'CommonBuffId' = 126094 - AUTONOMY_MOD_MARKET_STALLS_CUSTOMER: 'CommonBuffId' = 181131 - AUTONOMY_MOD_MARKET_STALLS_STOP_SOCIAL: 'CommonBuffId' = 143393 - AUTONOMY_MOD_MARKET_STALLS_TEND_STALL: 'CommonBuffId' = 132895 - AUTONOMY_MOD_MARKET_STALL_BROWSE: 'CommonBuffId' = 132958 - AUTONOMY_MOD_MARKET_STALL_HIRED_NPC_OPEN: 'CommonBuffId' = 151767 - AUTONOMY_MOD_MARKET_STALL_MAGIC_ADD_SPECTRAL_LOOK: 'CommonBuffId' = 217028 - AUTONOMY_MOD_MARKET_STALL_VENDOR_NPC: 'CommonBuffId' = 136193 - AUTONOMY_MOD_MARKET_STALL_VENDOR_NPC_COFFEE_CART: 'CommonBuffId' = 226097 - AUTONOMY_MOD_MEAN_SOCIALS_MORE: 'CommonBuffId' = 137512 - AUTONOMY_MOD_MICROPHONE_PERFORM_STAND_UP: 'CommonBuffId' = 32464 - AUTONOMY_MOD_MIRROR: 'CommonBuffId' = 128308 - AUTONOMY_MOD_MOLD_CLAY_BOB: 'CommonBuffId' = 148099 - AUTONOMY_MOD_MOVE_IN: 'CommonBuffId' = 310404 - AUTONOMY_MOD_MURAL_PAINT: 'CommonBuffId' = 146653 - AUTONOMY_MOD_NIGHTCLUB_DANCER: 'CommonBuffId' = 123546 - AUTONOMY_MOD_NO_AUTONOMOUS_CELL_PHONE: 'CommonBuffId' = 276966 - AUTONOMY_MOD_NO_CLEANING_DESKS: 'CommonBuffId' = 304086 - AUTONOMY_MOD_NO_CLEAN_FLOOR_BASIC: 'CommonBuffId' = 172992 - AUTONOMY_MOD_NO_CLEAN_FLOOR_EXTENSIVE: 'CommonBuffId' = 172998 - AUTONOMY_MOD_NO_SWIMMING: 'CommonBuffId' = 215379 - AUTONOMY_MOD_NO_TOILET_PRANK: 'CommonBuffId' = 304291 - AUTONOMY_MOD_OCEAN_ACTIVITY_COOLDOWN: 'CommonBuffId' = 215134 - AUTONOMY_MOD_OPEN_PRESENTS: 'CommonBuffId' = 190997 - AUTONOMY_MOD_OPEN_STREET_WORKOUT: 'CommonBuffId' = 40384 - AUTONOMY_MOD_OPEN_STREET_WORKOUT_DONE: 'CommonBuffId' = 40406 - AUTONOMY_MOD_ORDER_DRINK: 'CommonBuffId' = 27030 - AUTONOMY_MOD_ORDER_DRINK_SMALL: 'CommonBuffId' = 115739 - AUTONOMY_MOD_ORDER_FAVORITE_DRINK: 'CommonBuffId' = 123905 - AUTONOMY_MOD_PAIRED_DANCING_STEREO: 'CommonBuffId' = 303076 - AUTONOMY_MOD_PATIENT_AWAY_EVENT_COLLAPSED: 'CommonBuffId' = 114329 - AUTONOMY_MOD_PATIENT_COLLAPSE: 'CommonBuffId' = 113742 - AUTONOMY_MOD_PATIENT_PREGNANT_WAITING: 'CommonBuffId' = 114357 - AUTONOMY_MOD_PATIENT_PREGNANT_WALK_IN: 'CommonBuffId' = 114318 - AUTONOMY_MOD_PATIENT_WALK_INSIDE: 'CommonBuffId' = 113509 - AUTONOMY_MOD_PET_ADOPTION_ARRIVAL: 'CommonBuffId' = 170282 - AUTONOMY_MOD_PET_ADOPTION_OFFICER_DESTROY_CRATE: 'CommonBuffId' = 169596 - AUTONOMY_MOD_PET_ADOPTION_PETS_DESPAWN: 'CommonBuffId' = 169557 - AUTONOMY_MOD_PET_WALK: 'CommonBuffId' = 168030 - AUTONOMY_MOD_PET_WORLD_CAT_FISHER: 'CommonBuffId' = 164413 - AUTONOMY_MOD_PET_WORLD_CAT_GHOST: 'CommonBuffId' = 164414 - AUTONOMY_MOD_PET_WORLD_CAT_IN_HEAT: 'CommonBuffId' = 164393 - AUTONOMY_MOD_PET_WORLD_CAT_WANDERER: 'CommonBuffId' = 164412 - AUTONOMY_MOD_PET_WORLD_DOG_DOG_WALKER: 'CommonBuffId' = 168314 - AUTONOMY_MOD_PET_WORLD_DOG_GHOST: 'CommonBuffId' = 164415 - AUTONOMY_MOD_PET_WORLD_DOG_IN_HEAT: 'CommonBuffId' = 164411 - AUTONOMY_MOD_PET_WORLD_DOG_WANDERER: 'CommonBuffId' = 164392 - AUTONOMY_MOD_PET_WORLD_SIM_DOG_WALKER: 'CommonBuffId' = 168182 - AUTONOMY_MOD_PLAY_CHESS: 'CommonBuffId' = 27472 - AUTONOMY_MOD_PLAY_CHILDREN_INDOOR_OBJECTS: 'CommonBuffId' = 27511 - AUTONOMY_MOD_PLAY_CHILDREN_OUTDOOR_OBJECTS: 'CommonBuffId' = 27509 - AUTONOMY_MOD_PLAY_GAMES: 'CommonBuffId' = 34450 - AUTONOMY_MOD_PLAY_GAMING_RIG: 'CommonBuffId' = 27528 - AUTONOMY_MOD_PLAY_GUITAR: 'CommonBuffId' = 123630 - AUTONOMY_MOD_PLAY_MUSICAL_INSTRUMENTS: 'CommonBuffId' = 32463 - AUTONOMY_MOD_PLAY_ORGAN: 'CommonBuffId' = 155977 - AUTONOMY_MOD_PLAY_PIANO: 'CommonBuffId' = 303754 - AUTONOMY_MOD_PLAY_PIANO_BW_PARTY: 'CommonBuffId' = 37259 - AUTONOMY_MOD_PLAY_VIOLIN: 'CommonBuffId' = 123677 - AUTONOMY_MOD_POSTURE_BE_CARRIED: 'CommonBuffId' = 313136 - AUTONOMY_MOD_POSTURE_BE_CARRIED_BACK: 'CommonBuffId' = 313137 - AUTONOMY_MOD_POSTURE_CRIB: 'CommonBuffId' = 280281 - AUTONOMY_MOD_POSTURE_HIGH_CHAIR: 'CommonBuffId' = 280280 - AUTONOMY_MOD_POSTURE_LAY_ON_BACK: 'CommonBuffId' = 313135 - AUTONOMY_MOD_POSTURE_PLAY_MAT: 'CommonBuffId' = 280282 - AUTONOMY_MOD_PRACTICE_SPELLCASTING_COOLDOWN: 'CommonBuffId' = 220137 - AUTONOMY_MOD_PUT_AWAY_BOOKS: 'CommonBuffId' = 40090 - AUTONOMY_MOD_QUICK_SOCIAL_LESS: 'CommonBuffId' = 300711 - AUTONOMY_MOD_RANCH_WORLD_HORSE_AND_RIDER_HORSE: 'CommonBuffId' = 328816 - AUTONOMY_MOD_RANCH_WORLD_HORSE_AND_RIDER_SIM: 'CommonBuffId' = 328755 - AUTONOMY_MOD_RANGER_STATION: 'CommonBuffId' = 106122 - AUTONOMY_MOD_READ_BOOKS: 'CommonBuffId' = 27575 - AUTONOMY_MOD_RECREATION_TABLE_CLEANUP: 'CommonBuffId' = 317529 - AUTONOMY_MOD_RECREATION_TABLE_PLAY_SIMBLES: 'CommonBuffId' = 317528 - AUTONOMY_MOD_REPO_IDLE: 'CommonBuffId' = 229923 - AUTONOMY_MOD_RETAIL_BROWSE: 'CommonBuffId' = 109453 - AUTONOMY_MOD_RETAIL_BUY: 'CommonBuffId' = 109789 - AUTONOMY_MOD_RETAIL_EMPLOYEE_CLEAN: 'CommonBuffId' = 109776 - AUTONOMY_MOD_RETAIL_EMPLOYEE_CLOCK_IN: 'CommonBuffId' = 109787 - AUTONOMY_MOD_RETAIL_EMPLOYEE_ONLY_SCORE_STATIC_COMMODITIES: 'CommonBuffId' = 118378 - AUTONOMY_MOD_RETAIL_EMPLOYEE_RESTOCK: 'CommonBuffId' = 109779 - AUTONOMY_MOD_RETAIL_EMPLOYEE_RING_UP_CUSTOMERS: 'CommonBuffId' = 114894 - AUTONOMY_MOD_RETAIL_EMPLOYEE_SLACK_OFF: 'CommonBuffId' = 112297 - AUTONOMY_MOD_RETAIL_EMPLOYEE_SOCIALIZE: 'CommonBuffId' = 109780 - AUTONOMY_MOD_RETAIL_EMPLOYEE_SOCIALIZE_BACKUP: 'CommonBuffId' = 116088 - AUTONOMY_MOD_RETAIL_EMPLOYEE_STAND_NEAR_REGISTER: 'CommonBuffId' = 118376 - AUTONOMY_MOD_RETAIL_LOITER: 'CommonBuffId' = 116064 - AUTONOMY_MOD_ROMANCE_SOCIALS_MORE: 'CommonBuffId' = 136717 - AUTONOMY_MOD_SCARECROW: 'CommonBuffId' = 190059 - AUTONOMY_MOD_SCARECROW_ALWAYS_CONSIDER_SCARECROW_OBJECT: 'CommonBuffId' = 191325 - AUTONOMY_MOD_SCARE_SPOOKY: 'CommonBuffId' = 128311 - AUTONOMY_MOD_SCRAP_DRAWING: 'CommonBuffId' = 144974 - AUTONOMY_MOD_SCRAP_PAINTING: 'CommonBuffId' = 208152 - AUTONOMY_MOD_SCRAP_WOODWORK: 'CommonBuffId' = 145090 - AUTONOMY_MOD_SEASONAL_LEAVES: 'CommonBuffId' = 181071 - AUTONOMY_MOD_SEASONAL_SKATER: 'CommonBuffId' = 181070 - AUTONOMY_MOD_SEASONAL_SNOW: 'CommonBuffId' = 181491 - AUTONOMY_MOD_SECRET_LAB_VENUE: 'CommonBuffId' = 203426 - AUTONOMY_MOD_SHOWER: 'CommonBuffId' = 120583 - AUTONOMY_MOD_SIT: 'CommonBuffId' = 76180 - AUTONOMY_MOD_SKATING_RINK_ROUTINE_WATCH: 'CommonBuffId' = 180438 - AUTONOMY_MOD_SOCIALIZE_AS_BACKUP: 'CommonBuffId' = 96801 - AUTONOMY_MOD_SOCIALIZE_GREETINGS: 'CommonBuffId' = 115572 - AUTONOMY_MOD_SOCIALIZE_NOW: 'CommonBuffId' = 180880 - AUTONOMY_MOD_SOCIAL_LESS: 'CommonBuffId' = 123148 - AUTONOMY_MOD_SOCIAL_MORE: 'CommonBuffId' = 33931 - AUTONOMY_MOD_SOCIAL_MORE_ANNOYING: 'CommonBuffId' = 122338 - AUTONOMY_MOD_SOCIAL_MORE_DATE: 'CommonBuffId' = 118567 - AUTONOMY_MOD_SOCIAL_NONE: 'CommonBuffId' = 240036 - AUTONOMY_MOD_SPA_DO_STUFF: 'CommonBuffId' = 119014 - AUTONOMY_MOD_SPA_GUEST_ALL: 'CommonBuffId' = 273418 - AUTONOMY_MOD_SPA_GUEST_ARRIVAL: 'CommonBuffId' = 119688 - AUTONOMY_MOD_SPA_GUEST_DELAY_CHANGE_INTO_ROBE: 'CommonBuffId' = 273424 - AUTONOMY_MOD_SPA_GUEST_DELAY_CHANGE_INTO_ROBE_TIMED: 'CommonBuffId' = 273405 - AUTONOMY_MOD_SPA_GUEST_LEAVE_VENUE: 'CommonBuffId' = 119689 - AUTONOMY_MOD_SPA_MASSAGE_THERAPIST_ACTIVE: 'CommonBuffId' = 119015 - AUTONOMY_MOD_SPA_MASSAGE_THERAPIST_BORED: 'CommonBuffId' = 119019 - AUTONOMY_MOD_SPA_REFLEXOLOGIST_ACTIVE: 'CommonBuffId' = 119016 - AUTONOMY_MOD_SPA_REFLEXOLOGIST_BORED: 'CommonBuffId' = 119017 - AUTONOMY_MOD_SPA_YOGA_INSTRUCTOR_ARRIVAL: 'CommonBuffId' = 120241 - AUTONOMY_MOD_SPA_YOGA_INSTRUCTOR_BORED: 'CommonBuffId' = 119018 - AUTONOMY_MOD_SPLASH_PAD: 'CommonBuffId' = 303708 - AUTONOMY_MOD_STRANGER_VILLE_CONSPIRACIST: 'CommonBuffId' = 203333 - AUTONOMY_MOD_STRANGER_VILLE_OGA: 'CommonBuffId' = 203332 - AUTONOMY_MOD_STUDENT_COMMONS_EXAM_CRAM_PLAYER: 'CommonBuffId' = 222197 - AUTONOMY_MOD_STUDENT_COMMONS_GET_REFRESHMENTS: 'CommonBuffId' = 230207 - AUTONOMY_MOD_STUDENT_COMMONS_SLACKING: 'CommonBuffId' = 222359 - AUTONOMY_MOD_STUDENT_COMMONS_SLEEP_MORE: 'CommonBuffId' = 230208 - AUTONOMY_MOD_STUDENT_COMMONS_SOCIAL: 'CommonBuffId' = 222358 - AUTONOMY_MOD_STUDENT_COMMONS_STUDYING: 'CommonBuffId' = 222185 - AUTONOMY_MOD_STUDY_HOMEWORK: 'CommonBuffId' = 27682 - AUTONOMY_MOD_SUMMIT_BUNNY_SLOPE: 'CommonBuffId' = 247314 - AUTONOMY_MOD_SUMMIT_CLIMBER: 'CommonBuffId' = 247358 - AUTONOMY_MOD_SUMMIT_SLOPE: 'CommonBuffId' = 247313 - AUTONOMY_MOD_SUMMIT_SOLO_HIKER: 'CommonBuffId' = 247360 - AUTONOMY_MOD_SUMMIT_SOLO_SLEDDER: 'CommonBuffId' = 247359 - AUTONOMY_MOD_SUMMIT_TOURIST: 'CommonBuffId' = 253863 - AUTONOMY_MOD_SUMMONED_GHOST: 'CommonBuffId' = 108712 - AUTONOMY_MOD_SUMMON_GHOST_FAIL: 'CommonBuffId' = 215673 - AUTONOMY_MOD_SUPPRESS_PRE_ROLL_AUTONOMY: 'CommonBuffId' = 115876 - AUTONOMY_MOD_SWIMMER: 'CommonBuffId' = 124810 - AUTONOMY_MOD_TEND_BAR: 'CommonBuffId' = 27056 - AUTONOMY_MOD_TEND_BAR_CASUAL: 'CommonBuffId' = 203483 - AUTONOMY_MOD_THANK_HOST_FOR_INVITE: 'CommonBuffId' = 26284 - AUTONOMY_MOD_THRIFT_STORE_BROWSING: 'CommonBuffId' = 280735 - AUTONOMY_MOD_THRIFT_STORE_BUBBLE_TEA_DRINKING: 'CommonBuffId' = 280819 - AUTONOMY_MOD_THRIFT_STORE_COMEDY_PERFORMING: 'CommonBuffId' = 280900 - AUTONOMY_MOD_THRIFT_STORE_COMEDY_WAITING: 'CommonBuffId' = 280899 - AUTONOMY_MOD_THRIFT_STORE_FASHION_SHOW_OFF: 'CommonBuffId' = 280998 - AUTONOMY_MOD_THRIFT_STORE_ORDER_FOOD: 'CommonBuffId' = 294686 - AUTONOMY_MOD_THRIFT_STORE_PLAYER: 'CommonBuffId' = 280787 - AUTONOMY_MOD_THRIFT_STORE_POETRY_PERFORMING: 'CommonBuffId' = 280901 - AUTONOMY_MOD_THRIFT_STORE_POETRY_WAITING: 'CommonBuffId' = 280902 - AUTONOMY_MOD_TIDY: 'CommonBuffId' = 304708 - AUTONOMY_MOD_TOP_CAKE: 'CommonBuffId' = 31037 - AUTONOMY_MOD_TOWN_VISITOR: 'CommonBuffId' = 210422 - AUTONOMY_MOD_TRAIT_MELT_MASTER_EAT_GRILLED_CHEESE: 'CommonBuffId' = 132358 - AUTONOMY_MOD_TRAIT_VEGETARIAN_EAT_VEGETARIAN_FOOD: 'CommonBuffId' = 133129 - AUTONOMY_MOD_TRASH_CHUTE_THROW_AWAY: 'CommonBuffId' = 151163 - AUTONOMY_MOD_TRIGGER_HOUSE_CALL: 'CommonBuffId' = 114195 - AUTONOMY_MOD_TRIGGER_OUTBREAK: 'CommonBuffId' = 114270 - AUTONOMY_MOD_TUTOR: 'CommonBuffId' = 27653 - AUTONOMY_MOD_UNICORN_HORN: 'CommonBuffId' = 333940 - AUTONOMY_MOD_UNICORN_HORN_C: 'CommonBuffId' = 334258 - AUTONOMY_MOD_UNIVERSITY_WORLD_CONSTRAIN_TO_ATTRACTOR: 'CommonBuffId' = 222941 - AUTONOMY_MOD_UNIVERSITY_WORLD_STUDENT: 'CommonBuffId' = 222940 - AUTONOMY_MOD_USE_BONFIRE: 'CommonBuffId' = 126414 - AUTONOMY_MOD_USE_CAMPFIRE: 'CommonBuffId' = 105897 - AUTONOMY_MOD_USE_COMPUTER: 'CommonBuffId' = 27766 - AUTONOMY_MOD_USE_OUTDOOR_OBJECTS_BUSH: 'CommonBuffId' = 126337 - AUTONOMY_MOD_USE_OUTDOOR_OBJECTS_FISHING_LOCATION: 'CommonBuffId' = 76557 - AUTONOMY_MOD_USE_OUTDOOR_OBJECTS_GARDEN: 'CommonBuffId' = 38934 - AUTONOMY_MOD_USE_OUTDOOR_OBJECTS_HERBALIST: 'CommonBuffId' = 101858 - AUTONOMY_MOD_USE_OUTDOOR_OBJECTS_RESTROOM: 'CommonBuffId' = 40784 - AUTONOMY_MOD_USE_OUTDOOR_OBJECTS_RESTROOM_SHOWER: 'CommonBuffId' = 107843 - AUTONOMY_MOD_USE_PORTABLE_COMPUTER: 'CommonBuffId' = 225754 - AUTONOMY_MOD_USE_TABLET: 'CommonBuffId' = 27578 - AUTONOMY_MOD_VENUE_BEACH_BEACH_COMBER: 'CommonBuffId' = 207806 - AUTONOMY_MOD_VENUE_BEACH_LIFE_GUARD: 'CommonBuffId' = 207807 - AUTONOMY_MOD_VENUE_BEACH_MERFOLK: 'CommonBuffId' = 207808 - AUTONOMY_MOD_VENUE_BEACH_MERFOLK_UNDISCOVERED: 'CommonBuffId' = 209204 - AUTONOMY_MOD_VENUE_BEACH_SAND_ARTIST: 'CommonBuffId' = 207810 - AUTONOMY_MOD_VENUE_BEACH_SWIMMER: 'CommonBuffId' = 205388 - AUTONOMY_MOD_VENUE_BEACH_TANNER: 'CommonBuffId' = 207811 - AUTONOMY_MOD_VENUE_BEACH_WATER_ENTHUSIAST: 'CommonBuffId' = 207815 - AUTONOMY_MOD_VIEW_PAINTING: 'CommonBuffId' = 28372 - AUTONOMY_MOD_VIP_ROPE_ATTEMPT_TO_ENTER: 'CommonBuffId' = 199880 - AUTONOMY_MOD_VIP_ROPE_BOUNCER_ARRIVAL: 'CommonBuffId' = 191978 - AUTONOMY_MOD_VIP_ROPE_BOUNCER_IDLE: 'CommonBuffId' = 195307 - AUTONOMY_MOD_WAITING_FOR_CLASS: 'CommonBuffId' = 229426 - AUTONOMY_MOD_WATCH_CEREMONY: 'CommonBuffId' = 31019 - AUTONOMY_MOD_WATCH_KARAOKE: 'CommonBuffId' = 154186 - AUTONOMY_MOD_WATCH_STAND_UP: 'CommonBuffId' = 34443 - AUTONOMY_MOD_WATCH_TV: 'CommonBuffId' = 27033 - AUTONOMY_MOD_WATER_SCOOTER_WALK_BY: 'CommonBuffId' = 209526 - AUTONOMY_MOD_WELLNESS_ACTIVITY_PROMOTED: 'CommonBuffId' = 272558 - AUTONOMY_MOD_WELLNESS_ACTIVITY_PROMOTED_TIMED: 'CommonBuffId' = 272569 - AUTONOMY_MOD_WORKOUT: 'CommonBuffId' = 97595 - AUTO_SMOKE: 'CommonBuffId' = 97496 - AXOLOTL_BREED_COOLDOWN_HIDDEN: 'CommonBuffId' = 378235 - AXOLOTL_RELEASE_INSPIRED: 'CommonBuffId' = 380475 - A_GREAT_SCARE: 'CommonBuffId' = 103141 - A_GREAT_SCARE_GREAT_STORYTELLER: 'CommonBuffId' = 109738 - A_NEW_BEGINNING: 'CommonBuffId' = 100146 - A_SILLY_SCARE: 'CommonBuffId' = 108023 - A_SILLY_SCARE_GREAT_STORYTELLER: 'CommonBuffId' = 109740 - BABY_BIRTH_PARTNER: 'CommonBuffId' = 115502 - BABY_FEED_PREFERENCE_BODY: 'CommonBuffId' = 334605 - BABY_FEED_PREFERENCE_BOTTLE: 'CommonBuffId' = 334604 - BABY_SHOWER_ATTEND_SHOWER: 'CommonBuffId' = 305762 - BABY_SHOWER_BAD_BABY_NAME: 'CommonBuffId' = 305696 - BABY_SHOWER_GIFT_COOLDOWN: 'CommonBuffId' = 310458 - BABY_SHOWER_GOOD_BABY_NAME: 'CommonBuffId' = 305695 - BABY_SHOWER_TOO_MUCH_BABY: 'CommonBuffId' = 305763 - BABY_SHOWER_UNWANTED_ADVICE: 'CommonBuffId' = 305764 - BAD_MANNERS_VISITING: 'CommonBuffId' = 164675 - BAIT_CRYSTAL: 'CommonBuffId' = 98249 - BAIT_ELEMENT: 'CommonBuffId' = 98248 - BAIT_FRESH_FLOWER: 'CommonBuffId' = 76073 - BAIT_FRESH_FRUIT: 'CommonBuffId' = 76072 - BAIT_FROG: 'CommonBuffId' = 75548 - BAIT_GROUP_ORGANIC: 'CommonBuffId' = 75549 - BAIT_GROUP_TRASH: 'CommonBuffId' = 76076 - BAIT_MEDIUM_FISH: 'CommonBuffId' = 76071 - BAIT_METAL: 'CommonBuffId' = 98250 - BAIT_PLASMA_FRUIT: 'CommonBuffId' = 155037 - BAIT_ROTTEN_FRUIT: 'CommonBuffId' = 76075 - BAIT_SMALL_FISH: 'CommonBuffId' = 75556 - BATTLE_MONSTERS_HIDDEN_ATTACK_MISS: 'CommonBuffId' = 135448 - BATTLE_MONSTERS_HIDDEN_CHALLENGER: 'CommonBuffId' = 138030 - BATTLE_MONSTERS_HIDDEN_ELEMENTS_EARTH: 'CommonBuffId' = 135617 - BATTLE_MONSTERS_HIDDEN_ELEMENTS_FIRE: 'CommonBuffId' = 135614 - BATTLE_MONSTERS_HIDDEN_ELEMENTS_VOID: 'CommonBuffId' = 135616 - BATTLE_MONSTERS_HIDDEN_ELEMENTS_WATER: 'CommonBuffId' = 135615 - BATTLE_MONSTERS_HIDDEN_ELEMENTS_WIND: 'CommonBuffId' = 135618 - BATTLE_MONSTERS_HIDDEN_LEVEL_1: 'CommonBuffId' = 135605 - BATTLE_MONSTERS_HIDDEN_LEVEL_10: 'CommonBuffId' = 135604 - BATTLE_MONSTERS_HIDDEN_LEVEL_2: 'CommonBuffId' = 135606 - BATTLE_MONSTERS_HIDDEN_LEVEL_3: 'CommonBuffId' = 135607 - BATTLE_MONSTERS_HIDDEN_LEVEL_4: 'CommonBuffId' = 135608 - BATTLE_MONSTERS_HIDDEN_LEVEL_5: 'CommonBuffId' = 135609 - BATTLE_MONSTERS_HIDDEN_LEVEL_6: 'CommonBuffId' = 135610 - BATTLE_MONSTERS_HIDDEN_LEVEL_7: 'CommonBuffId' = 135611 - BATTLE_MONSTERS_HIDDEN_LEVEL_8: 'CommonBuffId' = 135612 - BATTLE_MONSTERS_HIDDEN_LEVEL_9: 'CommonBuffId' = 135613 - BATTLE_MONSTERS_HIDDEN_REACTIONS_CHEER: 'CommonBuffId' = 137733 - BATTLE_MONSTERS_HIDDEN_REACTIONS_VICTORY_CHEER: 'CommonBuffId' = 139217 - BATTLE_MONSTERS_HIDDEN_TRASH_CAN_COOLDOWN: 'CommonBuffId' = 134201 - BATUU_AGNON_FIRST_ORDER_AUTHORITY: 'CommonBuffId' = 238996 - BATUU_AGNON_IDENTIFIER: 'CommonBuffId' = 238987 - BATUU_ARREST_BUSTED: 'CommonBuffId' = 242891 - BATUU_ARREST_BUSTED_ANGRY: 'CommonBuffId' = 242997 - BATUU_ARREST_NOT_BUSTED: 'CommonBuffId' = 242892 - BATUU_ARREST_ROLE_DESPAWN_PRISONER: 'CommonBuffId' = 245251 - BATUU_ARREST_ROLE_ESCORT_ESCORTER: 'CommonBuffId' = 245248 - BATUU_ASPIRATIONS_BOUGHT_DROID_CHECK: 'CommonBuffId' = 245341 - BATUU_ASPIRATIONS_EXTOL_MIGHT_FAILURE: 'CommonBuffId' = 245470 - BATUU_ASPIRATIONS_EXTOL_MIGHT_OF_FIRST_ORDER: 'CommonBuffId' = 238933 - BATUU_ASPIRATIONS_HEROIC_PRESENCE_ACTOR: 'CommonBuffId' = 238938 - BATUU_ASPIRATIONS_HEROIC_PRESENCE_TARGET: 'CommonBuffId' = 238658 - BATUU_ASPIRATIONS_PREPARED_VOYAGER: 'CommonBuffId' = 238660 - BATUU_ASPIRATIONS_SLEIGHT_OF_HAND: 'CommonBuffId' = 238661 - BATUU_BATUUAN_MISSION_GIVER: 'CommonBuffId' = 242819 - BATUU_BATUUAN_MISSION_SCOUNDREL: 'CommonBuffId' = 244393 - BATUU_CHECK_ID_BYSTANDER_CANCEL_FOR_BRIBE: 'CommonBuffId' = 242478 - BATUU_CHECK_ID_BYSTANDER_CANCEL_FOR_CONVINCE: 'CommonBuffId' = 242479 - BATUU_CHECK_ID_CANCEL_FOR_BRIBE: 'CommonBuffId' = 242429 - BATUU_CHECK_ID_CANCEL_FOR_CONVINCE: 'CommonBuffId' = 242470 - BATUU_CHECK_ID_ORIGINAL_TARGET: 'CommonBuffId' = 242520 - BATUU_CHECK_ID_TARGET_COOLDOWN_HIDDEN: 'CommonBuffId' = 231390 - BATUU_CHECK_ID_TARGET_COOLDOWN_HIDDEN_NPC_ACTOR: 'CommonBuffId' = 250150 - BATUU_CHECK_POINT_DOOR_FIRST_ORDER: 'CommonBuffId' = 231456 - BATUU_CHECK_POINT_DOOR_RESISTANCE: 'CommonBuffId' = 231457 - BATUU_CONTROL_PANEL_ALARM_RAISED_FIRST_ORDER: 'CommonBuffId' = 249772 - BATUU_CONTROL_PANEL_ALARM_RAISED_RESISTANCE: 'CommonBuffId' = 249780 - BATUU_CONTROL_PANEL_ROOKIE_MISTAKE_FIRST_ORDER_SYSTEM: 'CommonBuffId' = 237376 - BATUU_CONTROL_PANEL_ROOKIE_MISTAKE_FIRST_ORDER_SYSTEM_ANGRY: 'CommonBuffId' = 237377 - BATUU_CONTROL_PANEL_ROOKIE_MISTAKE_RESISTANCE_SYSTEM_FIRST_ORDER: 'CommonBuffId' = 237381 - BATUU_CONTROL_PANEL_ROOKIE_MISTAKE_RESISTANCE_SYSTEM_FIRST_ORDER_ANGRY: 'CommonBuffId' = 237382 - BATUU_CONTROL_PANEL_ROOKIE_MISTAKE_RESISTANCE_SYSTEM_SCOUNDREL: 'CommonBuffId' = 237383 - BATUU_CONTROL_PANEL_ROOKIE_MISTAKE_RESISTANCE_SYSTEM_SCOUNDREL_ANGRY: 'CommonBuffId' = 237384 - BATUU_CONTROL_PANEL_UNDER_WATCH_FIRST_ORDER: 'CommonBuffId' = 231386 - BATUU_CONTROL_PANEL_UNDER_WATCH_RESISTANCE: 'CommonBuffId' = 231387 - BATUU_DROID_AURAL_SENSOR: 'CommonBuffId' = 245252 - BATUU_DROID_CANCEL_FOLLOW: 'CommonBuffId' = 237495 - BATUU_DROID_CANCEL_GET_ZAPPED: 'CommonBuffId' = 245114 - BATUU_DROID_DISCUSSED_SCHEMATICS: 'CommonBuffId' = 242906 - BATUU_DROID_DISTRACTED: 'CommonBuffId' = 246006 - BATUU_DROID_DISTRACTED_SWIPE_COOLDOWN: 'CommonBuffId' = 248822 - BATUU_DROID_DISTRACTED_SWIPE_FAIL: 'CommonBuffId' = 242348 - BATUU_DROID_DISTRACTED_SWIPE_SUCCESS: 'CommonBuffId' = 242347 - BATUU_DROID_SHOCK_DAZED: 'CommonBuffId' = 242971 - BATUU_FIRST_ORDER_MISSION_GIVER: 'CommonBuffId' = 233163 - BATUU_FIRST_ORDER_STORMTROOPER_HIGH_ALERT: 'CommonBuffId' = 231374 - BATUU_FIRST_ORDER_STORMTROOPER_HIGH_ALERT_RS6: 'CommonBuffId' = 244423 - BATUU_FIRST_ORDER_STORMTROOPER_HIGH_ALERT_TIMED: 'CommonBuffId' = 242911 - BATUU_HOLOCRON_JEDI: 'CommonBuffId' = 233179 - BATUU_HOLOCRON_SITH: 'CommonBuffId' = 233180 - BATUU_HONDO_GOOD_BUSINESS: 'CommonBuffId' = 238787 - BATUU_HONDO_IDENTIFIER: 'CommonBuffId' = 233796 - BATUU_HONDO_STEAL_CAN_ASK: 'CommonBuffId' = 233800 - BATUU_HONDO_STEAL_COOLDOWN: 'CommonBuffId' = 233798 - BATUU_INSPECTION_CLOSE_SHAVE: 'CommonBuffId' = 242890 - BATUU_INSPECTION_IN_FIGHT: 'CommonBuffId' = 250826 - BATUU_INSPECTION_ROLE_FIGHT_INSPECTOR: 'CommonBuffId' = 245311 - BATUU_INVITED_NPC: 'CommonBuffId' = 251642 - BATUU_KYLO_FEAR_THE_DARK_SIDE: 'CommonBuffId' = 238995 - BATUU_KYLO_FIRST_ORDER_MIGHT_NEGATIVE: 'CommonBuffId' = 238994 - BATUU_KYLO_FIRST_ORDER_MIGHT_POSITIVE: 'CommonBuffId' = 238993 - BATUU_KYLO_IDENTIFIER: 'CommonBuffId' = 238988 - BATUU_LIGHTSABER_REFINED_WEAPON: 'CommonBuffId' = 232333 - BATUU_LUCK_OF_BATUU: 'CommonBuffId' = 247412 - BATUU_MISSIONS_ASPIRATIONS_MISSION_COMPLETE: 'CommonBuffId' = 243193 - BATUU_MISSIONS_CONVINCE_TO_BET_VALUABLE_FAIL_SR9: 'CommonBuffId' = 246514 - BATUU_MISSIONS_DEFECTOR_WRONG_PERSON: 'CommonBuffId' = 243579 - BATUU_MISSIONS_DELIVERED_SPY_SUCCESS: 'CommonBuffId' = 242241 - BATUU_MISSIONS_EXIT_WAIT: 'CommonBuffId' = 242406 - BATUU_MISSIONS_FR13_INTIMIDATE_COOLDOWN: 'CommonBuffId' = 251739 - BATUU_MISSIONS_FR13_PATROL_END: 'CommonBuffId' = 245515 - BATUU_MISSIONS_FS1_RECENTLY_HEARD_PROPAGANDA: 'CommonBuffId' = 248364 - BATUU_MISSIONS_FS4_ASK_ABOUT_CRIMINAL_COOLDOWN: 'CommonBuffId' = 245754 - BATUU_MISSIONS_FS6_CHARM_COOLDOWN: 'CommonBuffId' = 245587 - BATUU_MISSIONS_FS6_INTIMIDATE_COOLDOWN: 'CommonBuffId' = 246641 - BATUU_MISSIONS_FS8_RECENTLY_EAVESDROPPED: 'CommonBuffId' = 249194 - BATUU_MISSIONS_FS8_RECENTLY_RECRUITED_OR_PAID: 'CommonBuffId' = 249193 - BATUU_MISSIONS_FS8_REY_STOP_AND_GO_MIND_ERASE: 'CommonBuffId' = 250516 - BATUU_MISSIONS_FS_7_FOUND_SPY: 'CommonBuffId' = 242013 - BATUU_MISSIONS_FS_7_IS_SPY: 'CommonBuffId' = 242003 - BATUU_MISSIONS_FS_7_SHARE_FAKE_INFO_ANTI_FO_SENTIMENTS: 'CommonBuffId' = 241716 - BATUU_MISSIONS_FS_7_SHARE_FAKE_INFO_HOLOTABLE_SECURITY_FLAW: 'CommonBuffId' = 241713 - BATUU_MISSIONS_FS_7_SHARE_FAKE_INFO_RUMOR: 'CommonBuffId' = 241712 - BATUU_MISSIONS_FS_7_SPY_DELIVERED_FALSE: 'CommonBuffId' = 248959 - BATUU_MISSIONS_FS_7_SPY_DELIVERED_TRUE: 'CommonBuffId' = 248958 - BATUU_MISSIONS_GO_TO_KYLO: 'CommonBuffId' = 241808 - BATUU_MISSIONS_HAS_INFO_ON_CRIMINAL_WHEREABOUTS: 'CommonBuffId' = 241273 - BATUU_MISSIONS_NR2_LIGHTSABER_CHALLENGE_COMPLETE: 'CommonBuffId' = 243948 - BATUU_MISSIONS_NR2_LIGHTSABER_NPC: 'CommonBuffId' = 243895 - BATUU_MISSIONS_PLAYED_SABACC_TOURNAMENT_1ST_OPPONENT_R8: 'CommonBuffId' = 244411 - BATUU_MISSIONS_PLAYED_SABACC_TOURNAMENT_2ND_OPPONENT_SR8: 'CommonBuffId' = 244412 - BATUU_MISSIONS_PLAYED_SABACC_TOURNAMENT_FINAL_OPPONENT_SR8: 'CommonBuffId' = 244413 - BATUU_MISSIONS_RECENTLY_TARGETED_FOR_MISSION_SOCIAL: 'CommonBuffId' = 244345 - BATUU_MISSIONS_RECRUIT_HEIST_FAIL: 'CommonBuffId' = 251796 - BATUU_MISSIONS_RESISTANCE_CONTACT: 'CommonBuffId' = 245246 - BATUU_MISSIONS_RESISTANCE_SAD: 'CommonBuffId' = 244480 - BATUU_MISSIONS_REY_ERASE_MIND: 'CommonBuffId' = 242128 - BATUU_MISSIONS_RICH_SCOUNDREL: 'CommonBuffId' = 245703 - BATUU_MISSIONS_RR15_CAN_ACCESS_DATA_WAITING: 'CommonBuffId' = 245980 - BATUU_MISSIONS_RS2_DATA_SPIKE_COOLDOWN: 'CommonBuffId' = 249564 - BATUU_MISSIONS_RS8_RESCUED_PRISONER: 'CommonBuffId' = 244752 - BATUU_MISSIONS_RS8_RESCUING_WITH_DROID: 'CommonBuffId' = 244699 - BATUU_MISSIONS_SCOUNDREL_CONTACT: 'CommonBuffId' = 245556 - BATUU_MISSIONS_SCOUNDREL_REPEATABLE_04_REVEAL_PASSCODE_COOLDOWN: 'CommonBuffId' = 244597 - BATUU_MISSIONS_SR3_CONTROL_PANEL_COOLDOWN_1: 'CommonBuffId' = 246216 - BATUU_MISSIONS_SR3_CONTROL_PANEL_COOLDOWN_2: 'CommonBuffId' = 246217 - BATUU_MISSIONS_SR3_CONTROL_PANEL_COOLDOWN_3: 'CommonBuffId' = 246218 - BATUU_MISSIONS_SR3_CONTROL_PANEL_COOLDOWN_4: 'CommonBuffId' = 246219 - BATUU_MISSIONS_SR3_CONTROL_PANEL_COOLDOWN_5: 'CommonBuffId' = 246220 - BATUU_MISSIONS_SR3_CONTROL_PANEL_COOLDOWN_6: 'CommonBuffId' = 246221 - BATUU_MISSIONS_SR3_CONTROL_PANEL_COOLDOWN_7: 'CommonBuffId' = 246222 - BATUU_MISSIONS_SR3_CONTROL_PANEL_COOLDOWN_8: 'CommonBuffId' = 246215 - BATUU_MISSIONS_SS10_CELEBRATED_SCOUNDREL: 'CommonBuffId' = 244159 - BATUU_MISSIONS_SS10_CELEBRATION_OVER: 'CommonBuffId' = 245851 - BATUU_MISSIONS_STARSHIP_BLAME_FAIL: 'CommonBuffId' = 244619 - BATUU_MISSIONS_STARSHIP_BLAME_SUCCESS: 'CommonBuffId' = 244618 - BATUU_MISSIONS_STARSHIP_DISPARAGE_FO_RR5: 'CommonBuffId' = 245052 - BATUU_MISSIONS_STARSHIP_INVESTIGATE_BLASTER: 'CommonBuffId' = 244629 - BATUU_MISSIONS_STARSHIP_SR9_ORDER_RECRUIT: 'CommonBuffId' = 244611 - BATUU_MISSIONS_STARSHIP_SS6_SCOUTED_MANUALLY: 'CommonBuffId' = 245622 - BATUU_MISSIONS_STARSHIP_TRY_FIX_FAIL: 'CommonBuffId' = 244615 - BATUU_MISSIONS_STARSHIP_TRY_FIX_SUCCESS: 'CommonBuffId' = 244614 - BATUU_MISSIONS_WEARING_FIRST_ORDER_UNIFORM: 'CommonBuffId' = 243461 - BATUU_MISSIONS_WEARING_RESISTANCE_DISGUISE: 'CommonBuffId' = 242103 - BATUU_MISSION_COMPLETE_FIRST_ORDER: 'CommonBuffId' = 244691 - BATUU_MISSION_COMPLETE_RESISTANCE: 'CommonBuffId' = 244693 - BATUU_MISSION_COMPLETE_SMUGGLER: 'CommonBuffId' = 244694 - BATUU_MISSION_SABACC_TOURNAMENT_1ST_OPPONENT: 'CommonBuffId' = 244448 - BATUU_MISSION_SABACC_TOURNAMENT_2ND_OPPONENT: 'CommonBuffId' = 244450 - BATUU_MISSION_SABACC_TOURNAMENT_FINAL_OPPONENT: 'CommonBuffId' = 244451 - BATUU_NPC_BRIBE_COOLDOWN: 'CommonBuffId' = 245620 - BATUU_NPC_CITIZEN_IDENTIFIER: 'CommonBuffId' = 241637 - BATUU_NPC_FIRST_ORDER_OFFICER_IDENTIFIER: 'CommonBuffId' = 241692 - BATUU_NPC_HONDO_OHNAKA: 'CommonBuffId' = 239650 - BATUU_NPC_LIGHTSABER_TRAIT: 'CommonBuffId' = 243755 - BATUU_NPC_LT_AGNON: 'CommonBuffId' = 239648 - BATUU_NPC_MOVE_TO_POSITION_COOLDOWN: 'CommonBuffId' = 240683 - BATUU_NPC_RESISTANCE_IDENTIFIER: 'CommonBuffId' = 245216 - BATUU_NPC_RESTRICTED_PATROL_COOLDOWN: 'CommonBuffId' = 246062 - BATUU_NPC_SCAN_COOLDOWN: 'CommonBuffId' = 240695 - BATUU_NPC_VENUE_OGAS_CANTINA_BARFLY: 'CommonBuffId' = 237867 - BATUU_NPC_VENUE_OGAS_CANTINA_BARTENDER: 'CommonBuffId' = 237866 - BATUU_NPC_VENUE_RESTRICTED_AREA_BEING_INVESTIGATED: 'CommonBuffId' = 243483 - BATUU_NPC_VENUE_RESTRICTED_AREA_FIRST_ORDER: 'CommonBuffId' = 240493 - BATUU_NPC_VENUE_RESTRICTED_AREA_RESISTANCE: 'CommonBuffId' = 240492 - BATUU_NPC_VENUE_RESTRICTED_AREA_SPOTTED: 'CommonBuffId' = 240666 - BATUU_NPC_VI_MORADI: 'CommonBuffId' = 239649 - BATUU_NPC_WALK_BY_CITIZEN: 'CommonBuffId' = 235807 - BATUU_NPC_WALK_BY_CITIZEN_RESISTANCE_SYMPATHIZER: 'CommonBuffId' = 243523 - BATUU_NPC_WALK_BY_CITIZEN_SCIENTIST: 'CommonBuffId' = 241556 - BATUU_NPC_WALK_BY_CITIZEN_SCIENTIST_DO_WORK: 'CommonBuffId' = 247415 - BATUU_NPC_WALK_BY_CITIZEN_SCIENTIST_JOINED_FO: 'CommonBuffId' = 241569 - BATUU_NPC_WALK_BY_CITIZEN_SUSPICIOUS: 'CommonBuffId' = 241612 - BATUU_NPC_WALK_BY_COOLDOWN: 'CommonBuffId' = 239701 - BATUU_NPC_WALK_BY_FIRST_ORDER_FS7_POTENTIAL_SPY_VFX_BUFF: 'CommonBuffId' = 248937 - BATUU_NPC_WALK_BY_FIRST_ORDER_OFFICER: 'CommonBuffId' = 232306 - BATUU_NPC_WALK_BY_FIRST_ORDER_OFFICER_RESISTANCE_SPY: 'CommonBuffId' = 242007 - BATUU_NPC_WALK_BY_FIRST_ORDER_STORMTROOPER: 'CommonBuffId' = 232307 - BATUU_NPC_WALK_BY_FIRST_ORDER_STORMTROOPER_PATROL: 'CommonBuffId' = 233328 - BATUU_NPC_WALK_BY_RESISTANCE_MEMBER: 'CommonBuffId' = 232309 - BATUU_NPC_WALK_BY_RESISTANCE_MEMBER_PATROL: 'CommonBuffId' = 233329 - BATUU_NPC_WALK_BY_RESISTANCE_MEMBER_PATROL_2: 'CommonBuffId' = 242493 - BATUU_NPC_WALK_BY_ROLE_STATES_SCOUNDREL_MEMBER: 'CommonBuffId' = 235897 - BATUU_PATROL_COOLDOWN: 'CommonBuffId' = 246383 - BATUU_PICKPOCKET_COOLDOWN: 'CommonBuffId' = 244759 - BATUU_REPUTATION_ENTHUSE_DONT_JOIN: 'CommonBuffId' = 243119 - BATUU_REPUTATION_ENTHUSE_FIRST_ORDER_FAN: 'CommonBuffId' = 243115 - BATUU_REPUTATION_ENTHUSE_FRIEND_OF_THE_RESISTANCE: 'CommonBuffId' = 243113 - BATUU_REPUTATION_FIRST_ORDER_NEGATIVE_INTERACTION_MODIFIER_LEVEL_1: 'CommonBuffId' = 243034 - BATUU_REPUTATION_FIRST_ORDER_NEGATIVE_INTERACTION_MODIFIER_LEVEL_2: 'CommonBuffId' = 243035 - BATUU_REPUTATION_FIRST_ORDER_NEGATIVE_INTERACTION_MODIFIER_LEVEL_3: 'CommonBuffId' = 243036 - BATUU_REPUTATION_FIRST_ORDER_NEGATIVE_INTERACTION_MODIFIER_LEVEL_4: 'CommonBuffId' = 243033 - BATUU_REPUTATION_FIRST_ORDER_NEGATIVE_INTERACTION_MODIFIER_LEVEL_5: 'CommonBuffId' = 243010 - BATUU_REPUTATION_RECRUIT_COOLDOWN: 'CommonBuffId' = 243104 - BATUU_REPUTATION_RESISTANCE_NEGATIVE_INTERACTION_MODIFIER_LEVEL_1: 'CommonBuffId' = 243044 - BATUU_REPUTATION_RESISTANCE_NEGATIVE_INTERACTION_MODIFIER_LEVEL_2: 'CommonBuffId' = 243045 - BATUU_REPUTATION_RESISTANCE_NEGATIVE_INTERACTION_MODIFIER_LEVEL_3: 'CommonBuffId' = 243046 - BATUU_REPUTATION_RESISTANCE_NEGATIVE_INTERACTION_MODIFIER_LEVEL_4: 'CommonBuffId' = 243043 - BATUU_REPUTATION_RESISTANCE_NEGATIVE_INTERACTION_MODIFIER_LEVEL_5: 'CommonBuffId' = 243004 - BATUU_REPUTATION_SCOUNDREL_NEGATIVE_INTERACTION_MODIFIER_LEVEL_1: 'CommonBuffId' = 243049 - BATUU_REPUTATION_SCOUNDREL_NEGATIVE_INTERACTION_MODIFIER_LEVEL_2: 'CommonBuffId' = 243050 - BATUU_REPUTATION_SCOUNDREL_NEGATIVE_INTERACTION_MODIFIER_LEVEL_3: 'CommonBuffId' = 243051 - BATUU_REPUTATION_SCOUNDREL_NEGATIVE_INTERACTION_MODIFIER_LEVEL_4: 'CommonBuffId' = 243048 - BATUU_REPUTATION_SCOUNDREL_NEGATIVE_INTERACTION_MODIFIER_LEVEL_5: 'CommonBuffId' = 243011 - BATUU_REPUTATION_TELLTALES_FIRST_ORDER_BRINGING_ORDER: 'CommonBuffId' = 243130 - BATUU_REPUTATION_TELLTALES_FIRST_ORDER_CRUSHING_THE_RESISTANCE: 'CommonBuffId' = 243131 - BATUU_REPUTATION_TELLTALES_FIRST_ORDER_THEY_DONT_WANT_ORDER: 'CommonBuffId' = 243132 - BATUU_REPUTATION_TELLTALES_RESISTANCE_DESPERATE_TIMES: 'CommonBuffId' = 243128 - BATUU_REPUTATION_TELLTALES_RESISTANCE_LIGHTING_THE_FIRE: 'CommonBuffId' = 243127 - BATUU_REPUTATION_TELLTALES_RESISTANCE_SNUFFED_FLAME: 'CommonBuffId' = 243129 - BATUU_REPUTATION_TELLTALES_RESISTANCE_WE_ARE_THE_SPARK: 'CommonBuffId' = 243126 - BATUU_REPUTATION_TELLTALES_SCOUNDREL_ANYTHING_FOR_A_PRICE: 'CommonBuffId' = 243134 - BATUU_REPUTATION_TELLTALES_SCOUNDREL_NOTHING_BUT_LIES: 'CommonBuffId' = 243137 - BATUU_REPUTATION_TELLTALES_SCOUNDREL_SPICE_WONT_SMUGGLE_ITSELF: 'CommonBuffId' = 243135 - BATUU_REPUTATION_TELLTALES_SCOUNDREL_THE_SCORE_WAS_THIS_BIG: 'CommonBuffId' = 243136 - BATUU_REPUTATION_THERE_IS_HOPE: 'CommonBuffId' = 243100 - BATUU_RESISTANCE_CAVE_COOLDOWN_LONG: 'CommonBuffId' = 245133 - BATUU_RESISTANCE_CAVE_COOLDOWN_SHORT: 'CommonBuffId' = 245132 - BATUU_RESISTANCE_CAVE_NEGATIVE_BUFF_1: 'CommonBuffId' = 245130 - BATUU_RESISTANCE_CAVE_NEGATIVE_BUFF_2: 'CommonBuffId' = 245131 - BATUU_RESISTANCE_CAVE_NEGATIVE_BUFF_3: 'CommonBuffId' = 245129 - BATUU_RESISTANCE_CAVE_POSITIVE_BUFF_1: 'CommonBuffId' = 243238 - BATUU_RESISTANCE_CAVE_POSITIVE_BUFF_2: 'CommonBuffId' = 243237 - BATUU_RESISTANCE_CAVE_POSITIVE_BUFF_3: 'CommonBuffId' = 245128 - BATUU_RESISTANCE_MISSION_GIVER: 'CommonBuffId' = 233177 - BATUU_REY_IDENTIFIER: 'CommonBuffId' = 238985 - BATUU_REY_IGNITE_THE_SPARK: 'CommonBuffId' = 238990 - BATUU_REY_NOTHING_TO_REPORT: 'CommonBuffId' = 238989 - BATUU_RR3_HAS_RECEIVED_FOOD: 'CommonBuffId' = 243939 - BATUU_SPECIAL_NPC_GET_INTO_POSITION_COOLDOWN: 'CommonBuffId' = 249788 - BATUU_SPECIAL_NPC_INCREASE_RELATIONSHIP_GAIN: 'CommonBuffId' = 243287 - BATUU_SPECIAL_NPC_KYLO_ROLE: 'CommonBuffId' = 249774 - BATUU_SPECIAL_NPC_REY_ROLE: 'CommonBuffId' = 250080 - BATUU_STARSHIP_BREAK: 'CommonBuffId' = 248735 - BATUU_STARSHIP_EXPLORE_COOLDOWN: 'CommonBuffId' = 245068 - BATUU_STARSHIP_EXPLORE_COOLDOWN_INTERSTELLAR_UPGRADE: 'CommonBuffId' = 248621 - BATUU_STARSHIP_EXPLORE_FIRST_ORDER_NEGATIVE: 'CommonBuffId' = 245073 - BATUU_STARSHIP_EXPLORE_FIRST_ORDER_POSITIVE: 'CommonBuffId' = 245069 - BATUU_STARSHIP_EXPLORE_RESISTANCE_NEGATIVE: 'CommonBuffId' = 245075 - BATUU_STARSHIP_EXPLORE_RESISTANCE_POSITIVE: 'CommonBuffId' = 245070 - BATUU_STARSHIP_EXPLORE_SCOUNDREL_NEGATIVE: 'CommonBuffId' = 245074 - BATUU_STARSHIP_EXPLORE_SCOUNDREL_POSITIVE: 'CommonBuffId' = 245072 - BATUU_STARSHIP_EXPLORE_WITH_GO_TO_SPACE: 'CommonBuffId' = 239378 - BATUU_STARSHIP_MISSION_CREW_ROLE: 'CommonBuffId' = 244885 - BATUU_STARSHIP_REPAIR_ROLE: 'CommonBuffId' = 239182 - BATUU_SUPPLY_CRATE_SLICE_FAIL: 'CommonBuffId' = 237335 - BATUU_SUPPLY_CRATE_SLICE_SUCCESS: 'CommonBuffId' = 237334 - BATUU_SWINDLE_COOLDOWN: 'CommonBuffId' = 238439 - BATUU_SYSTEM_OVERLOADED: 'CommonBuffId' = 239899 - BATUU_TIL_THE_SPIRE_COOLDOWN: 'CommonBuffId' = 247417 - BATUU_VENDOR_CANCEL_HIDDEN: 'CommonBuffId' = 245746 - BATUU_VI_DUPED: 'CommonBuffId' = 238991 - BATUU_VI_IDENTIFIER: 'CommonBuffId' = 238986 - BATUU_VI_STAND_TOGETHER: 'CommonBuffId' = 238992 - BATUU_VI_WALK_BY: 'CommonBuffId' = 245750 - BATUU_WHITELIST_NPC_GENERIC: 'CommonBuffId' = 240749 - BATUU_WHITELIST_SPECIAL_NPC_AGNON: 'CommonBuffId' = 241027 - BATUU_WHITELIST_SPECIAL_NPC_HONDO: 'CommonBuffId' = 239782 - BATUU_WHITELIST_SPECIAL_NPC_KYLO: 'CommonBuffId' = 240751 - BATUU_WHITELIST_SPECIAL_NPC_REY: 'CommonBuffId' = 240750 - BATUU_WHITELIST_SPECIAL_NPC_VI: 'CommonBuffId' = 241026 - BEACH_CAVE_ANCIENT_WRECK_OUTCOME_1_HIDDEN: 'CommonBuffId' = 210479 - BEACH_CAVE_ANCIENT_WRECK_OUTCOME_2_HIDDEN: 'CommonBuffId' = 210480 - BEACH_CAVE_BAT_COLONY_BAT_BITES: 'CommonBuffId' = 209184 - BEACH_CAVE_BAT_COLONY_NATURAL_HABITAT: 'CommonBuffId' = 209182 - BEACH_CAVE_BAT_COLONY_OUTCOME_1_HIDDEN: 'CommonBuffId' = 210484 - BEACH_CAVE_BAT_COLONY_OUTCOME_2_HIDDEN: 'CommonBuffId' = 210485 - BEACH_CAVE_CAVE_GRAFFITI_GOOD_DEED: 'CommonBuffId' = 209094 - BEACH_CAVE_CAVE_GRAFFITI_OUTCOME_1_HIDDEN: 'CommonBuffId' = 210462 - BEACH_CAVE_CAVE_GRAFFITI_OUTCOME_2_HIDDEN: 'CommonBuffId' = 210463 - BEACH_CAVE_CAVE_GRAFFITI_URBAN_ARTWORK: 'CommonBuffId' = 209097 - BEACH_CAVE_COLLECTION_OF_SHELLS_OUTCOME_1_HIDDEN: 'CommonBuffId' = 210486 - BEACH_CAVE_COLLECTION_OF_SHELLS_OUTCOME_2_HIDDEN: 'CommonBuffId' = 210487 - BEACH_CAVE_COLLECTION_OF_SHELLS_PINCHED_DURING_PILFERING: 'CommonBuffId' = 209185 - BEACH_CAVE_ENCHANTED_SONG_OUTCOME_1_HIDDEN: 'CommonBuffId' = 210460 - BEACH_CAVE_ENCHANTED_SONG_OUTCOME_2_HIDDEN: 'CommonBuffId' = 210461 - BEACH_CAVE_GLINT_OUT_OF_REACH_OUTCOME_1_HIDDEN: 'CommonBuffId' = 210477 - BEACH_CAVE_GLINT_OUT_OF_REACH_OUTCOME_2_HIDDEN: 'CommonBuffId' = 210478 - BEACH_CAVE_GLOW_WORMS_OUTCOME_1_HIDDEN: 'CommonBuffId' = 210490 - BEACH_CAVE_GLOW_WORMS_OUTCOME_2_HIDDEN: 'CommonBuffId' = 210491 - BEACH_CAVE_GLOW_WORMS_STARTLED_BY_LAVA: 'CommonBuffId' = 209188 - BEACH_CAVE_GLOW_WORMS_STRANGE_LIGHTS: 'CommonBuffId' = 209187 - BEACH_CAVE_LAVA_TUBES_OUTCOME_1_HIDDEN: 'CommonBuffId' = 210474 - BEACH_CAVE_LAVA_TUBES_OUTCOME_2_HIDDEN: 'CommonBuffId' = 210475 - BEACH_CAVE_LAVA_TUBES_RAN_FROM_KRAKEN: 'CommonBuffId' = 209160 - BEACH_CAVE_LIGHT_IN_THE_DARK_HIDDEN_LOCH: 'CommonBuffId' = 209106 - BEACH_CAVE_LIGHT_IN_THE_DARK_OUTCOME_1_HIDDEN: 'CommonBuffId' = 210464 - BEACH_CAVE_LIGHT_IN_THE_DARK_OUTCOME_2_HIDDEN: 'CommonBuffId' = 210465 - BEACH_CAVE_LIGHT_IN_THE_DARK_UNEXPECTED_TRIP: 'CommonBuffId' = 209110 - BEACH_CAVE_PLAYFUL_DOLPHINS_OUTCOME_1_HIDDEN: 'CommonBuffId' = 210488 - BEACH_CAVE_PLAYFUL_DOLPHINS_OUTCOME_2_HIDDEN: 'CommonBuffId' = 210489 - BEACH_CAVE_PLAYFUL_DOLPHINS_PLAYTIME_INTERRUPTED: 'CommonBuffId' = 209186 - BEACH_CAVE_STRANGE_NOISE_IN_THE_DARK_OF_THE_CAVE: 'CommonBuffId' = 209102 - BEACH_CAVE_STRANGE_NOISE_OUTCOME_1_HIDDEN: 'CommonBuffId' = 210466 - BEACH_CAVE_STRANGE_NOISE_OUTCOME_2_HIDDEN: 'CommonBuffId' = 210467 - BEACH_CAVE_STRANGE_NOISE_SPLENDOR: 'CommonBuffId' = 209100 - BEACH_CAVE_UNDERGROUND_POOLS_OUTCOME_1_HIDDEN: 'CommonBuffId' = 210472 - BEACH_CAVE_UNDERGROUND_POOLS_OUTCOME_2_HIDDEN: 'CommonBuffId' = 210473 - BEACH_COMBING_COMB_SEASHELLS: 'CommonBuffId' = 206640 - BEACH_COMBING_COMB_TRASH: 'CommonBuffId' = 206641 - BEACH_COMBING_COOLDOWN: 'CommonBuffId' = 210723 - BEACH_COMBING_FAIL_REACTIONS_CUTE_BABY_TURTLE: 'CommonBuffId' = 206736 - BEACH_COMBING_FAIL_REACTIONS_ESCAPED_YOUR_GRASP: 'CommonBuffId' = 206755 - BEACH_COMBING_FAIL_REACTIONS_MADE_CRAB_FRIEND: 'CommonBuffId' = 206735 - BEACH_COMBING_FAIL_REACTIONS_PINCHED_BY_CRAB: 'CommonBuffId' = 206733 - BEACH_COMBING_FAIL_REACTIONS_POOPED_ON: 'CommonBuffId' = 206752 - BEACH_COMBING_FAIL_REACTIONS_SNATCHED_BY_SEAGULL: 'CommonBuffId' = 206751 - BEACH_COMBING_FAIL_REACTIONS_TOUCHED_SOMETHING_GROSS: 'CommonBuffId' = 206756 - BEACH_COMBING_FAIL_REACTIONS_TOUCHED_SOMETHING_PAINFUL: 'CommonBuffId' = 206757 - BEACH_COMBING_FAIL_REACTIONS_WHAT_WAS_THAT: 'CommonBuffId' = 206753 - BEACH_COMBING_SURVEYING: 'CommonBuffId' = 206489 - BEAR_NEARBY: 'CommonBuffId' = 108234 - BEAR_ROARED_AT: 'CommonBuffId' = 108102 - BED_NAP_SLOSHED: 'CommonBuffId' = 10367 - BED_PERFECT_FIRMNESS: 'CommonBuffId' = 231308 - BED_UPDATES_LOW_QUALITY_KNEEL: 'CommonBuffId' = 293649 - BED_UPDATES_LOW_QUALITY_SIT: 'CommonBuffId' = 293648 - BED_UPDATES_PILLOW_FIGHT_LOSE: 'CommonBuffId' = 282996 - BED_UPDATES_PILLOW_FIGHT_WIN: 'CommonBuffId' = 282995 - BED_UPDATES_STAY_IN_SIT_ON_BED_FROM_CHAT: 'CommonBuffId' = 302672 - BED_UPDATES_STAY_IN_SIT_ON_BED_FROM_SIT: 'CommonBuffId' = 302674 - BED_UPDATES_STAY_IN_SIT_ON_GROUND: 'CommonBuffId' = 302784 - BEE_BOX_BEE_SWARM_CHEERED_UP: 'CommonBuffId' = 186570 - BEE_BOX_DISTURB_BOX_PLAYFUL: 'CommonBuffId' = 186204 - BEE_BOX_HONEY: 'CommonBuffId' = 186384 - BEE_BOX_HONEY_BEAR: 'CommonBuffId' = 189014 - BEE_BOX_HONEY_BEE_FOOD_DRINK: 'CommonBuffId' = 188942 - BEE_BOX_STUNG: 'CommonBuffId' = 186173 - BEE_BOX_WEARING_BEE_SUIT: 'CommonBuffId' = 186176 - BEGUILED: 'CommonBuffId' = 35120 - BEG_HOST_OLD_AGE_HORSE: 'CommonBuffId' = 324643 - BEING_INAPPROPRIATE: 'CommonBuffId' = 24336 - BEST_HUG_EVER: 'CommonBuffId' = 332288 - BE_GHOST_ANGER: 'CommonBuffId' = 102367 - BE_GHOST_ANIMAL_OBJECTS_KILLER_CHICKEN: 'CommonBuffId' = 267994 - BE_GHOST_ANIMAL_OBJECTS_KILLER_RABBIT: 'CommonBuffId' = 257787 - BE_GHOST_BROKEN_HEART: 'CommonBuffId' = 382009 - BE_GHOST_CLIMBING_ROUTE: 'CommonBuffId' = 250227 - BE_GHOST_COW_PLANT: 'CommonBuffId' = 102855 - BE_GHOST_DROWN: 'CommonBuffId' = 103659 - BE_GHOST_DROWN_CHILD: 'CommonBuffId' = 105677 - BE_GHOST_ELECTROCUTION: 'CommonBuffId' = 102368 - BE_GHOST_EMBARRASSMENT: 'CommonBuffId' = 102526 - BE_GHOST_FIRE: 'CommonBuffId' = 102369 - BE_GHOST_FIRE_CHILD: 'CommonBuffId' = 103607 - BE_GHOST_FLIES_TRASH_UPDATE: 'CommonBuffId' = 234849 - BE_GHOST_FROZEN: 'CommonBuffId' = 182186 - BE_GHOST_FROZEN_CHILD: 'CommonBuffId' = 182193 - BE_GHOST_GENERIC: 'CommonBuffId' = 102288 - BE_GHOST_GUIDRY: 'CommonBuffId' = 252854 - BE_GHOST_HAUNTED_HOUSE_TEMPERANCE: 'CommonBuffId' = 256361 - BE_GHOST_HUNGRY: 'CommonBuffId' = 102797 - BE_GHOST_METEORITE: 'CommonBuffId' = 295360 - BE_GHOST_MOLD_SYSTEM: 'CommonBuffId' = 343870 - BE_GHOST_MOTHER_PLANT: 'CommonBuffId' = 204160 - BE_GHOST_MURPHY_BED: 'CommonBuffId' = 229439 - BE_GHOST_OLD_AGE: 'CommonBuffId' = 102636 - BE_GHOST_OLD_AGE_PET_IDLE_YOWL: 'CommonBuffId' = 166676 - BE_GHOST_OVERHEATED: 'CommonBuffId' = 184952 - BE_GHOST_OVER_EXERTION: 'CommonBuffId' = 102696 - BE_GHOST_PLAYFUL: 'CommonBuffId' = 102503 - BE_GHOST_POISON: 'CommonBuffId' = 176265 - BE_GHOST_PUFFER_FISH: 'CommonBuffId' = 137464 - BE_GHOST_RODENTT_DISEASE: 'CommonBuffId' = 181921 - BE_GHOST_RODENT_DISEASE: 'CommonBuffId' = 181919 - BE_GHOST_RODENT_DISEASE_RODENT_COSTUME: 'CommonBuffId' = 185711 - BE_GHOST_STEAM: 'CommonBuffId' = 119953 - BE_GHOST_STEAM_CHILD: 'CommonBuffId' = 119954 - BE_GHOST_STINK_BOMB: 'CommonBuffId' = 284381 - BE_GHOST_URBAN_MYTH: 'CommonBuffId' = 284382 - BE_GHOST_VAMPIRE_SUN: 'CommonBuffId' = 151545 - BE_GHOST_VENDING_MACHINE: 'CommonBuffId' = 252088 - BE_GHOST_WITCH_OVERLOAD: 'CommonBuffId' = 216980 - BIRD_FLOCK_ATTACKED_FLOCK: 'CommonBuffId' = 172693 - BIRD_FLOCK_CHASED_FLOCK: 'CommonBuffId' = 172694 - BLESSINGS_ANCIENT_JOY: 'CommonBuffId' = 175088 - BLESSINGS_APPLY_BLESSINGS_ANCIENT_JOY: 'CommonBuffId' = 178958 - BLESSINGS_APPLY_BLESSINGS_ANCIENT_JOY_2: 'CommonBuffId' = 183534 - BLESSINGS_APPLY_BLESSINGS_GLORIOUS_TASTES: 'CommonBuffId' = 183533 - BLESSINGS_APPLY_BLESSINGS_IM_A_SKELETON_COMMON: 'CommonBuffId' = 176391 - BLESSINGS_APPLY_BLESSINGS_IM_A_SKELETON_RARE: 'CommonBuffId' = 176393 - BLESSINGS_APPLY_BLESSINGS_IM_A_SKELETON_UNCOMMON: 'CommonBuffId' = 176392 - BLESSINGS_APPLY_BLESSINGS_ITS_ALL_GOOD: 'CommonBuffId' = 183532 - BLESSINGS_APPLY_BLESSINGS_MONEY_COMMON: 'CommonBuffId' = 175323 - BLESSINGS_APPLY_BLESSINGS_MONEY_RARE: 'CommonBuffId' = 175324 - BLESSINGS_APPLY_BLESSINGS_MONEY_UNCOMMON: 'CommonBuffId' = 175325 - BLESSINGS_APPLY_BLESSINGS_PERSONAL_SUN: 'CommonBuffId' = 183531 - BLESSINGS_APPLY_BLESSINGS_RELATIONSHIPS_COMMON: 'CommonBuffId' = 175347 - BLESSINGS_APPLY_BLESSINGS_RELATIONSHIPS_RARE: 'CommonBuffId' = 175348 - BLESSINGS_APPLY_BLESSINGS_RELATIONSHIPS_UNCOMMON: 'CommonBuffId' = 175349 - BLESSINGS_APPLY_BLESSINGS_SERVICE_SKELETON_COMMON: 'CommonBuffId' = 177656 - BLESSINGS_APPLY_BLESSINGS_SERVICE_SKELETON_RARE: 'CommonBuffId' = 177658 - BLESSINGS_APPLY_BLESSINGS_SERVICE_SKELETON_UNCOMMON: 'CommonBuffId' = 177657 - BLESSINGS_EFFECTS_GLORIOUS_TASTES_GREAT_MEAL: 'CommonBuffId' = 175299 - BLESSINGS_EFFECTS_IM_A_SKELETON_COMMON: 'CommonBuffId' = 176399 - BLESSINGS_EFFECTS_IM_A_SKELETON_RARE: 'CommonBuffId' = 176401 - BLESSINGS_EFFECTS_IM_A_SKELETON_UNCOMMON: 'CommonBuffId' = 176400 - BLESSINGS_GLORIOUS_TASTES: 'CommonBuffId' = 175284 - BLESSINGS_ITS_ALL_GOOD: 'CommonBuffId' = 175207 - BLESSINGS_PERSONAL_SUN: 'CommonBuffId' = 175014 - BLOCK_CONSTRUCTION_TABLE_BONDING_TIME: 'CommonBuffId' = 165602 - BLOCK_CONSTRUCTION_TABLE_CONSTRUCTION_COLLABORATION: 'CommonBuffId' = 165365 - BODY_SPRAY: 'CommonBuffId' = 12387 - BOOK_READ_TOO_EASY_VAMPIRE_BOOK: 'CommonBuffId' = 149625 - BOOK_READ_TOO_HARD_VAMPIRE_BOOK: 'CommonBuffId' = 149627 - BOUQUET_STOP_HOLDING: 'CommonBuffId' = 282710 - BREATH_SPRAY: 'CommonBuffId' = 12388 - BROKEN_UP_OR_DIVORCED_HIDDEN: 'CommonBuffId' = 28121 - BUFFS_CORE_SOCIALS_BUFFS_PEEVED_CHILD: 'CommonBuffId' = 40595 - BUFFS_CORE_SOCIAL_BUFFS_AWKWARD_TURTLE: 'CommonBuffId' = 37659 - BUFFS_CORE_SOCIAL_BUFFS_DULL_HUMOR: 'CommonBuffId' = 37656 - BUFFS_CORE_SOCIAL_BUFFS_ENOUGH_IS_ENOUGH: 'CommonBuffId' = 37654 - BUFFS_CORE_SOCIAL_BUFFS_FLATTERED: 'CommonBuffId' = 37684 - BUFFS_CORE_SOCIAL_BUFFS_HOT_N_HEAVY: 'CommonBuffId' = 37657 - BUFFS_CORE_SOCIAL_BUFFS_MADE_A_DEEP_CONNECTION: 'CommonBuffId' = 37658 - BUFFS_CORE_SOCIAL_BUFFS_ON_A_ROLL: 'CommonBuffId' = 37664 - BUFFS_MAKE_A_MESS_COOLDOWN: 'CommonBuffId' = 168756 - BUFFS_MAKE_A_MESS_INSPIRED: 'CommonBuffId' = 163601 - BUFFS_MAKE_A_MESS_PLAYFUL: 'CommonBuffId' = 163602 - BUFFS_MENTOREE_BASKETBALL: 'CommonBuffId' = 147863 - BUFFS_MENTOREE_BY_MENTOR_PRO_FABRICATION: 'CommonBuffId' = 237524 - BUFFS_MENTOREE_BY_MENTOR_PRO_MURAL: 'CommonBuffId' = 152534 - BUFFS_MENTOREE_FABRICATION: 'CommonBuffId' = 237523 - BUFFS_MENTOREE_FISHING: 'CommonBuffId' = 207780 - BUFFS_MENTOREE_KNITTING: 'CommonBuffId' = 245597 - BUFFS_MENTOREE_MURAL: 'CommonBuffId' = 152533 - BUFFS_MENTOREE_ROBOTICS: 'CommonBuffId' = 227897 - BUFFS_MENTOREE_TODDLER_DANCING: 'CommonBuffId' = 150130 - BUFFS_MENTOREE_TODDLER_DANCING_CLINGY: 'CommonBuffId' = 154565 - BUFFS_MENTOREE_TODDLER_DANCING_INDEPENDENT: 'CommonBuffId' = 157434 - BUFFS_MENTOREE_TODDLER_FAILURE: 'CommonBuffId' = 156538 - BUFFS_MENTOREE_TODDLER_INTERACTING: 'CommonBuffId' = 254901 - BUFFS_MENTOREE_TODDLER_NESTING_BLOCKS: 'CommonBuffId' = 148197 - BUFFS_MENTOREE_TODDLER_NESTING_BLOCKS_CLINGY: 'CommonBuffId' = 154570 - BUFFS_MENTOREE_TODDLER_PROUD: 'CommonBuffId' = 156449 - BUFFS_PORTABLE_KEYBOARD_BUSKER_TIPPED_HIGH: 'CommonBuffId' = 147273 - BUFFS_PORTABLE_KEYBOARD_BUSKER_TIPPED_LOW: 'CommonBuffId' = 147274 - BUFFS_PORTABLE_KEYBOARD_BUSKER_TIPPED_MED: 'CommonBuffId' = 147275 - BUILD_LADDERS_SLIDE: 'CommonBuffId' = 236254 - BUILD_LADDERS_SLIDE_HAPPY: 'CommonBuffId' = 236653 - BUILD_UP_PARTNER: 'CommonBuffId' = 372344 - BURNOUT_BURNED_OUT: 'CommonBuffId' = 306680 - BURNOUT_CLEAR_MIND_FINE: 'CommonBuffId' = 306861 - BURNOUT_CLEAR_MIND_HAPPY: 'CommonBuffId' = 306747 - BURNOUT_FOG_CREATIVE: 'CommonBuffId' = 304277 - BURNOUT_FOG_MENTAL: 'CommonBuffId' = 306746 - BURNOUT_HIDDEN_CREATIVE_TRACKER: 'CommonBuffId' = 306676 - BURNOUT_HIDDEN_CREATIVE_TRACKER_DECREASE_LARGE: 'CommonBuffId' = 306714 - BURNOUT_HIDDEN_CREATIVE_TRACKER_DECREASE_SMALL: 'CommonBuffId' = 306715 - BURNOUT_HIDDEN_CREATIVE_TRACKER_INCREASE_LARGE: 'CommonBuffId' = 304276 - BURNOUT_HIDDEN_CREATIVE_TRACKER_INCREASE_SMALL: 'CommonBuffId' = 306713 - BURNOUT_HIDDEN_DECREASE_LARGE_FOG_BURNED_OUT_MENTAL_BLOCK: 'CommonBuffId' = 324909 - BURNOUT_HIDDEN_DECREASE_SMALL_FOG_BURNED_OUT_MENTAL_BLOCK: 'CommonBuffId' = 324908 - BURNOUT_HIDDEN_INCREASE_LARGE_FOG_BURNED_OUT: 'CommonBuffId' = 324906 - BURNOUT_HIDDEN_INCREASE_SMALL_FOG_BURNED_OUT: 'CommonBuffId' = 324907 - BURNOUT_HIDDEN_MENTAL_TRACKER: 'CommonBuffId' = 306750 - BURNOUT_HIDDEN_MENTAL_TRACKER_DECREASE_LARGE: 'CommonBuffId' = 306779 - BURNOUT_HIDDEN_MENTAL_TRACKER_DECREASE_SMALL: 'CommonBuffId' = 306780 - BURNOUT_HIDDEN_MENTAL_TRACKER_INCREASE_LARGE: 'CommonBuffId' = 306781 - BURNOUT_HIDDEN_MENTAL_TRACKER_INCREASE_SMALL: 'CommonBuffId' = 306802 - BURNOUT_HIDDEN_ON_VACATION: 'CommonBuffId' = 308561 - BURNOUT_HIDDEN_TIMER_BURNED_OUT: 'CommonBuffId' = 306803 - BURNOUT_HIDDEN_TIMER_FOG_CREATIVE: 'CommonBuffId' = 306678 - BURNOUT_HIDDEN_TIMER_FOG_MENTAL: 'CommonBuffId' = 306753 - BURNOUT_MENTAL_BLOCK: 'CommonBuffId' = 306776 - BUSH_PET_BIRD: 'CommonBuffId' = 171930 - BUSH_PET_DIRTY: 'CommonBuffId' = 176262 - BUSH_PET_FIND_ITEM: 'CommonBuffId' = 171931 - BUSH_PET_PLAY: 'CommonBuffId' = 171932 - BUSH_PET_SKUNKED: 'CommonBuffId' = 171906 - BUSH_PET_SQUIRREL_FAIL: 'CommonBuffId' = 171929 - BUSH_PET_SQUIRREL_SUCCESS: 'CommonBuffId' = 171910 - CAFETERIA_STATION_FAILED_PRANK: 'CommonBuffId' = 217688 - CAFETERIA_STATION_SERVER_BREAKFAST: 'CommonBuffId' = 229048 - CAFETERIA_STATION_SERVER_DINNER: 'CommonBuffId' = 229050 - CAFETERIA_STATION_SERVER_LUNCH: 'CommonBuffId' = 229049 - CAFETERIA_STATION_SERVER_PRANKED: 'CommonBuffId' = 218062 - CAFETERIA_STATION_TOO_SPICY: 'CommonBuffId' = 218816 - CAMPING_FOREST_HOME_SICK: 'CommonBuffId' = 105348 - CAMPING_FOREST_LOVES_OUTDOORS_REJUVENATED: 'CommonBuffId' = 107826 - CAMPING_FOREST_MOSQUITOES: 'CommonBuffId' = 110271 - CAMPING_FOREST_NEAT_HYGIENE_DECAY: 'CommonBuffId' = 107875 - CAMPING_FOREST_REFRESHED: 'CommonBuffId' = 104851 - CANNING_COWBERRY_JAM: 'CommonBuffId' = 257629 - CANNING_EXCELLENT_QUALITY: 'CommonBuffId' = 257630 - CANNING_JAMS: 'CommonBuffId' = 267680 - CANNING_MAYO_HATES: 'CommonBuffId' = 267681 - CANNING_MAYO_LIKES: 'CommonBuffId' = 267682 - CAREER_10_FAR_BEHIND: 'CommonBuffId' = 39475 - CAREER_10_FLUFFY_MISSING: 'CommonBuffId' = 75611 - CAREER_10_FLUFFY_RECOVERED: 'CommonBuffId' = 75608 - CAREER_10_HATERS_APPEASED: 'CommonBuffId' = 38547 - CAREER_10_LOST_GERBIL_HANDLING_RIGHT: 'CommonBuffId' = 75610 - CAREER_10_NEW_RECIPE: 'CommonBuffId' = 38531 - CAREER_10_PEER_STUDY: 'CommonBuffId' = 39471 - CAREER_10_RECAPTURED_FLUFFY: 'CommonBuffId' = 75609 - CAREER_10_SCAMMED: 'CommonBuffId' = 38532 - CAREER_10_UNCOMFORTABLE: 'CommonBuffId' = 106897 - CAREER_10_WROTE_FOR_TV: 'CommonBuffId' = 38583 - CAREER_11_EMPTY_CROWD: 'CommonBuffId' = 38203 - CAREER_11_EX_ON_HOLD: 'CommonBuffId' = 39531 - CAREER_11_FIERY_EX: 'CommonBuffId' = 39530 - CAREER_11_HOMEWORK_COMPLETE: 'CommonBuffId' = 39477 - CAREER_11_MOUNTAIN_OF_HOMEWORK: 'CommonBuffId' = 39480 - CAREER_11_PREFORMED_FOR_FRIENDS: 'CommonBuffId' = 38202 - CAREER_11_SENT_INTO_THE_HALL: 'CommonBuffId' = 75614 - CAREER_11_SOMEONE_ELSE_IN_TROUBLE: 'CommonBuffId' = 75612 - CAREER_12_CAUGHT_NAPPING: 'CommonBuffId' = 75616 - CAREER_12_DELAYED_POSTING: 'CommonBuffId' = 37960 - CAREER_12_NO_NEW_GOOD_NEWS: 'CommonBuffId' = 37958 - CAREER_12_PERFECT_C_STUDENT: 'CommonBuffId' = 39482 - CAREER_12_PE_NAP: 'CommonBuffId' = 75615 - CAREER_12_SMELLY_TIRADE: 'CommonBuffId' = 39532 - CAREER_13_A_PLUS_PROJECT: 'CommonBuffId' = 39488 - CAREER_13_CLASS_GOSSIP: 'CommonBuffId' = 75618 - CAREER_13_FLUBBED_ATTEMPT: 'CommonBuffId' = 38205 - CAREER_13_HECKLER_SHUTDOWN: 'CommonBuffId' = 38204 - CAREER_13_HUMOROUS_BOSS: 'CommonBuffId' = 38148 - CAREER_13_LOWER_GRADE: 'CommonBuffId' = 39490 - CAREER_13_MISSED_DEADLINE: 'CommonBuffId' = 39534 - CAREER_13_NOT_FULLY_PAID: 'CommonBuffId' = 37962 - CAREER_13_SECRET_ADMIRER: 'CommonBuffId' = 75617 - CAREER_13_SELF_LEARNING: 'CommonBuffId' = 39533 - CAREER_13_SLACKING_CLASSMATES: 'CommonBuffId' = 39489 - CAREER_14_ASSIGNMENT_EXTENSION: 'CommonBuffId' = 75620 - CAREER_14_COPIED_A_CLASSMATE: 'CommonBuffId' = 75619 - CAREER_14_FINDERS_KEEPERS: 'CommonBuffId' = 39491 - CAREER_14_HENCHMEN_CHAT: 'CommonBuffId' = 38655 - CAREER_14_MISSING_FINGERNAILS: 'CommonBuffId' = 38653 - CAREER_14_NO_LUNCH: 'CommonBuffId' = 75621 - CAREER_14_PRINCIPALS_SPEECH: 'CommonBuffId' = 39492 - CAREER_14_UNDERCOVER_STORIES: 'CommonBuffId' = 38652 - CAREER_15_BRANCHING_OUT: 'CommonBuffId' = 37964 - CAREER_15_DEMO_SCRAMBLE: 'CommonBuffId' = 39537 - CAREER_15_DIFFICULT_REPORT: 'CommonBuffId' = 39493 - CAREER_15_FAN_BACKLASH: 'CommonBuffId' = 37965 - CAREER_15_MENTOR_DISCOVERED: 'CommonBuffId' = 38428 - CAREER_15_NUMBED_MIND: 'CommonBuffId' = 39494 - CAREER_15_ONE_LESS_FRIEND: 'CommonBuffId' = 75622 - CAREER_15_PAGER_WORRIES: 'CommonBuffId' = 38149 - CAREER_15_RESTED_AND_RECOVERED: 'CommonBuffId' = 38052 - CAREER_15_SPEAK_UP: 'CommonBuffId' = 38150 - CAREER_15_SPY_INSTINCTS: 'CommonBuffId' = 38650 - CAREER_15_TASKS_CLEARED_OUT: 'CommonBuffId' = 39538 - CAREER_15_THE_FUMES: 'CommonBuffId' = 38053 - CAREER_15_TV_BIRTHDAY: 'CommonBuffId' = 75623 - CAREER_16_BABY_CRANKS: 'CommonBuffId' = 38051 - CAREER_16_DISSUADED_BULLIES: 'CommonBuffId' = 39495 - CAREER_16_DOCTORED_UP_BOSS: 'CommonBuffId' = 39541 - CAREER_16_EPIC_WEDGIE: 'CommonBuffId' = 39496 - CAREER_16_EXTRA_HOMEWORK: 'CommonBuffId' = 75630 - CAREER_16_IMPROVING_CAMARADERIE: 'CommonBuffId' = 39540 - CAREER_16_RIOT_STORIES: 'CommonBuffId' = 37993 - CAREER_16_TEST_RETAKEN: 'CommonBuffId' = 75629 - CAREER_16_WORKED_ALL_NIGHT: 'CommonBuffId' = 99454 - CAREER_16_WRITING_PRAISED: 'CommonBuffId' = 37967 - CAREER_16_YELLOW_JOURNALISM: 'CommonBuffId' = 37968 - CAREER_17_ANGRY_FRIEND: 'CommonBuffId' = 39500 - CAREER_17_CANCELED_PROJECT: 'CommonBuffId' = 39544 - CAREER_17_CHASED_OFF_STAGE: 'CommonBuffId' = 38209 - CAREER_17_HORRIBLE_HOST: 'CommonBuffId' = 37974 - CAREER_17_INCOMPETENT_AGENT: 'CommonBuffId' = 38158 - CAREER_17_MORE_PAPERWORK: 'CommonBuffId' = 38153 - CAREER_17_NO_COMPETITION: 'CommonBuffId' = 39542 - CAREER_17_PROJECT_THROWN_OUT: 'CommonBuffId' = 75631 - CAREER_17_RUSHED_PROJECT: 'CommonBuffId' = 39543 - CAREER_17_SIMPLE_MINDED_FRIEND: 'CommonBuffId' = 39499 - CAREER_17_SPLOTCH_PAINT_JOB: 'CommonBuffId' = 38058 - CAREER_17_STUNNING_BALLAD: 'CommonBuffId' = 38208 - CAREER_18_ACADEMIC_FAME: 'CommonBuffId' = 75634 - CAREER_18_BARGAIN_BIN_BOMB: 'CommonBuffId' = 37976 - CAREER_18_BORROWED_TUX: 'CommonBuffId' = 38211 - CAREER_18_CONFUSING_SEQUEL: 'CommonBuffId' = 37975 - CAREER_18_GREEN_LIT_IDEA: 'CommonBuffId' = 39545 - CAREER_18_LOST_HONESTLY: 'CommonBuffId' = 75633 - CAREER_18_RUINED_PIECES: 'CommonBuffId' = 38059 - CAREER_18_SURPRISE_WINNER: 'CommonBuffId' = 75635 - CAREER_18_THAT_AWKWARD_SOUND: 'CommonBuffId' = 38217 - CAREER_18_TRICKED_INTO_FAILURE: 'CommonBuffId' = 75632 - CAREER_18_TURNCOAT_MENTOR: 'CommonBuffId' = 38160 - CAREER_19_AIRPLANE_INNOVATION: 'CommonBuffId' = 75636 - CAREER_19_BENT_AIRPLANE: 'CommonBuffId' = 75638 - CAREER_19_BORING_CASE: 'CommonBuffId' = 38161 - CAREER_19_CATCHY_TUNE: 'CommonBuffId' = 38219 - CAREER_19_MASCOT_BEAT_DOWN: 'CommonBuffId' = 39548 - CAREER_19_OUTDATED_ARTIST: 'CommonBuffId' = 38061 - CAREER_19_PERSONAL_MASCOT: 'CommonBuffId' = 39549 - CAREER_19_PIDDLE_PIDDLE: 'CommonBuffId' = 38220 - CAREER_19_RAUCOUS_JEERS: 'CommonBuffId' = 39547 - CAREER_19_SHARED_DESIGN: 'CommonBuffId' = 75637 - CAREER_19_SOUND_DEBATE: 'CommonBuffId' = 38054 - CAREER_19_THREW_OFF_CURVE: 'CommonBuffId' = 39501 - CAREER_19_UNNEEDED_QUESTIONING: 'CommonBuffId' = 37994 - CAREER_1_ANOTHER_LECTURE: 'CommonBuffId' = 39443 - CAREER_1_ASLEEP_IN_CLASS: 'CommonBuffId' = 39445 - CAREER_1_QUICK_SNACK: 'CommonBuffId' = 75580 - CAREER_1_SENT_TO_PRINCIPAL: 'CommonBuffId' = 75579 - CAREER_1_SPITBALL_MARKSMAN: 'CommonBuffId' = 39439 - CAREER_20_ABSTRACT_MEMORY: 'CommonBuffId' = 38063 - CAREER_20_ANOTHERS_EMBARRASSMENT: 'CommonBuffId' = 75639 - CAREER_20_DISASTROUS_MATCH: 'CommonBuffId' = 39551 - CAREER_20_KITTEN_SAVIOR: 'CommonBuffId' = 37995 - CAREER_20_LIFE_LESSON: 'CommonBuffId' = 39502 - CAREER_20_NO_ONES_WORKING: 'CommonBuffId' = 38162 - CAREER_20_OFFICE_DOWNTIME: 'CommonBuffId' = 38163 - CAREER_20_PAINTERS_EYE: 'CommonBuffId' = 38062 - CAREER_20_UNIFIED_TEAM: 'CommonBuffId' = 39550 - CAREER_21_CAUGHT_WITH_A_BIB: 'CommonBuffId' = 75641 - CAREER_21_DEALING_WITH_PAIN: 'CommonBuffId' = 38065 - CAREER_21_ELECTRONIC_FUTURE: 'CommonBuffId' = 37977 - CAREER_21_FEARLESS_HIPSTERS: 'CommonBuffId' = 37996 - CAREER_21_FUTURE_BLACKMAIL: 'CommonBuffId' = 38164 - CAREER_21_FUTURE_FOCUSED: 'CommonBuffId' = 39504 - CAREER_21_INFORMATION_OVERLOAD: 'CommonBuffId' = 39505 - CAREER_21_LESS_CHORES: 'CommonBuffId' = 38064 - CAREER_21_LOST_SOME_FANS: 'CommonBuffId' = 38221 - CAREER_21_RACKET_ANGUISH: 'CommonBuffId' = 37997 - CAREER_21_SHARED_BISCUITS: 'CommonBuffId' = 75640 - CAREER_21_STUDY_BREAK: 'CommonBuffId' = 39503 - CAREER_22_CHARITABLE_ACTION: 'CommonBuffId' = 37979 - CAREER_22_CHEESY_SPEECH: 'CommonBuffId' = 38165 - CAREER_22_COLA_RUSH: 'CommonBuffId' = 39506 - CAREER_22_CULPRIT_CAUGHT: 'CommonBuffId' = 75643 - CAREER_22_DROPPED_WEAK_LINK: 'CommonBuffId' = 39552 - CAREER_22_MANUSCRIPT_SPOILERS: 'CommonBuffId' = 37978 - CAREER_22_ONGOING_SUGAR_RUSH: 'CommonBuffId' = 39508 - CAREER_22_OVERSLEPT: 'CommonBuffId' = 39507 - CAREER_22_PAINTING_RESTORER: 'CommonBuffId' = 38092 - CAREER_22_SEAT_TAKEN: 'CommonBuffId' = 38222 - CAREER_22_SIGN_TRANSFERRED: 'CommonBuffId' = 75644 - CAREER_22_THOROUGH_THRASHING: 'CommonBuffId' = 37999 - CAREER_23_ANGRY: 'CommonBuffId' = 106898 - CAREER_23_CAR_STUNT_REALITY: 'CommonBuffId' = 38003 - CAREER_23_DUKES_MOMENT: 'CommonBuffId' = 38001 - CAREER_23_FAILED_RUSE: 'CommonBuffId' = 75645 - CAREER_23_FEIGNED_ILLNESS: 'CommonBuffId' = 75646 - CAREER_23_HAPPY_WITH_RESULTS: 'CommonBuffId' = 39515 - CAREER_23_IN_THE_GAMER_ZONE: 'CommonBuffId' = 39553 - CAREER_23_LACKED_MOMENTUM: 'CommonBuffId' = 38095 - CAREER_23_LOWER_SDT_SCORE: 'CommonBuffId' = 39513 - CAREER_23_MOVEMENT_INSPIRATION: 'CommonBuffId' = 38094 - CAREER_23_OVER_PARTIED: 'CommonBuffId' = 39554 - CAREER_23_OVER_THE_TOP: 'CommonBuffId' = 37982 - CAREER_23_TERMINALLY_HOT: 'CommonBuffId' = 38166 - CAREER_23_TOTAL_PERFECTION: 'CommonBuffId' = 39514 - CAREER_23_UNORTHODOX_REPORT: 'CommonBuffId' = 37980 - CAREER_24_AHEAD_OF_RIVAL: 'CommonBuffId' = 39522 - CAREER_24_ANOTHER_LOST_MEAL: 'CommonBuffId' = 75649 - CAREER_24_CLEANED_THE_IVORIES: 'CommonBuffId' = 38227 - CAREER_24_CRITICALLY_ACCLAIMED: 'CommonBuffId' = 38096 - CAREER_24_FALSE_CLAIM: 'CommonBuffId' = 38097 - CAREER_24_FROSTBIT_FINGERS: 'CommonBuffId' = 38006 - CAREER_24_LAXATIVE_LACED_BROWNIE: 'CommonBuffId' = 75648 - CAREER_24_LEFT_EM_BEWILDERED: 'CommonBuffId' = 38005 - CAREER_24_MEMOIRS_CANCELED: 'CommonBuffId' = 38173 - CAREER_24_NEW_NICKNAME: 'CommonBuffId' = 38004 - CAREER_24_NOTEBOOK_RETURNED: 'CommonBuffId' = 39521 - CAREER_24_REWARDED_INSPIRATION: 'CommonBuffId' = 38099 - CAREER_24_SHAMED_BULLY: 'CommonBuffId' = 75647 - CAREER_24_SPY_GAMES: 'CommonBuffId' = 38167 - CAREER_24_STICKY_KEYS: 'CommonBuffId' = 38228 - CAREER_24_TRAP_GIVEN_TO_PRINCIPAL: 'CommonBuffId' = 75650 - CAREER_24_TUTORING_RIVAL: 'CommonBuffId' = 39525 - CAREER_24_UNCOMFORTABLE: 'CommonBuffId' = 106899 - CAREER_24_UNGRATEFUL_RIVAL: 'CommonBuffId' = 39523 - CAREER_25_ANYTHING_FOR_EXPOSURE: 'CommonBuffId' = 38100 - CAREER_25_APPEASED_THE_BRIDE: 'CommonBuffId' = 38229 - CAREER_25_BRIDEZILLA: 'CommonBuffId' = 38230 - CAREER_25_CONFIDENT: 'CommonBuffId' = 106900 - CAREER_25_EMBARRASSED: 'CommonBuffId' = 106964 - CAREER_25_HELPING_THE_COOL_KIDS: 'CommonBuffId' = 75652 - CAREER_25_PASSED_THE_BLAME: 'CommonBuffId' = 38325 - CAREER_25_QUIZASTER: 'CommonBuffId' = 39527 - CAREER_25_SLY_CHEATER: 'CommonBuffId' = 75653 - CAREER_25_STRAIGHT_ARROW_PARTNER: 'CommonBuffId' = 38174 - CAREER_25_TARNISHED_REPUTATION: 'CommonBuffId' = 38101 - CAREER_25_TRUTH_OR_DODGE_BALL: 'CommonBuffId' = 39528 - CAREER_25_UNLUCKY_NUMBER7: 'CommonBuffId' = 38007 - CAREER_25_UNRULY_CLASSMATES: 'CommonBuffId' = 39526 - CAREER_25_VENGEFUL_MODERATOR: 'CommonBuffId' = 39555 - CAREER_26_APPEALING_COMPOSITION: 'CommonBuffId' = 38231 - CAREER_26_BAD_ANSWERS: 'CommonBuffId' = 75584 - CAREER_26_CLASS_COMEDIAN: 'CommonBuffId' = 75592 - CAREER_26_COMPOSITION_IGNORED: 'CommonBuffId' = 38557 - CAREER_26_ENJOYABLE_INTERVIEW: 'CommonBuffId' = 75655 - CAREER_26_GOT_SPOOKED: 'CommonBuffId' = 37983 - CAREER_26_JOB_INSECURITY: 'CommonBuffId' = 38103 - CAREER_26_JOB_SECURITY: 'CommonBuffId' = 38102 - CAREER_26_LONG_INTERVIEW: 'CommonBuffId' = 75654 - CAREER_26_REEVALUATING_KEY_UNDERLINGS: 'CommonBuffId' = 38008 - CAREER_26_TASTE_OF_FAILURE: 'CommonBuffId' = 38177 - CAREER_26_TASTY_SECRETS: 'CommonBuffId' = 38175 - CAREER_27_CONFIDENT: 'CommonBuffId' = 106912 - CAREER_27_DISPERSED_THE_CROWD: 'CommonBuffId' = 38105 - CAREER_27_DREW_A_CROWD: 'CommonBuffId' = 38104 - CAREER_27_EMBARRASSED: 'CommonBuffId' = 106913 - CAREER_27_ENJOYABLE_VACATION: 'CommonBuffId' = 39556 - CAREER_28_ART_IN_THE_DARK: 'CommonBuffId' = 38108 - CAREER_28_BEATEN_BY_SLOB: 'CommonBuffId' = 38233 - CAREER_28_COLLECTION_BONANZA: 'CommonBuffId' = 38106 - CAREER_28_COMPANY_RECOVERING: 'CommonBuffId' = 39558 - CAREER_28_DESPICABLE_CFO: 'CommonBuffId' = 39557 - CAREER_28_HONORARY_WING: 'CommonBuffId' = 38107 - CAREER_28_IN_THE_CLEAR: 'CommonBuffId' = 38178 - CAREER_28_UNDER_SUSPICION: 'CommonBuffId' = 38179 - CAREER_29_COUNTRY_ROCKED: 'CommonBuffId' = 38328 - CAREER_29_ENERGIZED: 'CommonBuffId' = 106914 - CAREER_2_ANGRY: 'CommonBuffId' = 106882 - CAREER_2_FAILED_CALL_OUT: 'CommonBuffId' = 38563 - CAREER_2_GOOD_LAUGH: 'CommonBuffId' = 75583 - CAREER_2_LAUGHING_STOCK: 'CommonBuffId' = 75585 - CAREER_2_ROASTING_A_HACK: 'CommonBuffId' = 38564 - CAREER_2_SILVER_TOUNGED_SLACKER: 'CommonBuffId' = 38550 - CAREER_2_WET_PANTS: 'CommonBuffId' = 75586 - CAREER_30_EMBARRASSED: 'CommonBuffId' = 107442 - CAREER_30_ENERGIZED: 'CommonBuffId' = 107441 - CAREER_30_FAKE_DOCUMENTS: 'CommonBuffId' = 38424 - CAREER_30_KNOWLEDGE_LEAKER: 'CommonBuffId' = 38027 - CAREER_30_NO_CREDIT: 'CommonBuffId' = 38236 - CAREER_31_LOCKED_OUT: 'CommonBuffId' = 38026 - CAREER_31_OVERSTEPPED_FRIENDSHIP: 'CommonBuffId' = 38238 - CAREER_31_SECURITY_CRACKER: 'CommonBuffId' = 38021 - CAREER_32_COVERED_IN_SPITBALLS: 'CommonBuffId' = 38239 - CAREER_32_HAPPY: 'CommonBuffId' = 107440 - CAREER_32_INTERNET_AFLAME: 'CommonBuffId' = 38028 - CAREER_32_SAD: 'CommonBuffId' = 107439 - CAREER_32_SNEAK_PEEK: 'CommonBuffId' = 38030 - CAREER_32_UNBELIEVABLE_SPOILERS: 'CommonBuffId' = 38024 - CAREER_3_A_LITTLE_CHEATING: 'CommonBuffId' = 75587 - CAREER_3_STRESS_FREE_ANSWERING: 'CommonBuffId' = 39711 - CAREER_3_TATTLED_ON: 'CommonBuffId' = 75588 - CAREER_3_UNDER_PREPARED: 'CommonBuffId' = 39448 - CAREER_4_BALLISTIC_WATERMELON_GUM: 'CommonBuffId' = 75593 - CAREER_4_CHEWED_ANOTHERS_GUM: 'CommonBuffId' = 75590 - CAREER_4_DISSECTION_THEFT: 'CommonBuffId' = 39451 - CAREER_4_GENEROUS_FRIENDS: 'CommonBuffId' = 39455 - CAREER_4_ILL_GOTTEN_CHOW: 'CommonBuffId' = 39454 - CAREER_4_SHARED_USED_GUM: 'CommonBuffId' = 75594 - CAREER_4_SOUND_FAILURE: 'CommonBuffId' = 38567 - CAREER_4_WRONGLY_ACCUSED: 'CommonBuffId' = 75591 - CAREER_5_BULLYING_NERD: 'CommonBuffId' = 75595 - CAREER_5_FIRE_ALARM_EXTENSION: 'CommonBuffId' = 39458 - CAREER_5_HAPPY: 'CommonBuffId' = 106884 - CAREER_5_NEW_FRIEND: 'CommonBuffId' = 75597 - CAREER_5_SHORTED: 'CommonBuffId' = 38570 - CAREER_5_TURNED_AWAY_BY_FRIENDS: 'CommonBuffId' = 75596 - CAREER_5_UNCOMFORTABLE: 'CommonBuffId' = 106883 - CAREER_6_FIELD_TRIP: 'CommonBuffId' = 75599 - CAREER_6_FORGED_SIGNATURE: 'CommonBuffId' = 75598 - CAREER_6_FORGED_WRONG_NAME: 'CommonBuffId' = 75600 - CAREER_6_HYSTERICAL_CAULIFLOWER: 'CommonBuffId' = 38574 - CAREER_6_MISSED_FIELD_TRIP: 'CommonBuffId' = 75601 - CAREER_6_TESTING_ANGST: 'CommonBuffId' = 39461 - CAREER_6_UNGUARDED_ANSWERS: 'CommonBuffId' = 39459 - CAREER_7_CHOCOLATE_CHIP_COOKIE: 'CommonBuffId' = 75602 - CAREER_7_FALSELY_ACCUSED: 'CommonBuffId' = 75603 - CAREER_7_STILL_CONFUSED: 'CommonBuffId' = 39462 - CAREER_8_DISCUSSING_FEELINGS: 'CommonBuffId' = 39463 - CAREER_8_FEEBLE_MANAGER: 'CommonBuffId' = 38434 - CAREER_8_HELPED_ANOTHER: 'CommonBuffId' = 75604 - CAREER_8_HYPER_STRESS: 'CommonBuffId' = 39465 - CAREER_8_JUST_TRYING_TO_HELP: 'CommonBuffId' = 75605 - CAREER_8_PARENT_COUNSELOR_MEETING: 'CommonBuffId' = 39464 - CAREER_8_PLAYED_OFF: 'CommonBuffId' = 38579 - CAREER_8_WRONG_COMPANY: 'CommonBuffId' = 38578 - CAREER_9_NO_TIME_FOR_DOODLES: 'CommonBuffId' = 75606 - CAREER_9_REDONE_TEST: 'CommonBuffId' = 75607 - CAREER_9_THIRD_PERIOD_NAP: 'CommonBuffId' = 39469 - CAREER_9_UNCOMFORTABLE: 'CommonBuffId' = 106896 - CAREER_ABANDON_SHIP: 'CommonBuffId' = 37759 - CAREER_ACTIVIST_BREAK_WATCH_PROTEST_HIDDEN: 'CommonBuffId' = 136094 - CAREER_ACTIVIST_CAUSE_SUCCESSFUL_ECONOMY: 'CommonBuffId' = 136398 - CAREER_ACTIVIST_CAUSE_SUCCESSFUL_ENVIRONMENT: 'CommonBuffId' = 136395 - CAREER_ACTIVIST_CAUSE_SUCCESSFUL_JUSTICE: 'CommonBuffId' = 136397 - CAREER_ACTIVIST_CAUSE_SUCCESSFUL_PEACE: 'CommonBuffId' = 136396 - CAREER_ACTIVIST_CAUSE_SUCCESSFUL_TAX: 'CommonBuffId' = 136394 - CAREER_ACTIVIST_CONVINCED_TO_LEAVE_HIDDEN: 'CommonBuffId' = 142143 - CAREER_ACTIVIST_FLIP_FLOP_POLITICS: 'CommonBuffId' = 136613 - CAREER_ACTIVIST_JOB_PERFORMANCE_LUCKY_BREAK: 'CommonBuffId' = 141450 - CAREER_ACTIVIST_JOB_PERFORMANCE_MISTAKE_MADE: 'CommonBuffId' = 141411 - CAREER_ACTIVIST_JOB_PERFORMANCE_REVEAL_TRUTH: 'CommonBuffId' = 141451 - CAREER_ACTIVIST_POLITICAL_PARTISANS: 'CommonBuffId' = 136615 - CAREER_ACTIVIST_POLITICAL_PARTNERS: 'CommonBuffId' = 136614 - CAREER_ACTIVIST_POLITICIAN_APPROVAL: 'CommonBuffId' = 135696 - CAREER_ACTIVIST_POLITICIAN_APPROVAL_FROM_KISS_BABY: 'CommonBuffId' = 135825 - CAREER_ACTIVIST_POLITICIAN_GAMES: 'CommonBuffId' = 135697 - CAREER_ACTIVIST_PROMPT_CHOOSE_CAUSE: 'CommonBuffId' = 141181 - CAREER_ACTIVIST_PROMPT_CHOOSE_CAUSE_TIMER_HIDDEN: 'CommonBuffId' = 141173 - CAREER_ACTIVIST_PROTESTING_HIDDEN: 'CommonBuffId' = 135895 - CAREER_ACTIVIST_PROTEST_JOINED_OR_WATCHED_HIDDEN: 'CommonBuffId' = 147859 - CAREER_ACTIVIST_QUIT_JOB_HIDDEN: 'CommonBuffId' = 154532 - CAREER_ACTIVIST_UNETHICAL_BRIBE: 'CommonBuffId' = 135868 - CAREER_ACTIVIST_WATCH_PROTEST_COOLDOWN: 'CommonBuffId' = 155609 - CAREER_ADVICE_FAIL: 'CommonBuffId' = 32554 - CAREER_ADVICE_FIXED: 'CommonBuffId' = 32553 - CAREER_AGENCY_HERO: 'CommonBuffId' = 32120 - CAREER_ALIEN_CONTACT: 'CommonBuffId' = 37774 - CAREER_ANGRY_EMPLOYEES: 'CommonBuffId' = 33991 - CAREER_ATHLETE_COMPETITIVE_EDGE: 'CommonBuffId' = 107183 - CAREER_ATHLETE_OVER_AWED_BY_OPPONENTS: 'CommonBuffId' = 107182 - CAREER_ATHLETE_PUMPED: 'CommonBuffId' = 107181 - CAREER_ATHLETE_STATISTICAL_FERVOR: 'CommonBuffId' = 107179 - CAREER_ATHLETE_STATISTICAL_RAGE: 'CommonBuffId' = 107180 - CAREER_ATTENDANCE_CLASSES: 'CommonBuffId' = 34038 - CAREER_A_CAUSE_FOR_APPLAUSE: 'CommonBuffId' = 31364 - CAREER_BAD_MATH: 'CommonBuffId' = 38112 - CAREER_BAG_OF_POO: 'CommonBuffId' = 33024 - CAREER_BLOG_DEBUNKED: 'CommonBuffId' = 32533 - CAREER_BLOG_PLAGIARIST: 'CommonBuffId' = 32549 - CAREER_BLUFFING_BLUNDER: 'CommonBuffId' = 32170 - CAREER_BROWSE_INTELLIGENCE_DB_BORED: 'CommonBuffId' = 34150 - CAREER_BROWSE_INTELLIGENCE_DB_EMBARRASSED: 'CommonBuffId' = 34149 - CAREER_BROWSE_INTELLIGENCE_DB_WORK_PERF: 'CommonBuffId' = 34148 - CAREER_BUSINESS_21_CONFIDENT: 'CommonBuffId' = 108001 - CAREER_BUSINESS_22_HAPPY: 'CommonBuffId' = 108002 - CAREER_BUSINESS_23_CONFIDENT: 'CommonBuffId' = 108003 - CAREER_BUSINESS_27_PASS_THE_BLAME_EVIL: 'CommonBuffId' = 108006 - CAREER_BUSINESS_27_PASS_THE_BLAME_NORMAL: 'CommonBuffId' = 108005 - CAREER_BUSINESS_8_CLOSE_BRANCH_EVIL: 'CommonBuffId' = 107722 - CAREER_BUSINESS_8_CLOSE_BRANCH_NORMAL: 'CommonBuffId' = 107723 - CAREER_BUSINESS_8_CUT_BONUSES_EVIL: 'CommonBuffId' = 107721 - CAREER_BUSINESS_8_CUT_BONUSES_NORMAL: 'CommonBuffId' = 107720 - CAREER_BUSINESS_AGGRAVATED_BY_BLOWHARD: 'CommonBuffId' = 109063 - CAREER_BUSINESS_BLEW_THE_DEAL: 'CommonBuffId' = 108532 - CAREER_BUSINESS_FEELING_IMPORTANT: 'CommonBuffId' = 109061 - CAREER_BUSINESS_HIDDEN_INVESTED: 'CommonBuffId' = 110140 - CAREER_BUSINESS_HIDDEN_INVESTMENT_LOSE_A_BIT_1000: 'CommonBuffId' = 110104 - CAREER_BUSINESS_HIDDEN_INVESTMENT_LOSE_A_BIT_2000: 'CommonBuffId' = 110105 - CAREER_BUSINESS_HIDDEN_INVESTMENT_LOSE_A_BIT_5000: 'CommonBuffId' = 110114 - CAREER_BUSINESS_HIDDEN_INVESTMENT_LOSE_BIG_1000: 'CommonBuffId' = 110115 - CAREER_BUSINESS_HIDDEN_INVESTMENT_LOSE_BIG_2000: 'CommonBuffId' = 110116 - CAREER_BUSINESS_HIDDEN_INVESTMENT_LOSE_BIG_5000: 'CommonBuffId' = 110117 - CAREER_BUSINESS_HIDDEN_INVESTMENT_STAY_EVEN_1000: 'CommonBuffId' = 110118 - CAREER_BUSINESS_HIDDEN_INVESTMENT_STAY_EVEN_2000: 'CommonBuffId' = 110106 - CAREER_BUSINESS_HIDDEN_INVESTMENT_STAY_EVEN_5000: 'CommonBuffId' = 110107 - CAREER_BUSINESS_HIDDEN_INVESTMENT_WIN_A_BIT_1000: 'CommonBuffId' = 110108 - CAREER_BUSINESS_HIDDEN_INVESTMENT_WIN_A_BIT_2000: 'CommonBuffId' = 110109 - CAREER_BUSINESS_HIDDEN_INVESTMENT_WIN_A_BIT_5000: 'CommonBuffId' = 110110 - CAREER_BUSINESS_HIDDEN_INVESTMENT_WIN_BIG_1000: 'CommonBuffId' = 110111 - CAREER_BUSINESS_HIDDEN_INVESTMENT_WIN_BIG_2000: 'CommonBuffId' = 110112 - CAREER_BUSINESS_HIDDEN_INVESTMENT_WIN_BIG_5000: 'CommonBuffId' = 110113 - CAREER_BUSINESS_MADE_THE_SALE: 'CommonBuffId' = 108531 - CAREER_BUSINESS_NUMBERS: 'CommonBuffId' = 108530 - CAREER_BUSINESS_ON_TOP_OF_THE_MARKET: 'CommonBuffId' = 108543 - CAREER_BUSINESS_PAPERWORK_DRUDGERY: 'CommonBuffId' = 108529 - CAREER_BUSINESS_SHOT_DOWN: 'CommonBuffId' = 109062 - CAREER_CALCULATED_OUT: 'CommonBuffId' = 27935 - CAREER_CANT_GET_ME_DOWN: 'CommonBuffId' = 36048 - CAREER_CAPSULE_PLAYFUL: 'CommonBuffId' = 37738 - CAREER_CAPSULE_SICKNESS: 'CommonBuffId' = 28102 - CAREER_CARGO_DUMPED: 'CommonBuffId' = 37767 - CAREER_CAUGHT_GOUGING: 'CommonBuffId' = 100442 - CAREER_CELEBRITY_SLIGHTING: 'CommonBuffId' = 31239 - CAREER_CHEESE_LOVE: 'CommonBuffId' = 28536 - CAREER_CHEWED_OUT: 'CommonBuffId' = 37772 - CAREER_CIVIL_DESIGNER_CONCEPT_GAVE_FEEDBACK: 'CommonBuffId' = 237393 - CAREER_CIVIL_DESIGNER_CONCEPT_SOLID_DESIGNS: 'CommonBuffId' = 237394 - CAREER_CIVIL_DESIGNER_CONCEPT_SUBMIT_FAIL: 'CommonBuffId' = 234319 - CAREER_CIVIL_DESIGNER_CONCEPT_SUBMIT_SUCCESS: 'CommonBuffId' = 234320 - CAREER_CIVIL_DESIGNER_CONCEPT_SUBMIT_TED_ECO_INVENTION: 'CommonBuffId' = 234334 - CAREER_CIVIL_DESIGNER_CONCEPT_SUBMIT_TED_GREAT: 'CommonBuffId' = 234279 - CAREER_CIVIL_DESIGNER_CONCEPT_SUBMIT_TED_OKAY: 'CommonBuffId' = 234270 - CAREER_CIVIL_DESIGNER_CONCEPT_SUBMIT_TED_OUTSTANDING: 'CommonBuffId' = 234289 - CAREER_CIVIL_DESIGNER_CONCEPT_SUBMIT_TED_PERFECT: 'CommonBuffId' = 234290 - CAREER_CIVIL_DESIGNER_CONCEPT_SUBMIT_TED_POOR: 'CommonBuffId' = 234269 - CAREER_CIVIL_DESIGNER_COOLDOWN_RALLY: 'CommonBuffId' = 239193 - CAREER_CIVIL_DESIGNER_INTERVIEW_COOLDOWN_CIVIC_POLICIES: 'CommonBuffId' = 237481 - CAREER_CIVIL_DESIGNER_INTERVIEW_COOLDOWN_UTILITIES: 'CommonBuffId' = 239096 - CAREER_CIVIL_DESIGNER_RALLY_FAILED_TO_RALLY: 'CommonBuffId' = 237395 - CAREER_CIVIL_DESIGNER_SMOG_VACUUM_THERE_GOES_THE_NEIGHBORHOOD: 'CommonBuffId' = 234702 - CAREER_CIVIL_DESIGNER_TRAIT_CHAMPION_OF_THE_PEOPLE: 'CommonBuffId' = 234581 - CAREER_CIVIL_DESIGNER_TRAIT_ECO_ENGINEER: 'CommonBuffId' = 234584 - CAREER_CIVIL_DESIGNER_UNLOCK_FOOD_REWARD_RECIPES: 'CommonBuffId' = 235569 - CAREER_CIVIL_DESIGNER_VOTE_TRACKING_COMMUNITY_SPACE: 'CommonBuffId' = 240332 - CAREER_CIVIL_DESIGNER_VOTE_TRACKING_NEIGHBORHOOD_RENOVATION: 'CommonBuffId' = 240333 - CAREER_CIVIL_DESIGNER_WATCHING_RALLY: 'CommonBuffId' = 233519 - CAREER_CLEAN_VICTORY: 'CommonBuffId' = 31507 - CAREER_CONFRONTED_BY_COWORKER: 'CommonBuffId' = 33986 - CAREER_CONSERVATIONIST_AWAY_ACTIONS_BORED: 'CommonBuffId' = 209830 - CAREER_CONSERVATIONIST_AWAY_ACTIONS_PLAYFUL: 'CommonBuffId' = 209832 - CAREER_CONSERVATIONIST_AWAY_ACTIONS_UNCOMFORTABLE: 'CommonBuffId' = 209833 - CAREER_CONSERVATIONIST_CONSERVATION_AWARENESS_BORING_CONVERSATION: 'CommonBuffId' = 205160 - CAREER_CONSERVATIONIST_CONSERVATION_AWARENESS_CONSERVATION_KNOWLEDGE: 'CommonBuffId' = 205159 - CAREER_CONSERVATIONIST_CONSERVATION_AWARENESS_NOONE_LISTENING: 'CommonBuffId' = 205166 - CAREER_CONSERVATIONIST_CONSERVATION_AWARENESS_SPREADING_AWARENESS: 'CommonBuffId' = 205165 - CAREER_CONSERVATIONIST_CONSULT_REGULATION_COOLDOWN: 'CommonBuffId' = 211688 - CAREER_CONSERVATIONIST_CONSULT_REGULATION_GENERAL_ACCUSED_OF_WRONGDOING: 'CommonBuffId' = 206384 - CAREER_CONSERVATIONIST_CONSULT_REGULATION_LITTERING_ACCUSE_OF_LITTERING_COOLDOWN: 'CommonBuffId' = 212325 - CAREER_CONSERVATIONIST_CONSULT_REGULATION_ORGANIC_PRODUCE_EATING_ORGANIC: 'CommonBuffId' = 209822 - CAREER_CONSERVATIONIST_CONSULT_REGULATION_OVERFISHING_CAUGHT_FISHING_ILLEGALLY: 'CommonBuffId' = 209825 - CAREER_CONSERVATIONIST_CONSULT_REGULATION_OVERFISHING_ENFORCED_POLICY: 'CommonBuffId' = 206307 - CAREER_CONSERVATIONIST_CONSULT_REGULATION_OVERFISHING_FINED_FOR_FISHING: 'CommonBuffId' = 207055 - CAREER_CONSERVATIONIST_CONSULT_REGULATION_OVERFISHING_FISHING_ALLOWED: 'CommonBuffId' = 206308 - CAREER_CONSERVATIONIST_CONSULT_REGULATION_OVERFISHING_STOP_FISHING: 'CommonBuffId' = 206305 - CAREER_CONSERVATIONIST_CONSULT_REGULATION_REGULATION_COMPLETE: 'CommonBuffId' = 206280 - CAREER_CONSERVATIONIST_DISCOVERED_NEW_SPECIES: 'CommonBuffId' = 209924 - CAREER_CONSERVATIONIST_SPRAY_INVASIVE_SPECIES_INVASIVE_SPECIES_EXTERMINATOR: 'CommonBuffId' = 209823 - CAREER_CONSERVATIONIST_SUBMIT_GRANT_APPLICATION_FLUBBED_ATTEMPT: 'CommonBuffId' = 205741 - CAREER_CONSERVATIONIST_TAKE_SAMPLE_COOLDOWN_HIDDEN: 'CommonBuffId' = 210720 - CAREER_CONSERVATIONIST_TRAIT_FRIEND_OF_THE_SEA: 'CommonBuffId' = 207855 - CAREER_CORPORATE_WORKER_BRAIN_FRIED: 'CommonBuffId' = 248612 - CAREER_CORPORATE_WORKER_COMPANY_AMBASSADOR: 'CommonBuffId' = 248610 - CAREER_CORPORATE_WORKER_FAILED_ATTEMPT: 'CommonBuffId' = 248846 - CAREER_CORPORATE_WORKER_FIRED_UP_FOR_SUCCESS: 'CommonBuffId' = 248608 - CAREER_CORPORATE_WORKER_INSPIRATION_AND_PERSPIRATION: 'CommonBuffId' = 248609 - CAREER_CORPORATE_WORKER_JUICED: 'CommonBuffId' = 248845 - CAREER_CORPORATE_WORKER_LUCKY_ESCAPE: 'CommonBuffId' = 253824 - CAREER_CORPORATE_WORKER_ONE_OF_US: 'CommonBuffId' = 248611 - CAREER_CORPORATE_WORKER_OUT_LATE_SHAME: 'CommonBuffId' = 248811 - CAREER_CORPORATE_WORKER_OUT_LATE_TIMER: 'CommonBuffId' = 254397 - CAREER_CORPORATE_WORKER_TRAIT_CHARISMATIC_CROONER: 'CommonBuffId' = 249170 - CAREER_CORPORATE_WORKER_TRAIT_LEGENDARY_STAMINA: 'CommonBuffId' = 249175 - CAREER_CORPORATE_WORKER_UNLOCK_AMAZAKE: 'CommonBuffId' = 248994 - CAREER_CORPORATE_WORKER_UNLOCK_CHICKEN_YAKITORI: 'CommonBuffId' = 249015 - CAREER_CORPORATE_WORKER_UNLOCK_ENERGY_CRUSH: 'CommonBuffId' = 249014 - CAREER_CORPORATE_WORKER_WORKING_OVERTIME: 'CommonBuffId' = 248802 - CAREER_COUNTER_OPINION_DEBATE: 'CommonBuffId' = 33835 - CAREER_COUNTER_OPINION_DISMISSED: 'CommonBuffId' = 33833 - CAREER_CREATIVELY_DRAINED: 'CommonBuffId' = 31224 - CAREER_CRIMINAL_BANK_BLUEPRINT_INSIDE_SCOOP: 'CommonBuffId' = 33953 - CAREER_CRIMINAL_HACK_MAINFRAME_PATCHED_IN: 'CommonBuffId' = 33971 - CAREER_CRITIC_ENTHUSIASTIC_ABOUT_FOOD: 'CommonBuffId' = 137456 - CAREER_CRITIC_ENTHUSIASTIC_ABOUT_FOOD_HIDDEN: 'CommonBuffId' = 137468 - CAREER_CRITIC_HAS_BEEN_TO_FESTIVAL: 'CommonBuffId' = 138309 - CAREER_CRITIC_INSPIRED_GAIN_COOLDOWN: 'CommonBuffId' = 137763 - CAREER_CRITIC_PRAISED: 'CommonBuffId' = 139910 - CAREER_CRITIC_REVIEWED_BAD_DRINK: 'CommonBuffId' = 153063 - CAREER_CRITIC_REVIEWED_BAD_FOOD: 'CommonBuffId' = 137799 - CAREER_CRITIC_REVIEWED_BAD_PERFORMANCE: 'CommonBuffId' = 137907 - CAREER_CRITIC_REVIEWED_GOOD_DRINK: 'CommonBuffId' = 153062 - CAREER_CRITIC_REVIEWED_GOOD_FOOD: 'CommonBuffId' = 137798 - CAREER_CRITIC_REVIEWED_GOOD_PERFORMANCE: 'CommonBuffId' = 137908 - CAREER_CRITIC_REVIEWING_FOOD: 'CommonBuffId' = 137795 - CAREER_CRITIC_SNUBBED: 'CommonBuffId' = 137649 - CAREER_CRITIC_STUDIED_ART: 'CommonBuffId' = 137722 - CAREER_CRITIC_THAT_FOOD_MUST_BE_AWFUL: 'CommonBuffId' = 137560 - CAREER_CRITIC_WRITE_COLUMN_BOOST: 'CommonBuffId' = 152336 - CAREER_DAILY_TASK_COMPLETE_HIDDEN: 'CommonBuffId' = 288788 - CAREER_DEBRIS_COVERED_PATROLLER: 'CommonBuffId' = 37787 - CAREER_DECIMAL_FIXED: 'CommonBuffId' = 33089 - CAREER_DETECTIVE_APB_SUSPECT: 'CommonBuffId' = 111874 - CAREER_DETECTIVE_CAN_GET_CITATION: 'CommonBuffId' = 109484 - CAREER_DETECTIVE_CRACKING_THE_CASE: 'CommonBuffId' = 116203 - CAREER_DETECTIVE_DAY02_ALLOW_APB: 'CommonBuffId' = 116738 - CAREER_DETECTIVE_DUNCE_DUCTION: 'CommonBuffId' = 116206 - CAREER_DETECTIVE_FINISHED_INTERROGATION: 'CommonBuffId' = 113758 - CAREER_DETECTIVE_INTERROGATING_GUILTY_SUSPECT: 'CommonBuffId' = 113855 - CAREER_DETECTIVE_INTERROGATING_INNOCENT_SUSPECT: 'CommonBuffId' = 113854 - CAREER_DETECTIVE_NPC_REPORT_TAKEN: 'CommonBuffId' = 114579 - CAREER_DETECTIVE_ROLE_STATIC_COMMODITY_BUFFS_POLICE_STATION_CHIEF: 'CommonBuffId' = 116694 - CAREER_DETECTIVE_ROLE_STATIC_COMMODITY_BUFFS_POLICE_STATION_CIVILIAN: 'CommonBuffId' = 116347 - CAREER_DETECTIVE_ROLE_STATIC_COMMODITY_BUFFS_POLICE_STATION_LAB_TECH: 'CommonBuffId' = 115815 - CAREER_DETECTIVE_ROLE_STATIC_COMMODITY_BUFFS_POLICE_STATION_RECEPTIONIST: 'CommonBuffId' = 114826 - CAREER_DETECTIVE_SOLVED_CASE_RECENTLY: 'CommonBuffId' = 113109 - CAREER_DETECTIVE_UNCOMFORTABLE_SEARCH: 'CommonBuffId' = 110639 - CAREER_DETECTIVE_USED_CHEMICAL_ANALYZER: 'CommonBuffId' = 112552 - CAREER_DETECTIVE_WENT_TO_CRIME_SCENE: 'CommonBuffId' = 112551 - CAREER_DIABOLIC_PRESENTER: 'CommonBuffId' = 32367 - CAREER_DISAPPOINTING_ENCOUNTER: 'CommonBuffId' = 31377 - CAREER_DONATE_EARLY_WORK_ACCEPTED: 'CommonBuffId' = 34014 - CAREER_DONATE_EARLY_WORK_REJECTED: 'CommonBuffId' = 34016 - CAREER_DONATE_RECENT_WORK: 'CommonBuffId' = 34015 - CAREER_DOUBLE_ARREST: 'CommonBuffId' = 37828 - CAREER_DREADFUL_DISPLAY: 'CommonBuffId' = 32371 - CAREER_DREW_A_BLANK: 'CommonBuffId' = 31412 - CAREER_EARNED_PROMOTION: 'CommonBuffId' = 125702 - CAREER_EDGY_PIECE_ACCEPTED: 'CommonBuffId' = 33830 - CAREER_EDGY_PIECE_REJECTED: 'CommonBuffId' = 33831 - CAREER_EDIT_PAINTING_BETTER: 'CommonBuffId' = 33843 - CAREER_EDIT_PAINTING_WORSE: 'CommonBuffId' = 33845 - CAREER_EDUCATION_DONATION_ASK_COOLDOWN: 'CommonBuffId' = 221061 - CAREER_EDUCATION_FINISHED_TUTORING: 'CommonBuffId' = 220221 - CAREER_EDUCATION_VISIBLE_ALL_PLANNED_OUT: 'CommonBuffId' = 220294 - CAREER_EDUCATION_VISIBLE_BUDGETED: 'CommonBuffId' = 220295 - CAREER_EDUCATION_VISIBLE_EVERYTHINGS_ADDING_UP: 'CommonBuffId' = 220292 - CAREER_EDUCATION_VISIBLE_FEELING_PREPARED: 'CommonBuffId' = 220302 - CAREER_EDUCATION_VISIBLE_MADE_THE_GRADE: 'CommonBuffId' = 224612 - CAREER_EDUCATION_VISIBLE_MANY_HANDS: 'CommonBuffId' = 220994 - CAREER_EDUCATION_VISIBLE_PREPARED_TO_TEACH: 'CommonBuffId' = 220290 - CAREER_EDUCATION_VISIBLE_TEACHEM: 'CommonBuffId' = 227628 - CAREER_EDUCATION_VOLUNTEER_ASK_COOLDOWN: 'CommonBuffId' = 221062 - CAREER_EMPTY_HANDED: 'CommonBuffId' = 37809 - CAREER_ENGINEER_COMPUTER_DESIGNER: 'CommonBuffId' = 221157 - CAREER_ENGINEER_ENGINEERING_EDUCATION: 'CommonBuffId' = 221158 - CAREER_ENGINEER_EXHILARATED_ENGINEER: 'CommonBuffId' = 228427 - CAREER_ENGINEER_FOCUS_TESTED: 'CommonBuffId' = 221155 - CAREER_ENGINEER_OBJECT_REWARD_1: 'CommonBuffId' = 221170 - CAREER_ENGINEER_OBJECT_REWARD_2: 'CommonBuffId' = 221184 - CAREER_ENGINEER_TECH_TINKERER: 'CommonBuffId' = 222424 - CAREER_ENGINEER_TRIPLE_CHECKED: 'CommonBuffId' = 221163 - CAREER_ENTERTAINER_SOME_INSPIRATION: 'CommonBuffId' = 35995 - CAREER_EXAMINE_FAILED: 'CommonBuffId' = 37747 - CAREER_EXCELLENT_XXULYPS: 'CommonBuffId' = 37781 - CAREER_EXOTIC_JUICE_SUCCESS: 'CommonBuffId' = 33496 - CAREER_EXPERIMENTAL_ACCEPTED: 'CommonBuffId' = 34010 - CAREER_EXPERIMENTAL_REJECTED: 'CommonBuffId' = 34009 - CAREER_E_SPORTS_ASSEMBLE_THE_TEAM_COOLDOWN: 'CommonBuffId' = 227369 - CAREER_E_SPORTS_MATCH_SOON: 'CommonBuffId' = 227179 - CAREER_E_SPORTS_NOT_ENROLLED: 'CommonBuffId' = 230302 - CAREER_E_SPORTS_PLAYED_WITH_TEAM: 'CommonBuffId' = 226931 - CAREER_E_SPORTS_RECIEVED_DRAMA_NODE_FRI: 'CommonBuffId' = 228246 - CAREER_E_SPORTS_RECIEVED_DRAMA_NODE_SAT: 'CommonBuffId' = 228248 - CAREER_E_SPORTS_TEAMMATE_AUTONOMY: 'CommonBuffId' = 227364 - CAREER_E_SPORTS_VISIBLE_ALWAYS_NEXT_TIME: 'CommonBuffId' = 226601 - CAREER_E_SPORTS_VISIBLE_E_LEGEND: 'CommonBuffId' = 226606 - CAREER_E_SPORTS_VISIBLE_E_SUCCESS: 'CommonBuffId' = 226604 - CAREER_E_SPORTS_VISIBLE_E_VICTORY: 'CommonBuffId' = 226605 - CAREER_E_SPORTS_VISIBLE_POWER_DIPPING: 'CommonBuffId' = 226607 - CAREER_E_SPORTS_VISIBLE_POWER_SIPPING: 'CommonBuffId' = 226596 - CAREER_E_SPORTS_VISIBLE_POWER_SIPPING_INFERNO: 'CommonBuffId' = 226599 - CAREER_E_SPORTS_VISIBLE_POWER_SITTING: 'CommonBuffId' = 226597 - CAREER_E_SPORTS_VISIBLE_READY_TO_SCUFFLE: 'CommonBuffId' = 226598 - CAREER_E_SPORTS_VISIBLE_TEAM_PLAYER: 'CommonBuffId' = 226595 - CAREER_FAN_KICK_OUT_FAILURE: 'CommonBuffId' = 33477 - CAREER_FAN_KICK_OUT_SUCCESS: 'CommonBuffId' = 33478 - CAREER_FIRED: 'CommonBuffId' = 97449 - CAREER_FIRED_AMBITIOUS: 'CommonBuffId' = 97450 - CAREER_FIRED_INTERIOR_DECORATOR_INTERVIEW_BY_ENEMY: 'CommonBuffId' = 257719 - CAREER_FISHERMAN_AWAY_ACTIONS_HAPPY: 'CommonBuffId' = 210267 - CAREER_FISHERMAN_AWAY_ACTIONS_TENSE: 'CommonBuffId' = 211689 - CAREER_FORMULA_DISCOVERY: 'CommonBuffId' = 37735 - CAREER_FORTUNATE_OUTCOME: 'CommonBuffId' = 37786 - CAREER_FORUM_ENCRYPTED: 'CommonBuffId' = 33078 - CAREER_FORUM_POST_PICS: 'CommonBuffId' = 33077 - CAREER_FREELANCER_ARTIST_STELLAR_STUDENTS: 'CommonBuffId' = 208709 - CAREER_FREELANCER_ARTIST_UNRULY_CLASS: 'CommonBuffId' = 208708 - CAREER_FREELANCER_CLEAR_GOALS: 'CommonBuffId' = 208706 - CAREER_FREELANCER_GREAT_SESSION: 'CommonBuffId' = 208239 - CAREER_FREELANCER_HIDDEN_MET_WITH_CLIENT_CLASS: 'CommonBuffId' = 211962 - CAREER_FREELANCER_INSTRUCTIONS_UNCLEAR: 'CommonBuffId' = 208705 - CAREER_FREELANCER_OVERCLOCKED_PC: 'CommonBuffId' = 208696 - CAREER_FREELANCER_PROGRAMMER_RUDE_CLIENT: 'CommonBuffId' = 208228 - CAREER_FREELANCER_PROGRAMMER_SHARED_VISION: 'CommonBuffId' = 208229 - CAREER_FREELANCER_TERRIBLE_SESSION: 'CommonBuffId' = 208238 - CAREER_GARDENER_ACADEMIC_FAME_HAPPY: 'CommonBuffId' = 187041 - CAREER_GARDENER_BACK_TO_ROOTS_HAPPY: 'CommonBuffId' = 187038 - CAREER_GARDENER_DESIGN_CLASS_INSPIRED: 'CommonBuffId' = 187044 - CAREER_GARDENER_FLORAL_FIGHT_ANGRY: 'CommonBuffId' = 191624 - CAREER_GARDENER_FLORIST_CLIENTELE_FOCUSED: 'CommonBuffId' = 187040 - CAREER_GARDENER_HANDS_ON_APPROACH_ENERGIZED: 'CommonBuffId' = 187043 - CAREER_GARDENER_NATURE_WALK_ENERGIZED: 'CommonBuffId' = 187039 - CAREER_GARDENER_POOR_PROPOSAL_EMBARRASSED: 'CommonBuffId' = 187042 - CAREER_GARDENER_READ_ANGRY_LOW: 'CommonBuffId' = 191191 - CAREER_GARDENER_WRITING_PRAISED: 'CommonBuffId' = 191192 - CAREER_GLORZAK_BUST: 'CommonBuffId' = 37776 - CAREER_GOOD_INSTINCTS: 'CommonBuffId' = 37770 - CAREER_GOT_NEW_JOB: 'CommonBuffId' = 125723 - CAREER_GUARD_CLOSE_CALL: 'CommonBuffId' = 33043 - CAREER_GUARD_KO: 'CommonBuffId' = 33042 - CAREER_GUARD_SPOTTED: 'CommonBuffId' = 33045 - CAREER_HANDY_PERSON_ATTEND_LOCAL_ISSUE_COOLDOWN_HIDDEN: 'CommonBuffId' = 354675 - CAREER_HANDY_PERSON_BAD_COMPLAIN: 'CommonBuffId' = 353754 - CAREER_HANDY_PERSON_BODGE_JOB: 'CommonBuffId' = 353753 - CAREER_HANDY_PERSON_CLOSE_CALL: 'CommonBuffId' = 354269 - CAREER_HANDY_PERSON_CLOSE_ONE: 'CommonBuffId' = 354262 - CAREER_HANDY_PERSON_COMPLAIN_DONE_HIDDEN: 'CommonBuffId' = 354270 - CAREER_HANDY_PERSON_COMPLAIN_READY_HIDDEN: 'CommonBuffId' = 354261 - CAREER_HANDY_PERSON_DISHONEST: 'CommonBuffId' = 354265 - CAREER_HANDY_PERSON_HANDY_INJURY: 'CommonBuffId' = 354264 - CAREER_HANDY_PERSON_HAPPY_RESIDENT: 'CommonBuffId' = 353752 - CAREER_HANDY_PERSON_HONEST: 'CommonBuffId' = 354263 - CAREER_HANDY_PERSON_MASTER_HANDER: 'CommonBuffId' = 354268 - CAREER_HANDY_PERSON_NOT_SO_ACCURATE: 'CommonBuffId' = 354267 - CAREER_HANDY_PERSON_RESEARCH_REPAIR: 'CommonBuffId' = 353751 - CAREER_HANDY_PERSON_TRAINED_HANDY: 'CommonBuffId' = 354266 - CAREER_HARSH_REVIEW_ACCEPTED: 'CommonBuffId' = 34030 - CAREER_HARSH_REVIEW_REJECTED: 'CommonBuffId' = 34032 - CAREER_HECKLED_ON_STAGE: 'CommonBuffId' = 31189 - CAREER_HEIST_NEWBIE_SLEEPS: 'CommonBuffId' = 33063 - CAREER_HEIST_NOT_ENOUGH_SIMS: 'CommonBuffId' = 33067 - CAREER_HEIST_SUCCESS: 'CommonBuffId' = 33065 - CAREER_HIGH_SCHOOL_EXPELLED: 'CommonBuffId' = 298687 - CAREER_HIGH_SCHOOL_TEAM_BIG_WIN: 'CommonBuffId' = 277198 - CAREER_HIGH_SCHOOL_TEAM_HYPED: 'CommonBuffId' = 277196 - CAREER_HIGH_SCHOOL_TEAM_MAJOR_LOSS: 'CommonBuffId' = 277197 - CAREER_HIGH_STAKES_FAILURE: 'CommonBuffId' = 37755 - CAREER_HIGH_STAKES_SUCCESS: 'CommonBuffId' = 37752 - CAREER_HOW_IS_IT: 'CommonBuffId' = 37799 - CAREER_IDEA_THIEF: 'CommonBuffId' = 32555 - CAREER_IMPRESSIVE_INTERROGATION: 'CommonBuffId' = 32165 - CAREER_IMPRESSIVE_ROUTINE: 'CommonBuffId' = 31407 - CAREER_INFORMATION_FREE: 'CommonBuffId' = 33079 - CAREER_INFORMATION_SECURE: 'CommonBuffId' = 33080 - CAREER_INKED_BY_SPACE_SQUID: 'CommonBuffId' = 28112 - CAREER_INTERIOR_DECORATOR_BAD_BEHAVIOR_TRACKER: 'CommonBuffId' = 257432 - CAREER_INTERIOR_DECORATOR_COMMERICAL_GIG_COMPLETE: 'CommonBuffId' = 267264 - CAREER_INTERIOR_DECORATOR_FOLLOW_UP_CLIENT_CALL_DO_SOMETHING_DEBUG: 'CommonBuffId' = 261306 - CAREER_INTERIOR_DECORATOR_FOLLOW_UP_CLIENT_CALL_NOTE_LETTER_PENDING: 'CommonBuffId' = 255193 - CAREER_INTERIOR_DECORATOR_FOLLOW_UP_CLIENT_CALL_NOTE_RECENT_CALL_OR_LETTER: 'CommonBuffId' = 269324 - CAREER_INTERIOR_DECORATOR_FOLLOW_UP_COMMERCIAL_VENUE: 'CommonBuffId' = 255194 - CAREER_INTERIOR_DECORATOR_FOLLOW_UP_COMMERCIAL_VENUE_NEGATIVE: 'CommonBuffId' = 258311 - CAREER_INTERIOR_DECORATOR_FOLLOW_UP_COMMERCIAL_VENUE_POSITIVE: 'CommonBuffId' = 255195 - CAREER_INTERIOR_DECORATOR_FOLLOW_UP_SPONSORSHIP_COOLDOWN: 'CommonBuffId' = 258049 - CAREER_INTERIOR_DECORATOR_FOLLOW_UP_SPONSORSHIP_PACKAGE_PENDING: 'CommonBuffId' = 257995 - CAREER_INTERIOR_DECORATOR_FOLLOW_UP_TV_COOLDOWN: 'CommonBuffId' = 258075 - CAREER_INTERIOR_DECORATOR_FOLLOW_UP_TV_EXIT_TO_WATCH_SHOW: 'CommonBuffId' = 259498 - CAREER_INTERIOR_DECORATOR_FOLLOW_UP_TV_HOME_DECORATING_CHANNEL_NEGATIVE: 'CommonBuffId' = 258500 - CAREER_INTERIOR_DECORATOR_FOLLOW_UP_TV_HOME_DECORATING_CHANNEL_POSITIVE: 'CommonBuffId' = 258499 - CAREER_INTERIOR_DECORATOR_FOLLOW_UP_TV_TO_BE_FEATURED_NEGATIVE: 'CommonBuffId' = 258341 - CAREER_INTERIOR_DECORATOR_FOLLOW_UP_TV_TO_BE_FEATURED_POSITIVE: 'CommonBuffId' = 258051 - CAREER_INTERIOR_DECORATOR_FOLLOW_UP_TV_WAS_NOTIFIED: 'CommonBuffId' = 259632 - CAREER_INTERIOR_DECORATOR_GIG_COMPLETE: 'CommonBuffId' = 267263 - CAREER_INTERIOR_DECORATOR_HIDE_CLIENTS: 'CommonBuffId' = 263614 - CAREER_INTERIOR_DECORATOR_HIDE_CLIENTS_ROLE: 'CommonBuffId' = 261335 - CAREER_INTERIOR_DECORATOR_HIDE_CLIENTS_SITUATION: 'CommonBuffId' = 261867 - CAREER_INTERIOR_DECORATOR_HIDE_CLIENTS_SITUATION_NO_HOUSEHOLD: 'CommonBuffId' = 264520 - CAREER_INTERIOR_DECORATOR_INTERVIEW_BAD_BEHAVIOR_FIRE_ME: 'CommonBuffId' = 257376 - CAREER_INTERIOR_DECORATOR_INTERVIEW_GIG_CANCELLED: 'CommonBuffId' = 257713 - CAREER_INTERIOR_DECORATOR_INTERVIEW_LEARNED_INFO_1: 'CommonBuffId' = 260037 - CAREER_INTERIOR_DECORATOR_INTERVIEW_LEARNED_INFO_2: 'CommonBuffId' = 260038 - CAREER_INTERIOR_DECORATOR_INTERVIEW_LEARNED_INFO_GUARANTEED_SUCCESS_COOLDOWN: 'CommonBuffId' = 265106 - CAREER_INTERIOR_DECORATOR_INTERVIEW_ROLE_CLIENT: 'CommonBuffId' = 256879 - CAREER_INTERIOR_DECORATOR_INTERVIEW_ROLE_HOST: 'CommonBuffId' = 256878 - CAREER_INTERIOR_DECORATOR_REVEAL_CLIENT_MOOD_ANGRY: 'CommonBuffId' = 262902 - CAREER_INTERIOR_DECORATOR_REVEAL_CLIENT_MOOD_DEFAULT: 'CommonBuffId' = 262906 - CAREER_INTERIOR_DECORATOR_REVEAL_CLIENT_MOOD_HAPPY: 'CommonBuffId' = 262904 - CAREER_INTERIOR_DECORATOR_REVEAL_CLIENT_MOOD_SAD: 'CommonBuffId' = 262903 - CAREER_INTERIOR_DECORATOR_REVEAL_CLIENT_MOOD_VERY_HAPPY: 'CommonBuffId' = 262905 - CAREER_INTERIOR_DECORATOR_REVEAL_CLIENT_SHARED_FINAL_VERDICT_FALSE: 'CommonBuffId' = 268877 - CAREER_INTERIOR_DECORATOR_REVEAL_CLIENT_SHARED_FINAL_VERDICT_TRUE: 'CommonBuffId' = 258876 - CAREER_INTERIOR_DECORATOR_REVEAL_CLIENT_SOCIAL_COOLDOWN: 'CommonBuffId' = 259940 - CAREER_INTERIOR_DECORATOR_REVEAL_FINAL_VERDICT_GOAL_COMPLETE: 'CommonBuffId' = 265023 - CAREER_INTERIOR_DECORATOR_REVEAL_FINISHED: 'CommonBuffId' = 263755 - CAREER_INTERIOR_DECORATOR_REVEAL_GIG_SCORE_BIG_FAILURE: 'CommonBuffId' = 267060 - CAREER_INTERIOR_DECORATOR_REVEAL_GIG_SCORE_BIG_SUCCESS: 'CommonBuffId' = 267061 - CAREER_INTERIOR_DECORATOR_REVEAL_GIG_SCORE_FAILURE: 'CommonBuffId' = 267063 - CAREER_INTERIOR_DECORATOR_REVEAL_GIG_SCORE_SUCCESS: 'CommonBuffId' = 267062 - CAREER_INTERIOR_DECORATOR_REVEAL_JUST_KICKED_OUT: 'CommonBuffId' = 268874 - CAREER_INTERIOR_DECORATOR_REVEAL_PUSH_KICK_OFF_DELAYED: 'CommonBuffId' = 269286 - CAREER_INTERIOR_DECORATOR_REVEAL_READING_THE_ROOM_NEGATIVE_1: 'CommonBuffId' = 258583 - CAREER_INTERIOR_DECORATOR_REVEAL_READING_THE_ROOM_NEGATIVE_2: 'CommonBuffId' = 258584 - CAREER_INTERIOR_DECORATOR_REVEAL_READING_THE_ROOM_NEUTRAL: 'CommonBuffId' = 269245 - CAREER_INTERIOR_DECORATOR_REVEAL_READING_THE_ROOM_POSITIVE_1: 'CommonBuffId' = 258581 - CAREER_INTERIOR_DECORATOR_REVEAL_READING_THE_ROOM_POSITIVE_2: 'CommonBuffId' = 258582 - CAREER_INTERIOR_DECORATOR_REVEAL_ROLE_CLIENT_EXPLORE: 'CommonBuffId' = 257626 - CAREER_INTERIOR_DECORATOR_REVEAL_ROLE_CLIENT_EXPLORE_FINAL_REACTION: 'CommonBuffId' = 258676 - CAREER_INTERIOR_DECORATOR_REVEAL_ROLE_CLIENT_EXPLORE_NORMAL: 'CommonBuffId' = 258677 - CAREER_INTERIOR_DECORATOR_REVEAL_ROLE_CLIENT_ROUTE: 'CommonBuffId' = 263301 - CAREER_INTERIOR_DECORATOR_REVEAL_ROLE_CLIENT_WAIT: 'CommonBuffId' = 258911 - CAREER_INTERIOR_DECORATOR_REVEAL_ROLE_HOST_EXPLORE: 'CommonBuffId' = 258852 - CAREER_INTERIOR_DECORATOR_REVEAL_ROLE_HOST_GET_IN_GROUP: 'CommonBuffId' = 267870 - CAREER_INTERIOR_DECORATOR_REVEAL_ROLE_HOST_WAIT: 'CommonBuffId' = 267105 - CAREER_INTERIOR_DECORATOR_REVEAL_ROLE_NON_MEMBER: 'CommonBuffId' = 267774 - CAREER_INTERIOR_DECORATOR_REWARDS_REPUTATION_GAIN: 'CommonBuffId' = 267357 - CAREER_INVESTIGATIVE_FAILURE: 'CommonBuffId' = 32559 - CAREER_INVESTIGATIVE_PRO: 'CommonBuffId' = 32558 - CAREER_JUICE_LOVED_BY_ALL: 'CommonBuffId' = 33484 - CAREER_JUICE_SUPPORTED: 'CommonBuffId' = 33488 - CAREER_LAUNCH_CANCELED: 'CommonBuffId' = 28106 - CAREER_LAUNCH_SUCCESSFUL: 'CommonBuffId' = 28108 - CAREER_LEAF_ON_THE_WIND: 'CommonBuffId' = 37741 - CAREER_LIFEGUARD_AWAY_ACTIONS_CONFIDENT: 'CommonBuffId' = 210254 - CAREER_LIFEGUARD_AWAY_ACTIONS_TENSE: 'CommonBuffId' = 210257 - CAREER_LIFEGUARD_FLEX_CONFIDENT: 'CommonBuffId' = 212597 - CAREER_LIFEGUARD_STAND_WATCH_FOCUSED: 'CommonBuffId' = 212598 - CAREER_LOST_GAMER_CRED: 'CommonBuffId' = 34166 - CAREER_LOST_PROFITS: 'CommonBuffId' = 100441 - CAREER_MAD_GAMER_CRED: 'CommonBuffId' = 34169 - CAREER_MILITARY_ORDERED_TO_CLEAN: 'CommonBuffId' = 204179 - CAREER_MISSED_OPPORTUNITY: 'CommonBuffId' = 37811 - CAREER_MOON_ROCK: 'CommonBuffId' = 37929 - CAREER_MOVIE_BOMB: 'CommonBuffId' = 32556 - CAREER_MOVIE_VISION: 'CommonBuffId' = 32557 - CAREER_MOVING_UP: 'CommonBuffId' = 36045 - CAREER_MUSICAL_MASTER: 'CommonBuffId' = 31373 - CAREER_NOT_PROMOTED_RECENTLY: 'CommonBuffId' = 217058 - CAREER_NOT_SO_SMOOTH_MOVE: 'CommonBuffId' = 32307 - CAREER_OUT_OF_PRACTICE: 'CommonBuffId' = 32290 - CAREER_PAINTER_RESEARCH_ART_REF_FAIL: 'CommonBuffId' = 34065 - CAREER_PAINTER_RESEARCH_ART_REF_SUCCESS: 'CommonBuffId' = 34046 - CAREER_PATROLMEN_LAUGHING: 'CommonBuffId' = 37801 - CAREER_PATROL_FALLOUT: 'CommonBuffId' = 37778 - CAREER_PERSUASIVE: 'CommonBuffId' = 33993 - CAREER_PICK_POCKET_SUCCESS: 'CommonBuffId' = 98522 - CAREER_PLAYED_HOOKY: 'CommonBuffId' = 30731 - CAREER_POLITICAL_PARIAH: 'CommonBuffId' = 32567 - CAREER_POLITICAL_TRUTH_SAYER: 'CommonBuffId' = 32563 - CAREER_POOR_PERFORMANCE: 'CommonBuffId' = 77832 - CAREER_PRACTICE_MAKES_PERFECT: 'CommonBuffId' = 31221 - CAREER_PREGNANT_SPOUSE_HIDDEN: 'CommonBuffId' = 111037 - CAREER_PROMOTED_RECENTLY: 'CommonBuffId' = 113108 - CAREER_PROMOTION_AMBITIOUS: 'CommonBuffId' = 36047 - CAREER_PROMOTION_TIMER: 'CommonBuffId' = 217059 - CAREER_PROTEST_FAILURE: 'CommonBuffId' = 154313 - CAREER_PROTEST_SUCCESS: 'CommonBuffId' = 154311 - CAREER_REALLY_BUGGED: 'CommonBuffId' = 33967 - CAREER_REGRETTABLE_INACTION: 'CommonBuffId' = 37783 - CAREER_REJECTED_REPLACED: 'CommonBuffId' = 33799 - CAREER_RESPECTED_GAMER: 'CommonBuffId' = 34017 - CAREER_RETHINKING_OPTIONS: 'CommonBuffId' = 36046 - CAREER_ROMANCE_CONSULTANT_BAD_CALL: 'CommonBuffId' = 366984 - CAREER_ROMANCE_CONSULTANT_EYE_FOR_LOVE: 'CommonBuffId' = 366954 - CAREER_ROMANCE_CONSULTANT_HAPPY_COUPLE: 'CommonBuffId' = 366957 - CAREER_ROMANCE_CONSULTANT_HEART_TO_HEART_TRAIT: 'CommonBuffId' = 368495 - CAREER_ROMANCE_CONSULTANT_JUST_LISTEN: 'CommonBuffId' = 366958 - CAREER_ROMANCE_CONSULTANT_LOVE_BUZZ: 'CommonBuffId' = 366959 - CAREER_ROMANCE_CONSULTANT_LOVE_IS_DEAD: 'CommonBuffId' = 366956 - CAREER_ROMANCE_CONSULTANT_LOVE_IS_FLEETING: 'CommonBuffId' = 366953 - CAREER_ROMANCE_CONSULTANT_LOVE_IS_IN_THE_AIR: 'CommonBuffId' = 366952 - CAREER_ROMANCE_CONSULTANT_MATCHMAKING_FAILURE: 'CommonBuffId' = 366955 - CAREER_ROMANCE_CONSULTANT_NEW_POINT_OF_VIEW: 'CommonBuffId' = 366951 - CAREER_ROMANCE_CONSULTANT_RELATIONSHIP_SATISFACTION_TIPS_DECREASE_HIDDEN: 'CommonBuffId' = 370013 - CAREER_ROMANCE_CONSULTANT_RELATIONSHIP_SATISFACTION_TIPS_INCREASE_HIDDEN: 'CommonBuffId' = 370012 - CAREER_ROMANCE_CONSULTANT_SUCCESSFUL_THERAPY: 'CommonBuffId' = 366983 - CAREER_ROMANCE_CONSULTANT_SYMPATHY_FOR_SADNESS: 'CommonBuffId' = 366982 - CAREER_ROMANCE_CONSULTANT_WONDERFUL_SIGHT: 'CommonBuffId' = 366985 - CAREER_SAFE_CODES_OBTAINED: 'CommonBuffId' = 33053 - CAREER_SAFE_DRILL_FAILURE: 'CommonBuffId' = 33052 - CAREER_SAFE_DRILL_SUCCESS: 'CommonBuffId' = 33050 - CAREER_SCHOOL_DAY_ANGRY: 'CommonBuffId' = 34880 - CAREER_SCHOOL_DAY_BORED: 'CommonBuffId' = 34881 - CAREER_SCHOOL_DAY_CONFIDENT: 'CommonBuffId' = 34885 - CAREER_SCHOOL_DAY_EMBARRASSED: 'CommonBuffId' = 34882 - CAREER_SCHOOL_DAY_ENERGIZED: 'CommonBuffId' = 34886 - CAREER_SCHOOL_DAY_FLIRTY: 'CommonBuffId' = 34887 - CAREER_SCHOOL_DAY_FOCUSED: 'CommonBuffId' = 34888 - CAREER_SCHOOL_DAY_HAPPY: 'CommonBuffId' = 34889 - CAREER_SCHOOL_DAY_INSPIRED: 'CommonBuffId' = 34890 - CAREER_SCHOOL_DAY_PLAYFUL: 'CommonBuffId' = 34891 - CAREER_SCHOOL_DAY_SAD: 'CommonBuffId' = 34883 - CAREER_SCHOOL_DAY_STRESSED: 'CommonBuffId' = 34884 - CAREER_SCHOOL_GOOD_GRADES: 'CommonBuffId' = 100332 - CAREER_SCIENTIST_ALIEN_WORLD_START_GIVE_PORTAL: 'CommonBuffId' = 116475 - CAREER_SCIENTIST_BREAKTHROUGH_BUFF: 'CommonBuffId' = 109414 - CAREER_SCIENTIST_BREAKTHROUGH_MULTI_STAGE0: 'CommonBuffId' = 114447 - CAREER_SCIENTIST_BREAKTHROUGH_MULTI_STAGE1: 'CommonBuffId' = 114448 - CAREER_SCIENTIST_BREAKTHROUGH_MULTI_STAGE2: 'CommonBuffId' = 115570 - CAREER_SCIENTIST_BREAKTHROUGH_MULTI_STAGE3: 'CommonBuffId' = 114449 - CAREER_SCIENTIST_BREAKTHROUGH_MULTI_STAGE4: 'CommonBuffId' = 114450 - CAREER_SCIENTIST_BREAKTHROUGH_MULTI_STAGE5: 'CommonBuffId' = 114451 - CAREER_SCIENTIST_BREAKTHROUGH_MULTI_STAGE6: 'CommonBuffId' = 114452 - CAREER_SCIENTIST_BREAKTHROUGH_RECENTLY: 'CommonBuffId' = 113501 - CAREER_SCIENTIST_EXPERT_REPAIR: 'CommonBuffId' = 109673 - CAREER_SCIENTIST_ORDER_COWORKERS_ALIENS: 'CommonBuffId' = 113651 - CAREER_SCIENTIST_ORDER_COWORKERS_CRYSTALS: 'CommonBuffId' = 113646 - CAREER_SCIENTIST_ORDER_COWORKERS_EXPERIMENT: 'CommonBuffId' = 113648 - CAREER_SCIENTIST_ORDER_COWORKERS_FLORA: 'CommonBuffId' = 113647 - CAREER_SCIENTIST_ORDER_COWORKERS_GARDEN: 'CommonBuffId' = 113466 - CAREER_SCIENTIST_ORDER_COWORKERS_INVENT: 'CommonBuffId' = 113649 - CAREER_SCIENTIST_ORDER_COWORKERS_METALS: 'CommonBuffId' = 113629 - CAREER_SCIENTIST_ORDER_COWORKERS_ROCKET: 'CommonBuffId' = 113650 - CAREER_SCOUTING_CONFIDENT: 'CommonBuffId' = 188459 - CAREER_SCOUTING_EMBARRASSED: 'CommonBuffId' = 188457 - CAREER_SCOUTING_ENERGIZED: 'CommonBuffId' = 188461 - CAREER_SCOUTING_HAPPY: 'CommonBuffId' = 188436 - CAREER_SCOUTING_IS_WALK_BY: 'CommonBuffId' = 188555 - CAREER_SCOUTING_SAD: 'CommonBuffId' = 188463 - CAREER_SCOUTING_STRESSED: 'CommonBuffId' = 188462 - CAREER_SCOUTING_UNIFORM_WORN: 'CommonBuffId' = 190776 - CAREER_SIDE_HUSTLE_NAILED_IT: 'CommonBuffId' = 278872 - CAREER_SIDE_HUSTLE_RECENT_FOLLOWER: 'CommonBuffId' = 278483 - CAREER_SIDE_HUSTLE_SEALED_THE_DEAL: 'CommonBuffId' = 278873 - CAREER_SIMSFLUENCER_SIDE_HUSTLE_CURSED_CONCLUSION: 'CommonBuffId' = 276842 - CAREER_SIMSFLUENCER_SIDE_HUSTLE_DEMONITIZED: 'CommonBuffId' = 276841 - CAREER_SIMSFLUENCER_SIDE_HUSTLE_PRIME_PRODUCT: 'CommonBuffId' = 276843 - CAREER_SIMSFLUENCER_SIDE_HUSTLE_REVIEW_BUFF: 'CommonBuffId' = 278425 - CAREER_SOCCER_TEAM_CHANCE_CARD_BLEW_IT: 'CommonBuffId' = 221638 - CAREER_SOCCER_TEAM_CHANCE_CARD_GOAL: 'CommonBuffId' = 221637 - CAREER_SOCCER_TEAM_CHANCE_CARD_INJURY: 'CommonBuffId' = 221635 - CAREER_SOCCER_TEAM_CHANCE_CARD_RED_CARD: 'CommonBuffId' = 221639 - CAREER_SOCCER_TEAM_CHANCE_CARD_TOO_MUCH_ENERGY_DRINK: 'CommonBuffId' = 221636 - CAREER_SOCCER_TEAM_CHANCE_CARD_YELLOW_CARD: 'CommonBuffId' = 221640 - CAREER_SOCCER_TEAM_GAME_LOST_ARTS: 'CommonBuffId' = 228144 - CAREER_SOCCER_TEAM_GAME_LOST_SCIENCE: 'CommonBuffId' = 228162 - CAREER_SOCCER_TEAM_GAME_WON_ARTS: 'CommonBuffId' = 228143 - CAREER_SOCCER_TEAM_GAME_WON_SCIENCE: 'CommonBuffId' = 228160 - CAREER_SOCIAL_MEDIA_HAS_CHECKED_IN_AT_VENUE_HIDDEN: 'CommonBuffId' = 136910 - CAREER_SOCIAL_MEDIA_HIDDEN_COOLDOWN_CHARITY_STREAM: 'CommonBuffId' = 151263 - CAREER_SOCIAL_MEDIA_HIDDEN_COOLDOWN_PERSUADED_TO: 'CommonBuffId' = 153036 - CAREER_SOCIAL_MEDIA_HIDDEN_COOLDOWN_PICKED_SIM_REPRESENTED: 'CommonBuffId' = 141731 - CAREER_SOCIAL_MEDIA_HIDDEN_COOLDOWN_PRANK_STREAMERS: 'CommonBuffId' = 143908 - CAREER_SOCIAL_MEDIA_HIDDEN_COOLDOWN_RECORD_RANT: 'CommonBuffId' = 137775 - CAREER_SOCIAL_MEDIA_HIDDEN_COOLDOWN_SHARE_FUNNY_MEME: 'CommonBuffId' = 143907 - CAREER_SOCIAL_MEDIA_HIDDEN_COOLDOWN_SHARE_IMAGE_PROMOTE_IMAGE: 'CommonBuffId' = 137771 - CAREER_SOCIAL_MEDIA_HIDDEN_COOLDOWN_UPLOAD_VIRAL_VIDEO: 'CommonBuffId' = 137770 - CAREER_SOCIAL_MEDIA_INTERNET_PERSONALITY_ANGRY_FANS: 'CommonBuffId' = 137075 - CAREER_SOCIAL_MEDIA_INTERNET_PERSONALITY_MEME_FAIL: 'CommonBuffId' = 137072 - CAREER_SOCIAL_MEDIA_INTERNET_PERSONALITY_MEME_SUCCESS: 'CommonBuffId' = 137071 - CAREER_SOCIAL_MEDIA_INTERNET_PERSONALITY_PRANK_STREAMERS_FAIL: 'CommonBuffId' = 137073 - CAREER_SOCIAL_MEDIA_INTERNET_PERSONALITY_PRANK_STREAMERS_SUCCESS: 'CommonBuffId' = 137074 - CAREER_SOCIAL_MEDIA_INTERNET_PERSONALITY_PRE_STREAMING_MARATHON_HIDDEN: 'CommonBuffId' = 153949 - CAREER_SOCIAL_MEDIA_INTERNET_PERSONALITY_SHARE_JOKE_FAIL: 'CommonBuffId' = 141660 - CAREER_SOCIAL_MEDIA_INTERNET_PERSONALITY_SHARE_JOKE_SUCCESS: 'CommonBuffId' = 153486 - CAREER_SOCIAL_MEDIA_INTERNET_PERSONALITY_STREAMING_MARATHON: 'CommonBuffId' = 137040 - CAREER_SOCIAL_MEDIA_INTERNET_PERSONALITY_TRENDING: 'CommonBuffId' = 137039 - CAREER_SOCIAL_MEDIA_PERSUADED_TO_COOK: 'CommonBuffId' = 136649 - CAREER_SOCIAL_MEDIA_PERSUADED_TO_DO_COMEDY: 'CommonBuffId' = 136654 - CAREER_SOCIAL_MEDIA_PERSUADED_TO_FLIRT: 'CommonBuffId' = 136651 - CAREER_SOCIAL_MEDIA_PERSUADED_TO_GOOF_OFF: 'CommonBuffId' = 136655 - CAREER_SOCIAL_MEDIA_PERSUADED_TO_PLAY_GAMES: 'CommonBuffId' = 136656 - CAREER_SOCIAL_MEDIA_PERSUADED_TO_PLAY_MUSIC: 'CommonBuffId' = 136657 - CAREER_SOCIAL_MEDIA_PERSUADED_TO_RACCOON: 'CommonBuffId' = 150999 - CAREER_SOCIAL_MEDIA_PERSUADED_TO_RANT: 'CommonBuffId' = 136652 - CAREER_SOCIAL_MEDIA_PERSUADED_TO_SING: 'CommonBuffId' = 136796 - CAREER_SOCIAL_MEDIA_PERSUADED_TO_SMILE: 'CommonBuffId' = 136650 - CAREER_SOCIAL_MEDIA_PERSUADED_TO_WORK_OUT: 'CommonBuffId' = 136653 - CAREER_SOCIAL_MEDIA_PUBLIC_RELATIONS_DEVELOP_NETWORK_FAIL: 'CommonBuffId' = 137080 - CAREER_SOCIAL_MEDIA_PUBLIC_RELATIONS_DEVELOP_NETWORK_SUCCESS: 'CommonBuffId' = 137079 - CAREER_SOCIAL_MEDIA_PUBLIC_RELATIONS_REPRESENTED_FRIEND_FAIL: 'CommonBuffId' = 137081 - CAREER_SOCIAL_MEDIA_PUBLIC_RELATIONS_REPRESENTED_FRIEND_SUCCESS: 'CommonBuffId' = 137083 - CAREER_SOCIAL_MEDIA_PUBLIC_RELATIONS_REPRESENT_CLIENT_FAIL: 'CommonBuffId' = 137082 - CAREER_SOCIAL_MEDIA_PUBLIC_RELATIONS_REPRESENT_CLIENT_SUCCESS: 'CommonBuffId' = 137084 - CAREER_SOCIAL_MEDIA_PUBLIC_RELATIONS_TRENDING: 'CommonBuffId' = 137103 - CAREER_SO_MANY_ERRORS: 'CommonBuffId' = 31921 - CAREER_SPACE_DUPED: 'CommonBuffId' = 33444 - CAREER_SPACE_ROUTINE: 'CommonBuffId' = 33453 - CAREER_SPEAKER_POWER: 'CommonBuffId' = 32568 - CAREER_SPONSOR_ARTIST_FAILURE: 'CommonBuffId' = 34041 - CAREER_SPONSOR_ARTIST_SUCCESS: 'CommonBuffId' = 34040 - CAREER_SPY_SWAGGER: 'CommonBuffId' = 32304 - CAREER_STREAMER_SIDE_HUSTLE_BANNED: 'CommonBuffId' = 276733 - CAREER_STREAMER_SIDE_HUSTLE_BEATEN_AT_OWN_GAME: 'CommonBuffId' = 276738 - CAREER_STREAMER_SIDE_HUSTLE_BEHIND_THE_MASK: 'CommonBuffId' = 276736 - CAREER_STREAMER_SIDE_HUSTLE_TIP_COOLDOWN: 'CommonBuffId' = 297082 - CAREER_STUNK_IT_UP: 'CommonBuffId' = 31541 - CAREER_STYLE_INFLUENCER_ARTICLE_SUBMIT_FAILURE: 'CommonBuffId' = 198664 - CAREER_STYLE_INFLUENCER_FAKE_NEWS_ANGRY: 'CommonBuffId' = 197551 - CAREER_STYLE_INFLUENCER_FAKE_NEWS_EMBARRASSED: 'CommonBuffId' = 197552 - CAREER_STYLE_INFLUENCER_FAKE_NEWS_SAD: 'CommonBuffId' = 197550 - CAREER_STYLE_INFLUENCER_FASHION_FANATIC: 'CommonBuffId' = 197561 - CAREER_STYLE_INFLUENCER_IMPRESSION: 'CommonBuffId' = 197115 - CAREER_STYLE_INFLUENCER_INTERVIEW_HIDDEN_COOLDOWN: 'CommonBuffId' = 201602 - CAREER_STYLE_INFLUENCER_MODELING_LOOK: 'CommonBuffId' = 198915 - CAREER_STYLE_INFLUENCER_MODEL_LOOK: 'CommonBuffId' = 198813 - CAREER_STYLE_INFLUENCER_MODEL_LOOK_COOLDOWN: 'CommonBuffId' = 198814 - CAREER_STYLE_INFLUENCER_PROLIFIC_PERSONA: 'CommonBuffId' = 197560 - CAREER_STYLE_INFLUENCER_SCOOP: 'CommonBuffId' = 197553 - CAREER_STYLE_INFLUENCER_SELL_OUT: 'CommonBuffId' = 197555 - CAREER_STYLE_INFLUENCER_STANDBY_CONVICTIONS: 'CommonBuffId' = 197554 - CAREER_STYLE_INFLUENCER_UNHAPPY_CUSTOMER_ANGRY: 'CommonBuffId' = 197558 - CAREER_STYLE_INFLUENCER_UNHAPPY_CUSTOMER_SAD: 'CommonBuffId' = 197559 - CAREER_STYLE_INFLUENCER_WORKING_IT: 'CommonBuffId' = 197556 - CAREER_SUDDEN_INSPIRATION: 'CommonBuffId' = 31230 - CAREER_SUSPECT_ESCAPED: 'CommonBuffId' = 37940 - CAREER_TALK_TO_THE_HENCHMEN: 'CommonBuffId' = 32337 - CAREER_TAXES_EVADED: 'CommonBuffId' = 37805 - CAREER_TEACH_HANDS_ON_FAIL: 'CommonBuffId' = 34020 - CAREER_TEACH_HANDS_ON_SUCCESS: 'CommonBuffId' = 34022 - CAREER_TEACH_THEORY: 'CommonBuffId' = 34023 - CAREER_TEEN_BABYSITTER_01_COOKIE_BEFORE_DINNER: 'CommonBuffId' = 74391 - CAREER_TEEN_BABYSITTER_01_COOKIE_TANTRUM: 'CommonBuffId' = 74392 - CAREER_TEEN_BABYSITTER_02_BROWN_PAINT_EVERYWHERE: 'CommonBuffId' = 74394 - CAREER_TEEN_BABYSITTER_02_CLEANED_UP_MESS: 'CommonBuffId' = 74393 - CAREER_TEEN_BABYSITTER_02_LEFT_THE_MESS: 'CommonBuffId' = 74395 - CAREER_TEEN_BABYSITTER_03_LIFE_LESSONS: 'CommonBuffId' = 74396 - CAREER_TEEN_BARISTA_03_BREWED_MASTERPIECE: 'CommonBuffId' = 74430 - CAREER_TEEN_BARISTA_03_MORE_PRACTISE: 'CommonBuffId' = 74432 - CAREER_TEEN_FAST_FOOD_01_BREAK_TIME: 'CommonBuffId' = 74411 - CAREER_TEEN_FAST_FOOD_01_CLEANING_SHOW: 'CommonBuffId' = 74412 - CAREER_TEEN_FAST_FOOD_02_FIVE_SECOND_RULE: 'CommonBuffId' = 74413 - CAREER_TEEN_FAST_FOOD_02_HAIR_BURGER: 'CommonBuffId' = 74414 - CAREER_TEEN_FAST_FOOD_03_PROACTIVE_THINKING: 'CommonBuffId' = 74415 - CAREER_TEEN_MANUAL_LABOR_01_RECORD_SPEED: 'CommonBuffId' = 74433 - CAREER_TEEN_MANUAL_LABOR_02_DOUBLE_THE_WORK: 'CommonBuffId' = 74435 - CAREER_TEEN_MANUAL_LABOR_02_MINIMALISTIC_DESIGN: 'CommonBuffId' = 74434 - CAREER_TEEN_MANUAL_LABOR_03_BACKHOE_MASTER: 'CommonBuffId' = 74436 - CAREER_TEEN_MANUAL_LABOR_03_FLIPPED_BACKHOE: 'CommonBuffId' = 74437 - CAREER_TEEN_RETAIL_01_BURIED_CUSTOMER: 'CommonBuffId' = 74420 - CAREER_TEEN_RETAIL_01_SOLD_OUT_DISPLAY: 'CommonBuffId' = 74417 - CAREER_TEEN_RETAIL_02_CUSTOMER_PRAISE: 'CommonBuffId' = 74421 - CAREER_TEEN_RETAIL_03_CUSTOMER_TURNED_AWAY: 'CommonBuffId' = 74419 - CAREER_TEEN_RETAIL_03_GRATEFUL_CUSTOMER: 'CommonBuffId' = 74418 - CAREER_THE_BEST_AROUND: 'CommonBuffId' = 32184 - CAREER_TIRE_FAIL: 'CommonBuffId' = 33049 - CAREER_TIRE_FIXED: 'CommonBuffId' = 33048 - CAREER_TONE_BORED: 'CommonBuffId' = 154576 - CAREER_TONE_BORED_ACTIVIST_POLITICS: 'CommonBuffId' = 137300 - CAREER_TONE_CONFIDENT: 'CommonBuffId' = 145074 - CAREER_TONE_CONFIDENT_AGENT_AGENT: 'CommonBuffId' = 76864 - CAREER_TONE_CONFIDENT_AGENT_MAIN: 'CommonBuffId' = 76863 - CAREER_TONE_CONFIDENT_AGENT_VILLAIN: 'CommonBuffId' = 76866 - CAREER_TONE_CONFIDENT_BIG_BREAK: 'CommonBuffId' = 76839 - CAREER_TONE_CONFIDENT_CRIMINAL_BOSS: 'CommonBuffId' = 76807 - CAREER_TONE_EMBARRASSED: 'CommonBuffId' = 145062 - CAREER_TONE_EMBARRASSED_CONFIDENT: 'CommonBuffId' = 101215 - CAREER_TONE_ENERGIZED_ACTIVIST_MAIN: 'CommonBuffId' = 137297 - CAREER_TONE_FOCUSED_ASTRONAUT_MAIN: 'CommonBuffId' = 100970 - CAREER_TONE_FOCUSED_ASTRONAUT_RANGER: 'CommonBuffId' = 100973 - CAREER_TONE_HAPPY: 'CommonBuffId' = 145073 - CAREER_TONE_HAPPY_SLACK_OFF: 'CommonBuffId' = 100536 - CAREER_TONE_HAPPY_TAKE_IT_EASY: 'CommonBuffId' = 76774 - CAREER_TONE_HAPPY_TECH_GAMING: 'CommonBuffId' = 76870 - CAREER_TONE_HAPPY_TECH_MAIN: 'CommonBuffId' = 76868 - CAREER_TONE_INSPIRED_CULINARY_BARTENDER: 'CommonBuffId' = 76828 - CAREER_TONE_INSPIRED_CULINARY_MAIN: 'CommonBuffId' = 76818 - CAREER_TONE_INSPIRED_ENTERTAINER_MUSIC: 'CommonBuffId' = 76842 - CAREER_TONE_INSPIRED_PAINTER_ARTIST: 'CommonBuffId' = 76850 - CAREER_TONE_INSPIRED_PAINTER_MAIN: 'CommonBuffId' = 76847 - CAREER_TONE_INSPIRED_TECH_STARTUP: 'CommonBuffId' = 76873 - CAREER_TONE_INSPIRED_WRITER_AUTHOR: 'CommonBuffId' = 76879 - CAREER_TONE_INSPIRED_WRITER_MAIN: 'CommonBuffId' = 76876 - CAREER_TONE_PLAYFUL_ENTERTAINER_COMEDY: 'CommonBuffId' = 76845 - CAREER_TONE_SAD_FAILED_MISSION: 'CommonBuffId' = 76861 - CAREER_TONE_SCHOOL_TENSE: 'CommonBuffId' = 98354 - CAREER_TONE_STRESS: 'CommonBuffId' = 145075 - CAREER_TONE_STRESS_ASTRONAUT_SMUGGLER: 'CommonBuffId' = 76792 - CAREER_TONE_STRESS_PAINTER_CRITIC: 'CommonBuffId' = 76858 - CAREER_TONE_STRESS_WORKING_HARD: 'CommonBuffId' = 76770 - CAREER_TONE_STYLE_INFLUENCER_MAIN_RESEARCH: 'CommonBuffId' = 196952 - CAREER_TONE_STYLE_INFLUENCER_STYLIST_NETWORK: 'CommonBuffId' = 196951 - CAREER_TONE_STYLE_INFLUENCER_STYLIST_PAMPER: 'CommonBuffId' = 196953 - CAREER_TONE_STYLE_INFLUENCER_TREND_SETTER_PROMOTE_BAND: 'CommonBuffId' = 196954 - CAREER_TONE_STYLE_INFLUENCER_TREND_SETTER_SHOP: 'CommonBuffId' = 196955 - CAREER_TRIANGLE_SILENT: 'CommonBuffId' = 33090 - CAREER_TUTORING_FAILED: 'CommonBuffId' = 34013 - CAREER_TUTORING_WORTHWHILE: 'CommonBuffId' = 34011 - CAREER_UNCOMFORTABLE_IRRESPONSIBLE: 'CommonBuffId' = 163929 - CAREER_UNDEFENDED_GALAXY: 'CommonBuffId' = 37797 - CAREER_UNDER_PRICED_CORRECT: 'CommonBuffId' = 34036 - CAREER_UNDER_PRICED_OUT_BID: 'CommonBuffId' = 34035 - CAREER_UNDER_PRICED_PURCHASE: 'CommonBuffId' = 34037 - CAREER_UNGRATEFUL_PILOTS: 'CommonBuffId' = 37749 - CAREER_USELESS_MISSION: 'CommonBuffId' = 37758 - CAREER_VIRAL_CHASE: 'CommonBuffId' = 37942 - CAREER_VIRUS_CRIPPLES_COMPUTER: 'CommonBuffId' = 33072 - CAREER_VIRUS_INVESTIGATE_NOTHING: 'CommonBuffId' = 33071 - CAREER_VIRUS_INVESTIGATE_SUCCESS: 'CommonBuffId' = 33070 - CAREER_WORMHOLE_BACKLASH: 'CommonBuffId' = 37746 - CAREER_WORMHOLE_TRAVELER: 'CommonBuffId' = 37765 - CAREER_WORTHWHILE_LACERATIONS: 'CommonBuffId' = 37807 - CAREER_YELLED_AT_BY_COWORKER: 'CommonBuffId' = 27188 - CARRIED_PET: 'CommonBuffId' = 176876 - CATCH_SNOOPING: 'CommonBuffId' = 160255 - CATCH_SNOOPING_VISIBLE_ANGRY: 'CommonBuffId' = 164039 - CAT_ACTIVE_ROUGHHOUSE_PLAY_DECAY: 'CommonBuffId' = 173488 - CAT_BLOCK_ROUTABLE_SURFACE_MISBEHAVIOR: 'CommonBuffId' = 171975 - CAT_MAD_NIP_ATTACK_COOLDOWN: 'CommonBuffId' = 173594 - CAT_ON_ROUTABLE_SURFACE_MISBEHAVIOR: 'CommonBuffId' = 171915 - CAUGHT_IN_CURRENT_ROUTE_EVENT: 'CommonBuffId' = 212889 - CAULDRON_POTION_BFF_FAILURE: 'CommonBuffId' = 214263 - CAULDRON_POTION_BFF_SUCCESS: 'CommonBuffId' = 214261 - CAULDRON_POTION_BFF_SUCCESS_POTENT: 'CommonBuffId' = 214262 - CAULDRON_POTION_DEATH_PROOF_FAILURE: 'CommonBuffId' = 215772 - CAULDRON_POTION_DEATH_PROOF_FAILURE_POTENT: 'CommonBuffId' = 215776 - CAULDRON_POTION_DEATH_PROOF_SUCCESS: 'CommonBuffId' = 215771 - CAULDRON_POTION_DEATH_PROOF_SUCCESS_POTENT: 'CommonBuffId' = 215775 - CAULDRON_POTION_FAIL_POTION: 'CommonBuffId' = 218968 - CAULDRON_POTION_HATE_FAILURE: 'CommonBuffId' = 214250 - CAULDRON_POTION_HATE_SUCCESS: 'CommonBuffId' = 214251 - CAULDRON_POTION_HATE_SUCCESS_POTENT: 'CommonBuffId' = 214252 - CAULDRON_POTION_IMMORTALITY_FAILURE_TENSE: 'CommonBuffId' = 214403 - CAULDRON_POTION_IMMORTALITY_SUCCESS: 'CommonBuffId' = 219899 - CAULDRON_POTION_IMMORTALITY_SUCCESS_VFX: 'CommonBuffId' = 214393 - CAULDRON_POTION_LEARNED_POTION_COOLDOWN: 'CommonBuffId' = 216168 - CAULDRON_POTION_LOVE_FAILURE: 'CommonBuffId' = 214097 - CAULDRON_POTION_LOVE_SUCCESS: 'CommonBuffId' = 214098 - CAULDRON_POTION_LOVE_SUCCESS_POTENT: 'CommonBuffId' = 214099 - CAULDRON_POTION_LUCK: 'CommonBuffId' = 215690 - CAULDRON_POTION_LUCK_CHEAT_ALWAYS_MONEY: 'CommonBuffId' = 216800 - CAULDRON_POTION_LUCK_CHEAT_ALWAYS_OBJECTS: 'CommonBuffId' = 216799 - CAULDRON_POTION_LUCK_FAIL_TIMER: 'CommonBuffId' = 215780 - CAULDRON_POTION_LUCK_POTENT: 'CommonBuffId' = 215698 - CAULDRON_POTION_MAKE_GLOWY_FAILURE: 'CommonBuffId' = 214531 - CAULDRON_POTION_MAKE_GLOWY_FAILURE_POTENT: 'CommonBuffId' = 214536 - CAULDRON_POTION_MAKE_GLOWY_FAILURE_VFX_1: 'CommonBuffId' = 217447 - CAULDRON_POTION_MAKE_GLOWY_FAILURE_VFX_2: 'CommonBuffId' = 217448 - CAULDRON_POTION_MAKE_GLOWY_FAILURE_VFX_3: 'CommonBuffId' = 217451 - CAULDRON_POTION_MAKE_GLOWY_FAILURE_VFX_4: 'CommonBuffId' = 217452 - CAULDRON_POTION_MAKE_GLOWY_SUCCESS: 'CommonBuffId' = 214529 - CAULDRON_POTION_MAKE_GLOWY_SUCCESS_POTENT: 'CommonBuffId' = 214537 - CAULDRON_POTION_NULLIFY_FAILURE_1: 'CommonBuffId' = 214483 - CAULDRON_POTION_NULLIFY_FAILURE_11: 'CommonBuffId' = 214493 - CAULDRON_POTION_NULLIFY_FAILURE_12: 'CommonBuffId' = 214489 - CAULDRON_POTION_NULLIFY_FAILURE_13: 'CommonBuffId' = 214492 - CAULDRON_POTION_NULLIFY_FAILURE_14: 'CommonBuffId' = 214487 - CAULDRON_POTION_NULLIFY_FAILURE_15: 'CommonBuffId' = 214488 - CAULDRON_POTION_NULLIFY_FAILURE_15_POTENT: 'CommonBuffId' = 214500 - CAULDRON_POTION_NULLIFY_FAILURE_2: 'CommonBuffId' = 214490 - CAULDRON_POTION_NULLIFY_FAILURE_3: 'CommonBuffId' = 214498 - CAULDRON_POTION_NULLIFY_FAILURE_4: 'CommonBuffId' = 214495 - CAULDRON_POTION_NULLIFY_FAILURE_5: 'CommonBuffId' = 214485 - CAULDRON_POTION_NULLIFY_FAILURE_6: 'CommonBuffId' = 214491 - CAULDRON_POTION_NULLIFY_FAILURE_7: 'CommonBuffId' = 214494 - CAULDRON_POTION_NULLIFY_FAILURE_8: 'CommonBuffId' = 214497 - CAULDRON_POTION_NULLIFY_FAILURE_9: 'CommonBuffId' = 214496 - CAULDRON_POTION_NULLIFY_SUCCESS: 'CommonBuffId' = 217405 - CAULDRON_POTION_NULLIFY_SUCCESS_POTENT: 'CommonBuffId' = 217407 - CAULDRON_POTION_PHEROMONE_FAILURE: 'CommonBuffId' = 214940 - CAULDRON_POTION_PHEROMONE_SUCCESS: 'CommonBuffId' = 214941 - CAULDRON_POTION_PHEROMONE_SUCCESS_POTENT: 'CommonBuffId' = 214944 - CAULDRON_POTION_POISON: 'CommonBuffId' = 213624 - CAULDRON_POTION_POISON_FAIL_FORVAMPIRE: 'CommonBuffId' = 219207 - CAULDRON_POTION_POISON_POTENT: 'CommonBuffId' = 213687 - CAULDRON_POTION_RESET_WITCH_PERKS_FAIL: 'CommonBuffId' = 219285 - CAULDRON_POTION_SKILL_INCREASE: 'CommonBuffId' = 214466 - CAULDRON_POTION_SKILL_INCREASE_FAIL: 'CommonBuffId' = 219258 - CAULDRON_POTION_SKILL_INCREASE_POTENT: 'CommonBuffId' = 214467 - CAULDRON_STIR: 'CommonBuffId' = 220394 - CAULDRON_USAGE_CANCEL: 'CommonBuffId' = 220498 - CAVE_INSPIRED: 'CommonBuffId' = 345651 - CAVE_UNCOMFORTABLE: 'CommonBuffId' = 345652 - CELEBRATION_CANNON_BABY_BUST: 'CommonBuffId' = 321239 - CELEBRATION_CANNON_CELEBRATION_CATASTROPHE: 'CommonBuffId' = 322451 - CELEBRATION_CANNON_CONFETTI_TIME: 'CommonBuffId' = 322452 - CELEBRATION_CANNON_COOLDOWN: 'CommonBuffId' = 321084 - CELEBRATION_CANNON_ITS_A_SIM: 'CommonBuffId' = 321238 - CELEBRITY_ACQUAINTANCE: 'CommonBuffId' = 192633 - CELEBRITY_FAINT_COOLDOWN: 'CommonBuffId' = 198718 - CELEBRITY_FANS: 'CommonBuffId' = 196088 - CELEBRITY_FANS_FAN_TRAITS_NERVOUS: 'CommonBuffId' = 196909 - CELEBRITY_FANS_FAN_TRAITS_SOCIAL: 'CommonBuffId' = 196911 - CELEBRITY_FANS_FAN_TRAITS_TOUCHY: 'CommonBuffId' = 196910 - CELEBRITY_FAN_SOCIAL_COOLDOWN: 'CommonBuffId' = 198717 - CELEBRITY_FAN_WHIMS: 'CommonBuffId' = 193469 - CELEBRITY_MEET_AND_GREET_CELEBRITY: 'CommonBuffId' = 199597 - CELEBRITY_MEET_AND_GREET_FAME_AND_REP_BRONZE: 'CommonBuffId' = 199827 - CELEBRITY_MEET_AND_GREET_FAME_AND_REP_BRONZE_BAD_REP: 'CommonBuffId' = 202817 - CELEBRITY_MEET_AND_GREET_FAME_AND_REP_GOLD: 'CommonBuffId' = 199828 - CELEBRITY_MEET_AND_GREET_FAME_AND_REP_GOLD_BAD_REP: 'CommonBuffId' = 202818 - CELEBRITY_MEET_AND_GREET_FAME_AND_REP_SILVER: 'CommonBuffId' = 199829 - CELEBRITY_MEET_AND_GREET_FAME_AND_REP_SILVER_BAD_REP: 'CommonBuffId' = 202819 - CELEBRITY_MEET_AND_GREET_FAN: 'CommonBuffId' = 199598 - CELEBRITY_MEET_AND_GREET_POSE_FOR_PICTURES: 'CommonBuffId' = 201444 - CELEBRITY_NEAR_CELEBRITY: 'CommonBuffId' = 192980 - CELEBRITY_POSE_CELEBRITY: 'CommonBuffId' = 193799 - CELEBRITY_POSE_FAN: 'CommonBuffId' = 193800 - CELEBRITY_SOCIALS_AUTOGRAPH_FAILURE: 'CommonBuffId' = 194599 - CELEBRITY_SOCIALS_AUTOGRAPH_SUCCESS: 'CommonBuffId' = 194598 - CELEBRITY_SOCIALS_CELEB_HUG_FAILURE: 'CommonBuffId' = 198636 - CELEBRITY_SOCIALS_CELEB_SELFIE_FAILURE: 'CommonBuffId' = 198684 - CELEBRITY_SOCIALS_HUG_FAILURE: 'CommonBuffId' = 194594 - CELEBRITY_SOCIALS_HUG_SUCCESS: 'CommonBuffId' = 194589 - CELEBRITY_SOCIALS_SELFIE_FAILURE: 'CommonBuffId' = 194597 - CELEBRITY_SOCIALS_SELFIE_SUCCESS: 'CommonBuffId' = 194595 - CELEBRITY_STANS: 'CommonBuffId' = 196846 - CELEBRITY_TAKE_PICTURE_SUCCESS: 'CommonBuffId' = 194509 - CELEBRITY_TILE_HIDDEN_TILE_ACHIEVED_DEFACED_TILE: 'CommonBuffId' = 201078 - CELEBRITY_TILE_MOOD_DEFACE_PLAYFUL: 'CommonBuffId' = 198719 - CELEBRITY_TILE_PLACEMENT_CEREMONY_CROWD_MEMBER_GATHER: 'CommonBuffId' = 195851 - CELEBRITY_TILE_PLACEMENT_CEREMONY_CROWD_MEMBER_GATHER_IMPATIENT: 'CommonBuffId' = 195852 - CELEBRITY_TILE_PLACEMENT_CEREMONY_CROWD_MEMBER_START_CEREMONY: 'CommonBuffId' = 195853 - CELEBRITY_TILE_PLACEMENT_CEREMONY_HONOREE_GATHER: 'CommonBuffId' = 195846 - CELEBRITY_TILE_PLACEMENT_CEREMONY_HONOREE_GATHER_IMPATIENT: 'CommonBuffId' = 195848 - CELEBRITY_TILE_PLACEMENT_CEREMONY_HONOREE_START_CEREMONY: 'CommonBuffId' = 195850 - CELEBRITY_TILE_PLACE_TILE_CONFIDENT: 'CommonBuffId' = 198691 - CELEBRITY_TILE_TILE_EARNED_HAPPY: 'CommonBuffId' = 198692 - CELEBRITY_TILE_VIEW_CELEBRITY_NEGATIVE: 'CommonBuffId' = 196543 - CELEBRITY_TILE_VIEW_CELEBRITY_POSITIVE: 'CommonBuffId' = 196542 - CHARITY_BENEFIT_PARTY_GOLD: 'CommonBuffId' = 197821 - CHARITY_BENEFIT_PARTY_SILVER: 'CommonBuffId' = 197820 - CHEATING_INTENSITY_ANGRY: 'CommonBuffId' = 12783 - CHEATING_INTENSITY_BORED: 'CommonBuffId' = 12784 - CHEATING_INTENSITY_BUFF_PETS_HORSE_ANGRY: 'CommonBuffId' = 322156 - CHEATING_INTENSITY_BUFF_PETS_HORSE_CONFIDENT: 'CommonBuffId' = 322155 - CHEATING_INTENSITY_BUFF_PETS_HORSE_DAZED: 'CommonBuffId' = 322159 - CHEATING_INTENSITY_BUFF_PETS_HORSE_HAPPY: 'CommonBuffId' = 322154 - CHEATING_INTENSITY_BUFF_PETS_HORSE_SAD: 'CommonBuffId' = 322160 - CHEATING_INTENSITY_BUFF_PETS_HORSE_SCARED: 'CommonBuffId' = 322161 - CHEATING_INTENSITY_BUFF_PETS_HORSE_TENSE: 'CommonBuffId' = 322158 - CHEATING_INTENSITY_BUFF_PETS_HORSE_UNCOMFORTABLE: 'CommonBuffId' = 322157 - CHEATING_INTENSITY_BUFF_PETS_HORSE_VERY_ANGRY: 'CommonBuffId' = 322163 - CHEATING_INTENSITY_BUFF_PETS_HORSE_VERY_CONFIDENT: 'CommonBuffId' = 322164 - CHEATING_INTENSITY_BUFF_PETS_HORSE_VERY_DAZED: 'CommonBuffId' = 322165 - CHEATING_INTENSITY_BUFF_PETS_HORSE_VERY_HAPPY: 'CommonBuffId' = 322166 - CHEATING_INTENSITY_BUFF_PETS_HORSE_VERY_SAD: 'CommonBuffId' = 322167 - CHEATING_INTENSITY_BUFF_PETS_HORSE_VERY_SCARED: 'CommonBuffId' = 322168 - CHEATING_INTENSITY_BUFF_PETS_HORSE_VERY_TENSE: 'CommonBuffId' = 322169 - CHEATING_INTENSITY_BUFF_PETS_HORSE_VERY_UNCOMFORTABLE: 'CommonBuffId' = 322170 - CHEATING_INTENSITY_BUFF_SCARED: 'CommonBuffId' = 251737 - CHEATING_INTENSITY_BUFF_TERRIFIED: 'CommonBuffId' = 251738 - CHEATING_INTENSITY_CONFIDENT: 'CommonBuffId' = 12785 - CHEATING_INTENSITY_DEPRESSED: 'CommonBuffId' = 12787 - CHEATING_INTENSITY_ELATED: 'CommonBuffId' = 12788 - CHEATING_INTENSITY_EMBARRASSED: 'CommonBuffId' = 12789 - CHEATING_INTENSITY_ENERGIZED: 'CommonBuffId' = 12790 - CHEATING_INTENSITY_ENRAGED: 'CommonBuffId' = 12786 - CHEATING_INTENSITY_FEARLESS: 'CommonBuffId' = 12791 - CHEATING_INTENSITY_FLIRTY: 'CommonBuffId' = 12792 - CHEATING_INTENSITY_FOCUSED: 'CommonBuffId' = 12793 - CHEATING_INTENSITY_FURIOUS: 'CommonBuffId' = 12794 - CHEATING_INTENSITY_HAPPY: 'CommonBuffId' = 12795 - CHEATING_INTENSITY_HUMILIATED: 'CommonBuffId' = 12796 - CHEATING_INTENSITY_HYSTERICAL: 'CommonBuffId' = 12797 - CHEATING_INTENSITY_IMAGINATIVE: 'CommonBuffId' = 12798 - CHEATING_INTENSITY_INSPIRED: 'CommonBuffId' = 12799 - CHEATING_INTENSITY_IN_THE_ZONE: 'CommonBuffId' = 12800 - CHEATING_INTENSITY_MISERABLE: 'CommonBuffId' = 12801 - CHEATING_INTENSITY_MORTIFIED: 'CommonBuffId' = 12802 - CHEATING_INTENSITY_PASSIONATE: 'CommonBuffId' = 12803 - CHEATING_INTENSITY_PETS_DOG_ANGRY: 'CommonBuffId' = 158257 - CHEATING_INTENSITY_PETS_DOG_ANXIOUS: 'CommonBuffId' = 158262 - CHEATING_INTENSITY_PETS_DOG_ASHAMED: 'CommonBuffId' = 158260 - CHEATING_INTENSITY_PETS_DOG_EXCITED: 'CommonBuffId' = 158258 - CHEATING_INTENSITY_PETS_DOG_FLIRTY: 'CommonBuffId' = 158263 - CHEATING_INTENSITY_PETS_DOG_HAPPY: 'CommonBuffId' = 158265 - CHEATING_INTENSITY_PETS_DOG_MOPEY: 'CommonBuffId' = 158261 - CHEATING_INTENSITY_PETS_DOG_SAD: 'CommonBuffId' = 158259 - CHEATING_INTENSITY_PETS_DOG_SCARED: 'CommonBuffId' = 158264 - CHEATING_INTENSITY_PLAYFUL: 'CommonBuffId' = 12804 - CHEATING_INTENSITY_POSSESSED: 'CommonBuffId' = 201535 - CHEATING_INTENSITY_PUMPED: 'CommonBuffId' = 12805 - CHEATING_INTENSITY_SAD: 'CommonBuffId' = 12806 - CHEATING_INTENSITY_SILLY: 'CommonBuffId' = 12807 - CHEATING_INTENSITY_SLOSHED: 'CommonBuffId' = 12808 - CHEATING_INTENSITY_STRESSED: 'CommonBuffId' = 12809 - CHEATING_INTENSITY_TENSE: 'CommonBuffId' = 12810 - CHEATING_INTENSITY_UNCOMFORTABLE: 'CommonBuffId' = 12811 - CHEATING_OKAY: 'CommonBuffId' = 12778 - CHEATING_PETS_CAT_ANGRY: 'CommonBuffId' = 158444 - CHEATING_PETS_CAT_ANXIOUS: 'CommonBuffId' = 158195 - CHEATING_PETS_CAT_DROWSY: 'CommonBuffId' = 158149 - CHEATING_PETS_CAT_FLIRTY: 'CommonBuffId' = 158446 - CHEATING_PETS_CAT_HAPPY: 'CommonBuffId' = 158448 - CHEATING_PETS_CAT_SCARED: 'CommonBuffId' = 158447 - CHEATING_PETS_HYPER: 'CommonBuffId' = 157910 - CHECK_FRESHNESS_COOLDOWN: 'CommonBuffId' = 237002 - CHEERED_UP: 'CommonBuffId' = 24494 - CHEERFUL_SCENT: 'CommonBuffId' = 118502 - CHEER_MAT_CANT_STOP_THIS: 'CommonBuffId' = 292165 - CHEER_MAT_IN_GROUP_CHEER: 'CommonBuffId' = 300895 - CHEER_MAT_TEAM_SPIRIT: 'CommonBuffId' = 292166 - CHEER_MAT_TOO_MUCH_SPIRIT: 'CommonBuffId' = 292164 - CHEF_BEGIN_STATE: 'CommonBuffId' = 133753 - CHEF_HAS_ORDER: 'CommonBuffId' = 131588 - CHEMICAL_ANALYZER_INSPIRED: 'CommonBuffId' = 107960 - CHILDHOOD_FRIENDS_SCENARIO_REWARD_INVSIBLE: 'CommonBuffId' = 299508 - CHILDHOOD_PHASE_BEAR: 'CommonBuffId' = 164893 - CHILDHOOD_PHASE_BEAR_IN_COSTUME_ADULT: 'CommonBuffId' = 165769 - CHILDHOOD_PHASE_BEAR_IN_COSTUME_CHILD: 'CommonBuffId' = 165768 - CHILDHOOD_PHASE_BEAR_NOT_IN_COSTUME: 'CommonBuffId' = 165770 - CHILDHOOD_PHASE_BEAR_NOT_IN_COSTUME_IGNORE: 'CommonBuffId' = 166821 - CHILDHOOD_PHASE_CLINGY: 'CommonBuffId' = 164894 - CHILDHOOD_PHASE_CLINGY_SOCIAL_HAPPY: 'CommonBuffId' = 165607 - CHILDHOOD_PHASE_CLINGY_SOCIAL_STRESSED: 'CommonBuffId' = 165608 - CHILDHOOD_PHASE_DISTANT: 'CommonBuffId' = 164895 - CHILDHOOD_PHASE_DISTANT_PROXIMITY: 'CommonBuffId' = 165495 - CHILDHOOD_PHASE_LOUD: 'CommonBuffId' = 164897 - CHILDHOOD_PHASE_MEAN_STREAK: 'CommonBuffId' = 164898 - CHILDHOOD_PHASE_MEAN_STREAK_MEAN_SOCIAL: 'CommonBuffId' = 165685 - CHILDHOOD_PHASE_PICKY_EATER_A: 'CommonBuffId' = 164896 - CHILDHOOD_PHASE_PICKY_EATER_B: 'CommonBuffId' = 165204 - CHILDHOOD_PHASE_PICKY_EATER_C: 'CommonBuffId' = 165205 - CHILDHOOD_PHASE_PICKY_EATER_CONSUMED_FOOD_BAD: 'CommonBuffId' = 165184 - CHILDHOOD_PHASE_PICKY_EATER_CONSUMED_FOOD_GOOD: 'CommonBuffId' = 165183 - CHILDHOOD_PHASE_PICKY_EATER_D: 'CommonBuffId' = 165206 - CHILDHOOD_PHASE_PICKY_EATER_E: 'CommonBuffId' = 165207 - CHILDHOOD_PHASE_REBELLIOUS: 'CommonBuffId' = 164899 - CHILDREN_HIDDEN_GREET_RETURNING_CAREGIVER: 'CommonBuffId' = 168221 - CHILDREN_STORIES_NEIGHBOR_ADOPTED_A_BABY: 'CommonBuffId' = 279286 - CHILDREN_STORIES_NEIGHBOR_ADOPTED_A_CAT: 'CommonBuffId' = 279975 - CHILDREN_STORIES_NEIGHBOR_ADOPTED_A_CHILD: 'CommonBuffId' = 279288 - CHILDREN_STORIES_NEIGHBOR_ADOPTED_A_DOG: 'CommonBuffId' = 279977 - CHILDREN_STORIES_NEIGHBOR_ADOPTED_A_HORSE: 'CommonBuffId' = 337813 - CHILDREN_STORIES_NEIGHBOR_ADOPTED_A_TODDLER: 'CommonBuffId' = 279287 - CHILD_CONFIDENCE_HIDDEN_AFFORDANCE_CREATIVITY: 'CommonBuffId' = 307432 - CHILD_CONFIDENCE_HIDDEN_AFFORDANCE_HOMEWORK: 'CommonBuffId' = 307431 - CHILD_CONFIDENCE_HIDDEN_AFFORDANCE_MENTAL: 'CommonBuffId' = 307433 - CHILD_CONFIDENCE_HIDDEN_AFFORDANCE_MOTOR: 'CommonBuffId' = 307434 - CHILD_CONFIDENCE_HIDDEN_AFFORDANCE_SCHOOL: 'CommonBuffId' = 307430 - CHILD_CONFIDENCE_HIDDEN_AFFORDANCE_SOCIAL: 'CommonBuffId' = 307435 - CHILD_DIVORCE: 'CommonBuffId' = 97679 - CHILD_FIGHT: 'CommonBuffId' = 97588 - CHILD_HIDDEN_MET_NEW_SIBLING: 'CommonBuffId' = 97690 - CHILD_MET_NEW_SIBLING_ANGRY: 'CommonBuffId' = 97694 - CHILD_MET_NEW_SIBLING_HAPPY: 'CommonBuffId' = 97695 - CHILD_MET_NEW_SIBLING_SAD: 'CommonBuffId' = 97692 - CHOPSTICKS_OPTIONAL_PREFER_CHOPSTICKS: 'CommonBuffId' = 247897 - CHOPSTICKS_OPTIONAL_PREFER_FORKS: 'CommonBuffId' = 247909 - CINNAMON_BUN_AIR: 'CommonBuffId' = 118501 - CITY_LIFE_LIVING_STATUE_BUSKER_TIPPED_HIGH: 'CommonBuffId' = 143332 - CITY_LIFE_LIVING_STATUE_BUSKER_TIPPED_LOW: 'CommonBuffId' = 143331 - CITY_LIFE_LIVING_STATUE_BUSKER_TIPPED_MED: 'CommonBuffId' = 143333 - CIVIC_POLICY_GIVE_INFLUENCE_EXTRA_LARGE: 'CommonBuffId' = 234099 - CIVIC_POLICY_GIVE_INFLUENCE_LARGE: 'CommonBuffId' = 234097 - CIVIC_POLICY_GIVE_INFLUENCE_MEDIUM: 'CommonBuffId' = 234096 - CIVIC_POLICY_GIVE_INFLUENCE_SMALL: 'CommonBuffId' = 234093 - CIVIC_POLICY_GIVE_INFLUENCE_SMALL_FUN_COMMUNITY: 'CommonBuffId' = 234654 - CIVIC_POLICY_NPC_AUTONOMY_AGGRESSION: 'CommonBuffId' = 237929 - CIVIC_POLICY_NPC_AUTONOMY_BAG_NEIGHBORHOOD: 'CommonBuffId' = 237919 - CIVIC_POLICY_NPC_AUTONOMY_COMMUNAL_OWNERSHIP: 'CommonBuffId' = 237951 - CIVIC_POLICY_NPC_AUTONOMY_CREATIVE_ARTS: 'CommonBuffId' = 232215 - CIVIC_POLICY_NPC_AUTONOMY_FREE_LOVE: 'CommonBuffId' = 237930 - CIVIC_POLICY_NPC_AUTONOMY_FUN_COMMUNITY: 'CommonBuffId' = 232216 - CIVIC_POLICY_NPC_AUTONOMY_HOME_COOKING: 'CommonBuffId' = 232217 - CIVIC_POLICY_NPC_AUTONOMY_JUICED_COMMUNITY: 'CommonBuffId' = 232218 - CIVIC_POLICY_NPC_AUTONOMY_JUICED_COMMUNITY_DAZED: 'CommonBuffId' = 238039 - CIVIC_POLICY_NPC_AUTONOMY_MUSIC_ARTS: 'CommonBuffId' = 232219 - CIVIC_POLICY_NPC_AUTONOMY_OLD_DAYS: 'CommonBuffId' = 237931 - CIVIC_POLICY_NPC_AUTONOMY_SELF_CARE: 'CommonBuffId' = 232220 - CIVIC_POLICY_NPC_AUTONOMY_SELF_SUFFICIENT: 'CommonBuffId' = 232221 - CIVIC_POLICY_NPC_AUTONOMY_TECHNOLOGICAL_PROGRESS: 'CommonBuffId' = 232222 - CIVIC_POLICY_NPC_VOTE_COOLDOWN: 'CommonBuffId' = 237019 - CIVIC_POLICY_PLAYER_TRACKING_AGGRESSION: 'CommonBuffId' = 237926 - CIVIC_POLICY_PLAYER_TRACKING_COMMUNAL_OWNERSHIP: 'CommonBuffId' = 237953 - CIVIC_POLICY_PLAYER_TRACKING_CREATIVE_ARTS: 'CommonBuffId' = 232157 - CIVIC_POLICY_PLAYER_TRACKING_ECO_FRIENDLY_APPLIANCES: 'CommonBuffId' = 232601 - CIVIC_POLICY_PLAYER_TRACKING_FREE_LOVE: 'CommonBuffId' = 237928 - CIVIC_POLICY_PLAYER_TRACKING_FUN_COMMUNITY: 'CommonBuffId' = 232158 - CIVIC_POLICY_PLAYER_TRACKING_HOME_COOKING: 'CommonBuffId' = 232159 - CIVIC_POLICY_PLAYER_TRACKING_JUICED_COMMUNITY: 'CommonBuffId' = 232160 - CIVIC_POLICY_PLAYER_TRACKING_MUSIC_ARTS: 'CommonBuffId' = 232161 - CIVIC_POLICY_PLAYER_TRACKING_OBJECT_BASED_GREEN_GARDENING: 'CommonBuffId' = 234851 - CIVIC_POLICY_PLAYER_TRACKING_OLD_DAYS: 'CommonBuffId' = 237927 - CIVIC_POLICY_PLAYER_TRACKING_SELF_CARE: 'CommonBuffId' = 232162 - CIVIC_POLICY_PLAYER_TRACKING_SELF_SUFFICIENT: 'CommonBuffId' = 232163 - CIVIC_POLICY_PLAYER_TRACKING_TECHNOLOGICAL_PROGRESS: 'CommonBuffId' = 232164 - CIVIC_POLICY_PLAYER_TRACKING_UPCYCLING_INITIATIVE: 'CommonBuffId' = 233506 - CIVIC_POLICY_SOCIAL_BUFF_CONVINCE_TO_INSTALL_FAIL_ACTOR: 'CommonBuffId' = 233753 - CIVIC_POLICY_SOCIAL_BUFF_CONVINCE_TO_INSTALL_FAIL_TARGET: 'CommonBuffId' = 233754 - CIVIC_POLICY_SOCIAL_BUFF_CONVINCE_TO_INSTALL_SUCCESS_TARGET: 'CommonBuffId' = 233756 - CIVIC_POLICY_SOCIAL_BUFF_CONVINCE_TO_INSTALL_SUCCESS_TARGET_REPLACEMENT: 'CommonBuffId' = 233755 - CIVIC_POLICY_SOCIAL_BUFF_CONVINCE_TO_INSTALL_SUPER_FAIL_ACTOR: 'CommonBuffId' = 233751 - CIVIC_POLICY_SOCIAL_BUFF_CONVINCE_TO_INSTALL_SUPER_FAIL_TARGET: 'CommonBuffId' = 233752 - CIVIC_POLICY_SOCIAL_BUFF_CONVINCE_TO_REPEAL_TARGET_ANGRY: 'CommonBuffId' = 239017 - CIVIC_POLICY_SOCIAL_BUFF_CONVINCE_TO_REPEAL_TARGET_BORED: 'CommonBuffId' = 239018 - CIVIC_POLICY_SOCIAL_BUFF_CONVINCE_TO_SUPPORT_FAIL_ACTOR: 'CommonBuffId' = 233758 - CIVIC_POLICY_SOCIAL_BUFF_CONVINCE_TO_SUPPORT_FAIL_TARGET: 'CommonBuffId' = 233757 - CIVIC_POLICY_SOCIAL_BUFF_CONVINCE_TO_SUPPORT_SUCCESS_ACTOR: 'CommonBuffId' = 233750 - CIVIC_POLICY_SOCIAL_BUFF_CONVINCE_TO_SUPPORT_SUCCESS_TARGET: 'CommonBuffId' = 233759 - CLAIM_CRIMINAL_MASTERMIND_TARGET: 'CommonBuffId' = 26681 - CLEANED_TOILET_ENERGIZED: 'CommonBuffId' = 10454 - CLEANING_HAPPY: 'CommonBuffId' = 24003 - CLEANING_SAD: 'CommonBuffId' = 24004 - CLIMBING_ROUTE_BEST_VIEWS_HARDEST_CLIMBS: 'CommonBuffId' = 246137 - CLIMBING_ROUTE_BREAKING_POINT_REACHED: 'CommonBuffId' = 246127 - CLIMBING_ROUTE_BREAKING_POINT_REACHED_AVERAGE: 'CommonBuffId' = 247173 - CLIMBING_ROUTE_BREAKING_POINT_REACHED_AVERAGE_TRACKER: 'CommonBuffId' = 250558 - CLIMBING_ROUTE_BREAKING_POINT_REACHED_MASTER: 'CommonBuffId' = 247172 - CLIMBING_ROUTE_BREAKING_POINT_REACHED_MASTER_TRACKER: 'CommonBuffId' = 250559 - CLIMBING_ROUTE_BREAKING_POINT_REACHED_NOVICE_TRACKER: 'CommonBuffId' = 250560 - CLIMBING_ROUTE_CANCEL_CLIMB: 'CommonBuffId' = 247205 - CLIMBING_ROUTE_CLIMB_TRACKING_AVERAGE_ATTEMPT: 'CommonBuffId' = 247166 - CLIMBING_ROUTE_CLIMB_TRACKING_AVERAGE_BREAKING_POINT: 'CommonBuffId' = 245479 - CLIMBING_ROUTE_CLIMB_TRACKING_AVERAGE_CAUTIOUSLY: 'CommonBuffId' = 247167 - CLIMBING_ROUTE_CLIMB_TRACKING_AVERAGE_COURAGEOUSLY: 'CommonBuffId' = 247168 - CLIMBING_ROUTE_CLIMB_TRACKING_AVERAGE_METICULOUS_SESSION: 'CommonBuffId' = 245480 - CLIMBING_ROUTE_CLIMB_TRACKING_AVERAGE_NORMALLY: 'CommonBuffId' = 247169 - CLIMBING_ROUTE_CLIMB_TRACKING_AVERAGE_PRACTICE: 'CommonBuffId' = 245477 - CLIMBING_ROUTE_CLIMB_TRACKING_MASTER_ATTEMPT: 'CommonBuffId' = 247170 - CLIMBING_ROUTE_CLIMB_TRACKING_MASTER_BREAKING_POINT: 'CommonBuffId' = 245481 - CLIMBING_ROUTE_CLIMB_TRACKING_MASTER_CAUTIOUSLY: 'CommonBuffId' = 247177 - CLIMBING_ROUTE_CLIMB_TRACKING_MASTER_COURAGEOUSLY: 'CommonBuffId' = 247179 - CLIMBING_ROUTE_CLIMB_TRACKING_MASTER_METICULOUS_SESSION: 'CommonBuffId' = 245483 - CLIMBING_ROUTE_CLIMB_TRACKING_MASTER_NORMALLY: 'CommonBuffId' = 247178 - CLIMBING_ROUTE_CLIMB_TRACKING_MASTER_PRACTICE: 'CommonBuffId' = 245484 - CLIMBING_ROUTE_CLIMB_TRACKING_NOVICE_BREAKING_POINT: 'CommonBuffId' = 245485 - CLIMBING_ROUTE_CLIMB_TRACKING_NOVICE_CAUTIOUSLY: 'CommonBuffId' = 247163 - CLIMBING_ROUTE_CLIMB_TRACKING_NOVICE_COURAGEOUSLY: 'CommonBuffId' = 247165 - CLIMBING_ROUTE_CLIMB_TRACKING_NOVICE_METICULOUS_SESSION: 'CommonBuffId' = 245486 - CLIMBING_ROUTE_CLIMB_TRACKING_NOVICE_NORMALLY: 'CommonBuffId' = 247164 - CLIMBING_ROUTE_CLIMB_TRACKING_NOVICE_PRACTICE: 'CommonBuffId' = 245487 - CLIMBING_ROUTE_DID_RECENT_CLIMB: 'CommonBuffId' = 252875 - CLIMBING_ROUTE_EXCELS_AT_ELEVATING: 'CommonBuffId' = 246123 - CLIMBING_ROUTE_EXCELS_AT_ELEVATING_TRACKER: 'CommonBuffId' = 250575 - CLIMBING_ROUTE_FAILED_GRIP_SLIP: 'CommonBuffId' = 246119 - CLIMBING_ROUTE_FAILED_SLIP_GRIP_TRACKER: 'CommonBuffId' = 250573 - CLIMBING_ROUTE_FIGHTING_GRAVITY: 'CommonBuffId' = 246135 - CLIMBING_ROUTE_LESS_TALK_MORE_CHALK: 'CommonBuffId' = 246118 - CLIMBING_ROUTE_LESS_TALK_MORE_CHALK_TRACKER: 'CommonBuffId' = 250572 - CLIMBING_ROUTE_LIFE_ON_THE_ROCKS: 'CommonBuffId' = 246126 - CLIMBING_ROUTE_MORE_STRUGGLE_MORE_PROGRESS: 'CommonBuffId' = 246136 - CLIMBING_ROUTE_MOVING_UP: 'CommonBuffId' = 246121 - CLIMBING_ROUTE_NATURAL_BORN_CLIMBER: 'CommonBuffId' = 246134 - CLIMBING_ROUTE_NEVER_LOOK_DOWN: 'CommonBuffId' = 246132 - CLIMBING_ROUTE_NOT_READY_YET: 'CommonBuffId' = 246129 - CLIMBING_ROUTE_NOT_READY_YET_TRACKER: 'CommonBuffId' = 250570 - CLIMBING_ROUTE_OUTCOME_TRACKING_FAILURE: 'CommonBuffId' = 250494 - CLIMBING_ROUTE_OUTCOME_TRACKING_LARGE_FAILURE: 'CommonBuffId' = 250495 - CLIMBING_ROUTE_OUTCOME_TRACKING_LARGE_SUCCESS: 'CommonBuffId' = 250493 - CLIMBING_ROUTE_OUTCOME_TRACKING_SUCCESS: 'CommonBuffId' = 250492 - CLIMBING_ROUTE_PEAK_FAILURE: 'CommonBuffId' = 246125 - CLIMBING_ROUTE_PEAK_FAILURE_TRACKER: 'CommonBuffId' = 250577 - CLIMBING_ROUTE_PEAK_TRAINING: 'CommonBuffId' = 246122 - CLIMBING_ROUTE_PEAK_TRAINING_AVERAGE: 'CommonBuffId' = 247193 - CLIMBING_ROUTE_PEAK_TRAINING_AVERAGE_TRACKER: 'CommonBuffId' = 250561 - CLIMBING_ROUTE_PEAK_TRAINING_MASTER: 'CommonBuffId' = 247194 - CLIMBING_ROUTE_PEAK_TRAINING_MASTER_TRACKER: 'CommonBuffId' = 250562 - CLIMBING_ROUTE_PEAK_TRAINING_NOVICE_TRACKER: 'CommonBuffId' = 250563 - CLIMBING_ROUTE_PRACTICE_NOT_MAKE_PERFECT: 'CommonBuffId' = 246124 - CLIMBING_ROUTE_PRACTICE_NOT_MAKE_PERFECT_TRACKER: 'CommonBuffId' = 250576 - CLIMBING_ROUTE_REACHING_NEW_HEIGHTS: 'CommonBuffId' = 246131 - CLIMBING_ROUTE_REACHING_ROCK_BOTTOM: 'CommonBuffId' = 246120 - CLIMBING_ROUTE_REACHING_ROCK_BOTTOM_TRACKER: 'CommonBuffId' = 250574 - CLIMBING_ROUTE_RECENT_EXTREME_SUCCESS: 'CommonBuffId' = 252873 - CLIMBING_ROUTE_ROCKSTAR: 'CommonBuffId' = 246138 - CLIMBING_ROUTE_SKILL_GAIN_LARGE: 'CommonBuffId' = 246114 - CLIMBING_ROUTE_SKILL_GAIN_SMALL: 'CommonBuffId' = 245998 - CLIMBING_ROUTE_SLOW_AND_STEADY: 'CommonBuffId' = 246117 - CLIMBING_ROUTE_SLOW_AND_STEADY_AVERAGE: 'CommonBuffId' = 247198 - CLIMBING_ROUTE_SLOW_AND_STEADY_AVERAGE_TRACKER: 'CommonBuffId' = 250564 - CLIMBING_ROUTE_SLOW_AND_STEADY_MASTER: 'CommonBuffId' = 247199 - CLIMBING_ROUTE_SLOW_AND_STEADY_MASTER_TRACKER: 'CommonBuffId' = 250565 - CLIMBING_ROUTE_SLOW_AND_STEADY_NOVICE_TRACKER: 'CommonBuffId' = 250566 - CLIMBING_ROUTE_SPECTACULAR_CLIMBING: 'CommonBuffId' = 246128 - CLIMBING_ROUTE_SPECTACULAR_CLIMBING_TRACKER: 'CommonBuffId' = 250568 - CLIMBING_ROUTE_SUMMITOR_PLUMMET: 'CommonBuffId' = 246130 - CLIMBING_ROUTE_SUMMITOR_PLUMMET_TRACKER: 'CommonBuffId' = 250571 - CLIMBING_ROUTE_TIME_TO_ROCK: 'CommonBuffId' = 246133 - CLONING_MACHINE_FAILURE_GOATEE: 'CommonBuffId' = 115351 - CLOTHING_ANGRY_LION: 'CommonBuffId' = 33344 - CLOTHING_CATEGORY_TEMPERATURE_COLD_CLOTHING: 'CommonBuffId' = 182695 - CLOTHING_CATEGORY_TEMPERATURE_HOT_CLOTHING: 'CommonBuffId' = 182696 - CLOTHING_CATEGORY_TEMPERATURE_IMMUNE: 'CommonBuffId' = 182697 - CLOTHING_CATEGORY_TEMPERATURE_MODIFIER: 'CommonBuffId' = 190002 - CLOTHING_DAZED_BEAR: 'CommonBuffId' = 33347 - CLOTHING_ENERGIZED_OWL: 'CommonBuffId' = 33348 - CLOTHING_FLIRTY_COW: 'CommonBuffId' = 33342 - CLOTHING_HAT_OF_SHAME: 'CommonBuffId' = 40360 - CLOTHING_HYSTERICAL_TIGER: 'CommonBuffId' = 33346 - CLOTHING_INSPIRED_CHICKEN: 'CommonBuffId' = 33343 - CLOTHING_NUDE: 'CommonBuffId' = 128807 - CLOTHING_NUDE_TODDLER: 'CommonBuffId' = 157429 - CLOTHING_SAD_PANDA: 'CommonBuffId' = 33345 - CLOTHING_STAR_SPANGLED_GLASSES: 'CommonBuffId' = 100126 - CLOTHING_SUIT_OF_LOVE: 'CommonBuffId' = 40352 - CLOTHING_TICKLE_ME_PINK: 'CommonBuffId' = 40356 - CLOTHING_TRAGIC_CLOWN_MISERY_LOVES_COMPANY: 'CommonBuffId' = 139614 - CLOTHING_TRAGIC_CLOWN_TEARS_OF_A_CLOWN: 'CommonBuffId' = 139611 - CLUBS_BAD_CLUB_MEMBER: 'CommonBuffId' = 123823 - CLUBS_BROKE_A_RULE: 'CommonBuffId' = 123790 - CLUBS_BROKE_A_RULE_APPLIED_AFTER_INTERACTION_COMPLETES: 'CommonBuffId' = 130470 - CLUBS_FAILED_GAMBIT: 'CommonBuffId' = 123821 - CLUBS_INSECURE_THRONE: 'CommonBuffId' = 123822 - CLUBS_PASSED_THE_TORCH: 'CommonBuffId' = 123820 - CLUBS_PERKS_SOCIAL_BONUS_FRIENDLY: 'CommonBuffId' = 126042 - CLUBS_PERKS_SOCIAL_BONUS_FUNNY: 'CommonBuffId' = 126045 - CLUBS_PERKS_SOCIAL_BONUS_MEAN: 'CommonBuffId' = 126046 - CLUBS_PERKS_SOCIAL_BONUS_MISCHIEF: 'CommonBuffId' = 126044 - CLUBS_PERKS_SOCIAL_BONUS_ROMANTIC: 'CommonBuffId' = 126043 - CLUBS_REJECTED: 'CommonBuffId' = 123824 - CLUBS_TORCH_PASSED: 'CommonBuffId' = 123819 - CLUB_GATHERING_ADD_NPC_INVITE_COOLDOWN: 'CommonBuffId' = 130394 - CLUB_GATHERING_NPC_INVITE_COOLDOWN: 'CommonBuffId' = 130392 - CLUB_GATHERING_PROVIDED_AFFORDANCE: 'CommonBuffId' = 193128 - CLUB_PERKS_INFAMOUS_CLUB_INTIMIDATED_BY_CLUB_MEMBER: 'CommonBuffId' = 126311 - CLUB_PERKS_POPULAR_CLUB_AWED_BY_CLUB_MEMBER: 'CommonBuffId' = 126125 - CLUB_PERKS_SET_VIBE_AMONG_COMRADES_1: 'CommonBuffId' = 126064 - CLUB_PERKS_SET_VIBE_AMONG_COMRADES_2: 'CommonBuffId' = 126065 - CLUB_PERKS_SET_VIBE_AMONG_COMRADES_3: 'CommonBuffId' = 126066 - CLUB_PERKS_SET_VIBE_ANGRY_1: 'CommonBuffId' = 126053 - CLUB_PERKS_SET_VIBE_ANGRY_2: 'CommonBuffId' = 126054 - CLUB_PERKS_SET_VIBE_ANGRY_3: 'CommonBuffId' = 126052 - CLUB_PERKS_SET_VIBE_CONFIDENT_1: 'CommonBuffId' = 126056 - CLUB_PERKS_SET_VIBE_CONFIDENT_2: 'CommonBuffId' = 126057 - CLUB_PERKS_SET_VIBE_CONFIDENT_3: 'CommonBuffId' = 126058 - CLUB_PERKS_SET_VIBE_ENERGIZED_1: 'CommonBuffId' = 126060 - CLUB_PERKS_SET_VIBE_ENERGIZED_2: 'CommonBuffId' = 126061 - CLUB_PERKS_SET_VIBE_ENERGIZED_3: 'CommonBuffId' = 126062 - CLUB_PERKS_SET_VIBE_FLIRTY_1: 'CommonBuffId' = 126068 - CLUB_PERKS_SET_VIBE_FLIRTY_2: 'CommonBuffId' = 126069 - CLUB_PERKS_SET_VIBE_FLIRTY_3: 'CommonBuffId' = 126070 - CLUB_PERKS_SET_VIBE_FOCUSED_1: 'CommonBuffId' = 126072 - CLUB_PERKS_SET_VIBE_FOCUSED_2: 'CommonBuffId' = 126073 - CLUB_PERKS_SET_VIBE_FOCUSED_3: 'CommonBuffId' = 126074 - CLUB_PERKS_SET_VIBE_INSPIRED_1: 'CommonBuffId' = 126076 - CLUB_PERKS_SET_VIBE_INSPIRED_2: 'CommonBuffId' = 126077 - CLUB_PERKS_SET_VIBE_INSPIRED_3: 'CommonBuffId' = 126078 - CLUB_PERKS_SET_VIBE_PLAYFUL_1: 'CommonBuffId' = 126080 - CLUB_PERKS_SET_VIBE_PLAYFUL_2: 'CommonBuffId' = 126081 - CLUB_PERKS_SET_VIBE_PLAYFUL_3: 'CommonBuffId' = 126082 - CLUB_PERKS_SET_VIBE_SAD_1: 'CommonBuffId' = 126084 - CLUB_PERKS_SET_VIBE_SAD_2: 'CommonBuffId' = 126085 - CLUB_PERKS_SET_VIBE_SAD_3: 'CommonBuffId' = 126086 - CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_ACTING: 'CommonBuffId' = 201034 - CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_ARCHAEOLOGY: 'CommonBuffId' = 174280 - CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_BAKING: 'CommonBuffId' = 126252 - CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_BARTENDING: 'CommonBuffId' = 125834 - CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_CHARISMA: 'CommonBuffId' = 125872 - CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_COMEDY: 'CommonBuffId' = 125880 - CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_DJ: 'CommonBuffId' = 125881 - CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_DOG_TRAINING: 'CommonBuffId' = 170916 - CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_EQUESTRIAN_SKILL: 'CommonBuffId' = 332925 - CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_FABRICATION: 'CommonBuffId' = 231943 - CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_FISHING: 'CommonBuffId' = 125882 - CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_FITNESS: 'CommonBuffId' = 125883 - CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_FLOWER_ARRANGING: 'CommonBuffId' = 190030 - CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_GARDENING: 'CommonBuffId' = 125884 - CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_GOURMET_COOKING: 'CommonBuffId' = 125885 - CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_GUITAR: 'CommonBuffId' = 125886 - CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_HANDINESS: 'CommonBuffId' = 125888 - CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_HERBALISM: 'CommonBuffId' = 126267 - CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_HOME_STYLE_COOKING: 'CommonBuffId' = 125889 - CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_KNITTING: 'CommonBuffId' = 242249 - CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_LOGIC: 'CommonBuffId' = 125891 - CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_MISCHIEF: 'CommonBuffId' = 125892 - CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_PAINTING: 'CommonBuffId' = 125894 - CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_PARENTING: 'CommonBuffId' = 165915 - CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_PIANO: 'CommonBuffId' = 125896 - CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_PROGRAMMING: 'CommonBuffId' = 125897 - CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_RESEARCH_DEBATE: 'CommonBuffId' = 229649 - CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_ROBOTICS: 'CommonBuffId' = 219168 - CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_ROCKET_SCIENCE: 'CommonBuffId' = 125899 - CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_ROCK_CLIMBING: 'CommonBuffId' = 253671 - CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_ROMANCE: 'CommonBuffId' = 393392 - CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_SINGING: 'CommonBuffId' = 151916 - CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_SKIING: 'CommonBuffId' = 246489 - CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_SNOWBOARD: 'CommonBuffId' = 246796 - CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_VETERINARIAN: 'CommonBuffId' = 170915 - CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_VIDEO_GAMING: 'CommonBuffId' = 125900 - CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_VIOLIN: 'CommonBuffId' = 125902 - CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_WELLNESS: 'CommonBuffId' = 128403 - CLUB_PERKS_SKILL_BOOST_ADULT_MAJOR_WRITING: 'CommonBuffId' = 125906 - CLUB_PERKS_SKILL_BOOST_ADULT_MINOR_BOWLING: 'CommonBuffId' = 163340 - CLUB_PERKS_SKILL_BOOST_ADULT_MINOR_CROSS_STITCH: 'CommonBuffId' = 263767 - CLUB_PERKS_SKILL_BOOST_ADULT_MINOR_DANCING: 'CommonBuffId' = 128399 - CLUB_PERKS_SKILL_BOOST_ADULT_MINOR_JUICE_FIZZING: 'CommonBuffId' = 239068 - CLUB_PERKS_SKILL_BOOST_ADULT_MINOR_LOCAL_CULTURE: 'CommonBuffId' = 182983 - CLUB_PERKS_SKILL_BOOST_ADULT_MINOR_MEDIA_PRODUCTION: 'CommonBuffId' = 201031 - CLUB_PERKS_SKILL_BOOST_ADULT_MINOR_PHOTOGRAPHY: 'CommonBuffId' = 126250 - CLUB_PERKS_SKILL_BOOST_CHILD_CREATIVITY: 'CommonBuffId' = 125912 - CLUB_PERKS_SKILL_BOOST_CHILD_MENTAL: 'CommonBuffId' = 125915 - CLUB_PERKS_SKILL_BOOST_CHILD_MOTOR: 'CommonBuffId' = 125916 - CLUB_PERKS_SKILL_BOOST_CHILD_SOCIAL: 'CommonBuffId' = 125920 - COFFEE_UPGRADED: 'CommonBuffId' = 23830 - COFFIN_HUMAN_NIGHTMARE: 'CommonBuffId' = 154766 - COFFIN_VAMPIRE_DAY_MARE: 'CommonBuffId' = 154767 - COFFIN_VAMPIRE_GOOD_DREAM: 'CommonBuffId' = 154768 - COLLECTION_CASE_VIEW_FOCUSED: 'CommonBuffId' = 180428 - COLLEGE_ORGANIZATION_ART_SOCIETY_RANK_3: 'CommonBuffId' = 223666 - COLLEGE_ORGANIZATION_DEBATE_DECLARE_WINNER: 'CommonBuffId' = 225667 - COLLEGE_ORGANIZATION_DEBATE_EXTRA_CREDIT_COOLDOWN: 'CommonBuffId' = 229377 - COLLEGE_ORGANIZATION_EVENTS_SOCIAL_COUNTER: 'CommonBuffId' = 223955 - COLLEGE_ORGANIZATION_EVENTS_SOCIAL_COUNTER_ADD_ORG_PROGRESS: 'CommonBuffId' = 223964 - COLLEGE_ORGANIZATION_HONOR_SOCIETY_EXTRA_CREDIT_COOLDOWN: 'CommonBuffId' = 229573 - COLLEGE_ORGANIZATION_HONOR_SOCIETY_RANK3: 'CommonBuffId' = 226892 - COLLEGE_ORGANIZATION_ROBOTICS_RANK3: 'CommonBuffId' = 223083 - COLLEGE_ORGANIZATION_SCHOOL_SPIRIT_PARTY_STREAK_COOLDOWN: 'CommonBuffId' = 225224 - COLLEGE_ORGANIZATION_SECRET_SOCIETY_ATTACK_COOLDOWN: 'CommonBuffId' = 227357 - COLLEGE_ORGANIZATION_SECRET_SOCIETY_FEELING_GUILTY: 'CommonBuffId' = 219080 - COLLEGE_ORGANIZATION_SECRET_SOCIETY_FEELING_GUILTY_HIDDEN: 'CommonBuffId' = 219296 - COLLEGE_ORGANIZATION_SECRET_SOCIETY_FEELING_GUILTY_IN_NEGATIVE: 'CommonBuffId' = 221761 - COLLEGE_ORGANIZATION_SECRET_SOCIETY_JOIN_VISIT_MARKED: 'CommonBuffId' = 222708 - COLLEGE_ORGANIZATION_SECRET_SOCIETY_NPC_OFFERING_COOLDOWN: 'CommonBuffId' = 222671 - COLLEGE_ORGANIZATION_SECRET_SOCIETY_NPC_RANDOM_LOOT: 'CommonBuffId' = 221525 - COLLEGE_ORGANIZATION_SECRET_SOCIETY_RITUAL_IN_ROBE: 'CommonBuffId' = 230284 - COLLEGE_ORGANIZATION_SECRET_SOCIETY_SPRITE_ENERGETIC: 'CommonBuffId' = 219240 - COLLEGE_ORGANIZATION_SECRET_SOCIETY_SPRITE_FLIRTY: 'CommonBuffId' = 219239 - COLLEGE_ORGANIZATION_SECRET_SOCIETY_SPRITE_FOCUSED: 'CommonBuffId' = 219082 - COLLEGE_ORGANIZATION_SECRET_SOCIETY_SPRITE_HAPPY: 'CommonBuffId' = 219081 - COLLEGE_ORGANIZATION_SECRET_SOCIETY_SPRITE_INSPIRED: 'CommonBuffId' = 219083 - COLLEGE_ORGANIZATION_SECRET_SOCIETY_SPRITE_TENSE: 'CommonBuffId' = 219079 - COLLEGE_ORGANIZATION_SECRET_SOCIETY_SPRITE_TENSE_NONMEMBER: 'CommonBuffId' = 227439 - COLLEGE_ORGANIZATION_SECRET_SOCIETY_SPRITE_VISITOR: 'CommonBuffId' = 226734 - COLLEGE_ORGANIZATION_SECRET_SOCIETY_SPRITE_VISITOR_COOLDOWN: 'CommonBuffId' = 226819 - COLLEGE_ORGANIZATION_SECRET_SOCIETY_SUMMON_COOLDOWN: 'CommonBuffId' = 220517 - COMMUNAL_EVENTS_ANIMAL_DAY_ROLE_GUESTS: 'CommonBuffId' = 331504 - COMMUNAL_EVENTS_ANIMAL_DAY_ROLE_HOST: 'CommonBuffId' = 331503 - COMMUNAL_EVENTS_ANIMAL_DAY_ROLE_RANCH_HELPER: 'CommonBuffId' = 331505 - COMMUNAL_EVENTS_GUESTS_HAVE_MET_HOST: 'CommonBuffId' = 331489 - COMMUNAL_EVENTS_RANCH_GATHERING_ROLE_GRILL_MASTER: 'CommonBuffId' = 338333 - COMMUNAL_EVENTS_RANCH_GATHERING_ROLE_GUESTS: 'CommonBuffId' = 338331 - COMMUNAL_EVENTS_RANCH_GATHERING_ROLE_HOST: 'CommonBuffId' = 338332 - COMMUNITY_BOARD_HORSE_REMOVE_RIDER_BEFORE_RABBITHOLE: 'CommonBuffId' = 348308 - COMMUNITY_CLOSENESS_CIVIC_POLICY_CALL_NOT_VOTING_SHAME: 'CommonBuffId' = 238048 - COMMUNITY_CLOSENESS_COMPLAIN_SHUNNED: 'CommonBuffId' = 238147 - COMMUNITY_CLOSENESS_GOGREEN_RECYCLING_TIME: 'CommonBuffId' = 232980 - COMMUNITY_CLOSENESS_IN_HERITENCE_MARRIED_FOR_MONEY: 'CommonBuffId' = 233023 - COMMUNITY_CLOSENESS_LANDGRAB_POWER_CURSE_YOU_LANDGRAB: 'CommonBuffId' = 233034 - COMMUNITY_CLOSENESS_LANDGRAB_POWER_HIDDEN_DISCOUNT: 'CommonBuffId' = 233066 - COMMUNITY_CLOSENESS_PARENTAL_CHECK_IN_HIDDEN_VISIT_CHECK: 'CommonBuffId' = 238044 - COMMUNITY_CLOSENESS_PARENTAL_CHECK_IN_MISSED_PARENTS: 'CommonBuffId' = 238043 - COMMUNITY_CLOSENESS_PRANK_CALL_PRANK_CALLED: 'CommonBuffId' = 233030 - COMMUNITY_CLOSENESS_SIM_TOCK_WEIRD_MEMES: 'CommonBuffId' = 238042 - COMMUNITY_CLOSENESS_TELEMARKETER_HAPPY_SIM: 'CommonBuffId' = 233031 - COMMUNITY_CLOSENESS_THE_MOTIVE_GAMES_LOSER: 'CommonBuffId' = 235127 - COMMUNITY_CLOSENESS_THE_MOTIVE_GAMES_WINNER: 'CommonBuffId' = 233035 - COMMUNITY_CLOSENESS_THE_SIMULATION_ONLY_A_SIM: 'CommonBuffId' = 233032 - COMMUNITY_CLOSENESS_THE_SIMULATION_WOAH: 'CommonBuffId' = 233033 - COMPASSIONATE_DID_MEAN_SOCIAL: 'CommonBuffId' = 162036 - COMPASSIONATE_EMOTIONS_CALMED: 'CommonBuffId' = 160910 - COMPASSIONATE_SHARE_ANGRY: 'CommonBuffId' = 160916 - COMPASSIONATE_SHARE_EMBARRASSED: 'CommonBuffId' = 160918 - COMPASSIONATE_SHARE_SAD: 'CommonBuffId' = 160917 - COMPASSIONATE_SHARE_STRESSED: 'CommonBuffId' = 160919 - COMPUTER_GLASSES_APPEARANCE_WEARING_BLUE: 'CommonBuffId' = 225099 - COMPUTER_GLASSES_APPEARANCE_WEARING_GREEN: 'CommonBuffId' = 225100 - COMPUTER_GLASSES_APPEARANCE_WEARING_ORANGE: 'CommonBuffId' = 225149 - COMPUTER_GLASSES_APPEARANCE_WEARING_PINK: 'CommonBuffId' = 225098 - COMPUTER_GLASSES_APPEARANCE_WEARING_RED: 'CommonBuffId' = 224990 - COMPUTER_GLASSES_APPEARANCE_WEARING_YELLOW: 'CommonBuffId' = 225153 - CONFIDENCE_BELIEF_BREEDS_CONFIDENCE: 'CommonBuffId' = 307444 - CONFIDENCE_FEELING_DISCOURAGED: 'CommonBuffId' = 307441 - CONFIDENCE_FEELING_ENCOURAGED: 'CommonBuffId' = 307443 - CONFIDENCE_HIGH_CONFIDENCE_BOOST: 'CommonBuffId' = 306787 - CONFIDENCE_HIGH_IVE_GOT_THIS: 'CommonBuffId' = 306784 - CONFIDENCE_HIGH_I_BELIEVE_IN_ME: 'CommonBuffId' = 306785 - CONFIDENCE_HIGH_LEARNING_FROM_MISTAKES: 'CommonBuffId' = 306786 - CONFIDENCE_LOW_CRUSHED: 'CommonBuffId' = 306793 - CONFIDENCE_LOW_ILL_NEVER: 'CommonBuffId' = 306792 - CONFIDENCE_NEUTRAL_I_CAN: 'CommonBuffId' = 306791 - CONFIDENCE_NEUTRAL_I_CANNOT: 'CommonBuffId' = 306790 - CONFIDENCE_SUPPORTED_DRIVE: 'CommonBuffId' = 307445 - CONFIDENCE_UNFAIR_CRITICISM: 'CommonBuffId' = 307442 - CONFIDENT_BRAG_ABOUT_STARTUP: 'CommonBuffId' = 37296 - CONFIDENT_BY_POTION: 'CommonBuffId' = 26332 - CONFIDENT_DISCUSS_CONQUESTS: 'CommonBuffId' = 37010 - CONFIDENT_MAD_SKILLZ: 'CommonBuffId' = 31550 - CONFIDENT_SO_SNEAKY: 'CommonBuffId' = 36392 - CONSTELLATION_FORMATIONS: 'CommonBuffId' = 107388 - COOLDOWN_REPUTATION_DONATION: 'CommonBuffId' = 201973 - CORE_SOCIAL_ANGRY: 'CommonBuffId' = 10647 - CORE_SOCIAL_BORED: 'CommonBuffId' = 10653 - CORE_SOCIAL_EMBARRASSING: 'CommonBuffId' = 10651 - CORE_SOCIAL_FLIRTY: 'CommonBuffId' = 10658 - CORE_SOCIAL_HAPPY: 'CommonBuffId' = 10655 - CORE_SOCIAL_HAPPY_OUTGOING: 'CommonBuffId' = 29578 - CORE_SOCIAL_PLAYFUL: 'CommonBuffId' = 10649 - COSTUME_BOX_COSTUME_AAYLA_SECURA: 'CommonBuffId' = 361437 - COSTUME_BOX_COSTUME_ALIEN: 'CommonBuffId' = 364648 - COSTUME_BOX_COSTUME_APRON: 'CommonBuffId' = 361394 - COSTUME_BOX_COSTUME_ASTRONAUT: 'CommonBuffId' = 361424 - COSTUME_BOX_COSTUME_BEAR: 'CommonBuffId' = 365429 - COSTUME_BOX_COSTUME_BOBA_FETT: 'CommonBuffId' = 361432 - COSTUME_BOX_COSTUME_BUNNY: 'CommonBuffId' = 365092 - COSTUME_BOX_COSTUME_BUTLER: 'CommonBuffId' = 365482 - COSTUME_BOX_COSTUME_BUTLER_FLIRTY: 'CommonBuffId' = 371452 - COSTUME_BOX_COSTUME_CATFISH: 'CommonBuffId' = 381081 - COSTUME_BOX_COSTUME_CHEERLEADER: 'CommonBuffId' = 361428 - COSTUME_BOX_COSTUME_CLOWN: 'CommonBuffId' = 361418 - COSTUME_BOX_COSTUME_CUPID: 'CommonBuffId' = 361395 - COSTUME_BOX_COSTUME_DARTH_MAUL: 'CommonBuffId' = 361431 - COSTUME_BOX_COSTUME_DARTH_VADER: 'CommonBuffId' = 361430 - COSTUME_BOX_COSTUME_DOCTOR: 'CommonBuffId' = 364649 - COSTUME_BOX_COSTUME_EGGPLANT: 'CommonBuffId' = 361425 - COSTUME_BOX_COSTUME_FAIRY: 'CommonBuffId' = 365108 - COSTUME_BOX_COSTUME_FATHER_WINTER: 'CommonBuffId' = 365091 - COSTUME_BOX_COSTUME_FIREFIGHTER: 'CommonBuffId' = 361419 - COSTUME_BOX_COSTUME_FIREFIGHTER_FLIRTY: 'CommonBuffId' = 370426 - COSTUME_BOX_COSTUME_GNOME: 'CommonBuffId' = 365093 - COSTUME_BOX_COSTUME_GRIM_REAPER: 'CommonBuffId' = 361421 - COSTUME_BOX_COSTUME_HOT_DOG: 'CommonBuffId' = 361417 - COSTUME_BOX_COSTUME_KNIGHT: 'CommonBuffId' = 365156 - COSTUME_BOX_COSTUME_LUCHADOR: 'CommonBuffId' = 361427 - COSTUME_BOX_COSTUME_LUKE_SKYWALKER: 'CommonBuffId' = 361435 - COSTUME_BOX_COSTUME_MAID: 'CommonBuffId' = 361422 - COSTUME_BOX_COSTUME_MAID_FLIRTY: 'CommonBuffId' = 370425 - COSTUME_BOX_COSTUME_MAILMAN: 'CommonBuffId' = 361423 - COSTUME_BOX_COSTUME_MASCOT: 'CommonBuffId' = 365433 - COSTUME_BOX_COSTUME_MASCOT_2: 'CommonBuffId' = 394379 - COSTUME_BOX_COSTUME_MASK: 'CommonBuffId' = 372334 - COSTUME_BOX_COSTUME_NINJA: 'CommonBuffId' = 365106 - COSTUME_BOX_COSTUME_PANDA: 'CommonBuffId' = 364500 - COSTUME_BOX_COSTUME_PARK_RANGER: 'CommonBuffId' = 370424 - COSTUME_BOX_COSTUME_PEACH: 'CommonBuffId' = 361426 - COSTUME_BOX_COSTUME_PIRATE: 'CommonBuffId' = 365104 - COSTUME_BOX_COSTUME_PIZZA_DELIVERY: 'CommonBuffId' = 361429 - COSTUME_BOX_COSTUME_POLICE: 'CommonBuffId' = 364650 - COSTUME_BOX_COSTUME_PRINCESS_LEIA: 'CommonBuffId' = 361438 - COSTUME_BOX_COSTUME_RACOON: 'CommonBuffId' = 364501 - COSTUME_BOX_COSTUME_RANCH_HAND: 'CommonBuffId' = 363131 - COSTUME_BOX_COSTUME_ROBOT: 'CommonBuffId' = 361420 - COSTUME_BOX_COSTUME_SKELETON: 'CommonBuffId' = 365161 - COSTUME_BOX_COSTUME_SMUGGLER: 'CommonBuffId' = 361434 - COSTUME_BOX_COSTUME_SPACE_RANGER: 'CommonBuffId' = 361433 - COSTUME_BOX_COSTUME_SPARTAN: 'CommonBuffId' = 365105 - COSTUME_BOX_COSTUME_VICTORIAN: 'CommonBuffId' = 364634 - COSTUME_BOX_COSTUME_VILLAIN: 'CommonBuffId' = 361439 - COSTUME_BOX_COSTUME_WITCH: 'CommonBuffId' = 365109 - COSTUME_BOX_TIMER_CONFIDENT: 'CommonBuffId' = 361932 - COSTUME_BOX_TIMER_FLIRTY: 'CommonBuffId' = 363012 - COSTUME_BOX_TIMER_PLAYFUL: 'CommonBuffId' = 363011 - COTTAGE_WORLD_GOSSIPER_GO_TO_SQUARE_COOLDOWN: 'CommonBuffId' = 264562 - COTTAGE_WORLD_MUSIC_IN_THE_WOODS: 'CommonBuffId' = 267048 - COTTAGE_WORLD_NPC_FREE_DRINK_COOLDOWN: 'CommonBuffId' = 266868 - COTTAGE_WORLD_NPC_MYSTERY_BOX_COOLDOWN_GARDEN: 'CommonBuffId' = 267082 - COTTAGE_WORLD_NPC_MYSTERY_BOX_COOLDOWN_GROCERY: 'CommonBuffId' = 267083 - COTTAGE_WORLD_NPC_OFFER_FAVOR_COOLDOWN: 'CommonBuffId' = 265102 - COTTAGE_WORLD_NPC_RECEIVE_FAVOR_COOLDOWN: 'CommonBuffId' = 265103 - COTTAGE_WORLD_PROXIMITY_RUINS_CONFIDENT: 'CommonBuffId' = 268099 - COTTAGE_WORLD_PROXIMITY_RUINS_HIDDEN: 'CommonBuffId' = 268541 - COTTAGE_WORLD_PROXIMITY_WATERFULL_INSPIRED: 'CommonBuffId' = 268101 - COTTAGE_WORLD_SNAIL_AUTONOMOUS_COOLDOWN: 'CommonBuffId' = 268424 - COW_PLANT_ESSENCE_ANGRY: 'CommonBuffId' = 8666 - COW_PLANT_ESSENCE_BORED: 'CommonBuffId' = 8667 - COW_PLANT_ESSENCE_CONFIDENT: 'CommonBuffId' = 8668 - COW_PLANT_ESSENCE_EMBARRASSED: 'CommonBuffId' = 8669 - COW_PLANT_ESSENCE_ENERGIZED: 'CommonBuffId' = 8671 - COW_PLANT_ESSENCE_FLIRTY: 'CommonBuffId' = 8672 - COW_PLANT_ESSENCE_FOCUSED: 'CommonBuffId' = 8673 - COW_PLANT_ESSENCE_HAPPY: 'CommonBuffId' = 8674 - COW_PLANT_ESSENCE_INSPIRED: 'CommonBuffId' = 8675 - COW_PLANT_ESSENCE_LIFE: 'CommonBuffId' = 29987 - COW_PLANT_ESSENCE_PLAYFUL: 'CommonBuffId' = 8676 - COW_PLANT_ESSENCE_SAD: 'CommonBuffId' = 8677 - COW_PLANT_ESSENCE_SLOSHED: 'CommonBuffId' = 8678 - COW_PLANT_ESSENCE_STRESSED: 'CommonBuffId' = 8679 - COW_PLANT_ESSENCE_UNCOMFORTABLE: 'CommonBuffId' = 8680 - CRISP_AIR: 'CommonBuffId' = 108250 - CRISP_AIR_LOVES_OUTDOORS: 'CommonBuffId' = 108256 - CROSS_AGE_INTERACTIONS_CALL_THEM_SOMETHING_MEAN: 'CommonBuffId' = 316220 - CROSS_AGE_INTERACTIONS_CLAIM_ARE_ALIEN: 'CommonBuffId' = 316175 - CROSS_AGE_INTERACTIONS_CLAIM_ARE_HUMAN: 'CommonBuffId' = 316176 - CROSS_AGE_INTERACTIONS_CLAIM_ARE_PLANT_SIM: 'CommonBuffId' = 316174 - CROSS_AGE_INTERACTIONS_CLAIM_FAILED: 'CommonBuffId' = 316177 - CROSS_AGE_INTERACTIONS_DISAPPROVE_LACK_OF_CHILD_DISCIPLINE: 'CommonBuffId' = 312466 - CROSS_AGE_INTERACTIONS_DISAPPROVE_OF_CHILD_DISCIPLINING: 'CommonBuffId' = 312464 - CROSS_AGE_INTERACTIONS_ENTHUSE_ABOUT_NEW_SIBLING: 'CommonBuffId' = 316442 - CROSS_AGE_INTERACTIONS_FAMILY_KISS_LOCKOUT: 'CommonBuffId' = 329904 - CROSS_AGE_INTERACTIONS_FOUND_PARENT: 'CommonBuffId' = 312923 - CROSS_AGE_INTERACTIONS_GOOD_TIMES: 'CommonBuffId' = 314197 - CROSS_AGE_INTERACTIONS_MAKE_SCARY_FACE: 'CommonBuffId' = 316221 - CROSS_AGE_INTERACTIONS_MOAN_ABOUT_NEW_SIBLING: 'CommonBuffId' = 316441 - CROSS_AGE_INTERACTIONS_NOT_PICKED_UP: 'CommonBuffId' = 316714 - CROSS_AGE_INTERACTIONS_NOT_THE_FAVORITE: 'CommonBuffId' = 314029 - CROSS_AGE_INTERACTIONS_PICKED_UP: 'CommonBuffId' = 316713 - CROSS_AGE_INTERACTIONS_SAGE_ADVICE_BORED: 'CommonBuffId' = 313657 - CROSS_AGE_INTERACTIONS_SAGE_ADVICE_FAMILY: 'CommonBuffId' = 313249 - CROSS_AGE_INTERACTIONS_SAGE_ADVICE_FRIENDSHIP: 'CommonBuffId' = 313248 - CROSS_AGE_INTERACTIONS_SAGE_ADVICE_HARD_WORK: 'CommonBuffId' = 313252 - CROSS_AGE_INTERACTIONS_SAGE_ADVICE_LOVE: 'CommonBuffId' = 313247 - CROSS_AGE_INTERACTIONS_SAGE_ADVICE_MONEY: 'CommonBuffId' = 313250 - CROSS_AGE_INTERACTIONS_SAGE_ADVICE_RESPONSIBILITY: 'CommonBuffId' = 313251 - CROSS_AGE_INTERACTIONS_STRANGER_DANGER: 'CommonBuffId' = 313057 - CROSS_AGE_INTERACTIONS_SWEET_TREAT: 'CommonBuffId' = 313052 - CROSS_AGE_INTERACTIONS_THE_FAVORITE: 'CommonBuffId' = 314030 - CROSS_STITCH_COMPLETED: 'CommonBuffId' = 358615 - CROSS_STITCH_EXPERT_STITCHER: 'CommonBuffId' = 261191 - CROSS_STITCH_HOMESTYLE_STITCHING: 'CommonBuffId' = 261196 - CROSS_STITCH_NIFTY_STITCHING: 'CommonBuffId' = 261188 - CROSS_STITCH_ONE_POKE_TOO_MANY: 'CommonBuffId' = 261190 - CRUMPLE_BOTTOMED: 'CommonBuffId' = 264407 - CRY_OVER_DOLLHOUSE: 'CommonBuffId' = 12393 - CUDDLE_NEW_BABY: 'CommonBuffId' = 98944 - CUDDLE_ON_BED_ALLOW_SLEEP: 'CommonBuffId' = 366133 - CUDDLE_ON_BED_FORCE_LEAVE_SLEEP: 'CommonBuffId' = 361012 - CUDDLE_ON_BED_GO_TO_SLEEP: 'CommonBuffId' = 360647 - CUDDLE_ON_BED_IN_AWAKE_CUDDLE: 'CommonBuffId' = 360735 - CUDDLE_ON_BED_STAY_ASLEEP: 'CommonBuffId' = 361178 - CULLING_GHOST: 'CommonBuffId' = 161431 - CUP_OF_COZY: 'CommonBuffId' = 170014 - CURFEW_HIGH_RESPONSIBILITY: 'CommonBuffId' = 168811 - CURFEW_MID_RESPONSIBILITY: 'CommonBuffId' = 168812 - CURSES_ANCIENT_SICKNESS_COMMON: 'CommonBuffId' = 175022 - CURSES_ANCIENT_SICKNESS_RARE: 'CommonBuffId' = 175023 - CURSES_ANCIENT_SICKNESS_UNCOMMON: 'CommonBuffId' = 175024 - CURSES_APPLY_CURSE_ANCIENT_SICKNESS_COMMON: 'CommonBuffId' = 175035 - CURSES_APPLY_CURSE_ANCIENT_SICKNESS_RARE: 'CommonBuffId' = 175036 - CURSES_APPLY_CURSE_ANCIENT_SICKNESS_UNCOMMON: 'CommonBuffId' = 175034 - CURSES_APPLY_CURSE_GREEDY_NEEDS_COMMON: 'CommonBuffId' = 175181 - CURSES_APPLY_CURSE_GREEDY_NEEDS_RARE: 'CommonBuffId' = 175182 - CURSES_APPLY_CURSE_GREEDY_NEEDS_UNCOMMON: 'CommonBuffId' = 175183 - CURSES_APPLY_CURSE_MARKED_FOR_DEATH_RARE: 'CommonBuffId' = 175219 - CURSES_APPLY_CURSE_MARKED_FOR_DEATH_UNCOMMON: 'CommonBuffId' = 175220 - CURSES_APPLY_CURSE_PERSONAL_RAIN_CLOUD_COMMON: 'CommonBuffId' = 174901 - CURSES_APPLY_CURSE_PERSONAL_RAIN_CLOUD_RARE: 'CommonBuffId' = 174904 - CURSES_APPLY_CURSE_PERSONAL_RAIN_CLOUD_UNCOMMON: 'CommonBuffId' = 174903 - CURSES_APPLY_CURSE_SEEING_THINGS_COMMON: 'CommonBuffId' = 175263 - CURSES_APPLY_CURSE_SEEING_THINGS_RARE: 'CommonBuffId' = 175265 - CURSES_APPLY_CURSE_SEEING_THINGS_UNCOMMON: 'CommonBuffId' = 175264 - CURSES_APPLY_MARKED_FOR_DEATH_COMMON: 'CommonBuffId' = 180621 - CURSES_EFFECTS_GREEDY_NEEDS_DISPEL_AT_HIGH_MOTIVES: 'CommonBuffId' = 175209 - CURSES_EFFECTS_PERSONAL_RAIN_CLOUD_ANGRY: 'CommonBuffId' = 174936 - CURSES_EFFECTS_PERSONAL_RAIN_CLOUD_BORED: 'CommonBuffId' = 174939 - CURSES_EFFECTS_PERSONAL_RAIN_CLOUD_CONFIDENT: 'CommonBuffId' = 174940 - CURSES_EFFECTS_PERSONAL_RAIN_CLOUD_DAZED: 'CommonBuffId' = 174937 - CURSES_EFFECTS_PERSONAL_RAIN_CLOUD_EMBARRASSED: 'CommonBuffId' = 174938 - CURSES_EFFECTS_PERSONAL_RAIN_CLOUD_ENERGIZED: 'CommonBuffId' = 174941 - CURSES_EFFECTS_PERSONAL_RAIN_CLOUD_FLIRTY: 'CommonBuffId' = 174942 - CURSES_EFFECTS_PERSONAL_RAIN_CLOUD_FOCUSED: 'CommonBuffId' = 174943 - CURSES_EFFECTS_PERSONAL_RAIN_CLOUD_HAPPY: 'CommonBuffId' = 174944 - CURSES_EFFECTS_PERSONAL_RAIN_CLOUD_INSPIRED: 'CommonBuffId' = 174945 - CURSES_EFFECTS_PERSONAL_RAIN_CLOUD_PLAYFUL: 'CommonBuffId' = 174946 - CURSES_EFFECTS_PERSONAL_RAIN_CLOUD_SAD: 'CommonBuffId' = 174935 - CURSES_EFFECTS_PERSONAL_RAIN_CLOUD_STRESSED: 'CommonBuffId' = 174933 - CURSES_EFFECTS_PERSONAL_RAIN_CLOUD_STRESSED_SHORT: 'CommonBuffId' = 180189 - CURSES_EFFECTS_PERSONAL_RAIN_CLOUD_UNCOMFORTABLE: 'CommonBuffId' = 174948 - CURSES_FOUNTAIN_OF_MAGIC_TRAIT_HIDDEN: 'CommonBuffId' = 215755 - CURSES_GREEDY_NEEDS_COMMON: 'CommonBuffId' = 175188 - CURSES_GREEDY_NEEDS_RARE: 'CommonBuffId' = 175190 - CURSES_GREEDY_NEEDS_UNCOMMON: 'CommonBuffId' = 175189 - CURSES_HEX_OF_DUELIST_PUSH_OPPONENT: 'CommonBuffId' = 218332 - CURSES_INFECTIOUS_LAUGHTER_TEMP_IMMUNITY: 'CommonBuffId' = 215941 - CURSES_MARKED_FOR_DEATH_COMMON: 'CommonBuffId' = 180774 - CURSES_MARKED_FOR_DEATH_RARE: 'CommonBuffId' = 175223 - CURSES_MARKED_FOR_DEATH_UNCOMMON: 'CommonBuffId' = 175224 - CURSES_NIGHT_STALKER_BEING_CHASED: 'CommonBuffId' = 216417 - CURSES_NIGHT_STALKER_HIDDEN_STALKER_ROLE_IDLE: 'CommonBuffId' = 216312 - CURSES_NIGHT_STALKER_HIDDEN_STALKER_ROLE_LEAVE: 'CommonBuffId' = 216541 - CURSES_NIGHT_STALKER_HIDDEN_STALKER_ROLE_SCREAM: 'CommonBuffId' = 216313 - CURSES_NIGHT_STALKER_HIDDEN_TRAIT: 'CommonBuffId' = 215608 - CURSES_NIGHT_STALKER_HIDDEN_TRAIT_STALKER: 'CommonBuffId' = 216516 - CURSES_PERSONAL_RAIN_CLOUD_COMMON: 'CommonBuffId' = 174906 - CURSES_PERSONAL_RAIN_CLOUD_RARE: 'CommonBuffId' = 174907 - CURSES_PERSONAL_RAIN_CLOUD_UNCOMMON: 'CommonBuffId' = 174908 - CURSES_PUNCHABLEFACE_HIDDEN_BROADCASTER: 'CommonBuffId' = 215330 - CURSES_PUNCHABLE_FACE_HIDDEN_TRAIT: 'CommonBuffId' = 215276 - CURSES_REPULSIVENESS: 'CommonBuffId' = 215053 - CURSES_REPULSIVENESS_HIDDEN_REMOVEBUFF: 'CommonBuffId' = 215072 - CURSES_SEEING_THINGS_COMMON: 'CommonBuffId' = 175267 - CURSES_SEEING_THINGS_RARE: 'CommonBuffId' = 175269 - CURSES_SEEING_THINGS_UNCOMMON: 'CommonBuffId' = 175268 - CURSES_SWEATYSTENCH_HIDDEN_TRAIT: 'CommonBuffId' = 215514 - CURSES_TEMP_IMMUNITY: 'CommonBuffId' = 215741 - CURSES_TOUCHY_FEELY_HIDDEN_TRAIT: 'CommonBuffId' = 215496 - CUSTOM_STATE_WEDDING_BLISSFUL_MARRIAGE: 'CommonBuffId' = 279277 - CUSTOM_STATE_WEDDING_CONFIDENT_DELIVERY: 'CommonBuffId' = 279270 - CUSTOM_STATE_WEDDING_GOOD_SPEECH: 'CommonBuffId' = 279271 - CUSTOM_STATE_WEDDING_HONEYMOON_IS_OVER: 'CommonBuffId' = 279267 - CUSTOM_STATE_WEDDING_IS_WEAR: 'CommonBuffId' = 279274 - CUSTOM_STATE_WEDDING_OFFICIANT_SPEECH: 'CommonBuffId' = 279275 - CUSTOM_STATE_WEDDING_QUESTIONABLE_REFERENCES: 'CommonBuffId' = 279653 - CUSTOM_STATE_WEDDING_RUNAWAY: 'CommonBuffId' = 279269 - CUSTOM_STATE_WEDDING_SOMETHING_BLUE_SOMETHING: 'CommonBuffId' = 279268 - CUSTOM_STATE_WEDDING_STOP_SITTING: 'CommonBuffId' = 292134 - CUSTOM_STATE_WEDDING_THOSE_VOWS: 'CommonBuffId' = 279273 - CUSTOM_STATE_WEDDING_VOWS_OVER: 'CommonBuffId' = 291178 - CUSTOM_STATE_WEDDING_WEDDING_BUBBLES: 'CommonBuffId' = 279265 - CUSTOM_STATE_WEDDING_WEDDING_DAY_INSPIRATION: 'CommonBuffId' = 279279 - CUSTOM_STATE_WEDDING_WEDDING_DAY_NOT_TO_DOS: 'CommonBuffId' = 279280 - CUSTOM_STATE_WEDDING_WEDDING_KISS: 'CommonBuffId' = 279276 - CUSTOM_STATE_WEDDING_WEDDING_RICE: 'CommonBuffId' = 279266 - CUSTOM_STATE_WEDDING_WHAT_DID_THEY_SAY: 'CommonBuffId' = 279654 - CUSTOM_STATE_WEDDING_WISHING_AND_HOPING: 'CommonBuffId' = 279278 - CUSTOM_STATE_WEDDING_WITH_THIS_RING: 'CommonBuffId' = 279272 - DANCING_COUNTRY_DANCING: 'CommonBuffId' = 326349 - DANCING_COUNTRY_DANCING_IS_DANCING_GROUP: 'CommonBuffId' = 326432 - DANCING_COUNTRY_DANCING_WATCHER: 'CommonBuffId' = 326433 - DANCING_PAIRED_DANCING_SENTIMENTAL_SWAYING: 'CommonBuffId' = 278788 - DANCING_PAIRED_DANCING_THATS_MY_FOOT: 'CommonBuffId' = 278932 - DATE_DEBRIEF_AMAZING_RECOVERY: 'CommonBuffId' = 375123 - DATE_DEBRIEF_AMAZING_REGULAR: 'CommonBuffId' = 375124 - DATE_DEBRIEF_FINE_RECOVERY: 'CommonBuffId' = 375121 - DATE_DEBRIEF_FINE_REGULAR: 'CommonBuffId' = 375122 - DATE_DEBRIEF_POST_DATE_VALIDATION: 'CommonBuffId' = 376891 - DATE_DEBRIEF_TERRIBLE_RECOVERY: 'CommonBuffId' = 375119 - DATE_DEBRIEF_TERRIBLE_REGULAR: 'CommonBuffId' = 375120 - DEATH_BROKEN_HEART_DEPRESSED_FOOD_SHARING: 'CommonBuffId' = 381333 - DEATH_BROKEN_HEART_HEART_ACHE: 'CommonBuffId' = 377369 - DEATH_BROKEN_HEART_MISERY: 'CommonBuffId' = 377367 - DEATH_BROKEN_HEART_SORROW: 'CommonBuffId' = 377366 - DEATH_BROKEN_HEART_TOTAL_DESPAIR: 'CommonBuffId' = 377368 - DEATH_ELDER_EXHAUSTION_WARNING: 'CommonBuffId' = 9448 - DEATH_ELECTROCUTION_WARNING: 'CommonBuffId' = 8686 - DEATH_METEORITE_WARNING: 'CommonBuffId' = 294213 - DEATH_OF_SIM_ACQUAINTANCE: 'CommonBuffId' = 190991 - DEATH_OF_SIM_BFF: 'CommonBuffId' = 185333 - DEATH_OF_SIM_CHILD: 'CommonBuffId' = 185335 - DEATH_OF_SIM_CHILD_DISLIKED: 'CommonBuffId' = 185336 - DEATH_OF_SIM_DIVORCED: 'CommonBuffId' = 185338 - DEATH_OF_SIM_DIVORCED_DISLIKED: 'CommonBuffId' = 185339 - DEATH_OF_SIM_FRIEND: 'CommonBuffId' = 185340 - DEATH_OF_SIM_GOOD_FRIEND: 'CommonBuffId' = 185341 - DEATH_OF_SIM_GRANDPARENT: 'CommonBuffId' = 185343 - DEATH_OF_SIM_GRANDPARENT_DISLIKED: 'CommonBuffId' = 185344 - DEATH_OF_SIM_HORSE_FRIEND: 'CommonBuffId' = 324697 - DEATH_OF_SIM_HORSE_NEUTRAL: 'CommonBuffId' = 324696 - DEATH_OF_SIM_NEMESIS: 'CommonBuffId' = 190761 - DEATH_OF_SIM_NIBLING: 'CommonBuffId' = 185346 - DEATH_OF_SIM_NIBLING_DISLIKED: 'CommonBuffId' = 185347 - DEATH_OF_SIM_PARENT: 'CommonBuffId' = 185349 - DEATH_OF_SIM_PARENT_DISLIKED: 'CommonBuffId' = 185350 - DEATH_OF_SIM_PET_FRIEND: 'CommonBuffId' = 190774 - DEATH_OF_SIM_PET_NEUTRAL: 'CommonBuffId' = 190775 - DEATH_OF_SIM_PIBLING: 'CommonBuffId' = 185352 - DEATH_OF_SIM_PIBLING_DISLIKED: 'CommonBuffId' = 185353 - DEATH_OF_SIM_ROMANTIC: 'CommonBuffId' = 185354 - DEATH_OF_SIM_SIBLING: 'CommonBuffId' = 185356 - DEATH_OF_SIM_SIBLING_DISLIKED: 'CommonBuffId' = 185357 - DEATH_OF_SIM_SPOUSE: 'CommonBuffId' = 185359 - DEATH_OF_SIM_SPOUSE_DISLIKED: 'CommonBuffId' = 185360 - DEATH_PUFFER_FISH_CANCEL_PUT_DOWN: 'CommonBuffId' = 134978 - DEATH_URBAN_MYTH_SAW_MIRROR_EP12: 'CommonBuffId' = 295883 - DEATH_WONT_DO_DEATH_INTERACTIONS: 'CommonBuffId' = 360603 - DEATH_WONT_DO_DEATH_SOLO_INTERACTIONS: 'CommonBuffId' = 117010 - DEBATE_SKILL_CONVINCE_BATHE: 'CommonBuffId' = 228449 - DEBATE_SKILL_CONVINCE_CLEAN: 'CommonBuffId' = 223453 - DEBATE_SKILL_CONVINCE_COOK: 'CommonBuffId' = 228421 - DEBATE_SKILL_DEGRADED: 'CommonBuffId' = 227701 - DEBATE_SKILL_GOING_SOLO: 'CommonBuffId' = 227704 - DEBATE_SKILL_HOMEWORK_HELP_COOLDOWN_CLASS_A: 'CommonBuffId' = 227753 - DEBATE_SKILL_HOMEWORK_HELP_COOLDOWN_CLASS_B: 'CommonBuffId' = 227754 - DEBATE_SKILL_HOMEWORK_HELP_COOLDOWN_CLASS_C: 'CommonBuffId' = 227755 - DEBATE_SKILL_HOMEWORK_HELP_COOLDOWN_CLASS_D: 'CommonBuffId' = 227756 - DEBATE_SKILL_INEFFICIENT_STUDIER: 'CommonBuffId' = 227703 - DEBATE_SKILL_INSIDER_STUDY: 'CommonBuffId' = 227702 - DEBATE_SKILL_OVERBEARING: 'CommonBuffId' = 223542 - DEBATE_SKILL_PREPARED: 'CommonBuffId' = 225145 - DEBATE_SKILL_STUDY_TIPS_COOLDOWN: 'CommonBuffId' = 228199 - DEBT_COMMODITY: 'CommonBuffId' = 226841 - DEBT_POST_HUMOUS_POVERTY_MAD: 'CommonBuffId' = 228591 - DEBT_POST_HUMOUS_POVERTY_SAD: 'CommonBuffId' = 228590 - DEBUG_INTERACTIONS: 'CommonBuffId' = 161518 - DEBUG_INTERACTION_FAIL: 'CommonBuffId' = 290825 - DEBUG_PET_WANDERLUST_CARRY: 'CommonBuffId' = 163956 - DEBUG_PET_WANDERLUST_MISSING: 'CommonBuffId' = 173608 - DEBUG_PET_WANDERLUST_NOTHING: 'CommonBuffId' = 163958 - DEBUG_PET_WANDERLUST_PREGNANT: 'CommonBuffId' = 163957 - DEBUG_PET_WANDERLUST_SICK: 'CommonBuffId' = 163955 - DELIVERIES_ASK_FOR_TIP_COOLDOWN: 'CommonBuffId' = 262352 - DELIVERIES_COUPON_REDEEMED: 'CommonBuffId' = 267620 - DELIVERIES_FOOD_DELIVERY_EAT_AT_HOME: 'CommonBuffId' = 267132 - DENIZEN_POND_AGITATED_BITES: 'CommonBuffId' = 192260 - DENIZEN_POND_CALMING_DENIZENS: 'CommonBuffId' = 192257 - DENIZEN_POND_DENIZENS_DENIED: 'CommonBuffId' = 199409 - DENIZEN_POND_FERVENT_PREDATORS: 'CommonBuffId' = 192258 - DENIZEN_POND_MISCHIEVOUS_SPRITES: 'CommonBuffId' = 192261 - DENIZEN_POND_PLAYFUL_DENIZENS: 'CommonBuffId' = 192259 - DENIZEN_POND_SOPPING: 'CommonBuffId' = 199407 - DIPLOMA_ASPIRING_TO_KNOWLEDGE: 'CommonBuffId' = 224283 - DIPLOMA_GRADUATE_GAFFE: 'CommonBuffId' = 224285 - DIPLOMA_KIND_OF_BIG_DEAL: 'CommonBuffId' = 224284 - DIPLOMA_NOT_WORTH_PAPER_WRITTEN_ON: 'CommonBuffId' = 224280 - DIPLOMA_STUCK_IN_RUT: 'CommonBuffId' = 224281 - DIPLOMA_THAT_PLACE_SUCKS: 'CommonBuffId' = 224282 - DIPLOMA_TIME_WELL_SPENT: 'CommonBuffId' = 224277 - DISCERNING_DWELLER_PIECE_OF_CAKE: 'CommonBuffId' = 354202 - DISCERNING_DWELLER_WHAT_RULES: 'CommonBuffId' = 354203 - DISCIPLINE_BAD_GRADES: 'CommonBuffId' = 163548 - DISCIPLINE_BEING_DISCIPLINED: 'CommonBuffId' = 168536 - DISCIPLINE_BROKE_CURFEW: 'CommonBuffId' = 163288 - DISCIPLINE_GOOD_GRADES: 'CommonBuffId' = 163547 - DISCIPLINE_QUIT_JOB: 'CommonBuffId' = 163621 - DISCIPLINE_TEEN_JOB_PERFORMANCE_GOOD: 'CommonBuffId' = 163593 - DISCIPLINE_TIME_OUT_BORED: 'CommonBuffId' = 163231 - DISCIPLINE_TIME_OUT_BROKE: 'CommonBuffId' = 167841 - DISCIPLINE_TIME_OUT_FOCUSED: 'CommonBuffId' = 163233 - DISCIPLINE_TIME_OUT_SAD: 'CommonBuffId' = 163232 - DISCUSS_EXPANDING_THE_FAMILY_BABY_JOY: 'CommonBuffId' = 274751 - DISCUSS_EXPANDING_THE_FAMILY_COOLDOWN_HIDDEN: 'CommonBuffId' = 274120 - DISCUSS_EXPANDING_THE_FAMILY_FRIEND_EXPECTING: 'CommonBuffId' = 274523 - DISCUSS_EXPANDING_THE_FAMILY_HIDDEN_COOLDOWN_PREGNANCY_SUCCESS: 'CommonBuffId' = 275715 - DOCTOR_AWAY_EVENT_PATIENT: 'CommonBuffId' = 114016 - DOCTOR_PATIENT: 'CommonBuffId' = 115002 - DOCTOR_PATIENT_NO_VFX_WALK_STYLE: 'CommonBuffId' = 116260 - DOCTOR_PATIENT_VFX_BLUE: 'CommonBuffId' = 115646 - DOCTOR_PLAY_SET_ADULT_BECAME_DOCTOR: 'CommonBuffId' = 168521 - DOCTOR_PLAY_SET_ADULT_BECAME_VET: 'CommonBuffId' = 175695 - DOCTOR_PLAY_SET_CONFIDENT: 'CommonBuffId' = 161481 - DOCTOR_PLAY_SET_PLAYFUL: 'CommonBuffId' = 161479 - DOCTOR_PLAY_SET_SAD: 'CommonBuffId' = 161480 - DOG_ACTIVE_ROUGHHOUSE_PLAY_DECAY: 'CommonBuffId' = 173490 - DOG_CONDITIONING_SHORT_TERM_BARK: 'CommonBuffId' = 148253 - DOG_CONDITIONING_SHORT_TERM_BEG_FOR_FOOD: 'CommonBuffId' = 148254 - DOG_HEEL: 'CommonBuffId' = 167006 - DOG_ON_LEASH_HIDDEN: 'CommonBuffId' = 164919 - DOG_TO_DOG_PLAY_SOCIAL: 'CommonBuffId' = 176980 - DOG_TRAINING_BORED_PROTECTION: 'CommonBuffId' = 167211 - DOG_TRAINING_COOL_TRICK: 'CommonBuffId' = 164387 - DOG_TRAINING_FETCH_BORED_PROTECTION: 'CommonBuffId' = 168613 - DOG_TRAINING_PARTICIPANT: 'CommonBuffId' = 170274 - DOG_TRAINING_QUALITY_TIME: 'CommonBuffId' = 164372 - DOG_TRAINING_SHOW_OFF_DOG: 'CommonBuffId' = 165920 - DOG_TRAINING_SHOW_OFF_HUMAN: 'CommonBuffId' = 165750 - DOG_TRAINING_SHOW_OFF_TRICKS: 'CommonBuffId' = 170017 - DOG_TRAINING_TENSE: 'CommonBuffId' = 164386 - DOG_TRAINING_TRICK_LEARNED_EXIT_CONDITION_FETCH: 'CommonBuffId' = 167731 - DOG_TRAINING_TRICK_LEARNED_EXIT_CONDITION_HIDDEN: 'CommonBuffId' = 162553 - DOG_WALKING_GO_FOR_JOG_DOG_JOG_BEHAVIOR: 'CommonBuffId' = 177662 - DOG_WALKING_SIM_GOOD_WALK: 'CommonBuffId' = 165223 - DOLPHIN_DOLPHIN_FRIEND_1: 'CommonBuffId' = 206476 - DOLPHIN_DOLPHIN_FRIEND_2: 'CommonBuffId' = 206477 - DOLPHIN_DOLPHIN_FRIEND_3: 'CommonBuffId' = 206475 - DOLPHIN_FEED_COOLDOWN: 'CommonBuffId' = 211583 - DOLPHIN_FEED_RELATIONSHIP_MODIFIER: 'CommonBuffId' = 208348 - DOLPHIN_FIRST_ATTEMPT_DANCE: 'CommonBuffId' = 211536 - DOLPHIN_FIRST_ATTEMPT_FETCH: 'CommonBuffId' = 211537 - DOLPHIN_FIRST_ATTEMPT_JUMP: 'CommonBuffId' = 211611 - DOLPHIN_FIRST_ATTEMPT_KISS: 'CommonBuffId' = 211539 - DOLPHIN_FIRST_ATTEMPT_RUB_BELLY: 'CommonBuffId' = 211538 - DOLPHIN_MEAN_SPLASH_RELATIONSHIP_MAXIMIZER: 'CommonBuffId' = 212490 - DOLPHIN_NO_DOLPHIN: 'CommonBuffId' = 207032 - DOLPHIN_PET_RELATIONSHIP_MINIMIZER: 'CommonBuffId' = 211581 - DOLPHIN_RUB_BELLY_RELATIONSHIP_COOLDOWN: 'CommonBuffId' = 208355 - DOLPHIN_SPOUTING_OFF: 'CommonBuffId' = 206547 - DOLPHIN_SPOUTING_OFF_ANGRY: 'CommonBuffId' = 211224 - DOLPHIN_SPOUTING_OFF_SAD: 'CommonBuffId' = 211225 - DOLPHIN_SQUIRT_SILLINESS: 'CommonBuffId' = 206546 - DOLPHIN_SUMMON_COOLDOWN: 'CommonBuffId' = 211414 - DOLPHIN_TALK_RELATIONSHIP_MINIMIZER: 'CommonBuffId' = 211107 - DOLPHIN_TRICK_COOLDOWN_DANCE: 'CommonBuffId' = 206550 - DOLPHIN_TRICK_COOLDOWN_FETCH: 'CommonBuffId' = 206551 - DOLPHIN_TRICK_COOLDOWN_JUMP: 'CommonBuffId' = 211609 - DOLPHIN_TRICK_COOLDOWN_KISS: 'CommonBuffId' = 206552 - DOLPHIN_TRICK_COOLDOWN_RUB_BELLY: 'CommonBuffId' = 206549 - DRAINED: 'CommonBuffId' = 12396 - DRAMA_CLUB_ARRIVAL: 'CommonBuffId' = 200523 - DRAMA_CLUB_CRY_ON_DEMAND: 'CommonBuffId' = 199902 - DRAMA_CLUB_FRIDAY_SHOW: 'CommonBuffId' = 200344 - DRAMA_CLUB_HAPPY: 'CommonBuffId' = 200498 - DRAMA_CLUB_HOUSEHOLD_ATTENDING: 'CommonBuffId' = 200520 - DRAMA_CLUB_INSPIRED: 'CommonBuffId' = 200500 - DRAMA_CLUB_PRACTICE_ACTING_CONFIDENT: 'CommonBuffId' = 199901 - DRAMA_CLUB_PROMOTION: 'CommonBuffId' = 201014 - DRAMA_CLUB_SAD: 'CommonBuffId' = 200499 - DRINK_BEETLE_JUICE_3_INVISIBLE: 'CommonBuffId' = 235951 - DRINK_COFFEE_TEA_COOLDOWN: 'CommonBuffId' = 355197 - DRINK_MICROWAVE_HOT_WATER_NEGATIVE: 'CommonBuffId' = 352193 - DRINK_MILK_LIVESTOCK_BLACK: 'CommonBuffId' = 263350 - DRINK_MILK_LIVESTOCK_BROWN: 'CommonBuffId' = 262989 - DRINK_MILK_LIVESTOCK_ENRICHED: 'CommonBuffId' = 262979 - DRINK_MILK_LIVESTOCK_GOLD: 'CommonBuffId' = 263352 - DRINK_MILK_LIVESTOCK_GREEN: 'CommonBuffId' = 262997 - DRINK_MILK_LIVESTOCK_ORANGE: 'CommonBuffId' = 262995 - DRINK_MILK_LIVESTOCK_PINK: 'CommonBuffId' = 262994 - DRINK_MILK_LIVESTOCK_PINK_CHILD: 'CommonBuffId' = 268614 - DRINK_MILK_LIVESTOCK_RAINBOW: 'CommonBuffId' = 262990 - DRINK_MILK_LIVESTOCK_RED: 'CommonBuffId' = 262991 - DRINK_MOON_PETAL_CALM: 'CommonBuffId' = 289745 - DRINK_MOON_PETAL_STILLNESS: 'CommonBuffId' = 289746 - DRINK_NECTAR_ASTONISHING_AROMA_HIGH: 'CommonBuffId' = 132087 - DRINK_NECTAR_ASTONISHING_AROMA_HIGH_GREAT_PAIRING: 'CommonBuffId' = 132102 - DRINK_NECTAR_ASTONISHING_AROMA_NORMAL: 'CommonBuffId' = 132077 - DRINK_NECTAR_ASTONISHING_AROMA_NORMAL_GREAT_PAIRING: 'CommonBuffId' = 132105 - DRINK_NECTAR_BREATHTAKING_BALANCE_HIGH: 'CommonBuffId' = 132089 - DRINK_NECTAR_BREATHTAKING_BALANCE_HIGH_GREAT_PAIRING: 'CommonBuffId' = 132107 - DRINK_NECTAR_BREATHTAKING_BALANCE_NORMAL: 'CommonBuffId' = 132078 - DRINK_NECTAR_BREATHTAKING_BALANCE_NORMAL_GREAT_PAIRING: 'CommonBuffId' = 132109 - DRINK_NECTAR_COMMANDING_COMPLEXITY_HIGH: 'CommonBuffId' = 132091 - DRINK_NECTAR_COMMANDING_COMPLEXITY_HIGH_GREAT_PAIRING: 'CommonBuffId' = 132111 - DRINK_NECTAR_COMMANDING_COMPLEXITY_NORMAL: 'CommonBuffId' = 132079 - DRINK_NECTAR_COMMANDING_COMPLEXITY_NORMAL_GREAT_PAIRING: 'CommonBuffId' = 132113 - DRINK_NECTAR_FABULOUS_FINISH_HIGH: 'CommonBuffId' = 132093 - DRINK_NECTAR_FABULOUS_FINISH_HIGH_GREAT_PAIRING: 'CommonBuffId' = 132115 - DRINK_NECTAR_FABULOUS_FINISH_NORMAL: 'CommonBuffId' = 132076 - DRINK_NECTAR_FABULOUS_FINISH_NORMAL_GREAT_PAIRING: 'CommonBuffId' = 132117 - DRINK_NECTAR_LUSCIOUS_LIBATION: 'CommonBuffId' = 132085 - DRINK_NECTAR_LUSCIOUS_LIBATION_GREAT_PAIRING: 'CommonBuffId' = 133743 - DRINK_NECTAR_RED_PAIRING: 'CommonBuffId' = 132057 - DRINK_NECTAR_TANTALIZING_TANNINS_HIGH: 'CommonBuffId' = 132095 - DRINK_NECTAR_TANTALIZING_TANNINS_HIGH_GREAT_PAIRING: 'CommonBuffId' = 132119 - DRINK_NECTAR_TANTALIZING_TANNINS_NORMAL: 'CommonBuffId' = 132080 - DRINK_NECTAR_TANTALIZING_TANNINS_NORMAL_GREAT_PAIRING: 'CommonBuffId' = 132121 - DRINK_NECTAR_WHITE_PAIRING: 'CommonBuffId' = 132058 - DRINK_POWER_SIP_MIDNIGHT: 'CommonBuffId' = 289744 - DRINK_TEA_APPLE_CIDER: 'CommonBuffId' = 280353 - DRINK_TEA_BUILDERS_TEA_NOT_SWEET: 'CommonBuffId' = 356848 - DRINK_TEA_BUILDERS_TEA_TOO_SWEET: 'CommonBuffId' = 356851 - DRINK_TEA_CHAMOMILE_TEA: 'CommonBuffId' = 358715 - DRINK_TEA_COCOA: 'CommonBuffId' = 346704 - DRINK_TEA_COCOA_WITH_MARSHMALLOWS: 'CommonBuffId' = 346705 - DRINK_TEA_TEA_SET_BLACK_DRAGON: 'CommonBuffId' = 274312 - DRINK_TEA_TEA_SET_ORANGE_BLOSSOM: 'CommonBuffId' = 274313 - DRINK_TEA_UNICORN_GALAXY: 'CommonBuffId' = 346703 - DUMPSTER_DIRTY_FLIRTY: 'CommonBuffId' = 233597 - DUMPSTER_DIVE_FOR_COOLDOWN: 'CommonBuffId' = 240839 - DUMPSTER_DUMPSTER_DOVE: 'CommonBuffId' = 233595 - DUMPSTER_GROSSED_OUT_BY_DUMPSTERS: 'CommonBuffId' = 233596 - DUMPSTER_NAP_NOT_SLOB: 'CommonBuffId' = 238697 - DUMPSTER_NAP_SLOB: 'CommonBuffId' = 238696 - DUST_ASK_CLEAN_COOLDOWN: 'CommonBuffId' = 303735 - DUST_CLEAN_FRESH_N_FRISKY: 'CommonBuffId' = 254485 - DUST_CLEAN_PERFECTIONIST_ZEAL_1: 'CommonBuffId' = 254489 - DUST_CLEAN_PERFECTIONIST_ZEAL_2: 'CommonBuffId' = 254490 - DUST_CLEAN_PERFECTIONIST_ZEAL_3: 'CommonBuffId' = 254491 - DUST_CLEAN_PERFECTIONIST_ZEAL_4: 'CommonBuffId' = 254492 - DUST_DIRTY_MESSINESS_KILLS_THE_MOOD: 'CommonBuffId' = 254495 - DUST_DIRTY_MESSINESS_KILLS_THE_MOOD_FILTHY: 'CommonBuffId' = 257324 - DUST_DIRTY_NOT_USUALLY_LIKE_THIS: 'CommonBuffId' = 254494 - DUST_DUSTY_CHORE_GALORE: 'CommonBuffId' = 254493 - DUST_ENABLED: 'CommonBuffId' = 256481 - DUST_FILTHY_RAGE_CLEANING_1: 'CommonBuffId' = 254497 - DUST_FILTHY_RAGE_CLEANING_2: 'CommonBuffId' = 254498 - DUST_FILTHY_RAGE_CLEANING_3: 'CommonBuffId' = 254499 - DUST_FRIENDS_BUNNY_BFF: 'CommonBuffId' = 255315 - DUST_FRIENDS_BUNNY_CARE: 'CommonBuffId' = 255314 - DUST_FRIENDS_BUNNY_SAD: 'CommonBuffId' = 255316 - DUST_FRIENDS_FIEND_SCARED: 'CommonBuffId' = 255318 - DUST_FRIENDS_FIEND_SLAYER: 'CommonBuffId' = 255317 - DUST_INTERACTIONS_CHORE_SHAMED: 'CommonBuffId' = 254501 - DUST_INTERACTIONS_NOT_YOUR_HOUSEKEEPER: 'CommonBuffId' = 254502 - DUST_REACTION_COOLDOWN: 'CommonBuffId' = 318706 - DUST_STATE_CLEAN: 'CommonBuffId' = 254476 - DUST_STATE_DIRTY: 'CommonBuffId' = 254478 - DUST_STATE_DUSTY: 'CommonBuffId' = 254477 - DUST_STATE_FILTHY: 'CommonBuffId' = 254479 - DUST_STATE_NPC_DIRTY_FILTHY: 'CommonBuffId' = 257298 - DUST_STATE_SLOB_DIRTY: 'CommonBuffId' = 270224 - DUST_STATE_SLOB_FILTHY: 'CommonBuffId' = 270223 - DWELLING_HIDDEN_SUPPRESS_DECAY_OVERRIDE: 'CommonBuffId' = 237400 - DWELLING_MESS_AROUND_OUTERWORLD_FLING: 'CommonBuffId' = 245625 - DWELLING_WELL_RESTED: 'CommonBuffId' = 237379 - DWELLING_WOOHOO_TWO_FOR_BATUU: 'CommonBuffId' = 237406 - DYNAMIC_SIGN_VIEW_BUFF: 'CommonBuffId' = 133333 - ECO_FOOTPRINT_ACID_PUDDLE_HIDDEN: 'CommonBuffId' = 235221 - ECO_FOOTPRINT_BASK_IN_THE_LIGHT_BURNT: 'CommonBuffId' = 232109 - ECO_FOOTPRINT_BASK_IN_THE_LIGHT_PRAISED: 'CommonBuffId' = 232107 - ECO_FOOTPRINT_GREEN_BREATHE_DEEPLY: 'CommonBuffId' = 232134 - ECO_FOOTPRINT_HIDDEN_ACID_RAIN: 'CommonBuffId' = 239632 - ECO_FOOTPRINT_HIDDEN_BASK_IN_LIGHT_SUPRESSSUN: 'CommonBuffId' = 240794 - ECO_FOOTPRINT_HIDDEN_GREEN: 'CommonBuffId' = 232485 - ECO_FOOTPRINT_HIDDEN_INDUSTRIAL: 'CommonBuffId' = 232484 - ECO_FOOTPRINT_INDUSTRIAL_STRUGGLE_TO_BREATHE: 'CommonBuffId' = 232135 - ECO_INSPECTOR: 'CommonBuffId' = 239376 - ECO_LIVING: 'CommonBuffId' = 237050 - EMBARRASSED_GOT_LOST: 'CommonBuffId' = 75523 - EMBARRASSED_LONER: 'CommonBuffId' = 29532 - EMBARRASSING_CONVERSATION: 'CommonBuffId' = 12399 - EMOTIONAL_BUFFS_GENERAL_PETS_CAT_ANGRY_CATNIP: 'CommonBuffId' = 171119 - EMOTIONAL_BUFFS_GENERAL_PETS_CAT_ANGRY_LEVEL1: 'CommonBuffId' = 158476 - EMOTIONAL_BUFFS_GENERAL_PETS_CAT_ANGRY_LEVEL1_NOT_TIMED: 'CommonBuffId' = 168659 - EMOTIONAL_BUFFS_GENERAL_PETS_CAT_ANGRY_LEVEL2: 'CommonBuffId' = 158477 - EMOTIONAL_BUFFS_GENERAL_PETS_CAT_ANGRY_WALK_BY: 'CommonBuffId' = 171702 - EMOTIONAL_BUFFS_GENERAL_PETS_CAT_ANXIOUS_E_P05_THERMOSTAT: 'CommonBuffId' = 190956 - EMOTIONAL_BUFFS_GENERAL_PETS_CAT_ANXIOUS_LEVEL1: 'CommonBuffId' = 158478 - EMOTIONAL_BUFFS_GENERAL_PETS_CAT_ANXIOUS_LEVEL2: 'CommonBuffId' = 158479 - EMOTIONAL_BUFFS_GENERAL_PETS_CAT_DROWSY_CATNIP: 'CommonBuffId' = 171120 - EMOTIONAL_BUFFS_GENERAL_PETS_CAT_DROWSY_LEVEL1: 'CommonBuffId' = 158480 - EMOTIONAL_BUFFS_GENERAL_PETS_CAT_DROWSY_LEVEL2: 'CommonBuffId' = 158481 - EMOTIONAL_BUFFS_GENERAL_PETS_CAT_DROWSY_WALK_BY: 'CommonBuffId' = 178595 - EMOTIONAL_BUFFS_GENERAL_PETS_CAT_FINE_WALK_BY: 'CommonBuffId' = 171708 - EMOTIONAL_BUFFS_GENERAL_PETS_CAT_FLIRTY_CATNIP: 'CommonBuffId' = 171121 - EMOTIONAL_BUFFS_GENERAL_PETS_CAT_FLIRTY_LEVEL1: 'CommonBuffId' = 158482 - EMOTIONAL_BUFFS_GENERAL_PETS_CAT_FLIRTY_LEVEL2: 'CommonBuffId' = 158483 - EMOTIONAL_BUFFS_GENERAL_PETS_CAT_HAPPY_LEVEL1: 'CommonBuffId' = 158484 - EMOTIONAL_BUFFS_GENERAL_PETS_CAT_HAPPY_LEVEL2: 'CommonBuffId' = 158485 - EMOTIONAL_BUFFS_GENERAL_PETS_CAT_HAPPY_WALK_BY: 'CommonBuffId' = 171703 - EMOTIONAL_BUFFS_GENERAL_PETS_CAT_HYPER_CATNIP: 'CommonBuffId' = 171122 - EMOTIONAL_BUFFS_GENERAL_PETS_CAT_HYPER_LEVEL1: 'CommonBuffId' = 158486 - EMOTIONAL_BUFFS_GENERAL_PETS_CAT_HYPER_LEVEL2: 'CommonBuffId' = 158487 - EMOTIONAL_BUFFS_GENERAL_PETS_CAT_HYPER_WALK_BY: 'CommonBuffId' = 178593 - EMOTIONAL_BUFFS_GENERAL_PETS_CAT_SCARED_LEVEL1: 'CommonBuffId' = 158488 - EMOTIONAL_BUFFS_GENERAL_PETS_CAT_SCARED_LEVEL1_NOT_TIMED: 'CommonBuffId' = 168662 - EMOTIONAL_BUFFS_GENERAL_PETS_CAT_SCARED_LEVEL2: 'CommonBuffId' = 158489 - EMOTIONAL_BUFFS_GENERAL_PETS_CAT_VENGEFUL: 'CommonBuffId' = 165613 - EMOTIONAL_BUFFS_GENERAL_PETS_DOG_ANGRY_LEVEL1: 'CommonBuffId' = 158289 - EMOTIONAL_BUFFS_GENERAL_PETS_DOG_ANGRY_LEVEL1_NOT_TIMED: 'CommonBuffId' = 168661 - EMOTIONAL_BUFFS_GENERAL_PETS_DOG_ANGRY_LEVEL2: 'CommonBuffId' = 158311 - EMOTIONAL_BUFFS_GENERAL_PETS_DOG_ANGRY_WALK_BY: 'CommonBuffId' = 171704 - EMOTIONAL_BUFFS_GENERAL_PETS_DOG_ANXIOUS_E_P05_THERMOSTAT: 'CommonBuffId' = 190957 - EMOTIONAL_BUFFS_GENERAL_PETS_DOG_ANXIOUS_LEVEL1: 'CommonBuffId' = 158290 - EMOTIONAL_BUFFS_GENERAL_PETS_DOG_ANXIOUS_LEVEL2: 'CommonBuffId' = 158312 - EMOTIONAL_BUFFS_GENERAL_PETS_DOG_ASHAMED_LEVEL1: 'CommonBuffId' = 158291 - EMOTIONAL_BUFFS_GENERAL_PETS_DOG_ASHAMED_LEVEL2: 'CommonBuffId' = 158313 - EMOTIONAL_BUFFS_GENERAL_PETS_DOG_EXCITED_LEVEL1: 'CommonBuffId' = 158293 - EMOTIONAL_BUFFS_GENERAL_PETS_DOG_EXCITED_LEVEL2: 'CommonBuffId' = 158314 - EMOTIONAL_BUFFS_GENERAL_PETS_DOG_EXCITED_WALK_BY: 'CommonBuffId' = 178591 - EMOTIONAL_BUFFS_GENERAL_PETS_DOG_FINE_WALK_BY: 'CommonBuffId' = 171706 - EMOTIONAL_BUFFS_GENERAL_PETS_DOG_FLIRTY_LEVEL1: 'CommonBuffId' = 158292 - EMOTIONAL_BUFFS_GENERAL_PETS_DOG_FLIRTY_LEVEL2: 'CommonBuffId' = 158315 - EMOTIONAL_BUFFS_GENERAL_PETS_DOG_HAPPY_LEVEL1: 'CommonBuffId' = 158297 - EMOTIONAL_BUFFS_GENERAL_PETS_DOG_HAPPY_LEVEL2: 'CommonBuffId' = 158316 - EMOTIONAL_BUFFS_GENERAL_PETS_DOG_HAPPY_WALK_BY: 'CommonBuffId' = 171705 - EMOTIONAL_BUFFS_GENERAL_PETS_DOG_MOPEY_LEVEL1: 'CommonBuffId' = 158295 - EMOTIONAL_BUFFS_GENERAL_PETS_DOG_MOPEY_LEVEL2: 'CommonBuffId' = 158317 - EMOTIONAL_BUFFS_GENERAL_PETS_DOG_MOPEY_WALK_BY: 'CommonBuffId' = 178592 - EMOTIONAL_BUFFS_GENERAL_PETS_DOG_SAD_LEVEL1: 'CommonBuffId' = 158294 - EMOTIONAL_BUFFS_GENERAL_PETS_DOG_SAD_LEVEL2: 'CommonBuffId' = 158318 - EMOTIONAL_BUFFS_GENERAL_PETS_DOG_SCARED_LEVEL1: 'CommonBuffId' = 158296 - EMOTIONAL_BUFFS_GENERAL_PETS_DOG_SCARED_LEVEL1_NOT_TIMED: 'CommonBuffId' = 168660 - EMOTIONAL_BUFFS_GENERAL_PETS_DOG_SCARED_LEVEL2: 'CommonBuffId' = 158319 - EMOTIONAL_BUFFS_GENERAL_PETS_DOG_VENGEFUL: 'CommonBuffId' = 165615 - EMOTIONAL_BUFFS_SICKNESS_PETS_CAT_ANXIOUS: 'CommonBuffId' = 169698 - EMOTIONAL_BUFFS_SICKNESS_PETS_CAT_DROWSY: 'CommonBuffId' = 169697 - EMOTIONAL_BUFFS_SICKNESS_PETS_DOG_ANXIOUS: 'CommonBuffId' = 169695 - EMOTIONAL_BUFFS_SICKNESS_PETS_DOG_DROWSY: 'CommonBuffId' = 169696 - EMOTIONAL_BUFFS_WRITE_BOOK_CONFIDENT_HIGH: 'CommonBuffId' = 74803 - EMOTIONAL_BUFFS_WRITE_BOOK_CONFIDENT_LOW: 'CommonBuffId' = 74802 - EMOTIONAL_BUFFS_WRITE_BOOK_ENERGIZED_HIGH: 'CommonBuffId' = 74805 - EMOTIONAL_BUFFS_WRITE_BOOK_ENERGIZED_LOW: 'CommonBuffId' = 74804 - EMOTIONAL_BUFFS_WRITE_BOOK_FLIRTY_HIGH: 'CommonBuffId' = 74807 - EMOTIONAL_BUFFS_WRITE_BOOK_FLIRTY_LOW: 'CommonBuffId' = 74806 - EMOTIONAL_BUFFS_WRITE_BOOK_FOCUSED_HIGH: 'CommonBuffId' = 98157 - EMOTIONAL_BUFFS_WRITE_BOOK_FOCUSED_LOW: 'CommonBuffId' = 98156 - EMOTIONAL_BUFFS_WRITE_BOOK_INSPIRED_HIGH: 'CommonBuffId' = 98158 - EMOTIONAL_BUFFS_WRITE_BOOK_INSPIRED_LOW: 'CommonBuffId' = 98155 - EMOTIONAL_BUFFS_WRITE_BOOK_PLAYFUL_HIGH: 'CommonBuffId' = 74809 - EMOTIONAL_BUFFS_WRITE_BOOK_PLAYFUL_LOW: 'CommonBuffId' = 74808 - EMOTIONAL_BUFFS_WRITE_BOOK_SAD_HIGH: 'CommonBuffId' = 74811 - EMOTIONAL_BUFFS_WRITE_BOOK_SAD_LOW: 'CommonBuffId' = 74810 - EMOTIONAL_MELTDOWNS_EMBARRASSED: 'CommonBuffId' = 159502 - EMOTIONAL_MELTDOWNS_TENSE_NON_PARENT: 'CommonBuffId' = 159501 - EMOTIONAL_MELTDOWNS_TENSE_PARENT: 'CommonBuffId' = 160239 - EMOTIONAL_SUPPORT: 'CommonBuffId' = 99789 - ENCHANTED_CHARISMA: 'CommonBuffId' = 37497 - ENERGIZED_BY_POTION: 'CommonBuffId' = 26330 - ENERGIZING_SCENT: 'CommonBuffId' = 118500 - ENERGY_JUICE_ENERGIZED: 'CommonBuffId' = 99465 - ENERGY_JUICE_HIDDEN: 'CommonBuffId' = 99462 - ENLIGHTENED_AND_INSPIRED: 'CommonBuffId' = 118672 - ENLIGHTENED_CONFIDENCE: 'CommonBuffId' = 118514 - ENVIRONMENT_ANGRY_AMBIENCE_LARGE: 'CommonBuffId' = 12401 - ENVIRONMENT_ANGRY_AMBIENCE_MEDIUM: 'CommonBuffId' = 12402 - ENVIRONMENT_ANGRY_AMBIENCE_SMALL: 'CommonBuffId' = 12403 - ENVIRONMENT_BB_GAMEPLAY_EFFECTS_BAD_ENVIRONMENT_LARGE: 'CommonBuffId' = 238500 - ENVIRONMENT_BB_GAMEPLAY_EFFECTS_BAD_ENVIRONMENT_MEDIUM: 'CommonBuffId' = 238499 - ENVIRONMENT_BB_GAMEPLAY_EFFECTS_BAD_ENVIRONMENT_SMALL: 'CommonBuffId' = 238498 - ENVIRONMENT_BB_GAMEPLAY_EFFECTS_GOOD_ENVIRONMENT_LARGE: 'CommonBuffId' = 240250 - ENVIRONMENT_BB_GAMEPLAY_EFFECTS_GOOD_ENVIRONMENT_MEDIUM: 'CommonBuffId' = 240249 - ENVIRONMENT_BB_GAMEPLAY_EFFECTS_GOOD_ENVIRONMENT_SMALL: 'CommonBuffId' = 240248 - ENVIRONMENT_BB_GAMEPLAY_EFFECTS_SLOB_LARGE: 'CommonBuffId' = 238493 - ENVIRONMENT_BB_GAMEPLAY_EFFECTS_SLOB_LARGE_CHOOSER: 'CommonBuffId' = 239282 - ENVIRONMENT_BB_GAMEPLAY_EFFECTS_SLOB_MEDIUM: 'CommonBuffId' = 238495 - ENVIRONMENT_BB_GAMEPLAY_EFFECTS_SLOB_MEDIUM_CHOOSER: 'CommonBuffId' = 239281 - ENVIRONMENT_BB_GAMEPLAY_EFFECTS_SLOB_SMALL: 'CommonBuffId' = 238494 - ENVIRONMENT_BB_GAMEPLAY_EFFECTS_SLOB_SMALL_CHOOSER: 'CommonBuffId' = 239280 - ENVIRONMENT_BB_GAMEPLAY_EFFECTS_SNOB_LARGE: 'CommonBuffId' = 238492 - ENVIRONMENT_BB_GAMEPLAY_EFFECTS_SNOB_MEDIUM: 'CommonBuffId' = 238491 - ENVIRONMENT_BB_GAMEPLAY_EFFECTS_SNOB_SMALL: 'CommonBuffId' = 238490 - ENVIRONMENT_BORED_AMBIENCE_LARGE: 'CommonBuffId' = 12404 - ENVIRONMENT_BORED_AMBIENCE_MEDIUM: 'CommonBuffId' = 12405 - ENVIRONMENT_BORED_AMBIENCE_SMALL: 'CommonBuffId' = 12406 - ENVIRONMENT_CONFIDENT_AMBIENCE_LARGE: 'CommonBuffId' = 12407 - ENVIRONMENT_CONFIDENT_AMBIENCE_MEDIUM: 'CommonBuffId' = 12408 - ENVIRONMENT_CONFIDENT_AMBIENCE_SMALL: 'CommonBuffId' = 12409 - ENVIRONMENT_EMBARRASSED_AMBIENCE_LARGE: 'CommonBuffId' = 12410 - ENVIRONMENT_EMBARRASSED_AMBIENCE_MEDIUM: 'CommonBuffId' = 12411 - ENVIRONMENT_EMBARRASSED_AMBIENCE_SMALL: 'CommonBuffId' = 12412 - ENVIRONMENT_ENERGIZED_AMBIENCE_LARGE: 'CommonBuffId' = 12413 - ENVIRONMENT_ENERGIZED_AMBIENCE_MEDIUM: 'CommonBuffId' = 12414 - ENVIRONMENT_ENERGIZED_AMBIENCE_SMALL: 'CommonBuffId' = 12415 - ENVIRONMENT_FLIRTY_AMBIENCE_LARGE: 'CommonBuffId' = 12416 - ENVIRONMENT_FLIRTY_AMBIENCE_MEDIUM: 'CommonBuffId' = 12417 - ENVIRONMENT_FLIRTY_AMBIENCE_SMALL: 'CommonBuffId' = 12418 - ENVIRONMENT_FOCUSED_AMBIENCE_LARGE: 'CommonBuffId' = 12419 - ENVIRONMENT_FOCUSED_AMBIENCE_MEDIUM: 'CommonBuffId' = 12420 - ENVIRONMENT_FOCUSED_AMBIENCE_SMALL: 'CommonBuffId' = 12421 - ENVIRONMENT_HAPPY_AMBIENCE_LARGE: 'CommonBuffId' = 12422 - ENVIRONMENT_HAPPY_AMBIENCE_MEDIUM: 'CommonBuffId' = 12423 - ENVIRONMENT_HAPPY_AMBIENCE_SMALL: 'CommonBuffId' = 12424 - ENVIRONMENT_HAPPY_PEACE_AND_QUIET: 'CommonBuffId' = 179558 - ENVIRONMENT_HIDDEN_NEGATIVE: 'CommonBuffId' = 240236 - ENVIRONMENT_HIDDEN_NEGATIVE_SNOB: 'CommonBuffId' = 268126 - ENVIRONMENT_HIDDEN_POSITIVE: 'CommonBuffId' = 240234 - ENVIRONMENT_IMAGINATIVE_AMBIENCE_LARGE: 'CommonBuffId' = 12425 - ENVIRONMENT_IMAGINATIVE_AMBIENCE_MEDIUM: 'CommonBuffId' = 12426 - ENVIRONMENT_IMAGINATIVE_AMBIENCE_SMALL: 'CommonBuffId' = 12427 - ENVIRONMENT_NEGATIVE_BAD_SURROUNDINGS: 'CommonBuffId' = 12428 - ENVIRONMENT_NEGATIVE_ICKY_SURROUNDINGS: 'CommonBuffId' = 102939 - ENVIRONMENT_NEGATIVE_LITTER_BOX: 'CommonBuffId' = 172775 - ENVIRONMENT_NEGATIVE_UNPLEASANT_SURROUNDINGS: 'CommonBuffId' = 12429 - ENVIRONMENT_NEGATIVE_WRETCHED_SURROUNDINGS: 'CommonBuffId' = 12430 - ENVIRONMENT_PEACE_AND_QUIET_DISTRESS: 'CommonBuffId' = 179572 - ENVIRONMENT_PLAYFUL_AMBIENCE_LARGE: 'CommonBuffId' = 12431 - ENVIRONMENT_PLAYFUL_AMBIENCE_MEDIUM: 'CommonBuffId' = 12432 - ENVIRONMENT_PLAYFUL_AMBIENCE_SMALL: 'CommonBuffId' = 12433 - ENVIRONMENT_SAD_AMBIENCE_LARGE: 'CommonBuffId' = 12434 - ENVIRONMENT_SAD_AMBIENCE_MEDIUM: 'CommonBuffId' = 12435 - ENVIRONMENT_SAD_AMBIENCE_SMALL: 'CommonBuffId' = 12436 - ENVIRONMENT_SCARED_AMBIENCE_LARGE: 'CommonBuffId' = 251728 - ENVIRONMENT_SCARED_AMBIENCE_MEDIUM: 'CommonBuffId' = 251727 - ENVIRONMENT_SCARED_AMBIENCE_SMALL: 'CommonBuffId' = 251725 - ENVIRONMENT_TENSE_AMBIENCE_LARGE: 'CommonBuffId' = 12437 - ENVIRONMENT_TENSE_AMBIENCE_MEDIUM: 'CommonBuffId' = 12438 - ENVIRONMENT_TENSE_AMBIENCE_SMALL: 'CommonBuffId' = 12439 - EP10_FESTIVALS_AUTONOMY_BLESSING: 'CommonBuffId' = 252289 - EP10_FESTIVALS_AUTONOMY_HIKE: 'CommonBuffId' = 252281 - EP10_FESTIVALS_AUTONOMY_SELFIE: 'CommonBuffId' = 252290 - EP10_FESTIVALS_AUTONOMY_SNOW_FIGHT: 'CommonBuffId' = 253133 - EP10_FESTIVALS_AUTONOMY_VOID_CRITTER_HUNT: 'CommonBuffId' = 252288 - EP10_FESTIVALS_AUTONOMY_WISH: 'CommonBuffId' = 252282 - EP10_FESTIVALS_BLESSED_CHECK: 'CommonBuffId' = 267478 - EP10_FESTIVALS_GIVE_BLESSING: 'CommonBuffId' = 250932 - EP10_FESTIVALS_GOOD_WEATHER: 'CommonBuffId' = 254917 - EP10_FESTIVALS_GOOD_WEATHER_SNOW_FESTIVAL: 'CommonBuffId' = 254920 - EP10_FESTIVALS_MAKE_A_WISH: 'CommonBuffId' = 246877 - EP10_FESTIVALS_MAKE_A_WISH_TOGETHER: 'CommonBuffId' = 246878 - EP10_FESTIVALS_UNBLESSED_CHECK: 'CommonBuffId' = 253271 - EP10_FESTIVALS_VOID_CRITTER_HUNT_AVAILABLE: 'CommonBuffId' = 252725 - EP10_FESTIVALS_VOID_CRITTER_HUNT_AVAILABLE_NPC: 'CommonBuffId' = 252908 - EP10_FESTIVALS_VOID_CRITTER_HUNT_RECEIVED_PRIZE: 'CommonBuffId' = 252726 - EP10_FESTIVALS_VOID_CRITTER_HUNT_REMOVE_COUNT_AFTER_FESTIVAL: 'CommonBuffId' = 253423 - EP13_WORLD_FEELING_ANCHORED: 'CommonBuffId' = 320494 - EP13_WORLD_FISHERMANS_LUCK: 'CommonBuffId' = 320491 - EP13_WORLD_FOREST_FOR_THE_TREES: 'CommonBuffId' = 320495 - EP13_WORLD_STREET_PIANO_TUNES: 'CommonBuffId' = 320493 - EP13_WORLD_TOPIARYTASTIC: 'CommonBuffId' = 320516 - EP13_WORLD_WATCHOUT_FOR_WHITE_CLAW: 'CommonBuffId' = 320517 - EP13_WORLD_WHALEY_HAPPY: 'CommonBuffId' = 320518 - EP14_WORLD_CAVE_EXIT: 'CommonBuffId' = 325772 - EP14_WORLD_CAVE_FAILURE_EXIT: 'CommonBuffId' = 325025 - EP14_WORLD_CAVE_SELF_AWARE: 'CommonBuffId' = 325664 - EP14_WORLD_CAVE_SURVIVED_THE_CAVE: 'CommonBuffId' = 325665 - EP14_WORLD_CAVE_SURVIVED_THE_CAVE_DAZED: 'CommonBuffId' = 325666 - EP14_WORLD_HORSE_GRAVE: 'CommonBuffId' = 335440 - EP14_WORLD_NPC_ASK_FOR_LIFE_NECTAR_INGREDIENTS_MYSTERIOUS_RANCHER_COOLDOWN: 'CommonBuffId' = 322426 - EP14_WORLD_NPC_BONDING_TIME: 'CommonBuffId' = 322243 - EP14_WORLD_NPC_HIDDEN_READY_TO_RIDE_COOLDOWN: 'CommonBuffId' = 329418 - EP14_WORLD_NPC_NECTAR_KNOWLEDGE: 'CommonBuffId' = 322245 - EP14_WORLD_NPC_READY_TO_RANCH: 'CommonBuffId' = 322244 - EP14_WORLD_NPC_READY_TO_RIDE: 'CommonBuffId' = 322246 - EP14_WORLD_PROXIMITY_HORSE_ROCK: 'CommonBuffId' = 337346 - EP15_ADOPT_TIGER_ENERGIZED: 'CommonBuffId' = 353581 - EP15_ADOPT_TIGER_HAPPY: 'CommonBuffId' = 353582 - EP15_ADOPT_TIGER_HAPPY_PAT: 'CommonBuffId' = 353585 - EP15_ADOPT_TIGER_SAD: 'CommonBuffId' = 353583 - EP15_ADOPT_TIGER_SPECIAL_HAPPY: 'CommonBuffId' = 353584 - EP15_TRAIT_LOCAL: 'CommonBuffId' = 343328 - EP16_SPECIAL_NPC_SAD_BEAR: 'CommonBuffId' = 370490 - EP16_WORLD_FOUNTAIN_OF_DREAMS_STEAL_COOLDOWN_HIDDEN: 'CommonBuffId' = 369421 - EP16_WORLD_FOUNTAIN_OF_DREAMS_WISH_FOR_HAPPINESS: 'CommonBuffId' = 369265 - EP16_WORLD_FOUNTAIN_OF_DREAMS_WISH_FOR_LOVE: 'CommonBuffId' = 369264 - EP16_WORLD_FOUNTAIN_OF_DREAMS_WISH_FOR_OTHERS_HAPPINESS: 'CommonBuffId' = 369266 - EP16_WORLD_FOUNTAIN_OF_DREAMS_WISH_FOR_OTHERS_UNHAPPINESS: 'CommonBuffId' = 369297 - EP16_WORLD_REGION: 'CommonBuffId' = 388993 - EP16_WORLD_ROMANTIC_BLANKET_SPOT: 'CommonBuffId' = 370503 - EP16_WORLD_ROMANTIC_DATE_SPOT: 'CommonBuffId' = 370504 - EP16_WORLD_ROMANTIC_SUNSET_SPOT: 'CommonBuffId' = 370502 - EP16_WORLD_ROMANTIC_WALK: 'CommonBuffId' = 370508 - EP16_WORLD_WALL_OF_LOVE_CHANGE_LOVE_DECLARATIONS: 'CommonBuffId' = 369301 - EP16_WORLD_WALL_OF_LOVE_SYMBOL_OF_LOVE_ATTACHED: 'CommonBuffId' = 369299 - EP16_WORLD_WALL_OF_LOVE_SYMBOL_OF_LOVE_ERASED: 'CommonBuffId' = 369300 - EQUESTRIAN_CENTER_WATCHED_COMPETITIONS: 'CommonBuffId' = 333397 - EVENT_CONFIDENT: 'CommonBuffId' = 29685 - EVENT_ENERGIZED: 'CommonBuffId' = 29686 - EVENT_MARK: 'CommonBuffId' = 25287 - EVENT_NPC_HORSE_TRAINER_ADVERTISE_COOLDOWN: 'CommonBuffId' = 349073 - EVENT_NPC_IDLE: 'CommonBuffId' = 154886 - EVENT_NPC_VISITED_MAILBOX_COOLDOWN: 'CommonBuffId' = 154883 - EVENT_PLAYFUL: 'CommonBuffId' = 29683 - EVENT_STRESSED: 'CommonBuffId' = 29684 - EVENT_UNCOMFORTABLE: 'CommonBuffId' = 118871 - EVICTION_SYSTEM_JUST_EVICTED: 'CommonBuffId' = 355065 - EVICTION_SYSTEM_KICKED_OUT: 'CommonBuffId' = 346420 - EVICTION_SYSTEM_STAY_SUCCESS_CONFIDENT: 'CommonBuffId' = 346418 - EVICTION_SYSTEM_STAY_SUCCESS_HAPPY: 'CommonBuffId' = 346417 - EVICTION_SYSTEM_TENANT_ANGRY: 'CommonBuffId' = 355127 - EVICTION_SYSTEM_TENANT_ROLE: 'CommonBuffId' = 346412 - EXCURSION_MOUNTAIN_ACT_01_TIN_EMBARRASSED_LEADER: 'CommonBuffId' = 249367 - EXCURSION_MOUNTAIN_ACT_1_GOLD_HAPPY: 'CommonBuffId' = 241132 - EXCURSION_MOUNTAIN_ACT_1_SILVER_HAPPY: 'CommonBuffId' = 249411 - EXCURSION_MOUNTAIN_ACT_2_BRONZE_ANGRY: 'CommonBuffId' = 241126 - EXCURSION_MOUNTAIN_ACT_2_BRONZE_TENSE: 'CommonBuffId' = 241120 - EXCURSION_MOUNTAIN_ACT_2_GOLD_HAPPY: 'CommonBuffId' = 241130 - EXCURSION_MOUNTAIN_ACT_2_SILVER_HAPPY: 'CommonBuffId' = 249431 - EXCURSION_MOUNTAIN_ACT_2_TIN_SAD: 'CommonBuffId' = 249423 - EXCURSION_MOUNTAIN_ACT_3_AGAINST_ALL_ODDS: 'CommonBuffId' = 249539 - EXCURSION_MOUNTAIN_ACT_3_BRONZE: 'CommonBuffId' = 242018 - EXCURSION_MOUNTAIN_ACT_3_BRONZE_EMBARRASSED: 'CommonBuffId' = 241121 - EXCURSION_MOUNTAIN_ACT_3_DEFYING_GRAVITY: 'CommonBuffId' = 249540 - EXCURSION_MOUNTAIN_ACT_3_FEET_SHORT: 'CommonBuffId' = 249536 - EXCURSION_MOUNTAIN_ACT_3_GOLD_CONFIDENT: 'CommonBuffId' = 241125 - EXCURSION_MOUNTAIN_ACT_3_GOLD_INSPIRED: 'CommonBuffId' = 241119 - EXCURSION_MOUNTAIN_ACT_3_SILVER_CONFIDENT: 'CommonBuffId' = 241122 - EXCURSION_MOUNTAIN_ACT_3_SILVER_INSPIRED: 'CommonBuffId' = 241124 - EXCURSION_MOUNTAIN_ACT_3_TOP_OF_WORLD: 'CommonBuffId' = 249538 - EXCURSION_MOUNTAIN_BONKED_HEAD: 'CommonBuffId' = 249366 - EXCURSION_MOUNTAIN_CAVE_DRINK: 'CommonBuffId' = 253527 - EXCURSION_MOUNTAIN_CAVE_SLEEP: 'CommonBuffId' = 253528 - EXCURSION_MOUNTAIN_CAVE_WOOHOO: 'CommonBuffId' = 253625 - EXCURSION_MOUNTAIN_CLIMBING_MAP_NEAR: 'CommonBuffId' = 248013 - EXCURSION_MOUNTAIN_CLIMBING_PLAQUE_RANK_01: 'CommonBuffId' = 250091 - EXCURSION_MOUNTAIN_CLIMBING_PLAQUE_RANK_02: 'CommonBuffId' = 250094 - EXCURSION_MOUNTAIN_CLIMBING_PLAQUE_RANK_03: 'CommonBuffId' = 250095 - EXCURSION_MOUNTAIN_CLIMB_TAKE_PHOTO_COOLDOWN: 'CommonBuffId' = 250978 - EXCURSION_MOUNTAIN_CLIMB_TAKE_SELFIE_COOLDOWN: 'CommonBuffId' = 250891 - EXCURSION_MOUNTAIN_DIDNT_REACH_THE_PEAK: 'CommonBuffId' = 252879 - EXCURSION_MOUNTAIN_FIGHT_COOLDOWN: 'CommonBuffId' = 241768 - EXCURSION_MOUNTAIN_GROUP_MEMBER: 'CommonBuffId' = 241760 - EXCURSION_MOUNTAIN_HIDDEN_REACTION: 'CommonBuffId' = 241983 - EXCURSION_MOUNTAIN_INSPECT_CLIMB_COOLDOWN: 'CommonBuffId' = 241773 - EXCURSION_MOUNTAIN_MOTIVE_ADJUST: 'CommonBuffId' = 254801 - EXCURSION_MOUNTAIN_STUBBED_TOE: 'CommonBuffId' = 249365 - EXCURSION_MOUNTAIN_TIN_SAD: 'CommonBuffId' = 241227 - EXCURSION_MOUNTAIN_TIN_SAD_CLIMBER: 'CommonBuffId' = 249433 - EXPERIMENTAL_CURE_TESTED_ON_SELF: 'CommonBuffId' = 207406 - FACIAL_MASK_APPLIED_ANTI_AGING: 'CommonBuffId' = 271590 - FACIAL_MASK_APPLIED_ANTI_AGING_READY_TO_REMOVE: 'CommonBuffId' = 271591 - FACIAL_MASK_APPLIED_BASIC: 'CommonBuffId' = 271343 - FACIAL_MASK_APPLIED_BASIC_READY_TO_REMOVE: 'CommonBuffId' = 271348 - FACIAL_MASK_APPLIED_FAMILY_CTYAE: 'CommonBuffId' = 271528 - FACIAL_MASK_APPLIED_FAMILY_CTYAE_READY_TO_REMOVE: 'CommonBuffId' = 271531 - FACIAL_MASK_APPLIED_FAMILY_HATES_CHILDREN: 'CommonBuffId' = 271530 - FACIAL_MASK_APPLIED_FAMILY_HATES_CHILDREN_READY_TO_REMOVE: 'CommonBuffId' = 271534 - FACIAL_MASK_APPLIED_FAMILY_TODDLER: 'CommonBuffId' = 271529 - FACIAL_MASK_APPLIED_FAMILY_TODDLER_READY_TO_REMOVE: 'CommonBuffId' = 271533 - FACIAL_MASK_APPLIED_GOLD: 'CommonBuffId' = 271567 - FACIAL_MASK_APPLIED_GOLD_FREEGAN: 'CommonBuffId' = 271568 - FACIAL_MASK_APPLIED_GOLD_FREEGAN_READY_TO_REMOVE: 'CommonBuffId' = 271572 - FACIAL_MASK_APPLIED_GOLD_READY_TO_REMOVE: 'CommonBuffId' = 271573 - FACIAL_MASK_APPLIED_GOLD_SPECIAL: 'CommonBuffId' = 271569 - FACIAL_MASK_APPLIED_GOLD_SPECIAL_READY_TO_REMOVE: 'CommonBuffId' = 271574 - FACIAL_MASK_APPLIED_HYDRATING: 'CommonBuffId' = 271585 - FACIAL_MASK_APPLIED_HYDRATING_MERMAID: 'CommonBuffId' = 271604 - FACIAL_MASK_APPLIED_HYDRATING_MERMAID_READY_TO_REMOVE: 'CommonBuffId' = 271605 - FACIAL_MASK_APPLIED_HYDRATING_READY_TO_REMOVE: 'CommonBuffId' = 271586 - FACIAL_MASK_APPLIED_RANCID: 'CommonBuffId' = 272295 - FACIAL_MASK_APPLIED_RANCID_READY_TO_REMOVE: 'CommonBuffId' = 272300 - FACIAL_MASK_APPLIED_RANCID_VEGETARIAN: 'CommonBuffId' = 272296 - FACIAL_MASK_APPLIED_RANCID_VEGETARIAN_READY_TO_REMOVE: 'CommonBuffId' = 272302 - FACIAL_MASK_APPLIED_TOO_LONG_ANTIAGING: 'CommonBuffId' = 271583 - FACIAL_MASK_APPLIED_TOO_LONG_BASIC: 'CommonBuffId' = 271351 - FACIAL_MASK_APPLIED_TOO_LONG_FAMILY_TODDLER: 'CommonBuffId' = 271535 - FACIAL_MASK_APPLIED_TOO_LONG_GOLD: 'CommonBuffId' = 271580 - FACIAL_MASK_APPLIED_TOO_LONG_HYDRATING: 'CommonBuffId' = 271582 - FACIAL_MASK_APPLIED_TOO_LONG_RANCID: 'CommonBuffId' = 272298 - FACIAL_MASK_APPLIED_TOO_LONG_UV: 'CommonBuffId' = 271581 - FACIAL_MASK_APPLIED_UV: 'CommonBuffId' = 271593 - FACIAL_MASK_APPLIED_UV_READY_TO_REMOVE: 'CommonBuffId' = 271592 - FACIAL_MASK_BONUS_ANTI_AGING: 'CommonBuffId' = 271559 - FACIAL_MASK_BONUS_ANTI_AGING_BASIC: 'CommonBuffId' = 271560 - FACIAL_MASK_BONUS_BASIC: 'CommonBuffId' = 271462 - FACIAL_MASK_BONUS_FAMILY: 'CommonBuffId' = 271537 - FACIAL_MASK_BONUS_FAMILY_HATES_CHILDREN: 'CommonBuffId' = 271538 - FACIAL_MASK_BONUS_GOLD: 'CommonBuffId' = 271565 - FACIAL_MASK_BONUS_GOLD_FREEGAN: 'CommonBuffId' = 271566 - FACIAL_MASK_BONUS_GOLD_SPECIAL: 'CommonBuffId' = 271564 - FACIAL_MASK_BONUS_HYDRATING: 'CommonBuffId' = 271561 - FACIAL_MASK_BONUS_HYDRATING_MERMAID: 'CommonBuffId' = 271606 - FACIAL_MASK_BONUS_UV: 'CommonBuffId' = 271563 - FACIAL_MASK_BONUS_UV_VAMPIRE: 'CommonBuffId' = 271562 - FACIAL_MASK_COLD_BONUS: 'CommonBuffId' = 271634 - FACIAL_MASK_IRRITATED_SKIN: 'CommonBuffId' = 272291 - FACIAL_MASK_MASTER_ANTI_AGING: 'CommonBuffId' = 271551 - FACIAL_MASK_MASTER_FAMILY_CTYAE: 'CommonBuffId' = 271539 - FACIAL_MASK_MASTER_FAMILY_TODDLER: 'CommonBuffId' = 271541 - FACIAL_MASK_MASTER_GOLD: 'CommonBuffId' = 271557 - FACIAL_MASK_MASTER_HYDRATING: 'CommonBuffId' = 271558 - FACIAL_MASK_MASTER_RANCID: 'CommonBuffId' = 272293 - FACIAL_MASK_MASTER_RELAXING: 'CommonBuffId' = 271366 - FACIAL_MASK_MASTER_UV: 'CommonBuffId' = 271556 - FALL_CHALLENGE_DO_TD_CELEBRANT_ROLE: 'CommonBuffId' = 155506 - FALL_CHALLENGE_DO_TD_CELEBRANT_ROLE_ALWAYS: 'CommonBuffId' = 155504 - FALL_CHALLENGE_DO_TD_CELEBRATE_BUFF: 'CommonBuffId' = 153306 - FALL_CHALLENGE_DO_TD_CELEBRATE_CHILD: 'CommonBuffId' = 154600 - FALL_CHALLENGE_DO_TD_CELEBRATE_COSTUME_VFX_REMOVE_CHILD: 'CommonBuffId' = 154629 - FALL_CHALLENGE_DO_TD_CELEBRATE_COSTUME_VFX_REMOVE_CHILD_F: 'CommonBuffId' = 155143 - FALL_CHALLENGE_DO_TD_CELEBRATE_COSTUME_VFX_REMOVE_F_PREF: 'CommonBuffId' = 154628 - FALL_CHALLENGE_DO_TD_CELEBRATE_F_CHILD: 'CommonBuffId' = 155142 - FALL_CHALLENGE_DO_TD_CELEBRATE_F_PREF: 'CommonBuffId' = 153404 - FALL_CHALLENGE_DO_TD_CELEBRATE_M_PREF_VFX_REMOVE: 'CommonBuffId' = 154722 - FALL_CHALLENGE_DO_TD_HAS_BEEN_ASKED_FOR_SKULL: 'CommonBuffId' = 153215 - FALL_CHALLENGE_DO_TD_URN_STONE_COOLDOWN: 'CommonBuffId' = 154654 - FAME_FAME_OPPORTUNITY_ACTIVIST_BASE: 'CommonBuffId' = 192882 - FAME_FAME_OPPORTUNITY_ACTIVIST_POLITICIAN: 'CommonBuffId' = 192917 - FAME_FAME_OPPORTUNITY_ENTERTAINER_MUSIC: 'CommonBuffId' = 192961 - FAME_FAME_OPPORTUNITY_GARDENER_BASE: 'CommonBuffId' = 195695 - FAME_FAME_OPPORTUNITY_GARDENER_FLORIST: 'CommonBuffId' = 192962 - FAME_FAME_OPPORTUNITY_PAINTER_BASE: 'CommonBuffId' = 192963 - FAME_FAME_OPPORTUNITY_QUIT: 'CommonBuffId' = 202220 - FAME_FAME_OPPORTUNITY_SECRET_AGENT_VILLAIN: 'CommonBuffId' = 192965 - FAME_FAME_OPPORTUNITY_SOCIAL_MEDIA_BASE: 'CommonBuffId' = 192966 - FAME_FAME_OPPORTUNITY_STYLE_INFLUENCER_STYLIST: 'CommonBuffId' = 194321 - FAME_FAME_OPPORTUNITY_TECH_GURU_BASE: 'CommonBuffId' = 192967 - FAME_FAME_OPPORTUNITY_WRITER_BASE: 'CommonBuffId' = 192968 - FAME_LEVEL_1: 'CommonBuffId' = 191809 - FAME_LEVEL_2: 'CommonBuffId' = 191813 - FAME_LEVEL_3: 'CommonBuffId' = 191814 - FAME_LEVEL_4: 'CommonBuffId' = 191811 - FAME_LEVEL_5: 'CommonBuffId' = 191812 - FAME_LOCK_STAT: 'CommonBuffId' = 192950 - FAME_PERK_BAD_REPUTATION_PLAY_THE_VILLAIN: 'CommonBuffId' = 193788 - FAME_PERK_BRAND_ALL_NIGHTER: 'CommonBuffId' = 195943 - FAME_PERK_BRAND_ALL_NIGHTER_ACTIVE: 'CommonBuffId' = 195945 - FAME_PERK_BRAND_ALL_NIGHTER_CHARITY_STREAM: 'CommonBuffId' = 196061 - FAME_PERK_BRAND_ALL_NIGHTER_ENERGY_DRAIN: 'CommonBuffId' = 195949 - FAME_PERK_BRAND_CORPORATE_PARTNERSHIP: 'CommonBuffId' = 197602 - FAME_PERK_BRAND_LIFESTYLE_BRAND: 'CommonBuffId' = 197601 - FAME_PERK_BRAND_TRAILBLAZER: 'CommonBuffId' = 197600 - FAME_PERK_CAREER_HOPPER_PERK_BUFF: 'CommonBuffId' = 196005 - FAME_PERK_CELEBRITY_CLEANSE_FOCUSED: 'CommonBuffId' = 197596 - FAME_PERK_CELEBU_SERUM_DRANK_CONFIDENT: 'CommonBuffId' = 194891 - FAME_PERK_CELEBU_SERUM_DRANK_ENERGY: 'CommonBuffId' = 194892 - FAME_PERK_CELEBU_SERUM_DRANK_FLIRTY: 'CommonBuffId' = 194893 - FAME_PERK_CELEBU_SERUM_DRANK_FOCUS: 'CommonBuffId' = 194894 - FAME_PERK_CELEBU_SERUM_DRANK_FUN: 'CommonBuffId' = 194889 - FAME_PERK_CELEBU_SERUM_DRANK_HAPPY: 'CommonBuffId' = 194895 - FAME_PERK_CELEBU_SERUM_DRANK_HYGIENE: 'CommonBuffId' = 194890 - FAME_PERK_CELEBU_SERUM_DRANK_INSPIRED: 'CommonBuffId' = 194896 - FAME_PERK_CELEBU_SERUM_DRANK_SLEEP: 'CommonBuffId' = 194920 - FAME_PERK_CELEBU_SERUM_MAILBOX_TIMER: 'CommonBuffId' = 194603 - FAME_PERK_CELEBU_SERUM_WITHDRAWAL_TIMER: 'CommonBuffId' = 194990 - FAME_PERK_CORPORATE_PARTNERSHIP_DIALOG_COOLDOWN: 'CommonBuffId' = 194046 - FAME_PERK_CORPORATE_PARTNERSHIP_ROYALTY_BONUS: 'CommonBuffId' = 193596 - FAME_PERK_CORPORATE_PARTNERSHIP_ROYALTY_BONUS_TREND1: 'CommonBuffId' = 194059 - FAME_PERK_CORPORATE_PARTNERSHIP_ROYALTY_BONUS_TREND2: 'CommonBuffId' = 194063 - FAME_PERK_CORPORATE_PARTNERSHIP_ROYALTY_BONUS_TREND3: 'CommonBuffId' = 194062 - FAME_PERK_CORPORATE_PARTNERSHIP_ROYALTY_BONUS_TREND4: 'CommonBuffId' = 194061 - FAME_PERK_CORPORATE_PARTNERSHIP_ROYALTY_BONUS_TREND5: 'CommonBuffId' = 194060 - FAME_PERK_EASY_STREET_CAREER: 'CommonBuffId' = 196719 - FAME_PERK_EASY_STREET_LEAVE_WORK_CONFIDENT: 'CommonBuffId' = 196740 - FAME_PERK_EASY_STREET_LEAVE_WORK_ENERGIZED: 'CommonBuffId' = 196741 - FAME_PERK_EASY_STREET_LEAVE_WORK_FLIRTY: 'CommonBuffId' = 196742 - FAME_PERK_EASY_STREET_LEAVE_WORK_FOCUSED: 'CommonBuffId' = 196743 - FAME_PERK_EASY_STREET_LEAVE_WORK_HAPPY: 'CommonBuffId' = 196744 - FAME_PERK_EASY_STREET_LEAVE_WORK_INSPIRED: 'CommonBuffId' = 196745 - FAME_PERK_EASY_STREET_LEAVE_WORK_PLAYFUL: 'CommonBuffId' = 196746 - FAME_PERK_FAN_FAVORITE_CONFIDENT: 'CommonBuffId' = 196264 - FAME_PERK_FAN_FAVORITE_DAZED: 'CommonBuffId' = 196263 - FAME_PERK_FAN_FAVORITE_FAN_COOLDOWN: 'CommonBuffId' = 201204 - FAME_PERK_FAN_FAVORITE_HAS_PERK: 'CommonBuffId' = 196153 - FAME_PERK_FEUD_BRINGER_COMMENT_BACKLASH: 'CommonBuffId' = 193883 - FAME_PERK_FEUD_BRINGER_DISCUSSED_FEUD: 'CommonBuffId' = 193882 - FAME_PERK_FEUD_BRINGER_ENCOURAGING_CHIRPS: 'CommonBuffId' = 193885 - FAME_PERK_FEUD_BRINGER_HIDDEN_END_FEUD: 'CommonBuffId' = 193874 - FAME_PERK_FEUD_BRINGER_HIDDEN_FEUD_CHECK: 'CommonBuffId' = 193851 - FAME_PERK_FEUD_BRINGER_HIDDEN_PERK_BUFF: 'CommonBuffId' = 193978 - FAME_PERK_FEUD_BRINGER_INFURIATING_COMMENTS: 'CommonBuffId' = 193884 - FAME_PERK_FEUD_BRINGER_LOSING_FEUD: 'CommonBuffId' = 193886 - FAME_PERK_FEUD_BRINGER_LOST_FEUD: 'CommonBuffId' = 200325 - FAME_PERK_FEUD_BRINGER_WINNING_FEUD: 'CommonBuffId' = 193887 - FAME_PERK_GOOD_REPUTATION_GIVING_BACK: 'CommonBuffId' = 193789 - FAME_PERK_GOOD_REPUTATION_STAR_TREATMENT: 'CommonBuffId' = 193791 - FAME_PERK_GOOD_REPUTATION_STAR_TREATMENT_BROADCASTER_DELAY: 'CommonBuffId' = 196894 - FAME_PERK_GOOD_REPUTATION_STAR_TREATMENT_HIDDEN_REACT_COOLDOWN: 'CommonBuffId' = 202214 - FAME_PERK_HAS_PERK_RALLY: 'CommonBuffId' = 196071 - FAME_PERK_INFLUENCER: 'CommonBuffId' = 196259 - FAME_PERK_INFLUENCER_GIFT_RECIPIENT: 'CommonBuffId' = 194097 - FAME_PERK_INFLUENCER_LETTER_BUFFS_CONFIDENT: 'CommonBuffId' = 194852 - FAME_PERK_INFLUENCER_LETTER_BUFFS_ENERGIZED: 'CommonBuffId' = 194851 - FAME_PERK_INFLUENCER_LETTER_BUFFS_HAPPY: 'CommonBuffId' = 194848 - FAME_PERK_INFLUENCER_LETTER_BUFFS_INSPIRED: 'CommonBuffId' = 194849 - FAME_PERK_INFLUENCER_LETTER_BUFFS_PLAYFUL: 'CommonBuffId' = 194850 - FAME_PERK_INFLUENCER_NOT_GIFT_RECIPIENT: 'CommonBuffId' = 194098 - FAME_PERK_INSTANT_BESTIES: 'CommonBuffId' = 195135 - FAME_PERK_RALLY_AUDIENCE_EFFECTS: 'CommonBuffId' = 196223 - FAME_PERK_RALLY_AUTONOMOUS_WATCH: 'CommonBuffId' = 196030 - FAME_PERK_RALLY_COOLDOWN: 'CommonBuffId' = 198882 - FAME_PERK_RALLY_RALLYER_EFFECTS: 'CommonBuffId' = 196326 - FAME_PERK_RALLY_RALLYING: 'CommonBuffId' = 196064 - FAME_PERK_RELATIONSHIP_GAME_NETWORKING: 'CommonBuffId' = 193581 - FAME_PERK_RELATIONSHIP_GAME_PR_PERSON: 'CommonBuffId' = 195109 - FAME_PERK_RELATIONSHIP_GAME_PR_PERSON_COOLDOWN: 'CommonBuffId' = 195315 - FAME_PERK_RELATIONSHIP_GAME_PR_PERSON_DAZED: 'CommonBuffId' = 195319 - FAME_PERK_RELATIONSHIP_GAME_PR_PERSON_PLAYFUL: 'CommonBuffId' = 195482 - FAME_PERK_SKILL_CAREER_CELEBU_SERUM: 'CommonBuffId' = 197597 - FAME_PERK_SKILL_CAREER_ESTABLISHED_NAME: 'CommonBuffId' = 197599 - FAME_PERK_SKILL_CAREER_NOTICEABLE: 'CommonBuffId' = 197598 - FAME_PERK_SQUAD_COOLDOWN: 'CommonBuffId' = 196267 - FAME_PERK_SQUAD_OWNER: 'CommonBuffId' = 194260 - FAME_PERK_SQUAD_PERK_BUFF: 'CommonBuffId' = 196113 - FAME_PERK_SQUAD_ROLE: 'CommonBuffId' = 194255 - FAME_PERK_WHOS_BAD_HAS_PERK_REPUTATION_DECREASE: 'CommonBuffId' = 196175 - FAME_PROGRESSION_RANK_DOWN_0: 'CommonBuffId' = 189452 - FAME_PROGRESSION_RANK_DOWN_1: 'CommonBuffId' = 189448 - FAME_PROGRESSION_RANK_DOWN_2: 'CommonBuffId' = 189449 - FAME_PROGRESSION_RANK_DOWN_3: 'CommonBuffId' = 189450 - FAME_PROGRESSION_RANK_DOWN_4: 'CommonBuffId' = 189451 - FAME_PROGRESSION_RANK_DOWN_AMBITIOUS_0: 'CommonBuffId' = 189458 - FAME_PROGRESSION_RANK_DOWN_AMBITIOUS_1: 'CommonBuffId' = 189459 - FAME_PROGRESSION_RANK_DOWN_AMBITIOUS_2: 'CommonBuffId' = 189460 - FAME_PROGRESSION_RANK_DOWN_AMBITIOUS_3: 'CommonBuffId' = 189461 - FAME_PROGRESSION_RANK_DOWN_AMBITIOUS_4: 'CommonBuffId' = 189462 - FAME_PROGRESSION_RANK_UP_1: 'CommonBuffId' = 189443 - FAME_PROGRESSION_RANK_UP_2: 'CommonBuffId' = 189444 - FAME_PROGRESSION_RANK_UP_3: 'CommonBuffId' = 189445 - FAME_PROGRESSION_RANK_UP_4: 'CommonBuffId' = 189446 - FAME_PROGRESSION_RANK_UP_5: 'CommonBuffId' = 189442 - FAME_PROGRESSION_RANK_UP_AMBITIOUS_1: 'CommonBuffId' = 189465 - FAME_PROGRESSION_RANK_UP_AMBITIOUS_2: 'CommonBuffId' = 189466 - FAME_PROGRESSION_RANK_UP_AMBITIOUS_3: 'CommonBuffId' = 189467 - FAME_PROGRESSION_RANK_UP_AMBITIOUS_4: 'CommonBuffId' = 189468 - FAME_PROGRESSION_RANK_UP_AMBITIOUS_5: 'CommonBuffId' = 189464 - FAME_QUIRK_A_SERIOUS_ACTOR: 'CommonBuffId' = 192853 - FAME_QUIRK_A_SERIOUS_ACTOR_ANGRY: 'CommonBuffId' = 195908 - FAME_QUIRK_A_SERIOUS_ACTOR_INSPIRED: 'CommonBuffId' = 195909 - FAME_QUIRK_BE_GONE_COOLDOWN: 'CommonBuffId' = 195873 - FAME_QUIRK_BRUSHES_WITH_FAME: 'CommonBuffId' = 192852 - FAME_QUIRK_BRUSHES_WITH_FAME_ENERGIZED: 'CommonBuffId' = 194083 - FAME_QUIRK_BRUSHES_WITH_FAME_SAD: 'CommonBuffId' = 194082 - FAME_QUIRK_EMOTION_BOMB: 'CommonBuffId' = 192854 - FAME_QUIRK_EMOTION_BOMB_EXTRA_ANGER: 'CommonBuffId' = 196436 - FAME_QUIRK_EMOTION_BOMB_EXTRA_SADNESS: 'CommonBuffId' = 196438 - FAME_QUIRK_FAN_MAIL: 'CommonBuffId' = 192851 - FAME_QUIRK_JUICE_ENTHUSIAST: 'CommonBuffId' = 192860 - FAME_QUIRK_JUICE_ENTHUSIAST_ANGRY_CHILD: 'CommonBuffId' = 196077 - FAME_QUIRK_JUICE_ENTHUSIAST_ANGRY_TYAE: 'CommonBuffId' = 196050 - FAME_QUIRK_JUICE_ENTHUSIAST_CHILD: 'CommonBuffId' = 196276 - FAME_QUIRK_JUICE_ENTHUSIAST_ENERGIZED_CHILD: 'CommonBuffId' = 196079 - FAME_QUIRK_JUICE_ENTHUSIAST_ENERGIZED_TYAE: 'CommonBuffId' = 196048 - FAME_QUIRK_JUICE_ENTHUSIAST_SAD_CHILD: 'CommonBuffId' = 196081 - FAME_QUIRK_JUICE_ENTHUSIAST_SAD_TYAE: 'CommonBuffId' = 196049 - FAME_QUIRK_NO_TOUCHING: 'CommonBuffId' = 192856 - FAME_QUIRK_NO_TOUCHING_CONFIDENT: 'CommonBuffId' = 194079 - FAME_QUIRK_NO_TOUCHING_STRESSED: 'CommonBuffId' = 194078 - FAME_QUIRK_PAPARAZZI_DARLING: 'CommonBuffId' = 192859 - FAME_QUIRK_PAPARAZZI_DARLING_SHUTTER_LOVE: 'CommonBuffId' = 196144 - FAME_QUIRK_PHONE_FANATIC: 'CommonBuffId' = 191666 - FAME_QUIRK_PHONE_FANATIC_STRESSED: 'CommonBuffId' = 191707 - FAME_QUIRK_PUBLIC_NUMBER: 'CommonBuffId' = 192858 - FAME_QUIRK_PUBLIC_NUMBER_ANGRY: 'CommonBuffId' = 195406 - FAME_QUIRK_PUBLIC_NUMBER_EMBARRASSED: 'CommonBuffId' = 195405 - FAME_QUIRK_PUBLIC_NUMBER_FLIRTY: 'CommonBuffId' = 195407 - FAME_QUIRK_PUBLIC_NUMBER_HAPPY: 'CommonBuffId' = 195403 - FAME_QUIRK_PUBLIC_NUMBER_HIDDEN_COOLDOWN: 'CommonBuffId' = 198690 - FAME_QUIRK_PUBLIC_NUMBER_INSPIRED: 'CommonBuffId' = 195409 - FAME_QUIRK_PUBLIC_NUMBER_SAD: 'CommonBuffId' = 195404 - FAME_QUIRK_PUBLIC_NUMBER_STRESSED: 'CommonBuffId' = 195408 - FAME_QUIRK_REFINED_PALATE: 'CommonBuffId' = 192857 - FAME_QUIRK_STAN: 'CommonBuffId' = 192850 - FAME_QUIRK_VAIN_STREET: 'CommonBuffId' = 192855 - FAME_QUIRK_VAIN_STREET_CONFIDENT: 'CommonBuffId' = 195992 - FAME_QUIRK_VAIN_STREET_STRESSED: 'CommonBuffId' = 195991 - FAME_SHINE_RANK4: 'CommonBuffId' = 199150 - FAME_SHINE_RANK5: 'CommonBuffId' = 199151 - FAME_SOCIAL_EVENT_GOLD: 'CommonBuffId' = 200706 - FAMILIAR_ACTIVE: 'CommonBuffId' = 222233 - FAMILIAR_PET_ACTIVE_ADULT_CAT_SMALL_DOG: 'CommonBuffId' = 222231 - FAMILIAR_PET_ACTIVE_ADULT_LARGE_DOG: 'CommonBuffId' = 222230 - FAMILIAR_PET_ACTIVE_CHILD: 'CommonBuffId' = 222232 - FAMILIAR_RESURRECT: 'CommonBuffId' = 215224 - FAMILIAR_RESURRECT_COOLDOWN: 'CommonBuffId' = 215225 - FAMILIAR_TNS_COOLDOWN: 'CommonBuffId' = 215227 - FAMILIES_ARGUMENTS_LOSER: 'CommonBuffId' = 159389 - FAMILIES_ARGUMENTS_NO_WINNER: 'CommonBuffId' = 160084 - FAMILIES_ARGUMENTS_TYPE_ARGUMENTS: 'CommonBuffId' = 160061 - FAMILIES_ARGUMENTS_TYPE_CAREER: 'CommonBuffId' = 160050 - FAMILIES_ARGUMENTS_TYPE_CHILDREN: 'CommonBuffId' = 160052 - FAMILIES_ARGUMENTS_TYPE_CLEANLINESS: 'CommonBuffId' = 160057 - FAMILIES_ARGUMENTS_TYPE_CURFEW: 'CommonBuffId' = 168136 - FAMILIES_ARGUMENTS_TYPE_EXERCISING: 'CommonBuffId' = 160067 - FAMILIES_ARGUMENTS_TYPE_FOOD: 'CommonBuffId' = 160070 - FAMILIES_ARGUMENTS_TYPE_HOUSE_RULES: 'CommonBuffId' = 160065 - FAMILIES_ARGUMENTS_TYPE_HUMOR: 'CommonBuffId' = 160054 - FAMILIES_ARGUMENTS_TYPE_JOB: 'CommonBuffId' = 160063 - FAMILIES_ARGUMENTS_TYPE_KINDNESS: 'CommonBuffId' = 160053 - FAMILIES_ARGUMENTS_TYPE_LIFE_GOALS: 'CommonBuffId' = 160068 - FAMILIES_ARGUMENTS_TYPE_LIFE_OUTLOOK: 'CommonBuffId' = 160069 - FAMILIES_ARGUMENTS_TYPE_MORALS: 'CommonBuffId' = 160071 - FAMILIES_ARGUMENTS_TYPE_MUSIC: 'CommonBuffId' = 160060 - FAMILIES_ARGUMENTS_TYPE_NATURE_WONDERS: 'CommonBuffId' = 160056 - FAMILIES_ARGUMENTS_TYPE_PARENTING: 'CommonBuffId' = 160064 - FAMILIES_ARGUMENTS_TYPE_POLITICS: 'CommonBuffId' = 159364 - FAMILIES_ARGUMENTS_TYPE_ROMANCE: 'CommonBuffId' = 160058 - FAMILIES_ARGUMENTS_TYPE_SCHOOL: 'CommonBuffId' = 160062 - FAMILIES_ARGUMENTS_TYPE_SHARING: 'CommonBuffId' = 160051 - FAMILIES_ARGUMENTS_TYPE_SOCIAL_ANXIETY: 'CommonBuffId' = 160055 - FAMILIES_ARGUMENTS_TYPE_WHOS_BETTER: 'CommonBuffId' = 160066 - FAMILIES_ARGUMENTS_WINNER: 'CommonBuffId' = 159388 - FAMILIES_JUST_SHOVED: 'CommonBuffId' = 159939 - FAMILY_BULLETIN_BOARD_HAS_NOTE_DRAWING: 'CommonBuffId' = 163112 - FAMILY_BULLETIN_BOARD_HAS_NOTE_NEGATIVE: 'CommonBuffId' = 163109 - FAMILY_BULLETIN_BOARD_HAS_NOTE_POSITIVE: 'CommonBuffId' = 163108 - FAMILY_BULLETIN_BOARD_LOOK_AT_DRAWING: 'CommonBuffId' = 162728 - FAMILY_BULLETIN_BOARD_READ_NOTE: 'CommonBuffId' = 162458 - FAMILY_BULLETIN_BOARD_READ_NOTE_ANGRY: 'CommonBuffId' = 162705 - FAMILY_DYNAMICS_ADOPTION: 'CommonBuffId' = 317586 - FAMILY_DYNAMICS_BIRTHDAY_GIFT_CALL: 'CommonBuffId' = 322807 - FAMILY_DYNAMICS_CALMING_DOWN: 'CommonBuffId' = 312729 - FAMILY_DYNAMICS_CHATTY_CALL_CONFIDENT: 'CommonBuffId' = 319532 - FAMILY_DYNAMICS_CHATTY_CALL_HAPPY: 'CommonBuffId' = 319531 - FAMILY_DYNAMICS_CHATTY_CALL_PLAYFUL: 'CommonBuffId' = 319534 - FAMILY_DYNAMICS_CONTAGIOUS_ANGER: 'CommonBuffId' = 312728 - FAMILY_DYNAMICS_CONTAGIOUS_EMBARRASSMENT: 'CommonBuffId' = 312733 - FAMILY_DYNAMICS_CONTAGIOUS_FEAR: 'CommonBuffId' = 312731 - FAMILY_DYNAMICS_CONTAGIOUS_SADNESS: 'CommonBuffId' = 312734 - FAMILY_DYNAMICS_CONTAGIOUS_STRESS: 'CommonBuffId' = 312732 - FAMILY_DYNAMICS_FAMILY_TROPE_ADVENTURE_COOLDOWN: 'CommonBuffId' = 306626 - FAMILY_DYNAMICS_HIDDEN_CLOSE: 'CommonBuffId' = 317770 - FAMILY_DYNAMICS_HIDDEN_COMPLIANT: 'CommonBuffId' = 318080 - FAMILY_DYNAMICS_HIDDEN_DIFFICULT: 'CommonBuffId' = 318083 - FAMILY_DYNAMICS_HIDDEN_DISTANT: 'CommonBuffId' = 318078 - FAMILY_DYNAMICS_HIDDEN_JOKESTERS: 'CommonBuffId' = 318085 - FAMILY_DYNAMICS_HIDDEN_LOVING: 'CommonBuffId' = 320330 - FAMILY_DYNAMICS_HIDDEN_PERMISSIVE: 'CommonBuffId' = 320331 - FAMILY_DYNAMICS_PRAISE_MESS_ACTOR: 'CommonBuffId' = 320811 - FAMILY_DYNAMICS_PRAISE_MESS_HIDDEN: 'CommonBuffId' = 320808 - FAMILY_DYNAMICS_PRAISE_MESS_TARGET: 'CommonBuffId' = 320812 - FAMILY_DYNAMICS_SOCIAL_CLOSE: 'CommonBuffId' = 318077 - FAMILY_DYNAMICS_SOCIAL_COMPLIANT_AUTHORITY: 'CommonBuffId' = 320335 - FAMILY_DYNAMICS_SOCIAL_COMPLIANT_SUBORDINATE: 'CommonBuffId' = 318082 - FAMILY_DYNAMICS_SOCIAL_DIFFICULT: 'CommonBuffId' = 318084 - FAMILY_DYNAMICS_SOCIAL_DISTANT: 'CommonBuffId' = 318079 - FAMILY_DYNAMICS_SOCIAL_JOKESTERS: 'CommonBuffId' = 320332 - FAMILY_DYNAMICS_SOCIAL_LOVING: 'CommonBuffId' = 320333 - FAMILY_DYNAMICS_SOCIAL_PERMISSIVE_AUTHORITY: 'CommonBuffId' = 320334 - FAMILY_DYNAMICS_SOCIAL_PERMISSIVE_SUBORDINATE: 'CommonBuffId' = 320625 - FAMILY_GOSSIP: 'CommonBuffId' = 164737 - FAMILY_PORTRAIT_APPRECIATE_FAMILY: 'CommonBuffId' = 181414 - FAMILY_REL_BIT_ACQUIRED_PROXIMITY_HIGH: 'CommonBuffId' = 162438 - FAMILY_REL_BIT_ACQUIRED_PROXIMITY_LOW: 'CommonBuffId' = 162440 - FAMILY_REL_BIT_ACQUIRED_PROXIMITY_NEUTRAL: 'CommonBuffId' = 162439 - FASHION_MARKETPLACE_DIDNT_READ_THE_ROOM: 'CommonBuffId' = 287585 - FASHION_MARKETPLACE_FASHION_EMPIRE_GROWING: 'CommonBuffId' = 287589 - FASHION_MARKETPLACE_FASHION_FIRESTARTER: 'CommonBuffId' = 287594 - FASHION_MARKETPLACE_STYLE_REJECTION: 'CommonBuffId' = 287593 - FASHION_MARKETPLACE_WEARING_OUTFIT: 'CommonBuffId' = 286292 - FEARFUL_PET_RUN_AWAY: 'CommonBuffId' = 178105 - FEAR_BEING_ALONE_EFFECTS_ALONE: 'CommonBuffId' = 366274 - FEAR_BEING_ALONE_EFFECTS_BURDENED_FEELINGS: 'CommonBuffId' = 364232 - FEAR_BEING_ALONE_EFFECTS_SEEKING_SOLACE: 'CommonBuffId' = 364577 - FEAR_BEING_ALONE_EFFECTS_SIM_PROXIMITY: 'CommonBuffId' = 366273 - FEAR_BEING_ALONE_EFFECTS_SOLITUDE: 'CommonBuffId' = 364578 - FEAR_BEING_ALONE_TRAIT_EFFECTS: 'CommonBuffId' = 364231 - FEAR_BEING_CHEATED_ON_CONFRONTATION_PROGRESS: 'CommonBuffId' = 278550 - FEAR_BEING_CHEATED_ON_EFFECTS_CATCH_CHEATING: 'CommonBuffId' = 278341 - FEAR_BEING_CHEATED_ON_EFFECTS_SUSPICIOUS_ANGRY: 'CommonBuffId' = 278330 - FEAR_BEING_CHEATED_ON_EFFECTS_SUSPICIOUS_SAD: 'CommonBuffId' = 278340 - FEAR_BEING_CHEATED_ON_EFFECTS_TALK_RELATIONSHIP_FEARS_FAIL_ACTOR: 'CommonBuffId' = 278538 - FEAR_BEING_CHEATED_ON_EFFECTS_TALK_RELATIONSHIP_FEARS_FAIL_TARGET: 'CommonBuffId' = 278537 - FEAR_BEING_CHEATED_ON_EFFECTS_TALK_RELATIONSHIP_FEARS_SUCCESS: 'CommonBuffId' = 278539 - FEAR_BEING_CHEATED_ON_TRAIT_EFFECTS: 'CommonBuffId' = 278338 - FEAR_BEING_JUDGED_FIGURE_OUT_DIFFERENCES_FAIL: 'CommonBuffId' = 288469 - FEAR_BEING_JUDGED_FIGURE_OUT_DIFFERENCES_SUCCESS: 'CommonBuffId' = 288466 - FEAR_BEING_JUDGED_JUDGING_EYES: 'CommonBuffId' = 288468 - FEAR_BEING_JUDGED_JUDGING_EYES_LEVEL2: 'CommonBuffId' = 288467 - FEAR_BEING_JUDGED_TRACKER: 'CommonBuffId' = 288479 - FEAR_BEING_JUDGED_TRAIT_EFFECTS: 'CommonBuffId' = 288474 - FEAR_CONFRONTATION_PROGRESS_GAINED: 'CommonBuffId' = 295484 - FEAR_CONFRONTED_RECENTLY: 'CommonBuffId' = 277638 - FEAR_CONFRONT_FEAR_SUCCESS_CONFIDENCE_GAIN: 'CommonBuffId' = 308140 - FEAR_COW_PLANT_EFFECTS_COW_PLANT_PROXIMITY: 'CommonBuffId' = 277209 - FEAR_COW_PLANT_TRAIT_EFFECTS: 'CommonBuffId' = 277208 - FEAR_CROWDED_PLACES_EFFECTS_LEVEL_1: 'CommonBuffId' = 287761 - FEAR_CROWDED_PLACES_EFFECTS_LEVEL_2: 'CommonBuffId' = 287760 - FEAR_DARK_EFFECTS_SCARED_OUTSIDE: 'CommonBuffId' = 278014 - FEAR_DARK_EFFECTS_STARTLED_WAKE_UP: 'CommonBuffId' = 278154 - FEAR_DARK_TRAIT_EFFECTS: 'CommonBuffId' = 278005 - FEAR_DEAD_END_JOB_EFFECTS_PASSION_RETURN_FLAG: 'CommonBuffId' = 289790 - FEAR_DEAD_END_JOB_EFFECTS_PASSION_RETURN_TRACKER: 'CommonBuffId' = 277848 - FEAR_DEAD_END_JOB_EFFECTS_REGAIN_PASSION_FAIL: 'CommonBuffId' = 277853 - FEAR_DEAD_END_JOB_EFFECTS_REGAIN_PASSION_FOCUSED: 'CommonBuffId' = 277854 - FEAR_DEAD_END_JOB_EFFECTS_REGAIN_PASSION_INSPIRED: 'CommonBuffId' = 277855 - FEAR_DEAD_END_JOB_EFFECTS_SAD_RETURN: 'CommonBuffId' = 277847 - FEAR_DEAD_END_JOB_TRIGGER_PROGRESS: 'CommonBuffId' = 277972 - FEAR_DEATH_DISCUSS_FEARS_SUCCESS: 'CommonBuffId' = 296120 - FEAR_DEATH_EFFECTS_NEAR_REAPER: 'CommonBuffId' = 283721 - FEAR_DEATH_TRAIT_EFFECTS: 'CommonBuffId' = 283708 - FEAR_DISAPPOINTING_PARENTS_CONFRONTATION_PROGRESS: 'CommonBuffId' = 283667 - FEAR_DISAPPOINTING_PARENTS_EFFECTS_NEAR_PARENTS: 'CommonBuffId' = 284098 - FEAR_DISAPPOINTING_PARENTS_EFFECTS_WAKE_UP_TENSE: 'CommonBuffId' = 284099 - FEAR_DISAPPOINTING_PARENTS_SET_EXPECTATIONS_FAILURE: 'CommonBuffId' = 284102 - FEAR_DISAPPOINTING_PARENTS_SET_EXPECTATIONS_SUCCESS: 'CommonBuffId' = 284103 - FEAR_DISAPPOINTING_PARENTS_TRAIT_EFFECTS: 'CommonBuffId' = 283709 - FEAR_EVICTION_CONFRONTATION_PROGRESS: 'CommonBuffId' = 355835 - FEAR_EVICTION_EFFECTS_PHONE_PANIC_IDLE: 'CommonBuffId' = 342758 - FEAR_FAILING_AFTER_SCHOOL_CONFRONTATION_TRACKER: 'CommonBuffId' = 288077 - FEAR_FAILING_AFTER_SCHOOL_EFFECTS_LOST_EVENT: 'CommonBuffId' = 288120 - FEAR_FAILING_AFTER_SCHOOL_EFFECTS_WAKE_UP: 'CommonBuffId' = 288125 - FEAR_FAILING_AFTER_SCHOOL_TRIGGER_PROGRESS: 'CommonBuffId' = 288079 - FEAR_FAILING_CLASS_EFFECTS_GRADE_DROP: 'CommonBuffId' = 288114 - FEAR_FAILING_CLASS_EFFECTS_SCHOOL_ARRIVAL: 'CommonBuffId' = 287938 - FEAR_FAILING_CLASS_EXTRA_CREDIT_AVAILABLE: 'CommonBuffId' = 288094 - FEAR_FAILING_CLASS_TRIGGER_PROGRESS: 'CommonBuffId' = 288078 - FEAR_FAILING_TESTS_EFFECTS_MUST_BE_PREPARED: 'CommonBuffId' = 287710 - FEAR_FAILING_TESTS_EFFECTS_PREPARED_FAIL: 'CommonBuffId' = 290929 - FEAR_FAILING_TESTS_EFFECTS_TEST_DAY: 'CommonBuffId' = 287713 - FEAR_FAILING_TEST_CONFRONTATION_PROGRESS: 'CommonBuffId' = 287860 - FEAR_FAILURE_EFFECTS_PERFORMANCE_REVIEW_FAIL: 'CommonBuffId' = 283826 - FEAR_FAILURE_EFFECTS_PERFORMANCE_REVIEW_SUCCESS: 'CommonBuffId' = 283825 - FEAR_FAILURE_EFFECTS_SAD_CRAFTING: 'CommonBuffId' = 283796 - FEAR_FAILURE_EFFECTS_SAD_WAKE_UP: 'CommonBuffId' = 283797 - FEAR_FAILURE_EFFECTS_SHOW_OFF_COOLDOWN: 'CommonBuffId' = 283895 - FEAR_FAILURE_EFFECTS_SHOW_OFF_FAIL: 'CommonBuffId' = 283844 - FEAR_FAILURE_EFFECTS_SHOW_OFF_WAITING: 'CommonBuffId' = 283896 - FEAR_FAILURE_TRIGGER_PROGRESS: 'CommonBuffId' = 283789 - FEAR_FIRE_TRAIT_EFFECTS: 'CommonBuffId' = 277317 - FEAR_GAINED_ANXIETY: 'CommonBuffId' = 284204 - FEAR_GAINED_SCARED: 'CommonBuffId' = 284203 - FEAR_GHOSTS_EFFECTS_GHOST_PROXIMITY: 'CommonBuffId' = 277559 - FEAR_GHOSTS_EFFECTS_SCARED: 'CommonBuffId' = 277620 - FEAR_GHOSTS_TRAIT_EFFECTS_NEAR_GHOST_TRACKER: 'CommonBuffId' = 277558 - FEAR_HOMEWORK_CONFRONTATION_PROGRESS: 'CommonBuffId' = 286298 - FEAR_HOMEWORK_EFFECTS_NOTHING_ABSORBED: 'CommonBuffId' = 286711 - FEAR_HOMEWORK_EFFECTS_SHOULD_FINISH_HOMEWORK: 'CommonBuffId' = 286653 - FEAR_HORSES_GET_ADVICE_SUCCESS: 'CommonBuffId' = 323772 - FEAR_HORSES_TRAIT_EFFECTS: 'CommonBuffId' = 323759 - FEAR_HORSES_TRAIT_FEAR_REACT_TO_HORSES: 'CommonBuffId' = 339408 - FEAR_IMMUNITY_RESOLVED_RECENTLY: 'CommonBuffId' = 277115 - FEAR_INFERIOR_EFFECTS_BRILLIANCE_PROXIMITY: 'CommonBuffId' = 307978 - FEAR_INFERIOR_EFFECTS_SAD_WAKE_UP: 'CommonBuffId' = 307979 - FEAR_INTIMACY_EFFECTS_EMBRACING_VULNERABILITY: 'CommonBuffId' = 362863 - FEAR_INTIMACY_EFFECTS_EMOTIONAL_WALLS: 'CommonBuffId' = 362861 - FEAR_INTIMACY_EFFECTS_GROUNDED_BELIEFS: 'CommonBuffId' = 374375 - FEAR_INTIMACY_EFFECTS_TOUCH_SENSITIVITY: 'CommonBuffId' = 362862 - FEAR_INTIMACY_TRAIT_EFFECTS: 'CommonBuffId' = 362853 - FEAR_OF_EVICTION_DOOR_PANIC: 'CommonBuffId' = 351565 - FEAR_OF_EVICTION_EFFECTS: 'CommonBuffId' = 352133 - FEAR_SWIMMING_EFFECTS_SCARED_IN_WATER: 'CommonBuffId' = 277695 - FEAR_SWIMMING_TRAIT_EFFECTS: 'CommonBuffId' = 277688 - FEAR_TESTS_EFFECTS_PREPARED_SUCCESS: 'CommonBuffId' = 294552 - FESTIVAL_APPROPRIATENESS_NO_SINGING: 'CommonBuffId' = 154237 - FESTIVAL_AUTONOMY_BUY_T_SHIRT: 'CommonBuffId' = 143635 - FESTIVAL_AUTONOMY_WATCH: 'CommonBuffId' = 136206 - FESTIVAL_BLOSSOM_5_STAGES_OF_PETALS_1_HIDDEN: 'CommonBuffId' = 153016 - FESTIVAL_BLOSSOM_5_STAGES_OF_PETALS_2_HAPPY: 'CommonBuffId' = 153022 - FESTIVAL_BLOSSOM_5_STAGES_OF_PETALS_3_DENIAL: 'CommonBuffId' = 153019 - FESTIVAL_BLOSSOM_5_STAGES_OF_PETALS_4_ANGER: 'CommonBuffId' = 153020 - FESTIVAL_BLOSSOM_5_STAGES_OF_PETALS_5_BARGAIN: 'CommonBuffId' = 153021 - FESTIVAL_BLOSSOM_5_STAGES_OF_PETALS_6_DEPRESSION: 'CommonBuffId' = 153018 - FESTIVAL_BLOSSOM_5_STAGES_OF_PETALS_7_ACCEPTANCE: 'CommonBuffId' = 153017 - FESTIVAL_BLOSSOM_ALLOW_THROW_PETALS: 'CommonBuffId' = 143102 - FESTIVAL_BLOSSOM_AUTONOMY_ARTIST: 'CommonBuffId' = 136203 - FESTIVAL_BLOSSOM_AUTONOMY_DRINK_SAKURA_TEA: 'CommonBuffId' = 150875 - FESTIVAL_BLOSSOM_AUTONOMY_ROMANCE_INTERACTIONS: 'CommonBuffId' = 146792 - FESTIVAL_BLOSSOM_AUTONOMY_THROW_PETALS: 'CommonBuffId' = 135703 - FESTIVAL_BLOSSOM_AUTONOMY_VIEWERS: 'CommonBuffId' = 143729 - FESTIVAL_BLOSSOM_HAS_BEEN_SLEAZED: 'CommonBuffId' = 155131 - FESTIVAL_BLOSSOM_INSPIRATION: 'CommonBuffId' = 135699 - FESTIVAL_BLOSSOM_PLAYER_BUFF: 'CommonBuffId' = 143101 - FESTIVAL_BLOSSOM_PLAYER_TEST_ADD: 'CommonBuffId' = 144001 - FESTIVAL_BLOSSOM_PLAYER_TIMER: 'CommonBuffId' = 144002 - FESTIVAL_BLOSSOM_SAKURA_TEA_CHILD_BUFF: 'CommonBuffId' = 153901 - FESTIVAL_BLOSSOM_SAKURA_TEA_GURU_ONLY: 'CommonBuffId' = 150918 - FESTIVAL_BLOSSOM_SLEAZE_ANGRY: 'CommonBuffId' = 136256 - FESTIVAL_BLOSSOM_SLEAZE_FLIRTY: 'CommonBuffId' = 136216 - FESTIVAL_BLOSSOM_TEA_GLOW_SAKURA: 'CommonBuffId' = 147112 - FESTIVAL_BLOSSOM_TEA_GLOW_SAKURA_CHILD: 'CommonBuffId' = 147113 - FESTIVAL_BLOSSOM_THROW_PETALS_COOLDOWN: 'CommonBuffId' = 135704 - FESTIVAL_CONTESTS_HACKATHON_WINNER_BRONZE: 'CommonBuffId' = 144195 - FESTIVAL_CONTESTS_HACKATHON_WINNER_GOLD: 'CommonBuffId' = 144189 - FESTIVAL_CONTESTS_HACKATHON_WINNER_SILVER: 'CommonBuffId' = 144194 - FESTIVAL_CONTESTS_UGT_WINNER: 'CommonBuffId' = 144192 - FESTIVAL_DARK_TEA_DRINK: 'CommonBuffId' = 135532 - FESTIVAL_FLEA_MARKET_AUTONOMY_HAGGLER: 'CommonBuffId' = 142223 - FESTIVAL_FLEA_MARKET_HAGGLE_SUCCEED: 'CommonBuffId' = 142219 - FESTIVAL_FLEA_MARKET_PLAYER_BUFF: 'CommonBuffId' = 140386 - FESTIVAL_FLEA_MARKET_PLAYER_TEST_ADD: 'CommonBuffId' = 143999 - FESTIVAL_FLEA_MARKET_PLAYER_TIMER: 'CommonBuffId' = 144000 - FESTIVAL_FLEA_MARKET_TRADE_CD: 'CommonBuffId' = 144401 - FESTIVAL_FLEA_MARKET_TRADE_FAIL_CD: 'CommonBuffId' = 152786 - FESTIVAL_FLEA_MARKET_VENDOR: 'CommonBuffId' = 139949 - FESTIVAL_FOOD_AUTONOMY_BUBBLE_BLOWER: 'CommonBuffId' = 140094 - FESTIVAL_FOOD_AUTONOMY_CURRY_CONTEST_PARTICIPANT: 'CommonBuffId' = 146550 - FESTIVAL_FOOD_AUTONOMY_OVEREAT: 'CommonBuffId' = 136418 - FESTIVAL_FOOD_AUTONOMY_SAMPLE: 'CommonBuffId' = 141204 - FESTIVAL_FOOD_AUTONOMY_VOMIT: 'CommonBuffId' = 136590 - FESTIVAL_FOOD_CURRY_CONTEST_BURNT_TONGUE: 'CommonBuffId' = 146420 - FESTIVAL_FOOD_CURRY_CONTEST_COOLDOWN: 'CommonBuffId' = 146145 - FESTIVAL_FOOD_CURRY_CONTEST_FAILED: 'CommonBuffId' = 153580 - FESTIVAL_FOOD_CURRY_CONTEST_T_SHIRT: 'CommonBuffId' = 152354 - FESTIVAL_FOOD_CURRY_CONTEST_WON_CONTEST: 'CommonBuffId' = 153563 - FESTIVAL_FOOD_EAT_FASTER: 'CommonBuffId' = 142708 - FESTIVAL_FOOD_PLAYER_BUFF: 'CommonBuffId' = 139945 - FESTIVAL_FOOD_PLAYER_TEST_ADD: 'CommonBuffId' = 143997 - FESTIVAL_FOOD_PLAYER_TIMER: 'CommonBuffId' = 143998 - FESTIVAL_FOOD_SAMPLE_COOLDOWN: 'CommonBuffId' = 137152 - FESTIVAL_GENERAL_DRINK: 'CommonBuffId' = 134832 - FESTIVAL_GENERAL_EAT: 'CommonBuffId' = 134831 - FESTIVAL_LAMP_AUTONOMY_DARK_CONTESTANT: 'CommonBuffId' = 146920 - FESTIVAL_LAMP_AUTONOMY_LIGHT_CONTESTANT: 'CommonBuffId' = 146921 - FESTIVAL_LAMP_AUTONOMY_LIGHT_FIREWORKS: 'CommonBuffId' = 140096 - FESTIVAL_LAMP_CREATE_FIREWORKS_CD: 'CommonBuffId' = 152792 - FESTIVAL_LAMP_CREATE_VOODOO_CD: 'CommonBuffId' = 153427 - FESTIVAL_LAMP_DARK_TEA: 'CommonBuffId' = 134573 - FESTIVAL_LAMP_DAZED_BUFF: 'CommonBuffId' = 135540 - FESTIVAL_LAMP_LIGHT_TEA: 'CommonBuffId' = 134572 - FESTIVAL_LAMP_PLAYER_BUFF: 'CommonBuffId' = 140384 - FESTIVAL_LAMP_PLAYER_TEST_ADD: 'CommonBuffId' = 143996 - FESTIVAL_LAMP_PLAYER_TIMER: 'CommonBuffId' = 143995 - FESTIVAL_LAMP_TEA_GLOW_DARK: 'CommonBuffId' = 147116 - FESTIVAL_LAMP_TEA_GLOW_DARK_CHILD: 'CommonBuffId' = 147119 - FESTIVAL_LAMP_TEA_GLOW_LIGHT: 'CommonBuffId' = 147118 - FESTIVAL_LAMP_TEA_GLOW_LIGHT_CHILD: 'CommonBuffId' = 147117 - FESTIVAL_LIGHT_TEA_DRINK: 'CommonBuffId' = 135533 - FESTIVAL_LOGIC_AUTONOMY_HACK_THE_PLANET: 'CommonBuffId' = 141127 - FESTIVAL_LOGIC_AUTONOMY_ROCKET_SHIP_BUILDER: 'CommonBuffId' = 137242 - FESTIVAL_LOGIC_AUTONOMY_ROCKET_SHIP_USER: 'CommonBuffId' = 140945 - FESTIVAL_LOGIC_AUTONOMY_ROCKET_SHIP_WOOHOO: 'CommonBuffId' = 137328 - FESTIVAL_LOGIC_AUTONOMY_UGT: 'CommonBuffId' = 141199 - FESTIVAL_LOGIC_COSPLAY_SELFIE_FAIL: 'CommonBuffId' = 144353 - FESTIVAL_LOGIC_COSPLAY_SELFIE_SUCCESS: 'CommonBuffId' = 144352 - FESTIVAL_LOGIC_COSPLAY_SELFIE_TARGET_CD: 'CommonBuffId' = 144367 - FESTIVAL_LOGIC_EVENT_HACK_THE_PLANET: 'CommonBuffId' = 141168 - FESTIVAL_LOGIC_EVENT_UGT: 'CommonBuffId' = 141169 - FESTIVAL_LOGIC_HACK_THE_PLANET_CD: 'CommonBuffId' = 141092 - FESTIVAL_LOGIC_PLAYER_BUFF: 'CommonBuffId' = 140385 - FESTIVAL_LOGIC_PLAYER_TEST_ADD: 'CommonBuffId' = 143787 - FESTIVAL_LOGIC_PLAYER_TIMER: 'CommonBuffId' = 143796 - FESTIVAL_LOGIC_ROCKET_SHIP_USE_CD: 'CommonBuffId' = 153373 - FESTIVAL_LOGIC_ROCKET_SHIP_WOOHOO_CD: 'CommonBuffId' = 140980 - FESTIVAL_PLAYER_IGNORE_VENUES: 'CommonBuffId' = 154328 - FESTIVAL_TRAVEL_NP_CS_BEHAVIOR: 'CommonBuffId' = 149279 - FESTIVAL_TRAVEL_NP_CS_TEST_ADD: 'CommonBuffId' = 149280 - FESTIVAL_TRAVEL_NP_CS_TIMER: 'CommonBuffId' = 149278 - FIGHT_WITNESSED_BORED: 'CommonBuffId' = 99270 - FIGHT_WITNESSED_ENERGIZED: 'CommonBuffId' = 99267 - FIGHT_WITNESSED_HAPPY: 'CommonBuffId' = 99263 - FIGHT_WITNESSED_INSPIRING: 'CommonBuffId' = 99268 - FIGHT_WITNESSED_SAD: 'CommonBuffId' = 99266 - FIGHT_WITNESSED_STRESSED: 'CommonBuffId' = 99265 - FIGHT_WITNESSED_UNCOMFORTABLE: 'CommonBuffId' = 99269 - FILTHY_FABULOUS_TOILET_BUFFS_DIDNT_WASH_HANDS: 'CommonBuffId' = 257336 - FILTHY_FABULOUS_TOILET_BUFFS_USED_TOILET: 'CommonBuffId' = 257335 - FILTHY_FABULOUS_TOILET_BUFFS_WASHED_HANDS: 'CommonBuffId' = 257337 - FINISHED_BOOK: 'CommonBuffId' = 36577 - FIREWORKS_LIGHTING_HIDDEN: 'CommonBuffId' = 135817 - FIREWORKS_SINGED: 'CommonBuffId' = 134991 - FIREWORKS_WATCHING_HIDDEN: 'CommonBuffId' = 135816 - FIRE_CALLED_FIRE_FIGHTERS: 'CommonBuffId' = 237762 - FIRE_EXCITED_ADRENALINE_SEEKER: 'CommonBuffId' = 254553 - FIRE_EXTINGUISHED: 'CommonBuffId' = 98326 - FIRE_EXTINGUISHED_SIM: 'CommonBuffId' = 98328 - FIRE_EXTINGUISHER: 'CommonBuffId' = 97139 - FIRE_FINISHED_STRESSED: 'CommonBuffId' = 77651 - FIRE_FLIRTY_FIRE_FIGHTERS: 'CommonBuffId' = 237794 - FIRE_GRIM_REAPER_REACTED: 'CommonBuffId' = 100087 - FIRE_ON_FIRE: 'CommonBuffId' = 98786 - FIRE_ON_FIRE_PET_CAT: 'CommonBuffId' = 172014 - FIRE_ON_FIRE_PET_DOG: 'CommonBuffId' = 172015 - FIRE_RECENTLY_EXTINGUISHED: 'CommonBuffId' = 101043 - FIRE_RECENT_FIRE: 'CommonBuffId' = 100849 - FIRE_SIM_SINGED: 'CommonBuffId' = 98815 - FIRE_SIM_SINGED_PET_CAT: 'CommonBuffId' = 172020 - FIRE_SIM_SINGED_PET_DOG: 'CommonBuffId' = 172021 - FIRE_STRESSED: 'CommonBuffId' = 77649 - FIRE_STRESSED_PET_CAT: 'CommonBuffId' = 171899 - FIRE_STRESSED_PET_DOG: 'CommonBuffId' = 171900 - FIRE_TODDLER: 'CommonBuffId' = 157024 - FIRE_WEARING_FIRE_FIGHTER_OUTFIT: 'CommonBuffId' = 237760 - FIRST_KISS: 'CommonBuffId' = 29350 - FITNESS_SKILL_HIGH_STAMINA: 'CommonBuffId' = 212215 - FITNESS_SKILL_MEDIUM_STAMINA: 'CommonBuffId' = 212214 - FITNESS_SKILL_SWIM_STYLE_CHILD_MEDIUM: 'CommonBuffId' = 211073 - FITNESS_SKILL_SWIM_STYLE_TYAE_HIGH: 'CommonBuffId' = 211076 - FITNESS_SKILL_SWIM_STYLE_TYAE_MEDIUM: 'CommonBuffId' = 211075 - FLAVOR_INSPIRATION: 'CommonBuffId' = 130728 - FLIRTATIOUS_SCENT: 'CommonBuffId' = 118494 - FLIRTY_BY_POTION: 'CommonBuffId' = 26303 - FLIRTY_DEDICATED_SONG: 'CommonBuffId' = 30892 - FLOAT_AVAILABLE_HIDDEN: 'CommonBuffId' = 119067 - FOCUSED_BY_POTION: 'CommonBuffId' = 26329 - FOCUSED_ENLIGHTENMENT: 'CommonBuffId' = 118513 - FOCUSED_FEELING_FLEXY: 'CommonBuffId' = 118660 - FOCUSING_SCENT: 'CommonBuffId' = 118504 - FOOD_AMBROSIA_HAPPY_HIGH: 'CommonBuffId' = 102098 - FOOD_AMBROSIA_HAPPY_PET_CAT: 'CommonBuffId' = 175236 - FOOD_AMBROSIA_HAPPY_PET_DOG: 'CommonBuffId' = 175237 - FOOD_CHOPSTICKS_FAIL: 'CommonBuffId' = 148694 - FOOD_CHOPSTICKS_SUCCEED: 'CommonBuffId' = 148693 - FOOD_COOKING_0: 'CommonBuffId' = 10591 - FOOD_COOKING_0_FOODIE: 'CommonBuffId' = 27388 - FOOD_COOKING_1: 'CommonBuffId' = 10592 - FOOD_COOKING_1_FOODIE: 'CommonBuffId' = 27387 - FOOD_COOKING_2: 'CommonBuffId' = 10593 - FOOD_COOKING_2_FOODIE: 'CommonBuffId' = 27386 - FOOD_COOKING_2_GRILL_MASTER: 'CommonBuffId' = 105023 - FOOD_COOKING_3: 'CommonBuffId' = 10597 - FOOD_COOKING_3_GRILL_MASTER: 'CommonBuffId' = 105024 - FOOD_COOKING_4: 'CommonBuffId' = 10601 - FOOD_COOKING_4_FOODIE: 'CommonBuffId' = 27383 - FOOD_COOKING_4_GRILL_MASTER: 'CommonBuffId' = 105025 - FOOD_COOKING_5: 'CommonBuffId' = 10602 - FOOD_COOKING_5_BATUU: 'CommonBuffId' = 237774 - FOOD_COOKING_5_FOODIE: 'CommonBuffId' = 27384 - FOOD_COOKING_5_GRILL_MASTER: 'CommonBuffId' = 105026 - FOOD_COOKING_INGREDIENTS_BAD: 'CommonBuffId' = 76399 - FOOD_COOKING_INGREDIENTS_BAD_FOODIE: 'CommonBuffId' = 76415 - FOOD_COOKING_INGREDIENTS_GOOD: 'CommonBuffId' = 76392 - FOOD_COOKING_INGREDIENTS_GOOD_FOODIE: 'CommonBuffId' = 76416 - FOOD_COOKING_INGREDIENTS_GOOD_GRILL_MASTER: 'CommonBuffId' = 105027 - FOOD_COOKING_TODDLER_ANGRY: 'CommonBuffId' = 144669 - FOOD_COOKING_TODDLER_BAD: 'CommonBuffId' = 144667 - FOOD_COOKING_TODDLER_ENERGIZED: 'CommonBuffId' = 144668 - FOOD_COOKING_TODDLER_GOOD: 'CommonBuffId' = 144666 - FOOD_ECO_BUG_FOOD_SQUEAMISH: 'CommonBuffId' = 235697 - FOOD_EMOTION_ANGRY_HIGH: 'CommonBuffId' = 40894 - FOOD_EMOTION_ANGRY_LOW: 'CommonBuffId' = 40893 - FOOD_EMOTION_ENERGIZED_HIGH: 'CommonBuffId' = 40890 - FOOD_EMOTION_ENERGIZED_LOW: 'CommonBuffId' = 40886 - FOOD_EMOTION_FLIRTY_HIGH: 'CommonBuffId' = 40883 - FOOD_EMOTION_FLIRTY_LOW: 'CommonBuffId' = 40882 - FOOD_EMOTION_HAPPY: 'CommonBuffId' = 118436 - FOOD_EMOTION_PLAYFUL_HIGH: 'CommonBuffId' = 40885 - FOOD_EMOTION_PLAYFUL_LOW: 'CommonBuffId' = 40884 - FOOD_EXPERIMENTAL_0: 'CommonBuffId' = 130527 - FOOD_EXPERIMENTAL_2: 'CommonBuffId' = 130526 - FOOD_EXPERIMENTAL_3: 'CommonBuffId' = 130717 - FOOD_EXPERIMENTAL_4: 'CommonBuffId' = 130718 - FOOD_EXPERIMENTAL_5: 'CommonBuffId' = 130525 - FOOD_EXPERIMENTAL_FOODIE_0: 'CommonBuffId' = 131493 - FOOD_EXPERIMENTAL_FOODIE_2: 'CommonBuffId' = 131495 - FOOD_EXPERIMENTAL_FOODIE_3: 'CommonBuffId' = 131496 - FOOD_EXPERIMENTAL_FOODIE_4: 'CommonBuffId' = 131497 - FOOD_EXPERIMENTAL_FOODIE_5: 'CommonBuffId' = 131498 - FOOD_FAME_QUIRKS_REFINED_PALATE_HAPPY: 'CommonBuffId' = 193505 - FOOD_FAME_QUIRKS_REFINED_PALATE_HEAVY_UNCOMFORTABLE: 'CommonBuffId' = 193507 - FOOD_FAME_QUIRKS_REFINED_PALATE_UNCOMFORTABLE: 'CommonBuffId' = 193506 - FOOD_FOOD_FAILS_NINJA_FINGERS: 'CommonBuffId' = 149399 - FOOD_FOOD_FAILS_SPICY_SATISFACTION: 'CommonBuffId' = 149400 - FOOD_FRANKS_AND_BEANS_HIDDEN: 'CommonBuffId' = 102555 - FOOD_FRESH_CATCH: 'CommonBuffId' = 212555 - FOOD_HAS_EATEN_RECENTLY: 'CommonBuffId' = 132413 - FOOD_HAS_EATEN_RECENTLY_GROSS_MANNERS: 'CommonBuffId' = 164370 - FOOD_HAS_EATEN_RECENTLY_INCLUDING_CANCEL: 'CommonBuffId' = 137573 - FOOD_HAS_EATEN_TODAY_HIDDEN: 'CommonBuffId' = 155562 - FOOD_HAS_EATEN_WITHIN_HOUR: 'CommonBuffId' = 212237 - FOOD_HIDDEN_EATING_EXPERIMENTAL_FOOD: 'CommonBuffId' = 131557 - FOOD_LIFESTYLES_HEALTH_NUT_1: 'CommonBuffId' = 248272 - FOOD_LIFESTYLES_HEALTH_NUT_2: 'CommonBuffId' = 248271 - FOOD_LIFESTYLES_HEALTH_NUT_3: 'CommonBuffId' = 248270 - FOOD_LIFESTYLES_HEALTH_NUT_4: 'CommonBuffId' = 248304 - FOOD_LIFESTYLES_HEALTH_NUT_5: 'CommonBuffId' = 248303 - FOOD_LIFESTYLES_HEALTH_NUT_HEALTHY_MEAL: 'CommonBuffId' = 248356 - FOOD_LIFESTYLES_HEALTH_NUT_SAD: 'CommonBuffId' = 248344 - FOOD_LIFESTYLES_HEALTH_NUT_SUGAR_FOOD: 'CommonBuffId' = 248357 - FOOD_LIFESTYLES_JUNK_FOOD_1: 'CommonBuffId' = 248265 - FOOD_LIFESTYLES_JUNK_FOOD_2: 'CommonBuffId' = 248266 - FOOD_LIFESTYLES_JUNK_FOOD_3: 'CommonBuffId' = 248267 - FOOD_LIFESTYLES_JUNK_FOOD_4: 'CommonBuffId' = 248268 - FOOD_LIFESTYLES_JUNK_FOOD_5: 'CommonBuffId' = 248269 - FOOD_LIFESTYLES_JUNK_FOOD_BORED: 'CommonBuffId' = 248343 - FOOD_LIFESTYLES_JUNK_FOOD_HEALTHY_MEAL: 'CommonBuffId' = 248355 - FOOD_LIFESTYLES_JUNK_FOOD_SUGAR_FOOD: 'CommonBuffId' = 248354 - FOOD_LIFESTYLES_JUNK_FOOD_SUGAR_RUSH: 'CommonBuffId' = 250604 - FOOD_LIFESTYLES_JUNK_FOOD_SUGAR_RUSH_CRASH: 'CommonBuffId' = 250605 - FOOD_LUNA_FISH: 'CommonBuffId' = 289743 - FOOD_POISONING_ACTIVE: 'CommonBuffId' = 131881 - FOOD_POISONING_INFECTED: 'CommonBuffId' = 131877 - FOOD_POISONING_RECENTLY_PUKED: 'CommonBuffId' = 135000 - FOOD_POISONING_RECOVERY: 'CommonBuffId' = 131908 - FOOD_POISONING_REPORTED: 'CommonBuffId' = 131916 - FOOD_SHARING_EAT_TOGETHER_REJECTION_ALLOW_SAD_EAT: 'CommonBuffId' = 370635 - FOOD_SPICY_FAIL: 'CommonBuffId' = 148691 - FOOD_SPICY_SUCCEED: 'CommonBuffId' = 148692 - FOOD_SUPPRESS_EAT_IDLE_MIXER: 'CommonBuffId' = 152795 - FOOD_SUPPRESS_STANDARD_EAT_MIXER: 'CommonBuffId' = 142689 - FOOD_SURVIVED_PUFFER_FISH: 'CommonBuffId' = 153808 - FOOD_TODDLER_MESSY_QUIT: 'CommonBuffId' = 143923 - FOOD_UNBALANCED_MEALS: 'CommonBuffId' = 217241 - FOOD_VAMPIRE_GARLIC_NOODLES: 'CommonBuffId' = 156006 - FOOD_VILLAGER_HELP_MUSHROOM_MASH: 'CommonBuffId' = 267517 - FOOD_WALLEYE_SURPRISE_INSPIRED: 'CommonBuffId' = 102553 - FORGOTTEN_BIRTHDAY: 'CommonBuffId' = 12442 - FOUNTAIN_A_COIN_FOR_GOOD_LUCK: 'CommonBuffId' = 131818 - FOUNTAIN_ENTRANCED_BY_SUDS: 'CommonBuffId' = 132019 - FOUNTAIN_HIDDEN_ADDED_SOAP: 'CommonBuffId' = 132572 - FOUNTAIN_OF_LOCAL_KNOWLEDGE_PRESSURE_COOKER_TRACKER: 'CommonBuffId' = 351249 - FOUNTAIN_OF_LOCAL_KNOWLEDGE_REGIONAL_FOOD_TRACKER: 'CommonBuffId' = 359589 - FOUNTAIN_OF_LOCAL_KNOWLEDGE_TRAIT_HIDDEN: 'CommonBuffId' = 348277 - FOX_ANIMAL_CLOTHING_GRANDMA_1: 'CommonBuffId' = 268769 - FOX_ANIMAL_CLOTHING_GRANDMA_2: 'CommonBuffId' = 270056 - FOX_ANIMAL_CLOTHING_GRANDMA_3: 'CommonBuffId' = 270057 - FOX_ANIMAL_CLOTHING_GRANDMA_4: 'CommonBuffId' = 270058 - FOX_ANIMAL_CLOTHING_GRANDMA_5: 'CommonBuffId' = 270055 - FOX_ANIMAL_CLOTHING_GRANDMA_6: 'CommonBuffId' = 270054 - FOX_ANIMAL_CLOTHING_ROBBER_1: 'CommonBuffId' = 268770 - FOX_ANIMAL_CLOTHING_ROBBER_2: 'CommonBuffId' = 270062 - FOX_ANIMAL_CLOTHING_ROBBER_3: 'CommonBuffId' = 270063 - FOX_ANIMAL_CLOTHING_ROBBER_4: 'CommonBuffId' = 270064 - FOX_ANIMAL_CLOTHING_ROBBER_5: 'CommonBuffId' = 270065 - FOX_ANIMAL_CLOTHING_ROBBER_6: 'CommonBuffId' = 270061 - FOX_ANIMAL_CLOTHING_ROBBER_7: 'CommonBuffId' = 270060 - FOX_ANIMAL_CLOTHING_ROBIN_HOOD_1: 'CommonBuffId' = 268771 - FOX_ANIMAL_CLOTHING_ROBIN_HOOD_2: 'CommonBuffId' = 270070 - FOX_ANIMAL_CLOTHING_ROBIN_HOOD_3: 'CommonBuffId' = 270071 - FOX_ANIMAL_CLOTHING_ROBIN_HOOD_4: 'CommonBuffId' = 270072 - FOX_ANIMAL_CLOTHING_ROBIN_HOOD_5: 'CommonBuffId' = 270069 - FOX_ANIMAL_CLOTHING_ROBIN_HOOD_6: 'CommonBuffId' = 270068 - FOX_CHEATS: 'CommonBuffId' = 270789 - FOX_DANGEROUS_WILDS: 'CommonBuffId' = 268621 - FOX_DISCORDANT_ARIA: 'CommonBuffId' = 269564 - FOX_HIDDEN_CANCEL_STALK: 'CommonBuffId' = 265099 - FOX_HIDDEN_CANT_PLEAD: 'CommonBuffId' = 270272 - FOX_HIDDEN_EVIL_CHICKEN_SCARE: 'CommonBuffId' = 268567 - FOX_HIDDEN_LEAVE: 'CommonBuffId' = 271068 - FOX_HIDDEN_RELATIONSHIP_WITH_POUNCE_TARGET: 'CommonBuffId' = 268933 - FOX_HIDDEN_ROOSTER_SCARES_FOX: 'CommonBuffId' = 269365 - FOX_HIDDEN_STALK: 'CommonBuffId' = 263653 - FOX_HIDDEN_STOLE_EGG: 'CommonBuffId' = 269635 - FOX_HIDDEN_WAKE_UP: 'CommonBuffId' = 270484 - FOX_IS_SLEEPING: 'CommonBuffId' = 260308 - FOX_SITUATION_LEAVE: 'CommonBuffId' = 270639 - FOX_SITUATION_ON_LOT: 'CommonBuffId' = 268741 - FOX_SITUATION_OPEN_STREET: 'CommonBuffId' = 267984 - FOX_SITUATION_STEAL: 'CommonBuffId' = 261652 - FOX_SITUATION_STEAL_EGG_FOCUS: 'CommonBuffId' = 266380 - FOX_SITUATION_STEAL_STALK_FOCUS: 'CommonBuffId' = 266381 - FOX_WATCH_TARGET: 'CommonBuffId' = 260022 - FREE_DIVING_WETSUIT: 'CommonBuffId' = 206587 - FREE_FROM_TOXINS: 'CommonBuffId' = 118511 - FREE_LANCER_CAREER_FASHION_PHOTOGRAPHER_COMPLETED_STYLE_INFLUENCER_MEETING: 'CommonBuffId' = 220467 - FREE_LANCER_CAREER_FASHION_PHOTOGRAPHER_COVER_PHOTO: 'CommonBuffId' = 218676 - FREE_LANCER_CAREER_FASHION_PHOTOGRAPHER_FASHION_SIMSTAGRAM: 'CommonBuffId' = 218681 - FREE_LANCER_CAREER_FASHION_PHOTOGRAPHER_FASHION_STUDIO_NEAR_BACKDROP: 'CommonBuffId' = 221113 - FREE_LANCER_CAREER_FASHION_PHOTOGRAPHER_FASHION_STUDIO_NEAR_LIGHT: 'CommonBuffId' = 221140 - FREE_LANCER_CAREER_FASHION_PHOTOGRAPHER_FREELANCE_PHOTOS: 'CommonBuffId' = 218679 - FREE_LANCER_CAREER_FASHION_PHOTOGRAPHER_INFLUENCED_FASHION_PHOTOS: 'CommonBuffId' = 218680 - FREE_LANCER_CAREER_FASHION_PHOTOGRAPHER_INFLUENCED_PHOTOS: 'CommonBuffId' = 218687 - FREE_LANCER_CAREER_FASHION_PHOTOGRAPHER_INFLUENCER_STYLE: 'CommonBuffId' = 218685 - FREE_LANCER_CAREER_FASHION_PHOTOGRAPHER_PHOTO_EDITOR: 'CommonBuffId' = 218683 - FREE_LANCER_CAREER_FASHION_PHOTOGRAPHER_SAD_FASHION_SIMSTAGRAM: 'CommonBuffId' = 218682 - FREE_LANCER_CAREER_FASHION_PHOTOGRAPHER_STEADY_EYE: 'CommonBuffId' = 220228 - FRESH_CLEAN_SCENT: 'CommonBuffId' = 118497 - FRIDGE_BAD_FRIDGE: 'CommonBuffId' = 10245 - FRIDGE_GOOD_FRIDGE: 'CommonBuffId' = 10244 - FRIENDSHIP_BRACELET_APPLIED_1: 'CommonBuffId' = 320048 - FRIENDSHIP_BRACELET_APPLIED_2: 'CommonBuffId' = 320049 - FRIENDSHIP_BRACELET_APPLIED_3: 'CommonBuffId' = 320050 - FRIENDSHIP_BRACELET_APPLIED_4: 'CommonBuffId' = 320047 - FRIENDSHIP_BRACELET_APPLIED_5: 'CommonBuffId' = 319947 - FRIENDSHIP_BRACELET_AWKWARD: 'CommonBuffId' = 320181 - FRIENDSHIP_BRACELET_BRACELETLESS: 'CommonBuffId' = 320182 - FRIENDSHIP_BRACELET_NEEDS_CLEANUP: 'CommonBuffId' = 329149 - FTUE_AUTONOMY_MOD_DAY1_NO_SLEEP: 'CommonBuffId' = 201480 - FTUE_AUTONOMY_MOD_DAY1_SLEEP_MOTIVES: 'CommonBuffId' = 201256 - FTUE_AUTONOMY_MOD_DAY1_START_SUPPRESS_AUTONOMY_PLAYER_SIM: 'CommonBuffId' = 201242 - FTUE_AUTONOMY_MOD_DAY1_START_SUPPRESS_AUTONOMY_ROOMMATE_SIM: 'CommonBuffId' = 201459 - FTUE_AUTONOMY_MOD_DAY2_FREEZE_BLADDER_DECAY: 'CommonBuffId' = 204699 - FTUE_GIVE_GIFT: 'CommonBuffId' = 198669 - FTUE_ROLE_PLAYER_SIM: 'CommonBuffId' = 201457 - FTUE_ROLE_ROOMMATE_COOK: 'CommonBuffId' = 198046 - FTUE_ROOMMATE_GAVE_GIFT: 'CommonBuffId' = 201554 - FTUE_ROOMMATE_GIFT: 'CommonBuffId' = 199659 - FTUE_ROOMMATE_SLEEP: 'CommonBuffId' = 201000 - FTUE_ROOMMATE_WAVE: 'CommonBuffId' = 199414 - FTUE_WAVE_COOLDOWN: 'CommonBuffId' = 200005 - FUNNIEST_JOKE_PLAYFUL: 'CommonBuffId' = 98772 - FUNNY_CONVERSATION: 'CommonBuffId' = 12443 - FUSE_BOX_FLICKER_REACTION: 'CommonBuffId' = 354212 - FUSE_BOX_FLICKER_REACTION_IP: 'CommonBuffId' = 354225 - FUTURE_CUBE_BRIGHT: 'CommonBuffId' = 10298 - FUTURE_CUBE_BRIGHT_LOVE_LIFE: 'CommonBuffId' = 39895 - FUTURE_CUBE_FUTURE_LOOKS_BRIGHT: 'CommonBuffId' = 237787 - FUTURE_CUBE_GRIM: 'CommonBuffId' = 10299 - FUTURE_CUBE_GRIM_LOVE_LIFE: 'CommonBuffId' = 39896 - FUTURE_CUBE_INSPIRED: 'CommonBuffId' = 39912 - FUTURE_CUBE_READY_TO_STUDY: 'CommonBuffId' = 39902 - FUTURE_CUBE_UNSMART: 'CommonBuffId' = 39906 - FUTURE_CUBE_UN_CREATIVE: 'CommonBuffId' = 39913 - GAME_CHALLENGED_DONT_WAKE_LLAMA: 'CommonBuffId' = 127880 - GARDENER_LOVE_TO_GARDEN: 'CommonBuffId' = 131914 - GARLIC_BRAID_GARLIC_SICKNESS_LEVEL1: 'CommonBuffId' = 151175 - GARLIC_BRAID_GARLIC_SICKNESS_LEVEL2: 'CommonBuffId' = 151178 - GARLIC_BRAID_GARLIC_SICKNESS_LEVEL3: 'CommonBuffId' = 151177 - GARLIC_BRAID_IN_ONE_GARLIC: 'CommonBuffId' = 151190 - GARLIC_BRAID_IN_THREE_GARLIC: 'CommonBuffId' = 151201 - GARLIC_BRAID_IN_TWO_GARLIC: 'CommonBuffId' = 151200 - GENERIC_CANCEL_INTERACTION: 'CommonBuffId' = 226416 - GENERIC_EXIT_INTERACTION: 'CommonBuffId' = 226414 - GENERIC_INJURY_BUFFS_LEVEL_1: 'CommonBuffId' = 247128 - GENERIC_INJURY_BUFFS_LEVEL_1_CHILD: 'CommonBuffId' = 247200 - GENERIC_INJURY_BUFFS_LEVEL_2: 'CommonBuffId' = 247129 - GENERIC_INJURY_BUFFS_LEVEL_2_CHILD: 'CommonBuffId' = 247201 - GENERIC_REACTION_BEEN_SHOCKED: 'CommonBuffId' = 128925 - GETTING_MARRIED: 'CommonBuffId' = 99711 - GHOST_ANGRY: 'CommonBuffId' = 102467 - GHOST_DROWN_FEAR_WATER: 'CommonBuffId' = 103681 - GHOST_EMBARRASSMENT: 'CommonBuffId' = 102527 - GHOST_PLAYFUL: 'CommonBuffId' = 102504 - GHOST_SCARED_HORSE_NEIGH_FROM_BEYOND: 'CommonBuffId' = 324642 - GHOST_SIM_ANGRY: 'CommonBuffId' = 102488 - GHOST_SIM_PLAYFUL: 'CommonBuffId' = 102509 - GIANT_CROPS_PLANT_CRY_COOLDOWN: 'CommonBuffId' = 261508 - GIVE_GIFT_BRO_ACTOR: 'CommonBuffId' = 183064 - GIVE_GIFT_BRO_TARGET: 'CommonBuffId' = 183065 - GIVE_GIFT_HAPPY_GIVING_SPIRIT: 'CommonBuffId' = 181236 - GIVE_GIFT_HAPPY_LOVELY_SURPRISE: 'CommonBuffId' = 181237 - GIVE_GIFT_HIDDEN: 'CommonBuffId' = 190705 - GIVE_GIFT_PLAYFUL_GOTCHA_GAG_GIFT: 'CommonBuffId' = 181234 - GIVE_GIFT_ROMANTIC_ACTOR: 'CommonBuffId' = 183297 - GIVE_GIFT_ROMANTIC_TARGET: 'CommonBuffId' = 183298 - GIVE_GIFT_SAD_USELESS_GIFT: 'CommonBuffId' = 181239 - GLIMMERSTONE_COOLDOWN: 'CommonBuffId' = 219828 - GLOBAL_TEMPERATURE_BURNING: 'CommonBuffId' = 185971 - GLOBAL_TEMPERATURE_COLD: 'CommonBuffId' = 186056 - GLOBAL_TEMPERATURE_FREEZING: 'CommonBuffId' = 185970 - GLOBAL_TEMPERATURE_HOT: 'CommonBuffId' = 185978 - GLOBAL_TEMPERATURE_VEHICLE_EXIT_DELAY: 'CommonBuffId' = 222948 - GOING_OUT_SOCIALS_BREAK_UP_REJECTED_ANGRY: 'CommonBuffId' = 128795 - GOING_OUT_SOCIALS_BREAK_UP_SIMS_COOLDOWN: 'CommonBuffId' = 129863 - GOING_OUT_SOCIALS_BREAK_UP_SIMS_MEAN_OR_EVIL: 'CommonBuffId' = 275612 - GOING_OUT_SOCIALS_EXCHANGE_NUMBERS_CONFIDENT: 'CommonBuffId' = 125734 - GOING_OUT_SOCIALS_MATCHMAKE_COOLDOWN: 'CommonBuffId' = 125443 - GOING_OUT_SOCIALS_MATCH_MAKE_FEELING_THE_LOVE: 'CommonBuffId' = 274402 - GOING_OUT_SOCIALS_MATCH_MAKE_HOOK_UP_DISASTER: 'CommonBuffId' = 274403 - GOING_OUT_SOCIALS_MATCH_MAKE_HOOK_UP_MISHAP: 'CommonBuffId' = 274396 - GOING_OUT_SOCIALS_MATCH_MAKE_LOVE_DOCTOR: 'CommonBuffId' = 274401 - GOING_OUT_SOCIALS_MATCH_MAKE_TWO_SEPARATE_SOULS: 'CommonBuffId' = 274398 - GOING_OUT_SOCIALS_TALK_UP_SIM_COOLDOWN: 'CommonBuffId' = 129865 - GOING_OUT_SOCIALS_TALK_UP_SIM_FRIENDLY_CATASTROPHE: 'CommonBuffId' = 275567 - GOING_OUT_SOCIALS_TALK_UP_SIM_MADE_A_FRIEND: 'CommonBuffId' = 275569 - GOING_OUT_SOCIALS_TALK_UP_SIM_NOT_VERY_INTERESTING: 'CommonBuffId' = 275568 - GOING_OUT_SOCIALS_TALK_UP_SIM_REACTION: 'CommonBuffId' = 129402 - GOING_OUT_SOCIALS_TALK_UP_SIM_REACTION_HIDDEN: 'CommonBuffId' = 129391 - GOING_OUT_SOCIALS_TRASH_SIM_COOLDOWN: 'CommonBuffId' = 129864 - GOING_OUT_SOCIALS_TRASH_SIM_FALTERED_PLAN: 'CommonBuffId' = 275627 - GOING_OUT_SOCIALS_TRASH_SIM_MALICIOUS_INTENTIONS: 'CommonBuffId' = 275628 - GOING_OUT_SOCIALS_TRASH_SIM_REACTION: 'CommonBuffId' = 129419 - GOING_OUT_SOCIALS_TRASH_SIM_REACTION_HIDDEN: 'CommonBuffId' = 129392 - GOING_OUT_SOCIALS_TRASH_SIM_SIDE_SHAVE_BEENC_HOSEN: 'CommonBuffId' = 275626 - GOOD_MANNERS_FORBIDDEN_WORD_EMBARRASSMENT: 'CommonBuffId' = 164055 - GOOD_MANNERS_GROSS_MANNER_EMBARRASSMENT: 'CommonBuffId' = 160893 - GOOD_VICTORY: 'CommonBuffId' = 108025 - GOOD_VICTORY_GREAT_STORY: 'CommonBuffId' = 109732 - GOOD_VS_EVIL_ANGRY: 'CommonBuffId' = 26787 - GOOD_VS_EVIL_SAD: 'CommonBuffId' = 77298 - GOT_FIT: 'CommonBuffId' = 12447 - GO_FOR_WALK_DOG_IDLE_BEHAVIOR: 'CommonBuffId' = 165199 - GO_FOR_WALK_DOG_WALK_BEHAVIOR: 'CommonBuffId' = 166305 - GO_FOR_WALK_SIM_IDLE_BEHAVIOR: 'CommonBuffId' = 166239 - GO_FOR_WALK_SIM_WALK_BEHAVIOR: 'CommonBuffId' = 166114 - GO_ON_ADVENTURE_LIGHTHOUSE_CASE_CLOSED: 'CommonBuffId' = 175674 - GO_ON_ADVENTURE_LIGHTHOUSE_GHOST_DOG_HAPPY: 'CommonBuffId' = 175675 - GO_ON_ADVENTURE_LIGHTHOUSE_GHOST_DOG_SAD: 'CommonBuffId' = 175676 - GO_ON_ADVENTURE_LIGHTHOUSE_SAW_GHOST: 'CommonBuffId' = 175671 - GO_ON_ADVENTURE_LIGHTHOUSE_SUSPICIOUS: 'CommonBuffId' = 175673 - GO_ON_ADVENTURE_TOWN_SQUARE_A_B1: 'CommonBuffId' = 178248 - GO_ON_ADVENTURE_TOWN_SQUARE_DIRTY_AND_HAPPY: 'CommonBuffId' = 175955 - GO_ON_ADVENTURE_WHISKERMANS_WHARF_SAVED_DOG: 'CommonBuffId' = 175956 - GO_TO_FLOAT_HIDDEN: 'CommonBuffId' = 119068 - GRAND_MEAL_BIG_MEAL: 'CommonBuffId' = 182679 - GRAND_MEAL_FOOD_COMA: 'CommonBuffId' = 182678 - GRAND_MEAL_HIDDEN_ENJOY_COMPANY: 'CommonBuffId' = 191091 - GRIM_REAPER_ALWAYS_ON: 'CommonBuffId' = 76684 - GRIM_REAPER_DEMAND_SUCCESS: 'CommonBuffId' = 73900 - GRIM_REAPER_PLEAD_SUCCESS: 'CommonBuffId' = 73897 - GRIM_REAPER_ROLE: 'CommonBuffId' = 12450 - GRIM_REAPER_SEDUCED_DEATH: 'CommonBuffId' = 73899 - GRIM_REAPER_SPARED: 'CommonBuffId' = 12451 - GROSS_MANNERS_EMBARRASSED_GAMBLED_AND_LOST: 'CommonBuffId' = 161735 - GROSS_MANNERS_EMBARRASSED_REACTED: 'CommonBuffId' = 161734 - GROUNDED_BREAKING: 'CommonBuffId' = 163474 - GROUNDED_BREAK_REWARD_PLAYFUL: 'CommonBuffId' = 163473 - GROUNDED_BREAK_REWARD_STRESSED: 'CommonBuffId' = 163472 - GROUNDED_BROKE_FLAG: 'CommonBuffId' = 163470 - GROUNDED_CAUGHT_BREAKING: 'CommonBuffId' = 163476 - GROUNDED_CONTROLLERS_NO_COMPUTER: 'CommonBuffId' = 161725 - GROUNDED_CONTROLLERS_NO_FRIENDS: 'CommonBuffId' = 161746 - GROUNDED_CONTROLLERS_NO_MUSIC: 'CommonBuffId' = 161764 - GROUNDED_CONTROLLERS_NO_OFF_LOT: 'CommonBuffId' = 161737 - GROUNDED_CONTROLLERS_NO_PHONE: 'CommonBuffId' = 161757 - GROUNDED_CONTROLLERS_NO_TOYS: 'CommonBuffId' = 161789 - GROUNDED_CONTROLLERS_NO_TV: 'CommonBuffId' = 161676 - GROUNDED_NO_COMPUTER_HIGH_RESPONSIBILITY: 'CommonBuffId' = 161719 - GROUNDED_NO_COMPUTER_LOW_RESPONSIBILITY: 'CommonBuffId' = 161717 - GROUNDED_NO_COMPUTER_MED_RESPONSIBILITY: 'CommonBuffId' = 161720 - GROUNDED_NO_FRIENDS_HIGH_RESPONSIBILITY: 'CommonBuffId' = 161742 - GROUNDED_NO_FRIENDS_LOW_RESPONSIBILITY: 'CommonBuffId' = 161740 - GROUNDED_NO_FRIENDS_MED_RESPONSIBILITY: 'CommonBuffId' = 161743 - GROUNDED_NO_MUSIC_HIGH_RESPONSIBILITY: 'CommonBuffId' = 161761 - GROUNDED_NO_MUSIC_LOW_RESPONSIBILITY: 'CommonBuffId' = 161759 - GROUNDED_NO_MUSIC_MED_RESPONSIBILITY: 'CommonBuffId' = 161762 - GROUNDED_NO_OFF_LOT_HIGH_RESPONSIBILITY: 'CommonBuffId' = 161729 - GROUNDED_NO_OFF_LOT_LOW_RESPONSIBILITY: 'CommonBuffId' = 161727 - GROUNDED_NO_OFF_LOT_MED_RESPONSIBILITY: 'CommonBuffId' = 161730 - GROUNDED_NO_PHONE_HIGH_RESPONSIBILITY: 'CommonBuffId' = 161754 - GROUNDED_NO_PHONE_LOW_RESPONSIBILITY: 'CommonBuffId' = 161752 - GROUNDED_NO_PHONE_MED_RESPONSIBILITY: 'CommonBuffId' = 161755 - GROUNDED_NO_TOYS_HIGH_RESPONSIBILITY: 'CommonBuffId' = 161768 - GROUNDED_NO_TOYS_LOW_RESPONSIBILITY: 'CommonBuffId' = 161766 - GROUNDED_NO_TOYS_MED_RESPONSIBILITY: 'CommonBuffId' = 161769 - GROUNDED_NO_TV_HIGH_RESPONSIBILITY: 'CommonBuffId' = 161670 - GROUNDED_NO_TV_LOW_RESPONSIBILITY: 'CommonBuffId' = 161673 - GROUNDED_NO_TV_MED_RESPONSIBILITY: 'CommonBuffId' = 161672 - GROUNDED_STRESSOR: 'CommonBuffId' = 161674 - GROUNDED_WHINED_RECENTLY: 'CommonBuffId' = 168477 - GROUP_STORY_READY_TO_TELL: 'CommonBuffId' = 342622 - GROUP_WALKING_TRAIL_PREVENT_IMMEDIATE_SCORING: 'CommonBuffId' = 311561 - GROUP_WALKING_TRAIL_ROUTE_EVENT_JOG: 'CommonBuffId' = 318569 - GROUP_WALKING_TRAIL_ROUTE_EVENT_POWER_WALK: 'CommonBuffId' = 311537 - GROUP_WALKING_TRAIL_ROUTE_EVENT_REFLECTIVE_WALK: 'CommonBuffId' = 314802 - GROUP_WALKING_TRAIL_ROUTE_EVENT_WALK: 'CommonBuffId' = 311536 - GROUP_WALKING_TRAIL_SOLO_WALK_REWARDS_BRONZE: 'CommonBuffId' = 311966 - GROUP_WALKING_TRAIL_SOLO_WALK_REWARDS_SILVER_GOLD: 'CommonBuffId' = 311967 - GROUP_WALKING_TRAIL_SOLO_WALK_REWARDS_TIN: 'CommonBuffId' = 311965 - GROUP_WALKING_TRAIL_WALK_AROUND_WITH_LEADER_REWARDS_BRONZE: 'CommonBuffId' = 311963 - GROUP_WALKING_TRAIL_WALK_AROUND_WITH_LEADER_REWARDS_SILVER_GOLD: 'CommonBuffId' = 311964 - GROUP_WALKING_TRAIL_WALK_AROUND_WITH_LEADER_REWARDS_TIN: 'CommonBuffId' = 311962 - GROUP_WALKING_TRAIL_WALK_AROUND_WITH_MEMBER_REWARDS_BRONZE: 'CommonBuffId' = 311960 - GROUP_WALKING_TRAIL_WALK_AROUND_WITH_MEMBER_REWARDS_SILVER_GOLD: 'CommonBuffId' = 311961 - GROUP_WALKING_TRAIL_WALK_AROUND_WITH_MEMBER_REWARDS_TIN: 'CommonBuffId' = 311959 - GUIDED_MEDITATION_DEBUG_FEEDBACK_NEGATIVE: 'CommonBuffId' = 272732 - GUIDED_MEDITATION_DEBUG_FEEDBACK_NO_PAY: 'CommonBuffId' = 272731 - GUIDED_MEDITATION_DEBUG_FEEDBACK_POSITIVE: 'CommonBuffId' = 272733 - GUIDED_MEDITATION_DEBUG_FEEDBACK_TIP: 'CommonBuffId' = 272734 - GUIDED_MEDITATION_IN_CLASS: 'CommonBuffId' = 272143 - GUIDED_MEDITATION_IS_OUTSIDE: 'CommonBuffId' = 272316 - GUIDED_MEDITATION_POST_CLASS: 'CommonBuffId' = 272268 - GUIDED_MEDITATION_PRE_CLASS_CLASS_MEMBER: 'CommonBuffId' = 272231 - GUIDED_MEDITATION_PRE_CLASS_INSTRUCTOR: 'CommonBuffId' = 272156 - GUIDED_MEDITATION_SELF_DISCOVERY: 'CommonBuffId' = 272265 - GUIDED_MEDITATION_SELF_DISCOVERY_INCENSE: 'CommonBuffId' = 272266 - HAD_BABY: 'CommonBuffId' = 97243 - HAD_BABY_MALE: 'CommonBuffId' = 102462 - HAD_BABY_PET: 'CommonBuffId' = 169228 - HAD_SELF_DISCOVERY_HIDDEN: 'CommonBuffId' = 119066 - HAD_WOO_HOO_HIDDEN: 'CommonBuffId' = 75626 - HAIR_MAKE_UP_CHAIR_NEW_HAIR_CONFIDENT: 'CommonBuffId' = 197883 - HAIR_MAKE_UP_CHAIR_NEW_MAKE_UP_CONFIDENT: 'CommonBuffId' = 197884 - HAIR_MAKE_UP_CHAIR_REMOVE_HAT: 'CommonBuffId' = 200039 - HAIR_MAKE_UP_CHAIR_REMOVE_HAT_GIG: 'CommonBuffId' = 200999 - HAIR_MAKE_UP_CHAIR_STYLE_HAIR: 'CommonBuffId' = 196092 - HAIR_MAKE_UP_CHAIR_STYLIST_ARRIVAL: 'CommonBuffId' = 189724 - HAIR_MAKE_UP_CHAIR_STYLIST_BORED: 'CommonBuffId' = 189723 - HAIR_MAKE_UP_CHAIR_STYLIST_NEW_HAIR_INSPIRED: 'CommonBuffId' = 197882 - HAIR_MAKE_UP_CHAIR_STYLIST_NEW_MAKE_UP_INSPIRED: 'CommonBuffId' = 197888 - HAIR_MAKE_UP_CHAIR_STYLIST_WORKING: 'CommonBuffId' = 189722 - HAIR_MAKE_UP_CHAIR_WARDROBE_PEDESTAL_ALLOW_SIT: 'CommonBuffId' = 191942 - HAIR_MAKE_UP_CHAIR_WARDROBE_PEDESTAL_GIG_FAILED: 'CommonBuffId' = 189996 - HAIR_MAKE_UP_CHAIR_WARDROBE_PEDESTAL_KEEP_STYLE: 'CommonBuffId' = 189987 - HAPPILY_EVER_AFTER: 'CommonBuffId' = 103143 - HAPPILY_EVER_AFTER_GREAT_STORY: 'CommonBuffId' = 109734 - HAPPY_BY_POTION: 'CommonBuffId' = 26328 - HAPPY_HOUR: 'CommonBuffId' = 122665 - HAPPY_MEAN_MISCHIEF: 'CommonBuffId' = 37334 - HARVESTABLE_EMOTIONAL_BERRY_CONFIDENT: 'CommonBuffId' = 174575 - HARVESTABLE_EMOTIONAL_BERRY_ENERGIZED: 'CommonBuffId' = 174576 - HARVESTABLE_EMOTIONAL_BERRY_FLIRTY: 'CommonBuffId' = 174577 - HARVESTABLE_EMOTIONAL_BERRY_FOCUSED: 'CommonBuffId' = 174578 - HARVESTABLE_EMOTIONAL_BERRY_HAPPY: 'CommonBuffId' = 174574 - HARVESTABLE_EMOTIONAL_BERRY_INSPIRED: 'CommonBuffId' = 174579 - HARVESTABLE_EMOTIONAL_BERRY_PLAYFUL: 'CommonBuffId' = 174580 - HARVESTABLE_LEVEL0: 'CommonBuffId' = 103198 - HARVESTABLE_LEVEL1: 'CommonBuffId' = 103199 - HARVESTABLE_LEVEL2: 'CommonBuffId' = 103200 - HARVESTABLE_MUSHROOM_WILD_CHARMING: 'CommonBuffId' = 265137 - HARVESTABLE_MUSHROOM_WILD_CHARMING_STRONGER: 'CommonBuffId' = 266705 - HARVESTABLE_MUSHROOM_WILD_CHARMING_TODDLER: 'CommonBuffId' = 265649 - HARVESTABLE_MUSHROOM_WILD_CHARMING_TODDLER_STRONGER: 'CommonBuffId' = 266708 - HARVESTABLE_MUSHROOM_WILD_LOVELY: 'CommonBuffId' = 265138 - HARVESTABLE_MUSHROOM_WILD_LOVELY_PC: 'CommonBuffId' = 265651 - HARVESTABLE_MUSHROOM_WILD_LOVELY_PC_STRONGER: 'CommonBuffId' = 266712 - HARVESTABLE_MUSHROOM_WILD_LOVELY_STRONGER: 'CommonBuffId' = 266710 - HARVESTABLE_MUSHROOM_WILD_MYSTERIOUS: 'CommonBuffId' = 266742 - HARVESTABLE_MUSHROOM_WILD_NIGHTLY: 'CommonBuffId' = 265135 - HARVESTABLE_MUSHROOM_WILD_NIGHTLY_STRONGER: 'CommonBuffId' = 266714 - HARVESTABLE_MUSHROOM_WILD_SPICY: 'CommonBuffId' = 266253 - HARVESTABLE_MUSHROOM_WILD_SPICY_FAIL: 'CommonBuffId' = 266254 - HARVESTABLE_MUSHROOM_WILD_SPICY_FAIL_STRONGER: 'CommonBuffId' = 266718 - HARVESTABLE_MUSHROOM_WILD_SPICY_STRONGER: 'CommonBuffId' = 266716 - HARVESTABLE_MUSHROOM_WILD_VERDANT: 'CommonBuffId' = 265136 - HARVESTABLE_MUSHROOM_WILD_VERDANT_STRONGER: 'CommonBuffId' = 266720 - HARVESTABLE_MUSHROOM_WILD_VERDANT_TODDLER: 'CommonBuffId' = 265650 - HARVESTABLE_MUSHROOM_WILD_VERDANT_TODDLER_STRONGER: 'CommonBuffId' = 266722 - HARVESTABLE_VAMPIRE_EATS_GARLIC: 'CommonBuffId' = 155835 - HARVESTABLE_WEREWOLF_ATE_WOLFSBANE: 'CommonBuffId' = 298015 - HARVEST_FEST_GNOME_BAD_BUFF: 'CommonBuffId' = 180287 - HARVEST_FEST_GNOME_GOOD_BUFF: 'CommonBuffId' = 180286 - HAS_BEEN_WET: 'CommonBuffId' = 178758 - HAS_COMMITTED_TO_MAKING_IT_WORK_SENTIMENT_HIDDEN: 'CommonBuffId' = 378805 - HAS_SATISFIED_OR_VERY_SATISFIED_RELATIONSHIP_HIDDEN: 'CommonBuffId' = 378806 - HATES_CHILDREN_FLED_CHILD: 'CommonBuffId' = 259795 - HAUNTED_HOUSE_ACCURSED_REACTION_COOLDOWN: 'CommonBuffId' = 255061 - HAUNTED_HOUSE_BONEHILDA_NANNY_COOLDOWN: 'CommonBuffId' = 256679 - HAUNTED_HOUSE_DOLL_CREATE_COOLDOWN: 'CommonBuffId' = 256554 - HAUNTED_HOUSE_FIRST_TIME: 'CommonBuffId' = 252984 - HAUNTED_HOUSE_FORBIDDEN_CANDY_COOLDOWN: 'CommonBuffId' = 253677 - HAUNTED_HOUSE_GUIDRY_COOLDOWNS_DRINK: 'CommonBuffId' = 256462 - HAUNTED_HOUSE_GUIDRY_COOLDOWNS_HELP: 'CommonBuffId' = 256463 - HAUNTED_HOUSE_GUIDRY_COOLDOWNS_HUNGRY: 'CommonBuffId' = 256464 - HAUNTED_HOUSE_GUIDRY_COOLDOWNS_SLEEP: 'CommonBuffId' = 256465 - HAUNTED_HOUSE_GUIDRY_COOLDOWNS_SOUL: 'CommonBuffId' = 256582 - HAUNTED_HOUSE_GUIDRY_COOLDOWNS_TOO_SCARED: 'CommonBuffId' = 256466 - HAUNTED_HOUSE_GUIDRY_GIG: 'CommonBuffId' = 257092 - HAUNTED_HOUSE_GUIDRY_GOODBYE: 'CommonBuffId' = 255331 - HAUNTED_HOUSE_HEROIC_MODE_COOLDOWN: 'CommonBuffId' = 256332 - HAUNTED_HOUSE_PARANORMAL_INVESTIGATOR: 'CommonBuffId' = 254962 - HAUNTED_HOUSE_PARANORMAL_INVESTIGATOR_LEAVE_NOW: 'CommonBuffId' = 256781 - HAUNTED_HOUSE_PARANORMAL_INVESTIGATOR_OVER_MAX: 'CommonBuffId' = 257099 - HAUNTED_HOUSE_PARANORMAL_INVESTIGATOR_REACTION_COOLDOWN: 'CommonBuffId' = 256363 - HAUNTED_HOUSE_SOUL_SCRAP: 'CommonBuffId' = 256920 - HAUNTED_HOUSE_SPECTER_REACTION_COOLDOWN: 'CommonBuffId' = 255025 - HAUNTED_HOUSE_SPECTER_REACTION_IMMUNE: 'CommonBuffId' = 254147 - HAUNTED_HOUSE_SPECTER_SUMMON_COOLDOWN: 'CommonBuffId' = 256646 - HAUNTED_HOUSE_TEMPERANCE_BREAK_COOLDOWN: 'CommonBuffId' = 256678 - HAUNTED_HOUSE_TEMPERANCE_SCARED: 'CommonBuffId' = 256842 - HAUNTED_HOUSE_VISIBLE_ADRENALINE_SEEKER: 'CommonBuffId' = 256929 - HAUNTED_HOUSE_VISIBLE_AWKWARD_AURA: 'CommonBuffId' = 254789 - HAUNTED_HOUSE_VISIBLE_BONEHILDA_FORM: 'CommonBuffId' = 255370 - HAUNTED_HOUSE_VISIBLE_BUST_IN_FEEL_BAD: 'CommonBuffId' = 255073 - HAUNTED_HOUSE_VISIBLE_BUST_IN_FEEL_GOOD: 'CommonBuffId' = 255072 - HAUNTED_HOUSE_VISIBLE_FEAR_1: 'CommonBuffId' = 253117 - HAUNTED_HOUSE_VISIBLE_FEAR_3: 'CommonBuffId' = 253119 - HAUNTED_HOUSE_VISIBLE_FORBIDDEN_CANDY_BAD: 'CommonBuffId' = 253676 - HAUNTED_HOUSE_VISIBLE_FORBIDDEN_CANDY_GOOD: 'CommonBuffId' = 253675 - HAUNTED_HOUSE_VISIBLE_GHOST_FORM: 'CommonBuffId' = 255359 - HAUNTED_HOUSE_VISIBLE_MENACE: 'CommonBuffId' = 256773 - HAUNTED_HOUSE_VISIBLE_NEAR_TEMPERANCE: 'CommonBuffId' = 256373 - HAUNTED_HOUSE_VISIBLE_NOPE: 'CommonBuffId' = 254003 - HAUNTED_HOUSE_VISIBLE_OFFER_SOUL: 'CommonBuffId' = 254224 - HAUNTED_HOUSE_VISIBLE_PANIC: 'CommonBuffId' = 255345 - HAUNTED_HOUSE_VISIBLE_PARANORMAL_INVESTIGATOR_CHILD: 'CommonBuffId' = 255265 - HAUNTED_HOUSE_VISIBLE_READY_FOR_ANYTHING: 'CommonBuffId' = 253498 - HAUNTED_HOUSE_VISIBLE_SACRED_PROTECTION: 'CommonBuffId' = 253585 - HAUNTED_HOUSE_VISIBLE_SECOND_GUESSING: 'CommonBuffId' = 253499 - HAUNTED_HOUSE_VISIBLE_SOMETHING_AINT_RIGHT: 'CommonBuffId' = 253530 - HAUNTED_HOUSE_VISIBLE_SOUL_STUFFED: 'CommonBuffId' = 253679 - HAUNTED_HOUSE_VISIBLE_SPECTER_SLOSHED: 'CommonBuffId' = 253692 - HAUNTED_HOUSE_VISIBLE_SPECTRAL_SPRINKLES: 'CommonBuffId' = 254001 - HAUNTED_HOUSE_VISIBLE_WHAT_WAS_THAT: 'CommonBuffId' = 255353 - HEART_BED_NAUSEOUS_BUILD_UP: 'CommonBuffId' = 361617 - HIDDEN_BEING_MENTORED: 'CommonBuffId' = 38050 - HIDDEN_CHEF_COOKING: 'CommonBuffId' = 131282 - HIDDEN_CHEF_GIVE_COMPLIMENT: 'CommonBuffId' = 138534 - HIDDEN_CHEF_GIVE_INSULT: 'CommonBuffId' = 138535 - HIDDEN_CHILD_SKILL_IDEA_PERSON: 'CommonBuffId' = 308738 - HIDDEN_CONFIDENCE_CHILD_HIGH: 'CommonBuffId' = 306794 - HIDDEN_ENGAGED: 'CommonBuffId' = 281040 - HIDDEN_FIGHTING: 'CommonBuffId' = 120163 - HIDDEN_FIGHTING_VAMPIRES: 'CommonBuffId' = 156024 - HIDDEN_HOME_CHEF_COOKING_TIMER: 'CommonBuffId' = 140403 - HIDDEN_HOME_CHEF_GET_OUT: 'CommonBuffId' = 140405 - HIDDEN_HORSE_COMPETITION_ENTER_MASTER_COMPETITION: 'CommonBuffId' = 335588 - HIDDEN_HORSE_COMPETITION_WINNER_HORSE_REACTION: 'CommonBuffId' = 348347 - HIDDEN_HORSE_COMPETITION_WIN_COMPETITION: 'CommonBuffId' = 335589 - HIDDEN_HORSE_COMPETITION_WIN_MASTER_OR_ULTIMATE_COMPETITION: 'CommonBuffId' = 340311 - HIDDEN_HORSE_TRAINING_CANCEL: 'CommonBuffId' = 349192 - HIDDEN_INTERRUPT_INAPPROPRIATE_BEHAVIOR: 'CommonBuffId' = 129629 - HIDDEN_MARRIED: 'CommonBuffId' = 287888 - HIDDEN_MARRIED_NEWLY_WED: 'CommonBuffId' = 275285 - HIDDEN_MOOD_REPLACEMENT: 'CommonBuffId' = 26440 - HIDDEN_MOVE_AWAY_FROM_EQUESTRIAN_CENTER: 'CommonBuffId' = 349402 - HIDDEN_MOVE_AWAY_FROM_EQUESTRIAN_CENTER_FROM_SPECTATE: 'CommonBuffId' = 349403 - HIDDEN_OBJECT_TREAD_MILL_ROCK_CLIMBING_WALL_DEFEAT_FINAL_CLIMB_LEVEL: 'CommonBuffId' = 167902 - HIDDEN_PET_OWNER_EXIT_WATCH: 'CommonBuffId' = 170875 - HIDDEN_PET_STUBBORN_SCOLDED: 'CommonBuffId' = 166494 - HIDDEN_REMOVE_FOOTWEAR_FEMALE: 'CommonBuffId' = 119095 - HIDDEN_REMOVE_FOOTWEAR_FEMALE_SHOES: 'CommonBuffId' = 273533 - HIDDEN_REMOVE_FOOTWEAR_FEMALE_TIMEOUT: 'CommonBuffId' = 121071 - HIDDEN_REMOVE_FOOTWEAR_MALE: 'CommonBuffId' = 119094 - HIDDEN_REMOVE_FOOTWEAR_MALE_SHOES: 'CommonBuffId' = 273576 - HIDDEN_REMOVE_FOOTWEAR_MALE_TIMEOUT: 'CommonBuffId' = 121068 - HIDDEN_REMOVE_FOOTWEAR_TODDLER: 'CommonBuffId' = 273493 - HIDDEN_SCENARIO_3_INVITE_KICK_GOAL_ACTIVE: 'CommonBuffId' = 299785 - HIDDEN_SCENARIO_INHERITANCE_PHASE_1_DONATED_MONEY: 'CommonBuffId' = 338976 - HIDDEN_SCENARIO_INHERITANCE_PHASE_1_DRAMA_NODE_RECEIVED: 'CommonBuffId' = 339519 - HIDDEN_SCENARIO_INHERITANCE_PHASE_1_SENTIMENT_DECAY: 'CommonBuffId' = 347915 - HIDDEN_SCENARIO_INHERITANCE_PHASE_2_BURN_MONEY: 'CommonBuffId' = 338980 - HIDDEN_SCENARIO_INHERITANCE_PHASE_3_DONATE_INHERITANCE: 'CommonBuffId' = 338981 - HIDDEN_SCENARIO_INVITED_RIVAL: 'CommonBuffId' = 298066 - HIDDEN_SCENARIO_KICKED_OUT_RIVAL: 'CommonBuffId' = 298067 - HIDDEN_SCENARIO_STUCK_IN_THEIR_SHADOW_3_IMPROVE_WORSEN_ACTIVE: 'CommonBuffId' = 309102 - HIDDEN_SCENARIO_STUCK_IN_THEIR_SHADOW_3_RIVAL_ARRIVED: 'CommonBuffId' = 300430 - HIDDEN_SCENARIO_STUCK_IN_THEIR_SHADOW_ACCEPTED_PROPOSAL: 'CommonBuffId' = 297849 - HIDDEN_SCENARIO_STUCK_IN_THEIR_SHADOW_ASKED_ABOUT_CAREER: 'CommonBuffId' = 302136 - HIDDEN_SCENARIO_STUCK_IN_THEIR_SHADOW_ASTRONAUT_NO: 'CommonBuffId' = 302255 - HIDDEN_SCENARIO_STUCK_IN_THEIR_SHADOW_ASTRONAUT_YES: 'CommonBuffId' = 301599 - HIDDEN_SCENARIO_STUCK_IN_THEIR_SHADOW_CAN_QUIT: 'CommonBuffId' = 300348 - HIDDEN_SCENARIO_STUCK_IN_THEIR_SHADOW_GOAL_1_COMPLETE: 'CommonBuffId' = 299553 - HIDDEN_SCENARIO_STUCK_IN_THEIR_SHADOW_GOAL_2_COMPLETE: 'CommonBuffId' = 299554 - HIDDEN_SCENARIO_STUCK_IN_THEIR_SHADOW_HIGH_MOTIVES: 'CommonBuffId' = 302534 - HIDDEN_SCENARIO_STUCK_IN_THEIR_SHADOW_IMPROVE_WORSEN_COMPLETE: 'CommonBuffId' = 300059 - HIDDEN_SCENARIO_STUCK_IN_THEIR_SHADOW_PHASE_1_ANSWER_PHONE_GOAL_ACTIVE: 'CommonBuffId' = 323788 - HIDDEN_SCENARIO_STUCK_IN_THEIR_SHADOW_PHASE_3_ANSWER_PHONE_GOAL_ACTIVE: 'CommonBuffId' = 323840 - HIDDEN_SCENARIO_STUCK_IN_THEIR_SHADOW_REJECTED_PROPOSAL: 'CommonBuffId' = 297850 - HIDDEN_SCENARIO_STUCK_IN_THEIR_SHADOW_RIVAL_PURCHASES: 'CommonBuffId' = 299411 - HIDDEN_SCENARIO_STUCK_IN_THEIR_SHADOW_SCHMOOZED: 'CommonBuffId' = 300227 - HIDDEN_SCENARIO_STUCK_IN_THEIR_SHADOW_START: 'CommonBuffId' = 297026 - HIDDEN_SCENARIO_STUCK_IN_THEIR_SHADOW_VOODOO_OWNER: 'CommonBuffId' = 302339 - HIDDEN_SCENARIO_STUCK_IN_THEIR_SHADOW_WORKED_HARD: 'CommonBuffId' = 300139 - HIDDEN_SLEEPING_POD_WOOHOOING: 'CommonBuffId' = 200583 - HIDDEN_WITNESSED_DEATH_BODY: 'CommonBuffId' = 127005 - HIDDEN_WITNESSED_DEATH_MOURN: 'CommonBuffId' = 126962 - HIDDEN_WITNESSED_DEATH_REAPING: 'CommonBuffId' = 126992 - HIDDEN_YOGA_INSTRUCTOR_CLASS_STARTING: 'CommonBuffId' = 118679 - HIDDEN_YOGA_INSTRUCTOR_IN_CLASS: 'CommonBuffId' = 121795 - HIGH_SCHOOL_ACTIVE_ALL_IN_THE_BRANDING: 'CommonBuffId' = 284970 - HIGH_SCHOOL_ACTIVE_ASK_CAREER_DETAILS_COOLDOWN: 'CommonBuffId' = 282516 - HIGH_SCHOOL_ACTIVE_ASK_CAREER_DETAILS_NEGATIVE: 'CommonBuffId' = 290051 - HIGH_SCHOOL_ACTIVE_ASK_CAREER_DETAILS_POSITIVE: 'CommonBuffId' = 290050 - HIGH_SCHOOL_ACTIVE_ATTENDING_CLASS: 'CommonBuffId' = 287711 - HIGH_SCHOOL_ACTIVE_AVOIDED_CONSEQUENCES: 'CommonBuffId' = 277054 - HIGH_SCHOOL_ACTIVE_BRAND_RECOGNITION: 'CommonBuffId' = 284967 - HIGH_SCHOOL_ACTIVE_CAREER_DAY_CAN_ASK_CAREER_DETAILS: 'CommonBuffId' = 294255 - HIGH_SCHOOL_ACTIVE_CAREER_DAY_CLEAR_FUTURE: 'CommonBuffId' = 284357 - HIGH_SCHOOL_ACTIVE_CAREER_DAY_FUTURE_UNCERTAIN: 'CommonBuffId' = 284358 - HIGH_SCHOOL_ACTIVE_CAREER_DAY_WATCHED_1: 'CommonBuffId' = 289100 - HIGH_SCHOOL_ACTIVE_CAREER_DAY_WATCHED_2: 'CommonBuffId' = 289101 - HIGH_SCHOOL_ACTIVE_CAREER_DAY_WATCHED_3: 'CommonBuffId' = 289099 - HIGH_SCHOOL_ACTIVE_CAUGHT_FOR_TRUANCY: 'CommonBuffId' = 277057 - HIGH_SCHOOL_ACTIVE_CLAIMED_LOCKER: 'CommonBuffId' = 300256 - HIGH_SCHOOL_ACTIVE_CLASSICALLY_STUDIED: 'CommonBuffId' = 284939 - HIGH_SCHOOL_ACTIVE_CLUMPY_CLOTHING: 'CommonBuffId' = 291516 - HIGH_SCHOOL_ACTIVE_COMPLETED_T_POSE_CHALLENGE: 'CommonBuffId' = 293436 - HIGH_SCHOOL_ACTIVE_CRICKETS: 'CommonBuffId' = 284960 - HIGH_SCHOOL_ACTIVE_DEBUG_FORCE_CHANCE_CARD: 'CommonBuffId' = 297343 - HIGH_SCHOOL_ACTIVE_EXAM_FAIL: 'CommonBuffId' = 292772 - HIGH_SCHOOL_ACTIVE_EXAM_HIGH: 'CommonBuffId' = 292770 - HIGH_SCHOOL_ACTIVE_EXAM_MAX: 'CommonBuffId' = 292768 - HIGH_SCHOOL_ACTIVE_EXAM_POOR: 'CommonBuffId' = 292771 - HIGH_SCHOOL_ACTIVE_EXPERIMENT_GONE_WRONG: 'CommonBuffId' = 284933 - HIGH_SCHOOL_ACTIVE_FRIENDLY_GAME_OF_TELEPHONE: 'CommonBuffId' = 284894 - HIGH_SCHOOL_ACTIVE_GOAL_COUNT_1: 'CommonBuffId' = 300540 - HIGH_SCHOOL_ACTIVE_GOAL_COUNT_2: 'CommonBuffId' = 300541 - HIGH_SCHOOL_ACTIVE_GOT_AWAY_WITH_IT: 'CommonBuffId' = 284941 - HIGH_SCHOOL_ACTIVE_GOT_CLASS_LIST: 'CommonBuffId' = 282582 - HIGH_SCHOOL_ACTIVE_GOT_DETENTION_HIDDEN: 'CommonBuffId' = 276713 - HIGH_SCHOOL_ACTIVE_GRADE_TRICKLING_DOWNWARD: 'CommonBuffId' = 284964 - HIGH_SCHOOL_ACTIVE_HOOKY_AT_SCHOOL: 'CommonBuffId' = 285682 - HIGH_SCHOOL_ACTIVE_HOOKY_AT_SCHOOL_CAUGHT: 'CommonBuffId' = 304704 - HIGH_SCHOOL_ACTIVE_HOW_TO_CLIMB_THE_CORPORATE_LADDER: 'CommonBuffId' = 284962 - HIGH_SCHOOL_ACTIVE_IDEA_THEFT: 'CommonBuffId' = 291515 - HIGH_SCHOOL_ACTIVE_LAUGHING_STOCK: 'CommonBuffId' = 291512 - HIGH_SCHOOL_ACTIVE_MADE_TO_STAY_LATE: 'CommonBuffId' = 304698 - HIGH_SCHOOL_ACTIVE_MATH_WHIZ: 'CommonBuffId' = 291514 - HIGH_SCHOOL_ACTIVE_MORNING_JAMZ: 'CommonBuffId' = 291510 - HIGH_SCHOOL_ACTIVE_MOUTHED_OFF_WARNING: 'CommonBuffId' = 294896 - HIGH_SCHOOL_ACTIVE_MOUTHING_OFF: 'CommonBuffId' = 294893 - HIGH_SCHOOL_ACTIVE_NPC_JANITOR_CLEAN_BATHROOM_COOLDOWN: 'CommonBuffId' = 297004 - HIGH_SCHOOL_ACTIVE_NPC_JANITOR_CLEAN_PUDDLE_COOLDOWN: 'CommonBuffId' = 297005 - HIGH_SCHOOL_ACTIVE_NPC_JANITOR_CLEAN_TABLE_COOLDOWN: 'CommonBuffId' = 297007 - HIGH_SCHOOL_ACTIVE_NPC_MONITOR_DETENTION: 'CommonBuffId' = 297585 - HIGH_SCHOOL_ACTIVE_ONE_OF_THE_COOL_KIDS: 'CommonBuffId' = 284896 - HIGH_SCHOOL_ACTIVE_PATROL_COOLDOWN_BATHROOM: 'CommonBuffId' = 303587 - HIGH_SCHOOL_ACTIVE_PATROL_COOLDOWN_CAFETERIA: 'CommonBuffId' = 303588 - HIGH_SCHOOL_ACTIVE_PATROL_COOLDOWN_HALLWAY: 'CommonBuffId' = 303589 - HIGH_SCHOOL_ACTIVE_PATROL_COOLDOWN_MISC: 'CommonBuffId' = 303590 - HIGH_SCHOOL_ACTIVE_PA_BOREDOM: 'CommonBuffId' = 291511 - HIGH_SCHOOL_ACTIVE_PHYSICS_TO_THE_FACE: 'CommonBuffId' = 284935 - HIGH_SCHOOL_ACTIVE_READY_TO_TEST: 'CommonBuffId' = 284955 - HIGH_SCHOOL_ACTIVE_SENT_BACK_TO_SCHOOL: 'CommonBuffId' = 285639 - HIGH_SCHOOL_ACTIVE_SKIPPED_CLASS: 'CommonBuffId' = 287712 - HIGH_SCHOOL_ACTIVE_SPAGHETTI_ARCHITECT: 'CommonBuffId' = 291517 - HIGH_SCHOOL_ACTIVE_STOPPING_THE_SPREAD: 'CommonBuffId' = 284854 - HIGH_SCHOOL_ACTIVE_STUCK: 'CommonBuffId' = 284898 - HIGH_SCHOOL_ACTIVE_TONGUE_TIED: 'CommonBuffId' = 291513 - HIGH_SCHOOL_ACTIVE_TOOK_THE_BLAME: 'CommonBuffId' = 284893 - HIGH_SCHOOL_DAY_ROLE_DURING_CLASS: 'CommonBuffId' = 272760 - HIGH_SCHOOL_FESTIVAL_ALL_DO_MISCHIEF: 'CommonBuffId' = 282185 - HIGH_SCHOOL_FESTIVAL_ALL_DO_PHOTO_OP_ACTIVITY: 'CommonBuffId' = 282193 - HIGH_SCHOOL_FESTIVAL_ALL_ENTER_FESTIVAL: 'CommonBuffId' = 282496 - HIGH_SCHOOL_FESTIVAL_ALL_JUDGE_COMPETITION: 'CommonBuffId' = 282191 - HIGH_SCHOOL_FESTIVAL_ALL_SUBMIT_SCORE: 'CommonBuffId' = 282163 - HIGH_SCHOOL_FESTIVAL_ALL_WATCH_COMPETITION: 'CommonBuffId' = 282160 - HIGH_SCHOOL_FESTIVAL_ALL_WATCH_RESULT: 'CommonBuffId' = 282271 - HIGH_SCHOOL_FESTIVAL_ANNOUNCED_RESULTS: 'CommonBuffId' = 285562 - HIGH_SCHOOL_FESTIVAL_BIG_LEAGUE: 'CommonBuffId' = 291265 - HIGH_SCHOOL_FESTIVAL_BRANIAC_JAMMING: 'CommonBuffId' = 291267 - HIGH_SCHOOL_FESTIVAL_CHESS_BATTLE_NO_LAW: 'CommonBuffId' = 291266 - HIGH_SCHOOL_FESTIVAL_ENTERED_FESTIVAL: 'CommonBuffId' = 282498 - HIGH_SCHOOL_FESTIVAL_HYPED: 'CommonBuffId' = 291264 - HIGH_SCHOOL_FESTIVAL_SCIENCE_FAIR_DO_GAME_JAM: 'CommonBuffId' = 282096 - HIGH_SCHOOL_FESTIVAL_SCIENCE_FAIR_PLAY_CHESS: 'CommonBuffId' = 282180 - HIGH_SCHOOL_FESTIVAL_SCIENCE_FAIR_PLAY_CHESS_PUZZLE: 'CommonBuffId' = 282094 - HIGH_SCHOOL_FESTIVAL_SCIENCE_FAIR_PLAY_WITH_TABLET: 'CommonBuffId' = 282178 - HIGH_SCHOOL_FESTIVAL_SPORTS_DAY_DO_COMPETITIVE_CHEER: 'CommonBuffId' = 282267 - HIGH_SCHOOL_FESTIVAL_SPORTS_DAY_DO_SOLO_CHEER: 'CommonBuffId' = 282157 - HIGH_SCHOOL_FESTIVAL_SPORTS_DAY_PLAY_FOOTBALL: 'CommonBuffId' = 282186 - HIGH_SCHOOL_FESTIVAL_SUBMITTED_TO_COMPETITION: 'CommonBuffId' = 284989 - HIGH_SCHOOL_GRADUATION_BAD_VALEDICTORIAN_SPEECH: 'CommonBuffId' = 289387 - HIGH_SCHOOL_GRADUATION_GAVE_SPEECH: 'CommonBuffId' = 291680 - HIGH_SCHOOL_GRADUATION_GOOD_VALEDICTORIAN_SPEECH: 'CommonBuffId' = 289386 - HIGH_SCHOOL_GRADUATION_GOT_DIPLOMA: 'CommonBuffId' = 287699 - HIGH_SCHOOL_GRADUATION_GOT_DIPLOMA_VISIBLE: 'CommonBuffId' = 289384 - HIGH_SCHOOL_GRADUATION_GRADUATION_CAP_OFF: 'CommonBuffId' = 288616 - HIGH_SCHOOL_GRADUATION_GRADUATION_OUTFIT_BLACK: 'CommonBuffId' = 296480 - HIGH_SCHOOL_GRADUATION_GRADUATION_OUTFIT_BROWN: 'CommonBuffId' = 296585 - HIGH_SCHOOL_GRADUATION_GRADUATION_OUTFIT_CORAL: 'CommonBuffId' = 296587 - HIGH_SCHOOL_GRADUATION_GRADUATION_OUTFIT_GRAY: 'CommonBuffId' = 296586 - HIGH_SCHOOL_GRADUATION_GRADUATION_OUTFIT_GREEN_YELLOW: 'CommonBuffId' = 296588 - HIGH_SCHOOL_GRADUATION_GRADUATION_OUTFIT_HAT_BLACK: 'CommonBuffId' = 304543 - HIGH_SCHOOL_GRADUATION_GRADUATION_OUTFIT_HAT_BROWN: 'CommonBuffId' = 304544 - HIGH_SCHOOL_GRADUATION_GRADUATION_OUTFIT_HAT_CORAL: 'CommonBuffId' = 304545 - HIGH_SCHOOL_GRADUATION_GRADUATION_OUTFIT_HAT_GRAY: 'CommonBuffId' = 304546 - HIGH_SCHOOL_GRADUATION_GRADUATION_OUTFIT_HAT_GREEN_YELLOW: 'CommonBuffId' = 304547 - HIGH_SCHOOL_GRADUATION_GRADUATION_OUTFIT_HAT_NAVY_RED: 'CommonBuffId' = 304548 - HIGH_SCHOOL_GRADUATION_GRADUATION_OUTFIT_HAT_ORANGE: 'CommonBuffId' = 304549 - HIGH_SCHOOL_GRADUATION_GRADUATION_OUTFIT_HAT_PURPLE: 'CommonBuffId' = 304550 - HIGH_SCHOOL_GRADUATION_GRADUATION_OUTFIT_HAT_RED: 'CommonBuffId' = 304581 - HIGH_SCHOOL_GRADUATION_GRADUATION_OUTFIT_HAT_WHITE: 'CommonBuffId' = 304582 - HIGH_SCHOOL_GRADUATION_GRADUATION_OUTFIT_HAT_WHITE_BLUE: 'CommonBuffId' = 304583 - HIGH_SCHOOL_GRADUATION_GRADUATION_OUTFIT_NAVY_RED: 'CommonBuffId' = 296590 - HIGH_SCHOOL_GRADUATION_GRADUATION_OUTFIT_ORANGE: 'CommonBuffId' = 296591 - HIGH_SCHOOL_GRADUATION_GRADUATION_OUTFIT_PURPLE: 'CommonBuffId' = 296584 - HIGH_SCHOOL_GRADUATION_GRADUATION_OUTFIT_RED: 'CommonBuffId' = 296488 - HIGH_SCHOOL_GRADUATION_GRADUATION_OUTFIT_WHITE: 'CommonBuffId' = 296486 - HIGH_SCHOOL_GRADUATION_GRADUATION_OUTFIT_WHITE_BLUE: 'CommonBuffId' = 296589 - HIGH_SCHOOL_GRADUATION_HEARD_BAD_SPEECH: 'CommonBuffId' = 289389 - HIGH_SCHOOL_GRADUATION_HEARD_GOOD_SPEECH: 'CommonBuffId' = 289388 - HIGH_SCHOOL_GRADUATION_SHARED_SCHOOL_MEMORIES: 'CommonBuffId' = 289385 - HIGH_SCHOOL_GRADUATION_WAITING_FOR_GIVE_DIPLOMA: 'CommonBuffId' = 302812 - HIGH_SCHOOL_PROM_CELEBRITY_DATE: 'CommonBuffId' = 280982 - HIGH_SCHOOL_PROM_CROWN_AUTONOMY: 'CommonBuffId' = 303165 - HIGH_SCHOOL_PROM_CROWN_SPIN_JESTER: 'CommonBuffId' = 283491 - HIGH_SCHOOL_PROM_CROWN_SPIN_ROYALTY: 'CommonBuffId' = 283492 - HIGH_SCHOOL_PROM_GOT_PROM_TNS: 'CommonBuffId' = 303561 - HIGH_SCHOOL_PROM_HIDDEN_GOT_PROM_TNS: 'CommonBuffId' = 289892 - HIGH_SCHOOL_PROM_NOSTALGIA: 'CommonBuffId' = 291997 - HIGH_SCHOOL_PROM_PRESENTER_ROUTE_TO_PODIUM: 'CommonBuffId' = 291274 - HIGH_SCHOOL_PROM_PRESENTER_WAITING: 'CommonBuffId' = 291933 - HIGH_SCHOOL_PROM_PRESENTING: 'CommonBuffId' = 285055 - HIGH_SCHOOL_PROM_REJECTED_PROM_POSAL: 'CommonBuffId' = 280985 - HIGH_SCHOOL_PROM_ROLE_TEEN_GENERIC: 'CommonBuffId' = 289410 - HIGH_SCHOOL_PROM_ROLE_TEEN_PRE_VOTE: 'CommonBuffId' = 284077 - HIGH_SCHOOL_PROM_SELECT_SIGN_1: 'CommonBuffId' = 301957 - HIGH_SCHOOL_PROM_SELECT_SIGN_2: 'CommonBuffId' = 301958 - HIGH_SCHOOL_PROM_SELECT_SIGN_3: 'CommonBuffId' = 301959 - HIGH_SCHOOL_PROM_SELECT_SIGN_4: 'CommonBuffId' = 301960 - HIGH_SCHOOL_PROM_SELECT_SIGN_5: 'CommonBuffId' = 301961 - HIGH_SCHOOL_PROM_SO_SHINY: 'CommonBuffId' = 280983 - HIGH_SCHOOL_PROM_SUCCESSFUL_PROMPOSAL: 'CommonBuffId' = 280984 - HIGH_SCHOOL_PROM_TEEN_GATHERING: 'CommonBuffId' = 285056 - HIGH_SCHOOL_PROM_TEEN_POST_VOTE: 'CommonBuffId' = 294531 - HIGH_SCHOOL_PROM_VOTED_JESTER: 'CommonBuffId' = 284628 - HIGH_SCHOOL_PROM_VOTED_ROYALTY: 'CommonBuffId' = 284629 - HIGH_SCHOOL_PROM_WATCH_AWARDS: 'CommonBuffId' = 301076 - HIGH_SCHOOL_PROM_WEARING_CROWN: 'CommonBuffId' = 284110 - HIGH_SCHOOL_TEAMS_CRUSH_CONFIDENT: 'CommonBuffId' = 296242 - HIGH_SCHOOL_TEAMS_CRUSH_EMBARRASSED: 'CommonBuffId' = 296241 - HIKING_TRAIL_HIKE_AROUND_WITH_BRONZE: 'CommonBuffId' = 240590 - HIKING_TRAIL_HIKE_AROUND_WITH_GOLD: 'CommonBuffId' = 240592 - HIKING_TRAIL_HIKE_AROUND_WITH_GOLD_ALL_SIMS: 'CommonBuffId' = 249653 - HIKING_TRAIL_HIKE_AROUND_WITH_LEADER_SILVER: 'CommonBuffId' = 249505 - HIKING_TRAIL_HIKE_AROUND_WITH_LEADER_TIN: 'CommonBuffId' = 249504 - HIKING_TRAIL_HIKE_AROUND_WITH_SILVER: 'CommonBuffId' = 240591 - HIKING_TRAIL_HIKE_AROUND_WITH_TIN: 'CommonBuffId' = 240589 - HIKING_TRAIL_POI_ENVIRONMENT_BAMBOO: 'CommonBuffId' = 249881 - HIKING_TRAIL_POI_ENVIRONMENT_NATURE_COVE: 'CommonBuffId' = 249882 - HIKING_TRAIL_POI_OFFERING_HIGH_VALUE: 'CommonBuffId' = 249884 - HIKING_TRAIL_POI_OFFERING_NORMAL_VALUE: 'CommonBuffId' = 249885 - HIKING_TRAIL_POI_OFFERING_POOR_ITEM: 'CommonBuffId' = 249887 - HIKING_TRAIL_POI_OFFERING_VERY_POOR_VALUE: 'CommonBuffId' = 249886 - HIKING_TRAIL_POI_SELFIE_CEMETERY: 'CommonBuffId' = 253842 - HIKING_TRAIL_POI_SELFIE_HAPPY: 'CommonBuffId' = 249883 - HIKING_TRAIL_POI_WISH_HAPPY: 'CommonBuffId' = 249889 - HIKING_TRAIL_POI_WISH_SAD: 'CommonBuffId' = 249888 - HIKING_TRAIL_PREVENT_IMMEDIATE_SCORING: 'CommonBuffId' = 253843 - HIKING_TRAIL_ROUTE_EVENT_JOG: 'CommonBuffId' = 251094 - HIKING_TRAIL_ROUTE_EVENT_MEDITATIVE_WALK: 'CommonBuffId' = 251095 - HIKING_TRAIL_ROUTE_EVENT_MINDFUL_WALK: 'CommonBuffId' = 253845 - HIKING_TRAIL_ROUTE_EVENT_WALK: 'CommonBuffId' = 251096 - HIKING_TRAIL_SOLO_HIKE_BRONZE: 'CommonBuffId' = 249502 - HIKING_TRAIL_SOLO_HIKE_SILVER: 'CommonBuffId' = 249503 - HIKING_TRAIL_SOLO_HIKE_TIN: 'CommonBuffId' = 249501 - HOLIDAYS_FASTING_COMPLETE: 'CommonBuffId' = 185462 - HOLIDAYS_FASTING_CONTROLLER: 'CommonBuffId' = 185756 - HOLIDAYS_FASTING_FAILED: 'CommonBuffId' = 185760 - HOLIDAYS_FASTING_PROGRESS: 'CommonBuffId' = 185464 - HOLIDAYS_GO_STREAKING: 'CommonBuffId' = 190712 - HOLIDAYS_HIDDEN_BASE_SOCIALS: 'CommonBuffId' = 181954 - HOLIDAYS_SABOTAGE_DISCIPLINE_INTERACTIONS: 'CommonBuffId' = 190702 - HOLIDAYS_TRADITION_VISIBLE_ALMOST_MISSED_THE_BALL_DROP: 'CommonBuffId' = 187765 - HOLIDAYS_VISIBLE_EXCELLENT: 'CommonBuffId' = 184169 - HOLIDAYS_VISIBLE_FAILURE: 'CommonBuffId' = 184170 - HOLIDAYS_VISIBLE_GREAT: 'CommonBuffId' = 184171 - HOLIDAY_BASE_ACTIVE: 'CommonBuffId' = 190549 - HOLIDAY_BASE_SINGING_TERRAIN: 'CommonBuffId' = 190554 - HOLIDAY_CANDLES_FEELING_FESTIVE_KINARA: 'CommonBuffId' = 348580 - HOLIDAY_CANDLES_FEELING_FESTIVE_MENORAH: 'CommonBuffId' = 348377 - HOLIDAY_CRACKER_CANDY_BUFFS_DAZED: 'CommonBuffId' = 155089 - HOLIDAY_CRACKER_CANDY_BUFFS_ENERGIZED: 'CommonBuffId' = 155102 - HOLIDAY_CRACKER_CANDY_BUFFS_FLIRTY: 'CommonBuffId' = 155065 - HOLIDAY_CRACKER_CANDY_BUFFS_HAPPY: 'CommonBuffId' = 155103 - HOLIDAY_CRACKER_CANDY_BUFFS_PLAYFUL: 'CommonBuffId' = 155104 - HOLIDAY_CRACKER_CANDY_BUFFS_UNCOMFORTABLE: 'CommonBuffId' = 155107 - HOLIDAY_CRACKER_CHILD_ANGER_BUFF: 'CommonBuffId' = 154618 - HOLIDAY_CRACKER_FESTIVE_BUFF: 'CommonBuffId' = 154617 - HOLIDAY_CRACKER_PLAYFUL_BUFF: 'CommonBuffId' = 154615 - HOLIDAY_CRACKER_SAD_BUFF: 'CommonBuffId' = 154619 - HOLIDAY_CRACKER_STRESSED: 'CommonBuffId' = 156177 - HOLIDAY_CRACKER_STRESSED_ELDERS: 'CommonBuffId' = 154614 - HOLIDAY_DECORATIONS_NEARBY: 'CommonBuffId' = 182227 - HOLIDAY_HIDDEN_GETTING_FORGED_BREAKUP_LETTER: 'CommonBuffId' = 191193 - HOLIDAY_TRADITIONS_HIDDEN_ADMIRE_GHOSTS: 'CommonBuffId' = 185903 - HOLIDAY_TRADITIONS_HIDDEN_ADORE_OBJECT: 'CommonBuffId' = 185570 - HOLIDAY_TRADITIONS_HIDDEN_BE_FESTIVE: 'CommonBuffId' = 185824 - HOLIDAY_TRADITIONS_HIDDEN_BE_THANKFUL: 'CommonBuffId' = 185845 - HOLIDAY_TRADITIONS_HIDDEN_EGG_HUNT: 'CommonBuffId' = 185569 - HOLIDAY_TRADITIONS_HIDDEN_FATHER_WINTER: 'CommonBuffId' = 185904 - HOLIDAY_TRADITIONS_HIDDEN_FESTIVE_LIGHTING: 'CommonBuffId' = 192434 - HOLIDAY_TRADITIONS_HIDDEN_GIVEN_PRESENT: 'CommonBuffId' = 188738 - HOLIDAY_TRADITIONS_HIDDEN_GIVE_GIFTS_ACTIVE: 'CommonBuffId' = 183253 - HOLIDAY_TRADITIONS_HIDDEN_GIVING_FLOWER: 'CommonBuffId' = 190740 - HOLIDAY_TRADITIONS_HIDDEN_GNOMES: 'CommonBuffId' = 185039 - HOLIDAY_TRADITIONS_HIDDEN_GO_TO_SERVICES: 'CommonBuffId' = 182195 - HOLIDAY_TRADITIONS_HIDDEN_NPC_GIVE_GIFTS_AUTONOMY: 'CommonBuffId' = 186034 - HOLIDAY_TRADITIONS_HIDDEN_ON_VACATION: 'CommonBuffId' = 191349 - HOLIDAY_TRADITIONS_HIDDEN_PARTY_INTERACTIONS: 'CommonBuffId' = 186063 - HOLIDAY_TRADITIONS_HIDDEN_SING_BOX_OF_DECORATIONS: 'CommonBuffId' = 189822 - HOLIDAY_TRADITIONS_HIDDEN_SING_FIREWORKS: 'CommonBuffId' = 190543 - HOLIDAY_TRADITIONS_HIDDEN_SING_GNOME: 'CommonBuffId' = 189821 - HOLIDAY_TRADITIONS_HIDDEN_SING_GRAND_MEAL: 'CommonBuffId' = 189826 - HOLIDAY_TRADITIONS_HIDDEN_SING_HOLIDAY_TREE: 'CommonBuffId' = 189839 - HOLIDAY_TRADITIONS_HIDDEN_SING_LIGHTING_CANDLES: 'CommonBuffId' = 189837 - HOLIDAY_TRADITIONS_HIDDEN_SING_PRESENT_PILE: 'CommonBuffId' = 189824 - HOLIDAY_TRADITIONS_HIDDEN_THROW_CONFETTI: 'CommonBuffId' = 186062 - HOLIDAY_TRADITIONS_HIDDEN_WATCH_COUNTDOWN: 'CommonBuffId' = 184001 - HOLIDAY_TRADITIONS_HIDDEN_WEAR_COSTUMES: 'CommonBuffId' = 187795 - HOLIDAY_TRADITIONS_HIDDEN_WEAR_COSTUME_COSTUME_ON: 'CommonBuffId' = 188498 - HOLIDAY_TRADITIONS_VISIBLE_BACK_TO_THE_FLOWER_GARDEN: 'CommonBuffId' = 187719 - HOLIDAY_TRADITIONS_VISIBLE_BACK_TO_THE_NORTH_POLE: 'CommonBuffId' = 187712 - HOLIDAY_TRADITIONS_VISIBLE_COUNTDOWN_TO_HILARITY: 'CommonBuffId' = 187767 - HOLIDAY_TRADITIONS_VISIBLE_DECORATE_THIS: 'CommonBuffId' = 187770 - HOLIDAY_TRADITIONS_VISIBLE_DECORATION_DESTRUCTION: 'CommonBuffId' = 187771 - HOLIDAY_TRADITIONS_VISIBLE_EVIL_LITTLE_LETTER: 'CommonBuffId' = 188794 - HOLIDAY_TRADITIONS_VISIBLE_FAMILY_TIME_TOMORROW: 'CommonBuffId' = 182184 - HOLIDAY_TRADITIONS_VISIBLE_FATHER_WINTERS_GOT_GAME: 'CommonBuffId' = 187720 - HOLIDAY_TRADITIONS_VISIBLE_FEAST_TOMORROW: 'CommonBuffId' = 182182 - HOLIDAY_TRADITIONS_VISIBLE_FLOWER_BUNNYS_GOT_GAME: 'CommonBuffId' = 187718 - HOLIDAY_TRADITIONS_VISIBLE_FORGERY_FAILURE: 'CommonBuffId' = 188793 - HOLIDAY_TRADITIONS_VISIBLE_GAME_OVER_FATHER_WINTER: 'CommonBuffId' = 187725 - HOLIDAY_TRADITIONS_VISIBLE_GAME_OVER_FLOWER_BUNNY: 'CommonBuffId' = 187724 - HOLIDAY_TRADITIONS_VISIBLE_GIFT_GIFTS_CHANCE_CARD_FAILURE: 'CommonBuffId' = 190337 - HOLIDAY_TRADITIONS_VISIBLE_GIFT_GIFTS_CHANCE_CARD_SUCCESS_CHILD: 'CommonBuffId' = 190339 - HOLIDAY_TRADITIONS_VISIBLE_GIFT_GIFTS_CHANCE_CARD_SUCCESS_TEEN: 'CommonBuffId' = 190336 - HOLIDAY_TRADITIONS_VISIBLE_LEAVE_FATHER_WINTER_ALONE: 'CommonBuffId' = 187722 - HOLIDAY_TRADITIONS_VISIBLE_LEAVE_FLOWER_BUNNY_ALONE: 'CommonBuffId' = 187721 - HOLIDAY_TRADITIONS_VISIBLE_MADE_IT_TO_MIDNIGHT: 'CommonBuffId' = 185846 - HOLIDAY_TRADITIONS_VISIBLE_MEAL_IN_AND_DEAL_IN: 'CommonBuffId' = 187768 - HOLIDAY_TRADITIONS_VISIBLE_PRESENTS_TOMORROW: 'CommonBuffId' = 182183 - HOLIDAY_TRADITIONS_VISIBLE_ROMANTIC_DAY_TOMORROW: 'CommonBuffId' = 182180 - HOLIDAY_TRADITIONS_VISIBLE_WHAT_A_THING: 'CommonBuffId' = 190453 - HOLIDAY_TRADITIONS_VISIBLE_WONDERFUL_SERVICE: 'CommonBuffId' = 182198 - HOLIDAY_TRADITIONS_WEAR_COSTUMES_WALK_BY: 'CommonBuffId' = 188579 - HOLIDAY_TREE_DECORATION_FAIL_ANGRY: 'CommonBuffId' = 180641 - HOLIDAY_TREE_DECORATION_FAIL_EMBARRASSED: 'CommonBuffId' = 180643 - HOLIDAY_TREE_DECORATION_SUCCESS: 'CommonBuffId' = 180636 - HOLIDAY_TREE_FEELING_FESTIVE: 'CommonBuffId' = 180611 - HOLIDAY_TREE_HIDDEN_EXIT: 'CommonBuffId' = 191241 - HOLIDAY_TREE_HIDDEN_WATCH: 'CommonBuffId' = 191242 - HOLIDAY_TREE_SABOTAGE_HAPPY: 'CommonBuffId' = 183606 - HOLOTABLE_ALARM_FIRST_ORDER_BROADCASTER: 'CommonBuffId' = 245027 - HOLOTABLE_ALARM_RESISTANCE_BROADCASTER: 'CommonBuffId' = 245028 - HOLOTABLE_ALARM_TRIGGERED: 'CommonBuffId' = 251008 - HOLOTABLE_ARCHIVES_ARE_COMPLETE: 'CommonBuffId' = 243144 - HOP_SCOTCH_HOPPED_TO_TOP: 'CommonBuffId' = 340937 - HOP_SCOTCH_HOPPING_MAD: 'CommonBuffId' = 340938 - HOP_SCOTCH_IN_GAME: 'CommonBuffId' = 342594 - HOP_SCOTCH_JUST_FAILED_HOP: 'CommonBuffId' = 340641 - HOP_SCOTCH_MORTIFYING_MISSTEP: 'CommonBuffId' = 340939 - HORRIFYING_JOKE_EMBARRASSED: 'CommonBuffId' = 98774 - HORSE_ADD_SENTIMENT_WITNESS_FOAL_BIRTH: 'CommonBuffId' = 338491 - HORSE_BREEDING_BUFFS_SIM_FOAL_DELIVERY: 'CommonBuffId' = 324233 - HORSE_BREEDING_BUFFS_SIM_HEART_FOAL_OF_LOVE: 'CommonBuffId' = 324087 - HORSE_BREEDING_BUFFS_WOOHOO_COOLDOWN: 'CommonBuffId' = 323056 - HORSE_CARE_OBJECTS_HORSE_TOY_PLAYFUL: 'CommonBuffId' = 328979 - HORSE_CARE_OBJECTS_HORSE_TOY_SAD: 'CommonBuffId' = 328980 - HORSE_DRINK_WATER_COOLDOWN_AUTONOMOUS: 'CommonBuffId' = 348067 - HORSE_FATIGUE_REACTION_COOLDOWN: 'CommonBuffId' = 349441 - HORSE_FOAL_MENTOREE_BY_MENTOR_PRO_TEMPERAMENT_SKILL: 'CommonBuffId' = 329482 - HORSE_HIDDEN_BASK_IN_HORSE_BRAVERY_COOLDOWN: 'CommonBuffId' = 340981 - HORSE_HIDDEN_BE_WOKEN_UP: 'CommonBuffId' = 328400 - HORSE_HIDDEN_MEAN_ACTOR_COOLDOWN_HORSE: 'CommonBuffId' = 346921 - HORSE_HIDDEN_MEAN_ACTOR_COOLDOWN_SIM: 'CommonBuffId' = 346922 - HORSE_HIDDEN_TEACH_TO_CANTER_COOLDOWN: 'CommonBuffId' = 330837 - HORSE_HIDDEN_WILL_NOT_BUCK: 'CommonBuffId' = 340914 - HORSE_HORSE_COMPETITION_CHAMPIONSHIP_HORSE: 'CommonBuffId' = 333538 - HORSE_HORSE_COMPETITION_ENTERED_A_COMPETITION: 'CommonBuffId' = 335314 - HORSE_INTELLECTUAL_CHAT_PICKER_COOLDOWN: 'CommonBuffId' = 348388 - HORSE_IS_SLEEPING: 'CommonBuffId' = 325741 - HORSE_IS_SLEEPING_SS3: 'CommonBuffId' = 328034 - HORSE_IS_SOCIALIZING: 'CommonBuffId' = 328033 - HORSE_MOODLETS_ANGRY_DEFIANT_FAILED_ASK_FOR_COOPERATION: 'CommonBuffId' = 340907 - HORSE_MOODLETS_CONFIDENT_EP14_WORLD_NPC_HORSE_TRAINER: 'CommonBuffId' = 329635 - HORSE_MOODLETS_CONFIDENT_EQUESTRIAN_SKILL: 'CommonBuffId' = 324382 - HORSE_MOODLETS_CONFIDENT_HORSE_OBSTACLES_SUCCESS: 'CommonBuffId' = 332050 - HORSE_MOODLETS_CONFIDENT_HORSE_TRAINING_ENCOURAGEMENT: 'CommonBuffId' = 332051 - HORSE_MOODLETS_CONFIDENT_MASTER_TRAINER_DURING_TRAINING: 'CommonBuffId' = 328997 - HORSE_MOODLETS_CONFIDENT_MASTER_TRAINER_POST_RIDE: 'CommonBuffId' = 328998 - HORSE_MOODLETS_DAZED_MELLOW_TRAINING_DAZE: 'CommonBuffId' = 340908 - HORSE_MOODLETS_DAZED_NEW_FOAL: 'CommonBuffId' = 330839 - HORSE_MOODLETS_HAPPY_ALL_MOTIVES_HIGH: 'CommonBuffId' = 335959 - HORSE_MOODLETS_HAPPY_CRADLED_WELL: 'CommonBuffId' = 330141 - HORSE_MOODLETS_HAPPY_EATING_FOOD_QUALITY_EXCELLENT: 'CommonBuffId' = 324246 - HORSE_MOODLETS_HAPPY_EATING_FOOD_QUALITY_MAGNIFICENT: 'CommonBuffId' = 324247 - HORSE_MOODLETS_HAPPY_EATING_FOOD_QUALITY_NICE: 'CommonBuffId' = 324245 - HORSE_MOODLETS_HAPPY_EATING_FOOD_QUALITY_PERFECT: 'CommonBuffId' = 324248 - HORSE_MOODLETS_HAPPY_ENERGETIC_GOT_EXERCISE: 'CommonBuffId' = 340772 - HORSE_MOODLETS_HAPPY_EQUESTRIAN_SKILL: 'CommonBuffId' = 326892 - HORSE_MOODLETS_HAPPY_GENTLY_TOUCHED: 'CommonBuffId' = 330139 - HORSE_MOODLETS_HAPPY_TALK_TO_GOAT: 'CommonBuffId' = 331361 - HORSE_MOODLETS_HAPPY_TALK_TO_SHEEP: 'CommonBuffId' = 331364 - HORSE_MOODLETS_HAPPY_WEAN_TO_HAY: 'CommonBuffId' = 330047 - HORSE_MOODLETS_HAPPY_WHATS_THAT: 'CommonBuffId' = 331853 - HORSE_MOODLETS_SAD_HORSE_OBSTACLES_FAILURE: 'CommonBuffId' = 332052 - HORSE_MOODLETS_SAD_LOST_COMPETITION: 'CommonBuffId' = 324471 - HORSE_MOODLETS_SAD_NEEDY_NEEDS_HAND_FEED: 'CommonBuffId' = 340725 - HORSE_MOODLETS_SAD_STUCK_INSIDE: 'CommonBuffId' = 326341 - HORSE_MOODLETS_SAD_TALK_TO_GOAT: 'CommonBuffId' = 331362 - HORSE_MOODLETS_SAD_TALK_TO_SHEEP: 'CommonBuffId' = 331363 - HORSE_MOODLETS_SAD_WEAN_TO_HAY: 'CommonBuffId' = 330048 - HORSE_MOODLETS_SAD_WITNESSED_DEATH: 'CommonBuffId' = 347528 - HORSE_MOODLETS_SCARED_FIRE: 'CommonBuffId' = 331744 - HORSE_MOODLETS_SCARED_LIGHTNING_NEARBY: 'CommonBuffId' = 335304 - HORSE_MOODLETS_SCARED_ROUGHLY_TOUCHED: 'CommonBuffId' = 330140 - HORSE_MOODLETS_SCARED_SPOOKED: 'CommonBuffId' = 324470 - HORSE_MOODLETS_SCARED_WHATS_THAT: 'CommonBuffId' = 331854 - HORSE_MOODLETS_TENSE_DEFIANT_STRESSED_FROM_MOUNTING: 'CommonBuffId' = 340906 - HORSE_MOODLETS_TENSE_EQUESTRIAN_SKILL_RIDING_IRRITATION: 'CommonBuffId' = 324384 - HORSE_MOODLETS_TENSE_EQUESTRIAN_SKIL_FEELING_RIDER_STRESS: 'CommonBuffId' = 324385 - HORSE_MOODLETS_UNCOMFORTABLE_DESOLATE: 'CommonBuffId' = 322224 - HORSE_MOODLETS_UNCOMFORTABLE_DESPERATE_FOR_FUN: 'CommonBuffId' = 322222 - HORSE_MOODLETS_UNCOMFORTABLE_DIRTY: 'CommonBuffId' = 322225 - HORSE_MOODLETS_UNCOMFORTABLE_EXHAUSTED: 'CommonBuffId' = 322220 - HORSE_MOODLETS_UNCOMFORTABLE_FAMISHED: 'CommonBuffId' = 322218 - HORSE_MOODLETS_UNCOMFORTABLE_HUNGRY: 'CommonBuffId' = 322217 - HORSE_MOODLETS_UNCOMFORTABLE_LONELY: 'CommonBuffId' = 322223 - HORSE_MOODLETS_UNCOMFORTABLE_NEEDS_AMUSMENT: 'CommonBuffId' = 322221 - HORSE_MOODLETS_UNCOMFORTABLE_ROUGHLY_CRADLED: 'CommonBuffId' = 330142 - HORSE_MOODLETS_UNCOMFORTABLE_TIRED: 'CommonBuffId' = 322219 - HORSE_MOTIVE_HYGIENE_ALLOW_CARE: 'CommonBuffId' = 348616 - HORSE_OBSTACLES_SIM_FAILURE: 'CommonBuffId' = 332055 - HORSE_OBSTACLES_SIM_SUCCESS: 'CommonBuffId' = 332054 - HORSE_RIDING_ALWAYS_THROW_RIDER: 'CommonBuffId' = 332120 - HORSE_RIDING_APPEARANCE_MODIFIER_REINS: 'CommonBuffId' = 332274 - HORSE_RIDING_APPEARANCE_MODIFIER_SADDLE: 'CommonBuffId' = 332141 - HORSE_RIDING_AUTONOMOUS_SOCIAL_WITH_RIDDEN_HORSE: 'CommonBuffId' = 347618 - HORSE_RIDING_HAPPY_REIN_IN_THE_SCENERY: 'CommonBuffId' = 326887 - HORSE_RIDING_HORSE_CARRYING_SIM: 'CommonBuffId' = 339267 - HORSE_RIDING_HORSE_LOVER: 'CommonBuffId' = 349411 - HORSE_RIDING_HORSE_MOUNTED: 'CommonBuffId' = 317538 - HORSE_RIDING_NEVER_THROW_RIDER: 'CommonBuffId' = 332089 - HORSE_RIDING_REAR_UP_UNBUCKABLE: 'CommonBuffId' = 340123 - HORSE_RIDING_REAR_UP_UNEXPECTED_REARING: 'CommonBuffId' = 340124 - HORSE_RIDING_REINS_DOWN: 'CommonBuffId' = 342330 - HORSE_RIDING_SIM_BUCKED_EMBARRASSED: 'CommonBuffId' = 339401 - HORSE_RIDING_SIM_BUCKED_UNCOMFORTABLE: 'CommonBuffId' = 339400 - HORSE_RIDING_SIM_MOUNTED: 'CommonBuffId' = 317537 - HORSE_RIDING_THROW_RIDER: 'CommonBuffId' = 332086 - HORSE_RIDING_WALKSTYLE_CANTER: 'CommonBuffId' = 326965 - HORSE_RIDING_WALKSTYLE_CANTER_LOW_SKILL: 'CommonBuffId' = 331991 - HORSE_RIDING_WALKSTYLE_CANTER_LOW_SKILL_BUCK_WILD: 'CommonBuffId' = 331996 - HORSE_RIDING_WALKSTYLE_GHOST_CANTER: 'CommonBuffId' = 345117 - HORSE_RIDING_WALKSTYLE_GHOST_CANTER_LOW_SKILL: 'CommonBuffId' = 345118 - HORSE_RIDING_WALKSTYLE_GHOST_TROT: 'CommonBuffId' = 345115 - HORSE_RIDING_WALKSTYLE_GHOST_TROT_LOW_SKILL: 'CommonBuffId' = 345116 - HORSE_RIDING_WALKSTYLE_GHOST_WALK: 'CommonBuffId' = 345113 - HORSE_RIDING_WALKSTYLE_GHOST_WALK_LOW_SKILL: 'CommonBuffId' = 345114 - HORSE_RIDING_WALKSTYLE_TROT: 'CommonBuffId' = 326967 - HORSE_RIDING_WALKSTYLE_TROT_LOW_SKILL: 'CommonBuffId' = 331993 - HORSE_RIDING_WALKSTYLE_TROT_LOW_SKILL_BUCK_WILD: 'CommonBuffId' = 331997 - HORSE_RIDING_WALKSTYLE_WALK: 'CommonBuffId' = 326966 - HORSE_RIDING_WALKSTYLE_WALK_LOW_SKILL: 'CommonBuffId' = 331995 - HORSE_RUN_AROUND_COOLDOWN: 'CommonBuffId' = 348068 - HORSE_RUN_AROUND_FROLIC_COOLDOWN: 'CommonBuffId' = 352692 - HORSE_RUN_AROUND_PORTAL_DISABLE: 'CommonBuffId' = 353335 - HORSE_SEASON_WEATHER_WET_VFX: 'CommonBuffId' = 335391 - HORSE_SEASON_WEATHER_WET_VFX_FOAL: 'CommonBuffId' = 349449 - HORSE_TRAINING_ENDURANCE_FATIGUE_DECAY: 'CommonBuffId' = 337154 - HORSE_TRAINING_FATIGUE: 'CommonBuffId' = 327961 - HORSE_TRAINING_SOCIALS_CHARISMA: 'CommonBuffId' = 330480 - HORSE_TRAINING_SOCIALS_DANCE: 'CommonBuffId' = 330481 - HORSE_TRAINING_SOCIALS_FITNESS: 'CommonBuffId' = 330478 - HORSE_TRAINING_SOCIALS_GAME_JUMPING: 'CommonBuffId' = 330479 - HORSE_TRANSACTION_ASK_ABOUT_HORSES_HIDDEN: 'CommonBuffId' = 332748 - HORSE_TRANSACTION_RECENTLY_INTERACTED_HIDDEN: 'CommonBuffId' = 332749 - HORSE_WEATHER_AUTONOMY_HIDDEN_IN_THE_RAIN: 'CommonBuffId' = 335400 - HOT_POT_ALL_PARTICIPANTS: 'CommonBuffId' = 254214 - HOT_POT_ATE_WITH_OTHERS: 'CommonBuffId' = 250906 - HOT_POT_ROLE_EAT: 'CommonBuffId' = 249676 - HOT_POT_ROLE_GATHER: 'CommonBuffId' = 249673 - HOT_POT_ROLE_START_COOKING: 'CommonBuffId' = 249674 - HOT_POT_ROLE_WAIT_TO_EAT: 'CommonBuffId' = 249675 - HOT_POT_STARTED_EATING: 'CommonBuffId' = 250893 - HOT_POT_WARM_SIM: 'CommonBuffId' = 250886 - HOVER_LAMP_FOCUSED: 'CommonBuffId' = 109868 - HUMANOID_ROBOTS_BEHAVIOR_MODULES_CHILD_CARE: 'CommonBuffId' = 218995 - HUMANOID_ROBOTS_BEHAVIOR_MODULES_CLEANING: 'CommonBuffId' = 218996 - HUMANOID_ROBOTS_BEHAVIOR_MODULES_FIGHTER: 'CommonBuffId' = 218997 - HUMANOID_ROBOTS_BEHAVIOR_MODULES_GARDENING: 'CommonBuffId' = 218999 - HUMANOID_ROBOTS_BEHAVIOR_MODULES_PARTY: 'CommonBuffId' = 219712 - HUMANOID_ROBOTS_BEHAVIOR_MODULES_REPAIR: 'CommonBuffId' = 218998 - HUMANOID_ROBOTS_BEHAVIOR_MODULES_SECURITY: 'CommonBuffId' = 218994 - HUMANOID_ROBOTS_CREATION_CREATOR_MARKER: 'CommonBuffId' = 221905 - HUMANOID_ROBOTS_ELECTROCUTION_HYPER_CHARGED: 'CommonBuffId' = 223943 - HUMANOID_ROBOTS_ELECTROCUTION_SUPER_CHARGED: 'CommonBuffId' = 223942 - HUMANOID_ROBOTS_ENHANCEMENT_LEVEL_1: 'CommonBuffId' = 219924 - HUMANOID_ROBOTS_ENHANCEMENT_LEVEL_10: 'CommonBuffId' = 219923 - HUMANOID_ROBOTS_ENHANCEMENT_LEVEL_2: 'CommonBuffId' = 219925 - HUMANOID_ROBOTS_ENHANCEMENT_LEVEL_3: 'CommonBuffId' = 219926 - HUMANOID_ROBOTS_ENHANCEMENT_LEVEL_4: 'CommonBuffId' = 219927 - HUMANOID_ROBOTS_ENHANCEMENT_LEVEL_5: 'CommonBuffId' = 219928 - HUMANOID_ROBOTS_ENHANCEMENT_LEVEL_6: 'CommonBuffId' = 219929 - HUMANOID_ROBOTS_ENHANCEMENT_LEVEL_7: 'CommonBuffId' = 219930 - HUMANOID_ROBOTS_ENHANCEMENT_LEVEL_8: 'CommonBuffId' = 219931 - HUMANOID_ROBOTS_ENHANCEMENT_LEVEL_9: 'CommonBuffId' = 219932 - HUMANOID_ROBOTS_FLIRT_WITH_OBJECT: 'CommonBuffId' = 223394 - HUMANOID_ROBOTS_HOVER_MODE_WALK_STYLE: 'CommonBuffId' = 223735 - HUMANOID_ROBOTS_MAIN_BUFF: 'CommonBuffId' = 219638 - HUMANOID_ROBOTS_MOOD_VFX_ANGRY: 'CommonBuffId' = 221879 - HUMANOID_ROBOTS_MOOD_VFX_BORED: 'CommonBuffId' = 221881 - HUMANOID_ROBOTS_MOOD_VFX_CONFIDENT: 'CommonBuffId' = 221882 - HUMANOID_ROBOTS_MOOD_VFX_DAZED: 'CommonBuffId' = 227718 - HUMANOID_ROBOTS_MOOD_VFX_EMBARRASSED: 'CommonBuffId' = 221814 - HUMANOID_ROBOTS_MOOD_VFX_ENERGIZED: 'CommonBuffId' = 221818 - HUMANOID_ROBOTS_MOOD_VFX_FINE: 'CommonBuffId' = 221819 - HUMANOID_ROBOTS_MOOD_VFX_FLIRTY: 'CommonBuffId' = 221883 - HUMANOID_ROBOTS_MOOD_VFX_FOCUSED: 'CommonBuffId' = 221820 - HUMANOID_ROBOTS_MOOD_VFX_HAPPY: 'CommonBuffId' = 220400 - HUMANOID_ROBOTS_MOOD_VFX_INSPIRED: 'CommonBuffId' = 221821 - HUMANOID_ROBOTS_MOOD_VFX_ONTRAVEL: 'CommonBuffId' = 230601 - HUMANOID_ROBOTS_MOOD_VFX_PLAYFUL: 'CommonBuffId' = 221816 - HUMANOID_ROBOTS_MOOD_VFX_SAD: 'CommonBuffId' = 221813 - HUMANOID_ROBOTS_MOOD_VFX_STRESSED: 'CommonBuffId' = 221884 - HUMANOID_ROBOTS_MOOD_VFX_UNCOMFORTABLE: 'CommonBuffId' = 221885 - HUMANOID_ROBOTS_MOTIVES_ALL_MOTIVES_HIGH: 'CommonBuffId' = 230065 - HUMANOID_ROBOTS_MOTIVES_ALL_MOTIVES_PRETTY_HIGH: 'CommonBuffId' = 230067 - HUMANOID_ROBOTS_OUTFIT: 'CommonBuffId' = 218341 - HUMANOID_ROBOTS_OUTFIT_BEIGE_WHITE: 'CommonBuffId' = 227829 - HUMANOID_ROBOTS_OUTFIT_BLACK_BLUE: 'CommonBuffId' = 227830 - HUMANOID_ROBOTS_OUTFIT_GRAY_BROWN: 'CommonBuffId' = 227831 - HUMANOID_ROBOTS_OUTFIT_GREEN_BROWN: 'CommonBuffId' = 227832 - HUMANOID_ROBOTS_OUTFIT_RED_GREEN: 'CommonBuffId' = 227833 - HUMANOID_ROBOTS_OUTFIT_WHITE_COPPER: 'CommonBuffId' = 227834 - HUMANOID_ROBOTS_STOP_ENHANCEMENT: 'CommonBuffId' = 229860 - HUMANOID_ROBOTS_THEY_ARE_PLANNING_SOMETHING: 'CommonBuffId' = 227141 - HUMANOID_ROBOTS_VFX_MINI_BOT_SOCIAL: 'CommonBuffId' = 229243 - ICE_CREAM_CREPE_YOUTH: 'CommonBuffId' = 251499 - ILLUMINATED_BY_STARS: 'CommonBuffId' = 105318 - IMMEDIATELY_PREPARED_FOOD_HIDDEN: 'CommonBuffId' = 170451 - INCREDIBLE_STORYTELLER: 'CommonBuffId' = 108018 - INFANTS_CARRY_BACK_HIDDEN: 'CommonBuffId' = 272014 - INFANTS_PERSONALITY_GASSY_GAS_TROUBLE: 'CommonBuffId' = 286118 - INFANTS_PERSONALITY_GIVE_QUIRKS: 'CommonBuffId' = 336049 - INFANTS_PERSONALITY_GOOD_APPETITE_FULL: 'CommonBuffId' = 334030 - INFANTS_PERSONALITY_HICCUPS_IDLE: 'CommonBuffId' = 286117 - INFANTS_PERSONALITY_OBSESSED_WITH_SOUND: 'CommonBuffId' = 286125 - INFANTS_PERSONALITY_ONLY_SLEEPS_WHEN_HELD: 'CommonBuffId' = 333686 - INFANTS_PERSONALITY_REVEAL_DELAY: 'CommonBuffId' = 333666 - INFANTS_PERSONALITY_SELF_SOOTHED: 'CommonBuffId' = 334066 - INFANTS_PERSONALITY_SELF_SOOTHER: 'CommonBuffId' = 286120 - INFANTS_PERSONALITY_SNEEZE_TRAIT: 'CommonBuffId' = 286119 - INFANTS_PERSONALITY_TALKER_TRAIT: 'CommonBuffId' = 286121 - INFANTS_TYAE_CARRY_BACK_HIDDEN: 'CommonBuffId' = 271983 - INFANT_ANTICIPATION_MOMENTS_WATCH_END: 'CommonBuffId' = 319240 - INFANT_ATTACHMENT_CARED_FOR_GOOD: 'CommonBuffId' = 275644 - INFANT_ATTACHMENT_CARED_FOR_GREAT: 'CommonBuffId' = 319192 - INFANT_ATTACHMENT_IS_ANYONE_THERE: 'CommonBuffId' = 275648 - INFANT_ATTACHMENT_IS_ANYONE_THERE_NEGLECTED: 'CommonBuffId' = 319339 - INFANT_ATTACHMENT_LOVED_GOOD: 'CommonBuffId' = 275646 - INFANT_ATTACHMENT_LOVED_GREAT: 'CommonBuffId' = 319196 - INFANT_ATTACHMENT_LOVE_SHOWN_FINE: 'CommonBuffId' = 275645 - INFANT_ATTACHMENT_LOVE_SHOWN_NEGLECTED: 'CommonBuffId' = 319194 - INFANT_ATTACHMENT_MOTIVE_DISTRESS: 'CommonBuffId' = 275468 - INFANT_ATTACHMENT_NEEDS_HELP_FINE: 'CommonBuffId' = 275647 - INFANT_ATTACHMENT_NEEDS_HELP_NEGLECTED: 'CommonBuffId' = 319200 - INFANT_ATTACHMENT_NEEDS_MET_FINE: 'CommonBuffId' = 275643 - INFANT_ATTACHMENT_NEEDS_MET_NEGLECTED: 'CommonBuffId' = 319190 - INFANT_AUTO_AGE_UP_TEST: 'CommonBuffId' = 322790 - INFANT_AWAKE_TIME: 'CommonBuffId' = 327515 - INFANT_BABY_BOP: 'CommonBuffId' = 317598 - INFANT_BABY_FEED_CRAVING_NEW_FLAVOR: 'CommonBuffId' = 305360 - INFANT_BEING_BREAST_FED: 'CommonBuffId' = 333766 - INFANT_BEING_LET_OUT: 'CommonBuffId' = 326995 - INFANT_BGO_MESMERIZED: 'CommonBuffId' = 277355 - INFANT_CANT_BE_CONTAINED: 'CommonBuffId' = 282585 - INFANT_CANT_REACH_ANGRY: 'CommonBuffId' = 321037 - INFANT_CANT_REACH_SAD: 'CommonBuffId' = 321043 - INFANT_CAREGIVER_ACTIVE: 'CommonBuffId' = 281020 - INFANT_CAREGIVER_PASSIVE: 'CommonBuffId' = 281019 - INFANT_CAREGIVER_TIME_ALONE_SHOW_CONCERN: 'CommonBuffId' = 282866 - INFANT_CARRY_COOLDOWN: 'CommonBuffId' = 276020 - INFANT_CARRY_GIVE_CARRIED_SIM_HIDDEN_TARGET: 'CommonBuffId' = 335678 - INFANT_CARRY_PROTECT_CARRY: 'CommonBuffId' = 333166 - INFANT_CARRY_RESPONSE_ANGRY_CARRY: 'CommonBuffId' = 275847 - INFANT_CARRY_RESPONSE_ANGRY_CARRY_BACK: 'CommonBuffId' = 275848 - INFANT_CARRY_RESPONSE_ANGRY_PUT_DOWN: 'CommonBuffId' = 275841 - INFANT_CARRY_RESPONSE_HAPPY_CARRY: 'CommonBuffId' = 275840 - INFANT_CARRY_RESPONSE_HAPPY_CARRY_BACK: 'CommonBuffId' = 275849 - INFANT_CARRY_RESPONSE_HAPPY_PUT_DOWN: 'CommonBuffId' = 275850 - INFANT_CARRY_RESPONSE_SAD_CARRY: 'CommonBuffId' = 275839 - INFANT_CARRY_RESPONSE_SAD_CARRY_BACK: 'CommonBuffId' = 275853 - INFANT_CARRY_RESPONSE_SAD_PUT_DOWN: 'CommonBuffId' = 275851 - INFANT_CARRY_RIGHT_HIDDEN: 'CommonBuffId' = 276004 - INFANT_CHECK_ON_CLASH_PREVENTION: 'CommonBuffId' = 335346 - INFANT_CHECK_ON_NOT_CHECKED_SHOW_CONCERN: 'CommonBuffId' = 283485 - INFANT_CHOMP_COOLDOWN: 'CommonBuffId' = 339336 - INFANT_CRAWLING_LEVEL_ONE: 'CommonBuffId' = 309450 - INFANT_CRAWLING_LEVEL_TWO: 'CommonBuffId' = 309449 - INFANT_CRAWLING_ON_THE_MOVE: 'CommonBuffId' = 280971 - INFANT_CRAWLING_ROUTE_EVENT_REACT_SHOCKED: 'CommonBuffId' = 310631 - INFANT_CRAWLING_ROUTE_EVENT_TIMER: 'CommonBuffId' = 323346 - INFANT_CRYING_BABY: 'CommonBuffId' = 316000 - INFANT_CRYING_BABY_HATES_CHILDREN: 'CommonBuffId' = 316002 - INFANT_CRYING_INFANT: 'CommonBuffId' = 276062 - INFANT_CRY_REACTION: 'CommonBuffId' = 324066 - INFANT_CRY_REACTION_COOLDOWN: 'CommonBuffId' = 324067 - INFANT_DIAPER_RASH: 'CommonBuffId' = 275886 - INFANT_FRESHLY_DIAPERED: 'CommonBuffId' = 311691 - INFANT_HIDDEN_DIAPER_OVER_FULL: 'CommonBuffId' = 329250 - INFANT_HIDDEN_DIAPER_PARTIAL_FULL: 'CommonBuffId' = 329248 - INFANT_HIDDEN_STINKY_DIAPER_ACTOR: 'CommonBuffId' = 309713 - INFANT_HIGH_CHAIR_ALREADY_FED_FIRST_BITE: 'CommonBuffId' = 334560 - INFANT_HIGH_CHAIR_BETRAYED: 'CommonBuffId' = 283945 - INFANT_HIGH_CHAIR_FOOD_BOREDOM: 'CommonBuffId' = 283944 - INFANT_HIGH_CHAIR_LAST_FOOD_EATEN_APPLESAUCE: 'CommonBuffId' = 307631 - INFANT_HIGH_CHAIR_LAST_FOOD_EATEN_BANANA_SLICES: 'CommonBuffId' = 307639 - INFANT_HIGH_CHAIR_LAST_FOOD_EATEN_CRUSHED_CARROTS: 'CommonBuffId' = 307632 - INFANT_HIGH_CHAIR_LAST_FOOD_EATEN_HOMEMADE_HUMMUS: 'CommonBuffId' = 307643 - INFANT_HIGH_CHAIR_LAST_FOOD_EATEN_ICE_CREAM: 'CommonBuffId' = 307635 - INFANT_HIGH_CHAIR_LAST_FOOD_EATEN_MASHED_MANGO: 'CommonBuffId' = 307644 - INFANT_HIGH_CHAIR_LAST_FOOD_EATEN_MASHED_PEAS: 'CommonBuffId' = 307647 - INFANT_HIGH_CHAIR_LAST_FOOD_EATEN_OATMEAL_CEREAL: 'CommonBuffId' = 307641 - INFANT_HIGH_CHAIR_LAST_FOOD_EATEN_OATY_OS: 'CommonBuffId' = 307636 - INFANT_HIGH_CHAIR_LAST_FOOD_EATEN_PAPAYA_PASTE: 'CommonBuffId' = 307646 - INFANT_HIGH_CHAIR_LAST_FOOD_EATEN_PEANUT_BUTTER_PUFFS: 'CommonBuffId' = 307638 - INFANT_HIGH_CHAIR_LAST_FOOD_EATEN_PUMPKIN_PUREE: 'CommonBuffId' = 307633 - INFANT_HIGH_CHAIR_LAST_FOOD_EATEN_RICE_PORRIDGE: 'CommonBuffId' = 307640 - INFANT_HIGH_CHAIR_LAST_FOOD_EATEN_SMASHED_AVOCADO: 'CommonBuffId' = 307645 - INFANT_HIGH_CHAIR_LAST_FOOD_EATEN_SMASHED_LEMON: 'CommonBuffId' = 307634 - INFANT_HIGH_CHAIR_LAST_FOOD_EATEN_SWEET_POTATO_PUREE: 'CommonBuffId' = 307642 - INFANT_HIGH_CHAIR_LAST_FOOD_EATEN_YOGURT: 'CommonBuffId' = 307630 - INFANT_HIGH_CHAIR_LAST_FOOD_EATEN_YOGURT_MELTS: 'CommonBuffId' = 307637 - INFANT_HIGH_CHAIR_YUMMY: 'CommonBuffId' = 283943 - INFANT_INVITED_OVER: 'CommonBuffId' = 320281 - INFANT_IN_SPECIAL_MULTI_SIM: 'CommonBuffId' = 335989 - INFANT_IS_BEING_CARED_FOR: 'CommonBuffId' = 335779 - INFANT_LOUD_NOISE_NOISY_NEIGHBOR_HIDDEN: 'CommonBuffId' = 321698 - INFANT_LOUSY_LOCKPICKER: 'CommonBuffId' = 282608 - INFANT_MILESTONE_ANTICIPATION_MOMENT_ALLOW_SIT: 'CommonBuffId' = 332429 - INFANT_MILESTONE_ANTICIPATION_MOMENT_BIG: 'CommonBuffId' = 327859 - INFANT_MILESTONE_ANTICIPATION_MOMENT_JUST_GRABBED: 'CommonBuffId' = 327168 - INFANT_MILESTONE_ANTICIPATION_MOMENT_JUST_REACHED: 'CommonBuffId' = 327169 - INFANT_MILESTONE_ANTICIPATION_MOMENT_SMALL: 'CommonBuffId' = 327858 - INFANT_MILESTONE_BLOCK_ANTICIPATION_PUSHER: 'CommonBuffId' = 335142 - INFANT_MILESTONE_CAN_CRAWL: 'CommonBuffId' = 322738 - INFANT_MILESTONE_CELEBRATE_MY_PRIDE_AND_JOY: 'CommonBuffId' = 319246 - INFANT_MILESTONE_CELEBRATE_OUTSHINED: 'CommonBuffId' = 319247 - INFANT_MILESTONE_CELEBRATE_PUSH_BRAG_COOLDOWN: 'CommonBuffId' = 324374 - INFANT_MILESTONE_MAIN: 'CommonBuffId' = 287573 - INFANT_MILESTONE_NOT_SITTING_UP: 'CommonBuffId' = 288538 - INFANT_MILESTONE_RECENT_UNLOCK: 'CommonBuffId' = 328806 - INFANT_MILESTONE_SIT_UP: 'CommonBuffId' = 287574 - INFANT_MILESTONE_SLEPT_THROUGH_NIGHT: 'CommonBuffId' = 331333 - INFANT_MILESTONE_UNLOCK_TRIGGER: 'CommonBuffId' = 320410 - INFANT_MOTIVE_OVERRIDE_ENERGY_ANGRY: 'CommonBuffId' = 279868 - INFANT_MOTIVE_OVERRIDE_ENERGY_SAD: 'CommonBuffId' = 275519 - INFANT_MOTIVE_OVERRIDE_ENERGY_VERY_ANGRY: 'CommonBuffId' = 279869 - INFANT_MOTIVE_OVERRIDE_ENERGY_VERY_SAD: 'CommonBuffId' = 275520 - INFANT_MOTIVE_OVERRIDE_FUN_ANGRY: 'CommonBuffId' = 275522 - INFANT_MOTIVE_OVERRIDE_FUN_SAD: 'CommonBuffId' = 279865 - INFANT_MOTIVE_OVERRIDE_FUN_VERY_ANGRY: 'CommonBuffId' = 275523 - INFANT_MOTIVE_OVERRIDE_FUN_VERY_SAD: 'CommonBuffId' = 279866 - INFANT_MOTIVE_OVERRIDE_HUNGER_ANGRY: 'CommonBuffId' = 275489 - INFANT_MOTIVE_OVERRIDE_HUNGER_SAD: 'CommonBuffId' = 279863 - INFANT_MOTIVE_OVERRIDE_HUNGER_VERY_ANGRY: 'CommonBuffId' = 275491 - INFANT_MOTIVE_OVERRIDE_HUNGER_VERY_SAD: 'CommonBuffId' = 279864 - INFANT_MOTIVE_OVERRIDE_HYGIENE_ANGRY: 'CommonBuffId' = 317664 - INFANT_MOTIVE_OVERRIDE_HYGIENE_SAD: 'CommonBuffId' = 279861 - INFANT_MOTIVE_OVERRIDE_HYGIENE_VERY_ANGRY: 'CommonBuffId' = 317665 - INFANT_MOTIVE_OVERRIDE_HYGIENE_VERY_SAD: 'CommonBuffId' = 279862 - INFANT_NANNY_CHECK_ON_COOLDOWN: 'CommonBuffId' = 330803 - INFANT_PEEKABOO_AUTONOMOUS_COOLDOWN: 'CommonBuffId' = 333241 - INFANT_PLAY_BABY_LAUGH: 'CommonBuffId' = 279257 - INFANT_PLAY_MAT_HIDDEN_PLAY_WITH_TRACKER: 'CommonBuffId' = 334481 - INFANT_PLAY_MAT_JUST_STOPPED_INTERACTION: 'CommonBuffId' = 332297 - INFANT_PLAY_SQUISHY_AND_COLD: 'CommonBuffId' = 322089 - INFANT_PLAY_THAT_WAS_CUTE: 'CommonBuffId' = 279256 - INFANT_PLAY_WATER_BABY: 'CommonBuffId' = 322399 - INFANT_PLAY_WIBBLE_WOBBLE: 'CommonBuffId' = 279258 - INFANT_PRE_SLEEP_HIDDEN_BED_TIME_STORY: 'CommonBuffId' = 279904 - INFANT_PRE_SLEEP_HIDDEN_LULLED_TO_SLEEP: 'CommonBuffId' = 279905 - INFANT_PRE_SLEEP_HIDDEN_SOOTHED_TO_SLEEP: 'CommonBuffId' = 279906 - INFANT_REACTION_ANGRY: 'CommonBuffId' = 334370 - INFANT_REACTION_COOLDOWN: 'CommonBuffId' = 333196 - INFANT_REACTION_HAPPY: 'CommonBuffId' = 334371 - INFANT_REACTION_SAD: 'CommonBuffId' = 334372 - INFANT_REWARD_TRAIT_HAPPY: 'CommonBuffId' = 320153 - INFANT_REWARD_TRAIT_TOP_NOTCH: 'CommonBuffId' = 320150 - INFANT_REWARD_TRAIT_UNHAPPY: 'CommonBuffId' = 320154 - INFANT_RILED_UP: 'CommonBuffId' = 287903 - INFANT_RUDE_AWAKENING: 'CommonBuffId' = 276334 - INFANT_SIM_SOCIAL_BABYLESS_BLISS: 'CommonBuffId' = 286217 - INFANT_SIM_SOCIAL_BABY_WORRY: 'CommonBuffId' = 286216 - INFANT_SIM_SOCIAL_CUTE_BABY: 'CommonBuffId' = 274949 - INFANT_SIM_SOCIAL_JEALOUS: 'CommonBuffId' = 286345 - INFANT_SIM_SOCIAL_PARENTAL_PRESSURE: 'CommonBuffId' = 286218 - INFANT_SIM_SOCIAL_PROUD: 'CommonBuffId' = 286343 - INFANT_SIM_SOCIAL_SWEET_SIBLINGS: 'CommonBuffId' = 286414 - INFANT_SIM_SOCIAL_UGH_BABIES: 'CommonBuffId' = 274950 - INFANT_SLEEP_AWAKE_ANGRY: 'CommonBuffId' = 275451 - INFANT_SLEEP_AWAKE_HAPPY: 'CommonBuffId' = 275452 - INFANT_SLEEP_AWAKE_SAD: 'CommonBuffId' = 275450 - INFANT_SLEEP_BED_TIME_STORY: 'CommonBuffId' = 275453 - INFANT_SLEEP_HIDDEN_AWAKE_BUFFS_ALLOWED: 'CommonBuffId' = 329251 - INFANT_SLEEP_HIDDEN_MOTIVE_ADJUST: 'CommonBuffId' = 331278 - INFANT_SLEEP_HIDDEN_SLEEP_TIME_DONE: 'CommonBuffId' = 275624 - INFANT_SLEEP_LULLED_TO_SLEEP: 'CommonBuffId' = 275518 - INFANT_SLEEP_SOOTHED: 'CommonBuffId' = 334368 - INFANT_SLEEP_SOOTHED_TO_SLEEP: 'CommonBuffId' = 275445 - INFANT_SOCIAL_BOUNCE: 'CommonBuffId' = 283572 - INFANT_SOCIAL_OUCH: 'CommonBuffId' = 282668 - INFANT_SOCIAL_WERE_THOSE_FANGS: 'CommonBuffId' = 282669 - INFANT_STINKY_DIAPER_TARGET: 'CommonBuffId' = 305678 - INFANT_STOP_CRY: 'CommonBuffId' = 332110 - INFANT_STUCK_ANGRY: 'CommonBuffId' = 321036 - INFANT_STUCK_SAD: 'CommonBuffId' = 321041 - INFANT_TINY_DANCER: 'CommonBuffId' = 317597 - INFANT_TOP_NOTCH: 'CommonBuffId' = 275659 - INFANT_TRAIT_CALM: 'CommonBuffId' = 277619 - INFANT_TRAIT_CALM_BOREDOM_EXIT: 'CommonBuffId' = 334661 - INFANT_TRAIT_CALM_MOVE_COOLDOWN: 'CommonBuffId' = 335335 - INFANT_TRAIT_CAUTIOUS: 'CommonBuffId' = 284563 - INFANT_TRAIT_CAUTIOUS_CAREGIVER_PROXIMITY: 'CommonBuffId' = 334601 - INFANT_TRAIT_CAUTIOUS_FAMILIAR_SPACE: 'CommonBuffId' = 284558 - INFANT_TRAIT_CAUTIOUS_NEED_FAMILIAR_FACE: 'CommonBuffId' = 284556 - INFANT_TRAIT_CAUTIOUS_PROXIMITY_BROADCASTER: 'CommonBuffId' = 334608 - INFANT_TRAIT_CAUTIOUS_PUT_DOWN: 'CommonBuffId' = 284698 - INFANT_TRAIT_CAUTIOUS_SAFE: 'CommonBuffId' = 284582 - INFANT_TRAIT_CAUTIOUS_STRANGE_PLACE: 'CommonBuffId' = 284557 - INFANT_TRAIT_CAUTIOUS_STRANGE_PLACE_HIDDEN: 'CommonBuffId' = 334606 - INFANT_TRAIT_GASSY_RELEASED: 'CommonBuffId' = 288901 - INFANT_TRAIT_HOME_CHECK: 'CommonBuffId' = 284572 - INFANT_TRAIT_INTENSE: 'CommonBuffId' = 287895 - INFANT_TRAIT_INTENSE_REFUSE_EATING: 'CommonBuffId' = 287901 - INFANT_TRAIT_SENSITIVE_OVERSTIMULATED: 'CommonBuffId' = 275857 - INFANT_TRAIT_SUNNY: 'CommonBuffId' = 277824 - INFANT_TRAIT_WIGGLY: 'CommonBuffId' = 275837 - INFANT_TRAIT_WIGGLY_TIME_FOR_WIGGLES: 'CommonBuffId' = 275843 - INFANT_TUMMY_TIME_SOMEONE_JOINED: 'CommonBuffId' = 319754 - INFANT_UGH_INFANTS: 'CommonBuffId' = 333378 - INFANT_WIGGLE_TO_MUSIC_COOLDOWN: 'CommonBuffId' = 335336 - INFANT_WONT_STOP_CRYING: 'CommonBuffId' = 276064 - INFATUATING_SCENT: 'CommonBuffId' = 118495 - INFECTED_PLANT_ATTACKS_BOTANOPHOBIA: 'CommonBuffId' = 203660 - INFECTED_PLANT_ATTACKS_HIDDEN_ATTACK_COOLDOWN: 'CommonBuffId' = 206540 - INFECTED_PLANT_ATTACKS_HIDDEN_REACT_COOLDOWN: 'CommonBuffId' = 207455 - INFECTED_PLANT_ATTACKS_RECENTLY_MOCKED_PLANT: 'CommonBuffId' = 202514 - INFECTION_CURE_TEMP_INFECTION_IMMUNITY: 'CommonBuffId' = 204249 - INFECTION_SCANNER_FIGHT_SCANNING_SIM: 'CommonBuffId' = 207198 - INFECTION_SCANNER_TRIGGERED_POSSESSION: 'CommonBuffId' = 207194 - INFLUENTIAL_INDIVIDUAL_CHEER: 'CommonBuffId' = 232560 - INFLUENTIAL_INDIVIDUAL_SHUN: 'CommonBuffId' = 232481 - INSECTS_BUG_BITE: 'CommonBuffId' = 102983 - INSECTS_ICKY_BUG: 'CommonBuffId' = 102986 - INSECTS_STINK_BUG: 'CommonBuffId' = 102984 - INSECT_FARM_BEETLE_BURNS: 'CommonBuffId' = 237703 - INSIGHTFUL_MEDITATION: 'CommonBuffId' = 119058 - INSIGHTFUL_MEDITATION_INCENSE: 'CommonBuffId' = 120175 - INSPIRATIONAL_MORAL: 'CommonBuffId' = 108024 - INSPIRATIONAL_MORAL_GREAT_STORYTELLER: 'CommonBuffId' = 109743 - INSPIRATIONAL_SCENT: 'CommonBuffId' = 118496 - INSPIRED_BY_NATURE: 'CommonBuffId' = 108251 - INSPIRED_BY_NATURE_LOVES_OUTDOORS: 'CommonBuffId' = 108258 - INSPIRED_BY_POTION: 'CommonBuffId' = 26334 - INSPIRED_SAW_SOME_STARS: 'CommonBuffId' = 31630 - INSPIRED_STARRY_NIGHT: 'CommonBuffId' = 31632 - INSPIRED_WRITING_ENTHUSED: 'CommonBuffId' = 26700 - INSPIRING_CHILD_STORY: 'CommonBuffId' = 31122 - INSTILLED_CONFIDENCE: 'CommonBuffId' = 26690 - INSTRUMENT_PLAYING_BADLY: 'CommonBuffId' = 38906 - INTENSE_WEATHER_SLIPPING_ON_THIN_ICE: 'CommonBuffId' = 247636 - INTERACTABLE_CAVE_BEASTLY_LAUGHTER: 'CommonBuffId' = 249444 - INTERACTABLE_CAVE_GREAT_RANTINGS: 'CommonBuffId' = 249450 - INTERACTABLE_CAVE_IM_GROWLIN_HERE: 'CommonBuffId' = 249445 - INTERACTABLE_CAVE_LUCKY_SIMOLEON: 'CommonBuffId' = 249453 - INTERACTABLE_CAVE_MAD_RANTINGS: 'CommonBuffId' = 249449 - INTERACTABLE_CAVE_MONSTROUS_LOGIC: 'CommonBuffId' = 249446 - INTERACTABLE_CAVE_SERIOUSLY: 'CommonBuffId' = 249448 - INTERACTABLE_CAVE_SPIRIT_DANCE: 'CommonBuffId' = 249447 - INTERACTABLE_CAVE_THAT_WONT_BE_ME: 'CommonBuffId' = 249451 - INTERACTABLE_CAVE_THOSE_WHO_CAME_BEFORE: 'CommonBuffId' = 249452 - INTERACTABLE_STATUE_LASER_FOCUS: 'CommonBuffId' = 224542 - INTERACTABLE_STATUE_NPC_OFFERING_COOLDOWN: 'CommonBuffId' = 224637 - INTERACTABLE_STATUE_PLACEBO: 'CommonBuffId' = 224541 - INTERACTABLE_STATUE_SURREAL_FOCUS: 'CommonBuffId' = 224523 - INTERROGATION_TABLE_MOOD_CONTROL_CALM: 'CommonBuffId' = 104575 - INTERROGATION_TABLE_MOOD_CONTROL_DEFENSIVE: 'CommonBuffId' = 104576 - INTERROGATION_TABLE_MOOD_CONTROL_FRIENDLY: 'CommonBuffId' = 104583 - INTERROGATION_TABLE_MOOD_CONTROL_FURIOUS: 'CommonBuffId' = 104577 - INTERROGATION_TABLE_MOOD_CONTROL_SHY: 'CommonBuffId' = 104578 - INTERROGATION_TABLE_MOOD_CONTROL_SMUG: 'CommonBuffId' = 104579 - INTERROGATION_TABLE_MOOD_CONTROL_SUSPICIOUS: 'CommonBuffId' = 104580 - INTERROGATION_TABLE_MOOD_CONTROL_TENSE: 'CommonBuffId' = 104598 - INTERROGATION_TABLE_MOOD_CONTROL_TERRIFIED: 'CommonBuffId' = 104582 - INTERROGATION_TABLE_MOOD_CONTROL_WORRIED: 'CommonBuffId' = 104581 - INTERROGATION_TABLE_RESULTS_INTERROGATION_FAILURE: 'CommonBuffId' = 106733 - INTERROGATION_TABLE_RESULTS_INTERROGATION_SUCCESS: 'CommonBuffId' = 106732 - INVALID: 'CommonBuffId' = 0 - INVESTIGATION_SYSTEM_ARCHIVE_EVIDENCE_COOLDOWN: 'CommonBuffId' = 205555 - INVESTIGATION_SYSTEM_CRAFT_SPORE_FILTER_COOLDOWN: 'CommonBuffId' = 207381 - INVESTIGATION_SYSTEM_KEY_CARD_MILITARY_REQUISITION_COOLDOWN: 'CommonBuffId' = 207586 - INVESTIGATION_SYSTEM_MILITARY_WALK_BY_WALK_STYLE_OVERRIDE_NORMAL: 'CommonBuffId' = 207068 - INVESTIGATION_SYSTEM_MILITARY_WALK_BY_WALK_STYLE_OVERRIDE_TOUGH: 'CommonBuffId' = 207069 - INVESTIGATION_SYSTEM_STOP_IMPRESS_WITH_PHYSICAL_PROWESS_SUCCESS: 'CommonBuffId' = 204066 - INVESTIGATION_SYSTEM_STOP_IMPRESS_W_ITH_PHYSICAL_PROWESS_FAILURE: 'CommonBuffId' = 204085 - INVIGORATED_BY_NATURE: 'CommonBuffId' = 108252 - INVIGORATED_BY_NATURE_LOVES_OUTDOORS: 'CommonBuffId' = 108260 - IN_DEBT: 'CommonBuffId' = 226857 - IN_REGION_BATUU: 'CommonBuffId' = 237013 - IN_REGION_BATUU_PLAYER: 'CommonBuffId' = 245146 - IN_RELATIONSHIP: 'CommonBuffId' = 374159 - IRRESPONSIBLE_IGNORE_BILLS: 'CommonBuffId' = 163657 - ISLANDER_CULTURE_EXTRA_FOOD_COMPLETE_OBJECTIVE: 'CommonBuffId' = 209313 - ISLANDER_CULTURE_FIRE_BRIGADE_NEIGHBOR_SAVED_ME: 'CommonBuffId' = 209214 - ISLANDER_CULTURE_NEIGHBORS_HELPED_THROUGH_THE_LOSS: 'CommonBuffId' = 208671 - ISLANDER_CULTURE_ROLE_NEED_SOMETHING_FIXED_REPAIR: 'CommonBuffId' = 210643 - ISLANDER_CULTURE_ROLE_NEED_SOMETHING_FIXED_WAITING: 'CommonBuffId' = 210662 - ISLANDER_CULTURE_ROLE_VISITOR_DEATH_COMFORT: 'CommonBuffId' = 208638 - ISLANDER_CULTURE_TRAIT_ISLANDER: 'CommonBuffId' = 209324 - ISLAND_CANOE_FLOWER_SAIL: 'CommonBuffId' = 209114 - ISLAND_CANOE_SAIL_AWAY: 'CommonBuffId' = 209108 - ISLAND_CONSERVATION_AUTONOMY_BUFFS_NPC_ANTI_ENVIRONMENTALIST: 'CommonBuffId' = 208869 - ISLAND_CONSERVATION_AUTONOMY_BUFFS_NPC_LITTERING_SIM: 'CommonBuffId' = 208868 - ISLAND_CONSERVATION_AUTONOMY_BUFFS_NPC_POACHING_SIM: 'CommonBuffId' = 208867 - ISLAND_CONSERVATION_AUTONOMY_MOD_TURTLE_HATCHING_GENERAL: 'CommonBuffId' = 205466 - ISLAND_CONSERVATION_BUFFS_DIDNT_LISTEN: 'CommonBuffId' = 209458 - ISLAND_CONSERVATION_BUFFS_MAKING_A_DIFFERENCE: 'CommonBuffId' = 209475 - ISLAND_CONSERVATION_BUFFS_MAKING_A_DIFFERENCE_VFX: 'CommonBuffId' = 212655 - ISLAND_CONSERVATION_BUFFS_OUCH: 'CommonBuffId' = 210469 - ISLAND_CONSERVATION_BUFFS_STINKY_PILE: 'CommonBuffId' = 210493 - ISLAND_CONSERVATION_BUFFS_TAMING_VOLCANO: 'CommonBuffId' = 210470 - ISLAND_EVENTS_AUTONOMY_MOD_TURTLE_HATCHING_CONSERVATIONIST: 'CommonBuffId' = 210347 - ISLAND_EVENTS_BEACH_BONFIRE_AUTONOMY_MOD: 'CommonBuffId' = 211686 - ISLAND_EVENTS_FAMILY_FUN_AUTONOMY_MOD_CHILD: 'CommonBuffId' = 209542 - ISLAND_EVENTS_FAMILY_FUN_AUTONOMY_MOD_PARENT: 'CommonBuffId' = 209535 - ISLAND_EVENTS_FAMILY_FUN_AUTONOMY_MOD_VENDOR: 'CommonBuffId' = 209543 - ISLAND_EVENTS_FISHING_COMPETITION_AUTONOMY_MOD_ANNOUNCE_WINNER: 'CommonBuffId' = 208367 - ISLAND_EVENTS_FISHING_COMPETITION_AUTONOMY_MOD_VENDOR: 'CommonBuffId' = 208366 - ISLAND_EVENTS_FISHING_COMPETITION_DONE_FISHING: 'CommonBuffId' = 208336 - ISLAND_EVENTS_ISLAND_CELEBRATION_AUTONOMY_MOD_BONFIRE_FIRE_DANCE: 'CommonBuffId' = 208294 - ISLAND_EVENTS_ISLAND_CELEBRATION_AUTONOMY_MOD_CREATE_OBJECTON_TABLE: 'CommonBuffId' = 208289 - ISLAND_EVENTS_ISLAND_CELEBRATION_AUTONOMY_MOD_VENDOR: 'CommonBuffId' = 211343 - ISLAND_EVENTS_ISLAND_CELEBRATION_CONSTRAINED: 'CommonBuffId' = 212365 - ISLAND_EVENTS_PART_OF_THE_COMMUNITY: 'CommonBuffId' = 210659 - ISLAND_EVENTS_POTLUCK_AUTONOMY_MOD: 'CommonBuffId' = 209537 - ISLAND_EVENTS_TOWN_BBQ_AUTONOMY_MOD_GRAB_KAVA: 'CommonBuffId' = 212080 - ISLAND_EVENTS_TOWN_BBQ_AUTONOMY_MOD_HANG_OUT_PIT_BBQ: 'CommonBuffId' = 212467 - ISLAND_EVENTS_TOWN_BBQ_AUTONOMY_MOD_MAKE_KAVA: 'CommonBuffId' = 212077 - ISLAND_EVENTS_TOWN_BBQ_AUTONOMY_MOD_USE_PIT_BBQ: 'CommonBuffId' = 212055 - ISLAND_EVENTS_TURTLE_HATCHING_ENTHUSE_ABOUT_BABY_TURTLES: 'CommonBuffId' = 215934 - ISLAND_WATERFALL_ALL_NATURAL_SHOWER: 'CommonBuffId' = 207412 - ISLAND_WATERFALL_ATTRACT_FROGS_HIDDEN: 'CommonBuffId' = 207427 - ISLAND_WATERFALL_CATCH_FROGS_COOLDOWN_HIDDEN: 'CommonBuffId' = 207426 - ISLAND_WATERFALL_EYES_WATCHING: 'CommonBuffId' = 207411 - ISLAND_WATERFALL_SPOTTED_IN_THE_OPEN: 'CommonBuffId' = 207414 - ISLAND_WATERFALL_WATERFALL_ESCAPADES: 'CommonBuffId' = 207410 - ISLAND_WATERFALL_WATERFALL_FROLIC: 'CommonBuffId' = 207418 - IS_BEAR_BG: 'CommonBuffId' = 153741 - IS_DANCING: 'CommonBuffId' = 156894 - IS_FLOATING_HIDDEN: 'CommonBuffId' = 119069 - IS_KNIGHT: 'CommonBuffId' = 129890 - IS_OWNED_PET: 'CommonBuffId' = 221056 - IS_RUNNING_MICROPHONE_SUPER_NOT_VISIBLE: 'CommonBuffId' = 39717 - IS_WADING: 'CommonBuffId' = 207673 - IS_WEARING_TOWEL: 'CommonBuffId' = 119404 - JEALOUSY_CAUGHT_CHEATING: 'CommonBuffId' = 76385 - JEALOUSY_CAUGHT_CHEATING_FIANCE: 'CommonBuffId' = 394371 - JEALOUSY_CAUGHT_WITH_ANOTHER: 'CommonBuffId' = 76384 - JEALOUSY_CHEATER: 'CommonBuffId' = 129283 - JEALOUSY_CHEATING_DISCOVERED: 'CommonBuffId' = 76387 - JEALOUSY_COMPERSION: 'CommonBuffId' = 362338 - JEALOUSY_DOOMED_RELATIONSHIP: 'CommonBuffId' = 76388 - JEALOUSY_DRIFTING_LOVE: 'CommonBuffId' = 76375 - JEALOUSY_ENEMY_WITH_BENEFITS: 'CommonBuffId' = 76378 - JEALOUSY_EVEN_MORE_AWKWARD: 'CommonBuffId' = 76567 - JEALOUSY_FLIRTY_FIANCE: 'CommonBuffId' = 394372 - JEALOUSY_FLIRTY_SPOUSE: 'CommonBuffId' = 76376 - JEALOUSY_FREEZE_MISSING_SO_TIMER: 'CommonBuffId' = 259618 - JEALOUSY_HIDDEN_WITNESSED_CHEATING: 'CommonBuffId' = 129281 - JEALOUSY_LOVE_INTEREST: 'CommonBuffId' = 76374 - JEALOUSY_TRUE_ENEMY: 'CommonBuffId' = 76559 - JEALOUSY_UNFAITHFUL_LOVE: 'CommonBuffId' = 76574 - JEALOUSY_UNINTERESTED_SOUL_MATE: 'CommonBuffId' = 76377 - JEALOUSY_UPDATES_EVERYTHING_IS_FINE: 'CommonBuffId' = 368349 - JEALOUSY_UPDATES_FILLED_WITH_REGRET: 'CommonBuffId' = 368919 - JEALOUSY_UPDATES_STILL_FEELS_WRONG: 'CommonBuffId' = 368231 - JEALOUSY_UPDATES_THAT_FELT_GOOD: 'CommonBuffId' = 368918 - JEALOUSY_WOO_HOO_INTERRUPTURE: 'CommonBuffId' = 125709 - JEALOUS_LOVED_ONE: 'CommonBuffId' = 12456 - JEALOUS_LOVED_ONE_GLOOMY: 'CommonBuffId' = 36956 - JOB_LOSS_CONSOLE_COOLDOWN: 'CommonBuffId' = 308844 - JOB_LOSS_LAY_OFF_ASSURED_OF_NEW_JOB: 'CommonBuffId' = 311100 - JOB_LOSS_LAY_OFF_BETWEEN_JOBS: 'CommonBuffId' = 307297 - JOB_LOSS_LAY_OFF_CHANCE: 'CommonBuffId' = 306067 - JOB_LOSS_LAY_OFF_COOLDOWN: 'CommonBuffId' = 306066 - JOB_LOSS_LAY_OFF_DEVASTATING: 'CommonBuffId' = 307295 - JOB_LOSS_LAY_OFF_EXPIRED: 'CommonBuffId' = 315653 - JOB_LOSS_LAY_OFF_LOOMING: 'CommonBuffId' = 306346 - JOB_LOSS_LAY_OFF_NEVER_NEEDED_THIS_JOB: 'CommonBuffId' = 307296 - JOB_LOSS_LAY_OFF_PITY_PIZZA: 'CommonBuffId' = 308584 - JOB_LOSS_LAY_OFF_PROMISING_PIZZA: 'CommonBuffId' = 308585 - JOB_LOSS_LAY_OFF_SLACK_OFF_BOOST: 'CommonBuffId' = 306500 - JOB_LOSS_LAY_OFF_WORK_HARDER_BOOST: 'CommonBuffId' = 306501 - JOB_LOSS_LOOKING_FOR_WORK_POST_COOLDOWN: 'CommonBuffId' = 308845 - JOB_LOSS_RECENTLY_LOST_JOB: 'CommonBuffId' = 307761 - JOURNAL_ANGRY: 'CommonBuffId' = 160146 - JOURNAL_ANGRY_ENTRY: 'CommonBuffId' = 160176 - JOURNAL_CONFIDENT: 'CommonBuffId' = 160149 - JOURNAL_EMBARRASSED: 'CommonBuffId' = 160151 - JOURNAL_EMBARRASSED_ENTRY: 'CommonBuffId' = 160174 - JOURNAL_HAPPY: 'CommonBuffId' = 160150 - JOURNAL_INSPIRED: 'CommonBuffId' = 160148 - JOURNAL_JOURNAL_BEING_SNOOPED: 'CommonBuffId' = 167847 - JOURNAL_NORMAL_ENTRY: 'CommonBuffId' = 160169 - JOURNAL_SAD: 'CommonBuffId' = 160152 - JOURNAL_SAD_ENTRY: 'CommonBuffId' = 160175 - JOURNAL_SNOOPING_CONFIDENT: 'CommonBuffId' = 160258 - JOURNAL_SNOOPING_EMBARRASSED: 'CommonBuffId' = 160257 - JOURNAL_STRESSED_ENTRY: 'CommonBuffId' = 160172 - JUICE_FIZZER_DRINK_EFFECTS_JUICE_AND_SELTZER_CONFIDENT_1: 'CommonBuffId' = 236417 - JUICE_FIZZER_DRINK_EFFECTS_JUICE_AND_SELTZER_CONFIDENT_3: 'CommonBuffId' = 236418 - JUICE_FIZZER_DRINK_EFFECTS_JUICE_AND_SELTZER_CONFIDENT_6: 'CommonBuffId' = 236419 - JUICE_FIZZER_DRINK_EFFECTS_JUICE_AND_SELTZER_ENERGIZED_1: 'CommonBuffId' = 236414 - JUICE_FIZZER_DRINK_EFFECTS_JUICE_AND_SELTZER_ENERGIZED_3: 'CommonBuffId' = 236415 - JUICE_FIZZER_DRINK_EFFECTS_JUICE_AND_SELTZER_ENERGIZED_6: 'CommonBuffId' = 236416 - JUICE_FIZZER_DRINK_EFFECTS_JUICE_AND_SELTZER_FLIRTY_1: 'CommonBuffId' = 236421 - JUICE_FIZZER_DRINK_EFFECTS_JUICE_AND_SELTZER_FLIRTY_3: 'CommonBuffId' = 236422 - JUICE_FIZZER_DRINK_EFFECTS_JUICE_AND_SELTZER_FLIRTY_6: 'CommonBuffId' = 236423 - JUICE_FIZZER_DRINK_EFFECTS_JUICE_AND_SELTZER_FOCUSED_1: 'CommonBuffId' = 236433 - JUICE_FIZZER_DRINK_EFFECTS_JUICE_AND_SELTZER_FOCUSED_3: 'CommonBuffId' = 236434 - JUICE_FIZZER_DRINK_EFFECTS_JUICE_AND_SELTZER_FOCUSED_6: 'CommonBuffId' = 236435 - JUICE_FIZZER_DRINK_EFFECTS_JUICE_AND_SELTZER_HAPPY_1: 'CommonBuffId' = 236372 - JUICE_FIZZER_DRINK_EFFECTS_JUICE_AND_SELTZER_HAPPY_3: 'CommonBuffId' = 236375 - JUICE_FIZZER_DRINK_EFFECTS_JUICE_AND_SELTZER_HAPPY_6: 'CommonBuffId' = 236377 - JUICE_FIZZER_DRINK_EFFECTS_JUICE_AND_SELTZER_INSPIRED_1: 'CommonBuffId' = 236429 - JUICE_FIZZER_DRINK_EFFECTS_JUICE_AND_SELTZER_INSPIRED_3: 'CommonBuffId' = 236430 - JUICE_FIZZER_DRINK_EFFECTS_JUICE_AND_SELTZER_INSPIRED_6: 'CommonBuffId' = 236431 - JUICE_FIZZER_DRINK_EFFECTS_JUICE_AND_SELTZER_PASSED_OUT: 'CommonBuffId' = 236561 - JUICE_FIZZER_DRINK_EFFECTS_JUICE_AND_SELTZER_PLAYFUL_1: 'CommonBuffId' = 236437 - JUICE_FIZZER_DRINK_EFFECTS_JUICE_AND_SELTZER_PLAYFUL_3: 'CommonBuffId' = 236438 - JUICE_FIZZER_DRINK_EFFECTS_JUICE_AND_SELTZER_PLAYFUL_6: 'CommonBuffId' = 236439 - JUICE_FIZZER_DRINK_EFFECTS_KOMBUCHA_DAZED_FIZZY_HEAD: 'CommonBuffId' = 236985 - JUICE_FIZZER_DRINK_EFFECTS_KOMBUCHA_DAZED_FROM_ENERGIZED: 'CommonBuffId' = 236607 - JUICE_FIZZER_DRINK_EFFECTS_KOMBUCHA_DAZED_FROM_FOCUSED: 'CommonBuffId' = 240188 - JUICE_FIZZER_DRINK_EFFECTS_KOMBUCHA_ENERGIZED_1: 'CommonBuffId' = 236570 - JUICE_FIZZER_DRINK_EFFECTS_KOMBUCHA_ENERGIZED_2: 'CommonBuffId' = 236571 - JUICE_FIZZER_DRINK_EFFECTS_KOMBUCHA_ENERGIZED_4: 'CommonBuffId' = 236572 - JUICE_FIZZER_DRINK_EFFECTS_KOMBUCHA_FOCUSED_1: 'CommonBuffId' = 236573 - JUICE_FIZZER_DRINK_EFFECTS_KOMBUCHA_FOCUSED_2: 'CommonBuffId' = 236574 - JUICE_FIZZER_DRINK_EFFECTS_KOMBUCHA_FOCUSED_4: 'CommonBuffId' = 236575 - JUICE_FIZZER_DRINK_EFFECTS_KOMBUCHA_GRIMBUCHA_1: 'CommonBuffId' = 236604 - JUICE_FIZZER_DRINK_EFFECTS_KOMBUCHA_GRIMBUCHA_2: 'CommonBuffId' = 236605 - JUICE_FIZZER_DRINK_EFFECTS_KOMBUCHA_GRIMBUCHA_4: 'CommonBuffId' = 236606 - JUICE_FIZZER_DRINK_EFFECTS_KOMBUCHA_GRIMBUCHA_DAZED: 'CommonBuffId' = 236614 - JUICE_FIZZER_DRINK_EFFECTS_SUSPICIOUS_DANGEROUSLY_FIZZY: 'CommonBuffId' = 236624 - JUICE_FIZZER_DRINK_EFFECTS_SUSPICIOUS_HORRIBLY_FIZZY: 'CommonBuffId' = 236623 - JUICE_FIZZER_DRINK_EFFECTS_SUSPICIOUS_WEIRDLY_FIZZY: 'CommonBuffId' = 236622 - JUICE_FIZZER_KOMBUCHA_ENERGIZED: 'CommonBuffId' = 236593 - JUICE_FIZZER_KOMBUCHA_FOCUSED: 'CommonBuffId' = 236594 - JUICE_FIZZER_KOMBUCHA_GRIMBUCHA: 'CommonBuffId' = 236595 - JUICE_FIZZER_TRAIT_FIZZER_FOCUS: 'CommonBuffId' = 236953 - JUICE_FIZZER_TRAIT_FIZZY_HEAD: 'CommonBuffId' = 236951 - JUICE_FIZZING_FLAT_FIZZ_FACTS: 'CommonBuffId' = 235751 - JUICE_FIZZING_JUICY_FIZZ_KNOWELDGE: 'CommonBuffId' = 235750 - JUICE_FIZZING_KNOWLEDGE_FIZZLED_OUT: 'CommonBuffId' = 235752 - JUICE_FIZZING_SEND_FOR_EVALUATION_AVERAGE: 'CommonBuffId' = 236826 - JUICE_FIZZING_SEND_FOR_EVALUATION_AWFUL: 'CommonBuffId' = 236827 - JUICE_FIZZING_SEND_FOR_EVALUATION_OUTSTANDING: 'CommonBuffId' = 236828 - JUICE_FIZZING_SEND_FOR_EVALUATION_VERY_GOOD: 'CommonBuffId' = 236829 - JUICE_FIZZING_SEND_FOR_EVALUATION_WORLD_CLASS: 'CommonBuffId' = 236830 - JUICE_KEG_BLUE_RASPBERRY_CONFIDENT_1: 'CommonBuffId' = 208584 - JUICE_KEG_BLUE_RASPBERRY_CONFIDENT_2: 'CommonBuffId' = 208585 - JUICE_KEG_BLUE_RASPBERRY_CONFIDENT_3: 'CommonBuffId' = 208586 - JUICE_KEG_DRAGON_FRUIT_PLAYFUL_1: 'CommonBuffId' = 208587 - JUICE_KEG_DRAGON_FRUIT_PLAYFUL_2: 'CommonBuffId' = 208588 - JUICE_KEG_DRAGON_FRUIT_PLAYFUL_3: 'CommonBuffId' = 208589 - JUICE_KEG_FINISHED_KEG: 'CommonBuffId' = 222674 - JUICE_KEG_FLAT_JUICE_DEBUFF: 'CommonBuffId' = 210446 - JUICE_KEG_KEG_PARTY_SNACKS: 'CommonBuffId' = 222683 - JUICE_KEG_KEG_STAND_FAIL: 'CommonBuffId' = 209601 - JUICE_KEG_KEG_STAND_SUCCESS: 'CommonBuffId' = 209600 - JUICE_KEG_PASSION_FRUIT_FLIRTY_1: 'CommonBuffId' = 208590 - JUICE_KEG_PASSION_FRUIT_FLIRTY_2: 'CommonBuffId' = 208591 - JUICE_KEG_PASSION_FRUIT_FLIRTY_3: 'CommonBuffId' = 208592 - JUICE_KEG_PINEAPPLE_HAPPY_1: 'CommonBuffId' = 208593 - JUICE_KEG_PINEAPPLE_HAPPY_2: 'CommonBuffId' = 208594 - JUICE_KEG_PINEAPPLE_HAPPY_3: 'CommonBuffId' = 208595 - JUICE_KEG_TAPPER_FAILED: 'CommonBuffId' = 209599 - JUICE_KEG_TAPPER_SUCCESS: 'CommonBuffId' = 209598 - JUNGLE_REGION_ON_JUNGLE_VACATION: 'CommonBuffId' = 178668 - JUNGLE_REGION_WELCOME_PACKAGE: 'CommonBuffId' = 183105 - JUNGLE_WELCOME_PACKAGE_RECEIVED: 'CommonBuffId' = 183130 - KARAOKE_MACHINE_COOLDOWN: 'CommonBuffId' = 154416 - KARAOKE_MACHINE_END_GOOD_SINGING: 'CommonBuffId' = 141672 - KARAOKE_MACHINE_END_GOOD_SINGING_ACTIVATED: 'CommonBuffId' = 152435 - KARAOKE_MACHINE_END_GOOD_SINGING_BALLAD: 'CommonBuffId' = 154200 - KARAOKE_MACHINE_END_POOR_SINGING: 'CommonBuffId' = 141671 - KARAOKE_MACHINE_GOOD_SINGING_ACTOR_GENERAL: 'CommonBuffId' = 148245 - KARAOKE_MACHINE_GOOD_SINGING_ACTOR_TRAITS_BUFF: 'CommonBuffId' = 148243 - KARAOKE_MACHINE_GREAT_SINGING_ACTOR_GENERAL: 'CommonBuffId' = 148244 - KARAOKE_MACHINE_GREAT_SINGING_ACTOR_TRAITS_BUFF: 'CommonBuffId' = 148242 - KARAOKE_MACHINE_HIDDEN_BALLAD_WITH_CHILD: 'CommonBuffId' = 155691 - KARAOKE_MACHINE_HIDDEN_CURRENTLY_SINGING: 'CommonBuffId' = 152415 - KARAOKE_MACHINE_HIDDEN_CURRENTLY_SINGING_CONTEST: 'CommonBuffId' = 153655 - KARAOKE_MACHINE_HIDDEN_CURRENTLY_SINGING_Y_SIM: 'CommonBuffId' = 152419 - KARAOKE_MACHINE_HIDDEN_WATCHING_BALLAD: 'CommonBuffId' = 154274 - KARAOKE_MACHINE_POOR_SINGING_ACTOR_GENERAL: 'CommonBuffId' = 148246 - KARAOKE_MACHINE_POOR_SINGING_ACTOR_TRAITS_BUFF: 'CommonBuffId' = 148241 - KAVA_BOWL_DRINK_BUFFS_LEVEL_1: 'CommonBuffId' = 205923 - KAVA_BOWL_DRINK_BUFFS_LEVEL_2: 'CommonBuffId' = 205924 - KAVA_BOWL_DRINK_BUFFS_LEVEL_3: 'CommonBuffId' = 205925 - KAVA_BOWL_DRINK_BUFFS_WELL_RESTED: 'CommonBuffId' = 206153 - KAVA_PARTY_INCLUDED: 'CommonBuffId' = 206775 - KAVA_PARTY_PHASE_2: 'CommonBuffId' = 206767 - KEEPSAKE_BOX_ADULT_VFX: 'CommonBuffId' = 324062 - KEEPSAKE_BOX_CHILD_VFX: 'CommonBuffId' = 328017 - KEEPSAKE_BOX_FAMILY_ENTRUSTED: 'CommonBuffId' = 320392 - KEEPSAKE_BOX_PASSING_TORCH: 'CommonBuffId' = 320391 - KEEPSAKE_BOX_PONDER_MEANING_BEING_TOGETHER: 'CommonBuffId' = 320700 - KEEPSAKE_BOX_PONDER_MEANING_COOLDOWN: 'CommonBuffId' = 320564 - KEEPSAKE_BOX_PONDER_MEANING_ISNT_EVERYTHING: 'CommonBuffId' = 320704 - KEEPSAKE_BOX_PONDER_MEANING_NOBODY_KNOWS: 'CommonBuffId' = 320705 - KEEPSAKE_BOX_PONDER_MEANING_OBEDIENCE: 'CommonBuffId' = 322837 - KEEPSAKE_BOX_PONDER_MEANING_PATIENCE: 'CommonBuffId' = 320706 - KEEPSAKE_BOX_PONDER_MEANING_TOLERANCE: 'CommonBuffId' = 320707 - KEEPSAKE_BOX_PONDER_MEANING_UNCONDITIONAL: 'CommonBuffId' = 320708 - KEEPSAKE_BOX_PONDER_MEANING_WEIRD: 'CommonBuffId' = 320709 - KEEPSAKE_BOX_WANT_COOL_BOX: 'CommonBuffId' = 320393 - KIDDIE_POOL_ADULT_COOL_POOL: 'CommonBuffId' = 189635 - KIDDIE_POOL_ADULT_ERRATIC_SPLASHING: 'CommonBuffId' = 189630 - KIDDIE_POOL_ADULT_SPLASHY_FUN: 'CommonBuffId' = 189629 - KIDDIE_POOL_TODDLER_POOL_TIME_PLAYFUL: 'CommonBuffId' = 189626 - KISS_COOLDOWN_QUICK_SOCIAL_NOT_VISIBLE: 'CommonBuffId' = 39865 - KNITTING_AUTONOMOUS_COOLDOWN: 'CommonBuffId' = 250694 - KNITTING_DONATE_BEANIES: 'CommonBuffId' = 241076 - KNITTING_DONATE_CHILD_TOY: 'CommonBuffId' = 241085 - KNITTING_DONATE_DECORATIONS: 'CommonBuffId' = 241082 - KNITTING_DONATE_FURNISHINGS: 'CommonBuffId' = 241078 - KNITTING_DONATE_ONESIES: 'CommonBuffId' = 241083 - KNITTING_DONATE_POUFFES: 'CommonBuffId' = 241081 - KNITTING_DONATE_RUGS: 'CommonBuffId' = 241079 - KNITTING_DONATE_SOCKS: 'CommonBuffId' = 241077 - KNITTING_DONATE_SWEATERS: 'CommonBuffId' = 241080 - KNITTING_DONATE_SWEATER_SCARF: 'CommonBuffId' = 241084 - KNITTING_IS_KNITTING: 'CommonBuffId' = 245464 - KNITTING_VISIBLE_BRUTAL_KNITS: 'CommonBuffId' = 241317 - KNITTING_VISIBLE_FRESH_START: 'CommonBuffId' = 243734 - KNITTING_VISIBLE_GREAT_KNITS: 'CommonBuffId' = 239824 - KNITTING_VISIBLE_INTERNAL_SCREAMING: 'CommonBuffId' = 239822 - KNITTING_VISIBLE_INTERWOVEN_FATES: 'CommonBuffId' = 239812 - KNITTING_VISIBLE_ITCHY_KNITS: 'CommonBuffId' = 239811 - KNITTING_VISIBLE_KNEAT_KNITS: 'CommonBuffId' = 239807 - KNITTING_VISIBLE_KNITTABLE_CONTRIBUTE: 'CommonBuffId' = 239809 - KNITTING_VISIBLE_MADE_THAT: 'CommonBuffId' = 239870 - KNITTING_VISIBLE_NO_MORE_KNITTING: 'CommonBuffId' = 239808 - KNITTING_VISIBLE_READY_SET_KNIT: 'CommonBuffId' = 239810 - KNITTING_VISIBLE_SWEATER_CURSE: 'CommonBuffId' = 239813 - KNITTING_VISIBLE_UNFORTUKNITS: 'CommonBuffId' = 239823 - KNITTING_WEARING_KNITTED_CLOTHING: 'CommonBuffId' = 240782 - KNITTING_YELL_AT_COOLDOWN: 'CommonBuffId' = 244399 - KOTATSU_COSY: 'CommonBuffId' = 248530 - KOTATSU_COSY_UPGRADED: 'CommonBuffId' = 248536 - KOTATSU_DAZED: 'CommonBuffId' = 248531 - KOTATSU_DAZED_STRONGER: 'CommonBuffId' = 252298 - KOTATSU_FUNNY_BURNING_SMELL: 'CommonBuffId' = 248529 - KOTATSU_HIDDEN_TEMPERATURE_COLD: 'CommonBuffId' = 248532 - KOTATSU_HIDDEN_TEMPERATURE_COOL: 'CommonBuffId' = 248533 - KOTATSU_HIDDEN_TEMPERATURE_HOT: 'CommonBuffId' = 248534 - KOTATSU_HIDDEN_TEMPERATURE_WARM: 'CommonBuffId' = 248535 - LAMPOON_PARTY_GOLD: 'CommonBuffId' = 202959 - LANDLORD_TENANT_ANGRY_TENANT: 'CommonBuffId' = 355689 - LANDLORD_TENANT_ASKED_ABOUT_CONDITIONS_HIDDEN: 'CommonBuffId' = 353764 - LANDLORD_TENANT_ASK_ABOUT_RENTAL_NEGATIVE: 'CommonBuffId' = 355703 - LANDLORD_TENANT_ASK_ABOUT_RENTAL_POSITIVE: 'CommonBuffId' = 355690 - LANDLORD_TENANT_BLAME_TENANTS: 'CommonBuffId' = 355683 - LANDLORD_TENANT_COMMEND_TENANTS: 'CommonBuffId' = 355684 - LANDLORD_TENANT_COMPLAIN_ABOUT_RENTAL_CONDITIONS: 'CommonBuffId' = 355681 - LANDLORD_TENANT_COMPLIMENT_RENTAL_CONDTIONS: 'CommonBuffId' = 355682 - LANDLORD_TENANT_COUPON: 'CommonBuffId' = 345820 - LANDLORD_TENANT_CRITICIZE_NEIGHBORS: 'CommonBuffId' = 355685 - LANDLORD_TENANT_DO_INSPECTION_MAINTENANCE_AUTONOMOUS_PLAYER_COOLDOWN_HIDDEN: 'CommonBuffId' = 360443 - LANDLORD_TENANT_EMERGENCY_SUCCESS_HIDDEN: 'CommonBuffId' = 351013 - LANDLORD_TENANT_EVERY_LITTLE_BIT_COUNTS: 'CommonBuffId' = 345359 - LANDLORD_TENANT_FOR_RENT_SIGN_RUMINATE: 'CommonBuffId' = 353654 - LANDLORD_TENANT_GOLD_EVENTS_HIDDEN: 'CommonBuffId' = 350268 - LANDLORD_TENANT_GOLD_SOCIAL_EVENT_COMPLETE: 'CommonBuffId' = 354135 - LANDLORD_TENANT_HANDINESS_MODIFIER_HIDDEN: 'CommonBuffId' = 359529 - LANDLORD_TENANT_INCITE_TENANT_REVOLT: 'CommonBuffId' = 355686 - LANDLORD_TENANT_JUNK_MAIL_FAIL: 'CommonBuffId' = 357042 - LANDLORD_TENANT_LANDLORD_HIDDEN: 'CommonBuffId' = 345358 - LANDLORD_TENANT_MAINTENANCE_SUCCESS_HIDDEN: 'CommonBuffId' = 350497 - LANDLORD_TENANT_MOVE_HOUSEHOLD_OWES_FEE_HIDDEN: 'CommonBuffId' = 359178 - LANDLORD_TENANT_NEIGHBOR_CHAT_COOLDOWN_HIDDEN: 'CommonBuffId' = 354024 - LANDLORD_TENANT_NOTORIOUS_NEGOTIATOR: 'CommonBuffId' = 345360 - LANDLORD_TENANT_PRAISE_HAVING_GREAT_NEIGHBORS: 'CommonBuffId' = 355687 - LANDLORD_TENANT_REPO_ANGRY: 'CommonBuffId' = 354535 - LANDLORD_TENANT_RULE_BROKEN_HIDDEN: 'CommonBuffId' = 350269 - LANDLORD_TENANT_SORT_JUNK_MAIL_KIDS: 'CommonBuffId' = 357258 - LANDLORD_TENANT_SUGGEST_HOSTING_CHARITY_EVENT: 'CommonBuffId' = 355688 - LANDLORD_TENANT_TENANT_HIDDEN: 'CommonBuffId' = 358087 - LANDLORD_TENANT_WORTH_A_TRY: 'CommonBuffId' = 345361 - LARGE_SLEEP_DESIRE: 'CommonBuffId' = 8904 - LAUNDRY_CLEAN: 'CommonBuffId' = 176286 - LAUNDRY_DAMP: 'CommonBuffId' = 176291 - LAUNDRY_DIZZY: 'CommonBuffId' = 178389 - LAUNDRY_DRY: 'CommonBuffId' = 176290 - LAUNDRY_FILTHY: 'CommonBuffId' = 176293 - LAUNDRY_FRAGRANT: 'CommonBuffId' = 178523 - LAUNDRY_GRUNGY: 'CommonBuffId' = 176292 - LAUNDRY_PRISTINE: 'CommonBuffId' = 176287 - LAUNDRY_RANK: 'CommonBuffId' = 178525 - LAUNDRY_SOAKED: 'CommonBuffId' = 178524 - LAUNDRY_TODDLER_DAMP_DIRTY: 'CommonBuffId' = 178410 - LAUNDRY_USED: 'CommonBuffId' = 176289 - LAUNDRY_WARM: 'CommonBuffId' = 178522 - LAUNDRY_WASH_TUB_WASHED_OUT_ARMS: 'CommonBuffId' = 178412 - LAW_BLABBERMOUTH: 'CommonBuffId' = 228579 - LAW_IMPARTER_OF_KNOWLEDGE: 'CommonBuffId' = 228581 - LAW_JUDGE_HAS_SPOKEN: 'CommonBuffId' = 228584 - LAW_REPRESENT: 'CommonBuffId' = 228173 - LAW_UNAPPOINTED: 'CommonBuffId' = 228175 - LEAVE_POOL: 'CommonBuffId' = 106168 - LEAVE_WORK_BORED: 'CommonBuffId' = 23879 - LEAVE_WORK_EMBARRASSED: 'CommonBuffId' = 23880 - LEAVE_WORK_STRESSED: 'CommonBuffId' = 23905 - LEAVE_WORK_UNCOMFORTABLE: 'CommonBuffId' = 23910 - LECTURE_GRADES_EMBARRASSED: 'CommonBuffId' = 98975 - LECTURE_RESPONSIBILITIES_ANGRY: 'CommonBuffId' = 99231 - LIFESTYLES_ADRENALINE_SEEKER_AT_DANGEROUS_CAREER: 'CommonBuffId' = 249874 - LIFESTYLES_ADRENALINE_SEEKER_AT_EXCITING_VENUE: 'CommonBuffId' = 253510 - LIFESTYLES_ADRENALINE_SEEKER_AT_MUNDANE_CAREER: 'CommonBuffId' = 250383 - LIFESTYLES_ADRENALINE_SEEKER_AT_MUNDANE_VENUE: 'CommonBuffId' = 253140 - LIFESTYLES_ADRENALINE_SEEKER_BORED: 'CommonBuffId' = 250387 - LIFESTYLES_ADRENALINE_SEEKER_CONFIDENT: 'CommonBuffId' = 250385 - LIFESTYLES_ADRENALINE_SEEKER_DANGEROUS_WEATHER_COOLDOWN: 'CommonBuffId' = 253343 - LIFESTYLES_ADRENALINE_SEEKER_EXCITED_AT_FIRE: 'CommonBuffId' = 253200 - LIFESTYLES_ADRENALINE_SEEKER_FUN_GAIN: 'CommonBuffId' = 250384 - LIFESTYLES_ADRENALINE_SEEKER_MUNDANE_INTERACTIONS_FUN_LOSS: 'CommonBuffId' = 254080 - LIFESTYLES_ADRENALINE_SEEKER_THRILL_SEEKING_INTERACTIONS_FUN_GAIN: 'CommonBuffId' = 254079 - LIFESTYLES_CAN_UNLOCK_LIFESTYLES: 'CommonBuffId' = 246488 - LIFESTYLES_CLOSE_KNIT_LOST_A_FRIEND: 'CommonBuffId' = 248776 - LIFESTYLES_CLOSE_KNIT_NEW_FRIEND_TOO_MANY_FRIENDS: 'CommonBuffId' = 248647 - LIFESTYLES_COFFEE_FANATIC_DRANK_COFFEE: 'CommonBuffId' = 246571 - LIFESTYLES_COFFEE_FANATIC_NEED_MORE_COFFEE: 'CommonBuffId' = 246521 - LIFESTYLES_COFFEE_FANATIC_WAKES_UP: 'CommonBuffId' = 246560 - LIFESTYLES_DISLIKED_ENERGETIC: 'CommonBuffId' = 248176 - LIFESTYLES_DISLIKED_ENERGETIC_CONFLICT_OVERRIDE: 'CommonBuffId' = 248219 - LIFESTYLES_DISLIKED_SEDENTARY: 'CommonBuffId' = 248295 - LIFESTYLES_DISLIKED_SEDENTARY_CONFLICT_OVERRIDE: 'CommonBuffId' = 248301 - LIFESTYLES_DISLIKED_TECHNOPHOBE: 'CommonBuffId' = 249090 - LIFESTYLES_DISLIKED_TECHNOPHOBE_CONFLICT_OVERRIDE: 'CommonBuffId' = 249425 - LIFESTYLES_ENERGETIC_AT_ENERGETIC_CAREER: 'CommonBuffId' = 248756 - LIFESTYLES_ENERGETIC_AT_SEDENTARY_CAREER: 'CommonBuffId' = 248757 - LIFESTYLES_ENERGETIC_ENERGETIC_INTERACTIONS_FUN_GAIN: 'CommonBuffId' = 249913 - LIFESTYLES_ENERGETIC_NEGLECT_LIFESTYLE_00: 'CommonBuffId' = 250606 - LIFESTYLES_ENERGETIC_SEDENTARY_INTERACTIONS_FUN_LOSS: 'CommonBuffId' = 249914 - LIFESTYLES_ENERGETIC_SEDENTARY_POSTURE_FUN_LOSS: 'CommonBuffId' = 250612 - LIFESTYLES_FREQUENT_TRAVELER_CAN_ASK_ABOUT_HOME_REGION: 'CommonBuffId' = 254335 - LIFESTYLES_FREQUENT_TRAVELER_MET_LOCAL: 'CommonBuffId' = 246621 - LIFESTYLES_FREQUENT_TRAVELER_POST_VACATION_CONFIDENT: 'CommonBuffId' = 246393 - LIFESTYLES_FREQUENT_TRAVELER_POST_VACATION_ENERGIZED: 'CommonBuffId' = 246398 - LIFESTYLES_FREQUENT_TRAVELER_POST_VACATION_HAPPY: 'CommonBuffId' = 246397 - LIFESTYLES_FREQUENT_TRAVELER_POST_VACATION_INSPIRED: 'CommonBuffId' = 246396 - LIFESTYLES_FREQUENT_TRAVELER_REGION_TOURIST_NO_VACATION: 'CommonBuffId' = 246350 - LIFESTYLES_FREQUENT_TRAVELER_REGION_TOURIST_VACATION: 'CommonBuffId' = 246391 - LIFESTYLES_FREQUENT_TRAVELER_SHARE_TRAVEL_STORIES_ACTOR: 'CommonBuffId' = 252893 - LIFESTYLES_FREQUENT_TRAVELER_SHARE_TRAVEL_STORIES_LISTENER: 'CommonBuffId' = 252894 - LIFESTYLES_FREQUENT_TRAVELER_VACATION_PROGRESS_COOLDOWN: 'CommonBuffId' = 250138 - LIFESTYLES_FREQUENT_TRAVELER_VISIT_PROGRESS_REGION: 'CommonBuffId' = 246414 - LIFESTYLES_FREQUENT_TRAVELER_VISIT_PROGRESS_REGION_CAFE: 'CommonBuffId' = 246626 - LIFESTYLES_FREQUENT_TRAVELER_VISIT_REGION_COOLDOWN: 'CommonBuffId' = 254070 - LIFESTYLES_HAS_LIFESTYLE_ADRENALINE_SEEKER: 'CommonBuffId' = 248834 - LIFESTYLES_HAS_LIFESTYLE_ENERGETIC: 'CommonBuffId' = 248159 - LIFESTYLES_HAS_LIFESTYLE_FREQUENT_TRAVELER: 'CommonBuffId' = 246593 - LIFESTYLES_HAS_LIFESTYLE_HEALTH_FOOD_NUT: 'CommonBuffId' = 247606 - LIFESTYLES_HAS_LIFESTYLE_INDOORSY: 'CommonBuffId' = 248835 - LIFESTYLES_HAS_LIFESTYLE_JUNK_FOOD_DEVOURER: 'CommonBuffId' = 247607 - LIFESTYLES_HAS_LIFESTYLE_OUTDOORSY: 'CommonBuffId' = 248836 - LIFESTYLES_HAS_LIFESTYLE_SEDENTARY: 'CommonBuffId' = 248135 - LIFESTYLES_HAS_LIFESTYLE_WORKAHOLIC: 'CommonBuffId' = 245844 - LIFESTYLES_HAS_TRAIT_CLOSE_KNIT: 'CommonBuffId' = 253960 - LIFESTYLES_HAS_TRAIT_COFFEE_FANATIC: 'CommonBuffId' = 246516 - LIFESTYLES_HAS_TRAIT_HUNGRY_FOR_LOVE: 'CommonBuffId' = 253963 - LIFESTYLES_HAS_TRAIT_NETWORKER: 'CommonBuffId' = 253961 - LIFESTYLES_HAS_TRAIT_SINGLE_AND_LOVING_IT: 'CommonBuffId' = 253962 - LIFESTYLES_HAS_TRAIT_TECHIE: 'CommonBuffId' = 253956 - LIFESTYLES_HAS_TRAIT_TECHNOPHOBE: 'CommonBuffId' = 253957 - LIFESTYLES_HUNGRY_FOR_LOVE_CONSUMING_ROMANTIC_MEDIA: 'CommonBuffId' = 251020 - LIFESTYLES_HUNGRY_FOR_LOVE_FLIRTY_CONVERSATION: 'CommonBuffId' = 250756 - LIFESTYLES_HUNGRY_FOR_LOVE_IN_A_RELATIONSHIP: 'CommonBuffId' = 250757 - LIFESTYLES_HUNGRY_FOR_LOVE_NEAR_PARTNER: 'CommonBuffId' = 254104 - LIFESTYLES_HUNGRY_FOR_LOVE_NEAR_PARTNER_COOLDOWN: 'CommonBuffId' = 254110 - LIFESTYLES_HUNGRY_FOR_LOVE_NO_RELATIONSHIP: 'CommonBuffId' = 251261 - LIFESTYLES_HUNGRY_FOR_LOVE_ROMANTIC_MEDIA: 'CommonBuffId' = 251004 - LIFESTYLES_HUNGRY_FOR_LOVE_WAKE_UP_HAS_RELATIONSHIP: 'CommonBuffId' = 251075 - LIFESTYLES_INDOORSY_ANGRY_DOG_WALK: 'CommonBuffId' = 251967 - LIFESTYLES_INDOORSY_AT_OUTDOOR_CAREER: 'CommonBuffId' = 253609 - LIFESTYLES_INDOORSY_BORED: 'CommonBuffId' = 251319 - LIFESTYLES_INDOORSY_FINE: 'CommonBuffId' = 253142 - LIFESTYLES_INDOORSY_HAPPY: 'CommonBuffId' = 251318 - LIFESTYLES_INDOORSY_IM_INDOORS: 'CommonBuffId' = 251872 - LIFESTYLES_INDOORSY_IM_OUTDOORS: 'CommonBuffId' = 251873 - LIFESTYLES_INDOORSY_INDOORS_INTERACTIONS_FUN_GAIN: 'CommonBuffId' = 251874 - LIFESTYLES_INDOORSY_OUTDOORS_INTERACTIONS_FUN_LOSS: 'CommonBuffId' = 251875 - LIFESTYLES_LIKED_ENERGETIC: 'CommonBuffId' = 248318 - LIFESTYLES_LIKED_ENERGETIC_CONFLICT_OVERRIDE: 'CommonBuffId' = 248326 - LIFESTYLES_LIKED_INDOORSY_CONFLICT_OVERRIDE: 'CommonBuffId' = 253524 - LIFESTYLES_LIKED_TECHIE: 'CommonBuffId' = 249080 - LIFESTYLES_NEGLECT_ADRENALINE_SEEKER_LEVEL_1: 'CommonBuffId' = 250858 - LIFESTYLES_NEGLECT_ADRENALINE_SEEKER_LEVEL_2: 'CommonBuffId' = 250859 - LIFESTYLES_NEGLECT_CLOSE_KNIT_LEVEL_1: 'CommonBuffId' = 250547 - LIFESTYLES_NEGLECT_CLOSE_KNIT_LEVEL_2: 'CommonBuffId' = 250548 - LIFESTYLES_NEGLECT_COFFEE_FANATIC_LEVEL_1: 'CommonBuffId' = 246549 - LIFESTYLES_NEGLECT_COFFEE_FANATIC_LEVEL_2: 'CommonBuffId' = 247639 - LIFESTYLES_NEGLECT_ENERGETIC_CONFLICT_OVERRIDE: 'CommonBuffId' = 249151 - LIFESTYLES_NEGLECT_ENERGETIC_LEVEL_1: 'CommonBuffId' = 248573 - LIFESTYLES_NEGLECT_ENERGETIC_LEVEL_2: 'CommonBuffId' = 250601 - LIFESTYLES_NEGLECT_FOOD_HEALTH_NUT_LEVEL_1: 'CommonBuffId' = 250482 - LIFESTYLES_NEGLECT_FOOD_HEALTH_NUT_LEVEL_2: 'CommonBuffId' = 250483 - LIFESTYLES_NEGLECT_FOOD_JUNK_FOOD_LEVEL_1: 'CommonBuffId' = 250485 - LIFESTYLES_NEGLECT_FOOD_JUNK_FOOD_LEVEL_2: 'CommonBuffId' = 250484 - LIFESTYLES_NEGLECT_FREQUENT_TRAVELER_LEVEL_1: 'CommonBuffId' = 250352 - LIFESTYLES_NEGLECT_FREQUENT_TRAVELER_LEVEL_2: 'CommonBuffId' = 250356 - LIFESTYLES_NEGLECT_HUNGRY_FOR_LOVE_LEVEL_1: 'CommonBuffId' = 250670 - LIFESTYLES_NEGLECT_HUNGRY_FOR_LOVE_LEVEL_2: 'CommonBuffId' = 250669 - LIFESTYLES_NEGLECT_INDOORSY_LEVEL_1: 'CommonBuffId' = 250853 - LIFESTYLES_NEGLECT_INDOORSY_LEVEL_1_FINE_OVERRIDE: 'CommonBuffId' = 253639 - LIFESTYLES_NEGLECT_INDOORSY_LEVEL_2: 'CommonBuffId' = 250854 - LIFESTYLES_NEGLECT_INDOORSY_LEVEL_2_FINE_OVERRIDE: 'CommonBuffId' = 253640 - LIFESTYLES_NEGLECT_LEVEL_0_ADRENALINE_SEEKER: 'CommonBuffId' = 250841 - LIFESTYLES_NEGLECT_LEVEL_0_CLOSE_KNIT: 'CommonBuffId' = 250538 - LIFESTYLES_NEGLECT_LEVEL_0_COFFEE_FANATIC: 'CommonBuffId' = 252168 - LIFESTYLES_NEGLECT_LEVEL_0_FOOD_HEALTH_NUT: 'CommonBuffId' = 250480 - LIFESTYLES_NEGLECT_LEVEL_0_FOOD_JUNK_FOOD: 'CommonBuffId' = 250481 - LIFESTYLES_NEGLECT_LEVEL_0_FREQUENT_TRAVELER: 'CommonBuffId' = 250348 - LIFESTYLES_NEGLECT_LEVEL_0_HUNGRY_FOR_LOVE: 'CommonBuffId' = 250664 - LIFESTYLES_NEGLECT_LEVEL_0_INDOORSY: 'CommonBuffId' = 250842 - LIFESTYLES_NEGLECT_LEVEL_0_NETWORKER: 'CommonBuffId' = 250537 - LIFESTYLES_NEGLECT_LEVEL_0_NO_NEED_FOR_ROMANCE: 'CommonBuffId' = 250663 - LIFESTYLES_NEGLECT_LEVEL_0_OUTDOORSY: 'CommonBuffId' = 250843 - LIFESTYLES_NEGLECT_LEVEL_0_TECHIE: 'CommonBuffId' = 250535 - LIFESTYLES_NEGLECT_LEVEL_0_TECHNOPHOBE: 'CommonBuffId' = 250536 - LIFESTYLES_NEGLECT_LEVEL_0_WORKAHOLIC: 'CommonBuffId' = 250330 - LIFESTYLES_NEGLECT_NETWORKER_CONFLICT_OVERRIDE: 'CommonBuffId' = 250555 - LIFESTYLES_NEGLECT_NETWORKER_LEVEL_1: 'CommonBuffId' = 250550 - LIFESTYLES_NEGLECT_NETWORKER_LEVEL_2: 'CommonBuffId' = 250551 - LIFESTYLES_NEGLECT_NO_NEED_FOR_ROMANCE_CONFLICT_OVERRIDE: 'CommonBuffId' = 253861 - LIFESTYLES_NEGLECT_NO_NEED_FOR_ROMANCE_LEVEL_1: 'CommonBuffId' = 250666 - LIFESTYLES_NEGLECT_NO_NEED_FOR_ROMANCE_LEVEL_2: 'CommonBuffId' = 250667 - LIFESTYLES_NEGLECT_OUTDOORSY_LEVEL_1: 'CommonBuffId' = 250849 - LIFESTYLES_NEGLECT_OUTDOORSY_LEVEL_2: 'CommonBuffId' = 250852 - LIFESTYLES_NEGLECT_SEDENTARY_CONFLICT_OVERRIDE: 'CommonBuffId' = 249148 - LIFESTYLES_NEGLECT_SEDENTARY_LEVEL_1: 'CommonBuffId' = 248568 - LIFESTYLES_NEGLECT_SEDENTARY_LEVEL_2: 'CommonBuffId' = 250591 - LIFESTYLES_NEGLECT_TECHIE_LEVEL_1: 'CommonBuffId' = 250541 - LIFESTYLES_NEGLECT_TECHIE_LEVEL_2: 'CommonBuffId' = 250540 - LIFESTYLES_NEGLECT_TECHNOPHOBE_CONFLICT_OVERRIDE: 'CommonBuffId' = 250543 - LIFESTYLES_NEGLECT_TECHNOPHOBE_LEVEL_1: 'CommonBuffId' = 250544 - LIFESTYLES_NEGLECT_TECHNOPHOBE_LEVEL_2: 'CommonBuffId' = 250545 - LIFESTYLES_NEGLECT_WORKAHOLIC_LEVEL_1: 'CommonBuffId' = 250061 - LIFESTYLES_NEGLECT_WORKAHOLIC_LEVEL_2: 'CommonBuffId' = 250062 - LIFESTYLES_NEGLECT_WORKAHOLIC_OVERRIDE: 'CommonBuffId' = 250069 - LIFESTYLES_NETWORKER_AMONG_FRIENDS: 'CommonBuffId' = 248622 - LIFESTYLES_NETWORKER_AMONG_FRIENDS_OVERRIDE: 'CommonBuffId' = 248638 - LIFESTYLES_NETWORKER_DESOLATE_OVERRIDE: 'CommonBuffId' = 248670 - LIFESTYLES_NETWORKER_LONELY_OVERRIDE: 'CommonBuffId' = 248669 - LIFESTYLES_NETWORKER_LOST_A_FRIEND: 'CommonBuffId' = 248777 - LIFESTYLES_NETWORKER_NEW_FRIEND: 'CommonBuffId' = 248660 - LIFESTYLES_NO_NEED_FOR_ROMANCE_CONSUMING_ROMANTIC_MEDIA: 'CommonBuffId' = 251263 - LIFESTYLES_NO_NEED_FOR_ROMANCE_FLIRTY_CONVERSATION: 'CommonBuffId' = 251456 - LIFESTYLES_NO_NEED_FOR_ROMANCE_HAS_RELATIONSHIP: 'CommonBuffId' = 251260 - LIFESTYLES_NO_NEED_FOR_ROMANCE_NO_RELATIONSHIP: 'CommonBuffId' = 251258 - LIFESTYLES_NO_NEED_FOR_ROMANCE_ROMANTIC_MEDIA: 'CommonBuffId' = 251005 - LIFESTYLES_NO_NEED_FOR_ROMANCE_WAKEUP_NO_RELATIONSHIP: 'CommonBuffId' = 251195 - LIFESTYLES_NO_NEED_FOR_ROMANCE_WAKEUP_NO_RELATIONSHIP_CONFLICT_OVERRIDE: 'CommonBuffId' = 251199 - LIFESTYLES_OUTDOORSY_AT_OUTDOORSY_CAREER: 'CommonBuffId' = 252963 - LIFESTYLES_OUTDOORSY_BORED: 'CommonBuffId' = 251323 - LIFESTYLES_OUTDOORSY_ENERGIZED_DOG_WALK: 'CommonBuffId' = 251907 - LIFESTYLES_OUTDOORSY_HAPPY: 'CommonBuffId' = 251322 - LIFESTYLES_OUTDOORSY_HAPPY_DOG_TRICKS: 'CommonBuffId' = 251908 - LIFESTYLES_OUTDOORSY_IM_INDOORS: 'CommonBuffId' = 251864 - LIFESTYLES_OUTDOORSY_IM_OUTDOORS: 'CommonBuffId' = 251863 - LIFESTYLES_OUTDOORSY_INDOORS_INTERACTIONS_FUN_LOSS: 'CommonBuffId' = 251871 - LIFESTYLES_OUTDOORSY_OUTDOORS_INTERACTIONS_FUN_GAIN: 'CommonBuffId' = 251870 - LIFESTYLES_OUTDOORSY_STRESSED_INDOOR_WORK: 'CommonBuffId' = 251909 - LIFESTYLES_OUTDOORSY_STRESSED_INDOOR_WORK_COOLDOWN: 'CommonBuffId' = 253637 - LIFESTYLES_ROMANCE_PERFORMED_ROMANTIC_INTERACTION: 'CommonBuffId' = 251257 - LIFESTYLES_ROMANCE_ROMANTIC_MEDIA_TIMER: 'CommonBuffId' = 250973 - LIFESTYLES_ROMANCE_WAKE_UP_COOLDOWN: 'CommonBuffId' = 254177 - LIFESTYLES_SEDENTARY_AT_ENERGETIC_CAREER: 'CommonBuffId' = 248755 - LIFESTYLES_SEDENTARY_AT_SEDENTARY_CAREER: 'CommonBuffId' = 248754 - LIFESTYLES_SEDENTARY_ENERGETIC_INTERACTIONS_FUN_LOSS: 'CommonBuffId' = 249916 - LIFESTYLES_SEDENTARY_NEGLECT_LIFESTYLE_00: 'CommonBuffId' = 250599 - LIFESTYLES_SEDENTARY_SEATED: 'CommonBuffId' = 248558 - LIFESTYLES_SEDENTARY_SEATED_CONFLICT_OVERRIDE: 'CommonBuffId' = 249147 - LIFESTYLES_SEDENTARY_SEDENTARY_INTERACTIONS_FUNGAIN: 'CommonBuffId' = 249915 - LIFESTYLES_SEDENTARY_SEDENTARY_POSTURE_FUNGAIN: 'CommonBuffId' = 250617 - LIFESTYLES_SHARE_LIFESTYLE_TIPS_NEGATIVE: 'CommonBuffId' = 249196 - LIFESTYLES_SHARE_LIFESTYLE_TIPS_NEGATIVE_TARGET: 'CommonBuffId' = 253756 - LIFESTYLES_SHARE_LIFESTYLE_TIPS_POSITIVE: 'CommonBuffId' = 249195 - LIFESTYLES_SHARE_LIFESTYLE_TIPS_POSITIVE_TARGET: 'CommonBuffId' = 253754 - LIFESTYLES_SINGLE_AND_LOVING_IT_GOT_ENGAGED: 'CommonBuffId' = 254098 - LIFESTYLES_SINGLE_AND_LOVING_IT_GOT_ENGAGED_CONFLICT: 'CommonBuffId' = 254100 - LIFESTYLES_SINGLE_AND_LOVING_IT_HA_DWEDDING: 'CommonBuffId' = 254099 - LIFESTYLES_SINGLE_AND_LOVING_IT_HA_DWEDDING_CONFLICT: 'CommonBuffId' = 254101 - LIFESTYLES_SINGLE_AND_LOVING_IT_NEW_PARTNER: 'CommonBuffId' = 254097 - LIFESTYLES_SINGLE_AND_LOVING_IT_NEW_PARTNER_CONFLICT: 'CommonBuffId' = 254102 - LIFESTYLES_SLEEP_TIMER: 'CommonBuffId' = 251073 - LIFESTYLES_TECHIE_AT_TECH_CAREER: 'CommonBuffId' = 247925 - LIFESTYLES_TECHIE_CONVERSATION_TARGET_SIM_BOT: 'CommonBuffId' = 247899 - LIFESTYLES_TECHIE_LAUNDRY: 'CommonBuffId' = 254125 - LIFESTYLES_TECHIE_NO_POWER_LOT: 'CommonBuffId' = 251701 - LIFESTYLES_TECHIE_ON_OFF_THE_GRID_LOT: 'CommonBuffId' = 249563 - LIFESTYLES_TECHIE_OVERCLOCKED_COMPUTER: 'CommonBuffId' = 249560 - LIFESTYLES_TECHIE_OVERCLOCKED_VIDEO_GAME: 'CommonBuffId' = 249559 - LIFESTYLES_TECHIE_REPAIRING_ELECTRONICS: 'CommonBuffId' = 247726 - LIFESTYLES_TECHIE_SAW_BROKEN_ELECTRONICS: 'CommonBuffId' = 246957 - LIFESTYLES_TECHIE_SIM_BOT: 'CommonBuffId' = 247810 - LIFESTYLES_TECHIE_USING_ELECTRONICS: 'CommonBuffId' = 249421 - LIFESTYLES_TECHNOPHOBE_AT_TECH_CAREER: 'CommonBuffId' = 247926 - LIFESTYLES_TECHNOPHOBE_CONVERSATION_TARGET_SIM_BOT: 'CommonBuffId' = 247900 - LIFESTYLES_TECHNOPHOBE_LAUNDRY: 'CommonBuffId' = 254123 - LIFESTYLES_TECHNOPHOBE_NEED_TO_GAME_OVERRIDE: 'CommonBuffId' = 247910 - LIFESTYLES_TECHNOPHOBE_NO_POWER_LOT: 'CommonBuffId' = 251702 - LIFESTYLES_TECHNOPHOBE_OFF_THE_GRID_VISIT_COOLDOWN: 'CommonBuffId' = 249349 - LIFESTYLES_TECHNOPHOBE_ON_OFF_THE_GRID_LOT: 'CommonBuffId' = 248882 - LIFESTYLES_TECHNOPHOBE_REPAIRING_ELECTRONICS: 'CommonBuffId' = 247727 - LIFESTYLES_TECHNOPHOBE_SAW_BROKEN_ELECTRONICS: 'CommonBuffId' = 246955 - LIFESTYLES_TECHNOPHOBE_SIM_BOT: 'CommonBuffId' = 247811 - LIFESTYLES_TECHNOPHOBE_USING_ELECTRONICS: 'CommonBuffId' = 249422 - LIFESTYLES_WORKAHOLIC_AT_WORK: 'CommonBuffId' = 245827 - LIFESTYLES_WORKAHOLIC_AT_WORK_CONFLICT_OVERRIDE: 'CommonBuffId' = 246110 - LIFESTYLES_WORKAHOLIC_DEMAND_PROMOTION_COOLDOWN: 'CommonBuffId' = 250244 - LIFESTYLES_WORKAHOLIC_DEMAND_PROMOTION_FAIL: 'CommonBuffId' = 252176 - LIFESTYLES_WORKAHOLIC_LOST_JOB: 'CommonBuffId' = 246069 - LIFESTYLES_WORKAHOLIC_LOST_JOB_CONFLICT_OVERRIDE: 'CommonBuffId' = 246073 - LIFESTYLES_WORKAHOLIC_WORK_OFF_HOURS_LAZY: 'CommonBuffId' = 250085 - LIFESTYLES_WORKAHOLIC_WORK_OFF_HOURS_LAZY_POST_WORK: 'CommonBuffId' = 250153 - LIFE_MILESTONE_ABDUCTED_BY_ALIENS_HERE_ENERGIZED: 'CommonBuffId' = 306142 - LIFE_MILESTONE_ABDUCTED_BY_ALIENS_HERE_SCARED: 'CommonBuffId' = 306143 - LIFE_MILESTONE_BABY_KEEPSAKE_BIG_KID: 'CommonBuffId' = 306156 - LIFE_MILESTONE_BABY_KEEPSAKE_HAPPY: 'CommonBuffId' = 311463 - LIFE_MILESTONE_BABY_KEEPSAKE_MY_BABY: 'CommonBuffId' = 306157 - LIFE_MILESTONE_BABY_KEEPSAKE_SAD: 'CommonBuffId' = 311461 - LIFE_MILESTONE_BABY_KEEPSAKE_WHY_DID_I_KEEP_THIS: 'CommonBuffId' = 306158 - LIFE_MILESTONE_CAUGHT_CHEATER_HERE_ANGRY: 'CommonBuffId' = 306140 - LIFE_MILESTONE_CAUGHT_CHEATER_HERE_SAD: 'CommonBuffId' = 306139 - LIFE_MILESTONE_CHILD_DRAWINGS_CRINGE_KEEPSAKE: 'CommonBuffId' = 306150 - LIFE_MILESTONE_CHILD_DRAWINGS_OK_I_GUESS: 'CommonBuffId' = 306149 - LIFE_MILESTONE_CHILD_DRAWINGS_TERRIBLE_REMINDER: 'CommonBuffId' = 306151 - LIFE_MILESTONE_CHILD_DRAWINGS_WHAT_IMAGINATION_INSPIRED: 'CommonBuffId' = 306153 - LIFE_MILESTONE_CHILD_DRAWINGS_WHAT_IMAGINATION_PARENT: 'CommonBuffId' = 306152 - LIFE_MILESTONE_CHILD_DRAWINGS_WHAT_IMAGINATION_PLAYFUL: 'CommonBuffId' = 306154 - LIFE_MILESTONE_CHILD_DRAWINGS_WORK_ON_DISPLAY: 'CommonBuffId' = 306378 - LIFE_MILESTONE_ENGAGMENT_REJECTED_HERE: 'CommonBuffId' = 306138 - LIFE_MILESTONE_FIRST_BLADDER_FAILHERE: 'CommonBuffId' = 306144 - LIFE_MILESTONE_FIRST_FIRE_HERE: 'CommonBuffId' = 306145 - LIFE_MILESTONE_FIRST_FIRE_HERE_FIRE_OBJECT: 'CommonBuffId' = 315259 - LIFE_MILESTONE_FIRST_PROMOTION: 'CommonBuffId' = 306147 - LIFE_MILESTONE_GOT_MARRIED_HERE_POSITIVE: 'CommonBuffId' = 306146 - LIFE_MILESTONE_HIDDEN_CAN_GET_LOT_BASED_BUFF: 'CommonBuffId' = 315076 - LIFE_MILESTONE_HIDDEN_CAREER_MAX_LEVEL: 'CommonBuffId' = 311611 - LIFE_MILESTONE_HIDDEN_CAREER_MAX_LEVEL_AFTER_SCHOOL_ACTIVITY: 'CommonBuffId' = 311612 - LIFE_MILESTONE_HIDDEN_JUST_BECAME_NON_OCCULT: 'CommonBuffId' = 333236 - LIFE_MILESTONE_HIDDEN_JUST_HAD_BIRTHDAY: 'CommonBuffId' = 332971 - LIFE_MILESTONE_HIDDEN_JUST_HAD_SELF_DISCOVERY: 'CommonBuffId' = 313002 - LIFE_MILESTONE_HIDDEN_JUST_RESURRECTED_NO_BIT: 'CommonBuffId' = 329409 - LIFE_MILESTONE_HIDDEN_JUST_SURVIVED_HAUNTED_HOUSE: 'CommonBuffId' = 313485 - LIFE_MILESTONE_HIDDEN_JUST_WON_VILLAGE_FAIR: 'CommonBuffId' = 313486 - LIFE_MILESTONE_HIDDEN_RECENT_FIRST_FIRE: 'CommonBuffId' = 315083 - LIFE_MILESTONE_HIDDEN_RECENT_FIRST_PROMOTION: 'CommonBuffId' = 318750 - LIFE_MILESTONE_HIDDEN_RECENT_STRUCK_BY_LIGHTNING: 'CommonBuffId' = 315084 - LIFE_MILESTONE_HIDDEN_REFLECTION_COOLDOWN: 'CommonBuffId' = 311914 - LIFE_MILESTONE_LET_ME_FORGET: 'CommonBuffId' = 311913 - LIFE_MILESTONE_MANY_ENEMIES_NEGATIVE: 'CommonBuffId' = 311893 - LIFE_MILESTONE_MANY_ENEMIES_POSITIVE: 'CommonBuffId' = 311892 - LIFE_MILESTONE_MANY_FRIENDS: 'CommonBuffId' = 311894 - LIFE_MILESTONE_MARRIAGE_CERTIFICATE_HAPPY: 'CommonBuffId' = 306160 - LIFE_MILESTONE_MARRIAGE_CERTIFICATE_MARRIAGE_OF_MISTAKES: 'CommonBuffId' = 306163 - LIFE_MILESTONE_MARRIAGE_CERTIFICATE_NOT_MEANT_FOR_MARRIAGE: 'CommonBuffId' = 306162 - LIFE_MILESTONE_MARRIAGE_CERTIFICATE_TENSE: 'CommonBuffId' = 306161 - LIFE_MILESTONE_MEMORABILIA_OF_DEAD_SIM: 'CommonBuffId' = 335427 - LIFE_MILESTONE_NEXT_ADVENTURE: 'CommonBuffId' = 311896 - LIFE_MILESTONE_PRO_PROFESSIONAL: 'CommonBuffId' = 311910 - LIFE_MILESTONE_RESILIENT: 'CommonBuffId' = 311911 - LIFE_MILESTONE_REVIVED: 'CommonBuffId' = 311895 - LIFE_MILESTONE_SMOOTH_SAILING: 'CommonBuffId' = 311891 - LIFE_MILESTONE_STRUCK_BY_LIGHTNING_HERE: 'CommonBuffId' = 306141 - LIFE_MILESTONE_TOOTH_CERTIFICATE_ANGRY: 'CommonBuffId' = 312234 - LIFE_MILESTONE_TOOTH_CERTIFICATE_PLAYFUL: 'CommonBuffId' = 312177 - LIFE_MILESTONE_UNDER_ACHIEVING: 'CommonBuffId' = 311912 - LIFE_MILESTONE_UPS_AND_DOWNS: 'CommonBuffId' = 311889 - LIFE_SKILLS_AUTONOMY_CONFLICT_RESOLUTION_NEGATIVE: 'CommonBuffId' = 163773 - LIFE_SKILLS_AUTONOMY_CONFLICT_RESOLUTION_POSITIVE: 'CommonBuffId' = 163774 - LIFE_SKILLS_AUTONOMY_CONFLICT_RESOLUTION_VERY_NEGATIVE: 'CommonBuffId' = 168261 - LIFE_SKILLS_AUTONOMY_CONFLICT_RESOLUTION_VERY_POSITIVE: 'CommonBuffId' = 168262 - LIFE_SKILLS_AUTONOMY_EMOTIONAL_CONTROL_NEGATIVE: 'CommonBuffId' = 163776 - LIFE_SKILLS_AUTONOMY_EMOTIONAL_CONTROL_POSITIVE: 'CommonBuffId' = 163775 - LIFE_SKILLS_AUTONOMY_EMOTIONAL_CONTROL_VERY_NEGATIVE: 'CommonBuffId' = 168263 - LIFE_SKILLS_AUTONOMY_EMOTIONAL_CONTROL_VERY_POSITIVE: 'CommonBuffId' = 168264 - LIFE_SKILLS_AUTONOMY_EMPATHY_NEGATIVE: 'CommonBuffId' = 163778 - LIFE_SKILLS_AUTONOMY_EMPATHY_POSITIVE: 'CommonBuffId' = 163777 - LIFE_SKILLS_AUTONOMY_EMPATHY_VERY_NEGATIVE: 'CommonBuffId' = 168265 - LIFE_SKILLS_AUTONOMY_EMPATHY_VERY_POSITIVE: 'CommonBuffId' = 168266 - LIFE_SKILLS_AUTONOMY_MANNERS_NEGATIVE: 'CommonBuffId' = 163780 - LIFE_SKILLS_AUTONOMY_MANNERS_POSITIVE: 'CommonBuffId' = 163779 - LIFE_SKILLS_AUTONOMY_MANNERS_VERY_NEGATIVE: 'CommonBuffId' = 168267 - LIFE_SKILLS_AUTONOMY_MANNERS_VERY_POSITIVE: 'CommonBuffId' = 168268 - LIFE_SKILLS_AUTONOMY_RESPONSIBILITY_NEGATIVE: 'CommonBuffId' = 163782 - LIFE_SKILLS_AUTONOMY_RESPONSIBILITY_POSITIVE: 'CommonBuffId' = 163781 - LIFE_SKILLS_AUTONOMY_RESPONSIBILITY_VERY_NEGATIVE: 'CommonBuffId' = 168270 - LIFE_SKILLS_AUTONOMY_RESPONSIBILITY_VERY_POSITIVE: 'CommonBuffId' = 168271 - LIGHTHOUSE_CONCEIVED_HERE_HAPPY: 'CommonBuffId' = 172432 - LIGHTHOUSE_HAPPY: 'CommonBuffId' = 176176 - LISTENING_DEVICE_BUGGED: 'CommonBuffId' = 202322 - LIVESTOCK_PEN_WOOHOO_EMBARRASSED: 'CommonBuffId' = 263151 - LIVESTOCK_PEN_WOOHOO_UNCOMFORTABLE: 'CommonBuffId' = 263159 - LIVING_STATUE_BUSKER_AT_PO_COOLDOWN: 'CommonBuffId' = 155689 - LIVING_STATUE_BUSKER_CAN_BUSK_HIDDEN_BODY: 'CommonBuffId' = 144139 - LIVING_STATUE_BUSKER_CAN_BUSK_HIDDEN_HEAD: 'CommonBuffId' = 144171 - LIVING_VICARIOUSLY_SKILL_ADULT_BARTENDING: 'CommonBuffId' = 30183 - LIVING_VICARIOUSLY_SKILL_ADULT_BODYBUILDING: 'CommonBuffId' = 30184 - LIVING_VICARIOUSLY_SKILL_ADULT_CHARISMA: 'CommonBuffId' = 30182 - LIVING_VICARIOUSLY_SKILL_ADULT_COMEDY: 'CommonBuffId' = 30185 - LIVING_VICARIOUSLY_SKILL_ADULT_GARDENING: 'CommonBuffId' = 30186 - LIVING_VICARIOUSLY_SKILL_ADULT_GOURMET_COOKING: 'CommonBuffId' = 30187 - LIVING_VICARIOUSLY_SKILL_ADULT_GUITAR: 'CommonBuffId' = 30188 - LIVING_VICARIOUSLY_SKILL_ADULT_HACKING: 'CommonBuffId' = 30189 - LIVING_VICARIOUSLY_SKILL_ADULT_HANDINESS: 'CommonBuffId' = 30190 - LIVING_VICARIOUSLY_SKILL_ADULT_HOME_STYLE_COOKING: 'CommonBuffId' = 30191 - LIVING_VICARIOUSLY_SKILL_ADULT_LOGIC: 'CommonBuffId' = 30192 - LIVING_VICARIOUSLY_SKILL_ADULT_MISCHIEF: 'CommonBuffId' = 30193 - LIVING_VICARIOUSLY_SKILL_ADULT_PAINTING: 'CommonBuffId' = 30194 - LIVING_VICARIOUSLY_SKILL_ADULT_PIANO: 'CommonBuffId' = 30195 - LIVING_VICARIOUSLY_SKILL_ADULT_ROCKET_SCIENCE: 'CommonBuffId' = 30197 - LIVING_VICARIOUSLY_SKILL_ADULT_VIDEO_GAMING: 'CommonBuffId' = 30199 - LIVING_VICARIOUSLY_SKILL_ADULT_VIOLIN: 'CommonBuffId' = 30200 - LIVING_VICARIOUSLY_SKILL_ADULT_WRITING: 'CommonBuffId' = 30201 - LIVING_VICARIOUSLY_SKILL_CHILD_CREATIVITY: 'CommonBuffId' = 29852 - LIVING_VICARIOUSLY_SKILL_CHILD_LOGIC: 'CommonBuffId' = 29858 - LIVING_VICARIOUSLY_SKILL_CHILD_MOTOR: 'CommonBuffId' = 29859 - LIVING_VICARIOUSLY_SKILL_CHILD_SOCIAL: 'CommonBuffId' = 29860 - LOCAL_CULTURE_SKILL_FOOD_TOLERANCE: 'CommonBuffId' = 176930 - LOOT_CHARITY_DRAMA_NODE: 'CommonBuffId' = 198064 - LORE_RING_EP16_RING_CONFIDENT: 'CommonBuffId' = 366261 - LORE_RING_EP16_RING_HAZE: 'CommonBuffId' = 366262 - LOSE_TEETH_CURRENTLY_AGING_UP: 'CommonBuffId' = 340261 - LOSE_TEETH_FIX_TOOTH_COOLDOWN: 'CommonBuffId' = 332335 - LOSE_TEETH_MISADVENTURE_DELAY: 'CommonBuffId' = 315029 - LOSE_TEETH_MISSING_TOOTH_APPEARANCE_MODIFIER: 'CommonBuffId' = 312134 - LOSE_TEETH_MISSING_TOOTH_BED_SWIPE: 'CommonBuffId' = 327987 - LOSE_TEETH_TIMER: 'CommonBuffId' = 312133 - LOSE_TEETH_TOOTHTASTROPHE: 'CommonBuffId' = 314781 - LOSE_TEETH_TOOTH_FAIRY: 'CommonBuffId' = 314778 - LOSE_TEETH_TOOTH_FAIRY_COOLDOWN: 'CommonBuffId' = 314866 - LOSE_TEETH_TOOTH_FAIRY_LOCKOUT: 'CommonBuffId' = 334268 - LOSE_TEETH_TOOTH_YOINKED: 'CommonBuffId' = 314782 - LOSE_TEETH_WIGGLE_TOOTH: 'CommonBuffId' = 314783 - LOST_A_GAME: 'CommonBuffId' = 273092 - LOST_FIGHT: 'CommonBuffId' = 12464 - LOST_FIGHT_BEAR: 'CommonBuffId' = 108103 - LOST_FIGHT_VILLAIN: 'CommonBuffId' = 99535 - LOTUS_ENERGIZED: 'CommonBuffId' = 346129 - LOT_MODS_APARTMENT_PRO_CHEFS_KITCHEN: 'CommonBuffId' = 140092 - LOT_MODS_APARTMENT_PRO_GREAT_ATMOSPHERE: 'CommonBuffId' = 135662 - LOT_MODS_APARTMENT_PRO_GREAT_ATMOSPHERE_VISIBLE: 'CommonBuffId' = 141963 - LOT_MODS_APARTMENT_PRO_GREAT_VIEW: 'CommonBuffId' = 135667 - LOT_MODS_APARTMENT_PRO_HISTORICAL: 'CommonBuffId' = 135668 - LOT_MODS_APARTMENT_PRO_HOME_STUDIO: 'CommonBuffId' = 135661 - LOT_MODS_APARTMENT_PRO_NEAR_GOOD_SCHOOLS_VISIBLE: 'CommonBuffId' = 141965 - LOT_MODS_BASE_GAME_BRACING_BREEZES_HIDDEN: 'CommonBuffId' = 145503 - LOT_MODS_BASE_GAME_BRACING_BREEZES_VISIBLE: 'CommonBuffId' = 145530 - LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_BIRTHDAY_SUIT_VISIBLE: 'CommonBuffId' = 206402 - LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_BURNT_BITS_VISIBLE: 'CommonBuffId' = 206521 - LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_CHILD_HOUSEHOLD_HIDDEN: 'CommonBuffId' = 207151 - LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_DARING_DINER_CONFIDENT_VISIBLE: 'CommonBuffId' = 212028 - LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_DARING_DINER_ENERGIZED_VISIBLE: 'CommonBuffId' = 212029 - LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_DARING_DINER_FLIRTY_VISIBLE: 'CommonBuffId' = 212026 - LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_DARING_DINER_PLAYFUL_VISIBLE: 'CommonBuffId' = 212030 - LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_EH_WHY_NOT_VISIBLE: 'CommonBuffId' = 211965 - LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_EWWWWW_1_VISIBLE: 'CommonBuffId' = 207628 - LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_EWWWWW_2_VISIBLE: 'CommonBuffId' = 211920 - LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_GETTING_BUFF_VISIBLE: 'CommonBuffId' = 212081 - LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_GET_NUDE_HIDDEN: 'CommonBuffId' = 206158 - LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_HAVE_SOME_DECENCY_1_VISIBLE: 'CommonBuffId' = 207623 - LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_HAVE_SOME_DECENCY_2_VISIBLE: 'CommonBuffId' = 211925 - LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_IN_MY_ELEMENT_VISIBLE: 'CommonBuffId' = 212116 - LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_IN_THE_BUFF_1_VISIBLE: 'CommonBuffId' = 206401 - LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_IN_THE_BUFF_2_VISIBLE: 'CommonBuffId' = 211931 - LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_IS_NUDE_HIDDEN: 'CommonBuffId' = 212086 - LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_LOT_HANG_OUT_VISIBLE: 'CommonBuffId' = 206561 - LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_NATURAL_FORM_VISIBLE: 'CommonBuffId' = 212238 - LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_NEVER_NUDE_HIDDEN: 'CommonBuffId' = 206639 - LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_NOT_A_CARE_IN_THE_WORLD_VISIBLE: 'CommonBuffId' = 212084 - LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_OH_NATURAL_VISIBLE: 'CommonBuffId' = 212085 - LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_PERFECT_TAN_VISIBLE: 'CommonBuffId' = 212236 - LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_RISKY_BUSINESS_VISIBLE: 'CommonBuffId' = 206493 - LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_SAND_EVERYWHERE_2_VISIBLE: 'CommonBuffId' = 212271 - LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_SAND_EVERYWHERE_VISIBLE: 'CommonBuffId' = 212261 - LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_SKINNY_DIP_VISIBLE: 'CommonBuffId' = 212172 - LOT_MODS_BASE_GAME_CLOTHING_OPTIONAL_UPDATER_HIDDEN: 'CommonBuffId' = 211867 - LOT_MODS_BASE_GAME_CONVIVIAL_HIDDEN: 'CommonBuffId' = 145501 - LOT_MODS_BASE_GAME_CONVIVIAL_HIDDEN_VFX: 'CommonBuffId' = 191074 - LOT_MODS_BASE_GAME_CONVIVIAL_VISIBLE: 'CommonBuffId' = 145525 - LOT_MODS_BASE_GAME_GREAT_ACOUSTICS_HIDDEN: 'CommonBuffId' = 145499 - LOT_MODS_BASE_GAME_GREAT_ACOUSTICS_VISIBLE: 'CommonBuffId' = 145522 - LOT_MODS_BASE_GAME_GRODY_RESTAURANTS_HIDDEN: 'CommonBuffId' = 152195 - LOT_MODS_BASE_GAME_HIGH_SPEED_INTERNET_HIDDEN: 'CommonBuffId' = 145498 - LOT_MODS_BASE_GAME_HIGH_SPEED_INTERNET_VISIBLE: 'CommonBuffId' = 145519 - LOT_MODS_BASE_GAME_HOMEY_HIDDEN: 'CommonBuffId' = 145493 - LOT_MODS_BASE_GAME_HOMEY_INVISIBLE_VFX: 'CommonBuffId' = 157154 - LOT_MODS_BASE_GAME_HOMEY_VISIBLE: 'CommonBuffId' = 145494 - LOT_MODS_BASE_GAME_NATURAL_LIGHT_HANDINESS_HIDDEN: 'CommonBuffId' = 146577 - LOT_MODS_BASE_GAME_NATURAL_LIGHT_HIDDEN: 'CommonBuffId' = 145502 - LOT_MODS_BASE_GAME_NATURAL_LIGHT_VISIBLE: 'CommonBuffId' = 145528 - LOT_MODS_BASE_GAME_SCIENCE_LAIR_HIDDEN: 'CommonBuffId' = 145500 - LOT_MODS_BASE_GAME_SCIENCE_LAIR_VISIBLE: 'CommonBuffId' = 145524 - LOT_MODS_ISLAND_SPIRITS_BENEVOLENT_ADULT_HIDDEN: 'CommonBuffId' = 210152 - LOT_MODS_ISLAND_SPIRITS_BENEVOLENT_CHILD_HIDDEN: 'CommonBuffId' = 210131 - LOT_MODS_ISLAND_SPIRITS_ISLAND_ABUNDANCE_VISIBLE: 'CommonBuffId' = 208762 - LOT_MODS_ISLAND_SPIRITS_ISLAND_CURSE_ADULT_VISIBLE: 'CommonBuffId' = 208772 - LOT_MODS_ISLAND_SPIRITS_ISLAND_CURSE_CHILD_VISIBLE: 'CommonBuffId' = 208816 - LOT_MODS_ISLAND_SPIRITS_ISLAND_ENERGY_VISIBLE: 'CommonBuffId' = 208763 - LOT_MODS_ISLAND_SPIRITS_ISLAND_FEAR_VISIBLE: 'CommonBuffId' = 208774 - LOT_MODS_ISLAND_SPIRITS_ISLAND_IMPATIENCE_VISIBLE: 'CommonBuffId' = 208775 - LOT_MODS_ISLAND_SPIRITS_ISLAND_LUCK_VISIBLE: 'CommonBuffId' = 208718 - LOT_MODS_ISLAND_SPIRITS_MALICIOUS_ADULT_HIDDEN: 'CommonBuffId' = 210154 - LOT_MODS_ISLAND_SPIRITS_MALICIOUS_CHILD_HIDDEN: 'CommonBuffId' = 210155 - LOT_MODS_OCEANIC_PARADISE_MERFOLK_HIDDEN: 'CommonBuffId' = 209688 - LOT_MODS_OCEANIC_PARADISE_NOT_SWIMMING_HIDDEN: 'CommonBuffId' = 209445 - LOT_MODS_OCEANIC_PARADISE_NOT_WADING_HIDDEN: 'CommonBuffId' = 209430 - LOT_MODS_OCEANIC_PARADISE_OCEANIC_SPLENDOR_VISIBLE: 'CommonBuffId' = 209490 - LOT_MODS_OCEANIC_PARADISE_SWIMMING_HIDDEN: 'CommonBuffId' = 209444 - LOT_MODS_OCEANIC_PARADISE_WADING_HIDDEN: 'CommonBuffId' = 209429 - LOUNGE_CHAIR_DOZE_OFF: 'CommonBuffId' = 207020 - LOUNGE_CHAIR_LUXORIOUS_LOUNGING: 'CommonBuffId' = 206848 - LOUNGE_EVENT_AWARD_CEREMONY_BOOK: 'CommonBuffId' = 197459 - LOUNGE_EVENT_AWARD_CEREMONY_CAREER_GIG: 'CommonBuffId' = 197460 - LOUNGE_EVENT_AWARD_CEREMONY_PAINTING: 'CommonBuffId' = 197461 - LOUNGE_EVENT_AWARD_CEREMONY_SONG: 'CommonBuffId' = 197463 - LOUNGE_EVENT_AWARD_CEREMONY_VIDEO: 'CommonBuffId' = 197462 - LOVE_GURU_ROMANTIC_DESTINY: 'CommonBuffId' = 146662 - LOVE_GURU_ROMANTIC_DOOM: 'CommonBuffId' = 146663 - LUNAR_CYCLE_MERMAID_4_FULLMOON: 'CommonBuffId' = 295512 - LUNAR_CYCLE_MERMAID_4_FULLMOON_TELEGRAPH: 'CommonBuffId' = 295513 - LUNAR_CYCLE_VAMPIRE_0_NEW_MOON: 'CommonBuffId' = 295399 - LUNAR_CYCLE_VAMPIRE_0_NEW_MOON_TELEGRAPH: 'CommonBuffId' = 295404 - LUNAR_CYCLE_WELL_RESTED: 'CommonBuffId' = 289361 - LUNAR_CYCLE_WEREWOLVES_0_NEW_MOON: 'CommonBuffId' = 288669 - LUNAR_CYCLE_WEREWOLVES_0_NEW_MOON_BLESSED: 'CommonBuffId' = 296542 - LUNAR_CYCLE_WEREWOLVES_0_NEW_MOON_TELEGRAPH: 'CommonBuffId' = 291593 - LUNAR_CYCLE_WEREWOLVES_1_WAXING_CRESCENT: 'CommonBuffId' = 288670 - LUNAR_CYCLE_WEREWOLVES_1_WAXING_CRESCENT_BLESSED: 'CommonBuffId' = 296544 - LUNAR_CYCLE_WEREWOLVES_1_WAXING_CRESCENT_TELEGRAPH: 'CommonBuffId' = 291594 - LUNAR_CYCLE_WEREWOLVES_2_FIRST_QUARTER: 'CommonBuffId' = 288671 - LUNAR_CYCLE_WEREWOLVES_2_FIRST_QUARTER_BLESSED: 'CommonBuffId' = 296546 - LUNAR_CYCLE_WEREWOLVES_2_FIRST_QUARTER_BLESSED_NEGATIVE: 'CommonBuffId' = 296818 - LUNAR_CYCLE_WEREWOLVES_2_FIRST_QUARTER_NEGATIVE: 'CommonBuffId' = 296817 - LUNAR_CYCLE_WEREWOLVES_2_FIRST_QUARTER_TELEGRAPH: 'CommonBuffId' = 291595 - LUNAR_CYCLE_WEREWOLVES_2_FIRST_QUARTER_TELEGRAPH_NEGATIVE: 'CommonBuffId' = 296824 - LUNAR_CYCLE_WEREWOLVES_3_WAXING_GIBBOUS: 'CommonBuffId' = 288672 - LUNAR_CYCLE_WEREWOLVES_3_WAXING_GIBBOUS_BLESSED: 'CommonBuffId' = 296548 - LUNAR_CYCLE_WEREWOLVES_3_WAXING_GIBBOUS_TELEGRAPH: 'CommonBuffId' = 291596 - LUNAR_CYCLE_WEREWOLVES_4_FULL_MOON: 'CommonBuffId' = 288673 - LUNAR_CYCLE_WEREWOLVES_4_FULL_MOON_FORMER_LYCAN: 'CommonBuffId' = 297732 - LUNAR_CYCLE_WEREWOLVES_4_FULL_MOON_FORMER_LYCAN_TELEGRAPH: 'CommonBuffId' = 297733 - LUNAR_CYCLE_WEREWOLVES_4_FULL_MOON_FURY_RATE: 'CommonBuffId' = 289862 - LUNAR_CYCLE_WEREWOLVES_4_FULL_MOON_FURY_RATE_COOLDOWN: 'CommonBuffId' = 292722 - LUNAR_CYCLE_WEREWOLVES_4_FULL_MOON_FURY_RATE_RESISTANCE: 'CommonBuffId' = 295870 - LUNAR_CYCLE_WEREWOLVES_4_FULL_MOON_INSATIABLE_HUNGER_SPEED_UP: 'CommonBuffId' = 293927 - LUNAR_CYCLE_WEREWOLVES_4_FULL_MOON_PRE_PHASE: 'CommonBuffId' = 289429 - LUNAR_CYCLE_WEREWOLVES_4_FULL_MOON_PRE_PHASE_NEGATIVE: 'CommonBuffId' = 289428 - LUNAR_CYCLE_WEREWOLVES_4_FULL_MOON_TELEGRAPH: 'CommonBuffId' = 291597 - LUNAR_CYCLE_WEREWOLVES_5_WANING_GIBBOUS: 'CommonBuffId' = 288674 - LUNAR_CYCLE_WEREWOLVES_5_WANING_GIBBOUS_BLESSED: 'CommonBuffId' = 296550 - LUNAR_CYCLE_WEREWOLVES_5_WANING_GIBBOUS_TELEGRAPH: 'CommonBuffId' = 291660 - LUNAR_CYCLE_WEREWOLVES_6_THIRD_QUARTER: 'CommonBuffId' = 288675 - LUNAR_CYCLE_WEREWOLVES_6_THIRD_QUARTER_BLESSED: 'CommonBuffId' = 296552 - LUNAR_CYCLE_WEREWOLVES_6_THIRD_QUARTER_BLESSED_NEGATIVE: 'CommonBuffId' = 296820 - LUNAR_CYCLE_WEREWOLVES_6_THIRD_QUARTER_NEGATIVE: 'CommonBuffId' = 296819 - LUNAR_CYCLE_WEREWOLVES_6_THIRD_QUARTER_TELEGRAPH: 'CommonBuffId' = 291661 - LUNAR_CYCLE_WEREWOLVES_6_THIRD_QUARTER_TELEGRAPH_NEGATIVE: 'CommonBuffId' = 296825 - LUNAR_CYCLE_WEREWOLVES_7_WANING_CRESCENT: 'CommonBuffId' = 288676 - LUNAR_CYCLE_WEREWOLVES_7_WANING_CRESCENT_BLESSED: 'CommonBuffId' = 296554 - LUNAR_CYCLE_WEREWOLVES_7_WANING_CRESCENT_TELEGRAPH: 'CommonBuffId' = 291662 - LUNAR_CYCLE_WEREWOLVES_LUNAR_BLESSING: 'CommonBuffId' = 296555 - LUNAR_CYCLE_WEREWOLVES_MOON_BATH_DREAMS_0_NEW_MOON: 'CommonBuffId' = 290180 - LUNAR_CYCLE_WEREWOLVES_MOON_BATH_DREAMS_1_WAXING_CRESCENT: 'CommonBuffId' = 290186 - LUNAR_CYCLE_WEREWOLVES_MOON_BATH_DREAMS_2_FIRST_QUARTER: 'CommonBuffId' = 290187 - LUNAR_CYCLE_WEREWOLVES_MOON_BATH_DREAMS_3_WAXING_GIBBOUS: 'CommonBuffId' = 290218 - LUNAR_CYCLE_WEREWOLVES_MOON_BATH_DREAMS_4_FULLMOON: 'CommonBuffId' = 290294 - LUNAR_CYCLE_WEREWOLVES_MOON_BATH_DREAMS_5_WANING_GIBBOUS: 'CommonBuffId' = 290295 - LUNAR_CYCLE_WEREWOLVES_MOON_BATH_DREAMS_6_THIRD_QUARTER: 'CommonBuffId' = 290296 - LUNAR_CYCLE_WEREWOLVES_MOON_BATH_DREAMS_7_WANING_CRESCENT: 'CommonBuffId' = 290297 - LUNAR_CYCLE_WEREWOLVES_MOON_BATH_DREAMS_PUT_TO_BED: 'CommonBuffId' = 290331 - LUNAR_CYCLE_WITCH_4_FULLMOON: 'CommonBuffId' = 295529 - LUNAR_CYCLE_WITCH_4_FULLMOON_TELEGRAPH: 'CommonBuffId' = 295530 - MAGIC_DUEL_COOLDOWN: 'CommonBuffId' = 223063 - MAGIC_DUEL_LOSE: 'CommonBuffId' = 217338 - MAGIC_DUEL_WIN: 'CommonBuffId' = 217334 - MAGIC_HQ_BROWSE_BOOKS_COOLDOWN: 'CommonBuffId' = 222436 - MAGIC_IS_REAL: 'CommonBuffId' = 108016 - MAGIC_IS_REAL_GREAT_STORYTELLER: 'CommonBuffId' = 109745 - MAGIC_SAGE_MISCHIEF: 'CommonBuffId' = 212864 - MAGIC_SAGE_PRACTICAL: 'CommonBuffId' = 212866 - MAGIC_SAGE_UNTAMED: 'CommonBuffId' = 212869 - MAGIC_VENUE_NPC_EXPERIMENT_COOLDOWN: 'CommonBuffId' = 223356 - MAGIC_VENUE_NPC_INTERMEDIATE: 'CommonBuffId' = 213055 - MAGIC_VENUE_NPC_NOVICE: 'CommonBuffId' = 213039 - MAILBOX_GET_GIFT_COOLDOWN: 'CommonBuffId' = 185510 - MAKER_MENTOR_SHARE_IDEAS_COOLDOWN: 'CommonBuffId' = 238695 - MAM_BORING_CONVERSATION: 'CommonBuffId' = 12465 - MAM_SOCIAL_REBUFF: 'CommonBuffId' = 12466 - MARBLES_ANOTHER_FOR_THE_COLLECTION: 'CommonBuffId' = 348852 - MARBLES_ANTED_PLAYER_DURING_GAME_HIDDEN: 'CommonBuffId' = 348866 - MARBLES_ANTED_PLAYER_PRE_GAME_HIDDEN: 'CommonBuffId' = 348864 - MARBLES_FINDERS_KEEPERS: 'CommonBuffId' = 346977 - MARBLES_GUARANTEE_SUCCESS_TURN_HIDDEN: 'CommonBuffId' = 354796 - MARBLES_LOST_MY_MARBLES: 'CommonBuffId' = 348853 - MARBLES_MARBLE_MASTER: 'CommonBuffId' = 347884 - MARBLES_RUMMAGE_COOLDOWN: 'CommonBuffId' = 359584 - MARBLES_SORE_THUMB: 'CommonBuffId' = 347885 - MARBLES_TRADE_MARBLE_COOLDOWN: 'CommonBuffId' = 359583 - MASCOT_LOSE_MASK: 'CommonBuffId' = 226767 - MASCOT_OUTFIT_ARTS: 'CommonBuffId' = 225125 - MASCOT_OUTFIT_TECH: 'CommonBuffId' = 225126 - MASCOT_PUMPED_UP: 'CommonBuffId' = 224911 - MASCOT_PUMP_UP_COOLDOWN: 'CommonBuffId' = 228796 - MASCOT_WHATS_THAT_SMELL: 'CommonBuffId' = 224912 - MASTER_TRAINER_PRACTICE_MAKES_PERFECT: 'CommonBuffId' = 327405 - MASTER_TRAINER_TOP_RIDER_TIPS: 'CommonBuffId' = 321406 - MATCHMAKING_BLIND_DATE_CATFISH: 'CommonBuffId' = 376224 - MATCHMAKING_USED_APP: 'CommonBuffId' = 374480 - MAX_FAT: 'CommonBuffId' = 38111 - MAX_FIT: 'CommonBuffId' = 38060 - MECHANICAL_SUIT_BODY_BEIGE_WHITE: 'CommonBuffId' = 226719 - MECHANICAL_SUIT_BODY_BLACK_BLUE: 'CommonBuffId' = 226294 - MECHANICAL_SUIT_BODY_BLUE_RED: 'CommonBuffId' = 226720 - MECHANICAL_SUIT_BODY_GRAY_BROWN: 'CommonBuffId' = 226721 - MECHANICAL_SUIT_BODY_GREEN_BROWN: 'CommonBuffId' = 226722 - MECHANICAL_SUIT_BODY_RED_GREEN: 'CommonBuffId' = 226723 - MECHANICAL_SUIT_BODY_WHITE_COPPER: 'CommonBuffId' = 226724 - MECHANICAL_SUIT_HELMET_BLACK_BLUE: 'CommonBuffId' = 226293 - MECHANICAL_SUIT_HELMET_BLACK_COPPER: 'CommonBuffId' = 226725 - MECHANICAL_SUIT_HELMET_BLACK_GOLD: 'CommonBuffId' = 226726 - MECHANICAL_SUIT_HELMET_BLACK_GRAY: 'CommonBuffId' = 226727 - MECHANICAL_SUIT_HELMET_BLUE_GRAY: 'CommonBuffId' = 226728 - MECHANICAL_SUIT_HELMET_GRAY_BLACK: 'CommonBuffId' = 226729 - MECHANICAL_SUIT_HELMET_GREEN_BLACK: 'CommonBuffId' = 226730 - MECHANICAL_SUIT_HOVER_MODE: 'CommonBuffId' = 226295 - MEDITATION_BOREDOM: 'CommonBuffId' = 119050 - MEDITATION_MOTIVE_AND_DECAY_HIGH_SKILL: 'CommonBuffId' = 121345 - MEDITATION_MOTIVE_AND_DECAY_LEVEL10: 'CommonBuffId' = 121346 - MEDITATION_MOTIVE_AND_DECAY_LOW_SKILL: 'CommonBuffId' = 121343 - MEDITATION_MOTIVE_AND_DECAY_MED_SKILL: 'CommonBuffId' = 121344 - MEDITATION_MOTIVE_DECAY_MASSAGE_CHAIR_FOOT_SOAK: 'CommonBuffId' = 273380 - MEDITATION_SELF_DISCOVERY_HOMEWORK_EPIPHANY: 'CommonBuffId' = 271218 - MEMORY_ANGRY: 'CommonBuffId' = 37548 - MEMORY_CONFIDENT: 'CommonBuffId' = 37547 - MEMORY_EMBARRASSED: 'CommonBuffId' = 37551 - MEMORY_FLIRTY: 'CommonBuffId' = 37545 - MEMORY_HAPPY: 'CommonBuffId' = 37541 - MEMORY_INSPIRED: 'CommonBuffId' = 37550 - MEMORY_SAD: 'CommonBuffId' = 37549 - MEMORY_SCARED: 'CommonBuffId' = 254532 - MENTALLY_RELAXED: 'CommonBuffId' = 118512 - MENTOREE_ACTIVITY_TABLE: 'CommonBuffId' = 30026 - MENTOREE_BY_MENTOR_PRO_ACTIVITY_TABLE: 'CommonBuffId' = 40516 - MENTOREE_BY_MENTOR_PRO_CHESS: 'CommonBuffId' = 40517 - MENTOREE_BY_MENTOR_PRO_CHILD_HOMEWORK: 'CommonBuffId' = 40518 - MENTOREE_BY_MENTOR_PRO_COMEDY: 'CommonBuffId' = 290396 - MENTOREE_BY_MENTOR_PRO_EASEL: 'CommonBuffId' = 40519 - MENTOREE_BY_MENTOR_PRO_EQUESTRIAN: 'CommonBuffId' = 332040 - MENTOREE_BY_MENTOR_PRO_FISHING: 'CommonBuffId' = 207777 - MENTOREE_BY_MENTOR_PRO_GUITAR: 'CommonBuffId' = 40527 - MENTOREE_BY_MENTOR_PRO_HANDINESS: 'CommonBuffId' = 40520 - MENTOREE_BY_MENTOR_PRO_PIANO: 'CommonBuffId' = 40528 - MENTOREE_BY_MENTOR_PRO_PIPE_ORGAN: 'CommonBuffId' = 151304 - MENTOREE_BY_MENTOR_PRO_PROGRAMMING: 'CommonBuffId' = 290394 - MENTOREE_BY_MENTOR_PRO_PUNCHING_BAG: 'CommonBuffId' = 40521 - MENTOREE_BY_MENTOR_PRO_ROCKET_SCIENCE: 'CommonBuffId' = 290395 - MENTOREE_BY_MENTOR_PRO_TEEN_HOMEWORK: 'CommonBuffId' = 40522 - MENTOREE_BY_MENTOR_PRO_TREADMILL: 'CommonBuffId' = 40523 - MENTOREE_BY_MENTOR_PRO_VIOLIN: 'CommonBuffId' = 40529 - MENTOREE_BY_MENTOR_PRO_WORKOUT_MACHINE: 'CommonBuffId' = 40524 - MENTOREE_BY_MENTOR_PRO_WRITING: 'CommonBuffId' = 40525 - MENTOREE_CHESS: 'CommonBuffId' = 30695 - MENTOREE_CHILD_HOMEWORK: 'CommonBuffId' = 29295 - MENTOREE_COMEDY: 'CommonBuffId' = 290391 - MENTOREE_EASEL: 'CommonBuffId' = 30024 - MENTOREE_EQUESTRIAN_SKILL: 'CommonBuffId' = 329328 - MENTOREE_GUITAR: 'CommonBuffId' = 38157 - MENTOREE_HANDINESS: 'CommonBuffId' = 38432 - MENTOREE_PIANO: 'CommonBuffId' = 40486 - MENTOREE_PIPE_ORGAN: 'CommonBuffId' = 151303 - MENTOREE_PROGRAMMING: 'CommonBuffId' = 290390 - MENTOREE_PUNCHING_BAG: 'CommonBuffId' = 9171 - MENTOREE_ROCKET_SCIENCE: 'CommonBuffId' = 290392 - MENTOREE_TEEN_HOMEWORK: 'CommonBuffId' = 29154 - MENTOREE_TREADMILL: 'CommonBuffId' = 9167 - MENTOREE_VIOLIN: 'CommonBuffId' = 40487 - MENTOREE_WORKOUT_MACHINE: 'CommonBuffId' = 9163 - MENTOREE_WRITING: 'CommonBuffId' = 38056 - MENTORER: 'CommonBuffId' = 12467 - MERMAID_AQUATIC_LURE_EFFECTIVE_SKILL: 'CommonBuffId' = 210725 - MERMAID_BURNING_WEATHER: 'CommonBuffId' = 213441 - MERMAID_DISCOVERY_CHECK: 'CommonBuffId' = 215253 - MERMAID_DREAMING: 'CommonBuffId' = 215417 - MERMAID_HEIGHTENED_SENSATIONS: 'CommonBuffId' = 206216 - MERMAID_HYDRATION_DEHYDRATED: 'CommonBuffId' = 208501 - MERMAID_HYDRATION_DRIED_SCALES: 'CommonBuffId' = 208500 - MERMAID_HYPNOTIZE: 'CommonBuffId' = 213447 - MERMAID_INTENSE_TINGLING: 'CommonBuffId' = 206275 - MERMAID_IS_WADING: 'CommonBuffId' = 212613 - MERMAID_OCEAN_THREAT: 'CommonBuffId' = 207173 - MERMAID_OF_AGE: 'CommonBuffId' = 215478 - MERMAID_OUTSIDE_IN_RAIN: 'CommonBuffId' = 208387 - MERMAID_OUTSIDE_IN_RAIN_HEAV_YRAIN: 'CommonBuffId' = 209373 - MERMAID_OUTSIDE_IN_RAIN_NO_MODIFER: 'CommonBuffId' = 209379 - MERMAID_POWER_CHARMER: 'CommonBuffId' = 206027 - MERMAID_POWER_COOLDOWN_AQUATIC_LURE: 'CommonBuffId' = 205864 - MERMAID_POWER_COOLDOWN_CALL_STORM: 'CommonBuffId' = 205865 - MERMAID_POWER_COOLDOWN_CHARMER: 'CommonBuffId' = 205848 - MERMAID_POWER_COOLDOWN_INSPIRING: 'CommonBuffId' = 205849 - MERMAID_POWER_COOLDOWN_MERFOLK_KISS: 'CommonBuffId' = 205866 - MERMAID_POWER_COOLDOWN_QUESTION: 'CommonBuffId' = 205850 - MERMAID_POWER_COOLDOWN_REQUIEM: 'CommonBuffId' = 205851 - MERMAID_POWER_COOLDOWN_SIRENS_CALL: 'CommonBuffId' = 205867 - MERMAID_POWER_COOLDOWN_SUMMON_OCEAN_THREAT: 'CommonBuffId' = 205869 - MERMAID_POWER_INSPIRING: 'CommonBuffId' = 206025 - MERMAID_POWER_MERFOLK_KISS: 'CommonBuffId' = 206040 - MERMAID_POWER_QUESTION: 'CommonBuffId' = 206031 - MERMAID_POWER_REQUIEM: 'CommonBuffId' = 206037 - MERMAID_SHALLOW_WATER_CHECK: 'CommonBuffId' = 212420 - MERMAID_SHALLOW_WATER_VFX: 'CommonBuffId' = 212376 - MERMAID_SIREN_CALLED: 'CommonBuffId' = 213444 - MERMAID_STRANGE_REACTION: 'CommonBuffId' = 206172 - MERMAID_STRANGE_SENSATIONS: 'CommonBuffId' = 205931 - MERMAID_SWIM_WALK_STYLE: 'CommonBuffId' = 199046 - MERMAID_SWIM_WALK_STYLE_OCEAN: 'CommonBuffId' = 210128 - MERMAID_TEMPORARY_DISCOVERY: 'CommonBuffId' = 215412 - MERMAID_TRAIT: 'CommonBuffId' = 205407 - MESSED_UP_ENDING: 'CommonBuffId' = 103137 - MIDLIFE_CRISIS_DESIRE_FOR_EXCITEMENT: 'CommonBuffId' = 313567 - MIDLIFE_CRISIS_HIDDEN_BEFRIEND_A_STRAY: 'CommonBuffId' = 332556 - MIDLIFE_CRISIS_HIDDEN_CREATIVE_QUALITY_INCREASE: 'CommonBuffId' = 317909 - MIDLIFE_CRISIS_HIDDEN_GOLDEN_DATE: 'CommonBuffId' = 323622 - MIDLIFE_CRISIS_HIDDEN_MAX_A_SKILL: 'CommonBuffId' = 334199 - MIDLIFE_CRISIS_HIDDEN_SMART_HUB: 'CommonBuffId' = 323724 - MIDLIFE_CRISIS_HIDDEN_STRESS_ABOUT_LOST_TIME_COOLDOWN: 'CommonBuffId' = 318050 - MIDLIFE_CRISIS_MARCH_OF_TIME: 'CommonBuffId' = 313568 - MIDLIFE_CRISIS_RANDOM_MOOD_ANGRY: 'CommonBuffId' = 321214 - MIDLIFE_CRISIS_RANDOM_MOOD_CONFIDENT: 'CommonBuffId' = 321215 - MIDLIFE_CRISIS_RANDOM_MOOD_DAZED: 'CommonBuffId' = 321216 - MIDLIFE_CRISIS_RANDOM_MOOD_ENERGIZED: 'CommonBuffId' = 321217 - MIDLIFE_CRISIS_RANDOM_MOOD_FLIRTY: 'CommonBuffId' = 321218 - MIDLIFE_CRISIS_RANDOM_MOOD_FOCUSED: 'CommonBuffId' = 321219 - MIDLIFE_CRISIS_RANDOM_MOOD_INSPIRED: 'CommonBuffId' = 321220 - MIDLIFE_CRISIS_RANDOM_MOOD_SAD: 'CommonBuffId' = 321221 - MIDLIFE_CRISIS_RANDOM_MOOD_SCARED: 'CommonBuffId' = 321222 - MIDLIFE_CRISIS_RESOLUTION_ADVENTURE: 'CommonBuffId' = 314166 - MIDLIFE_CRISIS_RESOLUTION_CREATE: 'CommonBuffId' = 314167 - MIDLIFE_CRISIS_RESOLUTION_RELATIONSHIP: 'CommonBuffId' = 314169 - MIDLIFE_CRISIS_RESOLUTION_SUCCESS: 'CommonBuffId' = 314168 - MIDLIFE_CRISIS_TYPE_ADVENTURE: 'CommonBuffId' = 313922 - MIDLIFE_CRISIS_TYPE_CREATE: 'CommonBuffId' = 313923 - MIDLIFE_CRISIS_TYPE_RELATIONSHIP: 'CommonBuffId' = 313924 - MIDLIFE_CRISIS_TYPE_SUCCESS: 'CommonBuffId' = 313925 - MILITARY_CAREER_ADMIRE_MEDALS_HIGH: 'CommonBuffId' = 206624 - MILITARY_CAREER_ADMIRE_MEDALS_LOW: 'CommonBuffId' = 206622 - MILITARY_CAREER_ADMIRE_MEDALS_MEDIUM: 'CommonBuffId' = 206623 - MILITARY_CAREER_PORE_OVER_CASE_FILES: 'CommonBuffId' = 204695 - MILITARY_CAREER_RUN_DRILLS: 'CommonBuffId' = 204696 - MIND_CONTROL_SIT_COOLDOWN: 'CommonBuffId' = 115201 - MIND_POWERS_ALLURING_VISAGE_SELF: 'CommonBuffId' = 150023 - MIND_POWERS_ALLURING_VISAGE_SELF_2: 'CommonBuffId' = 150036 - MIND_POWERS_ALLURING_VISAGE_SELF_3: 'CommonBuffId' = 150037 - MIND_POWERS_ALLURING_VISAGE_TARGET: 'CommonBuffId' = 150029 - MIND_POWERS_ALLURING_VISAGE_TARGET_2: 'CommonBuffId' = 150052 - MIND_POWERS_ALLURING_VISAGE_TARGET_3: 'CommonBuffId' = 150053 - MIND_POWERS_COMMAND_BE_MEAN: 'CommonBuffId' = 150407 - MIND_POWERS_COMMAND_CLEAN: 'CommonBuffId' = 150147 - MIND_POWERS_COMMAND_REPAIR: 'CommonBuffId' = 150228 - MIND_POWERS_COMMAND_SIT: 'CommonBuffId' = 150156 - MIND_POWERS_COMMAND_WAKE_UP: 'CommonBuffId' = 150295 - MIND_POWERS_COMMAND_WORKOUT: 'CommonBuffId' = 150240 - MIND_POWERS_IRRESISTIBLE_SLUMBER: 'CommonBuffId' = 150475 - MIND_POWERS_MESMERIZE: 'CommonBuffId' = 150429 - MIND_POWERS_MESMERIZE_NIGHTTIME: 'CommonBuffId' = 155908 - MIN_FAT: 'CommonBuffId' = 77836 - MIN_FIT: 'CommonBuffId' = 77837 - MIRROR_MADE_SILLY_FACE: 'CommonBuffId' = 24193 - MIRROR_PSYCHED_UP: 'CommonBuffId' = 39888 - MISCHIEF_PRANKS_COOLDOWN_FAKE_ALIEN_CONTACT: 'CommonBuffId' = 98334 - MISCHIEF_PRANKS_COOLDOWN_FILL_BOSS_OFFICE_WITH_BALLOONS: 'CommonBuffId' = 98335 - MISCHIEF_PRANKS_COOLDOWN_FREE_THE_FROGS: 'CommonBuffId' = 98336 - MISCHIEF_PRANKS_COOLDOWN_GENERIC: 'CommonBuffId' = 98337 - MISCHIEF_PRANKS_COOLDOWN_HACK_INTO_COWORKERS_EMAIL: 'CommonBuffId' = 98338 - MISCHIEF_PRANKS_COOLDOWN_LURE_LLAMA_TO_THE_OFFICE: 'CommonBuffId' = 98339 - MISCHIEF_PRANKS_COOLDOWN_MAKE_ALL_INVISIBLE_INK_VISIBLE: 'CommonBuffId' = 98340 - MISCHIEF_PRANKS_COOLDOWN_MUSTACHES_FOR_ART: 'CommonBuffId' = 98341 - MISCHIEF_PRANKS_COOLDOWN_REARRANGE_KEYS_ON_THE_KEYBOARD: 'CommonBuffId' = 98342 - MISCHIEF_PRANKS_COOLDOWN_SELL_TEST_ANSWERS: 'CommonBuffId' = 98343 - MISCHIEF_PRANKS_COOLDOWN_SILLY_PUTTY_IN_THE_MIC: 'CommonBuffId' = 98344 - MISCHIEF_PRANKS_COOLDOWN_START_A_FOOD_FIGHT: 'CommonBuffId' = 98345 - MISCHIEF_PRANKS_COOLDOWN_STUFF_GEEKS_IN_LOCKER: 'CommonBuffId' = 98346 - MISCHIEF_PRANKS_COOLDOWN_STUFF_JOCKS_IN_LOCKER: 'CommonBuffId' = 98347 - MISCHIEF_PRANKS_COOLDOWN_UNLEASH_THE_GERBILS: 'CommonBuffId' = 98348 - MISCHIEF_PRANKS_COOLDOWN_WATER_CUP_PRANK: 'CommonBuffId' = 98349 - MISCHIEF_PRANKS_COOLDOWN_WRAP_BACON_AROUND_EVERYTHING: 'CommonBuffId' = 98350 - MISCHIEF_PRANKS_FAKE_ALIEN_CONTACT: 'CommonBuffId' = 36014 - MISCHIEF_PRANKS_FILL_BOSS_OFFICE_WITH_BALLOONS: 'CommonBuffId' = 36015 - MISCHIEF_PRANKS_FREE_THE_FROGS: 'CommonBuffId' = 36016 - MISCHIEF_PRANKS_GENERIC: 'CommonBuffId' = 26965 - MISCHIEF_PRANKS_HACK_INTO_COWORKERS_EMAIL: 'CommonBuffId' = 36020 - MISCHIEF_PRANKS_LURE_LLAMA_TO_THE_OFFICE: 'CommonBuffId' = 36013 - MISCHIEF_PRANKS_MAKE_ALL_INVISIBLE_INK_VISIBLE: 'CommonBuffId' = 36019 - MISCHIEF_PRANKS_MUSTACHES_FOR_ART: 'CommonBuffId' = 36018 - MISCHIEF_PRANKS_REARRANGE_KEYS_ON_THE_KEYBOARD: 'CommonBuffId' = 36021 - MISCHIEF_PRANKS_SELL_TEST_ANSWERS: 'CommonBuffId' = 35983 - MISCHIEF_PRANKS_SILLY_PUTTY_IN_THE_MIC: 'CommonBuffId' = 36017 - MISCHIEF_PRANKS_START_A_FOOD_FIGHT: 'CommonBuffId' = 35986 - MISCHIEF_PRANKS_STUFF_GEEKS_IN_LOCKER: 'CommonBuffId' = 35984 - MISCHIEF_PRANKS_STUFF_JOCKS_IN_LOCKER: 'CommonBuffId' = 35985 - MISCHIEF_PRANKS_SUCCESSFUL: 'CommonBuffId' = 35729 - MISCHIEF_PRANKS_SUCCESSFUL_OBJECT: 'CommonBuffId' = 98380 - MISCHIEF_PRANKS_UNLEASH_THE_GERBILS: 'CommonBuffId' = 35987 - MISCHIEF_PRANKS_UNSUCCESSFUL: 'CommonBuffId' = 35732 - MISCHIEF_PRANKS_WATER_CUP_PRANK: 'CommonBuffId' = 35889 - MISCHIEF_PRANKS_WRAP_BACON_AROUND_EVERYTHING: 'CommonBuffId' = 35672 - MISCHIEF_TEEN_PRANKS_CAUGHT: 'CommonBuffId' = 284916 - MISCHIEF_TEEN_PRANKS_NO_CATCHING: 'CommonBuffId' = 284914 - MISCHIEF_TEEN_PRANKS_PASSWORD_FAIL: 'CommonBuffId' = 285101 - MISCHIEF_TEEN_PRANKS_PASSWORD_SUCCESS: 'CommonBuffId' = 285102 - MISCHIEF_TEEN_PRANKS_PA_SPEAKER_FAIL: 'CommonBuffId' = 285104 - MISCHIEF_TEEN_PRANKS_PA_SPEAKER_SUCCESS: 'CommonBuffId' = 285105 - MISCHIEF_TEEN_PRANKS_STINK_CAPSULE_FAIL: 'CommonBuffId' = 285106 - MISCHIEF_TEEN_PRANKS_STINK_CAPSULE_TARGET: 'CommonBuffId' = 285107 - MISCHIEF_TEEN_PRANKS_SYSTEM_DARED_HIDDEN: 'CommonBuffId' = 285680 - MISCHIEF_TEEN_PRANKS_SYSTEM_FRAMED_HIDDEN: 'CommonBuffId' = 285700 - MISCHIEF_TEEN_PRANKS_SYSTEM_PRANKED_HIDDEN: 'CommonBuffId' = 285709 - MISCHIEF_TEEN_PRANKS_SYSTEM_RECENT_PRANK_HIDDEN: 'CommonBuffId' = 285500 - MISCHIEF_TEEN_PRANKS_URBAN_MYTH_EFFECT: 'CommonBuffId' = 285103 - MISCHIEF_TEEN_PRANKS_URBAN_MYTH_VAMPIRE: 'CommonBuffId' = 285100 - MISCHIEF_TEEN_PRANKS_WHITEBOARD_SUCCESS: 'CommonBuffId' = 285108 - MISSING_PETS_COMFORTED: 'CommonBuffId' = 173655 - MISSING_PETS_MISSING_MY_FURRY_FRIEND: 'CommonBuffId' = 173548 - MISSING_PETS_PROVIDE_WELCOME_BACK: 'CommonBuffId' = 176246 - MISSING_PETS_WELCOME_BACK: 'CommonBuffId' = 173838 - MISSING_PETS_WELCOME_BACK_AUTONOMY: 'CommonBuffId' = 174547 - MISSING_PETS_WOULDNT_SAY_IM_MISSING_IT: 'CommonBuffId' = 173560 - MOLD_SYSTEM_AFRAID_OF_THE_MOLD: 'CommonBuffId' = 345605 - MOLD_SYSTEM_BLOW_SPORES_AUTONOMOUS_COOLDOWN: 'CommonBuffId' = 356558 - MOLD_SYSTEM_BURN_MOLD_PILE_DONT_EXTINGUISH: 'CommonBuffId' = 353285 - MOLD_SYSTEM_FREEZE_SICKNESS_COMMODITIES: 'CommonBuffId' = 355805 - MOLD_SYSTEM_FUNGAL_OVERGROWTH_AUTONOMOUS_COOLDOWN: 'CommonBuffId' = 356556 - MOLD_SYSTEM_MOLD_FREE: 'CommonBuffId' = 342352 - MOLD_SYSTEM_MUSHROOM_RAGE: 'CommonBuffId' = 342351 - MOLD_SYSTEM_MUSHROOM_RAGE_EAT: 'CommonBuffId' = 356187 - MOLD_SYSTEM_PET_BLOCK_SICKNESS: 'CommonBuffId' = 357356 - MOLD_SYSTEM_PET_SICKNESS: 'CommonBuffId' = 357354 - MOLD_SYSTEM_SPOIL_FOOD_AUTONOMOUS_COOLDOWN: 'CommonBuffId' = 356557 - MOLD_SYSTEM_SPORE_SICKNESS: 'CommonBuffId' = 342350 - MOLD_SYSTEM_SPREAD_SPORES_AUTONOMOUS_COOLDOWN: 'CommonBuffId' = 356537 - MOLD_SYSTEM_TOXIC_CHILDREN: 'CommonBuffId' = 345833 - MOLD_SYSTEM_TOXIC_TIER_1_MILD: 'CommonBuffId' = 342347 - MOLD_SYSTEM_TOXIC_TIER_2_SEVERE: 'CommonBuffId' = 342348 - MOLD_SYSTEM_TOXIC_TIER_3_DEADLY: 'CommonBuffId' = 342349 - MOOD_BUFFS_HIDDEN_SCARED_TRACK_SCARED: 'CommonBuffId' = 251722 - MOOD_BUFFS_HIDDEN_SCARED_TRACK_TERRIFIED: 'CommonBuffId' = 251723 - MOOD_BUFFS_HORSES_HIDDEN_ANGRY: 'CommonBuffId' = 319703 - MOOD_BUFFS_HORSES_HIDDEN_ASLEEP: 'CommonBuffId' = 321110 - MOOD_BUFFS_HORSES_HIDDEN_CONFIDENT: 'CommonBuffId' = 319704 - MOOD_BUFFS_HORSES_HIDDEN_DAZED: 'CommonBuffId' = 319711 - MOOD_BUFFS_HORSES_HIDDEN_FINE: 'CommonBuffId' = 319708 - MOOD_BUFFS_HORSES_HIDDEN_HAPPY: 'CommonBuffId' = 319705 - MOOD_BUFFS_HORSES_HIDDEN_SAD: 'CommonBuffId' = 319712 - MOOD_BUFFS_HORSES_HIDDEN_SCARED: 'CommonBuffId' = 319710 - MOOD_BUFFS_HORSES_HIDDEN_TENSE: 'CommonBuffId' = 319707 - MOOD_BUFFS_HORSES_HIDDEN_UNCOMFORTABLE: 'CommonBuffId' = 319706 - MOOD_BUFFS_HORSES_HIDDEN_VERY_ANGRY: 'CommonBuffId' = 321118 - MOOD_BUFFS_HORSES_HIDDEN_VERY_CONFIDENT: 'CommonBuffId' = 321119 - MOOD_BUFFS_HORSES_HIDDEN_VERY_DAZED: 'CommonBuffId' = 321120 - MOOD_BUFFS_HORSES_HIDDEN_VERY_HAPPY: 'CommonBuffId' = 321121 - MOOD_BUFFS_HORSES_HIDDEN_VERY_SAD: 'CommonBuffId' = 321122 - MOOD_BUFFS_HORSES_HIDDEN_VERY_SCARED: 'CommonBuffId' = 321123 - MOOD_BUFFS_HORSES_HIDDEN_VERY_TENSE: 'CommonBuffId' = 321124 - MOOD_BUFFS_HORSES_HIDDEN_VERY_UNCOMFORTABLE: 'CommonBuffId' = 321125 - MOOD_BUFFS_LUNAR_CYCLE_MOON_BATHE_ALIEN_NOSTALGIA: 'CommonBuffId' = 300237 - MOOD_BUFFS_LUNAR_CYCLE_MOON_BATHE_ANTI_SPACED: 'CommonBuffId' = 295994 - MOOD_BUFFS_LUNAR_CYCLE_MOON_BATHE_ANTI_SPACED_WEREWOLF: 'CommonBuffId' = 295995 - MOOD_BUFFS_LUNAR_CYCLE_MOON_BATHE_CELESTIAL_REFRESH: 'CommonBuffId' = 289026 - MOOD_BUFFS_LUNAR_CYCLE_MOON_BATHE_CELESTIAL_REFRESH_WEREWOLF: 'CommonBuffId' = 295871 - MOOD_BUFFS_LUNAR_CYCLE_MOON_BATHE_FRISKY_MOON: 'CommonBuffId' = 295898 - MOOD_BUFFS_LUNAR_CYCLE_MOON_BATHE_FRISKY_MOON_WEREWOLF: 'CommonBuffId' = 295899 - MOOD_BUFFS_LUNAR_CYCLE_MOON_BATHE_JOYFUL_MOON: 'CommonBuffId' = 295997 - MOOD_BUFFS_LUNAR_CYCLE_MOON_BATHE_LUNAR_GLEE_FIRST_QUARTER: 'CommonBuffId' = 295893 - MOOD_BUFFS_LUNAR_CYCLE_MOON_BATHE_LUNAR_GLEE_FIRST_QUARTER_WEREWOLF: 'CommonBuffId' = 295894 - MOOD_BUFFS_LUNAR_CYCLE_MOON_BATHE_LUNAR_GLEE_THIRD_QUARTER: 'CommonBuffId' = 295992 - MOOD_BUFFS_LUNAR_CYCLE_MOON_BATHE_LUNAR_GLEE_THIRD_QUARTER_WEREWOLF: 'CommonBuffId' = 295993 - MOOD_BUFFS_LUNAR_CYCLE_MOON_BATHE_LUNAR_REASSURANCE: 'CommonBuffId' = 295990 - MOOD_BUFFS_LUNAR_CYCLE_MOON_BATHE_LUNAR_REASSURANCE_WEREWOLF: 'CommonBuffId' = 295991 - MOOD_BUFFS_LUNAR_CYCLE_MOON_BATHE_MOODY_MOON: 'CommonBuffId' = 289024 - MOOD_BUFFS_LUNAR_CYCLE_MOON_BATHE_NORMIE_SHINE: 'CommonBuffId' = 295872 - MOOD_BUFFS_LUNAR_CYCLE_MOON_BATHE_RECENT_MOON_BATHE: 'CommonBuffId' = 289022 - MOOD_BUFFS_LUNAR_CYCLE_MOON_BATHE_SPACE_ROCK_AMUSEMENT: 'CommonBuffId' = 295895 - MOOD_BUFFS_LUNAR_CYCLE_MOON_BATHE_SPACE_ROCK_AMUSEMENT_WEREWOLF: 'CommonBuffId' = 295896 - MOOD_BUFFS_LUNAR_CYCLE_MOON_BATHE_SPACE_ROCK_STRESS: 'CommonBuffId' = 295897 - MOOD_BUFFS_LUNAR_CYCLE_MOON_BATHE_WOLF_SHINE: 'CommonBuffId' = 289023 - MOOD_BUFFS_PETS_CATS_HIDDEN_ANXIOUS: 'CommonBuffId' = 158194 - MOOD_BUFFS_PETS_CAT_HIDDEN_ANGRY: 'CommonBuffId' = 158401 - MOOD_BUFFS_PETS_CAT_HIDDEN_ASLEEP: 'CommonBuffId' = 158559 - MOOD_BUFFS_PETS_CAT_HIDDEN_DROWSY: 'CommonBuffId' = 158140 - MOOD_BUFFS_PETS_CAT_HIDDEN_FINE: 'CommonBuffId' = 158402 - MOOD_BUFFS_PETS_CAT_HIDDEN_FLIRTY: 'CommonBuffId' = 158403 - MOOD_BUFFS_PETS_CAT_HIDDEN_HAPPY: 'CommonBuffId' = 158405 - MOOD_BUFFS_PETS_CAT_HIDDEN_SCARED: 'CommonBuffId' = 158404 - MOOD_BUFFS_PETS_DOG_HIDDEN_ANGRY: 'CommonBuffId' = 158280 - MOOD_BUFFS_PETS_DOG_HIDDEN_ANXIOUS: 'CommonBuffId' = 158279 - MOOD_BUFFS_PETS_DOG_HIDDEN_ASHAMED: 'CommonBuffId' = 158286 - MOOD_BUFFS_PETS_DOG_HIDDEN_ASLEEP: 'CommonBuffId' = 158285 - MOOD_BUFFS_PETS_DOG_HIDDEN_EXCITED: 'CommonBuffId' = 158276 - MOOD_BUFFS_PETS_DOG_HIDDEN_FINE: 'CommonBuffId' = 158284 - MOOD_BUFFS_PETS_DOG_HIDDEN_FLIRTY: 'CommonBuffId' = 158281 - MOOD_BUFFS_PETS_DOG_HIDDEN_HAPPY: 'CommonBuffId' = 158283 - MOOD_BUFFS_PETS_DOG_HIDDEN_MOPEY: 'CommonBuffId' = 158278 - MOOD_BUFFS_PETS_DOG_HIDDEN_SAD: 'CommonBuffId' = 158277 - MOOD_BUFFS_PETS_DOG_HIDDEN_SCARED: 'CommonBuffId' = 158282 - MOOD_BUFFS_SOCIALS_ANTI_ECO_DRAMA_DID_IT_JUST_MOVE: 'CommonBuffId' = 238413 - MOOD_BUFFS_SOCIALS_ANTI_ECO_DRAMA_FINE_VINTAGE: 'CommonBuffId' = 238419 - MOOD_BUFFS_SOCIALS_ANTI_ECO_DRAMA_FORCED_TO_RECYCLE: 'CommonBuffId' = 238409 - MOOD_BUFFS_SOCIALS_ANTI_ECO_DRAMA_HANDS_ON: 'CommonBuffId' = 238420 - MOOD_BUFFS_SOCIALS_ANTI_ECO_DRAMA_HOW_PEDESTRIAN: 'CommonBuffId' = 238410 - MOOD_BUFFS_SOCIALS_ANTI_ECO_DRAMA_SAVING_THE_WORLD: 'CommonBuffId' = 238418 - MOOD_BUFFS_SOCIALS_ANTI_ECO_DRAMA_SUPERB: 'CommonBuffId' = 238412 - MOOD_BUFFS_SOCIALS_ANTI_ECO_DRAMA_THIS_IS_EXACTLY_WHAT_THEY_WANT: 'CommonBuffId' = 238414 - MOOD_BUFFS_SOCIALS_ANTI_ECO_DRAMA_WATCH_THE_WORLD_BURN: 'CommonBuffId' = 238076 - MOOD_BUFFS_SOCIALS_ANTI_ECO_DRAMA_WHY_ARENT_WE_TALKING_ABOUT_ME: 'CommonBuffId' = 238408 - MOOD_BUFFS_SOCIALS_FEELING_IMPORTANT: 'CommonBuffId' = 107469 - MOOD_BUFFS_SOCIALS_FOLK_TALE_SUCCESS_LISTENERS: 'CommonBuffId' = 174856 - MOOD_BUFFS_SOCIALS_FOOLED_ME_ONCE: 'CommonBuffId' = 107461 - MOOD_BUFFS_SOCIALS_GREAT_INVESTMENT_TIPS: 'CommonBuffId' = 107459 - MOOD_BUFFS_SOCIALS_JUICY_OFFICE_GOSSIP: 'CommonBuffId' = 107236 - MOOD_HIDDEN_ANGRY: 'CommonBuffId' = 12831 - MOOD_HIDDEN_ASLEEP: 'CommonBuffId' = 27147 - MOOD_HIDDEN_BORED: 'CommonBuffId' = 12829 - MOOD_HIDDEN_CONFIDENT: 'CommonBuffId' = 12830 - MOOD_HIDDEN_DEPRESSED: 'CommonBuffId' = 12832 - MOOD_HIDDEN_ELATED: 'CommonBuffId' = 12834 - MOOD_HIDDEN_EMBARRASSED: 'CommonBuffId' = 12835 - MOOD_HIDDEN_ENERGIZED: 'CommonBuffId' = 12836 - MOOD_HIDDEN_ENRAGED: 'CommonBuffId' = 12840 - MOOD_HIDDEN_FEARLESS: 'CommonBuffId' = 12814 - MOOD_HIDDEN_FINE_DEFAULT: 'CommonBuffId' = 12837 - MOOD_HIDDEN_FLIRTY: 'CommonBuffId' = 12838 - MOOD_HIDDEN_FOCUSED: 'CommonBuffId' = 12839 - MOOD_HIDDEN_FURIOUS: 'CommonBuffId' = 12827 - MOOD_HIDDEN_GLOOMIER: 'CommonBuffId' = 27155 - MOOD_HIDDEN_GLOOMY: 'CommonBuffId' = 27154 - MOOD_HIDDEN_HAPPY: 'CommonBuffId' = 12841 - MOOD_HIDDEN_HOT_HEAD1: 'CommonBuffId' = 27321 - MOOD_HIDDEN_HOT_HEAD2: 'CommonBuffId' = 27323 - MOOD_HIDDEN_HOT_HEAD3: 'CommonBuffId' = 27320 - MOOD_HIDDEN_HUMILIATED: 'CommonBuffId' = 12842 - MOOD_HIDDEN_HYSTERICAL: 'CommonBuffId' = 12843 - MOOD_HIDDEN_IMAGINATIVE: 'CommonBuffId' = 12844 - MOOD_HIDDEN_INSPIRED: 'CommonBuffId' = 12845 - MOOD_HIDDEN_IN_THE_ZONE: 'CommonBuffId' = 12846 - MOOD_HIDDEN_MISERABLE: 'CommonBuffId' = 12847 - MOOD_HIDDEN_MORTIFIED: 'CommonBuffId' = 12848 - MOOD_HIDDEN_MUSERER_TRAIT_REPLACEMENT: 'CommonBuffId' = 37939 - MOOD_HIDDEN_MUSER_TRAIT_REPLACEMENT: 'CommonBuffId' = 27107 - MOOD_HIDDEN_NEUTRAL: 'CommonBuffId' = 12849 - MOOD_HIDDEN_PASSIONATE: 'CommonBuffId' = 12850 - MOOD_HIDDEN_PLAYFUL: 'CommonBuffId' = 12851 - MOOD_HIDDEN_POSSESSED: 'CommonBuffId' = 201540 - MOOD_HIDDEN_PUMPED: 'CommonBuffId' = 12852 - MOOD_HIDDEN_SAD: 'CommonBuffId' = 12853 - MOOD_HIDDEN_SILLY: 'CommonBuffId' = 12854 - MOOD_HIDDEN_SLOSHED: 'CommonBuffId' = 12855 - MOOD_HIDDEN_STRESSED: 'CommonBuffId' = 12856 - MOOD_HIDDEN_TENSE: 'CommonBuffId' = 12857 - MOOD_HIDDEN_UNCOMFORTABLE: 'CommonBuffId' = 12858 - MOOD_PETS_HIDDEN_HYPER: 'CommonBuffId' = 157880 - MOOD_REPLACEMENT_LOW_SOCIAL_HIDDEN: 'CommonBuffId' = 389884 - MOTHER_PLANT_ENERGIZED: 'CommonBuffId' = 204364 - MOTHER_PLANT_HOSTILE_REASON_WITH_INFECTED_SOCIALIZATION_BAD: 'CommonBuffId' = 204372 - MOTHER_PLANT_KNOCKED_OUT: 'CommonBuffId' = 204119 - MOTHER_PLANT_MADE_REQUEST: 'CommonBuffId' = 204363 - MOTHER_PLANT_RECENTLY_COMMANDED_FIGHT: 'CommonBuffId' = 207294 - MOTHER_PLANT_RECENTLY_FOUGHT: 'CommonBuffId' = 204374 - MOTHER_PLANT_RECENTLY_FOUGHT_BIG_FIGHT: 'CommonBuffId' = 206575 - MOTHER_PLANT_REVIVE: 'CommonBuffId' = 204114 - MOTHER_PLANT_SUCCESS: 'CommonBuffId' = 205007 - MOTIVES_ALL_MOTIVES_HIGH: 'CommonBuffId' = 26886 - MOTIVES_ALL_MOTIVES_PRETTY_HIGH: 'CommonBuffId' = 27116 - MOTIVES_BLADDER_HAS_TO_PEE: 'CommonBuffId' = 27109 - MOTIVES_BLADDER_REALLY_HAS_TO_PEE: 'CommonBuffId' = 27108 - MOTIVES_ENERGY_EXHAUSTED: 'CommonBuffId' = 12818 - MOTIVES_ENERGY_TIRED: 'CommonBuffId' = 12816 - MOTIVES_ENERGY_TRANQUILIZED: 'CommonBuffId' = 31566 - MOTIVES_FUN_DESPERATE_FOR_FUN: 'CommonBuffId' = 12819 - MOTIVES_FUN_HIGH: 'CommonBuffId' = 256947 - MOTIVES_FUN_NEEDS_AMUSEMENT: 'CommonBuffId' = 27113 - MOTIVES_HIDDEN_BLADDER_FILL_BLADDER: 'CommonBuffId' = 137304 - MOTIVES_HORSE_SUPPRESS_ALL: 'CommonBuffId' = 330660 - MOTIVES_HUMANOID_ROBOTS_DEPLETED_CHARGE: 'CommonBuffId' = 223435 - MOTIVES_HUMANOID_ROBOTS_DURABILITY_BREAKING_VFX: 'CommonBuffId' = 222670 - MOTIVES_HUMANOID_ROBOTS_DURABILITY_BROKEN_STATE: 'CommonBuffId' = 218479 - MOTIVES_HUMANOID_ROBOTS_DURABILITY_BROKEN_STATE_RUSTING: 'CommonBuffId' = 223429 - MOTIVES_HUMANOID_ROBOTS_DURABILITY_BROKEN_STATE_TRACKER: 'CommonBuffId' = 224389 - MOTIVES_HUMANOID_ROBOTS_DURABILITY_DILAPITATED: 'CommonBuffId' = 223431 - MOTIVES_HUMANOID_ROBOTS_DURABILITY_LOSS_FROM_WATER_HIGH: 'CommonBuffId' = 229576 - MOTIVES_HUMANOID_ROBOTS_DURABILITY_LOSS_FROM_WATER_LOW: 'CommonBuffId' = 229867 - MOTIVES_HUMANOID_ROBOTS_DURABILITY_ON_THE_FRITZ: 'CommonBuffId' = 223428 - MOTIVES_HUMANOID_ROBOTS_DURABILITY_STOP_LOSS: 'CommonBuffId' = 229903 - MOTIVES_HUMANOID_ROBOTS_DURABILITY_STOP_LOSS_TEMPORARY: 'CommonBuffId' = 230399 - MOTIVES_HUMANOID_ROBOTS_DURABILITY_WAKE_UP: 'CommonBuffId' = 218696 - MOTIVES_HUMANOID_ROBOTS_LOW_CHARGE: 'CommonBuffId' = 223434 - MOTIVES_HUMANOID_ROBOTS_RECHARGING: 'CommonBuffId' = 223742 - MOTIVES_HUNGER_HUNGRY: 'CommonBuffId' = 12820 - MOTIVES_HUNGER_HUNGRY_GLUTTON: 'CommonBuffId' = 30331 - MOTIVES_HUNGER_HUNGRY_PLANT_SIMS: 'CommonBuffId' = 164179 - MOTIVES_HUNGER_STARVING: 'CommonBuffId' = 12821 - MOTIVES_HUNGER_STARVING_GHOST: 'CommonBuffId' = 103387 - MOTIVES_HUNGER_STARVING_PLANT_SIMS: 'CommonBuffId' = 164180 - MOTIVES_HUNGER_STARVING_WEREWOLF: 'CommonBuffId' = 294060 - MOTIVES_HUNGER_WEREWOLF: 'CommonBuffId' = 294059 - MOTIVES_HYGIENE_CAMPING_TRAIT_REPLACEMENT: 'CommonBuffId' = 102274 - MOTIVES_HYGIENE_FILTHY: 'CommonBuffId' = 12823 - MOTIVES_HYGIENE_GRUNGY: 'CommonBuffId' = 27114 - MOTIVES_INFANT_ATTENTION_ANGRY: 'CommonBuffId' = 317667 - MOTIVES_INFANT_ATTENTION_ANGRY_VERY: 'CommonBuffId' = 317668 - MOTIVES_INFANT_ATTENTION_SAD: 'CommonBuffId' = 290177 - MOTIVES_INFANT_ATTENTION_SAD_VERY: 'CommonBuffId' = 290178 - MOTIVES_INVIS_DECAY_MODS_BLADDER_YELLOW: 'CommonBuffId' = 27132 - MOTIVES_INVIS_DECAY_MODS_ENERGY_YELLOW: 'CommonBuffId' = 27139 - MOTIVES_INVIS_DECAY_MODS_FUN_YELLOW: 'CommonBuffId' = 27141 - MOTIVES_INVIS_DECAY_MODS_HUNGER_YELLOW: 'CommonBuffId' = 27142 - MOTIVES_INVIS_DECAY_MODS_HYGIENE_YELLOW: 'CommonBuffId' = 27138 - MOTIVES_INVIS_DECAY_MODS_SOCIAL_YELLOW: 'CommonBuffId' = 27140 - MOTIVES_INVIS_DECAY_MODS_TODDLER_ATTENTION_YELLOW: 'CommonBuffId' = 317356 - MOTIVES_PEED_SELF: 'CommonBuffId' = 12815 - MOTIVES_PET_CAT_AFFECTION_DISTRESS: 'CommonBuffId' = 159597 - MOTIVES_PET_CAT_COMPLAIN: 'CommonBuffId' = 158396 - MOTIVES_PET_CAT_DROWSY_ENERGY: 'CommonBuffId' = 161155 - MOTIVES_PET_CAT_DROWSY_ENERGY_LAZY: 'CommonBuffId' = 174965 - MOTIVES_PET_CAT_FILTHY: 'CommonBuffId' = 175246 - MOTIVES_PET_CAT_HUNGER_COOLDOWN: 'CommonBuffId' = 177668 - MOTIVES_PET_CAT_HUNGRY: 'CommonBuffId' = 158695 - MOTIVES_PET_CAT_IN_HEAT: 'CommonBuffId' = 160629 - MOTIVES_PET_CAT_IN_S_S3_MODE: 'CommonBuffId' = 167047 - MOTIVES_PET_CAT_KITTEN_HYPER: 'CommonBuffId' = 164491 - MOTIVES_PET_CAT_LOW_BLADDER: 'CommonBuffId' = 167242 - MOTIVES_PET_CAT_LOW_BOWEL: 'CommonBuffId' = 167243 - MOTIVES_PET_CAT_PLAY_COOLDOWN: 'CommonBuffId' = 161291 - MOTIVES_PET_CAT_PLAY_DISTRESS: 'CommonBuffId' = 157738 - MOTIVES_PET_CAT_STARVING: 'CommonBuffId' = 158720 - MOTIVES_PET_CAT_SUPPRESS_ALL: 'CommonBuffId' = 176465 - MOTIVES_PET_DOG_AFFECTION_DISTRESS: 'CommonBuffId' = 163242 - MOTIVES_PET_DOG_DIRTY: 'CommonBuffId' = 173851 - MOTIVES_PET_DOG_DROWSY_ELDER: 'CommonBuffId' = 161086 - MOTIVES_PET_DOG_FILTHY: 'CommonBuffId' = 175250 - MOTIVES_PET_DOG_HUNGRY: 'CommonBuffId' = 160302 - MOTIVES_PET_DOG_IN_HEAT: 'CommonBuffId' = 160627 - MOTIVES_PET_DOG_IN_S_S3_MODE: 'CommonBuffId' = 167048 - MOTIVES_PET_DOG_LOW_BLADDER: 'CommonBuffId' = 167202 - MOTIVES_PET_DOG_LOW_BOWEL: 'CommonBuffId' = 167215 - MOTIVES_PET_DOG_MOPEY_ENERGY: 'CommonBuffId' = 159911 - MOTIVES_PET_DOG_MOPEY_ENERGY_LAZY: 'CommonBuffId' = 174966 - MOTIVES_PET_DOG_PLAY_DISTRESS: 'CommonBuffId' = 158752 - MOTIVES_PET_DOG_PLAY_LOW: 'CommonBuffId' = 174625 - MOTIVES_PET_DOG_PUPPY_EXCITEMENT: 'CommonBuffId' = 164476 - MOTIVES_PET_DOG_SPIN_BLADDER: 'CommonBuffId' = 171081 - MOTIVES_PET_DOG_SPIN_BOWEL: 'CommonBuffId' = 171055 - MOTIVES_PET_DOG_STARVING: 'CommonBuffId' = 158736 - MOTIVES_PET_DOG_SUPPRESS_ALL: 'CommonBuffId' = 176464 - MOTIVES_PET_KITTEN_FILTHY: 'CommonBuffId' = 175247 - MOTIVES_PET_PUPPY_FILTHY: 'CommonBuffId' = 175251 - MOTIVES_PET_SMALL_DOG_FILTHY: 'CommonBuffId' = 175249 - MOTIVES_PLANT_SIM_WATER_INVISIBLE: 'CommonBuffId' = 162899 - MOTIVES_PLANT_SIM_WATER_PARCHED: 'CommonBuffId' = 162703 - MOTIVES_PLANT_SIM_WATER_THIRSTY: 'CommonBuffId' = 162702 - MOTIVES_SOCIAL_DESOLATE: 'CommonBuffId' = 12826 - MOTIVES_SOCIAL_DESOLATE_OUTGOING: 'CommonBuffId' = 29574 - MOTIVES_SOCIAL_LONELY: 'CommonBuffId' = 12825 - MOTIVES_SOCIAL_LONELY_OUTGOING: 'CommonBuffId' = 29575 - MOTIVES_TODDLER_ALL_MOTIVES_OKAY_CHECK_TODDLER: 'CommonBuffId' = 157834 - MOTIVES_TODDLER_ATTENTION_ANGRY: 'CommonBuffId' = 142131 - MOTIVES_TODDLER_ATTENTION_ANGRY_VERY: 'CommonBuffId' = 142132 - MOTIVES_TODDLER_ATTENTION_SAD: 'CommonBuffId' = 142133 - MOTIVES_TODDLER_ATTENTION_SAD_VERY: 'CommonBuffId' = 142134 - MOTIVES_TODDLER_BLADDER_ANGRY: 'CommonBuffId' = 154170 - MOTIVES_TODDLER_BLADDER_ANGRY_VERY: 'CommonBuffId' = 154171 - MOTIVES_TODDLER_BLADDER_HIDDEN: 'CommonBuffId' = 154253 - MOTIVES_TODDLER_BLADDER_HIDDEN_VERY: 'CommonBuffId' = 154255 - MOTIVES_TODDLER_BLADDER_SAD: 'CommonBuffId' = 154172 - MOTIVES_TODDLER_BLADDER_SAD_VERY: 'CommonBuffId' = 154173 - MOTIVES_TODDLER_ENERGY_ANGRY: 'CommonBuffId' = 142045 - MOTIVES_TODDLER_ENERGY_ANGRY_VERY: 'CommonBuffId' = 142094 - MOTIVES_TODDLER_ENERGY_FAIL_WHAT_HAPPENED: 'CommonBuffId' = 156757 - MOTIVES_TODDLER_ENERGY_SAD: 'CommonBuffId' = 142095 - MOTIVES_TODDLER_ENERGY_SAD_VERY: 'CommonBuffId' = 142096 - MOTIVES_TODDLER_FUN_ANGRY: 'CommonBuffId' = 142117 - MOTIVES_TODDLER_FUN_ANGRY_VERY: 'CommonBuffId' = 142118 - MOTIVES_TODDLER_FUN_SAD: 'CommonBuffId' = 142119 - MOTIVES_TODDLER_FUN_SAD_VERY: 'CommonBuffId' = 142120 - MOTIVES_TODDLER_HUNGER_ANGRY: 'CommonBuffId' = 142101 - MOTIVES_TODDLER_HUNGER_ANGRY_VERY: 'CommonBuffId' = 142102 - MOTIVES_TODDLER_HUNGER_SAD: 'CommonBuffId' = 142127 - MOTIVES_TODDLER_HUNGER_SAD_VERY: 'CommonBuffId' = 142128 - MOTIVES_TODDLER_HYGIENE_ANGRY: 'CommonBuffId' = 142240 - MOTIVES_TODDLER_HYGIENE_ANGRY_VERY: 'CommonBuffId' = 142241 - MOTIVES_TODDLER_HYGIENE_SAD: 'CommonBuffId' = 142242 - MOTIVES_TODDLER_HYGIENE_SAD_VERY: 'CommonBuffId' = 142243 - MOTIVES_VAMPIRE_POWER_EMPTY: 'CommonBuffId' = 155954 - MOTIVES_VAMPIRE_POWER_LOW: 'CommonBuffId' = 150259 - MOTIVES_VAMPIRE_THIRST_IRRESISTIBLE_THIRST: 'CommonBuffId' = 149567 - MOTIVES_VAMPIRE_THIRST_NEED_TO_FEED: 'CommonBuffId' = 149566 - MOTIVES_VAMPIRE_THIRST_PARCHED: 'CommonBuffId' = 149568 - MOTIVE_PEED_SELF_POOL: 'CommonBuffId' = 105772 - MOVE_HOUSEHOLD_PRE_MOVE: 'CommonBuffId' = 359179 - MOVE_HOUSEHOLD_RECENT_MOVE: 'CommonBuffId' = 359176 - MOVE_IN_ASK_COOLDOWN: 'CommonBuffId' = 310049 - MOVE_IN_RECENT: 'CommonBuffId' = 310401 - MOVE_IN_STORY_PROGRESSION_KLEPTOMANIAC: 'CommonBuffId' = 280272 - MOVE_IN_STORY_PROGRESSION_LONER: 'CommonBuffId' = 280270 - MOVE_IN_STORY_PROGRESSION_OUTGOING: 'CommonBuffId' = 280269 - MOVE_IN_STORY_PROGRESSION_PARANOID: 'CommonBuffId' = 280274 - MOVIE_THEATER_BANNED: 'CommonBuffId' = 305952 - MOVIE_THEATER_CHANCE_CARD_ENJOYMENT_DOWN: 'CommonBuffId' = 305957 - MOVIE_THEATER_CHANCE_CARD_ENJOYMENT_UP: 'CommonBuffId' = 305956 - MOVIE_THEATER_IN_THEATER: 'CommonBuffId' = 333127 - MOVIE_THEATER_LETS_GO_OUT_TO_THE_LOBBY_SAD: 'CommonBuffId' = 305953 - MOVIE_THEATER_SHUSH_SHAMER_CONFIDENT: 'CommonBuffId' = 305929 - MOVIE_THEATER_SHUSH_SHAMER_EMBARRASSED: 'CommonBuffId' = 305950 - MOVIE_THEATER_TALLTASTROPHE_HAPPY: 'CommonBuffId' = 305954 - MOVIE_THEATER_TALLTASTROPHE_UNCOMFORTABLE: 'CommonBuffId' = 305955 - MOVIE_THEATER_WATCHED_ACTION_DISLIKED: 'CommonBuffId' = 305729 - MOVIE_THEATER_WATCHED_ACTION_LIKED: 'CommonBuffId' = 305572 - MOVIE_THEATER_WATCHED_COMEDY_DISLIKED: 'CommonBuffId' = 305772 - MOVIE_THEATER_WATCHED_COMEDY_LIKED: 'CommonBuffId' = 305731 - MOVIE_THEATER_WATCHED_DRAMA_DISLIKED: 'CommonBuffId' = 305774 - MOVIE_THEATER_WATCHED_DRAMA_LIKED: 'CommonBuffId' = 305773 - MOVIE_THEATER_WATCHED_HORROR_DISLIKED: 'CommonBuffId' = 305778 - MOVIE_THEATER_WATCHED_HORROR_LIKED: 'CommonBuffId' = 305777 - MOVIE_THEATER_WATCHED_KIDS_DISLIKED: 'CommonBuffId' = 305776 - MOVIE_THEATER_WATCHED_KIDS_LIKED: 'CommonBuffId' = 305775 - MOVIE_THEATER_WATCHED_ROMANCE_DISLIKED: 'CommonBuffId' = 305779 - MOVIE_THEATER_WATCHED_ROMANCE_LIKED: 'CommonBuffId' = 305730 - MOVIE_THEATER_WATCHED_ROMANCE_LIKED_CHILD: 'CommonBuffId' = 305828 - MUD_PUDDLE_ACID_MUD_PUDDLE: 'CommonBuffId' = 240861 - MUD_PUDDLE_MUDDY_GOOD_TIME: 'CommonBuffId' = 185172 - MUD_PUDDLE_SLIP_IMMUNITY: 'CommonBuffId' = 182091 - MUD_PUDDLE_SUPER_MUDDY: 'CommonBuffId' = 190282 - MULTI_UNIT_EVENT_ALGAE_YUCKY: 'CommonBuffId' = 344305 - MULTI_UNIT_EVENT_CHARITY_DRIVE_FEELS_GOOD: 'CommonBuffId' = 345530 - MULTI_UNIT_EVENT_CHEMICAL_BROADCASTER: 'CommonBuffId' = 345145 - MULTI_UNIT_EVENT_COMPLETED_COMMUNITY: 'CommonBuffId' = 358889 - MULTI_UNIT_EVENT_COMPLETED_PRIMARY: 'CommonBuffId' = 343477 - MULTI_UNIT_EVENT_COMPLETED_SECONDARY: 'CommonBuffId' = 352303 - MULTI_UNIT_EVENT_CURSED_AFTER_DESTROY: 'CommonBuffId' = 345177 - MULTI_UNIT_EVENT_ELECTRICAL_POWERLESS_PROVOCATION: 'CommonBuffId' = 344834 - MULTI_UNIT_EVENT_EXPLOSION_SHREDDED_NERVES: 'CommonBuffId' = 342828 - MULTI_UNIT_EVENT_HIDDEN_BLIGHT_UPROOT_COMPLETE: 'CommonBuffId' = 360299 - MULTI_UNIT_EVENT_HIDDEN_BLIGHT_UPROOT_DELAY_CHECK: 'CommonBuffId' = 360301 - MULTI_UNIT_EVENT_HIDDEN_CHARITY_DRIVE_COOLDOWN: 'CommonBuffId' = 345543 - MULTI_UNIT_EVENT_HIDDEN_HAUNTING_CANCEL_POSSESS: 'CommonBuffId' = 344754 - MULTI_UNIT_EVENT_HIDDEN_HAUNTING_CONFRONT_COOLDOWN: 'CommonBuffId' = 344716 - MULTI_UNIT_EVENT_HIDDEN_HAUNTING_POSSESS_COOLDOWN: 'CommonBuffId' = 344695 - MULTI_UNIT_EVENT_HIDDEN_NUISANCE_NOTE_COOLDOWN: 'CommonBuffId' = 349615 - MULTI_UNIT_EVENT_HIDDEN_SEWAGE_LEAK_FLUSH_COOLDOWN: 'CommonBuffId' = 356923 - MULTI_UNIT_EVENT_HIDDEN_TENANT_DID_FIX: 'CommonBuffId' = 353150 - MULTI_UNIT_EVENT_INFESTATION_FAIL_STOMP: 'CommonBuffId' = 357311 - MULTI_UNIT_EVENT_INFESTATION_UNCOMFORTABLE: 'CommonBuffId' = 345007 - MULTI_UNIT_EVENT_MAINTENANCE_DAY_AUTONOMY: 'CommonBuffId' = 343856 - MULTI_UNIT_EVENT_MAINTENANCE_DAY_COMMUNITY_SPIRIT: 'CommonBuffId' = 344267 - MULTI_UNIT_EVENT_NUISANCE_ANNOYING_NOISE: 'CommonBuffId' = 349597 - MULTI_UNIT_EVENT_NUISANCE_BAD_SMELL: 'CommonBuffId' = 349598 - MULTI_UNIT_EVENT_PET_DAY_WARM_AND_FUZZY: 'CommonBuffId' = 344833 - MULTI_UNIT_EVENT_SEWAGE_LEAK_SULK: 'CommonBuffId' = 344677 - MULTI_UNIT_EVENT_TENANT_REVOLT_AUTONOMY: 'CommonBuffId' = 358006 - MULTI_UNIT_EVENT_TENANT_REVOLT_MOB_RULES: 'CommonBuffId' = 352350 - MULTI_UNIT_EVENT_TRASH_OVERLOAD_END_TRASH_DRIVE: 'CommonBuffId' = 350681 - MULTI_UNIT_EVENT_TRASH_OVERLOAD_START_TRASH_DRIVE: 'CommonBuffId' = 350680 - MULTI_UNIT_EVENT_WATER_LEAK_ATTEMPT: 'CommonBuffId' = 356234 - MUSHROOM_HUNT_GROSSED_OUT_BY_FUNGUS: 'CommonBuffId' = 268560 - MUSIC_FESTIVAL_ARTIST_PERFORMER_END: 'CommonBuffId' = 269372 - MUSIC_FESTIVAL_ARTIST_PERFORMER_REACT: 'CommonBuffId' = 269373 - MUSIC_FESTIVAL_ARTIST_PERFORMER_SI_COMPATIBILITY: 'CommonBuffId' = 269751 - MUSIC_FESTIVAL_ARTIST_PERFORMER_START: 'CommonBuffId' = 269371 - MUSIC_FESTIVAL_AUTONOMY_MOD_ARTIST_ENTER: 'CommonBuffId' = 270408 - MUSIC_FESTIVAL_AUTONOMY_MOD_ARTIST_MAIN_ARTIST: 'CommonBuffId' = 269945 - MUSIC_FESTIVAL_AUTONOMY_MOD_ARTIST_OPENER_1: 'CommonBuffId' = 269943 - MUSIC_FESTIVAL_AUTONOMY_MOD_ARTIST_OPENER_2: 'CommonBuffId' = 269944 - MUSIC_FESTIVAL_AUTONOMY_MOD_FESTIVAL_GOER: 'CommonBuffId' = 269764 - MUSIC_FESTIVAL_AUTONOMY_MOD_FESTIVAL_GOER_ENDING: 'CommonBuffId' = 270743 - MUSIC_FESTIVAL_AUTONOMY_MOD_FESTIVAL_GOER_MAIN_ARTIST: 'CommonBuffId' = 269768 - MUSIC_FESTIVAL_AUTONOMY_MOD_FESTIVAL_GOER_NPC: 'CommonBuffId' = 270784 - MUSIC_FESTIVAL_AUTONOMY_MOD_FESTIVAL_GOER_OPENER_1: 'CommonBuffId' = 269766 - MUSIC_FESTIVAL_AUTONOMY_MOD_FESTIVAL_GOER_OPENER_2: 'CommonBuffId' = 269767 - MUSIC_FESTIVAL_AUTONOMY_MOD_FESTIVAL_GOER_POST_PERFORMANCE: 'CommonBuffId' = 269765 - MUSIC_FESTIVAL_AUTONOMY_MOD_FESTIVAL_GOER_STAGE_PERMISSIONS: 'CommonBuffId' = 269976 - MUSIC_FESTIVAL_COOLDOWNS_GET_HYPED_AUTONOMOUS: 'CommonBuffId' = 270809 - MUSIC_FESTIVAL_HIDDEN_MAIN_ARTIST: 'CommonBuffId' = 270112 - MUSIC_FESTIVAL_HIDDEN_WATCHING_PERFORMANCE_OPENER_1: 'CommonBuffId' = 270110 - MUSIC_FESTIVAL_HIDDEN_WATCHING_PERFORMANCE_OPENER_2: 'CommonBuffId' = 270111 - MUSIC_FESTIVAL_NPC_PURCHASE_COOLDOWN: 'CommonBuffId' = 270780 - MUSIC_FESTIVAL_VISIBLE_ENERGETIC_MAIN_ARTIST: 'CommonBuffId' = 270446 - MUSIC_FESTIVAL_VISIBLE_ENERGETIC_OPENER: 'CommonBuffId' = 270447 - MUSIC_FESTIVAL_VISIBLE_HAPPY_MAIN_ARTIST: 'CommonBuffId' = 270445 - MUSIC_FESTIVAL_VISIBLE_HAPPY_OPENER: 'CommonBuffId' = 270444 - MUSIC_FESTIVAL_VISIBLE_INSPIRED_POST_PERFORMANCE: 'CommonBuffId' = 270448 - MUSIC_FESTIVAL_WATCHING_END: 'CommonBuffId' = 270342 - MUSIC_FESTIVAL_WATCHING_REACT: 'CommonBuffId' = 270343 - MUSIC_FESTIVAL_WATCHING_START: 'CommonBuffId' = 270344 - MUSIC_PRODUCTION_STATION_LISTEN_BUFFS_LISTEN_ANGER: 'CommonBuffId' = 195378 - MUSIC_PRODUCTION_STATION_LISTEN_BUFFS_LISTEN_CONFIDENT: 'CommonBuffId' = 195377 - MUSIC_PRODUCTION_STATION_LISTEN_BUFFS_LISTEN_FLIRTY: 'CommonBuffId' = 195374 - MUSIC_PRODUCTION_STATION_LISTEN_BUFFS_LISTEN_FOCUSED: 'CommonBuffId' = 195375 - MUSIC_PRODUCTION_STATION_LISTEN_BUFFS_LISTEN_HAPPY: 'CommonBuffId' = 195373 - MUSIC_PRODUCTION_STATION_LISTEN_BUFFS_LISTEN_PLAYFUL: 'CommonBuffId' = 195376 - MUSIC_PRODUCTION_STATION_LISTEN_BUFFS_LISTEN_SAD: 'CommonBuffId' = 195372 - MUSIC_PRODUCTION_STATION_LISTEN_BUFFS_THATS_MY_SONG: 'CommonBuffId' = 195370 - MUSIC_PRODUCTION_STATION_REJECTION_LETTER_OFF_LOT: 'CommonBuffId' = 203301 - MUSIC_PRODUCTION_STATION_RELEASED_TRACK: 'CommonBuffId' = 194956 - MYSTICAL_RELIC_ANCIENT_JOY_CANT_CATCH: 'CommonBuffId' = 180262 - MYSTICAL_RELIC_ANCIENT_SICKNESS_CANT_CATCH: 'CommonBuffId' = 180261 - MYSTICAL_RELIC_CURSES_MARKED_FOR_DEATH_ELECTROCUTION_COOLDOWN: 'CommonBuffId' = 181087 - NAP: 'CommonBuffId' = 10362 - NATURAL_DANGERS_BEES_FAIL: 'CommonBuffId' = 177125 - NATURAL_DANGERS_BLOCK_ATTACK: 'CommonBuffId' = 181653 - NATURAL_DANGERS_BLOOD_BATS_FAIL: 'CommonBuffId' = 177128 - NATURAL_DANGERS_COOLDOWN: 'CommonBuffId' = 179883 - NATURAL_DANGERS_FIRE_FLIES_FAIL: 'CommonBuffId' = 177126 - NATURAL_DANGERS_FITNESS_SUCCESS: 'CommonBuffId' = 177169 - NATURAL_DANGERS_GEAR_SUCCESS: 'CommonBuffId' = 177136 - NATURAL_DANGERS_INSECTS_REPELLED: 'CommonBuffId' = 179463 - NATURAL_DANGERS_LIGHTNING_BUGS_FAIL: 'CommonBuffId' = 177127 - NATURAL_DANGERS_LOCAL_CULTURE_SKILL_SUCCESS: 'CommonBuffId' = 177171 - NATURAL_DANGERS_LOGIC_SKILL_SUCCESS: 'CommonBuffId' = 177170 - NATURAL_DANGERS_ROUTE_EVENT: 'CommonBuffId' = 180802 - NATURAL_DANGERS_SPIDER_FAIL: 'CommonBuffId' = 177129 - NATURAL_EARTHY_SCENT: 'CommonBuffId' = 118503 - NATURAL_FOCUS: 'CommonBuffId' = 108253 - NATURAL_FOCUS_LOVES_OUTDOORS: 'CommonBuffId' = 108263 - NAUSEOUS: 'CommonBuffId' = 9912 - NEARBY_PET_SKUNK: 'CommonBuffId' = 171963 - NEAR_FRIENDLY: 'CommonBuffId' = 32807 - NEAR_HOUSEHOLD_TODDLER: 'CommonBuffId' = 169547 - NEAR_MY_BABY: 'CommonBuffId' = 97289 - NEAR_MY_CHILD: 'CommonBuffId' = 32943 - NEAR_NEW_SIBLING: 'CommonBuffId' = 97686 - NEAR_PARTNER: 'CommonBuffId' = 32815 - NEAR_ROMANCE: 'CommonBuffId' = 32813 - NEAR_SOLAR_PANEL_ON: 'CommonBuffId' = 238802 - NEAR_UNFRIENDLY: 'CommonBuffId' = 32818 - NEIGHBOR_RELATIONSHIP_PHONE_CALL_FRIENDLY_BROUGHT_FRIENDS_TOGETHER: 'CommonBuffId' = 274065 - NEIGHBOR_RELATIONSHIP_PHONE_CALL_ROMANTIC_JUST_CALL_ME_CUPID: 'CommonBuffId' = 279203 - NEIGHBOR_TRAIT_BLIC_BLOCK_DANCE_COOLDOWN_HIDDEN: 'CommonBuffId' = 354232 - NEIGHBOR_TRAIT_CONTRIBUTE_FUNDS_COOLDOWN_FAMILY_HIDDEN: 'CommonBuffId' = 359364 - NEIGHBOR_TRAIT_CONTRIBUTE_FUNDS_COOLDOWN_HIDDEN: 'CommonBuffId' = 348263 - NEIGHBOR_TRAIT_CRINGE_AM_I_CRINGE: 'CommonBuffId' = 346655 - NEIGHBOR_TRAIT_CRINGE_BLIC_BLOCK_DANCE_NEGATIVE: 'CommonBuffId' = 346653 - NEIGHBOR_TRAIT_CRINGE_BLIC_BLOCK_DANCE_POSITIVE: 'CommonBuffId' = 346652 - NEIGHBOR_TRAIT_CRINGE_BLIC_BLOCK_DANCE_SELF: 'CommonBuffId' = 346651 - NEIGHBOR_TRAIT_CRINGE_BLIC_BLOCK_DANCE_SELF_TEMP: 'CommonBuffId' = 347689 - NEIGHBOR_TRAIT_CRINGE_COOLDOWN_HIDDEN: 'CommonBuffId' = 347014 - NEIGHBOR_TRAIT_CRINGE_CRUSTY_MEMES: 'CommonBuffId' = 346649 - NEIGHBOR_TRAIT_CRINGE_EMBRACE_YOUR_TRUTH: 'CommonBuffId' = 346656 - NEIGHBOR_TRAIT_CRINGE_IM_TOO_OLD_FOR_THIS: 'CommonBuffId' = 346650 - NEIGHBOR_TRAIT_CRINGE_IM_WAY_TOO_OLD_FOR_THIS: 'CommonBuffId' = 346654 - NEIGHBOR_TRAIT_CRINGE_STILL_GOT_IT: 'CommonBuffId' = 347876 - NEIGHBOR_TRAIT_CRINGE_WELL_MEMED_MY_FRIEND: 'CommonBuffId' = 346648 - NEIGHBOR_TRAIT_CRINGE_WORST_PUNS_NEGATIVE: 'CommonBuffId' = 355956 - NEIGHBOR_TRAIT_CRINGE_WORST_PUNS_POSITIVE: 'CommonBuffId' = 355955 - NEIGHBOR_TRAIT_GENEROUS_COOLDOWN_HIDDEN: 'CommonBuffId' = 348265 - NEIGHBOR_TRAIT_GENEROUS_FEELING_HEARD: 'CommonBuffId' = 346659 - NEIGHBOR_TRAIT_GENEROUS_FULL_OF_EMPATHY: 'CommonBuffId' = 346661 - NEIGHBOR_TRAIT_GENEROUS_GIFT: 'CommonBuffId' = 357005 - NEIGHBOR_TRAIT_GENEROUS_GIFT_OF_GIVING: 'CommonBuffId' = 346657 - NEIGHBOR_TRAIT_GENEROUS_GIFT_OF_GIVING_FAMILY: 'CommonBuffId' = 357006 - NEIGHBOR_TRAIT_GENEROUS_ICKY_FEELING: 'CommonBuffId' = 346675 - NEIGHBOR_TRAIT_GENEROUS_KIND_WORDS_RECIEVED: 'CommonBuffId' = 346660 - NEIGHBOR_TRAIT_GENEROUS_NEIGHBOR: 'CommonBuffId' = 356608 - NEIGHBOR_TRAIT_GENEROUS_SPREAD_THE_LOVE: 'CommonBuffId' = 346658 - NEIGHBOR_TRAIT_GENEROUS_UNPLEASANT_AURA: 'CommonBuffId' = 346672 - NEIGHBOR_TRAIT_LEARN_A_SECRET_HIDDEN: 'CommonBuffId' = 349861 - NEIGHBOR_TRAIT_NOSY_ADVICE_ACTOR: 'CommonBuffId' = 356496 - NEIGHBOR_TRAIT_NOSY_ADVICE_NEGATIVE_TARGET: 'CommonBuffId' = 356498 - NEIGHBOR_TRAIT_NOSY_ADVICE_POSITIVE_TARGET: 'CommonBuffId' = 356499 - NEIGHBOR_TRAIT_NOSY_ANIMAL_SPY: 'CommonBuffId' = 354536 - NEIGHBOR_TRAIT_NOSY_COOLDOWN_HIDDEN: 'CommonBuffId' = 348920 - NEIGHBOR_TRAIT_NOSY_DONT_BE_SUSPICIOUS: 'CommonBuffId' = 346644 - NEIGHBOR_TRAIT_NOSY_HOT_GOSSIP: 'CommonBuffId' = 346676 - NEIGHBOR_TRAIT_NOSY_JOURNAL_SNOOP: 'CommonBuffId' = 357564 - NEIGHBOR_TRAIT_NOSY_NEIGHBORHOOD_TELESCOPE: 'CommonBuffId' = 358014 - NEIGHBOR_TRAIT_NOSY_NOSY_NUISANCE: 'CommonBuffId' = 348922 - NEIGHBOR_TRAIT_NOSY_TEA_DEPRIVED: 'CommonBuffId' = 346677 - NEIGHBOR_TRAIT_NOSY_YOU_KNOW_YOU_LOVE_ME: 'CommonBuffId' = 346678 - NEIGHBOR_TRAIT_SPREAD_THE_CRINGE_HIDDEN: 'CommonBuffId' = 354726 - NEIGHBOR_TRAIT_SPREAD_THE_JOY_HIDDEN: 'CommonBuffId' = 354727 - NEIGHBOR_TRAIT_TEA_DEPRIVED_COUNTDOWN_HIDDEN: 'CommonBuffId' = 349565 - NEIGHBOR_TRAIT_WISE_COOLDOWN_HIDDEN: 'CommonBuffId' = 348264 - NEIGHBOR_TRAIT_WISE_ENERGIZED: 'CommonBuffId' = 348929 - NEIGHBOR_TRAIT_WISE_IMPORTANT_LESSON: 'CommonBuffId' = 356501 - NEIGHBOR_TRAIT_WISE_INSPIRATION_FOR_LIFE: 'CommonBuffId' = 346683 - NEIGHBOR_TRAIT_WISE_I_WAS_WRONGED_THAT_DAY: 'CommonBuffId' = 346689 - NEIGHBOR_TRAIT_WISE_LESSON_WELL_LEARNED: 'CommonBuffId' = 346684 - NEIGHBOR_TRAIT_WISE_MENTOR: 'CommonBuffId' = 356609 - NEIGHBOR_TRAIT_WISE_PASSING_IT_DOWN: 'CommonBuffId' = 346679 - NEIGHBOR_TRAIT_WISE_READY_FOR_LIFE: 'CommonBuffId' = 346680 - NEIGHBOR_TRAIT_WISE_SCARED: 'CommonBuffId' = 348927 - NEIGHBOR_TRAIT_WISE_SHARE_LIFE_EXPERIENCE: 'CommonBuffId' = 356500 - NEIGHBOR_TRAIT_WISE_THOSE_WERE_THE_DAYS: 'CommonBuffId' = 346686 - NEIGHBOR_TRAIT_WISE_THOSE_WERE_THE_DAYS_FLIRTY: 'CommonBuffId' = 346687 - NEIGHBOR_TRAIT_WISE_UGH_SPARE_ME: 'CommonBuffId' = 346681 - NEIGHBOR_TRAIT_WISE_WHERE_DID_THE_DAYS_GO: 'CommonBuffId' = 346688 - NEIGHBOR_TRAIT_WISE_WHERE_WAS_THIS_STORY_GOING: 'CommonBuffId' = 346682 - NEIGHBOR_TRAIT_WISE_WHO_ASKED: 'CommonBuffId' = 346685 - NEIGHBOR_TRAIT_WISE_WHY_OH_WHY: 'CommonBuffId' = 346690 - NEUTRAL_OVER48_HOURS: 'CommonBuffId' = 77767 - NEW_FRIEND_DRAMA_NODE_COOLDOWN: 'CommonBuffId' = 202751 - NEW_GOOD_FRIEND: 'CommonBuffId' = 12472 - NIGHTLIGHT: 'CommonBuffId' = 165358 - NO_GREETINGS: 'CommonBuffId' = 123741 - NO_SLEEP_24_HOURS: 'CommonBuffId' = 38133 - NO_SOCIAL_24_HOURS: 'CommonBuffId' = 38134 - NPC_ANGRY: 'CommonBuffId' = 29680 - NPC_BORED: 'CommonBuffId' = 29688 - NPC_CHEF_ANGRY: 'CommonBuffId' = 131377 - NPC_CHEF_CONFIDENT: 'CommonBuffId' = 131380 - NPC_CHEF_INSPIRED: 'CommonBuffId' = 131375 - NPC_CHEF_STRESSED: 'CommonBuffId' = 139951 - NPC_CHEF_VERY_ANGRY: 'CommonBuffId' = 131383 - NPC_CHEF_VERY_INSPIRED: 'CommonBuffId' = 131382 - NPC_DAZED: 'CommonBuffId' = 29744 - NPC_DISCOURAGE_SIT: 'CommonBuffId' = 136466 - NPC_DO_NOTHING: 'CommonBuffId' = 39236 - NPC_EMBARRASSED: 'CommonBuffId' = 29745 - NPC_FLIRTY: 'CommonBuffId' = 29678 - NPC_FOCUSED: 'CommonBuffId' = 29687 - NPC_HAPPY: 'CommonBuffId' = 29681 - NPC_INSPIRED: 'CommonBuffId' = 29682 - NPC_PET_SUPPRESS_ALL_MOTIVE_DECAY: 'CommonBuffId' = 168168 - NPC_RELATIONSHIP_AUTONOMY_GENERIC_COMMITMENT: 'CommonBuffId' = 280578 - NPC_RELATIONSHIP_AUTONOMY_HIDDEN_TARGET_BEST_FRIEND: 'CommonBuffId' = 310218 - NPC_RELATIONSHIP_AUTONOMY_HIDDEN_TARGET_BOYFRIEND_GIRLFRIEND: 'CommonBuffId' = 310223 - NPC_RELATIONSHIP_AUTONOMY_HIDDEN_TARGET_BREAK_UP: 'CommonBuffId' = 310221 - NPC_RELATIONSHIP_AUTONOMY_HIDDEN_TARGET_PROM: 'CommonBuffId' = 310220 - NPC_RELATIONSHIP_AUTONOMY_HIDDEN_TARGET_PROM_FRIENDS: 'CommonBuffId' = 310219 - NPC_RELATIONSHIP_AUTONOMY_HIDDEN_TARGET_PROPOSE: 'CommonBuffId' = 310222 - NPC_RELATIONSHIP_AUTONOMY_TALK_ABOUT_MARRIAGE: 'CommonBuffId' = 280633 - NPC_SAD: 'CommonBuffId' = 29679 - NPC_SUPPRESS_ALL_MOTIVES_EXCEPT_BLADDER: 'CommonBuffId' = 143413 - NPC_SUPPRESS_ALL_MOTIVE_DECAY: 'CommonBuffId' = 121359 - NPC_SUPPRESS_ALL_MOTIVE_DECAY_SS3: 'CommonBuffId' = 230218 - NPC_VERY_ANGRY: 'CommonBuffId' = 127091 - NPC_VILLAGERS_CONSPIRE_WITH_GNOMES_WHIMSICAL_EMBARRASSED: 'CommonBuffId' = 266411 - NPC_VILLAGERS_CONSPIRE_WITH_GNOMES_WHIMSICAL_ENERGIZED: 'CommonBuffId' = 266413 - NPC_VILLAGERS_CONSPIRE_WITH_GNOMES_WHIMSICAL_INSPIRED: 'CommonBuffId' = 266414 - NPC_VILLAGERS_CONSPIRE_WITH_GNOMES_WHIMSICAL_PLAYFUL: 'CommonBuffId' = 266412 - NPC_VILLAGERS_CONSPIRE_WITH_GNOMES_WHIMSICAL_STRESSED: 'CommonBuffId' = 266415 - OBJECT_AIR_CON_EFFECTS: 'CommonBuffId' = 357736 - OBJECT_AIR_CON_NEGATIVE: 'CommonBuffId' = 357735 - OBJECT_AIR_CON_POSITIVE: 'CommonBuffId' = 357734 - OBJECT_ALIEN_PORTAL_CALIBRATED: 'CommonBuffId' = 110526 - OBJECT_ALIEN_PORTAL_CONTACT: 'CommonBuffId' = 110658 - OBJECT_APARTMENT_BULLETIN_BOARD_ANGRY_FROM_PASSIVE_AGGRESSIVE_NOTE: 'CommonBuffId' = 145620 - OBJECT_APARTMENT_BULLETIN_BOARD_HAPPY_FROM_AFFIRMING_NOTE: 'CommonBuffId' = 145619 - OBJECT_APARTMENT_PROBLEM_ELECTRICAL_PROBLEM_OMINOUS_SPARKING: 'CommonBuffId' = 133097 - OBJECT_APARTMENT_PROBLEM_GOO_PUDDLE_GOO_GROSS_OUT: 'CommonBuffId' = 133094 - OBJECT_APARTMENT_PROBLEM_HANDY_HERO: 'CommonBuffId' = 143679 - OBJECT_APARTMENT_PROBLEM_LEAKY_PIPE_RISING_TIDE: 'CommonBuffId' = 133091 - OBJECT_APARTMENT_PROBLEM_MADE_IT_WORSE: 'CommonBuffId' = 143680 - OBJECT_APARTMENT_PROBLEM_MICE_MICE: 'CommonBuffId' = 144349 - OBJECT_APARTMENT_PROBLEM_MICE_RUDE_AWAKENING: 'CommonBuffId' = 151394 - OBJECT_APARTMENT_PROBLEM_MICE_SUSPICIOUS_SQUEAKING: 'CommonBuffId' = 144348 - OBJECT_APARTMENT_PROBLEM_NPC_COMPLAIN_TO_LANDLORD: 'CommonBuffId' = 150483 - OBJECT_APARTMENT_PROBLEM_RANDOM_SMELL_NOXIOUS_ODOR: 'CommonBuffId' = 133096 - OBJECT_APARTMENT_PROBLEM_RANDOM_SMELL_UNSETTLED_BY_ODOR: 'CommonBuffId' = 133095 - OBJECT_APARTMENT_PROBLEM_ROACH_HOLE_BUGGING_OUT: 'CommonBuffId' = 133093 - OBJECT_APARTMENT_PROBLEM_ROACH_HOLE_WAS_THAT: 'CommonBuffId' = 133092 - OBJECT_ARCADE_MACHINE_CONTINUE_GAME_HIDDEN: 'CommonBuffId' = 129531 - OBJECT_BABY_MOURN: 'CommonBuffId' = 100188 - OBJECT_BAR_GLOBE_CONTEMPLATED_WORLD_DOMINATION: 'CommonBuffId' = 145046 - OBJECT_BAR_GLOBE_FOUND_MY_CITY: 'CommonBuffId' = 145049 - OBJECT_BAR_GLOBE_STRIVING_FOR_GREATNESS: 'CommonBuffId' = 145048 - OBJECT_BAR_GLOBE_THE_VAST_WORLD: 'CommonBuffId' = 145047 - OBJECT_BASKETBALL_COACH_TIMER: 'CommonBuffId' = 154716 - OBJECT_BASKETBALL_DREAM_BIG: 'CommonBuffId' = 145875 - OBJECT_BASKETBALL_DREAM_BIG_SHOT_TAKEN_2_POINT: 'CommonBuffId' = 154209 - OBJECT_BASKETBALL_DREAM_BIG_SHOT_TAKEN_3_POINT: 'CommonBuffId' = 153704 - OBJECT_BASKETBALL_DREAM_BIG_SHOT_TAKEN_DOUBLE_CLUTCH: 'CommonBuffId' = 153705 - OBJECT_BASKETBALL_DREAM_BIG_SHOT_TAKEN_FLYING: 'CommonBuffId' = 153706 - OBJECT_BASKETBALL_DUNK_COMPETITION: 'CommonBuffId' = 147236 - OBJECT_BASKETBALL_RECENT_CURRY: 'CommonBuffId' = 147475 - OBJECT_BASKETBALL_SHOT_COMPETITION: 'CommonBuffId' = 147235 - OBJECT_BASKETBALL_SHOT_RESULT_MADE: 'CommonBuffId' = 146545 - OBJECT_BASKETBALL_SHOT_RESULT_MISSED: 'CommonBuffId' = 146546 - OBJECT_BASKETBALL_STOP_COACHING: 'CommonBuffId' = 155002 - OBJECT_BASKETBALL_TAKE_SHOT_2_POINT: 'CommonBuffId' = 145908 - OBJECT_BASKETBALL_TAKE_SHOT_3_POINT: 'CommonBuffId' = 145909 - OBJECT_BASKETBALL_TAKE_SHOT_ANY: 'CommonBuffId' = 145910 - OBJECT_BASKETBALL_TAKE_SHOT_CLOSE_SHOT: 'CommonBuffId' = 145906 - OBJECT_BASKETBALL_TAKE_SHOT_FREE_THROW: 'CommonBuffId' = 145907 - OBJECT_BASKETBALL_TAKE_SHOT_LONG_THREE: 'CommonBuffId' = 153823 - OBJECT_BASKETBALL_TAKING_A_SHOT: 'CommonBuffId' = 144051 - OBJECT_BASKETBALL_TAUNT: 'CommonBuffId' = 144054 - OBJECT_BASKETBALL_VISIBLE_CAUGHT_PRETENDING: 'CommonBuffId' = 146877 - OBJECT_BASKETBALL_VISIBLE_COURT_LOSS: 'CommonBuffId' = 146876 - OBJECT_BASKETBALL_VISIBLE_COURT_ROYALTY: 'CommonBuffId' = 146889 - OBJECT_BASKETBALL_VISIBLE_DUNKED_ON: 'CommonBuffId' = 146886 - OBJECT_BASKETBALL_VISIBLE_DUNK_MASTER: 'CommonBuffId' = 146885 - OBJECT_BASKETBALL_VISIBLE_GOOD_GAME: 'CommonBuffId' = 146887 - OBJECT_BASKETBALL_VISIBLE_HOT_LIKE_CURRY: 'CommonBuffId' = 146874 - OBJECT_BASKETBALL_VISIBLE_HOW_COULD_I_LOSE: 'CommonBuffId' = 146888 - OBJECT_BASKETBALL_VISIBLE_IN_THE_ZONE: 'CommonBuffId' = 146875 - OBJECT_BASKETBALL_VISIBLE_MASSIVE_DUNK: 'CommonBuffId' = 146880 - OBJECT_BASKETBALL_VISIBLE_ON_FIRE: 'CommonBuffId' = 146884 - OBJECT_BASKETBALL_VISIBLE_SPRAINED_ANKLE: 'CommonBuffId' = 146881 - OBJECT_BATHTUB_BABY_SOFT_SKIN: 'CommonBuffId' = 120480 - OBJECT_BATHTUB_BABY_SOFT_SKIN_INCENSE: 'CommonBuffId' = 120493 - OBJECT_BATHTUB_BUBBLES: 'CommonBuffId' = 12474 - OBJECT_BATHTUB_CLEAN_COAT: 'CommonBuffId' = 99511 - OBJECT_BATHTUB_FACE_MASK_HIDDEN: 'CommonBuffId' = 120486 - OBJECT_BATHTUB_FACE_MASK_HIDDEN_CHILD: 'CommonBuffId' = 146845 - OBJECT_BATHTUB_INFANT_BATH_BABY_BATH: 'CommonBuffId' = 273904 - OBJECT_BATHTUB_INFANT_BATH_BUBBLES: 'CommonBuffId' = 273908 - OBJECT_BATHTUB_INFANT_BATH_BUBBLES_VFX: 'CommonBuffId' = 283706 - OBJECT_BATHTUB_INFANT_BATH_BUBBLE_WATER_BABY: 'CommonBuffId' = 326409 - OBJECT_BATHTUB_INFANT_BATH_SOAKING_WET: 'CommonBuffId' = 273905 - OBJECT_BATHTUB_INFANT_BATH_WATER_BABY: 'CommonBuffId' = 273906 - OBJECT_BATHTUB_LIME_AND_SHINE: 'CommonBuffId' = 120482 - OBJECT_BATHTUB_LIME_AND_SHINE_INCENSE: 'CommonBuffId' = 120494 - OBJECT_BATHTUB_LOW_QUALITY: 'CommonBuffId' = 39241 - OBJECT_BATHTUB_PLAY: 'CommonBuffId' = 8231 - OBJECT_BATHTUB_RELAX: 'CommonBuffId' = 12476 - OBJECT_BATHTUB_RELAXING_LAVENDER: 'CommonBuffId' = 120481 - OBJECT_BATHTUB_RELAXING_LAVENDER_INCENSE: 'CommonBuffId' = 120495 - OBJECT_BATHTUB_RESTORATIVE_SOAK: 'CommonBuffId' = 120483 - OBJECT_BATHTUB_RESTORATIVE_SOAK_INCENSE: 'CommonBuffId' = 120496 - OBJECT_BATHTUB_ROSE_SCENTED_GARDEN: 'CommonBuffId' = 120484 - OBJECT_BATHTUB_ROSE_SCENTED_GARDEN_INCENSE: 'CommonBuffId' = 120497 - OBJECT_BATHTUB_SMELLS_LIKE_FLOWERS: 'CommonBuffId' = 120485 - OBJECT_BATHTUB_SMELLS_LIKE_FLOWERS_INCENSE: 'CommonBuffId' = 120498 - OBJECT_BATHTUB_TODDLER_BATH_BATH_TIME: 'CommonBuffId' = 150535 - OBJECT_BATHTUB_TODDLER_BATH_BUBBLE_FUN: 'CommonBuffId' = 150809 - OBJECT_BATHTUB_TODDLER_BATH_SPLASHY_SPLASHY: 'CommonBuffId' = 150537 - OBJECT_BATHTUB_TODDLER_BATH_TODDLER_SOAKING: 'CommonBuffId' = 150538 - OBJECT_BATHTUB_TODDLER_BATH_WATER_FUN: 'CommonBuffId' = 150536 - OBJECT_BATHTUB_WATER_HEATER_COLD: 'CommonBuffId' = 353062 - OBJECT_BATHTUB_WATER_HEATER_COLD_IP: 'CommonBuffId' = 353558 - OBJECT_BATHTUB_WATER_HEATER_COLD_IP_TIMED: 'CommonBuffId' = 354746 - OBJECT_BATHTUB_WATER_HEATER_COLD_TIMED: 'CommonBuffId' = 354745 - OBJECT_BATHTUB_WHIRLPOOL_RELAX: 'CommonBuffId' = 77316 - OBJECT_BATTLE_STATION_CANT_WIN_THEM_ALL: 'CommonBuffId' = 135135 - OBJECT_BATTLE_STATION_CLOSE_BATTLE: 'CommonBuffId' = 135134 - OBJECT_BATTLE_STATION_LOST_A_BATTLE: 'CommonBuffId' = 135137 - OBJECT_BATTLE_STATION_SHOULD_HAVE_WON: 'CommonBuffId' = 135136 - OBJECT_BATTLE_STATION_VICTOR: 'CommonBuffId' = 135133 - OBJECT_BED_MONSTER_UNDER_ENERGIZED_MONSTER_FRIEND: 'CommonBuffId' = 136465 - OBJECT_BED_MONSTER_UNDER_INTERRUPT_SLEEP: 'CommonBuffId' = 138779 - OBJECT_BED_MONSTER_UNDER_NEED_A_HUG: 'CommonBuffId' = 139152 - OBJECT_BED_MONSTER_UNDER_SPRAYING_FOR_MONSTER: 'CommonBuffId' = 136899 - OBJECT_BED_MONSTER_UNDER_SPRAY_FOR_MONSTER: 'CommonBuffId' = 139102 - OBJECT_BED_SCARED: 'CommonBuffId' = 133589 - OBJECT_BED_WOOHOO_COOLDOWN: 'CommonBuffId' = 12482 - OBJECT_BILLS_ANGRY: 'CommonBuffId' = 24344 - OBJECT_BILLS_SAD: 'CommonBuffId' = 24345 - OBJECT_BIRD_FEEDER_BIRDS: 'CommonBuffId' = 140759 - OBJECT_BIRD_FEEDER_BIRD_WATCHING: 'CommonBuffId' = 140735 - OBJECT_BIRTHDAY_CAKE_BAKED_ONE_CAKE: 'CommonBuffId' = 34706 - OBJECT_BIRTHDAY_CAKE_CANDLES_LIT: 'CommonBuffId' = 100394 - OBJECT_BIRTHDAY_CAKE_CELEBRATE: 'CommonBuffId' = 28561 - OBJECT_BONFIRE_BURNING_SENSATION: 'CommonBuffId' = 124696 - OBJECT_BONFIRE_BURNT_ARM: 'CommonBuffId' = 124682 - OBJECT_BONFIRE_COZY_BONFIRE: 'CommonBuffId' = 121835 - OBJECT_BONFIRE_COZY_FLIRTY_BUFF: 'CommonBuffId' = 126901 - OBJECT_BONFIRE_DIED_A_LITTLE_ART: 'CommonBuffId' = 124551 - OBJECT_BONFIRE_DIED_A_LITTLE_BOOK: 'CommonBuffId' = 123670 - OBJECT_BONFIRE_DIED_A_LITTLE_FOOD: 'CommonBuffId' = 124548 - OBJECT_BONFIRE_DIED_A_LITTLE_MUSIC: 'CommonBuffId' = 124649 - OBJECT_BONFIRE_FEELING_CONFIDENT: 'CommonBuffId' = 124707 - OBJECT_BONFIRE_FEELING_PLAYFUL: 'CommonBuffId' = 124658 - OBJECT_BONFIRE_FIRE_DECAY_STOP: 'CommonBuffId' = 126588 - OBJECT_BONFIRE_HAPPY_TOY: 'CommonBuffId' = 124657 - OBJECT_BONFIRE_HOMEWORK_HAPPY: 'CommonBuffId' = 124736 - OBJECT_BONFIRE_NOT_HOT_ENOUGH: 'CommonBuffId' = 125597 - OBJECT_BONFIRE_SAD_TOY: 'CommonBuffId' = 124656 - OBJECT_BONFIRE_WHATS_THAT_SMELL: 'CommonBuffId' = 124636 - OBJECT_BONSAI_ONE_WITH_PLANT: 'CommonBuffId' = 24596 - OBJECT_BONSAI_VIEW_ANGRY: 'CommonBuffId' = 37481 - OBJECT_BONSAI_VIEW_BOTCHED: 'CommonBuffId' = 37482 - OBJECT_BONSAI_VIEW_FLIRTY: 'CommonBuffId' = 37476 - OBJECT_BONSAI_VIEW_GENERIC: 'CommonBuffId' = 37483 - OBJECT_BONSAI_VIEW_INSPIRED: 'CommonBuffId' = 37480 - OBJECT_BONSAI_VIEW_PLAYFUL: 'CommonBuffId' = 37477 - OBJECT_BOOK_BROWSE_BOOKS: 'CommonBuffId' = 76994 - OBJECT_BOOK_STIMULATING_READ: 'CommonBuffId' = 75802 - OBJECT_BOWLING_LANE_BOWLING_KING: 'CommonBuffId' = 159005 - OBJECT_BOWLING_LANE_GLOVE_SHOES: 'CommonBuffId' = 161855 - OBJECT_BOWLING_LANE_HIDDEN_CHEATS_ALWAYS_TRICK: 'CommonBuffId' = 158907 - OBJECT_BOWLING_LANE_HIDDEN_CHEATS_NEVER_FAIL: 'CommonBuffId' = 158903 - OBJECT_BOWLING_LANE_HIDDEN_PICKED_UP_BALL: 'CommonBuffId' = 158386 - OBJECT_BOWLING_LANE_HIDDEN_SHOT_FAILED: 'CommonBuffId' = 158834 - OBJECT_BOWLING_LANE_HIDDEN_TURN_TAKEN: 'CommonBuffId' = 163786 - OBJECT_BOWLING_LANE_HIGH_SKILL_ON_FIRE: 'CommonBuffId' = 160622 - OBJECT_BOWLING_LANE_MOONLIGHT_BOWLING: 'CommonBuffId' = 161270 - OBJECT_BOWLING_LANE_OVER_BOWLED: 'CommonBuffId' = 159004 - OBJECT_BOWLING_LANE_SHOES: 'CommonBuffId' = 161421 - OBJECT_BOWLING_LANE_SORE_ARMS: 'CommonBuffId' = 159003 - OBJECT_BOWLING_LANE_THEY_CHEATED: 'CommonBuffId' = 159006 - OBJECT_BOWLING_LANE_WATCH_BOWLING_MATCH: 'CommonBuffId' = 159002 - OBJECT_BOX_OF_KINDNESS_SEARCH_COOLDOWN: 'CommonBuffId' = 199167 - OBJECT_BRAMBLE_PATCH_FREAKED_OUT: 'CommonBuffId' = 107011 - OBJECT_BRAMBLE_PATCH_MAULED_BY_BEAR: 'CommonBuffId' = 107012 - OBJECT_BRAMBLE_PATCH_TICKS: 'CommonBuffId' = 107010 - OBJECT_BUBBLE_BLOWER_AUTONOMOUS_USE_COOLDOWN_HIDDEN: 'CommonBuffId' = 135246 - OBJECT_BUBBLE_BLOWER_FAMILIARITY_REACTION_COOLDOWN: 'CommonBuffId' = 134857 - OBJECT_BUBBLE_BLOWER_USE_1_DEFAULT_FAIL1: 'CommonBuffId' = 135241 - OBJECT_BUBBLE_BLOWER_USE_1_DEFAULT_FAIL2: 'CommonBuffId' = 135991 - OBJECT_BUBBLE_BLOWER_USE_1_DEFAULT_SUCCESS1: 'CommonBuffId' = 135238 - OBJECT_BUBBLE_BLOWER_USE_1_DEFAULT_SUCCESS2: 'CommonBuffId' = 135992 - OBJECT_BUBBLE_BLOWER_USE_2_WHITE_FAIL1: 'CommonBuffId' = 135239 - OBJECT_BUBBLE_BLOWER_USE_2_WHITE_FAIL2: 'CommonBuffId' = 138273 - OBJECT_BUBBLE_BLOWER_USE_2_WHITE_SUCCESS1: 'CommonBuffId' = 135240 - OBJECT_BUBBLE_BLOWER_USE_2_WHITE_SUCCESS2: 'CommonBuffId' = 138274 - OBJECT_BUBBLE_BLOWER_USE_3_BLUE_FAIL1: 'CommonBuffId' = 135309 - OBJECT_BUBBLE_BLOWER_USE_3_BLUE_FAIL2: 'CommonBuffId' = 136023 - OBJECT_BUBBLE_BLOWER_USE_3_BLUE_SUCCESS1: 'CommonBuffId' = 135306 - OBJECT_BUBBLE_BLOWER_USE_3_BLUE_SUCCESS2: 'CommonBuffId' = 136022 - OBJECT_BUBBLE_BLOWER_USE_4_RED_FAIL1: 'CommonBuffId' = 135308 - OBJECT_BUBBLE_BLOWER_USE_4_RED_FAIL2: 'CommonBuffId' = 138290 - OBJECT_BUBBLE_BLOWER_USE_4_RED_SUCCESS1: 'CommonBuffId' = 135310 - OBJECT_BUBBLE_BLOWER_USE_4_RED_SUCCESS2: 'CommonBuffId' = 138289 - OBJECT_BUBBLE_BLOWER_USE_5_GREEN_FAIL1: 'CommonBuffId' = 135324 - OBJECT_BUBBLE_BLOWER_USE_5_GREEN_FAIL2: 'CommonBuffId' = 136298 - OBJECT_BUBBLE_BLOWER_USE_5_GREEN_SUCCESS1: 'CommonBuffId' = 135311 - OBJECT_BUBBLE_BLOWER_USE_5_GREEN_SUCCESS2: 'CommonBuffId' = 136299 - OBJECT_BUBBLE_BLOWER_USE_6_PURPLE_FAIL1: 'CommonBuffId' = 135307 - OBJECT_BUBBLE_BLOWER_USE_6_PURPLE_FAIL2: 'CommonBuffId' = 138277 - OBJECT_BUBBLE_BLOWER_USE_6_PURPLE_SUCCESS1: 'CommonBuffId' = 135325 - OBJECT_BUBBLE_BLOWER_USE_6_PURPLE_SUCCESS2: 'CommonBuffId' = 138278 - OBJECT_BUBBLE_BLOWER_USE_7_DENSE_FAIL1: 'CommonBuffId' = 135326 - OBJECT_BUBBLE_BLOWER_USE_7_DENSE_FAIL2: 'CommonBuffId' = 138291 - OBJECT_BUBBLE_BLOWER_USE_7_DENSE_SUCCESS1: 'CommonBuffId' = 135327 - OBJECT_BUBBLE_BLOWER_USE_7_DENSE_SUCCESS2: 'CommonBuffId' = 138292 - OBJECT_BUBBLE_BLOWER_USE_8_NEON_FAIL: 'CommonBuffId' = 135410 - OBJECT_BUBBLE_BLOWER_USE_8_NEON_FAIL2: 'CommonBuffId' = 135990 - OBJECT_BUBBLE_BLOWER_USE_8_NEON_SUCCESS: 'CommonBuffId' = 135409 - OBJECT_BUBBLE_BLOWER_USE_8_NEON_SUCCESS2: 'CommonBuffId' = 135993 - OBJECT_BUBBLE_BLOWER_USE_9_YELLOW_FAIL1: 'CommonBuffId' = 135904 - OBJECT_BUBBLE_BLOWER_USE_9_YELLOW_FAIL2: 'CommonBuffId' = 138276 - OBJECT_BUBBLE_BLOWER_USE_9_YELLOW_SUCCESS1: 'CommonBuffId' = 135903 - OBJECT_BUBBLE_BLOWER_USE_9_YELLOW_SUCCESS2: 'CommonBuffId' = 138275 - OBJECT_BUBBLE_BLOWER_USING_HIDDEN: 'CommonBuffId' = 143874 - OBJECT_BUBBLE_BOTTLE_ANNOYED_BY_BUBBLES: 'CommonBuffId' = 145888 - OBJECT_BUBBLE_BOTTLE_AUTONOMOUS_COOLDOWN_HIDDEN: 'CommonBuffId' = 145889 - OBJECT_BUBBLE_BOTTLE_BUBBLES: 'CommonBuffId' = 145884 - OBJECT_BUBBLE_BOTTLE_BUBBLES_HOW_INTERESTING: 'CommonBuffId' = 145886 - OBJECT_BUBBLE_BOTTLE_WHEE_BUBBLES: 'CommonBuffId' = 145885 - OBJECT_BUBBLE_BOTTLE_WOAH_BUBBLES: 'CommonBuffId' = 145887 - OBJECT_CAMPFIRE_BURNT_ARM: 'CommonBuffId' = 101942 - OBJECT_CAMPFIRE_COZY_FIRE: 'CommonBuffId' = 102665 - OBJECT_CAMPFIRE_MMMM_MARSHMALLOW: 'CommonBuffId' = 105236 - OBJECT_CAMPFIRE_SMORE: 'CommonBuffId' = 105238 - OBJECT_CAMPING_BATHROOM_BUGGED: 'CommonBuffId' = 104846 - OBJECT_CANDLE_MAKING_STATION_CANDLE_AURA_ENERGIZED_1: 'CommonBuffId' = 236742 - OBJECT_CANDLE_MAKING_STATION_CANDLE_AURA_ENERGIZED_2: 'CommonBuffId' = 236743 - OBJECT_CANDLE_MAKING_STATION_CANDLE_AURA_FLIRTY_1: 'CommonBuffId' = 236738 - OBJECT_CANDLE_MAKING_STATION_CANDLE_AURA_FLIRTY_2: 'CommonBuffId' = 236739 - OBJECT_CANDLE_MAKING_STATION_CANDLE_AURA_FOCUSED_1: 'CommonBuffId' = 236740 - OBJECT_CANDLE_MAKING_STATION_CANDLE_AURA_FOCUSED_2: 'CommonBuffId' = 236741 - OBJECT_CANDLE_MAKING_STATION_CANDLE_AURA_HAPPY_1: 'CommonBuffId' = 236735 - OBJECT_CANDLE_MAKING_STATION_CANDLE_AURA_HAPPY_2: 'CommonBuffId' = 236736 - OBJECT_CANDLE_MAKING_STATION_CANDLE_AURA_PLAYFUL_1: 'CommonBuffId' = 236744 - OBJECT_CANDLE_MAKING_STATION_CANDLE_AURA_SAD_1: 'CommonBuffId' = 236745 - OBJECT_CANDLE_MAKING_STATION_CANDLE_AURA_SAD_2: 'CommonBuffId' = 236737 - OBJECT_CANDY_BOWL_BOWL_OF_FRIGHTS_HAPPY: 'CommonBuffId' = 124902 - OBJECT_CANDY_BOWL_BOWL_OF_FRIGHTS_STRESSFUL: 'CommonBuffId' = 124903 - OBJECT_CARD_GAME_FOCUSED: 'CommonBuffId' = 9513 - OBJECT_CARD_GAME_LOSE1: 'CommonBuffId' = 9580 - OBJECT_CARD_GAME_LOSE2: 'CommonBuffId' = 9581 - OBJECT_CARD_GAME_LOSE3: 'CommonBuffId' = 9582 - OBJECT_CARD_GAME_WIN1: 'CommonBuffId' = 9576 - OBJECT_CARD_GAME_WIN2: 'CommonBuffId' = 9583 - OBJECT_CEILING_FAN_COOLING: 'CommonBuffId' = 210313 - OBJECT_CEILING_FAN_DRYING: 'CommonBuffId' = 210312 - OBJECT_CHAIR_IS_SITTING: 'CommonBuffId' = 12490 - OBJECT_CHEMISTRY_LAB_INTERESTING_RESULTS: 'CommonBuffId' = 105415 - OBJECT_CHEMISTRY_LAB_TOXIC_FUMES: 'CommonBuffId' = 105417 - OBJECT_CHEMISTRY_LAB_WHY_WONT_IT_WORK: 'CommonBuffId' = 105416 - OBJECT_CHESS_TABLE_PONDER: 'CommonBuffId' = 39970 - OBJECT_CHESS_TABLE_WIN: 'CommonBuffId' = 28209 - OBJECT_CHESS_TABLE_WIN_HIGH_LOGIC: 'CommonBuffId' = 28210 - OBJECT_CLAY_BLOB_INSPIRED: 'CommonBuffId' = 39930 - OBJECT_CLOSET_BREAKING_THROUGH: 'CommonBuffId' = 125375 - OBJECT_CLOSET_CLOSET_CHAOS: 'CommonBuffId' = 129060 - OBJECT_CLOSET_CONSOLE_COOLDOWN_HIDDEN: 'CommonBuffId' = 130145 - OBJECT_CLOSET_FASHION_RECOGNIZED: 'CommonBuffId' = 125382 - OBJECT_CLOSET_FASHION_SCORN: 'CommonBuffId' = 125392 - OBJECT_CLOSET_HUNG_UP: 'CommonBuffId' = 125393 - OBJECT_CLOSET_LEAVE_CLOSET_AFTER_CONSOLE: 'CommonBuffId' = 130315 - OBJECT_CLOSET_LOVE_STRANGE_PLACES: 'CommonBuffId' = 125377 - OBJECT_CLOSET_OUTFIT_TRACKER_BUFFS_ATHLETIC: 'CommonBuffId' = 121916 - OBJECT_CLOSET_OUTFIT_TRACKER_BUFFS_COLD_WEATHER: 'CommonBuffId' = 192477 - OBJECT_CLOSET_OUTFIT_TRACKER_BUFFS_EVERYDAY: 'CommonBuffId' = 121914 - OBJECT_CLOSET_OUTFIT_TRACKER_BUFFS_FAIL: 'CommonBuffId' = 121920 - OBJECT_CLOSET_OUTFIT_TRACKER_BUFFS_FORMAL: 'CommonBuffId' = 121915 - OBJECT_CLOSET_OUTFIT_TRACKER_BUFFS_HOT_WEATHER: 'CommonBuffId' = 192476 - OBJECT_CLOSET_OUTFIT_TRACKER_BUFFS_PARTY: 'CommonBuffId' = 121918 - OBJECT_CLOSET_OUTFIT_TRACKER_BUFFS_SLEEPWEAR: 'CommonBuffId' = 121917 - OBJECT_CLOSET_OUTFIT_TRACKER_BUFFS_SWIM: 'CommonBuffId' = 121919 - OBJECT_CLOSET_SEE_OUTFIT_COOLDOWN_ATHLETIC: 'CommonBuffId' = 129001 - OBJECT_CLOSET_SEE_OUTFIT_COOLDOWN_COLD_WEATHER: 'CommonBuffId' = 186304 - OBJECT_CLOSET_SEE_OUTFIT_COOLDOWN_EVERYDAY: 'CommonBuffId' = 129002 - OBJECT_CLOSET_SEE_OUTFIT_COOLDOWN_FORMAL: 'CommonBuffId' = 129003 - OBJECT_CLOSET_SEE_OUTFIT_COOLDOWN_HOT_WEATHER: 'CommonBuffId' = 186305 - OBJECT_CLOSET_SEE_OUTFIT_COOLDOWN_PARTY: 'CommonBuffId' = 129004 - OBJECT_CLOSET_SEE_OUTFIT_COOLDOWN_SLEEP: 'CommonBuffId' = 129005 - OBJECT_CLOSET_SEE_OUTFIT_COOLDOWN_SWIM: 'CommonBuffId' = 129006 - OBJECT_CLOSET_TRY_NEW_OUTFIT_KEEP_OUTFIT: 'CommonBuffId' = 121122 - OBJECT_CLOSET_VENUE_WOOHOO_EXHILERATING: 'CommonBuffId' = 377110 - OBJECT_COFFEE_CAFFEINE0: 'CommonBuffId' = 100835 - OBJECT_COFFEE_CAFFEINE1: 'CommonBuffId' = 12492 - OBJECT_COFFEE_CAFFEINE2: 'CommonBuffId' = 99749 - OBJECT_COFFEE_CART_LINGERING_FLAVOR_CONFIDENT: 'CommonBuffId' = 225265 - OBJECT_COFFEE_CART_LINGERING_FLAVOR_FOCUSED: 'CommonBuffId' = 225266 - OBJECT_COFFEE_CART_LINGERING_FLAVOR_INSPIRED: 'CommonBuffId' = 225268 - OBJECT_COFFEE_CART_LINGERING_FLAVOR_PLAYFUL: 'CommonBuffId' = 225267 - OBJECT_COFFEE_OVERLOAD: 'CommonBuffId' = 99783 - OBJECT_COFFIN_HIBERNATE: 'CommonBuffId' = 149961 - OBJECT_COFFIN_NON_VAMPIRE: 'CommonBuffId' = 149984 - OBJECT_COLLECTIBLES_FASCINATING_SPECIMEN: 'CommonBuffId' = 40109 - OBJECT_COMPUTER_BRAIN_FRIED: 'CommonBuffId' = 36129 - OBJECT_COMPUTER_EPIC_GAME: 'CommonBuffId' = 33114 - OBJECT_COMPUTER_EXCUSE_NOTE_COOLDOWN: 'CommonBuffId' = 100437 - OBJECT_COMPUTER_FOCUSED_RESEARCH_SIMPEDIA: 'CommonBuffId' = 31038 - OBJECT_COMPUTER_HIGH_SCORE: 'CommonBuffId' = 30991 - OBJECT_COMPUTER_INSPIRING_ART: 'CommonBuffId' = 40075 - OBJECT_COMPUTER_MAKE_CONNECTIONS_COOLDOWN: 'CommonBuffId' = 99637 - OBJECT_COMPUTER_PICK_UP_LINES: 'CommonBuffId' = 40080 - OBJECT_COMPUTER_PROGRAMMING_SKILL_ACCOMPLISHED: 'CommonBuffId' = 31591 - OBJECT_COMPUTER_PROGRAMMING_SKILL_FEELING_DEVIOUS: 'CommonBuffId' = 33268 - OBJECT_COMPUTER_PROGRAMMING_SKILL_JOB_WELL_DONE: 'CommonBuffId' = 33241 - OBJECT_COMPUTER_RESEARCH_IDIOMS_BORED: 'CommonBuffId' = 37238 - OBJECT_COMPUTER_RESEARCH_IDIOMS_INSPIRED: 'CommonBuffId' = 37236 - OBJECT_COMPUTER_RESPOND_TO_MAIL_NEGATIVE_CRITICISM: 'CommonBuffId' = 136551 - OBJECT_COMPUTER_RESPOND_TO_MAIL_POSITIVE_FEEDBACK: 'CommonBuffId' = 136550 - OBJECT_COMPUTER_RESPOND_TO_MAIL_TROLLED: 'CommonBuffId' = 136552 - OBJECT_COMPUTER_WATCH_SIM_TUBE_PLAYFUL: 'CommonBuffId' = 37223 - OBJECT_COOLER_REFRESHINGLY_COOL: 'CommonBuffId' = 102142 - OBJECT_COZY_FIRE: 'CommonBuffId' = 75075 - OBJECT_CRAFT_SALES_TABLE_AUTONOMY_MOD_BROWSE: 'CommonBuffId' = 145279 - OBJECT_CRAFT_SALES_TABLE_AUTONOMY_MOD_BROWSE_ONLY_SCORED: 'CommonBuffId' = 256565 - OBJECT_CRAFT_SALES_TABLE_AUTONOMY_MOD_CLOSE: 'CommonBuffId' = 147530 - OBJECT_CRAFT_SALES_TABLE_AUTONOMY_MOD_CREATE_ITEMS: 'CommonBuffId' = 148007 - OBJECT_CRAFT_SALES_TABLE_AUTONOMY_MOD_STOCK: 'CommonBuffId' = 146946 - OBJECT_CRAFT_SALES_TABLE_AUTONOMY_MOD_STOCK_PAINTINGS: 'CommonBuffId' = 154454 - OBJECT_CRAFT_SALES_TABLE_AUTONOMY_MOD_STOCK_PAINTINGS_STAFFED_ONLY: 'CommonBuffId' = 238446 - OBJECT_CRAFT_SALES_TABLE_AUTONOMY_MOD_STOCK_STAFFED_ONLY: 'CommonBuffId' = 238445 - OBJECT_CRAFT_SALES_TABLE_AUTONOMY_MOD_TEND: 'CommonBuffId' = 145287 - OBJECT_CRAFT_SALES_TABLE_HAGGLE_SUCCEED: 'CommonBuffId' = 145222 - OBJECT_CRAFT_SALES_TABLE_HIGHER_BUY_CHANCE: 'CommonBuffId' = 145274 - OBJECT_CRYSTAL_HELMET_DEBUFFS_ANGRY: 'CommonBuffId' = 194329 - OBJECT_CRYSTAL_HELMET_DEBUFFS_BORED: 'CommonBuffId' = 194305 - OBJECT_CRYSTAL_HELMET_DEBUFFS_EMBARRASSED: 'CommonBuffId' = 194306 - OBJECT_CRYSTAL_HELMET_DEBUFFS_SAD: 'CommonBuffId' = 194307 - OBJECT_CRYSTAL_HELMET_DEBUFFS_STRESSED: 'CommonBuffId' = 194304 - OBJECT_CRYSTAL_HELMET_DEBUFFS_UNCOMFORTABLE: 'CommonBuffId' = 194308 - OBJECT_CRYSTAL_HELMET_DESTROY_CRYSTAL: 'CommonBuffId' = 193352 - OBJECT_CRYSTAL_HELMET_EMBARRASSED_BY_VIEWER: 'CommonBuffId' = 198603 - OBJECT_CRYSTAL_HELMET_HAPPY_FROM_PROXIMITY_RAINBORZ: 'CommonBuffId' = 194859 - OBJECT_CRYSTAL_HELMET_MOTIVE_TANK_BLADDER: 'CommonBuffId' = 196663 - OBJECT_CRYSTAL_HELMET_MOTIVE_TANK_FUN: 'CommonBuffId' = 196664 - OBJECT_CRYSTAL_HELMET_MOTIVE_TANK_HUNGER: 'CommonBuffId' = 193558 - OBJECT_CRYSTAL_HELMET_MOTIVE_TANK_HYGIENE: 'CommonBuffId' = 196665 - OBJECT_CRYSTAL_HELMET_MOTIVE_TANK_PLANT_SIM_WATER: 'CommonBuffId' = 196666 - OBJECT_CRYSTAL_HELMET_MOTIVE_TANK_SOCIAL: 'CommonBuffId' = 196667 - OBJECT_CRYSTAL_HELMET_MOTIVE_TANK_VAMPIRE_POWER: 'CommonBuffId' = 196668 - OBJECT_CRYSTAL_HELMET_MOTIVE_TANK_VAMPIRE_THIRST: 'CommonBuffId' = 196669 - OBJECT_CRYSTAL_HELMET_REMOVE_QUIRK: 'CommonBuffId' = 200842 - OBJECT_CRYSTAL_HELMET_TRAITS_ALABASTER: 'CommonBuffId' = 193945 - OBJECT_CRYSTAL_HELMET_TRAITS_ALEXANDRITE_EP: 'CommonBuffId' = 193955 - OBJECT_CRYSTAL_HELMET_TRAITS_AMAZONITE_EP: 'CommonBuffId' = 193956 - OBJECT_CRYSTAL_HELMET_TRAITS_AMETHYST: 'CommonBuffId' = 193553 - OBJECT_CRYSTAL_HELMET_TRAITS_CITRINE: 'CommonBuffId' = 193957 - OBJECT_CRYSTAL_HELMET_TRAITS_CRANDESTINE_EP: 'CommonBuffId' = 193958 - OBJECT_CRYSTAL_HELMET_TRAITS_DIAMOND: 'CommonBuffId' = 193959 - OBJECT_CRYSTAL_HELMET_TRAITS_EMERALD: 'CommonBuffId' = 193960 - OBJECT_CRYSTAL_HELMET_TRAITS_FIRE_OPAL: 'CommonBuffId' = 193961 - OBJECT_CRYSTAL_HELMET_TRAITS_HEMATITE: 'CommonBuffId' = 193962 - OBJECT_CRYSTAL_HELMET_TRAITS_JET: 'CommonBuffId' = 193963 - OBJECT_CRYSTAL_HELMET_TRAITS_JONQUILYST: 'CommonBuffId' = 193964 - OBJECT_CRYSTAL_HELMET_TRAITS_NITELITE_EP: 'CommonBuffId' = 193965 - OBJECT_CRYSTAL_HELMET_TRAITS_ORANGE_TOPAZ: 'CommonBuffId' = 193966 - OBJECT_CRYSTAL_HELMET_TRAITS_PEACH: 'CommonBuffId' = 193967 - OBJECT_CRYSTAL_HELMET_TRAITS_PLUMBITE: 'CommonBuffId' = 193968 - OBJECT_CRYSTAL_HELMET_TRAITS_QUARTZ: 'CommonBuffId' = 193969 - OBJECT_CRYSTAL_HELMET_TRAITS_RAINBORZ: 'CommonBuffId' = 193970 - OBJECT_CRYSTAL_HELMET_TRAITS_ROSE: 'CommonBuffId' = 193971 - OBJECT_CRYSTAL_HELMET_TRAITS_RUBY: 'CommonBuffId' = 193972 - OBJECT_CRYSTAL_HELMET_TRAITS_SAPPHIRE: 'CommonBuffId' = 193973 - OBJECT_CRYSTAL_HELMET_TRAITS_SHINALITE: 'CommonBuffId' = 193974 - OBJECT_CRYSTAL_HELMET_TRAITS_SIMANITE: 'CommonBuffId' = 193975 - OBJECT_CRYSTAL_HELMET_TRAITS_TURQUOISE: 'CommonBuffId' = 193976 - OBJECT_CRYSTAL_HELMET_VFX_ADULT_ALABASTER: 'CommonBuffId' = 196573 - OBJECT_CRYSTAL_HELMET_VFX_ADULT_ALEXANDRITE_EP: 'CommonBuffId' = 196566 - OBJECT_CRYSTAL_HELMET_VFX_ADULT_AMAZONITE_EP: 'CommonBuffId' = 196580 - OBJECT_CRYSTAL_HELMET_VFX_ADULT_AMETHYST: 'CommonBuffId' = 196581 - OBJECT_CRYSTAL_HELMET_VFX_ADULT_CITRINE: 'CommonBuffId' = 196574 - OBJECT_CRYSTAL_HELMET_VFX_ADULT_CRANDESTINE_EP: 'CommonBuffId' = 196567 - OBJECT_CRYSTAL_HELMET_VFX_ADULT_DIAMOND: 'CommonBuffId' = 196582 - OBJECT_CRYSTAL_HELMET_VFX_ADULT_EMERALD: 'CommonBuffId' = 196575 - OBJECT_CRYSTAL_HELMET_VFX_ADULT_FIRE_OPAL: 'CommonBuffId' = 196583 - OBJECT_CRYSTAL_HELMET_VFX_ADULT_HEMATITE: 'CommonBuffId' = 196584 - OBJECT_CRYSTAL_HELMET_VFX_ADULT_JET: 'CommonBuffId' = 196568 - OBJECT_CRYSTAL_HELMET_VFX_ADULT_JONQUILYST: 'CommonBuffId' = 196569 - OBJECT_CRYSTAL_HELMET_VFX_ADULT_NITELITE_EP: 'CommonBuffId' = 196570 - OBJECT_CRYSTAL_HELMET_VFX_ADULT_ORANGE_TOPAZ: 'CommonBuffId' = 196576 - OBJECT_CRYSTAL_HELMET_VFX_ADULT_PEACH: 'CommonBuffId' = 196585 - OBJECT_CRYSTAL_HELMET_VFX_ADULT_PLUMBITE: 'CommonBuffId' = 196571 - OBJECT_CRYSTAL_HELMET_VFX_ADULT_QUARTZ: 'CommonBuffId' = 196577 - OBJECT_CRYSTAL_HELMET_VFX_ADULT_RAINBORZ: 'CommonBuffId' = 196572 - OBJECT_CRYSTAL_HELMET_VFX_ADULT_ROSE: 'CommonBuffId' = 196578 - OBJECT_CRYSTAL_HELMET_VFX_ADULT_RUBY: 'CommonBuffId' = 196586 - OBJECT_CRYSTAL_HELMET_VFX_ADULT_SAPPHIRE: 'CommonBuffId' = 196587 - OBJECT_CRYSTAL_HELMET_VFX_ADULT_SHINALITE: 'CommonBuffId' = 196588 - OBJECT_CRYSTAL_HELMET_VFX_ADULT_SIMANITE: 'CommonBuffId' = 196589 - OBJECT_CRYSTAL_HELMET_VFX_ADULT_TURQUOISE: 'CommonBuffId' = 196579 - OBJECT_CRYSTAL_HELMET_VFX_CHILD_ALABASTER: 'CommonBuffId' = 196590 - OBJECT_CRYSTAL_HELMET_VFX_CHILD_ALEXANDRITE_EP: 'CommonBuffId' = 196591 - OBJECT_CRYSTAL_HELMET_VFX_CHILD_AMAZONITE_EP: 'CommonBuffId' = 196592 - OBJECT_CRYSTAL_HELMET_VFX_CHILD_AMETHYST: 'CommonBuffId' = 196593 - OBJECT_CRYSTAL_HELMET_VFX_CHILD_CITRINE: 'CommonBuffId' = 196594 - OBJECT_CRYSTAL_HELMET_VFX_CHILD_CRANDESTINE_EP: 'CommonBuffId' = 196595 - OBJECT_CRYSTAL_HELMET_VFX_CHILD_DIAMOND: 'CommonBuffId' = 196596 - OBJECT_CRYSTAL_HELMET_VFX_CHILD_EMERALD: 'CommonBuffId' = 196597 - OBJECT_CRYSTAL_HELMET_VFX_CHILD_FIRE_OPAL: 'CommonBuffId' = 196598 - OBJECT_CRYSTAL_HELMET_VFX_CHILD_HEMATITE: 'CommonBuffId' = 196599 - OBJECT_CRYSTAL_HELMET_VFX_CHILD_JET: 'CommonBuffId' = 196600 - OBJECT_CRYSTAL_HELMET_VFX_CHILD_JONQUILYST: 'CommonBuffId' = 196601 - OBJECT_CRYSTAL_HELMET_VFX_CHILD_NITELITE_EP: 'CommonBuffId' = 196602 - OBJECT_CRYSTAL_HELMET_VFX_CHILD_ORANGE_TOPAZ: 'CommonBuffId' = 196603 - OBJECT_CRYSTAL_HELMET_VFX_CHILD_PEACH: 'CommonBuffId' = 196604 - OBJECT_CRYSTAL_HELMET_VFX_CHILD_PLUMBITE: 'CommonBuffId' = 196605 - OBJECT_CRYSTAL_HELMET_VFX_CHILD_QUARTZ: 'CommonBuffId' = 196606 - OBJECT_CRYSTAL_HELMET_VFX_CHILD_RAINBORZ: 'CommonBuffId' = 196607 - OBJECT_CRYSTAL_HELMET_VFX_CHILD_ROSE: 'CommonBuffId' = 196608 - OBJECT_CRYSTAL_HELMET_VFX_CHILD_RUBY: 'CommonBuffId' = 196609 - OBJECT_CRYSTAL_HELMET_VFX_CHILD_SAPPHIRE: 'CommonBuffId' = 196610 - OBJECT_CRYSTAL_HELMET_VFX_CHILD_SHINALITE: 'CommonBuffId' = 196611 - OBJECT_CRYSTAL_HELMET_VFX_CHILD_SIMANITE: 'CommonBuffId' = 196612 - OBJECT_CRYSTAL_HELMET_VFX_CHILD_TURQUOISE: 'CommonBuffId' = 196613 - OBJECT_CRYSTAL_HELMET_WEARING: 'CommonBuffId' = 192776 - OBJECT_CRYSTAL_HELMET_WEARING_INCOMPATIBLE_OUTFIT_BG: 'CommonBuffId' = 198617 - OBJECT_DANCE_FLOOR_DANCE_BATTLE_COMPLETE: 'CommonBuffId' = 129315 - OBJECT_DANCE_FLOOR_GROUP_DANCE_POSITIVE: 'CommonBuffId' = 128898 - OBJECT_DANCE_FLOOR_SHOW_OFF_MOVES_NEGATIVE: 'CommonBuffId' = 125319 - OBJECT_DANCE_FLOOR_SHOW_OFF_MOVES_NEUTRAL: 'CommonBuffId' = 128293 - OBJECT_DANCE_FLOOR_SHOW_OFF_MOVES_PERFORMER: 'CommonBuffId' = 125498 - OBJECT_DANCE_FLOOR_SHOW_OFF_MOVES_POSITIVE: 'CommonBuffId' = 125318 - OBJECT_DANCE_FLOOR_SHOW_OFF_MOVES_WATCHER: 'CommonBuffId' = 125499 - OBJECT_DARTBOARD_BULLS_EYE: 'CommonBuffId' = 128291 - OBJECT_DARTBOARD_DART_VICTORY: 'CommonBuffId' = 128481 - OBJECT_DARTBOARD_OFF_TARGET: 'CommonBuffId' = 128292 - OBJECT_DARTBOARD_SORE_LOSER: 'CommonBuffId' = 128480 - OBJECT_DARTBOARD_TAKING_A_TURN: 'CommonBuffId' = 127951 - OBJECT_DARTBOARD_WAITING_FOR_TURN: 'CommonBuffId' = 130245 - OBJECT_DJ_BOOTH_BUMP_IN_BEATS: 'CommonBuffId' = 122759 - OBJECT_DJ_BOOTH_FEEL_THE_CROWD_CONFIDENT: 'CommonBuffId' = 122749 - OBJECT_DJ_BOOTH_FEEL_THE_CROWD_DAZED: 'CommonBuffId' = 122747 - OBJECT_DJ_BOOTH_FEEL_THE_CROWD_ENERGIZED: 'CommonBuffId' = 122712 - OBJECT_DJ_BOOTH_FEEL_THE_CROWD_FLIRTY: 'CommonBuffId' = 122748 - OBJECT_DJ_BOOTH_FEEL_THE_CROWD_VFX: 'CommonBuffId' = 128367 - OBJECT_DJ_BOOTH_HIDDEN_CROWD_MEMBER: 'CommonBuffId' = 122968 - OBJECT_DJ_BOOTH_HIDDEN_DJ_PERFORMING: 'CommonBuffId' = 122685 - OBJECT_DJ_BOOTH_HIDDEN_DJ_PRACTICING: 'CommonBuffId' = 123910 - OBJECT_DJ_BOOTH_HIDDEN_FEEL_THE_CROWD_COOLDOWN: 'CommonBuffId' = 122756 - OBJECT_DJ_BOOTH_HIDDEN_GET_HYPED_COOLDOWN: 'CommonBuffId' = 122842 - OBJECT_DJ_BOOTH_HIDDEN_JUST_TIPPED: 'CommonBuffId' = 130613 - OBJECT_DJ_BOOTH_HIDDEN_TIPS_COLLECTED: 'CommonBuffId' = 128097 - OBJECT_DJ_BOOTH_IM_ADJ: 'CommonBuffId' = 122760 - OBJECT_DJ_BOOTH_MIX_MASTER: 'CommonBuffId' = 126112 - OBJECT_DJ_BOOTH_SERIOUS_SONIC_SKILLS: 'CommonBuffId' = 122758 - OBJECT_DJ_BOOTH_TERRIBLE_TURNTABLISM: 'CommonBuffId' = 122762 - OBJECT_DJ_BOOTH_UNCE_UNCE_UGH: 'CommonBuffId' = 122761 - OBJECT_DOLLHOUSE_ACT_OF_KINDNESS: 'CommonBuffId' = 32287 - OBJECT_DOLLHOUSE_DESTRUCTIVE_TODDLER_HAPPY: 'CommonBuffId' = 333447 - OBJECT_DOLLHOUSE_INSPIRED: 'CommonBuffId' = 30897 - OBJECT_DOLLHOUSE_INSPIRED_STAT_MOD: 'CommonBuffId' = 75731 - OBJECT_DOLLHOUSE_PLAYED_WITH: 'CommonBuffId' = 38797 - OBJECT_DOLLHOUSE_WICKED_ACT: 'CommonBuffId' = 30929 - OBJECT_DONE_PONDERING_HIDDEN: 'CommonBuffId' = 40570 - OBJECT_DONT_WAKE_LLAMA_KEEP_PLAYING: 'CommonBuffId' = 130259 - OBJECT_DONT_WAKE_LLAMA_LEFT_CHALLENGE: 'CommonBuffId' = 129595 - OBJECT_DONT_WAKE_LLAMA_LLAMA_ALMOST_FELL: 'CommonBuffId' = 127830 - OBJECT_DONT_WAKE_LLAMA_LLAMA_CRIES_SAD: 'CommonBuffId' = 127832 - OBJECT_DONT_WAKE_LLAMA_LLAMA_SLEEPS_HAPPY: 'CommonBuffId' = 127831 - OBJECT_DONT_WAKE_LLAMA_LOSE_CHALLENGE: 'CommonBuffId' = 129585 - OBJECT_DONT_WAKE_LLAMA_STOP_PLAYING: 'CommonBuffId' = 130067 - OBJECT_DRESSER_TRY_ON_OUTFITS: 'CommonBuffId' = 40131 - OBJECT_DRINK_ALIEN_JUICE_ENERGIZED: 'CommonBuffId' = 33746 - OBJECT_DRINK_ALIEN_JUICE_SOCIAL_MOTIVE: 'CommonBuffId' = 33747 - OBJECT_DRINK_ALIEN_JUICE_SOCIAL_SUCCESS: 'CommonBuffId' = 33748 - OBJECT_DRINK_BARTENDING_0: 'CommonBuffId' = 10402 - OBJECT_DRINK_BARTENDING_0_FOODIE: 'CommonBuffId' = 27401 - OBJECT_DRINK_BARTENDING_2: 'CommonBuffId' = 10404 - OBJECT_DRINK_BARTENDING_2_FLAMING: 'CommonBuffId' = 35019 - OBJECT_DRINK_BARTENDING_2_FOODIE: 'CommonBuffId' = 27402 - OBJECT_DRINK_BARTENDING_3: 'CommonBuffId' = 10405 - OBJECT_DRINK_BARTENDING_3_FLAMING: 'CommonBuffId' = 35068 - OBJECT_DRINK_BARTENDING_3_FOODIE: 'CommonBuffId' = 27403 - OBJECT_DRINK_BARTENDING_4: 'CommonBuffId' = 10406 - OBJECT_DRINK_BARTENDING_4_FLAMING: 'CommonBuffId' = 35069 - OBJECT_DRINK_BARTENDING_4_FOODIE: 'CommonBuffId' = 27404 - OBJECT_DRINK_BATUU_DAGOBAH_SLUG_SLINGER: 'CommonBuffId' = 237756 - OBJECT_DRINK_BATUU_FUZZY_TAUN_TAUN: 'CommonBuffId' = 237755 - OBJECT_DRINK_BATUU_JET_JUICE_BAD: 'CommonBuffId' = 237758 - OBJECT_DRINK_BATUU_JET_JUICE_GOOD: 'CommonBuffId' = 237757 - OBJECT_DRINK_BEETLE_JUICE_1_INVISIBLE: 'CommonBuffId' = 235883 - OBJECT_DRINK_BEETLE_JUICE_2_VISIBLE: 'CommonBuffId' = 235884 - OBJECT_DRINK_BEETLE_JUICE_4_VISIBLE: 'CommonBuffId' = 237484 - OBJECT_DRINK_BOILER_ROOM_ANGRY_HIGH: 'CommonBuffId' = 73913 - OBJECT_DRINK_BOILER_ROOM_ANGRY_LOW: 'CommonBuffId' = 73912 - OBJECT_DRINK_CREATIVE: 'CommonBuffId' = 26346 - OBJECT_DRINK_CUPID_JUICE_FLIRTY_HIGH: 'CommonBuffId' = 73915 - OBJECT_DRINK_CUPID_JUICE_FLIRTY_LOW: 'CommonBuffId' = 73914 - OBJECT_DRINK_DYED_COCKTAIL_EMBARRASSED: 'CommonBuffId' = 235886 - OBJECT_DRINK_DYED_COCKTAIL_HAPPY: 'CommonBuffId' = 235885 - OBJECT_DRINK_FIZZY_DRINK_HAPPY: 'CommonBuffId' = 118861 - OBJECT_DRINK_FLIRTY: 'CommonBuffId' = 26351 - OBJECT_DRINK_INTELLECTUAL: 'CommonBuffId' = 26347 - OBJECT_DRINK_PHYSICAL: 'CommonBuffId' = 26350 - OBJECT_DRINK_SCIENCE_TABLE_BORED: 'CommonBuffId' = 31738 - OBJECT_DRINK_SCIENCE_TABLE_CONFIDENT: 'CommonBuffId' = 31721 - OBJECT_DRINK_SCIENCE_TABLE_HAPPY: 'CommonBuffId' = 31737 - OBJECT_DRINK_SCIENCE_TABLE_UNCOMFORTABLE: 'CommonBuffId' = 31739 - OBJECT_DRINK_SNAGGLE_FLUSTER: 'CommonBuffId' = 76714 - OBJECT_DRINK_TEA_BLACK: 'CommonBuffId' = 8257 - OBJECT_DRINK_TEA_EARL: 'CommonBuffId' = 8440 - OBJECT_DRINK_TEA_GINSENG: 'CommonBuffId' = 8436 - OBJECT_DRINK_TEA_GREEN: 'CommonBuffId' = 8305 - OBJECT_DRINK_TEA_LEMON_HONEY_GINGER: 'CommonBuffId' = 118393 - OBJECT_DRINK_TEA_LEMON_HONEY_GINGER_NO_LOOT: 'CommonBuffId' = 272782 - OBJECT_DRINK_TEA_OOLONG: 'CommonBuffId' = 8432 - OBJECT_DRINK_TEA_YERBA_MATE: 'CommonBuffId' = 176983 - OBJECT_DRINK_TODDLER_HAPPY: 'CommonBuffId' = 144670 - OBJECT_DRINK_VILLAGER_HELP_FOCUSED: 'CommonBuffId' = 267494 - OBJECT_DRINK_VILLAGER_HELP_FOCUSED_SAMPLER: 'CommonBuffId' = 267495 - OBJECT_DRINK_VILLAGER_HELP_PLAYFUL: 'CommonBuffId' = 267492 - OBJECT_DRINK_VILLAGER_HELP_PLAYFUL_SAMPLER: 'CommonBuffId' = 267493 - OBJECT_EAR_BUDS_HIDDEN_COLOR_CHILD_BLACK: 'CommonBuffId' = 169300 - OBJECT_EAR_BUDS_HIDDEN_COLOR_CHILD_BLUE: 'CommonBuffId' = 169301 - OBJECT_EAR_BUDS_HIDDEN_COLOR_CHILD_GOLD: 'CommonBuffId' = 169302 - OBJECT_EAR_BUDS_HIDDEN_COLOR_CHILD_GREEN: 'CommonBuffId' = 169303 - OBJECT_EAR_BUDS_HIDDEN_COLOR_CHILD_ORANGE: 'CommonBuffId' = 169304 - OBJECT_EAR_BUDS_HIDDEN_COLOR_CHILD_PINK: 'CommonBuffId' = 169305 - OBJECT_EAR_BUDS_HIDDEN_COLOR_CHILD_RED: 'CommonBuffId' = 169306 - OBJECT_EAR_BUDS_HIDDEN_COLOR_CHILD_TEAL: 'CommonBuffId' = 169307 - OBJECT_EAR_BUDS_HIDDEN_COLOR_CHILD_WHITE: 'CommonBuffId' = 169308 - OBJECT_EAR_BUDS_HIDDEN_EAR_BUDS_COLOR_BLACK: 'CommonBuffId' = 168734 - OBJECT_EAR_BUDS_HIDDEN_EAR_BUDS_COLOR_BLUE: 'CommonBuffId' = 168733 - OBJECT_EAR_BUDS_HIDDEN_EAR_BUDS_COLOR_GOLD: 'CommonBuffId' = 168736 - OBJECT_EAR_BUDS_HIDDEN_EAR_BUDS_COLOR_GREEN: 'CommonBuffId' = 168737 - OBJECT_EAR_BUDS_HIDDEN_EAR_BUDS_COLOR_ORANGE: 'CommonBuffId' = 168735 - OBJECT_EAR_BUDS_HIDDEN_EAR_BUDS_COLOR_PINK: 'CommonBuffId' = 168738 - OBJECT_EAR_BUDS_HIDDEN_EAR_BUDS_COLOR_RED: 'CommonBuffId' = 168739 - OBJECT_EAR_BUDS_HIDDEN_EAR_BUDS_COLOR_TEAL: 'CommonBuffId' = 168740 - OBJECT_EAR_BUDS_HIDDEN_EAR_BUDS_COLOR_WHITE: 'CommonBuffId' = 168741 - OBJECT_EAR_BUDS_HIDDEN_LISTENING_TO_MUSIC: 'CommonBuffId' = 164760 - OBJECT_EAR_BUDS_HIDDEN_REACT_INTERRUPT_SLEEP: 'CommonBuffId' = 168545 - OBJECT_EASEL_CANVAS_CREATED: 'CommonBuffId' = 10678 - OBJECT_EASEL_PRACTICE_PAINTING: 'CommonBuffId' = 40762 - OBJECT_EAT_TOXIC_PLANTS_CHAMOMILE: 'CommonBuffId' = 107485 - OBJECT_EAT_TOXIC_PLANTS_ELDERBERRY: 'CommonBuffId' = 107483 - OBJECT_EAT_TOXIC_PLANTS_FIRE_LEAF: 'CommonBuffId' = 107484 - OBJECT_EAT_TOXIC_PLANTS_HUCKLEBERRY: 'CommonBuffId' = 107482 - OBJECT_EAT_TOXIC_PLANTS_MOREL: 'CommonBuffId' = 107486 - OBJECT_ESPRESSO_BRIGHT_EYED: 'CommonBuffId' = 122957 - OBJECT_ESPRESSO_CAFFEINATED: 'CommonBuffId' = 122949 - OBJECT_ESPRESSO_FREEDOM: 'CommonBuffId' = 122955 - OBJECT_ESPRESSO_FUN_EMPLOYED: 'CommonBuffId' = 122965 - OBJECT_ESPRESSO_MARKED_FOR_FUN: 'CommonBuffId' = 122952 - OBJECT_ESPRESSO_MMMM_CHOCOLATE: 'CommonBuffId' = 122954 - OBJECT_ESPRESSO_MMMM_PHENETHYLAMINE: 'CommonBuffId' = 122953 - OBJECT_ESPRESSO_NEW_DISCOVERY: 'CommonBuffId' = 122956 - OBJECT_ESPRESSO_SCALDED_MILK: 'CommonBuffId' = 124347 - OBJECT_ESPRESSO_SOPHISTICATED: 'CommonBuffId' = 122951 - OBJECT_ESPRESSO_WARM_COMFORT: 'CommonBuffId' = 122950 - OBJECT_EXAM_BED_DOCTOR_SOCIAL_RECLINED: 'CommonBuffId' = 114026 - OBJECT_EXAM_BED_DOCTOR_SOCIAL_SEATED: 'CommonBuffId' = 114025 - OBJECT_EXAM_BED_PATIENT_DISCHARGE: 'CommonBuffId' = 110882 - OBJECT_EXPERIMENTAL_FOOD_PHOTO_PHOTO_HIPSTER: 'CommonBuffId' = 131891 - OBJECT_EXPERIMENTAL_FOOD_PHOTO_WELL_CURATED_COLLECTION: 'CommonBuffId' = 131890 - OBJECT_FITNESS_FATIGUED: 'CommonBuffId' = 12543 - OBJECT_FITNESS_FATIGUED_LAZY: 'CommonBuffId' = 28907 - OBJECT_FITNESS_GOOD_WORKOUT: 'CommonBuffId' = 31361 - OBJECT_FITNESS_POTENTIALLY_SORE: 'CommonBuffId' = 23986 - OBJECT_FITNESS_SORE: 'CommonBuffId' = 23987 - OBJECT_FITNESS_VERY_FATIGUED: 'CommonBuffId' = 31362 - OBJECT_FLOWER_ARRANGEMENT_ANGRY_DISRESPECT: 'CommonBuffId' = 187612 - OBJECT_FLOWER_ARRANGEMENT_CONFIDENT_FRIENDSHIP_GIVER: 'CommonBuffId' = 187661 - OBJECT_FLOWER_ARRANGEMENT_CONFIDENT_MAGNIFICENCE: 'CommonBuffId' = 187616 - OBJECT_FLOWER_ARRANGEMENT_CONFIDENT_MAGNIFICENCE_GIVER: 'CommonBuffId' = 187662 - OBJECT_FLOWER_ARRANGEMENT_DAZED_CURSED: 'CommonBuffId' = 187615 - OBJECT_FLOWER_ARRANGEMENT_FAITHFUL_RECEIVER: 'CommonBuffId' = 187703 - OBJECT_FLOWER_ARRANGEMENT_FLIRTY_ROMANCE: 'CommonBuffId' = 187611 - OBJECT_FLOWER_ARRANGEMENT_FLIRTY_ROMANCE_GIVER: 'CommonBuffId' = 187664 - OBJECT_FLOWER_ARRANGEMENT_HAPPY_FAITHFUL: 'CommonBuffId' = 188219 - OBJECT_FLOWER_ARRANGEMENT_HAPPY_FRIENDSHIP: 'CommonBuffId' = 187606 - OBJECT_FLOWER_ARRANGEMENT_HAPPY_JOY: 'CommonBuffId' = 187608 - OBJECT_FLOWER_ARRANGEMENT_HAPPY_JOY_GIVER: 'CommonBuffId' = 187665 - OBJECT_FLOWER_ARRANGEMENT_HIDDEN_CHRISTMAS_ROSE_ASLEEP: 'CommonBuffId' = 188764 - OBJECT_FLOWER_ARRANGEMENT_HIDDEN_CHRISTMAS_ROSE_SLEEP_DESIRE: 'CommonBuffId' = 188763 - OBJECT_FLOWER_ARRANGEMENT_HIDDEN_CHRISTMAS_ROSE_WOKE_UP: 'CommonBuffId' = 188765 - OBJECT_FLOWER_ARRANGEMENT_HIDDEN_COOLDOWN: 'CommonBuffId' = 188848 - OBJECT_FLOWER_ARRANGEMENT_HIDDEN_CURSED_EFFECTS: 'CommonBuffId' = 188702 - OBJECT_FLOWER_ARRANGEMENT_HIDDEN_SNAPDRAGON_DISRESPECT: 'CommonBuffId' = 191507 - OBJECT_FLOWER_ARRANGEMENT_HIDDEN_SNAPDRAGON_DISRESPECT_TURN_ONE: 'CommonBuffId' = 188184 - OBJECT_FLOWER_ARRANGEMENT_HIDDEN_SNAPDRAGON_DISRESPECT_TURN_TWO: 'CommonBuffId' = 188185 - OBJECT_FLOWER_ARRANGEMENT_INSPIRED_CREATIVITY: 'CommonBuffId' = 187613 - OBJECT_FLOWER_ARRANGEMENT_INSPIRED_SEASONS: 'CommonBuffId' = 187614 - OBJECT_FLOWER_ARRANGEMENT_SAD_MOURNING: 'CommonBuffId' = 187610 - OBJECT_FOOSBALL_CHEERED: 'CommonBuffId' = 122868 - OBJECT_FOOSBALL_EMBARRASSED_CHALLENGE: 'CommonBuffId' = 127115 - OBJECT_FOOSBALL_HECKLED: 'CommonBuffId' = 122869 - OBJECT_FOOSBALL_LEFT_CHALLENGE: 'CommonBuffId' = 130262 - OBJECT_FOOSBALL_LOSE: 'CommonBuffId' = 124476 - OBJECT_FOOSBALL_TABLE_CHALLENGED: 'CommonBuffId' = 124814 - OBJECT_FOOSBALL_TABLE_CLUB_CHALLENGE: 'CommonBuffId' = 126310 - OBJECT_FOOSBALL_TABLE_PLAY_SIDE_A: 'CommonBuffId' = 123137 - OBJECT_FOOSBALL_TABLE_PLAY_SIDE_B: 'CommonBuffId' = 123138 - OBJECT_FOOSBALL_WIN: 'CommonBuffId' = 124475 - OBJECT_FRONT_DESK_BADGED_IN: 'CommonBuffId' = 112447 - OBJECT_FRONT_DESK_BE_CHECKED_IN: 'CommonBuffId' = 111910 - OBJECT_FRONT_DESK_STAFFED: 'CommonBuffId' = 110676 - OBJECT_FRUITCAKE_HATES: 'CommonBuffId' = 119331 - OBJECT_FRUITCAKE_LIKES: 'CommonBuffId' = 119335 - OBJECT_FRUIT_PUNCH_FOUNTAIN_CARAMEL: 'CommonBuffId' = 116947 - OBJECT_FRUIT_PUNCH_FOUNTAIN_CHEESE: 'CommonBuffId' = 116948 - OBJECT_FRUIT_PUNCH_FOUNTAIN_CIDER: 'CommonBuffId' = 116949 - OBJECT_FRUIT_PUNCH_FOUNTAIN_FUTURISTIC: 'CommonBuffId' = 116950 - OBJECT_FRUIT_PUNCH_FOUNTAIN_HIDDEN_DIP_FINGER_TIME_OUT: 'CommonBuffId' = 116976 - OBJECT_FRUIT_PUNCH_FOUNTAIN_HIDDEN_OBJECT_CHECK: 'CommonBuffId' = 117187 - OBJECT_FRUIT_PUNCH_FOUNTAIN_HIDDEN_SABOTAGED_FOUNTAIN: 'CommonBuffId' = 116964 - OBJECT_FRUIT_PUNCH_FOUNTAIN_IMPROVED_DRINK: 'CommonBuffId' = 116945 - OBJECT_FRUIT_PUNCH_FOUNTAIN_IMPROVED_FOOD_BALL: 'CommonBuffId' = 116953 - OBJECT_FRUIT_PUNCH_FOUNTAIN_PARTY_BONUS: 'CommonBuffId' = 117185 - OBJECT_FRUIT_PUNCH_FOUNTAIN_PARTY_EXTENDER: 'CommonBuffId' = 116951 - OBJECT_FRUIT_PUNCH_FOUNTAIN_SABOTAGE_PLAYFUL: 'CommonBuffId' = 116946 - OBJECT_FRUIT_PUNCH_FOUNTAIN_SABOTAGE_UNCOMFORTABLE: 'CommonBuffId' = 116952 - OBJECT_GARDENING_PLANT_CHILD_HELPED_CARE: 'CommonBuffId' = 260097 - OBJECT_GARDENING_PLANT_CHILD_TALK_TO_PLANT: 'CommonBuffId' = 260101 - OBJECT_GUITAR_PRACTICE: 'CommonBuffId' = 39949 - OBJECT_GUITAR_REAPER_BEING_PLAYED: 'CommonBuffId' = 150078 - OBJECT_GUITAR_RIGHTEOUS_RIFFS: 'CommonBuffId' = 36973 - OBJECT_GUITAR_ROCKING_RIFFS: 'CommonBuffId' = 34548 - OBJECT_HEART_BED_PLAYFUL: 'CommonBuffId' = 368804 - OBJECT_HEART_BED_TENSE: 'CommonBuffId' = 368806 - OBJECT_HEART_BED_UNCOMFORTABLE: 'CommonBuffId' = 368805 - OBJECT_HEAT_LAMP_HEATED_SURROUNDINGS: 'CommonBuffId' = 131770 - OBJECT_HEAT_LAMP_WARMED_BY_HEAT_LAMP: 'CommonBuffId' = 131781 - OBJECT_HERBALIST_POTION_CLEAR_MIND: 'CommonBuffId' = 108791 - OBJECT_HERBALIST_POTION_CLEAR_MIND_MASTERWORK: 'CommonBuffId' = 111692 - OBJECT_HERBALIST_POTION_CLEAR_MIND_NORMAL: 'CommonBuffId' = 111691 - OBJECT_HERBALIST_POTION_CLEAR_MIND_OUTSTANDING: 'CommonBuffId' = 111689 - OBJECT_HERBALIST_POTION_DEODORANT: 'CommonBuffId' = 104584 - OBJECT_HERBALIST_POTION_DEODORANT_MASTERWORK: 'CommonBuffId' = 111695 - OBJECT_HERBALIST_POTION_DEODORANT_OUTSTANDING: 'CommonBuffId' = 111694 - OBJECT_HERBALIST_POTION_DISGUSTING_APPLICATION: 'CommonBuffId' = 110751 - OBJECT_HERBALIST_POTION_DISGUSTING_LIQUID: 'CommonBuffId' = 104651 - OBJECT_HERBALIST_POTION_ENERGIZER: 'CommonBuffId' = 104585 - OBJECT_HERBALIST_POTION_ENERGIZER_MASTERWORK: 'CommonBuffId' = 111698 - OBJECT_HERBALIST_POTION_ENERGIZER_OUTSTANDING: 'CommonBuffId' = 111697 - OBJECT_HERBALIST_POTION_FERTILITY_POTION: 'CommonBuffId' = 104587 - OBJECT_HERBALIST_POTION_FERTILITY_POTION_MASTERWORK: 'CommonBuffId' = 105210 - OBJECT_HERBALIST_POTION_FERTILITY_POTION_NORMAL: 'CommonBuffId' = 105208 - OBJECT_HERBALIST_POTION_FERTILITY_POTION_OUTSTANDING: 'CommonBuffId' = 105209 - OBJECT_HERBALIST_POTION_INSECT_REPELLENT: 'CommonBuffId' = 104543 - OBJECT_HERBALIST_POTION_SKIN_BALM_HIDDEN: 'CommonBuffId' = 104570 - OBJECT_HERBALIST_POTION_TUMMY_FIXER: 'CommonBuffId' = 104586 - OBJECT_HIDDEN_PINGPONG_JUICE_PONG_PLAYING_AGAINST_RIVAL: 'CommonBuffId' = 230422 - OBJECT_HIDDEN_PINGPONG_WINNER: 'CommonBuffId' = 224875 - OBJECT_HOLDING_CELL_BEING_PUT_IN_CELL: 'CommonBuffId' = 112619 - OBJECT_HOLDING_CELL_FINGERPRINT_NEXT: 'CommonBuffId' = 112607 - OBJECT_HOLDING_CELL_INTERROGATE_NEXT: 'CommonBuffId' = 112609 - OBJECT_HOLDING_CELL_IN_CELL: 'CommonBuffId' = 104873 - OBJECT_HOLDING_CELL_MUGSHOT_NEXT: 'CommonBuffId' = 112608 - OBJECT_HOLDING_CELL_OUT_OF_CELL_TIMER: 'CommonBuffId' = 106109 - OBJECT_HOLDING_CELL_PUT_ME_BACK_IN_CELL: 'CommonBuffId' = 106110 - OBJECT_HOLDING_CELL_SEARCH_NEXT: 'CommonBuffId' = 112610 - OBJECT_HOLIDAY_CANDLE_FULLY_LIT: 'CommonBuffId' = 110530 - OBJECT_HOLIDAY_CANDLE_LIT: 'CommonBuffId' = 110493 - OBJECT_HOMEWORK_COMPLETE: 'CommonBuffId' = 31589 - OBJECT_HOMEWORK_HAS_ANSWER_KEY: 'CommonBuffId' = 33803 - OBJECT_HORSE_BED_HAPPY: 'CommonBuffId' = 329134 - OBJECT_HORSE_BED_UNCOMFORTABLE: 'CommonBuffId' = 329135 - OBJECT_HORSE_OBSTACLES_CHEATS_FAILURE: 'CommonBuffId' = 332059 - OBJECT_HORSE_OBSTACLES_CHEATS_SUCCESS: 'CommonBuffId' = 332058 - OBJECT_HORSE_OBSTACLES_IS_TRAINING: 'CommonBuffId' = 348970 - OBJECT_HORSE_OBSTACLES_SKILL_GAIN_HORSE_LARGE: 'CommonBuffId' = 333981 - OBJECT_HORSE_OBSTACLES_SKILL_GAIN_HORSE_SMALL: 'CommonBuffId' = 333387 - OBJECT_HORSE_OBSTACLES_SKILL_GAIN_HORSE_STANDARD: 'CommonBuffId' = 333980 - OBJECT_HORSE_OBSTACLES_SKILL_GAIN_SIM_LARGE: 'CommonBuffId' = 333985 - OBJECT_HORSE_OBSTACLES_SKILL_GAIN_SIM_SMALL: 'CommonBuffId' = 333982 - OBJECT_HORSE_OBSTACLES_SKILL_GAIN_SIM_STANDARD: 'CommonBuffId' = 333984 - OBJECT_HORSE_OBSTACLES_STOP_TRAINING: 'CommonBuffId' = 338877 - OBJECT_HORSE_SHOES_EMBARRASSING_SHOWING: 'CommonBuffId' = 109922 - OBJECT_HORSE_SHOES_LOSE: 'CommonBuffId' = 105891 - OBJECT_HORSE_SHOES_PLAYING: 'CommonBuffId' = 109968 - OBJECT_HORSE_SHOES_PRACTICE: 'CommonBuffId' = 106087 - OBJECT_HORSE_SHOES_SORE_LOSER: 'CommonBuffId' = 105089 - OBJECT_HORSE_SHOES_UNSOPHISTICATED: 'CommonBuffId' = 109921 - OBJECT_HORSE_SHOES_WIN: 'CommonBuffId' = 105086 - OBJECT_HORSE_TRAINING_SKILL_GAIN_TEMPERAMENT_SMALL: 'CommonBuffId' = 334179 - OBJECT_HORSE_TRAINING_SKILL_GAIN_TEMPERAMENT_STANDARD: 'CommonBuffId' = 334180 - OBJECT_HOT_SPRINGS_1_WARM_FEELINGS: 'CommonBuffId' = 248902 - OBJECT_HOT_SPRINGS_2_LOST_IN_WARMTH: 'CommonBuffId' = 248903 - OBJECT_HOT_SPRINGS_3_COMPLETE_RELAXATION: 'CommonBuffId' = 248904 - OBJECT_HOT_SPRINGS_BUFF_TRACKER: 'CommonBuffId' = 254617 - OBJECT_HOT_SPRINGS_HIDDEN_CLEAN: 'CommonBuffId' = 249179 - OBJECT_HOT_SPRINGS_ON_ENTER_DIRTY_HOT_SPRINGS: 'CommonBuffId' = 249459 - OBJECT_HOT_SPRINGS_ON_ENTER_GOOD_SIM: 'CommonBuffId' = 249295 - OBJECT_HOT_SPRINGS_ON_ENTER_SEEN_UNCLEAN: 'CommonBuffId' = 249296 - OBJECT_HOT_SPRINGS_SOAKED_TOO_LONG: 'CommonBuffId' = 248905 - OBJECT_HOT_SPRINGS_TIME_INSIDE_TRACKER: 'CommonBuffId' = 248956 - OBJECT_HOT_TUB_ANNOYED_BY_SPLASHER: 'CommonBuffId' = 119414 - OBJECT_HOT_TUB_AROMATHERAPY_JASMINE: 'CommonBuffId' = 118704 - OBJECT_HOT_TUB_AROMATHERAPY_LEMON: 'CommonBuffId' = 118703 - OBJECT_HOT_TUB_AROMATHERAPY_PEPPERMINT: 'CommonBuffId' = 118706 - OBJECT_HOT_TUB_AROMATHERAPY_SAGE: 'CommonBuffId' = 118705 - OBJECT_HOT_TUB_BORED_OF_SPLASHING: 'CommonBuffId' = 120477 - OBJECT_HOT_TUB_BROKEN: 'CommonBuffId' = 120649 - OBJECT_HOT_TUB_IN_HOT_TUB: 'CommonBuffId' = 120612 - OBJECT_HOT_TUB_MESSED_AROUND_HOT_TUB: 'CommonBuffId' = 119138 - OBJECT_HOT_TUB_MISTAKEN_SPLASH: 'CommonBuffId' = 119139 - OBJECT_HOT_TUB_NUDE: 'CommonBuffId' = 120584 - OBJECT_HOT_TUB_SPLASHED_HOT_WATER: 'CommonBuffId' = 119140 - OBJECT_HOT_TUB_SPLASHING: 'CommonBuffId' = 119141 - OBJECT_HOT_TUB_THIOACETONE_USED_HIDDEN: 'CommonBuffId' = 119144 - OBJECT_HOT_TUB_UNIMAGINABLE_ODOR: 'CommonBuffId' = 119142 - OBJECT_HOT_TUB_WOOHOO_IN_HOT_TUB: 'CommonBuffId' = 119143 - OBJECT_ICE_CREAM_CHILLED_TO_THE_BONE: 'CommonBuffId' = 121033 - OBJECT_ICE_CREAM_CHILLING_TOUCH_USED: 'CommonBuffId' = 121441 - OBJECT_ICE_CREAM_DRAGONS_FURY_CONFIDENT: 'CommonBuffId' = 121025 - OBJECT_ICE_CREAM_DRAGONS_FURY_UNCOMFORTABLE: 'CommonBuffId' = 121026 - OBJECT_ICE_CREAM_GREEN_LIFE: 'CommonBuffId' = 121031 - OBJECT_ICE_CREAM_HAUNTED: 'CommonBuffId' = 121040 - OBJECT_ICE_CREAM_HAUNTED_BROADCASTER: 'CommonBuffId' = 121041 - OBJECT_ICE_CREAM_HAUNTINGLY_TASTY_INSPIRED: 'CommonBuffId' = 121038 - OBJECT_ICE_CREAM_HAUNTINGLY_TASTY_SAD: 'CommonBuffId' = 121039 - OBJECT_ICE_CREAM_ICE_TREAT: 'CommonBuffId' = 121032 - OBJECT_ICE_CREAM_JUST_NUTS: 'CommonBuffId' = 121609 - OBJECT_ICE_CREAM_MIND_ASKEW_ANGRY: 'CommonBuffId' = 121043 - OBJECT_ICE_CREAM_MIND_ASKEW_BORED: 'CommonBuffId' = 121047 - OBJECT_ICE_CREAM_MIND_ASKEW_CONFIDENT: 'CommonBuffId' = 121045 - OBJECT_ICE_CREAM_MIND_ASKEW_DAZED: 'CommonBuffId' = 121054 - OBJECT_ICE_CREAM_MIND_ASKEW_EMBARRASSED: 'CommonBuffId' = 121048 - OBJECT_ICE_CREAM_MIND_ASKEW_ENERGIZED: 'CommonBuffId' = 121044 - OBJECT_ICE_CREAM_MIND_ASKEW_FLIRTY: 'CommonBuffId' = 121049 - OBJECT_ICE_CREAM_MIND_ASKEW_FOCUSED: 'CommonBuffId' = 121055 - OBJECT_ICE_CREAM_MIND_ASKEW_HAPPY: 'CommonBuffId' = 121050 - OBJECT_ICE_CREAM_MIND_ASKEW_HIDDEN: 'CommonBuffId' = 121028 - OBJECT_ICE_CREAM_MIND_ASKEW_INSPIRED: 'CommonBuffId' = 121056 - OBJECT_ICE_CREAM_MIND_ASKEW_PLAYFUL: 'CommonBuffId' = 121046 - OBJECT_ICE_CREAM_MIND_ASKEW_SAD: 'CommonBuffId' = 121053 - OBJECT_ICE_CREAM_MIND_ASKEW_STRESSED: 'CommonBuffId' = 121051 - OBJECT_ICE_CREAM_MIND_ASKEW_UNCOMFORTABLE: 'CommonBuffId' = 121052 - OBJECT_ICE_CREAM_PERFECT_TOPPINGS: 'CommonBuffId' = 121596 - OBJECT_ICE_CREAM_PURE_PERFECTION: 'CommonBuffId' = 121035 - OBJECT_ICE_CREAM_RUB_TUMMY: 'CommonBuffId' = 121425 - OBJECT_ICE_CREAM_SUGARY_GOODNESS: 'CommonBuffId' = 121036 - OBJECT_ICE_CREAM_TASTE_OF_DIET: 'CommonBuffId' = 121037 - OBJECT_ICE_CREAM_TASTE_OF_ROSES_ADULT: 'CommonBuffId' = 121030 - OBJECT_ICE_CREAM_TASTE_OF_ROSES_CHILD: 'CommonBuffId' = 121065 - OBJECT_INCENSE: 'CommonBuffId' = 118851 - OBJECT_INSECT_FARM_FEED_COMPOST: 'CommonBuffId' = 239042 - OBJECT_INSECT_FARM_WHY_BUGS: 'CommonBuffId' = 238847 - OBJECT_INTERACTIVE_BUSH_EWW: 'CommonBuffId' = 124869 - OBJECT_INTERACTIVE_BUSH_UNCOMFORTABLE_NAP: 'CommonBuffId' = 126307 - OBJECT_INVENTION_CONSTRUCTOR_INSPIRED: 'CommonBuffId' = 110195 - OBJECT_IN_WARMING_OBJECT: 'CommonBuffId' = 187519 - OBJECT_IS_PLAYING: 'CommonBuffId' = 151823 - OBJECT_IS_PLAYING_01: 'CommonBuffId' = 157657 - OBJECT_IS_PLAYING_02: 'CommonBuffId' = 157016 - OBJECT_IS_PLAYING_03: 'CommonBuffId' = 157017 - OBJECT_IS_PLAYING_04: 'CommonBuffId' = 157018 - OBJECT_IS_PLAYING_05: 'CommonBuffId' = 157019 - OBJECT_IS_PLAYING_NON_TODDLER: 'CommonBuffId' = 156821 - OBJECT_IS_PLAYING_SAND_ACTIVITIES_1: 'CommonBuffId' = 214541 - OBJECT_IS_PLAYING_SAND_ACTIVITIES_2: 'CommonBuffId' = 214543 - OBJECT_IS_PLAYING_SAND_ACTIVITIES_3: 'CommonBuffId' = 214544 - OBJECT_IS_PLAYING_SAND_ACTIVITIES_4: 'CommonBuffId' = 214545 - OBJECT_IS_PLAYING_SAND_ACTIVITIES_5: 'CommonBuffId' = 214546 - OBJECT_IS_SLEEPING_TODDLER: 'CommonBuffId' = 155008 - OBJECT_JUMP_STAND_DIVE_DISASTER: 'CommonBuffId' = 128655 - OBJECT_JUMP_STAND_DIVE_MASTER: 'CommonBuffId' = 128654 - OBJECT_JUMP_STAND_FREE_FLYING: 'CommonBuffId' = 128658 - OBJECT_JUMP_STAND_SPLASHED: 'CommonBuffId' = 128657 - OBJECT_JUMP_STAND_SWIMSUIT_MALFUNCTION: 'CommonBuffId' = 128656 - OBJECT_JUNGLE_GYM_BOAT_PLAYFUL: 'CommonBuffId' = 8596 - OBJECT_JUNGLE_GYM_ROCKET_SHIP_PLAYFUL: 'CommonBuffId' = 8615 - OBJECT_KIDS_TENT_IM_ANGRY_TODDLER: 'CommonBuffId' = 268551 - OBJECT_KIDS_TENT_IM_A_MONSTER: 'CommonBuffId' = 257391 - OBJECT_KIDS_TENT_IM_SCARED: 'CommonBuffId' = 257456 - OBJECT_KIDS_TENT_IS_PLAYING: 'CommonBuffId' = 268371 - OBJECT_KIDS_TENT_IS_PLAYING_1: 'CommonBuffId' = 267803 - OBJECT_KIDS_TENT_IS_PLAYING_2: 'CommonBuffId' = 267804 - OBJECT_KIDS_TENT_IS_PLAYING_3: 'CommonBuffId' = 267805 - OBJECT_KIDS_TENT_IS_PLAYING_4: 'CommonBuffId' = 267806 - OBJECT_KIDS_TENT_IS_PLAYING_5: 'CommonBuffId' = 267807 - OBJECT_KIDS_TENT_MAKE_BELIEVE: 'CommonBuffId' = 257390 - OBJECT_KIDS_TENT_SHABBY_TENT: 'CommonBuffId' = 257392 - OBJECT_LASER_LIGHT_SHOW: 'CommonBuffId' = 35451 - OBJECT_LASER_POINTER_PLAYFUL: 'CommonBuffId' = 158125 - OBJECT_LEAF_PILE_COZY_FIRE: 'CommonBuffId' = 182976 - OBJECT_LEAF_PILE_GROSS_PLAY_IN: 'CommonBuffId' = 186342 - OBJECT_LEAF_PILE_GROSS_WOOHOO: 'CommonBuffId' = 190668 - OBJECT_LEAF_PILE_RAKE_DISCIPLINE: 'CommonBuffId' = 190872 - OBJECT_MAILBOX_WALL_BROWSING: 'CommonBuffId' = 133185 - OBJECT_MARKET_STALLS_CAS_CHANGE_BLOSSOM_SHIRT: 'CommonBuffId' = 139598 - OBJECT_MARKET_STALLS_CAS_CHANGE_FOOD_SHIRT: 'CommonBuffId' = 132817 - OBJECT_MARKET_STALLS_CAS_CHANGE_LAMP_SHIRT: 'CommonBuffId' = 139596 - OBJECT_MARKET_STALLS_CAS_CHANGE_LOGIC_SHIRT: 'CommonBuffId' = 139597 - OBJECT_MARKET_STALLS_CURIO_SHOP_QUESTION_COOLDOWN: 'CommonBuffId' = 203216 - OBJECT_MARKET_STALLS_HAGGLE: 'CommonBuffId' = 132805 - OBJECT_MARKET_STALLS_HAGGLE_BATUU: 'CommonBuffId' = 250410 - OBJECT_MARKET_STALLS_HAGGLE_FAIL: 'CommonBuffId' = 132806 - OBJECT_MARKET_STALLS_IN_THE_KNOW: 'CommonBuffId' = 148137 - OBJECT_MARKET_STALLS_SHOW_OFF_PREVENTION: 'CommonBuffId' = 141666 - OBJECT_MASSAGE_CHAIR_ACHING_ARCHES: 'CommonBuffId' = 119782 - OBJECT_MASSAGE_CHAIR_FABULOUS_FEET: 'CommonBuffId' = 119783 - OBJECT_MASSAGE_CHAIR_FIRST_HAND_COMPLETE: 'CommonBuffId' = 119583 - OBJECT_MASSAGE_CHAIR_GETTING_MANICURE: 'CommonBuffId' = 273062 - OBJECT_MASSAGE_CHAIR_HAND_TABULOUS_MASSAGE: 'CommonBuffId' = 119947 - OBJECT_MASSAGE_CHAIR_HAPPY_HANDS: 'CommonBuffId' = 119780 - OBJECT_MASSAGE_CHAIR_HURT_HANDS: 'CommonBuffId' = 119781 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ALMOND_BEIGE: 'CommonBuffId' = 271702 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ALMOND_BLACK: 'CommonBuffId' = 271703 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ALMOND_BLUE: 'CommonBuffId' = 271704 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ALMOND_BLUE_LT: 'CommonBuffId' = 271705 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ALMOND_CREAM: 'CommonBuffId' = 271706 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ALMOND_GREEN: 'CommonBuffId' = 271707 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ALMOND_LILAC: 'CommonBuffId' = 271708 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ALMOND_PINK: 'CommonBuffId' = 271709 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ALMOND_PURPLE: 'CommonBuffId' = 271710 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ALMOND_RED: 'CommonBuffId' = 271711 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ALMOND_SILVER: 'CommonBuffId' = 271712 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ALMOND_WHITE: 'CommonBuffId' = 271713 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ALMOND_YELLOW: 'CommonBuffId' = 271714 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_ART_1: 'CommonBuffId' = 271779 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_ART_2: 'CommonBuffId' = 271780 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_ART_3: 'CommonBuffId' = 271781 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_ART_4: 'CommonBuffId' = 271782 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_ART_5: 'CommonBuffId' = 271783 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_ART_6: 'CommonBuffId' = 271778 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_BEIGE: 'CommonBuffId' = 271255 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_BLACK: 'CommonBuffId' = 271256 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_BLUE: 'CommonBuffId' = 271257 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_BLUE_LT: 'CommonBuffId' = 271355 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_CREAM: 'CommonBuffId' = 271991 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_GREEN: 'CommonBuffId' = 271363 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_LILAC: 'CommonBuffId' = 271370 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_MATTE_BEIGE: 'CommonBuffId' = 271745 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_MATTE_BLACK: 'CommonBuffId' = 271746 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_MATTE_BLUE: 'CommonBuffId' = 271747 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_MATTE_BLUE_LT: 'CommonBuffId' = 271748 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_MATTE_CREAM: 'CommonBuffId' = 271992 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_MATTE_GREEN: 'CommonBuffId' = 271749 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_MATTE_LILAC: 'CommonBuffId' = 271750 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_MATTE_PINK: 'CommonBuffId' = 271751 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_MATTE_PURPLE: 'CommonBuffId' = 271752 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_MATTE_RED: 'CommonBuffId' = 271753 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_MATTE_SILVER: 'CommonBuffId' = 271754 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_MATTE_WHITE: 'CommonBuffId' = 271755 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_MATTE_YELLOW: 'CommonBuffId' = 271756 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_PINK: 'CommonBuffId' = 271376 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_PURPLE: 'CommonBuffId' = 271382 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_RED: 'CommonBuffId' = 271388 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_SILVER: 'CommonBuffId' = 271394 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_SWIRL_BLACK: 'CommonBuffId' = 271787 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_SWIRL_BLUE: 'CommonBuffId' = 271788 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_SWIRL_CREAM: 'CommonBuffId' = 271789 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_SWIRL_PINK: 'CommonBuffId' = 271790 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_SWIRL_PURPLE: 'CommonBuffId' = 271791 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_SWIRL_SPACE: 'CommonBuffId' = 272825 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_SWIRL_TEAL: 'CommonBuffId' = 272824 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_SWIRL_WHITE: 'CommonBuffId' = 271792 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_WHITE: 'CommonBuffId' = 271400 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COFFIN_YELLOW: 'CommonBuffId' = 271406 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COMMUNITY_BLACK: 'CommonBuffId' = 272691 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COMMUNITY_BLUE: 'CommonBuffId' = 272142 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COMMUNITY_FUCHSIA: 'CommonBuffId' = 272692 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COMMUNITY_GREEN: 'CommonBuffId' = 272693 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COMMUNITY_MINT: 'CommonBuffId' = 272694 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COMMUNITY_ORANGE: 'CommonBuffId' = 272695 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COMMUNITY_PINK: 'CommonBuffId' = 272696 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COMMUNITY_PLUM: 'CommonBuffId' = 272697 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COMMUNITY_PURPLE: 'CommonBuffId' = 272698 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COMMUNITY_RED: 'CommonBuffId' = 272699 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_COMMUNITY_YELLOW: 'CommonBuffId' = 272700 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_BEIGE: 'CommonBuffId' = 271251 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_BLACK: 'CommonBuffId' = 271252 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_BLUE: 'CommonBuffId' = 271253 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_BLUE_LT: 'CommonBuffId' = 271356 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_ASEX: 'CommonBuffId' = 271886 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_BI: 'CommonBuffId' = 271887 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_BLACKPINK: 'CommonBuffId' = 272810 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_BLUE: 'CommonBuffId' = 271888 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_BLUE_YELLOW: 'CommonBuffId' = 272811 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_GRAYS: 'CommonBuffId' = 271889 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_LEATHER: 'CommonBuffId' = 271890 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_NON: 'CommonBuffId' = 271891 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_ORANGE: 'CommonBuffId' = 271892 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_PAN: 'CommonBuffId' = 271893 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_PASTEL: 'CommonBuffId' = 271894 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_PINKS: 'CommonBuffId' = 271895 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_PINK_WHITE: 'CommonBuffId' = 272812 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_PRIDE: 'CommonBuffId' = 271896 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_PURPLE_MUAVE: 'CommonBuffId' = 272813 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_SHORT_ASEX: 'CommonBuffId' = 271914 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_SHORT_BI: 'CommonBuffId' = 271915 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_SHORT_BLACK_PINK: 'CommonBuffId' = 272814 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_SHORT_BLUE: 'CommonBuffId' = 271916 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_SHORT_BLUE_YELLOW: 'CommonBuffId' = 272815 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_SHORT_GRAYS: 'CommonBuffId' = 271917 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_SHORT_LEATHER: 'CommonBuffId' = 271918 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_SHORT_NON: 'CommonBuffId' = 271919 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_SHORT_ORANGE: 'CommonBuffId' = 271920 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_SHORT_PAN: 'CommonBuffId' = 271921 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_SHORT_PASTEL: 'CommonBuffId' = 271922 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_SHORT_PINKS: 'CommonBuffId' = 271923 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_SHORT_PINK_WHITE: 'CommonBuffId' = 272816 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_SHORT_PRIDE: 'CommonBuffId' = 271924 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_SHORT_PURPLE_MUAVE: 'CommonBuffId' = 272817 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_SHORT_TRANS: 'CommonBuffId' = 271925 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_CONTRAST_TRANS: 'CommonBuffId' = 271897 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_GREEN: 'CommonBuffId' = 271364 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_LILAC: 'CommonBuffId' = 271371 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_PINK: 'CommonBuffId' = 271377 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_PURPLE: 'CommonBuffId' = 271383 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_RED: 'CommonBuffId' = 271389 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_SHORT_BEIGE: 'CommonBuffId' = 271940 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_SHORT_BLACK: 'CommonBuffId' = 271942 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_SHORT_BLUE: 'CommonBuffId' = 271941 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_SHORT_BLUE_LT: 'CommonBuffId' = 271943 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_SHORT_BUFFED_PINK: 'CommonBuffId' = 271807 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_SHORT_BUFFED_WHITE: 'CommonBuffId' = 271811 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_SHORT_CHOCOLATE: 'CommonBuffId' = 272818 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_SHORT_GREEN: 'CommonBuffId' = 271944 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_SHORT_LILAC: 'CommonBuffId' = 271945 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_SHORT_MUAVE: 'CommonBuffId' = 272819 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_SHORT_PINK: 'CommonBuffId' = 271946 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_SHORT_PINK_DUSTY: 'CommonBuffId' = 272820 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_SHORT_PURPLE: 'CommonBuffId' = 271947 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_SHORT_RED: 'CommonBuffId' = 271948 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_SHORT_SILVER: 'CommonBuffId' = 271949 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_SHORT_WHITE: 'CommonBuffId' = 271950 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_SHORT_YELLOW: 'CommonBuffId' = 271997 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_SILVER: 'CommonBuffId' = 271395 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_WHITE: 'CommonBuffId' = 271401 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_ROUND_YELLOW: 'CommonBuffId' = 271407 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_GRADIENT_BEIGE: 'CommonBuffId' = 271828 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_GRADIENT_BLACK: 'CommonBuffId' = 271829 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_GRADIENT_BLUE: 'CommonBuffId' = 271830 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_GRADIENT_BLUE_LT: 'CommonBuffId' = 271831 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_GRADIENT_CREAM: 'CommonBuffId' = 272010 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_GRADIENT_GREEN: 'CommonBuffId' = 271832 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_GRADIENT_LILAC: 'CommonBuffId' = 271834 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_GRADIENT_PINK: 'CommonBuffId' = 271835 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_GRADIENT_PURPLE: 'CommonBuffId' = 271836 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_GRADIENT_RED: 'CommonBuffId' = 271837 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_GRADIENT_SILVER: 'CommonBuffId' = 271838 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_GRADIENT_WHITE: 'CommonBuffId' = 271839 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_GRADIENT_YELLOW: 'CommonBuffId' = 271840 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_SPLIT_BEIGE: 'CommonBuffId' = 271856 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_SPLIT_BLACK: 'CommonBuffId' = 271858 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_SPLIT_BLUE: 'CommonBuffId' = 271860 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_SPLIT_BLUE_LT: 'CommonBuffId' = 271863 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_SPLIT_CREAM: 'CommonBuffId' = 272012 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_SPLIT_GREEN: 'CommonBuffId' = 271864 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_SPLIT_LILAC: 'CommonBuffId' = 271866 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_SPLIT_PINK: 'CommonBuffId' = 271868 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_SPLIT_PURPLE: 'CommonBuffId' = 271870 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_SPLIT_RED: 'CommonBuffId' = 271873 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_SPLIT_SILVER: 'CommonBuffId' = 271876 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_SPLIT_WHITE: 'CommonBuffId' = 271878 - OBJECT_MASSAGE_CHAIR_MANICURE_NAIL_STILETTO_SPLIT_YELLOW: 'CommonBuffId' = 271879 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ALMOND_BEIGE: 'CommonBuffId' = 271716 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ALMOND_BLACK: 'CommonBuffId' = 271717 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ALMOND_BLUE: 'CommonBuffId' = 271718 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ALMOND_BLUE_LT: 'CommonBuffId' = 271719 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ALMOND_CREAM: 'CommonBuffId' = 271721 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ALMOND_GREEN: 'CommonBuffId' = 271722 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ALMOND_LILAC: 'CommonBuffId' = 271723 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ALMOND_PINK: 'CommonBuffId' = 271724 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ALMOND_PURPLE: 'CommonBuffId' = 271725 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ALMOND_RED: 'CommonBuffId' = 271726 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ALMOND_SILVER: 'CommonBuffId' = 271727 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ALMOND_WHITE: 'CommonBuffId' = 271728 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ALMOND_YELLOW: 'CommonBuffId' = 271729 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_ART_1: 'CommonBuffId' = 271772 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_ART_2: 'CommonBuffId' = 271773 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_ART_3: 'CommonBuffId' = 271774 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_ART_4: 'CommonBuffId' = 271775 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_ART_5: 'CommonBuffId' = 271776 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_ART_6: 'CommonBuffId' = 271771 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_BEIGE: 'CommonBuffId' = 271267 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_BLACK: 'CommonBuffId' = 271268 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_BLUE: 'CommonBuffId' = 271269 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_BLUE_LT: 'CommonBuffId' = 271360 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_CREAM: 'CommonBuffId' = 271993 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_GREEN: 'CommonBuffId' = 271367 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_LILAC: 'CommonBuffId' = 271373 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_MATTE_BEIGE: 'CommonBuffId' = 271758 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_MATTE_BLACK: 'CommonBuffId' = 271759 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_MATTE_BLUE: 'CommonBuffId' = 271760 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_MATTE_BLUE_LT: 'CommonBuffId' = 271761 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_MATTE_CREAM: 'CommonBuffId' = 271994 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_MATTE_GREEN: 'CommonBuffId' = 271762 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_MATTE_LILAC: 'CommonBuffId' = 271763 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_MATTE_PINK: 'CommonBuffId' = 271764 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_MATTE_PURPLE: 'CommonBuffId' = 271765 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_MATTE_RED: 'CommonBuffId' = 271766 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_MATTE_SILVER: 'CommonBuffId' = 271767 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_MATTE_WHITE: 'CommonBuffId' = 271768 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_MATTE_YELLOW: 'CommonBuffId' = 271769 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_PINK: 'CommonBuffId' = 271379 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_PURPLE: 'CommonBuffId' = 271385 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_RED: 'CommonBuffId' = 271391 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_SILVER: 'CommonBuffId' = 271397 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_SWIRL_BLACK: 'CommonBuffId' = 271793 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_SWIRL_BLUE: 'CommonBuffId' = 271794 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_SWIRL_CREAM: 'CommonBuffId' = 271795 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_SWIRL_PINK: 'CommonBuffId' = 271796 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_SWIRL_PURPLE: 'CommonBuffId' = 271797 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_SWIRL_SPACE: 'CommonBuffId' = 272826 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_SWIRL_TEAL: 'CommonBuffId' = 272827 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_SWIRL_WHITE: 'CommonBuffId' = 271798 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_WHITE: 'CommonBuffId' = 271403 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COFFIN_YELLOW: 'CommonBuffId' = 271409 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COMMUNITY_BLACK: 'CommonBuffId' = 272701 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COMMUNITY_BLUE: 'CommonBuffId' = 272140 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COMMUNITY_FUCHSIA: 'CommonBuffId' = 272702 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COMMUNITY_GREEN: 'CommonBuffId' = 272703 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COMMUNITY_MINT: 'CommonBuffId' = 272704 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COMMUNITY_ORANGE: 'CommonBuffId' = 272705 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COMMUNITY_PINK: 'CommonBuffId' = 272706 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COMMUNITY_PLUM: 'CommonBuffId' = 272707 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COMMUNITY_PURPLE: 'CommonBuffId' = 272708 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COMMUNITY_RED: 'CommonBuffId' = 272709 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_COMMUNITY_YELLOW: 'CommonBuffId' = 272710 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_BEIGE: 'CommonBuffId' = 271270 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_BLACK: 'CommonBuffId' = 271271 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_BLUE: 'CommonBuffId' = 271272 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_BLUE_LT: 'CommonBuffId' = 271361 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_ASEX: 'CommonBuffId' = 271898 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_BI: 'CommonBuffId' = 271899 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_BLACKPINK: 'CommonBuffId' = 272803 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_BLUE: 'CommonBuffId' = 271900 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_BLUE_YELLOW: 'CommonBuffId' = 272802 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_GRAYS: 'CommonBuffId' = 271901 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_LEATHER: 'CommonBuffId' = 271902 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_NON: 'CommonBuffId' = 271903 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_ORANGE: 'CommonBuffId' = 271904 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_PAN: 'CommonBuffId' = 271905 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_PASTEL: 'CommonBuffId' = 271906 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_PINKS: 'CommonBuffId' = 271907 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_PINK_WHITE: 'CommonBuffId' = 272804 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_PRIDE: 'CommonBuffId' = 271908 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_PURPLE_MUAVE: 'CommonBuffId' = 272805 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_SHORT_ASEX: 'CommonBuffId' = 271926 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_SHORT_BI: 'CommonBuffId' = 271927 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_SHORT_BLACKPINK: 'CommonBuffId' = 272806 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_SHORT_BLUE: 'CommonBuffId' = 271928 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_SHORT_BLUE_YELLOW: 'CommonBuffId' = 272807 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_SHORT_GRAYS: 'CommonBuffId' = 271929 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_SHORT_LEATHER: 'CommonBuffId' = 271930 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_SHORT_NON: 'CommonBuffId' = 271931 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_SHORT_ORANGE: 'CommonBuffId' = 271932 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_SHORT_PAN: 'CommonBuffId' = 271933 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_SHORT_PASTEL: 'CommonBuffId' = 271934 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_SHORT_PINKS: 'CommonBuffId' = 271935 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_SHORT_PINK_WHITE: 'CommonBuffId' = 272808 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_SHORT_PRIDE: 'CommonBuffId' = 271936 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_SHORT_PURPLE_MUAVE: 'CommonBuffId' = 272809 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_SHORT_TRANS: 'CommonBuffId' = 271937 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_CONTRAST_TRANS: 'CommonBuffId' = 271909 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_GREEN: 'CommonBuffId' = 271368 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_LILAC: 'CommonBuffId' = 271374 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_PINK: 'CommonBuffId' = 271380 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_PURPLE: 'CommonBuffId' = 271386 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_RED: 'CommonBuffId' = 271392 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_SHORT_BEIGE: 'CommonBuffId' = 271998 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_SHORT_BLACK: 'CommonBuffId' = 271999 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_SHORT_BLUE: 'CommonBuffId' = 272000 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_SHORT_BLUE_LT: 'CommonBuffId' = 272001 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_SHORT_BUFFED_PINK: 'CommonBuffId' = 271819 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_SHORT_BUFFED_WHITE: 'CommonBuffId' = 271824 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_SHORT_CHOCOLATE: 'CommonBuffId' = 272822 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_SHORT_GREEN: 'CommonBuffId' = 272002 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_SHORT_LILAC: 'CommonBuffId' = 272003 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_SHORT_MUAVE: 'CommonBuffId' = 272821 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_SHORT_PINK: 'CommonBuffId' = 272004 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_SHORT_PINK_DUSTY: 'CommonBuffId' = 272823 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_SHORT_PURPLE: 'CommonBuffId' = 272005 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_SHORT_RED: 'CommonBuffId' = 272006 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_SHORT_SILVER: 'CommonBuffId' = 272007 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_SHORT_WHITE: 'CommonBuffId' = 272008 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_SHORT_YELLOW: 'CommonBuffId' = 272009 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_SILVER: 'CommonBuffId' = 271398 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_WHITE: 'CommonBuffId' = 271404 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_ROUND_YELLOW: 'CommonBuffId' = 271410 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_GRADIENT_BEIGE: 'CommonBuffId' = 271841 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_GRADIENT_BLACK: 'CommonBuffId' = 271842 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_GRADIENT_BLUE: 'CommonBuffId' = 271843 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_GRADIENT_BLUE_LT: 'CommonBuffId' = 271844 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_GRADIENT_CREAM: 'CommonBuffId' = 272011 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_GRADIENT_GREEN: 'CommonBuffId' = 271845 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_GRADIENT_LILAC: 'CommonBuffId' = 271846 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_GRADIENT_PINK: 'CommonBuffId' = 271847 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_GRADIENT_PURPLE: 'CommonBuffId' = 271848 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_GRADIENT_RED: 'CommonBuffId' = 271849 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_GRADIENT_SILVER: 'CommonBuffId' = 271851 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_GRADIENT_WHITE: 'CommonBuffId' = 271852 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_GRADIENT_YELLOW: 'CommonBuffId' = 271853 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_SPLIT_BEIGE: 'CommonBuffId' = 271857 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_SPLIT_BLACK: 'CommonBuffId' = 271859 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_SPLIT_BLUE: 'CommonBuffId' = 271861 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_SPLIT_BLUE_LT: 'CommonBuffId' = 271862 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_SPLIT_CREAM: 'CommonBuffId' = 272013 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_SPLIT_GREEN: 'CommonBuffId' = 271865 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_SPLIT_LILAC: 'CommonBuffId' = 271867 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_SPLIT_PINK: 'CommonBuffId' = 271869 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_SPLIT_PURPLE: 'CommonBuffId' = 271874 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_SPLIT_RED: 'CommonBuffId' = 271875 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_SPLIT_SILVER: 'CommonBuffId' = 271877 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_SPLIT_WHITE: 'CommonBuffId' = 271880 - OBJECT_MASSAGE_CHAIR_MANICURE_PICKER_STILETTO_SPLIT_YELLOW: 'CommonBuffId' = 271881 - OBJECT_MASSAGE_CHAIR_MANICURE_READY: 'CommonBuffId' = 273058 - OBJECT_MASSAGE_CHAIR_MANICURE_VFX_ALMOND: 'CommonBuffId' = 273045 - OBJECT_MASSAGE_CHAIR_MANICURE_VFX_COFFIN: 'CommonBuffId' = 273043 - OBJECT_MASSAGE_CHAIR_MANICURE_VFX_COMMUNITY: 'CommonBuffId' = 273046 - OBJECT_MASSAGE_CHAIR_MANICURE_VFX_ROUND: 'CommonBuffId' = 273047 - OBJECT_MASSAGE_CHAIR_MANICURE_VFX_STILETTO: 'CommonBuffId' = 273048 - OBJECT_MASSAGE_CHAIR_MANICURE_VISIBLE_BRO: 'CommonBuffId' = 271283 - OBJECT_MASSAGE_CHAIR_MANICURE_VISIBLE_CONFIDENT: 'CommonBuffId' = 271281 - OBJECT_MASSAGE_CHAIR_MANICURE_VISIBLE_FLIRTY: 'CommonBuffId' = 271280 - OBJECT_MASSAGE_CHAIR_MANICURE_VISIBLE_HAPPY: 'CommonBuffId' = 271279 - OBJECT_MASSAGE_CHAIR_MANICURE_VISIBLE_HATE_COLOR: 'CommonBuffId' = 272240 - OBJECT_MASSAGE_CHAIR_MANICURE_VISIBLE_LOVE_COLOR: 'CommonBuffId' = 272239 - OBJECT_MASSAGE_CHAIR_MANICURE_VISIBLE_PLAYFUL: 'CommonBuffId' = 271282 - OBJECT_MASSAGE_CHAIR_MANICURE_VISIBLE_WORN_AWAY: 'CommonBuffId' = 271647 - OBJECT_MASSAGE_CHAIR_MANIPEDI_BRO: 'CommonBuffId' = 271432 - OBJECT_MASSAGE_CHAIR_MANIPEDI_CONFIDENT: 'CommonBuffId' = 271433 - OBJECT_MASSAGE_CHAIR_MANIPEDI_FLIRTY: 'CommonBuffId' = 271434 - OBJECT_MASSAGE_CHAIR_MANIPEDI_HAPPY: 'CommonBuffId' = 271435 - OBJECT_MASSAGE_CHAIR_MANIPEDI_PLAYFUL: 'CommonBuffId' = 271436 - OBJECT_MASSAGE_CHAIR_OFFER_FOOT_MASSAGE: 'CommonBuffId' = 272210 - OBJECT_MASSAGE_CHAIR_OFFER_HAND_MASSAGE: 'CommonBuffId' = 272211 - OBJECT_MASSAGE_CHAIR_OFFER_MANICURE: 'CommonBuffId' = 272212 - OBJECT_MASSAGE_CHAIR_OFFER_PEDICURE: 'CommonBuffId' = 272213 - OBJECT_MASSAGE_CHAIR_ONE_DONE: 'CommonBuffId' = 271516 - OBJECT_MASSAGE_CHAIR_PAMPERED_PAWS: 'CommonBuffId' = 119946 - OBJECT_MASSAGE_CHAIR_PEDICURE_NAIL_BEIGE: 'CommonBuffId' = 271954 - OBJECT_MASSAGE_CHAIR_PEDICURE_NAIL_BLACK: 'CommonBuffId' = 271955 - OBJECT_MASSAGE_CHAIR_PEDICURE_NAIL_BLUE: 'CommonBuffId' = 271956 - OBJECT_MASSAGE_CHAIR_PEDICURE_NAIL_BLUE_LT: 'CommonBuffId' = 271957 - OBJECT_MASSAGE_CHAIR_PEDICURE_NAIL_CREAM: 'CommonBuffId' = 271975 - OBJECT_MASSAGE_CHAIR_PEDICURE_NAIL_GREEN: 'CommonBuffId' = 271958 - OBJECT_MASSAGE_CHAIR_PEDICURE_NAIL_LILAC: 'CommonBuffId' = 271959 - OBJECT_MASSAGE_CHAIR_PEDICURE_NAIL_PINK: 'CommonBuffId' = 271960 - OBJECT_MASSAGE_CHAIR_PEDICURE_NAIL_PURPLE: 'CommonBuffId' = 271961 - OBJECT_MASSAGE_CHAIR_PEDICURE_NAIL_RED: 'CommonBuffId' = 271621 - OBJECT_MASSAGE_CHAIR_PEDICURE_NAIL_SILVER: 'CommonBuffId' = 271962 - OBJECT_MASSAGE_CHAIR_PEDICURE_NAIL_WHITE: 'CommonBuffId' = 271963 - OBJECT_MASSAGE_CHAIR_PEDICURE_NAIL_YELLOW: 'CommonBuffId' = 271964 - OBJECT_MASSAGE_CHAIR_PEDICURE_PICKER_BEIGE: 'CommonBuffId' = 271965 - OBJECT_MASSAGE_CHAIR_PEDICURE_PICKER_BLACK: 'CommonBuffId' = 271977 - OBJECT_MASSAGE_CHAIR_PEDICURE_PICKER_BLUE: 'CommonBuffId' = 271966 - OBJECT_MASSAGE_CHAIR_PEDICURE_PICKER_BLUE_LT: 'CommonBuffId' = 271967 - OBJECT_MASSAGE_CHAIR_PEDICURE_PICKER_CREAM: 'CommonBuffId' = 271976 - OBJECT_MASSAGE_CHAIR_PEDICURE_PICKER_GREEN: 'CommonBuffId' = 271968 - OBJECT_MASSAGE_CHAIR_PEDICURE_PICKER_LILAC: 'CommonBuffId' = 271969 - OBJECT_MASSAGE_CHAIR_PEDICURE_PICKER_PINK: 'CommonBuffId' = 271970 - OBJECT_MASSAGE_CHAIR_PEDICURE_PICKER_PURPLE: 'CommonBuffId' = 271971 - OBJECT_MASSAGE_CHAIR_PEDICURE_PICKER_RED: 'CommonBuffId' = 271622 - OBJECT_MASSAGE_CHAIR_PEDICURE_PICKER_SILVER: 'CommonBuffId' = 271972 - OBJECT_MASSAGE_CHAIR_PEDICURE_PICKER_WHITE: 'CommonBuffId' = 271973 - OBJECT_MASSAGE_CHAIR_PEDICURE_PICKER_YELLOW: 'CommonBuffId' = 271974 - OBJECT_MASSAGE_CHAIR_PEDICURE_VISIBLE_BRO: 'CommonBuffId' = 271426 - OBJECT_MASSAGE_CHAIR_PEDICURE_VISIBLE_CONFIDENT: 'CommonBuffId' = 271427 - OBJECT_MASSAGE_CHAIR_PEDICURE_VISIBLE_FLIRTY: 'CommonBuffId' = 271428 - OBJECT_MASSAGE_CHAIR_PEDICURE_VISIBLE_HAPPY: 'CommonBuffId' = 271429 - OBJECT_MASSAGE_CHAIR_PEDICURE_VISIBLE_PLAYFUL: 'CommonBuffId' = 271430 - OBJECT_MASSAGE_CHAIR_PEDICURE_VISIBLE_WORN_AWAY: 'CommonBuffId' = 271648 - OBJECT_MASSAGE_CHAIR_REFRESHED_FLANGIES: 'CommonBuffId' = 119943 - OBJECT_MASSAGE_CHAIR_REMOVE_VISIBLE_NAIL_BUFF: 'CommonBuffId' = 273088 - OBJECT_MASSAGE_CHAIR_SOLEFUL_RUB: 'CommonBuffId' = 119944 - OBJECT_MASSAGE_CHAIR_TENDING: 'CommonBuffId' = 272164 - OBJECT_MASSAGE_CHAIR_WORN_OUT_NAILS: 'CommonBuffId' = 271649 - OBJECT_MASSAGE_TABLE_CONFIDENT_AROMA: 'CommonBuffId' = 117592 - OBJECT_MASSAGE_TABLE_CONFIDENT_AROMA_INCENSE: 'CommonBuffId' = 118898 - OBJECT_MASSAGE_TABLE_DEEPLY_RELAXED: 'CommonBuffId' = 117589 - OBJECT_MASSAGE_TABLE_DEEPLY_RELAXED_INCENSE: 'CommonBuffId' = 118899 - OBJECT_MASSAGE_TABLE_ENERGIZING_AROMA: 'CommonBuffId' = 117598 - OBJECT_MASSAGE_TABLE_ENERGIZING_AROMA_INCENSE: 'CommonBuffId' = 118900 - OBJECT_MASSAGE_TABLE_FERTILITY_BOOST: 'CommonBuffId' = 117594 - OBJECT_MASSAGE_TABLE_FERTILITY_BOOST_INCENSE: 'CommonBuffId' = 118901 - OBJECT_MASSAGE_TABLE_FOCUSING_AROMA: 'CommonBuffId' = 117600 - OBJECT_MASSAGE_TABLE_FOCUSING_AROMA_INCENSE: 'CommonBuffId' = 118902 - OBJECT_MASSAGE_TABLE_HIDDEN_JUST_GOT_MASSAGE_AROMATHERAPY: 'CommonBuffId' = 272445 - OBJECT_MASSAGE_TABLE_HIDDEN_JUST_GOT_MASSAGE_DEEPTISSUE: 'CommonBuffId' = 272446 - OBJECT_MASSAGE_TABLE_HIDDEN_JUST_GOT_MASSAGE_FERTILITY: 'CommonBuffId' = 272447 - OBJECT_MASSAGE_TABLE_HIDDEN_JUST_GOT_MASSAGE_SPORTS: 'CommonBuffId' = 272448 - OBJECT_MASSAGE_TABLE_HIDDEN_JUST_GOT_MASSAGE_STONE: 'CommonBuffId' = 272449 - OBJECT_MASSAGE_TABLE_HIDDEN_JUST_GOT_MASSAGE_SWEDISH: 'CommonBuffId' = 272450 - OBJECT_MASSAGE_TABLE_HOT_AND_HAPPY: 'CommonBuffId' = 117593 - OBJECT_MASSAGE_TABLE_HOT_AND_HAPPY_INCENSE: 'CommonBuffId' = 118903 - OBJECT_MASSAGE_TABLE_INSPIRATIONAL_AROMA: 'CommonBuffId' = 117599 - OBJECT_MASSAGE_TABLE_INSPIRATIONAL_AROMA_INCENSE: 'CommonBuffId' = 118904 - OBJECT_MASSAGE_TABLE_PASSED_GAS_HIDDEN: 'CommonBuffId' = 117597 - OBJECT_MASSAGE_TABLE_PREPPED_FOR_FITNESS: 'CommonBuffId' = 117591 - OBJECT_MASSAGE_TABLE_PREPPED_FOR_FITNESS_INCENSE: 'CommonBuffId' = 118906 - OBJECT_MASSAGE_TABLE_RELAXING_MASSAGE: 'CommonBuffId' = 117588 - OBJECT_MASSAGE_TABLE_RELAXING_MASSAGE_INCENSE: 'CommonBuffId' = 118907 - OBJECT_MASSAGE_TABLE_TENDING: 'CommonBuffId' = 272384 - OBJECT_MASSAGE_TABLE_UNCOMFORTABLE_MASSAGE: 'CommonBuffId' = 117596 - OBJECT_MASSAGE_TABLE_WORST_MASSAGE_EVER: 'CommonBuffId' = 117590 - OBJECT_MEDITATION_STOOL_CHILD_VFX: 'CommonBuffId' = 272117 - OBJECT_MICROSCOPE_INSPIRED: 'CommonBuffId' = 29927 - OBJECT_MICROWAVE_COLD: 'CommonBuffId' = 23985 - OBJECT_MICROWAVE_UPGRADED: 'CommonBuffId' = 28944 - OBJECT_MIRROR_ADMIRE_SELF_EMBARRASSED: 'CommonBuffId' = 97774 - OBJECT_MIRROR_ADMIRE_SELF_HAPPY: 'CommonBuffId' = 97771 - OBJECT_MIRROR_FEELING_FRUMPY: 'CommonBuffId' = 12440 - OBJECT_MIRROR_GUSSY_UP: 'CommonBuffId' = 12452 - OBJECT_MONKEY_BARS_PLAY: 'CommonBuffId' = 31649 - OBJECT_MOTION_GAMING_RIG_ADVENTURE: 'CommonBuffId' = 29392 - OBJECT_MOTION_GAMING_RIG_FAMILY: 'CommonBuffId' = 29399 - OBJECT_MOTION_GAMING_RIG_PUZZLE: 'CommonBuffId' = 39915 - OBJECT_MOTION_GAMING_RIG_SPORTS: 'CommonBuffId' = 29400 - OBJECT_MOVIE_AUTONOMY: 'CommonBuffId' = 191128 - OBJECT_MOVIE_BIG_SCREEN_LET_DOWN: 'CommonBuffId' = 129018 - OBJECT_MOVIE_BORING_MOVIE: 'CommonBuffId' = 129016 - OBJECT_MOVIE_CINEMA_SIN: 'CommonBuffId' = 129017 - OBJECT_MOVIE_GENRE_STAPLE: 'CommonBuffId' = 129020 - OBJECT_MOVIE_HIDDEN_CUDDLE_DONT_REACT: 'CommonBuffId' = 130510 - OBJECT_MOVIE_HIDDEN_FALL_ASLEEP: 'CommonBuffId' = 129462 - OBJECT_MOVIE_HIDDEN_SHUSH_TARGET: 'CommonBuffId' = 129286 - OBJECT_MOVIE_HIDDEN_WATCHED_ACTION: 'CommonBuffId' = 128976 - OBJECT_MOVIE_HIDDEN_WATCHED_COMEDY: 'CommonBuffId' = 128977 - OBJECT_MOVIE_HIDDEN_WATCHED_FAMILY: 'CommonBuffId' = 128979 - OBJECT_MOVIE_HIDDEN_WATCHED_HORROR: 'CommonBuffId' = 128978 - OBJECT_MOVIE_HIDDEN_WATCHED_ROMANCE: 'CommonBuffId' = 128980 - OBJECT_MOVIE_INTERESTING_FLICK: 'CommonBuffId' = 129019 - OBJECT_MOVIE_SILVER_SCREEN_MASTERPIECE: 'CommonBuffId' = 129021 - OBJECT_MUD_BATH_DECAY_MOD_FREEZE_FUN: 'CommonBuffId' = 121807 - OBJECT_MUD_BATH_MUCKY_MUD: 'CommonBuffId' = 120372 - OBJECT_MUD_BATH_MUD_IS_MAGIC: 'CommonBuffId' = 120371 - OBJECT_MUD_BATH_MUD_IS_MAGIC_INCENSE: 'CommonBuffId' = 120500 - OBJECT_MURAL_CAUGHT_DEFACING: 'CommonBuffId' = 150177 - OBJECT_MURAL_EP08_FLOOR_SCOOT_COOLDOWN: 'CommonBuffId' = 220779 - OBJECT_MURAL_FINISHED_A_MURAL: 'CommonBuffId' = 153091 - OBJECT_MURAL_IMPROVED_ART: 'CommonBuffId' = 149454 - OBJECT_MURAL_KICK_OFF: 'CommonBuffId' = 147462 - OBJECT_MURAL_KICK_OFF_NOW: 'CommonBuffId' = 154444 - OBJECT_MURAL_MARRED: 'CommonBuffId' = 149451 - OBJECT_MURAL_POLITICAL_MURAL: 'CommonBuffId' = 153267 - OBJECT_MURAL_SCOOT_COOLDOWN: 'CommonBuffId' = 147243 - OBJECT_MURAL_STATIC_COMMODITY_SCOLD: 'CommonBuffId' = 149995 - OBJECT_MURPHY_BED_REMOTE_TECH: 'CommonBuffId' = 230315 - OBJECT_MURPHY_BED_STUCK_UNDER_BED: 'CommonBuffId' = 230314 - OBJECT_MURPHY_BED_SWALLOWED_BY_BED: 'CommonBuffId' = 230318 - OBJECT_OCEAN_UNCOMFORTABLY_WARM: 'CommonBuffId' = 212979 - OBJECT_OFF_THE_GRID_BAD_RECEPTION: 'CommonBuffId' = 214402 - OBJECT_OFF_THE_GRID_CONSUME_AMPHIBIAN_AGILITY: 'CommonBuffId' = 235238 - OBJECT_OFF_THE_GRID_CONSUME_CRITTER: 'CommonBuffId' = 235234 - OBJECT_OFF_THE_GRID_CONSUME_FEASTED_LIKE_A_KING: 'CommonBuffId' = 235235 - OBJECT_OFF_THE_GRID_CONSUME_FORAGER_DELIGHT: 'CommonBuffId' = 235239 - OBJECT_OFF_THE_GRID_CONSUME_FRESH_CATCH: 'CommonBuffId' = 235237 - OBJECT_OFF_THE_GRID_CONSUME_LIVING_OFF_THE_LAND: 'CommonBuffId' = 235233 - OBJECT_OFF_THE_GRID_CONSUME_NATURES_REVENGE: 'CommonBuffId' = 235232 - OBJECT_OFF_THE_GRID_CONSUME_OMEGA_BRAIN_BOOST: 'CommonBuffId' = 235236 - OBJECT_OFF_THE_GRID_COOLDOWN_GATHER_SNOW: 'CommonBuffId' = 237053 - OBJECT_OFF_THE_GRID_COOLDOWN_GATHER_WATER: 'CommonBuffId' = 237051 - OBJECT_OFF_THE_GRID_FRIGIDLY_FRESH: 'CommonBuffId' = 212298 - OBJECT_OFF_THE_GRID_FUMES: 'CommonBuffId' = 212306 - OBJECT_OFF_THE_GRID_NEGATIVE_SORE_FROM_CHORES: 'CommonBuffId' = 237206 - OBJECT_OFF_THE_GRID_POSITIVE_CHAR: 'CommonBuffId' = 235225 - OBJECT_OFF_THE_GRID_POSITIVE_DROPPED_CALL: 'CommonBuffId' = 235223 - OBJECT_OFF_THE_GRID_POSITIVE_LOCAL_WATER: 'CommonBuffId' = 235226 - OBJECT_OFF_THE_GRID_POSITIVE_SPIT_SHINED: 'CommonBuffId' = 235224 - OBJECT_OVER_GLOATED: 'CommonBuffId' = 34086 - OBJECT_PAINTING_VIEW_INSPIRED: 'CommonBuffId' = 33647 - OBJECT_PAINTING_VIEW_TRAGIC_CLOWN_SAD: 'CommonBuffId' = 132564 - OBJECT_PET_BREAK_HIDING: 'CommonBuffId' = 163827 - OBJECT_PET_MINOR_CAGE_FED_RODENT: 'CommonBuffId' = 184003 - OBJECT_PET_MINOR_CAGE_FREEZE_RODENT_DISEASE: 'CommonBuffId' = 185938 - OBJECT_PET_MINOR_CAGE_HIDDEN_RODENT_DISEASE_CURED: 'CommonBuffId' = 185841 - OBJECT_PET_MINOR_CAGE_NEW_RODENT: 'CommonBuffId' = 184004 - OBJECT_PET_MINOR_CAGE_OBSERVE_HIDE_AND_SEEK: 'CommonBuffId' = 181475 - OBJECT_PET_MINOR_CAGE_OBSERVE_PIPE_SIZE_EXERCISE: 'CommonBuffId' = 181474 - OBJECT_PET_MINOR_CAGE_OBSERVE_RESTED_RODENT: 'CommonBuffId' = 181476 - OBJECT_PET_MINOR_CAGE_OBSERVE_RODENT_PEACE: 'CommonBuffId' = 181473 - OBJECT_PET_MINOR_CAGE_PLAYFUL_RODENT_PLAY_TIME: 'CommonBuffId' = 183684 - OBJECT_PET_MINOR_CAGE_RODENT_BITE: 'CommonBuffId' = 185508 - OBJECT_PET_MINOR_CAGE_RODENT_DEATH: 'CommonBuffId' = 188565 - OBJECT_PET_MINOR_CAGE_RODENT_DISEASE_1: 'CommonBuffId' = 181672 - OBJECT_PET_MINOR_CAGE_RODENT_DISEASE_2: 'CommonBuffId' = 181673 - OBJECT_PET_MINOR_CAGE_RODENT_DISEASE_3: 'CommonBuffId' = 181674 - OBJECT_PET_MINOR_CAGE_RODENT_FREEDOM: 'CommonBuffId' = 184005 - OBJECT_PET_RECIPE_ATE_PET_FOOD: 'CommonBuffId' = 169582 - OBJECT_PET_RECIPE_ATE_PET_FOOD_TODDLER: 'CommonBuffId' = 174911 - OBJECT_PET_RECIPE_DRANK_PET_FOOD: 'CommonBuffId' = 179771 - OBJECT_PET_RECIPE_DRANK_PET_FOOD_GLUTTON: 'CommonBuffId' = 179833 - OBJECT_PET_RECIPE_GLUTTON: 'CommonBuffId' = 169583 - OBJECT_PET_RECIPE_KISSED_BY_MINTY_BREATH: 'CommonBuffId' = 169580 - OBJECT_PET_RECIPE_MINTY_BREATH: 'CommonBuffId' = 169581 - OBJECT_PHONE_CHAT_SUCCESS: 'CommonBuffId' = 24064 - OBJECT_PHONE_HIGH_SCORE: 'CommonBuffId' = 97941 - OBJECT_PHONE_PRANK_FAIL: 'CommonBuffId' = 30831 - OBJECT_PHONE_PRANK_SUCCESS: 'CommonBuffId' = 30832 - OBJECT_PHONE_RESPOND_TO_MAIL_NEGATIVE_CRITICISM: 'CommonBuffId' = 136682 - OBJECT_PHONE_RESPOND_TO_MAIL_POSITIVE_FEEDBACK: 'CommonBuffId' = 136683 - OBJECT_PHONE_RESPOND_TO_MAIL_TROLLED: 'CommonBuffId' = 136679 - OBJECT_PHONE_SAD_HOTLINE: 'CommonBuffId' = 24365 - OBJECT_PHONE_SEND_SELFIE_FAILURE: 'CommonBuffId' = 377576 - OBJECT_PHONE_SEND_TEXT_SUCCESS: 'CommonBuffId' = 24011 - OBJECT_PIANO_COOL_KEY_CHORDS: 'CommonBuffId' = 34519 - OBJECT_PIANO_JAZZED_UP: 'CommonBuffId' = 24615 - OBJECT_PIANO_KILLER_KEY_CHORDS: 'CommonBuffId' = 36972 - OBJECT_PING_PONG_BETTER_SCHOOL_WINS: 'CommonBuffId' = 212748 - OBJECT_PIPE_ORGAN_PALLIATIVE_PIPES: 'CommonBuffId' = 151298 - OBJECT_PLASTIC_FLOWER_AROUND_AND_AROUND: 'CommonBuffId' = 143488 - OBJECT_PLASTIC_FLOWER_MESMERIZED: 'CommonBuffId' = 140845 - OBJECT_PLUMBING_USE_DIRTY: 'CommonBuffId' = 10165 - OBJECT_PODIUM_BRILLIANT_ORATOR: 'CommonBuffId' = 137263 - OBJECT_PODIUM_EVENT_RECEIVED_HIDDEN: 'CommonBuffId' = 136959 - OBJECT_PODIUM_FEEL_THE_CALL: 'CommonBuffId' = 136949 - OBJECT_PODIUM_FEEL_THE_CALL_ANGRY: 'CommonBuffId' = 136952 - OBJECT_PODIUM_FEEL_THE_CALL_CONFIDENT: 'CommonBuffId' = 136953 - OBJECT_PODIUM_FEEL_THE_CALL_ENERGIZED: 'CommonBuffId' = 136954 - OBJECT_PODIUM_FEEL_THE_CALL_HIDDEN: 'CommonBuffId' = 155448 - OBJECT_PODIUM_FEEL_THE_CALL_INSPIRED: 'CommonBuffId' = 136955 - OBJECT_PODIUM_GIVE_EULOGY: 'CommonBuffId' = 152738 - OBJECT_PODIUM_LAME_DRIVEL: 'CommonBuffId' = 136950 - OBJECT_PODIUM_LAME_DRIVEL_HIDDEN: 'CommonBuffId' = 155449 - OBJECT_PODIUM_WATCHING_SPEECH_ANGRY_HIDDEN: 'CommonBuffId' = 136939 - OBJECT_PODIUM_WATCHING_SPEECH_CONFIDENT_HIDDEN: 'CommonBuffId' = 136940 - OBJECT_PODIUM_WATCHING_SPEECH_ENERGIZED_HIDDEN: 'CommonBuffId' = 136941 - OBJECT_PODIUM_WATCHING_SPEECH_HIDDEN: 'CommonBuffId' = 136824 - OBJECT_PODIUM_WATCHING_SPEECH_INSPIRED_HIDDEN: 'CommonBuffId' = 136942 - OBJECT_POOL_UNCOMFORTABLY_WARM: 'CommonBuffId' = 107550 - OBJECT_POTTY_ACCIDENT: 'CommonBuffId' = 144960 - OBJECT_POTTY_BEING_MENTORED_HIDDEN: 'CommonBuffId' = 145219 - OBJECT_POTTY_BEING_MENTORED_HIDDEN_CLINGY: 'CommonBuffId' = 154563 - OBJECT_PREVENT_FREEZING: 'CommonBuffId' = 184873 - OBJECT_PUBLIC_BATHROOM_SO_GROSS: 'CommonBuffId' = 38544 - OBJECT_PUMPKIN_CARVED_ART: 'CommonBuffId' = 126865 - OBJECT_PUMPKIN_CARVE_PUMPKIN: 'CommonBuffId' = 125551 - OBJECT_PUMPKIN_INTERESTING_CARVING: 'CommonBuffId' = 125061 - OBJECT_PUMPKIN_PUMPKIN_HEAD: 'CommonBuffId' = 125058 - OBJECT_PUMPKIN_SMASHING_PUMPKINS: 'CommonBuffId' = 125060 - OBJECT_RANCH_NECTAR_AFTER_GLOW_CONFIDENT: 'CommonBuffId' = 323637 - OBJECT_RANCH_NECTAR_AFTER_GLOW_ENERGIZED: 'CommonBuffId' = 323638 - OBJECT_RANCH_NECTAR_AFTER_GLOW_FLIRTY: 'CommonBuffId' = 323639 - OBJECT_RANCH_NECTAR_AFTER_GLOW_HAPPY: 'CommonBuffId' = 323662 - OBJECT_RANCH_NECTAR_AFTER_GLOW_INSPIRED: 'CommonBuffId' = 323640 - OBJECT_RANCH_NECTAR_AFTER_GLOW_UNCOMFORTABLE: 'CommonBuffId' = 323663 - OBJECT_RANCH_NECTAR_MAKER_ENERGIZED: 'CommonBuffId' = 333569 - OBJECT_RANCH_NECTAR_MAKER_PLAYFUL: 'CommonBuffId' = 333567 - OBJECT_RANCH_NECTAR_MAKER_UNCOMFORTABLE: 'CommonBuffId' = 333566 - OBJECT_RANCH_NECTAR_MOOD_EFFECTS_CONFIDENT_1: 'CommonBuffId' = 315780 - OBJECT_RANCH_NECTAR_MOOD_EFFECTS_CONFIDENT_3: 'CommonBuffId' = 315781 - OBJECT_RANCH_NECTAR_MOOD_EFFECTS_CONFIDENT_6: 'CommonBuffId' = 315782 - OBJECT_RANCH_NECTAR_MOOD_EFFECTS_ENERGIZED_1: 'CommonBuffId' = 315784 - OBJECT_RANCH_NECTAR_MOOD_EFFECTS_ENERGIZED_3: 'CommonBuffId' = 315785 - OBJECT_RANCH_NECTAR_MOOD_EFFECTS_ENERGIZED_6: 'CommonBuffId' = 315786 - OBJECT_RANCH_NECTAR_MOOD_EFFECTS_FLIRTY_1: 'CommonBuffId' = 315788 - OBJECT_RANCH_NECTAR_MOOD_EFFECTS_FLIRTY_3: 'CommonBuffId' = 315789 - OBJECT_RANCH_NECTAR_MOOD_EFFECTS_FLIRTY_6: 'CommonBuffId' = 315790 - OBJECT_RANCH_NECTAR_MOOD_EFFECTS_HAPPY_1: 'CommonBuffId' = 315792 - OBJECT_RANCH_NECTAR_MOOD_EFFECTS_HAPPY_2: 'CommonBuffId' = 323632 - OBJECT_RANCH_NECTAR_MOOD_EFFECTS_HAPPY_3: 'CommonBuffId' = 315793 - OBJECT_RANCH_NECTAR_MOOD_EFFECTS_HAPPY_4: 'CommonBuffId' = 323633 - OBJECT_RANCH_NECTAR_MOOD_EFFECTS_HAPPY_6: 'CommonBuffId' = 315794 - OBJECT_RANCH_NECTAR_MOOD_EFFECTS_HIDDEN_AGED: 'CommonBuffId' = 323636 - OBJECT_RANCH_NECTAR_MOOD_EFFECTS_HIDDEN_POTATO: 'CommonBuffId' = 323635 - OBJECT_RANCH_NECTAR_MOOD_EFFECTS_INSPIRED_1: 'CommonBuffId' = 315796 - OBJECT_RANCH_NECTAR_MOOD_EFFECTS_INSPIRED_3: 'CommonBuffId' = 315797 - OBJECT_RANCH_NECTAR_MOOD_EFFECTS_INSPIRED_6: 'CommonBuffId' = 315798 - OBJECT_RANCH_NECTAR_PASSED_OUT: 'CommonBuffId' = 323417 - OBJECT_RANCH_NECTAR_TRAIT_BAD: 'CommonBuffId' = 338174 - OBJECT_RANCH_NECTAR_TRAIT_GOOD: 'CommonBuffId' = 338172 - OBJECT_RANCH_NECTAR_TRASH: 'CommonBuffId' = 323866 - OBJECT_RANCH_NECTAR_WILDGRASS: 'CommonBuffId' = 323665 - OBJECT_RANCH_NECTAR_WILDGRASS_AGED: 'CommonBuffId' = 323666 - OBJECT_READ_MAGAZINE_COOLDOWN_HIDDEN: 'CommonBuffId' = 120289 - OBJECT_ROCKET_SHIP_BITTEN_BY_ALIEN: 'CommonBuffId' = 39051 - OBJECT_ROCKET_SHIP_BUSTED_BY_SPACE_POLICE: 'CommonBuffId' = 39046 - OBJECT_ROCKET_SHIP_ESCAPED_CRASH: 'CommonBuffId' = 8580 - OBJECT_ROCKET_SHIP_EXPLORED_SPACE: 'CommonBuffId' = 8581 - OBJECT_ROCKET_SHIP_FIFTY_MILE_HIGH_CLUB: 'CommonBuffId' = 8584 - OBJECT_ROCKET_SHIP_FIFTY_MILE_HIGH_CLUB_TEEN: 'CommonBuffId' = 100785 - OBJECT_ROCKET_SHIP_JOINED_THE_FIFTY_MILE_HIGH_CLUB: 'CommonBuffId' = 8583 - OBJECT_ROCKET_SHIP_JOINED_THE_FIFTY_MILE_HIGH_CLUB_TEEN: 'CommonBuffId' = 100784 - OBJECT_ROCKET_SHIP_OPPRESSED_COLONISTS: 'CommonBuffId' = 39044 - OBJECT_ROCKET_SHIP_ORBITED_MOON: 'CommonBuffId' = 38471 - OBJECT_ROCKET_SHIP_SPACE_BATTLE_WIN: 'CommonBuffId' = 38737 - OBJECT_ROCKET_SHIP_SPACE_CHEESE: 'CommonBuffId' = 132354 - OBJECT_ROCKING_CHAIR_ELDER: 'CommonBuffId' = 242372 - OBJECT_ROCKING_CHAIR_REMINISCE_ANGRY: 'CommonBuffId' = 240871 - OBJECT_ROCKING_CHAIR_REMINISCE_EMBARRASSED: 'CommonBuffId' = 240872 - OBJECT_ROCKING_CHAIR_REMINISCE_HAPPY: 'CommonBuffId' = 240851 - OBJECT_ROCKING_CHAIR_REMINISCE_SAD: 'CommonBuffId' = 240869 - OBJECT_ROCKING_CHAIR_ROCK: 'CommonBuffId' = 242370 - OBJECT_SACK_LUNCH_HOMEMADE_MEAL: 'CommonBuffId' = 165119 - OBJECT_SACK_LUNCH_HOMEMADE_MEAL_HIGH: 'CommonBuffId' = 168705 - OBJECT_SCHOOL_LOCKER_DECORATION_COOLDOWN: 'CommonBuffId' = 290922 - OBJECT_SCHOOL_LOCKER_SNACK_COOLDOWN: 'CommonBuffId' = 298488 - OBJECT_SCHOOL_LOCKER_SOMETHING_ROTTEN: 'CommonBuffId' = 277069 - OBJECT_SEATING_COZY_LAZY: 'CommonBuffId' = 75859 - OBJECT_SEATING_HAPPY: 'CommonBuffId' = 25003 - OBJECT_SEATING_UNCOMFORTABLE: 'CommonBuffId' = 24999 - OBJECT_SERENADED: 'CommonBuffId' = 24621 - OBJECT_SERENADER: 'CommonBuffId' = 24623 - OBJECT_SHOWER_BRISK: 'CommonBuffId' = 39963 - OBJECT_SHOWER_CLEAN_VOCAL_SKILLS: 'CommonBuffId' = 141950 - OBJECT_SHOWER_DO_NOT_DISTURB: 'CommonBuffId' = 28592 - OBJECT_SHOWER_INSPIRATION: 'CommonBuffId' = 39849 - OBJECT_SHOWER_MESS_AROUND: 'CommonBuffId' = 227533 - OBJECT_SHOWER_NON_SINGING_HIDDEN: 'CommonBuffId' = 141946 - OBJECT_SHOWER_STEAMY: 'CommonBuffId' = 39863 - OBJECT_SHOWER_TAKE_SHOWER_HIGH_QUALITY: 'CommonBuffId' = 9966 - OBJECT_SHOWER_TAKE_SHOWER_HIGH_QUALITY_UPGRADE: 'CommonBuffId' = 10135 - OBJECT_SHOWER_TAKE_SHOWER_LOW_QUALITY: 'CommonBuffId' = 9967 - OBJECT_SHOWER_TAKE_SHOWER_UPGRADE: 'CommonBuffId' = 10134 - OBJECT_SINK_BRUSH_TEETH: 'CommonBuffId' = 12523 - OBJECT_SINK_IS_WASHING_DIRTY_DISHES: 'CommonBuffId' = 76836 - OBJECT_SINK_SOAP_UPGRADE: 'CommonBuffId' = 28529 - OBJECT_SKATING_RINK_BACKWARDS_REMOVE_TIMER: 'CommonBuffId' = 191015 - OBJECT_SKATING_RINK_BACKWARDS_WALK_STYLE_ICE: 'CommonBuffId' = 180434 - OBJECT_SKATING_RINK_BACKWARDS_WALK_STYLE_ROLLER: 'CommonBuffId' = 183908 - OBJECT_SKATING_RINK_ICE_SKILL_HIGH: 'CommonBuffId' = 183869 - OBJECT_SKATING_RINK_ICE_SKILL_LOW: 'CommonBuffId' = 180342 - OBJECT_SKATING_RINK_ICE_SKILL_MED: 'CommonBuffId' = 185397 - OBJECT_SKATING_RINK_PRACTICE_TRICKS: 'CommonBuffId' = 173346 - OBJECT_SKATING_RINK_PRACTICE_TRICKS_NO_VFX: 'CommonBuffId' = 189879 - OBJECT_SKATING_RINK_ROLLER_SKILL_HIGH: 'CommonBuffId' = 183901 - OBJECT_SKATING_RINK_ROLLER_SKILL_LOW: 'CommonBuffId' = 183902 - OBJECT_SKATING_RINK_ROLLER_SKILL_MED: 'CommonBuffId' = 185398 - OBJECT_SKATING_RINK_ROUTINE: 'CommonBuffId' = 185103 - OBJECT_SKATING_RINK_ROUTINE_NO_VFX: 'CommonBuffId' = 189878 - OBJECT_SKATING_RINK_ROUTINE_REACTIONS_FAILURE: 'CommonBuffId' = 190819 - OBJECT_SKATING_RINK_ROUTINE_REACTIONS_SUCCESS: 'CommonBuffId' = 190818 - OBJECT_SKATING_RINK_ROUTINE_SKATER_ADEQUATE: 'CommonBuffId' = 180131 - OBJECT_SKATING_RINK_ROUTINE_SKATER_AMAZING: 'CommonBuffId' = 180128 - OBJECT_SKATING_RINK_ROUTINE_SKATER_EMBARRASSING_NEG: 'CommonBuffId' = 180129 - OBJECT_SKATING_RINK_ROUTINE_SKATER_MESSED_UP_NEG: 'CommonBuffId' = 180130 - OBJECT_SKATING_RINK_ROUTINE_SKATER_PERFECT: 'CommonBuffId' = 180127 - OBJECT_SKATING_RINK_ROUTINE_WATCHER_ADEQUATE: 'CommonBuffId' = 180124 - OBJECT_SKATING_RINK_ROUTINE_WATCHER_PERFECT: 'CommonBuffId' = 180125 - OBJECT_SKATING_RINK_ROUTINE_WATCHER_TERRIBLE: 'CommonBuffId' = 180126 - OBJECT_SLIPPY_SLIDE_BACKYARD_WATER_PACK: 'CommonBuffId' = 140355 - OBJECT_SLIPPY_SLIDE_FOAMY_SLIDE: 'CommonBuffId' = 143346 - OBJECT_SLIPPY_SLIDE_HIDDEN_BROADCASTER_FAIL: 'CommonBuffId' = 140878 - OBJECT_SLIPPY_SLIDE_HIDDEN_BROADCASTER_SUCCESS: 'CommonBuffId' = 140879 - OBJECT_SLIPPY_SLIDE_HIDDEN_BROADCASTER_TRICK_FAIL: 'CommonBuffId' = 141457 - OBJECT_SLIPPY_SLIDE_HIDDEN_BROADCASTER_TRICK_SUCCESS: 'CommonBuffId' = 141458 - OBJECT_SLIPPY_SLIDE_HIDDEN_SLIDE_FAIL: 'CommonBuffId' = 140352 - OBJECT_SLIPPY_SLIDE_HIDDEN_SLIDING: 'CommonBuffId' = 142638 - OBJECT_SLIPPY_SLIDE_HIDDEN_SOAP_SUDS: 'CommonBuffId' = 141922 - OBJECT_SLIPPY_SLIDE_HIDDEN_SOAP_SUDS_CHILDREN: 'CommonBuffId' = 143421 - OBJECT_SLIPPY_SLIDE_TOO_SLIPPERY: 'CommonBuffId' = 140353 - OBJECT_SLIPPY_SLIDE_TRICKTASTROPHE: 'CommonBuffId' = 140354 - OBJECT_SLIPPY_SLIDE_TRICK_SLIDE_MASTER: 'CommonBuffId' = 140356 - OBJECT_SLIPPY_SLIDE_WATCH_BRO_SLIDE: 'CommonBuffId' = 141306 - OBJECT_SLIPPY_SLIDE_WATCH_GREAT_TRICKS: 'CommonBuffId' = 141307 - OBJECT_SLIPPY_SLIDE_WATCH_LOOKS_LIKE_FUN: 'CommonBuffId' = 141305 - OBJECT_SLIPPY_SLIDE_WATCH_SHOWOFF: 'CommonBuffId' = 141310 - OBJECT_SLIPPY_SLIDE_WATCH_SLIDE_FAIL: 'CommonBuffId' = 141309 - OBJECT_SLIPPY_SLIDE_WATCH_THAT_HAD_TO_HURT: 'CommonBuffId' = 141308 - OBJECT_SMART_HUB_BEEN_COMPLIMENTED: 'CommonBuffId' = 204332 - OBJECT_SMART_HUB_BEEN_INSULTED: 'CommonBuffId' = 204328 - OBJECT_SMART_HUB_GOT_AFFIRMATION: 'CommonBuffId' = 204003 - OBJECT_SMART_HUB_GOT_JOKE: 'CommonBuffId' = 204004 - OBJECT_SMART_HUB_GOT_NEWS: 'CommonBuffId' = 203963 - OBJECT_SMART_HUB_MISBEHAVIOR_ANGRY: 'CommonBuffId' = 204546 - OBJECT_SMART_HUB_MISBEHAVIOR_SAD: 'CommonBuffId' = 204547 - OBJECT_SMART_HUB_SERVICE_PROVIDED_PIZZA: 'CommonBuffId' = 204929 - OBJECT_SPACE_HEATER_HEATED_SURROUNDINGS: 'CommonBuffId' = 252945 - OBJECT_SPACE_HEATER_WARMED_BY_SPACE_HEATER: 'CommonBuffId' = 252944 - OBJECT_SQUAT_TOILET_PRANKED: 'CommonBuffId' = 347302 - OBJECT_STEAM_ROOM_HIDDEN_DEATH_BY_STEAM: 'CommonBuffId' = 119830 - OBJECT_STEAM_ROOM_HIDDEN_GET_OUT: 'CommonBuffId' = 122213 - OBJECT_STEAM_ROOM_HIDDEN_RELAXING: 'CommonBuffId' = 119633 - OBJECT_STEAM_ROOM_HOT_N_STEAMY: 'CommonBuffId' = 119397 - OBJECT_STEAM_ROOM_ROTTEN_EGGS: 'CommonBuffId' = 119398 - OBJECT_STEAM_ROOM_SATISFACTORY_STEAMING: 'CommonBuffId' = 119393 - OBJECT_STEAM_ROOM_STUPENDOUS_STEAMING: 'CommonBuffId' = 119394 - OBJECT_STEAM_ROOM_SUPERFLUOUS_STEAMING: 'CommonBuffId' = 119396 - OBJECT_STEAM_ROOM_SUPREME_STEAMING: 'CommonBuffId' = 119395 - OBJECT_STEREO_CLASSICAL_HIDDEN: 'CommonBuffId' = 354086 - OBJECT_STEREO_MUSIC: 'CommonBuffId' = 96812 - OBJECT_STEREO_MUSIC_FOCUS: 'CommonBuffId' = 240288 - OBJECT_STEREO_MUSIC_METAL: 'CommonBuffId' = 240287 - OBJECT_STEREO_MUSIC_ROMANCE: 'CommonBuffId' = 370714 - OBJECT_STEREO_MUSIC_TODDLER: 'CommonBuffId' = 147776 - OBJECT_STEREO_NEW_AGE_BORED: 'CommonBuffId' = 118102 - OBJECT_STEREO_NEW_AGE_FOCUSED: 'CommonBuffId' = 118101 - OBJECT_STEREO_NEW_AGE_HIDDEN: 'CommonBuffId' = 354087 - OBJECT_STEREO_SUMMER_STRUT: 'CommonBuffId' = 179825 - OBJECT_STEREO_WINTER_HOLIDAY: 'CommonBuffId' = 179922 - OBJECT_STOVE_HEAT_SENSOR: 'CommonBuffId' = 28861 - OBJECT_STUFFED_ANIMAL_HAPPY: 'CommonBuffId' = 33305 - OBJECT_STUFFED_ANIMAL_HUG_COOLDOWN: 'CommonBuffId' = 157859 - OBJECT_STUFFED_ANIMAL_PLAYFUL: 'CommonBuffId' = 31778 - OBJECT_SURFACE_USE_DIRTY: 'CommonBuffId' = 36389 - OBJECT_SWING_SET_EXIT_SWING: 'CommonBuffId' = 190191 - OBJECT_TELESCOPE_INSPIRED: 'CommonBuffId' = 29876 - OBJECT_TELESCOPE_LOGIC_FESTIVAL_CAUGHT_SPYING: 'CommonBuffId' = 144282 - OBJECT_TELESCOPE_LOGIC_FESTIVAL_WITNESSED_APARTMENT: 'CommonBuffId' = 144283 - OBJECT_TELESCOPE_NEIGHBORS_BORED: 'CommonBuffId' = 38838 - OBJECT_TELESCOPE_NEIGHBORS_EMBARRASSED: 'CommonBuffId' = 38840 - OBJECT_TELESCOPE_NEIGHBORS_FLIRTY: 'CommonBuffId' = 29910 - OBJECT_TELESCOPE_NEIGHBORS_PLAYFUL: 'CommonBuffId' = 38839 - OBJECT_TEMPERATURE_MODIFIER_EXERCISING: 'CommonBuffId' = 189969 - OBJECT_TEMPERATURE_MODIFIER_FIRE_CLIMBING: 'CommonBuffId' = 189818 - OBJECT_TEMPERATURE_MODIFIER_KIDDIE_POOL: 'CommonBuffId' = 189728 - OBJECT_TENT_GREAT_SCARE: 'CommonBuffId' = 105338 - OBJECT_TENT_HIDDEN_IN_TENT: 'CommonBuffId' = 185156 - OBJECT_TENT_REACTED_TO_WOO_HOO_HIDDEN: 'CommonBuffId' = 107517 - OBJECT_TENT_SCARED_BLADDERLESS: 'CommonBuffId' = 105337 - OBJECT_TENT_SMOKEY: 'CommonBuffId' = 105004 - OBJECT_TENT_WOOHOOED_IN_THE_WILD: 'CommonBuffId' = 105985 - OBJECT_TODDLER_JUNGLE_GYM_MAKE_BELIEVE_PIRATE: 'CommonBuffId' = 172892 - OBJECT_TODDLER_JUNGLE_GYM_MAKE_BELIEVE_PLAY_WITH_PIRATE: 'CommonBuffId' = 173516 - OBJECT_TODDLER_JUNGLE_GYM_MAKE_BELIEVE_PLAY_WITH_ROCKET: 'CommonBuffId' = 173517 - OBJECT_TODDLER_JUNGLE_GYM_MAKE_BELIEVE_ROCKET: 'CommonBuffId' = 172891 - OBJECT_TODDLER_JUNGLE_GYM_MAKE_BELIEVE_SHARED_WORLD_IMAGINATION: 'CommonBuffId' = 172960 - OBJECT_TODDLER_JUNGLE_GYM_SLIDE_FUN_SLIDE: 'CommonBuffId' = 171990 - OBJECT_TODDLER_JUNGLE_GYM_SLIDE_SCARY_SLIDE: 'CommonBuffId' = 172004 - OBJECT_TODDLER_JUNGLE_GYM_TUNNELS_A_MY_TUNNEL: 'CommonBuffId' = 171003 - OBJECT_TODDLER_JUNGLE_GYM_TUNNELS_H_TUNNEL_FUN: 'CommonBuffId' = 171002 - OBJECT_TODDLER_JUNGLE_GYM_TUNNELS_P_TUNNEL_ADVENTURE: 'CommonBuffId' = 171000 - OBJECT_TODDLER_JUNGLE_GYM_TUNNELS_S_SCRAPED_KNEE: 'CommonBuffId' = 171001 - OBJECT_TOILET_BATHROOM_BUDDY: 'CommonBuffId' = 214242 - OBJECT_TOILET_BIDET: 'CommonBuffId' = 96968 - OBJECT_TOILET_JUST_CRIED: 'CommonBuffId' = 214241 - OBJECT_TOILET_LOW_QUALITY: 'CommonBuffId' = 10450 - OBJECT_TOILET_NO_TABLET: 'CommonBuffId' = 100122 - OBJECT_TOILET_PRANKED: 'CommonBuffId' = 227118 - OBJECT_TOILET_TALKING_FAMILIARITY_REACTION_COOLDOWN: 'CommonBuffId' = 134855 - OBJECT_TOILET_TALKING_HIDDEN_NEGATIVE_STC: 'CommonBuffId' = 138089 - OBJECT_TOILET_TALKING_MASSAGE_ENERGIZED: 'CommonBuffId' = 134537 - OBJECT_TOILET_TALKING_WATCH_FOCUSED: 'CommonBuffId' = 142802 - OBJECT_TOILET_TALKING_WATCH_PLAYFUL: 'CommonBuffId' = 142803 - OBJECT_TOXIC_FIRE_LEAF_EXTREME_ITCH: 'CommonBuffId' = 102123 - OBJECT_TOXIC_FIRE_LEAF_EXTREME_ITCH_BASE_GAME: 'CommonBuffId' = 120040 - OBJECT_TOXIC_FIRE_LEAF_IRKSOME_ITCH: 'CommonBuffId' = 102101 - OBJECT_TOXIC_FIRE_LEAF_IRKSOME_ITCH_BASE_GAME: 'CommonBuffId' = 120041 - OBJECT_TOXIC_FIRE_LEAF_UNRELENTING_ITCH: 'CommonBuffId' = 102122 - OBJECT_TOXIC_FIRE_LEAF_UNRELENTING_ITCH_BASE_GAME: 'CommonBuffId' = 120042 - OBJECT_TOY_BALL_PET_PET_PLAYING: 'CommonBuffId' = 164418 - OBJECT_TOY_BOX_AWESOME_TOY: 'CommonBuffId' = 12530 - OBJECT_TOY_CLEAN_UP_HIDDEN_COOLDOWN: 'CommonBuffId' = 157507 - OBJECT_TOY_EMOTION_TALKING_DOLL_ANGRY: 'CommonBuffId' = 32949 - OBJECT_TOY_EMOTION_TALKING_DOLL_BORED: 'CommonBuffId' = 32950 - OBJECT_TOY_EMOTION_TALKING_DOLL_EMBARRASSED: 'CommonBuffId' = 32959 - OBJECT_TOY_EMOTION_TALKING_DOLL_HAPPY: 'CommonBuffId' = 32947 - OBJECT_TOY_EMOTION_TALKING_DOLL_PLAYFUL: 'CommonBuffId' = 32948 - OBJECT_TOY_EMOTION_TALKING_DOLL_SAD: 'CommonBuffId' = 32951 - OBJECT_TOY_EMOTION_TALKING_DOLL_STRESSED: 'CommonBuffId' = 32958 - OBJECT_TOY_SECRET_WORLD: 'CommonBuffId' = 147876 - OBJECT_TOY_TOYING_AROUND: 'CommonBuffId' = 24582 - OBJECT_TRASH_CHUTE_STRESSED: 'CommonBuffId' = 148387 - OBJECT_TREAD_MILL_ROCK_CLIMBING_WALL_DEFEATED_CLIMBING_HIGH_SCORE: 'CommonBuffId' = 165809 - OBJECT_TREAD_MILL_ROCK_CLIMBING_WALL_DEFEAT_CLIMB_LEVEL_1: 'CommonBuffId' = 165811 - OBJECT_TREAD_MILL_ROCK_CLIMBING_WALL_DEFEAT_CLIMB_LEVEL_2: 'CommonBuffId' = 165812 - OBJECT_TREAD_MILL_ROCK_CLIMBING_WALL_DEFEAT_CLIMB_LEVEL_3: 'CommonBuffId' = 165813 - OBJECT_TREAD_MILL_ROCK_CLIMBING_WALL_DEFEAT_CLIMB_LEVEL_4: 'CommonBuffId' = 165814 - OBJECT_TREAD_MILL_ROCK_CLIMBING_WALL_DEFEAT_CLIMB_LEVEL_5: 'CommonBuffId' = 165815 - OBJECT_TREAD_MILL_ROCK_CLIMBING_WALL_DEFEAT_CLIMB_LEVEL_CHAMPION: 'CommonBuffId' = 165816 - OBJECT_TREAD_MILL_ROCK_CLIMBING_WALL_HIDDEN_IS_CLIMBING: 'CommonBuffId' = 165282 - OBJECT_TREAD_MILL_ROCK_CLIMBING_WALL_SURVIVED_ROCK_WALL_MALFUNCTION: 'CommonBuffId' = 165817 - OBJECT_TV_CHILD_LEARNING_ADULTS: 'CommonBuffId' = 318272 - OBJECT_TV_CHILD_LEARNING_KIDS: 'CommonBuffId' = 338847 - OBJECT_TV_CTYAE_WATCHING_WITH_CT: 'CommonBuffId' = 229043 - OBJECT_TV_FIREPLACE_WINTER: 'CommonBuffId' = 179867 - OBJECT_TV_HOME_DECORATING_CHANNEL_DECORATOR_CREATIVE: 'CommonBuffId' = 257804 - OBJECT_TV_HOME_DECORATING_CHANNEL_DECORATOR_NOT_CREATIVE: 'CommonBuffId' = 257805 - OBJECT_TV_HOME_DECORATING_CHANNEL_NORMAL_CREATIVE: 'CommonBuffId' = 257807 - OBJECT_TV_HOME_DECORATING_CHANNEL_NORMAL_NOT_CREATIVE: 'CommonBuffId' = 257806 - OBJECT_TV_MINU_S06_COMEDY_CHANNEL: 'CommonBuffId' = 12536 - OBJECT_TV_MINU_S10_ROMANCE_CHANNEL_FLIRTY: 'CommonBuffId' = 10491 - OBJECT_TV_MINU_S16_KIDS_CHANNEL_KIDS: 'CommonBuffId' = 23734 - OBJECT_TV_MINU_S17_KIDS_CHANNEL_ADULTS: 'CommonBuffId' = 23736 - OBJECT_TV_PUBLIC_ACCESS: 'CommonBuffId' = 146008 - OBJECT_TV_SCARY_BRAVE: 'CommonBuffId' = 318280 - OBJECT_TV_SCARY_EXTRA_BRAVE: 'CommonBuffId' = 318281 - OBJECT_TV_SCARY_EXTRA_SCARED: 'CommonBuffId' = 318279 - OBJECT_TV_SCARY_RUN_AWAY: 'CommonBuffId' = 318282 - OBJECT_TV_SCARY_SCARED: 'CommonBuffId' = 318278 - OBJECT_TV_SCARY_TODDLER_NIGHTMARE: 'CommonBuffId' = 318283 - OBJECT_TV_SCARY_TODDLER_SAD: 'CommonBuffId' = 318365 - OBJECT_TV_SILENT_WESTERN_HORSE_LOVER: 'CommonBuffId' = 338475 - OBJECT_TV_SITCOM_PLAYFUL: 'CommonBuffId' = 321869 - OBJECT_TV_SITCOM_PLAYFUL_TOGETHER: 'CommonBuffId' = 321870 - OBJECT_TV_TEEN_EQUESTRIANS_HORSE_LOVER: 'CommonBuffId' = 338474 - OBJECT_TV_TEEN_EQUESTRIANS_KIDS: 'CommonBuffId' = 338473 - OBJECT_TV_TRAIT_LOVE_BUG: 'CommonBuffId' = 378229 - OBJECT_TV_TRAIT_SNOB: 'CommonBuffId' = 37111 - OBJECT_TV_TRAIT_SNOB_NEWS: 'CommonBuffId' = 98110 - OBJECT_TV_WEATHER_TV_CLIMATE_CHANGE: 'CommonBuffId' = 179839 - OBJECT_URN_STONE_MOURN_ENEMY: 'CommonBuffId' = 12540 - OBJECT_URN_STONE_MOURN_FRIEND: 'CommonBuffId' = 12541 - OBJECT_URN_STONE_MOURN_FRIEND_DOG: 'CommonBuffId' = 174950 - OBJECT_URN_STONE_MOURN_LOVED_ONE: 'CommonBuffId' = 103190 - OBJECT_URN_STONE_MOURN_NEUTRAL: 'CommonBuffId' = 12542 - OBJECT_URN_STONE_MOURN_NEUTRAL_PET: 'CommonBuffId' = 178053 - OBJECT_URN_STONE_RELEASE_SPIRIT_NEGATIVE: 'CommonBuffId' = 98917 - OBJECT_URN_STONE_RELEASE_SPIRIT_POSITIVE: 'CommonBuffId' = 98951 - OBJECT_VANITY_APPLIED_MAKE_UP: 'CommonBuffId' = 145345 - OBJECT_VANITY_APPLIED_MAKE_UP_BLUE: 'CommonBuffId' = 152383 - OBJECT_VANITY_APPLIED_MAKE_UP_GREEN: 'CommonBuffId' = 152384 - OBJECT_VANITY_APPLIED_MAKE_UP_PINK: 'CommonBuffId' = 152386 - OBJECT_VANITY_APPLIED_MAKE_UP_PURPLE: 'CommonBuffId' = 152385 - OBJECT_VANITY_MAKEUP_CLEAR_EYE_SHADOW: 'CommonBuffId' = 152603 - OBJECT_VANITY_MAKEUP_CLEAR_LIP_STICK: 'CommonBuffId' = 152604 - OBJECT_VANITY_MAKE_UP_APPLIED_BEIGE_EYES_DARK_RED_LIPS: 'CommonBuffId' = 151970 - OBJECT_VANITY_MAKE_UP_APPLIED_BEIGE_EYES_RED_LIPS: 'CommonBuffId' = 151971 - OBJECT_VANITY_MAKE_UP_APPLIED_BLACK_CAT_EYES: 'CommonBuffId' = 151981 - OBJECT_VANITY_MAKE_UP_APPLIED_BLACK_EYELINER_CORAL_LIPS: 'CommonBuffId' = 151987 - OBJECT_VANITY_MAKE_UP_APPLIED_BLACK_EYELINER_SATIN_PINK_LIPS: 'CommonBuffId' = 151984 - OBJECT_VANITY_MAKE_UP_APPLIED_BLACK_EYES: 'CommonBuffId' = 151983 - OBJECT_VANITY_MAKE_UP_APPLIED_BLACK_EYES_GLOSSY_ORANGE_LIPS: 'CommonBuffId' = 152010 - OBJECT_VANITY_MAKE_UP_APPLIED_BLACK_EYES_PINK_LIPS: 'CommonBuffId' = 152011 - OBJECT_VANITY_MAKE_UP_APPLIED_BLACK_EYES_SATIN_BLACK_LIPS: 'CommonBuffId' = 151982 - OBJECT_VANITY_MAKE_UP_APPLIED_BLUE_BLUE_EYES_PINK_LIPS: 'CommonBuffId' = 151994 - OBJECT_VANITY_MAKE_UP_APPLIED_BLUE_EYES_GLOSSY_BLUE_LIPS: 'CommonBuffId' = 151993 - OBJECT_VANITY_MAKE_UP_APPLIED_BLUE_EYES_GLOSSY_PINK_LIPS: 'CommonBuffId' = 151996 - OBJECT_VANITY_MAKE_UP_APPLIED_BLUE_EYES_GLOSSY_VIOLET_LIPS: 'CommonBuffId' = 151997 - OBJECT_VANITY_MAKE_UP_APPLIED_BLUE_EYES_PINK_LIPS: 'CommonBuffId' = 151992 - OBJECT_VANITY_MAKE_UP_APPLIED_BLUE_EYES_RED_LIPS: 'CommonBuffId' = 151995 - OBJECT_VANITY_MAKE_UP_APPLIED_BLUE_EYES_ROSE_LIPS: 'CommonBuffId' = 151999 - OBJECT_VANITY_MAKE_UP_APPLIED_BLUE_EYES_SATIN_BRONZE_LIPS: 'CommonBuffId' = 151998 - OBJECT_VANITY_MAKE_UP_APPLIED_BRONZE_EYES_GLOSSY_RED_LIPS: 'CommonBuffId' = 151973 - OBJECT_VANITY_MAKE_UP_APPLIED_BROWN_EYES: 'CommonBuffId' = 152003 - OBJECT_VANITY_MAKE_UP_APPLIED_BROWN_EYES_CORAL_LIPS: 'CommonBuffId' = 152006 - OBJECT_VANITY_MAKE_UP_APPLIED_BROWN_EYES_PINK_LIPS: 'CommonBuffId' = 152005 - OBJECT_VANITY_MAKE_UP_APPLIED_BROWN_EYES_ROSE_LIPS: 'CommonBuffId' = 152007 - OBJECT_VANITY_MAKE_UP_APPLIED_BROWN_EYES_SATIN_RED_LIPS: 'CommonBuffId' = 152008 - OBJECT_VANITY_MAKE_UP_APPLIED_GOLD_EYES_GLOSSY_RED_LIPS: 'CommonBuffId' = 152009 - OBJECT_VANITY_MAKE_UP_APPLIED_GOTH_BLACK_EYES_SATIN_BLACK_LIPS: 'CommonBuffId' = 151986 - OBJECT_VANITY_MAKE_UP_APPLIED_GOTH_BLACK_EYES_SATIN_RED_LIPS: 'CommonBuffId' = 151988 - OBJECT_VANITY_MAKE_UP_APPLIED_GRAY_BROWN_EYES_CORAL_LIPS: 'CommonBuffId' = 152004 - OBJECT_VANITY_MAKE_UP_APPLIED_GRAY_EYES_CORAL_LIPS: 'CommonBuffId' = 151974 - OBJECT_VANITY_MAKE_UP_APPLIED_GRAY_EYES_RED_LIPS: 'CommonBuffId' = 152012 - OBJECT_VANITY_MAKE_UP_APPLIED_GREEN_EYES_BRONZE_LIPS: 'CommonBuffId' = 152016 - OBJECT_VANITY_MAKE_UP_APPLIED_GREEN_EYES_GLOSSY_RED_LIPS: 'CommonBuffId' = 152014 - OBJECT_VANITY_MAKE_UP_APPLIED_GREEN_EYES_RED_LIPS: 'CommonBuffId' = 152015 - OBJECT_VANITY_MAKE_UP_APPLIED_GREEN_EYES_SATIN_CORAL_LIPS: 'CommonBuffId' = 152018 - OBJECT_VANITY_MAKE_UP_APPLIED_GREEN_EYES_SATIN_PINK_LIPS: 'CommonBuffId' = 152017 - OBJECT_VANITY_MAKE_UP_APPLIED_GREY_EYES_GLOSSY_RED_LIPS: 'CommonBuffId' = 151985 - OBJECT_VANITY_MAKE_UP_APPLIED_MAGENTA_EYES_RED_LIPS: 'CommonBuffId' = 152019 - OBJECT_VANITY_MAKE_UP_APPLIED_MAUVE_EYES_CORAL_LIPS: 'CommonBuffId' = 151975 - OBJECT_VANITY_MAKE_UP_APPLIED_MAUVE_EYES_GLOSSY_CORAL_LIPS: 'CommonBuffId' = 152020 - OBJECT_VANITY_MAKE_UP_APPLIED_PINK_EYES_GLOSSY_CORAL_LIPS: 'CommonBuffId' = 152022 - OBJECT_VANITY_MAKE_UP_APPLIED_PLUM_EYES_SATIN_RED_LIPS: 'CommonBuffId' = 152023 - OBJECT_VANITY_MAKE_UP_APPLIED_PURPLE_EYES_SATIN_VIOLET_LIPS: 'CommonBuffId' = 152021 - OBJECT_VANITY_MAKE_UP_APPLIED_RED_EYES: 'CommonBuffId' = 152024 - OBJECT_VANITY_MAKE_UP_APPLIED_SILVER_BLUE_ROSE_LIPS: 'CommonBuffId' = 151990 - OBJECT_VANITY_MAKE_UP_APPLIED_SILVER_BLUE_SATIN_BLUE_LIPS: 'CommonBuffId' = 151989 - OBJECT_VANITY_MAKE_UP_APPLIED_SILVER_BLUE_SATIN_RED_LIPS: 'CommonBuffId' = 151972 - OBJECT_VANITY_MAKE_UP_APPLIED_SILVER_BROWN_SATIN_BEIGE_LIPS: 'CommonBuffId' = 152000 - OBJECT_VANITY_MAKE_UP_APPLIED_SILVER_BROWN_SATIN_RED_LIPS: 'CommonBuffId' = 152002 - OBJECT_VANITY_MAKE_UP_APPLIED_SILVER_GREEN_SATIN_CORAL_LIPS: 'CommonBuffId' = 152013 - OBJECT_VANITY_MAKE_UP_APPLIED_SILVER_SATIN_BRONZE_LIPS: 'CommonBuffId' = 151980 - OBJECT_VANITY_MAKE_UP_APPLIED_SLIVER_PINK_PINK_LIPS: 'CommonBuffId' = 152001 - OBJECT_VANITY_MAKE_UP_APPLIED_THICK_BLACK_EYELINER: 'CommonBuffId' = 151976 - OBJECT_VANITY_MAKE_UP_APPLIED_TURQUOISE_EYES_CORAL_LIPS: 'CommonBuffId' = 151977 - OBJECT_VANITY_MAKE_UP_APPLIED_TURQUOISE_EYES_ROSE_LIPS: 'CommonBuffId' = 151978 - OBJECT_VANITY_MAKE_UP_APPLIED_TURQUOISE_EYES_SATIN_RED_LIPS: 'CommonBuffId' = 151991 - OBJECT_VANITY_MAKE_UP_APPLIED_VIOLET_EYES_RED_LIPS: 'CommonBuffId' = 151979 - OBJECT_VANITY_MAKE_UP_CLEAR_BLUSH: 'CommonBuffId' = 152600 - OBJECT_VANITY_MAKE_UP_CLEAR_EYELINER: 'CommonBuffId' = 152601 - OBJECT_VANITY_OOPS: 'CommonBuffId' = 145346 - OBJECT_VANITY_OOPS_BLUE: 'CommonBuffId' = 152377 - OBJECT_VANITY_OOPS_PINK: 'CommonBuffId' = 152378 - OBJECT_VANITY_OOPS_PURPLE: 'CommonBuffId' = 152379 - OBJECT_VANITY_OOPS_RED: 'CommonBuffId' = 152380 - OBJECT_VERTICAL_GARDEN_MEAT_WALL_SQUEAMISH: 'CommonBuffId' = 237753 - OBJECT_VERTICAL_GARDEN_MEAT_WALL_VEGETARIAN: 'CommonBuffId' = 237754 - OBJECT_VET_MEDICINE_STATION_CALMING_AGENT: 'CommonBuffId' = 171734 - OBJECT_VET_MEDICINE_STATION_RELAXATION_SERUM: 'CommonBuffId' = 171575 - OBJECT_VET_MEDICINE_STATION_REQUEST_CRAFTING_AGE_DOWN_TREAT: 'CommonBuffId' = 172311 - OBJECT_VET_MEDICINE_STATION_REQUEST_CRAFTING_AGE_UP_TREAT: 'CommonBuffId' = 172312 - OBJECT_VET_MEDICINE_STATION_REQUEST_CRAFTING_AMBROSIA_TREAT: 'CommonBuffId' = 172350 - OBJECT_VET_MEDICINE_STATION_REQUEST_CRAFTING_CALMING_AGENT: 'CommonBuffId' = 172304 - OBJECT_VET_MEDICINE_STATION_REQUEST_CRAFTING_RELAXATION_SERUM: 'CommonBuffId' = 172136 - OBJECT_VET_MEDICINE_STATION_REQUEST_CRAFTING_SICKNESS_TREAT_1: 'CommonBuffId' = 172306 - OBJECT_VET_MEDICINE_STATION_REQUEST_CRAFTING_SICKNESS_TREAT_2: 'CommonBuffId' = 172307 - OBJECT_VET_MEDICINE_STATION_REQUEST_CRAFTING_SICKNESS_TREAT_3: 'CommonBuffId' = 172308 - OBJECT_VET_MEDICINE_STATION_REQUEST_CRAFTING_SICKNESS_TREAT_4: 'CommonBuffId' = 172309 - OBJECT_VET_MEDICINE_STATION_REQUEST_CRAFTING_SICKNESS_TREAT_5: 'CommonBuffId' = 172310 - OBJECT_VET_MEDICINE_STATION_REQUEST_CRAFTING_SIMULATION_GEL: 'CommonBuffId' = 172303 - OBJECT_VET_MEDICINE_STATION_REQUEST_CRAFTING_WELLNESS_TREAT: 'CommonBuffId' = 172305 - OBJECT_VET_MEDICINE_STATION_SIMULATION_GEL: 'CommonBuffId' = 171749 - OBJECT_VIDEO_STATION_POST_UPDATE_COOLDOWN: 'CommonBuffId' = 192565 - OBJECT_VIDEO_STATION_POST_UPDATE_HYPE: 'CommonBuffId' = 192571 - OBJECT_VIDEO_STATION_STUDY_TRENDS: 'CommonBuffId' = 192549 - OBJECT_VIDEO_STATION_STUDY_TRENDS_COOLDOWN: 'CommonBuffId' = 199057 - OBJECT_VIOLIN_SCINTILLATING_STRINGS: 'CommonBuffId' = 36971 - OBJECT_VIOLIN_SOOTHING_STRINGS: 'CommonBuffId' = 34550 - OBJECT_WATER_SCOOTER_TRICKS: 'CommonBuffId' = 204840 - OBJECT_WILD_GRASS_CUTS: 'CommonBuffId' = 326663 - OBJECT_WILD_GRASS_HARVEST_BAD: 'CommonBuffId' = 326661 - OBJECT_WILD_GRASS_HARVEST_GOOD: 'CommonBuffId' = 326662 - OBJECT_WIND_CHIMES_SOUNDS_OF_THE_WINDS: 'CommonBuffId' = 141182 - OBJECT_WIND_CHIME_ANNOYING_CHIMES: 'CommonBuffId' = 143521 - OBJECT_WIND_CHIME_SOOTHING_CHIMES: 'CommonBuffId' = 143520 - OBJECT_WIND_CHIME_WOKEN_UP: 'CommonBuffId' = 190422 - OBJECT_WOOHOO_IN_PROGRESS_HIDDEN: 'CommonBuffId' = 156207 - OBJECT_XRAY_MACHINE_LASER_PRECISION: 'CommonBuffId' = 105798 - OBJECT_YOGA_MAT_CENTERED_AND_FOCUSED: 'CommonBuffId' = 117439 - OBJECT_YOGA_MAT_CENTERED_AND_FOCUSED_INCENSE: 'CommonBuffId' = 118925 - OBJECT_YOGA_MAT_CENTERED_AND_FOCUSED_YOGA_CLASS: 'CommonBuffId' = 118665 - OBJECT_YOGA_MAT_CHILD_FRIENDLY_CHILD: 'CommonBuffId' = 271117 - OBJECT_YOGA_MAT_CHILD_FRIENDLY_CHILD_INCENSE: 'CommonBuffId' = 271118 - OBJECT_YOGA_MAT_CHILD_FRIENDLY_CHILD_YOGA_CLASS: 'CommonBuffId' = 271119 - OBJECT_YOGA_MAT_CHILD_FRIENDLY_TYAE: 'CommonBuffId' = 271122 - OBJECT_YOGA_MAT_CHILD_FRIENDLY_TYAE_INCENSE: 'CommonBuffId' = 271123 - OBJECT_YOGA_MAT_CHILD_FRIENDLY_TYAE_YOGA_CLASS: 'CommonBuffId' = 271124 - OBJECT_YOGA_MAT_CHILD_POSE_BOAT: 'CommonBuffId' = 271327 - OBJECT_YOGA_MAT_CHILD_POSE_DOWNWARD_DOG: 'CommonBuffId' = 271189 - OBJECT_YOGA_MAT_CHILD_POSE_HALF_MOON: 'CommonBuffId' = 271200 - OBJECT_YOGA_MAT_CHILD_POSE_TREE: 'CommonBuffId' = 271190 - OBJECT_YOGA_MAT_IMPROVED_POSING: 'CommonBuffId' = 117441 - OBJECT_YOGA_MAT_IMPROVED_POSING_INCENSE: 'CommonBuffId' = 118929 - OBJECT_YOGA_MAT_SENSES_BOOSTED: 'CommonBuffId' = 117437 - OBJECT_YOGA_MAT_SENSES_BOOSTED_INCENSE: 'CommonBuffId' = 118924 - OBJECT_YOGA_MAT_SENSES_BOOSTED_YOGA_CLASS: 'CommonBuffId' = 118667 - OBJECT_YOGA_MAT_YOGA_BLISS: 'CommonBuffId' = 117440 - OBJECT_YOGA_MAT_YOGA_BLISS_INCENSE: 'CommonBuffId' = 118928 - OBJECT_YOGA_MAT_YOGIC_INSPIRATION: 'CommonBuffId' = 117438 - OBJECT_YOGA_MAT_YOGIC_INSPIRATION_INCENSE: 'CommonBuffId' = 118923 - OBJECT_YOGA_MAT_YOGIC_INSPIRATION_YOGA_CLASS: 'CommonBuffId' = 118669 - OCEAN_LADDER_CANNONBALL: 'CommonBuffId' = 211982 - OCEAN_LADDER_CLIMB: 'CommonBuffId' = 213431 - OCEAN_LADDER_JUMP: 'CommonBuffId' = 211984 - OCEAN_LADDER_SWAN_DIVE: 'CommonBuffId' = 211983 - OCEAN_SWIMMING_BASE_GAME_REACTIONS_LOST_YOUR_SUIT: 'CommonBuffId' = 211409 - OCEAN_SWIMMING_BASE_GAME_REACTIONS_SPLASHED: 'CommonBuffId' = 211352 - OCEAN_SWIMMING_BASE_GAME_REACTIONS_SUDDEN_CHILL: 'CommonBuffId' = 206442 - OCEAN_SWIMMING_BASE_GAME_REACTIONS_SUDDEN_CHILL_BLUE_TONE: 'CommonBuffId' = 211904 - OCEAN_SWIMMING_BASE_GAME_REACTIONS_SWIMMING_CRAMP: 'CommonBuffId' = 206439 - OCEAN_SWIMMING_BASE_GAME_REACTIONS_SWIMMING_CRAMP_JUST_ATE: 'CommonBuffId' = 212335 - OCEAN_SWIMMING_BASE_GAME_REACTIONS_THALASSOPHOBIA: 'CommonBuffId' = 206441 - OCEAN_SWIMMING_BASE_GAME_REACTION_SPLASHY_FUN: 'CommonBuffId' = 214463 - OCEAN_SWIMMING_BASE_GAME_REACTION_THALASSOPHOBIA: 'CommonBuffId' = 212330 - OCEAN_SWIMMING_BASE_GAME_REACTION_TRIGGER_COOLDOWN_NEGATIVE_BUFFS: 'CommonBuffId' = 212333 - OCEAN_SWIMMING_BASE_GAME_REACTION_TRIGGER_LOST_YOUR_SUIT: 'CommonBuffId' = 211346 - OCEAN_SWIMMING_BASE_GAME_REACTION_TRIGGER_SPLASHED: 'CommonBuffId' = 211350 - OCEAN_SWIMMING_BASE_GAME_REACTION_TRIGGER_SUDDEN_CHILL: 'CommonBuffId' = 211348 - OCEAN_SWIMMING_BASE_GAME_REACTION_TRIGGER_SUDDEN_CHILL_WADE: 'CommonBuffId' = 212692 - OCEAN_SWIMMING_BASE_GAME_REACTION_TRIGGER_SWIMMING_CRAMP: 'CommonBuffId' = 211345 - OCEAN_SWIMMING_BASE_GAME_REACTION_TRIGGER_THALASSOPHOBIA: 'CommonBuffId' = 211347 - OCEAN_SWIMMING_BASE_GAME_REACTION_TRIGGER_THALASSOPHOBIA_WADE: 'CommonBuffId' = 212344 - OCEAN_SWIMMING_BASE_GAME_REACTION_WAVE_TAG: 'CommonBuffId' = 212460 - OCEAN_SWIMMING_BASE_GAME_WAVE_TAG_AUTONOMY: 'CommonBuffId' = 215262 - OCEAN_SWIMMING_REACTIONS_CAUGHT_IN_CURRENT: 'CommonBuffId' = 205894 - OCEAN_SWIMMING_REACTIONS_PULLED_UNDER: 'CommonBuffId' = 205875 - OCEAN_SWIMMING_REACTIONS_SHARK_SIGHTING: 'CommonBuffId' = 205874 - OCEAN_SWIMMING_REACTIONS_SHARK_SIGHTING_POSITIVE: 'CommonBuffId' = 212310 - OCEAN_SWIMMING_REACTIONS_SLIMED: 'CommonBuffId' = 205900 - OCEAN_SWIMMING_REACTIONS_STUNG_BY_SOMETHING: 'CommonBuffId' = 205842 - OCEAN_SWIMMING_REACTIONS_STUNNING_VIEW: 'CommonBuffId' = 205898 - OCEAN_SWIMMING_REACTIONS_SWALLOWED_WATER: 'CommonBuffId' = 211393 - OCEAN_SWIMMING_REACTIONS_TICKLED_BY_OCEAN: 'CommonBuffId' = 205899 - OCEAN_SWIMMING_REACTION_TRIGGER_SHARK_SIGHTING: 'CommonBuffId' = 211245 - OCEAN_SWIMMING_REACTION_TRIGGER_SLIMED: 'CommonBuffId' = 211246 - OCEAN_SWIMMING_REACTION_TRIGGER_SLIMED_TRASH: 'CommonBuffId' = 215083 - OCEAN_SWIMMING_REACTION_TRIGGER_STUNG_BY_SOMETHING: 'CommonBuffId' = 211219 - OCEAN_SWIMMING_REACTION_TRIGGER_STUNNING_VIEW: 'CommonBuffId' = 211248 - OCEAN_SWIMMING_REACTION_TRIGGER_SWALLOWED_WATER: 'CommonBuffId' = 211252 - OCEAN_SWIMMING_REACTION_TRIGGER_TICKLED_BY_OCEAN: 'CommonBuffId' = 211249 - OCEAN_SWIMMING_SPLASHED_BROADCASTER: 'CommonBuffId' = 212503 - OFFER_GRATITUDE_MINDED_MY_MANNERS: 'CommonBuffId' = 160892 - OFFER_GRATITUDE_SUCH_GOOD_MANNERS: 'CommonBuffId' = 160890 - OFF_LOT_AUTONOMY_MOD_ALL: 'CommonBuffId' = 40411 - OFF_LOT_AUTONOMY_MOD_DEFAULT: 'CommonBuffId' = 130248 - OFF_LOT_AUTONOMY_MOD_OFF_LOT_ONLY: 'CommonBuffId' = 38293 - OFF_LOT_AUTONOMY_MOD_OFF_LOT_ONLY_CAMPFIRE: 'CommonBuffId' = 112081 - OFF_LOT_AUTONOMY_MOD_OFF_LOT_ONLY_GO_DANCING: 'CommonBuffId' = 126871 - OFF_LOT_AUTONOMY_MOD_ON_LOT_ONLY: 'CommonBuffId' = 38292 - OFF_LOT_AUTONOMY_MOD_ON_LOT_ONLY_ANCHORED_SPA: 'CommonBuffId' = 122390 - OFF_LOT_AUTONOMY_MOD_ON_LOT_ONLY_DJ_NPC: 'CommonBuffId' = 127027 - OFF_LOT_AUTONOMY_MOD_ON_LOT_ONLY_GO_DANCING: 'CommonBuffId' = 126872 - OFF_LOT_AUTONOMY_MOD_ON_LOT_ONLY_GRILL_MASTER: 'CommonBuffId' = 105939 - OFF_LOT_AUTONOMY_MOD_RESTRICTED: 'CommonBuffId' = 135730 - OFF_LOT_AUTONOMY_MOD_SHARED_SPACE_ONLY: 'CommonBuffId' = 349229 - OFF_THE_GRID_BRACKISH_WATER: 'CommonBuffId' = 212112 - ONIBI_STRONG_BUFFS_COLLECT_BLUE: 'CommonBuffId' = 251350 - ONIBI_STRONG_BUFFS_COLLECT_GREEN: 'CommonBuffId' = 251351 - ONIBI_STRONG_BUFFS_COLLECT_RED_ORANGE: 'CommonBuffId' = 251352 - ONIBI_STRONG_BUFFS_COLLECT_WHITE: 'CommonBuffId' = 251353 - ONIBI_STRONG_BUFFS_COLLECT_YELLOW: 'CommonBuffId' = 251354 - ONIBI_STRONG_BUFFS_WISH_BLUE: 'CommonBuffId' = 251338 - ONIBI_STRONG_BUFFS_WISH_GREEN: 'CommonBuffId' = 251339 - ONIBI_STRONG_BUFFS_WISH_RED_ORANGE: 'CommonBuffId' = 251340 - ONIBI_STRONG_BUFFS_WISH_WHITE: 'CommonBuffId' = 251341 - ONIBI_STRONG_BUFFS_WISH_YELLOW: 'CommonBuffId' = 251342 - ONIBI_WEAK_BUFFS_COLLECT_BLUE: 'CommonBuffId' = 251333 - ONIBI_WEAK_BUFFS_COLLECT_GREEN: 'CommonBuffId' = 251337 - ONIBI_WEAK_BUFFS_COLLECT_RED_ORANGE: 'CommonBuffId' = 251335 - ONIBI_WEAK_BUFFS_COLLECT_WHITE: 'CommonBuffId' = 251334 - ONIBI_WEAK_BUFFS_COLLECT_YELLOW: 'CommonBuffId' = 251336 - ONIBI_WEAK_BUFFS_WISH_BLUE: 'CommonBuffId' = 251343 - ONIBI_WEAK_BUFFS_WISH_GREEN: 'CommonBuffId' = 251344 - ONIBI_WEAK_BUFFS_WISH_RED_ORANGE: 'CommonBuffId' = 251345 - ONIBI_WEAK_BUFFS_WISH_WHITE: 'CommonBuffId' = 251346 - ONIBI_WEAK_BUFFS_WISH_YELLOW: 'CommonBuffId' = 251347 - ON_FOREIGN_LOT: 'CommonBuffId' = 12554 - OPENABLE_WINDOW_ACCEPTED_EVENT_COLLEGE_PARTY: 'CommonBuffId' = 282992 - OPENABLE_WINDOW_ACCEPTED_EVENT_HANGOUT: 'CommonBuffId' = 283416 - OPENABLE_WINDOW_ACCEPTED_EVENT_LOITERING: 'CommonBuffId' = 283415 - OPENABLE_WINDOW_ACCEPTED_EVENT_POP_CONCERT: 'CommonBuffId' = 283414 - OPENABLE_WINDOW_ACCEPTED_EVENT_R_MOVIE: 'CommonBuffId' = 283413 - OPENABLE_WINDOW_ACCEPTED_EVENT_SCHOOL_GAME: 'CommonBuffId' = 283412 - OPENABLE_WINDOW_ACCEPTED_EVENT_SLEEPOVER: 'CommonBuffId' = 283411 - OPENABLE_WINDOW_CAUGHT: 'CommonBuffId' = 283442 - OPENABLE_WINDOW_CLEARED_TO_GO: 'CommonBuffId' = 283017 - OPENABLE_WINDOW_CLEARED_TO_GO_AT_EVENT_HIDDEN: 'CommonBuffId' = 290386 - OPENABLE_WINDOW_COLLEGE_PARTY_NO_PARTY_COOLDOWN: 'CommonBuffId' = 373590 - OPENABLE_WINDOW_COLLEGE_PARTY_TRIGGER_COOLDOWN: 'CommonBuffId' = 373479 - OPENABLE_WINDOW_EVENT_OUTCOME_COLLEGE_PARTY_FAIL: 'CommonBuffId' = 283053 - OPENABLE_WINDOW_EVENT_OUTCOME_COLLEGE_PARTY_SUCCESS: 'CommonBuffId' = 283052 - OPENABLE_WINDOW_EVENT_OUTCOME_HANG_OUT_FAIL: 'CommonBuffId' = 283208 - OPENABLE_WINDOW_EVENT_OUTCOME_LOITERING_FAIL: 'CommonBuffId' = 283207 - OPENABLE_WINDOW_EVENT_OUTCOME_POP_CONCERT_FAIL: 'CommonBuffId' = 283204 - OPENABLE_WINDOW_EVENT_OUTCOME_POP_CONCERT_SUCCESS: 'CommonBuffId' = 283205 - OPENABLE_WINDOW_EVENT_OUTCOME_R_MOVIE_FAIL: 'CommonBuffId' = 283202 - OPENABLE_WINDOW_EVENT_OUTCOME_R_MOVIE_SUCCESS: 'CommonBuffId' = 283203 - OPENABLE_WINDOW_EVENT_OUTCOME_SCHOOL_GAME_FAIL: 'CommonBuffId' = 283210 - OPENABLE_WINDOW_EVENT_OUTCOME_SCHOOL_GAME_SUCCESS: 'CommonBuffId' = 283211 - OPENABLE_WINDOW_EVENT_OUTCOME_SLEEPOVER_FAIL: 'CommonBuffId' = 283206 - OPENABLE_WINDOW_EVENT_OUTCOME_WITH_FRIENDS_SUCCESS: 'CommonBuffId' = 283209 - OPENABLE_WINDOW_ROUTING_TO_EVENT_NOT_SNEAKING: 'CommonBuffId' = 283016 - OPENABLE_WINDOW_ROUTING_TO_EVENT_SNEAKING: 'CommonBuffId' = 283015 - OPENABLE_WINDOW_SNEAKING_BACK_IN_HIDDEN: 'CommonBuffId' = 290380 - OPENABLE_WINDOW_SNEAK_SUCCESSFUL: 'CommonBuffId' = 283441 - OPENABLE_WINDOW_TEMPORARY_WINDOW_ACCESS: 'CommonBuffId' = 283859 - OPEN_STREET_COTTAGE_WORLD_PICNICKER_CREATE_FOOD_COOLDOWN: 'CommonBuffId' = 265785 - OPEN_STREET_COTTAGE_WORLD_WANDERER_ATTRACTED_BEHAVIOR_WOODS: 'CommonBuffId' = 264536 - OPEN_STREET_COTTAGE_WORLD_WANDERER_FISH: 'CommonBuffId' = 263666 - OPEN_STREET_COTTAGE_WORLD_WANDERER_GARDEN: 'CommonBuffId' = 263667 - OPEN_STREET_COTTAGE_WORLD_WANDERER_SOCIALIZE: 'CommonBuffId' = 263764 - OPEN_STREET_COTTAGE_WORLD_WANDERER_SWIM: 'CommonBuffId' = 263663 - ORGANIZATIONS_ACTIVATE_CHEATS: 'CommonBuffId' = 225545 - ORRERY_FOCUSED: 'CommonBuffId' = 109869 - OUTSIDE_CHECK: 'CommonBuffId' = 76778 - OUTSIDE_CHECK_CURRENTLY_INSIDE: 'CommonBuffId' = 76781 - OUTSIDE_CHECK_CURRENTLY_OUTSIDE: 'CommonBuffId' = 76780 - OWNABLE_BUSINESS_CUSTOMER_ENVIRONMENT_ALREADY_APPLIED_LOOT: 'CommonBuffId' = 143387 - OWNABLE_BUSINESS_CUSTOMER_ENVIRONMENT_BAD_INSTRUMENT_PLAYING: 'CommonBuffId' = 143309 - OWNABLE_BUSINESS_CUSTOMER_ENVIRONMENT_BAD_SURROUNDINGS: 'CommonBuffId' = 143313 - OWNABLE_BUSINESS_CUSTOMER_ENVIRONMENT_BEAUTIFULLY_DECORATED: 'CommonBuffId' = 143312 - OWNABLE_BUSINESS_CUSTOMER_ENVIRONMENT_DECORATED: 'CommonBuffId' = 143311 - OWNABLE_BUSINESS_CUSTOMER_ENVIRONMENT_GOOD_MUSIC: 'CommonBuffId' = 143307 - OWNABLE_BUSINESS_CUSTOMER_ENVIRONMENT_NEAR_HEAT_SOURCE: 'CommonBuffId' = 143308 - OWNABLE_BUSINESS_CUSTOMER_ENVIRONMENT_NICELY_DECORATED: 'CommonBuffId' = 143310 - OWNABLE_BUSINESS_CUSTOMER_ENVIRONMENT_STEREO_MUSIC: 'CommonBuffId' = 143316 - OWNABLE_BUSINESS_CUSTOMER_ENVIRONMENT_UNPLEASANT_SURROUNDINGS: 'CommonBuffId' = 143314 - OWNABLE_BUSINESS_CUSTOMER_ENVIRONMENT_WRETCHED_SURROUNDINGS: 'CommonBuffId' = 143315 - OWNABLE_BUSINESS_EMPLOYEE_CHECK_UP_ON: 'CommonBuffId' = 137599 - OWNABLE_BUSINESS_EMPLOYEE_CRITICIZED: 'CommonBuffId' = 136969 - OWNABLE_BUSINESS_EMPLOYEE_EXHAUSTED: 'CommonBuffId' = 137104 - OWNABLE_BUSINESS_EMPLOYEE_EXHAUSTED_QUIT: 'CommonBuffId' = 142993 - OWNABLE_BUSINESS_EMPLOYEE_FIRED: 'CommonBuffId' = 136963 - OWNABLE_BUSINESS_EMPLOYEE_INSPIRED: 'CommonBuffId' = 136968 - OWNABLE_BUSINESS_EMPLOYEE_PRAISED: 'CommonBuffId' = 136967 - OWNABLE_BUSINESS_EMPLOYEE_QUIT_COOLDOWN: 'CommonBuffId' = 174471 - OWNABLE_BUSINESS_EMPLOYEE_SATISFACTION_MODIFIERS_PAY_0_PAID_ADEQUATELY: 'CommonBuffId' = 137167 - OWNABLE_BUSINESS_EMPLOYEE_SATISFACTION_MODIFIERS_PAY_MINU_S1_UNDERPAID: 'CommonBuffId' = 137158 - OWNABLE_BUSINESS_EMPLOYEE_SATISFACTION_MODIFIERS_PAY_MINU_S2_VERY_UNDERPAID: 'CommonBuffId' = 137159 - OWNABLE_BUSINESS_EMPLOYEE_SATISFACTION_MODIFIERS_PAY_MINU_S3_SEVERELY_UNDERPAID: 'CommonBuffId' = 137160 - OWNABLE_BUSINESS_EMPLOYEE_SATISFACTION_MODIFIERS_PAY_MINU_S4_GROSSLY_UNDERPAID: 'CommonBuffId' = 137161 - OWNABLE_BUSINESS_EMPLOYEE_SATISFACTION_MODIFIERS_PAY_PLU_S1_OVERPAID: 'CommonBuffId' = 137163 - OWNABLE_BUSINESS_EMPLOYEE_SATISFACTION_MODIFIERS_PAY_PLU_S2_VERY_OVERPAID: 'CommonBuffId' = 137164 - OWNABLE_BUSINESS_EMPLOYEE_SATISFACTION_MODIFIERS_PAY_PLU_S3_SEVERELY_OVERPAID: 'CommonBuffId' = 137165 - OWNABLE_BUSINESS_EMPLOYEE_SATISFACTION_MODIFIERS_PAY_PLU_S4_GROSSLY_OVERPAID: 'CommonBuffId' = 137166 - OWNABLE_BUSINESS_EMPLOYEE_SATISFACTION_STATES_NEUTRAL: 'CommonBuffId' = 137171 - OWNABLE_BUSINESS_EMPLOYEE_SATISFACTION_STATES_SATISFIED: 'CommonBuffId' = 137172 - OWNABLE_BUSINESS_EMPLOYEE_SATISFACTION_STATES_UNSATISFIED: 'CommonBuffId' = 137173 - OWNABLE_BUSINESS_EMPLOYEE_SATISFACTION_STATES_VERY_SATISFIED: 'CommonBuffId' = 137174 - OWNABLE_BUSINESS_EMPLOYEE_SATISFACTION_STATES_VERY_UNSATISFIED: 'CommonBuffId' = 137175 - OWNABLE_BUSINESS_EMPLOYEE_TRAINING_BRIEF: 'CommonBuffId' = 138007 - OWNABLE_BUSINESS_EMPLOYEE_TRAINING_EXTENSIVE: 'CommonBuffId' = 138008 - OWNABLE_BUSINESS_EMPLOYEE_TRAINING_STANDARD: 'CommonBuffId' = 138009 - OWNABLE_BUSINESS_EMPLOYEE_TRAINING_SUPPRESS_BACKUP: 'CommonBuffId' = 143662 - OWNABLE_BUSINESS_RESTAURANT_ALLOW_EATING: 'CommonBuffId' = 144204 - OWNABLE_RESTAURANT_DRINK_QUALITY_AMAZING: 'CommonBuffId' = 143109 - OWNABLE_RESTAURANT_DRINK_QUALITY_GOOD: 'CommonBuffId' = 143110 - OWNABLE_RESTAURANT_DRINK_QUALITY_GREAT: 'CommonBuffId' = 143111 - OWNABLE_RESTAURANT_DRINK_QUALITY_POOR: 'CommonBuffId' = 143112 - OWNABLE_RESTAURANT_DRINK_QUALITY_TERRIBLE: 'CommonBuffId' = 143113 - OWNABLE_RESTAURANT_DRINK_VALUE_AMAZING: 'CommonBuffId' = 143115 - OWNABLE_RESTAURANT_DRINK_VALUE_GOOD: 'CommonBuffId' = 143116 - OWNABLE_RESTAURANT_DRINK_VALUE_GREAT: 'CommonBuffId' = 143117 - OWNABLE_RESTAURANT_DRINK_VALUE_POOR: 'CommonBuffId' = 143118 - OWNABLE_RESTAURANT_DRINK_VALUE_TERRIBLE: 'CommonBuffId' = 143119 - OWNABLE_RESTAURANT_EMPLOYEE_CHEF_COOK_STYLE_CAREFUL: 'CommonBuffId' = 137888 - OWNABLE_RESTAURANT_EMPLOYEE_CHEF_COOK_STYLE_NORMAL: 'CommonBuffId' = 137887 - OWNABLE_RESTAURANT_EMPLOYEE_CHEF_COOK_STYLE_QUICK: 'CommonBuffId' = 137889 - OWNABLE_RESTAURANT_EMPLOYEE_SKILL_GAIN_HIGH_BARTENDING: 'CommonBuffId' = 143428 - OWNABLE_RESTAURANT_EMPLOYEE_SKILL_GAIN_HIGH_CHARISMA: 'CommonBuffId' = 143432 - OWNABLE_RESTAURANT_EMPLOYEE_SKILL_GAIN_HIGH_COMEDY: 'CommonBuffId' = 143433 - OWNABLE_RESTAURANT_EMPLOYEE_SKILL_GAIN_HIGH_FITNESS: 'CommonBuffId' = 143431 - OWNABLE_RESTAURANT_EMPLOYEE_SKILL_GAIN_HIGH_GOURMET: 'CommonBuffId' = 143429 - OWNABLE_RESTAURANT_EMPLOYEE_SKILL_GAIN_LOW_BARTENDING: 'CommonBuffId' = 143441 - OWNABLE_RESTAURANT_EMPLOYEE_SKILL_GAIN_LOW_CHARISMA: 'CommonBuffId' = 143437 - OWNABLE_RESTAURANT_EMPLOYEE_SKILL_GAIN_LOW_COMEDY: 'CommonBuffId' = 143438 - OWNABLE_RESTAURANT_EMPLOYEE_SKILL_GAIN_LOW_FITNESS: 'CommonBuffId' = 143439 - OWNABLE_RESTAURANT_EMPLOYEE_SKILL_GAIN_LOW_GOURMET: 'CommonBuffId' = 143440 - OWNABLE_RESTAURANT_EMPLOYEE_WAITER_SPILLED_FOOD: 'CommonBuffId' = 136909 - OWNABLE_RESTAURANT_FOOD_QUALITY_AMAZING: 'CommonBuffId' = 141912 - OWNABLE_RESTAURANT_FOOD_QUALITY_GOOD: 'CommonBuffId' = 141913 - OWNABLE_RESTAURANT_FOOD_QUALITY_GREAT: 'CommonBuffId' = 141914 - OWNABLE_RESTAURANT_FOOD_QUALITY_POOR: 'CommonBuffId' = 141915 - OWNABLE_RESTAURANT_FOOD_QUALITY_TERRIBLE: 'CommonBuffId' = 141916 - OWNABLE_RESTAURANT_FOOD_VALUE_AMAZING: 'CommonBuffId' = 136744 - OWNABLE_RESTAURANT_FOOD_VALUE_GOOD: 'CommonBuffId' = 136742 - OWNABLE_RESTAURANT_FOOD_VALUE_GREAT: 'CommonBuffId' = 136743 - OWNABLE_RESTAURANT_FOOD_VALUE_POOR: 'CommonBuffId' = 136741 - OWNABLE_RESTAURANT_FOOD_VALUE_TERRIBLE: 'CommonBuffId' = 136740 - OWNABLE_RESTAURANT_HOSPITALITY_DELAY_PLACE_ORDER: 'CommonBuffId' = 143842 - OWNABLE_RESTAURANT_HOSPITALITY_DISH_RECOMMENDED: 'CommonBuffId' = 136769 - OWNABLE_RESTAURANT_HOSPITALITY_DISH_RECOMMENDED_RANDOM_CHANCE: 'CommonBuffId' = 142075 - OWNABLE_RESTAURANT_HOSPITALITY_FOOD_COMPED: 'CommonBuffId' = 136767 - OWNABLE_RESTAURANT_HOSPITALITY_FREE_DESSERT: 'CommonBuffId' = 136770 - OWNABLE_RESTAURANT_HOSPITALITY_FREE_DRINKS: 'CommonBuffId' = 136771 - OWNABLE_RESTAURANT_HOSPITALITY_GROUP_WELCOMED: 'CommonBuffId' = 143486 - OWNABLE_RESTAURANT_HOSPITALITY_HOST_GREETING_DELIGHTFUL: 'CommonBuffId' = 136884 - OWNABLE_RESTAURANT_HOSPITALITY_HOST_GREETING_PLEASANT: 'CommonBuffId' = 136883 - OWNABLE_RESTAURANT_HOSPITALITY_HOST_GREETING_RUDE: 'CommonBuffId' = 136882 - OWNABLE_RESTAURANT_HOSPITALITY_ORDER_PRIORITIZED: 'CommonBuffId' = 143137 - OWNABLE_RESTAURANT_HOSPITALITY_TABLE_CHECKED_ON: 'CommonBuffId' = 136768 - OWNABLE_RESTAURANT_HOSPITALITY_WAITER_SERVICE_BAD: 'CommonBuffId' = 136887 - OWNABLE_RESTAURANT_HOSPITALITY_WAITER_SERVICE_GOOD: 'CommonBuffId' = 136889 - OWNABLE_RESTAURANT_HOSPITALITY_WAITER_SERVICE_GREAT: 'CommonBuffId' = 136888 - OWNABLE_RESTAURANT_HOSPITALITY_WANTS_DISH_RECOMMENDED: 'CommonBuffId' = 142077 - OWNABLE_RESTAURANT_PERK_LONGER_WAIT_TIME: 'CommonBuffId' = 142019 - OWNABLE_RESTAURANT_WAIT_TIME_BAD: 'CommonBuffId' = 136759 - OWNABLE_RESTAURANT_WAIT_TIME_DISGRUNTLED: 'CommonBuffId' = 136758 - OWNABLE_RESTAURANT_WAIT_TIME_GOOD: 'CommonBuffId' = 136757 - OWNABLE_RESTAURANT_WAIT_TIME_START: 'CommonBuffId' = 141602 - OWNABLE_RESTAURANT_WAIT_TIME_STOP: 'CommonBuffId' = 141910 - OWNABLE_VET_CLINIC_BEDSIDE_MANNER_DISMISS_PATIENT: 'CommonBuffId' = 178333 - OWNABLE_VET_CLINIC_BEDSIDE_MANNER_FRIENDLY_GREETING: 'CommonBuffId' = 168405 - OWNABLE_VET_CLINIC_BEDSIDE_MANNER_FRIENDLY_OWNER_SOCIAL: 'CommonBuffId' = 168408 - OWNABLE_VET_CLINIC_BEDSIDE_MANNER_FRIENDLY_PET_SOCIAL: 'CommonBuffId' = 168407 - OWNABLE_VET_CLINIC_BEDSIDE_MANNER_MEAN_GREETING: 'CommonBuffId' = 168406 - OWNABLE_VET_CLINIC_BEDSIDE_MANNER_MEAN_OWNER_SOCIAL: 'CommonBuffId' = 168410 - OWNABLE_VET_CLINIC_BEDSIDE_MANNER_MEAN_PET_SOCIAL: 'CommonBuffId' = 168409 - OWNABLE_VET_CLINIC_BEDSIDE_MANNER_NEUTRAL_GREETING: 'CommonBuffId' = 179802 - OWNABLE_VET_CLINIC_EMPLOYEE_TRAINING_BRIEF: 'CommonBuffId' = 168005 - OWNABLE_VET_CLINIC_EMPLOYEE_TRAINING_EXTENSIVE: 'CommonBuffId' = 168006 - OWNABLE_VET_CLINIC_EMPLOYEE_TRAINING_STANDARD: 'CommonBuffId' = 168007 - OWNABLE_VET_CLINIC_EMPLOYEE_TRAINING_SUPPRESS_BACKUP: 'CommonBuffId' = 168008 - OWNABLE_VET_CLINIC_PERK_LONGER_WAIT_TIME: 'CommonBuffId' = 167883 - OWNABLE_VET_CLINIC_PET_STRESS_01_AMAZING: 'CommonBuffId' = 178678 - OWNABLE_VET_CLINIC_PET_STRESS_02_GREAT: 'CommonBuffId' = 178679 - OWNABLE_VET_CLINIC_PET_STRESS_03_GOOD: 'CommonBuffId' = 178683 - OWNABLE_VET_CLINIC_PET_STRESS_04_BAD: 'CommonBuffId' = 168218 - OWNABLE_VET_CLINIC_PET_STRESS_05_TERRIBLE: 'CommonBuffId' = 168217 - OWNABLE_VET_CLINIC_QUALITY_OF_SERVICE_CONE_OF_SHAME: 'CommonBuffId' = 168804 - OWNABLE_VET_CLINIC_QUALITY_OF_SERVICE_CORRECT_TREATMENT_0_WORST: 'CommonBuffId' = 178633 - OWNABLE_VET_CLINIC_QUALITY_OF_SERVICE_CORRECT_TREATMENT_1_2ND_WORST: 'CommonBuffId' = 178634 - OWNABLE_VET_CLINIC_QUALITY_OF_SERVICE_CORRECT_TREATMENT_2_3RD_WORST: 'CommonBuffId' = 178635 - OWNABLE_VET_CLINIC_QUALITY_OF_SERVICE_CORRECT_TREATMENT_3_4TH_BEST: 'CommonBuffId' = 178636 - OWNABLE_VET_CLINIC_QUALITY_OF_SERVICE_CORRECT_TREATMENT_4_3RD_BEST: 'CommonBuffId' = 178637 - OWNABLE_VET_CLINIC_QUALITY_OF_SERVICE_CORRECT_TREATMENT_5_2ND_BEST: 'CommonBuffId' = 178638 - OWNABLE_VET_CLINIC_QUALITY_OF_SERVICE_CORRECT_TREATMENT_6_BEST: 'CommonBuffId' = 178639 - OWNABLE_VET_CLINIC_QUALITY_OF_SERVICE_GREAT_SERVICE: 'CommonBuffId' = 168805 - OWNABLE_VET_CLINIC_QUALITY_OF_SERVICE_INCORRECT_TREATMENT: 'CommonBuffId' = 168552 - OWNABLE_VET_CLINIC_RATING_TIMERS_PET_STRESS_AMAZING: 'CommonBuffId' = 178769 - OWNABLE_VET_CLINIC_RATING_TIMERS_PET_STRESS_GOOD: 'CommonBuffId' = 178771 - OWNABLE_VET_CLINIC_RATING_TIMERS_PET_STRESS_GREAT: 'CommonBuffId' = 178770 - OWNABLE_VET_CLINIC_RATING_TIMERS_WAIT_TIME_GOOD: 'CommonBuffId' = 178764 - OWNABLE_VET_CLINIC_STATES_CLEAN: 'CommonBuffId' = 171547 - OWNABLE_VET_CLINIC_STATES_DONT_CLEAN: 'CommonBuffId' = 171548 - OWNABLE_VET_CLINIC_STATES_DONT_TREAT: 'CommonBuffId' = 171550 - OWNABLE_VET_CLINIC_STATES_TREAT: 'CommonBuffId' = 171549 - OWNABLE_VET_CLINIC_VALUE_OF_SERVICE_AMAZING: 'CommonBuffId' = 168496 - OWNABLE_VET_CLINIC_VALUE_OF_SERVICE_GOOD: 'CommonBuffId' = 168497 - OWNABLE_VET_CLINIC_VALUE_OF_SERVICE_GREAT: 'CommonBuffId' = 168498 - OWNABLE_VET_CLINIC_VALUE_OF_SERVICE_NEUTRAL: 'CommonBuffId' = 168499 - OWNABLE_VET_CLINIC_VALUE_OF_SERVICE_POOR: 'CommonBuffId' = 168500 - OWNABLE_VET_CLINIC_VALUE_OF_SERVICE_TERRIBLE: 'CommonBuffId' = 168501 - OWNABLE_VET_CLINIC_WAIT_TIME_BAD: 'CommonBuffId' = 167891 - OWNABLE_VET_CLINIC_WAIT_TIME_DISGRUNTLED: 'CommonBuffId' = 167892 - OWNABLE_VET_CLINIC_WAIT_TIME_GOOD: 'CommonBuffId' = 167897 - OWNABLE_VET_CLINIC_WAIT_TIME_START: 'CommonBuffId' = 167898 - OWNABLE_VET_CLINIC_WAIT_TIME_STOP: 'CommonBuffId' = 167899 - PAPARAZZI_EMBARRASSED: 'CommonBuffId' = 196748 - PAPARAZZI_IDLE: 'CommonBuffId' = 201576 - PAPARAZZI_LOCKED_OUT: 'CommonBuffId' = 202199 - PAPARAZZI_MELTDOWN_1: 'CommonBuffId' = 191958 - PAPARAZZI_MELTDOWN_2: 'CommonBuffId' = 191974 - PAPARAZZI_MELTDOWN_3: 'CommonBuffId' = 191975 - PAPARAZZI_PHOTO_OPPORTUNITY: 'CommonBuffId' = 197103 - PAPARAZZI_REACTION_COOLDOWN: 'CommonBuffId' = 191955 - PAPARAZZI_TRAIT: 'CommonBuffId' = 191785 - PARENTING_SKILL_ALLOW_GROUP_COOK: 'CommonBuffId' = 161554 - PARENTING_SKILL_ALLOW_INTERACTION: 'CommonBuffId' = 161871 - PARENTING_SKILL_ALLOW_NAP_SLEEP: 'CommonBuffId' = 161558 - PARENTING_SKILL_ALLOW_SCHOOL_PROJECT: 'CommonBuffId' = 168767 - PARENTING_SKILL_LEVEL_01: 'CommonBuffId' = 160505 - PARENTING_SKILL_LEVEL_02: 'CommonBuffId' = 160510 - PARENTING_SKILL_LEVEL_03: 'CommonBuffId' = 160511 - PARENTING_SKILL_LEVEL_04: 'CommonBuffId' = 160512 - PARENTING_SKILL_LEVEL_05: 'CommonBuffId' = 160513 - PARENTING_SKILL_LEVEL_06: 'CommonBuffId' = 160514 - PARENTING_SKILL_LEVEL_07: 'CommonBuffId' = 160515 - PARENTING_SKILL_LEVEL_08: 'CommonBuffId' = 160516 - PARENTING_SKILL_LEVEL_09: 'CommonBuffId' = 160509 - PARENTING_SKILL_LEVEL_10: 'CommonBuffId' = 160508 - PARENTING_SKILL_PARENTING_TIPS_ANGRY: 'CommonBuffId' = 163208 - PARENTING_SKILL_PARENTING_TIPS_CONFIDENT: 'CommonBuffId' = 163207 - PARENTING_SKILL_PARENTING_TIPS_EMBARRASSED: 'CommonBuffId' = 163209 - PARENTING_SKILL_PARENTING_TIPS_HAPPY: 'CommonBuffId' = 163191 - PARENTING_SKILL_RESEARCH_ANGRY: 'CommonBuffId' = 160653 - PARENTING_SKILL_RESEARCH_CONFIDENT: 'CommonBuffId' = 160652 - PARENTING_SKILL_RESEARCH_EMBARRASSED: 'CommonBuffId' = 160654 - PARENTING_SKILL_RESEARCH_INSPIRED: 'CommonBuffId' = 162632 - PARENTING_SKILL_RESEARCH_STRESSED: 'CommonBuffId' = 162631 - PARENTING_SKILL_SOLVE_BLADDER: 'CommonBuffId' = 160558 - PARENTING_SKILL_SOLVE_BLADDER_ADVANCED: 'CommonBuffId' = 160561 - PARENTING_SKILL_SOLVE_COOLDOWN: 'CommonBuffId' = 162725 - PARENTING_SKILL_SUPER_PARENT: 'CommonBuffId' = 160762 - PARENTING_SKILL_SUPER_SOLVE_INFANT_COOLDOWN: 'CommonBuffId' = 166894 - PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_B_1_SUCCESS: 'CommonBuffId' = 177951 - PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_B_2_FAILURE: 'CommonBuffId' = 177953 - PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_B_2_SUCCESS: 'CommonBuffId' = 177952 - PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_CAMPSITE_CHASED: 'CommonBuffId' = 177995 - PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_C_1_SUCCESS: 'CommonBuffId' = 177955 - PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_C_2_FAILURE: 'CommonBuffId' = 177957 - PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_D_1_SUCCESS: 'CommonBuffId' = 177963 - PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_EGG_2_OPTION_1_FAILURE: 'CommonBuffId' = 180329 - PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_EGG_2_OPTION_2_FAILURE: 'CommonBuffId' = 180328 - PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_E_1_SUCCESS: 'CommonBuffId' = 177972 - PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_FIND_ARTIFACT: 'CommonBuffId' = 177996 - PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_F_1_SUCCESS: 'CommonBuffId' = 177981 - PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_F_2_FAILURE: 'CommonBuffId' = 178010 - PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_G_1_SUCCESS: 'CommonBuffId' = 177987 - PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_H_1_SUCCESS: 'CommonBuffId' = 177991 - PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_PACK_FAILURE: 'CommonBuffId' = 178002 - PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_PACK_SUCCESS: 'CommonBuffId' = 178003 - PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_QUICKSAND_2_OPTION_2_FAILURE: 'CommonBuffId' = 180330 - PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_SLOTHS_2_OPTION_2_FAILURE: 'CommonBuffId' = 180325 - PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_SLOTH_2_OPTION_1_FAILURE: 'CommonBuffId' = 180326 - PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_SLOTH_WALK: 'CommonBuffId' = 180331 - PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_SLOTH_WINK: 'CommonBuffId' = 180332 - PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_VINES_2_OPTION_1_FAILURE: 'CommonBuffId' = 180259 - PATH_OBSTACLE_ADVENTURE_REWARD_BUFFS_VINES_2_OPTION_2_FAILURE: 'CommonBuffId' = 180260 - PATH_OBSTACLE_SORE_HANDS: 'CommonBuffId' = 175098 - PA_MATRIARCH_SKILL_UP: 'CommonBuffId' = 29863 - PERFECT_DATE: 'CommonBuffId' = 372997 - PERFORMANCE_SPACE_AUTONOMY_BUSK_GUITAR: 'CommonBuffId' = 142053 - PERFORMANCE_SPACE_AUTONOMY_BUSK_VIOLIN: 'CommonBuffId' = 142052 - PERFORMANCE_SPACE_PUSH_TIP: 'CommonBuffId' = 135155 - PERFORMANCE_SPACE_PUSH_WATCH: 'CommonBuffId' = 143496 - PERFORMANCE_SPACE_TIP_RECIPIENT: 'CommonBuffId' = 133704 - PERFORMANCE_SPACE_TIP_RECIPIENT_WHILE_PERFORMING: 'CommonBuffId' = 143817 - PERSONA_POWERS_EMOTIONAL_DAMPENING_LEVEL1: 'CommonBuffId' = 151084 - PERSONA_POWERS_EMOTIONAL_DAMPENING_LEVEL2: 'CommonBuffId' = 151085 - PERSONA_POWERS_EMOTIONAL_DAMPENING_LEVEL3: 'CommonBuffId' = 151083 - PERSONA_POWERS_GARLIC_IMMUNITY: 'CommonBuffId' = 153329 - PERSONA_POWERS_LOSE_HUMANITY_FUN: 'CommonBuffId' = 150381 - PERSONA_POWERS_LOSE_HUMANITY_HYGIENE: 'CommonBuffId' = 150379 - PERSONA_POWERS_LOSE_HUMANITY_SOCIAL: 'CommonBuffId' = 150380 - PERSONA_POWERS_NOCTURNAL_AFFINITY_LEVEL1: 'CommonBuffId' = 151057 - PERSONA_POWERS_NOCTURNAL_AFFINITY_LEVEL2: 'CommonBuffId' = 151058 - PERSONA_POWERS_NOCTURNAL_AFFINITY_LEVEL3: 'CommonBuffId' = 151056 - PERSONA_POWERS_VAMPIRIC_SLUMBER_LEVEL1: 'CommonBuffId' = 151515 - PERSONA_POWERS_VAMPIRIC_SLUMBER_LEVEL2: 'CommonBuffId' = 151516 - PERSONA_POWERS_VAMPIRIC_SLUMBER_LEVEL3: 'CommonBuffId' = 151517 - PERSONA_POWERS_VAMPIRIC_SLUMBER_LEVEL4: 'CommonBuffId' = 151518 - PERSONA_POWERS_VAMPIRIC_SLUMBER_LEVEL5: 'CommonBuffId' = 151514 - PETS_AGGRESSIVE_TRAIT_HIDDEN: 'CommonBuffId' = 177754 - PETS_CANCEL_LAY_DOWN: 'CommonBuffId' = 168048 - PETS_CAT_SCRATCH_FURNITURE_SIM: 'CommonBuffId' = 163376 - PETS_DOG_SPLASHED_SIM: 'CommonBuffId' = 163813 - PETS_DOG_TOILET_DRINK_HIDDEN: 'CommonBuffId' = 163381 - PETS_DOG_TOILET_DRINK_SIM: 'CommonBuffId' = 163382 - PETS_EAT_PREPARED_PET_RECIPE_FOOD_HIDDEN: 'CommonBuffId' = 170454 - PETS_FEEL_THE_LOVE_ACTOR_SIM: 'CommonBuffId' = 170841 - PETS_FEEL_THE_LOVE_ACTOR_SIM_CAT: 'CommonBuffId' = 172393 - PETS_FEEL_THE_LOVE_TARGET_PET_COOLDOWN: 'CommonBuffId' = 170839 - PETS_FINDING_THINGS_REACTION_BUFF: 'CommonBuffId' = 173842 - PETS_IMITATE_PET_FAILURE_HIDDEN: 'CommonBuffId' = 173301 - PETS_IMITATE_PET_SUCCESS: 'CommonBuffId' = 173312 - PETS_INITIATED_PET_PET_COOL_DOWN: 'CommonBuffId' = 205707 - PETS_MISBEHAVIOR_RECENTLY_DISCIPLINED: 'CommonBuffId' = 167845 - PETS_OBSESS_MIXER_COOLDOWN: 'CommonBuffId' = 170537 - PETS_OWNER_RETURNS_PET_HIDDEN: 'CommonBuffId' = 171078 - PETS_OWNER_RETURNS_SIM_HIDDEN: 'CommonBuffId' = 171148 - PETS_PAMPER_PET_CAT: 'CommonBuffId' = 173702 - PETS_PAMPER_PET_DOG: 'CommonBuffId' = 173703 - PETS_PLAYED_WITH: 'CommonBuffId' = 178350 - PETS_PLAY_WRESTLE_ACTOR_SIM_FAIL: 'CommonBuffId' = 173700 - PETS_PLAY_WRESTLE_ACTOR_SIM_SUCCESS: 'CommonBuffId' = 173698 - PETS_SIM_DIRTY_PET: 'CommonBuffId' = 169046 - PETS_SIM_PEED_ON: 'CommonBuffId' = 167007 - PETS_SLEEP_FX_LARGE_DOG_ZZZZ: 'CommonBuffId' = 178600 - PETS_SLEEP_FX_SMALL_PET_ZZZZ: 'CommonBuffId' = 178605 - PETS_TREAT_COOLDOWN: 'CommonBuffId' = 167244 - PETS_TRIED_TO_BREED: 'CommonBuffId' = 172584 - PETS_WAYPOINT_ROUTE_EVENTS_CAT_LITTERBOX: 'CommonBuffId' = 169985 - PETS_WAYPOINT_ROUTE_EVENTS_CHASE_CAT: 'CommonBuffId' = 170326 - PETS_WAYPOINT_ROUTE_EVENTS_CHASE_DOG: 'CommonBuffId' = 170327 - PETS_WAYPOINT_ROUTE_EVENTS_DOG_HUNGER: 'CommonBuffId' = 169987 - PETS_WAY_POINT_ROUTE_EVENTS_CAT_LOW_AFFECTION: 'CommonBuffId' = 175869 - PET_ACTIVE_GO_FOR_WALK_PLAY_DECAY: 'CommonBuffId' = 172769 - PET_AGGRESSIVE_CALM_DOWN: 'CommonBuffId' = 173138 - PET_AGGRESSIVE_STRANGERS: 'CommonBuffId' = 173147 - PET_AUTONOMY_MOD_NEED_TO_DISCIPLINE_PET: 'CommonBuffId' = 169565 - PET_BE_EXAMINED: 'CommonBuffId' = 167756 - PET_CAT_IS_SLEEPING: 'CommonBuffId' = 158606 - PET_CAT_WANDERLUST: 'CommonBuffId' = 159114 - PET_CURIOUS_SEARCHING: 'CommonBuffId' = 172164 - PET_DISCIPLINE_FREQUENCY_HIGH_CAT_JUMP_ON_COUNTERS: 'CommonBuffId' = 177200 - PET_DISCIPLINE_FREQUENCY_HIGH_CAT_SCRATCHING: 'CommonBuffId' = 177201 - PET_DISCIPLINE_FREQUENCY_HIGH_DOG_BARK: 'CommonBuffId' = 177202 - PET_DISCIPLINE_FREQUENCY_HIGH_DOG_EAT_POOP: 'CommonBuffId' = 177205 - PET_DISCIPLINE_FREQUENCY_HIGH_DOG_JUMP_ON_COUNTERS: 'CommonBuffId' = 177206 - PET_DISCIPLINE_FREQUENCY_HIGH_DOG_PUDDLES_PLAY: 'CommonBuffId' = 177207 - PET_DISCIPLINE_FREQUENCY_HIGH_DOG_TOILET: 'CommonBuffId' = 177208 - PET_DISCIPLINE_FREQUENCY_HIGH_PET_ATTACK: 'CommonBuffId' = 177209 - PET_DISCIPLINE_FREQUENCY_HIGH_PET_BAT_KNOCK_TRASH: 'CommonBuffId' = 177210 - PET_DISCIPLINE_FREQUENCY_HIGH_PET_BEG_EATING: 'CommonBuffId' = 177211 - PET_DISCIPLINE_FREQUENCY_HIGH_PET_EAT_PEOPLE_FOOD: 'CommonBuffId' = 177212 - PET_DISCIPLINE_FREQUENCY_HIGH_PET_POTTY_TRAINING: 'CommonBuffId' = 177213 - PET_DISCIPLINE_FREQUENCY_HIGH_PET_PUDDLES_DRINK: 'CommonBuffId' = 177214 - PET_DISCIPLINE_FREQUENCY_HIGH_PET_TRASH_EAT: 'CommonBuffId' = 177215 - PET_DISCIPLINE_FREQUENCY_HIGH_PET_TRASH_PLAY: 'CommonBuffId' = 177216 - PET_DISCIPLINE_FREQUENCY_HIGH_PET_TRASH_RUMMAGE: 'CommonBuffId' = 177217 - PET_DISCIPLINE_FREQUENCY_HIGH_PET_WAKE_UP_SIMS: 'CommonBuffId' = 177218 - PET_DISCIPLINE_FREQUENCY_MEDIUM_CAT_JUMP_ON_COUNTERS: 'CommonBuffId' = 177179 - PET_DISCIPLINE_FREQUENCY_MEDIUM_CAT_SCRATCHING: 'CommonBuffId' = 177180 - PET_DISCIPLINE_FREQUENCY_MEDIUM_DOG_BARK: 'CommonBuffId' = 177181 - PET_DISCIPLINE_FREQUENCY_MEDIUM_DOG_EAT_POOP: 'CommonBuffId' = 177184 - PET_DISCIPLINE_FREQUENCY_MEDIUM_DOG_JUMP_ON_COUNTERS: 'CommonBuffId' = 177185 - PET_DISCIPLINE_FREQUENCY_MEDIUM_DOG_PUDDLES_PLAY: 'CommonBuffId' = 177186 - PET_DISCIPLINE_FREQUENCY_MEDIUM_DOG_TOILET: 'CommonBuffId' = 177187 - PET_DISCIPLINE_FREQUENCY_MEDIUM_PET_ATTACK: 'CommonBuffId' = 177188 - PET_DISCIPLINE_FREQUENCY_MEDIUM_PET_BAT_KNOCK_TRASH: 'CommonBuffId' = 177189 - PET_DISCIPLINE_FREQUENCY_MEDIUM_PET_BEG_EATING: 'CommonBuffId' = 177190 - PET_DISCIPLINE_FREQUENCY_MEDIUM_PET_EAT_PEOPLE_FOOD: 'CommonBuffId' = 177191 - PET_DISCIPLINE_FREQUENCY_MEDIUM_PET_POTTY_TRAINING: 'CommonBuffId' = 177192 - PET_DISCIPLINE_FREQUENCY_MEDIUM_PET_PUDDLES_DRINK: 'CommonBuffId' = 177193 - PET_DISCIPLINE_FREQUENCY_MEDIUM_PET_TRASH_EAT: 'CommonBuffId' = 177194 - PET_DISCIPLINE_FREQUENCY_MEDIUM_PET_TRASH_PLAY: 'CommonBuffId' = 177195 - PET_DISCIPLINE_FREQUENCY_MEDIUM_PET_TRASH_RUMMAGE: 'CommonBuffId' = 177196 - PET_DISCIPLINE_FREQUENCY_MEDIUM_PET_WAKE_UP_SIMS: 'CommonBuffId' = 177197 - PET_DOG_IS_SLEEPING: 'CommonBuffId' = 158528 - PET_DO_NOT_DISTURB: 'CommonBuffId' = 163908 - PET_ENCOURAGED_TO_WOOHOO: 'CommonBuffId' = 174515 - PET_HAIRY_BRUSHED: 'CommonBuffId' = 172878 - PET_HAIRY_CLEANED_HAIR_PILE: 'CommonBuffId' = 168317 - PET_HUNTER_GO_OUTSIDE_COOLDOWN_BUSH: 'CommonBuffId' = 177356 - PET_HUNTER_GO_OUTSIDE_COOLDOWN_DIG: 'CommonBuffId' = 177357 - PET_HUNTER_GO_OUTSIDE_COOLDOWN_FISHING_LOCATION: 'CommonBuffId' = 169344 - PET_HUNTER_GO_OUTSIDE_COOLDOWN_RUMMAGE_PILE: 'CommonBuffId' = 177823 - PET_HUNTER_GO_OUTSIDE_COOLDOWN_SNIFF: 'CommonBuffId' = 169322 - PET_HUNTER_OPEN_STREET: 'CommonBuffId' = 168780 - PET_INDEPENDENT_LET_OUT: 'CommonBuffId' = 177470 - PET_IS_DYING: 'CommonBuffId' = 164921 - PET_LAZE_COOLDOWN: 'CommonBuffId' = 178001 - PET_LAZY_RELAX_COOLDOWN: 'CommonBuffId' = 177736 - PET_LECTURED_OR_SCOLDED: 'CommonBuffId' = 173671 - PET_LIGHTNING_SCARED: 'CommonBuffId' = 188520 - PET_LITTER_BOX_KISSED_BY_LITTER_BREATH: 'CommonBuffId' = 159314 - PET_LITTER_BOX_LITTER_BREATH_HIDDEN: 'CommonBuffId' = 159273 - PET_LITTER_BOX_SQUEAMISH_TENSE: 'CommonBuffId' = 168955 - PET_OBSTACLE_COURSE_HIDDEN_FAILED_JUMP_FIRE_TAIL: 'CommonBuffId' = 172563 - PET_OBSTACLE_COURSE_HIDDEN_FAILED_OBSTACLE: 'CommonBuffId' = 172552 - PET_OBSTACLE_COURSE_HIDDEN_PASSED_OBSTACLE: 'CommonBuffId' = 172551 - PET_OBSTACLE_COURSE_HIDDEN_PRACTICED_HOOP: 'CommonBuffId' = 172594 - PET_OBSTACLE_COURSE_HIDDEN_PRACTICED_PLATFORM: 'CommonBuffId' = 172598 - PET_OBSTACLE_COURSE_HIDDEN_PRACTICED_RAMP: 'CommonBuffId' = 172596 - PET_OBSTACLE_COURSE_HIDDEN_PRACTICED_TUNNEL: 'CommonBuffId' = 172595 - PET_OBSTACLE_COURSE_HIDDEN_PRACTICED_WEAVING_FLAGS: 'CommonBuffId' = 172597 - PET_OBSTACLE_COURSE_PET_OWNER_HAPPY: 'CommonBuffId' = 170922 - PET_OBSTACLE_COURSE_PET_OWNER_TENSE: 'CommonBuffId' = 170923 - PET_OBSTACLE_COURSE_ROLE_PET_OWNER_WATCHING: 'CommonBuffId' = 170994 - PET_OBSTACLE_COURSE_ROLE_PET_RUN_COURSE: 'CommonBuffId' = 171028 - PET_OVERLAY_PLAID: 'CommonBuffId' = 174660 - PET_OVERLAY_PLAID_CAT: 'CommonBuffId' = 174676 - PET_OVERLAY_PLAID_SMALL_DOG: 'CommonBuffId' = 174677 - PET_OVERLAY_POLKA_DOTS: 'CommonBuffId' = 174661 - PET_OVERLAY_POLKA_DOTS_CAT: 'CommonBuffId' = 174678 - PET_OVERLAY_POLKA_DOTS_SMALL_DOG: 'CommonBuffId' = 174679 - PET_OVERLAY_RAINBOW: 'CommonBuffId' = 174662 - PET_OVERLAY_RAINBOW_CAT: 'CommonBuffId' = 174680 - PET_OVERLAY_RAINBOW_SMALL_DOG: 'CommonBuffId' = 174681 - PET_OWNER_VOCAL_REQUEST_SONG_HAPPY: 'CommonBuffId' = 177691 - PET_OWNER_VOCAL_REQUEST_SONG_TENSE: 'CommonBuffId' = 177692 - PET_PLASMA_EXTRACTED: 'CommonBuffId' = 170695 - PET_POOP_CLEAN_UP: 'CommonBuffId' = 161118 - PET_POOP_CLEAN_UP_SQUEAMISH: 'CommonBuffId' = 176096 - PET_POOP_INTERACTING_WITH: 'CommonBuffId' = 162510 - PET_POOP_STEPPED_ON: 'CommonBuffId' = 162023 - PET_PREFERENCE_SET_INSIDE: 'CommonBuffId' = 159270 - PET_PREFERENCE_SET_OUTSIDE: 'CommonBuffId' = 159271 - PET_RECENTLY_SCOLDED: 'CommonBuffId' = 161684 - PET_SEASON_WEATHER_WET_VFX_LARGE: 'CommonBuffId' = 190863 - PET_SEASON_WEATHER_WET_VFX_SMALL: 'CommonBuffId' = 190862 - PET_SICKNESS_BARFING: 'CommonBuffId' = 163807 - PET_SICKNESS_CRITICAL_FAILURE_BARFING: 'CommonBuffId' = 166037 - PET_SICKNESS_CRITICAL_FAILURE_EXTREME_LETHARGY: 'CommonBuffId' = 166038 - PET_SICKNESS_CRITICAL_FAILURE_FLEAS: 'CommonBuffId' = 166039 - PET_SICKNESS_CRITICAL_FAILURE_GLOWING_NOSE: 'CommonBuffId' = 166040 - PET_SICKNESS_CRITICAL_FAILURE_GOLDEN_POOP: 'CommonBuffId' = 166041 - PET_SICKNESS_CRITICAL_FAILURE_HOT_FEET: 'CommonBuffId' = 166047 - PET_SICKNESS_CRITICAL_FAILURE_ICEY_FUR: 'CommonBuffId' = 166042 - PET_SICKNESS_CRITICAL_FAILURE_MOUTH_MOTHS: 'CommonBuffId' = 166043 - PET_SICKNESS_CRITICAL_FAILURE_RAINBOW_POOP: 'CommonBuffId' = 166044 - PET_SICKNESS_CRITICAL_FAILURE_STINKY_FUR: 'CommonBuffId' = 166045 - PET_SICKNESS_CRITICAL_FAILURE_TEMPORARY_BLOCK_CRITICAL_FAILURE: 'CommonBuffId' = 169620 - PET_SICKNESS_CRITICAL_FAILURE_UNCONTROLLABLE_DROOLING: 'CommonBuffId' = 166046 - PET_SICKNESS_EXTREME_LETHARGY: 'CommonBuffId' = 163808 - PET_SICKNESS_FAILURE_CONTROLLER_BARFING: 'CommonBuffId' = 166022 - PET_SICKNESS_FAILURE_CONTROLLER_EXTREME_LETHARGY: 'CommonBuffId' = 166023 - PET_SICKNESS_FAILURE_CONTROLLER_FLEAS: 'CommonBuffId' = 166024 - PET_SICKNESS_FAILURE_CONTROLLER_GLOWING_NOSE: 'CommonBuffId' = 166025 - PET_SICKNESS_FAILURE_CONTROLLER_GOLDEN_POOP: 'CommonBuffId' = 166026 - PET_SICKNESS_FAILURE_CONTROLLER_HOT_FEET: 'CommonBuffId' = 166032 - PET_SICKNESS_FAILURE_CONTROLLER_ICEY_FUR: 'CommonBuffId' = 166027 - PET_SICKNESS_FAILURE_CONTROLLER_MOUTH_MOTHS: 'CommonBuffId' = 166028 - PET_SICKNESS_FAILURE_CONTROLLER_RAINBOW_POOP: 'CommonBuffId' = 166029 - PET_SICKNESS_FAILURE_CONTROLLER_STINKY_FUR: 'CommonBuffId' = 166030 - PET_SICKNESS_FAILURE_CONTROLLER_UNCONTROLLABLE_DROOLING: 'CommonBuffId' = 166031 - PET_SICKNESS_FLEAS: 'CommonBuffId' = 163806 - PET_SICKNESS_GLOWING_NOSE: 'CommonBuffId' = 163810 - PET_SICKNESS_GOLDEN_POOP: 'CommonBuffId' = 163811 - PET_SICKNESS_HOT_FEET: 'CommonBuffId' = 163802 - PET_SICKNESS_ICEY_FUR: 'CommonBuffId' = 163801 - PET_SICKNESS_MOUTH_MOTHS: 'CommonBuffId' = 163805 - PET_SICKNESS_RAINBOW_POOP: 'CommonBuffId' = 163803 - PET_SICKNESS_STINKY_FUR: 'CommonBuffId' = 163809 - PET_SICKNESS_TEMPORARY_BLOCK_SICKNESS: 'CommonBuffId' = 169691 - PET_SICKNESS_UNCONTROLLABLE_DROOLING: 'CommonBuffId' = 163804 - PET_SICKNESS_WELLNESS_TREAT_BLOCK_SICKNESS: 'CommonBuffId' = 171998 - PET_SMART_TELL_STORY: 'CommonBuffId' = 172406 - PET_SOCIAL_PARENT_TO_CHILD_COOLDOWN: 'CommonBuffId' = 164115 - PET_STOP_EATING_PET_NEARBY: 'CommonBuffId' = 174684 - PET_TEMPERATURE_AUTONOMY_HIDDEN_CAT_HOT: 'CommonBuffId' = 184254 - PET_TEMPERATURE_AUTONOMY_HIDDEN_DOG_HOT: 'CommonBuffId' = 184257 - PET_VFX_EXTREME_LETHARGY_ALL: 'CommonBuffId' = 169440 - PET_VFX_EXTREME_LETHARGY_ALL_CRITICAL: 'CommonBuffId' = 169441 - PET_VFX_FLEAS_CAT_SMALL_DOG: 'CommonBuffId' = 173617 - PET_VFX_FLEAS_CAT_SMALL_DOG_CRITICAL: 'CommonBuffId' = 173619 - PET_VFX_FLEAS_LARGE_DOG: 'CommonBuffId' = 173618 - PET_VFX_FLEAS_LARGE_DOG_CRITICAL: 'CommonBuffId' = 173620 - PET_VFX_GLOWING_NOSE_CAT: 'CommonBuffId' = 167626 - PET_VFX_GLOWING_NOSE_CAT_CRITICAL: 'CommonBuffId' = 167627 - PET_VFX_GLOWING_NOSE_LARGE_DOG: 'CommonBuffId' = 167631 - PET_VFX_GLOWING_NOSE_LARGE_DOG_CRITICAL: 'CommonBuffId' = 167632 - PET_VFX_GLOWING_NOSE_SMALL_DOG: 'CommonBuffId' = 167629 - PET_VFX_GLOWING_NOSE_SMALL_DOG_CRITICAL: 'CommonBuffId' = 167630 - PET_VFX_HOT_FEET_ALL: 'CommonBuffId' = 169618 - PET_VFX_HOT_FEET_ALL_CRITICAL: 'CommonBuffId' = 169619 - PET_VFX_ICEY_FUR_CAT: 'CommonBuffId' = 172982 - PET_VFX_ICEY_FUR_CAT_SMALL_DOG_CRITICAL: 'CommonBuffId' = 169437 - PET_VFX_ICEY_FUR_LARGE_DOG: 'CommonBuffId' = 172983 - PET_VFX_ICEY_FUR_LARGE_DOG_CRITICAL: 'CommonBuffId' = 169436 - PET_VFX_ICEY_FUR_SMALL_DOG: 'CommonBuffId' = 173093 - PET_VFX_ICEY_FUR_SMALL_DOG_ONLY_CRITICAL: 'CommonBuffId' = 172976 - PET_VFX_MOTH_MOUTH_ALL: 'CommonBuffId' = 169447 - PET_VFX_MOTH_MOUTH_ALL_CRITICAL: 'CommonBuffId' = 169448 - PET_VFX_STINKY_FUR_CAT_SMALL_DOG: 'CommonBuffId' = 167674 - PET_VFX_STINKY_FUR_CAT_SMALL_DOG_CRITICAL: 'CommonBuffId' = 167675 - PET_VFX_STINKY_FUR_LARGE_DOG: 'CommonBuffId' = 167676 - PET_VFX_STINKY_FUR_LARGE_DOG_CRITICAL: 'CommonBuffId' = 167677 - PET_VFX_UNCONTROLLABLE_DROOL_CAT_SMALL_DOG: 'CommonBuffId' = 167667 - PET_VFX_UNCONTROLLABLE_DROOL_CAT_SMALL_DOG_LEVEL2: 'CommonBuffId' = 169500 - PET_VFX_UNCONTROLLABLE_DROOL_LARGE_DOG: 'CommonBuffId' = 167668 - PET_VFX_UNCONTROLLABLE_DROOL_LARGE_DOG_LEVEL2: 'CommonBuffId' = 169501 - PET_WANDERLUST_GO_ON_ADVENTURE: 'CommonBuffId' = 173514 - PET_WEATHER_AUTONOMY_HIDDEN_IN_THE_RAIN: 'CommonBuffId' = 186242 - PET_WEATHER_HIDDEN_SNOWING_DOG: 'CommonBuffId' = 183070 - PET_WOOHOO_FAILURE_SAD_CATS: 'CommonBuffId' = 174258 - PET_WOOHOO_FAILURE_SAD_DOGS: 'CommonBuffId' = 174252 - PET_WOOHOO_OUTCOME_HAPPY_CATS: 'CommonBuffId' = 174260 - PET_WOOHOO_OUTCOME_HAPPY_DOGS: 'CommonBuffId' = 174261 - PHONE_BLACK: 'CommonBuffId' = 149354 - PHONE_BLACK_STRIPES: 'CommonBuffId' = 149355 - PHONE_BLUE_POLKA: 'CommonBuffId' = 149356 - PHONE_BREAK_UP_ACTOR_CONFIDENT_AVOIDED_CONFRONTATION: 'CommonBuffId' = 375896 - PHONE_BREAK_UP_ACTOR_HIDDEN_SFX: 'CommonBuffId' = 393718 - PHONE_BREAK_UP_ACTOR_TENSE_GUILTY: 'CommonBuffId' = 375895 - PHONE_BROWN: 'CommonBuffId' = 149357 - PHONE_COLOR_ASTRO_BLACK: 'CommonBuffId' = 284056 - PHONE_COLOR_ASTRO_GRAY: 'CommonBuffId' = 284057 - PHONE_COLOR_ASTRO_MAROON: 'CommonBuffId' = 284058 - PHONE_COLOR_ASTRO_PEACH: 'CommonBuffId' = 284059 - PHONE_COLOR_ASTRO_PINK: 'CommonBuffId' = 284060 - PHONE_COLOR_ASTRO_PURPLE: 'CommonBuffId' = 284061 - PHONE_COLOR_CASSETTE_BLACK: 'CommonBuffId' = 284312 - PHONE_COLOR_CASSETTE_BLUE: 'CommonBuffId' = 284314 - PHONE_COLOR_CASSETTE_GREEN: 'CommonBuffId' = 284313 - PHONE_COLOR_CASSETTE_ORANGE: 'CommonBuffId' = 284316 - PHONE_COLOR_CASSETTE_PINK: 'CommonBuffId' = 284315 - PHONE_COLOR_CASSETTE_RED: 'CommonBuffId' = 284311 - PHONE_COLOR_DUO_BABY_BLUE: 'CommonBuffId' = 284340 - PHONE_COLOR_DUO_BLACK: 'CommonBuffId' = 284343 - PHONE_COLOR_DUO_GREEN: 'CommonBuffId' = 284342 - PHONE_COLOR_DUO_LAVENDER: 'CommonBuffId' = 284341 - PHONE_COLOR_DUO_SLATE: 'CommonBuffId' = 284338 - PHONE_COLOR_DUO_UMBER: 'CommonBuffId' = 284339 - PHONE_COLOR_FLORAL_GREEN_BLUE: 'CommonBuffId' = 284262 - PHONE_COLOR_FLORAL_MAUVE: 'CommonBuffId' = 284263 - PHONE_COLOR_FLORAL_PEACH: 'CommonBuffId' = 284264 - PHONE_COLOR_FLORAL_PINK: 'CommonBuffId' = 284265 - PHONE_COLOR_FLORAL_SLATE: 'CommonBuffId' = 284266 - PHONE_COLOR_FLORAL_YELLOW: 'CommonBuffId' = 284267 - PHONE_COLOR_GEO_BLUE: 'CommonBuffId' = 284287 - PHONE_COLOR_GEO_BROWN: 'CommonBuffId' = 284292 - PHONE_COLOR_GEO_GOLD: 'CommonBuffId' = 284291 - PHONE_COLOR_GEO_GREEN: 'CommonBuffId' = 284289 - PHONE_COLOR_GEO_RED: 'CommonBuffId' = 284288 - PHONE_COLOR_GEO_SILVER: 'CommonBuffId' = 284290 - PHONE_COLOR_PAINT_BLACK: 'CommonBuffId' = 284028 - PHONE_COLOR_PAINT_BLUE: 'CommonBuffId' = 284029 - PHONE_COLOR_PAINT_CANARY: 'CommonBuffId' = 284030 - PHONE_COLOR_PAINT_GREEN: 'CommonBuffId' = 284031 - PHONE_COLOR_PAINT_TEAL: 'CommonBuffId' = 284032 - PHONE_COLOR_PAINT_WHITE: 'CommonBuffId' = 284033 - PHONE_COLOR_ROSE_BLACK: 'CommonBuffId' = 284238 - PHONE_COLOR_ROSE_BLUE: 'CommonBuffId' = 284239 - PHONE_COLOR_ROSE_GREEN: 'CommonBuffId' = 284240 - PHONE_COLOR_ROSE_LAVENDER: 'CommonBuffId' = 284241 - PHONE_COLOR_ROSE_METAL_GOLD: 'CommonBuffId' = 284242 - PHONE_COLOR_ROSE_WHITE: 'CommonBuffId' = 284243 - PHONE_COLOR_SWIRL_BLUE: 'CommonBuffId' = 283987 - PHONE_COLOR_SWIRL_GRAY: 'CommonBuffId' = 283989 - PHONE_COLOR_SWIRL_GREEN: 'CommonBuffId' = 283990 - PHONE_COLOR_SWIRL_ORANGE: 'CommonBuffId' = 283991 - PHONE_COLOR_SWIRL_PINK: 'CommonBuffId' = 283992 - PHONE_COLOR_SWIRL_PURPLE: 'CommonBuffId' = 283993 - PHONE_DARK_BLUE: 'CommonBuffId' = 149358 - PHONE_DARK_GREEN: 'CommonBuffId' = 149359 - PHONE_GOLD: 'CommonBuffId' = 149360 - PHONE_HOT_PINK_POLKA: 'CommonBuffId' = 149361 - PHONE_IDLE_COOLDOWN: 'CommonBuffId' = 310164 - PHONE_LIGHT_PINK: 'CommonBuffId' = 149362 - PHONE_LIME: 'CommonBuffId' = 149346 - PHONE_MINT_GREEN_STRIPES: 'CommonBuffId' = 149347 - PHONE_ORANGE_POLKA: 'CommonBuffId' = 149348 - PHONE_PURPLE: 'CommonBuffId' = 149349 - PHONE_RED: 'CommonBuffId' = 149350 - PHONE_ROSE_GOLD: 'CommonBuffId' = 149351 - PHONE_SILVER: 'CommonBuffId' = 149352 - PHONE_TURQUOISE_STRIPES: 'CommonBuffId' = 149345 - PHONE_WHITE: 'CommonBuffId' = 149353 - PHOTO_BOOTH_TAKE_PHOTO_FINE: 'CommonBuffId' = 296344 - PHOTO_BOOTH_TAKE_PHOTO_WITH_FRIENDLY_FAIL: 'CommonBuffId' = 293020 - PHOTO_BOOTH_TAKE_PHOTO_WITH_FRIENDLY_SUCCESS: 'CommonBuffId' = 293019 - PHOTO_BOOTH_TAKE_PHOTO_WITH_FUNNY_FAIL: 'CommonBuffId' = 293023 - PHOTO_BOOTH_TAKE_PHOTO_WITH_FUNNY_SUCCESS: 'CommonBuffId' = 293024 - PHOTO_BOOTH_TAKE_PHOTO_WITH_MISCHIEF_FAIL: 'CommonBuffId' = 293026 - PHOTO_BOOTH_TAKE_PHOTO_WITH_MISCHIEF_SUCCESS: 'CommonBuffId' = 293025 - PHOTO_BOOTH_TAKE_PHOTO_WITH_ROMANTIC_FAIL: 'CommonBuffId' = 293021 - PHOTO_BOOTH_TAKE_PHOTO_WITH_ROMANTIC_SUCCESS: 'CommonBuffId' = 293022 - PHOTO_BOOTH_TRACK_INITIATING_SIM: 'CommonBuffId' = 302417 - PHOTO_BOOTH_WOOHOO_GREAT: 'CommonBuffId' = 295910 - PHOTO_OP_STAND_CAUGHT_IN_THE_ACT: 'CommonBuffId' = 291270 - PHOTO_OP_STAND_TRASHED_TRIUMPH: 'CommonBuffId' = 291269 - PHYSICALLY_GIFTED: 'CommonBuffId' = 29626 - PICNIC_BASKET_COLDWEATHER: 'CommonBuffId' = 257906 - PICNIC_BASKET_HAPPY: 'CommonBuffId' = 257907 - PICNIC_BASKET_HAPPY_LOVES_OUTDOORS: 'CommonBuffId' = 258482 - PICNIC_BASKET_HOTWEATHER: 'CommonBuffId' = 257905 - PICNIC_BASKET_RAIN: 'CommonBuffId' = 257904 - PIER_ATTRACTIONS_BANNED_FERRIS_WHEEL: 'CommonBuffId' = 291046 - PIER_ATTRACTIONS_BANNED_HAUNTED_HOUSE: 'CommonBuffId' = 291195 - PIER_ATTRACTIONS_BANNED_TUNNEL_OF_LOVE: 'CommonBuffId' = 291196 - PIER_ATTRACTIONS_FERRIS_WHEEL_MESS_AROUND_1_A_FLIRTY: 'CommonBuffId' = 291082 - PIER_ATTRACTIONS_FERRIS_WHEEL_MESS_AROUND_1_B_DAZED: 'CommonBuffId' = 291106 - PIER_ATTRACTIONS_FERRIS_WHEEL_MESS_AROUND_2_A_SAD: 'CommonBuffId' = 291110 - PIER_ATTRACTIONS_FERRIS_WHEEL_MESS_AROUND_2_B_EMBARRASSED: 'CommonBuffId' = 291112 - PIER_ATTRACTIONS_FERRIS_WHEEL_RIDE_1_A_SCARED: 'CommonBuffId' = 291018 - PIER_ATTRACTIONS_FERRIS_WHEEL_RIDE_1_B_EMBARRASSED: 'CommonBuffId' = 291022 - PIER_ATTRACTIONS_FERRIS_WHEEL_RIDE_2_B_CONFIDENT: 'CommonBuffId' = 291024 - PIER_ATTRACTIONS_FERRIS_WHEEL_RIDE_2_B_EMBARRASSED: 'CommonBuffId' = 291034 - PIER_ATTRACTIONS_FERRIS_WHEEL_RIDE_3_A_BORED: 'CommonBuffId' = 291039 - PIER_ATTRACTIONS_FERRIS_WHEEL_RIDE_3_A_INSPIRED: 'CommonBuffId' = 291037 - PIER_ATTRACTIONS_FERRIS_WHEEL_RIDE_3_B_PLAYFUL: 'CommonBuffId' = 291045 - PIER_ATTRACTIONS_FERRIS_WHEEL_RIDE_WITH_1_A_TENSE: 'CommonBuffId' = 291052 - PIER_ATTRACTIONS_FERRIS_WHEEL_RIDE_WITH_1_B_SCARED: 'CommonBuffId' = 291059 - PIER_ATTRACTIONS_FERRIS_WHEEL_RIDE_WITH_2_A_FLIRTY: 'CommonBuffId' = 291061 - PIER_ATTRACTIONS_FERRIS_WHEEL_RIDE_WITH_2_B_EMBARRASSED: 'CommonBuffId' = 291064 - PIER_ATTRACTIONS_FERRIS_WHEEL_RIDE_WITH_3_A_PLAYFUL: 'CommonBuffId' = 291074 - PIER_ATTRACTIONS_FERRIS_WHEEL_RIDE_WITH_3_B_TENSE: 'CommonBuffId' = 291079 - PIER_ATTRACTIONS_FERRIS_WHEEL_RIDE_WITH_4_B_SAD: 'CommonBuffId' = 291094 - PIER_ATTRACTIONS_FERRIS_WHEEL_WOOHOO_1_A_CONFIDENT: 'CommonBuffId' = 291521 - PIER_ATTRACTIONS_FERRIS_WHEEL_WOOHOO_1_B_UNCOMFORTABLE: 'CommonBuffId' = 291114 - PIER_ATTRACTIONS_HAUNTED_HOUSE_MESS_AROUND_1_A_EMBARRASSED: 'CommonBuffId' = 291165 - PIER_ATTRACTIONS_HAUNTED_HOUSE_MESS_AROUND_1_B_SCARED: 'CommonBuffId' = 291167 - PIER_ATTRACTIONS_HAUNTED_HOUSE_MESS_AROUND_2_A_SCARED: 'CommonBuffId' = 291185 - PIER_ATTRACTIONS_HAUNTED_HOUSE_RIDE_1_SCARED: 'CommonBuffId' = 291125 - PIER_ATTRACTIONS_HAUNTED_HOUSE_RIDE_WITH_1_A_CONFIDENT: 'CommonBuffId' = 291128 - PIER_ATTRACTIONS_HAUNTED_HOUSE_RIDE_WITH_1_A_EMBARRASSED: 'CommonBuffId' = 291131 - PIER_ATTRACTIONS_HAUNTED_HOUSE_RIDE_WITH_1_B_EMBARRASSED: 'CommonBuffId' = 291139 - PIER_ATTRACTIONS_HAUNTED_HOUSE_RIDE_WITH_2_B_HAPPY: 'CommonBuffId' = 291161 - PIER_ATTRACTIONS_HAUNTED_HOUSE_RIDE_WITH_2_B_TENSE: 'CommonBuffId' = 291162 - PIER_ATTRACTIONS_HAUNTED_HOUSE_WOOHOO_1_A_SCARED: 'CommonBuffId' = 291188 - PIER_ATTRACTIONS_TUNNEL_OF_LOVE_MESS_AROUND_1_A_FLIRTY: 'CommonBuffId' = 291279 - PIER_ATTRACTIONS_TUNNEL_OF_LOVE_MESS_AROUND_1_B_CONFIDENT: 'CommonBuffId' = 291281 - PIER_ATTRACTIONS_TUNNEL_OF_LOVE_MESS_AROUND_2_A_EMBARRASSED: 'CommonBuffId' = 291284 - PIER_ATTRACTIONS_TUNNEL_OF_LOVE_RIDE_1_A_FOCUSED: 'CommonBuffId' = 291203 - PIER_ATTRACTIONS_TUNNEL_OF_LOVE_RIDE_1_A_TENSE: 'CommonBuffId' = 291205 - PIER_ATTRACTIONS_TUNNEL_OF_LOVE_RIDE_1_B_TENSE: 'CommonBuffId' = 291208 - PIER_ATTRACTIONS_TUNNEL_OF_LOVE_RIDE_2_A_CONFIDENT: 'CommonBuffId' = 291221 - PIER_ATTRACTIONS_TUNNEL_OF_LOVE_RIDE_2_B_SCARED: 'CommonBuffId' = 291223 - PIER_ATTRACTIONS_TUNNEL_OF_LOVE_RIDE_WITH_1_B_FLIRTY: 'CommonBuffId' = 291236 - PIER_ATTRACTIONS_TUNNEL_OF_LOVE_RIDE_WITH_2_A_SAD: 'CommonBuffId' = 291238 - PIER_ATTRACTIONS_TUNNEL_OF_LOVE_RIDE_WITH_2_B_SAD: 'CommonBuffId' = 291241 - PIPE_ORGAN_OMINOUS_REFRAIN: 'CommonBuffId' = 151459 - PIPE_ORGAN_VAMPIRIC_MELODY: 'CommonBuffId' = 151421 - PIT_BBQ_SERVING_THE_COMMUNITY: 'CommonBuffId' = 210737 - PIVOTAL_MOMENT_ASPIRATION_GOAL_COMPLETE_HIDDEN: 'CommonBuffId' = 357713 - PIVOTAL_MOMENT_COOLDOWN_1_HIDDEN: 'CommonBuffId' = 355472 - PIVOTAL_MOMENT_COOLDOWN_2_HIDDEN: 'CommonBuffId' = 357601 - PIVOTAL_MOMENT_COOLDOWN_3_HIDDEN: 'CommonBuffId' = 357602 - PIVOTAL_MOMENT_COOLDOWN_4_HIDDEN: 'CommonBuffId' = 357603 - PIVOTAL_MOMENT_HAS_JOB_HIDDEN: 'CommonBuffId' = 357803 - PIVOTAL_MOMENT_PHOTO_TAKEN_HIDDEN: 'CommonBuffId' = 356336 - PIVOTAL_MOMENT_REWARD_PURCHASED_HIDDEN: 'CommonBuffId' = 355574 - PIVOTAL_MOMENT_TRIGGER_1_HIDDEN: 'CommonBuffId' = 357605 - PIVOTAL_MOMENT_TRIGGER_2_HIDDEN: 'CommonBuffId' = 357606 - PIVOTAL_MOMENT_TRIGGER_3_HIDDEN: 'CommonBuffId' = 357607 - PIVOTAL_MOMENT_TRIGGER_4_HIDDEN: 'CommonBuffId' = 357608 - PIVOTAL_MOMENT_WHIM_COMPLETE_HIDDEN: 'CommonBuffId' = 356697 - PLACEMAT_INSPIRED: 'CommonBuffId' = 134050 - PLANT_MOON_PETAL_FLOWER_EATEN: 'CommonBuffId' = 291945 - PLANT_SIMS_FORBIDDEN_FRUIT_COOLDOWN: 'CommonBuffId' = 163656 - PLANT_SIMS_MAIN_VISIBLE: 'CommonBuffId' = 162844 - PLANT_SIMS_MAIN_VISIBLE_NPC: 'CommonBuffId' = 163437 - PLANT_SIMS_MOOD_AURAS_ANGRY: 'CommonBuffId' = 162841 - PLANT_SIMS_MOOD_AURAS_CONFIDENT: 'CommonBuffId' = 162837 - PLANT_SIMS_MOOD_AURAS_FLIRTY: 'CommonBuffId' = 162842 - PLANT_SIMS_MOOD_AURAS_PLAYFUL: 'CommonBuffId' = 162838 - PLANT_SIMS_MOOD_AURAS_SAD: 'CommonBuffId' = 162840 - PLANT_SIMS_MOOD_AURAS_UNCOMFORTABLE: 'CommonBuffId' = 162839 - PLANT_SIMS_PHOTOSYNTHESIS: 'CommonBuffId' = 162730 - PLANT_SIMS_SCENARIO_NOT_PLANT_SIM_INVISIBLE: 'CommonBuffId' = 294922 - PLANT_SIMS_SCENARIO_NOT_PLANT_SIM_TNS_INVISIBLE: 'CommonBuffId' = 297142 - PLANT_SIMS_SCENARIO_NOT_PLANT_SIM_VISIBLE: 'CommonBuffId' = 294909 - PLANT_SIMS_SCENARIO_REWARD_INVISIBLE: 'CommonBuffId' = 293723 - PLAYFUL_SCENT: 'CommonBuffId' = 121611 - PLAY_CHESS_FOCUSED_LOW: 'CommonBuffId' = 28269 - PLAY_CHESS_FOCUSED_MED: 'CommonBuffId' = 28271 - PLOPSY_SHIPPED: 'CommonBuffId' = 241761 - PODIUM_PAIR_DEBATE_SHOWDOWN_UNIFORM: 'CommonBuffId' = 230306 - PODIUM_PAIR_DEBATE_SHOWDOWN_UNIFORM_SCIENCE: 'CommonBuffId' = 230435 - PODIUM_PAIR_DEBATING: 'CommonBuffId' = 219247 - PODIUM_PAIR_VISIBLE_DEFT: 'CommonBuffId' = 218954 - PODIUM_PAIR_VISIBLE_DISAPPOINTING: 'CommonBuffId' = 218955 - PODIUM_PAIR_VISIBLE_DUD: 'CommonBuffId' = 218953 - PODIUM_PAIR_VISIBLE_VICTORIOUS: 'CommonBuffId' = 218950 - PODIUM_PAIR_VISIBLE_WISE_WORDS: 'CommonBuffId' = 222273 - PODIUM_PAIR_WATCHING: 'CommonBuffId' = 229809 - PODIUM_STAND_NEARBY_COOLDOWN: 'CommonBuffId' = 169459 - POISON_DYING: 'CommonBuffId' = 179683 - POISON_FEELING_ICKY: 'CommonBuffId' = 176141 - POISON_FEELING_ICKY_ANCIENT_RELIC_CURSE: 'CommonBuffId' = 179739 - POISON_FEELING_ICKY_BIT_BY_SPIDER: 'CommonBuffId' = 179740 - POISON_FEELING_ICKY_GATE: 'CommonBuffId' = 180014 - POISON_FEELING_ICKY_GHOST_BELCH: 'CommonBuffId' = 179741 - POISON_FEELING_ICKY_POISON_DART: 'CommonBuffId' = 179742 - POISON_FEELING_ICKY_POISON_GAS: 'CommonBuffId' = 180334 - POISON_FEELING_ICKY_STUNG_BY_BEE: 'CommonBuffId' = 179743 - POISON_OVERCAME_POISONING: 'CommonBuffId' = 176188 - POISON_OVERWHELMINGLY_POISONED: 'CommonBuffId' = 176189 - POISON_OVERWHELMINGLY_POISONED_ANCIENT_RELIC_CURSE: 'CommonBuffId' = 179744 - POISON_OVERWHELMINGLY_POISONED_BIT_BY_SPIDER: 'CommonBuffId' = 179745 - POISON_OVERWHELMINGLY_POISONED_GATE: 'CommonBuffId' = 180015 - POISON_OVERWHELMINGLY_POISONED_GHOST_BELCH: 'CommonBuffId' = 179746 - POISON_OVERWHELMINGLY_POISONED_POISON_DART: 'CommonBuffId' = 179747 - POISON_OVERWHELMINGLY_POISONED_POISON_GAS: 'CommonBuffId' = 180335 - POISON_OVERWHELMINGLY_POISONED_STUNG_BY_BEE: 'CommonBuffId' = 179748 - POISON_POISONED: 'CommonBuffId' = 176187 - POISON_POISONED_ANCIENT_RELIC_CURSE: 'CommonBuffId' = 179749 - POISON_POISONED_BIT_BY_SPIDER: 'CommonBuffId' = 179750 - POISON_POISONED_GATE: 'CommonBuffId' = 180016 - POISON_POISONED_GHOST_BELCH: 'CommonBuffId' = 179751 - POISON_POISONED_POISON_DART: 'CommonBuffId' = 179752 - POISON_POISONED_POISON_GAS: 'CommonBuffId' = 180336 - POISON_POISONED_STUNG_BY_BEE: 'CommonBuffId' = 179753 - POLITE_INTRODUCTION_POLITE_IS_RIGHT: 'CommonBuffId' = 161842 - POLITE_INTRODUCTION_SO_POLITE: 'CommonBuffId' = 161843 - POOLS_HYGIENE: 'CommonBuffId' = 156408 - POOLS_PLANT_SIM_WATER: 'CommonBuffId' = 164852 - POOLS_SITTING_POOL_SIDE: 'CommonBuffId' = 343464 - POOLS_SPLASHY_FUN: 'CommonBuffId' = 106177 - POOL_HAPPY_RELAXING_SWIM: 'CommonBuffId' = 103891 - POOL_TEMPERATURE_POLAR_BEAR_CLUB: 'CommonBuffId' = 180225 - POOL_TEMPERATURE_WATERS_FINE: 'CommonBuffId' = 180226 - POSITIVITY_CHALLENGE_VIEW_POSITIVITY_POSTER_TIER_1_CONFIDENT: 'CommonBuffId' = 198954 - POSITIVITY_CHALLENGE_VIEW_POSITIVITY_POSTER_TIER_1_FOCUSED: 'CommonBuffId' = 198953 - POSITIVITY_CHALLENGE_VIEW_POSITIVITY_POSTER_TIER_1_INSPIRED: 'CommonBuffId' = 198952 - POSITIVITY_CHALLENGE_VIEW_POSITIVITY_POSTER_TIER_2_CONFIDENT: 'CommonBuffId' = 198928 - POSITIVITY_CHALLENGE_VIEW_POSITIVITY_POSTER_TIER_2_FOCUSED: 'CommonBuffId' = 198956 - POSITIVITY_CHALLENGE_VIEW_POSITIVITY_POSTER_TIER_2_INSPIRED: 'CommonBuffId' = 198955 - POSITIVITY_CHALLENGE_VIEW_POSITIVITY_POSTER_TIER_3_CONFIDENT: 'CommonBuffId' = 198929 - POSITIVITY_CHALLENGE_VIEW_POSITIVITY_POSTER_TIER_3_FOCUSED: 'CommonBuffId' = 198957 - POSITIVITY_CHALLENGE_VIEW_POSITIVITY_POSTER_TIER_3_INSPIRED: 'CommonBuffId' = 198958 - POSITIVITY_CHALLENGE_VIEW_POSITIVITY_POSTER_TIER_4_CONFIDENT: 'CommonBuffId' = 198930 - POSITIVITY_CHALLENGE_VIEW_POSITIVITY_POSTER_TIER_4_FOCUSED: 'CommonBuffId' = 198959 - POSITIVITY_CHALLENGE_VIEW_POSITIVITY_POSTER_TIER_4_INSPIRED: 'CommonBuffId' = 198960 - POSITIVITY_CHALLENGE_VIEW_POSTER: 'CommonBuffId' = 198962 - POSSESSED_BEHAVIOR_EATING_INFECTED_FRUIT: 'CommonBuffId' = 203158 - POSSESSED_BEHAVIOR_FROM_ALLURING_MOTHER_PLANT: 'CommonBuffId' = 204371 - POSSESSED_BEHAVIOR_FROM_INFECTION_SCANNER: 'CommonBuffId' = 203389 - POSSESSED_BEHAVIOR_FROM_INFECTION_TIME: 'CommonBuffId' = 203122 - POSSESSED_BEHAVIOR_FROM_MOTHER_PLANT_LOSE: 'CommonBuffId' = 205282 - POSSESSED_BEHAVIOR_FROM_SPORE_HALLWAY: 'CommonBuffId' = 203702 - POSSESSED_BEHAVIOR_INFECTED_ATTACK: 'CommonBuffId' = 204729 - POSSESSED_BEHAVIOR_WALK_BY: 'CommonBuffId' = 204018 - POSSESSED_BEHAVIOR_WELCOME_WAGON: 'CommonBuffId' = 204536 - POSSESSED_JUICE_FIZZER_EP09_ADD_WALK_STYLE: 'CommonBuffId' = 236683 - POSSESSED_PLANT_SPORE_COOLDOWN: 'CommonBuffId' = 202902 - POSSESSED_PRE_WELCOME_WAGON: 'CommonBuffId' = 204537 - POSSESSED_TEND_INFECTED_PLANT_COOLDOWN: 'CommonBuffId' = 205352 - POSSESSED_VISIBLE: 'CommonBuffId' = 205491 - POSSESSED_WELCOME_WAGON_TIMED: 'CommonBuffId' = 205505 - POUNCE_STALK: 'CommonBuffId' = 171570 - PRAISE_GRADES_CONFIDENT: 'CommonBuffId' = 98981 - PREGNANCY_FREEZE_PROGRESS: 'CommonBuffId' = 248750 - PREGNANCY_IN_HEAT_ATTRACTOR: 'CommonBuffId' = 169035 - PREGNANCY_IN_HEAT_COOLDOWN: 'CommonBuffId' = 169036 - PREGNANCY_IN_LABOR: 'CommonBuffId' = 75271 - PREGNANCY_IN_LABOR_MALE: 'CommonBuffId' = 102463 - PREGNANCY_IN_LABOR_PET_CAT: 'CommonBuffId' = 169229 - PREGNANCY_IN_LABOR_PET_DOG: 'CommonBuffId' = 169251 - PREGNANCY_IN_LABOR_PET_HORSE: 'CommonBuffId' = 323055 - PREGNANCY_LABOR_REACT: 'CommonBuffId' = 98878 - PREGNANCY_NOT_PREGNANT: 'CommonBuffId' = 104000 - PREGNANCY_NOT_PREGNANT_HATES_CHILDREN: 'CommonBuffId' = 132010 - PREGNANCY_NOT_SHOWING: 'CommonBuffId' = 12560 - PREGNANCY_NOT_SHOWING_MALE: 'CommonBuffId' = 113493 - PREGNANCY_NOT_SHOWING_PET_CAT: 'CommonBuffId' = 169230 - PREGNANCY_NOT_SHOWING_PET_DOG: 'CommonBuffId' = 169250 - PREGNANCY_NOT_SHOWING_PET_HORSE: 'CommonBuffId' = 323051 - PREGNANCY_POST_LABOR_WORK_PERFORMANCE_MOD: 'CommonBuffId' = 103279 - PREGNANCY_TODDLER_FAMILY_LEAVE: 'CommonBuffId' = 157206 - PREGNANCY_TRIMESTER1: 'CommonBuffId' = 12561 - PREGNANCY_TRIMESTER1_HATES_CHILDREN: 'CommonBuffId' = 97309 - PREGNANCY_TRIMESTER1_MALE: 'CommonBuffId' = 102464 - PREGNANCY_TRIMESTER1_PET_CAT: 'CommonBuffId' = 169232 - PREGNANCY_TRIMESTER1_PET_DOG: 'CommonBuffId' = 169249 - PREGNANCY_TRIMESTER1_PET_HORSE: 'CommonBuffId' = 323052 - PREGNANCY_TRIMESTER2: 'CommonBuffId' = 12562 - PREGNANCY_TRIMESTER2_HATES_CHILDREN: 'CommonBuffId' = 97310 - PREGNANCY_TRIMESTER2_MALE: 'CommonBuffId' = 102465 - PREGNANCY_TRIMESTER2_PET_CAT: 'CommonBuffId' = 169233 - PREGNANCY_TRIMESTER2_PET_DOG: 'CommonBuffId' = 169248 - PREGNANCY_TRIMESTER2_PET_HORSE: 'CommonBuffId' = 323053 - PREGNANCY_TRIMESTER3: 'CommonBuffId' = 12563 - PREGNANCY_TRIMESTER3_HATES_CHILDREN: 'CommonBuffId' = 97311 - PREGNANCY_TRIMESTER3_MALE: 'CommonBuffId' = 102466 - PREGNANCY_TRIMESTER3_PET_CAT: 'CommonBuffId' = 169234 - PREGNANCY_TRIMESTER3_PET_DOG: 'CommonBuffId' = 169247 - PREGNANCY_TRIMESTER3_PET_HORSE: 'CommonBuffId' = 323054 - PRESENT_PILE_BAD_PRESENT: 'CommonBuffId' = 180956 - PRESENT_PILE_CAUGHT_PRANKING: 'CommonBuffId' = 185925 - PRESENT_PILE_CAUGHT_STEALING: 'CommonBuffId' = 181000 - PRESENT_PILE_GET_EXCITED: 'CommonBuffId' = 181006 - PRESENT_PILE_OPEN_COOLDOWN: 'CommonBuffId' = 180903 - PRESENT_PILE_PERFECT_PRESENT: 'CommonBuffId' = 180961 - PRESENT_PILE_SNEAK_COOLDOWN: 'CommonBuffId' = 190976 - PRESSURE_COOKER_SIMMERING_SATISFACTION: 'CommonBuffId' = 344658 - PRESSURE_COOKER_TOILANDTROUBLE: 'CommonBuffId' = 344659 - PREVENT_BUCK_OFF_OR_PUT_DOWN_SIM: 'CommonBuffId' = 330347 - PREVENT_DISMOUNTING: 'CommonBuffId' = 328887 - PREVENT_RUNNING: 'CommonBuffId' = 74343 - PRIVACY_EMBARRASSED: 'CommonBuffId' = 10425 - PRIVACY_EMBARRASSED_SHOWER_WALL: 'CommonBuffId' = 229668 - PRIVACY_EMBARRASSED_TARGET: 'CommonBuffId' = 99779 - PRIVACY_IMMUNE: 'CommonBuffId' = 39303 - PROFESSOR_NPC_ASK_FOR_HIGHER_GRADE_0_EMBARRASSED: 'CommonBuffId' = 225289 - PROFESSOR_NPC_ASK_FOR_HIGHER_GRADE_0_TENSE: 'CommonBuffId' = 225290 - PROFESSOR_NPC_ASK_FOR_HIGHER_GRADE_1_CONFIDENT: 'CommonBuffId' = 225294 - PROFESSOR_NPC_ASK_FOR_HIGHER_GRADE_1_EMBARRASSED: 'CommonBuffId' = 225291 - PROFESSOR_NPC_ASK_FOR_HIGHER_GRADE_1_TENSE: 'CommonBuffId' = 225293 - PROFESSOR_NPC_ASK_FOR_HIGHER_GRADE_1_UNCOMFORTABLE: 'CommonBuffId' = 225292 - PROFESSOR_NPC_ASK_FOR_HIGHER_GRADE_2_CONFIDENT: 'CommonBuffId' = 225384 - PROFESSOR_NPC_ASK_FOR_HIGHER_GRADE_2_TENSE: 'CommonBuffId' = 225295 - PROFESSOR_NPC_ASK_FOR_HIGHER_GRADE_2_UNCOMFORTABLE: 'CommonBuffId' = 227869 - PROFESSOR_NPC_ASK_FOR_HIGHER_GRADE_COOLDOWN_A: 'CommonBuffId' = 225698 - PROFESSOR_NPC_ASK_FOR_HIGHER_GRADE_COOLDOWN_B: 'CommonBuffId' = 225699 - PROFESSOR_NPC_ASK_FOR_HIGHER_GRADE_COOLDOWN_C: 'CommonBuffId' = 225700 - PROFESSOR_NPC_ASK_FOR_HIGHER_GRADE_COOLDOWN_D: 'CommonBuffId' = 225701 - PROFESSOR_NPC_ASK_FOR_HIGHER_GRADE_HIDDEN_ANGRY: 'CommonBuffId' = 225299 - PROFESSOR_NPC_ASK_FOR_HIGHER_GRADE_HIDDEN_UNCOMFORTABLE: 'CommonBuffId' = 225300 - PROFESSOR_NPC_ASK_FOR_HIGHER_GRADE_TERM_COOLDOWN_A: 'CommonBuffId' = 225782 - PROFESSOR_NPC_ASK_FOR_HIGHER_GRADE_TERM_COOLDOWN_B: 'CommonBuffId' = 225783 - PROFESSOR_NPC_ASK_FOR_HIGHER_GRADE_TERM_COOLDOWN_C: 'CommonBuffId' = 225784 - PROFESSOR_NPC_ASK_FOR_HIGHER_GRADE_TERM_COOLDOWN_D: 'CommonBuffId' = 225785 - PROMISE_RINGS_REJECTED: 'CommonBuffId' = 99508 - PROMO_NIGHT_GENERAL: 'CommonBuffId' = 124256 - PROTEIN_SHAKE: 'CommonBuffId' = 38979 - PROXIMITY_EMBARRASSED_BY_POOR_PLAYING: 'CommonBuffId' = 38910 - PROXIMITY_HATES_CHILDREN: 'CommonBuffId' = 10605 - PROXIMITY_HATES_CHILDREN_TENSE: 'CommonBuffId' = 258976 - PROXIMITY_OBJECT_ROMANTIC_FIREPLACE: 'CommonBuffId' = 135671 - PROXIMITY_POOR_PLAYING: 'CommonBuffId' = 38898 - PROXIMITY_TRAIT_CHILD_SKILL_PACK_ANIMAL: 'CommonBuffId' = 308831 - PTO_IN_NEED_OF_A_BREAK: 'CommonBuffId' = 111110 - PTO_NEEDS_A_DAY_OFF: 'CommonBuffId' = 111111 - PTO_NEEDS_A_VACATION: 'CommonBuffId' = 111112 - PUBERTY_CHANGES_ACNE_REMOVED: 'CommonBuffId' = 286428 - PUBERTY_CHANGES_CLEANSER_HIDDEN: 'CommonBuffId' = 302584 - PUBERTY_CHANGES_CONCEALER_FAIL: 'CommonBuffId' = 286275 - PUBERTY_CHANGES_CONCEALER_SUCCESS_HIDDEN: 'CommonBuffId' = 286276 - PUBERTY_CHANGES_CURRENTLY_SHAVING_BG: 'CommonBuffId' = 305278 - PUBERTY_CHANGES_GROWTH_ACNE: 'CommonBuffId' = 286425 - PUBERTY_CHANGES_GROWTH_FIRST_TIME: 'CommonBuffId' = 286424 - PUBERTY_CHANGES_GROWTH_HAIR_HAPPY: 'CommonBuffId' = 286427 - PUBERTY_CHANGES_GROWTH_HAIR_NEGATIVE: 'CommonBuffId' = 286497 - PUBERTY_CHANGES_HAS_ACNE: 'CommonBuffId' = 303135 - PUBERTY_CHANGES_MOCKED_ACNE: 'CommonBuffId' = 286430 - PUBERTY_CHANGES_MOCKED_HAIR: 'CommonBuffId' = 286431 - PUBERTY_CHANGES_MOCKED_HIDDEN: 'CommonBuffId' = 286498 - PUBERTY_CHANGES_SHAVING_NICKS: 'CommonBuffId' = 286429 - PUBERTY_CHANGES_SUPPORT: 'CommonBuffId' = 286426 - PUBERTY_CHANGES_SUPPORTED_HIDDEN: 'CommonBuffId' = 286474 - PUMPED_UP: 'CommonBuffId' = 27703 - PUNCHING_BAG_FEELING_FEARLESS: 'CommonBuffId' = 26576 - PUNCHING_BAG_FLYING_FEET: 'CommonBuffId' = 39349 - PUPPET_THEATER_ANNOYING_PUPPETS: 'CommonBuffId' = 133838 - PUPPET_THEATER_ENJOYABLE_PUPPET_SHOW: 'CommonBuffId' = 133836 - PUPPET_THEATER_GOOD_EFFORT: 'CommonBuffId' = 133837 - PUPPET_THEATER_GREAT_PERFORMANCE: 'CommonBuffId' = 133834 - PUPPET_THEATER_HIDDEN_MAKE_A_MISTAKE: 'CommonBuffId' = 133877 - PUPPET_THEATER_MADE_MISTAKES: 'CommonBuffId' = 133835 - QUADCOPTER_PLAY: 'CommonBuffId' = 224438 - QUICK_SOCIAL_COOLDOWN_JUICE_KEG_PARTY_SOCIALS: 'CommonBuffId' = 228627 - QUIRK_COOLDOWNS_FEAR_COFFEE_MAKER: 'CommonBuffId' = 168373 - QUIRK_COOLDOWNS_FEAR_COMPUTER: 'CommonBuffId' = 168375 - QUIRK_COOLDOWNS_FEAR_DISHWASHER: 'CommonBuffId' = 168376 - QUIRK_COOLDOWNS_FEAR_DOORBELL: 'CommonBuffId' = 168400 - QUIRK_COOLDOWNS_FEAR_FIRE: 'CommonBuffId' = 168377 - QUIRK_COOLDOWNS_FEAR_FITNESS_EQUIPMENT: 'CommonBuffId' = 168378 - QUIRK_COOLDOWNS_FEAR_GAMING: 'CommonBuffId' = 168379 - QUIRK_COOLDOWNS_FEAR_INSTRUMENT: 'CommonBuffId' = 168380 - QUIRK_COOLDOWNS_FEAR_MICROWAVE: 'CommonBuffId' = 168381 - QUIRK_COOLDOWNS_FEAR_ROBOT_VACUUM: 'CommonBuffId' = 172030 - QUIRK_COOLDOWNS_FEAR_SHOWER: 'CommonBuffId' = 168382 - QUIRK_COOLDOWNS_FEAR_STEREO: 'CommonBuffId' = 168383 - QUIRK_COOLDOWNS_FEAR_STOVE: 'CommonBuffId' = 168384 - QUIRK_COOLDOWNS_FEAR_SWIMMING: 'CommonBuffId' = 168385 - QUIRK_COOLDOWNS_FEAR_TOILET: 'CommonBuffId' = 168386 - QUIRK_COOLDOWNS_FEAR_TV: 'CommonBuffId' = 168387 - QUIRK_COOLDOWNS_FEAR_VACUUM: 'CommonBuffId' = 257145 - RAIN_RUN_COOLDOWN: 'CommonBuffId' = 184967 - RAIN_RUN_COOLDOWN_PLAY_IN_RAIN: 'CommonBuffId' = 191266 - REACTION_BREAK_INVESTIGATION: 'CommonBuffId' = 159914 - REACTION_BREAK_SOCIAL_CHAT: 'CommonBuffId' = 126524 - REACTION_COOLDOWN_DISGUSTED_FROM_OBJECT: 'CommonBuffId' = 141678 - REACTION_COOLDOWN_SHOCKED_FROM_OBJECT: 'CommonBuffId' = 141677 - REACTION_EXIT_WATCH_TV: 'CommonBuffId' = 130305 - READ_ANGRY_LOW: 'CommonBuffId' = 12565 - READ_BORING_LOW: 'CommonBuffId' = 12566 - READ_CAMPING_HAPPY: 'CommonBuffId' = 109380 - READ_CONFIDENT_LOW: 'CommonBuffId' = 12567 - READ_FLIRTY_LOW: 'CommonBuffId' = 12568 - READ_FOCUSED_LOW: 'CommonBuffId' = 12569 - READ_HAPPY_LOW: 'CommonBuffId' = 12570 - READ_INSPIRED_LOW: 'CommonBuffId' = 12571 - READ_KIDS_BOOK_HATES_CHILDREN: 'CommonBuffId' = 100439 - READ_PLAYFUL_DIRTY: 'CommonBuffId' = 12572 - READ_PLAYFUL_LOW: 'CommonBuffId' = 12573 - READ_SAD_LOW: 'CommonBuffId' = 12574 - READ_SKILL_TOO_EASY: 'CommonBuffId' = 12575 - READ_SKILL_TOO_HARD: 'CommonBuffId' = 12576 - READ_TO_CHILDREN_HIDDEN: 'CommonBuffId' = 328766 - REAPER_PLEADED_TO: 'CommonBuffId' = 37235 - RECENTLY_PREPARED_FOOD_HIDDEN: 'CommonBuffId' = 149760 - RECENTLY_SURVEYED: 'CommonBuffId' = 177627 - RECENT_STARGAZE: 'CommonBuffId' = 181095 - RECREATION_TABLE_FINISHED_PUZZLE_MISSING_PIECE: 'CommonBuffId' = 317698 - RECREATION_TABLE_PUZZLES_BORED: 'CommonBuffId' = 308438 - RECREATION_TABLE_PUZZLES_FINISHED_PUZZLE: 'CommonBuffId' = 308437 - RECREATION_TABLE_PUZZLES_OTHER_SMASHED: 'CommonBuffId' = 308571 - RECREATION_TABLE_PUZZLES_PIECE_OUT: 'CommonBuffId' = 308439 - RECREATION_TABLE_PUZZLES_PILE_BACKUP: 'CommonBuffId' = 318759 - RECREATION_TABLE_PUZZLES_REPLACE_FINAL_PIECE: 'CommonBuffId' = 308440 - RECREATION_TABLE_PUZZLES_SMASHED: 'CommonBuffId' = 308572 - RECREATION_TABLE_PUZZLES_SMASHED_TIMEOUT_HIDDEN: 'CommonBuffId' = 332100 - RECREATION_TABLE_PUZZLES_STEAL_PIECE: 'CommonBuffId' = 318799 - RECREATION_TABLE_SIMBLES_DOMINOES_LOSE: 'CommonBuffId' = 309428 - RECREATION_TABLE_SIMBLES_DOMINOES_PRACTICE_TEXT_TEST: 'CommonBuffId' = 330697 - RECREATION_TABLE_SIMBLES_DOMINOES_TRAY_BACKUP: 'CommonBuffId' = 318760 - RECREATION_TABLE_SIMBLES_DOMINOES_WIN: 'CommonBuffId' = 309427 - REGIONAL_GREETING_REGIONALTRAIT: 'CommonBuffId' = 339032 - REGION_CAMPING_FOREST: 'CommonBuffId' = 104835 - REGION_GENERIC: 'CommonBuffId' = 251292 - REGION_GENERIC_ALIEN_WORLD: 'CommonBuffId' = 252278 - REGION_GENERIC_BAY_AREA: 'CommonBuffId' = 302933 - REGION_GENERIC_COTTAGE_WORLD: 'CommonBuffId' = 269827 - REGION_GENERIC_DESTINATION: 'CommonBuffId' = 252222 - REGION_GENERIC_WEDDING_WORLD: 'CommonBuffId' = 285873 - REGION_VACATION_HOMESICK: 'CommonBuffId' = 251305 - REGION_VENUE_AT_PARK: 'CommonBuffId' = 324092 - REJECTED_BY_LOVER: 'CommonBuffId' = 100140 - REJECTED_PROPOSAL: 'CommonBuffId' = 98081 - RELATIONSHIP_APPROPRIATENESS_FRIENDS: 'CommonBuffId' = 75272 - RELATIONSHIP_APPROPRIATENESS_LOVERS: 'CommonBuffId' = 75274 - RELATIONSHIP_BROKEN_UP_FRIENDS_HIDDEN: 'CommonBuffId' = 289781 - RELATIONSHIP_BROKE_UP_ANGRY: 'CommonBuffId' = 77253 - RELATIONSHIP_BROKE_UP_GLOOMY_TRAIT: 'CommonBuffId' = 77265 - RELATIONSHIP_BROKE_UP_SAD: 'CommonBuffId' = 77249 - RELATIONSHIP_COUNSELING_COOLDOWN_HIDDEN: 'CommonBuffId' = 375606 - RELATIONSHIP_COUNSELING_GOAL_OF_ATTRACTION: 'CommonBuffId' = 375216 - RELATIONSHIP_COUNSELING_GOAL_OF_PERFECT_DATES: 'CommonBuffId' = 375218 - RELATIONSHIP_COUNSELING_GOAL_OF_ROMANTIC_IMPROVEMENT: 'CommonBuffId' = 375217 - RELATIONSHIP_COUNSELING_GOAL_OF_TRYING_SOMETHING_NEW: 'CommonBuffId' = 375219 - RELATIONSHIP_COUNSELING_IN_RELATIONSHIP_COUNSELING_HIDDEN: 'CommonBuffId' = 375140 - RELATIONSHIP_COUNSELING_IN_THERAPY: 'CommonBuffId' = 375222 - RELATIONSHIP_COUNSELING_I_SAID_IM_OK: 'CommonBuffId' = 375215 - RELATIONSHIP_COUNSELING_NEEDS_MORE_THERAPY: 'CommonBuffId' = 375220 - RELATIONSHIP_COUNSELING_THERAPY_BLUES: 'CommonBuffId' = 375223 - RELATIONSHIP_COUNSELING_THERAPY_IS_A_SCAM: 'CommonBuffId' = 375221 - RELATIONSHIP_COUNSELING_THEY_THINK_IM_NUTS: 'CommonBuffId' = 375144 - RELATIONSHIP_COUNSELING_WE_NEED_THERAPY: 'CommonBuffId' = 375143 - RELATIONSHIP_COUNSELING_WINNING_AT_THERAPY: 'CommonBuffId' = 375214 - RELATIONSHIP_EXPECTATIONS_CHANGE_OUTLOOK_COOLDOWN_HIDDEN: 'CommonBuffId' = 364923 - RELATIONSHIP_GOT_DIVORCED: 'CommonBuffId' = 32616 - RELATIONSHIP_GOT_ENGAGED: 'CommonBuffId' = 32615 - RELATIONSHIP_GOT_WIDOW: 'CommonBuffId' = 102085 - RELATIONSHIP_GOT_WIDOWER: 'CommonBuffId' = 102921 - RELATIONSHIP_HAD_WEDDING: 'CommonBuffId' = 12587 - RELATIONSHIP_NEW_BFF: 'CommonBuffId' = 77196 - RELATIONSHIP_NEW_ENEMY: 'CommonBuffId' = 77194 - RELATIONSHIP_NEW_ENEMY_EVIL: 'CommonBuffId' = 97373 - RELATIONSHIP_NEW_FRIEND: 'CommonBuffId' = 97650 - RELATIONSHIP_NEW_PARTNER: 'CommonBuffId' = 98092 - RELATIONSHIP_PROMISED: 'CommonBuffId' = 99474 - RELATIONSHIP_RENEWED_VOWS: 'CommonBuffId' = 99618 - RELATIONSHIP_RENEW_VOWS_COOLDOWN: 'CommonBuffId' = 97281 - RELATIONSHIP_SATISFACTION_ITS_COMPLICATED: 'CommonBuffId' = 364561 - RELATIONSHIP_SATISFACTION_MUTUALLY_DISSATISFIED: 'CommonBuffId' = 364560 - RELATIONSHIP_SATISFACTION_MUTUALLY_SATISFIED: 'CommonBuffId' = 364559 - RELATIONSHIP_SATISFACTION_REL_BIT_1_VERY_UNSATISFIED: 'CommonBuffId' = 364007 - RELATIONSHIP_SATISFACTION_REL_BIT_2_UNSATISFIED: 'CommonBuffId' = 364008 - RELATIONSHIP_SATISFACTION_REL_BIT_4_SATISFIED: 'CommonBuffId' = 364009 - RELATIONSHIP_SATISFACTION_REL_BIT_5_VERY_SATISIFED: 'CommonBuffId' = 364010 - RELATIONSHIP_SATISFACTION_TOTO_TNS_INFO_DELAY_HIDDEN: 'CommonBuffId' = 377156 - RELATIONSHIP_TODDLER_CAREGIVER: 'CommonBuffId' = 146494 - RELATIONSHIP_TODDLER_CAREGIVER_AUTONOMY: 'CommonBuffId' = 333126 - RELATIONSHIP_VERY_APPROPRIATE: 'CommonBuffId' = 74424 - RELATIONSHIP_WATCHED_WEDDING_HAPPY: 'CommonBuffId' = 12604 - RELATIONSHIP_WEDDING_CHEER_FAIL: 'CommonBuffId' = 12606 - RELATIONSHIP_WEDDING_CHEER_SUCCESS: 'CommonBuffId' = 12607 - RELATIONSHIP_WEDDING_DODGED_A_BULLET: 'CommonBuffId' = 12608 - RELATIONSHIP_WEDDING_HECKLE_FAIL: 'CommonBuffId' = 12609 - RELATIONSHIP_WEDDING_HECKLE_SUCCESS: 'CommonBuffId' = 12610 - RELATIONSHIP_WEDDING_HECKLE_SUCCESS_TARGET: 'CommonBuffId' = 12611 - RELATIONSHIP_WEDDING_LEFT_AT_THE_ALTAR: 'CommonBuffId' = 12612 - RELAXED_IN_BED: 'CommonBuffId' = 12613 - REPOMAN_CANT_REPO_ME: 'CommonBuffId' = 235069 - REPOMAN_INCREASE_FAILURE_CHANCE: 'CommonBuffId' = 235077 - REPOMAN_LOCKOUT_ALWAYS_FAIL: 'CommonBuffId' = 235061 - REPOMAN_LOCKOUT_APPEAL_TO_HUMANITY: 'CommonBuffId' = 235075 - REPOMAN_LOCKOUT_BRIBE: 'CommonBuffId' = 235078 - REPOMAN_LOCKOUT_FIGHT_THE_MAN: 'CommonBuffId' = 235074 - REPOMAN_REPO_BEAT_DOWN: 'CommonBuffId' = 235071 - REPOMAN_STUFF_TAKEN: 'CommonBuffId' = 241177 - REPOMAN_TAKE_OBJECT_TNS_COOLDOWN: 'CommonBuffId' = 360523 - REPO_OCCURRED: 'CommonBuffId' = 228341 - REPUTATION_HAS_BEEN_RANK_0: 'CommonBuffId' = 202632 - REPUTATION_HAS_BEEN_RANK_1: 'CommonBuffId' = 202680 - REPUTATION_HAS_BEEN_RANK_2: 'CommonBuffId' = 202681 - REPUTATION_HAS_BEEN_RANK_3: 'CommonBuffId' = 202682 - REPUTATION_HAS_BEEN_RANK_4: 'CommonBuffId' = 202683 - REPUTATION_HAS_BEEN_RANK_5: 'CommonBuffId' = 202684 - REPUTATION_HAS_BEEN_RANK_6: 'CommonBuffId' = 202685 - REPUTATION_PRISTINE_FRIENDSHIP: 'CommonBuffId' = 196112 - REPUTATION_SEEN: 'CommonBuffId' = 197339 - REPUTATION_TERRIBLE_FRIENDSHIP: 'CommonBuffId' = 202783 - REQUIRED_INGREDIENTS_HIDDEN: 'CommonBuffId' = 258830 - REQUIRED_INGREDIENTS_SELF_SUSTAINING: 'CommonBuffId' = 263862 - RESEARCHED_COOKING_TECHNIQUE: 'CommonBuffId' = 28605 - RESEARCHED_GARDENING: 'CommonBuffId' = 35943 - RESEARCHED_GUITAR: 'CommonBuffId' = 34497 - RESEARCHED_PIANO: 'CommonBuffId' = 34499 - RESEARCHED_VIOLIN: 'CommonBuffId' = 34498 - RESEARCH_MACHINE_HIDDEN_RISKY: 'CommonBuffId' = 228202 - RESEARCH_MACHINE_MENTALLY_DRAINED: 'CommonBuffId' = 228197 - RESEARCH_MACHINE_WELL_RESEARCHED: 'CommonBuffId' = 227545 - RESOLUTIONS_BARELY_MADE_IT: 'CommonBuffId' = 187826 - RESOLUTIONS_COMPLETE_BETTER_STUDENT: 'CommonBuffId' = 187838 - RESOLUTIONS_COMPLETE_COMPLETE_ASPIRATION_MILESTONE: 'CommonBuffId' = 187830 - RESOLUTIONS_COMPLETE_GET_BOYFRIEND_GIRLFRIEND: 'CommonBuffId' = 187834 - RESOLUTIONS_COMPLETE_GET_FIT: 'CommonBuffId' = 187833 - RESOLUTIONS_COMPLETE_GET_MORE_FOLLOWERS: 'CommonBuffId' = 187835 - RESOLUTIONS_COMPLETE_GET_PROMOTED: 'CommonBuffId' = 187831 - RESOLUTIONS_COMPLETE_GET_PROMOTED_SCOUTS: 'CommonBuffId' = 187837 - RESOLUTIONS_COMPLETE_LOSE_WEIGHT: 'CommonBuffId' = 187832 - RESOLUTIONS_COMPLETE_RAISE_SKILL: 'CommonBuffId' = 187836 - RESOLUTIONS_COMPLETE_WRITE_BOOK: 'CommonBuffId' = 187839 - RESOLUTIONS_FAILED_RESOLUTION: 'CommonBuffId' = 187828 - RESOLUTIONS_HIDDEN_COOLDOWN: 'CommonBuffId' = 186707 - RESOLUTIONS_HIDDEN_HAS_RESOLUTION: 'CommonBuffId' = 188005 - RESOLUTIONS_RESOLUTIONS_DONT_MATTER: 'CommonBuffId' = 187827 - RESOLUTIONS_RESOLUTION_DUE: 'CommonBuffId' = 187825 - RESOLUTION_MADE: 'CommonBuffId' = 186704 - RESTAURANTS_DINER_BASIC_ARRIVAL: 'CommonBuffId' = 132493 - RESTAURANTS_DINER_BASIC_CHECK_IN: 'CommonBuffId' = 132578 - RESTAURANTS_DINER_BASIC_EAT_FOOD: 'CommonBuffId' = 139028 - RESTAURANTS_DINER_BASIC_EAT_FOOD_CRITIC: 'CommonBuffId' = 141470 - RESTAURANTS_DINER_BASIC_ORDER_FROM_CHEF: 'CommonBuffId' = 132624 - RESTAURANTS_DINER_BASIC_POST_PLACE_ORDER: 'CommonBuffId' = 133233 - RESTAURANTS_DINER_BASIC_PREPARE_TO_LEAVE: 'CommonBuffId' = 133350 - RESTAURANTS_DINER_BASIC_PREPARE_TO_LEAVE_CRITIC: 'CommonBuffId' = 143683 - RESTAURANTS_DINER_BASIC_PRE_PLACE_ORDER: 'CommonBuffId' = 132667 - RESTAURANTS_DINER_BASIC_PRE_ROLL_ORDER: 'CommonBuffId' = 132860 - RESTAURANTS_DINER_BASIC_WAIT_FOR_FOOD: 'CommonBuffId' = 133109 - RESTAURANTS_DINER_BASIC_WAIT_FOR_FOOD_FROM_WAIT_STAFF: 'CommonBuffId' = 134378 - RESTAURANTS_DINER_BASIC_WAIT_FOR_TABLE: 'CommonBuffId' = 132654 - RESTAURANTS_DINER_HAPPY_DATE_FLIRTY: 'CommonBuffId' = 132702 - RESTAURANTS_DINER_PLAYER_PRE_PLACE_ORDER: 'CommonBuffId' = 133218 - RESTAURANTS_DINER_PLAYER_WAIT_FOR_FOOD_FROM_WAIT_STAFF: 'CommonBuffId' = 134375 - RESTAURANTS_DINER_WAIT_FOR_FOOD_STOP_DOING_STUFF: 'CommonBuffId' = 133110 - RESTAURANTS_FLIRTY_BREAKFAST: 'CommonBuffId' = 133358 - RESTAURANTS_FLIRTY_DINNER: 'CommonBuffId' = 133360 - RESTAURANTS_FLIRTY_LUNCH: 'CommonBuffId' = 133359 - RESTAURANTS_HAPPY_BREAKFAST: 'CommonBuffId' = 133355 - RESTAURANTS_HAPPY_DINNER: 'CommonBuffId' = 133357 - RESTAURANTS_HAPPY_LUNCH: 'CommonBuffId' = 133356 - RESTAURANTS_HIDDEN_FLIRTY_BREAKFAST: 'CommonBuffId' = 133602 - RESTAURANTS_HIDDEN_FLIRTY_DINNER: 'CommonBuffId' = 133604 - RESTAURANTS_HIDDEN_FLIRTY_LUNCH: 'CommonBuffId' = 133603 - RESTAURANTS_HIDDEN_HAPPY_BREAKFAST: 'CommonBuffId' = 133361 - RESTAURANTS_HIDDEN_HAPPY_DINNER: 'CommonBuffId' = 133601 - RESTAURANTS_HIDDEN_HAPPY_LUNCH: 'CommonBuffId' = 133600 - RESTAURANTS_HOST_ARRIVAL: 'CommonBuffId' = 132468 - RESTAURANTS_HOST_IDLE_AT_STATION: 'CommonBuffId' = 132576 - RESTAURANTS_HOST_SHOW_TO_TABLE: 'CommonBuffId' = 135131 - RESTAURANTS_RESTAURANT_AT_WORK: 'CommonBuffId' = 144763 - RESTAURANTS_WAITSTAFF_CLEAN: 'CommonBuffId' = 135847 - RESTAURANTS_WAITSTAFF_IDLE: 'CommonBuffId' = 133363 - RESTAURANT_BANNED: 'CommonBuffId' = 132849 - RETAIL_ADD_REL_BIT_EMPLOYEES_WONT_TALK_TO_LOT_OWNERS: 'CommonBuffId' = 117021 - RETAIL_CHECKOUT_TIMER_FREEZE: 'CommonBuffId' = 112180 - RETAIL_CHECK_ON_EMPLOYEE_COOLDOWN: 'CommonBuffId' = 116664 - RETAIL_CUSTOMER_START_WAITING_FOR_CHECKOUT: 'CommonBuffId' = 112198 - RETAIL_EMPLOYEE_CHANCE_TO_SLACK: 'CommonBuffId' = 115969 - RETAIL_EMPLOYEE_LEAVING_DUE_TO_TIME: 'CommonBuffId' = 116599 - RETAIL_EMPLOYEE_SATISFACTION_MODIFIERS_PAY_0_PAID_ADEQUATELY: 'CommonBuffId' = 112026 - RETAIL_EMPLOYEE_SATISFACTION_MODIFIERS_PAY_MINU_S1_UNDERPAID: 'CommonBuffId' = 112022 - RETAIL_EMPLOYEE_SATISFACTION_MODIFIERS_PAY_MINU_S2_VERY_UNDERPAID: 'CommonBuffId' = 112023 - RETAIL_EMPLOYEE_SATISFACTION_MODIFIERS_PAY_MINU_S3_SEVERELY_UNDERPAID: 'CommonBuffId' = 112024 - RETAIL_EMPLOYEE_SATISFACTION_MODIFIERS_PAY_MINU_S4_GROSSLY_UNDERPAID: 'CommonBuffId' = 112025 - RETAIL_EMPLOYEE_SATISFACTION_MODIFIERS_PAY_PLU_S1_OVERPAID: 'CommonBuffId' = 112027 - RETAIL_EMPLOYEE_SATISFACTION_MODIFIERS_PAY_PLU_S2_VERY_OVERPAID: 'CommonBuffId' = 112028 - RETAIL_EMPLOYEE_SATISFACTION_MODIFIERS_PAY_PLU_S3_SEVERELY_OVERPAID: 'CommonBuffId' = 112021 - RETAIL_EMPLOYEE_SATISFACTION_MODIFIERS_PAY_PLU_S4_GROSSLY_OVERPAID: 'CommonBuffId' = 112020 - RETAIL_EMPLOYEE_SATISFACTION_STATES_NEUTRAL: 'CommonBuffId' = 112068 - RETAIL_EMPLOYEE_SATISFACTION_STATES_SATISFIED: 'CommonBuffId' = 112070 - RETAIL_EMPLOYEE_SATISFACTION_STATES_UNSATISFIED: 'CommonBuffId' = 112071 - RETAIL_EMPLOYEE_SATISFACTION_STATES_VERY_SATISFIED: 'CommonBuffId' = 112069 - RETAIL_EMPLOYEE_SATISFACTION_STATES_VERY_UNSATISFIED: 'CommonBuffId' = 112072 - RETAIL_EMPLOYEE_SUPPRESS_FRONT_PAGE: 'CommonBuffId' = 115932 - RETAIL_LAUGH_AT_BROKEN_SIGN_COOLDOWN: 'CommonBuffId' = 110969 - RETAIL_PRAISE_EMPLOYEE_COOLDOWN: 'CommonBuffId' = 115328 - RETAIL_RECENT_PURCHASE: 'CommonBuffId' = 112137 - RETAIL_SURE_SALE_COOLDOWN: 'CommonBuffId' = 112363 - RETAIL_TIRED_OF_WAITING: 'CommonBuffId' = 112135 - RETAIL_TREND_SETTER: 'CommonBuffId' = 114680 - RETAIL_WAIT_TO_PURCHASE: 'CommonBuffId' = 112134 - RETAIL_WHAT_DID_IT_SPELL: 'CommonBuffId' = 110971 - RETURNED_FROM_ABDUCTION_ANGRY: 'CommonBuffId' = 114922 - RETURNED_FROM_ABDUCTION_DAZED: 'CommonBuffId' = 114921 - RETURNED_FROM_ABDUCTION_FOCUSED: 'CommonBuffId' = 114923 - REVEALED_DEEP_SECRET: 'CommonBuffId' = 77069 - RICHLY_SCENTED: 'CommonBuffId' = 118505 - RILED_UP_HOTHEADED: 'CommonBuffId' = 27745 - RILED_UP_HOTHEADED_PRANK: 'CommonBuffId' = 258442 - RILED_UP_HOTHEADED_WORK: 'CommonBuffId' = 258443 - RILED_UP_TARGET: 'CommonBuffId' = 77297 - ROBOTICS_ARM_EQUIPPED_BEIGE_WHITE: 'CommonBuffId' = 222151 - ROBOTICS_ARM_EQUIPPED_BLACK_BLUE: 'CommonBuffId' = 228984 - ROBOTICS_ARM_EQUIPPED_BLUE_RED: 'CommonBuffId' = 228985 - ROBOTICS_ARM_EQUIPPED_GRAY_BROWN: 'CommonBuffId' = 228986 - ROBOTICS_ARM_EQUIPPED_GREEN_BROWN: 'CommonBuffId' = 228987 - ROBOTICS_ARM_EQUIPPED_RED_GREEN: 'CommonBuffId' = 228988 - ROBOTICS_ARM_EQUIPPED_WHITE_COPPER: 'CommonBuffId' = 228989 - ROBOTICS_TABLE_ITS_ALIVE: 'CommonBuffId' = 223733 - ROBOTICS_TABLE_SORE_THUMB: 'CommonBuffId' = 222028 - ROBOT_BUILDING_EXHIBITION_BUILD_BOTS_COOLDOWN: 'CommonBuffId' = 225728 - ROCKET_SHIP_ESCAPE_POD_CHEWED_CABLES: 'CommonBuffId' = 77258 - ROCKET_SHIP_GALACTIC_MOVERS_HELPED_MOVE: 'CommonBuffId' = 77261 - ROCKET_SHIP_GALACTIC_MOVERS_NOT_ENOUGH_SPACE: 'CommonBuffId' = 77262 - ROCKET_SHIP_LOST_TREASURE_ALIEN_REPAIRS: 'CommonBuffId' = 77308 - ROCKET_SHIP_LOST_TREASURE_LOST_TREASURE: 'CommonBuffId' = 77307 - ROCKET_SHIP_OVERLORD_FLASHLIGHT: 'CommonBuffId' = 77208 - ROCKET_SHIP_OVERLORD_LEARNED_NOTHING: 'CommonBuffId' = 77214 - ROCKET_SHIP_OVERLORD_OUSTED: 'CommonBuffId' = 77210 - ROCKET_SHIP_OVERLORD_PETTY_ALIENS: 'CommonBuffId' = 77215 - ROCKET_SHIP_OVERLORD_PROMISED_LAND: 'CommonBuffId' = 77209 - ROCKET_SHIP_OVERLORD_RAMIFICATIONS_OF_POWER: 'CommonBuffId' = 77207 - ROCKET_SHIP_OVERLORD_SMOOSHED_REBELLION: 'CommonBuffId' = 77212 - ROCKET_SHIP_OVERLORD_TURNED_BENEVOLENT: 'CommonBuffId' = 77213 - ROCKET_SHIP_POOKA_POO_CALLED_THE_RANGERS: 'CommonBuffId' = 77268 - ROCKET_SHIP_POOKA_POO_FAILED_RESCUE: 'CommonBuffId' = 77270 - ROCKET_SHIP_POOKA_POO_RESCUE_COMPLETE: 'CommonBuffId' = 77269 - ROCKET_SHIP_SPACE_CRAZY_FORGOTTEN_OBJECTIVE: 'CommonBuffId' = 77290 - ROCKET_SHIP_SPACE_CRAZY_IRRATIONAL_ACTIONS: 'CommonBuffId' = 77284 - ROCKET_SHIP_SPACE_CRAZY_MADNESS_CURE: 'CommonBuffId' = 77285 - ROCKET_SHIP_SPACE_CRAZY_RECOVERY_FROM_MADNESS: 'CommonBuffId' = 77283 - ROCKET_SHIP_SPACE_CRAZY_SPACE_JUNK: 'CommonBuffId' = 77286 - ROCKET_SHIP_SPACE_CRAZY_SPACE_MADNESS: 'CommonBuffId' = 77282 - ROCKET_SHIP_SPACE_CRAZY_WAINING_SPACE_MADNESS: 'CommonBuffId' = 77287 - ROCKET_SHIP_STOWAWAY_ALIEN_NAPPING: 'CommonBuffId' = 77303 - ROCKET_SHIP_STOWAWAY_CUFFED_BY_STOWAWAY: 'CommonBuffId' = 77305 - ROCK_CLIMBING_GEAR_REPAIR_COOLDOWN: 'CommonBuffId' = 252530 - ROCK_CLIMBING_GEAR_WEARING_GEAR: 'CommonBuffId' = 247332 - ROLE_ALIEN_VISIT_ALIEN: 'CommonBuffId' = 114182 - ROLE_APM_MAILBOX_VISIT: 'CommonBuffId' = 350976 - ROLE_APPROPRIATENESS_ALIEN_VISIT_ALIEN: 'CommonBuffId' = 114149 - ROLE_APPROPRIATENESS_ALLOW_BARTENDING: 'CommonBuffId' = 35465 - ROLE_APPROPRIATENESS_ALLOW_COOKING: 'CommonBuffId' = 35470 - ROLE_APPROPRIATENESS_ALLOW_SLEEPING: 'CommonBuffId' = 35478 - ROLE_APPROPRIATENESS_AVOID_SITTING: 'CommonBuffId' = 201512 - ROLE_APPROPRIATENESS_BABY_BIRTH_HOSPITAL_NO_LABOR: 'CommonBuffId' = 112186 - ROLE_APPROPRIATENESS_CELEBRITY: 'CommonBuffId' = 196754 - ROLE_APPROPRIATENESS_COWORKER: 'CommonBuffId' = 108788 - ROLE_APPROPRIATENESS_COWORKER_FRONT_DESK_BADGE_IN: 'CommonBuffId' = 115777 - ROLE_APPROPRIATENESS_COWORKER_LUNCH: 'CommonBuffId' = 108789 - ROLE_APPROPRIATENESS_COWORKER_SCIENTIST_ALLOW: 'CommonBuffId' = 108846 - ROLE_APPROPRIATENESS_DOCTOR_CAREER_AWAY_EVENT_PATIENT: 'CommonBuffId' = 115633 - ROLE_APPROPRIATENESS_DOCTOR_CAREER_PATIENT: 'CommonBuffId' = 111788 - ROLE_APPROPRIATENESS_DOCTOR_CAREER_PLAYER: 'CommonBuffId' = 115830 - ROLE_APPROPRIATENESS_NO_BARTENDING: 'CommonBuffId' = 134456 - ROLE_APPROPRIATENESS_NO_BATHING: 'CommonBuffId' = 35368 - ROLE_APPROPRIATENESS_NO_CAKE: 'CommonBuffId' = 35369 - ROLE_APPROPRIATENESS_NO_CALL_TO_MEAL: 'CommonBuffId' = 101052 - ROLE_APPROPRIATENESS_NO_CLEANING: 'CommonBuffId' = 35370 - ROLE_APPROPRIATENESS_NO_COMPUTER: 'CommonBuffId' = 134457 - ROLE_APPROPRIATENESS_NO_COOKING: 'CommonBuffId' = 35365 - ROLE_APPROPRIATENESS_NO_DANCING: 'CommonBuffId' = 129759 - ROLE_APPROPRIATENESS_NO_EATING: 'CommonBuffId' = 35372 - ROLE_APPROPRIATENESS_NO_GRAB_SNACK: 'CommonBuffId' = 134458 - ROLE_APPROPRIATENESS_NO_PERFORMANCE_TIPPING: 'CommonBuffId' = 198707 - ROLE_APPROPRIATENESS_NO_PHONE: 'CommonBuffId' = 142027 - ROLE_APPROPRIATENESS_NO_PLAYING: 'CommonBuffId' = 137592 - ROLE_APPROPRIATENESS_NO_PLAYING_INSTRUMENTS: 'CommonBuffId' = 198708 - ROLE_APPROPRIATENESS_NO_READING: 'CommonBuffId' = 137593 - ROLE_APPROPRIATENESS_NO_READ_BOOKS: 'CommonBuffId' = 108838 - ROLE_APPROPRIATENESS_NO_SLEEPING: 'CommonBuffId' = 35390 - ROLE_APPROPRIATENESS_NO_SNOW_SHOVELING: 'CommonBuffId' = 250734 - ROLE_APPROPRIATENESS_NO_STEREO: 'CommonBuffId' = 35391 - ROLE_APPROPRIATENESS_NO_TOUCHING: 'CommonBuffId' = 132840 - ROLE_APPROPRIATENESS_NO_TV: 'CommonBuffId' = 155063 - ROLE_APPROPRIATENESS_NO_TV: 'CommonBuffId' = 108749 - ROLE_APPROPRIATENESS_NO_WORKOUT_BG: 'CommonBuffId' = 133051 - ROLE_APPROPRIATENESS_PLAYING_TRIVIA_BOX: 'CommonBuffId' = 386635 - ROLE_APPROPRIATENESS_SCIENTIST_FRONT_DESK: 'CommonBuffId' = 115893 - ROLE_APPROPRIATENESS_VISITOR: 'CommonBuffId' = 130085 - ROLE_BABY_SHOWER_GUEST: 'CommonBuffId' = 301105 - ROLE_BABY_SHOWER_GUEST_NPC: 'CommonBuffId' = 308982 - ROLE_BABY_SHOWER_HOST: 'CommonBuffId' = 308220 - ROLE_BARTENDER: 'CommonBuffId' = 12616 - ROLE_BAR_DRINKER: 'CommonBuffId' = 101021 - ROLE_BATUU_CONTROL_PANEL_SURVEILLANCE_ALARM_RESPONDER: 'CommonBuffId' = 240004 - ROLE_BE_WOKEN_UP: 'CommonBuffId' = 203046 - ROLE_BOWLING_VENUE_BOWLER: 'CommonBuffId' = 160126 - ROLE_BOWLING_VENUE_GROUP_1: 'CommonBuffId' = 161079 - ROLE_BOWLING_VENUE_GROUP_2: 'CommonBuffId' = 161080 - ROLE_BOWLING_VENUE_GROUP_3: 'CommonBuffId' = 161110 - ROLE_BOWLING_VENUE_GROUP_4: 'CommonBuffId' = 161111 - ROLE_BUTLER_BACK_TO_WORK: 'CommonBuffId' = 148769 - ROLE_BUTLER_BEEN_PRAISED: 'CommonBuffId' = 146340 - ROLE_BUTLER_BEEN_REPRIMANDED: 'CommonBuffId' = 146339 - ROLE_BUTLER_CAUGHT_NOT_WORKING: 'CommonBuffId' = 147258 - ROLE_BUTLER_DEFAULT: 'CommonBuffId' = 150512 - ROLE_BUTLER_DONT_COOK: 'CommonBuffId' = 151548 - ROLE_BUTLER_GARDENER_ROLE_NPC: 'CommonBuffId' = 150072 - ROLE_BUTLER_GIVEN_ORDER: 'CommonBuffId' = 152371 - ROLE_BUTLER_INVITE_GUESTS_ALWAYS_INVITE: 'CommonBuffId' = 147314 - ROLE_BUTLER_INVITE_GUESTS_NEVER_INVITE: 'CommonBuffId' = 147315 - ROLE_BUTLER_MAID_ROLE_NPC: 'CommonBuffId' = 150073 - ROLE_BUTLER_NANNY_ROLE_NPC: 'CommonBuffId' = 150074 - ROLE_BUTLER_NO_QUIRKY_ACTIONS: 'CommonBuffId' = 148740 - ROLE_BUTLER_NPC: 'CommonBuffId' = 145405 - ROLE_BUTLER_ORDER_CHECK_ON_MINOR: 'CommonBuffId' = 152549 - ROLE_BUTLER_REPAIRMAN_ROLE_NPC: 'CommonBuffId' = 150075 - ROLE_BUTLER_SITUATION_REPRIMANDED_BUTLER: 'CommonBuffId' = 149581 - ROLE_BUTLER_STATES_CARE_FOR_CHILDREN: 'CommonBuffId' = 152301 - ROLE_BUTLER_STATES_CLEAN: 'CommonBuffId' = 152305 - ROLE_BUTLER_STATES_DONT_CARE_FOR_CHILDREN: 'CommonBuffId' = 152302 - ROLE_BUTLER_STATES_DONT_CLEAN: 'CommonBuffId' = 152306 - ROLE_BUTLER_STATES_DONT_GARDEN: 'CommonBuffId' = 152304 - ROLE_BUTLER_STATES_DONT_REPAIR: 'CommonBuffId' = 152300 - ROLE_BUTLER_STATES_GARDEN: 'CommonBuffId' = 152303 - ROLE_BUTLER_STATES_REPAIR: 'CommonBuffId' = 152299 - ROLE_CALL_TO_MEAL_POLITE_HUNGER: 'CommonBuffId' = 98867 - ROLE_CANDLE_CRAFTER: 'CommonBuffId' = 232826 - ROLE_CANDLE_CRAFTER_CRAFTING_TIMEOUT: 'CommonBuffId' = 237996 - ROLE_CELEBRITY_CHANCE_WEAR_CRYSTAL_HELMET: 'CommonBuffId' = 198661 - ROLE_CELEBRITY_PLAY_GUITAR: 'CommonBuffId' = 202301 - ROLE_CELEBRITY_WALK_STYLE_APPLY: 'CommonBuffId' = 204573 - ROLE_CELEBRITY_WEAR_CRYSTAL_HELMET: 'CommonBuffId' = 198657 - ROLE_CHEF_PAN: 'CommonBuffId' = 139839 - ROLE_CHEF_POT: 'CommonBuffId' = 139840 - ROLE_CHEF_PREP: 'CommonBuffId' = 139841 - ROLE_CHEF_SERVE: 'CommonBuffId' = 139842 - ROLE_CHILD_CREATOR: 'CommonBuffId' = 232834 - ROLE_COLLEGE_ORGANIZATION_BAR_NIGHT_ART_SOCIETY_MEET_UP_PARTICIPANT: 'CommonBuffId' = 226527 - ROLE_COLLEGE_ORGANIZATION_BAR_NIGHT_DEBATE: 'CommonBuffId' = 228921 - ROLE_COLLEGE_ORGANIZATION_BAR_NIGHT_GENERAL: 'CommonBuffId' = 228894 - ROLE_COLLEGE_ORGANIZATION_BAR_NIGHT_HONOR_SOCIETY_PARTICIPANT: 'CommonBuffId' = 226898 - ROLE_COLLEGE_ORGANIZATION_BAR_NIGHT_PARTY: 'CommonBuffId' = 228924 - ROLE_COLLEGE_ORGANIZATION_BAR_NIGHT_PRANK: 'CommonBuffId' = 228923 - ROLE_COLLEGE_ORGANIZATION_BAR_NIGHT_ROBOTICS: 'CommonBuffId' = 228922 - ROLE_COLLEGE_ORGANIZATION_DEBATE_AUDIENCE: 'CommonBuffId' = 224130 - ROLE_COLLEGE_ORGANIZATION_DEBATE_DEBATER: 'CommonBuffId' = 224144 - ROLE_COLLEGE_ORGANIZATION_DEBATE_DECLARE: 'CommonBuffId' = 225702 - ROLE_COLLEGE_ORGANIZATION_DEBATE_GATHER: 'CommonBuffId' = 224142 - ROLE_COLLEGE_ORGANIZATION_DEBATE_JUDGE: 'CommonBuffId' = 224128 - ROLE_COLLEGE_ORGANIZATION_DEBATE_PARTICIPANT: 'CommonBuffId' = 224129 - ROLE_COLLEGE_ORGANIZATION_DEBATE_PLAYER: 'CommonBuffId' = 227489 - ROLE_COLLEGE_ORGANIZATION_DEBATE_REFRESHMENTS: 'CommonBuffId' = 224131 - ROLE_COLLEGE_ORGANIZATION_EVENTS_DEBATE_PLAYER: 'CommonBuffId' = 227486 - ROLE_COLLEGE_ORGANIZATION_EVENTS_PAINTIN_IN_THE_PARK_MEMBER: 'CommonBuffId' = 223441 - ROLE_COLLEGE_ORGANIZATION_EVENTS_PAINTIN_IN_THE_PARK_MODEL: 'CommonBuffId' = 227366 - ROLE_COLLEGE_ORGANIZATION_EVENTS_PAINTIN_IN_THE_PARK_PLAYER: 'CommonBuffId' = 223362 - ROLE_COLLEGE_ORGANIZATION_EVENTS_ROBOTICS_EXHIBITION_GO_TO_EVENT: 'CommonBuffId' = 224463 - ROLE_COLLEGE_ORGANIZATION_EVENTS_ROBOTICS_EXHIBITION_HUMANOID_ROBOT: 'CommonBuffId' = 230053 - ROLE_COLLEGE_ORGANIZATION_EVENTS_ROBOTICS_EXHIBITION_JUDGE_POST_JUDGING: 'CommonBuffId' = 224049 - ROLE_COLLEGE_ORGANIZATION_EVENTS_ROBOTICS_EXHIBITION_JUDGE_PRE_JUDGING: 'CommonBuffId' = 224050 - ROLE_COLLEGE_ORGANIZATION_EVENTS_ROBOTICS_EXHIBITION_PARTICIPANT: 'CommonBuffId' = 224051 - ROLE_COLLEGE_ORGANIZATION_EVENTS_ROBOTICS_EXHIBITION_PLAYER: 'CommonBuffId' = 223153 - ROLE_COLLEGE_ORGANIZATION_EVENTS_ROBOT_BUILDING_SESSION_GO_TO_EVENT: 'CommonBuffId' = 225330 - ROLE_COLLEGE_ORGANIZATION_EVENTS_ROBOT_BUILDING_SESSION_PARTICIPANT: 'CommonBuffId' = 225329 - ROLE_COLLEGE_ORGANIZATION_EVENTS_ROBOT_BUILDING_SESSION_PLAYER: 'CommonBuffId' = 225331 - ROLE_COLLEGE_ORGANIZATION_EVENTS_SECRET_SOCIETY_JOIN_VISIT: 'CommonBuffId' = 222756 - ROLE_COLLEGE_ORGANIZATION_EVENTS_SI_ROBOTICS_SOCIETY: 'CommonBuffId' = 230663 - ROLE_COLLEGE_ORGANIZATION_SCHOOL_SPIRIT_MASCOT: 'CommonBuffId' = 210856 - ROLE_COLLEGE_ORGANIZATION_SECRET_SOCIETY_GO_TO_RITUAL: 'CommonBuffId' = 224430 - ROLE_COLLEGE_ORGANIZATION_SECRET_SOCIETY_RITUAL: 'CommonBuffId' = 221642 - ROLE_COLLEGE_ORGANIZATION_SECRET_SOCIETY_RITUAL_PLAYER_MEMBER: 'CommonBuffId' = 228552 - ROLE_COLLEGE_ORGANIZATION_SECRET_SOCIETY_RITUAL_PLAYER_NONMEMBER: 'CommonBuffId' = 228551 - ROLE_COLLEGE_ORGANIZATION_SECRET_SOCIETY_RITUAL_SOCIAL_MORE_MEMBER_ONLY: 'CommonBuffId' = 228550 - ROLE_COLLEGE_ORGANIZATION_STUDY_GROUP_MEMBER: 'CommonBuffId' = 210838 - ROLE_COLLEGE_ORGANIZATION_STUDY_GROUP_PLAYER: 'CommonBuffId' = 210859 - ROLE_COMMUNITY_BOARD_DEBATER: 'CommonBuffId' = 224292 - ROLE_COMMUNITY_CLOSENESS_COMPLAINT_ANGRY_SIM: 'CommonBuffId' = 233783 - ROLE_COMMUNITY_CLOSENESS_HANDY_NEIGHBOR_BE_HANDY: 'CommonBuffId' = 233782 - ROLE_COMMUNITY_CLOSENESS_HANGOUT: 'CommonBuffId' = 234294 - ROLE_COMMUNITY_CLOSENESS_INTRO_TO_CIVIC_POLICIES: 'CommonBuffId' = 238072 - ROLE_COMMUNITY_CLOSENESS_INTRO_TO_CIVIC_POLICIES_HANG_OUT: 'CommonBuffId' = 239729 - ROLE_COMMUNITY_CLOSENESS_KNOCK_TNS_SHOWN: 'CommonBuffId' = 239097 - ROLE_COMMUNITY_CLOSENESS_RANDOM_GIFT_GIVE_GIFT: 'CommonBuffId' = 233784 - ROLE_COMMUNITY_CLOSENESS_SPARE_RECYCLINGS_RECYCLE: 'CommonBuffId' = 233785 - ROLE_COMMUNITY_CLOSENESS_TRASH_HELPER_PICKUP_TRASH: 'CommonBuffId' = 233781 - ROLE_COMMUNITY_GARDEN: 'CommonBuffId' = 223963 - ROLE_COTTAGE_WORLD_NPC_CRITTER_TENDER_COOK: 'CommonBuffId' = 264768 - ROLE_COTTAGE_WORLD_NPC_CRITTER_TENDER_FORAGE: 'CommonBuffId' = 264767 - ROLE_COTTAGE_WORLD_NPC_CRITTER_TENDER_GARDEN: 'CommonBuffId' = 264766 - ROLE_COTTAGE_WORLD_NPC_CRITTER_TENDER_GO_HOME: 'CommonBuffId' = 269654 - ROLE_COTTAGE_WORLD_NPC_CRITTER_TENDER_INTERACT_WITH_CRITTERS: 'CommonBuffId' = 264769 - ROLE_COTTAGE_WORLD_NPC_CRITTER_TENDER_SIT: 'CommonBuffId' = 269643 - ROLE_COTTAGE_WORLD_NPC_GROCERY_DELIVERY: 'CommonBuffId' = 269815 - ROLE_COWORKER: 'CommonBuffId' = 108695 - ROLE_CRAFT_SALES_TABLE_VENDOR_JUNGLE: 'CommonBuffId' = 178017 - ROLE_CUSTOM_STATE_WEDDING_COUPLE_ARRIVAL: 'CommonBuffId' = 277825 - ROLE_CUSTOM_STATE_WEDDING_COUPLE_BOUQUET_GATHER: 'CommonBuffId' = 278015 - ROLE_CUSTOM_STATE_WEDDING_COUPLE_BOUQUET_TOSS: 'CommonBuffId' = 278016 - ROLE_CUSTOM_STATE_WEDDING_COUPLE_CAKE: 'CommonBuffId' = 277836 - ROLE_CUSTOM_STATE_WEDDING_COUPLE_CAKE_EAT: 'CommonBuffId' = 278017 - ROLE_CUSTOM_STATE_WEDDING_COUPLE_CAKE_GATHER: 'CommonBuffId' = 278018 - ROLE_CUSTOM_STATE_WEDDING_COUPLE_DANCE: 'CommonBuffId' = 278019 - ROLE_CUSTOM_STATE_WEDDING_COUPLE_DANCE_GATHER: 'CommonBuffId' = 278020 - ROLE_CUSTOM_STATE_WEDDING_COUPLE_DANCE_GATHER_DANCE_FLOOR: 'CommonBuffId' = 278021 - ROLE_CUSTOM_STATE_WEDDING_COUPLE_DESSERTS: 'CommonBuffId' = 285085 - ROLE_CUSTOM_STATE_WEDDING_COUPLE_MEAL: 'CommonBuffId' = 278022 - ROLE_CUSTOM_STATE_WEDDING_COUPLE_MINGLE: 'CommonBuffId' = 277813 - ROLE_CUSTOM_STATE_WEDDING_COUPLE_POST_CEREMONY: 'CommonBuffId' = 278023 - ROLE_CUSTOM_STATE_WEDDING_COUPLE_PROCESSIONAL: 'CommonBuffId' = 277837 - ROLE_CUSTOM_STATE_WEDDING_COUPLE_RECESSIONAL: 'CommonBuffId' = 277838 - ROLE_CUSTOM_STATE_WEDDING_COUPLE_RECESSIONAL_GATHER: 'CommonBuffId' = 278024 - ROLE_CUSTOM_STATE_WEDDING_COUPLE_SIT_DOWN: 'CommonBuffId' = 277833 - ROLE_CUSTOM_STATE_WEDDING_COUPLE_TOAST: 'CommonBuffId' = 278025 - ROLE_CUSTOM_STATE_WEDDING_COUPLE_TOAST_GATHER: 'CommonBuffId' = 278028 - ROLE_CUSTOM_STATE_WEDDING_COUPLE_VOWS: 'CommonBuffId' = 278027 - ROLE_CUSTOM_STATE_WEDDING_COUPLE_VOWS_SPEECH: 'CommonBuffId' = 278029 - ROLE_CUSTOM_STATE_WEDDING_COUPLE_VOWS_WITH_OFFICIANT: 'CommonBuffId' = 278030 - ROLE_CUSTOM_STATE_WEDDING_FLOWER_SPREADER_ARRIVAL: 'CommonBuffId' = 278031 - ROLE_CUSTOM_STATE_WEDDING_FLOWER_SPREADER_BOUQUET_GATHER: 'CommonBuffId' = 278032 - ROLE_CUSTOM_STATE_WEDDING_FLOWER_SPREADER_BOUQUET_TOSS: 'CommonBuffId' = 278041 - ROLE_CUSTOM_STATE_WEDDING_FLOWER_SPREADER_CAKE: 'CommonBuffId' = 278042 - ROLE_CUSTOM_STATE_WEDDING_FLOWER_SPREADER_CAKE_EAT: 'CommonBuffId' = 278043 - ROLE_CUSTOM_STATE_WEDDING_FLOWER_SPREADER_CAKE_GATHER: 'CommonBuffId' = 278044 - ROLE_CUSTOM_STATE_WEDDING_FLOWER_SPREADER_DANCE: 'CommonBuffId' = 278045 - ROLE_CUSTOM_STATE_WEDDING_FLOWER_SPREADER_DANCE_GATHER: 'CommonBuffId' = 278046 - ROLE_CUSTOM_STATE_WEDDING_FLOWER_SPREADER_DANCE_GATHER_DANCE_FLOOR: 'CommonBuffId' = 278047 - ROLE_CUSTOM_STATE_WEDDING_FLOWER_SPREADER_MEAL: 'CommonBuffId' = 278048 - ROLE_CUSTOM_STATE_WEDDING_FLOWER_SPREADER_MINGLE: 'CommonBuffId' = 277814 - ROLE_CUSTOM_STATE_WEDDING_FLOWER_SPREADER_POST_CEREMONY: 'CommonBuffId' = 278049 - ROLE_CUSTOM_STATE_WEDDING_FLOWER_SPREADER_PROCESSIONAL: 'CommonBuffId' = 278050 - ROLE_CUSTOM_STATE_WEDDING_FLOWER_SPREADER_RECESSIONAL: 'CommonBuffId' = 278033 - ROLE_CUSTOM_STATE_WEDDING_FLOWER_SPREADER_RECESSIONAL_GATHER: 'CommonBuffId' = 278034 - ROLE_CUSTOM_STATE_WEDDING_FLOWER_SPREADER_SIT_DOWN: 'CommonBuffId' = 278035 - ROLE_CUSTOM_STATE_WEDDING_FLOWER_SPREADER_TOAST: 'CommonBuffId' = 278036 - ROLE_CUSTOM_STATE_WEDDING_FLOWER_SPREADER_TOAST_GATHER: 'CommonBuffId' = 278037 - ROLE_CUSTOM_STATE_WEDDING_FLOWER_SPREADER_VOWS: 'CommonBuffId' = 278038 - ROLE_CUSTOM_STATE_WEDDING_FLOWER_SPREADER_VOWS_SPEECH: 'CommonBuffId' = 278039 - ROLE_CUSTOM_STATE_WEDDING_FLOWER_SPREADER_VOWS_WITH_OFFICIANT: 'CommonBuffId' = 278040 - ROLE_CUSTOM_STATE_WEDDING_GUEST_ARRIVAL: 'CommonBuffId' = 278051 - ROLE_CUSTOM_STATE_WEDDING_GUEST_BOUQUET_GATHER: 'CommonBuffId' = 278052 - ROLE_CUSTOM_STATE_WEDDING_GUEST_BOUQUET_TOSS: 'CommonBuffId' = 278062 - ROLE_CUSTOM_STATE_WEDDING_GUEST_CAKE: 'CommonBuffId' = 278061 - ROLE_CUSTOM_STATE_WEDDING_GUEST_CAKE_EAT: 'CommonBuffId' = 278063 - ROLE_CUSTOM_STATE_WEDDING_GUEST_CAKE_GATHER: 'CommonBuffId' = 278064 - ROLE_CUSTOM_STATE_WEDDING_GUEST_DANCE: 'CommonBuffId' = 278065 - ROLE_CUSTOM_STATE_WEDDING_GUEST_DANCE_GATHER: 'CommonBuffId' = 278066 - ROLE_CUSTOM_STATE_WEDDING_GUEST_DANCE_GATHER_DANCE_FLOOR: 'CommonBuffId' = 278067 - ROLE_CUSTOM_STATE_WEDDING_GUEST_DESSERTS: 'CommonBuffId' = 285086 - ROLE_CUSTOM_STATE_WEDDING_GUEST_MEAL: 'CommonBuffId' = 278068 - ROLE_CUSTOM_STATE_WEDDING_GUEST_MINGLE: 'CommonBuffId' = 277815 - ROLE_CUSTOM_STATE_WEDDING_GUEST_POST_CEREMONY: 'CommonBuffId' = 278069 - ROLE_CUSTOM_STATE_WEDDING_GUEST_PROCESSIONAL: 'CommonBuffId' = 278053 - ROLE_CUSTOM_STATE_WEDDING_GUEST_RECESSIONAL: 'CommonBuffId' = 278054 - ROLE_CUSTOM_STATE_WEDDING_GUEST_RECESSIONAL_GATHER: 'CommonBuffId' = 278055 - ROLE_CUSTOM_STATE_WEDDING_GUEST_SIT_DOWN: 'CommonBuffId' = 277904 - ROLE_CUSTOM_STATE_WEDDING_GUEST_TOAST: 'CommonBuffId' = 278056 - ROLE_CUSTOM_STATE_WEDDING_GUEST_TOAST_GATHER: 'CommonBuffId' = 278057 - ROLE_CUSTOM_STATE_WEDDING_GUEST_VOWS: 'CommonBuffId' = 278058 - ROLE_CUSTOM_STATE_WEDDING_GUEST_VOWS_SPEECH: 'CommonBuffId' = 278059 - ROLE_CUSTOM_STATE_WEDDING_GUEST_VOWS_WITH_OFFICIANT: 'CommonBuffId' = 278060 - ROLE_CUSTOM_STATE_WEDDING_HONOR_ATTENDANT_ARRIVAL: 'CommonBuffId' = 278070 - ROLE_CUSTOM_STATE_WEDDING_HONOR_ATTENDANT_BOUQUET_GATHER: 'CommonBuffId' = 278071 - ROLE_CUSTOM_STATE_WEDDING_HONOR_ATTENDANT_BOUQUET_TOSS: 'CommonBuffId' = 278080 - ROLE_CUSTOM_STATE_WEDDING_HONOR_ATTENDANT_CAKE: 'CommonBuffId' = 278081 - ROLE_CUSTOM_STATE_WEDDING_HONOR_ATTENDANT_CAKE_EAT: 'CommonBuffId' = 278082 - ROLE_CUSTOM_STATE_WEDDING_HONOR_ATTENDANT_CAKE_GATHER: 'CommonBuffId' = 278083 - ROLE_CUSTOM_STATE_WEDDING_HONOR_ATTENDANT_DANCE: 'CommonBuffId' = 278084 - ROLE_CUSTOM_STATE_WEDDING_HONOR_ATTENDANT_DANCE_GATHER: 'CommonBuffId' = 278085 - ROLE_CUSTOM_STATE_WEDDING_HONOR_ATTENDANT_DANCE_GATHER_DANCE_FLOOR: 'CommonBuffId' = 278086 - ROLE_CUSTOM_STATE_WEDDING_HONOR_ATTENDANT_MEAL: 'CommonBuffId' = 278087 - ROLE_CUSTOM_STATE_WEDDING_HONOR_ATTENDANT_MINGLE: 'CommonBuffId' = 277816 - ROLE_CUSTOM_STATE_WEDDING_HONOR_ATTENDANT_POST_CEREMONY: 'CommonBuffId' = 278088 - ROLE_CUSTOM_STATE_WEDDING_HONOR_ATTENDANT_PROCESSIONAL: 'CommonBuffId' = 278089 - ROLE_CUSTOM_STATE_WEDDING_HONOR_ATTENDANT_RECESSIONAL: 'CommonBuffId' = 278072 - ROLE_CUSTOM_STATE_WEDDING_HONOR_ATTENDANT_RECESSIONNAL_GATHER: 'CommonBuffId' = 278073 - ROLE_CUSTOM_STATE_WEDDING_HONOR_ATTENDANT_SIT_DOWN: 'CommonBuffId' = 278074 - ROLE_CUSTOM_STATE_WEDDING_HONOR_ATTENDANT_TOAST: 'CommonBuffId' = 278075 - ROLE_CUSTOM_STATE_WEDDING_HONOR_ATTENDANT_TOAST_GATHER: 'CommonBuffId' = 278076 - ROLE_CUSTOM_STATE_WEDDING_HONOR_ATTENDANT_VOWS: 'CommonBuffId' = 278077 - ROLE_CUSTOM_STATE_WEDDING_HONOR_ATTENDANT_VOWS_SPEECH: 'CommonBuffId' = 278078 - ROLE_CUSTOM_STATE_WEDDING_HONOR_ATTENDANT_VOWS_WITH_OFFICIANT: 'CommonBuffId' = 278079 - ROLE_CUSTOM_STATE_WEDDING_OFFICIANT_ARRIVAL: 'CommonBuffId' = 278090 - ROLE_CUSTOM_STATE_WEDDING_OFFICIANT_BOUQUET_GATHER: 'CommonBuffId' = 278091 - ROLE_CUSTOM_STATE_WEDDING_OFFICIANT_BOUQUET_TOSS: 'CommonBuffId' = 278100 - ROLE_CUSTOM_STATE_WEDDING_OFFICIANT_CAKE: 'CommonBuffId' = 278101 - ROLE_CUSTOM_STATE_WEDDING_OFFICIANT_CAKE_EAT: 'CommonBuffId' = 278102 - ROLE_CUSTOM_STATE_WEDDING_OFFICIANT_CAKE_GATHER: 'CommonBuffId' = 278103 - ROLE_CUSTOM_STATE_WEDDING_OFFICIANT_DANCE: 'CommonBuffId' = 278104 - ROLE_CUSTOM_STATE_WEDDING_OFFICIANT_DANCE_GATHER: 'CommonBuffId' = 278105 - ROLE_CUSTOM_STATE_WEDDING_OFFICIANT_DANCE_GATHER_DANCE_FLOOR: 'CommonBuffId' = 278106 - ROLE_CUSTOM_STATE_WEDDING_OFFICIANT_MEAL: 'CommonBuffId' = 278107 - ROLE_CUSTOM_STATE_WEDDING_OFFICIANT_MINGLE: 'CommonBuffId' = 277817 - ROLE_CUSTOM_STATE_WEDDING_OFFICIANT_POST_CEREMONY: 'CommonBuffId' = 278108 - ROLE_CUSTOM_STATE_WEDDING_OFFICIANT_PROCESSIONAL: 'CommonBuffId' = 278109 - ROLE_CUSTOM_STATE_WEDDING_OFFICIANT_RECESSIONAL: 'CommonBuffId' = 278092 - ROLE_CUSTOM_STATE_WEDDING_OFFICIANT_RECESSIONAL_GATHER: 'CommonBuffId' = 278093 - ROLE_CUSTOM_STATE_WEDDING_OFFICIANT_SIT_DOWN: 'CommonBuffId' = 278094 - ROLE_CUSTOM_STATE_WEDDING_OFFICIANT_TOAST: 'CommonBuffId' = 278095 - ROLE_CUSTOM_STATE_WEDDING_OFFICIANT_TOAST_GATHER: 'CommonBuffId' = 278096 - ROLE_CUSTOM_STATE_WEDDING_OFFICIANT_VOWS: 'CommonBuffId' = 278097 - ROLE_CUSTOM_STATE_WEDDING_OFFICIANT_VOWS_SPEECH: 'CommonBuffId' = 278098 - ROLE_CUSTOM_STATE_WEDDING_OFFICIANT_VOWS_WITH_OFFICIANT: 'CommonBuffId' = 278099 - ROLE_DANCE_BATTLE_DANCER: 'CommonBuffId' = 129622 - ROLE_DANCE_BATTLE_WATCHER: 'CommonBuffId' = 129621 - ROLE_DELIVERIES_DROP_BAG: 'CommonBuffId' = 262208 - ROLE_DELIVERIES_GENERIC: 'CommonBuffId' = 262223 - ROLE_DELIVERIES_WAIT_FOR_CUSTOMER: 'CommonBuffId' = 262216 - ROLE_DELIVERIES_WAIT_FOR_TIP: 'CommonBuffId' = 262303 - ROLE_DETECTIVE_NP_CS_STATION_ARRESTED: 'CommonBuffId' = 116489 - ROLE_DETECTIVE_NP_CS_STATION_CRIMINAL: 'CommonBuffId' = 112474 - ROLE_DINNER_PARTY_GUEST_PHASE1: 'CommonBuffId' = 12625 - ROLE_DINNER_PARTY_GUEST_PHASE2: 'CommonBuffId' = 12626 - ROLE_DINNER_PARTY_HOST_PHASE1: 'CommonBuffId' = 12627 - ROLE_DINNER_PARTY_HOST_PHASE2: 'CommonBuffId' = 12628 - ROLE_DOCTOR_CAREER_DOCTOR: 'CommonBuffId' = 115348 - ROLE_DOCTOR_CAREER_DOCTOR_DIAGNOSER: 'CommonBuffId' = 116256 - ROLE_DOCTOR_CAREER_EMERGENCY_SAMPLE_ANALYSIS: 'CommonBuffId' = 114139 - ROLE_DOCTOR_CAREER_IS_PATIENT_DIAGNOSED_BLOATY_HEAD: 'CommonBuffId' = 115284 - ROLE_DOCTOR_CAREER_IS_PATIENT_DIAGNOSED_GAS_AND_GIGGLES: 'CommonBuffId' = 115282 - ROLE_DOCTOR_CAREER_IS_PATIENT_DIAGNOSED_LLAMA_FLU: 'CommonBuffId' = 115281 - ROLE_DOCTOR_CAREER_IS_PATIENT_DIAGNOSED_STARRY_EYES: 'CommonBuffId' = 115283 - ROLE_DOCTOR_CAREER_IS_PATIENT_HIGH_LEVEL: 'CommonBuffId' = 113779 - ROLE_DOCTOR_CAREER_IS_PATIENT_LOW_LEVEL: 'CommonBuffId' = 113744 - ROLE_DOCTOR_CAREER_IS_PATIENT_LOW_LEVEL_ADMITTED: 'CommonBuffId' = 115269 - ROLE_DOCTOR_CAREER_IS_PATIENT_PREGNANT: 'CommonBuffId' = 114080 - ROLE_DOCTOR_CAREER_NURSE: 'CommonBuffId' = 112216 - ROLE_DOCTOR_CAREER_OBGYN: 'CommonBuffId' = 116173 - ROLE_DOCTOR_CAREER_ORDERLY: 'CommonBuffId' = 112247 - ROLE_DOCTOR_CAREER_PATIENT_STATE_ADMITTED: 'CommonBuffId' = 114414 - ROLE_DOCTOR_CAREER_PATIENT_STATE_ARRIVAL: 'CommonBuffId' = 116676 - ROLE_DOCTOR_CAREER_PATIENT_STATE_DIAGNOSED: 'CommonBuffId' = 115798 - ROLE_DOCTOR_CAREER_PATIENT_STATE_TREATED: 'CommonBuffId' = 114415 - ROLE_DOCTOR_CAREER_PLAYER_HAD_BABY: 'CommonBuffId' = 116656 - ROLE_DOCTOR_CAREER_RECEPTIONIST: 'CommonBuffId' = 111789 - ROLE_EMPLOYEE: 'CommonBuffId' = 179092 - ROLE_EP16_SPECIAL_NPC_THERING_BEAR_HANGOUT: 'CommonBuffId' = 369737 - ROLE_EVENT_NPC: 'CommonBuffId' = 136555 - ROLE_EVENT_NPC_POSITIVITY_CHALLENGE: 'CommonBuffId' = 199079 - ROLE_FABRICATOR_RECYCLER: 'CommonBuffId' = 232825 - ROLE_FAMILY_DINNER_CHEF: 'CommonBuffId' = 33920 - ROLE_FAMILY_DINNER_EAT: 'CommonBuffId' = 33922 - ROLE_FAMILY_DINNER_EATER_SUPPRESS_HUNGER: 'CommonBuffId' = 33921 - ROLE_FASHION_SUBJECT: 'CommonBuffId' = 215304 - ROLE_GO_TO_FRONT_DOOR: 'CommonBuffId' = 204302 - ROLE_GROUP_COOKING_COOK_HEAD_COOK: 'CommonBuffId' = 264474 - ROLE_GROUP_COOKING_COOK_JOINED_COOKS: 'CommonBuffId' = 263898 - ROLE_GROUP_COOKING_COOK_STOP_COOKING: 'CommonBuffId' = 269313 - ROLE_GROUP_COOKING_GATHER_HEAD_COOK: 'CommonBuffId' = 263915 - ROLE_GROUP_COOKING_GATHER_JOINED_COOKS: 'CommonBuffId' = 263896 - ROLE_GROUP_COOKING_MENTOREE: 'CommonBuffId' = 267639 - ROLE_GUEST_SUPPRESS_SOCIAL_AUTONOMY: 'CommonBuffId' = 170450 - ROLE_HIGH_SCHOOL_ACTIVE_BASE_FACULTY: 'CommonBuffId' = 302783 - ROLE_HIGH_SCHOOL_ACTIVE_NPC_ATTEND_CLASS_PRINCIPAL: 'CommonBuffId' = 277031 - ROLE_HIGH_SCHOOL_ACTIVE_NPC_ATTEND_CLASS_STUDENT: 'CommonBuffId' = 276312 - ROLE_HIGH_SCHOOL_ACTIVE_NPC_ATTEND_CLASS_TEACHER: 'CommonBuffId' = 276313 - ROLE_HIGH_SCHOOL_ACTIVE_NPC_ATTEND_EXAM_PREP: 'CommonBuffId' = 304066 - ROLE_HIGH_SCHOOL_ACTIVE_NPC_CAREER_DAY_DISALLOW_PRE_ROLL_WATCH: 'CommonBuffId' = 304431 - ROLE_HIGH_SCHOOL_ACTIVE_NPC_CAREER_DAY_PROFESSIONAL: 'CommonBuffId' = 289106 - ROLE_HIGH_SCHOOL_ACTIVE_NPC_CLEAN_JANITOR: 'CommonBuffId' = 290222 - ROLE_HIGH_SCHOOL_ACTIVE_NPC_DO_STUFF_BULLIES: 'CommonBuffId' = 276442 - ROLE_HIGH_SCHOOL_ACTIVE_NPC_DO_STUFF_CAREER_DAY: 'CommonBuffId' = 282142 - ROLE_HIGH_SCHOOL_ACTIVE_NPC_DO_STUFF_CAREER_DAY_2: 'CommonBuffId' = 304416 - ROLE_HIGH_SCHOOL_ACTIVE_NPC_DO_STUFF_CAREER_DAY_3: 'CommonBuffId' = 304417 - ROLE_HIGH_SCHOOL_ACTIVE_NPC_DO_STUFF_DO_MISCHIEF: 'CommonBuffId' = 287886 - ROLE_HIGH_SCHOOL_ACTIVE_NPC_DO_STUFF_FIRE_DRILL: 'CommonBuffId' = 280938 - ROLE_HIGH_SCHOOL_ACTIVE_NPC_DO_STUFF_HIGH_SCHOOL_TEAM_RECRUITER: 'CommonBuffId' = 276556 - ROLE_HIGH_SCHOOL_ACTIVE_NPC_DO_STUFF_SOCIAL_MEDIA_ENTHUSIASTS: 'CommonBuffId' = 276536 - ROLE_HIGH_SCHOOL_ACTIVE_NPC_DO_STUFF_STUDY_BUDDIES: 'CommonBuffId' = 275831 - ROLE_HIGH_SCHOOL_ACTIVE_NPC_DO_STUFF_THROW_FOOTBALL_LEADER: 'CommonBuffId' = 284015 - ROLE_HIGH_SCHOOL_ACTIVE_NPC_DO_STUFF_T_POSE_LEADER: 'CommonBuffId' = 280764 - ROLE_HIGH_SCHOOL_ACTIVE_NPC_DO_STUFF_USE_LOCKER: 'CommonBuffId' = 286443 - ROLE_HIGH_SCHOOL_ACTIVE_NPC_GET_LUNCH: 'CommonBuffId' = 278839 - ROLE_HIGH_SCHOOL_ACTIVE_NPC_GET_LUNCH_CREATE: 'CommonBuffId' = 298820 - ROLE_HIGH_SCHOOL_ACTIVE_NPC_GO_TO_CLASS_1: 'CommonBuffId' = 293776 - ROLE_HIGH_SCHOOL_ACTIVE_NPC_GO_TO_CLASS_2: 'CommonBuffId' = 293817 - ROLE_HIGH_SCHOOL_ACTIVE_NPC_GO_TO_CLASS_TEACHER: 'CommonBuffId' = 297777 - ROLE_HIGH_SCHOOL_ACTIVE_NPC_GO_TO_EXAM_PREP: 'CommonBuffId' = 304063 - ROLE_HIGH_SCHOOL_ACTIVE_NPC_GO_TO_WHITEBOARD: 'CommonBuffId' = 280121 - ROLE_HIGH_SCHOOL_ACTIVE_NPC_HANG_OUT_PRINCIPAL: 'CommonBuffId' = 289475 - ROLE_HIGH_SCHOOL_ACTIVE_NPC_PREPARE_FOR_CLASS: 'CommonBuffId' = 276282 - ROLE_HIGH_SCHOOL_ACTIVE_NPC_SCHOOL_FIGHT_START_FIGHT: 'CommonBuffId' = 282863 - ROLE_HIGH_SCHOOL_ACTIVE_NPC_STOP_INTERACTION: 'CommonBuffId' = 276642 - ROLE_HIGH_SCHOOL_ACTIVE_NPC_STUDENT_ATTEND_CLASS_2: 'CommonBuffId' = 304592 - ROLE_HIGH_SCHOOL_ACTIVE_NPC_TEACH_EXAM_PREP: 'CommonBuffId' = 304082 - ROLE_HIGH_SCHOOL_ACTIVE_PLAYER_AFTER_SCHOOL: 'CommonBuffId' = 288882 - ROLE_HIGH_SCHOOL_ACTIVE_PLAYER_ATTEND_CLASS: 'CommonBuffId' = 276710 - ROLE_HIGH_SCHOOL_ACTIVE_PLAYER_BASE: 'CommonBuffId' = 294894 - ROLE_HIGH_SCHOOL_ACTIVE_PLAYER_CAREER_DAY: 'CommonBuffId' = 282052 - ROLE_HIGH_SCHOOL_ACTIVE_PLAYER_CAREER_DAY_AT_AUDITORIUM: 'CommonBuffId' = 282138 - ROLE_HIGH_SCHOOL_ACTIVE_PLAYER_FIRE_DRILL: 'CommonBuffId' = 280937 - ROLE_HIGH_SCHOOL_ACTIVE_PLAYER_GET_READY_FOR_CLASS: 'CommonBuffId' = 285939 - ROLE_HIGH_SCHOOL_ACTIVE_PLAYER_IS_CAREER_DAY_TRUE: 'CommonBuffId' = 282476 - ROLE_HIGH_SCHOOL_ACTIVE_PLAYER_IS_EXAM_DAY_TRUE: 'CommonBuffId' = 295491 - ROLE_HIGH_SCHOOL_ACTIVE_PLAYER_IS_EXAM_PREP_TRUE: 'CommonBuffId' = 292250 - ROLE_HIGH_SCHOOL_ACTIVE_PLAYER_IS_FIRE_DRILL_TRUE: 'CommonBuffId' = 285120 - ROLE_HIGH_SCHOOL_ACTIVE_PLAYER_ORIENTATION: 'CommonBuffId' = 276707 - ROLE_HIGH_SCHOOL_ACTIVE_PLAYER_TRUANT: 'CommonBuffId' = 285599 - ROLE_HIGH_SCHOOL_ACTIVE_USE_VENDING_MACHINE: 'CommonBuffId' = 297488 - ROLE_HIGH_SCHOOL_GRADUATION_AFFORDANCES: 'CommonBuffId' = 288487 - ROLE_HIGH_SCHOOL_GRADUATION_CALL_OUT_DIPLOMAS: 'CommonBuffId' = 288271 - ROLE_HIGH_SCHOOL_GRADUATION_CLEAN_UP_OUTFITS: 'CommonBuffId' = 305318 - ROLE_HIGH_SCHOOL_GRADUATION_GET_DIPLOMA: 'CommonBuffId' = 288488 - ROLE_HIGH_SCHOOL_GRADUATION_GIVE_SPEECH: 'CommonBuffId' = 288489 - ROLE_HIGH_SCHOOL_GRADUATION_PLEASANTRIES: 'CommonBuffId' = 288491 - ROLE_HIGH_SCHOOL_GRADUATION_THROW_CAP: 'CommonBuffId' = 288503 - ROLE_HIGH_SCHOOL_GRADUATION_WATCH_SPEECH: 'CommonBuffId' = 288441 - ROLE_HIGH_SCHOOL_GRADUATION_WATCH_SPEECH_BACK: 'CommonBuffId' = 288688 - ROLE_HOLIDAY_TRADITION_FATHER_WINTER_ADD_PRESENT: 'CommonBuffId' = 181568 - ROLE_HOLIDAY_TRADITION_FATHER_WINTER_ARRIVAL: 'CommonBuffId' = 181509 - ROLE_HOLIDAY_TRADITION_FATHER_WINTER_HANG_OUT: 'CommonBuffId' = 181512 - ROLE_HOLIDAY_TRADITION_FATHER_WINTER_LEAVE_LOT: 'CommonBuffId' = 188851 - ROLE_HOLIDAY_TRADITION_FLOWER_BUNNY_EXIT: 'CommonBuffId' = 186943 - ROLE_HOLIDAY_TRADITION_FLOWER_BUNNY_HANG_OUT: 'CommonBuffId' = 186944 - ROLE_HOLIDAY_TRADITION_FLOWER_BUNNY_OUTFIT: 'CommonBuffId' = 189297 - ROLE_HOLIDAY_TRADITION_TRICK_OR_TREAT_ARRIVAL: 'CommonBuffId' = 187599 - ROLE_HOLIDAY_TRADITION_TRICK_OR_TREAT_DONE: 'CommonBuffId' = 187691 - ROLE_HOLIDAY_TRADITION_TRICK_OR_TREAT_WAIT: 'CommonBuffId' = 187680 - ROLE_IMPRISONED: 'CommonBuffId' = 101250 - ROLE_INFECT_HOUSE: 'CommonBuffId' = 203120 - ROLE_INSECT_FARMER: 'CommonBuffId' = 233428 - ROLE_ISLAND_WELCOME_WAGON_KAVA_BEARER_PUT_DOWN: 'CommonBuffId' = 211527 - ROLE_ISLAND_WELCOME_WAGON_NEIGHBOR: 'CommonBuffId' = 211525 - ROLE_JOGGER_EAR_BUDS: 'CommonBuffId' = 166526 - ROLE_KARAOKE_SING_KARAOKE: 'CommonBuffId' = 138062 - ROLE_KARAOKE_SING_KARAOKE_CONTEST: 'CommonBuffId' = 138145 - ROLE_KARAOKE_SING_KARAOKE_DUET: 'CommonBuffId' = 140810 - ROLE_LEAVE_LOT_NOW: 'CommonBuffId' = 24238 - ROLE_LEAVE_LOT_NOW_MUST_RUN: 'CommonBuffId' = 24312 - ROLE_LEAVE_LOT_SOON: 'CommonBuffId' = 28380 - ROLE_LOOK_BUSY_IN_PLACE: 'CommonBuffId' = 101249 - ROLE_MAKERSPACEMENTOR: 'CommonBuffId' = 232823 - ROLE_MINGLER: 'CommonBuffId' = 12632 - ROLE_MOTHER_PLANT_BATTLE_COOLDOWN: 'CommonBuffId' = 205259 - ROLE_MOTHER_PLANT_BATTLE_COOLDOWN_ATTACK: 'CommonBuffId' = 204435 - ROLE_MOTHER_PLANT_BATTLE_COOLDOWN_INSPIRE: 'CommonBuffId' = 204437 - ROLE_MOTHER_PLANT_BATTLE_COOLDOWN_MEGA_SPRAY: 'CommonBuffId' = 204438 - ROLE_MOTHER_PLANT_BATTLE_COOLDOWN_RALLY: 'CommonBuffId' = 204436 - ROLE_MOTHER_PLANT_BATTLE_COOLDOWN_THROW_CURE: 'CommonBuffId' = 204439 - ROLE_MOTHER_PLANT_BATTLE_COOLDOWN_WARBLING_WARCRY: 'CommonBuffId' = 204440 - ROLE_MOTHER_PLANT_BATTLE_HELPER_ATTACK: 'CommonBuffId' = 203656 - ROLE_MOTHER_PLANT_BATTLE_HELPER_ATTACK_LOCATION_1: 'CommonBuffId' = 204404 - ROLE_MOTHER_PLANT_BATTLE_HELPER_ATTACK_LOCATION_2: 'CommonBuffId' = 204405 - ROLE_MOTHER_PLANT_BATTLE_HELPER_ATTACK_LOCATION_3: 'CommonBuffId' = 204403 - ROLE_MOTHER_PLANT_BATTLE_HELPER_BASE: 'CommonBuffId' = 203655 - ROLE_MOTHER_PLANT_BATTLE_HELPER_INSPIRE: 'CommonBuffId' = 203657 - ROLE_MOTHER_PLANT_BATTLE_HELPER_RALLY: 'CommonBuffId' = 203658 - ROLE_MOTHER_PLANT_BATTLE_HELPER_START: 'CommonBuffId' = 204380 - ROLE_MOTHER_PLANT_BATTLE_HELPER_THROW_CURE_NEXT: 'CommonBuffId' = 204502 - ROLE_MOTHER_PLANT_BATTLE_HELPER_WARBLING_WARCRY: 'CommonBuffId' = 203659 - ROLE_MOTHER_PLANT_BATTLE_OTHER_SIMS: 'CommonBuffId' = 207185 - ROLE_MOTHER_PLANT_BATTLE_PLAYER_ATTACK: 'CommonBuffId' = 203670 - ROLE_MOTHER_PLANT_BATTLE_PLAYER_BASE: 'CommonBuffId' = 203669 - ROLE_MOTHER_PLANT_BATTLE_PLAYER_INSPIRE: 'CommonBuffId' = 203672 - ROLE_MOTHER_PLANT_BATTLE_PLAYER_RALLY: 'CommonBuffId' = 203671 - ROLE_MOTHER_PLANT_BATTLE_PLAYER_START: 'CommonBuffId' = 204385 - ROLE_MOTHER_PLANT_BATTLE_PLAYER_WARBLING_WARCRY: 'CommonBuffId' = 203673 - ROLE_MOTHER_PLANT_BATTLE_ZOMBIE_BASE: 'CommonBuffId' = 203690 - ROLE_MOTHER_PLANT_BATTLE_ZOMBIE_START: 'CommonBuffId' = 204381 - ROLE_MOTHER_PLANT_BATTLE_ZOMBIE_WARBLING_WARCRY: 'CommonBuffId' = 203691 - ROLE_MULTI_UNIT_COMMUNITY_COOK: 'CommonBuffId' = 344208 - ROLE_MULTI_UNIT_COMMUNITY_GARDEN_TEND_GARDEN: 'CommonBuffId' = 343298 - ROLE_MULTI_UNIT_COMMUNITY_MAILBOX_GET_MAIL: 'CommonBuffId' = 343426 - ROLE_MULTI_UNIT_COMMUNITY_NEIGHBOR_CHAT: 'CommonBuffId' = 354022 - ROLE_MULTI_UNIT_COMMUNITY_USE_OBJECTS: 'CommonBuffId' = 343454 - ROLE_MULTI_UNIT_COMMUNITY_USE_TOILET: 'CommonBuffId' = 343458 - ROLE_MULTI_UNIT_EVENT_CHARITY_DRIVE_NPC: 'CommonBuffId' = 345529 - ROLE_MULTI_UNIT_EVENT_CHARITY_DRIVE_PLAYER: 'CommonBuffId' = 345508 - ROLE_MULTI_UNIT_EVENT_CURSED: 'CommonBuffId' = 345176 - ROLE_MULTI_UNIT_EVENT_HAUNTING_GHOST: 'CommonBuffId' = 344694 - ROLE_MULTI_UNIT_EVENT_HAUNTING_TENANT: 'CommonBuffId' = 344757 - ROLE_MULTI_UNIT_EVENT_NUISANCE_PLAYER: 'CommonBuffId' = 349596 - ROLE_MULTI_UNIT_EVENT_NUISANCE_PO_KNOCK: 'CommonBuffId' = 351870 - ROLE_MULTI_UNIT_EVENT_PET_DAY: 'CommonBuffId' = 344803 - ROLE_MULTI_UNIT_EVENT_SEWAGE_LEAK: 'CommonBuffId' = 344640 - ROLE_MULTI_UNIT_EVENT_TRASH_OVERLOAD: 'CommonBuffId' = 344181 - ROLE_MULTI_UNIT_EVENT_TRASH_OVERLOAD_TRASH_DRIVE: 'CommonBuffId' = 344182 - ROLE_NANNY_KIDS: 'CommonBuffId' = 143713 - ROLE_NANNY_LEAVE_LOT_NOW: 'CommonBuffId' = 143677 - ROLE_NANNY_MENTORED_ART: 'CommonBuffId' = 143793 - ROLE_NANNY_MENTORED_HOMEWORK: 'CommonBuffId' = 143792 - ROLE_NANNY_MENTORED_MUSIC: 'CommonBuffId' = 143794 - ROLE_NANNY_MENTORED_SWIM: 'CommonBuffId' = 143791 - ROLE_NO_CAREER_TALK: 'CommonBuffId' = 39294 - ROLE_ONSEN_VENUE_BROWSEVENDINGMACHINE: 'CommonBuffId' = 248288 - ROLE_ONSEN_VENUE_NOSOCIALIZECOOLDOWN: 'CommonBuffId' = 250622 - ROLE_ONSEN_VENUE_PLAYER_HOTSPRINGCOOLDOWN: 'CommonBuffId' = 248508 - ROLE_ONSEN_VENUE_POWERSOAKER: 'CommonBuffId' = 249507 - ROLE_ONSEN_VENUE_SHOWERCOOLDOWN: 'CommonBuffId' = 250628 - ROLE_ONSEN_VENUE_SOAKER_CHANGEINBATHE: 'CommonBuffId' = 248278 - ROLE_ONSEN_VENUE_SOAKER_CHANGEOUTBATHE: 'CommonBuffId' = 248279 - ROLE_ONSEN_VENUE_SOAKER_HOTSPRINGSOAK: 'CommonBuffId' = 248287 - ROLE_OPEN_STREET_COTTAGE_WORLD_FORAGER: 'CommonBuffId' = 264734 - ROLE_OPEN_STREET_COTTAGE_WORLD_GOSSIPER: 'CommonBuffId' = 264549 - ROLE_OPEN_STREET_COTTAGE_WORLD_PICNICKER: 'CommonBuffId' = 263839 - ROLE_OPEN_STREET_EP14_WORLD_COMMUNITY_BOARD_VIEWER: 'CommonBuffId' = 339332 - ROLE_OPEN_STREET_EP14_WORLD_EQUESTRIAN_CENTER_VISITOR: 'CommonBuffId' = 335563 - ROLE_OWNER_BILL_OWNER: 'CommonBuffId' = 176024 - ROLE_OWNER_BILL_OWNER_VFX: 'CommonBuffId' = 177919 - ROLE_PAINTER: 'CommonBuffId' = 232832 - ROLE_PET_PREVENT_CRITICAL_DECAY: 'CommonBuffId' = 168445 - ROLE_PHOTO_TRIPOD_LOCK_AUTONOMY: 'CommonBuffId' = 221131 - ROLE_PHOTO_TRIPOD_PHOTOGRAPHER: 'CommonBuffId' = 217410 - ROLE_PHOTO_TRIPOD_PHOTOGRAPHER_PHOTO_MODE: 'CommonBuffId' = 218435 - ROLE_PHOTO_TRIPOD_PHOTOGRAPHER_TAKE_PHOTO: 'CommonBuffId' = 218426 - ROLE_PHOTO_TRIPOD_POSE_CANT_WAIT_SEE: 'CommonBuffId' = 218693 - ROLE_PHOTO_TRIPOD_POSE_NOT_MY_GOOD_SIDE: 'CommonBuffId' = 218694 - ROLE_PHOTO_TRIPOD_POSE_TAKE_THE_PICTURE: 'CommonBuffId' = 218691 - ROLE_PHOTO_TRIPOD_SUBJECT: 'CommonBuffId' = 217409 - ROLE_PICNIC_ROMANTIC_BLANKET_EAT: 'CommonBuffId' = 364383 - ROLE_POSSESSED: 'CommonBuffId' = 202278 - ROLE_RANCH_HAND_NPC: 'CommonBuffId' = 305070 - ROLE_RANCH_HAND_NPC_ANIMAL_CARE_ROLE: 'CommonBuffId' = 305073 - ROLE_RANCH_HAND_NPC_ARRIVE: 'CommonBuffId' = 339306 - ROLE_RANCH_HAND_NPC_END: 'CommonBuffId' = 339312 - ROLE_RANCH_HAND_NPC_GARDENER_ROLE: 'CommonBuffId' = 305071 - ROLE_RANCH_HAND_NPC_REPAIRMAN_ROLE: 'CommonBuffId' = 305072 - ROLE_RANCH_HAND_STATES_CARE_FOR_ANIMALS: 'CommonBuffId' = 304754 - ROLE_RANCH_HAND_STATES_DONT_CARE_FOR_ANIMALS: 'CommonBuffId' = 304755 - ROLE_RANCH_HAND_STATES_DONT_GARDEN: 'CommonBuffId' = 304757 - ROLE_RANCH_HAND_STATES_DONT_REPAIR: 'CommonBuffId' = 304727 - ROLE_RANCH_HAND_STATES_GARDEN: 'CommonBuffId' = 304756 - ROLE_RANCH_HAND_STATES_REPAIR: 'CommonBuffId' = 304725 - ROLE_RECYCLING_GURU: 'CommonBuffId' = 232824 - ROLE_RESTAURANT_BACKGROUND_SOCIAL_DESIRE: 'CommonBuffId' = 138106 - ROLE_RESTAURANT_CAN_DRAW_ON_PLACEMAT: 'CommonBuffId' = 141036 - ROLE_RESTAURANT_PLAYER_EAT_FOOD: 'CommonBuffId' = 134540 - ROLE_RESTAURANT_PLAYER_WAIT_FOR_FOOD: 'CommonBuffId' = 134550 - ROLE_RESTAURANT_PREFER_SOCIALIZE_WITH_PARTY: 'CommonBuffId' = 138095 - ROLE_RESTAURANT_STAFF_SUPPRESS_SOCIALIZE_AUTONOMOUSLY: 'CommonBuffId' = 138206 - ROLE_RESTAURANT_STAY_ON_LOT: 'CommonBuffId' = 138028 - ROLE_RESTAURANT_STICKY_SEATING: 'CommonBuffId' = 138029 - ROLE_RESTAURANT_SUPPRESS_TRAINING: 'CommonBuffId' = 143648 - ROLE_SCHOOL_SPIRIT_PARTY_GAME_DAY_PARTY_MEMBER_PARTYING: 'CommonBuffId' = 225009 - ROLE_SCHOOL_SPIRIT_PARTY_GAME_DAY_PARTY_PARTY_GOER: 'CommonBuffId' = 225011 - ROLE_SCHOOL_SPIRIT_PARTY_GAME_DAY_PARTY_PLAYER: 'CommonBuffId' = 228447 - ROLE_SCHOOL_SPIRIT_PARTY_SCHOOL_SPIRIT_DAY_MEMBER_PARTYING: 'CommonBuffId' = 210853 - ROLE_SCHOOL_SPIRIT_PARTY_SCHOOL_SPIRIT_DAY_PLAYER: 'CommonBuffId' = 228448 - ROLE_SCHOOL_SPIRIT_PARTY_SCHOOL_SPIRIT_DAY_STUDENT_PARTYING: 'CommonBuffId' = 210857 - ROLE_SCHOOL_SPIRIT_PRANK_CREATIVITY_CELEBRATION_PAINTING: 'CommonBuffId' = 223409 - ROLE_SCHOOL_SPIRIT_PRANK_CREATIVITY_CELEBRATION_PARTYING: 'CommonBuffId' = 223410 - ROLE_SCHOOL_SPIRIT_PRANK_CREATIVITY_CELEBRATION_PLAYER: 'CommonBuffId' = 223439 - ROLE_SCHOOL_SPIRIT_PRANK_GAMEDAY_PARTY_MEMBER_PARTYING: 'CommonBuffId' = 223558 - ROLE_SCHOOL_SPIRIT_PRANK_GAMEDAY_PARTY_PLAYER: 'CommonBuffId' = 228444 - ROLE_SCHOOL_SPIRIT_PRANK_GAMEDAY_PARTY_RIVAL_PARTYING: 'CommonBuffId' = 223557 - ROLE_SCHOOL_SPIRIT_SCHOOL_CHEER: 'CommonBuffId' = 225048 - ROLE_SCROUNGER: 'CommonBuffId' = 234690 - ROLE_SERVICE_NPC_ADOPTION_OFFICER_AND_PETS_NO_FAILURES: 'CommonBuffId' = 169336 - ROLE_SERVICE_NPC_ADOPTION_OFFICER_ARRIVAL: 'CommonBuffId' = 169077 - ROLE_SERVICE_NPC_ADOPTION_OFFICER_ARRIVAL_FIND_PET: 'CommonBuffId' = 171190 - ROLE_SERVICE_NPC_ARRIVE: 'CommonBuffId' = 12633 - ROLE_SERVICE_NPC_GARDENER_SERVICE: 'CommonBuffId' = 130531 - ROLE_SERVICE_NPC_MAID: 'CommonBuffId' = 12634 - ROLE_SERVICE_NPC_MAID_UNIVERSITY_HOUSING: 'CommonBuffId' = 227449 - ROLE_SERVICE_NPC_MAILMAN: 'CommonBuffId' = 12635 - ROLE_SERVICE_NPC_NANNY: 'CommonBuffId' = 141866 - ROLE_SERVICE_NPC_NANNY_ARRIVE: 'CommonBuffId' = 143493 - ROLE_SERVICE_NPC_NANNY_BABY_PLAYING_COOLDOWN: 'CommonBuffId' = 143104 - ROLE_SERVICE_NPC_NANNY_MAKE_FOOD_COOLDOWN: 'CommonBuffId' = 143105 - ROLE_SERVICE_NPC_NANNY_NO_MORE_WORK: 'CommonBuffId' = 143414 - ROLE_SERVICE_NPC_NANNY_OVERTIME_WORK_TIME: 'CommonBuffId' = 143840 - ROLE_SERVICE_NPC_NANNY_WORK_TIME: 'CommonBuffId' = 143398 - ROLE_SERVICE_NPC_ONSEN_VENUE_EMPLOYEE_ARRIVE: 'CommonBuffId' = 247860 - ROLE_SERVICE_NPC_ONSEN_VENUE_EMPLOYEE_WORKING: 'CommonBuffId' = 247876 - ROLE_SERVICE_NPC_PET_ARRIVAL: 'CommonBuffId' = 164880 - ROLE_SERVICE_NPC_PET_ARRIVAL_SELL_ADOPT: 'CommonBuffId' = 171268 - ROLE_SERVICE_NPC_PET_CARE_WORKER_ARRIVAL: 'CommonBuffId' = 164148 - ROLE_SERVICE_NPC_PET_CARE_WORKER_LEAVE: 'CommonBuffId' = 164149 - ROLE_SERVICE_NPC_PET_CARE_WORKER_PET_INACCESSIBLE: 'CommonBuffId' = 177870 - ROLE_SERVICE_NPC_PET_CARE_WORKER_PET_ROUTE_TO_CRATE_SELL: 'CommonBuffId' = 169825 - ROLE_SERVICE_NPC_PET_CARE_WORKER_ROUTE_TO_CRATE: 'CommonBuffId' = 164684 - ROLE_SERVICE_NPC_PET_ROUTE_TO_CRATE: 'CommonBuffId' = 164881 - ROLE_SERVICE_NPC_PIZZA_DELIVERY: 'CommonBuffId' = 9829 - ROLE_SERVICE_NPC_REPAIR: 'CommonBuffId' = 129473 - ROLE_SITUATION_APARTMENT_NEIGHBORS_ANSWER_DOOR_COMPLAINT: 'CommonBuffId' = 139260 - ROLE_SITUATION_APARTMENT_NEIGHBORS_CHECK_MAIL: 'CommonBuffId' = 137331 - ROLE_SITUATION_APARTMENT_NEIGHBORS_COMPLAINED_TO_HIDDEN: 'CommonBuffId' = 140717 - ROLE_SITUATION_APARTMENT_NEIGHBORS_FLIRTY_SHOWER_HAS_BATHED: 'CommonBuffId' = 154398 - ROLE_SITUATION_APARTMENT_NEIGHBORS_HANGOUT_BRAINSTORM: 'CommonBuffId' = 141227 - ROLE_SITUATION_APARTMENT_NEIGHBORS_HANGOUT_CHILDS_PLAY: 'CommonBuffId' = 141232 - ROLE_SITUATION_APARTMENT_NEIGHBORS_HANGOUT_CHILD_COMPLAINT: 'CommonBuffId' = 141231 - ROLE_SITUATION_APARTMENT_NEIGHBORS_HANGOUT_FLIRTY_SHOWER: 'CommonBuffId' = 141226 - ROLE_SITUATION_APARTMENT_NEIGHBORS_HANGOUT_GEEK_OUT: 'CommonBuffId' = 141229 - ROLE_SITUATION_APARTMENT_NEIGHBORS_HANGOUT_GENERIC_GREETED: 'CommonBuffId' = 148298 - ROLE_SITUATION_APARTMENT_NEIGHBORS_HANGOUT_GENERIC_NOT_GREETED: 'CommonBuffId' = 139315 - ROLE_SITUATION_APARTMENT_NEIGHBORS_HANGOUT_KEY_GROUP_GAME_TIME: 'CommonBuffId' = 142572 - ROLE_SITUATION_APARTMENT_NEIGHBORS_HANGOUT_KEY_GROUP_PRE_PARTY: 'CommonBuffId' = 142571 - ROLE_SITUATION_APARTMENT_NEIGHBORS_HANGOUT_MUNCHIES: 'CommonBuffId' = 141228 - ROLE_SITUATION_APARTMENT_NEIGHBORS_HANGOUT_UNINVITED_ARRIVAL: 'CommonBuffId' = 141937 - ROLE_SITUATION_APARTMENT_NEIGHBORS_HANGOUT_WORKOUT: 'CommonBuffId' = 141230 - ROLE_SITUATION_APARTMENT_NEIGHBORS_NPC_WAIT_FOR_OCCUPANT_HIDDEN: 'CommonBuffId' = 155140 - ROLE_SITUATION_APARTMENT_NEIGHBORS_PENTHOUSE_HANGOUT_DONE_GREETING: 'CommonBuffId' = 154720 - ROLE_SITUATION_APARTMENT_NEIGHBORS_PLAYER_COMPLAIN_READY_HIDDEN: 'CommonBuffId' = 154282 - ROLE_SITUATION_APARTMENT_NEIGHBORS_PLAYER_WAIT_FOR_OCCUPANT_HIDDEN: 'CommonBuffId' = 154595 - ROLE_SITUATION_APARTMENT_NEIGHBORS_REACT_TO_YOU_INTRIGUED_NOISE: 'CommonBuffId' = 147080 - ROLE_SITUATION_APARTMENT_NEIGHBORS_REACT_TO_YOU_INTRIGUED_SMELL: 'CommonBuffId' = 147082 - ROLE_SITUATION_APARTMENT_NEIGHBORS_REACT_TO_YOU_KNOCK_ON_DOOR_ANGRY: 'CommonBuffId' = 150824 - ROLE_SITUATION_APARTMENT_NEIGHBORS_REACT_TO_YOU_KNOCK_ON_DOOR_POLITE: 'CommonBuffId' = 150827 - ROLE_SITUATION_APARTMENT_NEIGHBORS_REACT_TO_YOU_NO_SOCIAL: 'CommonBuffId' = 155942 - ROLE_SITUATION_APARTMENT_NEIGHBORS_TAKE_OUT_TRASH: 'CommonBuffId' = 137101 - ROLE_SITUATION_APARTMENT_NEIGHBOR_PLAYER_KNOCKED_POLITELY: 'CommonBuffId' = 155817 - ROLE_SITUATION_DJ_DANCING_NPC_DJ: 'CommonBuffId' = 122816 - ROLE_SITUATION_PENTHOUSE_HANGOUT_KEY_HOLDER_ARRIVAL: 'CommonBuffId' = 153859 - ROLE_SITUATION_PENTHOUSE_HANGOUT_KEY_HOLDER_GREET: 'CommonBuffId' = 155019 - ROLE_SITUATION_PENTHOUSE_HANGOUT_NON_KEY_HOLDER_ARRIVAL: 'CommonBuffId' = 155025 - ROLE_SITUATION_PENTHOUSE_HANGOUT_NON_KEY_HOLDER_GREET: 'CommonBuffId' = 155024 - ROLE_SLEEPOVER_GUEST: 'CommonBuffId' = 313210 - ROLE_SLEEPOVER_HOST: 'CommonBuffId' = 313209 - ROLE_SLEEPOVER_SLEEP: 'CommonBuffId' = 313208 - ROLE_TAKE_CARE_OF_BABY: 'CommonBuffId' = 194622 - ROLE_TAKE_PHOTO: 'CommonBuffId' = 180548 - ROLE_TOURIST_PHOTO_COOLDOWN_HIDDEN: 'CommonBuffId' = 155578 - ROLE_TOURIST_TAKE_PHOTO_NO_ATTRACTOR: 'CommonBuffId' = 201137 - ROLE_TOURIST_VIEW_ATTRACTOR_POINT: 'CommonBuffId' = 197031 - ROLE_TOURIST_VIEW_CELEBRITY_TILE: 'CommonBuffId' = 197029 - ROLE_TRAGIC_CLOWN_NPC: 'CommonBuffId' = 139606 - ROLE_TRAGIC_CLOWN_NPC_F_HAIR: 'CommonBuffId' = 140373 - ROLE_TRAGIC_CLOWN_NPC_M_HAIR: 'CommonBuffId' = 140372 - ROLE_TRASH_DIVER: 'CommonBuffId' = 224214 - ROLE_UNIVERSITY_GRADUATION_CEREMONY: 'CommonBuffId' = 227923 - ROLE_UNIVERSITY_GRADUATION_GATHER: 'CommonBuffId' = 227700 - ROLE_VAMPIRE_VISIT_ARRIVE: 'CommonBuffId' = 153608 - ROLE_VAMPIRE_VISIT_BITE: 'CommonBuffId' = 153607 - ROLE_VAMPIRE_VISIT_BREAK_IN: 'CommonBuffId' = 153609 - ROLE_VAMPIRE_VISIT_STARTLED_LEAVE: 'CommonBuffId' = 156871 - ROLE_VET_BILL_OWNER: 'CommonBuffId' = 168504 - ROLE_VET_BILL_OWNER_PET: 'CommonBuffId' = 178622 - ROLE_VET_CHECK_UP: 'CommonBuffId' = 169865 - ROLE_VET_CUSTOMER_ARRIVAL: 'CommonBuffId' = 166919 - ROLE_VET_EMPLOYEE: 'CommonBuffId' = 171651 - ROLE_VET_EMPLOYEE_EXAM_PET: 'CommonBuffId' = 167023 - ROLE_VET_EMPLOYEE_RESPONSIBILITIES: 'CommonBuffId' = 170055 - ROLE_VET_EMPLOYEE_SUPPRESS_INTERACTIONS: 'CommonBuffId' = 178611 - ROLE_VET_GREETED: 'CommonBuffId' = 167208 - ROLE_VET_NEED_TO_GREET: 'CommonBuffId' = 167207 - ROLE_VET_NO_PHONE: 'CommonBuffId' = 175870 - ROLE_VET_OWNER_SOCIALS: 'CommonBuffId' = 168788 - ROLE_VET_PET: 'CommonBuffId' = 168209 - ROLE_VET_PET_OWNER_DURING_SERVICE: 'CommonBuffId' = 178604 - ROLE_VET_PET_OWNER_STAY_NEAR_PET: 'CommonBuffId' = 169044 - ROLE_VET_PET_OWNER_SUPPRESS_INTERACTIONS: 'CommonBuffId' = 178404 - ROLE_VET_STAY_NEAR_PODIUM: 'CommonBuffId' = 169462 - ROLE_VET_SUPPRESS_GET_COMFORTABLE: 'CommonBuffId' = 168956 - ROLE_VET_SUPPRESS_SOCIAL_AUTONOMY: 'CommonBuffId' = 167085 - ROLE_VET_SUPPRESS_TRAINING: 'CommonBuffId' = 167679 - ROLE_VET_USE_VENDING_MACHINE: 'CommonBuffId' = 173500 - ROLE_VET_USE_VENDING_MACHINE_ONLY: 'CommonBuffId' = 173387 - ROLE_WAITING_IN_LINE: 'CommonBuffId' = 247161 - ROLE_WAIT_FOR_INVITATION_INTERACTIONS_ONLY: 'CommonBuffId' = 238905 - ROLE_WAIT_FOR_INVITATION_INTERACTIONS_ONLY_ANGRY: 'CommonBuffId' = 358726 - ROLE_WANT_FEAR_PARTY_HOST: 'CommonBuffId' = 302072 - ROLE_WEDDING_VENUE_VISITOR: 'CommonBuffId' = 274767 - ROLE_WELCOME_WAGON_NEIGHBOR_FOLLOW_DOOR_KNOCKER: 'CommonBuffId' = 120209 - ROLE_WELCOME_WAGON_NEIGHBOR_UNGREETED: 'CommonBuffId' = 120201 - ROLE_WELCOME_WAGON_SECRET_AGENT: 'CommonBuffId' = 203522 - ROLE_WELCOME_WAGON_SECRET_AGENT_NOTHING_TO_SEE_HERE: 'CommonBuffId' = 204543 - ROLE_WEREWOLF_REPAIRMAN_BE_HANDY: 'CommonBuffId' = 298463 - ROLE_WEREWOLF_REPAIRMAN_HANG_OUT: 'CommonBuffId' = 298800 - ROLE_WOODWORKER: 'CommonBuffId' = 232830 - ROMANCE_DYNAMICS_BREAK_UP_STRESS: 'CommonBuffId' = 365203 - ROMANCE_DYNAMICS_COMFORTED_BY_PARTNER: 'CommonBuffId' = 365180 - ROMANCE_DYNAMICS_CUT_IT_OFF_WITH_TOXIC_EX: 'CommonBuffId' = 365201 - ROMANCE_DYNAMICS_DAY_DREAMING_OF_PARTNER: 'CommonBuffId' = 365197 - ROMANCE_DYNAMICS_DISTRAUGHT_OVER_BREAK_UP: 'CommonBuffId' = 365202 - ROMANCE_DYNAMICS_ITS_GETTING_HOT_IN_HERE: 'CommonBuffId' = 365183 - ROMANCE_DYNAMICS_I_HAVE_A_BAD_FEELING: 'CommonBuffId' = 365182 - ROMANCE_DYNAMICS_I_HOPE_THEYRE_OKAY: 'CommonBuffId' = 365181 - ROMANCE_DYNAMICS_LOST_LOVE: 'CommonBuffId' = 365198 - ROMANCE_DYNAMICS_LOST_STEAMY_LOVE: 'CommonBuffId' = 365199 - ROMANCE_DYNAMICS_LOVE_IS_ALL_YOU_NEED: 'CommonBuffId' = 365185 - ROMANCE_DYNAMICS_LOVE_IS_MAD: 'CommonBuffId' = 365196 - ROMANCE_DYNAMICS_PARTNER_THOUGHTS_HIDDEN: 'CommonBuffId' = 376898 - ROMANCE_DYNAMICS_PARTNER_THOUGHTS_STRAINED_ANGRY: 'CommonBuffId' = 376896 - ROMANCE_DYNAMICS_PARTNER_THOUGHTS_STRAINED_HAPPY: 'CommonBuffId' = 376897 - ROMANCE_DYNAMICS_PARTNER_THOUGHTS_UNPREDICTABLE_FLIRTY: 'CommonBuffId' = 376894 - ROMANCE_DYNAMICS_PARTNER_THOUGHTS_UNPREDICTABLE_TENSE: 'CommonBuffId' = 376895 - ROMANCE_DYNAMICS_PARTNER_THOUGHTS_WHOLESOME: 'CommonBuffId' = 376893 - ROMANCE_DYNAMICS_PEACE_OF_MIND: 'CommonBuffId' = 365204 - ROMANCE_DYNAMICS_ROMANCE_TROPE_ADVENTURE_COOLDOWN: 'CommonBuffId' = 363091 - ROMANCE_DYNAMICS_ROMANCE_TROPE_ADVENTURE_COOLDOWN_STRAINED: 'CommonBuffId' = 393263 - ROMANCE_DYNAMICS_SHARED_SILLIES: 'CommonBuffId' = 365184 - ROMANCE_DYNAMICS_STEAMY_HIDDEN: 'CommonBuffId' = 362485 - ROMANCE_DYNAMICS_STEAMY_REBOUND: 'CommonBuffId' = 365200 - ROMANCE_DYNAMICS_STRAINED_HIDDEN: 'CommonBuffId' = 362498 - ROMANCE_DYNAMICS_UNPREDICTABLE_HIDDEN: 'CommonBuffId' = 362497 - ROMANCE_DYNAMICS_WHOLESOME_HIDDEN: 'CommonBuffId' = 362486 - ROMANCE_DYNAMICS_WORKING_ON_ROMANCE_DYNAMIC: 'CommonBuffId' = 363120 - ROMANCE_SKILL_AURA_OF_FLIRTINESS: 'CommonBuffId' = 370021 - ROMANCE_SKILL_DELAY_TIMER_AURA_OF_FLIRTINESS: 'CommonBuffId' = 392932 - ROMANCE_SKILL_DELAY_TIMER_SCAN_THE_ROOM: 'CommonBuffId' = 392933 - ROMANCE_SKILL_INCREASED_CHANCE: 'CommonBuffId' = 369828 - ROMANCE_SKILL_INCREASED_CHANCE_WOOHOO: 'CommonBuffId' = 369829 - ROMANCE_SKILL_SCAN_THE_ROOM: 'CommonBuffId' = 369827 - ROMANTIC_PHONE_CALLS_7_DATES_0_OUT_OF_7_WILD_DATES: 'CommonBuffId' = 372693 - ROMANTIC_PHONE_CALLS_7_DATES_1_OUT_OF_7_WILD_DATES: 'CommonBuffId' = 372991 - ROMANTIC_PHONE_CALLS_7_DATES_2_OUT_OF_7_WILD_DATES: 'CommonBuffId' = 372992 - ROMANTIC_PHONE_CALLS_7_DATES_3_OUT_OF_7_WILD_DATES: 'CommonBuffId' = 372993 - ROMANTIC_PHONE_CALLS_7_DATES_4_OUT_OF_7_WILD_DATES: 'CommonBuffId' = 372994 - ROMANTIC_PHONE_CALLS_7_DATES_5_OUT_OF_7_WILD_DATES: 'CommonBuffId' = 372995 - ROMANTIC_PHONE_CALLS_7_DATES_6_OUT_OF_7_WILD_DATES: 'CommonBuffId' = 372996 - ROMANTIC_PHONE_CALLS_7_WILD_DATES_FREE_RELATIONSHIP_COUNSELING_HIDDEN: 'CommonBuffId' = 373486 - ROMANTIC_PHONE_CALLS_BABE_COME_OVER_HEART_BED_HURRY: 'CommonBuffId' = 372694 - ROMANTIC_PHONE_CALLS_LOVE_YOU_HEART_MY_PIZZA: 'CommonBuffId' = 373895 - ROMANTIC_PHONE_CALLS_LOVE_YOU_TACO_BOUT_LOVE: 'CommonBuffId' = 372698 - ROMANTIC_PHONE_CALLS_SECRET_ADMIRER_VISIBLE_BUFF: 'CommonBuffId' = 372697 - ROMANTIC_PHONE_CALLS_SECRET_ADMIRER_WHO_WAS_THAT: 'CommonBuffId' = 372696 - ROMANTIC_PHONE_CALLS_THE_WEALTHY_WEIRDO_BLOCKED_HIDDEN: 'CommonBuffId' = 372703 - ROMANTIC_PHONE_CALLS_THE_WEALTHY_WEIRDO_MEETING_WITH_A_WEALTHY_WEIRDO: 'CommonBuffId' = 372695 - ROMANTIC_PHONE_CALLS_THE_WEALTHY_WEIRDO_NO_SHOW_WEIRDO: 'CommonBuffId' = 373087 - ROMANTIC_PHONE_CALLS_THE_WEALTHY_WEIRDO_WEALTHY_WEIRDO_REJECTED: 'CommonBuffId' = 372691 - ROMANTIC_PHONE_CALLS_THE_WEALTHY_WEIRDO_WEIRD_DATE: 'CommonBuffId' = 372692 - ROMANTIC_PHONE_CALLS_WE_NEED_TO_TALK_CHOCOLATE_LOVE: 'CommonBuffId' = 372699 - ROMANTIC_PHONE_CALLS_WE_NEED_TO_TALK_WHEREAREWE: 'CommonBuffId' = 372700 - ROMANTIC_SAGE_SELF_SOOTHE: 'CommonBuffId' = 379089 - ROMANTIC_VENUES_BIRDS_AND_THE_BEES: 'CommonBuffId' = 369863 - ROMANTIC_VENUES_KISS_BEHIND_BOOKSHELF_CONFIDENT: 'CommonBuffId' = 365776 - ROMANTIC_VENUES_KISS_BEHIND_BOOKSHELF_EMBARRASSED: 'CommonBuffId' = 365774 - ROMANTIC_VENUES_SEDUCTIVE_DANCE_IS_DANCING_HIDDEN: 'CommonBuffId' = 392495 - ROMANTIC_VENUES_SHARING_THE_SUNSET: 'CommonBuffId' = 368838 - ROMANTIC_VENUES_SWING_AND_A_MISS: 'CommonBuffId' = 368839 - ROOMMATE_NPC_ARCHETYPE_BREAKER: 'CommonBuffId' = 220347 - ROOMMATE_NPC_ARCHETYPE_CHEERLEADER: 'CommonBuffId' = 211753 - ROOMMATE_NPC_ARCHETYPE_CLINGY_SOCIALITE: 'CommonBuffId' = 207922 - ROOMMATE_NPC_ARCHETYPE_COUCHPOTATO: 'CommonBuffId' = 207923 - ROOMMATE_NPC_ARCHETYPE_EMO_LONER: 'CommonBuffId' = 211750 - ROOMMATE_NPC_ARCHETYPE_FIXER: 'CommonBuffId' = 211754 - ROOMMATE_NPC_ARCHETYPE_LOUD_MUSIC: 'CommonBuffId' = 211752 - ROOMMATE_NPC_ARCHETYPE_MEALMAKER: 'CommonBuffId' = 207921 - ROOMMATE_NPC_ARCHETYPE_PARTY_PLANNER: 'CommonBuffId' = 211751 - ROOMMATE_NPC_ARCHETYPE_SUPER_NEAT: 'CommonBuffId' = 207920 - ROOMMATE_NPC_ARGUMENT_ANGER: 'CommonBuffId' = 223259 - ROOMMATE_NPC_ARGUMENT_SADNESS: 'CommonBuffId' = 223261 - ROOMMATE_NPC_CLEAN_UP_TIME: 'CommonBuffId' = 223504 - ROOMMATE_NPC_EVENTS_ARGUMENT: 'CommonBuffId' = 221659 - ROOMMATE_NPC_EVENTS_GET_HYPE: 'CommonBuffId' = 221657 - ROOMMATE_NPC_EVENTS_LOCKED_OUT: 'CommonBuffId' = 221656 - ROOMMATE_NPC_EVENTS_WHISPERS: 'CommonBuffId' = 221660 - ROOMMATE_NPC_EVENTS_WOOING: 'CommonBuffId' = 221658 - ROOMMATE_NPC_FOUND_A_NOTE: 'CommonBuffId' = 221632 - ROOMMATE_NPC_GETTING_HYPED: 'CommonBuffId' = 223271 - ROOMMATE_NPC_INTERESTS_ART: 'CommonBuffId' = 211756 - ROOMMATE_NPC_INTERESTS_BAKING: 'CommonBuffId' = 211755 - ROOMMATE_NPC_INTERESTS_COMPUTERS: 'CommonBuffId' = 207927 - ROOMMATE_NPC_INTERESTS_FITNESS: 'CommonBuffId' = 211757 - ROOMMATE_NPC_INTERESTS_MUSIC: 'CommonBuffId' = 207926 - ROOMMATE_NPC_KICKED_OUT: 'CommonBuffId' = 223354 - ROOMMATE_NPC_KICKED_OUT_ANGRY: 'CommonBuffId' = 229262 - ROOMMATE_NPC_LATE_ON_RENT_REFUSAL: 'CommonBuffId' = 223350 - ROOMMATE_NPC_LOUD_NOISES: 'CommonBuffId' = 223270 - ROOMMATE_NPC_PARTY_COOLDOWN: 'CommonBuffId' = 212082 - ROOMMATE_NPC_POTENTIAL: 'CommonBuffId' = 220988 - ROOMMATE_NPC_QUIRKS_ABSENT: 'CommonBuffId' = 211759 - ROOMMATE_NPC_QUIRKS_BATHROOM_HOG: 'CommonBuffId' = 207928 - ROOMMATE_NPC_QUIRKS_BIG_CLOSET: 'CommonBuffId' = 211760 - ROOMMATE_NPC_QUIRKS_LATE_ON_RENT: 'CommonBuffId' = 220346 - ROOMMATE_NPC_QUIRKS_PRANKSTER: 'CommonBuffId' = 211761 - ROOMMATE_NPC_QUIRKS_PUBLIC_AFFECTION_DISPLAYER: 'CommonBuffId' = 207929 - ROOMMATE_NPC_RECENT_INTERACTIONS_CLEANING: 'CommonBuffId' = 220403 - ROOMMATE_NPC_RECENT_INTERACTIONS_COMPLIMENT: 'CommonBuffId' = 220406 - ROOMMATE_NPC_RECENT_INTERACTIONS_FIXING: 'CommonBuffId' = 220404 - ROOMMATE_NPC_RECENT_INTERACTIONS_FOOD: 'CommonBuffId' = 220405 - ROOMMATE_NPC_RECENT_INTERACTIONS_NOTES: 'CommonBuffId' = 220422 - ROOMMATE_NPC_RECENT_INTERACTIONS_PUBLIC_AFFECTION: 'CommonBuffId' = 220423 - ROOMMATE_NPC_RECENT_INTERACTIONS_TRASH: 'CommonBuffId' = 220407 - ROOMMATE_NPC_ROOMMATE_DRAMA: 'CommonBuffId' = 221755 - ROOMMATE_NPC_STANDARD: 'CommonBuffId' = 208160 - ROOMMATE_NPC_UNEXPECTED_KINDNESS: 'CommonBuffId' = 221648 - ROOMMATE_NPC_WHISPER_ANGRY: 'CommonBuffId' = 223473 - ROOMMATE_NPC_WHISPER_FLIRTY: 'CommonBuffId' = 223474 - ROOMMATE_NPC_WHISPER_HAPPY: 'CommonBuffId' = 223477 - ROOMMATE_NPC_WHISPER_INSPIRED: 'CommonBuffId' = 223472 - ROOMMATE_NPC_WHISPER_SAD: 'CommonBuffId' = 223478 - ROOMMATE_NPC_WHISPER_SAD_WATCHING: 'CommonBuffId' = 223476 - ROOMMATE_NPC_WHISPER_STRESSED_WATCHING: 'CommonBuffId' = 223475 - ROOMMATE_NPC_WOOING_SPURNED: 'CommonBuffId' = 223471 - ROOT_BEER_FLOAT_GOOD_OLD_DAYS: 'CommonBuffId' = 124812 - ROUTE_USE_PHONE: 'CommonBuffId' = 273647 - ROUTE_USE_PHONE_PLAYER_ONLY: 'CommonBuffId' = 282929 - ROYALTY_TRENDING_VIDEO: 'CommonBuffId' = 196736 - S4CL_EXAMPLE_APPLY_BARE_FEET: 'CommonBuffId' = 16461769487103204847 - SABACC_TABLE_ACCUSE_OF_CHEATING_ACCUSED: 'CommonBuffId' = 241815 - SABACC_TABLE_ACCUSE_OF_CHEATING_ACCUSER: 'CommonBuffId' = 241791 - SABACC_TABLE_BETTING: 'CommonBuffId' = 251755 - SABACC_TABLE_BETWEEN_BETTING_PHASES: 'CommonBuffId' = 251712 - SABACC_TABLE_CANCELLED: 'CommonBuffId' = 251746 - SABACC_TABLE_CANT_CHEAT_ME: 'CommonBuffId' = 241923 - SABACC_TABLE_CAUGHT_SABACC_CHEAT: 'CommonBuffId' = 241922 - SABACC_TABLE_CHEATED: 'CommonBuffId' = 237259 - SABACC_TABLE_CHEAT_SLEIGHT_OF_HAND_ACCUSER_FAIL: 'CommonBuffId' = 241925 - SABACC_TABLE_CHEAT_SLEIGHT_OF_HAND_NOTHING_UP_MY_SLEEVE: 'CommonBuffId' = 241924 - SABACC_TABLE_END: 'CommonBuffId' = 250860 - SABACC_TABLE_EVERYONE_FOLDED_I_WIN: 'CommonBuffId' = 243664 - SABACC_TABLE_FOLDED: 'CommonBuffId' = 233815 - SABACC_TABLE_GRABBED_CARDS: 'CommonBuffId' = 234914 - SABACC_TABLE_IN_GAME: 'CommonBuffId' = 230955 - SABACC_TABLE_NPC_NOT_ALLOWED_TO_PLAY: 'CommonBuffId' = 247612 - SABACC_TABLE_PLAY: 'CommonBuffId' = 244249 - SABACC_TABLE_PLAY_STYLE_CONFIDENT: 'CommonBuffId' = 237241 - SABACC_TABLE_PLAY_STYLE_LOGICAL: 'CommonBuffId' = 237242 - SABACC_TABLE_SCORED: 'CommonBuffId' = 245562 - SABACC_TABLE_VISIBLE_CALCULATED_MOVE: 'CommonBuffId' = 237246 - SABACC_TABLE_VISIBLE_FISHING_FOR_A_BREAK: 'CommonBuffId' = 243382 - SABACC_TABLE_VISIBLE_IDIOTS_ARRAY: 'CommonBuffId' = 243379 - SABACC_TABLE_VISIBLE_KNACK_FOR_SABACC: 'CommonBuffId' = 243377 - SABACC_TABLE_VISIBLE_NOT_MY_CREDITS: 'CommonBuffId' = 243381 - SABACC_TABLE_VISIBLE_PAYDAY: 'CommonBuffId' = 243378 - SABACC_TABLE_VISIBLE_PURE_SABACC: 'CommonBuffId' = 243380 - SABACC_TABLE_VISIBLE_WHILE_NOONE_IS_WATCHING: 'CommonBuffId' = 243663 - SAD_MELANCHOLY_THOUGHTS: 'CommonBuffId' = 26764 - SAD_STARTLED_BY_GHOST: 'CommonBuffId' = 156627 - SAD_SUBTLY_DEBASE: 'CommonBuffId' = 35133 - SAMPLE_FOODS_COOKING_0: 'CommonBuffId' = 143582 - SAMPLE_FOODS_COOKING_2: 'CommonBuffId' = 143586 - SAMPLE_FOODS_COOKING_3: 'CommonBuffId' = 143588 - SAMPLE_FOODS_COOKING_4: 'CommonBuffId' = 143589 - SAMPLE_FOODS_COOKING_5: 'CommonBuffId' = 143591 - SAMPLE_FOODS_COOKING_INGREDIENTS_BAD: 'CommonBuffId' = 143593 - SAMPLE_FOODS_COOKING_INGREDIENTS_GOOD: 'CommonBuffId' = 143595 - SAMPLE_FOODS_NAUSEOUS_LITE: 'CommonBuffId' = 143627 - SANCTUARY_BANNED: 'CommonBuffId' = 345604 - SANCTUARY_COOLDOWN: 'CommonBuffId' = 356755 - SANCTUARY_DONATION: 'CommonBuffId' = 345649 - SANCTUARY_EMBARRASSED: 'CommonBuffId' = 345648 - SANCTUARY_HAPPY: 'CommonBuffId' = 345646 - SANCTUARY_HEIST: 'CommonBuffId' = 345650 - SANCTUARY_PLAYFUL: 'CommonBuffId' = 345647 - SAND_ACTIVITES_GOOD_TIMES: 'CommonBuffId' = 210227 - SAND_ACTIVITES_SAND_SCULPTURE_COOLDOWN: 'CommonBuffId' = 216237 - SAND_ACTIVITES_SAND_SCULPTURE_IS_BUILDING: 'CommonBuffId' = 212673 - SAND_ACTIVITES_SAND_SCULPTURE_MONSTER_STOMPER: 'CommonBuffId' = 210595 - SAND_ACTIVITES_SAND_SCULPTURE_RUINED: 'CommonBuffId' = 210597 - SAND_ACTIVITES_SAND_SCULPTURE_SCULPTOR: 'CommonBuffId' = 210584 - SAND_PLAY_BEACHY_MOOD: 'CommonBuffId' = 277483 - SAND_PLAY_ROMANCE_WRIT_LARGE: 'CommonBuffId' = 277487 - SAND_PLAY_SANDY_SENTIMENTALITY: 'CommonBuffId' = 277482 - SAND_PLAY_SMILES_FOR_MILES: 'CommonBuffId' = 277488 - SAND_PLAY_SNOWY_MOOD: 'CommonBuffId' = 277486 - SAND_PLAY_SNOWY_SENTIMENTALITY: 'CommonBuffId' = 277507 - SAND_PLAY_STARRY_SAND: 'CommonBuffId' = 277484 - SAND_PLAY_STARRY_SNOW: 'CommonBuffId' = 277485 - SCARECROW_ASK_FOR_GARDENING_TIPS: 'CommonBuffId' = 189830 - SCARECROW_CANT_CHECK_POCKETS: 'CommonBuffId' = 188657 - SCARECROW_HIDDEN_ASK_FOR_TIPS_COOLDOWN: 'CommonBuffId' = 191244 - SCARECROW_HIDDEN_JUST_BEFRIENDED: 'CommonBuffId' = 190220 - SCARECROW_REACT_CHILD_NEGATIVE: 'CommonBuffId' = 189324 - SCARECROW_REACT_CHILD_POSITIVE: 'CommonBuffId' = 189323 - SCARECROW_REACT_FOCUSED: 'CommonBuffId' = 189325 - SCARECROW_REACT_NEGATIVE: 'CommonBuffId' = 189321 - SCARECROW_REACT_POSITIVE: 'CommonBuffId' = 189322 - SCARECROW_SITUATION_IS_SCARECROW: 'CommonBuffId' = 190165 - SCARED_ENCOURAGEMENT: 'CommonBuffId' = 256498 - SCARED_SLEEPING_SCARED: 'CommonBuffId' = 253327 - SCENARIO_ALIEN_ABDUCTION_CANCEL_RABBIT_HOLE: 'CommonBuffId' = 305127 - SCENARIO_ALIEN_ABDUCTION_HIDDEN_OUTCOME_CANCEL_RABBIT_HOLE: 'CommonBuffId' = 305237 - SCENARIO_ALIEN_ABDUCTION_PARENTS: 'CommonBuffId' = 305125 - SCENARIO_CARNAVAL_DANCE: 'CommonBuffId' = 285818 - SCENARIO_EXPLORE_THE_NIGHT_NIGHT_TIME: 'CommonBuffId' = 302113 - SCENARIO_EXPLORE_THE_NIGHT_SLEEPING_OR_PASSED_OUT: 'CommonBuffId' = 302117 - SCENARIO_EXPLORE_THE_NIGHT_STAYED_UP: 'CommonBuffId' = 302059 - SCENARIO_EXPLORE_THE_NIGHT_STAY_UP: 'CommonBuffId' = 302114 - SCENARIO_GROUP_COOKED: 'CommonBuffId' = 281109 - SCENARIO_HONEYMOONERS_JUST_MARRIED_HIDDEN: 'CommonBuffId' = 280685 - SCENARIO_IN_THE_MOODLET_HIDDEN: 'CommonBuffId' = 296355 - SCENARIO_IN_THE_MOODLET_MOOD_ANGRY: 'CommonBuffId' = 296363 - SCENARIO_IN_THE_MOODLET_MOOD_EMBARRASSED: 'CommonBuffId' = 296362 - SCENARIO_IN_THE_MOODLET_MOOD_SAD: 'CommonBuffId' = 296364 - SCENARIO_IN_THE_MOODLET_MOOD_TENSE: 'CommonBuffId' = 296365 - SCENARIO_IN_THE_MOODLET_MOOD_UNCOMFORTABLE: 'CommonBuffId' = 296366 - SCENARIO_NO_SKILLS_NO_PROBLEM: 'CommonBuffId' = 282977 - SCENARIO_ON_BOARDING_NEW_IN_TOWN_EXPLORING_TOWN: 'CommonBuffId' = 297044 - SCENARIO_ON_BOARDING_NEW_IN_TOWN_GOALED_PARTY: 'CommonBuffId' = 297904 - SCENARIO_ON_BOARDING_NEW_IN_TOWN_PHASE_1_MET_NEW_PEOPLE: 'CommonBuffId' = 297685 - SCENARIO_ON_BOARDING_NEW_IN_TOWN_PHASE_3A_ATHLETIC_OUTFIT: 'CommonBuffId' = 295817 - SCENARIO_ON_BOARDING_NEW_IN_TOWN_PHASE_3B_PARTY_OUTFIT: 'CommonBuffId' = 295818 - SCENARIO_ON_BOARDING_NEW_IN_TOWN_PHASE_3X_DRANK_MOODLET_SOLVER_POTION: 'CommonBuffId' = 295819 - SCENARIO_ON_BOARDING_NEW_IN_TOWN_PHASE_4_BOUGHT_OBSERVANT_TRAIT: 'CommonBuffId' = 295821 - SCENARIO_ON_BOARDING_NEW_IN_TOWN_PHASE_4_CHOSE_DATE: 'CommonBuffId' = 300767 - SCENARIO_ON_BOARDING_NEW_IN_TOWN_PHASE_4_CHOSE_HANGOUT: 'CommonBuffId' = 300768 - SCENARIO_ON_BOARDING_NEW_IN_TOWN_PHASE_4_RELATIONSHIP_GAIN: 'CommonBuffId' = 297060 - SCENARIO_PARENTING_PREDICAMENTS_AGED_UP: 'CommonBuffId' = 307947 - SCENARIO_PARENTING_PREDICAMENTS_AGE_UP_IN_QUEUE: 'CommonBuffId' = 308323 - SCENARIO_PARENTING_PREDICAMENTS_BIRTHDAY_PARTY: 'CommonBuffId' = 298969 - SCENARIO_PARENTING_PREDICAMENTS_TEEN_DATE: 'CommonBuffId' = 298973 - SCENARIO_PROUD_PARENT_ADOPTED_BABY: 'CommonBuffId' = 300937 - SCENARIO_PROUD_PARENT_TEEN_TNS_GIVEN: 'CommonBuffId' = 301064 - SCENARIO_STUCK_IN_THEIR_SHADOW_1_INVITED_RIVAL: 'CommonBuffId' = 295446 - SCENIC_BROADCASTER_CLIFF_LOOKOUT: 'CommonBuffId' = 179592 - SCENIC_BROADCASTER_HIGH_POINT: 'CommonBuffId' = 179594 - SCENIC_BROADCASTER_NATURAL_POOL: 'CommonBuffId' = 179596 - SCENIC_BROADCASTER_SECRET_AREA: 'CommonBuffId' = 179595 - SCENIC_BROADCASTER_WATERFALL_VISTA: 'CommonBuffId' = 179593 - SCHOOL_PROJECT_BOX_DESTROYED_PROJECT_DESTROYER: 'CommonBuffId' = 165434 - SCHOOL_PROJECT_BOX_DESTROYED_PROJECT_OWNER_ANGRY: 'CommonBuffId' = 165460 - SCHOOL_PROJECT_BOX_DESTROYED_PROJECT_OWNER_SAD: 'CommonBuffId' = 165463 - SCHOOL_PROJECT_BOX_EXTRA_CREDIT_POTENTIAL: 'CommonBuffId' = 162792 - SCHOOL_PROJECT_BOX_FINISHED_PROJECT: 'CommonBuffId' = 163000 - SCHOOL_PROJECT_BOX_FINISHED_PROJECT_NORMAL_OR_HIGH_QUALITY: 'CommonBuffId' = 163634 - SCHOOL_PROJECT_BOX_FINISHED_PROJECT_POOR_QUALITY: 'CommonBuffId' = 163633 - SCHOOL_PROJECT_BOX_RECEIVE_PROGRESS_NEXT_SCHOOL_DAY: 'CommonBuffId' = 163467 - SCHOOL_PROJECT_BOX_WORKING_CAREFULLY: 'CommonBuffId' = 162991 - SCIENTIST_BREAKTHROUGH_ANIMATION: 'CommonBuffId' = 108411 - SCUBA_REBREATHER: 'CommonBuffId' = 206586 - SCUBA_WETSUIT: 'CommonBuffId' = 214157 - SEANCE_TABLE_AINT_AFRAID: 'CommonBuffId' = 251622 - SEANCE_TABLE_BONEHILDA: 'CommonBuffId' = 253381 - SEANCE_TABLE_BOTCHED_RITUAL: 'CommonBuffId' = 251623 - SEANCE_TABLE_GHOSTS_ARE_JERKS: 'CommonBuffId' = 251626 - SEANCE_TABLE_GHOST_FORM_HOUSEHOLD: 'CommonBuffId' = 255378 - SEANCE_TABLE_HAUNTING_MESSAGE: 'CommonBuffId' = 251628 - SEANCE_TABLE_MELANCHOLY_MALAISE: 'CommonBuffId' = 251629 - SEANCE_TABLE_NOT_VISIBLE_GHOST_FORM_CHECK: 'CommonBuffId' = 255364 - SEANCE_TABLE_NOT_VISIBLE_IN_SEANCE: 'CommonBuffId' = 255082 - SEANCE_TABLE_NOT_VISIBLE_SEANCE_EXIT: 'CommonBuffId' = 251973 - SEANCE_TABLE_NOT_VISIBLE_SUCCESFUL_CEREMONY: 'CommonBuffId' = 253105 - SEANCE_TABLE_OTHERWORLDLY_GUIDANCE: 'CommonBuffId' = 251624 - SEANCE_TABLE_SPECTRAL_SMALL_TALK: 'CommonBuffId' = 251627 - SEANCE_TABLE_SPELLCASTER: 'CommonBuffId' = 255933 - SEANCE_TABLE_UHH_WHAT: 'CommonBuffId' = 251625 - SEASONAL_THROWING_MUD_HAPPY: 'CommonBuffId' = 181562 - SEASONAL_THROWING_MUD_PLAYFUL: 'CommonBuffId' = 181565 - SEASONAL_THROWING_NAILED_MUD: 'CommonBuffId' = 181835 - SEASONAL_THROWING_NAILED_SNOWBALL: 'CommonBuffId' = 181560 - SEASONAL_THROWING_NAILED_WATER_BALLOON: 'CommonBuffId' = 181836 - SEASONAL_THROWING_SKILL_LEVEL_01: 'CommonBuffId' = 183320 - SEASONAL_THROWING_SKILL_LEVEL_02: 'CommonBuffId' = 183321 - SEASONAL_THROWING_SKILL_LEVEL_03: 'CommonBuffId' = 183322 - SEASONAL_THROWING_SKILL_LEVEL_04: 'CommonBuffId' = 183323 - SEASONAL_THROWING_SKILL_LEVEL_05: 'CommonBuffId' = 183319 - SEASONAL_THROWING_SNOWBALL_HAPPY: 'CommonBuffId' = 181566 - SEASONAL_THROWING_SNOWBALL_PLAYFUL: 'CommonBuffId' = 181563 - SEASONAL_THROWING_SNOWBALL_UNCOMFORTABLE: 'CommonBuffId' = 247475 - SEASONAL_THROWING_WATER_BALLOON_HAPPY: 'CommonBuffId' = 181564 - SEASONAL_THROWING_WATER_BALLOON_HIDDEN_WET: 'CommonBuffId' = 191359 - SEASONAL_THROWING_WATER_BALLOON_PLAYFUL: 'CommonBuffId' = 181561 - SEA_FOOD_COLORFUL_MEAL: 'CommonBuffId' = 352534 - SEA_FOOD_FILLING_ENTREE: 'CommonBuffId' = 352535 - SEA_FOOD_UNIQUE_BEVERAGE: 'CommonBuffId' = 352533 - SECRET_LAB_VENUE: 'CommonBuffId' = 203479 - SEEDS_OF_DOUBT: 'CommonBuffId' = 35125 - SELF_DISCOVERY_ANIMAL_CAT: 'CommonBuffId' = 335501 - SELF_DISCOVERY_ANIMAL_DOG: 'CommonBuffId' = 335500 - SELF_DISCOVERY_CAN_MAKE_PROGRESS: 'CommonBuffId' = 315849 - SELF_DISCOVERY_DISCOVERY_MOMENT: 'CommonBuffId' = 318056 - SELF_DISCOVERY_DISCOVERY_MOMENT_COOLDOWN: 'CommonBuffId' = 318344 - SELF_DISCOVERY_DISCOVERY_MOMENT_COOLDOWN_PARANOID: 'CommonBuffId' = 342234 - SELF_DISCOVERY_DISCOVERY_MOMENT_COOLDOWN_SQUEAMISH: 'CommonBuffId' = 342233 - SELF_DISCOVERY_HYGIENE_PAUSE: 'CommonBuffId' = 334984 - SELF_DISCOVERY_METABOLISM_DRANK_SPOILED_MILK: 'CommonBuffId' = 319212 - SELF_DISCOVERY_MOOD_CURRENT_SITUATION_ANGRY: 'CommonBuffId' = 334507 - SELF_DISCOVERY_MOOD_CURRENT_SITUATION_SAD: 'CommonBuffId' = 334508 - SELF_DISCOVERY_ROMANCE_REJECTED_SOCIALS: 'CommonBuffId' = 375926 - SELF_DISCOVERY_SCARED_ERRATIC: 'CommonBuffId' = 335008 - SELF_DISCOVERY_VIRTUES_ACT_PROPER: 'CommonBuffId' = 335005 - SENTIMENT_ADORING_CONFIDENT_CONSOLE_DEATH: 'CommonBuffId' = 273916 - SENTIMENT_ADORING_CONFIDENT_GENERIC: 'CommonBuffId' = 246891 - SENTIMENT_ADORING_CONFIDENT_IMPRESSED: 'CommonBuffId' = 246930 - SENTIMENT_ADORING_CONFIDENT_LIFESAVER: 'CommonBuffId' = 247280 - SENTIMENT_ADORING_HAPPY_CONTAGION_GENERIC: 'CommonBuffId' = 246886 - SENTIMENT_ADORING_HAPPY_PRIMARY_AMAZING_BEING: 'CommonBuffId' = 274240 - SENTIMENT_ADORING_HAPPY_PRIMARY_CONSOLE_DEATH: 'CommonBuffId' = 273917 - SENTIMENT_ADORING_HAPPY_PRIMARY_DECORATOR_GOOD_BUILD: 'CommonBuffId' = 268269 - SENTIMENT_ADORING_HAPPY_PRIMARY_GENERIC: 'CommonBuffId' = 246883 - SENTIMENT_ADORING_HAPPY_PRIMARY_GROWING_FAMILY: 'CommonBuffId' = 274149 - SENTIMENT_ADORING_HAPPY_PRIMARY_IMPRESSED: 'CommonBuffId' = 246948 - SENTIMENT_ADORING_HAPPY_PRIMARY_INFECTIOUS_JOY: 'CommonBuffId' = 274150 - SENTIMENT_ADORING_HAPPY_PRIMARY_LIFESAVER: 'CommonBuffId' = 247281 - SENTIMENT_ADORING_HAPPY_PRIMARY_TWIN_FLAMES: 'CommonBuffId' = 357662 - SENTIMENT_ADORING_HAPPY_PRIMARY_WITNESS_FOAL_BIRTH: 'CommonBuffId' = 338408 - SENTIMENT_ADORING_INSPIRED_CONSOLE_DEATH: 'CommonBuffId' = 273918 - SENTIMENT_ADORING_INSPIRED_GENERIC: 'CommonBuffId' = 246905 - SENTIMENT_ADORING_INSPIRED_IMPRESSED: 'CommonBuffId' = 246962 - SENTIMENT_ADORING_INSPIRED_LIFESAVER: 'CommonBuffId' = 247282 - SENTIMENT_ADORING_PLAYFUL_CONTAGION_INFECTIOUS_JOY: 'CommonBuffId' = 314926 - SENTIMENT_ADORING_PLAYFUL_WITNESS_FOAL_BIRTH: 'CommonBuffId' = 338411 - SENTIMENT_BITTER_ANGRY_BIT_AT_BY_HORSE: 'CommonBuffId' = 340340 - SENTIMENT_BITTER_ANGRY_BREAKUP: 'CommonBuffId' = 247302 - SENTIMENT_BITTER_ANGRY_CHEATING: 'CommonBuffId' = 247300 - SENTIMENT_BITTER_ANGRY_CRUMPLEBOTTOMED: 'CommonBuffId' = 264468 - SENTIMENT_BITTER_ANGRY_DIVORCE: 'CommonBuffId' = 247306 - SENTIMENT_BITTER_ANGRY_FIGHT: 'CommonBuffId' = 247316 - SENTIMENT_BITTER_ANGRY_GENERIC: 'CommonBuffId' = 241022 - SENTIMENT_BITTER_ANGRY_HIKING_TRAIL: 'CommonBuffId' = 250368 - SENTIMENT_BITTER_ANGRY_LIFESTYLE_WORKAHOLIC: 'CommonBuffId' = 252772 - SENTIMENT_BITTER_ANGRY_LIVESTOCK_SOLD: 'CommonBuffId' = 263678 - SENTIMENT_BITTER_ANGRY_MOUNTAIN_CLIMB: 'CommonBuffId' = 253627 - SENTIMENT_BITTER_ANGRY_MOUNTAIN_CLIMB_LT: 'CommonBuffId' = 254127 - SENTIMENT_BITTER_ANGRY_NOT_THAT_CUTE: 'CommonBuffId' = 274212 - SENTIMENT_BITTER_ANGRY_VILLAGE_FAIR_BRIBE_FAIL: 'CommonBuffId' = 268422 - SENTIMENT_BITTER_ANGRY_YOGA_CLASS: 'CommonBuffId' = 271981 - SENTIMENT_BITTER_CONTAGION_HAPPY_GENERIC: 'CommonBuffId' = 241018 - SENTIMENT_BITTER_CONTAGION_HAPPY_SIBLING_JEALOUSY: 'CommonBuffId' = 274221 - SENTIMENT_BITTER_TENSE_PRIMARY_BIT_AT_BY_HORSE: 'CommonBuffId' = 340339 - SENTIMENT_BITTER_TENSE_PRIMARY_BREAKUP: 'CommonBuffId' = 247304 - SENTIMENT_BITTER_TENSE_PRIMARY_CHEATING: 'CommonBuffId' = 247285 - SENTIMENT_BITTER_TENSE_PRIMARY_CRUMPLEBOTTOMED: 'CommonBuffId' = 264469 - SENTIMENT_BITTER_TENSE_PRIMARY_DIVORCE: 'CommonBuffId' = 247307 - SENTIMENT_BITTER_TENSE_PRIMARY_FIGHT: 'CommonBuffId' = 247317 - SENTIMENT_BITTER_TENSE_PRIMARY_GENERIC: 'CommonBuffId' = 241020 - SENTIMENT_BITTER_TENSE_PRIMARY_HIKING_TRAIL: 'CommonBuffId' = 251494 - SENTIMENT_BITTER_TENSE_PRIMARY_LIFESTYLE_WORKAHOLIC: 'CommonBuffId' = 252773 - SENTIMENT_BITTER_TENSE_PRIMARY_LIVESTOCK_SOLD: 'CommonBuffId' = 263701 - SENTIMENT_BITTER_TENSE_PRIMARY_MOUNTAIN_CLIMB: 'CommonBuffId' = 254128 - SENTIMENT_BITTER_TENSE_PRIMARY_MOUNTAIN_CLIMB_LT: 'CommonBuffId' = 254137 - SENTIMENT_BITTER_TENSE_PRIMARY_PHONE_BREAK_UP: 'CommonBuffId' = 375528 - SENTIMENT_BITTER_TENSE_PRIMARY_WHATS_SO_SPECIAL: 'CommonBuffId' = 274204 - SENTIMENT_BITTER_TENSE_PRIMARY_YOGA_CLASS: 'CommonBuffId' = 271980 - SENTIMENT_CLOSE_CONFIDENT_LOYAL_REGAINED_TRUST: 'CommonBuffId' = 312706 - SENTIMENT_CLOSE_CONFIDENT_STRONGER_TOGETHER: 'CommonBuffId' = 357664 - SENTIMENT_CLOSE_FLIRTY_GENERIC: 'CommonBuffId' = 240624 - SENTIMENT_CLOSE_HAPPY_CONTAGION_GENERIC: 'CommonBuffId' = 240622 - SENTIMENT_CLOSE_HAPPY_CONTAGION_NEAR_DEATH: 'CommonBuffId' = 247388 - SENTIMENT_CLOSE_HAPPY_PRIMARY_ADOPTION: 'CommonBuffId' = 247383 - SENTIMENT_CLOSE_HAPPY_PRIMARY_CANNING_RECEIVED_GIFT: 'CommonBuffId' = 262186 - SENTIMENT_CLOSE_HAPPY_PRIMARY_COTTAGE_WORLD_NPC_GOSSIP: 'CommonBuffId' = 264955 - SENTIMENT_CLOSE_HAPPY_PRIMARY_GENERIC: 'CommonBuffId' = 240626 - SENTIMENT_CLOSE_HAPPY_PRIMARY_GENERIC_LT: 'CommonBuffId' = 247337 - SENTIMENT_CLOSE_HAPPY_PRIMARY_GROUP_COOKING_COOKING_TOGETHER: 'CommonBuffId' = 262315 - SENTIMENT_CLOSE_HAPPY_PRIMARY_HAPPY_NEW_DYNAMIC: 'CommonBuffId' = 357663 - SENTIMENT_CLOSE_HAPPY_PRIMARY_HIKING_TRAIL: 'CommonBuffId' = 250367 - SENTIMENT_CLOSE_HAPPY_PRIMARY_HOTPOT: 'CommonBuffId' = 252799 - SENTIMENT_CLOSE_HAPPY_PRIMARY_LIFESTYLE_CLOSE_KNIT: 'CommonBuffId' = 252776 - SENTIMENT_CLOSE_HAPPY_PRIMARY_LIGHT_FESTIVAL_WISH: 'CommonBuffId' = 253249 - SENTIMENT_CLOSE_HAPPY_PRIMARY_LOYAL_REGAINED_TRUST: 'CommonBuffId' = 312702 - SENTIMENT_CLOSE_HAPPY_PRIMARY_LYCAN_BOND: 'CommonBuffId' = 288813 - SENTIMENT_CLOSE_HAPPY_PRIMARY_MOUNTAIN_CLIMB: 'CommonBuffId' = 254129 - SENTIMENT_CLOSE_HAPPY_PRIMARY_NEAR_DEATH: 'CommonBuffId' = 247387 - SENTIMENT_CLOSE_HAPPY_PRIMARY_ONSEN: 'CommonBuffId' = 252802 - SENTIMENT_CLOSE_HAPPY_PRIMARY_PARTY: 'CommonBuffId' = 247373 - SENTIMENT_CLOSE_HAPPY_PRIMARY_PICNIC_BASKET_PICNIC_BONDING: 'CommonBuffId' = 262187 - SENTIMENT_CLOSE_HAPPY_PRIMARY_QUALITY_TIME: 'CommonBuffId' = 247333 - SENTIMENT_CLOSE_HAPPY_PRIMARY_SNOW: 'CommonBuffId' = 252582 - SENTIMENT_CLOSE_HAPPY_PRIMARY_SNOW_FESTIVAL_PARTY: 'CommonBuffId' = 253205 - SENTIMENT_CLOSE_HAPPY_PRIMARY_SNOW_FESTIVAL_PLAY: 'CommonBuffId' = 253195 - SENTIMENT_CLOSE_HAPPY_PRIMARY_TEA_SET_TEA_PARTY: 'CommonBuffId' = 280850 - SENTIMENT_CLOSE_HAPPY_PRIMARY_TRUSTING: 'CommonBuffId' = 283864 - SENTIMENT_CLOSE_HAPPY_PRIMARY_VACATION_SNOWY: 'CommonBuffId' = 252437 - SENTIMENT_CLOSE_HAPPY_PRIMARY_VILLAGER_HELP_HELPED_OUT: 'CommonBuffId' = 266370 - SENTIMENT_CLOSE_HAPPY_PRIMARY_VILLAGE_FAIR_BRIBE_SUCCESS: 'CommonBuffId' = 268400 - SENTIMENT_CLOSE_HAPPY_PRIMARY_YOUTH_FESTIVAL_BLESSED: 'CommonBuffId' = 253250 - SENTIMENT_CLOSE_PLAYFUL_ADOPTION: 'CommonBuffId' = 247386 - SENTIMENT_CLOSE_PLAYFUL_CANNING_RECEIVED_GIFT: 'CommonBuffId' = 262189 - SENTIMENT_CLOSE_PLAYFUL_COTTAGE_WORLD_NPC_GOSSIP: 'CommonBuffId' = 264956 - SENTIMENT_CLOSE_PLAYFUL_GENERIC: 'CommonBuffId' = 240625 - SENTIMENT_CLOSE_PLAYFUL_GENERIC_LT: 'CommonBuffId' = 247350 - SENTIMENT_CLOSE_PLAYFUL_GROUP_COOKING_COOKING_TOGETHER: 'CommonBuffId' = 262320 - SENTIMENT_CLOSE_PLAYFUL_HIKING_TRAIL: 'CommonBuffId' = 254133 - SENTIMENT_CLOSE_PLAYFUL_HOTPOT: 'CommonBuffId' = 252801 - SENTIMENT_CLOSE_PLAYFUL_LIFESTYLE_CLOSE_KNIT: 'CommonBuffId' = 252778 - SENTIMENT_CLOSE_PLAYFUL_LIGHT_FESTIVAL_WISH: 'CommonBuffId' = 253252 - SENTIMENT_CLOSE_PLAYFUL_LYCAN_BOND: 'CommonBuffId' = 288814 - SENTIMENT_CLOSE_PLAYFUL_MOUNTAIN_CLIMB: 'CommonBuffId' = 254131 - SENTIMENT_CLOSE_PLAYFUL_NEAR_DEATH: 'CommonBuffId' = 247401 - SENTIMENT_CLOSE_PLAYFUL_ONSEN: 'CommonBuffId' = 252804 - SENTIMENT_CLOSE_PLAYFUL_PARTY: 'CommonBuffId' = 247375 - SENTIMENT_CLOSE_PLAYFUL_PICNIC_BASKET_PICNIC_BONDING: 'CommonBuffId' = 262188 - SENTIMENT_CLOSE_PLAYFUL_QUALITY_TIME: 'CommonBuffId' = 247335 - SENTIMENT_CLOSE_PLAYFUL_SNOW: 'CommonBuffId' = 252584 - SENTIMENT_CLOSE_PLAYFUL_SNOW_FESTIVAL_PARTY: 'CommonBuffId' = 253206 - SENTIMENT_CLOSE_PLAYFUL_SNOW_FESTIVAL_PLAY: 'CommonBuffId' = 253196 - SENTIMENT_CLOSE_PLAYFUL_TEA_SET_TEA_PARTY: 'CommonBuffId' = 280853 - SENTIMENT_CLOSE_PLAYFUL_VACATION_SNOWY: 'CommonBuffId' = 252438 - SENTIMENT_CLOSE_PLAYFUL_VILLAGER_HELP_HELPED_OUT: 'CommonBuffId' = 266371 - SENTIMENT_CLOSE_PLAYFUL_YOUTH_FESTIVAL_BLESSED: 'CommonBuffId' = 253251 - SENTIMENT_CLOSE_SAD_CONTAGION_GENERIC: 'CommonBuffId' = 240623 - SENTIMENT_CLOSE_SAD_CONTAGION_NEAR_DEATH: 'CommonBuffId' = 247389 - SENTIMENT_CLOSE_TENSE_LOYAL_REGAINED_TRUST: 'CommonBuffId' = 312707 - SENTIMENT_CRUSH_EMBARRASSED_GENERIC: 'CommonBuffId' = 273031 - SENTIMENT_CRUSH_FLIRTY_PRIMARY_GENERIC: 'CommonBuffId' = 272848 - SENTIMENT_CRUSH_HAPPY_GENERIC: 'CommonBuffId' = 273029 - SENTIMENT_CRUSH_SAD_GENERIC: 'CommonBuffId' = 273033 - SENTIMENT_CRUSH_TENSE_GENERIC: 'CommonBuffId' = 272849 - SENTIMENT_ENAMORED_DAZED_GENERIC: 'CommonBuffId' = 240997 - SENTIMENT_ENAMORED_EMBARRASSED_GENERIC: 'CommonBuffId' = 240994 - SENTIMENT_ENAMORED_EMBARRASSED_GENERIC_LT: 'CommonBuffId' = 247456 - SENTIMENT_ENAMORED_EMBARRASSED_LOYAL_SECOND_CHANCE: 'CommonBuffId' = 312679 - SENTIMENT_ENAMORED_FLIRTY_PRIMARY_CANNING_GIFTED_JAR: 'CommonBuffId' = 262185 - SENTIMENT_ENAMORED_FLIRTY_PRIMARY_COTTAG_EWORLD_RUINS: 'CommonBuffId' = 268487 - SENTIMENT_ENAMORED_FLIRTY_PRIMARY_FIRST_DANCE_TOGETHER: 'CommonBuffId' = 274230 - SENTIMENT_ENAMORED_FLIRTY_PRIMARY_FULL_MOON_FIRST_KISS: 'CommonBuffId' = 290600 - SENTIMENT_ENAMORED_FLIRTY_PRIMARY_GENERIC: 'CommonBuffId' = 240991 - SENTIMENT_ENAMORED_FLIRTY_PRIMARY_GENERIC_LT: 'CommonBuffId' = 247457 - SENTIMENT_ENAMORED_FLIRTY_PRIMARY_LIFESTYLES_SHARED: 'CommonBuffId' = 252446 - SENTIMENT_ENAMORED_FLIRTY_PRIMARY_LIGHT_FESTIVAL_KISS: 'CommonBuffId' = 253190 - SENTIMENT_ENAMORED_FLIRTY_PRIMARY_LOYAL_SECOND_CHANCE: 'CommonBuffId' = 312678 - SENTIMENT_ENAMORED_FLIRTY_PRIMARY_MOUNTAIN: 'CommonBuffId' = 252797 - SENTIMENT_ENAMORED_FLIRTY_PRIMARY_MOUNTAIN_CLIMB: 'CommonBuffId' = 252790 - SENTIMENT_ENAMORED_FLIRTY_PRIMARY_MOUNTAIN_NEIGHBORHOOD: 'CommonBuffId' = 252793 - SENTIMENT_ENAMORED_FLIRTY_PRIMARY_OPPOSITES: 'CommonBuffId' = 252443 - SENTIMENT_ENAMORED_FLIRTY_PRIMARY_PAIRED_DANCING_FIRST_DANCE: 'CommonBuffId' = 280854 - SENTIMENT_ENAMORED_FLIRTY_PRIMARY_SLEEP_CUDDLED: 'CommonBuffId' = 362536 - SENTIMENT_ENAMORED_HAPPY_CANNING_GIFTED_JAR: 'CommonBuffId' = 262180 - SENTIMENT_ENAMORED_HAPPY_COTTAGE_WORLD_RUINS: 'CommonBuffId' = 268486 - SENTIMENT_ENAMORED_HAPPY_FULL_MOON_FIRST_KISS: 'CommonBuffId' = 290601 - SENTIMENT_ENAMORED_HAPPY_GENERIC: 'CommonBuffId' = 240996 - SENTIMENT_ENAMORED_HAPPY_GENERIC_LT: 'CommonBuffId' = 247458 - SENTIMENT_ENAMORED_HAPPY_LIFESTYLES_SHARED: 'CommonBuffId' = 252447 - SENTIMENT_ENAMORED_HAPPY_LIGHT_FESTIVAL_KISS: 'CommonBuffId' = 253191 - SENTIMENT_ENAMORED_HAPPY_LOYAL_SECOND_CHANCE: 'CommonBuffId' = 312677 - SENTIMENT_ENAMORED_HAPPY_MOUNTAIN: 'CommonBuffId' = 252796 - SENTIMENT_ENAMORED_HAPPY_MOUNTAIN_CLIMB: 'CommonBuffId' = 252791 - SENTIMENT_ENAMORED_HAPPY_MOUNTAIN_NEIGHBORHOOD: 'CommonBuffId' = 252794 - SENTIMENT_ENAMORED_HAPPY_OPPOSITES: 'CommonBuffId' = 252444 - SENTIMENT_ENAMORED_HAPPY_PAIRED_DANCING_FIRST_DANCE: 'CommonBuffId' = 280855 - SENTIMENT_ENAMORED_HAPPY_SLEEP_CUDDLED: 'CommonBuffId' = 370704 - SENTIMENT_FURIOUS_ANGRY_PRIMARY_CHEATING: 'CommonBuffId' = 247462 - SENTIMENT_FURIOUS_ANGRY_PRIMARY_DECORATOR_BAD_BUILD: 'CommonBuffId' = 268261 - SENTIMENT_FURIOUS_ANGRY_PRIMARY_GENERIC: 'CommonBuffId' = 241005 - SENTIMENT_FURIOUS_ANGRY_PRIMARY_LIGHT_FESTIVAL_JEALOUS: 'CommonBuffId' = 253216 - SENTIMENT_FURIOUS_ANGRY_PRIMARY_WEDDING: 'CommonBuffId' = 247469 - SENTIMENT_FURIOUS_ANGRY_PRIMARY_WEDDING_PARTIES_EJECTED_GUEST: 'CommonBuffId' = 274214 - SENTIMENT_FURIOUS_ANGRY_PRIMARY_WHY_TODAY: 'CommonBuffId' = 357665 - SENTIMENT_FURIOUS_CONFIDENT_BETTER_OFF_NOW: 'CommonBuffId' = 357667 - SENTIMENT_FURIOUS_CONFIDENT_CHEATING: 'CommonBuffId' = 247463 - SENTIMENT_FURIOUS_CONFIDENT_GENERIC: 'CommonBuffId' = 241009 - SENTIMENT_FURIOUS_CONFIDENT_WEDDING: 'CommonBuffId' = 247471 - SENTIMENT_FURIOUS_CONTAGION_ANGRY_GENERIC: 'CommonBuffId' = 241003 - SENTIMENT_FURIOUS_CONTAGION_ANGRY_HAPPY_EX: 'CommonBuffId' = 357668 - SENTIMENT_FURIOUS_TENSE_CHEATING: 'CommonBuffId' = 247467 - SENTIMENT_FURIOUS_TENSE_GENERIC: 'CommonBuffId' = 241007 - SENTIMENT_FURIOUS_TENSE_LIGHT_FESTIVAL_JEALOUS: 'CommonBuffId' = 253217 - SENTIMENT_FURIOUS_TENSE_REMINDED_OF_PAIN: 'CommonBuffId' = 357666 - SENTIMENT_FURIOUS_TENSE_WEDDING: 'CommonBuffId' = 247472 - SENTIMENT_FURIOUS_TENSE_WEDDING_PARTIES_EJECTED_GUEST: 'CommonBuffId' = 280856 - SENTIMENT_GUILTY_BIG_SAD_WOLF: 'CommonBuffId' = 288506 - SENTIMENT_GUILTY_EMBARRASSED_AWKWARD_DATE: 'CommonBuffId' = 247561 - SENTIMENT_GUILTY_EMBARRASSED_BAD_PARTY: 'CommonBuffId' = 247570 - SENTIMENT_GUILTY_EMBARRASSED_GENERIC: 'CommonBuffId' = 247541 - SENTIMENT_GUILTY_EMBARRASSED_LIFESTYLE_CLOSE_KNIT: 'CommonBuffId' = 252786 - SENTIMENT_GUILTY_EMBARRASSED_MOUNTAIN_CLIMB: 'CommonBuffId' = 254134 - SENTIMENT_GUILTY_EMBARRASSED_VILLAGE_FAIR_BRIBE_FAIL: 'CommonBuffId' = 268430 - SENTIMENT_GUILTY_SAD_CONTAGION_GENERIC: 'CommonBuffId' = 247555 - SENTIMENT_GUILTY_SAD_PRIMARY_AWKWARD_DATE: 'CommonBuffId' = 247563 - SENTIMENT_GUILTY_SAD_PRIMARY_BAD_PARTY: 'CommonBuffId' = 247574 - SENTIMENT_GUILTY_SAD_PRIMARY_GENERIC: 'CommonBuffId' = 247540 - SENTIMENT_GUILTY_SAD_PRIMARY_LIFESTYLE_CLOSE_KNIT: 'CommonBuffId' = 252787 - SENTIMENT_GUILTY_SAD_PRIMARY_MOUNTAIN_CLIMB: 'CommonBuffId' = 254135 - SENTIMENT_GUILTY_TENSE_AWKWARD_DATE: 'CommonBuffId' = 247568 - SENTIMENT_GUILTY_TENSE_BAD_PARTY: 'CommonBuffId' = 247577 - SENTIMENT_GUILTY_TENSE_GENERIC: 'CommonBuffId' = 247544 - SENTIMENT_GUILTY_TENSE_LIFESTYLE_CLOSE_KNIT: 'CommonBuffId' = 252788 - SENTIMENT_GUILTY_TENSE_MOUNTAIN_CLIMB: 'CommonBuffId' = 254136 - SENTIMENT_HURT_ANGRY_GENERIC: 'CommonBuffId' = 247589 - SENTIMENT_HURT_ANGRY_GENERIC_LT: 'CommonBuffId' = 247591 - SENTIMENT_HURT_ANGRY_LIFESTYLE_NETWORKER: 'CommonBuffId' = 252774 - SENTIMENT_HURT_ANGRY_LIVESTOCK_SOLD: 'CommonBuffId' = 263702 - SENTIMENT_HURT_ANGRY_REJECTION: 'CommonBuffId' = 247592 - SENTIMENT_HURT_ANGRY_ROMANTIC: 'CommonBuffId' = 247593 - SENTIMENT_HURT_ANGRY_SADDENED: 'CommonBuffId' = 247594 - SENTIMENT_HURT_ANGRY_SOLD_MY_FRIEND: 'CommonBuffId' = 339249 - SENTIMENT_HURT_ANGRY_SUSPICIOUS: 'CommonBuffId' = 283867 - SENTIMENT_HURT_ANGRY_WHERES_MY_ATTENTION: 'CommonBuffId' = 274229 - SENTIMENT_HURT_ANGRY_YOUTH_FESTIVAL_UNBLESSED: 'CommonBuffId' = 253225 - SENTIMENT_HURT_SAD_PRIMARY_GENERIC: 'CommonBuffId' = 247583 - SENTIMENT_HURT_SAD_PRIMARY_GENERIC_LT: 'CommonBuffId' = 247584 - SENTIMENT_HURT_SAD_PRIMARY_LIFESTYLE_NETWORKER: 'CommonBuffId' = 252775 - SENTIMENT_HURT_SAD_PRIMARY_LIVESTOCK_SOLD: 'CommonBuffId' = 263703 - SENTIMENT_HURT_SAD_PRIMARY_NO_ATTENTION_LEFT: 'CommonBuffId' = 274228 - SENTIMENT_HURT_SAD_PRIMARY_REJECTION: 'CommonBuffId' = 247586 - SENTIMENT_HURT_SAD_PRIMARY_ROMANTIC: 'CommonBuffId' = 247585 - SENTIMENT_HURT_SAD_PRIMARY_SADDENED: 'CommonBuffId' = 247587 - SENTIMENT_HURT_SAD_PRIMARY_SOLD_MY_FRIEND: 'CommonBuffId' = 339248 - SENTIMENT_HURT_SAD_PRIMARY_SUSPICIOUS: 'CommonBuffId' = 283868 - SENTIMENT_HURT_SAD_PRIMARY_YOUTH_FESTIVAL_UNBLESSED: 'CommonBuffId' = 253226 - SENTIMENT_MOTIVATING_CONFIDENT_EPICALLY_INSPIRED: 'CommonBuffId' = 309532 - SENTIMENT_MOTIVATING_CONFIDENT_EXTREME_SPORTS: 'CommonBuffId' = 252865 - SENTIMENT_MOTIVATING_CONFIDENT_FRIENDLY_ADVICE: 'CommonBuffId' = 273841 - SENTIMENT_MOTIVATING_ENERGIZED_CHAMPION_PARTNER: 'CommonBuffId' = 338939 - SENTIMENT_MOTIVATING_ENERGIZED_PRIMARY_EPICALLY_INSPIRED: 'CommonBuffId' = 309533 - SENTIMENT_MOTIVATING_ENERGIZED_PRIMARY_EXTREME_SPORTS: 'CommonBuffId' = 252858 - SENTIMENT_MOTIVATING_ENERGIZED_PRIMARY_FRIENDLY_ADVICE: 'CommonBuffId' = 273843 - SENTIMENT_MOTIVATING_FOCUSED_EPICALLY_INSPIRED: 'CommonBuffId' = 309534 - SENTIMENT_MOTIVATING_FOCUSED_EXTREME_SPORTS: 'CommonBuffId' = 252867 - SENTIMENT_MOTIVATING_FOCUSED_FRIENDLY_ADVICE: 'CommonBuffId' = 273844 - SENTIMENT_MOTIVATING_INSPIRED_CHAMPION_PARTNER: 'CommonBuffId' = 338937 - SENT_TEXT_COOLDOWN: 'CommonBuffId' = 100672 - SERUMS_ALIEN_AURA: 'CommonBuffId' = 104809 - SERUMS_ALL_BY_MYSELF: 'CommonBuffId' = 104805 - SERUMS_ANGRY_REAPER: 'CommonBuffId' = 107032 - SERUMS_BAD_LUCK: 'CommonBuffId' = 104807 - SERUMS_BEST_WAY_TO_RECOVER: 'CommonBuffId' = 104788 - SERUMS_BRILLIANT: 'CommonBuffId' = 104798 - SERUMS_BURNING_LOVE: 'CommonBuffId' = 104793 - SERUMS_CANT_FIX_MY_HEART: 'CommonBuffId' = 104808 - SERUMS_DO_YOU_KNOW_WHO_I_AM: 'CommonBuffId' = 104800 - SERUMS_FEAR_THE_REAPER: 'CommonBuffId' = 104796 - SERUMS_FIXERS_LUCK: 'CommonBuffId' = 104806 - SERUMS_FIZZY_EXPLOSION: 'CommonBuffId' = 112562 - SERUMS_GHOSTLY: 'CommonBuffId' = 104795 - SERUMS_MAD_AS_AN_OX: 'CommonBuffId' = 104797 - SERUMS_NOT_FEELING_WELL: 'CommonBuffId' = 104801 - SERUMS_PLACEBO_EFFECT: 'CommonBuffId' = 104789 - SERUMS_RAVENOUS: 'CommonBuffId' = 104786 - SERUMS_REAPERS_FRIEND: 'CommonBuffId' = 104803 - SERUMS_REAPER_REVIVED_FRIEND: 'CommonBuffId' = 115941 - SERUMS_RED_HOT_SERUM: 'CommonBuffId' = 104787 - SERUMS_ROSE_PERFUME_SERUM: 'CommonBuffId' = 104792 - SERUMS_SELF_EXPERIMENTATION: 'CommonBuffId' = 105161 - SERUMS_SPARK_DRIVE: 'CommonBuffId' = 104802 - SERUMS_TEMPTED_FATE: 'CommonBuffId' = 104804 - SERUMS_THIS_IS_BELOW_ME: 'CommonBuffId' = 104799 - SERUMS_WANT_TO_HIDE: 'CommonBuffId' = 104794 - SERUMS_WEIGHT_DISPOSAL: 'CommonBuffId' = 104791 - SERUMS_YUM_SPICY: 'CommonBuffId' = 104790 - SERVICE_SKELETON_NEAR_SKELETON_COMMON: 'CommonBuffId' = 177833 - SERVICE_SKELETON_NEAR_SKELETON_RARE: 'CommonBuffId' = 177835 - SERVICE_SKELETON_OUTFIT: 'CommonBuffId' = 181546 - SEXUAL_ORIENTATION_BECAME_WOOHOO_PARTNERS: 'CommonBuffId' = 294525 - SEXUAL_ORIENTATION_REJECTED_WOOHOO_PARTNERS: 'CommonBuffId' = 294526 - SHARED_BIG_NEWS_HAPPY: 'CommonBuffId' = 97066 - SHARED_BIG_NEWS_TENSE: 'CommonBuffId' = 97067 - SHOE_REMOVAL_SIGN_APPEARANCE_MODIFIER_BARE_FOOT: 'CommonBuffId' = 248147 - SHOE_REMOVAL_SIGN_APPEARANCE_MODIFIER_SLIPPERS: 'CommonBuffId' = 248148 - SHOE_REMOVAL_SIGN_BREAKING_RULES: 'CommonBuffId' = 248809 - SHOE_REMOVAL_SIGN_CAUGHT_EMBARRASSED: 'CommonBuffId' = 246808 - SHOE_REMOVAL_SIGN_COMPLIANT: 'CommonBuffId' = 246502 - SHOE_REMOVAL_SIGN_EXEMPTION: 'CommonBuffId' = 255240 - SHOE_REMOVAL_SIGN_NON_COMPLIANT: 'CommonBuffId' = 246503 - SHOE_REMOVAL_SIGN_NOT_WEARING_SHOES_EXEMPTION: 'CommonBuffId' = 254337 - SHOE_REMOVAL_SIGN_SHOES_OFF: 'CommonBuffId' = 246486 - SHOE_REMOVAL_SIGN_SLIPPERS_ON: 'CommonBuffId' = 246487 - SHOWER_WOOHOO_EMBARRASSED: 'CommonBuffId' = 229217 - SHOWER_WOOHOO_GOOD: 'CommonBuffId' = 229219 - SHOWER_WOOHOO_SPECTACULAR: 'CommonBuffId' = 229218 - SHOWER_WOOHOO_UNCOMFORTABLE: 'CommonBuffId' = 229220 - SICKNESS_ATE_HUMAN_FOOD: 'CommonBuffId' = 169740 - SICKNESS_EXERCISED: 'CommonBuffId' = 169739 - SICKNESS_IMMUNITY_GENERAL: 'CommonBuffId' = 9971 - SICKNESS_IS_SICK: 'CommonBuffId' = 168173 - SICKNESS_NEED_TO_PUKE: 'CommonBuffId' = 98267 - SICKNESS_PET_ATE_SPOILED_FOOD: 'CommonBuffId' = 158936 - SICKNESS_SABOTAGED_FOOD_SPICY: 'CommonBuffId' = 187147 - SICKNESS_SABOTAGED_FOOD_STOMACH_MEDS: 'CommonBuffId' = 187150 - SICKNESS_SABOTAGED_FOOD_YUCK_FRUIT: 'CommonBuffId' = 187148 - SICKNESS_SYSTEM_DIAGNOSED_0_NONE: 'CommonBuffId' = 109669 - SICKNESS_SYSTEM_DIAGNOSED_0_NONE_DOCTOR: 'CommonBuffId' = 114226 - SICKNESS_SYSTEM_DIAGNOSED_1_NONE_CHANCE: 'CommonBuffId' = 109670 - SICKNESS_SYSTEM_DIAGNOSED_BLOATY_HEAD: 'CommonBuffId' = 108169 - SICKNESS_SYSTEM_DIAGNOSED_BURNING_TUMMY: 'CommonBuffId' = 108170 - SICKNESS_SYSTEM_DIAGNOSED_GAS_AND_GIGGLES: 'CommonBuffId' = 108171 - SICKNESS_SYSTEM_DIAGNOSED_ITCHY_PLUMBOB: 'CommonBuffId' = 108172 - SICKNESS_SYSTEM_DIAGNOSED_LLAMA_FLU: 'CommonBuffId' = 108173 - SICKNESS_SYSTEM_DIAGNOSED_STARRY_EYES: 'CommonBuffId' = 108174 - SICKNESS_SYSTEM_DIAGNOSED_SWEATY_SHIVERS: 'CommonBuffId' = 108176 - SICKNESS_SYSTEM_DIAGNOSED_TRIPLE_THREAT: 'CommonBuffId' = 108175 - SICKNESS_SYSTEM_DOCTOR_AWAY_EVENTS_PATIENT_COLLAPSED: 'CommonBuffId' = 113901 - SICKNESS_SYSTEM_DOCTOR_AWAY_EVENTS_PATIENT_EXAMINED: 'CommonBuffId' = 113898 - SICKNESS_SYSTEM_DOCTOR_BEDSIDE_MANNER_GOOD: 'CommonBuffId' = 109837 - SICKNESS_SYSTEM_DOCTOR_EXAM_RESULTS_BAD: 'CommonBuffId' = 109082 - SICKNESS_SYSTEM_FAKE_SICK_COOLDOWN: 'CommonBuffId' = 112152 - SICKNESS_SYSTEM_HYGIENIC_POD_CURED: 'CommonBuffId' = 115141 - SICKNESS_SYSTEM_ILLNESS_BLOATY_HEAD: 'CommonBuffId' = 105478 - SICKNESS_SYSTEM_ILLNESS_BURNING_TUMMY: 'CommonBuffId' = 105621 - SICKNESS_SYSTEM_ILLNESS_CRITICALITY_MILD: 'CommonBuffId' = 105605 - SICKNESS_SYSTEM_ILLNESS_CRITICALITY_SEVERE: 'CommonBuffId' = 105606 - SICKNESS_SYSTEM_ILLNESS_DURATION_COMMODITY_STATE_IMMUNE: 'CommonBuffId' = 106531 - SICKNESS_SYSTEM_ILLNESS_DURATION_COMMODITY_STATE_MILD: 'CommonBuffId' = 106528 - SICKNESS_SYSTEM_ILLNESS_DURATION_COMMODITY_STATE_REMISSION: 'CommonBuffId' = 106530 - SICKNESS_SYSTEM_ILLNESS_DURATION_COMMODITY_STATE_REMOVE: 'CommonBuffId' = 106532 - SICKNESS_SYSTEM_ILLNESS_DURATION_COMMODITY_STATE_SEVERE: 'CommonBuffId' = 106529 - SICKNESS_SYSTEM_ILLNESS_GAS_AND_GIGGLES: 'CommonBuffId' = 105620 - SICKNESS_SYSTEM_ILLNESS_HOME_REMEDY: 'CommonBuffId' = 108672 - SICKNESS_SYSTEM_ILLNESS_ITCHY_PLUMBOB: 'CommonBuffId' = 105619 - SICKNESS_SYSTEM_ILLNESS_LLAMA_FLU: 'CommonBuffId' = 105618 - SICKNESS_SYSTEM_ILLNESS_SEVERE_CONTRACTED: 'CommonBuffId' = 105573 - SICKNESS_SYSTEM_ILLNESS_STARRY_EYES: 'CommonBuffId' = 105617 - SICKNESS_SYSTEM_ILLNESS_SWEATY_SHIVERS: 'CommonBuffId' = 105616 - SICKNESS_SYSTEM_ILLNESS_TRIPLE_THREAT: 'CommonBuffId' = 105615 - SICKNESS_SYSTEM_ILLNESS_X_NONE_PATIENT: 'CommonBuffId' = 113783 - SICKNESS_SYSTEM_MAKE_SICK_TRIPLE_THREAT: 'CommonBuffId' = 114355 - SICKNESS_SYSTEM_PATIENT_COLLAPSED: 'CommonBuffId' = 113332 - SICKNESS_SYSTEM_PATIENT_DIAGNOSIS_COMMODITY_STATE_STAGE0: 'CommonBuffId' = 114827 - SICKNESS_SYSTEM_PATIENT_DIAGNOSIS_COMMODITY_STATE_STAGE0_DONE: 'CommonBuffId' = 114878 - SICKNESS_SYSTEM_PATIENT_DIAGNOSIS_COMMODITY_STATE_STAGE0_RECEIVED: 'CommonBuffId' = 114881 - SICKNESS_SYSTEM_PATIENT_DIAGNOSIS_COMMODITY_STATE_STAGE1: 'CommonBuffId' = 109564 - SICKNESS_SYSTEM_PATIENT_DIAGNOSIS_COMMODITY_STATE_STAGE2: 'CommonBuffId' = 109565 - SICKNESS_SYSTEM_PATIENT_DIAGNOSIS_COMMODITY_STATE_STAGE3: 'CommonBuffId' = 109566 - SICKNESS_SYSTEM_PATIENT_DIAGNOSIS_COMMODITY_STATE_STAGE4: 'CommonBuffId' = 109567 - SICKNESS_SYSTEM_PATIENT_EXAMINED_1: 'CommonBuffId' = 107990 - SICKNESS_SYSTEM_PATIENT_EXAMINED_2: 'CommonBuffId' = 107991 - SICKNESS_SYSTEM_PATIENT_EXAMINED_CHECK_EARS: 'CommonBuffId' = 112594 - SICKNESS_SYSTEM_PATIENT_EXAMINED_CHECK_EYES: 'CommonBuffId' = 112593 - SICKNESS_SYSTEM_PATIENT_EXAMINED_PROBE: 'CommonBuffId' = 112595 - SICKNESS_SYSTEM_PATIENT_EXAMINED_TAKE_TEMP: 'CommonBuffId' = 112592 - SICKNESS_SYSTEM_PATIENT_SAMPLE_TAKEN: 'CommonBuffId' = 111239 - SICKNESS_SYSTEM_SLEEP_SYMPTOM_SUPPRESSION: 'CommonBuffId' = 112148 - SICKNESS_SYSTEM_SYMPTOM_COUGH_SNEEZE_MILD: 'CommonBuffId' = 105746 - SICKNESS_SYSTEM_SYMPTOM_COUGH_SNEEZE_SEVERE: 'CommonBuffId' = 105761 - SICKNESS_SYSTEM_SYMPTOM_DIZZY_MILD: 'CommonBuffId' = 105747 - SICKNESS_SYSTEM_SYMPTOM_DIZZY_SEVERE: 'CommonBuffId' = 105762 - SICKNESS_SYSTEM_SYMPTOM_FEVER_MILD: 'CommonBuffId' = 105748 - SICKNESS_SYSTEM_SYMPTOM_FEVER_SEVERE: 'CommonBuffId' = 105763 - SICKNESS_SYSTEM_SYMPTOM_GIGGLY_MILD: 'CommonBuffId' = 105365 - SICKNESS_SYSTEM_SYMPTOM_GIGGLY_SEVERE: 'CommonBuffId' = 105769 - SICKNESS_SYSTEM_SYMPTOM_HEADACHE_MILD: 'CommonBuffId' = 105370 - SICKNESS_SYSTEM_SYMPTOM_HEADACHE_SEVERE: 'CommonBuffId' = 105764 - SICKNESS_SYSTEM_SYMPTOM_ITCHY_MILD: 'CommonBuffId' = 105354 - SICKNESS_SYSTEM_SYMPTOM_ITCHY_SEVERE: 'CommonBuffId' = 105765 - SICKNESS_SYSTEM_SYMPTOM_NAUSEA_MILD: 'CommonBuffId' = 105453 - SICKNESS_SYSTEM_SYMPTOM_NAUSEA_SEVERE: 'CommonBuffId' = 105766 - SICKNESS_SYSTEM_SYMPTOM_SEEING_THINGS_MILD: 'CommonBuffId' = 105436 - SICKNESS_SYSTEM_SYMPTOM_SEEING_THINGS_SEVERE: 'CommonBuffId' = 105767 - SICKNESS_SYSTEM_SYMPTOM_STEAMY_EARS_MILD: 'CommonBuffId' = 105749 - SICKNESS_SYSTEM_SYMPTOM_STEAMY_EARS_SEVERE: 'CommonBuffId' = 105768 - SICKNESS_SYSTEM_SYMPTOM_TRIGGER: 'CommonBuffId' = 105526 - SICKNESS_SYSTEM_TAKE_MEDICINE_CURED: 'CommonBuffId' = 108716 - SICKNESS_SYSTEM_TAKE_MEDICINE_DAZED: 'CommonBuffId' = 105661 - SIM_BASKED_IN_BRAVERY: 'CommonBuffId' = 340980 - SIM_BE_WOKEN_UP_HIDDEN: 'CommonBuffId' = 10314 - SIM_CELEBRITY_DISGUISE: 'CommonBuffId' = 201066 - SIM_CHANGE_DIAPER_DIAPER_DISASTER: 'CommonBuffId' = 311692 - SIM_CHANGE_DIAPER_DISASTER_COOLDOWN: 'CommonBuffId' = 315094 - SIM_CHAT_SHORTEN_DURATION: 'CommonBuffId' = 391582 - SIM_CHILLED_FROZEN_SPELL: 'CommonBuffId' = 220093 - SIM_CITY_LIFE_PHONE_CHATTER_ANGRY: 'CommonBuffId' = 143976 - SIM_CITY_LIFE_PHONE_CHATTER_HAPPY: 'CommonBuffId' = 143977 - SIM_CITY_LIFE_PHONE_CHATTER_SAD: 'CommonBuffId' = 143978 - SIM_CURIO_SHOP_TENDING_SHOP: 'CommonBuffId' = 206573 - SIM_CURRENTLY_MAKING_DRINK: 'CommonBuffId' = 100136 - SIM_DOCTOR_DELIVERED_BABY_RECENTLY: 'CommonBuffId' = 113111 - SIM_DOCTOR_RESEARCH_MEDICAL_INFO: 'CommonBuffId' = 112667 - SIM_DOCTOR_RESEARCH_MEDICAL_INFO_COOLDOWN: 'CommonBuffId' = 112668 - SIM_EQUINE_ENERGY: 'CommonBuffId' = 340731 - SIM_FEAR_GENIUS_WRONG: 'CommonBuffId' = 273098 - SIM_FIX_RELATIONSHIP_COOLDOWN: 'CommonBuffId' = 167101 - SIM_GARDENING_SKILLED_QUALITY_VFX: 'CommonBuffId' = 191601 - SIM_GARDENING_SKILLED_QUALITY_VFX_TIMED: 'CommonBuffId' = 191605 - SIM_HAS_BRAWLED_RECENTLY_HIDDEN: 'CommonBuffId' = 124816 - SIM_HAZMAT_SUIT: 'CommonBuffId' = 203478 - SIM_HELPING_A_HORSE_IN_NEED: 'CommonBuffId' = 340729 - SIM_HIDDEN_CHECK_TODDLER_COOLDOWN: 'CommonBuffId' = 155201 - SIM_HIDDEN_CHECK_TODDLER_FAILED_NO_OBJECT: 'CommonBuffId' = 157838 - SIM_HORSE_ALLY: 'CommonBuffId' = 340722 - SIM_IN_RESTAURANT: 'CommonBuffId' = 130714 - SIM_IN_SPORE_HALLWAY: 'CommonBuffId' = 207072 - SIM_IN_VET: 'CommonBuffId' = 158852 - SIM_IS_BAR_TENDING: 'CommonBuffId' = 29363 - SIM_IS_COOKING: 'CommonBuffId' = 10090 - SIM_IS_DRINKING: 'CommonBuffId' = 9272 - SIM_IS_DYING: 'CommonBuffId' = 26171 - SIM_IS_EATING: 'CommonBuffId' = 9273 - SIM_IS_IN_BATH: 'CommonBuffId' = 195626 - SIM_IS_PERFORMING: 'CommonBuffId' = 200372 - SIM_IS_SLEEPING: 'CommonBuffId' = 10094 - SIM_IS_SLEEPING_HIDDEN: 'CommonBuffId' = 275549 - SIM_IS_SWIMMING: 'CommonBuffId' = 206484 - SIM_IS_TALKING: 'CommonBuffId' = 8876 - SIM_LAMPOON: 'CommonBuffId' = 201402 - SIM_LAZY_WOKEN_UP: 'CommonBuffId' = 35850 - SIM_LEASHED_TO_DOG: 'CommonBuffId' = 165193 - SIM_LOVE_GURU_ROMANTIC_ASK_HIDDEN: 'CommonBuffId' = 153593 - SIM_LOVE_GURU_WISDOM_ASK_HIDDEN: 'CommonBuffId' = 153792 - SIM_MORNING_SICKNESS: 'CommonBuffId' = 39405 - SIM_MULTI_TO_CARRY_INFANT_PREVENT_IDLE: 'CommonBuffId' = 329298 - SIM_NEEDY_STEED: 'CommonBuffId' = 340728 - SIM_PETS_ALLOWED_TO_EAT_HUMAN_FOOD: 'CommonBuffId' = 172797 - SIM_PETS_ATTACKING_HIDDEN: 'CommonBuffId' = 167556 - SIM_PETS_BE_WOKEN_UP_HIDDEN: 'CommonBuffId' = 158663 - SIM_PETS_FEAR_QUIRK_RUN_AWAY_THOUGHT_BALLOON: 'CommonBuffId' = 168530 - SIM_PETS_MISBEHAVIOR_BARKING: 'CommonBuffId' = 178426 - SIM_PETS_MISBEHAVIOR_BEG_FOR_FOOD: 'CommonBuffId' = 172827 - SIM_PETS_MISBEHAVIOR_JUMP_ON_COUNTERS_DOGS: 'CommonBuffId' = 178490 - SIM_PETS_PET_BED_KICK_OUT_HIDDEN: 'CommonBuffId' = 166971 - SIM_PETS_RELAX_LARGE_DOG: 'CommonBuffId' = 178109 - SIM_PETS_RELAX_SMALL_PET: 'CommonBuffId' = 178110 - SIM_PETS_SOLD_FOR_ADOPTION: 'CommonBuffId' = 170541 - SIM_PET_DOG_NO_SHAKE_OFF_COOLDOWN: 'CommonBuffId' = 172179 - SIM_PREFERENCE_BAD_TIME_ANGRY: 'CommonBuffId' = 260012 - SIM_PREFERENCE_BAD_TIME_UNCOMFORTABLE: 'CommonBuffId' = 260011 - SIM_PREFERENCE_COLOR_HAS_DISLIKE: 'CommonBuffId' = 267923 - SIM_PREFERENCE_COLOR_HAS_LIKE: 'CommonBuffId' = 267922 - SIM_PREFERENCE_DECOR_REACTION_ART_DECO: 'CommonBuffId' = 325876 - SIM_PREFERENCE_DECOR_REACTION_BASICS: 'CommonBuffId' = 262128 - SIM_PREFERENCE_DECOR_REACTION_BOHO: 'CommonBuffId' = 262129 - SIM_PREFERENCE_DECOR_REACTION_CONTEMPORARY: 'CommonBuffId' = 262130 - SIM_PREFERENCE_DECOR_REACTION_COOLDOWN: 'CommonBuffId' = 263787 - SIM_PREFERENCE_DECOR_REACTION_COSMOLUX: 'CommonBuffId' = 262131 - SIM_PREFERENCE_DECOR_REACTION_CUTE: 'CommonBuffId' = 325877 - SIM_PREFERENCE_DECOR_REACTION_FRENCH_COUNTRY: 'CommonBuffId' = 262133 - SIM_PREFERENCE_DECOR_REACTION_GARDEN: 'CommonBuffId' = 262134 - SIM_PREFERENCE_DECOR_REACTION_GOTHIC_FARMHOUSE: 'CommonBuffId' = 262135 - SIM_PREFERENCE_DECOR_REACTION_INDUSTRIAL: 'CommonBuffId' = 325879 - SIM_PREFERENCE_DECOR_REACTION_ISLAND: 'CommonBuffId' = 262136 - SIM_PREFERENCE_DECOR_REACTION_LUXE: 'CommonBuffId' = 325878 - SIM_PREFERENCE_DECOR_REACTION_MISSION: 'CommonBuffId' = 262137 - SIM_PREFERENCE_DECOR_REACTION_MODERN: 'CommonBuffId' = 262138 - SIM_PREFERENCE_DECOR_REACTION_PATIO: 'CommonBuffId' = 262139 - SIM_PREFERENCE_DECOR_REACTION_QUEEN_ANNE: 'CommonBuffId' = 262140 - SIM_PREFERENCE_DECOR_REACTION_SCANDINAVIAN_CONTEMPORARY: 'CommonBuffId' = 262141 - SIM_PREFERENCE_DECOR_REACTION_SHABBY: 'CommonBuffId' = 326020 - SIM_PREFERENCE_DECOR_REACTION_SUBURBAN_CONTEMPORARY: 'CommonBuffId' = 262143 - SIM_PREFERENCE_DECOR_REACTION_TUDOR: 'CommonBuffId' = 262144 - SIM_PREFERENCE_DECOR_REACTION_VINTAGE: 'CommonBuffId' = 325880 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_ACTING: 'CommonBuffId' = 264113 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_BAKING: 'CommonBuffId' = 264114 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_BOWLING: 'CommonBuffId' = 264115 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_COMEDY: 'CommonBuffId' = 264117 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_COOKING: 'CommonBuffId' = 258397 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_CROSS_STITCH: 'CommonBuffId' = 274550 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_DANCING: 'CommonBuffId' = 264118 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_DEBATING: 'CommonBuffId' = 264126 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_DJ_MIXING: 'CommonBuffId' = 264134 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_EQUESTRIAN_SKILL: 'CommonBuffId' = 340003 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_FISHING: 'CommonBuffId' = 264119 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_FITNESS: 'CommonBuffId' = 258769 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_GARDENING: 'CommonBuffId' = 264120 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_GUITAR: 'CommonBuffId' = 264135 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_HANDINESS: 'CommonBuffId' = 264121 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_KNITTING: 'CommonBuffId' = 274541 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_MEDIA_PRODUCTION: 'CommonBuffId' = 264122 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_MISCHIEF: 'CommonBuffId' = 264123 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_MIXOLOGY: 'CommonBuffId' = 264124 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_NECTAR_MAKING: 'CommonBuffId' = 340004 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_PAINTING: 'CommonBuffId' = 258770 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_PHOTOGRAPHY: 'CommonBuffId' = 264125 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_PIANO: 'CommonBuffId' = 264136 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_PIPE_ORGAN: 'CommonBuffId' = 264137 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_PROGRAMMING: 'CommonBuffId' = 264781 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_ROBOTICS: 'CommonBuffId' = 264127 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_ROCKET_SCIENCE: 'CommonBuffId' = 264129 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_ROCK_CLIMBING: 'CommonBuffId' = 264128 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_SINGING: 'CommonBuffId' = 264138 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_SKIING: 'CommonBuffId' = 264130 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_SNOWBOARDING: 'CommonBuffId' = 264131 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_VIDEO_GAMING: 'CommonBuffId' = 258771 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_VIOLIN: 'CommonBuffId' = 258772 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_WELLNESS: 'CommonBuffId' = 264132 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_WRITING: 'CommonBuffId' = 264133 - SIM_PREFERENCE_DISLIKES_DECOR_ART_DECO: 'CommonBuffId' = 325865 - SIM_PREFERENCE_DISLIKES_DECOR_BASICS: 'CommonBuffId' = 263808 - SIM_PREFERENCE_DISLIKES_DECOR_BOHO: 'CommonBuffId' = 263809 - SIM_PREFERENCE_DISLIKES_DECOR_CONTEMPORARY: 'CommonBuffId' = 263810 - SIM_PREFERENCE_DISLIKES_DECOR_COSMOLUX: 'CommonBuffId' = 263811 - SIM_PREFERENCE_DISLIKES_DECOR_CUTE: 'CommonBuffId' = 325866 - SIM_PREFERENCE_DISLIKES_DECOR_FRENCH_COUNTRY: 'CommonBuffId' = 263815 - SIM_PREFERENCE_DISLIKES_DECOR_GARDEN: 'CommonBuffId' = 263816 - SIM_PREFERENCE_DISLIKES_DECOR_GOTHIC_FARMHOUSE: 'CommonBuffId' = 263818 - SIM_PREFERENCE_DISLIKES_DECOR_INDUSTRIAL: 'CommonBuffId' = 325867 - SIM_PREFERENCE_DISLIKES_DECOR_ISLAND: 'CommonBuffId' = 263819 - SIM_PREFERENCE_DISLIKES_DECOR_LUXE: 'CommonBuffId' = 325868 - SIM_PREFERENCE_DISLIKES_DECOR_MISSION: 'CommonBuffId' = 263820 - SIM_PREFERENCE_DISLIKES_DECOR_MODERN: 'CommonBuffId' = 263821 - SIM_PREFERENCE_DISLIKES_DECOR_PATIO: 'CommonBuffId' = 263822 - SIM_PREFERENCE_DISLIKES_DECOR_QUEEN_ANNE: 'CommonBuffId' = 263823 - SIM_PREFERENCE_DISLIKES_DECOR_SCANDINAVIAN_CONTEMPORARY: 'CommonBuffId' = 263824 - SIM_PREFERENCE_DISLIKES_DECOR_SHABBY: 'CommonBuffId' = 326016 - SIM_PREFERENCE_DISLIKES_DECOR_SUBURBAN_CONTEMPORARY: 'CommonBuffId' = 263826 - SIM_PREFERENCE_DISLIKES_DECOR_TUDOR: 'CommonBuffId' = 263827 - SIM_PREFERENCE_DISLIKES_DECOR_VINTAGE: 'CommonBuffId' = 325869 - SIM_PREFERENCE_DISLIKES_FASHION_BASICS: 'CommonBuffId' = 272724 - SIM_PREFERENCE_DISLIKES_FASHION_BOHO: 'CommonBuffId' = 283087 - SIM_PREFERENCE_DISLIKES_FASHION_COLOSSAL_FASHION_FAUX_PAX: 'CommonBuffId' = 284515 - SIM_PREFERENCE_DISLIKES_FASHION_COUNTRY: 'CommonBuffId' = 283090 - SIM_PREFERENCE_DISLIKES_FASHION_HIPSTER: 'CommonBuffId' = 283091 - SIM_PREFERENCE_DISLIKES_FASHION_OUTDOORSY: 'CommonBuffId' = 283092 - SIM_PREFERENCE_DISLIKES_FASHION_POLISHED: 'CommonBuffId' = 283093 - SIM_PREFERENCE_DISLIKES_FASHION_PREPPY: 'CommonBuffId' = 283094 - SIM_PREFERENCE_DISLIKES_FASHION_ROCKER: 'CommonBuffId' = 283095 - SIM_PREFERENCE_DISLIKES_FASHION_STREETWEAR: 'CommonBuffId' = 283096 - SIM_PREFERENCE_DISLIKES_MUSIC_ALTERNATIVE: 'CommonBuffId' = 258801 - SIM_PREFERENCE_DISLIKES_MUSIC_AMERICANA: 'CommonBuffId' = 265288 - SIM_PREFERENCE_DISLIKES_MUSIC_BACKYARD: 'CommonBuffId' = 265275 - SIM_PREFERENCE_DISLIKES_MUSIC_BAROQUE: 'CommonBuffId' = 265278 - SIM_PREFERENCE_DISLIKES_MUSIC_BATUU: 'CommonBuffId' = 346364 - SIM_PREFERENCE_DISLIKES_MUSIC_BLUES: 'CommonBuffId' = 258802 - SIM_PREFERENCE_DISLIKES_MUSIC_BRAZILIAN: 'CommonBuffId' = 346363 - SIM_PREFERENCE_DISLIKES_MUSIC_CLASSICAL: 'CommonBuffId' = 258803 - SIM_PREFERENCE_DISLIKES_MUSIC_COTTAGE_CORE: 'CommonBuffId' = 274581 - SIM_PREFERENCE_DISLIKES_MUSIC_DJ: 'CommonBuffId' = 267532 - SIM_PREFERENCE_DISLIKES_MUSIC_EASY_LISTENING: 'CommonBuffId' = 265274 - SIM_PREFERENCE_DISLIKES_MUSIC_ELECTRONICA: 'CommonBuffId' = 258804 - SIM_PREFERENCE_DISLIKES_MUSIC_FOCUS: 'CommonBuffId' = 265290 - SIM_PREFERENCE_DISLIKES_MUSIC_HIP_HOP: 'CommonBuffId' = 258805 - SIM_PREFERENCE_DISLIKES_MUSIC_ISLAND: 'CommonBuffId' = 265287 - SIM_PREFERENCE_DISLIKES_MUSIC_JAPANESE_FOLK: 'CommonBuffId' = 265289 - SIM_PREFERENCE_DISLIKES_MUSIC_JAZZ: 'CommonBuffId' = 265277 - SIM_PREFERENCE_DISLIKES_MUSIC_KIDS: 'CommonBuffId' = 258735 - SIM_PREFERENCE_DISLIKES_MUSIC_LATIN: 'CommonBuffId' = 265281 - SIM_PREFERENCE_DISLIKES_MUSIC_LATIN_POP: 'CommonBuffId' = 265282 - SIM_PREFERENCE_DISLIKES_MUSIC_LULLABIES: 'CommonBuffId' = 258806 - SIM_PREFERENCE_DISLIKES_MUSIC_METAL: 'CommonBuffId' = 265291 - SIM_PREFERENCE_DISLIKES_MUSIC_NEW_AGE: 'CommonBuffId' = 265276 - SIM_PREFERENCE_DISLIKES_MUSIC_NU_DISCO: 'CommonBuffId' = 265280 - SIM_PREFERENCE_DISLIKES_MUSIC_OLDIES: 'CommonBuffId' = 312261 - SIM_PREFERENCE_DISLIKES_MUSIC_POP: 'CommonBuffId' = 258701 - SIM_PREFERENCE_DISLIKES_MUSIC_RANCH: 'CommonBuffId' = 334860 - SIM_PREFERENCE_DISLIKES_MUSIC_RETRO: 'CommonBuffId' = 258807 - SIM_PREFERENCE_DISLIKES_MUSIC_RNB: 'CommonBuffId' = 343312 - SIM_PREFERENCE_DISLIKES_MUSIC_ROMANCE: 'CommonBuffId' = 258808 - SIM_PREFERENCE_DISLIKES_MUSIC_SINGER_SONGWRITER: 'CommonBuffId' = 265285 - SIM_PREFERENCE_DISLIKES_MUSIC_SPOOKY: 'CommonBuffId' = 258809 - SIM_PREFERENCE_DISLIKES_MUSIC_STRANGE_TUNES: 'CommonBuffId' = 265283 - SIM_PREFERENCE_DISLIKES_MUSIC_SUMMER_STRUT: 'CommonBuffId' = 265286 - SIM_PREFERENCE_DISLIKES_MUSIC_S_POP: 'CommonBuffId' = 258810 - SIM_PREFERENCE_DISLIKES_MUSIC_TWEEN_POP: 'CommonBuffId' = 265279 - SIM_PREFERENCE_DISLIKES_MUSIC_WINTER_HOLIDAY: 'CommonBuffId' = 258811 - SIM_PREFERENCE_DISLIKES_MUSIC_WORLD: 'CommonBuffId' = 265284 - SIM_PREFERENCE_FASHION_DISCOVERY_COOLDOWN: 'CommonBuffId' = 283299 - SIM_PREFERENCE_FASHION_RECOGNITION_COOLDOWN: 'CommonBuffId' = 272765 - SIM_PREFERENCE_GAIN_COOLDOWN: 'CommonBuffId' = 263631 - SIM_PREFERENCE_HAS_PREFERENCE_ACTIVITY: 'CommonBuffId' = 258402 - SIM_PREFERENCE_HAS_PREFERENCE_COLOR: 'CommonBuffId' = 258400 - SIM_PREFERENCE_HAS_PREFERENCE_DECOR: 'CommonBuffId' = 258404 - SIM_PREFERENCE_HAS_PREFERENCE_FASHION: 'CommonBuffId' = 272664 - SIM_PREFERENCE_HAS_PREFERENCE_MUSIC: 'CommonBuffId' = 258403 - SIM_PREFERENCE_IDLE_COOLDOWN: 'CommonBuffId' = 269253 - SIM_PREFERENCE_LIKES_ACTIVITIES_ACTING: 'CommonBuffId' = 264201 - SIM_PREFERENCE_LIKES_ACTIVITIES_BAKING: 'CommonBuffId' = 264202 - SIM_PREFERENCE_LIKES_ACTIVITIES_BOWLING: 'CommonBuffId' = 264203 - SIM_PREFERENCE_LIKES_ACTIVITIES_COMEDY: 'CommonBuffId' = 264204 - SIM_PREFERENCE_LIKES_ACTIVITIES_COOKING: 'CommonBuffId' = 258394 - SIM_PREFERENCE_LIKES_ACTIVITIES_CROSS_STITCH: 'CommonBuffId' = 274551 - SIM_PREFERENCE_LIKES_ACTIVITIES_DANCING: 'CommonBuffId' = 264205 - SIM_PREFERENCE_LIKES_ACTIVITIES_DEBATING: 'CommonBuffId' = 264206 - SIM_PREFERENCE_LIKES_ACTIVITIES_DJ_MIXING: 'CommonBuffId' = 264207 - SIM_PREFERENCE_LIKES_ACTIVITIES_EQUESTRIAN_SKILL: 'CommonBuffId' = 340005 - SIM_PREFERENCE_LIKES_ACTIVITIES_FISHING: 'CommonBuffId' = 264208 - SIM_PREFERENCE_LIKES_ACTIVITIES_FITNESS: 'CommonBuffId' = 258773 - SIM_PREFERENCE_LIKES_ACTIVITIES_GARDENING: 'CommonBuffId' = 264209 - SIM_PREFERENCE_LIKES_ACTIVITIES_GUITAR: 'CommonBuffId' = 264210 - SIM_PREFERENCE_LIKES_ACTIVITIES_HANDINESS: 'CommonBuffId' = 264212 - SIM_PREFERENCE_LIKES_ACTIVITIES_KNITTING: 'CommonBuffId' = 274542 - SIM_PREFERENCE_LIKES_ACTIVITIES_MEDIA_PRODUCTION: 'CommonBuffId' = 264211 - SIM_PREFERENCE_LIKES_ACTIVITIES_MISCHIEF: 'CommonBuffId' = 264213 - SIM_PREFERENCE_LIKES_ACTIVITIES_MIXOLOGY: 'CommonBuffId' = 264214 - SIM_PREFERENCE_LIKES_ACTIVITIES_NECTAR_MAKING: 'CommonBuffId' = 340006 - SIM_PREFERENCE_LIKES_ACTIVITIES_PAINTING: 'CommonBuffId' = 258774 - SIM_PREFERENCE_LIKES_ACTIVITIES_PHOTOGRAPHY: 'CommonBuffId' = 264215 - SIM_PREFERENCE_LIKES_ACTIVITIES_PIANO: 'CommonBuffId' = 264216 - SIM_PREFERENCE_LIKES_ACTIVITIES_PIPE_ORGAN: 'CommonBuffId' = 264217 - SIM_PREFERENCE_LIKES_ACTIVITIES_PROGRAMMING: 'CommonBuffId' = 264780 - SIM_PREFERENCE_LIKES_ACTIVITIES_ROBOTICS: 'CommonBuffId' = 264218 - SIM_PREFERENCE_LIKES_ACTIVITIES_ROCKET_SCIENCE: 'CommonBuffId' = 264220 - SIM_PREFERENCE_LIKES_ACTIVITIES_ROCK_CLIMBING: 'CommonBuffId' = 264219 - SIM_PREFERENCE_LIKES_ACTIVITIES_SINGING: 'CommonBuffId' = 264221 - SIM_PREFERENCE_LIKES_ACTIVITIES_SKIING: 'CommonBuffId' = 264222 - SIM_PREFERENCE_LIKES_ACTIVITIES_SNOWBOARDING: 'CommonBuffId' = 264223 - SIM_PREFERENCE_LIKES_ACTIVITIES_VIDEO_GAMING: 'CommonBuffId' = 258775 - SIM_PREFERENCE_LIKES_ACTIVITIES_VIOLIN: 'CommonBuffId' = 258776 - SIM_PREFERENCE_LIKES_ACTIVITIES_WELLNESS: 'CommonBuffId' = 264224 - SIM_PREFERENCE_LIKES_ACTIVITIES_WRITING: 'CommonBuffId' = 264225 - SIM_PREFERENCE_LIKES_DECOR_ART_DECO: 'CommonBuffId' = 325870 - SIM_PREFERENCE_LIKES_DECOR_BASICS: 'CommonBuffId' = 263790 - SIM_PREFERENCE_LIKES_DECOR_BOHO: 'CommonBuffId' = 263791 - SIM_PREFERENCE_LIKES_DECOR_CONTEMPORARY: 'CommonBuffId' = 263792 - SIM_PREFERENCE_LIKES_DECOR_COSMOLUX: 'CommonBuffId' = 263793 - SIM_PREFERENCE_LIKES_DECOR_CUTE: 'CommonBuffId' = 325871 - SIM_PREFERENCE_LIKES_DECOR_FRENCH_COUNTRY: 'CommonBuffId' = 263795 - SIM_PREFERENCE_LIKES_DECOR_GARDEN: 'CommonBuffId' = 263796 - SIM_PREFERENCE_LIKES_DECOR_GOTHIC_FARMHOUSE: 'CommonBuffId' = 263797 - SIM_PREFERENCE_LIKES_DECOR_INDUSTRIAL: 'CommonBuffId' = 325872 - SIM_PREFERENCE_LIKES_DECOR_ISLAND: 'CommonBuffId' = 263798 - SIM_PREFERENCE_LIKES_DECOR_LUXE: 'CommonBuffId' = 325873 - SIM_PREFERENCE_LIKES_DECOR_MISSION: 'CommonBuffId' = 263799 - SIM_PREFERENCE_LIKES_DECOR_MODERN: 'CommonBuffId' = 263800 - SIM_PREFERENCE_LIKES_DECOR_PATIO: 'CommonBuffId' = 263801 - SIM_PREFERENCE_LIKES_DECOR_QUEEN_ANNE: 'CommonBuffId' = 263802 - SIM_PREFERENCE_LIKES_DECOR_SCANDINAVIAN_CONTEMPORARY: 'CommonBuffId' = 263803 - SIM_PREFERENCE_LIKES_DECOR_SHABBY: 'CommonBuffId' = 326015 - SIM_PREFERENCE_LIKES_DECOR_SUBURBAN_CONTEMPORARY: 'CommonBuffId' = 263805 - SIM_PREFERENCE_LIKES_DECOR_TUDOR: 'CommonBuffId' = 263806 - SIM_PREFERENCE_LIKES_DECOR_VINTAGE: 'CommonBuffId' = 325874 - SIM_PREFERENCE_LIKES_FASHION_BASICS: 'CommonBuffId' = 272653 - SIM_PREFERENCE_LIKES_FASHION_BOHO: 'CommonBuffId' = 283098 - SIM_PREFERENCE_LIKES_FASHION_COUNTRY: 'CommonBuffId' = 283100 - SIM_PREFERENCE_LIKES_FASHION_DEDICATED_FOLLOWER_OF_FASHION: 'CommonBuffId' = 284514 - SIM_PREFERENCE_LIKES_FASHION_HIPSTER: 'CommonBuffId' = 283101 - SIM_PREFERENCE_LIKES_FASHION_OUTDOORSY: 'CommonBuffId' = 283102 - SIM_PREFERENCE_LIKES_FASHION_POLISHED: 'CommonBuffId' = 283103 - SIM_PREFERENCE_LIKES_FASHION_PREPPY: 'CommonBuffId' = 283104 - SIM_PREFERENCE_LIKES_FASHION_ROCKER: 'CommonBuffId' = 283105 - SIM_PREFERENCE_LIKES_FASHION_STREETWEAR: 'CommonBuffId' = 283107 - SIM_PREFERENCE_LIKES_MUSIC_ALTERNATIVE: 'CommonBuffId' = 258790 - SIM_PREFERENCE_LIKES_MUSIC_AMERICANA: 'CommonBuffId' = 265306 - SIM_PREFERENCE_LIKES_MUSIC_BACKYARD: 'CommonBuffId' = 265293 - SIM_PREFERENCE_LIKES_MUSIC_BAROQUE: 'CommonBuffId' = 265297 - SIM_PREFERENCE_LIKES_MUSIC_BATUU: 'CommonBuffId' = 346362 - SIM_PREFERENCE_LIKES_MUSIC_BLUES: 'CommonBuffId' = 258791 - SIM_PREFERENCE_LIKES_MUSIC_BRAZILIAN: 'CommonBuffId' = 346361 - SIM_PREFERENCE_LIKES_MUSIC_CLASSICAL: 'CommonBuffId' = 258792 - SIM_PREFERENCE_LIKES_MUSIC_COTTAGE_CORE: 'CommonBuffId' = 274582 - SIM_PREFERENCE_LIKES_MUSIC_DJ: 'CommonBuffId' = 267533 - SIM_PREFERENCE_LIKES_MUSIC_EASY_LISTENING: 'CommonBuffId' = 265292 - SIM_PREFERENCE_LIKES_MUSIC_ELECTRONICA: 'CommonBuffId' = 258793 - SIM_PREFERENCE_LIKES_MUSIC_FOCUS: 'CommonBuffId' = 265308 - SIM_PREFERENCE_LIKES_MUSIC_HIP_HOP: 'CommonBuffId' = 258794 - SIM_PREFERENCE_LIKES_MUSIC_ISLAND: 'CommonBuffId' = 265304 - SIM_PREFERENCE_LIKES_MUSIC_JAPANESE_FOLK: 'CommonBuffId' = 265307 - SIM_PREFERENCE_LIKES_MUSIC_JAZZ: 'CommonBuffId' = 265295 - SIM_PREFERENCE_LIKES_MUSIC_KIDS: 'CommonBuffId' = 258734 - SIM_PREFERENCE_LIKES_MUSIC_LATIN: 'CommonBuffId' = 265299 - SIM_PREFERENCE_LIKES_MUSIC_LATIN_POP: 'CommonBuffId' = 265300 - SIM_PREFERENCE_LIKES_MUSIC_LULLABIES: 'CommonBuffId' = 258795 - SIM_PREFERENCE_LIKES_MUSIC_METAL: 'CommonBuffId' = 265309 - SIM_PREFERENCE_LIKES_MUSIC_NEW_AGE: 'CommonBuffId' = 265294 - SIM_PREFERENCE_LIKES_MUSIC_NU_DISCO: 'CommonBuffId' = 265298 - SIM_PREFERENCE_LIKES_MUSIC_OLDIES: 'CommonBuffId' = 312262 - SIM_PREFERENCE_LIKES_MUSIC_POP: 'CommonBuffId' = 258699 - SIM_PREFERENCE_LIKES_MUSIC_RANCH: 'CommonBuffId' = 334861 - SIM_PREFERENCE_LIKES_MUSIC_RETRO: 'CommonBuffId' = 258796 - SIM_PREFERENCE_LIKES_MUSIC_RNB: 'CommonBuffId' = 343315 - SIM_PREFERENCE_LIKES_MUSIC_ROMANCE: 'CommonBuffId' = 258797 - SIM_PREFERENCE_LIKES_MUSIC_SINGER_SONGWRITER: 'CommonBuffId' = 265395 - SIM_PREFERENCE_LIKES_MUSIC_SPOOKY: 'CommonBuffId' = 258798 - SIM_PREFERENCE_LIKES_MUSIC_STRANGE_TUNES: 'CommonBuffId' = 265301 - SIM_PREFERENCE_LIKES_MUSIC_SUMMER_STRUT: 'CommonBuffId' = 265303 - SIM_PREFERENCE_LIKES_MUSIC_S_POP: 'CommonBuffId' = 258799 - SIM_PREFERENCE_LIKES_MUSIC_TWEEN_POP: 'CommonBuffId' = 265396 - SIM_PREFERENCE_LIKES_MUSIC_WINTER_HOLIDAY: 'CommonBuffId' = 258800 - SIM_PREFERENCE_LIKES_MUSIC_WORLD: 'CommonBuffId' = 265302 - SIM_PREFERENCE_NO_GOOD_ENVIRONMENT: 'CommonBuffId' = 268284 - SIM_PREFERENCE_RECENT_DECOR_ART_DECO: 'CommonBuffId' = 325927 - SIM_PREFERENCE_RECENT_DECOR_BASICS: 'CommonBuffId' = 325929 - SIM_PREFERENCE_RECENT_DECOR_BOHO: 'CommonBuffId' = 325940 - SIM_PREFERENCE_RECENT_DECOR_CONTEMPORARY: 'CommonBuffId' = 325941 - SIM_PREFERENCE_RECENT_DECOR_COSMO_LUX: 'CommonBuffId' = 325942 - SIM_PREFERENCE_RECENT_DECOR_CUTE: 'CommonBuffId' = 325943 - SIM_PREFERENCE_RECENT_DECOR_FRENCH_COUNTRY: 'CommonBuffId' = 325944 - SIM_PREFERENCE_RECENT_DECOR_GARDEN: 'CommonBuffId' = 325945 - SIM_PREFERENCE_RECENT_DECOR_GOTHIC_FARMHOUSE: 'CommonBuffId' = 325946 - SIM_PREFERENCE_RECENT_DECOR_INDUSTRIAL: 'CommonBuffId' = 325947 - SIM_PREFERENCE_RECENT_DECOR_ISLAND: 'CommonBuffId' = 325948 - SIM_PREFERENCE_RECENT_DECOR_LUXE: 'CommonBuffId' = 325949 - SIM_PREFERENCE_RECENT_DECOR_MISSION: 'CommonBuffId' = 325950 - SIM_PREFERENCE_RECENT_DECOR_MODERN: 'CommonBuffId' = 325951 - SIM_PREFERENCE_RECENT_DECOR_PATIO: 'CommonBuffId' = 325952 - SIM_PREFERENCE_RECENT_DECOR_QUEEN_ANNE: 'CommonBuffId' = 325953 - SIM_PREFERENCE_RECENT_DECOR_SCANDINAVIAN_CONTEMPORARY: 'CommonBuffId' = 325954 - SIM_PREFERENCE_RECENT_DECOR_SHABBY: 'CommonBuffId' = 326019 - SIM_PREFERENCE_RECENT_DECOR_SUBURBAN_CONTEMPORARY: 'CommonBuffId' = 325957 - SIM_PREFERENCE_RECENT_DECOR_TUDOR: 'CommonBuffId' = 325955 - SIM_PREFERENCE_RECENT_DECOR_VINTAGE: 'CommonBuffId' = 325956 - SIM_PREFERENCE_RECENT_DISLIKES_ACTING: 'CommonBuffId' = 264362 - SIM_PREFERENCE_RECENT_DISLIKES_BAKING: 'CommonBuffId' = 264363 - SIM_PREFERENCE_RECENT_DISLIKES_BOWLING: 'CommonBuffId' = 264364 - SIM_PREFERENCE_RECENT_DISLIKES_COMEDY: 'CommonBuffId' = 264365 - SIM_PREFERENCE_RECENT_DISLIKES_COOKING: 'CommonBuffId' = 259487 - SIM_PREFERENCE_RECENT_DISLIKES_CROSS_STITCH: 'CommonBuffId' = 274552 - SIM_PREFERENCE_RECENT_DISLIKES_DANCING: 'CommonBuffId' = 264366 - SIM_PREFERENCE_RECENT_DISLIKES_DEBATING: 'CommonBuffId' = 264367 - SIM_PREFERENCE_RECENT_DISLIKES_DJ_MIXING: 'CommonBuffId' = 264368 - SIM_PREFERENCE_RECENT_DISLIKES_EQUESTRIAN_SKILL: 'CommonBuffId' = 340007 - SIM_PREFERENCE_RECENT_DISLIKES_FISHING: 'CommonBuffId' = 264369 - SIM_PREFERENCE_RECENT_DISLIKES_FITNESS: 'CommonBuffId' = 259490 - SIM_PREFERENCE_RECENT_DISLIKES_GARDENING: 'CommonBuffId' = 264370 - SIM_PREFERENCE_RECENT_DISLIKES_GUITAR: 'CommonBuffId' = 264371 - SIM_PREFERENCE_RECENT_DISLIKES_HANDINESS: 'CommonBuffId' = 264372 - SIM_PREFERENCE_RECENT_DISLIKES_KNITTING: 'CommonBuffId' = 274544 - SIM_PREFERENCE_RECENT_DISLIKES_MEDIA_PRODUCTION: 'CommonBuffId' = 264373 - SIM_PREFERENCE_RECENT_DISLIKES_MISCHIEF: 'CommonBuffId' = 264374 - SIM_PREFERENCE_RECENT_DISLIKES_MIXOLOGY: 'CommonBuffId' = 264375 - SIM_PREFERENCE_RECENT_DISLIKES_NECTAR_MAKING: 'CommonBuffId' = 340008 - SIM_PREFERENCE_RECENT_DISLIKES_PAINTING: 'CommonBuffId' = 259488 - SIM_PREFERENCE_RECENT_DISLIKES_PHOTOGRAPHY: 'CommonBuffId' = 264376 - SIM_PREFERENCE_RECENT_DISLIKES_PIANO: 'CommonBuffId' = 264377 - SIM_PREFERENCE_RECENT_DISLIKES_PIPE_ORGAN: 'CommonBuffId' = 264408 - SIM_PREFERENCE_RECENT_DISLIKES_PROGRAMMING: 'CommonBuffId' = 264786 - SIM_PREFERENCE_RECENT_DISLIKES_ROBOTICS: 'CommonBuffId' = 264378 - SIM_PREFERENCE_RECENT_DISLIKES_ROCKET_SCIENCE: 'CommonBuffId' = 264379 - SIM_PREFERENCE_RECENT_DISLIKES_ROCK_CLIMBING: 'CommonBuffId' = 264410 - SIM_PREFERENCE_RECENT_DISLIKES_SINGING: 'CommonBuffId' = 264380 - SIM_PREFERENCE_RECENT_DISLIKES_SKIING: 'CommonBuffId' = 264381 - SIM_PREFERENCE_RECENT_DISLIKES_SNOWBOARDING: 'CommonBuffId' = 264382 - SIM_PREFERENCE_RECENT_DISLIKES_VIDEO_GAMING: 'CommonBuffId' = 259485 - SIM_PREFERENCE_RECENT_DISLIKES_VIOLIN: 'CommonBuffId' = 259491 - SIM_PREFERENCE_RECENT_DISLIKES_WELLNESS: 'CommonBuffId' = 264383 - SIM_PREFERENCE_RECENT_DISLIKES_WRITING: 'CommonBuffId' = 264384 - SIM_PREFERENCE_RECENT_FASHION_DISLIKES_BASICS: 'CommonBuffId' = 272685 - SIM_PREFERENCE_RECENT_FASHION_DISLIKES_BOHO: 'CommonBuffId' = 283114 - SIM_PREFERENCE_RECENT_FASHION_DISLIKES_COUNTRY: 'CommonBuffId' = 283115 - SIM_PREFERENCE_RECENT_FASHION_DISLIKES_HIPSTER: 'CommonBuffId' = 283116 - SIM_PREFERENCE_RECENT_FASHION_DISLIKES_OUTDOORSY: 'CommonBuffId' = 283117 - SIM_PREFERENCE_RECENT_FASHION_DISLIKES_POLISHED: 'CommonBuffId' = 283118 - SIM_PREFERENCE_RECENT_FASHION_DISLIKES_PREPPY: 'CommonBuffId' = 283119 - SIM_PREFERENCE_RECENT_FASHION_DISLIKES_ROCKER: 'CommonBuffId' = 283120 - SIM_PREFERENCE_RECENT_FASHION_DISLIKES_STREETWEAR: 'CommonBuffId' = 283121 - SIM_PREFERENCE_RECENT_FASHION_LIKES_BASICS: 'CommonBuffId' = 272686 - SIM_PREFERENCE_RECENT_FASHION_LIKES_BOHO: 'CommonBuffId' = 283122 - SIM_PREFERENCE_RECENT_FASHION_LIKES_COUNTRY: 'CommonBuffId' = 283123 - SIM_PREFERENCE_RECENT_FASHION_LIKES_HIPSTER: 'CommonBuffId' = 283128 - SIM_PREFERENCE_RECENT_FASHION_LIKES_OUTDOORSY: 'CommonBuffId' = 283129 - SIM_PREFERENCE_RECENT_FASHION_LIKES_POLISHED: 'CommonBuffId' = 283130 - SIM_PREFERENCE_RECENT_FASHION_LIKES_PREPPY: 'CommonBuffId' = 283131 - SIM_PREFERENCE_RECENT_FASHION_LIKES_ROCKER: 'CommonBuffId' = 283132 - SIM_PREFERENCE_RECENT_FASHION_LIKES_STREETWEAR: 'CommonBuffId' = 283133 - SIM_PREFERENCE_RECENT_LIKES_ACTING: 'CommonBuffId' = 264385 - SIM_PREFERENCE_RECENT_LIKES_BAKING: 'CommonBuffId' = 264386 - SIM_PREFERENCE_RECENT_LIKES_BOWLING: 'CommonBuffId' = 264387 - SIM_PREFERENCE_RECENT_LIKES_COMEDY: 'CommonBuffId' = 264388 - SIM_PREFERENCE_RECENT_LIKES_COOKING: 'CommonBuffId' = 259492 - SIM_PREFERENCE_RECENT_LIKES_CROSS_STITCH: 'CommonBuffId' = 274553 - SIM_PREFERENCE_RECENT_LIKES_DANCING: 'CommonBuffId' = 264389 - SIM_PREFERENCE_RECENT_LIKES_DEBATING: 'CommonBuffId' = 264390 - SIM_PREFERENCE_RECENT_LIKES_DJ_MIXING: 'CommonBuffId' = 264391 - SIM_PREFERENCE_RECENT_LIKES_EQUESTRIAN_SKILL: 'CommonBuffId' = 340019 - SIM_PREFERENCE_RECENT_LIKES_FISHING: 'CommonBuffId' = 264412 - SIM_PREFERENCE_RECENT_LIKES_FITNESS: 'CommonBuffId' = 259493 - SIM_PREFERENCE_RECENT_LIKES_GARDENING: 'CommonBuffId' = 264392 - SIM_PREFERENCE_RECENT_LIKES_GUITAR: 'CommonBuffId' = 264393 - SIM_PREFERENCE_RECENT_LIKES_HANDINESS: 'CommonBuffId' = 264394 - SIM_PREFERENCE_RECENT_LIKES_KNITTING: 'CommonBuffId' = 274545 - SIM_PREFERENCE_RECENT_LIKES_MEDIA_PRODUCTION: 'CommonBuffId' = 264395 - SIM_PREFERENCE_RECENT_LIKES_MISCHIEF: 'CommonBuffId' = 264396 - SIM_PREFERENCE_RECENT_LIKES_MIXOLOGY: 'CommonBuffId' = 264397 - SIM_PREFERENCE_RECENT_LIKES_NECTAR_MAKING: 'CommonBuffId' = 340020 - SIM_PREFERENCE_RECENT_LIKES_PAINTING: 'CommonBuffId' = 259494 - SIM_PREFERENCE_RECENT_LIKES_PHOTOGRAPHY: 'CommonBuffId' = 264398 - SIM_PREFERENCE_RECENT_LIKES_PIANO: 'CommonBuffId' = 264399 - SIM_PREFERENCE_RECENT_LIKES_PIPE_ORGAN: 'CommonBuffId' = 264409 - SIM_PREFERENCE_RECENT_LIKES_PROGRAMMING: 'CommonBuffId' = 264785 - SIM_PREFERENCE_RECENT_LIKES_ROBOTICS: 'CommonBuffId' = 264400 - SIM_PREFERENCE_RECENT_LIKES_ROCKET_SCIENCE: 'CommonBuffId' = 264401 - SIM_PREFERENCE_RECENT_LIKES_ROCK_CLIMBING: 'CommonBuffId' = 264411 - SIM_PREFERENCE_RECENT_LIKES_SINGING: 'CommonBuffId' = 264402 - SIM_PREFERENCE_RECENT_LIKES_SKIING: 'CommonBuffId' = 264403 - SIM_PREFERENCE_RECENT_LIKES_SNOWBOARDING: 'CommonBuffId' = 264404 - SIM_PREFERENCE_RECENT_LIKES_VIDEO_GAMING: 'CommonBuffId' = 259496 - SIM_PREFERENCE_RECENT_LIKES_VIOLIN: 'CommonBuffId' = 259497 - SIM_PREFERENCE_RECENT_LIKES_WELLNESS: 'CommonBuffId' = 264405 - SIM_PREFERENCE_RECENT_LIKES_WRITING: 'CommonBuffId' = 264406 - SIM_PREFERENCE_RECENT_MUSIC_ALTERNATIVE: 'CommonBuffId' = 267542 - SIM_PREFERENCE_RECENT_MUSIC_AMERICANA: 'CommonBuffId' = 267543 - SIM_PREFERENCE_RECENT_MUSIC_BACKYARD: 'CommonBuffId' = 267544 - SIM_PREFERENCE_RECENT_MUSIC_BAROQUE: 'CommonBuffId' = 267545 - SIM_PREFERENCE_RECENT_MUSIC_BATUU: 'CommonBuffId' = 346391 - SIM_PREFERENCE_RECENT_MUSIC_BLUES: 'CommonBuffId' = 267546 - SIM_PREFERENCE_RECENT_MUSIC_BRAZILIAN: 'CommonBuffId' = 346392 - SIM_PREFERENCE_RECENT_MUSIC_CLASSICAL: 'CommonBuffId' = 267547 - SIM_PREFERENCE_RECENT_MUSIC_COTTAGE_CORE: 'CommonBuffId' = 274583 - SIM_PREFERENCE_RECENT_MUSIC_EASY_LISTENING: 'CommonBuffId' = 267548 - SIM_PREFERENCE_RECENT_MUSIC_ELECTRONICA: 'CommonBuffId' = 267549 - SIM_PREFERENCE_RECENT_MUSIC_FOCUS: 'CommonBuffId' = 267550 - SIM_PREFERENCE_RECENT_MUSIC_HIP_HOP: 'CommonBuffId' = 267551 - SIM_PREFERENCE_RECENT_MUSIC_ISLAND: 'CommonBuffId' = 267552 - SIM_PREFERENCE_RECENT_MUSIC_JAPANESE_FOLK: 'CommonBuffId' = 267553 - SIM_PREFERENCE_RECENT_MUSIC_JAZZ: 'CommonBuffId' = 267554 - SIM_PREFERENCE_RECENT_MUSIC_KIDS: 'CommonBuffId' = 267555 - SIM_PREFERENCE_RECENT_MUSIC_LATIN: 'CommonBuffId' = 267556 - SIM_PREFERENCE_RECENT_MUSIC_LATIN_POP: 'CommonBuffId' = 267557 - SIM_PREFERENCE_RECENT_MUSIC_LULLABIES: 'CommonBuffId' = 267558 - SIM_PREFERENCE_RECENT_MUSIC_METAL: 'CommonBuffId' = 267559 - SIM_PREFERENCE_RECENT_MUSIC_NEW_AGE: 'CommonBuffId' = 267560 - SIM_PREFERENCE_RECENT_MUSIC_NU_DISCO: 'CommonBuffId' = 267561 - SIM_PREFERENCE_RECENT_MUSIC_OLDIES: 'CommonBuffId' = 312263 - SIM_PREFERENCE_RECENT_MUSIC_POP: 'CommonBuffId' = 267562 - SIM_PREFERENCE_RECENT_MUSIC_RANCH: 'CommonBuffId' = 334862 - SIM_PREFERENCE_RECENT_MUSIC_RETRO: 'CommonBuffId' = 267563 - SIM_PREFERENCE_RECENT_MUSIC_RNB: 'CommonBuffId' = 343309 - SIM_PREFERENCE_RECENT_MUSIC_ROMANCE: 'CommonBuffId' = 267564 - SIM_PREFERENCE_RECENT_MUSIC_SINGER_SONGWRITER: 'CommonBuffId' = 267565 - SIM_PREFERENCE_RECENT_MUSIC_SPOOKY: 'CommonBuffId' = 267566 - SIM_PREFERENCE_RECENT_MUSIC_STRANGE_TUNES: 'CommonBuffId' = 267567 - SIM_PREFERENCE_RECENT_MUSIC_SUMMER_STRUT: 'CommonBuffId' = 267568 - SIM_PREFERENCE_RECENT_MUSIC_S_POP: 'CommonBuffId' = 267575 - SIM_PREFERENCE_RECENT_MUSIC_TWEEN_POP: 'CommonBuffId' = 267569 - SIM_PREFERENCE_RECENT_MUSIC_WINTER_HOLIDAY: 'CommonBuffId' = 267570 - SIM_PREFERENCE_RECENT_MUSIC_WORLD: 'CommonBuffId' = 267571 - SIM_PUBERTY_CHANGES_HAS_VISIBLE_BODY_HAIR_BG: 'CommonBuffId' = 303973 - SIM_RAY_CHILLED: 'CommonBuffId' = 105959 - SIM_RAY_FROZEN: 'CommonBuffId' = 103994 - SIM_RAY_FROZEN_CHILD: 'CommonBuffId' = 115718 - SIM_RAY_MIND_CONTROL_CLEAN: 'CommonBuffId' = 106199 - SIM_RAY_MIND_CONTROL_EAT: 'CommonBuffId' = 106127 - SIM_RAY_MIND_CONTROL_PANIC: 'CommonBuffId' = 106062 - SIM_RAY_MIND_CONTROL_SIT: 'CommonBuffId' = 106225 - SIM_RAY_MIND_CONTROL_SLEEP: 'CommonBuffId' = 106219 - SIM_RAY_MWHAHAHA: 'CommonBuffId' = 105904 - SIM_RAY_TRANSFORMED: 'CommonBuffId' = 103814 - SIM_REACT_TO_PET_BIRTH: 'CommonBuffId' = 169087 - SIM_READ_TO_THIS_SIM: 'CommonBuffId' = 153698 - SIM_RECENT_BIRTHDAY: 'CommonBuffId' = 125738 - SIM_RETURN_TO_LOT_COOLDOWN: 'CommonBuffId' = 177688 - SIM_SCARED_SCREAM_INCOHERENTLY_EMOTIONAL_SUPPORT: 'CommonBuffId' = 253289 - SIM_SCARED_SCREAM_INCOHERENTLY_IRRATIONAL_DANGER: 'CommonBuffId' = 253288 - SIM_SEASON_WEATHER_BLIZZARD_INSIDE: 'CommonBuffId' = 183483 - SIM_SEASON_WEATHER_BLIZZARD_OUTSIDE: 'CommonBuffId' = 183183 - SIM_SEASON_WEATHER_HIDDEN_ICY_ELDER_OUTSIDE: 'CommonBuffId' = 248759 - SIM_SEASON_WEATHER_HIDDEN_ICY_NON_ELDER: 'CommonBuffId' = 248770 - SIM_SEASON_WEATHER_HIDDEN_MOUNTAIN_SNOW_SNOW_ON_GROUND: 'CommonBuffId' = 248129 - SIM_SEASON_WEATHER_HIDDEN_STORMS_RAIN_INSIDE: 'CommonBuffId' = 183478 - SIM_SEASON_WEATHER_HIDDEN_STORMS_RAIN_OUTSIDE: 'CommonBuffId' = 183479 - SIM_SEASON_WEATHER_HIDDEN_STORMS_THUNDER_ANYWHERE: 'CommonBuffId' = 183480 - SIM_SEASON_WEATHER_HIDDEN_STORMS_THUNDER_INSIDE: 'CommonBuffId' = 183481 - SIM_SEASON_WEATHER_HIDDEN_STORMS_THUNDER_OUTSIDE: 'CommonBuffId' = 183482 - SIM_SEASON_WEATHER_RAIN_HEAVY_RAIN_INSIDE: 'CommonBuffId' = 183476 - SIM_SEASON_WEATHER_RAIN_HEAVY_RAIN_OUTSIDE: 'CommonBuffId' = 183123 - SIM_SEASON_WEATHER_RAIN_LIGHT_RAIN_INSIDE: 'CommonBuffId' = 183475 - SIM_SEASON_WEATHER_RAIN_LIGHT_RAIN_OUTSIDE: 'CommonBuffId' = 183122 - SIM_SHARE_DESIRE_FOR_INDEPENDENCE_COOLDOWN: 'CommonBuffId' = 340723 - SIM_SINGED: 'CommonBuffId' = 75843 - SIM_SOCIAL_HUG_COOLDOWN: 'CommonBuffId' = 215939 - SIM_SPEAKING_WITH_RELATIVE: 'CommonBuffId' = 127122 - SIM_STABLE_GOSSIP: 'CommonBuffId' = 340805 - SIM_START_GROUP_COOKING: 'CommonBuffId' = 270157 - SIM_SUPPRESS_TARGET_SIM_SOCIALS_HIDDEN: 'CommonBuffId' = 141984 - SIM_SUPPRESS_TARGET_SIM_SOCIALS_HIDDEN_AUTONOMOUS_ONLY: 'CommonBuffId' = 178272 - SIM_SUPPRESS_TARGET_SIM_SOCIALS_VAMPIRE_HIDDEN: 'CommonBuffId' = 176782 - SIM_TODDLER_CHANGE_DIAPER_DIRTY_DIAPER: 'CommonBuffId' = 151218 - SIM_TODDLER_CHANGE_DIAPER_DIRTY_DIAPER_DISASTER: 'CommonBuffId' = 151237 - SIM_TO_PET_HUG_HAPPY: 'CommonBuffId' = 160353 - SIM_TO_PET_HUG_HAPPY_DOG: 'CommonBuffId' = 167115 - SIM_TO_PET_KISS_HAPPY: 'CommonBuffId' = 160354 - SIM_TO_PET_KISS_HAPPY_DOG: 'CommonBuffId' = 167116 - SIM_VIBED_WITH_A_CHILL_HORSE: 'CommonBuffId' = 340910 - SIM_WAIT_STAFF_CUSTOMER_CHECK_ON_TABLE_COOLDOWN: 'CommonBuffId' = 134972 - SIM_WAKEUP_IN_X_HOURS_HIDDEN: 'CommonBuffId' = 77288 - SIM_WALK_STYLE_WALK_SLOWEST: 'CommonBuffId' = 253866 - SIM_WEATHER_BLIZZARD_SCARED_OUTSIDE: 'CommonBuffId' = 184861 - SIM_WEATHER_DISALLOW_FIRST_SNOW_REACT: 'CommonBuffId' = 302612 - SIM_WEATHER_HIDDEN_BLIZZARD: 'CommonBuffId' = 182690 - SIM_WEATHER_HIDDEN_CLOUDY: 'CommonBuffId' = 185980 - SIM_WEATHER_HIDDEN_CLOUDY_PARTIAL: 'CommonBuffId' = 211622 - SIM_WEATHER_HIDDEN_RAINING: 'CommonBuffId' = 182654 - SIM_WEATHER_HIDDEN_SNOWING: 'CommonBuffId' = 182653 - SIM_WEATHER_HIDDEN_SNOW_ON_GROUND: 'CommonBuffId' = 182698 - SIM_WEATHER_HIDDEN_SUNNY: 'CommonBuffId' = 185979 - SIM_WEATHER_HIDDEN_THUNDER_STORM: 'CommonBuffId' = 182691 - SIM_WEATHER_HIDDEN_WINDY: 'CommonBuffId' = 185981 - SIM_WEATHER_LIGHTNING_NEAR: 'CommonBuffId' = 185472 - SIM_WEATHER_LIGHTNING_NEAR_TODDLER: 'CommonBuffId' = 190217 - SIM_WEATHER_LIGHTNING_STRUCK: 'CommonBuffId' = 185540 - SIM_WEATHER_LIGHTNING_STRUCK_HYPER_CHARGED: 'CommonBuffId' = 186029 - SIM_WEATHER_LIGHTNING_STRUCK_INSANE: 'CommonBuffId' = 185568 - SIM_WEATHER_LIGHTNING_STRUCK_SUPERCHARGED: 'CommonBuffId' = 186028 - SIM_WEATHER_RAIN_GREAT_TIME: 'CommonBuffId' = 185735 - SIM_WEATHER_RAIN_PLAYING: 'CommonBuffId' = 184929 - SIM_WEATHER_RAIN_RUN_INSIDE: 'CommonBuffId' = 190792 - SIM_WEATHER_STORM_SCARED_INSIDE: 'CommonBuffId' = 184421 - SIM_WEATHER_STORM_SCARED_INSIDE_TODDLER: 'CommonBuffId' = 190218 - SIM_WEATHER_STORM_STORM_CHASER_INSIDE: 'CommonBuffId' = 185797 - SIM_WEATHER_STORM_STORM_CHASER_OUTSIDE: 'CommonBuffId' = 185798 - SIM_WEATHER_STORM_TENSE_OUTSIDE: 'CommonBuffId' = 184422 - SIM_WEATHER_STORM_TENSE_OUTSIDE_TODDLER: 'CommonBuffId' = 190219 - SIM_WEATHER_THUNDER_SNOWSTORM_SQUALL_OF_WONDERS: 'CommonBuffId' = 248793 - SIM_WETNESS_TODDLER: 'CommonBuffId' = 188071 - SIM_WETNESS_WET: 'CommonBuffId' = 183761 - SIM_WET_PUDDLE_COOLDOWN: 'CommonBuffId' = 190700 - SIM_WOKE_UP_NOT_LAZY: 'CommonBuffId' = 155804 - SITUATION_APARTMENT_NEIGHBORS_DOOR_ROUTED_TO_HIDDEN: 'CommonBuffId' = 139244 - SITUATION_APARTMENT_NEIGHBOR_BRAINSTORM_INSPIRED: 'CommonBuffId' = 153400 - SITUATION_APARTMENT_NEIGHBOR_INVITED_IN: 'CommonBuffId' = 139548 - SITUATION_APARTMENT_NEIGHBOR_NOISY_NEIGHBORS_ANGRY: 'CommonBuffId' = 136835 - SITUATION_APARTMENT_NEIGHBOR_NOISY_NEIGHBORS_TENSE: 'CommonBuffId' = 145007 - SITUATION_BETROTHED_BRONZE: 'CommonBuffId' = 76685 - SITUATION_BETROTHED_GOLD: 'CommonBuffId' = 76689 - SITUATION_BETROTHED_SILVER: 'CommonBuffId' = 76690 - SITUATION_BIRTHDAY_BRONZE: 'CommonBuffId' = 76662 - SITUATION_BIRTHDAY_GOLD: 'CommonBuffId' = 76664 - SITUATION_BIRTHDAY_SILVER: 'CommonBuffId' = 76663 - SITUATION_BREAK_IN: 'CommonBuffId' = 361112 - SITUATION_CAREGIVER_BABY: 'CommonBuffId' = 276011 - SITUATION_COOKOUT_PROPANE_VS_CHARCOAL: 'CommonBuffId' = 301548 - SITUATION_DATE_BRONZE: 'CommonBuffId' = 76687 - SITUATION_DATE_GOLD: 'CommonBuffId' = 76691 - SITUATION_DATE_SILVER: 'CommonBuffId' = 76692 - SITUATION_DOCTOR_CAREER_AT_WORK: 'CommonBuffId' = 112130 - SITUATION_DOCTOR_CAREER_DAY1: 'CommonBuffId' = 115809 - SITUATION_DOCTOR_CAREER_PATIENT_DIAGNOSIS_NO_ILLNESS: 'CommonBuffId' = 112642 - SITUATION_DOCTOR_CAREER_PATIENT_TREATED_MED_RECORD: 'CommonBuffId' = 112635 - SITUATION_DOCTOR_CAREER_SAMPLE_ANALYSIS_DATA_ENTRY: 'CommonBuffId' = 112636 - SITUATION_DOCTOR_CAREER_SAMPLE_ANALYSIS_DATA_ENTRY_EMERGENCY: 'CommonBuffId' = 116458 - SITUATION_DOCTOR_CAREER_SAMPLE_ANALYSIS_EMERGENCY_COLLECTED_ITEMS: 'CommonBuffId' = 116660 - SITUATION_FIRE_FINED_FOR_PHONY_CALL: 'CommonBuffId' = 239656 - SITUATION_FIRE_FIRE_BRIGADE_COOLDOWN: 'CommonBuffId' = 237751 - SITUATION_FIRE_FIRE_BRIGADE_ROLE_FIGHT_FIRE: 'CommonBuffId' = 237701 - SITUATION_FIRE_FIRE_FIGHTER_FINISHED_COOLDOWN: 'CommonBuffId' = 241074 - SITUATION_FIRE_FIRE_FIGHTER_ROLE_FIGHT_FIRE: 'CommonBuffId' = 234743 - SITUATION_FIRE_FIRE_FIGHTER_ROUTE_FAIL_COOLDOWN: 'CommonBuffId' = 234742 - SITUATION_FIRE_FIRE_FIGHTER_START_UP_COOLDOWN: 'CommonBuffId' = 241073 - SITUATION_FIRE_OVER: 'CommonBuffId' = 99542 - SITUATION_FIRE_PANIC: 'CommonBuffId' = 73844 - SITUATION_FIRE_PANIC_CAREGIVER: 'CommonBuffId' = 155636 - SITUATION_FIRE_SAFE: 'CommonBuffId' = 100125 - SITUATION_FIRE_SAFE_TODDLER: 'CommonBuffId' = 155675 - SITUATION_FIRE_SAVED_BY_FIRE_FIGHTER: 'CommonBuffId' = 234741 - SITUATION_GO_DANCING_NEGATIVE: 'CommonBuffId' = 125398 - SITUATION_GO_DANCING_POSITIVE: 'CommonBuffId' = 125397 - SITUATION_GUEST_BRONZE: 'CommonBuffId' = 76669 - SITUATION_GUEST_GOLD: 'CommonBuffId' = 76671 - SITUATION_GUEST_SILVER: 'CommonBuffId' = 76670 - SITUATION_HAPPY_HOUR: 'CommonBuffId' = 153663 - SITUATION_HIDDEN_PARTICIPATED_IN_KARAOKE_CONTEST: 'CommonBuffId' = 138183 - SITUATION_HOST_BRONZE: 'CommonBuffId' = 76673 - SITUATION_HOST_GOLD: 'CommonBuffId' = 76675 - SITUATION_HOST_SILVER: 'CommonBuffId' = 76674 - SITUATION_KARAOKE_CONTEST_WINNER: 'CommonBuffId' = 152874 - SITUATION_MULTI_SERVE_SITUATION_RANCH_NECTAR_AUTONOMOUS_COOLDOWN: 'CommonBuffId' = 336474 - SITUATION_NEIGHBORHOOD_POTLUCK_EAT: 'CommonBuffId' = 357113 - SITUATION_NEIGHBORHOOD_POTLUCK_GUEST: 'CommonBuffId' = 344236 - SITUATION_PATROL_IS_CRIMINAL: 'CommonBuffId' = 110750 - SITUATION_PATROL_TIMER_BUFF: 'CommonBuffId' = 116390 - SITUATION_PLAY_DATE_NPC_INVITE_BRONZE: 'CommonBuffId' = 117608 - SITUATION_PLAY_DATE_NPC_INVITE_GOLD: 'CommonBuffId' = 117610 - SITUATION_PLAY_DATE_NPC_INVITE_SILVER: 'CommonBuffId' = 117609 - SITUATION_POOL_PARTY_GUEST: 'CommonBuffId' = 344233 - SITUATION_POOL_PARTY_SWIM: 'CommonBuffId' = 357112 - SITUATION_POOL_PARTY_TOO_COLD: 'CommonBuffId' = 345154 - SITUATION_POOL_PARTY_TOO_HOT: 'CommonBuffId' = 345153 - SITUATION_PRE_POST_WEDDING_PARTIES_BACH_PARTY_ARRIVAL: 'CommonBuffId' = 275427 - SITUATION_PRE_POST_WEDDING_PARTIES_BACH_PARTY_BARFLY: 'CommonBuffId' = 275428 - SITUATION_PRE_POST_WEDDING_PARTIES_BACH_PARTY_DANCING: 'CommonBuffId' = 275429 - SITUATION_PRE_POST_WEDDING_PARTIES_BACH_PARTY_DESSERTS: 'CommonBuffId' = 275430 - SITUATION_PRE_POST_WEDDING_PARTIES_BACH_PARTY_DINNER: 'CommonBuffId' = 275431 - SITUATION_PRE_POST_WEDDING_PARTIES_BACH_PARTY_DRINKING: 'CommonBuffId' = 275432 - SITUATION_PRE_POST_WEDDING_PARTIES_BACH_PARTY_TOAST: 'CommonBuffId' = 275433 - SITUATION_PRE_POST_WEDDING_PARTIES_SLOW_MOTIVES: 'CommonBuffId' = 275422 - SITUATION_PRE_POST_WEDDING_PARTIES_TEA: 'CommonBuffId' = 278442 - SITUATION_S_S3_REQUEST: 'CommonBuffId' = 99555 - SITUATION_UNGREETED_PLAYER_VISITING_NPC: 'CommonBuffId' = 34725 - SITUATION_WEENIE_PARTY: 'CommonBuffId' = 192597 - SITUATION_WEENIE_ROAST_HOST_BRONZE: 'CommonBuffId' = 103827 - SITUATION_WEENIE_ROAST_HOST_GOLD: 'CommonBuffId' = 103829 - SITUATION_WEENIE_ROAST_HOST_SILVER: 'CommonBuffId' = 103828 - SITUATION_YOGA_CLASS_BENT_OUT_OF_SHAPE: 'CommonBuffId' = 118678 - SITUATION_YOGA_CLASS_CLASS_IS_JOINABLE: 'CommonBuffId' = 121561 - SITUATION_YOGA_CLASS_IS_OUTSIDE: 'CommonBuffId' = 272313 - SITUATION_YOGA_CLASS_MEMBER: 'CommonBuffId' = 120018 - SITUATION_YOGA_CLASS_MEMBER_PRE_CLASS: 'CommonBuffId' = 272015 - SITUATION_YOGA_CLASS_POST_CLASS: 'CommonBuffId' = 119972 - SIT_LOUNGE_FLOAT_LOUNGER_SPLASHED_ANGRY: 'CommonBuffId' = 212265 - SIT_LOUNGE_FLOAT_LOUNGER_SPLASHED_PLAYFUL: 'CommonBuffId' = 212273 - SIT_LOUNGE_FLOAT_LOUNGER_SPLASHED_RUDE_AWAKENING: 'CommonBuffId' = 212274 - SIT_LOUNGE_FLOAT_SUPER_SPLASHED_ANGRY: 'CommonBuffId' = 212275 - SIT_LOUNGE_FLOAT_SUPER_SPLASHED_PLAYFUL: 'CommonBuffId' = 212315 - SIT_LOUNGE_FLOAT_SUPER_SPLASH_PLAYFUL: 'CommonBuffId' = 212718 - SKELETON: 'CommonBuffId' = 175971 - SKELETON_HEARD_JOKE: 'CommonBuffId' = 176570 - SKELETON_SERVICE_SKELETON: 'CommonBuffId' = 177753 - SKELETON_SERVICE_SKELETON_LEAVE: 'CommonBuffId' = 178960 - SKELETON_SERVICE_SKELETON_RARE: 'CommonBuffId' = 177829 - SKELETON_SERVICE_SKELETON_UNCOMMON: 'CommonBuffId' = 177828 - SKIING_ADVICE_ON_AVOIDING_WIPE_OUTS_HIDDEN: 'CommonBuffId' = 245833 - SKIING_COACHED_HIDDEN: 'CommonBuffId' = 246329 - SKIING_COACH_FAILED_ON_COOLDOWN_HIDDEN: 'CommonBuffId' = 246478 - SKIING_DEATH_COOKIE_WARNING: 'CommonBuffId' = 245642 - SKIING_DEATH_COOKIE_WARNING_HIDDEN_COOLDOWN: 'CommonBuffId' = 245643 - SKIING_DISCUSS_PAST_SKI_EXPERIENCES_REMINISCING_ABOUT_GOODTIMES: 'CommonBuffId' = 246739 - SKIING_DISCUSS_PAST_SKI_EXPERIENCES_UNWANTED_MEMORIES: 'CommonBuffId' = 246740 - SKIING_GREAT_COACH: 'CommonBuffId' = 246327 - SKIING_NO_MATCH_FOR_THE_COOKIES: 'CommonBuffId' = 249599 - SKIING_OFFER_SKI_EXPERTISE_COOLDOWN_HIDDEN: 'CommonBuffId' = 246635 - SKIING_PREPARE_FOR_THE_MOMENT_COOLDOWN_HIDDEN: 'CommonBuffId' = 246766 - SKIING_PREPARE_FOR_THE_MOMENT_LOOKING_FOOLISH: 'CommonBuffId' = 246765 - SKIING_PREPARE_FOR_THE_MOMENT_READY_TO_SKI: 'CommonBuffId' = 246764 - SKIING_SKI_PUPIL: 'CommonBuffId' = 246328 - SKIING_TEACH_SKI_CLASS_KNOWLEDGE_SHARING: 'CommonBuffId' = 246289 - SKIING_WELL_WRITTEN_POST: 'CommonBuffId' = 245700 - SKILL_BARTENDING_HIGH: 'CommonBuffId' = 10357 - SKILL_BARTENDING_MED: 'CommonBuffId' = 10356 - SKILL_BARTENDING_TRICKS: 'CommonBuffId' = 98315 - SKILL_CHARISMA_GIVING_GUSTO_HIGH: 'CommonBuffId' = 31097 - SKILL_CHARISMA_GIVING_GUSTO_LOW: 'CommonBuffId' = 31093 - SKILL_CHARISMA_GIVING_GUSTO_MED: 'CommonBuffId' = 31096 - SKILL_CHARISMA_GIVING_GUSTO_SAD: 'CommonBuffId' = 31129 - SKILL_CHARISMA_SILVER_TONGUE: 'CommonBuffId' = 31301 - SKILL_COMEDY_BRIEFLY_AMUSED: 'CommonBuffId' = 31341 - SKILL_COMEDY_BUSTED_A_GUT: 'CommonBuffId' = 31345 - SKILL_COMEDY_COMEDY_GOLD: 'CommonBuffId' = 31346 - SKILL_COMEDY_FUNNY_BONE_TICKLED: 'CommonBuffId' = 31343 - SKILL_COMEDY_OVER_PRACTICED: 'CommonBuffId' = 30349 - SKILL_COMEDY_PERFECTLY_PRACTICED: 'CommonBuffId' = 30347 - SKILL_COMEDY_PERFORMANCE_PAYOUT_NORMAL: 'CommonBuffId' = 31625 - SKILL_COMEDY_PERFORMANCE_PAYOUT_OUTSTANDING: 'CommonBuffId' = 31624 - SKILL_COMEDY_PERFORMANCE_PAYOUT_POOR: 'CommonBuffId' = 31623 - SKILL_COMEDY_PSYCHED_SELF_OUT: 'CommonBuffId' = 30350 - SKILL_COMEDY_SOMEWHAT_PRACTICED: 'CommonBuffId' = 30346 - SKILL_COMEDY_WELL_PRACTICED: 'CommonBuffId' = 30348 - SKILL_COOKING_GOURMET: 'CommonBuffId' = 37341 - SKILL_COOKING_HIDDEN: 'CommonBuffId' = 76610 - SKILL_COOKING_HIGH: 'CommonBuffId' = 37340 - SKILL_COOKING_MED: 'CommonBuffId' = 37339 - SKILL_CREATIVITY_DAYDREAM: 'CommonBuffId' = 39396 - SKILL_EQUESTRIAN_SKILL_A_TERRIFIC_TROT: 'CommonBuffId' = 317973 - SKILL_EQUESTRIAN_SKILL_A_VIEW_FROM_HORSEBACK: 'CommonBuffId' = 317974 - SKILL_EQUESTRIAN_SKILL_BONDING_WITH_STEED: 'CommonBuffId' = 317975 - SKILL_EQUESTRIAN_SKILL_GIDDY_UP: 'CommonBuffId' = 317976 - SKILL_EQUESTRIAN_SKILL_HIGH_ON_THE_SADDLE: 'CommonBuffId' = 317971 - SKILL_EQUESTRIAN_SKILL_HORSING_AROUND: 'CommonBuffId' = 317977 - SKILL_EQUESTRIAN_SKILL_RIDING_RHYTHM: 'CommonBuffId' = 317978 - SKILL_EQUESTRIAN_SKILL_SADDLE_SORE: 'CommonBuffId' = 323078 - SKILL_EQUESTRIAN_SKILL_SADDLE_SORE_POST_RIDE: 'CommonBuffId' = 327015 - SKILL_EQUESTRIAN_SKILL_STAR_STUDENT: 'CommonBuffId' = 327171 - SKILL_EQUESTRIAN_SKILL_TAKIN_CARE_OF_BUSINESS: 'CommonBuffId' = 321626 - SKILL_FABRICATION_EXPLOSION: 'CommonBuffId' = 233402 - SKILL_FABRICATION_EXPLOSION_POSITIVE: 'CommonBuffId' = 237574 - SKILL_FABRICATION_FIGHT: 'CommonBuffId' = 233401 - SKILL_FABRICATION_RECENTLY_PROFESSED: 'CommonBuffId' = 237447 - SKILL_FISHING_AMAZING_CATCH: 'CommonBuffId' = 76428 - SKILL_FISHING_ANGLE_FOR_BIG_CATCH: 'CommonBuffId' = 208732 - SKILL_FISHING_CAUGHT_ENDANGERED_FISH: 'CommonBuffId' = 212672 - SKILL_FISHING_CAUGHT_EXCELLENT_FISH: 'CommonBuffId' = 216899 - SKILL_FISHING_CAUGHT_FISH: 'CommonBuffId' = 76816 - SKILL_FISHING_CAUGHT_FISH_WITH_BAIT: 'CommonBuffId' = 77314 - SKILL_FISHING_CAUGHT_LARGE_FISH: 'CommonBuffId' = 100093 - SKILL_FISHING_EXPERT_TIP_GIVER: 'CommonBuffId' = 214365 - SKILL_FISHING_FISH_FRIEND: 'CommonBuffId' = 212663 - SKILL_FISHING_GREAT_CATCH: 'CommonBuffId' = 76427 - SKILL_FISHING_TOLD_TO_FISH: 'CommonBuffId' = 212626 - SKILL_GARDENING_TEACH_ABOUT_PLANTS_COOLDOWN: 'CommonBuffId' = 263254 - SKILL_HANDINESS_OUCH: 'CommonBuffId' = 28424 - SKILL_HANDINESS_PRETTY_HANDY: 'CommonBuffId' = 28431 - SKILL_HANDINESS_SO_HANDY: 'CommonBuffId' = 28440 - SKILL_MENTAL_ATTEMPT_MENTAL_TELEPATHY: 'CommonBuffId' = 99501 - SKILL_MISCHIEF_FAILED_MONEY_SPAM: 'CommonBuffId' = 38483 - SKILL_MUSIC_COMPETENT_COMPOSER: 'CommonBuffId' = 37456 - SKILL_MUSIC_WRITE_LYRICS: 'CommonBuffId' = 153710 - SKILL_PAINTING_INSPIRING_ARTIST: 'CommonBuffId' = 37329 - SKILL_PAINTING_MADE_MASTERPIECE: 'CommonBuffId' = 98301 - SKILL_PAINTING_SPOKE_WITH_AGENT: 'CommonBuffId' = 38642 - SKILL_PROGRAMMING_CAUGHT_CHEATING: 'CommonBuffId' = 37294 - SKILL_PROGRAMMING_CAUGHT_HACKING_WORK_PERFORMANCE: 'CommonBuffId' = 38562 - SKILL_PROGRAMMING_HACKED_GRADES: 'CommonBuffId' = 37293 - SKILL_PROGRAMMING_HACKED_SUPERCOMPUTER: 'CommonBuffId' = 36845 - SKILL_PROGRAMMING_HACKED_TARGET1: 'CommonBuffId' = 31606 - SKILL_PROGRAMMING_HACKED_TARGET2: 'CommonBuffId' = 32388 - SKILL_PROGRAMMING_HACKED_TARGET3: 'CommonBuffId' = 32389 - SKILL_PROGRAMMING_HACKED_TARGET4: 'CommonBuffId' = 32390 - SKILL_PROGRAMMING_HACKED_TARGET5: 'CommonBuffId' = 32391 - SKILL_PROGRAMMING_HACKED_TARGET6: 'CommonBuffId' = 32392 - SKILL_PROGRAMMING_HACKED_WORK_PERFORMANCE: 'CommonBuffId' = 38554 - SKILL_ROCK_CLIMBING_BAR_CONSUME_TIMER_ENERGY: 'CommonBuffId' = 253715 - SKILL_ROCK_CLIMBING_BAR_CONSUME_TIMER_PROTEIN: 'CommonBuffId' = 253698 - SKILL_ROCK_CLIMBING_CHALK_HANDS_COOLDOWN: 'CommonBuffId' = 245982 - SKILL_ROCK_CLIMBING_COACHED_SKILL_GAIN: 'CommonBuffId' = 246956 - SKILL_ROCK_CLIMBING_CONFIDENT_GRIP: 'CommonBuffId' = 245986 - SKILL_ROCK_CLIMBING_GREAT_COACH: 'CommonBuffId' = 246954 - SKILL_ROCK_CLIMBING_HARD_HANDS: 'CommonBuffId' = 245993 - SKILL_ROCK_CLIMBING_MAKE_ENERGY_BAR_COOLDOWN: 'CommonBuffId' = 246413 - SKILL_ROCK_CLIMBING_MAKE_PROTEIN_BAR_COOLDOWN: 'CommonBuffId' = 246412 - SKILL_ROCK_CLIMBING_OFFER_TIPS_COOLDOWN: 'CommonBuffId' = 253070 - SKILL_ROCK_CLIMBING_PART_TIMER: 'CommonBuffId' = 245995 - SKILL_ROCK_CLIMBING_PASSABLE_PREPARATION: 'CommonBuffId' = 245989 - SKILL_ROCK_CLIMBING_PLANNED_FOR_THE_PINNACLE: 'CommonBuffId' = 245991 - SKILL_ROCK_CLIMBING_READY_AS_EVER: 'CommonBuffId' = 245988 - SKILL_ROCK_CLIMBING_ROCK_CLIMBING_PUPIL: 'CommonBuffId' = 245992 - SKILL_ROCK_CLIMBING_ROCK_CLIMBING_REBUTTAL: 'CommonBuffId' = 245997 - SKILL_ROCK_CLIMBING_STRETCH_TOO_FAR: 'CommonBuffId' = 245990 - SKILL_ROCK_CLIMBING_TASTES_LIKE_CARDBOARD: 'CommonBuffId' = 253700 - SKILL_ROCK_CLIMBING_VAUNTED_VISTA: 'CommonBuffId' = 245996 - SKILL_TRAIT_ENTREPRENEUR_THE_KNOWLEDGE: 'CommonBuffId' = 277993 - SKILL_UP_CHECK_FLAG: 'CommonBuffId' = 282273 - SKILL_VIDEO_GAMING_GAMED_OUT: 'CommonBuffId' = 31758 - SKILL_VIDEO_GAMING_GOOD_SESSION: 'CommonBuffId' = 38877 - SKILL_VIDEO_GAMING_TOURNAMENT_LOSS: 'CommonBuffId' = 31910 - SKILL_VIDEO_GAMING_TOURNAMENT_WIN: 'CommonBuffId' = 31909 - SKILL_WELLNESS_IDLE: 'CommonBuffId' = 118686 - SKILL_WOOHOO_COMPLETELY_SATISFIED: 'CommonBuffId' = 34027 - SKILL_WOOHOO_PERFORMED_POORLY: 'CommonBuffId' = 34021 - SKILL_WOOHOO_PLEASANTLY_SATISFIED: 'CommonBuffId' = 34026 - SKILL_WOOHOO_SEEING_STARS: 'CommonBuffId' = 34028 - SKILL_WOOHOO_UNSATISFIED: 'CommonBuffId' = 34034 - SKILL_WRITING_BEAT_WRITERS_BLOCK: 'CommonBuffId' = 34377 - SKILL_WRITING_LITERARY_EXAMPLE: 'CommonBuffId' = 34324 - SKILL_WRITING_NEW_NOVEL: 'CommonBuffId' = 34089 - SKILL_WRITING_PROLIFIC_WRITER: 'CommonBuffId' = 39302 - SKILL_WRITING_WRITERS_BLOCK: 'CommonBuffId' = 34131 - SLEEPING_BAG_CAMPIN_OUT: 'CommonBuffId' = 312948 - SLEEPING_BAG_EW_BUGS: 'CommonBuffId' = 312945 - SLEEPING_BAG_HOST_OF_HORROR: 'CommonBuffId' = 312951 - SLEEPING_BAG_JUST_A_STORY: 'CommonBuffId' = 312955 - SLEEPING_BAG_MY_BACK: 'CommonBuffId' = 312947 - SLEEPING_BAG_PILLOW_CONQUER: 'CommonBuffId' = 312954 - SLEEPING_BAG_PRANK_BROADCASTER: 'CommonBuffId' = 320652 - SLEEPING_BAG_PRANK_FEELING_IT: 'CommonBuffId' = 320651 - SLEEPING_BAG_PRANK_NOT_FEELING_IT: 'CommonBuffId' = 320650 - SLEEPING_BAG_PRANK_VIEWER: 'CommonBuffId' = 320649 - SLEEPING_BAG_PUMMELED_BY_PILLOWS: 'CommonBuffId' = 312953 - SLEEPING_BAG_SNUG_AS_A_BUG: 'CommonBuffId' = 312946 - SLEEPING_BAG_SPELLBOUND_SPECTATOR: 'CommonBuffId' = 312950 - SLEEPING_BAG_STORYWEAVER: 'CommonBuffId' = 312949 - SLEEPING_POD_CIRCADIAN_TWEAKER: 'CommonBuffId' = 200636 - SLEEPING_POD_MISCHIEF_ANGRY: 'CommonBuffId' = 200411 - SLEEPING_POD_MISCHIEF_BORED: 'CommonBuffId' = 200413 - SLEEPING_POD_MISCHIEF_CAUGHT_NEGATIVE: 'CommonBuffId' = 200895 - SLEEPING_POD_MISCHIEF_EMBARRASSED: 'CommonBuffId' = 200412 - SLEEPING_POD_MISCHIEF_NOT_CAUGHT_POSITIVE: 'CommonBuffId' = 200894 - SLEEPING_POD_MISCHIEF_SAD: 'CommonBuffId' = 200410 - SLEEPING_POD_MISCHIEF_TRAPPED: 'CommonBuffId' = 200425 - SLEEPING_POD_MISCHIEF_WITNESS_SABOTAGE: 'CommonBuffId' = 200947 - SLEEPING_POD_SLEEP_MOTIVE_DECAY_SUPPRESSION: 'CommonBuffId' = 201367 - SLEEPING_POD_SUBLIMINAL_TRANSMITTER_DREAMS_CONFIDENT: 'CommonBuffId' = 200402 - SLEEPING_POD_SUBLIMINAL_TRANSMITTER_DREAMS_EDUCATIONAL: 'CommonBuffId' = 200407 - SLEEPING_POD_SUBLIMINAL_TRANSMITTER_DREAMS_ENERGIZED: 'CommonBuffId' = 200404 - SLEEPING_POD_SUBLIMINAL_TRANSMITTER_DREAMS_FOCUSED: 'CommonBuffId' = 200403 - SLEEPING_POD_SUBLIMINAL_TRANSMITTER_DREAMS_FUN: 'CommonBuffId' = 200406 - SLEEPING_POD_SUBLIMINAL_TRANSMITTER_DREAMS_INSPIRED: 'CommonBuffId' = 200400 - SLEEPING_POD_SUBLIMINAL_TRANSMITTER_DREAMS_RESTFUL: 'CommonBuffId' = 200401 - SLEEPING_POD_SUBLIMINAL_TRANSMITTER_DREAMS_SOCIAL: 'CommonBuffId' = 200405 - SLEEPING_POD_SUBLIMINAL_TRANSMITTER_INTERRUPTED_DREAMS: 'CommonBuffId' = 201035 - SLEEPING_POD_UP_N_ATOMIZER: 'CommonBuffId' = 200960 - SLEEPOVER_SLEEPING_BAG_SETUP: 'CommonBuffId' = 333456 - SLEEPOVER_SNACKS_COOLDOWN: 'CommonBuffId' = 313777 - SLEEPOVER_TIME_FOR_BED: 'CommonBuffId' = 333627 - SLOW_EXPERIENCES_STATES_EMOTIONAL_CONTROL: 'CommonBuffId' = 245284 - SLOW_EXPERIENCES_STATES_SLOWED_DOWN: 'CommonBuffId' = 245283 - SLOW_EXPERIENCES_STATE_1: 'CommonBuffId' = 394567 - SLOW_EXPERIENCES_SURGE_EMOTION_ANGRY: 'CommonBuffId' = 245682 - SLOW_EXPERIENCES_SURGE_EMOTION_BORED: 'CommonBuffId' = 245683 - SLOW_EXPERIENCES_SURGE_EMOTION_CONFIDENT: 'CommonBuffId' = 245692 - SLOW_EXPERIENCES_SURGE_EMOTION_DAZED: 'CommonBuffId' = 245693 - SLOW_EXPERIENCES_SURGE_EMOTION_EMBARRASSED: 'CommonBuffId' = 245694 - SLOW_EXPERIENCES_SURGE_EMOTION_ENERGIZED: 'CommonBuffId' = 245695 - SLOW_EXPERIENCES_SURGE_EMOTION_FLIRTY: 'CommonBuffId' = 245684 - SLOW_EXPERIENCES_SURGE_EMOTION_FOCUSED: 'CommonBuffId' = 245685 - SLOW_EXPERIENCES_SURGE_EMOTION_HAPPY: 'CommonBuffId' = 245686 - SLOW_EXPERIENCES_SURGE_EMOTION_INSPIRED: 'CommonBuffId' = 245687 - SLOW_EXPERIENCES_SURGE_EMOTION_PLAYFUL: 'CommonBuffId' = 245688 - SLOW_EXPERIENCES_SURGE_EMOTION_SAD: 'CommonBuffId' = 245689 - SLOW_EXPERIENCES_SURGE_EMOTION_STRESSED: 'CommonBuffId' = 245690 - SLOW_EXPERIENCES_SURGE_EMOTION_UNCOMFORTABLE: 'CommonBuffId' = 245691 - SMALL_SLEEP_DESIRE: 'CommonBuffId' = 8847 - SNOOPING_BLACKMAIL_GENERIC: 'CommonBuffId' = 344320 - SNOOPING_BLACKMAIL_PUBLIC_MENACE: 'CommonBuffId' = 344321 - SNOOPING_BREAKING_AND_ENTERING_OCCUPANT_RETURN_ROLE: 'CommonBuffId' = 346271 - SNOOPING_BREAKING_AND_ENTERING_PLAYER_ROLE: 'CommonBuffId' = 346269 - SNOOPING_CAUGHT: 'CommonBuffId' = 343928 - SNOOPING_CAUGHT_VISIBLE: 'CommonBuffId' = 344405 - SNOOPING_CONFRONTED_BRIBE_AVAILABLE: 'CommonBuffId' = 346581 - SNOOPING_COOLDOWN: 'CommonBuffId' = 344323 - SNOOPING_GETTING_SECRET_FAIL: 'CommonBuffId' = 343938 - SNOOPING_GETTING_SECRET_SUCCESS: 'CommonBuffId' = 343940 - SNOOPING_KEEP_SECRET: 'CommonBuffId' = 344322 - SNOOPING_NO_CATCHING: 'CommonBuffId' = 343723 - SNOOPING_SEEKER_OF_SECRETS_FELINE_JESTER: 'CommonBuffId' = 347867 - SNOOPING_SEEKER_OF_SECRETS_FELINE_MASTER: 'CommonBuffId' = 347866 - SNOOPING_SEEKER_OF_SECRETS_OBJECTIVE_TRACKER_SECRET: 'CommonBuffId' = 347171 - SNOOPING_SEEKER_OF_SECRETS_OBJECTIVE_TRACKER_TIGER_BADGE: 'CommonBuffId' = 351117 - SNOOPING_SEEKER_OF_SECRETS_ULTIMATE_FELINE_MASTER: 'CommonBuffId' = 355672 - SNOOPING_TRAIT_BUFF_MENACE_HIDDEN: 'CommonBuffId' = 350411 - SNOOPING_TRAIT_BUFF_SAFE_KEEPER_HIDDEN: 'CommonBuffId' = 350412 - SNORKEL_MASK_ADULT: 'CommonBuffId' = 206585 - SNORKEL_MASK_CHILD: 'CommonBuffId' = 208767 - SNORKEL_SCUBA_FREE_DIVING_FLIPPERS_ADULT: 'CommonBuffId' = 214156 - SNORKEL_SCUBA_FREE_DIVING_FLIPPERS_CHILD: 'CommonBuffId' = 214160 - SNORKEL_SCUBA_FREE_DIVING_VISIBLE_SEASHELL_FAIL: 'CommonBuffId' = 208601 - SNORKEL_SCUBA_FREE_DIVING_VISIBLE_TREASURE_FAIL: 'CommonBuffId' = 208616 - SNOWBOARDING_GAPERS_GONNA_TACO: 'CommonBuffId' = 247392 - SNOWBOARDING_HIDDEN_ASK_TO_BE_SNOW_BRO_COOLDOWN: 'CommonBuffId' = 246928 - SNOWBOARDING_HIDDEN_CHECK_CONDITIONS_COOLDOWN: 'CommonBuffId' = 253673 - SNOWBOARDING_HIDDEN_COACH_FAILURE: 'CommonBuffId' = 247404 - SNOWBOARDING_HIDDEN_COACH_SUCCESS: 'CommonBuffId' = 247402 - SNOWBOARDING_HIDDEN_ENDURE_THE_BURN: 'CommonBuffId' = 247279 - SNOWBOARDING_HIDDEN_GET_HYPED_COOLDOWN: 'CommonBuffId' = 246900 - SNOWBOARDING_HIDDEN_PROVIDE_TIPS_COOLDOWN: 'CommonBuffId' = 246860 - SNOWBOARDING_HIDDEN_STRETCH_IT_OUT_COOLDOWN: 'CommonBuffId' = 247259 - SNOWBOARDING_LEFT_HANGING: 'CommonBuffId' = 246959 - SNOWBOARDING_MOCKING_BACKFIRE: 'CommonBuffId' = 247423 - SNOWBOARDING_NOT_A_GROM: 'CommonBuffId' = 247396 - SNOWBOARDING_PREPARED_FOR_FROST: 'CommonBuffId' = 247588 - SNOWBOARDING_READY_FOR_THE_RUN: 'CommonBuffId' = 246901 - SNOWBOARDING_READY_FOR_THE_RUN_HIGH_WEIGHT: 'CommonBuffId' = 246902 - SNOWBOARDING_SKIER_BURN: 'CommonBuffId' = 247385 - SNOWBOARDING_SNOW_BRO_HIGH_FIVE: 'CommonBuffId' = 246958 - SNOWBOARDING_TEACHN_TO_STOMP: 'CommonBuffId' = 247391 - SNOWBOARDING_WASNT_PREPARED: 'CommonBuffId' = 247590 - SNOW_DRIFT_SHOVEL: 'CommonBuffId' = 183790 - SNOW_DRIFT_SUPPRESS_IDLES_WHEN_SHOVELING: 'CommonBuffId' = 256563 - SNOW_EFFECTS_DISCIPLINE: 'CommonBuffId' = 190696 - SNOW_EFFECTS_LET_IT_SNOW: 'CommonBuffId' = 181132 - SNOW_EFFECTS_SNOWING_NEGATIVE: 'CommonBuffId' = 181134 - SNOW_EFFECTS_SNOWING_POSITIVE: 'CommonBuffId' = 181133 - SNOW_EFFECTS_SNOW_FACED: 'CommonBuffId' = 181151 - SNOW_EFFECTS_SNOW_FUN_HAPPY: 'CommonBuffId' = 181145 - SNOW_EFFECTS_SNOW_FUN_PLAYFUL: 'CommonBuffId' = 181147 - SNOW_EFFECTS_SNOW_IDLE: 'CommonBuffId' = 181002 - SNOW_PAL_ADD_SNOW_MIXER: 'CommonBuffId' = 189580 - SNOW_PAL_BUILD_MIXER: 'CommonBuffId' = 189585 - SNOW_PAL_BUILD_SNOW_PAL: 'CommonBuffId' = 180543 - SNOW_PAL_DESTROYED_SNOW_PAL: 'CommonBuffId' = 189633 - SNOW_PAL_PICKED_SIM: 'CommonBuffId' = 183011 - SNOW_PAL_RUNNING_INTERACTION: 'CommonBuffId' = 188806 - SNOW_PAL_SNOW_DRIFT: 'CommonBuffId' = 183053 - SNOW_PAL_SNOW_DRIFT_BOOST: 'CommonBuffId' = 188953 - SNOW_PAL_TELL_STORY: 'CommonBuffId' = 180568 - SNOW_SPORTS_SLOPE_AUTONOMY: 'CommonBuffId' = 248984 - SNOW_SPORTS_SLOPE_DEBUG_FORCE_FAILURE_OUTCOME: 'CommonBuffId' = 251479 - SNOW_SPORTS_SLOPE_DEBUG_FORCE_SUCCESS_OUTCOME: 'CommonBuffId' = 251478 - SNOW_SPORTS_SLOPE_DEBUG_FORCE_X_EVENT_FAIL: 'CommonBuffId' = 252123 - SNOW_SPORTS_SLOPE_DEBUG_FORCE_X_EVENT_SUCCESS: 'CommonBuffId' = 252122 - SNOW_SPORTS_SLOPE_DID_CRASH: 'CommonBuffId' = 252248 - SNOW_SPORTS_SLOPE_ENERGIZED_CERTIFIED_RIPPER: 'CommonBuffId' = 246446 - SNOW_SPORTS_SLOPE_ENERGIZED_SHREDDIN_THE_GNAR: 'CommonBuffId' = 246447 - SNOW_SPORTS_SLOPE_ENERGIZED_SKI_ENTHUSIAST: 'CommonBuffId' = 246450 - SNOW_SPORTS_SLOPE_HAPPY_DONE_WITH_STEEZ: 'CommonBuffId' = 246452 - SNOW_SPORTS_SLOPE_HAPPY_EXCELLENT_TIME_SKIING: 'CommonBuffId' = 246454 - SNOW_SPORTS_SLOPE_HAPPY_FEEL_LIKE_A_KID: 'CommonBuffId' = 246540 - SNOW_SPORTS_SLOPE_HAPPY_FEEL_THE_RUSH: 'CommonBuffId' = 246453 - SNOW_SPORTS_SLOPE_HAPPY_GLOWING_WITH_GLEE: 'CommonBuffId' = 246455 - SNOW_SPORTS_SLOPE_HAPPY_MASTER_OF_SKIIING: 'CommonBuffId' = 246451 - SNOW_SPORTS_SLOPE_HAPPY_SNOWBOARD_ENTHUSIAST: 'CommonBuffId' = 246469 - SNOW_SPORTS_SLOPE_HIGH_INTENSITY: 'CommonBuffId' = 247310 - SNOW_SPORTS_SLOPE_IS_SLEDDING: 'CommonBuffId' = 255270 - SNOW_SPORTS_SLOPE_LOW_INTENSITY: 'CommonBuffId' = 247309 - SNOW_SPORTS_SLOPE_MED_INTENSITY: 'CommonBuffId' = 247311 - SNOW_SPORTS_SLOPE_RECENT_EXTREME_SUCCESS: 'CommonBuffId' = 252869 - SNOW_SPORTS_SLOPE_RECENT_INJURY: 'CommonBuffId' = 254353 - SNOW_SPORTS_SLOPE_RECENT_SKI_OR_SNOWBOARD: 'CommonBuffId' = 252515 - SNOW_SPORTS_SLOPE_REMOVE_TURNS: 'CommonBuffId' = 256535 - SNOW_SPORTS_SLOPE_RENTAL_GEAR: 'CommonBuffId' = 253784 - SNOW_SPORTS_SLOPE_SAD_BETTER_LUCK_NEXT_TIME: 'CommonBuffId' = 246456 - SNOW_SPORTS_SLOPE_SAD_GETTING_TOOOLD: 'CommonBuffId' = 246448 - SNOW_SPORTS_SLOPE_SAD_IT_WASNT_MY_DAY: 'CommonBuffId' = 246457 - SNOW_SPORTS_SLOPE_SAD_I_CAN_DO_BETTER: 'CommonBuffId' = 246460 - SNOW_SPORTS_SLOPE_SAD_NEED_MORE_PRACTICE: 'CommonBuffId' = 246444 - SNOW_SPORTS_SLOPE_SAD_NOT_AS_READY_AS_I_THOUGHT: 'CommonBuffId' = 246445 - SNOW_SPORTS_SLOPE_SAD_SO_MANY_BUMPS: 'CommonBuffId' = 246459 - SNOW_SPORTS_SLOPE_SAD_TOO_MUCH_SLOPE: 'CommonBuffId' = 246458 - SNOW_SPORTS_SLOPE_SAD_WHAT_AM_I_DOING_WRONG: 'CommonBuffId' = 246443 - SNOW_SPORTS_SLOPE_SAD_WHAT_A_BIFF: 'CommonBuffId' = 246442 - SNOW_SPORTS_SLOPE_SLOPE_SETTINGS_CLEAR_TIMER: 'CommonBuffId' = 251990 - SNOW_SPORTS_SLOPE_UNCOMFORTABLE_SORE_FEET: 'CommonBuffId' = 248083 - SNOW_SPORTS_SLOPE_WEARING_BOOTS_SKI: 'CommonBuffId' = 255259 - SNOW_SPORTS_SLOPE_WEARING_BOOTS_SNOWBOARD: 'CommonBuffId' = 255258 - SNOW_SPORTS_SLOPE_WEAR_BOOTS_SKI: 'CommonBuffId' = 254529 - SNOW_SPORTS_SLOPE_WEAR_BOOTS_SNOWBOARD: 'CommonBuffId' = 254528 - SOCCER_BALL_AUTONOMOUS: 'CommonBuffId' = 230107 - SOCCER_BALL_HIDDEN_BALL_BUFFS_0: 'CommonBuffId' = 224525 - SOCCER_BALL_HIDDEN_BALL_BUFFS_1: 'CommonBuffId' = 224526 - SOCCER_BALL_HIDDEN_BALL_BUFFS_2: 'CommonBuffId' = 224527 - SOCCER_BALL_HIDDEN_BALL_BUFFS_3: 'CommonBuffId' = 224528 - SOCCER_BALL_HIDDEN_BALL_BUFFS_4: 'CommonBuffId' = 228801 - SOCCER_BALL_HIDDEN_KICKING: 'CommonBuffId' = 224631 - SOCCER_BALL_HIDDEN_PICKED_ALREADY: 'CommonBuffId' = 229827 - SOCCER_BALL_MISSED_THE_KICK: 'CommonBuffId' = 224617 - SOCCER_BALL_NEW_RECORD: 'CommonBuffId' = 224619 - SOCCER_BALL_SOCCER_RAGE: 'CommonBuffId' = 224462 - SOCCER_BALL_SOCCER_SUCKAGE: 'CommonBuffId' = 224459 - SOCCER_BALL_WHO_AM_I: 'CommonBuffId' = 224618 - SOCIALS_OCTOBER_CHALLENGE_TREAT: 'CommonBuffId' = 126732 - SOCIALS_OCTOBER_CHALLENGE_TRICK: 'CommonBuffId' = 126731 - SOCIAL_MEDIA_APPLICATION_DISABLE: 'CommonBuffId' = 303000 - SOCIAL_MEDIA_DISABLE_AT_FAMILY_DINNER: 'CommonBuffId' = 292431 - SOCIAL_MEDIA_DISABLE_AT_LUNCH: 'CommonBuffId' = 285137 - SOCIAL_MEDIA_DISABLE_AT_PROM: 'CommonBuffId' = 285122 - SOCIAL_MEDIA_DISABLE_BACK_FROM_WORK: 'CommonBuffId' = 292432 - SOCIAL_MEDIA_DISABLE_BROWSING_THRIFT_STORE: 'CommonBuffId' = 285196 - SOCIAL_MEDIA_DISABLE_CAREER_DAY_FINISHED: 'CommonBuffId' = 285144 - SOCIAL_MEDIA_DISABLE_CHANGED_OUTFIT: 'CommonBuffId' = 292434 - SOCIAL_MEDIA_DISABLE_CHEERLEADING_PRACTICE_FINISHED: 'CommonBuffId' = 285212 - SOCIAL_MEDIA_DISABLE_CHESS_PRACTICE_FINISHED: 'CommonBuffId' = 285213 - SOCIAL_MEDIA_DISABLE_COMPUTER_LAB_PRACTICE_FINISHED: 'CommonBuffId' = 285216 - SOCIAL_MEDIA_DISABLE_CRIED_IN_LOCKER: 'CommonBuffId' = 285155 - SOCIAL_MEDIA_DISABLE_DEATH_STINK_CAPSULE: 'CommonBuffId' = 285204 - SOCIAL_MEDIA_DISABLE_DEATH_URBAN_MYTH: 'CommonBuffId' = 285201 - SOCIAL_MEDIA_DISABLE_DETENTION_FINISHED: 'CommonBuffId' = 285139 - SOCIAL_MEDIA_DISABLE_DRINKING_BUBBLE_TEA: 'CommonBuffId' = 285184 - SOCIAL_MEDIA_DISABLE_DROPPED_OUT: 'CommonBuffId' = 285225 - SOCIAL_MEDIA_DISABLE_EATING_CAFETERIA_FOOD: 'CommonBuffId' = 285181 - SOCIAL_MEDIA_DISABLE_FINALS_FINISHED: 'CommonBuffId' = 285135 - SOCIAL_MEDIA_DISABLE_FIRE_DRILL_FINISHED: 'CommonBuffId' = 285146 - SOCIAL_MEDIA_DISABLE_FOOTBALL_PRACTICE_FINISHED: 'CommonBuffId' = 285209 - SOCIAL_MEDIA_DISABLE_GOING_ON_VACATION: 'CommonBuffId' = 292435 - SOCIAL_MEDIA_DISABLE_GOT_ENGAGED: 'CommonBuffId' = 292439 - SOCIAL_MEDIA_DISABLE_GOT_MARRIED: 'CommonBuffId' = 292440 - SOCIAL_MEDIA_DISABLE_GRADUATED: 'CommonBuffId' = 285128 - SOCIAL_MEDIA_DISABLE_HID_IN_LOCKER: 'CommonBuffId' = 285157 - SOCIAL_MEDIA_DISABLE_HOMEWORK_FINISHED: 'CommonBuffId' = 285228 - SOCIAL_MEDIA_DISABLE_HOSTING_PARTY: 'CommonBuffId' = 292441 - SOCIAL_MEDIA_DISABLE_JOINED_CLUB: 'CommonBuffId' = 285208 - SOCIAL_MEDIA_DISABLE_NEW_BABY: 'CommonBuffId' = 292442 - SOCIAL_MEDIA_DISABLE_ORIENTATION_FINISHED: 'CommonBuffId' = 285131 - SOCIAL_MEDIA_DISABLE_PASSION_EXCELLENCE: 'CommonBuffId' = 285193 - SOCIAL_MEDIA_DISABLE_PASSION_FASHION: 'CommonBuffId' = 285189 - SOCIAL_MEDIA_DISABLE_PASSION_PARTY: 'CommonBuffId' = 285192 - SOCIAL_MEDIA_DISABLE_PHOTO_BOOTH_PHOTO: 'CommonBuffId' = 285176 - SOCIAL_MEDIA_DISABLE_PHOTO_BOOTH_ROMANCE: 'CommonBuffId' = 285177 - SOCIAL_MEDIA_DISABLE_PILLOW_FIGHT: 'CommonBuffId' = 285089 - SOCIAL_MEDIA_DISABLE_PRANKED: 'CommonBuffId' = 285205 - SOCIAL_MEDIA_DISABLE_PREPARE_PROM: 'CommonBuffId' = 285118 - SOCIAL_MEDIA_DISABLE_PROMOTE_FASHION: 'CommonBuffId' = 285117 - SOCIAL_MEDIA_DISABLE_PROMOTE_SIMSFLUENCER: 'CommonBuffId' = 285185 - SOCIAL_MEDIA_DISABLE_PROMOTE_VIDEO_GAME_STREAM: 'CommonBuffId' = 285188 - SOCIAL_MEDIA_DISABLE_PROM_JESTER: 'CommonBuffId' = 285127 - SOCIAL_MEDIA_DISABLE_PROM_ROYALTY: 'CommonBuffId' = 285124 - SOCIAL_MEDIA_DISABLE_RETURNED_FROM_TRAVEL: 'CommonBuffId' = 292443 - SOCIAL_MEDIA_DISABLE_REVIEWED_BOOK: 'CommonBuffId' = 292444 - SOCIAL_MEDIA_DISABLE_REVIEWED_MEDIA: 'CommonBuffId' = 292445 - SOCIAL_MEDIA_DISABLE_SAW_FIGHT: 'CommonBuffId' = 285141 - SOCIAL_MEDIA_DISABLE_SNEAKING_OUT: 'CommonBuffId' = 285160 - SOCIAL_MEDIA_DISABLE_SOCIALLY_AWKWARD: 'CommonBuffId' = 285180 - SOCIAL_MEDIA_DISABLE_WENT_LOITERING: 'CommonBuffId' = 285166 - SOCIAL_MEDIA_DISABLE_WENT_ON_SHOPPING_TRIP: 'CommonBuffId' = 292446 - SOCIAL_MEDIA_DISABLE_WENT_ON_VACATION: 'CommonBuffId' = 292447 - SOCIAL_MEDIA_DISABLE_WENT_TO_COLLEGE_PARTY: 'CommonBuffId' = 285162 - SOCIAL_MEDIA_DISABLE_WENT_TO_CONCERT: 'CommonBuffId' = 285168 - SOCIAL_MEDIA_DISABLE_WENT_TO_FOOTBALL_GAME: 'CommonBuffId' = 285171 - SOCIAL_MEDIA_DISABLE_WENT_TO_HANG_OUT: 'CommonBuffId' = 285163 - SOCIAL_MEDIA_DISABLE_WENT_TO_R_MOVIE: 'CommonBuffId' = 285170 - SOCIAL_MEDIA_DISABLE_WENT_TO_SLEEPOVER: 'CommonBuffId' = 285174 - SOCIAL_MEDIA_DISABLE_WITNESSED_DEATH: 'CommonBuffId' = 292448 - SOCIAL_MEDIA_ENABLE_AT_FAMILY_DINNER: 'CommonBuffId' = 292500 - SOCIAL_MEDIA_ENABLE_AT_LUNCH: 'CommonBuffId' = 285136 - SOCIAL_MEDIA_ENABLE_AT_PROM: 'CommonBuffId' = 285121 - SOCIAL_MEDIA_ENABLE_BACK_FROM_WORK: 'CommonBuffId' = 292501 - SOCIAL_MEDIA_ENABLE_BROWSING_THRIFT_STORE: 'CommonBuffId' = 285195 - SOCIAL_MEDIA_ENABLE_CAREER_DAY_FINISHED: 'CommonBuffId' = 285143 - SOCIAL_MEDIA_ENABLE_CHANGED_OUTFIT: 'CommonBuffId' = 292503 - SOCIAL_MEDIA_ENABLE_CHEERLEADING_PRACTICE_FINISHED: 'CommonBuffId' = 285211 - SOCIAL_MEDIA_ENABLE_CHESS_PRACTICE_FINISHED: 'CommonBuffId' = 285214 - SOCIAL_MEDIA_ENABLE_COMPUTER_LAB_PRACTICE_FINISHED: 'CommonBuffId' = 285215 - SOCIAL_MEDIA_ENABLE_CRIED_IN_LOCKER: 'CommonBuffId' = 285156 - SOCIAL_MEDIA_ENABLE_DEATH_STINK_CAPSULE: 'CommonBuffId' = 285203 - SOCIAL_MEDIA_ENABLE_DEATH_URBAN_MYTH: 'CommonBuffId' = 285202 - SOCIAL_MEDIA_ENABLE_DETENTION_FINISHED: 'CommonBuffId' = 285138 - SOCIAL_MEDIA_ENABLE_DRINKING_BUBBLE_TEA: 'CommonBuffId' = 285183 - SOCIAL_MEDIA_ENABLE_DROPPED_OUT: 'CommonBuffId' = 285226 - SOCIAL_MEDIA_ENABLE_EATING_CAFETERIA_FOOD: 'CommonBuffId' = 285182 - SOCIAL_MEDIA_ENABLE_FINALS_FINISHED: 'CommonBuffId' = 285134 - SOCIAL_MEDIA_ENABLE_FIRE_DRILL_FINISHED: 'CommonBuffId' = 285145 - SOCIAL_MEDIA_ENABLE_FOOTBALL_PRACTICE_FINISHED: 'CommonBuffId' = 285210 - SOCIAL_MEDIA_ENABLE_GOING_ON_VACATION: 'CommonBuffId' = 292504 - SOCIAL_MEDIA_ENABLE_GOT_ENGAGED: 'CommonBuffId' = 292505 - SOCIAL_MEDIA_ENABLE_GOT_MARRIED: 'CommonBuffId' = 292506 - SOCIAL_MEDIA_ENABLE_GRADUATED: 'CommonBuffId' = 285129 - SOCIAL_MEDIA_ENABLE_HID_IN_LOCKER: 'CommonBuffId' = 285158 - SOCIAL_MEDIA_ENABLE_HOMEWORK_FINISHED: 'CommonBuffId' = 285227 - SOCIAL_MEDIA_ENABLE_HOSTING_PARTY: 'CommonBuffId' = 292507 - SOCIAL_MEDIA_ENABLE_JOINED_CLUB: 'CommonBuffId' = 285207 - SOCIAL_MEDIA_ENABLE_NEW_BABY: 'CommonBuffId' = 292508 - SOCIAL_MEDIA_ENABLE_ORIENTATION_FINISHED: 'CommonBuffId' = 285130 - SOCIAL_MEDIA_ENABLE_PASSION_EXCELLENCE: 'CommonBuffId' = 285194 - SOCIAL_MEDIA_ENABLE_PASSION_FASHION: 'CommonBuffId' = 285190 - SOCIAL_MEDIA_ENABLE_PASSION_PARTY: 'CommonBuffId' = 285191 - SOCIAL_MEDIA_ENABLE_PHOTO_BOOTH_PHOTO: 'CommonBuffId' = 285175 - SOCIAL_MEDIA_ENABLE_PHOTO_BOOTH_ROMANCE: 'CommonBuffId' = 285178 - SOCIAL_MEDIA_ENABLE_PILLOW_FIGHT: 'CommonBuffId' = 284506 - SOCIAL_MEDIA_ENABLE_PRANKED: 'CommonBuffId' = 285206 - SOCIAL_MEDIA_ENABLE_PREPARE_PROM: 'CommonBuffId' = 285119 - SOCIAL_MEDIA_ENABLE_PROMOTE_FASHION: 'CommonBuffId' = 285116 - SOCIAL_MEDIA_ENABLE_PROMOTE_SIMSFLUENCER: 'CommonBuffId' = 285186 - SOCIAL_MEDIA_ENABLE_PROMOTE_VIDEO_GAME_STREAM: 'CommonBuffId' = 285187 - SOCIAL_MEDIA_ENABLE_PROM_JESTER: 'CommonBuffId' = 285126 - SOCIAL_MEDIA_ENABLE_PROM_ROYALTY: 'CommonBuffId' = 285125 - SOCIAL_MEDIA_ENABLE_RETURNED_FROM_TRAVEL: 'CommonBuffId' = 292509 - SOCIAL_MEDIA_ENABLE_REVIEWED_BOOK: 'CommonBuffId' = 292510 - SOCIAL_MEDIA_ENABLE_REVIEWED_MEDIA: 'CommonBuffId' = 292511 - SOCIAL_MEDIA_ENABLE_SAW_FIGHT: 'CommonBuffId' = 285140 - SOCIAL_MEDIA_ENABLE_SNEAKING_OUT: 'CommonBuffId' = 285159 - SOCIAL_MEDIA_ENABLE_SOCIALLY_AWKWARD: 'CommonBuffId' = 285179 - SOCIAL_MEDIA_ENABLE_WENT_LOITERING: 'CommonBuffId' = 285165 - SOCIAL_MEDIA_ENABLE_WENT_ON_SHOPPING_TRIP: 'CommonBuffId' = 292512 - SOCIAL_MEDIA_ENABLE_WENT_ON_VACATION: 'CommonBuffId' = 292513 - SOCIAL_MEDIA_ENABLE_WENT_TO_COLLEGE_PARTY: 'CommonBuffId' = 285161 - SOCIAL_MEDIA_ENABLE_WENT_TO_CONCERT: 'CommonBuffId' = 285167 - SOCIAL_MEDIA_ENABLE_WENT_TO_FOOTBALL_GAME: 'CommonBuffId' = 285172 - SOCIAL_MEDIA_ENABLE_WENT_TO_HANG_OUT: 'CommonBuffId' = 285164 - SOCIAL_MEDIA_ENABLE_WENT_TO_R_MOVIE: 'CommonBuffId' = 285169 - SOCIAL_MEDIA_ENABLE_WENT_TO_SLEEPOVER: 'CommonBuffId' = 285173 - SOCIAL_MEDIA_ENABLE_WITNESSED_DEATH: 'CommonBuffId' = 292514 - SOCIAL_MEDIA_MOODLETS_ANGRY: 'CommonBuffId' = 283564 - SOCIAL_MEDIA_MOODLETS_CONFIDENT: 'CommonBuffId' = 283565 - SOCIAL_MEDIA_MOODLETS_EMBARRASSED: 'CommonBuffId' = 283566 - SOCIAL_MEDIA_MOODLETS_ENERGIZED: 'CommonBuffId' = 283567 - SOCIAL_MEDIA_MOODLETS_FLIRTY: 'CommonBuffId' = 283568 - SOCIAL_MEDIA_MOODLETS_HAPPY: 'CommonBuffId' = 283569 - SOCIAL_MEDIA_MOODLETS_SAD: 'CommonBuffId' = 283570 - SOCIAL_MEDIA_MOODLETS_STRESSED: 'CommonBuffId' = 283571 - SOCIAL_MEDIA_MOODLETS_SUPERIOR_ANGRY: 'CommonBuffId' = 283589 - SOCIAL_MEDIA_MOODLETS_SUPERIOR_CONFIDENT: 'CommonBuffId' = 283590 - SOCIAL_MEDIA_MOODLETS_SUPERIOR_EMBARRASSED: 'CommonBuffId' = 283591 - SOCIAL_MEDIA_MOODLETS_SUPERIOR_ENERGIZED: 'CommonBuffId' = 283592 - SOCIAL_MEDIA_MOODLETS_SUPERIOR_FLIRTY: 'CommonBuffId' = 283593 - SOCIAL_MEDIA_MOODLETS_SUPERIOR_HAPPY: 'CommonBuffId' = 283594 - SOCIAL_MEDIA_MOODLETS_SUPERIOR_SAD: 'CommonBuffId' = 283595 - SOCIAL_MEDIA_MOODLETS_SUPERIOR_STRESSED: 'CommonBuffId' = 283596 - SOCIAL_MEDIA_MOODLETS_SUPERIOR_UNCOMFORTABLE: 'CommonBuffId' = 285781 - SOCIAL_MEDIA_MOODLETS_UNCOMFORTABLE: 'CommonBuffId' = 285779 - SOCIAL_MEDIA_PANEL_ACTIVE: 'CommonBuffId' = 303905 - SOCIAL_MEDIA_POST_LESS_OFTEN: 'CommonBuffId' = 277258 - SOCIAL_MEDIA_POST_MORE_OFTEN: 'CommonBuffId' = 277252 - SOCIAL_MEDIA_SUPPRESS_TNS: 'CommonBuffId' = 298267 - SOCIAL_MEDIA_TALKED_ABOUT_MOODLETS_HIDDEN_NPC: 'CommonBuffId' = 283612 - SOCIAL_NETWORK_SOCIAL_MEDIA_FATIGUE: 'CommonBuffId' = 200267 - SOCIAL_SHOW_FLASH_CARDS_TODDLER_BOREDOM_ANGRY: 'CommonBuffId' = 143382 - SOCIAL_SHOW_FLASH_CARDS_TODDLER_BOREDOM_SAD: 'CommonBuffId' = 143383 - SOCIAL_SHOW_FLASH_CARDS_TODDLER_ENJOYING: 'CommonBuffId' = 146468 - SOCIAL_SHOW_FLASH_CARDS_TODDLER_GUESS_RIGHT: 'CommonBuffId' = 143277 - SOCIAL_SHOW_FLASH_CARDS_TODDLER_GUESS_WRONG: 'CommonBuffId' = 143278 - SOCIAL_SHOW_FLASH_CARDS_TODDLER_HOLDING_CARD: 'CommonBuffId' = 143275 - SOLAR_PANEL_TESTED_SELF_CLEAN_FAIL: 'CommonBuffId' = 238090 - SOLAR_PANEL_TESTED_SELF_CLEAN_SUCCESS: 'CommonBuffId' = 238089 - SPARKED_BY_CLOUDS: 'CommonBuffId' = 105319 - SPECIAL_MOMENTS_HAD_WOOHOO_MARRIED_ON_VACATION_HIDDEN: 'CommonBuffId' = 280580 - SPELLS_CASTING_SPELL_OBJECT_CLEAN: 'CommonBuffId' = 216176 - SPELLS_CASTING_SPELL_OBJECT_DUPLICATE: 'CommonBuffId' = 216177 - SPELLS_CASTING_SPELL_OBJECT_FIRE: 'CommonBuffId' = 216180 - SPELLS_CASTING_SPELL_OBJECT_LIGHTNING: 'CommonBuffId' = 216178 - SPELLS_CASTING_SPELL_OBJECT_REPAIR: 'CommonBuffId' = 216179 - SPELLS_CASTING_SPELL_SELF_CLONE: 'CommonBuffId' = 216201 - SPELLS_CASTING_SPELL_SIM_CHANGE_SIM_APPEARANCE: 'CommonBuffId' = 216203 - SPELLS_CASTING_SPELL_SIM_CONFUSE: 'CommonBuffId' = 216202 - SPELLS_CASTING_SPELL_SIM_FIRE: 'CommonBuffId' = 216200 - SPELLS_CASTING_SPELL_SIM_FREEZE: 'CommonBuffId' = 216199 - SPELLS_CASTING_SPELL_SIM_LIGHTNING: 'CommonBuffId' = 216197 - SPELLS_CASTING_SPELL_SIM_SADNESS: 'CommonBuffId' = 216196 - SPELLS_CASTING_SPELL_SIM_TRANSFORM: 'CommonBuffId' = 216198 - SPELLS_CASTING_SPELL_TERRAIN_CONJURE_FOOD: 'CommonBuffId' = 216259 - SPELLS_CASTING_SPELL_TERRAIN_SPAWN_PLANT: 'CommonBuffId' = 216261 - SPELLS_CASTING_SPELL_TERRAIN_TELEPORT: 'CommonBuffId' = 216260 - SPELLS_CAST_FIRE_NOPANIC: 'CommonBuffId' = 218910 - SPELLS_CLONE_BREAK_OBJECT_COOLDOWN: 'CommonBuffId' = 216326 - SPELLS_CLONE_CLEAN: 'CommonBuffId' = 215945 - SPELLS_CLONE_COOK: 'CommonBuffId' = 215974 - SPELLS_CLONE_FAIL_EVIL: 'CommonBuffId' = 216117 - SPELLS_CLONE_FIGHT_AUTONOMOUS_COOLDOWN: 'CommonBuffId' = 216325 - SPELLS_CLONE_MEAN_INT_COOLDOWN: 'CommonBuffId' = 216299 - SPELLS_CLONE_SUCCESS: 'CommonBuffId' = 215997 - SPELLS_DEBUG_OUTCOME_CHANCE_FAIL: 'CommonBuffId' = 216648 - SPELLS_DEBUG_OUTCOME_CHANCE_SUCCEED: 'CommonBuffId' = 216647 - SPELLS_FIGHT: 'CommonBuffId' = 215368 - SPELLS_FIRE: 'CommonBuffId' = 217264 - SPELLS_FREEZE_CHILLED: 'CommonBuffId' = 222804 - SPELLS_FROZEN: 'CommonBuffId' = 215498 - SPELLS_FROZEN_CHARGED: 'CommonBuffId' = 215587 - SPELLS_FROZEN_FAIL: 'CommonBuffId' = 221541 - SPELLS_FROZEN_FAIL_VISIBLE: 'CommonBuffId' = 222830 - SPELLS_LIGHTNING: 'CommonBuffId' = 217239 - SPELLS_LOVE: 'CommonBuffId' = 215401 - SPELLS_MIND_CONTROL_CONTROLLED_AI: 'CommonBuffId' = 216139 - SPELLS_MIND_CONTROL_CONTROLLED_AI_LONG_DURATION: 'CommonBuffId' = 216142 - SPELLS_PRACTICE_SPELLCASTING_LEARNED_SPELL: 'CommonBuffId' = 215007 - SPELLS_REACTION_COOLDOWN: 'CommonBuffId' = 214902 - SPELLS_REMOVE_CURSE_COOLDOWN: 'CommonBuffId' = 215991 - SPELLS_REMOVE_CURSE_COOLDOWN_SHORT: 'CommonBuffId' = 215992 - SPELLS_SEARCH_FOR_TOMES_COOLDOWN: 'CommonBuffId' = 216294 - SPELLS_SEARCH_FOR_TOMES_REMOVE_COUNTER: 'CommonBuffId' = 217669 - SPELLS_SIM_CLEAN_SLOW_HYGIENE_DECAY: 'CommonBuffId' = 215618 - SPELLS_SIM_CONFUSE_BE_CONFUSED: 'CommonBuffId' = 213320 - SPELLS_SIM_CONFUSE_BE_CONFUSED_CHARGED: 'CommonBuffId' = 213323 - SPELLS_SIM_GET_TRANSFORMED_IN_TO_OBJECT: 'CommonBuffId' = 213741 - SPELLS_SIM_GET_TRANSFORMED_IN_TO_OBJECT_LONG: 'CommonBuffId' = 221277 - SPELLS_SIM_RESURRECT: 'CommonBuffId' = 213595 - SPELLS_SIM_RESURRECT_CHARGED: 'CommonBuffId' = 213596 - SPELLS_SIM_RESURRECT_FAIL: 'CommonBuffId' = 213611 - SPELLS_SIM_SADNESS_BE_SAD: 'CommonBuffId' = 213372 - SPELLS_SIM_SADNESS_BE_SAD_CHARGED: 'CommonBuffId' = 213374 - SPELLS_STEAL_CAUGHT_STEALING: 'CommonBuffId' = 218608 - SPELLS_STEAL_SUCCESS: 'CommonBuffId' = 218602 - SPELLS_STEAL_WITNESS_STEALING: 'CommonBuffId' = 218605 - SPELLS_TEACH_SPELL_COOLDOWN_CATEGORY_MISCHIEF: 'CommonBuffId' = 213677 - SPELLS_TEACH_SPELL_COOLDOWN_CATEGORY_PRACTICAL: 'CommonBuffId' = 213681 - SPELLS_TEACH_SPELL_COOLDOWN_CATEGORY_UNTAMED: 'CommonBuffId' = 213682 - SPELL_REPULSIVENESS: 'CommonBuffId' = 216514 - SPELL_REPULSIVENESS_CHARGED: 'CommonBuffId' = 216521 - SPINE_TINGLING_THRILL: 'CommonBuffId' = 108014 - SPINE_TINGLING_THRILL_GREAT_STORYTELLER: 'CommonBuffId' = 109747 - SPIRIT_HOUSE_SOOTHING_SMELL: 'CommonBuffId' = 350193 - SPLASH_COOLDOWN: 'CommonBuffId' = 215761 - SPLASH_PAD_ANGRY_STOMP: 'CommonBuffId' = 304326 - SPLASH_PAD_COLD_WEATHER: 'CommonBuffId' = 304328 - SPLASH_PAD_RAINY: 'CommonBuffId' = 304327 - SPLASH_PAD_SHENANIGANS: 'CommonBuffId' = 304323 - SPLASH_PAD_STATISTIC: 'CommonBuffId' = 311089 - SPLASH_PAD_STOMPED: 'CommonBuffId' = 304325 - SPLASH_PAD_WATER_WET: 'CommonBuffId' = 304324 - SPLASH_WATER_IN_EYE: 'CommonBuffId' = 105900 - SPORE_HALLWAY_CONNECTIVITY: 'CommonBuffId' = 204775 - SPORTS_ARENA_LOSS_RIVAL_SCHOOL: 'CommonBuffId' = 222429 - SPORTS_ARENA_LOSS_RIVAL_SCHOOL_HOTHEADED: 'CommonBuffId' = 222432 - SPORTS_ARENA_NO_SCHOOL_SAW_A_GREAT_GAME: 'CommonBuffId' = 228163 - SPORTS_ARENA_WINNER_MY_SCHOOL: 'CommonBuffId' = 222427 - SPORTS_ARENA_WINNER_MY_SCHOOL_ACTIVE_TRAIT: 'CommonBuffId' = 222430 - SPRING_CHALLENGE_2016_GIVE_PRISTINE_GROWFRUIT: 'CommonBuffId' = 135591 - SPRING_CHALLENGE_2016_GIVE_X_GROWFRUIT: 'CommonBuffId' = 135429 - SPRING_CHALLENGE_PLANT_SIMS_NPC_ANGRY: 'CommonBuffId' = 163064 - SPRING_CHALLENGE_PLANT_SIMS_NPC_BEANS_GIVEN: 'CommonBuffId' = 163053 - SPRING_CHALLENGE_PLANT_SIMS_NPC_CONFIDENT: 'CommonBuffId' = 163066 - SPRING_CHALLENGE_PLANT_SIMS_NPC_FLIRTY: 'CommonBuffId' = 163067 - SPRING_CHALLENGE_PLANT_SIMS_NPC_PLAYFUL: 'CommonBuffId' = 163069 - SPRING_CHALLENGE_PLANT_SIMS_NPC_ROLE: 'CommonBuffId' = 163061 - SPRING_CHALLENGE_PLANT_SIMS_NPC_SAD: 'CommonBuffId' = 163065 - SPRING_CHALLENGE_PLANT_SIMS_NPC_UNCOMFORTABLE: 'CommonBuffId' = 163068 - SPRINKLER_PLAYED_IN: 'CommonBuffId' = 185928 - SPRINKLER_WET_FX_ADULT: 'CommonBuffId' = 189638 - SPRINKLER_WET_FX_CHILD: 'CommonBuffId' = 189656 - SPRINKLER_WET_FX_TODDLER: 'CommonBuffId' = 189772 - SQUAT_TOILET_ENERGIZED: 'CommonBuffId' = 351054 - SQUAT_TOILET_EXHAUSTED: 'CommonBuffId' = 351106 - STAGE_SOUND_TURN_OFF: 'CommonBuffId' = 198940 - STARTLED_BY_GHOST_TENSE: 'CommonBuffId' = 102401 - STOP_FLOATING: 'CommonBuffId' = 119855 - STORY_PROGRESSION_NEIGHBORHOOD_STORIES_RELATIONSHIP_UPDATES_NEIGHBOR_BECOMING_BEST_FRIENDS: 'CommonBuffId' = 381993 - STORY_PROGRESSION_NEIGHBORHOOD_STORIES_RELATIONSHIP_UPDATES_NEIGHBOR_BECOMING_DESPISED: 'CommonBuffId' = 381994 - STORY_PROGRESSION_NEIGHBORHOOD_STORIES_RELATIONSHIP_UPDATES_NEIGHBOR_BECOMING_FRIENDS: 'CommonBuffId' = 381926 - STORY_PROGRESSION_NEIGHBORHOOD_STORIES_RELATIONSHIP_UPDATES_NEIGHBOR_ROMANCE_RELATIONSHIP_END: 'CommonBuffId' = 381997 - STORY_PROGRESSION_NEIGHBORHOOD_STORIES_RELATIONSHIP_UPDATES_NEIGHBOR_ROMANCE_RELATIONSHIP_RESTART: 'CommonBuffId' = 381996 - STORY_PROGRESSION_NEIGHBORHOOD_STORIES_RELATIONSHIP_UPDATES_NEIGHBOR_ROMANCE_RELATIONSHIP_START: 'CommonBuffId' = 381995 - STRANGELY_CALMING_SCENT: 'CommonBuffId' = 118499 - STRAYS_HAS_EXPLORED_BUSH: 'CommonBuffId' = 175441 - STRAYS_HAS_EXPLORED_DIRT_MOUND: 'CommonBuffId' = 175444 - STRAYS_HAS_EXPLORED_FISH_PILE: 'CommonBuffId' = 175442 - STRAYS_HAS_EXPLORED_SEAWEED_PILE: 'CommonBuffId' = 175443 - STREAKER_REACTION_HIDDEN: 'CommonBuffId' = 100091 - STREAK_ENERGIZED: 'CommonBuffId' = 99588 - STREAMING_DRONE_HAPPY_STREAMING: 'CommonBuffId' = 200190 - STREAMING_DRONE_SAD_BROKEN: 'CommonBuffId' = 200192 - STREAMING_DRONE_STREAMING: 'CommonBuffId' = 193298 - STREET_BUSKER_ACTIVE_HIDDEN: 'CommonBuffId' = 140750 - STUDENT_COMMONS_ARTS_POETRY_PRESENTED_POETRY: 'CommonBuffId' = 221910 - STUDENT_COMMONS_ARTS_POETRY_READING: 'CommonBuffId' = 221765 - STUDENT_COMMONS_ARTS_POETRY_TEA_SERVING: 'CommonBuffId' = 221843 - STUDENT_COMMONS_ARTS_POETRY_WAITING: 'CommonBuffId' = 221842 - STUDENT_COMMONS_EXAM_CRAM_LAST_CHANCE_TO_STUDY: 'CommonBuffId' = 222223 - STUDENT_COMMONS_MIXER_JUICE_KEG_BEARER_ARRIVE: 'CommonBuffId' = 222117 - STUDENT_COMMONS_MIXER_PARTY: 'CommonBuffId' = 222166 - STUDENT_COMMONS_POETRY_TEA_SERVE_COOLDOWN: 'CommonBuffId' = 229861 - STUDENT_COMMONS_PROFESSOR_GOOD: 'CommonBuffId' = 222365 - STUDENT_COMMONS_PROFESSOR_GRUMPY: 'CommonBuffId' = 222362 - STUDENT_COMMONS_PROFESSOR_HIP: 'CommonBuffId' = 222363 - STUDENT_COMMONS_SCIENCE_E_SPORTS_EVENT_PARTICIPATING: 'CommonBuffId' = 221970 - STUDENT_COMMONS_SCIENCE_E_SPORTS_POWER_SIP_COOLDOWN: 'CommonBuffId' = 222312 - STUFFED_ANIMAL_INSPIRED: 'CommonBuffId' = 25068 - STUFFED_ANIMAL_TODDLER_TALK_BABBLE_COOLDOWN: 'CommonBuffId' = 328272 - STYLEBOARD_FIND_MUSE_MOOD_HIGH_CONFIDENT: 'CommonBuffId' = 198545 - STYLEBOARD_FIND_MUSE_MOOD_HIGH_ENERGIZED: 'CommonBuffId' = 198546 - STYLEBOARD_FIND_MUSE_MOOD_HIGH_FLIRTY: 'CommonBuffId' = 198548 - STYLEBOARD_FIND_MUSE_MOOD_HIGH_INSPIRED: 'CommonBuffId' = 198551 - STYLEBOARD_FIND_MUSE_MOOD_LOW_CONFIDENT: 'CommonBuffId' = 198538 - STYLEBOARD_FIND_MUSE_MOOD_LOW_ENERGIZED: 'CommonBuffId' = 198547 - STYLEBOARD_FIND_MUSE_MOOD_LOW_FLIRTY: 'CommonBuffId' = 198549 - STYLEBOARD_FIND_MUSE_MOOD_LOW_INSPIRED: 'CommonBuffId' = 198550 - STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_ATHLETIC_CONFIDENT: 'CommonBuffId' = 198311 - STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_ATHLETIC_ENERGIZED: 'CommonBuffId' = 198313 - STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_ATHLETIC_FLIRTY: 'CommonBuffId' = 198314 - STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_ATHLETIC_INSPIRED: 'CommonBuffId' = 198312 - STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_CAREER_CONFIDENT: 'CommonBuffId' = 198347 - STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_CAREER_ENERGIZED: 'CommonBuffId' = 198353 - STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_CAREER_FLIRTY: 'CommonBuffId' = 198359 - STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_CAREER_INSPIRED: 'CommonBuffId' = 198365 - STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_EVERYDAY_CONFIDENT: 'CommonBuffId' = 198348 - STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_EVERYDAY_ENERGIZED: 'CommonBuffId' = 198354 - STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_EVERYDAY_FLIRTY: 'CommonBuffId' = 198360 - STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_EVERYDAY_INSPIRED: 'CommonBuffId' = 198366 - STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_FORMAL_CONFIDENT: 'CommonBuffId' = 198352 - STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_FORMAL_ENERGIZED: 'CommonBuffId' = 198355 - STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_FORMAL_FLIRTY: 'CommonBuffId' = 198361 - STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_FORMAL_INSPIRED: 'CommonBuffId' = 198367 - STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_PARTY_CONFIDENT: 'CommonBuffId' = 198351 - STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_PARTY_ENERGIZED: 'CommonBuffId' = 198358 - STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_PARTY_FLIRTY: 'CommonBuffId' = 198364 - STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_PARTY_INSPIRED: 'CommonBuffId' = 198368 - STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_SLEEP_CONFIDENT: 'CommonBuffId' = 198350 - STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_SLEEP_ENERGIZED: 'CommonBuffId' = 198357 - STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_SLEEP_FLIRTY: 'CommonBuffId' = 198363 - STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_SLEEP_INSPIRED: 'CommonBuffId' = 198369 - STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_SWIMWEAR_CONFIDENT: 'CommonBuffId' = 198349 - STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_SWIMWEAR_ENERGIZED: 'CommonBuffId' = 198356 - STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_SWIMWEAR_FLIRTY: 'CommonBuffId' = 198362 - STYLEBOARD_INFUSED_OUTFIT_CONTROLLER_SWIMWEAR_INSPIRED: 'CommonBuffId' = 198370 - STYLEBOARD_INFUSED_OUTFIT_MOOD_CONFIDENT: 'CommonBuffId' = 198489 - STYLEBOARD_INFUSED_OUTFIT_MOOD_ENERGIZED: 'CommonBuffId' = 198492 - STYLEBOARD_INFUSED_OUTFIT_MOOD_FLIRTY: 'CommonBuffId' = 198491 - STYLEBOARD_INFUSED_OUTFIT_MOOD_INSPIRED: 'CommonBuffId' = 198490 - STYLEBOARD_INFUSED_OUTFIT_TRIGGER_ATHLETIC_CONFIDENT: 'CommonBuffId' = 198324 - STYLEBOARD_INFUSED_OUTFIT_TRIGGER_ATHLETIC_ENERGIZED: 'CommonBuffId' = 198321 - STYLEBOARD_INFUSED_OUTFIT_TRIGGER_ATHLETIC_FLIRTY: 'CommonBuffId' = 198322 - STYLEBOARD_INFUSED_OUTFIT_TRIGGER_ATHLETIC_INSPIRED: 'CommonBuffId' = 198323 - STYLEBOARD_INFUSED_OUTFIT_TRIGGER_CAREER_CONFIDENT: 'CommonBuffId' = 198320 - STYLEBOARD_INFUSED_OUTFIT_TRIGGER_CAREER_ENERGIZED: 'CommonBuffId' = 198319 - STYLEBOARD_INFUSED_OUTFIT_TRIGGER_CAREER_FLIRTY: 'CommonBuffId' = 198318 - STYLEBOARD_INFUSED_OUTFIT_TRIGGER_CAREER_INSPIRED: 'CommonBuffId' = 198342 - STYLEBOARD_INFUSED_OUTFIT_TRIGGER_EVERYDAY_CONFIDENT: 'CommonBuffId' = 198341 - STYLEBOARD_INFUSED_OUTFIT_TRIGGER_EVERYDAY_ENERGIZED: 'CommonBuffId' = 198340 - STYLEBOARD_INFUSED_OUTFIT_TRIGGER_EVERYDAY_FLIRTY: 'CommonBuffId' = 198339 - STYLEBOARD_INFUSED_OUTFIT_TRIGGER_EVERYDAY_INSPIRED: 'CommonBuffId' = 198338 - STYLEBOARD_INFUSED_OUTFIT_TRIGGER_FORMAL_CONFIDENT: 'CommonBuffId' = 198337 - STYLEBOARD_INFUSED_OUTFIT_TRIGGER_FORMAL_ENERGIZED: 'CommonBuffId' = 198336 - STYLEBOARD_INFUSED_OUTFIT_TRIGGER_FORMAL_FLIRTY: 'CommonBuffId' = 198335 - STYLEBOARD_INFUSED_OUTFIT_TRIGGER_FORMAL_INSPIRED: 'CommonBuffId' = 198317 - STYLEBOARD_INFUSED_OUTFIT_TRIGGER_PARTY_CONFIDENT: 'CommonBuffId' = 198334 - STYLEBOARD_INFUSED_OUTFIT_TRIGGER_PARTY_ENERGIZED: 'CommonBuffId' = 198333 - STYLEBOARD_INFUSED_OUTFIT_TRIGGER_PARTY_FLIRTY: 'CommonBuffId' = 198332 - STYLEBOARD_INFUSED_OUTFIT_TRIGGER_PARTY_INSPIRED: 'CommonBuffId' = 198331 - STYLEBOARD_INFUSED_OUTFIT_TRIGGER_SLEEP_CONFIDENT: 'CommonBuffId' = 198330 - STYLEBOARD_INFUSED_OUTFIT_TRIGGER_SLEEP_ENERGIZED: 'CommonBuffId' = 198329 - STYLEBOARD_INFUSED_OUTFIT_TRIGGER_SLEEP_FLIRTY: 'CommonBuffId' = 198328 - STYLEBOARD_INFUSED_OUTFIT_TRIGGER_SLEEP_INSPIRED: 'CommonBuffId' = 198327 - STYLEBOARD_INFUSED_OUTFIT_TRIGGER_SWIMWEAR_CONFIDENT: 'CommonBuffId' = 198326 - STYLEBOARD_INFUSED_OUTFIT_TRIGGER_SWIMWEAR_ENERGIZED: 'CommonBuffId' = 198325 - STYLEBOARD_INFUSED_OUTFIT_TRIGGER_SWIMWEAR_FLIRTY: 'CommonBuffId' = 198316 - STYLEBOARD_INFUSED_OUTFIT_TRIGGER_SWIMWEAR_INSPIRED: 'CommonBuffId' = 198315 - SUNLIGHT_REVERSAL_COCKTAIL_HIDDEN: 'CommonBuffId' = 156617 - SUN_TAN_APPLIED_SUN_BLOCK: 'CommonBuffId' = 208856 - SUN_TAN_BURNING: 'CommonBuffId' = 209552 - SUN_TAN_BURNT: 'CommonBuffId' = 208517 - SUN_TAN_CURRENTLY_SUNBATHING: 'CommonBuffId' = 200789 - SUN_TAN_LOCK_DECAY: 'CommonBuffId' = 206066 - SUN_TAN_PRANK: 'CommonBuffId' = 209805 - SUN_TAN_PRANKED_EMBARRASSED: 'CommonBuffId' = 209804 - SUN_TAN_PRANKED_SIM: 'CommonBuffId' = 209768 - SUN_TAN_STARTING_TO_BURN: 'CommonBuffId' = 211808 - SUN_TAN_TANNED: 'CommonBuffId' = 208515 - SUN_TAN_TANNING: 'CommonBuffId' = 209554 - SUN_TAN_VFX: 'CommonBuffId' = 211913 - SUPER_PARENT_ROLE_MODEL_LIFE_SKILL_GAIN: 'CommonBuffId' = 165200 - SUPPRESS_ALL_AUTONOMY: 'CommonBuffId' = 169901 - SUPPRESS_ALL_INTERACTION: 'CommonBuffId' = 24732 - SUPPRESS_BE_AFFECTIONATE_ALL: 'CommonBuffId' = 389298 - SUPPRESS_BE_AFFECTIONATE_AS_ACTOR: 'CommonBuffId' = 389294 - SUPPRESS_BE_AFFECTIONATE_AS_TARGET: 'CommonBuffId' = 389297 - SUPPRESS_EMOTION_IDLE: 'CommonBuffId' = 129126 - SUPPRESS_EMOTION_IDLE_10_MIN: 'CommonBuffId' = 394162 - SUPPRESS_FRONT_PAGE_PIE_MENU: 'CommonBuffId' = 115761 - SUPPRESS_FRONT_PAGE_PIE_MENU: 'CommonBuffId' = 121942 - SUPPRESS_HOUSE_INFECTION: 'CommonBuffId' = 203134 - SUPPRESS_HUNGER_AUTONOMY: 'CommonBuffId' = 354328 - SUPPRESS_IN_LABOR: 'CommonBuffId' = 256302 - SUPPRESS_LOVE_LETTER: 'CommonBuffId' = 100870 - SUPPRESS_REACTION_SMELLS_BAD: 'CommonBuffId' = 99740 - SUPPRESS_ROMANTIC_SOCIALS_ACTOR: 'CommonBuffId' = 383351 - SUPPRESS_ROMANTIC_SOCIALS_TARGET: 'CommonBuffId' = 383749 - SUPPRESS_SIM_CHAT_ALL: 'CommonBuffId' = 394424 - SUPPRESS_SIM_CHAT_AS_ACTOR: 'CommonBuffId' = 394422 - SUPPRESS_SIM_CHAT_AS_TARGET: 'CommonBuffId' = 394423 - SUPPRESS_SNOW_IDLE: 'CommonBuffId' = 190542 - SUPPRESS_SOCIALS_TARGETED_ACTOR: 'CommonBuffId' = 384533 - SUPPRESS_SOCIALS_TARGETED_TARGET: 'CommonBuffId' = 384534 - SUPPRESS_SOCIAL_PICKER_SI_ALL: 'CommonBuffId' = 388560 - SUPPRESS_SOCIAL_PICKER_SI_AS_ACTOR: 'CommonBuffId' = 388562 - SUPPRESS_SOCIAL_PICKER_SI_AS_TARGET: 'CommonBuffId' = 388564 - SUPPRESS_TEMPERATURE_IDLE: 'CommonBuffId' = 188623 - SUPPRESS_TRAIT_IDLE: 'CommonBuffId' = 334350 - SUPPRESS_VISIBLE_MOTIVES: 'CommonBuffId' = 27833 - SUPPRESS_VISIBLE_MOTIVES_EXCLUDE_ENERGY: 'CommonBuffId' = 243486 - SURPRISE_HOLIDAY_BATTLE_ROYALE_AUTONOMY: 'CommonBuffId' = 182289 - SURPRISE_HOLIDAY_DISCOUNT_DAY: 'CommonBuffId' = 182267 - SURPRISE_HOLIDAY_LOTTERY_AUTONOMY: 'CommonBuffId' = 184906 - SURPRISE_HOLIDAY_LOTTERY_COOLDOWN: 'CommonBuffId' = 181580 - SURPRISE_HOLIDAY_LOTTERY_INSPIRED: 'CommonBuffId' = 181582 - SURPRISE_HOLIDAY_LOTTERY_SAD_BUFF: 'CommonBuffId' = 181900 - SURPRISE_HOLIDAY_LOTTERY_WIN_BUFF: 'CommonBuffId' = 181905 - SURPRISE_HOLIDAY_NIGHT_ON_THE_TOWN: 'CommonBuffId' = 182263 - SURPRISE_HOLIDAY_PIRATE_DAY_AUTONOMY: 'CommonBuffId' = 182293 - SURPRISE_HOLIDAY_PRANK_DAY_AUTONOMY: 'CommonBuffId' = 182296 - SURPRISE_HOLIDAY_SKILL_DAY_CONFIDENT: 'CommonBuffId' = 186641 - SURPRISE_HOLIDAY_SKILL_DAY_INCREASE_SKILL_GAIN: 'CommonBuffId' = 182300 - SURPRISE_HOLIDAY_TV_PREMIERE: 'CommonBuffId' = 182304 - SURPRISE_HOLIDAY_TV_PREMIERE_HAPPY_BUFF: 'CommonBuffId' = 183430 - SURPRISE_HOLIDAY_TV_PREMIERE_SPOILED: 'CommonBuffId' = 183488 - SURPRISE_HOLIDAY_TV_PREMIERE_WATCHED_HIDDEN: 'CommonBuffId' = 183431 - SWEAR_COOLDOWN: 'CommonBuffId' = 167444 - TALES_OF_THE_DEAD: 'CommonBuffId' = 103142 - TALES_OF_THE_DEAD_GREAT_STORYTELLER: 'CommonBuffId' = 109749 - TANDEM_SLEDDER_SITUATION_LEADER: 'CommonBuffId' = 251682 - TEACH_TO_SAY_PLEASE_ANGRY_TODDLER: 'CommonBuffId' = 161225 - TEACH_TO_SAY_PLEASE_BORED_CHILD: 'CommonBuffId' = 161226 - TEACH_TO_SAY_PLEASE_CONFIDENT_CHILD: 'CommonBuffId' = 161223 - TEACH_TO_SAY_PLEASE_HAPPY_TODDLER: 'CommonBuffId' = 161222 - TEACH_TO_SAY_PLEASE_INSPIRED_CHILD: 'CommonBuffId' = 161224 - TEACH_TO_SAY_SORRY_CHILD_BORED: 'CommonBuffId' = 166782 - TEACH_TO_SAY_SORRY_CHILD_CONFIDENT: 'CommonBuffId' = 166784 - TEACH_TO_SAY_SORRY_CHILD_INSPIRED: 'CommonBuffId' = 166783 - TEACH_TO_SAY_SORRY_TODDLER_ANGRY: 'CommonBuffId' = 166780 - TEACH_TO_SAY_SORRY_TODDLER_HAPPY: 'CommonBuffId' = 166781 - TEA_SET_PRIM_AND_PROPER: 'CommonBuffId' = 278935 - TEA_SET_TRADITIONAL_TEA: 'CommonBuffId' = 278934 - TEA_UPGRADED: 'CommonBuffId' = 28947 - TEEN_ASPIRATIONS_SOCIAL_FOLLOWERS: 'CommonBuffId' = 287404 - TEEN_MOOD_SWING_ANGRY: 'CommonBuffId' = 162334 - TEEN_MOOD_SWING_EMBARRASSED: 'CommonBuffId' = 162337 - TEEN_MOOD_SWING_LOUD_MUSIC_REACTION: 'CommonBuffId' = 163399 - TEEN_MOOD_SWING_PUSH_MOOD_SWING_COOLDOWN: 'CommonBuffId' = 162346 - TEEN_MOOD_SWING_SAD: 'CommonBuffId' = 162336 - TEEN_MOOD_SWING_STRESSED: 'CommonBuffId' = 162335 - TEEN_RELATIONSHIP_DRAMA_CRUSH_ANGRY: 'CommonBuffId' = 289490 - TEEN_RELATIONSHIP_DRAMA_CRUSH_BROADCASTER_INVISIBLE: 'CommonBuffId' = 289554 - TEEN_RELATIONSHIP_DRAMA_CRUSH_IN_ROOM: 'CommonBuffId' = 289483 - TEEN_RELATIONSHIP_DRAMA_CRUSH_NEGATIVE_CHAT: 'CommonBuffId' = 289485 - TEEN_RELATIONSHIP_DRAMA_CRUSH_POSITIVE_CHAT: 'CommonBuffId' = 289484 - TEEN_RELATIONSHIP_DRAMA_CRUSH_REJECTED: 'CommonBuffId' = 289482 - TEEN_RELATIONSHIP_DRAMA_CRUSH_SWOONING: 'CommonBuffId' = 289487 - TEEN_RELATIONSHIP_DRAMA_CRUSH_TENSE_CHAT: 'CommonBuffId' = 289486 - TEEN_RELATIONSHIP_DRAMA_CRUSH_TEXTING: 'CommonBuffId' = 289481 - TEEN_RELATIONSHIP_DRAMA_REJECTED_FRIEND: 'CommonBuffId' = 297948 - TEMPERAMENT_ANTI_CAPITALIST_CANINE_WORK_IS_THE_POOP: 'CommonBuffId' = 290871 - TEMPERAMENT_BIG_BAD_WOLF_OVERWHELMING_AGGRESSION: 'CommonBuffId' = 290507 - TEMPERAMENT_CARNIVORE_NEED_REAL_MEAT: 'CommonBuffId' = 293836 - TEMPERAMENT_COOLDOWN_GOTTA_MARK_SOMETHING: 'CommonBuffId' = 297153 - TEMPERAMENT_COOLDOWN_NEED_HIBERNATE: 'CommonBuffId' = 297097 - TEMPERAMENT_COOLDOWN_NEED_LOVE: 'CommonBuffId' = 297098 - TEMPERAMENT_COOLDOWN_OVERWHELMING_AGGRESSION: 'CommonBuffId' = 297096 - TEMPERAMENT_COOLDOWN_SUDDEN_CRAVING: 'CommonBuffId' = 297094 - TEMPERAMENT_COOLDOWN_WALLS_CLOSING_IN: 'CommonBuffId' = 297095 - TEMPERAMENT_EASILY_EXCITABLE_SCREEN_TIME: 'CommonBuffId' = 293838 - TEMPERAMENT_FEELS_OUTCASTED_BOTTOM_OF_THE_PACK: 'CommonBuffId' = 294002 - TEMPERAMENT_FEELS_OUTCASTED_NOBODY_UNDERSTANDSME: 'CommonBuffId' = 294001 - TEMPERAMENT_FRISKY_NEED_LOVE: 'CommonBuffId' = 295326 - TEMPERAMENT_HIDDEN_ANTI_CAPITALIST_CANINE: 'CommonBuffId' = 290555 - TEMPERAMENT_HIDDEN_BIG_BAD_WOLF: 'CommonBuffId' = 290107 - TEMPERAMENT_HIDDEN_BOTTOM_OF_THE_PACK_COOLDOWN: 'CommonBuffId' = 298500 - TEMPERAMENT_HIDDEN_CARNIVORE: 'CommonBuffId' = 293834 - TEMPERAMENT_HIDDEN_EASY_EXCITABLE: 'CommonBuffId' = 293840 - TEMPERAMENT_HIDDEN_FEELS_OUTCASTED: 'CommonBuffId' = 294000 - TEMPERAMENT_HIDDEN_FEELS_OUTCASTED_TRAIT: 'CommonBuffId' = 294003 - TEMPERAMENT_HIDDEN_FRISKY: 'CommonBuffId' = 295380 - TEMPERAMENT_HIDDEN_GRUMPY_WOLF: 'CommonBuffId' = 290108 - TEMPERAMENT_HIDDEN_HUNGRY_LIKE_WOLF: 'CommonBuffId' = 294057 - TEMPERAMENT_HIDDEN_LUNAR_FOREST: 'CommonBuffId' = 294324 - TEMPERAMENT_HIDDEN_LUNAR_HUNT: 'CommonBuffId' = 294325 - TEMPERAMENT_HIDDEN_LUNAR_NIGHT: 'CommonBuffId' = 294323 - TEMPERAMENT_HIDDEN_LUNAR_WOLF: 'CommonBuffId' = 294322 - TEMPERAMENT_HIDDEN_PRIDEFUL: 'CommonBuffId' = 290003 - TEMPERAMENT_HIDDEN_RESTLESS_ANIMAL: 'CommonBuffId' = 290111 - TEMPERAMENT_HIDDEN_RESTLESS_ANIMAL_REMOVE: 'CommonBuffId' = 294127 - TEMPERAMENT_HIDDEN_SENSITIVE_HEARING: 'CommonBuffId' = 294511 - TEMPERAMENT_HIDDEN_SENSITIVE_HEARING_COOLDOWN: 'CommonBuffId' = 299674 - TEMPERAMENT_HIDDEN_SURVIVAL_INSTINCTS: 'CommonBuffId' = 290110 - TEMPERAMENT_HIDDEN_WRACKED_WITH_GUILT: 'CommonBuffId' = 290109 - TEMPERAMENT_IM_SO_CLEAN: 'CommonBuffId' = 293999 - TEMPERAMENT_LUNAR_TEMPERAMENT_GAIN: 'CommonBuffId' = 299766 - TEMPERAMENT_MUST_BE_CLEAN: 'CommonBuffId' = 293996 - TEMPERAMENT_NEED_HIBERNATE: 'CommonBuffId' = 294124 - TEMPERAMENT_NIGHT_WOLF_DAY_TIME: 'CommonBuffId' = 294327 - TEMPERAMENT_NIGHT_WOLF_DAY_TIME_WHILE_SLEEPING: 'CommonBuffId' = 294329 - TEMPERAMENT_PRIDEFUL_NARCISSIST: 'CommonBuffId' = 295383 - TEMPERAMENT_PRIDEFUL_WOUNDED_PRIDE: 'CommonBuffId' = 295382 - TEMPERAMENT_RESTLESS_ANIMAL_WALLS_CLOSING_IN: 'CommonBuffId' = 290448 - TEMPERAMENT_SENSITIVE_HEARING_LOUD_NOISES: 'CommonBuffId' = 294513 - TEMPERAMENT_SUDDEN_CRAVING: 'CommonBuffId' = 294061 - TEMPERAMENT_SURVIVAL_INSTINCTS_FIGHT_OR_FLIGHT: 'CommonBuffId' = 290510 - TEMPERAMENT_TERRITORIAL_GOTTA_MARK_NOW: 'CommonBuffId' = 297152 - TEMPERAMENT_TERRITORIAL_GOTTA_MARK_SOMETHING: 'CommonBuffId' = 293884 - TEMPERAMENT_TERRITORY_MARKED: 'CommonBuffId' = 293998 - TEMPERAMENT_WET_AND_HATE_IT: 'CommonBuffId' = 294129 - TEMPERAMENT_WET_AND_HATE_IT_WHILE_WET: 'CommonBuffId' = 294342 - TEMPERAMENT_WOLF_BRAIN_HEAD_HURT: 'CommonBuffId' = 294326 - TEMPERAMENT_WRACKED_WITH_GUILT_TRANSFORMATION: 'CommonBuffId' = 290508 - TEMPERAMENT_WRACKED_WITH_GUILT_WHAT_HAVE_I_BECOME: 'CommonBuffId' = 290509 - TEMPERATURE_CHILLED: 'CommonBuffId' = 180207 - TEMPERATURE_DISCOURAGE_OUTSIDE_INTERACTIONS_HIDDEN: 'CommonBuffId' = 186065 - TEMPERATURE_FORCE_COMFORTABLE: 'CommonBuffId' = 182899 - TEMPERATURE_FREEZING: 'CommonBuffId' = 180208 - TEMPERATURE_FREEZING_EXTREME: 'CommonBuffId' = 182205 - TEMPERATURE_GHOST_FREEZE: 'CommonBuffId' = 182891 - TEMPERATURE_GHOST_GHOST_CHILLED_HAPPY: 'CommonBuffId' = 184144 - TEMPERATURE_GHOST_GHOST_CHILLED_UNCOMFORTABLE: 'CommonBuffId' = 184145 - TEMPERATURE_GHOST_PLASMA_WARMED_HAPPY: 'CommonBuffId' = 184146 - TEMPERATURE_GHOST_PLASMA_WARMED_UNCOMFORTABLE: 'CommonBuffId' = 184147 - TEMPERATURE_HIDDEN_CHILLED: 'CommonBuffId' = 185937 - TEMPERATURE_HIDDEN_EXTREME_FREEZING: 'CommonBuffId' = 186001 - TEMPERATURE_HIDDEN_EXTREME_MELTING: 'CommonBuffId' = 186004 - TEMPERATURE_HIDDEN_FREEZING: 'CommonBuffId' = 186000 - TEMPERATURE_HIDDEN_MELTING: 'CommonBuffId' = 186003 - TEMPERATURE_HIDDEN_NEUTRAL: 'CommonBuffId' = 190849 - TEMPERATURE_HIDDEN_OVERHEATING: 'CommonBuffId' = 186002 - TEMPERATURE_HIDDEN_TROPICAL_WARMTH: 'CommonBuffId' = 211084 - TEMPERATURE_IMMUNE_TO_TEMPERATURE: 'CommonBuffId' = 185065 - TEMPERATURE_INFANT_COLD: 'CommonBuffId' = 314015 - TEMPERATURE_INFANT_HOT: 'CommonBuffId' = 314016 - TEMPERATURE_MELTING: 'CommonBuffId' = 180206 - TEMPERATURE_MELTING_EXTREME: 'CommonBuffId' = 182207 - TEMPERATURE_OVERHEATING: 'CommonBuffId' = 180205 - TEMPERATURE_POOL_COLD: 'CommonBuffId' = 185467 - TEMPERATURE_POOL_FREEZING: 'CommonBuffId' = 185468 - TEMPERATURE_POOL_WARM: 'CommonBuffId' = 185469 - TEMPERATURE_POSITIVE_BURNING_MAN_BURNING: 'CommonBuffId' = 183574 - TEMPERATURE_POSITIVE_BURNING_MAN_HOT: 'CommonBuffId' = 183573 - TEMPERATURE_POSITIVE_ICE_MAN_COLD: 'CommonBuffId' = 183575 - TEMPERATURE_POSITIVE_ICE_MAN_FREEZING: 'CommonBuffId' = 183576 - TEMPERATURE_SIM_RAY_CHILLED: 'CommonBuffId' = 185173 - TEMPERATURE_SIM_RAY_FROZEN: 'CommonBuffId' = 185165 - TEMPERATURE_SUPPRESS_TEMPERATURE_OUTFIT_SWAP: 'CommonBuffId' = 184255 - TEMPERATURE_TODDLER_COLD: 'CommonBuffId' = 186083 - TEMPERATURE_TODDLER_HOT: 'CommonBuffId' = 186084 - TEMPERATURE_TRAIT_BURNING_MAN: 'CommonBuffId' = 183570 - TEMPERATURE_TRAIT_ICE_MAN: 'CommonBuffId' = 183571 - TEMPERATURE_VFX_COLD_BREATH_C: 'CommonBuffId' = 184196 - TEMPERATURE_VFX_COLD_BREATH_HORSE: 'CommonBuffId' = 335306 - TEMPERATURE_VFX_COLD_BREATH_I: 'CommonBuffId' = 334461 - TEMPERATURE_VFX_COLD_BREATH_P: 'CommonBuffId' = 184197 - TEMPERATURE_VFX_COLD_BREATH_TYAE: 'CommonBuffId' = 184195 - TEMPERATURE_VFX_COLD_BREATH_V: 'CommonBuffId' = 190826 - TEMPERATURE_WARM_WATER: 'CommonBuffId' = 209183 - TEMPLE_ARCHAEOLOGY_SKILL_GAIN: 'CommonBuffId' = 179377 - TEMPLE_GATE_TRY_TO_PASS_WITH_RELIC_GLOW: 'CommonBuffId' = 179553 - TEMPLE_HAPPY: 'CommonBuffId' = 345990 - TEMPLE_LOOK_AROUND_COOLDOWN: 'CommonBuffId' = 183238 - TEMPLE_PLANTS: 'CommonBuffId' = 179107 - TEMPLE_TRAP_ACTIVATE_SUCCESS: 'CommonBuffId' = 179533 - TEMPLE_TRAP_PUNISHMENT_BLADDER_SCARE: 'CommonBuffId' = 174448 - TEMPLE_TRAP_PUNISHMENT_BLADDER_SCARE_VAMPIRE: 'CommonBuffId' = 174452 - TEMPLE_TRAP_PUNISHMENT_BONE_DUST_HIDDEN: 'CommonBuffId' = 178285 - TEMPLE_TRAP_PUNISHMENT_FIRE_HIDDEN: 'CommonBuffId' = 178286 - TEMPLE_TRAP_PUNISHMENT_MISERABLE_VACATION: 'CommonBuffId' = 174451 - TEMPLE_TRAP_PUNISHMENT_NOTHING_BAD: 'CommonBuffId' = 174447 - TEMPLE_TRAP_PUNISHMENT_RESTLESS_HORROR: 'CommonBuffId' = 174449 - TEMPLE_TRAP_PUNISHMENT_SO_ALONE: 'CommonBuffId' = 174450 - TEMPORARY_CLONE_LEAVE: 'CommonBuffId' = 215169 - TEMPORARY_STAY_AWKWARD_TENSION: 'CommonBuffId' = 307449 - TEMPORARY_STAY_COOL_LINEAGE: 'CommonBuffId' = 307218 - TEMPORARY_STAY_DISASTER: 'CommonBuffId' = 319896 - TEMPORARY_STAY_DOPPEL_GANGER: 'CommonBuffId' = 312758 - TEMPORARY_STAY_EAT_CANDY: 'CommonBuffId' = 316262 - TEMPORARY_STAY_FAMILY_BONDS: 'CommonBuffId' = 307217 - TEMPORARY_STAY_FAMILY_FOREVER: 'CommonBuffId' = 307219 - TEMPORARY_STAY_GET_THEM_OUT: 'CommonBuffId' = 308306 - TEMPORARY_STAY_GLOOMY: 'CommonBuffId' = 310694 - TEMPORARY_STAY_GLOOMY_PRESENCE: 'CommonBuffId' = 310696 - TEMPORARY_STAY_GOOD_COMPANY: 'CommonBuffId' = 307448 - TEMPORARY_STAY_GOOD_FRIENDS: 'CommonBuffId' = 312759 - TEMPORARY_STAY_GRANDPARENT_LOVE: 'CommonBuffId' = 307224 - TEMPORARY_STAY_GRIEVING: 'CommonBuffId' = 312760 - TEMPORARY_STAY_HIDDEN_FAMILY_REUNION: 'CommonBuffId' = 307725 - TEMPORARY_STAY_HIDDEN_GOODBYE: 'CommonBuffId' = 310008 - TEMPORARY_STAY_HIDDEN_GUEST: 'CommonBuffId' = 303300 - TEMPORARY_STAY_HIDDEN_GUEST_HELP: 'CommonBuffId' = 308110 - TEMPORARY_STAY_HIDDEN_GUEST_SPECIAL_CLONE: 'CommonBuffId' = 312751 - TEMPORARY_STAY_HIDDEN_GUEST_SPECIAL_COUCH_SURFER: 'CommonBuffId' = 312750 - TEMPORARY_STAY_HIDDEN_GUEST_SPECIAL_COUCH_SURFER_KYLE: 'CommonBuffId' = 330800 - TEMPORARY_STAY_HIDDEN_GUEST_SPECIAL_DISASTER: 'CommonBuffId' = 312747 - TEMPORARY_STAY_HIDDEN_GUEST_SPECIAL_FRIEND: 'CommonBuffId' = 312752 - TEMPORARY_STAY_HIDDEN_GUEST_SPECIAL_HOUSEHOLD_LOSS: 'CommonBuffId' = 312753 - TEMPORARY_STAY_HIDDEN_GUEST_SPECIAL_INFANT_INTRO: 'CommonBuffId' = 324276 - TEMPORARY_STAY_HIDDEN_GUEST_SPECIAL_MOPEY: 'CommonBuffId' = 312430 - TEMPORARY_STAY_HIDDEN_GUEST_SPECIAL_PARENTAL_HELP: 'CommonBuffId' = 322376 - TEMPORARY_STAY_HIDDEN_HELP_BOOST: 'CommonBuffId' = 307215 - TEMPORARY_STAY_HIDDEN_INFANT_INTRO_START: 'CommonBuffId' = 324422 - TEMPORARY_STAY_HIDDEN_PARENTAL_BOOST: 'CommonBuffId' = 322377 - TEMPORARY_STAY_HIDDEN_PARENTAL_BOOST_COOLDOWN: 'CommonBuffId' = 323302 - TEMPORARY_STAY_HIDDEN_PARENTAL_HELP_SCHEDULE: 'CommonBuffId' = 327281 - TEMPORARY_STAY_HIDDEN_SPECIAL_BEHAVIOR_COOLDOWN: 'CommonBuffId' = 311524 - TEMPORARY_STAY_HIDDEN_SPECIAL_BEHAVIOR_COOLDOWN_CANDY: 'CommonBuffId' = 330801 - TEMPORARY_STAY_HIDDEN_SPECIAL_BEHAVIOR_COOLDOWN_KYLE: 'CommonBuffId' = 328182 - TEMPORARY_STAY_HIDDEN_STOP_HELPING: 'CommonBuffId' = 307216 - TEMPORARY_STAY_HIDDEN_SUMMON: 'CommonBuffId' = 323020 - TEMPORARY_STAY_HIDDEN_SUMMON_SNACKS_COOLDOWN: 'CommonBuffId' = 311088 - TEMPORARY_STAY_HIDDEN_WELCOME_ME: 'CommonBuffId' = 310003 - TEMPORARY_STAY_HIDDEN_WELCOME_ME_COOLDOWN: 'CommonBuffId' = 312770 - TEMPORARY_STAY_MEANING_OF_FAMILY: 'CommonBuffId' = 307220 - TEMPORARY_STAY_MEANING_OF_FAMILY_TODDLER: 'CommonBuffId' = 307222 - TEMPORARY_STAY_NICE_SEEING_FAMILY: 'CommonBuffId' = 307453 - TEMPORARY_STAY_NICE_SEEING_FRIENDS: 'CommonBuffId' = 307452 - TEMPORARY_STAY_NICE_SEEING_GRANDPARENTS: 'CommonBuffId' = 307451 - TEMPORARY_STAY_NICE_SEEING_PARENTS: 'CommonBuffId' = 307450 - TEMPORARY_STAY_POWER_SIP_LLAMA_BERRY: 'CommonBuffId' = 310415 - TEMPORARY_STAY_WHOSE_KID_IS_THIS: 'CommonBuffId' = 310698 - TEMP_RANDOM_CALC_01: 'CommonBuffId' = 144975 - TEMP_RANDOM_CALC_02: 'CommonBuffId' = 144976 - TENSE_GHOSTLY_YOWL_CAT: 'CommonBuffId' = 174603 - TENSE_GHOSTLY_YOWL_DOG: 'CommonBuffId' = 174604 - TENSION_RELIEF_SCENT: 'CommonBuffId' = 118498 - THERMOSTAT_COOLER_HAPPY: 'CommonBuffId' = 188978 - THERMOSTAT_COOLER_UNCOMFORTABLE: 'CommonBuffId' = 188980 - THERMOSTAT_HIDDEN_GLOBAL_HIGH: 'CommonBuffId' = 190651 - THERMOSTAT_HIDDEN_GLOBAL_LOW: 'CommonBuffId' = 190656 - THERMOSTAT_HIDDEN_GLOBAL_MEDIUM: 'CommonBuffId' = 190657 - THERMOSTAT_HIDDEN_TEMPERATURE_CHANGE_COOLER: 'CommonBuffId' = 190675 - THERMOSTAT_HIDDEN_TEMPERATURE_CHANGE_WARMER: 'CommonBuffId' = 190671 - THERMOSTAT_ROUTE_REACT_COOLDOWN: 'CommonBuffId' = 189619 - THERMOSTAT_WARMER_HAPPY: 'CommonBuffId' = 188979 - THERMOSTAT_WARMER_UNCOMFORTABLE: 'CommonBuffId' = 188981 - THREATENED_CRIMINAL: 'CommonBuffId' = 36592 - THREATENED_VICTIM: 'CommonBuffId' = 36593 - THRIFT_STORE_BUBBLE_BUNCH: 'CommonBuffId' = 282903 - THRIFT_STORE_BUBBLICIOUS_BEVERAGE: 'CommonBuffId' = 282910 - THRIFT_STORE_COMEDY_CALLING: 'CommonBuffId' = 282907 - THRIFT_STORE_EVENT_PERFORMED: 'CommonBuffId' = 280933 - THRIFT_STORE_FOBBED_OFF_FASHION: 'CommonBuffId' = 281215 - THRIFT_STORE_LIVE_POETS_SOCIETY: 'CommonBuffId' = 282909 - THRIFT_STORE_PERFORMANCE_FINISHED: 'CommonBuffId' = 300571 - THRIFT_STORE_STYLE_SESSION: 'CommonBuffId' = 282905 - THRIFT_STORE_TREND_TIP_BASICS: 'CommonBuffId' = 281224 - THRIFT_STORE_TREND_TIP_BOHO: 'CommonBuffId' = 281221 - THRIFT_STORE_TREND_TIP_COUNTRY: 'CommonBuffId' = 281217 - THRIFT_STORE_TREND_TIP_HIPSTER: 'CommonBuffId' = 281220 - THRIFT_STORE_TREND_TIP_NONE: 'CommonBuffId' = 281226 - THRIFT_STORE_TREND_TIP_OUTDOORSY: 'CommonBuffId' = 281223 - THRIFT_STORE_TREND_TIP_POLISHED: 'CommonBuffId' = 281227 - THRIFT_STORE_TREND_TIP_PREPPY: 'CommonBuffId' = 281219 - THRIFT_STORE_TREND_TIP_ROCKER: 'CommonBuffId' = 281225 - THRIFT_STORE_TREND_TIP_STREETWEAR: 'CommonBuffId' = 281222 - THROW_FOOTBALL_HEADING_FOR_THE_BIG_LEAGUES: 'CommonBuffId' = 283024 - THROW_FOOTBALL_HIDDEN_BALL_REGULAR: 'CommonBuffId' = 285958 - THROW_FOOTBALL_HIDDEN_BALL_REWARD: 'CommonBuffId' = 285959 - THROW_FOOTBALL_PRACTICE_MAKES_PAINFUL: 'CommonBuffId' = 283023 - THROW_FOOTBALL_SMELL_THE_GLORY: 'CommonBuffId' = 283025 - TODDLERS_AT_DAYCARE: 'CommonBuffId' = 157127 - TODDLERS_BIRTHDAY_CELEBRATION: 'CommonBuffId' = 157688 - TODDLERS_BITE: 'CommonBuffId' = 162589 - TODDLERS_BITE_CHILD: 'CommonBuffId' = 164670 - TODDLERS_BITE_TODDLER: 'CommonBuffId' = 164669 - TODDLERS_CAREGIVER_AWAKE: 'CommonBuffId' = 157452 - TODDLERS_CTYAE_CRYING_TODDLER: 'CommonBuffId' = 140754 - TODDLERS_CTYAE_ENOUGH_ALREADY: 'CommonBuffId' = 156740 - TODDLERS_CTYAE_GROWING_UP: 'CommonBuffId' = 156743 - TODDLERS_CTYAE_HIDDEN_PLAYING_DOLLS_WITH_TODDLER: 'CommonBuffId' = 156460 - TODDLERS_CTYAE_HIDDEN_WATCHING_TV_WITH_TODDLER: 'CommonBuffId' = 156459 - TODDLERS_CTYAE_STINKY_DIAPER: 'CommonBuffId' = 140767 - TODDLERS_CTYAE_TANTRUM_THROWING_TODDLER: 'CommonBuffId' = 151193 - TODDLERS_CTYAE_THAT_WAS_CUTE: 'CommonBuffId' = 156985 - TODDLERS_CTYAE_TODDLER_BIRTHDAY: 'CommonBuffId' = 156742 - TODDLERS_CTYAE_TODDLER_SAID_WHAT: 'CommonBuffId' = 156228 - TODDLERS_CTYAE_UGH_TODDLERS: 'CommonBuffId' = 156741 - TODDLERS_CTYAE_WATCH_TODDLER_TOY_SHOW: 'CommonBuffId' = 155714 - TODDLERS_DANCE_SHAKING_TAIL: 'CommonBuffId' = 147370 - TODDLERS_DEFIANCE_ACTOR_DISOBEDIENT_TODDLER: 'CommonBuffId' = 141558 - TODDLERS_DEFIANCE_ACTOR_UNCOOPERATIVE_TODDLER: 'CommonBuffId' = 141545 - TODDLERS_DEFIANCE_DONT_GIVE_ME_ORDERS: 'CommonBuffId' = 156771 - TODDLERS_DEFIANCE_DONT_WANT_TO: 'CommonBuffId' = 141541 - TODDLERS_DEFIANCE_DONT_WANT_TO_VISIBLE: 'CommonBuffId' = 156774 - TODDLERS_DEFIANCE_MEANIE: 'CommonBuffId' = 141565 - TODDLERS_DEFIANCE_SILLY_ADULTS: 'CommonBuffId' = 154240 - TODDLERS_DEFIANCE_TOO_HYPER: 'CommonBuffId' = 156769 - TODDLERS_GETTING_SO_BIG_UNCOMFORTABLE: 'CommonBuffId' = 145986 - TODDLERS_GROWING_SO_FAST_HAPPY: 'CommonBuffId' = 150540 - TODDLERS_HIDDEN_CAREGIVER_RECENTLY_RETURNED_FROM_WORK: 'CommonBuffId' = 154998 - TODDLERS_HIDDEN_CAREGIVER_SLEEP_DO_NOT_DISTURB: 'CommonBuffId' = 157458 - TODDLERS_HIDDEN_CAUGHT_BAD_BEHAVIOR: 'CommonBuffId' = 156593 - TODDLERS_HIDDEN_GREET_RETURNING_CAREGIVER: 'CommonBuffId' = 154980 - TODDLERS_HIDDEN_HAS_BEEN_COMFORTED: 'CommonBuffId' = 157007 - TODDLERS_HIDDEN_HAS_BEEN_WATCHED: 'CommonBuffId' = 151818 - TODDLERS_HIDDEN_HAS_NOT_BEEN_WATCHED: 'CommonBuffId' = 151819 - TODDLERS_HIDDEN_RECENTLY_SNUGGLED: 'CommonBuffId' = 156944 - TODDLERS_HIDDEN_SKILL_COMMUNICATION_LEVELS_1: 'CommonBuffId' = 154473 - TODDLERS_HIDDEN_SKILL_COMMUNICATION_LEVELS_2: 'CommonBuffId' = 154474 - TODDLERS_HIDDEN_SKILL_COMMUNICATION_LEVELS_3: 'CommonBuffId' = 154475 - TODDLERS_HIDDEN_SKILL_COMMUNICATION_LEVELS_4: 'CommonBuffId' = 154476 - TODDLERS_HIDDEN_SKILL_COMMUNICATION_LEVELS_5: 'CommonBuffId' = 154472 - TODDLERS_HIDDEN_SKILL_IMAGINATION_LEVELS_1: 'CommonBuffId' = 154478 - TODDLERS_HIDDEN_SKILL_IMAGINATION_LEVELS_2: 'CommonBuffId' = 154479 - TODDLERS_HIDDEN_SKILL_IMAGINATION_LEVELS_3: 'CommonBuffId' = 154480 - TODDLERS_HIDDEN_SKILL_IMAGINATION_LEVELS_4: 'CommonBuffId' = 154481 - TODDLERS_HIDDEN_SKILL_IMAGINATION_LEVELS_5: 'CommonBuffId' = 154477 - TODDLERS_HIDDEN_SKILL_MOVEMENT_LEVELS_1: 'CommonBuffId' = 147041 - TODDLERS_HIDDEN_SKILL_MOVEMENT_LEVELS_2: 'CommonBuffId' = 147033 - TODDLERS_HIDDEN_SKILL_MOVEMENT_LEVELS_3: 'CommonBuffId' = 154487 - TODDLERS_HIDDEN_SKILL_MOVEMENT_LEVELS_4: 'CommonBuffId' = 147035 - TODDLERS_HIDDEN_SKILL_MOVEMENT_LEVELS_5: 'CommonBuffId' = 154488 - TODDLERS_HIDDEN_SKILL_POTTY_LEVELS_1: 'CommonBuffId' = 154490 - TODDLERS_HIDDEN_SKILL_POTTY_LEVELS_2: 'CommonBuffId' = 154491 - TODDLERS_HIDDEN_SKILL_POTTY_LEVELS_3: 'CommonBuffId' = 154492 - TODDLERS_HIDDEN_SKILL_THINKING_LEVELS_1: 'CommonBuffId' = 154483 - TODDLERS_HIDDEN_SKILL_THINKING_LEVELS_2: 'CommonBuffId' = 154484 - TODDLERS_HIDDEN_SKILL_THINKING_LEVELS_3: 'CommonBuffId' = 154485 - TODDLERS_HIDDEN_SKILL_THINKING_LEVELS_4: 'CommonBuffId' = 154486 - TODDLERS_HIDDEN_SKILL_THINKING_LEVELS_5: 'CommonBuffId' = 154482 - TODDLERS_HIDDEN_STEREO_LISTENED_TO_LULLABIES: 'CommonBuffId' = 155940 - TODDLERS_HIDDEN_WAIT_TIMER: 'CommonBuffId' = 156791 - TODDLERS_HUG_LOVED: 'CommonBuffId' = 156981 - TODDLERS_LEFT_BEHIND: 'CommonBuffId' = 156744 - TODDLERS_LEFT_BEHIND_IN_HIGH_CHAIR: 'CommonBuffId' = 157129 - TODDLERS_LYING_DOWN_ABOUT_TO_SLEEP: 'CommonBuffId' = 157574 - TODDLERS_NAP_NOT_ENOUGH_NAP: 'CommonBuffId' = 156534 - TODDLERS_READ_TO_LOVED: 'CommonBuffId' = 156982 - TODDLERS_SNUGGLE_LOVED: 'CommonBuffId' = 156943 - TODDLERS_STRANGER_DANGER: 'CommonBuffId' = 154495 - TODDLERS_STRANGER_DANGER_CLINGY: 'CommonBuffId' = 154551 - TODDLERS_TEACH_TO_TALK_FRUSTRATED_WITH_WORDS: 'CommonBuffId' = 155780 - TODDLERS_TEACH_TO_TALK_LEARNED_WORDS: 'CommonBuffId' = 155779 - TODDLERS_TEACH_TO_TALK_P_HAS_RESPONDED: 'CommonBuffId' = 155761 - TODDLERS_TEACH_TO_TALK_TIRED_OF_WORDS: 'CommonBuffId' = 155781 - TODDLERS_TEACH_TO_TALK_TYAE_HAS_TAUGHT: 'CommonBuffId' = 155760 - TODDLERS_TODDLER_AWAKE: 'CommonBuffId' = 154183 - TODDLERS_TODDLER_CANT_TALK: 'CommonBuffId' = 156227 - TODDLERS_WAS_CAREGIVER: 'CommonBuffId' = 157470 - TODDLERS_WATCH_TODDLERS_DISTRESS_COOLDOWN: 'CommonBuffId' = 157524 - TODDLER_AUTONOMY_MOD_IN_HIGH_CHAIR: 'CommonBuffId' = 144745 - TODDLER_BED_AFTER_NIGHTMARE: 'CommonBuffId' = 157677 - TODDLER_BED_HAS_BEEN_READ_TO_SLEEP: 'CommonBuffId' = 150369 - TODDLER_BED_HAS_BEEN_TUCKED_IN: 'CommonBuffId' = 150406 - TODDLER_BED_HIDDEN_NIGHTMARE_INCEPTION: 'CommonBuffId' = 152878 - TODDLER_BED_LOVED: 'CommonBuffId' = 150399 - TODDLER_BED_MOMENTS_PEACE: 'CommonBuffId' = 150401 - TODDLER_BED_NIGHTMARE: 'CommonBuffId' = 152880 - TODDLER_BED_PUT_ME_TO_BED: 'CommonBuffId' = 157679 - TODDLER_BED_PUT_TODDLER_TO_BED_AUTONOMY: 'CommonBuffId' = 150557 - TODDLER_BED_RESTED: 'CommonBuffId' = 156726 - TODDLER_BED_TUCK_IN_AUTONOMY: 'CommonBuffId' = 149394 - TODDLER_BOREDOM_DOLLHOUSE_ANGRY: 'CommonBuffId' = 152295 - TODDLER_BOREDOM_DOLLHOUSE_SAD: 'CommonBuffId' = 152297 - TODDLER_BOREDOM_DOLLHOUSE_SATISFIED: 'CommonBuffId' = 152296 - TODDLER_BOREDOM_NESTING_BLOCKS_ANGRY: 'CommonBuffId' = 152270 - TODDLER_BOREDOM_NESTING_BLOCKS_SAD: 'CommonBuffId' = 152272 - TODDLER_BOREDOM_NESTING_BLOCKS_SATISFIED: 'CommonBuffId' = 152273 - TODDLER_BOREDOM_POTTY_SATISFIED: 'CommonBuffId' = 156764 - TODDLER_BOREDOM_ROUGHHOUSING_ANGRY: 'CommonBuffId' = 152280 - TODDLER_BOREDOM_ROUGHHOUSING_SAD: 'CommonBuffId' = 152281 - TODDLER_BOREDOM_ROUGHHOUSING_SATISFIED: 'CommonBuffId' = 152282 - TODDLER_BOREDOM_STEREO_ANGRY: 'CommonBuffId' = 152283 - TODDLER_BOREDOM_STEREO_DANCING_ANGRY: 'CommonBuffId' = 156723 - TODDLER_BOREDOM_STEREO_DANCING_SAD: 'CommonBuffId' = 156725 - TODDLER_BOREDOM_STEREO_DANCING_SATISFIED: 'CommonBuffId' = 156724 - TODDLER_BOREDOM_STEREO_SAD: 'CommonBuffId' = 152284 - TODDLER_BOREDOM_STEREO_SATISFIED: 'CommonBuffId' = 152285 - TODDLER_BOREDOM_TODDLER_BOOK_ANGRY: 'CommonBuffId' = 152286 - TODDLER_BOREDOM_TODDLER_BOOK_SAD: 'CommonBuffId' = 152287 - TODDLER_BOREDOM_TODDLER_BOOK_SATISFIED: 'CommonBuffId' = 152288 - TODDLER_BOREDOM_TOYS_ANGRY: 'CommonBuffId' = 152291 - TODDLER_BOREDOM_TOYS_SAD: 'CommonBuffId' = 152290 - TODDLER_BOREDOM_TOYS_SATISFIED: 'CommonBuffId' = 152289 - TODDLER_BOREDOM_TV_ANGRY: 'CommonBuffId' = 152292 - TODDLER_BOREDOM_TV_SAD: 'CommonBuffId' = 152293 - TODDLER_BOREDOM_TV_SATISFIED: 'CommonBuffId' = 152294 - TODDLER_CHECK_TODDLER_FEED_TODDLER: 'CommonBuffId' = 146039 - TODDLER_CHECK_TODDLER_FEED_TODDLER_DESSERT: 'CommonBuffId' = 153918 - TODDLER_CHECK_TODDLER_FEED_TODDLER_DRINK: 'CommonBuffId' = 152866 - TODDLER_DIAPER_RASH: 'CommonBuffId' = 156762 - TODDLER_HAS_DIRTY_DIAPER: 'CommonBuffId' = 140766 - TODDLER_JUNGLE_GYM_BALL_PIT: 'CommonBuffId' = 170762 - TODDLER_JUNGLE_GYM_SLIDE_CLIMBER_SLIDE_CATCH: 'CommonBuffId' = 172850 - TODDLER_JUNGLE_GYM_STARTING_MAKE_BELIEVE: 'CommonBuffId' = 173477 - TODDLER_PERSONALITY_ASK_TO_CARRY: 'CommonBuffId' = 318175 - TODDLER_PERSONALITY_BEING_CARRIED_ANGRY: 'CommonBuffId' = 313257 - TODDLER_PERSONALITY_BEING_CARRIED_HAPPY: 'CommonBuffId' = 313245 - TODDLER_PERSONALITY_BEING_CARRIED_SAD: 'CommonBuffId' = 313256 - TODDLER_PERSONALITY_DESTRUCTIVE_TODDLER: 'CommonBuffId' = 333448 - TODDLER_PERSONALITY_FORCED_TO_WAKE_UP: 'CommonBuffId' = 313466 - TODDLER_PERSONALITY_FORCED_TO_WAKE_UP_COOLDOWN: 'CommonBuffId' = 314214 - TODDLER_PERSONALITY_FORCED_TO_WAKE_UP_HATES_BED_TIME: 'CommonBuffId' = 314832 - TODDLER_PERSONALITY_GIVE_QUIRKS: 'CommonBuffId' = 336060 - TODDLER_PERSONALITY_HATES_BED_TIME_ENERGY_YELLOW_OVERRIDE: 'CommonBuffId' = 313690 - TODDLER_PERSONALITY_HATES_BED_TIME_ROLL_WAKE_UP: 'CommonBuffId' = 314212 - TODDLER_PERSONALITY_HEAVY_SLEEPER_SAFE_SLEEP: 'CommonBuffId' = 313461 - TODDLER_PERSONALITY_HIDDEN_BEING_HELD: 'CommonBuffId' = 314040 - TODDLER_PERSONALITY_HIDDEN_BEING_HELD_BY_CAREGIVER: 'CommonBuffId' = 322777 - TODDLER_PERSONALITY_HIDDEN_EARLY_RISER_COOLDOWN: 'CommonBuffId' = 319502 - TODDLER_PERSONALITY_HIDDEN_READ_TOME: 'CommonBuffId' = 318173 - TODDLER_PERSONALITY_HIDDEN_SING_A_SONG_TIME: 'CommonBuffId' = 334319 - TODDLER_PERSONALITY_LIGHT_SLEEPER_ROLL_WAKE_UP: 'CommonBuffId' = 313464 - TODDLER_PERSONALITY_PICKY_EATER_EWW_YUCK: 'CommonBuffId' = 313468 - TODDLER_PERSONALITY_PICKY_EATER_EWW_YUCK_MIXED: 'CommonBuffId' = 313687 - TODDLER_PERSONALITY_PICKY_EATER_HUNGER_YELLOW_OVERRIDE: 'CommonBuffId' = 313786 - TODDLER_PERSONALITY_REVEAL_DELAY: 'CommonBuffId' = 333670 - TODDLER_PERSONALITY_WAKING_UP_ANGRY: 'CommonBuffId' = 313262 - TODDLER_PERSONALITY_WAKING_UP_HAPPY: 'CommonBuffId' = 313260 - TODDLER_PERSONALITY_WAKING_UP_SAD: 'CommonBuffId' = 313261 - TODDLER_PLAY_IN_OCEAN_VFX: 'CommonBuffId' = 212940 - TODDLER_PLAY_IN_OCEAN_VFX_3: 'CommonBuffId' = 214476 - TODDLER_PLAY_IN_OCEAN_VFX_4: 'CommonBuffId' = 214477 - TODDLER_PLAY_IN_OCEAN_VFX_5: 'CommonBuffId' = 214478 - TODDLER_WHY_WEAR_CLOTHES: 'CommonBuffId' = 153408 - TOLD_GOODBYE_INVISIBLE: 'CommonBuffId' = 101049 - TOLD_GREAT_STORY: 'CommonBuffId' = 103136 - TOWN_MASCOT_BROADCASTERS_DANCE: 'CommonBuffId' = 251254 - TOWN_MASCOT_BUFFS_DANCE: 'CommonBuffId' = 250418 - TOWN_MASCOT_BUFFS_HANG_AROUND_STATUE_LOCK_OUT: 'CommonBuffId' = 252452 - TOWN_MASCOT_BUFFS_LOCK_OUTS_CAPSULE: 'CommonBuffId' = 251180 - TOWN_MASCOT_BUFFS_STATUE_LOT_VISIT: 'CommonBuffId' = 250682 - TOWN_MASCOT_BUFFS_STATUE_SELFIE: 'CommonBuffId' = 251859 - TOWN_SCULPTURE_BLESSED_BY_JUNGLE: 'CommonBuffId' = 175068 - TOWN_SCULPTURE_CURSED_NO_MORE: 'CommonBuffId' = 175071 - TOY_BALL_PET_HANDLED_CHEWED_BALL: 'CommonBuffId' = 164347 - TRAGIC_CLOWN_SUCH_TRAGEDY: 'CommonBuffId' = 139613 - TRAINING_DUMMY_FIGHT_LOST: 'CommonBuffId' = 203259 - TRAINING_DUMMY_TURN_TAKEN: 'CommonBuffId' = 203255 - TRAINING_DUMMY_WATCHING: 'CommonBuffId' = 203258 - TRAIT_ACTIVE: 'CommonBuffId' = 9328 - TRAIT_ACTIVE_ANTSY: 'CommonBuffId' = 27457 - TRAIT_ACTIVE_LOW_ACTIVITY_HIDDEN: 'CommonBuffId' = 40879 - TRAIT_ADOPT_TIGER_HIDDEN: 'CommonBuffId' = 353575 - TRAIT_ADULT: 'CommonBuffId' = 34526 - TRAIT_ADVENTUROUS: 'CommonBuffId' = 252086 - TRAIT_ALLURING: 'CommonBuffId' = 26189 - TRAIT_ALWAYS_WELCOME: 'CommonBuffId' = 35505 - TRAIT_AMBITIOUS: 'CommonBuffId' = 12650 - TRAIT_AMBITIOUS_LOW_ADVANCEMENT_HIDDEN: 'CommonBuffId' = 37817 - TRAIT_AMBITIOUS_PROMOTION_ANX: 'CommonBuffId' = 73908 - TRAIT_AMBITIOUS_PROMOTION_ANX_JOBLESS: 'CommonBuffId' = 97459 - TRAIT_ANGLERS_TRANQUILITY_FISHING: 'CommonBuffId' = 157955 - TRAIT_ANIMAL_ENTHUSIAST: 'CommonBuffId' = 257637 - TRAIT_ANIMAL_ENTHUSIAST_DANCE_FAIL: 'CommonBuffId' = 268090 - TRAIT_ANIMAL_ENTHUSIAST_DANCE_SUCCESS: 'CommonBuffId' = 268091 - TRAIT_ANIMAL_ENTHUSIAST_ENERGIZED_CONVERSATION: 'CommonBuffId' = 260395 - TRAIT_ANIMAL_ENTHUSIAST_HAPPY_BONDING: 'CommonBuffId' = 260391 - TRAIT_ANIMAL_ENTHUSIAST_INSPIRED_EGG: 'CommonBuffId' = 260396 - TRAIT_ANIMAL_ENTHUSIAST_PLAY_TO_COOLDOWN: 'CommonBuffId' = 270607 - TRAIT_ANIMAL_ENTHUSIAST_SAD_MISS_ANIMALS: 'CommonBuffId' = 260392 - TRAIT_ANIMAL_ENTHUSIAST_SELLING_ANIMAL_STRONGER: 'CommonBuffId' = 260394 - TRAIT_ANIMAL_WHISPERER: 'CommonBuffId' = 172194 - TRAIT_ANTISEPTIC: 'CommonBuffId' = 26372 - TRAIT_ARGUMENTATIVE: 'CommonBuffId' = 163099 - TRAIT_ART_LOVER: 'CommonBuffId' = 28555 - TRAIT_ART_LOVER_INSPIRED: 'CommonBuffId' = 28582 - TRAIT_ART_LOVER_NATURE_IS_ART: 'CommonBuffId' = 107784 - TRAIT_ASPIRATION_CHALLENGE_POSITIVITY_KINDNESS_AMBASSADOR: 'CommonBuffId' = 198886 - TRAIT_ASPIRATION_FTUE_CAREER_MINDED: 'CommonBuffId' = 201240 - TRAIT_ASPIRATION_FTUE_OVER_ACHIEVER: 'CommonBuffId' = 197774 - TRAIT_ASPIRATION_LORD_OF_THE_KNITS: 'CommonBuffId' = 240406 - TRAIT_ASPIRATION_SLINGER_OF_SPELLS: 'CommonBuffId' = 217374 - TRAIT_AT_PEACE_WITH_NATURE: 'CommonBuffId' = 108423 - TRAIT_BABY: 'CommonBuffId' = 34521 - TRAIT_BANE_SABOTAGE: 'CommonBuffId' = 27212 - TRAIT_BEACHBUM_LAIDBACK: 'CommonBuffId' = 308569 - TRAIT_BONEHILDA: 'CommonBuffId' = 253238 - TRAIT_BONEHILDA_AUTONOMY: 'CommonBuffId' = 253360 - TRAIT_BOOKWORM: 'CommonBuffId' = 28598 - TRAIT_BOOKWORM_INSPIRED: 'CommonBuffId' = 28599 - TRAIT_BRAVE: 'CommonBuffId' = 253270 - TRAIT_BRO: 'CommonBuffId' = 12655 - TRAIT_BRO_BROXIMITY_HIDDEN: 'CommonBuffId' = 12656 - TRAIT_BRO_BRO_LOVE: 'CommonBuffId' = 74074 - TRAIT_BRO_WATCHED_SPORTS: 'CommonBuffId' = 31208 - TRAIT_CAMPING_ADD_TRAIT_HIDDEN: 'CommonBuffId' = 104273 - TRAIT_CAMPING_HIDDEN: 'CommonBuffId' = 102266 - TRAIT_CAREER_SCOUTING_APTITUDE: 'CommonBuffId' = 187865 - TRAIT_CAREFREE: 'CommonBuffId' = 308568 - TRAIT_CAT_LOVER: 'CommonBuffId' = 157980 - TRAIT_CAT_LOVER_ADOPTION: 'CommonBuffId' = 174829 - TRAIT_CAT_LOVER_DEATH: 'CommonBuffId' = 174831 - TRAIT_CAT_LOVER_MET_NEW_CAT: 'CommonBuffId' = 158024 - TRAIT_CAT_LOVER_TAKEN: 'CommonBuffId' = 174830 - TRAIT_CHEERFUL: 'CommonBuffId' = 9324 - TRAIT_CHEERFUL_CHEERED_TO_DEATH: 'CommonBuffId' = 258458 - TRAIT_CHEERFUL_HAPPY_BONUS: 'CommonBuffId' = 258463 - TRAIT_CHEERFUL_LOOK_AT_BRIGHT_SIDE_COOLDOWN: 'CommonBuffId' = 258456 - TRAIT_CHILD: 'CommonBuffId' = 34523 - TRAIT_CHILDISH: 'CommonBuffId' = 12661 - TRAIT_CHILDISH_PLAYED_WITH_CHILDREN: 'CommonBuffId' = 37938 - TRAIT_CHILDISH_WATCHED_KIDS_CHANNEL: 'CommonBuffId' = 31237 - TRAIT_CHILD_OF_THE_OCEAN: 'CommonBuffId' = 204497 - TRAIT_CHILD_OF_THE_OCEAN_FISH_SADNESS: 'CommonBuffId' = 211734 - TRAIT_CHILD_OF_THE_OCEAN_VISIBLE_BIG_FISH: 'CommonBuffId' = 210724 - TRAIT_CHILD_OF_THE_OCEAN_VISIBLE_CHILD: 'CommonBuffId' = 210721 - TRAIT_CHILD_OF_THE_OCEAN_VISIBLE_FISH_FREEDOM: 'CommonBuffId' = 210716 - TRAIT_CHILD_OF_THE_OCEAN_VISIBLE_HURT_FISH: 'CommonBuffId' = 210715 - TRAIT_CHILD_OF_THE_OCEAN_VISIBLE_MAROONED: 'CommonBuffId' = 210722 - TRAIT_CHILD_OF_THE_OCEAN_VISIBLE_STOMACH_SQUALL: 'CommonBuffId' = 210714 - TRAIT_CHILD_OF_THE_OCEAN_WADING: 'CommonBuffId' = 214586 - TRAIT_CHILD_OF_THE_SEA: 'CommonBuffId' = 341882 - TRAIT_CHILD_OF_THE_SEA_COMMUNITY_CONTENDER: 'CommonBuffId' = 344489 - TRAIT_CHILD_OF_THE_SEA_CULTURAL_ACTIVITIES: 'CommonBuffId' = 344487 - TRAIT_CHILD_OF_THE_SEA_KINSHIP_COOLDOWN: 'CommonBuffId' = 341997 - TRAIT_CHILD_OF_THE_SEA_KINSHIP_HIDDEN: 'CommonBuffId' = 352290 - TRAIT_CHILD_OF_THE_SEA_SKY_LANTERN_COOLDOWN: 'CommonBuffId' = 353504 - TRAIT_CHILD_OF_THE_SEA_VISIBLE_ADRIFT: 'CommonBuffId' = 341999 - TRAIT_CHILD_OF_THE_SEA_VISIBLE_COMMUNITY_CONTENDER: 'CommonBuffId' = 344046 - TRAIT_CHILD_OF_THE_SEA_VISIBLE_CONNECTED_ROOTS: 'CommonBuffId' = 341998 - TRAIT_CHILD_OF_THE_SEA_VISIBLE_GREAT_RELEASE: 'CommonBuffId' = 342000 - TRAIT_CHILD_OF_THE_SEA_VISIBLE_RELATIVELY_DISTANT: 'CommonBuffId' = 341618 - TRAIT_CHILD_SKILL_HEAD_STRONG: 'CommonBuffId' = 308832 - TRAIT_CHILD_SKILL_PACK_ANIMAL_MENTOR: 'CommonBuffId' = 308833 - TRAIT_CLEAR_PERSPECTIVE: 'CommonBuffId' = 308570 - TRAIT_CLIMATE_CHANGE_WOKE_HIDDEN: 'CommonBuffId' = 179875 - TRAIT_CLUMSY: 'CommonBuffId' = 12664 - TRAIT_CLUMSY_SILLY_ME: 'CommonBuffId' = 37733 - TRAIT_CLUMSY_SLIP_COOLDOWN: 'CommonBuffId' = 258226 - TRAIT_COLDHEARTED: 'CommonBuffId' = 275545 - TRAIT_COMMITMENTPHOBE_BROKE_UP: 'CommonBuffId' = 74407 - TRAIT_COMMITMENT_ISSUES: 'CommonBuffId' = 74339 - TRAIT_COMMITMENT_ISSUES_CAREER_COMMITMENT_HIDDEN: 'CommonBuffId' = 12666 - TRAIT_COMMITMENT_ISSUES_FEELING_TRAPPED_CAREER: 'CommonBuffId' = 74358 - TRAIT_COMMITMENT_ISSUES_FEELING_TRAPPED_REL: 'CommonBuffId' = 74397 - TRAIT_COMMITMENT_ISSUES_QUIT_JOB: 'CommonBuffId' = 12665 - TRAIT_COMMITMENT_ISSUES_QUIT_JOB_COOLDOWN: 'CommonBuffId' = 98332 - TRAIT_COMMITMENT_ISSUES_RELATIONSHIP_COMMITMENT_HIDDEN: 'CommonBuffId' = 74350 - TRAIT_COMPASSIONATE: 'CommonBuffId' = 160863 - TRAIT_COTTAGE_WORLD_NPC_AGNES_CRUMPLEBOTTOM_ANGRY: 'CommonBuffId' = 264153 - TRAIT_COTTAGE_WORLD_NPC_HEADLINE_AGATHA_CRUMPLEBOTTOM: 'CommonBuffId' = 262913 - TRAIT_COTTAGE_WORLD_NPC_HEADLINE_AGNES_CRUMPLEBOTTOM: 'CommonBuffId' = 262914 - TRAIT_COTTAGE_WORLD_NPC_HEADLINE_CRITTER_TENDER: 'CommonBuffId' = 262915 - TRAIT_COTTAGE_WORLD_NPC_HEADLINE_GROCERY_DELIVERY: 'CommonBuffId' = 262916 - TRAIT_COTTAGE_WORLD_NPC_HEADLINE_GROCERY_OWNER: 'CommonBuffId' = 262917 - TRAIT_COTTAGE_WORLD_NPC_HEADLINE_MAYOR: 'CommonBuffId' = 262918 - TRAIT_COTTAGE_WORLD_NPC_HEADLINE_PUB_OWNER: 'CommonBuffId' = 262919 - TRAIT_COUNTRY_CARETAKER: 'CommonBuffId' = 265331 - TRAIT_CREATIVE: 'CommonBuffId' = 12697 - TRAIT_CREATIVELY_GIFTED: 'CommonBuffId' = 29625 - TRAIT_CREATIVE_BEAUTIFUL_INSPIRATION: 'CommonBuffId' = 107954 - TRAIT_CREATIVE_LOW_CREATIVITY_HIDDEN: 'CommonBuffId' = 27167 - TRAIT_CREATIVE_UNCREATIVE: 'CommonBuffId' = 74668 - TRAIT_CRINGE: 'CommonBuffId' = 341155 - TRAIT_CULINARY_TRAINING: 'CommonBuffId' = 28694 - TRAIT_CURIOUS_ABOUT_CLUBS: 'CommonBuffId' = 125557 - TRAIT_DANCE_MACHINE: 'CommonBuffId' = 126089 - TRAIT_DANCE_MACHINE_PARTY_TIME_ENERGIZED: 'CommonBuffId' = 126103 - TRAIT_DANCE_MACHINE_READY_TO_PARTY: 'CommonBuffId' = 126123 - TRAIT_DANCE_MACHINE_WHERES_THE_PARTY: 'CommonBuffId' = 126181 - TRAIT_DANCE_MACHINE_WORK_LOOT: 'CommonBuffId' = 126200 - TRAIT_DASTARDLY: 'CommonBuffId' = 27098 - TRAIT_DAUNTLESS: 'CommonBuffId' = 283720 - TRAIT_DEBUG_OUTCOMES: 'CommonBuffId' = 258315 - TRAIT_DISCERNING_DWELLER_NEIGHBORLY: 'CommonBuffId' = 350270 - TRAIT_DOG_LOVER: 'CommonBuffId' = 157981 - TRAIT_DOG_LOVER_ADOPTION: 'CommonBuffId' = 174832 - TRAIT_DOG_LOVER_DEATH: 'CommonBuffId' = 174834 - TRAIT_DOG_LOVER_MET_NEW_DOG: 'CommonBuffId' = 158023 - TRAIT_DOG_LOVER_TAKEN: 'CommonBuffId' = 174833 - TRAIT_ECO_MASTER: 'CommonBuffId' = 234890 - TRAIT_ECO_MASTER_HEADLINE: 'CommonBuffId' = 241275 - TRAIT_ELDER: 'CommonBuffId' = 34527 - TRAIT_EMOTIONAL_CONTROL: 'CommonBuffId' = 160276 - TRAIT_ENTREPRENEUR: 'CommonBuffId' = 234891 - TRAIT_ENTREPRENEUR_HEADLINE: 'CommonBuffId' = 241277 - TRAIT_EP14_WORLD_NPC_HEADLINE_HORSE_TRAINER: 'CommonBuffId' = 323474 - TRAIT_EP14_WORLD_NPC_HEADLINE_MYSTERIOUS_RANCHER: 'CommonBuffId' = 323473 - TRAIT_EP14_WORLD_NPC_HORSE_TRAINER: 'CommonBuffId' = 321629 - TRAIT_EP14_WORLD_NPC_MYSTERIOUS_RANCHER: 'CommonBuffId' = 319493 - TRAIT_EP16_SPECIAL_NPC_THERING_BEAR: 'CommonBuffId' = 370190 - TRAIT_ESSENCE_OF_FLAVOR: 'CommonBuffId' = 26186 - TRAIT_EVIL: 'CommonBuffId' = 12672 - TRAIT_EVIL_HELPED_OTHERS: 'CommonBuffId' = 151266 - TRAIT_EVIL_NEAR_MISERY: 'CommonBuffId' = 30202 - TRAIT_EVIL_NEAR_MISERY_HIDDEN: 'CommonBuffId' = 74235 - TRAIT_EVIL_SUPPRESS_MANIACAL_LAUGH: 'CommonBuffId' = 98694 - TRAIT_EXPLORER: 'CommonBuffId' = 368634 - TRAIT_FAMILY_ORIENTED: 'CommonBuffId' = 12675 - TRAIT_FAMILY_ORIENTED_HIDDEN: 'CommonBuffId' = 74232 - TRAIT_FAMILY_ORIENTED_LOW_FAMILY_TIME_HIDDEN: 'CommonBuffId' = 74244 - TRAIT_FAMILY_ORIENTED_MISSING_FAMILY: 'CommonBuffId' = 30696 - TRAIT_FAMILY_ORIENTED_NEAR_FAMILY: 'CommonBuffId' = 10610 - TRAIT_FARTISAN_KNOCKOUT: 'CommonBuffId' = 12681 - TRAIT_FEELING_ANGRY: 'CommonBuffId' = 27207 - TRAIT_FEELING_CONFIDENT: 'CommonBuffId' = 9289 - TRAIT_FEELING_ENERGIZED: 'CommonBuffId' = 9331 - TRAIT_FEELING_FLIRTY: 'CommonBuffId' = 9305 - TRAIT_FEELING_FOCUSED: 'CommonBuffId' = 9294 - TRAIT_FEELING_HAPPY: 'CommonBuffId' = 9323 - TRAIT_FEELING_INSPIRED: 'CommonBuffId' = 9300 - TRAIT_FEELING_PLAYFUL: 'CommonBuffId' = 9341 - TRAIT_FEELING_SAD: 'CommonBuffId' = 9336 - TRAIT_FOODIE: 'CommonBuffId' = 27178 - TRAIT_FOODIE_INSPIRED_TV: 'CommonBuffId' = 34198 - TRAIT_FOREVER_FRESH: 'CommonBuffId' = 183032 - TRAIT_FOREVER_FULL: 'CommonBuffId' = 183031 - TRAIT_FORTUNE_INVESTED_GIVE_INTEREST_CHECK: 'CommonBuffId' = 77748 - TRAIT_FOX_DEFAULT: 'CommonBuffId' = 259923 - TRAIT_FREEGAN: 'CommonBuffId' = 234436 - TRAIT_FREEGAN_BADDEAL: 'CommonBuffId' = 234613 - TRAIT_FREEGAN_CONSUMERIST_SHAME: 'CommonBuffId' = 234614 - TRAIT_FREEGAN_CORPORATE_SELLOUT: 'CommonBuffId' = 234621 - TRAIT_FREEGAN_DISCOUNT_DENIED: 'CommonBuffId' = 237105 - TRAIT_FREEGAN_DISCOUNT_DENIED_FINAL: 'CommonBuffId' = 237110 - TRAIT_FREEGAN_FREED_FROM_RAT_RACE: 'CommonBuffId' = 234622 - TRAIT_FREEGAN_JUST_FINE: 'CommonBuffId' = 234618 - TRAIT_FREEGAN_LUCKY_FIND: 'CommonBuffId' = 234619 - TRAIT_FREEGAN_MEALS_ON_THE_CHEAP: 'CommonBuffId' = 234617 - TRAIT_FREEGAN_PREVENTED_FOOD_WASTE: 'CommonBuffId' = 234620 - TRAIT_FREEGAN_RECENTLY_DOVE_FOR_MEALS: 'CommonBuffId' = 237555 - TRAIT_FREEGAN_RUMMAGE_COOLDOWN: 'CommonBuffId' = 237077 - TRAIT_FREEGAN_SWEET_SAVINGS: 'CommonBuffId' = 234623 - TRAIT_FREEGAN_TOUGH_NEGOTIATOR: 'CommonBuffId' = 234624 - TRAIT_FREEGAN_UNNECESSARY_SPENDING: 'CommonBuffId' = 234616 - TRAIT_FREEGAN_URBAN_SQUATTER: 'CommonBuffId' = 234505 - TRAIT_FROM_PROXIMITY_CHILD_OF_THE_SEA_NEARBY_RELATIONSHIP: 'CommonBuffId' = 341619 - TRAIT_GEEK: 'CommonBuffId' = 12684 - TRAIT_GEEKY_CONVERSATION: 'CommonBuffId' = 12685 - TRAIT_GEEK_ALIEN_TV: 'CommonBuffId' = 107151 - TRAIT_GEEK_COLLECTED_SOMETHING: 'CommonBuffId' = 35518 - TRAIT_GEEK_LOW_GAMING_NEED_HIDDEN: 'CommonBuffId' = 27549 - TRAIT_GEEK_NEED_TO_GAME: 'CommonBuffId' = 74952 - TRAIT_GEEK_NEED_TO_GAME_ACTIVE: 'CommonBuffId' = 98089 - TRAIT_GEEK_OUT: 'CommonBuffId' = 27543 - TRAIT_GENEROUS: 'CommonBuffId' = 341201 - TRAIT_GENIUS: 'CommonBuffId' = 12687 - TRAIT_GENIUS_GIVE_EUREKA_MOMENT_SKILL: 'CommonBuffId' = 258365 - TRAIT_GENIUS_SOLVE_HARD_PROBLEMS_COOLDOWN: 'CommonBuffId' = 258253 - TRAIT_GENIUS_UNCHALLENGED: 'CommonBuffId' = 28782 - TRAIT_GENIUS_UNCHALLENGED_HIDDEN: 'CommonBuffId' = 75499 - TRAIT_GLOOMY: 'CommonBuffId' = 9333 - TRAIT_GLOOMY_NEAR_GHOSTS: 'CommonBuffId' = 258933 - TRAIT_GLOOMY_NEAR_GHOST_HIDDEN: 'CommonBuffId' = 258931 - TRAIT_GLUTTON: 'CommonBuffId' = 12689 - TRAIT_GOOD: 'CommonBuffId' = 30413 - TRAIT_GOOD_DID_GOOD: 'CommonBuffId' = 35774 - TRAIT_GOOD_GOOD_VIBES: 'CommonBuffId' = 30482 - TRAIT_GOOD_GOOD_VIBES_HIDDEN: 'CommonBuffId' = 74236 - TRAIT_GOOFBALL: 'CommonBuffId' = 9338 - TRAIT_GREAT_KISSER: 'CommonBuffId' = 26644 - TRAIT_GREAT_STORYTELLER_CONFIDENT: 'CommonBuffId' = 110161 - TRAIT_GREAT_STORYTELLER_ENERGIZED: 'CommonBuffId' = 110159 - TRAIT_GREAT_STORYTELLER_INSPIRATIONAL_STORY: 'CommonBuffId' = 110156 - TRAIT_GREAT_STORYTELLER_PLAYFUL: 'CommonBuffId' = 110163 - TRAIT_GREEN_FIEND: 'CommonBuffId' = 233724 - TRAIT_GREEN_FIEND_VISIBLE_CLEAN_AIR_SPACE: 'CommonBuffId' = 231698 - TRAIT_GREEN_FIEND_VISIBLE_GREENER_WORLD: 'CommonBuffId' = 233587 - TRAIT_GREEN_FIEND_VISIBLE_UNCONTROLLABLE_FOOTPRINT: 'CommonBuffId' = 231680 - TRAIT_GREEN_FIEND_VISIBLE_UNNATURAL_ENVIRONMENT: 'CommonBuffId' = 231697 - TRAIT_GREGARIOUS: 'CommonBuffId' = 27090 - TRAIT_HAPPY_TODDLER: 'CommonBuffId' = 143163 - TRAIT_HAPPY_TODDLER_REMINISCENT: 'CommonBuffId' = 143166 - TRAIT_HARDLY_HUNGRY: 'CommonBuffId' = 26374 - TRAIT_HATES_CHILDREN: 'CommonBuffId' = 76800 - TRAIT_HATES_CHILDREN_AWAY_FROM_CHILDREN: 'CommonBuffId' = 258866 - TRAIT_HATES_CHILDREN_HIDDEN: 'CommonBuffId' = 74233 - TRAIT_HATES_CHILDREN_TRY_FOR_BABY: 'CommonBuffId' = 31305 - TRAIT_HATES_INFANTS: 'CommonBuffId' = 333376 - TRAIT_HATES_TODDLERS_HIDDEN: 'CommonBuffId' = 157197 - TRAIT_HAUNTED_HOUSE_TEMPERANCE: 'CommonBuffId' = 256354 - TRAIT_HEART_TO_HEART_NEAR_HAPPY_COUPLES: 'CommonBuffId' = 368499 - TRAIT_HERBALISM_POTION_GRILL_MASTER: 'CommonBuffId' = 105308 - TRAIT_HERO_OF_STRANGER_VILLE: 'CommonBuffId' = 204512 - TRAIT_HERO_OF_STRANGER_VILLE_PACKAGE_SCHEDULE: 'CommonBuffId' = 204515 - TRAIT_HIDDEN_CONSPIRACY_THEORIST: 'CommonBuffId' = 201419 - TRAIT_HIDDEN_CURIO_SHOP: 'CommonBuffId' = 204872 - TRAIT_HIDDEN_INFECTED: 'CommonBuffId' = 201416 - TRAIT_HIDDEN_MILITARY: 'CommonBuffId' = 201418 - TRAIT_HIDDEN_SCIENTIST: 'CommonBuffId' = 201417 - TRAIT_HIDDEN_VETERAN_HERMIT: 'CommonBuffId' = 203138 - TRAIT_HIGH_MAINTENANCE_COOLDOWN_HIDDEN: 'CommonBuffId' = 272494 - TRAIT_HIGH_MAINTENANCE_HIDDEN: 'CommonBuffId' = 272270 - TRAIT_HIGH_MAINTENANCE_IN_SUN_HIDDEN: 'CommonBuffId' = 272458 - TRAIT_HIGH_MAINTENANCE_SOLVE_STRUGGLE: 'CommonBuffId' = 272576 - TRAIT_HIGH_MAINTENANCE_VISIBLE_BUTT_HURT: 'CommonBuffId' = 272342 - TRAIT_HIGH_MAINTENANCE_VISIBLE_CATHARSIS: 'CommonBuffId' = 272521 - TRAIT_HIGH_MAINTENANCE_VISIBLE_DRANK_POOL: 'CommonBuffId' = 272346 - TRAIT_HIGH_MAINTENANCE_VISIBLE_DRANK_SEA: 'CommonBuffId' = 272347 - TRAIT_HIGH_MAINTENANCE_VISIBLE_HANG_NAIL: 'CommonBuffId' = 272345 - TRAIT_HIGH_MAINTENANCE_VISIBLE_HATE_SUN: 'CommonBuffId' = 272344 - TRAIT_HIGH_MAINTENANCE_VISIBLE_SHAMPOO_EYES: 'CommonBuffId' = 272349 - TRAIT_HIGH_MAINTENANCE_VISIBLE_SPLASH_BACK: 'CommonBuffId' = 272348 - TRAIT_HIGH_MAINTENANCE_VISIBLE_WEIRD_DREAM: 'CommonBuffId' = 272341 - TRAIT_HIGH_MAINTENANCE_VISIBLE_WORST_DAY: 'CommonBuffId' = 272350 - TRAIT_HIGH_MAINTENANCE_WORST_DAY_COOLDOWN_HIDDEN: 'CommonBuffId' = 272519 - TRAIT_HIGH_METABOLISM: 'CommonBuffId' = 27088 - TRAIT_HIGH_SCHOOL_TEAM_CHEER_TEAM: 'CommonBuffId' = 277049 - TRAIT_HIGH_SCHOOL_TEAM_CHESS_TEAM: 'CommonBuffId' = 277051 - TRAIT_HIGH_SCHOOL_TEAM_COMPUTER_TEAM: 'CommonBuffId' = 277052 - TRAIT_HIGH_SCHOOL_TEAM_FOOTBALL_TEAM: 'CommonBuffId' = 277050 - TRAIT_HILARIOUS: 'CommonBuffId' = 27171 - TRAIT_HILARIOUS_DAZED: 'CommonBuffId' = 99856 - TRAIT_HOLIDAY_TRADITION_FATHER_WINTER: 'CommonBuffId' = 183344 - TRAIT_HOLIDAY_TRADITION_FATHER_WINTER_BABY: 'CommonBuffId' = 183366 - TRAIT_HOME_TURF: 'CommonBuffId' = 144200 - TRAIT_HOME_TURF_AM_I_HOME: 'CommonBuffId' = 144209 - TRAIT_HOME_TURF_HOME_SWEET_HOME: 'CommonBuffId' = 144211 - TRAIT_HOME_TURF_HOME_SWEET_HOME_COOL_DOWN: 'CommonBuffId' = 144934 - TRAIT_HORSES_AGE_ADULT: 'CommonBuffId' = 321106 - TRAIT_HORSES_AGE_CHILD: 'CommonBuffId' = 321105 - TRAIT_HORSES_AGE_ELDER: 'CommonBuffId' = 321107 - TRAIT_HORSE_GAMEPLAY_CURIOUS: 'CommonBuffId' = 323853 - TRAIT_HORSE_GAMEPLAY_EQUESTRIAN_CENTER_CHAMPION_HORSE: 'CommonBuffId' = 331652 - TRAIT_HORSE_GAMEPLAY_HORSE_BREEDING_CHAMPION_GENES: 'CommonBuffId' = 323126 - TRAIT_HORSE_GAMEPLAY_PLAYFUL: 'CommonBuffId' = 322885 - TRAIT_HORSE_GAMEPLAY_TOP_NOTCH_FOAL: 'CommonBuffId' = 330838 - TRAIT_HORSE_LOVER: 'CommonBuffId' = 320899 - TRAIT_HORSE_LOVER_HORSE_EMPATHY_ANGRY: 'CommonBuffId' = 320902 - TRAIT_HORSE_LOVER_HORSE_EMPATHY_HAPPY: 'CommonBuffId' = 320964 - TRAIT_HORSE_LOVER_HORSE_EMPATHY_SAD: 'CommonBuffId' = 320963 - TRAIT_HORSE_LOVER_NEED_HORSE_INTERACTION_TIMER: 'CommonBuffId' = 320967 - TRAIT_HORSE_PERSONALITY_AGGRESSIVE: 'CommonBuffId' = 323825 - TRAIT_HORSE_PERSONALITY_BRAVE: 'CommonBuffId' = 322833 - TRAIT_HORSE_PERSONALITY_DEFIANT: 'CommonBuffId' = 323829 - TRAIT_HORSE_PERSONALITY_ENERGETIC: 'CommonBuffId' = 322879 - TRAIT_HORSE_PERSONALITY_FEARFUL: 'CommonBuffId' = 322835 - TRAIT_HORSE_PERSONALITY_FREE_SPIRIT: 'CommonBuffId' = 323827 - TRAIT_HORSE_PERSONALITY_FREE_SPIRIT_INSIDE: 'CommonBuffId' = 336664 - TRAIT_HORSE_PERSONALITY_FRIENDLY: 'CommonBuffId' = 322877 - TRAIT_HORSE_PERSONALITY_INDEPENDENT: 'CommonBuffId' = 323828 - TRAIT_HORSE_PERSONALITY_INTELLIGENT: 'CommonBuffId' = 322883 - TRAIT_HORSE_PERSONALITY_MELLOW: 'CommonBuffId' = 322881 - TRAIT_HORSE_PERSONALITY_NEEDY: 'CommonBuffId' = 327818 - TRAIT_HORSE_PERSONALITY_RESILIENT: 'CommonBuffId' = 327596 - TRAIT_HORSE_PLAYFUL_WANTS_TOYS: 'CommonBuffId' = 322888 - TRAIT_HOT_HEADED: 'CommonBuffId' = 12691 - TRAIT_HOT_HEATED_RILED: 'CommonBuffId' = 27214 - TRAIT_ICONIC: 'CommonBuffId' = 287318 - TRAIT_INDEPENDENT: 'CommonBuffId' = 26386 - TRAIT_INFANT: 'CommonBuffId' = 271169 - TRAIT_INSANE: 'CommonBuffId' = 12694 - TRAIT_INSANE_ANGRY: 'CommonBuffId' = 31530 - TRAIT_INSANE_FLIRTY: 'CommonBuffId' = 31532 - TRAIT_INSANE_HAPPY: 'CommonBuffId' = 31529 - TRAIT_INSANE_PRETTY_GIRL: 'CommonBuffId' = 76855 - TRAIT_INSANE_PRETTY_GIRL_HIDDEN: 'CommonBuffId' = 76707 - TRAIT_INSANE_SAD: 'CommonBuffId' = 31531 - TRAIT_INSIDER: 'CommonBuffId' = 125439 - TRAIT_INSIDER_MAX_STATISTIC: 'CommonBuffId' = 389119 - TRAIT_IRRESPONSIBLE: 'CommonBuffId' = 317400 - TRAIT_ISLAND_ANCESTORS: 'CommonBuffId' = 204496 - TRAIT_ISLAND_ANCESTORS_ENERGIZED: 'CommonBuffId' = 212072 - TRAIT_ISLAND_ANCESTORS_SPIRIT_BLESS_COOLDOWN: 'CommonBuffId' = 211657 - TRAIT_ISLAND_ANCESTORS_SPIRIT_DISAPPOINTED: 'CommonBuffId' = 212268 - TRAIT_ISLAND_ANCESTORS_SPIRIT_ELEMENTAL: 'CommonBuffId' = 211594 - TRAIT_ISLAND_ANCESTORS_SPIRIT_ELEMENTAL_POWER: 'CommonBuffId' = 211711 - TRAIT_ISLAND_ANCESTORS_SPIRIT_METEOR_COOLDOWN: 'CommonBuffId' = 211670 - TRAIT_ISLAND_ANCESTORS_SPIRIT_PUDDLE_COOLDOWN: 'CommonBuffId' = 212254 - TRAIT_ISLAND_ANCESTORS_SPIRIT_ROLE_AUTONOMY_NEGATIVE_JUDGING: 'CommonBuffId' = 214845 - TRAIT_ISLAND_ANCESTORS_SPIRIT_ROLE_AUTONOMY_POSITIVE_JUDGING: 'CommonBuffId' = 214844 - TRAIT_ISLAND_ANCESTORS_SUMMON: 'CommonBuffId' = 211255 - TRAIT_ISLAND_ANCESTORS_VISIBLE_BLESSING_OF_FORTUNE: 'CommonBuffId' = 211204 - TRAIT_ISLAND_ANCESTORS_VISIBLE_BLESSING_OF_FORTUNE_2: 'CommonBuffId' = 211239 - TRAIT_ISLAND_ANCESTORS_VISIBLE_BLESSING_OF_FRIENDSHIP: 'CommonBuffId' = 211202 - TRAIT_ISLAND_ANCESTORS_VISIBLE_BLESSING_OF_FRIENDSHIP_2: 'CommonBuffId' = 211240 - TRAIT_ISLAND_ANCESTORS_VISIBLE_BLESSING_OF_LOVE: 'CommonBuffId' = 211203 - TRAIT_ISLAND_ANCESTORS_VISIBLE_BLESSING_OF_LOVE_2: 'CommonBuffId' = 211241 - TRAIT_ISLAND_ANCESTORS_VISIBLE_CHILD_BLESSING: 'CommonBuffId' = 212089 - TRAIT_ISLAND_ANCESTORS_VISIBLE_DIFFERENCE: 'CommonBuffId' = 211168 - TRAIT_ISLAND_ANCESTORS_VISIBLE_DISAPPOINTED: 'CommonBuffId' = 211231 - TRAIT_ISLAND_ANCESTORS_VISIBLE_FEELIN_VIBES: 'CommonBuffId' = 211167 - TRAIT_ISLAND_ANCESTORS_VISIBLE_INCLUDED: 'CommonBuffId' = 211164 - TRAIT_ISLAND_ANCESTORS_VISIBLE_ISLAND_RECIPE: 'CommonBuffId' = 211165 - TRAIT_ISLAND_ANCESTORS_VISIBLE_TASTE_OF_HOME: 'CommonBuffId' = 211166 - TRAIT_IS_GHOST: 'CommonBuffId' = 187112 - TRAIT_JEALOUS: 'CommonBuffId' = 124880 - TRAIT_JEALOUSY_TALK_THROUGH_ISSUES_COOLDOWN: 'CommonBuffId' = 259628 - TRAIT_JEALOUS_JEALOUS_FURY: 'CommonBuffId' = 126687 - TRAIT_JEALOUS_LOVE_ENVY: 'CommonBuffId' = 126644 - TRAIT_JEALOUS_LOW_SO_TIME_HIDDEN: 'CommonBuffId' = 124936 - TRAIT_JEALOUS_MISSING_SO: 'CommonBuffId' = 124888 - TRAIT_JEALOUS_NEAR_SO: 'CommonBuffId' = 124882 - TRAIT_JEALOUS_NEAR_SO_HIDDEN: 'CommonBuffId' = 124884 - TRAIT_JEALOUS_PANGS: 'CommonBuffId' = 127141 - TRAIT_KINDNESS_AMBASSADOR_HAS_BEEN_CHALLENGED_POSITIVITY: 'CommonBuffId' = 198890 - TRAIT_KLEPTOMANIAC: 'CommonBuffId' = 131785 - TRAIT_KLEPTO_CAUGHT_STEALING: 'CommonBuffId' = 132374 - TRAIT_KLEPTO_EXHILARATING_STEAL: 'CommonBuffId' = 132237 - TRAIT_KLEPTO_EXHILARATING_STEAL_LOW_VALUE_OBJECT: 'CommonBuffId' = 132750 - TRAIT_KLEPTO_EXHILARATING_STEAL_MED_VALUE_OBJECT: 'CommonBuffId' = 132751 - TRAIT_KLEPTO_NEED_TO_SWIPE: 'CommonBuffId' = 132230 - TRAIT_KLEPTO_NEED_TO_SWIPE_HIDDEN: 'CommonBuffId' = 132224 - TRAIT_KLEPTO_RETURN_STOLEN_OBJECT: 'CommonBuffId' = 132241 - TRAIT_KLEPTO_WITNESS_STEALING: 'CommonBuffId' = 132376 - TRAIT_LACTOSE_INTOLERANT: 'CommonBuffId' = 257636 - TRAIT_LACTOSE_INTOLERANT_ATE_DAIRY: 'CommonBuffId' = 257774 - TRAIT_LACTOSE_INTOLERANT_ATE_DAIRY_AGAIN: 'CommonBuffId' = 257775 - TRAIT_LACTOSE_INTOLERANT_HAPPY_EATING_DAIRY: 'CommonBuffId' = 257773 - TRAIT_LACTOSE_INTOLERANT_NO_DAIRY: 'CommonBuffId' = 257777 - TRAIT_LAZY: 'CommonBuffId' = 9600 - TRAIT_LAZY_CHORES: 'CommonBuffId' = 28981 - TRAIT_LAZY_NAP: 'CommonBuffId' = 28980 - TRAIT_LAZY_TV: 'CommonBuffId' = 28949 - TRAIT_LEGENDARY: 'CommonBuffId' = 27092 - TRAIT_LEGENDARY_LANDLORD_HOME_MANAGER: 'CommonBuffId' = 350267 - TRAIT_LIFE_SKILLS_BAD_MANNERS: 'CommonBuffId' = 160849 - TRAIT_LIFE_SKILLS_GOOD_MANNERS: 'CommonBuffId' = 160842 - TRAIT_LONER: 'CommonBuffId' = 9603 - TRAIT_LONER_IS_ALONE: 'CommonBuffId' = 38731 - TRAIT_LONER_NEAR_STRANGERS: 'CommonBuffId' = 30712 - TRAIT_LONER_NEAR_STRANGERS_HIDDEN: 'CommonBuffId' = 74237 - TRAIT_LONER_NOT_ALONE: 'CommonBuffId' = 38730 - TRAIT_LOVES_OUTDOORS: 'CommonBuffId' = 75297 - TRAIT_LOVES_OUTDOORS_AM_I_OUTSIDE: 'CommonBuffId' = 37465 - TRAIT_LOVES_OUTDOORS_BEAUTIFUL_OUTDOORS: 'CommonBuffId' = 107785 - TRAIT_LOVES_OUTDOORS_CAUGHT_CRITTER: 'CommonBuffId' = 111309 - TRAIT_LOVES_OUTDOORS_COOPED_UP: 'CommonBuffId' = 31348 - TRAIT_LOVES_OUTDOORS_FRESH_AIR: 'CommonBuffId' = 31347 - TRAIT_LOVES_OUTDOORS_LOW_INSIDE_HIDDEN: 'CommonBuffId' = 75442 - TRAIT_LOVES_OUTDOORS_PEACEFUL_WAKING: 'CommonBuffId' = 107786 - TRAIT_LOVE_STRUCK: 'CommonBuffId' = 362410 - TRAIT_LOVE_STRUCK_HIDDEN_NEAR_PARTNER_COOLDOWN: 'CommonBuffId' = 370604 - TRAIT_LOVE_STRUCK_VISIBLE_ETERNAL_OPTIMISIM: 'CommonBuffId' = 362096 - TRAIT_LOVE_STRUCK_VISIBLE_LOVERS_BLISS: 'CommonBuffId' = 362095 - TRAIT_LOVE_STRUCK_VISIBLE_UNREQUITED_LOVE: 'CommonBuffId' = 362097 - TRAIT_LOYAL: 'CommonBuffId' = 311268 - TRAIT_LOYAL_CALLED_OUT: 'CommonBuffId' = 317408 - TRAIT_LOYAL_CHEATING_CONFESSED: 'CommonBuffId' = 311762 - TRAIT_LOYAL_CHEATING_CONFESSED_TARGET: 'CommonBuffId' = 312085 - TRAIT_LOYAL_CHEATING_GUILT_REMINDER: 'CommonBuffId' = 311764 - TRAIT_LOYAL_CHEATING_KNOWN_REMINDER: 'CommonBuffId' = 312301 - TRAIT_LOYAL_CHEATING_SECRET_GUILT: 'CommonBuffId' = 311761 - TRAIT_LOYAL_CONFRONT_ACTOR_COOLDOWN: 'CommonBuffId' = 314552 - TRAIT_LOYAL_DOG_OWNER_BOND: 'CommonBuffId' = 314272 - TRAIT_LOYAL_FRIEND_IS_TARGET_MEAN_INTERACTION: 'CommonBuffId' = 314551 - TRAIT_LOYAL_GRIEVING: 'CommonBuffId' = 314271 - TRAIT_LOYAL_IN_RELATIONSHIP: 'CommonBuffId' = 315357 - TRAIT_LOYAL_LOYAL_EMPLOYEE: 'CommonBuffId' = 317128 - TRAIT_LOYAL_MEAN_ACTOR: 'CommonBuffId' = 315356 - TRAIT_LOYAL_OCCULT_BOND: 'CommonBuffId' = 316056 - TRAIT_LOYAL_PRINCIPLES: 'CommonBuffId' = 316202 - TRAIT_LOYAL_PROMISED_HELP: 'CommonBuffId' = 313883 - TRAIT_LOYAL_ROMANCED_TAKEN_LOYAL_SIM: 'CommonBuffId' = 312302 - TRAIT_LOYAL_SAFE_SECRET: 'CommonBuffId' = 317406 - TRAIT_LOYAL_SURROUNDED: 'CommonBuffId' = 313587 - TRAIT_LOYAL_TRASH_TALKING_CONFESSED: 'CommonBuffId' = 312042 - TRAIT_LOYAL_TRASH_TALKING_GUILT: 'CommonBuffId' = 312043 - TRAIT_LOYAL_TRUST_REBUILT: 'CommonBuffId' = 311763 - TRAIT_LOYAL_TRUST_REBUILT_FAIL: 'CommonBuffId' = 312660 - TRAIT_LOYAL_TRUST_REBUILT_TARGET_COOLDOWN: 'CommonBuffId' = 312661 - TRAIT_LOYAL_WITNESSED_MEAN_BULLY: 'CommonBuffId' = 312055 - TRAIT_LOYAL_WITNESSED_MEAN_FRIEND: 'CommonBuffId' = 312056 - TRAIT_MAKER: 'CommonBuffId' = 230746 - TRAIT_MAKER_NPC: 'CommonBuffId' = 234892 - TRAIT_MAKER_NPC_HEADLINE: 'CommonBuffId' = 241274 - TRAIT_MAKER_VISIBLE_IDLE_HANDS: 'CommonBuffId' = 230751 - TRAIT_MAKER_VISIBLE_MAKIN_MATERIALS: 'CommonBuffId' = 230750 - TRAIT_MAKE_PREGNANT: 'CommonBuffId' = 238606 - TRAIT_MASTER_TRAINER: 'CommonBuffId' = 321398 - TRAIT_MATERIALISTIC: 'CommonBuffId' = 37716 - TRAIT_MATERIALISTIC_JUST_ADMIRED: 'CommonBuffId' = 35960 - TRAIT_MATERIALISTIC_JUST_ADMIRED2: 'CommonBuffId' = 75741 - TRAIT_MATERIALISTIC_JUST_ADMIRED3: 'CommonBuffId' = 75742 - TRAIT_MATERIALISTIC_NEED_TO_ADMIRE_HIDDEN: 'CommonBuffId' = 35961 - TRAIT_MATERIALISTIC_WANT_NEW_STUFF: 'CommonBuffId' = 75750 - TRAIT_MEAN: 'CommonBuffId' = 12700 - TRAIT_MEDIATOR: 'CommonBuffId' = 163098 - TRAIT_MELT_MASTER: 'CommonBuffId' = 132339 - TRAIT_MEMORABLE: 'CommonBuffId' = 32428 - TRAIT_MENTALLY_GIFTED: 'CommonBuffId' = 29627 - TRAIT_MISS_HANGING_OUT: 'CommonBuffId' = 125556 - TRAIT_MORNING_PERSON: 'CommonBuffId' = 32427 - TRAIT_MORNING_PERSON_ACTIVE: 'CommonBuffId' = 97673 - TRAIT_MORNING_PERSON_CHECK_ACTIVE: 'CommonBuffId' = 97685 - TRAIT_MUSEUM_PATRON_CONFIDENT: 'CommonBuffId' = 179088 - TRAIT_MUSEUM_PATRON_DONATED_TO_MUSEUM: 'CommonBuffId' = 179095 - TRAIT_MUSEUM_PATRON_FLIRTY: 'CommonBuffId' = 179089 - TRAIT_MUSIC_LOVER: 'CommonBuffId' = 9605 - TRAIT_MUSIC_LOVER_INSPIRED: 'CommonBuffId' = 35895 - TRAIT_MUSIC_LOVER_MUSIC_NEED_HIDDEN_TRIGGER: 'CommonBuffId' = 74088 - TRAIT_MUSIC_LOVER_NO_MUSIC: 'CommonBuffId' = 29315 - TRAIT_MUSIC_LOVER_PLAYING_MUSIC: 'CommonBuffId' = 29340 - TRAIT_NEAT: 'CommonBuffId' = 12701 - TRAIT_NEAT_CLEANING_FRENZY: 'CommonBuffId' = 35965 - TRAIT_NEAT_NEUROTIC_CLEAN: 'CommonBuffId' = 258246 - TRAIT_NEAT_TOO_MUCH_DIRT: 'CommonBuffId' = 107827 - TRAIT_NECTAR_KNOW_IT_ALL: 'CommonBuffId' = 340827 - TRAIT_NECTAR_KNOW_IT_ALL_DRUNK_NECTAR_SOOTH: 'CommonBuffId' = 340986 - TRAIT_NEEDS_NO_ONE: 'CommonBuffId' = 183030 - TRAIT_NEVER_WEARY: 'CommonBuffId' = 26378 - TRAIT_NIGHT_OWL: 'CommonBuffId' = 32425 - TRAIT_NIGHT_OWL_ACTIVE: 'CommonBuffId' = 97698 - TRAIT_NIGHT_OWL_CHECK_ACTIVE: 'CommonBuffId' = 97700 - TRAIT_NOSY: 'CommonBuffId' = 341157 - TRAIT_NPC_POLICE_ASSISTANT: 'CommonBuffId' = 114514 - TRAIT_NPC_POLICE_OFFICER: 'CommonBuffId' = 106176 - TRAIT_OUTGOING: 'CommonBuffId' = 29572 - TRAIT_OVER_ACHIEVER: 'CommonBuffId' = 284366 - TRAIT_OVER_ACHIEVER_CRAFTED_POOR_QUALITY: 'CommonBuffId' = 284143 - TRAIT_OVER_ACHIEVER_EXTRA_CREDIT_AVAILABLE: 'CommonBuffId' = 284513 - TRAIT_OVER_ACHIEVER_EYE_ROLL: 'CommonBuffId' = 284138 - TRAIT_OVER_ACHIEVER_FINISH_CAREER_TASK: 'CommonBuffId' = 284141 - TRAIT_OVER_ACHIEVER_FORGET_CAREER_TASK: 'CommonBuffId' = 284140 - TRAIT_OVER_ACHIEVER_NEARBY_OVER_ACHIEVER: 'CommonBuffId' = 284139 - TRAIT_OVER_ACHIEVER_NO_SKILL_UP: 'CommonBuffId' = 284142 - TRAIT_OVER_ACHIEVER_PREPARED_FAIL: 'CommonBuffId' = 284136 - TRAIT_OVER_ACHIEVER_PREPARED_SUCCESS_ENERGIZED: 'CommonBuffId' = 284137 - TRAIT_OVER_ACHIEVER_PREPARED_SUCCESS_FOCUSED: 'CommonBuffId' = 284151 - TRAIT_OVER_ACHIEVER_PREPARED_SUCCESS_INSPIRED: 'CommonBuffId' = 284150 - TRAIT_OVER_ACHIEVER_SKILL_MAX: 'CommonBuffId' = 284144 - TRAIT_OVER_ACHIEVER_SKILL_UP: 'CommonBuffId' = 284145 - TRAIT_PARANOID: 'CommonBuffId' = 203545 - TRAIT_PARANOID_COMPUTER_LOOK_UP_CONSPIRACY_THEORIES_ANGRY: 'CommonBuffId' = 203771 - TRAIT_PARANOID_COMPUTER_LOOK_UP_CONSPIRACY_THEORIES_CONFIDENT: 'CommonBuffId' = 203769 - TRAIT_PARANOID_COMPUTER_LOOK_UP_CONSPIRACY_THEORIES_TENSE: 'CommonBuffId' = 203770 - TRAIT_PARANOID_FROM_BEING_UNDERGROUND: 'CommonBuffId' = 203674 - TRAIT_PARANOID_FROM_OTHERS_TALKING: 'CommonBuffId' = 203630 - TRAIT_PARANOID_UNDERGROUND_CHECK_TIMER: 'CommonBuffId' = 203762 - TRAIT_PARTY_ANIMAL: 'CommonBuffId' = 284365 - TRAIT_PARTY_ANIMAL_AT_PARTY: 'CommonBuffId' = 284133 - TRAIT_PARTY_ANIMAL_AT_PARTY_AFTER_EFFECT: 'CommonBuffId' = 284876 - TRAIT_PARTY_ANIMAL_LARGE_SOCIAL_GROUP_HIDDEN: 'CommonBuffId' = 284842 - TRAIT_PARTY_ANIMAL_MISSED_PARTY: 'CommonBuffId' = 284131 - TRAIT_PARTY_ANIMAL_NO_PARTY_RECENTLY: 'CommonBuffId' = 284132 - TRAIT_PARTY_ANIMAL_PARTY_MEMORY_CONFIDENT: 'CommonBuffId' = 284126 - TRAIT_PARTY_ANIMAL_PARTY_MEMORY_ENERGIZED: 'CommonBuffId' = 284134 - TRAIT_PARTY_ANIMAL_PARTY_MEMORY_FAIL: 'CommonBuffId' = 284128 - TRAIT_PARTY_ANIMAL_PARTY_MEMORY_FOCUSED: 'CommonBuffId' = 284135 - TRAIT_PARTY_ANIMAL_PARTY_MEMORY_HAPPY: 'CommonBuffId' = 284127 - TRAIT_PARTY_ANIMAL_PARTY_MEMORY_INSPIRED: 'CommonBuffId' = 284125 - TRAIT_PARTY_ANIMAL_REJECTED_WOOOO: 'CommonBuffId' = 284124 - TRAIT_PARTY_ANIMAL_VIBE_CHECK_FAIL: 'CommonBuffId' = 284129 - TRAIT_PARTY_ANIMAL_VIBE_CHECK_SUCCESS: 'CommonBuffId' = 284130 - TRAIT_PARTY_ANIMAL_WOOOO_AUTONOMOUS_COOLDOWN_HIDDEN: 'CommonBuffId' = 290197 - TRAIT_PARTY_ANIMAL_WOOOO_TRACKER_HIDDEN: 'CommonBuffId' = 284832 - TRAIT_PATIENT: 'CommonBuffId' = 26375 - TRAIT_PERFECTIONIST: 'CommonBuffId' = 9618 - TRAIT_PERFECTIONIST_FOCUSED_PAY_OFF: 'CommonBuffId' = 258755 - TRAIT_PERFECTIONIST_IN_THE_ZONE: 'CommonBuffId' = 258633 - TRAIT_PERFECTIONIST_NO_RETRY_COOLDOWN: 'CommonBuffId' = 258842 - TRAIT_PERFECTIONIST_OUTSTANDING: 'CommonBuffId' = 33777 - TRAIT_PERFECTIONIST_POOR: 'CommonBuffId' = 33778 - TRAIT_PERFECTIONIST_QUALITY_INCREASE: 'CommonBuffId' = 258757 - TRAIT_PERFECTIONIST_RETRY_COOLDOWN: 'CommonBuffId' = 258590 - TRAIT_PERSONALITY_RECYCLE_DISCIPLE_REQUIRED_TO_RECYCLE: 'CommonBuffId' = 232796 - TRAIT_PERSONALITY_RECYCLE_DISCIPLE_RUMMAGE_COOLDOWN: 'CommonBuffId' = 232792 - TRAIT_PERSONALITY_RECYCLE_DISCIPLE_SALVAGE_THRILLS: 'CommonBuffId' = 232794 - TRAIT_PERSONALITY_RECYCLE_DISCIPLE_SCOLDED_TIMER: 'CommonBuffId' = 241625 - TRAIT_PERSONALITY_RECYCLE_DISCIPLE_STRAINING_TO_SCOUR: 'CommonBuffId' = 232795 - TRAIT_PERSONALITY_RECYCLE_DISCIPLE_UNDISCIPLINED_CRAVING: 'CommonBuffId' = 232797 - TRAIT_PET_ACTIVE: 'CommonBuffId' = 158205 - TRAIT_PET_ACTIVE_CAT: 'CommonBuffId' = 176165 - TRAIT_PET_AGE_ADULT: 'CommonBuffId' = 167110 - TRAIT_PET_AGE_CHILD: 'CommonBuffId' = 167108 - TRAIT_PET_AGE_ELDER: 'CommonBuffId' = 167109 - TRAIT_PET_AGGRESSIVE: 'CommonBuffId' = 158789 - TRAIT_PET_CURIOUS: 'CommonBuffId' = 158214 - TRAIT_PET_FRIENDLY: 'CommonBuffId' = 158786 - TRAIT_PET_GLUTTON: 'CommonBuffId' = 159983 - TRAIT_PET_HAIRY: 'CommonBuffId' = 158793 - TRAIT_PET_HUNTER: 'CommonBuffId' = 159985 - TRAIT_PET_INDEPENDENT: 'CommonBuffId' = 158791 - TRAIT_PET_LAZY: 'CommonBuffId' = 158206 - TRAIT_PET_NAUGHTY: 'CommonBuffId' = 159984 - TRAIT_PET_PLAYFUL: 'CommonBuffId' = 164047 - TRAIT_PET_PLAYFUL_TRAIT_INTERACTION: 'CommonBuffId' = 190999 - TRAIT_PET_PROTECTIVE: 'CommonBuffId' = 158792 - TRAIT_PET_QUIRK_FEAR_BREWER: 'CommonBuffId' = 160874 - TRAIT_PET_QUIRK_FEAR_COMPUTER: 'CommonBuffId' = 160875 - TRAIT_PET_QUIRK_FEAR_DISHWASHER: 'CommonBuffId' = 160885 - TRAIT_PET_QUIRK_FEAR_FIRE: 'CommonBuffId' = 160886 - TRAIT_PET_QUIRK_FEAR_FITNESS_EQUIPMENT: 'CommonBuffId' = 160887 - TRAIT_PET_QUIRK_FEAR_GAMING: 'CommonBuffId' = 160876 - TRAIT_PET_QUIRK_FEAR_INSTRUMENT: 'CommonBuffId' = 160877 - TRAIT_PET_QUIRK_FEAR_MICROWAVE: 'CommonBuffId' = 160878 - TRAIT_PET_QUIRK_FEAR_ROBOT_VACUUM: 'CommonBuffId' = 171325 - TRAIT_PET_QUIRK_FEAR_SHOWER: 'CommonBuffId' = 160879 - TRAIT_PET_QUIRK_FEAR_STEREO: 'CommonBuffId' = 160880 - TRAIT_PET_QUIRK_FEAR_SWIMMING: 'CommonBuffId' = 171911 - TRAIT_PET_QUIRK_FEAR_TOILET: 'CommonBuffId' = 160882 - TRAIT_PET_QUIRK_FEAR_TV: 'CommonBuffId' = 160883 - TRAIT_PET_QUIRK_FEAR_VACUUM: 'CommonBuffId' = 257146 - TRAIT_PET_QUIRK_OBSESS_BREWER: 'CommonBuffId' = 160804 - TRAIT_PET_QUIRK_OBSESS_COMPUTER: 'CommonBuffId' = 160805 - TRAIT_PET_QUIRK_OBSESS_COOKING: 'CommonBuffId' = 160814 - TRAIT_PET_QUIRK_OBSESS_DISHWASHER: 'CommonBuffId' = 160815 - TRAIT_PET_QUIRK_OBSESS_DOORBELL: 'CommonBuffId' = 160816 - TRAIT_PET_QUIRK_OBSESS_FIRE: 'CommonBuffId' = 160817 - TRAIT_PET_QUIRK_OBSESS_FISH_TANK: 'CommonBuffId' = 160806 - TRAIT_PET_QUIRK_OBSESS_FITNESS_EQUIPMENT: 'CommonBuffId' = 160807 - TRAIT_PET_QUIRK_OBSESS_FRIDGE: 'CommonBuffId' = 160808 - TRAIT_PET_QUIRK_OBSESS_GAMING: 'CommonBuffId' = 160809 - TRAIT_PET_QUIRK_OBSESS_INSTRUMENT: 'CommonBuffId' = 160810 - TRAIT_PET_QUIRK_OBSESS_MICROWAVE: 'CommonBuffId' = 160811 - TRAIT_PET_QUIRK_OBSESS_PET_MINOR_CAGE: 'CommonBuffId' = 184411 - TRAIT_PET_QUIRK_OBSESS_ROBOT_VACUUM: 'CommonBuffId' = 171326 - TRAIT_PET_QUIRK_OBSESS_SHOWER: 'CommonBuffId' = 160812 - TRAIT_PET_QUIRK_OBSESS_STEREO: 'CommonBuffId' = 160813 - TRAIT_PET_QUIRK_OBSESS_TOILET: 'CommonBuffId' = 160818 - TRAIT_PET_QUIRK_OBSESS_TV: 'CommonBuffId' = 160784 - TRAIT_PET_QUIRK_OBSESS_VACUUM: 'CommonBuffId' = 257150 - TRAIT_PET_SKITTISH: 'CommonBuffId' = 158787 - TRAIT_PET_SMART: 'CommonBuffId' = 158790 - TRAIT_PET_STUBBORN: 'CommonBuffId' = 158215 - TRAIT_PET_VOCAL: 'CommonBuffId' = 158788 - TRAIT_PET_WANDERLUST: 'CommonBuffId' = 158707 - TRAIT_PIPER_CAROL_OF_CLEANING: 'CommonBuffId' = 28069 - TRAIT_PLANT_SIM: 'CommonBuffId' = 162669 - TRAIT_POLY: 'CommonBuffId' = 368635 - TRAIT_PRACTICE_MAKES_PERFECT_CHILD_HIDDEN: 'CommonBuffId' = 374055 - TRAIT_PRACTICE_MAKES_PERFECT_CLEAR_MIND_INSPIRED: 'CommonBuffId' = 369453 - TRAIT_PRACTICE_MAKES_PERFECT_CREATIVE_TIER_0_HIDDEN: 'CommonBuffId' = 371144 - TRAIT_PRACTICE_MAKES_PERFECT_CREATIVE_TIER_1_HIDDEN: 'CommonBuffId' = 371069 - TRAIT_PRACTICE_MAKES_PERFECT_CREATIVE_TIER_2_HIDDEN: 'CommonBuffId' = 371070 - TRAIT_PRACTICE_MAKES_PERFECT_CREATIVE_TIER_3_HIDDEN: 'CommonBuffId' = 371071 - TRAIT_PRACTICE_MAKES_PERFECT_CREATIVE_TIER_4_HIDDEN: 'CommonBuffId' = 371145 - TRAIT_PRACTICE_MAKES_PERFECT_HIDDEN: 'CommonBuffId' = 369246 - TRAIT_PRACTICE_MAKES_PERFECT_LACK_OF_PRACTICE_SAD: 'CommonBuffId' = 370198 - TRAIT_PRACTICE_MAKES_PERFECT_LACK_OF_PRACTICE_SAD_MENTAL: 'CommonBuffId' = 381232 - TRAIT_PRACTICE_MAKES_PERFECT_LACK_OF_PRACTICE_SAD_PHYSICAL: 'CommonBuffId' = 381234 - TRAIT_PRACTICE_MAKES_PERFECT_LACK_OF_PRACTICE_SAD_SOCIAL: 'CommonBuffId' = 381233 - TRAIT_PRACTICE_MAKES_PERFECT_LIFE_HACK_INSPIRED: 'CommonBuffId' = 370159 - TRAIT_PRACTICE_MAKES_PERFECT_MENTAL_TIER_0_HIDDEN: 'CommonBuffId' = 371240 - TRAIT_PRACTICE_MAKES_PERFECT_MENTAL_TIER_1_HIDDEN: 'CommonBuffId' = 371139 - TRAIT_PRACTICE_MAKES_PERFECT_MENTAL_TIER_2_HIDDEN: 'CommonBuffId' = 371140 - TRAIT_PRACTICE_MAKES_PERFECT_MENTAL_TIER_3_HIDDEN: 'CommonBuffId' = 371141 - TRAIT_PRACTICE_MAKES_PERFECT_MENTAL_TIER_4_HIDDEN: 'CommonBuffId' = 371239 - TRAIT_PRACTICE_MAKES_PERFECT_MINDFUL_FOCUSED: 'CommonBuffId' = 370158 - TRAIT_PRACTICE_MAKES_PERFECT_ON_A_ROLL_FOCUSED: 'CommonBuffId' = 369240 - TRAIT_PRACTICE_MAKES_PERFECT_ON_A_ROLL_FOCUSED_MENTAL: 'CommonBuffId' = 381222 - TRAIT_PRACTICE_MAKES_PERFECT_ON_A_ROLL_FOCUSED_PHYSICAL: 'CommonBuffId' = 381223 - TRAIT_PRACTICE_MAKES_PERFECT_ON_A_ROLL_FOCUSED_SOCIAL: 'CommonBuffId' = 381224 - TRAIT_PRACTICE_MAKES_PERFECT_PAUSE_FOR_CLARITY_COOLDOWN: 'CommonBuffId' = 372129 - TRAIT_PRACTICE_MAKES_PERFECT_PERFECTED_FOCUSED: 'CommonBuffId' = 370200 - TRAIT_PRACTICE_MAKES_PERFECT_PERFECT_FOCUSED: 'CommonBuffId' = 370199 - TRAIT_PRACTICE_MAKES_PERFECT_PERFECT_FOCUSED_MENTAL: 'CommonBuffId' = 381235 - TRAIT_PRACTICE_MAKES_PERFECT_PERFECT_FOCUSED_PHYSICAL: 'CommonBuffId' = 381236 - TRAIT_PRACTICE_MAKES_PERFECT_PERFECT_FOCUSED_SOCIAL: 'CommonBuffId' = 381237 - TRAIT_PRACTICE_MAKES_PERFECT_PHYSICAL_TIER_0_HIDDEN: 'CommonBuffId' = 371242 - TRAIT_PRACTICE_MAKES_PERFECT_PHYSICAL_TIER_1_HIDDEN: 'CommonBuffId' = 371243 - TRAIT_PRACTICE_MAKES_PERFECT_PHYSICAL_TIER_2_HIDDEN: 'CommonBuffId' = 371244 - TRAIT_PRACTICE_MAKES_PERFECT_PHYSICAL_TIER_3_HIDDEN: 'CommonBuffId' = 371245 - TRAIT_PRACTICE_MAKES_PERFECT_PHYSICAL_TIER_4_HIDDEN: 'CommonBuffId' = 371246 - TRAIT_PRACTICE_MAKES_PERFECT_PRACTICE_SKILL_WHIM_HIDDEN: 'CommonBuffId' = 376449 - TRAIT_PRACTICE_MAKES_PERFECT_SOCIAL_TIER_0_HIDDEN: 'CommonBuffId' = 371248 - TRAIT_PRACTICE_MAKES_PERFECT_SOCIAL_TIER_1_HIDDEN: 'CommonBuffId' = 371249 - TRAIT_PRACTICE_MAKES_PERFECT_SOCIAL_TIER_2_HIDDEN: 'CommonBuffId' = 371250 - TRAIT_PRACTICE_MAKES_PERFECT_SOCIAL_TIER_3_HIDDEN: 'CommonBuffId' = 371251 - TRAIT_PRACTICE_MAKES_PERFECT_SOCIAL_TIER_4_HIDDEN: 'CommonBuffId' = 371252 - TRAIT_PRACTICE_MAKES_PERFECT_SO_BORING_BORED: 'CommonBuffId' = 370197 - TRAIT_PRACTICE_MAKES_PERFECT_WHIM_TRACKER_HIDDEN: 'CommonBuffId' = 372621 - TRAIT_PROFESSIONAL_SLACKER: 'CommonBuffId' = 308566 - TRAIT_PROPER: 'CommonBuffId' = 251987 - TRAIT_PROPER_CAREER_FIRED: 'CommonBuffId' = 252080 - TRAIT_PROPER_CAREER_MISSING_WORK: 'CommonBuffId' = 252082 - TRAIT_PROPER_CAREER_POOR_PERFORMANCE: 'CommonBuffId' = 252084 - TRAIT_PROPER_CAREER_PROMOTION: 'CommonBuffId' = 252083 - TRAIT_PROPER_CAREER_QUIT: 'CommonBuffId' = 252081 - TRAIT_PROPER_FORMAL_WEAR: 'CommonBuffId' = 252078 - TRAIT_PROPER_LOST_FIGHT: 'CommonBuffId' = 252292 - TRAIT_PROPER_WITNESSED_BEHAVIOR: 'CommonBuffId' = 252296 - TRAIT_PROPER_WON_FIGHT: 'CommonBuffId' = 252291 - TRAIT_QUICK_LEARNER: 'CommonBuffId' = 27106 - TRAIT_RANCHER: 'CommonBuffId' = 320972 - TRAIT_RANCHER_NEED_RANCH_INTERACTION_TIMER: 'CommonBuffId' = 320973 - TRAIT_RANCHER_RANCH_CHORES_EMBARASSED: 'CommonBuffId' = 320990 - TRAIT_RANCHER_RANCH_CHORES_HAPPY: 'CommonBuffId' = 320989 - TRAIT_RECYCLE_DISCIPLE: 'CommonBuffId' = 232714 - TRAIT_RECYCLE_DISCIPLE_CAUGHT_STEALING: 'CommonBuffId' = 232743 - TRAIT_RECYCLE_DISCIPLE_REQUIRED_CONTROLLER_HIDDEN: 'CommonBuffId' = 239443 - TRAIT_RELATABLE: 'CommonBuffId' = 282772 - TRAIT_RESPONSIBLE: 'CommonBuffId' = 329368 - TRAIT_REWARD_NEW_IN_TOWN_INSPIRED_EXPLORER: 'CommonBuffId' = 297770 - TRAIT_ROMANTIC: 'CommonBuffId' = 9302 - TRAIT_ROMANTICALLY_RESERVED: 'CommonBuffId' = 361648 - TRAIT_ROMANTICALLY_RESERVED_HIDDEN: 'CommonBuffId' = 361649 - TRAIT_ROMANTICALLY_RESERVED_HONORING_MYSELF: 'CommonBuffId' = 361972 - TRAIT_ROMANTICALLY_RESERVED_NEAR_ROMANCE_COOLDOWN_HIDDEN: 'CommonBuffId' = 370603 - TRAIT_ROMANTICALLY_RESERVED_ROMANTIC_YEARNING: 'CommonBuffId' = 361970 - TRAIT_ROMANTICALLY_RESERVED_UNWANTED_ADVANCES: 'CommonBuffId' = 361971 - TRAIT_ROMANTIC_CHARMED_BY_NATURE: 'CommonBuffId' = 107886 - TRAIT_ROMANTIC_LOVELORN: 'CommonBuffId' = 27518 - TRAIT_ROMANTIC_LOVELORN_HIDDEN: 'CommonBuffId' = 75034 - TRAIT_ROMANTIC_SAGE: 'CommonBuffId' = 378264 - TRAIT_SAVANT: 'CommonBuffId' = 39879 - TRAIT_SELDOM_SLEEPY: 'CommonBuffId' = 183028 - TRAIT_SELF_ABSORBED: 'CommonBuffId' = 317399 - TRAIT_SELF_ABSORBED_ATTENDING_ACTING_GIG: 'CommonBuffId' = 200009 - TRAIT_SELF_ABSORBED_FLATTERED: 'CommonBuffId' = 199776 - TRAIT_SELF_ABSORBED_FOR_ME: 'CommonBuffId' = 199779 - TRAIT_SELF_ABSORBED_GREAT_FRIENDS_I_HAVE: 'CommonBuffId' = 199778 - TRAIT_SELF_ABSORBED_HUNGRY_FOR_ATTENTION: 'CommonBuffId' = 199777 - TRAIT_SELF_ABSORBED_LACKING_ANONYMOUS_ATTENTION: 'CommonBuffId' = 199781 - TRAIT_SELF_ABSORBED_OUT_OF_SPOTLIGHT: 'CommonBuffId' = 199587 - TRAIT_SELF_ABSORBED_PICTURE_WORTHY: 'CommonBuffId' = 199714 - TRAIT_SELF_ABSORBED_POPULAR: 'CommonBuffId' = 199782 - TRAIT_SELF_ABSORBED_RECOGNIZED_ICON: 'CommonBuffId' = 199710 - TRAIT_SELF_ABSORBED_RESET_TIMER_NO_DEBUFF: 'CommonBuffId' = 203081 - TRAIT_SELF_ABSORBED_SIMSTA_FAMOUS: 'CommonBuffId' = 199783 - TRAIT_SELF_ABSORBED_SPOTLIGHT_READY: 'CommonBuffId' = 199729 - TRAIT_SELF_ASSURED: 'CommonBuffId' = 12652 - TRAIT_SINCERE: 'CommonBuffId' = 26904 - TRAIT_SLOB: 'CommonBuffId' = 12702 - TRAIT_SLOB_NATURAL_DIRT: 'CommonBuffId' = 108424 - TRAIT_SNOB: 'CommonBuffId' = 9622 - TRAIT_SNOB_NOT_ENOUGH_CULTURE: 'CommonBuffId' = 107828 - TRAIT_SNOB_UNITY: 'CommonBuffId' = 31905 - TRAIT_SNOB_UNITY_HIDDEN: 'CommonBuffId' = 74238 - TRAIT_SOCIALLY_AWKWARD: 'CommonBuffId' = 272886 - TRAIT_SOCIALLY_AWKWARD_HIDDEN_EXPRESS_NERVOUSNESS_AROUND_NEW_SIMS_COOLDOWN: 'CommonBuffId' = 295125 - TRAIT_SOCIALLY_AWKWARD_HIDDEN_ITS_OKAY_TO_BE_A_LITTLE_AWKWARD_COOLDOWN: 'CommonBuffId' = 272899 - TRAIT_SOCIALLY_AWKWARD_VISIBLE_BEFRIENDED_COWORKER: 'CommonBuffId' = 272901 - TRAIT_SOCIALLY_AWKWARD_VISIBLE_CENTER_OF_ATTENTION: 'CommonBuffId' = 272897 - TRAIT_SOCIALLY_AWKWARD_VISIBLE_COOLEST_KID_IN_SCHOOL: 'CommonBuffId' = 272903 - TRAIT_SOCIALLY_AWKWARD_VISIBLE_FEELING_ENCOURAGED: 'CommonBuffId' = 272896 - TRAIT_SOCIALLY_AWKWARD_VISIBLE_FEELING_OVERWHELMED: 'CommonBuffId' = 272893 - TRAIT_SOCIALLY_AWKWARD_VISIBLE_FEELING_UNDERSTOOD: 'CommonBuffId' = 272904 - TRAIT_SOCIALLY_AWKWARD_VISIBLE_INTIMIDATING_ENVIRONMENT: 'CommonBuffId' = 272895 - TRAIT_SOCIALLY_AWKWARD_VISIBLE_THAT_DID_NOT_GO_AS_PLANNED: 'CommonBuffId' = 272902 - TRAIT_SOCIALLY_AWKWARD_VISIBLE__WITH_MY_PEOPLE: 'CommonBuffId' = 272894 - TRAIT_SOCIALLY_GIFTED: 'CommonBuffId' = 29624 - TRAIT_SPECIES_CAT: 'CommonBuffId' = 144675 - TRAIT_SPECIES_DOG: 'CommonBuffId' = 131197 - TRAIT_SPECIES_EXTENDED_LARGE_DOG: 'CommonBuffId' = 173770 - TRAIT_SPECIES_EXTENDED_SMALL_DOG: 'CommonBuffId' = 173771 - TRAIT_SPEED_CLEANER: 'CommonBuffId' = 26620 - TRAIT_SPEED_READER: 'CommonBuffId' = 32627 - TRAIT_SQUEAMISH: 'CommonBuffId' = 102339 - TRAIT_SQUEAMISH_EWW_GROSS: 'CommonBuffId' = 102727 - TRAIT_SQUEAMISH_EWW_GROSS_FISHING: 'CommonBuffId' = 116275 - TRAIT_STEEL_BLADDER: 'CommonBuffId' = 26376 - TRAIT_SURVIVALIST_FRESH_INGREDIENTS: 'CommonBuffId' = 108879 - TRAIT_SURVIVALIST_PRIMITIVE_AWAKENING: 'CommonBuffId' = 108923 - TRAIT_SURVIVALIST_RUSTIC_COMFORT: 'CommonBuffId' = 108917 - TRAIT_SURVIVALIST_RUSTIC_COMFORT_NO_COMMODITY: 'CommonBuffId' = 116277 - TRAIT_SURVIVALIST_SIMPLE_SATISFACTION: 'CommonBuffId' = 108966 - TRAIT_SURVIVAL_INSTINCT: 'CommonBuffId' = 249918 - TRAIT_TEEN: 'CommonBuffId' = 34524 - TRAIT_THE_KNACK: 'CommonBuffId' = 99840 - TRAIT_TODDLER: 'CommonBuffId' = 141769 - TRAIT_TODDLER_ANGELIC: 'CommonBuffId' = 143170 - TRAIT_TODDLER_ANGELIC_EASYGOING: 'CommonBuffId' = 143251 - TRAIT_TODDLER_CHARMER: 'CommonBuffId' = 143177 - TRAIT_TODDLER_CHARMER_CHARMED: 'CommonBuffId' = 154709 - TRAIT_TODDLER_CHARMER_NEW_FRIENDS: 'CommonBuffId' = 154714 - TRAIT_TODDLER_CHARMER_WHERE_IS_EVERYONE: 'CommonBuffId' = 143271 - TRAIT_TODDLER_CLINGY: 'CommonBuffId' = 143171 - TRAIT_TODDLER_CLINGY_WHERES_MAMA_DADA: 'CommonBuffId' = 143284 - TRAIT_TODDLER_FUSSY: 'CommonBuffId' = 143172 - TRAIT_TODDLER_FUSSY_GOT_MY_WAY: 'CommonBuffId' = 154394 - TRAIT_TODDLER_FUSSY_LISTEN_TO_ME: 'CommonBuffId' = 154389 - TRAIT_TODDLER_FUSSY_OWWIE: 'CommonBuffId' = 154388 - TRAIT_TODDLER_FUSSY_TODDLER_ANGER: 'CommonBuffId' = 154408 - TRAIT_TODDLER_FUSSY_TODDLER_STRESS: 'CommonBuffId' = 154407 - TRAIT_TODDLER_FUSSY_UNDER_MY_THUMB: 'CommonBuffId' = 154392 - TRAIT_TODDLER_INDEPENDENT: 'CommonBuffId' = 143174 - TRAIT_TODDLER_INDEPENDENT_ON_MY_OWN: 'CommonBuffId' = 143347 - TRAIT_TODDLER_INQUISITIVE: 'CommonBuffId' = 143176 - TRAIT_TODDLER_INQUISITIVE_LEARNED_SOMETHING_NEW: 'CommonBuffId' = 154460 - TRAIT_TODDLER_INQUISITIVE_NEED_TO_LEARN: 'CommonBuffId' = 143348 - TRAIT_TODDLER_INQUISITIVE_NEED_TO_LEARN_LOOT_BUFF: 'CommonBuffId' = 157209 - TRAIT_TODDLER_PERSONALITY_AGGRESSIVE: 'CommonBuffId' = 306540 - TRAIT_TODDLER_PERSONALITY_AUDIO_LOVER: 'CommonBuffId' = 306541 - TRAIT_TODDLER_PERSONALITY_BOOK_LOVER: 'CommonBuffId' = 306550 - TRAIT_TODDLER_PERSONALITY_DESTRUCTIVE: 'CommonBuffId' = 306551 - TRAIT_TODDLER_PERSONALITY_GOOD_APPETITE: 'CommonBuffId' = 306553 - TRAIT_TODDLER_PERSONALITY_HATES_BED_TIME: 'CommonBuffId' = 306554 - TRAIT_TODDLER_PERSONALITY_HATES_CARRY: 'CommonBuffId' = 314339 - TRAIT_TODDLER_PERSONALITY_HEAVY_SLEEPER: 'CommonBuffId' = 313462 - TRAIT_TODDLER_PERSONALITY_LIGHT_SLEEPER: 'CommonBuffId' = 313463 - TRAIT_TODDLER_PERSONALITY_LOVES_CARRY: 'CommonBuffId' = 306544 - TRAIT_TODDLER_PERSONALITY_PICKY_EATER: 'CommonBuffId' = 313467 - TRAIT_TODDLER_PERSONALITY_SINGER: 'CommonBuffId' = 306549 - TRAIT_TODDLER_PERSONALITY_WATER_LOVER: 'CommonBuffId' = 305555 - TRAIT_TODDLER_SILLY: 'CommonBuffId' = 143175 - TRAIT_TODDLER_SILLY_BUTT_BUTT: 'CommonBuffId' = 154244 - TRAIT_TODDLER_SILLY_MADE_A_SILLY: 'CommonBuffId' = 156739 - TRAIT_TODDLER_SILLY_WHAGGA_WHAGGA: 'CommonBuffId' = 143290 - TRAIT_TODDLER_WILD: 'CommonBuffId' = 143173 - TRAIT_TODDLER_WILD_RUN_RUN_RUN: 'CommonBuffId' = 143296 - TRAIT_TODDLER_WILD_STUCK_INSIDE: 'CommonBuffId' = 154276 - TRAIT_TODDLER_WILD_WIND_IN_MY_HAIR: 'CommonBuffId' = 154275 - TRAIT_TOP_NOTCH_TODDLER: 'CommonBuffId' = 143164 - TRAIT_TOWN_MASCOT: 'CommonBuffId' = 249204 - TRAIT_TRUE_MASTER: 'CommonBuffId' = 156008 - TRAIT_UNCONTROLLED_EMOTION: 'CommonBuffId' = 160266 - TRAIT_UNFEELING: 'CommonBuffId' = 160955 - TRAIT_UNFLIRTY: 'CommonBuffId' = 132584 - TRAIT_UNFLIRTY_COMMITTED_CRASS_ACT_HIDDEN: 'CommonBuffId' = 133067 - TRAIT_UNFLIRTY_DEFROSTED_ACTOR_COLD_SHOULDER_OUTCOME_FAIL: 'CommonBuffId' = 132742 - TRAIT_UNFLIRTY_FLIRTY_DISASTER_ACTOR_OUTCOME_FAIL: 'CommonBuffId' = 132596 - TRAIT_UNFLIRTY_FLIRTY_RETARGET_OUTCOME_FAIL: 'CommonBuffId' = 132594 - TRAIT_UNFLIRTY_FOR_SHAME_TARGET_REPRIMAND_OUTCOME_SUCCESS: 'CommonBuffId' = 132739 - TRAIT_UNFLIRTY_HOLD_YOUR_HORSES_TARGET_OUTCOME_FAIL: 'CommonBuffId' = 132597 - TRAIT_UNFLIRTY_ICED_TARGET_COLD_SHOULDER_OUTCOME_SUCCESS: 'CommonBuffId' = 132741 - TRAIT_UNFLIRTY_MOVING_TOO_FAST: 'CommonBuffId' = 132595 - TRAIT_UNFLIRTY_SHAMING_BACKFIRE_ACTOR_REPRIMAND_OUTCOME_FAIL: 'CommonBuffId' = 132740 - TRAIT_UNFLIRTY_WITNESSED_CRASS_ACT: 'CommonBuffId' = 132593 - TRAIT_UNIVERSITY_HIGHER_EDUCATION: 'CommonBuffId' = 308613 - TRAIT_UNTROUBLED: 'CommonBuffId' = 283838 - TRAIT_VEGETARIAN_EATING_MEATY_FOOD: 'CommonBuffId' = 143538 - TRAIT_VEGETARIAN_EVANGELIZE_HIDDEN: 'CommonBuffId' = 152511 - TRAIT_VEGETARIAN_HAS_EATEN_HIDDEN: 'CommonBuffId' = 154206 - TRAIT_VEGETARIAN_HAS_EATEN_MEAT_SUBSTITUTE_HIDDEN: 'CommonBuffId' = 132738 - TRAIT_VEGETARIAN_SUPERIORITY_COMPLEX: 'CommonBuffId' = 132645 - TRAIT_VEGETARIAN_TAINTED_WITH_MEAT: 'CommonBuffId' = 132644 - TRAIT_VEGETARIAN_VEGETARIAN_APPROVED: 'CommonBuffId' = 132640 - TRAIT_WALK_STYLE_BATUU_STORMTROOPER: 'CommonBuffId' = 243235 - TRAIT_WALK_STYLE_BUTCH: 'CommonBuffId' = 29581 - TRAIT_WALK_STYLE_CELEBRITY: 'CommonBuffId' = 196761 - TRAIT_WALK_STYLE_CREEPY: 'CommonBuffId' = 155565 - TRAIT_WALK_STYLE_ENERGETIC: 'CommonBuffId' = 98759 - TRAIT_WALK_STYLE_FEMININE: 'CommonBuffId' = 29580 - TRAIT_WALK_STYLE_GOOFY: 'CommonBuffId' = 29579 - TRAIT_WALK_STYLE_PERKY: 'CommonBuffId' = 24602 - TRAIT_WALK_STYLE_SLEEPY: 'CommonBuffId' = 98758 - TRAIT_WALK_STYLE_SNOOTY: 'CommonBuffId' = 24600 - TRAIT_WALK_STYLE_SWAGGER: 'CommonBuffId' = 24601 - TRAIT_WEATHER_PREFERENCE_LOVES_RAIN: 'CommonBuffId' = 189225 - TRAIT_WEATHER_PREFERENCE_LOVES_SNOW: 'CommonBuffId' = 189232 - TRAIT_WISE: 'CommonBuffId' = 341159 - TRAIT_WITH_MY_FRIENDS: 'CommonBuffId' = 125555 - TRAIT_WORLDLY_KNOWLEDGE: 'CommonBuffId' = 249838 - TRAIT_WORLDLY_KNOWLEDGE_LOCAL_DELICACY: 'CommonBuffId' = 249957 - TRAIT_WORLDLY_KNOWLEDGE_NOTEWORTHY_NEGOTIATION: 'CommonBuffId' = 249840 - TRAIT_YOUNG_ADULT: 'CommonBuffId' = 34525 - TRASH_UPDATE_FLIES_FOOD_NOT_FRIENDS: 'CommonBuffId' = 232255 - TRASH_UPDATE_FRUSTRATION_INFESTATION: 'CommonBuffId' = 232257 - TRASH_UPDATE_NEAT_ON_LOT: 'CommonBuffId' = 238406 - TRASH_UPDATE_ROACH_WRANGLER: 'CommonBuffId' = 232256 - TRASH_UPDATE_SLOB_LAZY_ON_LOT: 'CommonBuffId' = 238844 - TRASH_UPDATE_SWATTED: 'CommonBuffId' = 232252 - TRASH_UPDATE_WASTE_MANAGER_AUTONOMY_MOD_CONSULT: 'CommonBuffId' = 235103 - TRASH_UPDATE_WASTE_MANAGER_AUTONOMY_MOD_LEAVE: 'CommonBuffId' = 235111 - TRASH_UPDATE_WASTE_MANAGER_AUTONOMY_MOD_PICK_UP_TRASH: 'CommonBuffId' = 235095 - TRASH_UPDATE_WASTE_MANAGER_AUTONOMY_MOD_PLAYER: 'CommonBuffId' = 235812 - TRASH_UPDATE_WASTE_MANAGER_AUTONOMY_MOD_PLAYER_END: 'CommonBuffId' = 239756 - TRASH_UPDATE_WASTE_MANAGER_AUTONOMY_MOD_PLAYER_TAKE_PAYMENT: 'CommonBuffId' = 235944 - TREASURED_TALE: 'CommonBuffId' = 108017 - TREASURED_TALE_GREAT_STORYTELLER: 'CommonBuffId' = 109751 - TREEHOUSE_MESS_AROUND_GOT_SOME_FRESH_AIR: 'CommonBuffId' = 323565 - TREEHOUSE_MESS_AROUND_SPLINTERS: 'CommonBuffId' = 323603 - TREEHOUSE_PLAY_ON_DURATION: 'CommonBuffId' = 315735 - TREEHOUSE_TREEHOUSE_ADVENTURES: 'CommonBuffId' = 308591 - TREEHOUSE_WOOHOO_GOT_SOME_FRESH_AIR: 'CommonBuffId' = 318687 - TREEHOUSE_WOOHOO_SPLINTERS: 'CommonBuffId' = 318686 - TRIVIA_BOX_GAME_END: 'CommonBuffId' = 365494 - TRIVIA_BOX_GAME_END_ABORT: 'CommonBuffId' = 383577 - TRIVIA_BOX_GUESS_TRACKING_CRY: 'CommonBuffId' = 365307 - TRIVIA_BOX_GUESS_TRACKING_MIND_BLOWN: 'CommonBuffId' = 365308 - TRIVIA_BOX_GUESS_TRACKING_SCREAM: 'CommonBuffId' = 358497 - TRIVIA_BOX_GUESS_TRACKING_SURPRISED: 'CommonBuffId' = 358498 - TRIVIA_BOX_GUESS_TRACKING_SWEAT_SMILE: 'CommonBuffId' = 358496 - TRIVIA_BOX_GUESS_TRACKING_THINKING: 'CommonBuffId' = 365309 - TRIVIA_BOX_GUESS_TRACKING_VOMIT: 'CommonBuffId' = 365310 - TRIVIA_BOX_GUESS_TRACKING_ZIPPER_MOUTH: 'CommonBuffId' = 365311 - TRIVIA_BOX_THUMBS_UP_HAPPY: 'CommonBuffId' = 366015 - TRIVIA_BOX_THUMBS_UP_TENSE: 'CommonBuffId' = 366016 - TRIVIA_BOX_WOO_WHO_ANSWER_TRACKER: 'CommonBuffId' = 363109 - TRIVIA_BOX_WOO_WHO_FLIRTY: 'CommonBuffId' = 366014 - TRIVIA_BOX_WOO_WHO_QUESTION_ASKER: 'CommonBuffId' = 363165 - TUCK_IN_COOLDOWN: 'CommonBuffId' = 168470 - TUTORIAL_ADD_BOOK: 'CommonBuffId' = 100486 - TUTORIAL_ADD_SATISFACTION_POINTS: 'CommonBuffId' = 100688 - TUTORIAL_HUNGER: 'CommonBuffId' = 99745 - TUTORIAL_INSPIRED: 'CommonBuffId' = 99216 - TUTORIAL_MOTIVES_HYGIENE_GRUNGY: 'CommonBuffId' = 99387 - TUTORIAL_REMOVE_INSPIRED: 'CommonBuffId' = 100159 - TV_BE_TWEEN_WATCHED: 'CommonBuffId' = 138243 - TYAE_BABY_FEED_BITTEN: 'CommonBuffId' = 275495 - TYAE_BABY_FEED_BITTEN_VAMPIRE_BABY: 'CommonBuffId' = 275496 - TYAE_BABY_FEED_SPIT_UP_ON: 'CommonBuffId' = 275498 - UMBRELLA_ADD_UMBRELLA: 'CommonBuffId' = 190771 - UMBRELLA_BROKEN: 'CommonBuffId' = 186660 - UMBRELLA_CLOSE: 'CommonBuffId' = 185734 - UMBRELLA_CLOSE_1_HOUR: 'CommonBuffId' = 191230 - UMBRELLA_OPEN: 'CommonBuffId' = 185715 - UMBRELLA_STORM: 'CommonBuffId' = 186643 - UNENLIGHTENING_LECTURE: 'CommonBuffId' = 118516 - UNFEELING_RILE_UP_ANGRY: 'CommonBuffId' = 160965 - UNFEELING_RILE_UP_EMBARRASSED: 'CommonBuffId' = 160967 - UNFEELING_RILE_UP_SAD: 'CommonBuffId' = 160968 - UNFEELING_RILE_UP_STRESSED: 'CommonBuffId' = 160969 - UNIT_RATING_MAINTENANCE_DAY_COOLDOWN: 'CommonBuffId' = 360952 - UNIVERSITY_AFTER_CLASS_GO_HOME: 'CommonBuffId' = 230556 - UNIVERSITY_CHEATING_CAUGHT: 'CommonBuffId' = 223206 - UNIVERSITY_CHEATING_CAUGHT_GOOD_TRAITS: 'CommonBuffId' = 223207 - UNIVERSITY_CHEATING_CAUGHT_HIDDEN: 'CommonBuffId' = 228382 - UNIVERSITY_CHEATING_SUCCESS: 'CommonBuffId' = 223209 - UNIVERSITY_CLASSROOM_SHELL_A_TASTE_OF_HIGHER_LEARNING: 'CommonBuffId' = 220314 - UNIVERSITY_CLASSROOM_SHELL_INSPIRED_QUOTE: 'CommonBuffId' = 220306 - UNIVERSITY_CLASSROOM_SHELL_TUTORIFIC: 'CommonBuffId' = 220307 - UNIVERSITY_CLASSROOM_SHELL_VISIT_OFFICE_HOURS_COOLDOWN_A: 'CommonBuffId' = 222234 - UNIVERSITY_CLASSROOM_SHELL_VISIT_OFFICE_HOURS_COOLDOWN_B: 'CommonBuffId' = 222239 - UNIVERSITY_CLASSROOM_SHELL_VISIT_OFFICE_HOURS_COOLDOWN_C: 'CommonBuffId' = 222240 - UNIVERSITY_CLASSROOM_SHELL_VISIT_OFFICE_HOURS_COOLDOWN_D: 'CommonBuffId' = 222241 - UNIVERSITY_EMAIL_PRFOESSOR_COOLDOWN_PHONE: 'CommonBuffId' = 224038 - UNIVERSITY_EMAIL_PROFESSOR_COOLDOWNS_A: 'CommonBuffId' = 224039 - UNIVERSITY_EMAIL_PROFESSOR_COOLDOWNS_B: 'CommonBuffId' = 224040 - UNIVERSITY_EMAIL_PROFESSOR_COOLDOWNS_C: 'CommonBuffId' = 224041 - UNIVERSITY_EMAIL_PROFESSOR_COOLDOWNS_D: 'CommonBuffId' = 224042 - UNIVERSITY_ENROLLMENT_ACCEPTANCE_HIGH: 'CommonBuffId' = 229214 - UNIVERSITY_ENROLLMENT_ACCEPTANCE_LOW: 'CommonBuffId' = 229212 - UNIVERSITY_ENROLLMENT_ACCEPTANCE_MEDIUM: 'CommonBuffId' = 229213 - UNIVERSITY_ENROLLMENT_CONFIDENCE_LOW: 'CommonBuffId' = 222411 - UNIVERSITY_ENROLLMENT_CONNECTIONS_FAILURE: 'CommonBuffId' = 219815 - UNIVERSITY_ENROLLMENT_CONNECTIONS_FAILURE_ARTS: 'CommonBuffId' = 227528 - UNIVERSITY_ENROLLMENT_CONNECTIONS_FAILURE_SCIENCE: 'CommonBuffId' = 227529 - UNIVERSITY_ENROLLMENT_CONNECTIONS_SUCCESS: 'CommonBuffId' = 219814 - UNIVERSITY_ENROLLMENT_CONNECTIONS_SUCCESS_ARTS: 'CommonBuffId' = 227525 - UNIVERSITY_ENROLLMENT_CONNECTIONS_SUCCESS_SCIENCE: 'CommonBuffId' = 227526 - UNIVERSITY_ENROLLMENT_DONATE_FAILURE: 'CommonBuffId' = 219817 - UNIVERSITY_ENROLLMENT_DONATE_SUCCESS: 'CommonBuffId' = 219816 - UNIVERSITY_ENROLLMENT_FIRST_UNIVERSITY_MEMORY: 'CommonBuffId' = 220046 - UNIVERSITY_ENROLLMENT_FLAUNT_FAME_FAILURE: 'CommonBuffId' = 219819 - UNIVERSITY_ENROLLMENT_FLAUNT_FAME_SUCCESS: 'CommonBuffId' = 219818 - UNIVERSITY_ENROLLMENT_STRESS_HIGH: 'CommonBuffId' = 222410 - UNIVERSITY_ENROLLMENT_STRESS_NORMAL: 'CommonBuffId' = 222357 - UNIVERSITY_FINAL_EXAM_PRACTICE_PRESENT_TRACKER: 'CommonBuffId' = 229023 - UNIVERSITY_FINAL_EXAM_STRESS: 'CommonBuffId' = 224028 - UNIVERSITY_FINAL_EXAM_UNCOMFORTABLE: 'CommonBuffId' = 229431 - UNIVERSITY_FINAL_EXAM_WENT_TO_CLASS: 'CommonBuffId' = 230493 - UNIVERSITY_GRADUATION_CAP: 'CommonBuffId' = 229460 - UNIVERSITY_GRADUATION_GRADUATED: 'CommonBuffId' = 228536 - UNIVERSITY_HIDDEN_FINAL_EXAM_DONE_A: 'CommonBuffId' = 230446 - UNIVERSITY_HIDDEN_FINAL_EXAM_DONE_B: 'CommonBuffId' = 230447 - UNIVERSITY_HIDDEN_FINAL_EXAM_DONE_C: 'CommonBuffId' = 230448 - UNIVERSITY_HIDDEN_FINAL_EXAM_DONE_D: 'CommonBuffId' = 230449 - UNIVERSITY_RIVALRY_CAUGHT_RED_HANDED: 'CommonBuffId' = 224643 - UNIVERSITY_RIVALRY_CAUGHT_RED_HANDED_ANGRY: 'CommonBuffId' = 226574 - UNIVERSITY_RIVALRY_CAUGHT_RED_HANDED_SAD: 'CommonBuffId' = 226575 - UNIVERSITY_RIVALRY_PRIDE_TARNISHED_SAD: 'CommonBuffId' = 226624 - UNIVERSITY_RIVALRY_ROLES_LEAVE: 'CommonBuffId' = 226698 - UNIVERSITY_RIVALRY_ROLES_PRANK: 'CommonBuffId' = 226697 - UNIVERSITY_RIVALRY_SCHOOL_PRIDE_LEVEL_1: 'CommonBuffId' = 226452 - UNIVERSITY_RIVALRY_SCHOOL_PRIDE_LEVEL_2: 'CommonBuffId' = 226454 - UNIVERSITY_RIVARLY_REMINDED_OF_SUPERIORITY_CONFIDENT: 'CommonBuffId' = 226593 - UNIVERSITY_RIVARLY_REMINDED_OF_SUPERIORITY_PLAYFUL: 'CommonBuffId' = 226592 - UNIVERSITY_SCHOLARSHIPS_FULL_RIDE: 'CommonBuffId' = 226282 - UNIVERSITY_SCHOLARSHIPS_PICKER_RESULT_CHECK: 'CommonBuffId' = 227898 - UNIVERSITY_SCHOLARSHIPS_SCHOLARSHIP_SURE: 'CommonBuffId' = 226277 - UNIVERSITY_SCHOLARSHIPS_SIZEABLE_SCHOLARSHIP: 'CommonBuffId' = 226283 - UNIVERSITY_SIGNING_BONUS_COOLDOWN: 'CommonBuffId' = 227984 - UNIVERSITY_STUDYING: 'CommonBuffId' = 223950 - UNIVERSITY_STUDYING_FEELING_STUDIOUS: 'CommonBuffId' = 223840 - UNIVERSITY_STUDYING_LOSING_FOCUS: 'CommonBuffId' = 223842 - UNIVERSITY_STUDYING_TRULY_CRAMMED: 'CommonBuffId' = 223843 - UNIVERSITY_STUDYING_WELL_PREPARED: 'CommonBuffId' = 223841 - UNIVERSITY_TERM_PRESENTATION_FEDBACK: 'CommonBuffId' = 225971 - UNIVERSITY_TERM_PRESENTATION_REACTION_HIGH: 'CommonBuffId' = 229324 - UNIVERSITY_TERM_PRESENTATION_REACTION_LOW: 'CommonBuffId' = 229322 - UNIVERSITY_TERM_PRESENTATION_REACTION_MED: 'CommonBuffId' = 229323 - UNIVERSITY_WITHDRAW_COOLDOWN: 'CommonBuffId' = 228136 - UNLEASH: 'CommonBuffId' = 178466 - UNWANTED_PROPOSAL: 'CommonBuffId' = 98093 - VACUUM_CLEANER_ALL_MESSES_TERMINATED: 'CommonBuffId' = 257419 - VACUUM_CLEANER_AUTONOMOUS_COOLDOWN: 'CommonBuffId' = 258689 - VACUUM_CLEANER_NO_DUST_LEFT_BEHIND: 'CommonBuffId' = 256898 - VACUUM_CLEANER_VAPORIZING_PULSE: 'CommonBuffId' = 258473 - VACUUM_CLEANER_WHAT_CANT_BE_VACUUMED: 'CommonBuffId' = 257797 - VAMPIRES_MOTIVES_ALL_MOTIVES_HIGH: 'CommonBuffId' = 155738 - VAMPIRES_MOTIVES_ALL_MOTIVES_PRETTY_HIGH: 'CommonBuffId' = 155739 - VAMPIRES_MOTIVES_DISPEL_GREEDY_NEEDS: 'CommonBuffId' = 182712 - VAMPIRES_PERSONA_POWERS_POTENT_POWER_LEVEL1: 'CommonBuffId' = 153431 - VAMPIRES_PERSONA_POWERS_POTENT_POWER_LEVEL2: 'CommonBuffId' = 153432 - VAMPIRES_PERSONA_POWERS_POTENT_POWER_LEVEL3: 'CommonBuffId' = 153433 - VAMPIRES_PERSONA_POWERS_VAMPIRIC_STRENGTH_LEVEL1: 'CommonBuffId' = 154687 - VAMPIRES_PERSONA_POWERS_VAMPIRIC_STRENGTH_LEVEL2: 'CommonBuffId' = 154688 - VAMPIRES_PERSONA_POWERS_VAMPIRIC_STRENGTH_LEVEL3: 'CommonBuffId' = 154686 - VAMPIRE_BAT_MESS_AROUND: 'CommonBuffId' = 156106 - VAMPIRE_BAT_WOOHOO: 'CommonBuffId' = 152748 - VAMPIRE_BURNED_BY_SUN: 'CommonBuffId' = 151450 - VAMPIRE_BURNED_BY_SUN_GHOST: 'CommonBuffId' = 153337 - VAMPIRE_BURNED_BY_SUN_GHOST_RESISTANCE_SOLIS_LEVEL1: 'CommonBuffId' = 155476 - VAMPIRE_BURNED_BY_SUN_GHOST_RESISTANCE_SOLIS_LEVEL2: 'CommonBuffId' = 155477 - VAMPIRE_BURNED_BY_SUN_GHOST_WEAKNESS_SUNLIGHT_LEVEL1: 'CommonBuffId' = 155478 - VAMPIRE_BURNED_BY_SUN_GHOST_WEAKNESS_SUNLIGHT_LEVEL2: 'CommonBuffId' = 155479 - VAMPIRE_BURNED_BY_SUN_GHOST_WEAKNESS_SUNLIGHT_LEVEL3: 'CommonBuffId' = 155480 - VAMPIRE_BURNED_BY_SUN_RESISTANCE_SOLIS_LEVEL1: 'CommonBuffId' = 151923 - VAMPIRE_BURNED_BY_SUN_RESISTANCE_SOLIS_LEVEL2: 'CommonBuffId' = 151924 - VAMPIRE_BURNED_BY_SUN_WEAKNESS_SUNLIGHT_LEVEL1: 'CommonBuffId' = 152506 - VAMPIRE_BURNED_BY_SUN_WEAKNESS_SUNLIGHT_LEVEL2: 'CommonBuffId' = 152507 - VAMPIRE_BURNED_BY_SUN_WEAKNESS_SUNLIGHT_LEVEL3: 'CommonBuffId' = 152505 - VAMPIRE_CHANCE_OF_VAMPIRE: 'CommonBuffId' = 155855 - VAMPIRE_CREATION_APPETITE_LOST: 'CommonBuffId' = 149428 - VAMPIRE_CREATION_DISGUSTED_BY_FOOD: 'CommonBuffId' = 149427 - VAMPIRE_CREATION_REACTION_COOLDOWN: 'CommonBuffId' = 156256 - VAMPIRE_CREATION_STRANGELY_HUNGRY: 'CommonBuffId' = 149423 - VAMPIRE_CREATION_STRANGE_THIRST: 'CommonBuffId' = 149536 - VAMPIRE_CURED_A_FRIEND: 'CommonBuffId' = 151512 - VAMPIRE_CURED_A_VAMPIRE: 'CommonBuffId' = 150158 - VAMPIRE_DARK_MEDITATION: 'CommonBuffId' = 155654 - VAMPIRE_DAY_TIME: 'CommonBuffId' = 151171 - VAMPIRE_DEFEATED_A_HUNTER: 'CommonBuffId' = 150160 - VAMPIRE_DONT_EAT: 'CommonBuffId' = 191752 - VAMPIRE_DRINK_IN_PROGRESS: 'CommonBuffId' = 151090 - VAMPIRE_DYING_FROM_SUN: 'CommonBuffId' = 151451 - VAMPIRE_DYING_FROM_SUN_RESISTANCE_SOLIS_LEVEL1: 'CommonBuffId' = 151910 - VAMPIRE_DYING_FROM_SUN_RESISTANCE_SOLIS_LEVEL2: 'CommonBuffId' = 151911 - VAMPIRE_DYING_FROM_SUN_WEAKNESS_SUNLIGHT_LEVEL1: 'CommonBuffId' = 152503 - VAMPIRE_DYING_FROM_SUN_WEAKNESS_SUNLIGHT_LEVEL2: 'CommonBuffId' = 152504 - VAMPIRE_DYING_FROM_SUN_WEAKNESS_SUNLIGHT_LEVEL3: 'CommonBuffId' = 152502 - VAMPIRE_HIDDEN_DRAIN_LIFE_SPIRIT_TARGET: 'CommonBuffId' = 151920 - VAMPIRE_HIDDEN_DRINK_DEEPLY_TARGET: 'CommonBuffId' = 151919 - VAMPIRE_HIDDEN_FAVOR_VAMPIRE_SOCIALS: 'CommonBuffId' = 154179 - VAMPIRE_INVITES_VAMPIRE_CREATION_NORMIE: 'CommonBuffId' = 152982 - VAMPIRE_INVITES_VAMPIRE_CREATION_TARGET: 'CommonBuffId' = 152760 - VAMPIRE_INVITES_VAMPIRE_CREATION_VAMPIRE_OFFER: 'CommonBuffId' = 152442 - VAMPIRE_IN_SUN: 'CommonBuffId' = 151170 - VAMPIRE_IS_VAMPIRE: 'CommonBuffId' = 149543 - VAMPIRE_MENTOR_TIMEOUT: 'CommonBuffId' = 156600 - VAMPIRE_MIND_POWERS_DISPEL: 'CommonBuffId' = 156589 - VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_ANGRY_1: 'CommonBuffId' = 150605 - VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_ANGRY_2: 'CommonBuffId' = 150606 - VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_ANGRY_3: 'CommonBuffId' = 150604 - VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_BORED_1: 'CommonBuffId' = 150611 - VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_BORED_2: 'CommonBuffId' = 150612 - VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_BORED_3: 'CommonBuffId' = 150610 - VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_CONFIDENT_1: 'CommonBuffId' = 150617 - VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_CONFIDENT_2: 'CommonBuffId' = 150618 - VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_CONFIDENT_3: 'CommonBuffId' = 150616 - VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_DAZED_1: 'CommonBuffId' = 150623 - VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_DAZED_2: 'CommonBuffId' = 150624 - VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_DAZED_3: 'CommonBuffId' = 150622 - VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_EMBARRASSED_1: 'CommonBuffId' = 150641 - VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_EMBARRASSED_2: 'CommonBuffId' = 150640 - VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_EMBARRASSED_3: 'CommonBuffId' = 150638 - VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_ENERGIZED_1: 'CommonBuffId' = 150634 - VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_ENERGIZED_2: 'CommonBuffId' = 150635 - VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_ENERGIZED_3: 'CommonBuffId' = 150633 - VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_FLIRTY_1: 'CommonBuffId' = 150586 - VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_FLIRTY_2: 'CommonBuffId' = 150587 - VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_FLIRTY_3: 'CommonBuffId' = 150585 - VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_FOCUSED_1: 'CommonBuffId' = 150592 - VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_FOCUSED_2: 'CommonBuffId' = 150593 - VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_FOCUSED_3: 'CommonBuffId' = 150591 - VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_HAPPY_1: 'CommonBuffId' = 150570 - VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_HAPPY_2: 'CommonBuffId' = 150583 - VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_HAPPY_3: 'CommonBuffId' = 150582 - VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_INSPIRED_1: 'CommonBuffId' = 150599 - VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_INSPIRED_2: 'CommonBuffId' = 150600 - VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_INSPIRED_3: 'CommonBuffId' = 150598 - VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_PLAYFUL_1: 'CommonBuffId' = 150649 - VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_PLAYFUL_2: 'CommonBuffId' = 150650 - VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_PLAYFUL_3: 'CommonBuffId' = 150648 - VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_SAD_1: 'CommonBuffId' = 150663 - VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_SAD_2: 'CommonBuffId' = 150664 - VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_SAD_3: 'CommonBuffId' = 150662 - VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_STRESSED_1: 'CommonBuffId' = 150666 - VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_STRESSED_2: 'CommonBuffId' = 150667 - VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_STRESSED_3: 'CommonBuffId' = 150665 - VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_UNCOMFORTABLE_1: 'CommonBuffId' = 150669 - VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_UNCOMFORTABLE_2: 'CommonBuffId' = 150670 - VAMPIRE_MIND_POWERS_EMOTIONAL_BURST_UNCOMFORTABLE_3: 'CommonBuffId' = 150668 - VAMPIRE_MIND_POWERS_HALLUCINATE: 'CommonBuffId' = 150755 - VAMPIRE_MORTAL_MELANCHOLY: 'CommonBuffId' = 150162 - VAMPIRE_NON_VAMPIRE_EATS_PLASMA_FRUIT: 'CommonBuffId' = 153397 - VAMPIRE_NON_VAMPIRE_VAMPIRE_RESISTANCE_COCKTAIL: 'CommonBuffId' = 155487 - VAMPIRE_NPC_ENABLE_VAMPIRE_ROUTING: 'CommonBuffId' = 155269 - VAMPIRE_PLASMA_FRUIT_SALAD: 'CommonBuffId' = 156011 - VAMPIRE_RAGE_OUT: 'CommonBuffId' = 150063 - VAMPIRE_RECENTLY_BITTEN: 'CommonBuffId' = 150749 - VAMPIRE_RECENTLY_BITTEN_STRENGTH2: 'CommonBuffId' = 151763 - VAMPIRE_RECENTLY_BITTEN_STRENGTH3: 'CommonBuffId' = 151764 - VAMPIRE_RECENTLY_BITTEN_WITH_PERMISSION: 'CommonBuffId' = 156797 - VAMPIRE_RECENTLY_DRANK: 'CommonBuffId' = 150748 - VAMPIRE_RECENTLY_DRANK_STRENGTH2: 'CommonBuffId' = 151775 - VAMPIRE_RESEARCH_TOO_EASY: 'CommonBuffId' = 153826 - VAMPIRE_RESISTANCE_COCKTAIL_HIDDEN: 'CommonBuffId' = 156615 - VAMPIRE_SHOW_OFF_POWERS_ACTOR_HIDDEN: 'CommonBuffId' = 152822 - VAMPIRE_SLAYING_FOILED: 'CommonBuffId' = 150159 - VAMPIRE_SLEPT_LIKE_THE_UNDEAD: 'CommonBuffId' = 150163 - VAMPIRE_SPIRIT_POWERS_BAT_ENABLED: 'CommonBuffId' = 152520 - VAMPIRE_SPIRIT_POWERS_MIST_ENABLED: 'CommonBuffId' = 152521 - VAMPIRE_SPIRIT_POWERS_RESTORE_LIFE_SPIRIT: 'CommonBuffId' = 152829 - VAMPIRE_SPIRIT_POWERS_VAMPIRE_RUN_ENABLED: 'CommonBuffId' = 152621 - VAMPIRE_SUNLIGHT_RESISTANCE_SOLIS_LEVEL3: 'CommonBuffId' = 155245 - VAMPIRE_SUNLIGHT_REVERSAL: 'CommonBuffId' = 155561 - VAMPIRE_SUNLIGHT_REVERSAL_COCKTAIL: 'CommonBuffId' = 155530 - VAMPIRE_SUNLIGHT_REVERSAL_RESISTANCE_SOLIS_LEVEL1: 'CommonBuffId' = 155598 - VAMPIRE_SUNLIGHT_REVERSAL_RESISTANCE_SOLIS_LEVEL2: 'CommonBuffId' = 155599 - VAMPIRE_SUNLIGHT_REVERSAL_RESISTANCE_SOLIS_LEVEL3: 'CommonBuffId' = 155774 - VAMPIRE_SUNLIGHT_REVERSAL_WEAKNESS_SUNLIGHT_LEVEL1: 'CommonBuffId' = 155600 - VAMPIRE_SUNLIGHT_REVERSAL_WEAKNESS_SUNLIGHT_LEVEL2: 'CommonBuffId' = 155601 - VAMPIRE_SUNLIGHT_REVERSAL_WEAKNESS_SUNLIGHT_LEVEL3: 'CommonBuffId' = 155602 - VAMPIRE_TASTY_SIM: 'CommonBuffId' = 151570 - VAMPIRE_UNWILLING_SNACK: 'CommonBuffId' = 154327 - VAMPIRE_VAMPIRE_NO_MORE: 'CommonBuffId' = 150161 - VAMPIRE_VAMPIRIC_SPAR_GOOD_PRACTICE_DUEL: 'CommonBuffId' = 154309 - VAMPIRE_WEAKENED_FROM_FIGHT: 'CommonBuffId' = 151107 - VAMPIRE_WEAKNESSES_DAY_TIME_LEVEL1: 'CommonBuffId' = 152545 - VAMPIRE_WEAKNESSES_DAY_TIME_LEVEL2: 'CommonBuffId' = 152546 - VAMPIRE_WEAKNESSES_DAY_TIME_LEVEL3: 'CommonBuffId' = 152544 - VAMPIRE_WEAKNESSES_ETERNAL_SADNESS: 'CommonBuffId' = 152411 - VAMPIRE_WEAKNESSES_ETERNAL_SADNESS_HIDDEN: 'CommonBuffId' = 152410 - VAMPIRE_WEAKNESSES_INEFFICIENT_DRINKER: 'CommonBuffId' = 152484 - VAMPIRE_WEAKNESSES_INSATIABLE_THIRST: 'CommonBuffId' = 152609 - VAMPIRE_WEAKNESSES_SUNLIGHT_LEVEL1: 'CommonBuffId' = 153438 - VAMPIRE_WEAKNESSES_SUNLIGHT_LEVEL2: 'CommonBuffId' = 153439 - VAMPIRE_WEAKNESSES_SUNLIGHT_LEVEL3: 'CommonBuffId' = 153437 - VAMPIRE_WEAKNESSES_UNCONTROLLABLE_HISSING: 'CommonBuffId' = 152539 - VAMPIRE_WEAKNESSES_UNCONTROLLABLE_HISSING_HIDDEN: 'CommonBuffId' = 152596 - VAMPIRE_WEAKNESSES_UNPLEASANT_AURA: 'CommonBuffId' = 152808 - VAMPIRE_WEAKNESSES_VAMPIRE_WITH_A_CONSCIENCE_GUILTY_DRINKER: 'CommonBuffId' = 152618 - VAMPIRE_WEAKNESSES_WITHERED_STOMACH: 'CommonBuffId' = 152241 - VAULT_BUFFS_FOCUSED_EVERYTHING_BURNS: 'CommonBuffId' = 193491 - VAULT_BUFFS_HIDDEN_BREAKING_INTO_UNOWNED_SAFE: 'CommonBuffId' = 200889 - VAULT_BUFFS_HIDDEN_IS_MAKING_IT_RAIN: 'CommonBuffId' = 201908 - VAULT_BUFFS_HIDDEN_MONEY_PHONE_COOLDOWN: 'CommonBuffId' = 202366 - VAULT_BUFFS_MADE_IT_POUR_CONFIDENT: 'CommonBuffId' = 197950 - VAULT_BUFFS_MADE_IT_RAIN_PLAYFUL: 'CommonBuffId' = 193489 - VAULT_BUFFS_MADE_IT_TRICKLE_PLAYFUL: 'CommonBuffId' = 197949 - VAULT_BUFFS_PLAYFUL_MONEY_PHONE: 'CommonBuffId' = 201006 - VAULT_BUFFS_SAD_WATCH_THE_WORLD_BURN: 'CommonBuffId' = 193490 - VAULT_BUFFS_VAULT_DOOR_ANGRY_THIEF_RAGE: 'CommonBuffId' = 193486 - VAULT_BUFFS_VAULT_DOOR_CONFIDENT_MASTER_THIEF: 'CommonBuffId' = 193488 - VAULT_BUFFS_VAULT_DOOR_SAD_AWFUL_THIEF: 'CommonBuffId' = 193487 - VAULT_BUFFS_WALK_IN_SAFE_CONFIDENT_MASTER_ESCAPE_ARTIST: 'CommonBuffId' = 202081 - VAULT_BUFFS_WALK_IN_SAFE_EXCITED_IM_RICH: 'CommonBuffId' = 193483 - VAULT_BUFFS_WALK_IN_SAFE_FLIRTY_MONEY_LOVE: 'CommonBuffId' = 193482 - VAULT_BUFFS_WALK_IN_SAFE_FOCUSED_MONEY_DREAMS: 'CommonBuffId' = 193484 - VAULT_BUFFS_WALK_IN_SAFE_PLAYFUL_FUN_MONEY: 'CommonBuffId' = 193475 - VAULT_BUFFS_WALK_IN_SAFE_STRESSED_TRAPPED_IN_SAFE: 'CommonBuffId' = 202080 - VEHICLE_BIKE_FRESH_AIR: 'CommonBuffId' = 227649 - VEHICLE_BIKE_GREEN_TRAVELER: 'CommonBuffId' = 227715 - VEHICLE_BIKE_RIDING: 'CommonBuffId' = 211196 - VEHICLE_BIKE_RIDING_KIDS_BIKE_BIKING_IS_HARD: 'CommonBuffId' = 305934 - VEHICLE_BIKE_RIDING_KIDS_BIKE_CANT_CONCENTRATE: 'CommonBuffId' = 306734 - VEHICLE_BIKE_RIDING_KIDS_BIKE_CHILD_CAN_NOW_RIDE: 'CommonBuffId' = 305932 - VEHICLE_BIKE_RIDING_KIDS_BIKE_HIDDEN_HONK_HORN: 'CommonBuffId' = 313615 - VEHICLE_BIKE_RIDING_KIDS_BIKE_HIDDEN_HORN_COOLDOWN: 'CommonBuffId' = 313632 - VEHICLE_BIKE_RIDING_KIDS_BIKE_HIDDEN_IS_MENTORED: 'CommonBuffId' = 332946 - VEHICLE_BIKE_RIDING_KIDS_BIKE_HIDDEN_PRACTICE: 'CommonBuffId' = 313614 - VEHICLE_BIKE_RIDING_KIDS_BIKE_HIDDEN_PRACTICE_COOLDOWN: 'CommonBuffId' = 313634 - VEHICLE_BIKE_RIDING_KIDS_BIKE_HIDDEN_TRICK: 'CommonBuffId' = 313626 - VEHICLE_BIKE_RIDING_KIDS_BIKE_HIDDEN_TRICK_COOLDOWN: 'CommonBuffId' = 313633 - VEHICLE_BIKE_RIDING_KIDS_BIKE_MENTOR: 'CommonBuffId' = 313336 - VEHICLE_BIKE_RIDING_KIDS_BIKE_NEVER_GET_BETTER: 'CommonBuffId' = 305933 - VEHICLE_BIKE_RIDING_KIDS_BIKE_SICK_TRICKS: 'CommonBuffId' = 306664 - VEHICLE_BIKE_RIDING_KIDS_BIKE_TAKES_ME_BACK: 'CommonBuffId' = 321064 - VEHICLE_BIKE_RIDING_KIDS_BIKE_TAUGHT_BY_THE_BEST: 'CommonBuffId' = 321065 - VEHICLE_BIKE_RIDING_KIDS_BIKE_TAUGHT_TO_RIDE: 'CommonBuffId' = 305931 - VEHICLE_BIKE_RIDING_KIDS_BIKE_TAUGHT_TO_RIDE_NOT_PARENT: 'CommonBuffId' = 318213 - VEHICLE_BIKE_WEARING_HELMET: 'CommonBuffId' = 230889 - VENDING_MACHINE_ALL_WARMED_UP: 'CommonBuffId' = 251928 - VENDING_MACHINE_ATE_MY_MONEY: 'CommonBuffId' = 247241 - VENDING_MACHINE_BLACK_5_BURGER: 'CommonBuffId' = 247234 - VENDING_MACHINE_CHICKEN_TERIYAKI_PIZZA: 'CommonBuffId' = 247237 - VENDING_MACHINE_CHILLED_OUT: 'CommonBuffId' = 251929 - VENDING_MACHINE_CUPIDS_CUPCAKE: 'CommonBuffId' = 247238 - VENDING_MACHINE_DEBUG_ALWAYS_FAIL: 'CommonBuffId' = 251188 - VENDING_MACHINE_DEBUG_ALWAYS_SUCCEED: 'CommonBuffId' = 251186 - VENDING_MACHINE_FLUFFY_WHITE_RIBBON_CAKE: 'CommonBuffId' = 247240 - VENDING_MACHINE_GALACTIC_VITA_WATER: 'CommonBuffId' = 247239 - VENDING_MACHINE_GHOST_FLASHBACKS_OF_BEING_CRUSHED: 'CommonBuffId' = 252090 - VENDING_MACHINE_HIDDEN_SHAKE_COOLDOWN: 'CommonBuffId' = 255057 - VENDING_MACHINE_HIDDEN_WEARING_FESTIVAL_KIMONO: 'CommonBuffId' = 253161 - VENDING_MACHINE_HIDDEN_WEARING_FESTIVAL_PAPER_KABUTO: 'CommonBuffId' = 253163 - VENDING_MACHINE_HIDDEN_WEARING_FESTIVAL_SNOW_OUTFIT: 'CommonBuffId' = 253162 - VENDING_MACHINE_PURE_RAGE: 'CommonBuffId' = 251918 - VENDING_MACHINE_TOO_CHILLED_OUT: 'CommonBuffId' = 251982 - VENDING_MACHINE_TOO_WARMED_UP: 'CommonBuffId' = 251981 - VENDING_MACHINE_WASTE_OF_TIME: 'CommonBuffId' = 251917 - VENUE_BAR: 'CommonBuffId' = 370735 - VENUE_BEACH: 'CommonBuffId' = 370374 - VENUE_BEACH_MERFOLK_DISCOVERED_TEST: 'CommonBuffId' = 209098 - VENUE_GYM: 'CommonBuffId' = 365878 - VENUE_KARAOKE: 'CommonBuffId' = 370738 - VENUE_LIBRARY: 'CommonBuffId' = 365779 - VENUE_LOUNGE: 'CommonBuffId' = 370737 - VENUE_MUSEUM: 'CommonBuffId' = 365780 - VENUE_NIGHTCLUB: 'CommonBuffId' = 370736 - VET_BAD_BREATH: 'CommonBuffId' = 170079 - VET_CONE_OF_SHAME: 'CommonBuffId' = 171707 - VET_CONE_OF_SHAME_APPEARANCE_CAT: 'CommonBuffId' = 172531 - VET_CONE_OF_SHAME_APPEARANCE_DOG: 'CommonBuffId' = 172532 - VET_CONE_OF_SHAME_APPEARANCE_SMALL_DOG: 'CommonBuffId' = 172533 - VET_CONE_OF_SHAME_DURATION: 'CommonBuffId' = 171744 - VET_CONE_OF_SHAME_OWNER_REMOVAL: 'CommonBuffId' = 171742 - VET_CONE_OF_SHAME_SELF_REMOVAL: 'CommonBuffId' = 171743 - VET_GREET_PATIENT_COOLDOWN: 'CommonBuffId' = 174800 - VET_SOOTHE_COOLDOWN: 'CommonBuffId' = 178064 - VET_SURGERY_SUCCESSFUL_OUTCOME: 'CommonBuffId' = 175630 - VET_SYMPTOM_DISCOVERY: 'CommonBuffId' = 172256 - VET_SYMPTOM_DISCOVERY_LARGE: 'CommonBuffId' = 173175 - VIDEO_GAME_CONSOLE_PARTY_LOSER_MP: 'CommonBuffId' = 145532 - VIDEO_GAME_CONSOLE_PARTY_WINNER_MP: 'CommonBuffId' = 145531 - VIDEO_GAME_CONSOLE_PARTY_WINNER_SP: 'CommonBuffId' = 153532 - VIDEO_GAME_CONSOLE_PLATFORMER_WINNER_SP: 'CommonBuffId' = 152187 - VIDEO_GAME_CONSOLE_PLAYING_HIDDEN: 'CommonBuffId' = 145713 - VIDEO_GAME_CONSOLE_RACING_LOSER_MP: 'CommonBuffId' = 145536 - VIDEO_GAME_CONSOLE_RACING_WINNER_MP: 'CommonBuffId' = 145535 - VIDEO_GAME_CONSOLE_RACING_WINNER_SP: 'CommonBuffId' = 153531 - VIDEO_GAME_CONSOLE_RAGE_QUIT: 'CommonBuffId' = 145523 - VIDEO_GAME_CONSOLE_RPG_WINNER_SP: 'CommonBuffId' = 152188 - VIEW_ANGRY: 'CommonBuffId' = 12709 - VIEW_CONFIDENT: 'CommonBuffId' = 40816 - VIEW_ENERGIZED: 'CommonBuffId' = 12710 - VIEW_FLIRTY: 'CommonBuffId' = 12711 - VIEW_FOCUSED: 'CommonBuffId' = 12712 - VIEW_HAPPY: 'CommonBuffId' = 12713 - VIEW_IMAGINATIVE: 'CommonBuffId' = 12714 - VIEW_PLAYFUL: 'CommonBuffId' = 100356 - VIEW_SAD: 'CommonBuffId' = 12715 - VILLAGER_HELP_AGATHA_BERRY: 'CommonBuffId' = 268931 - VILLAGER_HELP_DISCOVERY_TNS_COOLDOWN: 'CommonBuffId' = 344536 - VILLAGER_HELP_IN_REGION_NPC_VILLAGER_DISCOVERY: 'CommonBuffId' = 268971 - VILLAGER_HELP_ON_QUEST_HIDDEN: 'CommonBuffId' = 268627 - VILLAGER_HELP_QUEST_COOLDOWN_FOOD_FORAGE_SHORT: 'CommonBuffId' = 267950 - VILLAGER_HELP_QUEST_COOLDOWN_GARDEN_SHORT: 'CommonBuffId' = 267948 - VILLAGER_HELP_QUEST_COOLDOWN_LIVESTOCK_GARDEN_LONG: 'CommonBuffId' = 267952 - VILLAGER_HELP_QUEST_COOLDOWN_LIVESTOCK_SHORT: 'CommonBuffId' = 267947 - VILLAGER_HELP_QUEST_COOLDOWN_SOCIAL_MEDIUM: 'CommonBuffId' = 267951 - VILLAGER_HELP_QUEST_COOLDOWN_SOCIAL_SHORT: 'CommonBuffId' = 267946 - VILLAGER_HELP_QUEST_COOLDOWN_WILD_ANIMAL_FOOD_LONG: 'CommonBuffId' = 267953 - VILLAGER_HELP_QUEST_COOLDOWN_WILD_ANIMAL_SHORT: 'CommonBuffId' = 267949 - VILLAGER_HELP_SITUATION_GOSSIPER: 'CommonBuffId' = 264050 - VILLAGE_FAIR_AUTONOMY_COMPETITOR_PEN: 'CommonBuffId' = 266346 - VILLAGE_FAIR_AUTONOMY_COMPETITOR_STAND_A: 'CommonBuffId' = 266564 - VILLAGE_FAIR_AUTONOMY_COMPETITOR_STAND_B: 'CommonBuffId' = 266565 - VILLAGE_FAIR_AUTONOMY_GENERIC_FESTIVAL_GOER: 'CommonBuffId' = 261209 - VILLAGE_FAIR_AUTONOMY_JUDGE: 'CommonBuffId' = 260706 - VILLAGE_FAIR_CUTTING_HEDGE_ART: 'CommonBuffId' = 268905 - VILLAGE_FAIR_HIDDEN_BRIBED: 'CommonBuffId' = 268291 - VILLAGE_FAIR_HIDDEN_CHEAT_1ST_PRIMARY: 'CommonBuffId' = 269089 - VILLAGE_FAIR_HIDDEN_CHEAT_1ST_SUB: 'CommonBuffId' = 269090 - VILLAGE_FAIR_HIDDEN_CHEAT_LAST_PRIMARY: 'CommonBuffId' = 269091 - VILLAGE_FAIR_HIDDEN_CHEAT_LAST_SUB: 'CommonBuffId' = 269092 - VILLAGE_FAIR_HIDDEN_JUDGED: 'CommonBuffId' = 260710 - VILLAGE_FAIR_HIDDEN_PLAYER: 'CommonBuffId' = 264543 - VILLAGE_FAIR_HIDDEN_SUBMITTED_A: 'CommonBuffId' = 260708 - VILLAGE_FAIR_HIDDEN_SUBMITTED_B: 'CommonBuffId' = 260709 - VILLAGE_FAIR_HIDDEN_VIEW_TNS_GIVEN: 'CommonBuffId' = 268548 - VILLAGE_FAIR_HIDDEN_VILLAGE_FAIR_TRADITIONS_COOLDOWN: 'CommonBuffId' = 268941 - VILLAGE_FAIR_SUBMITTED_ENTRY_EXCELLENT: 'CommonBuffId' = 261315 - VILLAGE_FAIR_SUBMITTED_ENTRY_NORMAL: 'CommonBuffId' = 261314 - VILLAGE_FAIR_SUBMITTED_ENTRY_POOR: 'CommonBuffId' = 261313 - VILLAGE_FAIR_VIEW_SUBMISSION_GOOD: 'CommonBuffId' = 261241 - VILLAGE_FAIR_VIEW_SUBMISSION_POOR: 'CommonBuffId' = 261240 - VILLAGE_SHOPS_RETAIL_THERAPY: 'CommonBuffId' = 268024 - VILLAGE_SHOPS_WINDOW_SHOP_HIDDEN: 'CommonBuffId' = 268025 - VIOLIN_SAD_SONG: 'CommonBuffId' = 9771 - VIP_ROPE_FIGHT_EMBARRASSED: 'CommonBuffId' = 195631 - VIP_ROPE_HIDDEN_ATTEMPT_TO_ENTER_COOLDOWN: 'CommonBuffId' = 200878 - VIP_ROPE_HIDDEN_MAX_BRIBE: 'CommonBuffId' = 199882 - VIP_ROPE_NPC_SUCCESS: 'CommonBuffId' = 199888 - VOLUNTEER_EVENTS_ADVENTURE_COMPLETE: 'CommonBuffId' = 160545 - VOLUNTEER_EVENTS_BAKE_SALE: 'CommonBuffId' = 160579 - VOLUNTEER_EVENTS_BEACH: 'CommonBuffId' = 160575 - VOLUNTEER_EVENTS_BEACH_EMBARRASSED: 'CommonBuffId' = 166105 - VOLUNTEER_EVENTS_BEACH_HAPPY: 'CommonBuffId' = 166108 - VOLUNTEER_EVENTS_HIDDEN_STOP: 'CommonBuffId' = 163909 - VOLUNTEER_EVENTS_NURSING_HOME: 'CommonBuffId' = 160577 - VOLUNTEER_EVENTS_NURSING_HOME_BORED: 'CommonBuffId' = 165916 - VOLUNTEER_EVENTS_NURSING_HOME_EMBARRASSED: 'CommonBuffId' = 161988 - VOLUNTEER_EVENTS_NURSING_HOME_ENERGIZED: 'CommonBuffId' = 165998 - VOLUNTEER_EVENTS_SOUP_KITCHEN: 'CommonBuffId' = 160578 - VOLUNTEER_EVENTS_VOLUNTEER_END_ANGRY: 'CommonBuffId' = 160584 - VOLUNTEER_EVENTS_VOLUNTEER_END_HAPPY: 'CommonBuffId' = 160583 - VOLUNTEER_EVENTS_WALK: 'CommonBuffId' = 160576 - VOODOO_BACKFIRE_BAD: 'CommonBuffId' = 9098 - VOODOO_BACKFIRE_SAD: 'CommonBuffId' = 9122 - VOODOO_BIND: 'CommonBuffId' = 36975 - VOODOO_DAZED: 'CommonBuffId' = 12717 - VOODOO_FUN: 'CommonBuffId' = 12718 - VOODOO_LOVE: 'CommonBuffId' = 12719 - VOODOO_PAIN: 'CommonBuffId' = 12720 - VOODOO_UNCOMFORTABLE: 'CommonBuffId' = 12721 - WAKEUP_UNCOMFORTABLE: 'CommonBuffId' = 12731 - WAKE_UP_TO_SLEEP: 'CommonBuffId' = 331067 - WALK_BY_DOORBELL_RINGER: 'CommonBuffId' = 12732 - WALK_BY_MAILBOX_VISIT: 'CommonBuffId' = 24824 - WALK_BY_NPC_RING_DOORBELL_COOLDOWN: 'CommonBuffId' = 100156 - WALK_BY_PET_WORLD_JOGGER: 'CommonBuffId' = 166527 - WALK_BY_PET_WORLD_NO_HUNGER: 'CommonBuffId' = 167531 - WALK_BY_RENT_DUE_APARTMENT_LANDLORD: 'CommonBuffId' = 143689 - WALK_BY_STAND_IDLE: 'CommonBuffId' = 12733 - WALK_STYLE_ANGRY: 'CommonBuffId' = 116080 - WANT_ASPIRATION_GOAL_COMPLETED: 'CommonBuffId' = 273579 - WANT_FEAR_CONFRONTATION_SUCCESS_INFERIOR_BE_PRAISED: 'CommonBuffId' = 309265 - WANT_FEAR_CONFRONTATION_SUCCESS_INFERIOR_BE_PRAISED_PARTIAL: 'CommonBuffId' = 309266 - WANT_FEAR_CONFRONTATION_SUCCESS_INFERIOR_COOLDOWN: 'CommonBuffId' = 319043 - WANT_FEAR_FULFILLMENT_NEGATIVE_LEVEL_1: 'CommonBuffId' = 272994 - WANT_FEAR_FULFILLMENT_NEGATIVE_LEVEL_2: 'CommonBuffId' = 272995 - WANT_FEAR_FULFILLMENT_NEGATIVE_LEVEL_3: 'CommonBuffId' = 272996 - WANT_FEAR_LIKED_MUSIC_COOLDOWN: 'CommonBuffId' = 344335 - WANT_FEAR_LIKED_MUSIC_LISTEN_TO_ALTERNATIVE: 'CommonBuffId' = 301398 - WANT_FEAR_LIKED_MUSIC_LISTEN_TO_AMERICANA: 'CommonBuffId' = 301440 - WANT_FEAR_LIKED_MUSIC_LISTEN_TO_BACKYARD: 'CommonBuffId' = 301427 - WANT_FEAR_LIKED_MUSIC_LISTEN_TO_BAROQUE: 'CommonBuffId' = 301431 - WANT_FEAR_LIKED_MUSIC_LISTEN_TO_BATUU: 'CommonBuffId' = 346289 - WANT_FEAR_LIKED_MUSIC_LISTEN_TO_BLUES: 'CommonBuffId' = 301402 - WANT_FEAR_LIKED_MUSIC_LISTEN_TO_BRAZILIAN: 'CommonBuffId' = 346290 - WANT_FEAR_LIKED_MUSIC_LISTEN_TO_CLASSICAL: 'CommonBuffId' = 301403 - WANT_FEAR_LIKED_MUSIC_LISTEN_TO_COTTAGE_CORE: 'CommonBuffId' = 301455 - WANT_FEAR_LIKED_MUSIC_LISTEN_TO_DJ: 'CommonBuffId' = 301429 - WANT_FEAR_LIKED_MUSIC_LISTEN_TO_EASY_LISTENING: 'CommonBuffId' = 301426 - WANT_FEAR_LIKED_MUSIC_LISTEN_TO_ELECTRONICA: 'CommonBuffId' = 301404 - WANT_FEAR_LIKED_MUSIC_LISTEN_TO_FOCUS: 'CommonBuffId' = 301442 - WANT_FEAR_LIKED_MUSIC_LISTEN_TO_HIP_HOP: 'CommonBuffId' = 301415 - WANT_FEAR_LIKED_MUSIC_LISTEN_TO_ISLAND: 'CommonBuffId' = 301439 - WANT_FEAR_LIKED_MUSIC_LISTEN_TO_JAPANESE_FOLK: 'CommonBuffId' = 301441 - WANT_FEAR_LIKED_MUSIC_LISTEN_TO_JAZZ: 'CommonBuffId' = 301430 - WANT_FEAR_LIKED_MUSIC_LISTEN_TO_KIDS: 'CommonBuffId' = 301416 - WANT_FEAR_LIKED_MUSIC_LISTEN_TO_LATIN: 'CommonBuffId' = 301434 - WANT_FEAR_LIKED_MUSIC_LISTEN_TO_LATIN_POP: 'CommonBuffId' = 301435 - WANT_FEAR_LIKED_MUSIC_LISTEN_TO_LULLABIES: 'CommonBuffId' = 301417 - WANT_FEAR_LIKED_MUSIC_LISTEN_TO_METAL: 'CommonBuffId' = 301443 - WANT_FEAR_LIKED_MUSIC_LISTEN_TO_NEW_AGE: 'CommonBuffId' = 301428 - WANT_FEAR_LIKED_MUSIC_LISTEN_TO_NU_DISCO: 'CommonBuffId' = 301456 - WANT_FEAR_LIKED_MUSIC_LISTEN_TO_OLDIES: 'CommonBuffId' = 312572 - WANT_FEAR_LIKED_MUSIC_LISTEN_TO_POP: 'CommonBuffId' = 301418 - WANT_FEAR_LIKED_MUSIC_LISTEN_TO_RANCH: 'CommonBuffId' = 334865 - WANT_FEAR_LIKED_MUSIC_LISTEN_TO_RETRO: 'CommonBuffId' = 301419 - WANT_FEAR_LIKED_MUSIC_LISTEN_TO_RNB: 'CommonBuffId' = 343181 - WANT_FEAR_LIKED_MUSIC_LISTEN_TO_ROMANCE: 'CommonBuffId' = 301420 - WANT_FEAR_LIKED_MUSIC_LISTEN_TO_SINGER_SONGWRITER: 'CommonBuffId' = 301437 - WANT_FEAR_LIKED_MUSIC_LISTEN_TO_SPOOKY: 'CommonBuffId' = 301421 - WANT_FEAR_LIKED_MUSIC_LISTEN_TO_STRANGE_TUNES: 'CommonBuffId' = 301436 - WANT_FEAR_LIKED_MUSIC_LISTEN_TO_SUMMER_STRUT: 'CommonBuffId' = 301438 - WANT_FEAR_LIKED_MUSIC_LISTEN_TO_S_POP: 'CommonBuffId' = 301422 - WANT_FEAR_LIKED_MUSIC_LISTEN_TO_TWEEN_POP: 'CommonBuffId' = 301432 - WANT_FEAR_LIKED_MUSIC_LISTEN_TO_WINTER_MUSIC: 'CommonBuffId' = 301423 - WANT_FEAR_LIKED_MUSIC_LISTEN_TO_WORLD: 'CommonBuffId' = 301424 - WANT_GAINED_CONFIDENT: 'CommonBuffId' = 291767 - WANT_GAINED_ENERGIZED: 'CommonBuffId' = 291771 - WANT_GAINED_FLIRTY: 'CommonBuffId' = 291766 - WANT_GAINED_FOCUSED: 'CommonBuffId' = 291770 - WANT_GAINED_HAPPY: 'CommonBuffId' = 284205 - WANT_GAINED_INSPIRED: 'CommonBuffId' = 291769 - WANT_GAINED_PLAYFUL: 'CommonBuffId' = 291768 - WANT_MAKE_CONNECTIONS_TRACKER: 'CommonBuffId' = 287474 - WANT_MISS_WORK_TRACKER: 'CommonBuffId' = 287490 - WANT_SLACK_OFF_TRACKER: 'CommonBuffId' = 287476 - WANT_WORK_HARD_TRACKER: 'CommonBuffId' = 287477 - WANT_WORK_TASK_COMPLETED: 'CommonBuffId' = 273587 - WARDROBE_PEDESTAL_STYLED_PLAYFUL: 'CommonBuffId' = 197876 - WARDROBE_PEDESTAL_STYLIST_ARRIVAL: 'CommonBuffId' = 191621 - WARDROBE_PEDESTAL_STYLIST_BORED: 'CommonBuffId' = 191622 - WARDROBE_PEDESTAL_STYLIST_WORKING: 'CommonBuffId' = 191623 - WATCH_AFFORDANCE: 'CommonBuffId' = 164176 - WATERFALL_WALL_CALMING_WATER: 'CommonBuffId' = 118021 - WEARING_PAPER_BAG: 'CommonBuffId' = 238402 - WEARING_PAPER_BAG_INFLUENCE_POINTS_COOLDOWN: 'CommonBuffId' = 239235 - WEATHER_PREFERENCE_LOVES_COLD_TEMP_IS_COLD: 'CommonBuffId' = 189166 - WEATHER_PREFERENCE_LOVES_COLD_TEMP_IS_FREEZING: 'CommonBuffId' = 189167 - WEATHER_PREFERENCE_LOVES_HOT_TEMP_IS_BURNING: 'CommonBuffId' = 189175 - WEATHER_PREFERENCE_LOVES_HOT_TEMP_IS_HOT: 'CommonBuffId' = 189174 - WEATHER_PREFERENCE_WIND_HATES_WIND: 'CommonBuffId' = 189205 - WEATHER_PREFERENCE_WIND_LOVES_WIND: 'CommonBuffId' = 189204 - WEATHER_TEMPERATURE_WARMED_BY_KISS: 'CommonBuffId' = 183659 - WEATHER_TEMPERATURE_WARMED_UP_FLIRTY: 'CommonBuffId' = 183657 - WEATHER_TEMPERATURE_WARMED_UP_HAPPY: 'CommonBuffId' = 183658 - WEATHER_TEMPERATURE_WARMED_UP_ITS_A_SIGN: 'CommonBuffId' = 188450 - WEDDING_AISLE_DEBUG: 'CommonBuffId' = 278003 - WEDDING_AISLE_PICKED_BOUQUET_TYPE_1_1: 'CommonBuffId' = 280291 - WEDDING_AISLE_PICKED_BOUQUET_TYPE_1_2: 'CommonBuffId' = 280292 - WEDDING_AISLE_PICKED_BOUQUET_TYPE_1_3: 'CommonBuffId' = 280293 - WEDDING_AISLE_PICKED_BOUQUET_TYPE_1_4: 'CommonBuffId' = 280294 - WEDDING_AISLE_PICKED_BOUQUET_TYPE_1_5: 'CommonBuffId' = 280295 - WEDDING_AISLE_PICKED_BOUQUET_TYPE_1_6: 'CommonBuffId' = 280296 - WEDDING_AISLE_PICKED_BOUQUET_TYPE_1_7: 'CommonBuffId' = 280290 - WEDDING_AISLE_PICKED_BOUQUET_TYPE_2_1: 'CommonBuffId' = 280299 - WEDDING_AISLE_PICKED_BOUQUET_TYPE_2_2: 'CommonBuffId' = 280300 - WEDDING_AISLE_PICKED_BOUQUET_TYPE_2_3: 'CommonBuffId' = 280301 - WEDDING_AISLE_PICKED_BOUQUET_TYPE_2_4: 'CommonBuffId' = 280302 - WEDDING_AISLE_PICKED_BOUQUET_TYPE_2_5: 'CommonBuffId' = 280303 - WEDDING_AISLE_PICKED_BOUQUET_TYPE_2_6: 'CommonBuffId' = 280304 - WEDDING_AISLE_PICKED_BOUQUET_TYPE_2_7: 'CommonBuffId' = 280305 - WEDDING_AISLE_PICKED_BOUQUET_TYPE_2_8: 'CommonBuffId' = 280298 - WEDDING_AISLE_WEDDING_EXCITEMENT: 'CommonBuffId' = 277751 - WEDDING_AISLE_WEDDING_NERVES: 'CommonBuffId' = 277750 - WEDDING_ARCH_FANTASIZE_ANGRY: 'CommonBuffId' = 12736 - WEDDING_ARCH_FANTASIZE_COMMITMENT_ISSUES: 'CommonBuffId' = 97346 - WEDDING_ARCH_FANTASIZE_FLIRTY: 'CommonBuffId' = 12737 - WEDDING_ARCH_FANTASIZE_HAPPY: 'CommonBuffId' = 12738 - WEDDING_BETROTHED_CEREMONY: 'CommonBuffId' = 9368 - WEDDING_BETROTHED_GATHER: 'CommonBuffId' = 9369 - WEDDING_BETROTHED_RECEPTION: 'CommonBuffId' = 9370 - WEDDING_CAKE_CUT_CAKE_JM_BUFF: 'CommonBuffId' = 12739 - WEDDING_CAKE_CUT_CAKE_NO_JM_BUFF: 'CommonBuffId' = 12740 - WEDDING_CAME_TO_WEDDING_DURATION: 'CommonBuffId' = 283185 - WEDDING_CAME_TO_WEDDING_LOOT: 'CommonBuffId' = 283180 - WEDDING_CATERER_PREP: 'CommonBuffId' = 12746 - WEDDING_CEREMONY_FLOWER_BOUQUET_CAUGHT: 'CommonBuffId' = 274213 - WEDDING_CEREMONY_FLOWER_BOUQUET_EXPRESS_ANGER: 'CommonBuffId' = 277595 - WEDDING_CEREMONY_FLOWER_BOUQUET_EXPRESS_JOY: 'CommonBuffId' = 277594 - WEDDING_CEREMONY_FLOWER_BOUQUET_ROSETHORN: 'CommonBuffId' = 277591 - WEDDING_CEREMONY_FLOWER_BOUQUET_TOSSED: 'CommonBuffId' = 277577 - WEDDING_CUSTOM_STATE_OFFICIANT_SPEECH_COMPLETE: 'CommonBuffId' = 278952 - WEDDING_CUSTOM_STATE_ROLES_COUPLE_ARRIVAL: 'CommonBuffId' = 275934 - WEDDING_CUSTOM_STATE_SPEECH_COMPLETE: 'CommonBuffId' = 282132 - WEDDING_GROUP_DANCING_ALL_SYNCED_UP: 'CommonBuffId' = 279766 - WEDDING_GROUP_DANCING_IS_DANCING: 'CommonBuffId' = 278208 - WEDDING_GUEST_CEREMONY: 'CommonBuffId' = 12751 - WEDDING_GUEST_GATHER: 'CommonBuffId' = 12752 - WEDDING_GUEST_GATHER_IMPATIENT: 'CommonBuffId' = 12753 - WEDDING_GUEST_POST_CAKE: 'CommonBuffId' = 12754 - WEDDING_GUEST_PRE_CAKE: 'CommonBuffId' = 12755 - WEDDING_GUEST_RECEPTION: 'CommonBuffId' = 12756 - WEDDING_PARTIES_ALL_OVER_AGAIN: 'CommonBuffId' = 274218 - WEDDING_PARTIES_PARTY_HEARTY: 'CommonBuffId' = 274216 - WEDDING_SHELL_DRESS_SHOP: 'CommonBuffId' = 276428 - WEDDING_SHELL_TOWN_HALL_GET_MARRIED_ROLE_GETTING_MARRIED: 'CommonBuffId' = 276445 - WEDDING_SHELL_TOWN_HALL_GET_MARRIED_ROLE_START: 'CommonBuffId' = 276382 - WEDDING_SHELL_TOWN_HALL_GET_MARRIED_SITUATION_ENDED: 'CommonBuffId' = 276429 - WEDDING_TOAST_FINISHED: 'CommonBuffId' = 291224 - WEDDING_TOAST_HEARD_TOAST_SUCCESS: 'CommonBuffId' = 280616 - WEDDING_TOAST_MADE_TOAST_FAILURE: 'CommonBuffId' = 280615 - WEDDING_TOAST_MADE_TOAST_SUCCESS: 'CommonBuffId' = 280614 - WEDDING_WASH_ON_OR_PARTY_DURATION: 'CommonBuffId' = 283182 - WEDDING_WASH_ON_OR_PARTY_LOOT: 'CommonBuffId' = 283189 - WEDDING_WEDDING_TRADITION_BOUQUET_TOSS: 'CommonBuffId' = 276469 - WEDDING_WEDDING_TRADITION_COUPLE_CUT_CAKE: 'CommonBuffId' = 276474 - WEDDING_WEDDING_TRADITION_FIRST_DANCE: 'CommonBuffId' = 276470 - WEDDING_WEDDING_TRADITION_GROUP_DANCE: 'CommonBuffId' = 280626 - WEDDING_WEDDING_TRADITION_HAD_BOUQET: 'CommonBuffId' = 276471 - WEDDING_WEDDING_TRADITION_HAD_WEDDING_CAKE: 'CommonBuffId' = 276472 - WEDDING_WEDDING_TRADITION_HONOR_US: 'CommonBuffId' = 281070 - WEDDING_WEDDING_TRADITION_INVITED_TO_WEDDING: 'CommonBuffId' = 281067 - WEDDING_WEDDING_TRADITION_ITS_AN_HONOR: 'CommonBuffId' = 281064 - WEDDING_WEDDING_TRADITION_RING_EXCHANGE: 'CommonBuffId' = 276468 - WEDDING_WEDDING_TRADITION_SOCIALS: 'CommonBuffId' = 280992 - WEDDING_WEDDING_TRADITION_SPOUSAL_KISS: 'CommonBuffId' = 276467 - WEDDING_WEDDING_TRADITION_WALKED_DOWN_AISLE: 'CommonBuffId' = 276473 - WEDDING_WORLD_BIOLUMINESCENT_BURST: 'CommonBuffId' = 279922 - WEDDING_WORLD_BROADCASTER_FOUNTAIN: 'CommonBuffId' = 279928 - WEDDING_WORLD_BROADCASTER_TREE: 'CommonBuffId' = 279929 - WEDDING_WORLD_GRAPE_THIEF: 'CommonBuffId' = 279923 - WEDDING_WORLD_HANDPICKED: 'CommonBuffId' = 279924 - WEDDING_WORLD_METHUSELAH_MYSTERY: 'CommonBuffId' = 279920 - WEDDING_WORLD_RIVIERA_REFRESHER: 'CommonBuffId' = 279921 - WEDDING_WORLD_ROMANTIC_COIN_TOSS: 'CommonBuffId' = 279925 - WEDDING_WORLD_TOWN_SQUARE_ROMANCE: 'CommonBuffId' = 279919 - WEDDING_WORLD_WATERFALL_WISTFULNESS: 'CommonBuffId' = 279918 - WELCOME_WAGON_FRUITCAKE_BEARER_PUT_DOWN_FRUITCAKE: 'CommonBuffId' = 120127 - WELLNESS_CALMING_AURA: 'CommonBuffId' = 272284 - WELLNESS_CALMING_AURA_COOLDOWN: 'CommonBuffId' = 272285 - WELLNESS_CALMING_AURA_TARGET: 'CommonBuffId' = 272286 - WELLNESS_CUCUMBER_POWER_SIP: 'CommonBuffId' = 272638 - WELLNESS_HUSTLE: 'CommonBuffId' = 272722 - WELLNESS_MAINTAIN_HARMONY: 'CommonBuffId' = 272537 - WELLNESS_MAINTAIN_HARMONY_COMPLETE: 'CommonBuffId' = 272538 - WELLNESS_MASTER_WELLNESS: 'CommonBuffId' = 272544 - WELLNESS_MOMENT_OF_CLARITY: 'CommonBuffId' = 272278 - WELLNESS_MOMENT_OF_CLARITY_COOLDOWN: 'CommonBuffId' = 272279 - WELLNESS_PEACEFUL: 'CommonBuffId' = 272429 - WELLNESS_PROMOTE_COOLDOWN: 'CommonBuffId' = 272652 - WELLNESS_REGULAR: 'CommonBuffId' = 272456 - WELLNESS_REPEAT_CUSTOMER_COOLDOWN: 'CommonBuffId' = 272853 - WELLNESS_SATISFIED: 'CommonBuffId' = 272452 - WELLNESS_TEA: 'CommonBuffId' = 272776 - WELLNESS_TEA_BREWER: 'CommonBuffId' = 272854 - WEREWOLF_ABILITIES_DIG_SPOT: 'CommonBuffId' = 292378 - WEREWOLF_ABILITIES_DONT_LOOK_AT_ME: 'CommonBuffId' = 292063 - WEREWOLF_ABILITIES_FRESH_MEAT: 'CommonBuffId' = 292755 - WEREWOLF_ABILITIES_HUNTER_STRIDE: 'CommonBuffId' = 290325 - WEREWOLF_ABILITIES_INTIMIDATION: 'CommonBuffId' = 292384 - WEREWOLF_ABILITIES_IS_SMELLING: 'CommonBuffId' = 297981 - WEREWOLF_ABILITIES_LUNAR_HOWL: 'CommonBuffId' = 298352 - WEREWOLF_ABILITIES_LUNAR_HOWL_COOLDOWN: 'CommonBuffId' = 292571 - WEREWOLF_ABILITIES_NATURAL_HEALING: 'CommonBuffId' = 290527 - WEREWOLF_ABILITIES_NEARBY_MARKED: 'CommonBuffId' = 292059 - WEREWOLF_ABILITIES_OCCULT_SMELL: 'CommonBuffId' = 297805 - WEREWOLF_ABILITIES_PACIFY_COOLDOWN: 'CommonBuffId' = 292124 - WEREWOLF_ABILITIES_PRIMAL: 'CommonBuffId' = 289930 - WEREWOLF_ABILITIES_RESIST_COOLDOWN: 'CommonBuffId' = 290215 - WEREWOLF_ABILITIES_RESIST_SUCCESS: 'CommonBuffId' = 297752 - WEREWOLF_ABILITIES_SAD_WOLF: 'CommonBuffId' = 290328 - WEREWOLF_ABILITIES_SMELLS_ALIEN: 'CommonBuffId' = 290205 - WEREWOLF_ABILITIES_SMELLS_ANGRY: 'CommonBuffId' = 290198 - WEREWOLF_ABILITIES_SMELLS_FLIRTY: 'CommonBuffId' = 290201 - WEREWOLF_ABILITIES_SMELLS_GENERIC: 'CommonBuffId' = 290183 - WEREWOLF_ABILITIES_SMELLS_LIKE_VAMPIRE: 'CommonBuffId' = 295321 - WEREWOLF_ABILITIES_SMELLS_MERMAID: 'CommonBuffId' = 290206 - WEREWOLF_ABILITIES_SMELLS_SCARED: 'CommonBuffId' = 290200 - WEREWOLF_ABILITIES_SMELLS_VAMPIRE: 'CommonBuffId' = 290203 - WEREWOLF_ABILITIES_SMELLS_WEREWOLF: 'CommonBuffId' = 290202 - WEREWOLF_ABILITIES_SMELLS_WITCH: 'CommonBuffId' = 290204 - WEREWOLF_ABILITIES_SOMBER_HOWL_COOLDOWN: 'CommonBuffId' = 290332 - WEREWOLF_ABILITIES_SPEED: 'CommonBuffId' = 290517 - WEREWOLF_ABILITIES_SURPRISINGLY_TASTY: 'CommonBuffId' = 293994 - WEREWOLF_ABILITIES_TANTALIZING_AROMA: 'CommonBuffId' = 290210 - WEREWOLF_ABILITIES_TANTALIZING_AROMA_FLIRTY: 'CommonBuffId' = 297756 - WEREWOLF_ABILITIES_TANTALIZING_AROMA_PLAYFUL: 'CommonBuffId' = 297757 - WEREWOLF_ABILITIES_TEACH_TO_HOWL: 'CommonBuffId' = 295585 - WEREWOLF_ABILITIES_THE_HORRORS: 'CommonBuffId' = 290324 - WEREWOLF_ABILITIES_TOOTHACHE: 'CommonBuffId' = 289514 - WEREWOLF_ABILITIES_WEREWOLF_DIPLOMACY: 'CommonBuffId' = 298161 - WEREWOLF_ABILITIES_WEREWOLF_DISTRUST: 'CommonBuffId' = 298160 - WEREWOLF_ABILITIES_WEREWOLF_GUIDANCE_PC: 'CommonBuffId' = 292126 - WEREWOLF_ABILITIES_WEREWOLF_GUIDANCE_PC_HAPPY: 'CommonBuffId' = 296231 - WEREWOLF_ABILITIES_WEREWOLF_GUIDANCE_TYAE: 'CommonBuffId' = 292125 - WEREWOLF_ABILITIES_WEREWOLF_MENACE: 'CommonBuffId' = 292065 - WEREWOLF_ABILITIES_WHAT_HAVE_I_DONE: 'CommonBuffId' = 289515 - WEREWOLF_ABILITIES_WOLF_AMONGUS: 'CommonBuffId' = 297758 - WEREWOLF_ACTOR_ABOUT_TO_FIGHT: 'CommonBuffId' = 290866 - WEREWOLF_ALL_AGES: 'CommonBuffId' = 291538 - WEREWOLF_ALPHA_OF_HOUSE: 'CommonBuffId' = 292947 - WEREWOLF_APEX: 'CommonBuffId' = 297282 - WEREWOLF_ASPIRATIONS_ALREADY_FAINTED: 'CommonBuffId' = 296166 - WEREWOLF_ASPIRATIONS_EXPERIENCE_FULL_MOON: 'CommonBuffId' = 291330 - WEREWOLF_ASPIRATIONS_FRIENDLY_WOLF: 'CommonBuffId' = 291634 - WEREWOLF_ASPIRATIONS_WIN_WEREWOLF_FIGHT: 'CommonBuffId' = 291341 - WEREWOLF_BATUU_WOLF: 'CommonBuffId' = 299990 - WEREWOLF_BEASTLY_GROWTH_SPURT: 'CommonBuffId' = 292942 - WEREWOLF_CD_LORE_BOOKS_NOTIF: 'CommonBuffId' = 300389 - WEREWOLF_COMMAND_TO_WORK_OUT: 'CommonBuffId' = 293826 - WEREWOLF_CREATION_ASKING_TO_BE_TURNED: 'CommonBuffId' = 293713 - WEREWOLF_CREATION_BECOMING_HUMAN: 'CommonBuffId' = 288322 - WEREWOLF_CREATION_BECOMING_HUMAN_WEREBIES: 'CommonBuffId' = 288332 - WEREWOLF_CREATION_BEING_TURNED: 'CommonBuffId' = 289681 - WEREWOLF_CREATION_CD_BEEN_ASKED: 'CommonBuffId' = 293712 - WEREWOLF_CREATION_FORCED_SCARED: 'CommonBuffId' = 289421 - WEREWOLF_CREATION_INSATIABLE_HUNGER_1: 'CommonBuffId' = 288315 - WEREWOLF_CREATION_INSATIABLE_HUNGER_2: 'CommonBuffId' = 288318 - WEREWOLF_CREATION_PAINFUL_BITE: 'CommonBuffId' = 293717 - WEREWOLF_CREATION_TURNED: 'CommonBuffId' = 288319 - WEREWOLF_CREATION_WEREBIES_1: 'CommonBuffId' = 288320 - WEREWOLF_CREATION_WEREBIES_2: 'CommonBuffId' = 288321 - WEREWOLF_CREATION_WEREBIES_PAUSED: 'CommonBuffId' = 292408 - WEREWOLF_CREATION_WITNESS_SCARED: 'CommonBuffId' = 289676 - WEREWOLF_DISGUST_COOLDOWN: 'CommonBuffId' = 300157 - WEREWOLF_DOG_WATER: 'CommonBuffId' = 295323 - WEREWOLF_DONT_BE_A_JERK: 'CommonBuffId' = 288741 - WEREWOLF_DONT_RESET_FURY: 'CommonBuffId' = 295135 - WEREWOLF_DONT_RUN_AWAY: 'CommonBuffId' = 299805 - WEREWOLF_ENRAGE_TARGET: 'CommonBuffId' = 298610 - WEREWOLF_FATED_MATES: 'CommonBuffId' = 293547 - WEREWOLF_FIGHT_SIM_LOST: 'CommonBuffId' = 287971 - WEREWOLF_FIGHT_SIM_WON: 'CommonBuffId' = 287973 - WEREWOLF_FIGHT_SPARRING: 'CommonBuffId' = 287966 - WEREWOLF_FIGHT_VAMPIRE_LOST: 'CommonBuffId' = 287968 - WEREWOLF_FIGHT_VAMPIRE_WON: 'CommonBuffId' = 287967 - WEREWOLF_FIGHT_WOLF_BEAT_SIM: 'CommonBuffId' = 287972 - WEREWOLF_FIGHT_WOLF_BEAT_VAMPIRE: 'CommonBuffId' = 287970 - WEREWOLF_FIGHT_WOLF_LOST_TO_SIM: 'CommonBuffId' = 287969 - WEREWOLF_FIGHT_WOLF_LOST_TO_VAMPIRE: 'CommonBuffId' = 287974 - WEREWOLF_FLUFFY_PUPPY: 'CommonBuffId' = 291181 - WEREWOLF_FURY_EXTREME: 'CommonBuffId' = 285805 - WEREWOLF_FURY_FREEZE: 'CommonBuffId' = 299670 - WEREWOLF_FURY_GLOW_EXTREME: 'CommonBuffId' = 290769 - WEREWOLF_FURY_GLOW_HIGH: 'CommonBuffId' = 290770 - WEREWOLF_FURY_HIGH: 'CommonBuffId' = 285804 - WEREWOLF_FURY_LOW: 'CommonBuffId' = 285802 - WEREWOLF_FURY_MEDIUM: 'CommonBuffId' = 285803 - WEREWOLF_FURY_RAMPAGE: 'CommonBuffId' = 285807 - WEREWOLF_HARASS_COOLDOWN: 'CommonBuffId' = 293625 - WEREWOLF_IN_BEAST_FORM: 'CommonBuffId' = 300835 - WEREWOLF_IS_WEREWOLF: 'CommonBuffId' = 276405 - WEREWOLF_KICKED_FROM_PACK: 'CommonBuffId' = 293156 - WEREWOLF_MOON_MADNESS: 'CommonBuffId' = 292945 - WEREWOLF_NEAR_TRANSFORMED_WEREWOLF: 'CommonBuffId' = 288846 - WEREWOLF_NEW_FANG_PAIN: 'CommonBuffId' = 292940 - WEREWOLF_NOT_MEANT_TO_BE: 'CommonBuffId' = 293548 - WEREWOLF_NPC_OUTSIDE_WOLF_TOWN_DEFAULT: 'CommonBuffId' = 293876 - WEREWOLF_NPC_OUTSIDE_WOLF_TOWN_RESTRICTED: 'CommonBuffId' = 293874 - WEREWOLF_PACK_A: 'CommonBuffId' = 290636 - WEREWOLF_PACK_ALLIANCE_FEUD_ALL_FOR_WOLF: 'CommonBuffId' = 289720 - WEREWOLF_PACK_ALLIANCE_FEUD_FEUDING: 'CommonBuffId' = 289721 - WEREWOLF_PACK_ALLIANCE_FEUD_HIDDEN_ALLIANCE: 'CommonBuffId' = 289717 - WEREWOLF_PACK_ALLIANCE_FEUD_HIDDEN_FEUD: 'CommonBuffId' = 289718 - WEREWOLF_PACK_ALLIANCE_FEUD_HIDDEN_NEUTRAL: 'CommonBuffId' = 289709 - WEREWOLF_PACK_A_NPC: 'CommonBuffId' = 293739 - WEREWOLF_PACK_B: 'CommonBuffId' = 290637 - WEREWOLF_PACK_BAD_PACK_MEMBER: 'CommonBuffId' = 290472 - WEREWOLF_PACK_B_NPC: 'CommonBuffId' = 293738 - WEREWOLF_PACK_CHECK_RESOURCES_COOLDOWN: 'CommonBuffId' = 289619 - WEREWOLF_PACK_CHECK_RESOURCES_COOLDOWN_SPECIAL_A: 'CommonBuffId' = 289628 - WEREWOLF_PACK_CHECK_RESOURCES_COOLDOWN_SPECIAL_B: 'CommonBuffId' = 289629 - WEREWOLF_PACK_COOLDOWN_CHALLENGE_LEADER: 'CommonBuffId' = 293734 - WEREWOLF_PACK_COOLDOWN_FRIENDLY_TUG_OF_WAR: 'CommonBuffId' = 296626 - WEREWOLF_PACK_DEMOTED: 'CommonBuffId' = 290944 - WEREWOLF_PACK_DISCIPLINED: 'CommonBuffId' = 293361 - WEREWOLF_PACK_DISCIPLINE_PROBATION: 'CommonBuffId' = 286088 - WEREWOLF_PACK_DISCIPLINE_PROBATION_LEADER: 'CommonBuffId' = 286783 - WEREWOLF_PACK_DISCIPLINE_REPORT_TO_LEADER: 'CommonBuffId' = 286152 - WEREWOLF_PACK_DISCIPLINE_REPORT_TO_LEADER_FRIEND_A: 'CommonBuffId' = 287086 - WEREWOLF_PACK_DISCIPLINE_REPORT_TO_LEADER_FRIEND_B: 'CommonBuffId' = 287087 - WEREWOLF_PACK_DISCIPLINE_STRONG_WARNING_DIPLOMACY: 'CommonBuffId' = 286153 - WEREWOLF_PACK_DISCIPLINE_STRONG_WARNING_EXPAND_EXPLORE: 'CommonBuffId' = 286202 - WEREWOLF_PACK_DISCIPLINE_STRONG_WARNING_PACK_PARTICIPATION: 'CommonBuffId' = 286203 - WEREWOLF_PACK_DISCIPLINE_STRONG_WARNING_SELF_IMPROVEMENT: 'CommonBuffId' = 286204 - WEREWOLF_PACK_DISCIPLINE_STRONG_WARNING_SELF_SUFFICIENCY: 'CommonBuffId' = 286205 - WEREWOLF_PACK_DISCIPLINE_WARNING: 'CommonBuffId' = 297603 - WEREWOLF_PACK_DISCIPLINE_WARNING_DIPLOMACY: 'CommonBuffId' = 286087 - WEREWOLF_PACK_DISCIPLINE_WARNING_EXPAND_EXPLORE: 'CommonBuffId' = 286195 - WEREWOLF_PACK_DISCIPLINE_WARNING_PACK_PARTICIPATION: 'CommonBuffId' = 286196 - WEREWOLF_PACK_DISCIPLINE_WARNING_SELF_IMPROVEMENT: 'CommonBuffId' = 286197 - WEREWOLF_PACK_DISCIPLINE_WARNING_SELF_SUFFICIENCY: 'CommonBuffId' = 286198 - WEREWOLF_PACK_FETCH_COOLDOWN: 'CommonBuffId' = 294217 - WEREWOLF_PACK_FRIEND_A: 'CommonBuffId' = 286992 - WEREWOLF_PACK_FRIEND_B: 'CommonBuffId' = 286993 - WEREWOLF_PACK_JOIN_TRIAL_GAVE_COLLECTABLE_PACK_A: 'CommonBuffId' = 287566 - WEREWOLF_PACK_JOIN_TRIAL_GAVE_COLLECTABLE_PACK_B: 'CommonBuffId' = 287568 - WEREWOLF_PACK_JOIN_TRIAL_GAVE_FOOD_PACK_A: 'CommonBuffId' = 287565 - WEREWOLF_PACK_JOIN_TRIAL_GAVE_FOOD_PACK_B: 'CommonBuffId' = 287567 - WEREWOLF_PACK_JOIN_TRIAL_IN_PROGRESS_PACK_A: 'CommonBuffId' = 292266 - WEREWOLF_PACK_JOIN_TRIAL_IN_PROGRESS_PACK_B: 'CommonBuffId' = 292267 - WEREWOLF_PACK_JOIN_TRIAL_LUNAR_EPIPHANY_PACK_A: 'CommonBuffId' = 292243 - WEREWOLF_PACK_JOIN_TRIAL_LUNAR_EPIPHANY_PACK_B: 'CommonBuffId' = 292244 - WEREWOLF_PACK_JOIN_TRIAL_PACK_HOWL_PACK_A: 'CommonBuffId' = 292247 - WEREWOLF_PACK_JOIN_TRIAL_PACK_HOWL_PACK_B: 'CommonBuffId' = 292248 - WEREWOLF_PACK_JOIN_TRIAL_SCAVENGE_PACK_A: 'CommonBuffId' = 292245 - WEREWOLF_PACK_JOIN_TRIAL_SCAVENGE_PACK_B: 'CommonBuffId' = 292246 - WEREWOLF_PACK_JOIN_TRIAL_SPAR_PACK_A: 'CommonBuffId' = 289579 - WEREWOLF_PACK_JOIN_TRIAL_SPAR_PACK_B: 'CommonBuffId' = 289580 - WEREWOLF_PACK_LEADER_TO_LEADER_ANGRY: 'CommonBuffId' = 293570 - WEREWOLF_PACK_LEADER_TO_LEADER_CD: 'CommonBuffId' = 293582 - WEREWOLF_PACK_LEADER_TO_LEADER_CONFIDENT: 'CommonBuffId' = 293569 - WEREWOLF_PACK_LET_DOWN_THE_PACK: 'CommonBuffId' = 290474 - WEREWOLF_PACK_NEW_ALPHA_IN_TOWN: 'CommonBuffId' = 290937 - WEREWOLF_PACK_NPC_ENTER_SHELL_COOLDOWN: 'CommonBuffId' = 290578 - WEREWOLF_PACK_NPC_GIVE_GIFT_COOLDOWN: 'CommonBuffId' = 292203 - WEREWOLF_PACK_PRIDE_OF_THE_PACK: 'CommonBuffId' = 290473 - WEREWOLF_PACK_PROMOTED: 'CommonBuffId' = 290945 - WEREWOLF_PACK_RECENTLY_DECLINED_INVITE_A: 'CommonBuffId' = 290560 - WEREWOLF_PACK_RECENTLY_DECLINED_INVITE_B: 'CommonBuffId' = 290561 - WEREWOLF_PACK_RECENTLY_DISCPLINED_CD: 'CommonBuffId' = 293360 - WEREWOLF_PACK_RECENTLY_GAVE_UP_LEADERSHIP: 'CommonBuffId' = 291004 - WEREWOLF_PACK_RECENTLY_GOT_GIFT_FROM_NPC: 'CommonBuffId' = 292204 - WEREWOLF_PACK_RECENTLY_KICKED_OUT_A: 'CommonBuffId' = 291065 - WEREWOLF_PACK_RECENTLY_KICKED_OUT_B: 'CommonBuffId' = 291066 - WEREWOLF_PACK_RECENTLY_LEFT_A: 'CommonBuffId' = 290556 - WEREWOLF_PACK_RECENTLY_LEFT_B: 'CommonBuffId' = 290557 - WEREWOLF_PACK_RECENTLY_LOST_TRUST_A: 'CommonBuffId' = 290558 - WEREWOLF_PACK_RECENTLY_LOST_TRUST_B: 'CommonBuffId' = 290559 - WEREWOLF_PACK_RECENTLY_MENTORED: 'CommonBuffId' = 292322 - WEREWOLF_PACK_TRUST_AT_RISK_FRIEND_A: 'CommonBuffId' = 286995 - WEREWOLF_PACK_TRUST_AT_RISK_FRIEND_B: 'CommonBuffId' = 286996 - WEREWOLF_PACK_TRUST_WARNING_COOLDOWN_FRIEND_A: 'CommonBuffId' = 287043 - WEREWOLF_PACK_TRUST_WARNING_COOLDOWN_FRIEND_B: 'CommonBuffId' = 287044 - WEREWOLF_PACK_UPHOLDING_PACK_VALUES: 'CommonBuffId' = 290471 - WEREWOLF_PACK_VALUE_EXPAND_EXPLORE_VISITING: 'CommonBuffId' = 289138 - WEREWOLF_PACK_VALUE_EXPAND_EXPLORE_VISIT_GAIN: 'CommonBuffId' = 289382 - WEREWOLF_PACK_VALUE_MOD_DIPLOMACY: 'CommonBuffId' = 289119 - WEREWOLF_PACK_VALUE_MOD_EXPAND_EXPLORE: 'CommonBuffId' = 289120 - WEREWOLF_PACK_VALUE_MOD_PACK_PARTICIPATION_A: 'CommonBuffId' = 289519 - WEREWOLF_PACK_VALUE_MOD_PACK_PARTICIPATION_B: 'CommonBuffId' = 289529 - WEREWOLF_PACK_VALUE_MOD_SELF_IMPROVEMENT: 'CommonBuffId' = 289123 - WEREWOLF_PACK_VALUE_MOD_SELF_SUFFICIENCY: 'CommonBuffId' = 289124 - WEREWOLF_PACK_VALUE_PAUSE_DECAY_A: 'CommonBuffId' = 298222 - WEREWOLF_PACK_VALUE_PAUSE_DECAY_B: 'CommonBuffId' = 298223 - WEREWOLF_RABBIT_HOLE_COOLDOWN: 'CommonBuffId' = 288570 - WEREWOLF_RAMPAGE: 'CommonBuffId' = 285810 - WEREWOLF_RAMPAGE_FIRST_TIME: 'CommonBuffId' = 288633 - WEREWOLF_RATHER_NOT_TALK: 'CommonBuffId' = 288598 - WEREWOLF_RAW_MEAT: 'CommonBuffId' = 290319 - WEREWOLF_ROLE_SHOW_WEREFORM: 'CommonBuffId' = 288997 - WEREWOLF_SCARED_REACTION: 'CommonBuffId' = 288087 - WEREWOLF_SHOULD_RAMPAGE_AFTER_FIGHT: 'CommonBuffId' = 290870 - WEREWOLF_SMASH_COOLDOWN: 'CommonBuffId' = 296725 - WEREWOLF_SORE_THROAT: 'CommonBuffId' = 298273 - WEREWOLF_SORE_THROAT_FORMER_LYCAN: 'CommonBuffId' = 298312 - WEREWOLF_STRONGER_THAN_I_THOUGHT: 'CommonBuffId' = 290925 - WEREWOLF_SYMPATHY_COOLDOWN: 'CommonBuffId' = 293315 - WEREWOLF_SYMPATHY_FAIL: 'CommonBuffId' = 293316 - WEREWOLF_THAT_WAS_WEIRD: 'CommonBuffId' = 288770 - WEREWOLF_TRANSFORMATION_MASTERY: 'CommonBuffId' = 288777 - WEREWOLF_WEREWOLF_AWESOME: 'CommonBuffId' = 294879 - WEREWOLF_WEREWOLF_REPAIRMAN_COOLDOWN: 'CommonBuffId' = 298904 - WEREWOLF_WET: 'CommonBuffId' = 292756 - WEREWOLF_WHAT_HAPPENED: 'CommonBuffId' = 288590 - WEREWOLF_WOLF_TOWN_RABBIT_HOLE_TRANSFORMATION: 'CommonBuffId' = 299770 - WEREWOLF_WOOHOO: 'CommonBuffId' = 293001 - WEREWOLF_WORST_HANGOVER: 'CommonBuffId' = 288592 - WEREWOLF_ZOOMIES_COOLDOWN: 'CommonBuffId' = 293627 - WETNESS_IMMUNE: 'CommonBuffId' = 190198 - WILDLIFE_ENCOUNTER_ALL_IN_THE_PREPARATION: 'CommonBuffId' = 248072 - WILDLIFE_ENCOUNTER_AS_BAD_AS_THEY_SAID: 'CommonBuffId' = 248075 - WILDLIFE_ENCOUNTER_ATTACKED: 'CommonBuffId' = 247863 - WILDLIFE_ENCOUNTER_AT_LEAST_NOT_ME: 'CommonBuffId' = 248071 - WILDLIFE_ENCOUNTER_BADLY_SCRATCHED_AND_BUFFETED: 'CommonBuffId' = 248077 - WILDLIFE_ENCOUNTER_CENTIPEDE_PANIC_RUN_ROUTE_EVENT: 'CommonBuffId' = 253928 - WILDLIFE_ENCOUNTER_DANGEROUS_OUT_HERE: 'CommonBuffId' = 248070 - WILDLIFE_ENCOUNTER_HIKING_TRAIL_ATTACK_COOLDOWN: 'CommonBuffId' = 249480 - WILDLIFE_ENCOUNTER_MIND_OVER_MENACE: 'CommonBuffId' = 248073 - WILDLIFE_ENCOUNTER_PAINFUL_BITE: 'CommonBuffId' = 248076 - WILDLIFE_ENCOUNTER_PEACEFUL_NATURE: 'CommonBuffId' = 248082 - WILDLIFE_ENCOUNTER_SHOCKING_ENCOUNTER: 'CommonBuffId' = 248078 - WILDLIFE_ENCOUNTER_SKILLFUL_SHIMMY: 'CommonBuffId' = 248074 - WILDLIFE_ENCOUNTER_SPIRITUAL_AWE: 'CommonBuffId' = 248080 - WILDLIFE_ENCOUNTER_SPIRITUAL_BLESSING: 'CommonBuffId' = 248079 - WILDLIFE_ENCOUNTER_SPIRITUAL_MISFORTUNE_BLADDER: 'CommonBuffId' = 249526 - WILDLIFE_ENCOUNTER_SPIRITUAL_MISFORTUNE_ENERGY: 'CommonBuffId' = 248081 - WILDLIFE_ENCOUNTER_SPIRITUAL_MISFORTUNE_FUN: 'CommonBuffId' = 249530 - WILDLIFE_ENCOUNTER_SPIRITUAL_MISFORTUNE_HUNGER: 'CommonBuffId' = 249529 - WILDLIFE_ENCOUNTER_SPIRITUAL_MISFORTUNE_HYGIENE: 'CommonBuffId' = 249527 - WILDLIFE_ENCOUNTER_SPIRITUAL_MISFORTUNE_SOCIAL: 'CommonBuffId' = 249528 - WISHING_WELL_ACCEPTED_FATE: 'CommonBuffId' = 131025 - WISHING_WELL_ADOPTION_PRE_APPROVED: 'CommonBuffId' = 131057 - WISHING_WELL_ALWAYS_SUNNY: 'CommonBuffId' = 131043 - WISHING_WELL_A_FEW_YEARS_YOUNGER: 'CommonBuffId' = 131050 - WISHING_WELL_CANT_GET_PREGNANT: 'CommonBuffId' = 133105 - WISHING_WELL_CANT_STOP_SMILING: 'CommonBuffId' = 131049 - WISHING_WELL_CHANCE_AT_LIFE: 'CommonBuffId' = 131022 - WISHING_WELL_EXPEDIENT_LEARNING: 'CommonBuffId' = 131030 - WISHING_WELL_EXTENDED_YOUTH: 'CommonBuffId' = 131051 - WISHING_WELL_EXTRA_VIGOR: 'CommonBuffId' = 131047 - WISHING_WELL_FEELING_YOUNG: 'CommonBuffId' = 131052 - WISHING_WELL_FOGGED_MIND: 'CommonBuffId' = 131031 - WISHING_WELL_FOREVER_CHEERFUL: 'CommonBuffId' = 131044 - WISHING_WELL_FORTUNES_ABOUND: 'CommonBuffId' = 131038 - WISHING_WELL_GRADES_DROPPED: 'CommonBuffId' = 131278 - WISHING_WELL_HAPPINESS_DOESNT_LAST_FOREVER: 'CommonBuffId' = 131046 - WISHING_WELL_HIDDEN_ALREADY_WISHED: 'CommonBuffId' = 132178 - WISHING_WELL_HIDDEN_ALWAYS_REVIVE: 'CommonBuffId' = 131231 - WISHING_WELL_HIDDEN_BLACKMAIL: 'CommonBuffId' = 131188 - WISHING_WELL_HIDDEN_CANNOT_REVIVE: 'CommonBuffId' = 131285 - WISHING_WELL_HIDDEN_ULTIMATE_PICK_UP_LINE: 'CommonBuffId' = 131189 - WISHING_WELL_HIDDEN_WHERES_MY_HAPPINESS_BROADCASTER: 'CommonBuffId' = 132123 - WISHING_WELL_HOPELESS_IN_ROMANCE: 'CommonBuffId' = 131027 - WISHING_WELL_INGREDIENTS_FOR_LIFE: 'CommonBuffId' = 132156 - WISHING_WELL_I_AM_HAPPY: 'CommonBuffId' = 131045 - WISHING_WELL_I_WISHED_FOR_BETTER_GRADES: 'CommonBuffId' = 131232 - WISHING_WELL_I_WISHED_FOR_THE_PROMOTION: 'CommonBuffId' = 131036 - WISHING_WELL_JOYS_OF_CHILDREN_ANGRY: 'CommonBuffId' = 131059 - WISHING_WELL_JOYS_OF_CHILDREN_HAPPY: 'CommonBuffId' = 131021 - WISHING_WELL_JUST_A_GHOST: 'CommonBuffId' = 131024 - WISHING_WELL_LACK_OF_TALENT: 'CommonBuffId' = 131033 - WISHING_WELL_LEAKING_HAPPINESS: 'CommonBuffId' = 131048 - WISHING_WELL_LEARNED_DARKEST_SECRETS: 'CommonBuffId' = 131039 - WISHING_WELL_LOSS_OF_YOUTH: 'CommonBuffId' = 131055 - WISHING_WELL_MICROTRANSACTIONS: 'CommonBuffId' = 131041 - WISHING_WELL_MIDAS_TOUCH: 'CommonBuffId' = 131040 - WISHING_WELL_MIND_NUMBED: 'CommonBuffId' = 131032 - WISHING_WELL_MIRACLE_REVIVAL: 'CommonBuffId' = 131229 - WISHING_WELL_MYSTICAL_ROMANCE_TIPS: 'CommonBuffId' = 131017 - WISHING_WELL_MY_SIMOLEONS_BURNED_UP: 'CommonBuffId' = 131042 - WISHING_WELL_NOT_WHAT_I_WISHED_FOR: 'CommonBuffId' = 131035 - WISHING_WELL_NOT_WHAT_I_WISHED_FOR_KIDS: 'CommonBuffId' = 133387 - WISHING_WELL_OVEREXERTED_SELF: 'CommonBuffId' = 131054 - WISHING_WELL_OVERFLOWING_VIGOR: 'CommonBuffId' = 131053 - WISHING_WELL_PERPETUAL_YOUTH: 'CommonBuffId' = 131056 - WISHING_WELL_RAISING_A_GHOST: 'CommonBuffId' = 131060 - WISHING_WELL_SKILL_LEARNED: 'CommonBuffId' = 131029 - WISHING_WELL_TRY_FOR_BABY: 'CommonBuffId' = 131058 - WISHING_WELL_ULTIMATE_FLIRTY: 'CommonBuffId' = 131018 - WISHING_WELL_UNIVERSAL_KNOWLEDGE: 'CommonBuffId' = 131028 - WISHING_WELL_WHERE_IS_MY_HAPPINESS: 'CommonBuffId' = 131020 - WISHING_WELL_WISH_NOT_GRANTED: 'CommonBuffId' = 131023 - WISHING_WELL_WON_THE_LOTTERY: 'CommonBuffId' = 131037 - WISHING_WELL_WORKED_SO_HARD: 'CommonBuffId' = 131019 - WITCH_OCCULT_BLOODLINE_ANCIENT: 'CommonBuffId' = 218079 - WITCH_OCCULT_BLOODLINE_STRONG: 'CommonBuffId' = 218078 - WITCH_OCCULT_BLOODLINE_WEAK: 'CommonBuffId' = 218077 - WITCH_OCCULT_BUILD_CHARGE_COOLDOWN: 'CommonBuffId' = 215424 - WITCH_OCCULT_BUILD_CHARGE_COOLDOWN_MAGICAL_RESONANCE: 'CommonBuffId' = 219110 - WITCH_OCCULT_CHARGE_1_CHARGED: 'CommonBuffId' = 213026 - WITCH_OCCULT_CHARGE_2_OVERCHARGED: 'CommonBuffId' = 213028 - WITCH_OCCULT_CHARGE_3_DANGEROUSLY_OVERCHARGED: 'CommonBuffId' = 213029 - WITCH_OCCULT_CHARGE_APPLY_FX_1_CHARGED: 'CommonBuffId' = 215727 - WITCH_OCCULT_CHARGE_APPLY_FX_2_OVERCHARGED: 'CommonBuffId' = 215730 - WITCH_OCCULT_CHARGE_APPLY_FX_3_DANGEROUSLY_OVERCHARGED: 'CommonBuffId' = 215729 - WITCH_OCCULT_CHARGE_REACTION_COOLDOWN: 'CommonBuffId' = 215508 - WITCH_OCCULT_DISCHARGE_COOLDOWN: 'CommonBuffId' = 215423 - WITCH_OCCULT_DISCHARGE_COOLDOWN_MAGICAL_RESONANCE: 'CommonBuffId' = 219113 - WITCH_OCCULT_IS_WITCH: 'CommonBuffId' = 213063 - WITCH_OCCULT_IS_WITCH_ANY_AGE: 'CommonBuffId' = 217701 - WITCH_OCCULT_LOCK_CHARGE: 'CommonBuffId' = 213035 - WITCH_OCCULT_LOCK_NPC_STATS: 'CommonBuffId' = 219035 - WITCH_OCCULT_MAGIC_TRAINING_STOP: 'CommonBuffId' = 215391 - WITCH_OCCULT_MOTE_SIGHT_TIMEOUT: 'CommonBuffId' = 215166 - WITCH_OCCULT_MY_POWER_GROWS: 'CommonBuffId' = 215360 - WITCH_OCCULT_RITE_OF_ASCENSION_COOLDOWN: 'CommonBuffId' = 215285 - WITCH_OCCULT_RUN_AWAY_FORCE_PANIC: 'CommonBuffId' = 215500 - WITCH_OCCULT_SCARED_BY_MAGIC: 'CommonBuffId' = 215490 - WITCH_OCCULT_USE_WAND: 'CommonBuffId' = 215320 - WITCH_OCCULT_USE_WAND_NPC: 'CommonBuffId' = 222845 - WITCH_OVERLOAD_DID_THEY_JUST_EXPLODE: 'CommonBuffId' = 222899 - WITCH_OVERLOAD_MAGICAL_OVERLOAD: 'CommonBuffId' = 216967 - WITCH_PERKS_CHARGE_CONTROL: 'CommonBuffId' = 217120 - WITCH_PERKS_DISCHARGE: 'CommonBuffId' = 218296 - WITCH_PERKS_EXTRA_CHEMISTRY_TASTY: 'CommonBuffId' = 217234 - WITCH_PERKS_HIDDEN_KNOWLEDGE_IS_MAGIC: 'CommonBuffId' = 218017 - WITCH_PERKS_MAGICAL_RESONANCE: 'CommonBuffId' = 219095 - WITCH_PERKS_MAGICAL_RESONANCE_APPLY_FX_ACTIVE: 'CommonBuffId' = 219109 - WITCH_PERKS_MAGICAL_RESONANCE_APPLY_FX_PASSIVE: 'CommonBuffId' = 219102 - WITCH_PERKS_POTENT_POTABLES: 'CommonBuffId' = 217928 - WITCH_PERKS_SOCIALITE: 'CommonBuffId' = 219681 - WITNESSED_DEATH_FRIEND: 'CommonBuffId' = 12757 - WITNESSED_DEATH_FRIEND_DOG: 'CommonBuffId' = 174973 - WITNESSED_DEATH_LOVED_ONE: 'CommonBuffId' = 12758 - WITNESSED_DEATH_NEMESIS: 'CommonBuffId' = 12759 - WITNESSED_DEATH_NEUTRAL: 'CommonBuffId' = 12760 - WITNESSED_HORSE_DEATH_FRIEND: 'CommonBuffId' = 352683 - WITNESSED_HORSE_DEATH_NEUTRAL: 'CommonBuffId' = 352682 - WITNESSED_PET_DEATH_FRIEND: 'CommonBuffId' = 175450 - WITNESSED_PET_DEATH_NEUTRAL: 'CommonBuffId' = 175451 - WITNESSED_RESCUED_NEGLECTED_CHILD: 'CommonBuffId' = 132511 - WITNESSED_RESCUED_NEGLECTED_HORSE: 'CommonBuffId' = 328099 - WITNESSED_RESCUED_PET: 'CommonBuffId' = 165472 - WITNESSED_SOLD_ADOPTED_PET: 'CommonBuffId' = 169860 - WOLF_TOWN_ADVENTURE_COOLDOWN_A_SCULPTURE_SECRET: 'CommonBuffId' = 288723 - WOLF_TOWN_ADVENTURE_COOLDOWN_B_OPEN_REWARD: 'CommonBuffId' = 288724 - WOLF_TOWN_ADVENTURE_EXIT_MINE: 'CommonBuffId' = 288575 - WOLF_TOWN_ADVENTURE_EXIT_ON_LOT: 'CommonBuffId' = 292620 - WOLF_TOWN_ADVENTURE_EXIT_PORTA: 'CommonBuffId' = 288580 - WOLF_TOWN_ADVENTURE_EXIT_SEWER: 'CommonBuffId' = 288581 - WOLF_TOWN_ADVENTURE_HAS_EXPLORED_FOR_AWHILE: 'CommonBuffId' = 288839 - WOLF_TOWN_ADVENTURE_NEXT_MOMENT_AREA_A: 'CommonBuffId' = 288638 - WOLF_TOWN_ADVENTURE_NEXT_MOMENT_AREA_B: 'CommonBuffId' = 288639 - WOLF_TOWN_ADVENTURE_NEXT_MOMENT_AREA_C: 'CommonBuffId' = 288640 - WOLF_TOWN_ADVENTURE_NEXT_MOMENT_SPLIT_A: 'CommonBuffId' = 288641 - WOLF_TOWN_ADVENTURE_NEXT_MOMENT_SPLIT_B: 'CommonBuffId' = 288643 - WOLF_TOWN_ADVENTURE_NEXT_MOMENT_SPLIT_C: 'CommonBuffId' = 288642 - WOLF_TOWN_ADVENTURE_PREVIOUS_MOMENT_AREA_A: 'CommonBuffId' = 288602 - WOLF_TOWN_ADVENTURE_PREVIOUS_MOMENT_AREA_B: 'CommonBuffId' = 288603 - WOLF_TOWN_ADVENTURE_PREVIOUS_MOMENT_AREA_C: 'CommonBuffId' = 288604 - WOLF_TOWN_ADVENTURE_PREVIOUS_MOMENT_SPLIT_A: 'CommonBuffId' = 288605 - WOLF_TOWN_ADVENTURE_PREVIOUS_MOMENT_SPLIT_B: 'CommonBuffId' = 288606 - WOLF_TOWN_ADVENTURE_PREVIOUS_MOMENT_SPLIT_C: 'CommonBuffId' = 288607 - WOLF_TOWN_DEBUG_BEAT_GREG: 'CommonBuffId' = 294238 - WOLF_TOWN_GREGS_GIFT: 'CommonBuffId' = 290243 - WOLF_TOWN_GREGS_GIFT_FROM_ASKING: 'CommonBuffId' = 290245 - WOLF_TOWN_GREGS_GIFT_MOTIVE_CHANGE: 'CommonBuffId' = 294848 - WOLF_TOWN_GREG_COMMUNICATION_DEFAULT: 'CommonBuffId' = 290130 - WOLF_TOWN_GREG_COMMUNICATION_MORE: 'CommonBuffId' = 290131 - WOLF_TOWN_GREG_DANGEROUS_SCENT: 'CommonBuffId' = 290120 - WOLF_TOWN_GREG_SOMETHINGS_WATCHING: 'CommonBuffId' = 290121 - WOLF_TOWN_GREG_SOMETHINGS_WATCHING_PARANOID: 'CommonBuffId' = 290123 - WOLF_TOWN_HOWL_SPOT_NIGHT: 'CommonBuffId' = 297835 - WOLF_TOWN_IN_REGION: 'CommonBuffId' = 287121 - WOLF_TOWN_LAKE_LUNVIK: 'CommonBuffId' = 291242 - WOLF_TOWN_NPC_CREATE_OBJECT_COOLDOWN: 'CommonBuffId' = 291325 - WOLF_TOWN_NPC_GREG: 'CommonBuffId' = 290061 - WOLF_TOWN_NPC_GREG_AUTO_HOWL_COOLDOWN: 'CommonBuffId' = 294572 - WOLF_TOWN_NPC_GREG_CONFUSED: 'CommonBuffId' = 294746 - WOLF_TOWN_NPC_GREG_FROG_COOLDOWN: 'CommonBuffId' = 300217 - WOLF_TOWN_NPC_GREG_NAP_COOLDOWN: 'CommonBuffId' = 296212 - WOLF_TOWN_NPC_GREG_NAP_COOLDOWN_SHORT: 'CommonBuffId' = 298568 - WOLF_TOWN_NPC_GREG_WANT_TO_LEAVE: 'CommonBuffId' = 294748 - WOLF_TOWN_PORTAL_ALLOWANCE_FLAG_ON_LOT: 'CommonBuffId' = 296885 - WOLF_TOWN_PORTAL_ALLOWANCE_FLAG_PORTAL_MINE: 'CommonBuffId' = 288344 - WOLF_TOWN_PORTAL_ALLOWANCE_FLAG_PORTAL_MINE_TEMP: 'CommonBuffId' = 301018 - WOLF_TOWN_PORTAL_ALLOWANCE_FLAG_PORTAL_SEWER: 'CommonBuffId' = 288345 - WOLF_TOWN_PORTAL_ALLOWANCE_FLAG_PORTAL_SEWER_MINE: 'CommonBuffId' = 288346 - WOLF_TOWN_PORTAL_ALLOWANCE_FLAG_PORTAL_SEWER_MINE_TEMP: 'CommonBuffId' = 301020 - WOLF_TOWN_PORTAL_ALLOWANCE_FLAG_PORTAL_SEWER_TEMP: 'CommonBuffId' = 301019 - WOLF_TOWN_PORTAL_BASIC_TELEPORT_FIRST_TIME: 'CommonBuffId' = 291547 - WOLF_TOWN_ROLE_BAR_WEREWOLF_ONLY: 'CommonBuffId' = 299741 - WOLF_TOWN_ROLE_FRIEND_SPAR: 'CommonBuffId' = 295337 - WOLF_TOWN_ROLE_GREG_IN_TOWN: 'CommonBuffId' = 290139 - WOLF_TOWN_ROLE_WANDER: 'CommonBuffId' = 292072 - WOLF_TOWN_ROLE_WEREWOLF_PACK_HANG_OUT_ACTIVE: 'CommonBuffId' = 290581 - WOLF_TOWN_ROLE_WEREWOLF_PACK_HANG_OUT_CHILL: 'CommonBuffId' = 290569 - WOLF_TOWN_ROLE_WEREWOLF_PACK_HANG_OUT_FOOD: 'CommonBuffId' = 290576 - WOLF_TOWN_ROLE_WEREWOLF_PACK_HANG_OUT_GARDEN: 'CommonBuffId' = 299591 - WOLF_TOWN_ROLE_WEREWOLF_PACK_HANG_OUT_SHELL_A: 'CommonBuffId' = 290562 - WOLF_TOWN_ROLE_WEREWOLF_PACK_HANG_OUT_SHELL_B: 'CommonBuffId' = 290563 - WOLF_TOWN_SIM_BEAT_GREG_HIDDEN: 'CommonBuffId' = 294237 - WOLF_TOWN_WOLF_EYES_EVERYWHERE: 'CommonBuffId' = 291282 - WOLF_TOWN_WOLF_EYES_EVERYWHERE_COOLDOWN: 'CommonBuffId' = 291287 - WON_FIGHT: 'CommonBuffId' = 12763 - WON_FIGHT_BEAR: 'CommonBuffId' = 108104 - WON_FIGHT_MEAN: 'CommonBuffId' = 36147 - WON_FIGHT_SUPER_NATURAL_SUPERIORITY: 'CommonBuffId' = 287975 - WON_FIGHT_VILLAIN: 'CommonBuffId' = 99533 - WOOHOO_AUTONOMY_COOLDOWN: 'CommonBuffId' = 132485 - WOOHOO_FIRST_TIME: 'CommonBuffId' = 99544 - WOOHOO_HAPPY_HOT_SPRINGS_COMPLETELY: 'CommonBuffId' = 248753 - WOOHOO_HAPPY_HOT_SPRINGS_PLEASANTLY: 'CommonBuffId' = 248752 - WOOHOO_HAPPY_LIVESTOCK_PEN_COMPLETELY: 'CommonBuffId' = 263125 - WOOHOO_HAPPY_LIVESTOCK_PEN_COMPLETELY_SLOB: 'CommonBuffId' = 263133 - WOOHOO_HAPPY_LIVESTOCK_PEN_PLEASANTLY: 'CommonBuffId' = 263126 - WOOHOO_HAPPY_ROMANTIC_BLANKET: 'CommonBuffId' = 366918 - WOOHOO_PLEASANTLY_SATISFIED_TEEN: 'CommonBuffId' = 97166 - WOOHOO_SEEING_STARS_TEEN: 'CommonBuffId' = 97181 - WOOHOO_SLEEPING_POD: 'CommonBuffId' = 200578 - WOOHOO_SLEEPING_POD_TEEN: 'CommonBuffId' = 200579 - WOOHOO_WITH_GHOST: 'CommonBuffId' = 102773 - WORKOUT_ENTHUSIASM: 'CommonBuffId' = 26365 - WORKOUT_VIDEOS_COMPLETED_POSE_1: 'CommonBuffId' = 166904 - WORKOUT_VIDEOS_COMPLETED_POSE_2: 'CommonBuffId' = 166905 - WORKOUT_VIDEOS_COMPLETED_POSE_3: 'CommonBuffId' = 166906 - WORKOUT_VIDEOS_COMPLETED_POSE_4: 'CommonBuffId' = 166907 - WORKOUT_VIDEOS_COMPLETED_POSE_5: 'CommonBuffId' = 166910 - WORKOUT_VIDEOS_COMPLETED_POSE_6: 'CommonBuffId' = 166911 - WORKOUT_VIDEOS_COMPLETED_POSE_7: 'CommonBuffId' = 166912 - WORKOUT_VIDEOS_COMPLETED_POSE_8: 'CommonBuffId' = 166913 - WORK_RIVAL_ADD_BIT_DELAYED: 'CommonBuffId' = 335741 - WORK_RIVAL_COOLDOWN: 'CommonBuffId' = 308711 - WORK_RIVAL_DEBUG_INCREASE_CHANCE: 'CommonBuffId' = 333237 - WORK_RIVAL_GUILTY_SABOTEUR: 'CommonBuffId' = 309021 - WORK_RIVAL_SATISFIED_SABOTEUR: 'CommonBuffId' = 309022 - XP_BOOSTS_FRIENDSHIP_REL_GAIN: 'CommonBuffId' = 149979 - XP_BOOSTS_FRIENDSHIP_REL_GAIN_CHILD: 'CommonBuffId' = 156796 - XP_BOOSTS_JOB_PERFORMANCE: 'CommonBuffId' = 149681 - XP_BOOSTS_MOTIVE_DECAY_DECREASE: 'CommonBuffId' = 149985 - XP_BOOSTS_MOTIVE_DECREASE_HYGIENE_HUNGER: 'CommonBuffId' = 189808 - XP_BOOSTS_SATISFACTION_POINTS_GAIN: 'CommonBuffId' = 149983 - XP_BOOSTS_SKILL_BOOST: 'CommonBuffId' = 149980 - XP_BOOSTS_SKILL_BOOST_ARTS: 'CommonBuffId' = 189806 - XP_BOOSTS_SKILL_BOOST_GARDENING_CULINARY: 'CommonBuffId' = 189785 - ZONE_MODIFIERS_CELEBRITY_HOME_LOT_TRAIT_EMBARRASSED: 'CommonBuffId' = 199708 - ZONE_MODIFIERS_CELEBRITY_HOME_LOT_TRAIT_HAPPY: 'CommonBuffId' = 199707 - ZONE_MODIFIERS_CELEBRITY_HOME_LOT_TRAIT_INVITED: 'CommonBuffId' = 199715 - ZONE_MODIFIERS_GEOTHERMAL_EFFECTIVE_TEMPERATURE: 'CommonBuffId' = 231818 - ZONE_MODIFIERS_GEOTHERMAL_SWIMMING_HAPPY: 'CommonBuffId' = 231825 - ZONE_MODIFIERS_NATURAL_WELL_DRINK_WATER_HAPPY: 'CommonBuffId' = 231826 - ZONE_MODIFIERS_NATURAL_WELL_EFFECTIVE_TEMPERATURE: 'CommonBuffId' = 231822 - ZONE_MODIFIERS_TINY_HOME_IDLE: 'CommonBuffId' = 230506 - ZONE_MODIFIERS_TINY_HOME_TIER_1: 'CommonBuffId' = 230340 - ZONE_MODIFIERS_TINY_HOME_TIER_2: 'CommonBuffId' = 230341 - ZONE_MODIFIERS_TINY_HOME_TIER_3: 'CommonBuffId' = 230342 - ZONE_MODIFIERS_VOLCANIC_ACTIVITY_MAJOR: 'CommonBuffId' = 208364 - ZONE_MODIFIERS_VOLCANIC_ACTIVITY_MINOR: 'CommonBuffId' = 208362 - ZONE_MODS_PETS_BREEDING_GROUND_ENERGIZED: 'CommonBuffId' = 172937 - ZONE_MODS_PETS_BREEDING_GROUND_VFX_HIDDEN: 'CommonBuffId' = 172935 - ZONE_MODS_PETS_TRAINING_GROUND_VFX_HIDDEN: 'CommonBuffId' = 172967 - ZONE_MODS_STUDY_SPOT: 'CommonBuffId' = 225841 - ZONE_MODS_STUDY_SPOT_STUDYING_HIGH: 'CommonBuffId' = 229230 - ZONE_MODS_STUDY_SPOT_STUDYING_LOW: 'CommonBuffId' = 229229 - ZONE_MODS_TRAIT_GREAT_VIEW_AUTONOMOUS_COOLDOWN_HIDDEN: 'CommonBuffId' = 155944 - ZONE_MOD_APARTMENT_CON_HAUNTED_TENSE: 'CommonBuffId' = 145596 - ZONE_MOD_CELEBRITY_HANG_OUT_LOW_FAME: 'CommonBuffId' = 191748 - ZONE_MOD_PRO_CHEFS_KITCHEN_VISIBLE: 'CommonBuffId' = 141962 - ZONE_MOD_PRO_CON_PRICEY_VISIBLE: 'CommonBuffId' = 152357 - ZONE_MOD_PRO_HOME_STUDIO_VISIBLE: 'CommonBuffId' = 141964 - ZONE_MOD_TRAIT_CHEFS_KITCHEN_VFX_HIDDEN: 'CommonBuffId' = 151957 - ZONE_MOD_TRAIT_CHILDS_PLAY_PLAYFUL_ADULT: 'CommonBuffId' = 147683 - ZONE_MOD_TRAIT_CHILDS_PLAY_PLAYFUL_CHILD_VISIBLE: 'CommonBuffId' = 147686 - ZONE_MOD_TRAIT_CHILDS_PLAY_VFX_HIDDEN: 'CommonBuffId' = 151960 - ZONE_MOD_TRAIT_CURSED_HIDDEN: 'CommonBuffId' = 154593 - ZONE_MOD_TRAIT_HOME_STUDIO_HANDINESS_VFX_HIDDEN: 'CommonBuffId' = 152191 - ZONE_MOD_TRAIT_HOME_STUDIO_VFX_HIDDEN: 'CommonBuffId' = 151958 - ZONE_MOD_TRAIT_MEAN_VIBE_ANGRY: 'CommonBuffId' = 145688 - ZONE_MOD_TRAIT_ON_LEY_LINE_ENERGIZED: 'CommonBuffId' = 147689 - ZONE_MOD_TRAIT_ON_LEY_LINE_VFX_HIDDEN: 'CommonBuffId' = 154284 - ZONE_MOD_TRAIT_PENNY_PIXIES_HAPPY: 'CommonBuffId' = 145693 - ZONE_MOD_TRAIT_PENNY_PIXIES_VFX_HIDDEN: 'CommonBuffId' = 145694 - ZONE_MOD_TRAIT_QUAKE_ZONE_REACTION_DELAY_MAJOR_HIDDEN: 'CommonBuffId' = 153353 - ZONE_MOD_TRAIT_QUAKE_ZONE_REACTION_DELAY_MINOR_HIDDEN: 'CommonBuffId' = 153092 - ZONE_MOD_TRAIT_QUAKE_ZONE_SCARED_ACTIVE_PET_CAT: 'CommonBuffId' = 176922 - ZONE_MOD_TRAIT_QUAKE_ZONE_SCARED_ACTIVE_PET_DOG: 'CommonBuffId' = 176919 - ZONE_MOD_TRAIT_QUAKE_ZONE_TENSE_ACTIVE: 'CommonBuffId' = 148228 - ZONE_MOD_TRAIT_QUAKE_ZONE_TENSE_PASSIVE: 'CommonBuffId' = 147685 - ZONE_MOD_TRAIT_ROMANTIC_ATMOSPHERE_CONFIDENT: 'CommonBuffId' = 145710 - ZONE_MOD_TRAIT_ROMANTIC_ATMOSPHERE_FLIRTY: 'CommonBuffId' = 145711 - ZONE_MOD_TRAIT_SUNNY_ASPECT_ENERGIZED: 'CommonBuffId' = 145551 - ZONE_MOD_TRAIT_SUNNY_ASPECT_HAPPY: 'CommonBuffId' = 153172 - ZONE_MOD_TRAIT_SUNNY_ASPECT_INSPIRED: 'CommonBuffId' = 153171 diff --git a/Scripts/s4ap/sims4communitylib/enums/clubs_enum.py b/Scripts/s4ap/sims4communitylib/enums/clubs_enum.py deleted file mode 100644 index 1073e3e..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/clubs_enum.py +++ /dev/null @@ -1,108 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonClubInteractionGroupId(CommonInt): - """Identifiers for vanilla club activities. - - """ - INVALID: 'CommonClubInteractionGroupId' = 0 - FOOD_AND_DRINK_GRILLED_CHEESE: 'CommonClubInteractionGroupId' = 132512 - FUN_AND_GAMES_BASKETBALL: 'CommonClubInteractionGroupId' = 151720 - FUN_AND_GAMES_SLIPPY_SLIDE: 'CommonClubInteractionGroupId' = 140842 - HOBBIES_BATTLE_MONSTERS: 'CommonClubInteractionGroupId' = 134452 - HOBBIES_PUPPET_PERFORMANCE: 'CommonClubInteractionGroupId' = 134451 - KLEPTO_SWIPE_OBJECTS: 'CommonClubInteractionGroupId' = 132513 - OBJECT_BASED_HOT_TUB_SP02: 'CommonClubInteractionGroupId' = 130264 - OBJECT_BASED_BONFIRE: 'CommonClubInteractionGroupId' = 123557 - OBJECT_BASED_BROWSE_WEB: 'CommonClubInteractionGroupId' = 129741 - OBJECT_BASED_BUBBLE_BLOWER: 'CommonClubInteractionGroupId' = 180935 - OBJECT_BASED_CLEAN: 'CommonClubInteractionGroupId' = 122483 - OBJECT_BASED_DANCE: 'CommonClubInteractionGroupId' = 122479 - OBJECT_BASED_DO_HOMEWORK: 'CommonClubInteractionGroupId' = 127699 - OBJECT_BASED_DRINK_BAR_DRINKS: 'CommonClubInteractionGroupId' = 122484 - OBJECT_BASED_DRINK_ESPRESSO: 'CommonClubInteractionGroupId' = 127694 - OBJECT_BASED_EAT: 'CommonClubInteractionGroupId' = 122480 - OBJECT_BASED_EXCAVATE: 'CommonClubInteractionGroupId' = 182934 - OBJECT_BASED_GATHER_FROGS: 'CommonClubInteractionGroupId' = 129789 - OBJECT_BASED_GRILL: 'CommonClubInteractionGroupId' = 122477 - OBJECT_BASED_LISTEN_TO_MUSIC: 'CommonClubInteractionGroupId' = 122469 - OBJECT_BASED_MAZE_WANDER: 'CommonClubInteractionGroupId' = 128518 - OBJECT_BASED_MEDITATE: 'CommonClubInteractionGroupId' = 129744 - OBJECT_BASED_MOVIES: 'CommonClubInteractionGroupId' = 129625 - OBJECT_BASED_PLAY_ARCADE_MACHINE: 'CommonClubInteractionGroupId' = 128638 - OBJECT_BASED_PLAY_BOWLING: 'CommonClubInteractionGroupId' = 161275 - OBJECT_BASED_PLAY_CARDS: 'CommonClubInteractionGroupId' = 122470 - OBJECT_BASED_PLAY_DARTS: 'CommonClubInteractionGroupId' = 128331 - OBJECT_BASED_PLAY_DONT_WAKE_THE_LLAMA: 'CommonClubInteractionGroupId' = 128334 - OBJECT_BASED_PLAY_FOOSBALL: 'CommonClubInteractionGroupId' = 128328 - OBJECT_BASED_PLAY_HORSESHOES: 'CommonClubInteractionGroupId' = 128631 - OBJECT_BASED_PLAY_IN_CLOSET: 'CommonClubInteractionGroupId' = 127750 - OBJECT_BASED_PLAY_ON_PLAY_GROUND: 'CommonClubInteractionGroupId' = 122471 - OBJECT_BASED_PLAY_PHYSICAL_GAMES: 'CommonClubInteractionGroupId' = 128505 - OBJECT_BASED_PLAY_PUB_GAMES: 'CommonClubInteractionGroupId' = 128541 - OBJECT_BASED_PLAY_WITH_TOYS: 'CommonClubInteractionGroupId' = 122473 - OBJECT_BASED_POPCORN: 'CommonClubInteractionGroupId' = 179311 - OBJECT_BASED_POSSESS: 'CommonClubInteractionGroupId' = 128422 - OBJECT_BASED_READ: 'CommonClubInteractionGroupId' = 122482 - OBJECT_BASED_SABOTAGE: 'CommonClubInteractionGroupId' = 128499 - OBJECT_BASED_SHOWER_AND_BATHE: 'CommonClubInteractionGroupId' = 122481 - OBJECT_BASED_SLEEP: 'CommonClubInteractionGroupId' = 122478 - OBJECT_BASED_SWIM: 'CommonClubInteractionGroupId' = 122476 - OBJECT_BASED_TRY_ON_OUTFITS: 'CommonClubInteractionGroupId' = 128542 - OBJECT_BASED_USE_JUMP_STAND: 'CommonClubInteractionGroupId' = 129742 - OBJECT_BASED_USE_SCIENCE_OBJECTS: 'CommonClubInteractionGroupId' = 126323 - OBJECT_BASED_VIE_WART: 'CommonClubInteractionGroupId' = 122472 - OBJECT_BASED_WATCH_LIVE_ENTERTAINMENT: 'CommonClubInteractionGroupId' = 129105 - OBJECT_BASED_WATCH_TV: 'CommonClubInteractionGroupId' = 122468 - OBJECT_BASED_YOGA: 'CommonClubInteractionGroupId' = 129745 - OTHER_USE_ALIEN_POWERS: 'CommonClubInteractionGroupId' = 126319 - OUTDOOR_PLAY_IN_FOUNTAIN: 'CommonClubInteractionGroupId' = 132964 - ROAR: 'CommonClubInteractionGroupId' = 128338 - SKILL_BUILDING_BAKING: 'CommonClubInteractionGroupId' = 126320 - SKILL_BUILDING_COOK: 'CommonClubInteractionGroupId' = 122443 - SKILL_BUILDING_DJ: 'CommonClubInteractionGroupId' = 122547 - SKILL_BUILDING_DO_COMEDY: 'CommonClubInteractionGroupId' = 122434 - SKILL_BUILDING_FISH: 'CommonClubInteractionGroupId' = 122444 - SKILL_BUILDING_FITNESS_WORKOUT: 'CommonClubInteractionGroupId' = 121923 - SKILL_BUILDING_FIX_OBJECTS: 'CommonClubInteractionGroupId' = 122450 - SKILL_BUILDING_GARDEN: 'CommonClubInteractionGroupId' = 122445 - SKILL_BUILDING_HACK: 'CommonClubInteractionGroupId' = 122437 - SKILL_BUILDING_MIX_BAR_DRINKS: 'CommonClubInteractionGroupId' = 122436 - SKILL_BUILDING_PAINT: 'CommonClubInteractionGroupId' = 122433 - SKILL_BUILDING_PLAY_AN_INSTRUMENT: 'CommonClubInteractionGroupId' = 122446 - SKILL_BUILDING_PLAY_CHESS: 'CommonClubInteractionGroupId' = 121700 - SKILL_BUILDING_PLAY_GUITAR: 'CommonClubInteractionGroupId' = 122447 - SKILL_BUILDING_PLAY_PIANO: 'CommonClubInteractionGroupId' = 122448 - SKILL_BUILDING_PLAY_PIPE_ORGAN: 'CommonClubInteractionGroupId' = 152374 - SKILL_BUILDING_PLAY_VIDEO_GAMES: 'CommonClubInteractionGroupId' = 122439 - SKILL_BUILDING_PLAY_VIOLIN: 'CommonClubInteractionGroupId' = 122449 - SKILL_BUILDING_PROGRAM: 'CommonClubInteractionGroupId' = 122438 - SKILL_BUILDING_ROCKET_SCIENCE_ACTIONS: 'CommonClubInteractionGroupId' = 121552 - SKILL_BUILDING_SINGING: 'CommonClubInteractionGroupId' = 149981 - SKILL_BUILDING_USE_MICROSCOPE: 'CommonClubInteractionGroupId' = 122452 - SKILL_BUILDING_USE_SCIENCE_TABLE: 'CommonClubInteractionGroupId' = 127751 - SKILL_BUILDING_USE_TELESCOPE: 'CommonClubInteractionGroupId' = 122435 - SKILL_BUILDING_WELLNESS: 'CommonClubInteractionGroupId' = 126340 - SKILL_BUILDING_WOODWORK: 'CommonClubInteractionGroupId' = 122441 - SKILL_BUILDING_WRITE: 'CommonClubInteractionGroupId' = 122440 - SOCIAL_BE_FRIENDLY: 'CommonClubInteractionGroupId' = 122422 - SOCIAL_BE_FUNNY: 'CommonClubInteractionGroupId' = 122426 - SOCIAL_BE_MEAN: 'CommonClubInteractionGroupId' = 121698 - SOCIAL_BE_MISCHIEVOUS: 'CommonClubInteractionGroupId' = 122429 - SOCIAL_BE_ROMANTIC: 'CommonClubInteractionGroupId' = 122431 - SOCIAL_FIGHT: 'CommonClubInteractionGroupId' = 122428 - SOCIAL_GIVE_SPEECHES: 'CommonClubInteractionGroupId' = 151396 - SOCIAL_HUG: 'CommonClubInteractionGroupId' = 122421 - SOCIAL_KISS: 'CommonClubInteractionGroupId' = 122424 - SOCIAL_SCARE: 'CommonClubInteractionGroupId' = 122430 - SOCIAL_TELL_JOKES: 'CommonClubInteractionGroupId' = 122427 - SOCIAL_WOOHOO: 'CommonClubInteractionGroupId' = 121679 - VAMPIRE_DRINK_PLASMA: 'CommonClubInteractionGroupId' = 154430 - VAMPIRE_USE_POWERS: 'CommonClubInteractionGroupId' = 154429 diff --git a/Scripts/s4ap/sims4communitylib/enums/common_age.py b/Scripts/s4ap/sims4communitylib/enums/common_age.py deleted file mode 100644 index b54cdfc..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_age.py +++ /dev/null @@ -1,184 +0,0 @@ -""" -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 -""" -from typing import Dict, Union, Tuple, Iterator - -from sims.sim_info import SimInfo -from sims.sim_info_types import Age -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonAge(CommonInt): - """Custom Age enum containing all ages, because there have been too many problems when referencing the vanilla Age in various places. - - """ - INVALID: 'CommonAge' = 0 - BABY: 'CommonAge' = 1 - INFANT: 'CommonAge' = 2 - TODDLER: 'CommonAge' = 4 - CHILD: 'CommonAge' = 8 - TEEN: 'CommonAge' = 16 - YOUNGADULT: 'CommonAge' = 32 - ADULT: 'CommonAge' = 64 - ELDER: 'CommonAge' = 128 - - @classmethod - def get_all(cls, exclude_values: Iterator['CommonAge'] = None) -> Tuple['CommonAge']: - """get_all(exclude_values=None) - - Get a collection of all values. - - :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonAge], optional - :return: A collection of all values. - :rtype: Tuple[CommonAge] - """ - if exclude_values is None: - exclude_values = (cls.INVALID,) - # noinspection PyTypeChecker - value_list: Tuple[CommonAge, ...] = tuple([value for value in cls.values if value not in exclude_values]) - return value_list - - @classmethod - def get_all_names(cls, exclude_values: Iterator['CommonAge'] = None) -> Tuple[str]: - """get_all_names(exclude_values=None) - - Retrieve a collection of the names of all values. - - :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonAge], optional - :return: A collection of the names of all values. - :rtype: Tuple[str] - """ - name_list: Tuple[str] = tuple([value.name for value in cls.get_all(exclude_values=exclude_values)]) - return name_list - - @classmethod - def get_comma_separated_names_string(cls, exclude_values: Iterator['CommonAge'] = None) -> str: - """get_comma_separated_names_string(exclude_values=None) - - Create a string containing all names of all values, separated by a comma. - - :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonAge], optional - :return: A string containing all names of all values, separated by a comma. - :rtype: str - """ - return ', '.join(cls.get_all_names(exclude_values=exclude_values)) - - @staticmethod - def get_age(sim_info: SimInfo) -> 'CommonAge': - """get_age(sim_info) - - Retrieve the CommonAge of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The CommonAge that represents what age a Sim is or INVALID if their age cannot be determined. - :rtype: CommonAge - """ - from s4ap.sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils - if CommonAgeUtils.is_baby(sim_info): - return CommonAge.BABY - elif CommonAgeUtils.is_infant(sim_info): - return CommonAge.INFANT - elif CommonAgeUtils.is_toddler(sim_info): - return CommonAge.TODDLER - elif CommonAgeUtils.is_child(sim_info): - return CommonAge.CHILD - elif CommonAgeUtils.is_teen(sim_info): - return CommonAge.TEEN - elif CommonAgeUtils.is_young_adult(sim_info): - return CommonAge.YOUNGADULT - elif CommonAgeUtils.is_adult(sim_info): - return CommonAge.ADULT - elif CommonAgeUtils.is_elder(sim_info): - return CommonAge.ELDER - return CommonAge.INVALID - - @staticmethod - def convert_to_vanilla(value: 'CommonAge') -> Union[Age, None]: - """convert_to_vanilla(value) - - Convert a CommonAge into the vanilla Age enum. - - :param value: An instance of CommonAge - :type value: CommonAge - :return: The specified CommonAge translated to Age or None if the value could not be translated. - :rtype: Union[Age, None] - """ - if value is None or value == CommonAge.INVALID: - return None - if isinstance(value, Age): - return value - age_conversion_mapping: Dict[CommonAge, Age] = { - CommonAge.BABY: Age.BABY, - CommonAge.INFANT: Age.INFANT, - CommonAge.TODDLER: Age.TODDLER, - CommonAge.CHILD: Age.CHILD, - CommonAge.TEEN: Age.TEEN, - CommonAge.YOUNGADULT: Age.YOUNGADULT, - CommonAge.ADULT: Age.ADULT, - CommonAge.ELDER: Age.ELDER - } - return age_conversion_mapping.get(value, None) - - @staticmethod - def convert_from_vanilla(value: Union[int, Age]) -> 'CommonAge': - """convert_from_vanilla(value) - - Convert a vanilla Age to a CommonAge. - - :param value: An instance of Age - :type value: Age - :return: The specified Age translated to CommonAge or INVALID if the value could not be translated. - :rtype: CommonAge - """ - if value is None: - return CommonAge.INVALID - if isinstance(value, CommonAge): - return value - age_conversion_mapping: Dict[int, CommonAge] = { - int(Age.BABY): CommonAge.BABY, - int(Age.INFANT): CommonAge.INFANT, - int(Age.TODDLER): CommonAge.TODDLER, - int(Age.CHILD): CommonAge.CHILD, - int(Age.TEEN): CommonAge.TEEN, - int(Age.YOUNGADULT): CommonAge.YOUNGADULT, - int(Age.ADULT): CommonAge.ADULT, - int(Age.ELDER): CommonAge.ELDER - } - value = int(value) - if value not in age_conversion_mapping: - return CommonAge.INVALID - return age_conversion_mapping[value] - - @staticmethod - def convert_to_localized_string_id(value: Union[int, 'CommonAge']) -> Union[int, str]: - """convert_to_localized_string_id(value) - - Convert a CommonAge into a Localized String identifier. - - :param value: An instance of a CommonAge - :type value: CommonAge - :return: The specified CommonAge translated to a localized string identifier. If no localized string id is found, the name property of the value will be used instead. - :rtype: Union[int, str] - """ - from s4ap.sims4communitylib.enums.strings_enum import CommonStringId - display_name_mapping = { - CommonAge.BABY: CommonStringId.BABY, - CommonAge.INFANT: CommonStringId.INFANT, - CommonAge.TODDLER: CommonStringId.TODDLER, - CommonAge.CHILD: CommonStringId.CHILD, - CommonAge.TEEN: CommonStringId.TEEN, - CommonAge.YOUNGADULT: CommonStringId.YOUNG_ADULT, - CommonAge.ADULT: CommonStringId.ADULT, - CommonAge.ELDER: CommonStringId.ELDER - } - if isinstance(value, int) and not isinstance(value, CommonAge): - value = CommonAge.convert_from_vanilla(value) - return display_name_mapping.get(value, value.name if hasattr(value, 'name') else str(value)) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_appearance_modifier_priority.py b/Scripts/s4ap/sims4communitylib/enums/common_appearance_modifier_priority.py deleted file mode 100644 index 635c854..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_appearance_modifier_priority.py +++ /dev/null @@ -1,121 +0,0 @@ -""" -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 -""" -from typing import Union, Iterator, Tuple - -from buffs.appearance_modifier.appearance_modifier import AppearanceModifierPriority -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonAppearanceModifierPriority(CommonInt): - """Priorities for appearance modifiers. These priorities determine the order in which appearance modifiers are applied, which ones override which.""" - INVALID: 'CommonAppearanceModifierPriority' = ... - FROZEN: 'CommonAppearanceModifierPriority' = ... - MANNEQUIN: 'CommonAppearanceModifierPriority' = ... - PATIENT: 'CommonAppearanceModifierPriority' = ... - SICKNESS: 'CommonAppearanceModifierPriority' = ... - TRANSFORMED: 'CommonAppearanceModifierPriority' = ... - - @classmethod - def get_all(cls, exclude_values: Iterator['CommonAppearanceModifierPriority'] = None) -> Tuple['CommonAppearanceModifierPriority']: - """get_all(exclude_values=None) - - Get a collection of all values. - - :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonAppearanceModifierPriority], optional - :return: A collection of all values. - :rtype: Tuple[CommonAppearanceModifierPriority] - """ - if exclude_values is None: - exclude_values = (cls.INVALID,) - # noinspection PyTypeChecker - value_list: Tuple[CommonAppearanceModifierPriority, ...] = tuple([value for value in cls.values if value not in exclude_values]) - return value_list - - @classmethod - def get_all_names(cls, exclude_values: Iterator['CommonAppearanceModifierPriority'] = None) -> Tuple[str]: - """get_all_names(exclude_values=None) - - Retrieve a collection of the names of all values. - - :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonAppearanceModifierPriority], optional - :return: A collection of the names of all values. - :rtype: Tuple[str] - """ - name_list: Tuple[str] = tuple([value.name for value in cls.get_all(exclude_values=exclude_values)]) - return name_list - - @classmethod - def get_comma_separated_names_string(cls, exclude_values: Iterator['CommonAppearanceModifierPriority'] = None) -> str: - """get_comma_separated_names_string(exclude_values=None) - - Create a string containing all names of all values, separated by a comma. - - :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonAppearanceModifierPriority], optional - :return: A string containing all names of all values, separated by a comma. - :rtype: str - """ - return ', '.join(cls.get_all_names(exclude_values=exclude_values)) - - @staticmethod - def convert_to_vanilla(value: 'CommonAppearanceModifierPriority') -> AppearanceModifierPriority: - """convert_to_vanilla(value) - - Convert a value into the vanilla AppearanceModifierPriority enum. - - :param value: An instance of CommonAppearanceModifierPriority - :type value: CommonAppearanceModifierPriority - :return: The specified value translated to AppearanceModifierPriority or INVALID if the value could not be translated. - :rtype: AppearanceModifierPriority - """ - if value is None or value == CommonAppearanceModifierPriority.INVALID: - return AppearanceModifierPriority.INVALID - if isinstance(value, AppearanceModifierPriority): - return value - mapping = dict() - if hasattr(AppearanceModifierPriority, 'MANNEQUIN'): - mapping[CommonAppearanceModifierPriority.MANNEQUIN] = AppearanceModifierPriority.MANNEQUIN - if hasattr(AppearanceModifierPriority, 'SICKNESS'): - mapping[CommonAppearanceModifierPriority.SICKNESS] = AppearanceModifierPriority.SICKNESS - if hasattr(AppearanceModifierPriority, 'PATIENT'): - mapping[CommonAppearanceModifierPriority.PATIENT] = AppearanceModifierPriority.PATIENT - if hasattr(AppearanceModifierPriority, 'TRANSFORMED'): - mapping[CommonAppearanceModifierPriority.TRANSFORMED] = AppearanceModifierPriority.TRANSFORMED - if hasattr(AppearanceModifierPriority, 'FROZEN'): - mapping[CommonAppearanceModifierPriority.FROZEN] = AppearanceModifierPriority.FROZEN - return mapping.get(value, AppearanceModifierPriority.INVALID) - - @staticmethod - def convert_from_vanilla(value: Union[int, AppearanceModifierPriority]) -> 'CommonAppearanceModifierPriority': - """convert_from_vanilla(value) - - Convert a value into a CommonAppearanceModifierPriority enum. - - :param value: An instance of AppearanceModifierPriority - :type value: AppearanceModifierPriority - :return: The specified value translated to CommonAppearanceModifierPriority or INVALID if the value could not be translated. - :rtype: CommonAppearanceModifierPriority - """ - if value is None or value == AppearanceModifierPriority.INVALID: - return CommonAppearanceModifierPriority.INVALID - if isinstance(value, CommonAppearanceModifierPriority): - return value - mapping = dict() - if hasattr(AppearanceModifierPriority, 'MANNEQUIN'): - mapping[AppearanceModifierPriority.MANNEQUIN] = CommonAppearanceModifierPriority.MANNEQUIN - if hasattr(AppearanceModifierPriority, 'SICKNESS'): - mapping[AppearanceModifierPriority.SICKNESS] = CommonAppearanceModifierPriority.SICKNESS - if hasattr(AppearanceModifierPriority, 'PATIENT'): - mapping[AppearanceModifierPriority.PATIENT] = CommonAppearanceModifierPriority.PATIENT - if hasattr(AppearanceModifierPriority, 'TRANSFORMED'): - mapping[AppearanceModifierPriority.TRANSFORMED] = CommonAppearanceModifierPriority.TRANSFORMED - if hasattr(AppearanceModifierPriority, 'FROZEN'): - mapping[AppearanceModifierPriority.FROZEN] = CommonAppearanceModifierPriority.FROZEN - return mapping.get(value, CommonAppearanceModifierPriority.INVALID) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_appearance_modifier_type.py b/Scripts/s4ap/sims4communitylib/enums/common_appearance_modifier_type.py deleted file mode 100644 index f42f145..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_appearance_modifier_type.py +++ /dev/null @@ -1,18 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonAppearanceModifierType(CommonInt): - """Types for appearance modifiers.""" - SET_CAS_PART: 'CommonAppearanceModifierType' = 0 - RANDOMIZE_BODY_TYPE_COLOR: 'CommonAppearanceModifierType' = 1 - RANDOMIZE_SKIN_TONE_FROM_TAGS: 'CommonAppearanceModifierType' = 2 - GENERATE_OUTFIT: 'CommonAppearanceModifierType' = 3 - RANDOMIZE_CAS_PART: 'CommonAppearanceModifierType' = 4 - CUSTOM: 'CommonAppearanceModifierType' = 5000 diff --git a/Scripts/s4ap/sims4communitylib/enums/common_body_frame.py b/Scripts/s4ap/sims4communitylib/enums/common_body_frame.py deleted file mode 100644 index 3a2918f..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_body_frame.py +++ /dev/null @@ -1,78 +0,0 @@ -""" -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 -""" -from typing import Tuple, Iterator - -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt -from s4ap.sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils -from s4ap.sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils - - -class CommonBodyFrame(CommonInt): - """Custom Body Frames enum containing all body frames. - - """ - INVALID: 'CommonBodyFrame' = 0 - MASCULINE: 'CommonBodyFrame' = 1 - FEMININE: 'CommonBodyFrame' = 2 - - @classmethod - def get_all(cls, exclude_values: Iterator['CommonBodyFrame'] = None) -> Tuple['CommonBodyFrame']: - """get_all(exclude_values=None) - - Get a collection of all values. - - :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonBodyFrame], optional - :return: A collection of all values. - :rtype: Tuple[CommonBodyFrame] - """ - if exclude_values is None: - exclude_values = (cls.INVALID,) - # noinspection PyTypeChecker - value_list: Tuple[CommonBodyFrame] = tuple([value for value in cls.values if value not in exclude_values]) - return value_list - - @classmethod - def get_all_names(cls, exclude_values: Iterator['CommonBodyFrame'] = None) -> Tuple[str]: - """get_all_names(exclude_values=None) - - Retrieve a collection of the names of all values. - - :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonBodyFrame], optional - :return: A collection of the names of all values. - :rtype: Tuple[str] - """ - name_list: Tuple[str] = tuple([value.name for value in cls.get_all(exclude_values=exclude_values)]) - return name_list - - @staticmethod - def get_body_frame(sim_info: SimInfo) -> 'CommonBodyFrame': - """get_body_frame(sim_info) - - Retrieve the CommonBodyFrame of a sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The body frame of the Sim or INVALID if their current body frame cannot be determined. - :rtype: CommonBodyFrame - """ - from s4ap.sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils - if CommonSpeciesUtils.is_animal(sim_info): - if CommonGenderUtils.is_male(sim_info): - return CommonBodyFrame.MASCULINE - if CommonGenderUtils.is_female(sim_info): - return CommonBodyFrame.FEMININE - return CommonBodyFrame.INVALID - - if CommonSimGenderOptionUtils.has_masculine_frame(sim_info): - return CommonBodyFrame.MASCULINE - if CommonSimGenderOptionUtils.has_feminine_frame(sim_info): - return CommonBodyFrame.FEMININE - return CommonBodyFrame.INVALID diff --git a/Scripts/s4ap/sims4communitylib/enums/common_body_slot.py b/Scripts/s4ap/sims4communitylib/enums/common_body_slot.py deleted file mode 100644 index 2c77d75..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_body_slot.py +++ /dev/null @@ -1,728 +0,0 @@ -""" -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 -""" -from typing import Union, Iterator, Tuple - -from sims.outfits.outfit_enums import BodyType -from s4ap.sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags - - -class CommonBodySlot(CommonIntFlags): - """Slots on the body of Sims that CAS Parts can be attached to.""" - NONE: 'CommonBodySlot' = 0 - ACNE: 'CommonBodySlot' = 72 - ATTACHMENT_BACK: 'CommonBodySlot' = 88 - BIRTHMARK_ARMS: 'CommonBodySlot' = 94 - BIRTHMARK_FACE: 'CommonBodySlot' = 91 - BIRTHMARK_LEGS: 'CommonBodySlot' = 98 - BIRTHMARK_TORSO_BACK: 'CommonBodySlot' = 92 - BIRTHMARK_TORSO_FRONT: 'CommonBodySlot' = 93 - BITE: 'CommonBodySlot' = 76 - BLANKET: 'CommonBodySlot' = 104 - BLUSH: 'CommonBodySlot' = 32 - BODY_FRECKLES: 'CommonBodySlot' = 77 - BODY_HAIR_ARM: 'CommonBodySlot' = 78 - BODY_HAIR_LEG: 'CommonBodySlot' = 79 - BODY_HAIR_TORSO_BACK: 'CommonBodySlot' = 81 - BODY_HAIR_TORSO_FRONT: 'CommonBodySlot' = 80 - BODY_SCAR_ARM_LEFT: 'CommonBodySlot' = 82 - BODY_SCAR_ARM_RIGHT: 'CommonBodySlot' = 83 - BODY_SCAR_LEG_LEFT: 'CommonBodySlot' = 86 - BODY_SCAR_LEG_RIGHT: 'CommonBodySlot' = 87 - BODY_SCAR_TORSO_BACK: 'CommonBodySlot' = 85 - BODY_SCAR_TORSO_FRONT: 'CommonBodySlot' = 84 - BRIDLE: 'CommonBodySlot' = 102 - BROW_RING_LEFT: 'CommonBodySlot' = 20 - BROW_RING_RIGHT: 'CommonBodySlot' = 21 - CUMMERBUND: 'CommonBodySlot' = 9 - EARRINGS: 'CommonBodySlot' = 10 - EARS: 'CommonBodySlot' = 60 - EYE_COLOR: 'CommonBodySlot' = 35 - EYE_COLOR_SECONDARY: 'CommonBodySlot' = 63 - EYE_LINER: 'CommonBodySlot' = 31 - EYE_SHADOW: 'CommonBodySlot' = 30 - EYEBROWS: 'CommonBodySlot' = 34 - FACE_PAINT: 'CommonBodySlot' = 33 - FACE_SCAR: 'CommonBodySlot' = 90 - FACIAL_HAIR: 'CommonBodySlot' = 28 - FINGERNAIL: 'CommonBodySlot' = 73 - FOREARM_SCAR: 'CommonBodySlot' = 71 - FULL_BODY: 'CommonBodySlot' = 5 - FUR_BODY: 'CommonBodySlot' = 59 - GLASSES: 'CommonBodySlot' = 11 - GLOVES: 'CommonBodySlot' = 13 - HAIR: 'CommonBodySlot' = 2 - HAIR_COLOR_OVERRIDE: 'CommonBodySlot' = 75 - HAIR_FEATHERS: 'CommonBodySlot' = 109 - HAIR_FORELOCK: 'CommonBodySlot' = 108 - HAIR_MANE: 'CommonBodySlot' = 106 - HAIR_TAIL: 'CommonBodySlot' = 107 - HAT: 'CommonBodySlot' = 1 - HEAD: 'CommonBodySlot' = 3 - HORN: 'CommonBodySlot' = 110 - INDEX_FINGER_LEFT: 'CommonBodySlot' = 22 - INDEX_FINGER_RIGHT: 'CommonBodySlot' = 23 - LIP_RING_LEFT: 'CommonBodySlot' = 16 - LIP_RING_RIGHT: 'CommonBodySlot' = 17 - LIPSTICK: 'CommonBodySlot' = 29 - LOWER_BODY: 'CommonBodySlot' = 7 - EYELASHES: 'CommonBodySlot' = 37 - MIDDLE_FINGER_LEFT: 'CommonBodySlot' = 26 - MIDDLE_FINGER_RIGHT: 'CommonBodySlot' = 27 - MOLE_BACK_UPPER: 'CommonBodySlot' = 97 - MOLE_CHEST_UPPER: 'CommonBodySlot' = 96 - MOLE_FACE: 'CommonBodySlot' = 95 - NECKLACE: 'CommonBodySlot' = 12 - NOSE_RING_LEFT: 'CommonBodySlot' = 18 - NOSE_RING_RIGHT: 'CommonBodySlot' = 19 - OCCULT_BROW: 'CommonBodySlot' = 64 - OCCULT_EYE_SOCKET: 'CommonBodySlot' = 65 - OCCULT_EYELID: 'CommonBodySlot' = 66 - OCCULT_LEFT_CHEEK: 'CommonBodySlot' = 68 - OCCULT_MOUTH: 'CommonBodySlot' = 67 - OCCULT_NECK_SCAR: 'CommonBodySlot' = 70 - OCCULT_RIGHT_CHEEK: 'CommonBodySlot' = 69 - REINS: 'CommonBodySlot' = 103 - RING_FINGER_LEFT: 'CommonBodySlot' = 24 - RING_FINGER_RIGHT: 'CommonBodySlot' = 25 - SADDLE: 'CommonBodySlot' = 101 - SHOES: 'CommonBodySlot' = 8 - SKIN_DETAIL_ACNE_PUBERTY: 'CommonBodySlot' = 89 - SKIN_DETAIL_CREASE_FOREHEAD: 'CommonBodySlot' = 38 - SKIN_DETAIL_CREASE_MOUTH: 'CommonBodySlot' = 57 - SKIN_DETAIL_DIMPLE_LEFT: 'CommonBodySlot' = 40 - SKIN_DETAIL_DIMPLE_RIGHT: 'CommonBodySlot' = 41 - SKIN_DETAIL_FRECKLES: 'CommonBodySlot' = 39 - SKIN_DETAIL_HOOF_COLOR: 'CommonBodySlot' = 105 - SKIN_DETAIL_MOLE_CHEEK_LEFT: 'CommonBodySlot' = 55 - SKIN_DETAIL_MOLE_CHEEK_RIGHT: 'CommonBodySlot' = 56 - SKIN_DETAIL_MOLE_LIP_LEFT: 'CommonBodySlot' = 43 - SKIN_DETAIL_MOLE_LIP_RIGHT: 'CommonBodySlot' = 44 - SKIN_DETAIL_NOSE_COLOR: 'CommonBodySlot' = 62 - SKIN_OVERLAY: 'CommonBodySlot' = 58 - SOCKS: 'CommonBodySlot' = 36 - STRETCH_MARKS_BACK: 'CommonBodySlot' = 100 - STRETCH_MARKS_FRONT: 'CommonBodySlot' = 99 - TAIL: 'CommonBodySlot' = 61 - TAIL_BASE: 'CommonBodySlot' = 111 - TATTOO_ARM_LOWER_LEFT: 'CommonBodySlot' = 45 - TATTOO_ARM_LOWER_RIGHT: 'CommonBodySlot' = 47 - TATTOO_ARM_UPPER_LEFT: 'CommonBodySlot' = 46 - TATTOO_ARM_UPPER_RIGHT: 'CommonBodySlot' = 48 - TATTOO_LEG_LEFT: 'CommonBodySlot' = 49 - TATTOO_LEG_RIGHT: 'CommonBodySlot' = 50 - TATTOO_TORSO_BACK_LOWER: 'CommonBodySlot' = 51 - TATTOO_TORSO_BACK_UPPER: 'CommonBodySlot' = 52 - TATTOO_TORSO_FRONT_LOWER: 'CommonBodySlot' = 53 - TATTOO_TORSO_FRONT_UPPER: 'CommonBodySlot' = 54 - TEETH: 'CommonBodySlot' = 4 - TIGHTS: 'CommonBodySlot' = 42 - TOENAIL: 'CommonBodySlot' = 74 - UPPER_BODY: 'CommonBodySlot' = 6 - WRIST_LEFT: 'CommonBodySlot' = 14 - WRIST_RIGHT: 'CommonBodySlot' = 15 - - @classmethod - def get_all(cls, exclude_values: Iterator['CommonBodySlot'] = None) -> Tuple['CommonBodySlot']: - """get_all(exclude_values=None) - - Get a collection of all values. - - :param exclude_values: These values will be excluded. If set to None, NONE will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonBodySlot], optional - :return: A collection of all values. - :rtype: Tuple[CommonBodySlot] - """ - if exclude_values is None: - exclude_values = (cls.NONE,) - # noinspection PyTypeChecker - value_list: Tuple[CommonBodySlot, ...] = tuple([value for value in cls.values if value not in exclude_values]) - return value_list - - @classmethod - def get_all_names(cls, exclude_values: Iterator['CommonBodySlot'] = None) -> Tuple[str]: - """get_all_names(exclude_values=None) - - Retrieve a collection of the names of all values. - - :param exclude_values: These values will be excluded. If set to None, NONE will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonBodySlot], optional - :return: A collection of the names of all values. - :rtype: Tuple[str] - """ - name_list: Tuple[str] = tuple([value.name for value in cls.get_all(exclude_values=exclude_values)]) - return name_list - - @classmethod - def get_comma_separated_names_string(cls, exclude_values: Iterator['CommonBodySlot'] = None) -> str: - """get_comma_separated_names_string(exclude_values=None) - - Create a string containing all names of all values, separated by a comma. - - :param exclude_values: These values will be excluded. If set to None, NONE will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonBodySlot], optional - :return: A string containing all names of all values, separated by a comma. - :rtype: str - """ - return ', '.join(cls.get_all_names(exclude_values=exclude_values)) - - @staticmethod - def convert_to_vanilla(value: Union['CommonBodySlot', BodyType, int]) -> Union[BodyType, 'CommonBodySlot', int]: - """convert_to_vanilla(value) - - Convert a CommonBodySlot into the vanilla BodyType enum. - - :param value: An instance of a CommonBodySlot - :type value: CommonBodySlot - :return: The specified CommonBodySlot translated to a BodyType or the value itself if the CommonBodySlot could not be translated. - :rtype: Union[BodyType, int] - """ - if value is None or value == CommonBodySlot.NONE: - return BodyType.NONE - if isinstance(value, BodyType): - return value - mapping = dict() - if hasattr(BodyType, 'ACNE'): - mapping[CommonBodySlot.ACNE] = BodyType.ACNE - if hasattr(BodyType, 'ATTACHMENT_BACK'): - mapping[CommonBodySlot.ATTACHMENT_BACK] = BodyType.ATTACHMENT_BACK - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'BIRTHMARKARMS'): - mapping[CommonBodySlot.BIRTHMARK_ARMS] = BodyType.BIRTHMARKARMS - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'BIRTHMARKFACE'): - mapping[CommonBodySlot.BIRTHMARK_FACE] = BodyType.BIRTHMARKFACE - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'BIRTHMARKLEGS'): - mapping[CommonBodySlot.BIRTHMARK_LEGS] = BodyType.BIRTHMARKLEGS - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'BIRTHMARKTORSOBACK'): - mapping[CommonBodySlot.BIRTHMARK_TORSO_BACK] = BodyType.BIRTHMARKTORSOBACK - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'BIRTHMARKTORSOFRONT'): - mapping[CommonBodySlot.BIRTHMARK_TORSO_FRONT] = BodyType.BIRTHMARKTORSOFRONT - if hasattr(BodyType, 'BITE'): - mapping[CommonBodySlot.BITE] = BodyType.BITE - if hasattr(BodyType, 'BLANKET'): - mapping[CommonBodySlot.BLANKET] = BodyType.BLANKET - if hasattr(BodyType, 'BLUSH'): - mapping[CommonBodySlot.BLUSH] = BodyType.BLUSH - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'BODYFRECKLES'): - mapping[CommonBodySlot.BODY_FRECKLES] = BodyType.BODYFRECKLES - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'BODYHAIR_ARM'): - mapping[CommonBodySlot.BODY_HAIR_ARM] = BodyType.BODYHAIR_ARM - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'BODYHAIR_LEG'): - mapping[CommonBodySlot.BODY_HAIR_LEG] = BodyType.BODYHAIR_LEG - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'BODYHAIR_TORSOBACK'): - mapping[CommonBodySlot.BODY_HAIR_TORSO_BACK] = BodyType.BODYHAIR_TORSOBACK - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'BODYHAIR_TORSOFRONT'): - mapping[CommonBodySlot.BODY_HAIR_TORSO_FRONT] = BodyType.BODYHAIR_TORSOFRONT - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'BODYSCAR_ARMLEFT'): - mapping[CommonBodySlot.BODY_SCAR_ARM_LEFT] = BodyType.BODYSCAR_ARMLEFT - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'BODYSCAR_ARMRIGHT'): - mapping[CommonBodySlot.BODY_SCAR_ARM_RIGHT] = BodyType.BODYSCAR_ARMRIGHT - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'BODYSCAR_LEGLEFT'): - mapping[CommonBodySlot.BODY_SCAR_LEG_LEFT] = BodyType.BODYSCAR_LEGLEFT - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'BODYSCAR_LEGRIGHT'): - mapping[CommonBodySlot.BODY_SCAR_LEG_RIGHT] = BodyType.BODYSCAR_LEGRIGHT - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'BODYSCAR_TORSOBACK'): - mapping[CommonBodySlot.BODY_SCAR_TORSO_BACK] = BodyType.BODYSCAR_TORSOBACK - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'BODYSCAR_TORSOFRONT'): - mapping[CommonBodySlot.BODY_SCAR_TORSO_FRONT] = BodyType.BODYSCAR_TORSOFRONT - if hasattr(BodyType, 'BRIDLE'): - mapping[CommonBodySlot.BRIDLE] = BodyType.BRIDLE - if hasattr(BodyType, 'BROW_RING_LEFT'): - mapping[CommonBodySlot.BROW_RING_LEFT] = BodyType.BROW_RING_LEFT - if hasattr(BodyType, 'BROW_RING_RIGHT'): - mapping[CommonBodySlot.BROW_RING_RIGHT] = BodyType.BROW_RING_RIGHT - if hasattr(BodyType, 'CUMMERBUND'): - mapping[CommonBodySlot.CUMMERBUND] = BodyType.CUMMERBUND - if hasattr(BodyType, 'EARRINGS'): - mapping[CommonBodySlot.EARRINGS] = BodyType.EARRINGS - if hasattr(BodyType, 'EARS'): - mapping[CommonBodySlot.EARS] = BodyType.EARS - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'EYECOLOR'): - mapping[CommonBodySlot.EYE_COLOR] = BodyType.EYECOLOR - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'EYECOLOR_SECONDARY'): - mapping[CommonBodySlot.EYE_COLOR_SECONDARY] = BodyType.EYECOLOR_SECONDARY - if hasattr(BodyType, 'EYE_LINER'): - mapping[CommonBodySlot.EYE_LINER] = BodyType.EYE_LINER - if hasattr(BodyType, 'EYE_SHADOW'): - mapping[CommonBodySlot.EYE_SHADOW] = BodyType.EYE_SHADOW - if hasattr(BodyType, 'EYEBROWS'): - mapping[CommonBodySlot.EYEBROWS] = BodyType.EYEBROWS - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'FACEPAINT'): - mapping[CommonBodySlot.FACE_PAINT] = BodyType.FACEPAINT - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'SCARFACE'): - mapping[CommonBodySlot.FACE_SCAR] = BodyType.SCARFACE - if hasattr(BodyType, 'FACIAL_HAIR'): - mapping[CommonBodySlot.FACIAL_HAIR] = BodyType.FACIAL_HAIR - if hasattr(BodyType, 'FINGERNAIL'): - mapping[CommonBodySlot.FINGERNAIL] = BodyType.FINGERNAIL - if hasattr(BodyType, 'FOREARM_SCAR'): - mapping[CommonBodySlot.FOREARM_SCAR] = BodyType.FOREARM_SCAR - if hasattr(BodyType, 'FULL_BODY'): - mapping[CommonBodySlot.FULL_BODY] = BodyType.FULL_BODY - if hasattr(BodyType, 'FUR_BODY'): - mapping[CommonBodySlot.FUR_BODY] = BodyType.FUR_BODY - if hasattr(BodyType, 'GLASSES'): - mapping[CommonBodySlot.GLASSES] = BodyType.GLASSES - if hasattr(BodyType, 'GLOVES'): - mapping[CommonBodySlot.GLOVES] = BodyType.GLOVES - if hasattr(BodyType, 'HAIR'): - mapping[CommonBodySlot.HAIR] = BodyType.HAIR - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'HAIRCOLOR_OVERRIDE'): - mapping[CommonBodySlot.HAIR_COLOR_OVERRIDE] = BodyType.HAIRCOLOR_OVERRIDE - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'HAIR_FEATHERS'): - mapping[CommonBodySlot.HAIR_FEATHERS] = BodyType.HAIR_FEATHERS - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'HAIR_FORELOCK'): - mapping[CommonBodySlot.HAIR_FORELOCK] = BodyType.HAIR_FORELOCK - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'HAIR_MANE'): - mapping[CommonBodySlot.HAIR_MANE] = BodyType.HAIR_MANE - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'HAIR_TAIL'): - mapping[CommonBodySlot.HAIR_TAIL] = BodyType.HAIR_TAIL - if hasattr(BodyType, 'HAT'): - mapping[CommonBodySlot.HAT] = BodyType.HAT - if hasattr(BodyType, 'HEAD'): - mapping[CommonBodySlot.HEAD] = BodyType.HEAD - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'HORN'): - mapping[CommonBodySlot.HORN] = BodyType.HORN - if hasattr(BodyType, 'INDEX_FINGER_LEFT'): - mapping[CommonBodySlot.INDEX_FINGER_LEFT] = BodyType.INDEX_FINGER_LEFT - if hasattr(BodyType, 'INDEX_FINGER_RIGHT'): - mapping[CommonBodySlot.INDEX_FINGER_RIGHT] = BodyType.INDEX_FINGER_RIGHT - if hasattr(BodyType, 'LIP_RING_LEFT'): - mapping[CommonBodySlot.LIP_RING_LEFT] = BodyType.LIP_RING_LEFT - if hasattr(BodyType, 'LIP_RING_RIGHT'): - mapping[CommonBodySlot.LIP_RING_RIGHT] = BodyType.LIP_RING_RIGHT - if hasattr(BodyType, 'LIPS_TICK'): - mapping[CommonBodySlot.LIPSTICK] = BodyType.LIPS_TICK - if hasattr(BodyType, 'LOWER_BODY'): - mapping[CommonBodySlot.LOWER_BODY] = BodyType.LOWER_BODY - if hasattr(BodyType, 'EYELASHES'): - mapping[CommonBodySlot.EYELASHES] = BodyType.EYELASHES - if hasattr(BodyType, 'MIDDLE_FINGER_LEFT'): - mapping[CommonBodySlot.MIDDLE_FINGER_LEFT] = BodyType.MIDDLE_FINGER_LEFT - if hasattr(BodyType, 'MIDDLE_FINGER_RIGHT'): - mapping[CommonBodySlot.MIDDLE_FINGER_RIGHT] = BodyType.MIDDLE_FINGER_RIGHT - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'MOLEBACKUPPER'): - mapping[CommonBodySlot.MOLE_BACK_UPPER] = BodyType.MOLEBACKUPPER - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'MOLECHESTUPPER'): - mapping[CommonBodySlot.MOLE_CHEST_UPPER] = BodyType.MOLECHESTUPPER - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'MOLEFACE'): - mapping[CommonBodySlot.MOLE_FACE] = BodyType.MOLEFACE - if hasattr(BodyType, 'NECKLACE'): - mapping[CommonBodySlot.NECKLACE] = BodyType.NECKLACE - if hasattr(BodyType, 'NOSE_RING_LEFT'): - mapping[CommonBodySlot.NOSE_RING_LEFT] = BodyType.NOSE_RING_LEFT - if hasattr(BodyType, 'NOSE_RING_RIGHT'): - mapping[CommonBodySlot.NOSE_RING_RIGHT] = BodyType.NOSE_RING_RIGHT - if hasattr(BodyType, 'OCCULT_BROW'): - mapping[CommonBodySlot.OCCULT_BROW] = BodyType.OCCULT_BROW - if hasattr(BodyType, 'OCCULT_EYE_SOCKET'): - mapping[CommonBodySlot.OCCULT_EYE_SOCKET] = BodyType.OCCULT_EYE_SOCKET - if hasattr(BodyType, 'OCCULT_EYE_LID'): - mapping[CommonBodySlot.OCCULT_EYELID] = BodyType.OCCULT_EYE_LID - if hasattr(BodyType, 'OCCULT_LEFT_CHEEK'): - mapping[CommonBodySlot.OCCULT_LEFT_CHEEK] = BodyType.OCCULT_LEFT_CHEEK - if hasattr(BodyType, 'OCCULT_MOUTH'): - mapping[CommonBodySlot.OCCULT_MOUTH] = BodyType.OCCULT_MOUTH - if hasattr(BodyType, 'OCCULT_NECK_SCAR'): - mapping[CommonBodySlot.OCCULT_NECK_SCAR] = BodyType.OCCULT_NECK_SCAR - if hasattr(BodyType, 'OCCULT_RIGHT_CHEEK'): - mapping[CommonBodySlot.OCCULT_RIGHT_CHEEK] = BodyType.OCCULT_RIGHT_CHEEK - if hasattr(BodyType, 'REINS'): - mapping[CommonBodySlot.REINS] = BodyType.REINS - if hasattr(BodyType, 'RING_FINGER_LEFT'): - mapping[CommonBodySlot.RING_FINGER_LEFT] = BodyType.RING_FINGER_LEFT - if hasattr(BodyType, 'RING_FINGER_RIGHT'): - mapping[CommonBodySlot.RING_FINGER_RIGHT] = BodyType.RING_FINGER_RIGHT - if hasattr(BodyType, 'SADDLE'): - mapping[CommonBodySlot.SADDLE] = BodyType.SADDLE - if hasattr(BodyType, 'SHOES'): - mapping[CommonBodySlot.SHOES] = BodyType.SHOES - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'SKINDETAIL_ACNE_PUBERTY'): - mapping[CommonBodySlot.SKIN_DETAIL_ACNE_PUBERTY] = BodyType.SKINDETAIL_ACNE_PUBERTY - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'SKINDETAIL_CREASE_FOREHEAD'): - mapping[CommonBodySlot.SKIN_DETAIL_CREASE_FOREHEAD] = BodyType.SKINDETAIL_CREASE_FOREHEAD - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'SKINDETAIL_CREASE_MOUTH'): - mapping[CommonBodySlot.SKIN_DETAIL_CREASE_MOUTH] = BodyType.SKINDETAIL_CREASE_MOUTH - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'SKINDETAIL_DIMPLE_LEFT'): - mapping[CommonBodySlot.SKIN_DETAIL_DIMPLE_LEFT] = BodyType.SKINDETAIL_DIMPLE_LEFT - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'SKINDETAIL_DIMPLE_RIGHT'): - mapping[CommonBodySlot.SKIN_DETAIL_DIMPLE_RIGHT] = BodyType.SKINDETAIL_DIMPLE_RIGHT - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'SKINDETAIL_FRECKLES'): - mapping[CommonBodySlot.SKIN_DETAIL_FRECKLES] = BodyType.SKINDETAIL_FRECKLES - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'SKINDETAIL_HOOF_COLOR'): - mapping[CommonBodySlot.SKIN_DETAIL_HOOF_COLOR] = BodyType.SKINDETAIL_HOOF_COLOR - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'SKINDETAIL_MOLE_CHEEK_LEFT'): - mapping[CommonBodySlot.SKIN_DETAIL_MOLE_CHEEK_LEFT] = BodyType.SKINDETAIL_MOLE_CHEEK_LEFT - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'SKINDETAIL_MOLE_CHEEK_RIGHT'): - mapping[CommonBodySlot.SKIN_DETAIL_MOLE_CHEEK_RIGHT] = BodyType.SKINDETAIL_MOLE_CHEEK_RIGHT - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'SKINDETAIL_MOLE_LIP_LEFT'): - mapping[CommonBodySlot.SKIN_DETAIL_MOLE_LIP_LEFT] = BodyType.SKINDETAIL_MOLE_LIP_LEFT - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'SKINDETAIL_MOLE_LIP_RIGHT'): - mapping[CommonBodySlot.SKIN_DETAIL_MOLE_LIP_RIGHT] = BodyType.SKINDETAIL_MOLE_LIP_RIGHT - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'SKINDETAIL_NOSE_COLOR'): - mapping[CommonBodySlot.SKIN_DETAIL_NOSE_COLOR] = BodyType.SKINDETAIL_NOSE_COLOR - if hasattr(BodyType, 'SKIN_OVERLAY'): - mapping[CommonBodySlot.SKIN_OVERLAY] = BodyType.SKIN_OVERLAY - if hasattr(BodyType, 'SOCKS'): - mapping[CommonBodySlot.SOCKS] = BodyType.SOCKS - if hasattr(BodyType, 'STRETCHMARKS_BACK'): - mapping[CommonBodySlot.STRETCH_MARKS_BACK] = BodyType.STRETCHMARKS_BACK - if hasattr(BodyType, 'STRETCHMARKS_FRONT'): - mapping[CommonBodySlot.STRETCH_MARKS_FRONT] = BodyType.STRETCHMARKS_FRONT - if hasattr(BodyType, 'TAIL'): - mapping[CommonBodySlot.TAIL] = BodyType.TAIL - if hasattr(BodyType, 'TAIL_BASE'): - mapping[CommonBodySlot.TAIL_BASE] = BodyType.TAIL_BASE - if hasattr(BodyType, 'TATTOO_ARM_LOWER_LEFT'): - mapping[CommonBodySlot.TATTOO_ARM_LOWER_LEFT] = BodyType.TATTOO_ARM_LOWER_LEFT - if hasattr(BodyType, 'TATTOO_ARM_LOWER_RIGHT'): - mapping[CommonBodySlot.TATTOO_ARM_LOWER_RIGHT] = BodyType.TATTOO_ARM_LOWER_RIGHT - if hasattr(BodyType, 'TATTOO_ARM_UPPER_LEFT'): - mapping[CommonBodySlot.TATTOO_ARM_UPPER_LEFT] = BodyType.TATTOO_ARM_UPPER_LEFT - if hasattr(BodyType, 'TATTOO_ARM_UPPER_RIGHT'): - mapping[CommonBodySlot.TATTOO_ARM_UPPER_RIGHT] = BodyType.TATTOO_ARM_UPPER_RIGHT - if hasattr(BodyType, 'TATTOO_LEG_LEFT'): - mapping[CommonBodySlot.TATTOO_LEG_LEFT] = BodyType.TATTOO_LEG_LEFT - if hasattr(BodyType, 'TATTOO_LEG_RIGHT'): - mapping[CommonBodySlot.TATTOO_LEG_RIGHT] = BodyType.TATTOO_LEG_RIGHT - if hasattr(BodyType, 'TATTOO_TORSO_BACK_LOWER'): - mapping[CommonBodySlot.TATTOO_TORSO_BACK_LOWER] = BodyType.TATTOO_TORSO_BACK_LOWER - if hasattr(BodyType, 'TATTOO_TORSO_BACK_UPPER'): - mapping[CommonBodySlot.TATTOO_TORSO_BACK_UPPER] = BodyType.TATTOO_TORSO_BACK_UPPER - if hasattr(BodyType, 'TATTOO_TORSO_FRONT_LOWER'): - mapping[CommonBodySlot.TATTOO_TORSO_FRONT_LOWER] = BodyType.TATTOO_TORSO_FRONT_LOWER - if hasattr(BodyType, 'TATTOO_TORSO_FRONT_UPPER'): - mapping[CommonBodySlot.TATTOO_TORSO_FRONT_UPPER] = BodyType.TATTOO_TORSO_FRONT_UPPER - if hasattr(BodyType, 'TEETH'): - mapping[CommonBodySlot.TEETH] = BodyType.TEETH - if hasattr(BodyType, 'TIGHTS'): - mapping[CommonBodySlot.TIGHTS] = BodyType.TIGHTS - if hasattr(BodyType, 'TOENAIL'): - mapping[CommonBodySlot.TOENAIL] = BodyType.TOENAIL - if hasattr(BodyType, 'UPPER_BODY'): - mapping[CommonBodySlot.UPPER_BODY] = BodyType.UPPER_BODY - if hasattr(BodyType, 'WRIST_LEFT'): - mapping[CommonBodySlot.WRIST_LEFT] = BodyType.WRIST_LEFT - if hasattr(BodyType, 'WRIST_RIGHT'): - mapping[CommonBodySlot.WRIST_RIGHT] = BodyType.WRIST_RIGHT - return mapping.get(value, value) - - @staticmethod - def convert_from_vanilla(value: Union['CommonBodySlot', BodyType, int]) -> Union['CommonBodySlot', BodyType, int]: - """convert_from_vanilla(value) - - Convert a BodyType into a CommonBodySlot - - :param value: An instance of a BodyType - :type value: Union[CommonBodySlot, BodyType, int] - :return: The specified BodyType translated to a CommonBodySlot or the value itself if the BodyType could not be translated. - :rtype: Union[CommonBodySlot, int] - """ - if value is None or value == CommonBodySlot.NONE: - return CommonBodySlot.NONE - if isinstance(value, CommonBodySlot): - return value - mapping = dict() - if hasattr(BodyType, 'ACNE'): - mapping[BodyType.ACNE] = CommonBodySlot.ACNE - if hasattr(BodyType, 'ATTACHMENT_BACK'): - mapping[BodyType.ATTACHMENT_BACK] = CommonBodySlot.ATTACHMENT_BACK - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'BIRTHMARKARMS'): - mapping[BodyType.BIRTHMARKARMS] = CommonBodySlot.BIRTHMARK_ARMS - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'BIRTHMARKFACE'): - mapping[BodyType.BIRTHMARKFACE] = CommonBodySlot.BIRTHMARK_FACE - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'BIRTHMARKLEGS'): - mapping[BodyType.BIRTHMARKLEGS] = CommonBodySlot.BIRTHMARK_LEGS - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'BIRTHMARKTORSOBACK'): - mapping[BodyType.BIRTHMARKTORSOBACK] = CommonBodySlot.BIRTHMARK_TORSO_BACK - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'BIRTHMARKTORSOFRONT'): - mapping[BodyType.BIRTHMARKTORSOFRONT] = CommonBodySlot.BIRTHMARK_TORSO_FRONT - if hasattr(BodyType, 'BITE'): - mapping[BodyType.BITE] = CommonBodySlot.BITE - if hasattr(BodyType, 'BLANKET'): - mapping[BodyType.BLANKET] = CommonBodySlot.BLANKET - if hasattr(BodyType, 'BLUSH'): - mapping[BodyType.BLUSH] = CommonBodySlot.BLUSH - if hasattr(BodyType, 'BRIDLE'): - mapping[BodyType.BRIDLE] = CommonBodySlot.BRIDLE - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'BODYFRECKLES'): - mapping[BodyType.BODYFRECKLES] = CommonBodySlot.BODY_FRECKLES - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'BODYHAIR_ARM'): - mapping[BodyType.BODYHAIR_ARM] = CommonBodySlot.BODY_HAIR_ARM - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'BODYHAIR_LEG'): - mapping[BodyType.BODYHAIR_LEG] = CommonBodySlot.BODY_HAIR_LEG - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'BODYHAIR_TORSOBACK'): - mapping[BodyType.BODYHAIR_TORSOBACK] = CommonBodySlot.BODY_HAIR_TORSO_BACK - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'BODYHAIR_TORSOFRONT'): - mapping[BodyType.BODYHAIR_TORSOFRONT] = CommonBodySlot.BODY_HAIR_TORSO_FRONT - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'BODYSCAR_ARMLEFT'): - mapping[BodyType.BODYSCAR_ARMLEFT] = CommonBodySlot.BODY_SCAR_ARM_LEFT - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'BODYSCAR_ARMRIGHT'): - mapping[BodyType.BODYSCAR_ARMRIGHT] = CommonBodySlot.BODY_SCAR_ARM_RIGHT - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'BODYSCAR_LEGLEFT'): - mapping[BodyType.BODYSCAR_LEGLEFT] = CommonBodySlot.BODY_SCAR_LEG_LEFT - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'BODYSCAR_LEGRIGHT'): - mapping[BodyType.BODYSCAR_LEGRIGHT] = CommonBodySlot.BODY_SCAR_LEG_RIGHT - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'BODYSCAR_TORSOBACK'): - mapping[BodyType.BODYSCAR_TORSOBACK] = CommonBodySlot.BODY_SCAR_TORSO_BACK - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'BODYSCAR_TORSOFRONT'): - mapping[BodyType.BODYSCAR_TORSOFRONT] = CommonBodySlot.BODY_SCAR_TORSO_FRONT - if hasattr(BodyType, 'BROW_RING_LEFT'): - mapping[BodyType.BROW_RING_LEFT] = CommonBodySlot.BROW_RING_LEFT - if hasattr(BodyType, 'BROW_RING_RIGHT'): - mapping[BodyType.BROW_RING_RIGHT] = CommonBodySlot.BROW_RING_RIGHT - if hasattr(BodyType, 'CUMMERBUND'): - mapping[BodyType.CUMMERBUND] = CommonBodySlot.CUMMERBUND - if hasattr(BodyType, 'EARRINGS'): - mapping[BodyType.EARRINGS] = CommonBodySlot.EARRINGS - if hasattr(BodyType, 'EARS'): - mapping[BodyType.EARS] = CommonBodySlot.EARS - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'EYECOLOR'): - mapping[BodyType.EYECOLOR] = CommonBodySlot.EYE_COLOR - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'EYECOLOR_SECONDARY'): - mapping[BodyType.EYECOLOR_SECONDARY] = CommonBodySlot.EYE_COLOR_SECONDARY - if hasattr(BodyType, 'EYE_LINER'): - mapping[BodyType.EYE_LINER] = CommonBodySlot.EYE_LINER - if hasattr(BodyType, 'EYE_SHADOW'): - mapping[BodyType.EYE_SHADOW] = CommonBodySlot.EYE_SHADOW - if hasattr(BodyType, 'EYEBROWS'): - mapping[BodyType.EYEBROWS] = CommonBodySlot.EYEBROWS - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'FACEPAINT'): - mapping[BodyType.FACEPAINT] = CommonBodySlot.FACE_PAINT - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'SCARFACE'): - mapping[BodyType.SCARFACE] = CommonBodySlot.FACE_SCAR - if hasattr(BodyType, 'FACIAL_HAIR'): - mapping[BodyType.FACIAL_HAIR] = CommonBodySlot.FACIAL_HAIR - if hasattr(BodyType, 'FINGERNAIL'): - mapping[BodyType.FINGERNAIL] = CommonBodySlot.FINGERNAIL - if hasattr(BodyType, 'FOREARM_SCAR'): - mapping[BodyType.FOREARM_SCAR] = CommonBodySlot.FOREARM_SCAR - if hasattr(BodyType, 'FULL_BODY'): - mapping[BodyType.FULL_BODY] = CommonBodySlot.FULL_BODY - if hasattr(BodyType, 'FUR_BODY'): - mapping[BodyType.FUR_BODY] = CommonBodySlot.FUR_BODY - if hasattr(BodyType, 'GLASSES'): - mapping[BodyType.GLASSES] = CommonBodySlot.GLASSES - if hasattr(BodyType, 'GLOVES'): - mapping[BodyType.GLOVES] = CommonBodySlot.GLOVES - if hasattr(BodyType, 'HAIR'): - mapping[BodyType.HAIR] = CommonBodySlot.HAIR - if hasattr(BodyType, 'HAIR_FEATHERS'): - mapping[BodyType.HAIR_FEATHERS] = CommonBodySlot.HAIR_FEATHERS - if hasattr(BodyType, 'HAIR_FORELOCK'): - mapping[BodyType.HAIR_FORELOCK] = CommonBodySlot.HAIR_FORELOCK - if hasattr(BodyType, 'HAIR_MANE'): - mapping[BodyType.HAIR_MANE] = CommonBodySlot.HAIR_MANE - if hasattr(BodyType, 'HAIR_TAIL'): - mapping[BodyType.HAIR_TAIL] = CommonBodySlot.HAIR_TAIL - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'HAIRCOLOR_OVERRIDE'): - mapping[BodyType.HAIRCOLOR_OVERRIDE] = CommonBodySlot.HAIR_COLOR_OVERRIDE - if hasattr(BodyType, 'HAT'): - mapping[BodyType.HAT] = CommonBodySlot.HAT - if hasattr(BodyType, 'HEAD'): - mapping[BodyType.HEAD] = CommonBodySlot.HEAD - if hasattr(BodyType, 'HORN'): - mapping[BodyType.HORN] = CommonBodySlot.HORN - if hasattr(BodyType, 'INDEX_FINGER_LEFT'): - mapping[BodyType.INDEX_FINGER_LEFT] = CommonBodySlot.INDEX_FINGER_LEFT - if hasattr(BodyType, 'INDEX_FINGER_RIGHT'): - mapping[BodyType.INDEX_FINGER_RIGHT] = CommonBodySlot.INDEX_FINGER_RIGHT - if hasattr(BodyType, 'LIP_RING_LEFT'): - mapping[BodyType.LIP_RING_LEFT] = CommonBodySlot.LIP_RING_LEFT - if hasattr(BodyType, 'LIP_RING_RIGHT'): - mapping[BodyType.LIP_RING_RIGHT] = CommonBodySlot.LIP_RING_RIGHT - if hasattr(BodyType, 'LIPS_TICK'): - mapping[BodyType.LIPS_TICK] = CommonBodySlot.LIPSTICK - if hasattr(BodyType, 'LOWER_BODY'): - mapping[BodyType.LOWER_BODY] = CommonBodySlot.LOWER_BODY - if hasattr(BodyType, 'EYELASHES'): - mapping[BodyType.EYELASHES] = CommonBodySlot.EYELASHES - if hasattr(BodyType, 'MIDDLE_FINGER_LEFT'): - mapping[BodyType.MIDDLE_FINGER_LEFT] = CommonBodySlot.MIDDLE_FINGER_LEFT - if hasattr(BodyType, 'MIDDLE_FINGER_RIGHT'): - mapping[BodyType.MIDDLE_FINGER_RIGHT] = CommonBodySlot.MIDDLE_FINGER_RIGHT - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'MOLEBACKUPPER'): - mapping[BodyType.MOLEBACKUPPER] = CommonBodySlot.MOLE_BACK_UPPER - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'MOLECHESTUPPER'): - mapping[BodyType.MOLECHESTUPPER] = CommonBodySlot.MOLE_CHEST_UPPER - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'MOLEFACE'): - mapping[BodyType.MOLEFACE] = CommonBodySlot.MOLE_FACE - if hasattr(BodyType, 'NECKLACE'): - mapping[BodyType.NECKLACE] = CommonBodySlot.NECKLACE - if hasattr(BodyType, 'NOSE_RING_LEFT'): - mapping[BodyType.NOSE_RING_LEFT] = CommonBodySlot.NOSE_RING_LEFT - if hasattr(BodyType, 'NOSE_RING_RIGHT'): - mapping[BodyType.NOSE_RING_RIGHT] = CommonBodySlot.NOSE_RING_RIGHT - if hasattr(BodyType, 'OCCULT_BROW'): - mapping[BodyType.OCCULT_BROW] = CommonBodySlot.OCCULT_BROW - if hasattr(BodyType, 'OCCULT_EYE_SOCKET'): - mapping[BodyType.OCCULT_EYE_SOCKET] = CommonBodySlot.OCCULT_EYE_SOCKET - if hasattr(BodyType, 'OCCULT_EYE_LID'): - mapping[BodyType.OCCULT_EYE_LID] = CommonBodySlot.OCCULT_EYELID - if hasattr(BodyType, 'OCCULT_LEFT_CHEEK'): - mapping[BodyType.OCCULT_LEFT_CHEEK] = CommonBodySlot.OCCULT_LEFT_CHEEK - if hasattr(BodyType, 'OCCULT_MOUTH'): - mapping[BodyType.OCCULT_MOUTH] = CommonBodySlot.OCCULT_MOUTH - if hasattr(BodyType, 'OCCULT_NECK_SCAR'): - mapping[BodyType.OCCULT_NECK_SCAR] = CommonBodySlot.OCCULT_NECK_SCAR - if hasattr(BodyType, 'OCCULT_RIGHT_CHEEK'): - mapping[BodyType.OCCULT_RIGHT_CHEEK] = CommonBodySlot.OCCULT_RIGHT_CHEEK - if hasattr(BodyType, 'REINS'): - mapping[BodyType.REINS] = CommonBodySlot.REINS - if hasattr(BodyType, 'RING_FINGER_LEFT'): - mapping[BodyType.RING_FINGER_LEFT] = CommonBodySlot.RING_FINGER_LEFT - if hasattr(BodyType, 'RING_FINGER_RIGHT'): - mapping[BodyType.RING_FINGER_RIGHT] = CommonBodySlot.RING_FINGER_RIGHT - if hasattr(BodyType, 'SADDLE'): - mapping[BodyType.SADDLE] = CommonBodySlot.SADDLE - if hasattr(BodyType, 'SHOES'): - mapping[BodyType.SHOES] = CommonBodySlot.SHOES - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'SKINDETAIL_ACNE_PUBERTY'): - mapping[BodyType.SKINDETAIL_ACNE_PUBERTY] = CommonBodySlot.SKIN_DETAIL_ACNE_PUBERTY - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'SKINDETAIL_CREASE_FOREHEAD'): - mapping[BodyType.SKINDETAIL_CREASE_FOREHEAD] = CommonBodySlot.SKIN_DETAIL_CREASE_FOREHEAD - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'SKINDETAIL_CREASE_MOUTH'): - mapping[BodyType.SKINDETAIL_CREASE_MOUTH] = CommonBodySlot.SKIN_DETAIL_CREASE_MOUTH - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'SKINDETAIL_DIMPLE_LEFT'): - mapping[BodyType.SKINDETAIL_DIMPLE_LEFT] = CommonBodySlot.SKIN_DETAIL_DIMPLE_LEFT - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'SKINDETAIL_DIMPLE_RIGHT'): - mapping[BodyType.SKINDETAIL_DIMPLE_RIGHT] = CommonBodySlot.SKIN_DETAIL_DIMPLE_RIGHT - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'SKINDETAIL_FRECKLES'): - mapping[BodyType.SKINDETAIL_FRECKLES] = CommonBodySlot.SKIN_DETAIL_FRECKLES - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'SKINDETAIL_HOOF_COLOR'): - mapping[BodyType.SKINDETAIL_HOOF_COLOR] = CommonBodySlot.SKIN_DETAIL_HOOF_COLOR - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'SKINDETAIL_MOLE_CHEEK_LEFT'): - mapping[BodyType.SKINDETAIL_MOLE_CHEEK_LEFT] = CommonBodySlot.SKIN_DETAIL_MOLE_CHEEK_LEFT - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'SKINDETAIL_MOLE_CHEEK_RIGHT'): - mapping[BodyType.SKINDETAIL_MOLE_CHEEK_RIGHT] = CommonBodySlot.SKIN_DETAIL_MOLE_CHEEK_RIGHT - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'SKINDETAIL_MOLE_LIP_LEFT'): - mapping[BodyType.SKINDETAIL_MOLE_LIP_LEFT] = CommonBodySlot.SKIN_DETAIL_MOLE_LIP_LEFT - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'SKINDETAIL_MOLE_LIP_RIGHT'): - mapping[BodyType.SKINDETAIL_MOLE_LIP_RIGHT] = CommonBodySlot.SKIN_DETAIL_MOLE_LIP_RIGHT - # noinspection SpellCheckingInspection - if hasattr(BodyType, 'SKINDETAIL_NOSE_COLOR'): - mapping[BodyType.SKINDETAIL_NOSE_COLOR] = CommonBodySlot.SKIN_DETAIL_NOSE_COLOR - if hasattr(BodyType, 'SKIN_OVERLAY'): - mapping[BodyType.SKIN_OVERLAY] = CommonBodySlot.SKIN_OVERLAY - if hasattr(BodyType, 'SOCKS'): - mapping[BodyType.SOCKS] = CommonBodySlot.SOCKS - if hasattr(BodyType, 'STRETCHMARKS_BACK'): - mapping[BodyType.STRETCHMARKS_BACK] = CommonBodySlot.STRETCH_MARKS_BACK - if hasattr(BodyType, 'STRETCHMARKS_FRONT'): - mapping[BodyType.STRETCHMARKS_FRONT] = CommonBodySlot.STRETCH_MARKS_FRONT - if hasattr(BodyType, 'TAIL'): - mapping[BodyType.TAIL] = CommonBodySlot.TAIL - if hasattr(BodyType, 'TAIL_BASE'): - mapping[BodyType.TAIL_BASE] = CommonBodySlot.TAIL_BASE - if hasattr(BodyType, 'TATTOO_ARM_LOWER_LEFT'): - mapping[BodyType.TATTOO_ARM_LOWER_LEFT] = CommonBodySlot.TATTOO_ARM_LOWER_LEFT - if hasattr(BodyType, 'TATTOO_ARM_LOWER_RIGHT'): - mapping[BodyType.TATTOO_ARM_LOWER_RIGHT] = CommonBodySlot.TATTOO_ARM_LOWER_RIGHT - if hasattr(BodyType, 'TATTOO_ARM_UPPER_LEFT'): - mapping[BodyType.TATTOO_ARM_UPPER_LEFT] = CommonBodySlot.TATTOO_ARM_UPPER_LEFT - if hasattr(BodyType, 'TATTOO_ARM_UPPER_RIGHT'): - mapping[BodyType.TATTOO_ARM_UPPER_RIGHT] = CommonBodySlot.TATTOO_ARM_UPPER_RIGHT - if hasattr(BodyType, 'TATTOO_LEG_LEFT'): - mapping[BodyType.TATTOO_LEG_LEFT] = CommonBodySlot.TATTOO_LEG_LEFT - if hasattr(BodyType, 'TATTOO_LEG_RIGHT'): - mapping[BodyType.TATTOO_LEG_RIGHT] = CommonBodySlot.TATTOO_LEG_RIGHT - if hasattr(BodyType, 'TATTOO_TORSO_BACK_LOWER'): - mapping[BodyType.TATTOO_TORSO_BACK_LOWER] = CommonBodySlot.TATTOO_TORSO_BACK_LOWER - if hasattr(BodyType, 'TATTOO_TORSO_BACK_UPPER'): - mapping[BodyType.TATTOO_TORSO_BACK_UPPER] = CommonBodySlot.TATTOO_TORSO_BACK_UPPER - if hasattr(BodyType, 'TATTOO_TORSO_FRONT_LOWER'): - mapping[BodyType.TATTOO_TORSO_FRONT_LOWER] = CommonBodySlot.TATTOO_TORSO_FRONT_LOWER - if hasattr(BodyType, 'TATTOO_TORSO_FRONT_UPPER'): - mapping[BodyType.TATTOO_TORSO_FRONT_UPPER] = CommonBodySlot.TATTOO_TORSO_FRONT_UPPER - if hasattr(BodyType, 'TEETH'): - mapping[BodyType.TEETH] = CommonBodySlot.TEETH - if hasattr(BodyType, 'TIGHTS'): - mapping[BodyType.TIGHTS] = CommonBodySlot.TIGHTS - if hasattr(BodyType, 'TOENAIL'): - mapping[BodyType.TOENAIL] = CommonBodySlot.TOENAIL - if hasattr(BodyType, 'UPPER_BODY'): - mapping[BodyType.UPPER_BODY] = CommonBodySlot.UPPER_BODY - if hasattr(BodyType, 'WRIST_LEFT'): - mapping[BodyType.WRIST_LEFT] = CommonBodySlot.WRIST_LEFT - if hasattr(BodyType, 'WRIST_RIGHT'): - mapping[BodyType.WRIST_RIGHT] = CommonBodySlot.WRIST_RIGHT - return mapping.get(value, value) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_bucks_types.py b/Scripts/s4ap/sims4communitylib/enums/common_bucks_types.py deleted file mode 100644 index 504420d..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_bucks_types.py +++ /dev/null @@ -1,203 +0,0 @@ -""" -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 -""" -from typing import Iterator, Tuple, Union - -from bucks.bucks_enums import BucksType -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonBucksType(CommonInt): - """Variants of Bucks Types.""" - INVALID: 'CommonBucksType' = ... - RETAIL: 'CommonBucksType' = ... - VAMPIRE_POWER: 'CommonBucksType' = ... - VAMPIRE_WEAKNESS: 'CommonBucksType' = ... - VET: 'CommonBucksType' = ... - CLUB: 'CommonBucksType' = ... - RESTAURANT: 'CommonBucksType' = ... - RECYCLE_BITS: 'CommonBucksType' = ... - RECYCLE_PIECES: 'CommonBucksType' = ... - FAME_PERK: 'CommonBucksType' = ... - FAME_QUIRK: 'CommonBucksType' = ... - WITCH_PERK: 'CommonBucksType' = ... - INFLUENCE: 'CommonBucksType' = ... - GALACTIC_CREDIT: 'CommonBucksType' = ... - WEREWOLF_ABILITY: 'CommonBucksType' = ... - WEREWOLF_ABILITY_QUEST: 'CommonBucksType' = ... - - @classmethod - def get_all(cls, exclude_values: Iterator['CommonBucksType'] = None) -> Tuple['CommonBucksType']: - """get_all(exclude_values=None) - - Get a collection of all values. - - :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonBucksType], optional - :return: A collection of all values. - :rtype: Tuple[CommonBucksType] - """ - if exclude_values is None: - exclude_values = (cls.INVALID,) - # noinspection PyTypeChecker - value_list: Tuple[CommonBucksType, ...] = tuple([value for value in cls.values if value not in exclude_values]) - return value_list - - @classmethod - def get_all_names(cls, exclude_values: Iterator['CommonBucksType'] = None) -> Tuple[str]: - """get_all_names(exclude_values=None) - - Retrieve a collection of the names of all values. - - :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonBucksType], optional - :return: A collection of the names of all values. - :rtype: Tuple[str] - """ - name_list: Tuple[str] = tuple([value.name for value in cls.get_all(exclude_values=exclude_values)]) - return name_list - - @classmethod - def get_comma_separated_names_string(cls, exclude_values: Iterator['CommonBucksType'] = None) -> str: - """get_comma_separated_names_string(exclude_values=None) - - Create a string containing all names of all values, separated by a comma. - - :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonBucksType], optional - :return: A string containing all names of all values, separated by a comma. - :rtype: str - """ - return ', '.join(cls.get_all_names(exclude_values=exclude_values)) - - @staticmethod - def convert_to_vanilla(value: 'CommonBucksType') -> Union[BucksType, None]: - """convert_to_vanilla(value) - - Convert a value into the vanilla BucksType enum. - - :param value: An instance of CommonBucksType - :type value: CommonBucksType - :return: The specified value translated to BucksType or None if the value could not be translated. - :rtype: Union[BucksType, None] - """ - if value is None or value == CommonBucksType.INVALID: - return None - if isinstance(value, BucksType): - return value - mapping = dict() - if hasattr(BucksType, 'RetailBucks'): - mapping[CommonBucksType.RETAIL] = BucksType.RetailBucks - if hasattr(BucksType, 'VampirePowerBucks'): - mapping[CommonBucksType.VAMPIRE_POWER] = BucksType.VampirePowerBucks - if hasattr(BucksType, 'VampireWeaknessBucks'): - mapping[CommonBucksType.VAMPIRE_WEAKNESS] = BucksType.VampireWeaknessBucks - if hasattr(BucksType, 'VetBucks'): - mapping[CommonBucksType.VET] = BucksType.VetBucks - if hasattr(BucksType, 'ClubBucks'): - mapping[CommonBucksType.CLUB] = BucksType.ClubBucks - if hasattr(BucksType, 'RestaurantBucks'): - mapping[CommonBucksType.RESTAURANT] = BucksType.RestaurantBucks - if hasattr(BucksType, 'RecycleBitsBucks'): - mapping[CommonBucksType.RECYCLE_BITS] = BucksType.RecycleBitsBucks - if hasattr(BucksType, 'RecyclePiecesBucks'): - mapping[CommonBucksType.RECYCLE_PIECES] = BucksType.RecyclePiecesBucks - if hasattr(BucksType, 'FamePerkBucks'): - mapping[CommonBucksType.FAME_PERK] = BucksType.FamePerkBucks - if hasattr(BucksType, 'FameQuirkBucks'): - mapping[CommonBucksType.FAME_QUIRK] = BucksType.FameQuirkBucks - if hasattr(BucksType, 'WitchPerkBucks'): - mapping[CommonBucksType.WITCH_PERK] = BucksType.WitchPerkBucks - if hasattr(BucksType, 'InfluenceBuck'): - mapping[CommonBucksType.INFLUENCE] = BucksType.InfluenceBuck - if hasattr(BucksType, 'GalacticCredits'): - mapping[CommonBucksType.GALACTIC_CREDIT] = BucksType.GalacticCredits - if hasattr(BucksType, 'WerewolfAbilityBucks'): - mapping[CommonBucksType.WEREWOLF_ABILITY] = BucksType.WerewolfAbilityBucks - if hasattr(BucksType, 'WerewolfQuestAbilityBucks'): - mapping[CommonBucksType.WEREWOLF_ABILITY_QUEST] = BucksType.WerewolfQuestAbilityBucks - return mapping.get(value, None) - - @staticmethod - def convert_from_vanilla(value: Union[int, BucksType]) -> 'CommonBucksType': - """convert_from_vanilla(value) - - Convert a value into a CommonBucksType enum. - - :param value: An instance of BucksType - :type value: BucksType - :return: The specified value translated to CommonBucksType or INVALID if the value could not be translated. - :rtype: Union[BucksType, None] - """ - if value is None: - return CommonBucksType.INVALID - if isinstance(value, CommonBucksType): - return value - mapping = dict() - if hasattr(BucksType, 'RetailBucks'): - mapping[BucksType.RetailBucks] = CommonBucksType.RETAIL - if hasattr(BucksType, 'VampirePowerBucks'): - mapping[BucksType.VampirePowerBucks] = CommonBucksType.VAMPIRE_POWER - if hasattr(BucksType, 'VampireWeaknessBucks'): - mapping[BucksType.VampireWeaknessBucks] = CommonBucksType.VAMPIRE_WEAKNESS - if hasattr(BucksType, 'VetBucks'): - mapping[BucksType.VetBucks] = CommonBucksType.VET - if hasattr(BucksType, 'ClubBucks'): - mapping[BucksType.ClubBucks] = CommonBucksType.CLUB - if hasattr(BucksType, 'RestaurantBucks'): - mapping[BucksType.RestaurantBucks] = CommonBucksType.RESTAURANT - if hasattr(BucksType, 'RecycleBitsBucks'): - mapping[BucksType.RecycleBitsBucks] = CommonBucksType.RECYCLE_BITS - if hasattr(BucksType, 'RecyclePiecesBucks'): - mapping[BucksType.RecyclePiecesBucks] = CommonBucksType.RECYCLE_PIECES - if hasattr(BucksType, 'FamePerkBucks'): - mapping[BucksType.FamePerkBucks] = CommonBucksType.FAME_PERK - if hasattr(BucksType, 'FameQuirkBucks'): - mapping[BucksType.FameQuirkBucks] = CommonBucksType.FAME_QUIRK - if hasattr(BucksType, 'WitchPerkBucks'): - mapping[BucksType.WitchPerkBucks] = CommonBucksType.WITCH_PERK - if hasattr(BucksType, 'InfluenceBuck'): - mapping[BucksType.InfluenceBuck] = CommonBucksType.INFLUENCE - if hasattr(BucksType, 'GalacticCredits'): - mapping[BucksType.GalacticCredits] = CommonBucksType.GALACTIC_CREDIT - if hasattr(BucksType, 'WerewolfAbilityBucks'): - mapping[BucksType.WerewolfAbilityBucks] = CommonBucksType.WEREWOLF_ABILITY - if hasattr(BucksType, 'WerewolfQuestAbilityBucks'): - mapping[BucksType.WerewolfQuestAbilityBucks] = CommonBucksType.WEREWOLF_ABILITY_QUEST - return mapping.get(value, value) - - @staticmethod - def convert_to_localized_string_id(value: 'CommonBucksType') -> Union[int, str]: - """convert_to_localized_string_id(value) - - Convert a CommonBucksType into a Localized String identifier. - - :param value: An instance of a CommonBucksType - :type value: CommonBucksType - :return: The specified CommonBucksType translated to a localized string identifier. If no localized string id is found, the name property of the value will be used instead. - :rtype: Union[int, str] - """ - display_name_mapping = { - # CommonBucksType.RETAIL: 0, - # CommonBucksType.VAMPIRE_POWER: 0, - # CommonBucksType.VAMPIRE_WEAKNESS: 0, - # CommonBucksType.VET: 0, - # CommonBucksType.CLUB: 0, - # CommonBucksType.RESTAURANT: 0, - # CommonBucksType.RECYCLE_BITS: 0, - # CommonBucksType.RECYCLE_PIECES: 0, - # CommonBucksType.FAME_PERK: 0, - # CommonBucksType.FAME_QUIRK: 0, - # CommonBucksType.WITCH_PERK: 0, - # CommonBucksType.INFLUENCE: 0, - # CommonBucksType.GALACTIC_CREDIT: 0, - # CommonBucksType.WEREWOLF_ABILITY: 0, - # CommonBucksType.WEREWOLF_ABILITY_QUEST: 0, - } - if isinstance(value, int) and not isinstance(value, CommonBucksType): - value = CommonBucksType.convert_from_vanilla(value) - return display_name_mapping.get(value, value.name if hasattr(value, 'name') else str(value)) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_business_advertising_type.py b/Scripts/s4ap/sims4communitylib/enums/common_business_advertising_type.py deleted file mode 100644 index 037c3d3..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_business_advertising_type.py +++ /dev/null @@ -1,141 +0,0 @@ -""" -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 -""" -from typing import Iterator, Tuple, Union - -from business.business_enums import BusinessAdvertisingType -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonBusinessAdvertisingType(CommonInt): - """Advertising types for businesses.""" - INVALID: 'CommonBusinessAdvertisingType' = ... - BUSINESS_NONE: 'CommonBusinessAdvertisingType' = ... - BUSINESS_RADIO: 'CommonBusinessAdvertisingType' = ... - RETAIL_TV_LONG: 'CommonBusinessAdvertisingType' = ... - RETAIL_TV_SHORT: 'CommonBusinessAdvertisingType' = ... - RETAIL_WEB_LONG: 'CommonBusinessAdvertisingType' = ... - RETAIL_WEB_SHORT: 'CommonBusinessAdvertisingType' = ... - BUSINESS_WEB: 'CommonBusinessAdvertisingType' = ... - BUSINESS_NEWSPAPER: 'CommonBusinessAdvertisingType' = ... - BUSINESS_TV: 'CommonBusinessAdvertisingType' = ... - - @classmethod - def get_all(cls, exclude_values: Iterator['CommonBusinessAdvertisingType'] = None) -> Tuple['CommonBusinessAdvertisingType']: - """get_all(exclude_values=None) - - Get a collection of all values. - - :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonBusinessAdvertisingType], optional - :return: A collection of all values. - :rtype: Tuple[CommonBusinessAdvertisingType] - """ - if exclude_values is None: - exclude_values = (cls.INVALID,) - # noinspection PyTypeChecker - value_list: Tuple[CommonBusinessAdvertisingType, ...] = tuple([value for value in cls.values if value not in exclude_values]) - return value_list - - @classmethod - def get_all_names(cls, exclude_values: Iterator['CommonBusinessAdvertisingType'] = None) -> Tuple[str]: - """get_all_names(exclude_values=None) - - Retrieve a collection of the names of all values. - - :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonBusinessAdvertisingType], optional - :return: A collection of the names of all values. - :rtype: Tuple[str] - """ - name_list: Tuple[str] = tuple([value.name for value in cls.get_all(exclude_values=exclude_values)]) - return name_list - - @classmethod - def get_comma_separated_names_string(cls, exclude_values: Iterator['CommonBusinessAdvertisingType'] = None) -> str: - """get_comma_separated_names_string(exclude_values=None) - - Create a string containing all names of all values, separated by a comma. - - :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonBusinessAdvertisingType], optional - :return: A string containing all names of all values, separated by a comma. - :rtype: str - """ - return ', '.join(cls.get_all_names(exclude_values=exclude_values)) - - @staticmethod - def convert_to_vanilla(value: 'CommonBusinessAdvertisingType') -> BusinessAdvertisingType: - """convert_to_vanilla(value) - - Convert a value into the vanilla BusinessAdvertisingType enum. - - :param value: An instance of CommonBusinessAdvertisingType - :type value: CommonBusinessAdvertisingType - :return: The specified value translated to BusinessAdvertisingType or INVALID if the value could not be translated. - :rtype: BusinessAdvertisingType - """ - if value is None or value == CommonBusinessAdvertisingType.INVALID: - return BusinessAdvertisingType.INVALID - if isinstance(value, BusinessAdvertisingType): - return value - mapping = dict() - if hasattr(BusinessAdvertisingType, 'Business_None'): - mapping[CommonBusinessAdvertisingType.BUSINESS_NONE] = BusinessAdvertisingType.Business_None - if hasattr(BusinessAdvertisingType, 'Business_Radio'): - mapping[CommonBusinessAdvertisingType.BUSINESS_RADIO] = BusinessAdvertisingType.Business_Radio - if hasattr(BusinessAdvertisingType, 'Retail_TV_Long'): - mapping[CommonBusinessAdvertisingType.RETAIL_TV_LONG] = BusinessAdvertisingType.Retail_TV_Long - if hasattr(BusinessAdvertisingType, 'Retail_TV_Short'): - mapping[CommonBusinessAdvertisingType.RETAIL_TV_SHORT] = BusinessAdvertisingType.Retail_TV_Short - if hasattr(BusinessAdvertisingType, 'Retail_Web_Long'): - mapping[CommonBusinessAdvertisingType.RETAIL_WEB_LONG] = BusinessAdvertisingType.Retail_Web_Long - if hasattr(BusinessAdvertisingType, 'Retail_Web_Short'): - mapping[CommonBusinessAdvertisingType.RETAIL_WEB_SHORT] = BusinessAdvertisingType.Retail_Web_Short - if hasattr(BusinessAdvertisingType, 'Business_Web'): - mapping[CommonBusinessAdvertisingType.BUSINESS_WEB] = BusinessAdvertisingType.Business_Web - if hasattr(BusinessAdvertisingType, 'Business_Newspaper'): - mapping[CommonBusinessAdvertisingType.BUSINESS_NEWSPAPER] = BusinessAdvertisingType.Business_Newspaper - if hasattr(BusinessAdvertisingType, 'Business_TV'): - mapping[CommonBusinessAdvertisingType.BUSINESS_TV] = BusinessAdvertisingType.Business_TV - return mapping.get(value, BusinessAdvertisingType.INVALID) - - @staticmethod - def convert_from_vanilla(value: Union[int, BusinessAdvertisingType]) -> 'CommonBusinessAdvertisingType': - """convert_from_vanilla(value) - - Convert a value into a CommonBusinessAdvertisingType enum. - - :param value: An instance of BusinessAdvertisingType - :type value: BusinessAdvertisingType - :return: The specified value translated to CommonBusinessAdvertisingType or INVALID if the value could not be translated. - :rtype: CommonBusinessAdvertisingType - """ - if value is None or value == BusinessAdvertisingType.INVALID: - return CommonBusinessAdvertisingType.INVALID - if isinstance(value, CommonBusinessAdvertisingType): - return value - mapping = dict() - if hasattr(BusinessAdvertisingType, 'Business_None'): - mapping[BusinessAdvertisingType.Business_None] = CommonBusinessAdvertisingType.BUSINESS_NONE - if hasattr(BusinessAdvertisingType, 'Business_Radio'): - mapping[BusinessAdvertisingType.Business_Radio] = CommonBusinessAdvertisingType.BUSINESS_RADIO - if hasattr(BusinessAdvertisingType, 'Retail_TV_Long'): - mapping[BusinessAdvertisingType.Retail_TV_Long] = CommonBusinessAdvertisingType.RETAIL_TV_LONG - if hasattr(BusinessAdvertisingType, 'Retail_TV_Short'): - mapping[BusinessAdvertisingType.Retail_TV_Short] = CommonBusinessAdvertisingType.RETAIL_TV_SHORT - if hasattr(BusinessAdvertisingType, 'Retail_Web_Long'): - mapping[BusinessAdvertisingType.Retail_Web_Long] = CommonBusinessAdvertisingType.RETAIL_WEB_LONG - if hasattr(BusinessAdvertisingType, 'Retail_Web_Short'): - mapping[BusinessAdvertisingType.Retail_Web_Short] = CommonBusinessAdvertisingType.RETAIL_WEB_SHORT - if hasattr(BusinessAdvertisingType, 'Business_Web'): - mapping[BusinessAdvertisingType.Business_Web] = CommonBusinessAdvertisingType.BUSINESS_WEB - if hasattr(BusinessAdvertisingType, 'Business_Newspaper'): - mapping[BusinessAdvertisingType.Business_Newspaper] = CommonBusinessAdvertisingType.BUSINESS_NEWSPAPER - if hasattr(BusinessAdvertisingType, 'Business_TV'): - mapping[BusinessAdvertisingType.Business_TV] = CommonBusinessAdvertisingType.BUSINESS_TV - return mapping.get(value, CommonBusinessAdvertisingType.INVALID) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_business_customer_star_rating_type.py b/Scripts/s4ap/sims4communitylib/enums/common_business_customer_star_rating_type.py deleted file mode 100644 index ba0522f..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_business_customer_star_rating_type.py +++ /dev/null @@ -1,148 +0,0 @@ -""" -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 -""" -from typing import Iterator, Tuple, Union - -from business.business_enums import BusinessCustomerStarRatingBuffBuckets -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonBusinessCustomerStarRatingType(CommonInt): - """Customer star rating types""" - INVALID: 'CommonBusinessCustomerStarRatingType' = ... - SERVICE: 'CommonBusinessCustomerStarRatingType' = ... - AMBIANCE: 'CommonBusinessCustomerStarRatingType' = ... - FOOD_QUALITY: 'CommonBusinessCustomerStarRatingType' = ... - FOOD_VALUE: 'CommonBusinessCustomerStarRatingType' = ... - PERSONAL_TOUCH: 'CommonBusinessCustomerStarRatingType' = ... - WAIT_TIME: 'CommonBusinessCustomerStarRatingType' = ... - MISC: 'CommonBusinessCustomerStarRatingType' = ... - STRESS_LEVEL: 'CommonBusinessCustomerStarRatingType' = ... - SERVICE_VALUE: 'CommonBusinessCustomerStarRatingType' = ... - SERVICE_QUALITY: 'CommonBusinessCustomerStarRatingType' = ... - - @classmethod - def get_all(cls, exclude_values: Iterator['CommonBusinessCustomerStarRatingType'] = None) -> Tuple['CommonBusinessCustomerStarRatingType']: - """get_all(exclude_values=None) - - Get a collection of all values. - - :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonBusinessCustomerStarRatingType], optional - :return: A collection of all values. - :rtype: Tuple[CommonBusinessCustomerStarRatingType] - """ - if exclude_values is None: - exclude_values = (cls.INVALID,) - # noinspection PyTypeChecker - value_list: Tuple[CommonBusinessCustomerStarRatingType, ...] = tuple([value for value in cls.values if value not in exclude_values]) - return value_list - - @classmethod - def get_all_names(cls, exclude_values: Iterator['CommonBusinessCustomerStarRatingType'] = None) -> Tuple[str]: - """get_all_names(exclude_values=None) - - Retrieve a collection of the names of all values. - - :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonBusinessCustomerStarRatingType], optional - :return: A collection of the names of all values. - :rtype: Tuple[str] - """ - name_list: Tuple[str] = tuple([value.name for value in cls.get_all(exclude_values=exclude_values)]) - return name_list - - @classmethod - def get_comma_separated_names_string(cls, exclude_values: Iterator['CommonBusinessCustomerStarRatingType'] = None) -> str: - """get_comma_separated_names_string(exclude_values=None) - - Create a string containing all names of all values, separated by a comma. - - :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonBusinessCustomerStarRatingType], optional - :return: A string containing all names of all values, separated by a comma. - :rtype: str - """ - return ', '.join(cls.get_all_names(exclude_values=exclude_values)) - - @staticmethod - def convert_to_vanilla(value: 'CommonBusinessCustomerStarRatingType') -> BusinessCustomerStarRatingBuffBuckets: - """convert_to_vanilla(value) - - Convert a value into the vanilla BusinessCustomerStarRatingBuffBuckets enum. - - :param value: An instance of CommonBusinessCustomerStarRatingType - :type value: CommonBusinessCustomerStarRatingType - :return: The specified value translated to BusinessCustomerStarRatingBuffBuckets or INVALID if the value could not be translated. - :rtype: BusinessCustomerStarRatingBuffBuckets - """ - if value is None or value == CommonBusinessCustomerStarRatingType.INVALID: - return BusinessCustomerStarRatingBuffBuckets.INVALID - if isinstance(value, BusinessCustomerStarRatingBuffBuckets): - return value - mapping = dict() - if hasattr(BusinessCustomerStarRatingBuffBuckets, 'SERVICE'): - mapping[CommonBusinessCustomerStarRatingType.SERVICE] = BusinessCustomerStarRatingBuffBuckets.SERVICE - if hasattr(BusinessCustomerStarRatingBuffBuckets, 'AMBIANCE'): - mapping[CommonBusinessCustomerStarRatingType.AMBIANCE] = BusinessCustomerStarRatingBuffBuckets.AMBIANCE - if hasattr(BusinessCustomerStarRatingBuffBuckets, 'FOOD_QUALITY'): - mapping[CommonBusinessCustomerStarRatingType.FOOD_QUALITY] = BusinessCustomerStarRatingBuffBuckets.FOOD_QUALITY - if hasattr(BusinessCustomerStarRatingBuffBuckets, 'FOOD_VALUE'): - mapping[CommonBusinessCustomerStarRatingType.FOOD_VALUE] = BusinessCustomerStarRatingBuffBuckets.FOOD_VALUE - if hasattr(BusinessCustomerStarRatingBuffBuckets, 'PERSONAL_TOUCH'): - mapping[CommonBusinessCustomerStarRatingType.PERSONAL_TOUCH] = BusinessCustomerStarRatingBuffBuckets.PERSONAL_TOUCH - if hasattr(BusinessCustomerStarRatingBuffBuckets, 'WAIT_TIME'): - mapping[CommonBusinessCustomerStarRatingType.WAIT_TIME] = BusinessCustomerStarRatingBuffBuckets.WAIT_TIME - if hasattr(BusinessCustomerStarRatingBuffBuckets, 'MISC'): - mapping[CommonBusinessCustomerStarRatingType.MISC] = BusinessCustomerStarRatingBuffBuckets.MISC - if hasattr(BusinessCustomerStarRatingBuffBuckets, 'STRESS_LEVEL'): - mapping[CommonBusinessCustomerStarRatingType.STRESS_LEVEL] = BusinessCustomerStarRatingBuffBuckets.STRESS_LEVEL - if hasattr(BusinessCustomerStarRatingBuffBuckets, 'SERVICE_VALUE'): - mapping[CommonBusinessCustomerStarRatingType.SERVICE_VALUE] = BusinessCustomerStarRatingBuffBuckets.SERVICE_VALUE - if hasattr(BusinessCustomerStarRatingBuffBuckets, 'SERVICE_QUALITY'): - mapping[CommonBusinessCustomerStarRatingType.SERVICE_QUALITY] = BusinessCustomerStarRatingBuffBuckets.SERVICE_QUALITY - return mapping.get(value, BusinessCustomerStarRatingBuffBuckets.INVALID) - - @staticmethod - def convert_from_vanilla(value: Union[int, BusinessCustomerStarRatingBuffBuckets]) -> 'CommonBusinessCustomerStarRatingType': - """convert_from_vanilla(value) - - Convert a value into a CommonBusinessCustomerStarRatingType enum. - - :param value: An instance of BusinessCustomerStarRatingBuffBuckets - :type value: BusinessCustomerStarRatingBuffBuckets - :return: The specified value translated to CommonBusinessCustomerStarRatingType or INVALID if the value could not be translated. - :rtype: CommonBusinessCustomerStarRatingType - """ - if value is None or value == BusinessCustomerStarRatingBuffBuckets.INVALID: - return CommonBusinessCustomerStarRatingType.INVALID - if isinstance(value, CommonBusinessCustomerStarRatingType): - return value - mapping = dict() - if hasattr(BusinessCustomerStarRatingBuffBuckets, 'SERVICE'): - mapping[BusinessCustomerStarRatingBuffBuckets.SERVICE] = CommonBusinessCustomerStarRatingType.SERVICE - if hasattr(BusinessCustomerStarRatingBuffBuckets, 'AMBIANCE'): - mapping[BusinessCustomerStarRatingBuffBuckets.AMBIANCE] = CommonBusinessCustomerStarRatingType.AMBIANCE - if hasattr(BusinessCustomerStarRatingBuffBuckets, 'FOOD_QUALITY'): - mapping[BusinessCustomerStarRatingBuffBuckets.FOOD_QUALITY] = CommonBusinessCustomerStarRatingType.FOOD_QUALITY - if hasattr(BusinessCustomerStarRatingBuffBuckets, 'FOOD_VALUE'): - mapping[BusinessCustomerStarRatingBuffBuckets.FOOD_VALUE] = CommonBusinessCustomerStarRatingType.FOOD_VALUE - if hasattr(BusinessCustomerStarRatingBuffBuckets, 'PERSONAL_TOUCH'): - mapping[BusinessCustomerStarRatingBuffBuckets.PERSONAL_TOUCH] = CommonBusinessCustomerStarRatingType.PERSONAL_TOUCH - if hasattr(BusinessCustomerStarRatingBuffBuckets, 'WAIT_TIME'): - mapping[BusinessCustomerStarRatingBuffBuckets.WAIT_TIME] = CommonBusinessCustomerStarRatingType.WAIT_TIME - if hasattr(BusinessCustomerStarRatingBuffBuckets, 'MISC'): - mapping[BusinessCustomerStarRatingBuffBuckets.MISC] = CommonBusinessCustomerStarRatingType.MISC - if hasattr(BusinessCustomerStarRatingBuffBuckets, 'STRESS_LEVEL'): - mapping[BusinessCustomerStarRatingBuffBuckets.STRESS_LEVEL] = CommonBusinessCustomerStarRatingType.STRESS_LEVEL - if hasattr(BusinessCustomerStarRatingBuffBuckets, 'SERVICE_VALUE'): - mapping[BusinessCustomerStarRatingBuffBuckets.SERVICE_VALUE] = CommonBusinessCustomerStarRatingType.SERVICE_VALUE - if hasattr(BusinessCustomerStarRatingBuffBuckets, 'SERVICE_QUALITY'): - mapping[BusinessCustomerStarRatingBuffBuckets.SERVICE_QUALITY] = CommonBusinessCustomerStarRatingType.SERVICE_QUALITY - return mapping.get(value, CommonBusinessCustomerStarRatingType.INVALID) - - diff --git a/Scripts/s4ap/sims4communitylib/enums/common_business_employee_type.py b/Scripts/s4ap/sims4communitylib/enums/common_business_employee_type.py deleted file mode 100644 index d94130f..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_business_employee_type.py +++ /dev/null @@ -1,122 +0,0 @@ -""" -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 -""" -from typing import Iterator, Tuple, Union - -from business.business_enums import BusinessEmployeeType -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonBusinessEmployeeType(CommonInt): - """Employee types of various businesses.""" - INVALID: 'CommonBusinessEmployeeType' = ... - RETAIL: 'CommonBusinessEmployeeType' = ... - RESTAURANT_CHEF: 'CommonBusinessEmployeeType' = ... - RESTAURANT_WAITSTAFF: 'CommonBusinessEmployeeType' = ... - RESTAURANT_HOST: 'CommonBusinessEmployeeType' = ... - VET: 'CommonBusinessEmployeeType' = ... - - @classmethod - def get_all(cls, exclude_values: Iterator['CommonBusinessEmployeeType'] = None) -> Tuple['CommonBusinessEmployeeType']: - """get_all(exclude_values=None) - - Get a collection of all values. - - :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonBusinessEmployeeType], optional - :return: A collection of all values. - :rtype: Tuple[CommonBusinessEmployeeType] - """ - if exclude_values is None: - exclude_values = (cls.INVALID,) - # noinspection PyTypeChecker - value_list: Tuple[CommonBusinessEmployeeType, ...] = tuple([value for value in cls.values if value not in exclude_values]) - return value_list - - @classmethod - def get_all_names(cls, exclude_values: Iterator['CommonBusinessEmployeeType'] = None) -> Tuple[str]: - """get_all_names(exclude_values=None) - - Retrieve a collection of the names of all values. - - :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonBusinessEmployeeType], optional - :return: A collection of the names of all values. - :rtype: Tuple[str] - """ - name_list: Tuple[str] = tuple([value.name for value in cls.get_all(exclude_values=exclude_values)]) - return name_list - - @classmethod - def get_comma_separated_names_string(cls, exclude_values: Iterator['CommonBusinessEmployeeType'] = None) -> str: - """get_comma_separated_names_string(exclude_values=None) - - Create a string containing all names of all values, separated by a comma. - - :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonBusinessEmployeeType], optional - :return: A string containing all names of all values, separated by a comma. - :rtype: str - """ - return ', '.join(cls.get_all_names(exclude_values=exclude_values)) - - @staticmethod - def convert_to_vanilla(value: 'CommonBusinessEmployeeType') -> BusinessEmployeeType: - """convert_to_vanilla(value) - - Convert a value into the vanilla BusinessEmployeeType enum. - - :param value: An instance of CommonBusinessEmployeeType - :type value: CommonBusinessEmployeeType - :return: The specified value translated to BusinessEmployeeType or INVALID if the value could not be translated. - :rtype: BusinessEmployeeType - """ - if value is None or value == CommonBusinessEmployeeType.INVALID: - return BusinessEmployeeType.INVALID - if isinstance(value, BusinessEmployeeType): - return value - mapping = dict() - if hasattr(BusinessEmployeeType, 'RETAIL'): - mapping[CommonBusinessEmployeeType.RETAIL] = BusinessEmployeeType.RETAIL - if hasattr(BusinessEmployeeType, 'RESTAURANT_CHEF'): - mapping[CommonBusinessEmployeeType.RESTAURANT_CHEF] = BusinessEmployeeType.RESTAURANT_CHEF - if hasattr(BusinessEmployeeType, 'RESTAURANT_WAITSTAFF'): - mapping[CommonBusinessEmployeeType.RESTAURANT_WAITSTAFF] = BusinessEmployeeType.RESTAURANT_WAITSTAFF - if hasattr(BusinessEmployeeType, 'RESTAURANT_HOST'): - mapping[CommonBusinessEmployeeType.RESTAURANT_HOST] = BusinessEmployeeType.RESTAURANT_HOST - if hasattr(BusinessEmployeeType, 'VET'): - mapping[CommonBusinessEmployeeType.VET] = BusinessEmployeeType.VET - return mapping.get(value, BusinessEmployeeType.INVALID) - - @staticmethod - def convert_from_vanilla(value: Union[int, BusinessEmployeeType]) -> 'CommonBusinessEmployeeType': - """convert_from_vanilla(value) - - Convert a value into a CommonBusinessEmployeeType enum. - - :param value: An instance of BusinessEmployeeType - :type value: BusinessEmployeeType - :return: The specified value translated to CommonBusinessEmployeeType or INVALID if the value could not be translated. - :rtype: CommonBusinessEmployeeType - """ - if value is None or value == BusinessEmployeeType.INVALID: - return CommonBusinessEmployeeType.INVALID - if isinstance(value, CommonBusinessEmployeeType): - return value - mapping = dict() - if hasattr(BusinessEmployeeType, 'RETAIL'): - mapping[BusinessEmployeeType.RETAIL] = CommonBusinessEmployeeType.RETAIL - if hasattr(BusinessEmployeeType, 'RESTAURANT_CHEF'): - mapping[BusinessEmployeeType.RESTAURANT_CHEF] = CommonBusinessEmployeeType.RESTAURANT_CHEF - if hasattr(BusinessEmployeeType, 'RESTAURANT_WAITSTAFF'): - mapping[BusinessEmployeeType.RESTAURANT_WAITSTAFF] = CommonBusinessEmployeeType.RESTAURANT_WAITSTAFF - if hasattr(BusinessEmployeeType, 'RESTAURANT_HOST'): - mapping[BusinessEmployeeType.RESTAURANT_HOST] = CommonBusinessEmployeeType.RESTAURANT_HOST - if hasattr(BusinessEmployeeType, 'VET'): - mapping[BusinessEmployeeType.VET] = CommonBusinessEmployeeType.VET - return mapping.get(value, CommonBusinessEmployeeType.INVALID) - diff --git a/Scripts/s4ap/sims4communitylib/enums/common_business_quality_type.py b/Scripts/s4ap/sims4communitylib/enums/common_business_quality_type.py deleted file mode 100644 index 3f950ff..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_business_quality_type.py +++ /dev/null @@ -1,111 +0,0 @@ -""" -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 -""" -from typing import Iterator, Tuple, Union - -from business.business_enums import BusinessQualityType -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonBusinessQualityType(CommonInt): - """Different quality types of a Business.""" - INVALID: 'CommonBusinessQualityType' = ... - LOW: 'CommonBusinessQualityType' = ... - MEDIUM: 'CommonBusinessQualityType' = ... - HIGH: 'CommonBusinessQualityType' = ... - - @classmethod - def get_all(cls, exclude_values: Iterator['CommonBusinessQualityType'] = None) -> Tuple['CommonBusinessQualityType']: - """get_all(exclude_values=None) - - Get a collection of all values. - - :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonBusinessQualityType], optional - :return: A collection of all values. - :rtype: Tuple[CommonBusinessQualityType] - """ - if exclude_values is None: - exclude_values = (cls.INVALID,) - # noinspection PyTypeChecker - value_list: Tuple[CommonBusinessQualityType, ...] = tuple([value for value in cls.values if value not in exclude_values]) - return value_list - - @classmethod - def get_all_names(cls, exclude_values: Iterator['CommonBusinessQualityType'] = None) -> Tuple[str]: - """get_all_names(exclude_values=None) - - Retrieve a collection of the names of all values. - - :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonBusinessQualityType], optional - :return: A collection of the names of all values. - :rtype: Tuple[str] - """ - name_list: Tuple[str] = tuple([value.name for value in cls.get_all(exclude_values=exclude_values)]) - return name_list - - @classmethod - def get_comma_separated_names_string(cls, exclude_values: Iterator['CommonBusinessQualityType'] = None) -> str: - """get_comma_separated_names_string(exclude_values=None) - - Create a string containing all names of all values, separated by a comma. - - :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonBusinessQualityType], optional - :return: A string containing all names of all values, separated by a comma. - :rtype: str - """ - return ', '.join(cls.get_all_names(exclude_values=exclude_values)) - - @staticmethod - def convert_to_vanilla(value: 'CommonBusinessQualityType') -> BusinessQualityType: - """convert_to_vanilla(value) - - Convert a value into the vanilla BusinessQualityType enum. - - :param value: An instance of CommonBusinessQualityType - :type value: CommonBusinessQualityType - :return: The specified value translated to BusinessQualityType or INVALID if the value could not be translated. - :rtype: BusinessQualityType - """ - if value is None or value == CommonBusinessQualityType.INVALID: - return BusinessQualityType.INVALID - if isinstance(value, BusinessQualityType): - return value - mapping = dict() - if hasattr(BusinessQualityType, 'LOW'): - mapping[CommonBusinessQualityType.LOW] = BusinessQualityType.LOW - if hasattr(BusinessQualityType, 'MEDIUM'): - mapping[CommonBusinessQualityType.MEDIUM] = BusinessQualityType.MEDIUM - if hasattr(BusinessQualityType, 'HIGH'): - mapping[CommonBusinessQualityType.HIGH] = BusinessQualityType.HIGH - return mapping.get(value, BusinessQualityType.INVALID) - - @staticmethod - def convert_from_vanilla(value: Union[int, BusinessQualityType]) -> 'CommonBusinessQualityType': - """convert_from_vanilla(value) - - Convert a value into a CommonBusinessQualityType enum. - - :param value: An instance of BusinessQualityType - :type value: BusinessQualityType - :return: The specified value translated to CommonBusinessQualityType or INVALID if the value could not be translated. - :rtype: CommonBusinessQualityType - """ - if value is None or value == BusinessQualityType.INVALID: - return CommonBusinessQualityType.INVALID - if isinstance(value, CommonBusinessQualityType): - return value - mapping = dict() - if hasattr(BusinessQualityType, 'LOW'): - mapping[BusinessQualityType.LOW] = CommonBusinessQualityType.LOW - if hasattr(BusinessQualityType, 'MEDIUM'): - mapping[BusinessQualityType.MEDIUM] = CommonBusinessQualityType.MEDIUM - if hasattr(BusinessQualityType, 'HIGH'): - mapping[BusinessQualityType.HIGH] = CommonBusinessQualityType.HIGH - return mapping.get(value, CommonBusinessQualityType.INVALID) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_career_ids.py b/Scripts/s4ap/sims4communitylib/enums/common_career_ids.py deleted file mode 100644 index e1cb913..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_career_ids.py +++ /dev/null @@ -1,145 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonCareerId(CommonInt): - """Decimal Identifiers for Careers. - - """ - ACTIVE_ACTOR: 'CommonCareerId' = 189135 - ACTIVE_DOCTOR: 'CommonCareerId' = 107230 - ACTIVE_SCIENTIST: 'CommonCareerId' = 107255 - ACTIVIST: 'CommonCareerId' = 135201 - ASTRONAUT: 'CommonCareerId' = 12893 - ATHLETIC: 'CommonCareerId' = 106458 - BATUU_MISSIONS: 'CommonCareerId' = 231099 - BUSINESS: 'CommonCareerId' = 106460 - CIVIL_DESIGNER: 'CommonCareerId' = 232767 - CONSERVATIONIST: 'CommonCareerId' = 204960 - CORPORATE_WORKER: 'CommonCareerId' = 248315 - COTTAGE_WORLD_VILLAGER_HELP: 'CommonCareerId' = 260893 - CRIMINAL: 'CommonCareerId' = 27927 - CRITIC: 'CommonCareerId' = 136115 - CULINARY: 'CommonCareerId' = 9231 - DETECTIVE: 'CommonCareerId' = 106132 - EDUCATION: 'CommonCareerId' = 219591 - ENGINEER: 'CommonCareerId' = 217872 - ENTERTAINER: 'CommonCareerId' = 27929 - FREELANCER_WITH_AGENCY_ARTIST: 'CommonCareerId' = 205686 - FREELANCER_WITH_AGENCY_FASHION_PHOTOGRAPHER: 'CommonCareerId' = 214782 - FREELANCER_WITH_AGENCY_MAKER: 'CommonCareerId' = 232809 - FREELANCER_WITH_AGENCY_NONE: 'CommonCareerId' = 206791 - FREELANCER_WITH_AGENCY_PARANORMAL_INVESTIGATOR: 'CommonCareerId' = 252593 - FREELANCER_WITH_AGENCY_PROGRAMMER: 'CommonCareerId' = 207568 - FREELANCER_WITH_AGENCY_WRITER: 'CommonCareerId' = 207579 - GARDENER: 'CommonCareerId' = 186159 - INTERIOR_DECORATOR: 'CommonCareerId' = 257934 - LAW: 'CommonCareerId' = 223298 - MILITARY: 'CommonCareerId' = 202483 - NPC_ACTOR_CAREER_CAMERA_OPERATOR: 'CommonCareerId' = 196625 - NPC_ACTOR_CAREER_HAIR_AND_MAKEUP_STYLIST: 'CommonCareerId' = 195951 - NPC_ACTOR_CAREER_PRODUCER: 'CommonCareerId' = 196627 - NPC_ACTOR_CAREER_SPECIAL_EFFECTS_OPERATOR: 'CommonCareerId' = 196558 - NPC_ACTOR_CAREER_WARDROBE_STYLIST: 'CommonCareerId' = 195952 - NPC_BUSINESS_RESTAURANT_CHEF: 'CommonCareerId' = 136209 - NPC_BUSINESS_RESTAURANT_CRITIC: 'CommonCareerId' = 139565 - NPC_BUSINESS_RESTAURANT_HOST: 'CommonCareerId' = 136208 - NPC_BUSINESS_RESTAURANT_WAITER: 'CommonCareerId' = 136210 - NPC_BUSINESS_RETAIL_EMPLOYEE: 'CommonCareerId' = 110057 - NPC_BUSINESS_VET_CLINIC_VET: 'CommonCareerId' = 168569 - NPC_CHESTNUT_RIDGE_HORSE_TRAINER: 'CommonCareerId' = 324723 - NPC_CHESTNUT_RIDGE_MYSTERIOUS_RANCHER: 'CommonCareerId' = 324722 - NPC_COTTAGE_WORLD_GARDEN_SHOP_OWNER: 'CommonCareerId' = 260407 - NPC_COTTAGE_WORLD_GROCERY_STORE_DELIVERY: 'CommonCareerId' = 260409 - NPC_COTTAGE_WORLD_GROCERY_STORE_OWNER: 'CommonCareerId' = 260408 - NPC_HIGH_SCHOOL_ACTIVE_TEACHER: 'CommonCareerId' = 296393 - NPC_RANCH_HAND: 'CommonCareerId' = 304769 - NPC_SERVICES_BONEHILDA: 'CommonCareerId' = 256924 - NPC_SERVICES_BUTLER: 'CommonCareerId' = 147718 - NPC_SERVICES_DELIVERIES_FOOD: 'CommonCareerId' = 262368 - NPC_SERVICES_DELIVERIES_PIZZA: 'CommonCareerId' = 110043 - NPC_SERVICES_FIREFIGHTER: 'CommonCareerId' = 237780 - NPC_SERVICES_GARDENER: 'CommonCareerId' = 130529 - NPC_SERVICES_HOME_CHEF: 'CommonCareerId' = 140900 - NPC_SERVICES_MAID: 'CommonCareerId' = 109456 - NPC_SERVICES_MAIL: 'CommonCareerId' = 109457 - NPC_SERVICES_MASSAGE_THERAPIST: 'CommonCareerId' = 119666 - NPC_SERVICES_NANNY: 'CommonCareerId' = 141901 - NPC_SERVICES_REPAIR: 'CommonCareerId' = 129471 - NPC_SPECIAL_ADOPTION_OFFICER: 'CommonCareerId' = 175923 - NPC_SPECIAL_ECO_INSPECTOR: 'CommonCareerId' = 242362 - NPC_SPECIAL_FATHER_WINTER: 'CommonCareerId' = 183371 - NPC_SPECIAL_GRIM_REAPER: 'CommonCareerId' = 110326 - NPC_SPECIAL_GYM_TRAINER: 'CommonCareerId' = 112014 - NPC_SPECIAL_MASTER_FISHER: 'CommonCareerId' = 112090 - NPC_SPECIAL_RANGER: 'CommonCareerId' = 112104 - NPC_SPECIAL_TRAGIC_CLOWN: 'CommonCareerId' = 139889 - NPC_SPECIAL_YOGA_INSTRUCTOR: 'CommonCareerId' = 118612 - NPC_STRANGER_VILLE_ALIEN_POLLINATOR: 'CommonCareerId' = 115639 - NPC_STRANGER_VILLE_OGA: 'CommonCareerId' = 205712 - NPC_STRANGER_VILLE_SCIENTIST: 'CommonCareerId' = 205705 - NPC_UNIVERSITY_PROFESSOR_ARTS: 'CommonCareerId' = 224750 - NPC_UNIVERSITY_PROFESSOR_SCIENCE: 'CommonCareerId' = 224751 - NPC_VENUE_BARISTA: 'CommonCareerId' = 122270 - NPC_VENUE_BARTENDER: 'CommonCareerId' = 109458 - NPC_VENUE_BARTENDER_COMPANY: 'CommonCareerId' = 130590 - NPC_VENUE_BAR_REGULAR: 'CommonCareerId' = 122658 - NPC_VENUE_COMMUNITY_GARDENER: 'CommonCareerId' = 112083 - NPC_VENUE_CURIO_SHOP_OWNER: 'CommonCareerId' = 206662 - NPC_VENUE_DJ: 'CommonCareerId' = 122818 - NPC_VENUE_LANDLORD: 'CommonCareerId' = 143653 - NPC_VENUE_LIBRARIAN: 'CommonCareerId' = 112015 - NPC_VENUE_MASSAGE_THERAPIST: 'CommonCareerId' = 118550 - NPC_VENUE_MAYOR: 'CommonCareerId' = 260410 - NPC_VENUE_PAPARAZZI: 'CommonCareerId' = 197295 - NPC_VENUE_PUB_OWNER: 'CommonCareerId' = 260411 - NPC_VENUE_REFLEXOLOGIST: 'CommonCareerId' = 119506 - NPC_VENUE_STALL_VENDOR: 'CommonCareerId' = 143285 - NPC_VENUE_STALL_VENDOR_WEDDING_FLOWER: 'CommonCareerId' = 276665 - NPC_WOLF_TOWN_BARTENDER: 'CommonCareerId' = 294303 - ODD_JOB: 'CommonCareerId' = 207004 - PAINTER: 'CommonCareerId' = 27930 - PART_TIME_BABY_SITTER_ADULT: 'CommonCareerId' = 208723 - PART_TIME_BABY_SITTER_TEEN: 'CommonCareerId' = 35221 - PART_TIME_BARISTA_ADULT: 'CommonCareerId' = 208737 - PART_TIME_BARISTA_TEEN: 'CommonCareerId' = 35220 - PART_TIME_DIVER: 'CommonCareerId' = 208405 - PART_TIME_FAST_FOOD_ADULT: 'CommonCareerId' = 208761 - PART_TIME_FAST_FOOD_TEEN: 'CommonCareerId' = 35157 - PART_TIME_FISHERMAN: 'CommonCareerId' = 207607 - PART_TIME_LIFEGUARD_ADULT: 'CommonCareerId' = 205662 - PART_TIME_LIFEGUARD_TEEN: 'CommonCareerId' = 208881 - PART_TIME_MANUAL_LABOR_ADULT: 'CommonCareerId' = 208779 - PART_TIME_MANUAL_LABOR_TEEN: 'CommonCareerId' = 35218 - PART_TIME_RETAIL_ADULT: 'CommonCareerId' = 208874 - PART_TIME_RETAIL_TEEN: 'CommonCareerId' = 35219 - PART_TIME_SIMSFLUENCER_SIDE_HUSTLE_ADULT: 'CommonCareerId' = 277662 - PART_TIME_SIMSFLUENCER_SIDE_HUSTLE_TEEN: 'CommonCareerId' = 277663 - PART_TIME_STREAMER_SIDE_HUSTLE_ADULT: 'CommonCareerId' = 273912 - PART_TIME_STREAMER_SIDE_HUSTLE_TEEN: 'CommonCareerId' = 273911 - SCHOOL_CHILD: 'CommonCareerId' = 12895 - SCHOOL_TEEN: 'CommonCareerId' = 9541 - SECRET_AGENT: 'CommonCareerId' = 27931 - SOCIAL_MEDIA: 'CommonCareerId' = 135363 - STYLE_INFLUENCER: 'CommonCareerId' = 193202 - TECH_GURU: 'CommonCareerId' = 27932 - UNIVERSITY: 'CommonCareerId' = 223698 - UNIVERSITY_COURSE_SLOT_A: 'CommonCareerId' = 209979 - UNIVERSITY_COURSE_SLOT_B: 'CommonCareerId' = 209984 - UNIVERSITY_COURSE_SLOT_C: 'CommonCareerId' = 209988 - UNIVERSITY_COURSE_SLOT_D: 'CommonCareerId' = 209989 - VOLUNTEER_DRAMA_CLUB: 'CommonCareerId' = 199274 - VOLUNTEER_E_SPORTS: 'CommonCareerId' = 217092 - VOLUNTEER_HIGH_SCHOOL_TEAM_CHEER_TEAM: 'CommonCareerId' = 276604 - VOLUNTEER_HIGH_SCHOOL_TEAM_CHESS_TEAM: 'CommonCareerId' = 276602 - VOLUNTEER_HIGH_SCHOOL_TEAM_COMPUTER_TEAM: 'CommonCareerId' = 276603 - VOLUNTEER_HIGH_SCHOOL_TEAM_FOOTBALL_TEAM: 'CommonCareerId' = 276605 - VOLUNTEER_SCOUTING: 'CommonCareerId' = 186513 - VOLUNTEER_SOCCER_TEAM: 'CommonCareerId' = 220913 - WRITER: 'CommonCareerId' = 27933 diff --git a/Scripts/s4ap/sims4communitylib/enums/common_character_restrictions.py b/Scripts/s4ap/sims4communitylib/enums/common_character_restrictions.py deleted file mode 100644 index a9b4449..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_character_restrictions.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonCharacterRestriction(CommonInt): - """Character restrictions for use in text input fields. - - """ - NONE: 'CommonCharacterRestriction' = ... - NUMBERS_ONLY: 'CommonCharacterRestriction' = ... diff --git a/Scripts/s4ap/sims4communitylib/enums/common_civic_policy_status_type.py b/Scripts/s4ap/sims4communitylib/enums/common_civic_policy_status_type.py deleted file mode 100644 index ebf0453..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_civic_policy_status_type.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonCivicPolicyStatusType(CommonInt): - """ The status a Civic Policy may have in a Zone or Venue. """ - ENACTED = ... - BALLOTED = ... - UP_FOR_REPEAL = ... - DORMANT = ... diff --git a/Scripts/s4ap/sims4communitylib/enums/common_civic_policy_type.py b/Scripts/s4ap/sims4communitylib/enums/common_civic_policy_type.py deleted file mode 100644 index 8ad717e..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_civic_policy_type.py +++ /dev/null @@ -1,14 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonCivicPolicyType(CommonInt): - """ The types of Civic Policies. """ - STREET = ... - VENUE = ... diff --git a/Scripts/s4ap/sims4communitylib/enums/common_cloud_type.py b/Scripts/s4ap/sims4communitylib/enums/common_cloud_type.py deleted file mode 100644 index 8737c64..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_cloud_type.py +++ /dev/null @@ -1,116 +0,0 @@ -""" -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 -""" -from typing import Tuple, Union, Iterator - -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - -# noinspection PyBroadException -try: - from weather.weather_enums import CloudType -except: - class CloudType(CommonInt): - """Mock class.""" - PARTLY_CLOUDY = 2000 - CLEAR = 2001 - LIGHT_RAINCLOUDS = 2002 - DARK_RAINCLOUDS = 2003 - # noinspection SpellCheckingInspection - LIGHT_SNOWCLOUDS = 2004 - # noinspection SpellCheckingInspection - DARK_SNOWCLOUDS = 2005 - CLOUDY = 2006 - HEATWAVE = 2007 - STRANGE = 2008 - VERY_STRANGE = 2009 - SKYBOX_INDUSTRIAL = 2010 - - -class CommonCloudType(CommonInt): - """Identifiers for cloud types.""" - PARTLY_CLOUDY: 'CommonCloudType' = ... - CLEAR: 'CommonCloudType' = ... - LIGHT_RAIN_CLOUDS: 'CommonCloudType' = ... - DARK_RAIN_CLOUDS: 'CommonCloudType' = ... - LIGHT_SNOW_CLOUDS: 'CommonCloudType' = ... - DARK_SNOW_CLOUDS: 'CommonCloudType' = ... - CLOUDY: 'CommonCloudType' = ... - HEATWAVE: 'CommonCloudType' = ... - STRANGE: 'CommonCloudType' = ... - VERY_STRANGE: 'CommonCloudType' = ... - SKY_BOX_INDUSTRIAL: 'CommonCloudType' = ... - - @classmethod - def get_all(cls, exclude_values: Iterator['CommonCloudType'] = ()) -> Tuple['CommonCloudType']: - """get_all(exclude_values=()) - - Get a collection of all values. - - :param exclude_values: These values will be excluded. Default is an empty collection. - :type exclude_values: Iterator[CommonCloudType], optional - :return: A collection of all values. - :rtype: Tuple[CommonCloudType] - """ - # noinspection PyTypeChecker - value_list: Tuple[CommonCloudType, ...] = tuple([value for value in cls.values if value not in exclude_values]) - return value_list - - @staticmethod - def convert_to_vanilla(value: 'CommonCloudType') -> Union[CloudType, None]: - """convert_to_vanilla(value) - - Convert a CommonCloudType into the vanilla CloudType enum. - - :param value: An instance of CommonCloudType - :type value: CommonCloudType - :return: The specified CommonCloudType translated to CloudType or None if a vanilla CloudType is not found. - :rtype: Union[CloudType, None] - """ - if isinstance(value, CloudType): - return value - mapping = { - CommonCloudType.PARTLY_CLOUDY: CloudType.PARTLY_CLOUDY, - CommonCloudType.CLEAR: CloudType.CLEAR, - CommonCloudType.LIGHT_RAIN_CLOUDS: CloudType.LIGHT_RAINCLOUDS, - CommonCloudType.DARK_RAIN_CLOUDS: CloudType.DARK_RAINCLOUDS, - CommonCloudType.LIGHT_SNOW_CLOUDS: CloudType.LIGHT_SNOWCLOUDS, - CommonCloudType.DARK_SNOW_CLOUDS: CloudType.DARK_SNOWCLOUDS, - CommonCloudType.CLOUDY: CloudType.CLOUDY, - CommonCloudType.HEATWAVE: CloudType.HEATWAVE, - CommonCloudType.STRANGE: CloudType.STRANGE, - CommonCloudType.VERY_STRANGE: CloudType.VERY_STRANGE, - CommonCloudType.SKY_BOX_INDUSTRIAL: CloudType.SKYBOX_INDUSTRIAL, - } - return mapping.get(value, value) - - @staticmethod - def convert_from_vanilla(value: CloudType) -> Union['CommonCloudType', None]: - """convert_from_vanilla(value) - - Convert a vanilla CloudType into a CommonCloudType enum. - - :param value: An instance of CommonCloudType - :type value: CommonCloudType - :return: The specified CloudType translated to CloudType or None if the value could not be translated. - :rtype: Union[CloudType, None] - """ - if isinstance(value, CommonCloudType): - return value - mapping = { - CloudType.PARTLY_CLOUDY: CommonCloudType.PARTLY_CLOUDY, - CloudType.CLEAR: CommonCloudType.CLEAR, - CloudType.LIGHT_RAINCLOUDS: CommonCloudType.LIGHT_RAIN_CLOUDS, - CloudType.DARK_RAINCLOUDS: CommonCloudType.DARK_RAIN_CLOUDS, - CloudType.LIGHT_SNOWCLOUDS: CommonCloudType.LIGHT_SNOW_CLOUDS, - CloudType.DARK_SNOWCLOUDS: CommonCloudType.DARK_SNOW_CLOUDS, - CloudType.CLOUDY: CommonCloudType.CLOUDY, - CloudType.HEATWAVE: CommonCloudType.HEATWAVE, - CloudType.STRANGE: CommonCloudType.STRANGE, - CloudType.VERY_STRANGE: CommonCloudType.VERY_STRANGE, - CloudType.SKYBOX_INDUSTRIAL: CommonCloudType.SKY_BOX_INDUSTRIAL, - } - return mapping.get(value, value) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_combined_species.py b/Scripts/s4ap/sims4communitylib/enums/common_combined_species.py deleted file mode 100644 index 0ff5439..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_combined_species.py +++ /dev/null @@ -1,96 +0,0 @@ -""" -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 -""" -from typing import Tuple - -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonCombinedSpecies(CommonInt): - """Various combined species types to reduce code ugliness""" - NONE: 'CommonCombinedSpecies' = ... - HUMAN: 'CommonCombinedSpecies' = ... # Human - ANIMAL: 'CommonCombinedSpecies' = ... # Large Dog, Small Dog, Cat, Fox - PET: 'CommonCombinedSpecies' = ... # Large Dog, Small Dog, Cat - NON_PET: 'CommonCombinedSpecies' = ... # Fox - DOG: 'CommonCombinedSpecies' = ... # Large Dog, Small Dog - CAT: 'CommonCombinedSpecies' = ... # Cat - FOX: 'CommonCombinedSpecies' = ... # Fox - HORSE: 'CommonCombinedSpecies' = ... # Horse - - @classmethod - def convert_to_signature(cls, combined_species: 'CommonCombinedSpecies') -> str: - """convert_to_signature(combined_species) - - Convert a CommonCombinedSpecies to a unique signature. - - :param combined_species: The value to convert. - :type combined_species: CommonCombinedSpecies - :return: A string signature that uniquely represents the CommonCombinedSpecies or the name of the CommonCombinedSpecies, if no unique signature is found. - :rtype: str - """ - mapping = { - CommonCombinedSpecies.HUMAN: 'Human', - CommonCombinedSpecies.ANIMAL: 'Animal', - CommonCombinedSpecies.PET: 'Pet', - CommonCombinedSpecies.NON_PET: 'Non_Pet', - CommonCombinedSpecies.DOG: 'Dog', - CommonCombinedSpecies.CAT: 'Cat', - CommonCombinedSpecies.FOX: 'Fox', - CommonCombinedSpecies.HORSE: 'Horse', - } - return mapping.get(combined_species, combined_species.name) - - @classmethod - def convert_to_enum_xml(cls, combined_species: 'CommonCombinedSpecies') -> Tuple[str]: - """convert_to_species_xml(combined_species) - - Convert a CommonCombinedSpecies to the xml representations of species. i.e. ((species),) - - :param combined_species: The value to convert. - :type combined_species: CommonCombinedSpecies - :return: A collection of strings that represent the xml associated with the value. - :rtype: Tuple[str] - """ - if combined_species == CommonCombinedSpecies.ANIMAL: - result: Tuple[str, ...] = (*cls.convert_to_enum_xml(CommonCombinedSpecies.DOG), *cls.convert_to_enum_xml(CommonCombinedSpecies.CAT), *cls.convert_to_enum_xml(CommonCombinedSpecies.FOX), *cls.convert_to_enum_xml(CommonCombinedSpecies.HORSE)) - return result - if combined_species == CommonCombinedSpecies.PET: - result: Tuple[str, ...] = (*cls.convert_to_enum_xml(CommonCombinedSpecies.DOG), *cls.convert_to_enum_xml(CommonCombinedSpecies.CAT), *cls.convert_to_enum_xml(CommonCombinedSpecies.HORSE)) - return result - if combined_species == CommonCombinedSpecies.NON_PET: - result: Tuple[str, ...] = (*cls.convert_to_enum_xml(CommonCombinedSpecies.HUMAN),) - return result - - mapping = { - CommonCombinedSpecies.HUMAN: ('HUMAN',), - CommonCombinedSpecies.DOG: ('DOG',), - CommonCombinedSpecies.CAT: ('CAT',), - CommonCombinedSpecies.FOX: ('FOX',), - CommonCombinedSpecies.HORSE: ('HORSE',), - } - return mapping.get(combined_species, tuple()) - - @classmethod - def is_animal(cls, combined_species: 'CommonCombinedSpecies') -> bool: - """is_animal(combined_species) - - Determine if a value represents an animal. - - :param combined_species: The value to check. - :type combined_species: CommonCombinedSpecies - :return: True, if the value represents an Animal. False, if not. - :rtype: bool - """ - return combined_species in ( - CommonCombinedSpecies.ANIMAL, - CommonCombinedSpecies.PET, - CommonCombinedSpecies.DOG, - CommonCombinedSpecies.CAT, - CommonCombinedSpecies.FOX, - CommonCombinedSpecies.HORSE - ) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_currency_modify_reasons.py b/Scripts/s4ap/sims4communitylib/enums/common_currency_modify_reasons.py deleted file mode 100644 index 22f95a3..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_currency_modify_reasons.py +++ /dev/null @@ -1,54 +0,0 @@ -""" -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 -""" -from protocolbuffers import Consts_pb2 -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonCurrencyModifyReason(CommonInt): - """Various reasons for currencies to be modified.""" - # Change reasons - CHEAT: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_MONEY_CHEAT - SPLIT_HOUSEHOLD: 'CommonCurrencyModifyReason' = Consts_pb2.FUNDS_SPLIT_HOUSEHOLD - - # Add reasons - INTERACTION_REWARD: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_INTERACTION_REWARD - EVENT_REWARD: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_EVENET_REWARD - OBJECT_SELL: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_OBJECT_SELL - STRUCTURE_SELL: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_STRUCTURE_SELL - LOT_SELL: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_LOT_SELL - HOUSEHOLD_TRANSFER_GAIN: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_HOUSEHOLD_TRANSFER_GAIN - SIM_POINTS_EXCHANGED: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_SIM_POINTS_EXCHANGED - SIM_WALLET_FUNDED: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_SIM_WALLET_FUNDED - CAREER: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_MONEY_CAREER - ASPIRATION_REWARD: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_MONEY_ASPIRATION_REWARD - ROYALTY: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_MONEY_ROYALTY - FIRE_INSURANCE: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_MONEY_FIREINSURANCE - RETAIL_PROFITS: 'CommonCurrencyModifyReason' = Consts_pb2.FUNDS_RETAIL_PROFITS - RETAIL_TRANSFER_GAIN: 'CommonCurrencyModifyReason' = Consts_pb2.FUNDS_RETAIL_TRANSFER_GAIN - HOLIDAY_LOTTERY: 'CommonCurrencyModifyReason' = Consts_pb2.FUNDS_HOLIDAY_LOTTERY - LIFESTYLE_BRAND: 'CommonCurrencyModifyReason' = Consts_pb2.FUNDS_LIFESTYLE_BRAND - ROOMMATE_RENT: 'CommonCurrencyModifyReason' = Consts_pb2.FUNDS_ROOMMATE_RENT - SCHOLARSHIP_SURPLUS: 'CommonCurrencyModifyReason' = Consts_pb2.FUNDS_SCHOLARSHIP_SURPLUS - MARKETPLACE_OBJECT_SALE: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_MONEY_OBJECT_MARKETPLACE_SALE - - # Remove reasons - INTERACTION_COST: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_INTERACTION_COST - EVENT_COST: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_EVENT_COST - OBJECT_BUY: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_OBJECT_BUY - STRUCTURE_BUY: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_STRUCTURE_BUY - CAS_ITEM_BUY: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_CAS_BUY - BLUEPRINT_CONSTRUCTED: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_LOT_BUY - LOT_BUY: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_LOT_BUY - HOUSEHOLD_TRANSFER_LOSS: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_HOUSEHOLD_TRANSFER_LOSS - SIM_WALLET_EMPTIED: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_SIM_WALLET_EMPTIED - CRAFTING_COST: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_CRAFTING_COST - VACATION: 'CommonCurrencyModifyReason' = Consts_pb2.FUNDS_MONEY_VACATION - RETAIL_ITEM_BUY: 'CommonCurrencyModifyReason' = Consts_pb2.FUNDS_RETAIL_ITEM_BUY - RETAIL_TRANSFER_LOSS: 'CommonCurrencyModifyReason' = Consts_pb2.FUNDS_RETAIL_TRANSFER_LOSS - TUITION_COST: 'CommonCurrencyModifyReason' = Consts_pb2.FUNDS_TUITION_COST - SIM_DEATH_COST: 'CommonCurrencyModifyReason' = Consts_pb2.TELEMETRY_LOANS_SIM_DEATH diff --git a/Scripts/s4ap/sims4communitylib/enums/common_death_types.py b/Scripts/s4ap/sims4communitylib/enums/common_death_types.py deleted file mode 100644 index 73f1df1..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_death_types.py +++ /dev/null @@ -1,213 +0,0 @@ -""" -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 -""" -from typing import Union - -from interactions.utils.death import DeathType -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonDeathType(CommonInt): - """Various types of deaths Sims can have.""" - NONE: 'CommonDeathType' = ... - ANGER: 'CommonDeathType' = ... - CLIMBING_ROUTE: 'CommonDeathType' = ... - COW_PLANT: 'CommonDeathType' = ... - DEATH_FLOWER_ARRANGEMENT: 'CommonDeathType' = ... - DROWN: 'CommonDeathType' = ... - ELDER_EXHAUSTION: 'CommonDeathType' = ... - ELECTROCUTION: 'CommonDeathType' = ... - EMBARRASSMENT: 'CommonDeathType' = ... - FIRE: 'CommonDeathType' = ... - FLIES: 'CommonDeathType' = ... - FROZEN: 'CommonDeathType' = ... - HUNGER: 'CommonDeathType' = ... - KILLER_CHICKEN: 'CommonDeathType' = ... - KILLER_RABBIT: 'CommonDeathType' = ... - LAUGHTER: 'CommonDeathType' = ... - LIGHTNING: 'CommonDeathType' = ... - METEORITE: 'CommonDeathType' = ... - MOTHER_PLANT: 'CommonDeathType' = ... - MURPHY_BED: 'CommonDeathType' = ... - OLD_AGE: 'CommonDeathType' = ... - OVERHEAT: 'CommonDeathType' = ... - POISON: 'CommonDeathType' = ... - PUFFERFISH: 'CommonDeathType' = ... - RODENT_DISEASE: 'CommonDeathType' = ... - STEAM: 'CommonDeathType' = ... - STINK_BOMB: 'CommonDeathType' = ... - SUN: 'CommonDeathType' = ... - URBAN_MYTH: 'CommonDeathType' = ... - VENDING_MACHINE: 'CommonDeathType' = ... - WITCH_OVERLOAD: 'CommonDeathType' = ... - - @staticmethod - def get_random() -> 'CommonDeathType': - """get_random() - - Retrieve a random death type. - - :return: A death type. - :rtype: CommonDeathType - """ - return CommonDeathType.convert_from_vanilla(DeathType.get_random_death_type()) - - @staticmethod - def convert_to_vanilla(value: Union['CommonDeathType', int, DeathType]) -> Union[DeathType, 'CommonDeathType', int]: - """convert_to_vanilla(value) - - Convert a CommonDeathType into the vanilla DeathType enum. - - :param value: An instance of a CommonDeathType - :type value: CommonDeathType - :return: The specified value translated to a DeathType or the value itself if it could not be translated. - :rtype: DeathType - """ - if value is None or value == CommonDeathType.NONE: - return DeathType.NONE - if isinstance(value, DeathType): - return value - mapping = dict() - if hasattr(DeathType, 'Hunger'): - mapping[CommonDeathType.HUNGER] = DeathType.Hunger - if hasattr(DeathType, 'Old Age'): - mapping[CommonDeathType.OLD_AGE] = getattr(DeathType, 'Old Age') - if hasattr(DeathType, 'Cowplant'): - mapping[CommonDeathType.COW_PLANT] = DeathType.Cowplant - if hasattr(DeathType, 'Electrocution'): - mapping[CommonDeathType.ELECTROCUTION] = DeathType.Electrocution - if hasattr(DeathType, 'Anger'): - mapping[CommonDeathType.ANGER] = DeathType.Anger - if hasattr(DeathType, 'Laughter'): - mapping[CommonDeathType.LAUGHTER] = DeathType.Laughter - if hasattr(DeathType, 'ElderExhaustion'): - mapping[CommonDeathType.ELDER_EXHAUSTION] = DeathType.ElderExhaustion - if hasattr(DeathType, 'Embarrassment'): - mapping[CommonDeathType.EMBARRASSMENT] = DeathType.Embarrassment - if hasattr(DeathType, 'Fire'): - mapping[CommonDeathType.FIRE] = DeathType.Fire - if hasattr(DeathType, 'Drown'): - mapping[CommonDeathType.DROWN] = DeathType.Drown - if hasattr(DeathType, 'Steam'): - mapping[CommonDeathType.STEAM] = DeathType.Steam - if hasattr(DeathType, 'Pufferfish'): - mapping[CommonDeathType.PUFFERFISH] = DeathType.Pufferfish - if hasattr(DeathType, 'Sun'): - mapping[CommonDeathType.SUN] = DeathType.Sun - if hasattr(DeathType, 'Poison'): - mapping[CommonDeathType.POISON] = DeathType.Poison - if hasattr(DeathType, 'RodentDisease'): - mapping[CommonDeathType.RODENT_DISEASE] = DeathType.RodentDisease - if hasattr(DeathType, 'Frozen'): - mapping[CommonDeathType.FROZEN] = DeathType.Frozen - if hasattr(DeathType, 'Overheat'): - mapping[CommonDeathType.OVERHEAT] = DeathType.Overheat - if hasattr(DeathType, 'Lightning'): - mapping[CommonDeathType.LIGHTNING] = DeathType.Lightning - if hasattr(DeathType, 'DeathFlowerArrangement'): - mapping[CommonDeathType.DEATH_FLOWER_ARRANGEMENT] = DeathType.DeathFlowerArrangement - if hasattr(DeathType, 'MotherPlant'): - mapping[CommonDeathType.MOTHER_PLANT] = DeathType.MotherPlant - if hasattr(DeathType, 'WitchOverload'): - mapping[CommonDeathType.WITCH_OVERLOAD] = DeathType.WitchOverload - if hasattr(DeathType, 'MurphyBed'): - mapping[CommonDeathType.MURPHY_BED] = DeathType.MurphyBed - if hasattr(DeathType, 'Flies'): - mapping[CommonDeathType.FLIES] = DeathType.Flies - if hasattr(DeathType, 'VendingMachine'): - mapping[CommonDeathType.VENDING_MACHINE] = DeathType.VendingMachine - if hasattr(DeathType, 'ClimbingRoute'): - mapping[CommonDeathType.CLIMBING_ROUTE] = DeathType.ClimbingRoute - if hasattr(DeathType, 'KillerRabbit'): - mapping[CommonDeathType.KILLER_RABBIT] = DeathType.KillerRabbit - if hasattr(DeathType, 'KillerChicken'): - mapping[CommonDeathType.KILLER_CHICKEN] = DeathType.KillerChicken - if hasattr(DeathType, 'Meteorite'): - mapping[CommonDeathType.METEORITE] = DeathType.Meteorite - if hasattr(DeathType, 'StinkBomb'): - mapping[CommonDeathType.STINK_BOMB] = DeathType.StinkBomb - if hasattr(DeathType, 'UrbanMyth'): - mapping[CommonDeathType.URBAN_MYTH] = DeathType.UrbanMyth - return mapping.get(value, DeathType.NONE) - - @staticmethod - def convert_from_vanilla(value: Union[DeathType, int, 'CommonDeathType']) -> Union['CommonDeathType', DeathType, int]: - """convert_from_vanilla(value) - - Convert a DeathType into a CommonDeathType enum. - - :param value: An instance of a DeathType - :type value: DeathType - :return: The specified value translated to a CommonDeathType or NONE if it could not be translated. - :rtype: CommonDeathType - """ - if value is None or value == DeathType.NONE: - return CommonDeathType.NONE - if isinstance(value, CommonDeathType): - return value - mapping = dict() - if hasattr(DeathType, 'Hunger'): - mapping[DeathType.Hunger] = CommonDeathType.HUNGER - if hasattr(DeathType, 'Old Age'): - mapping[getattr(DeathType, 'Old Age')] = CommonDeathType.OLD_AGE - if hasattr(DeathType, 'Cowplant'): - mapping[DeathType.Cowplant] = CommonDeathType.COW_PLANT - if hasattr(DeathType, 'Electrocution'): - mapping[DeathType.Electrocution] = CommonDeathType.ELECTROCUTION - if hasattr(DeathType, 'Anger'): - mapping[DeathType.Anger] = CommonDeathType.ANGER - if hasattr(DeathType, 'Laughter'): - mapping[DeathType.Laughter] = CommonDeathType.LAUGHTER - if hasattr(DeathType, 'ElderExhaustion'): - mapping[DeathType.ElderExhaustion] = CommonDeathType.ELDER_EXHAUSTION - if hasattr(DeathType, 'Embarrassment'): - mapping[DeathType.Embarrassment] = CommonDeathType.EMBARRASSMENT - if hasattr(DeathType, 'Fire'): - mapping[DeathType.Fire] = CommonDeathType.FIRE - if hasattr(DeathType, 'Drown'): - mapping[DeathType.Drown] = CommonDeathType.DROWN - if hasattr(DeathType, 'Steam'): - mapping[DeathType.Steam] = CommonDeathType.STEAM - if hasattr(DeathType, 'Pufferfish'): - mapping[DeathType.Pufferfish] = CommonDeathType.PUFFERFISH - if hasattr(DeathType, 'Sun'): - mapping[DeathType.Sun] = CommonDeathType.SUN - if hasattr(DeathType, 'Poison'): - mapping[DeathType.Poison] = CommonDeathType.POISON - if hasattr(DeathType, 'RodentDisease'): - mapping[DeathType.RodentDisease] = CommonDeathType.RODENT_DISEASE - if hasattr(DeathType, 'Frozen'): - mapping[DeathType.Frozen] = CommonDeathType.FROZEN - if hasattr(DeathType, 'Overheat'): - mapping[DeathType.Overheat] = CommonDeathType.OVERHEAT - if hasattr(DeathType, 'Lightning'): - mapping[DeathType.Lightning] = CommonDeathType.LIGHTNING - if hasattr(DeathType, 'DeathFlowerArrangement'): - mapping[DeathType.DeathFlowerArrangement] = CommonDeathType.DEATH_FLOWER_ARRANGEMENT - if hasattr(DeathType, 'MotherPlant'): - mapping[DeathType.MotherPlant] = CommonDeathType.MOTHER_PLANT - if hasattr(DeathType, 'WitchOverload'): - mapping[DeathType.WitchOverload] = CommonDeathType.WITCH_OVERLOAD - if hasattr(DeathType, 'MurphyBed'): - mapping[DeathType.MurphyBed] = CommonDeathType.MURPHY_BED - if hasattr(DeathType, 'Flies'): - mapping[DeathType.Flies] = CommonDeathType.FLIES - if hasattr(DeathType, 'VendingMachine'): - mapping[DeathType.VendingMachine] = CommonDeathType.VENDING_MACHINE - if hasattr(DeathType, 'ClimbingRoute'): - mapping[DeathType.ClimbingRoute] = CommonDeathType.CLIMBING_ROUTE - if hasattr(DeathType, 'KillerRabbit'): - mapping[DeathType.KillerRabbit] = CommonDeathType.KILLER_RABBIT - if hasattr(DeathType, 'KillerChicken'): - mapping[DeathType.KillerChicken] = CommonDeathType.KILLER_CHICKEN - if hasattr(DeathType, 'Meteorite'): - mapping[DeathType.Meteorite] = CommonDeathType.METEORITE - if hasattr(DeathType, 'StinkBomb'): - mapping[DeathType.StinkBomb] = CommonDeathType.STINK_BOMB - if hasattr(DeathType, 'UrbanMyth'): - mapping[DeathType.UrbanMyth] = CommonDeathType.URBAN_MYTH - return mapping.get(value, CommonDeathType.NONE) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_enum.py b/Scripts/s4ap/sims4communitylib/enums/common_enum.py deleted file mode 100644 index 96bc2b1..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_enum.py +++ /dev/null @@ -1,90 +0,0 @@ -""" -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 -""" -from typing import Any, List, Union, Iterator - - -class CommonEnumMetaclass(type): - """A metaclass that converts the properties of a class into enum objects and allows iteration of those properties. - - """ - def __new__(mcs, cls: Any, bases: Any, class_dict: Any): - obj_attrs = set(dir(type(cls, (object,), {}))) - enum_cls = super().__new__(mcs, cls, bases, class_dict) - member_names = set(class_dict.keys()) - obj_attrs - enum_dict = dict() - for member_name in member_names: - if callable(getattr(enum_cls, member_name)) or (member_name.startswith('_') and member_name.endswith('_')): - continue - enum_dict[member_name] = getattr(enum_cls, member_name) - enum_cls._members_ = enum_dict - expected_enum_type = mcs.get_enum_type() - for enum_name, enum_value in enum_dict.items(): - if hasattr(enum_value, 'value'): - enum_value = enum_value.value - if expected_enum_type is not None and type(enum_value) != expected_enum_type: - raise ValueError('Incorrect enum value type for class \'{}\', expected type \'{}\', got type: \'{}\'. Enum Name: \'{}\', Enum Value: \'{}\''.format(cls, expected_enum_type, type(enum_value), enum_name, enum_value)) - common_enum = mcs._get_common_enum(enum_name, enum_value, enum_cls.__name__) - setattr(enum_cls, enum_name, common_enum) - - return enum_cls - - def __call__(cls, val: Any): - for (enum_name, enum_value) in cls._members_.items(): - if val == enum_name or val == enum_value: - return getattr(cls, enum_name) - raise KeyError('Value: \'{}\' not found within class \'{}\''.format(val, cls.__name__)) - - @classmethod - def _get_common_enum(mcs, enum_name: str, enum_value: Any, class_name: str): - from s4ap.sims4communitylib.enums.enumtypes.object_enum import CommonEnumObject - return CommonEnumObject(enum_name, enum_value, class_name) - - @classmethod - def get_enum_type(mcs) -> Union[type, None]: - """Retrieve the enum type of this class. - - :return: The expected enum type. - :rtype: A base type. - """ - return None - - def items(cls) -> List[Any]: - """Retrieve all enum items of the class - - :return: A collection of the enum items of all enums of the class. - :rtype: List[Any] - """ - return [getattr(cls, name) for (name, value) in cls._members_.items()] - - def names(cls) -> List[str]: - """Retrieve all names of all enums of the class. - - :return: A collection of the names of all enums of the class. - :rtype: List[str] - """ - return list(cls._members_.keys()) - - def values(cls) -> List[Any]: - """Retrieve all enum values of all enums of this class - - :return: A collection of the enum values of all enums of the class. - :rtype: List[Any] - """ - return list(cls._members_.values()) - - def __getitem__(cls, key: str): - return getattr(cls._members_, key.upper()) - - def __iter__(cls) -> Iterator[Any]: - return cls._members_.__iter__() - - def __len__(cls) -> int: - return len(cls._members_) - - def __repr__(cls) -> str: - return '{}'.format(cls.__name__) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_fund_types.py b/Scripts/s4ap/sims4communitylib/enums/common_fund_types.py deleted file mode 100644 index 551ce57..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_fund_types.py +++ /dev/null @@ -1,13 +0,0 @@ -""" -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 -""" - -# This class is obsolete, please use CommonFundsSource from common_funds_sources instead. -from s4ap.sims4communitylib.enums.common_funds_sources import CommonFundsSource - - -CommonFundType = CommonFundsSource diff --git a/Scripts/s4ap/sims4communitylib/enums/common_funds_sources.py b/Scripts/s4ap/sims4communitylib/enums/common_funds_sources.py deleted file mode 100644 index 4885025..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_funds_sources.py +++ /dev/null @@ -1,63 +0,0 @@ -""" -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 -""" -from typing import Dict - -from sims.funds import FundsSource -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonFundsSource(CommonInt): - """Sources of funds.""" - HOUSEHOLD: 'CommonFundsSource' = ... - RETAIL: 'CommonFundsSource' = ... - BUSINESS: 'CommonFundsSource' = ... - STATISTIC: 'CommonFundsSource' = ... - BUCKS: 'CommonFundsSource' = ... - NO_SOURCE: 'CommonFundsSource' = ... - - @staticmethod - def convert_to_vanilla(value: 'CommonFundsSource') -> FundsSource: - """convert_to_vanilla(value) - - Convert a value into the vanilla FundsSource enum. - - :param value: An instance of the enum. - :type value: CommonFundsSource - :return: The specified value translated to FundsSource or HOUSEHOLD if the value could not be translated. - :rtype: Union[FundsSource, None] - """ - mapping: Dict[CommonFundsSource, FundsSource] = { - CommonFundsSource.HOUSEHOLD: FundsSource.HOUSEHOLD, - CommonFundsSource.RETAIL: FundsSource.RETAIL, - CommonFundsSource.BUSINESS: FundsSource.BUSINESS, - CommonFundsSource.STATISTIC: FundsSource.STATISTIC, - CommonFundsSource.BUCKS: FundsSource.BUCKS, - CommonFundsSource.NO_SOURCE: FundsSource.NO_SOURCE, - } - return mapping.get(value, FundsSource.HOUSEHOLD) - - @staticmethod - def convert_from_vanilla(value: FundsSource) -> 'CommonFundsSource': - """convert_from_vanilla(value) - - Convert a vanilla FundsSource to value. - - :param value: An instance of the enum. - :type value: FundsSource - :return: The specified value translated to CommonFundsSource or HOUSEHOLD if the value could not be translated. - :rtype: CommonFundsSource - """ - mapping: Dict[FundsSource, CommonFundsSource] = { - FundsSource.HOUSEHOLD: CommonFundsSource.HOUSEHOLD, - FundsSource.RETAIL: CommonFundsSource.RETAIL, - FundsSource.BUSINESS: CommonFundsSource.BUSINESS, - FundsSource.STATISTIC: CommonFundsSource.STATISTIC, - FundsSource.BUCKS: CommonFundsSource.BUCKS, - FundsSource.NO_SOURCE: CommonFundsSource.NO_SOURCE, - } - return mapping.get(value, CommonFundsSource.HOUSEHOLD) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_game_tag_category.py b/Scripts/s4ap/sims4communitylib/enums/common_game_tag_category.py deleted file mode 100644 index 1ce15fe..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_game_tag_category.py +++ /dev/null @@ -1,431 +0,0 @@ -""" -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 -""" -from typing import Union, Tuple, Iterator - -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt -from tag import TagCategory - - -class CommonGameTagCategory(CommonInt): - """Variants of Game Tag Categories.""" - INVALID: 'CommonGameTagCategory' = ... - ACCESSORIES: 'CommonGameTagCategory' = ... - ACNE_LEVEL: 'CommonGameTagCategory' = ... - AGE_APPROPRIATE: 'CommonGameTagCategory' = ... - APPEARANCE_MODIFIER: 'CommonGameTagCategory' = ... - ARCHETYPE: 'CommonGameTagCategory' = ... - BOTTOM: 'CommonGameTagCategory' = ... - BOTTOM_ACCESSORY: 'CommonGameTagCategory' = ... - BREED: 'CommonGameTagCategory' = ... - BREED_GROUP: 'CommonGameTagCategory' = ... - BUILD: 'CommonGameTagCategory' = ... - BUY_CAT_EE: 'CommonGameTagCategory' = ... - BUY_CAT_LD: 'CommonGameTagCategory' = ... - BUY_CAT_MAG: 'CommonGameTagCategory' = ... - BUY_CAT_PA: 'CommonGameTagCategory' = ... - BUY_CAT_SS: 'CommonGameTagCategory' = ... - BUY_CAT_VO: 'CommonGameTagCategory' = ... - COAT_PATTERN: 'CommonGameTagCategory' = ... - COLOR: 'CommonGameTagCategory' = ... - COLOR_PALETTE: 'CommonGameTagCategory' = ... - DOG_SIZE: 'CommonGameTagCategory' = ... - EARS: 'CommonGameTagCategory' = ... - ENSEMBLE: 'CommonGameTagCategory' = ... - EYE_BROW_SHAPE: 'CommonGameTagCategory' = ... - EYE_BROW_THICKNESS: 'CommonGameTagCategory' = ... - EYE_COLOR: 'CommonGameTagCategory' = ... - FABRIC: 'CommonGameTagCategory' = ... - FACE_DETAIL: 'CommonGameTagCategory' = ... - FACE_MAKE_UP: 'CommonGameTagCategory' = ... - FACIAL_HAIR: 'CommonGameTagCategory' = ... - FASHION: 'CommonGameTagCategory' = ... - FLOOR_PATTERN: 'CommonGameTagCategory' = ... - FULL_BODY: 'CommonGameTagCategory' = ... - FUR: 'CommonGameTagCategory' = ... - FUR_LENGTH: 'CommonGameTagCategory' = ... - GENDER_APPROPRIATE: 'CommonGameTagCategory' = ... - GROWTH_LEVEL: 'CommonGameTagCategory' = ... - GROWTH_TYPE: 'CommonGameTagCategory' = ... - HAIR: 'CommonGameTagCategory' = ... - HAIR_COLOR: 'CommonGameTagCategory' = ... - HAIR_LENGTH: 'CommonGameTagCategory' = ... - HAIR_TEXTURE: 'CommonGameTagCategory' = ... - HAT: 'CommonGameTagCategory' = ... - MOOD: 'CommonGameTagCategory' = ... - NOSE_COLOR: 'CommonGameTagCategory' = ... - NUDE_PART: 'CommonGameTagCategory' = ... - OCCULT: 'CommonGameTagCategory' = ... - OUTFIT_CATEGORY: 'CommonGameTagCategory' = ... - PATTERN: 'CommonGameTagCategory' = ... - PERSONA: 'CommonGameTagCategory' = ... - REWARD: 'CommonGameTagCategory' = ... - SHOES: 'CommonGameTagCategory' = ... - SKILL: 'CommonGameTagCategory' = ... - SKIN_HUE: 'CommonGameTagCategory' = ... - SKIN_TONE_BLEND: 'CommonGameTagCategory' = ... - SKIN_TONE_TYPE: 'CommonGameTagCategory' = ... - SKIN_VALUE: 'CommonGameTagCategory' = ... - SPECIAL: 'CommonGameTagCategory' = ... - SPECIAL_CONTENT: 'CommonGameTagCategory' = ... - STYLE: 'CommonGameTagCategory' = ... - TAIL: 'CommonGameTagCategory' = ... - TERRAIN_PAINT: 'CommonGameTagCategory' = ... - TOP: 'CommonGameTagCategory' = ... - TRAIT_GROUP: 'CommonGameTagCategory' = ... - UNIFORM: 'CommonGameTagCategory' = ... - VAMPIRE_ARCHETYPE: 'CommonGameTagCategory' = ... - WALL_PATTERN: 'CommonGameTagCategory' = ... - WORLD_LOG: 'CommonGameTagCategory' = ... - - @classmethod - def get_all(cls, exclude_values: Iterator['CommonGameTagCategory'] = None) -> Tuple['CommonGameTagCategory']: - """get_all(exclude_values=None) - - Get a collection of all values. - - :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonTagCategory], optional - :return: A collection of all values. - :rtype: Tuple[CommonGameTagCategory] - """ - if exclude_values is None: - exclude_values = (cls.INVALID,) - # noinspection PyTypeChecker - value_list: Tuple[CommonGameTagCategory, ...] = tuple([value for value in cls.values if value not in exclude_values]) - return value_list - - @classmethod - def get_all_names(cls, exclude_values: Iterator['CommonGameTagCategory'] = None) -> Tuple[str]: - """get_all_names(exclude_values=None) - - Retrieve a collection of the names of all values. - - :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonTagCategory], optional - :return: A collection of the names of all values. - :rtype: Tuple[str] - """ - name_list: Tuple[str] = tuple([value.name for value in cls.get_all(exclude_values=exclude_values)]) - return name_list - - @classmethod - def get_comma_separated_names_string(cls, exclude_values: Iterator['CommonGameTagCategory'] = None) -> str: - """get_comma_separated_names_string(exclude_values=None) - - Create a string containing all names of all values, separated by a comma. - - :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonTagCategory], optional - :return: A string containing all names of all values, separated by a comma. - :rtype: str - """ - return ', '.join(cls.get_all_names(exclude_values=exclude_values)) - - @staticmethod - def convert_to_vanilla(value: 'CommonGameTagCategory') -> Union[TagCategory, None]: - """convert_to_vanilla(value) - - Convert a value into the vanilla TagCategory enum. - - :param value: An instance of CommonTagCategory - :type value: CommonGameTagCategory - :return: The specified value translated to TagCategory or INVALID if the value could not be translated. - :rtype: Union[TagCategory, None] - """ - if value is None or value == CommonGameTagCategory.INVALID: - return TagCategory.INVALID - if isinstance(value, TagCategory): - return value - mapping = dict() - if hasattr(TagCategory, 'Mood'): - mapping[CommonGameTagCategory.MOOD] = TagCategory.Mood - if hasattr(TagCategory, 'Color'): - mapping[CommonGameTagCategory.COLOR] = TagCategory.Color - if hasattr(TagCategory, 'Style'): - mapping[CommonGameTagCategory.STYLE] = TagCategory.Style - if hasattr(TagCategory, 'AgeAppropriate'): - mapping[CommonGameTagCategory.AGE_APPROPRIATE] = TagCategory.AgeAppropriate - if hasattr(TagCategory, 'Archetype'): - mapping[CommonGameTagCategory.ARCHETYPE] = TagCategory.Archetype - if hasattr(TagCategory, 'OutfitCategory'): - mapping[CommonGameTagCategory.OUTFIT_CATEGORY] = TagCategory.OutfitCategory - if hasattr(TagCategory, 'Skill'): - mapping[CommonGameTagCategory.SKILL] = TagCategory.Skill - if hasattr(TagCategory, 'EyeColor'): - mapping[CommonGameTagCategory.EYE_COLOR] = TagCategory.EyeColor - if hasattr(TagCategory, 'Persona'): - mapping[CommonGameTagCategory.PERSONA] = TagCategory.Persona - if hasattr(TagCategory, 'Special'): - mapping[CommonGameTagCategory.SPECIAL] = TagCategory.Special - if hasattr(TagCategory, 'HairColor'): - mapping[CommonGameTagCategory.HAIR_COLOR] = TagCategory.HairColor - if hasattr(TagCategory, 'ColorPalette'): - mapping[CommonGameTagCategory.COLOR_PALETTE] = TagCategory.ColorPalette - if hasattr(TagCategory, 'Hair'): - mapping[CommonGameTagCategory.HAIR] = TagCategory.Hair - if hasattr(TagCategory, 'FacialHair'): - mapping[CommonGameTagCategory.FACIAL_HAIR] = TagCategory.FacialHair - if hasattr(TagCategory, 'Hat'): - mapping[CommonGameTagCategory.HAT] = TagCategory.Hat - if hasattr(TagCategory, 'FaceMakeup'): - mapping[CommonGameTagCategory.FACE_MAKE_UP] = TagCategory.FaceMakeup - if hasattr(TagCategory, 'Top'): - mapping[CommonGameTagCategory.TOP] = TagCategory.Top - if hasattr(TagCategory, 'Bottom'): - mapping[CommonGameTagCategory.BOTTOM] = TagCategory.Bottom - if hasattr(TagCategory, 'FullBody'): - mapping[CommonGameTagCategory.FULL_BODY] = TagCategory.FullBody - if hasattr(TagCategory, 'Shoes'): - mapping[CommonGameTagCategory.SHOES] = TagCategory.Shoes - if hasattr(TagCategory, 'BottomAccessory'): - mapping[CommonGameTagCategory.BOTTOM_ACCESSORY] = TagCategory.BottomAccessory - if hasattr(TagCategory, 'BuyCatEE'): - mapping[CommonGameTagCategory.BUY_CAT_EE] = TagCategory.BuyCatEE - if hasattr(TagCategory, 'BuyCatPA'): - mapping[CommonGameTagCategory.BUY_CAT_PA] = TagCategory.BuyCatPA - if hasattr(TagCategory, 'BuyCatLD'): - mapping[CommonGameTagCategory.BUY_CAT_LD] = TagCategory.BuyCatLD - if hasattr(TagCategory, 'BuyCatSS'): - mapping[CommonGameTagCategory.BUY_CAT_SS] = TagCategory.BuyCatSS - if hasattr(TagCategory, 'BuyCatVO'): - mapping[CommonGameTagCategory.BUY_CAT_VO] = TagCategory.BuyCatVO - if hasattr(TagCategory, 'Uniform'): - mapping[CommonGameTagCategory.UNIFORM] = TagCategory.Uniform - if hasattr(TagCategory, 'Accessories'): - mapping[CommonGameTagCategory.ACCESSORIES] = TagCategory.Accessories - if hasattr(TagCategory, 'BuyCatMAG'): - mapping[CommonGameTagCategory.BUY_CAT_MAG] = TagCategory.BuyCatMAG - if hasattr(TagCategory, 'FloorPattern'): - mapping[CommonGameTagCategory.FLOOR_PATTERN] = TagCategory.FloorPattern - if hasattr(TagCategory, 'WallPattern'): - mapping[CommonGameTagCategory.WALL_PATTERN] = TagCategory.WallPattern - if hasattr(TagCategory, 'Fabric'): - mapping[CommonGameTagCategory.FABRIC] = TagCategory.Fabric - if hasattr(TagCategory, 'Build'): - mapping[CommonGameTagCategory.BUILD] = TagCategory.Build - if hasattr(TagCategory, 'Pattern'): - mapping[CommonGameTagCategory.PATTERN] = TagCategory.Pattern - if hasattr(TagCategory, 'HairLength'): - mapping[CommonGameTagCategory.HAIR_LENGTH] = TagCategory.HairLength - if hasattr(TagCategory, 'HairTexture'): - mapping[CommonGameTagCategory.HAIR_TEXTURE] = TagCategory.HairTexture - if hasattr(TagCategory, 'TraitGroup'): - mapping[CommonGameTagCategory.TRAIT_GROUP] = TagCategory.TraitGroup - if hasattr(TagCategory, 'SkinHue'): - mapping[CommonGameTagCategory.SKIN_HUE] = TagCategory.SkinHue - if hasattr(TagCategory, 'Reward'): - mapping[CommonGameTagCategory.REWARD] = TagCategory.Reward - if hasattr(TagCategory, 'TerrainPaint'): - mapping[CommonGameTagCategory.TERRAIN_PAINT] = TagCategory.TerrainPaint - if hasattr(TagCategory, 'EyebrowThickness'): - mapping[CommonGameTagCategory.EYE_BROW_THICKNESS] = TagCategory.EyebrowThickness - if hasattr(TagCategory, 'EyebrowShape'): - mapping[CommonGameTagCategory.EYE_BROW_SHAPE] = TagCategory.EyebrowShape - if hasattr(TagCategory, 'Ensemble'): - mapping[CommonGameTagCategory.ENSEMBLE] = TagCategory.Ensemble - if hasattr(TagCategory, 'SkintoneType'): - mapping[CommonGameTagCategory.SKIN_TONE_TYPE] = TagCategory.SkintoneType - if hasattr(TagCategory, 'Occult'): - mapping[CommonGameTagCategory.OCCULT] = TagCategory.Occult - if hasattr(TagCategory, 'SkintoneBlend'): - mapping[CommonGameTagCategory.SKIN_TONE_BLEND] = TagCategory.SkintoneBlend - if hasattr(TagCategory, 'GenderAppropriate'): - mapping[CommonGameTagCategory.GENDER_APPROPRIATE] = TagCategory.GenderAppropriate - if hasattr(TagCategory, 'NudePart'): - mapping[CommonGameTagCategory.NUDE_PART] = TagCategory.NudePart - if hasattr(TagCategory, 'FaceDetail'): - mapping[CommonGameTagCategory.FACE_DETAIL] = TagCategory.FaceDetail - if hasattr(TagCategory, 'VampireArchetype'): - mapping[CommonGameTagCategory.VAMPIRE_ARCHETYPE] = TagCategory.VampireArchetype - if hasattr(TagCategory, 'Ears'): - mapping[CommonGameTagCategory.EARS] = TagCategory.Ears - if hasattr(TagCategory, 'Breed'): - mapping[CommonGameTagCategory.BREED] = TagCategory.Breed - if hasattr(TagCategory, 'Tail'): - mapping[CommonGameTagCategory.TAIL] = TagCategory.Tail - if hasattr(TagCategory, 'Fur'): - mapping[CommonGameTagCategory.FUR] = TagCategory.Fur - if hasattr(TagCategory, 'DogSize'): - mapping[CommonGameTagCategory.DOG_SIZE] = TagCategory.DogSize - if hasattr(TagCategory, 'BreedGroup'): - mapping[CommonGameTagCategory.BREED_GROUP] = TagCategory.BreedGroup - if hasattr(TagCategory, 'NoseColor'): - mapping[CommonGameTagCategory.NOSE_COLOR] = TagCategory.NoseColor - if hasattr(TagCategory, 'WorldLog'): - mapping[CommonGameTagCategory.WORLD_LOG] = TagCategory.WorldLog - if hasattr(TagCategory, 'CoatPattern'): - mapping[CommonGameTagCategory.COAT_PATTERN] = TagCategory.CoatPattern - if hasattr(TagCategory, 'FurLength'): - mapping[CommonGameTagCategory.FUR_LENGTH] = TagCategory.FurLength - if hasattr(TagCategory, 'AppearanceModifier'): - mapping[CommonGameTagCategory.APPEARANCE_MODIFIER] = TagCategory.AppearanceModifier - if hasattr(TagCategory, 'SpecialContent'): - mapping[CommonGameTagCategory.SPECIAL_CONTENT] = TagCategory.SpecialContent - if hasattr(TagCategory, 'Fashion'): - mapping[CommonGameTagCategory.FASHION] = TagCategory.Fashion - if hasattr(TagCategory, 'GrowthLevel'): - mapping[CommonGameTagCategory.GROWTH_LEVEL] = TagCategory.GrowthLevel - if hasattr(TagCategory, 'GrowthType'): - mapping[CommonGameTagCategory.GROWTH_TYPE] = TagCategory.GrowthType - if hasattr(TagCategory, 'SkinValue'): - mapping[CommonGameTagCategory.SKIN_VALUE] = TagCategory.SkinValue - if hasattr(TagCategory, 'AcneLevel'): - mapping[CommonGameTagCategory.ACNE_LEVEL] = TagCategory.AcneLevel - return mapping.get(value, TagCategory.INVALID) - - @staticmethod - def convert_from_vanilla(value: Union[int, TagCategory]) -> 'CommonGameTagCategory': - """convert_from_vanilla(value) - - Convert a value into a CommonTagCategory enum. - - :param value: An instance of TagCategory - :type value: TagCategory - :return: The specified value translated to CommonTagCategory or INVALID if the value could not be translated. - :rtype: TagCategory - """ - if value is None or value == TagCategory.INVALID: - return CommonGameTagCategory.INVALID - if isinstance(value, CommonGameTagCategory): - return value - mapping = dict() - if hasattr(TagCategory, 'Mood'): - mapping[TagCategory.Mood] = CommonGameTagCategory.MOOD - if hasattr(TagCategory, 'Color'): - mapping[TagCategory.Color] = CommonGameTagCategory.COLOR - if hasattr(TagCategory, 'Style'): - mapping[TagCategory.Style] = CommonGameTagCategory.STYLE - if hasattr(TagCategory, 'AgeAppropriate'): - mapping[TagCategory.AgeAppropriate] = CommonGameTagCategory.AGE_APPROPRIATE - if hasattr(TagCategory, 'Archetype'): - mapping[TagCategory.Archetype] = CommonGameTagCategory.ARCHETYPE - if hasattr(TagCategory, 'OutfitCategory'): - mapping[TagCategory.OutfitCategory] = CommonGameTagCategory.OUTFIT_CATEGORY - if hasattr(TagCategory, 'Skill'): - mapping[TagCategory.Skill] = CommonGameTagCategory.SKILL - if hasattr(TagCategory, 'EyeColor'): - mapping[TagCategory.EyeColor] = CommonGameTagCategory.EYE_COLOR - if hasattr(TagCategory, 'Persona'): - mapping[TagCategory.Persona] = CommonGameTagCategory.PERSONA - if hasattr(TagCategory, 'Special'): - mapping[TagCategory.Special] = CommonGameTagCategory.SPECIAL - if hasattr(TagCategory, 'HairColor'): - mapping[TagCategory.HairColor] = CommonGameTagCategory.HAIR_COLOR - if hasattr(TagCategory, 'ColorPalette'): - mapping[TagCategory.ColorPalette] = CommonGameTagCategory.COLOR_PALETTE - if hasattr(TagCategory, 'Hair'): - mapping[TagCategory.Hair] = CommonGameTagCategory.HAIR - if hasattr(TagCategory, 'FacialHair'): - mapping[TagCategory.FacialHair] = CommonGameTagCategory.FACIAL_HAIR - if hasattr(TagCategory, 'Hat'): - mapping[TagCategory.Hat] = CommonGameTagCategory.HAT - if hasattr(TagCategory, 'FaceMakeup'): - mapping[TagCategory.FaceMakeup] = CommonGameTagCategory.FACE_MAKE_UP - if hasattr(TagCategory, 'Top'): - mapping[TagCategory.Top] = CommonGameTagCategory.TOP - if hasattr(TagCategory, 'Bottom'): - mapping[TagCategory.Bottom] = CommonGameTagCategory.BOTTOM - if hasattr(TagCategory, 'FullBody'): - mapping[TagCategory.FullBody] = CommonGameTagCategory.FULL_BODY - if hasattr(TagCategory, 'Shoes'): - mapping[TagCategory.Shoes] = CommonGameTagCategory.SHOES - if hasattr(TagCategory, 'BottomAccessory'): - mapping[TagCategory.BottomAccessory] = CommonGameTagCategory.BOTTOM_ACCESSORY - if hasattr(TagCategory, 'BuyCatEE'): - mapping[TagCategory.BuyCatEE] = CommonGameTagCategory.BUY_CAT_EE - if hasattr(TagCategory, 'BuyCatPA'): - mapping[TagCategory.BuyCatPA] = CommonGameTagCategory.BUY_CAT_PA - if hasattr(TagCategory, 'BuyCatLD'): - mapping[TagCategory.BuyCatLD] = CommonGameTagCategory.BUY_CAT_LD - if hasattr(TagCategory, 'BuyCatSS'): - mapping[TagCategory.BuyCatSS] = CommonGameTagCategory.BUY_CAT_SS - if hasattr(TagCategory, 'BuyCatVO'): - mapping[TagCategory.BuyCatVO] = CommonGameTagCategory.BUY_CAT_VO - if hasattr(TagCategory, 'Uniform'): - mapping[TagCategory.Uniform] = CommonGameTagCategory.UNIFORM - if hasattr(TagCategory, 'Accessories'): - mapping[TagCategory.Accessories] = CommonGameTagCategory.ACCESSORIES - if hasattr(TagCategory, 'BuyCatMAG'): - mapping[TagCategory.BuyCatMAG] = CommonGameTagCategory.BUY_CAT_MAG - if hasattr(TagCategory, 'FloorPattern'): - mapping[TagCategory.FloorPattern] = CommonGameTagCategory.FLOOR_PATTERN - if hasattr(TagCategory, 'WallPattern'): - mapping[TagCategory.WallPattern] = CommonGameTagCategory.WALL_PATTERN - if hasattr(TagCategory, 'Fabric'): - mapping[TagCategory.Fabric] = CommonGameTagCategory.FABRIC - if hasattr(TagCategory, 'Build'): - mapping[TagCategory.Build] = CommonGameTagCategory.BUILD - if hasattr(TagCategory, 'Pattern'): - mapping[TagCategory.Pattern] = CommonGameTagCategory.PATTERN - if hasattr(TagCategory, 'HairLength'): - mapping[TagCategory.HairLength] = CommonGameTagCategory.HAIR_LENGTH - if hasattr(TagCategory, 'HairTexture'): - mapping[TagCategory.HairTexture] = CommonGameTagCategory.HAIR_TEXTURE - if hasattr(TagCategory, 'TraitGroup'): - mapping[TagCategory.TraitGroup] = CommonGameTagCategory.TRAIT_GROUP - if hasattr(TagCategory, 'SkinHue'): - mapping[TagCategory.SkinHue] = CommonGameTagCategory.SKIN_HUE - if hasattr(TagCategory, 'Reward'): - mapping[TagCategory.Reward] = CommonGameTagCategory.REWARD - if hasattr(TagCategory, 'TerrainPaint'): - mapping[TagCategory.TerrainPaint] = CommonGameTagCategory.TERRAIN_PAINT - if hasattr(TagCategory, 'EyebrowThickness'): - mapping[TagCategory.EyebrowThickness] = CommonGameTagCategory.EYE_BROW_THICKNESS - if hasattr(TagCategory, 'EyebrowShape'): - mapping[TagCategory.EyebrowShape] = CommonGameTagCategory.EYE_BROW_SHAPE - if hasattr(TagCategory, 'Ensemble'): - mapping[TagCategory.Ensemble] = CommonGameTagCategory.ENSEMBLE - if hasattr(TagCategory, 'SkintoneType'): - mapping[TagCategory.SkintoneType] = CommonGameTagCategory.SKIN_TONE_TYPE - if hasattr(TagCategory, 'Occult'): - mapping[TagCategory.Occult] = CommonGameTagCategory.OCCULT - if hasattr(TagCategory, 'SkintoneBlend'): - mapping[TagCategory.SkintoneBlend] = CommonGameTagCategory.SKIN_TONE_BLEND - if hasattr(TagCategory, 'GenderAppropriate'): - mapping[TagCategory.GenderAppropriate] = CommonGameTagCategory.GENDER_APPROPRIATE - if hasattr(TagCategory, 'NudePart'): - mapping[TagCategory.NudePart] = CommonGameTagCategory.NUDE_PART - if hasattr(TagCategory, 'FaceDetail'): - mapping[TagCategory.FaceDetail] = CommonGameTagCategory.FACE_DETAIL - if hasattr(TagCategory, 'VampireArchetype'): - mapping[TagCategory.VampireArchetype] = CommonGameTagCategory.VAMPIRE_ARCHETYPE - if hasattr(TagCategory, 'Ears'): - mapping[TagCategory.Ears] = CommonGameTagCategory.EARS - if hasattr(TagCategory, 'Breed'): - mapping[TagCategory.Breed] = CommonGameTagCategory.BREED - if hasattr(TagCategory, 'Tail'): - mapping[TagCategory.Tail] = CommonGameTagCategory.TAIL - if hasattr(TagCategory, 'Fur'): - mapping[TagCategory.Fur] = CommonGameTagCategory.FUR - if hasattr(TagCategory, 'DogSize'): - mapping[TagCategory.DogSize] = CommonGameTagCategory.DOG_SIZE - if hasattr(TagCategory, 'BreedGroup'): - mapping[TagCategory.BreedGroup] = CommonGameTagCategory.BREED_GROUP - if hasattr(TagCategory, 'NoseColor'): - mapping[TagCategory.NoseColor] = CommonGameTagCategory.NOSE_COLOR - if hasattr(TagCategory, 'WorldLog'): - mapping[TagCategory.WorldLog] = CommonGameTagCategory.WORLD_LOG - if hasattr(TagCategory, 'CoatPattern'): - mapping[TagCategory.CoatPattern] = CommonGameTagCategory.COAT_PATTERN - if hasattr(TagCategory, 'FurLength'): - mapping[TagCategory.FurLength] = CommonGameTagCategory.FUR_LENGTH - if hasattr(TagCategory, 'AppearanceModifier'): - mapping[TagCategory.AppearanceModifier] = CommonGameTagCategory.APPEARANCE_MODIFIER - if hasattr(TagCategory, 'SpecialContent'): - mapping[TagCategory.SpecialContent] = CommonGameTagCategory.SPECIAL_CONTENT - if hasattr(TagCategory, 'Fashion'): - mapping[TagCategory.Fashion] = CommonGameTagCategory.FASHION - if hasattr(TagCategory, 'GrowthLevel'): - mapping[TagCategory.GrowthLevel] = CommonGameTagCategory.GROWTH_LEVEL - if hasattr(TagCategory, 'GrowthType'): - mapping[TagCategory.GrowthType] = CommonGameTagCategory.GROWTH_TYPE - if hasattr(TagCategory, 'SkinValue'): - mapping[TagCategory.SkinValue] = CommonGameTagCategory.SKIN_VALUE - if hasattr(TagCategory, 'AcneLevel'): - mapping[TagCategory.AcneLevel] = CommonGameTagCategory.ACNE_LEVEL - return mapping.get(value, CommonGameTagCategory.INVALID) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_gender.py b/Scripts/s4ap/sims4communitylib/enums/common_gender.py deleted file mode 100644 index ed6d641..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_gender.py +++ /dev/null @@ -1,148 +0,0 @@ -""" -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 -""" -from typing import Union, Tuple, Iterator - -from sims.sim_info import SimInfo -from sims.sim_info_types import Gender -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonGender(CommonInt): - """Custom Gender enum containing all genders. - - """ - INVALID: 'CommonGender' = 0 - MALE: 'CommonGender' = 4096 - FEMALE: 'CommonGender' = 8192 - - @classmethod - def get_all(cls, exclude_values: Iterator['CommonGender'] = None) -> Tuple['CommonGender']: - """get_all(exclude_values=None) - - Get a collection of all values. - - :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonGender], optional - :return: A collection of all values. - :rtype: Tuple[CommonGender] - """ - if exclude_values is None: - exclude_values = (cls.INVALID,) - # noinspection PyTypeChecker - value_list: Tuple[CommonGender, ...] = tuple([value for value in cls.values if value not in exclude_values]) - return value_list - - @classmethod - def get_all_names(cls, exclude_values: Iterator['CommonGender'] = None) -> Tuple[str]: - """get_all_names(exclude_values=None) - - Retrieve a collection of the names of all values. - - :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonGender], optional - :return: A collection of the names of all values. - :rtype: Tuple[str] - """ - name_list: Tuple[str] = tuple([value.name for value in cls.get_all(exclude_values=exclude_values)]) - return name_list - - @classmethod - def get_comma_separated_names_string(cls, exclude_values: Iterator['CommonGender'] = None) -> str: - """get_comma_separated_names_string(exclude_values=None) - - Create a string containing all names of all values, separated by a comma. - - :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonGender], optional - :return: A string containing all names of all values, separated by a comma. - :rtype: str - """ - return ', '.join(cls.get_all_names(exclude_values=exclude_values)) - - @staticmethod - def get_gender(sim_info: SimInfo) -> 'CommonGender': - """get_gender(sim_info) - - Retrieve the CommonGender of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The CommonGender that represents what gender a Sim is or CommonGender.INVALID if their gender cannot be determined. - :rtype: CommonGender - """ - from s4ap.sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils - if CommonGenderUtils.is_male(sim_info): - return CommonGender.MALE - elif CommonGenderUtils.is_female(sim_info): - return CommonGender.FEMALE - return CommonGender.INVALID - - @staticmethod - def convert_to_vanilla(value: 'CommonGender') -> Union[Gender, None]: - """convert_to_vanilla(value) - - Convert a value into the vanilla Gender enum. - - :param value: An instance of CommonGender - :type value: CommonGender - :return: The specified value translated to Gender or None if the value could not be translated. - :rtype: Union[Gender, None] - """ - if value is None or value == CommonGender.INVALID: - return None - if isinstance(value, Gender): - return value - mapping = { - CommonGender.MALE: Gender.MALE, - CommonGender.FEMALE: Gender.FEMALE - } - return mapping.get(value, None) - - @staticmethod - def convert_from_vanilla(value: Union[int, Gender]) -> 'CommonGender': - """convert_from_vanilla(value) - - Convert a value into a CommonGender enum. - - :param value: An instance of Gender - :type value: Gender - :return: The specified value translated to CommonGender or INVALID if the value could not be translated. - :rtype: CommonGender - """ - if value is None: - return CommonGender.INVALID - if isinstance(value, CommonGender): - return value - mapping = { - int(Gender.MALE): CommonGender.MALE, - int(Gender.FEMALE): CommonGender.FEMALE - } - value = int(value) - if value not in mapping: - return CommonGender.INVALID - return mapping[value] - - @staticmethod - def convert_to_localized_string_id(value: 'CommonGender') -> Union[int, str]: - """convert_to_localized_string_id(value) - - Convert a CommonGender into a Localized String identifier. - - :param value: An instance of a CommonGender - :type value: CommonGender - :return: The specified CommonGender translated to a localized string identifier. If no localized string id is found, the name property of the value will be used instead. - :rtype: Union[int, str] - """ - from s4ap.sims4communitylib.enums.strings_enum import CommonStringId - mapping = { - CommonGender.MALE: CommonStringId.MALE, - CommonGender.FEMALE: CommonStringId.FEMALE - } - if isinstance(value, int) and not isinstance(value, CommonGender): - value = CommonGender.convert_from_vanilla(value) - return mapping.get(value, value.name if hasattr(value, 'name') else str(value)) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_gender_preference_type.py b/Scripts/s4ap/sims4communitylib/enums/common_gender_preference_type.py deleted file mode 100644 index 0864ed1..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_gender_preference_type.py +++ /dev/null @@ -1,67 +0,0 @@ -""" -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 -""" -from typing import Dict, Union - -from sims.global_gender_preference_tuning import GenderPreferenceType -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonGenderPreferenceType(CommonInt): - """Custom Gender Preference Type enum. - - """ - INVALID: 'CommonGenderPreferenceType' = 0 - ROMANTIC: 'CommonGenderPreferenceType' = 1 - WOOHOO: 'CommonGenderPreferenceType' = 2 - - @staticmethod - def convert_to_vanilla(value: 'CommonGenderPreferenceType') -> Union[GenderPreferenceType, None]: - """convert_to_vanilla(value) - - Convert a CommonGenderPreferenceType into the vanilla GenderPreferenceType enum. - - :param value: An instance of Common Gender Preference Type - :type value: CommonGenderPreferenceType - :return: The specified CommonGenderPreferenceType translated to GenderPreferenceType or None if the value could not be translated. - :rtype: Union[GenderPreferenceType, None] - """ - if value is None or value == CommonGenderPreferenceType.INVALID: - return GenderPreferenceType.INVALID - if isinstance(value, GenderPreferenceType): - return value - conversion_mapping: Dict[CommonGenderPreferenceType, GenderPreferenceType] = { - CommonGenderPreferenceType.INVALID: GenderPreferenceType.INVALID, - CommonGenderPreferenceType.ROMANTIC: GenderPreferenceType.ROMANTIC, - CommonGenderPreferenceType.WOOHOO: GenderPreferenceType.WOOHOO, - } - return conversion_mapping.get(value, None) - - @staticmethod - def convert_from_vanilla(value: Union[int, GenderPreferenceType]) -> 'CommonGenderPreferenceType': - """convert_from_vanilla(value) - - Convert a vanilla GenderPreferenceType to a CommonGenderPreferenceType. - - :param value: An instance of Gender Preference Type - :type value: GenderPreferenceType - :return: The specified GenderPreferenceType translated to CommonGenderPreferenceType or INVALID if the value could not be translated. - :rtype: CommonGenderPreferenceType - """ - if value is None or value == GenderPreferenceType.INVALID: - return CommonGenderPreferenceType.INVALID - if isinstance(value, CommonGenderPreferenceType): - return value - conversion_mapping: Dict[int, CommonGenderPreferenceType] = { - int(GenderPreferenceType.INVALID): CommonGenderPreferenceType.INVALID, - int(GenderPreferenceType.ROMANTIC): CommonGenderPreferenceType.ROMANTIC, - int(GenderPreferenceType.WOOHOO): CommonGenderPreferenceType.WOOHOO - } - value = int(value) - if value not in conversion_mapping: - return CommonGenderPreferenceType.INVALID - return conversion_mapping[value] diff --git a/Scripts/s4ap/sims4communitylib/enums/common_ground_cover_type.py b/Scripts/s4ap/sims4communitylib/enums/common_ground_cover_type.py deleted file mode 100644 index 1b37bae..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_ground_cover_type.py +++ /dev/null @@ -1,78 +0,0 @@ -""" -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 -""" -from typing import Tuple, Union, Iterator - -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - -# noinspection PyBroadException -try: - from weather.weather_enums import GroundCoverType -except: - class GroundCoverType(CommonInt): - """Mock class.""" - RAIN_ACCUMULATION = 1002 - SNOW_ACCUMULATION = 1003 - - -class CommonGroundCoverType(CommonInt): - """Identifiers for ground cover types.""" - RAIN_ACCUMULATION: 'CommonGroundCoverType' = ... - SNOW_ACCUMULATION: 'CommonGroundCoverType' = ... - - @classmethod - def get_all(cls, exclude_values: Iterator['CommonGroundCoverType'] = ()) -> Tuple['CommonGroundCoverType']: - """get_all(exclude_values=()) - - Get a collection of all values. - - :param exclude_values: These values will be excluded. Default is an empty collection. - :type exclude_values: Iterator[CommonGroundCoverType], optional - :return: A collection of all values. - :rtype: Tuple[CommonGroundCoverType] - """ - # noinspection PyTypeChecker - value_list: Tuple[CommonGroundCoverType, ...] = tuple([value for value in cls.values if value not in exclude_values]) - return value_list - - @staticmethod - def convert_to_vanilla(value: 'CommonGroundCoverType') -> Union[GroundCoverType, None]: - """convert_to_vanilla(value) - - Convert a CommonGroundCoverType into the vanilla GroundCoverType enum. - - :param value: An instance of CommonGroundCoverType - :type value: CommonGroundCoverType - :return: The specified CommonGroundCoverType translated to GroundCoverType, or None if the value could not be translated. - :rtype: Union[GroundCoverType, None] - """ - if isinstance(value, GroundCoverType): - return value - mapping = { - CommonGroundCoverType.RAIN_ACCUMULATION: GroundCoverType.RAIN_ACCUMULATION, - CommonGroundCoverType.SNOW_ACCUMULATION: GroundCoverType.SNOW_ACCUMULATION - } - return mapping.get(value, None) - - @staticmethod - def convert_from_vanilla(value: GroundCoverType) -> Union['CommonGroundCoverType', None]: - """convert_from_vanilla(value) - - Convert a vanilla GroundCoverType into a CommonGroundCoverType enum. - - :param value: An instance of GroundCoverType - :type value: GroundCoverType - :return: The specified GroundCoverType translated to CommonGroundCoverType, or None if the value could not be translated. - :rtype: Union[CommonGroundCoverType, None] - """ - if isinstance(value, CommonGroundCoverType): - return value - mapping = { - GroundCoverType.RAIN_ACCUMULATION: CommonGroundCoverType.RAIN_ACCUMULATION, - GroundCoverType.SNOW_ACCUMULATION: CommonGroundCoverType.SNOW_ACCUMULATION - } - return mapping.get(value, None) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_key.py b/Scripts/s4ap/sims4communitylib/enums/common_key.py deleted file mode 100644 index f55e98e..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_key.py +++ /dev/null @@ -1,230 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonKey(CommonInt): - """Keys and their Key Codes for various keys on the keyboard. Currently recognizes Windows and Mac keys.""" - INVALID: 'CommonKey' = -1 - # Windows Keys - BACKSPACE: 'CommonKey' = 8 - TAB: 'CommonKey' = 9 - NUM_PAD_OFF_5: 'CommonKey' = 12 - ENTER: 'CommonKey' = 13 - SHIFT: 'CommonKey' = 16 # Can be used for both Left and Right SHIFT - CTRL: 'CommonKey' = 17 # Can be used for both Left and Right CTRL - ALT: 'CommonKey' = 18 # Can be used for both Left and Right ALT - PAUSE: 'CommonKey' = 19 - CAPS_LOCK: 'CommonKey' = 20 - ESCAPE: 'CommonKey' = 27 - SPACE: 'CommonKey' = 32 - PAGE_UP: 'CommonKey' = 33 - PAGE_DOWN: 'CommonKey' = 34 - END: 'CommonKey' = 35 - HOME: 'CommonKey' = 36 - ARROW_LEFT: 'CommonKey' = 37 - ARROW_UP: 'CommonKey' = 38 - ARROW_RIGHT: 'CommonKey' = 39 - ARROW_DOWN: 'CommonKey' = 40 - SYSTEM_REQUEST: 'CommonKey' = 44 - INSERT: 'CommonKey' = 45 - DELETE: 'CommonKey' = 46 - KEY_0: 'CommonKey' = 48 - KEY_1: 'CommonKey' = 49 - KEY_2: 'CommonKey' = 50 - KEY_3: 'CommonKey' = 51 - KEY_4: 'CommonKey' = 52 - KEY_5: 'CommonKey' = 53 - KEY_6: 'CommonKey' = 54 - KEY_7: 'CommonKey' = 55 - KEY_8: 'CommonKey' = 56 - KEY_9: 'CommonKey' = 57 - KEY_A: 'CommonKey' = 65 - KEY_B: 'CommonKey' = 66 - KEY_C: 'CommonKey' = 67 - KEY_D: 'CommonKey' = 68 - KEY_E: 'CommonKey' = 69 - KEY_F: 'CommonKey' = 70 - KEY_G: 'CommonKey' = 71 - KEY_H: 'CommonKey' = 72 - KEY_I: 'CommonKey' = 73 - KEY_J: 'CommonKey' = 74 - KEY_K: 'CommonKey' = 75 - KEY_L: 'CommonKey' = 76 - KEY_M: 'CommonKey' = 77 - KEY_N: 'CommonKey' = 78 - KEY_O: 'CommonKey' = 79 - KEY_P: 'CommonKey' = 80 - KEY_Q: 'CommonKey' = 81 - KEY_R: 'CommonKey' = 82 - KEY_S: 'CommonKey' = 83 - KEY_T: 'CommonKey' = 84 - KEY_U: 'CommonKey' = 85 - KEY_V: 'CommonKey' = 86 - KEY_W: 'CommonKey' = 87 - KEY_X: 'CommonKey' = 88 - KEY_Y: 'CommonKey' = 89 - KEY_Z: 'CommonKey' = 90 - WINDOWS_LEFT: 'CommonKey' = 91 - WINDOWS_RIGHT: 'CommonKey' = 92 - APPLICATIONS: 'CommonKey' = 93 - NUM_PAD_0: 'CommonKey' = 96 - NUM_PAD_1: 'CommonKey' = 97 - NUM_PAD_2: 'CommonKey' = 98 - NUM_PAD_3: 'CommonKey' = 99 - NUM_PAD_4: 'CommonKey' = 100 - NUM_PAD_5: 'CommonKey' = 101 - NUM_PAD_6: 'CommonKey' = 102 - NUM_PAD_7: 'CommonKey' = 103 - NUM_PAD_8: 'CommonKey' = 104 - NUM_PAD_9: 'CommonKey' = 105 - NUM_PAD_MULTIPLY: 'CommonKey' = 106 - NUM_PAD_ADD: 'CommonKey' = 107 - NUM_PAD_SUBTRACT: 'CommonKey' = 109 - NUM_PAD_DECIMAL: 'CommonKey' = 110 - NUM_PAD_DIVIDE: 'CommonKey' = 111 - NUM_PAD_ENTER: 'CommonKey' = 13 - F1: 'CommonKey' = 112 - F2: 'CommonKey' = 113 - F3: 'CommonKey' = 114 - F4: 'CommonKey' = 115 - F5: 'CommonKey' = 116 - F6: 'CommonKey' = 117 - F7: 'CommonKey' = 118 - F8: 'CommonKey' = 119 - F9: 'CommonKey' = 120 - F10: 'CommonKey' = 121 - F11: 'CommonKey' = 122 - F12: 'CommonKey' = 123 - NUM_LOCK: 'CommonKey' = 144 - SCROLL_LOCK: 'CommonKey' = 145 - EQUAL: 'CommonKey' = 187 - SHIFT_LEFT: 'CommonKey' = 160 - SHIFT_RIGHT: 'CommonKey' = 161 - CTRL_LEFT: 'CommonKey' = 162 - CTRL_RIGHT: 'CommonKey' = 163 - ALT_LEFT: 'CommonKey' = 164 - ALT_RIGHT: 'CommonKey' = 165 - SEMICOLON: 'CommonKey' = 186 - COMMA: 'CommonKey' = 188 - SUBTRACT: 'CommonKey' = 189 - PERIOD: 'CommonKey' = 190 - FORWARD_SLASH: 'CommonKey' = 191 - BACK_SLASH: 'CommonKey' = 220 - TILDE: 'CommonKey' = 192 - SQUARE_BRACKET_LEFT: 'CommonKey' = 219 - SQUARE_BRACKET_RIGHT: 'CommonKey' = 221 - SINGLE_QUOTE: 'CommonKey' = 222 - - # noinspection PyBroadException - try: - import os - if os.name != 'nt': - # Mac Keys - BACKSPACE: 'CommonKey' = 51 - TAB: 'CommonKey' = 48 - ENTER: 'CommonKey' = 36 - SHIFT: 'CommonKey' = 56 # Left Shift since Mac does not have a common key code - CTRL: 'CommonKey' = 55 - ALT: 'CommonKey' = 58 # Left Alt since Mac does not have a common key code - CAPS_LOCK: 'CommonKey' = 57 - ESCAPE: 'CommonKey' = 53 - SPACE: 'CommonKey' = 49 - PAGE_UP: 'CommonKey' = 116 - PAGE_DOWN: 'CommonKey' = 121 - END: 'CommonKey' = 119 - HOME: 'CommonKey' = 115 - ARROW_LEFT: 'CommonKey' = 123 - ARROW_UP: 'CommonKey' = 126 - ARROW_RIGHT: 'CommonKey' = 124 - ARROW_DOWN: 'CommonKey' = 125 - INSERT: 'CommonKey' = -1 # No insert key on Mac - DELETE: 'CommonKey' = 117 - KEY_0: 'CommonKey' = 29 - KEY_1: 'CommonKey' = 18 - KEY_2: 'CommonKey' = 19 - KEY_3: 'CommonKey' = 20 - KEY_4: 'CommonKey' = 21 - KEY_5: 'CommonKey' = 23 - KEY_6: 'CommonKey' = 22 - KEY_7: 'CommonKey' = 26 - KEY_8: 'CommonKey' = 28 - KEY_9: 'CommonKey' = 25 - KEY_A: 'CommonKey' = 0 - KEY_B: 'CommonKey' = 11 - KEY_C: 'CommonKey' = 8 - KEY_D: 'CommonKey' = 2 - KEY_E: 'CommonKey' = 14 - KEY_F: 'CommonKey' = 3 - KEY_G: 'CommonKey' = 5 - KEY_H: 'CommonKey' = 4 - KEY_I: 'CommonKey' = 34 - KEY_J: 'CommonKey' = 38 - KEY_K: 'CommonKey' = 40 - KEY_L: 'CommonKey' = 37 - KEY_M: 'CommonKey' = 46 - KEY_N: 'CommonKey' = 45 - KEY_O: 'CommonKey' = 31 - KEY_P: 'CommonKey' = 35 - KEY_Q: 'CommonKey' = 12 - KEY_R: 'CommonKey' = 15 - KEY_S: 'CommonKey' = 1 - KEY_T: 'CommonKey' = 17 - KEY_U: 'CommonKey' = 32 - KEY_V: 'CommonKey' = 9 - KEY_W: 'CommonKey' = 13 - KEY_Y: 'CommonKey' = 16 - KEY_X: 'CommonKey' = 7 - KEY_Z: 'CommonKey' = 6 - NUM_PAD_0: 'CommonKey' = 82 - NUM_PAD_1: 'CommonKey' = 83 - NUM_PAD_2: 'CommonKey' = 84 - NUM_PAD_3: 'CommonKey' = 85 - NUM_PAD_4: 'CommonKey' = 86 - NUM_PAD_5: 'CommonKey' = 87 - NUM_PAD_6: 'CommonKey' = 88 - NUM_PAD_7: 'CommonKey' = 89 - NUM_PAD_8: 'CommonKey' = 91 - NUM_PAD_9: 'CommonKey' = 92 - NUM_PAD_MULTIPLY: 'CommonKey' = 67 - NUM_PAD_ADD: 'CommonKey' = 69 - NUM_PAD_SUBTRACT: 'CommonKey' = 78 - NUM_PAD_DECIMAL: 'CommonKey' = 65 - NUM_PAD_DIVIDE: 'CommonKey' = 75 - NUM_PAD_ENTER: 'CommonKey' = 76 - F1: 'CommonKey' = 122 - F2: 'CommonKey' = 120 - F3: 'CommonKey' = 99 - F4: 'CommonKey' = 118 - F5: 'CommonKey' = 96 - F6: 'CommonKey' = 97 - F7: 'CommonKey' = 98 - F8: 'CommonKey' = 100 - F9: 'CommonKey' = 101 - F10: 'CommonKey' = 109 - F11: 'CommonKey' = 103 - F12: 'CommonKey' = 111 - EQUAL: 'CommonKey' = 24 - SHIFT_LEFT: 'CommonKey' = 56 - SHIFT_RIGHT: 'CommonKey' = 60 - CTRL_LEFT: 'CommonKey' = 55 - CTRL_RIGHT: 'CommonKey' = 55 - ALT_LEFT: 'CommonKey' = 58 - ALT_RIGHT: 'CommonKey' = 61 - SEMICOLON: 'CommonKey' = 41 - COMMA: 'CommonKey' = 43 - SUBTRACT: 'CommonKey' = 27 - PERIOD: 'CommonKey' = 47 - FORWARD_SLASH: 'CommonKey' = 44 - BACK_SLASH: 'CommonKey' = 42 - TILDE: 'CommonKey' = 50 - SQUARE_BRACKET_LEFT: 'CommonKey' = 33 - SQUARE_BRACKET_RIGHT: 'CommonKey' = 30 - SINGLE_QUOTE: 'CommonKey' = 39 - except: - pass diff --git a/Scripts/s4ap/sims4communitylib/enums/common_object_delivery_method.py b/Scripts/s4ap/sims4communitylib/enums/common_object_delivery_method.py deleted file mode 100644 index 45e48c9..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_object_delivery_method.py +++ /dev/null @@ -1,109 +0,0 @@ -""" -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 -""" -from typing import Iterator, Tuple - -from interactions.base.picker_interaction import PickerInteractionDeliveryMethod -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonObjectDeliveryMethod(CommonInt): - """A method of delivery for objects.""" - NONE: 'CommonObjectDeliveryMethod' = ... - DELIVERY_SERVICE: 'CommonObjectDeliveryMethod' = ... - INVENTORY: 'CommonObjectDeliveryMethod' = ... - MAIL: 'CommonObjectDeliveryMethod' = ... - - @classmethod - def get_all(cls, exclude_values: Iterator['CommonObjectDeliveryMethod'] = None) -> Tuple['CommonObjectDeliveryMethod']: - """get_all(exclude_values=None) - - Get a collection of all values. - - :param exclude_values: These values will be excluded. If set to None, NONE will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonObjectDeliveryMethod], optional - :return: A collection of all values. - :rtype: Tuple[CommonObjectDeliveryMethod] - """ - if exclude_values is None: - exclude_values = (cls.NONE,) - # noinspection PyTypeChecker - value_list: Tuple[CommonObjectDeliveryMethod, ...] = tuple([value for value in cls.values if value not in exclude_values]) - return value_list - - @classmethod - def get_all_names(cls, exclude_values: Iterator['CommonObjectDeliveryMethod'] = None) -> Tuple[str]: - """get_all_names(exclude_values=None) - - Retrieve a collection of the names of all values. - - :param exclude_values: These values will be excluded. If set to None, NONE will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonObjectDeliveryMethod], optional - :return: A collection of the names of all values. - :rtype: Tuple[str] - """ - name_list: Tuple[str] = tuple([value.name for value in cls.get_all(exclude_values=exclude_values)]) - return name_list - - @classmethod - def get_comma_separated_names_string(cls, exclude_values: Iterator['CommonObjectDeliveryMethod'] = None) -> str: - """get_comma_separated_names_string(exclude_values=None) - - Create a string containing all names of all values, separated by a comma. - - :param exclude_values: These values will be excluded. If set to None, NONE will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonObjectDeliveryMethod], optional - :return: A string containing all names of all values, separated by a comma. - :rtype: str - """ - return ', '.join(cls.get_all_names(exclude_values=exclude_values)) - - @staticmethod - def convert_to_vanilla(value: 'CommonObjectDeliveryMethod') -> PickerInteractionDeliveryMethod: - """convert_to_vanilla(value) - - Convert a value into the vanilla PickerInteractionDeliveryMethod enum. - - :param value: An instance of CommonObjectDeliveryMethod - :type value: CommonObjectDeliveryMethod - :return: The specified value translated to PickerInteractionDeliveryMethod or INVENTORY if the value could not be translated. - :rtype: PickerInteractionDeliveryMethod - """ - if value is None or value == CommonObjectDeliveryMethod.NONE: - return PickerInteractionDeliveryMethod.INVENTORY - if isinstance(value, PickerInteractionDeliveryMethod): - # noinspection PyTypeChecker - return value - mapping = { - CommonObjectDeliveryMethod.INVENTORY: PickerInteractionDeliveryMethod.INVENTORY, - CommonObjectDeliveryMethod.MAIL: PickerInteractionDeliveryMethod.MAILMAN, - CommonObjectDeliveryMethod.DELIVERY_SERVICE: PickerInteractionDeliveryMethod.DELIVERY_SERVICE_NPC, - } - return mapping.get(value, PickerInteractionDeliveryMethod.INVENTORY) - - @staticmethod - def convert_from_vanilla(value: PickerInteractionDeliveryMethod) -> 'CommonObjectDeliveryMethod': - """convert_from_vanilla(value) - - Convert a value into a CommonObjectDeliveryMethod enum. - - :param value: An instance of PickerInteractionDeliveryMethod - :type value: PickerInteractionDeliveryMethod - :return: The specified value translated to CommonObjectDeliveryMethod or INVENTORY if the value could not be translated. - :rtype: CommonObjectDeliveryMethod - """ - if value is None or value == CommonObjectDeliveryMethod.NONE: - return PickerInteractionDeliveryMethod.INVENTORY - if isinstance(value, PickerInteractionDeliveryMethod): - # noinspection PyTypeChecker - return value - mapping = { - PickerInteractionDeliveryMethod.INVENTORY: CommonObjectDeliveryMethod.INVENTORY, - PickerInteractionDeliveryMethod.MAILMAN: CommonObjectDeliveryMethod.MAIL, - PickerInteractionDeliveryMethod.DELIVERY_SERVICE_NPC: CommonObjectDeliveryMethod.DELIVERY_SERVICE, - } - return mapping.get(value, CommonObjectDeliveryMethod.INVENTORY) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_object_filter_type.py b/Scripts/s4ap/sims4communitylib/enums/common_object_filter_type.py deleted file mode 100644 index e505cea..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_object_filter_type.py +++ /dev/null @@ -1,15 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonObjectFilterType(CommonInt): - """The type of an object filter.""" - OBJECT_DEFINITION_FILTER = 0 - OBJECT_TAG_FILTER = 1 - CUSTOM = 5000 diff --git a/Scripts/s4ap/sims4communitylib/enums/common_object_preference_tag.py b/Scripts/s4ap/sims4communitylib/enums/common_object_preference_tag.py deleted file mode 100644 index 0c5d814..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_object_preference_tag.py +++ /dev/null @@ -1,23 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonObjectPreferenceTag(CommonInt): - """ Object preference tags. """ - INVALID: 'CommonObjectPreferenceTag' = -1 - LOVESEAT: 'CommonObjectPreferenceTag' = 0 - BED: 'CommonObjectPreferenceTag' = 1 - STUFFED_ANIMAL: 'CommonObjectPreferenceTag' = 2 - INSTRUMENT: 'CommonObjectPreferenceTag' = 3 - COMPUTER: 'CommonObjectPreferenceTag' = 4 - FOOD: 'CommonObjectPreferenceTag' = 5 - DRINK: 'CommonObjectPreferenceTag' = 6 - TENT: 'CommonObjectPreferenceTag' = 7 - FOOD_BOWL: 'CommonObjectPreferenceTag' = 8 - PET_SLEEP_OBJECT: 'CommonObjectPreferenceTag' = 9 diff --git a/Scripts/s4ap/sims4communitylib/enums/common_object_quality.py b/Scripts/s4ap/sims4communitylib/enums/common_object_quality.py deleted file mode 100644 index 6807474..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_object_quality.py +++ /dev/null @@ -1,55 +0,0 @@ -""" -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 -""" -from typing import Tuple, Iterator - -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonObjectQuality(CommonInt): - """Various types of object quality.""" - POOR: 'CommonObjectQuality' = ... - NORMAL: 'CommonObjectQuality' = ... - OUTSTANDING: 'CommonObjectQuality' = ... - - @classmethod - def get_all(cls, exclude_values: Iterator['CommonObjectQuality'] = ()) -> Tuple['CommonObjectQuality']: - """get_all(exclude_values=()) - - Get a collection of all values. - - :param exclude_values: These values will be excluded. Default is an empty collection. - :type exclude_values: Iterator[CommonObjectQuality], optional - :return: A collection of all values. - :rtype: Tuple[CommonObjectQuality] - """ - # noinspection PyTypeChecker - value_list: Tuple[CommonObjectQuality, ...] = tuple([value for value in cls.values if value not in exclude_values]) - return value_list - - @classmethod - def get_all_names(cls, exclude_values: Iterator['CommonObjectQuality'] = ()) -> Tuple[str]: - """get_all_names(exclude_values=()) - - Retrieve a collection of the names of all values. - - :return: A collection of the names of all values. - :rtype: Tuple[str] - """ - name_list: Tuple[str] = tuple([value.name for value in cls.get_all(exclude_values=exclude_values)]) - return name_list - - @classmethod - def get_comma_separated_names_string(cls, exclude_values: Iterator['CommonObjectQuality'] = ()) -> str: - """get_comma_separated_names_string(exclude_values=()) - - Create a string containing all names of all values, separated by a comma. - - :return: A string containing all names of all values, separated by a comma. - :rtype: str - """ - return ', '.join(cls.get_all_names(exclude_values=exclude_values)) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_object_slot_name_ids.py b/Scripts/s4ap/sims4communitylib/enums/common_object_slot_name_ids.py deleted file mode 100644 index cb5e4f1..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_object_slot_name_ids.py +++ /dev/null @@ -1,13 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonObjectSlotNameId(CommonInt): - """The string identifiers of slot names of objects.""" - DECORATION_SMALL_2 = 0xC8DB9C09 # DECO_SML_2 diff --git a/Scripts/s4ap/sims4communitylib/enums/common_object_state_ids.py b/Scripts/s4ap/sims4communitylib/enums/common_object_state_ids.py deleted file mode 100644 index 21d1eaf..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_object_state_ids.py +++ /dev/null @@ -1,14 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonObjectStateId(CommonInt): - """Identifier for object states. In most cases you will want to use CommonObjectStateValueId instead!""" - COMPUTER = 15102 - QUALITY = 15303 diff --git a/Scripts/s4ap/sims4communitylib/enums/common_object_state_value_ids.py b/Scripts/s4ap/sims4communitylib/enums/common_object_state_value_ids.py deleted file mode 100644 index 0d72113..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_object_state_value_ids.py +++ /dev/null @@ -1,33 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonObjectStateValueId(CommonInt): - """Identifier for object state values.""" - MURPHY_BED_OPEN = 228113 - MURPHY_BED_CLOSED = 228114 - COMPUTER_GAME_MARIA_SISTERS = 32922 - COMPUTER_SPACE_WOOHOO = 96857 - COMPUTER_OFF = 15106 - QUALITY_NORMAL = 15304 - QUALITY_OUTSTANDING = 15305 - QUALITY_POOR = 15306 - WASH_TUB_FUNCTIONS_EMPTY = 176816 - WASH_TUB_FUNCTIONS_WASHING = 176817 - WASH_TUB_FUNCTIONS_WATER_DIRTY = 177286 - WASH_TUB_FUNCTIONS_WATER_CLEAN = 177285 - WASH_TUB_LOAD_PROGRESS_DONE = 179510 - WASH_TUB_LOAD_PROGRESS_INCOMPLETE = 179511 - - PREGNANT_IN_LABOR = 75273 - PREGNANT_FIRST_TRIMESTER = 15298 - PREGNANT_SECOND_TRIMESTER = 15301 - PREGNANT_THIRD_TRIMESTER = 15302 - PREGNANT_NOT_SHOWING = 15300 - PREGNANT_NOT_PREGNANT = 15299 diff --git a/Scripts/s4ap/sims4communitylib/enums/common_occult_type.py b/Scripts/s4ap/sims4communitylib/enums/common_occult_type.py deleted file mode 100644 index 4e5aabf..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_occult_type.py +++ /dev/null @@ -1,175 +0,0 @@ -""" -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 -""" -from typing import Union, Tuple, Iterator, Dict - -from protocolbuffers.Localization_pb2 import LocalizedString -from sims.occult.occult_enums import OccultType -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId - - -class CommonOccultType(CommonInt): - """Custom Occult Types enum containing all occults. DLC not required. - - """ - NONE: 'CommonOccultType' = ... - ALIEN: 'CommonOccultType' = ... - GHOST: 'CommonOccultType' = ... - MERMAID: 'CommonOccultType' = ... - NON_OCCULT: 'CommonOccultType' = ... - PLANT_SIM: 'CommonOccultType' = ... - ROBOT: 'CommonOccultType' = ... - SCARECROW: 'CommonOccultType' = ... - SKELETON: 'CommonOccultType' = ... - VAMPIRE: 'CommonOccultType' = ... - WEREWOLF: 'CommonOccultType' = ... - WITCH: 'CommonOccultType' = ... - - @classmethod - def get_all(cls, exclude_occult_types: Iterator['CommonOccultType'] = None) -> Tuple['CommonOccultType']: - """get_all(exclude_occult_types=None) - - Get a collection of all values. - - :param exclude_occult_types: These values will be excluded. If set to None, NONE will be excluded automatically. Default is None. - :type exclude_occult_types: Iterator[CommonOccultType], optional - :return: A collection of all CommonOccultType, without CommonOccultType.NONE. - :rtype: Tuple[CommonOccultType] - """ - if exclude_occult_types is None: - exclude_occult_types = (cls.NONE,) - # noinspection PyTypeChecker - value_list: Tuple[CommonOccultType] = tuple([value for value in cls.values if value not in exclude_occult_types]) - return value_list - - @classmethod - def get_all_names(cls, exclude_occult_types: Iterator['CommonOccultType'] = None) -> Tuple[str]: - """get_all_names(exclude_occult_types=None) - - Retrieve a collection of the names of all values. - - :param exclude_occult_types: These values will be excluded. If set to None, NONE will be excluded automatically. Default is None. - :type exclude_occult_types: Iterator[CommonOccultType], optional - :return: A collection of the names of all values. - :rtype: Tuple[str] - """ - name_list: Tuple[str] = tuple([value.name for value in cls.get_all(exclude_occult_types=exclude_occult_types)]) - return name_list - - @classmethod - def get_comma_separated_names_string(cls, exclude_occult_types: Iterator['CommonOccultType'] = None) -> str: - """get_comma_separated_names_string(exclude_occult_types=None) - - Create a string containing all names of all values, separated by a comma. - - :param exclude_occult_types: These values will be excluded. If set to None, NONE will be excluded automatically. Default is None. - :type exclude_occult_types: Iterator[CommonOccultType], optional - :return: A string containing all names of all values, separated by a comma. - :rtype: str - """ - return ', '.join(cls.get_all_names(exclude_occult_types=exclude_occult_types)) - - @staticmethod - def determine_occult_type(sim_info: SimInfo) -> 'CommonOccultType': - """determine_occult_type(sim_info) - - Determine the type of Occult a Sim is. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The CommonOccultType that represents what a Sim is. - :rtype: CommonOccultType - """ - from s4ap.sims4communitylib.utils.sims.common_sim_occult_type_utils import CommonSimOccultTypeUtils - return CommonSimOccultTypeUtils.determine_occult_type(sim_info) - - @staticmethod - def determine_current_occult_type(sim_info: SimInfo) -> 'CommonOccultType': - """determine_current_occult_type(sim_info) - - Determine the type of Occult a Sim is currently appearing as. - i.e. A mermaid with their tail out would currently be a MERMAID. But a Mermaid Sim with no tail out would currently be a CommonOccultType.NONE - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The CommonOccultType the Sim is currently appearing as, or CommonOccultType.NONE if they are not appearing as any Occult or are appearing as their HUMAN disguise/occult. - :rtype: CommonOccultType - """ - from s4ap.sims4communitylib.utils.sims.common_sim_occult_type_utils import CommonSimOccultTypeUtils - return CommonSimOccultTypeUtils.determine_current_occult_type(sim_info) - - @staticmethod - def convert_to_vanilla(occult_type: 'CommonOccultType') -> Union[OccultType, None]: - """convert_to_vanilla(occult_type) - - Convert a CommonOccultType into the vanilla OccultType enum. - - .. note:: Not all CommonOccultTypes have an OccultType to convert to! They will return None in those cases! (Ghost, Plant Sim, Robot, Skeleton) - - :param occult_type: An instance of CommonOccultType - :type occult_type: CommonOccultType - :return: The specified CommonOccultType translated to OccultType, or None if the value could not be translated. - :rtype: Union[OccultType, None] - """ - from s4ap.sims4communitylib.utils.sims.common_sim_occult_type_utils import CommonSimOccultTypeUtils - return CommonSimOccultTypeUtils.convert_custom_type_to_vanilla(occult_type) - - @staticmethod - def convert_from_vanilla(value: Union[OccultType, 'CommonOccultType', int]) -> Union['CommonOccultType', OccultType, int]: - """convert_from_vanilla(value) - - Convert a vanilla value into this enum. - - :param value: The value to convert. - :type value: Union[OccultType, 'CommonOccultType', int] - :return: The specified value translated to CommonOccultType. The value will be returned if it cannot be translated. - :rtype: Union['CommonOccultType', OccultType, int] - """ - mapping: Dict[OccultType, CommonOccultType] = dict() - if hasattr(OccultType, 'HUMAN'): - mapping[OccultType.HUMAN] = CommonOccultType.NON_OCCULT - if hasattr(OccultType, 'ALIEN'): - mapping[OccultType.ALIEN] = CommonOccultType.ALIEN - if hasattr(OccultType, 'VAMPIRE'): - mapping[OccultType.VAMPIRE] = CommonOccultType.VAMPIRE - if hasattr(OccultType, 'MERMAID'): - mapping[OccultType.MERMAID] = CommonOccultType.MERMAID - if hasattr(OccultType, 'WITCH'): - mapping[OccultType.WITCH] = CommonOccultType.WITCH - if hasattr(OccultType, 'WEREWOLF'): - mapping[OccultType.WEREWOLF] = CommonOccultType.WEREWOLF - return mapping.get(value, value) - - @staticmethod - def convert_to_localized_string_id(value: 'CommonOccultType') -> Union[int, str, CommonStringId, LocalizedString]: - """convert_to_localized_string_id(value) - - Convert a CommonOccultType into a Localized String identifier. - - :param value: An instance of a CommonOccultType - :type value: CommonOccultType - :return: The specified CommonOccultType translated to a localized string identifier. If no localized string id is found, the name property of the value will be used instead. - :rtype: Union[int, str, CommonStringId, LocalizedString] - """ - mapping: Dict[CommonOccultType, CommonStringId] = { - CommonOccultType.NONE: CommonStringId.S4CL_NONE, - CommonOccultType.ALIEN: CommonStringId.S4CL_ALIEN, - CommonOccultType.MERMAID: CommonStringId.S4CL_MERMAID, - CommonOccultType.ROBOT: CommonStringId.S4CL_ROBOT, - CommonOccultType.SCARECROW: CommonStringId.S4CL_SCARECROW, - CommonOccultType.SKELETON: CommonStringId.S4CL_SKELETON, - CommonOccultType.VAMPIRE: CommonStringId.S4CL_VAMPIRE, - CommonOccultType.WITCH: CommonStringId.S4CL_WITCH, - CommonOccultType.PLANT_SIM: CommonStringId.S4CL_PLANT_SIM, - CommonOccultType.GHOST: CommonStringId.S4CL_GHOST, - CommonOccultType.WEREWOLF: CommonStringId.S4CL_WEREWOLF, - CommonOccultType.NON_OCCULT: CommonStringId.S4CL_NON_OCCULT, - } - - return mapping.get(value, value.name if hasattr(value, 'name') else str(value)) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_posture_id.py b/Scripts/s4ap/sims4communitylib/enums/common_posture_id.py deleted file mode 100644 index b8481e1..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_posture_id.py +++ /dev/null @@ -1,186 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonPostureId(CommonInt): - """Identifiers for postures.""" - ALIEN_PORTAL: 'CommonPostureId' = 110849 - ARCADE_MACHINE: 'CommonPostureId' = 127556 - BAR_MAKE_DRINK: 'CommonPostureId' = 15514 - BATHTUB_TODDLER_BATH: 'CommonPostureId' = 143802 - BATHTUB_TAKE_BATH: 'CommonPostureId' = 15515 - BATHTUB_BUBBLE_BATH: 'CommonPostureId' = 35351 - BATHTUB_PET_BATH: 'CommonPostureId' = 165598 - BE_CARRIED: 'CommonPostureId' = 132262 - CARRY_SIM: 'CommonPostureId' = 132169 - CAVE_WOOHOO: 'CommonPostureId' = 252479 - BEACH_CAVE: 'CommonPostureId' = 210419 - BEACH_TOWEL: 'CommonPostureId' = 208930 - BED_NAP: 'CommonPostureId' = 15517 - BED_RELAX: 'CommonPostureId' = 15518 - BED_SLEEP: 'CommonPostureId' = 15519 - BED_UNDER_COVERS: 'CommonPostureId' = 33972 - BED_WOOHOO: 'CommonPostureId' = 15520 - BONFIRE_STAND_INTIMATE: 'CommonPostureId' = 126186 - BOOKING_STATION: 'CommonPostureId' = 109496 - BUSH: 'CommonPostureId' = 124832 - BUSH_FERTILIZE_STANDING: 'CommonPostureId' = 127097 - BUSH_WOOHOO: 'CommonPostureId' = 125220 - CARRY_NOTHING: 'CommonPostureId' = 15521 - CARRY_OBJECT: 'CommonPostureId' = 15522 - CLOSET: 'CommonPostureId' = 121953 - CLOSET_WOOHOO: 'CommonPostureId' = 123382 - COFFIN_SLEEP: 'CommonPostureId' = 149837 - COFFIN_WOOHOO: 'CommonPostureId' = 154863 - COOK: 'CommonPostureId' = 15525 - DANCE: 'CommonPostureId' = 15526 - DANCE_FLOOR: 'CommonPostureId' = 124490 - DART_BOARD: 'CommonPostureId' = 127819 - DENIZEN_SWIMS: 'CommonPostureId' = 200577 - DJ_BOOTH: 'CommonPostureId' = 121363 - DUMPSTER_NAP: 'CommonPostureId' = 239034 - DUMPSTER_WOOHOO: 'CommonPostureId' = 234105 - FLOATING: 'CommonPostureId' = 207354 - FOOSBALL_TABLE: 'CommonPostureId' = 121523 - FOUNTAIN: 'CommonPostureId' = 131552 - FOX_STEAL_EGG: 'CommonPostureId' = 267029 - GRILL: 'CommonPostureId' = 35023 - GROUP_DANCE: 'CommonPostureId' = 129321 - GROUP_DANCING: 'CommonPostureId' = 278187 - GROUP_WORKOUT_DANCE: 'CommonPostureId' = 166807 - GROUP_WORKOUT_POWER_SCULPT: 'CommonPostureId' = 164935 - HAIR_MAKE_UP_CHAIR_HAIR: 'CommonPostureId' = 189778 - HAIR_MAKE_UP_CHAIR_MAKE_UP: 'CommonPostureId' = 189779 - HIDE_UNDER_OBJECT: 'CommonPostureId' = 174205 - HOLDING_CELL_DOOR: 'CommonPostureId' = 109798 - HOSPITAL_EXAM_BED_RECLINE: 'CommonPostureId' = 107794 - HOSPITAL_EXAM_BED_SIT: 'CommonPostureId' = 107793 - HOSPITAL_EXAM_BED_STAND: 'CommonPostureId' = 110594 - HOSPITAL_TREADMILL_DOCTOR: 'CommonPostureId' = 111461 - HOSPITAL_TREADMILL_PATIENT_WAIT: 'CommonPostureId' = 111957 - HOT_SPRINGS_SIT: 'CommonPostureId' = 247297 - HOT_SPRINGS_STAND: 'CommonPostureId' = 247298 - HOT_SPRINGS_WOOHOO: 'CommonPostureId' = 247299 - HOT_TUB_SIT: 'CommonPostureId' = 117257 - HOT_TUB_STAND: 'CommonPostureId' = 117256 - HOT_TUB_WOOHOO: 'CommonPostureId' = 117782 - HUMANOID_ROBOT_ACTIVATE: 'CommonPostureId' = 229263 - HUMANOID_ROBOT_BROKEN: 'CommonPostureId' = 228705 - HUMANOID_ROBOT_POWERED_DOWN: 'CommonPostureId' = 229690 - HUMANOID_ROBOT_STASIS_SIT: 'CommonPostureId' = 228808 - HUMANOID_ROBOT_STASIS_STAND: 'CommonPostureId' = 228802 - ICE_SKATE: 'CommonPostureId' = 172634 - ISLAND_CANOE: 'CommonPostureId' = 206337 - ISLAND_CANOE_SIT: 'CommonPostureId' = 208298 - ISLAND_CANOE_STAND: 'CommonPostureId' = 208299 - ISLAND_WATERFALL_PLAY: 'CommonPostureId' = 207479 - ISLAND_WATERFALL_WOOHOO: 'CommonPostureId' = 207291 - JUICE_KEG_KEG_STAND: 'CommonPostureId' = 208473 - JUMP_STAND: 'CommonPostureId' = 128689 - JUNGLE_GYM: 'CommonPostureId' = 36915 - KARAOKE_MACHINE: 'CommonPostureId' = 137354 - KIDDIE_POOL_GIVE_POOL: 'CommonPostureId' = 188318 - KIDDIE_POOL_LOUNGE: 'CommonPostureId' = 188578 - KID_TENT: 'CommonPostureId' = 259639 - KNEEL: 'CommonPostureId' = 15527 - LAY_DOWN: 'CommonPostureId' = 161631 - LAY_DOWN_ON_GROUND: 'CommonPostureId' = 124535 - LIVESTOCK_PEN: 'CommonPostureId' = 263848 - LIVESTOCK_PEN_WOOHOO: 'CommonPostureId' = 263110 - LEAF_PILE_WOOHOO: 'CommonPostureId' = 185751 - LIGHTHOUSE_WOOHOO: 'CommonPostureId' = 172241 - LOUNGE_CHAIR: 'CommonPostureId' = 207639 - MASSAGE_CHAIR_FOOT_MASSAGE_LEFT: 'CommonPostureId' = 120080 - MASSAGE_CHAIR_FOOT_MASSAGE_RIGHT: 'CommonPostureId' = 120081 - MASSAGE_CHAIR_RECLINED: 'CommonPostureId' = 119303 - MASSAGE_TABLE_CUSTOMER: 'CommonPostureId' = 117578 - MASSAGE_TABLE_THERAPIST: 'CommonPostureId' = 120212 - MEDITATE_LEVITATION: 'CommonPostureId' = 118964 - MEDITATE_MEDITATION: 'CommonPostureId' = 118962 - MICROSCOPE: 'CommonPostureId' = 10477 - MONKEY_BARS_HANG_OUT: 'CommonPostureId' = 15529 - MONKEY_BARS_PLAY: 'CommonPostureId' = 15530 - MOTION_BASED_GAMING: 'CommonPostureId' = 37063 - MOVING_STAND: 'CommonPostureId' = 30530 - OBSERVATORY: 'CommonPostureId' = 34816 - PAIRED_DANCING: 'CommonPostureId' = 272515 - PET_INTIMATE: 'CommonPostureId' = 164333 - PING_PONG_READY_STANCE: 'CommonPostureId' = 212553 - PODIUM_PAIR_DEBATE: 'CommonPostureId' = 221261 - POTTY_CHAIR_SIT: 'CommonPostureId' = 144863 - PUBLIC_BATHROOM: 'CommonPostureId' = 38367 - PUNCHING_BAG: 'CommonPostureId' = 10254 - PUPPET_THEATER: 'CommonPostureId' = 135680 - RABBIT_HOLE_BRAMBLE: 'CommonPostureId' = 102995 - RABBIT_HOLE_CAVE: 'CommonPostureId' = 99237 - RABBIT_HOLE_EURO_BRAMBLE: 'CommonPostureId' = 126039 - RABBIT_HOLE_TREE: 'CommonPostureId' = 98538 - RELAXING_BATH: 'CommonPostureId' = 120382 - ROCKET_SHIP: 'CommonPostureId' = 34856 - ROCKET_SHIP_WOOHOO: 'CommonPostureId' = 15531 - ROLLER_SKATE: 'CommonPostureId' = 182936 - SHOWER: 'CommonPostureId' = 15532 - SHOWER_CLEAN: 'CommonPostureId' = 15533 - SHOWER_WOOHOO: 'CommonPostureId' = 227360 - SIT: 'CommonPostureId' = 15535 - SIT_INTIMATE: 'CommonPostureId' = 15536 - SIT_INTIMATE_BOOTH: 'CommonPostureId' = 131139 - SIT_IN_TODDLER_HIGH_CHAIR: 'CommonPostureId' = 135522 - SIT_LOUNGE_FLOAT: 'CommonPostureId' = 210552 - SIT_ON_GROUND: 'CommonPostureId' = 134340 - SIT_POOL_EDGE: 'CommonPostureId' = 103374 - SIT_TOGETHER: 'CommonPostureId' = 131565 - SIT_CHAISE: 'CommonPostureId' = 260053 - SIT_KOTATSU: 'CommonPostureId' = 247766 - SIT_ROBOT_VACUUM: 'CommonPostureId' = 170752 - SIT_ROCKING_CHAIR: 'CommonPostureId' = 240809 - SLEEPING_POD_SLEEP: 'CommonPostureId' = 200051 - SLEEPING_POD_WOOHOO: 'CommonPostureId' = 200543 - SMALL_TELESCOPE: 'CommonPostureId' = 292843 - SNOW_SPORTS_SLOPE_SKI: 'CommonPostureId' = 237666 - SNOW_SPORTS_SLOPE_SLED: 'CommonPostureId' = 246810 - SNOW_SPORTS_SLOPE_SLED_TOGETHER: 'CommonPostureId' = 238052 - SNOW_SPORTS_SLOPE_SNOWBOARD: 'CommonPostureId' = 246792 - SOFA_NAP: 'CommonPostureId' = 28879 - STAND: 'CommonPostureId' = 15537 - STAND_EXCLUSIVE: 'CommonPostureId' = 23832 - STAND_ON_OBJECT: 'CommonPostureId' = 158065 - STARGAZE: 'CommonPostureId' = 104171 - STEAM_ROOM_SIT: 'CommonPostureId' = 120222 - STEAM_ROOM_WOOHOO: 'CommonPostureId' = 119528 - SURGERY_TABLE_DOCTOR_STAND: 'CommonPostureId' = 110016 - SURGERY_TABLE_PATIENT_RECLINE: 'CommonPostureId' = 110017 - SWIM: 'CommonPostureId' = 39398 - SWING_SET: 'CommonPostureId' = 186153 - TELESCOPE_WOOHOO: 'CommonPostureId' = 15538 - TENT: 'CommonPostureId' = 103267 - TENT_WOOHOO: 'CommonPostureId' = 103266 - TODDLER_JUNGLE_GYM_BALL_PIT: 'CommonPostureId' = 170635 - TODDLER_JUNGLE_GYM_SLIDE: 'CommonPostureId' = 170664 - TODDLER_JUNGLE_GYM_TUNNELS: 'CommonPostureId' = 170645 - TOILET_SIT: 'CommonPostureId' = 15539 - TOILET_SIT_STALL: 'CommonPostureId' = 214050 - TOILET_STAND: 'CommonPostureId' = 15540 - TOILET_STAND_STALL: 'CommonPostureId' = 214049 - TREADMILL: 'CommonPostureId' = 15541 - VEHICLE_BIKE_SIT: 'CommonPostureId' = 209143 - WALK_IN_SAFE_WOOHOO: 'CommonPostureId' = 193829 - WARDROBE_PEDESTAL: 'CommonPostureId' = 191328 - WATCH_INTIMATE: 'CommonPostureId' = 129111 - WATER_SCOOTER: 'CommonPostureId' = 199821 - WEDDING_CAKE_CUT_TOGETHER: 'CommonPostureId' = 276773 - WEDDING_AISLE_RUNNER_WALK_TOGETHER: 'CommonPostureId' = 275168 - WORKOUT_MACHINE: 'CommonPostureId' = 15542 - XRAY_MACHINE_SCAN_DOCTOR: 'CommonPostureId' = 109936 - XRAY_MACHINE_SCAN_PATIENT: 'CommonPostureId' = 105968 - YOGA: 'CommonPostureId' = 117358 - VET_EXAM_TABLE_PET: 'CommonPostureId' = 165261 - VET_EXAM_TABLE_VET: 'CommonPostureId' = 165262 - VET_SURGERY_PET: 'CommonPostureId' = 171965 - VET_SURGERY_VET: 'CommonPostureId' = 166573 diff --git a/Scripts/s4ap/sims4communitylib/enums/common_precipitation_type.py b/Scripts/s4ap/sims4communitylib/enums/common_precipitation_type.py deleted file mode 100644 index 257350b..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_precipitation_type.py +++ /dev/null @@ -1,78 +0,0 @@ -""" -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 -""" -from typing import Tuple, Union, Iterator - -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - -# noinspection PyBroadException -try: - from weather.weather_enums import PrecipitationType -except: - class PrecipitationType(CommonInt): - """Mock class.""" - RAIN = 1000 - SNOW = 1001 - - -class CommonPrecipitationType(CommonInt): - """Identifiers for precipitation types.""" - RAIN: 'CommonPrecipitationType' = ... - SNOW: 'CommonPrecipitationType' = ... - - @classmethod - def get_all(cls, exclude_values: Iterator['CommonPrecipitationType'] = ()) -> Tuple['CommonPrecipitationType']: - """get_all(exclude_values=()) - - Get a collection of all values. - - :param exclude_values: These values will be excluded. Default is an empty collection. - :type exclude_values: Iterator[CommonPrecipitationType], optional - :return: A collection of all values. - :rtype: Tuple[CommonPrecipitationType] - """ - # noinspection PyTypeChecker - value_list: Tuple[CommonPrecipitationType, ...] = tuple([value for value in cls.values if value not in exclude_values]) - return value_list - - @staticmethod - def convert_to_vanilla(value: 'CommonPrecipitationType') -> PrecipitationType: - """convert_to_vanilla(value) - - Convert a CommonPrecipitationType into PrecipitationType. - - :param value: An instance of CommonPrecipitationType - :type value: CommonPrecipitationType - :return: The specified CommonPrecipitationType translated to PrecipitationType, or the value itself if the value could not be translated. - :rtype: PrecipitationType - """ - if isinstance(value, PrecipitationType): - return value - mapping = { - CommonPrecipitationType.RAIN: PrecipitationType.RAIN, - CommonPrecipitationType.SNOW: PrecipitationType.SNOW - } - return mapping.get(value, value) - - @staticmethod - def convert_from_vanilla(value: PrecipitationType) -> Union['CommonPrecipitationType', None]: - """convert_from_vanilla(value) - - Convert a vanilla PrecipitationType into CommonPrecipitationType. - - :param value: An instance of PrecipitationType - :type value: PrecipitationType - :return: The specified PrecipitationType translated to CommonPrecipitationType, or the value itself if the value could not be translated. - :rtype: CommonPrecipitationType - """ - if isinstance(value, CommonPrecipitationType): - return value - mapping = { - PrecipitationType.RAIN: CommonPrecipitationType.RAIN, - PrecipitationType.SNOW: CommonPrecipitationType.SNOW - } - return mapping.get(value, value) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_pregnancy_origin.py b/Scripts/s4ap/sims4communitylib/enums/common_pregnancy_origin.py deleted file mode 100644 index 23c020a..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_pregnancy_origin.py +++ /dev/null @@ -1,21 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonPregnancyOrigin(CommonInt): - """ Various origins that a pregnancy may come from. """ - VANILLA_WOOHOO = 0 - ALIEN_ABDUCTION = 64 - VAMPIRE_BATS = 65 - LIGHTHOUSE = 66 - FATHER_WINTER = 67 - MONEY_PILE = 68 - MERFOLK = 69 - ELEMENTAL = 70 - CUSTOM = 60000 diff --git a/Scripts/s4ap/sims4communitylib/enums/common_puddle_liquid.py b/Scripts/s4ap/sims4communitylib/enums/common_puddle_liquid.py deleted file mode 100644 index d9ae245..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_puddle_liquid.py +++ /dev/null @@ -1,82 +0,0 @@ -""" -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 -""" -from typing import Union - -from objects.puddles import PuddleLiquid -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonPuddleLiquid(CommonInt): - """ Various types of liquids a puddle may have. """ - INVALID: 'CommonPuddleLiquid' = ... - ACID: 'CommonPuddleLiquid' = ... - DARK_MATTER: 'CommonPuddleLiquid' = ... - GREEN_GOO: 'CommonPuddleLiquid' = ... - MUD: 'CommonPuddleLiquid' = ... - VOMIT: 'CommonPuddleLiquid' = ... - WATER: 'CommonPuddleLiquid' = ... - - @staticmethod - def convert_to_vanilla(value: 'CommonPuddleLiquid') -> Union[PuddleLiquid, None]: - """convert_to_vanilla(value) - - Convert a value into the vanilla PuddleLiquid enum. - - :param value: An instance of a CommonPuddleLiquid - :type value: CommonPuddleLiquid - :return: The specified value translated to a PuddleLiquid or INVALID if the value could not be translated. - :rtype: Union[PuddleLiquid, None] - """ - if value is None or value == CommonPuddleLiquid.INVALID: - return PuddleLiquid.INVALID - if isinstance(value, PuddleLiquid): - return value - mapping = dict() - if hasattr(PuddleLiquid, 'WATER'): - mapping[CommonPuddleLiquid.WATER] = PuddleLiquid.WATER - if hasattr(PuddleLiquid, 'Dark Matter'): - mapping[CommonPuddleLiquid.DARK_MATTER] = getattr(PuddleLiquid, 'Dark Matter') - if hasattr(PuddleLiquid, 'GreenGoo'): - mapping[CommonPuddleLiquid.GREEN_GOO] = PuddleLiquid.GreenGoo - if hasattr(PuddleLiquid, 'Vomit'): - mapping[CommonPuddleLiquid.VOMIT] = PuddleLiquid.Vomit - if hasattr(PuddleLiquid, 'Mud'): - mapping[CommonPuddleLiquid.MUD] = PuddleLiquid.Mud - if hasattr(PuddleLiquid, 'Acid'): - mapping[CommonPuddleLiquid.ACID] = PuddleLiquid.Acid - return mapping.get(value, PuddleLiquid.INVALID) - - @staticmethod - def convert_from_vanilla(value: PuddleLiquid) -> Union['CommonPuddleLiquid', None]: - """convert_from_vanilla(value) - - Convert a value into a CommonPuddleLiquid enum. - - :param value: An instance of a PuddleLiquid - :type value: PuddleLiquid - :return: The specified value translated to a CommonPuddleLiquid or INVALID if the value could not be translated. - :rtype: Union['CommonPuddleLiquid', None] - """ - if value is None or value == CommonPuddleLiquid.INVALID: - return PuddleLiquid.INVALID - if isinstance(value, CommonPuddleLiquid): - return value - mapping = dict() - if hasattr(PuddleLiquid, 'WATER'): - mapping[PuddleLiquid.WATER] = CommonPuddleLiquid.WATER - if hasattr(PuddleLiquid, 'Dark Matter'): - mapping[getattr(PuddleLiquid, 'Dark Matter')] = CommonPuddleLiquid.DARK_MATTER - if hasattr(PuddleLiquid, 'GreenGoo'): - mapping[PuddleLiquid.GreenGoo] = CommonPuddleLiquid.GREEN_GOO - if hasattr(PuddleLiquid, 'Vomit'): - mapping[PuddleLiquid.Vomit] = CommonPuddleLiquid.VOMIT - if hasattr(PuddleLiquid, 'Mud'): - mapping[PuddleLiquid.Mud] = CommonPuddleLiquid.MUD - if hasattr(PuddleLiquid, 'Acid'): - mapping[PuddleLiquid.Acid] = CommonPuddleLiquid.ACID - return mapping.get(value, PuddleLiquid.INVALID) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_puddle_size.py b/Scripts/s4ap/sims4communitylib/enums/common_puddle_size.py deleted file mode 100644 index 396bfbc..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_puddle_size.py +++ /dev/null @@ -1,61 +0,0 @@ -""" -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 -""" -from objects.puddles import PuddleSize -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonPuddleSize(CommonInt): - """ Various sizes of puddles. """ - NONE: 'CommonPuddleSize' = ... - SMALL: 'CommonPuddleSize' = ... - MEDIUM: 'CommonPuddleSize' = ... - LARGE: 'CommonPuddleSize' = ... - - @staticmethod - def convert_to_vanilla(value: 'CommonPuddleSize') -> PuddleSize: - """convert_to_vanilla(value) - - Convert a value into the vanilla PuddleSize enum. - - :param value: An instance of a CommonPuddleSize - :type value: CommonPuddleSize - :return: The specified value translated to a PuddleSize or NoPuddle if the value could not be translated. - :rtype: PuddleSize - """ - if value is None or value == CommonPuddleSize.NONE: - return PuddleSize.NoPuddle - if isinstance(value, PuddleSize): - return value - mapping = { - CommonPuddleSize.SMALL: PuddleSize.SmallPuddle, - CommonPuddleSize.MEDIUM: PuddleSize.MediumPuddle, - CommonPuddleSize.LARGE: PuddleSize.LargePuddle, - } - return mapping.get(value, PuddleSize.NoPuddle) - - @staticmethod - def convert_from_vanilla(value: PuddleSize) -> 'CommonPuddleSize': - """convert_from_vanilla(value) - - Convert a value into a CommonPuddleSize enum. - - :param value: An instance of a PuddleSize - :type value: PuddleSize - :return: The specified value translated to a CommonPuddleSize or NONE if the value could not be translated. - :rtype: CommonPuddleSize - """ - if value is None or value == PuddleSize.NoPuddle: - return CommonPuddleSize.NONE - if isinstance(value, CommonPuddleSize): - return value - mapping = { - PuddleSize.SmallPuddle: CommonPuddleSize.SMALL, - PuddleSize.MediumPuddle: CommonPuddleSize.MEDIUM, - PuddleSize.LargePuddle: CommonPuddleSize.LARGE, - } - return mapping.get(value, CommonPuddleSize.NONE) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_region_id.py b/Scripts/s4ap/sims4communitylib/enums/common_region_id.py deleted file mode 100644 index 6627b81..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_region_id.py +++ /dev/null @@ -1,53 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonRegionId(CommonInt): - """Decimal Identifiers for Regions. - - """ - INVALID: 'CommonRegionId' = 0 - ACTING_STUDIO: 'CommonRegionId' = 190064 - ALIEN_WORLD: 'CommonRegionId' = 108705 - BATUU: 'CommonRegionId' = 231104 - BAY_AREA: 'CommonRegionId' = 302872 - CAMPING_FOREST: 'CommonRegionId' = 104096 - CAREER_DOCTOR_CLINIC: 'CommonRegionId' = 109306 - CHESTNUT_RIDGE: 'CommonRegionId' = 311185 - CITY_LIFE: 'CommonRegionId' = 134252 - COTTAGE_WORLD: 'CommonRegionId' = 257397 - ECO_WORLD: 'CommonRegionId' = 228200 - FAME_WORLD: 'CommonRegionId' = 195493 - FORGOTTEN_GROTTO: 'CommonRegionId' = 104062 - HIGH_SCHOOL_WORLD: 'CommonRegionId' = 272365 - ISLAND_WORLD: 'CommonRegionId' = 208308 - JUNGLE: 'CommonRegionId' = 173593 - MAGIC_VENUE: 'CommonRegionId' = 219134 - MAGIC_WORLD: 'CommonRegionId' = 216626 - MOUNTAIN_WORLD: 'CommonRegionId' = 238454 - NEW_CREST: 'CommonRegionId' = 119917 - NORTH_EUROPE: 'CommonRegionId' = 123129 - OASIS_SPRINGS: 'CommonRegionId' = 104065 - PET_WORLD: 'CommonRegionId' = 166547 - POLICE_STATION: 'CommonRegionId' = 108706 - RETAIL: 'CommonRegionId' = 108704 - SCIENCE_LAB: 'CommonRegionId' = 108707 - SLYVAN_GLADE: 'CommonRegionId' = 104063 - STRANGE_TOWN: 'CommonRegionId' = 201699 - TEST_WORLD: 'CommonRegionId' = 104066 - TEST_WORLD_EP07: 'CommonRegionId' = 197994 - TEST_WORLD_GP02: 'CommonRegionId' = 121398 - TEST_WORLD_MAGALOG: 'CommonRegionId' = 104067 - TEST_WORLD_MEGA_LOTS: 'CommonRegionId' = 131195 - TEST_WORLD_PERFORMANCE: 'CommonRegionId' = 104068 - UNIVERSITY_WORLD: 'CommonRegionId' = 208814 - VAMPIRE_WORLD: 'CommonRegionId' = 152175 - WEDDING_WORLD: 'CommonRegionId' = 272129 - WILLOW_CREEK: 'CommonRegionId' = 104064 - WOLF_TOWN: 'CommonRegionId' = 285909 diff --git a/Scripts/s4ap/sims4communitylib/enums/common_runnable_state.py b/Scripts/s4ap/sims4communitylib/enums/common_runnable_state.py deleted file mode 100644 index 09fc968..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_runnable_state.py +++ /dev/null @@ -1,17 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonRunnableState(CommonInt): - """ States that a runnable can be in. """ - STOPPED = ... - STOPPING = ... - RUNNING = ... - STARTING = ... - WAITING_TO_START = ... diff --git a/Scripts/s4ap/sims4communitylib/enums/common_runnable_state_type.py b/Scripts/s4ap/sims4communitylib/enums/common_runnable_state_type.py deleted file mode 100644 index f7dee88..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_runnable_state_type.py +++ /dev/null @@ -1,17 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonRunnableStateType(CommonInt): - """ States that a runnable can be in. """ - STOPPED = ... - STOPPING = ... - RUNNING = ... - STARTING = ... - WAITING_TO_START = ... diff --git a/Scripts/s4ap/sims4communitylib/enums/common_side.py b/Scripts/s4ap/sims4communitylib/enums/common_side.py deleted file mode 100644 index 147d8bd..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_side.py +++ /dev/null @@ -1,108 +0,0 @@ -""" -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 -""" -from typing import Iterator, Tuple, Union - -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonSide(CommonInt): - """A side of an object.""" - NONE: 'CommonSide' = ... - LEFT: 'CommonSide' = ... - RIGHT: 'CommonSide' = ... - FRONT: 'CommonSide' = ... - BACK: 'CommonSide' = ... - TOP: 'CommonSide' = ... - BOTTOM: 'CommonSide' = ... - - @classmethod - def get_all(cls, exclude_values: Iterator['CommonSide'] = None) -> Tuple['CommonSide']: - """get_all(exclude_values=None) - - Get a collection of all values. - - :param exclude_values: These values will be excluded. If set to None, NONE will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonSide], optional - :return: A collection of all values. - :rtype: Tuple[CommonSide] - """ - if exclude_values is None: - exclude_values = (cls.NONE,) - # noinspection PyTypeChecker - result: Tuple[CommonSide, ...] = tuple([value for value in cls.values if value not in exclude_values]) - return result - - @classmethod - def get_all_names(cls, exclude_values: Iterator['CommonSide'] = None) -> Tuple[str]: - """get_all_names(exclude_values=None) - - Retrieve a collection of the names of all values. - - :param exclude_values: These values will not be returned. If set to None, NONE will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonSide], optional - :return: A collection of the names of all values. - :rtype: Tuple[str] - """ - name_list: Tuple[str] = tuple([value.name for value in cls.get_all(exclude_values=exclude_values)]) - return name_list - - @classmethod - def get_comma_separated_names_string(cls, exclude_values: Iterator['CommonSide'] = None) -> str: - """get_comma_separated_names_string(exclude_values=None) - - Create a string containing all names of all values, separated by a comma. - - :param exclude_values: These values will not be returned. If set to None, NONE will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonSide], optional - :return: A string containing all names of all values, separated by a comma. - :rtype: str - """ - return ', '.join(cls.get_all_names(exclude_values=exclude_values)) - - @classmethod - def convert_to_opposite(cls, value: 'CommonSide') -> 'CommonSide': - """convert_to_opposite(value) - - Convert a value to its opposite. - - :param value: An instance of a value - :type value: CommonSide - :return: The specified value converted to its opposite or the value itself if it could not be converted. - :rtype: CommonSide - """ - mapping = { - CommonSide.LEFT: CommonSide.RIGHT, - CommonSide.RIGHT: CommonSide.LEFT, - CommonSide.FRONT: CommonSide.BACK, - CommonSide.BACK: CommonSide.FRONT, - CommonSide.TOP: CommonSide.BOTTOM, - CommonSide.BOTTOM: CommonSide.TOP, - } - return mapping.get(value, value) - - @classmethod - def convert_to_localized_string_id(cls, value: Union[int, 'CommonSide']) -> Union[int, str]: - """convert_to_localized_string_id(value) - - Convert a value into a Localized String identifier. - - :param value: An instance of a value - :type value: CommonSide - :return: The specified value translated to a localized string identifier. If no localized string id is found, the name property of the value will be used instead. - :rtype: Union[int, str] - """ - from s4ap.sims4communitylib.enums.strings_enum import CommonStringId - mapping = { - CommonSide.LEFT: CommonStringId.S4CL_LEFT, - CommonSide.RIGHT: CommonStringId.S4CL_RIGHT, - CommonSide.FRONT: CommonStringId.S4CL_FRONT, - CommonSide.BACK: CommonStringId.S4CL_BACK, - CommonSide.TOP: CommonStringId.S4CL_TOP, - CommonSide.BOTTOM: CommonStringId.S4CL_BOTTOM, - } - return mapping.get(value, value.name if hasattr(value, 'name') else str(value)) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_sim_demographic_types.py b/Scripts/s4ap/sims4communitylib/enums/common_sim_demographic_types.py deleted file mode 100644 index fbe101f..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_sim_demographic_types.py +++ /dev/null @@ -1,172 +0,0 @@ -""" -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 -""" -from typing import Union, Tuple, Iterator, Dict, Set - -from protocolbuffers.Localization_pb2 import LocalizedString -from s4ap.sims4communitylib.enums.enumtypes.common_versioned_int_flags import CommonVersionedIntFlags -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.utils.math.common_bitwise_utils import CommonBitwiseUtils - - -class CommonSimDemographicType(CommonVersionedIntFlags): - """ Various demographics of Sims. """ - NONE: 'CommonSimDemographicType' = ... - HOUSEHOLD: 'CommonSimDemographicType' = ... - NON_HOUSEHOLD: 'CommonSimDemographicType' = ... - CURRENTLY_CONTROLLED: 'CommonSimDemographicType' = ... - - # Gender - MALE: 'CommonSimDemographicType' = ... - FEMALE: 'CommonSimDemographicType' = ... - - # Age - BABY: 'CommonSimDemographicType' = ... - INFANT: 'CommonSimDemographicType' = ... - CHILD: 'CommonSimDemographicType' = ... - TODDLER: 'CommonSimDemographicType' = ... - TEEN: 'CommonSimDemographicType' = ... - ADULT: 'CommonSimDemographicType' = ... - YOUNG_ADULT: 'CommonSimDemographicType' = ... - ELDER: 'CommonSimDemographicType' = ... - - # Occult - ALIEN: 'CommonSimDemographicType' = ... - GHOST: 'CommonSimDemographicType' = ... - MERMAID: 'CommonSimDemographicType' = ... - NON_OCCULT: 'CommonSimDemographicType' = ... - PLANT: 'CommonSimDemographicType' = ... - ROBOT: 'CommonSimDemographicType' = ... - SKELETON: 'CommonSimDemographicType' = ... - VAMPIRE: 'CommonSimDemographicType' = ... - WEREWOLF: 'CommonSimDemographicType' = ... - WITCH: 'CommonSimDemographicType' = ... - - # Species - HUMAN: 'CommonSimDemographicType' = ... - SMALL_DOG: 'CommonSimDemographicType' = ... - LARGE_DOG: 'CommonSimDemographicType' = ... - CAT: 'CommonSimDemographicType' = ... - FOX: 'CommonSimDemographicType' = ... - HORSE: 'CommonSimDemographicType' = ... - - # Obsolete - PLAYER_SIMS: 'CommonSimDemographicType' = ... - NPC_SIMS: 'CommonSimDemographicType' = ... - ACTIVE_SIM: 'CommonSimDemographicType' = ... - CONTROLLED: 'CommonSimDemographicType' = ... - - @classmethod - def get_version(cls) -> str: - """The version of the enum. If this changes, it means values have changed and should be updated.""" - return 'v1.2' - - @classmethod - def get_all(cls, exclude_values: Iterator['CommonSimDemographicType'] = None) -> Tuple['CommonSimDemographicType']: - """get_all(exclude_values=None) - - Get a collection of all values. - - :param exclude_values: These values will be excluded. If set to None, NONE will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonTypesOfSims], optional - :return: A collection of all values. - :rtype: Tuple[CommonSimDemographicType] - """ - if exclude_values is None: - exclude_values = (cls.NONE,) - obsolete_values = cls.get_obsolete_values() - # noinspection PyTypeChecker - result: Tuple[CommonSimDemographicType, ...] = tuple([val for val in cls.values if val not in exclude_values and val not in obsolete_values]) - return result - - @classmethod - def get_all_flags(cls, exclude_values: Iterator['CommonSimDemographicType'] = None) -> 'CommonSimDemographicType': - """get_all_flags(exclude_values=None) - - Get a flag containing all values. - - :param exclude_values: These values will be excluded. If set to None, NONE will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonTypesOfSims], optional - :return: A flag containing all values. - :rtype: CommonSimDemographicType - """ - value_flags = CommonSimDemographicType.NONE - for value in cls.get_all(exclude_values=exclude_values): - if value_flags == CommonSimDemographicType.NONE: - value_flags = value - else: - value_flags = CommonBitwiseUtils.add_flags(value_flags, value) - return value_flags - - @staticmethod - def to_display_name(value: 'CommonSimDemographicType') -> Union[int, LocalizedString]: - """Convert a value to a display name.""" - mappings = { - CommonSimDemographicType.HOUSEHOLD: CommonStringId.S4CL_HOUSEHOLD, - CommonSimDemographicType.NON_HOUSEHOLD: CommonStringId.S4CL_NON_HOUSEHOLD, - CommonSimDemographicType.CURRENTLY_CONTROLLED: CommonStringId.S4CL_CURRENTLY_CONTROLLED, - # Gender - CommonSimDemographicType.MALE: CommonStringId.MALE, - CommonSimDemographicType.FEMALE: CommonStringId.FEMALE, - # Age - CommonSimDemographicType.BABY: CommonStringId.BABY, - CommonSimDemographicType.TODDLER: CommonStringId.TODDLER, - CommonSimDemographicType.CHILD: CommonStringId.CHILD, - CommonSimDemographicType.TEEN: CommonStringId.TEEN, - CommonSimDemographicType.ADULT: CommonStringId.ADULT, - CommonSimDemographicType.YOUNG_ADULT: CommonStringId.YOUNG_ADULT, - CommonSimDemographicType.ELDER: CommonStringId.ELDER, - # Occult - CommonSimDemographicType.ALIEN: CommonStringId.S4CL_ALIEN, - CommonSimDemographicType.GHOST: CommonStringId.S4CL_GHOST, - CommonSimDemographicType.MERMAID: CommonStringId.S4CL_MERMAID, - CommonSimDemographicType.NON_OCCULT: CommonStringId.S4CL_NON_OCCULT, - CommonSimDemographicType.PLANT: CommonStringId.S4CL_PLANT_SIM, - CommonSimDemographicType.ROBOT: CommonStringId.S4CL_ROBOT, - CommonSimDemographicType.SKELETON: CommonStringId.S4CL_SKELETON, - CommonSimDemographicType.VAMPIRE: CommonStringId.S4CL_VAMPIRE, - CommonSimDemographicType.WEREWOLF: CommonStringId.S4CL_WEREWOLF, - CommonSimDemographicType.WITCH: CommonStringId.S4CL_WITCH, - # Species - CommonSimDemographicType.HUMAN: CommonStringId.HUMAN, - CommonSimDemographicType.SMALL_DOG: CommonStringId.SMALL_DOG, - CommonSimDemographicType.LARGE_DOG: CommonStringId.LARGE_DOG, - CommonSimDemographicType.CAT: CommonStringId.CAT, - CommonSimDemographicType.FOX: CommonStringId.FOX, - CommonSimDemographicType.HORSE: CommonStringId.HORSE, - } - return mappings.get(value, value.name if hasattr(value, 'name') else str(value)) - - @staticmethod - def to_display_description(value: 'CommonSimDemographicType') -> Union[int, LocalizedString]: - """Convert a value to a display description.""" - mappings = { - CommonSimDemographicType.HOUSEHOLD: CommonStringId.S4CL_HOUSEHOLD_DESCRIPTION, - CommonSimDemographicType.NON_HOUSEHOLD: CommonStringId.S4CL_NON_HOUSEHOLD_DESCRIPTION, - CommonSimDemographicType.CURRENTLY_CONTROLLED: CommonStringId.S4CL_CURRENTLY_CONTROLLED_DESCRIPTION, - } - return mappings.get(value, 0) - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_obsolete_values(cls) -> Set['CommonSimDemographicType']: - return { - CommonSimDemographicType.ACTIVE_SIM, - CommonSimDemographicType.PLAYER_SIMS, - CommonSimDemographicType.NPC_SIMS, - CommonSimDemographicType.CONTROLLED - } - - @classmethod - def _get_obsolete_conversion_mapping(cls) -> Dict['CommonSimDemographicType', 'CommonSimDemographicType']: - mapping: Dict[CommonSimDemographicType, CommonSimDemographicType] = { - CommonSimDemographicType.ACTIVE_SIM: CommonSimDemographicType.CURRENTLY_CONTROLLED, - CommonSimDemographicType.CONTROLLED: CommonSimDemographicType.CURRENTLY_CONTROLLED, - CommonSimDemographicType.NPC_SIMS: CommonSimDemographicType.NON_HOUSEHOLD, - CommonSimDemographicType.PLAYER_SIMS: CommonSimDemographicType.HOUSEHOLD - } - return mapping diff --git a/Scripts/s4ap/sims4communitylib/enums/common_sim_name_type.py b/Scripts/s4ap/sims4communitylib/enums/common_sim_name_type.py deleted file mode 100644 index 6d0c9a7..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_sim_name_type.py +++ /dev/null @@ -1,236 +0,0 @@ -""" -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 -""" -from typing import Tuple, Iterator - -from sims.sim_spawner_enums import SimNameType -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonSimNameType(CommonInt): - """Types of names.""" - DEFAULT: 'CommonSimNameType' = ... - JAPANESE: 'CommonSimNameType' = ... - MOROCCAN: 'CommonSimNameType' = ... - INDIAN: 'CommonSimNameType' = ... - CAT: 'CommonSimNameType' = ... - DOG: 'CommonSimNameType' = ... - SKELETON: 'CommonSimNameType' = ... - LATIN: 'CommonSimNameType' = ... - ISLANDER: 'CommonSimNameType' = ... - CHINESE: 'CommonSimNameType' = ... - FAMILIAR_DRAGON: 'CommonSimNameType' = ... - FAMILIAR_BUNNERFLY: 'CommonSimNameType' = ... - FAMILIAR_FAIRY: 'CommonSimNameType' = ... - FAMILIAR_FROG: 'CommonSimNameType' = ... - FAMILIAR_OWL: 'CommonSimNameType' = ... - FAMILIAR_PHOENIX: 'CommonSimNameType' = ... - FAMILIAR_RAVEN: 'CommonSimNameType' = ... - FAMILIAR_SKULL: 'CommonSimNameType' = ... - FAMILIAR_VOID_CRITTER: 'CommonSimNameType' = ... - FAMILIAR_VOODOO_DOLL: 'CommonSimNameType' = ... - FAMILIAR_BAT: 'CommonSimNameType' = ... - HUMANOID_ROBOT: 'CommonSimNameType' = ... - HUMANOID_ROBOT_GENERIC: 'CommonSimNameType' = ... - MARKETPLACE_NAME: 'CommonSimNameType' = ... - MARKETPLACE_FASHION_NAME: 'CommonSimNameType' = ... - STAR_WARS_GENERAL: 'CommonSimNameType' = ... - STAR_WARS_FIRST_ORDER: 'CommonSimNameType' = ... - STAR_WARS_STORM_TROOPER: 'CommonSimNameType' = ... - FOX: 'CommonSimNameType' = ... - - @classmethod - def get_all(cls, exclude_values: Iterator['CommonSimNameType'] = None) -> Tuple['CommonSimNameType']: - """get_all(exclude_values=None) - - Get a collection of all values. - - :param exclude_values: These values will be excluded. If set to None, DEFAULT will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonSimNameType], optional - :return: A collection of all values. - :rtype: Tuple[CommonSimNameType] - """ - if exclude_values is None: - exclude_values = (cls.DEFAULT,) - # noinspection PyTypeChecker - value_list: Tuple[CommonSimNameType] = tuple([value for value in cls.values if value not in exclude_values]) - return value_list - - @classmethod - def get_all_names(cls, exclude_values: Iterator['CommonSimNameType'] = None) -> Tuple[str]: - """get_all_names(exclude_values=None) - - Retrieve a collection of the names of all values. - - :param exclude_values: These values will be excluded. If set to None, DEFAULT will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonSimNameType], optional - :return: A collection of the names of all values. - :rtype: Tuple[str] - """ - name_list: Tuple[str] = tuple([value.name for value in cls.get_all(exclude_values=exclude_values)]) - return name_list - - @classmethod - def get_comma_separated_names_string(cls, exclude_values: Iterator['CommonSimNameType'] = None) -> str: - """get_comma_separated_names_string(exclude_values=None) - - Create a string containing all names of all values, separated by a comma. - - :param exclude_values: These values will be excluded. If set to None, DEFAULT will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonSimNameType], optional - :return: A string containing all names of all values, separated by a comma. - :rtype: str - """ - return ', '.join(cls.get_all_names(exclude_values=exclude_values)) - - @classmethod - def convert_to_vanilla(cls, value: 'CommonSimNameType') -> SimNameType: - """convert_to_vanilla(value) - - Convert a value into the vanilla SimNameType enum. - - :param value: An instance of CommonSimNameType. - :type value: CommonSimNameType - :return: The specified value translated to SimNameType or DEFAULT if the value could not be translated. - :rtype: SimNameType - """ - if value is None or value == CommonSimNameType.DEFAULT: - return SimNameType.DEFAULT - if isinstance(value, SimNameType): - return value - mapping = dict() - if hasattr(SimNameType, 'Japanese'): - mapping[CommonSimNameType.JAPANESE] = SimNameType.Japanese - if hasattr(SimNameType, 'Moroccan'): - mapping[CommonSimNameType.MOROCCAN] = SimNameType.Moroccan - if hasattr(SimNameType, 'Indian'): - mapping[CommonSimNameType.INDIAN] = SimNameType.Indian - if hasattr(SimNameType, 'Cat'): - mapping[CommonSimNameType.CAT] = SimNameType.Cat - if hasattr(SimNameType, 'Dog'): - mapping[CommonSimNameType.DOG] = SimNameType.Dog - if hasattr(SimNameType, 'Skeleton'): - mapping[CommonSimNameType.SKELETON] = SimNameType.Skeleton - if hasattr(SimNameType, 'Latin'): - mapping[CommonSimNameType.LATIN] = SimNameType.Latin - if hasattr(SimNameType, 'Islander'): - mapping[CommonSimNameType.ISLANDER] = SimNameType.Islander - if hasattr(SimNameType, 'Chinese'): - mapping[CommonSimNameType.CHINESE] = SimNameType.Chinese - if hasattr(SimNameType, 'FamiliarDragon'): - mapping[CommonSimNameType.FAMILIAR_DRAGON] = SimNameType.FamiliarDragon - if hasattr(SimNameType, 'FamiliarBunnerfly'): - mapping[CommonSimNameType.FAMILIAR_BUNNERFLY] = SimNameType.FamiliarBunnerfly - if hasattr(SimNameType, 'FamiliarFairy'): - mapping[CommonSimNameType.FAMILIAR_FAIRY] = SimNameType.FamiliarFairy - if hasattr(SimNameType, 'FamiliarFrog'): - mapping[CommonSimNameType.FAMILIAR_FROG] = SimNameType.FamiliarFrog - if hasattr(SimNameType, 'FamiliarOwl'): - mapping[CommonSimNameType.FAMILIAR_OWL] = SimNameType.FamiliarOwl - if hasattr(SimNameType, 'FamiliarPhoenix'): - mapping[CommonSimNameType.FAMILIAR_PHOENIX] = SimNameType.FamiliarPhoenix - if hasattr(SimNameType, 'FamiliarRaven'): - mapping[CommonSimNameType.FAMILIAR_RAVEN] = SimNameType.FamiliarRaven - if hasattr(SimNameType, 'FamiliarSkull'): - mapping[CommonSimNameType.FAMILIAR_SKULL] = SimNameType.FamiliarSkull - if hasattr(SimNameType, 'FamiliarVoidcritter'): - mapping[CommonSimNameType.FAMILIAR_VOID_CRITTER] = SimNameType.FamiliarVoidcritter - if hasattr(SimNameType, 'FamiliarVoodooDoll'): - mapping[CommonSimNameType.FAMILIAR_VOODOO_DOLL] = SimNameType.FamiliarVoodooDoll - if hasattr(SimNameType, 'FamiliarBat'): - mapping[CommonSimNameType.FAMILIAR_BAT] = SimNameType.FamiliarBat - if hasattr(SimNameType, 'HumanoidRobot'): - mapping[CommonSimNameType.HUMANOID_ROBOT] = SimNameType.HumanoidRobot - if hasattr(SimNameType, 'HumanoidRobot_Generic'): - mapping[CommonSimNameType.HUMANOID_ROBOT_GENERIC] = SimNameType.HumanoidRobot_Generic - if hasattr(SimNameType, 'Marketplace_Name'): - mapping[CommonSimNameType.MARKETPLACE_NAME] = SimNameType.Marketplace_Name - if hasattr(SimNameType, 'StarWars_General'): - mapping[CommonSimNameType.STAR_WARS_GENERAL] = SimNameType.StarWars_General - if hasattr(SimNameType, 'StarWars_FirstOrder'): - mapping[CommonSimNameType.STAR_WARS_FIRST_ORDER] = SimNameType.StarWars_FirstOrder - if hasattr(SimNameType, 'StarWars_Stormtrooper'): - mapping[CommonSimNameType.STAR_WARS_STORM_TROOPER] = SimNameType.StarWars_Stormtrooper - if hasattr(SimNameType, 'Fox'): - mapping[CommonSimNameType.FOX] = SimNameType.Fox - if hasattr(SimNameType, 'FashionMarketplace_Name'): - mapping[CommonSimNameType.MARKETPLACE_FASHION_NAME] = SimNameType.FashionMarketplace_Name - return mapping.get(value, SimNameType.DEFAULT) - - @classmethod - def convert_from_vanilla(cls, value: SimNameType) -> 'CommonSimNameType': - """convert_from_vanilla(value) - - Convert a vanilla value into a CommonSimNameType enum. - - :param value: An instance of SimNameType. - :type value: SimNameType - :return: The specified value translated to CommonSimNameType or DEFAULT if the value could not be translated. - :rtype: CommonSimNameType - """ - if value is None or value == SimNameType.DEFAULT: - return CommonSimNameType.DEFAULT - if isinstance(value, CommonSimNameType): - return value - mapping = dict() - if hasattr(SimNameType, 'Japanese'): - mapping[SimNameType.Japanese] = CommonSimNameType.JAPANESE - if hasattr(SimNameType, 'Moroccan'): - mapping[SimNameType.Moroccan] = CommonSimNameType.MOROCCAN - if hasattr(SimNameType, 'Indian'): - mapping[SimNameType.Indian] = CommonSimNameType.INDIAN - if hasattr(SimNameType, 'Cat'): - mapping[SimNameType.Cat] = CommonSimNameType.CAT - if hasattr(SimNameType, 'Dog'): - mapping[SimNameType.Dog] = CommonSimNameType.DOG - if hasattr(SimNameType, 'Skeleton'): - mapping[SimNameType.Skeleton] = CommonSimNameType.SKELETON - if hasattr(SimNameType, 'Latin'): - mapping[SimNameType.Latin] = CommonSimNameType.LATIN - if hasattr(SimNameType, 'Islander'): - mapping[SimNameType.Islander] = CommonSimNameType.ISLANDER - if hasattr(SimNameType, 'Chinese'): - mapping[SimNameType.Chinese] = CommonSimNameType.CHINESE - if hasattr(SimNameType, 'FamiliarDragon'): - mapping[SimNameType.FamiliarDragon] = CommonSimNameType.FAMILIAR_DRAGON - if hasattr(SimNameType, 'FamiliarBunnerfly'): - mapping[SimNameType.FamiliarBunnerfly] = CommonSimNameType.FAMILIAR_BUNNERFLY - if hasattr(SimNameType, 'FamiliarFairy'): - mapping[SimNameType.FamiliarFairy] = CommonSimNameType.FAMILIAR_FAIRY - if hasattr(SimNameType, 'FamiliarFrog'): - mapping[SimNameType.FamiliarFrog] = CommonSimNameType.FAMILIAR_FROG - if hasattr(SimNameType, 'FamiliarOwl'): - mapping[SimNameType.FamiliarOwl] = CommonSimNameType.FAMILIAR_OWL - if hasattr(SimNameType, 'FamiliarPhoenix'): - mapping[SimNameType.FamiliarPhoenix] = CommonSimNameType.FAMILIAR_PHOENIX - if hasattr(SimNameType, 'FamiliarRaven'): - mapping[SimNameType.FamiliarRaven] = CommonSimNameType.FAMILIAR_RAVEN - if hasattr(SimNameType, 'FamiliarSkull'): - mapping[SimNameType.FamiliarSkull] = CommonSimNameType.FAMILIAR_SKULL - if hasattr(SimNameType, 'FamiliarVoidcritter'): - mapping[SimNameType.FamiliarVoidcritter] = CommonSimNameType.FAMILIAR_VOID_CRITTER - if hasattr(SimNameType, 'FamiliarVoodooDoll'): - mapping[SimNameType.FamiliarVoodooDoll] = CommonSimNameType.FAMILIAR_VOODOO_DOLL - if hasattr(SimNameType, 'FamiliarBat'): - mapping[SimNameType.FamiliarBat] = CommonSimNameType.FAMILIAR_BAT - if hasattr(SimNameType, 'HumanoidRobot'): - mapping[SimNameType.HumanoidRobot] = CommonSimNameType.HUMANOID_ROBOT - if hasattr(SimNameType, 'HumanoidRobot_Generic'): - mapping[SimNameType.HumanoidRobot_Generic] = CommonSimNameType.HUMANOID_ROBOT_GENERIC - if hasattr(SimNameType, 'Marketplace_Name'): - mapping[SimNameType.Marketplace_Name] = CommonSimNameType.MARKETPLACE_NAME - if hasattr(SimNameType, 'StarWars_General'): - mapping[SimNameType.StarWars_General] = CommonSimNameType.STAR_WARS_GENERAL - if hasattr(SimNameType, 'StarWars_FirstOrder'): - mapping[SimNameType.StarWars_FirstOrder] = CommonSimNameType.STAR_WARS_FIRST_ORDER - if hasattr(SimNameType, 'StarWars_Stormtrooper'): - mapping[SimNameType.StarWars_Stormtrooper] = CommonSimNameType.STAR_WARS_STORM_TROOPER - if hasattr(SimNameType, 'Fox'): - mapping[SimNameType.Fox] = CommonSimNameType.FOX - if hasattr(SimNameType, 'FashionMarketplace_Name'): - mapping[SimNameType.FashionMarketplace_Name] = CommonSimNameType.MARKETPLACE_FASHION_NAME - return mapping.get(value, CommonSimNameType.DEFAULT) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_skill_effectiveness.py b/Scripts/s4ap/sims4communitylib/enums/common_skill_effectiveness.py deleted file mode 100644 index f283a35..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_skill_effectiveness.py +++ /dev/null @@ -1,107 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt -from statistics.skill import SkillEffectiveness - - -class CommonSkillEffectiveness(CommonInt): - """Various Skill Effectiveness.""" - HUGE: 'CommonSkillEffectiveness' = ... - LARGE: 'CommonSkillEffectiveness' = ... - PERIODIC_LARGE: 'CommonSkillEffectiveness' = ... - PERIODIC_SMALL: 'CommonSkillEffectiveness' = ... - PERIODIC_STANDARD: 'CommonSkillEffectiveness' = ... - PERIODIC_STANDARD_TODDLER: 'CommonSkillEffectiveness' = ... - PERIODIC_TONE: 'CommonSkillEffectiveness' = ... - PERIODIC_VERY_SMALL: 'CommonSkillEffectiveness' = ... - SMALL: 'CommonSkillEffectiveness' = ... - TINY: 'CommonSkillEffectiveness' = ... - TODDLER: 'CommonSkillEffectiveness' = ... - - @staticmethod - def convert_to_vanilla(value: 'CommonSkillEffectiveness') -> SkillEffectiveness: - """convert_to_vanilla(value) - - Convert a value into a vanilla SkillEffectiveness value. - - :param value: An instance of CommonSkillEffectiveness - :type value: CommonSkillEffectiveness - :return: The specified value translated to an SkillEffectiveness or StandardPeriodic if the value could not be translated. - :rtype: SkillEffectiveness - """ - if value is None: - # noinspection PyUnresolvedReferences - return SkillEffectiveness.StandardPeriodic - if isinstance(value, SkillEffectiveness): - return value - mapping = dict() - if hasattr(SkillEffectiveness, 'Small'): - mapping[CommonSkillEffectiveness.SMALL] = SkillEffectiveness.Small - if hasattr(SkillEffectiveness, 'Large'): - mapping[CommonSkillEffectiveness.LARGE] = SkillEffectiveness.Large - if hasattr(SkillEffectiveness, 'SmallPeriodic'): - mapping[CommonSkillEffectiveness.PERIODIC_SMALL] = SkillEffectiveness.SmallPeriodic - if hasattr(SkillEffectiveness, 'StandardPeriodic'): - mapping[CommonSkillEffectiveness.PERIODIC_STANDARD] = SkillEffectiveness.StandardPeriodic - if hasattr(SkillEffectiveness, 'LargePeriodic'): - mapping[CommonSkillEffectiveness.PERIODIC_LARGE] = SkillEffectiveness.LargePeriodic - if hasattr(SkillEffectiveness, 'Tiny'): - mapping[CommonSkillEffectiveness.TINY] = SkillEffectiveness.Tiny - if hasattr(SkillEffectiveness, 'Huge'): - mapping[CommonSkillEffectiveness.HUGE] = SkillEffectiveness.Huge - if hasattr(SkillEffectiveness, 'VerySmallPeriodic'): - mapping[CommonSkillEffectiveness.PERIODIC_VERY_SMALL] = SkillEffectiveness.VerySmallPeriodic - if hasattr(SkillEffectiveness, 'TonePeriodic'): - mapping[CommonSkillEffectiveness.PERIODIC_TONE] = SkillEffectiveness.TonePeriodic - if hasattr(SkillEffectiveness, 'Toddler'): - mapping[CommonSkillEffectiveness.TODDLER] = SkillEffectiveness.Toddler - if hasattr(SkillEffectiveness, 'ToddlerStandardPeriodic'): - mapping[CommonSkillEffectiveness.PERIODIC_STANDARD_TODDLER] = SkillEffectiveness.ToddlerStandardPeriodic - - return mapping.get(value, getattr(SkillEffectiveness, 'StandardPeriodic', None)) - - @staticmethod - def convert_from_vanilla(value: SkillEffectiveness) -> 'CommonSkillEffectiveness': - """convert_from_vanilla(value) - - Convert a vanilla value to a CommonSkillEffectiveness value. - - :param value: An instance of SkillEffectiveness - :type value: SkillEffectiveness - :return: The specified value translated to a CommonSkillEffectiveness or PERIODIC_STANDARD if the value could not be translated. - :rtype: CommonSkillEffectiveness - """ - if value is None: - return CommonSkillEffectiveness.PERIODIC_STANDARD - if isinstance(value, CommonSkillEffectiveness): - return value - mapping = dict() - if hasattr(SkillEffectiveness, 'Small'): - mapping[SkillEffectiveness.Small] = CommonSkillEffectiveness.SMALL - if hasattr(SkillEffectiveness, 'Large'): - mapping[SkillEffectiveness.Large] = CommonSkillEffectiveness.LARGE - if hasattr(SkillEffectiveness, 'SmallPeriodic'): - mapping[SkillEffectiveness.SmallPeriodic] = CommonSkillEffectiveness.PERIODIC_SMALL - if hasattr(SkillEffectiveness, 'StandardPeriodic'): - mapping[SkillEffectiveness.StandardPeriodic] = CommonSkillEffectiveness.PERIODIC_STANDARD - if hasattr(SkillEffectiveness, 'LargePeriodic'): - mapping[SkillEffectiveness.LargePeriodic] = CommonSkillEffectiveness.PERIODIC_LARGE - if hasattr(SkillEffectiveness, 'Tiny'): - mapping[SkillEffectiveness.Tiny] = CommonSkillEffectiveness.TINY - if hasattr(SkillEffectiveness, 'Huge'): - mapping[SkillEffectiveness.Huge] = CommonSkillEffectiveness.HUGE - if hasattr(SkillEffectiveness, 'VerySmallPeriodic'): - mapping[SkillEffectiveness.VerySmallPeriodic] = CommonSkillEffectiveness.PERIODIC_VERY_SMALL - if hasattr(SkillEffectiveness, 'TonePeriodic'): - mapping[SkillEffectiveness.TonePeriodic] = CommonSkillEffectiveness.PERIODIC_TONE - if hasattr(SkillEffectiveness, 'Toddler'): - mapping[SkillEffectiveness.Toddler] = CommonSkillEffectiveness.TODDLER - if hasattr(SkillEffectiveness, 'ToddlerStandardPeriodic'): - mapping[SkillEffectiveness.ToddlerStandardPeriodic] = CommonSkillEffectiveness.PERIODIC_STANDARD_TODDLER - - return mapping.get(value, CommonSkillEffectiveness.PERIODIC_STANDARD) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_slot_type.py b/Scripts/s4ap/sims4communitylib/enums/common_slot_type.py deleted file mode 100644 index a330d3c..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_slot_type.py +++ /dev/null @@ -1,116 +0,0 @@ -""" -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 -""" - - -class CommonSlotType: - """Slot types for various objects. - - """ - ACTIVITY_TABLE_PAINTING: 'CommonSlotType' = 'ActivityTablePainting' - ANIMATION_SLOT_SIM_INTERACTION: 'CommonSlotType' = 'animationSlot_SimInteraction' - ANIMATION_SLOT_SIT_INDIVIDUAL: 'CommonSlotType' = 'animationSlot_SitIndividual' - ANIMATION_SLOT_SIT_SHARED: 'CommonSlotType' = 'animationSlot_SitShared' - APPLIANCE_EMBEDDED: 'CommonSlotType' = 'ApplianceEmbedded' - APPLIANCE_SURFACE: 'CommonSlotType' = 'ApplianceSurface' - ARCHAEOLOGY_TABLE: 'CommonSlotType' = 'archaeologyTable' - AUTO_PET_FEEDER: 'CommonSlotType' = 'AutoPetFeeder' - BANQUET_TABLE_CENTER_PIECE: 'CommonSlotType' = 'BanquetTableCenterpiece' - BAR_SERVE: 'CommonSlotType' = 'BarServe' - BOOKSHELVES_E: 'CommonSlotType' = 'BookShelves_E' - BOOKSHELVES_W: 'CommonSlotType' = 'BookShelves_W' - BOOTH: 'CommonSlotType' = 'Booth' - BOOTH_CORNER: 'CommonSlotType' = 'BoothCorner' - BULLETIN_BOARD_CURFEW_DRAWING: 'CommonSlotType' = 'bulletinBoardCurfewDrawing' - BULLETIN_BOARD_CURFEW_NOTE: 'CommonSlotType' = 'bulletinBoardCurfewNote' - CAMERA_TRIPOD: 'CommonSlotType' = 'Camera_Tripod' - CAMPFIRE_SIT: 'CommonSlotType' = 'CampfireSit' - CARVING_STATION: 'CommonSlotType' = 'CarvingStation' - CHEF_STATION_FOOD_PLATTER: 'CommonSlotType' = 'ChefStationFoodPlatter' - CHEMISTRY_LAB_SCIENCE: 'CommonSlotType' = 'ChemistryLabScience' - CLONING_MACHINE_CLONE: 'CommonSlotType' = 'CloningMachineClone' - CLONING_MACHINE_SIM: 'CommonSlotType' = 'CloningMachineSim' - CLONING_MACHINE_SOURCE: 'CommonSlotType' = 'CloningMachineSource' - COLLECTION_SKULL_DISPLAY: 'CommonSlotType' = 'Collection_Skull_Display' - COLLECT_MONSTER_BATTLE_CARD: 'CommonSlotType' = 'collectMonsterBattleCard' - CRAFT_ROBOTICS: 'CommonSlotType' = 'CraftRobotics' - CUPCAKE_MACHINE_SERVE: 'CommonSlotType' = 'CupcakeMachineServe' - CURTAIN: 'CommonSlotType' = 'Curtain' - DRINK_DECANTER: 'CommonSlotType' = 'DrinkDecanter' - DRINK_TRAY_SERVE: 'CommonSlotType' = 'DrinkTrayServe' - EASEL_PAINT: 'CommonSlotType' = 'EaselPaint' - ESPRESSO_BAR_BREW: 'CommonSlotType' = 'espressoBarBrew' - ESPRESSO_BAR_GRIND: 'CommonSlotType' = 'espressoBarGrind' - ESPRESSO_MACHINE_CUP: 'CommonSlotType' = 'EspressoMachineCup' - FENCE_DECO: 'CommonSlotType' = 'FenceDeco' - FENCE_RAIL_SIDE_DECO: 'CommonSlotType' = 'FenceRailSideDeco' - FLOOR_MURAL_PAINT: 'CommonSlotType' = 'FloorMuralPaint' - FLOWER_ARRANGEMENT: 'CommonSlotType' = 'FlowerArrangement' - GAMEPLAY_SLOT_DECO_LARGE: 'CommonSlotType' = '_gameplaySlot_Deco_Large' - GAMEPLAY_SLOT_DECO_MEDIUM: 'CommonSlotType' = '_gameplaySlot_Deco_Medium' - GAMEPLAY_SLOT_DECO_SMALL: 'CommonSlotType' = '_gameplaySlot_Deco_Small' - GARAGE_MURAL_PAINT: 'CommonSlotType' = 'GarageMuralPaint' - GLOBE_BAR_DECANTER: 'CommonSlotType' = 'GlobeBar_Decanter' - GRILL_COOK: 'CommonSlotType' = 'GrillCook' - HOLIDAY_TREE_DECORATION_GARLAND: 'CommonSlotType' = 'HolidayTree_Decoration_Garland' - HOLIDAY_TREE_DECORATION_ORNAMENT: 'CommonSlotType' = 'HolidayTree_Decoration_Ornament' - HOLIDAY_TREE_DECORATION_SKIRT: 'CommonSlotType' = 'HolidayTree_Decoration_Skirt' - HOLIDAY_TREE_DECORATION_TOPPER: 'CommonSlotType' = 'HolidayTree_Decoration_Topper' - HOLIDAY_TREE_PRESENT_PILE: 'CommonSlotType' = 'HolidayTree_PresentPile' - HUMANOID_BOT: 'CommonSlotType' = 'humanoidBot' - INVENTION_CONSTRUCTOR_SCIENCE: 'CommonSlotType' = 'InventionConstructorScience' - JUICE_KEG_CUP: 'CommonSlotType' = 'JuiceKegCup' - LAUNDRY_WASHING_MACHINE: 'CommonSlotType' = 'Laundry_WashingMachine' - MAGIC_WAND_DISPLAY: 'CommonSlotType' = 'MagicWandDisplay' - MECH_SUIT_HEAD: 'CommonSlotType' = 'MechSuitHead' - MICROWAVE_COOK: 'CommonSlotType' = 'MicrowaveCook' - MONSTER_BATTLE_SCREEN: 'CommonSlotType' = 'monsterBattleScreen' - NIGHTSTAND: 'CommonSlotType' = 'Nightstand' - OBJECT_SURFACE_2_X_1: 'CommonSlotType' = '2x1ObjectSurface' - OFFERING: 'CommonSlotType' = 'Offering' - OVEN_COOK: 'CommonSlotType' = 'OvenCook' - PARTY_BOT: 'CommonSlotType' = 'PartyBot' - PEDESTAL_STATUE: 'CommonSlotType' = 'PedestalStatue' - PHOTO_COLLAGE_FRAME_LANDSCAPE_MED: 'CommonSlotType' = 'PhotoCollageFrame_Landscape_Med' - PHOTO_COLLAGE_FRAME_LANDSCAPE_SMALL: 'CommonSlotType' = 'PhotoCollageFrame_Landscape_Small' - PHOTO_COLLAGE_FRAME_PORTRAIT_MED: 'CommonSlotType' = 'PhotoCollageFrame_Portrait_Med' - PHOTO_COLLAGE_FRAME_PORTRAIT_SMALL: 'CommonSlotType' = 'PhotoCollageFrame_Portrait_Small' - PING_PONG_CUP: 'CommonSlotType' = 'PingPongCup' - PLACEMAT_DRAWING: 'CommonSlotType' = 'PlacematDrawing' - PLANT_COW: 'CommonSlotType' = 'PlantCow' - PLANT_LARGE: 'CommonSlotType' = 'PlantLarge' - PLANT_SIMS_MAGIC_BEANS: 'CommonSlotType' = 'PlantSims_MagicBeans' - PLANT_SMALL: 'CommonSlotType' = 'PlantSmall' - POSTCARD_BOARD_COLLECT: 'CommonSlotType' = 'PostcardBoardCollect' - RESTAURANT_SIGN_DECAL_4_X_1_X_2: 'CommonSlotType' = 'RestaurantSignDecal4x1x2' - RESTAURANT_SIGN_DECAL: 'CommonSlotType' = 'RestaurantSignDecal' - RESTAURANT_SIGN_DECAL_LARGE: 'CommonSlotType' = 'RestaurantSignDecalLarge' - RETAIL_FOOD_DISPLAY_SHOW: 'CommonSlotType' = 'RetailFoodDisplayShow' - ROBOT_VACUUM: 'CommonSlotType' = 'RobotVacuum' - ROLLUP_MURAL_PAINT: 'CommonSlotType' = 'RollupMuralPaint' - SIT_CHAIR: 'CommonSlotType' = 'SitChair' - SIT_CHAIR_LARGE: 'CommonSlotType' = 'SitChairLrg' - SIT_CHAIR_TALL: 'CommonSlotType' = 'SitChairTall' - SIT_DRINK: 'CommonSlotType' = 'SitDrink' - SIT_EAT: 'CommonSlotType' = 'SitEat' - SIT_INDIVIDUAL: 'CommonSlotType' = 'SitIndividual' - SIT_SHARED: 'CommonSlotType' = 'SitShared' - SPAWN_POINT: 'CommonSlotType' = 'SpawnPoint' - STAGE: 'CommonSlotType' = 'Stage' - STAND_INDIVIDUAL: 'CommonSlotType' = 'StandIndividual' - STAND_SHARED: 'CommonSlotType' = 'StandShared' - STAR_TILE: 'CommonSlotType' = 'starTile' - STOVE_COOK: 'CommonSlotType' = 'StoveCook' - STYLEBOARD: 'CommonSlotType' = 'Styleboard' - SURGERY_TABLE_BASSINET: 'CommonSlotType' = 'SurgeryTable_Bassinet' - TABLE_GAME_INDIVIDUAL: 'CommonSlotType' = 'TableGameIndividual' - TABLE_GAME_SHARED: 'CommonSlotType' = 'TableGameShared' - TODDLER_SIPPY_CUP: 'CommonSlotType' = 'ToddlerSippyCup' - TV_STAND_TV: 'CommonSlotType' = 'TvStandTV' - VIDEO_STATION: 'CommonSlotType' = 'VideoStation' - WALL_MURAL_PAINT: 'CommonSlotType' = 'WallMuralPaint' - WOODWORK_IN_PROGRESS: 'CommonSlotType' = 'WoodworkInProgress' diff --git a/Scripts/s4ap/sims4communitylib/enums/common_species.py b/Scripts/s4ap/sims4communitylib/enums/common_species.py deleted file mode 100644 index fe36b1e..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_species.py +++ /dev/null @@ -1,189 +0,0 @@ -""" -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 -""" -from typing import Union, Tuple, Iterator - -from sims.sim_info import SimInfo -from sims.sim_info_types import Species, SpeciesExtended -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonSpecies(CommonInt): - """Custom Species enum containing all species (including extended species). - - """ - INVALID: 'CommonSpecies' = ... - HUMAN: 'CommonSpecies' = ... - SMALL_DOG: 'CommonSpecies' = ... - LARGE_DOG: 'CommonSpecies' = ... - CAT: 'CommonSpecies' = ... - FOX: 'CommonSpecies' = ... - HORSE: 'CommonSpecies' = ... - - @classmethod - def get_all(cls, exclude_values: Iterator['CommonSpecies'] = None) -> Tuple['CommonSpecies']: - """get_all(exclude_values=None) - - Get a collection of all values. - - :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonSpecies], optional - :return: A collection of all values. - :rtype: Tuple[CommonSpecies] - """ - if exclude_values is None: - exclude_values = (cls.INVALID,) - # noinspection PyTypeChecker - value_list: Tuple[CommonSpecies, ...] = tuple([value for value in cls.values if value not in exclude_values]) - return value_list - - @classmethod - def get_all_names(cls, exclude_values: Iterator['CommonSpecies'] = None) -> Tuple[str]: - """get_all_names(exclude_values=None) - - Retrieve a collection of the names of all values. - - :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonSpecies], optional - :return: A collection of the names of all values. - :rtype: Tuple[str] - """ - name_list: Tuple[str] = tuple([value.name for value in cls.get_all(exclude_values=exclude_values)]) - return name_list - - @classmethod - def get_comma_separated_names_string(cls, exclude_values: Iterator['CommonSpecies'] = None) -> str: - """get_comma_separated_names_string(exclude_values=None) - - Create a string containing all names of all values, separated by a comma. - - :param exclude_values: These values will be excluded. If set to None, INVALID will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonSpecies], optional - :return: A string containing all names of all values, separated by a comma. - :rtype: str - """ - return ', '.join(cls.get_all_names(exclude_values=exclude_values)) - - @staticmethod - def get_species(sim_info: SimInfo) -> 'CommonSpecies': - """get_species(sim_info) - - Retrieve the CommonSpecies of a sim. Use this instead of CommonSpeciesUtils.get_species to determine a more specific species. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: A species matching the Sim or INVALID if no matching species is found. - :rtype: CommonSpecies - """ - from s4ap.sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils - if CommonSpeciesUtils.is_human(sim_info): - return CommonSpecies.HUMAN - elif CommonSpeciesUtils.is_fox(sim_info): - return CommonSpecies.FOX - elif CommonSpeciesUtils.is_small_dog(sim_info): - return CommonSpecies.SMALL_DOG - elif CommonSpeciesUtils.is_large_dog(sim_info): - return CommonSpecies.LARGE_DOG - elif CommonSpeciesUtils.is_cat(sim_info): - return CommonSpecies.CAT - elif CommonSpeciesUtils.is_horse(sim_info): - return CommonSpecies.HORSE - return CommonSpecies.INVALID - - @staticmethod - def convert_to_vanilla(value: 'CommonSpecies') -> Union[SpeciesExtended, None]: - """convert_to_vanilla(value) - - Convert a value into the vanilla SpeciesExtended enum. - - :param value: An instance of CommonSpecies - :type value: CommonSpecies - :return: The specified value translated to SpeciesExtended or INVALID if the value could not be translated. - :rtype: Union[SpeciesExtended, None] - """ - if value is None or value == CommonSpecies.INVALID: - return None - if isinstance(value, SpeciesExtended) or isinstance(value, Species): - # noinspection PyTypeChecker - return value - mapping = { - CommonSpecies.HUMAN: SpeciesExtended.HUMAN, - } - if hasattr(SpeciesExtended, 'SMALLDOG'): - mapping[CommonSpecies.SMALL_DOG] = SpeciesExtended.SMALLDOG - if hasattr(SpeciesExtended, 'DOG'): - mapping[CommonSpecies.LARGE_DOG] = SpeciesExtended.DOG - if hasattr(SpeciesExtended, 'CAT'): - mapping[CommonSpecies.CAT] = SpeciesExtended.CAT - if hasattr(SpeciesExtended, 'FOX'): - mapping[CommonSpecies.FOX] = SpeciesExtended.FOX - if hasattr(SpeciesExtended, 'HORSE'): - mapping[CommonSpecies.HORSE] = SpeciesExtended.HORSE - return mapping.get(value, None) - - @staticmethod - def convert_from_vanilla(value: SpeciesExtended) -> 'CommonSpecies': - """convert_from_vanilla(value) - - Convert a value into a CommonSpecies enum. - - :param value: An instance of SpeciesExtended - :type value: SpeciesExtended - :return: The specified value translated to CommonSpecies or INVALID if the value could not be translated. - :rtype: CommonSpecies - """ - if value is None or value == CommonSpecies.INVALID: - return SpeciesExtended.INVALID - if isinstance(value, CommonSpecies): - # noinspection PyTypeChecker - return value - mapping = { - Species.HUMAN: CommonSpecies.HUMAN, - } - if hasattr(SpeciesExtended, 'SMALLDOG'): - mapping[SpeciesExtended.SMALLDOG] = CommonSpecies.SMALL_DOG - if hasattr(Species, 'DOG'): - mapping[Species.DOG] = CommonSpecies.LARGE_DOG - if hasattr(Species, 'CAT'): - mapping[Species.CAT] = CommonSpecies.CAT - if hasattr(Species, 'FOX'): - mapping[Species.FOX] = CommonSpecies.FOX - if hasattr(Species, 'HORSE'): - mapping[Species.HORSE] = CommonSpecies.HORSE - return mapping.get(value, CommonSpecies.INVALID) - - @staticmethod - def convert_to_localized_string_id(value: 'CommonSpecies') -> Union[int, str]: - """convert_to_localized_string_id(value) - - Convert a value into a Localized String identifier. - - :param value: An instance of a CommonSpecies - :type value: CommonSpecies - :return: The specified value translated to a localized string identifier. If no localized string id is found, the name property of the value will be used instead. - :rtype: Union[int, str] - """ - from s4ap.sims4communitylib.enums.strings_enum import CommonStringId - display_name_mapping = { - CommonSpecies.HUMAN: CommonStringId.HUMAN, - CommonSpecies.LARGE_DOG: CommonStringId.LARGE_DOG, - CommonSpecies.SMALL_DOG: CommonStringId.SMALL_DOG, - CommonSpecies.CAT: CommonStringId.CAT, - CommonSpecies.FOX: CommonStringId.FOX, - CommonSpecies.HORSE: CommonStringId.HORSE, - } - if isinstance(value, int) and not isinstance(value, CommonSpecies): - from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils - # noinspection PyTypeChecker - converted_value = CommonResourceUtils.get_enum_by_int_value(value, SpeciesExtended, default_value=None) - if converted_value is None: - return str(value) - value = CommonSpecies.convert_from_vanilla(converted_value) - if not isinstance(value, CommonSpecies): - # noinspection PyTypeChecker - value = CommonSpecies.convert_from_vanilla(value) - return display_name_mapping.get(value, value.name if hasattr(value, 'name') else str(value)) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_statistic_category.py b/Scripts/s4ap/sims4communitylib/enums/common_statistic_category.py deleted file mode 100644 index fed6184..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_statistic_category.py +++ /dev/null @@ -1,75 +0,0 @@ -""" -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 -""" -from typing import Union - -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt -from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils -from statistics.statistic_categories import StatisticCategory - - -def _get_statistic_category(name: str) -> Union[StatisticCategory, int]: - return CommonResourceUtils.get_enum_by_name(name, StatisticCategory, default_value=StatisticCategory.INVALID) - - -class CommonStatisticCategory(CommonInt): - """Custom Statistic Category equivalent to the DynamicEnum statistics.statistic_categories.StatisticCategory - - """ - INVALID: 'CommonStatisticCategory' = _get_statistic_category('INVALID') - - ANGRY_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Angry_Buffs') - ASLEEP_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Asleep_Buffs') - BAD_FOOD_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('BadFood_Buffs') - BORED_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Bored_Buffs') - CHEF_COOK_STYLE_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('ChefCookStyle_Buffs') - CHILDHOOD_PHASE_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('ChildhoodPhase_Buffs') - CLOTHING_OPTIONAL_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('ClothingOptional_Buffs') - CONFIDENT_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Confident_Buffs') - EMBARRASSED_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Embarrassed_Buffs') - ENERGIZED_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Energized_Buffs') - FINE_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Fine_Buffs') - FLIRTY_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Flirty_Buffs') - FOCUSED_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Focused_Buffs') - GAMES_COM_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Gamescom_Buffs') - GROUNDED_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Grounded_Buffs') - HACKING_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Hacking_Buffs') - HAPPY_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Happy_Buffs') - INJURY_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Injury_Buffs') - INSPIRED_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Inspired_Buffs') - ITCHY_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Itchy_Buffs') - MIND_CONTROL_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('MindControl_Buffs') - MIND_POWERS_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('MindPowers_Buffs') - MODULE_TUNABLES: 'CommonStatisticCategory' = _get_statistic_category('MODULE_TUNABLES') - MOTIVE_COMMODITIES: 'CommonStatisticCategory' = _get_statistic_category('Motive_Commodities') - OBJECT_BED_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Object_Bed_Buffs') - OBJECT_BOOK_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Object_Book_Buffs') - OBJECT_JUNGLE_GYM_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Object_JungleGym_Buffs') - OBJECT_MICROSCOPE_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Object_Microscope_Buffs') - OBJECT_MIRROR_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Object_Mirror_Buffs') - OBJECT_MOTION_GAMING_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Object_MotionGaming_Buffs') - OBJECT_OBSERVATORY_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Object_Observatory_Buffs') - OBJECT_STEREO_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Object_Stereo_Buffs') - OBJECT_TOY_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Object_Toy_Buffs') - OBJECT_TV_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Object_TV_Buffs') - PET_SICKNESS_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('PetSickness_Buffs') - PLAYFUL_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Playful_Buffs') - PRANK_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Prank_Buffs') - PRANK_COOLDOWN_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('PrankCooldown_Buffs') - SAD_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Sad_Buffs') - SCARED_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Scared_Buffs') - SICKNESS_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Sickness_Buffs') - SLOSHED_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Sloshed_Buffs') - SOCIAL_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Social_Buffs') - STRESSED_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Stressed_Buffs') - SURVEY_COOLDOWN_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('SurveyCooldown_Buffs') - TEEN_MOOD_SWING_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('TeenMoodSwing_Buffs') - TEMPLE_FUN_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Temple_Fun_Buffs') - UNCOMFORTABLE_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Uncomfortable_Buffs') - UNIVERSITY_STUDYING_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('University_Studying_Buffs') - VAMPIRE_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('Vampire_Buffs') - WILDLIFE_ENCOUNTER_BUFFS: 'CommonStatisticCategory' = _get_statistic_category('WildlifeEncounter_Buffs') diff --git a/Scripts/s4ap/sims4communitylib/enums/common_street_civic_policy_ids.py b/Scripts/s4ap/sims4communitylib/enums/common_street_civic_policy_ids.py deleted file mode 100644 index fb38568..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_street_civic_policy_ids.py +++ /dev/null @@ -1,37 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonStreetCivicPolicyId(CommonInt): - """ Identifiers of Street Civic Policies. """ - GENERAL_ECO_FRIENDLY_APPLIANCES: 'CommonStreetCivicPolicyId' = 232589 - GENERAL_SHUT_OFF_DAY_POWER: 'CommonStreetCivicPolicyId' = 233562 - GENERAL_SHUT_OFF_DAY_WATER: 'CommonStreetCivicPolicyId' = 233563 - GENERAL_COMMUNAL_OWNERSHIP: 'CommonStreetCivicPolicyId' = 237915 - GENERAL_BAG_NEIGHBORHOOD: 'CommonStreetCivicPolicyId' = 237916 - OBJECT_BASED_UPCYCLING_INITIATIVE: 'CommonStreetCivicPolicyId' = 226333 - OBJECT_BASED_UTILITY_PRODUCTION: 'CommonStreetCivicPolicyId' = 233559 - OBJECT_BASED_GREEN_GARDENING: 'CommonStreetCivicPolicyId' = 233560 - SKILL_BASED_OLD_DAYS: 'CommonStreetCivicPolicyId' = 237848 - SKILL_BASED_FREE_LOVE: 'CommonStreetCivicPolicyId' = 237846 - SKILL_BASED_AGGRESSION: 'CommonStreetCivicPolicyId' = 237847 - SKILL_BASED_SELF_CARE: 'CommonStreetCivicPolicyId' = 231968 - SKILL_BASED_JUICED_COMMUNITY: 'CommonStreetCivicPolicyId' = 231969 - SKILL_BASED_HOME_COOKING: 'CommonStreetCivicPolicyId' = 231970 - SKILL_BASED_TECHNOLOGICAL_PROGRESS: 'CommonStreetCivicPolicyId' = 231971 - SKILL_BASED_CREATIVE_ARTS: 'CommonStreetCivicPolicyId' = 231972 - SKILL_BASED_FUN_COMMUNITY: 'CommonStreetCivicPolicyId' = 231973 - SKILL_BASED_MUSIC_ARTS: 'CommonStreetCivicPolicyId' = 231974 - SKILL_BASED_SELF_SUFFICIENT: 'CommonStreetCivicPolicyId' = 231975 - NEIGHBORHOOD_RENOVATION_MODERN_POLICY_INNER_CITY: 'CommonStreetCivicPolicyId' = 233188 - NEIGHBORHOOD_RENOVATION_MODERN_POLICY_INDUSTRIAL: 'CommonStreetCivicPolicyId' = 233189 - NEIGHBORHOOD_RENOVATION_MODERN_POLICY_SUBURBAN: 'CommonStreetCivicPolicyId' = 233190 - NEIGHBORHOOD_RENOVATION_GREEN_POLICY_SUBURBAN: 'CommonStreetCivicPolicyId' = 233193 - NEIGHBORHOOD_RENOVATION_GREEN_POLICY_INDUSTRIAL: 'CommonStreetCivicPolicyId' = 233194 - NEIGHBORHOOD_RENOVATION_GREEN_POLICY_INNER_CITY: 'CommonStreetCivicPolicyId' = 233195 diff --git a/Scripts/s4ap/sims4communitylib/enums/common_temperature.py b/Scripts/s4ap/sims4communitylib/enums/common_temperature.py deleted file mode 100644 index e93e569..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_temperature.py +++ /dev/null @@ -1,98 +0,0 @@ -""" -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 -""" -from typing import Tuple, Union, Iterator - -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - -# noinspection PyBroadException -try: - from weather.weather_enums import Temperature -except: - class Temperature(CommonInt): - """Mock class.""" - FREEZING = -3 - COLD = -2 - COOL = -1 - WARM = 0 - HOT = 1 - BURNING = 2 - - -class CommonTemperature(CommonInt): - """Identifiers for temperatures.""" - FREEZING: 'CommonTemperature' = ... - COLD: 'CommonTemperature' = ... - COOL: 'CommonTemperature' = ... - WARM: 'CommonTemperature' = ... - HOT: 'CommonTemperature' = ... - BURNING: 'CommonTemperature' = ... - - @classmethod - def get_all(cls, exclude_values: Iterator['CommonTemperature'] = ()) -> Tuple['CommonTemperature']: - """get_all(exclude_values=()) - - Get a collection of all values. - - :param exclude_values: These values will be excluded. Default is an empty collection. - :type exclude_values: Iterator[CommonTemperature], optional - :return: A collection of all values. - :rtype: Tuple[CommonTemperature] - """ - # noinspection PyTypeChecker - value_list: Tuple[CommonTemperature, ...] = tuple([value for value in cls.values if value not in exclude_values]) - return value_list - - @staticmethod - def convert_to_vanilla(value: 'CommonTemperature') -> Union[Temperature, None]: - """convert_to_vanilla(value) - - Convert a value into Temperature. - - :param value: An instance of CommonTemperature - :type value: CommonTemperature - :return: The specified value translated to Temperature, or None if the value could not be translated. - :rtype: Union[Temperature, None] - """ - if value is None: - return None - if isinstance(value, Temperature): - return value - mapping = { - CommonTemperature.FREEZING: Temperature.FREEZING, - CommonTemperature.COLD: Temperature.COLD, - CommonTemperature.COOL: Temperature.COOL, - CommonTemperature.WARM: Temperature.WARM, - CommonTemperature.HOT: Temperature.HOT, - CommonTemperature.BURNING: Temperature.BURNING, - } - return mapping.get(value, None) - - @staticmethod - def convert_from_vanilla(value: Temperature) -> Union['CommonTemperature', None]: - """convert_from_vanilla(value) - - Convert a value into CommonTemperature. - - :param value: An instance of Temperature - :type value: Temperature - :return: The specified value translated to CommonTemperature, or None if the value could not be translated. - :rtype: Union[CommonTemperature, None] - """ - if value is None: - return None - if isinstance(value, CommonTemperature): - return value - mapping = { - Temperature.FREEZING: CommonTemperature.FREEZING, - Temperature.COLD: CommonTemperature.COLD, - Temperature.COOL: CommonTemperature.COOL, - Temperature.WARM: CommonTemperature.WARM, - Temperature.HOT: CommonTemperature.HOT, - Temperature.BURNING: CommonTemperature.BURNING, - } - return mapping.get(value, None) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_venue_civic_policy_ids.py b/Scripts/s4ap/sims4communitylib/enums/common_venue_civic_policy_ids.py deleted file mode 100644 index 410909d..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_venue_civic_policy_ids.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonVenueCivicPolicyId(CommonInt): - """ Identifiers of Venue Civic Policies. """ - COMMUNITY_LOT_DEFAULT: 'CommonVenueCivicPolicyId' = 228300 - COMMUNITY_LOT_GARDEN: 'CommonVenueCivicPolicyId' = 228267 - COMMUNITY_LOT_MAKER_SPACE: 'CommonVenueCivicPolicyId' = 231467 - COMMUNITY_LOT_MARKET: 'CommonVenueCivicPolicyId' = 228268 diff --git a/Scripts/s4ap/sims4communitylib/enums/common_voice_actor_type.py b/Scripts/s4ap/sims4communitylib/enums/common_voice_actor_type.py deleted file mode 100644 index 2f0dade..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_voice_actor_type.py +++ /dev/null @@ -1,102 +0,0 @@ -""" -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 -""" -from typing import Tuple, Iterator - -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonVoiceActorType(CommonInt): - """Various Voice Actor types.""" - UNKNOWN: 'CommonVoiceActorType' = 0 - MUTE: 'CommonVoiceActorType' = 1 - - # Special - KYLO_REN_1: 'CommonVoiceActorType' = 1719082469 - HONDO_OHNAKA_1: 'CommonVoiceActorType' = 1769415226 - REY_1: 'CommonVoiceActorType' = 1601639154 - - # Human - TODDLER_HUMAN_AMBIGUOUS_1: 'CommonVoiceActorType' = 1635194332 - - INFANT_HUMAN_AMBIGUOUS_1: 'CommonVoiceActorType' = 1752637603 - - CHILD_HUMAN_AMBIGUOUS_1: 'CommonVoiceActorType' = 1853303381 - CHILD_HUMAN_AMBIGUOUS_2: 'CommonVoiceActorType' = 1853303382 - - ADULT_HUMAN_AMBIGUOUS_1: 'CommonVoiceActorType' = 1802970399 - - ADULT_HUMAN_FEMININE_1: 'CommonVoiceActorType' = 1802970392 - ADULT_HUMAN_FEMININE_2: 'CommonVoiceActorType' = 1802970394 - - ADULT_HUMAN_MASCULINE_1: 'CommonVoiceActorType' = 1685527060 - ADULT_HUMAN_MASCULINE_2: 'CommonVoiceActorType' = 1685527061 - ADULT_HUMAN_MASCULINE_3: 'CommonVoiceActorType' = 1685527063 - - # Dog - CHILD_DOG_AMBIGUOUS_1: 'CommonVoiceActorType' = 1786192777 - - ADULT_DOG_AMBIGUOUS_1: 'CommonVoiceActorType' = 1836525760 - ADULT_DOG_AMBIGUOUS_2: 'CommonVoiceActorType' = 1836525762 - ADULT_DOG_AMBIGUOUS_3: 'CommonVoiceActorType' = 1836525763 - ADULT_DOG_AMBIGUOUS_4: 'CommonVoiceActorType' = 1836525765 - - # Cat - CHILD_CAT_AMBIGUOUS_1: 'CommonVoiceActorType' = 1719082493 - ADULT_CAT_AMBIGUOUS_1: 'CommonVoiceActorType' = 1702304872 - ADULT_CAT_AMBIGUOUS_2: 'CommonVoiceActorType' = 1702304875 - - # Fox - ADULT_FOX_AMBIGUOUS_1: 'CommonVoiceActorType' = 1886858530 - - # Horse - ADULT_HORSE_AMBIGUOUS_1: 'CommonVoiceActorType' = 1886858546 - CHILD_HORSE_AMBIGUOUS_1: 'CommonVoiceActorType' = 1853303388 - - @classmethod - def get_all(cls, exclude_values: Iterator['CommonVoiceActorType'] = None) -> Tuple['CommonVoiceActorType']: - """get_all(exclude_values=None) - - Get a collection of all values. - - :param exclude_values: These values will be excluded. If set to None, UNKNOWN will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonVoiceActorType], optional - :return: A collection of all values. - :rtype: Tuple[CommonVoiceActorType] - """ - if exclude_values is None: - exclude_values = (cls.UNKNOWN,) - # noinspection PyTypeChecker - value_list: Tuple[CommonVoiceActorType] = tuple([value for value in cls.values if value not in exclude_values]) - return value_list - - @classmethod - def get_all_names(cls, exclude_values: Iterator['CommonVoiceActorType'] = None) -> Tuple[str]: - """get_all_names(exclude_values=None) - - Retrieve a collection of the names of all values. - - :param exclude_values: These values will be excluded. If set to None, UNKNOWN will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonVoiceActorType], optional - :return: A collection of the names of all values. - :rtype: Tuple[str] - """ - name_list: Tuple[str] = tuple([value.name for value in cls.get_all(exclude_values=exclude_values)]) - return name_list - - @classmethod - def get_comma_separated_names_string(cls, exclude_values: Iterator['CommonVoiceActorType'] = None) -> str: - """get_comma_separated_names_string(exclude_values=None) - - Create a string containing all names of all values, separated by a comma. - - :param exclude_values: These values will be excluded. If set to None, UNKNOWN will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonVoiceActorType], optional - :return: A string containing all names of all values, separated by a comma. - :rtype: str - """ - return ', '.join(cls.get_all_names(exclude_values=exclude_values)) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_weather_effect_type.py b/Scripts/s4ap/sims4communitylib/enums/common_weather_effect_type.py deleted file mode 100644 index d784e2d..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_weather_effect_type.py +++ /dev/null @@ -1,124 +0,0 @@ -""" -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 -""" -from typing import Tuple, Union, Iterator - -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - -# noinspection PyBroadException -try: - from weather.weather_enums import WeatherEffectType -except: - class WeatherEffectType(CommonInt): - """Mock class.""" - WINDOW_FROST = 1004 - WATER_FROZEN = 1005 - WIND = 1006 - TEMPERATURE = 1007 - THUNDER = 1008 - LIGHTNING = 1009 - SNOW_FRESHNESS = 1010 - STRANGERVILLE_ACT = 1011 - ECO_FOOTPRINT = 1012 - ACID_RAIN = 1013 - # noinspection SpellCheckingInspection - STARWARS_RESISTANCE = 1014 - # noinspection SpellCheckingInspection - STARWARS_FIRST_ORDER = 1015 - SNOW_ICINESS = 1016 - - -class CommonWeatherEffectType(CommonInt): - """Identifiers for weather effects types.""" - WINDOW_FROST: 'CommonWeatherEffectType' = ... - WATER_FROZEN: 'CommonWeatherEffectType' = ... - WIND: 'CommonWeatherEffectType' = ... - TEMPERATURE: 'CommonWeatherEffectType' = ... - THUNDER: 'CommonWeatherEffectType' = ... - LIGHTNING: 'CommonWeatherEffectType' = ... - SNOW_FRESHNESS: 'CommonWeatherEffectType' = ... - STRANGERVILLE_ACT: 'CommonWeatherEffectType' = ... - ECO_FOOTPRINT: 'CommonWeatherEffectType' = ... - ACID_RAIN: 'CommonWeatherEffectType' = ... - STAR_WARS_RESISTANCE: 'CommonWeatherEffectType' = ... - STAR_WARS_FIRST_ORDER: 'CommonWeatherEffectType' = ... - SNOW_ICINESS: 'CommonWeatherEffectType' = ... - - @classmethod - def get_all(cls, exclude_values: Iterator['CommonWeatherEffectType'] = ()) -> Tuple['CommonWeatherEffectType']: - """get_all(exclude_values=()) - - Get a collection of all values. - - :param exclude_values: These values will be excluded. Default is an empty collection. - :type exclude_values: Iterator[CommonWeatherEffectType], optional - :return: A collection of all values. - :rtype: Tuple[CommonWeatherEffectType] - """ - # noinspection PyTypeChecker - value_list: Tuple[CommonWeatherEffectType, ...] = tuple([value for value in cls.values if value not in exclude_values]) - return value_list - - @staticmethod - def convert_to_vanilla(value: 'CommonWeatherEffectType') -> Union[WeatherEffectType, None]: - """convert_to_vanilla(value) - - Convert a CommonWeatherEffectType into WeatherEffectType. - - :param value: An instance of CommonWeatherEffectType - :type value: CommonWeatherEffectType - :return: The specified CommonWeatherEffectType translated to WeatherEffectType, or None if the value could not be translated. - :rtype: Union[WeatherEffectType, None] - """ - if isinstance(value, WeatherEffectType): - return value - mapping = { - CommonWeatherEffectType.WINDOW_FROST: WeatherEffectType.WINDOW_FROST, - CommonWeatherEffectType.WATER_FROZEN: WeatherEffectType.WATER_FROZEN, - CommonWeatherEffectType.WIND: WeatherEffectType.WIND, - CommonWeatherEffectType.TEMPERATURE: WeatherEffectType.TEMPERATURE, - CommonWeatherEffectType.THUNDER: WeatherEffectType.THUNDER, - CommonWeatherEffectType.LIGHTNING: WeatherEffectType.LIGHTNING, - CommonWeatherEffectType.SNOW_FRESHNESS: WeatherEffectType.SNOW_FRESHNESS, - CommonWeatherEffectType.STRANGERVILLE_ACT: WeatherEffectType.STRANGERVILLE_ACT, - CommonWeatherEffectType.ECO_FOOTPRINT: WeatherEffectType.ECO_FOOTPRINT, - CommonWeatherEffectType.ACID_RAIN: WeatherEffectType.ACID_RAIN, - CommonWeatherEffectType.STAR_WARS_RESISTANCE: WeatherEffectType.STARWARS_RESISTANCE, - CommonWeatherEffectType.STAR_WARS_FIRST_ORDER: WeatherEffectType.STARWARS_FIRST_ORDER, - CommonWeatherEffectType.SNOW_ICINESS: WeatherEffectType.SNOW_ICINESS, - } - return mapping.get(value, None) - - @staticmethod - def convert_from_vanilla(value: WeatherEffectType) -> Union['CommonWeatherEffectType', None]: - """convert_from_vanilla(value) - - Convert a vanilla WeatherEffectType into CommonWeatherEffectType. - - :param value: An instance of WeatherEffectType - :type value: WeatherEffectType - :return: The specified WeatherEffectType translated to CommonWeatherEffectType, or None if the value could not be translated. - :rtype: Union[CommonWeatherEffectType, None] - """ - if isinstance(value, CommonWeatherEffectType): - return value - mapping = { - WeatherEffectType.WINDOW_FROST: CommonWeatherEffectType.WINDOW_FROST, - WeatherEffectType.WATER_FROZEN: CommonWeatherEffectType.WATER_FROZEN, - WeatherEffectType.WIND: CommonWeatherEffectType.WIND, - WeatherEffectType.TEMPERATURE: CommonWeatherEffectType.TEMPERATURE, - WeatherEffectType.THUNDER: CommonWeatherEffectType.THUNDER, - WeatherEffectType.LIGHTNING: CommonWeatherEffectType.LIGHTNING, - WeatherEffectType.SNOW_FRESHNESS: CommonWeatherEffectType.SNOW_FRESHNESS, - WeatherEffectType.STRANGERVILLE_ACT: CommonWeatherEffectType.STRANGERVILLE_ACT, - WeatherEffectType.ECO_FOOTPRINT: CommonWeatherEffectType.ECO_FOOTPRINT, - WeatherEffectType.ACID_RAIN: CommonWeatherEffectType.ACID_RAIN, - WeatherEffectType.STARWARS_RESISTANCE: CommonWeatherEffectType.STAR_WARS_RESISTANCE, - WeatherEffectType.STARWARS_FIRST_ORDER: CommonWeatherEffectType.STAR_WARS_FIRST_ORDER, - WeatherEffectType.SNOW_ICINESS: CommonWeatherEffectType.SNOW_ICINESS, - } - return mapping.get(value, None) diff --git a/Scripts/s4ap/sims4communitylib/enums/common_weather_event_ids.py b/Scripts/s4ap/sims4communitylib/enums/common_weather_event_ids.py deleted file mode 100644 index 5174ab6..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_weather_event_ids.py +++ /dev/null @@ -1,58 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonWeatherEventId(CommonInt): - """Identifiers for weather events.""" - CLEAR: 'CommonWeatherEventId' = 182337 - CLEAR_BURNING: 'CommonWeatherEventId' = 182381 - CLEAR_COLD: 'CommonWeatherEventId' = 182377 - CLEAR_COOL: 'CommonWeatherEventId' = 182378 - CLEAR_FREEZING: 'CommonWeatherEventId' = 182380 - CLEAR_HOT: 'CommonWeatherEventId' = 182379 - CLEAR_SHOWER_COOL: 'CommonWeatherEventId' = 182383 - CLEAR_SHOWER_HOT: 'CommonWeatherEventId' = 182384 - CLEAR_SHOWER_WARM: 'CommonWeatherEventId' = 182343 - CLEAR_WINDY_BURNING: 'CommonWeatherEventId' = 182388 - CLEAR_WINDY_COLD: 'CommonWeatherEventId' = 182385 - CLEAR_WINDY_COOL: 'CommonWeatherEventId' = 182389 - CLEAR_WINDY_FREEZING: 'CommonWeatherEventId' = 182386 - CLEAR_WINDY_HOT: 'CommonWeatherEventId' = 182387 - CLEAR_WINDY_WARM: 'CommonWeatherEventId' = 182341 - CLOUDY_COLD: 'CommonWeatherEventId' = 182354 - CLOUDY_COOL: 'CommonWeatherEventId' = 182335 - CLOUDY_FREEZING: 'CommonWeatherEventId' = 182356 - CLOUDY_HOT: 'CommonWeatherEventId' = 182355 - CLOUDY_LIGHTNING: 'CommonWeatherEventId' = 188032 - CLOUDY_WARM: 'CommonWeatherEventId' = 182353 - FAST_RAIN: 'CommonWeatherEventId' = 184681 - HEATWAVE: 'CommonWeatherEventId' = 182344 - MAGIC_REALM: 'CommonWeatherEventId' = 221119 - PARTLY_CLOUDY_COLD: 'CommonWeatherEventId' = 182359 - PARTLY_CLOUDY_COOL: 'CommonWeatherEventId' = 182360 - PARTLY_CLOUDY_FREEZING: 'CommonWeatherEventId' = 182361 - PARTLY_CLOUDY_HOT: 'CommonWeatherEventId' = 182362 - PARTLY_CLOUDY_SNOW_COLD: 'CommonWeatherEventId' = 254595 - PARTLY_CLOUDY_SNOW_COOL: 'CommonWeatherEventId' = 188239 - PARTLY_CLOUDY_WARM: 'CommonWeatherEventId' = 182339 - PARTLY_CLOUDY_WARM_DEFAULT: 'CommonWeatherEventId' = 254183 - RAINSTORM_COLD: 'CommonWeatherEventId' = 182370 - RAINSTORM_COOL: 'CommonWeatherEventId' = 182332 - RAINSTORM_WARM: 'CommonWeatherEventId' = 182371 - RAINSTORM_WARM_MONSOON: 'CommonWeatherEventId' = 212683 - RAIN_HEAVY_COLD: 'CommonWeatherEventId' = 182367 - RAIN_HEAVY_COOL: 'CommonWeatherEventId' = 182325 - RAIN_HEAVY_WARM: 'CommonWeatherEventId' = 182368 - RAIN_LIGHT_COLD: 'CommonWeatherEventId' = 182363 - RAIN_LIGHT_COOL: 'CommonWeatherEventId' = 182322 - RAIN_LIGHT_WARM: 'CommonWeatherEventId' = 182365 - SNOWSTORM: 'CommonWeatherEventId' = 182331 - SNOW_HEAVY_FREEZING: 'CommonWeatherEventId' = 182374 - SNOW_LIGHT_FREEZING: 'CommonWeatherEventId' = 182376 - SNOW_THUNDERSTORM: 'CommonWeatherEventId' = 187809 diff --git a/Scripts/s4ap/sims4communitylib/enums/common_weather_type.py b/Scripts/s4ap/sims4communitylib/enums/common_weather_type.py deleted file mode 100644 index f4a2cce..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/common_weather_type.py +++ /dev/null @@ -1,280 +0,0 @@ -""" -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 -""" -from typing import Tuple, Union, Iterator - -from s4ap.sims4communitylib.enums.common_temperature import Temperature -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - -# noinspection PyBroadException -try: - from weather.weather_enums import WeatherType -except: - class WeatherType(CommonInt): - """Mock class.""" - Freezing = Temperature.FREEZING - Cold = Temperature.COLD - Cool = Temperature.COOL - Warm = Temperature.WARM - Hot = Temperature.HOT - Burning = Temperature.BURNING - UNDEFINED = 10 - AnySnow = 11 - AnyRain = 12 - Max_Snow_Accumulation = 13 - Max_Rain_Accumulation = 14 - AnyLightning = 15 - StruckByLightning = 16 - - -class CommonWeatherType(CommonInt): - """Identifiers for weather types.""" - UNDEFINED: 'CommonWeatherType' = ... - FREEZING: 'CommonWeatherType' = ... - COLD: 'CommonWeatherType' = ... - COOL: 'CommonWeatherType' = ... - WARM: 'CommonWeatherType' = ... - HOT: 'CommonWeatherType' = ... - BURNING: 'CommonWeatherType' = ... - ANY_SNOW: 'CommonWeatherType' = ... - ANY_RAIN: 'CommonWeatherType' = ... - MAX_SNOW_ACCUMULATION: 'CommonWeatherType' = ... - MAX_RAIN_ACCUMULATION: 'CommonWeatherType' = ... - ANY_LIGHTNING: 'CommonWeatherType' = ... - STRUCK_BY_LIGHTNING: 'CommonWeatherType' = ... - RAIN_LIGHT: 'CommonWeatherType' = ... - RAIN_HEAVY: 'CommonWeatherType' = ... - RAIN_STORM: 'CommonWeatherType' = ... - SNOW_LIGHT: 'CommonWeatherType' = ... - SNOW_HEAVY: 'CommonWeatherType' = ... - SNOW_STORM: 'CommonWeatherType' = ... - CLOUDY_PARTIAL: 'CommonWeatherType' = ... - CLOUDY_FULL: 'CommonWeatherType' = ... - WINDY: 'CommonWeatherType' = ... - SUN_SHOWER: 'CommonWeatherType' = ... - SUNNY: 'CommonWeatherType' = ... - HEATWAVE: 'CommonWeatherType' = ... - THUNDER: 'CommonWeatherType' = ... - MIN_SNOW_ACCUMULATION: 'CommonWeatherType' = ... - MED_SNOW_ACCUMULATION: 'CommonWeatherType' = ... - HIGH_SNOW_ACCUMULATION: 'CommonWeatherType' = ... - VAMPIRE_SAFE_CLOUD_LEVEL: 'CommonWeatherType' = ... - CLEAR_SKIES: 'CommonWeatherType' = ... - THUNDER_SNOW: 'CommonWeatherType' = ... - SUNSNOW: 'CommonWeatherType' = ... - DRY_LIGHTNING: 'CommonWeatherType' = ... - WINDY_HOT: 'CommonWeatherType' = ... - CLOUDY_WARM: 'CommonWeatherType' = ... - STRANGE_WEATHER: 'CommonWeatherType' = ... - SUNBATHING_WEATHER: 'CommonWeatherType' = ... - ICY: 'CommonWeatherType' = ... - FROZEN_WATER: 'CommonWeatherType' = ... - - @classmethod - def get_all(cls, exclude_values: Iterator['CommonWeatherType'] = None) -> Tuple['CommonWeatherType']: - """get_all(exclude_values=None) - - Get a collection of all values. - - :param exclude_values: These values will be excluded. If set to None, UNDEFINED will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonWeatherType], optional - :return: A collection of all values. - :rtype: Tuple[CommonWeatherType] - """ - if exclude_values is None: - exclude_values = (cls.UNDEFINED,) - # noinspection PyTypeChecker - value_list: Tuple[CommonWeatherType, ...] = tuple([value for value in cls.values if value not in exclude_values]) - return value_list - - @staticmethod - def convert_to_vanilla(value: 'CommonWeatherType') -> Union[WeatherType, None]: - """convert_to_vanilla(value) - - Convert a CommonWeatherType into WeatherType. - - :param value: An instance of CommonWeatherType - :type value: CommonWeatherType - :return: The specified CommonWeatherType translated to WeatherType, or None if the value could not be translated. - :rtype: Union[WeatherType, None] - """ - mapping = dict() - if hasattr(WeatherType, 'Freezing'): - mapping[CommonWeatherType.FREEZING] = WeatherType.Freezing - if hasattr(WeatherType, 'Cold'): - mapping[CommonWeatherType.COLD] = WeatherType.Cold - if hasattr(WeatherType, 'Cool'): - mapping[CommonWeatherType.COOL] = WeatherType.Cool - if hasattr(WeatherType, 'Warm'): - mapping[CommonWeatherType.WARM] = WeatherType.Warm - if hasattr(WeatherType, 'Hot'): - mapping[CommonWeatherType.HOT] = WeatherType.Hot - if hasattr(WeatherType, 'Burning'): - mapping[CommonWeatherType.BURNING] = WeatherType.Burning - if hasattr(WeatherType, 'UNDEFINED'): - mapping[CommonWeatherType.UNDEFINED] = WeatherType.UNDEFINED - if hasattr(WeatherType, 'AnySnow'): - mapping[CommonWeatherType.ANY_SNOW] = WeatherType.AnySnow - if hasattr(WeatherType, 'AnyRain'): - mapping[CommonWeatherType.ANY_RAIN] = WeatherType.AnyRain - if hasattr(WeatherType, 'Max_Snow_Accumulation'): - mapping[CommonWeatherType.MAX_SNOW_ACCUMULATION] = WeatherType.Max_Snow_Accumulation - if hasattr(WeatherType, 'Max_Rain_Accumulation'): - mapping[CommonWeatherType.MAX_RAIN_ACCUMULATION] = WeatherType.Max_Rain_Accumulation - if hasattr(WeatherType, 'AnyLightning'): - mapping[CommonWeatherType.ANY_LIGHTNING] = WeatherType.AnyLightning - if hasattr(WeatherType, 'StruckByLightning'): - mapping[CommonWeatherType.STRUCK_BY_LIGHTNING] = WeatherType.StruckByLightning - if hasattr(WeatherType, 'Rain_Light'): - mapping[CommonWeatherType.RAIN_LIGHT] = WeatherType.Rain_Light - if hasattr(WeatherType, 'Rain_Heavy'): - mapping[CommonWeatherType.RAIN_HEAVY] = WeatherType.Rain_Heavy - if hasattr(WeatherType, 'Rain_Storm'): - mapping[CommonWeatherType.RAIN_STORM] = WeatherType.Rain_Storm - if hasattr(WeatherType, 'Snow_Light'): - mapping[CommonWeatherType.SNOW_LIGHT] = WeatherType.Snow_Light - if hasattr(WeatherType, 'Snow_Heavy'): - mapping[CommonWeatherType.SNOW_HEAVY] = WeatherType.Snow_Heavy - if hasattr(WeatherType, 'Snow_Storm'): - mapping[CommonWeatherType.SNOW_STORM] = WeatherType.Snow_Storm - if hasattr(WeatherType, 'Cloudy_Partial'): - mapping[CommonWeatherType.CLOUDY_PARTIAL] = WeatherType.Cloudy_Partial - if hasattr(WeatherType, 'Cloudy_Full'): - mapping[CommonWeatherType.CLOUDY_FULL] = WeatherType.Cloudy_Full - if hasattr(WeatherType, 'Windy'): - mapping[CommonWeatherType.WINDY] = WeatherType.Windy - if hasattr(WeatherType, 'Sun_Shower'): - mapping[CommonWeatherType.SUN_SHOWER] = WeatherType.Sun_Shower - if hasattr(WeatherType, 'Sunny'): - mapping[CommonWeatherType.SUNNY] = WeatherType.Sunny - if hasattr(WeatherType, 'Heatwave'): - mapping[CommonWeatherType.HEATWAVE] = WeatherType.Heatwave - if hasattr(WeatherType, 'Thunder'): - mapping[CommonWeatherType.THUNDER] = WeatherType.Thunder - if hasattr(WeatherType, 'Min_Snow_Accumulation'): - mapping[CommonWeatherType.MIN_SNOW_ACCUMULATION] = WeatherType.Min_Snow_Accumulation - if hasattr(WeatherType, 'Med_Snow_Accumulation'): - mapping[CommonWeatherType.MED_SNOW_ACCUMULATION] = WeatherType.Med_Snow_Accumulation - if hasattr(WeatherType, 'High_Snow_Accumulation'): - mapping[CommonWeatherType.HIGH_SNOW_ACCUMULATION] = WeatherType.High_Snow_Accumulation - if hasattr(WeatherType, 'Vampire_Safe_CloudLevel'): - mapping[CommonWeatherType.VAMPIRE_SAFE_CLOUD_LEVEL] = WeatherType.Vampire_Safe_CloudLevel - if hasattr(WeatherType, 'Clear_Skies'): - mapping[CommonWeatherType.CLEAR_SKIES] = WeatherType.Clear_Skies - if hasattr(WeatherType, 'Thundersnow'): - mapping[CommonWeatherType.THUNDER_SNOW] = WeatherType.Thundersnow - if hasattr(WeatherType, 'Sunsnow'): - mapping[CommonWeatherType.SUNSNOW] = WeatherType.Sunsnow - if hasattr(WeatherType, 'Dry_Lightning'): - mapping[CommonWeatherType.DRY_LIGHTNING] = WeatherType.Dry_Lightning - if hasattr(WeatherType, 'Windy_Hot'): - mapping[CommonWeatherType.WINDY_HOT] = WeatherType.Windy_Hot - if hasattr(WeatherType, 'Cloudy_Warm'): - mapping[CommonWeatherType.CLOUDY_WARM] = WeatherType.Cloudy_Warm - if hasattr(WeatherType, 'StrangeWeather'): - mapping[CommonWeatherType.STRANGE_WEATHER] = WeatherType.StrangeWeather - if hasattr(WeatherType, 'Sunbathing_Weather'): - mapping[CommonWeatherType.SUNBATHING_WEATHER] = WeatherType.Sunbathing_Weather - if hasattr(WeatherType, 'Icy'): - mapping[CommonWeatherType.ICY] = WeatherType.Icy - if hasattr(WeatherType, 'Frozen_Water'): - mapping[CommonWeatherType.FROZEN_WATER] = WeatherType.Frozen_Water - return mapping.get(value, None) - - @staticmethod - def convert_from_vanilla(value: WeatherType) -> Union['CommonWeatherType', None]: - """convert_from_vanilla(value) - - Convert a vanilla WeatherType into CommonWeatherType. - - :param value: An instance of WeatherType - :type value: WeatherType - :return: The specified WeatherType translated to CommonWeatherType, or None if the value could not be translated. - :rtype: Union[CommonWeatherType, None] - """ - mapping = dict() - if hasattr(WeatherType, 'Freezing'): - mapping[WeatherType.Freezing] = CommonWeatherType.FREEZING - if hasattr(WeatherType, 'Cold'): - mapping[WeatherType.Cold] = CommonWeatherType.COLD - if hasattr(WeatherType, 'Cool'): - mapping[WeatherType.Cool] = CommonWeatherType.COOL - if hasattr(WeatherType, 'Warm'): - mapping[WeatherType.Warm] = CommonWeatherType.WARM - if hasattr(WeatherType, 'Hot'): - mapping[WeatherType.Hot] = CommonWeatherType.HOT - if hasattr(WeatherType, 'Burning'): - mapping[WeatherType.Burning] = CommonWeatherType.BURNING - if hasattr(WeatherType, 'UNDEFINED'): - mapping[WeatherType.UNDEFINED] = CommonWeatherType.UNDEFINED - if hasattr(WeatherType, 'AnySnow'): - mapping[WeatherType.AnySnow] = CommonWeatherType.ANY_SNOW - if hasattr(WeatherType, 'AnyRain'): - mapping[WeatherType.AnyRain] = CommonWeatherType.ANY_RAIN - if hasattr(WeatherType, 'Max_Snow_Accumulation'): - mapping[WeatherType.Max_Snow_Accumulation] = CommonWeatherType.MAX_SNOW_ACCUMULATION - if hasattr(WeatherType, 'Max_Rain_Accumulation'): - mapping[WeatherType.Max_Rain_Accumulation] = CommonWeatherType.MAX_RAIN_ACCUMULATION - if hasattr(WeatherType, 'AnyLightning'): - mapping[WeatherType.AnyLightning] = CommonWeatherType.ANY_LIGHTNING - if hasattr(WeatherType, 'StruckByLightning'): - mapping[WeatherType.StruckByLightning] = CommonWeatherType.STRUCK_BY_LIGHTNING - if hasattr(WeatherType, 'Rain_Light'): - mapping[WeatherType.Rain_Light] = CommonWeatherType.RAIN_LIGHT - if hasattr(WeatherType, 'Rain_Heavy'): - mapping[WeatherType.Rain_Heavy] = CommonWeatherType.RAIN_HEAVY - if hasattr(WeatherType, 'Rain_Storm'): - mapping[WeatherType.Rain_Storm] = CommonWeatherType.RAIN_STORM - if hasattr(WeatherType, 'Snow_Light'): - mapping[WeatherType.Snow_Light] = CommonWeatherType.SNOW_LIGHT - if hasattr(WeatherType, 'Snow_Heavy'): - mapping[WeatherType.Snow_Heavy] = CommonWeatherType.SNOW_HEAVY - if hasattr(WeatherType, 'Snow_Storm'): - mapping[WeatherType.Snow_Storm] = CommonWeatherType.SNOW_STORM - if hasattr(WeatherType, 'Cloudy_Partial'): - mapping[WeatherType.Cloudy_Partial] = CommonWeatherType.CLOUDY_PARTIAL - if hasattr(WeatherType, 'Cloudy_Full'): - mapping[WeatherType.Cloudy_Full] = CommonWeatherType.CLOUDY_FULL - if hasattr(WeatherType, 'Windy'): - mapping[WeatherType.Windy] = CommonWeatherType.WINDY - if hasattr(WeatherType, 'Sun_Shower'): - mapping[WeatherType.Sun_Shower] = CommonWeatherType.SUN_SHOWER - if hasattr(WeatherType, 'Sunny'): - mapping[WeatherType.Sunny] = CommonWeatherType.SUNNY - if hasattr(WeatherType, 'Heatwave'): - mapping[WeatherType.Heatwave] = CommonWeatherType.HEATWAVE - if hasattr(WeatherType, 'Thunder'): - mapping[WeatherType.Thunder] = CommonWeatherType.THUNDER - if hasattr(WeatherType, 'Min_Snow_Accumulation'): - mapping[WeatherType.Min_Snow_Accumulation] = CommonWeatherType.MIN_SNOW_ACCUMULATION - if hasattr(WeatherType, 'Med_Snow_Accumulation'): - mapping[WeatherType.Med_Snow_Accumulation] = CommonWeatherType.MED_SNOW_ACCUMULATION - if hasattr(WeatherType, 'High_Snow_Accumulation'): - mapping[WeatherType.High_Snow_Accumulation] = CommonWeatherType.HIGH_SNOW_ACCUMULATION - if hasattr(WeatherType, 'Vampire_Safe_CloudLevel'): - mapping[WeatherType.Vampire_Safe_CloudLevel] = CommonWeatherType.VAMPIRE_SAFE_CLOUD_LEVEL - if hasattr(WeatherType, 'Clear_Skies'): - mapping[WeatherType.Clear_Skies] = CommonWeatherType.CLEAR_SKIES - if hasattr(WeatherType, 'Thundersnow'): - mapping[WeatherType.Thundersnow] = CommonWeatherType.THUNDER_SNOW - if hasattr(WeatherType, 'Sunsnow'): - mapping[WeatherType.Sunsnow] = CommonWeatherType.SUNSNOW - if hasattr(WeatherType, 'Dry_Lightning'): - mapping[WeatherType.Dry_Lightning] = CommonWeatherType.DRY_LIGHTNING - if hasattr(WeatherType, 'Windy_Hot'): - mapping[WeatherType.Windy_Hot] = CommonWeatherType.WINDY_HOT - if hasattr(WeatherType, 'Cloudy_Warm'): - mapping[WeatherType.Cloudy_Warm] = CommonWeatherType.CLOUDY_WARM - if hasattr(WeatherType, 'StrangeWeather'): - mapping[WeatherType.StrangeWeather] = CommonWeatherType.STRANGE_WEATHER - if hasattr(WeatherType, 'Sunbathing_Weather'): - mapping[WeatherType.Sunbathing_Weather] = CommonWeatherType.SUNBATHING_WEATHER - if hasattr(WeatherType, 'Icy'): - mapping[WeatherType.Icy] = CommonWeatherType.ICY - if hasattr(WeatherType, 'Frozen_Water'): - mapping[WeatherType.Frozen_Water] = CommonWeatherType.FROZEN_WATER - return mapping.get(value, None) diff --git a/Scripts/s4ap/sims4communitylib/enums/enumtypes/__init__.py b/Scripts/s4ap/sims4communitylib/enums/enumtypes/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/enumtypes/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/enums/enumtypes/common_int.py b/Scripts/s4ap/sims4communitylib/enums/enumtypes/common_int.py deleted file mode 100644 index 3c93619..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/enumtypes/common_int.py +++ /dev/null @@ -1,130 +0,0 @@ -""" -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 -""" -from collections import OrderedDict -from typing import Iterator, Union, Tuple - -# noinspection PyBroadException -try: - # noinspection PyUnresolvedReferences - from enum import Int -except: - # Created from example provided at https://stackoverflow.com/questions/5189699/how-to-make-a-class-property - # noinspection PyMissingOrEmptyDocstring - class _ClassPropertyDescriptor(object): - - # noinspection PyMissingTypeHints,SpellCheckingInspection - def __init__(self, fget, fset=None): - self.fget = fget - self.fset = fset - - # noinspection PyMissingTypeHints,SpellCheckingInspection - def __get__(self, obj, klass=None): - if klass is None: - # noinspection SpellCheckingInspection - klass = type(obj) - return self.fget.__get__(obj, klass)() - - # noinspection PyMissingTypeHints - def __set__(self, obj, value): - if not self.fset: - raise AttributeError("can't set attribute") - type_ = type(obj) - return self.fset.__get__(obj, type_)(value) - - # noinspection PyMissingTypeHints - def setter(self, func): - if not isinstance(func, (classmethod, staticmethod)): - func = classmethod(func) - # noinspection SpellCheckingInspection - self.fset = func - return self - - # noinspection PyMissingTypeHints,SpellCheckingInspection - def _classproperty(func): - if not isinstance(func, (classmethod, staticmethod)): - func = classmethod(func) - return _ClassPropertyDescriptor(func) - - # noinspection PyMissingOrEmptyDocstring - class Int: - # noinspection PyPropertyDefinition - @property - def name(self) -> str: - return '' - - # noinspection PyPropertyDefinition - @property - def value(self) -> int: - return 0 - - # noinspection PyPropertyDefinition,PyMethodParameters - @_classproperty - def values(cls) -> Iterator[int]: - return tuple() - - # noinspection PyPropertyDefinition,PyMethodParameters - @_classproperty - def name_to_value(cls) -> OrderedDict: - return OrderedDict() - - # noinspection PyPropertyDefinition,PyMethodParameters - @_classproperty - def value_to_name(cls) -> OrderedDict: - return OrderedDict() - - def __int__(self) -> int: - pass - - def __float__(self) -> float: - pass - - def __sub__(self, other: Union['Int', int]) -> int: - pass - - def __invert__(self) -> int: - pass - - def __add__(self, other: Union['Int', int]) -> int: - pass - - def __divmod__(self, other: Union['Int', int]) -> Tuple[int, int]: - pass - - def __mod__(self, other: Union['Int', int]) -> int: - pass - - def __mul__(self, other: Union['Int', int]) -> int: - pass - - def __neg__(self) -> int: - pass - - def __ge__(self, other: Union['Int', int]) -> bool: - pass - - def __le__(self, other: Union['Int', int]) -> bool: - pass - - def __lt__(self, other: Union['Int', int]) -> bool: - pass - - def __gt__(self, other: Union['Int', int]) -> bool: - pass - - def __eq__(self, other: Union['Int', int]) -> bool: - pass - - def __hash__(self) -> int: - pass - - -class CommonInt(Int): - """An inheritable class that inherits from the vanilla Sims 4 enum.Int class so you don't have to. - - """ - pass diff --git a/Scripts/s4ap/sims4communitylib/enums/enumtypes/common_int_flags.py b/Scripts/s4ap/sims4communitylib/enums/enumtypes/common_int_flags.py deleted file mode 100644 index abde036..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/enumtypes/common_int_flags.py +++ /dev/null @@ -1,160 +0,0 @@ -""" -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 -""" -from collections import OrderedDict -from typing import Iterator, Union, Tuple, List - -# noinspection PyBroadException -try: - # noinspection PyUnresolvedReferences - from enum import IntFlags -except: - # noinspection PyMissingOrEmptyDocstring - class _ClassPropertyDescriptor(object): - - # noinspection PyMissingTypeHints,SpellCheckingInspection - def __init__(self, fget, fset=None): - self.fget = fget - self.fset = fset - - # noinspection PyMissingTypeHints,SpellCheckingInspection - def __get__(self, obj, klass=None): - if klass is None: - # noinspection SpellCheckingInspection - klass = type(obj) - return self.fget.__get__(obj, klass)() - - # noinspection PyMissingTypeHints - def __set__(self, obj, value): - if not self.fset: - raise AttributeError("can't set attribute") - type_ = type(obj) - return self.fset.__get__(obj, type_)(value) - - # noinspection PyMissingTypeHints - def setter(self, func): - if not isinstance(func, (classmethod, staticmethod)): - func = classmethod(func) - # noinspection SpellCheckingInspection - self.fset = func - return self - - - # noinspection PyMissingTypeHints,SpellCheckingInspection - def _classproperty(func): - if not isinstance(func, (classmethod, staticmethod)): - func = classmethod(func) - return _ClassPropertyDescriptor(func) - - # noinspection PyMissingOrEmptyDocstring - class IntFlags: - # From Int - # noinspection PyPropertyDefinition - @property - def name(self) -> str: - return '' - - # noinspection PyPropertyDefinition - @property - def value(self) -> int: - return 0 - - # noinspection PyPropertyDefinition,PyMethodParameters - @_classproperty - def values(cls) -> Iterator[int]: - return tuple() - - # noinspection PyPropertyDefinition,PyMethodParameters - @_classproperty - def name_to_value(cls) -> OrderedDict: - return OrderedDict() - - # noinspection PyPropertyDefinition,PyMethodParameters - @_classproperty - def value_to_name(cls) -> OrderedDict: - return OrderedDict() - - def __int__(self) -> int: - pass - - def __float__(self) -> float: - pass - - def __sub__(self, other: Union['IntFlags', int]) -> int: - pass - - def __invert__(self) -> int: - pass - - def __add__(self, other: Union['IntFlags', int]) -> int: - pass - - # noinspection SpellCheckingInspection - def __divmod__(self, other: Union['IntFlags', int]) -> Tuple[int, int]: - pass - - def __mod__(self, other: Union['IntFlags', int]) -> int: - pass - - def __mul__(self, other: Union['IntFlags', int]) -> int: - pass - - def __neg__(self) -> int: - pass - - def __ge__(self, other: Union['IntFlags', int]) -> bool: - pass - - def __le__(self, other: Union['IntFlags', int]) -> bool: - pass - - def __lt__(self, other: Union['IntFlags', int]) -> bool: - pass - - def __gt__(self, other: Union['IntFlags', int]) -> bool: - pass - - def __eq__(self, other: Union['IntFlags', int]) -> bool: - pass - - def __hash__(self) -> int: - pass - - # From IntFlags - @classmethod - def _get_unknown_value(cls, value: 'IntFlags') -> 'IntFlags': - pass - - @staticmethod - def _next_auto_value(value: 'IntFlags') -> 'IntFlags': - pass - - def _get_bits(self) -> Tuple[List[int], 'IntFlags']: - pass - - @classmethod - def list_values_from_flags(cls, value: 'IntFlags') -> List['IntFlags']: - pass - - def __iter__(self) -> Iterator['IntFlags']: - pass - - def __contains__(self, value: 'IntFlags'): - pass - - def __and__(self, other: 'IntFlags'): - pass - - def __or__(self, other: 'IntFlags'): - pass - - -class CommonIntFlags(IntFlags): - """An inheritable class that inherits from the vanilla Sims 4 enum.IntFlags class so you don't have to. - - """ - pass diff --git a/Scripts/s4ap/sims4communitylib/enums/enumtypes/common_versioned_int.py b/Scripts/s4ap/sims4communitylib/enums/enumtypes/common_versioned_int.py deleted file mode 100644 index 95c1871..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/enumtypes/common_versioned_int.py +++ /dev/null @@ -1,55 +0,0 @@ -""" -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 -""" -from typing import Set, Dict - -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt -from s4ap.sims4communitylib.enums.enumtypes.common_versioned_values_mixin import CommonVersionedValuesMixin - - -class CommonVersionedInt(CommonInt, CommonVersionedValuesMixin): - """Integer, but with a version.""" - - @classmethod - def get_version(cls) -> str: - """The version of the enum. If this changes, it means values have changed and should be updated.""" - raise NotImplementedError() - - @classmethod - def is_obsolete_value(cls, value: 'CommonVersionedInt') -> bool: - """Determine if a value is considered to be obsolete.""" - return value in cls.get_obsolete_values() - - @classmethod - def get_obsolete_values(cls) -> Set['CommonVersionedInt']: - """Retrieve a set of values considered as obsolete.""" - raise NotImplementedError() - - @classmethod - def _get_obsolete_conversion_mapping(cls) -> Dict['CommonVersionedInt', 'CommonVersionedInt']: - """_get_obsolete_conversion_mapping() - - Retrieve a mapping of obsolete values into non-obsolete values. - - :return: A mapping of obsolete values into non-obsolete values. - :type: Dict[CommonVersionedInt, CommonVersionedInt] - """ - raise NotImplementedError() - - @classmethod - def convert_obsolete_value(cls, value: 'CommonVersionedInt') -> 'CommonVersionedInt': - """convert_obsolete_value(value) - - Convert an obsolete value to its new equivalent, if there is one. - - - """ - mapping: Dict[CommonVersionedInt, CommonVersionedInt] = cls._get_obsolete_conversion_mapping() - convert_value = mapping.get(value, value) - if convert_value == value: - return convert_value - return cls.convert_obsolete_value(convert_value) diff --git a/Scripts/s4ap/sims4communitylib/enums/enumtypes/common_versioned_int_flags.py b/Scripts/s4ap/sims4communitylib/enums/enumtypes/common_versioned_int_flags.py deleted file mode 100644 index 8a238f1..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/enumtypes/common_versioned_int_flags.py +++ /dev/null @@ -1,55 +0,0 @@ -""" -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 -""" -from typing import Set, Dict - -from s4ap.sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags -from s4ap.sims4communitylib.enums.enumtypes.common_versioned_values_mixin import CommonVersionedValuesMixin - - -class CommonVersionedIntFlags(CommonIntFlags, CommonVersionedValuesMixin): - """Integer flags, but with a version.""" - - @classmethod - def get_version(cls) -> str: - """The version of the enum. If this changes, it means values have changed and should be updated.""" - raise NotImplementedError() - - @classmethod - def is_obsolete_value(cls, value: 'CommonVersionedIntFlags') -> bool: - """Determine if a value is considered to be obsolete.""" - return value in cls.get_obsolete_values() - - @classmethod - def get_obsolete_values(cls) -> Set['CommonVersionedIntFlags']: - """Retrieve a set of values considered as obsolete.""" - raise NotImplementedError() - - @classmethod - def _get_obsolete_conversion_mapping(cls) -> Dict['CommonVersionedIntFlags', 'CommonVersionedIntFlags']: - """_get_obsolete_conversion_mapping() - - Retrieve a mapping of obsolete values into non-obsolete values. - - :return: A mapping of obsolete values into non-obsolete values. - :type: Dict[CommonVersionedIntFlags, CommonVersionedIntFlags] - """ - raise NotImplementedError() - - @classmethod - def convert_obsolete_value(cls, value: 'CommonVersionedIntFlags') -> 'CommonVersionedIntFlags': - """convert_obsolete_value(value) - - Convert an obsolete value to its new equivalent, if there is one. - - - """ - mapping: Dict[CommonVersionedIntFlags, CommonVersionedIntFlags] = cls._get_obsolete_conversion_mapping() - convert_value = mapping.get(value, value) - if convert_value == value: - return convert_value - return cls.convert_obsolete_value(convert_value) diff --git a/Scripts/s4ap/sims4communitylib/enums/enumtypes/common_versioned_values_mixin.py b/Scripts/s4ap/sims4communitylib/enums/enumtypes/common_versioned_values_mixin.py deleted file mode 100644 index 5a038ab..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/enumtypes/common_versioned_values_mixin.py +++ /dev/null @@ -1,52 +0,0 @@ -""" -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 -""" -from typing import Set, Dict - - -class CommonVersionedValuesMixin: - """A mixin that provides versioning for values.""" - - @classmethod - def get_version(cls) -> str: - """The version of the enum. If this changes, it means values have changed and should be updated.""" - raise NotImplementedError() - - @classmethod - def is_obsolete_value(cls, value: 'CommonVersionedValuesMixin') -> bool: - """Determine if a value is considered to be obsolete.""" - return value in cls.get_obsolete_values() - - @classmethod - def get_obsolete_values(cls) -> Set['CommonVersionedValuesMixin']: - """Retrieve a set of values considered as obsolete.""" - raise NotImplementedError() - - @classmethod - def _get_obsolete_conversion_mapping(cls) -> Dict['CommonVersionedValuesMixin', 'CommonVersionedValuesMixin']: - """_get_obsolete_conversion_mapping() - - Retrieve a mapping of obsolete values into non-obsolete values. - - :return: A mapping of obsolete values into non-obsolete values. - :type: Dict[CommonVersionedValuesMixin, CommonVersionedValuesMixin] - """ - raise NotImplementedError() - - @classmethod - def convert_obsolete_value(cls, value: 'CommonVersionedValuesMixin') -> 'CommonVersionedValuesMixin': - """convert_obsolete_value(value) - - Convert an obsolete value to its new equivalent, if there is one. - - - """ - mapping: Dict[CommonVersionedValuesMixin, CommonVersionedValuesMixin] = cls._get_obsolete_conversion_mapping() - convert_value = mapping.get(value, value) - if convert_value == value: - return convert_value - return cls.convert_obsolete_value(convert_value) diff --git a/Scripts/s4ap/sims4communitylib/enums/enumtypes/float_enum.py b/Scripts/s4ap/sims4communitylib/enums/enumtypes/float_enum.py deleted file mode 100644 index 8e56576..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/enumtypes/float_enum.py +++ /dev/null @@ -1,87 +0,0 @@ -""" -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 -""" -from typing import Any -from s4ap.sims4communitylib.enums.common_enum import CommonEnumMetaclass - - -class CommonEnumFloat(float): - """CommonEnumFloat(enum_name, enum_value, class_name) - - An enum that holds a float value. - - :param enum_name: The name of the enum. - :type enum_name: str - :param enum_value: The value of the enum. - :type enum_value: float - :param class_name: The name of the class containing the enum. - :type class_name: str - """ - def __init__(self, enum_name: str, enum_value: float, class_name: str): - super().__init__() - self._name = enum_name - self._value = enum_value - self._class_name = class_name - - def __new__(cls, _, enum_value: float, class_name: str): - return super().__new__(cls, enum_value) - - @property - def name(self) -> str: - """The name of the enum. - - :return: The name of the enum. - :rtype: str - """ - return self._name - - @property - def value(self) -> float: - """The value of the enum. - - :return: The value of the enum. - :rtype: float - """ - return self._value - - def __eq__(self, other: Any): - other_value = other - if hasattr(other, 'value'): - other_value = other.value - return self.value.__eq__(other_value) - - def __repr__(self) -> str: - return '{}.{}'.format(self._class_name, self.name) - - def __str__(self) -> str: - return self.__repr__() - - def __hash__(self) -> int: - return hash(self.value) - - -class CommonEnumFloatMetaclass(CommonEnumMetaclass): - """A metaclass for float enums. - - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_enum_type(mcs) -> Any: - return float - - @classmethod - def _get_common_enum(mcs, enum_name: str, enum_value: float, class_name: str): - return CommonEnumFloat(enum_name, enum_value, class_name) - - -class CommonEnumFloatBase(float, metaclass=CommonEnumFloatMetaclass): - """An inheritable class to turn properties into float enums. - - """ - def __call__(self, val) -> CommonEnumFloat: - pass diff --git a/Scripts/s4ap/sims4communitylib/enums/enumtypes/int_enum.py b/Scripts/s4ap/sims4communitylib/enums/enumtypes/int_enum.py deleted file mode 100644 index eae7837..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/enumtypes/int_enum.py +++ /dev/null @@ -1,90 +0,0 @@ -""" -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 -""" -from typing import Any - -from s4ap.sims4communitylib.enums.common_enum import CommonEnumMetaclass - - -class CommonEnumInt(int): - """CommonEnumInt(enum_name, enum_value, class_name) - - An enum that holds an integer value. - - :param enum_name: The name of the enum. - :type enum_name: str - :param enum_value: The value of the enum. - :type enum_value: int - :param class_name: The name of the class containing the enum. - :type class_name: str - """ - def __init__(self, enum_name: str, enum_value: int, class_name: str): - super().__init__() - self._name = enum_name - self._value = enum_value - self._class_name = class_name - - def __new__(cls, _, enum_value: int, class_name: str): - return super().__new__(cls, enum_value) - - @property - def name(self) -> str: - """The name of the enum. - - :return: The name of the enum. - :rtype: str - """ - return self._name - - @property - def value(self) -> int: - """The value of the enum. - - :return: The value of the enum. - :rtype: int - """ - return self._value - - def __eq__(self, other: Any): - other_value = other - if hasattr(other, 'value'): - other_value = other.value - return self.value.__eq__(other_value) - - def __repr__(self) -> str: - return '{}.{}'.format(self._class_name, self.name) - - def __str__(self) -> str: - return self.__repr__() - - def __hash__(self) -> int: - return hash(self.value) - - -class CommonEnumIntMetaclass(CommonEnumMetaclass): - """A metaclass for integer enums. - - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_enum_type(mcs) -> Any: - return int - - @classmethod - def _get_common_enum(mcs, enum_name: str, enum_value: int, class_name: str): - return CommonEnumInt(enum_name, enum_value, class_name) - - -class CommonEnumIntBase(int, metaclass=CommonEnumIntMetaclass): - """An inheritable class to turn properties into integer enums. - - .. warning:: This class is obsolete, please inherit from :class:`.CommonInt` instead. - - """ - def __call__(self, val) -> CommonEnumInt: - pass diff --git a/Scripts/s4ap/sims4communitylib/enums/enumtypes/object_enum.py b/Scripts/s4ap/sims4communitylib/enums/enumtypes/object_enum.py deleted file mode 100644 index 7c943dc..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/enumtypes/object_enum.py +++ /dev/null @@ -1,87 +0,0 @@ -""" -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 -""" -from typing import Any -from s4ap.sims4communitylib.enums.common_enum import CommonEnumMetaclass - - -class CommonEnumObject(object): - """CommonEnumObject(enum_name, enum_value, class_name) - - An enum that holds an object value. - - :param enum_name: The name of the enum. - :type enum_name: str - :param enum_value: The value of the enum. - :type enum_value: object - :param class_name: The name of the class containing the enum. - :type class_name: str - """ - def __init__(self, enum_name: str, enum_value: object, class_name: str): - super().__init__() - self._name = enum_name - self._value = enum_value - self._class_name = class_name - - def __new__(cls, _, enum_value: object, class_name: str): - return super().__new__(cls, enum_value) - - @property - def name(self) -> str: - """The name of the enum. - - :return: The name of the enum. - :rtype: str - """ - return self._name - - @property - def value(self) -> object: - """The value of the enum. - - :return: The value of the enum. - :rtype: object - """ - return self._value - - def __eq__(self, other: Any): - other_value = other - if hasattr(other, 'value'): - other_value = other.value - return self.value.__eq__(other_value) - - def __repr__(self) -> str: - return '{}.{}'.format(self._class_name, self.name) - - def __str__(self) -> str: - return self.__repr__() - - def __hash__(self) -> int: - return hash(self.value) - - -class CommonEnumObjectMetaclass(CommonEnumMetaclass): - """A metaclass for object enums. - - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_enum_type(mcs) -> Any: - return object - - @classmethod - def _get_common_enum(mcs, enum_name: str, enum_value: object, class_name: str): - return CommonEnumObject(enum_name, enum_value, class_name) - - -class CommonEnumObjectBase(object, metaclass=CommonEnumObjectMetaclass): - """An inheritable class to turn properties of the class into object enums. - - """ - def __call__(self, val) -> CommonEnumObject: - pass diff --git a/Scripts/s4ap/sims4communitylib/enums/enumtypes/string_enum.py b/Scripts/s4ap/sims4communitylib/enums/enumtypes/string_enum.py deleted file mode 100644 index d133e16..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/enumtypes/string_enum.py +++ /dev/null @@ -1,87 +0,0 @@ -""" -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 -""" -from typing import Any -from s4ap.sims4communitylib.enums.common_enum import CommonEnumMetaclass - - -class CommonEnumString(str): - """CommonEnumString(enum_name, enum_value, class_name) - - An enum that holds a string value. - - :param enum_name: The name of the enum. - :type enum_name: str - :param enum_value: The value of the enum. - :type enum_value: str - :param class_name: The name of the class containing the enum. - :type class_name: str - """ - def __init__(self, enum_name: str, enum_value: str, class_name: str): - super().__init__() - self._name = enum_name - self._value = enum_value - self._class_name = class_name - - def __new__(cls, _, enum_value: float, class_name: str): - return super().__new__(cls, enum_value) - - @property - def name(self) -> str: - """The name of the enum. - - :return: The name of the enum. - :rtype: str - """ - return self._name - - @property - def value(self) -> str: - """The value of the enum. - - :return: The value of the enum. - :rtype: str - """ - return self._value - - def __eq__(self, other: Any): - other_value = other - if hasattr(other, 'value'): - other_value = other.value - return self.value.__eq__(other_value) - - def __repr__(self) -> str: - return '{}.{}'.format(self._class_name, self.name) - - def __str__(self) -> str: - return self.__repr__() - - def __hash__(self) -> int: - return hash(self.value) - - -class CommonEnumStringMetaclass(CommonEnumMetaclass): - """A metaclass for string enums. - - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_enum_type(mcs) -> Any: - return str - - @classmethod - def _get_common_enum(mcs, enum_name: str, enum_value: str, class_name: str): - return CommonEnumString(enum_name, enum_value, class_name) - - -class CommonEnumStringBase(str, metaclass=CommonEnumStringMetaclass): - """An inheritable class to turn properties into string enums. - - """ - def __call__(self, val) -> CommonEnumString: - pass diff --git a/Scripts/s4ap/sims4communitylib/enums/furniture_objects_enum.py b/Scripts/s4ap/sims4communitylib/enums/furniture_objects_enum.py deleted file mode 100644 index 4c0f435..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/furniture_objects_enum.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonFurnitureObjectId(CommonInt): - """Identifiers for vanilla furniture. - - """ - INVALID: 'CommonFurnitureObjectId' = 0 - BASSINET_EMPTY_01: 'CommonFurnitureObjectId' = 36210 diff --git a/Scripts/s4ap/sims4communitylib/enums/icons_enum.py b/Scripts/s4ap/sims4communitylib/enums/icons_enum.py deleted file mode 100644 index ffa89b2..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/icons_enum.py +++ /dev/null @@ -1,31 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonIconId(CommonInt): - """Identifiers for vanilla and Sims 4 Community Library icons. - - """ - # S4CL - INVALID: 'CommonIconId' = 0 - S4CLIB_ARROW_RIGHT_ICON: 'CommonIconId' = 3589997896388655139 - S4CLIB_ARROW_LEFT_ICON: 'CommonIconId' = 13667220474349513917 - S4CLIB_BLANK_SQUARE_ICON: 'CommonIconId' = 4439072745437234428 - S4CLIB_TEXT_PREV_SQUARE_ICON: 'CommonIconId' = 1424335400624427567 - S4CLIB_TEXT_NEXT_SQUARE_ICON: 'CommonIconId' = 14634347509917412899 - S4CLIB_UNFILLED_CIRCLE_ICON: 'CommonIconId' = 9610273937086697256 - S4CLIB_FILLED_CIRCLE_ICON: 'CommonIconId' = 10758398356376085395 - S4CLIB_CHECKED_CIRCLE_ICON: 'CommonIconId' = 16231466457332412750 - S4CLIB_X_ICON: 'CommonIconId' = 9145956676194943410 - S4CLIB_ARROW_NAVIGATE_INTO_ICON: 'CommonIconId' = 17672018034831121750 - S4CLIB_QUESTION_MARK_ICON: 'CommonIconId' = 16712671502182128037 - S4CLIB_SIX_SIDED_DICE_ICON: 'CommonIconId' = 1749603411595915770 - S4CLIB_CHECKED_SQUARE_ICON: 'CommonIconId' = 12632258471925492012 - S4CLIB_UNCHECKED_SQUARE_ICON: 'CommonIconId' = 6160391714040730819 - MISSING_IMAGE_ICON: 'CommonIconId' = 3526464109639239417 diff --git a/Scripts/s4ap/sims4communitylib/enums/interactions_enum.py b/Scripts/s4ap/sims4communitylib/enums/interactions_enum.py deleted file mode 100644 index 5ef9c64..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/interactions_enum.py +++ /dev/null @@ -1,145 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonInteractionId(CommonInt): - """Identifiers for interactions. - - """ - INVALID: 'CommonInteractionId' = 0 - PICK_UP_SIM: 'CommonInteractionId' = 141018 - PICK_UP_SIM_REVERSED: 'CommonInteractionId' = 141925 - CARRY_PICK_UP_TO_BED: 'CommonInteractionId' = 156217 - CARRY_PICK_UP: 'CommonInteractionId' = 134423 - CARRY_PICK_UP_FROM_SEATED: 'CommonInteractionId' = 155633 - CARRY_HUG: 'CommonInteractionId' = 155721 - CARRY_HOLD_OBJECT: 'CommonInteractionId' = 13135 - CARRY_HOLD_SIM: 'CommonInteractionId' = 132170 - CALL_INTO_ARMS_PICK_UP_PET: 'CommonInteractionId' = 173668 - SIM_TO_PET_NON_TOUCHING_PICKUP_PET: 'CommonInteractionId' = 186124 - SOCIAL_MIXER_SUPER_PICK_UP_PET: 'CommonInteractionId' = 160585 - MIXER_SOCIAL_T_PETS_FRIENDLY_HOLD_UP_CARRYING_CHILD: 'CommonInteractionId' = 168236 - GO_HERE: 'CommonInteractionId' = 14410 - SUPER_INTERACTION_GO_HERE: 'CommonInteractionId' = 27242 - GUITAR_PRACTICE: 'CommonInteractionId' = 13471 - - SIM_STAND: 'CommonInteractionId' = 13983 - SIM_STAND_EXCLUSIVE: 'CommonInteractionId' = 23835 - STAND_PASSIVE: 'CommonInteractionId' = 14310 - SIM_SWIM: 'CommonInteractionId' = 102325 - SIM_CHAT: 'CommonInteractionId' = 13998 - SIM_BE_AFFECTIONATE: 'CommonInteractionId' = 13991 - CAT_STAND: 'CommonInteractionId' = 120562 - CAT_STAND_PASSIVE: 'CommonInteractionId' = 120558 - DOG_STAND: 'CommonInteractionId' = 120569 - DOG_STAND_PASSIVE: 'CommonInteractionId' = 120561 - DOG_SWIM: 'CommonInteractionId' = 170682 - DOG_SWIM_PASSIVE: 'CommonInteractionId' = 174558 - FOX_STAND: 'CommonInteractionId' = 257164 - FOX_STAND_PASSIVE: 'CommonInteractionId' = 257160 - - HORSE_STAND: 'CommonInteractionId' = 120430 - HORSE_STAND_PASSIVE: 'CommonInteractionId' = 120431 - - # Deliver Baby - DELIVER_BABY_CAT: 'CommonInteractionId' = 159901 - DELIVER_BABY_DOG: 'CommonInteractionId' = 159902 - BASSINET_DELIVER_BABY: 'CommonInteractionId' = 13070 - SIM_DELIVER_BABY_CREATE_BASSINET: 'CommonInteractionId' = 97294 - - # Sit - SEATING_SIT: 'CommonInteractionId' = 31564 - SEATING_SIT_TODDLER_BED: 'CommonInteractionId' = 156920 - SEATING_SIT_SINGLE: 'CommonInteractionId' = 74779 - SEATING_SIT_CTYAE: 'CommonInteractionId' = 157667 - SEATING_SIT_RESTAURANT_RALLY_ONLY: 'CommonInteractionId' = 134949 - SEATING_SIT_POST_GRAND_MEAL_WAIT_ENJOY_COMPANY: 'CommonInteractionId' = 182774 - SEATING_SIT_DIRECTOR_CHAIR: 'CommonInteractionId' = 191162 - SEATING_SIT_HAIR_MAKE_UP_CHAIR: 'CommonInteractionId' = 201508 - SIT_PASSIVE: 'CommonInteractionId' = 14244 - - # Shower - GENERIC_SHOWER: 'CommonInteractionId' = 13439 - SHOWER_TAKE_SHOWER: 'CommonInteractionId' = 13950 - SHOWER_TAKE_SHOWER_NO_PRIVACY: 'CommonInteractionId' = 110817 - SHOWER_TAKE_SHOWER_PASSIVE: 'CommonInteractionId' = 13952 - SHOWER_TAKE_SHOWER_APARTMENT_NEIGHBOR_FLIRTY: 'CommonInteractionId' = 154397 - SHOWER_TAKE_SHOWER_BRISK: 'CommonInteractionId' = 39965 - SHOWER_TAKE_SHOWER_BRISK_NO_PRIVACY: 'CommonInteractionId' = 110818 - SHOWER_TAKE_SHOWER_COLD_SHOWER: 'CommonInteractionId' = 24332 - SHOWER_TAKE_SHOWER_COLD_SHOWER_NO_PRIVACY: 'CommonInteractionId' = 110819 - SHOWER_TAKE_SHOWER_ENERGIZED: 'CommonInteractionId' = 23839 - SHOWER_TAKE_SHOWER_ENERGIZED_NO_PRIVACY: 'CommonInteractionId' = 110820 - SHOWER_TAKE_SHOWER_SING_IN_SHOWER: 'CommonInteractionId' = 141926 - SHOWER_TAKE_SHOWER_STEAMY: 'CommonInteractionId' = 39860 - SHOWER_TAKE_SHOWER_STEAMY_NO_PRIVACY: 'CommonInteractionId' = 110821 - SHOWER_TAKE_SHOWER_THOUGHTFUL: 'CommonInteractionId' = 39845 - SHOWER_TAKE_SHOWER_THOUGHTFUL_NO_PRIVACY: 'CommonInteractionId' = 110822 - SUPER_INTERACTION_CAMPING_BATHROOM_SHOWER_FEMALE: 'CommonInteractionId' = 104658 - SUPER_INTERACTION_CAMPING_BATHROOM_SHOWER_MALE: 'CommonInteractionId' = 104659 - SIM_RAIN_SHOWER: 'CommonInteractionId' = 185951 - SOCIAL_MIXER_SHOWER_SING_IN_SHOWER: 'CommonInteractionId' = 141216 - SOCIAL_MIXER_SHOWER_SING_IN_SHOWER_AUTONOMOUS: 'CommonInteractionId' = 141928 - - # Bath - GENERIC_BATH: 'CommonInteractionId' = 13427 - GENERIC_BUBBLE_BATH: 'CommonInteractionId' = 35352 - GENERIC_RELAXING_BATH: 'CommonInteractionId' = 120467 - BATHTUB_TAKE_BATH_LOOP: 'CommonInteractionId' = 13085 - BATHTUB_TAKE_BATH_RELAXING_BATH_IDLE_LOOP: 'CommonInteractionId' = 120473 - BATHTUB_TAKE_BATH_RELAXING_BATH_PLAY: 'CommonInteractionId' = 120474 - BATHTUB_TAKE_BATH_RELAXING_BATH_FALL_ASLEEP: 'CommonInteractionId' = 120475 - BATHTUB_TAKE_BATH_RELAXING_BATH_IDLE_LOOP_MUD: 'CommonInteractionId' = 121800 - BATHTUB_TAKE_BATH_RELAXING_BATH_PLAY_MUD: 'CommonInteractionId' = 121804 - BATHTUB_TAKE_BATH_RELAXING_BATH_FALL_ASLEEP_MUD: 'CommonInteractionId' = 121802 - BATHTUB_TAKE_BUBBLE_BATH_MERMAID: 'CommonInteractionId' = 213939 - BATHTUB_TAKE_BATH_MERMAID: 'CommonInteractionId' = 213938 - BATHTUB_NAP_MERMAID: 'CommonInteractionId' = 215915 - BATHTUB_PLAY_MERMAID: 'CommonInteractionId' = 215876 - IDLE_HYGIENE_MERMAID: 'CommonInteractionId' = 215764 - - # S4CL - S4CL_DEBUG_SHOW_RUNNING_AND_QUEUED_INTERACTIONS: 'CommonInteractionId' = 5900237111545222349 - S4CL_DEBUG_SHOW_ACTIVE_BUFFS: 'CommonInteractionId' = 12481803320243318715 - S4CL_DEBUG_SHOW_TRAITS: 'CommonInteractionId' = 2108116777929577381 - S4CL_DEBUG_SHOW_RUNNING_SITUATIONS: 'CommonInteractionId' = 10355438442708473961 - S4CL_DEBUG_LOG_ALL_INTERACTIONS: 'CommonInteractionId' = 741312864308659038 - S4CL_DEBUG_LOG_ALL_INTERACTIONS_PHONE: 'CommonInteractionId' = 2534976194662328318 - S4CL_DEBUG_INDUCE_LABOR: 'CommonInteractionId' = 5145499017874001819 - S4CL_DEBUG_OBJECT_BREAK: 'CommonInteractionId' = 14420264135453255013 - S4CL_DEBUG_OBJECT_FIX: 'CommonInteractionId' = 11726582335911165817 - S4CL_DEBUG_OBJECT_MAKE_DIRTY: 'CommonInteractionId' = 1799349573117453079 - S4CL_DEBUG_OBJECT_MAKE_CLEAN: 'CommonInteractionId' = 5335871574274933500 - S4CL_DEBUG_LOG_ALL_GAME_TAGS: 'CommonInteractionId' = 13483495329565765760 - S4CL_DEBUG_CHANGE_OBJECT_STATES: 'CommonInteractionId' = 15058010603771996272 - - S4CL_SOCIAL_SUPER_SIM_TO_PET_HUMAN: 'CommonInteractionId' = 17045599576038631962 - S4CL_SOCIAL_SUPER_SIM_TO_PET_PET: 'CommonInteractionId' = 17048453908224900188 - - S4CL_SOCIAL_SUPER_SIM_TO_FOX_HUMAN: 'CommonInteractionId' = 0xCC4FDF3D68E78F5E - S4CL_SOCIAL_SUPER_SIM_TO_FOX_FOX: 'CommonInteractionId' = 0xCC2B053D68C8B3F0 - - SHOWER_TAKE_SHOWER_WALL_PRIVACY_CHILD_TEEN = 224187 - GENERIC_TOILET_SIT_STALL = 213986 - - # bar_OrderDrink - BAR_ORDER_DRINK = 13050 - # bar_PushOrderDrink_Autonomous - BAR_ORDER_DRINK_AUTONOMOUS = 13053 - # bar_Order_Food - BAR_ORDER_FOOD = 178213 - - # bar_WaitForDrink - BAR_WAIT_FOR_DRINK = 13065 - # bar_WaitFor_Food - BAR_WAIT_FOR_FOOD = 178214 - # bar_WaitForFood_CriticCareer - BAR_WAIT_FOR_FOOD_CRITIC = 137790 - - TOGGLE_PHONE_SILENCE = 40130 # toggle_phone_silence diff --git a/Scripts/s4ap/sims4communitylib/enums/long_term_sentiments_enum.py b/Scripts/s4ap/sims4communitylib/enums/long_term_sentiments_enum.py deleted file mode 100644 index 6200d94..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/long_term_sentiments_enum.py +++ /dev/null @@ -1,38 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonLongTermSentimentId(CommonInt): - """Identifiers for vanilla long term sentiments.""" - INVALID: 'CommonLongTermSentimentId' = 0 - ADORING_LIFESAVER: 'CommonLongTermSentimentId' = 246646 - ADORING_WEDDING_TRADITION_BEST_MAN: 'CommonLongTermSentimentId' = 276284 - ADORING_WEDDING_TRADITION_MAID_OF_HONOR: 'CommonLongTermSentimentId' = 276285 - BITTER_CHEATING: 'CommonLongTermSentimentId' = 246536 - BITTER_GRUDGE: 'CommonLongTermSentimentId' = 239982 - BITTER_MOUNTAIN_CLIMB_ACT2_CANCELLATION: 'CommonLongTermSentimentId' = 249892 - CLOSE_GENERIC: 'CommonLongTermSentimentId' = 239984 - CLOSE_I_KNOW_THEY_HAVE_GOT_MY_BACK: 'CommonLongTermSentimentId' = 273246 - CLOSE_LYCAN_BOND: 'CommonLongTermSentimentId' = 288810 - CLOSE_MOUNTAIN_CLIMB_ACT3_GOLD: 'CommonLongTermSentimentId' = 249898 - CLOSE_THEY_UNDERSTAND: 'CommonLongTermSentimentId' = 273068 - CLOSE_TWO_PEAS_IN_A_POD: 'CommonLongTermSentimentId' = 273067 - CRUSH_GENERIC: 'CommonLongTermSentimentId' = 272840 - ENAMORED_COTTAGE_WORLD_RUINS: 'CommonLongTermSentimentId' = 268491 - ENAMORED_FATED_TO_WED: 'CommonLongTermSentimentId' = 293551 - ENAMORED_FULL_MOON_FIRST_KISS: 'CommonLongTermSentimentId' = 290598 - ENAMORED_GENERIC: 'CommonLongTermSentimentId' = 246613 - ENAMORED_LIGHT_FESTIVAL_KISS: 'CommonLongTermSentimentId' = 253185 - ENAMORED_MOUNTAIN_CLIMB: 'CommonLongTermSentimentId' = 252690 - ENAMORED_MOUNTAIN_NEIGHBORHOOD: 'CommonLongTermSentimentId' = 252689 - GUILTY_FATE_DEFIED: 'CommonLongTermSentimentId' = 293552 - GUILTY_MOUNTAIN_CLIMB_ACT_2_CANCELLATION: 'CommonLongTermSentimentId' = 249896 - HURT_GENERIC: 'CommonLongTermSentimentId' = 246637 - NEEDS_DISTANCE_PROPOSAL: 'CommonLongTermSentimentId' = 278170 - REJECTED_PROPOSAL: 'CommonLongTermSentimentId' = 278176 diff --git a/Scripts/s4ap/sims4communitylib/enums/lot_traits_enum.py b/Scripts/s4ap/sims4communitylib/enums/lot_traits_enum.py deleted file mode 100644 index 52a7dd6..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/lot_traits_enum.py +++ /dev/null @@ -1,67 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonLotTraitId(CommonInt): - """Identifiers for vanilla lot traits. - - """ - INVALID: 'CommonLotTraitId' = 0 - CELEBRITY_HANG_OUT_HIGH_FAME: 'CommonLotTraitId' = 191710 - CELEBRITY_HANG_OUT_LOW_FAME: 'CommonLotTraitId' = 191708 - CELEBRITY_HOME_LOT_TRAIT: 'CommonLotTraitId' = 199661 - CHILDS_PLAY: 'CommonLotTraitId' = 144151 - CON_CURSED: 'CommonLotTraitId' = 137285 - CON_HAUNTED: 'CommonLotTraitId' = 137286 - CON_LIVELY_NEIGHBORS: 'CommonLotTraitId' = 137276 - CON_NEEDS_TLC: 'CommonLotTraitId' = 137283 - CON_PRICEY: 'CommonLotTraitId' = 137272 - CONVIVIAL: 'CommonLotTraitId' = 144156 - CREEPY_CRAWLIES: 'CommonLotTraitId' = 179482 - FILTHY: 'CommonLotTraitId' = 144148 - FRESH_AIR: 'CommonLotTraitId' = 144158 - GNOMES: 'CommonLotTraitId' = 147778 - GREAT_ACOUSTICS: 'CommonLotTraitId' = 144154 - GREAT_SOIL: 'CommonLotTraitId' = 144150 - GREMLINS: 'CommonLotTraitId' = 147847 - GRODY: 'CommonLotTraitId' = 144146 - HAUNTED: 'CommonLotTraitId' = 149429 - HIGH_SPEED_INTERNET: 'CommonLotTraitId' = 144153 - HOMEY: 'CommonLotTraitId' = 144152 - MEAN_VIBE: 'CommonLotTraitId' = 144144 - NATURAL_LIGHT: 'CommonLotTraitId' = 144157 - NO_TRESPASSING: 'CommonLotTraitId' = 144159 - ON_DARK_LEY_LINE: 'CommonLotTraitId' = 154647 - PEACE_AND_QUIET: 'CommonLotTraitId' = 179555 - PENNY_PIXIES: 'CommonLotTraitId' = 144147 - PET_WORLD_BREEDING_GROUND: 'CommonLotTraitId' = 170199 - PET_WORLD_CAT_FRIENDLY: 'CommonLotTraitId' = 170196 - PET_WORLD_CAT_HANGOUT: 'CommonLotTraitId' = 170190 - PET_WORLD_DOG_FRIENDLY: 'CommonLotTraitId' = 170197 - PET_WORLD_DOG_HANGOUT: 'CommonLotTraitId' = 170191 - PET_WORLD_TRAINING_GROUND: 'CommonLotTraitId' = 170198 - PRO_CHEAP: 'CommonLotTraitId' = 137273 - PRO_CHEFS_KITCHEN: 'CommonLotTraitId' = 137281 - PRO_GREAT_ATMOSPHERE: 'CommonLotTraitId' = 137287 - PRO_GREAT_VIEW: 'CommonLotTraitId' = 137278 - PRO_HISTORICAL: 'CommonLotTraitId' = 137280 - PRO_HOME_STUDIO: 'CommonLotTraitId' = 137284 - PRO_LOW_DEPOSIT: 'CommonLotTraitId' = 137282 - PRO_NEAR_GOOD_SCHOOLS: 'CommonLotTraitId' = 137223 - PRO_ON_LEY_LINE: 'CommonLotTraitId' = 137275 - PRO_QUIET: 'CommonLotTraitId' = 137277 - PRO_ROMANTIC_FIREPLACE: 'CommonLotTraitId' = 137279 - PRO_SERVICED_APARTMENT: 'CommonLotTraitId' = 137274 - QUAKE_ZONE: 'CommonLotTraitId' = 144143 - REGISTERED_VAMPIRE_LAIR: 'CommonLotTraitId' = 155246 - ROMANTIC_ATMOSPHERE: 'CommonLotTraitId' = 144149 - SCIENCE_LAIR: 'CommonLotTraitId' = 144155 - SUNNY_ASPECT: 'CommonLotTraitId' = 144145 - TEEN_HANG_OUT: 'CommonLotTraitId' = 162560 - VAMPIRE_NEXUS: 'CommonLotTraitId' = 154888 diff --git a/Scripts/s4ap/sims4communitylib/enums/moods_enum.py b/Scripts/s4ap/sims4communitylib/enums/moods_enum.py deleted file mode 100644 index ddb804a..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/moods_enum.py +++ /dev/null @@ -1,35 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonMoodId(CommonInt): - """Identifiers for vanilla sim moods. - - """ - INVALID: 'CommonMoodId' = 0 - CONFIDENT: 'CommonMoodId' = 14634 - SLEEPING: 'CommonMoodId' = 27149 - STRESSED: 'CommonMoodId' = 14645 - EMBARRASSED: 'CommonMoodId' = 14635 - FLIRTY: 'CommonMoodId' = 14638 - ENERGIZED: 'CommonMoodId' = 14636 - ANGRY: 'CommonMoodId' = 14632 - FOCUSED: 'CommonMoodId' = 14639 - HAPPY: 'CommonMoodId' = 14640 - UNCOMFORTABLE: 'CommonMoodId' = 14646 - BORED: 'CommonMoodId' = 14633 - DAZED: 'CommonMoodId' = 14644 - PLAYFUL: 'CommonMoodId' = 14642 - SAD: 'CommonMoodId' = 14643 - FINE: 'CommonMoodId' = 14637 - INSPIRED: 'CommonMoodId' = 14641 - POSSESSED: 'CommonMoodId' = 201531 - SCARED: 'CommonMoodId' = 251719 - SCARED_DOG: 'CommonMoodId' = 158181 - SCARED_CAT: 'CommonMoodId' = 158442 \ No newline at end of file diff --git a/Scripts/s4ap/sims4communitylib/enums/motives_enum.py b/Scripts/s4ap/sims4communitylib/enums/motives_enum.py deleted file mode 100644 index 1212500..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/motives_enum.py +++ /dev/null @@ -1,53 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonMotiveId(CommonInt): - """Identifiers for vanilla sim motives. - - """ - INVALID: 'CommonMotiveId' = 0 - BLADDER: 'CommonMotiveId' = 16652 # motive_Bladder - ANIMAL_FOX_BLADDER: 'CommonMotiveId' = 270467 # commodity_Motive_Fox_Bladder - PET_CAT_BLADDER: 'CommonMotiveId' = 151036 # commodity_Motive_PetCat_Bladder - PET_DOG_BLADDER: 'CommonMotiveId' = 151032 # commodity_Motive_PetDog_Bladder - PET_HORSE_BLADDER: 'CommonMotiveId' = 312267 # motive_Horse_Bladder - # This motive doesn't actually exist, it is used when mapping motives. The value is arbitrary. - BOWEL: 'CommonMotiveId' = INVALID - PET_CAT_BOWEL: 'CommonMotiveId' = 157949 # commodity_Motive_PetCat_Bowel - PET_DOG_BOWEL: 'CommonMotiveId' = 158698 # commodity_Motive_PetDog_Bowel - ENERGY: 'CommonMotiveId' = 16654 # motive_Energy - PET_CAT_ENERGY: 'CommonMotiveId' = 151037 # commodity_Motive_PetCat_Energy - PET_DOG_ENERGY: 'CommonMotiveId' = 151033 # commodity_Motive_PetDog_Energy - PET_HORSE_ENERGY: 'CommonMotiveId' = 312266 # motive_Horse_Energy - SERVO_CHARGE: 'CommonMotiveId' = 218484 # motive_Robots_Charge - FUN: 'CommonMotiveId' = 16655 # motive_Fun - PET_CAT_PLAY: 'CommonMotiveId' = 157718 # commodity_Motive_PetCat_Play - PET_DOG_PLAY: 'CommonMotiveId' = 158699 # commodity_Motive_PetDog_Play - PET_HORSE_FUN: 'CommonMotiveId' = 312268 # motive_Horse_Fun - HUNGER: 'CommonMotiveId' = 16656 # motive_Hunger - PET_CAT_HUNGER: 'CommonMotiveId' = 151035 # commodity_Motive_PetCat_Hunger - PET_DOG_HUNGER: 'CommonMotiveId' = 151031 # commodity_Motive_PetDog_Hunger - PET_HORSE_HUNGER: 'CommonMotiveId' = 312265 # motive_Horse_Hunger - HYGIENE: 'CommonMotiveId' = 16657 # motive_Hygiene - ANIMAL_FOX_HYGIENE: 'CommonMotiveId' = 270701 # motive_Hygiene_Fox - PET_CAT_HYGIENE: 'CommonMotiveId' = 157055 # commodity_Motive_PetCat_Hygiene - PET_DOG_HYGIENE: 'CommonMotiveId' = 157056 # commodity_Motive_PetDog_Hygiene - PET_HORSE_HYGIENE: 'CommonMotiveId' = 312269 # motive_Horse_Hygiene - SOCIAL: 'CommonMotiveId' = 16658 # motive_Social - PET_CAT_AFFECTION: 'CommonMotiveId' = 151038 # commodity_Motive_PetCat_Affection - PET_DOG_AFFECTION: 'CommonMotiveId' = 151034 # commodity_Motive_PetDog_Affection - PET_HORSE_SOCIAL: 'CommonMotiveId' = 312270 # motive_Horse_Social - VAMPIRE_POWER: 'CommonMotiveId' = 150238 # commodity_Motive_Visible_Vampire_Power - VAMPIRE_THIRST: 'CommonMotiveId' = 149541 # commodity_Motive_Visible_Vampire_Thirst - PLANT_SIM_WATER: 'CommonMotiveId' = 162675 # motive_PlantSim_Water - SERVO_DURABILITY: 'CommonMotiveId' = 218485 # motive_Robots_Durability - MERMAID_HYDRATION: 'CommonMotiveId' = HYGIENE - WITCH_MAGIC: 'CommonMotiveId' = 213024 # commodity_Motive_WitchOccult_Charge - WEREWOLF_FURY: 'CommonMotiveId' = 276223 # commodity_Motive_Werewolf_Fury diff --git a/Scripts/s4ap/sims4communitylib/enums/relationship_bit_collection_uids_enum.py b/Scripts/s4ap/sims4communitylib/enums/relationship_bit_collection_uids_enum.py deleted file mode 100644 index e512326..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/relationship_bit_collection_uids_enum.py +++ /dev/null @@ -1,38 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonRelationshipBitCollectionUid(CommonInt): - """The values within the dynamic RelationshipBitCollectionUid enum.""" - INVALID: 'CommonRelationshipBitCollectionUid' = 0 - ALL: 'CommonRelationshipBitCollectionUid' = 1 - CHILD: 'CommonRelationshipBitCollectionUid' = 72 - ENGAGED: 'CommonRelationshipBitCollectionUid' = 67 - FAMILY: 'CommonRelationshipBitCollectionUid' = 64 - FAMILY_ACQUIRED_NEGATIVE: 'CommonRelationshipBitCollectionUid' = 68 - FAMILY_ACQUIRED_NEUTRAL: 'CommonRelationshipBitCollectionUid' = 71 - FAMILY_ACQUIRED_POSITIVE: 'CommonRelationshipBitCollectionUid' = 69 - FRIEND: 'CommonRelationshipBitCollectionUid' = 65 - GIGS: 'CommonRelationshipBitCollectionUid' = 73 - PET: 'CommonRelationshipBitCollectionUid' = 70 - ROMANCE: 'CommonRelationshipBitCollectionUid' = 66 - SENTIMENT_ADORING: 'CommonRelationshipBitCollectionUid' = 82 - SENTIMENT_BITTER: 'CommonRelationshipBitCollectionUid' = 76 - SENTIMENT_CLOSE: 'CommonRelationshipBitCollectionUid' = 78 - SENTIMENT_ENAMORED: 'CommonRelationshipBitCollectionUid' = 79 - SENTIMENT_FURIOUS: 'CommonRelationshipBitCollectionUid' = 77 - SENTIMENT_GUILTY: 'CommonRelationshipBitCollectionUid' = 84 - SENTIMENT_HURT: 'CommonRelationshipBitCollectionUid' = 83 - SENTIMENT_LONG_TERM: 'CommonRelationshipBitCollectionUid' = 81 - SENTIMENT_MOTIVATING: 'CommonRelationshipBitCollectionUid' = 85 - SENTIMENT_NEGATIVE: 'CommonRelationshipBitCollectionUid' = 74 - SENTIMENT_POSITIVE: 'CommonRelationshipBitCollectionUid' = 75 - SENTIMENT_SHORT_TERM: 'CommonRelationshipBitCollectionUid' = 80 - - diff --git a/Scripts/s4ap/sims4communitylib/enums/relationship_bit_collections_enum.py b/Scripts/s4ap/sims4communitylib/enums/relationship_bit_collections_enum.py deleted file mode 100644 index 4ec86f5..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/relationship_bit_collections_enum.py +++ /dev/null @@ -1,34 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonRelationshipBitCollectionId(CommonInt): - """Identifiers for vanilla relationship bit collections.""" - INVALID: 'CommonRelationshipBitCollectionId' = 0 - CHILD: 'CommonRelationshipBitCollectionId' = 195565 - FAMILY: 'CommonRelationshipBitCollectionId' = 15806 - FAMILY_ACQUIRED_NEGATIVE: 'CommonRelationshipBitCollectionId' = 162462 - FAMILY_ACQUIRED_NEUTRAL: 'CommonRelationshipBitCollectionId' = 164649 - FAMILY_ACQUIRED_POSITIVE: 'CommonRelationshipBitCollectionId' = 164128 - FRIEND: 'CommonRelationshipBitCollectionId' = 15807 - FRIEND_AT_LEAST_FRIEND: 'CommonRelationshipBitCollectionId' = 273773 - ROMANTIC: 'CommonRelationshipBitCollectionId' = 240628 - ROMANTIC_HAVE_BEEN_EXES: 'CommonRelationshipBitCollectionId' = 274292 - SENTIMENT_ADORING: 'CommonRelationshipBitCollectionId' = 246492 - SENTIMENT_BITTER: 'CommonRelationshipBitCollectionId' = 240104 - SENTIMENT_CLOSE: 'CommonRelationshipBitCollectionId' = 240103 - SENTIMENT_ENAMORED: 'CommonRelationshipBitCollectionId' = 240107 - SENTIMENT_FURIOUS: 'CommonRelationshipBitCollectionId' = 240105 - SENTIMENT_GUILTY: 'CommonRelationshipBitCollectionId' = 246491 - SENTIMENT_HURT: 'CommonRelationshipBitCollectionId' = 246490 - SENTIMENT_LONG_TERM: 'CommonRelationshipBitCollectionId' = 240114 - SENTIMENT_MOTIVATING: 'CommonRelationshipBitCollectionId' = 252843 - SENTIMENT_NEGATIVE: 'CommonRelationshipBitCollectionId' = 240110 - SENTIMENT_POSITIVE: 'CommonRelationshipBitCollectionId' = 240109 - SENTIMENT_SHORT_TERM: 'CommonRelationshipBitCollectionId' = 240113 diff --git a/Scripts/s4ap/sims4communitylib/enums/relationship_bits_enum.py b/Scripts/s4ap/sims4communitylib/enums/relationship_bits_enum.py deleted file mode 100644 index be54a50..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/relationship_bits_enum.py +++ /dev/null @@ -1,514 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonRelationshipBitId(CommonInt): - """Identifiers for vanilla sim relationship bits. - - """ - INVALID: 'CommonRelationshipBitId' = 0 - ACTOR_CAREER_COWORKER_REL_BITS_COMMERCIAL_DIRECTOR: 'CommonRelationshipBitId' = 194371 - ACTOR_CAREER_COWORKER_REL_BITS_COSTAR1: 'CommonRelationshipBitId' = 196312 - ACTOR_CAREER_COWORKER_REL_BITS_COSTAR2: 'CommonRelationshipBitId' = 197701 - ACTOR_CAREER_COWORKER_REL_BITS_FILM_DIRECTOR: 'CommonRelationshipBitId' = 194696 - ACTOR_CAREER_COWORKER_REL_BITS_HIGH_BUDGET_TV_DIRECTOR: 'CommonRelationshipBitId' = 194373 - ACTOR_CAREER_COWORKER_REL_BITS_LOW_BUDGET_TV_DIRECTOR: 'CommonRelationshipBitId' = 194372 - APARTMENT_NEIGHBOR_HAS_KEY: 'CommonRelationshipBitId' = 135106 - ASKED_FOR_SIGNATURE: 'CommonRelationshipBitId' = 234697 - AUTHORITY_DEFAULT: 'CommonRelationshipBitId' = 161996 - BATUU_MISSIONS_FS7_SPY_SHARED_FAKE_INFO_NOT_SPY_1: 'CommonRelationshipBitId' = 248907 - BATUU_MISSIONS_FS7_SPY_SHARED_FAKE_INFO_NOT_SPY_2: 'CommonRelationshipBitId' = 248908 - BATUU_MISSIONS_FS7_SPY_SHARED_FAKE_INFO_NOT_SPY_3: 'CommonRelationshipBitId' = 248906 - BATUU_MISSIONS_FS7_SPY_SHARED_FAKE_INFO_SPY_1: 'CommonRelationshipBitId' = 248893 - BATUU_MISSIONS_FS7_SPY_SHARED_FAKE_INFO_SPY_2: 'CommonRelationshipBitId' = 248894 - BATUU_MISSIONS_FS7_SPY_SHARED_FAKE_INFO_SPY_3: 'CommonRelationshipBitId' = 248892 - BOUQUET_HAS_CAUGHT_BOUQUET: 'CommonRelationshipBitId' = 278814 - BOUQUET_HAS_THROWN_BOUQUET: 'CommonRelationshipBitId' = 278811 - CAT_OWNED: 'CommonRelationshipBitId' = 148063 - CAT_OWNER: 'CommonRelationshipBitId' = 148062 - CELEBRITY_ACQUAINTANCE: 'CommonRelationshipBitId' = 192631 - CELEBRITY_SHUNNED: 'CommonRelationshipBitId' = 194919 - CELEBRITY_SOCIAL_TIMEOUT_ASK: 'CommonRelationshipBitId' = 195082 - CELEBRITY_SOCIAL_TIMEOUT_COMPARE: 'CommonRelationshipBitId' = 195075 - CELEBRITY_SOCIAL_TIMEOUT_DIP_KISS: 'CommonRelationshipBitId' = 195080 - CELEBRITY_SOCIAL_TIMEOUT_FIRST_KISS: 'CommonRelationshipBitId' = 195096 - CELEBRITY_SOCIAL_TIMEOUT_IMPLY: 'CommonRelationshipBitId' = 195076 - CELEBRITY_SOCIAL_TIMEOUT_INTERESTS: 'CommonRelationshipBitId' = 195073 - CELEBRITY_SOCIAL_TIMEOUT_KISS_HAND: 'CommonRelationshipBitId' = 195078 - CELEBRITY_SOCIAL_TIMEOUT_NAUGHTY: 'CommonRelationshipBitId' = 195077 - CELEBRITY_SOCIAL_TIMEOUT_PERSONAL_STORY: 'CommonRelationshipBitId' = 195079 - CELEBRITY_SOCIAL_TIMEOUT_TENDER_KISS: 'CommonRelationshipBitId' = 195081 - CELEBRITY_SOCIAL_TIMEOUT_WOOHOO: 'CommonRelationshipBitId' = 195083 - CLONE: 'CommonRelationshipBitId' = 216270 - CLUBS_GAMES_COM_SECRET_CRUSH: 'CommonRelationshipBitId' = 122859 - COMMUNITY_CLOSENESS_BORROWED_SIMOLEONS: 'CommonRelationshipBitId' = 232917 - COMMUNITY_CLOSENESS_WRONG_NUMBER_DEBT: 'CommonRelationshipBitId' = 239192 - CT_NOT_PARENT_CARE_DEPENDENT: 'CommonRelationshipBitId' = 162483 - CT_NOT_PARENT_CARE_GIVER: 'CommonRelationshipBitId' = 162482 - DARED: 'CommonRelationshipBitId' = 121352 - DATE_SITUATION_BIT: 'CommonRelationshipBitId' = 37762 - DATE_SITUATION_BIT_BLIND_DATE: 'CommonRelationshipBitId' = 201485 - DEBUG_SITUATION_BIT: 'CommonRelationshipBitId' = 37769 - DETECTIVE_CAREER_ARRESTED: 'CommonRelationshipBitId' = 113055 - DETECTIVE_CAREER_CRIMINAL: 'CommonRelationshipBitId' = 113060 - DETECTIVE_FOUND_GUILTY: 'CommonRelationshipBitId' = 116146 - DOG_OWNED: 'CommonRelationshipBitId' = 148061 - DOG_OWNER: 'CommonRelationshipBitId' = 148060 - E_SPORTS_TEAMMATES: 'CommonRelationshipBitId' = 226586 - FAMILIAR: 'CommonRelationshipBitId' = 215119 - FAMILY_ACQUIRED_CHILD_HIGH_REL_HIGH_AUTH: 'CommonRelationshipBitId' = 161969 - FAMILY_ACQUIRED_CHILD_HIGH_REL_LOW_AUTH: 'CommonRelationshipBitId' = 161971 - FAMILY_ACQUIRED_CHILD_MAX_REL_HIGH_AUTH: 'CommonRelationshipBitId' = 161973 - FAMILY_ACQUIRED_CHILD_MAX_REL_LOW_AUTH: 'CommonRelationshipBitId' = 161975 - FAMILY_ACQUIRED_CHILD_NEUTRAL_REL_HIGH_AUTH: 'CommonRelationshipBitId' = 161977 - FAMILY_ACQUIRED_CHILD_NEUTRAL_REL_LOW_AUTH: 'CommonRelationshipBitId' = 161979 - FAMILY_ACQUIRED_CHILD_POOR_REL_HIGH_AUTH: 'CommonRelationshipBitId' = 161981 - FAMILY_ACQUIRED_CHILD_POOR_REL_LOW_AUTH: 'CommonRelationshipBitId' = 161983 - FAMILY_ACQUIRED_GRANDCHILD_HIGH_REL: 'CommonRelationshipBitId' = 161910 - FAMILY_ACQUIRED_GRANDCHILD_NEUTRAL_REL: 'CommonRelationshipBitId' = 161922 - FAMILY_ACQUIRED_GRANDCHILD_POOR_REL: 'CommonRelationshipBitId' = 161924 - FAMILY_ACQUIRED_GRANDPARENT_HIGH_REL: 'CommonRelationshipBitId' = 161909 - FAMILY_ACQUIRED_GRANDPARENT_NEUTRAL_REL: 'CommonRelationshipBitId' = 161911 - FAMILY_ACQUIRED_GRANDPARENT_POOR_REL: 'CommonRelationshipBitId' = 161923 - FAMILY_ACQUIRED_PARENT_HIGH_REL_HIGH_AUTH: 'CommonRelationshipBitId' = 161968 - FAMILY_ACQUIRED_PARENT_HIGH_REL_LOW_AUTH: 'CommonRelationshipBitId' = 161970 - FAMILY_ACQUIRED_PARENT_MAX_REL_HIGH_AUTH: 'CommonRelationshipBitId' = 161972 - FAMILY_ACQUIRED_PARENT_MAX_REL_LOW_AUTH: 'CommonRelationshipBitId' = 161974 - FAMILY_ACQUIRED_PARENT_NEUTRAL_REL_HIGH_AUTH: 'CommonRelationshipBitId' = 161976 - FAMILY_ACQUIRED_PARENT_NEUTRAL_REL_LOW_AUTH: 'CommonRelationshipBitId' = 161978 - FAMILY_ACQUIRED_PARENT_POOR_REL_HIGH_AUTH: 'CommonRelationshipBitId' = 161980 - FAMILY_ACQUIRED_PARENT_POOR_REL_LOW_AUTH: 'CommonRelationshipBitId' = 161982 - FAMILY_ACQUIRED_SIBLING_HIGH_REL_HIGH_RIVAL: 'CommonRelationshipBitId' = 161931 - FAMILY_ACQUIRED_SIBLING_HIGH_REL_LOW_RIVAL: 'CommonRelationshipBitId' = 161930 - FAMILY_ACQUIRED_SIBLING_NEUTRAL_REL_HIGH_RIVAL: 'CommonRelationshipBitId' = 161932 - FAMILY_ACQUIRED_SIBLING_NEUTRAL_REL_LOW_RIVAL: 'CommonRelationshipBitId' = 161933 - FAMILY_ACQUIRED_SIBLING_POOR_REL_HIGH_RIVAL: 'CommonRelationshipBitId' = 161934 - FAMILY_ACQUIRED_SIBLING_POOR_REL_LOW_RIVAL: 'CommonRelationshipBitId' = 161935 - FAMILY_AUNT_UNCLE: 'CommonRelationshipBitId' = 8829 - FAMILY_BROTHER_SISTER: 'CommonRelationshipBitId' = 8802 - FAMILY_COUSIN: 'CommonRelationshipBitId' = 8826 - FAMILY_GRANDCHILD: 'CommonRelationshipBitId' = 8807 - FAMILY_GRANDPARENT: 'CommonRelationshipBitId' = 8808 - FAMILY_HUSBAND_WIFE: 'CommonRelationshipBitId' = 24490 - FAMILY_NIECE_NEPHEW: 'CommonRelationshipBitId' = 9989 - FAMILY_PARENT: 'CommonRelationshipBitId' = 8809 - FAMILY_SON_DAUGHTER: 'CommonRelationshipBitId' = 8805 - FAMILY_STEP_SIBLING: 'CommonRelationshipBitId' = 8824 - FAN_STAN_STAN: 'CommonRelationshipBitId' = 194374 - FAN_STAN_STAN_COOLDOWN: 'CommonRelationshipBitId' = 194411 - FEAR_BEING_CHEATED_ON_TRACKER: 'CommonRelationshipBitId' = 278255 - FEAR_BEING_JUDGED_MEAN_TRACKER: 'CommonRelationshipBitId' = 288656 - FEUD_NEUTRAL: 'CommonRelationshipBitId' = 193903 - FEUD_TARGET: 'CommonRelationshipBitId' = 193944 - FOX_DONT_STEAL: 'CommonRelationshipBitId' = 260898 - FRIENDSHIP_ACQUAINTANCES: 'CommonRelationshipBitId' = 15792 - FRIENDSHIP_BFF: 'CommonRelationshipBitId' = 15794 - FRIENDSHIP_BFF_BROMANTIC_PARTNER: 'CommonRelationshipBitId' = 31211 - FRIENDSHIP_BFF_EVIL: 'CommonRelationshipBitId' = 15795 - FRIENDSHIP_CONFIDANT: 'CommonRelationshipBitId' = 248676 - FRIENDSHIP_DESPISED: 'CommonRelationshipBitId' = 15796 - FRIENDSHIP_DISLIKED: 'CommonRelationshipBitId' = 15802 - FRIENDSHIP_FRIEND: 'CommonRelationshipBitId' = 15797 - FRIENDSHIP_FRIEND_EVIL: 'CommonRelationshipBitId' = 15798 - FRIENDSHIP_GOOD_FRIENDS: 'CommonRelationshipBitId' = 15799 - FRIENDSHIP_GOOD_FRIENDS_EVIL: 'CommonRelationshipBitId' = 15800 - FRIENDSHIP_NEMESIS: 'CommonRelationshipBitId' = 15801 - FRIENDSHIP_NEUTRAL_BIT: 'CommonRelationshipBitId' = 15809 - HAS_BEEN_FRIENDS: 'CommonRelationshipBitId' = 129295 - HAS_MET: 'CommonRelationshipBitId' = 15803 - HAVE_BEEN_EXES: 'CommonRelationshipBitId' = 274289 - HAVE_BEEN_ROMANTIC: 'CommonRelationshipBitId' = 98756 - HELP_BATUUANS_CHEER_UP: 'CommonRelationshipBitId' = 244327 - HELP_BATUUANS_CHEER_UP_FINISHED: 'CommonRelationshipBitId' = 244328 - HELP_BATUUANS_GIVE_CREDITS: 'CommonRelationshipBitId' = 244005 - HELP_BATUUANS_GIVE_CREDITS_FINISHED: 'CommonRelationshipBitId' = 244006 - HELP_BATUUANS_GIVE_DROID_PARTS: 'CommonRelationshipBitId' = 244000 - HELP_BATUUANS_GIVE_DROID_PARTS_FINISHED: 'CommonRelationshipBitId' = 244001 - HELP_BATUUANS_GIVE_FOOD: 'CommonRelationshipBitId' = 243995 - HELP_BATUUANS_GIVE_FOOD_FINISHED: 'CommonRelationshipBitId' = 243996 - HELP_BATUUANS_PLAY_SABACC: 'CommonRelationshipBitId' = 243893 - HELP_BATUUANS_PLAY_SABACC_FINISHED: 'CommonRelationshipBitId' = 243920 - HIGH_SCHOOL_TEAM_CHEER_TEAM_TEAMMATES: 'CommonRelationshipBitId' = 276585 - HIGH_SCHOOL_TEAM_CHESS_TEAM_TEAMMATES: 'CommonRelationshipBitId' = 276584 - HIGH_SCHOOL_TEAM_COMPUTER_TEAM_TEAMMATES: 'CommonRelationshipBitId' = 276586 - HIGH_SCHOOL_TEAM_FOOTBALL_TEAM_TEAMMATES: 'CommonRelationshipBitId' = 276587 - HIGH_SCHOOL_TEAM_RIVAL: 'CommonRelationshipBitId' = 277655 - INTERIOR_DECORATOR_CLIENT: 'CommonRelationshipBitId' = 259991 - INTERIOR_DECORATOR_CLIENT_COOLDOWN_FIRED: 'CommonRelationshipBitId' = 264540 - INTERIOR_DECORATOR_CLIENT_COOLDOWN_NORMAL: 'CommonRelationshipBitId' = 264537 - INTERIOR_DECORATOR_CLIENT_FOLLOW_UP_CLIENT_CALL_NPC_INVITE_POST_SITUATION: 'CommonRelationshipBitId' = 260877 - INTERIOR_DECORATOR_CLIENT_FOLLOW_UP_OFFERED_GIG_REFERRED: 'CommonRelationshipBitId' = 260531 - INTERIOR_DECORATOR_CLIENT_FOLLOW_UP_OFFERED_GIG_RETURNING_NEGATIVE: 'CommonRelationshipBitId' = 260532 - INTERIOR_DECORATOR_CLIENT_FOLLOW_UP_OFFERED_GIG_RETURNING_POSITIVE: 'CommonRelationshipBitId' = 260533 - INTERIOR_DECORATOR_CLIENT_FOLLOW_UP_RETURNING_GIG_COOLDOWN: 'CommonRelationshipBitId' = 261233 - INTERROGATION_FINISHED: 'CommonRelationshipBitId' = 109991 - INVESTIGATION_SYSTEM_DISCUSSED_SPORES: 'CommonRelationshipBitId' = 203603 - INVESTIGATION_SYSTEM_RECRUITED: 'CommonRelationshipBitId' = 203604 - INVESTIGATION_SYSTEM_REL_BITS_FAILED_TO_RECRUIT: 'CommonRelationshipBitId' = 205562 - INVESTIGATION_SYSTEM_REQUESTED_KEY_CARD: 'CommonRelationshipBitId' = 204495 - INVESTIGATION_SYSTEM_VACCINE_TEST_SUBJECT: 'CommonRelationshipBitId' = 206182 - IS_CLONE: 'CommonRelationshipBitId' = 109549 - LANDLORD: 'CommonRelationshipBitId' = 135305 - LEGAL_CLIENT: 'CommonRelationshipBitId' = 228184 - LISTENING_DEVICE_BUGGED_BUGGEE: 'CommonRelationshipBitId' = 202324 - LISTENING_DEVICE_BUGGED_BUGGER: 'CommonRelationshipBitId' = 201980 - LIVING_ROOMMATE: 'CommonRelationshipBitId' = 8812 - LOAN_LARGE: 'CommonRelationshipBitId' = 28912 - LOAN_SMALL: 'CommonRelationshipBitId' = 28911 - MERMAID_MERFOLK_WOKE: 'CommonRelationshipBitId' = 208278 - MET_DISGUISED_ALIEN: 'CommonRelationshipBitId' = 185854 - MISCHIEF_NEUTRAL_BIT: 'CommonRelationshipBitId' = 26922 - MISCHIEF_PARTNERS_IN_CRIME: 'CommonRelationshipBitId' = 26923 - NEIGHBOR: 'CommonRelationshipBitId' = 75294 - NEIGHBOR_HAS_KEY: 'CommonRelationshipBitId' = 195367 - NO_LONGER_FRIENDS: 'CommonRelationshipBitId' = 273547 - OBJECT_FRIENDSHIP_ACQUAINTANCES: 'CommonRelationshipBitId' = 204519 - OBJECT_FRIENDSHIP_DESPISED: 'CommonRelationshipBitId' = 204523 - OBJECT_FRIENDSHIP_DISLIKED: 'CommonRelationshipBitId' = 204524 - OBJECT_FRIENDSHIP_FRIEND: 'CommonRelationshipBitId' = 204525 - OBJECT_FRIENDSHIP_GOOD_FRIENDS: 'CommonRelationshipBitId' = 204527 - OBJECT_FRIENDSHIP_NEMESIS: 'CommonRelationshipBitId' = 204529 - OPENABLE_WINDOW_EVENT_INVITE_TRACKER: 'CommonRelationshipBitId' = 283043 - PERSONALITY_ANALYZED: 'CommonRelationshipBitId' = 107716 - PET_TO_PET_FRIENDLY: 'CommonRelationshipBitId' = 159636 - PET_TO_PET_HOSTILE: 'CommonRelationshipBitId' = 159635 - PET_TO_PET_NEUTRAL: 'CommonRelationshipBitId' = 159634 - PLAY_DATE_SITUATION_BIT: 'CommonRelationshipBitId' = 117189 - POSSESSED_ALLOW_WAKE_UP: 'CommonRelationshipBitId' = 204754 - PREGNANCY_BIRTH_PARENT: 'CommonRelationshipBitId' = 100705 - PROFESSOR_NPC: 'CommonRelationshipBitId' = 227706 - PROM_HIGH_SCHOOL_PROM_DATE: 'CommonRelationshipBitId' = 295931 - PROM_HIGH_SCHOOL_PROM_DATE_FRIENDS: 'CommonRelationshipBitId' = 295932 - PROM_HIGH_SCHOOL_PROM_DITCHING_PROM: 'CommonRelationshipBitId' = 295930 - RBC_CHILD: 'CommonRelationshipBitId' = 195565 - RBC_FAMILY: 'CommonRelationshipBitId' = 15806 - RBC_FAMILY_ACQUIRED_NEGATIVE: 'CommonRelationshipBitId' = 162462 - RBC_FAMILY_ACQUIRED_NEUTRAL: 'CommonRelationshipBitId' = 164649 - RBC_FAMILY_ACQUIRED_POSITIVE: 'CommonRelationshipBitId' = 164128 - RBC_FRIEND: 'CommonRelationshipBitId' = 15807 - RELATIONSHIP_BIT_COLLECTION_FRIEND_AT_LEAST_FRIEND: 'CommonRelationshipBitId' = 273773 - RELATIONSHIP_BIT_COLLECTION_ROMANTIC: 'CommonRelationshipBitId' = 240628 - RELATIONSHIP_BIT_COLLECTION_ROMANTIC_HAVE_BEEN_EXES: 'CommonRelationshipBitId' = 274292 - RELATIONSHIP_BIT_COLLECTION_SENTIMENT_ADORING: 'CommonRelationshipBitId' = 246492 - RELATIONSHIP_BIT_COLLECTION_SENTIMENT_BITTER: 'CommonRelationshipBitId' = 240104 - RELATIONSHIP_BIT_COLLECTION_SENTIMENT_CLOSE: 'CommonRelationshipBitId' = 240103 - RELATIONSHIP_BIT_COLLECTION_SENTIMENT_ENAMORED: 'CommonRelationshipBitId' = 240107 - RELATIONSHIP_BIT_COLLECTION_SENTIMENT_FURIOUS: 'CommonRelationshipBitId' = 240105 - RELATIONSHIP_BIT_COLLECTION_SENTIMENT_GUILTY: 'CommonRelationshipBitId' = 246491 - RELATIONSHIP_BIT_COLLECTION_SENTIMENT_HURT: 'CommonRelationshipBitId' = 246490 - RELATIONSHIP_BIT_COLLECTION_SENTIMENT_LONG_TERM: 'CommonRelationshipBitId' = 240114 - RELATIONSHIP_BIT_COLLECTION_SENTIMENT_MOTIVATING: 'CommonRelationshipBitId' = 252843 - RELATIONSHIP_BIT_COLLECTION_SENTIMENT_NEGATIVE: 'CommonRelationshipBitId' = 240110 - RELATIONSHIP_BIT_COLLECTION_SENTIMENT_POSITIVE: 'CommonRelationshipBitId' = 240109 - RELATIONSHIP_BIT_COLLECTION_SENTIMENT_SHORT_TERM: 'CommonRelationshipBitId' = 240113 - RELATIONSHIP_BIT_CO_WORKERS: 'CommonRelationshipBitId' = 107373 - RELATIONSHIP_BIT_KNOWS_IS_ALIEN: 'CommonRelationshipBitId' = 103299 - RELATIONSHIP_BIT_KNOWS_IS_ALIEN_BOTH_SIMS_ARE_ALIENS: 'CommonRelationshipBitId' = 116465 - RETAIL_EMPLOYEES_WONT_TALK_TO_LOT_OWNERS: 'CommonRelationshipBitId' = 117017 - RIVALRY_DEFAULT: 'CommonRelationshipBitId' = 161997 - ROBOT_ACTIVATION_MARKER: 'CommonRelationshipBitId' = 230574 - ROBOT_CREATION: 'CommonRelationshipBitId' = 218722 - ROBOT_CREATOR: 'CommonRelationshipBitId' = 218723 - ROMANCE_FAITHFUL: 'CommonRelationshipBitId' = 187709 - ROMANCE_NEUTRAL_BIT: 'CommonRelationshipBitId' = 15810 - ROMANTIC_BROKEN_UP: 'CommonRelationshipBitId' = 15811 - ROMANTIC_BROKEN_UP_ENGAGED: 'CommonRelationshipBitId' = 15812 - ROMANTIC_CHEATED_WITH: 'CommonRelationshipBitId' = 37265 - ROMANTIC_COMBO_ACQUAINTANCES: 'CommonRelationshipBitId' = 77585 - ROMANTIC_COMBO_AWKWARD_FRIENDS: 'CommonRelationshipBitId' = 15826 - ROMANTIC_COMBO_AWKWARD_LOVERS: 'CommonRelationshipBitId' = 15827 - ROMANTIC_COMBO_BAD_MATCH: 'CommonRelationshipBitId' = 15828 - ROMANTIC_COMBO_BAD_ROMANCE: 'CommonRelationshipBitId' = 15843 - ROMANTIC_COMBO_DESPISED: 'CommonRelationshipBitId' = 77648 - ROMANTIC_COMBO_DISLIKED: 'CommonRelationshipBitId' = 77647 - ROMANTIC_COMBO_ENEMIES_WITH_BENEFITS: 'CommonRelationshipBitId' = 15830 - ROMANTIC_COMBO_FRENEMIES: 'CommonRelationshipBitId' = 15831 - ROMANTIC_COMBO_HOT_AND_COLD: 'CommonRelationshipBitId' = 15832 - ROMANTIC_COMBO_ITS_AWKWARD: 'CommonRelationshipBitId' = 15833 - ROMANTIC_COMBO_ITS_COMPLICATED: 'CommonRelationshipBitId' = 15834 - ROMANTIC_COMBO_ITS_VERY_AWKWARD: 'CommonRelationshipBitId' = 15835 - ROMANTIC_COMBO_ITS_VERY_COMPLICATED: 'CommonRelationshipBitId' = 15836 - ROMANTIC_COMBO_JUST_FRIENDS: 'CommonRelationshipBitId' = 77633 - ROMANTIC_COMBO_JUST_GOOD_FRIENDS: 'CommonRelationshipBitId' = 77634 - ROMANTIC_COMBO_LOVEBIRDS: 'CommonRelationshipBitId' = 15829 - ROMANTIC_COMBO_LOVERS: 'CommonRelationshipBitId' = 15837 - ROMANTIC_COMBO_ROMANTIC_INTEREST: 'CommonRelationshipBitId' = 15838 - ROMANTIC_COMBO_SOUL_MATES: 'CommonRelationshipBitId' = 15839 - ROMANTIC_COMBO_SWEETHEARTS: 'CommonRelationshipBitId' = 15840 - ROMANTIC_COMBO_TERRIBLE_MATCH: 'CommonRelationshipBitId' = 15841 - ROMANTIC_COMBO_TOTAL_OPPOSITES: 'CommonRelationshipBitId' = 15842 - ROMANTIC_DEAD_SPOUSE: 'CommonRelationshipBitId' = 104161 - ROMANTIC_DESPISED_EX: 'CommonRelationshipBitId' = 15814 - ROMANTIC_DIVORCED: 'CommonRelationshipBitId' = 15815 - ROMANTIC_ENGAGED: 'CommonRelationshipBitId' = 15816 - ROMANTIC_EXCHANGED_NUMBERS: 'CommonRelationshipBitId' = 127076 - ROMANTIC_FATED_MATES: 'CommonRelationshipBitId' = 293538 - ROMANTIC_FIRST_KISS: 'CommonRelationshipBitId' = 10150 - ROMANTIC_FRUSTRATED_EX: 'CommonRelationshipBitId' = 15817 - ROMANTIC_GETTING_MARRIED: 'CommonRelationshipBitId' = 15818 - ROMANTIC_GOT_COLD_FEET: 'CommonRelationshipBitId' = 15819 - ROMANTIC_HAS_BEEN_UNFAITHFUL: 'CommonRelationshipBitId' = 36957 - ROMANTIC_HAVE_DONE_WOOHOO: 'CommonRelationshipBitId' = 34619 - ROMANTIC_HAVE_DONE_WOOHOO_RECENTLY: 'CommonRelationshipBitId' = 97154 - ROMANTIC_LEAVE_AT_THE_ALTAR: 'CommonRelationshipBitId' = 39356 - ROMANTIC_LEFT_AT_THE_ALTAR: 'CommonRelationshipBitId' = 15821 - ROMANTIC_MARRIED: 'CommonRelationshipBitId' = 15822 - ROMANTIC_MARRIED_NEWLY_WED: 'CommonRelationshipBitId' = 274846 - ROMANTIC_PROMISED: 'CommonRelationshipBitId' = 99429 - ROMANTIC_RENEWING_VOWS: 'CommonRelationshipBitId' = 99616 - ROMANTIC_SIGNIFICANT_OTHER: 'CommonRelationshipBitId' = 15825 - ROMANTIC_WIDOW: 'CommonRelationshipBitId' = 102081 - ROMANTIC_WIDOWER: 'CommonRelationshipBitId' = 102911 - ROOMMATE_NPC: 'CommonRelationshipBitId' = 209563 - SECRET_AGENT_DEFEATED_SUPER_VILLAIN: 'CommonRelationshipBitId' = 99522 - SECRET_AGENT_EXPOSED_AS_SUPER_VILLAIN: 'CommonRelationshipBitId' = 38788 - SECRET_AGENT_INVESTIGATED: 'CommonRelationshipBitId' = 37066 - SECRET_AGENT_KNOWN_SUPER_VILLAIN: 'CommonRelationshipBitId' = 38790 - SENTIMENT_LONG_TERM_ADORING_LIFESAVER: 'CommonRelationshipBitId' = 246646 - SENTIMENT_LONG_TERM_ADORING_WEDDING_TRADITION_BEST_MAN: 'CommonRelationshipBitId' = 276284 - SENTIMENT_LONG_TERM_ADORING_WEDDING_TRADITION_MAID_OF_HONOR: 'CommonRelationshipBitId' = 276285 - SENTIMENT_LONG_TERM_BITTER_CHEATING: 'CommonRelationshipBitId' = 246536 - SENTIMENT_LONG_TERM_BITTER_GRUDGE: 'CommonRelationshipBitId' = 239982 - SENTIMENT_LONG_TERM_BITTER_MOUNTAIN_CLIMB_ACT2_CANCELLATION: 'CommonRelationshipBitId' = 249892 - SENTIMENT_LONG_TERM_CLOSE_GENERIC: 'CommonRelationshipBitId' = 239984 - SENTIMENT_LONG_TERM_CLOSE_I_KNOW_THEY_HAVE_GOT_MY_BACK: 'CommonRelationshipBitId' = 273246 - SENTIMENT_LONG_TERM_CLOSE_LYCAN_BOND: 'CommonRelationshipBitId' = 288810 - SENTIMENT_LONG_TERM_CLOSE_MOUNTAIN_CLIMB_ACT3_GOLD: 'CommonRelationshipBitId' = 249898 - SENTIMENT_LONG_TERM_CLOSE_THEY_UNDERSTAND: 'CommonRelationshipBitId' = 273068 - SENTIMENT_LONG_TERM_CLOSE_TWO_PEAS_IN_A_POD: 'CommonRelationshipBitId' = 273067 - SENTIMENT_LONG_TERM_CRUSH_GENERIC: 'CommonRelationshipBitId' = 272840 - SENTIMENT_LONG_TERM_ENAMORED_COTTAGE_WORLD_RUINS: 'CommonRelationshipBitId' = 268491 - SENTIMENT_LONG_TERM_ENAMORED_FATED_TO_WED: 'CommonRelationshipBitId' = 293551 - SENTIMENT_LONG_TERM_ENAMORED_FULL_MOON_FIRST_KISS: 'CommonRelationshipBitId' = 290598 - SENTIMENT_LONG_TERM_ENAMORED_GENERIC: 'CommonRelationshipBitId' = 246613 - SENTIMENT_LONG_TERM_ENAMORED_LIGHT_FESTIVAL_KISS: 'CommonRelationshipBitId' = 253185 - SENTIMENT_LONG_TERM_ENAMORED_MOUNTAIN_CLIMB: 'CommonRelationshipBitId' = 252690 - SENTIMENT_LONG_TERM_ENAMORED_MOUNTAIN_NEIGHBORHOOD: 'CommonRelationshipBitId' = 252689 - SENTIMENT_LONG_TERM_GUILTY_FATE_DEFIED: 'CommonRelationshipBitId' = 293552 - SENTIMENT_LONG_TERM_GUILTY_MOUNTAIN_CLIMB_ACT_2_CANCELLATION: 'CommonRelationshipBitId' = 249896 - SENTIMENT_LONG_TERM_HURT_GENERIC: 'CommonRelationshipBitId' = 246637 - SENTIMENT_LONG_TERM_NEEDS_DISTANCE_PROPOSAL: 'CommonRelationshipBitId' = 278170 - SENTIMENT_LONG_TERM_REJECTED_PROPOSAL: 'CommonRelationshipBitId' = 278176 - SENTIMENT_SHORT_TERM_ADORING_CONSOLE_DEATH: 'CommonRelationshipBitId' = 273923 - SENTIMENT_SHORT_TERM_ADORING_DECORATOR_GOOD_BUILD: 'CommonRelationshipBitId' = 268267 - SENTIMENT_SHORT_TERM_ADORING_GENERIC: 'CommonRelationshipBitId' = 246530 - SENTIMENT_SHORT_TERM_ADORING_IMPRESSED: 'CommonRelationshipBitId' = 246535 - SENTIMENT_SHORT_TERM_ADORING_WEDDING_TRADITION_GAVE_GOOD_SPEECH: 'CommonRelationshipBitId' = 276548 - SENTIMENT_SHORT_TERM_BITTER_BREAKUP: 'CommonRelationshipBitId' = 246538 - SENTIMENT_SHORT_TERM_BITTER_CRUMPLE_BOTTOMED: 'CommonRelationshipBitId' = 264465 - SENTIMENT_SHORT_TERM_BITTER_DIVORCE: 'CommonRelationshipBitId' = 246539 - SENTIMENT_SHORT_TERM_BITTER_EXCURSION_CANCEL_ACT1: 'CommonRelationshipBitId' = 249751 - SENTIMENT_SHORT_TERM_BITTER_FIGHT: 'CommonRelationshipBitId' = 246597 - SENTIMENT_SHORT_TERM_BITTER_GRUDGE_AGAINST_PACK_A: 'CommonRelationshipBitId' = 290940 - SENTIMENT_SHORT_TERM_BITTER_GRUDGE_AGAINST_PACK_B: 'CommonRelationshipBitId' = 290941 - SENTIMENT_SHORT_TERM_BITTER_HIGH_SCHOOL_PROM_NO_PROM_INVITE: 'CommonRelationshipBitId' = 282640 - SENTIMENT_SHORT_TERM_BITTER_HIKING_TRAIL_GROUP_HIKE_TIN_REWARD: 'CommonRelationshipBitId' = 250363 - SENTIMENT_SHORT_TERM_BITTER_LIFESTYLE_WORKAHOLIC: 'CommonRelationshipBitId' = 252693 - SENTIMENT_SHORT_TERM_BITTER_LIVESTOCK_SOLD: 'CommonRelationshipBitId' = 263707 - SENTIMENT_SHORT_TERM_BITTER_OPENABLE_WINDOW_FAIL_EVENT: 'CommonRelationshipBitId' = 283047 - SENTIMENT_SHORT_TERM_BITTER_VILLAGE_FAIR_BRIBE_FAIL: 'CommonRelationshipBitId' = 268415 - SENTIMENT_SHORT_TERM_BITTER_WEDDING_TRADITION_NOT_INVITED_TO_WEDDING: 'CommonRelationshipBitId' = 276835 - SENTIMENT_SHORT_TERM_BITTER_WEDDING_TRADITION_NOT_SELECTED_BEST_MAN: 'CommonRelationshipBitId' = 276551 - SENTIMENT_SHORT_TERM_BITTER_WEDDING_TRADITION_NOT_SELECTED_MAID_OF_HONOR: 'CommonRelationshipBitId' = 276553 - SENTIMENT_SHORT_TERM_BITTER_YOGA_CLASS: 'CommonRelationshipBitId' = 271953 - SENTIMENT_SHORT_TERM_CLOSE_ADOPTION: 'CommonRelationshipBitId' = 246610 - SENTIMENT_SHORT_TERM_CLOSE_CANNING_RECEIVE_GIFT: 'CommonRelationshipBitId' = 260816 - SENTIMENT_SHORT_TERM_CLOSE_COTTAGE_WORLD_NPC_GOSSIP: 'CommonRelationshipBitId' = 264954 - SENTIMENT_SHORT_TERM_CLOSE_GENERIC: 'CommonRelationshipBitId' = 246604 - SENTIMENT_SHORT_TERM_CLOSE_GOOD_FIRST_IMPRESSION: 'CommonRelationshipBitId' = 273242 - SENTIMENT_SHORT_TERM_CLOSE_GROUP_COOKING_COOKING_TOGETHER: 'CommonRelationshipBitId' = 262317 - SENTIMENT_SHORT_TERM_CLOSE_HIGH_SCHOOL_PROM_SKIPPING_PROM_TOGETHER: 'CommonRelationshipBitId' = 282637 - SENTIMENT_SHORT_TERM_CLOSE_HIKING_TRAIL_GROUP_HIKE_GOLD_REWARD: 'CommonRelationshipBitId' = 250366 - SENTIMENT_SHORT_TERM_CLOSE_HOTPOT: 'CommonRelationshipBitId' = 252685 - SENTIMENT_SHORT_TERM_CLOSE_LIFESTYLE_CLOSE_KNIT: 'CommonRelationshipBitId' = 252687 - SENTIMENT_SHORT_TERM_CLOSE_LIGHT_FESTIVAL_WISH: 'CommonRelationshipBitId' = 253253 - SENTIMENT_SHORT_TERM_CLOSE_NEAR_DEATH: 'CommonRelationshipBitId' = 246647 - SENTIMENT_SHORT_TERM_CLOSE_ONSEN: 'CommonRelationshipBitId' = 252680 - SENTIMENT_SHORT_TERM_CLOSE_OPENABLE_WINDOW_SUCCESS_EVENT: 'CommonRelationshipBitId' = 283050 - SENTIMENT_SHORT_TERM_CLOSE_PARTY: 'CommonRelationshipBitId' = 246606 - SENTIMENT_SHORT_TERM_CLOSE_PICNIC_BASKET_PICNIC_BONDING: 'CommonRelationshipBitId' = 260815 - SENTIMENT_SHORT_TERM_CLOSE_QUALITY_TIME: 'CommonRelationshipBitId' = 246603 - SENTIMENT_SHORT_TERM_CLOSE_SNOW: 'CommonRelationshipBitId' = 252567 - SENTIMENT_SHORT_TERM_CLOSE_SNOW_FESTIVAL_PARTY: 'CommonRelationshipBitId' = 253207 - SENTIMENT_SHORT_TERM_CLOSE_SNOW_FESTIVAL_PLAY: 'CommonRelationshipBitId' = 253194 - SENTIMENT_SHORT_TERM_CLOSE_TEA_SET_TEA_PARTY: 'CommonRelationshipBitId' = 280848 - SENTIMENT_SHORT_TERM_CLOSE_THROW_FOOTBALL_BONDING_MOMENT: 'CommonRelationshipBitId' = 286015 - SENTIMENT_SHORT_TERM_CLOSE_TRUSTING: 'CommonRelationshipBitId' = 283871 - SENTIMENT_SHORT_TERM_CLOSE_VACATION_SNOWY: 'CommonRelationshipBitId' = 252426 - SENTIMENT_SHORT_TERM_CLOSE_VILLAGER_HELP_HELPED_OUT: 'CommonRelationshipBitId' = 266363 - SENTIMENT_SHORT_TERM_CLOSE_VILLAGE_FAIR_BRIBE_SUCCESS: 'CommonRelationshipBitId' = 268392 - SENTIMENT_SHORT_TERM_CLOSE_WOLFY_WARMTH: 'CommonRelationshipBitId' = 290478 - SENTIMENT_SHORT_TERM_CLOSE_YOUTH_FESTIVAL_BLESSED: 'CommonRelationshipBitId' = 253254 - SENTIMENT_SHORT_TERM_ENAMORED_CANNING_GIFT_JAR: 'CommonRelationshipBitId' = 260818 - SENTIMENT_SHORT_TERM_ENAMORED_FATED_MATES: 'CommonRelationshipBitId' = 293545 - SENTIMENT_SHORT_TERM_ENAMORED_GENERIC: 'CommonRelationshipBitId' = 239988 - SENTIMENT_SHORT_TERM_ENAMORED_HIGH_SCHOOL_PROM_IMPRESSED_BY_PROMPOSAL: 'CommonRelationshipBitId' = 282638 - SENTIMENT_SHORT_TERM_ENAMORED_LIFESTYLES_SHARED: 'CommonRelationshipBitId' = 252423 - SENTIMENT_SHORT_TERM_ENAMORED_MOUNTAIN: 'CommonRelationshipBitId' = 252688 - SENTIMENT_SHORT_TERM_ENAMORED_OPPOSITES: 'CommonRelationshipBitId' = 252422 - SENTIMENT_SHORT_TERM_ENAMORED_PAIRED_DANCING_FIRST_DANCE: 'CommonRelationshipBitId' = 280849 - SENTIMENT_SHORT_TERM_FURIOUS_CHEATING: 'CommonRelationshipBitId' = 246622 - SENTIMENT_SHORT_TERM_FURIOUS_DECORATOR_BAD_BUILD: 'CommonRelationshipBitId' = 268257 - SENTIMENT_SHORT_TERM_FURIOUS_GENERIC: 'CommonRelationshipBitId' = 239980 - SENTIMENT_SHORT_TERM_FURIOUS_LIGHT_FESTIVAL_JEALOUS: 'CommonRelationshipBitId' = 253211 - SENTIMENT_SHORT_TERM_FURIOUS_PACK_RIVALRY: 'CommonRelationshipBitId' = 290475 - SENTIMENT_SHORT_TERM_FURIOUS_WEDDING: 'CommonRelationshipBitId' = 246623 - SENTIMENT_SHORT_TERM_FURIOUS_WEDDING_PARTIES_EJECTED_GUEST: 'CommonRelationshipBitId' = 280830 - SENTIMENT_SHORT_TERM_FURIOUS_WEDDING_TRADITION_ATE_CAKE_EARLY: 'CommonRelationshipBitId' = 276559 - SENTIMENT_SHORT_TERM_FURIOUS_WEDDING_TRADITION_GOT_INTO_FIGHT: 'CommonRelationshipBitId' = 276557 - SENTIMENT_SHORT_TERM_FURIOUS_WEDDING_TRADITION_INTERRUPTED_CEREMONY: 'CommonRelationshipBitId' = 276558 - SENTIMENT_SHORT_TERM_FURIOUS_WEDDING_TRADITION_ROMANTICALLY_UP_STAGED: 'CommonRelationshipBitId' = 276660 - SENTIMENT_SHORT_TERM_FURIOUS_WEDDING_TRADITION_YOU_DIED: 'CommonRelationshipBitId' = 276555 - SENTIMENT_SHORT_TERM_GUILTY_ABANDONED_PACK: 'CommonRelationshipBitId' = 290477 - SENTIMENT_SHORT_TERM_GUILTY_AWKWARD_DATE: 'CommonRelationshipBitId' = 246631 - SENTIMENT_SHORT_TERM_GUILTY_BAD_PARTY: 'CommonRelationshipBitId' = 246633 - SENTIMENT_SHORT_TERM_GUILTY_BIG_SAD_WOLF: 'CommonRelationshipBitId' = 288509 - SENTIMENT_SHORT_TERM_GUILTY_GENERIC: 'CommonRelationshipBitId' = 246630 - SENTIMENT_SHORT_TERM_GUILTY_HIGH_SCHOOL_PROM_BROKEN_PACT: 'CommonRelationshipBitId' = 287902 - SENTIMENT_SHORT_TERM_GUILTY_LIFESTYLE_CLOSE_KNIT: 'CommonRelationshipBitId' = 252691 - SENTIMENT_SHORT_TERM_GUILTY_VILLAGE_FAIR_BRIBE_FAIL: 'CommonRelationshipBitId' = 268427 - SENTIMENT_SHORT_TERM_HURT_GENERIC: 'CommonRelationshipBitId' = 246644 - SENTIMENT_SHORT_TERM_HURT_HIGH_SCHOOL_PROM_BROKEN_DITCH_PROMISE: 'CommonRelationshipBitId' = 282639 - SENTIMENT_SHORT_TERM_HURT_HURT_BY_PACK_MATE: 'CommonRelationshipBitId' = 290476 - SENTIMENT_SHORT_TERM_HURT_LIFESTYLE_NETWORKER: 'CommonRelationshipBitId' = 252692 - SENTIMENT_SHORT_TERM_HURT_LIVESTOCK_SOLD: 'CommonRelationshipBitId' = 263706 - SENTIMENT_SHORT_TERM_HURT_REJECTION: 'CommonRelationshipBitId' = 246640 - SENTIMENT_SHORT_TERM_HURT_ROMANTIC: 'CommonRelationshipBitId' = 246638 - SENTIMENT_SHORT_TERM_HURT_SADDENED: 'CommonRelationshipBitId' = 246642 - SENTIMENT_SHORT_TERM_HURT_SUSPICIOUS: 'CommonRelationshipBitId' = 283870 - SENTIMENT_SHORT_TERM_HURT_YOUTH_FESTIVAL_UNBLESSED: 'CommonRelationshipBitId' = 253227 - SENTIMENT_SHORT_TERM_MOTIVATING_EXTREME_SPORTS: 'CommonRelationshipBitId' = 252845 - SENTIMENT_SHORT_TERM_MOTIVATING_FRIENDLY_ADVICE: 'CommonRelationshipBitId' = 273845 - SENTIMENT_SHORT_TERM_NEEDS_DISTANCE_FRIEND: 'CommonRelationshipBitId' = 278173 - SENTIMENT_SHORT_TERM_NEEDS_DISTANCE_GENERIC_ROMANTIC: 'CommonRelationshipBitId' = 278172 - SENTIMENT_SHORT_TERM_REJECTED_FRIEND: 'CommonRelationshipBitId' = 278178 - SENTIMENT_SHORT_TERM_REJECTED_GENERIC_ROMANTIC: 'CommonRelationshipBitId' = 278177 - SEXUAL_ORIENTATION_WOOHOO_PARTNERS: 'CommonRelationshipBitId' = 291678 - SHORT_TERMS_ASKED_ABOUT_SENTIMENT_COOLDOWN: 'CommonRelationshipBitId' = 250188 - SHORT_TERM_BITS_ARGUMENTS_HAD_ARGUMENT: 'CommonRelationshipBitId' = 162652 - SHORT_TERM_BITS_CLUBS_NEW_MEMBER_GREETED: 'CommonRelationshipBitId' = 130611 - SHORT_TERM_BITS_KICKED_OUT_INAPPROPRIATE_BEHAVIOR: 'CommonRelationshipBitId' = 129869 - SHORT_TERM_BITS_QUICK_SOCIAL_HUG_NOT_VISIBLE: 'CommonRelationshipBitId' = 77250 - SHORT_TERM_BITS_QUICK_SOCIAL_KISS_NOT_VISIBLE: 'CommonRelationshipBitId' = 77251 - SHORT_TERM_BITS_QUICK_SOCIAL_SHOW_FUNNY_VIDEO_NOT_VISIBLE: 'CommonRelationshipBitId' = 77252 - SHORT_TERM_BITS_RESTAURANTS_DINING: 'CommonRelationshipBitId' = 132610 - SHORT_TERM_BITS_TREAD_MILL_ROCK_CLIMBING_WALL_BEAT_HIGH_SCORE: 'CommonRelationshipBitId' = 167893 - SHORT_TERM_HEALED_NEGATIVE_SENTIMENT: 'CommonRelationshipBitId' = 250815 - SHORT_TERM_HIGH_SCHOOL_ACTIVE_ASKED_CAREER_DETAILS: 'CommonRelationshipBitId' = 289096 - SHORT_TERM_IN_FIGHT_WITH: 'CommonRelationshipBitId' = 15845 - SHORT_TERM_IN_QUARREL_WITH: 'CommonRelationshipBitId' = 15846 - SHORT_TERM_JUST_BROKE_UP_OR_DIVORCED: 'CommonRelationshipBitId' = 97332 - SHORT_TERM_MIND_POWERS_ALLURING_VISAGE_SOCIAL_ENCOURAGE: 'CommonRelationshipBitId' = 150062 - SHORT_TERM_ORDERING_SIM: 'CommonRelationshipBitId' = 265566 - SHORT_TERM_RECENT_FIRST_KISS: 'CommonRelationshipBitId' = 77371 - SHORT_TERM_RECENT_NEGATIVE_SOCIAL: 'CommonRelationshipBitId' = 99712 - SHORT_TERM_SNOOPED_IN_JOURNAL: 'CommonRelationshipBitId' = 160252 - SHORT_TERM_SOCIAL_MEDIA_CAREER_REPRESENT: 'CommonRelationshipBitId' = 145918 - SHORT_TERM_VILLAGER_HELP_SHORT_SOCIAL_PACKAGE_COOLDOWN: 'CommonRelationshipBitId' = 263907 - SHORT_TERM_WEDDING_TRADITION_ASK_TO_BE_IN_WEDDING_PARTY: 'CommonRelationshipBitId' = 276839 - SHORT_TERM_WEDDING_TRADITION_ASK_TO_COME_TO_WEDDING: 'CommonRelationshipBitId' = 276837 - SIM_TO_ANIMAL_OBJECT_ACQUAINTANCES: 'CommonRelationshipBitId' = 271028 - SIM_TO_ANIMAL_OBJECT_DESPISED: 'CommonRelationshipBitId' = 271030 - SIM_TO_ANIMAL_OBJECT_DISLIKED: 'CommonRelationshipBitId' = 271029 - SIM_TO_ANIMAL_OBJECT_FRIEND: 'CommonRelationshipBitId' = 271026 - SIM_TO_ANIMAL_OBJECT_GOOD_FRIEND: 'CommonRelationshipBitId' = 271027 - SIM_TO_DOLPHIN_BEST_FRIEND: 'CommonRelationshipBitId' = 207283 - SIM_TO_DOLPHIN_CHUM: 'CommonRelationshipBitId' = 207281 - SIM_TO_DOLPHIN_CURIOUS: 'CommonRelationshipBitId' = 207280 - SIM_TO_DOLPHIN_DISLIKED: 'CommonRelationshipBitId' = 207277 - SIM_TO_DOLPHIN_FEARED: 'CommonRelationshipBitId' = 207276 - SIM_TO_DOLPHIN_FRIEND: 'CommonRelationshipBitId' = 207282 - SIM_TO_DOLPHIN_INDIFFERENT: 'CommonRelationshipBitId' = 207279 - SIM_TO_DOLPHIN_SOULMATE: 'CommonRelationshipBitId' = 207284 - SIM_TO_DOLPHIN_WARY: 'CommonRelationshipBitId' = 207278 - SIM_TO_PET_00_DESPISED: 'CommonRelationshipBitId' = 159231 - SIM_TO_PET_01_DISLIKED: 'CommonRelationshipBitId' = 159232 - SIM_TO_PET_02_ACQUAINTANCE: 'CommonRelationshipBitId' = 159233 - SIM_TO_PET_03_FRIEND: 'CommonRelationshipBitId' = 159236 - SIM_TO_PET_04_GOOD_FRIEND: 'CommonRelationshipBitId' = 159234 - SIM_TO_PET_05_COMPANION: 'CommonRelationshipBitId' = 159235 - SIM_TO_PET_INDIFFERENT_NEUTRAL_BIT: 'CommonRelationshipBitId' = 159230 - SITUATION_BIT_BIRTHDAY_GUEST: 'CommonRelationshipBitId' = 38420 - SITUATION_BIT_WEDDING_COUPLE: 'CommonRelationshipBitId' = 38422 - SITUATION_BIT_WEDDING_GUEST: 'CommonRelationshipBitId' = 38421 - SITUATION_BIT_WELCOME_WAGON_GUEST: 'CommonRelationshipBitId' = 120016 - SITUATION_BIT_WOLF_TOWN_SPARRING_PARTNER: 'CommonRelationshipBitId' = 291740 - SNOW_BRO: 'CommonRelationshipBitId' = 246797 - SOCCER_TEAM_TEAMMATES: 'CommonRelationshipBitId' = 221133 - SOCIAL_CONTEXT_AWKWARDNESS_AWKWARD: 'CommonRelationshipBitId' = 24089 - SOCIAL_CONTEXT_AWKWARDNESS_CASUAL: 'CommonRelationshipBitId' = 115902 - SOCIAL_CONTEXT_AWKWARDNESS_VERY_AWKWARD: 'CommonRelationshipBitId' = 24090 - SOCIAL_CONTEXT_BIT_INTERROGATION_TABLE_CALM: 'CommonRelationshipBitId' = 103962 - SOCIAL_CONTEXT_BIT_INTERROGATION_TABLE_DEFENSIVE: 'CommonRelationshipBitId' = 103961 - SOCIAL_CONTEXT_BIT_INTERROGATION_TABLE_FRIENDLY: 'CommonRelationshipBitId' = 103960 - SOCIAL_CONTEXT_BIT_INTERROGATION_TABLE_FURIOUS: 'CommonRelationshipBitId' = 103959 - SOCIAL_CONTEXT_BIT_INTERROGATION_TABLE_SHY: 'CommonRelationshipBitId' = 103958 - SOCIAL_CONTEXT_BIT_INTERROGATION_TABLE_SMUG: 'CommonRelationshipBitId' = 104781 - SOCIAL_CONTEXT_BIT_INTERROGATION_TABLE_SUSPICIOUS: 'CommonRelationshipBitId' = 103957 - SOCIAL_CONTEXT_BIT_INTERROGATION_TABLE_TENSE: 'CommonRelationshipBitId' = 103956 - SOCIAL_CONTEXT_BIT_INTERROGATION_TABLE_TENSE_DEFAULT: 'CommonRelationshipBitId' = 105228 - SOCIAL_CONTEXT_BIT_INTERROGATION_TABLE_TERRIFIED: 'CommonRelationshipBitId' = 103636 - SOCIAL_CONTEXT_BIT_INTERROGATION_TABLE_VERY_WORRIED: 'CommonRelationshipBitId' = 103955 - SOCIAL_CONTEXT_BIT_INTERROGATION_TABLE_WORRIED: 'CommonRelationshipBitId' = 103953 - SOCIAL_CONTEXT_CASUAL: 'CommonRelationshipBitId' = 24032 - SOCIAL_CONTEXT_FRIENDSHIP_ABHORRENT: 'CommonRelationshipBitId' = 24088 - SOCIAL_CONTEXT_FRIENDSHIP_DISTASTEFUL: 'CommonRelationshipBitId' = 24086 - SOCIAL_CONTEXT_FRIENDSHIP_FRIENDLY: 'CommonRelationshipBitId' = 24085 - SOCIAL_CONTEXT_FRIENDSHIP_OFFENSIVE: 'CommonRelationshipBitId' = 24087 - SOCIAL_CONTEXT_FUN_BORING: 'CommonRelationshipBitId' = 24081 - SOCIAL_CONTEXT_FUN_CASUAL: 'CommonRelationshipBitId' = 115903 - SOCIAL_CONTEXT_FUN_FUNNY: 'CommonRelationshipBitId' = 24077 - SOCIAL_CONTEXT_FUN_HILARIOUS: 'CommonRelationshipBitId' = 24079 - SOCIAL_CONTEXT_FUN_INSUFFERABLY_TEDIOUS: 'CommonRelationshipBitId' = 24083 - SOCIAL_CONTEXT_FUN_TEDIOUS: 'CommonRelationshipBitId' = 24082 - SOCIAL_CONTEXT_RETAIL_MILDLY_INTERESTED: 'CommonRelationshipBitId' = 111602 - SOCIAL_CONTEXT_RETAIL_UNINTERESTED: 'CommonRelationshipBitId' = 111600 - SOCIAL_CONTEXT_RETAIL_VERY_INTERESTED: 'CommonRelationshipBitId' = 111601 - SOCIAL_CONTEXT_ROMANCE_AMOROUS: 'CommonRelationshipBitId' = 24076 - SOCIAL_CONTEXT_ROMANCE_CASUAL: 'CommonRelationshipBitId' = 115904 - SOCIAL_CONTEXT_ROMANCE_STEAMY: 'CommonRelationshipBitId' = 24080 - SOCIAL_CONTEXT_ROMANCE_SUGGESTIVE: 'CommonRelationshipBitId' = 24078 - SOCIAL_MEDIA_CONTACTLIST: 'CommonRelationshipBitId' = 277014 - SPECIAL_BITS_ARCH_ENEMIES: 'CommonRelationshipBitId' = 26561 - SPECIAL_BITS_DECLARED_ARCH_ENEMY: 'CommonRelationshipBitId' = 26566 - SPECIAL_BITS_ENEMY: 'CommonRelationshipBitId' = 26560 - SPECIAL_BITS_GREETED: 'CommonRelationshipBitId' = 122768 - SPELLS_MIND_CONTROLLED: 'CommonRelationshipBitId' = 216188 - SQUAD_MEMBER: 'CommonRelationshipBitId' = 196234 - SUMMON_GHOST_FAIL: 'CommonRelationshipBitId' = 215677 - TANDEM_SLEDDERS: 'CommonRelationshipBitId' = 251537 - TENANT: 'CommonRelationshipBitId' = 148657 - TODDLER_CARE_DEPENDENT_EFFECTIVE: 'CommonRelationshipBitId' = 155923 - TODDLER_CARE_GIVER_EFFECTIVE: 'CommonRelationshipBitId' = 155918 - TODDLER_NOT_PARENT_CARE_DEPENDENT: 'CommonRelationshipBitId' = 152851 - TODDLER_NOT_PARENT_CARE_GIVER: 'CommonRelationshipBitId' = 146488 - TODDLER_STRANGER: 'CommonRelationshipBitId' = 141125 - TRY_TO_GREET: 'CommonRelationshipBitId' = 194904 - VAMPIRE_MASTER: 'CommonRelationshipBitId' = 149548 - VAMPIRE_OFFSPRING: 'CommonRelationshipBitId' = 149549 - VILLAGER_HELP_AGATHA_2_ACCEPTED_ROSE: 'CommonRelationshipBitId' = 269871 - VILLAGER_HELP_AGATHA_2_SOLD_TO: 'CommonRelationshipBitId' = 268939 - VILLAGER_HELP_GOT_GROCERY_ORDER_ALREADY: 'CommonRelationshipBitId' = 267298 - VILLAGER_HELP_MYSTERY_GIFTER_NO: 'CommonRelationshipBitId' = 265418 - VILLAGER_HELP_MYSTERY_GIFTER_YES: 'CommonRelationshipBitId' = 265417 - WEDDING_CUSTOM_STATE_FLOWER_SPREADER: 'CommonRelationshipBitId' = 275958 - WEDDING_CUSTOM_STATE_FLOWER_SPREADER_SIGNIFICANT_OTHER: 'CommonRelationshipBitId' = 281996 - WEDDING_CUSTOM_STATE_HONORED_WEDDING_PARTY: 'CommonRelationshipBitId' = 283690 - WEDDING_CUSTOM_STATE_HONOR_ATTENDANT: 'CommonRelationshipBitId' = 275959 - WEDDING_CUSTOM_STATE_HONOR_ATTENDANT_SIGNIFICANT_OTHER: 'CommonRelationshipBitId' = 281997 - WEDDING_CUSTOM_STATE_OFFICIANT: 'CommonRelationshipBitId' = 275957 - WEDDING_CUSTOM_STATE_OFFICIANT_SIGNIFICANT_OTHER: 'CommonRelationshipBitId' = 281998 - WEDDING_CUSTOM_STATE_RING_BEARER: 'CommonRelationshipBitId' = 279776 - WEDDING_CUSTOM_STATE_RING_BEARER_SIGNIFICANT_OTHER: 'CommonRelationshipBitId' = 281999 - WEDDING_VOW_RENEWAL_CUSTOM_STATE_HONOR_ATTENDANT: 'CommonRelationshipBitId' = 289919 - WEDDING_VOW_RENEWAL_CUSTOM_STATE_HONOR_ATTENDANT_SIGNIFICANT_OTHER: 'CommonRelationshipBitId' = 289920 - WELLNESS_REPEAT_CUSTOMER: 'CommonRelationshipBitId' = 276949 - WRITING_JOURNALISM_ARTICLE_INTERVIEW: 'CommonRelationshipBitId' = 33719 - WRITING_JOURNALISM_ARTICLE_INTERVIEW_NEGATIVE: 'CommonRelationshipBitId' = 33720 - WRITING_JOURNALISM_ARTICLE_INTERVIEW_POSITIVE: 'CommonRelationshipBitId' = 33721 diff --git a/Scripts/s4ap/sims4communitylib/enums/relationship_tracks_enum.py b/Scripts/s4ap/sims4communitylib/enums/relationship_tracks_enum.py deleted file mode 100644 index fc1d67a..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/relationship_tracks_enum.py +++ /dev/null @@ -1,23 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonRelationshipTrackId(CommonInt): - """Identifiers for vanilla sim relationship tracks. - - """ - INVALID: 'CommonRelationshipTrackId' = 0 - AUTHORITY: 'CommonRelationshipTrackId' = 161998 - FEUD: 'CommonRelationshipTrackId' = 193901 - FRIENDSHIP: 'CommonRelationshipTrackId' = 16650 - MISCHIEF: 'CommonRelationshipTrackId' = 26920 - RIVALRY: 'CommonRelationshipTrackId' = 161999 - ROMANCE: 'CommonRelationshipTrackId' = 16651 - SIM_TO_PET_FRIENDSHIP: 'CommonRelationshipTrackId' = 159228 - SMART_HUB_FRIENDSHIP: 'CommonRelationshipTrackId' = 203686 diff --git a/Scripts/s4ap/sims4communitylib/enums/relationship_types_enum.py b/Scripts/s4ap/sims4communitylib/enums/relationship_types_enum.py deleted file mode 100644 index fb6d96c..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/relationship_types_enum.py +++ /dev/null @@ -1,21 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonRelationshipTypeId(CommonInt): - """Identifiers for relationship types.""" - INVALID: 'CommonRelationshipTypeId' = 0 - ROMANTIC: 'CommonRelationshipTypeId' = 2 - UPSET_WITH: 'CommonRelationshipTypeId' = 3 - FAMILY: 'CommonRelationshipTypeId' = 4 - SIGNIFICANT_OTHER: 'CommonRelationshipTypeId' = 5 - WRITING_JOURNALISM_INTERVIEW: 'CommonRelationshipTypeId' = 6 - ACQUIRED_FAMILY: 'CommonRelationshipTypeId' = 7 - PET_RELATIONSHIP: 'CommonRelationshipTypeId' = 8 - SENTIMENT: 'CommonRelationshipTypeId' = 9 diff --git a/Scripts/s4ap/sims4communitylib/enums/short_term_relationship_tracks_enum.py b/Scripts/s4ap/sims4communitylib/enums/short_term_relationship_tracks_enum.py deleted file mode 100644 index a04bf75..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/short_term_relationship_tracks_enum.py +++ /dev/null @@ -1,30 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonShortTermRelationshipTrackId(CommonInt): - """Identifiers for vanilla sim short-term relationship tracks. - - """ - INVALID: 'CommonShortTermRelationshipTrackId' = 0 - AWKWARDNESS: 'CommonShortTermRelationshipTrackId' = 24098 - FRIENDSHIP: 'CommonShortTermRelationshipTrackId' = 24099 - FUN: 'CommonShortTermRelationshipTrackId' = 24100 - INTERROGATION_TABLE_CALM: 'CommonShortTermRelationshipTrackId' = 103618 - INTERROGATION_TABLE_DEFENSIVE: 'CommonShortTermRelationshipTrackId' = 103617 - INTERROGATION_TABLE_FRIENDLY: 'CommonShortTermRelationshipTrackId' = 103613 - INTERROGATION_TABLE_FURIOUS: 'CommonShortTermRelationshipTrackId' = 103616 - INTERROGATION_TABLE_SHY: 'CommonShortTermRelationshipTrackId' = 103598 - INTERROGATION_TABLE_SMUG: 'CommonShortTermRelationshipTrackId' = 103619 - INTERROGATION_TABLE_SUSPICIOUS: 'CommonShortTermRelationshipTrackId' = 103612 - INTERROGATION_TABLE_TENSE: 'CommonShortTermRelationshipTrackId' = 103615 - INTERROGATION_TABLE_TERRIFIED: 'CommonShortTermRelationshipTrackId' = 103614 - INTERROGATION_TABLE_WORRIED: 'CommonShortTermRelationshipTrackId' = 103620 - RETAIL_PURCHASE_INTEREST: 'CommonShortTermRelationshipTrackId' = 111598 - ROMANCE: 'CommonShortTermRelationshipTrackId' = 24101 diff --git a/Scripts/s4ap/sims4communitylib/enums/short_term_sentiments_enum.py b/Scripts/s4ap/sims4communitylib/enums/short_term_sentiments_enum.py deleted file mode 100644 index 6354553..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/short_term_sentiments_enum.py +++ /dev/null @@ -1,107 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonShortTermSentimentId(CommonInt): - """Identifiers for vanilla short term sentiments.""" - INVALID: 'CommonShortTermSentimentId' = 0 - ADORING_CONSOLE_DEATH: 'CommonShortTermSentimentId' = 273923 - ADORING_DECORATOR_GOOD_BUILD: 'CommonShortTermSentimentId' = 268267 - ADORING_GENERIC: 'CommonShortTermSentimentId' = 246530 - ADORING_IMPRESSED: 'CommonShortTermSentimentId' = 246535 - ADORING_WEDDING_TRADITION_GAVE_GOOD_SPEECH: 'CommonShortTermSentimentId' = 276548 - BITTER_CRUMPLE_BOTTOMED: 'CommonShortTermSentimentId' = 264465 - BITTER_BREAKUP: 'CommonShortTermSentimentId' = 246538 - BITTER_DIVORCE: 'CommonShortTermSentimentId' = 246539 - BITTER_EXCURSION_CANCEL_ACT1: 'CommonShortTermSentimentId' = 249751 - BITTER_FIGHT: 'CommonShortTermSentimentId' = 246597 - BITTER_GRUDGE_AGAINST_PACK_A: 'CommonShortTermSentimentId' = 290940 - BITTER_GRUDGE_AGAINST_PACK_B: 'CommonShortTermSentimentId' = 290941 - BITTER_HIGH_SCHOOL_PROM_NO_PROM_INVITE: 'CommonShortTermSentimentId' = 282640 - BITTER_HIKING_TRAIL_GROUP_HIKE_TIN_REWARD: 'CommonShortTermSentimentId' = 250363 - BITTER_LIFESTYLE_WORKAHOLIC: 'CommonShortTermSentimentId' = 252693 - BITTER_LIVESTOCK_SOLD: 'CommonShortTermSentimentId' = 263707 - BITTER_OPENABLE_WINDOW_FAIL_EVENT: 'CommonShortTermSentimentId' = 283047 - BITTER_VILLAGE_FAIR_BRIBE_FAIL: 'CommonShortTermSentimentId' = 268415 - BITTER_WEDDING_TRADITION_NOT_INVITED_TO_WEDDING: 'CommonShortTermSentimentId' = 276835 - BITTER_WEDDING_TRADITION_NOT_SELECTED_BEST_MAN: 'CommonShortTermSentimentId' = 276551 - BITTER_WEDDING_TRADITION_NOT_SELECTED_MAID_OF_HONOR: 'CommonShortTermSentimentId' = 276553 - BITTER_YOGA_CLASS: 'CommonShortTermSentimentId' = 271953 - CLOSE_ADOPTION: 'CommonShortTermSentimentId' = 246610 - CLOSE_CANNING_RECEIVE_GIFT: 'CommonShortTermSentimentId' = 260816 - CLOSE_COTTAGE_WORLD_NPC_GOSSIP: 'CommonShortTermSentimentId' = 264954 - CLOSE_GENERIC: 'CommonShortTermSentimentId' = 246604 - CLOSE_GOOD_FIRST_IMPRESSION: 'CommonShortTermSentimentId' = 273242 - CLOSE_GROUP_COOKING_COOKING_TOGETHER: 'CommonShortTermSentimentId' = 262317 - CLOSE_NEAR_DEATH: 'CommonShortTermSentimentId' = 246647 - CLOSE_PARTY: 'CommonShortTermSentimentId' = 246606 - CLOSE_QUALITY_TIME: 'CommonShortTermSentimentId' = 246603 - CLOSE_HIGH_SCHOOL_PROM_SKIPPING_PROM_TOGETHER: 'CommonShortTermSentimentId' = 282637 - CLOSE_HIKING_TRAIL_GROUP_HIKE_GOLD_REWARD: 'CommonShortTermSentimentId' = 250366 - CLOSE_HOTPOT: 'CommonShortTermSentimentId' = 252685 - CLOSE_LIFESTYLE_CLOSE_KNIT: 'CommonShortTermSentimentId' = 252687 - CLOSE_LIGHT_FESTIVAL_WISH: 'CommonShortTermSentimentId' = 253253 - CLOSE_ONSEN: 'CommonShortTermSentimentId' = 252680 - CLOSE_OPENABLE_WINDOW_SUCCESS_EVENT: 'CommonShortTermSentimentId' = 283050 - CLOSE_PICNIC_BASKET_PICNIC_BONDING: 'CommonShortTermSentimentId' = 260815 - CLOSE_SNOW: 'CommonShortTermSentimentId' = 252567 - CLOSE_SNOW_FESTIVAL_PARTY: 'CommonShortTermSentimentId' = 253207 - CLOSE_SNOW_FESTIVAL_PLAY: 'CommonShortTermSentimentId' = 253194 - CLOSE_TEA_SET_TEA_PARTY: 'CommonShortTermSentimentId' = 280848 - CLOSE_THROW_FOOTBALL_BONDING_MOMENT: 'CommonShortTermSentimentId' = 286015 - CLOSE_TRUSTING: 'CommonShortTermSentimentId' = 283871 - CLOSE_VACATION_SNOWY: 'CommonShortTermSentimentId' = 252426 - CLOSE_VILLAGE_FAIR_BRIBE_SUCCESS: 'CommonShortTermSentimentId' = 268392 - CLOSE_VILLAGER_HELP_HELPED_OUT: 'CommonShortTermSentimentId' = 266363 - CLOSE_WOLFY_WARMTH: 'CommonShortTermSentimentId' = 290478 - CLOSE_YOUTH_FESTIVAL_BLESSED: 'CommonShortTermSentimentId' = 253254 - ENAMORED_CANNING_GIFT_JAR: 'CommonShortTermSentimentId' = 260818 - ENAMORED_FATED_MATES: 'CommonShortTermSentimentId' = 293545 - ENAMORED_GENERIC: 'CommonShortTermSentimentId' = 239988 - ENAMORED_HIGH_SCHOOL_PROM_IMPRESSED_BY_PROMPOSAL: 'CommonShortTermSentimentId' = 282638 - ENAMORED_LIFESTYLES_SHARED: 'CommonShortTermSentimentId' = 252423 - ENAMORED_MOUNTAIN: 'CommonShortTermSentimentId' = 252688 - ENAMORED_OPPOSITES: 'CommonShortTermSentimentId' = 252422 - ENAMORED_PAIRED_DANCING_FIRST_DANCE: 'CommonShortTermSentimentId' = 280849 - FURIOUS_CHEATING: 'CommonShortTermSentimentId' = 246622 - FURIOUS_DECORATOR_BAD_BUILD: 'CommonShortTermSentimentId' = 268257 - FURIOUS_GENERIC: 'CommonShortTermSentimentId' = 239980 - FURIOUS_LIGHT_FESTIVAL_JEALOUS: 'CommonShortTermSentimentId' = 253211 - FURIOUS_PACK_RIVALRY: 'CommonShortTermSentimentId' = 290475 - FURIOUS_WEDDING: 'CommonShortTermSentimentId' = 246623 - FURIOUS_WEDDING_PARTIES_EJECTED_GUEST: 'CommonShortTermSentimentId' = 280830 - FURIOUS_WEDDING_TRADITION_ATE_CAKE_EARLY: 'CommonShortTermSentimentId' = 276559 - FURIOUS_WEDDING_TRADITION_GOT_INTO_FIGHT: 'CommonShortTermSentimentId' = 276557 - FURIOUS_WEDDING_TRADITION_INTERRUPTED_CEREMONY: 'CommonShortTermSentimentId' = 276558 - FURIOUS_WEDDING_TRADITION_ROMANTICALLY_UP_STAGED: 'CommonShortTermSentimentId' = 276660 - FURIOUS_WEDDING_TRADITION_YOU_DIED: 'CommonShortTermSentimentId' = 276555 - GUILTY_ABANDONED_PACK: 'CommonShortTermSentimentId' = 290477 - GUILTY_AWKWARD_DATE: 'CommonShortTermSentimentId' = 246631 - GUILTY_BAD_PARTY: 'CommonShortTermSentimentId' = 246633 - GUILTY_BIG_SAD_WOLF: 'CommonShortTermSentimentId' = 288509 - GUILTY_GENERIC: 'CommonShortTermSentimentId' = 246630 - GUILTY_HIGH_SCHOOL_PROM_BROKEN_PACT: 'CommonShortTermSentimentId' = 287902 - GUILTY_LIFESTYLE_CLOSE_KNIT: 'CommonShortTermSentimentId' = 252691 - GUILTY_VILLAGE_FAIR_BRIBE_FAIL: 'CommonShortTermSentimentId' = 268427 - HURT_GENERIC: 'CommonShortTermSentimentId' = 246644 - HURT_HIGH_SCHOOL_PROM_BROKEN_DITCH_PROMISE: 'CommonShortTermSentimentId' = 282639 - HURT_HURT_BY_PACK_MATE: 'CommonShortTermSentimentId' = 290476 - HURT_LIVESTOCK_SOLD: 'CommonShortTermSentimentId' = 263706 - HURT_REJECTION: 'CommonShortTermSentimentId' = 246640 - HURT_ROMANTIC: 'CommonShortTermSentimentId' = 246638 - HURT_SADDENED: 'CommonShortTermSentimentId' = 246642 - HURT_SUSPICIOUS: 'CommonShortTermSentimentId' = 283870 - HURT_LIFESTYLE_NETWORKER: 'CommonShortTermSentimentId' = 252692 - HURT_YOUTH_FESTIVAL_UNBLESSED: 'CommonShortTermSentimentId' = 253227 - MOTIVATING_EXTREME_SPORTS: 'CommonShortTermSentimentId' = 252845 - MOTIVATING_FRIENDLY_ADVICE: 'CommonShortTermSentimentId' = 273845 - NEEDS_DISTANCE_FRIEND: 'CommonShortTermSentimentId' = 278173 - NEEDS_DISTANCE_GENERIC_ROMANTIC: 'CommonShortTermSentimentId' = 278172 - REJECTED_FRIEND: 'CommonShortTermSentimentId' = 278178 - REJECTED_GENERIC_ROMANTIC: 'CommonShortTermSentimentId' = 278177 diff --git a/Scripts/s4ap/sims4communitylib/enums/sim_type.py b/Scripts/s4ap/sims4communitylib/enums/sim_type.py deleted file mode 100644 index c625c90..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/sim_type.py +++ /dev/null @@ -1,629 +0,0 @@ -""" -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 -""" -from typing import Tuple, Iterator - -from s4ap.sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags - - -class CommonSimType(CommonIntFlags): - """Various Sim Types that describe the Age, Species, and Occult Type of a Sim in a single value.""" - NONE: 'CommonSimType' = ... - - ELDER_HUMAN: 'CommonSimType' = ... - ELDER_HUMAN_VAMPIRE: 'CommonSimType' = ... - ELDER_HUMAN_GHOST: 'CommonSimType' = ... - ELDER_HUMAN_ALIEN: 'CommonSimType' = ... - ELDER_HUMAN_MERMAID: 'CommonSimType' = ... - ELDER_HUMAN_WITCH: 'CommonSimType' = ... - ELDER_HUMAN_ROBOT: 'CommonSimType' = ... - ELDER_HUMAN_SCARECROW: 'CommonSimType' = ... - ELDER_HUMAN_SKELETON: 'CommonSimType' = ... - ELDER_HUMAN_PLANT_SIM: 'CommonSimType' = ... - ELDER_HUMAN_WEREWOLF: 'CommonSimType' = ... - - ADULT_HUMAN: 'CommonSimType' = ... - ADULT_HUMAN_VAMPIRE: 'CommonSimType' = ... - ADULT_HUMAN_GHOST: 'CommonSimType' = ... - ADULT_HUMAN_ALIEN: 'CommonSimType' = ... - ADULT_HUMAN_MERMAID: 'CommonSimType' = ... - ADULT_HUMAN_WITCH: 'CommonSimType' = ... - ADULT_HUMAN_ROBOT: 'CommonSimType' = ... - ADULT_HUMAN_SCARECROW: 'CommonSimType' = ... - ADULT_HUMAN_SKELETON: 'CommonSimType' = ... - ADULT_HUMAN_PLANT_SIM: 'CommonSimType' = ... - ADULT_HUMAN_WEREWOLF: 'CommonSimType' = ... - - YOUNG_ADULT_HUMAN: 'CommonSimType' = ... - YOUNG_ADULT_HUMAN_VAMPIRE: 'CommonSimType' = ... - YOUNG_ADULT_HUMAN_GHOST: 'CommonSimType' = ... - YOUNG_ADULT_HUMAN_ALIEN: 'CommonSimType' = ... - YOUNG_ADULT_HUMAN_MERMAID: 'CommonSimType' = ... - YOUNG_ADULT_HUMAN_WITCH: 'CommonSimType' = ... - YOUNG_ADULT_HUMAN_ROBOT: 'CommonSimType' = ... - YOUNG_ADULT_HUMAN_SCARECROW: 'CommonSimType' = ... - YOUNG_ADULT_HUMAN_SKELETON: 'CommonSimType' = ... - YOUNG_ADULT_HUMAN_PLANT_SIM: 'CommonSimType' = ... - YOUNG_ADULT_HUMAN_WEREWOLF: 'CommonSimType' = ... - - TEEN_HUMAN: 'CommonSimType' = ... - TEEN_HUMAN_VAMPIRE: 'CommonSimType' = ... - TEEN_HUMAN_GHOST: 'CommonSimType' = ... - TEEN_HUMAN_ALIEN: 'CommonSimType' = ... - TEEN_HUMAN_MERMAID: 'CommonSimType' = ... - TEEN_HUMAN_WITCH: 'CommonSimType' = ... - TEEN_HUMAN_ROBOT: 'CommonSimType' = ... - TEEN_HUMAN_SCARECROW: 'CommonSimType' = ... - TEEN_HUMAN_SKELETON: 'CommonSimType' = ... - TEEN_HUMAN_PLANT_SIM: 'CommonSimType' = ... - TEEN_HUMAN_WEREWOLF: 'CommonSimType' = ... - - CHILD_HUMAN: 'CommonSimType' = ... - CHILD_HUMAN_VAMPIRE: 'CommonSimType' = ... - CHILD_HUMAN_GHOST: 'CommonSimType' = ... - CHILD_HUMAN_ALIEN: 'CommonSimType' = ... - CHILD_HUMAN_MERMAID: 'CommonSimType' = ... - CHILD_HUMAN_WITCH: 'CommonSimType' = ... - CHILD_HUMAN_ROBOT: 'CommonSimType' = ... - CHILD_HUMAN_SCARECROW: 'CommonSimType' = ... - CHILD_HUMAN_SKELETON: 'CommonSimType' = ... - CHILD_HUMAN_PLANT_SIM: 'CommonSimType' = ... - CHILD_HUMAN_WEREWOLF: 'CommonSimType' = ... - - TODDLER_HUMAN: 'CommonSimType' = ... - TODDLER_HUMAN_VAMPIRE: 'CommonSimType' = ... - TODDLER_HUMAN_GHOST: 'CommonSimType' = ... - TODDLER_HUMAN_ALIEN: 'CommonSimType' = ... - TODDLER_HUMAN_MERMAID: 'CommonSimType' = ... - TODDLER_HUMAN_WITCH: 'CommonSimType' = ... - TODDLER_HUMAN_ROBOT: 'CommonSimType' = ... - TODDLER_HUMAN_SCARECROW: 'CommonSimType' = ... - TODDLER_HUMAN_SKELETON: 'CommonSimType' = ... - TODDLER_HUMAN_PLANT_SIM: 'CommonSimType' = ... - TODDLER_HUMAN_WEREWOLF: 'CommonSimType' = ... - - INFANT_HUMAN: 'CommonSimType' = ... - INFANT_HUMAN_VAMPIRE: 'CommonSimType' = ... - INFANT_HUMAN_GHOST: 'CommonSimType' = ... - INFANT_HUMAN_ALIEN: 'CommonSimType' = ... - INFANT_HUMAN_MERMAID: 'CommonSimType' = ... - INFANT_HUMAN_WITCH: 'CommonSimType' = ... - INFANT_HUMAN_ROBOT: 'CommonSimType' = ... - INFANT_HUMAN_SCARECROW: 'CommonSimType' = ... - INFANT_HUMAN_SKELETON: 'CommonSimType' = ... - INFANT_HUMAN_PLANT_SIM: 'CommonSimType' = ... - INFANT_HUMAN_WEREWOLF: 'CommonSimType' = ... - - BABY_HUMAN: 'CommonSimType' = ... - BABY_HUMAN_VAMPIRE: 'CommonSimType' = ... - BABY_HUMAN_GHOST: 'CommonSimType' = ... - BABY_HUMAN_ALIEN: 'CommonSimType' = ... - BABY_HUMAN_MERMAID: 'CommonSimType' = ... - BABY_HUMAN_WITCH: 'CommonSimType' = ... - BABY_HUMAN_ROBOT: 'CommonSimType' = ... - BABY_HUMAN_SCARECROW: 'CommonSimType' = ... - BABY_HUMAN_SKELETON: 'CommonSimType' = ... - BABY_HUMAN_PLANT_SIM: 'CommonSimType' = ... - BABY_HUMAN_WEREWOLF: 'CommonSimType' = ... - - CHILD_DOG: 'CommonSimType' = ... - CHILD_DOG_VAMPIRE: 'CommonSimType' = ... - CHILD_DOG_GHOST: 'CommonSimType' = ... - CHILD_DOG_ALIEN: 'CommonSimType' = ... - CHILD_DOG_MERMAID: 'CommonSimType' = ... - CHILD_DOG_WITCH: 'CommonSimType' = ... - CHILD_DOG_ROBOT: 'CommonSimType' = ... - CHILD_DOG_SCARECROW: 'CommonSimType' = ... - CHILD_DOG_SKELETON: 'CommonSimType' = ... - CHILD_DOG_PLANT_SIM: 'CommonSimType' = ... - CHILD_DOG_WEREWOLF: 'CommonSimType' = ... - - ELDER_SMALL_DOG: 'CommonSimType' = ... - ELDER_SMALL_DOG_VAMPIRE: 'CommonSimType' = ... - ELDER_SMALL_DOG_GHOST: 'CommonSimType' = ... - ELDER_SMALL_DOG_ALIEN: 'CommonSimType' = ... - ELDER_SMALL_DOG_MERMAID: 'CommonSimType' = ... - ELDER_SMALL_DOG_WITCH: 'CommonSimType' = ... - ELDER_SMALL_DOG_ROBOT: 'CommonSimType' = ... - ELDER_SMALL_DOG_SCARECROW: 'CommonSimType' = ... - ELDER_SMALL_DOG_SKELETON: 'CommonSimType' = ... - ELDER_SMALL_DOG_PLANT_SIM: 'CommonSimType' = ... - ELDER_SMALL_DOG_WEREWOLF: 'CommonSimType' = ... - - ADULT_SMALL_DOG: 'CommonSimType' = ... - ADULT_SMALL_DOG_VAMPIRE: 'CommonSimType' = ... - ADULT_SMALL_DOG_GHOST: 'CommonSimType' = ... - ADULT_SMALL_DOG_ALIEN: 'CommonSimType' = ... - ADULT_SMALL_DOG_MERMAID: 'CommonSimType' = ... - ADULT_SMALL_DOG_WITCH: 'CommonSimType' = ... - ADULT_SMALL_DOG_ROBOT: 'CommonSimType' = ... - ADULT_SMALL_DOG_SCARECROW: 'CommonSimType' = ... - ADULT_SMALL_DOG_SKELETON: 'CommonSimType' = ... - ADULT_SMALL_DOG_PLANT_SIM: 'CommonSimType' = ... - ADULT_SMALL_DOG_WEREWOLF: 'CommonSimType' = ... - - CHILD_SMALL_DOG: 'CommonSimType' = ... - CHILD_SMALL_DOG_VAMPIRE: 'CommonSimType' = ... - CHILD_SMALL_DOG_GHOST: 'CommonSimType' = ... - CHILD_SMALL_DOG_ALIEN: 'CommonSimType' = ... - CHILD_SMALL_DOG_MERMAID: 'CommonSimType' = ... - CHILD_SMALL_DOG_WITCH: 'CommonSimType' = ... - CHILD_SMALL_DOG_ROBOT: 'CommonSimType' = ... - CHILD_SMALL_DOG_SCARECROW: 'CommonSimType' = ... - CHILD_SMALL_DOG_SKELETON: 'CommonSimType' = ... - CHILD_SMALL_DOG_PLANT_SIM: 'CommonSimType' = ... - CHILD_SMALL_DOG_WEREWOLF: 'CommonSimType' = ... - - ELDER_LARGE_DOG: 'CommonSimType' = ... - ELDER_LARGE_DOG_VAMPIRE: 'CommonSimType' = ... - ELDER_LARGE_DOG_GHOST: 'CommonSimType' = ... - ELDER_LARGE_DOG_ALIEN: 'CommonSimType' = ... - ELDER_LARGE_DOG_MERMAID: 'CommonSimType' = ... - ELDER_LARGE_DOG_WITCH: 'CommonSimType' = ... - ELDER_LARGE_DOG_ROBOT: 'CommonSimType' = ... - ELDER_LARGE_DOG_SCARECROW: 'CommonSimType' = ... - ELDER_LARGE_DOG_SKELETON: 'CommonSimType' = ... - ELDER_LARGE_DOG_PLANT_SIM: 'CommonSimType' = ... - ELDER_LARGE_DOG_WEREWOLF: 'CommonSimType' = ... - - ADULT_LARGE_DOG: 'CommonSimType' = ... - ADULT_LARGE_DOG_VAMPIRE: 'CommonSimType' = ... - ADULT_LARGE_DOG_GHOST: 'CommonSimType' = ... - ADULT_LARGE_DOG_ALIEN: 'CommonSimType' = ... - ADULT_LARGE_DOG_MERMAID: 'CommonSimType' = ... - ADULT_LARGE_DOG_WITCH: 'CommonSimType' = ... - ADULT_LARGE_DOG_ROBOT: 'CommonSimType' = ... - ADULT_LARGE_DOG_SCARECROW: 'CommonSimType' = ... - ADULT_LARGE_DOG_SKELETON: 'CommonSimType' = ... - ADULT_LARGE_DOG_PLANT_SIM: 'CommonSimType' = ... - ADULT_LARGE_DOG_WEREWOLF: 'CommonSimType' = ... - - CHILD_LARGE_DOG: 'CommonSimType' = ... - CHILD_LARGE_DOG_VAMPIRE: 'CommonSimType' = ... - CHILD_LARGE_DOG_GHOST: 'CommonSimType' = ... - CHILD_LARGE_DOG_ALIEN: 'CommonSimType' = ... - CHILD_LARGE_DOG_MERMAID: 'CommonSimType' = ... - CHILD_LARGE_DOG_WITCH: 'CommonSimType' = ... - CHILD_LARGE_DOG_ROBOT: 'CommonSimType' = ... - CHILD_LARGE_DOG_SCARECROW: 'CommonSimType' = ... - CHILD_LARGE_DOG_SKELETON: 'CommonSimType' = ... - CHILD_LARGE_DOG_PLANT_SIM: 'CommonSimType' = ... - CHILD_LARGE_DOG_WEREWOLF: 'CommonSimType' = ... - - ELDER_CAT: 'CommonSimType' = ... - ELDER_CAT_VAMPIRE: 'CommonSimType' = ... - ELDER_CAT_GHOST: 'CommonSimType' = ... - ELDER_CAT_ALIEN: 'CommonSimType' = ... - ELDER_CAT_MERMAID: 'CommonSimType' = ... - ELDER_CAT_WITCH: 'CommonSimType' = ... - ELDER_CAT_ROBOT: 'CommonSimType' = ... - ELDER_CAT_SCARECROW: 'CommonSimType' = ... - ELDER_CAT_SKELETON: 'CommonSimType' = ... - ELDER_CAT_PLANT_SIM: 'CommonSimType' = ... - ELDER_CAT_WEREWOLF: 'CommonSimType' = ... - - ADULT_CAT: 'CommonSimType' = ... - ADULT_CAT_VAMPIRE: 'CommonSimType' = ... - ADULT_CAT_GHOST: 'CommonSimType' = ... - ADULT_CAT_ALIEN: 'CommonSimType' = ... - ADULT_CAT_MERMAID: 'CommonSimType' = ... - ADULT_CAT_WITCH: 'CommonSimType' = ... - ADULT_CAT_ROBOT: 'CommonSimType' = ... - ADULT_CAT_SCARECROW: 'CommonSimType' = ... - ADULT_CAT_SKELETON: 'CommonSimType' = ... - ADULT_CAT_PLANT_SIM: 'CommonSimType' = ... - ADULT_CAT_WEREWOLF: 'CommonSimType' = ... - - CHILD_CAT: 'CommonSimType' = ... - CHILD_CAT_VAMPIRE: 'CommonSimType' = ... - CHILD_CAT_GHOST: 'CommonSimType' = ... - CHILD_CAT_ALIEN: 'CommonSimType' = ... - CHILD_CAT_MERMAID: 'CommonSimType' = ... - CHILD_CAT_WITCH: 'CommonSimType' = ... - CHILD_CAT_ROBOT: 'CommonSimType' = ... - CHILD_CAT_SCARECROW: 'CommonSimType' = ... - CHILD_CAT_SKELETON: 'CommonSimType' = ... - CHILD_CAT_PLANT_SIM: 'CommonSimType' = ... - CHILD_CAT_WEREWOLF: 'CommonSimType' = ... - - ELDER_FOX: 'CommonSimType' = ... - ELDER_FOX_VAMPIRE: 'CommonSimType' = ... - ELDER_FOX_GHOST: 'CommonSimType' = ... - ELDER_FOX_ALIEN: 'CommonSimType' = ... - ELDER_FOX_MERMAID: 'CommonSimType' = ... - ELDER_FOX_WITCH: 'CommonSimType' = ... - ELDER_FOX_ROBOT: 'CommonSimType' = ... - ELDER_FOX_SCARECROW: 'CommonSimType' = ... - ELDER_FOX_SKELETON: 'CommonSimType' = ... - ELDER_FOX_PLANT_SIM: 'CommonSimType' = ... - ELDER_FOX_WEREWOLF: 'CommonSimType' = ... - - ADULT_FOX: 'CommonSimType' = ... - ADULT_FOX_VAMPIRE: 'CommonSimType' = ... - ADULT_FOX_GHOST: 'CommonSimType' = ... - ADULT_FOX_ALIEN: 'CommonSimType' = ... - ADULT_FOX_MERMAID: 'CommonSimType' = ... - ADULT_FOX_WITCH: 'CommonSimType' = ... - ADULT_FOX_ROBOT: 'CommonSimType' = ... - ADULT_FOX_SCARECROW: 'CommonSimType' = ... - ADULT_FOX_SKELETON: 'CommonSimType' = ... - ADULT_FOX_PLANT_SIM: 'CommonSimType' = ... - ADULT_FOX_WEREWOLF: 'CommonSimType' = ... - - CHILD_FOX: 'CommonSimType' = ... - CHILD_FOX_VAMPIRE: 'CommonSimType' = ... - CHILD_FOX_GHOST: 'CommonSimType' = ... - CHILD_FOX_ALIEN: 'CommonSimType' = ... - CHILD_FOX_MERMAID: 'CommonSimType' = ... - CHILD_FOX_WITCH: 'CommonSimType' = ... - CHILD_FOX_ROBOT: 'CommonSimType' = ... - CHILD_FOX_SCARECROW: 'CommonSimType' = ... - CHILD_FOX_SKELETON: 'CommonSimType' = ... - CHILD_FOX_PLANT_SIM: 'CommonSimType' = ... - CHILD_FOX_WEREWOLF: 'CommonSimType' = ... - - ELDER_HORSE: 'CommonSimType' = ... - ELDER_HORSE_VAMPIRE: 'CommonSimType' = ... - ELDER_HORSE_GHOST: 'CommonSimType' = ... - ELDER_HORSE_ALIEN: 'CommonSimType' = ... - ELDER_HORSE_MERMAID: 'CommonSimType' = ... - ELDER_HORSE_WITCH: 'CommonSimType' = ... - ELDER_HORSE_ROBOT: 'CommonSimType' = ... - ELDER_HORSE_SCARECROW: 'CommonSimType' = ... - ELDER_HORSE_SKELETON: 'CommonSimType' = ... - ELDER_HORSE_PLANT_SIM: 'CommonSimType' = ... - ELDER_HORSE_WEREWOLF: 'CommonSimType' = ... - - ADULT_HORSE: 'CommonSimType' = ... - ADULT_HORSE_VAMPIRE: 'CommonSimType' = ... - ADULT_HORSE_GHOST: 'CommonSimType' = ... - ADULT_HORSE_ALIEN: 'CommonSimType' = ... - ADULT_HORSE_MERMAID: 'CommonSimType' = ... - ADULT_HORSE_WITCH: 'CommonSimType' = ... - ADULT_HORSE_ROBOT: 'CommonSimType' = ... - ADULT_HORSE_SCARECROW: 'CommonSimType' = ... - ADULT_HORSE_SKELETON: 'CommonSimType' = ... - ADULT_HORSE_PLANT_SIM: 'CommonSimType' = ... - ADULT_HORSE_WEREWOLF: 'CommonSimType' = ... - - CHILD_HORSE: 'CommonSimType' = ... - CHILD_HORSE_VAMPIRE: 'CommonSimType' = ... - CHILD_HORSE_GHOST: 'CommonSimType' = ... - CHILD_HORSE_ALIEN: 'CommonSimType' = ... - CHILD_HORSE_MERMAID: 'CommonSimType' = ... - CHILD_HORSE_WITCH: 'CommonSimType' = ... - CHILD_HORSE_ROBOT: 'CommonSimType' = ... - CHILD_HORSE_SCARECROW: 'CommonSimType' = ... - CHILD_HORSE_SKELETON: 'CommonSimType' = ... - CHILD_HORSE_PLANT_SIM: 'CommonSimType' = ... - CHILD_HORSE_WEREWOLF: 'CommonSimType' = ... - - @classmethod - def get_all(cls, include_teen_young_adult_and_elder: bool = False, include_baby: bool = False, include_infant: bool = False, include_separate_child_dog_types: bool = False, exclude_values: Iterator['CommonSimType'] = None) -> Tuple['CommonSimType']: - """get_all(include_teen_young_adult_and_elder=False, include_baby=False, include_infant=False, include_separate_child_dog_types=False, exclude_values=None) - - Retrieve a collection of all Sim Types. - - :param include_teen_young_adult_and_elder: If set to True, the TEEN, YOUNG_ADULT, and ELDER Sim Types will be returned. If False, they will be excluded. Default is False. - :type include_teen_young_adult_and_elder: bool, optional - :param include_baby: If set to True, the BABY Sim Type will be included in the result. If False, the BABY Sim Type will not be included. Default is False. - :type include_baby: bool, optional - :param include_infant: If set to True, the INFANT Sim Type will be included in the result. If False, the INFANT Sim Type will not be included. Default is False. - :type include_infant: bool, optional - :param include_separate_child_dog_types: If set to True, the Child Dog Sim Types (CHILD_LARGE_DOG, CHILD_SMALL_DOG, etc.) will be included in the result. If False, they will not be included. Default is False. - :type include_separate_child_dog_types: bool, optional - :param exclude_values: These values will be excluded. If set to None, NONE will be excluded automatically. Default is None. - :type exclude_values: Iterator[CommonSimType], optional - :return: A collection of all Sim Types. - :rtype: Tuple[CommonSimType] - """ - if exclude_values is None: - exclude_values = (cls.NONE,) - sim_types: Tuple[CommonSimType, ...] = ( - CommonSimType.ADULT_HUMAN, - CommonSimType.ADULT_HUMAN_VAMPIRE, - CommonSimType.ADULT_HUMAN_GHOST, - CommonSimType.ADULT_HUMAN_ALIEN, - CommonSimType.ADULT_HUMAN_MERMAID, - CommonSimType.ADULT_HUMAN_WITCH, - CommonSimType.ADULT_HUMAN_ROBOT, - CommonSimType.ADULT_HUMAN_SCARECROW, - CommonSimType.ADULT_HUMAN_SKELETON, - CommonSimType.ADULT_HUMAN_PLANT_SIM, - CommonSimType.ADULT_HUMAN_WEREWOLF, - - CommonSimType.CHILD_HUMAN, - CommonSimType.CHILD_HUMAN_VAMPIRE, - CommonSimType.CHILD_HUMAN_GHOST, - CommonSimType.CHILD_HUMAN_ALIEN, - CommonSimType.CHILD_HUMAN_MERMAID, - CommonSimType.CHILD_HUMAN_WITCH, - CommonSimType.CHILD_HUMAN_ROBOT, - CommonSimType.CHILD_HUMAN_SCARECROW, - CommonSimType.CHILD_HUMAN_SKELETON, - CommonSimType.CHILD_HUMAN_PLANT_SIM, - CommonSimType.CHILD_HUMAN_WEREWOLF, - - CommonSimType.TODDLER_HUMAN, - CommonSimType.TODDLER_HUMAN_VAMPIRE, - CommonSimType.TODDLER_HUMAN_GHOST, - CommonSimType.TODDLER_HUMAN_ALIEN, - CommonSimType.TODDLER_HUMAN_MERMAID, - CommonSimType.TODDLER_HUMAN_WITCH, - CommonSimType.TODDLER_HUMAN_ROBOT, - CommonSimType.TODDLER_HUMAN_SCARECROW, - CommonSimType.TODDLER_HUMAN_SKELETON, - CommonSimType.TODDLER_HUMAN_PLANT_SIM, - CommonSimType.TODDLER_HUMAN_WEREWOLF, - - CommonSimType.ADULT_SMALL_DOG, - CommonSimType.ADULT_SMALL_DOG_VAMPIRE, - CommonSimType.ADULT_SMALL_DOG_GHOST, - CommonSimType.ADULT_SMALL_DOG_ALIEN, - CommonSimType.ADULT_SMALL_DOG_MERMAID, - CommonSimType.ADULT_SMALL_DOG_WITCH, - CommonSimType.ADULT_SMALL_DOG_ROBOT, - CommonSimType.ADULT_SMALL_DOG_SCARECROW, - CommonSimType.ADULT_SMALL_DOG_SKELETON, - CommonSimType.ADULT_SMALL_DOG_PLANT_SIM, - CommonSimType.ADULT_SMALL_DOG_WEREWOLF, - - CommonSimType.ADULT_LARGE_DOG, - CommonSimType.ADULT_LARGE_DOG_VAMPIRE, - CommonSimType.ADULT_LARGE_DOG_GHOST, - CommonSimType.ADULT_LARGE_DOG_ALIEN, - CommonSimType.ADULT_LARGE_DOG_MERMAID, - CommonSimType.ADULT_LARGE_DOG_WITCH, - CommonSimType.ADULT_LARGE_DOG_ROBOT, - CommonSimType.ADULT_LARGE_DOG_SCARECROW, - CommonSimType.ADULT_LARGE_DOG_SKELETON, - CommonSimType.ADULT_LARGE_DOG_PLANT_SIM, - CommonSimType.ADULT_LARGE_DOG_WEREWOLF, - - CommonSimType.ADULT_CAT, - CommonSimType.ADULT_CAT_VAMPIRE, - CommonSimType.ADULT_CAT_GHOST, - CommonSimType.ADULT_CAT_ALIEN, - CommonSimType.ADULT_CAT_MERMAID, - CommonSimType.ADULT_CAT_WITCH, - CommonSimType.ADULT_CAT_ROBOT, - CommonSimType.ADULT_CAT_SCARECROW, - CommonSimType.ADULT_CAT_SKELETON, - CommonSimType.ADULT_CAT_PLANT_SIM, - CommonSimType.ADULT_CAT_WEREWOLF, - - CommonSimType.CHILD_CAT, - CommonSimType.CHILD_CAT_VAMPIRE, - CommonSimType.CHILD_CAT_GHOST, - CommonSimType.CHILD_CAT_ALIEN, - CommonSimType.CHILD_CAT_MERMAID, - CommonSimType.CHILD_CAT_WITCH, - CommonSimType.CHILD_CAT_ROBOT, - CommonSimType.CHILD_CAT_SCARECROW, - CommonSimType.CHILD_CAT_SKELETON, - CommonSimType.CHILD_CAT_PLANT_SIM, - CommonSimType.CHILD_CAT_WEREWOLF, - - CommonSimType.ADULT_FOX, - CommonSimType.ADULT_FOX_VAMPIRE, - CommonSimType.ADULT_FOX_GHOST, - CommonSimType.ADULT_FOX_ALIEN, - CommonSimType.ADULT_FOX_MERMAID, - CommonSimType.ADULT_FOX_WITCH, - CommonSimType.ADULT_FOX_ROBOT, - CommonSimType.ADULT_FOX_SCARECROW, - CommonSimType.ADULT_FOX_SKELETON, - CommonSimType.ADULT_FOX_PLANT_SIM, - CommonSimType.ADULT_FOX_WEREWOLF, - - CommonSimType.CHILD_FOX, - CommonSimType.CHILD_FOX_VAMPIRE, - CommonSimType.CHILD_FOX_GHOST, - CommonSimType.CHILD_FOX_ALIEN, - CommonSimType.CHILD_FOX_MERMAID, - CommonSimType.CHILD_FOX_WITCH, - CommonSimType.CHILD_FOX_ROBOT, - CommonSimType.CHILD_FOX_SCARECROW, - CommonSimType.CHILD_FOX_SKELETON, - CommonSimType.CHILD_FOX_PLANT_SIM, - CommonSimType.CHILD_FOX_WEREWOLF, - - CommonSimType.CHILD_DOG, - CommonSimType.CHILD_DOG_VAMPIRE, - CommonSimType.CHILD_DOG_GHOST, - CommonSimType.CHILD_DOG_ALIEN, - CommonSimType.CHILD_DOG_MERMAID, - CommonSimType.CHILD_DOG_WITCH, - CommonSimType.CHILD_DOG_ROBOT, - CommonSimType.CHILD_DOG_SCARECROW, - CommonSimType.CHILD_DOG_SKELETON, - CommonSimType.CHILD_DOG_PLANT_SIM, - CommonSimType.CHILD_DOG_WEREWOLF, - - CommonSimType.ADULT_HORSE, - CommonSimType.ADULT_HORSE_VAMPIRE, - CommonSimType.ADULT_HORSE_GHOST, - CommonSimType.ADULT_HORSE_ALIEN, - CommonSimType.ADULT_HORSE_MERMAID, - CommonSimType.ADULT_HORSE_WITCH, - CommonSimType.ADULT_HORSE_ROBOT, - CommonSimType.ADULT_HORSE_SCARECROW, - CommonSimType.ADULT_HORSE_SKELETON, - CommonSimType.ADULT_HORSE_PLANT_SIM, - CommonSimType.ADULT_HORSE_WEREWOLF, - - CommonSimType.CHILD_HORSE, - CommonSimType.CHILD_HORSE_VAMPIRE, - CommonSimType.CHILD_HORSE_GHOST, - CommonSimType.CHILD_HORSE_ALIEN, - CommonSimType.CHILD_HORSE_MERMAID, - CommonSimType.CHILD_HORSE_WITCH, - CommonSimType.CHILD_HORSE_ROBOT, - CommonSimType.CHILD_HORSE_SCARECROW, - CommonSimType.CHILD_HORSE_SKELETON, - CommonSimType.CHILD_HORSE_PLANT_SIM, - CommonSimType.CHILD_HORSE_WEREWOLF, - ) - if include_teen_young_adult_and_elder: - sim_types: Tuple[CommonSimType, ...] = ( - *sim_types, - CommonSimType.ELDER_HUMAN, - CommonSimType.ELDER_HUMAN_VAMPIRE, - CommonSimType.ELDER_HUMAN_GHOST, - CommonSimType.ELDER_HUMAN_ALIEN, - CommonSimType.ELDER_HUMAN_MERMAID, - CommonSimType.ELDER_HUMAN_WITCH, - CommonSimType.ELDER_HUMAN_ROBOT, - CommonSimType.ELDER_HUMAN_SCARECROW, - CommonSimType.ELDER_HUMAN_SKELETON, - CommonSimType.ELDER_HUMAN_PLANT_SIM, - CommonSimType.ELDER_HUMAN_WEREWOLF, - - CommonSimType.YOUNG_ADULT_HUMAN, - CommonSimType.YOUNG_ADULT_HUMAN_VAMPIRE, - CommonSimType.YOUNG_ADULT_HUMAN_GHOST, - CommonSimType.YOUNG_ADULT_HUMAN_ALIEN, - CommonSimType.YOUNG_ADULT_HUMAN_MERMAID, - CommonSimType.YOUNG_ADULT_HUMAN_WITCH, - CommonSimType.YOUNG_ADULT_HUMAN_ROBOT, - CommonSimType.YOUNG_ADULT_HUMAN_SCARECROW, - CommonSimType.YOUNG_ADULT_HUMAN_SKELETON, - CommonSimType.YOUNG_ADULT_HUMAN_PLANT_SIM, - CommonSimType.YOUNG_ADULT_HUMAN_WEREWOLF, - - CommonSimType.TEEN_HUMAN, - CommonSimType.TEEN_HUMAN_VAMPIRE, - CommonSimType.TEEN_HUMAN_GHOST, - CommonSimType.TEEN_HUMAN_ALIEN, - CommonSimType.TEEN_HUMAN_MERMAID, - CommonSimType.TEEN_HUMAN_WITCH, - CommonSimType.TEEN_HUMAN_ROBOT, - CommonSimType.TEEN_HUMAN_SCARECROW, - CommonSimType.TEEN_HUMAN_SKELETON, - CommonSimType.TEEN_HUMAN_PLANT_SIM, - CommonSimType.TEEN_HUMAN_WEREWOLF, - - CommonSimType.ELDER_SMALL_DOG, - CommonSimType.ELDER_SMALL_DOG_VAMPIRE, - CommonSimType.ELDER_SMALL_DOG_GHOST, - CommonSimType.ELDER_SMALL_DOG_ALIEN, - CommonSimType.ELDER_SMALL_DOG_MERMAID, - CommonSimType.ELDER_SMALL_DOG_WITCH, - CommonSimType.ELDER_SMALL_DOG_ROBOT, - CommonSimType.ELDER_SMALL_DOG_SCARECROW, - CommonSimType.ELDER_SMALL_DOG_SKELETON, - CommonSimType.ELDER_SMALL_DOG_PLANT_SIM, - CommonSimType.ELDER_SMALL_DOG_WEREWOLF, - - CommonSimType.ELDER_LARGE_DOG, - CommonSimType.ELDER_LARGE_DOG_VAMPIRE, - CommonSimType.ELDER_LARGE_DOG_GHOST, - CommonSimType.ELDER_LARGE_DOG_ALIEN, - CommonSimType.ELDER_LARGE_DOG_MERMAID, - CommonSimType.ELDER_LARGE_DOG_WITCH, - CommonSimType.ELDER_LARGE_DOG_ROBOT, - CommonSimType.ELDER_LARGE_DOG_SCARECROW, - CommonSimType.ELDER_LARGE_DOG_SKELETON, - CommonSimType.ELDER_LARGE_DOG_PLANT_SIM, - CommonSimType.ELDER_LARGE_DOG_WEREWOLF, - - CommonSimType.ELDER_CAT, - CommonSimType.ELDER_CAT_VAMPIRE, - CommonSimType.ELDER_CAT_GHOST, - CommonSimType.ELDER_CAT_ALIEN, - CommonSimType.ELDER_CAT_MERMAID, - CommonSimType.ELDER_CAT_WITCH, - CommonSimType.ELDER_CAT_ROBOT, - CommonSimType.ELDER_CAT_SCARECROW, - CommonSimType.ELDER_CAT_SKELETON, - CommonSimType.ELDER_CAT_PLANT_SIM, - CommonSimType.ELDER_CAT_WEREWOLF, - - CommonSimType.ELDER_FOX, - CommonSimType.ELDER_FOX_VAMPIRE, - CommonSimType.ELDER_FOX_GHOST, - CommonSimType.ELDER_FOX_ALIEN, - CommonSimType.ELDER_FOX_MERMAID, - CommonSimType.ELDER_FOX_WITCH, - CommonSimType.ELDER_FOX_ROBOT, - CommonSimType.ELDER_FOX_SCARECROW, - CommonSimType.ELDER_FOX_SKELETON, - CommonSimType.ELDER_FOX_PLANT_SIM, - CommonSimType.ELDER_FOX_WEREWOLF, - - CommonSimType.ELDER_HORSE, - CommonSimType.ELDER_HORSE_VAMPIRE, - CommonSimType.ELDER_HORSE_GHOST, - CommonSimType.ELDER_HORSE_ALIEN, - CommonSimType.ELDER_HORSE_MERMAID, - CommonSimType.ELDER_HORSE_WITCH, - CommonSimType.ELDER_HORSE_ROBOT, - CommonSimType.ELDER_HORSE_SCARECROW, - CommonSimType.ELDER_HORSE_SKELETON, - CommonSimType.ELDER_HORSE_PLANT_SIM, - CommonSimType.ELDER_HORSE_WEREWOLF, - ) - if include_baby: - sim_types: Tuple[CommonSimType, ...] = ( - *sim_types, - CommonSimType.BABY_HUMAN, - CommonSimType.BABY_HUMAN_VAMPIRE, - CommonSimType.BABY_HUMAN_GHOST, - CommonSimType.BABY_HUMAN_ALIEN, - CommonSimType.BABY_HUMAN_MERMAID, - CommonSimType.BABY_HUMAN_WITCH, - CommonSimType.BABY_HUMAN_ROBOT, - CommonSimType.BABY_HUMAN_SCARECROW, - CommonSimType.BABY_HUMAN_SKELETON, - CommonSimType.BABY_HUMAN_PLANT_SIM, - CommonSimType.BABY_HUMAN_WEREWOLF, - ) - if include_infant: - sim_types: Tuple[CommonSimType, ...] = ( - *sim_types, - CommonSimType.INFANT_HUMAN, - CommonSimType.INFANT_HUMAN_VAMPIRE, - CommonSimType.INFANT_HUMAN_GHOST, - CommonSimType.INFANT_HUMAN_ALIEN, - CommonSimType.INFANT_HUMAN_MERMAID, - CommonSimType.INFANT_HUMAN_WITCH, - CommonSimType.INFANT_HUMAN_ROBOT, - CommonSimType.INFANT_HUMAN_SCARECROW, - CommonSimType.INFANT_HUMAN_SKELETON, - CommonSimType.INFANT_HUMAN_PLANT_SIM, - CommonSimType.INFANT_HUMAN_WEREWOLF, - ) - if include_separate_child_dog_types: - sim_types: Tuple[CommonSimType, ...] = ( - *sim_types, - CommonSimType.CHILD_SMALL_DOG, - CommonSimType.CHILD_SMALL_DOG_VAMPIRE, - CommonSimType.CHILD_SMALL_DOG_GHOST, - CommonSimType.CHILD_SMALL_DOG_ALIEN, - CommonSimType.CHILD_SMALL_DOG_MERMAID, - CommonSimType.CHILD_SMALL_DOG_WITCH, - CommonSimType.CHILD_SMALL_DOG_ROBOT, - CommonSimType.CHILD_SMALL_DOG_SCARECROW, - CommonSimType.CHILD_SMALL_DOG_SKELETON, - CommonSimType.CHILD_SMALL_DOG_PLANT_SIM, - CommonSimType.CHILD_SMALL_DOG_WEREWOLF, - - CommonSimType.CHILD_LARGE_DOG, - CommonSimType.CHILD_LARGE_DOG_VAMPIRE, - CommonSimType.CHILD_LARGE_DOG_GHOST, - CommonSimType.CHILD_LARGE_DOG_ALIEN, - CommonSimType.CHILD_LARGE_DOG_MERMAID, - CommonSimType.CHILD_LARGE_DOG_WITCH, - CommonSimType.CHILD_LARGE_DOG_ROBOT, - CommonSimType.CHILD_LARGE_DOG_SCARECROW, - CommonSimType.CHILD_LARGE_DOG_SKELETON, - CommonSimType.CHILD_LARGE_DOG_PLANT_SIM, - CommonSimType.CHILD_LARGE_DOG_WEREWOLF, - ) - # noinspection PyTypeChecker - value_list: Tuple[CommonSimType] = tuple([value for value in sim_types if value not in exclude_values]) - return value_list diff --git a/Scripts/s4ap/sims4communitylib/enums/situation_jobs_enum.py b/Scripts/s4ap/sims4communitylib/enums/situation_jobs_enum.py deleted file mode 100644 index 6859772..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/situation_jobs_enum.py +++ /dev/null @@ -1,1083 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonSituationJobId(CommonInt): - """Identifiers for vanilla situation jobs. - - """ - INVALID: 'CommonSituationJobId' = 0 - ACTOR_CAREER_BACKGROUND_ACTOR: 'CommonSituationJobId' = 191066 - ACTOR_CAREER_BACKGROUND_PRODUCER: 'CommonSituationJobId' = 191067 - ACTOR_CAREER_COSTAR1: 'CommonSituationJobId' = 189270 - ACTOR_CAREER_CO_STAR2: 'CommonSituationJobId' = 189271 - ACTOR_CAREER_DIRECTOR_COMMERCIAL: 'CommonSituationJobId' = 197472 - ACTOR_CAREER_DIRECTOR_FILM: 'CommonSituationJobId' = 197475 - ACTOR_CAREER_DIRECTOR_HIGH_BUDGET_TV: 'CommonSituationJobId' = 197474 - ACTOR_CAREER_DIRECTOR_LOW_BUDGET_TV: 'CommonSituationJobId' = 197473 - ACTOR_CAREER_DOLLY_CAMERA_OPERATOR: 'CommonSituationJobId' = 190526 - ACTOR_CAREER_PLAYER: 'CommonSituationJobId' = 189160 - ACTOR_CAREER_SPECIAL_EFFECTS_OPERATOR: 'CommonSituationJobId' = 192113 - ACTOR_CAREER_STATIONARY_CAMERA_OPERATOR: 'CommonSituationJobId' = 191283 - ARTIST_MUSEUM: 'CommonSituationJobId' = 29789 - ART_SOCIETY_BAR_NIGHT_MEET_UP_PARTICIPANT: 'CommonSituationJobId' = 226520 - BARFLY: 'CommonSituationJobId' = 16158 - BARFLY_ALIEN: 'CommonSituationJobId' = 122605 - BARFLY_ALIEN_WORLD: 'CommonSituationJobId' = 114218 - BARFLY_BEAR: 'CommonSituationJobId' = 126606 - BARFLY_CAREER: 'CommonSituationJobId' = 122661 - BARFLY_FEMALE: 'CommonSituationJobId' = 122607 - BARFLY_GHOST: 'CommonSituationJobId' = 122608 - BARFLY_JUNGLE: 'CommonSituationJobId' = 180837 - BARFLY_KARAOKE: 'CommonSituationJobId' = 138046 - BARFLY_KARAOKE_CAREER: 'CommonSituationJobId' = 138047 - BARFLY_KARAOKE_CAREER_HAPPY_HOUR: 'CommonSituationJobId' = 138116 - BARFLY_KARAOKE_PLAYER: 'CommonSituationJobId' = 138193 - BARFLY_KNIGHT: 'CommonSituationJobId' = 129889 - BARFLY_LOUNGE: 'CommonSituationJobId' = 74683 - BARFLY_LOUNGE_ELDER: 'CommonSituationJobId' = 110052 - BARFLY_LOUNGE_PLAYER: 'CommonSituationJobId' = 134421 - BARFLY_MALE: 'CommonSituationJobId' = 122609 - BARFLY_MILITARY: 'CommonSituationJobId' = 204036 - BARFLY_PLAYER: 'CommonSituationJobId' = 126354 - BARFLY_REGULARS: 'CommonSituationJobId' = 122563 - BARFLY_SINGLE: 'CommonSituationJobId' = 122610 - BARFLY_VISITOR: 'CommonSituationJobId' = 122601 - BARTENDER: 'CommonSituationJobId' = 16159 - BARTENDER_ALIEN_WORLD: 'CommonSituationJobId' = 114208 - BARTENDER_BAR: 'CommonSituationJobId' = 16161 - BARTENDER_BAR_MYSHUNO_MEADOWS: 'CommonSituationJobId' = 147048 - BARTENDER_BIRTHDAY_PARTY: 'CommonSituationJobId' = 31638 - BARTENDER_BLACK_AND_WHITE_PARTY: 'CommonSituationJobId' = 35089 - BARTENDER_COSTUME_PARTY: 'CommonSituationJobId' = 35083 - BARTENDER_DINNER_PARTY: 'CommonSituationJobId' = 16154 - BARTENDER_GO_DANCING: 'CommonSituationJobId' = 130591 - BARTENDER_HIRED_NPC: 'CommonSituationJobId' = 123712 - BARTENDER_JUNGLE: 'CommonSituationJobId' = 185004 - BARTENDER_OPEN_STREET: 'CommonSituationJobId' = 153474 - BARTENDER_SINGLES_PARTY: 'CommonSituationJobId' = 16177 - BARTENDER_WEDDING: 'CommonSituationJobId' = 16169 - BAR_LADY: 'CommonSituationJobId' = 16162 - BAR_NIGHT_ART_SOCIETY_PLAYER: 'CommonSituationJobId' = 231031 - BAR_NIGHT_DEBATE_ORG_PLAYER: 'CommonSituationJobId' = 231032 - BAR_NIGHT_HONOR_SOCIETY_PLAYER: 'CommonSituationJobId' = 231033 - BAR_NIGHT_PARTY_PLAYER: 'CommonSituationJobId' = 231034 - BAR_NIGHT_PRANK_PLAYER: 'CommonSituationJobId' = 231035 - BAR_NIGHT_ROBOTICS_PLAYER: 'CommonSituationJobId' = 231036 - BASIC_TRAIT_ECO_PERSONALITY_ECO_MASTER: 'CommonSituationJobId' = 234900 - BASIC_TRAIT_ECO_PERSONALITY_ENTREPRENEUR: 'CommonSituationJobId' = 234899 - BASIC_TRAIT_ECO_PERSONALITY_MAKER: 'CommonSituationJobId' = 234898 - BIRTHDAY_CELEBRANT: 'CommonSituationJobId' = 31925 - BIRTHDAY_CELEBRANT_NPC_INVITER: 'CommonSituationJobId' = 117396 - BUTLER: 'CommonSituationJobId' = 145805 - CAFE_BARISTA: 'CommonSituationJobId' = 122242 - CAFE_BARISTA_HIRED_NPC: 'CommonSituationJobId' = 123734 - CAFE_CUSTOMERS_BUSINESS_CUSTOMER: 'CommonSituationJobId' = 122261 - CAFE_CUSTOMERS_CAFE_FRIEND: 'CommonSituationJobId' = 122262 - CAFE_CUSTOMERS_GENERIC_CUSTOMER: 'CommonSituationJobId' = 122310 - CAFE_CUSTOMERS_MEDIA_ADDICT: 'CommonSituationJobId' = 122240 - CAFE_CUSTOMERS_READER: 'CommonSituationJobId' = 122241 - CAFE_CUSTOMERS_TO_GO_CUSTOMER: 'CommonSituationJobId' = 122260 - CAREER_DETECTIVE_POLICE_STATION_CHIEF: 'CommonSituationJobId' = 116692 - CAREER_DETECTIVE_POLICE_STATION_LAB_TECH: 'CommonSituationJobId' = 115813 - CAREER_DETECTIVE_POLICE_STATION_NPC_DETECTIVE: 'CommonSituationJobId' = 116596 - CAREER_DETECTIVE_POLICE_STATION_RECEPTIONIST: 'CommonSituationJobId' = 114834 - CAREER_DOCTOR_PLAYER: 'CommonSituationJobId' = 110837 - CAREER_SCIENTIST_ALIEN_VISIT_ALIEN: 'CommonSituationJobId' = 113537 - CAREER_SCIENTIST_COWORKER: 'CommonSituationJobId' = 107568 - CAREER_SCIENTIST_COWORKER_FRONT_DESK: 'CommonSituationJobId' = 115833 - CAREER_SCIENTIST_PLAYER: 'CommonSituationJobId' = 107504 - CATERER: 'CommonSituationJobId' = 16163 - CATERER_BIRTHDAY_PARTY: 'CommonSituationJobId' = 31636 - CATERER_BIRTHDAY_PARTY_NPC_INVITE: 'CommonSituationJobId' = 117411 - CATERER_BLACK_AND_WHITE_PARTY: 'CommonSituationJobId' = 35086 - CATERER_COSTUME_PARTY: 'CommonSituationJobId' = 35082 - CATERER_DINNER_PARTY: 'CommonSituationJobId' = 16155 - CATERER_HIRED_NPC: 'CommonSituationJobId' = 123704 - CATERER_SPOOKY_PARTY: 'CommonSituationJobId' = 125425 - CATERER_VEGETARIAN_HIRED_NPC: 'CommonSituationJobId' = 150485 - CATERER_WEDDING: 'CommonSituationJobId' = 16171 - CHEF_FAMILY_MEAL: 'CommonSituationJobId' = 33907 - CHEF_GASTROPUB: 'CommonSituationJobId' = 9223 - CHESS_PLAYER_PARK: 'CommonSituationJobId' = 27468 - CHILD_PLAYING_PARK: 'CommonSituationJobId' = 27504 - CIVIC_INSPECTOR_INSPECTOR: 'CommonSituationJobId' = 233262 - CLUB_GATHERING: 'CommonSituationJobId' = 122316 - CLUB_PARTY_ACTOR_TARGET: 'CommonSituationJobId' = 126458 - CLUB_PARTY_CLUB_MEMBERS: 'CommonSituationJobId' = 126456 - CLUB_PARTY_INVITE_SIM_PICKER: 'CommonSituationJobId' = 126658 - CLUB_PARTY_NPC_INVITE: 'CommonSituationJobId' = 126457 - COLLEGE_ORGANIZATIONS_ROBOTICS_ROBOTICS_EXHIBITION_HUMANOID_BOT: 'CommonSituationJobId' = 223676 - COLLEGE_ORGANIZATIONS_ROBOTICS_ROBOTICS_EXHIBITION_JUDGE: 'CommonSituationJobId' = 223677 - COLLEGE_ORGANIZATIONS_ROBOTICS_ROBOTICS_EXHIBITION_PARTICIPANT: 'CommonSituationJobId' = 223675 - COLLEGE_ORGANIZATIONS_ROBOTICS_ROBOTICS_EXHIBITION_PLAYER: 'CommonSituationJobId' = 223872 - COLLEGE_ORGANIZATIONS_ROBOTICS_ROBOT_BUILDING_SESSION_PARTICIPANT: 'CommonSituationJobId' = 225325 - COLLEGE_ORGANIZATIONS_ROBOTICS_ROBOT_BUILDING_SESSION_PLAYER: 'CommonSituationJobId' = 225324 - COLLEGE_ORGANIZATIONS_SCHOOL_SPIRIT_PARTY_GAME_DAY_PARTY_MEMBER: 'CommonSituationJobId' = 225089 - COLLEGE_ORGANIZATIONS_SCHOOL_SPIRIT_PARTY_GAME_DAY_PARTY_PARTY_GOER: 'CommonSituationJobId' = 225090 - COLLEGE_ORGANIZATIONS_SCHOOL_SPIRIT_PARTY_GAME_DAY_PARTY_PLAYER: 'CommonSituationJobId' = 225052 - COLLEGE_ORGANIZATIONS_SCHOOL_SPIRIT_PARTY_SCHOOL_SPIRIT_DAY_MEMBER: 'CommonSituationJobId' = 208844 - COLLEGE_ORGANIZATIONS_SCHOOL_SPIRIT_PARTY_SCHOOL_SPIRIT_DAY_PLAYER: 'CommonSituationJobId' = 209370 - COLLEGE_ORGANIZATIONS_SCHOOL_SPIRIT_PARTY_SCHOOL_SPIRIT_DAY_STUDENT: 'CommonSituationJobId' = 208843 - COLLEGE_ORGANIZATIONS_SCHOOL_SPIRIT_PRANK_CREATIVITY_CELEBRATION_MASCOT: 'CommonSituationJobId' = 230450 - COLLEGE_ORGANIZATIONS_SCHOOL_SPIRIT_PRANK_CREATIVITY_CELEBRATION_MEMBER: 'CommonSituationJobId' = 223233 - COLLEGE_ORGANIZATIONS_SCHOOL_SPIRIT_PRANK_CREATIVITY_CELEBRATION_PLAYER: 'CommonSituationJobId' = 223231 - COLLEGE_ORGANIZATIONS_SCHOOL_SPIRIT_PRANK_CREATIVITY_CELEBRATION_STUDENT: 'CommonSituationJobId' = 223234 - COLLEGE_ORGANIZATIONS_SCHOOL_SPIRIT_PRANK_GAME_DAY_PARTY_MEMBER: 'CommonSituationJobId' = 223246 - COLLEGE_ORGANIZATIONS_SCHOOL_SPIRIT_PRANK_GAME_DAY_PARTY_PLAYER: 'CommonSituationJobId' = 223324 - COLLEGE_ORGANIZATIONS_SCHOOL_SPIRIT_PRANK_GAME_DAY_PARTY_RIVAL: 'CommonSituationJobId' = 223247 - COLLEGE_ORGANIZATIONS_SECRET_SOCIETY_RITUAL_MEMBER: 'CommonSituationJobId' = 221500 - COLLEGE_ORGANIZATIONS_SECRET_SOCIETY_RITUAL_PLAYER: 'CommonSituationJobId' = 223039 - COLLEGE_ORGANIZATIONS_STUDY_GROUP_MEMBERS: 'CommonSituationJobId' = 209041 - COLLEGE_ORGANIZATIONS_STUDY_GROUP_PLAYER: 'CommonSituationJobId' = 209036 - COLLEGE_ORGANIZATION_SECRET_SOCIETY_JOIN_VISIT: 'CommonSituationJobId' = 222431 - COMMUNITY_CLOSENESS_COMPLAINT: 'CommonSituationJobId' = 233537 - COMMUNITY_CLOSENESS_HANDY_NEIGHBOR: 'CommonSituationJobId' = 233540 - COMMUNITY_CLOSENESS_INTRO_TO_CIVIC_POLICIES_ECO_MASTER: 'CommonSituationJobId' = 238069 - COMMUNITY_CLOSENESS_INTRO_TO_CIVIC_POLICIES_ENTREPRENEUR: 'CommonSituationJobId' = 238070 - COMMUNITY_CLOSENESS_RANDOM_GIFT: 'CommonSituationJobId' = 233539 - COMMUNITY_CLOSENESS_SPARE_RECYCLING: 'CommonSituationJobId' = 233542 - COMMUNITY_CLOSENESS_TRASH_HELP: 'CommonSituationJobId' = 233541 - COWORKER_PROMOTION_PARTY: 'CommonSituationJobId' = 125926 - COWORKER_PROMOTION_PARTY_ACTOR_TARGET: 'CommonSituationJobId' = 125928 - COWORKER_PROMOTION_PARTY_INVITE_SIM_PICKER: 'CommonSituationJobId' = 126659 - COWORKER_PROMOTION_PARTY_NPC_INVITE: 'CommonSituationJobId' = 126278 - DATE_ACTOR: 'CommonSituationJobId' = 34258 - DATE_ACTOR_TARGET: 'CommonSituationJobId' = 117124 - DATE_ACTOR_TEEN: 'CommonSituationJobId' = 99351 - DATE_NPC_INVITER: 'CommonSituationJobId' = 117102 - DATE_TARGET: 'CommonSituationJobId' = 34256 - DATE_TARGET_TEEN: 'CommonSituationJobId' = 99352 - DEBATE_BAR_NIGHT_MEET_UP_PARTICIPANT: 'CommonSituationJobId' = 222257 - DEBATE_DEBATER: 'CommonSituationJobId' = 222727 - DEBUG_BARTENDER_JOB: 'CommonSituationJobId' = 16150 - DEBUG_CATERER_JOB: 'CommonSituationJobId' = 16151 - DEBUG_GUEST_JOB: 'CommonSituationJobId' = 16152 - DEBUG_HOST_JOB: 'CommonSituationJobId' = 16153 - DEBUG_MULTI_GUEST_JOB: 'CommonSituationJobId' = 26109 - DEBUG_SOAK_GUEST_JOB: 'CommonSituationJobId' = 101359 - DYNAMIC_OBJECT_BOARD_DEBATER: 'CommonSituationJobId' = 224289 - DYNAMIC_OBJECT_TRASH_DIVER: 'CommonSituationJobId' = 224216 - ECO_INSPECTOR_INSPECTOR: 'CommonSituationJobId' = 232057 - ECO_PERSONALITY_ECO_MASTER: 'CommonSituationJobId' = 235532 - ECO_PERSONALITY_ECO_MASTER_WALK_BY: 'CommonSituationJobId' = 241203 - ECO_PERSONALITY_ENTREPRENEUR: 'CommonSituationJobId' = 235534 - ECO_PERSONALITY_ENTREPRENEUR_WALK_BY: 'CommonSituationJobId' = 241202 - ECO_PERSONALITY_MAKER: 'CommonSituationJobId' = 235533 - ECO_PERSONALITY_MAKER_WALK_BY: 'CommonSituationJobId' = 241201 - ENTERTAINER_BIRTHDAY_PARTY: 'CommonSituationJobId' = 32407 - ENTERTAINER_BLACK_AND_WHITE_PARTY: 'CommonSituationJobId' = 35087 - ENTERTAINER_GUITAR_AT_HOME: 'CommonSituationJobId' = 123625 - ENTERTAINER_LOUNGE: 'CommonSituationJobId' = 40134 - ENTERTAINER_MIC_COMEDY_AT_HOME: 'CommonSituationJobId' = 123691 - ENTERTAINER_MIC_COMEDY_AT_HOME_LAMPOON: 'CommonSituationJobId' = 202118 - ENTERTAINER_MIC_COMEDY_AT_HOME_NPC_HIRED: 'CommonSituationJobId' = 202446 - ENTERTAINER_MIC_COMEDY_HIRE_FROM_MICROPHONE: 'CommonSituationJobId' = 202692 - ENTERTAINER_ORGAN_AT_HOME: 'CommonSituationJobId' = 155974 - ENTERTAINER_PIANO_AT_HOME: 'CommonSituationJobId' = 123592 - ENTERTAINER_VIOLIN_AT_HOME: 'CommonSituationJobId' = 123681 - ENTERTAINER_WEDDING: 'CommonSituationJobId' = 99098 - EVENT_NPC_CALL_OVER: 'CommonSituationJobId' = 149783 - EVENT_NPC_CALL_OVER_MBB: 'CommonSituationJobId' = 198849 - EXERCISE_GYM: 'CommonSituationJobId' = 16165 - E_SPORTS_TEAMMATE: 'CommonSituationJobId' = 227362 - E_SPORTS_TEAMMATE_ARTS: 'CommonSituationJobId' = 229681 - FAN_STAN_CELEBRITY_SIM: 'CommonSituationJobId' = 193805 - FAN_STAN_FAN: 'CommonSituationJobId' = 194429 - FAN_STAN_FAN_CHILD: 'CommonSituationJobId' = 201698 - FAN_STAN_FAN_TEEN: 'CommonSituationJobId' = 202007 - FAN_STAN_STAN: 'CommonSituationJobId' = 194426 - FASHION_SUBJECT: 'CommonSituationJobId' = 215289 - FESTIVAL_BLOSSOM_ARTIST: 'CommonSituationJobId' = 136083 - FESTIVAL_BLOSSOM_BARTENDER: 'CommonSituationJobId' = 140533 - FESTIVAL_BLOSSOM_CRAFT_SALES_TABLE_VENDOR_PAINTING: 'CommonSituationJobId' = 153678 - FESTIVAL_BLOSSOM_CRAZY_TEEN: 'CommonSituationJobId' = 135707 - FESTIVAL_BLOSSOM_ENTERTAINER: 'CommonSituationJobId' = 140536 - FESTIVAL_BLOSSOM_GENERAL: 'CommonSituationJobId' = 140495 - FESTIVAL_BLOSSOM_LOVE_GURU: 'CommonSituationJobId' = 146779 - FESTIVAL_BLOSSOM_MARKET_STALLS_VENDOR: 'CommonSituationJobId' = 140503 - FESTIVAL_BLOSSOM_PETAL_HEAD: 'CommonSituationJobId' = 135706 - FESTIVAL_BLOSSOM_ROMANTIC_COUPLE: 'CommonSituationJobId' = 146787 - FESTIVAL_BLOSSOM_SLEAZE: 'CommonSituationJobId' = 136243 - FESTIVAL_FLEA_MARKET_CRAFT_SALES_TABLE_VENDOR: 'CommonSituationJobId' = 146841 - FESTIVAL_FLEA_MARKET_CRAFT_SALES_TABLE_VENDOR_PAINTING: 'CommonSituationJobId' = 153687 - FESTIVAL_FLEA_MARKET_ENTERTAINER: 'CommonSituationJobId' = 142723 - FESTIVAL_FLEA_MARKET_GENERAL: 'CommonSituationJobId' = 140497 - FESTIVAL_FLEA_MARKET_HAGGLER: 'CommonSituationJobId' = 142229 - FESTIVAL_FLEA_MARKET_MARKET_STALLS_VENDOR: 'CommonSituationJobId' = 140528 - FESTIVAL_FLEA_MARKET_VENDOR: 'CommonSituationJobId' = 139947 - FESTIVAL_FOOD_BARTENDER: 'CommonSituationJobId' = 140534 - FESTIVAL_FOOD_ENTERTAINER: 'CommonSituationJobId' = 140546 - FESTIVAL_FOOD_GENERAL: 'CommonSituationJobId' = 140498 - FESTIVAL_FOOD_GRILL_MASTER: 'CommonSituationJobId' = 140103 - FESTIVAL_FOOD_MARKET_STALLS_VENDOR: 'CommonSituationJobId' = 140529 - FESTIVAL_FOOD_OVER_EATER: 'CommonSituationJobId' = 136419 - FESTIVAL_GARDENER: 'CommonSituationJobId' = 139636 - FESTIVAL_LAMP_BARTENDER: 'CommonSituationJobId' = 140535 - FESTIVAL_LAMP_DARK_CONTESTANT: 'CommonSituationJobId' = 146833 - FESTIVAL_LAMP_DARK_SIDER: 'CommonSituationJobId' = 143377 - FESTIVAL_LAMP_ENTERTAINER: 'CommonSituationJobId' = 140547 - FESTIVAL_LAMP_GENERAL: 'CommonSituationJobId' = 140500 - FESTIVAL_LAMP_LIGHT_CONTESTANT: 'CommonSituationJobId' = 146834 - FESTIVAL_LAMP_MARKET_STALLS_VENDOR: 'CommonSituationJobId' = 140531 - FESTIVAL_LIGHT_DARK_SIDERS: 'CommonSituationJobId' = 134836 - FESTIVAL_LOGIC_FAIR_COSPLAYER: 'CommonSituationJobId' = 137227 - FESTIVAL_LOGIC_FAIR_GAMERS: 'CommonSituationJobId' = 140932 - FESTIVAL_LOGIC_FAIR_GENERAL: 'CommonSituationJobId' = 140501 - FESTIVAL_LOGIC_FAIR_HACKERS: 'CommonSituationJobId' = 141163 - FESTIVAL_LOGIC_FAIR_MARKET_STALLS_VENDOR: 'CommonSituationJobId' = 140532 - FESTIVAL_LOGIC_FAIR_ROCKET_SHIP_WOOHOOERS: 'CommonSituationJobId' = 142734 - # Also known as UGT: 'CommonSituationJobId' = Ultimate Gaming Test - FESTIVAL_LOGIC_FAIR_ULTIMATE_GAMING_TESTERS: 'CommonSituationJobId' = 141303 - FESTIVAL_PLAYER_SIM: 'CommonSituationJobId' = 140377 - FIRE: 'CommonSituationJobId' = 73823 - FIRE_BRIGADE_VOLUNTEER: 'CommonSituationJobId' = 208733 - FREELANCER_FASHION_PHOTOGRAPHER: 'CommonSituationJobId' = 216224 - FREELANCER_FASHION_PHOTOGRAPHER_STYLE_INFLUENCER: 'CommonSituationJobId' = 216220 - GARDENER_SERVICE: 'CommonSituationJobId' = 130543 - GENERIC: 'CommonSituationJobId' = 99709 - GENERIC_ANY_SPECIES: 'CommonSituationJobId' = 168875 - GENERIC_NO_CHURN: 'CommonSituationJobId' = 101227 - GHOST: 'CommonSituationJobId' = 101847 - GHOST_HAUNTED_APARTMENT: 'CommonSituationJobId' = 139825 - GHOST_PETS: 'CommonSituationJobId' = 165594 - GO_FOR_WALK_DOG: 'CommonSituationJobId' = 165052 - GO_FOR_WALK_SIM: 'CommonSituationJobId' = 165051 - GREETED_NPC_VISING_NPC: 'CommonSituationJobId' = 34419 - GREETED_PLAYER_VISITING_NPC: 'CommonSituationJobId' = 34420 - GREETED_RUDE_ALIEN: 'CommonSituationJobId' = 108084 - GREETED_TUTORIAL_HOUSEMATE: 'CommonSituationJobId' = 198048 - GRILL_MASTER_WEENIE_ROAST: 'CommonSituationJobId' = 103692 - GRIM_REAPER: 'CommonSituationJobId' = 16180 - GUEST_BIRTHDAY_PARTY: 'CommonSituationJobId' = 31633 - GUEST_BIRTHDAY_PARTY_ACTOR_TARGET: 'CommonSituationJobId' = 117383 - GUEST_BIRTHDAY_PARTY_NPC_INVITE: 'CommonSituationJobId' = 117544 - GUEST_BIRTHDAY_PARTY_NPC_INVITE_SIM_PICKER: 'CommonSituationJobId' = 117841 - GUEST_BLACK_AND_WHITE_PARTY: 'CommonSituationJobId' = 35084 - GUEST_CHARITY_BENEFIT_PARTY: 'CommonSituationJobId' = 200793 - GUEST_COSTUME_PARTY: 'CommonSituationJobId' = 35080 - GUEST_EATER_FAMILY_MEAL: 'CommonSituationJobId' = 33909 - GUEST_GUEST_OF_HONOR: 'CommonSituationJobId' = 197863 - GUEST_LAMPOON_PARTY: 'CommonSituationJobId' = 201956 - GUEST_PARTY: 'CommonSituationJobId' = 16167 - GUEST_SPOOKY_PARTY: 'CommonSituationJobId' = 125415 - GUEST_WEDDING: 'CommonSituationJobId' = 16173 - GUEST_WEENIE_ROAST: 'CommonSituationJobId' = 103719 - HAIR_MAKE_UP_CHAIR_STYLIST: 'CommonSituationJobId' = 189486 - HOLIDAY_TRADITION_FATHER_WINTER: 'CommonSituationJobId' = 181420 - HOLIDAY_TRADITION_FLOWER_BUNNY: 'CommonSituationJobId' = 186903 - HOLIDAY_TRADITION_TRICK_OR_TREAT: 'CommonSituationJobId' = 187508 - HOLIDAY_TRADITION_WALK_BYS_GHOSTS: 'CommonSituationJobId' = 187133 - HOLIDAY_TRADITION_WALK_BYS_NUDISTS: 'CommonSituationJobId' = 190699 - HOLIDAY_TRADITION_WALK_BYS_TRICK_OR_TREAT: 'CommonSituationJobId' = 188034 - HOLIDAY_TRADITION_WALK_BY_FESTIVE_OUTFITS: 'CommonSituationJobId' = 182163 - HOLIDAY_TRADITION_WALK_BY_FORMAL_OUTFITS: 'CommonSituationJobId' = 182178 - HONOR_SOCIETY_BAR_NIGHT_MEET_UP_PARTICIPANT: 'CommonSituationJobId' = 229024 - HOSPITAL_PATIENT_1: 'CommonSituationJobId' = 108631 - HOSPITAL_PATIENT_ADMITTED: 'CommonSituationJobId' = 113608 - HOSPITAL_PATIENT_ADMITTED_CHILDREN: 'CommonSituationJobId' = 115599 - HOSPITAL_PATIENT_ADMITTED_ELDER: 'CommonSituationJobId' = 115989 - HOSPITAL_PATIENT_ADMITTED_T_YA: 'CommonSituationJobId' = 115990 - HOSPITAL_PATIENT_AWAY_EVENT_TRIGGER: 'CommonSituationJobId' = 114202 - HOSPITAL_PATIENT_LOW_LEVEL_ALL: 'CommonSituationJobId' = 116215 - HOSPITAL_PATIENT_PLAYER_BABY_LABOR: 'CommonSituationJobId' = 112164 - HOST_BLACK_AND_WHITE_PARTY: 'CommonSituationJobId' = 35085 - HOST_COSTUME_PARTY: 'CommonSituationJobId' = 35081 - HOST_SPOOKY_PARTY: 'CommonSituationJobId' = 125420 - HOST_WEENIE_ROAST: 'CommonSituationJobId' = 103721 - HOUSEHOLD_EATER_FAMILY_MEAL: 'CommonSituationJobId' = 33908 - INVITED_OVER: 'CommonSituationJobId' = 40350 - INVITED_SUMMONED_GHOST: 'CommonSituationJobId' = 108709 - INVITE_TO: 'CommonSituationJobId' = 40715 - INVITE_TO_MAGIC_PORTAL: 'CommonSituationJobId' = 222422 - ISLANDER_CULTURE_ACTOR: 'CommonSituationJobId' = 208466 - ISLANDER_CULTURE_DOOR_KNOCKER: 'CommonSituationJobId' = 208465 - ISLANDER_CULTURE_DOOR_KNOCKER_EXTRA_FOOD: 'CommonSituationJobId' = 209456 - ISLANDER_CULTURE_FOOD_BEARER: 'CommonSituationJobId' = 208464 - ISLANDER_CULTURE_NEED_SOMETHING_FIXED_REPAIRMAN: 'CommonSituationJobId' = 208712 - ISLANDER_CULTURE_NEIGHBOR: 'CommonSituationJobId' = 208467 - ISLAND_ANCESTORS_VISIT_ISLAND_ELEMENTAL: 'CommonSituationJobId' = 210214 - ISLAND_CONSERVATION_ANTI_ENVIRONMENTALIST: 'CommonSituationJobId' = 208860 - ISLAND_CONSERVATION_CONSERVATIONIST: 'CommonSituationJobId' = 211665 - ISLAND_CONSERVATION_LITTERING_SIM: 'CommonSituationJobId' = 208859 - ISLAND_CONSERVATION_POACHING_SIM: 'CommonSituationJobId' = 208858 - ISLAND_EVENTS_BEACH_BONFIRE_TOWN_LOCAL: 'CommonSituationJobId' = 205612 - ISLAND_EVENTS_FAMILY_FUN_DAY_LOCAL_KID: 'CommonSituationJobId' = 205615 - ISLAND_EVENTS_FAMILY_FUN_DAY_LOCAL_PARENT: 'CommonSituationJobId' = 205616 - ISLAND_EVENTS_FAMILY_FUN_DAY_VENDOR: 'CommonSituationJobId' = 205614 - ISLAND_EVENTS_FISHING_COMPETITION_CONTESTANT: 'CommonSituationJobId' = 204668 - ISLAND_EVENTS_FISHING_COMPETITION_HOST: 'CommonSituationJobId' = 204677 - ISLAND_EVENTS_FLOWERS_AND_MUSIC_MUSICIAN: 'CommonSituationJobId' = 205618 - ISLAND_EVENTS_FLOWERS_AND_MUSIC_TOWN_LOCAL: 'CommonSituationJobId' = 205617 - ISLAND_EVENTS_ISLAND_CELEBRATION_PAINTER_FIRE_DANCER: 'CommonSituationJobId' = 204999 - ISLAND_EVENTS_ISLAND_CELEBRATION_SAND_ARTIST_MUSICIAN: 'CommonSituationJobId' = 205645 - ISLAND_EVENTS_ISLAND_CELEBRATION_STALL_VENDOR: 'CommonSituationJobId' = 205644 - ISLAND_EVENTS_ISLAND_CELEBRATION_TABLE_VENDOR: 'CommonSituationJobId' = 205643 - ISLAND_EVENTS_ISLAND_CELEBRATION_TOWN_LOCAL: 'CommonSituationJobId' = 205646 - ISLAND_EVENTS_POTLUCK_TOWN_LOCAL: 'CommonSituationJobId' = 204560 - ISLAND_EVENTS_TOWN_BBQ_ISLAND_COOK: 'CommonSituationJobId' = 205634 - ISLAND_EVENTS_TOWN_BBQ_TOWN_LOCAL: 'CommonSituationJobId' = 205633 - ISLAND_EVENTS_TURTLE_HATCHING_CONSERVATIONIST: 'CommonSituationJobId' = 205490 - ISLAND_EVENTS_TURTLE_HATCHING_FANATIC: 'CommonSituationJobId' = 205488 - ISLAND_EVENTS_TURTLE_HATCHING_LOCALS: 'CommonSituationJobId' = 205489 - ISLAND_SPIRITS_VISIT_EMPTY: 'CommonSituationJobId' = 211703 - KARAOKE_CONTESTANT: 'CommonSituationJobId' = 138152 - KARAOKE_CONTESTANT_SCORED: 'CommonSituationJobId' = 153657 - KARAOKE_DUET: 'CommonSituationJobId' = 140815 - KARAOKE_SINGLE: 'CommonSituationJobId' = 138189 - KAVA_PARTY_GUEST: 'CommonSituationJobId' = 206387 - KAVA_PARTY_HOST: 'CommonSituationJobId' = 206388 - KAVA_PARTY_ISLAND_GUEST: 'CommonSituationJobId' = 206390 - LIBRARIAN: 'CommonSituationJobId' = 40082 - LIBRARY_READER_PLAYER: 'CommonSituationJobId' = 134429 - LIBRARY_STRANGER_VILLE_CONSPIRACIST: 'CommonSituationJobId' = 204087 - LIBRARY_STRANGER_VILLE_SCIENTIST: 'CommonSituationJobId' = 204079 - LOUNGE_EVENT_AWARD_ATTENDEE: 'CommonSituationJobId' = 192672 - LOUNGE_EVENT_AWARD_HOST: 'CommonSituationJobId' = 192673 - LOUNGE_EVENT_MEET_A_CELEBRITY: 'CommonSituationJobId' = 192670 - LOUNGE_EVENT_OPEN_MIC: 'CommonSituationJobId' = 192671 - LOUNGE_EVENT_OPEN_MIC_CONTESTANT_PLAYER: 'CommonSituationJobId' = 195978 - LOUNGE_EVENT_PLAYER_CONTROLLER: 'CommonSituationJobId' = 195977 - MAGIC_HQ_PLAYER: 'CommonSituationJobId' = 223444 - MAGIC_SAGE_MISCHIEF: 'CommonSituationJobId' = 212837 - MAGIC_SAGE_PRACTICAL: 'CommonSituationJobId' = 212838 - MAGIC_SAGE_UNTAMED: 'CommonSituationJobId' = 212839 - MAGIC_VENUE_NPC_INTERMEDIATE: 'CommonSituationJobId' = 213056 - MAGIC_VENUE_NPC_NOVICE: 'CommonSituationJobId' = 212936 - MAID: 'CommonSituationJobId' = 16174 - MAID_UNIVERSITY_HOUSING: 'CommonSituationJobId' = 221343 - MAILMAN: 'CommonSituationJobId' = 16175 - MARKET_STALLS_CUSTOMER_MAGIC: 'CommonSituationJobId' = 217683 - MARKET_STALLS_VENDOR_CAFETERIA_STATION: 'CommonSituationJobId' = 220130 - MARKET_STALLS_VENDOR_CAFETERIA_STATION_HIRED_NPC: 'CommonSituationJobId' = 217900 - MARKET_STALLS_VENDOR_COFFEE_CART: 'CommonSituationJobId' = 225987 - MARKET_STALLS_VENDOR_COFFEE_CART_HIRED_NPC: 'CommonSituationJobId' = 226531 - MARKET_STALLS_VENDOR_ISLAND_WORLD: 'CommonSituationJobId' = 215327 - MARKET_STALLS_VENDOR_MAGIC: 'CommonSituationJobId' = 216970 - MARKET_STALLS_VENDOR_MAGIC_HIRED_NPC_BROOM: 'CommonSituationJobId' = 217645 - MARKET_STALLS_VENDOR_MAGIC_HIRED_NPC_POTION: 'CommonSituationJobId' = 217839 - MARKET_STALLS_VENDOR_MAGIC_HIRED_NPC_WAND: 'CommonSituationJobId' = 217840 - MARKET_STALLS_VENDOR_MAGIC_POTION: 'CommonSituationJobId' = 217866 - MARKET_STALLS_VENDOR_MAGIC_WAND: 'CommonSituationJobId' = 217867 - MARKET_STALLS_VENDOR_ROBOTICS_EXHIBITION: 'CommonSituationJobId' = 230069 - MASSAGE_THERAPIST_SERVICE: 'CommonSituationJobId' = 118593 - MEDITATION_TELEPORT_TO: 'CommonSituationJobId' = 119810 - MENTOR_LIBRARY_MUSEUM: 'CommonSituationJobId' = 27651 - MOTHER_PLANT_BATTLE_HELPERS_1: 'CommonSituationJobId' = 203318 - MOTHER_PLANT_BATTLE_HELPERS_2: 'CommonSituationJobId' = 203319 - MOTHER_PLANT_BATTLE_HELPERS_3: 'CommonSituationJobId' = 203320 - MOTHER_PLANT_BATTLE_OTHER_PLAYERS: 'CommonSituationJobId' = 203322 - MOTHER_PLANT_BATTLE_PRIMARY_PLAYER: 'CommonSituationJobId' = 203321 - MOTHER_PLANT_BATTLE_RUN_AWAY: 'CommonSituationJobId' = 207317 - MOTHER_PLANT_BATTLE_ZOMBIE: 'CommonSituationJobId' = 203330 - NANNY: 'CommonSituationJobId' = 141842 - NATURAL_POOL_SWIMMER: 'CommonSituationJobId' = 175205 - NIGHT_STALKER: 'CommonSituationJobId' = 216315 - NIGHT_STALKER_TARGET: 'CommonSituationJobId' = 216402 - NPC_INVITES_ANGRY_TEXT_ACTOR_TARGET: 'CommonSituationJobId' = 127301 - NPC_INVITES_ANGRY_TEXT_INVITE_SIM_PICKER: 'CommonSituationJobId' = 127302 - NPC_INVITES_ANGRY_TEXT_NPC_INVITE: 'CommonSituationJobId' = 127303 - NPC_INVITES_BAR_ACTOR_TARGET: 'CommonSituationJobId' = 127377 - NPC_INVITES_BAR_INVITE_SIM_PICKER: 'CommonSituationJobId' = 127378 - NPC_INVITES_BAR_NPC_INVITE: 'CommonSituationJobId' = 127379 - NPC_INVITES_FLIRTY_TEXT_ACTOR_TARGET: 'CommonSituationJobId' = 127281 - NPC_INVITES_FLIRTY_TEXT_INVITE_SIM_PICKER: 'CommonSituationJobId' = 127282 - NPC_INVITES_FLIRTY_TEXT_NPC_INVITE: 'CommonSituationJobId' = 127283 - NPC_INVITES_GYM_ACTOR_TARGET: 'CommonSituationJobId' = 127225 - NPC_INVITES_GYM_INVITE_SIM_PICKER: 'CommonSituationJobId' = 127227 - NPC_INVITES_GYM_NPC_INVITE: 'CommonSituationJobId' = 127226 - NPC_INVITES_HAPPY_ACTOR_TARGET: 'CommonSituationJobId' = 127246 - NPC_INVITES_HAPPY_TEXT_INVITE_SIM_PICKER: 'CommonSituationJobId' = 127247 - NPC_INVITES_HAPPY_TEXT_NPC_INVITE: 'CommonSituationJobId' = 127248 - NPC_INVITES_INVITE_OVER_ACTOR_TARGET: 'CommonSituationJobId' = 128964 - NPC_INVITES_INVITE_OVER_INVITE_SIM_PICKER: 'CommonSituationJobId' = 128965 - NPC_INVITES_INVITE_OVER_NPC_INVITE: 'CommonSituationJobId' = 128966 - NPC_INVITES_MAGIC_DUEL_CHALLENGE_CHALLENGED: 'CommonSituationJobId' = 218374 - NPC_INVITES_MAGIC_DUEL_CHALLENGE_CHALLENGER: 'CommonSituationJobId' = 218469 - NPC_INVITES_PLAYFUL_TEXT_ACTOR_TARGET: 'CommonSituationJobId' = 127271 - NPC_INVITES_PLAYFUL_TEXT_INVITE_SIM_PICKER: 'CommonSituationJobId' = 127270 - NPC_INVITES_PLAYFUL_TEXT_NPC_INVITE: 'CommonSituationJobId' = 127272 - NPC_INVITES_RECOMMEND_LOCAL_HANGOUT_BAR_ACTOR_TARGET: 'CommonSituationJobId' = 137953 - NPC_INVITES_RECOMMEND_LOCAL_HANGOUT_BAR_INVITE_SIM_PICKER: 'CommonSituationJobId' = 137954 - NPC_INVITES_RECOMMEND_LOCAL_HANGOUT_BAR_NPC_INVITE: 'CommonSituationJobId' = 137955 - NPC_INVITES_RECOMMEND_RESTAURANT_ACTOR_TARGET: 'CommonSituationJobId' = 140078 - NPC_INVITES_RECOMMEND_RESTAURANT_INVITE_SIM_PICKER: 'CommonSituationJobId' = 140079 - NPC_INVITES_RECOMMEND_RESTAURANT_NPC_INVITE: 'CommonSituationJobId' = 140080 - NPC_INVITES_RESTAURANT_ACTOR_TARGET: 'CommonSituationJobId' = 131937 - NPC_INVITES_RESTAURANT_INVITE_SIM_PICKER: 'CommonSituationJobId' = 131938 - NPC_INVITES_RESTAURANT_NPC_INVITE: 'CommonSituationJobId' = 131939 - NPC_SPA_GUEST_ANNOYING: 'CommonSituationJobId' = 118873 - NPC_SPA_GUEST_BULL_IN_CHINA_SHOP: 'CommonSituationJobId' = 118872 - NPC_SPA_GUEST_NORMAL: 'CommonSituationJobId' = 118874 - NPC_SPA_GUEST_NORMAL_COUPLE: 'CommonSituationJobId' = 119687 - NPC_SPA_GUEST_PRANKSTER: 'CommonSituationJobId' = 118875 - NPC_SPA_GUEST_SNOB: 'CommonSituationJobId' = 118876 - OBJECT_FASHION_STUDIO_TRIPOD_PHOTOGRAPHER: 'CommonSituationJobId' = 216822 - OBJECT_FASHION_STUDIO_TRIPOD_SUBJECT: 'CommonSituationJobId' = 216823 - OBJECT_FASHION_STUDIO_TRIPOD_SUBJECT_2: 'CommonSituationJobId' = 217664 - OBJECT_FASHION_STUDIO_TRIPOD_SUBJECT_3: 'CommonSituationJobId' = 217665 - OBJECT_FASHION_STUDIO_TRIPOD_SUBJECT_CARRY: 'CommonSituationJobId' = 217895 - OPEN_STREETS_ALIEN: 'CommonSituationJobId' = 113917 - OPEN_STREETS_BBQ: 'CommonSituationJobId' = 38902 - OPEN_STREETS_BONFIRE: 'CommonSituationJobId' = 126403 - OPEN_STREETS_CAMPING_FOREST_CAMPFIRE: 'CommonSituationJobId' = 107878 - OPEN_STREETS_CAMPING_FOREST_FISHERMAN: 'CommonSituationJobId' = 106104 - OPEN_STREETS_CAMPING_FOREST_FOREST_GHOST: 'CommonSituationJobId' = 108332 - OPEN_STREETS_CAMPING_FOREST_FOREST_RANGER: 'CommonSituationJobId' = 108823 - OPEN_STREETS_CAMPING_FOREST_RANGER_STATION: 'CommonSituationJobId' = 106107 - OPEN_STREETS_CAMPING_FOREST_RESTROOM: 'CommonSituationJobId' = 106106 - OPEN_STREETS_CAMPING_FOREST_RESTROOM_SHOWER: 'CommonSituationJobId' = 110034 - OPEN_STREETS_CHALET_GARDENS_FAMILY_TOURIST2: 'CommonSituationJobId' = 126379 - OPEN_STREETS_CHALET_GARDENS_FAMILY_TOURIST: 'CommonSituationJobId' = 126351 - OPEN_STREETS_CHALET_GARDENS_FLIRTY_TOURIST2: 'CommonSituationJobId' = 126390 - OPEN_STREETS_CHALET_GARDENS_FLIRTY_TOURIST: 'CommonSituationJobId' = 126389 - OPEN_STREETS_CHALET_GARDENS_GENERIC_TOURIST2: 'CommonSituationJobId' = 126353 - OPEN_STREETS_CHALET_GARDENS_GENERIC_TOURIST: 'CommonSituationJobId' = 126238 - OPEN_STREETS_CHALET_GARDENS_GHOST_GARDENER: 'CommonSituationJobId' = 125473 - OPEN_STREETS_CHALET_GARDENS_GHOST_PAINTER: 'CommonSituationJobId' = 125472 - OPEN_STREETS_CHALET_GARDENS_LONELY_TOURIST: 'CommonSituationJobId' = 126243 - OPEN_STREETS_CHESS: 'CommonSituationJobId' = 38487 - OPEN_STREETS_CITY_LIFE_BASKET_BALLER: 'CommonSituationJobId' = 149957 - OPEN_STREETS_CITY_LIFE_CITY_REPAIR: 'CommonSituationJobId' = 144296 - OPEN_STREETS_CITY_LIFE_LIVING_STATUE_BUSKER: 'CommonSituationJobId' = 134262 - OPEN_STREETS_CITY_LIFE_MURAL_PAINTER: 'CommonSituationJobId' = 149971 - OPEN_STREETS_CITY_LIFE_MYSHUNO_MEADOWS_GENERIC_TOURIST: 'CommonSituationJobId' = 138477 - OPEN_STREETS_CITY_LIFE_TOURIST: 'CommonSituationJobId' = 134261 - OPEN_STREETS_CITY_LIFE_WEIRDO: 'CommonSituationJobId' = 134263 - OPEN_STREETS_CITY_LIFE_WEIRDO_BATHROBE_ELDER: 'CommonSituationJobId' = 145027 - OPEN_STREETS_CITY_LIFE_WEIRDO_RACCOON: 'CommonSituationJobId' = 145029 - OPEN_STREETS_CITY_LIFE_WEIRDO_TOWELS: 'CommonSituationJobId' = 145030 - OPEN_STREETS_EUROPE_BRAWL: 'CommonSituationJobId' = 122808 - OPEN_STREETS_EUROPE_TOURIST: 'CommonSituationJobId' = 122809 - OPEN_STREETS_EVENT_NPC_CHALLENGE: 'CommonSituationJobId' = 133758 - OPEN_STREETS_FAME_WORLD_CELEBRITY: 'CommonSituationJobId' = 197062 - OPEN_STREETS_FAME_WORLD_TOURIST: 'CommonSituationJobId' = 197053 - OPEN_STREETS_FISHER: 'CommonSituationJobId' = 77049 - OPEN_STREETS_FISHER_LOCAL: 'CommonSituationJobId' = 127055 - OPEN_STREETS_GARDEN: 'CommonSituationJobId' = 38936 - OPEN_STREETS_GRILL_GROUP: 'CommonSituationJobId' = 126543 - OPEN_STREETS_ISLAND_FISHER: 'CommonSituationJobId' = 216172 - OPEN_STREETS_ISLAND_WORLD_MERFOLK: 'CommonSituationJobId' = 210407 - OPEN_STREETS_ISLAND_WORLD_TOWN_VISITOR: 'CommonSituationJobId' = 210410 - OPEN_STREETS_JOGGER: 'CommonSituationJobId' = 40409 - OPEN_STREETS_JUNGLE_MARKETPLACE_BROWSER: 'CommonSituationJobId' = 178175 - OPEN_STREETS_JUNGLE_MARKETPLACE_FISHERMAN: 'CommonSituationJobId' = 178121 - OPEN_STREETS_JUNGLE_MARKETPLACE_TOURIST_TAKE_PHOTO: 'CommonSituationJobId' = 178230 - OPEN_STREETS_LOUNGER: 'CommonSituationJobId' = 77025 - OPEN_STREETS_MARKET_STALLS_CUSTOMER: 'CommonSituationJobId' = 181017 - OPEN_STREETS_MASTER_FISHERMAN: 'CommonSituationJobId' = 40509 - OPEN_STREETS_MASTER_GARDENER: 'CommonSituationJobId' = 40366 - OPEN_STREETS_MYSHUNO_MEADOWS_CHILDREN_PLAYING: 'CommonSituationJobId' = 154536 - OPEN_STREETS_MYSHUNO_MEADOWS_FISHER: 'CommonSituationJobId' = 155931 - OPEN_STREETS_MYSHUNO_MEADOWS_FORMAL_VISITORS: 'CommonSituationJobId' = 154537 - OPEN_STREETS_MYSHUNO_MEADOWS_JOGGER: 'CommonSituationJobId' = 155567 - OPEN_STREETS_MYSHUNO_MEADOWS_LIVING_STATUE_BUSKER: 'CommonSituationJobId' = 151727 - OPEN_STREETS_MYSHUNO_MEADOWS_TOWNIE: 'CommonSituationJobId' = 155682 - OPEN_STREETS_MYSHUNO_MEADOWS_WEIRDO: 'CommonSituationJobId' = 151728 - OPEN_STREETS_PAINTER: 'CommonSituationJobId' = 126203 - OPEN_STREETS_PICNIC_TABLE: 'CommonSituationJobId' = 126163 - OPEN_STREETS_PLAYGROUND: 'CommonSituationJobId' = 38312 - OPEN_STREETS_RESTROOM: 'CommonSituationJobId' = 40786 - OPEN_STREETS_RESTROOM_LOCAL: 'CommonSituationJobId' = 127059 - OPEN_STREETS_SEASONAL_LEAVES: 'CommonSituationJobId' = 181007 - OPEN_STREETS_SEASONAL_PUDDLES: 'CommonSituationJobId' = 181009 - OPEN_STREETS_SEASONAL_SKATER: 'CommonSituationJobId' = 181008 - OPEN_STREETS_SEASONAL_SKATER_PRO: 'CommonSituationJobId' = 185771 - OPEN_STREETS_SEASONAL_SNOW_CHILD: 'CommonSituationJobId' = 185707 - OPEN_STREETS_SEASONAL_SNOW_TYAE: 'CommonSituationJobId' = 181488 - OPEN_STREET_CITY_LIFE_LIVES_ON_STREET_ADULT: 'CommonSituationJobId' = 134683 - OPEN_STREET_CITY_LIFE_LIVES_ON_STREET_CHILD: 'CommonSituationJobId' = 152482 - ORG_EVENT_DEBATE_SHOWDOWN_AUDIENCE_MEMBER: 'CommonSituationJobId' = 222731 - ORG_EVENT_DEBATE_SHOWDOWN_JUDGE: 'CommonSituationJobId' = 222729 - ORG_EVENT_DEBATE_SHOWDOWN_JUDGE_DECLARE: 'CommonSituationJobId' = 229268 - ORG_EVENT_DEBATE_SHOWDOWN_PARTICIPANT: 'CommonSituationJobId' = 222730 - ORG_EVENT_DEBATE_SHOWDOWN_PLAYER: 'CommonSituationJobId' = 225829 - ORG_EVENT_DEBATE_SHOWDOWN_PLAYER_PRACTICE: 'CommonSituationJobId' = 230077 - ORG_EVENT_DEBATE_SHOWDOWN_PRACTICE_PARTICIPANT: 'CommonSituationJobId' = 228583 - ORG_EVENT_PAINTING_IN_THE_PARK_MEMBERS: 'CommonSituationJobId' = 223216 - ORG_EVENT_PAINTING_IN_THE_PARK_MODEL: 'CommonSituationJobId' = 227009 - ORG_EVENT_PAINTING_IN_THE_PARK_PLAYER: 'CommonSituationJobId' = 223358 - PAPARAZZI_LOCKED_OUT: 'CommonSituationJobId' = 200949 - PAPARAZZI_PAPARAZZI: 'CommonSituationJobId' = 196400 - PARK_DEFAULT: 'CommonSituationJobId' = 76134 - PARK_DEFAULT_PCTYAE: 'CommonSituationJobId' = 157919 - PARK_FISHER: 'CommonSituationJobId' = 77050 - PARK_GARDENER: 'CommonSituationJobId' = 77051 - PARK_PLAYER: 'CommonSituationJobId' = 134438 - PARTY_BAR_NIGHT_MEET_UP_PARTICIPANT: 'CommonSituationJobId' = 229025 - PARTY_HOST: 'CommonSituationJobId' = 16168 - PARTY_HOST_CHARITY_BENEFIT: 'CommonSituationJobId' = 202428 - PARTY_HOST_KEG_PARTY: 'CommonSituationJobId' = 222556 - PARTY_HOST_LAMPOON: 'CommonSituationJobId' = 202122 - PARTY_RESIDENT: 'CommonSituationJobId' = 26053 - PATIENT_AWAY_EVENT_HOUSE_CALL: 'CommonSituationJobId' = 114053 - PATIENT_AWAY_EVENT_OUTBREAK: 'CommonSituationJobId' = 114027 - PATRON_MUSEUM: 'CommonSituationJobId' = 29785 - PATRON_MUSEUM_JUNGLE_NATIVE: 'CommonSituationJobId' = 185013 - PATRON_MUSEUM_JUNGLE_TOURIST: 'CommonSituationJobId' = 185021 - PATRON_MUSEUM_PLAYER: 'CommonSituationJobId' = 134430 - PET_CARE_PET: 'CommonSituationJobId' = 164140 - PET_CARE_PET_CARE_WORKER: 'CommonSituationJobId' = 164139 - PET_OBSTACLE_COURSE_PET: 'CommonSituationJobId' = 172175 - PET_OBSTACLE_COURSE_PET_OWNER: 'CommonSituationJobId' = 172176 - PIZZA_DELIVERY: 'CommonSituationJobId' = 9830 - PLAY_DATE_ACTOR_TARGET: 'CommonSituationJobId' = 117181 - PLAY_DATE_NPC_INVITER: 'CommonSituationJobId' = 117173 - PLAY_DATE_NPC_PARENT: 'CommonSituationJobId' = 117184 - PLAY_DATE_PLAYER_PARENT: 'CommonSituationJobId' = 118329 - PLAY_HOOKY_ACTOR_TARGET: 'CommonSituationJobId' = 125960 - PLAY_HOOKY_INVITE_SIM_PICKER: 'CommonSituationJobId' = 126661 - PLAY_HOOKY_NPC_HOST: 'CommonSituationJobId' = 125959 - PRANK_BAR_NIGHT_MEET_UP_PARTICIPANT: 'CommonSituationJobId' = 229026 - PRESENT_PILE_GROUP: 'CommonSituationJobId' = 185128 - PRESENT_PILE_SIM: 'CommonSituationJobId' = 185129 - PROTESTER: 'CommonSituationJobId' = 136556 - READER_LIBRARY: 'CommonSituationJobId' = 27571 - RECOMMEND_LOCAL_HANGOUT_CLUB_PARTY_ACTOR_TARGET: 'CommonSituationJobId' = 137956 - RECOMMEND_LOCAL_HANGOUT_CLUB_PARTY_CLUB_MEMBERS: 'CommonSituationJobId' = 137957 - RECOMMEND_LOCAL_HANGOUT_CLUB_PARTY_INVITE: 'CommonSituationJobId' = 137964 - RECOMMEND_LOCAL_HANGOUT_CLUB_PARTY_SIM_PICKER: 'CommonSituationJobId' = 137958 - RECOMMEND_LOCAL_HANGOUT_MUSEUM_ACTOR_TARGET: 'CommonSituationJobId' = 137995 - RECOMMEND_LOCAL_HANGOUT_MUSEUM_INVITE_SIM_PICKER: 'CommonSituationJobId' = 137996 - RECOMMEND_LOCAL_HANGOUT_MUSEUM_NPC_INVITE: 'CommonSituationJobId' = 137997 - RELAXATION_VENUES_CELEBRITY_HANG_OUT_HIGH_FAME: 'CommonSituationJobId' = 195426 - RELAXATION_VENUES_CELEBRITY_HANG_OUT_LOW_FAME: 'CommonSituationJobId' = 195425 - RELAXATION_VENUE_BARTENDER: 'CommonSituationJobId' = 156407 - RELAXATION_VENUE_MASSAGE_THERAPIST: 'CommonSituationJobId' = 117815 - RELAXATION_VENUE_REFLEXOLOGIST: 'CommonSituationJobId' = 119519 - REPAIR: 'CommonSituationJobId' = 129478 - RESTAURANT_DINER_BACKGROUND_BAD_DATE_ANGRY_SIM: 'CommonSituationJobId' = 132758 - RESTAURANT_DINER_BACKGROUND_BAD_DATE_FLIRTY_SIM: 'CommonSituationJobId' = 132759 - RESTAURANT_DINER_BACKGROUND_HAPPY_DATE: 'CommonSituationJobId' = 132676 - RESTAURANT_DINER_BACKGROUND_NPC_CELEBRITY: 'CommonSituationJobId' = 196197 - RESTAURANT_DINER_BACKGROUND_NPC_CRITIC: 'CommonSituationJobId' = 141387 - RESTAURANT_DINER_BACKGROUND_NPC_EARLY_BIRDS: 'CommonSituationJobId' = 132779 - RESTAURANT_DINER_BACKGROUND_NPC_FAMILY_MEAL_CHILD: 'CommonSituationJobId' = 132883 - RESTAURANT_DINER_BACKGROUND_NPC_FAMILY_MEAL_PARENT: 'CommonSituationJobId' = 132884 - RESTAURANT_DINER_BACKGROUND_STANDARD: 'CommonSituationJobId' = 132459 - RESTAURANT_DINER_EVENTS_NPC_BUSINESS_SUITS: 'CommonSituationJobId' = 133907 - RESTAURANT_DINER_EVENTS_NPC_COSPLAY: 'CommonSituationJobId' = 133902 - RESTAURANT_DINER_EVENTS_NPC_GHOSTS: 'CommonSituationJobId' = 133903 - RESTAURANT_DINER_EVENTS_NPC_NEARLY_NUDE: 'CommonSituationJobId' = 133909 - RESTAURANT_DINER_EVENTS_NPC_SPACE_RACE: 'CommonSituationJobId' = 133908 - RESTAURANT_DINER_SUB_NPC_BAD_DATE_ANGRY_SIM: 'CommonSituationJobId' = 132757 - RESTAURANT_DINER_SUB_NPC_BAD_DATE_FLIRTY_SIM: 'CommonSituationJobId' = 132756 - RESTAURANT_DINER_SUB_NPC_CELEBRITY: 'CommonSituationJobId' = 196200 - RESTAURANT_DINER_SUB_NPC_CRITIC: 'CommonSituationJobId' = 141389 - RESTAURANT_DINER_SUB_NPC_EARLY_BIRDS: 'CommonSituationJobId' = 132778 - RESTAURANT_DINER_SUB_NPC_FAMILY_MEAL_CHILD: 'CommonSituationJobId' = 132885 - RESTAURANT_DINER_SUB_NPC_FAMILY_MEAL_PARENT: 'CommonSituationJobId' = 132886 - RESTAURANT_DINER_SUB_NPC_HAPPY_DATE: 'CommonSituationJobId' = 132675 - RESTAURANT_DINER_SUB_STANDARD: 'CommonSituationJobId' = 132458 - ROBOTICS_BAR_NIGHT_MEET_UP_PARTICIPANT: 'CommonSituationJobId' = 229042 - ROOMMATE_NPC_EVENT: 'CommonSituationJobId' = 221661 - ROOMMATE_NPC_EVENT_ARGUMENT: 'CommonSituationJobId' = 223202 - ROOMMATE_NPC_EVENT_GET_HYPE: 'CommonSituationJobId' = 223201 - ROOMMATE_NPC_EVENT_LOCKED_OUT: 'CommonSituationJobId' = 223199 - ROOMMATE_NPC_EVENT_WHISPERS: 'CommonSituationJobId' = 223203 - ROOMMATE_NPC_EVENT_WOOING: 'CommonSituationJobId' = 223200 - ROOMMATE_NPC_STANDARD: 'CommonSituationJobId' = 208141 - ROOMMATE_NPC_STANDARD_FRIENDS: 'CommonSituationJobId' = 210614 - ROOMMATE_NPC_STANDARD_PARTY: 'CommonSituationJobId' = 212049 - ROOMMATE_NPC_STANDARD_POTENTIAL: 'CommonSituationJobId' = 220605 - ROOMMATE_NPC_STANDARD_SIGNIFICANT_OTHER: 'CommonSituationJobId' = 210690 - SECRET_LAB_PLAYER: 'CommonSituationJobId' = 204571 - SITUATION_APARTMENT_NEIGHBORS_VISITOR_COMPLAINT_NOISE: 'CommonSituationJobId' = 146044 - SITUATION_APARTMENT_NEIGHBORS_VISITOR_INTRIGUED_NOISE: 'CommonSituationJobId' = 146051 - SITUATION_APARTMENT_NEIGHBORS_VISITOR_INTRIGUED_SMELL: 'CommonSituationJobId' = 146054 - SITUATION_APARTMENT_NEIGHBOR_NPC_CHAT: 'CommonSituationJobId' = 155249 - SITUATION_APARTMENT_NEIGHBOR_NPC_CHECK_MAIL: 'CommonSituationJobId' = 137333 - SITUATION_APARTMENT_NEIGHBOR_NPC_HOST_LOUD_FIGHT: 'CommonSituationJobId' = 145044 - SITUATION_APARTMENT_NEIGHBOR_NPC_HOST_LOUD_MUSIC: 'CommonSituationJobId' = 138077 - SITUATION_APARTMENT_NEIGHBOR_NPC_HOST_LOUD_WOOHOO: 'CommonSituationJobId' = 138078 - SITUATION_APARTMENT_NEIGHBOR_NPC_INVITED_HANGOUT: 'CommonSituationJobId' = 146556 - SITUATION_APARTMENT_NEIGHBOR_NPC_TAKE_OUT_TRASH: 'CommonSituationJobId' = 137046 - SITUATION_APARTMENT_NEIGHBOR_PLAYER_HOST_CHAT: 'CommonSituationJobId' = 155252 - SITUATION_APARTMENT_NEIGHBOR_PLAYER_HOST_HANGOUT_GENERIC: 'CommonSituationJobId' = 139272 - SITUATION_APARTMENT_NEIGHBOR_VISITOR_HANGOUT_BRAINSTORM_ART_LOVER: 'CommonSituationJobId' = 141312 - SITUATION_APARTMENT_NEIGHBOR_VISITOR_HANGOUT_BRAINSTORM_CREATIVE: 'CommonSituationJobId' = 141311 - SITUATION_APARTMENT_NEIGHBOR_VISITOR_HANGOUT_CHILDS_PLAY: 'CommonSituationJobId' = 141134 - SITUATION_APARTMENT_NEIGHBOR_VISITOR_HANGOUT_CHILD_COMPLAINT: 'CommonSituationJobId' = 141133 - SITUATION_APARTMENT_NEIGHBOR_VISITOR_HANGOUT_FLIRTY_SHOWER: 'CommonSituationJobId' = 141135 - SITUATION_APARTMENT_NEIGHBOR_VISITOR_HANGOUT_GEEK_OUT: 'CommonSituationJobId' = 141132 - SITUATION_APARTMENT_NEIGHBOR_VISITOR_HANGOUT_GENERIC_BORED: 'CommonSituationJobId' = 139265 - SITUATION_APARTMENT_NEIGHBOR_VISITOR_HANGOUT_KEY_GROUP: 'CommonSituationJobId' = 140397 - SITUATION_APARTMENT_NEIGHBOR_VISITOR_HANGOUT_MUNCHIES_FOODIE: 'CommonSituationJobId' = 141313 - SITUATION_APARTMENT_NEIGHBOR_VISITOR_HANGOUT_MUNCHIES_GLUTTON: 'CommonSituationJobId' = 141314 - SITUATION_APARTMENT_NEIGHBOR_VISITOR_HANGOUT_UNINVITED_GOOFBALL: 'CommonSituationJobId' = 141929 - SITUATION_APARTMENT_NEIGHBOR_VISITOR_HANGOUT_UNINVITED_INSANE: 'CommonSituationJobId' = 141935 - SITUATION_APARTMENT_NEIGHBOR_VISITOR_HANGOUT_WORKOUT: 'CommonSituationJobId' = 141131 - SITUATION_BASIC_TRAIT_STRANGER_VILLE_NPC_CONSPIRACIST: 'CommonSituationJobId' = 206856 - SITUATION_BASIC_TRAIT_STRANGER_VILLE_NPC_MILITARY: 'CommonSituationJobId' = 206855 - SITUATION_BASIC_TRAIT_STRANGER_VILLE_NPC_SCIENTIST: 'CommonSituationJobId' = 206857 - SITUATION_CAREER_DOCTOR_NPC_ASSISTANT: 'CommonSituationJobId' = 111986 - SITUATION_CAREER_DOCTOR_NPC_DOCTOR: 'CommonSituationJobId' = 111985 - SITUATION_CAREER_DOCTOR_NPC_DOCTOR_DIAGNOSER: 'CommonSituationJobId' = 116252 - SITUATION_CAREER_DOCTOR_NPC_NURSE: 'CommonSituationJobId' = 111276 - SITUATION_CAREER_DOCTOR_NPC_OBGYN: 'CommonSituationJobId' = 116172 - SITUATION_CAREER_DOCTOR_NPC_ORDERLY: 'CommonSituationJobId' = 112046 - SITUATION_CAREER_DOCTOR_PATIENT_ADMITTED_LOW: 'CommonSituationJobId' = 113532 - SITUATION_CELEBRITY: 'CommonSituationJobId' = 196518 - SITUATION_CELEBRITY_GUITAR: 'CommonSituationJobId' = 202419 - SITUATION_CELEBRITY_MEET_AND_GREET_CELEBRITY: 'CommonSituationJobId' = 199570 - SITUATION_CELEBRITY_MEET_AND_GREET_FAN: 'CommonSituationJobId' = 199571 - SITUATION_CELEBRITY_TILE_PLACEMENT_CEREMONY_CROWD_MEMBER: 'CommonSituationJobId' = 195785 - SITUATION_CELEBRITY_TILE_PLACEMENT_CEREMONY_HONOREE: 'CommonSituationJobId' = 195784 - SITUATION_CITY_INVITES_ACTOR: 'CommonSituationJobId' = 139546 - SITUATION_CITY_INVITES_TARGET_SIM: 'CommonSituationJobId' = 143134 - SITUATION_CLUB_GO_DANCING_BACKGROUND_PARTY_GOER: 'CommonSituationJobId' = 123414 - SITUATION_CLUB_GO_DANCING_NPC_DANCER: 'CommonSituationJobId' = 123140 - SITUATION_CLUB_GO_DANCING_NPC_DANCE_PARTY_POOPER: 'CommonSituationJobId' = 123154 - SITUATION_CLUB_GO_DANCING_NPC_DJ: 'CommonSituationJobId' = 122831 - SITUATION_CLUB_GO_DANCING_NPC_DJ_AUDIENCE: 'CommonSituationJobId' = 123014 - SITUATION_CLUB_GO_DANCING_NPC_DJ_HIRED: 'CommonSituationJobId' = 123727 - SITUATION_CLUB_GO_DANCING_NPC_DJ_HIRED_LEVEL10: 'CommonSituationJobId' = 124275 - SITUATION_CLUB_GO_DANCING_NPC_DJ_LEVEL10: 'CommonSituationJobId' = 124255 - SITUATION_CLUB_GO_DANCING_PARTY_GOER: 'CommonSituationJobId' = 123013 - SITUATION_CLUB_GO_DANCING_PARTY_GOER_ACTOR: 'CommonSituationJobId' = 125412 - SITUATION_COUNTER: 'CommonSituationJobId' = 181150 - SITUATION_CRAFT_SALES_TABLE_OWNER: 'CommonSituationJobId' = 155035 - SITUATION_CRAFT_SALES_TABLE_VENDOR: 'CommonSituationJobId' = 153605 - SITUATION_CRAFT_SALES_TABLE_VENDOR_JUNGLE: 'CommonSituationJobId' = 177941 - SITUATION_CRAFT_SALES_TABLE_VENDOR_PAINTER: 'CommonSituationJobId' = 154396 - SITUATION_DANCE_BATTLE_FOLLOWER: 'CommonSituationJobId' = 128538 - SITUATION_DANCE_BATTLE_LEADER: 'CommonSituationJobId' = 128537 - SITUATION_DANCE_TOGETHER_FOLLOWER: 'CommonSituationJobId' = 128100 - SITUATION_DANCE_TOGETHER_LEADER: 'CommonSituationJobId' = 128099 - SITUATION_DETECTIVE_APB_CRIMINAL: 'CommonSituationJobId' = 107969 - SITUATION_DETECTIVE_APB_DECOY: 'CommonSituationJobId' = 108028 - SITUATION_DETECTIVE_APB_DETECTIVE: 'CommonSituationJobId' = 108029 - SITUATION_DETECTIVE_APB_NEUTRAL: 'CommonSituationJobId' = 109091 - SITUATION_DETECTIVE_CRIME_SCENE_OFFICER: 'CommonSituationJobId' = 109168 - SITUATION_DETECTIVE_CRIME_SCENE_PLAYER: 'CommonSituationJobId' = 109056 - SITUATION_DETECTIVE_CRIME_SCENE_WITNESS: 'CommonSituationJobId' = 109167 - SITUATION_DETECTIVE_PATROL_FIGHTER: 'CommonSituationJobId' = 110694 - SITUATION_DETECTIVE_PATROL_PLAYER: 'CommonSituationJobId' = 110742 - SITUATION_DETECTIVE_POLICE_STATION_ARRESTED: 'CommonSituationJobId' = 109134 - SITUATION_DETECTIVE_POLICE_STATION_CIVILIAN: 'CommonSituationJobId' = 108698 - SITUATION_DETECTIVE_POLICE_STATION_CRIMINAL: 'CommonSituationJobId' = 112327 - SITUATION_DETECTIVE_POLICE_STATION_NPC_ASSISTANT: 'CommonSituationJobId' = 114512 - SITUATION_DETECTIVE_POLICE_STATION_NPC_OFFICER: 'CommonSituationJobId' = 109997 - SITUATION_DETECTIVE_POLICE_STATION_PLAYER: 'CommonSituationJobId' = 109187 - SITUATION_DOCTOR_CAREER_PATIENT_ADMITTED_LOW_RECLINE: 'CommonSituationJobId' = 116177 - SITUATION_DOCTOR_CAREER_PATIENT_PREGNANT_EMERGENCY: 'CommonSituationJobId' = 113635 - SITUATION_GROUP_INTERACTION_FOLLOWER: 'CommonSituationJobId' = 187208 - SITUATION_GROUP_INTERACTION_LEADER: 'CommonSituationJobId' = 187206 - SITUATION_HOLIDAY: 'CommonSituationJobId' = 182319 - SITUATION_INFECTED: 'CommonSituationJobId' = 202598 - SITUATION_INFECTED_ATTACK: 'CommonSituationJobId' = 204727 - SITUATION_LANDLORD: 'CommonSituationJobId' = 135301 - SITUATION_LEAVE_NOW: 'CommonSituationJobId' = 24225 - SITUATION_LEAVE_NOW_MUST_RUN: 'CommonSituationJobId' = 24321 - SITUATION_LEAVE_SOON: 'CommonSituationJobId' = 24221 - SITUATION_MARKET_STALLS_CUSTOMER: 'CommonSituationJobId' = 132960 - SITUATION_MARKET_STALLS_VENDOR: 'CommonSituationJobId' = 132892 - SITUATION_MARKET_STALLS_VENDOR_CURIO_SHOP: 'CommonSituationJobId' = 202393 - SITUATION_MARKET_STALLS_VENDOR_HIRED_NPC: 'CommonSituationJobId' = 132882 - SITUATION_MARKET_STALLS_VENDOR_JUNGLE: 'CommonSituationJobId' = 182887 - SITUATION_MARKET_STALLS_VENDOR_SEASONAL: 'CommonSituationJobId' = 191308 - SITUATION_NPC_INVITES_LOUNGE_EVENT_ACTOR: 'CommonSituationJobId' = 198863 - SITUATION_NPC_INVITES_LOUNGE_EVENT_TARGET_SIM: 'CommonSituationJobId' = 198864 - SITUATION_PENTHOUSE_NEIGHBORS_HANGOUT_MUNCHIES_KEY_HOLDERS_FOODIE: 'CommonSituationJobId' = 146195 - SITUATION_PENTHOUSE_NEIGHBORS_HANGOUT_MUNCHIES_KEY_HOLDERS_GLUTTON: 'CommonSituationJobId' = 146196 - SITUATION_PENTHOUSE_NEIGHBORS_HANGOUT_MUNCHIES_NON_KEY_HOLDERS_FOODIE: 'CommonSituationJobId' = 146193 - SITUATION_PENTHOUSE_NEIGHBORS_HANGOUT_MUNCHIES_NON_KEY_HOLDERS_GLUTTON: 'CommonSituationJobId' = 146194 - SITUATION_PENTHOUSE_NEIGHBORS_VISITOR_HANGOUT_BRAINSTORM_KEY_HOLDERS_ART_LOVER: 'CommonSituationJobId' = 146280 - SITUATION_PENTHOUSE_NEIGHBORS_VISITOR_HANGOUT_BRAINSTORM_KEY_HOLDERS_CREATIVE: 'CommonSituationJobId' = 146279 - SITUATION_PENTHOUSE_NEIGHBORS_VISITOR_HANGOUT_BRAINSTORM_NON_KEY_HOLDERS_ART_LOVER: 'CommonSituationJobId' = 146278 - SITUATION_PENTHOUSE_NEIGHBORS_VISITOR_HANGOUT_BRAINSTORM_NON_KEY_HOLDERS_CREATIVE: 'CommonSituationJobId' = 146282 - SITUATION_PENTHOUSE_NEIGHBORS_VISITOR_HANGOUT_CHILDS_PLAY_KEY_HOLDERS: 'CommonSituationJobId' = 146408 - SITUATION_PENTHOUSE_NEIGHBORS_VISITOR_HANGOUT_CHILDS_PLAY_NON_KEY_HOLDERS: 'CommonSituationJobId' = 146409 - SITUATION_PENTHOUSE_NEIGHBORS_VISITOR_HANGOUT_GEEK_OUT_KEY_HOLDERS: 'CommonSituationJobId' = 146405 - SITUATION_PENTHOUSE_NEIGHBORS_VISITOR_HANGOUT_GEEK_OUT_NON_KEY_HOLDERS: 'CommonSituationJobId' = 146406 - SITUATION_PENTHOUSE_NEIGHBORS_VISITOR_HANGOUT_GENERIC_BORED_KEY_HOLDERS: 'CommonSituationJobId' = 146328 - SITUATION_PENTHOUSE_NEIGHBORS_VISITOR_HANGOUT_GENERIC_BORED_NON_KEY_HOLDERS: 'CommonSituationJobId' = 146329 - SITUATION_PENTHOUSE_NEIGHBORS_VISITOR_HANGOUT_UNINVITED_KEY_HOLDERS_GOOFBALL: 'CommonSituationJobId' = 146356 - SITUATION_PENTHOUSE_NEIGHBORS_VISITOR_HANGOUT_UNINVITED_KEY_HOLDERS_INSANE: 'CommonSituationJobId' = 146357 - SITUATION_PENTHOUSE_NEIGHBORS_VISITOR_HANGOUT_UNINVITED_NON_KEY_HOLDERS_GOOFBALL: 'CommonSituationJobId' = 146359 - SITUATION_PENTHOUSE_NEIGHBORS_VISITOR_HANGOUT_UNINVITED_NON_KEY_HOLDERS_INSANE: 'CommonSituationJobId' = 146360 - SITUATION_PENTHOUSE_NEIGHBORS_VISITOR_HANGOUT_WORKOUT_KEY_HOLDERS: 'CommonSituationJobId' = 146402 - SITUATION_PENTHOUSE_NEIGHBORS_VISITOR_HANGOUT_WORKOUT_NON_KEY_HOLDERS: 'CommonSituationJobId' = 146403 - SITUATION_PERFORMANCE_SPACE_BUSKER_HIRED_GUITAR: 'CommonSituationJobId' = 152921 - SITUATION_PERFORMANCE_SPACE_BUSKER_HIRED_VIOLIN: 'CommonSituationJobId' = 152920 - SITUATION_PERFORMANCE_SPACE_BUSKER_OPEN_STREET: 'CommonSituationJobId' = 142718 - SITUATION_PERFORMANCE_SPACE_BUSKER_VIOLIN: 'CommonSituationJobId' = 142060 - SITUATION_PET_ADOPTION_ADOPTABLE_PET: 'CommonSituationJobId' = 166817 - SITUATION_PET_ADOPTION_ADOPTION_OFFICER: 'CommonSituationJobId' = 166816 - SITUATION_POSSESSED: 'CommonSituationJobId' = 202246 - SITUATION_RETAIL_CUSTOMER_BARGAIN_SHOPPER: 'CommonSituationJobId' = 109149 - SITUATION_RETAIL_CUSTOMER_CELEBRITY_HIGH_FAME: 'CommonSituationJobId' = 195643 - SITUATION_RETAIL_CUSTOMER_CELEBRITY_LOW_FAME: 'CommonSituationJobId' = 195641 - SITUATION_RETAIL_CUSTOMER_LOITERER: 'CommonSituationJobId' = 109150 - SITUATION_RETAIL_CUSTOMER_MID_RANGE: 'CommonSituationJobId' = 109151 - SITUATION_RETAIL_CUSTOMER_SOCIALIZER: 'CommonSituationJobId' = 109152 - SITUATION_RETAIL_CUSTOMER_WEALTHY: 'CommonSituationJobId' = 109044 - SITUATION_RETAIL_EMPLOYEE: 'CommonSituationJobId' = 109248 - SITUATION_RETAIL_NPC_EMPLOYEE: 'CommonSituationJobId' = 112113 - SITUATION_SCARECROW: 'CommonSituationJobId' = 187081 - SITUATION_SCARECROW_PURPLE: 'CommonSituationJobId' = 191041 - SITUATION_SCARECROW_RED: 'CommonSituationJobId' = 191040 - SITUATION_SERVICE_SKELETON: 'CommonSituationJobId' = 177648 - SITUATION_SET_TABLE: 'CommonSituationJobId' = 161858 - SITUATION_SINGLE_SIM_LEAVE: 'CommonSituationJobId' = 101252 - SITUATION_SQUAD_PERK_SQUAD_LEADER: 'CommonSituationJobId' = 195512 - SITUATION_SQUAD_PERK_SQUAD_MEMBER: 'CommonSituationJobId' = 195505 - SITUATION_TEMPLE_SKELETON: 'CommonSituationJobId' = 178432 - SITUATION_TODDLER_CAREGIVER: 'CommonSituationJobId' = 156098 - SITUATION_TV_WORK_OUT_TOGETHER_FOLLOWER: 'CommonSituationJobId' = 164401 - SITUATION_TV_WORK_OUT_TOGETHER_LEADER: 'CommonSituationJobId' = 164400 - SITUATION_VIP_ROPE_BOUNCER: 'CommonSituationJobId' = 191861 - SLEEPER_PARK: 'CommonSituationJobId' = 27474 - SPA_GUEST_PLAYER: 'CommonSituationJobId' = 118867 - STAY_THE_NIGHT: 'CommonSituationJobId' = 40429 - STUDENT_LIBRARY_MUSEUM: 'CommonSituationJobId' = 27676 - TEEN_PARK: 'CommonSituationJobId' = 40112 - TELEPORT_TO_MAGIC_HQ_FAIL: 'CommonSituationJobId' = 215130 - TEMPORARY_CLONE: 'CommonSituationJobId' = 215158 - TODDLER_PLAY_DATE_GUEST_CAREGIVER: 'CommonSituationJobId' = 170144 - TODDLER_PLAY_DATE_GUEST_TODDLER: 'CommonSituationJobId' = 170082 - TODDLER_PLAY_DATE_HOST_CARE_GIVER: 'CommonSituationJobId' = 170083 - TODDLER_PLAY_DATE_HOST_TODDLER: 'CommonSituationJobId' = 170084 - TRAGIC_CLOWN: 'CommonSituationJobId' = 139603 - TRAINER_GYM: 'CommonSituationJobId' = 40327 - TRAINING_DUMMY_GROUP: 'CommonSituationJobId' = 203290 - TRAINING_DUMMY_SIM: 'CommonSituationJobId' = 203291 - TRASH_DUMPER: 'CommonSituationJobId' = 234516 - TRASH_UPDATE_WASTE_MANAGER: 'CommonSituationJobId' = 235043 - TRASH_UPDATE_WASTE_MANAGER_PLAYER: 'CommonSituationJobId' = 235802 - TUTORIAL_WELCOME_WAGON: 'CommonSituationJobId' = 77001 - UNGREETED_NPC_VISITING_NPC: 'CommonSituationJobId' = 34418 - UNGREETED_NPC_VISITING_NPC_UNIVERSITY: 'CommonSituationJobId' = 230379 - UNGREETED_PLAYER_VISITING_NPC: 'CommonSituationJobId' = 34417 - UNIVERSITY_GRADUATION_CEREMONY_ARTS: 'CommonSituationJobId' = 227001 - UNIVERSITY_GRADUATION_CEREMONY_ARTS_HOST: 'CommonSituationJobId' = 227912 - UNIVERSITY_GRADUATION_CEREMONY_ARTS_HOUSEHOLD: 'CommonSituationJobId' = 230458 - UNIVERSITY_GRADUATION_CEREMONY_SCIENCE: 'CommonSituationJobId' = 227003 - UNIVERSITY_GRADUATION_CEREMONY_SCIENCE_HOST: 'CommonSituationJobId' = 227918 - UNIVERSITY_GRADUATION_CEREMONY_SCIENCE_HOUSEHOLD: 'CommonSituationJobId' = 230455 - UNIVERSITY_RIVALS_RIVALS_ARTS: 'CommonSituationJobId' = 226703 - UNIVERSITY_RIVALS_RIVALS_SCIENCE: 'CommonSituationJobId' = 226701 - UNIVERSITY_STUDENT: 'CommonSituationJobId' = 221720 - UNIVERSITY_WORLD_ARTS_GHOST: 'CommonSituationJobId' = 222905 - UNIVERSITY_WORLD_ARTS_MASCOT: 'CommonSituationJobId' = 222866 - UNIVERSITY_WORLD_ARTS_STUDENT: 'CommonSituationJobId' = 222511 - UNIVERSITY_WORLD_CTYAE_SWIMMER: 'CommonSituationJobId' = 222840 - UNIVERSITY_WORLD_SCIENCE_MASCOT: 'CommonSituationJobId' = 222867 - UNIVERSITY_WORLD_SCIENCE_ROBOT: 'CommonSituationJobId' = 222943 - UNIVERSITY_WORLD_SCIENCE_STUDENT: 'CommonSituationJobId' = 222537 - UNIVERSITY_WORLD_TOURING_TEEN: 'CommonSituationJobId' = 222768 - UNIVERSITY_WORLD_YA_SWIMMER: 'CommonSituationJobId' = 222764 - VAMPIRE_INVITES_VAMPIRE_CREATION_NORMIE: 'CommonSituationJobId' = 152831 - VAMPIRE_INVITES_VAMPIRE_CREATION_VAMPIRE: 'CommonSituationJobId' = 152407 - VAMPIRE_VISIT: 'CommonSituationJobId' = 152616 - VAMPIRE_VISIT_INITIAL: 'CommonSituationJobId' = 155259 - VENUE_ARTS_CENTER_FORMAL_VIEWER: 'CommonSituationJobId' = 144891 - VENUE_ARTS_CENTER_GHOST_VIEWER: 'CommonSituationJobId' = 144899 - VENUE_ARTS_CENTER_MUSICIAN_GUITAR: 'CommonSituationJobId' = 144841 - VENUE_ARTS_CENTER_MUSICIAN_PIANO: 'CommonSituationJobId' = 144853 - VENUE_ARTS_CENTER_MUSICIAN_VIOLIN: 'CommonSituationJobId' = 144854 - VENUE_ARTS_CENTER_PAINTER: 'CommonSituationJobId' = 144674 - VENUE_ARTS_CENTER_PARTY_MUSICIAN_GUITAR: 'CommonSituationJobId' = 144879 - VENUE_ARTS_CENTER_PARTY_MUSICIAN_PIANO: 'CommonSituationJobId' = 144880 - VENUE_ARTS_CENTER_PARTY_MUSICIAN_VIOLIN: 'CommonSituationJobId' = 144881 - VENUE_ARTS_CENTER_PARTY_PAINTER: 'CommonSituationJobId' = 144894 - VENUE_ARTS_CENTER_PARTY_VIEWER: 'CommonSituationJobId' = 144893 - VENUE_ARTS_CENTER_PLAYER: 'CommonSituationJobId' = 148660 - VENUE_ARTS_CENTER_SCULPTOR: 'CommonSituationJobId' = 144777 - VENUE_ARTS_CENTER_VIEWER: 'CommonSituationJobId' = 144266 - VENUE_ARTS_CENTER_YOUNG_MUSICIAN_PIANO: 'CommonSituationJobId' = 144856 - VENUE_ARTS_CENTER_YOUNG_MUSICIAN_VIOLIN: 'CommonSituationJobId' = 144855 - VENUE_ARTS_CENTER_YOUNG_PAINTER: 'CommonSituationJobId' = 144834 - VENUE_ARTS_CENTER_YOUNG_VIEWER: 'CommonSituationJobId' = 144835 - VENUE_BAR_ALIEN_NIGHT: 'CommonSituationJobId' = 122626 - VENUE_BAR_BEAR_NIGHT: 'CommonSituationJobId' = 126612 - VENUE_BAR_GHOST_NIGHT: 'CommonSituationJobId' = 122625 - VENUE_BAR_GUYS_NIGHT: 'CommonSituationJobId' = 122629 - VENUE_BAR_HAPPY_HOUR: 'CommonSituationJobId' = 121146 - VENUE_BAR_KNIGHT_NIGHT: 'CommonSituationJobId' = 130283 - VENUE_BAR_LADIES_NIGHT: 'CommonSituationJobId' = 122627 - VENUE_BAR_SINGLES_NIGHT: 'CommonSituationJobId' = 122628 - VENUE_BEACH_BEACH_COMBER: 'CommonSituationJobId' = 207758 - VENUE_BEACH_BEACH_COMBER_WALK_BY: 'CommonSituationJobId' = 212410 - VENUE_BEACH_LIFE_GUARD: 'CommonSituationJobId' = 207759 - VENUE_BEACH_MERFOLK: 'CommonSituationJobId' = 207760 - VENUE_BEACH_SAND_ARTIST: 'CommonSituationJobId' = 207761 - VENUE_BEACH_SWIMMER: 'CommonSituationJobId' = 205337 - VENUE_BEACH_TANNER: 'CommonSituationJobId' = 207762 - VENUE_BEACH_WATER_ENTHUSIAST: 'CommonSituationJobId' = 207763 - VENUE_BOWLING_BOWLER: 'CommonSituationJobId' = 160124 - VENUE_BOWLING_GROUP_2_BOWLER: 'CommonSituationJobId' = 161094 - VENUE_BOWLING_GROUP_3_BOWLER: 'CommonSituationJobId' = 161106 - VENUE_BOWLING_GROUP_4_BOWLER: 'CommonSituationJobId' = 161107 - VENUE_BOWLING_GROUP_BOWLER: 'CommonSituationJobId' = 161083 - VENUE_BOWLING_TEEN_BOWLER: 'CommonSituationJobId' = 160167 - VENUE_CHEF: 'CommonSituationJobId' = 130833 - VENUE_COMMUNITY_GARDEN_GARDENER_GROUP: 'CommonSituationJobId' = 223954 - VENUE_COMMUNITY_MARKET_SHOPPER_GROUP: 'CommonSituationJobId' = 224112 - VENUE_COMMUNITY_SHARED_CANDLE_CRAFTER: 'CommonSituationJobId' = 235342 - VENUE_COMMUNITY_SHARED_CHILD: 'CommonSituationJobId' = 232586 - VENUE_COMMUNITY_SHARED_FABRICATOR: 'CommonSituationJobId' = 232583 - VENUE_COMMUNITY_SHARED_GARDENER: 'CommonSituationJobId' = 232370 - VENUE_COMMUNITY_SHARED_INSECT_FARMER: 'CommonSituationJobId' = 233424 - VENUE_COMMUNITY_SHARED_PAINTER: 'CommonSituationJobId' = 232585 - VENUE_COMMUNITY_SHARED_SCROUNGER: 'CommonSituationJobId' = 234657 - VENUE_COMMUNITY_SHARED_SCROUNGER_WOOHOO: 'CommonSituationJobId' = 235511 - VENUE_COMMUNITY_SHARED_WOODWORKER: 'CommonSituationJobId' = 232584 - VENUE_HOME_CHEF: 'CommonSituationJobId' = 140124 - VENUE_HOST: 'CommonSituationJobId' = 131306 - VENUE_MAKER_SPACE_MENTOR: 'CommonSituationJobId' = 232587 - VENUE_MAKER_SPACE_RECYCLING_GURU: 'CommonSituationJobId' = 232588 - VENUE_MARKETPLACE_SHOPPER: 'CommonSituationJobId' = 233861 - VENUE_MASTER_FISHERMAN: 'CommonSituationJobId' = 77065 - VENUE_MASTER_GARDENER: 'CommonSituationJobId' = 77066 - VENUE_MASTER_HERBALIST: 'CommonSituationJobId' = 102179 - VENUE_NIGHTCLUB_NPC_DANCER: 'CommonSituationJobId' = 123554 - VENUE_PETS_BLACKLIST: 'CommonSituationJobId' = 169533 - VENUE_PETS_CAT: 'CommonSituationJobId' = 170229 - VENUE_PETS_DOG: 'CommonSituationJobId' = 169532 - VENUE_PETS_PET_OWNER_CAT_ARTS_CENTER: 'CommonSituationJobId' = 172750 - VENUE_PETS_PET_OWNER_CAT_BAR: 'CommonSituationJobId' = 170226 - VENUE_PETS_PET_OWNER_CAT_CAFE: 'CommonSituationJobId' = 179099 - VENUE_PETS_PET_OWNER_CAT_CLUB: 'CommonSituationJobId' = 172494 - VENUE_PETS_PET_OWNER_CAT_GYM: 'CommonSituationJobId' = 172547 - VENUE_PETS_PET_OWNER_CAT_KARAOKE: 'CommonSituationJobId' = 172778 - VENUE_PETS_PET_OWNER_CAT_LIBRARY: 'CommonSituationJobId' = 172647 - VENUE_PETS_PET_OWNER_CAT_LOUNGE: 'CommonSituationJobId' = 172677 - VENUE_PETS_PET_OWNER_CAT_MUSEUM: 'CommonSituationJobId' = 172703 - VENUE_PETS_PET_OWNER_CAT_PARK: 'CommonSituationJobId' = 170227 - VENUE_PETS_PET_OWNER_CAT_POOL: 'CommonSituationJobId' = 172804 - VENUE_PETS_PET_OWNER_DOG_ARTS_CENTER: 'CommonSituationJobId' = 172751 - VENUE_PETS_PET_OWNER_DOG_BAR: 'CommonSituationJobId' = 169522 - VENUE_PETS_PET_OWNER_DOG_CAFE: 'CommonSituationJobId' = 179102 - VENUE_PETS_PET_OWNER_DOG_CLUB: 'CommonSituationJobId' = 172495 - VENUE_PETS_PET_OWNER_DOG_GYM: 'CommonSituationJobId' = 172558 - VENUE_PETS_PET_OWNER_DOG_KARAOKE: 'CommonSituationJobId' = 172780 - VENUE_PETS_PET_OWNER_DOG_LIBRARY: 'CommonSituationJobId' = 172656 - VENUE_PETS_PET_OWNER_DOG_LOUNGE: 'CommonSituationJobId' = 172678 - VENUE_PETS_PET_OWNER_DOG_MUSEUM: 'CommonSituationJobId' = 172704 - VENUE_PETS_PET_OWNER_DOG_PARK: 'CommonSituationJobId' = 169523 - VENUE_PETS_PET_OWNER_DOG_POOL: 'CommonSituationJobId' = 172803 - VENUE_POOL_CHILD_SWIMMER: 'CommonSituationJobId' = 125100 - VENUE_POOL_ELDER_SWIMMER: 'CommonSituationJobId' = 125101 - VENUE_POOL_GENERIC_SWIMMER: 'CommonSituationJobId' = 125099 - VENUE_POOL_LOUNGER: 'CommonSituationJobId' = 125102 - VENUE_POOL_PLAYER_SWIMMER: 'CommonSituationJobId' = 176643 - VENUE_RESTAURANT_DINER_PLAYER: 'CommonSituationJobId' = 132719 - VENUE_RESTAURANT_PLAYER_GROUP_IDLE: 'CommonSituationJobId' = 135262 - VENUE_STUDENT_COMMONS_ARTS_MIXER_JUICE_KEG_BEARER: 'CommonSituationJobId' = 222054 - VENUE_STUDENT_COMMONS_ARTS_MIXER_MASCOT: 'CommonSituationJobId' = 229957 - VENUE_STUDENT_COMMONS_ARTS_MIXER_STUDENT: 'CommonSituationJobId' = 222134 - VENUE_STUDENT_COMMONS_ARTS_POETRY_CONTESTANT: 'CommonSituationJobId' = 221663 - VENUE_STUDENT_COMMONS_ARTS_POETRY_CONTESTANT_PLAYER: 'CommonSituationJobId' = 221589 - VENUE_STUDENT_COMMONS_ARTS_POETRY_PLAYER_CONTROLLER: 'CommonSituationJobId' = 221628 - VENUE_STUDENT_COMMONS_ARTS_POETRY_TEA_SERVER: 'CommonSituationJobId' = 221800 - VENUE_STUDENT_COMMONS_EXAM_CRAM_PLAYER: 'CommonSituationJobId' = 222192 - VENUE_STUDENT_COMMONS_MIXER_PROFESSOR: 'CommonSituationJobId' = 222136 - VENUE_STUDENT_COMMONS_PROFESSOR_ARTS_GOOD: 'CommonSituationJobId' = 219265 - VENUE_STUDENT_COMMONS_PROFESSOR_ARTS_GRUMPY: 'CommonSituationJobId' = 219264 - VENUE_STUDENT_COMMONS_PROFESSOR_ARTS_HIP: 'CommonSituationJobId' = 219263 - VENUE_STUDENT_COMMONS_PROFESSOR_ARTS_SMART: 'CommonSituationJobId' = 226916 - VENUE_STUDENT_COMMONS_PROFESSOR_SCIENCE_GOOD: 'CommonSituationJobId' = 219267 - VENUE_STUDENT_COMMONS_PROFESSOR_SCIENCE_GRUMPY: 'CommonSituationJobId' = 219268 - VENUE_STUDENT_COMMONS_PROFESSOR_SCIENCE_HIP: 'CommonSituationJobId' = 219269 - VENUE_STUDENT_COMMONS_PROFESSOR_SCIENCE_SMART: 'CommonSituationJobId' = 226915 - VENUE_STUDENT_COMMONS_SCIENCE_E_SPORTS_CONTESTANT: 'CommonSituationJobId' = 221664 - VENUE_STUDENT_COMMONS_SCIENCE_E_SPORTS_EXPERT_CONTESTANT: 'CommonSituationJobId' = 221971 - VENUE_STUDENT_COMMONS_SCIENCE_MIXER_JUICE_KEG_BEARER: 'CommonSituationJobId' = 220377 - VENUE_STUDENT_COMMONS_SCIENCE_MIXER_MASCOT: 'CommonSituationJobId' = 229952 - VENUE_STUDENT_COMMONS_SCIENCE_MIXER_PROFESSOR: 'CommonSituationJobId' = 230396 - VENUE_STUDENT_COMMONS_SCIENCE_MIXER_STUDENT: 'CommonSituationJobId' = 222135 - VENUE_STUDENT_COMMONS_STUDENTS_ARTS: 'CommonSituationJobId' = 219230 - VENUE_STUDENT_COMMONS_STUDENTS_SCIENCE: 'CommonSituationJobId' = 219231 - VENUE_STUDENT_COMMONS_VISITORS_ARTS: 'CommonSituationJobId' = 219232 - VENUE_STUDENT_COMMONS_VISITORS_SCIENCE: 'CommonSituationJobId' = 219233 - VENUE_WAITER: 'CommonSituationJobId' = 130418 - VET_EMPLOYEE: 'CommonSituationJobId' = 165162 - VET_PET: 'CommonSituationJobId' = 164710 - VET_PET_EXAM: 'CommonSituationJobId' = 170927 - VET_PET_OWNER: 'CommonSituationJobId' = 164711 - VET_PLAYER: 'CommonSituationJobId' = 168071 - VET_PLAYER_PET_EXAM: 'CommonSituationJobId' = 174920 - VET_VENDING_MACHINE_CUSTOMER: 'CommonSituationJobId' = 172630 - VISITOR: 'CommonSituationJobId' = 16182 - VISITOR_PET: 'CommonSituationJobId' = 175547 - VISITOR_ROOMMATE: 'CommonSituationJobId' = 196885 - VOODOO_SUMMONED: 'CommonSituationJobId' = 40531 - WALKER_BEAR: 'CommonSituationJobId' = 104590 - WALKER_CAMPING_FOREST: 'CommonSituationJobId' = 106140 - WALKER_CITY_LIFE_APARTMENT_NEIGHBOR_VISITOR_COME_FROM_APT: 'CommonSituationJobId' = 141055 - WALKER_CITY_LIFE_APARTMENT_NEIGHBOR_VISITOR_GO_TO_APT: 'CommonSituationJobId' = 141054 - WALKER_CITY_LIFE_COFFEE_DRINKER: 'CommonSituationJobId' = 134352 - WALKER_CITY_LIFE_COMMUTER: 'CommonSituationJobId' = 134353 - WALKER_CITY_LIFE_COMMUTER_APARTMENT_NEIGHBOR_SCHOOL_COME_FROM_APT: 'CommonSituationJobId' = 139560 - WALKER_CITY_LIFE_COMMUTER_APARTMENT_NEIGHBOR_SCHOOL_GO_TO_APT: 'CommonSituationJobId' = 141047 - WALKER_CITY_LIFE_COMMUTER_APARTMENT_NEIGHBOR_WORK_COME_FROM_APT: 'CommonSituationJobId' = 139556 - WALKER_CITY_LIFE_COMMUTER_APARTMENT_NEIGHBOR_WORK_GO_TO_APT: 'CommonSituationJobId' = 141048 - WALKER_CITY_LIFE_LIVES_ON_STREET: 'CommonSituationJobId' = 155986 - WALKER_CITY_LIFE_PHONE_CHATTER: 'CommonSituationJobId' = 134355 - WALKER_CITY_LIFE_SNACKER: 'CommonSituationJobId' = 134354 - WALKER_CLOWN: 'CommonSituationJobId' = 97228 - WALKER_CRIMINAL: 'CommonSituationJobId' = 97224 - WALKER_DESERT_OASIS: 'CommonSituationJobId' = 9484 - WALKER_DOG_BEING_WALKED: 'CommonSituationJobId' = 133588 - WALKER_GARDENER: 'CommonSituationJobId' = 196906 - WALKER_GARDENER_TO_LOT: 'CommonSituationJobId' = 200555 - WALKER_GARDEN_DISTRICT: 'CommonSituationJobId' = 9485 - WALKER_GARDEN_DISTRICT_FAMILY_TIME: 'CommonSituationJobId' = 36749 - WALKER_GARDEN_DISTRICT_ON_THE_TOWN: 'CommonSituationJobId' = 36748 - WALKER_GARDEN_DISTRICT_PARK_AFTER_DARK: 'CommonSituationJobId' = 36772 - WALKER_GARDEN_DISTRICT_PARK_JOGGER: 'CommonSituationJobId' = 36773 - WALKER_GARDEN_DISTRICT_PARK_PLAY_TIME: 'CommonSituationJobId' = 36771 - WALKER_GARDEN_DISTRICT_PARK_RELAXER: 'CommonSituationJobId' = 36775 - WALKER_GARDEN_DISTRICT_PARK_STREAKER: 'CommonSituationJobId' = 238444 - WALKER_GARDEN_DISTRICT_SCHOOL_COMMUTER: 'CommonSituationJobId' = 36744 - WALKER_GARDEN_DISTRICT_WORK_COMMUTER: 'CommonSituationJobId' = 36732 - WALKER_HOT_DOG: 'CommonSituationJobId' = 97231 - WALKER_JOB: 'CommonSituationJobId' = 16183 - WALKER_JUNGLE_STRAY_CAT: 'CommonSituationJobId' = 181416 - WALKER_JUNGLE_STRAY_DOG: 'CommonSituationJobId' = 181417 - WALKER_MAID: 'CommonSituationJobId' = 97236 - WALKER_MAID_TO_LOT: 'CommonSituationJobId' = 200553 - WALKER_NEIGHBOR: 'CommonSituationJobId' = 120058 - WALKER_NEIGHBOR_PARK_JOGGER: 'CommonSituationJobId' = 126209 - WALKER_NEIGHBOR_SCHOOL_COMMUTER: 'CommonSituationJobId' = 126177 - WALKER_PET_WORLD_DOG_WALKERS_DOG: 'CommonSituationJobId' = 168142 - WALKER_PET_WORLD_DOG_WALKERS_WALKER: 'CommonSituationJobId' = 168143 - WALKER_PET_WORLD_GHOST_CAT: 'CommonSituationJobId' = 164210 - WALKER_PET_WORLD_GHOST_DOG: 'CommonSituationJobId' = 164209 - WALKER_PET_WORLD_GHOST_DOG_LIGHTHOUSE: 'CommonSituationJobId' = 175691 - WALKER_PET_WORLD_SIM_BEACH_JOGGER: 'CommonSituationJobId' = 164199 - WALKER_PET_WORLD_SIM_BEACH_WALKER: 'CommonSituationJobId' = 164200 - WALKER_PET_WORLD_SIM_WORKER: 'CommonSituationJobId' = 163998 - WALKER_PET_WORLD_STRAY_CAT: 'CommonSituationJobId' = 164205 - WALKER_PET_WORLD_STRAY_CAT_FISHER: 'CommonSituationJobId' = 164207 - WALKER_PET_WORLD_STRAY_CAT_IN_HEAT: 'CommonSituationJobId' = 164206 - WALKER_PET_WORLD_STRAY_CAT_ON_LOT: 'CommonSituationJobId' = 178581 - WALKER_PET_WORLD_STRAY_DOG: 'CommonSituationJobId' = 164203 - WALKER_PET_WORLD_STRAY_DOG_IN_HEAT: 'CommonSituationJobId' = 164204 - WALKER_PET_WORLD_STRAY_DOG_ON_LOT: 'CommonSituationJobId' = 178589 - WALKER_PIZZA: 'CommonSituationJobId' = 97237 - WALKER_RENT_DUE_APARTMENT_LANDLORD: 'CommonSituationJobId' = 143687 - WALKER_REPAIRMAN: 'CommonSituationJobId' = 197789 - WALKER_REPAIRMAN_TO_LOT: 'CommonSituationJobId' = 200557 - WALKER_RING_DOORBELL_ACQUIRED_FAMILY_REL_BIT: 'CommonSituationJobId' = 164640 - WALKER_RING_DOORBELL_NEIGHBOR: 'CommonSituationJobId' = 100054 - WALKER_RING_DOORBELL_VAMPIRE: 'CommonSituationJobId' = 153168 - WALKER_RING_DOORBELL_WITH_RELATIONSHIP: 'CommonSituationJobId' = 40341 - WALKER_TEEN: 'CommonSituationJobId' = 160243 - WALKER_VAMPIRE: 'CommonSituationJobId' = 153740 - WALKER_VAMPIRE_HAS_HOME: 'CommonSituationJobId' = 156392 - WALKER_WALK_OF_SHAME: 'CommonSituationJobId' = 76150 - WALKER_WINDENBURG: 'CommonSituationJobId' = 9486 - WALK_BY_ALIEN: 'CommonSituationJobId' = 113924 - WALK_BY_ALIEN_IN_DISGUISE: 'CommonSituationJobId' = 116921 - WALK_BY_CELEBRITY_HANG_OUT_HIGH_FAME: 'CommonSituationJobId' = 191718 - WALK_BY_CELEBRITY_HANG_OUT_HIGH_FAME_YAE: 'CommonSituationJobId' = 202103 - WALK_BY_CELEBRITY_HANG_OUT_LOW_FAME: 'CommonSituationJobId' = 191719 - WALK_BY_CELEBRITY_HANG_OUT_LOW_FAME_YAE: 'CommonSituationJobId' = 202104 - WALK_BY_ECO_WORLD_FREEGAN: 'CommonSituationJobId' = 236937 - WALK_BY_ECO_WORLD_VOTER_WALK_BY: 'CommonSituationJobId' = 234197 - WALK_BY_EVENT_FALL_CHALLENGE_2016_DO_TD_CELEBRATOR: 'CommonSituationJobId' = 153130 - WALK_BY_EVENT_SPRING_CHALLENGE_PLANT_SIM_NPC: 'CommonSituationJobId' = 163058 - WALK_BY_FAKE_VAMPIRE: 'CommonSituationJobId' = 153770 - WALK_BY_FAME_WORLD_CELEBRITY_LEAVE_HOME: 'CommonSituationJobId' = 196918 - WALK_BY_FAME_WORLD_CELEBRITY_RETURN_HOME: 'CommonSituationJobId' = 196919 - WALK_BY_FAME_WORLD_PAPARAZZI: 'CommonSituationJobId' = 200337 - WALK_BY_FAME_WORLD_RESIDENTS_SCHOOL_LEAVE_HOME: 'CommonSituationJobId' = 196881 - WALK_BY_FAME_WORLD_RESIDENTS_SCHOOL_RETURN_HOME: 'CommonSituationJobId' = 196886 - WALK_BY_FAME_WORLD_RESIDENTS_WORK_LEAVE_HOME: 'CommonSituationJobId' = 196817 - WALK_BY_FAME_WORLD_RESIDENTS_WORK_RETURN_HOME: 'CommonSituationJobId' = 196818 - WALK_BY_FAME_WORLD_STUDIO_ACTOR: 'CommonSituationJobId' = 197814 - WALK_BY_FAME_WORLD_STUDIO_ASSISTANT: 'CommonSituationJobId' = 197788 - WALK_BY_FAME_WORLD_TOURIST: 'CommonSituationJobId' = 201115 - WALK_BY_ISLANDER: 'CommonSituationJobId' = 216000 - WALK_BY_ISLANDER_JOGGER: 'CommonSituationJobId' = 216137 - WALK_BY_ISLANDER_LOUNGER: 'CommonSituationJobId' = 216537 - WALK_BY_ISLANDER_TEEN: 'CommonSituationJobId' = 216147 - WALK_BY_JUNGLE_CHILD: 'CommonSituationJobId' = 181345 - WALK_BY_JUNGLE_TYAE: 'CommonSituationJobId' = 181344 - WALK_BY_MAGIC_DUELIST: 'CommonSituationJobId' = 216809 - WALK_BY_MAGIC_PORTAL_GO_TO_PORTAL: 'CommonSituationJobId' = 217141 - WALK_BY_MAGIC_PORTAL_LEAVE_PORTAL: 'CommonSituationJobId' = 217139 - WALK_BY_POLICE_PATROL: 'CommonSituationJobId' = 112412 - WALK_BY_RING_DOORBELL_MAX_FAMILY_REL_BIT: 'CommonSituationJobId' = 168417 - WALK_BY_SCOUTING: 'CommonSituationJobId' = 188543 - WALK_BY_SEASONAL_FALL: 'CommonSituationJobId' = 184890 - WALK_BY_SEASONAL_SPRING: 'CommonSituationJobId' = 184888 - WALK_BY_SEASONAL_SUMMER: 'CommonSituationJobId' = 184889 - WALK_BY_SEASONAL_WINTER: 'CommonSituationJobId' = 184891 - WALK_BY_STRANGER_VILLE_CONSPIRACIST: 'CommonSituationJobId' = 203308 - WALK_BY_STRANGER_VILLE_CONSPIRACIST_LIBRARY: 'CommonSituationJobId' = 207322 - WALK_BY_STRANGER_VILLE_INFECTED: 'CommonSituationJobId' = 203974 - WALK_BY_STRANGER_VILLE_MILITARY: 'CommonSituationJobId' = 203293 - WALK_BY_STRANGER_VILLE_MILITARY_BAR: 'CommonSituationJobId' = 207323 - WALK_BY_STRANGER_VILLE_OGA: 'CommonSituationJobId' = 203307 - WALK_BY_STRANGER_VILLE_SCIENTIST: 'CommonSituationJobId' = 203294 - WALK_BY_STRANGER_VILLE_SCIENTIST_LIBRARY: 'CommonSituationJobId' = 207324 - WALK_BY_SURPRISE_HOLIDAY_PIRATE_DAY: 'CommonSituationJobId' = 182814 - WALK_BY_TRAGIC_CLOWN: 'CommonSituationJobId' = 139892 - WALK_BY_UNIVERSITY_STUDENT_HANGOUT_ARTS_STUDENT: 'CommonSituationJobId' = 225745 - WALK_BY_UNIVERSITY_STUDENT_HANGOUT_PROFESSOR: 'CommonSituationJobId' = 225747 - WALK_BY_UNIVERSITY_STUDENT_HANGOUT_SCIENCE_PROFESSOR: 'CommonSituationJobId' = 230611 - WALK_BY_UNIVERSITY_STUDENT_HANGOUT_SCIENCE_STUDENT: 'CommonSituationJobId' = 225746 - WALK_BY_UNIVERSITY_WORLD_ARTS_FROM_ARENA_ATHLETE_E_SPORTS: 'CommonSituationJobId' = 222568 - WALK_BY_UNIVERSITY_WORLD_ARTS_FROM_ARENA_ATHLETE_SOCCER: 'CommonSituationJobId' = 222569 - WALK_BY_UNIVERSITY_WORLD_ARTS_FROM_ARENA_MASCOT: 'CommonSituationJobId' = 222864 - WALK_BY_UNIVERSITY_WORLD_ARTS_FROM_ARENA_SPORTS_FAN_E_SPORTS: 'CommonSituationJobId' = 222570 - WALK_BY_UNIVERSITY_WORLD_ARTS_FROM_ARENA_SPORTS_FAN_SOCCER: 'CommonSituationJobId' = 222571 - WALK_BY_UNIVERSITY_WORLD_ARTS_FROM_CLASS_BIKE_STUDENT: 'CommonSituationJobId' = 222818 - WALK_BY_UNIVERSITY_WORLD_ARTS_FROM_CLASS_PROFESSOR: 'CommonSituationJobId' = 222574 - WALK_BY_UNIVERSITY_WORLD_ARTS_FROM_CLASS_STUDENT: 'CommonSituationJobId' = 222573 - WALK_BY_UNIVERSITY_WORLD_ARTS_SCHOOL_GHOST: 'CommonSituationJobId' = 222757 - WALK_BY_UNIVERSITY_WORLD_ARTS_TO_ARENA_ATHLETE_E_SPORTS: 'CommonSituationJobId' = 222549 - WALK_BY_UNIVERSITY_WORLD_ARTS_TO_ARENA_ATHLETE_SOCCER: 'CommonSituationJobId' = 222552 - WALK_BY_UNIVERSITY_WORLD_ARTS_TO_ARENA_MASCOT: 'CommonSituationJobId' = 222863 - WALK_BY_UNIVERSITY_WORLD_ARTS_TO_ARENA_SPORTS_FAN_E_SPORTS: 'CommonSituationJobId' = 222550 - WALK_BY_UNIVERSITY_WORLD_ARTS_TO_ARENA_SPORTS_FAN_SOCCER: 'CommonSituationJobId' = 222551 - WALK_BY_UNIVERSITY_WORLD_ARTS_TO_CLASS_BIKE_STUDENT: 'CommonSituationJobId' = 222816 - WALK_BY_UNIVERSITY_WORLD_ARTS_TO_CLASS_PROFESSOR: 'CommonSituationJobId' = 222581 - WALK_BY_UNIVERSITY_WORLD_ARTS_TO_CLASS_STUDENT: 'CommonSituationJobId' = 222582 - WALK_BY_UNIVERSITY_WORLD_GENERAL_ARTS_BIKE_STUDENT: 'CommonSituationJobId' = 228134 - WALK_BY_UNIVERSITY_WORLD_GENERAL_ARTS_STUDENT: 'CommonSituationJobId' = 222662 - WALK_BY_UNIVERSITY_WORLD_GENERAL_PROFESSOR: 'CommonSituationJobId' = 222664 - WALK_BY_UNIVERSITY_WORLD_GENERAL_SCIENCE_BIKE_STUDENT: 'CommonSituationJobId' = 228135 - WALK_BY_UNIVERSITY_WORLD_GENERAL_SCIENCE_STUDENT: 'CommonSituationJobId' = 222663 - WALK_BY_UNIVERSITY_WORLD_SCIENCE_FROM_ARENA_ATHLETE_E_SPORTS: 'CommonSituationJobId' = 222616 - WALK_BY_UNIVERSITY_WORLD_SCIENCE_FROM_ARENA_ATHLETE_SOCCER: 'CommonSituationJobId' = 222617 - WALK_BY_UNIVERSITY_WORLD_SCIENCE_FROM_ARENA_MASCOT: 'CommonSituationJobId' = 222861 - WALK_BY_UNIVERSITY_WORLD_SCIENCE_FROM_ARENA_SPORTS_FAN_E_SPORTS: 'CommonSituationJobId' = 222618 - WALK_BY_UNIVERSITY_WORLD_SCIENCE_FROM_ARENA_SPORTS_FAN_SOCCER: 'CommonSituationJobId' = 222619 - WALK_BY_UNIVERSITY_WORLD_SCIENCE_FROM_CLASS_BIKE_STUDENT: 'CommonSituationJobId' = 222815 - WALK_BY_UNIVERSITY_WORLD_SCIENCE_FROM_CLASS_PROFESSOR: 'CommonSituationJobId' = 222621 - WALK_BY_UNIVERSITY_WORLD_SCIENCE_FROM_CLASS_STUDENT: 'CommonSituationJobId' = 222622 - WALK_BY_UNIVERSITY_WORLD_SCIENCE_TO_ARENA_ATHLETE_E_SPORTS: 'CommonSituationJobId' = 222626 - WALK_BY_UNIVERSITY_WORLD_SCIENCE_TO_ARENA_ATHLETE_SOCCER: 'CommonSituationJobId' = 222627 - WALK_BY_UNIVERSITY_WORLD_SCIENCE_TO_ARENA_MASCOT: 'CommonSituationJobId' = 222862 - WALK_BY_UNIVERSITY_WORLD_SCIENCE_TO_ARENA_SPORTS_FAN_E_SPORTS: 'CommonSituationJobId' = 222628 - WALK_BY_UNIVERSITY_WORLD_SCIENCE_TO_ARENA_SPORTS_FAN_SOCCER: 'CommonSituationJobId' = 222629 - WALK_BY_UNIVERSITY_WORLD_SCIENCE_TO_CLASS_BIKE_STUDENT: 'CommonSituationJobId' = 222814 - WALK_BY_UNIVERSITY_WORLD_SCIENCE_TO_CLASS_PROFESSOR: 'CommonSituationJobId' = 222631 - WALK_BY_UNIVERSITY_WORLD_SCIENCE_TO_CLASS_STUDENT: 'CommonSituationJobId' = 222632 - WALK_BY_WEATHER_RAINING: 'CommonSituationJobId' = 184885 - WALK_BY_WEATHER_SNOWING: 'CommonSituationJobId' = 184886 - WARDROBE_PEDESTAL_STYLIST: 'CommonSituationJobId' = 191613 - WATER_SCOOTER_WALK_BY_JOB: 'CommonSituationJobId' = 209405 - WEDDING_BETROTHED: 'CommonSituationJobId' = 9363 - WELCOME_WAGON_DOOR_KNOCKER_NEIGHBOR: 'CommonSituationJobId' = 119786 - WELCOME_WAGON_DOOR_KNOCKER_NEIGHBOR_INFECTED: 'CommonSituationJobId' = 202804 - WELCOME_WAGON_FRUIT_BEARER_NEIGHBOR: 'CommonSituationJobId' = 119361 - WELCOME_WAGON_FRUIT_BEARER_NEIGHBOR_INFECTED: 'CommonSituationJobId' = 202805 - WELCOME_WAGON_NEW_NEIGHBOR_ACTOR: 'CommonSituationJobId' = 119362 - WELCOME_WAGON_NEW_NEIGHBOR_ACTOR_STRANGE: 'CommonSituationJobId' = 204555 - WELCOME_WAGON_SECRET_AGENT: 'CommonSituationJobId' = 202808 - WELCOME_WAGON_WELCOMING_NEIGHBOR: 'CommonSituationJobId' = 119352 - WELCOME_WAGON_WELCOMING_NEIGHBOR_INFECTED: 'CommonSituationJobId' = 202806 - YOGA_CLASS_MEMBER: 'CommonSituationJobId' = 118131 - YOGA_INSTRUCTOR: 'CommonSituationJobId' = 118130 - YOGA_INSTRUCTOR_IDLE: 'CommonSituationJobId' = 118373 diff --git a/Scripts/s4ap/sims4communitylib/enums/situations_enum.py b/Scripts/s4ap/sims4communitylib/enums/situations_enum.py deleted file mode 100644 index 71247b7..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/situations_enum.py +++ /dev/null @@ -1,1217 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonSituationId(CommonInt): - """Identifiers for vanilla situations. - - """ - INVALID: 'CommonSituationId' = 0 - ACTOR_CAREER_BACKGROUND_ACTOR: 'CommonSituationId' = 191064 - ACTOR_CAREER_BACKGROUND_PRODUCER: 'CommonSituationId' = 191065 - ACTOR_CAREER_CO_STAR1: 'CommonSituationId' = 189568 - ACTOR_CAREER_CO_STAR2: 'CommonSituationId' = 189569 - ACTOR_CAREER_DIRECTOR_COMMERCIAL: 'CommonSituationId' = 197476 - ACTOR_CAREER_DIRECTOR_FILM: 'CommonSituationId' = 197479 - ACTOR_CAREER_DIRECTOR_HIGH_BUDGET_TV: 'CommonSituationId' = 197478 - ACTOR_CAREER_DIRECTOR_LOW_BUDGET_TV: 'CommonSituationId' = 197477 - ACTOR_CAREER_DOLLY_CAMERA_OPERATOR: 'CommonSituationId' = 190522 - ACTOR_CAREER_SINGING_IN_THE_RAIN_CO_STAR1_MALE: 'CommonSituationId' = 190331 - ACTOR_CAREER_SPECIAL_EFFECTS_OPERATOR: 'CommonSituationId' = 192112 - ACTOR_CAREER_STATIONARY_CAMERA_OPERATOR: 'CommonSituationId' = 191287 - ALIEN_BARFLY: 'CommonSituationId' = 122604 - ALIEN_NIGHT: 'CommonSituationId' = 122635 - ALIEN_WORLD_BARFLY: 'CommonSituationId' = 114215 - ALIEN_WORLD_BARTENDER: 'CommonSituationId' = 114212 - ANCHORED_OPEN_STREETS_BONFIRE_THREE_SIMS: 'CommonSituationId' = 126402 - ANCHORED_OPEN_STREETS_BONFIRE_TWO_SIMS: 'CommonSituationId' = 126401 - APARTMENTS_NEIGHBOR_CHECK_MAIL: 'CommonSituationId' = 137329 - APARTMENTS_NEIGHBOR_TRASH_CHUTE_USE: 'CommonSituationId' = 137041 - ARTS_CENTER_VENUE_FORMAL_VIEWER: 'CommonSituationId' = 144897 - ARTS_CENTER_VENUE_GHOST_VIEWER: 'CommonSituationId' = 144898 - ARTS_CENTER_VENUE_MUSICIAN_GUITAR: 'CommonSituationId' = 144843 - ARTS_CENTER_VENUE_MUSICIAN_PIANO: 'CommonSituationId' = 144839 - ARTS_CENTER_VENUE_MUSICIAN_VIOLIN: 'CommonSituationId' = 144844 - ARTS_CENTER_VENUE_PAINTER: 'CommonSituationId' = 144672 - ARTS_CENTER_VENUE_PARTY_MUSICIAN_GUITAR: 'CommonSituationId' = 144883 - ARTS_CENTER_VENUE_PARTY_MUSICIAN_PIANO: 'CommonSituationId' = 144889 - ARTS_CENTER_VENUE_PARTY_MUSICIAN_VIOLIN: 'CommonSituationId' = 144890 - ARTS_CENTER_VENUE_PARTY_PAINTER: 'CommonSituationId' = 144895 - ARTS_CENTER_VENUE_PARTY_VIEWER: 'CommonSituationId' = 144896 - ARTS_CENTER_VENUE_SCULPTOR: 'CommonSituationId' = 144771 - ARTS_CENTER_VENUE_VIEWER: 'CommonSituationId' = 144259 - ARTS_CENTER_VENUE_VIEWER_DRINKER: 'CommonSituationId' = 154450 - ARTS_CENTER_VENUE_YOUNG_MUSICIAN_PIANO: 'CommonSituationId' = 144857 - ARTS_CENTER_VENUE_YOUNG_MUSICIAN_VIOLIN: 'CommonSituationId' = 144845 - ARTS_CENTER_VENUE_YOUNG_PAINTER: 'CommonSituationId' = 144833 - ARTS_CENTER_VENUE_YOUNG_VIEWER: 'CommonSituationId' = 144836 - AUTONOMOUS_HOLIDAY_TRADITION_FLOWER_BUNNY: 'CommonSituationId' = 186910 - AUTONOMOUS_OPEN_STREETS_BBQ: 'CommonSituationId' = 38900 - AUTONOMOUS_OPEN_STREETS_BUSH: 'CommonSituationId' = 126332 - AUTONOMOUS_OPEN_STREETS_BUSH_NEIGHBOR: 'CommonSituationId' = 127058 - AUTONOMOUS_OPEN_STREETS_CITY_LIFE_CITY_REPAIR: 'CommonSituationId' = 144295 - AUTONOMOUS_OPEN_STREETS_CITY_LIFE_LIVES_ON_STREET_ADULT: 'CommonSituationId' = 184969 - AUTONOMOUS_OPEN_STREETS_CITY_LIFE_LIVES_ON_STREET_ADULT_A: 'CommonSituationId' = 134673 - AUTONOMOUS_OPEN_STREETS_CITY_LIFE_LIVES_ON_STREET_ADULT_B: 'CommonSituationId' = 155988 - AUTONOMOUS_OPEN_STREETS_CITY_LIFE_LIVES_ON_STREET_ADULT_C: 'CommonSituationId' = 155989 - AUTONOMOUS_OPEN_STREETS_CITY_LIFE_LIVES_ON_STREET_ADULT_D: 'CommonSituationId' = 155990 - AUTONOMOUS_OPEN_STREETS_CITY_LIFE_LIVES_ON_STREET_CHILD: 'CommonSituationId' = 152483 - AUTONOMOUS_OPEN_STREETS_CITY_LIFE_LIVING_STATUE_BUSKER: 'CommonSituationId' = 134212 - AUTONOMOUS_OPEN_STREETS_CITY_LIFE_TOURIST: 'CommonSituationId' = 134209 - AUTONOMOUS_OPEN_STREETS_CITY_LIFE_WEIRDOS: 'CommonSituationId' = 139837 - AUTONOMOUS_OPEN_STREETS_CITY_LIFE_WEIRDO_BATHROBE_ELDER: 'CommonSituationId' = 145068 - AUTONOMOUS_OPEN_STREETS_CITY_LIFE_WEIRDO_DAY_TIME: 'CommonSituationId' = 134211 - AUTONOMOUS_OPEN_STREETS_CITY_LIFE_WEIRDO_RACCOON: 'CommonSituationId' = 145070 - AUTONOMOUS_OPEN_STREETS_FISH: 'CommonSituationId' = 77048 - AUTONOMOUS_OPEN_STREETS_FISH_NEIGHBOR: 'CommonSituationId' = 127054 - AUTONOMOUS_OPEN_STREETS_GARDEN: 'CommonSituationId' = 38937 - AUTONOMOUS_OPEN_STREETS_JOGGER: 'CommonSituationId' = 40408 - AUTONOMOUS_OPEN_STREETS_MARKET_STALLS_CUSTOMER: 'CommonSituationId' = 180994 - AUTONOMOUS_OPEN_STREETS_MARKET_STALLS_CUSTOMER_ISLANDER: 'CommonSituationId' = 215816 - AUTONOMOUS_OPEN_STREETS_MARKET_STALLS_CUSTOMER_SEASONAL: 'CommonSituationId' = 191323 - AUTONOMOUS_OPEN_STREETS_MASTER_FISHERMAN: 'CommonSituationId' = 40505 - AUTONOMOUS_OPEN_STREETS_MASTER_GARDENER: 'CommonSituationId' = 40367 - AUTONOMOUS_OPEN_STREETS_PAINTER: 'CommonSituationId' = 126202 - AUTONOMOUS_OPEN_STREETS_RESTROOM: 'CommonSituationId' = 40785 - AUTONOMOUS_OPEN_STREETS_SEASONAL_LEAVES: 'CommonSituationId' = 180995 - AUTONOMOUS_OPEN_STREETS_SEASONAL_SKATER: 'CommonSituationId' = 180996 - AUTONOMOUS_OPEN_STREETS_SEASONAL_SKATER_PRO: 'CommonSituationId' = 185769 - AUTONOMOUS_OPEN_STREETS_SEASONAL_SNOW_CHILD: 'CommonSituationId' = 185706 - AUTONOMOUS_OPEN_STREETS_SEASONAL_SNOW_TYAE: 'CommonSituationId' = 181487 - AUTONOMOUS_OPEN_STREETS_TOURIST: 'CommonSituationId' = 122804 - AUTONOMOUS_OPEN_STREET_BRAWL: 'CommonSituationId' = 122806 - AUTONOMOUS_OPEN_STREET_CITY_LIFE_WEIRDO_DAY_TIME_RACCOON: 'CommonSituationId' = 145065 - AUTONOMOUS_OPEN_STREET_CITY_LIFE_WEIRDO_DAY_TIME_TOWELS: 'CommonSituationId' = 145066 - AUTO_SMOKE_PARTY: 'CommonSituationId' = 16184 - BABY_BIRTH_HOSPITAL: 'CommonSituationId' = 112065 - BACKGROUND_CAFE: 'CommonSituationId' = 122313 - BARISTA_VENUE: 'CommonSituationId' = 122314 - BARTENDER_RELAXATION_VENUE: 'CommonSituationId' = 156409 - BARTENDER_RESTAURANT: 'CommonSituationId' = 134881 - BAR_BARFLY: 'CommonSituationId' = 121150 - BAR_BARTENDER: 'CommonSituationId' = 121151 - BAR_BARTENDER_ARTS_CENTER_VENUE: 'CommonSituationId' = 144979 - BAR_BARTENDER_GO_DANCING: 'CommonSituationId' = 128105 - BAR_BARTENDER_JUNGLE: 'CommonSituationId' = 185003 - BAR_BARTENDER_MYSHUNO_MEADOWS: 'CommonSituationId' = 147049 - BAR_COLLEGE_EVENT_ART_SOCIETY_PLAYER: 'CommonSituationId' = 231023 - BAR_COLLEGE_EVENT_DEBATE_ORG_PLAYER: 'CommonSituationId' = 231024 - BAR_COLLEGE_EVENT_HONOR_SOCIETY_PLAYER: 'CommonSituationId' = 231025 - BAR_COLLEGE_EVENT_PARTY_PLAYER: 'CommonSituationId' = 231026 - BAR_COLLEGE_EVENT_PRANK_PLAYER: 'CommonSituationId' = 231027 - BAR_COLLEGE_EVENT_ROBOTICS_PLAYER: 'CommonSituationId' = 231019 - BAR_HAPPY_HOUR: 'CommonSituationId' = 121141 - BASIC_TRAIT_SITUATION_ECO_PERSONALITY_ECO_MASTER: 'CommonSituationId' = 234896 - BASIC_TRAIT_SITUATION_ECO_PERSONALITY_ENTREPRENEUR: 'CommonSituationId' = 234895 - BASIC_TRAIT_SITUATION_ECO_PERSONALITY_MAKER: 'CommonSituationId' = 234894 - BASIC_TRAIT_STRANGERVILLE_NPC_SCIENTIST: 'CommonSituationId' = 206839 - BASIC_TRAIT_STRANGER_VILLE_NPC_CONSPIRACIST: 'CommonSituationId' = 206838 - BASIC_TRAIT_STRANGER_VILLE_NPC_MILITARY: 'CommonSituationId' = 206840 - BASIC_TRAIT_STRANGER_VILLE_NPC_SCIENTIST: 'CommonSituationId' = 2068390186 - BEACH_VENUE_BEACH_COMBER: 'CommonSituationId' = 205294 - BEACH_VENUE_LIFE_GUARD: 'CommonSituationId' = 205296 - BEACH_VENUE_MERFOLK: 'CommonSituationId' = 205293 - BEACH_VENUE_SAND_ARTIST: 'CommonSituationId' = 205295 - BEACH_VENUE_SUN_TANNER_SITUATION: 'CommonSituationId' = 210067 - BEACH_VENUE_SWIMMER: 'CommonSituationId' = 207831 - BEACH_VENUE_TANNER: 'CommonSituationId' = 205292 - BEACH_VENUE_WATER_ENTHUSIAST: 'CommonSituationId' = 205291 - BEAR_BARFLY: 'CommonSituationId' = 126605 - BEAR_NIGHT: 'CommonSituationId' = 126611 - BIRTHDAY_PARTY: 'CommonSituationId' = 31635 - BLACK_AND_WHITE_PARTY: 'CommonSituationId' = 35077 - BOWLING_VENUE_FAMILY_BOWLING: 'CommonSituationId' = 160120 - BOWLING_VENUE_GROUP_2_BOWLING: 'CommonSituationId' = 161096 - BOWLING_VENUE_GROUP_3_BOWLING: 'CommonSituationId' = 161104 - BOWLING_VENUE_GROUP_4_BOWLING: 'CommonSituationId' = 161105 - BOWLING_VENUE_GROUP_BOWLING: 'CommonSituationId' = 160163 - BOWLING_VENUE_TEEN_GROUP_BOWLING: 'CommonSituationId' = 160228 - BOWLING_VENUE_TEEN_HANG_OUT: 'CommonSituationId' = 160164 - BUTLER_SITUATION: 'CommonSituationId' = 145804 - CAFE_BUSINESS_PARTNERS: 'CommonSituationId' = 122325 - CAFE_FRIENDS: 'CommonSituationId' = 122323 - CAFE_GENERIC_CUSTOMER: 'CommonSituationId' = 122309 - CAFE_MEDIA_ADDICT: 'CommonSituationId' = 122319 - CAFE_READER: 'CommonSituationId' = 122320 - CAFE_TO_GO_CUSTOMER: 'CommonSituationId' = 122321 - CALLBACK_TO_LODGING: 'CommonSituationId' = 111723 - CALL_EVENT_NPC_OVER: 'CommonSituationId' = 149685 - CALL_EVENT_NPC_OVER_FALL_CHALLENGE: 'CommonSituationId' = 153349 - CALL_EVENT_NPC_OVER_POSITIVITY_CHALLENGE: 'CommonSituationId' = 198764 - CALL_EVENT_NPC_OVER_SPRING_CHALLENGE: 'CommonSituationId' = 162944 - CAMPFIRE_FOUR_SIMS: 'CommonSituationId' = 106016 - CAMPFIRE_THREE_SIMS: 'CommonSituationId' = 106015 - CAMPFIRE_TWO_SIMS: 'CommonSituationId' = 105947 - CAREER_ACTOR_CAREER_COMMERCIAL_HOSPITAL: 'CommonSituationId' = 192847 - CAREER_ACTOR_CAREER_COMMERCIAL_HOUSE_NICE: 'CommonSituationId' = 193601 - CAREER_ACTOR_CAREER_COMMERCIAL_KIDS: 'CommonSituationId' = 193603 - CAREER_ACTOR_CAREER_COMMERCIAL_PIRATE: 'CommonSituationId' = 192688 - CAREER_ACTOR_CAREER_COMMERCIAL_WESTERN: 'CommonSituationId' = 193599 - CAREER_ACTOR_CAREER_MOVIE_CITY: 'CommonSituationId' = 189158 - CAREER_ACTOR_CAREER_MOVIE_MEDIEVAL: 'CommonSituationId' = 193677 - CAREER_ACTOR_CAREER_MOVIE_PIRATE: 'CommonSituationId' = 193678 - CAREER_ACTOR_CAREER_MOVIE_SUPERHERO: 'CommonSituationId' = 193680 - CAREER_ACTOR_CAREER_MOVIE_VICTORIAN: 'CommonSituationId' = 193679 - CAREER_ACTOR_CAREER_MOVIE_WESTERN: 'CommonSituationId' = 193676 - CAREER_ACTOR_CAREER_TV_HIGH_APOCALYPSE: 'CommonSituationId' = 193646 - CAREER_ACTOR_CAREER_TV_HIGH_HOSPITAL: 'CommonSituationId' = 193647 - CAREER_ACTOR_CAREER_TV_HIGH_POLICE: 'CommonSituationId' = 193650 - CAREER_ACTOR_CAREER_TV_HIGH_VICTORIAN: 'CommonSituationId' = 193649 - CAREER_ACTOR_CAREER_TV_HIGH_WESTERN: 'CommonSituationId' = 193648 - CAREER_ACTOR_CAREER_TV_LOW_HOUSE_LOW: 'CommonSituationId' = 193619 - CAREER_ACTOR_CAREER_TV_LOW_HOUSE_NICE: 'CommonSituationId' = 193617 - CAREER_ACTOR_CAREER_TV_LOW_KIDS: 'CommonSituationId' = 193620 - CAREER_ACTOR_CAREER_TV_LOW_PIRATE: 'CommonSituationId' = 193616 - CAREER_ACTOR_CAREER_TV_LOW_WESTERN: 'CommonSituationId' = 193618 - CAREER_BARFLY: 'CommonSituationId' = 122660 - CAREER_DETECTIVE_APB_PLAYER: 'CommonSituationId' = 115361 - CAREER_DETECTIVE_CRIME_SCENE: 'CommonSituationId' = 108865 - CAREER_DETECTIVE_CRIME_SCENE_PLAYER: 'CommonSituationId' = 115003 - CAREER_DETECTIVE_PATROL: 'CommonSituationId' = 110690 - CAREER_DETECTIVE_POLICE_STATION_CHIEF: 'CommonSituationId' = 116968 - CAREER_DETECTIVE_POLICE_STATION_CRIMINALS: 'CommonSituationId' = 112325 - CAREER_DETECTIVE_POLICE_STATION_NPC_OFFICERS: 'CommonSituationId' = 109998 - CAREER_DOCTOR_AWAY_EVENTS_HOUSE_CALL_PATIENT: 'CommonSituationId' = 114221 - CAREER_DOCTOR_AWAY_EVENTS_OUTBREAK_PATIENT: 'CommonSituationId' = 114222 - CAREER_DOCTOR_AWAY_EVENT_DOCTOR: 'CommonSituationId' = 114242 - CAREER_DOCTOR_HOUSE_CALL_TRIGGER: 'CommonSituationId' = 114186 - CAREER_DOCTOR_NPC_ASSISTANT: 'CommonSituationId' = 112371 - CAREER_DOCTOR_NPC_DOCTOR: 'CommonSituationId' = 112370 - CAREER_DOCTOR_NPC_DOCTOR_DIAGNOSER: 'CommonSituationId' = 116250 - CAREER_DOCTOR_NPC_NURSE: 'CommonSituationId' = 112409 - CAREER_DOCTOR_NPC_ORDERLY: 'CommonSituationId' = 112408 - CAREER_DOCTOR_NPC_PATIENT_ADMITTED: 'CommonSituationId' = 112666 - CAREER_DOCTOR_NPC_PATIENT_ADMITTED_RECLINE: 'CommonSituationId' = 116179 - CAREER_DOCTOR_OUTBREAK_TRIGGER: 'CommonSituationId' = 114271 - CAREER_EVENT_DETECTIVE_CAREER_1: 'CommonSituationId' = 108607 - CAREER_EVENT_DETECTIVE_CAREER_APB_NO_SUSPECT: 'CommonSituationId' = 112177 - CAREER_EVENT_DETECTIVE_CAREER_CLUES_NO_APB_NO_SUSPECT: 'CommonSituationId' = 112176 - CAREER_EVENT_DETECTIVE_CAREER_DAY01: 'CommonSituationId' = 112170 - CAREER_EVENT_DETECTIVE_CAREER_DAY02: 'CommonSituationId' = 112171 - CAREER_EVENT_DETECTIVE_CAREER_DAY03: 'CommonSituationId' = 112172 - CAREER_EVENT_DETECTIVE_CAREER_HAVE_SUSPECT: 'CommonSituationId' = 112173 - CAREER_EVENT_DETECTIVE_CAREER_NO_CASE: 'CommonSituationId' = 112174 - CAREER_EVENT_DETECTIVE_CAREER_NO_CLUES_NO_SUSPECT: 'CommonSituationId' = 112175 - CAREER_EVENT_DOCTOR_CAREER_ROUNDS_HIGH: 'CommonSituationId' = 112606 - CAREER_EVENT_DOCTOR_CAREER_ROUNDS_HIGH_COLLAPSED_PATIENT: 'CommonSituationId' = 115225 - CAREER_EVENT_DOCTOR_CAREER_ROUNDS_HIGH_DELIVER_BABY: 'CommonSituationId' = 115227 - CAREER_EVENT_DOCTOR_CAREER_ROUNDS_HIGH_HOUSE_CALL: 'CommonSituationId' = 114263 - CAREER_EVENT_DOCTOR_CAREER_ROUNDS_HIGH_OUTBREAK: 'CommonSituationId' = 114283 - CAREER_EVENT_DOCTOR_CAREER_ROUNDS_LOW: 'CommonSituationId' = 112628 - CAREER_EVENT_DOCTOR_CAREER_ROUNDS_LOW_SAMPLE_ANALYSIS: 'CommonSituationId' = 115234 - CAREER_EVENT_DOCTOR_CAREER_ROUNDS_MID: 'CommonSituationId' = 108049 - CAREER_EVENT_DOCTOR_CAREER_ROUNDS_MID_COLLAPSED_PATIENT: 'CommonSituationId' = 115231 - CAREER_EVENT_DOCTOR_CAREER_ROUNDS_MID_HOUSE_CALL: 'CommonSituationId' = 114292 - CAREER_EVENT_DOCTOR_CAREER_ROUNDS_MID_SAMPLE_ANALYSIS: 'CommonSituationId' = 115232 - CAREER_EVENT_DOCTOR_CAREER_SOCIALIZE: 'CommonSituationId' = 112664 - CAREER_EVENT_DOCTOR_CAREER_SOCIALIZE_DAY2: 'CommonSituationId' = 115773 - CAREER_EVENT_DOCTOR_UNDERSTAFFED: 'CommonSituationId' = 112676 - CAREER_EVENT_DOCTOR_UNDERSTAFFED_COLLAPSED_PATIENT: 'CommonSituationId' = 116016 - CAREER_EVENT_DOCTOR_UNDERSTAFFED_DELIVER_BABY: 'CommonSituationId' = 116017 - CAREER_EVENT_DOCTOR_UNDERSTAFFED_HOUSE_CALL: 'CommonSituationId' = 114250 - CAREER_EVENT_DOCTOR_UNDERSTAFFED_OUTBREAK: 'CommonSituationId' = 114279 - CAREER_EVENT_SCIENTIST_CAREER_ALIEN_VISIT: 'CommonSituationId' = 113534 - CAREER_EVENT_SCIENTIST_CAREER_ALIEN_WORLD_EVENT: 'CommonSituationId' = 113611 - CAREER_EVENT_SCIENTIST_CAREER_MAIN: 'CommonSituationId' = 112350 - CAREER_EVENT_SCIENTIST_CAREER_SIM_RAY_SURPRISE: 'CommonSituationId' = 113546 - CAREER_EVENT_SCIENTIST_CAREER_SURPRISE_COLLECT: 'CommonSituationId' = 112977 - CAREER_EVENT_SCIENTIST_CAREER_SURPRISE_GOOD_BAD: 'CommonSituationId' = 112743 - CAREGIVER_TODDLER: 'CommonSituationId' = 155917 - CAT_HANGOUT_STRAY_ON_LOT: 'CommonSituationId' = 178578 - CELEBRITY_GUITAR: 'CommonSituationId' = 202414 - CELEBRITY_HANG_OUT_HIGH_FAME: 'CommonSituationId' = 191716 - CELEBRITY_HANG_OUT_HIGH_FAME_YAE: 'CommonSituationId' = 202101 - CELEBRITY_HANG_OUT_LOW_FAME: 'CommonSituationId' = 191715 - CELEBRITY_HANG_OUT_LOW_FAME_YAE: 'CommonSituationId' = 202102 - CELEBRITY_TILE_PLACEMENT_CEREMONY_SITUATION: 'CommonSituationId' = 195786 - CHALET_GARDENS_FLIRTY_COUPLE: 'CommonSituationId' = 126388 - CHALET_GARDENS_PLAYER: 'CommonSituationId' = 127063 - CHARITY_BENEFIT_PARTY_NPC_HOSTED: 'CommonSituationId' = 202445 - CHARITY_BENEFIT_PARTY_SITUATION: 'CommonSituationId' = 197576 - CHEF_SITUATION: 'CommonSituationId' = 131068 - CITY_INVITES_FESTIVALS_ALL_BUY_A_SHIRT: 'CommonSituationId' = 149687 - CITY_INVITES_FESTIVALS_BLOSSOM_DRINK_TEA: 'CommonSituationId' = 138970 - CITY_INVITES_FESTIVALS_BLOSSOM_KISS: 'CommonSituationId' = 138971 - CITY_INVITES_FESTIVALS_BLOSSOM_MEET_PEOPLE: 'CommonSituationId' = 138951 - CITY_INVITES_FESTIVALS_BLOSSOM_PAINT: 'CommonSituationId' = 138950 - CITY_INVITES_FESTIVALS_BLOSSOM_THROW_PETALS: 'CommonSituationId' = 138949 - CITY_INVITES_FESTIVALS_FLEA_MARKET_BUY_SOMETHING: 'CommonSituationId' = 138973 - CITY_INVITES_FESTIVALS_FLEA_MARKET_HAGGLE: 'CommonSituationId' = 138972 - CITY_INVITES_FESTIVALS_FLEA_MARKET_WATCH_PERFORMER: 'CommonSituationId' = 138974 - CITY_INVITES_FESTIVALS_FOOD_BLOW_BUBBLES: 'CommonSituationId' = 148686 - CITY_INVITES_FESTIVALS_FOOD_BUY_INGREDIENTS: 'CommonSituationId' = 138953 - CITY_INVITES_FESTIVALS_FOOD_DISCUSS_LOCAL_CUISINE: 'CommonSituationId' = 138975 - CITY_INVITES_FESTIVALS_FOOD_EAT_BURRITO: 'CommonSituationId' = 138969 - CITY_INVITES_FESTIVALS_FOOD_EAT_SPICY: 'CommonSituationId' = 138948 - CITY_INVITES_FESTIVALS_FOOD_HARVEST: 'CommonSituationId' = 138983 - CITY_INVITES_FESTIVALS_FOOD_SAMPLE: 'CommonSituationId' = 138946 - CITY_INVITES_FESTIVALS_FOOD_TRY_CHOPSTICKS_FOOD: 'CommonSituationId' = 149417 - CITY_INVITES_FESTIVALS_LAMP_BUY_SHIRT: 'CommonSituationId' = 138954 - CITY_INVITES_FESTIVALS_LAMP_DRINK_TEA: 'CommonSituationId' = 138956 - CITY_INVITES_FESTIVALS_LAMP_EAT_FOOD: 'CommonSituationId' = 138978 - CITY_INVITES_FESTIVALS_LAMP_LIGHT_FIREWORKS: 'CommonSituationId' = 149688 - CITY_INVITES_FESTIVALS_LAMP_WATCH_FIREWORKS: 'CommonSituationId' = 138955 - CITY_INVITES_FESTIVALS_LOGIC_BUILD_ROCKET: 'CommonSituationId' = 138952 - CITY_INVITES_FESTIVALS_LOGIC_MOTION_GAMING: 'CommonSituationId' = 138979 - CITY_INVITES_FESTIVALS_LOGIC_OBSERVATORY: 'CommonSituationId' = 138982 - CITY_INVITES_FESTIVALS_LOGIC_PARTICIPATE_IN_CONTEST: 'CommonSituationId' = 138977 - CITY_INVITES_FESTIVALS_LOGIC_PROGRAM: 'CommonSituationId' = 138981 - CITY_INVITES_VENUE_INVITES_BAR: 'CommonSituationId' = 138976 - CITY_INVITES_VENUE_INVITES_GYM: 'CommonSituationId' = 138980 - CITY_INVITES_VENUE_INVITES_KARAOKE: 'CommonSituationId' = 142958 - CITY_INVITES_VENUE_INVITES_PARK: 'CommonSituationId' = 142959 - CIVIC_INSPECTOR_SITUATION: 'CommonSituationId' = 233261 - CLUB_GATHERING_SITUATION: 'CommonSituationId' = 122304 - COLLEGE_ORGANIZATIONS_EVENTS_SCHOOL_SPIRIT_DAY_MASCOT: 'CommonSituationId' = 208840 - COLLEGE_ORGANIZATIONS_EVENTS_SCHOOL_SPIRIT_PARTY_GAME_DAY_PARTY: 'CommonSituationId' = 208839 - COLLEGE_ORGANIZATIONS_EVENTS_SCHOOL_SPIRIT_PARTY_SCHOOL_SPIRIT_DAY: 'CommonSituationId' = 208838 - COLLEGE_ORGANIZATIONS_EVENTS_SCHOOL_SPIRIT_PRANK_ARTS_MASCOT: 'CommonSituationId' = 223449 - COLLEGE_ORGANIZATIONS_EVENTS_SCHOOL_SPIRIT_PRANK_SCIENCE_MASCOT: 'CommonSituationId' = 223450 - COLLEGE_ORGANIZATIONS_SMALL_EVENTS_STUDY_GROUP: 'CommonSituationId' = 209035 - COLLEGE_ORGANIZATION_PLAYER_DEBATE: 'CommonSituationId' = 225827 - COLLEGE_ORGANIZATION_PLAYER_DEBATE_PRACTICE: 'CommonSituationId' = 230075 - COLLEGE_ORGANIZATION_PLAYER_ROBOTICS_EXHIBITION: 'CommonSituationId' = 223860 - COLLEGE_ORGANIZATION_PLAYER_ROBOT_BUILDING_SESSION: 'CommonSituationId' = 225320 - COLLEGE_ORGANIZATION_PLAYER_SCHOOL_SPIRIT_PARTY_GAME_DAY_PARTY: 'CommonSituationId' = 225054 - COLLEGE_ORGANIZATION_PLAYER_SCHOOL_SPIRIT_PARTY_SCHOOL_SPIRIT_DAY: 'CommonSituationId' = 209367 - COLLEGE_ORGANIZATION_PLAYER_SCHOOL_SPIRIT_PRANK_CREATIVITY_CELEBRATION: 'CommonSituationId' = 223221 - COLLEGE_ORGANIZATION_PLAYER_SCHOOL_SPIRIT_PRANK_GAME_DAY_PARTY: 'CommonSituationId' = 223255 - COLLEGE_ORGANIZATION_PLAYER_SECRET_SOCIETY_RITUAL: 'CommonSituationId' = 223040 - COLLEGE_ORGANIZATION_ROBOTICS_EXHIBITION: 'CommonSituationId' = 223865 - COLLEGE_ORGANIZATION_SCHOOL_SPIRIT_PRANK_CREATIVITY_CELEBRATION: 'CommonSituationId' = 223236 - COLLEGE_ORGANIZATION_SCHOOL_SPIRIT_PRANK_GAME_DAY_PARTY: 'CommonSituationId' = 223248 - COMMUNITY_CLOSENESS_BIRTHDAY_GIFT: 'CommonSituationId' = 235003 - COMMUNITY_CLOSENESS_COMPLAINT: 'CommonSituationId' = 233496 - COMMUNITY_CLOSENESS_HANDY_NEIGHBOR: 'CommonSituationId' = 233495 - COMMUNITY_CLOSENESS_INTRO_TO_CIVIC_POLICIES_ECO_MASTER: 'CommonSituationId' = 237860 - COMMUNITY_CLOSENESS_INTRO_TO_CIVIC_POLICIES_ENTREPRENEUR: 'CommonSituationId' = 238041 - COMMUNITY_CLOSENESS_RANDOM_GIFT: 'CommonSituationId' = 233499 - COMMUNITY_CLOSENESS_SPARE_RECYCLING: 'CommonSituationId' = 233497 - COMMUNITY_CLOSENESS_TRASH_HELP: 'CommonSituationId' = 233498 - COMMUNITY_GARDEN_GARDENER: 'CommonSituationId' = 223951 - COMMUNITY_GROUP_MARKETPLACE_SHOPPER_PARENTS_WITH_CHILD: 'CommonSituationId' = 233879 - COMMUNITY_GROUP_SCROUNGER_WOOHOO: 'CommonSituationId' = 234659 - COMMUNITY_LOT_BOARD_DEBATER: 'CommonSituationId' = 224288 - COMMUNITY_MAKER_SPACE_MENTOR: 'CommonSituationId' = 232581 - COMMUNITY_MAKER_SPACE_RECYCLING_GURU: 'CommonSituationId' = 232582 - COMMUNITY_MARKETPLACE_SHOPPER: 'CommonSituationId' = 233862 - COMMUNITY_MARKET_SHOPPERS: 'CommonSituationId' = 224110 - COMMUNITY_SHARED_CANDLE_CRAFTER: 'CommonSituationId' = 235341 - COMMUNITY_SHARED_CHILD: 'CommonSituationId' = 232580 - COMMUNITY_SHARED_FABRICATOR: 'CommonSituationId' = 232577 - COMMUNITY_SHARED_GARDENER: 'CommonSituationId' = 232071 - COMMUNITY_SHARED_INSECT_FARMER: 'CommonSituationId' = 233423 - COMMUNITY_SHARED_PAINTER: 'CommonSituationId' = 232579 - COMMUNITY_SHARED_SCROUNGER: 'CommonSituationId' = 234655 - COMMUNITY_SHARED_WOODWORKER: 'CommonSituationId' = 232578 - COMPLEX_CLUB_DANCER: 'CommonSituationId' = 123532 - COMPLEX_CLUB_DANCER_SKILLED: 'CommonSituationId' = 123139 - COMPLEX_CLUB_DANCE_PARTY_POOPER: 'CommonSituationId' = 123156 - COMPLEX_CLUB_DJ_AUDIENCE: 'CommonSituationId' = 122997 - COMPLEX_EXPERIMENT: 'CommonSituationId' = 16185 - COSTUME_PARTY: 'CommonSituationId' = 35078 - COUNTDOWN_SITUATION: 'CommonSituationId' = 181148 - CRAFT_SALES_TABLE_OPEN_STREET_SALE: 'CommonSituationId' = 146715 - CRAFT_SALES_TABLE_OPEN_STREET_SALE_CUSTOMER: 'CommonSituationId' = 146713 - CRAFT_SALES_TABLE_YARD_SALE: 'CommonSituationId' = 146680 - CRAFT_SALES_TABLE_YARD_SALE_CUSTOMER: 'CommonSituationId' = 146683 - CREATE_AND_USE_OBJECT_FASHION_STUDIO_TRIPOD_TAKE_PHOTO_OF: 'CommonSituationId' = 216818 - CREATE_AND_USE_OBJECT_FASHION_STUDIO_TRIPOD_TAKE_PHOTO_OF_3_SIMS: 'CommonSituationId' = 217702 - CREATE_AND_USE_OBJECT_FASHION_STUDIO_TRIPOD_TAKE_PHOTO_OF_3_SIMS_SOLO: 'CommonSituationId' = 218299 - CREATE_AND_USE_OBJECT_FASHION_STUDIO_TRIPOD_TAKE_PHOTO_OF_CARRY: 'CommonSituationId' = 217892 - CREATE_AND_USE_OBJECT_FASHION_STUDIO_TRIPOD_TAKE_PHOTO_OF_CARRY_PET: 'CommonSituationId' = 218213 - CREATE_AND_USE_OBJECT_FASHION_STUDIO_TRIPOD_TAKE_PHOTO_OF_PAIRED: 'CommonSituationId' = 218091 - CREATE_AND_USE_OBJECT_FASHION_STUDIO_TRIPOD_TAKE_PHOTO_OF_PAIRED_LARGE_PET: 'CommonSituationId' = 219953 - CREATE_AND_USE_OBJECT_FASHION_STUDIO_TRIPOD_TAKE_PHOTO_OF_SINGLE_SIM: 'CommonSituationId' = 218739 - CREATE_AND_USE_OBJECT_FASHION_STUDIO_TRIPOD_TAKE_PHOTO_WITH_2_SIMS: 'CommonSituationId' = 218016 - CREATE_AND_USE_OBJECT_FASHION_STUDIO_TRIPOD_TAKE_PHOTO_WITH_3_SIMS: 'CommonSituationId' = 218412 - DANCE_BATTLE_SITUATION: 'CommonSituationId' = 128467 - DANCE_TOGETHER_SET_01: 'CommonSituationId' = 128577 - DANCE_TOGETHER_SET_02: 'CommonSituationId' = 129197 - DANCE_TOGETHER_SET_03: 'CommonSituationId' = 129194 - DANCE_TOGETHER_SET_04: 'CommonSituationId' = 129195 - DANCE_TOGETHER_SET_05: 'CommonSituationId' = 129196 - DANCE_TOGETHER_SET_06: 'CommonSituationId' = 129198 - DATE: 'CommonSituationId' = 16193 - DATE_TEEN: 'CommonSituationId' = 76577 - DEBATE_SHOWDOWN_DEBATE: 'CommonSituationId' = 222726 - DEBUG_PARTY: 'CommonSituationId' = 16186 - DETECTIVE_APB: 'CommonSituationId' = 107968 - DETECTIVE_APB_NEUTRAL: 'CommonSituationId' = 109103 - DETECTIVE_POLICE_STATION_ARREST: 'CommonSituationId' = 109132 - DETECTIVE_POLICE_STATION_CIVILIAN: 'CommonSituationId' = 108697 - DINNER_PARTY: 'CommonSituationId' = 16194 - DOG_HANGOUT_STRAY_ON_LOT: 'CommonSituationId' = 178594 - ECO_FOOTPRINT_SUN_RAYS: 'CommonSituationId' = 232861 - ECO_INSPECTOR_SITUATION: 'CommonSituationId' = 231860 - ECO_PERSONALITY_ECO_MASTER: 'CommonSituationId' = 235528 - ECO_PERSONALITY_ENTREPRENEUR: 'CommonSituationId' = 235529 - ECO_PERSONALITY_MAKER: 'CommonSituationId' = 235527 - EMPTY_LOT_NO_PAPARAZZI: 'CommonSituationId' = 197035 - ENSEMBLE_GROUP_CAFE_BUSINESS_MEETING: 'CommonSituationId' = 124925 - ENSEMBLE_GROUP_CAFE_FRIENDS: 'CommonSituationId' = 124926 - EVENT_LOGIC_FESTIVAL_HACKATHON: 'CommonSituationId' = 141300 - EVENT_LOGIC_FESTIVAL_UGT: 'CommonSituationId' = 141142 - E_SPORTS_ASSEMBLE_THE_TEAM: 'CommonSituationId' = 227361 - E_SPORTS_ASSEMBLE_THE_TEAM_ARTS: 'CommonSituationId' = 229679 - FAMILY_MEAL: 'CommonSituationId' = 33906 - FAN_FAN_STAN_FAN_TEEN: 'CommonSituationId' = 202009 - FAN_MEET_AND_GREET: 'CommonSituationId' = 201177 - FAN_STAN_CELEBRITY_SIMS: 'CommonSituationId' = 193803 - FAN_STAN_FAN: 'CommonSituationId' = 194437 - FAN_STAN_FAN_CHILD: 'CommonSituationId' = 201696 - FAN_STAN_STAN: 'CommonSituationId' = 194420 - FEMALE_BARFLY: 'CommonSituationId' = 122617 - FESTIVAL_BARTENDER_BLOSSOM_FESTIVAL: 'CommonSituationId' = 140557 - FESTIVAL_BARTENDER_FOOD_FESTIVAL: 'CommonSituationId' = 140572 - FESTIVAL_BARTENDER_LAMP_FESTIVAL: 'CommonSituationId' = 140559 - FESTIVAL_BLOSSOM_ARTIST: 'CommonSituationId' = 136082 - FESTIVAL_BLOSSOM_CRAFT_SALES_TABLE_VENDOR_PAINTING: 'CommonSituationId' = 153686 - FESTIVAL_BLOSSOM_CRAZY_TEEN: 'CommonSituationId' = 135712 - FESTIVAL_BLOSSOM_FESTIVAL_ROMANTIC_COUPLE: 'CommonSituationId' = 146773 - FESTIVAL_BLOSSOM_GENERAL: 'CommonSituationId' = 140573 - FESTIVAL_BLOSSOM_LOVE_GURU: 'CommonSituationId' = 146774 - FESTIVAL_BLOSSOM_PETAL_HEAD: 'CommonSituationId' = 135711 - FESTIVAL_BLOSSOM_SLEAZE: 'CommonSituationId' = 136236 - FESTIVAL_BLOSSOM_VIEWERS: 'CommonSituationId' = 143728 - FESTIVAL_BUSKER_BLOSSOM: 'CommonSituationId' = 142677 - FESTIVAL_BUSKER_FLEA_MARKET: 'CommonSituationId' = 142722 - FESTIVAL_BUSKER_FOOD: 'CommonSituationId' = 142675 - FESTIVAL_BUSKER_LAMP: 'CommonSituationId' = 142676 - FESTIVAL_FLEA_MARKET_CRAFT_SALES_TABLE_GENERAL_VENDOR: 'CommonSituationId' = 146944 - FESTIVAL_FLEA_MARKET_CRAFT_SALES_TABLE_PAINTING_VENDOR: 'CommonSituationId' = 146943 - FESTIVAL_FLEA_MARKET_GENERAL: 'CommonSituationId' = 140579 - FESTIVAL_FLEA_MARKET_HAGGLERS: 'CommonSituationId' = 142228 - FESTIVAL_FLEA_MARKET_VENDOR: 'CommonSituationId' = 139946 - FESTIVAL_FOOD_BUBBLE_BLOWERS: 'CommonSituationId' = 140104 - FESTIVAL_FOOD_GENERAL: 'CommonSituationId' = 140574 - FESTIVAL_FOOD_OVER_EATER: 'CommonSituationId' = 136423 - FESTIVAL_GARDENER: 'CommonSituationId' = 139615 - FESTIVAL_GUITARIST: 'CommonSituationId' = 134971 - FESTIVAL_LAMP_CONTEST_SITUATION: 'CommonSituationId' = 146802 - FESTIVAL_LAMP_DARK_SIDER: 'CommonSituationId' = 134839 - FESTIVAL_LAMP_DAZER: 'CommonSituationId' = 150997 - FESTIVAL_LAMP_FIREWORK_LIGHTERS: 'CommonSituationId' = 140105 - FESTIVAL_LAMP_GENERAL: 'CommonSituationId' = 140575 - FESTIVAL_LAMP_LIGHT_SIDER: 'CommonSituationId' = 134838 - FESTIVAL_LOGIC_CHESS: 'CommonSituationId' = 141323 - FESTIVAL_LOGIC_COSPLAYER: 'CommonSituationId' = 140789 - FESTIVAL_LOGIC_FAIR_ROCKET_SHIP_WOOHOOERS: 'CommonSituationId' = 142271 - FESTIVAL_LOGIC_GAMERS: 'CommonSituationId' = 140931 - FESTIVAL_LOGIC_GENERAL: 'CommonSituationId' = 140577 - FESTIVAL_LOGIC_ROCKET_SHIP_HOBBYIST: 'CommonSituationId' = 140938 - FESTIVAL_LOGIC_ROCKET_SHIP_USERS: 'CommonSituationId' = 140947 - FESTIVAL_ORGANIZATION_EVENT_PAINTING_IN_THE_PARK_MODEL: 'CommonSituationId' = 227365 - FESTIVAL_ORGANIZATION_EVENT_PAINTING_IN_THE_PARK_PAINTERS: 'CommonSituationId' = 223213 - FESTIVAL_ORGANIZATION_EVENT_PAINTING_IN_THE_PARK_PLAYER: 'CommonSituationId' = 223357 - FESTIVAL_ORGANIZATION_EVENT_TYPE_SECRET_SOCIETY_RITUAL_MEMBER: 'CommonSituationId' = 222542 - FESTIVAL_PLAYER_BLOSSOM_FESTIVAL: 'CommonSituationId' = 140632 - FESTIVAL_PLAYER_FLEA_MARKET: 'CommonSituationId' = 140633 - FESTIVAL_PLAYER_FOOD_FESTIVAL: 'CommonSituationId' = 140634 - FESTIVAL_PLAYER_LAMP_FESTIVAL: 'CommonSituationId' = 140635 - FESTIVAL_PLAYER_LOGIC_FAIR: 'CommonSituationId' = 140636 - FESTIVAL_SERVER: 'CommonSituationId' = 136515 - FESTIVAL_STALL_VENDOR_ARTS_QUAD: 'CommonSituationId' = 228432 - FESTIVAL_STALL_VENDOR_BLOSSOM_FESTIVAL: 'CommonSituationId' = 140568 - FESTIVAL_STALL_VENDOR_FLEA_MARKET: 'CommonSituationId' = 140567 - FESTIVAL_STALL_VENDOR_FOOD_FESTIVAL: 'CommonSituationId' = 140570 - FESTIVAL_STALL_VENDOR_LAMP_FESTIVAL: 'CommonSituationId' = 140569 - FESTIVAL_STALL_VENDOR_LOGIC_FAIR: 'CommonSituationId' = 140571 - FESTIVAL_TRAVEL_WITH_NPC: 'CommonSituationId' = 149285 - FIRE: 'CommonSituationId' = 73821 - FOREST_RANGER_VACATION_ARRIVAL: 'CommonSituationId' = 109025 - GARDENER_SERVICE_SITUATION: 'CommonSituationId' = 130533 - GARDEN_CHALET_FAMILY: 'CommonSituationId' = 126380 - GARDEN_CHALET_GHOST_COUPLE: 'CommonSituationId' = 125461 - GARDEN_CHALET_TOURIST_COUPLE: 'CommonSituationId' = 126350 - GHOST: 'CommonSituationId' = 101846 - GHOST_BARFLY: 'CommonSituationId' = 122619 - GHOST_NIGHT: 'CommonSituationId' = 122623 - GHOST_PETS: 'CommonSituationId' = 165585 - GHOST_STORY_SUMMONED_GHOST: 'CommonSituationId' = 108708 - GO_DANCING_BACKGROUND_PARTY_GOER_SITUATION: 'CommonSituationId' = 123650 - GO_DANCING_BACKGROUND_SITUATION: 'CommonSituationId' = 123649 - GO_DANCING_COMPLEX_CLUB_PARTY_GOER: 'CommonSituationId' = 122998 - GO_DANCING_COMPLEX_CLUB_PARTY_GOER_BLUFFS_ONLY: 'CommonSituationId' = 127427 - GO_DANCING_COMPLEX_CLUB_PARTY_GOER_CHALET_ONLY: 'CommonSituationId' = 127428 - GO_DANCING_COMPLEX_CLUB_PARTY_GOER_NIGHTCLUB_ONLY: 'CommonSituationId' = 127425 - GO_DANCING_COMPLEX_CLUB_PARTY_GOER_RUINS_ONLY: 'CommonSituationId' = 127426 - GREETED_NPC_VISITING_NPC: 'CommonSituationId' = 34412 - GREETED_NPC_VISITING_PLAYER_PET: 'CommonSituationId' = 175544 - GREETED_NPC_VISITING_PLAYER_ROOMMATE: 'CommonSituationId' = 196880 - GREETED_NPC_VISITING_PLAYER_SITUATION: 'CommonSituationId' = 39299 - GREETED_PLAYER_VISITING_NPC: 'CommonSituationId' = 34413 - GRILL_THREE_SIMS: 'CommonSituationId' = 126542 - GRILL_TWO_SIMS: 'CommonSituationId' = 126541 - GRIM_REAPER: 'CommonSituationId' = 16195 - GROUP_SING_HAPPY_BIRTHDAY: 'CommonSituationId' = 188118 - GROUP_SING_JIGGLE_BELLS: 'CommonSituationId' = 188119 - GROUP_SING_JOLLY_FELLOW: 'CommonSituationId' = 188120 - GROUP_SING_MAYZIE: 'CommonSituationId' = 188121 - GROUP_SING_SITUATION: 'CommonSituationId' = 187204 - GUYS_NIGHT: 'CommonSituationId' = 122637 - GYM_PLAYER: 'CommonSituationId' = 122389 - GYM_TRAINER_VENUE: 'CommonSituationId' = 120466 - GYM_VISITOR: 'CommonSituationId' = 120521 - HAIR_MAKE_UP_CHAIR_STYLIST: 'CommonSituationId' = 189456 - HARVEST_FEST_GNOME: 'CommonSituationId' = 181583 - HARVEST_FEST_GNOME_BERSERK: 'CommonSituationId' = 187566 - HIRED_NPC_BARISTA: 'CommonSituationId' = 123735 - HIRED_NPC_BARTENDER: 'CommonSituationId' = 123711 - HIRED_NPC_CATERER: 'CommonSituationId' = 123703 - HIRED_NPC_CATERER_VEGETARIAN: 'CommonSituationId' = 150481 - HIRED_NPC_DJ: 'CommonSituationId' = 123728 - HIRED_NPC_DJ_LEVEL10: 'CommonSituationId' = 124280 - HIRED_NPC_ENTERTAINER_GUITAR: 'CommonSituationId' = 123632 - HIRED_NPC_ENTERTAINER_MIC_COMEDY: 'CommonSituationId' = 123693 - HIRED_NPC_ENTERTAINER_ORGAN: 'CommonSituationId' = 155970 - HIRED_NPC_ENTERTAINER_PIANO: 'CommonSituationId' = 123599 - HIRED_NPC_ENTERTAINER_VIOLIN: 'CommonSituationId' = 123683 - HIRED_NPC_FASHION_SUBJECT: 'CommonSituationId' = 215288 - HIRED_NPC_MAGIC_VENDOR_STALL_BROOM: 'CommonSituationId' = 217636 - HIRED_NPC_MAGIC_VENDOR_STALL_POTION: 'CommonSituationId' = 217847 - HIRED_NPC_MAGIC_VENDOR_STALL_WAND: 'CommonSituationId' = 217848 - HIRED_NPC_STALL_VENDOR: 'CommonSituationId' = 132880 - HIRED_NPC_VENDOR_STALL: 'CommonSituationId' = 143512 - HIRED_NPC_VENDOR_STALL_CAFETERIA_STATION: 'CommonSituationId' = 217903 - HOLIDAY_SITUATION: 'CommonSituationId' = 182317 - HOLIDAY_TRADITIONS_WALK_BYS_FESTIVE_OUTFITS: 'CommonSituationId' = 182161 - HOLIDAY_TRADITIONS_WALK_BYS_FORMAL_OUTFITS: 'CommonSituationId' = 182177 - HOLIDAY_TRADITIONS_WALK_BYS_GHOSTS: 'CommonSituationId' = 182187 - HOLIDAY_TRADITIONS_WALK_BYS_NUDE_SIMS: 'CommonSituationId' = 190698 - HOLIDAY_TRADITIONS_WALK_BYS_TRICK_OR_TREAT: 'CommonSituationId' = 188033 - HOLIDAY_VISITOR_HOLIDAY_TRADITION_FATHER_WINTER: 'CommonSituationId' = 181459 - HOME_CHEF_SITUATION: 'CommonSituationId' = 134741 - HOSPITAL_PATIENT_ADMITTED: 'CommonSituationId' = 112448 - HOSPITAL_PATIENT_ADMITTED_HIGH_LEVEL: 'CommonSituationId' = 114457 - HOSPITAL_PATIENT_DIAGNOSED_BLOATY_HEAD: 'CommonSituationId' = 115279 - HOSPITAL_PATIENT_DIAGNOSED_GAS_AND_GIGGLES: 'CommonSituationId' = 115278 - HOSPITAL_PATIENT_DIAGNOSED_LLAMA_FLU: 'CommonSituationId' = 115277 - HOSPITAL_PATIENT_DIAGNOSED_STARRY_EYES: 'CommonSituationId' = 115276 - HOSPITAL_PATIENT_HIGH_LEVEL: 'CommonSituationId' = 112414 - HOSPITAL_PATIENT_LOW_LEVEL: 'CommonSituationId' = 108587 - HOSPITAL_PATIENT_LOW_LEVEL_CHILD: 'CommonSituationId' = 115642 - HOSPITAL_PATIENT_LOW_LEVEL_ELDER: 'CommonSituationId' = 115974 - HOST_1: 'CommonSituationId' = 132187 - HOUSE_PARTY: 'CommonSituationId' = 33294 - INFECTED_SITUATION: 'CommonSituationId' = 202595 - INVITE_OVER: 'CommonSituationId' = 40353 - INVITE_TO: 'CommonSituationId' = 40714 - INVITE_TO_MAGIC_PORTAL: 'CommonSituationId' = 222413 - ISLANDER_CULTURE_FIRE_BRIGADE: 'CommonSituationId' = 208895 - ISLANDER_CULTURE_NEED_SOMETHING_FIXED: 'CommonSituationId' = 208713 - ISLAND_ANCESTORS: 'CommonSituationId' = 210248 - ISLAND_EVENTS_ONE_STATE_BEACH_BONFIRE_TOWN_LOCAL: 'CommonSituationId' = 205603 - ISLAND_EVENTS_ONE_STATE_FAMILY_FUN_DAY_LOCAL_KID: 'CommonSituationId' = 205599 - ISLAND_EVENTS_ONE_STATE_FAMILY_FUN_DAY_LOCAL_PARENT: 'CommonSituationId' = 205600 - ISLAND_EVENTS_ONE_STATE_FAMILY_FUN_DAY_VENDOR: 'CommonSituationId' = 205598 - ISLAND_EVENTS_ONE_STATE_FLOWERS_AND_MUSIC_MUSICIAN: 'CommonSituationId' = 205602 - ISLAND_EVENTS_ONE_STATE_FLOWERS_AND_MUSIC_TOWN_LOCAL: 'CommonSituationId' = 205601 - ISLAND_EVENTS_ONE_STATE_TOWN_BBQ_ISLAND_COOK: 'CommonSituationId' = 205597 - ISLAND_EVENTS_ONE_STATE_TOWN_BBQ_TOWN_LOCAL: 'CommonSituationId' = 205596 - ISLAND_EVENTS_ONE_STATE_TURTLE_HATCHING_CONSERVATIONIST: 'CommonSituationId' = 205482 - ISLAND_EVENTS_ONE_STATE_TURTLE_HATCHING_FANATIC: 'CommonSituationId' = 205480 - ISLAND_EVENTS_ONE_STATE_TURTLE_HATCHING_LOCALS: 'CommonSituationId' = 205481 - ISLAND_EVENTS_POTLUCK_TOWN_POTLUCK_TOWN_LOCAL: 'CommonSituationId' = 204558 - ISLAND_EVENTS_POTLUCK_TOWN_POTLUCK_TOWN_LOCAL_BONFIRE: 'CommonSituationId' = 214655 - ISLAND_EVENTS_TWO_STATE_FISHING_COMPETITION_CATCH_FISH_WATCH_CEREMONY: 'CommonSituationId' = 208694 - ISLAND_EVENTS_TWO_STATE_FISHING_COMPETITION_VENDOR_ANNOUNCER: 'CommonSituationId' = 208695 - ISLAND_EVENTS_TWO_STATE_ISLAND_CELEBRATION_PAINTER_FIRE_DANCER: 'CommonSituationId' = 204998 - ISLAND_EVENTS_TWO_STATE_ISLAND_CELEBRATION_SAND_ARTIST_MUSICIAN: 'CommonSituationId' = 205641 - ISLAND_EVENTS_TWO_STATE_ISLAND_CELEBRATION_STALL_VENDOR: 'CommonSituationId' = 205639 - ISLAND_EVENTS_TWO_STATE_ISLAND_CELEBRATION_TABLE_VENDOR: 'CommonSituationId' = 205640 - ISLAND_EVENTS_TWO_STATE_ISLAND_CELEBRATION_TOWN_LOCAL: 'CommonSituationId' = 205642 - ISLAND_PRE_WELCOME_WAGON: 'CommonSituationId' = 211430 - ISLAND_SPIRITS_ACTIVE: 'CommonSituationId' = 208519 - ISLAND_SPIRITS_INACTIVE: 'CommonSituationId' = 209377 - ISLAND_WELCOME_WAGON: 'CommonSituationId' = 211431 - JUNGLE_BARFLY: 'CommonSituationId' = 180836 - KARAOKE_BARFLY: 'CommonSituationId' = 138040 - KARAOKE_CAREER_BARFLY: 'CommonSituationId' = 138083 - KARAOKE_CONTEST: 'CommonSituationId' = 138148 - KARAOKE_CONTESTANT: 'CommonSituationId' = 153658 - KARAOKE_DUET: 'CommonSituationId' = 140814 - KARAOKE_DUET_GROUP: 'CommonSituationId' = 150234 - KARAOKE_DUET_SIM: 'CommonSituationId' = 150244 - KARAOKE_HAPPY_HOUR: 'CommonSituationId' = 138114 - KARAOKE_SINGLE: 'CommonSituationId' = 138196 - KAVA_PARTY_SITUATION: 'CommonSituationId' = 206333 - KEG_PARTY: 'CommonSituationId' = 221796 - KNIGHT_BARFLY: 'CommonSituationId' = 129888 - KNIGHT_NIGHT: 'CommonSituationId' = 130282 - LADIES_NIGHT: 'CommonSituationId' = 16196 - LADIES_NIGHTS: 'CommonSituationId' = 122636 - LAMPOON_PARTY_NPC_INVITE: 'CommonSituationId' = 202448 - LAMPOON_PARTY_SITUATION: 'CommonSituationId' = 197831 - LANDLORD: 'CommonSituationId' = 135299 - LEAVE: 'CommonSituationId' = 24196 - LEAVE_NOW_MUST_RUN: 'CommonSituationId' = 24322 - LIBRARY_MUSEUM_VENUE_MENTOR: 'CommonSituationId' = 134234 - LIBRARY_MUSEUM_VENUE_STUDENT: 'CommonSituationId' = 134242 - LIBRARY_VENUE_CHESS_PLAYER: 'CommonSituationId' = 134244 - LIBRARY_VENUE_LIBRARIAN: 'CommonSituationId' = 134232 - LIBRARY_VENUE_READER: 'CommonSituationId' = 134240 - LIBRARY_VENUE_STRANGER_VILLE_CONSPIRACIST: 'CommonSituationId' = 204076 - LIBRARY_VENUE_STRANGER_VILLE_SCIENTIST: 'CommonSituationId' = 204075 - LKG_PARTY: 'CommonSituationId' = 16187 - LOOPING_INTERACTION_SET_THE_TABLE: 'CommonSituationId' = 161838 - LOOPING_INTERACTION_SET_THE_TABLE_AUTONOMOUS: 'CommonSituationId' = 163857 - LOUD_NEIGHBOR_APARTMENT_FIGHT: 'CommonSituationId' = 145041 - LOUD_NEIGHBOR_APARTMENT_MUSIC: 'CommonSituationId' = 138071 - LOUD_NEIGHBOR_APARTMENT_NPC_ANSWER_DOOR_LOUD_FIGHT: 'CommonSituationId' = 145043 - LOUD_NEIGHBOR_APARTMENT_NPC_ANSWER_DOOR_LOUD_MUSIC: 'CommonSituationId' = 138072 - LOUD_NEIGHBOR_APARTMENT_NPC_ANSWER_DOOR_LOUD_WOOHOO: 'CommonSituationId' = 138079 - LOUD_NEIGHBOR_APARTMENT_WOOHOO: 'CommonSituationId' = 138070 - LOUNGE_EVENT_AWARD_CELEBRITY: 'CommonSituationId' = 197816 - LOUNGE_EVENT_AWARD_HOST: 'CommonSituationId' = 197605 - LOUNGE_EVENT_AWARD_PLAYER: 'CommonSituationId' = 197824 - LOUNGE_EVENT_MEET_A_CELEBRITY: 'CommonSituationId' = 197592 - LOUNGE_VENUE_BARFLY: 'CommonSituationId' = 134267 - LOUNGE_VENUE_BARFLY_ELDER: 'CommonSituationId' = 134268 - LOUNGE_VENUE_COMEDIAN_ENTERTAINER: 'CommonSituationId' = 134259 - LOUNGE_VENUE_INSTRUMENT_ENTERTAINER: 'CommonSituationId' = 134341 - MAGIC_DUEL_CHALLENGE: 'CommonSituationId' = 218413 - MAGIC_DUEL_CHALLENGE_ARTIFACT: 'CommonSituationId' = 220266 - MAGIC_DUEL_CHALLENGE_HEATED: 'CommonSituationId' = 220223 - MAGIC_DUEL_CHALLENGE_ITEMS: 'CommonSituationId' = 220268 - MAGIC_DUEL_CHALLENGE_KNOWLEDGE: 'CommonSituationId' = 220267 - MAGIC_HQ_PLAYER: 'CommonSituationId' = 223442 - MAID_SITUATION: 'CommonSituationId' = 16188 - MAILMAN_SITUATION: 'CommonSituationId' = 16189 - MALE_BARFLY: 'CommonSituationId' = 122618 - MASSAGE_THERAPIST_SERVICE_CALL: 'CommonSituationId' = 119133 - MASSAGE_THERAPIST_VENUE: 'CommonSituationId' = 119161 - MEDITATION_TELEPORT_TO: 'CommonSituationId' = 119817 - MEET_WITH_STYLE_INFLUENCER: 'CommonSituationId' = 216216 - MOTHER_PLANT_BATTLE_SITUATION: 'CommonSituationId' = 203311 - MTX_TEST_EVENT: 'CommonSituationId' = 25897 - MUSEUM_VENUE_ARTIST: 'CommonSituationId' = 134377 - MUSEUM_VENUE_PATRON: 'CommonSituationId' = 134376 - MUSEUM_VENUE_PATRON_JUNGLE_NATIVE: 'CommonSituationId' = 185010 - MUSEUM_VENUE_PATRON_JUNGLE_TOURIST: 'CommonSituationId' = 185019 - MYSHUNO_MEADOWS_ADULT_VISITOR: 'CommonSituationId' = 138475 - MYSHUNO_MEADOWS_CHILD_VISITOR: 'CommonSituationId' = 154529 - MYSHUNO_MEADOWS_FISHER: 'CommonSituationId' = 152409 - MYSHUNO_MEADOWS_FORMAL_VISITOR: 'CommonSituationId' = 154539 - MYSHUNO_MEADOWS_INVITE: 'CommonSituationId' = 138476 - MYSHUNO_MEADOWS_JOGGER: 'CommonSituationId' = 155568 - MYSHUNO_MEADOWS_LIVING_STATUE_BUSKER: 'CommonSituationId' = 151393 - MYSHUNO_MEADOWS_WEIRDO: 'CommonSituationId' = 151391 - NANNY_SITUATION: 'CommonSituationId' = 141841 - NATURAL_POOL_SWIMMER_SITUATION: 'CommonSituationId' = 175204 - NPC_HOSTED_BIRTHDAY_PARTY: 'CommonSituationId' = 117360 - NPC_INVITES_ANGRY_TEXT: 'CommonSituationId' = 127298 - NPC_INVITES_BAR_NIGHT: 'CommonSituationId' = 127380 - NPC_INVITES_BAR_NIGHT_ALIENS_NIGHT: 'CommonSituationId' = 128117 - NPC_INVITES_BAR_NIGHT_BEAR_NIGHT: 'CommonSituationId' = 128118 - NPC_INVITES_BAR_NIGHT_GHOSTS_NIGHT: 'CommonSituationId' = 128119 - NPC_INVITES_BAR_NIGHT_GUYS_NIGHT: 'CommonSituationId' = 128120 - NPC_INVITES_BAR_NIGHT_KNIGHT_NIGHT: 'CommonSituationId' = 130365 - NPC_INVITES_BAR_NIGHT_LADIES_NIGHT: 'CommonSituationId' = 128121 - NPC_INVITES_BAR_NIGHT_SINGLES_NIGHT: 'CommonSituationId' = 128122 - NPC_INVITES_CLUB_PARTY: 'CommonSituationId' = 126453 - NPC_INVITES_ENERGIZED_TEXT_GYM: 'CommonSituationId' = 127222 - NPC_INVITES_FAMILY_VENUE: 'CommonSituationId' = 165289 - NPC_INVITES_FLIRTY_TEXT: 'CommonSituationId' = 127278 - NPC_INVITES_HAPPY_TEXT: 'CommonSituationId' = 127242 - NPC_INVITES_INVITE_TO_NPC_HOME: 'CommonSituationId' = 128961 - NPC_INVITES_INVITE_TO_NPC_HOME_FAMILY: 'CommonSituationId' = 165264 - NPC_INVITES_LOUNGE_EVENT: 'CommonSituationId' = 215483 - NPC_INVITES_PLAYFUL_TEXT: 'CommonSituationId' = 127267 - NPC_INVITE_DATE: 'CommonSituationId' = 117059 - NPC_INVITE_DATE_BLIND: 'CommonSituationId' = 201483 - NPC_INVITE_PLAY_DATE: 'CommonSituationId' = 117170 - NPC_INVITE_PLAY_HOOKY: 'CommonSituationId' = 125950 - NPC_INVITE_PROMOTION_PARTY: 'CommonSituationId' = 125930 - NPC_INVITE_RECOMMEND_RESTAURANT: 'CommonSituationId' = 140076 - NPC_INVITE_RESTAURANT_DATE: 'CommonSituationId' = 136713 - NPC_INVITE_RESTAURANT_FRIENDLY: 'CommonSituationId' = 136766 - NPC_INVITE_RESTAURANT_STANDARD: 'CommonSituationId' = 136626 - NPC_SPA_GUEST_ANNOYING: 'CommonSituationId' = 119060 - NPC_SPA_GUEST_BULL: 'CommonSituationId' = 119062 - NPC_SPA_GUEST_CELEBRITY_HIGH_FAME: 'CommonSituationId' = 195410 - NPC_SPA_GUEST_CELEBRITY_LOW_FAME: 'CommonSituationId' = 195428 - NPC_SPA_GUEST_COUPLE_MASSAGE: 'CommonSituationId' = 119306 - NPC_SPA_GUEST_COUPLE_STEAM_ROOM: 'CommonSituationId' = 119503 - NPC_SPA_GUEST_COUPLE_YOGA: 'CommonSituationId' = 119307 - NPC_SPA_GUEST_NORMAL: 'CommonSituationId' = 119059 - NPC_SPA_GUEST_PRANKSTER: 'CommonSituationId' = 119061 - NPC_SPA_GUEST_SNOB: 'CommonSituationId' = 119063 - NPC_SPA_GUEST_VISITOR: 'CommonSituationId' = 129884 - NPC_VISIT_ANY_VENUE: 'CommonSituationId' = 101273 - OPEN_MIC_CONTESTANT_NPC: 'CommonSituationId' = 197205 - OPEN_MIC_CONTESTANT_PLAYER: 'CommonSituationId' = 197206 - OPEN_MIC_CONTESTANT_STUDENT_COMMONS_ARTS_POETRY_NPC: 'CommonSituationId' = 221612 - OPEN_MIC_CONTESTANT_STUDENT_COMMONS_ARTS_POETRY_PLAYER: 'CommonSituationId' = 221613 - OPEN_MIC_PLAYER_CONTROLLER_SITUATION: 'CommonSituationId' = 195976 - OPEN_MIC_PLAYER_CONTROLLER_STUDENT_COMMONS_ARTS_POETRY: 'CommonSituationId' = 221561 - OPEN_STREETS_ALIEN: 'CommonSituationId' = 113847 - OPEN_STREETS_AUTONOMY_CHALET_GARDENS_LONELY: 'CommonSituationId' = 126236 - OPEN_STREETS_AUTONOMY_CHALET_GARDENS_SINGLE_TOURIST: 'CommonSituationId' = 126237 - OPEN_STREETS_AUTONOMY_CHALET_GARDENS_VISITOR: 'CommonSituationId' = 129882 - OPEN_STREETS_AUTONOMY_CITY_LIFE_BASKET_BALLER: 'CommonSituationId' = 184971 - OPEN_STREETS_AUTONOMY_CITY_LIFE_BASKET_BALLER_A: 'CommonSituationId' = 149955 - OPEN_STREETS_AUTONOMY_CITY_LIFE_BASKET_BALLER_B: 'CommonSituationId' = 149968 - OPEN_STREETS_AUTONOMY_CITY_LIFE_MURAL_PAINTER: 'CommonSituationId' = 149970 - OPEN_STREETS_AUTONOMY_EVENT_NPC_CHALLENGE: 'CommonSituationId' = 133756 - OPEN_STREETS_AUTONOMY_FAME_WORLD_CELEBRITY: 'CommonSituationId' = 197063 - OPEN_STREETS_AUTONOMY_FAME_WORLD_TOURIST: 'CommonSituationId' = 196926 - OPEN_STREETS_AUTONOMY_FAME_WORLD_TOURIST_LOT_TRAIT: 'CommonSituationId' = 201123 - OPEN_STREETS_AUTONOMY_ISLAND_FISHERMAN: 'CommonSituationId' = 216171 - OPEN_STREETS_AUTONOMY_ISLAND_WORLD_BEACH_COMBER: 'CommonSituationId' = 210660 - OPEN_STREETS_AUTONOMY_ISLAND_WORLD_MERFOLK: 'CommonSituationId' = 210415 - OPEN_STREETS_AUTONOMY_ISLAND_WORLD_TOWN_VISITOR: 'CommonSituationId' = 210414 - OPEN_STREETS_AUTONOMY_JUNGLE_MARKETPLACE_BROWSER: 'CommonSituationId' = 178171 - OPEN_STREETS_AUTONOMY_JUNGLE_MARKETPLACE_FISH: 'CommonSituationId' = 178117 - OPEN_STREETS_AUTONOMY_JUNGLE_MARKETPLACE_TOURIST_TAKE_PHOTO: 'CommonSituationId' = 178229 - OPEN_STREETS_AUTONOMY_PET_WORLD_STRAY_CAT_FISHER: 'CommonSituationId' = 163983 - OPEN_STREETS_AUTONOMY_PET_WORLD_STRAY_CAT_GHOST: 'CommonSituationId' = 163985 - OPEN_STREETS_AUTONOMY_PET_WORLD_STRAY_CAT_IN_HEAT: 'CommonSituationId' = 163982 - OPEN_STREETS_AUTONOMY_PET_WORLD_STRAY_CAT_JUNGLE: 'CommonSituationId' = 181421 - OPEN_STREETS_AUTONOMY_PET_WORLD_STRAY_CAT_WANDERER: 'CommonSituationId' = 163981 - OPEN_STREETS_AUTONOMY_PET_WORLD_STRAY_DOG_GHOST: 'CommonSituationId' = 163984 - OPEN_STREETS_AUTONOMY_PET_WORLD_STRAY_DOG_IN_HEAT: 'CommonSituationId' = 163980 - OPEN_STREETS_AUTONOMY_PET_WORLD_STRAY_DOG_JUNGLE: 'CommonSituationId' = 181422 - OPEN_STREETS_AUTONOMY_PET_WORLD_STRAY_DOG_WANDERER: 'CommonSituationId' = 163979 - OPEN_STREETS_AUTONOMY_UNIVERSITY_RIVALRY_PRANK_ARTS: 'CommonSituationId' = 226693 - OPEN_STREETS_AUTONOMY_UNIVERSITY_RIVALRY_PRANK_SCIENCE: 'CommonSituationId' = 226710 - OPEN_STREETS_AUTONOMY_UNIVERSITY_WORLD_ARTS_GHOST: 'CommonSituationId' = 222904 - OPEN_STREETS_AUTONOMY_UNIVERSITY_WORLD_ARTS_MASCOT: 'CommonSituationId' = 222870 - OPEN_STREETS_AUTONOMY_UNIVERSITY_WORLD_ARTS_STUDENT: 'CommonSituationId' = 222901 - OPEN_STREETS_AUTONOMY_UNIVERSITY_WORLD_CTYAE_SWIMMER: 'CommonSituationId' = 222841 - OPEN_STREETS_AUTONOMY_UNIVERSITY_WORLD_SCIENCE_MASCOT: 'CommonSituationId' = 222871 - OPEN_STREETS_AUTONOMY_UNIVERSITY_WORLD_SCIENCE_ROBOT: 'CommonSituationId' = 222942 - OPEN_STREETS_AUTONOMY_UNIVERSITY_WORLD_SCIENCE_STUDENT: 'CommonSituationId' = 222902 - OPEN_STREETS_AUTONOMY_UNIVERSITY_WORLD_TOURING_TEEN: 'CommonSituationId' = 222766 - OPEN_STREETS_AUTONOMY_UNIVERSITY_WORLD_YA_SWIMMER: 'CommonSituationId' = 222763 - OPEN_STREETS_BARTENDER: 'CommonSituationId' = 142879 - OPEN_STREETS_CAMPING_FOREST_BEAR: 'CommonSituationId' = 104740 - OPEN_STREETS_CAMPING_FOREST_FISH: 'CommonSituationId' = 106116 - OPEN_STREETS_CAMPING_FOREST_FOREST_GHOST: 'CommonSituationId' = 108333 - OPEN_STREETS_CAMPING_FOREST_FOREST_RANGER: 'CommonSituationId' = 108824 - OPEN_STREETS_CAMPING_FOREST_RANGER_STATION: 'CommonSituationId' = 106119 - OPEN_STREETS_CAMPING_FOREST_RESTROOM: 'CommonSituationId' = 106117 - OPEN_STREETS_CAMPING_FOREST_RESTROOM_SHOWER: 'CommonSituationId' = 110032 - OPEN_STREETS_CHESS: 'CommonSituationId' = 38486 - OPEN_STREETS_ISLAND_LOUNGER: 'CommonSituationId' = 216155 - OPEN_STREETS_LOUNGER: 'CommonSituationId' = 76164 - OPEN_STREETS_NOBODY: 'CommonSituationId' = 77328 - OPEN_STREETS_PLAYGROUND: 'CommonSituationId' = 38307 - OPEN_STREETS_STALL_VENDOR: 'CommonSituationId' = 136915 - OPEN_STREETS_STALL_VENDOR_COFFEE_CART: 'CommonSituationId' = 225986 - OPEN_STREETS_STALL_VENDOR_CURIO_SHOP: 'CommonSituationId' = 202394 - OPEN_STREETS_STALL_VENDOR_ISLAND_WORLD: 'CommonSituationId' = 215326 - OPEN_STREETS_STALL_VENDOR_JUNGLE: 'CommonSituationId' = 182889 - OPEN_STREETS_STALL_VENDOR_MAGIC: 'CommonSituationId' = 216971 - OPEN_STREETS_STALL_VENDOR_MAGIC_POTION: 'CommonSituationId' = 217862 - OPEN_STREETS_STALL_VENDOR_MAGIC_WAND: 'CommonSituationId' = 217863 - OPEN_STREETS_STALL_VENDOR_SEASONAL: 'CommonSituationId' = 191307 - OPEN_STREET_CRAFT_SALES_TABLE_VENDOR: 'CommonSituationId' = 153603 - OPEN_STREET_CRAFT_SALES_TABLE_VENDORS_PAINTINGS: 'CommonSituationId' = 153604 - OPEN_STREET_CRAFT_SALES_TABLE_VENDOR_JUNGLE: 'CommonSituationId' = 177663 - OPEN_STREET_STRANGER_VILLE_CONSPIRACIST_01: 'CommonSituationId' = 203329 - OPEN_STREET_STRANGER_VILLE_CONSPIRACIST_02: 'CommonSituationId' = 206165 - OPEN_STREET_STRANGER_VILLE_CONSPIRACIST_03: 'CommonSituationId' = 206166 - OPEN_STREET_STRANGER_VILLE_INFECTED: 'CommonSituationId' = 203973 - OPEN_STREET_STRANGER_VILLE_OGA_01: 'CommonSituationId' = 203328 - OPEN_STREET_STRANGER_VILLE_OGA_02: 'CommonSituationId' = 206200 - OPEN_STREET_STRANGER_VILLE_OGA_03: 'CommonSituationId' = 206202 - ORGANIZATION_EVENT_STALL_VENDOR_CREATIVITY_CELEBRATION: 'CommonSituationId' = 228429 - ORGANIZATION_EVENT_STALL_VENDOR_ROBOTIC_EXHIBITION: 'CommonSituationId' = 228431 - ORGANIZATION_EVENT_STALL_VENDOR_SCHOOL_SPIRIT_DAY: 'CommonSituationId' = 228430 - PAPARAZZI_LOCK_OUT_SITUATION: 'CommonSituationId' = 200979 - PAPARAZZI_PAPARAZZI: 'CommonSituationId' = 196395 - PAPARAZZI_PAPARAZZI_LOCKED: 'CommonSituationId' = 201019 - PAPARAZZI_PAPARAZZI_UNLOCKED: 'CommonSituationId' = 200991 - PARK_CHESS_PLAYER: 'CommonSituationId' = 124376 - PARK_CHILD_PLAYING: 'CommonSituationId' = 124379 - PARK_DEFAULT: 'CommonSituationId' = 124378 - PARK_GARDENER: 'CommonSituationId' = 124381 - PARK_PLAYER: 'CommonSituationId' = 126602 - PARK_SLEEPER: 'CommonSituationId' = 124377 - PARK_TEEN: 'CommonSituationId' = 124384 - PARK_VISITOR: 'CommonSituationId' = 126603 - PATIENT_EMERGENCY_COLLAPSED_PATIENT: 'CommonSituationId' = 113496 - PATIENT_EMERGENCY_DELIVER_BABY: 'CommonSituationId' = 113524 - PATIENT_EMERGENCY_SAMPLE_ANALYSIS: 'CommonSituationId' = 114096 - PERFORMANCE_SPACE_BUSKER_OPEN_STREET: 'CommonSituationId' = 142719 - PERFORMANCE_SPACE_BUSKER_OPEN_STREET_VIOLIN: 'CommonSituationId' = 156102 - PERFORMANCE_SPACE_HIRED_NPC_BUSKER_GUITAR: 'CommonSituationId' = 142065 - PERFORMANCE_SPACE_HIRED_NPC_BUSKER_VIOLIN: 'CommonSituationId' = 142066 - PET_ADOPTION: 'CommonSituationId' = 166801 - PET_CARE_SELL_ADOPT: 'CommonSituationId' = 169806 - PET_CARE_SELL_ADOPT_SELL: 'CommonSituationId' = 170954 - PET_CARE_SITUATION: 'CommonSituationId' = 164137 - PET_OBSTACLE_COURSE: 'CommonSituationId' = 172224 - PICNIC_TABLE_THREE_SIMS: 'CommonSituationId' = 126174 - PICNIC_TABLE_TWO_SIMS: 'CommonSituationId' = 126161 - PIZZA_DELIVERY_NEW: 'CommonSituationId' = 74299 - PLAYER_ARTS_CENTER_VENUE: 'CommonSituationId' = 148725 - PLAYER_BARFLY: 'CommonSituationId' = 126352 - PLAYER_BARFLY_KARAOKE: 'CommonSituationId' = 138195 - PLAYER_BARFLY_LOUNGE: 'CommonSituationId' = 134424 - PLAYER_PARK_DEFAULT: 'CommonSituationId' = 134437 - PLAYER_PATRON_MUSEUM: 'CommonSituationId' = 134427 - PLAYER_PET_OWNER_CHECK_UP_PET: 'CommonSituationId' = 169163 - PLAYER_PET_OWNER_NEUTER: 'CommonSituationId' = 175468 - PLAYER_PET_OWNER_SICK_PET: 'CommonSituationId' = 169162 - PLAYER_PET_OWNER_SPAY: 'CommonSituationId' = 169864 - PLAYER_PET_OWNER_UNNEUTER: 'CommonSituationId' = 175467 - PLAYER_PET_OWNER_UN_SPAY: 'CommonSituationId' = 169909 - PLAYER_READER_LIBRARY: 'CommonSituationId' = 134431 - PLAYER_SECRET_LAB: 'CommonSituationId' = 204565 - POOL_VENUE_LOUNGER_LOUNGER: 'CommonSituationId' = 125575 - POOL_VENUE_SWIMMER_CHILD_SWIMMER: 'CommonSituationId' = 125572 - POOL_VENUE_SWIMMER_ELDER_SWIMMER: 'CommonSituationId' = 125573 - POOL_VENUE_SWIMMER_GENERIC_SWIMMER: 'CommonSituationId' = 125574 - POOL_VENUE_SWIMMER_PLAYER_SWIMMER: 'CommonSituationId' = 125697 - POOL_VENUE_SWIMMER_VISITOR_SWIMMER: 'CommonSituationId' = 129881 - POSSESSED_SITUATION: 'CommonSituationId' = 202077 - PRESENT_PILE_OPEN_PRESENTS: 'CommonSituationId' = 186232 - PRE_WELCOME_WAGON: 'CommonSituationId' = 156258 - PRE_WELCOME_WAGON_ISLANDER_CULTURE_DEATH_COMFORT: 'CommonSituationId' = 208663 - PRE_WELCOME_WAGON_ISLANDER_CULTURE_EXTRA_FOOD: 'CommonSituationId' = 208434 - PROTEST: 'CommonSituationId' = 136560 - REFLEXOLOGIST_VENUE: 'CommonSituationId' = 119511 - REGULAR_BARFLY: 'CommonSituationId' = 122622 - REPAIR_SITUATION: 'CommonSituationId' = 129479 - REPO_SITUATION: 'CommonSituationId' = 224390 - RESTAURANT_DINER_BACKGROUND_NPC_BAD_DATE: 'CommonSituationId' = 132752 - RESTAURANT_DINER_BACKGROUND_NPC_CELEBRITY_HIGH_FAME: 'CommonSituationId' = 196202 - RESTAURANT_DINER_BACKGROUND_NPC_CELEBRITY_LOW_FAME: 'CommonSituationId' = 196203 - RESTAURANT_DINER_BACKGROUND_NPC_CRITIC: 'CommonSituationId' = 141385 - RESTAURANT_DINER_BACKGROUND_NPC_EARLY_BIRDS: 'CommonSituationId' = 132776 - RESTAURANT_DINER_BACKGROUND_NPC_FAMILY_MEAL: 'CommonSituationId' = 132887 - RESTAURANT_DINER_BACKGROUND_NPC_HAPPY_DATE: 'CommonSituationId' = 132672 - RESTAURANT_DINER_BACKGROUND_NPC_STANDARD: 'CommonSituationId' = 132428 - RESTAURANT_DINER_EVENTS_NPC_BUSINESS_LUNCH: 'CommonSituationId' = 133881 - RESTAURANT_DINER_EVENTS_NPC_COSPLAY_NIGHT: 'CommonSituationId' = 133883 - RESTAURANT_DINER_EVENTS_NPC_DATE_NIGHT: 'CommonSituationId' = 133887 - RESTAURANT_DINER_EVENTS_NPC_EARLY_BIRD_SPECIAL: 'CommonSituationId' = 133882 - RESTAURANT_DINER_EVENTS_NPC_FAMILY_NIGHT: 'CommonSituationId' = 133880 - RESTAURANT_DINER_EVENTS_NPC_GHOST_NIGHT: 'CommonSituationId' = 133885 - RESTAURANT_DINER_EVENTS_NPC_NEARLY_NUDE_NIGHT: 'CommonSituationId' = 133884 - RESTAURANT_DINER_EVENTS_NPC_SPACE_RACE_DAY: 'CommonSituationId' = 133886 - RESTAURANT_DINER_SUB_NPC_BAD_DATE_ANGRY_SIM: 'CommonSituationId' = 132753 - RESTAURANT_DINER_SUB_NPC_BAD_DATE_FLIRTY_SIM: 'CommonSituationId' = 132755 - RESTAURANT_DINER_SUB_NPC_CELEBRITY: 'CommonSituationId' = 196206 - RESTAURANT_DINER_SUB_NPC_CRITIC: 'CommonSituationId' = 141388 - RESTAURANT_DINER_SUB_NPC_EARLY_BIRDS: 'CommonSituationId' = 132777 - RESTAURANT_DINER_SUB_NPC_FAMILY_MEAL_CHILD: 'CommonSituationId' = 132889 - RESTAURANT_DINER_SUB_NPC_FAMILY_MEAL_PARENT: 'CommonSituationId' = 132888 - RESTAURANT_DINER_SUB_NPC_HAPPY_DATE: 'CommonSituationId' = 132674 - RESTAURANT_DINER_SUB_NPC_STANDARD: 'CommonSituationId' = 132503 - RESTAURANT_PLAYER_GROUP: 'CommonSituationId' = 132711 - RESTAURANT_PLAYER_GROUP_IDLE: 'CommonSituationId' = 135258 - RESTAURANT_WAIT_STAFF: 'CommonSituationId' = 132213 - RETAIL_CUSTOMER_BARGAIN_SHOPPER: 'CommonSituationId' = 109145 - RETAIL_CUSTOMER_BARGAIN_SHOPPER_1: 'CommonSituationId' = 115725 - RETAIL_CUSTOMER_CELEBRITY_HANG_OUT_HIGH_FAME: 'CommonSituationId' = 195646 - RETAIL_CUSTOMER_CELEBRITY_HANG_OUT_LOW_FAME: 'CommonSituationId' = 195645 - RETAIL_CUSTOMER_LOITERER: 'CommonSituationId' = 109147 - RETAIL_CUSTOMER_MID_RANGE: 'CommonSituationId' = 109148 - RETAIL_CUSTOMER_MID_RANGE_1: 'CommonSituationId' = 115729 - RETAIL_CUSTOMER_MID_RANGE_2: 'CommonSituationId' = 115730 - RETAIL_CUSTOMER_SOCAILIZER: 'CommonSituationId' = 109146 - RETAIL_CUSTOMER_WEALTHY: 'CommonSituationId' = 109045 - RETAIL_CUSTOMER_WEALTHY_1: 'CommonSituationId' = 115732 - RETAIL_CUSTOMER_WEALTHY_2: 'CommonSituationId' = 115733 - RETAIL_CUSTOMER_WEALTHY_3: 'CommonSituationId' = 115734 - RETAIL_EMPLOYEE_HARD_WORKER: 'CommonSituationId' = 110399 - RETAIL_EMPLOYEE_NPC_STORE_HARD_WORKER: 'CommonSituationId' = 112196 - ROOMMATE_NPC_EVENTS_ARGUMENT: 'CommonSituationId' = 220805 - ROOMMATE_NPC_EVENTS_GET_HYPE: 'CommonSituationId' = 220807 - ROOMMATE_NPC_EVENTS_LOCKED_OUT: 'CommonSituationId' = 220806 - ROOMMATE_NPC_EVENTS_WHISPERS: 'CommonSituationId' = 220809 - ROOMMATE_NPC_EVENTS_WOOING: 'CommonSituationId' = 220808 - ROOMMATE_NPC_FRIEND: 'CommonSituationId' = 210758 - ROOMMATE_NPC_PARTY: 'CommonSituationId' = 212048 - ROOMMATE_NPC_POTENTIAL_ROOMMATE: 'CommonSituationId' = 220813 - ROOMMATE_NPC_SIGNIFICANT_OTHER: 'CommonSituationId' = 210759 - ROOMMATE_NPC_SITUATION: 'CommonSituationId' = 209550 - SCARECROW_PURPLE: 'CommonSituationId' = 191044 - SCARECROW_RED: 'CommonSituationId' = 191043 - SCARECROW_SITUATION: 'CommonSituationId' = 187072 - SCIENTIST_LAB_ALIEN_VISIT_ALIEN: 'CommonSituationId' = 113536 - SERVICE_SKELETON: 'CommonSituationId' = 177640 - SERVICE_SKELETON_RARE: 'CommonSituationId' = 177857 - SERVICE_SKELETON_UNCOMMON: 'CommonSituationId' = 177858 - SIMPLE_TELEPORT_TO_MAGIC_HQ_FAIL: 'CommonSituationId' = 215556 - SIM_BACKGROUND_CELEBRITY: 'CommonSituationId' = 196516 - SINGLES_BARFLY: 'CommonSituationId' = 122620 - SINGLES_NIGHT: 'CommonSituationId' = 122638 - SINGLE_JOB_CHALET_GARDENS_VISITOR: 'CommonSituationId' = 130273 - SINGLE_JOB_CLUB_DJ: 'CommonSituationId' = 122995 - SINGLE_JOB_CLUB_DJ_LEVEL10: 'CommonSituationId' = 124257 - SINGLE_JOB_COWORKER_RETAIL_EMPLOYEE: 'CommonSituationId' = 109236 - SINGLE_JOB_COWORKER_SCIENTIST: 'CommonSituationId' = 108670 - SINGLE_JOB_COWORKER_SCIENTIST_FRONT_DESK: 'CommonSituationId' = 115831 - SINGLE_JOB_MAGIC_SAGE_MISCHIEF: 'CommonSituationId' = 212842 - SINGLE_JOB_MAGIC_SAGE_PRACTICAL: 'CommonSituationId' = 212843 - SINGLE_JOB_MAGIC_SAGE_UNTAMED: 'CommonSituationId' = 212844 - SINGLE_JOB_MAGIC_VENUE_NPC_INTERMEDIATE: 'CommonSituationId' = 213051 - SINGLE_JOB_MAGIC_VENUE_NPC_INTERMEDIATE_USE_WAND: 'CommonSituationId' = 222850 - SINGLE_JOB_MAGIC_VENUE_NPC_NOVICE: 'CommonSituationId' = 212927 - SINGLE_JOB_MAGIC_VENUE_NPC_NOVICE_USE_WAND: 'CommonSituationId' = 222852 - SINGLE_JOB_MARKET_STALLS_CUSTOMER: 'CommonSituationId' = 132959 - SINGLE_JOB_MARKET_STALLS_CUSTOMER_MAGIC: 'CommonSituationId' = 217680 - SINGLE_JOB_MOTHER_PLANT_RUN_AWAY: 'CommonSituationId' = 207316 - SINGLE_SIM_LEAVE: 'CommonSituationId' = 101251 - SINGLE_SIM_VISITOR_TRICK_OR_TREAT: 'CommonSituationId' = 187507 - SITUATION_COMPLEX_APARTMENT_GROUP_HANGOUT: 'CommonSituationId' = 140390 - SITUATION_COMPLEX_APARTMENT_GROUP_HANGOUT_GAME_TIME: 'CommonSituationId' = 142201 - SITUATION_COMPLEX_APARTMENT_GROUP_HANGOUT_PRE_PARTY: 'CommonSituationId' = 142200 - SITUATION_COMPLEX_APARTMENT_NEIGHBOR_CHAT: 'CommonSituationId' = 155007 - SITUATION_COMPLEX_GHOST_HAUNTED_APARTMENT: 'CommonSituationId' = 139824 - SITUATION_COMPLEX_NEIGHBOR_COMPLAINT_NOISE: 'CommonSituationId' = 146032 - SITUATION_COMPLEX_NEIGHBOR_HANGOUT_BRAINSTORM_ART_LOVER: 'CommonSituationId' = 141316 - SITUATION_COMPLEX_NEIGHBOR_HANGOUT_BRAINSTORM_CREATIVE: 'CommonSituationId' = 141317 - SITUATION_COMPLEX_NEIGHBOR_HANGOUT_CHILDS_PLAY: 'CommonSituationId' = 141116 - SITUATION_COMPLEX_NEIGHBOR_HANGOUT_CHILD_COMPLAINT: 'CommonSituationId' = 141118 - SITUATION_COMPLEX_NEIGHBOR_HANGOUT_FLIRTY_SHOWER: 'CommonSituationId' = 141120 - SITUATION_COMPLEX_NEIGHBOR_HANGOUT_GEEK_OUT: 'CommonSituationId' = 141117 - SITUATION_COMPLEX_NEIGHBOR_HANGOUT_GENERIC: 'CommonSituationId' = 139264 - SITUATION_COMPLEX_NEIGHBOR_HANGOUT_MUNCHIES_FOODIE: 'CommonSituationId' = 141319 - SITUATION_COMPLEX_NEIGHBOR_HANGOUT_MUNCHIES_GLUTTON: 'CommonSituationId' = 141318 - SITUATION_COMPLEX_NEIGHBOR_HANGOUT_PENTHOUSE_BRAINSTORM_KEY_HOLDERS_ART_LOVER: 'CommonSituationId' = 146268 - SITUATION_COMPLEX_NEIGHBOR_HANGOUT_PENTHOUSE_BRAINSTORM_KEY_HOLDERS_CREATIVE: 'CommonSituationId' = 146269 - SITUATION_COMPLEX_NEIGHBOR_HANGOUT_PENTHOUSE_BRAINSTORM_NON_KEY_HOLDERS_ART_LOVER: 'CommonSituationId' = 146270 - SITUATION_COMPLEX_NEIGHBOR_HANGOUT_PENTHOUSE_BRAINSTORM_NON_KEY_HOLDERS_CREATIVE: 'CommonSituationId' = 146273 - SITUATION_COMPLEX_NEIGHBOR_HANGOUT_PENTHOUSE_CHILDS_PLAY_KEY_HOLDERS: 'CommonSituationId' = 146418 - SITUATION_COMPLEX_NEIGHBOR_HANGOUT_PENTHOUSE_CHILDS_PLAY_NON_KEY_HOLDERS: 'CommonSituationId' = 146419 - SITUATION_COMPLEX_NEIGHBOR_HANGOUT_PENTHOUSE_GEEK_OUT_KEY_HOLDERS: 'CommonSituationId' = 146414 - SITUATION_COMPLEX_NEIGHBOR_HANGOUT_PENTHOUSE_GEEK_OUT_NON_KEY_HOLDERS: 'CommonSituationId' = 146415 - SITUATION_COMPLEX_NEIGHBOR_HANGOUT_PENTHOUSE_GENERIC_KEY_HOLDERS: 'CommonSituationId' = 146331 - SITUATION_COMPLEX_NEIGHBOR_HANGOUT_PENTHOUSE_GENERIC_NON_KEY_HOLDERS: 'CommonSituationId' = 146332 - SITUATION_COMPLEX_NEIGHBOR_HANGOUT_PENTHOUSE_MUNCHIES_KEY_HOLDERS_FOODIE: 'CommonSituationId' = 146197 - SITUATION_COMPLEX_NEIGHBOR_HANGOUT_PENTHOUSE_MUNCHIES_KEY_HOLDERS_GLUTTON: 'CommonSituationId' = 146198 - SITUATION_COMPLEX_NEIGHBOR_HANGOUT_PENTHOUSE_MUNCHIES_NON_KEY_HOLDERS_FOODIE: 'CommonSituationId' = 146165 - SITUATION_COMPLEX_NEIGHBOR_HANGOUT_PENTHOUSE_MUNCHIES_NON_KEY_HOLDERS_GLUTTON: 'CommonSituationId' = 146166 - SITUATION_COMPLEX_NEIGHBOR_HANGOUT_PENTHOUSE_UNINVITED_KEY_HOLDERS_GOOFBALL: 'CommonSituationId' = 146378 - SITUATION_COMPLEX_NEIGHBOR_HANGOUT_PENTHOUSE_UNINVITED_KEY_HOLDERS_INSANE: 'CommonSituationId' = 146379 - SITUATION_COMPLEX_NEIGHBOR_HANGOUT_PENTHOUSE_UNINVITED_NON_KEY_HOLDERS_GOOFBALL: 'CommonSituationId' = 146380 - SITUATION_COMPLEX_NEIGHBOR_HANGOUT_PENTHOUSE_UNINVITED_NON_KEY_HOLDERS_INSANE: 'CommonSituationId' = 146381 - SITUATION_COMPLEX_NEIGHBOR_HANGOUT_PENTHOUSE_WORKOUT_KEY_HOLDERS: 'CommonSituationId' = 146411 - SITUATION_COMPLEX_NEIGHBOR_HANGOUT_PENTHOUSE_WORKOUT_NON_KEY_HOLDERS: 'CommonSituationId' = 146412 - SITUATION_COMPLEX_NEIGHBOR_HANGOUT_UNINVITED_GOOFBALL: 'CommonSituationId' = 141943 - SITUATION_COMPLEX_NEIGHBOR_HANGOUT_UNINVITED_INSANE: 'CommonSituationId' = 141927 - SITUATION_COMPLEX_NEIGHBOR_HANGOUT_WORKOUT: 'CommonSituationId' = 141119 - SITUATION_COMPLEX_NEIGHBOR_INTRIGUED_NOISE: 'CommonSituationId' = 146090 - SITUATION_COMPLEX_NEIGHBOR_INTRIGUED_SMELL: 'CommonSituationId' = 146089 - SITUATION_SIMPLE_APARTMENT_NEIGHBORS_INVITED_HANGOUT: 'CommonSituationId' = 146518 - SITUATION_SIMPLE_INFECTED_ATTACK: 'CommonSituationId' = 204726 - SITUATION_SIMPLE_NPC_INVITE_CRITIC_CAREER_RECOMMEND_LOCAL_HANGOUT_BAR: 'CommonSituationId' = 137936 - SITUATION_SIMPLE_NPC_INVITE_CRITIC_CAREER_RECOMMEND_LOCAL_HANGOUT_CLUB: 'CommonSituationId' = 137937 - SITUATION_SIMPLE_NPC_INVITE_CRITIC_CAREER_RECOMMEND_LOCAL_HANGOUT_MUSEUM: 'CommonSituationId' = 137938 - SITUATION_SIMPLE_RUDE_ALIEN_VISITORS: 'CommonSituationId' = 108167 - SITUATION_SIMPLE_TEMPLE_SKELETON: 'CommonSituationId' = 178516 - SITUATION_SIMPLE_TUTORIAL_HOUSEMATE: 'CommonSituationId' = 198047 - SITUATION_SIMPLE_VAMPIRE_CREATION_AT_NPC_HOME: 'CommonSituationId' = 152886 - SITUATION_SIMPLE_VAMPIRE_CREATION_AT_PLAYER_HOME: 'CommonSituationId' = 152907 - SOAK_PARTY: 'CommonSituationId' = 101358 - SPA_GUEST_PLAYER: 'CommonSituationId' = 118687 - SPECTRAL_STALKER_SITUATION: 'CommonSituationId' = 216307 - SPELL_SUMMON_GHOST_FAIL: 'CommonSituationId' = 215671 - SPOOKY_PARTY_SP04: 'CommonSituationId' = 125869 - SPOOKY_PARTY_S_P04: 'CommonSituationId' = 125869 - SQUAD_GATHERING: 'CommonSituationId' = 196099 - STAY_THE_NIGHT: 'CommonSituationId' = 40440 - STRANGER_VILLE_MILITARY_BARFLY: 'CommonSituationId' = 204035 - STRANGE_POST_WELCOME_WAGON: 'CommonSituationId' = 202792 - STRANGE_PRE_WELCOME_WAGON: 'CommonSituationId' = 202793 - STRANGE_WELCOME_WAGON: 'CommonSituationId' = 202794 - STUDENT_COMMONS_ARTS_EXAM_CRAM_STUDENT: 'CommonSituationId' = 230200 - STUDENT_COMMONS_ARTS_MIXER_MASCOT: 'CommonSituationId' = 229947 - STUDENT_COMMONS_ARTS_MIXER_STUDENT: 'CommonSituationId' = 222139 - STUDENT_COMMONS_ARTS_POETRY_TEA_SERVER: 'CommonSituationId' = 221830 - STUDENT_COMMONS_ARTS_PROFESSORS_GOOD: 'CommonSituationId' = 219186 - STUDENT_COMMONS_ARTS_PROFESSORS_GRUMPY: 'CommonSituationId' = 219185 - STUDENT_COMMONS_ARTS_PROFESSORS_HIP: 'CommonSituationId' = 219184 - STUDENT_COMMONS_ARTS_PROFESSORS_SMART: 'CommonSituationId' = 226919 - STUDENT_COMMONS_ARTS_STUDENTS_SLACKER: 'CommonSituationId' = 219181 - STUDENT_COMMONS_ARTS_STUDENTS_SOCIAL: 'CommonSituationId' = 219180 - STUDENT_COMMONS_ARTS_STUDENTS_STUDIOUS: 'CommonSituationId' = 219182 - STUDENT_COMMONS_ARTS_VISITORS: 'CommonSituationId' = 219187 - STUDENT_COMMONS_EXAM_CRAM_PLAYER: 'CommonSituationId' = 222195 - STUDENT_COMMONS_MIXER_PROFESSOR: 'CommonSituationId' = 222140 - STUDENT_COMMONS_SCIENCE_EXAM_CRAM_STUDENT: 'CommonSituationId' = 230202 - STUDENT_COMMONS_SCIENCE_E_SPORTS_CONTESTANT: 'CommonSituationId' = 221978 - STUDENT_COMMONS_SCIENCE_E_SPORTS_EXPERT_CONTESTANT: 'CommonSituationId' = 221979 - STUDENT_COMMONS_SCIENCE_MIXER_MASCOT: 'CommonSituationId' = 229948 - STUDENT_COMMONS_SCIENCE_MIXER_STUDENT: 'CommonSituationId' = 222158 - STUDENT_COMMONS_SCIENCE_PROFESSORS_GOOD: 'CommonSituationId' = 219191 - STUDENT_COMMONS_SCIENCE_PROFESSORS_GRUMPY: 'CommonSituationId' = 219192 - STUDENT_COMMONS_SCIENCE_PROFESSORS_HIP: 'CommonSituationId' = 219193 - STUDENT_COMMONS_SCIENCE_PROFESSORS_SMART: 'CommonSituationId' = 226918 - STUDENT_COMMONS_SCIENCE_STUDENTS_SLACKER: 'CommonSituationId' = 219195 - STUDENT_COMMONS_SCIENCE_STUDENTS_SOCIAL: 'CommonSituationId' = 219196 - STUDENT_COMMONS_SCIENCE_STUDENTS_STUDIOUS: 'CommonSituationId' = 219197 - STUDENT_COMMONS_SCIENCE_VISITORS: 'CommonSituationId' = 219189 - SUB_PRESENT_PILE_OPEN_PRESENTS: 'CommonSituationId' = 186233 - SUB_RESTAURANT_PLAYER_GROUP: 'CommonSituationId' = 132748 - SUB_TRAINING_DUMMY_PRACTICE_FIGHTING_WITH: 'CommonSituationId' = 203279 - SUMMON_LIGHTHOUSE_GHOST_DOG: 'CommonSituationId' = 175666 - TEMPORARY_CLONE: 'CommonSituationId' = 215157 - TEMPORARY_CLONE_CHARGED: 'CommonSituationId' = 216362 - TEMPORARY_CLONE_FAIL: 'CommonSituationId' = 216123 - TEST_FESTIVAL_ONE_STATE_EVENT: 'CommonSituationId' = 133655 - TEST_FESTIVAL_TWO_STATE_EVENT: 'CommonSituationId' = 133656 - TODDLER_PLAY_DATE: 'CommonSituationId' = 170158 - TOURIST_BARFLY_MYSHUNO_MEADOWS: 'CommonSituationId' = 151725 - TRAGIC_CLOWN: 'CommonSituationId' = 139602 - TRAINING_DUMMY_PRACTICE_FIGHTING_WITH: 'CommonSituationId' = 203278 - TRASH_DIVER: 'CommonSituationId' = 224194 - TRASH_DUMPER: 'CommonSituationId' = 234514 - TRASH_UPDATE_WASTE_MANAGER: 'CommonSituationId' = 235041 - UNGREETED_NPC_VISITING_NPC: 'CommonSituationId' = 34410 - UNGREETED_NPC_VISITING_NPC_UNIVERSITY: 'CommonSituationId' = 230377 - UNGREETED_PLAYER_VISITING_NPC: 'CommonSituationId' = 34411 - UNIVERSITY_ART_SOCIETY_BAR_NIGHT: 'CommonSituationId' = 226488 - UNIVERSITY_DEBATE_ORG_BAR_NIGHT: 'CommonSituationId' = 222303 - UNIVERSITY_GRADUATION_ARTS: 'CommonSituationId' = 226999 - UNIVERSITY_GRADUATION_SCIENCE: 'CommonSituationId' = 227006 - UNIVERSITY_HONOR_SOCIETY_BAR_NIGHT: 'CommonSituationId' = 226481 - UNIVERSITY_HOUSING_KICK_OUT_SITUATION: 'CommonSituationId' = 220603 - UNIVERSITY_HOUSING_MAID: 'CommonSituationId' = 222805 - UNIVERSITY_MIXER_PARTY_STUDENT_COMMONS_ART_MIXER_JUICE_KEG: 'CommonSituationId' = 222126 - UNIVERSITY_MIXER_PARTY_STUDENT_COMMONS_SCIENCE_MIXER_JUICE_KEG: 'CommonSituationId' = 220359 - UNIVERSITY_ORGANIZATION_DEBATE_SQUAD_DEBATE_SHOWDOWN: 'CommonSituationId' = 222828 - UNIVERSITY_ORGANIZATION_MEMBER_SINGLE_JOB_DEBATE_PRACTICE: 'CommonSituationId' = 228356 - UNIVERSITY_ORGANIZATION_MEMBER_SINGLE_JOB_ROBOT_BUILDING_SESSION: 'CommonSituationId' = 228362 - UNIVERSITY_ORGANIZATION_MEMBER_SINGLE_JOB_SECRET_SOCIETY_JOIN_VISIT: 'CommonSituationId' = 222710 - UNIVERSITY_PARTY_BAR_NIGHT: 'CommonSituationId' = 227731 - UNIVERSITY_PRANK_BAR_NIGHT: 'CommonSituationId' = 226489 - UNIVERSITY_ROBOTICS_BAR_NIGHT: 'CommonSituationId' = 226490 - UNIVERSITY_STUDENT_HANGOUT_ARTS_STUDENT: 'CommonSituationId' = 225553 - UNIVERSITY_STUDENT_HANGOUT_PROFESSOR: 'CommonSituationId' = 225550 - UNIVERSITY_STUDENT_HANGOUT_SCIENCE_PROFESSOR: 'CommonSituationId' = 230609 - UNIVERSITY_STUDENT_HANGOUT_SCIENCE_STUDENT: 'CommonSituationId' = 225558 - VAMPIRE_NIGHTTIME: 'CommonSituationId' = 152610 - VAMPIRE_NIGHTTIME_INITIAL: 'CommonSituationId' = 155503 - VENDOR_STALL_CAFETERIA_STATION: 'CommonSituationId' = 220129 - VENDOR_STALL_COFFEE_CART_HIRED_NPC: 'CommonSituationId' = 226530 - VENDOR_STALL_COFFEE_CART_VENUE: 'CommonSituationId' = 226020 - VENUE_BACKGROUND_HOSPITAL: 'CommonSituationId' = 115405 - VENUE_BAR: 'CommonSituationId' = 29374 - VENUE_CRAFT_SALES_TABLE_VENDOR: 'CommonSituationId' = 224122 - VENUE_CRAFT_SALES_TABLE_VENDOR_PAINTINGS: 'CommonSituationId' = 234949 - VENUE_GENERIC: 'CommonSituationId' = 99708 - VENUE_GYM: 'CommonSituationId' = 16199 - VENUE_HERMIT: 'CommonSituationId' = 105590 - VENUE_PARK: 'CommonSituationId' = 27467 - VENUE_PET_OWNER_CAT_ARTS_CENTER: 'CommonSituationId' = 172749 - VENUE_PET_OWNER_CAT_BAR: 'CommonSituationId' = 170211 - VENUE_PET_OWNER_CAT_CAFE: 'CommonSituationId' = 179098 - VENUE_PET_OWNER_CAT_CLUB: 'CommonSituationId' = 172492 - VENUE_PET_OWNER_CAT_GYM: 'CommonSituationId' = 172580 - VENUE_PET_OWNER_CAT_KARAOKE: 'CommonSituationId' = 172784 - VENUE_PET_OWNER_CAT_LIBRARY: 'CommonSituationId' = 172643 - VENUE_PET_OWNER_CAT_LOUNGE: 'CommonSituationId' = 172679 - VENUE_PET_OWNER_CAT_MUSEUM: 'CommonSituationId' = 172710 - VENUE_PET_OWNER_CAT_PARK: 'CommonSituationId' = 170212 - VENUE_PET_OWNER_CAT_POOL: 'CommonSituationId' = 172808 - VENUE_PET_OWNER_DOG_ARTS_CENTER: 'CommonSituationId' = 172752 - VENUE_PET_OWNER_DOG_BAR: 'CommonSituationId' = 169502 - VENUE_PET_OWNER_DOG_CAFE: 'CommonSituationId' = 179103 - VENUE_PET_OWNER_DOG_CLUB: 'CommonSituationId' = 172496 - VENUE_PET_OWNER_DOG_GYM: 'CommonSituationId' = 172583 - VENUE_PET_OWNER_DOG_KARAOKE: 'CommonSituationId' = 172785 - VENUE_PET_OWNER_DOG_LIBRARY: 'CommonSituationId' = 172652 - VENUE_PET_OWNER_DOG_LOUNGE: 'CommonSituationId' = 172680 - VENUE_PET_OWNER_DOG_MUSEUM: 'CommonSituationId' = 172711 - VENUE_PET_OWNER_DOG_PARK: 'CommonSituationId' = 169465 - VENUE_PET_OWNER_DOG_POOL: 'CommonSituationId' = 172809 - VET_CHECK_UP_CAT: 'CommonSituationId' = 167591 - VET_CHECK_UP_CAT_TEEN: 'CommonSituationId' = 174419 - VET_CHECK_UP_DOG: 'CommonSituationId' = 167592 - VET_CHECK_UP_DOG_TEEN: 'CommonSituationId' = 174425 - VET_CUSTOMER_VENDING_MACHINE_SITUATION: 'CommonSituationId' = 172624 - VET_DIAGNOSIS: 'CommonSituationId' = 165425 - VET_EMPLOYEE: 'CommonSituationId' = 165161 - VET_PLAYER: 'CommonSituationId' = 168070 - VET_SICK_CAT: 'CommonSituationId' = 167550 - VET_SICK_CAT_HIGH_LEVEL: 'CommonSituationId' = 175540 - VET_SICK_CAT_HIGH_LEVEL_TEEN: 'CommonSituationId' = 175542 - VET_SICK_CAT_MID_LEVEL: 'CommonSituationId' = 175539 - VET_SICK_CAT_MID_LEVEL_TEEN: 'CommonSituationId' = 175541 - VET_SICK_CAT_TEEN: 'CommonSituationId' = 174441 - VET_SICK_DOG: 'CommonSituationId' = 164629 - VET_SICK_DOG_HIGH_LEVEL: 'CommonSituationId' = 175550 - VET_SICK_DOG_HIGH_LEVEL_TEEN: 'CommonSituationId' = 175551 - VET_SICK_DOG_MID_LEVEL: 'CommonSituationId' = 175548 - VET_SICK_DOG_MID_LEVEL_TEEN: 'CommonSituationId' = 175549 - VET_SICK_DOG_TEEN: 'CommonSituationId' = 174438 - VIP_ROPE_BOUNCER: 'CommonSituationId' = 194488 - VISITOR_BARFLY: 'CommonSituationId' = 122602 - VOODOO_SUMMON: 'CommonSituationId' = 40508 - WALK_BY_AMBIENT: 'CommonSituationId' = 24807 - WALK_BY_AMBIENT_ALIEN: 'CommonSituationId' = 113923 - WALK_BY_AMBIENT_ALIEN_IN_DISGUISE: 'CommonSituationId' = 116920 - WALK_BY_AMBIENT_CAMPING_FOREST: 'CommonSituationId' = 106136 - WALK_BY_AMBIENT_CITY_LIFE_APARTMENT_NEIGHBORS_COMMUTER_SCHOOL_COME_FROM_APT: 'CommonSituationId' = 139559 - WALK_BY_AMBIENT_CITY_LIFE_APARTMENT_NEIGHBORS_COMMUTER_SCHOOL_GO_TO_APT: 'CommonSituationId' = 141062 - WALK_BY_AMBIENT_CITY_LIFE_APARTMENT_NEIGHBORS_COMMUTER_WORK_COME_FROM_APT: 'CommonSituationId' = 139550 - WALK_BY_AMBIENT_CITY_LIFE_APARTMENT_NEIGHBORS_COMMUTER_WORK_GO_TO_APT: 'CommonSituationId' = 141061 - WALK_BY_AMBIENT_CITY_LIFE_APARTMENT_NEIGHBORS_VISITOR_COME_FROM_APT: 'CommonSituationId' = 141060 - WALK_BY_AMBIENT_CITY_LIFE_APARTMENT_NEIGHBORS_VISITOR_GO_TO_APT: 'CommonSituationId' = 141059 - WALK_BY_AMBIENT_CITY_LIFE_COFFEE_DRINKER: 'CommonSituationId' = 134206 - WALK_BY_AMBIENT_CITY_LIFE_COMMUTER: 'CommonSituationId' = 134208 - WALK_BY_AMBIENT_CITY_LIFE_LIVES_ON_STREET: 'CommonSituationId' = 155984 - WALK_BY_AMBIENT_CITY_LIFE_PHONE_CHATTER: 'CommonSituationId' = 134210 - WALK_BY_AMBIENT_CITY_LIFE_SNACKER: 'CommonSituationId' = 134207 - WALK_BY_AMBIENT_CITY_LIFE_WEIRDO_TOWELS: 'CommonSituationId' = 145071 - WALK_BY_AMBIENT_CLOWN: 'CommonSituationId' = 97227 - WALK_BY_AMBIENT_CRIMINAL: 'CommonSituationId' = 97223 - WALK_BY_AMBIENT_DESERT_OASIS: 'CommonSituationId' = 25166 - WALK_BY_AMBIENT_ECO_WORLD_FREEGAN: 'CommonSituationId' = 236933 - WALK_BY_AMBIENT_ECO_WORLD_VOTER_WALK_BY: 'CommonSituationId' = 234195 - WALK_BY_AMBIENT_EVENT_NPC_FALL_CHALLENGE: 'CommonSituationId' = 153170 - WALK_BY_AMBIENT_EVENT_NPC_SPRING_CHALLENGE: 'CommonSituationId' = 162934 - WALK_BY_AMBIENT_EVENT_NPC_XP_BOOST: 'CommonSituationId' = 149996 - WALK_BY_AMBIENT_FAKE_VAMPIRE_AFTER_DARK: 'CommonSituationId' = 153768 - WALK_BY_AMBIENT_FAME_WORLD_PAPARAZZI: 'CommonSituationId' = 200334 - WALK_BY_AMBIENT_FAME_WORLD_RESIDENTS_CELEBRITY_LEAVE_HOME: 'CommonSituationId' = 196922 - WALK_BY_AMBIENT_FAME_WORLD_RESIDENTS_CELEBRITY_RETURN_HOME: 'CommonSituationId' = 196923 - WALK_BY_AMBIENT_FAME_WORLD_RESIDENTS_SCHOOL_LEAVE_HOME: 'CommonSituationId' = 196887 - WALK_BY_AMBIENT_FAME_WORLD_RESIDENTS_SCHOOL_RETURN_HOME: 'CommonSituationId' = 196889 - WALK_BY_AMBIENT_FAME_WORLD_RESIDENTS_WORK_LEAVE_HOME: 'CommonSituationId' = 196863 - WALK_BY_AMBIENT_FAME_WORLD_RESIDENTS_WORK_RETURN_HOME: 'CommonSituationId' = 196865 - WALK_BY_AMBIENT_FAME_WORLD_STUDIO_ACTOR: 'CommonSituationId' = 197813 - WALK_BY_AMBIENT_FAME_WORLD_STUDIO_ASSISTANT: 'CommonSituationId' = 197811 - WALK_BY_AMBIENT_FAME_WORLD_TOURIST: 'CommonSituationId' = 201114 - WALK_BY_AMBIENT_GARDENER: 'CommonSituationId' = 196892 - WALK_BY_AMBIENT_GARDENER_TO_LOT: 'CommonSituationId' = 200559 - WALK_BY_AMBIENT_GARDEN_DISTRICT: 'CommonSituationId' = 25165 - WALK_BY_AMBIENT_GARDEN_DISTRICT_FAMILY_TIME: 'CommonSituationId' = 36751 - WALK_BY_AMBIENT_GARDEN_DISTRICT_ON_THE_TOWN: 'CommonSituationId' = 36750 - WALK_BY_AMBIENT_GARDEN_DISTRICT_PARK_AFTER_DARK: 'CommonSituationId' = 36779 - WALK_BY_AMBIENT_GARDEN_DISTRICT_PARK_JOGGER: 'CommonSituationId' = 36777 - WALK_BY_AMBIENT_GARDEN_DISTRICT_PARK_PLAY_TIME: 'CommonSituationId' = 36766 - WALK_BY_AMBIENT_GARDEN_DISTRICT_PARK_RELAXER: 'CommonSituationId' = 36778 - WALK_BY_AMBIENT_GARDEN_DISTRICT_PARK_STREAKER: 'CommonSituationId' = 238441 - WALK_BY_AMBIENT_GARDEN_DISTRICT_SCHOOL_COMMUTE: 'CommonSituationId' = 36743 - WALK_BY_AMBIENT_GARDEN_DISTRICT_WORK_COMMUTE: 'CommonSituationId' = 36650 - WALK_BY_AMBIENT_HOT_DOG: 'CommonSituationId' = 97230 - WALK_BY_AMBIENT_ISLAND_WORLD_FAMILY_TIME: 'CommonSituationId' = 216134 - WALK_BY_AMBIENT_ISLAND_WORLD_JOGGER: 'CommonSituationId' = 216130 - WALK_BY_AMBIENT_ISLAND_WORLD_RELAXER: 'CommonSituationId' = 216135 - WALK_BY_AMBIENT_ISLAND_WORLD_TEEN: 'CommonSituationId' = 216131 - WALK_BY_AMBIENT_MAGIC_PORTAL_GO_TO_PORTAL: 'CommonSituationId' = 217134 - WALK_BY_AMBIENT_MAGIC_PORTAL_LEAVE_PORTAL: 'CommonSituationId' = 217131 - WALK_BY_AMBIENT_MAID: 'CommonSituationId' = 97233 - WALK_BY_AMBIENT_MAID_TO_LOT: 'CommonSituationId' = 200551 - WALK_BY_AMBIENT_MAILMAN: 'CommonSituationId' = 112304 - WALK_BY_AMBIENT_NEIGHBOR_JOGGER: 'CommonSituationId' = 126207 - WALK_BY_AMBIENT_NEIGHBOR_SCHOOL_COMMUTE: 'CommonSituationId' = 126180 - WALK_BY_AMBIENT_PET_WORLD_BEACH_JOGGER: 'CommonSituationId' = 163939 - WALK_BY_AMBIENT_PET_WORLD_BEACH_WALKER: 'CommonSituationId' = 163940 - WALK_BY_AMBIENT_PET_WORLD_DOG_WALKER: 'CommonSituationId' = 167623 - WALK_BY_AMBIENT_PET_WORLD_WORKER: 'CommonSituationId' = 163938 - WALK_BY_AMBIENT_PIZZA: 'CommonSituationId' = 97234 - WALK_BY_AMBIENT_POLICE_PATROL: 'CommonSituationId' = 112411 - WALK_BY_AMBIENT_REPAIRMAN: 'CommonSituationId' = 196916 - WALK_BY_AMBIENT_REPAIRMAN_TO_LOT: 'CommonSituationId' = 200561 - WALK_BY_AMBIENT_SCOUTING: 'CommonSituationId' = 188541 - WALK_BY_AMBIENT_STRANGER_VILLE_MILITARY_01: 'CommonSituationId' = 203282 - WALK_BY_AMBIENT_STRANGER_VILLE_MILITARY_02: 'CommonSituationId' = 206206 - WALK_BY_AMBIENT_STRANGER_VILLE_MILITARY_03: 'CommonSituationId' = 206207 - WALK_BY_AMBIENT_STRANGER_VILLE_MILITARY_04: 'CommonSituationId' = 206208 - WALK_BY_AMBIENT_STRANGER_VILLE_SCIENTIST_01: 'CommonSituationId' = 203281 - WALK_BY_AMBIENT_STRANGER_VILLE_SCIENTIST_02: 'CommonSituationId' = 206214 - WALK_BY_AMBIENT_STRANGER_VILLE_SCIENTIST_03: 'CommonSituationId' = 206215 - WALK_BY_AMBIENT_STRANGER_VILLE_SCIENTIST_04: 'CommonSituationId' = 206217 - WALK_BY_AMBIENT_TEEN: 'CommonSituationId' = 160242 - WALK_BY_AMBIENT_TRAGIC_CLOWN: 'CommonSituationId' = 139893 - WALK_BY_AMBIENT_VAMPIRE_AFTER_DARK: 'CommonSituationId' = 153739 - WALK_BY_AMBIENT_VAMPIRE_AFTER_DARK_HAS_HOME: 'CommonSituationId' = 156394 - WALK_BY_AMBIENT_WALK_OF_SHAME: 'CommonSituationId' = 76157 - WALK_BY_AMBIENT_WEATHER_RAINING: 'CommonSituationId' = 184882 - WALK_BY_AMBIENT_WEATHER_SNOWING: 'CommonSituationId' = 184883 - WALK_BY_AMBIENT_WINDENBURG: 'CommonSituationId' = 25167 - WALK_BY_DOG_WALKER_WALK_TYAE: 'CommonSituationId' = 168135 - WALK_BY_ECO_PERSONALITY_ECO_MASTER: 'CommonSituationId' = 241169 - WALK_BY_ECO_PERSONALITY_ENTREPRENEUR: 'CommonSituationId' = 241170 - WALK_BY_ECO_PERSONALITY_MAKER: 'CommonSituationId' = 241171 - WALK_BY_EVENT_FALL_CHALLENGE2016_DO_TD_CELEBRATOR: 'CommonSituationId' = 153126 - WALK_BY_EVENT_SPRING_CHALLENGE_PLANT_SIM_NPC: 'CommonSituationId' = 163056 - WALK_BY_ISLAND_CONSERVATION_ANTI_ENVIRONMENTALIST: 'CommonSituationId' = 210237 - WALK_BY_ISLAND_CONSERVATION_CONSERVATIONIST: 'CommonSituationId' = 211666 - WALK_BY_ISLAND_CONSERVATION_LITTERING_SIM: 'CommonSituationId' = 210238 - WALK_BY_ISLAND_CONSERVATION_POACHING_SIM: 'CommonSituationId' = 210239 - WALK_BY_JUNGLE_CHILD: 'CommonSituationId' = 181342 - WALK_BY_JUNGLE_TYAE: 'CommonSituationId' = 181341 - WALK_BY_MAGIC_DUEL: 'CommonSituationId' = 216807 - WALK_BY_NEIGHBOR: 'CommonSituationId' = 120057 - WALK_BY_NOBODY: 'CommonSituationId' = 77411 - WALK_BY_RENT_DUE_APARTMENT_LANDLORD: 'CommonSituationId' = 143686 - WALK_BY_RING_DOORBELL_ACQUIRED_FAMILY_REL_BIT: 'CommonSituationId' = 164639 - WALK_BY_RING_DOORBELL_MAX_FAMILY_REL_BIT: 'CommonSituationId' = 168415 - WALK_BY_RING_DOORBELL_NEIGHBOR: 'CommonSituationId' = 100055 - WALK_BY_RING_DOORBELL_VAMPIRE: 'CommonSituationId' = 153167 - WALK_BY_RING_DOORBELL_VAMPIRES_INITIAL: 'CommonSituationId' = 157974 - WALK_BY_RING_DOORBELL_WITH_RELATIONSHIP: 'CommonSituationId' = 35723 - WALK_BY_SURPRISE_HOLIDAY_PIRATE_DAY: 'CommonSituationId' = 182798 - WALK_BY_UNIVERSITY_WORLD_ARTS_FROM_ARENA_ATHLETE_E_SPORTS: 'CommonSituationId' = 222604 - WALK_BY_UNIVERSITY_WORLD_ARTS_FROM_ARENA_ATHLETE_SOCCER: 'CommonSituationId' = 222605 - WALK_BY_UNIVERSITY_WORLD_ARTS_FROM_ARENA_MASCOT: 'CommonSituationId' = 222859 - WALK_BY_UNIVERSITY_WORLD_ARTS_FROM_ARENA_SPORTS_FAN_E_SPORTS: 'CommonSituationId' = 222606 - WALK_BY_UNIVERSITY_WORLD_ARTS_FROM_ARENA_SPORTS_FAN_SOCCER: 'CommonSituationId' = 222607 - WALK_BY_UNIVERSITY_WORLD_ARTS_FROM_CLASS_BIKE_STUDENT: 'CommonSituationId' = 222810 - WALK_BY_UNIVERSITY_WORLD_ARTS_FROM_CLASS_PROFESSOR: 'CommonSituationId' = 222598 - WALK_BY_UNIVERSITY_WORLD_ARTS_FROM_CLASS_STUDENT: 'CommonSituationId' = 222599 - WALK_BY_UNIVERSITY_WORLD_ARTS_TO_ARENA_ATHLETE_E_SPORTS: 'CommonSituationId' = 222608 - WALK_BY_UNIVERSITY_WORLD_ARTS_TO_ARENA_ATHLETE_SOCCER: 'CommonSituationId' = 222609 - WALK_BY_UNIVERSITY_WORLD_ARTS_TO_ARENA_MASCOT: 'CommonSituationId' = 222860 - WALK_BY_UNIVERSITY_WORLD_ARTS_TO_ARENA_SPORTS_FAN_E_SPORTS: 'CommonSituationId' = 222610 - WALK_BY_UNIVERSITY_WORLD_ARTS_TO_ARENA_SPORTS_FAN_SOCCER: 'CommonSituationId' = 222611 - WALK_BY_UNIVERSITY_WORLD_ARTS_TO_CLASS_BIKE_STUDENT: 'CommonSituationId' = 222811 - WALK_BY_UNIVERSITY_WORLD_ARTS_TO_CLASS_PROFESSOR: 'CommonSituationId' = 222602 - WALK_BY_UNIVERSITY_WORLD_ARTS_TO_CLASS_STUDENT: 'CommonSituationId' = 222603 - WALK_BY_UNIVERSITY_WORLD_GENERAL_ARTS_BIKE_STUDENT: 'CommonSituationId' = 222820 - WALK_BY_UNIVERSITY_WORLD_GENERAL_ARTS_STUDENT: 'CommonSituationId' = 222666 - WALK_BY_UNIVERSITY_WORLD_GENERAL_PROFESSOR: 'CommonSituationId' = 222668 - WALK_BY_UNIVERSITY_WORLD_GENERAL_SCIENCE_BIKE_STUDENT: 'CommonSituationId' = 222821 - WALK_BY_UNIVERSITY_WORLD_GENERAL_SCIENCE_STUDENT: 'CommonSituationId' = 222667 - WALK_BY_UNIVERSITY_WORLD_NOTEBOOK_STUDENTS_ARTS: 'CommonSituationId' = 229520 - WALK_BY_UNIVERSITY_WORLD_NOTEBOOK_STUDENTS_SCIENCE: 'CommonSituationId' = 229521 - WALK_BY_UNIVERSITY_WORLD_SCIENCE_FROM_ARENA_ATHLETE_E_SPORTS: 'CommonSituationId' = 222636 - WALK_BY_UNIVERSITY_WORLD_SCIENCE_FROM_ARENA_ATHLETE_SOCCER: 'CommonSituationId' = 222637 - WALK_BY_UNIVERSITY_WORLD_SCIENCE_FROM_ARENA_MASCOT: 'CommonSituationId' = 222857 - WALK_BY_UNIVERSITY_WORLD_SCIENCE_FROM_ARENA_SPORTS_FAN_E_SPORTS: 'CommonSituationId' = 222638 - WALK_BY_UNIVERSITY_WORLD_SCIENCE_FROM_ARENA_SPORTS_FAN_SOCCER: 'CommonSituationId' = 222639 - WALK_BY_UNIVERSITY_WORLD_SCIENCE_FROM_CLASS_BIKE_STUDENT: 'CommonSituationId' = 222812 - WALK_BY_UNIVERSITY_WORLD_SCIENCE_FROM_CLASS_PROFESSOR: 'CommonSituationId' = 222642 - WALK_BY_UNIVERSITY_WORLD_SCIENCE_FROM_CLASS_STUDENT: 'CommonSituationId' = 222643 - WALK_BY_UNIVERSITY_WORLD_SCIENCE_TO_ARENA_ATHLETE_E_SPORTS: 'CommonSituationId' = 222646 - WALK_BY_UNIVERSITY_WORLD_SCIENCE_TO_ARENA_ATHLETE_SOCCER: 'CommonSituationId' = 222647 - WALK_BY_UNIVERSITY_WORLD_SCIENCE_TO_ARENA_MASCOT: 'CommonSituationId' = 222858 - WALK_BY_UNIVERSITY_WORLD_SCIENCE_TO_ARENA_SPORTS_FAN_E_SPORTS: 'CommonSituationId' = 222649 - WALK_BY_UNIVERSITY_WORLD_SCIENCE_TO_ARENA_SPORTS_FAN_SOCCER: 'CommonSituationId' = 222650 - WALK_BY_UNIVERSITY_WORLD_SCIENCE_TO_CLASS_BIKE_STUDENT: 'CommonSituationId' = 222813 - WALK_BY_UNIVERSITY_WORLD_SCIENCE_TO_CLASS_PROFESSOR: 'CommonSituationId' = 222653 - WALK_BY_UNIVERSITY_WORLD_SCIENCE_TO_CLASS_STUDENT: 'CommonSituationId' = 222654 - WALK_BY_WATER_SCOOTER_1: 'CommonSituationId' = 209284 - WALK_BY_WATER_SCOOTER_ISLAND_CANOE: 'CommonSituationId' = 214012 - WALK_DOG_GO_FOR_JOG: 'CommonSituationId' = 166358 - WALK_DOG_LONG: 'CommonSituationId' = 166533 - WALK_DOG_SHORT: 'CommonSituationId' = 166532 - WALK_DOG_SITUATION: 'CommonSituationId' = 165652 - WARDROBE_PEDESTAL_STYLIST: 'CommonSituationId' = 191614 - WEDDING: 'CommonSituationId' = 16202 - WEENIE_ROAST: 'CommonSituationId' = 103691 - WELCOME_WAGON: 'CommonSituationId' = 119785 - WELCOME_WAGON_ISLANDER_CULTURE_DEATH_COMFORT: 'CommonSituationId' = 208665 - WELCOME_WAGON_ISLANDER_CULTURE_EXTRA_FOOD: 'CommonSituationId' = 208435 - WORK_OUT_DANCE_TOGETHER: 'CommonSituationId' = 166819 - WORK_OUT_POWER_SCULPTING_TOGETHER: 'CommonSituationId' = 164398 - YOGA_CLASS_BRAIN_BOOSTING: 'CommonSituationId' = 118796 - YOGA_CLASS_ENERGY_CENTERING: 'CommonSituationId' = 118132 - YOGA_CLASS_MIND_CONCENTRATING: 'CommonSituationId' = 118797 - YOGA_CLASS_POST_HANGOUT: 'CommonSituationId' = 122121 - YOGA_INSTRUCTOR_VENUE: 'CommonSituationId' = 12 diff --git a/Scripts/s4ap/sims4communitylib/enums/skills_enum.py b/Scripts/s4ap/sims4communitylib/enums/skills_enum.py deleted file mode 100644 index c050041..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/skills_enum.py +++ /dev/null @@ -1,154 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonSkillId(CommonInt): - """Identifiers for sim skills. - - """ - INVALID: 'CommonSkillId' = 0 - ACTING: 'CommonSkillId' = 194727 - ARCHAEOLOGY: 'CommonSkillId' = 174237 - BAKING: 'CommonSkillId' = 104198 - BOWLING: 'CommonSkillId' = 158659 - CHARISMA: 'CommonSkillId' = 16699 - CHOPSTICKS: 'CommonSkillId' = 142593 - COMEDY: 'CommonSkillId' = 16698 - COMMUNICATION: 'CommonSkillId' = 140170 - COOKING: 'CommonSkillId' = 16705 - CREATIVITY: 'CommonSkillId' = 16718 - CROSS_STITCH: 'CommonSkillId' = 259758 - DANCING: 'CommonSkillId' = 128145 - DARTBOARD_DARTS: 'CommonSkillId' = 127868 - DJ_MIXING: 'CommonSkillId' = 121612 - ENTREPRENEUR: 'CommonSkillId' = 274197 - EQUESTRIAN_SKILL: 'CommonSkillId' = 322708 - FABRICATION: 'CommonSkillId' = 231908 - FISHING: 'CommonSkillId' = 39397 - FITNESS: 'CommonSkillId' = 16659 - FLOWER_ARRANGING: 'CommonSkillId' = 186703 - FOOSBALL: 'CommonSkillId' = 122854 - GARDENING: 'CommonSkillId' = 16700 - GOURMET_COOKING: 'CommonSkillId' = 16701 - GUITAR: 'CommonSkillId' = 16702 - HANDINESS: 'CommonSkillId' = 16704 - HERBALISM: 'CommonSkillId' = 101920 - HORSE_AGILITY: 'CommonSkillId' = 324632 - HORSE_ENDURANCE: 'CommonSkillId' = 324634 - HORSE_JUMPING: 'CommonSkillId' = 324633 - HORSE_TEMPERAMENT: 'CommonSkillId' = 324631 - HUMANOID_ROBOT_ENHANCEMENT: 'CommonSkillId' = 224672 - IMAGINATION: 'CommonSkillId' = 140706 - INFANT_CRAWL_HIDDEN: 'CommonSkillId' = 297187 - INFANT_MILESTONE_FINE_MOTOR_HIDDEN: 'CommonSkillId' = 273725 - INFANT_MILESTONE_GROSS_MOTOR_HIDDEN: 'CommonSkillId' = 273723 - INFANT_MILESTONE_SOCIAL_HIDDEN: 'CommonSkillId' = 273726 - INFANT_SOCIAL_AGE_UP_HIDDEN: 'CommonSkillId' = 324352 - JUICE_FIZZING: 'CommonSkillId' = 234806 - JUICE_PONG: 'CommonSkillId' = 213548 - KNITTING: 'CommonSkillId' = 239521 - LOGIC: 'CommonSkillId' = 16706 - MAINTENANCE: 'CommonSkillId' = 111904 - MEDIA_PRODUCTION: 'CommonSkillId' = 192655 - MEDIUM: 'CommonSkillId' = 255249 - MENTAL: 'CommonSkillId' = 16719 - MISCHIEF: 'CommonSkillId' = 16707 - MIXOLOGY: 'CommonSkillId' = 16695 - MOTOR: 'CommonSkillId' = 16720 - MOVEMENT: 'CommonSkillId' = 136140 - PAINTING: 'CommonSkillId' = 16708 - PARENTING: 'CommonSkillId' = 160504 - PET_POOP_CLEAN_UP: 'CommonSkillId' = 161097 - PET_TRAINING: 'CommonSkillId' = 161220 - PHOTOGRAPHY: 'CommonSkillId' = 105774 - PIANO: 'CommonSkillId' = 16709 - PING_PONG: 'CommonSkillId' = 212561 - PIPE_ORGAN: 'CommonSkillId' = 149665 - POTTY: 'CommonSkillId' = 144913 - PROGRAMMING: 'CommonSkillId' = 16703 - RANCH_NECTAR: 'CommonSkillId' = 315761 - RESEARCH_AND_DEBATE: 'CommonSkillId' = 221014 - ROBOTICS: 'CommonSkillId' = 217413 - ROCKET_SCIENCE: 'CommonSkillId' = 16710 - ROCK_CLIMBING: 'CommonSkillId' = 245639 - ROCK_CLIMBING_HIDDEN: 'CommonSkillId' = 165900 - SALES: 'CommonSkillId' = 111902 - SELVADORADIAN_CULTURE: 'CommonSkillId' = 174687 - SHELL_TUTOR_PICKED_SKILL_HIDDEN: 'CommonSkillId' = 224628 - SINGING: 'CommonSkillId' = 137811 - SKATING_HIDDEN: 'CommonSkillId' = 179925 - SKIING: 'CommonSkillId' = 245613 - SNOWBOARDING: 'CommonSkillId' = 246054 - SOCIAL: 'CommonSkillId' = 16721 - SPICY_FOOD: 'CommonSkillId' = 142592 - THINKING: 'CommonSkillId' = 140504 - THROWING_THINGS: 'CommonSkillId' = DARTBOARD_DARTS - VAMPIRE_LORE_HIDDEN: 'CommonSkillId' = 149556 - VETERINARIAN: 'CommonSkillId' = 161190 - VIDEO_GAMING: 'CommonSkillId' = 16712 - VIOLIN: 'CommonSkillId' = 16713 - WELLNESS: 'CommonSkillId' = 117858 - WORK_ETHIC: 'CommonSkillId' = 111903 - WRITING: 'CommonSkillId' = 16714 - - # All of the following values are obsolete, please use the above values instead! - ADULT_MAJOR_ACTING: 'CommonSkillId' = ACTING - ADULT_MAJOR_ARCHAEOLOGY: 'CommonSkillId' = ARCHAEOLOGY - ADULT_MAJOR_BAKING: 'CommonSkillId' = BAKING - ADULT_MAJOR_BAR_TENDING: 'CommonSkillId' = MIXOLOGY - ADULT_MAJOR_CHARISMA: 'CommonSkillId' = CHARISMA - ADULT_MAJOR_COMEDY: 'CommonSkillId' = COMEDY - ADULT_MAJOR_DJ_MIXING: 'CommonSkillId' = DJ_MIXING - ADULT_MAJOR_FABRICATION: 'CommonSkillId' = FABRICATION - ADULT_MAJOR_FISHING: 'CommonSkillId' = FISHING - ADULT_MAJOR_FLOWER_ARRANGING: 'CommonSkillId' = FLOWER_ARRANGING - ADULT_MAJOR_GARDENING: 'CommonSkillId' = GARDENING - ADULT_MAJOR_GOURMET_COOKING: 'CommonSkillId' = GOURMET_COOKING - ADULT_MAJOR_GUITAR: 'CommonSkillId' = GUITAR - ADULT_MAJOR_HANDINESS: 'CommonSkillId' = HANDINESS - ADULT_MAJOR_HERBALISM: 'CommonSkillId' = HERBALISM - ADULT_MAJOR_HOME_STYLE_COOKING: 'CommonSkillId' = COOKING - ADULT_MAJOR_LOGIC: 'CommonSkillId' = LOGIC - ADULT_MAJOR_MISCHIEF: 'CommonSkillId' = MISCHIEF - ADULT_MAJOR_PAINTING: 'CommonSkillId' = PAINTING - ADULT_MAJOR_PARENTING: 'CommonSkillId' = PARENTING - ADULT_MAJOR_PHOTOGRAPHY: 'CommonSkillId' = PHOTOGRAPHY - ADULT_MAJOR_PIANO: 'CommonSkillId' = PIANO - ADULT_MAJOR_PIPE_ORGAN: 'CommonSkillId' = PIPE_ORGAN - ADULT_MAJOR_PROGRAMMING: 'CommonSkillId' = PROGRAMMING - ADULT_MAJOR_ROCKET_SCIENCE: 'CommonSkillId' = ROCKET_SCIENCE - ADULT_MAJOR_SINGING: 'CommonSkillId' = SINGING - ADULT_MAJOR_VETERINARIAN: 'CommonSkillId' = VETERINARIAN - ADULT_MAJOR_VIDEO_GAMING: 'CommonSkillId' = VIDEO_GAMING - ADULT_MAJOR_VIOLIN: 'CommonSkillId' = VIOLIN - ADULT_MAJOR_WELLNESS: 'CommonSkillId' = WELLNESS - ADULT_MAJOR_WRITING: 'CommonSkillId' = WRITING - ADULT_MINOR_DANCING: 'CommonSkillId' = DANCING - ADULT_MINOR_JUICE_FIZZING: 'CommonSkillId' = JUICE_FIZZING - ADULT_MINOR_LOCAL_CULTURE: 'CommonSkillId' = SELVADORADIAN_CULTURE - ADULT_MINOR_MEDIA_PRODUCTION: 'CommonSkillId' = MEDIA_PRODUCTION - CHILD_CREATIVITY: 'CommonSkillId' = CREATIVITY - CHILD_MENTAL: 'CommonSkillId' = MENTAL - CHILD_MOTOR: 'CommonSkillId' = MOTOR - CHILD_SOCIAL: 'CommonSkillId' = SOCIAL - DOG_TRAINING: 'CommonSkillId' = PET_TRAINING - SKATING = SKATING_HIDDEN - HIDDEN_SKATING: 'CommonSkillId' = SKATING_HIDDEN - HIDDEN_TREAD_MILL_ROCK_CLIMBING_WALL_CLIMB: 'CommonSkillId' = ROCK_CLIMBING_HIDDEN - HIDDEN_VAMPIRE_LORE: 'CommonSkillId' = VAMPIRE_LORE_HIDDEN - OBJECT_UPGRADE_COMPUTER_GAMING: 'CommonSkillId' = 29027 - RETAIL_MAINTENANCE: 'CommonSkillId' = MAINTENANCE - RETAIL_SALES: 'CommonSkillId' = SALES - RETAIL_WORK_ETHIC: 'CommonSkillId' = WORK_ETHIC - TODDLER_COMMUNICATION: 'CommonSkillId' = COMMUNICATION - TODDLER_IMAGINATION: 'CommonSkillId' = IMAGINATION - TODDLER_MOVEMENT: 'CommonSkillId' = MOVEMENT - TODDLER_POTTY: 'CommonSkillId' = POTTY - TODDLER_THINKING: 'CommonSkillId' = THINKING - VAMPIRE_LORE = VAMPIRE_LORE_HIDDEN diff --git a/Scripts/s4ap/sims4communitylib/enums/statistics_enum.py b/Scripts/s4ap/sims4communitylib/enums/statistics_enum.py deleted file mode 100644 index c83c171..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/statistics_enum.py +++ /dev/null @@ -1,1698 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonStatisticId(CommonInt): - """Identifiers for vanilla statistics. - - """ - INVALID: 'CommonStatisticId' = 0 - ACTOR_CAREER_MAIN_GOAL: 'CommonStatisticId' = 197925 - ACTOR_CAREER_PRE_PERFORMANCE_DIRECTOR_PRODUCER: 'CommonStatisticId' = 193186 - ACTOR_CAREER_PRE_PERFORMANCE_DOLLY_CAMERA: 'CommonStatisticId' = 194698 - ACTOR_CAREER_PRE_PERFORMANCE_STATIONARY_CAMERA: 'CommonStatisticId' = 194697 - ACTOR_CAREER_PREP_TASK_PRACTICE_ACTION: 'CommonStatisticId' = 199419 - ACTOR_CAREER_PREP_TASK_PRACTICE_DRAMATIC: 'CommonStatisticId' = 199420 - ACTOR_CAREER_PREP_TASK_PRACTICE_ROMANTIC: 'CommonStatisticId' = 199418 - ACTOR_CAREER_PREP_TASK_RELATIONSHIP_CO_STAR: 'CommonStatisticId' = 197221 - ACTOR_CAREER_PREP_TASK_RELATIONSHIP_DIRECTOR: 'CommonStatisticId' = 197222 - ACTOR_CAREER_PREP_TASK_RESEARCH_FLIRTY: 'CommonStatisticId' = 199421 - ACTOR_CAREER_PREP_TASK_RESEARCH_FUNNY: 'CommonStatisticId' = 199422 - ACTOR_CAREER_PREP_TASK_RESEARCH_MEAN: 'CommonStatisticId' = 199423 - ACTOR_CAREER_PREP_TASK_SKILL_ACTING: 'CommonStatisticId' = 199417 - ACTOR_CAREER_PREP_TASK_SKILL_CHARISMA: 'CommonStatisticId' = 197223 - ACTOR_CAREER_PREP_TASK_SKILL_COMEDY: 'CommonStatisticId' = 197225 - ACTOR_CAREER_PREP_TASK_SKILL_FITNESS: 'CommonStatisticId' = 197224 - ACTOR_CAREER_PREP_TASK_SKILL_GUITAR: 'CommonStatisticId' = 197226 - ACTOR_CAREER_PREP_TASK_SKILL_HANDINESS: 'CommonStatisticId' = 197227 - ACTOR_CAREER_SAFE_OUTCOME: 'CommonStatisticId' = 197349 - ADVENTUROUS_PET_GO_ON_ADVENTURE_LIGHTHOUSE_PROGRESS: 'CommonStatisticId' = 175555 - AGE_ADULT: 'CommonStatisticId' = 38438 - AGE_CHILD: 'CommonStatisticId' = 38441 - AGE_ELDER: 'CommonStatisticId' = 38437 - AGE_TEEN: 'CommonStatisticId' = 38440 - AGE_YOUNG_ADULT: 'CommonStatisticId' = 38439 - ALIEN_ABDUCTION_COOLDOWN: 'CommonStatisticId' = 102866 - ALIEN_ABDUCTION_TRACKER: 'CommonStatisticId' = 102865 - ALIEN_MEMORY_ERASE_COOLDOWN: 'CommonStatisticId' = 103694 - ALIEN_WATCH_ALIEN_TV: 'CommonStatisticId' = 107154 - ANCIENT_ARTIFACT_UNCOVER_STATE_FLAG: 'CommonStatisticId' = 184279 - APARTMENT_BULLETIN_BOARD_TIMER: 'CommonStatisticId' = 145322 - ARCADE_MACHINE_GAME_OVER_TIME_OUT: 'CommonStatisticId' = 128204 - ARCADE_MACHINE_LIVES_LEFT: 'CommonStatisticId' = 127410 - ARCADE_MACHINE_NUMBER_OF_PLAYERS: 'CommonStatisticId' = 128094 - ARCADE_MACHINE_PROGRESSION: 'CommonStatisticId' = 127408 - ARCHAEOLOGY_SKILL_GIVE_AUTHENTICATION_MAIL: 'CommonStatisticId' = 176117 - ARCHAEOLOGY_TABLE_ANALYZE_COLLECTIBLE: 'CommonStatisticId' = 182766 - ARCHAEOLOGY_TABLE_AUTHENTICATE_ARTIFACT: 'CommonStatisticId' = 182767 - ARCHAEOLOGY_TABLE_EXTRACT_ELEMENT: 'CommonStatisticId' = 182769 - ARCHAEOLOGY_TABLE_REFINE_CRYSTAL: 'CommonStatisticId' = 182768 - ARCHAEOLOGY_TABLE_UNCOVER_ARTIFACT: 'CommonStatisticId' = 182770 - ASKED_FOR_ADVICE: 'CommonStatisticId' = 166010 - ASPIRATION_WORLD_FAMOUS_CELEBRITY_ASKED_FOR_SELFIE_COUNT: 'CommonStatisticId' = 197546 - ASPIRATION_WORLD_FAMOUS_CELEBRITY_INCITE_CHEER_COUNT: 'CommonStatisticId' = 197547 - ATTRACTOR_POINTS_TOURIST_TAKE_PHOTO: 'CommonStatisticId' = 178223 - ATTRACTOR_POINTS_TOURIST_VIEW: 'CommonStatisticId' = 196996 - AUTO_PET_FEEDER_FOOD_REMAINING: 'CommonStatisticId' = 159119 - AUTONOMY_FAMILY_BULLETIN_BOARD: 'CommonStatisticId' = 166672 - AUTONOMY_GHOST_HAUNT: 'CommonStatisticId' = 102775 - AUTONOMY_TRAIT_GHOST_COW_PLANT: 'CommonStatisticId' = 102856 - AWAY_ACTION_DIRTY: 'CommonStatisticId' = 75572 - AWAY_ACTION_GARDEN: 'CommonStatisticId' = 75733 - AWAY_ACTIONS_BEDS: 'CommonStatisticId' = 76162 - AWAY_ACTIONS_GARDEN_PLANTS: 'CommonStatisticId' = 76182 - AWAY_ACTIONS_HAS_SKILL_OBJECTS_BARTENDING: 'CommonStatisticId' = 76256 - AWAY_ACTIONS_HAS_SKILL_OBJECTS_CHARISMA: 'CommonStatisticId' = 76257 - AWAY_ACTIONS_HAS_SKILL_OBJECTS_CHILD_CREATIVITY: 'CommonStatisticId' = 76272 - AWAY_ACTIONS_HAS_SKILL_OBJECTS_CHILD_MENTAL: 'CommonStatisticId' = 76273 - AWAY_ACTIONS_HAS_SKILL_OBJECTS_CHILD_MOTOR: 'CommonStatisticId' = 76274 - AWAY_ACTIONS_HAS_SKILL_OBJECTS_CHILD_SOCIAL: 'CommonStatisticId' = 76275 - AWAY_ACTIONS_HAS_SKILL_OBJECTS_COMEDY: 'CommonStatisticId' = 76258 - AWAY_ACTIONS_HAS_SKILL_OBJECTS_COOKING: 'CommonStatisticId' = 76263 - AWAY_ACTIONS_HAS_SKILL_OBJECTS_FISHING: 'CommonStatisticId' = 76259 - AWAY_ACTIONS_HAS_SKILL_OBJECTS_FITNESS: 'CommonStatisticId' = 76276 - AWAY_ACTIONS_HAS_SKILL_OBJECTS_GUITAR: 'CommonStatisticId' = 76261 - AWAY_ACTIONS_HAS_SKILL_OBJECTS_HANDINESS: 'CommonStatisticId' = 76262 - AWAY_ACTIONS_HAS_SKILL_OBJECTS_LOGIC: 'CommonStatisticId' = 76260 - AWAY_ACTIONS_HAS_SKILL_OBJECTS_MISCHIEF: 'CommonStatisticId' = 76264 - AWAY_ACTIONS_HAS_SKILL_OBJECTS_PAINTING: 'CommonStatisticId' = 76265 - AWAY_ACTIONS_HAS_SKILL_OBJECTS_PIANO: 'CommonStatisticId' = 76266 - AWAY_ACTIONS_HAS_SKILL_OBJECTS_PROGRAMMING: 'CommonStatisticId' = 76267 - AWAY_ACTIONS_HAS_SKILL_OBJECTS_ROCKET_SCIENCE: 'CommonStatisticId' = 76268 - AWAY_ACTIONS_HAS_SKILL_OBJECTS_VIDEO_GAMING: 'CommonStatisticId' = 76269 - AWAY_ACTIONS_HAS_SKILL_OBJECTS_VIOLIN: 'CommonStatisticId' = 76270 - AWAY_ACTIONS_HAS_SKILL_OBJECTS_WELLNESS: 'CommonStatisticId' = 118846 - AWAY_ACTIONS_HAS_SKILL_OBJECTS_WRITING: 'CommonStatisticId' = 76271 - AWAY_ACTIONS_ITEMS_TO_CLEAN: 'CommonStatisticId' = 76166 - BABY_CARE_HUNGER: 'CommonStatisticId' = 38633 - BABY_CARE_HYGIENE: 'CommonStatisticId' = 38632 - BABY_CARE_SOCIAL: 'CommonStatisticId' = 38634 - BABY_FALLING_ASLEEP: 'CommonStatisticId' = 100020 - BABY_NEW: 'CommonStatisticId' = 98939 - BANQUET_TABLE_FOOD_SPAWNED: 'CommonStatisticId' = 116824 - BASKETBALL_COACH_TIMER: 'CommonStatisticId' = 154698 - BASSINET_NEGLECTED: 'CommonStatisticId' = 100339 - BECOMING_VAMPIRE: 'CommonStatisticId' = 149438 - BED_MONSTER_UNDER_REL_TRACKER: 'CommonStatisticId' = 136457 - BEE_BOX_HONEY: 'CommonStatisticId' = 186126 - BEE_BOX_MITES_COUNTDOWN: 'CommonStatisticId' = 190590 - BEE_BOX_MOOD: 'CommonStatisticId' = 186127 - BIRD_FLOCK_DESTROY_FLOCK: 'CommonStatisticId' = 174711 - BLESSINGS_ANCIENT_JOY_CONTAGIOUS: 'CommonStatisticId' = 175092 - BONFIRE_FIRE_INTENSITY: 'CommonStatisticId' = 121461 - BONSAI_GROWTH: 'CommonStatisticId' = 16450 - BOOK_CRAFTING_LEVEL: 'CommonStatisticId' = 100664 - BOOKING_STATION_FINGERPRINT_COOLDOWN: 'CommonStatisticId' = 110663 - BOOKING_STATION_MUGSHOT_COOLDOWN: 'CommonStatisticId' = 110664 - BOOKING_STATION_SEARCH_COOLDOWN: 'CommonStatisticId' = 110646 - BREW_POT: 'CommonStatisticId' = 27539 - BREW_SINGLE: 'CommonStatisticId' = 27552 - BUFF_ALL_MOTIVES_HIGH_GATE: 'CommonStatisticId' = 27153 - BUFF_BURNING_LOVE_START_FIRE: 'CommonStatisticId' = 107076 - BUFF_CLEANING_EMOTION: 'CommonStatisticId' = 24005 - BUFF_CONFIDENT_BY_POTION: 'CommonStatisticId' = 26335 - BUFF_DROWN_GHOST_FEAR_OF_WATER: 'CommonStatisticId' = 107571 - BUFF_ENERGIZED_BY_POTION: 'CommonStatisticId' = 26337 - BUFF_ENOUGH_ALREADY: 'CommonStatisticId' = 157743 - BUFF_FLIRTY_BY_POTION: 'CommonStatisticId' = 26305 - BUFF_FOCUSED_BY_POTION: 'CommonStatisticId' = 26338 - BUFF_GHOST_ANGRY: 'CommonStatisticId' = 102473 - BUFF_GHOST_EMBARRASSMENT: 'CommonStatisticId' = 102525 - BUFF_GHOST_PLAYFUL: 'CommonStatisticId' = 102501 - BUFF_HAPPY_BY_POTION: 'CommonStatisticId' = 26339 - BUFF_HERBALIST_POTION_INSECT_REPELLENT: 'CommonStatisticId' = 104530 - BUFF_HERBALIST_POTION_SKIN_BALM: 'CommonStatisticId' = 104568 - BUFF_HYPER_CHARGED: 'CommonStatisticId' = 190884 - BUFF_INSIDER_TRAIT_CURIOUS_ABOUT_CLUBS: 'CommonStatisticId' = 125580 - BUFF_INSIDER_TRAIT_MISS_HANGING_OUT: 'CommonStatisticId' = 125579 - BUFF_INSPIRED_BY_POTION: 'CommonStatisticId' = 26340 - BUFF_LOST_FIGHT: 'CommonStatisticId' = 16445 - BUFF_OBJECT_BATHTUB_BUBBLES: 'CommonStatisticId' = 16480 - BUFF_OBJECT_BATHTUB_PLAY: 'CommonStatisticId' = 8229 - BUFF_OBJECT_BED_RELAX: 'CommonStatisticId' = 16482 - BUFF_OBJECT_BONSAI_ONE_WITH_PLANT: 'CommonStatisticId' = 40066 - BUFF_OBJECT_BOOK_READ_FLIRTY_LOW: 'CommonStatisticId' = 16490 - BUFF_OBJECT_BOOK_READ_FOCUSED_LOW: 'CommonStatisticId' = 16491 - BUFF_OBJECT_BOOK_READ_PLAYFUL_DIRTY: 'CommonStatisticId' = 16494 - BUFF_OBJECT_BOOK_READ_SKILL_TOO_EASY: 'CommonStatisticId' = 16497 - BUFF_OBJECT_BOOK_READ_SKILL_TOO_HARD: 'CommonStatisticId' = 16498 - BUFF_OBJECT_BOOK_SKILL_TOO_EASY_VAMPIRE_BOOK: 'CommonStatisticId' = 149624 - BUFF_OBJECT_BOOK_SKILL_TOO_HARD_VAMPIRE_BOOK: 'CommonStatisticId' = 149626 - BUFF_OBJECT_CELEBU_SERUM_DRANK_CONFIDENT: 'CommonStatisticId' = 194907 - BUFF_OBJECT_CELEBU_SERUM_DRANK_ENERGY: 'CommonStatisticId' = 194909 - BUFF_OBJECT_CELEBU_SERUM_DRANK_FLIRTY: 'CommonStatisticId' = 194910 - BUFF_OBJECT_CELEBU_SERUM_DRANK_FOCUS: 'CommonStatisticId' = 194911 - BUFF_OBJECT_CELEBU_SERUM_DRANK_FUN: 'CommonStatisticId' = 194905 - BUFF_OBJECT_CELEBU_SERUM_DRANK_HAPPY: 'CommonStatisticId' = 194912 - BUFF_OBJECT_CELEBU_SERUM_DRANK_HYGIENE: 'CommonStatisticId' = 194906 - BUFF_OBJECT_CELEBU_SERUM_DRANK_INSPIRED: 'CommonStatisticId' = 194914 - BUFF_OBJECT_CELEBU_SERUM_DRANK_SLEEP: 'CommonStatisticId' = 194915 - BUFF_OBJECT_COFFEE_CAFFEINE0: 'CommonStatisticId' = 100836 - BUFF_OBJECT_COFFEE_CAFFEINE1: 'CommonStatisticId' = 16500 - BUFF_OBJECT_COFFEE_CAFFEINE2: 'CommonStatisticId' = 99750 - BUFF_OBJECT_COFFEE_OVERLOAD: 'CommonStatisticId' = 99782 - BUFF_OBJECT_COMPUTER_BRAIN_FRIED: 'CommonStatisticId' = 36128 - BUFF_OBJECT_COMPUTER_VAMPIRE_RESEARCH_TOO_EASY: 'CommonStatisticId' = 153825 - BUFF_OBJECT_COOKING_OBJECTS: 'CommonStatisticId' = 76609 - BUFF_OBJECT_FITNESS_FATIGUE: 'CommonStatisticId' = 16508 - BUFF_OBJECT_FITNESS_GOOD_WORKOUT: 'CommonStatisticId' = 97348 - BUFF_OBJECT_FITNESS_PULLED_MUSCLE: 'CommonStatisticId' = 97347 - BUFF_OBJECT_HOT_TUB_AROMATHERAPY_JASMINE: 'CommonStatisticId' = 118694 - BUFF_OBJECT_HOT_TUB_AROMATHERAPY_LEMON: 'CommonStatisticId' = 118693 - BUFF_OBJECT_HOT_TUB_AROMATHERAPY_PEPPERMINT: 'CommonStatisticId' = 118696 - BUFF_OBJECT_HOT_TUB_AROMATHERAPY_SAGE: 'CommonStatisticId' = 118695 - BUFF_OBJECT_MIRROR_BODY_SPRAY: 'CommonStatisticId' = 16522 - BUFF_OBJECT_MIRROR_BREATH_SPRAY: 'CommonStatisticId' = 16523 - BUFF_OBJECT_MIRROR_GUSSY_UP: 'CommonStatisticId' = 16525 - BUFF_OBJECT_MONKEY_BARS_PLAY: 'CommonStatisticId' = 31634 - BUFF_OBJECT_PLUMBING_USE_DIRTY: 'CommonStatisticId' = 10164 - BUFF_OBJECT_SEATING_COMFORT: 'CommonStatisticId' = 25002 - BUFF_OBJECT_SEATING_DISCOMFORT: 'CommonStatisticId' = 24998 - BUFF_OBJECT_SHOWER_TAKE_SHOWER_HIGH_QUALITY: 'CommonStatisticId' = 9963 - BUFF_OBJECT_SHOWER_TAKE_SHOWER_HIGH_QUALITY_UPGRADE: 'CommonStatisticId' = 10132 - BUFF_OBJECT_SHOWER_TAKE_SHOWER_LOW_QUALITY: 'CommonStatisticId' = 9964 - BUFF_OBJECT_SHOWER_TAKE_SHOWER_UPGRADE: 'CommonStatisticId' = 10133 - BUFF_OBJECT_STEAM_ROOM_COMFORT: 'CommonStatisticId' = 119390 - BUFF_OBJECT_STEAM_ROOM_EXPOSURE: 'CommonStatisticId' = 119409 - BUFF_OBJECT_STEREO_MUSIC_TODDLER: 'CommonStatisticId' = 147770 - BUFF_OBJECT_SURFACE_USE_DIRTY: 'CommonStatisticId' = 36390 - BUFF_OBJECT_TV_GENERIC_WATCH: 'CommonStatisticId' = 31014 - BUFF_OBJECT_VOODOO_DOLL_DAZED: 'CommonStatisticId' = 16540 - BUFF_OBJECT_VOODOO_DOLL_FUN: 'CommonStatisticId' = 16541 - BUFF_OBJECT_VOODOO_DOLL_LOVE: 'CommonStatisticId' = 16542 - BUFF_OBJECT_VOODOO_DOLL_PAIN: 'CommonStatisticId' = 16543 - BUFF_OBJECT_VOODOO_DOLL_UNCOMFORTABLE: 'CommonStatisticId' = 16544 - BUFF_OBJECT_WRITING_WRITERS_BLOCK: 'CommonStatisticId' = 34130 - BUFF_ON_FOREIGN_LOT: 'CommonStatisticId' = 16446 - BUFF_RELATIONSHIP_FIGHT_WIN: 'CommonStatisticId' = 16552 - BUFF_RELATIONSHIP_FIGHT_WIN_VILLAIN: 'CommonStatisticId' = 99532 - BUFF_RELATIONSHIP_LOST_FIGHT_VILLAIN: 'CommonStatisticId' = 99536 - BUFF_RELATIONSHIP_NEW_SIBLING: 'CommonStatisticId' = 97689 - BUFF_RELATIONSHIP_NEW_SIBLING_BABY: 'CommonStatisticId' = 97930 - BUFF_SERENADED: 'CommonStatisticId' = 39460 - BUFF_SERUM_FAILURES_TRACKER: 'CommonStatisticId' = 105159 - BUFF_SOCIAL_ANGRY_CONVERSATION: 'CommonStatisticId' = 10642 - BUFF_SOCIAL_AWKWARD_TURTLE: 'CommonStatisticId' = 37843 - BUFF_SOCIAL_BORING_CONVERSATION: 'CommonStatisticId' = 10645 - BUFF_SOCIAL_DULL_HUMOR: 'CommonStatisticId' = 37856 - BUFF_SOCIAL_EMBARRASSING_CONVERSATION: 'CommonStatisticId' = 10643 - BUFF_SOCIAL_FLATTERED: 'CommonStatisticId' = 37857 - BUFF_SOCIAL_FLIRTY_CONVERSATION: 'CommonStatisticId' = 10641 - BUFF_SOCIAL_HAPPY_CONVERSATION: 'CommonStatisticId' = 10644 - BUFF_SOCIAL_HOT_N_HEAVY: 'CommonStatisticId' = 37858 - BUFF_SOCIAL_MADE_A_DEEP_CONNECTION: 'CommonStatisticId' = 37948 - BUFF_SOCIAL_ON_A_ROLL: 'CommonStatisticId' = 37950 - BUFF_SOCIAL_PLAYFUL_CONVERSATION: 'CommonStatisticId' = 10640 - BUFF_STEREO_MUSIC: 'CommonStatisticId' = 96813 - BUFF_STEREO_NEW_AGE_BORED: 'CommonStatisticId' = 118098 - BUFF_STEREO_NEW_AGE_FOCUSED: 'CommonStatisticId' = 118099 - BUFF_STEREO_SUMMER_STRUT: 'CommonStatisticId' = 186227 - BUFF_STEREO_WINTER_HOLIDAY: 'CommonStatisticId' = 186234 - BUFF_TIME_IN_RESTAURANT_FLIRTY_BREAKFAST: 'CommonStatisticId' = 133606 - BUFF_TIME_IN_RESTAURANT_FLIRTY_DINNER: 'CommonStatisticId' = 133608 - BUFF_TIME_IN_RESTAURANT_FLIRTY_LUNCH: 'CommonStatisticId' = 133607 - BUFF_TIME_IN_RESTAURANT_HAPPY_BREAKFAST: 'CommonStatisticId' = 133362 - BUFF_TIME_IN_RESTAURANT_HAPPY_DINNER: 'CommonStatisticId' = 133416 - BUFF_TIME_IN_RESTAURANT_HAPPY_LUNCH: 'CommonStatisticId' = 133415 - BUFF_TODDLER_AWAKE: 'CommonStatisticId' = 154194 - BUFF_TODDLER_CAREGIVER_AWAKE: 'CommonStatisticId' = 157460 - BUFF_TRAIT_FARTISAN_KNOCK_OUT: 'CommonStatisticId' = 16570 - BUFF_TRAIT_GHOST_OLD_AGE_PET_IDLE_YOWL: 'CommonStatisticId' = 166679 - BUFF_TRAIT_SNOB_HORSESHOES_BORING: 'CommonStatisticId' = 111547 - BUFF_WEATHER_TV_CLIMATE_CHANGE: 'CommonStatisticId' = 179838 - BUSH_PET_AVAILABLE: 'CommonStatisticId' = 171519 - BUSKING_TOTAL_TIPS_TNS: 'CommonStatisticId' = 144187 - CAMPFIRE_FIRE_INTENSITY: 'CommonStatisticId' = 101759 - CAREER_ACTIVIST_PROMOTED_CAUSE_SIMS_COUNT: 'CommonStatisticId' = 135405 - CAREER_ACTIVIST_PROMOTED_POLICY_SIMS_COUNT: 'CommonStatisticId' = 135568 - CAREER_ACTIVIST_SECURED_VOTE_SIMS_COUNT: 'CommonStatisticId' = 136297 - CAREER_ACTIVIST_SIMOLEONS_RAISED_FOR_CAUSE_ALL: 'CommonStatisticId' = 135754 - CAREER_ACTIVIST_SIMOLEONS_RAISED_FOR_CAUSE_ECONOMY_STATISTIC: 'CommonStatisticId' = 135469 - CAREER_ACTIVIST_SIMOLEONS_RAISED_FOR_CAUSE_ECONOMY: 'CommonStatisticId' = 136369 - CAREER_ACTIVIST_SIMOLEONS_RAISED_FOR_CAUSE_ENVIRONMENT_STATISTIC: 'CommonStatisticId' = 135467 - CAREER_ACTIVIST_SIMOLEONS_RAISED_FOR_CAUSE_ENVIRONMENT: 'CommonStatisticId' = 136370 - CAREER_ACTIVIST_SIMOLEONS_RAISED_FOR_CAUSE_JUSTICE_STATISTIC: 'CommonStatisticId' = 135471 - CAREER_ACTIVIST_SIMOLEONS_RAISED_FOR_CAUSE_JUSTICE: 'CommonStatisticId' = 136371 - CAREER_ACTIVIST_SIMOLEONS_RAISED_FOR_CAUSE_PEACE_STATISTIC: 'CommonStatisticId' = 135470 - CAREER_ACTIVIST_SIMOLEONS_RAISED_FOR_CAUSE_PEACE: 'CommonStatisticId' = 136372 - CAREER_ACTIVIST_SIMOLEONS_RAISED_FOR_CAUSE_TAX_STATISTIC: 'CommonStatisticId' = 135468 - CAREER_ACTIVIST_SIMOLEONS_RAISED_FOR_CAUSE_TAX: 'CommonStatisticId' = 136373 - CAREER_BANK_BLUEPRINT_INSIDE_SCOOP: 'CommonStatisticId' = 33952 - CAREER_BENEFIT_ACTIVIST: 'CommonStatisticId' = 135207 - CAREER_BENEFIT_ACTIVIST_CHARITY: 'CommonStatisticId' = 151710 - CAREER_BENEFIT_ACTIVIST_POLITICIAN: 'CommonStatisticId' = 153615 - CAREER_BENEFIT_AGENT: 'CommonStatisticId' = 76229 - CAREER_BENEFIT_ASTRONAUT: 'CommonStatisticId' = 76227 - CAREER_BENEFIT_ATHLETE: 'CommonStatisticId' = 106738 - CAREER_BENEFIT_BUSINESS: 'CommonStatisticId' = 106739 - CAREER_BENEFIT_CRIMINAL: 'CommonStatisticId' = 76225 - CAREER_BENEFIT_CRITIC: 'CommonStatisticId' = 136153 - CAREER_BENEFIT_CULINARY: 'CommonStatisticId' = 76232 - CAREER_BENEFIT_DRAMA_CLUB: 'CommonStatisticId' = 199910 - CAREER_BENEFIT_ENTERTAINER: 'CommonStatisticId' = 76234 - CAREER_BENEFIT_GARDENER: 'CommonStatisticId' = 186189 - CAREER_BENEFIT_PAINTER: 'CommonStatisticId' = 76236 - CAREER_BENEFIT_SCOUTING: 'CommonStatisticId' = 187002 - CAREER_BENEFIT_SOCIAL_MEDIA: 'CommonStatisticId' = 135396 - CAREER_BENEFIT_STYLE_INFLUENCER: 'CommonStatisticId' = 193215 - CAREER_BENEFIT_TECH: 'CommonStatisticId' = 76237 - CAREER_BENEFIT_WRITER: 'CommonStatisticId' = 76238 - CAREER_CHILD_NEGLECT: 'CommonStatisticId' = 98946 - CAREER_DETECTIVE_ANALYZE_CLUE_HANDICAP: 'CommonStatisticId' = 115370 - CAREER_DETECTIVE_ARRESTED_SUSPECT: 'CommonStatisticId' = 112060 - CAREER_DETECTIVE_CASES_SOLVED: 'CommonStatisticId' = 111452 - CAREER_DETECTIVE_DEBUG_EVENT_SELECTED: 'CommonStatisticId' = 112734 - CAREER_DETECTIVE_HAS_CASE: 'CommonStatisticId' = 112059 - CAREER_DETECTIVE_INTERROGATION_AT100: 'CommonStatisticId' = 116463 - CAREER_DETECTIVE_ON_PATROL_TIMER: 'CommonStatisticId' = 116389 - CAREER_DETECTIVE_SINGLE_DAY_GOAL_TRACKING_CITATIONS: 'CommonStatisticId' = 116375 - CAREER_DETECTIVE_SINGLE_DAY_GOAL_TRACKING_CRIME_PICS: 'CommonStatisticId' = 116378 - CAREER_DETECTIVE_SINGLE_DAY_GOAL_TRACKING_EVIDENCE_COLLECTED: 'CommonStatisticId' = 116377 - CAREER_DETECTIVE_SINGLE_DAY_GOAL_TRACKING_SOCIAL_CIV: 'CommonStatisticId' = 116376 - CAREER_DETECTIVE_SINGLE_DAY_GOAL_TRACKING_WITNESS_REPORTS: 'CommonStatisticId' = 116379 - CAREER_DIVERT_FUNDS_COOLDOWN: 'CommonStatisticId' = 36961 - CAREER_HACK_PAYOUT_MULTIPLIER: 'CommonStatisticId' = 33981 - CAREER_HOMEWORK: 'CommonStatisticId' = 16571 - CAREER_HOMEWORK_EXTRA_CREDIT: 'CommonStatisticId' = 33900 - CAREER_HOMEWORK_MAKEUP: 'CommonStatisticId' = 33899 - CAREER_INSTANT_BACKGROUND_CHECK_COOLDOWN: 'CommonStatisticId' = 34735 - CAREER_INTELLIGENCE_DB_WORK_PERF: 'CommonStatisticId' = 34167 - CAREER_INVESTIGATE_SIM_COOLDOWN: 'CommonStatisticId' = 34203 - CAREER_PAINTER_AGENT: 'CommonStatisticId' = 30738 - CAREER_PERFORMANCE: 'CommonStatisticId' = 16662 - CAREER_PERFORMANCE_ACTIVIST: 'CommonStatisticId' = 141770 - CAREER_PERFORMANCE_ACTOR: 'CommonStatisticId' = 196749 - CAREER_PERFORMANCE_ASTRONAUT: 'CommonStatisticId' = 24170 - CAREER_PERFORMANCE_ATHLETE: 'CommonStatisticId' = 106741 - CAREER_PERFORMANCE_BUSINESS: 'CommonStatisticId' = 106742 - CAREER_PERFORMANCE_CRIMINAL: 'CommonStatisticId' = 27782 - CAREER_PERFORMANCE_CRITIC: 'CommonStatisticId' = 136181 - CAREER_PERFORMANCE_CULINARY: 'CommonStatisticId' = 24167 - CAREER_PERFORMANCE_DETECTIVE: 'CommonStatisticId' = 108581 - CAREER_PERFORMANCE_DOCTOR: 'CommonStatisticId' = 108718 - CAREER_PERFORMANCE_DRAMA_CLUB: 'CommonStatisticId' = 199905 - CAREER_PERFORMANCE_ENTERTAINER: 'CommonStatisticId' = 27781 - CAREER_PERFORMANCE_GARDENER: 'CommonStatisticId' = 186187 - CAREER_PERFORMANCE_GRADE_SCHOOL: 'CommonStatisticId' = 24169 - CAREER_PERFORMANCE_HIGHSCHOOL: 'CommonStatisticId' = 24168 - CAREER_PERFORMANCE_MILITARY: 'CommonStatisticId' = 202507 - CAREER_PERFORMANCE_PAINTER: 'CommonStatisticId' = 27786 - CAREER_PERFORMANCE_SCIENTIST: 'CommonStatisticId' = 108717 - CAREER_PERFORMANCE_SECRET_AGENT: 'CommonStatisticId' = 27780 - CAREER_PERFORMANCE_SOCIAL_MEDIA: 'CommonStatisticId' = 135394 - CAREER_PERFORMANCE_STYLE_INFLUENCER: 'CommonStatisticId' = 193216 - CAREER_PERFORMANCE_TECH_GURU: 'CommonStatisticId' = 27783 - CAREER_PERFORMANCE_TEEN_BABYSITTER: 'CommonStatisticId' = 35169 - CAREER_PERFORMANCE_TEEN_BARISTA: 'CommonStatisticId' = 35168 - CAREER_PERFORMANCE_TEEN_FAST_FOOD: 'CommonStatisticId' = 35165 - CAREER_PERFORMANCE_TEEN_MANUAL_LABOR: 'CommonStatisticId' = 35166 - CAREER_PERFORMANCE_TEEN_RETAIL: 'CommonStatisticId' = 35167 - CAREER_PERFORMANCE_VOLUNTEER_SCOUTING: 'CommonStatisticId' = 186592 - CAREER_PERFORMANCE_WRITER: 'CommonStatisticId' = 27784 - CAREER_PICKPOCKET_COOLDOWN: 'CommonStatisticId' = 36960 - CAREER_SCIENTIST_BREAKTHROUGH_LEVEL: 'CommonStatisticId' = 114887 - CAREER_SCIENTIST_BREAKTHROUGH_PROGRESS: 'CommonStatisticId' = 108216 - CAREER_SCIENTIST_INVENT_ALIEN_PORTAL: 'CommonStatisticId' = 115207 - CAREER_SCIENTIST_INVENT_CLONING_MACHINE: 'CommonStatisticId' = 115208 - CAREER_SCIENTIST_INVENT_HOVER_LAMP: 'CommonStatisticId' = 115205 - CAREER_SCIENTIST_INVENT_MOMENTUM_CONSERVER: 'CommonStatisticId' = 115204 - CAREER_SCIENTIST_INVENT_SATELLITE_DISH: 'CommonStatisticId' = 115203 - CAREER_SCIENTIST_INVENT_SIM_RAY: 'CommonStatisticId' = 115206 - CAREER_SCIENTIST_INVENTING: 'CommonStatisticId' = 113011 - CAREER_SCIENTIST_SITUATION_GOAL_CHAIN_BREAKTHROUGH_10: 'CommonStatisticId' = 112767 - CAREER_SCIENTIST_SITUATION_GOAL_CHAIN_BREAKTHROUGH_11: 'CommonStatisticId' = 112768 - CAREER_SCIENTIST_SITUATION_GOAL_CHAIN_BREAKTHROUGH_12: 'CommonStatisticId' = 112769 - CAREER_SCIENTIST_SITUATION_GOAL_CHAIN_BREAKTHROUGH_13: 'CommonStatisticId' = 112770 - CAREER_SCIENTIST_SITUATION_GOAL_CHAIN_BREAKTHROUGH_14: 'CommonStatisticId' = 112771 - CAREER_SCIENTIST_SITUATION_GOAL_CHAIN_BREAKTHROUGH_15: 'CommonStatisticId' = 112772 - CAREER_SCIENTIST_SITUATION_GOAL_CHAIN_BREAKTHROUGH_16: 'CommonStatisticId' = 112773 - CAREER_SCIENTIST_SITUATION_GOAL_CHAIN_BREAKTHROUGH_17: 'CommonStatisticId' = 112774 - CAREER_SCIENTIST_SITUATION_GOAL_CHAIN_BREAKTHROUGH_18: 'CommonStatisticId' = 112775 - CAREER_SCIENTIST_SITUATION_GOAL_CHAIN_BREAKTHROUGH_19: 'CommonStatisticId' = 112776 - CAREER_SCIENTIST_SITUATION_GOAL_CHAIN_BREAKTHROUGH_1: 'CommonStatisticId' = 112715 - CAREER_SCIENTIST_SITUATION_GOAL_CHAIN_BREAKTHROUGH_20: 'CommonStatisticId' = 112817 - CAREER_SCIENTIST_SITUATION_GOAL_CHAIN_BREAKTHROUGH_21: 'CommonStatisticId' = 112758 - CAREER_SCIENTIST_SITUATION_GOAL_CHAIN_BREAKTHROUGH_2: 'CommonStatisticId' = 112759 - CAREER_SCIENTIST_SITUATION_GOAL_CHAIN_BREAKTHROUGH_3: 'CommonStatisticId' = 112760 - CAREER_SCIENTIST_SITUATION_GOAL_CHAIN_BREAKTHROUGH_4: 'CommonStatisticId' = 112761 - CAREER_SCIENTIST_SITUATION_GOAL_CHAIN_BREAKTHROUGH_5: 'CommonStatisticId' = 112762 - CAREER_SCIENTIST_SITUATION_GOAL_CHAIN_BREAKTHROUGH_6: 'CommonStatisticId' = 112763 - CAREER_SCIENTIST_SITUATION_GOAL_CHAIN_BREAKTHROUGH_7: 'CommonStatisticId' = 112764 - CAREER_SCIENTIST_SITUATION_GOAL_CHAIN_BREAKTHROUGH_8: 'CommonStatisticId' = 112765 - CAREER_SCIENTIST_SITUATION_GOAL_CHAIN_BREAKTHROUGH_9: 'CommonStatisticId' = 112766 - CAREER_SCIENTIST_UPGRADE_CLONE_SIM: 'CommonStatisticId' = 113556 - CAREER_SCIENTIST_UPGRADE_DETECT_ALIENS: 'CommonStatisticId' = 113555 - CAREER_SCIENTIST_UPGRADE_MIND_CONTROL_CHANGE_CLOTHES: 'CommonStatisticId' = 113336 - CAREER_SCIENTIST_UPGRADE_MIND_CONTROL_CLEAN: 'CommonStatisticId' = 113333 - CAREER_SCIENTIST_UPGRADE_MIND_CONTROL_EAT: 'CommonStatisticId' = 113335 - CAREER_SCIENTIST_UPGRADE_MIND_CONTROL_PANIC: 'CommonStatisticId' = 113339 - CAREER_SCIENTIST_UPGRADE_MIND_CONTROL_SIT: 'CommonStatisticId' = 113338 - CAREER_SCIENTIST_UPGRADE_MIND_CONTROL_SLEEP: 'CommonStatisticId' = 113337 - CAREER_SCIENTIST_UPGRADE_TRANSFORM: 'CommonStatisticId' = 113247 - CAREER_SCIENTIST_UPGRADE_TRANSFORM_SIM: 'CommonStatisticId' = 113299 - CAREER_SCIENTIST_UPGRADE_TRAVEL_ALIEN_WORLD: 'CommonStatisticId' = 113557 - CAREER_SCOUTING_BADGES_COLLECTED: 'CommonStatisticId' = 187093 - CAREER_SESSION_PERFORMANCE_CHANGE: 'CommonStatisticId' = 99886 - CAREER_SOCIAL_MEDIA_FOLLOWERS_LOST_GAINED_TNS_TOTAL: 'CommonStatisticId' = 143928 - CAREER_SOCIAL_MEDIA_PROFIT_GAINED_TNS_TOTAL: 'CommonStatisticId' = 143927 - CAREER_SOCIAL_MEDIA_PUBLIC_RELATIONS_REPRESENT: 'CommonStatisticId' = 145911 - CAREER_TECH_GURU_FREELANCE_MULTIPLIER: 'CommonStatisticId' = 34384 - CAREER_TONE_PERFORMANCE: 'CommonStatisticId' = 75576 - CAT_COLD_WEATHER_GET_WARM: 'CommonStatisticId' = 185585 - CAT_HOT_WEATHER_LAZE: 'CommonStatisticId' = 183616 - CHALET_GARDENS_WANDER_MAZE_COOLDOWN: 'CommonStatisticId' = 126322 - CHEF_STATION_IN_USE: 'CommonStatisticId' = 156196 - CHEF_STATION_ORDER_COUNT: 'CommonStatisticId' = 131251 - CHILDHOOD_PHASE: 'CommonStatisticId' = 164773 - COLLECT_AFTER_EATING_TIMER: 'CommonStatisticId' = 74875 - COLLECT_SPORE_GLOW: 'CommonStatisticId' = 205802 - COLLECTABLE_ROCK_DECAY: 'CommonStatisticId' = 77481 - COLLECTION_CITY_LIFE_POWER_BOX_POSTERS_SPAWN_TIMER: 'CommonStatisticId' = 143929 - COLLECTION_SPAWN_GROUND_OBJECT: 'CommonStatisticId' = 16572 - COLLECTION_SPAWN_SLOT_OBJECT: 'CommonStatisticId' = 16573 - COMEDY_SKILL_PERFORMANCE_PAYOUT: 'CommonStatisticId' = 31619 - COMEDY_SKILL_PRACTICE_ROUTINE: 'CommonStatisticId' = 30481 - CRAFT_SALES_TABLE_CREATE_OBJECT: 'CommonStatisticId' = 147957 - CRAFTING_PROGRESS: 'CommonStatisticId' = 16574 - CRIME_MAP_ANALYZE_COOLDOWN: 'CommonStatisticId' = 107612 - CULLING_GHOST: 'CommonStatisticId' = 161328 - CULTURAL_FOOD_RECIPE_UNLOCKS: 'CommonStatisticId' = 137036 - CURIOUS_TRAIT_SEARCH_COUNT: 'CommonStatisticId' = 172155 - CURSES_ANCIENT_SICKNESS_CONTAGIOUS_COMMON: 'CommonStatisticId' = 175025 - CURSES_ANCIENT_SICKNESS_CONTAGIOUS_RARE: 'CommonStatisticId' = 175029 - CURSES_ANCIENT_SICKNESS_CONTAGIOUS_UNCOMMON: 'CommonStatisticId' = 175030 - CURSES_SEEING_THINGS_DISPEL_COUNTER: 'CommonStatisticId' = 175277 - DANCE_BATTLE_SCORE: 'CommonStatisticId' = 128954 - DEATH_ELDER_EXHAUSTION: 'CommonStatisticId' = 9451 - DEATH_ELDER_EXHAUSTION_TRACKER: 'CommonStatisticId' = 9450 - DEATH_ELECTROCUTION: 'CommonStatisticId' = 8938 - DEATH_ELECTROCUTION_TRACKER: 'CommonStatisticId' = 8935 - DEATH_PUFFER_FISH: 'CommonStatisticId' = 135086 - DEATH_TEMPERATURE_BURNING: 'CommonStatisticId' = 182175 - DEATH_TEMPERATURE_FREEZING: 'CommonStatisticId' = 182176 - DENIZEN_POND_CLEANING: 'CommonStatisticId' = 194428 - DENIZEN_POND_DIRTINESS: 'CommonStatisticId' = 200850 - DENIZEN_POND_FEEDING: 'CommonStatisticId' = 196544 - DENIZEN_POND_HUNGER: 'CommonStatisticId' = 192251 - DIRT_MOUND_AVAILABILITY: 'CommonStatisticId' = 173092 - DIRT_MOUND_DUG: 'CommonStatisticId' = 172107 - DIRTINESS: 'CommonStatisticId' = 16575 - DISCIPLINE_CAT_JUMP_ON_COUNTERS: 'CommonStatisticId' = 170719 - DISCIPLINE_CAT_SCRATCHING: 'CommonStatisticId' = 162259 - DISCIPLINE_DOG_BARK: 'CommonStatisticId' = 165941 - DISCIPLINE_DOG_EAT_POOP: 'CommonStatisticId' = 168488 - DISCIPLINE_DOG_JUMP_ON_COUNTERS: 'CommonStatisticId' = 170720 - DISCIPLINE_DOG_PUDDLES_PLAY: 'CommonStatisticId' = 162273 - DISCIPLINE_DOG_TOILET: 'CommonStatisticId' = 162261 - DISCIPLINE_FREQUENCY_CAT_JUMP_ON_COUNTERS: 'CommonStatisticId' = 177148 - DISCIPLINE_FREQUENCY_CAT_SCRATCHING: 'CommonStatisticId' = 177149 - DISCIPLINE_FREQUENCY_DOG_BARK: 'CommonStatisticId' = 177150 - DISCIPLINE_FREQUENCY_DOG_CHASE: 'CommonStatisticId' = 177151 - DISCIPLINE_FREQUENCY_DOG_EAT_POOP: 'CommonStatisticId' = 177153 - DISCIPLINE_FREQUENCY_DOG_JUMP_ON_COUNTERS: 'CommonStatisticId' = 177154 - DISCIPLINE_FREQUENCY_DOG_PUDDLES_PLAY: 'CommonStatisticId' = 177155 - DISCIPLINE_FREQUENCY_DOG_TOILET: 'CommonStatisticId' = 177156 - DISCIPLINE_FREQUENCY_PET_ATTACK: 'CommonStatisticId' = 177157 - DISCIPLINE_FREQUENCY_PET_BAT_KNOCK_TRASH: 'CommonStatisticId' = 177158 - DISCIPLINE_FREQUENCY_PET_BEG_EATING: 'CommonStatisticId' = 177159 - DISCIPLINE_FREQUENCY_PET_EAT_PEOPLE_FOOD: 'CommonStatisticId' = 177160 - DISCIPLINE_FREQUENCY_PET_POTTY_TRAINING: 'CommonStatisticId' = 177161 - DISCIPLINE_FREQUENCY_PET_PUDDLES_DRINK: 'CommonStatisticId' = 177162 - DISCIPLINE_FREQUENCY_PET_TRASH_EAT: 'CommonStatisticId' = 177163 - DISCIPLINE_FREQUENCY_PET_TRASH_PLAY: 'CommonStatisticId' = 177164 - DISCIPLINE_FREQUENCY_PET_TRASH_RUMMAGE: 'CommonStatisticId' = 177165 - DISCIPLINE_FREQUENCY_PET_WAKE_UP_SIMS: 'CommonStatisticId' = 177166 - DISCIPLINE_NEED_CAT_JUMP_ON_COUNTERS: 'CommonStatisticId' = 170723 - DISCIPLINE_NEED_CAT_SCRATCHING: 'CommonStatisticId' = 163620 - DISCIPLINE_NEED_DOG_BARK: 'CommonStatisticId' = 168560 - DISCIPLINE_NEED_DOG_CHASE: 'CommonStatisticId' = 163625 - DISCIPLINE_NEED_DOG_EAT_POOP: 'CommonStatisticId' = 168489 - DISCIPLINE_NEED_DOG_JUMP_ON_COUNTERS: 'CommonStatisticId' = 170724 - DISCIPLINE_NEED_DOG_PUDDLES_PLAY: 'CommonStatisticId' = 163629 - DISCIPLINE_NEED_DOG_TOILET: 'CommonStatisticId' = 163630 - DISCIPLINE_NEED_PET_ATTACK: 'CommonStatisticId' = 163631 - DISCIPLINE_NEED_PET_BAT_KNOCK_TRASH: 'CommonStatisticId' = 163731 - DISCIPLINE_NEED_PET_BEG_EATING: 'CommonStatisticId' = 163632 - DISCIPLINE_NEED_PET_EAT_PEOPLE_FOOD: 'CommonStatisticId' = 170722 - DISCIPLINE_NEED_PET_POTTY_TRAINING: 'CommonStatisticId' = 163628 - DISCIPLINE_NEED_PET_PUDDLES_DRINK: 'CommonStatisticId' = 163635 - DISCIPLINE_NEED_PET_TRASH_EAT: 'CommonStatisticId' = 163636 - DISCIPLINE_NEED_PET_TRASH_PLAY: 'CommonStatisticId' = 163637 - DISCIPLINE_NEED_PET_TRASH_RUMMAGE: 'CommonStatisticId' = 163752 - DISCIPLINE_NEED_PET_WAKE_UP_SIMS: 'CommonStatisticId' = 170721 - DISCIPLINE_PET_ATTACK: 'CommonStatisticId' = 162272 - DISCIPLINE_PET_BEG_EATING: 'CommonStatisticId' = 162269 - DISCIPLINE_PET_CHASE: 'CommonStatisticId' = 162263 - DISCIPLINE_PET_EAT_PEOPLE_FOOD: 'CommonStatisticId' = 170717 - DISCIPLINE_PET_POTTY_TRAINING: 'CommonStatisticId' = 162264 - DISCIPLINE_PET_PUDDLES_DRINK: 'CommonStatisticId' = 162265 - DISCIPLINE_PET_TRASH_EAT: 'CommonStatisticId' = 162266 - DISCIPLINE_PET_TRASH_PLAY: 'CommonStatisticId' = 162267 - DISCIPLINE_PET_WAKE_UP_SIMS: 'CommonStatisticId' = 170718 - DOCTOR_CAREER_WORKED_HOURS: 'CommonStatisticId' = 112129 - DOCTOR_PLAY_SET_TOTAL_PLAYTIME: 'CommonStatisticId' = 168522 - DOG_HOT_WEATHER_PANT: 'CommonStatisticId' = 183492 - DOG_SNOWING_RUN: 'CommonStatisticId' = 184225 - DOG_TRAINING_FETCH: 'CommonStatisticId' = 161288 - DOG_TRAINING_HEEL: 'CommonStatisticId' = 161283 - DOG_TRAINING_LIE_DOWN: 'CommonStatisticId' = 161287 - DOG_TRAINING_PLAY_DEAD: 'CommonStatisticId' = 161289 - DOG_TRAINING_ROLL_OVER: 'CommonStatisticId' = 161285 - DOG_TRAINING_SHAKE: 'CommonStatisticId' = 161290 - DOG_TRAINING_SHOW_OFF_TRICKS: 'CommonStatisticId' = 170020 - DOG_TRAINING_SIT: 'CommonStatisticId' = 161284 - DOG_TRAINING_SPEAK: 'CommonStatisticId' = 161286 - DOG_WALK_DOG_TIMER: 'CommonStatisticId' = 166678 - DOLLHOUSE_SMASHED: 'CommonStatisticId' = 35314 - DYNAMIC_SIGN_TIMER: 'CommonStatisticId' = 133263 - EMOTION_AUTONOMY_ANGRY: 'CommonStatisticId' = 16455 - EMOTION_AUTONOMY_ASLEEP: 'CommonStatisticId' = 27146 - EMOTION_AUTONOMY_BORED: 'CommonStatisticId' = 16456 - EMOTION_AUTONOMY_CONFIDENT: 'CommonStatisticId' = 16457 - EMOTION_AUTONOMY_DAZED: 'CommonStatisticId' = 16470 - EMOTION_AUTONOMY_EMBARRASSED: 'CommonStatisticId' = 16462 - EMOTION_AUTONOMY_ENERGIZED: 'CommonStatisticId' = 16463 - EMOTION_AUTONOMY_FLIRTY: 'CommonStatisticId' = 16464 - EMOTION_AUTONOMY_FOCUSED: 'CommonStatisticId' = 16465 - EMOTION_AUTONOMY_HAPPY: 'CommonStatisticId' = 16466 - EMOTION_AUTONOMY_INSPIRED: 'CommonStatisticId' = 16467 - EMOTION_AUTONOMY_PLAYFUL: 'CommonStatisticId' = 16468 - EMOTION_AUTONOMY_POSSESSED: 'CommonStatisticId' = 202880 - EMOTION_AUTONOMY_SAD: 'CommonStatisticId' = 16469 - EMOTION_AUTONOMY_STRESSED: 'CommonStatisticId' = 16471 - EMOTION_AUTONOMY_UNCOMFORTABLE: 'CommonStatisticId' = 16472 - EMOTION_PETS_ANGRY_DOG: 'CommonStatisticId' = 158224 - EMOTION_PETS_ANXIOUS_DOG: 'CommonStatisticId' = 158223 - EMOTION_PETS_ASHAMED_DOG: 'CommonStatisticId' = 158230 - EMOTION_PETS_ASLEEP_DOG: 'CommonStatisticId' = 158229 - EMOTION_PETS_AUTONOMY_HYPER: 'CommonStatisticId' = 157907 - EMOTION_PETS_CATS_AUTONOMY_ANGRY: 'CommonStatisticId' = 158406 - EMOTION_PETS_CATS_AUTONOMY_ANXIOUS: 'CommonStatisticId' = 158189 - EMOTION_PETS_CATS_AUTONOMY_ASLEEP: 'CommonStatisticId' = 158551 - EMOTION_PETS_CATS_AUTONOMY_DROWSY: 'CommonStatisticId' = 158142 - EMOTION_PETS_CATS_AUTONOMY_FLIRTY: 'CommonStatisticId' = 158408 - EMOTION_PETS_CATS_AUTONOMY_HAPPY: 'CommonStatisticId' = 158410 - EMOTION_PETS_CATS_AUTONOMY_SCARED: 'CommonStatisticId' = 158409 - EMOTION_PETS_EXCITED_DOG: 'CommonStatisticId' = 158220 - EMOTION_PETS_FLIRTY_DOG: 'CommonStatisticId' = 158226 - EMOTION_PETS_HAPPY_DOG: 'CommonStatisticId' = 158228 - EMOTION_PETS_MOPEY_DOG: 'CommonStatisticId' = 158222 - EMOTION_PETS_SAD_DOG: 'CommonStatisticId' = 158221 - EMOTION_PETS_SCARED_DOG: 'CommonStatisticId' = 158227 - ENVIRONMENT_ANGRY: 'CommonStatisticId' = 16576 - ENVIRONMENT_ASLEEP: 'CommonStatisticId' = 99396 - ENVIRONMENT_BORED: 'CommonStatisticId' = 16577 - ENVIRONMENT_CONFIDENT: 'CommonStatisticId' = 16578 - ENVIRONMENT_DAZED: 'CommonStatisticId' = 99395 - ENVIRONMENT_DROWSY_PETS: 'CommonStatisticId' = 158141 - ENVIRONMENT_EMBARRASSED: 'CommonStatisticId' = 16579 - ENVIRONMENT_ENERGIZED: 'CommonStatisticId' = 16580 - ENVIRONMENT_FINE: 'CommonStatisticId' = 99397 - ENVIRONMENT_FLIRTY: 'CommonStatisticId' = 16581 - ENVIRONMENT_FOCUSED: 'CommonStatisticId' = 16582 - ENVIRONMENT_HAPPY: 'CommonStatisticId' = 16583 - ENVIRONMENT_HYPER_PETS: 'CommonStatisticId' = 157870 - ENVIRONMENT_IMAGINATIVE: 'CommonStatisticId' = 16584 - ENVIRONMENT_NEGATIVE: 'CommonStatisticId' = 16585 - ENVIRONMENT_PETS_ANXIOUS: 'CommonStatisticId' = 158190 - ENVIRONMENT_PLAYFUL: 'CommonStatisticId' = 16586 - ENVIRONMENT_POSITIVE: 'CommonStatisticId' = 97781 - ENVIRONMENT_POSSESSED: 'CommonStatisticId' = 201541 - ENVIRONMENT_SAD: 'CommonStatisticId' = 16587 - ENVIRONMENT_TENSE: 'CommonStatisticId' = 16588 - ENVIRONMENT_UNCOMFORTABLE: 'CommonStatisticId' = 99394 - EXCAVATION_PILE_PROGRESS: 'CommonStatisticId' = 177105 - FAME_PERK_BRAND_ALL_NIGHTER_CHARITY_STREAM: 'CommonStatisticId' = 196060 - FAME_PERK_BRAND_ALL_NIGHTER_CHARITY_STREAM_CANCELLATION: 'CommonStatisticId' = 196090 - FAME_PERK_BRAND_ALL_NIGHTER_CHARITY_STREAM_FAME_PAYOUT: 'CommonStatisticId' = 198519 - FAME_PERK_CAREER_HOPPER_MULTIPLIER: 'CommonStatisticId' = 195757 - FAME_PERK_SQUAD_MEMBER_AUTONOMY: 'CommonStatisticId' = 201645 - FAME_PERKS_INFLUENCER_GIFT_DELIVERY: 'CommonStatisticId' = 194664 - FAME_QUIRK_A_SERIOUS_ACTOR_ANGER: 'CommonStatisticId' = 195906 - FAME_QUIRK_BRUSHES_WITH_FAME_TOUCH_METER: 'CommonStatisticId' = 194072 - FAME_QUIRK_EMOTION_BOMB_ANGER: 'CommonStatisticId' = 200818 - FAME_QUIRK_EMOTION_BOMB_SADNESS: 'CommonStatisticId' = 200819 - FAME_QUIRK_NO_TOUCHING_TOUCH_METER: 'CommonStatisticId' = 194071 - FAME_QUIRK_PHONE_FANATIC: 'CommonStatisticId' = 191706 - FAME_QUIRK_VAIN_STREET_VAIN_METER: 'CommonStatisticId' = 195986 - FAME_QUIRKS_FAN_MAIL_GIFT_DELIVERY: 'CommonStatisticId' = 195790 - FAME_QUIRKS_JUICE_ENTHUSIAST_CHILD: 'CommonStatisticId' = 196278 - FAME_QUIRKS_JUICE_ENTHUSIAST_TYAE: 'CommonStatisticId' = 196262 - FAME_WORLD_TAKE_PHOTO_NO_ATTRACTOR: 'CommonStatisticId' = 201140 - FESTIVAL_BLOSSOM_DRINK_TEA: 'CommonStatisticId' = 150594 - FESTIVAL_BLOSSOM_VIEW_PLANTS: 'CommonStatisticId' = 143730 - FESTIVAL_DARK_SIDER_DRINK_TEA: 'CommonStatisticId' = 135530 - FESTIVAL_FIREWORKS_FIREWORK_DISPLAY_TIMER: 'CommonStatisticId' = 135874 - FESTIVAL_FIREWORKS_FIREWORK_INDOOR_EXPLOSION: 'CommonStatisticId' = 142083 - FESTIVAL_FIREWORKS_FUSE_TIMER: 'CommonStatisticId' = 135047 - FESTIVAL_FIREWORKS_FUSE_TIMER_DUD: 'CommonStatisticId' = 135831 - FESTIVAL_FIREWORKS_FUSE_TIMER_INDOORS: 'CommonStatisticId' = 142073 - FESTIVAL_FIREWORKS_FUSE_TIMER_NEIGHBOR: 'CommonStatisticId' = 150515 - FESTIVAL_FIREWORKS_FUSE_TIMER_QUICK: 'CommonStatisticId' = 135830 - FESTIVAL_FIREWORKS_REPEATER_RESET_TIMER: 'CommonStatisticId' = 140909 - FESTIVAL_FIREWORKS_SPARKLER_TIMER: 'CommonStatisticId' = 143690 - FESTIVAL_FIREWORKS_SPENT_TIMER: 'CommonStatisticId' = 142168 - FESTIVAL_FIREWORKS_WATCHING: 'CommonStatisticId' = 150511 - FESTIVAL_FLEA_MARKET_HAGGLER: 'CommonStatisticId' = 142222 - FESTIVAL_GENERAL_EAT_FOOD: 'CommonStatisticId' = 134829 - FESTIVAL_LIGHT_SIDER_DRINK_TEA: 'CommonStatisticId' = 135529 - FESTIVAL_NPC_BUFF_TIMERS: 'CommonStatisticId' = 149281 - FESTIVAL_NPC_BUFF_TIMERS_AT_FESTIVAL: 'CommonStatisticId' = 149282 - FESTIVAL_PLAYER_BUFF_TIMERS_AT_FESTIVAL_BLOSSOM: 'CommonStatisticId' = 144007 - FESTIVAL_PLAYER_BUFF_TIMERS_AT_FESTIVAL_FLEA_MARKET: 'CommonStatisticId' = 144008 - FESTIVAL_PLAYER_BUFF_TIMERS_AT_FESTIVAL_FOOD: 'CommonStatisticId' = 144009 - FESTIVAL_PLAYER_BUFF_TIMERS_AT_FESTIVAL_LAMP: 'CommonStatisticId' = 144010 - FESTIVAL_PLAYER_BUFF_TIMERS_AT_FESTIVAL_LOGIC: 'CommonStatisticId' = 143990 - FESTIVAL_PLAYER_BUFF_TIMERS_BLOSSOM: 'CommonStatisticId' = 144004 - FESTIVAL_PLAYER_BUFF_TIMERS_FLEA_MARKET: 'CommonStatisticId' = 144005 - FESTIVAL_PLAYER_BUFF_TIMERS_FOOD: 'CommonStatisticId' = 144003 - FESTIVAL_PLAYER_BUFF_TIMERS_LAMP: 'CommonStatisticId' = 144006 - FESTIVAL_PLAYER_BUFF_TIMERS_LOGIC: 'CommonStatisticId' = 143789 - FESTIVAL_WATCH_INTERACTIONS: 'CommonStatisticId' = 136205 - FESTIVALS_HACK_THE_PLANET_SCORE: 'CommonStatisticId' = 141090 - FESTIVALS_UGT_GAME_COUNT_ADVENTURE: 'CommonStatisticId' = 141685 - FESTIVALS_UGT_GAME_COUNT_FAMILY: 'CommonStatisticId' = 141687 - FESTIVALS_UGT_GAME_COUNT_PUZZLE: 'CommonStatisticId' = 141686 - FESTIVALS_UGT_GAME_COUNT_SPORTS: 'CommonStatisticId' = 141688 - FESTIVALS_UGT_GAME_COUNT_TOTAL: 'CommonStatisticId' = 141735 - FESTIVALS_UGT_PLAYER_SCORE_ADVENTURE: 'CommonStatisticId' = 141690 - FESTIVALS_UGT_PLAYER_SCORE_FAMILY: 'CommonStatisticId' = 141693 - FESTIVALS_UGT_PLAYER_SCORE_PUZZLE: 'CommonStatisticId' = 141692 - FESTIVALS_UGT_PLAYER_SCORE_SPORTS: 'CommonStatisticId' = 141691 - FESTIVALS_UGT_SCORE: 'CommonStatisticId' = 141046 - FISH_FRESHNESS: 'CommonStatisticId' = 77040 - FISHING_FAIL_AT_FISHING: 'CommonStatisticId' = 76386 - FISHING_LOCATION_RECENTLY_EXAMINED: 'CommonStatisticId' = 76365 - FISHING_NEED_TO_CAST: 'CommonStatisticId' = 74423 - FISHING_WEIGHT: 'CommonStatisticId' = 76023 - FITNESS_FAT: 'CommonStatisticId' = 16589 - FITNESS_FIT: 'CommonStatisticId' = 16590 - FLOWER_ARRANGEMENT_BEGONIA_CURSED_EFFECTS: 'CommonStatisticId' = 188243 - FLOWER_ARRANGEMENT_SCENT_CROCUS: 'CommonStatisticId' = 186913 - FLOWER_ARRANGEMENT_SCENT_LILY_LIFE_ESSENCE: 'CommonStatisticId' = 188710 - FLOWER_ARRANGEMENT_TULIP_FAITHFUL_EFFECTS: 'CommonStatisticId' = 188190 - FLOWER_ARRANGEMENT_WILTING: 'CommonStatisticId' = 186915 - FLOWER_BUNNY_PLACED_FLOWER_NEARBY: 'CommonStatisticId' = 187682 - FLOWER_DROP_COUNTER: 'CommonStatisticId' = 187473 - FOOD_POISONING: 'CommonStatisticId' = 131883 - FRESHNESS: 'CommonStatisticId' = 16591 - FROGS_FROG_BREEDING_COOLDOWN_FOR_SIM: 'CommonStatisticId' = 98396 - FRUIT_PUNCH_FOUNTAIN_SERVINGS: 'CommonStatisticId' = 116834 - GAME_FOREVER: 'CommonStatisticId' = 38997 - GARDENING_AGGREGATE: 'CommonStatisticId' = 8776 - GARDENING_DECAY: 'CommonStatisticId' = 16592 - GARDENING_EVOLUTION: 'CommonStatisticId' = 39327 - GARDENING_EXPIRATION: 'CommonStatisticId' = 16593 - GARDENING_FERTILIZER: 'CommonStatisticId' = 16594 - GARDENING_FERTILIZER_B: 'CommonStatisticId' = 16595 - GARDENING_FERTILIZER_C: 'CommonStatisticId' = 16596 - GARDENING_FRUIT_DECAY: 'CommonStatisticId' = 16597 - GARDENING_FRUIT_SIZE: 'CommonStatisticId' = 16598 - GARDENING_GERMINATION: 'CommonStatisticId' = 16599 - GARDENING_GROWTH: 'CommonStatisticId' = 16600 - GARDENING_INFESTATION: 'CommonStatisticId' = 16601 - GARDENING_MOISTURE: 'CommonStatisticId' = 16602 - GARDENING_TEMPLE: 'CommonStatisticId' = 179472 - GARDENING_WEEDS: 'CommonStatisticId' = 16603 - GARLIC_BRAID_GARLIC_LEVEL: 'CommonStatisticId' = 151174 - GENDER_PREFERENCE_FEMALE: 'CommonStatisticId' = 16663 - GENDER_PREFERENCE_MALE: 'CommonStatisticId' = 16664 - GIVE_ROMANTIC_GIFT_AUTONOMY: 'CommonStatisticId' = 186035 - GLOAT: 'CommonStatisticId' = 34085 - GO_FOR_WALK_DOG_BEHAVIOR: 'CommonStatisticId' = 166364 - GO_FOR_WALK_SIM_BEHAVIOR: 'CommonStatisticId' = 166218 - GRILLED_CHEESE_ASPIRATION_GRILLED_CHEESE_ATE: 'CommonStatisticId' = 132369 - GRIM_REAPER_DEATH_COUNT: 'CommonStatisticId' = 16665 - GROUP_STORY_WAITING: 'CommonStatisticId' = 110879 - HAIR_MAKE_UP_CHAIR_WARDROBE_PEDESTAL_LOOP_COUNT: 'CommonStatisticId' = 189981 - HAVE_BABY_AT_HOSPITAL_LEAVE: 'CommonStatisticId' = 116653 - HOLDING_CELL_CAPACITY: 'CommonStatisticId' = 105310 - HOLIDAY_TREE_FESTIVE: 'CommonStatisticId' = 180629 - HOLIDAY_TREE_GARLAND_PROGRESS: 'CommonStatisticId' = 180422 - HOLIDAY_TREE_ORNAMENTS_PROGRESS: 'CommonStatisticId' = 180421 - HOLIDAY_TREE_SKIRT_PROGRESS: 'CommonStatisticId' = 181647 - HOLIDAY_TREE_TOPPER_PROGRESS: 'CommonStatisticId' = 180423 - HORSESHOE_BAD_THROWS: 'CommonStatisticId' = 111640 - INCENSE_TIME_LEFT: 'CommonStatisticId' = 118476 - INFECTED_CHEMICAL_ANALYZER_PROGRESS: 'CommonStatisticId' = 204831 - INFECTION_CURE_EXPERIMENTAL_TRACKER: 'CommonStatisticId' = 204175 - INFECTION_CURE_VACCINE_DURATION: 'CommonStatisticId' = 207420 - INFECTION_SCANNER_CHARGE: 'CommonStatisticId' = 203442 - INSECT_SPAWNER_VISIBILITY: 'CommonStatisticId' = 110554 - INTERACTIVE_BUSH_DIRTINESS: 'CommonStatisticId' = 124865 - INTERROGATION_TABLE_PROGRESS: 'CommonStatisticId' = 104629 - INVESTIGATION_SYSTEM_STRANGER_VILLE_CRATER_INVESTIGATION_COUNT: 'CommonStatisticId' = 205430 - JUNGLE_WORLD_LOOK_AROUND: 'CommonStatisticId' = 181759 - JUNK_PILE_SEARCHES_AVAILABLE: 'CommonStatisticId' = 204673 - KARAOKE_MACHINE_CONTEST_SCORE: 'CommonStatisticId' = 153653 - KARAOKE_MACHINE_SCORE: 'CommonStatisticId' = 137536 - LAUNDRY_AMOUNT: 'CommonStatisticId' = 175582 - LAUNDRY_DRYER_LINT_TRAY_VOLUME: 'CommonStatisticId' = 176404 - LAUNDRY_DRYER_OBJECT_DRYING_DURATION: 'CommonStatisticId' = 176051 - LAUNDRY_HAMPER_CAPACITY: 'CommonStatisticId' = 175574 - LAUNDRY_OBJECT_CLEANLINESS: 'CommonStatisticId' = 175411 - LAUNDRY_OBJECT_DRYNESS: 'CommonStatisticId' = 175430 - LAUNDRY_OBJECT_SCENTED: 'CommonStatisticId' = 175436 - LAUNDRY_OBJECT_WASHING_MACHINE_BROKENESS_PLUMBING: 'CommonStatisticId' = 177039 - LAUNDRY_WASHING_MACHINE_CLEANING_ADDITIVE: 'CommonStatisticId' = 176375 - LAUNDRY_WASHING_MACHINE_OBJECT_CLEANING_DURATION: 'CommonStatisticId' = 175882 - LICENSE_LYRICS: 'CommonStatisticId' = 153883 - LICENSE_LYRICS_GUITAR: 'CommonStatisticId' = 139953 - LICENSE_LYRICS_MICROPHONE: 'CommonStatisticId' = 139859 - LICENSE_LYRICS_PIANO: 'CommonStatisticId' = 139954 - LICENSE_SONG_DJ_MIX: 'CommonStatisticId' = 126100 - LICENSE_SONG_GUITAR: 'CommonStatisticId' = 16605 - LICENSE_SONG_PIANO: 'CommonStatisticId' = 16606 - LICENSE_SONG_PIPE_ORGAN: 'CommonStatisticId' = 151358 - LICENSE_SONG_VIOLIN: 'CommonStatisticId' = 16607 - LIFE_SKILL_CONFLICT_RESOLUTION: 'CommonStatisticId' = 161616 - LIFE_SKILL_EMOTIONAL_CONTROL: 'CommonStatisticId' = 161618 - LIFE_SKILL_EMPATHY: 'CommonStatisticId' = 161617 - LIFE_SKILL_MANNERS: 'CommonStatisticId' = 161614 - LIFE_SKILL_RESPONSIBILITY: 'CommonStatisticId' = 161615 - LIFE_SKILLS_AUTONOMY_CONFLICT_RESOLUTION_NEGATIVE: 'CommonStatisticId' = 163757 - LIFE_SKILLS_AUTONOMY_CONFLICT_RESOLUTION_POSITIVE: 'CommonStatisticId' = 163756 - LIFE_SKILLS_AUTONOMY_EMOTIONAL_CONTROL_NEGATIVE: 'CommonStatisticId' = 163759 - LIFE_SKILLS_AUTONOMY_EMOTIONAL_CONTROL_POSITIVE: 'CommonStatisticId' = 163758 - LIFE_SKILLS_AUTONOMY_EMPATHY_NEGATIVE: 'CommonStatisticId' = 163761 - LIFE_SKILLS_AUTONOMY_EMPATHY_POSITIVE: 'CommonStatisticId' = 163760 - LIFE_SKILLS_AUTONOMY_MANNERS_NEGATIVE: 'CommonStatisticId' = 163771 - LIFE_SKILLS_AUTONOMY_MANNERS_POSITIVE: 'CommonStatisticId' = 163770 - LIFE_SKILLS_AUTONOMY_RESPONSIBILITY_NEGATIVE: 'CommonStatisticId' = 163755 - LIFE_SKILLS_AUTONOMY_RESPONSIBILITY_POSITIVE: 'CommonStatisticId' = 163754 - LOCAL_CULTURE_SKILL_FOOD_TOLERANCE: 'CommonStatisticId' = 176981 - LOT_DECORATED_STATE_VALUE: 'CommonStatisticId' = 183842 - LTR_FEUD_MAIN: 'CommonStatisticId' = 193901 - LTR_FRIENDSHIP_MAIN: 'CommonStatisticId' = 16650 - LTR_MISCHIEF_MAIN: 'CommonStatisticId' = 26920 - LTR_ROMANCE_MAIN: 'CommonStatisticId' = 16651 - LTR_SIM_TO_PET_FRIENDSHIP_MAIN: 'CommonStatisticId' = 159228 - MAKE_A_MESS_FLOUR_VARIANT_D: 'CommonStatisticId' = 165012 - MAKE_A_MESS_FLOUR_VARIANT_E: 'CommonStatisticId' = 165138 - MAKE_A_MESS_FLOUR_VARIANT_F: 'CommonStatisticId' = 165139 - MAKE_A_MESS_VARIANT_A: 'CommonStatisticId' = 162810 - MAKE_A_MESS_VARIANT_B: 'CommonStatisticId' = 162995 - MAKE_A_MESS_VARIANT_C: 'CommonStatisticId' = 162997 - MARKET_STALL_FOOD_STALL_ORDER: 'CommonStatisticId' = 178814 - MARKET_STALLS_BROWSE: 'CommonStatisticId' = 170543 - MASSAGE_TABLE_FINISHED: 'CommonStatisticId' = 121999 - MASSAGE_TABLE_STONE_MASSAGE: 'CommonStatisticId' = 120462 - MICROSCOPE_COLLECT: 'CommonStatisticId' = 31894 - MOTHER_PLANT_BATTLE_MOTHER_HEALTH: 'CommonStatisticId' = 204445 - MOTHER_PLANT_BATTLE_PLAYER_HEALTH: 'CommonStatisticId' = 203584 - MOTHER_PLANT_ENRAGE: 'CommonStatisticId' = 204704 - MOTIVE_BABY_BLADDER: 'CommonStatisticId' = 16609 - MOTIVE_BABY_DISTRACTION: 'CommonStatisticId' = 8947 - MOTIVE_BABY_ENERGY: 'CommonStatisticId' = 16610 - MOTIVE_BABY_HUNGER: 'CommonStatisticId' = 16611 - MOTIVE_BABY_SOCIAL: 'CommonStatisticId' = 16612 - MOTIVE_BLADDER: 'CommonStatisticId' = 16652 - MOTIVE_CAMPING_FOREST_GOOD_AT_PEACE: 'CommonStatisticId' = 108425 - MOTIVE_CAMPING_FOREST_HOME_SICK: 'CommonStatisticId' = 104114 - MOTIVE_CAMPING_FOREST_NEAT_TOO_MUCH_DIRT: 'CommonStatisticId' = 107835 - MOTIVE_CAMPING_FOREST_REFRESHED: 'CommonStatisticId' = 104832 - MOTIVE_CAMPING_FOREST_SLOB_NATURAL_DIRT: 'CommonStatisticId' = 108426 - MOTIVE_CAMPING_FOREST_SNOB_NOT_ENOUGH_CULTURE: 'CommonStatisticId' = 107829 - MOTIVE_COMFORT: 'CommonStatisticId' = 16653 - MOTIVE_ENERGY: 'CommonStatisticId' = 16654 - MOTIVE_FUN: 'CommonStatisticId' = 16655 - MOTIVE_HANG_OUT: 'CommonStatisticId' = 16615 - MOTIVE_HUNGER: 'CommonStatisticId' = 16656 - MOTIVE_HYGIENE: 'CommonStatisticId' = 16657 - MOTIVE_HYGIENE_HANDS: 'CommonStatisticId' = 16616 - MOTIVE_HYGIENE_ORAL: 'CommonStatisticId' = 16617 - MOTIVE_MAKE_ONE_DESSERT: 'CommonStatisticId' = 34124 - MOTIVE_MAKE_ONE_GROUP_MEAL: 'CommonStatisticId' = 34123 - MOTIVE_MOURN_FRIEND: 'CommonStatisticId' = 99668 - MOTIVE_MOURN_LOVED_ONE: 'CommonStatisticId' = 99667 - MOTIVE_MOURN_NEMESIS: 'CommonStatisticId' = 99669 - MOTIVE_NAUSEA: 'CommonStatisticId' = 16618 - MOTIVE_ANIMAL_FOX_BLADDER: 'CommonStatisticId' = 270467 - MOTIVE_ANIMAL_FOX_HYGIENE: 'CommonStatisticId' = 270701 - MOTIVE_PET_CAT_AFFECTION: 'CommonStatisticId' = 151038 - MOTIVE_PET_CAT_BLADDER: 'CommonStatisticId' = 151036 - MOTIVE_PET_CAT_BOWEL: 'CommonStatisticId' = 157949 - MOTIVE_PET_CAT_ENERGY: 'CommonStatisticId' = 151037 - MOTIVE_PET_CAT_HUNGER: 'CommonStatisticId' = 151035 - MOTIVE_PET_CAT_HYGIENE: 'CommonStatisticId' = 157055 - MOTIVE_PET_CAT_PLAY: 'CommonStatisticId' = 157718 - MOTIVE_PET_DOG_AFFECTION: 'CommonStatisticId' = 151034 - MOTIVE_PET_DOG_BLADDER: 'CommonStatisticId' = 151032 - MOTIVE_PET_DOG_BOWEL: 'CommonStatisticId' = 158698 - MOTIVE_PET_DOG_ENERGY: 'CommonStatisticId' = 151033 - MOTIVE_PET_DOG_HUNGER: 'CommonStatisticId' = 151031 - MOTIVE_PET_DOG_HYGIENE: 'CommonStatisticId' = 157056 - MOTIVE_PET_DOG_PLAY: 'CommonStatisticId' = 158699 - MOTIVE_PLANT_SIM_WATER: 'CommonStatisticId' = 162675 - MOTIVE_ROLE_ALIEN_VISIT_ALIEN: 'CommonStatisticId' = 114183 - MOTIVE_ROLE_BAR_MINGLER: 'CommonStatisticId' = 16620 - MOTIVE_ROLE_BARTENDER: 'CommonStatisticId' = 16623 - MOTIVE_ROLE_BARTENDER_TEND: 'CommonStatisticId' = 16622 - MOTIVE_ROLE_CATERER: 'CommonStatisticId' = 16624 - MOTIVE_ROLE_DINNER_PARTY_HOST: 'CommonStatisticId' = 16625 - MOTIVE_ROLE_DRINK: 'CommonStatisticId' = 101020 - MOTIVE_ROLE_EAT: 'CommonStatisticId' = 122235 - MOTIVE_ROLE_EAT_ONE_SLICE_OF_CAKE: 'CommonStatisticId' = 8901 - MOTIVE_ROLE_GRIM_REAPER: 'CommonStatisticId' = 16628 - MOTIVE_ROLE_GRIM_REAPER_REAP_SOUL: 'CommonStatisticId' = 16627 - MOTIVE_ROLE_SMUGGLER: 'CommonStatisticId' = 28804 - MOTIVE_ROLE_WEDDING_GUEST: 'CommonStatisticId' = 8898 - MOTIVE_ROLE_WORKOUT: 'CommonStatisticId' = 97594 - MOTIVE_SOCIAL: 'CommonStatisticId' = 16658 - MOTIVE_THIRST: 'CommonStatisticId' = 10020 - MOTIVE_TODDLER_ATTENTION: 'CommonStatisticId' = 142037 - MOTIVE_VISIBLE_VAMPIRE_POWER: 'CommonStatisticId' = 150238 - MOTIVE_VISIBLE_VAMPIRE_THIRST: 'CommonStatisticId' = 149541 - MURAL_ACTIVIST_GLOBE: 'CommonStatisticId' = 148595 - MURAL_ACTIVIST_TREES: 'CommonStatisticId' = 148594 - MURAL_CANYON: 'CommonStatisticId' = 148589 - MURAL_CULTURAL_ELEPHANT: 'CommonStatisticId' = 148911 - MURAL_CULTURAL_FISH: 'CommonStatisticId' = 148909 - MURAL_CULTURAL_GIRL: 'CommonStatisticId' = 148912 - MURAL_CULTURAL_JAPANESE: 'CommonStatisticId' = 148910 - MURAL_DECAY: 'CommonStatisticId' = 147256 - MURAL_EGYPT: 'CommonStatisticId' = 148482 - MURAL_FIG_GIRL: 'CommonStatisticId' = 150994 - MURAL_FIG_HAT_LADY: 'CommonStatisticId' = 150995 - MURAL_FIG_HEART: 'CommonStatisticId' = 150993 - MURAL_FIG_PENGUIN: 'CommonStatisticId' = 150996 - MURAL_FISH: 'CommonStatisticId' = 146763 - MURAL_FLOWERS: 'CommonStatisticId' = 146762 - MURAL_GANG: 'CommonStatisticId' = 148484 - MURAL_GARDEN: 'CommonStatisticId' = 148590 - MURAL_GEISHA: 'CommonStatisticId' = 148483 - MURAL_GRAF_PIECE: 'CommonStatisticId' = 148913 - MURAL_GRAF_PURPLE: 'CommonStatisticId' = 148914 - MURAL_ILLUSION_BIRDS: 'CommonStatisticId' = 151702 - MURAL_ILLUSION_FISH: 'CommonStatisticId' = 151672 - MURAL_ILLUSION_FOUNTAIN: 'CommonStatisticId' = 151671 - MURAL_ILLUSION_RAINBOW: 'CommonStatisticId' = 151673 - MURAL_KING: 'CommonStatisticId' = 148481 - MURAL_KOI: 'CommonStatisticId' = 148588 - MURAL_LEAVES: 'CommonStatisticId' = 147390 - MURAL_MAGENTA_CITY: 'CommonStatisticId' = 147837 - MURAL_MOSAIC_CITY: 'CommonStatisticId' = 147838 - MURAL_ORANGE_CITY: 'CommonStatisticId' = 148485 - MURAL_TREE: 'CommonStatisticId' = 147494 - MURAL_UNIVERSE: 'CommonStatisticId' = 148591 - MURAL_ZILLA_CITY: 'CommonStatisticId' = 148486 - MUSIC_PRODUCTION_STATION_CD_ON_RADIO: 'CommonStatisticId' = 203042 - MUSIC_PRODUCTION_STATION_MUSIC_LABEL_DINKY_BEATS: 'CommonStatisticId' = 194714 - MUSIC_PRODUCTION_STATION_MUSIC_LABEL_MAXIS_MUSIC_MACHINE: 'CommonStatisticId' = 194715 - MUSIC_PRODUCTION_STATION_MUSIC_LABEL_NEW_TASTE_MAKERS: 'CommonStatisticId' = 194716 - MUSIC_PRODUCTION_STATION_RELEASE_COOLDOWN: 'CommonStatisticId' = 201546 - MYSTICAL_RELIC_COOLDOWN: 'CommonStatisticId' = 179668 - NATURAL_DANGERS: 'CommonStatisticId' = 176613 - NATURAL_DANGERS_TEMPLE: 'CommonStatisticId' = 181822 - NEW_OBJECT: 'CommonStatisticId' = 167504 - NPC_GRIM_REAPER_BE_REAPED: 'CommonStatisticId' = 16666 - NPC_GRIM_REAPER_CLEMENCY: 'CommonStatisticId' = 16667 - NPC_GRIM_REAPER_COUNT: 'CommonStatisticId' = 16668 - OBJECT_APARTMENT_PROBLEM_FLOWING_PUDDLE: 'CommonStatisticId' = 155520 - OBJECT_APARTMENT_PROBLEM_POWER_OUTAGE: 'CommonStatisticId' = 133845 - OBJECT_APARTMENT_PROBLEM_SEVERITY: 'CommonStatisticId' = 133061 - OBJECT_AUTO_PET_FEEDER_REFILL_VFX: 'CommonStatisticId' = 160119 - OBJECT_AUTO_PET_FEEDER_SCHEDULE_TIMER: 'CommonStatisticId' = 159034 - OBJECT_AUTOGRAPHED_OBJECT_APPRAISAL_COOLDOWN_TIMER: 'CommonStatisticId' = 200664 - OBJECT_BACKYARD_DRINK_TRAY_SERVINGS: 'CommonStatisticId' = 140055 - OBJECT_BASKETBALL_COMPETITION_TIMER: 'CommonStatisticId' = 153689 - OBJECT_BASKETBALL_GLASS_STATUS: 'CommonStatisticId' = 153627 - OBJECT_BASKETBALL_IN_THE_ZONE_SHOT_TRACKER: 'CommonStatisticId' = 147787 - OBJECT_BASKETBALL_ON_FIRE_SHOT_TRACKER: 'CommonStatisticId' = 147788 - OBJECT_BATTLE_STATION_PROGRESS: 'CommonStatisticId' = 134837 - OBJECT_BED_MONSTER_UNDER_PREVENT_SPAWN_COUNTER: 'CommonStatisticId' = 135989 - OBJECT_BEE_BOX_RELATIONSHIP: 'CommonStatisticId' = 186135 - OBJECT_BLOCK_CONSTRUCTION_TABLE_PROGRESS: 'CommonStatisticId' = 165304 - OBJECT_BOOK_PROGRESS: 'CommonStatisticId' = 36408 - OBJECT_BOOKS_BROWSED: 'CommonStatisticId' = 76992 - OBJECT_BOWLING_LANE_GAME_IN_PROGRESS: 'CommonStatisticId' = 161517 - OBJECT_BOWLING_LANE_RELATIONSHIP: 'CommonStatisticId' = 160133 - OBJECT_BOWLING_LANE_RERACK_RESET: 'CommonStatisticId' = 158519 - OBJECT_BOWLING_LANE_SORE_ARMS_TRACKER: 'CommonStatisticId' = 162030 - OBJECT_BOWLING_LANE_STRIKE_COUNTER: 'CommonStatisticId' = 162431 - OBJECT_BOWLING_LANE_TURKEY_STRIKES_COUNTER: 'CommonStatisticId' = 162393 - OBJECT_BROKENNESS: 'CommonStatisticId' = 16633 - OBJECT_BUBBLE_BLOWER_CARTRIDGE_CHARGES: 'CommonStatisticId' = 133034 - OBJECT_BURNING: 'CommonStatisticId' = 39470 - OBJECT_CHESS_TABLE_PROGRESS: 'CommonStatisticId' = 16669 - OBJECT_CLAY_BLOB_PROGRESS: 'CommonStatisticId' = 16670 - OBJECT_CLEAR_EASEL: 'CommonStatisticId' = 154802 - OBJECT_CLOSET_CHANGE_COUNTER: 'CommonStatisticId' = 126939 - OBJECT_CLOSET_TRYING_OUTFITS_ON: 'CommonStatisticId' = 143372 - OBJECT_COMPUTER_CHARITY_COOLDOWN: 'CommonStatisticId' = 31127 - OBJECT_COMPUTER_GAME_MOD_BLICBLOCK: 'CommonStatisticId' = 32835 - OBJECT_COMPUTER_GAME_MOD_HILLOCK: 'CommonStatisticId' = 32839 - OBJECT_COMPUTER_GAME_MOD_INCREDIBLE_SPORTS: 'CommonStatisticId' = 32840 - OBJECT_COMPUTER_GAME_MOD_MARIA_SISTERS: 'CommonStatisticId' = 32841 - OBJECT_COMPUTER_GAME_MOD_REFUGE: 'CommonStatisticId' = 32842 - OBJECT_COMPUTER_GAME_MOD_ROAD_RIVAL: 'CommonStatisticId' = 32843 - OBJECT_COMPUTER_GAME_MOD_SIMS_FOREVER_RENAMED: 'CommonStatisticId' = 32838 - OBJECT_COMPUTER_GAME_TOURNAMENT_PAYOUT_MULTIPLIER: 'CommonStatisticId' = 31893 - OBJECT_COMPUTER_REPAIR_TIMEOUT: 'CommonStatisticId' = 203501 - OBJECT_COMPUTER_SOCIAL_NETWORK_FOLLOWERS: 'CommonStatisticId' = 31167 - OBJECT_COMPUTER_SOCIAL_NETWORK_IMAGE_COOLDOWN: 'CommonStatisticId' = 31198 - OBJECT_COMPUTER_SOCIAL_NETWORK_ON: 'CommonStatisticId' = 31166 - OBJECT_COMPUTER_SOCIAL_NETWORK_VIDEO_COOLDOWN: 'CommonStatisticId' = 31203 - OBJECT_COMPUTER_VIDEO_GAMING_RESEARCH: 'CommonStatisticId' = 32053 - OBJECT_COMPUTER_VIDEO_GAMING_STREAMS: 'CommonStatisticId' = 32054 - OBJECT_COMPUTER_VIDEO_GAMING_FAN_COUNT: 'CommonStatisticId' = 33411 - OBJECT_CONSUMABLE: 'CommonStatisticId' = 16634 - OBJECT_CONSUMABLE_QUALITY: 'CommonStatisticId' = 16671 - OBJECT_CONSUMABLE_SABOTAGED: 'CommonStatisticId' = 187177 - OBJECT_CONSUMABLE_SERVINGS: 'CommonStatisticId' = 16672 - OBJECT_COUNT_TOYS: 'CommonStatisticId' = 176598 - OBJECT_COW_PLANT_HUNGER: 'CommonStatisticId' = 16635 - OBJECT_CRAFT_SALES_TABLE_AUTONOMY_BROWSE_TABLE: 'CommonStatisticId' = 145285 - OBJECT_CRIME_SCENE_PHOTO_TAKEN: 'CommonStatisticId' = 108811 - OBJECT_CRIME_SCENE_PRINTS_TAKEN: 'CommonStatisticId' = 108812 - OBJECT_CRIME_SCENE_SAMPLE_TAKEN: 'CommonStatisticId' = 108813 - OBJECT_CRIME_SCENE_WITNESS_REPORT_TAKEN: 'CommonStatisticId' = 108814 - OBJECT_CRYSTAL_HELMET_CRYSTAL_BATTERY_LIFE: 'CommonStatisticId' = 192883 - OBJECT_CUPCAKE_FACTORY_BATTER: 'CommonStatisticId' = 16636 - OBJECT_DANCE_FLOOR_SHOW_OFF_MOVES: 'CommonStatisticId' = 125306 - OBJECT_DARTBOARD_GAME_IN_PROGRESS: 'CommonStatisticId' = 130238 - OBJECT_DARTBOARD_ROUND_SCORE: 'CommonStatisticId' = 127975 - OBJECT_DISHES_DISH_COUNT: 'CommonStatisticId' = 16674 - OBJECT_DISHWASHER_TIME_LEFT: 'CommonStatisticId' = 122157 - OBJECT_DJ_BOOTH_ACTOR_JUST_TIPPED: 'CommonStatisticId' = 130631 - OBJECT_DJ_BOOTH_AUDIENCE_PARTICIPATION: 'CommonStatisticId' = 125698 - OBJECT_DJ_BOOTH_AUDIENCE_POSITIVE_BUFF: 'CommonStatisticId' = 128368 - OBJECT_DJ_BOOTH_DJ_PERFORMANCE_DURATION: 'CommonStatisticId' = 123799 - OBJECT_DJ_BOOTH_PERFORMANCE_STATE_DECAY: 'CommonStatisticId' = 124623 - OBJECT_DJ_BOOTH_SHOW_QUALITY: 'CommonStatisticId' = 123168 - OBJECT_DJ_BOOTH_TIPS: 'CommonStatisticId' = 127877 - OBJECT_DOLLHOUSE_PLAY_COUNT: 'CommonStatisticId' = 37467 - OBJECT_DONT_WAKE_LLAMA_BOT_SECTION: 'CommonStatisticId' = 127158 - OBJECT_DONT_WAKE_LLAMA_GAME_COUNT: 'CommonStatisticId' = 130258 - OBJECT_DONT_WAKE_LLAMA_TOP_SECTION: 'CommonStatisticId' = 127160 - OBJECT_EGG_FOUND: 'CommonStatisticId' = 190498 - OBJECT_FERTILIZER_COOLDOWN: 'CommonStatisticId' = 97593 - OBJECT_FIRE_BEEN_EXTINGUISHED: 'CommonStatisticId' = 75770 - OBJECT_FIRE_RAIN: 'CommonStatisticId' = 190384 - OBJECT_FIRE_STRENGTH: 'CommonStatisticId' = 39323 - OBJECT_FIRE_LEAF_ELIXIR_OF_BURNING: 'CommonStatisticId' = 104298 - OBJECT_FIRE_LEAF_NEAR: 'CommonStatisticId' = 104033 - OBJECT_FIRE_LEAF_RASH: 'CommonStatisticId' = 104035 - OBJECT_FRONT_DESK_AWAY_EVENT_TIMER: 'CommonStatisticId' = 115560 - OBJECT_FRONT_DESK_HOUSE_CALL_TIMER: 'CommonStatisticId' = 115536 - OBJECT_FRONT_DESK_OUTBREAK_TIMER: 'CommonStatisticId' = 115537 - OBJECT_GNOME_RELATIONSHIP: 'CommonStatisticId' = 180290 - OBJECT_GUITAR_ROCKIN_RIFFS: 'CommonStatisticId' = 34551 - OBJECT_GUITAR_SINGING_QUALITY: 'CommonStatisticId' = 110731 - OBJECT_HOLIDAY_CANDLE_LIT: 'CommonStatisticId' = 110394 - OBJECT_HOSPITAL_EXAM_BED_DIRTINESS: 'CommonStatisticId' = 107405 - OBJECT_HOT_TUB_IN_USE: 'CommonStatisticId' = 119029 - OBJECT_INFECTED_PLANT_RECENTLY_NURTURED: 'CommonStatisticId' = 202472 - OBJECT_INVENTION_CONSTRUCTOR_ASSEMBLE_MIXER_TRACKER: 'CommonStatisticId' = 109959 - OBJECT_INVENTION_CONSTRUCTOR_INVENT_MIXER_TRACKER: 'CommonStatisticId' = 110100 - OBJECT_JIG_ALIEN_ORB_VFX: 'CommonStatisticId' = 116352 - OBJECT_KARAOKE_MACHINE_START_DUET: 'CommonStatisticId' = 149672 - OBJECT_LASER_LIGHT_SHOW_ROTATION: 'CommonStatisticId' = 35336 - OBJECT_LEAF_PILE_COUNT: 'CommonStatisticId' = 180201 - OBJECT_LEAF_PILE_DESTROY_TIMER: 'CommonStatisticId' = 207084 - OBJECT_LEAF_PILE_FIRE_INTENSITY: 'CommonStatisticId' = 182939 - OBJECT_LEAF_PILE_FRESHNESS: 'CommonStatisticId' = 183132 - OBJECT_LIGHT: 'CommonStatisticId' = 99424 - OBJECT_LITTER_BOX_RAKE: 'CommonStatisticId' = 161504 - OBJECT_LITTER_BOX_STORAGE: 'CommonStatisticId' = 170290 - OBJECT_LITTER_BOX_TURRET: 'CommonStatisticId' = 161505 - OBJECT_MAILBOX_INVENTORY_COUNT: 'CommonStatisticId' = 16675 - OBJECT_MAILBOX_WALL_AUTONOMOUS_DELIVERY: 'CommonStatisticId' = 143559 - OBJECT_MASSAGE_CHAIR_FOOT_MASSAGE: 'CommonStatisticId' = 119766 - OBJECT_MASSAGE_CHAIR_HAND_MASSAGE: 'CommonStatisticId' = 119765 - OBJECT_MICROWAVE_FLAVOR_UPGRADED: 'CommonStatisticId' = 97014 - OBJECT_MINOR_PET_CAGE_ACTIVITY: 'CommonStatisticId' = 180912 - OBJECT_MINOR_PET_CAGE_AGE: 'CommonStatisticId' = 183341 - OBJECT_MINOR_PET_CAGE_ATTENTION: 'CommonStatisticId' = 180913 - OBJECT_MINOR_PET_CAGE_CLEANLINESS: 'CommonStatisticId' = 183955 - OBJECT_MINOR_PET_CAGE_ENERGY: 'CommonStatisticId' = 181288 - OBJECT_MINOR_PET_CAGE_HUNGER: 'CommonStatisticId' = 180911 - OBJECT_MINOR_PET_CAGE_RODENT_DISEASE: 'CommonStatisticId' = 185283 - OBJECT_MIRROR_EPIC_STORY: 'CommonStatisticId' = 31306 - OBJECT_MONSTERS_LEVEL: 'CommonStatisticId' = 134167 - OBJECT_MOTHER_PLANT_RELATIONSHIP: 'CommonStatisticId' = 206016 - OBJECT_MOTHER_PLANT_DEFEAT: 'CommonStatisticId' = 205212 - OBJECT_MOTION_GAMING_RIG_ADVENTURE: 'CommonStatisticId' = 29386 - OBJECT_MOTION_GAMING_RIG_FAMILY: 'CommonStatisticId' = 29387 - OBJECT_MOTION_GAMING_RIG_PUZZLE: 'CommonStatisticId' = 39919 - OBJECT_MOTION_GAMING_RIG_SPORTS: 'CommonStatisticId' = 29388 - OBJECT_MOVIE_ENJOYMENT: 'CommonStatisticId' = 128901 - OBJECT_MOVIE_LENGTH: 'CommonStatisticId' = 129182 - OBJECT_MURAL_KICK_OFF_TRACKER: 'CommonStatisticId' = 154292 - OBJECT_MUSIC_PRODUCTION_STATION_TRACKS_RELEASED: 'CommonStatisticId' = 194853 - OBJECT_MUSIC_PRODUCTION_STATION_TRACKS_RELEASED_DINKY_BEATS: 'CommonStatisticId' = 197041 - OBJECT_MUSIC_PRODUCTION_STATION_TRACKS_RELEASED_MAXIS_MUSIC_MACHINE: 'CommonStatisticId' = 197042 - OBJECT_MUSIC_PRODUCTION_STATION_TRACKS_RELEASED_NEW_TASTE_MAKERS: 'CommonStatisticId' = 197043 - OBJECT_NUM_SIMS_WATCHING: 'CommonStatisticId' = 31618 - OBJECT_OVEN_COOKING_PROGRESS: 'CommonStatisticId' = 16637 - OBJECT_PARK_FOUNTAIN_SOAP: 'CommonStatisticId' = 131534 - OBJECT_PET_MINOR_CAGE_FOOD: 'CommonStatisticId' = 181295 - OBJECT_PET_MINOR_CAGE_RELATIONSHIP: 'CommonStatisticId' = 180924 - OBJECT_PET_POOP_DESTROY: 'CommonStatisticId' = 161056 - OBJECT_PHOTO_STUDIO_IN_PLACE_COUNT_2_SIMS: 'CommonStatisticId' = 111877 - OBJECT_PHOTO_STUDIO_IN_PLACE_COUNT_3_SIMS: 'CommonStatisticId' = 111830 - OBJECT_PIANO_COOL_KEY_CHORDS: 'CommonStatisticId' = 34518 - OBJECT_PIPE_ORGAN_PALLIATIVE_PIPES: 'CommonStatisticId' = 151296 - OBJECT_PODIUM_SPEECH_HAPPY_COUNT: 'CommonStatisticId' = 147282 - OBJECT_PODIUM_SPEECH_UNHAPPY_COUNT: 'CommonStatisticId' = 147283 - OBJECT_POPCORN_BURNING_CARAMEL: 'CommonStatisticId' = 130645 - OBJECT_POPCORN_BURNING_CHEDDAR: 'CommonStatisticId' = 130646 - OBJECT_POPCORN_BURNING_KETTLE: 'CommonStatisticId' = 130647 - OBJECT_POPCORN_BURNING_POPCORN: 'CommonStatisticId' = 130648 - OBJECT_POPCORN_POPPER_PROGRESS: 'CommonStatisticId' = 129056 - OBJECT_POPCORN_POPPER_SERVINGS: 'CommonStatisticId' = 128955 - OBJECT_POSTCARD_COOLDOWN_APPALOOSA_PLAINS: 'CommonStatisticId' = 29793 - OBJECT_POSTCARD_COOLDOWN_BARNACLE_BAY: 'CommonStatisticId' = 29794 - OBJECT_POSTCARD_COOLDOWN_BRIDGEPORT: 'CommonStatisticId' = 29795 - OBJECT_POSTCARD_COOLDOWN_CHAMPS_LES_SIMS: 'CommonStatisticId' = 29796 - OBJECT_POSTCARD_COOLDOWN_DRAGON_VALLEY: 'CommonStatisticId' = 29797 - OBJECT_POSTCARD_COOLDOWN_ISLA_PARADISO: 'CommonStatisticId' = 29798 - OBJECT_POSTCARD_COOLDOWN_LITTLE_HAVEN: 'CommonStatisticId' = 29799 - OBJECT_POSTCARD_COOLDOWN_LUCKY_PALMS: 'CommonStatisticId' = 29800 - OBJECT_POSTCARD_COOLDOWN_LUNAR_LAKES: 'CommonStatisticId' = 29801 - OBJECT_POSTCARD_COOLDOWN_MIDNIGHT_HOLLOW: 'CommonStatisticId' = 29802 - OBJECT_POSTCARD_COOLDOWN_MOONLIGHT_FALLS: 'CommonStatisticId' = 29803 - OBJECT_POSTCARD_COOLDOWN_RIVERVIEW: 'CommonStatisticId' = 29804 - OBJECT_POSTCARD_COOLDOWN_SUNSET_VALLEY: 'CommonStatisticId' = 29805 - OBJECT_POSTCARD_COOLDOWN_TWINBROOK: 'CommonStatisticId' = 29806 - OBJECT_POSTCARD_PENPAL_REPLY: 'CommonStatisticId' = 29756 - OBJECT_POSTCARDS_APPALOOSA_PLAINS: 'CommonStatisticId' = 29715 - OBJECT_POSTCARDS_BARNACLE_BAY: 'CommonStatisticId' = 29719 - OBJECT_POSTCARDS_BRIDGEPORT: 'CommonStatisticId' = 29712 - OBJECT_POSTCARDS_CHAMPS_LES_SIMS: 'CommonStatisticId' = 29720 - OBJECT_POSTCARDS_DRAGON_VALLEY: 'CommonStatisticId' = 29724 - OBJECT_POSTCARDS_ISLA_PARADISO: 'CommonStatisticId' = 29723 - OBJECT_POSTCARDS_LITTLE_HAVEN: 'CommonStatisticId' = 29714 - OBJECT_POSTCARDS_LUCKY_PALMS: 'CommonStatisticId' = 29717 - OBJECT_POSTCARDS_LUNAR_LAKES: 'CommonStatisticId' = 29721 - OBJECT_POSTCARDS_MIDNIGHT_HOLLOW: 'CommonStatisticId' = 29722 - OBJECT_POSTCARDS_MOONLIGHT_FALLS: 'CommonStatisticId' = 29716 - OBJECT_POSTCARDS_RIVERVIEW: 'CommonStatisticId' = 29713 - OBJECT_POSTCARDS_SUNSET_VALLEY: 'CommonStatisticId' = 29710 - OBJECT_POSTCARDS_TWINBROOK: 'CommonStatisticId' = 29711 - OBJECT_POSTCARDS_WAITING_FOR_PENPAL_REPLY: 'CommonStatisticId' = 29757 - OBJECT_POTTY_CHAIR_CONFIDENCE: 'CommonStatisticId' = 144921 - OBJECT_PUBLIC_BATHROOM_CAPACITY: 'CommonStatisticId' = 102628 - OBJECT_PUDDLE_EVAPORATION: 'CommonStatisticId' = 183781 - OBJECT_PUDDLE_WATER: 'CommonStatisticId' = 16676 - OBJECT_PUPPET_THEATER_CLAP: 'CommonStatisticId' = 135935 - OBJECT_PUPPET_THEATER_FAILURES: 'CommonStatisticId' = 133858 - OBJECT_PUPPET_THEATER_JOKE: 'CommonStatisticId' = 135934 - OBJECT_PUPPET_THEATER_SCARED: 'CommonStatisticId' = 135936 - OBJECT_PUPPET_THEATER_STAGE: 'CommonStatisticId' = 133859 - OBJECT_RABBIT_HOLE_BRAMBLE_ADVENTURE_STATE: 'CommonStatisticId' = 103097 - OBJECT_RABBIT_HOLE_CAVE_ADVENTURE_STATE: 'CommonStatisticId' = 77469 - OBJECT_RABBIT_HOLE_RELATIONSHIP: 'CommonStatisticId' = 74098 - OBJECT_RABBIT_HOLE_TREE_ADVENTURE_STATE: 'CommonStatisticId' = 77452 - OBJECT_ROAST_MARSHMALLOW_PROGRESS: 'CommonStatisticId' = 112001 - OBJECT_ROBOT_VACUUM_AUTO_CLEAN_TIMER: 'CommonStatisticId' = 173413 - OBJECT_ROBOT_VACUUM_CLEAR_TRASH: 'CommonStatisticId' = 176156 - OBJECT_ROBOT_VACUUM_DOCK_AUTO_CLEAN_TIMER: 'CommonStatisticId' = 173318 - OBJECT_ROBOT_VACUUM_DOCKED_VFX: 'CommonStatisticId' = 176678 - OBJECT_ROBOT_VACUUM_RUNNING_TIME: 'CommonStatisticId' = 173116 - OBJECT_ROBOT_VACUUM_TRASH_CAPACITY: 'CommonStatisticId' = 173115 - OBJECT_ROCKET_SHIP_FUEL: 'CommonStatisticId' = 9691 - OBJECT_ROCKET_SHIP_PROGRESS: 'CommonStatisticId' = 16677 - OBJECT_ROCKET_SHIP_ROCKETS_IN_SPACE: 'CommonStatisticId' = 16678 - OBJECT_ROCKET_SHIP_SABOTAGE: 'CommonStatisticId' = 29448 - OBJECT_ROCKET_SHIP_SPACE_WOOHOO_COUNT: 'CommonStatisticId' = 16679 - OBJECT_SCARECROW_REL: 'CommonStatisticId' = 187939 - OBJECT_SCHOOL_PROJECT_BOX_PROGRESS: 'CommonStatisticId' = 161800 - OBJECT_SCHOOL_PROJECT_BOX_QUALITY: 'CommonStatisticId' = 161799 - OBJECT_SCULPTURE_CONTROL_OVER_SIM: 'CommonStatisticId' = 24887 - OBJECT_SCULPTURE_ENERGY: 'CommonStatisticId' = 24767 - OBJECT_SCULPTURE_RELATIONSHIP: 'CommonStatisticId' = 9892 - OBJECT_SEED_AMOUNT: 'CommonStatisticId' = 140672 - OBJECT_SIM_RAY_CHILLED: 'CommonStatisticId' = 109432 - OBJECT_SIM_RAY_FROZEN: 'CommonStatisticId' = 105910 - OBJECT_SIM_RAY_FROZEN_CHILD: 'CommonStatisticId' = 115717 - OBJECT_SKATING_RINK_ROUTINE_MISTAKES: 'CommonStatisticId' = 180586 - OBJECT_SKATING_RINK_ROUTINE_TOTAL: 'CommonStatisticId' = 180593 - OBJECT_SKATING_RINK_SKATERS_ACTIVE: 'CommonStatisticId' = 180133 - OBJECT_SKATING_RINK_WATCHER_TOTAL: 'CommonStatisticId' = 191312 - OBJECT_SKULL_DISPLAY_CASE_CELEBRATE_COOL_DOWN_TIMER: 'CommonStatisticId' = 154769 - OBJECT_SLEEPING_POD_SLEEP_DURATION: 'CommonStatisticId' = 201167 - OBJECT_SLIPPY_SLIDE_IN_USE: 'CommonStatisticId' = 140219 - OBJECT_SLIPPY_SLIDE_SLIDE_AMOUNT: 'CommonStatisticId' = 140357 - OBJECT_SLIPPY_SLIDE_SLIDING: 'CommonStatisticId' = 143922 - OBJECT_SLIPPY_SLIDE_SOAP: 'CommonStatisticId' = 140670 - OBJECT_SMART_HUB_REL: 'CommonStatisticId' = 203455 - OBJECT_SMOKE_SOURCES: 'CommonStatisticId' = 75461 - OBJECT_SNOW_PAL_HEALTH: 'CommonStatisticId' = 180385 - OBJECT_SNOW_PAL_RELATIONSHIP: 'CommonStatisticId' = 180500 - OBJECT_SNOW_SNOW_MELT: 'CommonStatisticId' = 180386 - OBJECT_SNOW_SNOW_MELT_FIRE: 'CommonStatisticId' = 188747 - OBJECT_SPRINKLERS_DISABLED_NUM: 'CommonStatisticId' = 184640 - OBJECT_SPRINKLERS_ENABLED_NUM: 'CommonStatisticId' = 184403 - OBJECT_STAFF_ASSIGNED_RELATIONSHIP: 'CommonStatisticId' = 119087 - OBJECT_STAFF_ASSIGNED_RELATIONSHIP_BG: 'CommonStatisticId' = 132465 - OBJECT_STAFF_STUDIO_OBJECTS: 'CommonStatisticId' = 189729 - OBJECT_STATE_VALUE_ELIXIR_OF_BURNING_APPLIED: 'CommonStatisticId' = 104263 - OBJECT_STATE_VALUE_HERBICIDE_APPLIED: 'CommonStatisticId' = 111940 - OBJECT_STEAM_ROOM_SABOTAGE_FIRE_LEAF: 'CommonStatisticId' = 120043 - OBJECT_STEAM_ROOM_SABOTAGE_SULFUR: 'CommonStatisticId' = 119485 - OBJECT_STINGS_NEGATIVE: 'CommonStatisticId' = 131012 - OBJECT_STINGS_NEUTRAL: 'CommonStatisticId' = 131013 - OBJECT_STINGS_OVERWHELMING_NEGATIVE: 'CommonStatisticId' = 131014 - OBJECT_STINGS_OVERWHELMING_POSITIVE: 'CommonStatisticId' = 131015 - OBJECT_STINGS_POSITIVE: 'CommonStatisticId' = 131011 - OBJECT_STOVE_FLAVORIZED: 'CommonStatisticId' = 37345 - OBJECT_STREAMING_DRONE_BATTERY: 'CommonStatisticId' = 194617 - OBJECT_STUFFED_ANIMAL_RELATIONSHIP: 'CommonStatisticId' = 10229 - OBJECT_TALKING_TOILET_BIDET_TIMER: 'CommonStatisticId' = 146291 - OBJECT_TALKING_TOILET_BIDET_VFX: 'CommonStatisticId' = 146290 - OBJECT_TALKING_TOILET_BROKENNESS_ELECTRONIC: 'CommonStatisticId' = 132902 - OBJECT_TALKING_TOILET_REL_STC: 'CommonStatisticId' = 138082 - OBJECT_TALKING_TOILET_RELATIONSHIP: 'CommonStatisticId' = 134179 - OBJECT_TALKING_TOILET_ROOM_DRYING_VFX: 'CommonStatisticId' = 139985 - OBJECT_TALKING_TOILET_SELF_CLEANING_VFX: 'CommonStatisticId' = 142671 - OBJECT_TEMPLE_TRAP_ACTIVATED_0: 'CommonStatisticId' = 179617 - OBJECT_TEMPLE_TRAP_ACTIVATED_1: 'CommonStatisticId' = 179618 - OBJECT_TEMPLE_TRAP_ACTIVATED_2: 'CommonStatisticId' = 179619 - OBJECT_TEMPLE_TRAP_ACTIVATED_3: 'CommonStatisticId' = 179620 - OBJECT_TEMPLE_TRAP_EXAMINE_0: 'CommonStatisticId' = 174002 - OBJECT_TEMPLE_TRAP_EXAMINE_1: 'CommonStatisticId' = 174003 - OBJECT_TEMPLE_TRAP_EXAMINE_2: 'CommonStatisticId' = 174004 - OBJECT_TEMPLE_TRAP_EXAMINE_3: 'CommonStatisticId' = 174005 - OBJECT_TEMPLE_TRAP_EXAMINE_PROGRESS: 'CommonStatisticId' = 179014 - OBJECT_TENT_SIM_CHATTING: 'CommonStatisticId' = 111162 - OBJECT_TENT_SIMS_IN_TENT: 'CommonStatisticId' = 110685 - OBJECT_THERMOSTAT_LOT_STAT_COUNTER: 'CommonStatisticId' = 188002 - OBJECT_THERMOSTAT_LOT_STAT_SETTING: 'CommonStatisticId' = 187710 - OBJECT_TIMER: 'CommonStatisticId' = 154238 - OBJECT_TOY_BALL_PET_CHEWEDNESS: 'CommonStatisticId' = 157968 - OBJECT_TRASH_AMOUNT: 'CommonStatisticId' = 16680 - OBJECT_TRASH_CAPACITY: 'CommonStatisticId' = 16681 - OBJECT_TRASH_CHUTE_BROKENNESS_JAM: 'CommonStatisticId' = 133525 - OBJECT_TRASH_CONSUMABLE: 'CommonStatisticId' = 76727 - OBJECT_TRASH_GROWTH: 'CommonStatisticId' = 16639 - OBJECT_TRASH_HI_TECH_CYCLE: 'CommonStatisticId' = 27561 - OBJECT_TRASH_JUST_FAILED_OUTDOOR: 'CommonStatisticId' = 99446 - OBJECT_TRASH_STINK: 'CommonStatisticId' = 27382 - OBJECT_TREAD_MILL_ROCK_CLIMBING_WALL_CLIMB_PROGRESS: 'CommonStatisticId' = 166015 - OBJECT_TREAD_MILL_ROCK_CLIMBING_WALL_SELF_REPAIR_PROGRESS: 'CommonStatisticId' = 167831 - OBJECT_UPGRADE_AROMATHERAPY: 'CommonStatisticId' = 118643 - OBJECT_UPGRADE_BOWLING_LANE_MOON_LIGHT: 'CommonStatisticId' = 158115 - OBJECT_UPGRADE_CHEMICAL_ANALYZER_NEVER_BREAKS: 'CommonStatisticId' = 108304 - OBJECT_UPGRADE_CHEMISTRY_LAB: 'CommonStatisticId' = 105358 - OBJECT_UPGRADE_COFFEE_MAKER_INFUSER: 'CommonStatisticId' = 26045 - OBJECT_UPGRADE_COMPUTER_GAMING_SKILL: 'CommonStatisticId' = 29027 - OBJECT_UPGRADE_COMPUTER_HACKING_MONEY: 'CommonStatisticId' = 29028 - OBJECT_UPGRADE_DISHWASHER_QUIET_RUNNING: 'CommonStatisticId' = 122287 - OBJECT_UPGRADE_DISHWASHER_SPEEDY_CLEANER: 'CommonStatisticId' = 122275 - OBJECT_UPGRADE_DJ_BOOTH_FIREPROOF: 'CommonStatisticId' = 123463 - OBJECT_UPGRADE_DJ_BOOTH_TELESPLOSION: 'CommonStatisticId' = 123465 - OBJECT_UPGRADE_DJ_BOOTH_VFX_EMITTER: 'CommonStatisticId' = 123921 - OBJECT_UPGRADE_DJ_BOOTH_VIDEO_SCREEN: 'CommonStatisticId' = 123464 - OBJECT_UPGRADE_ESPRESSO_MACHINE: 'CommonStatisticId' = 126466 - OBJECT_UPGRADE_FIREPLACE_AUTO_LIGHT: 'CommonStatisticId' = 74684 - OBJECT_UPGRADE_FIREPLACE_FIRESAFE: 'CommonStatisticId' = 74685 - OBJECT_UPGRADE_GENERIC_FAST_ENERGY: 'CommonStatisticId' = 28491 - OBJECT_UPGRADE_GENERIC_FAST_HYGIENE: 'CommonStatisticId' = 9761 - OBJECT_UPGRADE_GENERIC_FASTER_HYGIENE: 'CommonStatisticId' = 9762 - OBJECT_UPGRADE_GENERIC_INCREASE_QUALITY: 'CommonStatisticId' = 16682 - OBJECT_UPGRADE_GENERIC_LOCK_BROKENNESS: 'CommonStatisticId' = 16683 - OBJECT_UPGRADE_GENERIC_LOCK_DIRTINESS: 'CommonStatisticId' = 16684 - OBJECT_UPGRADE_GENERIC_LOCK_HYGIENE: 'CommonStatisticId' = 16685 - OBJECT_UPGRADE_GENERIC_LOWER_BROKENNESS: 'CommonStatisticId' = 16686 - OBJECT_UPGRADE_GENERIC_LOWER_DIRTINESS: 'CommonStatisticId' = 16687 - OBJECT_UPGRADE_HEAT_LAMP_FIRE_SAFE: 'CommonStatisticId' = 131676 - OBJECT_UPGRADE_INVENTION_CONSTRUCTOR_UPGRADE: 'CommonStatisticId' = 112000 - OBJECT_UPGRADE_KARAOKE_MACHINE_AUTO_TUNE: 'CommonStatisticId' = 141793 - OBJECT_UPGRADE_KARAOKE_MACHINE_TELESPLOSION: 'CommonStatisticId' = 141791 - OBJECT_UPGRADE_LAUNDRY_CLOTHES_LINE_IRON_LINE: 'CommonStatisticId' = 177424 - OBJECT_UPGRADE_LAUNDRY_DRYER_LINT_LESS: 'CommonStatisticId' = 177310 - OBJECT_UPGRADE_LAUNDRY_DRYER_NEVER_BREAKS: 'CommonStatisticId' = 177308 - OBJECT_UPGRADE_LAUNDRY_DRYER_QUIET: 'CommonStatisticId' = 177309 - OBJECT_UPGRADE_LAUNDRY_DRYER_SPEED_CYCLE: 'CommonStatisticId' = 177307 - OBJECT_UPGRADE_LAUNDRY_WASHING_MACHINE_INGREDIENT_TRAY: 'CommonStatisticId' = 176336 - OBJECT_UPGRADE_LAUNDRY_WASHING_MACHINE_NEVER_BREAKS: 'CommonStatisticId' = 177242 - OBJECT_UPGRADE_LAUNDRY_WASHING_MACHINE_NOISELESS: 'CommonStatisticId' = 176958 - OBJECT_UPGRADE_LAUNDRY_WASHING_MACHINE_PRE_SOAK: 'CommonStatisticId' = 176953 - OBJECT_UPGRADE_LAUNDRY_WASHING_MACHINE_SPEED_CYCLE: 'CommonStatisticId' = 176951 - OBJECT_UPGRADE_MICROSCOPE_PRECISION_LENSES: 'CommonStatisticId' = 16688 - OBJECT_UPGRADE_MOVIE_BETTER_PROJECTION: 'CommonStatisticId' = 129336 - OBJECT_UPGRADE_ROBOT_VACUUM_DOCK_CLEAR_TRASH: 'CommonStatisticId' = 173324 - OBJECT_UPGRADE_ROBOT_VACUUM_DOCK_MORE_AUTO_CLEAN: 'CommonStatisticId' = 173341 - OBJECT_UPGRADE_ROBOT_VACUUM_FASTER: 'CommonStatisticId' = 171242 - OBJECT_UPGRADE_ROBOT_VACUUM_MORE_STORAGE: 'CommonStatisticId' = 171243 - OBJECT_UPGRADE_ROBOT_VACUUM_QUIET: 'CommonStatisticId' = 171244 - OBJECT_UPGRADE_ROBOT_VACUUM_WET_VAC: 'CommonStatisticId' = 171246 - OBJECT_UPGRADE_ROCKET_SHIP_CARGO_BAY: 'CommonStatisticId' = 38971 - OBJECT_UPGRADE_ROCKET_SHIP_FUEL_STORAGE: 'CommonStatisticId' = 16689 - OBJECT_UPGRADE_ROCKET_SHIP_ION_CANNON: 'CommonStatisticId' = 16690 - OBJECT_UPGRADE_ROCKET_SHIP_LANDING_COMPUTER: 'CommonStatisticId' = 16691 - OBJECT_UPGRADE_ROCKET_SHIP_LANDING_STABILIZERS: 'CommonStatisticId' = 16692 - OBJECT_UPGRADE_ROCKET_SHIP_MANEUVERING_THRUSTERS: 'CommonStatisticId' = 16693 - OBJECT_UPGRADE_ROCKET_SHIP_RAM_SCOOP: 'CommonStatisticId' = 16694 - OBJECT_UPGRADE_ROCKET_SHIP_WORMHOLE_GENERATOR: 'CommonStatisticId' = 114437 - OBJECT_UPGRADE_SIM_RAY_MIND_CONTROL_CHANGE_CLOTHES: 'CommonStatisticId' = 114363 - OBJECT_UPGRADE_SIM_RAY_MIND_CONTROL_CLEAN: 'CommonStatisticId' = 114364 - OBJECT_UPGRADE_SIM_RAY_MIND_CONTROL_EAT: 'CommonStatisticId' = 114365 - OBJECT_UPGRADE_SIM_RAY_MIND_CONTROL_PANIC: 'CommonStatisticId' = 114366 - OBJECT_UPGRADE_SIM_RAY_MIND_CONTROL_SIT: 'CommonStatisticId' = 114367 - OBJECT_UPGRADE_SIM_RAY_MIND_CONTROL_SLEEP: 'CommonStatisticId' = 114368 - OBJECT_UPGRADE_SIM_RAY_TRANSFORM_OBJECT: 'CommonStatisticId' = 114361 - OBJECT_UPGRADE_SIM_RAY_TRANSFORM_SIM: 'CommonStatisticId' = 114362 - OBJECT_UPGRADE_SKETCHPAD_HIGH_PERFORMANCE: 'CommonStatisticId' = 198094 - OBJECT_UPGRADE_SLEEPING_POD_CIRCADIAN_TWEAKER: 'CommonStatisticId' = 200135 - OBJECT_UPGRADE_SLEEPING_POD_EMOTION_DEPRIVATION: 'CommonStatisticId' = 200137 - OBJECT_UPGRADE_SLEEPING_POD_FLOOR_LIGHTING: 'CommonStatisticId' = 200136 - OBJECT_UPGRADE_SLEEPING_POD_SUBLIMINAL_TRANSMITTER: 'CommonStatisticId' = 200122 - OBJECT_UPGRADE_SLEEPING_POD_UNBREAKABLE: 'CommonStatisticId' = 200138 - OBJECT_UPGRADE_SLEEPING_POD_UP_N_ATOMIZER: 'CommonStatisticId' = 200140 - OBJECT_UPGRADE_SPRINKLER_PUDDLE_PREVENTION: 'CommonStatisticId' = 184668 - OBJECT_UPGRADE_SPRINKLER_UNBREAKABLE: 'CommonStatisticId' = 184667 - OBJECT_UPGRADE_STEAM_ROOM_PRECISION_TEMPERATURE: 'CommonStatisticId' = 119102 - OBJECT_UPGRADE_STEREO: 'CommonStatisticId' = 118642 - OBJECT_UPGRADE_STREAMING_DRONE_BATTERY: 'CommonStatisticId' = 194536 - OBJECT_UPGRADE_STREAMING_DRONE_BREAKS_LESS: 'CommonStatisticId' = 194537 - OBJECT_UPGRADE_STREAMING_DRONE_VIDEO_QUALITY: 'CommonStatisticId' = 194538 - OBJECT_UPGRADE_TALKING_TOILET_BIDET_SHOW: 'CommonStatisticId' = 146240 - OBJECT_UPGRADE_TALKING_TOILET_CUSTOM_PERSONA: 'CommonStatisticId' = 135636 - OBJECT_UPGRADE_TALKING_TOILET_LOCK_BROKENNESS_ELECTRONIC: 'CommonStatisticId' = 141810 - OBJECT_UPGRADE_TALKING_TOILET_LOCK_BROKENNESS_PLUMBING: 'CommonStatisticId' = 141801 - OBJECT_UPGRADE_TALKING_TOILET_LOWER_BROKENNESS_ELECTRONIC: 'CommonStatisticId' = 141800 - OBJECT_UPGRADE_TALKING_TOILET_ROOM_DRYING: 'CommonStatisticId' = 132923 - OBJECT_UPGRADE_TALKING_TOILET_SELF_CLEANING: 'CommonStatisticId' = 132925 - OBJECT_UPGRADE_TALKING_TOILET_VFX_EMITTER: 'CommonStatisticId' = 132924 - OBJECT_UPGRADE_TELESCOPE_PRECISION_EYEPIECE: 'CommonStatisticId' = 9700 - OBJECT_UPGRADE_TRASH_CHUTE_NEVER_JAM: 'CommonStatisticId' = 141324 - OBJECT_UPGRADE_TREAD_MILL_ROCK_CLIMBING_WALL_SELF_REPAIRING: 'CommonStatisticId' = 165741 - OBJECT_UPGRADE_TV_SUPER_RECEPTION: 'CommonStatisticId' = 10516 - OBJECT_UPGRADE_UNBREAKABLE: 'CommonStatisticId' = 118644 - OBJECT_UPGRADE_VIDEO_GAME_CONSOLE_TELESPLOSION: 'CommonStatisticId' = 145555 - OBJECT_UPGRADE_VIDEO_GAME_CONSOLE_TIGHTEN_UP_GRAPHICS: 'CommonStatisticId' = 145557 - OBJECT_UPGRADE_VIDEO_GAME_CONSOLE_UNBREAKABLE: 'CommonStatisticId' = 145556 - OBJECT_UPGRADE_VIDEO_STATION_LIGHTS: 'CommonStatisticId' = 192501 - OBJECT_UPGRADE_VIDEO_STATION_STORAGE: 'CommonStatisticId' = 192500 - OBJECT_UPGRADE_VIDEO_STATION_UNBREAKABLE: 'CommonStatisticId' = 192499 - OBJECT_UPGRADE_WEATHER_CONTROLLER_CAPACITIVE_EFFICIENCY: 'CommonStatisticId' = 186466 - OBJECT_UPGRADE_WEATHER_CONTROLLER_CLIMATIC_HYDRATOR: 'CommonStatisticId' = 186464 - OBJECT_UPGRADE_WEATHER_CONTROLLER_GYROSCOPE_DURABILITY: 'CommonStatisticId' = 186460 - OBJECT_UPGRADE_WEATHER_CONTROLLER_HUMIDITY_CHILLER: 'CommonStatisticId' = 186463 - OBJECT_UPGRADE_WEATHER_CONTROLLER_MOISTURE_VAPORATOR: 'CommonStatisticId' = 186465 - OBJECT_UPGRADE_WEATHER_CONTROLLER_SELF_REPAIRING_NANITES: 'CommonStatisticId' = 186461 - OBJECT_UPGRADE_WEATHER_CONTROLLER_TEMPORAL_MODIFIER_UNIT: 'CommonStatisticId' = 186462 - OBJECT_UPGRADE_XRAY_MACHINE_AUTO_CALIBRATE: 'CommonStatisticId' = 109287 - OBJECT_UPGRADE_XRAY_MACHINE_NEVER_BREAKS: 'CommonStatisticId' = 109286 - OBJECT_VFX_MACHINE_CONTROL_UNIT: 'CommonStatisticId' = 193877 - OBJECT_VFX_MACHINE_TOGGLE: 'CommonStatisticId' = 193900 - OBJECT_VIDEO_RECORDING_POLISH: 'CommonStatisticId' = 192402 - OBJECT_VIDEO_RECORDING_QUALITY: 'CommonStatisticId' = 192412 - OBJECT_VIDEOS_UPLOADED: 'CommonStatisticId' = 203205 - OBJECT_VIOLIN_SOOTHING_STRINGS: 'CommonStatisticId' = 34552 - OBJECT_VIP_ROPE_RELATIONSHIP: 'CommonStatisticId' = 194781 - OBJECT_VOODOO_DOLL_RELATIONSHIP: 'CommonStatisticId' = 97150 - OBJECT_WATER_BUCKET_CAPACITY: 'CommonStatisticId' = 183213 - OBJECT_WEATHER_CONTROLLER_IN_USE: 'CommonStatisticId' = 187982 - OBJECT_WIND_CHIME_ANNOYING_CHIMES: 'CommonStatisticId' = 143516 - OBJECT_WIND_CHIME_SOOTHING_CHIMES: 'CommonStatisticId' = 143518 - OBJECT_WIND_CHIME_SOUNDS_OF_WIND: 'CommonStatisticId' = 141179 - OBJECT_WIND_CHIMES_ANIMATE: 'CommonStatisticId' = 140783 - OBJECT_WIND_CHIMES_TIMING: 'CommonStatisticId' = 140435 - OBJECT_XRAY_MACHINE_CALIBRATE: 'CommonStatisticId' = 105834 - OWNABLE_BUSINESS_ADVERTISING_INTERNET: 'CommonStatisticId' = 141297 - OWNABLE_BUSINESS_ADVERTISING_NEWSPAPER: 'CommonStatisticId' = 141295 - OWNABLE_BUSINESS_ADVERTISING_RADIO: 'CommonStatisticId' = 141296 - OWNABLE_BUSINESS_ADVERTISING_TV: 'CommonStatisticId' = 141298 - OWNABLE_BUSINESS_EMPLOYEE_SATISFACTION: 'CommonStatisticId' = 137205 - OWNABLE_BUSINESS_TRAINING_BRIEF: 'CommonStatisticId' = 143640 - OWNABLE_BUSINESS_TRAINING_EXTENSIVE: 'CommonStatisticId' = 143641 - OWNABLE_BUSINESS_TRAINING_STANDARD: 'CommonStatisticId' = 143636 - OWNABLE_RESTAURANT_CUSTOMER_QUALITY: 'CommonStatisticId' = 142184 - OWNABLE_RESTAURANT_CUSTOMER_STAR_RATING: 'CommonStatisticId' = 142545 - OWNABLE_RESTAURANT_CUSTOMER_VALUE: 'CommonStatisticId' = 142185 - OWNABLE_RESTAURANT_CUSTOMER_WAIT_TIME: 'CommonStatisticId' = 140530 - OWNABLE_RESTAURANT_EMPLOYEE_CHEF_COOK_STYLE_CAREFUL: 'CommonStatisticId' = 144017 - OWNABLE_RESTAURANT_EMPLOYEE_CHEF_COOK_STYLE_NORMAL: 'CommonStatisticId' = 144019 - OWNABLE_RESTAURANT_EMPLOYEE_CHEF_COOK_STYLE_QUICK: 'CommonStatisticId' = 144020 - OWNABLE_VET_CLINIC_CUSTOMER_VALUE_OF_SERVICE: 'CommonStatisticId' = 168448 - OWNABLE_VET_CLINIC_CUSTOMER_WAIT_TIME: 'CommonStatisticId' = 167884 - OWNABLE_VET_CLINIC_TRAINING_BRIEF: 'CommonStatisticId' = 167734 - OWNABLE_VET_CLINIC_TRAINING_EXTENSIVE: 'CommonStatisticId' = 167737 - OWNABLE_VET_CLINIC_TRAINING_STANDARD: 'CommonStatisticId' = 167741 - OWNABLE_VET_CLINIC_VET_MEDICINE_VENDING_MACHINE_INVENTORY_COUNT: 'CommonStatisticId' = 172459 - OWNABLE_VET_CUSTOMER_STAR_RATING: 'CommonStatisticId' = 158853 - PAPARAZZI_FULFILMENT: 'CommonStatisticId' = 196693 - PAPARAZZI_MELTDOWN: 'CommonStatisticId' = 191956 - PARENTING_CHANCE_CARDS_ADVENTURE_COOLDOWN: 'CommonStatisticId' = 167856 - PARENTING_SKILL_SUPER_PARENT: 'CommonStatisticId' = 160760 - PATH_OBSTACLE_CLEAR: 'CommonStatisticId' = 181047 - PATH_OBSTACLE_TEMPLE_LOCK: 'CommonStatisticId' = 178563 - PATH_OBSTACLE_TRAVEL_THROUGH_ADVENTURE: 'CommonStatisticId' = 175717 - PERFORMANCE_SPACE_LID: 'CommonStatisticId' = 143479 - PET_CAT_PREGNANCY_VOMIT_COUNT: 'CommonStatisticId' = 174482 - PET_EMOTION_TRIGGERS_ELDER_DROWSY: 'CommonStatisticId' = 160997 - PET_EMOTION_TRIGGERS_EXCITED: 'CommonStatisticId' = 164472 - PET_EMOTION_TRIGGERS_HYPER: 'CommonStatisticId' = 164475 - PET_EMOTION_TRIGGERS_IN_HEAT_CAT: 'CommonStatisticId' = 160498 - PET_EMOTION_TRIGGERS_IN_HEAT_DOG: 'CommonStatisticId' = 160519 - PET_FOOD_BOWL_FRESHNESS: 'CommonStatisticId' = 158892 - PET_HAIRY_TRAIT_SHED_COUNTER: 'CommonStatisticId' = 178058 - PET_OBSTACLE_COURSE_FAULTS: 'CommonStatisticId' = 170390 - PET_PHOTOGRAPHY_SIMSTAGRAM: 'CommonStatisticId' = 170340 - PET_WORLD_WALK_BYS_CAT_BEG: 'CommonStatisticId' = 165423 - PET_WORLD_WALK_BYS_CAT_FIND_OBJECT: 'CommonStatisticId' = 165416 - PET_WORLD_WALK_BYS_CAT_SLEEP: 'CommonStatisticId' = 165424 - PET_WORLD_WALK_BYS_CAT_SOCIALIZE: 'CommonStatisticId' = 165426 - PET_WORLD_WALK_BYS_DOG_BEG: 'CommonStatisticId' = 165414 - PET_WORLD_WALK_BYS_DOG_SLEEP: 'CommonStatisticId' = 165415 - PET_WORLD_WALK_BYS_DOG_SOCIALIZE: 'CommonStatisticId' = 165413 - PETS_CAT_SCRATCH_FURNITURE_OBJECT: 'CommonStatisticId' = 163404 - PETS_SELL_VALUE_AGGRESSIVE: 'CommonStatisticId' = 174211 - PETS_SELL_VALUE_FRIENDLY: 'CommonStatisticId' = 169906 - PETS_SELL_VALUE_LOYAL: 'CommonStatisticId' = 169905 - PETS_SELL_VALUE_NAUGHTY: 'CommonStatisticId' = 174210 - PETS_SELL_VALUE_PLAYFUL: 'CommonStatisticId' = 174209 - PETS_SELL_VALUE_SMART: 'CommonStatisticId' = 169907 - PETS_SELL_VALUE_STUBBORN: 'CommonStatisticId' = 174212 - PETS_SNIFF_NEW_OBJECT: 'CommonStatisticId' = 175857 - PETS_SPIN_LOW_BLADDER_BOWEL: 'CommonStatisticId' = 171061 - POISONED_ANCIENT_RELIC_CURSE: 'CommonStatisticId' = 179713 - POISONED_BIT_BY_SPIDER: 'CommonStatisticId' = 179715 - POISONED_GATE: 'CommonStatisticId' = 180017 - POISONED_GHOST_BELCH: 'CommonStatisticId' = 179719 - POISONED_POISON_DART: 'CommonStatisticId' = 179716 - POISONED_POISON_GAS: 'CommonStatisticId' = 180263 - POISONED_STUNG_BY_BEE: 'CommonStatisticId' = 179714 - POISONED_STUNG_BY_SCORPION: 'CommonStatisticId' = 179718 - POLITE_HUNGER: 'CommonStatisticId' = 27956 - PREGNANCY: 'CommonStatisticId' = 16640 - PREGNANCY_CAT: 'CommonStatisticId' = 169190 - PREGNANCY_HORSE: 'CommonStatisticId' = 323070 - PREGNANCY_CONTRACTION_MAX: 'CommonStatisticId' = 76975 - PREGNANCY_CONTRACTION_TIMER: 'CommonStatisticId' = 76973 - PREGNANCY_DISCOVERY: 'CommonStatisticId' = 16641 - PREGNANCY_DISCOVERY_PET: 'CommonStatisticId' = 169238 - PREGNANCY_DOG: 'CommonStatisticId' = 169191 - PREGNANCY_GENDER_CHANCE: 'CommonStatisticId' = 117011 - PRESENT_PILE_BIRTHDAY_COUNT: 'CommonStatisticId' = 188867 - PRESENT_PILE_PRESENT_AMOUNT: 'CommonStatisticId' = 180947 - PROGRAMMING_SKILL_APP_PROGRESS: 'CommonStatisticId' = 33284 - PROGRAMMING_SKILL_FREELANCE_PROGRESS: 'CommonStatisticId' = 33234 - PROGRAMMING_SKILL_GAME_PROGRESS: 'CommonStatisticId' = 36387 - PROGRAMMING_SKILL_PLUGIN_PROGRESS: 'CommonStatisticId' = 31410 - PROGRAMMING_SKILL_VIRUS_PROGRESS: 'CommonStatisticId' = 33259 - PTO: 'CommonStatisticId' = 111109 - RABBIT_HOLE_BRAMBLE_HERBICIDE_COOLDOWN: 'CommonStatisticId' = 103189 - RAIN_OBJECT_WETNESS: 'CommonStatisticId' = 183352 - RAIN_PET_WETNESS: 'CommonStatisticId' = 186244 - RAIN_SIM_WETNESS: 'CommonStatisticId' = 183350 - RAINBOW: 'CommonStatisticId' = 187940 - RANDOM: 'CommonStatisticId' = 161235 - RANKED_FAME: 'CommonStatisticId' = 188229 - RANKED_FAME_QUIRKS_A_SERIOUS_ACTOR: 'CommonStatisticId' = 199731 - RANKED_FAME_QUIRKS_BRUSHES_WITH_FAME: 'CommonStatisticId' = 199740 - RANKED_FAME_QUIRKS_EMOTION_BOMB: 'CommonStatisticId' = 199738 - RANKED_FAME_QUIRKS_FAN_MAIL: 'CommonStatisticId' = 199737 - RANKED_FAME_QUIRKS_JUICE_ENTHUSIAST: 'CommonStatisticId' = 199742 - RANKED_FAME_QUIRKS_NO_TOUCHING: 'CommonStatisticId' = 199739 - RANKED_FAME_QUIRKS_PAPARAZZI_DARLING: 'CommonStatisticId' = 199736 - RANKED_FAME_QUIRKS_PHONE_FANATIC: 'CommonStatisticId' = 199741 - RANKED_FAME_QUIRKS_PUBLIC_NUMBER: 'CommonStatisticId' = 199733 - RANKED_FAME_QUIRKS_REFINED_PALATE: 'CommonStatisticId' = 199735 - RANKED_FAME_QUIRKS_STAN: 'CommonStatisticId' = 199743 - RANKED_FAME_QUIRKS_VAIN_STREET: 'CommonStatisticId' = 199734 - RANKED_OCCULT_VAMPIRE_DO_NOT_DRINK_DEEPLY: 'CommonStatisticId' = 155468 - RANKED_OCCULT_VAMPIRE_DO_NOT_DRINK_WITHOUT_PERMISSION: 'CommonStatisticId' = 155644 - RANKED_OCCULT_VAMPIRE_SURVIVE_DAY_TRACKER: 'CommonStatisticId' = 155663 - RANKED_OCCULT_VAMPIRE_XP: 'CommonStatisticId' = 150071 - RANKED_REPUTATION: 'CommonStatisticId' = 192283 - RANKED_SOCIAL_NETWORK_FATIGUE_COUNTER: 'CommonStatisticId' = 200264 - RELATIONSHIP_TRACK_AUTHORITY: 'CommonStatisticId' = 161998 - RELATIONSHIP_TRACK_RIVALRY: 'CommonStatisticId' = 161999 - RELATIONSHIP_TRACK_SHORT_TERM_CONTEXT_INTERROGATION_TABLE_CALM: 'CommonStatisticId' = 103618 - RELATIONSHIP_TRACK_SHORT_TERM_CONTEXT_INTERROGATION_TABLE_DEFENSIVE: 'CommonStatisticId' = 103617 - RELATIONSHIP_TRACK_SHORT_TERM_CONTEXT_INTERROGATION_TABLE_FRIENDLY: 'CommonStatisticId' = 103613 - RELATIONSHIP_TRACK_SHORT_TERM_CONTEXT_INTERROGATION_TABLE_FURIOUS: 'CommonStatisticId' = 103616 - RELATIONSHIP_TRACK_SHORT_TERM_CONTEXT_INTERROGATION_TABLE_SHY: 'CommonStatisticId' = 103598 - RELATIONSHIP_TRACK_SHORT_TERM_CONTEXT_INTERROGATION_TABLE_SMUG: 'CommonStatisticId' = 103619 - RELATIONSHIP_TRACK_SHORT_TERM_CONTEXT_INTERROGATION_TABLE_SUSPICIOUS: 'CommonStatisticId' = 103612 - RELATIONSHIP_TRACK_SHORT_TERM_CONTEXT_INTERROGATION_TABLE_TENSE: 'CommonStatisticId' = 103615 - RELATIONSHIP_TRACK_SHORT_TERM_CONTEXT_INTERROGATION_TABLE_TERRIFIED: 'CommonStatisticId' = 103614 - RELATIONSHIP_TRACK_SHORT_TERM_CONTEXT_INTERROGATION_TABLE_WORRIED: 'CommonStatisticId' = 103620 - RELATIONSHIP_TRACK_SHORT_TERM_CONTEXT_RETAIL_PURCHASE_INTEREST: 'CommonStatisticId' = 111598 - RETAIL_ADVERTISE_ON_THE_WEB_LONG: 'CommonStatisticId' = 116021 - RETAIL_ADVERTISE_ON_THE_WEB_SHORT: 'CommonStatisticId' = 114453 - RETAIL_ADVERTISE_TV_LONG: 'CommonStatisticId' = 116024 - RETAIL_ADVERTISE_TV_SHORT: 'CommonStatisticId' = 114173 - RETAIL_EMPLOYEE_SATISFACTION: 'CommonStatisticId' = 112066 - RETAIL_PRICE_RANGE_MAX: 'CommonStatisticId' = 112493 - RETAIL_PRICE_RANGE_MIN: 'CommonStatisticId' = 112494 - RETAIL_PURCHASE_INTENT: 'CommonStatisticId' = 113505 - RETAIL_WAIT_TO_PURCHASE: 'CommonStatisticId' = 112136 - ROLL_UP_BUTTERFLY: 'CommonStatisticId' = 149258 - ROLL_UP_CITY_CLOUDS: 'CommonStatisticId' = 149268 - ROLL_UP_CITY_LAYERS: 'CommonStatisticId' = 149265 - ROLL_UP_CITY_LINES: 'CommonStatisticId' = 149266 - ROLL_UP_CITY_NIGHT: 'CommonStatisticId' = 149267 - ROLL_UP_CUL_BUTTERFLY: 'CommonStatisticId' = 149261 - ROLL_UP_CUL_FLOWER: 'CommonStatisticId' = 149262 - ROLL_UP_CUL_OCTOPUS: 'CommonStatisticId' = 149264 - ROLL_UP_CUL_PEACOCK: 'CommonStatisticId' = 149260 - ROLL_UP_GRAF_GOLD: 'CommonStatisticId' = 149269 - ROLL_UP_GRAF_GREEN: 'CommonStatisticId' = 149270 - ROLL_UP_TREES: 'CommonStatisticId' = 149259 - ROOMMATE_COUNTER: 'CommonStatisticId' = 200721 - SATELLITE_DISH_DEFLECT_VFX_COOLDOWN: 'CommonStatisticId' = 115909 - SATELLITE_DISH_HIVE_MIND_COOLDOWN: 'CommonStatisticId' = 107519 - SATELLITE_DISH_VFX_COOLDOWN: 'CommonStatisticId' = 115520 - SERUMS_TESTS_COMPLETED_AGE_AWAY: 'CommonStatisticId' = 104968 - SERUMS_TESTS_COMPLETED_ALIEN_AURA: 'CommonStatisticId' = 104969 - SERUMS_TESTS_COMPLETED_EMBIGGEN: 'CommonStatisticId' = 104978 - SERUMS_TESTS_COMPLETED_FIXERS_LUCK: 'CommonStatisticId' = 104979 - SERUMS_TESTS_COMPLETED_GHOST_GOO: 'CommonStatisticId' = 104980 - SERUMS_TESTS_COMPLETED_NEED_FIXER: 'CommonStatisticId' = 104981 - SERUMS_TESTS_COMPLETED_OX_STRENGTH: 'CommonStatisticId' = 104982 - SERUMS_TESTS_COMPLETED_REAPERS_FRIEND: 'CommonStatisticId' = 104970 - SERUMS_TESTS_COMPLETED_RED_HOT: 'CommonStatisticId' = 104971 - SERUMS_TESTS_COMPLETED_ROSE_PERFUME: 'CommonStatisticId' = 104972 - SERUMS_TESTS_COMPLETED_SLIMIFY: 'CommonStatisticId' = 104973 - SERUMS_TESTS_COMPLETED_SMART: 'CommonStatisticId' = 104974 - SERUMS_TESTS_COMPLETED_SNAKE_OIL: 'CommonStatisticId' = 104975 - SERUMS_TESTS_COMPLETED_SPARK_DRIVE: 'CommonStatisticId' = 104976 - SERUMS_TESTS_COMPLETED_SYNTHETIC_FOOD: 'CommonStatisticId' = 104977 - SERVICE_NPC_WAIT_FOR_WORK: 'CommonStatisticId' = 29694 - SICKNESS_BEHAVIOR: 'CommonStatisticId' = 169645 - SICKNESS_CRITICAL_DURATION_BARFING: 'CommonStatisticId' = 168431 - SICKNESS_CRITICAL_DURATION_EXTREME_LETHARGY: 'CommonStatisticId' = 168432 - SICKNESS_CRITICAL_DURATION_FLEAS: 'CommonStatisticId' = 168433 - SICKNESS_CRITICAL_DURATION_GLOWING_NOSE: 'CommonStatisticId' = 168434 - SICKNESS_CRITICAL_DURATION_GOLDEN_POOP: 'CommonStatisticId' = 168435 - SICKNESS_CRITICAL_DURATION_HOT_FEET: 'CommonStatisticId' = 168441 - SICKNESS_CRITICAL_DURATION_ICEY_FUR: 'CommonStatisticId' = 168436 - SICKNESS_CRITICAL_DURATION_MOUTH_MOTHS: 'CommonStatisticId' = 168437 - SICKNESS_CRITICAL_DURATION_RAINBOW_POOP: 'CommonStatisticId' = 168438 - SICKNESS_CRITICAL_DURATION_STINKY_FUR: 'CommonStatisticId' = 168440 - SICKNESS_CRITICAL_DURATION_UNCONTROLLABLE_DROOLING: 'CommonStatisticId' = 168439 - SICKNESS_DAYS_SINCE_LAST_SICK: 'CommonStatisticId' = 169731 - SICKNESS_SINCE_LAST_SICK_TIMER: 'CommonStatisticId' = 169732 - SICKNESS_SYSTEM_DOCTOR_EXAMS_RAN: 'CommonStatisticId' = 116636 - SICKNESS_SYSTEM_HOME_REMEDY: 'CommonStatisticId' = 108660 - SICKNESS_SYSTEM_ILLNESS_DURATION: 'CommonStatisticId' = 105481 - SICKNESS_SYSTEM_PATIENT_DIAGNOSIS: 'CommonStatisticId' = 107214 - SICKNESS_SYSTEM_PATIENT_EXAM_RESULTS: 'CommonStatisticId' = 107988 - SICKNESS_SYSTEM_PATIENT_EXAMS_RAN: 'CommonStatisticId' = 107999 - SICKNESS_SYSTEM_SURGERY_TABLE_PATIENT_TREATMENTS: 'CommonStatisticId' = 110400 - SICKNESS_SYSTEM_SYMPTOM_TRIGGER: 'CommonStatisticId' = 105528 - SIM_BODY_TEMPERATURE: 'CommonStatisticId' = 181210 - SIM_BUBBLE_BLOWER_EFFECTIVENESS: 'CommonStatisticId' = 135797 - SIM_EFFECTIVE_TEMPERATURE: 'CommonStatisticId' = 181204 - SIM_INFO_BASKETBALL_WINS: 'CommonStatisticId' = 147473 - SIM_INFO_OUTDOORS_CHECK: 'CommonStatisticId' = 76777 - SIM_INFO_TIME_SINCE_LAST_SLEPT: 'CommonStatisticId' = 33350 - SIM_INFO_TIME_SINCE_LAST_SOCIAL: 'CommonStatisticId' = 33351 - SIM_OBJECT_FAMILIARITY_BUBBLE_BLOWER: 'CommonStatisticId' = 134849 - SIM_OBJECT_FAMILIARITY_TALKING_TOILET: 'CommonStatisticId' = 134821 - SIM_OVERHEATING: 'CommonStatisticId' = 190848 - SIM_SWIMMING: 'CommonStatisticId' = 103887 - SIM_TO_PET_IMITATE_PET: 'CommonStatisticId' = 173475 - SITUATION_APB_ASKED_ABOUT_SUSPECT: 'CommonStatisticId' = 109995 - SITUATION_DANCE_FEVER: 'CommonStatisticId' = 74758 - SITUATION_SEASONAL_GO_SKATE: 'CommonStatisticId' = 181135 - SITUATION_SEASONAL_PLAY_IN_LEAVES: 'CommonStatisticId' = 181137 - SITUATION_SEASONAL_SNOW: 'CommonStatisticId' = 181492 - SKELETON: 'CommonStatisticId' = 175973 - SKELETON_JOKE_COUNT: 'CommonStatisticId' = 176171 - SKILL_ADULT_MAJOR_ACTING: 'CommonStatisticId' = 194727 - SKILL_ADULT_MAJOR_ARCHAEOLOGY: 'CommonStatisticId' = 174237 - SKILL_ADULT_MAJOR_BAKING: 'CommonStatisticId' = 104198 - SKILL_ADULT_MAJOR_BARTENDING: 'CommonStatisticId' = 16695 - SKILL_ADULT_MAJOR_CHARISMA: 'CommonStatisticId' = 16699 - SKILL_ADULT_MAJOR_COMEDY: 'CommonStatisticId' = 16698 - SKILL_ADULT_MAJOR_DJ_MIXING: 'CommonStatisticId' = 121612 - SKILL_ADULT_MAJOR_FABRICATION: 'CommonStatisticId' = 231908 - SKILL_ADULT_MAJOR_FISHING: 'CommonStatisticId' = 39397 - SKILL_ADULT_MAJOR_FLOWER_ARRANGING: 'CommonStatisticId' = 186703 - SKILL_ADULT_MAJOR_GARDENING: 'CommonStatisticId' = 16700 - SKILL_ADULT_MAJOR_GOURMET_COOKING: 'CommonStatisticId' = 16701 - SKILL_ADULT_MAJOR_GUITAR: 'CommonStatisticId' = 16702 - SKILL_ADULT_MAJOR_HANDINESS: 'CommonStatisticId' = 16704 - SKILL_ADULT_MAJOR_HERBALISM: 'CommonStatisticId' = 101920 - SKILL_ADULT_MAJOR_HOME_STYLE_COOKING: 'CommonStatisticId' = 16705 - SKILL_ADULT_MAJOR_LOGIC: 'CommonStatisticId' = 16706 - SKILL_ADULT_MAJOR_MISCHIEF: 'CommonStatisticId' = 16707 - SKILL_ADULT_MAJOR_PAINTING: 'CommonStatisticId' = 16708 - SKILL_ADULT_MAJOR_PARENTING: 'CommonStatisticId' = 160504 - SKILL_ADULT_MAJOR_PHOTOGRAPHY: 'CommonStatisticId' = 105774 - SKILL_ADULT_MAJOR_PIANO: 'CommonStatisticId' = 16709 - SKILL_ADULT_MAJOR_PIPE_ORGAN: 'CommonStatisticId' = 149665 - SKILL_ADULT_MAJOR_PROGRAMMING: 'CommonStatisticId' = 16703 - SKILL_ADULT_MAJOR_ROCKET_SCIENCE: 'CommonStatisticId' = 16710 - SKILL_ADULT_MAJOR_SINGING: 'CommonStatisticId' = 137811 - SKILL_ADULT_MAJOR_VETERINARIAN: 'CommonStatisticId' = 161190 - SKILL_ADULT_MAJOR_VIDEO_GAMING: 'CommonStatisticId' = 16712 - SKILL_ADULT_MAJOR_VIOLIN: 'CommonStatisticId' = 16713 - SKILL_ADULT_MAJOR_WELLNESS: 'CommonStatisticId' = 117858 - SKILL_ADULT_MAJOR_WRITING: 'CommonStatisticId' = 16714 - SKILL_ADULT_MINOR_DANCING: 'CommonStatisticId' = 128145 - SKILL_ADULT_MINOR_JUICE_FIZZING: 'CommonStatisticId' = 234806 - SKILL_ADULT_MINOR_LOCAL_CULTURE: 'CommonStatisticId' = 174687 - SKILL_ADULT_MINOR_MEDIA_PRODUCTION: 'CommonStatisticId' = 192655 - SKILL_BOWLING: 'CommonStatisticId' = 158659 - SKILL_CHARISMA_NEGOTIATE_PROMOTION_COOLDOWN: 'CommonStatisticId' = 37246 - SKILL_CHILD_CREATIVITY: 'CommonStatisticId' = 16718 - SKILL_CHILD_MENTAL: 'CommonStatisticId' = 16719 - SKILL_CHILD_MOTOR: 'CommonStatisticId' = 16720 - SKILL_CHILD_SOCIAL: 'CommonStatisticId' = 16721 - SKILL_CHOPSTICKS: 'CommonStatisticId' = 142593 - SKILL_DOG_TRAINING: 'CommonStatisticId' = 161220 - SKILL_FITNESS: 'CommonStatisticId' = 16659 - SKILL_FOOSBALL: 'CommonStatisticId' = 122854 - SKILL_HIDDEN_SKATING: 'CommonStatisticId' = 179925 - SKILL_HIDDEN_TREAD_MILL_ROCK_CLIMBING_WALL_CLIMB: 'CommonStatisticId' = 165900 - SKILL_HIDDEN_VAMPIRE_LORE: 'CommonStatisticId' = 149556 - SKILL_HORSE_SHOES: 'CommonStatisticId' = 104859 - SKILL_PET_POOP_CLEANUP: 'CommonStatisticId' = 161097 - SKILL_RETAIL_MAINTENANCE: 'CommonStatisticId' = 111904 - SKILL_RETAIL_SALES: 'CommonStatisticId' = 111902 - SKILL_RETAIL_WORK_ETHIC: 'CommonStatisticId' = 111903 - SKILL_SPICY_FOOD: 'CommonStatisticId' = 142592 - SKILL_THROWING_THINGS: 'CommonStatisticId' = 127868 - SKILL_TODDLER_COMMUNICATION: 'CommonStatisticId' = 140170 - SKILL_TODDLER_IMAGINATION: 'CommonStatisticId' = 140706 - SKILL_TODDLER_MOVEMENT: 'CommonStatisticId' = 136140 - SKILL_TODDLER_POTTY: 'CommonStatisticId' = 144913 - SKILL_TODDLER_THINKING: 'CommonStatisticId' = 140504 - SKILL_VIDEO_GAMING_BLICBLOCK: 'CommonStatisticId' = 31807 - SKILL_VIDEO_GAMING_HILLOCK: 'CommonStatisticId' = 31813 - SKILL_VIDEO_GAMING_INCREDIBLE_SPORTS: 'CommonStatisticId' = 31808 - SKILL_VIDEO_GAMING_MANIAC_MATCHUMS: 'CommonStatisticId' = 31811 - SKILL_VIDEO_GAMING_MARIA_SISTERS: 'CommonStatisticId' = 31809 - SKILL_VIDEO_GAMING_PARTY: 'CommonStatisticId' = 145448 - SKILL_VIDEO_GAMING_PLATFORMER: 'CommonStatisticId' = 145447 - SKILL_VIDEO_GAMING_RACING: 'CommonStatisticId' = 145450 - SKILL_VIDEO_GAMING_REFUGE: 'CommonStatisticId' = 31810 - SKILL_VIDEO_GAMING_ROAD_RIVAL: 'CommonStatisticId' = 31812 - SKILL_VIDEO_GAMING_RPG: 'CommonStatisticId' = 145449 - SKILL_VIDEO_GAMING_SIMS_FOREVER_RENAMED: 'CommonStatisticId' = 31806 - SMART_HUB_FRIENDSHIP_MAIN: 'CommonStatisticId' = 203686 - SOCIAL_CONTEXT_AWKWARDNESS: 'CommonStatisticId' = 24098 - SOCIAL_CONTEXT_FRIENDSHIP: 'CommonStatisticId' = 24099 - SOCIAL_CONTEXT_FUN: 'CommonStatisticId' = 24100 - SOCIAL_CONTEXT_ROMANCE: 'CommonStatisticId' = 24101 - SOCIAL_NETWORK_FOLLOWERS_TNS_TOTAL: 'CommonStatisticId' = 144940 - SPRING_CHALLENGE_2016_NPC_FERTILIZER_STOCK: 'CommonStatisticId' = 135535 - STUFFED_ANIMAL_LOVE: 'CommonStatisticId' = 8240 - STYLE_INFLUENCER_ARTICLE_PROGRESS: 'CommonStatisticId' = 198610 - STYLEBOARD_COMPLETION: 'CommonStatisticId' = 198120 - TEMPLE_EXCAVATION_SITE_PROGRESS: 'CommonStatisticId' = 183739 - TEMPLE_TRAP_VIEW: 'CommonStatisticId' = 183186 - TIME_MOOD_NEUTRAL_MAINTAINED: 'CommonStatisticId' = 77762 - TODDLER_DIAPER_LOAD: 'CommonStatisticId' = 140764 - TODDLER_JUNGLE_GYM_PLAY_PRETEND_COUNTER: 'CommonStatisticId' = 174394 - TODDLERS_CAREGIVER_PLAY_WITH_TODDLER: 'CommonStatisticId' = 157445 - TODDLERS_CAREGIVER_WATCH_TODDLER: 'CommonStatisticId' = 151787 - TODDLERS_WATCH: 'CommonStatisticId' = 144294 - TODDLERS_WILD_OUTSIDE_OR_INSIDE: 'CommonStatisticId' = 154270 - TOURIST_CELEBRITY_TILE_VIEW: 'CommonStatisticId' = 197022 - TRAIT_ACTIVE_ACTIVITY: 'CommonStatisticId' = 27458 - TRAIT_ACTIVE_TENSE_TIMER: 'CommonStatisticId' = 99491 - TRAIT_AMBITIOUS_NEED_TO_ADVANCE: 'CommonStatisticId' = 29116 - TRAIT_AUTONOMY_ACTIVE: 'CommonStatisticId' = 29105 - TRAIT_AUTONOMY_ART_LOVER: 'CommonStatisticId' = 28563 - TRAIT_AUTONOMY_BOOKWORM: 'CommonStatisticId' = 28597 - TRAIT_AUTONOMY_BRO: 'CommonStatisticId' = 29124 - TRAIT_AUTONOMY_CHILDHOOD_PHASE_LOUD: 'CommonStatisticId' = 165673 - TRAIT_AUTONOMY_CHILDHOOD_PHASE_REBELLIOUS: 'CommonStatisticId' = 165366 - TRAIT_AUTONOMY_CHILDISH: 'CommonStatisticId' = 29125 - TRAIT_AUTONOMY_CREATIVE: 'CommonStatisticId' = 28630 - TRAIT_AUTONOMY_DANCE_MACHINE: 'CommonStatisticId' = 126090 - TRAIT_AUTONOMY_EMOTIONAL_CONTROL: 'CommonStatisticId' = 160277 - TRAIT_AUTONOMY_EVIL: 'CommonStatisticId' = 29117 - TRAIT_AUTONOMY_FAMILY_ORIENTED: 'CommonStatisticId' = 29118 - TRAIT_AUTONOMY_FOODIE: 'CommonStatisticId' = 29084 - TRAIT_AUTONOMY_GEEK: 'CommonStatisticId' = 29107 - TRAIT_AUTONOMY_GENIUS: 'CommonStatisticId' = 29109 - TRAIT_AUTONOMY_GHOST: 'CommonStatisticId' = 115027 - TRAIT_AUTONOMY_GHOST_FROZEN: 'CommonStatisticId' = 187684 - TRAIT_AUTONOMY_GHOST_OVERHEAT: 'CommonStatisticId' = 187685 - TRAIT_AUTONOMY_GLUTTON: 'CommonStatisticId' = 29120 - TRAIT_AUTONOMY_GOOD: 'CommonStatisticId' = 29121 - TRAIT_AUTONOMY_GOOFBALL: 'CommonStatisticId' = 29110 - TRAIT_AUTONOMY_HATES_CHILDREN: 'CommonStatisticId' = 29129 - TRAIT_AUTONOMY_HOT_HEADED: 'CommonStatisticId' = 29104 - TRAIT_AUTONOMY_INSANE: 'CommonStatisticId' = 76587 - TRAIT_AUTONOMY_INSIDER: 'CommonStatisticId' = 125438 - TRAIT_AUTONOMY_JEALOUS: 'CommonStatisticId' = 124989 - TRAIT_AUTONOMY_KLEPTOMANIAC: 'CommonStatisticId' = 131787 - TRAIT_AUTONOMY_LAZY: 'CommonStatisticId' = 29111 - TRAIT_AUTONOMY_LIFE_SKILLS_BAD_MANNERS: 'CommonStatisticId' = 160850 - TRAIT_AUTONOMY_LONER: 'CommonStatisticId' = 77332 - TRAIT_AUTONOMY_LOVES_OUTDOORS: 'CommonStatisticId' = 77338 - TRAIT_AUTONOMY_MATERIALISTIC: 'CommonStatisticId' = 29153 - TRAIT_AUTONOMY_MEAN: 'CommonStatisticId' = 29112 - TRAIT_AUTONOMY_MUSIC_LOVER: 'CommonStatisticId' = 29113 - TRAIT_AUTONOMY_NEAT: 'CommonStatisticId' = 29114 - TRAIT_AUTONOMY_PARANOID: 'CommonStatisticId' = 203546 - TRAIT_AUTONOMY_ROMANTIC: 'CommonStatisticId' = 29106 - TRAIT_AUTONOMY_SELF_ABSORBED: 'CommonStatisticId' = 199605 - TRAIT_AUTONOMY_SLOB: 'CommonStatisticId' = 29123 - TRAIT_AUTONOMY_SNOB: 'CommonStatisticId' = 29151 - TRAIT_AUTONOMY_UNCONTROLLED_EMOTION: 'CommonStatisticId' = 160267 - TRAIT_AUTONOMY_WEATHER_PREFERENCE_LOVES_RAIN: 'CommonStatisticId' = 189201 - TRAIT_AUTONOMY_WEATHER_PREFERENCE_LOVES_SNOW: 'CommonStatisticId' = 189231 - TRAIT_BRO_BROXIMITY: 'CommonStatisticId' = 74073 - TRAIT_CAT_LOVER_NEAR_CATS: 'CommonStatisticId' = 158004 - TRAIT_COMMITMENT_ISSUES_CAREER_COMMITMENT: 'CommonStatisticId' = 37524 - TRAIT_COMMITMENT_ISSUES_RELATIONSHIP_COMMITMENT: 'CommonStatisticId' = 31262 - TRAIT_CREATIVE_CREATIVITY: 'CommonStatisticId' = 27162 - TRAIT_CREATIVE_TENSE_TIMER: 'CommonStatisticId' = 99719 - TRAIT_DANCE_MACHINE_DANCE_NEED: 'CommonStatisticId' = 126188 - TRAIT_DOG_LOVER_NEAR_DOGS: 'CommonStatisticId' = 158005 - TRAIT_EVIL_MISERY_NEARBY: 'CommonStatisticId' = 74224 - TRAIT_FAMILY_ORIENTED_FAMILY_TIME: 'CommonStatisticId' = 30687 - TRAIT_FAMILY_ORIENTED_MISSING_FAMILY_SAD_TIMER: 'CommonStatisticId' = 99795 - TRAIT_FAMILY_ORIENTED_NEAR_FAMILY: 'CommonStatisticId' = 74225 - TRAIT_FAMILY_ORIENTED_NEAR_FAMILY_HAPPY_TIMER: 'CommonStatisticId' = 99814 - TRAIT_FORTUNE_INVESTED_INTEREST_CHECK_TIMER: 'CommonStatisticId' = 27949 - TRAIT_GEEK_ALIEN_TV: 'CommonStatisticId' = 107152 - TRAIT_GEEK_GAMING_NEED: 'CommonStatisticId' = 27550 - TRAIT_GEEK_GAMING_NEED_BUFF_DECAY: 'CommonStatisticId' = 98070 - TRAIT_GEEK_GEEK_OUT: 'CommonStatisticId' = 39000 - TRAIT_GENIUS_MENTAL_STIMULATION: 'CommonStatisticId' = 28786 - TRAIT_GOOD_NEAR_POSITIVITY: 'CommonStatisticId' = 74226 - TRAIT_HATES_CHILDREN_NEAR_CHILDREN: 'CommonStatisticId' = 74227 - TRAIT_HATES_CHILDREN_NEAR_TODDLERS: 'CommonStatisticId' = 157196 - TRAIT_INSANE_INSANITY: 'CommonStatisticId' = 29131 - TRAIT_JEALOUS_MISSING_SO_SAD_TIMER: 'CommonStatisticId' = 124917 - TRAIT_JEALOUS_NEAR_SO: 'CommonStatisticId' = 124881 - TRAIT_JEALOUS_NEAR_SO_HAPPY_TIMER: 'CommonStatisticId' = 124918 - TRAIT_JEALOUS_SO_TIME: 'CommonStatisticId' = 124957 - TRAIT_KLEPTOMANIAC_NEED_TO_SWIPE: 'CommonStatisticId' = 132222 - TRAIT_LAZY_TV: 'CommonStatisticId' = 103226 - TRAIT_LONER_NEAR_LOW_RELATIONS: 'CommonStatisticId' = 74228 - TRAIT_LONER_SOLITUDE: 'CommonStatisticId' = 29122 - TRAIT_LOVES_THE_OUTDOORS: 'CommonStatisticId' = 29152 - TRAIT_LOVES_THE_OUTDOORS_AM_I_OUTSIDE: 'CommonStatisticId' = 75462 - TRAIT_LOVES_THE_OUTDOORS_TENSE_TIMER: 'CommonStatisticId' = 98963 - TRAIT_MATERIALISTIC_ADMIRE_NEED: 'CommonStatisticId' = 35959 - TRAIT_MATERIALISTIC_ADMIRE_OBJECT: 'CommonStatisticId' = 98882 - TRAIT_MORNING_PERSON_CHECK_ACTIVE: 'CommonStatisticId' = 97676 - TRAIT_MUSIC_LOVER_INSPIRED_BY_MUSIC: 'CommonStatisticId' = 74243 - TRAIT_MUSIC_LOVER_INSPIRED_PLAY: 'CommonStatisticId' = 74104 - TRAIT_MUSIC_LOVER_MUSIC_NEED: 'CommonStatisticId' = 29314 - TRAIT_NIGHT_OWL_CHECK_ACTIVE: 'CommonStatisticId' = 97703 - TRAIT_OCCULT_ALIEN_BRAIN_POWER: 'CommonStatisticId' = 103330 - TRAIT_PET_ACTIVE: 'CommonStatisticId' = 158207 - TRAIT_PET_AGGRESSIVE: 'CommonStatisticId' = 158810 - TRAIT_PET_CURIOUS: 'CommonStatisticId' = 158216 - TRAIT_PET_FRIENDLY: 'CommonStatisticId' = 158806 - TRAIT_PET_GLUTTON: 'CommonStatisticId' = 159988 - TRAIT_PET_HAIRY: 'CommonStatisticId' = 158814 - TRAIT_PET_HUNTER: 'CommonStatisticId' = 159986 - TRAIT_PET_INDEPENDENT: 'CommonStatisticId' = 158812 - TRAIT_PET_LAZY: 'CommonStatisticId' = 158208 - TRAIT_PET_NAUGHTY: 'CommonStatisticId' = 159987 - TRAIT_PET_PLAYFUL: 'CommonStatisticId' = 164048 - TRAIT_PET_PROTECTIVE: 'CommonStatisticId' = 158822 - TRAIT_PET_QUIRK_FEAR_COFFEE_MAKER: 'CommonStatisticId' = 161771 - TRAIT_PET_QUIRK_FEAR_COMPUTER: 'CommonStatisticId' = 161772 - TRAIT_PET_QUIRK_FEAR_COOKING: 'CommonStatisticId' = 161773 - TRAIT_PET_QUIRK_FEAR_DISHWASHER: 'CommonStatisticId' = 161774 - TRAIT_PET_QUIRK_FEAR_FIRE: 'CommonStatisticId' = 161776 - TRAIT_PET_QUIRK_FEAR_FITNESS_EQUIPMENT: 'CommonStatisticId' = 161778 - TRAIT_PET_QUIRK_FEAR_GAMING: 'CommonStatisticId' = 161780 - TRAIT_PET_QUIRK_FEAR_INSTRUMENT: 'CommonStatisticId' = 161781 - TRAIT_PET_QUIRK_FEAR_MICROWAVE: 'CommonStatisticId' = 161782 - TRAIT_PET_QUIRK_FEAR_ROBOT_VACUUM: 'CommonStatisticId' = 171322 - TRAIT_PET_QUIRK_FEAR_SHOWER: 'CommonStatisticId' = 161783 - TRAIT_PET_QUIRK_FEAR_STEREO: 'CommonStatisticId' = 161784 - TRAIT_PET_QUIRK_FEAR_TOILET: 'CommonStatisticId' = 161785 - TRAIT_PET_QUIRK_FEAR_TV: 'CommonStatisticId' = 161786 - TRAIT_PET_QUIRK_OBSESS_COFFEE_MAKER: 'CommonStatisticId' = 159259 - TRAIT_PET_QUIRK_OBSESS_COMPUTER: 'CommonStatisticId' = 159263 - TRAIT_PET_QUIRK_OBSESS_COOKING: 'CommonStatisticId' = 159253 - TRAIT_PET_QUIRK_OBSESS_DISHWASHER: 'CommonStatisticId' = 159255 - TRAIT_PET_QUIRK_OBSESS_DOORBELL: 'CommonStatisticId' = 160803 - TRAIT_PET_QUIRK_OBSESS_FIRE: 'CommonStatisticId' = 159256 - TRAIT_PET_QUIRK_OBSESS_FISH_TANK: 'CommonStatisticId' = 159261 - TRAIT_PET_QUIRK_OBSESS_FITNESS_EQUIPMENT: 'CommonStatisticId' = 159258 - TRAIT_PET_QUIRK_OBSESS_FRIDGE: 'CommonStatisticId' = 159266 - TRAIT_PET_QUIRK_OBSESS_GAMING: 'CommonStatisticId' = 159260 - TRAIT_PET_QUIRK_OBSESS_INSTRUMENT: 'CommonStatisticId' = 159254 - TRAIT_PET_QUIRK_OBSESS_MICROWAVE: 'CommonStatisticId' = 159257 - TRAIT_PET_QUIRK_OBSESS_PET_MINOR_CAGE: 'CommonStatisticId' = 184412 - TRAIT_PET_QUIRK_OBSESS_ROBOT_VACUUM: 'CommonStatisticId' = 171321 - TRAIT_PET_QUIRK_OBSESS_SHOWER: 'CommonStatisticId' = 159265 - TRAIT_PET_QUIRK_OBSESS_STEREO: 'CommonStatisticId' = 159252 - TRAIT_PET_QUIRK_OBSESS_SWIMMING: 'CommonStatisticId' = 171913 - TRAIT_PET_QUIRK_OBSESS_TOILET: 'CommonStatisticId' = 159264 - TRAIT_PET_QUIRK_OBSESS_TV: 'CommonStatisticId' = 158819 - TRAIT_PET_SKITTISH: 'CommonStatisticId' = 158808 - TRAIT_PET_SMART: 'CommonStatisticId' = 158811 - TRAIT_PET_STUBBORN: 'CommonStatisticId' = 158217 - TRAIT_PET_VOCAL: 'CommonStatisticId' = 158809 - TRAIT_PET_WANDERLUST: 'CommonStatisticId' = 158709 - TRAIT_PLANT_SIM_EAT_TIMER: 'CommonStatisticId' = 162818 - TRAIT_PLANT_SIM_TIMER: 'CommonStatisticId' = 164593 - TRAIT_ROMANTIC_AFFECTION: 'CommonStatisticId' = 27519 - TRAIT_SELF_ABSORBED_OUT_OF_SPOTLIGHT_TIMER: 'CommonStatisticId' = 199573 - TRAIT_SNOB_NEAR_SNOBS: 'CommonStatisticId' = 74229 - TRAIT_THE_KNACK_UPGRADE_TIMER: 'CommonStatisticId' = 99841 - TRAIT_TODDLER_ANGELIC_RANDOMLY_GETS_HAPPY: 'CommonStatisticId' = 143246 - TRAIT_TODDLER_AUTONOMY_ANGELIC: 'CommonStatisticId' = 143221 - TRAIT_TODDLER_AUTONOMY_CHARMER: 'CommonStatisticId' = 143230 - TRAIT_TODDLER_AUTONOMY_CLINGY: 'CommonStatisticId' = 143223 - TRAIT_TODDLER_AUTONOMY_FUSSY: 'CommonStatisticId' = 143231 - TRAIT_TODDLER_AUTONOMY_INDEPENDENT: 'CommonStatisticId' = 143232 - TRAIT_TODDLER_AUTONOMY_INQUISITIVE: 'CommonStatisticId' = 143233 - TRAIT_TODDLER_AUTONOMY_SILLY: 'CommonStatisticId' = 143234 - TRAIT_TODDLER_AUTONOMY_WILD: 'CommonStatisticId' = 143235 - TRAIT_TODDLER_CHARMER_NO_SOCIALIZATION_SADNESS: 'CommonStatisticId' = 143261 - TRAIT_TODDLER_CLINGY_NO_PARENTS_SADNESS: 'CommonStatisticId' = 143345 - TRAIT_TODDLER_INDEPENDENT_NO_PARENTS_HAPPINESS: 'CommonStatisticId' = 143344 - TRAIT_TODDLER_INQUISITIVE_NO_THINKING_SADNESS: 'CommonStatisticId' = 143342 - TRAIT_TODDLER_SILLY_RANDOMLY_GETS_PLAYFUL: 'CommonStatisticId' = 143288 - TRAIT_TODDLER_WILD_RANDOMLY_GETS_ENERGY: 'CommonStatisticId' = 143294 - TURNS: 'CommonStatisticId' = 16726 - TV_CHANNEL_SURF_COOLDOWN: 'CommonStatisticId' = 130211 - UMBRELLA_BREAK: 'CommonStatisticId' = 186447 - VAMPIRE_SUN_EXPOSURE: 'CommonStatisticId' = 151449 - VAULT_WALK_IN_SAFE_SIMOLEONS: 'CommonStatisticId' = 193396 - VET_STRESS_FAILS_CUMULATIVE: 'CommonStatisticId' = 178675 - VET_TREATMENT_DISCOVERY: 'CommonStatisticId' = 158913 - VET_TREATMENT_PREVENT_STRESS: 'CommonStatisticId' = 177681 - VET_TREATMENT_STRESS: 'CommonStatisticId' = 158956 - VET_TREATMENT_STRESS_CUMULATIVE: 'CommonStatisticId' = 168206 - VIDEO_GAME_CONSOLE_NUMBER_OF_PLAYERS: 'CommonStatisticId' = 152671 - VIDEO_GAMING_SKILL_GAMED_OUT: 'CommonStatisticId' = 31760 - VIDEO_GAMING_SKILL_GOOD_SESSION: 'CommonStatisticId' = 38981 - WALK_DOG_WAIT_AROUND: 'CommonStatisticId' = 173999 - WATCH_CAT: 'CommonStatisticId' = 166989 - WATCH_DOG: 'CommonStatisticId' = 166994 - WEDDING_PROGRESS: 'CommonStatisticId' = 16643 - WOODWORK_FURNITURE: 'CommonStatisticId' = 16644 - WOODWORK_FURNITURE_CURVED: 'CommonStatisticId' = 16645 - WOODWORK_MUSIC: 'CommonStatisticId' = 16646 - WOODWORK_SCULPTURE_LARGE: 'CommonStatisticId' = 16647 - WOODWORK_SCULPTURE_SMALL: 'CommonStatisticId' = 16648 - WOOHOO_ENERGY: 'CommonStatisticId' = 16649 - WRITING_SKILL_LITERARY_DIGEST: 'CommonStatisticId' = 35340 diff --git a/Scripts/s4ap/sims4communitylib/enums/strings_enum.py b/Scripts/s4ap/sims4communitylib/enums/strings_enum.py deleted file mode 100644 index ec01668..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/strings_enum.py +++ /dev/null @@ -1,269 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonStringId(CommonInt): - """Identifiers for localization strings. - - .. note:: These identifiers point to strings within String Tables within package files. - - """ - INVALID: 'CommonStringId' = 0 - # Notifications - EXCEPTION_OCCURRED_TITLE: 'CommonStringId' = 3506527463 - EXCEPTION_OCCURRED_TITLE_FOR_MOD: 'CommonStringId' = 1541569535 - # 0.String - EXCEPTION_OCCURRED_TEXT: 'CommonStringId' = 1656389837 - - # Dialog - OK: 'CommonStringId' = 3648501874 - OK_ALL_CAPS: 'CommonStringId' = 1102906806 - CANCEL: 'CommonStringId' = 3497542682 - CANCEL_ALL_CAPS: 'CommonStringId' = 1249800636 - - # Navigation - NEXT: 'CommonStringId' = 982796106 - PREVIOUS: 'CommonStringId' = 4210670582 - # Tokens: {0.String} - GO_TO_STRING: 'CommonStringId' = 3934117375 - - # Text - # Tokens: {0.String} - TEXT_WITH_GREEN_COLOR: 'CommonStringId' = 3458194999 - # Tokens: {0.String} - TEXT_WITH_RED_COLOR: 'CommonStringId' = 835489330 - # Tokens: {0.String} - TEXT_WITH_BLUE_COLOR: 'CommonStringId' = 1505840180 - # Tokens: {0.String} - TEXT_WITH_YELLOW_COLOR: 'CommonStringId' = 3457894271 - # Tokens: {0.String} - TEXT_WITH_ORANGE_COLOR: 'CommonStringId' = 2567694686 - - # Ages - BABY: 'CommonStringId' = 4016862175 - INFANT: 'CommonStringId' = 0xD0D04D65 - TODDLER: 'CommonStringId' = 3252370736 - CHILD: 'CommonStringId' = 2993678259 - TEEN: 'CommonStringId' = 1166433319 - YOUNG_ADULT: 'CommonStringId' = 2053658442 - ADULT: 'CommonStringId' = 1747466136 - ELDER: 'CommonStringId' = 685867388 - - # Gender - MALE: 'CommonStringId' = 434606820 - FEMALE: 'CommonStringId' = 2933657479 - - # Species - HUMAN: 'CommonStringId' = 3519680994 - SMALL_DOG: 'CommonStringId' = 698804483 - LARGE_DOG: 'CommonStringId' = 1545624565 - CAT: 'CommonStringId' = 1720023562 - FOX: 'CommonStringId' = 0xCE739947 - HORSE: 'CommonStringId' = 0x773BB19E - - S4CL_ALIEN: 'CommonStringId' = 0x340EA312 - S4CL_GHOST: 'CommonStringId' = 0xEFCD14BE - S4CL_MERMAID: 'CommonStringId' = 0x9E3A9746 - S4CL_NON_OCCULT: 'CommonStringId' = 0x2763B1A0 - S4CL_PLANT_SIM: 'CommonStringId' = 0x64E66FA1 - S4CL_ROBOT: 'CommonStringId' = 0x730D2277 - S4CL_SCARECROW: 'CommonStringId' = 0x3AFF1B32 - S4CL_SKELETON: 'CommonStringId' = 0xCF5256A8 - S4CL_VAMPIRE: 'CommonStringId' = 0x760EC7C9 - S4CL_WEREWOLF: 'CommonStringId' = 0xA3E400E6 - S4CL_WITCH: 'CommonStringId' = 0x2D55956A - S4CL_HOUSEHOLD: 'CommonStringId' = 0x846D3A8C - S4CL_HOUSEHOLD_DESCRIPTION: 'CommonStringId' = 0xC04E5A9E - S4CL_NON_HOUSEHOLD: 'CommonStringId' = 0xC3AAF6A2 - S4CL_NON_HOUSEHOLD_DESCRIPTION: 'CommonStringId' = 0xC07E9015 - S4CL_CURRENTLY_CONTROLLED: 'CommonStringId' = 0x0EF5C39D - S4CL_CURRENTLY_CONTROLLED_DESCRIPTION: 'CommonStringId' = 0xBF7B9D74 - - # Pregnancy - GET_PREGNANT: 'CommonStringId' = 3694037554 - GET_OTHER_PREGNANT: 'CommonStringId' = 3780444441 - CANNOT_EDIT_PREGNANT_SIMS: 'CommonStringId' = 1715308569 - PREGNANT_OUTCOME: 'CommonStringId' = 3717297329 - - # Gender Options - TOILET_USE_STANDING: 'CommonStringId' = 3730566822 - TOILET_USE_SITTING: 'CommonStringId' = 4265081704 - SEXUAL_ORIENTATION: 'CommonStringId' = 0xB4F0EDC8 - THIS_SIM_IS_ROMANTICALLY_ATTRACTED_TO: 'CommonStringId' = 0xF808D0AB - THIS_SIM_IS_EXPLORING_ROMANTICALLY: 'CommonStringId' = 0x52609912 - THIS_SIM_IS_INTERESTED_IN_WOOHOO_WITH: 'CommonStringId' = 0x4790F2DC - - # Misc Text - CUSTOM_GENDER_SETTINGS: 'CommonStringId' = 2156245727 - CLOTHING_PREFERENCE: 'CommonStringId' = 611620004 - MASCULINE: 'CommonStringId' = 585998164 - FEMININE: 'CommonStringId' = 667254132 - PHYSICAL_FRAME: 'CommonStringId' = 2574825855 - ZERO_THROUGH_NINE = 0x8FE40C44 - - # Store - THIS_REWARD_IS_NOT_AVAILABLE_FOR_YOUR_SIM_OR_IT_IS_ALREADY_OWNED_BY_YOUR_SIM = 0x0709B9CC - INSUFFICIENT_POINTS = 0x67D91493 - - # Text - # Tokens: {0.String} - STRING_NOT_FOUND_WITH_IDENTIFIER: 'CommonStringId' = 3037244137 - - # Test - TESTING_TEST_BUTTON_ONE: 'CommonStringId' = 367590350 - TESTING_TEST_BUTTON_TWO: 'CommonStringId' = 367590349 - TESTING_SOME_TEXT_FOR_TESTING: 'CommonStringId' = 1352970207 - TESTING_TEST_TEXT_NO_TOKENS: 'CommonStringId' = 3987872118 - # Tokens: {0.SimFirstName} {0.SimLastName} - TESTING_TEST_TEXT_WITH_SIM_FIRST_AND_LAST_NAME: 'CommonStringId' = 4280406738 - # Tokens: {0.String} - TESTING_TEST_TEXT_WITH_STRING_TOKEN: 'CommonStringId' = 2977195159 - # Tokens: {0.Number} - TESTING_TEST_TEXT_WITH_NUMBER_TOKEN: 'CommonStringId' = 4138001347 - - # S4CL - S4CL_SIMS_4_COMMUNITY_LIBRARY: 'CommonStringId' = 1638558923 - S4CL_LOG_ALL_INTERACTIONS: 'CommonStringId' = 3133049591 - # Tokens: {0.String} - S4CL_DONE_LOGGING_ALL_INTERACTIONS: 'CommonStringId' = 207690817 - - # Sim Actions. - S4CL_OBJECT_IS_IN_USE = 0x7EC77EF6 - # Tokens: {0.SimFirstName} - S4CL_SIM_NOT_ALLOWED_THERE = 0x48245F2A - # Tokens: {0.SimFirstName} - S4CL_SIM_CANNOT_REACH_THAT_SPOT = 0x6B324A52 - # Tokens: {0.SimFirstName} {1.SimFirstName} - S4CL_SIM_CANNOT_REACH_SIM = 0x6B324A52 - # Tokens: {0.SimFirstName} - S4CL_NOT_ENOUGH_ROOM_FOR_SIM_HERE = 0x36EB7A72 - # Tokens: {0.SimFirstName} - S4CL_SIM_IS_NOT_PREGNANT: 'CommonStringId' = 0x4992E851 - # Tokens: {0.SimFirstName} {0.SimLastName} (Sim) - S4CL_SIM_CANNOT_BE_PICKED_UP = 0xAB3DD412 - - # Tokens: {0.SimFirstName} - S4CL_SIM_ALREADY_HAS_THIS_TRAIT = 0x854F2F29 - # Tokens: {0.SimFirstName} - S4CL_SIM_DOES_NOT_HAVE_THIS_TRAIT = 0x663E6FD7 - - S4CL_YES: 'CommonStringId' = 0x3A6189A6 - S4CL_NO: 'CommonStringId' = 0x6377188C - S4CL_RANDOM: 'CommonStringId' = 0xB5ADADF0 - S4CL_CONFIRMATION: 'CommonStringId' = 0x963ACF86 - S4CL_GO_BACK = 0xD74B6B28 - S4CL_NONE = 0x2CA33BDB - S4CL_NO_SIMS = 0x90F0B600 - S4CL_NO_OPTIONS_WILL_BE_INCLUDED = 0xF3E7F3A3 - S4CL_ALL = 0x419C2C6E - S4CL_ALL_SIMS = 0x6B670346 - S4CL_ALL_OPTIONS_WILL_BE_INCLUDED = 0x36CAAB74 - S4CL_ANY = 0x3F9C28A5 - S4CL_DECLINED = 0x5FD633CB - S4CL_ACCEPTED = 0xB667ABF6 - S4CL_ACCEPT = 0xD0F420D1 - S4CL_DECLINE = 0xA60FC6F5 - S4CL_DEFAULT = 0x2EA8FB98 - S4CL_REMOVE_ALL = 0x5C6C2580 - S4CL_REMOVE = 0x8B3681B1 - S4CL_NOT_IMPLEMENTED = 0x54860E10 - S4CL_CUSTOM_BREED = 0x599432EA - - # Species - S4CL_DOG: 'CommonStringId' = 0x20953C2D - - # Separators - # {0.String}{1.String} - S4CL_COMBINE_TWO_STRINGS: 'CommonStringId' = 4217460952 - # Tokens: {0.String}: {1.String} - STRING_COLON_SPACE_STRING = 0x6284ACBA - # Tokens: {0.String}, {1.String} - STRING_COMMA_SPACE_STRING = 0x1429B07C - # Tokens: {0.String} {1.String} - STRING_SPACE_STRING = 0x0699D5F4 - # Tokens: {0.String} ({1.String}) - STRING_SPACE_PARENTHESIS_SURROUNDED_STRING = 0x1A406429 - # Tokens: {0.String}\n{1.String} - STRING_NEWLINE_STRING = 0xCE1E042E - # Tokens: {0.String}\n\n{1.String} - STRING_NEWLINE_NEWLINE_STRING = 0xBA331D00 - # Tokens: {0.String}-{1.String} - STRING_HYPHEN_STRING = 0x032A81F9 - # Tokens: {0.String} are {1.String} - S4CL_STRING_ARE_STRING = 0x92AF2862 - # Tokens: {0.String} is {1.String} - S4CL_STRING_IS_STRING = 0xC1166AC4 - # Tokens: {0.String}+{1.String} - S4CL_STRING_PLUS_STRING = 0x82ED46EB - # Tokens: {0.String} or {1.String} - S4CL_STRING_OR_STRING = 0x1DC61DF5 - # Tokens: {0.String}, or {1.String} - S4CL_STRING_COMMA_SPACE_OR_STRING = 0x34E0269D - # Tokens: {0.String} and {1.String} - S4CL_STRING_AND_STRING = 0xCFB35A51 - # Tokens: {0.String}, and {1.String} - S4CL_STRING_COMMA_SPACE_AND_STRING = 0x419E6969 - - # String Modifiers - # Tokens: ({0.String}) - S4CL_PARENTHESIS_SURROUNDED_STRING = 0xD7FDCAF5 - - S4CL_PLEASE_WAIT = 0xF2237D1E - S4CL_RANDOMIZATION_COMPLETE = 0x8ABA94C5 - - S4CL_PREGNANCY = 0x3F70BCAA - - S4CL_RESTART_REQUIRED = 0x955D0179 - S4CL_CHANGES_MADE_RESTART_REQUIRED_DESCRIPTION = 0x6B5119FB - # (From Debug) - S4CL_BUFF_REASON_FROM_DEBUG = 0x38C2E6F7 - - # Purchase - S4CL_PURCHASE_SUCCESSFUL = 0xF3C59252 - S4CL_YOUR_PURCHASED_ITEMS_ARE_ON_THE_WAY = 0x5A8D580D - S4CL_YOUR_PURCHASED_ITEMS_ARE_IN_YOUR_INVENTORY = 0xF33F9A95 - S4CL_TOO_EXPENSIVE = 0x59F9C698 - - S4CL_THIS_FEATURE_IS_NOT_YET_IMPLEMENTED = 0x556801EE - - # Sim Name - # Tokens: {0.SimFirstName} {0.SimLastName} (Sim One) - S4CL_SIM_NAME = 0xAC8F626F - # Tokens: {0.SimFirstName} {0.SimLastName} (Sim One) {1.SimFirstName} {1.SimLastName} (Sim Two) - S4CL_SIM_NAME_AND_SIM_NAME = 0xD8740FE4 - # Tokens: {0.String} (A String) {1.SimFirstName} {1.SimLastName} (The Last Sim) - S4CL_STRING_COMMA_SPACE_AND_SIM_NAME = 0x2EACE203 - # Tokens: {0.SimFirstName} {0.SimLastName} (The First Sim) {1.String} (A String) - S4CL_SIM_NAME_COMMA_SPACE_AND_STRING = 0x2A8148D8 - - # Tokens: {0.String} - S4CL_UID_STRING = 0x0313D2A0 - # Tokens: {0.String} (Current) - S4CL_CURRENT_STRING = 0x860F13B5 - # Tokens: {0.String} (Count) - S4CL_COUNT_STRING = 0x423122EB - # Tokens: {0.String} (Error Message) - S4CL_ERROR_STRING = 0xA1C925BC - # Tokens: {0.String} (Failed Message) - S4CL_FAILED_STRING = 0x0F818D6F - # Tokens: {0.String} (Failure Message) - S4CL_FAILURE_STRING = 0x33A94544 - # Tokens: {0.String} (Success Message) - S4CL_SUCCESS_STRING = 0xC6D15497 - # Tokens: {0.String} (String Message) - S4CL_EXCLAMATION_EXCLAMATION_STRING = 0xA07FA6C6 - - S4CL_LEFT = 0x003EB432 - S4CL_RIGHT = 0xE816F049 - S4CL_FRONT = 0x4B21A032 - S4CL_BACK = 0x5CF9CF48 - S4CL_TOP = 0x406CCC4A - S4CL_BOTTOM = 0xE864BA60 - S4CL_UP = 0x5C770DAE - S4CL_DOWN = 0x87EDD469 diff --git a/Scripts/s4ap/sims4communitylib/enums/tags_enum.py b/Scripts/s4ap/sims4communitylib/enums/tags_enum.py deleted file mode 100644 index 75a03bb..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/tags_enum.py +++ /dev/null @@ -1,4867 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -# noinspection SpellCheckingInspection -class CommonGameTag(CommonInt): - """Identifiers for vanilla game tags (These have been gathered dynamically from the :class:`.Tag` enum). - - """ - INVALID: 'CommonGameTag' = 0 - ACNE_LEVEL_HEAVY: 'CommonGameTag' = 114722 - ACNE_LEVEL_LIGHT: 'CommonGameTag' = 114724 - ACNE_LEVEL_MEDIUM: 'CommonGameTag' = 114723 - ACNE_LEVEL_NONE: 'CommonGameTag' = 114732 - AGE_APPROPRIATE_ADULT: 'CommonGameTag' = 84 - AGE_APPROPRIATE_CHILD: 'CommonGameTag' = 85 - AGE_APPROPRIATE_ELDER: 'CommonGameTag' = 72 - AGE_APPROPRIATE_INFANT: 'CommonGameTag' = 2912 - AGE_APPROPRIATE_TEEN: 'CommonGameTag' = 291 - AGE_APPROPRIATE_TODDLER: 'CommonGameTag' = 1657 - AGE_APPROPRIATE_YOUNG_ADULT: 'CommonGameTag' = 71 - APPEARANCE_MODIFIER_HAIR_MAKEUP_CHAIR_HAIR_STYLE: 'CommonGameTag' = 61494 - APPEARANCE_MODIFIER_HAIR_MAKEUP_CHAIR_MAKEUP: 'CommonGameTag' = 61609 - APPROPRIATENESS_BARTENDING: 'CommonGameTag' = 406 - APPROPRIATENESS_BATHING: 'CommonGameTag' = 402 - APPROPRIATENESS_CAKE: 'CommonGameTag' = 605 - APPROPRIATENESS_CALL_TO_MEAL: 'CommonGameTag' = 1170 - APPROPRIATENESS_CLEANING: 'CommonGameTag' = 404 - APPROPRIATENESS_COMPUTER: 'CommonGameTag' = 1373 - APPROPRIATENESS_COOKING: 'CommonGameTag' = 405 - APPROPRIATENESS_DANCING: 'CommonGameTag' = 603 - APPROPRIATENESS_DESK_CLEAN: 'CommonGameTag' = 2838 - APPROPRIATENESS_EATING: 'CommonGameTag' = 604 - APPROPRIATENESS_FRONT_DESK: 'CommonGameTag' = 12413 - APPROPRIATENESS_GRAB_SNACK: 'CommonGameTag' = 939 - APPROPRIATENESS_GUEST: 'CommonGameTag' = 367 - APPROPRIATENESS_HIRED_WORKER: 'CommonGameTag' = 368 - APPROPRIATENESS_HOST: 'CommonGameTag' = 370 - APPROPRIATENESS_NOT_DURING_WORK: 'CommonGameTag' = 1274 - APPROPRIATENESS_NOT_DURING_WORK_LUNCH: 'CommonGameTag' = 1275 - APPROPRIATENESS_PHONE: 'CommonGameTag' = 1594 - APPROPRIATENESS_PHONE_GAME: 'CommonGameTag' = 1626 - APPROPRIATENESS_PLAYING: 'CommonGameTag' = 1539 - APPROPRIATENESS_PLAY_INSTRUMENT: 'CommonGameTag' = 2156 - APPROPRIATENESS_READ_BOOKS: 'CommonGameTag' = 1276 - APPROPRIATENESS_SERVICE_NPC: 'CommonGameTag' = 369 - APPROPRIATENESS_SHOWER: 'CommonGameTag' = 352 - APPROPRIATENESS_SINGING: 'CommonGameTag' = 55385 - APPROPRIATENESS_SLEEPING: 'CommonGameTag' = 403 - APPROPRIATENESS_SNOW_SHOVELING: 'CommonGameTag' = 69706 - APPROPRIATENESS_SOCIAL_PICKER: 'CommonGameTag' = 1645 - APPROPRIATENESS_STEREO: 'CommonGameTag' = 530 - APPROPRIATENESS_TIP: 'CommonGameTag' = 2155 - APPROPRIATENESS_TOUCHING: 'CommonGameTag' = 1526 - APPROPRIATENESS_TRASH: 'CommonGameTag' = 12423 - APPROPRIATENESS_TV_WATCHING: 'CommonGameTag' = 1273 - APPROPRIATENESS_VIEW: 'CommonGameTag' = 12428 - APPROPRIATENESS_VISITOR: 'CommonGameTag' = 1497 - APPROPRIATENESS_WORKOUT: 'CommonGameTag' = 1277 - APPROPRIATENESS_WORK_SCIENTIST: 'CommonGameTag' = 12297 - ARCHETYPE_AFRICAN: 'CommonGameTag' = 73 - ARCHETYPE_ASIAN: 'CommonGameTag' = 75 - ARCHETYPE_CAUCASIAN: 'CommonGameTag' = 76 - ARCHETYPE_ISLAND: 'CommonGameTag' = 2206 - ARCHETYPE_LATIN: 'CommonGameTag' = 312 - ARCHETYPE_MIDDLE_EASTERN: 'CommonGameTag' = 74 - ARCHETYPE_NATIVE_AMERICAN: 'CommonGameTag' = 2996 - ARCHETYPE_NORTH_AMERICAN: 'CommonGameTag' = 89 - ARCHETYPE_SOUTH_ASIAN: 'CommonGameTag' = 88 - ATTRACTOR_POINT_BEACH: 'CommonGameTag' = 2194 - ATTRACTOR_POINT_BEACH_WALK_BY: 'CommonGameTag' = 2204 - ATTRACTOR_POINT_BLOSSOM_GURU: 'CommonGameTag' = 55386 - ATTRACTOR_POINT_BUSKER: 'CommonGameTag' = 1571 - ATTRACTOR_POINT_DYNAMIC_SPAWN_POINT: 'CommonGameTag' = 1915 - ATTRACTOR_POINT_FIREWORKS: 'CommonGameTag' = 55399 - ATTRACTOR_POINT_FLEA_MARKET_VENDOR: 'CommonGameTag' = 55334 - ATTRACTOR_POINT_GO_FOR_WALK: 'CommonGameTag' = 1916 - ATTRACTOR_POINT_GO_FOR_WALK_LONG: 'CommonGameTag' = 57394 - ATTRACTOR_POINT_GO_FOR_WALK_LONG_02: 'CommonGameTag' = 57432 - ATTRACTOR_POINT_GO_FOR_WALK_LONG_03: 'CommonGameTag' = 57433 - ATTRACTOR_POINT_GO_FOR_WALK_MEDIUM: 'CommonGameTag' = 57393 - ATTRACTOR_POINT_GO_FOR_WALK_MED_02: 'CommonGameTag' = 57436 - ATTRACTOR_POINT_GO_FOR_WALK_MED_03: 'CommonGameTag' = 57437 - ATTRACTOR_POINT_GO_FOR_WALK_SHORT: 'CommonGameTag' = 57389 - ATTRACTOR_POINT_GO_FOR_WALK_SHORT_02: 'CommonGameTag' = 57434 - ATTRACTOR_POINT_GO_FOR_WALK_SHORT_03: 'CommonGameTag' = 57435 - ATTRACTOR_POINT_GUITAR: 'CommonGameTag' = 2158 - ATTRACTOR_POINT_MAGIC_DUELING: 'CommonGameTag' = 2222 - ATTRACTOR_POINT_PROTESTER: 'CommonGameTag' = 1582 - ATTRACTOR_POINT_TOURIST: 'CommonGameTag' = 1570 - ATTRACTOR_POINT_UNIVERSITY_QUAD: 'CommonGameTag' = 2230 - ATTRACTOR_POINT_VILLAGE_SQUARE: 'CommonGameTag' = 2600 - ATTRACTOR_POINT_WOODS_POINT_OF_INTEREST: 'CommonGameTag' = 2599 - BOTTOM_BIKINI: 'CommonGameTag' = 1235 - BOTTOM_CROPPED: 'CommonGameTag' = 945 - BOTTOM_JEANS: 'CommonGameTag' = 382 - BOTTOM_LEGGINGS: 'CommonGameTag' = 381 - BOTTOM_PANTS: 'CommonGameTag' = 152 - BOTTOM_SHORTS: 'CommonGameTag' = 154 - BOTTOM_SKIRT: 'CommonGameTag' = 153 - BOTTOM_SWIMSHORT: 'CommonGameTag' = 1238 - BOTTOM_SWIMWEAR: 'CommonGameTag' = 1544 - BOTTOM_UNDERWEAR: 'CommonGameTag' = 1543 - BOTTOM_UNDERWEAR_FEMALE: 'CommonGameTag' = 946 - BOTTOM_UNDERWEAR_MALE: 'CommonGameTag' = 1040 - BREED_CAT_ABYSSINIAN: 'CommonGameTag' = 1830 - BREED_CAT_AMERICAN_BOBTAIL: 'CommonGameTag' = 1831 - BREED_CAT_AMERICAN_LONGHAIR: 'CommonGameTag' = 1931 - BREED_CAT_AMERICAN_SHORTHAIR: 'CommonGameTag' = 1833 - BREED_CAT_AMERICAN_WIREHAIR: 'CommonGameTag' = 1834 - BREED_CAT_BALINESE: 'CommonGameTag' = 1835 - BREED_CAT_BENGAL: 'CommonGameTag' = 1836 - BREED_CAT_BIRMAN: 'CommonGameTag' = 1837 - BREED_CAT_BLACK_CAT: 'CommonGameTag' = 1838 - BREED_CAT_BOMBAY: 'CommonGameTag' = 1839 - BREED_CAT_BRITISH_LONGHAIR: 'CommonGameTag' = 1840 - BREED_CAT_BRITISH_SHORTHAIR: 'CommonGameTag' = 1841 - BREED_CAT_BURMESE: 'CommonGameTag' = 1842 - BREED_CAT_CALICO: 'CommonGameTag' = 1843 - BREED_CAT_CHARTREUX: 'CommonGameTag' = 1844 - BREED_CAT_COLORPOINT_SHORTHAIR: 'CommonGameTag' = 1845 - BREED_CAT_CORNISH_REX: 'CommonGameTag' = 1832 - BREED_CAT_DEVON_REX: 'CommonGameTag' = 1846 - BREED_CAT_EGYPTIAN_MAU: 'CommonGameTag' = 1847 - BREED_CAT_GERMAN_REX: 'CommonGameTag' = 1848 - BREED_CAT_HAVANA_BROWN: 'CommonGameTag' = 1849 - BREED_CAT_HIMALAYAN: 'CommonGameTag' = 1850 - BREED_CAT_JAPANESE_BOBTAIL: 'CommonGameTag' = 1851 - BREED_CAT_JAVANESE: 'CommonGameTag' = 1852 - BREED_CAT_KORAT: 'CommonGameTag' = 1853 - BREED_CAT_KURILIAN_BOBTAIL: 'CommonGameTag' = 1854 - BREED_CAT_LA_PERM: 'CommonGameTag' = 1855 - BREED_CAT_LYKOI: 'CommonGameTag' = 1975 - BREED_CAT_MAINE_COON: 'CommonGameTag' = 1856 - BREED_CAT_MANX: 'CommonGameTag' = 1857 - BREED_CAT_MIXED: 'CommonGameTag' = 1926 - BREED_CAT_NORWEGIAN_FOREST: 'CommonGameTag' = 1858 - BREED_CAT_OCICAT: 'CommonGameTag' = 1859 - BREED_CAT_ORIENTAL: 'CommonGameTag' = 1860 - BREED_CAT_ORIENTAL_SHORTHAIR: 'CommonGameTag' = 1861 - BREED_CAT_PERSIAN: 'CommonGameTag' = 1862 - BREED_CAT_RACCOON: 'CommonGameTag' = 1974 - BREED_CAT_RAGDOLL: 'CommonGameTag' = 1863 - BREED_CAT_RUSSIAN_BLUE: 'CommonGameTag' = 1864 - BREED_CAT_SAVANNAH: 'CommonGameTag' = 1865 - BREED_CAT_SCOTTISH_FOLD: 'CommonGameTag' = 1866 - BREED_CAT_SHORTHAIR_TABBY: 'CommonGameTag' = 1867 - BREED_CAT_SIAMESE: 'CommonGameTag' = 1868 - BREED_CAT_SIBERIAN: 'CommonGameTag' = 1869 - BREED_CAT_SINGAPURA: 'CommonGameTag' = 1870 - BREED_CAT_SOMALI: 'CommonGameTag' = 1871 - BREED_CAT_SPHYNX: 'CommonGameTag' = 1886 - BREED_CAT_TONKINESE: 'CommonGameTag' = 1872 - BREED_CAT_TURKISH_ANGORA: 'CommonGameTag' = 1873 - BREED_CAT_TUXEDO_CAT: 'CommonGameTag' = 1874 - BREED_FOX_WILD_FOX: 'CommonGameTag' = 112662 - BREED_GROUP_HERDING: 'CommonGameTag' = 1893 - BREED_GROUP_HOUND: 'CommonGameTag' = 1894 - BREED_GROUP_NON_SPORTING: 'CommonGameTag' = 1911 - BREED_GROUP_SPORTING: 'CommonGameTag' = 1895 - BREED_GROUP_TERRIER: 'CommonGameTag' = 1896 - BREED_GROUP_TOY: 'CommonGameTag' = 1897 - BREED_GROUP_WORKING: 'CommonGameTag' = 1898 - BREED_HORSE_AKHAL_TEKE: 'CommonGameTag' = 118866 - BREED_HORSE_AMERICAN_QUARTER_HORSE: 'CommonGameTag' = 118815 - BREED_HORSE_AMERICAN_SADDLEBRED: 'CommonGameTag' = 118816 - BREED_HORSE_AMERICAN_STANDARDBRED: 'CommonGameTag' = 118824 - BREED_HORSE_ANDALUSIAN: 'CommonGameTag' = 118817 - BREED_HORSE_ANGLO_ARABIAN: 'CommonGameTag' = 118818 - BREED_HORSE_APPALOOSA: 'CommonGameTag' = 118819 - BREED_HORSE_ARABIAN: 'CommonGameTag' = 118820 - BREED_HORSE_AUSTRALIAN_STOCK_HORSE: 'CommonGameTag' = 118821 - BREED_HORSE_BARB: 'CommonGameTag' = 118822 - BREED_HORSE_CLYDESDALE: 'CommonGameTag' = 118808 - BREED_HORSE_COLORADO_RANGER: 'CommonGameTag' = 118809 - BREED_HORSE_DUTCH_WARMBLOOD: 'CommonGameTag' = 118810 - BREED_HORSE_FRIESIAN: 'CommonGameTag' = 118823 - BREED_HORSE_GELDERLANDER: 'CommonGameTag' = 118811 - BREED_HORSE_GYPSY_VANNER: 'CommonGameTag' = 118825 - BREED_HORSE_HANOVERIAN: 'CommonGameTag' = 118826 - BREED_HORSE_HOLSTEINER: 'CommonGameTag' = 118827 - BREED_HORSE_IRISH_DRAUGHT: 'CommonGameTag' = 118828 - BREED_HORSE_LIPIZZANER: 'CommonGameTag' = 118829 - BREED_HORSE_LUSITANO: 'CommonGameTag' = 118802 - BREED_HORSE_MISSOURI_FOX_TROTTER: 'CommonGameTag' = 118873 - BREED_HORSE_MIXED: 'CommonGameTag' = 3003 - BREED_HORSE_MORGAN: 'CommonGameTag' = 118796 - BREED_HORSE_MUSTANG: 'CommonGameTag' = 118803 - BREED_HORSE_NEZ_PERCE: 'CommonGameTag' = 118804 - BREED_HORSE_NOKOTA: 'CommonGameTag' = 118805 - BREED_HORSE_PAINT: 'CommonGameTag' = 118867 - BREED_HORSE_PALOMINO: 'CommonGameTag' = 118868 - BREED_HORSE_PERCHERON: 'CommonGameTag' = 118869 - BREED_HORSE_SELLE_FRANCAIS: 'CommonGameTag' = 118870 - BREED_HORSE_SHIRE: 'CommonGameTag' = 118830 - BREED_HORSE_TENNESSEE_WALKER: 'CommonGameTag' = 118832 - BREED_HORSE_THOROUGHBRED: 'CommonGameTag' = 118807 - BREED_HORSE_TRAKEHNER: 'CommonGameTag' = 118831 - BREED_HORSE_WELSH_COB: 'CommonGameTag' = 118806 - BREED_LARGE_DOG_AFGHAN_HOUND: 'CommonGameTag' = 1814 - BREED_LARGE_DOG_AIREDALE_TERRIER: 'CommonGameTag' = 1745 - BREED_LARGE_DOG_AKITA: 'CommonGameTag' = 1746 - BREED_LARGE_DOG_ALASKAN_MALAMUTE: 'CommonGameTag' = 1747 - BREED_LARGE_DOG_AMERICAN_ESKIMO: 'CommonGameTag' = 1748 - BREED_LARGE_DOG_AMERICAN_FOXHOUND: 'CommonGameTag' = 1797 - BREED_LARGE_DOG_AUSTRALIAN_CATTLE_DOG: 'CommonGameTag' = 1750 - BREED_LARGE_DOG_AUSTRALIAN_SHEPHERD: 'CommonGameTag' = 1735 - BREED_LARGE_DOG_BEDLINGTON_TERRIER: 'CommonGameTag' = 1950 - BREED_LARGE_DOG_BERNESE_MOUNTAIN_DOG: 'CommonGameTag' = 1751 - BREED_LARGE_DOG_BLACK_AND_TAN_COONHOUND: 'CommonGameTag' = 1798 - BREED_LARGE_DOG_BLACK_RUSSIAN_TERRIER: 'CommonGameTag' = 1961 - BREED_LARGE_DOG_BLOODHOUND: 'CommonGameTag' = 1753 - BREED_LARGE_DOG_BLUETICK_COONHOUND: 'CommonGameTag' = 1796 - BREED_LARGE_DOG_BORDER_COLLIE: 'CommonGameTag' = 1736 - BREED_LARGE_DOG_BORZOI: 'CommonGameTag' = 1826 - BREED_LARGE_DOG_BOXER: 'CommonGameTag' = 1755 - BREED_LARGE_DOG_BRITTANY: 'CommonGameTag' = 1816 - BREED_LARGE_DOG_BULLMASTIFF: 'CommonGameTag' = 1951 - BREED_LARGE_DOG_CANAAN: 'CommonGameTag' = 1952 - BREED_LARGE_DOG_CHESAPEAKE_BAY_RETRIEVER: 'CommonGameTag' = 1795 - BREED_LARGE_DOG_CHOW_CHOW: 'CommonGameTag' = 1759 - BREED_LARGE_DOG_CHOW_LAB_MIX: 'CommonGameTag' = 1953 - BREED_LARGE_DOG_COLLIE: 'CommonGameTag' = 1740 - BREED_LARGE_DOG_CURLY_COATED_RETRIEVER: 'CommonGameTag' = 1794 - BREED_LARGE_DOG_DALMATIAN: 'CommonGameTag' = 1741 - BREED_LARGE_DOG_DINGO: 'CommonGameTag' = 1954 - BREED_LARGE_DOG_DOBERMAN: 'CommonGameTag' = 1742 - BREED_LARGE_DOG_DOBERMAN_PINSCHER: 'CommonGameTag' = 1761 - BREED_LARGE_DOG_ENGLISH_FOXHOUND: 'CommonGameTag' = 1821 - BREED_LARGE_DOG_ENGLISH_SETTER: 'CommonGameTag' = 1819 - BREED_LARGE_DOG_ENGLISH_SPRINGER_SPANIEL: 'CommonGameTag' = 1762 - BREED_LARGE_DOG_FIELD_SPANIEL: 'CommonGameTag' = 1801 - BREED_LARGE_DOG_GERMAN_POINTER: 'CommonGameTag' = 1737 - BREED_LARGE_DOG_GERMAN_SHEPHERD: 'CommonGameTag' = 1743 - BREED_LARGE_DOG_GIANT_SCHNAUZER: 'CommonGameTag' = 1792 - BREED_LARGE_DOG_GOLDEN_DOODLE: 'CommonGameTag' = 1800 - BREED_LARGE_DOG_GOLDEN_RETRIEVER: 'CommonGameTag' = 1731 - BREED_LARGE_DOG_GREAT_DANE: 'CommonGameTag' = 1734 - BREED_LARGE_DOG_GREAT_PYRANEES: 'CommonGameTag' = 1955 - BREED_LARGE_DOG_GREYHOUND: 'CommonGameTag' = 1764 - BREED_LARGE_DOG_HUSKY: 'CommonGameTag' = 1744 - BREED_LARGE_DOG_IBIZAN: 'CommonGameTag' = 1738 - BREED_LARGE_DOG_IRISH_RED_AND_WHITE_SETTER: 'CommonGameTag' = 1802 - BREED_LARGE_DOG_IRISH_SETTER: 'CommonGameTag' = 1803 - BREED_LARGE_DOG_IRISH_TERRIER: 'CommonGameTag' = 1828 - BREED_LARGE_DOG_IRISH_WOLFHOUND: 'CommonGameTag' = 1827 - BREED_LARGE_DOG_KEESHOND: 'CommonGameTag' = 1767 - BREED_LARGE_DOG_KERRY_BLUE_TERRIER: 'CommonGameTag' = 1956 - BREED_LARGE_DOG_LABRADOODLE: 'CommonGameTag' = 1957 - BREED_LARGE_DOG_LABRADOR_RETRIEVER: 'CommonGameTag' = 1768 - BREED_LARGE_DOG_MASTIFF: 'CommonGameTag' = 1804 - BREED_LARGE_DOG_MIXED: 'CommonGameTag' = 1928 - BREED_LARGE_DOG_NEWFOUNDLAND: 'CommonGameTag' = 1769 - BREED_LARGE_DOG_NORWEGIAN_ELK_SHEPHERD: 'CommonGameTag' = 1958 - BREED_LARGE_DOG_OLD_ENGLISH_SHEEPDOG: 'CommonGameTag' = 1771 - BREED_LARGE_DOG_OTTERHOUND: 'CommonGameTag' = 1772 - BREED_LARGE_DOG_PHARAOH_HOUND: 'CommonGameTag' = 1774 - BREED_LARGE_DOG_PIT_BULL: 'CommonGameTag' = 1749 - BREED_LARGE_DOG_POINTER: 'CommonGameTag' = 1775 - BREED_LARGE_DOG_POLISH_LOWLAND_SHEEPDOG: 'CommonGameTag' = 1807 - BREED_LARGE_DOG_POODLE: 'CommonGameTag' = 1777 - BREED_LARGE_DOG_PORTUGUESE_WATER_DOG: 'CommonGameTag' = 1791 - BREED_LARGE_DOG_REDBONE_COONHOUND: 'CommonGameTag' = 1810 - BREED_LARGE_DOG_RHODESIAN_RIDGEBACK: 'CommonGameTag' = 1815 - BREED_LARGE_DOG_ROTTWEILER: 'CommonGameTag' = 1779 - BREED_LARGE_DOG_SAINT_BERNARD: 'CommonGameTag' = 1780 - BREED_LARGE_DOG_SAMOYED: 'CommonGameTag' = 1781 - BREED_LARGE_DOG_SCHNAUZER: 'CommonGameTag' = 1732 - BREED_LARGE_DOG_SHAR_PEI: 'CommonGameTag' = 1959 - BREED_LARGE_DOG_SIBERIAN_HUSKY: 'CommonGameTag' = 1812 - BREED_LARGE_DOG_TIBETAN_MASTIFF: 'CommonGameTag' = 1960 - BREED_LARGE_DOG_VIZSLA: 'CommonGameTag' = 1809 - BREED_LARGE_DOG_WEIMARANER: 'CommonGameTag' = 1788 - BREED_LARGE_DOG_WELSH_SPRINGER_SPANIEL: 'CommonGameTag' = 1808 - BREED_LARGE_DOG_WHEATENS_TERRIER: 'CommonGameTag' = 1962 - BREED_NONE: 'CommonGameTag' = 1733 - BREED_SMALL_DOG_BASENJI: 'CommonGameTag' = 1817 - BREED_SMALL_DOG_BEAGLE: 'CommonGameTag' = 1739 - BREED_SMALL_DOG_BICHON_FRISE: 'CommonGameTag' = 1752 - BREED_SMALL_DOG_BOCKER: 'CommonGameTag' = 1963 - BREED_SMALL_DOG_BOSTON_TERRIER: 'CommonGameTag' = 1754 - BREED_SMALL_DOG_BULLDOG: 'CommonGameTag' = 1756 - BREED_SMALL_DOG_BULL_TERRIER: 'CommonGameTag' = 1829 - BREED_SMALL_DOG_CARDIGAN_WELSH_CORGI: 'CommonGameTag' = 1964 - BREED_SMALL_DOG_CAVALIER_KING_CHARLES_SPANIEL: 'CommonGameTag' = 1757 - BREED_SMALL_DOG_CHIHUAHUA: 'CommonGameTag' = 1758 - BREED_SMALL_DOG_COCKAPOO: 'CommonGameTag' = 1965 - BREED_SMALL_DOG_COCKER_SPANIEL: 'CommonGameTag' = 1760 - BREED_SMALL_DOG_DASCHUND: 'CommonGameTag' = 1966 - BREED_SMALL_DOG_ENGLISH_COCKER_SPANIEL: 'CommonGameTag' = 1818 - BREED_SMALL_DOG_ENGLISH_TOY_SPANIEL: 'CommonGameTag' = 1967 - BREED_SMALL_DOG_FOX: 'CommonGameTag' = 1968 - BREED_SMALL_DOG_FRENCH_BULLDOG: 'CommonGameTag' = 1763 - BREED_SMALL_DOG_HAVANESE: 'CommonGameTag' = 1793 - BREED_SMALL_DOG_ICELANDIC_SHEEP_DOG: 'CommonGameTag' = 1993 - BREED_SMALL_DOG_ITALIAN_GREYHOUND: 'CommonGameTag' = 1825 - BREED_SMALL_DOG_JACK_RUSSEL_TERRIER: 'CommonGameTag' = 1766 - BREED_SMALL_DOG_LHASA_APSO: 'CommonGameTag' = 1823 - BREED_SMALL_DOG_MALTESE: 'CommonGameTag' = 1943 - BREED_SMALL_DOG_MINIATURE_PINSCHER: 'CommonGameTag' = 1805 - BREED_SMALL_DOG_MINIATURE_POODLE: 'CommonGameTag' = 1969 - BREED_SMALL_DOG_MINIATURE_SCHNAUZER: 'CommonGameTag' = 1806 - BREED_SMALL_DOG_MIXED: 'CommonGameTag' = 1927 - BREED_SMALL_DOG_NORWEGIAN_BUHUND: 'CommonGameTag' = 1992 - BREED_SMALL_DOG_PAPILLON: 'CommonGameTag' = 1773 - BREED_SMALL_DOG_PARSON_RUSSEL_TERRIER: 'CommonGameTag' = 1970 - BREED_SMALL_DOG_PEKINGESE: 'CommonGameTag' = 1770 - BREED_SMALL_DOG_PEMBROKE_WELSH_CORGI: 'CommonGameTag' = 1971 - BREED_SMALL_DOG_POMERANIAN: 'CommonGameTag' = 1776 - BREED_SMALL_DOG_PUG: 'CommonGameTag' = 1778 - BREED_SMALL_DOG_PUGGLE: 'CommonGameTag' = 1820 - BREED_SMALL_DOG_SCHIPPERKE: 'CommonGameTag' = 1782 - BREED_SMALL_DOG_SCHNOODLE: 'CommonGameTag' = 1972 - BREED_SMALL_DOG_SCOTTISH_TERRIER: 'CommonGameTag' = 1783 - BREED_SMALL_DOG_SHETLAND_SHEEPDOG: 'CommonGameTag' = 1811 - BREED_SMALL_DOG_SHIBA_INU: 'CommonGameTag' = 1784 - BREED_SMALL_DOG_SHIH_TZU: 'CommonGameTag' = 1785 - BREED_SMALL_DOG_SILKY_TERRIER: 'CommonGameTag' = 1973 - BREED_SMALL_DOG_SMOOTH_FOX_TERRIER: 'CommonGameTag' = 1813 - BREED_SMALL_DOG_SPITZ: 'CommonGameTag' = 1991 - BREED_SMALL_DOG_STAFFORDSHIRE_BULL_TERRIER: 'CommonGameTag' = 1824 - BREED_SMALL_DOG_STANDARD_SCHNAUZER: 'CommonGameTag' = 1786 - BREED_SMALL_DOG_TOY_FOX_TERRIER: 'CommonGameTag' = 1787 - BREED_SMALL_DOG_WEST_HIGHLAND_WHITE_TERRIER: 'CommonGameTag' = 1822 - BREED_SMALL_DOG_WHIPPET: 'CommonGameTag' = 1799 - BREED_SMALL_DOG_WIRE_FOX_TERRIER: 'CommonGameTag' = 1789 - BREED_SMALL_DOG_YORKSHIRE_TERRIER: 'CommonGameTag' = 1790 - BUFF_AGGRAVATING_CONVERSATION: 'CommonGameTag' = 2784 - BUFF_APPEARANCE_MODIFIER_MAKEUP: 'CommonGameTag' = 2154 - BUFF_BUSINESS_CUSTOMER_STAR_RATING: 'CommonGameTag' = 1551 - BUFF_BUSINESS_EMPLOYEE_TRAINING: 'CommonGameTag' = 1548 - BUFF_CAULDRON_POTION_MAKE_GLOWY_FAILURE_VFX: 'CommonGameTag' = 49168 - BUFF_DAY_NIGHT_TRACKING: 'CommonGameTag' = 1678 - BUFF_DISLIKE_MUSIC: 'CommonGameTag' = 2791 - BUFF_HUMANOID_ROBOT_MOOD_VFX: 'CommonGameTag' = 65653 - BUFF_MYSTICAL_RELIC_CURSE: 'CommonGameTag' = 45079 - BUFF_NAILS_ALMOND: 'CommonGameTag' = 18473 - BUFF_NAILS_COFFIN: 'CommonGameTag' = 18467 - BUFF_NAILS_COMMUNITY: 'CommonGameTag' = 18481 - BUFF_NAILS_PICKER: 'CommonGameTag' = 18470 - BUFF_NAILS_ROUND: 'CommonGameTag' = 18468 - BUFF_NAILS_SHORT: 'CommonGameTag' = 18480 - BUFF_NAILS_STILETTO: 'CommonGameTag' = 18469 - BUFF_NAILS_VISIBLE: 'CommonGameTag' = 18484 - BUFF_NECTAR_JUICE_MOOD_DRINK_1: 'CommonGameTag' = 2969 - BUFF_NECTAR_JUICE_MOOD_DRINK_2: 'CommonGameTag' = 2970 - BUFF_NECTAR_JUICE_MOOD_DRINK_3: 'CommonGameTag' = 2971 - BUFF_NECTAR_JUICE_MOOD_DRINK_4: 'CommonGameTag' = 2972 - BUFF_OWNABLE_RESTAURANT_CUSTOMER: 'CommonGameTag' = 2150 - BUFF_POSSESSED_BUFFS: 'CommonGameTag' = 47139 - BUFF_POSSESSED_BUFFS_NO_ANIMATE: 'CommonGameTag' = 47148 - BUFF_SCENARIOS_ACCEPTED_ASTRONAUT: 'CommonGameTag' = 2840 - BUFF_SCHOOL_NEGATIVE: 'CommonGameTag' = 2728 - BUFF_SOCIAL_MEDIA_ENABLE_POST: 'CommonGameTag' = 114738 - BUFF_SPELLS_CASTING_SPELL: 'CommonGameTag' = 49157 - BUFF_TEMPERATURE: 'CommonGameTag' = 2481 - BUFF_VAMPIRE_SUNLIGHT: 'CommonGameTag' = 40989 - BUFF_WEATHER: 'CommonGameTag' = 59431 - BUFF_WEDDING_GUEST_DANCE: 'CommonGameTag' = 133147 - BUILD_ARCH: 'CommonGameTag' = 561 - BUILD_BB_GAMEPLAY_EFFECT_COLUMNS_BILLS_DECREASE: 'CommonGameTag' = 2419 - BUILD_BB_GAMEPLAY_EFFECT_COLUMNS_BILLS_INCREASE: 'CommonGameTag' = 2420 - BUILD_BB_GAMEPLAY_EFFECT_COLUMNS_ECO_FOOTPRINT_MINUS1: 'CommonGameTag' = 2413 - BUILD_BB_GAMEPLAY_EFFECT_COLUMNS_ECO_FOOTPRINT_MINUS2: 'CommonGameTag' = 2414 - BUILD_BB_GAMEPLAY_EFFECT_COLUMNS_ECO_FOOTPRINT_PLUS1: 'CommonGameTag' = 2411 - BUILD_BB_GAMEPLAY_EFFECT_COLUMNS_ECO_FOOTPRINT_PLUS2: 'CommonGameTag' = 2412 - BUILD_BB_GAMEPLAY_EFFECT_COLUMNS_ENVIRONMENT_SCORE_MINUS1: 'CommonGameTag' = 2417 - BUILD_BB_GAMEPLAY_EFFECT_COLUMNS_ENVIRONMENT_SCORE_MINUS2: 'CommonGameTag' = 2418 - BUILD_BB_GAMEPLAY_EFFECT_COLUMNS_ENVIRONMENT_SCORE_PLUS1: 'CommonGameTag' = 2415 - BUILD_BB_GAMEPLAY_EFFECT_COLUMNS_ENVIRONMENT_SCORE_PLUS2: 'CommonGameTag' = 2416 - BUILD_BB_GAMEPLAY_EFFECT_FENCES_BILLS_DECREASE: 'CommonGameTag' = 2409 - BUILD_BB_GAMEPLAY_EFFECT_FENCES_BILLS_INCREASE: 'CommonGameTag' = 2410 - BUILD_BB_GAMEPLAY_EFFECT_FENCES_ECO_FOOTPRINT_MINUS1: 'CommonGameTag' = 2403 - BUILD_BB_GAMEPLAY_EFFECT_FENCES_ECO_FOOTPRINT_MINUS2: 'CommonGameTag' = 2404 - BUILD_BB_GAMEPLAY_EFFECT_FENCES_ECO_FOOTPRINT_PLUS1: 'CommonGameTag' = 2401 - BUILD_BB_GAMEPLAY_EFFECT_FENCES_ECO_FOOTPRINT_PLUS2: 'CommonGameTag' = 2402 - BUILD_BB_GAMEPLAY_EFFECT_FENCES_ENVIRONMENT_SCORE_MINUS1: 'CommonGameTag' = 2407 - BUILD_BB_GAMEPLAY_EFFECT_FENCES_ENVIRONMENT_SCORE_MINUS2: 'CommonGameTag' = 2408 - BUILD_BB_GAMEPLAY_EFFECT_FENCES_ENVIRONMENT_SCORE_PLUS1: 'CommonGameTag' = 2405 - BUILD_BB_GAMEPLAY_EFFECT_FENCES_ENVIRONMENT_SCORE_PLUS2: 'CommonGameTag' = 2406 - BUILD_BB_GAMEPLAY_EFFECT_FLOOR_PATTERN_DECREASE_BILLS: 'CommonGameTag' = 2329 - BUILD_BB_GAMEPLAY_EFFECT_FLOOR_PATTERN_ECO_FOOTPRINT_MINUS1: 'CommonGameTag' = 2308 - BUILD_BB_GAMEPLAY_EFFECT_FLOOR_PATTERN_ECO_FOOTPRINT_MINUS2: 'CommonGameTag' = 2309 - BUILD_BB_GAMEPLAY_EFFECT_FLOOR_PATTERN_ECO_FOOTPRINT_PLUS1: 'CommonGameTag' = 2306 - BUILD_BB_GAMEPLAY_EFFECT_FLOOR_PATTERN_ECO_FOOTPRINT_PLUS2: 'CommonGameTag' = 2307 - BUILD_BB_GAMEPLAY_EFFECT_FLOOR_PATTERN_ENVIRONMENT_SCORE_MINUS1: 'CommonGameTag' = 2296 - BUILD_BB_GAMEPLAY_EFFECT_FLOOR_PATTERN_ENVIRONMENT_SCORE_MINUS2: 'CommonGameTag' = 2297 - BUILD_BB_GAMEPLAY_EFFECT_FLOOR_PATTERN_ENVIRONMENT_SCORE_PLUS1: 'CommonGameTag' = 2294 - BUILD_BB_GAMEPLAY_EFFECT_FLOOR_PATTERN_ENVIRONMENT_SCORE_PLUS2: 'CommonGameTag' = 2295 - BUILD_BB_GAMEPLAY_EFFECT_FLOOR_PATTERN_INCREASE_BILLS: 'CommonGameTag' = 2328 - BUILD_BB_GAMEPLAY_EFFECT_OBJECT_DECREASE_BILLS: 'CommonGameTag' = 2327 - BUILD_BB_GAMEPLAY_EFFECT_OBJECT_ECO_FOOTPRINT_MINUS1: 'CommonGameTag' = 2300 - BUILD_BB_GAMEPLAY_EFFECT_OBJECT_ECO_FOOTPRINT_MINUS2: 'CommonGameTag' = 2301 - BUILD_BB_GAMEPLAY_EFFECT_OBJECT_ECO_FOOTPRINT_PLUS1: 'CommonGameTag' = 2298 - BUILD_BB_GAMEPLAY_EFFECT_OBJECT_ECO_FOOTPRINT_PLUS2: 'CommonGameTag' = 2299 - BUILD_BB_GAMEPLAY_EFFECT_OBJECT_ECO_FOOTPRINT_PLUS_PARK: 'CommonGameTag' = 2444 - BUILD_BB_GAMEPLAY_EFFECT_OBJECT_ENVIRONMENT_SCORE_MINUS1: 'CommonGameTag' = 2288 - BUILD_BB_GAMEPLAY_EFFECT_OBJECT_ENVIRONMENT_SCORE_MINUS2: 'CommonGameTag' = 2289 - BUILD_BB_GAMEPLAY_EFFECT_OBJECT_ENVIRONMENT_SCORE_PLUS1: 'CommonGameTag' = 2286 - BUILD_BB_GAMEPLAY_EFFECT_OBJECT_ENVIRONMENT_SCORE_PLUS2: 'CommonGameTag' = 2287 - BUILD_BB_GAMEPLAY_EFFECT_OBJECT_INCREASE_BILLS: 'CommonGameTag' = 2326 - BUILD_BB_GAMEPLAY_EFFECT_OBJECT_POWER_CONSUMER: 'CommonGameTag' = 2314 - BUILD_BB_GAMEPLAY_EFFECT_OBJECT_POWER_PRODUCER: 'CommonGameTag' = 2316 - BUILD_BB_GAMEPLAY_EFFECT_OBJECT_WATER_CONSUMER: 'CommonGameTag' = 2315 - BUILD_BB_GAMEPLAY_EFFECT_OBJECT_WATER_PRODUCER: 'CommonGameTag' = 2317 - BUILD_BB_GAMEPLAY_EFFECT_POOL_SURFACE_POWER_CONSUMER: 'CommonGameTag' = 2322 - BUILD_BB_GAMEPLAY_EFFECT_POOL_SURFACE_POWER_PRODUCER: 'CommonGameTag' = 2324 - BUILD_BB_GAMEPLAY_EFFECT_POOL_SURFACE_WATER_CONSUMER: 'CommonGameTag' = 2323 - BUILD_BB_GAMEPLAY_EFFECT_POOL_SURFACE_WATER_PRODUCER: 'CommonGameTag' = 2325 - BUILD_BB_GAMEPLAY_EFFECT_ROOF_MATERIAL_DECREASE_BILLS: 'CommonGameTag' = 2333 - BUILD_BB_GAMEPLAY_EFFECT_ROOF_MATERIAL_ECO_FOOTPRINT_MINUS1: 'CommonGameTag' = 2312 - BUILD_BB_GAMEPLAY_EFFECT_ROOF_MATERIAL_ECO_FOOTPRINT_MINUS2: 'CommonGameTag' = 2313 - BUILD_BB_GAMEPLAY_EFFECT_ROOF_MATERIAL_ECO_FOOTPRINT_PLUS1: 'CommonGameTag' = 2310 - BUILD_BB_GAMEPLAY_EFFECT_ROOF_MATERIAL_ECO_FOOTPRINT_PLUS2: 'CommonGameTag' = 2311 - BUILD_BB_GAMEPLAY_EFFECT_ROOF_MATERIAL_ENVIRONMENT_SCORE_MINUS1: 'CommonGameTag' = 2319 - BUILD_BB_GAMEPLAY_EFFECT_ROOF_MATERIAL_ENVIRONMENT_SCORE_PLUS1: 'CommonGameTag' = 2318 - BUILD_BB_GAMEPLAY_EFFECT_ROOF_MATERIAL_INCREASE_BILLS: 'CommonGameTag' = 2332 - BUILD_BB_GAMEPLAY_EFFECT_ROOF_MATERIAL_POWER_PRODUCER: 'CommonGameTag' = 2320 - BUILD_BB_GAMEPLAY_EFFECT_ROOF_MATERIAL_WATER_PRODUCER: 'CommonGameTag' = 2321 - BUILD_BB_GAMEPLAY_EFFECT_WALL_PATTERN_DECREASE_BILLS: 'CommonGameTag' = 2331 - BUILD_BB_GAMEPLAY_EFFECT_WALL_PATTERN_ECO_FOOTPRINT_MINUS1: 'CommonGameTag' = 2304 - BUILD_BB_GAMEPLAY_EFFECT_WALL_PATTERN_ECO_FOOTPRINT_MINUS2: 'CommonGameTag' = 2305 - BUILD_BB_GAMEPLAY_EFFECT_WALL_PATTERN_ECO_FOOTPRINT_PLUS1: 'CommonGameTag' = 2302 - BUILD_BB_GAMEPLAY_EFFECT_WALL_PATTERN_ECO_FOOTPRINT_PLUS2: 'CommonGameTag' = 2303 - BUILD_BB_GAMEPLAY_EFFECT_WALL_PATTERN_ENVIRONMENT_SCORE_MINUS1: 'CommonGameTag' = 2292 - BUILD_BB_GAMEPLAY_EFFECT_WALL_PATTERN_ENVIRONMENT_SCORE_MINUS2: 'CommonGameTag' = 2293 - BUILD_BB_GAMEPLAY_EFFECT_WALL_PATTERN_ENVIRONMENT_SCORE_PLUS1: 'CommonGameTag' = 2290 - BUILD_BB_GAMEPLAY_EFFECT_WALL_PATTERN_ENVIRONMENT_SCORE_PLUS2: 'CommonGameTag' = 2291 - BUILD_BB_GAMEPLAY_EFFECT_WALL_PATTERN_INCREASE_BILLS: 'CommonGameTag' = 2330 - BUILD_BLOCK: 'CommonGameTag' = 548 - BUILD_BLOCK_BASEMENT: 'CommonGameTag' = 242 - BUILD_BLOCK_CURVED_WALL: 'CommonGameTag' = 2829 - BUILD_BLOCK_DECK: 'CommonGameTag' = 1062 - BUILD_BLOCK_DIAGONAL: 'CommonGameTag' = 1070 - BUILD_BLOCK_FOUNTAIN: 'CommonGameTag' = 232 - BUILD_BLOCK_FOUNTAIN_TOOL: 'CommonGameTag' = 233 - BUILD_BLOCK_NO_WALLS: 'CommonGameTag' = 1064 - BUILD_BLOCK_PLATFORM: 'CommonGameTag' = 2491 - BUILD_BLOCK_PLATFORM_TOOL: 'CommonGameTag' = 2492 - BUILD_BLOCK_POOL: 'CommonGameTag' = 1226 - BUILD_BLOCK_POOL_TOOL: 'CommonGameTag' = 1227 - BUILD_BLOCK_WALL_TOOL: 'CommonGameTag' = 653 - BUILD_BLOCK_WITH_WALLS: 'CommonGameTag' = 1063 - BUILD_BUY_AUTONOMY_MARKER_ATTRACTOR: 'CommonGameTag' = 1638 - BUILD_BUY_NO_AUTONOMY_LIGHTS: 'CommonGameTag' = 1637 - BUILD_BUY_NO_AUTONOMY_PLANTS: 'CommonGameTag' = 1636 - BUILD_BUY_NO_AUTONOMY_RUGS: 'CommonGameTag' = 1639 - BUILD_BUY_NO_AUTONOMY_SCULPTURES: 'CommonGameTag' = 1634 - BUILD_BUY_WORLD_OBJECTS: 'CommonGameTag' = 787 - BUILD_COLUMN: 'CommonGameTag' = 538 - BUILD_DOOR: 'CommonGameTag' = 535 - BUILD_DOOR_CURVED: 'CommonGameTag' = 2827 - BUILD_DOOR_CURVED_SMALL: 'CommonGameTag' = 2830 - BUILD_DOOR_DOUBLE: 'CommonGameTag' = 918 - BUILD_DOOR_SINGLE: 'CommonGameTag' = 974 - BUILD_ELEVATOR: 'CommonGameTag' = 1611 - BUILD_FENCE: 'CommonGameTag' = 544 - BUILD_FLOOR_PATTERN: 'CommonGameTag' = 541 - BUILD_FLOOR_TRIM: 'CommonGameTag' = 554 - BUILD_FLOWER: 'CommonGameTag' = 556 - BUILD_FLOWER_BUSH: 'CommonGameTag' = 1068 - BUILD_FLOWER_GROUND_COVER: 'CommonGameTag' = 1067 - BUILD_FLOWER_MISC: 'CommonGameTag' = 1069 - BUILD_FOUNDATION: 'CommonGameTag' = 552 - BUILD_FOUNTAIN_TRIM: 'CommonGameTag' = 1081 - BUILD_FRIEZE: 'CommonGameTag' = 550 - BUILD_GATE: 'CommonGameTag' = 537 - BUILD_GATE_DOUBLE: 'CommonGameTag' = 915 - BUILD_GATE_SINGLE: 'CommonGameTag' = 976 - BUILD_GENERIC: 'CommonGameTag' = 1596 - BUILD_HALF_WALL: 'CommonGameTag' = 1441 - BUILD_HALF_WALL_TRIM: 'CommonGameTag' = 1442 - BUILD_IS_SHELL_BUILDING: 'CommonGameTag' = 1574 - BUILD_LADDER: 'CommonGameTag' = 2425 - BUILD_PLATFORM_TRIM: 'CommonGameTag' = 2483 - BUILD_POND: 'CommonGameTag' = 2570 - BUILD_POOL_STYLES: 'CommonGameTag' = 251 - BUILD_POOL_TRIM: 'CommonGameTag' = 250 - BUILD_POST: 'CommonGameTag' = 782 - BUILD_RAILING: 'CommonGameTag' = 547 - BUILD_ROCK: 'CommonGameTag' = 560 - BUILD_ROOF: 'CommonGameTag' = 540 - BUILD_ROOF_ATTACHMENT: 'CommonGameTag' = 539 - BUILD_ROOF_ATTACHMENT_MISC: 'CommonGameTag' = 975 - BUILD_ROOF_CHIMNEY: 'CommonGameTag' = 919 - BUILD_ROOF_DIAGONAL: 'CommonGameTag' = 906 - BUILD_ROOF_ORTHOGONAL: 'CommonGameTag' = 977 - BUILD_ROOF_PATTERN: 'CommonGameTag' = 543 - BUILD_ROOF_TRIM: 'CommonGameTag' = 551 - BUILD_RUG: 'CommonGameTag' = 559 - BUILD_SHRUB: 'CommonGameTag' = 557 - BUILD_SHRUB_BUSH: 'CommonGameTag' = 1065 - BUILD_SHRUB_CACTUS: 'CommonGameTag' = 1066 - BUILD_SPANDREL: 'CommonGameTag' = 545 - BUILD_STAIR: 'CommonGameTag' = 546 - BUILD_STYLE: 'CommonGameTag' = 549 - BUILD_STYLES_UBURBAN_CONTEMPORARY: 'CommonGameTag' = 2546 - BUILD_STYLE_ART_DECO: 'CommonGameTag' = 2825 - BUILD_STYLE_BASICS: 'CommonGameTag' = 2537 - BUILD_STYLE_BOHO: 'CommonGameTag' = 2534 - BUILD_STYLE_CONTEMPORARY: 'CommonGameTag' = 2535 - BUILD_STYLE_COSMOLUX: 'CommonGameTag' = 2536 - BUILD_STYLE_CUTE: 'CommonGameTag' = 2908 - BUILD_STYLE_DOUBLE_GALLERY: 'CommonGameTag' = 2539 - BUILD_STYLE_EVENTS: 'CommonGameTag' = 2745 - BUILD_STYLE_FRENCH_COUNTRY: 'CommonGameTag' = 2540 - BUILD_STYLE_GARDEN: 'CommonGameTag' = 2549 - BUILD_STYLE_GOTHIC_FARMHOUSE: 'CommonGameTag' = 2541 - BUILD_STYLE_HOLIDAYS: 'CommonGameTag' = 2744 - BUILD_STYLE_INDUSTRIAL: 'CommonGameTag' = 2727 - BUILD_STYLE_ISLAND: 'CommonGameTag' = 2548 - BUILD_STYLE_LUXE: 'CommonGameTag' = 2841 - BUILD_STYLE_MID_CENTURY: 'CommonGameTag' = 2555 - BUILD_STYLE_MISSION: 'CommonGameTag' = 2542 - BUILD_STYLE_MODERN: 'CommonGameTag' = 2543 - BUILD_STYLE_PATIO: 'CommonGameTag' = 2538 - BUILD_STYLE_QUEEN_ANNE: 'CommonGameTag' = 2544 - BUILD_STYLE_SCANDINAVIAN_CONTEMPORARY: 'CommonGameTag' = 2550 - BUILD_STYLE_SHOTGUN: 'CommonGameTag' = 2545 - BUILD_STYLE_TUDOR: 'CommonGameTag' = 2547 - BUILD_STYLE_VINTAGE: 'CommonGameTag' = 2826 - BUILD_TREE: 'CommonGameTag' = 558 - BUILD_WALL_ATTACHMENT: 'CommonGameTag' = 555 - BUILD_WALL_PATTERN: 'CommonGameTag' = 542 - BUILD_WATER_OBJECTS_BUILD_MODE_WATER_STYLES: 'CommonGameTag' = 2636 - BUILD_WATER_OBJECTS_BY_FUNCTION_WATER_STYLES: 'CommonGameTag' = 2643 - BUILD_WEDDING_ARCH: 'CommonGameTag' = 981 - BUILD_WINDOW: 'CommonGameTag' = 536 - BUILD_WINDOW_CURVED: 'CommonGameTag' = 2828 - BUILD_WINDOW_CURVED_SMALL: 'CommonGameTag' = 2831 - BUYCAT_WATER_OBJECTS_BUILD_MODE_ATTRACTORS: 'CommonGameTag' = 2637 - BUYCAT_WATER_OBJECTS_BUILD_MODE_FOUNTAIN_DECORATIONS: 'CommonGameTag' = 2633 - BUYCAT_WATER_OBJECTS_BUILD_MODE_POND_ITEMS: 'CommonGameTag' = 2632 - BUYCAT_WATER_OBJECTS_BUILD_MODE_POOL_OBJECTS: 'CommonGameTag' = 2635 - BUYCAT_WATER_OBJECTS_BY_FUNCTION_ATTRACTORS: 'CommonGameTag' = 2644 - BUYCAT_WATER_OBJECTS_BY_FUNCTION_FOUNTAIN_DECORATIONS: 'CommonGameTag' = 2639 - BUYCAT_WATER_OBJECTS_BY_FUNCTION_OPEN_WATER_OBJECTS: 'CommonGameTag' = 2642 - BUYCAT_WATER_OBJECTS_BY_FUNCTION_POOL_OBJECTS: 'CommonGameTag' = 2641 - BUYCAT_WATER_OBJECTS_BY_FUNCTION_WATER_EMITTERS: 'CommonGameTag' = 2640 - BUYCAT_WATER_OBJECTS_BY_ROOM_WATER_DECORATIONS: 'CommonGameTag' = 2638 - BUY_CAT_CLEAN_POWER: 'CommonGameTag' = 67591 - BUY_CAT_COLLECTION_ALIEN: 'CommonGameTag' = 1044 - BUY_CAT_COLLECTION_ALL: 'CommonGameTag' = 1053 - BUY_CAT_COLLECTION_CAPSULE: 'CommonGameTag' = 69729 - BUY_CAT_COLLECTION_CITY_POSTER: 'CommonGameTag' = 55378 - BUY_CAT_COLLECTION_CRYSTAL: 'CommonGameTag' = 1041 - BUY_CAT_COLLECTION_ELEMENT: 'CommonGameTag' = 1042 - BUY_CAT_COLLECTION_FISH: 'CommonGameTag' = 1051 - BUY_CAT_COLLECTION_FOSSIL: 'CommonGameTag' = 1043 - BUY_CAT_COLLECTION_FROG: 'CommonGameTag' = 1052 - BUY_CAT_COLLECTION_GACHAPON: 'CommonGameTag' = 69728 - BUY_CAT_COLLECTION_GARDENING: 'CommonGameTag' = 1159 - BUY_CAT_COLLECTION_METAL: 'CommonGameTag' = 1045 - BUY_CAT_COLLECTION_MY_SIM: 'CommonGameTag' = 1046 - BUY_CAT_COLLECTION_POSTCARD: 'CommonGameTag' = 1049 - BUY_CAT_COLLECTION_SLIDE: 'CommonGameTag' = 1048 - BUY_CAT_COLLECTION_SNOW_GLOBE: 'CommonGameTag' = 55377 - BUY_CAT_COLLECTION_SPACE_PRINT: 'CommonGameTag' = 1047 - BUY_CAT_COLLECTION_SPACE_ROCK: 'CommonGameTag' = 1050 - BUY_CAT_COLLECTION_TREASURE: 'CommonGameTag' = 2043 - BUY_CAT_COLUMNS: 'CommonGameTag' = 429 - BUY_CAT_COMMUNITY: 'CommonGameTag' = 1352 - BUY_CAT_EASEL: 'CommonGameTag' = 440 - BUY_CAT_EE_ACTIVE_ACTIVITY: 'CommonGameTag' = 970 - BUY_CAT_EE_ALARM: 'CommonGameTag' = 169 - BUY_CAT_EE_AUDIO: 'CommonGameTag' = 163 - BUY_CAT_EE_BAR: 'CommonGameTag' = 176 - BUY_CAT_EE_BASKETBALL: 'CommonGameTag' = 456 - BUY_CAT_EE_CHESS_TABLE: 'CommonGameTag' = 457 - BUY_CAT_EE_CLOCK: 'CommonGameTag' = 171 - BUY_CAT_EE_COMPUTER: 'CommonGameTag' = 162 - BUY_CAT_EE_CREATIVE_ACTIVITY: 'CommonGameTag' = 968 - BUY_CAT_EE_GARDENING: 'CommonGameTag' = 2075 - BUY_CAT_EE_HOBBY_SKILL: 'CommonGameTag' = 165 - BUY_CAT_EE_INDOOR_ACTIVITY: 'CommonGameTag' = 173 - BUY_CAT_EE_KID_ACTIVITY: 'CommonGameTag' = 174 - BUY_CAT_EE_KID_FURNITURE: 'CommonGameTag' = 167 - BUY_CAT_EE_KID_TOY: 'CommonGameTag' = 168 - BUY_CAT_EE_KNOWLEDGE_ACTIVITY: 'CommonGameTag' = 969 - BUY_CAT_EE_MISC_ELECTRONICS: 'CommonGameTag' = 177 - BUY_CAT_EE_MISC_ENTERTAINMENT: 'CommonGameTag' = 178 - BUY_CAT_EE_MISC_KIDS: 'CommonGameTag' = 179 - BUY_CAT_EE_MONKEY_BARS: 'CommonGameTag' = 458 - BUY_CAT_EE_OUTDOOR_ACTIVITY: 'CommonGameTag' = 175 - BUY_CAT_EE_PARTY: 'CommonGameTag' = 166 - BUY_CAT_EE_PET_ACTIVITY_TOYS: 'CommonGameTag' = 2014 - BUY_CAT_EE_PET_MISC: 'CommonGameTag' = 1948 - BUY_CAT_EE_PET_TOYS: 'CommonGameTag' = 1944 - BUY_CAT_EE_PET_VET: 'CommonGameTag' = 1947 - BUY_CAT_EE_TODDLERS: 'CommonGameTag' = 172 - BUY_CAT_EE_TRANSPORTATION: 'CommonGameTag' = 2237 - BUY_CAT_EE_TV: 'CommonGameTag' = 161 - BUY_CAT_EE_TV_SETS: 'CommonGameTag' = 164 - BUY_CAT_EE_TV_STAND: 'CommonGameTag' = 1122 - BUY_CAT_EE_VIDEO_GAME_CONSOLE: 'CommonGameTag' = 55356 - BUY_CAT_HOLIDAY_ALL: 'CommonGameTag' = 2084 - BUY_CAT_HOLIDAY_DECOR_ALL: 'CommonGameTag' = 2085 - BUY_CAT_INSTRUMENT: 'CommonGameTag' = 441 - BUY_CAT_LD_AWNING: 'CommonGameTag' = 979 - BUY_CAT_LD_BATHROOM_ACCENT: 'CommonGameTag' = 194 - BUY_CAT_LD_CEILING_DECORATION: 'CommonGameTag' = 2188 - BUY_CAT_LD_CEILING_LIGHT: 'CommonGameTag' = 205 - BUY_CAT_LD_CLUTTER: 'CommonGameTag' = 823 - BUY_CAT_LD_CURTAIN_BLIND: 'CommonGameTag' = 978 - BUY_CAT_LD_FIREPLACE: 'CommonGameTag' = 785 - BUY_CAT_LD_FLOOR_LAMP: 'CommonGameTag' = 204 - BUY_CAT_LD_FOUNTAIN_DECORATION: 'CommonGameTag' = 199 - BUY_CAT_LD_FOUNTAIN_EMITTER: 'CommonGameTag' = 231 - BUY_CAT_LD_FOUNTAIN_OBJECTS: 'CommonGameTag' = 252 - BUY_CAT_LD_KID_DECORATION: 'CommonGameTag' = 196 - BUY_CAT_LD_LAWN_ORNAMENT: 'CommonGameTag' = 195 - BUY_CAT_LD_MIRROR: 'CommonGameTag' = 207 - BUY_CAT_LD_MIRROR_FREESTANDING: 'CommonGameTag' = 965 - BUY_CAT_LD_MIRROR_WALL: 'CommonGameTag' = 964 - BUY_CAT_LD_MISC_DECORATION: 'CommonGameTag' = 209 - BUY_CAT_LD_MISC_LIGHT: 'CommonGameTag' = 208 - BUY_CAT_LD_NIGHT_LIGHT: 'CommonGameTag' = 1718 - BUY_CAT_LD_OUTDOOR_LIGHT: 'CommonGameTag' = 206 - BUY_CAT_LD_PLANT: 'CommonGameTag' = 202 - BUY_CAT_LD_POOL_DECORATIONS: 'CommonGameTag' = 1246 - BUY_CAT_LD_POOL_OBJECTS: 'CommonGameTag' = 1228 - BUY_CAT_LD_POOL_OBJECTS_INVENTORYABLE: 'CommonGameTag' = 2211 - BUY_CAT_LD_RUG: 'CommonGameTag' = 198 - BUY_CAT_LD_RUG_MANAGED: 'CommonGameTag' = 1496 - BUY_CAT_LD_SCULPTURE: 'CommonGameTag' = 200 - BUY_CAT_LD_TABLE_LAMP: 'CommonGameTag' = 203 - BUY_CAT_LD_WALL_DECORATION: 'CommonGameTag' = 201 - BUY_CAT_LD_WALL_LIGHT: 'CommonGameTag' = 310 - BUY_CAT_LD_WALL_SCULPTURE: 'CommonGameTag' = 824 - BUY_CAT_LD_WINDOW_TREATMENT: 'CommonGameTag' = 197 - BUY_CAT_LOT_REQ_ELEVATOR: 'CommonGameTag' = 55374 - BUY_CAT_LOT_REQ_ELEVATOR_BG: 'CommonGameTag' = 2240 - BUY_CAT_LOT_REQ_MAILBOX: 'CommonGameTag' = 55375 - BUY_CAT_LOT_REQ_MAILBOX_BG: 'CommonGameTag' = 2241 - BUY_CAT_LOT_REQ_TRASH_CHUTE: 'CommonGameTag' = 55376 - BUY_CAT_LOT_REQ_TRASH_CHUTE_BG: 'CommonGameTag' = 2242 - BUY_CAT_MAG_BATHROOM: 'CommonGameTag' = 271 - BUY_CAT_MAG_BEDROOM: 'CommonGameTag' = 272 - BUY_CAT_MAG_CAREER: 'CommonGameTag' = 468 - BUY_CAT_MAG_DINING_ROOM: 'CommonGameTag' = 273 - BUY_CAT_MAG_KIDS: 'CommonGameTag' = 864 - BUY_CAT_MAG_KITCHEN: 'CommonGameTag' = 274 - BUY_CAT_MAG_LIVING_ROOM: 'CommonGameTag' = 270 - BUY_CAT_MAG_MISC: 'CommonGameTag' = 407 - BUY_CAT_MAG_OUTDOOR: 'CommonGameTag' = 275 - BUY_CAT_MAG_STUDY: 'CommonGameTag' = 276 - BUY_CAT_OTG_APPLIANCES: 'CommonGameTag' = 2380 - BUY_CAT_OTG_CRAFTING: 'CommonGameTag' = 2381 - BUY_CAT_OTG_LIGHTING: 'CommonGameTag' = 2382 - BUY_CAT_OTG_MISC: 'CommonGameTag' = 2383 - BUY_CAT_OTG_OUTDOOR_ACTIVITIES: 'CommonGameTag' = 2384 - BUY_CAT_OTG_PLUMBING: 'CommonGameTag' = 2385 - BUY_CAT_PAINTING: 'CommonGameTag' = 446 - BUY_CAT_PA_COFFEE_MAKER: 'CommonGameTag' = 966 - BUY_CAT_PA_DISPOSABLE: 'CommonGameTag' = 188 - BUY_CAT_PA_DISPOSAL_INDOOR: 'CommonGameTag' = 972 - BUY_CAT_PA_DISPOSAL_OUTDOOR: 'CommonGameTag' = 973 - BUY_CAT_PA_LARGE_APPLIANCE: 'CommonGameTag' = 185 - BUY_CAT_PA_LITTER_BOX: 'CommonGameTag' = 1978 - BUY_CAT_PA_MICROWAVE: 'CommonGameTag' = 967 - BUY_CAT_PA_MISC_APPLIANCE: 'CommonGameTag' = 193 - BUY_CAT_PA_MISC_PLUMBING: 'CommonGameTag' = 192 - BUY_CAT_PA_MISC_SMALL_APPLIANCE: 'CommonGameTag' = 191 - BUY_CAT_PA_OUTDOOR_COOKING: 'CommonGameTag' = 190 - BUY_CAT_PA_PET_CARE: 'CommonGameTag' = 1945 - BUY_CAT_PA_PET_FOOD: 'CommonGameTag' = 1976 - BUY_CAT_PA_PUBLIC_RESTROOM: 'CommonGameTag' = 2042 - BUY_CAT_PA_REFRIGERATOR: 'CommonGameTag' = 189 - BUY_CAT_PA_SHOWER: 'CommonGameTag' = 183 - BUY_CAT_PA_SINK: 'CommonGameTag' = 180 - BUY_CAT_PA_SINK_COUNTER: 'CommonGameTag' = 920 - BUY_CAT_PA_SINK_FREESTANDING: 'CommonGameTag' = 182 - BUY_CAT_PA_SMALL_APPLIANCE: 'CommonGameTag' = 186 - BUY_CAT_PA_STOVE: 'CommonGameTag' = 187 - BUY_CAT_PA_STOVE_HOOD: 'CommonGameTag' = 913 - BUY_CAT_PA_TOILET: 'CommonGameTag' = 181 - BUY_CAT_PA_TUB: 'CommonGameTag' = 184 - BUY_CAT_SHAREABLE: 'CommonGameTag' = 1261 - BUY_CAT_SPANDRELS_FRIEZES_TRIM: 'CommonGameTag' = 430 - BUY_CAT_SS_ACCENT_TABLE: 'CommonGameTag' = 1123 - BUY_CAT_SS_BARSTOOL: 'CommonGameTag' = 224 - BUY_CAT_SS_BED: 'CommonGameTag' = 225 - BUY_CAT_SS_BED_DOUBLE: 'CommonGameTag' = 914 - BUY_CAT_SS_BED_SINGLE: 'CommonGameTag' = 971 - BUY_CAT_SS_BOOKSHELF: 'CommonGameTag' = 226 - BUY_CAT_SS_BUNK_BED: 'CommonGameTag' = 2526 - BUY_CAT_SS_CABINET: 'CommonGameTag' = 211 - BUY_CAT_SS_COFFEE_TABLE: 'CommonGameTag' = 214 - BUY_CAT_SS_COUNTER: 'CommonGameTag' = 210 - BUY_CAT_SS_DESK: 'CommonGameTag' = 215 - BUY_CAT_SS_DESK_CHAIR: 'CommonGameTag' = 222 - BUY_CAT_SS_DINING_CHAIR: 'CommonGameTag' = 217 - BUY_CAT_SS_DINING_TABLE: 'CommonGameTag' = 212 - BUY_CAT_SS_DINING_TABLE_LONG: 'CommonGameTag' = 963 - BUY_CAT_SS_DINING_TABLE_SHORT: 'CommonGameTag' = 962 - BUY_CAT_SS_DISPLAY: 'CommonGameTag' = 216 - BUY_CAT_SS_DRESSER: 'CommonGameTag' = 227 - BUY_CAT_SS_DRESSER_CLOTHES: 'CommonGameTag' = 2553 - BUY_CAT_SS_ELEMENT_DISPLAY: 'CommonGameTag' = 1072 - BUY_CAT_SS_END_TABLE: 'CommonGameTag' = 213 - BUY_CAT_SS_HALLWAY_TABLE: 'CommonGameTag' = 1126 - BUY_CAT_SS_LIVING_CHAIR: 'CommonGameTag' = 221 - BUY_CAT_SS_LOVE_SEAT: 'CommonGameTag' = 219 - BUY_CAT_SS_MISC_COMFORT: 'CommonGameTag' = 229 - BUY_CAT_SS_MISC_STORAGE: 'CommonGameTag' = 230 - BUY_CAT_SS_MISC_SURFACE: 'CommonGameTag' = 228 - BUY_CAT_SS_MODULAR_SHELVING: 'CommonGameTag' = 2527 - BUY_CAT_SS_OUTDOOR_BENCH: 'CommonGameTag' = 916 - BUY_CAT_SS_OUTDOOR_CHAIR: 'CommonGameTag' = 220 - BUY_CAT_SS_OUTDOOR_SEATING: 'CommonGameTag' = 223 - BUY_CAT_SS_OUTDOOR_TABLE: 'CommonGameTag' = 917 - BUY_CAT_SS_PET_BED: 'CommonGameTag' = 1977 - BUY_CAT_SS_PET_FURNITURE: 'CommonGameTag' = 1946 - BUY_CAT_SS_POSTCARD_BOARD: 'CommonGameTag' = 1071 - BUY_CAT_SS_SCRATCHING_POST: 'CommonGameTag' = 1979 - BUY_CAT_SS_SOFA: 'CommonGameTag' = 218 - BUY_CAT_VENUE_ARTS_CENTER: 'CommonGameTag' = 1604 - BUY_CAT_VENUE_ARTS_COMMONS: 'CommonGameTag' = 2273 - BUY_CAT_VENUE_AUDITORIUM: 'CommonGameTag' = 114756 - BUY_CAT_VENUE_AUDITORIUM_CAREER_DAY: 'CommonGameTag' = 114759 - BUY_CAT_VENUE_AUDITORIUM_FORMAL_DANCE: 'CommonGameTag' = 114758 - BUY_CAT_VENUE_AUDITORIUM_GRADUATION: 'CommonGameTag' = 114760 - BUY_CAT_VENUE_BAR: 'CommonGameTag' = 1353 - BUY_CAT_VENUE_BEACH: 'CommonGameTag' = 2199 - BUY_CAT_VENUE_BLUFFS: 'CommonGameTag' = 24612 - BUY_CAT_VENUE_CAFE: 'CommonGameTag' = 24578 - BUY_CAT_VENUE_CAFE_BG: 'CommonGameTag' = 2731 - BUY_CAT_VENUE_CHALET: 'CommonGameTag' = 24611 - BUY_CAT_VENUE_CLUB: 'CommonGameTag' = 1354 - BUY_CAT_VENUE_COMMUNITY_SPACE_DEFAULT: 'CommonGameTag' = 2438 - BUY_CAT_VENUE_COMMUNITY_SPACE_GARDEN: 'CommonGameTag' = 2440 - BUY_CAT_VENUE_COMMUNITY_SPACE_MAKER_SPACE: 'CommonGameTag' = 2439 - BUY_CAT_VENUE_COMMUNITY_SPACE_MARKETPLACE: 'CommonGameTag' = 2441 - BUY_CAT_VENUE_DOCTOR_CLINIC: 'CommonGameTag' = 1362 - BUY_CAT_VENUE_FOREST_PARK: 'CommonGameTag' = 1355 - BUY_CAT_VENUE_GYM: 'CommonGameTag' = 1356 - BUY_CAT_VENUE_HIGH_SCHOOL: 'CommonGameTag' = 114752 - BUY_CAT_VENUE_KARAOKE: 'CommonGameTag' = 1579 - BUY_CAT_VENUE_LIBRARY: 'CommonGameTag' = 1357 - BUY_CAT_VENUE_LOUNGE: 'CommonGameTag' = 1358 - BUY_CAT_VENUE_MUSEUM: 'CommonGameTag' = 1359 - BUY_CAT_VENUE_ONSEN: 'CommonGameTag' = 69662 - BUY_CAT_VENUE_PARK: 'CommonGameTag' = 1360 - BUY_CAT_VENUE_PENTHOUSE: 'CommonGameTag' = 55373 - BUY_CAT_VENUE_PENTHOUSE_BG: 'CommonGameTag' = 2239 - BUY_CAT_VENUE_POLICE_STATION: 'CommonGameTag' = 1363 - BUY_CAT_VENUE_POOL: 'CommonGameTag' = 1459 - BUY_CAT_VENUE_REC_CENTER: 'CommonGameTag' = 116755 - BUY_CAT_VENUE_RELAXATION_CENTER: 'CommonGameTag' = 18436 - BUY_CAT_VENUE_RESTAURANT: 'CommonGameTag' = 26625 - BUY_CAT_VENUE_RESTAURANT_BG: 'CommonGameTag' = 2730 - BUY_CAT_VENUE_RETAIL: 'CommonGameTag' = 1361 - BUY_CAT_VENUE_RUINS: 'CommonGameTag' = 24613 - BUY_CAT_VENUE_SCIENCE_COMMONS: 'CommonGameTag' = 2272 - BUY_CAT_VENUE_SCIENTIST_LAB: 'CommonGameTag' = 1364 - BUY_CAT_VENUE_STAR_GARDEN: 'CommonGameTag' = 1580 - BUY_CAT_VENUE_THRIFT_STORE: 'CommonGameTag' = 114757 - BUY_CAT_VENUE_UNIVERSITY_HOUSING: 'CommonGameTag' = 2229 - BUY_CAT_VENUE_VET: 'CommonGameTag' = 57401 - BUY_CAT_VENUE_VET_BG: 'CommonGameTag' = 2729 - BUY_CAT_VENUE_WEDDING: 'CommonGameTag' = 2746 - BUY_CAT_WINDOWS: 'CommonGameTag' = 428 - BUY_TAG_DISABLE_PLACEMENT_OUTLINE: 'CommonGameTag' = 43017 - BUY_TAG_NOT_AUTO_COUNTER_APPLIANCE: 'CommonGameTag' = 2274 - BUY_TAG_SHOW_IF_WALLS_CUTAWAY: 'CommonGameTag' = 1492 - CAS_CATEGORY_MEDICAL_WEARABLE_BODY_TORSO: 'CommonGameTag' = 2911 - CAS_CATEGORY_MEDICAL_WEARABLE_FACE: 'CommonGameTag' = 2910 - CAS_STORY_ADD_CAREER: 'CommonGameTag' = 2213 - CAS_STORY_ADD_FUNDS: 'CommonGameTag' = 2212 - CAS_STORY_ADD_OCCULT: 'CommonGameTag' = 2215 - CAS_STORY_ADD_SKILL: 'CommonGameTag' = 2214 - COAT_PATTERN_BICOLOR: 'CommonGameTag' = 2004 - COAT_PATTERN_BLANKET: 'CommonGameTag' = 2991 - COAT_PATTERN_BRINDLE: 'CommonGameTag' = 1995 - COAT_PATTERN_CALICO: 'CommonGameTag' = 2006 - COAT_PATTERN_COLORPOINT: 'CommonGameTag' = 2019 - COAT_PATTERN_DAPPLE: 'CommonGameTag' = 2989 - COAT_PATTERN_FANTASY: 'CommonGameTag' = 2009 - COAT_PATTERN_HARLEQUIN: 'CommonGameTag' = 2022 - COAT_PATTERN_LEOPARD: 'CommonGameTag' = 2990 - COAT_PATTERN_MASK: 'CommonGameTag' = 2001 - COAT_PATTERN_MERLE: 'CommonGameTag' = 1999 - COAT_PATTERN_PAINT: 'CommonGameTag' = 2988 - COAT_PATTERN_ROSETTE: 'CommonGameTag' = 2008 - COAT_PATTERN_SABLE: 'CommonGameTag' = 1996 - COAT_PATTERN_SADDLE: 'CommonGameTag' = 2000 - COAT_PATTERN_SOLID: 'CommonGameTag' = 1994 - COAT_PATTERN_SPECKLED: 'CommonGameTag' = 1998 - COAT_PATTERN_SPOTTED: 'CommonGameTag' = 1997 - COAT_PATTERN_STRIPED: 'CommonGameTag' = 2003 - COAT_PATTERN_TABBY: 'CommonGameTag' = 2002 - COAT_PATTERN_TIPPED: 'CommonGameTag' = 2007 - COAT_PATTERN_TORTOISESHELL: 'CommonGameTag' = 2005 - COAT_PATTERN_TRI_COLOR: 'CommonGameTag' = 2021 - COLOR_BLACK: 'CommonGameTag' = 93 - COLOR_BLUE: 'CommonGameTag' = 68 - COLOR_BROWN: 'CommonGameTag' = 91 - COLOR_BROWN_LIGHT: 'CommonGameTag' = 293 - COLOR_CHESTNUT_HORSE: 'CommonGameTag' = 2992 - COLOR_DARK_BROWN: 'CommonGameTag' = 90 - COLOR_FANTASY_HORSE: 'CommonGameTag' = 2994 - COLOR_GOLD_HORSE: 'CommonGameTag' = 2993 - COLOR_GRAY: 'CommonGameTag' = 92 - COLOR_GREEN: 'CommonGameTag' = 69 - COLOR_ORANGE: 'CommonGameTag' = 95 - COLOR_PALETTE_EARTH_TONES: 'CommonGameTag' = 280 - COLOR_PALETTE_GOTH_ROCK_PUNK: 'CommonGameTag' = 288 - COLOR_PALETTE_GRAYSCALE_DARK: 'CommonGameTag' = 282 - COLOR_PALETTE_GRAYSCALE_LIGHT: 'CommonGameTag' = 283 - COLOR_PALETTE_JEWEL: 'CommonGameTag' = 141 - COLOR_PALETTE_SPRING: 'CommonGameTag' = 285 - COLOR_PALETTE_SUMMER: 'CommonGameTag' = 286 - COLOR_PALETTE_WINTER: 'CommonGameTag' = 287 - COLOR_PINK: 'CommonGameTag' = 106 - COLOR_PURPLE: 'CommonGameTag' = 107 - COLOR_RED: 'CommonGameTag' = 65 - COLOR_WHITE: 'CommonGameTag' = 105 - COLOR_YELLOW: 'CommonGameTag' = 104 - CRAFTING_GARDENING: 'CommonGameTag' = 424 - CRAFTING_SONG: 'CommonGameTag' = 447 - DD_BUFF_OWNABLEBROTHEL_PATRON: 'CommonGameTag' = 1000001 - DD_BUYCAT_VENUE_BROTHEL: 'CommonGameTag' = 1000011 - DD_FILTER_BROTHELPATRON_STANDARD: 'CommonGameTag' = 1000007 - DD_INTERACTION_BROTHELSTAFF_HARLOTSTUD_IDLE: 'CommonGameTag' = 1000010 - DD_JOB_BROTHELPATRON: 'CommonGameTag' = 1000002 - DD_ROLE_BROTHELPATRON: 'CommonGameTag' = 1000003 - DD_ROLE_BROTHELPATRONFREEROAM: 'CommonGameTag' = 1000020 - DD_ROLE_BROTHELPATRONFREEROAM_READYFORSERVICE: 'CommonGameTag' = 1000021 - DD_ROLE_BROTHELPATRONSITDOWN: 'CommonGameTag' = 1000026 - DD_ROLE_BROTHELPATRON_BESERVICED: 'CommonGameTag' = 1000005 - DD_ROLE_BROTHELPATRON_READYFORSTAFFTOTAKEORDER: 'CommonGameTag' = 1000004 - DD_ROLE_BROTHELSTAFF: 'CommonGameTag' = 1000009 - DD_ROLE_BROTHELSTAFF_BARTENDER: 'CommonGameTag' = 1000017 - DD_ROLE_BROTHELSTAFF_MAINTENANCE: 'CommonGameTag' = 1000016 - DD_ROLE_BROTHELSTAFF_STRIPPER: 'CommonGameTag' = 1000012 - DD_SITUATION_BROTHELPATRON: 'CommonGameTag' = 1000006 - DD_SITUATION_BROTHELPATRON_PLAYER: 'CommonGameTag' = 1000025 - DD_SITUATION_BROTHELSTAFF: 'CommonGameTag' = 1000013 - DD_SITUATION_BROTHELSTAFF_AUTONOMOUS: 'CommonGameTag' = 1000018 - DD_SITUATION_BROTHELSTAFF_BARTENDER: 'CommonGameTag' = 1000023 - DD_SITUATION_BROTHELSTAFF_HARLOTSTUD: 'CommonGameTag' = 1000022 - DD_SITUATION_BROTHELSTAFF_HOST: 'CommonGameTag' = 1000024 - DD_SITUATION_BROTHELSTAFF_MAINTENANCE: 'CommonGameTag' = 1000015 - DD_SITUATION_BROTHELSTAFF_PLAYER: 'CommonGameTag' = 1000019 - DD_SITUATION_BROTHELSTAFF_STRIPPER: 'CommonGameTag' = 1000014 - DEPRECIATED: 'CommonGameTag' = 118792 - DOG_SIZE_LARGE: 'CommonGameTag' = 1892 - DOG_SIZE_SMALL: 'CommonGameTag' = 1891 - DRINKS_ANY: 'CommonGameTag' = 159 - DRINKS_BAR_ALCOHOLIC: 'CommonGameTag' = 157 - DRINKS_BAR_ANY: 'CommonGameTag' = 160 - DRINKS_BAR_NON_ALCOHOLIC: 'CommonGameTag' = 158 - DRINK_ALCOHOLIC: 'CommonGameTag' = 264 - DRINK_ANY: 'CommonGameTag' = 269 - DRINK_BUBBLE_TEA: 'CommonGameTag' = 114701 - DRINK_CRAFTED: 'CommonGameTag' = 351 - DRINK_CRAFTED_COFFEE_TEA: 'CommonGameTag' = 459 - DRINK_FIZZY: 'CommonGameTag' = 18451 - DRINK_KAVA: 'CommonGameTag' = 63538 - DRINK_MILK: 'CommonGameTag' = 2948 - DRINK_NON_ALCOHOLIC: 'CommonGameTag' = 265 - DRINK_SERUM: 'CommonGameTag' = 12290 - DRINK_SPACE_ENERGY: 'CommonGameTag' = 691 - DRINK_TODDLER: 'CommonGameTag' = 1661 - DUPLICATE_AFFORDANCE_ANIMAL_WATCH: 'CommonGameTag' = 2702 - DUPLICATE_AFFORDANCE_COMPUTER: 'CommonGameTag' = 2836 - DUPLICATE_AFFORDANCE_COUNTER: 'CommonGameTag' = 57450 - DUPLICATE_AFFORDANCE_HIGH_SCHOOL_ACTIVE_CLEAN_SINK: 'CommonGameTag' = 114744 - DUPLICATE_AFFORDANCE_HIGH_SCHOOL_ACTIVE_CLEAN_TABLE: 'CommonGameTag' = 114741 - DUPLICATE_AFFORDANCE_HIGH_SCHOOL_ACTIVE_CLEAN_TOILET: 'CommonGameTag' = 114742 - DUPLICATE_AFFORDANCE_HIGH_SCHOOL_ACTIVE_CREATE_PUDDLE: 'CommonGameTag' = 114743 - DUPLICATE_AFFORDANCE_HIGH_SCHOOL_BACKGROUND: 'CommonGameTag' = 114736 - DUPLICATE_AFFORDANCE_INFANT_WATCH: 'CommonGameTag' = 2952 - DUPLICATE_AFFORDANCE_MAGIC_HQ_BE_AMAZED: 'CommonGameTag' = 49184 - DUPLICATE_AFFORDANCE_MAGIC_HQ_BROWSE_BOOKS: 'CommonGameTag' = 49185 - DUPLICATE_AFFORDANCE_MIRROR: 'CommonGameTag' = 2172 - DUPLICATE_AFFORDANCE_PONDS: 'CommonGameTag' = 2589 - DUPLICATE_AFFORDANCE_READ: 'CommonGameTag' = 1173 - DUPLICATE_AFFORDANCE_SCRATCH: 'CommonGameTag' = 57449 - DUPLICATE_AFFORDANCE_SINK: 'CommonGameTag' = 2096 - DUPLICATE_AFFORDANCE_TALK_TO_PLANT: 'CommonGameTag' = 2701 - DUPLICATE_AFFORDANCE_TOYS_PICK_UP: 'CommonGameTag' = 1697 - DUPLICATE_AFFORDANCE_TOYS_PLAY_WITH: 'CommonGameTag' = 1696 - DUPLICATE_AFFORDANCE_TRAIT_INTERACTIONS: 'CommonGameTag' = 1174 - DUPLICATE_AFFORDANCE_VIEW: 'CommonGameTag' = 1175 - DUPLICATE_AFFORDANCE_WASH_HANDS: 'CommonGameTag' = 2837 - DUPLICATE_AFFORDANCE_WILD_GRASS_HARVEST: 'CommonGameTag' = 118878 - EARS_DOWN: 'CommonGameTag' = 57347 - EARS_UP: 'CommonGameTag' = 57348 - ENSEMBLE_FIN_ORANGE_RED: 'CommonGameTag' = 63537 - ENSEMBLE_FIN_PASTEL: 'CommonGameTag' = 63535 - ENSEMBLE_FIN_TEAL_PURPLE: 'CommonGameTag' = 63536 - ENSEMBLE_SWIM_BANDEAU_BLACK: 'CommonGameTag' = 1257 - ENSEMBLE_SWIM_BANDEAU_BLUE: 'CommonGameTag' = 1258 - ENSEMBLE_SWIM_BANDEAU_CORAL: 'CommonGameTag' = 1251 - ENSEMBLE_SWIM_BANDEAU_YELLOW: 'CommonGameTag' = 1254 - ENSEMBLE_SWIM_HALTER_BLACK: 'CommonGameTag' = 1239 - ENSEMBLE_SWIM_HALTER_LIME: 'CommonGameTag' = 1255 - ENSEMBLE_SWIM_HALTER_RED: 'CommonGameTag' = 1252 - ENSEMBLE_SWIM_HALTER_WHITE: 'CommonGameTag' = 1256 - ENSEMBLE_SWIM_METAL_BROWN: 'CommonGameTag' = 1259 - ENSEMBLE_SWIM_METAL_GREEN: 'CommonGameTag' = 1260 - ENSEMBLE_SWIM_METAL_PINK: 'CommonGameTag' = 1250 - ENSEMBLE_SWIM_METAL_TEAL: 'CommonGameTag' = 1253 - EYEBROW_SHAPE_ARCHED: 'CommonGameTag' = 1060 - EYEBROW_SHAPE_CURVED: 'CommonGameTag' = 1059 - EYEBROW_SHAPE_STRAIGHT: 'CommonGameTag' = 1058 - EYEBROW_THICKNESS_BALD: 'CommonGameTag' = 12393 - EYEBROW_THICKNESS_BUSHY: 'CommonGameTag' = 1054 - EYEBROW_THICKNESS_MEDIUM: 'CommonGameTag' = 1057 - EYEBROW_THICKNESS_SPARSE: 'CommonGameTag' = 1056 - EYEBROW_THICKNESS_THIN: 'CommonGameTag' = 1055 - EYE_COLOR_ALIEN: 'CommonGameTag' = 12392 - EYE_COLOR_AMBER: 'CommonGameTag' = 114 - EYE_COLOR_AQUA: 'CommonGameTag' = 115 - EYE_COLOR_BLACK: 'CommonGameTag' = 116 - EYE_COLOR_BLUE: 'CommonGameTag' = 117 - EYE_COLOR_BLUE_GRAY: 'CommonGameTag' = 1884 - EYE_COLOR_BROWN: 'CommonGameTag' = 118 - EYE_COLOR_DARK_BROWN: 'CommonGameTag' = 119 - EYE_COLOR_GOLDEN: 'CommonGameTag' = 423 - EYE_COLOR_GRAY: 'CommonGameTag' = 120 - EYE_COLOR_GREEN: 'CommonGameTag' = 121 - EYE_COLOR_HAZEL: 'CommonGameTag' = 421 - EYE_COLOR_HAZEL_BLUE: 'CommonGameTag' = 122 - EYE_COLOR_HAZEL_GREEN: 'CommonGameTag' = 123 - EYE_COLOR_HONEY: 'CommonGameTag' = 422 - EYE_COLOR_LIGHT_BLUE: 'CommonGameTag' = 124 - EYE_COLOR_LIGHT_BROWN: 'CommonGameTag' = 125 - EYE_COLOR_LIGHT_GREEN: 'CommonGameTag' = 126 - EYE_COLOR_LIGHT_YELLOW: 'CommonGameTag' = 1880 - EYE_COLOR_PURPLE: 'CommonGameTag' = 2763 - EYE_COLOR_VAMPIRE_BLACK: 'CommonGameTag' = 40988 - EYE_COLOR_VAMPIRE_BLUE_BLACK: 'CommonGameTag' = 40980 - EYE_COLOR_VAMPIRE_GREEN: 'CommonGameTag' = 40981 - EYE_COLOR_VAMPIRE_ICE_BLUE: 'CommonGameTag' = 40982 - EYE_COLOR_VAMPIRE_PURPLE: 'CommonGameTag' = 40983 - EYE_COLOR_VAMPIRE_RED: 'CommonGameTag' = 40984 - EYE_COLOR_VAMPIRE_RED_BLACK: 'CommonGameTag' = 40985 - EYE_COLOR_VAMPIRE_WHITE: 'CommonGameTag' = 40986 - EYE_COLOR_VAMPIRE_YELLOW: 'CommonGameTag' = 40987 - EYE_COLOR_YELLOW: 'CommonGameTag' = 1879 - EYE_COLOR_YELLOW_GREEN: 'CommonGameTag' = 1885 - FABRIC_COTTON: 'CommonGameTag' = 532 - FABRIC_DENIM: 'CommonGameTag' = 587 - FABRIC_LEATHER: 'CommonGameTag' = 531 - FABRIC_METAL: 'CommonGameTag' = 932 - FABRIC_SILK: 'CommonGameTag' = 585 - FABRIC_SILVER: 'CommonGameTag' = 933 - FABRIC_SYNTHETIC: 'CommonGameTag' = 584 - FABRIC_WOOL: 'CommonGameTag' = 586 - FACE_DETAIL_FRECKLES_NOSE: 'CommonGameTag' = 1651 - FACE_DETAIL_FRECKLES_SPREAD: 'CommonGameTag' = 1650 - FACE_DETAIL_TEETH_BUCK: 'CommonGameTag' = 1647 - FACE_DETAIL_TEETH_GAP: 'CommonGameTag' = 1649 - FACE_DETAIL_TEETH_SNAGGLE: 'CommonGameTag' = 1648 - FACE_DETAIL_TEETH_STRAIGHT: 'CommonGameTag' = 1652 - FACIAL_HAIR_BEARD: 'CommonGameTag' = 378 - FACIAL_HAIR_GOATEE: 'CommonGameTag' = 379 - FACIAL_HAIR_MUSTACHE: 'CommonGameTag' = 380 - FASHION_RARITY_COMMON: 'CommonGameTag' = 2803 - FASHION_RARITY_EXCLUSIVE: 'CommonGameTag' = 2806 - FASHION_RARITY_EXCLUSIVE_DEPOP: 'CommonGameTag' = 2807 - FASHION_RARITY_RARE: 'CommonGameTag' = 2804 - FASHION_RARITY_VERY_RARE: 'CommonGameTag' = 2805 - FIRE_FLAMMABLE_AUTO_ADDED: 'CommonGameTag' = 1925 - FLOOR_PATTERN_CARPET: 'CommonGameTag' = 298 - FLOOR_PATTERN_DIRT_SAND: 'CommonGameTag' = 309 - FLOOR_PATTERN_FLOWERS: 'CommonGameTag' = 308 - FLOOR_PATTERN_GRASS: 'CommonGameTag' = 307 - FLOOR_PATTERN_LINOLEUM: 'CommonGameTag' = 303 - FLOOR_PATTERN_MASONRY: 'CommonGameTag' = 302 - FLOOR_PATTERN_METAL: 'CommonGameTag' = 304 - FLOOR_PATTERN_MISC: 'CommonGameTag' = 305 - FLOOR_PATTERN_OUTDOOR: 'CommonGameTag' = 306 - FLOOR_PATTERN_STONE: 'CommonGameTag' = 301 - FLOOR_PATTERN_TILE: 'CommonGameTag' = 299 - FLOOR_PATTERN_WOOD: 'CommonGameTag' = 300 - FOOD_ANY: 'CommonGameTag' = 268 - FOOD_AROMATIC: 'CommonGameTag' = 1614 - FOOD_BATUU: 'CommonGameTag' = 51240 - FOOD_BEACH_BUM: 'CommonGameTag' = 2203 - FOOD_BURRITO: 'CommonGameTag' = 1602 - FOOD_CAFETERIA_STATION_PRANKED: 'CommonGameTag' = 65551 - FOOD_CAMPFIRE: 'CommonGameTag' = 10263 - FOOD_CHOPSTICKS: 'CommonGameTag' = 55379 - FOOD_DESSERT: 'CommonGameTag' = 359 - FOOD_DISH_BOWL: 'CommonGameTag' = 1980 - FOOD_DISH_PLATE: 'CommonGameTag' = 1981 - FOOD_DISH_SHORT_FOOD: 'CommonGameTag' = 1988 - FOOD_DISH_TALL_FOOD: 'CommonGameTag' = 1987 - FOOD_EAT_WITH_TODDLER_SIZED: 'CommonGameTag' = 1675 - FOOD_EAT_WITH_UTENSIL: 'CommonGameTag' = 1674 - FOOD_EXOTIC: 'CommonGameTag' = 2939 - FOOD_FOOD_BLOB_APPLESAUCE_LIGHT_BROWN: 'CommonGameTag' = 1687 - FOOD_FOOD_BLOB_FRUIT_SALAD_RED_YELLOW_BLUE: 'CommonGameTag' = 1688 - FOOD_FOOD_BLOB_MAC_CHEESE_YELLOW_SPOTTY: 'CommonGameTag' = 1689 - FOOD_FOOD_BLOB_MINESTRONE_REDDISH_BROWN: 'CommonGameTag' = 1690 - FOOD_FOOD_BLOB_OATMEAL_LIGHT_BROWN_SPOTTY: 'CommonGameTag' = 1691 - FOOD_FOOD_BLOB_PEAS_GREEN: 'CommonGameTag' = 1693 - FOOD_FOOD_BLOB_YOGURT_PINK_WHITISH: 'CommonGameTag' = 1692 - FOOD_FRIDGE: 'CommonGameTag' = 348 - FOOD_GOURMET_MEAL: 'CommonGameTag' = 2511 - FOOD_GRAND_MEAL_EP05: 'CommonGameTag' = 2083 - FOOD_GRILLED_CHEESE: 'CommonGameTag' = 1499 - FOOD_HAS_FISH: 'CommonGameTag' = 2201 - FOOD_HAS_MEAT: 'CommonGameTag' = 1572 - FOOD_HAS_MEAT_SUBSTITUTE: 'CommonGameTag' = 1573 - FOOD_HAY: 'CommonGameTag' = 118801 - FOOD_HEALTHY: 'CommonGameTag' = 2494 - FOOD_HEALTHY_MEAL: 'CommonGameTag' = 2754 - FOOD_HORSE_FRIENDLY: 'CommonGameTag' = 2973 - FOOD_ICO: 'CommonGameTag' = 1984 - FOOD_ISLAND: 'CommonGameTag' = 63511 - FOOD_JUNGLE: 'CommonGameTag' = 45089 - FOOD_JUNK: 'CommonGameTag' = 2495 - FOOD_JUNK_SUGAR_ADDED: 'CommonGameTag' = 2755 - FOOD_KALUA_PORK: 'CommonGameTag' = 63512 - FOOD_MADE_WITH_GOLDEN_EGG: 'CommonGameTag' = 2627 - FOOD_MADE_WITH_OBSIDIAN_EGG: 'CommonGameTag' = 2628 - FOOD_MEAL_BREAKFAST: 'CommonGameTag' = 1728 - FOOD_MEAL_DINNER: 'CommonGameTag' = 1730 - FOOD_MEAL_LUNCH: 'CommonGameTag' = 1729 - FOOD_MULTI: 'CommonGameTag' = 347 - FOOD_PICKY_EATER_A_LIKE: 'CommonGameTag' = 1712 - FOOD_PICKY_EATER_B_LIKE: 'CommonGameTag' = 1713 - FOOD_PICKY_EATER_C_LIKE: 'CommonGameTag' = 1714 - FOOD_PICKY_EATER_DISLIKE: 'CommonGameTag' = 1717 - FOOD_PICKY_EATER_D_LIKE: 'CommonGameTag' = 1715 - FOOD_PICKY_EATER_E_LIKE: 'CommonGameTag' = 1716 - FOOD_PIE: 'CommonGameTag' = 2609 - FOOD_PREPARED: 'CommonGameTag' = 759 - FOOD_QUICK_MEAL: 'CommonGameTag' = 2236 - FOOD_SACK_LUNCH: 'CommonGameTag' = 43025 - FOOD_SINGLE: 'CommonGameTag' = 1686 - FOOD_SNACK: 'CommonGameTag' = 651 - FOOD_SPICY: 'CommonGameTag' = 1603 - FOOD_TODDLER_DISLIKE: 'CommonGameTag' = 1659 - FOOD_TODDLER_LIKE: 'CommonGameTag' = 1660 - FULL_BODY_APRON: 'CommonGameTag' = 951 - FULL_BODY_COSTUME: 'CommonGameTag' = 948 - FULL_BODY_JUMPSUITS: 'CommonGameTag' = 374 - FULL_BODY_LINGERIE: 'CommonGameTag' = 950 - FULL_BODY_LONG_DRESS: 'CommonGameTag' = 375 - FULL_BODY_OUTERWEAR: 'CommonGameTag' = 947 - FULL_BODY_OVERALL: 'CommonGameTag' = 952 - FULL_BODY_ROBE: 'CommonGameTag' = 949 - FULL_BODY_SHORT_DRESS: 'CommonGameTag' = 376 - FULL_BODY_SUITS: 'CommonGameTag' = 377 - FULL_BODY_SWIMSUIT: 'CommonGameTag' = 1237 - FUNC_ACCURSED_OBJECT: 'CommonGameTag' = 86019 - FUNC_ACCURSED_OBJECT_REWARD_DOLL: 'CommonGameTag' = 86026 - FUNC_ACCURSED_OBJECT_REWARD_TENDRIL: 'CommonGameTag' = 86027 - FUNC_ACID_MUD_PUDDLE: 'CommonGameTag' = 67625 - FUNC_ACTIVITY_TABLE: 'CommonGameTag' = 688 - FUNC_ACTIVITY_TABLE_DRAWING: 'CommonGameTag' = 934 - FUNC_ACTOR_CAREER_CELL_DOOR: 'CommonGameTag' = 61496 - FUNC_ACTOR_CAREER_FRIDGE: 'CommonGameTag' = 61495 - FUNC_ACTOR_CAREER_HOSPITAL_EXAM_BED: 'CommonGameTag' = 61497 - FUNC_ACTOR_CAREER_MOVIE_MEDIEVAL_STAGE_PROP: 'CommonGameTag' = 61647 - FUNC_ACTOR_CAREER_MOVIE_PIRATE_STAGE_PROP: 'CommonGameTag' = 61625 - FUNC_ACTOR_CAREER_MOVIE_SUPER_HERO_STAGE_PROP: 'CommonGameTag' = 61627 - FUNC_ACTOR_CAREER_PEDESTAL: 'CommonGameTag' = 61498 - FUNC_ACTOR_CAREER_PIRATE_WHEEL: 'CommonGameTag' = 61499 - FUNC_ACTOR_CAREER_STAGE_MARK_LARGE: 'CommonGameTag' = 61500 - FUNC_ACTOR_CAREER_STAGE_OBJECT_ALL: 'CommonGameTag' = 61611 - FUNC_ACTOR_CAREER_STAGE_OBJECT_CAMPFIRE: 'CommonGameTag' = 61633 - FUNC_ACTOR_CAREER_STUDIO_DOOR_PRIVATE: 'CommonGameTag' = 61641 - FUNC_ACTOR_CAREER_TV_HIGH_APOCALYPSE_STAGE_PROP: 'CommonGameTag' = 61626 - FUNC_ADVENTURE_GEAR: 'CommonGameTag' = 69710 - FUNC_AIR: 'CommonGameTag' = 1284 - FUNC_ALERT: 'CommonGameTag' = 1392 - FUNC_ALIEN: 'CommonGameTag' = 12397 - FUNC_ALIEN_PORTAL: 'CommonGameTag' = 12436 - FUNC_ALIEN_SATELLITE_DISH: 'CommonGameTag' = 12370 - FUNC_AMBROSIA: 'CommonGameTag' = 1989 - FUNC_AMBROSIA_TREAT: 'CommonGameTag' = 57399 - FUNC_ANIMAL: 'CommonGameTag' = 506 - FUNC_ANIMAL_OBJECT: 'CommonGameTag' = 2709 - FUNC_ANIMAL_OBJECT_ANIMAL_CLOTHES: 'CommonGameTag' = 2602 - FUNC_ANIMAL_OBJECT_ANIMAL_CLOTHES_FOR_CHICKEN: 'CommonGameTag' = 2604 - FUNC_ANIMAL_OBJECT_ANIMAL_CLOTHES_FOR_COW: 'CommonGameTag' = 2605 - FUNC_ANIMAL_OBJECT_ANIMAL_CLOTHES_FOR_FOX: 'CommonGameTag' = 2634 - FUNC_ANIMAL_OBJECT_ANIMAL_CLOTHES_FOR_LLAMA: 'CommonGameTag' = 2606 - FUNC_ANIMAL_OBJECT_ANIMAL_CLOTHES_FOR_RABBIT: 'CommonGameTag' = 2603 - FUNC_ANIMAL_OBJECT_FEEDER: 'CommonGameTag' = 3002 - FUNC_ANIMAL_OBJECT_LIVESTOCK: 'CommonGameTag' = 2710 - FUNC_ANIMAL_OBJECT_LIVESTOCK_CHICKEN: 'CommonGameTag' = 2711 - FUNC_ANIMAL_OBJECT_LIVESTOCK_CHICKEN_CHICK: 'CommonGameTag' = 2714 - FUNC_ANIMAL_OBJECT_LIVESTOCK_CHICKEN_EGG: 'CommonGameTag' = 2715 - FUNC_ANIMAL_OBJECT_LIVESTOCK_CHICKEN_HEN: 'CommonGameTag' = 2712 - FUNC_ANIMAL_OBJECT_LIVESTOCK_CHICKEN_ROOSTER: 'CommonGameTag' = 2713 - FUNC_ANIMAL_OBJECT_LIVESTOCK_CHICKEN_SPECIAL_EGG: 'CommonGameTag' = 2697 - FUNC_ANIMAL_OBJECT_LIVESTOCK_COOP: 'CommonGameTag' = 2718 - FUNC_ANIMAL_OBJECT_LIVESTOCK_COW: 'CommonGameTag' = 2716 - FUNC_ANIMAL_OBJECT_LIVESTOCK_GOAT: 'CommonGameTag' = 118785 - FUNC_ANIMAL_OBJECT_LIVESTOCK_LLAMA: 'CommonGameTag' = 2717 - FUNC_ANIMAL_OBJECT_LIVESTOCK_PEN: 'CommonGameTag' = 2719 - FUNC_ANIMAL_OBJECT_LIVESTOCK_SHEEP: 'CommonGameTag' = 118786 - FUNC_ANIMAL_OBJECT_LIVESTOCK_SHEEP_BLACK: 'CommonGameTag' = 118813 - FUNC_ANIMAL_OBJECT_LIVESTOCK_SHEEP_COLORS: 'CommonGameTag' = 118814 - FUNC_ANIMAL_OBJECT_LIVESTOCK_SHEEP_WHITE: 'CommonGameTag' = 118812 - FUNC_ANIMAL_OBJECT_WILD: 'CommonGameTag' = 2720 - FUNC_ANIMAL_OBJECT_WILD_BIRD_HOME: 'CommonGameTag' = 2722 - FUNC_ANIMAL_OBJECT_WILD_BIRD_HOME_ANIMATED_BIRD: 'CommonGameTag' = 112664 - FUNC_ANIMAL_OBJECT_WILD_RABBIT: 'CommonGameTag' = 2721 - FUNC_ANIMAL_OBJECT_WILD_RABBIT_HOME: 'CommonGameTag' = 2723 - FUNC_ANIMAL_OBJECT_WILD_RABBIT_MOUND: 'CommonGameTag' = 2724 - FUNC_ANNIVERSARY: 'CommonGameTag' = 1366 - FUNC_ANNIVERSARY_21: 'CommonGameTag' = 2519 - FUNC_APARTMENT_PROBLEM: 'CommonGameTag' = 55333 - FUNC_APPARITION: 'CommonGameTag' = 1195 - FUNC_AQUARIUM: 'CommonGameTag' = 1109 - FUNC_ARCADE: 'CommonGameTag' = 24605 - FUNC_ARCHAEOLOGY_CAN_BE_STUDIED: 'CommonGameTag' = 45112 - FUNC_ARCHAEOLOGY_CAN_BE_STUDIED_BG: 'CommonGameTag' = 2051 - FUNC_ARCHAEOLOGY_ITEM_MED: 'CommonGameTag' = 45073 - FUNC_ARCHAEOLOGY_ITEM_SMALL: 'CommonGameTag' = 45074 - FUNC_ARCHAEOLOGY_TABLE: 'CommonGameTag' = 45072 - FUNC_ART: 'CommonGameTag' = 484 - FUNC_ARTS_UNIVERSITY_SHELL: 'CommonGameTag' = 65548 - FUNC_ARTS_UNIVERSITY_SHELL_SHELL1: 'CommonGameTag' = 65560 - FUNC_ARTS_UNIVERSITY_SHELL_SHELL2: 'CommonGameTag' = 65561 - FUNC_ART_SCULPTURE: 'CommonGameTag' = 2209 - FUNC_ASH_PILE: 'CommonGameTag' = 1465 - FUNC_ASTRONAUT: 'CommonGameTag' = 1131 - FUNC_ATHLETIC: 'CommonGameTag' = 476 - FUNC_ATMOSPHERIC_CONDENSER: 'CommonGameTag' = 67616 - FUNC_ATOM: 'CommonGameTag' = 1394 - FUNC_AURAL_USE_TERRAIN_TYPES: 'CommonGameTag' = 2525 - FUNC_AUTHOR: 'CommonGameTag' = 1119 - FUNC_AUTOGRAPHED_OBJECT: 'CommonGameTag' = 61614 - FUNC_AUTONOMY_AREA_MARKER: 'CommonGameTag' = 2186 - FUNC_AUTO_PET_FEEDER: 'CommonGameTag' = 57396 - FUNC_AWNING: 'CommonGameTag' = 1155 - FUNC_BABY: 'CommonGameTag' = 744 - FUNC_BABY_SHOWER_GIFT: 'CommonGameTag' = 116740 - FUNC_BABY_YODA: 'CommonGameTag' = 2280 - FUNC_BADGE: 'CommonGameTag' = 1421 - FUNC_BAIT_CRYSTAL: 'CommonGameTag' = 983 - FUNC_BAIT_ELEMENT: 'CommonGameTag' = 982 - FUNC_BAIT_FRESH_FLOWER: 'CommonGameTag' = 827 - FUNC_BAIT_FRESH_FRUIT: 'CommonGameTag' = 825 - FUNC_BAIT_FROG: 'CommonGameTag' = 788 - FUNC_BAIT_MED_FISH: 'CommonGameTag' = 829 - FUNC_BAIT_METAL: 'CommonGameTag' = 984 - FUNC_BAIT_ORGANIC: 'CommonGameTag' = 789 - FUNC_BAIT_PLASMA_FRUIT: 'CommonGameTag' = 40972 - FUNC_BAIT_ROTTEN_FLOWER: 'CommonGameTag' = 828 - FUNC_BAIT_ROTTEN_FRUIT: 'CommonGameTag' = 826 - FUNC_BAIT_SMALL_FISH: 'CommonGameTag' = 796 - FUNC_BAIT_TRASH: 'CommonGameTag' = 830 - FUNC_BAKE: 'CommonGameTag' = 1385 - FUNC_BAKING: 'CommonGameTag' = 1387 - FUNC_BALL: 'CommonGameTag' = 528 - FUNC_BANQUET: 'CommonGameTag' = 8218 - FUNC_BANQUET_TABLE: 'CommonGameTag' = 8213 - FUNC_BAR: 'CommonGameTag' = 498 - FUNC_BARBECUE: 'CommonGameTag' = 1079 - FUNC_BARREL: 'CommonGameTag' = 12378 - FUNC_BAR_GLOBE: 'CommonGameTag' = 36865 - FUNC_BASEBOARD: 'CommonGameTag' = 1084 - FUNC_BASIN: 'CommonGameTag' = 1110 - FUNC_BASKET: 'CommonGameTag' = 527 - FUNC_BASKETBALL: 'CommonGameTag' = 55404 - FUNC_BASKETBALL_HOOP: 'CommonGameTag' = 55402 - FUNC_BASSINET: 'CommonGameTag' = 2926 - FUNC_BAT: 'CommonGameTag' = 1220 - FUNC_BATH: 'CommonGameTag' = 1022 - FUNC_BATHROOM: 'CommonGameTag' = 1023 - FUNC_BATHTUB: 'CommonGameTag' = 990 - FUNC_BATTLE_STATION: 'CommonGameTag' = 32770 - FUNC_BATUU_ANTIQUITIES: 'CommonGameTag' = 51230 - FUNC_BATUU_BINOCULARS: 'CommonGameTag' = 51238 - FUNC_BATUU_BLASTER: 'CommonGameTag' = 51233 - FUNC_BATUU_COMM_LINK: 'CommonGameTag' = 51234 - FUNC_BATUU_CONTROL_PANEL: 'CommonGameTag' = 51239 - FUNC_BATUU_CONTROL_PANEL_FIRST_ORDER: 'CommonGameTag' = 51250 - FUNC_BATUU_CONTROL_PANEL_FIRST_ORDER_COMMUNICATIONS_TOWER: 'CommonGameTag' = 51244 - FUNC_BATUU_CONTROL_PANEL_MAIN_STRIP: 'CommonGameTag' = 51257 - FUNC_BATUU_CONTROL_PANEL_RESISTANCE: 'CommonGameTag' = 51256 - FUNC_BATUU_DATA_SPIKE: 'CommonGameTag' = 51235 - FUNC_BATUU_FAKE_ID: 'CommonGameTag' = 51236 - FUNC_BATUU_MISSION_RS8_RESCUE_PREP_OBJ: 'CommonGameTag' = 51245 - FUNC_BATUU_MISSION_VALUABLE: 'CommonGameTag' = 51242 - FUNC_BATUU_PORG: 'CommonGameTag' = 51271 - FUNC_BATUU_SHELL: 'CommonGameTag' = 51249 - FUNC_BATUU_SHELL_DOCKING_BAY: 'CommonGameTag' = 51247 - FUNC_BATUU_SHELL_DWELLING: 'CommonGameTag' = 51248 - FUNC_BATUU_SUPPLY_CRATE: 'CommonGameTag' = 51206 - FUNC_BATUU_SUPPLY_CRATE_BLACK_SPIRE: 'CommonGameTag' = 51268 - FUNC_BATUU_SUPPLY_CRATE_FIRST_ORDER: 'CommonGameTag' = 51267 - FUNC_BATUU_SUPPLY_CRATE_RESISTANCE: 'CommonGameTag' = 51266 - FUNC_BATUU_THERMAL_DETONATOR: 'CommonGameTag' = 51237 - FUNC_BBQ: 'CommonGameTag' = 1078 - FUNC_BEACH_CAVE: 'CommonGameTag' = 63534 - FUNC_BEAM: 'CommonGameTag' = 1427 - FUNC_BEAR: 'CommonGameTag' = 508 - FUNC_BEAST: 'CommonGameTag' = 1216 - FUNC_BED: 'CommonGameTag' = 777 - FUNC_BEDSIDE_TABLE: 'CommonGameTag' = 1009 - FUNC_BED_KID: 'CommonGameTag' = 888 - FUNC_BED_VALID_MONSTER_UNDER_TARGET: 'CommonGameTag' = 1542 - FUNC_BEE_BOX: 'CommonGameTag' = 59449 - FUNC_BEE_SWARM: 'CommonGameTag' = 59452 - FUNC_BENCH: 'CommonGameTag' = 494 - FUNC_BEVERAGE: 'CommonGameTag' = 500 - FUNC_BG_PIPE_ORGAN: 'CommonGameTag' = 1709 - FUNC_BG_YOGA_MAT: 'CommonGameTag' = 1710 - FUNC_BICYCLE: 'CommonGameTag' = 2956 - FUNC_BIKE: 'CommonGameTag' = 2278 - FUNC_BIN: 'CommonGameTag' = 925 - FUNC_BIO_FUEL: 'CommonGameTag' = 2336 - FUNC_BIRD_FEEDER: 'CommonGameTag' = 34820 - FUNC_BIZARRE_IDOL: 'CommonGameTag' = 86030 - FUNC_BLADDER: 'CommonGameTag' = 995 - FUNC_BLINDS: 'CommonGameTag' = 1153 - FUNC_BLOB: 'CommonGameTag' = 512 - FUNC_BLOCK_CONSTRUCTION_TABLE: 'CommonGameTag' = 43029 - FUNC_BONE: 'CommonGameTag' = 1210 - FUNC_BONFIRE: 'CommonGameTag' = 2190 - FUNC_BONY: 'CommonGameTag' = 1211 - FUNC_BOOK: 'CommonGameTag' = 893 - FUNC_BOOKCASE: 'CommonGameTag' = 1389 - FUNC_BOOK_BOOK_OF_LIFE: 'CommonGameTag' = 1177 - FUNC_BOOK_DO_NOT_PUT_AWAY: 'CommonGameTag' = 2839 - FUNC_BOOK_HOMEWORK: 'CommonGameTag' = 1080 - FUNC_BOOK_MAGIC_TOME: 'CommonGameTag' = 49153 - FUNC_BOOK_MANUAL: 'CommonGameTag' = 2767 - FUNC_BOOK_PLAYER_CREATED: 'CommonGameTag' = 656 - FUNC_BOOK_WEREWOLF: 'CommonGameTag' = 135184 - FUNC_BOOMBOX: 'CommonGameTag' = 991 - FUNC_BOOTH: 'CommonGameTag' = 26629 - FUNC_BOOTH_BANQUETTE: 'CommonGameTag' = 26641 - FUNC_BOOTH_CORNER: 'CommonGameTag' = 26636 - FUNC_BOTTLE: 'CommonGameTag' = 1160 - FUNC_BOWL: 'CommonGameTag' = 1222 - FUNC_BOWLING: 'CommonGameTag' = 38925 - FUNC_BOWLING_LANE: 'CommonGameTag' = 38913 - FUNC_BOWLING_LANE_BG: 'CommonGameTag' = 1720 - FUNC_BOX: 'CommonGameTag' = 579 - FUNC_BOX_OF_DECORATIONS: 'CommonGameTag' = 59408 - FUNC_BREWER: 'CommonGameTag' = 1882 - FUNC_BRICK: 'CommonGameTag' = 1086 - FUNC_BRIEFCASE: 'CommonGameTag' = 55407 - FUNC_BUBBLE_BLOWER: 'CommonGameTag' = 55310 - FUNC_BUBBLE_TEA_COUNTER: 'CommonGameTag' = 114698 - FUNC_BUCKET: 'CommonGameTag' = 1291 - FUNC_BUFFET: 'CommonGameTag' = 8217 - FUNC_BUILD_OBJ_HAS_ADDITIONAL_GAMEPLAY: 'CommonGameTag' = 2808 - FUNC_BUSH: 'CommonGameTag' = 1163 - FUNC_BUSINESS: 'CommonGameTag' = 1323 - FUNC_BUSINESS_LIGHT: 'CommonGameTag' = 1545 - FUNC_CABINET: 'CommonGameTag' = 1409 - FUNC_CAFETERIA_STATION: 'CommonGameTag' = 65550 - FUNC_CAGE: 'CommonGameTag' = 1431 - FUNC_CAKE: 'CommonGameTag' = 1391 - FUNC_CALENDAR: 'CommonGameTag' = 1395 - FUNC_CAMERAS: 'CommonGameTag' = 1381 - FUNC_CAMERA_NORMAL: 'CommonGameTag' = 12342 - FUNC_CAMERA_OUTSTANDING: 'CommonGameTag' = 12343 - FUNC_CAMERA_POOR: 'CommonGameTag' = 12341 - FUNC_CAMERA_PRO: 'CommonGameTag' = 79875 - FUNC_CAMERA_SLOT_TRIPOD: 'CommonGameTag' = 2221 - FUNC_CAMERA_TRIPOD: 'CommonGameTag' = 79873 - FUNC_CAMERA_TRIPOD_ANCHOR_MARK: 'CommonGameTag' = 79877 - FUNC_CAMPFIRE: 'CommonGameTag' = 10246 - FUNC_CAMPING: 'CommonGameTag' = 10245 - FUNC_CANDLE: 'CommonGameTag' = 1207 - FUNC_CANDLES: 'CommonGameTag' = 1328 - FUNC_CANDLE_MAKING_STATION: 'CommonGameTag' = 67628 - FUNC_CANDY_BOWL: 'CommonGameTag' = 2117 - FUNC_CANDY_SKULL: 'CommonGameTag' = 1554 - FUNC_CANDY_SKULL_01: 'CommonGameTag' = 1555 - FUNC_CANDY_SKULL_02: 'CommonGameTag' = 1556 - FUNC_CANDY_SKULL_03: 'CommonGameTag' = 1557 - FUNC_CANDY_SKULL_04: 'CommonGameTag' = 1558 - FUNC_CANDY_SKULL_05: 'CommonGameTag' = 1559 - FUNC_CANDY_SKULL_06: 'CommonGameTag' = 1560 - FUNC_CANDY_SKULL_07: 'CommonGameTag' = 1561 - FUNC_CANDY_SKULL_08: 'CommonGameTag' = 1562 - FUNC_CANDY_SKULL_09: 'CommonGameTag' = 1563 - FUNC_CANDY_SKULL_10: 'CommonGameTag' = 1564 - FUNC_CANNED_GOOD: 'CommonGameTag' = 2580 - FUNC_CANS: 'CommonGameTag' = 1297 - FUNC_CANT_REPOSSESS: 'CommonGameTag' = 2276 - FUNC_CANVAS: 'CommonGameTag' = 573 - FUNC_CAN_BE_VACUUMED: 'CommonGameTag' = 94213 - FUNC_CAN_BE_VACUUMED_GROSS: 'CommonGameTag' = 94214 - FUNC_CAN_BE_VACUUMED_HANDHELD: 'CommonGameTag' = 94224 - FUNC_CARDS: 'CommonGameTag' = 1316 - FUNC_CARD_GAME: 'CommonGameTag' = 922 - FUNC_CARD_TABLE: 'CommonGameTag' = 988 - FUNC_CARPENTER: 'CommonGameTag' = 492 - FUNC_CARPET: 'CommonGameTag' = 1161 - FUNC_CART: 'CommonGameTag' = 1402 - FUNC_CARVED_PUMPKIN: 'CommonGameTag' = 22529 - FUNC_CARVING_STATION: 'CommonGameTag' = 22540 - FUNC_CASE: 'CommonGameTag' = 1411 - FUNC_CAT_CONDO: 'CommonGameTag' = 57383 - FUNC_CAT_WAND: 'CommonGameTag' = 57429 - FUNC_CAT_WAND_RAINBOW: 'CommonGameTag' = 57453 - FUNC_CAULDRON: 'CommonGameTag' = 49155 - FUNC_CAULDRON_BG: 'CommonGameTag' = 2597 - FUNC_CAULDRON_POTION: 'CommonGameTag' = 49156 - FUNC_CELEBRITY_FAN_TARGETABLE: 'CommonGameTag' = 61475 - FUNC_CELEBRITY_TILE_ORIGINAL: 'CommonGameTag' = 61636 - FUNC_CELL: 'CommonGameTag' = 1378 - FUNC_CEMETERY: 'CommonGameTag' = 1200 - FUNC_CHAIR: 'CommonGameTag' = 1303 - FUNC_CHAIR_DEBATE_SHOWDOWN_AUDIENCE: 'CommonGameTag' = 65592 - FUNC_CHAIR_DEBATE_SHOWDOWN_JUDGE: 'CommonGameTag' = 65593 - FUNC_CHALKBOARD: 'CommonGameTag' = 1426 - FUNC_CHANGE_CLOTHES: 'CommonGameTag' = 1448 - FUNC_CHANGING_TABLE: 'CommonGameTag' = 2957 - FUNC_CHARISMA: 'CommonGameTag' = 1099 - FUNC_CHEER_MAT_GROUP: 'CommonGameTag' = 114753 - FUNC_CHEER_MAT_SOLO: 'CommonGameTag' = 114754 - FUNC_CHEF: 'CommonGameTag' = 1115 - FUNC_CHEF_STATION: 'CommonGameTag' = 26627 - FUNC_CHEM_ANALYZER: 'CommonGameTag' = 12361 - FUNC_CHEM_LAB: 'CommonGameTag' = 12360 - FUNC_CHESS: 'CommonGameTag' = 485 - FUNC_CHILD: 'CommonGameTag' = 1136 - FUNC_CHILD_VIOLIN: 'CommonGameTag' = 1176 - FUNC_CHIMNEY: 'CommonGameTag' = 1164 - FUNC_CHRISTMAS: 'CommonGameTag' = 1327 - FUNC_CLAY: 'CommonGameTag' = 511 - FUNC_CLIMBING_ROUTE: 'CommonGameTag' = 69692 - FUNC_CLIMBING_ROUTE_LARGE: 'CommonGameTag' = 69701 - FUNC_CLIMBING_ROUTE_MEDIUM: 'CommonGameTag' = 69700 - FUNC_CLIMBING_ROUTE_SMALL: 'CommonGameTag' = 69699 - FUNC_CLOBBERS_SNOW_FOOTPRINTS: 'CommonGameTag' = 2114 - FUNC_CLONE_NORMAL_MIN: 'CommonGameTag' = 12344 - FUNC_CLOSET: 'CommonGameTag' = 1139 - FUNC_CLOTHES: 'CommonGameTag' = 1162 - FUNC_CLUBS: 'CommonGameTag' = 24593 - FUNC_CLUE: 'CommonGameTag' = 12371 - FUNC_COAT_RACK: 'CommonGameTag' = 1500 - FUNC_COBWEB: 'CommonGameTag' = 1193 - FUNC_COCONUT_PLANT: 'CommonGameTag' = 63518 - FUNC_COFFEE: 'CommonGameTag' = 525 - FUNC_COFFEE_CART: 'CommonGameTag' = 65603 - FUNC_COFFEE_MAKER: 'CommonGameTag' = 1167 - FUNC_COFFIN: 'CommonGameTag' = 40970 - FUNC_COLLECTIBLE: 'CommonGameTag' = 2787 - FUNC_COLLECTION_MONSTERS: 'CommonGameTag' = 32771 - FUNC_COLLECTION_SPAWNER: 'CommonGameTag' = 12425 - FUNC_COLLECTION_WEREWOLF: 'CommonGameTag' = 2792 - FUNC_COLLECT_ARTIFACT: 'CommonGameTag' = 45075 - FUNC_COLLECT_ARTIFACT_FAKE: 'CommonGameTag' = 45076 - FUNC_COLLECT_ARTIFACT_GENUINE: 'CommonGameTag' = 45092 - FUNC_COLLECT_ARTIFACT_KNIFE: 'CommonGameTag' = 45098 - FUNC_COLLECT_ARTIFACT_MAIL: 'CommonGameTag' = 45077 - FUNC_COLLECT_ARTIFACT_MAIL_FAKE: 'CommonGameTag' = 45093 - FUNC_COLLECT_ARTIFACT_MASK: 'CommonGameTag' = 45099 - FUNC_COLLECT_ARTIFACT_SKULL: 'CommonGameTag' = 45100 - FUNC_COLLECT_ARTIFACT_STATUE: 'CommonGameTag' = 45101 - FUNC_COLLECT_ARTIFACT_VASE: 'CommonGameTag' = 45097 - FUNC_COLOR_FROM_SAND: 'CommonGameTag' = 2200 - FUNC_COMEDY: 'CommonGameTag' = 1130 - FUNC_COMEDY_ROUTINE: 'CommonGameTag' = 589 - FUNC_COMEDY_ROUTINE_LONG: 'CommonGameTag' = 594 - FUNC_COMEDY_ROUTINE_MEDIUM: 'CommonGameTag' = 593 - FUNC_COMEDY_ROUTINE_SHORT: 'CommonGameTag' = 592 - FUNC_COMMUNITY_BOARD_BG: 'CommonGameTag' = 2284 - FUNC_COMMUNITY_BOARD_EP14: 'CommonGameTag' = 118798 - FUNC_COMPUTER: 'CommonGameTag' = 514 - FUNC_COMPUTER_GLASSES: 'CommonGameTag' = 65655 - FUNC_CONCEPT_ECO_INVENTION: 'CommonGameTag' = 67612 - FUNC_CONCEPT_MUNICIPAL: 'CommonGameTag' = 67611 - FUNC_CONCRETE: 'CommonGameTag' = 1092 - FUNC_COOK: 'CommonGameTag' = 524 - FUNC_COOKING: 'CommonGameTag' = 1102 - FUNC_COOLER: 'CommonGameTag' = 10243 - FUNC_CORPORATE_WORKER_APOLOGY_GIFT: 'CommonGameTag' = 69742 - FUNC_COT: 'CommonGameTag' = 1287 - FUNC_COUCH: 'CommonGameTag' = 989 - FUNC_COUNTER: 'CommonGameTag' = 1525 - FUNC_COW: 'CommonGameTag' = 112681 - FUNC_COWPLANT: 'CommonGameTag' = 1375 - FUNC_CRAFT: 'CommonGameTag' = 513 - FUNC_CRAFTED_CANDLE: 'CommonGameTag' = 67622 - FUNC_CRAFTED_OBJECT_GENERIC: 'CommonGameTag' = 2824 - FUNC_CRAFT_SALES_TABLE: 'CommonGameTag' = 55365 - FUNC_CRAFT_SALES_TABLE_JUNGLE_SUPPLIES_FUN: 'CommonGameTag' = 2047 - FUNC_CRAFT_SALES_TABLE_JUNGLE_SUPPLIES_FURNITURE: 'CommonGameTag' = 2046 - FUNC_CRAFT_SALES_TABLE_JUNGLE_SUPPLIES_PET: 'CommonGameTag' = 2048 - FUNC_CRAFT_SALES_TABLE_JUNGLE_SUPPLIES_SUPPLIES: 'CommonGameTag' = 2045 - FUNC_CRAFT_SALES_TABLE_PAINTING: 'CommonGameTag' = 2387 - FUNC_CRAFT_SALES_TABLE_REQUIRED_OBJECT_BG: 'CommonGameTag' = 2285 - FUNC_CRAFT_SALES_TABLE_SECRET_ITEMS_COLLECTIBLES: 'CommonGameTag' = 2050 - FUNC_CRAFT_SALES_TABLE_SECRET_ITEMS_SUPPLIES: 'CommonGameTag' = 2049 - FUNC_CRAFT_SALES_TABLE_TABLE: 'CommonGameTag' = 2386 - FUNC_CRATE: 'CommonGameTag' = 12379 - FUNC_CRATES: 'CommonGameTag' = 1401 - FUNC_CRATES_ROUTABLE: 'CommonGameTag' = 57385 - FUNC_CREATIVITY: 'CommonGameTag' = 24597 - FUNC_CRIB: 'CommonGameTag' = 745 - FUNC_CRIME_MAP: 'CommonGameTag' = 12372 - FUNC_CRIMINAL: 'CommonGameTag' = 1113 - FUNC_CROSS_STITCH: 'CommonGameTag' = 2577 - FUNC_CROSS_STITCH_HOOP: 'CommonGameTag' = 2613 - FUNC_CROSS_STITCH_HOOP_COMPLETE: 'CommonGameTag' = 2614 - FUNC_CRYPT: 'CommonGameTag' = 1201 - FUNC_CRYSTAL_BALL: 'CommonGameTag' = 1184 - FUNC_CUBE: 'CommonGameTag' = 502 - FUNC_CULINARY: 'CommonGameTag' = 1114 - FUNC_CULLING_PORTAL: 'CommonGameTag' = 1546 - FUNC_CUP: 'CommonGameTag' = 1302 - FUNC_CUPBOARD: 'CommonGameTag' = 1012 - FUNC_CUPCAKE_MACHINE: 'CommonGameTag' = 1376 - FUNC_CURTAIN: 'CommonGameTag' = 1014 - FUNC_DANCEFLOOR: 'CommonGameTag' = 1455 - FUNC_DANCING: 'CommonGameTag' = 24601 - FUNC_DARTBOARD: 'CommonGameTag' = 24609 - FUNC_DAY_OF_THE_DEAD: 'CommonGameTag' = 1565 - FUNC_DEATH: 'CommonGameTag' = 575 - FUNC_DECAL: 'CommonGameTag' = 1151 - FUNC_DENIZEN_POND: 'CommonGameTag' = 2157 - FUNC_DESSERT: 'CommonGameTag' = 1386 - FUNC_DETECTIVE: 'CommonGameTag' = 12327 - FUNC_DETECTIVE_CHIEF_CHAIR: 'CommonGameTag' = 12435 - FUNC_DETECTIVE_CLUE_ADD_TO_MAP: 'CommonGameTag' = 12318 - FUNC_DETECTIVE_CLUE_CHEMICAL: 'CommonGameTag' = 12296 - FUNC_DETECTIVE_CLUE_DATABASE: 'CommonGameTag' = 12326 - FUNC_DETECTIVE_CLUE_PICTURE: 'CommonGameTag' = 12312 - FUNC_DETECTIVE_CLUE_SAMPLE: 'CommonGameTag' = 12313 - FUNC_DEW_COLLECTOR: 'CommonGameTag' = 67615 - FUNC_DEW_COLLECTOR_HIGH_QUALITY: 'CommonGameTag' = 67646 - FUNC_DIA_DE_LOS_MUERTOS: 'CommonGameTag' = 1566 - FUNC_DIGITAL_FRAME: 'CommonGameTag' = 2216 - FUNC_DINING: 'CommonGameTag' = 1124 - FUNC_DINING_CHAIR: 'CommonGameTag' = 1006 - FUNC_DINING_HUTCH: 'CommonGameTag' = 1125 - FUNC_DINOSAUR: 'CommonGameTag' = 509 - FUNC_DIPLOMA: 'CommonGameTag' = 1415 - FUNC_DIRECTOR_CHAIR: 'CommonGameTag' = 61463 - FUNC_DISABLE_AUTO_SHAPE: 'CommonGameTag' = 2551 - FUNC_DISABLE_IN_LOT_THUMBNAILS: 'CommonGameTag' = 2100 - FUNC_DISHWASHER: 'CommonGameTag' = 1451 - FUNC_DISPENSER: 'CommonGameTag' = 1419 - FUNC_DIVIDER: 'CommonGameTag' = 1033 - FUNC_DJING: 'CommonGameTag' = 24600 - FUNC_DJ_BOOTH: 'CommonGameTag' = 1456 - FUNC_DOCTOR: 'CommonGameTag' = 12328 - FUNC_DOCTOR_ITEM_SAMPLE: 'CommonGameTag' = 12330 - FUNC_DOCTOR_OBJECT_EXAM_BED: 'CommonGameTag' = 12329 - FUNC_DOCTOR_OBJECT_MEDICAL_TREADMILL: 'CommonGameTag' = 12348 - FUNC_DOCTOR_OBJECT_SURGERY_TABLE: 'CommonGameTag' = 12333 - FUNC_DOCTOR_OBJECT_XRAY_MACHINE: 'CommonGameTag' = 12332 - FUNC_DOCTOR_PLAYSET: 'CommonGameTag' = 43030 - FUNC_DOESNT_SPAWN_FIRE: 'CommonGameTag' = 1494 - FUNC_DOLL: 'CommonGameTag' = 580 - FUNC_DOLLHOUSE: 'CommonGameTag' = 666 - FUNC_DOLLY_CAMERA: 'CommonGameTag' = 61462 - FUNC_DOLPHIN_ALBINO: 'CommonGameTag' = 63492 - FUNC_DOLPHIN_MERFOLK: 'CommonGameTag' = 63493 - FUNC_DOLPHIN_SPAWNER: 'CommonGameTag' = 63494 - FUNC_DOLPHIN_STANDARD: 'CommonGameTag' = 63491 - FUNC_DONT_WAKE_LLAMA: 'CommonGameTag' = 24608 - FUNC_DOUBLE_BED: 'CommonGameTag' = 778 - FUNC_DRAGON: 'CommonGameTag' = 510 - FUNC_DRAWING_POSTED: 'CommonGameTag' = 43011 - FUNC_DRAW_SOMETHING: 'CommonGameTag' = 1003 - FUNC_DRINK: 'CommonGameTag' = 499 - FUNC_DRINK_GIFTING: 'CommonGameTag' = 2666 - FUNC_DRINK_TRAY: 'CommonGameTag' = 1552 - FUNC_DROID_BB_SERIES: 'CommonGameTag' = 51219 - FUNC_DROID_PERSONALITY_CHIP: 'CommonGameTag' = 51211 - FUNC_DROID_PERSONALITY_CHIP_FIRST_ORDER: 'CommonGameTag' = 51213 - FUNC_DROID_PERSONALITY_CHIP_FIRST_ORDER_2: 'CommonGameTag' = 51252 - FUNC_DROID_PERSONALITY_CHIP_RESISTANCE: 'CommonGameTag' = 51212 - FUNC_DROID_PERSONALITY_CHIP_RESISTANCE_2: 'CommonGameTag' = 51251 - FUNC_DROID_PERSONALITY_CHIP_SCOUNDREL: 'CommonGameTag' = 51214 - FUNC_DROID_PERSONALITY_CHIP_SCOUNDREL_2: 'CommonGameTag' = 51253 - FUNC_DROID_R_SERIES: 'CommonGameTag' = 51220 - FUNC_DROPS_LEAVES_EP10_MAPLE_GREEN: 'CommonGameTag' = 2513 - FUNC_DROPS_LEAVES_EP10_MAPLE_RED: 'CommonGameTag' = 2514 - FUNC_DROPS_LEAVES_LARGE: 'CommonGameTag' = 2063 - FUNC_DROPS_LEAVES_MEDIUM: 'CommonGameTag' = 2062 - FUNC_DROPS_LEAVES_SMALL: 'CommonGameTag' = 2056 - FUNC_DROPS_LEAVES_X_LARGE: 'CommonGameTag' = 2064 - FUNC_DUCT: 'CommonGameTag' = 1428 - FUNC_DUMPSTER: 'CommonGameTag' = 67605 - FUNC_DUMPSTER_DEAL_APPLIANCE: 'CommonGameTag' = 2446 - FUNC_DUMPSTER_DEAL_BURNT_AND_SCRATCHED: 'CommonGameTag' = 2445 - FUNC_DUMPSTER_DEAL_COLLECTIBLE: 'CommonGameTag' = 2454 - FUNC_DUMPSTER_DEAL_CRAFTABLE: 'CommonGameTag' = 2455 - FUNC_DUMPSTER_DEAL_MISCELLANEOUS: 'CommonGameTag' = 2448 - FUNC_DUMPSTER_DEAL_PLUMBING: 'CommonGameTag' = 2447 - FUNC_DUMPSTER_DEAL_UPGRADE_PART: 'CommonGameTag' = 2456 - FUNC_DUMPSTER_HIGH_PRICE_DROP: 'CommonGameTag' = 67610 - FUNC_DUMPSTER_INSECT: 'CommonGameTag' = 67645 - FUNC_DUMPSTER_LOW_PRICE_DROP: 'CommonGameTag' = 67609 - FUNC_DUMPSTER_MEAL_FOOD: 'CommonGameTag' = 2452 - FUNC_DUMPSTER_MEAL_INGREDIENT: 'CommonGameTag' = 2451 - FUNC_DUMPSTER_MEAL_INSECT: 'CommonGameTag' = 2453 - FUNC_DUMPSTER_UNIQUE_DROP: 'CommonGameTag' = 67608 - FUNC_DUST_BUNNY: 'CommonGameTag' = 94216 - FUNC_DUST_FRIEND: 'CommonGameTag' = 94215 - FUNC_DUST_PILE: 'CommonGameTag' = 94209 - FUNC_EARBUDS: 'CommonGameTag' = 1725 - FUNC_EASEL: 'CommonGameTag' = 482 - FUNC_EASTER_EGG: 'CommonGameTag' = 2082 - FUNC_ECO_ECO_FRIENDLY_APPLIANCES: 'CommonGameTag' = 2375 - FUNC_ECO_FOOTPRINT_OBJECT_STATE: 'CommonGameTag' = 2376 - FUNC_ECO_FOOTPRINT_SUN_RAY: 'CommonGameTag' = 67588 - FUNC_ECO_GREEN_GARDENING: 'CommonGameTag' = 2374 - FUNC_ECO_NEIGHBORHOOD_UTILITY: 'CommonGameTag' = 2372 - FUNC_ECO_UPCYCLING_INITIATIVE: 'CommonGameTag' = 2373 - FUNC_EGG: 'CommonGameTag' = 2576 - FUNC_EGG_SEARCH: 'CommonGameTag' = 112685 - FUNC_ENERGY: 'CommonGameTag' = 997 - FUNC_ENHANCED_SMELL: 'CommonGameTag' = 135183 - FUNC_ENTERTAINER: 'CommonGameTag' = 1129 - FUNC_ENTERTAINMENT_CENTER: 'CommonGameTag' = 2940 - FUNC_EP01_ALIEN_TRANSMUTE_COMPATIBLE: 'CommonGameTag' = 12369 - FUNC_EP01_COLLECTIBLE_BG: 'CommonGameTag' = 2038 - FUNC_EP01_SERUM_AGE_AWAY: 'CommonGameTag' = 12422 - FUNC_EP01_SERUM_ALIEN_AURA: 'CommonGameTag' = 12421 - FUNC_EP01_SERUM_EMBIGGEN: 'CommonGameTag' = 12416 - FUNC_EP01_SERUM_FIXERS_LUCK: 'CommonGameTag' = 12419 - FUNC_EP01_SERUM_GHOST_GOO: 'CommonGameTag' = 12417 - FUNC_EP01_SERUM_NEED_FIXER: 'CommonGameTag' = 12354 - FUNC_EP01_SERUM_OX_STRENGTH: 'CommonGameTag' = 12418 - FUNC_EP01_SERUM_REAPERS_FRIEND: 'CommonGameTag' = 12420 - FUNC_EP01_SERUM_RED_HOT: 'CommonGameTag' = 12414 - FUNC_EP01_SERUM_ROSE_PERFUME: 'CommonGameTag' = 12352 - FUNC_EP01_SERUM_SLIMIFY: 'CommonGameTag' = 12415 - FUNC_EP01_SERUM_SMART: 'CommonGameTag' = 12356 - FUNC_EP01_SERUM_SNAKE_OIL: 'CommonGameTag' = 12353 - FUNC_EP01_SERUM_SPARK_DRIVE: 'CommonGameTag' = 12355 - FUNC_EP01_SERUM_SYNTHETIC_FOOD: 'CommonGameTag' = 12351 - FUNC_EP10_FESTIVAL_FOOD: 'CommonGameTag' = 69732 - FUNC_EQUESTRIAN_CENTER: 'CommonGameTag' = 118871 - FUNC_ESPORTS_GAMER: 'CommonGameTag' = 1134 - FUNC_ESPRESSO_BAR: 'CommonGameTag' = 1452 - FUNC_ESPRESSO_GRINDER: 'CommonGameTag' = 1454 - FUNC_ESPRESSO_MACHINE: 'CommonGameTag' = 1453 - FUNC_ETAGERE: 'CommonGameTag' = 1035 - FUNC_EXERCISE: 'CommonGameTag' = 473 - FUNC_EXIT: 'CommonGameTag' = 1416 - FUNC_EXPERIMENTAL_FOOD: 'CommonGameTag' = 26631 - FUNC_EXTINGUISHER: 'CommonGameTag' = 1417 - FUNC_FABRICATED_ITEM: 'CommonGameTag' = 67587 - FUNC_FABRICATION_DYE: 'CommonGameTag' = 67590 - FUNC_FABRICATION_DYE_COMMON: 'CommonGameTag' = 67637 - FUNC_FABRICATOR: 'CommonGameTag' = 67586 - FUNC_FACE: 'CommonGameTag' = 1214 - FUNC_FACIAL_MASK: 'CommonGameTag' = 18472 - FUNC_FAMILY_BULLETIN_BOARD: 'CommonGameTag' = 43016 - FUNC_FAN: 'CommonGameTag' = 1414 - FUNC_FASHION_STUDIO_SEARCH: 'CommonGameTag' = 2220 - FUNC_FAUCET: 'CommonGameTag' = 1138 - FUNC_FAVORITE_CHOPSTICKS: 'CommonGameTag' = 69685 - FUNC_FAVORITE_CHOPSTICK_CLASSIC_WOOD: 'CommonGameTag' = 69741 - FUNC_FAVORITE_CHOPSTICK_PLASTIC: 'CommonGameTag' = 69687 - FUNC_FAVORITE_CHOPSTICK_STEEL: 'CommonGameTag' = 69688 - FUNC_FAVORITE_CHOPSTICK_WOOD: 'CommonGameTag' = 69686 - FUNC_FESTIVAL_AUTONOMY_AREA_MARKER: 'CommonGameTag' = 1575 - FUNC_FESTIVAL_AUTONOMY_AREA_MARKER: 'CommonGameTag' = 55297 - FUNC_FESTIVAL_BLOSSOM_TEA_FOUNTAIN: 'CommonGameTag' = 55388 - FUNC_FESTIVAL_CURRY_CONTEST: 'CommonGameTag' = 55369 - FUNC_FESTIVAL_FIREWORKS_DARK_SIDE: 'CommonGameTag' = 55366 - FUNC_FESTIVAL_FIREWORKS_LIGHT_SIDE: 'CommonGameTag' = 55367 - FUNC_FESTIVAL_FLEA_MARKET_OBJECTS: 'CommonGameTag' = 55392 - FUNC_FESTIVAL_LAMP_TEA_FOUNTAINS: 'CommonGameTag' = 55387 - FUNC_FESTIVAL_TEA_DARK_TEA: 'CommonGameTag' = 55345 - FUNC_FESTIVAL_TEA_LIGHT_TEA: 'CommonGameTag' = 55346 - FUNC_FESTIVAL_TEA_SAKURA: 'CommonGameTag' = 55347 - FUNC_FETCHABLE: 'CommonGameTag' = 1875 - FUNC_FIGURINE: 'CommonGameTag' = 1157 - FUNC_FILE_HOLDER: 'CommonGameTag' = 1425 - FUNC_FILTH_FIEND: 'CommonGameTag' = 94217 - FUNC_FIRE: 'CommonGameTag' = 1305 - FUNC_FIREPLACE_MAGIC: 'CommonGameTag' = 49183 - FUNC_FIREWORKS: 'CommonGameTag' = 1578 - FUNC_FIREWORKS_ARTS_CRAFTS: 'CommonGameTag' = 1588 - FUNC_FIREWORKS_BLOSSOM: 'CommonGameTag' = 1583 - FUNC_FIREWORKS_FOOD: 'CommonGameTag' = 1586 - FUNC_FIREWORKS_LAMP: 'CommonGameTag' = 1585 - FUNC_FIREWORKS_LOGIC: 'CommonGameTag' = 1584 - FUNC_FIREWORKS_MUSIC: 'CommonGameTag' = 1587 - FUNC_FIREWORKS_SPARKLER: 'CommonGameTag' = 1590 - FUNC_FIREWORKS_SPARKLER_BLOSSOM: 'CommonGameTag' = 55408 - FUNC_FIREWORKS_SPARKLER_FOOD: 'CommonGameTag' = 55409 - FUNC_FIREWORKS_SPARKLER_LAMP: 'CommonGameTag' = 55410 - FUNC_FIREWORKS_SPARKLER_LOGIC: 'CommonGameTag' = 55411 - FUNC_FIREWORKS_SPARKLER_WEDDING: 'CommonGameTag' = 55412 - FUNC_FIREWORKS_WEDDING: 'CommonGameTag' = 1589 - FUNC_FIRE_ALARM: 'CommonGameTag' = 1165 - FUNC_FIRE_PIT: 'CommonGameTag' = 1306 - FUNC_FISH: 'CommonGameTag' = 992 - FUNC_FISHING_LOCATION_ANY: 'CommonGameTag' = 2164 - FUNC_FISHING_LOCATION_HOLE: 'CommonGameTag' = 937 - FUNC_FISHING_LOCATION_SPOT: 'CommonGameTag' = 938 - FUNC_FISHING_SPOT_BAY: 'CommonGameTag' = 63528 - FUNC_FISHING_SPOT_COMMON: 'CommonGameTag' = 2193 - FUNC_FISHING_SPOT_RARE: 'CommonGameTag' = 2192 - FUNC_FISHING_SPOT_TROPICAL: 'CommonGameTag' = 63526 - FUNC_FISHING_SPOT_UNCOMMON: 'CommonGameTag' = 2191 - FUNC_FISH_ENDANGERED: 'CommonGameTag' = 63503 - FUNC_FISH_FISHBOWL: 'CommonGameTag' = 869 - FUNC_FISH_INVASIVE: 'CommonGameTag' = 2195 - FUNC_FITNESS: 'CommonGameTag' = 474 - FUNC_FLAG: 'CommonGameTag' = 1403 - FUNC_FLAGSTONE: 'CommonGameTag' = 1094 - FUNC_FLOWER: 'CommonGameTag' = 1314 - FUNC_FLOWERS_10: 'CommonGameTag' = 59490 - FUNC_FLOWERS_3: 'CommonGameTag' = 59483 - FUNC_FLOWERS_4: 'CommonGameTag' = 59484 - FUNC_FLOWERS_5: 'CommonGameTag' = 59485 - FUNC_FLOWERS_6: 'CommonGameTag' = 59486 - FUNC_FLOWERS_7: 'CommonGameTag' = 59487 - FUNC_FLOWERS_8: 'CommonGameTag' = 59488 - FUNC_FLOWERS_9: 'CommonGameTag' = 59489 - FUNC_FLOWERS_BOP_BEG: 'CommonGameTag' = 2106 - FUNC_FLOWERS_CHRY_SNAP: 'CommonGameTag' = 2104 - FUNC_FLOWERS_DAI_BLU: 'CommonGameTag' = 2102 - FUNC_FLOWERS_LILY_DEATH: 'CommonGameTag' = 2107 - FUNC_FLOWERS_ROS_DAH: 'CommonGameTag' = 2103 - FUNC_FLOWERS_SCENT: 'CommonGameTag' = 2090 - FUNC_FLOWERS_SCENT_RARE: 'CommonGameTag' = 2091 - FUNC_FLOWERS_SNO_CROC: 'CommonGameTag' = 2101 - FUNC_FLOWERS_TUL_CHRI: 'CommonGameTag' = 2105 - FUNC_FLOWER_ARRANGEMENT: 'CommonGameTag' = 59457 - FUNC_FLOWER_GIFTING: 'CommonGameTag' = 2668 - FUNC_FOLDERS: 'CommonGameTag' = 1412 - FUNC_FOLDING: 'CommonGameTag' = 1304 - FUNC_FOOD: 'CommonGameTag' = 520 - FUNC_FOOD_PET_EDIBLE: 'CommonGameTag' = 2030 - FUNC_FOOD_PLATTER: 'CommonGameTag' = 26643 - FUNC_FOOSBALL_TABLE: 'CommonGameTag' = 24591 - FUNC_FORAGED_PLANT: 'CommonGameTag' = 2698 - FUNC_FORTUNE: 'CommonGameTag' = 1180 - FUNC_FORTUNE_TELLING: 'CommonGameTag' = 8200 - FUNC_FOSSIL_BRUSHED: 'CommonGameTag' = 2044 - FUNC_FOSSIL_ROCK: 'CommonGameTag' = 2037 - FUNC_FOUNTAIN: 'CommonGameTag' = 8216 - FUNC_FOX: 'CommonGameTag' = 2591 - FUNC_FOX_DEN: 'CommonGameTag' = 2629 - FUNC_FREELANCER_CANVAS_CHARACTER_DESIGN: 'CommonGameTag' = 2177 - FUNC_FREELANCER_CANVAS_ENVIRONMENT_DESIGN: 'CommonGameTag' = 2178 - FUNC_FREELANCER_CANVAS_ICON: 'CommonGameTag' = 2183 - FUNC_FREELANCER_CANVAS_ILLUSTRATIVE: 'CommonGameTag' = 2184 - FUNC_FREELANCER_CANVAS_LOGO: 'CommonGameTag' = 2182 - FUNC_FREELANCER_CANVAS_PORTRAIT: 'CommonGameTag' = 2179 - FUNC_FREELANCER_CANVAS_RECREATED_ART: 'CommonGameTag' = 2181 - FUNC_FREELANCER_CANVAS_REFERENCE: 'CommonGameTag' = 2185 - FUNC_FREELANCER_CANVAS_SPLASH_ART: 'CommonGameTag' = 2180 - FUNC_FREELANCE_MAKER_CARVED_CANDLES: 'CommonGameTag' = 67599 - FUNC_FREELANCE_MAKER_COUCH: 'CommonGameTag' = 67596 - FUNC_FREELANCE_MAKER_CRAFTED_CANDLES: 'CommonGameTag' = 67601 - FUNC_FREELANCE_MAKER_FINE_WALL_DECOR: 'CommonGameTag' = 67602 - FUNC_FREELANCE_MAKER_FLOOR_LIGHTS: 'CommonGameTag' = 67598 - FUNC_FREELANCE_MAKER_JAR_CANDLES: 'CommonGameTag' = 67595 - FUNC_FREELANCE_MAKER_KIDS_BED: 'CommonGameTag' = 67600 - FUNC_FREELANCE_MAKER_KOMBUCHA: 'CommonGameTag' = 67597 - FUNC_FREELANCE_MAKER_RUGS: 'CommonGameTag' = 67593 - FUNC_FREELANCE_MAKER_TOFIZZ: 'CommonGameTag' = 67594 - FUNC_FRIDGE: 'CommonGameTag' = 1002 - FUNC_FRIDGE_MINI: 'CommonGameTag' = 2233 - FUNC_FRIDGE_SKIN_CARE: 'CommonGameTag' = 18471 - FUNC_FRIENDSHIP_BRACELET: 'CommonGameTag' = 116749 - FUNC_FROG_PUMP: 'CommonGameTag' = 2798 - FUNC_FRONT_DESK: 'CommonGameTag' = 12331 - FUNC_FROSTY: 'CommonGameTag' = 1337 - FUNC_FRUIT_CAKE: 'CommonGameTag' = 1445 - FUNC_FRUIT_PUNCH_FOUNTAIN: 'CommonGameTag' = 8214 - FUNC_FRYING_PAN: 'CommonGameTag' = 2449 - FUNC_FUN: 'CommonGameTag' = 999 - FUNC_FUTURE: 'CommonGameTag' = 503 - FUNC_GAME: 'CommonGameTag' = 481 - FUNC_GAMING: 'CommonGameTag' = 1075 - FUNC_GARBAGE: 'CommonGameTag' = 924 - FUNC_GARDEN: 'CommonGameTag' = 1150 - FUNC_GARDENING: 'CommonGameTag' = 1107 - FUNC_GARDENING_FERTILIZER_BAD: 'CommonGameTag' = 862 - FUNC_GARDENING_FERTILIZER_HIGH: 'CommonGameTag' = 859 - FUNC_GARDENING_FERTILIZER_LOW: 'CommonGameTag' = 861 - FUNC_GARDENING_FERTILIZER_MAX: 'CommonGameTag' = 870 - FUNC_GARDENING_FERTILIZER_MED: 'CommonGameTag' = 860 - FUNC_GARDENING_FLOWERS: 'CommonGameTag' = 59463 - FUNC_GARDENING_FORBIDDEN_FRUIT: 'CommonGameTag' = 1708 - FUNC_GARDENING_GRAFTABLE: 'CommonGameTag' = 2092 - FUNC_GARDENING_GROWFRUIT: 'CommonGameTag' = 1502 - FUNC_GARDENING_MONEY_TREE: 'CommonGameTag' = 59482 - FUNC_GARDENING_PATCH: 'CommonGameTag' = 112641 - FUNC_GARDENING_SEEDS: 'CommonGameTag' = 1029 - FUNC_GARDENING_SEED_COMMON: 'CommonGameTag' = 831 - FUNC_GARDENING_SEED_RARE: 'CommonGameTag' = 833 - FUNC_GARDENING_SEED_UNCOMMON: 'CommonGameTag' = 832 - FUNC_GARDENING_SKILL_PLANT: 'CommonGameTag' = 1721 - FUNC_GARDENING_SPRINKLER: 'CommonGameTag' = 59437 - FUNC_GARDENING_TOXIC: 'CommonGameTag' = 10254 - FUNC_GARDENING_WILD: 'CommonGameTag' = 1272 - FUNC_GARDEN_FLOWER: 'CommonGameTag' = 2781 - FUNC_GARDEN_GARLIC: 'CommonGameTag' = 40971 - FUNC_GARDEN_GHOST_DESTROY: 'CommonGameTag' = 2176 - FUNC_GARDEN_PLASMA_TREE: 'CommonGameTag' = 40973 - FUNC_GARLAND: 'CommonGameTag' = 1334 - FUNC_GARLIC: 'CommonGameTag' = 40962 - FUNC_GATE: 'CommonGameTag' = 1390 - FUNC_GATOR: 'CommonGameTag' = 112694 - FUNC_GETS_DIRTY: 'CommonGameTag' = 2516 - FUNC_GHOST: 'CommonGameTag' = 1190 - FUNC_GIANT_CROPS_FERTILIZER: 'CommonGameTag' = 112642 - FUNC_GIANT_CROPS_FRUIT: 'CommonGameTag' = 112645 - FUNC_GIANT_CROPS_FRUIT_GIANT_MUSHROOM: 'CommonGameTag' = 112680 - FUNC_GIANT_CROPS_PLANT: 'CommonGameTag' = 112644 - FUNC_GIANT_CROPS_SEED_PACKET: 'CommonGameTag' = 112643 - FUNC_GIANT_CROP_LARGE: 'CommonGameTag' = 2612 - FUNC_GIANT_CROP_MEDIUM: 'CommonGameTag' = 2611 - FUNC_GIANT_CROP_SMALL: 'CommonGameTag' = 2610 - FUNC_GIVE_GIFT_NOT_GIFTABLE: 'CommonGameTag' = 2160 - FUNC_GIVE_GIFT_REWARD: 'CommonGameTag' = 2088 - FUNC_GLASS: 'CommonGameTag' = 1432 - FUNC_GNOME: 'CommonGameTag' = 1365 - FUNC_GNOME_KICK_REWARD: 'CommonGameTag' = 2087 - FUNC_GONDOLA_BOTTOM: 'CommonGameTag' = 69654 - FUNC_GONDOLA_TOP: 'CommonGameTag' = 69653 - FUNC_GOURMET_COOKING: 'CommonGameTag' = 1104 - FUNC_GO_DANCING_OBJECT_VISIBILITY: 'CommonGameTag' = 24587 - FUNC_GO_FOR_WALK_DOG_INTERACTIONS: 'CommonGameTag' = 57395 - FUNC_GRAFFITI: 'CommonGameTag' = 55403 - FUNC_GRAND_MEAL: 'CommonGameTag' = 2095 - FUNC_GRASS: 'CommonGameTag' = 1093 - FUNC_GRAVE: 'CommonGameTag' = 1198 - FUNC_GRAVESTONE: 'CommonGameTag' = 1203 - FUNC_GREEN_SCREEN: 'CommonGameTag' = 61465 - FUNC_GRILL_RECIPE: 'CommonGameTag' = 1247 - FUNC_GUITAR: 'CommonGameTag' = 565 - FUNC_GYM: 'CommonGameTag' = 562 - FUNC_GYPSY: 'CommonGameTag' = 1183 - FUNC_HABITAT: 'CommonGameTag' = 77826 - FUNC_HAIR_MAKEUP_CHAIR: 'CommonGameTag' = 61442 - FUNC_HAIR_PILE: 'CommonGameTag' = 57411 - FUNC_HALLOWEEN: 'CommonGameTag' = 1179 - FUNC_HAMPER: 'CommonGameTag' = 75783 - FUNC_HAMSTER: 'CommonGameTag' = 77828 - FUNC_HAND: 'CommonGameTag' = 1209 - FUNC_HANDINESS: 'CommonGameTag' = 1100 - FUNC_HANUKKAH: 'CommonGameTag' = 1329 - FUNC_HARDWOOD: 'CommonGameTag' = 1095 - FUNC_HARVESTABLE: 'CommonGameTag' = 2126 - FUNC_HARVESTABLE_COW: 'CommonGameTag' = 2590 - FUNC_HARVESTABLE_FRUIT: 'CommonGameTag' = 2592 - FUNC_HARVESTABLE_LARGE: 'CommonGameTag' = 2587 - FUNC_HARVESTABLE_RARE: 'CommonGameTag' = 2072 - FUNC_HARVESTABLE_SUPER_RARE: 'CommonGameTag' = 2074 - FUNC_HARVESTABLE_UNCOMMON: 'CommonGameTag' = 2073 - FUNC_HARVESTABLE_WALL: 'CommonGameTag' = 2588 - FUNC_HAUNTED: 'CommonGameTag' = 1223 - FUNC_HAUNTED_PAINTING: 'CommonGameTag' = 86028 - FUNC_HEAD: 'CommonGameTag' = 1213 - FUNC_HEALTH: 'CommonGameTag' = 475 - FUNC_HEART: 'CommonGameTag' = 1369 - FUNC_HEAT_LAMP: 'CommonGameTag' = 14338 - FUNC_HEAT_LAMP_BG: 'CommonGameTag' = 1520 - FUNC_HEDGEHOG: 'CommonGameTag' = 77829 - FUNC_HEN: 'CommonGameTag' = 112684 - FUNC_HERBALISM: 'CommonGameTag' = 10249 - FUNC_HERBALISM_INGREDIENT: 'CommonGameTag' = 10251 - FUNC_HERBALISM_INGREDIENT_CHAMOMILE: 'CommonGameTag' = 10271 - FUNC_HERBALISM_INGREDIENT_ELDERBERRY: 'CommonGameTag' = 10272 - FUNC_HERBALISM_INGREDIENT_FIRELEAF: 'CommonGameTag' = 10273 - FUNC_HERBALISM_INGREDIENT_HUCKLEBERRY: 'CommonGameTag' = 10274 - FUNC_HERBALISM_INGREDIENT_MOREL_MUSHROOM: 'CommonGameTag' = 10275 - FUNC_HERBALISM_PLANT: 'CommonGameTag' = 10250 - FUNC_HERBALISM_POTION: 'CommonGameTag' = 10255 - FUNC_HIDEABLE: 'CommonGameTag' = 1914 - FUNC_HIGH_CHAIR: 'CommonGameTag' = 1654 - FUNC_HIGH_CHAIR_DRINK: 'CommonGameTag' = 1695 - FUNC_HIGH_CHAIR_FOOD: 'CommonGameTag' = 1694 - FUNC_HIGH_SCHOOL_ACTIVE_AMPHITHEATRE: 'CommonGameTag' = 114709 - FUNC_HIGH_SCHOOL_ACTIVE_CAFETERIA_STATION: 'CommonGameTag' = 114693 - FUNC_HIGH_SCHOOL_ACTIVE_CAREER_DAY_TABLE: 'CommonGameTag' = 114731 - FUNC_HIGH_SCHOOL_ACTIVE_EXAM_BOOK: 'CommonGameTag' = 114690 - FUNC_HIGH_SCHOOL_ACTIVE_FIELD: 'CommonGameTag' = 114708 - FUNC_HIGH_SCHOOL_ACTIVE_PRINCIPAL_DESK: 'CommonGameTag' = 114717 - FUNC_HIGH_SCHOOL_ACTIVE_SPEAKER: 'CommonGameTag' = 114700 - FUNC_HIGH_SCHOOL_ACTIVE_WHITEBOARD: 'CommonGameTag' = 114691 - FUNC_HIGH_SCHOOL_ACTIVE_WORK_BOOK: 'CommonGameTag' = 114689 - FUNC_HIGH_SCHOOL_PROM_BULLETIN_BOARD: 'CommonGameTag' = 114716 - FUNC_HIGH_SCHOOL_PROM_DRINK_FOUNTAIN: 'CommonGameTag' = 114719 - FUNC_HIGH_SCHOOL_PROM_PODIUM: 'CommonGameTag' = 2822 - FUNC_HOLIDAY: 'CommonGameTag' = 1326 - FUNC_HOLIDAY_CANDLE: 'CommonGameTag' = 2128 - FUNC_HOLIDAY_CANDLE_2: 'CommonGameTag' = 59478 - FUNC_HOLIDAY_DECO_OBJECTS: 'CommonGameTag' = 2098 - FUNC_HOLIDAY_FESTIVE_LIGHTING: 'CommonGameTag' = 2129 - FUNC_HOLIDAY_GNOME_GROUP01: 'CommonGameTag' = 2121 - FUNC_HOLIDAY_GNOME_GROUP02: 'CommonGameTag' = 2122 - FUNC_HOLIDAY_GNOME_GROUP03: 'CommonGameTag' = 2123 - FUNC_HOLIDAY_GNOME_GROUP04: 'CommonGameTag' = 2124 - FUNC_HOLIDAY_TRADITION_BAKING_RECIPE: 'CommonGameTag' = 2116 - FUNC_HOLIDAY_TRADITION_BONFIRE: 'CommonGameTag' = 2109 - FUNC_HOLIDAY_TRADITION_DECO_BE_ROMANTIC: 'CommonGameTag' = 2108 - FUNC_HOLIDAY_TRADITION_HAVE_DECORATIONS: 'CommonGameTag' = 2110 - FUNC_HOLIDAY_TRADITION_OPEN_PRESENTS: 'CommonGameTag' = 2111 - FUNC_HOLIDAY_TRADITION_PARTY: 'CommonGameTag' = 2112 - FUNC_HOLIDAY_TREE: 'CommonGameTag' = 59409 - FUNC_HOLIDAY_TREE_GARLAND: 'CommonGameTag' = 59412 - FUNC_HOLIDAY_TREE_ORNAMENTS: 'CommonGameTag' = 59411 - FUNC_HOLIDAY_TREE_SKIRT: 'CommonGameTag' = 59413 - FUNC_HOLIDAY_TREE_TOPPER: 'CommonGameTag' = 59414 - FUNC_HOLOTABLE: 'CommonGameTag' = 51223 - FUNC_HOLOTABLE_FIRST_ORDER_PURCHASE: 'CommonGameTag' = 51207 - FUNC_HOLOTABLE_RESISTANCE_PURCHASE: 'CommonGameTag' = 51208 - FUNC_HONEY: 'CommonGameTag' = 59450 - FUNC_HOOD: 'CommonGameTag' = 1168 - FUNC_HOOP: 'CommonGameTag' = 553 - FUNC_HORSE: 'CommonGameTag' = 118906 - FUNC_HORSE_BARRELS: 'CommonGameTag' = 118883 - FUNC_HORSE_BED: 'CommonGameTag' = 118787 - FUNC_HORSE_JUMPS: 'CommonGameTag' = 118882 - FUNC_HORSE_MANURE: 'CommonGameTag' = 2978 - FUNC_HORSE_TOY: 'CommonGameTag' = 118797 - FUNC_HOSPITAL: 'CommonGameTag' = 1377 - FUNC_HOST_STATION: 'CommonGameTag' = 26628 - FUNC_HOT_SAUCE: 'CommonGameTag' = 1300 - FUNC_HOT_SPRINGS: 'CommonGameTag' = 69675 - FUNC_HOT_TUB: 'CommonGameTag' = 1444 - FUNC_HOUSE: 'CommonGameTag' = 1224 - FUNC_HOUSEHOLD_INVENTORY_OBJECT_PROXY: 'CommonGameTag' = 2388 - FUNC_HUNGER: 'CommonGameTag' = 996 - FUNC_HUTCH: 'CommonGameTag' = 1030 - FUNC_HYDRAULIC: 'CommonGameTag' = 1429 - FUNC_HYGIENE: 'CommonGameTag' = 998 - FUNC_ICE_CHEST: 'CommonGameTag' = 1249 - FUNC_ICE_CREAM: 'CommonGameTag' = 20486 - FUNC_ICE_CREAM_BOWL: 'CommonGameTag' = 20483 - FUNC_ICE_CREAM_CARTON: 'CommonGameTag' = 20482 - FUNC_ICE_CREAM_CONE: 'CommonGameTag' = 20484 - FUNC_ICE_CREAM_MACHINE: 'CommonGameTag' = 20481 - FUNC_ICE_CREAM_MILK_SHAKE: 'CommonGameTag' = 20485 - FUNC_IMPORTANT_ITEMS: 'CommonGameTag' = 2283 - FUNC_INCENSE: 'CommonGameTag' = 18442 - FUNC_INFANT_CRIB: 'CommonGameTag' = 2913 - FUNC_INFANT_MESMERIZE: 'CommonGameTag' = 2946 - FUNC_INFANT_PLAY_MAT: 'CommonGameTag' = 2914 - FUNC_INFECTED_PLANT: 'CommonGameTag' = 47129 - FUNC_INFLATABLE: 'CommonGameTag' = 1286 - FUNC_INFO_BOARD: 'CommonGameTag' = 69714 - FUNC_INGREDIENT: 'CommonGameTag' = 523 - FUNC_INGREDIENT_APPLE: 'CommonGameTag' = 2654 - FUNC_INGREDIENT_ARTISAN_HERB_BREAD: 'CommonGameTag' = 12302 - FUNC_INGREDIENT_AUBERGINE: 'CommonGameTag' = 112648 - FUNC_INGREDIENT_AUBERGINE_BG: 'CommonGameTag' = 2616 - FUNC_INGREDIENT_BEETLE: 'CommonGameTag' = 10253 - FUNC_INGREDIENT_BERRY: 'CommonGameTag' = 2584 - FUNC_INGREDIENT_BLACKBERRY: 'CommonGameTag' = 2651 - FUNC_INGREDIENT_BLUEBERRY: 'CommonGameTag' = 2620 - FUNC_INGREDIENT_BREAD: 'CommonGameTag' = 2595 - FUNC_INGREDIENT_CHEESE: 'CommonGameTag' = 2593 - FUNC_INGREDIENT_CHOCOLATE: 'CommonGameTag' = 2607 - FUNC_INGREDIENT_COWBERRY_JAM_OR_HONEY: 'CommonGameTag' = 2586 - FUNC_INGREDIENT_COWPLANT_ESSENCE: 'CommonGameTag' = 12373 - FUNC_INGREDIENT_CRAWDAD: 'CommonGameTag' = 10241 - FUNC_INGREDIENT_CROSS_STITCH_WOOL: 'CommonGameTag' = 112650 - FUNC_INGREDIENT_CRYSTAL: 'CommonGameTag' = 1345 - FUNC_INGREDIENT_CRYSTAL_ALIEN: 'CommonGameTag' = 12386 - FUNC_INGREDIENT_CRYSTAL_COMMON: 'CommonGameTag' = 1349 - FUNC_INGREDIENT_CRYSTAL_RARE: 'CommonGameTag' = 1351 - FUNC_INGREDIENT_CRYSTAL_UNCOMMON: 'CommonGameTag' = 1350 - FUNC_INGREDIENT_EXOTIC_FRUIT_PIE: 'CommonGameTag' = 12305 - FUNC_INGREDIENT_EXOTIC_FRUIT_TART: 'CommonGameTag' = 12301 - FUNC_INGREDIENT_FISH: 'CommonGameTag' = 817 - FUNC_INGREDIENT_FISH_PIE: 'CommonGameTag' = 12303 - FUNC_INGREDIENT_FISH_PUFFERFISH: 'CommonGameTag' = 55335 - FUNC_INGREDIENT_FIZZY_JUICE: 'CommonGameTag' = 67631 - FUNC_INGREDIENT_FIZZY_JUICE_EP09: 'CommonGameTag' = 2429 - FUNC_INGREDIENT_FLOUR_OR_SUGAR: 'CommonGameTag' = 2618 - FUNC_INGREDIENT_FRUIT: 'CommonGameTag' = 795 - FUNC_INGREDIENT_FRUITCAKE_SET1: 'CommonGameTag' = 12307 - FUNC_INGREDIENT_FRUITCAKE_SET2: 'CommonGameTag' = 12308 - FUNC_INGREDIENT_FRUIT_MUFFINS: 'CommonGameTag' = 12298 - FUNC_INGREDIENT_FRUIT_OR_VEGGIE: 'CommonGameTag' = 2585 - FUNC_INGREDIENT_FRUIT_SCONES: 'CommonGameTag' = 12299 - FUNC_INGREDIENT_GRIMBUCHA_EP09: 'CommonGameTag' = 2432 - FUNC_INGREDIENT_HERB: 'CommonGameTag' = 816 - FUNC_INGREDIENT_INFECTED_SPORE: 'CommonGameTag' = 47142 - FUNC_INGREDIENT_INSECT: 'CommonGameTag' = 1242 - FUNC_INGREDIENT_JELLY_FILLED_DOUGHNUTS: 'CommonGameTag' = 12306 - FUNC_INGREDIENT_JELLY_OR_JAM: 'CommonGameTag' = 2619 - FUNC_INGREDIENT_KOMBUCHA: 'CommonGameTag' = 67632 - FUNC_INGREDIENT_KOMBUCHA_EP09: 'CommonGameTag' = 2430 - FUNC_INGREDIENT_LETTUCE: 'CommonGameTag' = 112646 - FUNC_INGREDIENT_LETTUCE_BG: 'CommonGameTag' = 2615 - FUNC_INGREDIENT_LOCUST: 'CommonGameTag' = 10242 - FUNC_INGREDIENT_MEAT: 'CommonGameTag' = 2594 - FUNC_INGREDIENT_MEAT_RED: 'CommonGameTag' = 2785 - FUNC_INGREDIENT_MEAT_SUBSTITUTE: 'CommonGameTag' = 2630 - FUNC_INGREDIENT_MEAT_SUBSTITUTE_SOURCE: 'CommonGameTag' = 2631 - FUNC_INGREDIENT_METAL: 'CommonGameTag' = 1344 - FUNC_INGREDIENT_METAL_ALIEN: 'CommonGameTag' = 12387 - FUNC_INGREDIENT_METAL_COMMON: 'CommonGameTag' = 1346 - FUNC_INGREDIENT_METAL_RARE: 'CommonGameTag' = 1348 - FUNC_INGREDIENT_METAL_UNCOMMON: 'CommonGameTag' = 1347 - FUNC_INGREDIENT_MILK_OR_EGGS: 'CommonGameTag' = 2648 - FUNC_INGREDIENT_MUSHROOM: 'CommonGameTag' = 1243 - FUNC_INGREDIENT_PLANT_ALIEN: 'CommonGameTag' = 12388 - FUNC_INGREDIENT_PUMPKIN: 'CommonGameTag' = 112647 - FUNC_INGREDIENT_PUMPKIN_BG: 'CommonGameTag' = 2617 - FUNC_INGREDIENT_RAINBOW_GELATIN_CAKE_SET1: 'CommonGameTag' = 12309 - FUNC_INGREDIENT_RAINBOW_GELATIN_CAKE_SET2: 'CommonGameTag' = 12310 - FUNC_INGREDIENT_RASPBERRY: 'CommonGameTag' = 2652 - FUNC_INGREDIENT_ROSE_QUARTZ: 'CommonGameTag' = 12364 - FUNC_INGREDIENT_SELTZER: 'CommonGameTag' = 67633 - FUNC_INGREDIENT_STANDARD_FRUIT_PIE: 'CommonGameTag' = 12304 - FUNC_INGREDIENT_STANDARD_FRUIT_TART: 'CommonGameTag' = 12300 - FUNC_INGREDIENT_STRAWBERRY: 'CommonGameTag' = 2653 - FUNC_INGREDIENT_SUSPICIOUS: 'CommonGameTag' = 67634 - FUNC_INGREDIENT_SUSPICIOUS_EP09: 'CommonGameTag' = 2431 - FUNC_INGREDIENT_TOMATO: 'CommonGameTag' = 2596 - FUNC_INGREDIENT_VEGGIE: 'CommonGameTag' = 815 - FUNC_INGREDIENT_WATERMELON: 'CommonGameTag' = 112663 - FUNC_INGREDIENT_WAX_BLOCK: 'CommonGameTag' = 67636 - FUNC_INSANE_TALK_TO_OBJECTS: 'CommonGameTag' = 1929 - FUNC_INSECT: 'CommonGameTag' = 2575 - FUNC_INSECT_FARM: 'CommonGameTag' = 67592 - FUNC_INSECT_FARMED: 'CommonGameTag' = 67649 - FUNC_INSECT_WILD: 'CommonGameTag' = 10298 - FUNC_INSTRUMENT: 'CommonGameTag' = 570 - FUNC_INSTRUMENTS: 'CommonGameTag' = 1413 - FUNC_INTERACTIVE_BUSH: 'CommonGameTag' = 24588 - FUNC_INTERACTIVE_BUSH_BG: 'CommonGameTag' = 2070 - FUNC_INTERACTIVE_CLOSET: 'CommonGameTag' = 24589 - FUNC_INTERIOR_DECORATOR_GIG_OBJECT_WEIRD: 'CommonGameTag' = 53253 - FUNC_INTERIOR_DECORATOR_NEW: 'CommonGameTag' = 53251 - FUNC_INVENTION_CONSTRUCTOR: 'CommonGameTag' = 12394 - FUNC_INVESTIGATION_DOSSIER: 'CommonGameTag' = 47165 - FUNC_INVESTIGATION_EVIDENCE: 'CommonGameTag' = 47106 - FUNC_INVESTIGATION_HAZMAT_SUIT: 'CommonGameTag' = 47147 - FUNC_INVESTIGATION_JUNK_PILE: 'CommonGameTag' = 47126 - FUNC_INVESTIGATION_KEYCARD: 'CommonGameTag' = 47164 - FUNC_INVESTIGATION_SEALED_DOOR_FLOOR: 'CommonGameTag' = 47136 - FUNC_INVESTIGATION_SEALED_DOOR_HALLWAY: 'CommonGameTag' = 47138 - FUNC_INVESTIGATION_SEALED_DOOR_MOTHER_PLANT: 'CommonGameTag' = 47137 - FUNC_INVESTIGATION_SPORE_FILTER: 'CommonGameTag' = 47146 - FUNC_INVESTIGATION_SPORE_SAMPLE: 'CommonGameTag' = 47135 - FUNC_INVISIBLE: 'CommonGameTag' = 1219 - FUNC_ISLAND_CANOE: 'CommonGameTag' = 63501 - FUNC_ISLAND_CANOE_BEACH_VENUE: 'CommonGameTag' = 2198 - FUNC_ISLAND_SPIRIT: 'CommonGameTag' = 63497 - FUNC_ISLAND_SPIRIT_INACTIVE: 'CommonGameTag' = 63498 - FUNC_ITEM_BATUU: 'CommonGameTag' = 2464 - FUNC_JACK_O_LANTERN: 'CommonGameTag' = 1206 - FUNC_JAIL: 'CommonGameTag' = 1379 - FUNC_JIG: 'CommonGameTag' = 1342 - FUNC_JOURNAL: 'CommonGameTag' = 43009 - FUNC_JOURNALIST: 'CommonGameTag' = 1118 - FUNC_JOURNAL_BASE_GAME: 'CommonGameTag' = 1724 - FUNC_JUICE_FIZZER: 'CommonGameTag' = 67629 - FUNC_JUICE_FIZZING_PRODUCT: 'CommonGameTag' = 67635 - FUNC_JUICE_KEG: 'CommonGameTag' = 65539 - FUNC_JUICE_KEG_CONFIDENT: 'CommonGameTag' = 65543 - FUNC_JUICE_KEG_FLIRTY: 'CommonGameTag' = 65542 - FUNC_JUICE_KEG_HAPPY: 'CommonGameTag' = 65544 - FUNC_JUICE_KEG_PLAYFUL: 'CommonGameTag' = 65545 - FUNC_JUMP_STAND: 'CommonGameTag' = 24604 - FUNC_JUNGLE: 'CommonGameTag' = 563 - FUNC_JUNGLE_GYM: 'CommonGameTag' = 1034 - FUNC_KARAOKE_MACHINE: 'CommonGameTag' = 1581 - FUNC_KEROSENE: 'CommonGameTag' = 1282 - FUNC_KETCHUP: 'CommonGameTag' = 1298 - FUNC_KETTLE: 'CommonGameTag' = 1221 - FUNC_KID: 'CommonGameTag' = 1091 - FUNC_KIDDIE_POOL: 'CommonGameTag' = 59462 - FUNC_KIDS_TENT: 'CommonGameTag' = 2554 - FUNC_KNIFE: 'CommonGameTag' = 1140 - FUNC_KNITTING: 'CommonGameTag' = 83992 - FUNC_KNITTING_BABY_ONESIE: 'CommonGameTag' = 83983 - FUNC_KNITTING_BEANIE: 'CommonGameTag' = 83973 - FUNC_KNITTING_CHILD_SWEATER: 'CommonGameTag' = 83988 - FUNC_KNITTING_CLOTHING: 'CommonGameTag' = 83993 - FUNC_KNITTING_DECORATION: 'CommonGameTag' = 83979 - FUNC_KNITTING_FURNISHING: 'CommonGameTag' = 83975 - FUNC_KNITTING_GIFTED: 'CommonGameTag' = 83990 - FUNC_KNITTING_GRIM: 'CommonGameTag' = 83987 - FUNC_KNITTING_ONESIE: 'CommonGameTag' = 83980 - FUNC_KNITTING_POUFFE: 'CommonGameTag' = 83978 - FUNC_KNITTING_RUG: 'CommonGameTag' = 83976 - FUNC_KNITTING_SOCKS: 'CommonGameTag' = 83974 - FUNC_KNITTING_SWEATER: 'CommonGameTag' = 83977 - FUNC_KNITTING_SWEATER_SCARF: 'CommonGameTag' = 83981 - FUNC_KNITTING_TOY: 'CommonGameTag' = 83982 - FUNC_KNITTING_WIP: 'CommonGameTag' = 2463 - FUNC_KNIVES: 'CommonGameTag' = 1141 - FUNC_KNOWLEDGE: 'CommonGameTag' = 24595 - FUNC_KWANZAA: 'CommonGameTag' = 1330 - FUNC_LAB: 'CommonGameTag' = 1400 - FUNC_LAB_DOOR: 'CommonGameTag' = 47105 - FUNC_LADDER: 'CommonGameTag' = 1230 - FUNC_LAMP: 'CommonGameTag' = 1283 - FUNC_LAMP_POST: 'CommonGameTag' = 1293 - FUNC_LANDFILL_DUMPABLE_APPLIANCE: 'CommonGameTag' = 67607 - FUNC_LANTERN: 'CommonGameTag' = 1205 - FUNC_LAPTOP: 'CommonGameTag' = 515 - FUNC_LASER: 'CommonGameTag' = 1396 - FUNC_LASER_LIGHT: 'CommonGameTag' = 24577 - FUNC_LAUNDRY_CLOTHES_LINE: 'CommonGameTag' = 75781 - FUNC_LAUNDRY_DRYER: 'CommonGameTag' = 75779 - FUNC_LAUNDRY_HAMPER: 'CommonGameTag' = 2033 - FUNC_LAUNDRY_HERO_OBJECT: 'CommonGameTag' = 2032 - FUNC_LAUNDRY_PILE: 'CommonGameTag' = 75777 - FUNC_LAUNDRY_SEARCH_TERM: 'CommonGameTag' = 75782 - FUNC_LAUNDRY_WASHING_MACHINE: 'CommonGameTag' = 75778 - FUNC_LAUNDRY_WASH_TUB: 'CommonGameTag' = 75780 - FUNC_LAVA_ROCK: 'CommonGameTag' = 63499 - FUNC_LEAF_PILE: 'CommonGameTag' = 59432 - FUNC_LECTERN: 'CommonGameTag' = 55405 - FUNC_LIFESTYLES_ELECTRONICS: 'CommonGameTag' = 2493 - FUNC_LIFESTYLES_TECH_BOOK: 'CommonGameTag' = 2505 - FUNC_LIFESTYLES_TECH_SCHOOL_PROJECT: 'CommonGameTag' = 2506 - FUNC_LIFE_MILESTONE_MEMORABILIA: 'CommonGameTag' = 2917 - FUNC_LIGHTING_NOT_STAGE_LIGHTS: 'CommonGameTag' = 61467 - FUNC_LIGHTNING_CAN_STRIKE: 'CommonGameTag' = 2076 - FUNC_LIGHTNING_CLEANUP: 'CommonGameTag' = 59491 - FUNC_LIGHTNING_OBJECT: 'CommonGameTag' = 59440 - FUNC_LIGHTS: 'CommonGameTag' = 1338 - FUNC_LIGHTSABER_CRYSTAL: 'CommonGameTag' = 51203 - FUNC_LIGHTSABER_HILT: 'CommonGameTag' = 51204 - FUNC_LIGHT_CANDLE_WITH_AUTO_LIGHTS: 'CommonGameTag' = 1446 - FUNC_LIGHT_NON_ELECTRIC: 'CommonGameTag' = 1374 - FUNC_LIGHT_NO_AUTO_LIGHTS: 'CommonGameTag' = 1325 - FUNC_LINOLEUM: 'CommonGameTag' = 1097 - FUNC_LISTENING_DEVICE_BUG: 'CommonGameTag' = 47145 - FUNC_LITTER_BOX: 'CommonGameTag' = 57355 - FUNC_LITTER_BOX_HIGH_TECH: 'CommonGameTag' = 57360 - FUNC_LIVESTOCK_FEED: 'CommonGameTag' = 2726 - FUNC_LIVESTOCK_FEED_FISHY: 'CommonGameTag' = 2571 - FUNC_LIVESTOCK_FEED_HEALTHY: 'CommonGameTag' = 2572 - FUNC_LIVESTOCK_FEED_PILE: 'CommonGameTag' = 2649 - FUNC_LIVESTOCK_FEED_PILE_BASIC: 'CommonGameTag' = 2699 - FUNC_LIVE_DRAG_ALLOWED_WITH_CHILDREN: 'CommonGameTag' = 1722 - FUNC_LIVING_CHAIR: 'CommonGameTag' = 1005 - FUNC_LLAMA: 'CommonGameTag' = 112682 - FUNC_LOCATOR_BEACH_PORTAL: 'CommonGameTag' = 2187 - FUNC_LOCATOR_TERRAIN_WALKSTYLE_PORTAL: 'CommonGameTag' = 2482 - FUNC_LOG: 'CommonGameTag' = 1307 - FUNC_LOGIC: 'CommonGameTag' = 1098 - FUNC_LOTUS: 'CommonGameTag' = 1288 - FUNC_LOUD_TOYS: 'CommonGameTag' = 2967 - FUNC_LOUNGE_EVENT_AWARD_TROPHY: 'CommonGameTag' = 61632 - FUNC_MACHINE: 'CommonGameTag' = 578 - FUNC_MAGAZINE: 'CommonGameTag' = 1405 - FUNC_MAGIC_BEAN: 'CommonGameTag' = 1701 - FUNC_MAGIC_BEAN_ANGRY_RED: 'CommonGameTag' = 1702 - FUNC_MAGIC_BEAN_CONFIDENT_LIGHT_BLUE: 'CommonGameTag' = 1707 - FUNC_MAGIC_BEAN_FLIRTY_PINK: 'CommonGameTag' = 1705 - FUNC_MAGIC_BEAN_PLAYFUL_GREEN: 'CommonGameTag' = 1703 - FUNC_MAGIC_BEAN_SAD_NAVY_BLUE: 'CommonGameTag' = 1706 - FUNC_MAGIC_BEAN_UNCOMFORTABLE_ORANGE: 'CommonGameTag' = 1704 - FUNC_MAGIC_BROOM: 'CommonGameTag' = 49169 - FUNC_MAGIC_PORTAL_DUELING_TO_HQ: 'CommonGameTag' = 49159 - FUNC_MAGIC_PORTAL_HQ_TO_DUELING: 'CommonGameTag' = 49160 - FUNC_MAGIC_PORTAL_HQ_TO_MARKET: 'CommonGameTag' = 49161 - FUNC_MAGIC_PORTAL_HQ_TO_VISTA: 'CommonGameTag' = 49162 - FUNC_MAGIC_PORTAL_MARKET_TO_HQ: 'CommonGameTag' = 49163 - FUNC_MAGIC_PORTAL_VISTA_TO_HQ: 'CommonGameTag' = 49164 - FUNC_MAHI_MAHI: 'CommonGameTag' = 63509 - FUNC_MAILBOX: 'CommonGameTag' = 954 - FUNC_MAILBOX_GROUND: 'CommonGameTag' = 2954 - FUNC_MAILBOX_WALL: 'CommonGameTag' = 2168 - FUNC_MAKEUP_TABLE: 'CommonGameTag' = 36868 - FUNC_MANNEQUIN: 'CommonGameTag' = 1322 - FUNC_MANSION: 'CommonGameTag' = 1225 - FUNC_MAP: 'CommonGameTag' = 1312 - FUNC_MARKET_STALL: 'CommonGameTag' = 55298 - FUNC_MARKET_STALLS: 'CommonGameTag' = 1932 - FUNC_MARKET_STALLS_DOCKYARD_PETS: 'CommonGameTag' = 57410 - FUNC_MARKET_STALLS_PURCHASE_FOOD: 'CommonGameTag' = 2378 - FUNC_MARKET_STALLS_PURCHASE_NON_FOOD: 'CommonGameTag' = 2379 - FUNC_MARKET_STALLS_SEAFOOD: 'CommonGameTag' = 1936 - FUNC_MARKET_STALLS_SEASONAL_FALL: 'CommonGameTag' = 59404 - FUNC_MARKET_STALLS_SEASONAL_SPRING: 'CommonGameTag' = 59403 - FUNC_MARKET_STALLS_SEASONAL_SUMMER: 'CommonGameTag' = 59402 - FUNC_MARKET_STALLS_SEASONAL_WINTER: 'CommonGameTag' = 59405 - FUNC_MARKET_STALLS_SQUARE_SNACKS: 'CommonGameTag' = 57405 - FUNC_MARKET_STALLS_SQUARE_SNACKS_PETS: 'CommonGameTag' = 57406 - FUNC_MARKET_STALL_MUSIC_FOOD: 'CommonGameTag' = 2561 - FUNC_MARKET_STALL_MUSIC_SHOP: 'CommonGameTag' = 2562 - FUNC_MASCOT: 'CommonGameTag' = 1295 - FUNC_MASONRY: 'CommonGameTag' = 1096 - FUNC_MASSAGE: 'CommonGameTag' = 18454 - FUNC_MASSAGE_CHAIR: 'CommonGameTag' = 18440 - FUNC_MASSAGE_TABLE: 'CommonGameTag' = 18434 - FUNC_MATTRESS: 'CommonGameTag' = 1285 - FUNC_MEAL: 'CommonGameTag' = 521 - FUNC_MEAL_MEAT: 'CommonGameTag' = 2573 - FUNC_MEAL_VEGGIE: 'CommonGameTag' = 2574 - FUNC_MEAT_WALL: 'CommonGameTag' = 67648 - FUNC_MECH_SUIT_BODY: 'CommonGameTag' = 65639 - FUNC_MECH_SUIT_HEAD: 'CommonGameTag' = 65640 - FUNC_MEDITATION: 'CommonGameTag' = 18452 - FUNC_MEDITATION_STOOL: 'CommonGameTag' = 18438 - FUNC_MEDITATION_STOOL_TEMP: 'CommonGameTag' = 18482 - FUNC_MEDIUM: 'CommonGameTag' = 1188 - FUNC_MEGAPHONE: 'CommonGameTag' = 55406 - FUNC_MENTAL: 'CommonGameTag' = 24599 - FUNC_MERCHANDISE_VENDING_MACHINE: 'CommonGameTag' = 2508 - FUNC_MESS: 'CommonGameTag' = 43031 - FUNC_METAL: 'CommonGameTag' = 1090 - FUNC_MICROPHONE: 'CommonGameTag' = 488 - FUNC_MICROSCOPE: 'CommonGameTag' = 857 - FUNC_MICROWAVE: 'CommonGameTag' = 526 - FUNC_MILITARY_CAREER_MEDAL: 'CommonGameTag' = 47143 - FUNC_MILK: 'CommonGameTag' = 2579 - FUNC_MILK_BASIC: 'CommonGameTag' = 2977 - FUNC_MINI_BOTS: 'CommonGameTag' = 65582 - FUNC_MINI_BOTS_PARTY: 'CommonGameTag' = 65641 - FUNC_MINI_BOTS_WORKER: 'CommonGameTag' = 2275 - FUNC_MIRROR_NO_VANITY: 'CommonGameTag' = 2165 - FUNC_MIXOLOGIST: 'CommonGameTag' = 1116 - FUNC_MIXOLOGY: 'CommonGameTag' = 1103 - FUNC_MODEL: 'CommonGameTag' = 1158 - FUNC_MONKEY: 'CommonGameTag' = 564 - FUNC_MONKEY_BARS: 'CommonGameTag' = 1001 - FUNC_MONSTER: 'CommonGameTag' = 1217 - FUNC_MOTHER_PLANT: 'CommonGameTag' = 47131 - FUNC_MOTHER_PLANT_PIT: 'CommonGameTag' = 47144 - FUNC_MOTION: 'CommonGameTag' = 480 - FUNC_MOTION_GAMING_RIG: 'CommonGameTag' = 1016 - FUNC_MOTOR: 'CommonGameTag' = 24598 - FUNC_MOVIE: 'CommonGameTag' = 1498 - FUNC_MOVIE_THEATER: 'CommonGameTag' = 116737 - FUNC_MUD_BATH: 'CommonGameTag' = 18456 - FUNC_MUD_PUDDLE: 'CommonGameTag' = 59406 - FUNC_MUG: 'CommonGameTag' = 1301 - FUNC_MURAL: 'CommonGameTag' = 55371 - FUNC_MUSIC: 'CommonGameTag' = 491 - FUNC_MUSICIAN: 'CommonGameTag' = 1083 - FUNC_MUSIC_DISC: 'CommonGameTag' = 61470 - FUNC_MUSIC_PRODUCTION_STATION: 'CommonGameTag' = 61469 - FUNC_MUSTARD: 'CommonGameTag' = 1299 - FUNC_MYSTICAL_RELIC_BOTTOM: 'CommonGameTag' = 45067 - FUNC_MYSTICAL_RELIC_CRYSTAL: 'CommonGameTag' = 45068 - FUNC_MYSTICAL_RELIC_FUSED: 'CommonGameTag' = 45078 - FUNC_MYSTICAL_RELIC_TOP: 'CommonGameTag' = 45066 - FUNC_MYSTICAL_RELIC_UNBREAKABLE: 'CommonGameTag' = 45111 - FUNC_NECTAR: 'CommonGameTag' = 1527 - FUNC_NECTAR_MAKER: 'CommonGameTag' = 118885 - FUNC_NECTAR_RACK: 'CommonGameTag' = 118884 - FUNC_NEON: 'CommonGameTag' = 12400 - FUNC_NESTING_BLOCKS: 'CommonGameTag' = 1662 - FUNC_NEVER_RECEIVES_SNOW: 'CommonGameTag' = 2069 - FUNC_NON_BAR_JUICE_ENTHUSIAST_QUIRK: 'CommonGameTag' = 2144 - FUNC_NOT_MANAGED_AS_RUG: 'CommonGameTag' = 2752 - FUNC_NO_AUTONOMOUS_VIEW: 'CommonGameTag' = 2703 - FUNC_NO_CLEAN_UP_FROM_INVENTORY: 'CommonGameTag' = 2210 - FUNC_OBJECT_UPGRADE_PART: 'CommonGameTag' = 780 - FUNC_OBSERVATORY: 'CommonGameTag' = 572 - FUNC_OFF_THE_GRID: 'CommonGameTag' = 2219 - FUNC_OFF_THE_GRID_TOGGLE_UTILITY_USAGE: 'CommonGameTag' = 2427 - FUNC_OPENABLE_WINDOW: 'CommonGameTag' = 2823 - FUNC_ORACLE: 'CommonGameTag' = 1185 - FUNC_ORRERY: 'CommonGameTag' = 12429 - FUNC_OTTOMAN: 'CommonGameTag' = 1007 - FUNC_OUTDOOR: 'CommonGameTag' = 1430 - FUNC_OUTDOORS: 'CommonGameTag' = 1280 - FUNC_OUTDOOR_CHAIR: 'CommonGameTag' = 1004 - FUNC_OUTDOOR_PLANT: 'CommonGameTag' = 1013 - FUNC_OVEN: 'CommonGameTag' = 748 - FUNC_PAINT: 'CommonGameTag' = 483 - FUNC_PAINTER: 'CommonGameTag' = 1120 - FUNC_PAINTING: 'CommonGameTag' = 894 - FUNC_PAINTING_EMOTIONAL: 'CommonGameTag' = 2799 - FUNC_PAINTING_GIFTING: 'CommonGameTag' = 2667 - FUNC_PAINTING_HAUNTED: 'CommonGameTag' = 2515 - FUNC_PANS: 'CommonGameTag' = 1296 - FUNC_PAPER: 'CommonGameTag' = 1418 - FUNC_PAPER_POSTED: 'CommonGameTag' = 43010 - FUNC_PARK_FOUNTAIN: 'CommonGameTag' = 30721 - FUNC_PARTY: 'CommonGameTag' = 529 - FUNC_PATH_OBSTACLE_JUNGLE_01_ENTRANCE: 'CommonGameTag' = 45060 - FUNC_PATH_OBSTACLE_JUNGLE_01_EXIT: 'CommonGameTag' = 45061 - FUNC_PATH_OBSTACLE_JUNGLE_02_ENTRANCE: 'CommonGameTag' = 45062 - FUNC_PATH_OBSTACLE_JUNGLE_02_EXIT: 'CommonGameTag' = 45063 - FUNC_PATH_OBSTACLE_JUNGLE_03_ENTRANCE: 'CommonGameTag' = 45080 - FUNC_PATH_OBSTACLE_JUNGLE_03_EXIT: 'CommonGameTag' = 45081 - FUNC_PATH_OBSTACLE_JUNGLE_04_ENTRANCE: 'CommonGameTag' = 45082 - FUNC_PATH_OBSTACLE_JUNGLE_04_EXIT: 'CommonGameTag' = 45083 - FUNC_PATH_OBSTACLE_JUNGLE_05_ENTRANCE: 'CommonGameTag' = 45084 - FUNC_PATH_OBSTACLE_JUNGLE_05_EXIT: 'CommonGameTag' = 45085 - FUNC_PATH_OBSTACLE_JUNGLE_06_ENTRANCE: 'CommonGameTag' = 45086 - FUNC_PATH_OBSTACLE_JUNGLE_06_EXIT: 'CommonGameTag' = 45087 - FUNC_PATH_OBSTACLE_JUNGLE_POOL_ENTRANCE: 'CommonGameTag' = 45095 - FUNC_PATH_OBSTACLE_JUNGLE_POOL_EXIT: 'CommonGameTag' = 45096 - FUNC_PATH_OBSTACLE_JUNGLE_TEMPLE_ENTRANCE: 'CommonGameTag' = 45064 - FUNC_PATH_OBSTACLE_JUNGLE_TEMPLE_EXIT: 'CommonGameTag' = 45065 - FUNC_PATIO_FURNITURE: 'CommonGameTag' = 1011 - FUNC_PEDESTAL: 'CommonGameTag' = 1399 - FUNC_PEN: 'CommonGameTag' = 112687 - FUNC_PERFORMANCE_SPACE: 'CommonGameTag' = 55299 - FUNC_PET_BALL: 'CommonGameTag' = 57412 - FUNC_PET_BED: 'CommonGameTag' = 57386 - FUNC_PET_BOWL: 'CommonGameTag' = 1876 - FUNC_PET_BUSH: 'CommonGameTag' = 57445 - FUNC_PET_CATNIP: 'CommonGameTag' = 57421 - FUNC_PET_CRATE: 'CommonGameTag' = 57388 - FUNC_PET_DIRT_MOUND: 'CommonGameTag' = 57448 - FUNC_PET_DOG_TOY: 'CommonGameTag' = 57454 - FUNC_PET_FEAR_SOUNDS_BG: 'CommonGameTag' = 2171 - FUNC_PET_FILLER: 'CommonGameTag' = 57380 - FUNC_PET_FILLER_THREE: 'CommonGameTag' = 57382 - FUNC_PET_FILLER_TWO: 'CommonGameTag' = 57381 - FUNC_PET_FISH_PILE: 'CommonGameTag' = 57446 - FUNC_PET_FOOD: 'CommonGameTag' = 57379 - FUNC_PET_GIFT: 'CommonGameTag' = 57444 - FUNC_PET_HIDE_NO_FADE: 'CommonGameTag' = 2031 - FUNC_PET_MINOR_CAGE: 'CommonGameTag' = 77825 - FUNC_PET_MINOR_CAGE_BG: 'CommonGameTag' = 2052 - FUNC_PET_NO_ROUTE_UNDER: 'CommonGameTag' = 2028 - FUNC_PET_OBSTACLE_COURSE: 'CommonGameTag' = 57415 - FUNC_PET_OBSTACLE_COURSE_HOOP: 'CommonGameTag' = 57416 - FUNC_PET_OBSTACLE_COURSE_PLATFORM: 'CommonGameTag' = 57418 - FUNC_PET_OBSTACLE_COURSE_RAMP: 'CommonGameTag' = 57417 - FUNC_PET_OBSTACLE_COURSE_TUNNEL: 'CommonGameTag' = 57420 - FUNC_PET_OBSTACLE_COURSE_WEAVING_FLAGS: 'CommonGameTag' = 57419 - FUNC_PET_POOP: 'CommonGameTag' = 57361 - FUNC_PET_POOP_NO_CLEAN: 'CommonGameTag' = 57455 - FUNC_PET_RECIPE: 'CommonGameTag' = 57404 - FUNC_PET_RECIPE_FOOD: 'CommonGameTag' = 1930 - FUNC_PET_SCRATCHABLE_FURNITURE: 'CommonGameTag' = 1878 - FUNC_PET_SEAWEED: 'CommonGameTag' = 57447 - FUNC_PET_SQUEAKY_BALL: 'CommonGameTag' = 57413 - FUNC_PET_TOY: 'CommonGameTag' = 1877 - FUNC_PET_TOY_BOX: 'CommonGameTag' = 57376 - FUNC_PET_TOY_NEW: 'CommonGameTag' = 57440 - FUNC_PET_TOY_SMART_TRAIT_CARRY: 'CommonGameTag' = 57456 - FUNC_PET_TREAT: 'CommonGameTag' = 57426 - FUNC_PET_TREAT_EDIBLE: 'CommonGameTag' = 57431 - FUNC_PET_TREAT_EDIBLE_CHILD: 'CommonGameTag' = 57438 - FUNC_PET_TREAT_EDIBLE_ELDER: 'CommonGameTag' = 57439 - FUNC_PET_VACUUM: 'CommonGameTag' = 2518 - FUNC_PHANTOM: 'CommonGameTag' = 1194 - FUNC_PHOTO: 'CommonGameTag' = 1382 - FUNC_PHOTOGRAPHY: 'CommonGameTag' = 1383 - FUNC_PHOTOGRAPHY_DISALLOW: 'CommonGameTag' = 1438 - FUNC_PHOTO_BOOTH: 'CommonGameTag' = 114718 - FUNC_PHOTO_COLLAGE: 'CommonGameTag' = 79874 - FUNC_PHOTO_OP_STAND: 'CommonGameTag' = 114702 - FUNC_PHOTO_STUDIO: 'CommonGameTag' = 1941 - FUNC_PHOTO_STUDIO_SEARCH: 'CommonGameTag' = 2218 - FUNC_PIANO: 'CommonGameTag' = 566 - FUNC_PICNIC: 'CommonGameTag' = 1317 - FUNC_PICNICBASKET_BG: 'CommonGameTag' = 2700 - FUNC_PICNIC_BASKET: 'CommonGameTag' = 112649 - FUNC_PICNIC_TABLE: 'CommonGameTag' = 1248 - FUNC_PIER_ATTRACTIONS: 'CommonGameTag' = 114720 - FUNC_PILLAR: 'CommonGameTag' = 1010 - FUNC_PIPE: 'CommonGameTag' = 1410 - FUNC_PIPE_ORGAN: 'CommonGameTag' = 40963 - FUNC_PIRATE: 'CommonGameTag' = 501 - FUNC_PIT_BBQ: 'CommonGameTag' = 63527 - FUNC_PIZZA_DELIVERY_POST_JOB_LOSS: 'CommonGameTag' = 116738 - FUNC_PLACEABLE_ON_TREEHOUSE: 'CommonGameTag' = 2968 - FUNC_PLACEMAT_DRAWING: 'CommonGameTag' = 26639 - FUNC_PLACEMAT_FORMAL: 'CommonGameTag' = 1711 - FUNC_PLANTER_BOX: 'CommonGameTag' = 1149 - FUNC_PLAQUE: 'CommonGameTag' = 1420 - FUNC_PLAY: 'CommonGameTag' = 1142 - FUNC_PLUSH: 'CommonGameTag' = 1021 - FUNC_PODIUM: 'CommonGameTag' = 1577 - FUNC_PODIUM_PAIR: 'CommonGameTag' = 65591 - FUNC_PODIUM_PAIR_DEBATE_SHOWDOWN: 'CommonGameTag' = 65594 - FUNC_POLE: 'CommonGameTag' = 1404 - FUNC_POLICE: 'CommonGameTag' = 12398 - FUNC_POND: 'CommonGameTag' = 2645 - FUNC_POND_FISHSIGN: 'CommonGameTag' = 2601 - FUNC_POOL: 'CommonGameTag' = 1233 - FUNC_POOL_LADDER: 'CommonGameTag' = 1240 - FUNC_POOL_LIGHT: 'CommonGameTag' = 1234 - FUNC_POPCORN: 'CommonGameTag' = 28674 - FUNC_POPCORN_BUTTERED: 'CommonGameTag' = 28678 - FUNC_POPCORN_CARAMEL: 'CommonGameTag' = 28676 - FUNC_POPCORN_CHEDDAR: 'CommonGameTag' = 28675 - FUNC_POPCORN_KETTLE: 'CommonGameTag' = 28677 - FUNC_POPCORN_POPPER: 'CommonGameTag' = 28673 - FUNC_PORTABLE_BAR: 'CommonGameTag' = 24602 - FUNC_PORTABLE_KEYBOARD: 'CommonGameTag' = 1627 - FUNC_PORTAL: 'CommonGameTag' = 1435 - FUNC_PORTRAIT: 'CommonGameTag' = 1422 - FUNC_POSTER: 'CommonGameTag' = 895 - FUNC_POT: 'CommonGameTag' = 1144 - FUNC_POTION: 'CommonGameTag' = 993 - FUNC_POTTY: 'CommonGameTag' = 1664 - FUNC_POWER_GENERATOR: 'CommonGameTag' = 67617 - FUNC_PREGENERATE_DEFAULT_MAT_GEO_STATE_THUMBNAIL_ONLY: 'CommonGameTag' = 2170 - FUNC_PRESENT_PILE: 'CommonGameTag' = 59410 - FUNC_PRESENT_PILE_LARGE: 'CommonGameTag' = 59416 - FUNC_PRESENT_PILE_SMALL: 'CommonGameTag' = 59415 - FUNC_PREVENT_RECYCLING: 'CommonGameTag' = 2442 - FUNC_PRISON: 'CommonGameTag' = 1380 - FUNC_PRIVACY_OBEY_APPROPRIATE: 'CommonGameTag' = 61640 - FUNC_PRODUCE: 'CommonGameTag' = 2582 - FUNC_PROGRAMMING: 'CommonGameTag' = 1101 - FUNC_PROPANE: 'CommonGameTag' = 1281 - FUNC_PSYCHIC: 'CommonGameTag' = 1186 - FUNC_PUBLIC_BATHROOM: 'CommonGameTag' = 1340 - FUNC_PUDDLE: 'CommonGameTag' = 567 - FUNC_PUMPKIN: 'CommonGameTag' = 1204 - FUNC_PUNCHING: 'CommonGameTag' = 477 - FUNC_PUPPET_THEATER: 'CommonGameTag' = 32769 - FUNC_PURCHASE_BEACH: 'CommonGameTag' = 63506 - FUNC_PURCHASE_BEACH_ACCESSORIES: 'CommonGameTag' = 63532 - FUNC_PURCHASE_BEACH_FISHING: 'CommonGameTag' = 63529 - FUNC_PURCHASE_BEACH_FRUITS: 'CommonGameTag' = 63533 - FUNC_PURCHASE_BEACH_LEISURE: 'CommonGameTag' = 63530 - FUNC_PURCHASE_BEACH_VEHICLES: 'CommonGameTag' = 63531 - FUNC_PURCHASE_MUSIC_FESTIVAL: 'CommonGameTag' = 2564 - FUNC_PURCHASE_PICKER_CATEGORY_BOOK_EMOTIONAL: 'CommonGameTag' = 1037 - FUNC_PURCHASE_PICKER_CATEGORY_BOOK_SKILL: 'CommonGameTag' = 1036 - FUNC_PURCHASE_VACATION_FUN: 'CommonGameTag' = 2503 - FUNC_PURCHASE_VACATION_FURNITURE: 'CommonGameTag' = 2500 - FUNC_PURCHASE_VACATION_MISC: 'CommonGameTag' = 2504 - FUNC_PURCHASE_VACATION_SUPPLIES: 'CommonGameTag' = 2502 - FUNC_PURCHASE_VACATION_TENTS: 'CommonGameTag' = 2501 - FUNC_PUZZLES: 'CommonGameTag' = 2949 - FUNC_PUZZLES_PIECES: 'CommonGameTag' = 116757 - FUNC_QUADCOPTER: 'CommonGameTag' = 65624 - FUNC_RACK: 'CommonGameTag' = 1146 - FUNC_RANCH_NECTAR: 'CommonGameTag' = 118791 - FUNC_RANCH_NECTARITEMS: 'CommonGameTag' = 118876 - FUNC_RANCH_NECTARMAKER: 'CommonGameTag' = 118875 - FUNC_RANCH_NECTAR_BOTTLE: 'CommonGameTag' = 118790 - FUNC_RANGE: 'CommonGameTag' = 1169 - FUNC_RANGER_STATION: 'CommonGameTag' = 1341 - FUNC_RANGER_STATION_CATEGORY_FUN: 'CommonGameTag' = 1889 - FUNC_RANGER_STATION_CATEGORY_FURNITURE: 'CommonGameTag' = 1888 - FUNC_RANGER_STATION_CATEGORY_INGREDIENT: 'CommonGameTag' = 1890 - FUNC_RANGER_STATION_CATEGORY_PET: 'CommonGameTag' = 2012 - FUNC_RANGER_STATION_CATEGORY_SUPPLIES: 'CommonGameTag' = 1887 - FUNC_RANGER_STATION_FUN: 'CommonGameTag' = 10269 - FUNC_RANGER_STATION_FURNITURE: 'CommonGameTag' = 10268 - FUNC_RANGER_STATION_INGREDIENT: 'CommonGameTag' = 10270 - FUNC_RANGER_STATION_SUPPLIES: 'CommonGameTag' = 10267 - FUNC_RAT: 'CommonGameTag' = 77830 - FUNC_REAPER: 'CommonGameTag' = 576 - FUNC_REBATE_PLANT: 'CommonGameTag' = 2205 - FUNC_RECIPE: 'CommonGameTag' = 522 - FUNC_RECIPE_BAKING_CUPCAKE_FACTORY: 'CommonGameTag' = 12377 - FUNC_RECIPE_BAKING_OVEN: 'CommonGameTag' = 12376 - FUNC_RECLINER: 'CommonGameTag' = 1111 - FUNC_RECORDING: 'CommonGameTag' = 47149 - FUNC_RECYCLER: 'CommonGameTag' = 67585 - FUNC_REFRIGERATOR: 'CommonGameTag' = 519 - FUNC_REGISTERED_VAMPIRE_LAIR: 'CommonGameTag' = 2271 - FUNC_REGISTERS: 'CommonGameTag' = 12395 - FUNC_RELAXATION: 'CommonGameTag' = 18457 - FUNC_REPAIR_BURNT: 'CommonGameTag' = 67644 - FUNC_REPAIR_BURNT_VARIABLE_HEIGHT: 'CommonGameTag' = 67643 - FUNC_REPAIR_BURNT_VARIABLE_HEIGHT_BG: 'CommonGameTag' = 2435 - FUNC_REQUIRES_OCEAN_LOT: 'CommonGameTag' = 63519 - FUNC_RESEARCH_MACHINE: 'CommonGameTag' = 65631 - FUNC_RESTAURANT_NOT_A_TABLE: 'CommonGameTag' = 26649 - FUNC_RETAIL: 'CommonGameTag' = 1321 - FUNC_RETAIL_FRIDGE: 'CommonGameTag' = 12431 - FUNC_RETAIL_NEON_LIGHT: 'CommonGameTag' = 12365 - FUNC_RETAIL_NPC_ITEM_FOR_SALE: 'CommonGameTag' = 12384 - FUNC_RETAIL_PEDESTAL: 'CommonGameTag' = 12383 - FUNC_RETAIL_REGISTER: 'CommonGameTag' = 12311 - FUNC_REVIEW_PRODUCT_BEAUTY: 'CommonGameTag' = 61557 - FUNC_REVIEW_PRODUCT_GADGET: 'CommonGameTag' = 61559 - FUNC_REVIEW_PRODUCT_TECH: 'CommonGameTag' = 61558 - FUNC_REWARD: 'CommonGameTag' = 1121 - FUNC_RIG: 'CommonGameTag' = 1015 - FUNC_ROBOTICS_TABLE: 'CommonGameTag' = 65565 - FUNC_ROBOTIC_ARM: 'CommonGameTag' = 2281 - FUNC_ROBOT_VACUUM: 'CommonGameTag' = 1982 - FUNC_ROBOT_VACUUM_BASE: 'CommonGameTag' = 1983 - FUNC_ROBOT_VACUUM_CLEAN_DEFAULT: 'CommonGameTag' = 57422 - FUNC_ROBOT_VACUUM_CLEAN_UPGRADE: 'CommonGameTag' = 57423 - FUNC_ROBOT_VACUUM_MESS_DEFAULT_CLEAN: 'CommonGameTag' = 2010 - FUNC_ROBOT_VACUUM_MESS_UPGRADED_CLEAN: 'CommonGameTag' = 2011 - FUNC_ROCK: 'CommonGameTag' = 1318 - FUNC_ROCKET: 'CommonGameTag' = 495 - FUNC_ROCKET_SCIENCE: 'CommonGameTag' = 1105 - FUNC_ROCKING_CHAIR: 'CommonGameTag' = 2462 - FUNC_ROCKING_CHAIR_ARM_CHAIR: 'CommonGameTag' = 83986 - FUNC_ROCK_CLIMBING_WALL: 'CommonGameTag' = 71681 - FUNC_ROCK_WALL: 'CommonGameTag' = 71682 - FUNC_ROOMMATE_ABSENT: 'CommonGameTag' = 2263 - FUNC_ROOMMATE_ART: 'CommonGameTag' = 2259 - FUNC_ROOMMATE_BAKING: 'CommonGameTag' = 2257 - FUNC_ROOMMATE_BATHROOM_HOG: 'CommonGameTag' = 2262 - FUNC_ROOMMATE_BIG_CLOSET: 'CommonGameTag' = 2264 - FUNC_ROOMMATE_BREAKER: 'CommonGameTag' = 2256 - FUNC_ROOMMATE_CANT_STOP_THE_BEAT: 'CommonGameTag' = 2255 - FUNC_ROOMMATE_CHEERLEADER: 'CommonGameTag' = 2248 - FUNC_ROOMMATE_CLINGY_SOCIALITE: 'CommonGameTag' = 2251 - FUNC_ROOMMATE_COMPUTER: 'CommonGameTag' = 2260 - FUNC_ROOMMATE_COUCH_POTATO: 'CommonGameTag' = 2252 - FUNC_ROOMMATE_EMO_LONER: 'CommonGameTag' = 2254 - FUNC_ROOMMATE_FITNESS: 'CommonGameTag' = 2261 - FUNC_ROOMMATE_FIXER: 'CommonGameTag' = 2250 - FUNC_ROOMMATE_LATE_ON_RENT: 'CommonGameTag' = 2267 - FUNC_ROOMMATE_MEAL_MAKER: 'CommonGameTag' = 2249 - FUNC_ROOMMATE_MUSIC: 'CommonGameTag' = 2258 - FUNC_ROOMMATE_PARTY_PLANNER: 'CommonGameTag' = 2253 - FUNC_ROOMMATE_PRANKSTER: 'CommonGameTag' = 2266 - FUNC_ROOMMATE_PUBLIC_AFFECTION_DISPLAYER: 'CommonGameTag' = 2265 - FUNC_ROOMMATE_SUPER_NEAT: 'CommonGameTag' = 2247 - FUNC_ROOSTER: 'CommonGameTag' = 112683 - FUNC_RUBBISH: 'CommonGameTag' = 923 - FUNC_RUG: 'CommonGameTag' = 2020 - FUNC_RUSTIC: 'CommonGameTag' = 1320 - FUNC_SABACC_CHIP_PILE: 'CommonGameTag' = 51254 - FUNC_SACRED_CANDLE: 'CommonGameTag' = 86020 - FUNC_SADCLOWN: 'CommonGameTag' = 2943 - FUNC_SALE: 'CommonGameTag' = 1406 - FUNC_SALINE: 'CommonGameTag' = 1407 - FUNC_SAUCER: 'CommonGameTag' = 1393 - FUNC_SAUCE_POT: 'CommonGameTag' = 2450 - FUNC_SAUNA: 'CommonGameTag' = 18455 - FUNC_SAWHORSE: 'CommonGameTag' = 1408 - FUNC_SCARECROW: 'CommonGameTag' = 59459 - FUNC_SCENT_FLOWER_HIGH_SKILL: 'CommonGameTag' = 59470 - FUNC_SCENT_FLOWER_LOW_SKILL: 'CommonGameTag' = 59469 - FUNC_SCHOOL_LOCKER: 'CommonGameTag' = 114692 - FUNC_SCHOOL_PROJECT_BOX_CHILD: 'CommonGameTag' = 43013 - FUNC_SCHOOL_PROJECT_BOX_TEEN: 'CommonGameTag' = 43014 - FUNC_SCIENCE: 'CommonGameTag' = 1019 - FUNC_SCIENCE_TABLE: 'CommonGameTag' = 858 - FUNC_SCIENCE_UNIVERSITY_SHELL: 'CommonGameTag' = 65549 - FUNC_SCIENCE_UNIVERSITY_SHELL_SHELL_1: 'CommonGameTag' = 65562 - FUNC_SCIENCE_UNIVERSITY_SHELL_SHELL_2: 'CommonGameTag' = 65563 - FUNC_SCIENTIST: 'CommonGameTag' = 12396 - FUNC_SCRATCHED_ALL: 'CommonGameTag' = 57369 - FUNC_SCRATCHED_LOW: 'CommonGameTag' = 57368 - FUNC_SCRATCHING_POST: 'CommonGameTag' = 57384 - FUNC_SCREEN: 'CommonGameTag' = 1031 - FUNC_SCULPTURE: 'CommonGameTag' = 2581 - FUNC_SCYTHE: 'CommonGameTag' = 574 - FUNC_SEANCE: 'CommonGameTag' = 1189 - FUNC_SEANCE_CIRCLE: 'CommonGameTag' = 86018 - FUNC_SEANCE_TABLE: 'CommonGameTag' = 86017 - FUNC_SEASHELL: 'CommonGameTag' = 63508 - FUNC_SEASONAL: 'CommonGameTag' = 59445 - FUNC_SECRET_AGENT: 'CommonGameTag' = 1127 - FUNC_SECRET_SOCIETY_GARDEN: 'CommonGameTag' = 65569 - FUNC_SECTIONAL_SOFA_CHAISE: 'CommonGameTag' = 53249 - FUNC_SECTIONAL_SOFA_PIECE: 'CommonGameTag' = 2558 - FUNC_SECTIONAL_SOFA_WHOLE: 'CommonGameTag' = 2557 - FUNC_SEER: 'CommonGameTag' = 1187 - FUNC_SERUMS: 'CommonGameTag' = 12430 - FUNC_SERVICE_INDOOR: 'CommonGameTag' = 2976 - FUNC_SERVICE_OUTDOOR: 'CommonGameTag' = 2975 - FUNC_SHADES: 'CommonGameTag' = 1154 - FUNC_SHEET: 'CommonGameTag' = 1290 - FUNC_SHELF: 'CommonGameTag' = 1148 - FUNC_SHELL_INTERACTIVE: 'CommonGameTag' = 2245 - FUNC_SHIP: 'CommonGameTag' = 496 - FUNC_SHOES_SEARCH: 'CommonGameTag' = 2556 - FUNC_SHOWER: 'CommonGameTag' = 1315 - FUNC_SHOWER_TUB: 'CommonGameTag' = 1663 - FUNC_SHUTTLE: 'CommonGameTag' = 1397 - FUNC_SIGN: 'CommonGameTag' = 1027 - FUNC_SIMBLES: 'CommonGameTag' = 2953 - FUNC_SIM_RAY: 'CommonGameTag' = 1278 - FUNC_SIM_RAY_NOT_VALID_TRANSFORM_RESULT: 'CommonGameTag' = 2778 - FUNC_SIM_RAY_NOT_VALID_TRANSFORM_RESULT_BG: 'CommonGameTag' = 1528 - FUNC_SIM_RAY_TRANSFORM_ALIEN_VISITOR_ALLOW: 'CommonGameTag' = 12362 - FUNC_SING: 'CommonGameTag' = 489 - FUNC_SINGLE_BED: 'CommonGameTag' = 779 - FUNC_SINK: 'CommonGameTag' = 1313 - FUNC_SIT: 'CommonGameTag' = 1434 - FUNC_SIT_LOUNGE: 'CommonGameTag' = 2196 - FUNC_SIT_LOUNGE_FLOAT: 'CommonGameTag' = 2202 - FUNC_SKATING_RINK: 'CommonGameTag' = 59407 - FUNC_SKATING_RINK_ICE_NATURAL: 'CommonGameTag' = 59399 - FUNC_SKATING_RINK_ICE_RINK: 'CommonGameTag' = 59398 - FUNC_SKATING_RINK_LARGE: 'CommonGameTag' = 59436 - FUNC_SKATING_RINK_ROLLER_RINK: 'CommonGameTag' = 59400 - FUNC_SKATING_RINK_SEASONAL: 'CommonGameTag' = 59448 - FUNC_SKATING_RINK_SMALL: 'CommonGameTag' = 59435 - FUNC_SKELETON: 'CommonGameTag' = 1208 - FUNC_SKETCHPAD: 'CommonGameTag' = 2159 - FUNC_SKILLS: 'CommonGameTag' = 1384 - FUNC_SKULL: 'CommonGameTag' = 1212 - FUNC_SLEEP: 'CommonGameTag' = 1143 - FUNC_SLEEPING_BAG: 'CommonGameTag' = 2931 - FUNC_SLEEPING_BAG_TODDLER: 'CommonGameTag' = 2932 - FUNC_SLEEPING_POD: 'CommonGameTag' = 61624 - FUNC_SLIDE_LAWN: 'CommonGameTag' = 34818 - FUNC_SLIPPY_SLIDE: 'CommonGameTag' = 34817 - FUNC_SMART_HUB: 'CommonGameTag' = 2174 - FUNC_SNOB_ART_ASSESS: 'CommonGameTag' = 2133 - FUNC_SNOB_ART_ASSESS_NO_RESERVE: 'CommonGameTag' = 2134 - FUNC_SNOW: 'CommonGameTag' = 1333 - FUNC_SNOW_ANGEL: 'CommonGameTag' = 2484 - FUNC_SNOW_DRIFT: 'CommonGameTag' = 2485 - FUNC_SNOW_MAN: 'CommonGameTag' = 1336 - FUNC_SNOW_PAL: 'CommonGameTag' = 2486 - FUNC_SNOW_SPORTS_SLOPE_BUNNY_SLOPE: 'CommonGameTag' = 69646 - FUNC_SNOW_SPORTS_SLOPE_EASY_SLOPE: 'CommonGameTag' = 69647 - FUNC_SNOW_SPORTS_SLOPE_EXPERT_SLOPE: 'CommonGameTag' = 69649 - FUNC_SNOW_SPORTS_SLOPE_EXTREME_SLOPE: 'CommonGameTag' = 69650 - FUNC_SNOW_SPORTS_SLOPE_INTERMEDIATE_SLOPE: 'CommonGameTag' = 69648 - FUNC_SNOW_SPORTS_SLOPE_SKIS: 'CommonGameTag' = 69643 - FUNC_SNOW_SPORTS_SLOPE_SKIS_ADULT: 'CommonGameTag' = 69715 - FUNC_SNOW_SPORTS_SLOPE_SKIS_ADULT_RENTABLE: 'CommonGameTag' = 69717 - FUNC_SNOW_SPORTS_SLOPE_SKIS_CHILD: 'CommonGameTag' = 69676 - FUNC_SNOW_SPORTS_SLOPE_SKIS_CHILD_RENTABLE: 'CommonGameTag' = 69719 - FUNC_SNOW_SPORTS_SLOPE_SKIS_RENTED: 'CommonGameTag' = 69678 - FUNC_SNOW_SPORTS_SLOPE_SLED: 'CommonGameTag' = 69645 - FUNC_SNOW_SPORTS_SLOPE_SNOWBOARD: 'CommonGameTag' = 69644 - FUNC_SNOW_SPORTS_SLOPE_SNOWBOARD_ADULT: 'CommonGameTag' = 69716 - FUNC_SNOW_SPORTS_SLOPE_SNOWBOARD_ADULT_RENTABLE: 'CommonGameTag' = 69718 - FUNC_SNOW_SPORTS_SLOPE_SNOWBOARD_CHILD: 'CommonGameTag' = 69677 - FUNC_SNOW_SPORTS_SLOPE_SNOWBOARD_CHILD_RENTABLE: 'CommonGameTag' = 69720 - FUNC_SNOW_SPORTS_SLOPE_SNOWBOARD_RENTED: 'CommonGameTag' = 69679 - FUNC_SOAP: 'CommonGameTag' = 1423 - FUNC_SOCCER_BALL: 'CommonGameTag' = 65540 - FUNC_SOCIAL: 'CommonGameTag' = 1000 - FUNC_SOLAR_PANEL: 'CommonGameTag' = 67613 - FUNC_SOUND: 'CommonGameTag' = 517 - FUNC_SPACE: 'CommonGameTag' = 497 - FUNC_SPACESHIP: 'CommonGameTag' = 994 - FUNC_SPACE_RANGER: 'CommonGameTag' = 1132 - FUNC_SPAWNER: 'CommonGameTag' = 2782 - FUNC_SPECTER: 'CommonGameTag' = 86022 - FUNC_SPECTER_JAR_FRIENDLY: 'CommonGameTag' = 86023 - FUNC_SPECTER_JAR_MEAN: 'CommonGameTag' = 86024 - FUNC_SPECTER_JAR_MYSTERIOUS: 'CommonGameTag' = 86025 - FUNC_SPELLS_DUPLICATE: 'CommonGameTag' = 49165 - FUNC_SPELLS_DUPLICATE_BG: 'CommonGameTag' = 2268 - FUNC_SPELLS_STEAL: 'CommonGameTag' = 49167 - FUNC_SPELLS_STEAL_BG: 'CommonGameTag' = 2436 - FUNC_SPIDER: 'CommonGameTag' = 1192 - FUNC_SPIRIT: 'CommonGameTag' = 1197 - FUNC_SPLASH_PAD: 'CommonGameTag' = 116739 - FUNC_SPLASH_PAD_OPEN_STREET: 'CommonGameTag' = 116758 - FUNC_SPLASH_PAD_PLAY_ON: 'CommonGameTag' = 116756 - FUNC_SPLASH_PAD_WHALE: 'CommonGameTag' = 116759 - FUNC_SPOOK: 'CommonGameTag' = 1196 - FUNC_SPOOKY: 'CommonGameTag' = 1178 - FUNC_SPORTS_ARENA_ARTS: 'CommonGameTag' = 65607 - FUNC_SPORTS_ARENA_SCIENCE: 'CommonGameTag' = 65608 - FUNC_SPRINKLER: 'CommonGameTag' = 1061 - FUNC_SPRINKLER_FLOOR: 'CommonGameTag' = 2099 - FUNC_SP_TABLE: 'CommonGameTag' = 1182 - FUNC_STAGE_GATE_ACTORS: 'CommonGameTag' = 61464 - FUNC_STAGE_LIGHT_ALL: 'CommonGameTag' = 61461 - FUNC_STAGE_MARK_DUO_1_1: 'CommonGameTag' = 61443 - FUNC_STAGE_MARK_DUO_1_2: 'CommonGameTag' = 61444 - FUNC_STAGE_MARK_DUO_1_3: 'CommonGameTag' = 61445 - FUNC_STAGE_MARK_DUO_2_1: 'CommonGameTag' = 61481 - FUNC_STAGE_MARK_DUO_2_2: 'CommonGameTag' = 61482 - FUNC_STAGE_MARK_DUO_2_3: 'CommonGameTag' = 61483 - FUNC_STAGE_MARK_DUO_3_1: 'CommonGameTag' = 61484 - FUNC_STAGE_MARK_DUO_3_2: 'CommonGameTag' = 61485 - FUNC_STAGE_MARK_DUO_3_3: 'CommonGameTag' = 61486 - FUNC_STAGE_MARK_DUO_SWORD_FIGHT: 'CommonGameTag' = 61623 - FUNC_STAGE_MARK_SOLO_1_1: 'CommonGameTag' = 61446 - FUNC_STAGE_MARK_SOLO_1_2: 'CommonGameTag' = 61447 - FUNC_STAGE_MARK_SOLO_1_3: 'CommonGameTag' = 61448 - FUNC_STAGE_MARK_SOLO_2_1: 'CommonGameTag' = 61487 - FUNC_STAGE_MARK_SOLO_2_2: 'CommonGameTag' = 61488 - FUNC_STAGE_MARK_SOLO_2_3: 'CommonGameTag' = 61489 - FUNC_STAGE_MARK_SOLO_3_1: 'CommonGameTag' = 61490 - FUNC_STAGE_MARK_SOLO_3_2: 'CommonGameTag' = 61491 - FUNC_STAGE_MARK_SOLO_3_3: 'CommonGameTag' = 61492 - FUNC_STAGE_MARK_SOLO_DEATH: 'CommonGameTag' = 61622 - FUNC_STALLS_CURIO_SHOP_OBJECTS: 'CommonGameTag' = 47107 - FUNC_STALLS_PRODUCE_CURRY_CHILI: 'CommonGameTag' = 55342 - FUNC_STALLS_PRODUCE_GROCERY: 'CommonGameTag' = 55341 - FUNC_STALLS_PRODUCE_SAFFRON: 'CommonGameTag' = 55343 - FUNC_STALLS_PRODUCE_WASABI: 'CommonGameTag' = 55344 - FUNC_STALLS_SCHWAG_FESTIVAL_ALL_STALLS: 'CommonGameTag' = 55349 - FUNC_STALLS_SCHWAG_FESTIVAL_BLOSSOM: 'CommonGameTag' = 55336 - FUNC_STALLS_SCHWAG_FESTIVAL_FLEA_MARKET: 'CommonGameTag' = 55337 - FUNC_STALLS_SCHWAG_FESTIVAL_FOOD: 'CommonGameTag' = 55338 - FUNC_STALLS_SCHWAG_FESTIVAL_LAMP: 'CommonGameTag' = 55339 - FUNC_STALLS_SCHWAG_FESTIVAL_LOGIC: 'CommonGameTag' = 55340 - FUNC_STAND: 'CommonGameTag' = 1166 - FUNC_STANDING_LAMP: 'CommonGameTag' = 1137 - FUNC_STATUE: 'CommonGameTag' = 1156 - FUNC_STEAM_FISSURE: 'CommonGameTag' = 24585 - FUNC_STEAM_ROOM: 'CommonGameTag' = 18444 - FUNC_STEAM_VENT: 'CommonGameTag' = 63500 - FUNC_STEPS: 'CommonGameTag' = 1077 - FUNC_STEREO: 'CommonGameTag' = 516 - FUNC_STEREO_PUBLIC: 'CommonGameTag' = 2135 - FUNC_STICKER: 'CommonGameTag' = 1152 - FUNC_STONE: 'CommonGameTag' = 1089 - FUNC_STOOL: 'CommonGameTag' = 1008 - FUNC_STORE: 'CommonGameTag' = 12424 - FUNC_STRATEGY: 'CommonGameTag' = 487 - FUNC_STRIPED: 'CommonGameTag' = 1388 - FUNC_STUFFED: 'CommonGameTag' = 504 - FUNC_STUFFED_ANIMAL: 'CommonGameTag' = 1020 - FUNC_STUMP: 'CommonGameTag' = 1308 - FUNC_STYLEBOARD: 'CommonGameTag' = 2130 - FUNC_SUGAR_SKULL: 'CommonGameTag' = 1567 - FUNC_SUITCASE: 'CommonGameTag' = 2950 - FUNC_SUITCASE_CHILD: 'CommonGameTag' = 116754 - FUNC_SUITCASE_DESTROY: 'CommonGameTag' = 116751 - FUNC_SUNFLOWER: 'CommonGameTag' = 1398 - FUNC_SUPPLIES: 'CommonGameTag' = 1294 - FUNC_SWIM: 'CommonGameTag' = 1231 - FUNC_SWIMMING_POOL: 'CommonGameTag' = 1232 - FUNC_SWING_SET: 'CommonGameTag' = 2125 - FUNC_SWING_SET_BG: 'CommonGameTag' = 2120 - FUNC_SWIPE_BASIC: 'CommonGameTag' = 2136 - FUNC_SWIPE_HIGH_SKILL: 'CommonGameTag' = 2138 - FUNC_SWIPE_HOUSEHOLD_INVENTORY_BASIC: 'CommonGameTag' = 2139 - FUNC_SWIPE_HOUSEHOLD_INVENTORY_HIGH_SKILL: 'CommonGameTag' = 2141 - FUNC_SWIPE_HOUSEHOLD_INVENTORY_MED_SKILL: 'CommonGameTag' = 2140 - FUNC_SWIPE_MED_SKILL: 'CommonGameTag' = 2137 - FUNC_SYNC_SHOE_REMOVAL_RULE: 'CommonGameTag' = 69667 - FUNC_SYSTEM: 'CommonGameTag' = 518 - FUNC_SYSTEM_SPAWNED_DUST_FRIEND: 'CommonGameTag' = 2522 - FUNC_SYSTEM_SPAWNED_DUST_PILE: 'CommonGameTag' = 2523 - FUNC_SYSTEM_SPAWNED_SPECTER: 'CommonGameTag' = 2524 - FUNC_SYSTEM_SPAWNED_WILD_GRASS: 'CommonGameTag' = 2983 - FUNC_TABLE: 'CommonGameTag' = 486 - FUNC_TABLET: 'CommonGameTag' = 1108 - FUNC_TABLE_CHANGE_DIAPER: 'CommonGameTag' = 2915 - FUNC_TABLE_CLOTH: 'CommonGameTag' = 1335 - FUNC_TABLE_DINING: 'CommonGameTag' = 2769 - FUNC_TABLE_DINING_BAR: 'CommonGameTag' = 1538 - FUNC_TABLE_DINING_UMBRELLA: 'CommonGameTag' = 1547 - FUNC_TABLE_LOW: 'CommonGameTag' = 2507 - FUNC_TANK: 'CommonGameTag' = 1433 - FUNC_TARP: 'CommonGameTag' = 1289 - FUNC_TEA: 'CommonGameTag' = 577 - FUNC_TEA_SET: 'CommonGameTag' = 133126 - FUNC_TECH_GURU: 'CommonGameTag' = 1133 - FUNC_TEDDY: 'CommonGameTag' = 1073 - FUNC_TEDDY_BEAR: 'CommonGameTag' = 1074 - FUNC_TELESCOPE: 'CommonGameTag' = 571 - FUNC_TELEVISION: 'CommonGameTag' = 470 - FUNC_TELLER: 'CommonGameTag' = 1181 - FUNC_TEMPERATURE_COOLER: 'CommonGameTag' = 2060 - FUNC_TEMPERATURE_HEATER: 'CommonGameTag' = 2059 - FUNC_TEMPLE_CHEST: 'CommonGameTag' = 45091 - FUNC_TEMPLE_GATE: 'CommonGameTag' = 45057 - FUNC_TEMPLE_TRAP: 'CommonGameTag' = 45058 - FUNC_TEMP_CRAFT_SALES_TABLE_CREATED_OBJECTS: 'CommonGameTag' = 55370 - FUNC_TEMP_CRAFT_SALES_TABLE_CREATED_OBJECTS_BG: 'CommonGameTag' = 2040 - FUNC_TENT: 'CommonGameTag' = 2478 - FUNC_TERM_PRESENTATION_CLASS_A: 'CommonGameTag' = 65649 - FUNC_TERM_PRESENTATION_CLASS_B: 'CommonGameTag' = 65650 - FUNC_TERM_PRESENTATION_CLASS_C: 'CommonGameTag' = 65651 - FUNC_TERM_PRESENTATION_CLASS_D: 'CommonGameTag' = 65652 - FUNC_TERRACOTTA: 'CommonGameTag' = 1087 - FUNC_TERRARIUM: 'CommonGameTag' = 77827 - FUNC_THERMOSTAT: 'CommonGameTag' = 59456 - FUNC_THRIFT_STORE_RETAIL_RACK: 'CommonGameTag' = 114699 - FUNC_THROWING_MUD: 'CommonGameTag' = 59428 - FUNC_THROWING_SNOWBALLS: 'CommonGameTag' = 2487 - FUNC_THROWING_WATER_BALLOONS: 'CommonGameTag' = 59427 - FUNC_THROW_FOOTBALL: 'CommonGameTag' = 114737 - FUNC_TILE: 'CommonGameTag' = 1088 - FUNC_TOASTING_BUCKET: 'CommonGameTag' = 133149 - FUNC_TOASTING_BUCKET_BG: 'CommonGameTag' = 2764 - FUNC_TODDLER: 'CommonGameTag' = 1685 - FUNC_TODDLER_BALL_PIT: 'CommonGameTag' = 73734 - FUNC_TODDLER_BED: 'CommonGameTag' = 1658 - FUNC_TODDLER_BOOKCASE: 'CommonGameTag' = 1666 - FUNC_TODDLER_GYM_OBJECT_BALL_PIT: 'CommonGameTag' = 2928 - FUNC_TODDLER_GYM_OBJECT_FULL: 'CommonGameTag' = 1727 - FUNC_TODDLER_GYM_OBJECT_SLIDE: 'CommonGameTag' = 1726 - FUNC_TODDLER_GYM_OBJECT_SLIDE_CLIMBER: 'CommonGameTag' = 2929 - FUNC_TODDLER_GYM_OBJECT_TUNNELS: 'CommonGameTag' = 2930 - FUNC_TODDLER_JUNGLE_GYM_OBJECT: 'CommonGameTag' = 73729 - FUNC_TODDLER_PERSONALITY_PICKY_EATER_MIXED_FOOD: 'CommonGameTag' = 2933 - FUNC_TODDLER_SEATING: 'CommonGameTag' = 1676 - FUNC_TODDLER_SLIDE: 'CommonGameTag' = 2935 - FUNC_TODDLER_TOY_BOX: 'CommonGameTag' = 1665 - FUNC_TOILET: 'CommonGameTag' = 1881 - FUNC_TOILET_TALKING: 'CommonGameTag' = 55311 - FUNC_TOMB: 'CommonGameTag' = 1202 - FUNC_TOMBSTONE: 'CommonGameTag' = 1199 - FUNC_TOWEL: 'CommonGameTag' = 1147 - FUNC_TOY: 'CommonGameTag' = 505 - FUNC_TOY_BOX: 'CommonGameTag' = 1018 - FUNC_TOY_BOX_PURCHASE: 'CommonGameTag' = 1646 - FUNC_TOY_BOX_TOYS_TO_CLEAN_UP: 'CommonGameTag' = 533 - FUNC_TOY_ROBOT: 'CommonGameTag' = 65625 - FUNC_TRASH: 'CommonGameTag' = 581 - FUNC_TRASHCAN_DIAPER_PAIL: 'CommonGameTag' = 2916 - FUNC_TRASHCAN_INDOOR_LIDDED: 'CommonGameTag' = 2951 - FUNC_TRASH_CAN: 'CommonGameTag' = 891 - FUNC_TRASH_CAN_HI_TECH: 'CommonGameTag' = 2443 - FUNC_TRASH_CAN_INDOOR: 'CommonGameTag' = 2349 - FUNC_TRASH_CAN_OUTDOOR: 'CommonGameTag' = 892 - FUNC_TRASH_PILE: 'CommonGameTag' = 568 - FUNC_TRASH_PILE_COMPOSTABLE: 'CommonGameTag' = 2335 - FUNC_TRASH_PILE_RECYCLABLE: 'CommonGameTag' = 2334 - FUNC_TREADMILL: 'CommonGameTag' = 478 - FUNC_TREASURE: 'CommonGameTag' = 63510 - FUNC_TREASURE_CHEST: 'CommonGameTag' = 45113 - FUNC_TREE: 'CommonGameTag' = 1332 - FUNC_TREEHOUSE: 'CommonGameTag' = 116752 - FUNC_TREEHOUSE_BASE: 'CommonGameTag' = 116743 - FUNC_TREEHOUSE_BELL: 'CommonGameTag' = 116746 - FUNC_TREEHOUSE_COMPATIBLE: 'CommonGameTag' = 116750 - FUNC_TREEHOUSE_LIGHTS: 'CommonGameTag' = 116753 - FUNC_TREEHOUSE_POLE: 'CommonGameTag' = 116745 - FUNC_TREEHOUSE_SLIDE: 'CommonGameTag' = 116744 - FUNC_TREND_CELEBRITY: 'CommonGameTag' = 61638 - FUNC_TREND_PRODUCT_REVIEW_BEAUTY: 'CommonGameTag' = 61547 - FUNC_TREND_PRODUCT_REVIEW_TECH: 'CommonGameTag' = 61548 - FUNC_TREND_PRODUCT_REVIEW_TOY: 'CommonGameTag' = 61549 - FUNC_TREND_SKILL_ACTING: 'CommonGameTag' = 61635 - FUNC_TREND_SKILL_ARCHAEOLOGY: 'CommonGameTag' = 61501 - FUNC_TREND_SKILL_BAKING: 'CommonGameTag' = 61502 - FUNC_TREND_SKILL_BOWLING: 'CommonGameTag' = 61503 - FUNC_TREND_SKILL_CHARISMA: 'CommonGameTag' = 61504 - FUNC_TREND_SKILL_COMEDY: 'CommonGameTag' = 61505 - FUNC_TREND_SKILL_COOKING_GOURMET: 'CommonGameTag' = 61506 - FUNC_TREND_SKILL_COOKING_HOME_STYLE: 'CommonGameTag' = 61507 - FUNC_TREND_SKILL_DANCING: 'CommonGameTag' = 61508 - FUNC_TREND_SKILL_DJ_MIXING: 'CommonGameTag' = 61509 - FUNC_TREND_SKILL_FISHING: 'CommonGameTag' = 61510 - FUNC_TREND_SKILL_FITNESS: 'CommonGameTag' = 61511 - FUNC_TREND_SKILL_FLOWER_ARRANGING: 'CommonGameTag' = 2750 - FUNC_TREND_SKILL_GARDENING: 'CommonGameTag' = 61513 - FUNC_TREND_SKILL_GUITAR: 'CommonGameTag' = 61514 - FUNC_TREND_SKILL_HANDINESS: 'CommonGameTag' = 61515 - FUNC_TREND_SKILL_HERBALISM: 'CommonGameTag' = 61516 - FUNC_TREND_SKILL_JUICE_FIZZING: 'CommonGameTag' = 67619 - FUNC_TREND_SKILL_KNIT: 'CommonGameTag' = 2460 - FUNC_TREND_SKILL_KNITTING: 'CommonGameTag' = 83970 - FUNC_TREND_SKILL_LOCAL_CULTURE: 'CommonGameTag' = 61517 - FUNC_TREND_SKILL_LOGIC: 'CommonGameTag' = 61518 - FUNC_TREND_SKILL_MEDIA_PRODUCTION: 'CommonGameTag' = 61630 - FUNC_TREND_SKILL_MISCHIEF: 'CommonGameTag' = 61519 - FUNC_TREND_SKILL_MIXOLOGY: 'CommonGameTag' = 61520 - FUNC_TREND_SKILL_PAINTING: 'CommonGameTag' = 61521 - FUNC_TREND_SKILL_PARENTING: 'CommonGameTag' = 61522 - FUNC_TREND_SKILL_PET_TRAINING: 'CommonGameTag' = 61523 - FUNC_TREND_SKILL_PHOTOGRAPHY: 'CommonGameTag' = 61524 - FUNC_TREND_SKILL_PIANO: 'CommonGameTag' = 61525 - FUNC_TREND_SKILL_PIPE_ORGAN: 'CommonGameTag' = 61526 - FUNC_TREND_SKILL_PROGRAMMING: 'CommonGameTag' = 61527 - FUNC_TREND_SKILL_ROBOTICS: 'CommonGameTag' = 65632 - FUNC_TREND_SKILL_ROCKET_SCIENCE: 'CommonGameTag' = 61631 - FUNC_TREND_SKILL_SINGING: 'CommonGameTag' = 61528 - FUNC_TREND_SKILL_VAMPIRE_LORE: 'CommonGameTag' = 61529 - FUNC_TREND_SKILL_VETERINARIAN: 'CommonGameTag' = 61530 - FUNC_TREND_SKILL_VIDEO_GAMING: 'CommonGameTag' = 61531 - FUNC_TREND_SKILL_VIOLIN: 'CommonGameTag' = 61532 - FUNC_TREND_SKILL_WELLNESS: 'CommonGameTag' = 61533 - FUNC_TREND_SKILL_WRITING: 'CommonGameTag' = 61534 - FUNC_TREND_TIPS_BEAUTY: 'CommonGameTag' = 61545 - FUNC_TREND_TIPS_FASHION: 'CommonGameTag' = 61546 - FUNC_TREND_TODDLER_CHILD: 'CommonGameTag' = 61550 - FUNC_TREND_TRAVEL: 'CommonGameTag' = 61551 - FUNC_TREND_VLOG_ANGRY: 'CommonGameTag' = 61535 - FUNC_TREND_VLOG_CONFIDENT: 'CommonGameTag' = 61536 - FUNC_TREND_VLOG_DAZED: 'CommonGameTag' = 61537 - FUNC_TREND_VLOG_EMBARRASSED: 'CommonGameTag' = 61538 - FUNC_TREND_VLOG_ENERGIZED: 'CommonGameTag' = 61539 - FUNC_TREND_VLOG_FLIRTY: 'CommonGameTag' = 61540 - FUNC_TREND_VLOG_FOCUSED: 'CommonGameTag' = 61610 - FUNC_TREND_VLOG_HAPPY: 'CommonGameTag' = 61541 - FUNC_TREND_VLOG_INSPIRED: 'CommonGameTag' = 61542 - FUNC_TREND_VLOG_PLAYFUL: 'CommonGameTag' = 61543 - FUNC_TREND_VLOG_SAD: 'CommonGameTag' = 61544 - FUNC_TRIANGLE: 'CommonGameTag' = 1424 - FUNC_TRIM: 'CommonGameTag' = 1135 - FUNC_TRUNK: 'CommonGameTag' = 1292 - FUNC_TURTLE: 'CommonGameTag' = 1241 - FUNC_TV: 'CommonGameTag' = 471 - FUNC_TV_STAND_SEARCH: 'CommonGameTag' = 2243 - FUNC_TWIST: 'CommonGameTag' = 8215 - FUNC_UMBRELLA: 'CommonGameTag' = 59430 - FUNC_UMBRELLA_ADULT: 'CommonGameTag' = 59443 - FUNC_UMBRELLA_CHILD: 'CommonGameTag' = 59444 - FUNC_UMBRELLA_RACK: 'CommonGameTag' = 59441 - FUNC_UMBRELLA_TABLE: 'CommonGameTag' = 1553 - FUNC_UMBRELLA_USER: 'CommonGameTag' = 2118 - FUNC_UNBREAKABLE_OBJECT: 'CommonGameTag' = 1172 - FUNC_UNICORN: 'CommonGameTag' = 507 - FUNC_UNIVERSITY_HOUSING_BED: 'CommonGameTag' = 65626 - FUNC_UNIVERSITY_KIOSK_ACADEMIC: 'CommonGameTag' = 65575 - FUNC_UNIVERSITY_KIOSK_DECO_SURFACE: 'CommonGameTag' = 65574 - FUNC_UNIVERSITY_KIOSK_DECO_WALL: 'CommonGameTag' = 65573 - FUNC_UNIVERSITY_KIOSK_DECO_WALL_ST: 'CommonGameTag' = 65615 - FUNC_UNIVERSITY_KIOSK_ITEM: 'CommonGameTag' = 65564 - FUNC_UNIVERSITY_KIOSK_ITEM_ST: 'CommonGameTag' = 65614 - FUNC_UNIVERSITY_TEXT_BOOK: 'CommonGameTag' = 2235 - FUNC_UNUSED_USE_ME: 'CommonGameTag' = 2175 - FUNC_UNUSED_USE_ME_2: 'CommonGameTag' = 2228 - FUNC_URN: 'CommonGameTag' = 1076 - FUNC_URNSTONE: 'CommonGameTag' = 814 - FUNC_USE_SLOTTING_SOUND_OVERRIDE: 'CommonGameTag' = 2552 - FUNC_VACUUM_CLEANER: 'CommonGameTag' = 94210 - FUNC_VACUUM_CLEANER_HANDHELD: 'CommonGameTag' = 94211 - FUNC_VACUUM_CLEANER_HIGH: 'CommonGameTag' = 94218 - FUNC_VACUUM_CLEANER_LOW: 'CommonGameTag' = 94226 - FUNC_VACUUM_CLEANER_MED: 'CommonGameTag' = 94219 - FUNC_VACUUM_CLEANER_UPRIGHT: 'CommonGameTag' = 94212 - FUNC_VACUUM_HEIGHT_FLOOR: 'CommonGameTag' = 94220 - FUNC_VACUUM_HEIGHT_HIGH: 'CommonGameTag' = 94223 - FUNC_VACUUM_HEIGHT_LOW: 'CommonGameTag' = 94221 - FUNC_VACUUM_HEIGHT_MEDIUM: 'CommonGameTag' = 94222 - FUNC_VALENTINES_DAY: 'CommonGameTag' = 1370 - FUNC_VAMPIRE_TOME: 'CommonGameTag' = 40961 - FUNC_VAMPIRE_TOME_SET_1: 'CommonGameTag' = 40974 - FUNC_VAMPIRE_TOME_SET_2: 'CommonGameTag' = 40975 - FUNC_VAMPIRE_TOME_SET_3: 'CommonGameTag' = 40976 - FUNC_VAMPIRE_TOME_ULTIMATE: 'CommonGameTag' = 40977 - FUNC_VANITY_TABLE: 'CommonGameTag' = 36866 - FUNC_VASE: 'CommonGameTag' = 1145 - FUNC_VAULT_DOOR: 'CommonGameTag' = 61472 - FUNC_VAULT_SAFE: 'CommonGameTag' = 61471 - FUNC_VEHICLE: 'CommonGameTag' = 2226 - FUNC_VEHICLE_BIKE: 'CommonGameTag' = 2227 - FUNC_VEHICLE_BIKE_CHILD: 'CommonGameTag' = 2936 - FUNC_VEHICLE_BIKE_HORN: 'CommonGameTag' = 2937 - FUNC_VEHICLE_BIKE_TYAE: 'CommonGameTag' = 2938 - FUNC_VEHICLE_LAND: 'CommonGameTag' = 2231 - FUNC_VEHICLE_WATER: 'CommonGameTag' = 2232 - FUNC_VENDING_MACHINE_COLD_DRINK_AND_SNACK_ENERGY_EP10: 'CommonGameTag' = 69672 - FUNC_VENDING_MACHINE_COLD_DRINK_AND_SNACK_FOOD_EP10: 'CommonGameTag' = 69671 - FUNC_VENDING_MACHINE_COLD_DRINK_AND_SNACK_FRUIT_EP10: 'CommonGameTag' = 69673 - FUNC_VENDING_MACHINE_HOT_FOOD_AND_DRINK_ENERGY_EP10: 'CommonGameTag' = 69670 - FUNC_VENDING_MACHINE_HOT_FOOD_AND_DRINK_FOOD_EP10: 'CommonGameTag' = 69669 - FUNC_VENUE_NOT_DESTROYABLE_BY_CLEAN_UP: 'CommonGameTag' = 2013 - FUNC_VENUE_NOT_UNBROKEN_BY_CLEAN_UP: 'CommonGameTag' = 2509 - FUNC_VERTICAL_GARDEN: 'CommonGameTag' = 67618 - FUNC_VET: 'CommonGameTag' = 57378 - FUNC_VET_EXAM_TABLE: 'CommonGameTag' = 57375 - FUNC_VET_MEDICINE_STATION: 'CommonGameTag' = 57428 - FUNC_VET_PODIUM: 'CommonGameTag' = 57374 - FUNC_VET_SURGERY_STATION: 'CommonGameTag' = 57390 - FUNC_VET_VENDING_MACHINE: 'CommonGameTag' = 57430 - FUNC_VFX_MACHINE_CONTROL_DESK: 'CommonGameTag' = 61479 - FUNC_VFX_MACHINE_EMITTER: 'CommonGameTag' = 61468 - FUNC_VIDEO_GAME: 'CommonGameTag' = 1644 - FUNC_VIDEO_GAME_2: 'CommonGameTag' = 479 - FUNC_VIDEO_GAME_CONSOLE_DISPLAY: 'CommonGameTag' = 55368 - FUNC_VIDEO_GAMING: 'CommonGameTag' = 24596 - FUNC_VIDEO_RECORDING: 'CommonGameTag' = 61474 - FUNC_VIDEO_RECORDING_BG: 'CommonGameTag' = 2189 - FUNC_VIDEO_STATION: 'CommonGameTag' = 61473 - FUNC_VILLAGE_FAIR_COMPETITION_STAND: 'CommonGameTag' = 112665 - FUNC_VILLAGE_FAIR_COMPETITION_STAND_A: 'CommonGameTag' = 112667 - FUNC_VILLAGE_FAIR_COMPETITION_STAND_B: 'CommonGameTag' = 112668 - FUNC_VILLAGE_FAIR_NPC_CHICKEN: 'CommonGameTag' = 112689 - FUNC_VILLAGE_SHOPS_CAT_ANIMAL: 'CommonGameTag' = 2655 - FUNC_VILLAGE_SHOPS_CAT_BOOKS: 'CommonGameTag' = 2656 - FUNC_VILLAGE_SHOPS_CAT_FISH: 'CommonGameTag' = 2657 - FUNC_VILLAGE_SHOPS_CAT_FLOWERS: 'CommonGameTag' = 2658 - FUNC_VILLAGE_SHOPS_CAT_FRUIT: 'CommonGameTag' = 2659 - FUNC_VILLAGE_SHOPS_CAT_GARDEN_INGREDIENTS: 'CommonGameTag' = 2660 - FUNC_VILLAGE_SHOPS_CAT_GROCERY_INGREDIENTS: 'CommonGameTag' = 2661 - FUNC_VILLAGE_SHOPS_CAT_MISC: 'CommonGameTag' = 2662 - FUNC_VILLAGE_SHOPS_CAT_SEEDS: 'CommonGameTag' = 2663 - FUNC_VILLAGE_SHOPS_CAT_SPECIAL: 'CommonGameTag' = 2664 - FUNC_VILLAGE_SHOPS_CAT_VEGETABLES: 'CommonGameTag' = 2665 - FUNC_VILLAGE_SHOPS_SELLABLE: 'CommonGameTag' = 2583 - FUNC_VILLAGE_SIGN: 'CommonGameTag' = 112688 - FUNC_VILLAIN: 'CommonGameTag' = 1128 - FUNC_VIOLIN: 'CommonGameTag' = 569 - FUNC_VIOLIN_ADULT: 'CommonGameTag' = 1635 - FUNC_VIP_ROPE: 'CommonGameTag' = 61477 - FUNC_VOCAL: 'CommonGameTag' = 490 - FUNC_VOODOO: 'CommonGameTag' = 582 - FUNC_WAINSCOTING: 'CommonGameTag' = 1085 - FUNC_WAITER_STATION: 'CommonGameTag' = 26626 - FUNC_WALL_LAMP: 'CommonGameTag' = 1112 - FUNC_WALL_TEST_LINE_OF_SIGHT: 'CommonGameTag' = 2029 - FUNC_WANDS: 'CommonGameTag' = 49173 - FUNC_WARDROBE_PEDESTAL: 'CommonGameTag' = 61441 - FUNC_WARMING_RACK: 'CommonGameTag' = 12375 - FUNC_WATER_SCOOTER: 'CommonGameTag' = 63490 - FUNC_WATER_SCOOTER_BEACH_VENUE: 'CommonGameTag' = 2197 - FUNC_WATER_TROUGH: 'CommonGameTag' = 118877 - FUNC_WAX_BLOCK: 'CommonGameTag' = 67630 - FUNC_WEB: 'CommonGameTag' = 1191 - FUNC_WEDDING_AISLE: 'CommonGameTag' = 2756 - FUNC_WEDDING_AISLE_LONG: 'CommonGameTag' = 2772 - FUNC_WEDDING_AISLE_MEDIUM: 'CommonGameTag' = 2771 - FUNC_WEDDING_AISLE_SHORT: 'CommonGameTag' = 2770 - FUNC_WEDDING_ARCH: 'CommonGameTag' = 2747 - FUNC_WEDDING_BOUQUET: 'CommonGameTag' = 2751 - FUNC_WEDDING_CAKE_CUPCAKE_TOWER: 'CommonGameTag' = 133128 - FUNC_WEDDING_CAKE_CYLINDER: 'CommonGameTag' = 133129 - FUNC_WEDDING_CAKE_CYLINDER_3D: 'CommonGameTag' = 133130 - FUNC_WEDDING_CAKE_CYLINDER_BEACHY: 'CommonGameTag' = 133131 - FUNC_WEDDING_CAKE_CYLINDER_FLORAL: 'CommonGameTag' = 133132 - FUNC_WEDDING_CAKE_HEART: 'CommonGameTag' = 133133 - FUNC_WEDDING_CAKE_HEXAGON: 'CommonGameTag' = 133134 - FUNC_WEDDING_CAKE_LARGE_ANIM: 'CommonGameTag' = 2758 - FUNC_WEDDING_CAKE_PILLOW: 'CommonGameTag' = 133135 - FUNC_WEDDING_CAKE_PROP_CHOCOLATE: 'CommonGameTag' = 2760 - FUNC_WEDDING_CAKE_PROP_RED_VELVET: 'CommonGameTag' = 2762 - FUNC_WEDDING_CAKE_PROP_VANILLA: 'CommonGameTag' = 2761 - FUNC_WEDDING_CAKE_SQUARE: 'CommonGameTag' = 133136 - FUNC_WEDDING_CAKE_TOPPER: 'CommonGameTag' = 2757 - FUNC_WEDDING_CAKE_TOPPER_COW_PLANT: 'CommonGameTag' = 133137 - FUNC_WEDDING_CAKE_TOPPER_CUT_OUT: 'CommonGameTag' = 133138 - FUNC_WEDDING_CAKE_TOPPER_FIGURES: 'CommonGameTag' = 133139 - FUNC_WEDDING_CAKE_TOPPER_FLORAL_ROSE: 'CommonGameTag' = 133140 - FUNC_WEDDING_CAKE_TOPPER_FLORAL_TROPICAL: 'CommonGameTag' = 133141 - FUNC_WEDDING_CAKE_TOPPER_HEARTS: 'CommonGameTag' = 133142 - FUNC_WEDDING_CAKE_TOPPER_LETTERING: 'CommonGameTag' = 133143 - FUNC_WEDDING_CAKE_TOPPER_PENNANTS: 'CommonGameTag' = 133144 - FUNC_WEDDING_CAKE_TOPPER_RAINBOW: 'CommonGameTag' = 133145 - FUNC_WEDDING_CAKE_TOPPER_STARS: 'CommonGameTag' = 133146 - FUNC_WELLNESS: 'CommonGameTag' = 18453 - FUNC_WELLNESS_MONEY: 'CommonGameTag' = 2793 - FUNC_WEREWOLF: 'CommonGameTag' = 1215 - FUNC_WEREWOLF_CANNOT_DEVOUR: 'CommonGameTag' = 2794 - FUNC_WEREWOLF_PACK_ACCEPTABLE_GIFT: 'CommonGameTag' = 2786 - FUNC_WFS: 'CommonGameTag' = 61480 - FUNC_WFS_PRE_MADE_CELEBRITY: 'CommonGameTag' = 61612 - FUNC_WHIRLPOOL_TUB: 'CommonGameTag' = 882 - FUNC_WILDERNESS: 'CommonGameTag' = 1279 - FUNC_WILDLIFE_ENCOUNTER_DETERRENT: 'CommonGameTag' = 69665 - FUNC_WILDLIFE_ENCOUNTER_REMEDY: 'CommonGameTag' = 69666 - FUNC_WILD_GRASS: 'CommonGameTag' = 118789 - FUNC_WILD_GRASS_SYSTEM_SPAWNED: 'CommonGameTag' = 118788 - FUNC_WIND_CHIMES: 'CommonGameTag' = 34819 - FUNC_WIND_TURBINE: 'CommonGameTag' = 67614 - FUNC_WIND_TURBINE_UPGRADED_LIGHTNING_ROD: 'CommonGameTag' = 2437 - FUNC_WISHING_WELL: 'CommonGameTag' = 30722 - FUNC_WITCH: 'CommonGameTag' = 1218 - FUNC_WOLF_TOWN_GREG_SIGN: 'CommonGameTag' = 135185 - FUNC_WOLF_TOWN_PORTAL_HOWL_SPOT_BOTTOM: 'CommonGameTag' = 135171 - FUNC_WOLF_TOWN_PORTAL_HOWL_SPOT_TOP: 'CommonGameTag' = 135172 - FUNC_WOLF_TOWN_PORTAL_MINE: 'CommonGameTag' = 135173 - FUNC_WOLF_TOWN_PORTAL_ON_LOT_VERSION: 'CommonGameTag' = 135176 - FUNC_WOLF_TOWN_PORTAL_PORTA_POTTY: 'CommonGameTag' = 135174 - FUNC_WOLF_TOWN_PORTAL_SEWER: 'CommonGameTag' = 135175 - FUNC_WOLF_TOWN_SHELL_PACK_A: 'CommonGameTag' = 135169 - FUNC_WOLF_TOWN_SHELL_PACK_B: 'CommonGameTag' = 135170 - FUNC_WOOD: 'CommonGameTag' = 1319 - FUNC_WOODWORKING: 'CommonGameTag' = 1462 - FUNC_WOOL: 'CommonGameTag' = 2578 - FUNC_WOOL_SEARCH: 'CommonGameTag' = 112686 - FUNC_WORKBENCH: 'CommonGameTag' = 493 - FUNC_WORKOUT: 'CommonGameTag' = 472 - FUNC_WORKOUT_MACHINE: 'CommonGameTag' = 1324 - FUNC_WRITER: 'CommonGameTag' = 1117 - FUNC_WRITING: 'CommonGameTag' = 1106 - FUNC_XMAS: 'CommonGameTag' = 1331 - FUNC_YARNY: 'CommonGameTag' = 83971 - FUNC_YARNY_STATUE: 'CommonGameTag' = 83991 - FUNC_YARN_BASKET: 'CommonGameTag' = 2625 - FUNC_YOGA: 'CommonGameTag' = 18458 - FUNC_YOGA_CLASS_INSTRUCTOR_MAT: 'CommonGameTag' = 18447 - FUNC_YOGA_CLASS_MEMBER_MAT: 'CommonGameTag' = 18448 - FUNC_YOGA_CLASS_MEMBER_TEMP_MAT: 'CommonGameTag' = 18449 - FUNC_YOGA_MAT: 'CommonGameTag' = 18433 - FUR_CHOW: 'CommonGameTag' = 57356 - FUR_COLLIE: 'CommonGameTag' = 57364 - FUR_LENGTH_HAIRLESS: 'CommonGameTag' = 2018 - FUR_LENGTH_LONG_HAIR: 'CommonGameTag' = 2017 - FUR_LENGTH_SHORT_HAIR: 'CommonGameTag' = 2016 - FUR_MEDIUM_SMOOTH: 'CommonGameTag' = 57357 - FUR_MEDIUM_WIRY: 'CommonGameTag' = 57366 - FUR_POODLE: 'CommonGameTag' = 57358 - FUR_RETRIEVER: 'CommonGameTag' = 57359 - FUR_SPANIEL: 'CommonGameTag' = 57365 - GENDER_APPROPRIATE_FEMALE: 'CommonGameTag' = 1530 - GENDER_APPROPRIATE_MALE: 'CommonGameTag' = 1529 - GENRE_ACTIVITY_TABLE_DINO: 'CommonGameTag' = 877 - GENRE_ACTIVITY_TABLE_FAMILY: 'CommonGameTag' = 878 - GENRE_ACTIVITY_TABLE_HORSE: 'CommonGameTag' = 879 - GENRE_ACTIVITY_TABLE_SHAPES: 'CommonGameTag' = 880 - GENRE_ACTIVITY_TABLE_TRUCK: 'CommonGameTag' = 881 - GENRE_BOOK_BIOGRAPHY: 'CommonGameTag' = 768 - GENRE_BOOK_CHILDRENS: 'CommonGameTag' = 769 - GENRE_BOOK_EMOTIONAL: 'CommonGameTag' = 980 - GENRE_BOOK_EMOTION_CONFIDENT: 'CommonGameTag' = 790 - GENRE_BOOK_EMOTION_ENERGIZED: 'CommonGameTag' = 791 - GENRE_BOOK_EMOTION_FLIRTY: 'CommonGameTag' = 792 - GENRE_BOOK_EMOTION_FOCUSED: 'CommonGameTag' = 1038 - GENRE_BOOK_EMOTION_INSPIRED: 'CommonGameTag' = 1039 - GENRE_BOOK_EMOTION_PLAYFUL: 'CommonGameTag' = 793 - GENRE_BOOK_EMOTION_SAD: 'CommonGameTag' = 794 - GENRE_BOOK_FANTASY: 'CommonGameTag' = 770 - GENRE_BOOK_MAGIC: 'CommonGameTag' = 2224 - GENRE_BOOK_MYSTERY_THRILLER: 'CommonGameTag' = 866 - GENRE_BOOK_NON_FICTION: 'CommonGameTag' = 771 - GENRE_BOOK_POEMS: 'CommonGameTag' = 772 - GENRE_BOOK_ROMANCE: 'CommonGameTag' = 773 - GENRE_BOOK_SCI_FI: 'CommonGameTag' = 774 - GENRE_BOOK_SCREEN_PLAY: 'CommonGameTag' = 775 - GENRE_BOOK_SHORT_STORIES: 'CommonGameTag' = 776 - GENRE_BOOK_SKILL: 'CommonGameTag' = 1032 - GENRE_BOOK_SKILL_ACTING: 'CommonGameTag' = 61493 - GENRE_BOOK_SKILL_ARCHAEOLOGY: 'CommonGameTag' = 45069 - GENRE_BOOK_SKILL_BARTENDING: 'CommonGameTag' = 797 - GENRE_BOOK_SKILL_CHARISMA: 'CommonGameTag' = 798 - GENRE_BOOK_SKILL_COMEDY: 'CommonGameTag' = 799 - GENRE_BOOK_SKILL_COOKING: 'CommonGameTag' = 800 - GENRE_BOOK_SKILL_EQUESTRIAN_SKILL: 'CommonGameTag' = 2981 - GENRE_BOOK_SKILL_FABRICATION: 'CommonGameTag' = 67621 - GENRE_BOOK_SKILL_FISHING: 'CommonGameTag' = 921 - GENRE_BOOK_SKILL_FITNESS: 'CommonGameTag' = 810 - GENRE_BOOK_SKILL_GARDENING: 'CommonGameTag' = 801 - GENRE_BOOK_SKILL_GOURMET: 'CommonGameTag' = 802 - GENRE_BOOK_SKILL_GUITAR: 'CommonGameTag' = 803 - GENRE_BOOK_SKILL_HACKING: 'CommonGameTag' = 804 - GENRE_BOOK_SKILL_HANDINESS: 'CommonGameTag' = 805 - GENRE_BOOK_SKILL_HERBALISM: 'CommonGameTag' = 10256 - GENRE_BOOK_SKILL_KNITTING: 'CommonGameTag' = 2766 - GENRE_BOOK_SKILL_LOGIC: 'CommonGameTag' = 806 - GENRE_BOOK_SKILL_MISCHIEF: 'CommonGameTag' = 807 - GENRE_BOOK_SKILL_PAINTING: 'CommonGameTag' = 808 - GENRE_BOOK_SKILL_PARENTING: 'CommonGameTag' = 43012 - GENRE_BOOK_SKILL_PIANO: 'CommonGameTag' = 809 - GENRE_BOOK_SKILL_RESEARCH_DEBATE: 'CommonGameTag' = 2246 - GENRE_BOOK_SKILL_ROBOTICS: 'CommonGameTag' = 65623 - GENRE_BOOK_SKILL_ROCKET_SCIENCE: 'CommonGameTag' = 811 - GENRE_BOOK_SKILL_VIDEO_GAMING: 'CommonGameTag' = 812 - GENRE_BOOK_SKILL_VIOLIN: 'CommonGameTag' = 813 - GENRE_BOOK_SKILL_WELLNESS: 'CommonGameTag' = 18483 - GENRE_BOOK_SKILL_WOO_HOO: 'CommonGameTag' = 865 - GENRE_BOOK_SKILL_WRITING: 'CommonGameTag' = 818 - GENRE_BOOK_SUPERNATURAL: 'CommonGameTag' = 819 - GENRE_BOOK_TODDLER_PICTURE_BOOK: 'CommonGameTag' = 1656 - GENRE_BOOK_TRAVEL_GUIDE: 'CommonGameTag' = 45071 - GENRE_PAINTING_ABSTRACT: 'CommonGameTag' = 667 - GENRE_PAINTING_CLASSICS: 'CommonGameTag' = 669 - GENRE_PAINTING_IMPRESSIONISM: 'CommonGameTag' = 670 - GENRE_PAINTING_LANDSCAPE: 'CommonGameTag' = 10260 - GENRE_PAINTING_MATHEMATICS: 'CommonGameTag' = 671 - GENRE_PAINTING_POP_ART: 'CommonGameTag' = 672 - GENRE_PAINTING_REALISM: 'CommonGameTag' = 673 - GENRE_PAINTING_SURREALISM: 'CommonGameTag' = 674 - GP09: 'CommonGameTag' = 51270 - GROUP_PHOTO_X_ACTOR: 'CommonGameTag' = 1436 - GROUP_PHOTO_Y_ACTOR: 'CommonGameTag' = 1437 - GROUP_PHOTO_Z_ACTOR: 'CommonGameTag' = 2217 - GROWTH_LEVEL_HAIR_0: 'CommonGameTag' = 2810 - GROWTH_LEVEL_HAIR_1: 'CommonGameTag' = 2811 - GROWTH_LEVEL_HAIR_2: 'CommonGameTag' = 2812 - GROWTH_LEVEL_HAIR_3: 'CommonGameTag' = 2813 - GROWTH_TYPE_FACIAL_HAIR_BEARD: 'CommonGameTag' = 2817 - GROWTH_TYPE_FACIAL_HAIR_CHIN_STRAP: 'CommonGameTag' = 2818 - GROWTH_TYPE_FACIAL_HAIR_GOATEE: 'CommonGameTag' = 2820 - GROWTH_TYPE_FACIAL_HAIR_MUSTACHE: 'CommonGameTag' = 2819 - GROWTH_TYPE_FACIAL_HAIR_SOUL_PATCH: 'CommonGameTag' = 2821 - GROWTH_TYPE_HAIR_ARMS: 'CommonGameTag' = 2814 - GROWTH_TYPE_HAIR_LEGS: 'CommonGameTag' = 2815 - GROWTH_TYPE_HAIR_TORSO: 'CommonGameTag' = 2816 - GROWTH_TYPE_HAIR_TORSO_BACK: 'CommonGameTag' = 114735 - GROWTH_TYPE_HAIR_TORSO_BELLY: 'CommonGameTag' = 114734 - GROWTH_TYPE_HAIR_TORSO_CHEST: 'CommonGameTag' = 114733 - HAIR_COLOR_AUBURN: 'CommonGameTag' = 896 - HAIR_COLOR_BAY_ROAN: 'CommonGameTag' = 118833 - HAIR_COLOR_BLACK: 'CommonGameTag' = 131 - HAIR_COLOR_BLACK_SALT_AND_PEPPER: 'CommonGameTag' = 897 - HAIR_COLOR_BLONDE: 'CommonGameTag' = 94 - HAIR_COLOR_BROWN: 'CommonGameTag' = 132 - HAIR_COLOR_BROWN_DUN: 'CommonGameTag' = 118834 - HAIR_COLOR_BROWN_SALT_AND_PEPPER: 'CommonGameTag' = 898 - HAIR_COLOR_BUCK_SKIN: 'CommonGameTag' = 118835 - HAIR_COLOR_CHESTNUT: 'CommonGameTag' = 118836 - HAIR_COLOR_CREMELLO: 'CommonGameTag' = 118837 - HAIR_COLOR_DARK_BAY: 'CommonGameTag' = 118838 - HAIR_COLOR_DARK_BLUE: 'CommonGameTag' = 899 - HAIR_COLOR_DARK_BROWN: 'CommonGameTag' = 133 - HAIR_COLOR_DARK_GRAY: 'CommonGameTag' = 118839 - HAIR_COLOR_DARK_GRAY_COOL: 'CommonGameTag' = 118840 - HAIR_COLOR_DARK_GRAY_WARM: 'CommonGameTag' = 118841 - HAIR_COLOR_DIRTY_BLOND: 'CommonGameTag' = 900 - HAIR_COLOR_GOLD: 'CommonGameTag' = 118842 - HAIR_COLOR_GRAY: 'CommonGameTag' = 134 - HAIR_COLOR_GRAY_WARM: 'CommonGameTag' = 118843 - HAIR_COLOR_GREEN: 'CommonGameTag' = 901 - HAIR_COLOR_HOT_PINK: 'CommonGameTag' = 902 - HAIR_COLOR_LIGHT_BAY: 'CommonGameTag' = 118844 - HAIR_COLOR_LIGHT_BLONDE: 'CommonGameTag' = 2532 - HAIR_COLOR_LIGHT_BROWN: 'CommonGameTag' = 2530 - HAIR_COLOR_LIGHT_CHESTNUT: 'CommonGameTag' = 118845 - HAIR_COLOR_LIGHT_GRAY_COOL: 'CommonGameTag' = 118846 - HAIR_COLOR_LIGHT_GRAY_WARM: 'CommonGameTag' = 118847 - HAIR_COLOR_LIVER_CHESTNUT: 'CommonGameTag' = 118848 - HAIR_COLOR_MOUSE_DUN: 'CommonGameTag' = 118849 - HAIR_COLOR_NEUTRAL_BLACK: 'CommonGameTag' = 2528 - HAIR_COLOR_NEUTRAL_BLONDE: 'CommonGameTag' = 2531 - HAIR_COLOR_ORANGE: 'CommonGameTag' = 135 - HAIR_COLOR_PALOMINO: 'CommonGameTag' = 118850 - HAIR_COLOR_PASTEL_BLUE: 'CommonGameTag' = 118851 - HAIR_COLOR_PASTEL_GREEN: 'CommonGameTag' = 118852 - HAIR_COLOR_PASTEL_HOT_PINK: 'CommonGameTag' = 118853 - HAIR_COLOR_PASTEL_ORANGE: 'CommonGameTag' = 118854 - HAIR_COLOR_PASTEL_PINK: 'CommonGameTag' = 118855 - HAIR_COLOR_PASTEL_PURPLE: 'CommonGameTag' = 118856 - HAIR_COLOR_PASTEL_RED: 'CommonGameTag' = 118857 - HAIR_COLOR_PASTEL_TURQUOISE: 'CommonGameTag' = 118858 - HAIR_COLOR_PASTEL_YELLOW: 'CommonGameTag' = 118859 - HAIR_COLOR_PLATINUM: 'CommonGameTag' = 96 - HAIR_COLOR_PURPLE_PASTEL: 'CommonGameTag' = 903 - HAIR_COLOR_RED: 'CommonGameTag' = 136 - HAIR_COLOR_RED_DUN: 'CommonGameTag' = 118860 - HAIR_COLOR_RED_ROAN: 'CommonGameTag' = 118861 - HAIR_COLOR_ROSE_GRAY: 'CommonGameTag' = 118864 - HAIR_COLOR_SEAL_BROWN: 'CommonGameTag' = 118862 - HAIR_COLOR_TURQUOISE: 'CommonGameTag' = 904 - HAIR_COLOR_WARM_BROWN: 'CommonGameTag' = 2529 - HAIR_COLOR_WHITE: 'CommonGameTag' = 905 - HAIR_COLOR_WHITE_BLONDE: 'CommonGameTag' = 2533 - HAIR_COLOR_YELLOW_DUN: 'CommonGameTag' = 118863 - HAIR_CURLY: 'CommonGameTag' = 314 - HAIR_LENGTH_LONG: 'CommonGameTag' = 664 - HAIR_LENGTH_MEDIUM: 'CommonGameTag' = 820 - HAIR_LENGTH_SHORT: 'CommonGameTag' = 662 - HAIR_LENGTH_UPDO: 'CommonGameTag' = 2173 - HAIR_LONG: 'CommonGameTag' = 151 - HAIR_MEDIUM: 'CommonGameTag' = 150 - HAIR_SHORT: 'CommonGameTag' = 149 - HAIR_STRAIGHT: 'CommonGameTag' = 313 - HAIR_TEXTURE_BALD: 'CommonGameTag' = 12391 - HAIR_TEXTURE_CURLY: 'CommonGameTag' = 821 - HAIR_TEXTURE_STRAIGHT: 'CommonGameTag' = 822 - HAIR_TEXTURE_WAVY: 'CommonGameTag' = 663 - HAIR_WAVY: 'CommonGameTag' = 315 - HAT_BRIM: 'CommonGameTag' = 371 - HAT_BRIMLESS: 'CommonGameTag' = 372 - HAT_CAP: 'CommonGameTag' = 373 - HAT_PAPER_BAG: 'CommonGameTag' = 2428 - HOOF_COLOR_DARK: 'CommonGameTag' = 118900 - HOOF_COLOR_DARK_MIX: 'CommonGameTag' = 118901 - HOOF_COLOR_LIGHT: 'CommonGameTag' = 118902 - HOOF_COLOR_LIGHT_MIX: 'CommonGameTag' = 118903 - HOOF_COLOR_MIX: 'CommonGameTag' = 118904 - HORN_COLOR_BLACK: 'CommonGameTag' = 118887 - HORN_COLOR_BLACK_GOLD: 'CommonGameTag' = 118888 - HORN_COLOR_BLACK_SILVER: 'CommonGameTag' = 118889 - HORN_COLOR_GOLD: 'CommonGameTag' = 118890 - HORN_COLOR_HOT_PINK: 'CommonGameTag' = 118899 - HORN_COLOR_PASTEL: 'CommonGameTag' = 118891 - HORN_COLOR_PINK: 'CommonGameTag' = 118892 - HORN_COLOR_PINK_PURPLE: 'CommonGameTag' = 118893 - HORN_COLOR_RAINBOW: 'CommonGameTag' = 118894 - HORN_COLOR_SILVER: 'CommonGameTag' = 118895 - HORN_COLOR_WHITE: 'CommonGameTag' = 118896 - HORN_COLOR_WHITE_GOLD: 'CommonGameTag' = 118897 - HORN_COLOR_WHITE_SILVER: 'CommonGameTag' = 118898 - HOUSEHOLD_MEMBER_1: 'CommonGameTag' = 642 - HOUSEHOLD_MEMBER_2: 'CommonGameTag' = 643 - HOUSEHOLD_MEMBER_3: 'CommonGameTag' = 644 - HOUSEHOLD_MEMBER_4: 'CommonGameTag' = 645 - HOUSEHOLD_MEMBER_5: 'CommonGameTag' = 646 - HOUSEHOLD_MEMBER_6: 'CommonGameTag' = 647 - HOUSEHOLD_MEMBER_7: 'CommonGameTag' = 648 - HOUSEHOLD_MEMBER_8: 'CommonGameTag' = 649 - INSTRUMENT_VIOLIN: 'CommonGameTag' = 401 - INTERACTION_ADOPTION: 'CommonGameTag' = 57441 - INTERACTION_ADVENTUROUS_ONE_SHOT: 'CommonGameTag' = 69723 - INTERACTION_ALL: 'CommonGameTag' = 462 - INTERACTION_ANIMAL_OBJECTS_SOCIAL_ALL: 'CommonGameTag' = 2982 - INTERACTION_ARGUMENT: 'CommonGameTag' = 43015 - INTERACTION_ASK_TO_LEAVE_LOT: 'CommonGameTag' = 689 - INTERACTION_BAR_VENUE: 'CommonGameTag' = 1599 - INTERACTION_BASKETBALL_PLAY: 'CommonGameTag' = 2127 - INTERACTION_BATHTUB: 'CommonGameTag' = 2348 - INTERACTION_BATUU_IGNORE_REPUTATION: 'CommonGameTag' = 51246 - INTERACTION_BE_READ_TO: 'CommonGameTag' = 863 - INTERACTION_BONFIRE: 'CommonGameTag' = 24590 - INTERACTION_BROWSE_RESEARCH: 'CommonGameTag' = 757 - INTERACTION_BURNOUT_ALL_DECREASE_LARGE: 'CommonGameTag' = 2923 - INTERACTION_BURNOUT_ALL_DECREASE_SMALL: 'CommonGameTag' = 2922 - INTERACTION_BURNOUT_CREATIVE_INCREASE_LARGE: 'CommonGameTag' = 2919 - INTERACTION_BURNOUT_CREATIVE_INCREASE_SMALL: 'CommonGameTag' = 2918 - INTERACTION_BURNOUT_MENTAL_INCREASE_LARGE: 'CommonGameTag' = 2921 - INTERACTION_BURNOUT_MENTAL_INCREASE_SMALL: 'CommonGameTag' = 2920 - INTERACTION_CAMPFIRE: 'CommonGameTag' = 2775 - INTERACTION_CAREER_WORK_RABBIT_HOLE: 'CommonGameTag' = 2490 - INTERACTION_CAREGIVER_SITUATION_MOTIVE_SOLVED: 'CommonGameTag' = 2945 - INTERACTION_CHARITY: 'CommonGameTag' = 750 - INTERACTION_CHAT: 'CommonGameTag' = 342 - INTERACTION_CLEAN: 'CommonGameTag' = 781 - INTERACTION_CLIMBING_ROUTE: 'CommonGameTag' = 69691 - INTERACTION_COLLECT: 'CommonGameTag' = 1309 - INTERACTION_COMEDY_MIC: 'CommonGameTag' = 1613 - INTERACTION_COMPUTER: 'CommonGameTag' = 439 - INTERACTION_COMPUTER_TYPING: 'CommonGameTag' = 1367 - INTERACTION_CONSUME: 'CommonGameTag' = 394 - INTERACTION_COOK: 'CommonGameTag' = 358 - INTERACTION_COUNTRY_CARETAKER_GIVE_GIFT: 'CommonGameTag' = 112655 - INTERACTION_COUNTRY_CARETAKER_SOCIALIZE_WITH_CRITTERS: 'CommonGameTag' = 112656 - INTERACTION_COUNTRY_CARETAKER_TAKE_GIFT: 'CommonGameTag' = 112657 - INTERACTION_CREATIVE_CRAFT: 'CommonGameTag' = 2942 - INTERACTION_CURIO_SHOP_BROWSE_BUY: 'CommonGameTag' = 47134 - INTERACTION_DEATH: 'CommonGameTag' = 425 - INTERACTION_DOCTOR_TREAT_PATIENT: 'CommonGameTag' = 12337 - INTERACTION_DRINK: 'CommonGameTag' = 654 - INTERACTION_ECO_FOOTPRINT_GREEN: 'CommonGameTag' = 67603 - INTERACTION_EXAM_TABLE_EXAM: 'CommonGameTag' = 57391 - INTERACTION_EXTREME_SPORTS: 'CommonGameTag' = 69727 - INTERACTION_FASHION_BLOG: 'CommonGameTag' = 2131 - INTERACTION_FEAR_PLANT: 'CommonGameTag' = 2802 - INTERACTION_FESTIVE: 'CommonGameTag' = 2058 - INTERACTION_FOOSBALL_TABLE_PLAY: 'CommonGameTag' = 24581 - INTERACTION_FRIENDLY: 'CommonGameTag' = 431 - INTERACTION_FUNNY: 'CommonGameTag' = 432 - INTERACTION_GAME_CONSOLE: 'CommonGameTag' = 55384 - INTERACTION_GO_JOGGING: 'CommonGameTag' = 926 - INTERACTION_GREEN_UPGRADED: 'CommonGameTag' = 67589 - INTERACTION_GREETING: 'CommonGameTag' = 453 - INTERACTION_GROUP_DANCE_TOGETHER: 'CommonGameTag' = 24607 - INTERACTION_GROUP_WORKOUT: 'CommonGameTag' = 71683 - INTERACTION_HACK: 'CommonGameTag' = 435 - INTERACTION_HUG: 'CommonGameTag' = 1990 - INTERACTION_IGNORE_GROUNDING: 'CommonGameTag' = 43028 - INTERACTION_INFECT_HOUSE: 'CommonGameTag' = 47125 - INTERACTION_INSTRUMENT_LISTEN: 'CommonGameTag' = 639 - INTERACTION_INTELLIGENCE_RESEARCH: 'CommonGameTag' = 746 - INTERACTION_INVENTION_CONSTRUCTOR_UPGRADE: 'CommonGameTag' = 12368 - INTERACTION_INVITE_TO_STAY: 'CommonGameTag' = 417 - INTERACTION_JOKE: 'CommonGameTag' = 871 - INTERACTION_JUICE_KEG: 'CommonGameTag' = 2347 - INTERACTION_KARAOKE_VENUE: 'CommonGameTag' = 1600 - INTERACTION_KISS: 'CommonGameTag' = 350 - INTERACTION_KNITTING: 'CommonGameTag' = 2624 - INTERACTION_LAUNDRY_GENERATE_NO_PILE: 'CommonGameTag' = 2035 - INTERACTION_LAUNDRY_PUT_AWAY_FINISHED_LAUNDRY: 'CommonGameTag' = 2034 - INTERACTION_LEAVE: 'CommonGameTag' = 420 - INTERACTION_LEAVE_MUST_RUN: 'CommonGameTag' = 419 - INTERACTION_LIFESTYLES_ADRENALINE_SEEKER_DISCOURAGE_AUTONOMY: 'CommonGameTag' = 69730 - INTERACTION_LIFESTYLES_ADRENALINE_SEEKER_FLEXIBLE_LENGTH: 'CommonGameTag' = 69655 - INTERACTION_LIFESTYLES_ADRENALINE_SEEKER_MUNDANE: 'CommonGameTag' = 69712 - INTERACTION_LIFESTYLES_ADRENALINE_SEEKER_ONE_SHOT: 'CommonGameTag' = 69656 - INTERACTION_LIFESTYLES_ELECTRONICS: 'CommonGameTag' = 69651 - INTERACTION_LIFESTYLES_ELECTRONICS_REPAIR: 'CommonGameTag' = 69652 - INTERACTION_LIFESTYLES_ENERGETIC_AUTONOMY: 'CommonGameTag' = 69737 - INTERACTION_LIFESTYLES_ENERGETIC_FLEXIBLE_LENGTH: 'CommonGameTag' = 69634 - INTERACTION_LIFESTYLES_ENERGETIC_ONE_SHOT: 'CommonGameTag' = 69690 - INTERACTION_LIFESTYLES_FREQUENT_TRAVELER_FLEXIBLE_LENGTH: 'CommonGameTag' = 69636 - INTERACTION_LIFESTYLES_FREQUENT_TRAVELER_ONE_SHOT: 'CommonGameTag' = 69635 - INTERACTION_LIFESTYLES_INDOORSY_AUTONOMY: 'CommonGameTag' = 69731 - INTERACTION_LIFESTYLES_INDOORSY_FLEXIBLE_LENGTH: 'CommonGameTag' = 2749 - INTERACTION_LIFESTYLES_INDOORSY_ONE_SHOT: 'CommonGameTag' = 69658 - INTERACTION_LIFESTYLES_OUTDOORSY_AUTONOMY: 'CommonGameTag' = 69734 - INTERACTION_LIFESTYLES_OUTDOORSY_FLEXIBLE_LENGTH: 'CommonGameTag' = 2776 - INTERACTION_LIFESTYLES_OUTDOORSY_ONE_SHOT: 'CommonGameTag' = 2777 - INTERACTION_LIFESTYLES_ROMANTIC_MEDIA: 'CommonGameTag' = 69713 - INTERACTION_LIFESTYLES_SEDENTARY_AUTONOMY: 'CommonGameTag' = 69736 - INTERACTION_LIFESTYLES_SEDENTARY_FLEXIBLE_LENGTH: 'CommonGameTag' = 2759 - INTERACTION_LIFESTYLES_SEDENTARY_ONE_SHOT: 'CommonGameTag' = 69689 - INTERACTION_LIFESTYLES_TECHIE_AUTONOMY: 'CommonGameTag' = 69735 - INTERACTION_LIFESTYLES_TECHIE_FLEXIBLE_LENGTH: 'CommonGameTag' = 69638 - INTERACTION_LIFESTYLES_TECHIE_ONE_SHOT: 'CommonGameTag' = 69639 - INTERACTION_LIFESTYLES_TECHNOPHOBE_FLEXIBLE_LENGTH: 'CommonGameTag' = 69641 - INTERACTION_LIFESTYLES_TECHNOPHOBE_ONE_SHOT: 'CommonGameTag' = 69640 - INTERACTION_LIFESTYLES_TECHNOPHOBE_SABOTAGE: 'CommonGameTag' = 69704 - INTERACTION_LIFESTYLES_TECH_CAREER: 'CommonGameTag' = 69663 - INTERACTION_LISTEN_MUSIC: 'CommonGameTag' = 444 - INTERACTION_MAKE_APP: 'CommonGameTag' = 683 - INTERACTION_MAKE_COFFEE_OR_TEA: 'CommonGameTag' = 1028 - INTERACTION_MARKET_STALLS_TEND: 'CommonGameTag' = 1934 - INTERACTION_MARKET_STALL_TEND: 'CommonGameTag' = 55400 - INTERACTION_MASSAGE_TABLE: 'CommonGameTag' = 18439 - INTERACTION_MEAN: 'CommonGameTag' = 433 - INTERACTION_MENTOR: 'CommonGameTag' = 455 - INTERACTION_MENTOR_MUSIC: 'CommonGameTag' = 695 - INTERACTION_MENTOR_SKILL: 'CommonGameTag' = 2809 - INTERACTION_MISCHIEVOUS: 'CommonGameTag' = 434 - INTERACTION_MIXER: 'CommonGameTag' = 461 - INTERACTION_NAP: 'CommonGameTag' = 591 - INTERACTION_NESTING_BLOCKS: 'CommonGameTag' = 1698 - INTERACTION_NOISY_ELECTRONICS: 'CommonGameTag' = 1628 - INTERACTION_OBSERVATORY: 'CommonGameTag' = 1598 - INTERACTION_OLD_DAY_FINE: 'CommonGameTag' = 67638 - INTERACTION_PAINT: 'CommonGameTag' = 694 - INTERACTION_PAINT_BY_REFERENCE: 'CommonGameTag' = 1372 - INTERACTION_PAINT_MURAL: 'CommonGameTag' = 55359 - INTERACTION_PARK_VENUE: 'CommonGameTag' = 1601 - INTERACTION_PARTY: 'CommonGameTag' = 2061 - INTERACTION_PERFORM_COMEDY_ROUTINE: 'CommonGameTag' = 469 - INTERACTION_PETS_FRIENDLY: 'CommonGameTag' = 57370 - INTERACTION_PETS_GREETING: 'CommonGameTag' = 57372 - INTERACTION_PETS_MEAN: 'CommonGameTag' = 57371 - INTERACTION_PETS_SS3_ALLOWED: 'CommonGameTag' = 2015 - INTERACTION_PET_MISBEHAVIOR: 'CommonGameTag' = 57397 - INTERACTION_PHOTO_STUDIO_TAKE_PICTURE: 'CommonGameTag' = 1942 - INTERACTION_PLANT_SIM_PLANT_CARE: 'CommonGameTag' = 2774 - INTERACTION_PLANT_SIM_WATER: 'CommonGameTag' = 2773 - INTERACTION_PLAY_DJ_BOOTH: 'CommonGameTag' = 1618 - INTERACTION_PLAY_GAME: 'CommonGameTag' = 640 - INTERACTION_PLAY_GUITAR: 'CommonGameTag' = 1615 - INTERACTION_PLAY_GUITAR_FOR_TIPS: 'CommonGameTag' = 1024 - INTERACTION_PLAY_INSTRUMENT: 'CommonGameTag' = 442 - INTERACTION_PLAY_INSTRUMENT_FOR_TIPS: 'CommonGameTag' = 443 - INTERACTION_PLAY_INSTRUMENT_OR_COMEDY_FOR_TIPS: 'CommonGameTag' = 606 - INTERACTION_PLAY_PIANO: 'CommonGameTag' = 690 - INTERACTION_PLAY_PIANO_FOR_TIPS: 'CommonGameTag' = 1025 - INTERACTION_PLAY_TOY: 'CommonGameTag' = 1339 - INTERACTION_PLAY_VIDEO_GAMES: 'CommonGameTag' = 685 - INTERACTION_PLAY_VIOLIN: 'CommonGameTag' = 1616 - INTERACTION_PLAY_VIOLIN_FOR_TIPS: 'CommonGameTag' = 1026 - INTERACTION_PLAY_WITH_CAT: 'CommonGameTag' = 57362 - INTERACTION_PLAY_WITH_DOG: 'CommonGameTag' = 57363 - INTERACTION_PRACTICE_ACTING: 'CommonGameTag' = 61552 - INTERACTION_PRACTICE_CODING: 'CommonGameTag' = 693 - INTERACTION_PRACTICE_DEBATE: 'CommonGameTag' = 65648 - INTERACTION_PRACTICE_WRITING: 'CommonGameTag' = 692 - INTERACTION_PRANK: 'CommonGameTag' = 583 - INTERACTION_PRANK_OBJECT: 'CommonGameTag' = 752 - INTERACTION_PROGRAMMING: 'CommonGameTag' = 751 - INTERACTION_PUBLISH_BOOK: 'CommonGameTag' = 660 - INTERACTION_PUNCHING_BAG: 'CommonGameTag' = 2788 - INTERACTION_QUICK_SOCIAL: 'CommonGameTag' = 2832 - INTERACTION_READ_TO_CHILD: 'CommonGameTag' = 931 - INTERACTION_RELATIONSHIP_PANEL_INVITEO_VER: 'CommonGameTag' = 2834 - INTERACTION_REPAIR: 'CommonGameTag' = 464 - INTERACTION_RESTAURANT_WAIT_TO_PLACE_ORDER: 'CommonGameTag' = 2151 - INTERACTION_RETAIL: 'CommonGameTag' = 12347 - INTERACTION_RIVAL_REMINISCE: 'CommonGameTag' = 2795 - INTERACTION_ROCKET: 'CommonGameTag' = 465 - INTERACTION_ROCKETSHIP_BUILD: 'CommonGameTag' = 2941 - INTERACTION_ROCKET_SHIP_LAUNCH: 'CommonGameTag' = 438 - INTERACTION_ROCKET_SHIP_UPGRADE: 'CommonGameTag' = 437 - INTERACTION_RUN_AWAY: 'CommonGameTag' = 57443 - INTERACTION_SCHOOL_WORK: 'CommonGameTag' = 43026 - INTERACTION_SCIENCE_TABLE: 'CommonGameTag' = 786 - INTERACTION_SEASON_FALL: 'CommonGameTag' = 59420 - INTERACTION_SEASON_SPRING: 'CommonGameTag' = 59418 - INTERACTION_SEASON_SUMMER: 'CommonGameTag' = 59419 - INTERACTION_SEASON_WINTER: 'CommonGameTag' = 59421 - INTERACTION_SELL_ART: 'CommonGameTag' = 661 - INTERACTION_SHOWER: 'CommonGameTag' = 1447 - INTERACTION_SHOWOFF: 'CommonGameTag' = 427 - INTERACTION_SIM_TV: 'CommonGameTag' = 55362 - INTERACTION_SITUATION_PHOTOGRAPHY: 'CommonGameTag' = 79876 - INTERACTION_SKATING_ICE_SKATING: 'CommonGameTag' = 59395 - INTERACTION_SKATING_ROLLER_SKATING: 'CommonGameTag' = 59396 - INTERACTION_SKATING_ROUTINE: 'CommonGameTag' = 59397 - INTERACTION_SKATING_SKATING: 'CommonGameTag' = 59394 - INTERACTION_SKATING_TRICK: 'CommonGameTag' = 59401 - INTERACTION_SKETCH: 'CommonGameTag' = 2132 - INTERACTION_SKIING: 'CommonGameTag' = 69726 - INTERACTION_SKILL_ACTING: 'CommonGameTag' = 2340 - INTERACTION_SKILL_BAKING: 'CommonGameTag' = 2346 - INTERACTION_SKILL_BARTENDING: 'CommonGameTag' = 835 - INTERACTION_SKILL_CHARISMA: 'CommonGameTag' = 837 - INTERACTION_SKILL_CHILD_CREATIVITY: 'CommonGameTag' = 853 - INTERACTION_SKILL_CHILD_MENTAL: 'CommonGameTag' = 854 - INTERACTION_SKILL_CHILD_MOTOR: 'CommonGameTag' = 855 - INTERACTION_SKILL_CHILD_SOCIAL: 'CommonGameTag' = 856 - INTERACTION_SKILL_COMEDY: 'CommonGameTag' = 838 - INTERACTION_SKILL_DANCING: 'CommonGameTag' = 2343 - INTERACTION_SKILL_DJ_MIXING: 'CommonGameTag' = 2342 - INTERACTION_SKILL_DOG_TRAINING: 'CommonGameTag' = 57373 - INTERACTION_SKILL_EQUESTRIAN_SKILL: 'CommonGameTag' = 2980 - INTERACTION_SKILL_FABRICATION: 'CommonGameTag' = 2434 - INTERACTION_SKILL_FISHING: 'CommonGameTag' = 839 - INTERACTION_SKILL_FITNESS: 'CommonGameTag' = 836 - INTERACTION_SKILL_FLOWER_ARRANGEMENT: 'CommonGameTag' = 2344 - INTERACTION_SKILL_GARDENING: 'CommonGameTag' = 834 - INTERACTION_SKILL_GOURMET_COOKING: 'CommonGameTag' = 840 - INTERACTION_SKILL_GUITAR: 'CommonGameTag' = 841 - INTERACTION_SKILL_HANDINESS: 'CommonGameTag' = 842 - INTERACTION_SKILL_HERBALISM: 'CommonGameTag' = 2339 - INTERACTION_SKILL_HOME_STYLE_COOKING: 'CommonGameTag' = 843 - INTERACTION_SKILL_JUICE_FIZZING: 'CommonGameTag' = 2424 - INTERACTION_SKILL_KNITTING: 'CommonGameTag' = 2461 - INTERACTION_SKILL_LOGIC: 'CommonGameTag' = 844 - INTERACTION_SKILL_MEDIA_PRODUCTION: 'CommonGameTag' = 2338 - INTERACTION_SKILL_MISCHIEF: 'CommonGameTag' = 845 - INTERACTION_SKILL_PAINTING: 'CommonGameTag' = 846 - INTERACTION_SKILL_PHOTOGRAPHY: 'CommonGameTag' = 1938 - INTERACTION_SKILL_PIANO: 'CommonGameTag' = 847 - INTERACTION_SKILL_PIPE_ORGAN: 'CommonGameTag' = 2341 - INTERACTION_SKILL_PROGRAMMING: 'CommonGameTag' = 848 - INTERACTION_SKILL_RANCH_NECTAR: 'CommonGameTag' = 118865 - INTERACTION_SKILL_ROBOTICS: 'CommonGameTag' = 2345 - INTERACTION_SKILL_ROCKET_SCIENCE: 'CommonGameTag' = 849 - INTERACTION_SKILL_SINGING: 'CommonGameTag' = 55364 - INTERACTION_SKILL_SINGING_KARAOKE: 'CommonGameTag' = 1617 - INTERACTION_SKILL_VIDEO_GAMING: 'CommonGameTag' = 850 - INTERACTION_SKILL_VIOLIN: 'CommonGameTag' = 851 - INTERACTION_SKILL_WELLNESS: 'CommonGameTag' = 18465 - INTERACTION_SKILL_WELLNESS_BG: 'CommonGameTag' = 2337 - INTERACTION_SKILL_WRITING: 'CommonGameTag' = 852 - INTERACTION_SKY_GAZE: 'CommonGameTag' = 2944 - INTERACTION_SLEDDING: 'CommonGameTag' = 69725 - INTERACTION_SLEEP: 'CommonGameTag' = 451 - INTERACTION_SLEEP_GROUP: 'CommonGameTag' = 2094 - INTERACTION_SLEEP_NAP: 'CommonGameTag' = 59477 - INTERACTION_SNIFF_NEW_OBJECTS: 'CommonGameTag' = 2093 - INTERACTION_SNOWBOARDING: 'CommonGameTag' = 69724 - INTERACTION_SOCIAL_ALL: 'CommonGameTag' = 2161 - INTERACTION_SOCIAL_CONTAGIOUS: 'CommonGameTag' = 2041 - INTERACTION_SOCIAL_FIGHT: 'CommonGameTag' = 2801 - INTERACTION_SOCIAL_HORSE_TO_SIM: 'CommonGameTag' = 118905 - INTERACTION_SOCIAL_MEDIA_CHECK_IN: 'CommonGameTag' = 1619 - INTERACTION_SOCIAL_MEDIA_PERSUADE_TO: 'CommonGameTag' = 55319 - INTERACTION_SOCIAL_MIXER: 'CommonGameTag' = 2162 - INTERACTION_SOCIAL_NETWORK: 'CommonGameTag' = 1595 - INTERACTION_SOCIAL_SUPER: 'CommonGameTag' = 454 - INTERACTION_SOCIAL_TOUCHING: 'CommonGameTag' = 2163 - INTERACTION_SPRAY_GRAFFITI: 'CommonGameTag' = 55361 - INTERACTION_STEREO_DANCE: 'CommonGameTag' = 876 - INTERACTION_STEREO_LISTEN: 'CommonGameTag' = 638 - INTERACTION_STUFFED_ANIMAL_BABBLE: 'CommonGameTag' = 1723 - INTERACTION_SUPER: 'CommonGameTag' = 460 - INTERACTION_SURGERY_STATION_EXAM: 'CommonGameTag' = 57392 - INTERACTION_SWIM: 'CommonGameTag' = 1591 - INTERACTION_TAKE_PHOTO: 'CommonGameTag' = 1939 - INTERACTION_TAKE_PIZZA: 'CommonGameTag' = 1640 - INTERACTION_TALK_LIKE_A_PIRATE_DAY: 'CommonGameTag' = 2480 - INTERACTION_TEEN_CAREER_RABBIT_HOLE: 'CommonGameTag' = 1719 - INTERACTION_TELESCOPE: 'CommonGameTag' = 436 - INTERACTION_TELL_STORY: 'CommonGameTag' = 466 - INTERACTION_TENT_SLEEP: 'CommonGameTag' = 2477 - INTERACTION_THROWING: 'CommonGameTag' = 2488 - INTERACTION_THROWING_MUD: 'CommonGameTag' = 59425 - INTERACTION_THROWING_SNOWBALL: 'CommonGameTag' = 2489 - INTERACTION_THROWING_WATER_BALLOON: 'CommonGameTag' = 59426 - INTERACTION_TODDLER_EAT_ACTIVE: 'CommonGameTag' = 2934 - INTERACTION_TOURNAMENT: 'CommonGameTag' = 749 - INTERACTION_TRANSFER_FIRELEAF_RASH: 'CommonGameTag' = 2479 - INTERACTION_TREADMILL: 'CommonGameTag' = 353 - INTERACTION_TRY_FOR_BABY: 'CommonGameTag' = 452 - INTERACTION_UNIVERSITY_STUDY_WITH: 'CommonGameTag' = 65609 - INTERACTION_UPGRADE: 'CommonGameTag' = 658 - INTERACTION_UPGRADE_CLEAN_BREAK: 'CommonGameTag' = 2517 - INTERACTION_USE_TOILET: 'CommonGameTag' = 396 - INTERACTION_VACUUM: 'CommonGameTag' = 94225 - INTERACTION_VIDEO_GAME_LIVESTREAM: 'CommonGameTag' = 1641 - INTERACTION_VIDEO_GAME_MONEY: 'CommonGameTag' = 655 - INTERACTION_VIDEO_GAME_STREAM_LETS_PLAY: 'CommonGameTag' = 1642 - INTERACTION_VIEW_ART: 'CommonGameTag' = 758 - INTERACTION_VISIT_LOT: 'CommonGameTag' = 449 - INTERACTION_VOODOO: 'CommonGameTag' = 426 - INTERACTION_WAITSTAFF_IDLE: 'CommonGameTag' = 26634 - INTERACTION_WAIT_IN_LINE: 'CommonGameTag' = 2497 - INTERACTION_WATCH_PERFORMER: 'CommonGameTag' = 1597 - INTERACTION_WATCH_TV: 'CommonGameTag' = 450 - INTERACTION_WATCH_TV_COOKING: 'CommonGameTag' = 55320 - INTERACTION_WATCH_TV_ROM_COM_ACT: 'CommonGameTag' = 55321 - INTERACTION_WEATHER_RAIN: 'CommonGameTag' = 59423 - INTERACTION_WEATHER_SNOW: 'CommonGameTag' = 59422 - INTERACTION_WELLNESS_GUIDE: 'CommonGameTag' = 18477 - INTERACTION_WELLNESS_HUSTLE: 'CommonGameTag' = 18479 - INTERACTION_WELLNESS_MINDFULNESS: 'CommonGameTag' = 18474 - INTERACTION_WELLNESS_PEACEFUL: 'CommonGameTag' = 18476 - INTERACTION_WELLNESS_REGULAR: 'CommonGameTag' = 18478 - INTERACTION_WELLNESS_RELAXATION: 'CommonGameTag' = 18475 - INTERACTION_WOODWORKING: 'CommonGameTag' = 1612 - INTERACTION_WORKOUT: 'CommonGameTag' = 463 - INTERACTION_WORKOUT_MACHINE: 'CommonGameTag' = 354 - INTERACTION_WORKOUT_PUSH_THE_LIMITS: 'CommonGameTag' = 1171 - INTERACTION_WRITE: 'CommonGameTag' = 55360 - INTERACTION_WRITE_ARTICLE: 'CommonGameTag' = 665 - INTERACTION_WRITE_JOKES: 'CommonGameTag' = 696 - INTERACTION_YOGA_CLASS_MEMBER: 'CommonGameTag' = 18461 - INVALID: 'CommonGameTag' = 0 - INVENTORY_ANIMAL_CARE_ANIMALS: 'CommonGameTag' = 2984 - INVENTORY_ANIMAL_CARE_CARE: 'CommonGameTag' = 2985 - INVENTORY_BOOKS_FUN: 'CommonGameTag' = 2350 - INVENTORY_BOOKS_OTHER: 'CommonGameTag' = 2352 - INVENTORY_BOOKS_SKILL: 'CommonGameTag' = 2351 - INVENTORY_COLLECTIBLE_CREATURE: 'CommonGameTag' = 2353 - INVENTORY_COLLECTIBLE_DECORATION: 'CommonGameTag' = 2354 - INVENTORY_COLLECTIBLE_NATURAL: 'CommonGameTag' = 2355 - INVENTORY_COLLECTIBLE_OTHER: 'CommonGameTag' = 2356 - INVENTORY_CONSUMABLE_DRINK: 'CommonGameTag' = 2358 - INVENTORY_CONSUMABLE_FOOD: 'CommonGameTag' = 2357 - INVENTORY_CONSUMABLE_OTHER: 'CommonGameTag' = 2359 - INVENTORY_FASHION_ALL: 'CommonGameTag' = 114707 - INVENTORY_FASHION_LISTED: 'CommonGameTag' = 114704 - INVENTORY_FASHION_PENDING_SALE: 'CommonGameTag' = 114705 - INVENTORY_FASHION_UNAVAILABLE: 'CommonGameTag' = 114706 - INVENTORY_GARDENING_OTHER: 'CommonGameTag' = 2360 - INVENTORY_HOME_SKILL_DECORATION: 'CommonGameTag' = 2362 - INVENTORY_HOME_SKILL_HOME: 'CommonGameTag' = 2363 - INVENTORY_HOME_SKILL_LITTLE_ONES: 'CommonGameTag' = 2364 - INVENTORY_HOME_SKILL_SKILL: 'CommonGameTag' = 2361 - INVENTORY_PLOPSY_ALL: 'CommonGameTag' = 2459 - INVENTORY_PLOPSY_LISTED: 'CommonGameTag' = 2457 - INVENTORY_PLOPSY_PENDING_SALE: 'CommonGameTag' = 2458 - INVENTORY_PLOPSY_UNAVAILABLE: 'CommonGameTag' = 83989 - INVENTORY_SCRAPS_JUNK: 'CommonGameTag' = 2371 - INVENTORY_SCRAPS_PARTS: 'CommonGameTag' = 2370 - INVENTORY_SIM_CRAFTED_ARTWORK: 'CommonGameTag' = 2368 - INVENTORY_SIM_CRAFTED_OTHER: 'CommonGameTag' = 2369 - INVENTORY_SPECIAL_CAREER_ACTIVITY: 'CommonGameTag' = 2365 - INVENTORY_SPECIAL_EDUCATION: 'CommonGameTag' = 2366 - INVENTORY_SPECIAL_STORY: 'CommonGameTag' = 2367 - JOB_BATUU_NPC: 'CommonGameTag' = 2512 - JOB_RESTAURANT_DINER: 'CommonGameTag' = 2145 - JOB_VENUE: 'CommonGameTag' = 1464 - JOB_VET_PATIENT: 'CommonGameTag' = 57442 - JOB_WALKBY: 'CommonGameTag' = 1463 - LESSON_ASPIRATIONS_WANTS: 'CommonGameTag' = 2869 - LESSON_BEGINNER: 'CommonGameTag' = 2848 - LESSON_BEGINNER_BUILD_MODE: 'CommonGameTag' = 2857 - LESSON_BEGINNER_CAS: 'CommonGameTag' = 2855 - LESSON_BEGINNER_CONTROLS: 'CommonGameTag' = 2858 - LESSON_BEGINNER_LIVE_MODE: 'CommonGameTag' = 2856 - LESSON_BUILDING: 'CommonGameTag' = 2875 - LESSON_BUILD_MODE: 'CommonGameTag' = 2852 - LESSON_CAS: 'CommonGameTag' = 2849 - LESSON_CHILD_ACCOUNT_ONLY: 'CommonGameTag' = 2906 - LESSON_CHILD_ACCOUNT_RESTRICTED: 'CommonGameTag' = 2907 - LESSON_CONSOLE_ONLY: 'CommonGameTag' = 2902 - LESSON_DEBUG_CATEGORY: 'CommonGameTag' = 2845 - LESSON_DEBUG_SUBCATEGORY: 'CommonGameTag' = 2846 - LESSON_DESK_TOP_ONLY: 'CommonGameTag' = 2901 - LESSON_EMOTIONS: 'CommonGameTag' = 2867 - LESSON_EP01_GET_TO_WORK: 'CommonGameTag' = 2883 - LESSON_EP02_GET_TOGETHER: 'CommonGameTag' = 2880 - LESSON_EP03_CITY_LIVING: 'CommonGameTag' = 2884 - LESSON_EP04_CAP: 'CommonGameTag' = 2881 - LESSON_EP04_CATS_AND_DOGS: 'CommonGameTag' = 2885 - LESSON_EP05_SEASONS: 'CommonGameTag' = 2882 - LESSON_EP06_GET_FAMOUS: 'CommonGameTag' = 2886 - LESSON_EP07_ISLAND_LIVING: 'CommonGameTag' = 2887 - LESSON_EP08_DISCOVER_UNIVERSITY: 'CommonGameTag' = 2888 - LESSON_EP09_ECO_LIFESTYLE: 'CommonGameTag' = 2889 - LESSON_EP10_SNOWY_ESCAPE: 'CommonGameTag' = 2890 - LESSON_EP11_COTTAGE_LIVING: 'CommonGameTag' = 2891 - LESSON_EP12_HIGH_SCHOOL_YEARS: 'CommonGameTag' = 2892 - LESSON_EP13_GROWING_TOGETHER: 'CommonGameTag' = 2955 - LESSON_FACEBODY: 'CommonGameTag' = 2860 - LESSON_FAMILY: 'CommonGameTag' = 2873 - LESSON_FILTER_SEARCH_BUILD_MODE: 'CommonGameTag' = 2879 - LESSON_GALLERY: 'CommonGameTag' = 2854 - LESSON_GP01_OUTDOOR_RETREAT: 'CommonGameTag' = 2900 - LESSON_GP02_SPA_DAY: 'CommonGameTag' = 2893 - LESSON_GP03_DINE_OUT: 'CommonGameTag' = 2894 - LESSON_GP05_PARENTHOOD: 'CommonGameTag' = 2895 - LESSON_GP06_JUNGLE_ADVENTURE: 'CommonGameTag' = 2896 - LESSON_GP10_DREAM_HOME_DECORATOR: 'CommonGameTag' = 2897 - LESSON_GP11_MY_WEDDING_STORIES: 'CommonGameTag' = 2898 - LESSON_GP12_WEREWOLVES: 'CommonGameTag' = 2899 - LESSON_IDENTITY_PERSONALITY: 'CommonGameTag' = 2859 - LESSON_INVENTORY_COLLECTIBLES: 'CommonGameTag' = 2903 - LESSON_LANDSCAPING: 'CommonGameTag' = 2877 - LESSON_LIFE_DEATH: 'CommonGameTag' = 2865 - LESSON_LIVE_MODE: 'CommonGameTag' = 2851 - LESSON_LOT_SETTINGS: 'CommonGameTag' = 2878 - LESSON_MONEY_WORK: 'CommonGameTag' = 2870 - LESSON_NEEDS: 'CommonGameTag' = 2866 - LESSON_NEIGHBOHOOD_STORIES: 'CommonGameTag' = 2863 - LESSON_NEIGHBORS_HOUSEHOLDS: 'CommonGameTag' = 2862 - LESSON_OBJECTS: 'CommonGameTag' = 2876 - LESSON_OUTFITS: 'CommonGameTag' = 2861 - LESSON_PERSONALITY: 'CommonGameTag' = 2868 - LESSON_PRONOUNS: 'CommonGameTag' = 2905 - LESSON_RELATIONSHIPS: 'CommonGameTag' = 2872 - LESSON_SCENARIOS: 'CommonGameTag' = 2853 - LESSON_SKILLS: 'CommonGameTag' = 2871 - LESSON_TIME: 'CommonGameTag' = 2864 - LESSON_TOOLBAR: 'CommonGameTag' = 2904 - LESSON_TRAVEL_MOVING: 'CommonGameTag' = 2874 - LESSON_UNCATEGORIZED: 'CommonGameTag' = 2847 - LESSON_WORLD_MAP: 'CommonGameTag' = 2850 - LIFESTYLES_DANGEROUS_CAREER: 'CommonGameTag' = 69711 - LIFESTYLES_HIGH_ENERGY_CAREER: 'CommonGameTag' = 69683 - LIFESTYLES_INDOORSY_CAREER: 'CommonGameTag' = 69733 - LIFESTYLES_LOW_ENERGY_CAREER: 'CommonGameTag' = 69684 - LIFESTYLES_OUTDOORSY_CAREER: 'CommonGameTag' = 69721 - MAILBOX: 'CommonGameTag' = 346 - MAIN_PET_SOCIAL: 'CommonGameTag' = 57349 - MENTOR_ACTIVITY_TABLE: 'CommonGameTag' = 588 - MENTOR_EASEL: 'CommonGameTag' = 365 - MENTOR_FITNESS: 'CommonGameTag' = 357 - MENTOR_GUITAR: 'CommonGameTag' = 361 - MENTOR_MURAL: 'CommonGameTag' = 55398 - MENTOR_PIANO: 'CommonGameTag' = 362 - MENTOR_REPAIR: 'CommonGameTag' = 765 - MENTOR_TREADMILL: 'CommonGameTag' = 355 - MENTOR_UPGRADE: 'CommonGameTag' = 766 - MENTOR_VIOLIN: 'CommonGameTag' = 363 - MENTOR_WOODWORKING_TABLE: 'CommonGameTag' = 764 - MENTOR_WORKOUT_MACHINE: 'CommonGameTag' = 356 - MICROSCOPE_SLIDE_CRYSTAL: 'CommonGameTag' = 344 - MICROSCOPE_SLIDE_FOSSIL: 'CommonGameTag' = 343 - MICROSCOPE_SLIDE_PLANT: 'CommonGameTag' = 345 - MOOD_ANGRY: 'CommonGameTag' = 317 - MOOD_BORED: 'CommonGameTag' = 318 - MOOD_CONFIDENT: 'CommonGameTag' = 319 - MOOD_CRANKY: 'CommonGameTag' = 320 - MOOD_DEPRESSED: 'CommonGameTag' = 321 - MOOD_DRUNK: 'CommonGameTag' = 322 - MOOD_EMBARRASSED: 'CommonGameTag' = 323 - MOOD_ENERGIZED: 'CommonGameTag' = 324 - MOOD_FINE: 'CommonGameTag' = 331 - MOOD_FLIRTY: 'CommonGameTag' = 325 - MOOD_FOCUSED: 'CommonGameTag' = 326 - MOOD_HAPPY: 'CommonGameTag' = 328 - MOOD_IMAGINATIVE: 'CommonGameTag' = 329 - MOOD_OPTIMISM: 'CommonGameTag' = 64 - MOOD_PLAYFUL: 'CommonGameTag' = 332 - MOOD_SAD: 'CommonGameTag' = 333 - MOOD_SLOSHED: 'CommonGameTag' = 334 - MOOD_TENSE: 'CommonGameTag' = 327 - MOOD_UNCOMFORTABLE: 'CommonGameTag' = 330 - NONE_EP03_PLEASE_REUSE_ME: 'CommonGameTag' = 24592 - NOSE_COLOR_BLACK: 'CommonGameTag' = 1917 - NOSE_COLOR_BLACK_PINK: 'CommonGameTag' = 1922 - NOSE_COLOR_BROWN: 'CommonGameTag' = 1918 - NOSE_COLOR_BROWN_PINK: 'CommonGameTag' = 1923 - NOSE_COLOR_LIVER: 'CommonGameTag' = 1919 - NOSE_COLOR_PINK: 'CommonGameTag' = 1920 - NOSE_COLOR_TAN: 'CommonGameTag' = 1921 - NUDE_PART_ALWAYS: 'CommonGameTag' = 1540 - NUDE_PART_MALE_WITH_BREAST: 'CommonGameTag' = 1541 - OBJECT_BAR: 'CommonGameTag' = 349 - OBJECT_MURAL: 'CommonGameTag' = 55363 - OCCULT_ALIEN: 'CommonGameTag' = 12319 - OCCULT_HUMAN: 'CommonGameTag' = 1310 - OCCULT_MERMAID: 'CommonGameTag' = 2208 - OCCULT_VAMPIRE: 'CommonGameTag' = 1677 - OCCULT_WEREWOLF: 'CommonGameTag' = 2779 - OCCULT_WITCH: 'CommonGameTag' = 2279 - OUTFIT_ARTS_CRITIC: 'CommonGameTag' = 55301 - OUTFIT_ART_CRITIC_LEVEL10: 'CommonGameTag' = 55393 - OUTFIT_CATEGORY_ATHLETIC: 'CommonGameTag' = 80 - OUTFIT_CATEGORY_BATHING: 'CommonGameTag' = 82 - OUTFIT_CATEGORY_BATUU: 'CommonGameTag' = 2470 - OUTFIT_CATEGORY_CAREER: 'CommonGameTag' = 263 - OUTFIT_CATEGORY_COLD_WEATHER: 'CommonGameTag' = 2054 - OUTFIT_CATEGORY_EVERYDAY: 'CommonGameTag' = 77 - OUTFIT_CATEGORY_FORMAL: 'CommonGameTag' = 78 - OUTFIT_CATEGORY_HOT_WEATHER: 'CommonGameTag' = 2053 - OUTFIT_CATEGORY_PARTY: 'CommonGameTag' = 83 - OUTFIT_CATEGORY_RETAIL_UNIFORMS: 'CommonGameTag' = 1371 - OUTFIT_CATEGORY_SITUATION: 'CommonGameTag' = 335 - OUTFIT_CATEGORY_SLEEP: 'CommonGameTag' = 81 - OUTFIT_CATEGORY_SWIMWEAR: 'CommonGameTag' = 1229 - OUTFIT_CATEGORY_UNUSED: 'CommonGameTag' = 79 - OUTFIT_CATEGORY_WITCH: 'CommonGameTag' = 8210 - OUTFIT_FOOD_CRITIC: 'CommonGameTag' = 55300 - OUTFIT_FOOD_CRITIC_LEVEL10: 'CommonGameTag' = 55394 - PATTERN_ANIMAL: 'CommonGameTag' = 590 - PATTERN_BICOLOR: 'CommonGameTag' = 1905 - PATTERN_BRINDLE: 'CommonGameTag' = 1902 - PATTERN_CALICO: 'CommonGameTag' = 1912 - PATTERN_HARLEQUIN: 'CommonGameTag' = 1909 - PATTERN_MERLE: 'CommonGameTag' = 1907 - PATTERN_SABLE: 'CommonGameTag' = 1910 - PATTERN_SADDLE: 'CommonGameTag' = 1903 - PATTERN_SPECKLED: 'CommonGameTag' = 1913 - PATTERN_SPOTTED: 'CommonGameTag' = 1900 - PATTERN_STRIPED: 'CommonGameTag' = 1901 - PATTERN_SWIRLED: 'CommonGameTag' = 1904 - PATTERN_TABBY: 'CommonGameTag' = 1899 - PATTERN_TRICOLOR: 'CommonGameTag' = 1906 - PATTERN_TUXEDO: 'CommonGameTag' = 1908 - PERSONA_BOHO: 'CommonGameTag' = 130 - PERSONA_FASHIONISTA: 'CommonGameTag' = 129 - PERSONA_MOM: 'CommonGameTag' = 148 - PERSONA_ROCKER: 'CommonGameTag' = 128 - PORTAL_DISALLOWANCE_MASCOT: 'CommonGameTag' = 69745 - PORTAL_DISALLOWANCE_UNGREETED: 'CommonGameTag' = 668 - POSTURE_LIFESTYLES_RELAXED_SIT: 'CommonGameTag' = 69695 - RECIPE_BANQUET_TABLE_OPTION: 'CommonGameTag' = 2753 - RECIPE_CANDLE_MAKING_STATION_CANDLE: 'CommonGameTag' = 67604 - RECIPE_CATEGORY_CAKE_PIE: 'CommonGameTag' = 1536 - RECIPE_CATEGORY_CHOCOLATE: 'CommonGameTag' = 1537 - RECIPE_CATEGORY_COLD: 'CommonGameTag' = 1533 - RECIPE_CATEGORY_DRINKS: 'CommonGameTag' = 1518 - RECIPE_CATEGORY_EGGS: 'CommonGameTag' = 112677 - RECIPE_CATEGORY_FIZZY: 'CommonGameTag' = 1531 - RECIPE_CATEGORY_FRUIT: 'CommonGameTag' = 1532 - RECIPE_CATEGORY_GRAINS: 'CommonGameTag' = 1515 - RECIPE_CATEGORY_HOT: 'CommonGameTag' = 1534 - RECIPE_CATEGORY_MEAT: 'CommonGameTag' = 1513 - RECIPE_CATEGORY_MILK: 'CommonGameTag' = 112678 - RECIPE_CATEGORY_MISC: 'CommonGameTag' = 1517 - RECIPE_CATEGORY_NECTAR: 'CommonGameTag' = 1535 - RECIPE_CATEGORY_SEAFOOD: 'CommonGameTag' = 1519 - RECIPE_CATEGORY_SWEETS: 'CommonGameTag' = 1516 - RECIPE_CATEGORY_VEGETARIAN: 'CommonGameTag' = 1514 - RECIPE_CATEGORY_VILLAGE_FAIR_NPC_EGG: 'CommonGameTag' = 112690 - RECIPE_CATEGORY_VILLAGE_FAIR_NPC_MILK: 'CommonGameTag' = 112692 - RECIPE_CATEGORY_VILLAGE_FAIR_NPC_WOOL: 'CommonGameTag' = 112691 - RECIPE_CATEGORY_WATER: 'CommonGameTag' = 1522 - RECIPE_CATEGORY_WHOLE_PIE: 'CommonGameTag' = 2647 - RECIPE_CAULDRON_POTION: 'CommonGameTag' = 49154 - RECIPE_CHEFS_CHOICE_CHILD_FRIENDLY: 'CommonGameTag' = 1521 - RECIPE_CHILD_RESTRICTED: 'CommonGameTag' = 1523 - RECIPE_COURSE_APPETIZER: 'CommonGameTag' = 1507 - RECIPE_COURSE_DESSERT: 'CommonGameTag' = 1509 - RECIPE_COURSE_DRINK: 'CommonGameTag' = 1524 - RECIPE_COURSE_MAIN: 'CommonGameTag' = 1508 - RECIPE_FASHION_TRENDI_BROWSER: 'CommonGameTag' = 114703 - RECIPE_FLOWER_ARRANGEMENT: 'CommonGameTag' = 59472 - RECIPE_GROUP_COOKING_USES_CUTTING_BOARD: 'CommonGameTag' = 2669 - RECIPE_GROUP_COOKING_USES_CUTTING_BOARD_APPLE: 'CommonGameTag' = 2677 - RECIPE_GROUP_COOKING_USES_CUTTING_BOARD_ASPARAGUS: 'CommonGameTag' = 2678 - RECIPE_GROUP_COOKING_USES_CUTTING_BOARD_BEANS: 'CommonGameTag' = 2671 - RECIPE_GROUP_COOKING_USES_CUTTING_BOARD_BELLPEPPER: 'CommonGameTag' = 2679 - RECIPE_GROUP_COOKING_USES_CUTTING_BOARD_BREAD: 'CommonGameTag' = 2680 - RECIPE_GROUP_COOKING_USES_CUTTING_BOARD_CHICKEN: 'CommonGameTag' = 2672 - RECIPE_GROUP_COOKING_USES_CUTTING_BOARD_DOUGH: 'CommonGameTag' = 2673 - RECIPE_GROUP_COOKING_USES_CUTTING_BOARD_FISH: 'CommonGameTag' = 2674 - RECIPE_GROUP_COOKING_USES_CUTTING_BOARD_FISH_WHITE: 'CommonGameTag' = 2675 - RECIPE_GROUP_COOKING_USES_CUTTING_BOARD_LETTUCE: 'CommonGameTag' = 2681 - RECIPE_GROUP_COOKING_USES_CUTTING_BOARD_MEATRED: 'CommonGameTag' = 2676 - RECIPE_GROUP_COOKING_USES_CUTTING_BOARD_MELON: 'CommonGameTag' = 2682 - RECIPE_GROUP_COOKING_USES_CUTTING_BOARD_ONION: 'CommonGameTag' = 2683 - RECIPE_GROUP_COOKING_USES_CUTTING_BOARD_POTATO: 'CommonGameTag' = 2686 - RECIPE_GROUP_COOKING_USES_CUTTING_BOARD_SHRIMP: 'CommonGameTag' = 2684 - RECIPE_GROUP_COOKING_USES_CUTTING_BOARD_TOMATO: 'CommonGameTag' = 2685 - RECIPE_GROUP_COOKING_USES_MIXING_BOWL: 'CommonGameTag' = 2670 - RECIPE_GROUP_COOKING_USES_MIXING_BOWL_CASSOROLE_WHITE: 'CommonGameTag' = 2687 - RECIPE_GROUP_COOKING_USES_MIXING_BOWL_CHOCOLATE: 'CommonGameTag' = 2688 - RECIPE_GROUP_COOKING_USES_MIXING_BOWL_DOUGH: 'CommonGameTag' = 2690 - RECIPE_GROUP_COOKING_USES_MIXING_BOWL_EGGS: 'CommonGameTag' = 2695 - RECIPE_GROUP_COOKING_USES_MIXING_BOWL_MEAT: 'CommonGameTag' = 2694 - RECIPE_GROUP_COOKING_USES_MIXING_BOWL_PASTA: 'CommonGameTag' = 2693 - RECIPE_GROUP_COOKING_USES_MIXING_BOWL_SALAD: 'CommonGameTag' = 2689 - RECIPE_GROUP_COOKING_USES_MIXING_BOWL_SALAD_FRUIT: 'CommonGameTag' = 2692 - RECIPE_GROUP_COOKING_USES_MIXING_BOWL_SPICE: 'CommonGameTag' = 2691 - RECIPE_GROUP_COOKING_USES_MIXING_BOWL_WHITE_SAUCE: 'CommonGameTag' = 2696 - RECIPE_MEAL_BREAKFAST: 'CommonGameTag' = 1510 - RECIPE_MEAL_DINNER: 'CommonGameTag' = 1512 - RECIPE_MEAL_LUNCH: 'CommonGameTag' = 1511 - RECIPE_PLOPSY_BROWSER: 'CommonGameTag' = 83985 - RECIPE_TYPE_BAKING_SKILL: 'CommonGameTag' = 2621 - RECIPE_TYPE_COOKING_SKILL: 'CommonGameTag' = 2623 - RECIPE_TYPE_CROSS_STITCH_ANIMALS: 'CommonGameTag' = 112651 - RECIPE_TYPE_CROSS_STITCH_FOODS: 'CommonGameTag' = 112652 - RECIPE_TYPE_CROSS_STITCH_NATURE: 'CommonGameTag' = 112653 - RECIPE_TYPE_DRINK: 'CommonGameTag' = 1506 - RECIPE_TYPE_DRINK_PRANK: 'CommonGameTag' = 2423 - RECIPE_TYPE_FOOD: 'CommonGameTag' = 1505 - RECIPE_TYPE_GOURMET_COOKING_SKILL: 'CommonGameTag' = 2622 - RECIPE_TYPE_LIVESTOCK_FEED: 'CommonGameTag' = 2725 - RECIPE_TYPE_PET_DRINK: 'CommonGameTag' = 57425 - RECIPE_TYPE_PET_FOOD: 'CommonGameTag' = 57424 - REGION_ACTIVE_CAREER: 'CommonGameTag' = 12437 - REGION_CAMPING: 'CommonGameTag' = 1245 - REGION_JUNGLE: 'CommonGameTag' = 45059 - REGION_RESIDENTIAL: 'CommonGameTag' = 1244 - REGION_RETAIL: 'CommonGameTag' = 12374 - RESERVED_TEMP_BETA_FIX_DO_NOT_USE_1: 'CommonGameTag' = 138 - RESERVED_TEMP_BETA_FIX_DO_NOT_USE_2: 'CommonGameTag' = 139 - RESERVED_TEMP_BETA_FIX_DO_NOT_USE_3: 'CommonGameTag' = 142 - RESERVED_TEMP_BETA_FIX_DO_NOT_USE_4: 'CommonGameTag' = 143 - RESERVED_TEMP_BETA_FIX_DO_NOT_USE_5: 'CommonGameTag' = 144 - RESERVED_TEMP_BETA_FIX_DO_NOT_USE_6: 'CommonGameTag' = 147 - RESERVED_TEMP_BETA_FIX_DO_NOT_USE_7: 'CommonGameTag' = 281 - RESERVED_TEMP_BETA_FIX_DO_NOT_USE_8: 'CommonGameTag' = 284 - RESERVED_TEMP_BETA_FIX_DO_NOT_USE_9: 'CommonGameTag' = 290 - REWARD_CAS_PART: 'CommonGameTag' = 767 - ROLE_BAKE_ONE_CAKE: 'CommonGameTag' = 2277 - ROLE_BARTENDER: 'CommonGameTag' = 277 - ROLE_BUSINESS_CUSTOMER: 'CommonGameTag' = 1924 - ROLE_CAREER: 'CommonGameTag' = 467 - ROLE_CATERER: 'CommonGameTag' = 278 - ROLE_COLLEGE_ORGANIZATION_EVENT: 'CommonGameTag' = 65583 - ROLE_COWORKER: 'CommonGameTag' = 12292 - ROLE_CUSTOMER: 'CommonGameTag' = 2142 - ROLE_DATE: 'CommonGameTag' = 1439 - ROLE_DETECTIVE: 'CommonGameTag' = 12294 - ROLE_DOCTOR: 'CommonGameTag' = 12295 - ROLE_ENTERTAINER: 'CommonGameTag' = 650 - ROLE_EXCLUDE_FROM_YOGA_AND_MEDITATION_CLASS: 'CommonGameTag' = 2732 - ROLE_FESTIVAL_ARTS_CRAFTS: 'CommonGameTag' = 55317 - ROLE_FESTIVAL_BLOSSOM: 'CommonGameTag' = 55312 - ROLE_FESTIVAL_FLEA_MARKET: 'CommonGameTag' = 55318 - ROLE_FESTIVAL_FOOD: 'CommonGameTag' = 55315 - ROLE_FESTIVAL_LAMP: 'CommonGameTag' = 55313 - ROLE_FESTIVAL_LOGIC: 'CommonGameTag' = 55314 - ROLE_FESTIVAL_MUSIC: 'CommonGameTag' = 55316 - ROLE_FORTUNE_TELLER: 'CommonGameTag' = 8199 - ROLE_GUEST: 'CommonGameTag' = 266 - ROLE_HOST: 'CommonGameTag' = 267 - ROLE_HOST_AT_STATION: 'CommonGameTag' = 26635 - ROLE_LEAVE: 'CommonGameTag' = 418 - ROLE_MAID: 'CommonGameTag' = 279 - ROLE_NO_VISIT_COOLDOWN: 'CommonGameTag' = 2650 - ROLE_RESTAURANT_DINER: 'CommonGameTag' = 2147 - ROLE_RESTAURANT_EAT: 'CommonGameTag' = 2148 - ROLE_RESTAURANT_POST_PLACE_ORDER: 'CommonGameTag' = 2149 - ROLE_RESTAURANT_STAFF: 'CommonGameTag' = 26633 - ROLE_ROOMMATE_NPC: 'CommonGameTag' = 65541 - ROLE_SCIENTIST: 'CommonGameTag' = 12293 - ROLE_SERVICE: 'CommonGameTag' = 416 - ROLE_SPA_STAFF_BORED: 'CommonGameTag' = 18441 - ROLE_STATE_EP01_PATIENT_TREATED: 'CommonGameTag' = 12434 - ROLE_VET_PATIENT: 'CommonGameTag' = 57400 - ROLE_VIP_ROPE_ALLOWED: 'CommonGameTag' = 2143 - ROLE_WEDDING_PARTY: 'CommonGameTag' = 2748 - ROLE_YOGA_CLASS_POST_CLASS: 'CommonGameTag' = 18435 - ROLE_YOGA_PRE_CLASS: 'CommonGameTag' = 18463 - ROYALTY_APPS: 'CommonGameTag' = 908 - ROYALTY_BOOKS: 'CommonGameTag' = 909 - ROYALTY_GAMES: 'CommonGameTag' = 910 - ROYALTY_LYRICS: 'CommonGameTag' = 1629 - ROYALTY_PAINTINGS: 'CommonGameTag' = 911 - ROYALTY_SONGS: 'CommonGameTag' = 912 - SHOES_BOOTS: 'CommonGameTag' = 384 - SHOES_FLATS: 'CommonGameTag' = 385 - SHOES_HEELS: 'CommonGameTag' = 386 - SHOES_LACE_UP_ADULT: 'CommonGameTag' = 387 - SHOES_LACE_UP_CHILDREN: 'CommonGameTag' = 388 - SHOES_LOAFERS: 'CommonGameTag' = 389 - SHOES_SANDALS: 'CommonGameTag' = 390 - SHOES_SLIPPERS: 'CommonGameTag' = 391 - SHOES_SNEAKERS: 'CommonGameTag' = 392 - SHOES_WEDGES: 'CommonGameTag' = 393 - SICKNESS_CHECK_UP: 'CommonGameTag' = 57407 - SICKNESS_CURED_BY_EXAM_TABLE: 'CommonGameTag' = 57451 - SICKNESS_CURED_BY_SURGERY_STATION: 'CommonGameTag' = 57452 - SICKNESS_ILLNESS: 'CommonGameTag' = 57408 - SICKNESS_PET_EXAM: 'CommonGameTag' = 57403 - SITUATION_ACTIVE_CAREER: 'CommonGameTag' = 12358 - SITUATION_ACTIVE_CAREER_ADULT: 'CommonGameTag' = 2835 - SITUATION_ACTIVE_CAREER_HIGH_SCHOOL: 'CommonGameTag' = 114710 - SITUATION_ACTIVE_CAREER_SCIENTIST: 'CommonGameTag' = 12427 - SITUATION_ACTOR_CAREER_COMMERCIAL: 'CommonGameTag' = 61553 - SITUATION_ACTOR_CAREER_MOVIE: 'CommonGameTag' = 61556 - SITUATION_ACTOR_CAREER_PREP_TASK_ACTING: 'CommonGameTag' = 61615 - SITUATION_ACTOR_CAREER_PREP_TASK_CHARISMA: 'CommonGameTag' = 61458 - SITUATION_ACTOR_CAREER_PREP_TASK_COMEDY: 'CommonGameTag' = 61456 - SITUATION_ACTOR_CAREER_PREP_TASK_CO_STAR_REL: 'CommonGameTag' = 61454 - SITUATION_ACTOR_CAREER_PREP_TASK_DIRECTOR_REL: 'CommonGameTag' = 61455 - SITUATION_ACTOR_CAREER_PREP_TASK_FITNESS: 'CommonGameTag' = 61459 - SITUATION_ACTOR_CAREER_PREP_TASK_GUITAR: 'CommonGameTag' = 61460 - SITUATION_ACTOR_CAREER_PREP_TASK_HANDINESS: 'CommonGameTag' = 61457 - SITUATION_ACTOR_CAREER_PREP_TASK_PRACTICE_ACTION: 'CommonGameTag' = 61619 - SITUATION_ACTOR_CAREER_PREP_TASK_PRACTICE_DRAMATIC: 'CommonGameTag' = 61620 - SITUATION_ACTOR_CAREER_PREP_TASK_PRACTICE_ROMANTIC: 'CommonGameTag' = 61621 - SITUATION_ACTOR_CAREER_PREP_TASK_RESEARCH_FLIRTY: 'CommonGameTag' = 61616 - SITUATION_ACTOR_CAREER_PREP_TASK_RESEARCH_FUNNY: 'CommonGameTag' = 61617 - SITUATION_ACTOR_CAREER_PREP_TASK_RESEARCH_MEAN: 'CommonGameTag' = 61618 - SITUATION_ACTOR_CAREER_TV_HIGH: 'CommonGameTag' = 61555 - SITUATION_ACTOR_CAREER_TV_LOW: 'CommonGameTag' = 61554 - SITUATION_APARTMENT_NEIGHBOR_ANSWER_DOOR_COMPLAINT: 'CommonGameTag' = 55304 - SITUATION_APARTMENT_NEIGHBOR_LOUD_NOISES: 'CommonGameTag' = 55303 - SITUATION_BASKET_BALLER_A: 'CommonGameTag' = 55381 - SITUATION_BASKET_BALLER_B: 'CommonGameTag' = 55382 - SITUATION_BATUU_ARREST: 'CommonGameTag' = 51231 - SITUATION_BATUU_FR13_MISSION: 'CommonGameTag' = 51278 - SITUATION_BATUU_FS2_MISSION: 'CommonGameTag' = 51263 - SITUATION_BATUU_FS3_MISSION: 'CommonGameTag' = 51264 - SITUATION_BATUU_FS4_CRIMINAL: 'CommonGameTag' = 51255 - SITUATION_BATUU_FS6_MISSION: 'CommonGameTag' = 51262 - SITUATION_BATUU_FS7_MISSION: 'CommonGameTag' = 51261 - SITUATION_BATUU_INSPECTION: 'CommonGameTag' = 51232 - SITUATION_BATUU_MISSION_LIGHTSABER: 'CommonGameTag' = 51241 - SITUATION_BATUU_OGAS_CELEBRATION_BLACKLISTED: 'CommonGameTag' = 51243 - SITUATION_BATUU_RS2_MISSION: 'CommonGameTag' = 51272 - SITUATION_BATUU_RS4_MISSION: 'CommonGameTag' = 51269 - SITUATION_BATUU_RS6_MISSION: 'CommonGameTag' = 51273 - SITUATION_BATUU_RS7_MISSION: 'CommonGameTag' = 51274 - SITUATION_BATUU_SABACC_OPPONENT_1: 'CommonGameTag' = 51258 - SITUATION_BATUU_SABACC_OPPONENT_2: 'CommonGameTag' = 51259 - SITUATION_BATUU_SABACC_OPPONENT_3: 'CommonGameTag' = 51260 - SITUATION_BATUU_SR4_MISSION: 'CommonGameTag' = 51275 - SITUATION_BATUU_SR9_MISSION: 'CommonGameTag' = 51265 - SITUATION_BATUU_SS8_MISSION: 'CommonGameTag' = 51276 - SITUATION_BATUU_SS9_MISSION: 'CommonGameTag' = 51277 - SITUATION_BEAR: 'CommonGameTag' = 10247 - SITUATION_BONFIRE: 'CommonGameTag' = 24586 - SITUATION_BOWLING_GROUP: 'CommonGameTag' = 38919 - SITUATION_BOWLING_GROUP_2: 'CommonGameTag' = 38920 - SITUATION_BOWLING_GROUP_3: 'CommonGameTag' = 38921 - SITUATION_BOWLING_GROUP_4: 'CommonGameTag' = 38922 - SITUATION_BUSKER: 'CommonGameTag' = 55308 - SITUATION_BUTLER: 'CommonGameTag' = 36867 - SITUATION_CELEBRITY_FAN: 'CommonGameTag' = 61476 - SITUATION_CITY_INVITES: 'CommonGameTag' = 55380 - SITUATION_CITY_REPAIR: 'CommonGameTag' = 55355 - SITUATION_CLOWN: 'CommonGameTag' = 955 - SITUATION_COMPLAINT_NOISE: 'CommonGameTag' = 55425 - SITUATION_COOKING_INTERACTIONS: 'CommonGameTag' = 1017 - SITUATION_CRIMINAL: 'CommonGameTag' = 956 - SITUATION_DANCE_TOGETHER: 'CommonGameTag' = 24606 - SITUATION_DECORATOR_CAREER_HIDE_CLIENTS: 'CommonGameTag' = 53250 - SITUATION_DJ_PERFORMANCE: 'CommonGameTag' = 24582 - SITUATION_EVENT_NPC: 'CommonGameTag' = 1501 - SITUATION_FESTIVAL: 'CommonGameTag' = 55401 - SITUATION_FESTIVAL_BLOSSOM_ROMANTIC_COUPLE: 'CommonGameTag' = 55390 - SITUATION_FESTIVAL_LOGIC_ROCKET_SHIP_WOOHOOERS: 'CommonGameTag' = 55389 - SITUATION_FIREFIGHTER: 'CommonGameTag' = 2377 - SITUATION_FLOWER_BUNNY: 'CommonGameTag' = 59476 - SITUATION_FOREST_GHOST: 'CommonGameTag' = 10259 - SITUATION_FOREST_RANGER: 'CommonGameTag' = 10264 - SITUATION_FOX_ON_LOT: 'CommonGameTag' = 112671 - SITUATION_GARDENER: 'CommonGameTag' = 2152 - SITUATION_GNOME_BERSERK: 'CommonGameTag' = 59455 - SITUATION_GNOME_NORMAL: 'CommonGameTag' = 59454 - SITUATION_GP07_WALKBY_CONSPIRACIST_01: 'CommonGameTag' = 47158 - SITUATION_GP07_WALKBY_CONSPIRACIST_02: 'CommonGameTag' = 47159 - SITUATION_GP07_WALKBY_CONSPIRACIST_03: 'CommonGameTag' = 47160 - SITUATION_GP07_WALKBY_FBI_01: 'CommonGameTag' = 47161 - SITUATION_GP07_WALKBY_FBI_02: 'CommonGameTag' = 47162 - SITUATION_GP07_WALKBY_FBI_03: 'CommonGameTag' = 47163 - SITUATION_GP07_WALKBY_MILITARY_01: 'CommonGameTag' = 47150 - SITUATION_GP07_WALKBY_MILITARY_02: 'CommonGameTag' = 47151 - SITUATION_GP07_WALKBY_MILITARY_03: 'CommonGameTag' = 47152 - SITUATION_GP07_WALKBY_MILITARY_04: 'CommonGameTag' = 47153 - SITUATION_GP07_WALKBY_SCIENTIST_01: 'CommonGameTag' = 47154 - SITUATION_GP07_WALKBY_SCIENTIST_02: 'CommonGameTag' = 47155 - SITUATION_GP07_WALKBY_SCIENTIST_03: 'CommonGameTag' = 47156 - SITUATION_GP07_WALKBY_SCIENTIST_04: 'CommonGameTag' = 47157 - SITUATION_GRILL_GROUP: 'CommonGameTag' = 1461 - SITUATION_GROUP_CHEER: 'CommonGameTag' = 114739 - SITUATION_GROUP_COOKING: 'CommonGameTag' = 2646 - SITUATION_GROUP_DANCING: 'CommonGameTag' = 133127 - SITUATION_GROUP_WALKING: 'CommonGameTag' = 116747 - SITUATION_HIGH_SCHOOL_ACTIVE_HOOKY_AT_SCHOOL: 'CommonGameTag' = 114711 - SITUATION_HIKING_TRAIL: 'CommonGameTag' = 69746 - SITUATION_HIRED_NANNY: 'CommonGameTag' = 1550 - SITUATION_HOLIDAY: 'CommonGameTag' = 59460 - SITUATION_HOME_CHEF: 'CommonGameTag' = 26642 - SITUATION_HOT_DOG: 'CommonGameTag' = 958 - SITUATION_INTERIOR_DECORATOR_GIG_DEPENDENT: 'CommonGameTag' = 53252 - SITUATION_INTRIGUED_NOISE: 'CommonGameTag' = 55426 - SITUATION_INTRIGUED_SMELL: 'CommonGameTag' = 55427 - SITUATION_ISLAND_SPIRITS: 'CommonGameTag' = 63496 - SITUATION_KIDS_BIKE_PRACTICE: 'CommonGameTag' = 116742 - SITUATION_LIVES_ON_STREET_A: 'CommonGameTag' = 55435 - SITUATION_LIVES_ON_STREET_B: 'CommonGameTag' = 55436 - SITUATION_LIVES_ON_STREET_C: 'CommonGameTag' = 55437 - SITUATION_LIVES_ON_STREET_D: 'CommonGameTag' = 55438 - SITUATION_MAID: 'CommonGameTag' = 957 - SITUATION_MAILMAN: 'CommonGameTag' = 1343 - SITUATION_MARKET_STALL_VENDOR: 'CommonGameTag' = 1949 - SITUATION_MASTER_FISHERMAN: 'CommonGameTag' = 889 - SITUATION_MASTER_GARDENER: 'CommonGameTag' = 890 - SITUATION_MURAL_PAINTER: 'CommonGameTag' = 55383 - SITUATION_NIGHT_TIME_VISIT: 'CommonGameTag' = 1679 - SITUATION_PET_OBSTACLE_COURSE: 'CommonGameTag' = 57427 - SITUATION_PICNIC_TABLE: 'CommonGameTag' = 1460 - SITUATION_PIZZA: 'CommonGameTag' = 960 - SITUATION_PLAYER_FACING_CAN_HOST: 'CommonGameTag' = 1643 - SITUATION_PLAYER_VISITING_NPC: 'CommonGameTag' = 1493 - SITUATION_POSSESSED: 'CommonGameTag' = 47124 - SITUATION_PROMO_NIGHT: 'CommonGameTag' = 24594 - SITUATION_RANCH_HAND: 'CommonGameTag' = 118800 - SITUATION_REAPER: 'CommonGameTag' = 959 - SITUATION_REPAIRMAN: 'CommonGameTag' = 2153 - SITUATION_RESTAURANT_DINING: 'CommonGameTag' = 2146 - SITUATION_RETAIL_CUSTOMER: 'CommonGameTag' = 12323 - SITUATION_RETAIL_EMPLOYEE: 'CommonGameTag' = 12324 - SITUATION_RING_DOORBELL: 'CommonGameTag' = 684 - SITUATION_ROOMMATE_NPC_POTENTIAL: 'CommonGameTag' = 65572 - SITUATION_SECRET_SOCIETY: 'CommonGameTag' = 65570 - SITUATION_SLEEP_OVER: 'CommonGameTag' = 116741 - SITUATION_SPOOKY_PARTY: 'CommonGameTag' = 22541 - SITUATION_SQUAD: 'CommonGameTag' = 61634 - SITUATION_STAY_OVER: 'CommonGameTag' = 116748 - SITUATION_SUN_RAY: 'CommonGameTag' = 67647 - SITUATION_TRAGIC_CLOWN: 'CommonGameTag' = 1504 - SITUATION_TUTORIAL_FTUE: 'CommonGameTag' = 2167 - SITUATION_UMBRELLA_USER: 'CommonGameTag' = 2119 - SITUATION_UNIVERSITY_HOUSING_KICK_OUT_BLOCKER: 'CommonGameTag' = 65571 - SITUATION_UNIVERSITY_RIVALS_PRANK: 'CommonGameTag' = 65606 - SITUATION_VENUE_KARAOKE_DUETERS: 'CommonGameTag' = 55391 - SITUATION_VET_PLAYER_PET_OWNER: 'CommonGameTag' = 2498 - SITUATION_VET_SICK_PET: 'CommonGameTag' = 2499 - SITUATION_VIP_ROPE_BOUNCER: 'CommonGameTag' = 61613 - SITUATION_VISITOR_NPCS: 'CommonGameTag' = 2282 - SITUATION_VISITOR_NPC_ANGRY_SIM: 'CommonGameTag' = 67606 - SITUATION_WAIT_IN_LINE_TOGETHER: 'CommonGameTag' = 2496 - SITUATION_WALKBY_FIRST_ORDER_OFFICER_SPY: 'CommonGameTag' = 51226 - SITUATION_WEATHER_RAIN_HEAVY: 'CommonGameTag' = 2078 - SITUATION_WEATHER_RAIN_LIGHT: 'CommonGameTag' = 2079 - SITUATION_WEATHER_RAIN_STORM: 'CommonGameTag' = 2077 - SITUATION_WEATHER_SNOW_HEAVY: 'CommonGameTag' = 2080 - SITUATION_WEATHER_SNOW_STORM: 'CommonGameTag' = 2081 - SITUATION_WEDDING: 'CommonGameTag' = 133148 - SITUATION_WEIRDO: 'CommonGameTag' = 55309 - SITUATION_WELCOME_WAGON: 'CommonGameTag' = 1457 - SITUATION_WELCOME_WAGON_MAIN: 'CommonGameTag' = 2844 - SITUATION_YOGA_CLASS: 'CommonGameTag' = 18462 - SKILL_ADULT: 'CommonGameTag' = 2925 - SKILL_ALL: 'CommonGameTag' = 448 - SKILL_ALL_VISIBLE: 'CommonGameTag' = 2097 - SKILL_ARCHAEOLOGY: 'CommonGameTag' = 45094 - SKILL_ATHLETIC: 'CommonGameTag' = 86 - SKILL_BARTENDING: 'CommonGameTag' = 137 - SKILL_CHARISMA: 'CommonGameTag' = 676 - SKILL_CHILD: 'CommonGameTag' = 641 - SKILL_CLIMBING_SKIING_SNOWBOARDING: 'CommonGameTag' = 69698 - SKILL_COMEDY: 'CommonGameTag' = 2797 - SKILL_COMEDY_OR_MISCHIEF: 'CommonGameTag' = 1576 - SKILL_COOKING: 'CommonGameTag' = 87 - SKILL_CREATIVE: 'CommonGameTag' = 336 - SKILL_CROSS_STITCH: 'CommonGameTag' = 112661 - SKILL_DOG_TRAINING: 'CommonGameTag' = 57367 - SKILL_EQUESTRIAN_SKILL: 'CommonGameTag' = 2979 - SKILL_FITNESS_OR_PROGRAMMING: 'CommonGameTag' = 652 - SKILL_FLOWER_ARRANGING: 'CommonGameTag' = 59451 - SKILL_GARDENING: 'CommonGameTag' = 1605 - SKILL_GUITAR_OR_COMEDY: 'CommonGameTag' = 935 - SKILL_HANDINESS: 'CommonGameTag' = 1368 - SKILL_HORSE: 'CommonGameTag' = 2974 - SKILL_JUICE_FIZZING: 'CommonGameTag' = 67620 - SKILL_KNITTING: 'CommonGameTag' = 2626 - SKILL_LIFE: 'CommonGameTag' = 2986 - SKILL_LOCAL_CULTURE: 'CommonGameTag' = 45070 - SKILL_LOGIC: 'CommonGameTag' = 677 - SKILL_MENTAL: 'CommonGameTag' = 337 - SKILL_MENTORABLE: 'CommonGameTag' = 2765 - SKILL_MISCHIEF: 'CommonGameTag' = 2796 - SKILL_MUSICAL: 'CommonGameTag' = 445 - SKILL_MUSIC_OR_COMEDY: 'CommonGameTag' = 55305 - SKILL_PAINTING: 'CommonGameTag' = 1607 - SKILL_PERFORMANCE: 'CommonGameTag' = 1630 - SKILL_PHOTOGRAPHY: 'CommonGameTag' = 1940 - SKILL_PHOTOGRAPHY_BG: 'CommonGameTag' = 1609 - SKILL_PHYSICAL: 'CommonGameTag' = 338 - SKILL_PIPE_ORGAN: 'CommonGameTag' = 40969 - SKILL_PROGRAMMING: 'CommonGameTag' = 1606 - SKILL_PSYCHIC: 'CommonGameTag' = 8194 - SKILL_RANCH_NECTAR: 'CommonGameTag' = 2987 - SKILL_ROCKET_SCIENCE: 'CommonGameTag' = 678 - SKILL_ROCK_CLIMBING: 'CommonGameTag' = 69697 - SKILL_SCHOOL_TASK: 'CommonGameTag' = 1653 - SKILL_SINGING: 'CommonGameTag' = 1633 - SKILL_SKATING: 'CommonGameTag' = 59393 - SKILL_SKIING: 'CommonGameTag' = 69637 - SKILL_SNOWBOARDING: 'CommonGameTag' = 69696 - SKILL_SOCIAL: 'CommonGameTag' = 339 - SKILL_TODDLER: 'CommonGameTag' = 1655 - SKILL_VIDEO_GAMING: 'CommonGameTag' = 675 - SKILL_VIOLIN_OR_GUITAR: 'CommonGameTag' = 936 - SKILL_WELLNESS: 'CommonGameTag' = 18466 - SKILL_WELLNESS_BG: 'CommonGameTag' = 1608 - SKILL_WRITING: 'CommonGameTag' = 679 - SKINTONE_BLEND_YES: 'CommonGameTag' = 1458 - SKINTONE_TYPE_FANTASY: 'CommonGameTag' = 12317 - SKINTONE_TYPE_NATURAL: 'CommonGameTag' = 12316 - SKINTONE_TYPE_SICKNESS_1: 'CommonGameTag' = 12320 - SKINTONE_TYPE_SICKNESS_2: 'CommonGameTag' = 12321 - SKINTONE_TYPE_SICKNESS_3: 'CommonGameTag' = 12322 - SKINTONE_TYPE_SICKNESS_GREEN: 'CommonGameTag' = 12325 - SKIN_HUE_BLUE: 'CommonGameTag' = 12382 - SKIN_HUE_BLUE_SKIN: 'CommonGameTag' = 1449 - SKIN_HUE_GREEN: 'CommonGameTag' = 12389 - SKIN_HUE_GREEN_SKIN: 'CommonGameTag' = 1450 - SKIN_HUE_OLIVE: 'CommonGameTag' = 763 - SKIN_HUE_PURPLE: 'CommonGameTag' = 12390 - SKIN_HUE_RED: 'CommonGameTag' = 761 - SKIN_HUE_RED_SKIN: 'CommonGameTag' = 1625 - SKIN_HUE_YELLOW: 'CommonGameTag' = 762 - SKIN_VALUE_0: 'CommonGameTag' = 114730 - SKIN_VALUE_1: 'CommonGameTag' = 114725 - SKIN_VALUE_2: 'CommonGameTag' = 114726 - SKIN_VALUE_3: 'CommonGameTag' = 114727 - SKIN_VALUE_4: 'CommonGameTag' = 114728 - SKIN_VALUE_5: 'CommonGameTag' = 114729 - SOCIAL_BLACK_AND_WHITE: 'CommonGameTag' = 686 - SOCIAL_COSTUME_PARTY: 'CommonGameTag' = 687 - SOCIAL_FLIRTY: 'CommonGameTag' = 340 - SOCIAL_WEENIE_ROAST: 'CommonGameTag' = 10244 - SOCIAL_WOOHOO: 'CommonGameTag' = 364 - SP03_PLEASE_REUSE_ME_I_WAS_BLANK_ON_ACCIDENT: 'CommonGameTag' = 20487 - SP03_PLEASE_REUSE_ME_I_WAS_BLANK_ON_ACCIDENT_2: 'CommonGameTag' = 20488 - SPAWN_ARRIVAL: 'CommonGameTag' = 397 - SPAWN_ARTS_PARK: 'CommonGameTag' = 65622 - SPAWN_ARTS_QUAD: 'CommonGameTag' = 65619 - SPAWN_ARTS_UNIVERSITY_SHELL: 'CommonGameTag' = 65546 - SPAWN_ARTS_UNIVERSITY_SHELL_SHELL_1: 'CommonGameTag' = 65556 - SPAWN_ARTS_UNIVERSITY_SHELL_SHELL_2: 'CommonGameTag' = 65557 - SPAWN_BATTLE_HELPER: 'CommonGameTag' = 47133 - SPAWN_BATUU_DWELLING: 'CommonGameTag' = 51216 - SPAWN_BATUU_FIRST_ORDER_PATROL: 'CommonGameTag' = 51227 - SPAWN_BATUU_LT_AGNON: 'CommonGameTag' = 51218 - SPAWN_BATUU_RESISTANCE_PATROL_1: 'CommonGameTag' = 51228 - SPAWN_BATUU_RESISTANCE_PATROL_2: 'CommonGameTag' = 51229 - SPAWN_BATUU_VI_MORADI: 'CommonGameTag' = 51217 - SPAWN_CLOTHING_STORE: 'CommonGameTag' = 118795 - SPAWN_COTTAGE_WORLD_CRITTER_TENDER: 'CommonGameTag' = 112670 - SPAWN_COTTAGE_WORLD_FOXHOLE: 'CommonGameTag' = 112669 - SPAWN_EQUESTRIAN_CENTER: 'CommonGameTag' = 118793 - SPAWN_EQUESTRIAN_CENTER_EXIT: 'CommonGameTag' = 118872 - SPAWN_FIREPLACE: 'CommonGameTag' = 2057 - SPAWN_GENERIC_01: 'CommonGameTag' = 2465 - SPAWN_GENERIC_02: 'CommonGameTag' = 2466 - SPAWN_GENERIC_03: 'CommonGameTag' = 2467 - SPAWN_GENERIC_04: 'CommonGameTag' = 2468 - SPAWN_GENERIC_05: 'CommonGameTag' = 2469 - SPAWN_GRIM_REAPER: 'CommonGameTag' = 987 - SPAWN_GROCERY_STORE: 'CommonGameTag' = 118794 - SPAWN_LIGHTHOUSE: 'CommonGameTag' = 57409 - SPAWN_LIGHTHOUSE_ARRIVAL: 'CommonGameTag' = 1935 - SPAWN_MAGIC_PORTAL: 'CommonGameTag' = 2223 - SPAWN_MAGIC_PORTAL_MARKET: 'CommonGameTag' = 49182 - SPAWN_MARKET_STALL_MAGIC_BROOM: 'CommonGameTag' = 49166 - SPAWN_MARKET_STALL_MAGIC_POTION: 'CommonGameTag' = 49171 - SPAWN_MARKET_STALL_MAGIC_WAND: 'CommonGameTag' = 49172 - SPAWN_MARKET_STALL_WEDDING_CHINESE: 'CommonGameTag' = 133123 - SPAWN_MARKET_STALL_WEDDING_INDIAN: 'CommonGameTag' = 133124 - SPAWN_MARKET_STALL_WEDDING_PATISSERIE: 'CommonGameTag' = 133125 - SPAWN_MUSIC_FESTIVAL: 'CommonGameTag' = 2559 - SPAWN_NIGHT_STALKER: 'CommonGameTag' = 49158 - SPAWN_PET_CRATE: 'CommonGameTag' = 57387 - SPAWN_PIER_ARRIVAL: 'CommonGameTag' = 114749 - SPAWN_REAR_WALKBY: 'CommonGameTag' = 400 - SPAWN_SCIENCE_QUAD: 'CommonGameTag' = 65620 - SPAWN_SCIENCE_UNIVERSITY_SHELL: 'CommonGameTag' = 65547 - SPAWN_SCIENCE_UNIVERSITY_SHELL_SHELL_1: 'CommonGameTag' = 65558 - SPAWN_SCIENCE_UNIVERSITY_SHELL_SHELL_2: 'CommonGameTag' = 65559 - SPAWN_SEANCE: 'CommonGameTag' = 86021 - SPAWN_SECRET_SOCIETY: 'CommonGameTag' = 65621 - SPAWN_SHELL_ARRIVAL: 'CommonGameTag' = 1933 - SPAWN_SKELETON_ARRIVAL: 'CommonGameTag' = 2039 - SPAWN_SNOW_SPORTS_SLOPE_BUNNY_SLOPE: 'CommonGameTag' = 69740 - SPAWN_STAGE_ARTIST: 'CommonGameTag' = 2560 - SPAWN_STARSHIP: 'CommonGameTag' = 51215 - SPAWN_VISITOR_ARRIVAL: 'CommonGameTag' = 399 - SPAWN_WALKBY: 'CommonGameTag' = 398 - SPAWN_WALKBY_SPORTS_SHELL_EP08: 'CommonGameTag' = 2234 - SPAWN_WALK_BY_SHELL_01: 'CommonGameTag' = 2924 - SPAWN_WOLF_TOWN_GREG: 'CommonGameTag' = 135181 - SPAWN_WOLF_TOWN_HOWL_SPOT_TOP: 'CommonGameTag' = 135182 - SPAWN_WOLF_TOWN_MINE: 'CommonGameTag' = 135177 - SPAWN_WOLF_TOWN_ON_LOT_VERSION: 'CommonGameTag' = 135180 - SPAWN_WOLF_TOWN_PORTA_POTTY: 'CommonGameTag' = 135178 - SPAWN_WOLF_TOWN_SEWER: 'CommonGameTag' = 135179 - SPAWN_ZOMBIE: 'CommonGameTag' = 47132 - SPECIAL_CONTENT_ANNIVERSARY_21: 'CommonGameTag' = 2521 - SPECIAL_NUDE: 'CommonGameTag' = 127 - SPELL_MAGIC: 'CommonGameTag' = 49170 - STYLE_ARTS_QUARTER: 'CommonGameTag' = 55330 - STYLE_BOHEMIAN: 'CommonGameTag' = 1495 - STYLE_BUSINESS: 'CommonGameTag' = 1593 - STYLE_CAS_BLACK_HISTORY_MONTH: 'CommonGameTag' = 2768 - STYLE_CAS_BRANDED_ANNIVERSARY_21: 'CommonGameTag' = 2520 - STYLE_CAS_BRANDED_MAC: 'CommonGameTag' = 2433 - STYLE_CAS_BRANDED_ME_UNDIES: 'CommonGameTag' = 167937 - STYLE_CAS_DEPOP: 'CommonGameTag' = 114740 - STYLE_CAS_DESIGNED_BY: 'CommonGameTag' = 2909 - STYLE_CAS_EBONIX_NAILS: 'CommonGameTag' = 18485 - STYLE_CLASSICS: 'CommonGameTag' = 239 - STYLE_COUNTRY: 'CommonGameTag' = 985 - STYLE_FASHION_DISTRICT: 'CommonGameTag' = 55331 - STYLE_FESTIVAL_BLOSSOM: 'CommonGameTag' = 55348 - STYLE_FESTIVAL_DARK: 'CommonGameTag' = 1623 - STYLE_FESTIVAL_FOOD: 'CommonGameTag' = 1624 - STYLE_FESTIVAL_LIGHT: 'CommonGameTag' = 1622 - STYLE_FESTIVAL_NERD: 'CommonGameTag' = 1621 - STYLE_FESTIVAL_ROMANCE: 'CommonGameTag' = 1620 - STYLE_FORMAL_MODERN: 'CommonGameTag' = 248 - STYLE_FORMAL_TRENDY: 'CommonGameTag' = 249 - STYLE_FRANKENSTEIN: 'CommonGameTag' = 8197 - STYLE_GAMER: 'CommonGameTag' = 2842 - STYLE_GEN_CITY_SLEEK: 'CommonGameTag' = 238 - STYLE_GEN_CONTEMPORARY_BASIC: 'CommonGameTag' = 240 - STYLE_GEN_CONTEMPORARY_DESIGNER: 'CommonGameTag' = 241 - STYLE_GEN_OUTDOOR_EXPLORER: 'CommonGameTag' = 243 - STYLE_GEN_PARTY_TRENDY: 'CommonGameTag' = 244 - STYLE_GEN_POLISHED: 'CommonGameTag' = 245 - STYLE_GEN_PREPPY: 'CommonGameTag' = 246 - STYLE_GEN_ROMANTIC: 'CommonGameTag' = 247 - STYLE_GEN_SUMMER: 'CommonGameTag' = 237 - STYLE_GLAMPING: 'CommonGameTag' = 10265 - STYLE_GOTH_ROCK_PUNK: 'CommonGameTag' = 289 - STYLE_HIPSTER: 'CommonGameTag' = 986 - STYLE_ISLANDER: 'CommonGameTag' = 63495 - STYLE_ISLAND_ELEMENTAL: 'CommonGameTag' = 63517 - STYLE_JAPANESE_CONTEMPORARY: 'CommonGameTag' = 69693 - STYLE_JUNGLE: 'CommonGameTag' = 2036 - STYLE_NATIVE_AMERICAN: 'CommonGameTag' = 2995 - STYLE_PIRATE: 'CommonGameTag' = 8196 - STYLE_PROFESSOR_NPC_GOOD: 'CommonGameTag' = 65597 - STYLE_PROFESSOR_NPC_GRUMPY: 'CommonGameTag' = 65596 - STYLE_PROFESSOR_NPC_HIP: 'CommonGameTag' = 65595 - STYLE_PROFESSOR_NPC_SMART: 'CommonGameTag' = 65598 - STYLE_SEASONAL_FALL: 'CommonGameTag' = 2066 - STYLE_SEASONAL_SPRING: 'CommonGameTag' = 2067 - STYLE_SEASONAL_SUMMER: 'CommonGameTag' = 2068 - STYLE_SEASONAL_WINTER: 'CommonGameTag' = 2065 - STYLE_SHABBY: 'CommonGameTag' = 2780 - STYLE_SPICE_MARKET: 'CommonGameTag' = 55332 - STYLE_SPORTY: 'CommonGameTag' = 2843 - STYLE_STREET: 'CommonGameTag' = 1592 - STYLE_VAMPIRE_ARCHETYPE_DRACULA: 'CommonGameTag' = 1681 - STYLE_VAMPIRE_ARCHETYPE_MODERN: 'CommonGameTag' = 1682 - STYLE_VAMPIRE_ARCHETYPE_NOSFERATU: 'CommonGameTag' = 1680 - STYLE_VAMPIRE_ARCHETYPE_PUNK: 'CommonGameTag' = 1684 - STYLE_VAMPIRE_ARCHETYPE_VICTORIAN: 'CommonGameTag' = 1683 - STYLE_VAMPIRE_WALKBY_MODERN: 'CommonGameTag' = 40966 - STYLE_VAMPIRE_WALKBY_NOSFERATU: 'CommonGameTag' = 40964 - STYLE_VAMPIRE_WALKBY_PUNK: 'CommonGameTag' = 40968 - STYLE_VAMPIRE_WALKBY_VICTORIAN: 'CommonGameTag' = 40967 - STYLE_WITCH: 'CommonGameTag' = 8195 - TAIL_LONG: 'CommonGameTag' = 2707 - TAIL_RING: 'CommonGameTag' = 2704 - TAIL_SABER: 'CommonGameTag' = 2705 - TAIL_SCREW: 'CommonGameTag' = 2706 - TAIL_STUB: 'CommonGameTag' = 2708 - TERRAIN_MANIP_ALL: 'CommonGameTag' = 2169 - TERRAIN_PAINT_ALL: 'CommonGameTag' = 1082 - TERRAIN_PAINT_DIRT: 'CommonGameTag' = 872 - TERRAIN_PAINT_GRASS: 'CommonGameTag' = 873 - TERRAIN_PAINT_MISC: 'CommonGameTag' = 875 - TERRAIN_PAINT_STONE: 'CommonGameTag' = 874 - TOOLTIP_AMBIENCE_ANGRY: 'CommonGameTag' = 732 - TOOLTIP_AMBIENCE_BORED: 'CommonGameTag' = 733 - TOOLTIP_AMBIENCE_CONFIDENT: 'CommonGameTag' = 734 - TOOLTIP_AMBIENCE_EMBARRASSED: 'CommonGameTag' = 735 - TOOLTIP_AMBIENCE_ENERGIZED: 'CommonGameTag' = 736 - TOOLTIP_AMBIENCE_FLIRTY: 'CommonGameTag' = 737 - TOOLTIP_AMBIENCE_FOCUSED: 'CommonGameTag' = 738 - TOOLTIP_AMBIENCE_HAPPY: 'CommonGameTag' = 739 - TOOLTIP_AMBIENCE_IMAGINATIVE: 'CommonGameTag' = 740 - TOOLTIP_AMBIENCE_PLAYFUL: 'CommonGameTag' = 741 - TOOLTIP_AMBIENCE_SAD: 'CommonGameTag' = 742 - TOOLTIP_AMBIENCE_TENSE: 'CommonGameTag' = 743 - TOOLTIP_BILLS_DECREASE: 'CommonGameTag' = 2396 - TOOLTIP_BILLS_INCREASE: 'CommonGameTag' = 2395 - TOOLTIP_COLUMN_HEIGHT_RESTRICTED: 'CommonGameTag' = 2238 - TOOLTIP_CRAFTING_QUALITY_CARPENTRY: 'CommonGameTag' = 706 - TOOLTIP_CRAFTING_QUALITY_COOKING: 'CommonGameTag' = 703 - TOOLTIP_CRAFTING_QUALITY_DRINKS: 'CommonGameTag' = 704 - TOOLTIP_CRAFTING_QUALITY_PAINTING: 'CommonGameTag' = 705 - TOOLTIP_ECO_FOOTPRINT_NEGATIVE: 'CommonGameTag' = 67624 - TOOLTIP_ECO_FOOTPRINT_POSITIVE: 'CommonGameTag' = 67623 - TOOLTIP_ENVIRONMENT_SCORE_NEGATIVE: 'CommonGameTag' = 2389 - TOOLTIP_ENVIRONMENT_SCORE_POSITIVE: 'CommonGameTag' = 2390 - TOOLTIP_EP02_SKILL_DANCE: 'CommonGameTag' = 3001 - TOOLTIP_EP09_ECO_FOOTPRINT_NEGATIVE: 'CommonGameTag' = 2422 - TOOLTIP_EP09_ECO_FOOTPRINT_POSITIVE: 'CommonGameTag' = 2421 - TOOLTIP_HIGH_FIRE_RESISTANCE: 'CommonGameTag' = 2392 - TOOLTIP_HIGH_WATER_RESISTANCE: 'CommonGameTag' = 2394 - TOOLTIP_LOW_FIRE_RESISTANCE: 'CommonGameTag' = 2391 - TOOLTIP_LOW_WATER_RESISTANCE: 'CommonGameTag' = 2393 - TOOLTIP_MISC_CATS_ONLY: 'CommonGameTag' = 2027 - TOOLTIP_MISC_CHILDREN_ONLY: 'CommonGameTag' = 783 - TOOLTIP_MISC_CHILDREN_TODDLER_INFANT_ONLY: 'CommonGameTag' = 2960 - TOOLTIP_MISC_CHILDREN_TODDLER_ONLY: 'CommonGameTag' = 2959 - TOOLTIP_MISC_COMFORT: 'CommonGameTag' = 784 - TOOLTIP_MISC_DOGS_ONLY: 'CommonGameTag' = 2026 - TOOLTIP_MISC_INFANT_ONLY: 'CommonGameTag' = 2958 - TOOLTIP_MISC_NEWBORN_ONLY: 'CommonGameTag' = 2927 - TOOLTIP_MISC_PETS_ONLY: 'CommonGameTag' = 2025 - TOOLTIP_MISC_RELIABILITY: 'CommonGameTag' = 907 - TOOLTIP_MISC_TODDLER_INFANT_ONLY: 'CommonGameTag' = 2961 - TOOLTIP_MISC_TODDLER_ONLY: 'CommonGameTag' = 1667 - TOOLTIP_MISC_UNBREAKABLE: 'CommonGameTag' = 731 - TOOLTIP_MISC_UNCOMFORTABLE: 'CommonGameTag' = 747 - TOOLTIP_MISC_UNCOMFORTABLE_FOR_ADULTS: 'CommonGameTag' = 940 - TOOLTIP_MISC_WEREWOLF_ONLY_DOOR: 'CommonGameTag' = 2783 - TOOLTIP_MOOD_RELIEF_ANGRY: 'CommonGameTag' = 710 - TOOLTIP_MOOD_RELIEF_BORED: 'CommonGameTag' = 711 - TOOLTIP_MOOD_RELIEF_EMBARRASSED: 'CommonGameTag' = 712 - TOOLTIP_MOOD_RELIEF_SAD: 'CommonGameTag' = 709 - TOOLTIP_MOOD_RELIEF_STRESS: 'CommonGameTag' = 707 - TOOLTIP_MOOD_RELIEF_UNCOMFORTABLE: 'CommonGameTag' = 708 - TOOLTIP_MOTIVE_BLADDER: 'CommonGameTag' = 701 - TOOLTIP_MOTIVE_ENERGY: 'CommonGameTag' = 698 - TOOLTIP_MOTIVE_FUN: 'CommonGameTag' = 699 - TOOLTIP_MOTIVE_HUNGER: 'CommonGameTag' = 702 - TOOLTIP_MOTIVE_HYGIENE: 'CommonGameTag' = 697 - TOOLTIP_MOTIVE_SOCIAL: 'CommonGameTag' = 700 - TOOLTIP_OFF_THE_GRID: 'CommonGameTag' = 2207 - TOOLTIP_POWER_CONSUMER: 'CommonGameTag' = 2398 - TOOLTIP_POWER_PRODUCER: 'CommonGameTag' = 2397 - TOOLTIP_SKILL_ACTING: 'CommonGameTag' = 61637 - TOOLTIP_SKILL_AGILITY: 'CommonGameTag' = 2999 - TOOLTIP_SKILL_ARCHAEOLOGY: 'CommonGameTag' = 45110 - TOOLTIP_SKILL_BARTENDING: 'CommonGameTag' = 717 - TOOLTIP_SKILL_CHARISMA: 'CommonGameTag' = 729 - TOOLTIP_SKILL_COMEDY: 'CommonGameTag' = 726 - TOOLTIP_SKILL_COMMUNICATION: 'CommonGameTag' = 1670 - TOOLTIP_SKILL_COOKING: 'CommonGameTag' = 713 - TOOLTIP_SKILL_CREATIVITY: 'CommonGameTag' = 927 - TOOLTIP_SKILL_DANCE: 'CommonGameTag' = 24615 - TOOLTIP_SKILL_DJ: 'CommonGameTag' = 24614 - TOOLTIP_SKILL_DOG_TRAINING: 'CommonGameTag' = 2023 - TOOLTIP_SKILL_ENTREPRENEUR: 'CommonGameTag' = 2964 - TOOLTIP_SKILL_EQUESTRIAN: 'CommonGameTag' = 3000 - TOOLTIP_SKILL_FITNESS: 'CommonGameTag' = 716 - TOOLTIP_SKILL_FLOWER_ARRANGING: 'CommonGameTag' = 2115 - TOOLTIP_SKILL_GARDENING: 'CommonGameTag' = 728 - TOOLTIP_SKILL_GUITAR: 'CommonGameTag' = 727 - TOOLTIP_SKILL_HANDINESS: 'CommonGameTag' = 719 - TOOLTIP_SKILL_IMAGINATION: 'CommonGameTag' = 1669 - TOOLTIP_SKILL_JUMPING: 'CommonGameTag' = 2998 - TOOLTIP_SKILL_LOGIC: 'CommonGameTag' = 721 - TOOLTIP_SKILL_MENTAL: 'CommonGameTag' = 928 - TOOLTIP_SKILL_MISCHIEF: 'CommonGameTag' = 722 - TOOLTIP_SKILL_MOTOR: 'CommonGameTag' = 929 - TOOLTIP_SKILL_MOVEMENT: 'CommonGameTag' = 1668 - TOOLTIP_SKILL_NECTAR_MAKING: 'CommonGameTag' = 2997 - TOOLTIP_SKILL_PAINTING: 'CommonGameTag' = 718 - TOOLTIP_SKILL_PARENTING: 'CommonGameTag' = 2962 - TOOLTIP_SKILL_PIANO: 'CommonGameTag' = 724 - TOOLTIP_SKILL_PIPE_ORGAN: 'CommonGameTag' = 40978 - TOOLTIP_SKILL_POTTY: 'CommonGameTag' = 1672 - TOOLTIP_SKILL_PROGRAMMING: 'CommonGameTag' = 715 - TOOLTIP_SKILL_PSYCHIC: 'CommonGameTag' = 8212 - TOOLTIP_SKILL_RESEARCH_DEBATE: 'CommonGameTag' = 2269 - TOOLTIP_SKILL_ROBOTICS: 'CommonGameTag' = 2270 - TOOLTIP_SKILL_ROCKET_SCIENCE: 'CommonGameTag' = 720 - TOOLTIP_SKILL_SINGING: 'CommonGameTag' = 55434 - TOOLTIP_SKILL_SKIING: 'CommonGameTag' = 2965 - TOOLTIP_SKILL_SNOWBOARDING: 'CommonGameTag' = 2966 - TOOLTIP_SKILL_SOCIAL: 'CommonGameTag' = 930 - TOOLTIP_SKILL_THINKING: 'CommonGameTag' = 1671 - TOOLTIP_SKILL_VAMPIRE_LORE: 'CommonGameTag' = 2963 - TOOLTIP_SKILL_VET: 'CommonGameTag' = 2024 - TOOLTIP_SKILL_VIDEO_GAMING: 'CommonGameTag' = 714 - TOOLTIP_SKILL_VIOLIN: 'CommonGameTag' = 725 - TOOLTIP_SKILL_WELLNESS: 'CommonGameTag' = 18459 - TOOLTIP_SKILL_WOOHOO: 'CommonGameTag' = 730 - TOOLTIP_SKILL_WRITING: 'CommonGameTag' = 723 - TOOLTIP_WATER_CONSUMER: 'CommonGameTag' = 2400 - TOOLTIP_WATER_PRODUCER: 'CommonGameTag' = 2399 - TOP_BIKINI: 'CommonGameTag' = 1236 - TOP_BLOUSE: 'CommonGameTag' = 155 - TOP_BRASSIERE: 'CommonGameTag' = 944 - TOP_BUTTON_UPS: 'CommonGameTag' = 395 - TOP_JACKET: 'CommonGameTag' = 295 - TOP_POLO: 'CommonGameTag' = 943 - TOP_SHIRT_TEE: 'CommonGameTag' = 296 - TOP_SUIT_JACKET: 'CommonGameTag' = 942 - TOP_SWEATER: 'CommonGameTag' = 297 - TOP_SWEATSHIRT: 'CommonGameTag' = 941 - TOP_TANKTOP: 'CommonGameTag' = 360 - TOP_VEST: 'CommonGameTag' = 156 - TRAIT_ACHIEVEMENT: 'CommonGameTag' = 235 - TRAIT_AGE: 'CommonGameTag' = 657 - TRAIT_GROUP_EMOTIONAL: 'CommonGameTag' = 753 - TRAIT_GROUP_HOBBIES: 'CommonGameTag' = 754 - TRAIT_GROUP_LIFESTYLE: 'CommonGameTag' = 755 - TRAIT_GROUP_SOCIAL: 'CommonGameTag' = 756 - TRAIT_PERSONALITY: 'CommonGameTag' = 234 - TRAIT_WALKSTYLE: 'CommonGameTag' = 236 - UNIFORM_ACTIVIST_CRIMINAL_JUSTICE: 'CommonGameTag' = 55413 - UNIFORM_ACTIVIST_ECONOMIC_GROWTH: 'CommonGameTag' = 55414 - UNIFORM_ACTIVIST_ENVIRONMENT: 'CommonGameTag' = 55415 - UNIFORM_ACTIVIST_GLOBAL_PEACE: 'CommonGameTag' = 55416 - UNIFORM_ACTIVIST_TAX_REFORM: 'CommonGameTag' = 55417 - UNIFORM_ACTOR_CAREER_COMMERCIAL_HOSPITAL_ACTOR: 'CommonGameTag' = 61561 - UNIFORM_ACTOR_CAREER_COMMERCIAL_HOSPITAL_CO_STAR: 'CommonGameTag' = 61562 - UNIFORM_ACTOR_CAREER_COMMERCIAL_HOUSE_NICE_ACTOR: 'CommonGameTag' = 61564 - UNIFORM_ACTOR_CAREER_COMMERCIAL_HOUSE_NICE_CO_STAR: 'CommonGameTag' = 61565 - UNIFORM_ACTOR_CAREER_COMMERCIAL_KIDS_ACTOR: 'CommonGameTag' = 61566 - UNIFORM_ACTOR_CAREER_COMMERCIAL_PIRATE_ACTOR: 'CommonGameTag' = 61560 - UNIFORM_ACTOR_CAREER_COMMERCIAL_WESTERN_ACTOR: 'CommonGameTag' = 61563 - UNIFORM_ACTOR_CAREER_MOVIE_CITY_ACTOR: 'CommonGameTag' = 61608 - UNIFORM_ACTOR_CAREER_MOVIE_CITY_CO_STAR: 'CommonGameTag' = 61452 - UNIFORM_ACTOR_CAREER_MOVIE_CITY_LOVE_INTEREST: 'CommonGameTag' = 61451 - UNIFORM_ACTOR_CAREER_MOVIE_MEDIEVAL_ACTOR: 'CommonGameTag' = 61594 - UNIFORM_ACTOR_CAREER_MOVIE_MEDIEVAL_LOVE_INTEREST: 'CommonGameTag' = 61596 - UNIFORM_ACTOR_CAREER_MOVIE_MEDIEVAL_VILLAIN: 'CommonGameTag' = 61595 - UNIFORM_ACTOR_CAREER_MOVIE_PIRATE_ACTOR: 'CommonGameTag' = 61591 - UNIFORM_ACTOR_CAREER_MOVIE_PIRATE_LOVE_INTEREST: 'CommonGameTag' = 61593 - UNIFORM_ACTOR_CAREER_MOVIE_PIRATE_VILLAIN: 'CommonGameTag' = 61592 - UNIFORM_ACTOR_CAREER_MOVIE_SUPER_HERO_ACTOR: 'CommonGameTag' = 61603 - UNIFORM_ACTOR_CAREER_MOVIE_SUPER_HERO_LOVE_INTEREST: 'CommonGameTag' = 61605 - UNIFORM_ACTOR_CAREER_MOVIE_SUPER_HERO_VILLAIN: 'CommonGameTag' = 61604 - UNIFORM_ACTOR_CAREER_MOVIE_VICTORIAN_ACTOR: 'CommonGameTag' = 61600 - UNIFORM_ACTOR_CAREER_MOVIE_VICTORIAN_CO_STAR: 'CommonGameTag' = 61602 - UNIFORM_ACTOR_CAREER_MOVIE_VICTORIAN_LOVE_INTEREST: 'CommonGameTag' = 61601 - UNIFORM_ACTOR_CAREER_MOVIE_WESTERN_ACTOR: 'CommonGameTag' = 61597 - UNIFORM_ACTOR_CAREER_MOVIE_WESTERN_ALIEN: 'CommonGameTag' = 61599 - UNIFORM_ACTOR_CAREER_MOVIE_WESTERN_CREATURE: 'CommonGameTag' = 61598 - UNIFORM_ACTOR_CAREER_TV_HIGH_APOCALYPSE_ACTOR: 'CommonGameTag' = 61577 - UNIFORM_ACTOR_CAREER_TV_HIGH_APOCALYPSE_CO_STAR: 'CommonGameTag' = 61578 - UNIFORM_ACTOR_CAREER_TV_HIGH_APOCALYPSE_VILLAIN: 'CommonGameTag' = 61579 - UNIFORM_ACTOR_CAREER_TV_HIGH_HOSPITAL_ACTOR: 'CommonGameTag' = 61580 - UNIFORM_ACTOR_CAREER_TV_HIGH_HOSPITAL_CO_STAR: 'CommonGameTag' = 61582 - UNIFORM_ACTOR_CAREER_TV_HIGH_HOSPITAL_LOVE_INTEREST: 'CommonGameTag' = 61581 - UNIFORM_ACTOR_CAREER_TV_HIGH_POLICE_ACTOR: 'CommonGameTag' = 61588 - UNIFORM_ACTOR_CAREER_TV_HIGH_POLICE_CO_STAR: 'CommonGameTag' = 61590 - UNIFORM_ACTOR_CAREER_TV_HIGH_POLICE_VILLAIN: 'CommonGameTag' = 61589 - UNIFORM_ACTOR_CAREER_TV_HIGH_VICTORIAN_ACTOR: 'CommonGameTag' = 61585 - UNIFORM_ACTOR_CAREER_TV_HIGH_VICTORIAN_CO_STAR: 'CommonGameTag' = 61587 - UNIFORM_ACTOR_CAREER_TV_HIGH_VICTORIAN_LOVE_INTEREST: 'CommonGameTag' = 61586 - UNIFORM_ACTOR_CAREER_TV_HIGH_WESTERN_ACTOR: 'CommonGameTag' = 61583 - UNIFORM_ACTOR_CAREER_TV_HIGH_WESTERN_VILLAIN: 'CommonGameTag' = 61584 - UNIFORM_ACTOR_CAREER_TV_LOW_HOUSE_LOW_ACTOR: 'CommonGameTag' = 61574 - UNIFORM_ACTOR_CAREER_TV_LOW_HOUSE_LOW_CO_STAR: 'CommonGameTag' = 61575 - UNIFORM_ACTOR_CAREER_TV_LOW_HOUSE_NICE_ACTOR: 'CommonGameTag' = 61570 - UNIFORM_ACTOR_CAREER_TV_LOW_HOUSE_NICE_CO_STAR: 'CommonGameTag' = 61571 - UNIFORM_ACTOR_CAREER_TV_LOW_KIDS_ACTOR: 'CommonGameTag' = 61576 - UNIFORM_ACTOR_CAREER_TV_LOW_PIRATE_ACTOR: 'CommonGameTag' = 61567 - UNIFORM_ACTOR_CAREER_TV_LOW_PIRATE_CO_STAR: 'CommonGameTag' = 61569 - UNIFORM_ACTOR_CAREER_TV_LOW_PIRATE_LOVE_INTEREST: 'CommonGameTag' = 61568 - UNIFORM_ACTOR_CAREER_TV_LOW_WESTERN_ACTOR: 'CommonGameTag' = 61572 - UNIFORM_ACTOR_CAREER_TV_LOW_WESTERN_CO_STAR: 'CommonGameTag' = 61573 - UNIFORM_ARRESTED: 'CommonGameTag' = 12336 - UNIFORM_ARTS_CENTER_PAINTER: 'CommonGameTag' = 55357 - UNIFORM_ART_CRITIC_SHOW_FORMAL: 'CommonGameTag' = 55395 - UNIFORM_ASTRONAUT_STATUE_GOLD: 'CommonGameTag' = 55302 - UNIFORM_ASTRONAUT_STATUE_SILVER: 'CommonGameTag' = 55354 - UNIFORM_ASTRONAUT_SUIT: 'CommonGameTag' = 614 - UNIFORM_ATHLETIC_CHEERLEADER: 'CommonGameTag' = 1262 - UNIFORM_ATHLETIC_LIFTER: 'CommonGameTag' = 1263 - UNIFORM_ATHLETIC_MAJOR_LEAGUER: 'CommonGameTag' = 1266 - UNIFORM_ATHLETIC_MASCOT: 'CommonGameTag' = 1264 - UNIFORM_ATHLETIC_MINOR_LEAGUER: 'CommonGameTag' = 1267 - UNIFORM_ATHLETIC_TRACK_SUIT: 'CommonGameTag' = 1265 - UNIFORM_BABYSITTER: 'CommonGameTag' = 887 - UNIFORM_BACKGROUND_ACTOR_COSTUME_1: 'CommonGameTag' = 61642 - UNIFORM_BACKGROUND_ACTOR_COSTUME_2: 'CommonGameTag' = 61643 - UNIFORM_BACKGROUND_ACTOR_COSTUME_3: 'CommonGameTag' = 61644 - UNIFORM_BACKGROUND_ACTOR_COSTUME_4: 'CommonGameTag' = 61645 - UNIFORM_BACKGROUND_ACTOR_COSTUME_5: 'CommonGameTag' = 61646 - UNIFORM_BARISTA: 'CommonGameTag' = 884 - UNIFORM_BARTENDER: 'CommonGameTag' = 621 - UNIFORM_BARTENDER_JUNGLE: 'CommonGameTag' = 45090 - UNIFORM_BARTENDER_WOLF_TOWN: 'CommonGameTag' = 2789 - UNIFORM_BATUU_ALIEN_ABEDNEDO: 'CommonGameTag' = 2471 - UNIFORM_BATUU_ALIEN_BITH: 'CommonGameTag' = 2472 - UNIFORM_BATUU_ALIEN_MIRIALAN: 'CommonGameTag' = 2473 - UNIFORM_BATUU_ALIEN_TWILEK: 'CommonGameTag' = 2474 - UNIFORM_BATUU_ALIEN_WEEQUAY: 'CommonGameTag' = 2475 - UNIFORM_BATUU_ALIEN_ZABRAK: 'CommonGameTag' = 2476 - UNIFORM_BATUU_BARTENDER: 'CommonGameTag' = 51225 - UNIFORM_BATUU_CITIZEN: 'CommonGameTag' = 51210 - UNIFORM_BATUU_FIRST_ORDER_OFFICER: 'CommonGameTag' = 51205 - UNIFORM_BATUU_FIRST_ORDER_PILOT: 'CommonGameTag' = 51221 - UNIFORM_BATUU_FIRST_ORDER_STORMTROOPER: 'CommonGameTag' = 51201 - UNIFORM_BATUU_RESISTANCE_MEMBER: 'CommonGameTag' = 51202 - UNIFORM_BATUU_RESISTANCE_PILOT: 'CommonGameTag' = 51222 - UNIFORM_BATUU_SCOUNDREL_MEMBER: 'CommonGameTag' = 51209 - UNIFORM_BATUU_SERVICE_NPC: 'CommonGameTag' = 51224 - UNIFORM_BEAR_SUIT: 'CommonGameTag' = 10258 - UNIFORM_BED_UPDATES_NO_CROSS_LEGGED: 'CommonGameTag' = 2833 - UNIFORM_BEE_KEEPING_SUIT: 'CommonGameTag' = 59466 - UNIFORM_BIG_HEAD: 'CommonGameTag' = 2244 - UNIFORM_BIKE_HELMET: 'CommonGameTag' = 65618 - UNIFORM_BLACK_AND_WHITE_PARTY: 'CommonGameTag' = 682 - UNIFORM_BLACK_TURTLENECK: 'CommonGameTag' = 627 - UNIFORM_BONEHILDA: 'CommonGameTag' = 86029 - UNIFORM_BOWLING_GLOVES: 'CommonGameTag' = 38924 - UNIFORM_BOWLING_NPC: 'CommonGameTag' = 38918 - UNIFORM_BOWLING_SHOES: 'CommonGameTag' = 38923 - UNIFORM_BOWLING_TEAM_1: 'CommonGameTag' = 38914 - UNIFORM_BOWLING_TEAM_2: 'CommonGameTag' = 38915 - UNIFORM_BOWLING_TEAM_3: 'CommonGameTag' = 38916 - UNIFORM_BOWLING_TEAM_4: 'CommonGameTag' = 38917 - UNIFORM_BUSINESS_CHEAP_SUIT: 'CommonGameTag' = 1269 - UNIFORM_BUSINESS_DECENT_SUIT: 'CommonGameTag' = 1270 - UNIFORM_BUSINESS_EXPENSIVE_SUIT: 'CommonGameTag' = 1271 - UNIFORM_BUSINESS_OFFICE_WORKER: 'CommonGameTag' = 1268 - UNIFORM_BUTLER: 'CommonGameTag' = 36869 - UNIFORM_CAMERA_OPERATOR: 'CommonGameTag' = 61450 - UNIFORM_CAREER_CRIMINAL_BASE: 'CommonGameTag' = 2734 - UNIFORM_CAREER_CRIMINAL_ORACLE_BASE: 'CommonGameTag' = 2735 - UNIFORM_CAREER_ENGINEER_BASE: 'CommonGameTag' = 2736 - UNIFORM_CAREER_ENGINEER_COMPUTER: 'CommonGameTag' = 2737 - UNIFORM_CAREER_ENGINEER_MECHANICAL: 'CommonGameTag' = 2738 - UNIFORM_CAREER_ENTERTAINER_BASE: 'CommonGameTag' = 2733 - UNIFORM_CAREER_GARDENER_BOTANIST: 'CommonGameTag' = 59480 - UNIFORM_CAREER_GARDENER_FLORIST: 'CommonGameTag' = 59481 - UNIFORM_CAREER_GARDENER_MAIN: 'CommonGameTag' = 59479 - UNIFORM_CAREER_SOCIAL_MEDIA_BASE: 'CommonGameTag' = 2739 - UNIFORM_CAREER_SOCIAL_MEDIA_INTERNET: 'CommonGameTag' = 2740 - UNIFORM_CAREER_STYLE_INFLUENCER: 'CommonGameTag' = 2741 - UNIFORM_CAREER_TECH_GURU_BASE: 'CommonGameTag' = 2742 - UNIFORM_CAREER_TECH_GURU_START_UP: 'CommonGameTag' = 2743 - UNIFORM_CHEF: 'CommonGameTag' = 620 - UNIFORM_CHILDHOOD_PHASE_BEAR: 'CommonGameTag' = 43027 - UNIFORM_CIVIC_INSPECTOR: 'CommonGameTag' = 67627 - UNIFORM_CIVIL_DESIGNER_CIVIC_PLANNER: 'CommonGameTag' = 67641 - UNIFORM_CIVIL_DESIGNER_GREEN_TECHNICIAN: 'CommonGameTag' = 67640 - UNIFORM_CIVIL_DESIGNER_MAIN: 'CommonGameTag' = 67639 - UNIFORM_CLOWN: 'CommonGameTag' = 680 - UNIFORM_CONCERT_OUTFIT: 'CommonGameTag' = 618 - UNIFORM_CONSERVATIONIST_ENVIRONMENTAL_MANAGER: 'CommonGameTag' = 63523 - UNIFORM_CONSERVATIONIST_MAIN: 'CommonGameTag' = 63522 - UNIFORM_CONSERVATIONIST_MARINE_BIOLOGIST: 'CommonGameTag' = 63524 - UNIFORM_CONSPIRACIST: 'CommonGameTag' = 47130 - UNIFORM_COOK: 'CommonGameTag' = 619 - UNIFORM_CORPORATE_WORKER_EXPERT: 'CommonGameTag' = 69708 - UNIFORM_CORPORATE_WORKER_MAIN: 'CommonGameTag' = 69707 - UNIFORM_CORPORATE_WORKER_SUPERVISOR: 'CommonGameTag' = 69709 - UNIFORM_COSTUME_AAYLA_SECURA: 'CommonGameTag' = 1486 - UNIFORM_COSTUME_ALIEN_HUNTER: 'CommonGameTag' = 1700 - UNIFORM_COSTUME_ANIMAL_HOOD: 'CommonGameTag' = 2113 - UNIFORM_COSTUME_ANIMAL_HOODIE: 'CommonGameTag' = 59475 - UNIFORM_COSTUME_ASTRONAUT_ORANGE: 'CommonGameTag' = 1480 - UNIFORM_COSTUME_ASTRONAUT_WHITE: 'CommonGameTag' = 1466 - UNIFORM_COSTUME_BOBA_FETT: 'CommonGameTag' = 1475 - UNIFORM_COSTUME_CARTOON_PLUMBERS: 'CommonGameTag' = 1631 - UNIFORM_COSTUME_CHEERLEADER_GREEN: 'CommonGameTag' = 1476 - UNIFORM_COSTUME_CLOWN_PINK: 'CommonGameTag' = 1481 - UNIFORM_COSTUME_CLOWN_YELLOW: 'CommonGameTag' = 1467 - UNIFORM_COSTUME_COLORFUL_ANIMALS: 'CommonGameTag' = 1632 - UNIFORM_COSTUME_DARTH_MAUL: 'CommonGameTag' = 1474 - UNIFORM_COSTUME_DARTH_VADER: 'CommonGameTag' = 1473 - UNIFORM_COSTUME_FAIRY: 'CommonGameTag' = 22530 - UNIFORM_COSTUME_FAIRY_BLUE: 'CommonGameTag' = 22547 - UNIFORM_COSTUME_FAIRY_GREEN: 'CommonGameTag' = 22546 - UNIFORM_COSTUME_FAIRY_PURPLE: 'CommonGameTag' = 22548 - UNIFORM_COSTUME_HOLIDAY_HELPER: 'CommonGameTag' = 59473 - UNIFORM_COSTUME_HOT_DOG_RED: 'CommonGameTag' = 1468 - UNIFORM_COSTUME_LEGIONNAIRE: 'CommonGameTag' = 22532 - UNIFORM_COSTUME_LEIA: 'CommonGameTag' = 1485 - UNIFORM_COSTUME_LLAMA: 'CommonGameTag' = 22531 - UNIFORM_COSTUME_LLAMA_GIRL_PURPLE: 'CommonGameTag' = 22549 - UNIFORM_COSTUME_LLAMA_MAN_BLACK: 'CommonGameTag' = 22544 - UNIFORM_COSTUME_LUKE_SKYWALKER: 'CommonGameTag' = 1472 - UNIFORM_COSTUME_MAID_BLACK: 'CommonGameTag' = 1483 - UNIFORM_COSTUME_MAID_BLUE: 'CommonGameTag' = 1470 - UNIFORM_COSTUME_MAILMAN_BLUE: 'CommonGameTag' = 1479 - UNIFORM_COSTUME_MASCOT_BLUE_BLACK: 'CommonGameTag' = 1469 - UNIFORM_COSTUME_MASCOT_WHITE: 'CommonGameTag' = 1482 - UNIFORM_COSTUME_MONSTER: 'CommonGameTag' = 1699 - UNIFORM_COSTUME_NINJA: 'CommonGameTag' = 22533 - UNIFORM_COSTUME_NINJA_RED: 'CommonGameTag' = 22543 - UNIFORM_COSTUME_PIRATE: 'CommonGameTag' = 22534 - UNIFORM_COSTUME_PIRATE_BROWN: 'CommonGameTag' = 22559 - UNIFORM_COSTUME_PIRATE_NAVY: 'CommonGameTag' = 22542 - UNIFORM_COSTUME_PIRATE_RED: 'CommonGameTag' = 22550 - UNIFORM_COSTUME_PIRATE_WHITE: 'CommonGameTag' = 22566 - UNIFORM_COSTUME_PIZZA_ORANGE: 'CommonGameTag' = 1471 - UNIFORM_COSTUME_PIZZA_RED: 'CommonGameTag' = 1484 - UNIFORM_COSTUME_PRINCESS: 'CommonGameTag' = 22537 - UNIFORM_COSTUME_PRINCESS_BLUE: 'CommonGameTag' = 22556 - UNIFORM_COSTUME_PRINCESS_GOLD: 'CommonGameTag' = 22557 - UNIFORM_COSTUME_PRINCESS_PINK: 'CommonGameTag' = 22558 - UNIFORM_COSTUME_PUMPKIN_BROWN: 'CommonGameTag' = 22564 - UNIFORM_COSTUME_PUMPKIN_MAN: 'CommonGameTag' = 22535 - UNIFORM_COSTUME_PUMPKIN_NAVY: 'CommonGameTag' = 22563 - UNIFORM_COSTUME_PUMPKIN_PLUM: 'CommonGameTag' = 22565 - UNIFORM_COSTUME_ROBO_HAT: 'CommonGameTag' = 2225 - UNIFORM_COSTUME_SAUSAGE_GRAY: 'CommonGameTag' = 1489 - UNIFORM_COSTUME_SCHOOL_GIRL: 'CommonGameTag' = 22538 - UNIFORM_COSTUME_SKELETON: 'CommonGameTag' = 22539 - UNIFORM_COSTUME_SKELETON_GREEN: 'CommonGameTag' = 22561 - UNIFORM_COSTUME_SKELETON_ORANGE: 'CommonGameTag' = 22562 - UNIFORM_COSTUME_SKELETON_WHITE: 'CommonGameTag' = 22560 - UNIFORM_COSTUME_SMUGGLER_BROWN: 'CommonGameTag' = 1488 - UNIFORM_COSTUME_SMUGGLER_TAN: 'CommonGameTag' = 1477 - UNIFORM_COSTUME_SPACE_RANGER_BLACK: 'CommonGameTag' = 1487 - UNIFORM_COSTUME_SPACE_RANGER_BLUE: 'CommonGameTag' = 1478 - UNIFORM_COSTUME_SPARTAN_BROWN: 'CommonGameTag' = 22551 - UNIFORM_COSTUME_SPARTAN_GOLD: 'CommonGameTag' = 22545 - UNIFORM_COSTUME_TREE_FIR: 'CommonGameTag' = 59474 - UNIFORM_COSTUME_WITCH: 'CommonGameTag' = 22536 - UNIFORM_COSTUME_WITCH_BLACK: 'CommonGameTag' = 22552 - UNIFORM_COSTUME_WITCH_GREEN: 'CommonGameTag' = 22553 - UNIFORM_COSTUME_WITCH_ORANGE: 'CommonGameTag' = 22554 - UNIFORM_COSTUME_YODA: 'CommonGameTag' = 1490 - UNIFORM_COSTUME_ZOMBIE_BLUE: 'CommonGameTag' = 22555 - UNIFORM_COTTAGE_WORLD_NPC_CRITTER_TENDER: 'CommonGameTag' = 112672 - UNIFORM_COTTAGE_WORLD_NPC_GROCERY_DELIVERY: 'CommonGameTag' = 112673 - UNIFORM_COTTAGE_WORLD_NPC_GROCERY_OWNER: 'CommonGameTag' = 112674 - UNIFORM_COTTAGE_WORLD_NPC_MAYOR: 'CommonGameTag' = 112675 - UNIFORM_COTTAGE_WORLD_NPC_MAYOR_MALE: 'CommonGameTag' = 112679 - UNIFORM_COTTAGE_WORLD_NPC_PUB_OWNER: 'CommonGameTag' = 112676 - UNIFORM_COWBOY_STATUE_GOLD: 'CommonGameTag' = 55433 - UNIFORM_CRIME_BOSS: 'CommonGameTag' = 623 - UNIFORM_CRIME_LORD_HAT: 'CommonGameTag' = 622 - UNIFORM_DAY_OF_THE_DEAD_WALKBY: 'CommonGameTag' = 1568 - UNIFORM_DAY_OF_THE_DEAD_WALKBY_FEMALE: 'CommonGameTag' = 1569 - UNIFORM_DEBATE_JUDGE: 'CommonGameTag' = 65590 - UNIFORM_DELIVERIES_FOOD_DELIVERY: 'CommonGameTag' = 2598 - UNIFORM_DELIVERIES_GROCERY_DELIVERY: 'CommonGameTag' = 112654 - UNIFORM_DETECTIVE: 'CommonGameTag' = 12334 - UNIFORM_DIRECTOR: 'CommonGameTag' = 61449 - UNIFORM_DIVER: 'CommonGameTag' = 63515 - UNIFORM_DJ_HIGH: 'CommonGameTag' = 24584 - UNIFORM_DJ_LOW: 'CommonGameTag' = 24583 - UNIFORM_DOCTOR_HIGH: 'CommonGameTag' = 12340 - UNIFORM_DOCTOR_LOW: 'CommonGameTag' = 12339 - UNIFORM_DRAMA_CLUB: 'CommonGameTag' = 61639 - UNIFORM_ECO_INSPECTOR: 'CommonGameTag' = 67626 - UNIFORM_EDUCATION: 'CommonGameTag' = 65552 - UNIFORM_EDUCATION_ADMIN: 'CommonGameTag' = 65553 - UNIFORM_EDUCATION_PROFESSOR: 'CommonGameTag' = 65554 - UNIFORM_ELBOW_PATCH_JACKET: 'CommonGameTag' = 625 - UNIFORM_EP01_ALIEN: 'CommonGameTag' = 12385 - UNIFORM_EP01_DOCTOR_MID: 'CommonGameTag' = 12357 - UNIFORM_EP01_POLICE_CHIEF: 'CommonGameTag' = 12426 - UNIFORM_EP01_RETAIL_EMPLOYEE: 'CommonGameTag' = 12412 - UNIFORM_EP01_SCIENTIST_ALIEN_HUNTER: 'CommonGameTag' = 12381 - UNIFORM_EP01_SCIENTIST_HIGH: 'CommonGameTag' = 12349 - UNIFORM_EP01_SCIENTIST_LOW: 'CommonGameTag' = 12350 - UNIFORM_EP01_SCIENTIST_MID: 'CommonGameTag' = 12359 - UNIFORM_EP01_SCIENTIST_VERY_HIGH: 'CommonGameTag' = 12399 - UNIFORM_EP01_SUSPECT_BLACK_HAIR: 'CommonGameTag' = 12401 - UNIFORM_EP01_SUSPECT_BLONDE_HAIR: 'CommonGameTag' = 12367 - UNIFORM_EP01_SUSPECT_BOTTOM_PANTS: 'CommonGameTag' = 12408 - UNIFORM_EP01_SUSPECT_BOTTOM_SHORTS: 'CommonGameTag' = 12411 - UNIFORM_EP01_SUSPECT_BOTTOM_SKIRT: 'CommonGameTag' = 12409 - UNIFORM_EP01_SUSPECT_BOTTOM_SLACKS: 'CommonGameTag' = 12410 - UNIFORM_EP01_SUSPECT_BROWN_HAIR: 'CommonGameTag' = 12402 - UNIFORM_EP01_SUSPECT_GREY_HAIR: 'CommonGameTag' = 12432 - UNIFORM_EP01_SUSPECT_RED_HAIR: 'CommonGameTag' = 12366 - UNIFORM_EP01_SUSPECT_TOP_BLOUSE: 'CommonGameTag' = 12406 - UNIFORM_EP01_SUSPECT_TOP_JACKET: 'CommonGameTag' = 12404 - UNIFORM_EP01_SUSPECT_TOP_LONG_SLEEVE: 'CommonGameTag' = 12405 - UNIFORM_EP01_SUSPECT_TOP_SHORT_SLEEVE: 'CommonGameTag' = 12403 - UNIFORM_EP01_SUSPECT_TOP_TANK: 'CommonGameTag' = 12407 - UNIFORM_EP07_VENDOR: 'CommonGameTag' = 63525 - UNIFORM_EP14_HORSE_TRAINER: 'CommonGameTag' = 118886 - UNIFORM_ESPORTS_PLAYER_ARTS: 'CommonGameTag' = 65601 - UNIFORM_ESPORTS_PLAYER_SCIENCE: 'CommonGameTag' = 65602 - UNIFORM_FAIRY: 'CommonGameTag' = 8209 - UNIFORM_FAST_FOOD: 'CommonGameTag' = 883 - UNIFORM_FATHER_WINTER: 'CommonGameTag' = 2071 - UNIFORM_FATHER_WINTER_SUMMER: 'CommonGameTag' = 2086 - UNIFORM_FESTIVAL_BLOSSOM_SHIRT: 'CommonGameTag' = 55350 - UNIFORM_FESTIVAL_FOOD_CURRY_CONTEST_SHIRT: 'CommonGameTag' = 55397 - UNIFORM_FESTIVAL_FOOD_SHIRT: 'CommonGameTag' = 55351 - UNIFORM_FESTIVAL_LAMP_SHIRT: 'CommonGameTag' = 55352 - UNIFORM_FESTIVAL_LLAMA_BLUE: 'CommonGameTag' = 55421 - UNIFORM_FESTIVAL_LLAMA_GOLD: 'CommonGameTag' = 55423 - UNIFORM_FESTIVAL_LLAMA_SILVER: 'CommonGameTag' = 55424 - UNIFORM_FESTIVAL_LLAMA_YELLOW: 'CommonGameTag' = 55422 - UNIFORM_FESTIVAL_LOGIC_SHIRT: 'CommonGameTag' = 55353 - UNIFORM_FESTIVAL_MUSIC_SHIRT: 'CommonGameTag' = 2563 - UNIFORM_FESTIVAL_VILLAGE_FAIR_ATTENDEE: 'CommonGameTag' = 112666 - UNIFORM_FESTIVE_SPIRIT: 'CommonGameTag' = 2089 - UNIFORM_FIREFIGHTER: 'CommonGameTag' = 2426 - UNIFORM_FLOWER_BUNNY: 'CommonGameTag' = 59458 - UNIFORM_FOOD_CRITIC_RESTAURANT_CASUAL: 'CommonGameTag' = 55396 - UNIFORM_FOREST_RANGER: 'CommonGameTag' = 10266 - UNIFORM_FORTUNE_TELLER: 'CommonGameTag' = 8198 - UNIFORM_FRANKENSTEIN: 'CommonGameTag' = 8201 - UNIFORM_GAMESCOM_CLOSET_FAIL: 'CommonGameTag' = 24579 - UNIFORM_GAMESCOM_CLOSET_SUCCEED: 'CommonGameTag' = 24580 - UNIFORM_GP01_CF_TANK_LACE: 'CommonGameTag' = 10291 - UNIFORM_GP01_CU_POCKET_ZIP: 'CommonGameTag' = 10288 - UNIFORM_GP01_CU_TEE_LONG_SHIRT_PANTS: 'CommonGameTag' = 10290 - UNIFORM_GP01_CU_TEE_LONG_SHIRT_SHORTS: 'CommonGameTag' = 10287 - UNIFORM_GP01_CU_VEST_DOWN: 'CommonGameTag' = 10289 - UNIFORM_GP01_WALKBYS_1: 'CommonGameTag' = 10292 - UNIFORM_GP01_WALKBYS_2: 'CommonGameTag' = 10293 - UNIFORM_GP01_WALKBYS_3: 'CommonGameTag' = 10294 - UNIFORM_GP01_WALKBYS_4: 'CommonGameTag' = 10295 - UNIFORM_GP01_WALKBYS_5: 'CommonGameTag' = 10296 - UNIFORM_GP01_WALKBYS_6: 'CommonGameTag' = 10297 - UNIFORM_GP01_YF_JACKET_FLEECE: 'CommonGameTag' = 10279 - UNIFORM_GP01_YF_LAYERS: 'CommonGameTag' = 10276 - UNIFORM_GP01_YF_LAYERS_HAT: 'CommonGameTag' = 10277 - UNIFORM_GP01_YF_TEE_TIED: 'CommonGameTag' = 10281 - UNIFORM_GP01_YF_VEST_FLANNEL: 'CommonGameTag' = 10278 - UNIFORM_GP01_YF_VEST_TEE: 'CommonGameTag' = 10280 - UNIFORM_GP01_YM_FINGER_SHIRT: 'CommonGameTag' = 10285 - UNIFORM_GP01_YM_TANK: 'CommonGameTag' = 10283 - UNIFORM_GP01_YM_THICK_LAYERS: 'CommonGameTag' = 10284 - UNIFORM_GP01_YM_VEST_CARABINER: 'CommonGameTag' = 10282 - UNIFORM_GP01_YM_VEST_FLEECE: 'CommonGameTag' = 10286 - UNIFORM_GRIM_REAPER: 'CommonGameTag' = 316 - UNIFORM_GRIM_REAPER_HELPER: 'CommonGameTag' = 366 - UNIFORM_HACKER: 'CommonGameTag' = 624 - UNIFORM_HAIR_MAKEUP_CHAIR_STYLIST: 'CommonGameTag' = 61453 - UNIFORM_HAZMAT_SUIT: 'CommonGameTag' = 47127 - UNIFORM_HAZMAT_SUIT_WITH_FILTER: 'CommonGameTag' = 47128 - UNIFORM_HERMIT: 'CommonGameTag' = 10257 - UNIFORM_HIGH_SCHOOL_ACTIVE_PRINCIPAL: 'CommonGameTag' = 114750 - UNIFORM_HIGH_SCHOOL_ACTIVE_TEACHER: 'CommonGameTag' = 114751 - UNIFORM_HIGH_SCHOOL_FESTIVAL_CHEER_REWARD: 'CommonGameTag' = 114713 - UNIFORM_HIGH_SCHOOL_FESTIVAL_CHESS_REWARD: 'CommonGameTag' = 114714 - UNIFORM_HIGH_SCHOOL_FESTIVAL_COMPUTER_REWARD: 'CommonGameTag' = 114715 - UNIFORM_HIGH_SCHOOL_FESTIVAL_FOOTBALL_REWARD: 'CommonGameTag' = 114712 - UNIFORM_HIGH_SCHOOL_GRADUATION: 'CommonGameTag' = 114721 - UNIFORM_HIGH_SCHOOL_TEAM_CHEER_TEAM: 'CommonGameTag' = 114694 - UNIFORM_HIGH_SCHOOL_TEAM_CHESS_TEAM: 'CommonGameTag' = 114696 - UNIFORM_HIGH_SCHOOL_TEAM_COMPUTER_TEAM: 'CommonGameTag' = 114697 - UNIFORM_HIGH_SCHOOL_TEAM_FOOTBALL_TEAM: 'CommonGameTag' = 114695 - UNIFORM_HIGH_SCHOOL_TEAM_SUPPORT_CHEER: 'CommonGameTag' = 114745 - UNIFORM_HIGH_SCHOOL_TEAM_SUPPORT_CHESS: 'CommonGameTag' = 114746 - UNIFORM_HIGH_SCHOOL_TEAM_SUPPORT_COMPUTER: 'CommonGameTag' = 114747 - UNIFORM_HIGH_SCHOOL_TEAM_SUPPORT_FOOTBALL: 'CommonGameTag' = 114748 - UNIFORM_HIRED_NANNY: 'CommonGameTag' = 1549 - UNIFORM_HORSE_CHILD_SADDLE: 'CommonGameTag' = 118874 - UNIFORM_HOT_DOG: 'CommonGameTag' = 681 - UNIFORM_INVESTIGATIVE_JOURNALIST: 'CommonGameTag' = 626 - UNIFORM_ISLAND_ELEMENTAL: 'CommonGameTag' = 63516 - UNIFORM_ISLAND_LOCAL: 'CommonGameTag' = 63513 - UNIFORM_ISLAND_LOCAL_FLOWER_MUSIC: 'CommonGameTag' = 63514 - UNIFORM_JAPANESE_TRADITIONAL: 'CommonGameTag' = 69694 - UNIFORM_JUNGLE_VENDOR1: 'CommonGameTag' = 45102 - UNIFORM_JUNGLE_VENDOR2: 'CommonGameTag' = 45103 - UNIFORM_JUNGLE_VENDOR3: 'CommonGameTag' = 45104 - UNIFORM_KIDS_BIKE_HELMET: 'CommonGameTag' = 2947 - UNIFORM_KNIGHT_SUIT: 'CommonGameTag' = 24610 - UNIFORM_LAW_CAREER_JUDGE: 'CommonGameTag' = 65628 - UNIFORM_LAW_CAREER_MAIN: 'CommonGameTag' = 65627 - UNIFORM_LAW_CAREER_MAIN_HIGH: 'CommonGameTag' = 65630 - UNIFORM_LAW_CAREER_PRIVATE_ATTORNEY: 'CommonGameTag' = 65629 - UNIFORM_LIBRARIAN_WOLF_TOWN: 'CommonGameTag' = 2790 - UNIFORM_LIFEGUARD: 'CommonGameTag' = 63502 - UNIFORM_LOVE_GURU: 'CommonGameTag' = 55358 - UNIFORM_MAID: 'CommonGameTag' = 262 - UNIFORM_MAID_DEPRECATED: 'CommonGameTag' = 636 - UNIFORM_MAILMAN: 'CommonGameTag' = 341 - UNIFORM_MAINTENANCE_WORKER: 'CommonGameTag' = 613 - UNIFORM_MANUAL_LABOR: 'CommonGameTag' = 885 - UNIFORM_MASCOT_ALT_ARTS: 'CommonGameTag' = 65588 - UNIFORM_MASCOT_ALT_SCIENCE: 'CommonGameTag' = 65589 - UNIFORM_MASCOT_ARTS: 'CommonGameTag' = 65586 - UNIFORM_MASCOT_SCIENCE: 'CommonGameTag' = 65587 - UNIFORM_MASSAGE_THERAPIST: 'CommonGameTag' = 18446 - UNIFORM_MASSAGE_TOWEL: 'CommonGameTag' = 18450 - UNIFORM_MASTER_FISHERMAN: 'CommonGameTag' = 867 - UNIFORM_MASTER_GARDENER: 'CommonGameTag' = 868 - UNIFORM_MILITARY_COVERT_HEADSET: 'CommonGameTag' = 47123 - UNIFORM_MILITARY_COVERT_SUIT: 'CommonGameTag' = 47121 - UNIFORM_MILITARY_COVERT_SUNGLASSES: 'CommonGameTag' = 47122 - UNIFORM_MILITARY_MAIN_LEVEL_01: 'CommonGameTag' = 47111 - UNIFORM_MILITARY_MAIN_LEVEL_02: 'CommonGameTag' = 47112 - UNIFORM_MILITARY_MAIN_LEVEL_03: 'CommonGameTag' = 47113 - UNIFORM_MILITARY_MAIN_LEVEL_04: 'CommonGameTag' = 47114 - UNIFORM_MILITARY_MAIN_LEVEL_05: 'CommonGameTag' = 47115 - UNIFORM_MILITARY_OFFICER_LEVEL_01: 'CommonGameTag' = 47116 - UNIFORM_MILITARY_OFFICER_LEVEL_02: 'CommonGameTag' = 47117 - UNIFORM_MILITARY_OFFICER_LEVEL_03: 'CommonGameTag' = 47118 - UNIFORM_MILITARY_OFFICER_LEVEL_04: 'CommonGameTag' = 47119 - UNIFORM_MILITARY_OFFICER_LEVEL_05: 'CommonGameTag' = 47120 - UNIFORM_MUSIC_FESTIVAL_SHIRT_BEBE: 'CommonGameTag' = 2566 - UNIFORM_MUSIC_FESTIVAL_SHIRT_DAVE: 'CommonGameTag' = 2569 - UNIFORM_MUSIC_FESTIVAL_SHIRT_JOY: 'CommonGameTag' = 2568 - UNIFORM_MUSIC_FESTIVAL_SHIRT_SIM_SESSIONS: 'CommonGameTag' = 2565 - UNIFORM_MUSIC_FESTIVAL_SHIRT_SOM: 'CommonGameTag' = 2567 - UNIFORM_NINJA: 'CommonGameTag' = 8205 - UNIFORM_OFFICE_WORKER: 'CommonGameTag' = 607 - UNIFORM_ONSEN_VENUE_EMPLOYEE: 'CommonGameTag' = 69664 - UNIFORM_ORACLE: 'CommonGameTag' = 659 - UNIFORM_ORGANIZATION_ART_SOCIETY_MEMBER: 'CommonGameTag' = 65617 - UNIFORM_ORGANIZATION_ART_SOCIETY_MODEL: 'CommonGameTag' = 65616 - UNIFORM_ORGANIZATION_DEBATE: 'CommonGameTag' = 65635 - UNIFORM_ORGANIZATION_DEBATE_JUDGE: 'CommonGameTag' = 65642 - UNIFORM_ORGANIZATION_DEBATE_SHOWDOWN: 'CommonGameTag' = 65643 - UNIFORM_ORGANIZATION_DEBATE_SHOWDOWN_FOXBURY: 'CommonGameTag' = 65654 - UNIFORM_ORGANIZATION_HONOR: 'CommonGameTag' = 65636 - UNIFORM_ORGANIZATION_PARTY: 'CommonGameTag' = 65637 - UNIFORM_ORGANIZATION_PRANK: 'CommonGameTag' = 65638 - UNIFORM_ORGANIZATION_ROBOTICS: 'CommonGameTag' = 65634 - UNIFORM_PAINTER: 'CommonGameTag' = 629 - UNIFORM_PAPARAZZI: 'CommonGameTag' = 61606 - UNIFORM_PARTS_BRIDE: 'CommonGameTag' = 631 - UNIFORM_PARTS_GROOM: 'CommonGameTag' = 630 - UNIFORM_PARTS_LIBRARIAN: 'CommonGameTag' = 633 - UNIFORM_PARTS_OFFICE_WORKER: 'CommonGameTag' = 634 - UNIFORM_PARTS_PARK_SLEEPER: 'CommonGameTag' = 635 - UNIFORM_PARTY_PARTY_HATS: 'CommonGameTag' = 632 - UNIFORM_PART_TIME_FISHERMAN: 'CommonGameTag' = 63520 - UNIFORM_PATIENT: 'CommonGameTag' = 12338 - UNIFORM_PIRATE: 'CommonGameTag' = 8203 - UNIFORM_PIZZA_DELIVERY: 'CommonGameTag' = 637 - UNIFORM_POLICE_OFFICER: 'CommonGameTag' = 12335 - UNIFORM_POLITICIAN_HIGH_LEVEL: 'CommonGameTag' = 55418 - UNIFORM_POLITICIAN_LOW_LEVEL: 'CommonGameTag' = 55420 - UNIFORM_POLITICIAN_MEDIUM_LEVEL: 'CommonGameTag' = 55419 - UNIFORM_PRINCESS: 'CommonGameTag' = 8208 - UNIFORM_PRODUCER: 'CommonGameTag' = 61628 - UNIFORM_PROFESSOR_NPC_GOOD: 'CommonGameTag' = 65647 - UNIFORM_PROFESSOR_NPC_GRUMPY: 'CommonGameTag' = 65646 - UNIFORM_PROFESSOR_NPC_HIP: 'CommonGameTag' = 65645 - UNIFORM_PROFESSOR_NPC_SMART: 'CommonGameTag' = 65644 - UNIFORM_PRO_GAMER: 'CommonGameTag' = 628 - UNIFORM_PUMPKIN: 'CommonGameTag' = 8206 - UNIFORM_RACCOON: 'CommonGameTag' = 55372 - UNIFORM_RANCH_HAND: 'CommonGameTag' = 118799 - UNIFORM_REFLEXOLOGIST: 'CommonGameTag' = 18460 - UNIFORM_REPAIR: 'CommonGameTag' = 1491 - UNIFORM_REPO_PERSON: 'CommonGameTag' = 65633 - UNIFORM_RESTAURANT_CRITIC: 'CommonGameTag' = 26644 - UNIFORM_RETAIL: 'CommonGameTag' = 886 - UNIFORM_ROBE: 'CommonGameTag' = 18437 - UNIFORM_ROCK_CLIMBING_GEAR_GLOVES: 'CommonGameTag' = 69743 - UNIFORM_ROCK_CLIMBING_GEAR_SHOES: 'CommonGameTag' = 69744 - UNIFORM_SCHOOL_GIRL: 'CommonGameTag' = 8207 - UNIFORM_SCOUT_BASIC: 'CommonGameTag' = 59464 - UNIFORM_SCOUT_EXPERT: 'CommonGameTag' = 59465 - UNIFORM_SECRET_SOCIETY_LEVEL_1: 'CommonGameTag' = 65566 - UNIFORM_SECRET_SOCIETY_LEVEL_2: 'CommonGameTag' = 65567 - UNIFORM_SECRET_SOCIETY_LEVEL_3: 'CommonGameTag' = 65568 - UNIFORM_SHOES_OFF_INDOORS: 'CommonGameTag' = 69703 - UNIFORM_SKATING_GENERIC: 'CommonGameTag' = 59471 - UNIFORM_SKATING_ICE: 'CommonGameTag' = 59433 - UNIFORM_SKATING_PRO: 'CommonGameTag' = 59442 - UNIFORM_SKATING_ROLLER: 'CommonGameTag' = 59434 - UNIFORM_SKELETON: 'CommonGameTag' = 8204 - UNIFORM_SKELETON_GP06: 'CommonGameTag' = 45088 - UNIFORM_SKI_BOOTS: 'CommonGameTag' = 69738 - UNIFORM_SLIPPERS_INDOORS: 'CommonGameTag' = 69702 - UNIFORM_SMUGGLER: 'CommonGameTag' = 616 - UNIFORM_SNOWBOARD_BOOTS: 'CommonGameTag' = 69739 - UNIFORM_SNOWY_VENDOR: 'CommonGameTag' = 69722 - UNIFORM_SOCCER_PLAYER_ARTS: 'CommonGameTag' = 65599 - UNIFORM_SOCCER_PLAYER_SCIENCE: 'CommonGameTag' = 65600 - UNIFORM_SPACE_RANGER: 'CommonGameTag' = 615 - UNIFORM_SPARTAN: 'CommonGameTag' = 8211 - UNIFORM_SPELLCASTER_EDGY: 'CommonGameTag' = 49177 - UNIFORM_SPELLCASTER_FAIRYTALE: 'CommonGameTag' = 49176 - UNIFORM_SPELLCASTER_SAGE: 'CommonGameTag' = 49178 - UNIFORM_SPELLCASTER_SAGE_MISCHIEF: 'CommonGameTag' = 49180 - UNIFORM_SPELLCASTER_SAGE_PRACTICAL: 'CommonGameTag' = 49179 - UNIFORM_SPELLCASTER_SAGE_UNTAMED: 'CommonGameTag' = 49181 - UNIFORM_SPELLCASTER_STREET_MODERN: 'CommonGameTag' = 49175 - UNIFORM_SPELLCASTER_VINTAGE: 'CommonGameTag' = 49174 - UNIFORM_SPORTS_FAN_ARTS: 'CommonGameTag' = 65604 - UNIFORM_SPORTS_FAN_SCIENCE: 'CommonGameTag' = 65605 - UNIFORM_STALLS_CURIO_SHOP_HAT: 'CommonGameTag' = 47109 - UNIFORM_STALLS_CURIO_SHOP_SHIRT: 'CommonGameTag' = 47110 - UNIFORM_STALLS_CURIO_SHOP_VENDOR: 'CommonGameTag' = 47108 - UNIFORM_STALLS_FOOD_FESTIVAL: 'CommonGameTag' = 55429 - UNIFORM_STALLS_GENERIC: 'CommonGameTag' = 55428 - UNIFORM_STALLS_GENERIC_MARKET_STALLS: 'CommonGameTag' = 1937 - UNIFORM_STALLS_LAMP_FESTIVAL: 'CommonGameTag' = 55430 - UNIFORM_STALLS_NERD_FESTIVAL: 'CommonGameTag' = 55432 - UNIFORM_STALLS_PET_WORLD: 'CommonGameTag' = 1986 - UNIFORM_STALLS_ROMANCE_FESTIVAL: 'CommonGameTag' = 55431 - UNIFORM_STALLS_WEDDING_FLOWER: 'CommonGameTag' = 133121 - UNIFORM_STALLS_WEDDING_PATISSERIE: 'CommonGameTag' = 133122 - UNIFORM_STRANGERVILLE_SCIENTIST: 'CommonGameTag' = 47140 - UNIFORM_SUIT: 'CommonGameTag' = 608 - UNIFORM_SUIT_LEISURE: 'CommonGameTag' = 617 - UNIFORM_SUMMIT_STUDENT: 'CommonGameTag' = 69674 - UNIFORM_SUPER_TUXEDO: 'CommonGameTag' = 610 - UNIFORM_TACTICAL_TURTLENECK: 'CommonGameTag' = 612 - UNIFORM_TEENAGER: 'CommonGameTag' = 760 - UNIFORM_TODDLER_DIAPER_ONLY: 'CommonGameTag' = 1673 - UNIFORM_TOURIST: 'CommonGameTag' = 55306 - UNIFORM_TOURIST_BASE_GAME: 'CommonGameTag' = 2166 - UNIFORM_TOWEL: 'CommonGameTag' = 1440 - UNIFORM_TRAGIC_CLOWN: 'CommonGameTag' = 1503 - UNIFORM_TURTLE_FANATIC: 'CommonGameTag' = 63521 - UNIFORM_TUXEDO: 'CommonGameTag' = 609 - UNIFORM_UNIVERSITY_GRADUATION_ARTS: 'CommonGameTag' = 65610 - UNIFORM_UNIVERSITY_GRADUATION_ARTS_NO_CAP: 'CommonGameTag' = 65611 - UNIFORM_UNIVERSITY_GRADUATION_SCIENCE: 'CommonGameTag' = 65612 - UNIFORM_UNIVERSITY_GRADUATION_SCIENCE_NO_CAP: 'CommonGameTag' = 65613 - UNIFORM_UNIVERSITY_KIOSK_BOTTOM_AH: 'CommonGameTag' = 65578 - UNIFORM_UNIVERSITY_KIOSK_BOTTOM_ST: 'CommonGameTag' = 65579 - UNIFORM_UNIVERSITY_KIOSK_HAT_AH: 'CommonGameTag' = 65580 - UNIFORM_UNIVERSITY_KIOSK_HAT_ST: 'CommonGameTag' = 65581 - UNIFORM_UNIVERSITY_KIOSK_TOP_AH: 'CommonGameTag' = 65576 - UNIFORM_UNIVERSITY_KIOSK_TOP_ST: 'CommonGameTag' = 65577 - UNIFORM_UNIVERSITY_STUDENT: 'CommonGameTag' = 65555 - UNIFORM_UNIVERSITY_STUDENT_ARTS: 'CommonGameTag' = 65584 - UNIFORM_UNIVERSITY_STUDENT_SCIENCE: 'CommonGameTag' = 65585 - UNIFORM_VENDING_MACHINE_PAPER_HAT: 'CommonGameTag' = 69681 - UNIFORM_VENDING_MACHINE_SNOW_OUTFIT: 'CommonGameTag' = 69682 - UNIFORM_VENDING_MACHINE_YUKATA: 'CommonGameTag' = 69680 - UNIFORM_VET: 'CommonGameTag' = 57398 - UNIFORM_VFX_MACHINE_OPERATOR: 'CommonGameTag' = 61629 - UNIFORM_VILLAIN: 'CommonGameTag' = 611 - UNIFORM_VIP_ROPE_BOUNCER: 'CommonGameTag' = 61478 - UNIFORM_WARDROBE_PEDESTAL_STYLIST: 'CommonGameTag' = 61466 - UNIFORM_WASTE_MANAGER: 'CommonGameTag' = 67642 - UNIFORM_WEIRDO: 'CommonGameTag' = 55307 - UNIFORM_WINDENBURG_BARISTA: 'CommonGameTag' = 24603 - UNIFORM_WITCH: 'CommonGameTag' = 8202 - UNIFORM_YOGA_INSTRUCTOR: 'CommonGameTag' = 18445 - VENUE_OBJECT_BENCH: 'CommonGameTag' = 598 - VENUE_OBJECT_CHAIR: 'CommonGameTag' = 961 - VENUE_OBJECT_EXERCISE: 'CommonGameTag' = 601 - VENUE_OBJECT_LOCKER: 'CommonGameTag' = 1443 - VENUE_OBJECT_MICROPHONE: 'CommonGameTag' = 597 - VENUE_OBJECT_MONKEY_BARS: 'CommonGameTag' = 599 - VENUE_OBJECT_ONSEN_LOCKER: 'CommonGameTag' = 69661 - VENUE_OBJECT_PAINTING: 'CommonGameTag' = 595 - VENUE_OBJECT_PATIO_TABLE: 'CommonGameTag' = 602 - VENUE_OBJECT_PLAYGROUND: 'CommonGameTag' = 600 - VENUE_OBJECT_RELAXATION: 'CommonGameTag' = 18443 - VENUE_OBJECT_SCULPTURE: 'CommonGameTag' = 596 - WALL_PATTERN_MASONRY: 'CommonGameTag' = 412 - WALL_PATTERN_MISC: 'CommonGameTag' = 415 - WALL_PATTERN_PAINT: 'CommonGameTag' = 408 - WALL_PATTERN_PANELING: 'CommonGameTag' = 411 - WALL_PATTERN_ROCK_AND_STONE: 'CommonGameTag' = 413 - WALL_PATTERN_SIDING: 'CommonGameTag' = 414 - WALL_PATTERN_TILE: 'CommonGameTag' = 410 - WALL_PATTERN_WALLPAPER: 'CommonGameTag' = 409 - WORLD_LOG_NOT_INTERACTIVE: 'CommonGameTag' = 1985 diff --git a/Scripts/s4ap/sims4communitylib/enums/traits_enum.py b/Scripts/s4ap/sims4communitylib/enums/traits_enum.py deleted file mode 100644 index 79acb97..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/traits_enum.py +++ /dev/null @@ -1,2715 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -# noinspection SpellCheckingInspection -class CommonTraitId(CommonInt): - """Identifiers for vanilla sim traits. - - """ - INVALID: 'CommonTraitId' = 0 - # S4CL - S4CL_MAIN_TRAIT: 'CommonTraitId' = 11620901522964063678 - S4CL_MAIN_TRAIT_HUMAN: 'CommonTraitId' = 14622983050963926956 - S4CL_MAIN_TRAIT_LARGE_DOG: 'CommonTraitId' = 16449767532803985357 - S4CL_MAIN_TRAIT_SMALL_DOG: 'CommonTraitId' = 5284118362600111737 - S4CL_MAIN_TRAIT_CAT: 'CommonTraitId' = 4108675957767251387 - S4CL_MAIN_TRAIT_FOX: 'CommonTraitId' = 0x38F9F903CFDDA804 - S4CL_MAIN_TRAIT_HORSE: 'CommonTraitId' = 0xAB4F5D9C641CB480 - S4CL_GENDER_OPTIONS_TOILET_UNKNOWN: 'CommonTraitId' = 0xCDD5658C08ED76D1 - S4CL_GENDER_OPTIONS_TOILET_STANDING_LARGE_DOG: 'CommonTraitId' = 0x596114D020EC43FA - S4CL_GENDER_OPTIONS_TOILET_SITTING_LARGE_DOG: 'CommonTraitId' = 0x1CE27237D2E3CA18 - S4CL_GENDER_OPTIONS_TOILET_STANDING_SMALL_DOG: 'CommonTraitId' = 0x65563037218958A2 - S4CL_GENDER_OPTIONS_TOILET_SITTING_SMALL_DOG: 'CommonTraitId' = 0x0B510ED610177874 - S4CL_GENDER_OPTIONS_TOILET_STANDING_CAT: 'CommonTraitId' = 0x044F7270266F8418 - S4CL_GENDER_OPTIONS_TOILET_SITTING_CAT: 'CommonTraitId' = 0xDB01DDB64FBD9B1E - S4CL_GENDER_OPTIONS_TOILET_STANDING_FOX: 'CommonTraitId' = 0x043E787026611B13 - S4CL_GENDER_OPTIONS_TOILET_SITTING_FOX: 'CommonTraitId' = 0xDAF0EFB64FAF46B5 - S4CL_GENDER_OPTIONS_TOILET_STANDING_HORSE: 'CommonTraitId' = 0x68AE8C13E8E70F1B - S4CL_GENDER_OPTIONS_TOILET_SITTING_HORSE: 'CommonTraitId' = 0xFE5E27AB9E824119 - - S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_LARGE_DOG: 'CommonTraitId' = 0x4F78FA2C6D704D37 - S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_LARGE_DOG: 'CommonTraitId' = 0x297A1DAA08640410 - S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_SMALL_DOG: 'CommonTraitId' = 0x4FA275D67AD6D9BF - S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_SMALL_DOG: 'CommonTraitId' = 0x5FE2BF1B88452A0C - S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_CAT: 'CommonTraitId' = 0x9CBE8604CD20F86D - S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_CAT: 'CommonTraitId' = 0xECCA44C52A8A9586 - S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_FOX: 'CommonTraitId' = 0x9CB49004CD18B4EA - S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_FOX: 'CommonTraitId' = 0xECB946C52A7C265D - S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_HORSE: 'CommonTraitId' = 0xAB4B78269AB15E72 - S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_HORSE: 'CommonTraitId' = 0xA6B30A268329CB01 - - S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_LARGE_DOG: 'CommonTraitId' = 0xF49A4DA8F37E4700 - S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_LARGE_DOG: 'CommonTraitId' = 0x66DBBBCC31E8E9B5 - S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_SMALL_DOG: 'CommonTraitId' = 0x408C1088D2971E7C - S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_SMALL_DOG: 'CommonTraitId' = 0xBF34158EBC37DAA1 - S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_CAT: 'CommonTraitId' = 0x085EA775A40A2216 - S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_CAT: 'CommonTraitId' = 0xAFF7AF13EBFD7673 - S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_FOX: 'CommonTraitId' = 0x084DA975A3FBB2ED - S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_FOX: 'CommonTraitId' = 0xAFED8513EBF4DA5C - S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_HORSE: 'CommonTraitId' = 0x8B87472A135AB931 - S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_HORSE: 'CommonTraitId' = 0xAE2C5DC67BD07418 - - # Obsolete backwards compatible traits (These are traits that EA removed) - ACTOR_CAREER_HIDDEN_AUDITION_AWAITING_AUDITION: 'CommonTraitId' = 198564 # Apparently EA deleted this trait. - ACTOR_CAREER_HIDDEN_CHECKPOINTS_AUDITION_SUCCESS_COMMERCIAL: 'CommonTraitId' = 198583 # Apparently EA deleted this trait. - ACTOR_CAREER_HIDDEN_CHECKPOINTS_AUDITION_SUCCESS_FILM: 'CommonTraitId' = 198584 # Apparently EA deleted this trait. - ACTOR_CAREER_HIDDEN_CHECKPOINTS_AUDITION_SUCCESS_HIGH_BUDGET_TV: 'CommonTraitId' = 198581 # Apparently EA deleted this trait. - ACTOR_CAREER_HIDDEN_CHECKPOINTS_AUDITION_SUCCESS_LOW_BUDGET_TV: 'CommonTraitId' = 198582 # Apparently EA deleted this trait. - PET_INSIDE_OUTSIDE: 'CommonTraitId' = 158719 # Apparently EA deleted this trait. - ACCEPTED_TO_UNIVERSITY: 'CommonTraitId' = 219693 - ACTIVE: 'CommonTraitId' = 27419 - ACTOR_CAREER_HIDDEN_CHECKPOINTS_NEW_TO_ACTOR_CAREER: 'CommonTraitId' = 198763 - ADOPT_TIGER_COMMODITY_HIDDEN: 'CommonTraitId' = 357832 - ADOPT_TIGER_HIDDEN: 'CommonTraitId' = 353574 - ADULT: 'CommonTraitId' = 34319 - ADVENTUROUS: 'CommonTraitId' = 252085 - ALLURING: 'CommonTraitId' = 26200 - ALWAYS_WELCOME: 'CommonTraitId' = 35504 - AMBITIOUS: 'CommonTraitId' = 16823 - ANGLERS_TRANQUILITY: 'CommonTraitId' = 26390 - ANIMAL_ATTRACTION: 'CommonTraitId' = 171824 - ANIMAL_CLOTHING_FOX_GRANDMA_1: 'CommonTraitId' = 268721 - ANIMAL_CLOTHING_FOX_GRANDMA_2: 'CommonTraitId' = 270028 - ANIMAL_CLOTHING_FOX_GRANDMA_3: 'CommonTraitId' = 270029 - ANIMAL_CLOTHING_FOX_GRANDMA_4: 'CommonTraitId' = 270030 - ANIMAL_CLOTHING_FOX_GRANDMA_5: 'CommonTraitId' = 270027 - ANIMAL_CLOTHING_FOX_GRANDMA_6: 'CommonTraitId' = 270026 - ANIMAL_CLOTHING_FOX_ROBBER_1: 'CommonTraitId' = 268722 - ANIMAL_CLOTHING_FOX_ROBBER_2: 'CommonTraitId' = 270033 - ANIMAL_CLOTHING_FOX_ROBBER_3: 'CommonTraitId' = 270034 - ANIMAL_CLOTHING_FOX_ROBBER_4: 'CommonTraitId' = 270035 - ANIMAL_CLOTHING_FOX_ROBBER_5: 'CommonTraitId' = 270036 - ANIMAL_CLOTHING_FOX_ROBBER_6: 'CommonTraitId' = 270031 - ANIMAL_CLOTHING_FOX_ROBBER_7: 'CommonTraitId' = 270032 - ANIMAL_CLOTHING_FOX_ROBIN_HOOD_1: 'CommonTraitId' = 268727 - ANIMAL_CLOTHING_FOX_ROBIN_HOOD_2: 'CommonTraitId' = 270039 - ANIMAL_CLOTHING_FOX_ROBIN_HOOD_3: 'CommonTraitId' = 270040 - ANIMAL_CLOTHING_FOX_ROBIN_HOOD_4: 'CommonTraitId' = 270041 - ANIMAL_CLOTHING_FOX_ROBIN_HOOD_5: 'CommonTraitId' = 270038 - ANIMAL_CLOTHING_FOX_ROBIN_HOOD_6: 'CommonTraitId' = 270037 - ANIMAL_ENTHUSIAST: 'CommonTraitId' = 257365 - ANIMAL_WHISPERER: 'CommonTraitId' = 171817 - ANTISEPTIC: 'CommonTraitId' = 26388 - APPRAISER: 'CommonTraitId' = 76821 - ARCHAEOLOGY_SCHOLAR_MUSEUM_PATRON: 'CommonTraitId' = 179023 - ARCHAEOLOGY_SKILL_GIVE_AUTHENTICATION_MAIL_PROHIBIT: 'CommonTraitId' = 176123 - ART_LOVER: 'CommonTraitId' = 27918 - ATTRACTION_ACTIVITIES_BROKE_TURN_OFF: 'CommonTraitId' = 365709 - ATTRACTION_ACTIVITIES_BROKE_TURN_ON: 'CommonTraitId' = 365708 - ATTRACTION_ACTIVITIES_CAREER_MINDED_TURN_OFF: 'CommonTraitId' = 365711 - ATTRACTION_ACTIVITIES_CAREER_MINDED_TURN_ON: 'CommonTraitId' = 365710 - ATTRACTION_ACTIVITIES_HIGHLY_SKILLED_TURN_OFF: 'CommonTraitId' = 365735 - ATTRACTION_ACTIVITIES_HIGHLY_SKILLED_TURN_ON: 'CommonTraitId' = 365734 - ATTRACTION_ACTIVITIES_SELF_EMPLOYED_TURN_OFF: 'CommonTraitId' = 365741 - ATTRACTION_ACTIVITIES_SELF_EMPLOYED_TURN_ON: 'CommonTraitId' = 365740 - ATTRACTION_ACTIVITIES_SLACKER_TURN_OFF: 'CommonTraitId' = 365743 - ATTRACTION_ACTIVITIES_SLACKER_TURN_ON: 'CommonTraitId' = 365742 - ATTRACTION_ACTIVITIES_TAKEN_TURN_OFF: 'CommonTraitId' = 365745 - ATTRACTION_ACTIVITIES_TAKEN_TURN_ON: 'CommonTraitId' = 365744 - ATTRACTION_ACTIVITIES_WEALTHY_TURN_OFF: 'CommonTraitId' = 365747 - ATTRACTION_ACTIVITIES_WEALTHY_TURN_ON: 'CommonTraitId' = 365746 - ATTRACTION_CHANGE_ATTRACTION_SETTINGS_TURN_OFF: 'CommonTraitId' = 373234 - ATTRACTION_CHARACTERISTICS_AMBITIONLESS_TURN_OFF: 'CommonTraitId' = 363398 - ATTRACTION_CHARACTERISTICS_AMBITIONLESS_TURN_ON: 'CommonTraitId' = 363397 - ATTRACTION_CHARACTERISTICS_AMBITIOUS_TURN_OFF: 'CommonTraitId' = 363922 - ATTRACTION_CHARACTERISTICS_AMBITIOUS_TURN_ON: 'CommonTraitId' = 363923 - ATTRACTION_CHARACTERISTICS_ARGUMENTATIVE_TURN_OFF: 'CommonTraitId' = 363924 - ATTRACTION_CHARACTERISTICS_ARGUMENTATIVE_TURN_ON: 'CommonTraitId' = 363925 - ATTRACTION_CHARACTERISTICS_CEREBRAL_TURN_OFF: 'CommonTraitId' = 363926 - ATTRACTION_CHARACTERISTICS_CEREBRAL_TURN_ON: 'CommonTraitId' = 363927 - ATTRACTION_CHARACTERISTICS_CLEAN_TURN_OFF: 'CommonTraitId' = 363928 - ATTRACTION_CHARACTERISTICS_CLEAN_TURN_ON: 'CommonTraitId' = 363929 - ATTRACTION_CHARACTERISTICS_EGOTISTICAL_TURN_OFF: 'CommonTraitId' = 363930 - ATTRACTION_CHARACTERISTICS_EGOTISTICAL_TURN_ON: 'CommonTraitId' = 363931 - ATTRACTION_CHARACTERISTICS_EMOTIONAL_DECISION_MAKERS_TURN_OFF: 'CommonTraitId' = 363932 - ATTRACTION_CHARACTERISTICS_EMOTIONAL_DECISION_MAKERS_TURN_ON: 'CommonTraitId' = 363933 - ATTRACTION_CHARACTERISTICS_FAMILY_MOTIVATED_TURN_OFF: 'CommonTraitId' = 363934 - ATTRACTION_CHARACTERISTICS_FAMILY_MOTIVATED_TURN_ON: 'CommonTraitId' = 363935 - ATTRACTION_CHARACTERISTICS_FUNNY_TURN_OFF: 'CommonTraitId' = 363936 - ATTRACTION_CHARACTERISTICS_FUNNY_TURN_ON: 'CommonTraitId' = 363937 - ATTRACTION_CHARACTERISTICS_HARD_WORKING_TURN_OFF: 'CommonTraitId' = 363938 - ATTRACTION_CHARACTERISTICS_HARD_WORKING_TURN_ON: 'CommonTraitId' = 363939 - ATTRACTION_CHARACTERISTICS_HIGH_ENERGY_TURN_OFF: 'CommonTraitId' = 363940 - ATTRACTION_CHARACTERISTICS_HIGH_ENERGY_TURN_ON: 'CommonTraitId' = 363941 - ATTRACTION_CHARACTERISTICS_HOME_BODY_TURN_OFF: 'CommonTraitId' = 363942 - ATTRACTION_CHARACTERISTICS_HOME_BODY_TURN_ON: 'CommonTraitId' = 363943 - ATTRACTION_CHARACTERISTICS_IDEALIST_TURN_OFF: 'CommonTraitId' = 363944 - ATTRACTION_CHARACTERISTICS_IDEALIST_TURN_ON: 'CommonTraitId' = 363945 - ATTRACTION_CHARACTERISTICS_MESSY_TURN_OFF: 'CommonTraitId' = 363946 - ATTRACTION_CHARACTERISTICS_MESSY_TURN_ON: 'CommonTraitId' = 363947 - ATTRACTION_CHARACTERISTICS_NATURE_ENTHUSIAST_TURN_OFF: 'CommonTraitId' = 363948 - ATTRACTION_CHARACTERISTICS_NATURE_ENTHUSIAST_TURN_ON: 'CommonTraitId' = 363949 - ATTRACTION_CHARACTERISTICS_OPTIMISTIC_TURN_OFF: 'CommonTraitId' = 363950 - ATTRACTION_CHARACTERISTICS_OPTIMISTIC_TURN_ON: 'CommonTraitId' = 363951 - ATTRACTION_CHARACTERISTICS_PESSIMISTIC_TURN_OFF: 'CommonTraitId' = 363952 - ATTRACTION_CHARACTERISTICS_PESSIMISTIC_TURN_ON: 'CommonTraitId' = 363953 - ATTRACTION_CHARACTERISTICS_PET_ENTHUSIAST_TURN_OFF: 'CommonTraitId' = 363954 - ATTRACTION_CHARACTERISTICS_PET_ENTHUSIAST_TURN_ON: 'CommonTraitId' = 363955 - ATTRACTION_CHARACTERISTICS_SPIRITED_TURN_OFF: 'CommonTraitId' = 363956 - ATTRACTION_CHARACTERISTICS_SPIRITED_TURN_ON: 'CommonTraitId' = 363957 - ATTRACTION_FASHION_BASICS_TURN_OFF: 'CommonTraitId' = 363402 - ATTRACTION_FASHION_BASICS_TURN_ON: 'CommonTraitId' = 363401 - ATTRACTION_FASHION_BOHO_TURN_OFF: 'CommonTraitId' = 364950 - ATTRACTION_FASHION_BOHO_TURN_ON: 'CommonTraitId' = 364951 - ATTRACTION_FASHION_COSTUMES_TURN_OFF: 'CommonTraitId' = 373277 - ATTRACTION_FASHION_COSTUMES_TURN_ON: 'CommonTraitId' = 373276 - ATTRACTION_FASHION_COUNTRY_TURN_OFF: 'CommonTraitId' = 364952 - ATTRACTION_FASHION_COUNTRY_TURN_ON: 'CommonTraitId' = 364953 - ATTRACTION_FASHION_HIPSTER_TURN_OFF: 'CommonTraitId' = 364955 - ATTRACTION_FASHION_HIPSTER_TURN_ON: 'CommonTraitId' = 364954 - ATTRACTION_FASHION_OUTDOORSY_TURN_OFF: 'CommonTraitId' = 364957 - ATTRACTION_FASHION_OUTDOORSY_TURN_ON: 'CommonTraitId' = 364956 - ATTRACTION_FASHION_POLISHED_TURN_OFF: 'CommonTraitId' = 364958 - ATTRACTION_FASHION_POLISHED_TURN_ON: 'CommonTraitId' = 364959 - ATTRACTION_FASHION_PREPPY_TURN_OFF: 'CommonTraitId' = 364960 - ATTRACTION_FASHION_PREPPY_TURN_ON: 'CommonTraitId' = 364961 - ATTRACTION_FASHION_ROCKER_TURN_OFF: 'CommonTraitId' = 364963 - ATTRACTION_FASHION_ROCKER_TURN_ON: 'CommonTraitId' = 364962 - ATTRACTION_FASHION_STREETWEAR_TURN_OFF: 'CommonTraitId' = 364965 - ATTRACTION_FASHION_STREETWEAR_TURN_ON: 'CommonTraitId' = 364964 - ATTRACTION_HAIR_COLOR_AUBURN_TURN_OFF: 'CommonTraitId' = 363405 - ATTRACTION_HAIR_COLOR_AUBURN_TURN_ON: 'CommonTraitId' = 363406 - ATTRACTION_HAIR_COLOR_BLACK_TURN_OFF: 'CommonTraitId' = 364993 - ATTRACTION_HAIR_COLOR_BLACK_TURN_ON: 'CommonTraitId' = 364992 - ATTRACTION_HAIR_COLOR_BLONDE_TURN_OFF: 'CommonTraitId' = 364994 - ATTRACTION_HAIR_COLOR_BLONDE_TURN_ON: 'CommonTraitId' = 364995 - ATTRACTION_HAIR_COLOR_BROWN_TURN_OFF: 'CommonTraitId' = 364998 - ATTRACTION_HAIR_COLOR_BROWN_TURN_ON: 'CommonTraitId' = 364999 - ATTRACTION_HAIR_COLOR_DARK_BLUE_TURN_OFF: 'CommonTraitId' = 364997 - ATTRACTION_HAIR_COLOR_DARK_BLUE_TURN_ON: 'CommonTraitId' = 364996 - ATTRACTION_HAIR_COLOR_GRAY_TURN_OFF: 'CommonTraitId' = 365000 - ATTRACTION_HAIR_COLOR_GRAY_TURN_ON: 'CommonTraitId' = 365001 - ATTRACTION_HAIR_COLOR_GREEN_TURN_OFF: 'CommonTraitId' = 365003 - ATTRACTION_HAIR_COLOR_GREEN_TURN_ON: 'CommonTraitId' = 365002 - ATTRACTION_HAIR_COLOR_HOT_PINK_TURN_OFF: 'CommonTraitId' = 365004 - ATTRACTION_HAIR_COLOR_HOT_PINK_TURN_ON: 'CommonTraitId' = 365005 - ATTRACTION_HAIR_COLOR_ORANGE_TURN_OFF: 'CommonTraitId' = 365007 - ATTRACTION_HAIR_COLOR_ORANGE_TURN_ON: 'CommonTraitId' = 365006 - ATTRACTION_HAIR_COLOR_PLATINUM_TURN_OFF: 'CommonTraitId' = 365009 - ATTRACTION_HAIR_COLOR_PLATINUM_TURN_ON: 'CommonTraitId' = 365008 - ATTRACTION_HAIR_COLOR_PURPLE_PASTEL_TURN_OFF: 'CommonTraitId' = 365011 - ATTRACTION_HAIR_COLOR_PURPLE_PASTEL_TURN_ON: 'CommonTraitId' = 365010 - ATTRACTION_HAIR_COLOR_RED_TURN_OFF: 'CommonTraitId' = 365013 - ATTRACTION_HAIR_COLOR_RED_TURN_ON: 'CommonTraitId' = 365012 - ATTRACTION_HAIR_COLOR_TURQUOISE_TURN_OFF: 'CommonTraitId' = 365015 - ATTRACTION_HAIR_COLOR_TURQUOISE_TURN_ON: 'CommonTraitId' = 365014 - ATTRACTION_HAIR_COLOR_WHITE_TURN_OFF: 'CommonTraitId' = 365017 - ATTRACTION_HAIR_COLOR_WHITE_TURN_ON: 'CommonTraitId' = 365016 - ATTRACTION_OUTFIT_COLOR_BLACK_TURN_OFF: 'CommonTraitId' = 363480 - ATTRACTION_OUTFIT_COLOR_BLACK_TURN_ON: 'CommonTraitId' = 363481 - ATTRACTION_OUTFIT_COLOR_BLUE_TURN_OFF: 'CommonTraitId' = 365029 - ATTRACTION_OUTFIT_COLOR_BLUE_TURN_ON: 'CommonTraitId' = 365028 - ATTRACTION_OUTFIT_COLOR_BROWN_TURN_OFF: 'CommonTraitId' = 365031 - ATTRACTION_OUTFIT_COLOR_BROWN_TURN_ON: 'CommonTraitId' = 365030 - ATTRACTION_OUTFIT_COLOR_GRAY_TURN_OFF: 'CommonTraitId' = 365033 - ATTRACTION_OUTFIT_COLOR_GRAY_TURN_ON: 'CommonTraitId' = 365032 - ATTRACTION_OUTFIT_COLOR_GREEN_TURN_OFF: 'CommonTraitId' = 365035 - ATTRACTION_OUTFIT_COLOR_GREEN_TURN_ON: 'CommonTraitId' = 365034 - ATTRACTION_OUTFIT_COLOR_ORANGE_TURN_OFF: 'CommonTraitId' = 365037 - ATTRACTION_OUTFIT_COLOR_ORANGE_TURN_ON: 'CommonTraitId' = 365036 - ATTRACTION_OUTFIT_COLOR_PINK_TURN_OFF: 'CommonTraitId' = 365039 - ATTRACTION_OUTFIT_COLOR_PINK_TURN_ON: 'CommonTraitId' = 365038 - ATTRACTION_OUTFIT_COLOR_PURPLE_TURN_OFF: 'CommonTraitId' = 365041 - ATTRACTION_OUTFIT_COLOR_PURPLE_TURN_ON: 'CommonTraitId' = 365040 - ATTRACTION_OUTFIT_COLOR_RED_TURN_OFF: 'CommonTraitId' = 365042 - ATTRACTION_OUTFIT_COLOR_RED_TURN_ON: 'CommonTraitId' = 365043 - ATTRACTION_OUTFIT_COLOR_WHITE_TURN_OFF: 'CommonTraitId' = 365045 - ATTRACTION_OUTFIT_COLOR_WHITE_TURN_ON: 'CommonTraitId' = 365044 - ATTRACTION_OUTFIT_COLOR_YELLOW_TURN_OFF: 'CommonTraitId' = 365047 - ATTRACTION_OUTFIT_COLOR_YELLOW_TURN_ON: 'CommonTraitId' = 365046 - ATTRACTION_ROMANCE_STYLES_AFFECTION_TURN_OFF: 'CommonTraitId' = 363455 - ATTRACTION_ROMANCE_STYLES_AFFECTION_TURN_ON: 'CommonTraitId' = 363456 - ATTRACTION_ROMANCE_STYLES_FLIRTING_TURN_OFF: 'CommonTraitId' = 364600 - ATTRACTION_ROMANCE_STYLES_FLIRTING_TURN_ON: 'CommonTraitId' = 364601 - ATTRACTION_ROMANCE_STYLES_GIFT_GIVING_TURN_OFF: 'CommonTraitId' = 364660 - ATTRACTION_ROMANCE_STYLES_GIFT_GIVING_TURN_ON: 'CommonTraitId' = 364661 - ATTRACTION_ROMANCE_STYLES_PHYSICAL_INTIMACY_TURN_OFF: 'CommonTraitId' = 364662 - ATTRACTION_ROMANCE_STYLES_PHYSICAL_INTIMACY_TURN_ON: 'CommonTraitId' = 364663 - ATTRACTION_ROMANCE_STYLES_WOOHOO_TURN_OFF: 'CommonTraitId' = 364664 - ATTRACTION_ROMANCE_STYLES_WOOHOO_TURN_ON: 'CommonTraitId' = 364665 - ATTRACTION_SKILL_ARCHETYPES_ACADEMIC_TURN_OFF: 'CommonTraitId' = 377508 - ATTRACTION_SKILL_ARCHETYPES_ACADEMIC_TURN_ON: 'CommonTraitId' = 377507 - ATTRACTION_SKILL_ARCHETYPES_ARTS_AND_CRAFTS_TURN_OFF: 'CommonTraitId' = 377495 - ATTRACTION_SKILL_ARCHETYPES_ARTS_AND_CRAFTS_TURN_ON: 'CommonTraitId' = 377494 - ATTRACTION_SKILL_ARCHETYPES_COOKING_TURN_OFF: 'CommonTraitId' = 377510 - ATTRACTION_SKILL_ARCHETYPES_COOKING_TURN_ON: 'CommonTraitId' = 377509 - ATTRACTION_SKILL_ARCHETYPES_DRINK_MAKING_TURN_OFF: 'CommonTraitId' = 377512 - ATTRACTION_SKILL_ARCHETYPES_DRINK_MAKING_TURN_ON: 'CommonTraitId' = 377511 - ATTRACTION_SKILL_ARCHETYPES_ENGINEERING_TURN_OFF: 'CommonTraitId' = 377514 - ATTRACTION_SKILL_ARCHETYPES_ENGINEERING_TURN_ON: 'CommonTraitId' = 377513 - ATTRACTION_SKILL_ARCHETYPES_HEALTH_AND_SPORTS_TURN_OFF: 'CommonTraitId' = 377516 - ATTRACTION_SKILL_ARCHETYPES_HEALTH_AND_SPORTS_TURN_ON: 'CommonTraitId' = 377515 - ATTRACTION_SKILL_ARCHETYPES_INTERPERSONAL_TURN_OFF: 'CommonTraitId' = 377518 - ATTRACTION_SKILL_ARCHETYPES_INTERPERSONAL_TURN_ON: 'CommonTraitId' = 377517 - ATTRACTION_SKILL_ARCHETYPES_MEDIA_AND_TECH_TURN_OFF: 'CommonTraitId' = 377520 - ATTRACTION_SKILL_ARCHETYPES_MEDIA_AND_TECH_TURN_ON: 'CommonTraitId' = 377519 - ATTRACTION_SKILL_ARCHETYPES_NATURE_TURN_OFF: 'CommonTraitId' = 377522 - ATTRACTION_SKILL_ARCHETYPES_NATURE_TURN_ON: 'CommonTraitId' = 377521 - ATTRACTION_SKILL_ARCHETYPES_PERFORMER_TURN_OFF: 'CommonTraitId' = 377524 - ATTRACTION_SKILL_ARCHETYPES_PERFORMER_TURN_ON: 'CommonTraitId' = 377523 - ATTRACTION_SKILL_ARCHETYPES_SENSE_OF_HUMOR_TURN_OFF: 'CommonTraitId' = 377526 - ATTRACTION_SKILL_ARCHETYPES_SENSE_OF_HUMOR_TURN_ON: 'CommonTraitId' = 377525 - AT_DAYCARE: 'CommonTraitId' = 105482 - BABY: 'CommonTraitId' = 34314 - BANE: 'CommonTraitId' = 27217 - BATUU_ALIEN: 'CommonTraitId' = 238971 - BATUU_ALIEN_ABEDNEDO: 'CommonTraitId' = 239906 - BATUU_ALIEN_BITH: 'CommonTraitId' = 239907 - BATUU_ALIEN_MIRIALAN: 'CommonTraitId' = 239904 - BATUU_ALIEN_TWILEK: 'CommonTraitId' = 239903 - BATUU_ALIEN_WEEQUAY: 'CommonTraitId' = 239902 - BATUU_ALIEN_ZABRAK: 'CommonTraitId' = 239905 - BATUU_FIRST_ORDER: 'CommonTraitId' = 233327 - BATUU_FIRST_ORDER_OFFICER: 'CommonTraitId' = 233345 - BATUU_FIRST_ORDER_OFFICER_RESISTANCE_SPY: 'CommonTraitId' = 249384 - BATUU_FIRST_ORDER_STORMTROOPER: 'CommonTraitId' = 233346 - BATUU_KNOWN: 'CommonTraitId' = 245215 - BATUU_LIGHTSABER: 'CommonTraitId' = 243724 - BATUU_LIGHTSABER_BLUE: 'CommonTraitId' = 235144 - BATUU_LIGHTSABER_GREEN: 'CommonTraitId' = 235145 - BATUU_LIGHTSABER_RED: 'CommonTraitId' = 235110 - BATUU_MISSION_ASK_ABOUT_FIRST_ORDER: 'CommonTraitId' = 237697 - BATUU_MISSION_ASK_ABOUT_RESISTANCE: 'CommonTraitId' = 237696 - BATUU_MISSION_BRIBE_CREDITS: 'CommonTraitId' = 240384 - BATUU_MISSION_BRIBE_DROID_PARTS: 'CommonTraitId' = 240386 - BATUU_MISSION_BRIBE_FOOD: 'CommonTraitId' = 240385 - BATUU_MISSION_BRIBE_HAS_BEEN_BRIBED: 'CommonTraitId' = 240413 - BATUU_MISSION_BRIBE_KYBER: 'CommonTraitId' = 248127 - BATUU_MISSION_BRIBE_PORG: 'CommonTraitId' = 248126 - BATUU_MISSION_CONVINCED_SCIENTIST_JOIN_FIRST_ORDER: 'CommonTraitId' = 241596 - BATUU_MISSION_DEFECTOR: 'CommonTraitId' = 243568 - BATUU_MISSION_FIRST_ORDER_REPEATABLE_1: 'CommonTraitId' = 244522 - BATUU_MISSION_FIRST_ORDER_REPEATABLE_13: 'CommonTraitId' = 244465 - BATUU_MISSION_FIRST_ORDER_REPEATABLE_2: 'CommonTraitId' = 244224 - BATUU_MISSION_FIRST_ORDER_REPEATABLE_3: 'CommonTraitId' = 244225 - BATUU_MISSION_FIRST_ORDER_STORY_4: 'CommonTraitId' = 246285 - BATUU_MISSION_FIRST_ORDER_STORY_4_CRIMINAL: 'CommonTraitId' = 245960 - BATUU_MISSION_FIRST_ORDER_STORY_4_CRIMINAL_HELPER: 'CommonTraitId' = 245961 - BATUU_MISSION_FIRST_ORDER_STORY_4_OBTAINED_CRIMINAL_INFO: 'CommonTraitId' = 241263 - BATUU_MISSION_FIRST_ORDER_STORY_6_SCIENTIST_JOINED: 'CommonTraitId' = 243731 - BATUU_MISSION_FIRST_ORDER_STORY_7_SHARED_FAKE_INFO_ALL: 'CommonTraitId' = 241718 - BATUU_MISSION_FREE_DRINKS_AT_OGAS_CANTINA: 'CommonTraitId' = 244158 - BATUU_MISSION_GIVEN_INFO: 'CommonTraitId' = 240524 - BATUU_MISSION_IS_INFORMANT: 'CommonTraitId' = 239909 - BATUU_MISSION_IS_RESISTANCE_SYMPATHIZER: 'CommonTraitId' = 243525 - BATUU_MISSION_RESISTANCE_CONTACT: 'CommonTraitId' = 240037 - BATUU_MISSION_RESISTANCE_REPEATABLE_15_CAN_RETRIEVE_DATA: 'CommonTraitId' = 245194 - BATUU_MISSION_RESISTANCE_REPEATABLE_1_PART_1: 'CommonTraitId' = 244227 - BATUU_MISSION_RESISTANCE_REPEATABLE_1_PART_2: 'CommonTraitId' = 244228 - BATUU_MISSION_RESISTANCE_REPEATABLE_2: 'CommonTraitId' = 244229 - BATUU_MISSION_RESISTANCE_STORY_2_OBTAINED_FIRST_ORDER_ACCESS_CODE: 'CommonTraitId' = 239472 - BATUU_MISSION_RESISTANCE_STORY_3_REPAIRED: 'CommonTraitId' = 251238 - BATUU_MISSION_RESISTANCE_STORY_3_SCRAMBLED: 'CommonTraitId' = 251237 - BATUU_MISSION_RESISTANCE_STORY_9_DESTROY_JAMMING_EQUIPMENT: 'CommonTraitId' = 243978 - BATUU_MISSION_SABACC_TOURNAMENT_1ST_OPPONENT: 'CommonTraitId' = 244445 - BATUU_MISSION_SABACC_TOURNAMENT_2ND_OPPONENT: 'CommonTraitId' = 244446 - BATUU_MISSION_SABACC_TOURNAMENT_FINAL_OPPONENT: 'CommonTraitId' = 244447 - BATUU_MISSION_SABACC_TOURNAMENT_PLAYED_ALL_OPPONENTS: 'CommonTraitId' = 250970 - BATUU_MISSION_SCIENTIST_DO_WORK: 'CommonTraitId' = 247605 - BATUU_MISSION_SCOUNDREL_CONTACT: 'CommonTraitId' = 240262 - BATUU_MISSION_SCOUNDREL_REPEATABLE_4_CONTRABAND_LOCATION_BLACK_SPIRE_OUTPOST: 'CommonTraitId' = 244602 - BATUU_MISSION_SCOUNDREL_REPEATABLE_4_CONTRABAND_LOCATION_FIRST_ORDER: 'CommonTraitId' = 244601 - BATUU_MISSION_SCOUNDREL_STORY_7_RECRUITED_HEIST: 'CommonTraitId' = 244826 - BATUU_MISSION_STORMTROOPER_CHECK_ID: 'CommonTraitId' = 243985 - BATUU_NPC: 'CommonTraitId' = 231263 - BATUU_NPC_CITIZEN: 'CommonTraitId' = 235820 - BATUU_REPUTATION_NEGATIVE_FIRST_ORDER_MODIFIER_LEVEL_1: 'CommonTraitId' = 243013 - BATUU_REPUTATION_NEGATIVE_FIRST_ORDER_MODIFIER_LEVEL_2: 'CommonTraitId' = 243040 - BATUU_REPUTATION_NEGATIVE_FIRST_ORDER_MODIFIER_LEVEL_3: 'CommonTraitId' = 243041 - BATUU_REPUTATION_NEGATIVE_FIRST_ORDER_MODIFIER_LEVEL_4: 'CommonTraitId' = 243039 - BATUU_REPUTATION_NEGATIVE_FIRST_ORDER_MODIFIER_LEVEL_5: 'CommonTraitId' = 243038 - BATUU_REPUTATION_NEGATIVE_RESISTANCE_MODIFIER_LEVEL_1: 'CommonTraitId' = 243062 - BATUU_REPUTATION_NEGATIVE_RESISTANCE_MODIFIER_LEVEL_2: 'CommonTraitId' = 243063 - BATUU_REPUTATION_NEGATIVE_RESISTANCE_MODIFIER_LEVEL_3: 'CommonTraitId' = 243064 - BATUU_REPUTATION_NEGATIVE_RESISTANCE_MODIFIER_LEVEL_4: 'CommonTraitId' = 243065 - BATUU_REPUTATION_NEGATIVE_RESISTANCE_MODIFIER_LEVEL_5: 'CommonTraitId' = 243066 - BATUU_REPUTATION_NEGATIVE_SCOUNDREL_MODIFIER_LEVEL_1: 'CommonTraitId' = 243069 - BATUU_REPUTATION_NEGATIVE_SCOUNDREL_MODIFIER_LEVEL_2: 'CommonTraitId' = 243070 - BATUU_REPUTATION_NEGATIVE_SCOUNDREL_MODIFIER_LEVEL_3: 'CommonTraitId' = 243071 - BATUU_REPUTATION_NEGATIVE_SCOUNDREL_MODIFIER_LEVEL_4: 'CommonTraitId' = 243072 - BATUU_REPUTATION_NEGATIVE_SCOUNDREL_MODIFIER_LEVEL_5: 'CommonTraitId' = 243073 - BATUU_RESISTANCE: 'CommonTraitId' = 233326 - BATUU_RICH_SCOUNDREL: 'CommonTraitId' = 244192 - BATUU_SCOUNDREL: 'CommonTraitId' = 233344 - BAY_AREA_NPC_ADHARA_MICHAELSON_HIDDEN: 'CommonTraitId' = 302879 - BAY_AREA_NPC_AURELIO_ROBLES_HIDDEN: 'CommonTraitId' = 302877 - BAY_AREA_NPC_BERNICE_ROBLES_HIDDEN: 'CommonTraitId' = 302875 - BAY_AREA_NPC_CHRISTOPHER_MICHAELSON_HIDDEN: 'CommonTraitId' = 302878 - BAY_AREA_NPC_DOLI_RUANO_HIDDEN: 'CommonTraitId' = 302881 - BAY_AREA_NPC_ELEANOR_SULLIVAN_HIDDEN: 'CommonTraitId' = 302885 - BAY_AREA_NPC_IAN_ROBLES_HIDDEN: 'CommonTraitId' = 302876 - BAY_AREA_NPC_IGNACIO_ROBLES_HIDDEN: 'CommonTraitId' = 302874 - BAY_AREA_NPC_JAY_ROBLES_HIDDEN: 'CommonTraitId' = 302880 - BAY_AREA_NPC_KARMINE_LUNA_HIDDEN: 'CommonTraitId' = 302884 - BAY_AREA_NPC_KYLE_KYLESON_HIDDEN: 'CommonTraitId' = 302886 - BAY_AREA_NPC_ORION_MICHAELSON_HIDDEN: 'CommonTraitId' = 308600 - BAY_AREA_NPC_PENELOPE_MICHAELSON_HIDDEN: 'CommonTraitId' = 308601 - BAY_AREA_NPC_TALA_RUANO_HIDDEN: 'CommonTraitId' = 302882 - BAY_AREA_NPC_XOCHITL_LUNA_HIDDEN: 'CommonTraitId' = 302883 - BEACH_BUM_LAID_BACK: 'CommonTraitId' = 211971 - BEGUILING: 'CommonTraitId' = 26203 - BONEHILDA: 'CommonTraitId' = 253237 - BOOKWORM: 'CommonTraitId' = 27916 - BRAVE: 'CommonTraitId' = 253268 - BREASTS_FORCE_OFF: 'CommonTraitId' = 136862 - BREASTS_FORCE_ON: 'CommonTraitId' = 136863 - BRO: 'CommonTraitId' = 16826 - BUSINESS_SAVVY: 'CommonTraitId' = 27082 - CAREER_FREELANCER_AGENCIES_FASHION_PHOTOGRAPHER: 'CommonTraitId' = 214787 - CAREER_FREELANCER_AGENCIES_INTERIOR_DECORATOR: 'CommonTraitId' = 257957 - CAREER_FREELANCER_AGENCIES_MAKER: 'CommonTraitId' = 234236 - CAREER_FREELANCER_AGENCIES_PAINTING: 'CommonTraitId' = 205700 - CAREER_FREELANCER_AGENCIES_PARANORMAL_INVESTIGATOR: 'CommonTraitId' = 252647 - CAREER_FREELANCER_AGENCIES_PROGRAMMING: 'CommonTraitId' = 205701 - CAREER_FREELANCER_AGENCIES_WRITING: 'CommonTraitId' = 205702 - CAREER_FREELANCER_BONUS_GIG_PAYOUT: 'CommonTraitId' = 211624 - CAREER_FREELANCER_COMPLETED_MEET_WITH_CLIENT: 'CommonTraitId' = 212114 - CAREER_FREELANCER_FASHION_PHOTOGRAPHER_UNLOCKED_MAGAZINE_COVER_SUBMISSION: 'CommonTraitId' = 219050 - CAREER_FREELANCER_FASHION_PHOTOGRAPHER_UNLOCKED_PHOTO_EDITOR: 'CommonTraitId' = 219051 - CAREER_FREELANCER_FASHION_PHOTOGRAPHER_WAITING_FOR_MAGAZINE: 'CommonTraitId' = 221339 - CAREER_FREELANCER_PARANORMAL_INVESTIGATOR_LICENSE: 'CommonTraitId' = 252818 - CAREER_FREELANCER_UNLOCKED_MEET: 'CommonTraitId' = 211942 - CAREER_FREELANCER_UNLOCKED_OVERCLOCK: 'CommonTraitId' = 209478 - CAREER_LIFEGUARD_REWARDS_LEVEL_2: 'CommonTraitId' = 212019 - CAREER_LIFEGUARD_REWARDS_LEVEL_3: 'CommonTraitId' = 212020 - CAREER_PAY_BOOSTS_LAW_CLIENTS_1: 'CommonTraitId' = 228732 - CAREER_PAY_BOOSTS_LAW_CLIENTS_10: 'CommonTraitId' = 228741 - CAREER_PAY_BOOSTS_LAW_CLIENTS_2: 'CommonTraitId' = 228733 - CAREER_PAY_BOOSTS_LAW_CLIENTS_3: 'CommonTraitId' = 228734 - CAREER_PAY_BOOSTS_LAW_CLIENTS_4: 'CommonTraitId' = 228735 - CAREER_PAY_BOOSTS_LAW_CLIENTS_5: 'CommonTraitId' = 228736 - CAREER_PAY_BOOSTS_LAW_CLIENTS_6: 'CommonTraitId' = 228737 - CAREER_PAY_BOOSTS_LAW_CLIENTS_7: 'CommonTraitId' = 228738 - CAREER_PAY_BOOSTS_LAW_CLIENTS_8: 'CommonTraitId' = 228739 - CAREER_PAY_BOOSTS_LAW_CLIENTS_9: 'CommonTraitId' = 228740 - CAREER_SCIENTIST_EVENT_INVENTING: 'CommonTraitId' = 112700 - CAREER_SIMSFLUENCER_SIDE_HUSTLE_CAN_REVIEW: 'CommonTraitId' = 278995 - CAREER_SIMSFLUENCER_SIDE_HUSTLE_GIFT_DELIVERY: 'CommonTraitId' = 278996 - CAREFREE: 'CommonTraitId' = 26476 - CARRIER_PREFERENCE_INFANT_BLACK_YELLOW: 'CommonTraitId' = 325315 - CARRIER_PREFERENCE_INFANT_GREY: 'CommonTraitId' = 307874 - CARRIER_PREFERENCE_INFANT_PINK: 'CommonTraitId' = 307875 - CARRIER_PREFERENCE_INFANT_STURDY_BLUE: 'CommonTraitId' = 325317 - CARRIER_PREFERENCE_INFANT_STURDY_GRAY: 'CommonTraitId' = 325318 - CARRIER_PREFERENCE_INFANT_STURDY_GREEN: 'CommonTraitId' = 325319 - CARRIER_PREFERENCE_INFANT_STURDY_ORANGE: 'CommonTraitId' = 317068 - CARRIER_PREFERENCE_INFANT_STURDY_RED: 'CommonTraitId' = 325320 - CARRIER_PREFERENCE_INFANT_WHITE: 'CommonTraitId' = 325316 - CAS_STORY_CAREER_ACTIVIST: 'CommonTraitId' = 213270 - CAS_STORY_CAREER_ACTIVIST_LEVEL_2: 'CommonTraitId' = 216463 - CAS_STORY_CAREER_ACTIVIST_LEVEL_3: 'CommonTraitId' = 216464 - CAS_STORY_CAREER_ACTOR: 'CommonTraitId' = 213263 - CAS_STORY_CAREER_ACTOR_LEVEL_2: 'CommonTraitId' = 216475 - CAS_STORY_CAREER_ACTOR_LEVEL_3: 'CommonTraitId' = 216476 - CAS_STORY_CAREER_ASTRONAUT: 'CommonTraitId' = 213204 - CAS_STORY_CAREER_ASTRONAUT_LEVEL_2: 'CommonTraitId' = 216412 - CAS_STORY_CAREER_ASTRONAUT_LEVEL_3: 'CommonTraitId' = 216413 - CAS_STORY_CAREER_ATHLETIC: 'CommonTraitId' = 217480 - CAS_STORY_CAREER_ATHLETIC_2: 'CommonTraitId' = 217481 - CAS_STORY_CAREER_ATHLETIC_3: 'CommonTraitId' = 217482 - CAS_STORY_CAREER_BUSINESS: 'CommonTraitId' = 213205 - CAS_STORY_CAREER_BUSINESS_LEVEL_2: 'CommonTraitId' = 216421 - CAS_STORY_CAREER_BUSINESS_LEVEL_3: 'CommonTraitId' = 216422 - CAS_STORY_CAREER_CIVIL_DESIGNER: 'CommonTraitId' = 239454 - CAS_STORY_CAREER_CIVIL_DESIGNER_LEVEL_2: 'CommonTraitId' = 239456 - CAS_STORY_CAREER_CIVIL_DESIGNER_LEVEL_3: 'CommonTraitId' = 239455 - CAS_STORY_CAREER_CONSERVATIONIST: 'CommonTraitId' = 215946 - CAS_STORY_CAREER_CONSERVATIONIST_LEVEL_2: 'CommonTraitId' = 216478 - CAS_STORY_CAREER_CONSERVATIONIST_LEVEL_3: 'CommonTraitId' = 216479 - CAS_STORY_CAREER_CORPORATE_0: 'CommonTraitId' = 251783 - CAS_STORY_CAREER_CORPORATE_LEVEL_2: 'CommonTraitId' = 251784 - CAS_STORY_CAREER_CORPORATE_LEVEL_3: 'CommonTraitId' = 251785 - CAS_STORY_CAREER_CRIMINAL: 'CommonTraitId' = 213206 - CAS_STORY_CAREER_CRIMINAL_LEVEL_2: 'CommonTraitId' = 216424 - CAS_STORY_CAREER_CRIMINAL_LEVEL_3: 'CommonTraitId' = 216425 - CAS_STORY_CAREER_CRITIC: 'CommonTraitId' = 213267 - CAS_STORY_CAREER_CRITIC_LEVEL_2: 'CommonTraitId' = 216466 - CAS_STORY_CAREER_CRITIC_LEVEL_3: 'CommonTraitId' = 216467 - CAS_STORY_CAREER_CULINARY: 'CommonTraitId' = 213207 - CAS_STORY_CAREER_CULINARY_LEVEL_2: 'CommonTraitId' = 216427 - CAS_STORY_CAREER_CULINARY_LEVEL_3: 'CommonTraitId' = 216428 - CAS_STORY_CAREER_DETECTIVE: 'CommonTraitId' = 213264 - CAS_STORY_CAREER_DETECTIVE_LEVEL_2: 'CommonTraitId' = 216451 - CAS_STORY_CAREER_DETECTIVE_LEVEL_3: 'CommonTraitId' = 216452 - CAS_STORY_CAREER_DIVER: 'CommonTraitId' = 215948 - CAS_STORY_CAREER_DIVER_LEVEL_2: 'CommonTraitId' = 216481 - CAS_STORY_CAREER_DIVER_LEVEL_3: 'CommonTraitId' = 216482 - CAS_STORY_CAREER_DOCTOR: 'CommonTraitId' = 213265 - CAS_STORY_CAREER_DOCTOR_LEVEL_2: 'CommonTraitId' = 216454 - CAS_STORY_CAREER_DOCTOR_LEVEL_3: 'CommonTraitId' = 216455 - CAS_STORY_CAREER_EDUCATION: 'CommonTraitId' = 227290 - CAS_STORY_CAREER_EDUCATION_LEVEL_2: 'CommonTraitId' = 227291 - CAS_STORY_CAREER_EDUCATION_LEVEL_3: 'CommonTraitId' = 227292 - CAS_STORY_CAREER_ENGINEER: 'CommonTraitId' = 227295 - CAS_STORY_CAREER_ENGINEER_LEVEL_2: 'CommonTraitId' = 227296 - CAS_STORY_CAREER_ENGINEER_LEVEL_3: 'CommonTraitId' = 227297 - CAS_STORY_CAREER_ENTERTAINER: 'CommonTraitId' = 213208 - CAS_STORY_CAREER_ENTERTAINER_LEVEL_2: 'CommonTraitId' = 216430 - CAS_STORY_CAREER_ENTERTAINER_LEVEL_3: 'CommonTraitId' = 216431 - CAS_STORY_CAREER_FISHERMAN: 'CommonTraitId' = 216487 - CAS_STORY_CAREER_FISHERMAN_LEVEL_2: 'CommonTraitId' = 216484 - CAS_STORY_CAREER_FISHERMAN_LEVEL_3: 'CommonTraitId' = 216485 - CAS_STORY_CAREER_FREELANCER: 'CommonTraitId' = 213209 - CAS_STORY_CAREER_GARDENER: 'CommonTraitId' = 213269 - CAS_STORY_CAREER_GARDENER_LEVEL_2: 'CommonTraitId' = 216472 - CAS_STORY_CAREER_GARDENER_LEVEL_3: 'CommonTraitId' = 216473 - CAS_STORY_CAREER_LAW: 'CommonTraitId' = 227298 - CAS_STORY_CAREER_LAW_LEVEL_2: 'CommonTraitId' = 227299 - CAS_STORY_CAREER_LAW_LEVEL_3: 'CommonTraitId' = 227300 - CAS_STORY_CAREER_LIFEGUARD: 'CommonTraitId' = 217924 - CAS_STORY_CAREER_LIFEGUARD_LEVEL_2: 'CommonTraitId' = 217925 - CAS_STORY_CAREER_LIFEGUARD_LEVEL_3: 'CommonTraitId' = 217926 - CAS_STORY_CAREER_MILITARY: 'CommonTraitId' = 215965 - CAS_STORY_CAREER_MILITARY_LEVEL_2: 'CommonTraitId' = 216460 - CAS_STORY_CAREER_MILITARY_LEVEL_3: 'CommonTraitId' = 216461 - CAS_STORY_CAREER_PAINTER: 'CommonTraitId' = 213177 - CAS_STORY_CAREER_PAINTER_LEVEL_2: 'CommonTraitId' = 216436 - CAS_STORY_CAREER_PAINTER_LEVEL_3: 'CommonTraitId' = 216437 - CAS_STORY_CAREER_ROMANCE_CONSULTANT_LEVEL_1: 'CommonTraitId' = 365475 - CAS_STORY_CAREER_ROMANCE_CONSULTANT_LEVEL_2: 'CommonTraitId' = 365476 - CAS_STORY_CAREER_ROMANCE_CONSULTANT_LEVEL_3: 'CommonTraitId' = 365477 - CAS_STORY_CAREER_SCIENTIST: 'CommonTraitId' = 213266 - CAS_STORY_CAREER_SCIENTIST_LEVEL_2: 'CommonTraitId' = 216457 - CAS_STORY_CAREER_SCIENTIST_LEVEL_3: 'CommonTraitId' = 216458 - CAS_STORY_CAREER_SECRET_AGENT: 'CommonTraitId' = 213210 - CAS_STORY_CAREER_SECRET_AGENT_LEVEL_2: 'CommonTraitId' = 216439 - CAS_STORY_CAREER_SECRET_AGENT_LEVEL_3: 'CommonTraitId' = 216440 - CAS_STORY_CAREER_SOCIAL_MEDIA: 'CommonTraitId' = 213268 - CAS_STORY_CAREER_SOCIAL_MEDIA_LEVEL_2: 'CommonTraitId' = 216469 - CAS_STORY_CAREER_SOCIAL_MEDIA_LEVEL_3: 'CommonTraitId' = 216470 - CAS_STORY_CAREER_STYLE_INFLUENCER: 'CommonTraitId' = 213211 - CAS_STORY_CAREER_STYLE_INFLUENCER_LEVEL_2: 'CommonTraitId' = 216442 - CAS_STORY_CAREER_STYLE_INFLUENCER_LEVEL_3: 'CommonTraitId' = 216443 - CAS_STORY_CAREER_TECH_GURU: 'CommonTraitId' = 213212 - CAS_STORY_CAREER_TECH_GURU_LEVEL_2: 'CommonTraitId' = 216445 - CAS_STORY_CAREER_TECH_GURU_LEVEL_3: 'CommonTraitId' = 216446 - CAS_STORY_CAREER_UNEMPLOYED: 'CommonTraitId' = 216896 - CAS_STORY_CAREER_WRITER: 'CommonTraitId' = 213213 - CAS_STORY_CAREER_WRITER_LEVEL_2: 'CommonTraitId' = 216448 - CAS_STORY_CAREER_WRITER_LEVEL_3: 'CommonTraitId' = 216449 - CAS_STORY_HOUSEHOLD_FUNDS_HIGH: 'CommonTraitId' = 215921 - CAS_STORY_HOUSEHOLD_FUNDS_LOW: 'CommonTraitId' = 215919 - CAS_STORY_HOUSEHOLD_FUNDS_MED: 'CommonTraitId' = 215920 - CAS_STORY_OCCULT_GHOST: 'CommonTraitId' = 213178 - CAS_STORY_OCCULT_VAMPIRE: 'CommonTraitId' = 213261 - CAS_STORY_SKILL_ACTING: 'CommonTraitId' = 213281 - CAS_STORY_SKILL_ACTING_3: 'CommonTraitId' = 216742 - CAS_STORY_SKILL_ARCHAEOLOGY: 'CommonTraitId' = 213277 - CAS_STORY_SKILL_ARCHAEOLOGY_3: 'CommonTraitId' = 216734 - CAS_STORY_SKILL_BAKING: 'CommonTraitId' = 213272 - CAS_STORY_SKILL_BAKING_3: 'CommonTraitId' = 216722 - CAS_STORY_SKILL_BOWLING: 'CommonTraitId' = 215951 - CAS_STORY_SKILL_BOWLING_3: 'CommonTraitId' = 216728 - CAS_STORY_SKILL_CHARISMA: 'CommonTraitId' = 213189 - CAS_STORY_SKILL_CHARISMA_3: 'CommonTraitId' = 216676 - CAS_STORY_SKILL_COMEDY: 'CommonTraitId' = 213190 - CAS_STORY_SKILL_COMEDY_3: 'CommonTraitId' = 216678 - CAS_STORY_SKILL_COOKING: 'CommonTraitId' = 213185 - CAS_STORY_SKILL_COOKING_3: 'CommonTraitId' = 216680 - CAS_STORY_SKILL_CROSS_STITCH: 'CommonTraitId' = 260955 - CAS_STORY_SKILL_CROSS_STITCH_3: 'CommonTraitId' = 260956 - CAS_STORY_SKILL_DANCING_1: 'CommonTraitId' = 213203 - CAS_STORY_SKILL_DANCING_2: 'CommonTraitId' = 216777 - CAS_STORY_SKILL_DANCING_3: 'CommonTraitId' = 216778 - CAS_STORY_SKILL_DJ_MIXING: 'CommonTraitId' = 213274 - CAS_STORY_SKILL_DJ_MIXING_3: 'CommonTraitId' = 216726 - CAS_STORY_SKILL_ENTREPRENEUR: 'CommonTraitId' = 288961 - CAS_STORY_SKILL_ENTREPRENEUR_3: 'CommonTraitId' = 288962 - CAS_STORY_SKILL_EQUESTRIAN_SKILL: 'CommonTraitId' = 334054 - CAS_STORY_SKILL_EQUESTRIAN_SKILL_3: 'CommonTraitId' = 334055 - CAS_STORY_SKILL_FABRICATION: 'CommonTraitId' = 239334 - CAS_STORY_SKILL_FABRICATION_3: 'CommonTraitId' = 239335 - CAS_STORY_SKILL_FISHING: 'CommonTraitId' = 213191 - CAS_STORY_SKILL_FISHING_3: 'CommonTraitId' = 216684 - CAS_STORY_SKILL_FITNESS: 'CommonTraitId' = 213187 - CAS_STORY_SKILL_FITNESS_3: 'CommonTraitId' = 216686 - CAS_STORY_SKILL_FLOWER_ARRANGING: 'CommonTraitId' = 213280 - CAS_STORY_SKILL_FLOWER_ARRANGING_3: 'CommonTraitId' = 216740 - CAS_STORY_SKILL_GARDENING: 'CommonTraitId' = 213192 - CAS_STORY_SKILL_GARDENING_3: 'CommonTraitId' = 216688 - CAS_STORY_SKILL_GOURMET_COOKING: 'CommonTraitId' = 213193 - CAS_STORY_SKILL_GOURMET_COOKING_3: 'CommonTraitId' = 216690 - CAS_STORY_SKILL_GUITAR: 'CommonTraitId' = 213194 - CAS_STORY_SKILL_GUITAR_3: 'CommonTraitId' = 216692 - CAS_STORY_SKILL_HANDINESS: 'CommonTraitId' = 213195 - CAS_STORY_SKILL_HANDINESS_3: 'CommonTraitId' = 216694 - CAS_STORY_SKILL_HERBALISM: 'CommonTraitId' = 213271 - CAS_STORY_SKILL_HERBALISM_3: 'CommonTraitId' = 216720 - CAS_STORY_SKILL_JUICE_FIZZING: 'CommonTraitId' = 239333 - CAS_STORY_SKILL_JUICE_FIZZING_3: 'CommonTraitId' = 239337 - CAS_STORY_SKILL_LOCAL_CULTURE: 'CommonTraitId' = 217042 - CAS_STORY_SKILL_LOCAL_CULTURE_3: 'CommonTraitId' = 217043 - CAS_STORY_SKILL_LOGIC: 'CommonTraitId' = 213196 - CAS_STORY_SKILL_LOGIC_3: 'CommonTraitId' = 216696 - CAS_STORY_SKILL_MISCHIEF: 'CommonTraitId' = 213197 - CAS_STORY_SKILL_MISCHIEF_3: 'CommonTraitId' = 216698 - CAS_STORY_SKILL_MIXOLOGY: 'CommonTraitId' = 213188 - CAS_STORY_SKILL_MIXOLOGY_3: 'CommonTraitId' = 216700 - CAS_STORY_SKILL_NECTAR: 'CommonTraitId' = 334061 - CAS_STORY_SKILL_NECTAR_3: 'CommonTraitId' = 334062 - CAS_STORY_SKILL_PAINTING: 'CommonTraitId' = 213176 - CAS_STORY_SKILL_PAINTING_3: 'CommonTraitId' = 216702 - CAS_STORY_SKILL_PARENTING: 'CommonTraitId' = 213276 - CAS_STORY_SKILL_PARENTING_3: 'CommonTraitId' = 216732 - CAS_STORY_SKILL_PET_TRAINING: 'CommonTraitId' = 217046 - CAS_STORY_SKILL_PET_TRAINING_3: 'CommonTraitId' = 217047 - CAS_STORY_SKILL_PHOTOGRAPHY: 'CommonTraitId' = 213198 - CAS_STORY_SKILL_PHOTOGRAPHY_3: 'CommonTraitId' = 216704 - CAS_STORY_SKILL_PIANO: 'CommonTraitId' = 213199 - CAS_STORY_SKILL_PIANO_3: 'CommonTraitId' = 216706 - CAS_STORY_SKILL_PIPE_ORGAN: 'CommonTraitId' = 213275 - CAS_STORY_SKILL_PIPE_ORGAN_3: 'CommonTraitId' = 216730 - CAS_STORY_SKILL_PROGRAMMING: 'CommonTraitId' = 213184 - CAS_STORY_SKILL_PROGRAMMING_3: 'CommonTraitId' = 216708 - CAS_STORY_SKILL_RESEARCH_DEBATE: 'CommonTraitId' = 227287 - CAS_STORY_SKILL_RESEARCH_DEBATE_3: 'CommonTraitId' = 227288 - CAS_STORY_SKILL_ROBOTICS: 'CommonTraitId' = 227278 - CAS_STORY_SKILL_ROBOTICS_3: 'CommonTraitId' = 227279 - CAS_STORY_SKILL_ROCKET_SCIENCE: 'CommonTraitId' = 213200 - CAS_STORY_SKILL_ROCKET_SCIENCE_3: 'CommonTraitId' = 216710 - CAS_STORY_SKILL_ROCK_CLIMBING: 'CommonTraitId' = 251792 - CAS_STORY_SKILL_ROCK_CLIMBING_3: 'CommonTraitId' = 251793 - CAS_STORY_SKILL_ROMANCE: 'CommonTraitId' = 365472 - CAS_STORY_SKILL_SINGING: 'CommonTraitId' = 213278 - CAS_STORY_SKILL_SINGING_3: 'CommonTraitId' = 216736 - CAS_STORY_SKILL_SKIING: 'CommonTraitId' = 251797 - CAS_STORY_SKILL_SKIING_3: 'CommonTraitId' = 251798 - CAS_STORY_SKILL_SNOWBOARDING: 'CommonTraitId' = 251799 - CAS_STORY_SKILL_SNOWBOARDING_3: 'CommonTraitId' = 251800 - CAS_STORY_SKILL_VAMPIRE_LORE: 'CommonTraitId' = 217484 - CAS_STORY_SKILL_VAMPIRE_LORE_3: 'CommonTraitId' = 217485 - CAS_STORY_SKILL_VETERINARIAN: 'CommonTraitId' = 213279 - CAS_STORY_SKILL_VETERINARIAN_3: 'CommonTraitId' = 216738 - CAS_STORY_SKILL_VIDEO_GAMING: 'CommonTraitId' = 213201 - CAS_STORY_SKILL_VIDEO_GAMING_3: 'CommonTraitId' = 216713 - CAS_STORY_SKILL_VIOLIN: 'CommonTraitId' = 213202 - CAS_STORY_SKILL_VIOLIN_3: 'CommonTraitId' = 216716 - CAS_STORY_SKILL_WELLNESS: 'CommonTraitId' = 213273 - CAS_STORY_SKILL_WELLNESS_3: 'CommonTraitId' = 216724 - CAS_STORY_SKILL_WRITING: 'CommonTraitId' = 213186 - CAS_STORY_SKILL_WRITING_3: 'CommonTraitId' = 216718 - CAT_LOVER: 'CommonTraitId' = 157978 - CAT_QUIRK_SLEEP_STYLE_BACK: 'CommonTraitId' = 155557 - CAT_QUIRK_SLEEP_STYLE_CURL: 'CommonTraitId' = 155556 - CAT_QUIRK_STAND_WATCH_FALSE: 'CommonTraitId' = 173581 - CAT_QUIRK_STAND_WATCH_TRUE: 'CommonTraitId' = 173582 - CAULDRON_POTION_IMMORTALITY: 'CommonTraitId' = 214389 - CAULDRON_POTION_LUCK_CLUMSY: 'CommonTraitId' = 215779 - CELEBRITY_FANS_NERVOUS: 'CommonTraitId' = 196899 - CELEBRITY_FANS_SOCIAL: 'CommonTraitId' = 196900 - CELEBRITY_FANS_TOUCHY: 'CommonTraitId' = 196902 - CHALLENGE_KINDNESS_AMBASSADOR: 'CommonTraitId' = 198885 - CHAMPION_OF_THE_PEOPLE: 'CommonTraitId' = 234567 - CHEERFUL: 'CommonTraitId' = 9322 - CHILD: 'CommonTraitId' = 34316 - CHILDHOOD_PHASE_BEAR: 'CommonTraitId' = 164767 - CHILDHOOD_PHASE_CLINGY: 'CommonTraitId' = 164764 - CHILDHOOD_PHASE_DISTANT: 'CommonTraitId' = 164768 - CHILDHOOD_PHASE_LOUD: 'CommonTraitId' = 164766 - CHILDHOOD_PHASE_MEAN_STREAK: 'CommonTraitId' = 164769 - CHILDHOOD_PHASE_PICKY_EATER_A: 'CommonTraitId' = 164763 - CHILDHOOD_PHASE_PICKY_EATER_B: 'CommonTraitId' = 164972 - CHILDHOOD_PHASE_PICKY_EATER_C: 'CommonTraitId' = 164973 - CHILDHOOD_PHASE_PICKY_EATER_D: 'CommonTraitId' = 164974 - CHILDHOOD_PHASE_PICKY_EATER_DISGUSTED_BY_FOOD: 'CommonTraitId' = 165165 - CHILDHOOD_PHASE_PICKY_EATER_E: 'CommonTraitId' = 164975 - CHILDHOOD_PHASE_REBELLIOUS: 'CommonTraitId' = 164765 - CHILDISH: 'CommonTraitId' = 16830 - CHILD_CONFIDENCE_HIGH: 'CommonTraitId' = 314056 - CHILD_CONFIDENCE_LOW: 'CommonTraitId' = 314054 - CHILD_CONFIDENCE_NEUTRAL: 'CommonTraitId' = 314055 - CHILD_OF_THE_ISLANDS: 'CommonTraitId' = 204492 - CHILD_OF_THE_OCEAN: 'CommonTraitId' = 204493 - CHILD_OF_THE_OCEAN_DISGUSTED_BY_FISH: 'CommonTraitId' = 213619 - CHILD_OF_THE_SEA: 'CommonTraitId' = 341881 - CHILD_ROMANTIC_SAGE_HIDDEN: 'CommonTraitId' = 378263 - CHILD_SKILL_REWARD_HEAD_STRONG: 'CommonTraitId' = 308365 - CHILD_SKILL_REWARD_IDEA_PERSON: 'CommonTraitId' = 308367 - CHILD_SKILL_REWARD_PACK_ANIMAL: 'CommonTraitId' = 308366 - CHILD_SKILL_REWARD_PRATICED_HOST: 'CommonTraitId' = 308364 - CHOPSTICK_SAVVY: 'CommonTraitId' = 146104 - CHRONICLER: 'CommonTraitId' = 27692 - CIVIC_POLICY_COMMUNAL_OWNERSHIP: 'CommonTraitId' = 237950 - CIVIC_POLICY_ECO_FRIENDLY_APPLIANCES: 'CommonTraitId' = 232593 - CIVIC_POLICY_GREEN_GARDENING: 'CommonTraitId' = 233572 - CIVIC_POLICY_MODERN_POLICY: 'CommonTraitId' = 234944 - CIVIC_POLICY_REPEAL_STARTED: 'CommonTraitId' = 233502 - CIVIC_POLICY_SKILL_BASED_AGGRESSION: 'CommonTraitId' = 237910 - CIVIC_POLICY_SKILL_BASED_CREATIVE_ARTS: 'CommonTraitId' = 232030 - CIVIC_POLICY_SKILL_BASED_FREE_LOVE: 'CommonTraitId' = 237911 - CIVIC_POLICY_SKILL_BASED_FUN_COMMUNITY: 'CommonTraitId' = 232031 - CIVIC_POLICY_SKILL_BASED_HOME_COOKING: 'CommonTraitId' = 232032 - CIVIC_POLICY_SKILL_BASED_JUICED_COMMUNITY: 'CommonTraitId' = 232033 - CIVIC_POLICY_SKILL_BASED_MUSIC_ARTS: 'CommonTraitId' = 232034 - CIVIC_POLICY_SKILL_BASED_OLD_DAYS: 'CommonTraitId' = 237912 - CIVIC_POLICY_SKILL_BASED_SELF_CARE: 'CommonTraitId' = 232035 - CIVIC_POLICY_SKILL_BASED_SELF_SUFFICIENT: 'CommonTraitId' = 232036 - CIVIC_POLICY_SKILL_BASED_TECHNOLOGICAL_PROGRESS: 'CommonTraitId' = 232028 - CIVIC_POLICY_UPCYCLING_INITIATIVE: 'CommonTraitId' = 226549 - CIVIC_POLICY_UTILITY_PRODUCTION: 'CommonTraitId' = 233573 - CLUB_PRESIDENT: 'CommonTraitId' = 122922 - CLUMSY: 'CommonTraitId' = 16832 - COLD_HEARTED: 'CommonTraitId' = 275418 - COLLECTOR: 'CommonTraitId' = 35719 - COLLEGE_ORGANIZATIONS_ART_SOCIETY_RANK_1: 'CommonTraitId' = 229134 - COLLEGE_ORGANIZATIONS_ART_SOCIETY_RANK_2: 'CommonTraitId' = 223669 - COLLEGE_ORGANIZATIONS_ART_SOCIETY_RANK_3: 'CommonTraitId' = 223663 - COLLEGE_ORGANIZATIONS_DEBATE_RANK_1: 'CommonTraitId' = 229135 - COLLEGE_ORGANIZATIONS_DEBATE_RANK_2: 'CommonTraitId' = 224179 - COLLEGE_ORGANIZATIONS_DEBATE_RANK_3: 'CommonTraitId' = 224180 - COLLEGE_ORGANIZATIONS_HONOR_SOCIETY_RANK_1: 'CommonTraitId' = 229136 - COLLEGE_ORGANIZATIONS_HONOR_SOCIETY_RANK_2: 'CommonTraitId' = 226876 - COLLEGE_ORGANIZATIONS_HONOR_SOCIETY_RANK_3: 'CommonTraitId' = 226877 - COLLEGE_ORGANIZATIONS_ROBOTICS_RANK_1: 'CommonTraitId' = 229137 - COLLEGE_ORGANIZATIONS_ROBOTICS_RANK_2: 'CommonTraitId' = 223079 - COLLEGE_ORGANIZATIONS_ROBOTICS_RANK_3: 'CommonTraitId' = 223080 - COLLEGE_ORGANIZATIONS_SCHOOL_SPIRIT_PARTY_RANK_1: 'CommonTraitId' = 229138 - COLLEGE_ORGANIZATIONS_SCHOOL_SPIRIT_PARTY_RANK_2: 'CommonTraitId' = 225314 - COLLEGE_ORGANIZATIONS_SCHOOL_SPIRIT_PARTY_RANK_3: 'CommonTraitId' = 229139 - COLLEGE_ORGANIZATIONS_SCHOOL_SPIRIT_PRANK_RANK_1: 'CommonTraitId' = 229140 - COLLEGE_ORGANIZATIONS_SCHOOL_SPIRIT_PRANK_RANK_2: 'CommonTraitId' = 224603 - COLLEGE_ORGANIZATIONS_SCHOOL_SPIRIT_PRANK_RANK_3: 'CommonTraitId' = 229141 - COLLEGE_ORGANIZATIONS_SECRET_SOCIETY_FAVOR_HIGH: 'CommonTraitId' = 227496 - COLLEGE_ORGANIZATIONS_SECRET_SOCIETY_FAVOR_LOW: 'CommonTraitId' = 227494 - COLLEGE_ORGANIZATIONS_SECRET_SOCIETY_FAVOR_MED: 'CommonTraitId' = 227495 - COLLEGE_ORGANIZATIONS_SECRET_SOCIETY_JOIN_VISIT_MARKED: 'CommonTraitId' = 228781 - COLLEGE_ORGANIZATIONS_SECRET_SOCIETY_MEMBER: 'CommonTraitId' = 219299 - COMMITMENT_ISSUES: 'CommonTraitId' = 16833 - COMMUNITY_BOARD_ASKED_ABOUT_COMMUNITY: 'CommonTraitId' = 341810 - COMPUTER_GLASSES_WEARING: 'CommonTraitId' = 225007 - COMPUTER_GLASSES_WEARING_BLUE: 'CommonTraitId' = 225161 - COMPUTER_GLASSES_WEARING_GREEN: 'CommonTraitId' = 225162 - COMPUTER_GLASSES_WEARING_ORANGE: 'CommonTraitId' = 225163 - COMPUTER_GLASSES_WEARING_PINK: 'CommonTraitId' = 225160 - COMPUTER_GLASSES_WEARING_RED: 'CommonTraitId' = 225159 - COMPUTER_GLASSES_WEARING_YELLOW: 'CommonTraitId' = 225164 - CONNECTIONS: 'CommonTraitId' = 32431 - CORPORATE_WORKER_CHARISMATIC_CROONER: 'CommonTraitId' = 248982 - CORPORATE_WORKER_LEGENDARY_STAMINA: 'CommonTraitId' = 248983 - COTTAGE_WORLD_NPC_AGATHA_CRUMPLEBOTTOM: 'CommonTraitId' = 260169 - COTTAGE_WORLD_NPC_AGNES_CRUMPLEBOTTOM: 'CommonTraitId' = 259314 - COTTAGE_WORLD_NPC_CRITTER_TENDER: 'CommonTraitId' = 260173 - COTTAGE_WORLD_NPC_GROCERY_DELIVERY: 'CommonTraitId' = 260172 - COTTAGE_WORLD_NPC_GROCERY_OWNER: 'CommonTraitId' = 260171 - COTTAGE_WORLD_NPC_MAYOR: 'CommonTraitId' = 260170 - COTTAGE_WORLD_NPC_PUB_OWNER: 'CommonTraitId' = 260174 - CREATIVE: 'CommonTraitId' = 16850 - CREATIVELY_GIFTED: 'CommonTraitId' = 29619 - CREATIVE_VISIONARY: 'CommonTraitId' = 32423 - CRINGE: 'CommonTraitId' = 341153 - CRYSTAL_HELMET_ALABASTER: 'CommonTraitId' = 193977 - CRYSTAL_HELMET_ALEXANDRITE_EP: 'CommonTraitId' = 193979 - CRYSTAL_HELMET_AMAZONITE_EP: 'CommonTraitId' = 193980 - CRYSTAL_HELMET_AMETHYST: 'CommonTraitId' = 193528 - CRYSTAL_HELMET_CITRINE: 'CommonTraitId' = 193983 - CRYSTAL_HELMET_CRANDESTINE_EP: 'CommonTraitId' = 193984 - CRYSTAL_HELMET_DIAMOND: 'CommonTraitId' = 193985 - CRYSTAL_HELMET_EMERALD: 'CommonTraitId' = 193986 - CRYSTAL_HELMET_FIRE_OPAL: 'CommonTraitId' = 193987 - CRYSTAL_HELMET_HEMATITE: 'CommonTraitId' = 193988 - CRYSTAL_HELMET_JET: 'CommonTraitId' = 193989 - CRYSTAL_HELMET_JONQUILYST: 'CommonTraitId' = 193990 - CRYSTAL_HELMET_NITELITE_EP: 'CommonTraitId' = 193991 - CRYSTAL_HELMET_ORANGE_TOPAZ: 'CommonTraitId' = 193992 - CRYSTAL_HELMET_PEACH: 'CommonTraitId' = 193993 - CRYSTAL_HELMET_PLUMBITE: 'CommonTraitId' = 193994 - CRYSTAL_HELMET_QUARTZ: 'CommonTraitId' = 193995 - CRYSTAL_HELMET_RAINBORZ: 'CommonTraitId' = 193996 - CRYSTAL_HELMET_ROSE: 'CommonTraitId' = 193997 - CRYSTAL_HELMET_RUBY: 'CommonTraitId' = 193998 - CRYSTAL_HELMET_SAPPHIRE: 'CommonTraitId' = 193999 - CRYSTAL_HELMET_SHINALITE: 'CommonTraitId' = 194000 - CRYSTAL_HELMET_SIMANITE: 'CommonTraitId' = 194001 - CRYSTAL_HELMET_TURQUOISE: 'CommonTraitId' = 194002 - CURSES_FOUNTAIN_OF_MAGIC: 'CommonTraitId' = 214645 - CURSES_HEX_OF_DUELIST: 'CommonTraitId' = 214644 - CURSES_INFECTIOUS_LAUGHTER: 'CommonTraitId' = 214650 - CURSES_NIGHT_STALKER: 'CommonTraitId' = 214649 - CURSES_PUNCHABLE_FACE: 'CommonTraitId' = 214646 - CURSES_REPULSIVENESS: 'CommonTraitId' = 214643 - CURSES_SWEATY_STENCH: 'CommonTraitId' = 214647 - CURSES_TOUCHY_FEELY: 'CommonTraitId' = 214648 - CURSES_WILD_MAGIC: 'CommonTraitId' = 213183 - DANCE_MACHINE: 'CommonTraitId' = 126088 - DASTARDLY: 'CommonTraitId' = 27084 - DAUNTLESS: 'CommonTraitId' = 283147 - DETECTIVE_CAREER_CRIMINAL: 'CommonTraitId' = 113564 - DETECTIVE_CAREER_POLICE_STATION_CRIMINAL_NPC: 'CommonTraitId' = 116487 - DIAPER_PREFERENCE_BABY_CLOTH: 'CommonTraitId' = 306617 - DISCIPLINED_OUT_CAT_JUMP_ON_COUNTERS: 'CommonTraitId' = 170710 - DISCIPLINED_OUT_CAT_SCRATCHING: 'CommonTraitId' = 167067 - DISCIPLINED_OUT_DOG_BARK: 'CommonTraitId' = 167071 - DISCIPLINED_OUT_DOG_EAT_POOP: 'CommonTraitId' = 168486 - DISCIPLINED_OUT_DOG_JUMP_ON_COUNTERS: 'CommonTraitId' = 170709 - DISCIPLINED_OUT_DOG_PUDDLES_PLAY: 'CommonTraitId' = 167069 - DISCIPLINED_OUT_DOG_TOILET: 'CommonTraitId' = 167068 - DISCIPLINED_OUT_PET_ATTACK: 'CommonTraitId' = 167058 - DISCIPLINED_OUT_PET_BEG_EATING: 'CommonTraitId' = 167059 - DISCIPLINED_OUT_PET_EAT_PEOPLE_FOOD: 'CommonTraitId' = 170712 - DISCIPLINED_OUT_PET_POTTY_TRAINING: 'CommonTraitId' = 167072 - DISCIPLINED_OUT_PET_PUDDLES_DRINK: 'CommonTraitId' = 167061 - DISCIPLINED_OUT_PET_TRASH_EAT: 'CommonTraitId' = 167062 - DISCIPLINED_OUT_PET_TRASH_PLAY: 'CommonTraitId' = 167063 - DISCIPLINED_OUT_PET_WAKE_UP_SIMS: 'CommonTraitId' = 170711 - DISCIPLINE_PET_POTTY_TRAINING: 'CommonTraitId' = 162247 - DISGUSTED_BY_FOOD: 'CommonTraitId' = 149446 - DISGUSTED_BY_FOOD_ANIMATION: 'CommonTraitId' = 248309 - DOCTOR_SICKNESS_RESISTANT: 'CommonTraitId' = 114410 - DOG_LOVER: 'CommonTraitId' = 157979 - DOG_QUIRK_BARKER_LOUD: 'CommonTraitId' = 148643 - DOG_QUIRK_BARKER_NEUTRAL: 'CommonTraitId' = 148645 - DOG_QUIRK_BARKER_QUIET: 'CommonTraitId' = 148644 - ECO_ENGINEER: 'CommonTraitId' = 234566 - ECO_MASTER: 'CommonTraitId' = 234887 - EDUCATION_TEACH_10: 'CommonTraitId' = 220312 - EDUCATION_TEACH_7: 'CommonTraitId' = 220305 - EDUCATION_TEACH_8: 'CommonTraitId' = 220310 - EDUCATION_TEACH_9: 'CommonTraitId' = 220311 - ELDER: 'CommonTraitId' = 34320 - ENTREPRENEUR: 'CommonTraitId' = 234889 - ENTREPRENEURIAL: 'CommonTraitId' = 32444 - ENTREPRENEUR_THE_KNOWLEDGE: 'CommonTraitId' = 277990 - EP14_WORLD_HAS_WON_HORSE_COMPETITION_HIDDEN: 'CommonTraitId' = 338664 - EP14_WORLD_LOCAL_HIDDEN: 'CommonTraitId' = 340041 - EP14_WORLD_NPC_HAS_ASKED_ABOUT_LIFE_NECTAR_HIDDEN: 'CommonTraitId' = 322422 - EP14_WORLD_NPC_HORSE_TRAINER_GOODBYE_HIDDEN: 'CommonTraitId' = 350340 - EP14_WORLD_NPC_HORSE_TRAINER_HELLO_HIDDEN: 'CommonTraitId' = 350339 - EP14_WORLD_NPC_HORSE_TRAINER_HIDDEN: 'CommonTraitId' = 321628 - EP14_WORLD_NPC_MYSTERIOUS_RANCHER_HIDDEN: 'CommonTraitId' = 321627 - EP15_LOCAL_HIDDEN: 'CommonTraitId' = 343326 - EP15_NPC_ALON_SADYA_HIDDEN: 'CommonTraitId' = 343822 - EP15_NPC_ARTURO_LINH_HIDDEN: 'CommonTraitId' = 343820 - EP15_NPC_BUA_BUN_MA_HIDDEN: 'CommonTraitId' = 343816 - EP15_NPC_CHANH_LINH_HIDDEN: 'CommonTraitId' = 343819 - EP15_NPC_KASEM_BUN_MA_HIDDEN: 'CommonTraitId' = 343818 - EP15_NPC_LIEN_SADYA_HIDDEN: 'CommonTraitId' = 343821 - EP15_NPC_NIN_BUN_MA_HIDDEN: 'CommonTraitId' = 343817 - EP15_NPC_THI_LINH_HIDDEN: 'CommonTraitId' = 343823 - EP15_NPC_VANESHA_CAHYAPUTRI_HIDDEN: 'CommonTraitId' = 343824 - EP15_NPC_ZHAFIRA_CAHYAPUTRI_HIDDEN: 'CommonTraitId' = 343825 - EP16_WORLD_WALL_OF_LOVE_WROTE_ON_WALL_HIDDEN: 'CommonTraitId' = 369483 - EPIC_POET: 'CommonTraitId' = 30922 - ESSENCE_OF_FLAVOR: 'CommonTraitId' = 26197 - ETERNAL_BOND: 'CommonTraitId' = 26201 - EVICTION_SYSTEM_USED_FREE_CHANCE_HIDDEN: 'CommonTraitId' = 351533 - EVIL: 'CommonTraitId' = 16836 - EVIL_BEGONIA_SCENT: 'CommonTraitId' = 188801 - EXCURSION_MOUNTAINEER_RANK_1: 'CommonTraitId' = 249427 - EXCURSION_MOUNTAINEER_RANK_2: 'CommonTraitId' = 249430 - EXCURSION_MOUNTAINEER_RANK_3: 'CommonTraitId' = 249429 - EXPRESSIONISTIC: 'CommonTraitId' = 75815 - E_SPORTS: 'CommonTraitId' = 226661 - E_SPORTS_OFFERED: 'CommonTraitId' = 227952 - E_SPORTS_ONE_MATCHES_WON: 'CommonTraitId' = 227110 - E_SPORTS_TWO_MATCHES_WON: 'CommonTraitId' = 227111 - FAKE_GENIUS: 'CommonTraitId' = 106999 - FAME_LEVEL1: 'CommonTraitId' = 191807 - FAME_LEVEL2: 'CommonTraitId' = 191819 - FAME_LEVEL3: 'CommonTraitId' = 191820 - FAME_LEVEL4: 'CommonTraitId' = 191817 - FAME_LEVEL5: 'CommonTraitId' = 191818 - FAME_TRAITS_CELEBRITY_WALK_ON: 'CommonTraitId' = 204539 - FAME_TRAITS_SHINE_OFF: 'CommonTraitId' = 199156 - FAME_TRAITS_SHINE_ON_RANK4: 'CommonTraitId' = 199155 - FAME_TRAITS_SHINE_ON_RANK5: 'CommonTraitId' = 199223 - FAMILY_ORIENTED: 'CommonTraitId' = 16838 - FAMILY_SIM: 'CommonTraitId' = 27083 - FASHION_MARKETPLACE_SOLD_HYPE_OUTFIT: 'CommonTraitId' = 287494 - FASHION_MARKETPLACE_WEARING_OUTFIT: 'CommonTraitId' = 286922 - FAST_FASTIDIOUS: 'CommonTraitId' = 256786 - FEAR_BEING_ALONE: 'CommonTraitId' = 364229 - FEAR_BEING_CHEATED_ON: 'CommonTraitId' = 277086 - FEAR_BEING_JUDGED: 'CommonTraitId' = 277087 - FEAR_COW_PLANT: 'CommonTraitId' = 277088 - FEAR_CROWDED_PLACES: 'CommonTraitId' = 277089 - FEAR_DARK: 'CommonTraitId' = 277094 - FEAR_DEAD_END_JOB: 'CommonTraitId' = 277090 - FEAR_DEATH: 'CommonTraitId' = 277091 - FEAR_DEATH_GHOST_URBAN_MYTH_EP12: 'CommonTraitId' = 285880 - FEAR_DISAPPOINTING_PARENTS: 'CommonTraitId' = 277098 - FEAR_DISAPPOINTING_PARENTS_PARENT_DECEASED_FLAG: 'CommonTraitId' = 304222 - FEAR_EVICTION: 'CommonTraitId' = 342289 - FEAR_FAILING_AFTER_SCHOOL_ACTIVITIES: 'CommonTraitId' = 277095 - FEAR_FAILING_CLASS: 'CommonTraitId' = 277096 - FEAR_FAILING_TESTS: 'CommonTraitId' = 277097 - FEAR_FAILURE: 'CommonTraitId' = 277080 - FEAR_FIRE: 'CommonTraitId' = 277081 - FEAR_GHOSTS: 'CommonTraitId' = 277082 - FEAR_HOMEWORK: 'CommonTraitId' = 277099 - FEAR_HORSES: 'CommonTraitId' = 323758 - FEAR_HORSES_PROGRESS: 'CommonTraitId' = 324580 - FEAR_INFERIOR: 'CommonTraitId' = 307957 - FEAR_INTIMACY: 'CommonTraitId' = 362851 - FEAR_SWIMMING: 'CommonTraitId' = 277083 - FEAR_UNFULFILLED: 'CommonTraitId' = 277084 - FEED_PREFERENCE_BABY_BODY: 'CommonTraitId' = 305140 - FEED_PREFERENCE_BABY_BOTTLE: 'CommonTraitId' = 305139 - FERTILE: 'CommonTraitId' = 26498 - FILTH_DWELLER: 'CommonTraitId' = 256785 - FIZZY_HEAD: 'CommonTraitId' = 236949 - FLOWER_BUNNY: 'CommonTraitId' = 186785 - FOODIE: 'CommonTraitId' = 27176 - FOOD_PREFERENCE_INFANT_APPLESAUCE: 'CommonTraitId' = 289167 - FOOD_PREFERENCE_INFANT_BANANA_SLICES: 'CommonTraitId' = 289275 - FOOD_PREFERENCE_INFANT_CRUSHED_CARROTS: 'CommonTraitId' = 289182 - FOOD_PREFERENCE_INFANT_HOMEMADE_HUMMUS: 'CommonTraitId' = 289183 - FOOD_PREFERENCE_INFANT_ICE_CREAM: 'CommonTraitId' = 289192 - FOOD_PREFERENCE_INFANT_MASHED_MANGO: 'CommonTraitId' = 289193 - FOOD_PREFERENCE_INFANT_MASHED_PEAS: 'CommonTraitId' = 289194 - FOOD_PREFERENCE_INFANT_OATMEAL_CEREAL: 'CommonTraitId' = 289184 - FOOD_PREFERENCE_INFANT_OAT_YOS: 'CommonTraitId' = 289277 - FOOD_PREFERENCE_INFANT_PAPAYA_PASTE: 'CommonTraitId' = 289185 - FOOD_PREFERENCE_INFANT_PEANUT_BUTTER_PUFFS: 'CommonTraitId' = 289278 - FOOD_PREFERENCE_INFANT_PUMPKIN_PUREE: 'CommonTraitId' = 289186 - FOOD_PREFERENCE_INFANT_RICE_PORRIDGE: 'CommonTraitId' = 289187 - FOOD_PREFERENCE_INFANT_SMASHED_AVOCADO: 'CommonTraitId' = 289188 - FOOD_PREFERENCE_INFANT_SMASHED_LEMON: 'CommonTraitId' = 289189 - FOOD_PREFERENCE_INFANT_SWEET_POTATO_PUREE: 'CommonTraitId' = 289190 - FOOD_PREFERENCE_INFANT_YOGURT: 'CommonTraitId' = 289191 - FOOD_PREFERENCE_INFANT_YOGURT_MELTS: 'CommonTraitId' = 289276 - FOREST_GHOST: 'CommonTraitId' = 108313 - FOREST_GHOST_GLOOMY: 'CommonTraitId' = 108315 - FOREST_GHOST_GOOFY: 'CommonTraitId' = 108316 - FOREST_GHOST_MEAN: 'CommonTraitId' = 108317 - FOREVER_FRESH: 'CommonTraitId' = 183037 - FOREVER_FULL: 'CommonTraitId' = 183035 - FOX_ADULT: 'CommonTraitId' = 267313 - FOX_ELDER: 'CommonTraitId' = 267314 - FREEGAN: 'CommonTraitId' = 234414 - FREE_SERVICES: 'CommonTraitId' = 32110 - FRESH_CHEF: 'CommonTraitId' = 26199 - FRIENDSHIP_BRACELET_1_HIDDEN: 'CommonTraitId' = 320053 - FRIENDSHIP_BRACELET_2_HIDDEN: 'CommonTraitId' = 320054 - FRIENDSHIP_BRACELET_3_HIDDEN: 'CommonTraitId' = 320055 - FRIENDSHIP_BRACELET_4_HIDDEN: 'CommonTraitId' = 320052 - FRIENDSHIP_BRACELET_5_HIDDEN: 'CommonTraitId' = 319942 - FRIENDSHIP_BRACELET_NEEDS_CLEANUP_HIDDEN: 'CommonTraitId' = 329148 - FRIEND_OF_THE_SEA: 'CommonTraitId' = 206419 - FRUGAL: 'CommonTraitId' = 32111 - FTUE_CAREER_MINDED_INITIAL: 'CommonTraitId' = 200838 - FTUE_OVER_ACHIEVER: 'CommonTraitId' = 197728 - GAMEPLAY_MOUNTED_BUFFS: 'CommonTraitId' = 335365 - GEEK: 'CommonTraitId' = 16841 - GENDER_FEMALE: 'CommonTraitId' = 102448 - GENDER_MALE: 'CommonTraitId' = 102447 - GENDER_OPTIONS_ATTRACTED_TO_FEMALE: 'CommonTraitId' = 276492 - GENDER_OPTIONS_ATTRACTED_TO_MALE: 'CommonTraitId' = 276493 - GENDER_OPTIONS_ATTRACTED_TO_NOT_FEMALE: 'CommonTraitId' = 276494 - GENDER_OPTIONS_ATTRACTED_TO_NOT_MALE: 'CommonTraitId' = 276495 - GENDER_OPTIONS_CLOTHING_MENS_WEAR: 'CommonTraitId' = 136879 - GENDER_OPTIONS_CLOTHING_WOMENS_WEAR: 'CommonTraitId' = 136880 - GENDER_OPTIONS_FRAME_FEMININE: 'CommonTraitId' = 136878 - GENDER_OPTIONS_FRAME_MASCULINE: 'CommonTraitId' = 136877 - GENDER_OPTIONS_LACTATION_CANNOT_LACTATE: 'CommonTraitId' = 275052 - GENDER_OPTIONS_LACTATION_CAN_LACTATE: 'CommonTraitId' = 274985 - GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED: 'CommonTraitId' = 136875 - GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE: 'CommonTraitId' = 136874 - GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED: 'CommonTraitId' = 137716 - GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE: 'CommonTraitId' = 137717 - GENDER_OPTIONS_SEXUALITY_EXPLORING: 'CommonTraitId' = 276496 - GENDER_OPTIONS_SEXUALITY_NOT_EXPLORING: 'CommonTraitId' = 276497 - GENDER_OPTIONS_TOILET_SITTING: 'CommonTraitId' = 137718 - GENDER_OPTIONS_TOILET_STANDING: 'CommonTraitId' = 136876 - GENEROUS: 'CommonTraitId' = 341152 - GENIUS: 'CommonTraitId' = 27917 - GHOST_ANGER: 'CommonTraitId' = 101679 - GHOST_ANIMAL_OBJECTS_KILLER_CHICKEN: 'CommonTraitId' = 267992 - GHOST_ANIMAL_OBJECTS_KILLER_RABBIT: 'CommonTraitId' = 258168 - GHOST_BEETLE: 'CommonTraitId' = 235995 - GHOST_BROKEN_HEART: 'CommonTraitId' = 379066 - GHOST_CAULDRON_POTION_IMMORTALITY_FAILURE: 'CommonTraitId' = 214409 - GHOST_CLIMBING_ROUTE: 'CommonTraitId' = 250224 - GHOST_COW_PLANT: 'CommonTraitId' = 101704 - GHOST_CURSES_NIGHT_STALKER_STALKER: 'CommonTraitId' = 216314 - GHOST_DEATH_FLOWER: 'CommonTraitId' = 190748 - GHOST_DROWN: 'CommonTraitId' = 103599 - GHOST_ELDER_EXHAUSTION: 'CommonTraitId' = 101680 - GHOST_ELECTROCUTION: 'CommonTraitId' = 101681 - GHOST_EMBARRASSMENT: 'CommonTraitId' = 101682 - GHOST_FIRE: 'CommonTraitId' = 101676 - GHOST_FLIES: 'CommonTraitId' = 234848 - GHOST_FROZEN: 'CommonTraitId' = 182185 - GHOST_HUNGER: 'CommonTraitId' = 101683 - GHOST_LAUGHTER: 'CommonTraitId' = 101684 - GHOST_LIGHTNING: 'CommonTraitId' = 186331 - GHOST_METEORITE: 'CommonTraitId' = 294292 - GHOST_MOLD_SYSTEM: 'CommonTraitId' = 343869 - GHOST_MOTHER_PLANT: 'CommonTraitId' = 204157 - GHOST_MURPHY_BED: 'CommonTraitId' = 228335 - GHOST_OLD_AGE: 'CommonTraitId' = 101685 - GHOST_OVERHEAT: 'CommonTraitId' = 184951 - GHOST_POISON: 'CommonTraitId' = 176264 - GHOST_PUFFER_FISH: 'CommonTraitId' = 137461 - GHOST_RISEN: 'CommonTraitId' = 103032 - GHOST_RODENT_DISEASE: 'CommonTraitId' = 181918 - GHOST_SEANCE_TABLE: 'CommonTraitId' = 255360 - GHOST_STEAM: 'CommonTraitId' = 119951 - GHOST_STINK_BOMB: 'CommonTraitId' = 284364 - GHOST_URBAN_MYTH: 'CommonTraitId' = 284363 - GHOST_URBAN_MYTH_EP12: 'CommonTraitId' = 285905 - GHOST_VAMPIRE_SUN: 'CommonTraitId' = 151547 - GHOST_VENDING_MACHINE: 'CommonTraitId' = 249747 - GHOST_WITCH_OVERLOAD: 'CommonTraitId' = 216974 - GLOOMY: 'CommonTraitId' = 9332 - GLUTTON: 'CommonTraitId' = 16843 - GOOD: 'CommonTraitId' = 27915 - GOOFBALL: 'CommonTraitId' = 9337 - GRADE_SCHOOL_A: 'CommonTraitId' = 98698 - GRADE_SCHOOL_B: 'CommonTraitId' = 98699 - GRADE_SCHOOL_C: 'CommonTraitId' = 98700 - GRADE_SCHOOL_D: 'CommonTraitId' = 98701 - GRADE_SCHOOL_F: 'CommonTraitId' = 98702 - GREAT_KISSER: 'CommonTraitId' = 26686 - GREAT_STORYTELLER: 'CommonTraitId' = 103263 - GREEN_FIEND: 'CommonTraitId' = 231699 - GREGARIOUS: 'CommonTraitId' = 27087 - GYM_RAT: 'CommonTraitId' = 26427 - HANDEDNESS_LEFT: 'CommonTraitId' = 113589 - HANDEDNESS_RIGHT: 'CommonTraitId' = 113588 - HANDY_PERSON_GOLDEN_WRENCH: 'CommonTraitId' = 354602 - HAPPY_TODDLER: 'CommonTraitId' = 143145 - HARDLY_HUNGRY: 'CommonTraitId' = 26389 - HAS_MET_NANNY: 'CommonTraitId' = 143765 - HAS_MET_RANCH_HAND: 'CommonTraitId' = 339307 - HAS_VISITED_DEEP_WOODS: 'CommonTraitId' = 132285 - HAS_VISITED_FORGOTTEN_GROTTO: 'CommonTraitId' = 119496 - HAS_VISITED_SYLVAN_GLADE: 'CommonTraitId' = 119401 - HATES_CHILDREN: 'CommonTraitId' = 16844 - HATES_MAYO: 'CommonTraitId' = 267875 - HAUNTED_HOUSE_TEMPERANCE: 'CommonTraitId' = 256353 - HEART_TO_HEART: 'CommonTraitId' = 368493 - HEROIC_PRESENCE: 'CommonTraitId' = 238654 - HERO_OF_STRANGER_VILLE: 'CommonTraitId' = 204044 - HIDDEN_ACTOR_CAREER_AGENCY_AI_STAFFING: 'CommonTraitId' = 193399 - HIDDEN_ACTOR_CAREER_AGENCY_EVERYDAY_EXTRAS: 'CommonTraitId' = 193398 - HIDDEN_ACTOR_CAREER_AGENCY_GRAN: 'CommonTraitId' = 193401 - HIDDEN_ACTOR_CAREER_AGENCY_WELL_SUITED: 'CommonTraitId' = 193400 - HIDDEN_BASKETBALL_DREAM_BIG: 'CommonTraitId' = 145874 - HIDDEN_BEEN_KISSED: 'CommonTraitId' = 101390 - HIDDEN_BOWLED_PERFECT_LLAMA: 'CommonTraitId' = 162471 - HIDDEN_CAMPING: 'CommonTraitId' = 102265 - HIDDEN_CAREER_ACTIVIST_CAUSE_ECONOMY: 'CommonTraitId' = 135285 - HIDDEN_CAREER_ACTIVIST_CAUSE_ENVIRONMENT: 'CommonTraitId' = 135277 - HIDDEN_CAREER_ACTIVIST_CAUSE_JUSTICE: 'CommonTraitId' = 135288 - HIDDEN_CAREER_ACTIVIST_CAUSE_PEACE: 'CommonTraitId' = 135287 - HIDDEN_CAREER_ACTIVIST_CAUSE_TAX: 'CommonTraitId' = 135284 - HIDDEN_CAREER_ACTIVIST_HAS_CAUSE: 'CommonTraitId' = 136437 - HIDDEN_CAREER_ACTIVIST_POLITICAL_POSITION_LEFT: 'CommonTraitId' = 136608 - HIDDEN_CAREER_ACTIVIST_POLITICAL_POSITION_RIGHT: 'CommonTraitId' = 136609 - HIDDEN_CAREER_CRITIC_THRIFTY: 'CommonTraitId' = 139623 - HIDDEN_CAREER_CUSTOM: 'CommonTraitId' = 192698 - HIDDEN_CAREER_PAY_BOOSTS_2X: 'CommonTraitId' = 196731 - HIDDEN_CHALLENGE_POSITIVITY_COLLECTED_REWARD_1: 'CommonTraitId' = 198899 - HIDDEN_CHALLENGE_POSITIVITY_COLLECTED_REWARD_2: 'CommonTraitId' = 198900 - HIDDEN_CHALLENGE_POSITIVITY_COLLECTED_REWARD_3: 'CommonTraitId' = 198901 - HIDDEN_CHALLENGE_POSITIVITY_COLLECTED_REWARD_4: 'CommonTraitId' = 198902 - HIDDEN_CHILD_CANNOT_AGE_UP_DOES_NOT_PERSIST: 'CommonTraitId' = 116617 - HIDDEN_CLIMATE_CHANGE_WOKE: 'CommonTraitId' = 179869 - HIDDEN_DRAMA_CLUB: 'CommonTraitId' = 199635 - HIDDEN_DRAMA_CLUB_CRY_ON_DEMAND: 'CommonTraitId' = 201079 - HIDDEN_EAR_BUDS_MUSIC_LOVER_HAS_BEEN_GIVEN: 'CommonTraitId' = 166558 - HIDDEN_EMPLOYEE_QUIT: 'CommonTraitId' = 174483 - HIDDEN_EVENT_FALL_CHALLENGE_DO_TD_RECEIVED_SKULL_DISPLAY: 'CommonTraitId' = 153497 - HIDDEN_FAME_CELEBRITY_TILE_ACHIEVED: 'CommonTraitId' = 197536 - HIDDEN_FAME_QUIRK_STAR_TREATMENT: 'CommonTraitId' = 196358 - HIDDEN_FAVORITE_MOVIE_ACTION: 'CommonTraitId' = 128970 - HIDDEN_FAVORITE_MOVIE_COMEDY: 'CommonTraitId' = 128972 - HIDDEN_FAVORITE_MOVIE_FAMILY: 'CommonTraitId' = 128974 - HIDDEN_FAVORITE_MOVIE_HORROR: 'CommonTraitId' = 128971 - HIDDEN_FAVORITE_MOVIE_ROMANCE: 'CommonTraitId' = 128973 - HIDDEN_FIRST_SNOW: 'CommonTraitId' = 183661 - HIDDEN_FOOD_FESTIVAL_CURRY_CONTEST_WINNER: 'CommonTraitId' = 146178 - HIDDEN_HAD_FIGHT: 'CommonTraitId' = 101391 - HIDDEN_HAD_WOOHOO: 'CommonTraitId' = 101389 - HIDDEN_HAS_BEEN_SCIENTIST: 'CommonTraitId' = 131641 - HIDDEN_HAS_MONSTER_FRIEND: 'CommonTraitId' = 139186 - HIDDEN_HAS_RESEARCHED_RODENT_DISEASE: 'CommonTraitId' = 182224 - HIDDEN_HAS_TASTED_EXPERIMENTAL_FOOD: 'CommonTraitId' = 134072 - HIDDEN_HAS_ULTIMATE_SNOW_PAL: 'CommonTraitId' = 185954 - HIDDEN_HATES_FRUITCAKE: 'CommonTraitId' = 119187 - HIDDEN_HATES_FRUIT_CAKE_CONTROLLER: 'CommonTraitId' = 124839 - HIDDEN_IS_ADOPTION_OFFICER: 'CommonTraitId' = 175924 - HIDDEN_IS_DISGUISED: 'CommonTraitId' = 200510 - HIDDEN_IS_EVENT_NPC_CHALLENGE: 'CommonTraitId' = 133798 - HIDDEN_IS_EVENT_NPC_CHALLENGE_MBB: 'CommonTraitId' = 204280 - HIDDEN_IS_NATIVE: 'CommonTraitId' = 180954 - HIDDEN_IS_NATIVE_STRAY: 'CommonTraitId' = 181434 - HIDDEN_IS_NOT_DISGUISED: 'CommonTraitId' = 200511 - HIDDEN_JOINED_FIFTY_MILE_HIGH_CLUB: 'CommonTraitId' = 8612 - HIDDEN_JOINED_FIFTY_MILE_HIGH_CLUB_TEEN: 'CommonTraitId' = 100786 - HIDDEN_JUNGLE_WELCOME_PACKAGE_RECEIVED: 'CommonTraitId' = 183129 - HIDDEN_LANDLORD: 'CommonTraitId' = 133800 - HIDDEN_LIGHTHOUSE_CONCEPTION: 'CommonTraitId' = 172412 - HIDDEN_LIKES_FRUITCAKE: 'CommonTraitId' = 119186 - HIDDEN_NPC_IS_DJ: 'CommonTraitId' = 122820 - HIDDEN_PAINTING_MASTER: 'CommonTraitId' = 27014 - HIDDEN_PET_MINOR_CAGE_RODENT_DISEASE_IMMUNE: 'CommonTraitId' = 183401 - HIDDEN_PET_MINOR_CAGE_RODENT_DISEASE_REMOVED_COSTUME: 'CommonTraitId' = 185712 - HIDDEN_RECEIVED_EXPERIMENTAL_FOOD_TNS: 'CommonTraitId' = 143126 - HIDDEN_RESTAURANT_AT_WORK: 'CommonTraitId' = 144761 - HIDDEN_ROCKET_SHIP_HAS_WATCHED_ALIEN: 'CommonTraitId' = 103205 - HIDDEN_ROLE_STATE_VET_EMPLOYEE_CLEAN: 'CommonTraitId' = 178713 - HIDDEN_ROLE_STATE_VET_EMPLOYEE_DONT_CLEAN: 'CommonTraitId' = 178714 - HIDDEN_ROLE_STATE_VET_EMPLOYEE_DONT_TREAT: 'CommonTraitId' = 178716 - HIDDEN_ROLE_STATE_VET_EMPLOYEE_TREAT: 'CommonTraitId' = 178715 - HIDDEN_SKELETON: 'CommonTraitId' = 175972 - HIDDEN_SKELETON_SERVICE_SKELETON: 'CommonTraitId' = 177810 - HIDDEN_SKELETON_TEMPLE_SKELETON: 'CommonTraitId' = 178437 - HIDDEN_SPRING_CHALLENGE2016_GOT_GROW_FRUIT_STARTER: 'CommonTraitId' = 137247 - HIDDEN_SPRING_CHALLENGE_2016_GAVE_PRISTINE_GROW_FRUIT: 'CommonTraitId' = 135593 - HIDDEN_SPRING_CHALLENGE_2016_GAVE_X_GROW_FRUIT_COMPLETED: 'CommonTraitId' = 135551 - HIDDEN_SUPER_FERTILIZER_UNLOCK: 'CommonTraitId' = 109815 - HIDDEN_TEMPERATURE_PREFERENCE_COOL: 'CommonTraitId' = 179141 - HIDDEN_TEMPERATURE_PREFERENCE_WARM: 'CommonTraitId' = 179142 - HIDDEN_TREAD_MILL_CLIMBING_WALL_CHALLENGE_COMPLETE_1: 'CommonTraitId' = 167758 - HIDDEN_TREAD_MILL_CLIMBING_WALL_CHALLENGE_COMPLETE_2: 'CommonTraitId' = 167759 - HIDDEN_TREAD_MILL_CLIMBING_WALL_CHALLENGE_COMPLETE_3: 'CommonTraitId' = 167760 - HIDDEN_TREAD_MILL_CLIMBING_WALL_CHALLENGE_COMPLETE_4: 'CommonTraitId' = 167761 - HIDDEN_TREAD_MILL_CLIMBING_WALL_CHALLENGE_COMPLETE_5: 'CommonTraitId' = 167762 - HIDDEN_UNLOCKED_GRILLED_CHEESE_ASPIRATION: 'CommonTraitId' = 132500 - HIDDEN_UNLOCKED_POSITIVITY_CHALLENGE_ASPIRATION: 'CommonTraitId' = 198781 - HIDDEN_UNLOCK_CAMPING_SCULPTURE: 'CommonTraitId' = 108125 - HIDDEN_VAMPIRE_POWER_SUSCEPTIBILITY: 'CommonTraitId' = 151836 - HIDDEN_VAMPIRE_SPIRIT_POWERS_BAT_ENABLED: 'CommonTraitId' = 155860 - HIDDEN_VAMPIRE_SPIRIT_POWERS_MIST_ENABLED: 'CommonTraitId' = 155861 - HIDDEN_VAMPIRE_SPIRIT_POWERS_VAMPIRE_RUN_ENABLED: 'CommonTraitId' = 155862 - HIDDEN_VFX_MASK_CURSED: 'CommonTraitId' = 181193 - HIDDEN_WEATHER_RAIN_HATE: 'CommonTraitId' = 179138 - HIDDEN_WEATHER_RAIN_LOVE: 'CommonTraitId' = 179137 - HIDDEN_WEATHER_SNOW_HATE: 'CommonTraitId' = 179140 - HIDDEN_WEATHER_SNOW_LOVE: 'CommonTraitId' = 179139 - HIDDEN_WEATHER_SUN_HATE: 'CommonTraitId' = 179134 - HIDDEN_WEATHER_SUN_LOVE: 'CommonTraitId' = 179133 - HIDDEN_WEATHER_WIND_HATE: 'CommonTraitId' = 179136 - HIDDEN_WEATHER_WIND_LOVE: 'CommonTraitId' = 179135 - HIGH_FLIER: 'CommonTraitId' = 283144 - HIGH_MAINTENANCE: 'CommonTraitId' = 272336 - HIGH_METABOLISM: 'CommonTraitId' = 27080 - HIGH_SCHOOL_A: 'CommonTraitId' = 98707 - HIGH_SCHOOL_ACTIVE_HAD_ORIENTATION: 'CommonTraitId' = 276765 - HIGH_SCHOOL_ACTIVE_LEARNED_TPOSE_CHALLENGE: 'CommonTraitId' = 300531 - HIGH_SCHOOL_B: 'CommonTraitId' = 98706 - HIGH_SCHOOL_C: 'CommonTraitId' = 98705 - HIGH_SCHOOL_D: 'CommonTraitId' = 98704 - HIGH_SCHOOL_EXIT_DROPOUT: 'CommonTraitId' = 277741 - HIGH_SCHOOL_EXIT_EARNED_GED: 'CommonTraitId' = 291086 - HIGH_SCHOOL_EXIT_EXPELLED: 'CommonTraitId' = 277742 - HIGH_SCHOOL_EXIT_GRADUATE_EARLY: 'CommonTraitId' = 277740 - HIGH_SCHOOL_EXIT_GRADUATE_HONORS: 'CommonTraitId' = 277738 - HIGH_SCHOOL_EXIT_GRADUATE_VALEDICTORIAN: 'CommonTraitId' = 277739 - HIGH_SCHOOL_F: 'CommonTraitId' = 98703 - HIGH_SCHOOL_NPC_ASH_HARJO: 'CommonTraitId' = 301315 - HIGH_SCHOOL_NPC_CAFETERIA_WORKER: 'CommonTraitId' = 300519 - HIGH_SCHOOL_NPC_JANITOR: 'CommonTraitId' = 300488 - HIGH_SCHOOL_NPC_PRINCIPLE: 'CommonTraitId' = 300487 - HIGH_SCHOOL_NPC_TEACHER_1: 'CommonTraitId' = 300380 - HIGH_SCHOOL_NPC_TEACHER_2: 'CommonTraitId' = 300382 - HIGH_SCHOOL_NPC_THRIFT_STORE_OWNER: 'CommonTraitId' = 300384 - HIGH_SCHOO_ACTIVE_CLASS_1_STUDENT: 'CommonTraitId' = 293779 - HIGH_SKILL_FISHING: 'CommonTraitId' = 215146 - HILARIOUS: 'CommonTraitId' = 27170 - HOLIDAY_TRADITION_FATHER_WINTER: 'CommonTraitId' = 183343 - HOLIDAY_TRADITION_FATHER_WINTER_BABY: 'CommonTraitId' = 183361 - HOME_TURF: 'CommonTraitId' = 144199 - HORSE_AGE_ADULT: 'CommonTraitId' = 321082 - HORSE_AGE_CHILD: 'CommonTraitId' = 321081 - HORSE_AGE_ELDER: 'CommonTraitId' = 321083 - HORSE_COMPETITION_BARREL_RACING_BEGINNER_COMPLETE_HIDDEN: 'CommonTraitId' = 349913 - HORSE_COMPETITION_BARREL_RACING_EXPERT_COMPLETE_HIDDEN: 'CommonTraitId' = 349916 - HORSE_COMPETITION_BARREL_RACING_INTERMEDIATE_COMPLETE_HIDDEN: 'CommonTraitId' = 349919 - HORSE_COMPETITION_BARREL_RACING_MASTER_COMPLETE_HIDDEN: 'CommonTraitId' = 350467 - HORSE_COMPETITION_ENDURACE_RACING_BEGINNER_COMPLETE_HIDDEN: 'CommonTraitId' = 349922 - HORSE_COMPETITION_ENDURACE_RACING_EXPERT_COMPLETE_HIDDEN: 'CommonTraitId' = 349923 - HORSE_COMPETITION_ENDURACE_RACING_INTERMEDIATE_COMPLETE_HIDDEN: 'CommonTraitId' = 349924 - HORSE_COMPETITION_ENDURACE_RACING_MASTER_COMPLETE_HIDDEN: 'CommonTraitId' = 350468 - HORSE_COMPETITION_SHOW_JUMPING_BEGINNER_COMPLETE_HIDDEN: 'CommonTraitId' = 349926 - HORSE_COMPETITION_SHOW_JUMPING_EXPERT_COMPLETE_HIDDEN: 'CommonTraitId' = 349927 - HORSE_COMPETITION_SHOW_JUMPING_INTERMEDIATE_COMPLETE_HIDDEN: 'CommonTraitId' = 349928 - HORSE_COMPETITION_SHOW_JUMPING_MASTER_COMPLETE_HIDDEN: 'CommonTraitId' = 350469 - HORSE_COMPETITION_WESTERN_PLEASURE_BEGINNER_COMPLETE_HIDDEN: 'CommonTraitId' = 349931 - HORSE_COMPETITION_WESTERN_PLEASURE_EXPERT_COMPLETE_HIDDEN: 'CommonTraitId' = 349932 - HORSE_COMPETITION_WESTERN_PLEASURE_INTERMEDIATE_COMPLETE_HIDDEN: 'CommonTraitId' = 349933 - HORSE_COMPETITION_WESTERN_PLEASURE_MASTER_COMPLETE_HIDDEN: 'CommonTraitId' = 350470 - HORSE_GAMEPLAY_CURIOUS: 'CommonTraitId' = 323854 - HORSE_GAMEPLAY_EQUESTRIAN_CENTER_CHAMPION_HORSE: 'CommonTraitId' = 331651 - HORSE_GAMEPLAY_HORSE_BREEDING_CHAMPION_GENES: 'CommonTraitId' = 323125 - HORSE_GAMEPLAY_MOUNTED_BUFFS_REINS_MODIFIER: 'CommonTraitId' = 335364 - HORSE_GAMEPLAY_PLAYFUL: 'CommonTraitId' = 322884 - HORSE_GAMEPLAY_RESILIENT: 'CommonTraitId' = 327598 - HORSE_GAMEPLAY_REWARD_TRAIT_TOP_NOTCH_FOAL: 'CommonTraitId' = 330841 - HORSE_HORSE_COMPETITION_BARREL_RACING_BEGINNER_1ST: 'CommonTraitId' = 332577 - HORSE_HORSE_COMPETITION_BARREL_RACING_BEGINNER_2ND: 'CommonTraitId' = 332605 - HORSE_HORSE_COMPETITION_BARREL_RACING_BEGINNER_3RD: 'CommonTraitId' = 332606 - HORSE_HORSE_COMPETITION_BARREL_RACING_EXPERT_1ST: 'CommonTraitId' = 332610 - HORSE_HORSE_COMPETITION_BARREL_RACING_EXPERT_2ND: 'CommonTraitId' = 332611 - HORSE_HORSE_COMPETITION_BARREL_RACING_EXPERT_3RD: 'CommonTraitId' = 332612 - HORSE_HORSE_COMPETITION_BARREL_RACING_INTERMEDIATE_1ST: 'CommonTraitId' = 332607 - HORSE_HORSE_COMPETITION_BARREL_RACING_INTERMEDIATE_2ND: 'CommonTraitId' = 332608 - HORSE_HORSE_COMPETITION_BARREL_RACING_INTERMEDIATE_3RD: 'CommonTraitId' = 332609 - HORSE_HORSE_COMPETITION_BARREL_RACING_MASTER_1ST: 'CommonTraitId' = 332613 - HORSE_HORSE_COMPETITION_BARREL_RACING_MASTER_2ND: 'CommonTraitId' = 332614 - HORSE_HORSE_COMPETITION_BARREL_RACING_MASTER_3RD: 'CommonTraitId' = 332615 - HORSE_HORSE_COMPETITION_ENDURANCE_RACING_BEGINNER_1ST: 'CommonTraitId' = 332630 - HORSE_HORSE_COMPETITION_ENDURANCE_RACING_BEGINNER_2ND: 'CommonTraitId' = 332631 - HORSE_HORSE_COMPETITION_ENDURANCE_RACING_BEGINNER_3RD: 'CommonTraitId' = 332632 - HORSE_HORSE_COMPETITION_ENDURANCE_RACING_EXPERT_1ST: 'CommonTraitId' = 332636 - HORSE_HORSE_COMPETITION_ENDURANCE_RACING_EXPERT_2ND: 'CommonTraitId' = 332637 - HORSE_HORSE_COMPETITION_ENDURANCE_RACING_EXPERT_3RD: 'CommonTraitId' = 332638 - HORSE_HORSE_COMPETITION_ENDURANCE_RACING_INTERMEDIATE_1ST: 'CommonTraitId' = 332633 - HORSE_HORSE_COMPETITION_ENDURANCE_RACING_INTERMEDIATE_2ND: 'CommonTraitId' = 332634 - HORSE_HORSE_COMPETITION_ENDURANCE_RACING_INTERMEDIATE_3RD: 'CommonTraitId' = 332635 - HORSE_HORSE_COMPETITION_ENDURANCE_RACING_MASTER_1ST: 'CommonTraitId' = 332639 - HORSE_HORSE_COMPETITION_ENDURANCE_RACING_MASTER_2ND: 'CommonTraitId' = 332640 - HORSE_HORSE_COMPETITION_ENDURANCE_RACING_MASTER_3RD: 'CommonTraitId' = 332641 - HORSE_HORSE_COMPETITION_NO_COMPETITIONS_WON: 'CommonTraitId' = 332655 - HORSE_HORSE_COMPETITION_SHOW_JUMPING_BEGINNER_1ST: 'CommonTraitId' = 332617 - HORSE_HORSE_COMPETITION_SHOW_JUMPING_BEGINNER_2ND: 'CommonTraitId' = 332618 - HORSE_HORSE_COMPETITION_SHOW_JUMPING_BEGINNER_3RD: 'CommonTraitId' = 332619 - HORSE_HORSE_COMPETITION_SHOW_JUMPING_EXPERT_1ST: 'CommonTraitId' = 332623 - HORSE_HORSE_COMPETITION_SHOW_JUMPING_EXPERT_2ND: 'CommonTraitId' = 332624 - HORSE_HORSE_COMPETITION_SHOW_JUMPING_EXPERT_3RD: 'CommonTraitId' = 332625 - HORSE_HORSE_COMPETITION_SHOW_JUMPING_INTERMEDIATE_1ST: 'CommonTraitId' = 332620 - HORSE_HORSE_COMPETITION_SHOW_JUMPING_INTERMEDIATE_2ND: 'CommonTraitId' = 332621 - HORSE_HORSE_COMPETITION_SHOW_JUMPING_INTERMEDIATE_3RD: 'CommonTraitId' = 332622 - HORSE_HORSE_COMPETITION_SHOW_JUMPING_MASTER_1ST: 'CommonTraitId' = 332626 - HORSE_HORSE_COMPETITION_SHOW_JUMPING_MASTER_2ND: 'CommonTraitId' = 332627 - HORSE_HORSE_COMPETITION_SHOW_JUMPING_MASTER_3RD: 'CommonTraitId' = 332628 - HORSE_HORSE_COMPETITION_ULTIMATE_CHAMPIONSHIP_1ST: 'CommonTraitId' = 334426 - HORSE_HORSE_COMPETITION_ULTIMATE_CHAMPIONSHIP_2ND: 'CommonTraitId' = 334427 - HORSE_HORSE_COMPETITION_ULTIMATE_CHAMPIONSHIP_3RD: 'CommonTraitId' = 334428 - HORSE_HORSE_COMPETITION_WESTERN_PLEASURE_BEGINNER_1ST: 'CommonTraitId' = 332643 - HORSE_HORSE_COMPETITION_WESTERN_PLEASURE_BEGINNER_2ND: 'CommonTraitId' = 332644 - HORSE_HORSE_COMPETITION_WESTERN_PLEASURE_BEGINNER_3RD: 'CommonTraitId' = 332645 - HORSE_HORSE_COMPETITION_WESTERN_PLEASURE_EXPERT_1ST: 'CommonTraitId' = 332649 - HORSE_HORSE_COMPETITION_WESTERN_PLEASURE_EXPERT_2ND: 'CommonTraitId' = 332650 - HORSE_HORSE_COMPETITION_WESTERN_PLEASURE_EXPERT_3RD: 'CommonTraitId' = 332651 - HORSE_HORSE_COMPETITION_WESTERN_PLEASURE_INTERMEDIATE_1ST: 'CommonTraitId' = 332646 - HORSE_HORSE_COMPETITION_WESTERN_PLEASURE_INTERMEDIATE_2ND: 'CommonTraitId' = 332647 - HORSE_HORSE_COMPETITION_WESTERN_PLEASURE_INTERMEDIATE_3RD: 'CommonTraitId' = 332648 - HORSE_HORSE_COMPETITION_WESTERN_PLEASURE_MASTER_1ST: 'CommonTraitId' = 332652 - HORSE_HORSE_COMPETITION_WESTERN_PLEASURE_MASTER_2ND: 'CommonTraitId' = 332653 - HORSE_HORSE_COMPETITION_WESTERN_PLEASURE_MASTER_3RD: 'CommonTraitId' = 332654 - HORSE_HORSE_TRANSACTION_RESCUE_HIDDEN: 'CommonTraitId' = 342879 - HORSE_LOVER: 'CommonTraitId' = 320965 - HORSE_PERSONALITY_AGGRESSIVE: 'CommonTraitId' = 323824 - HORSE_PERSONALITY_BRAVE: 'CommonTraitId' = 322830 - HORSE_PERSONALITY_DEFIANT: 'CommonTraitId' = 323821 - HORSE_PERSONALITY_ENERGETIC: 'CommonTraitId' = 322878 - HORSE_PERSONALITY_FEARFUL: 'CommonTraitId' = 322834 - HORSE_PERSONALITY_FREESPIRIT: 'CommonTraitId' = 323822 - HORSE_PERSONALITY_FRIENDLY: 'CommonTraitId' = 322836 - HORSE_PERSONALITY_INDEPENDENT: 'CommonTraitId' = 323823 - HORSE_PERSONALITY_INTELLIGENT: 'CommonTraitId' = 322882 - HORSE_PERSONALITY_MELLOW: 'CommonTraitId' = 322880 - HORSE_PERSONALITY_NEEDY: 'CommonTraitId' = 327817 - HOT_HEADED: 'CommonTraitId' = 16845 - HUMANOID_ROBOT_BEHAVIOR_MODULES_CHILD_CARE_ACTIVE: 'CommonTraitId' = 218976 - HUMANOID_ROBOT_BEHAVIOR_MODULES_CHILD_CARE_LEARNED: 'CommonTraitId' = 224700 - HUMANOID_ROBOT_BEHAVIOR_MODULES_CHILD_CARE_NOT_LEARNED: 'CommonTraitId' = 221933 - HUMANOID_ROBOT_BEHAVIOR_MODULES_CHILD_CARE_TRIGGER_UNLOCK: 'CommonTraitId' = 224686 - HUMANOID_ROBOT_BEHAVIOR_MODULES_CLEANING_ACTIVE: 'CommonTraitId' = 218970 - HUMANOID_ROBOT_BEHAVIOR_MODULES_CLEANING_LEARNED: 'CommonTraitId' = 224694 - HUMANOID_ROBOT_BEHAVIOR_MODULES_CLEANING_NOT_LEARNED: 'CommonTraitId' = 221934 - HUMANOID_ROBOT_BEHAVIOR_MODULES_CLEANING_TRIGGER_UNLOCK: 'CommonTraitId' = 224680 - HUMANOID_ROBOT_BEHAVIOR_MODULES_GARDENING_ACTIVE: 'CommonTraitId' = 218972 - HUMANOID_ROBOT_BEHAVIOR_MODULES_GARDENING_LEARNED: 'CommonTraitId' = 224696 - HUMANOID_ROBOT_BEHAVIOR_MODULES_GARDENING_NOT_LEARNED: 'CommonTraitId' = 221936 - HUMANOID_ROBOT_BEHAVIOR_MODULES_GARDENING_TRIGGER_UNLOCK: 'CommonTraitId' = 224687 - HUMANOID_ROBOT_BEHAVIOR_MODULES_PARTY_ACTIVE: 'CommonTraitId' = 219663 - HUMANOID_ROBOT_BEHAVIOR_MODULES_PARTY_LEARNED: 'CommonTraitId' = 224697 - HUMANOID_ROBOT_BEHAVIOR_MODULES_PARTY_NOT_LEARNED: 'CommonTraitId' = 221937 - HUMANOID_ROBOT_BEHAVIOR_MODULES_PARTY_TRIGGER_UNLOCK: 'CommonTraitId' = 224688 - HUMANOID_ROBOT_BEHAVIOR_MODULES_REPAIR_ACTIVE: 'CommonTraitId' = 218973 - HUMANOID_ROBOT_BEHAVIOR_MODULES_REPAIR_LEARNED: 'CommonTraitId' = 224698 - HUMANOID_ROBOT_BEHAVIOR_MODULES_REPAIR_NOT_LEARNED: 'CommonTraitId' = 221938 - HUMANOID_ROBOT_BEHAVIOR_MODULES_REPAIR_TRIGGER_UNLOCK: 'CommonTraitId' = 224689 - HUMANOID_ROBOT_BEHAVIOR_MODULES_SECURITY_ACTIVE: 'CommonTraitId' = 218974 - HUMANOID_ROBOT_BEHAVIOR_MODULES_SECURITY_LEARNED: 'CommonTraitId' = 224699 - HUMANOID_ROBOT_BEHAVIOR_MODULES_SECURITY_NOT_LEARNED: 'CommonTraitId' = 221939 - HUMANOID_ROBOT_BEHAVIOR_MODULES_SECURITY_TRIGGER_UNLOCK: 'CommonTraitId' = 224682 - HUMANOID_ROBOT_ENHANCEMENT_LEVEL_1: 'CommonTraitId' = 219911 - HUMANOID_ROBOT_ENHANCEMENT_LEVEL_10: 'CommonTraitId' = 219910 - HUMANOID_ROBOT_ENHANCEMENT_LEVEL_2: 'CommonTraitId' = 219912 - HUMANOID_ROBOT_ENHANCEMENT_LEVEL_3: 'CommonTraitId' = 219913 - HUMANOID_ROBOT_ENHANCEMENT_LEVEL_4: 'CommonTraitId' = 219914 - HUMANOID_ROBOT_ENHANCEMENT_LEVEL_5: 'CommonTraitId' = 219915 - HUMANOID_ROBOT_ENHANCEMENT_LEVEL_6: 'CommonTraitId' = 219916 - HUMANOID_ROBOT_ENHANCEMENT_LEVEL_7: 'CommonTraitId' = 219917 - HUMANOID_ROBOT_ENHANCEMENT_LEVEL_8: 'CommonTraitId' = 219918 - HUMANOID_ROBOT_ENHANCEMENT_LEVEL_9: 'CommonTraitId' = 219919 - HUMANOID_ROBOT_HOVER: 'CommonTraitId' = 229578 - HUMANOID_ROBOT_OUTFIT_BEIGE_WHITE: 'CommonTraitId' = 228855 - HUMANOID_ROBOT_OUTFIT_BLACK_BLUE: 'CommonTraitId' = 228856 - HUMANOID_ROBOT_OUTFIT_BLUE_RED: 'CommonTraitId' = 228858 - HUMANOID_ROBOT_OUTFIT_GRAY_BROWN: 'CommonTraitId' = 228857 - HUMANOID_ROBOT_OUTFIT_GREEN_BROWN: 'CommonTraitId' = 228859 - HUMANOID_ROBOT_OUTFIT_RED_GREEN: 'CommonTraitId' = 228860 - HUMANOID_ROBOT_OUTFIT_WHITE_COPPER: 'CommonTraitId' = 228861 - ICONIC: 'CommonTraitId' = 282899 - IDENTIFIED_CHAMOMILE: 'CommonTraitId' = 104486 - IDENTIFIED_CHAMOMILE_TOXIC: 'CommonTraitId' = 104487 - IDENTIFIED_ELDERBERRY: 'CommonTraitId' = 104480 - IDENTIFIED_ELDERBERRY_TOXIC: 'CommonTraitId' = 104481 - IDENTIFIED_FIRE_LEAF: 'CommonTraitId' = 104484 - IDENTIFIED_FIRE_LEAF_TOXIC: 'CommonTraitId' = 104485 - IDENTIFIED_HUCKLEBERRY: 'CommonTraitId' = 104482 - IDENTIFIED_HUCKLEBERRY_TOXIC: 'CommonTraitId' = 104483 - IDENTIFIED_MOREL: 'CommonTraitId' = 104488 - IDENTIFIED_MOREL_TOXIC: 'CommonTraitId' = 104489 - INCREDIBLY_FRIENDLY: 'CommonTraitId' = 102783 - INDEPENDENT: 'CommonTraitId' = 26393 - INFANT: 'CommonTraitId' = 266297 - INFANT_CALM: 'CommonTraitId' = 273755 - INFANT_CAUTIOUS: 'CommonTraitId' = 273756 - INFANT_INTENSE: 'CommonTraitId' = 273757 - INFANT_MILESTONE_BG_UNLOCK_CORE_HIDDEN: 'CommonTraitId' = 289863 - INFANT_MILESTONE_BG_UNLOCK_FIRST_BATH_HIDDEN: 'CommonTraitId' = 287069 - INFANT_MILESTONE_BG_UNLOCK_FIRST_BLOWOUT_HIDDEN: 'CommonTraitId' = 321444 - INFANT_MILESTONE_BG_UNLOCK_FIRST_BUBBLE_BATH_HIDDEN: 'CommonTraitId' = 287070 - INFANT_MILESTONE_BG_UNLOCK_FIRST_FOOD_HIDDEN: 'CommonTraitId' = 287066 - INFANT_MILESTONE_BG_UNLOCK_FIRST_TRIP_TO_PARK_HIDDEN: 'CommonTraitId' = 287072 - INFANT_MILESTONE_BG_UNLOCK_FIRST_VACATION_HIDDEN: 'CommonTraitId' = 287073 - INFANT_MILESTONE_BG_UNLOCK_FIRST_VISITORS_HIDDEN: 'CommonTraitId' = 287071 - INFANT_MILESTONE_BG_UNLOCK_FIRST_VISIT_TO_FAMILY_HIDDEN: 'CommonTraitId' = 287074 - INFANT_MILESTONE_BG_UNLOCK_PEES_ON_PARENT_HIDDEN: 'CommonTraitId' = 287068 - INFANT_MILESTONE_CAN_CRAWL_HIDDEN: 'CommonTraitId' = 322737 - INFANT_MILESTONE_CLAP_HIDDEN: 'CommonTraitId' = 291534 - INFANT_MILESTONE_COO_HIDDEN: 'CommonTraitId' = 291535 - INFANT_MILESTONE_IMMOBILE_HIDDEN: 'CommonTraitId' = 291557 - INFANT_MILESTONE_LAUGH_HIDDEN: 'CommonTraitId' = 291533 - INFANT_MILESTONE_SIT_UP_HIDDEN: 'CommonTraitId' = 287588 - INFANT_MILESTONE_SLEPT_THROUGH_NIGHT_HIDDEN: 'CommonTraitId' = 331334 - INFANT_PERSONALITY_FREQUENTLY_HICCUPS_HIDDEN: 'CommonTraitId' = 286064 - INFANT_PERSONALITY_FREQUENTLY_HICCUPS_VISIBLE: 'CommonTraitId' = 319874 - INFANT_PERSONALITY_FREQUENTLY_SNEEZES_HIDDEN: 'CommonTraitId' = 286065 - INFANT_PERSONALITY_FREQUENTLY_SNEEZES_VISIBLE: 'CommonTraitId' = 319875 - INFANT_PERSONALITY_GASSY_HIDDEN: 'CommonTraitId' = 286074 - INFANT_PERSONALITY_GASSY_VISIBLE: 'CommonTraitId' = 319914 - INFANT_PERSONALITY_GOOD_APPETITE_HIDDEN: 'CommonTraitId' = 286075 - INFANT_PERSONALITY_GOOD_APPETITE_VISIBLE: 'CommonTraitId' = 319915 - INFANT_PERSONALITY_HAPPY_SPITTER_HIDDEN: 'CommonTraitId' = 286076 - INFANT_PERSONALITY_HAPPY_SPITTER_VISIBLE: 'CommonTraitId' = 319916 - INFANT_PERSONALITY_HATES_BEING_HELD_HIDDEN: 'CommonTraitId' = 286077 - INFANT_PERSONALITY_HATES_BEING_HELD_VISIBLE: 'CommonTraitId' = 319917 - INFANT_PERSONALITY_HATES_WAKING_UP_HIDDEN: 'CommonTraitId' = 286078 - INFANT_PERSONALITY_HATES_WAKING_UP_VISIBLE: 'CommonTraitId' = 319918 - INFANT_PERSONALITY_LOVES_BEING_HELD_HIDDEN: 'CommonTraitId' = 286079 - INFANT_PERSONALITY_LOVES_BEING_HELD_VISIBLE: 'CommonTraitId' = 319919 - INFANT_PERSONALITY_LOVES_WAKING_UP_HIDDEN: 'CommonTraitId' = 286080 - INFANT_PERSONALITY_LOVES_WAKING_UP_VISIBLE: 'CommonTraitId' = 319920 - INFANT_PERSONALITY_MESSY_EATER_HIDDEN: 'CommonTraitId' = 286081 - INFANT_PERSONALITY_MESSY_EATER_VISIBLE: 'CommonTraitId' = 319921 - INFANT_PERSONALITY_OBSESSED_WITH_SOUND_HIDDEN: 'CommonTraitId' = 286073 - INFANT_PERSONALITY_OBSESSED_WITH_SOUND_VISIBLE: 'CommonTraitId' = 319876 - INFANT_PERSONALITY_ONLY_SLEEPS_WHEN_HELD_HIDDEN: 'CommonTraitId' = 286072 - INFANT_PERSONALITY_ONLY_SLEEPS_WHEN_HELD_VISIBLE: 'CommonTraitId' = 319877 - INFANT_PERSONALITY_PEES_DURING_CHANGES_HIDDEN: 'CommonTraitId' = 286071 - INFANT_PERSONALITY_PEES_DURING_CHANGES_VISIBLE: 'CommonTraitId' = 319878 - INFANT_PERSONALITY_PEES_DURING_FEEDING_HIDDEN: 'CommonTraitId' = 286070 - INFANT_PERSONALITY_PEES_DURING_FEEDING_VISIBLE: 'CommonTraitId' = 319879 - INFANT_PERSONALITY_PICKY_EATER_HIDDEN: 'CommonTraitId' = 286069 - INFANT_PERSONALITY_PICKY_EATER_VISIBLE: 'CommonTraitId' = 319880 - INFANT_PERSONALITY_RISES_WITH_THE_SUN_HIDDEN: 'CommonTraitId' = 286067 - INFANT_PERSONALITY_RISES_WITH_THE_SUN_VISIBLE: 'CommonTraitId' = 319881 - INFANT_PERSONALITY_SELF_SOOTHER_HIDDEN: 'CommonTraitId' = 286066 - INFANT_PERSONALITY_SELF_SOOTHER_VISIBLE: 'CommonTraitId' = 319912 - INFANT_PERSONALITY_TALKER_HIDDEN: 'CommonTraitId' = 286068 - INFANT_PERSONALITY_TALKER_VISIBLE: 'CommonTraitId' = 319913 - INFANT_SENSITIVE: 'CommonTraitId' = 273758 - INFANT_SUNNY: 'CommonTraitId' = 273759 - INFANT_WIGGLY: 'CommonTraitId' = 273760 - INSANE: 'CommonTraitId' = 16848 - INSIDER: 'CommonTraitId' = 125437 - INTERIOR_DECORATOR_CLIENT_COOLDOWN: 'CommonTraitId' = 265334 - INTERIOR_DECORATOR_CLIENT_FOLLOW_UP_GIG_NEGATIVE: 'CommonTraitId' = 265375 - INTERIOR_DECORATOR_CLIENT_FOLLOW_UP_GIG_POSITIVE: 'CommonTraitId' = 265376 - INTERIOR_DECORATOR_CLIENT_FOLLOW_UP_GIG_REFERRED: 'CommonTraitId' = 265374 - INTERIOR_DECORATOR_HIDE_CLIENTS: 'CommonTraitId' = 261858 - INTRO_TO_VAMPIRE_CALLER: 'CommonTraitId' = 154812 - INVESTED: 'CommonTraitId' = 27942 - IN_THE_KNOW: 'CommonTraitId' = 144978 - ISLANDER_CULTURE_ISLANDER: 'CommonTraitId' = 208611 - IS_ALIEN_POLLINATOR: 'CommonTraitId' = 112688 - IS_BEAR: 'CommonTraitId' = 104472 - IS_BORN_FROM_ALIEN_ABDUCTION: 'CommonTraitId' = 102922 - IS_BUTLER: 'CommonTraitId' = 147121 - IS_CHALET_GARDENS_GHOST: 'CommonTraitId' = 125534 - IS_CITY_REPAIR: 'CommonTraitId' = 155997 - IS_CUSTOM_GENDER: 'CommonTraitId' = 136866 - IS_FIREFIGHTER: 'CommonTraitId' = 237784 - IS_FOREST_RANGER: 'CommonTraitId' = 108760 - IS_GARDENER: 'CommonTraitId' = 196904 - IS_GARDENER_SERVICE: 'CommonTraitId' = 130541 - IS_GRIM_REAPER: 'CommonTraitId' = 16851 - IS_IN_COLLEGE_ORGANIZATION: 'CommonTraitId' = 210946 - IS_LAND_ANCESTOR_ELEMENTAL: 'CommonTraitId' = 211645 - IS_MAID: 'CommonTraitId' = 16852 - IS_MAILMAN: 'CommonTraitId' = 16853 - IS_MASSAGE_THERAPIST: 'CommonTraitId' = 119668 - IS_MASTER_FISHERMAN: 'CommonTraitId' = 40467 - IS_MASTER_GARDENER: 'CommonTraitId' = 40359 - IS_MASTER_HERBALIST: 'CommonTraitId' = 101850 - IS_NANNY: 'CommonTraitId' = 141854 - IS_PIZZA_DELIVERY: 'CommonTraitId' = 10581 - IS_PLANT_SIM_NPC: 'CommonTraitId' = 164296 - IS_PREGNANT: 'CommonTraitId' = 16854 - IS_PREGNANT_ALIEN_ABDUCTION: 'CommonTraitId' = 139579 - IS_PREMADE_PO: 'CommonTraitId' = 350528 - IS_RANCH_HAND: 'CommonTraitId' = 303813 - IS_REPAIR: 'CommonTraitId' = 129480 - IS_RESTAURANT_CRITIC: 'CommonTraitId' = 139513 - IS_SCHOOL_GHOST: 'CommonTraitId' = 229389 - IS_STATUE_BUSKER: 'CommonTraitId' = 155999 - IS_TRAGIC_CLOWN: 'CommonTraitId' = 139879 - IS_WEIRDO: 'CommonTraitId' = 155998 - JEALOUS: 'CommonTraitId' = 124879 - JOB_LOSS_IN_LAY_OFF_PERIOD: 'CommonTraitId' = 306064 - JUNGLE_EXPLORER_TREASURE_HUNTER: 'CommonTraitId' = 178994 - JUNGLE_EXPLORER_TREASURE_HUNTER_BG: 'CommonTraitId' = 194391 - KEEPSAKE_BOX_DESIGNATED_HIDDEN: 'CommonTraitId' = 322584 - KIDS_BIKE_CANT_RIDE: 'CommonTraitId' = 305615 - KIDS_BIKE_CAN_RIDE: 'CommonTraitId' = 305620 - KLEPTOMANIAC: 'CommonTraitId' = 131783 - KNITTING_GIFTED_GRIM: 'CommonTraitId' = 243910 - KNOWLEDGE_SLINGER_OF_SPELLS: 'CommonTraitId' = 217373 - LACTOSE_INTOLERANT: 'CommonTraitId' = 257367 - LAZY: 'CommonTraitId' = 9599 - LEGENDARY: 'CommonTraitId' = 27091 - LIFESTYLE_ADRENALINE_SEEKER: 'CommonTraitId' = 248829 - LIFESTYLE_CLOSE_KNIT: 'CommonTraitId' = 248617 - LIFESTYLE_COFFEE_FANATIC: 'CommonTraitId' = 246515 - LIFESTYLE_ENERGETIC: 'CommonTraitId' = 248151 - LIFESTYLE_FREQUENT_TRAVELER: 'CommonTraitId' = 246345 - LIFESTYLE_HEALTH_FOOD_NUT: 'CommonTraitId' = 247602 - LIFESTYLE_HUNGRY_FOR_HUMAN_LOVE: 'CommonTraitId' = 250662 - LIFESTYLE_INDOORSY: 'CommonTraitId' = 248830 - LIFESTYLE_JUNK_FOOD_DEVOURER: 'CommonTraitId' = 247603 - LIFESTYLE_NETWORKER: 'CommonTraitId' = 248616 - LIFESTYLE_NO_NEED_FOR_HUMAN_ROMANCE: 'CommonTraitId' = 250661 - LIFESTYLE_OUTDOORSY: 'CommonTraitId' = 248831 - LIFESTYLE_SEDENTARY: 'CommonTraitId' = 248133 - LIFESTYLE_TECHIE: 'CommonTraitId' = 246953 - LIFESTYLE_TECHNOPHOBE: 'CommonTraitId' = 246952 - LIFESTYLE_WORKAHOLIC: 'CommonTraitId' = 245828 - LIFE_SKILLS_ARGUMENTATIVE: 'CommonTraitId' = 161628 - LIFE_SKILLS_BAD_MANNERS: 'CommonTraitId' = 160848 - LIFE_SKILLS_COMPASSIONATE: 'CommonTraitId' = 160862 - LIFE_SKILLS_EMOTIONAL_CONTROL: 'CommonTraitId' = 160275 - LIFE_SKILLS_GOOD_MANNERS: 'CommonTraitId' = 160841 - LIFE_SKILLS_IRRESPONSIBLE: 'CommonTraitId' = 161626 - LIFE_SKILLS_MEDIATOR: 'CommonTraitId' = 161627 - LIFE_SKILLS_RESPONSIBLE: 'CommonTraitId' = 161625 - LIFE_SKILLS_UNCONTROLLED_EMOTION: 'CommonTraitId' = 160265 - LIFE_SKILLS_UNFEELING: 'CommonTraitId' = 160954 - LIKES_MAYO: 'CommonTraitId' = 267876 - LIVING_VICARIOUSLY: 'CommonTraitId' = 29837 - LONER: 'CommonTraitId' = 9602 - LONGEVITY: 'CommonTraitId' = 27081 - LOT_TRAIT_SIMPLE_LIVING_COOK_BOOK: 'CommonTraitId' = 268277 - LOVESTRUCK: 'CommonTraitId' = 362090 - LOVES_OUTDOORS: 'CommonTraitId' = 27914 - LOVE_EXPLORER: 'CommonTraitId' = 367987 - LOVE_GURU: 'CommonTraitId' = 146648 - LOVE_POLY: 'CommonTraitId' = 367988 - LOYAL: 'CommonTraitId' = 311267 - MAGIC_DARREL_CHARM: 'CommonTraitId' = 220515 - MAGIC_EMILIA_ERNEST: 'CommonTraitId' = 220554 - MAGIC_GEMMA_CHARM: 'CommonTraitId' = 220555 - MAGIC_GRACE_ANANSI: 'CommonTraitId' = 220816 - MAGIC_MARKET_STALL_SPECTRAL_LOOK: 'CommonTraitId' = 217017 - MAGIC_MINERVA_CHARM: 'CommonTraitId' = 220508 - MAGIC_PERKS_MAGIC_VENUE_NPC: 'CommonTraitId' = 219098 - MAGIC_POTIONS_INTERMEDIATE: 'CommonTraitId' = 218530 - MAGIC_POTIONS_NOVICE: 'CommonTraitId' = 218532 - MAGIC_POTIONS_SAGE: 'CommonTraitId' = 218531 - MAGIC_SAGE_MISCHIEF: 'CommonTraitId' = 212849 - MAGIC_SAGE_PRACTICAL: 'CommonTraitId' = 212850 - MAGIC_SAGE_UNTAMED: 'CommonTraitId' = 212851 - MAGIC_SPELLS_MAGIC_SAGE_MISCHIEF: 'CommonTraitId' = 215988 - MAGIC_SPELLS_MAGIC_SAGE_PRACTICAL: 'CommonTraitId' = 215989 - MAGIC_SPELLS_MAGIC_SAGE_UNTAMED: 'CommonTraitId' = 215987 - MAGIC_SPELLS_MAGIC_VENUE_NPC_INTERMEDIATE: 'CommonTraitId' = 215986 - MAGIC_SPELLS_MAGIC_VENUE_NPC_NOVICE: 'CommonTraitId' = 215984 - MAGIC_TOMAX_COLLETTE: 'CommonTraitId' = 220818 - MAKER: 'CommonTraitId' = 230745 - MAKE_PREGNANT: 'CommonTraitId' = 238592 - MARKETABLE: 'CommonTraitId' = 31924 - MASTERMIND: 'CommonTraitId' = 27184 - MASTER_MAKER: 'CommonTraitId' = 231700 - MASTER_TRAINER: 'CommonTraitId' = 321397 - MATCHMAKING_DISABLED_HIDDEN: 'CommonTraitId' = 365861 - MATERIALISTIC: 'CommonTraitId' = 27913 - MEAN: 'CommonTraitId' = 16857 - MECHANICAL_SUIT_HOVER_ENGAGED: 'CommonTraitId' = 226744 - MECHANICAL_SUIT_WEARING_BODY_BEIGE_WHITE: 'CommonTraitId' = 226777 - MECHANICAL_SUIT_WEARING_BODY_BLACK_BLUE: 'CommonTraitId' = 226778 - MECHANICAL_SUIT_WEARING_BODY_BLUE_RED: 'CommonTraitId' = 226783 - MECHANICAL_SUIT_WEARING_BODY_GRAY_BROWN: 'CommonTraitId' = 226779 - MECHANICAL_SUIT_WEARING_BODY_GREEN_BROWN: 'CommonTraitId' = 226780 - MECHANICAL_SUIT_WEARING_BODY_RED_GREEN: 'CommonTraitId' = 226781 - MECHANICAL_SUIT_WEARING_BODY_WHITE_COPPER: 'CommonTraitId' = 226782 - MECHANICAL_SUIT_WEARING_HELMET_BLACK_BLUE: 'CommonTraitId' = 226800 - MECHANICAL_SUIT_WEARING_HELMET_BLACK_COPPER: 'CommonTraitId' = 226801 - MECHANICAL_SUIT_WEARING_HELMET_BLACK_GOLD: 'CommonTraitId' = 226802 - MECHANICAL_SUIT_WEARING_HELMET_BLACK_GRAY: 'CommonTraitId' = 226803 - MECHANICAL_SUIT_WEARING_HELMET_BLUE_GRAY: 'CommonTraitId' = 226804 - MECHANICAL_SUIT_WEARING_HELMET_GRAY_BLACK: 'CommonTraitId' = 226805 - MECHANICAL_SUIT_WEARING_HELMET_GREEN_BLACK: 'CommonTraitId' = 226806 - MEDIUM_SWIMMING: 'CommonTraitId' = 212821 - MELT_MASTER: 'CommonTraitId' = 132296 - MEMORABLE: 'CommonTraitId' = 32429 - MENTALLY_GIFTED: 'CommonTraitId' = 29620 - MENTOR: 'CommonTraitId' = 26691 - MIDLIFE_CRISIS_HAD_A_CRISIS: 'CommonTraitId' = 313577 - MISBEHAVIOR_CAT_JUMP_ON_COUNTERS: 'CommonTraitId' = 170714 - MISBEHAVIOR_CAT_SCRATCHING: 'CommonTraitId' = 162242 - MISBEHAVIOR_DOG_BARK: 'CommonTraitId' = 165942 - MISBEHAVIOR_DOG_EAT_POOP: 'CommonTraitId' = 168487 - MISBEHAVIOR_DOG_JUMP_ON_COUNTERS: 'CommonTraitId' = 170713 - MISBEHAVIOR_DOG_PUDDLES_PLAY: 'CommonTraitId' = 162246 - MISBEHAVIOR_DOG_TOILET: 'CommonTraitId' = 162243 - MISBEHAVIOR_PET_ATTACK: 'CommonTraitId' = 162253 - MISBEHAVIOR_PET_BEG_EATING: 'CommonTraitId' = 162252 - MISBEHAVIOR_PET_DEBUG: 'CommonTraitId' = 173099 - MISBEHAVIOR_PET_EAT_PEOPLE_FOOD: 'CommonTraitId' = 170716 - MISBEHAVIOR_PET_PUDDLES_DRINK: 'CommonTraitId' = 162249 - MISBEHAVIOR_PET_TRASH_EAT: 'CommonTraitId' = 162250 - MISBEHAVIOR_PET_TRASH_PLAY: 'CommonTraitId' = 162251 - MISBEHAVIOR_PET_WAKE_UP_SIMS: 'CommonTraitId' = 170715 - MORNING_PERSON: 'CommonTraitId' = 32426 - MULTI_UNIT_ASPIRATION_DISCERNING_DWELLER: 'CommonTraitId' = 341149 - MULTI_UNIT_ASPIRATION_FOUNTAIN_OF_LOCAL_KNOWLEDGE: 'CommonTraitId' = 341160 - MULTI_UNIT_ASPIRATION_LEGENDARY_LANDLORD: 'CommonTraitId' = 341148 - MULTI_UNIT_ASPIRATION_SEEKER_OF_SECRETS: 'CommonTraitId' = 341161 - MULTI_UNIT_EVENT_TENANT_REVOLT_GENERIC_CAUSE_HIDDEN: 'CommonTraitId' = 344508 - MULTI_UNIT_GUIDE_KNOWLEDGEABLE_LEASER: 'CommonTraitId' = 352408 - MUSER: 'CommonTraitId' = 27085 - MUSIC_FESTIVAL_BEBE_REXHA: 'CommonTraitId' = 269689 - MUSIC_FESTIVAL_DAVE_BAYLEY: 'CommonTraitId' = 269691 - MUSIC_FESTIVAL_JOY_OLADOKUN: 'CommonTraitId' = 269690 - MUSIC_LOVER: 'CommonTraitId' = 9604 - NATURAL_SPEAKER: 'CommonTraitId' = 206416 - NATURE_COUNTRY_CARETAKER_NATURE_CONVERSATIONALIST: 'CommonTraitId' = 260922 - NATURE_INFLUENTIAL_INDIVIDUAL: 'CommonTraitId' = 232081 - NATURE_MASTER_MIXER: 'CommonTraitId' = 217412 - NEAT: 'CommonTraitId' = 16858 - NECTAR_KNOW_IT_ALL: 'CommonTraitId' = 340646 - NEEDS_NO_ONE: 'CommonTraitId' = 183034 - NEVER_WEARY: 'CommonTraitId' = 26392 - NEW_IN_TOWN_INSPIRED_EXPLORER: 'CommonTraitId' = 297768 - NIGHT_OWL: 'CommonTraitId' = 32424 - NIGHT_OWL_CRYSTAL_HELMET: 'CommonTraitId' = 198854 - NOSY: 'CommonTraitId' = 341150 - NOSY_NEIGHBOR: 'CommonTraitId' = 274012 - NPC_MAKER: 'CommonTraitId' = 234888 - NPC_TENANT_APPLICANT_HIDDEN: 'CommonTraitId' = 350825 - OBSERVANT: 'CommonTraitId' = 32635 - OCCULT_ALIEN: 'CommonTraitId' = 102785 - OCCULT_ALIEN_CURRENT: 'CommonTraitId' = 103230 - OCCULT_ALIEN_FAKE_ALIEN: 'CommonTraitId' = 105149 - OCCULT_ALIEN_PART: 'CommonTraitId' = 102784 - OCCULT_MERFOLK_WOKE: 'CommonTraitId' = 206170 - OCCULT_MERMAID: 'CommonTraitId' = 199043 - OCCULT_MERMAID_DISCOVERED: 'CommonTraitId' = 215252 - OCCULT_MERMAID_MERMAID_FORM: 'CommonTraitId' = 199044 - OCCULT_MERMAID_TEMPORARY_DISCOVERED: 'CommonTraitId' = 215414 - OCCULT_MERMAID_TYAE: 'CommonTraitId' = 211545 - OCCULT_NO_OCCULT: 'CommonTraitId' = 154191 - OCCULT_ROBOT: 'CommonTraitId' = 218444 - OCCULT_VAMPIRE: 'CommonTraitId' = 149527 - OCCULT_VAMPIRE_BAT_BABY: 'CommonTraitId' = 152783 - OCCULT_VAMPIRE_CURED: 'CommonTraitId' = 150164 - OCCULT_VAMPIRE_DARK_FORM: 'CommonTraitId' = 149528 - OCCULT_VAMPIRE_DARK_LEY_LINE: 'CommonTraitId' = 154672 - OCCULT_VAMPIRE_MANIFESTED: 'CommonTraitId' = 153867 - OCCULT_VAMPIRE_MANUAL_DARK_FORM: 'CommonTraitId' = 156397 - OCCULT_WEREWOLF: 'CommonTraitId' = 289780 - OCCULT_WEREWOLF_ABILITIES_TRANSFORMATION_MASTERY: 'CommonTraitId' = 300559 - OCCULT_WEREWOLF_ASPIRATION_TRAITS_BETTER_FURY_CONTROL: 'CommonTraitId' = 291632 - OCCULT_WEREWOLF_ASPIRATION_TRAITS_BETTER_TURNING: 'CommonTraitId' = 291633 - OCCULT_WEREWOLF_ASPIRATION_TRAITS_FORMERLY_CAN: 'CommonTraitId' = 294207 - OCCULT_WEREWOLF_ASPIRATION_TRAITS_FRIENDLY_WOLF: 'CommonTraitId' = 291631 - OCCULT_WEREWOLF_ASPIRATION_TRAITS_MORE_FEAR: 'CommonTraitId' = 291635 - OCCULT_WEREWOLF_DORMANT_WOLF: 'CommonTraitId' = 288908 - OCCULT_WEREWOLF_GREATER_WOLF_BLOOD: 'CommonTraitId' = 289080 - OCCULT_WEREWOLF_HAD_FIRST_FULL_MOON: 'CommonTraitId' = 294966 - OCCULT_WEREWOLF_HAD_FIRST_TRANSFORMATION: 'CommonTraitId' = 288566 - OCCULT_WEREWOLF_HAS_FATED_MATE: 'CommonTraitId' = 293542 - OCCULT_WEREWOLF_IMMORTAL_WOLF: 'CommonTraitId' = 290521 - OCCULT_WEREWOLF_INITIATION_BONUS_TRAIT: 'CommonTraitId' = 290981 - OCCULT_WEREWOLF_MANIFESTED: 'CommonTraitId' = 276221 - OCCULT_WEREWOLF_NATURAL_HEALING: 'CommonTraitId' = 290526 - OCCULT_WEREWOLF_NO_FURY_GLOW: 'CommonTraitId' = 290772 - OCCULT_WEREWOLF_PRIMAL_INSTINCT: 'CommonTraitId' = 289945 - OCCULT_WEREWOLF_SUPER_SPEED: 'CommonTraitId' = 299122 - OCCULT_WEREWOLF_TEACH_TO_HOWL: 'CommonTraitId' = 295581 - OCCULT_WEREWOLF_TEMPERAMENTS_ANTI_CAPITALIST_CANINE: 'CommonTraitId' = 285387 - OCCULT_WEREWOLF_TEMPERAMENTS_BIG_BAD_WOLF: 'CommonTraitId' = 285363 - OCCULT_WEREWOLF_TEMPERAMENTS_CARNIVORE: 'CommonTraitId' = 285386 - OCCULT_WEREWOLF_TEMPERAMENTS_EASY_EXCITABLE: 'CommonTraitId' = 285388 - OCCULT_WEREWOLF_TEMPERAMENTS_FEELS_OUTCASTED: 'CommonTraitId' = 285371 - OCCULT_WEREWOLF_TEMPERAMENTS_FRISKY: 'CommonTraitId' = 285383 - OCCULT_WEREWOLF_TEMPERAMENTS_GRUMPY_WOLF: 'CommonTraitId' = 285381 - OCCULT_WEREWOLF_TEMPERAMENTS_HATES_BEING_WET: 'CommonTraitId' = 285382 - OCCULT_WEREWOLF_TEMPERAMENTS_HUNGRY_LIKE_THE_WOLF: 'CommonTraitId' = 285372 - OCCULT_WEREWOLF_TEMPERAMENTS_LUNAR_FOREST_MARK: 'CommonTraitId' = 291646 - OCCULT_WEREWOLF_TEMPERAMENTS_LUNAR_HUNT_MARK: 'CommonTraitId' = 291647 - OCCULT_WEREWOLF_TEMPERAMENTS_LUNAR_NIGHT_MARK: 'CommonTraitId' = 291645 - OCCULT_WEREWOLF_TEMPERAMENTS_LUNAR_WOLF_MARK: 'CommonTraitId' = 291644 - OCCULT_WEREWOLF_TEMPERAMENTS_MUST_BE_CLEAN: 'CommonTraitId' = 285369 - OCCULT_WEREWOLF_TEMPERAMENTS_NIGHT_WOLF: 'CommonTraitId' = 285391 - OCCULT_WEREWOLF_TEMPERAMENTS_PRIDEFUL: 'CommonTraitId' = 285368 - OCCULT_WEREWOLF_TEMPERAMENTS_RESTLESS_ANIMAL: 'CommonTraitId' = 285385 - OCCULT_WEREWOLF_TEMPERAMENTS_SENSITIVE_HEARING: 'CommonTraitId' = 285389 - OCCULT_WEREWOLF_TEMPERAMENTS_SURVIVAL_INSTINCTS: 'CommonTraitId' = 285367 - OCCULT_WEREWOLF_TEMPERAMENTS_TERRITORIAL: 'CommonTraitId' = 285366 - OCCULT_WEREWOLF_TEMPERAMENTS_WOLF_BRAIN: 'CommonTraitId' = 285390 - OCCULT_WEREWOLF_TEMPERAMENTS_WRACKED_WITH_GUILT: 'CommonTraitId' = 285364 - OCCULT_WEREWOLF_WEREFORM: 'CommonTraitId' = 276222 - OCCULT_WEREWOLF_WEREWOLF_ALLY: 'CommonTraitId' = 290172 - OCCULT_WITCH: 'CommonTraitId' = 213050 - OCCULT_WITCH_ASKED_ABOUT_MAGIC: 'CommonTraitId' = 215188 - OCCULT_WITCH_BLOODLINE_ANCIENT: 'CommonTraitId' = 218027 - OCCULT_WITCH_BLOODLINE_STRONG: 'CommonTraitId' = 218026 - OCCULT_WITCH_BLOODLINE_WEAK: 'CommonTraitId' = 218025 - OCCULT_WITCH_BROOM_USE_BROOM_TELEPORT: 'CommonTraitId' = 217844 - OCCULT_WITCH_FORMER_WITCH: 'CommonTraitId' = 215284 - OCCULT_WITCH_MANIFESTED: 'CommonTraitId' = 213061 - OCCULT_WITCH_MOTE_SIGHT: 'CommonTraitId' = 215163 - OCCULT_WITCH_PERKS_MOTE_HOUND: 'CommonTraitId' = 217145 - OCCULT_WITCH_TELEPORT: 'CommonTraitId' = 214838 - OCCULT_WITCH_WANDS_PREFER_WANDS: 'CommonTraitId' = 215298 - OCCULT_WITCH_WANDS_USE_WAND: 'CommonTraitId' = 215301 - ONE_WITH_NATURE: 'CommonTraitId' = 76817 - ON_TRASH_UPDATE_LOT: 'CommonTraitId' = 238937 - OUTGOING: 'CommonTraitId' = 29571 - OVER_ACHIEVER: 'CommonTraitId' = 284113 - PAPARAZZI: 'CommonTraitId' = 191783 - PARANOID: 'CommonTraitId' = 203542 - PARANORMAL_INVESTIGATOR_ASKED_GRIM: 'CommonTraitId' = 254374 - PARANORMAL_INVESTIGATOR_MEDIUM: 'CommonTraitId' = 255255 - PARENTING_SKILL_UNDERSTAND_BABY: 'CommonTraitId' = 163783 - PARTY_ANIMAL: 'CommonTraitId' = 284112 - PA_MATRIARCH: 'CommonTraitId' = 29827 - PERFECTIONIST: 'CommonTraitId' = 9617 - PERFECT_HOST: 'CommonTraitId' = 27172 - PERK_FEUD_TARGET: 'CommonTraitId' = 200795 - PETS_ADVENTURE_A: 'CommonTraitId' = 173060 - PETS_ADVENTURE_AA_UNSEEN: 'CommonTraitId' = 175942 - PETS_ADVENTURE_AB_UNSEEN: 'CommonTraitId' = 175943 - PETS_ADVENTURE_AC_UNSEEN: 'CommonTraitId' = 175944 - PETS_ADVENTURE_B: 'CommonTraitId' = 173058 - PETS_ADVENTURE_C: 'CommonTraitId' = 173059 - PETS_ADVENTURE_CA: 'CommonTraitId' = 175945 - PETS_ADVENTURE_CB: 'CommonTraitId' = 175946 - PETS_ADVENTURE_CC: 'CommonTraitId' = 175947 - PETS_ADVENTURE_LIGHTHOUSE_DOG: 'CommonTraitId' = 175660 - PETS_ADVENTURE_XA: 'CommonTraitId' = 173061 - PETS_ADVENTURE_XB: 'CommonTraitId' = 173062 - PETS_ADVENTURE_XC: 'CommonTraitId' = 173063 - PETS_TRAINING_COMMAND_FETCH: 'CommonTraitId' = 161172 - PETS_TRAINING_COMMAND_HEEL: 'CommonTraitId' = 161173 - PETS_TRAINING_COMMAND_LIE_DOWN: 'CommonTraitId' = 161170 - PETS_TRAINING_COMMAND_PLAY_DEAD: 'CommonTraitId' = 161174 - PETS_TRAINING_COMMAND_ROLL_OVER: 'CommonTraitId' = 161171 - PETS_TRAINING_COMMAND_SHAKE: 'CommonTraitId' = 161175 - PETS_TRAINING_COMMAND_SIT: 'CommonTraitId' = 161168 - PETS_TRAINING_COMMAND_SPEAK: 'CommonTraitId' = 161169 - PET_ACTIVE_CAT: 'CommonTraitId' = 158201 - PET_ACTIVE_DOG: 'CommonTraitId' = 171613 - PET_AGE_ADULT: 'CommonTraitId' = 167104 - PET_AGE_CHILD: 'CommonTraitId' = 167107 - PET_AGE_ELDER: 'CommonTraitId' = 167106 - PET_AGGRESSIVE_CAT: 'CommonTraitId' = 158768 - PET_AGGRESSIVE_DOG: 'CommonTraitId' = 171612 - PET_CURIOUS_CAT: 'CommonTraitId' = 158211 - PET_CURIOUS_DOG: 'CommonTraitId' = 171611 - PET_FRIENDLY_CAT: 'CommonTraitId' = 158765 - PET_FRIENDLY_DOG: 'CommonTraitId' = 171610 - PET_GLUTTON_CAT: 'CommonTraitId' = 159977 - PET_GLUTTON_DOG: 'CommonTraitId' = 171609 - PET_HAIRY_CAT: 'CommonTraitId' = 158772 - PET_HAIRY_DOG: 'CommonTraitId' = 171608 - PET_HUNTER_CAT: 'CommonTraitId' = 159972 - PET_HUNTER_DOG: 'CommonTraitId' = 171607 - PET_INDEPENDENT_CAT: 'CommonTraitId' = 158770 - PET_INDEPENDENT_DOG: 'CommonTraitId' = 171605 - PET_INSIDE_ONLY: 'CommonTraitId' = 158717 - PET_LAZY_CAT: 'CommonTraitId' = 158202 - PET_LAZY_DOG: 'CommonTraitId' = 171606 - PET_LOYAL_CAT: 'CommonTraitId' = 158771 - PET_LOYAL_DOG: 'CommonTraitId' = 171604 - PET_MISSING_PET: 'CommonTraitId' = 173563 - PET_NAUGHTY_CAT: 'CommonTraitId' = 159976 - PET_NAUGHTY_DOG: 'CommonTraitId' = 171603 - PET_OUTSIDE_ONLY: 'CommonTraitId' = 158718 - PET_PARENT_ADVENTURE: 'CommonTraitId' = 173544 - PET_PLAYFUL_CAT: 'CommonTraitId' = 164046 - PET_PLAYFUL_DOG: 'CommonTraitId' = 171602 - PET_QUIRK_FEAR_COFFEE_MAKER: 'CommonTraitId' = 159300 - PET_QUIRK_FEAR_COMPUTER: 'CommonTraitId' = 159302 - PET_QUIRK_FEAR_DISHWASHER: 'CommonTraitId' = 159295 - PET_QUIRK_FEAR_DOOR_BELL: 'CommonTraitId' = 159311 - PET_QUIRK_FEAR_FIRE: 'CommonTraitId' = 159296 - PET_QUIRK_FEAR_FITNESS_EQUIPMENT: 'CommonTraitId' = 159299 - PET_QUIRK_FEAR_GAMING: 'CommonTraitId' = 159301 - PET_QUIRK_FEAR_INSTRUMENT: 'CommonTraitId' = 159294 - PET_QUIRK_FEAR_MICROWAVE: 'CommonTraitId' = 159298 - PET_QUIRK_FEAR_ROBOT_VACUUM: 'CommonTraitId' = 171319 - PET_QUIRK_FEAR_SHOWER: 'CommonTraitId' = 159304 - PET_QUIRK_FEAR_STEREO: 'CommonTraitId' = 159292 - PET_QUIRK_FEAR_STOVE: 'CommonTraitId' = 159293 - PET_QUIRK_FEAR_SWIMMING: 'CommonTraitId' = 159297 - PET_QUIRK_FEAR_TOILET: 'CommonTraitId' = 159303 - PET_QUIRK_FEAR_TV: 'CommonTraitId' = 158096 - PET_QUIRK_FEAR_VACUUM: 'CommonTraitId' = 257142 - PET_QUIRK_OBSESSED_COFFEE_MAKER: 'CommonTraitId' = 159244 - PET_QUIRK_OBSESSED_COMPUTER: 'CommonTraitId' = 159248 - PET_QUIRK_OBSESSED_COOKING: 'CommonTraitId' = 159238 - PET_QUIRK_OBSESSED_DISHWASHER: 'CommonTraitId' = 159240 - PET_QUIRK_OBSESSED_DOOR_BELL: 'CommonTraitId' = 159312 - PET_QUIRK_OBSESSED_FIRE: 'CommonTraitId' = 159241 - PET_QUIRK_OBSESSED_FISH_TANKS: 'CommonTraitId' = 159246 - PET_QUIRK_OBSESSED_FITNESS_EQUIPMENT: 'CommonTraitId' = 159243 - PET_QUIRK_OBSESSED_FRIDGE: 'CommonTraitId' = 159251 - PET_QUIRK_OBSESSED_GAMING: 'CommonTraitId' = 159245 - PET_QUIRK_OBSESSED_INSTRUMENT: 'CommonTraitId' = 159239 - PET_QUIRK_OBSESSED_MICROWAVE: 'CommonTraitId' = 159242 - PET_QUIRK_OBSESSED_PET_MINOR_CAGE: 'CommonTraitId' = 184406 - PET_QUIRK_OBSESSED_ROBOT_VACUUM: 'CommonTraitId' = 171320 - PET_QUIRK_OBSESSED_SHOWER: 'CommonTraitId' = 159250 - PET_QUIRK_OBSESSED_STEREO: 'CommonTraitId' = 159237 - PET_QUIRK_OBSESSED_SWIMMING: 'CommonTraitId' = 171912 - PET_QUIRK_OBSESSED_TOILET: 'CommonTraitId' = 159249 - PET_QUIRK_OBSESSED_TV: 'CommonTraitId' = 158739 - PET_QUIRK_OBSESSED_VACUUM: 'CommonTraitId' = 257156 - PET_QUIRK_PET_BED_SPIN: 'CommonTraitId' = 174976 - PET_QUIRK_PREGNANCY_VOMITING_NO: 'CommonTraitId' = 174466 - PET_QUIRK_PREGNANCY_VOMITING_YES: 'CommonTraitId' = 174465 - PET_SKITTISH_CAT: 'CommonTraitId' = 158766 - PET_SKITTISH_DOG: 'CommonTraitId' = 171601 - PET_SMART_CAT: 'CommonTraitId' = 158769 - PET_SMART_DOG: 'CommonTraitId' = 171600 - PET_STUBBORN_CAT: 'CommonTraitId' = 158210 - PET_STUBBORN_DOG: 'CommonTraitId' = 171599 - PET_VOCAL_CAT: 'CommonTraitId' = 158767 - PET_VOCAL_DOG: 'CommonTraitId' = 171598 - PET_WANDERLUST_CAT: 'CommonTraitId' = 158693 - PET_WANDERLUST_DOG: 'CommonTraitId' = 171597 - PHONE_BLACK: 'CommonTraitId' = 149328 - PHONE_BLACK_STRIPES: 'CommonTraitId' = 149329 - PHONE_BLUE_POLKA: 'CommonTraitId' = 149330 - PHONE_BROWN: 'CommonTraitId' = 149331 - PHONE_COLOR_ASTRO_BLACK: 'CommonTraitId' = 284068 - PHONE_COLOR_ASTRO_GRAY: 'CommonTraitId' = 284069 - PHONE_COLOR_ASTRO_MAROON: 'CommonTraitId' = 284070 - PHONE_COLOR_ASTRO_PEACH: 'CommonTraitId' = 284071 - PHONE_COLOR_ASTRO_PINK: 'CommonTraitId' = 284072 - PHONE_COLOR_ASTRO_PURPLE: 'CommonTraitId' = 284073 - PHONE_COLOR_CASSETTE_BLACK: 'CommonTraitId' = 284318 - PHONE_COLOR_CASSETTE_BLUE: 'CommonTraitId' = 284320 - PHONE_COLOR_CASSETTE_GREEN: 'CommonTraitId' = 284319 - PHONE_COLOR_CASSETTE_ORANGE: 'CommonTraitId' = 284322 - PHONE_COLOR_CASSETTE_PINK: 'CommonTraitId' = 284321 - PHONE_COLOR_CASSETTE_RED: 'CommonTraitId' = 284317 - PHONE_COLOR_DUO_BABY_BLUE: 'CommonTraitId' = 284346 - PHONE_COLOR_DUO_BLACK: 'CommonTraitId' = 284349 - PHONE_COLOR_DUO_GREEN: 'CommonTraitId' = 284348 - PHONE_COLOR_DUO_LAVENDER: 'CommonTraitId' = 284347 - PHONE_COLOR_DUO_SLATE: 'CommonTraitId' = 284344 - PHONE_COLOR_DUO_UMBER: 'CommonTraitId' = 284345 - PHONE_COLOR_FLORAL_GREEN_BLUE: 'CommonTraitId' = 284269 - PHONE_COLOR_FLORAL_MAUVE: 'CommonTraitId' = 284271 - PHONE_COLOR_FLORAL_PEACH: 'CommonTraitId' = 284268 - PHONE_COLOR_FLORAL_PINK: 'CommonTraitId' = 284272 - PHONE_COLOR_FLORAL_SLATE: 'CommonTraitId' = 284273 - PHONE_COLOR_FLORAL_YELLOW: 'CommonTraitId' = 284270 - PHONE_COLOR_GEO_BLUE: 'CommonTraitId' = 284293 - PHONE_COLOR_GEO_BROWN: 'CommonTraitId' = 284298 - PHONE_COLOR_GEO_GOLD: 'CommonTraitId' = 284297 - PHONE_COLOR_GEO_GREEN: 'CommonTraitId' = 284295 - PHONE_COLOR_GEO_RED: 'CommonTraitId' = 284294 - PHONE_COLOR_GEO_SILVER: 'CommonTraitId' = 284296 - PHONE_COLOR_PAINT_BLACK: 'CommonTraitId' = 284040 - PHONE_COLOR_PAINT_BLUE: 'CommonTraitId' = 284041 - PHONE_COLOR_PAINT_CANARY: 'CommonTraitId' = 284042 - PHONE_COLOR_PAINT_GREEN: 'CommonTraitId' = 284044 - PHONE_COLOR_PAINT_TEAL: 'CommonTraitId' = 284046 - PHONE_COLOR_PAINT_WHITE: 'CommonTraitId' = 284047 - PHONE_COLOR_ROSE_BLACK: 'CommonTraitId' = 284244 - PHONE_COLOR_ROSE_BLUE: 'CommonTraitId' = 284245 - PHONE_COLOR_ROSE_GREEN: 'CommonTraitId' = 284246 - PHONE_COLOR_ROSE_LAVENDER: 'CommonTraitId' = 284247 - PHONE_COLOR_ROSE_METAL_GOLD: 'CommonTraitId' = 284248 - PHONE_COLOR_ROSE_WHITE: 'CommonTraitId' = 284249 - PHONE_COLOR_SWIRL_BLUE: 'CommonTraitId' = 283981 - PHONE_COLOR_SWIRL_GRAY: 'CommonTraitId' = 283985 - PHONE_COLOR_SWIRL_GREEN: 'CommonTraitId' = 283980 - PHONE_COLOR_SWIRL_ORANGE: 'CommonTraitId' = 283983 - PHONE_COLOR_SWIRL_PINK: 'CommonTraitId' = 283982 - PHONE_COLOR_SWIRL_PURPLE: 'CommonTraitId' = 283984 - PHONE_DARK_BLUE: 'CommonTraitId' = 149332 - PHONE_DARK_GREEN: 'CommonTraitId' = 149333 - PHONE_GOLD: 'CommonTraitId' = 149334 - PHONE_HOT_PINK_POLKA: 'CommonTraitId' = 149335 - PHONE_LIGHT_PINK: 'CommonTraitId' = 149336 - PHONE_LIME: 'CommonTraitId' = 149320 - PHONE_MINT_GREEN_STRIPES: 'CommonTraitId' = 149321 - PHONE_ORANGE_POLKA: 'CommonTraitId' = 149322 - PHONE_PURPLE: 'CommonTraitId' = 149323 - PHONE_RED: 'CommonTraitId' = 149324 - PHONE_ROSE_GOLD: 'CommonTraitId' = 149325 - PHONE_SILVER: 'CommonTraitId' = 149326 - PHONE_TURQUOISE_STRIPES: 'CommonTraitId' = 149319 - PHONE_WHITE: 'CommonTraitId' = 149327 - PHYSICALLY_GIFTED: 'CommonTraitId' = 29618 - PIPER: 'CommonTraitId' = 28009 - PLANT_SIM: 'CommonTraitId' = 162668 - PLANT_SIM_CHALLENGE_RECEIVED_STUMP: 'CommonTraitId' = 163733 - PLAYER: 'CommonTraitId' = 26202 - POTION_MASTER: 'CommonTraitId' = 26198 - PRACTICE_MAKES_PERFECT: 'CommonTraitId' = 368744 - PRACTICE_MAKES_PERFECT_BUFF_TRAIT_CREATIVE_TIER_0: 'CommonTraitId' = 371379 - PRACTICE_MAKES_PERFECT_BUFF_TRAIT_CREATIVE_TIER_1: 'CommonTraitId' = 371389 - PRACTICE_MAKES_PERFECT_BUFF_TRAIT_CREATIVE_TIER_2: 'CommonTraitId' = 371390 - PRACTICE_MAKES_PERFECT_BUFF_TRAIT_CREATIVE_TIER_3: 'CommonTraitId' = 371391 - PRACTICE_MAKES_PERFECT_BUFF_TRAIT_CREATIVE_TIER_4: 'CommonTraitId' = 371392 - PRACTICE_MAKES_PERFECT_BUFF_TRAIT_MENTAL_TIER_0: 'CommonTraitId' = 371393 - PRACTICE_MAKES_PERFECT_BUFF_TRAIT_MENTAL_TIER_1: 'CommonTraitId' = 371394 - PRACTICE_MAKES_PERFECT_BUFF_TRAIT_MENTAL_TIER_2: 'CommonTraitId' = 371395 - PRACTICE_MAKES_PERFECT_BUFF_TRAIT_MENTAL_TIER_3: 'CommonTraitId' = 371396 - PRACTICE_MAKES_PERFECT_BUFF_TRAIT_MENTAL_TIER_4: 'CommonTraitId' = 371397 - PRACTICE_MAKES_PERFECT_BUFF_TRAIT_PHYSICAL_TIER_0: 'CommonTraitId' = 371398 - PRACTICE_MAKES_PERFECT_BUFF_TRAIT_PHYSICAL_TIER_1: 'CommonTraitId' = 371399 - PRACTICE_MAKES_PERFECT_BUFF_TRAIT_PHYSICAL_TIER_2: 'CommonTraitId' = 371400 - PRACTICE_MAKES_PERFECT_BUFF_TRAIT_PHYSICAL_TIER_3: 'CommonTraitId' = 371401 - PRACTICE_MAKES_PERFECT_BUFF_TRAIT_PHYSICAL_TIER_4: 'CommonTraitId' = 371402 - PRACTICE_MAKES_PERFECT_BUFF_TRAIT_SOCIAL_TIER_0: 'CommonTraitId' = 371403 - PRACTICE_MAKES_PERFECT_BUFF_TRAIT_SOCIAL_TIER_1: 'CommonTraitId' = 371404 - PRACTICE_MAKES_PERFECT_BUFF_TRAIT_SOCIAL_TIER_2: 'CommonTraitId' = 371405 - PRACTICE_MAKES_PERFECT_BUFF_TRAIT_SOCIAL_TIER_3: 'CommonTraitId' = 371406 - PRACTICE_MAKES_PERFECT_BUFF_TRAIT_SOCIAL_TIER_4: 'CommonTraitId' = 371407 - PRACTICE_MAKES_PERFECT_TRACKING_CREATIVE: 'CommonTraitId' = 370886 - PRACTICE_MAKES_PERFECT_TRACKING_MENTAL: 'CommonTraitId' = 370887 - PRACTICE_MAKES_PERFECT_TRACKING_PHYSICAL: 'CommonTraitId' = 370888 - PRACTICE_MAKES_PERFECT_TRACKING_SOCIAL: 'CommonTraitId' = 370885 - PREGNANCY_OPTIONS_PET_CAN_NOT_REPRODUCE: 'CommonTraitId' = 162564 - PREGNANCY_OPTIONS_PET_CAN_REPRODUCE: 'CommonTraitId' = 162563 - PREPARED_VOYAGER: 'CommonTraitId' = 238653 - PROFESSIONAL_SLACKER: 'CommonTraitId' = 32442 - PROFESSOR_NPC_COURSE_ARTS_A: 'CommonTraitId' = 221851 - PROFESSOR_NPC_COURSE_ARTS_B: 'CommonTraitId' = 224821 - PROFESSOR_NPC_COURSE_ARTS_C: 'CommonTraitId' = 224822 - PROFESSOR_NPC_COURSE_ARTS_D: 'CommonTraitId' = 224823 - PROFESSOR_NPC_COURSE_SCIENCE_A: 'CommonTraitId' = 224863 - PROFESSOR_NPC_COURSE_SCIENCE_B: 'CommonTraitId' = 224864 - PROFESSOR_NPC_COURSE_SCIENCE_C: 'CommonTraitId' = 224865 - PROFESSOR_NPC_COURSE_SCIENCE_D: 'CommonTraitId' = 224866 - PROFESSOR_NPC_IS_ARTS_PROFESSOR: 'CommonTraitId' = 224965 - PROFESSOR_NPC_IS_SCIENCE_PROFESSOR: 'CommonTraitId' = 224966 - PROPER: 'CommonTraitId' = 251970 - PUBERTY_CHANGES_EXPERIENCED_FIRST_TIME: 'CommonTraitId' = 286434 - QUICK_LEARNER: 'CommonTraitId' = 27086 - RANCHER: 'CommonTraitId' = 320988 - RECYCLE_DISCIPLE: 'CommonTraitId' = 232692 - REGAINED_HUMANITY: 'CommonTraitId' = 154825 - RELATABLE: 'CommonTraitId' = 282767 - RELATIONSHIP_EXPECTATIONS_EMOTIONAL_EXCLUSIVITY_NO: 'CommonTraitId' = 361822 - RELATIONSHIP_EXPECTATIONS_EMOTIONAL_EXCLUSIVITY_YES: 'CommonTraitId' = 361821 - RELATIONSHIP_EXPECTATIONS_OPEN_TO_CHANGE_NO: 'CommonTraitId' = 361824 - RELATIONSHIP_EXPECTATIONS_OPEN_TO_CHANGE_YES: 'CommonTraitId' = 361823 - RELATIONSHIP_EXPECTATIONS_PHYSICAL_EXCLUSIVITY_NO: 'CommonTraitId' = 361820 - RELATIONSHIP_EXPECTATIONS_PHYSICAL_EXCLUSIVITY_YES: 'CommonTraitId' = 361819 - RELATIONSHIP_EXPECTATIONS_WOOHOO_EXCLUSIVITY_NO: 'CommonTraitId' = 373826 - RELATIONSHIP_EXPECTATIONS_WOOHOO_EXCLUSIVITY_YES: 'CommonTraitId' = 373825 - REPUTATION_HAS_BEEN_RANK_1_TERRIBLE: 'CommonTraitId' = 194218 - REPUTATION_HAS_BEEN_RANK_2_REALLY_BAD: 'CommonTraitId' = 194219 - REPUTATION_HAS_BEEN_RANK_3_BAD: 'CommonTraitId' = 194220 - REPUTATION_HAS_BEEN_RANK_4_NEUTRAL: 'CommonTraitId' = 194221 - REPUTATION_HAS_BEEN_RANK_5_GOOD: 'CommonTraitId' = 194222 - REPUTATION_HAS_BEEN_RANK_6_REALLY_GOOD: 'CommonTraitId' = 194225 - REPUTATION_HAS_BEEN_RANK_7_PRISTINE: 'CommonTraitId' = 194226 - REPUTATION_RANK_1_TERRIBLE: 'CommonTraitId' = 194206 - REPUTATION_RANK_2_REALLY_BAD: 'CommonTraitId' = 194209 - REPUTATION_RANK_3_BAD: 'CommonTraitId' = 194212 - REPUTATION_RANK_4_NEUTRAL: 'CommonTraitId' = 194214 - REPUTATION_RANK_5_GOOD: 'CommonTraitId' = 194215 - REPUTATION_RANK_6_REALLY_GOOD: 'CommonTraitId' = 194217 - REPUTATION_RANK_7_PRISTINE: 'CommonTraitId' = 194224 - RESEARCH_MACHINE_ACTING: 'CommonTraitId' = 227795 - RESEARCH_MACHINE_CHARISMA: 'CommonTraitId' = 227796 - RESEARCH_MACHINE_COMEDY: 'CommonTraitId' = 227797 - RESEARCH_MACHINE_COOKING: 'CommonTraitId' = 227799 - RESEARCH_MACHINE_FITNESS: 'CommonTraitId' = 227787 - RESEARCH_MACHINE_GARDENING: 'CommonTraitId' = 227800 - RESEARCH_MACHINE_HANDINESS: 'CommonTraitId' = 227788 - RESEARCH_MACHINE_LOGIC: 'CommonTraitId' = 227801 - RESEARCH_MACHINE_PAINTING: 'CommonTraitId' = 227798 - RESEARCH_MACHINE_PHOTOGRAPHY: 'CommonTraitId' = 227802 - RESEARCH_MACHINE_PROGRAMMING: 'CommonTraitId' = 227791 - RESEARCH_MACHINE_RESEARCH: 'CommonTraitId' = 227789 - RESEARCH_MACHINE_ROBOTICS: 'CommonTraitId' = 227792 - RESEARCH_MACHINE_ROCKET_SCIENCE: 'CommonTraitId' = 227793 - RESEARCH_MACHINE_VIDEO_GAMING: 'CommonTraitId' = 227794 - RESEARCH_MACHINE_WRITING: 'CommonTraitId' = 227790 - REWARD_CHILD_CONFIDENCE_HIGH_SELF_ESTEEM: 'CommonTraitId' = 307541 - REWARD_CHILD_CONFIDENCE_LOW_SELF_ESTEEM: 'CommonTraitId' = 307542 - REWARD_HIGH_SCHOOL_TEAM_CHEER_TEAM: 'CommonTraitId' = 277021 - REWARD_HIGH_SCHOOL_TEAM_CHESS_TEAM: 'CommonTraitId' = 277022 - REWARD_HIGH_SCHOOL_TEAM_COMPUTER_TEAM: 'CommonTraitId' = 277024 - REWARD_HIGH_SCHOOL_TEAM_FOOTBALL_TEAM: 'CommonTraitId' = 277023 - REWARD_INFANT_HAPPY: 'CommonTraitId' = 273819 - REWARD_INFANT_TOP_NOTCH: 'CommonTraitId' = 273820 - REWARD_INFANT_UNHAPPY: 'CommonTraitId' = 273818 - RIDER_GAMEPLAY_MOUNTED_REINS_DOWN: 'CommonTraitId' = 348818 - ROBOTICS_ARM_WEARING_BEIGE_WHITE: 'CommonTraitId' = 228954 - ROBOTICS_ARM_WEARING_BLACK_BLUE: 'CommonTraitId' = 228977 - ROBOTICS_ARM_WEARING_BLUE_RED: 'CommonTraitId' = 228978 - ROBOTICS_ARM_WEARING_GRAY_BROWN: 'CommonTraitId' = 228979 - ROBOTICS_ARM_WEARING_GREEN_BROWN: 'CommonTraitId' = 228980 - ROBOTICS_ARM_WEARING_RED_GREEN: 'CommonTraitId' = 228981 - ROBOTICS_ARM_WEARING_WHITE_COPPER: 'CommonTraitId' = 228982 - ROCK_CLIMBING_GEAR_HAS_GEAR: 'CommonTraitId' = 246686 - ROCK_CLIMBING_GEAR_WEARING_GEAR: 'CommonTraitId' = 253624 - ROMANTIC: 'CommonTraitId' = 27454 - ROMANTICALLY_RESERVED: 'CommonTraitId' = 361564 - ROMANTIC_SAGE: 'CommonTraitId' = 377565 - ROOMMATE_NPC_ARCHETYPE_BREAKER: 'CommonTraitId' = 220348 - ROOMMATE_NPC_ARCHETYPE_CHEERLEADER: 'CommonTraitId' = 211764 - ROOMMATE_NPC_ARCHETYPE_CLINGY_SOCIALITE: 'CommonTraitId' = 207908 - ROOMMATE_NPC_ARCHETYPE_COUCH_POTATO: 'CommonTraitId' = 207909 - ROOMMATE_NPC_ARCHETYPE_EMO_LONER: 'CommonTraitId' = 211741 - ROOMMATE_NPC_ARCHETYPE_FIXER: 'CommonTraitId' = 211765 - ROOMMATE_NPC_ARCHETYPE_LOUD_MUSIC: 'CommonTraitId' = 211740 - ROOMMATE_NPC_ARCHETYPE_MEAL_MAKER: 'CommonTraitId' = 207907 - ROOMMATE_NPC_ARCHETYPE_PARTY_PLANNER: 'CommonTraitId' = 211742 - ROOMMATE_NPC_ARCHETYPE_SUPER_NEAT: 'CommonTraitId' = 207906 - ROOMMATE_NPC_INTEREST_ART: 'CommonTraitId' = 211745 - ROOMMATE_NPC_INTEREST_BAKING: 'CommonTraitId' = 211743 - ROOMMATE_NPC_INTEREST_COMPUTERS: 'CommonTraitId' = 207911 - ROOMMATE_NPC_INTEREST_FITNESS: 'CommonTraitId' = 211744 - ROOMMATE_NPC_INTEREST_MUSIC: 'CommonTraitId' = 207910 - ROOMMATE_NPC_QUIRK_ABSENT: 'CommonTraitId' = 211746 - ROOMMATE_NPC_QUIRK_BATHROOM_HOG: 'CommonTraitId' = 207912 - ROOMMATE_NPC_QUIRK_BIG_CLOSET: 'CommonTraitId' = 211747 - ROOMMATE_NPC_QUIRK_LATE_ON_RENT: 'CommonTraitId' = 220349 - ROOMMATE_NPC_QUIRK_PRANKSTER: 'CommonTraitId' = 211748 - ROOMMATE_NPC_QUIRK_PUBLIC_AFFECTION_DISPLAYER: 'CommonTraitId' = 207913 - ROOMMATE_NPC_STANDARD: 'CommonTraitId' = 208150 - SACRED_KNITTING_KNOWLEDGE: 'CommonTraitId' = 240379 - SAVANT: 'CommonTraitId' = 39880 - SCARECROW: 'CommonTraitId' = 187088 - SCENARIO_ALIEN_ADBUCTION_ADULTS: 'CommonTraitId' = 305121 - SCENARIO_COOKOUT: 'CommonTraitId' = 301713 - SCENARIO_EXPLORE_THE_NIGHT: 'CommonTraitId' = 301995 - SCENARIO_EXPLORE_THE_NIGHT_STAYED_UP: 'CommonTraitId' = 302450 - SCENARIO_INHERITANCE_GOAL_GRANDMOTHER_GHOST: 'CommonTraitId' = 343559 - SCENARIO_INHERITANCE_GOAL_MONEY_DONATED: 'CommonTraitId' = 343560 - SCENARIO_INHERITANCE_GOAL_READ_WILL: 'CommonTraitId' = 345458 - SCENARIO_INHERITANCE_GOAL_SIBLINGS_FRIENDS: 'CommonTraitId' = 343561 - SCENARIO_INHERITANCE_GRANDMOTHER: 'CommonTraitId' = 339198 - SCENARIO_IN_THE_MOODLET: 'CommonTraitId' = 296354 - SCENARIO_NEW_IN_TOWN: 'CommonTraitId' = 296645 - SCENARIO_NEW_IN_TOWN_P1_7A_INTRO: 'CommonTraitId' = 297992 - SCENARIO_NEW_IN_TOWN_P1_7B_INTRO: 'CommonTraitId' = 297993 - SCENARIO_NEW_IN_TOWN_P1_7C_INTRO: 'CommonTraitId' = 297994 - SCENARIO_NEW_IN_TOWN_P3A_INTRO: 'CommonTraitId' = 297995 - SCENARIO_NEW_IN_TOWN_P3A_NEW_ACQUAINTANCE_CALLER_FRIEND_GYM: 'CommonTraitId' = 301762 - SCENARIO_NEW_IN_TOWN_P3B_INTRO: 'CommonTraitId' = 297996 - SCENARIO_NEW_IN_TOWN_P3B_NEW_ACQUAINTANCE_CALLER_FRIEND_BAR: 'CommonTraitId' = 301767 - SCENARIO_NEW_IN_TOWN_P3B_NEW_ACQUAINTANCE_CALLER_ROMANCE_BAR: 'CommonTraitId' = 301768 - SCENARIO_NEW_IN_TOWN_P4_RELATIONSHIP_GAIN: 'CommonTraitId' = 297998 - SCENARIO_NEW_IN_TOWN_WOOHOOED: 'CommonTraitId' = 297997 - SCENARIO_NO_SKILLS_NO_PROBLEM: 'CommonTraitId' = 282974 - SCENARIO_PARENTING_PREDICAMENTS_CHILD: 'CommonTraitId' = 299357 - SCENARIO_PARENTING_PREDICAMENTS_FINAL_GRADE_LEONARDO_A: 'CommonTraitId' = 306256 - SCENARIO_PARENTING_PREDICAMENTS_FINAL_GRADE_LEONARDO_F: 'CommonTraitId' = 306257 - SCENARIO_PARENTING_PREDICAMENTS_FINAL_GRADE_SOFIA_A: 'CommonTraitId' = 306254 - SCENARIO_PARENTING_PREDICAMENTS_FINAL_GRADE_SOFIA_F: 'CommonTraitId' = 306255 - SCENARIO_PARENTING_PREDICAMENTS_JENNIFER: 'CommonTraitId' = 298981 - SCENARIO_PARENTING_PREDICAMENTS_LEONARDO: 'CommonTraitId' = 298983 - SCENARIO_PARENTING_PREDICAMENTS_PABLO: 'CommonTraitId' = 298982 - SCENARIO_PARENTING_PREDICAMENTS_PARENT: 'CommonTraitId' = 299358 - SCENARIO_PARENTING_PREDICAMENTS_PRINCIPAL: 'CommonTraitId' = 303367 - SCENARIO_PARENTING_PREDICAMENTS_SOFIA: 'CommonTraitId' = 298984 - SCENARIO_PREMADES_NOT_RIVAL: 'CommonTraitId' = 299962 - SCENARIO_PREMADES_RIVAL: 'CommonTraitId' = 295011 - SCENARIO_PROUD_PARENT: 'CommonTraitId' = 300938 - SCENARIO_STUCK_IN_THEIR_SHADOW_NOVA: 'CommonTraitId' = 298980 - SCENARIO_STUCK_IN_THEIR_SHADOW_P1_COMPLETED_MOTIVES: 'CommonTraitId' = 302191 - SCENARIO_STUCK_IN_THEIR_SHADOW_P1_COMPLETED_PROGRAMMING: 'CommonTraitId' = 302192 - SCENARIO_STUCK_IN_THEIR_SHADOW_P2_RIVAL_PURCHASES: 'CommonTraitId' = 302194 - SCENARIO_STUCK_IN_THEIR_SHADOW_P3_COMPLETED_IMPROVE_WORSEN: 'CommonTraitId' = 302193 - SCENARIO_STUCK_IN_THEIR_SHADOW_P3_DECISION_GOAL_ACTIVE: 'CommonTraitId' = 302202 - SCENARIO_STUCK_IN_THEIR_SHADOW_P3_RIVAL_ARRIVED: 'CommonTraitId' = 302185 - SCENARIO_STUCK_IN_THEIR_SHADOW_P3_RIVAL_INVITED: 'CommonTraitId' = 302198 - SCENARIO_STUCK_IN_THEIR_SHADOW_P3_RIVAL_KICKED: 'CommonTraitId' = 302200 - SCENARIO_STUCK_IN_THEIR_SHADOW_P3_RIVAL_SLEEPOVER: 'CommonTraitId' = 302201 - SCENARIO_STUCK_IN_THEIR_SHADOW_P3_START: 'CommonTraitId' = 302199 - SCENARIO_STUCK_IN_THEIR_SHADOW_P3_VOODOO_OWNER: 'CommonTraitId' = 302340 - SCENARIO_STUCK_IN_THEIR_SHADOW_P4A_ASKED_ABOUT_CAREER: 'CommonTraitId' = 302187 - SCENARIO_STUCK_IN_THEIR_SHADOW_P4A_ASTRONAUT_NO: 'CommonTraitId' = 302254 - SCENARIO_STUCK_IN_THEIR_SHADOW_P4A_ASTRONAUT_YES: 'CommonTraitId' = 302189 - SCENARIO_STUCK_IN_THEIR_SHADOW_P4B_CAN_QUIT: 'CommonTraitId' = 302190 - SCENARIO_STUCK_IN_THEIR_SHADOW_P4B_INDIE_DEVELOPER_ACCEPTED: 'CommonTraitId' = 302197 - SCENARIO_STUCK_IN_THEIR_SHADOW_P4B_INDIE_DEVELOPER_REJECTED: 'CommonTraitId' = 302196 - SCENARIO_STUCK_IN_THEIR_SHADOW_P4B_PROMOTED: 'CommonTraitId' = 303245 - SCENARIO_UNLUCKY_CHEF: 'CommonTraitId' = 282934 - SCHOOL_LOCKER_CLAIMED: 'CommonTraitId' = 277724 - SCIENTIST_EXPERT_REPAIR: 'CommonTraitId' = 109675 - SCOUTING_APTITUDE: 'CommonTraitId' = 187481 - SCUBA_GEAR_DIVE_KNIFE: 'CommonTraitId' = 206056 - SCUBA_GEAR_REBREATHER: 'CommonTraitId' = 206055 - SCUBA_GEAR_SPEAR_FISHING_GUN: 'CommonTraitId' = 206057 - SCUBA_GEAR_TREASURE_TOOL: 'CommonTraitId' = 206054 - SCUBA_GEAR_UNDERWATER_CAMERA: 'CommonTraitId' = 206058 - SEASONED_GAMER: 'CommonTraitId' = 226681 - SELDOM_SLEEPY: 'CommonTraitId' = 183024 - SELF_ABSORBED: 'CommonTraitId' = 199561 - SELF_ASSURED: 'CommonTraitId' = 16824 - SELF_DISCOVERY_MAX_HIDDEN: 'CommonTraitId' = 315699 - SEXUAL_ORIENTATION_WOOHOO_INTERESTS_FEMALE: 'CommonTraitId' = 291675 - SEXUAL_ORIENTATION_WOOHOO_INTERESTS_MALE: 'CommonTraitId' = 291674 - SEXUAL_ORIENTATION_WOOHOO_INTERESTS_NOT_FEMALE: 'CommonTraitId' = 292092 - SEXUAL_ORIENTATION_WOOHOO_INTERESTS_NOT_MALE: 'CommonTraitId' = 292093 - SHAMELESS: 'CommonTraitId' = 26439 - SICKNESS_IMMUNITY: 'CommonTraitId' = 231050 - SIM_PREFERENCE_ACTIVE_DISLIKE: 'CommonTraitId' = 266824 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_ACTING: 'CommonTraitId' = 264140 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_BAKING: 'CommonTraitId' = 264546 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_BOWLING: 'CommonTraitId' = 264142 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_COMEDY: 'CommonTraitId' = 264143 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_COOKING: 'CommonTraitId' = 258758 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_CROSS_STITCH: 'CommonTraitId' = 274573 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_DANCING: 'CommonTraitId' = 264144 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_DEBATING: 'CommonTraitId' = 264159 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_DJ_MIXING: 'CommonTraitId' = 264170 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_EQUESTRIAN_SKILL: 'CommonTraitId' = 339782 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_FISHING: 'CommonTraitId' = 264145 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_FITNESS: 'CommonTraitId' = 258759 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_GARDENING: 'CommonTraitId' = 264146 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_GUITAR: 'CommonTraitId' = 264171 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_HANDINESS: 'CommonTraitId' = 264147 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_KNITTING: 'CommonTraitId' = 274572 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_MEDIA_PRODUCTION: 'CommonTraitId' = 264148 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_MISCHIEF: 'CommonTraitId' = 264149 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_MIXOLOGY: 'CommonTraitId' = 264150 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_NECTAR_MAKING: 'CommonTraitId' = 339781 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_PAINTING: 'CommonTraitId' = 258760 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_PHOTOGRAPHY: 'CommonTraitId' = 264151 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_PIANO: 'CommonTraitId' = 264172 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_PIPE_ORGAN: 'CommonTraitId' = 264173 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_PROGRAMMING: 'CommonTraitId' = 264160 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_ROBOTICS: 'CommonTraitId' = 264162 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_ROCKET_SCIENCE: 'CommonTraitId' = 264164 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_ROCK_CLIMBING: 'CommonTraitId' = 264163 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_ROMANCE_SKILL: 'CommonTraitId' = 395731 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_SINGING: 'CommonTraitId' = 264174 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_SKIING: 'CommonTraitId' = 264165 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_SNOWBOARDING: 'CommonTraitId' = 264166 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_VIDEO_GAMING: 'CommonTraitId' = 258761 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_VIOLIN: 'CommonTraitId' = 258762 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_WELLNESS: 'CommonTraitId' = 269263 - SIM_PREFERENCE_DISLIKES_ACTIVITIES_WRITING: 'CommonTraitId' = 264168 - SIM_PREFERENCE_DISLIKES_CHARACTERISTIC_AMBITIONLESS: 'CommonTraitId' = 306407 - SIM_PREFERENCE_DISLIKES_CHARACTERISTIC_ARGUMENTATIVE: 'CommonTraitId' = 306408 - SIM_PREFERENCE_DISLIKES_CHARACTERISTIC_CEREBRAL: 'CommonTraitId' = 306423 - SIM_PREFERENCE_DISLIKES_CHARACTERISTIC_EGOTISTICAL: 'CommonTraitId' = 306410 - SIM_PREFERENCE_DISLIKES_CHARACTERISTIC_EMOTIONAL_DECISION_MAKER: 'CommonTraitId' = 306411 - SIM_PREFERENCE_DISLIKES_CHARACTERISTIC_FUNNY: 'CommonTraitId' = 306412 - SIM_PREFERENCE_DISLIKES_CHARACTERISTIC_HARD_WORKER: 'CommonTraitId' = 306413 - SIM_PREFERENCE_DISLIKES_CHARACTERISTIC_HIGH_ENERGY: 'CommonTraitId' = 306414 - SIM_PREFERENCE_DISLIKES_CHARACTERISTIC_HOMEBODY: 'CommonTraitId' = 306417 - SIM_PREFERENCE_DISLIKES_CHARACTERISTIC_IDEALIST: 'CommonTraitId' = 306415 - SIM_PREFERENCE_DISLIKES_CHARACTERISTIC_KID_ENTHUSIAST: 'CommonTraitId' = 306416 - SIM_PREFERENCE_DISLIKES_CHARACTERISTIC_MISCHIEVOUS: 'CommonTraitId' = 306418 - SIM_PREFERENCE_DISLIKES_CHARACTERISTIC_NATURE_ENTHUSIAST: 'CommonTraitId' = 306409 - SIM_PREFERENCE_DISLIKES_CHARACTERISTIC_OPTIMIST: 'CommonTraitId' = 306419 - SIM_PREFERENCE_DISLIKES_CHARACTERISTIC_PESSIMIST: 'CommonTraitId' = 306420 - SIM_PREFERENCE_DISLIKES_CHARACTERISTIC_PET_ENTHUSIAST: 'CommonTraitId' = 306421 - SIM_PREFERENCE_DISLIKES_CHARACTERISTIC_ROMANCE_ENTHUSIAST: 'CommonTraitId' = 306422 - SIM_PREFERENCE_DISLIKES_CHARACTERISTIC_SPIRITED: 'CommonTraitId' = 306424 - SIM_PREFERENCE_DISLIKES_COLOR_BLACK: 'CommonTraitId' = 258209 - SIM_PREFERENCE_DISLIKES_COLOR_BLUE: 'CommonTraitId' = 258205 - SIM_PREFERENCE_DISLIKES_COLOR_BROWN: 'CommonTraitId' = 258208 - SIM_PREFERENCE_DISLIKES_COLOR_GRAY: 'CommonTraitId' = 258211 - SIM_PREFERENCE_DISLIKES_COLOR_GREEN: 'CommonTraitId' = 258204 - SIM_PREFERENCE_DISLIKES_COLOR_ORANGE: 'CommonTraitId' = 257860 - SIM_PREFERENCE_DISLIKES_COLOR_PINK: 'CommonTraitId' = 258212 - SIM_PREFERENCE_DISLIKES_COLOR_PURPLE: 'CommonTraitId' = 258207 - SIM_PREFERENCE_DISLIKES_COLOR_RED: 'CommonTraitId' = 257855 - SIM_PREFERENCE_DISLIKES_COLOR_WHITE: 'CommonTraitId' = 258210 - SIM_PREFERENCE_DISLIKES_COLOR_YELLOW: 'CommonTraitId' = 257861 - SIM_PREFERENCE_DISLIKES_COMMUNICATION_AFFECTION: 'CommonTraitId' = 306481 - SIM_PREFERENCE_DISLIKES_COMMUNICATION_ARGUMENTS: 'CommonTraitId' = 306482 - SIM_PREFERENCE_DISLIKES_COMMUNICATION_COMPLAINTS: 'CommonTraitId' = 306483 - SIM_PREFERENCE_DISLIKES_COMMUNICATION_COMPLIMENTS: 'CommonTraitId' = 306484 - SIM_PREFERENCE_DISLIKES_COMMUNICATION_DECEPTION: 'CommonTraitId' = 306485 - SIM_PREFERENCE_DISLIKES_COMMUNICATION_DEEP_THOUGHTS: 'CommonTraitId' = 306486 - SIM_PREFERENCE_DISLIKES_COMMUNICATION_FLIRTATION: 'CommonTraitId' = 306487 - SIM_PREFERENCE_DISLIKES_COMMUNICATION_GOSSIP: 'CommonTraitId' = 306488 - SIM_PREFERENCE_DISLIKES_COMMUNICATION_HOBBIES: 'CommonTraitId' = 306489 - SIM_PREFERENCE_DISLIKES_COMMUNICATION_INTERESTS: 'CommonTraitId' = 306490 - SIM_PREFERENCE_DISLIKES_COMMUNICATION_JOKES: 'CommonTraitId' = 306491 - SIM_PREFERENCE_DISLIKES_COMMUNICATION_MALICIOUS: 'CommonTraitId' = 306492 - SIM_PREFERENCE_DISLIKES_COMMUNICATION_PHYSICAL_INTIMACY: 'CommonTraitId' = 306493 - SIM_PREFERENCE_DISLIKES_COMMUNICATION_POTTY_HUMOR: 'CommonTraitId' = 306494 - SIM_PREFERENCE_DISLIKES_COMMUNICATION_PRANKS: 'CommonTraitId' = 306495 - SIM_PREFERENCE_DISLIKES_COMMUNICATION_SILLY_BEHAVIOR: 'CommonTraitId' = 306496 - SIM_PREFERENCE_DISLIKES_COMMUNICATION_SMALL_TALK: 'CommonTraitId' = 306497 - SIM_PREFERENCE_DISLIKES_COMMUNICATION_STORIES: 'CommonTraitId' = 306498 - SIM_PREFERENCE_DISLIKES_DECOR_ART_DECO: 'CommonTraitId' = 325842 - SIM_PREFERENCE_DISLIKES_DECOR_BASICS: 'CommonTraitId' = 257867 - SIM_PREFERENCE_DISLIKES_DECOR_BOHO: 'CommonTraitId' = 257886 - SIM_PREFERENCE_DISLIKES_DECOR_CONTEMPORARY: 'CommonTraitId' = 257868 - SIM_PREFERENCE_DISLIKES_DECOR_COSMOLUX: 'CommonTraitId' = 257873 - SIM_PREFERENCE_DISLIKES_DECOR_CUTE: 'CommonTraitId' = 325849 - SIM_PREFERENCE_DISLIKES_DECOR_FRENCH_COUNTRY: 'CommonTraitId' = 257875 - SIM_PREFERENCE_DISLIKES_DECOR_GARDEN: 'CommonTraitId' = 257888 - SIM_PREFERENCE_DISLIKES_DECOR_GOTHIC_FARMHOUSE: 'CommonTraitId' = 257876 - SIM_PREFERENCE_DISLIKES_DECOR_INDUSTRIAL: 'CommonTraitId' = 325840 - SIM_PREFERENCE_DISLIKES_DECOR_ISLAND: 'CommonTraitId' = 257887 - SIM_PREFERENCE_DISLIKES_DECOR_LUXE: 'CommonTraitId' = 325846 - SIM_PREFERENCE_DISLIKES_DECOR_MISSION: 'CommonTraitId' = 257877 - SIM_PREFERENCE_DISLIKES_DECOR_MODERN: 'CommonTraitId' = 257878 - SIM_PREFERENCE_DISLIKES_DECOR_PATIO: 'CommonTraitId' = 257869 - SIM_PREFERENCE_DISLIKES_DECOR_QUEEN_ANNE: 'CommonTraitId' = 257879 - SIM_PREFERENCE_DISLIKES_DECOR_SCANDINAVIAN_CONTEMPORARY: 'CommonTraitId' = 258202 - SIM_PREFERENCE_DISLIKES_DECOR_SHABBY: 'CommonTraitId' = 326010 - SIM_PREFERENCE_DISLIKES_DECOR_SUBURBAN_CONTEMPORARY: 'CommonTraitId' = 257884 - SIM_PREFERENCE_DISLIKES_DECOR_TUDOR: 'CommonTraitId' = 257885 - SIM_PREFERENCE_DISLIKES_DECOR_VINTAGE: 'CommonTraitId' = 325844 - SIM_PREFERENCE_DISLIKES_FASHION_BASICS: 'CommonTraitId' = 272669 - SIM_PREFERENCE_DISLIKES_FASHION_BOHO: 'CommonTraitId' = 283148 - SIM_PREFERENCE_DISLIKES_FASHION_COUNTRY: 'CommonTraitId' = 283149 - SIM_PREFERENCE_DISLIKES_FASHION_HIPSTER: 'CommonTraitId' = 283150 - SIM_PREFERENCE_DISLIKES_FASHION_OUTDOORSY: 'CommonTraitId' = 283151 - SIM_PREFERENCE_DISLIKES_FASHION_POLISHED: 'CommonTraitId' = 283152 - SIM_PREFERENCE_DISLIKES_FASHION_PREPPY: 'CommonTraitId' = 283153 - SIM_PREFERENCE_DISLIKES_FASHION_ROCKER: 'CommonTraitId' = 283154 - SIM_PREFERENCE_DISLIKES_FASHION_STREETWEAR: 'CommonTraitId' = 283155 - SIM_PREFERENCE_DISLIKES_MUSIC_ALTERNATIVE: 'CommonTraitId' = 258255 - SIM_PREFERENCE_DISLIKES_MUSIC_AMERICANA: 'CommonTraitId' = 259055 - SIM_PREFERENCE_DISLIKES_MUSIC_BACKYARD: 'CommonTraitId' = 259056 - SIM_PREFERENCE_DISLIKES_MUSIC_BAROQUE: 'CommonTraitId' = 259057 - SIM_PREFERENCE_DISLIKES_MUSIC_BATUU: 'CommonTraitId' = 346277 - SIM_PREFERENCE_DISLIKES_MUSIC_BLUES: 'CommonTraitId' = 258256 - SIM_PREFERENCE_DISLIKES_MUSIC_BRAZILLIAN: 'CommonTraitId' = 346276 - SIM_PREFERENCE_DISLIKES_MUSIC_CLASSICAL: 'CommonTraitId' = 258257 - SIM_PREFERENCE_DISLIKES_MUSIC_COTTAGE_CORE: 'CommonTraitId' = 274593 - SIM_PREFERENCE_DISLIKES_MUSIC_DJ: 'CommonTraitId' = 267538 - SIM_PREFERENCE_DISLIKES_MUSIC_EASY_LISTENING: 'CommonTraitId' = 259058 - SIM_PREFERENCE_DISLIKES_MUSIC_ELECTRONICA: 'CommonTraitId' = 258258 - SIM_PREFERENCE_DISLIKES_MUSIC_FOCUS: 'CommonTraitId' = 259059 - SIM_PREFERENCE_DISLIKES_MUSIC_HIP_HOP: 'CommonTraitId' = 258259 - SIM_PREFERENCE_DISLIKES_MUSIC_ISLAND: 'CommonTraitId' = 259060 - SIM_PREFERENCE_DISLIKES_MUSIC_JAPANESE_FOLK: 'CommonTraitId' = 259075 - SIM_PREFERENCE_DISLIKES_MUSIC_JAZZ: 'CommonTraitId' = 259076 - SIM_PREFERENCE_DISLIKES_MUSIC_KIDS: 'CommonTraitId' = 258260 - SIM_PREFERENCE_DISLIKES_MUSIC_LATIN: 'CommonTraitId' = 259077 - SIM_PREFERENCE_DISLIKES_MUSIC_LATIN_POP: 'CommonTraitId' = 259078 - SIM_PREFERENCE_DISLIKES_MUSIC_LULLABIES: 'CommonTraitId' = 258261 - SIM_PREFERENCE_DISLIKES_MUSIC_METAL: 'CommonTraitId' = 259079 - SIM_PREFERENCE_DISLIKES_MUSIC_NEW_AGE: 'CommonTraitId' = 259080 - SIM_PREFERENCE_DISLIKES_MUSIC_NU_DISCO: 'CommonTraitId' = 259081 - SIM_PREFERENCE_DISLIKES_MUSIC_OLDIES: 'CommonTraitId' = 312568 - SIM_PREFERENCE_DISLIKES_MUSIC_POP: 'CommonTraitId' = 258262 - SIM_PREFERENCE_DISLIKES_MUSIC_RANCH: 'CommonTraitId' = 334822 - SIM_PREFERENCE_DISLIKES_MUSIC_RETRO: 'CommonTraitId' = 258263 - SIM_PREFERENCE_DISLIKES_MUSIC_RNB: 'CommonTraitId' = 343175 - SIM_PREFERENCE_DISLIKES_MUSIC_ROMANCE: 'CommonTraitId' = 258264 - SIM_PREFERENCE_DISLIKES_MUSIC_SINGER_SONGWRITER: 'CommonTraitId' = 259082 - SIM_PREFERENCE_DISLIKES_MUSIC_SPOOKY: 'CommonTraitId' = 258265 - SIM_PREFERENCE_DISLIKES_MUSIC_STRANGE_TUNES: 'CommonTraitId' = 259083 - SIM_PREFERENCE_DISLIKES_MUSIC_SUMMER_STRUT: 'CommonTraitId' = 259084 - SIM_PREFERENCE_DISLIKES_MUSIC_S_POP: 'CommonTraitId' = 258266 - SIM_PREFERENCE_DISLIKES_MUSIC_TWEEN_POP: 'CommonTraitId' = 259085 - SIM_PREFERENCE_DISLIKES_MUSIC_WINTER_HOLIDAY: 'CommonTraitId' = 258267 - SIM_PREFERENCE_DISLIKES_MUSIC_WORLD: 'CommonTraitId' = 259086 - SIM_PREFERENCE_LIKES_ACTIVITIES_ACTING: 'CommonTraitId' = 264175 - SIM_PREFERENCE_LIKES_ACTIVITIES_BAKING: 'CommonTraitId' = 264547 - SIM_PREFERENCE_LIKES_ACTIVITIES_BOWLING: 'CommonTraitId' = 264177 - SIM_PREFERENCE_LIKES_ACTIVITIES_COMEDY: 'CommonTraitId' = 264178 - SIM_PREFERENCE_LIKES_ACTIVITIES_COOKING: 'CommonTraitId' = 258764 - SIM_PREFERENCE_LIKES_ACTIVITIES_CROSS_STITCH: 'CommonTraitId' = 274575 - SIM_PREFERENCE_LIKES_ACTIVITIES_DANCING: 'CommonTraitId' = 264179 - SIM_PREFERENCE_LIKES_ACTIVITIES_DEBATING: 'CommonTraitId' = 264188 - SIM_PREFERENCE_LIKES_ACTIVITIES_DJ_MIXING: 'CommonTraitId' = 264196 - SIM_PREFERENCE_LIKES_ACTIVITIES_EQUESTRIAN_SKILL: 'CommonTraitId' = 339784 - SIM_PREFERENCE_LIKES_ACTIVITIES_FISHING: 'CommonTraitId' = 264180 - SIM_PREFERENCE_LIKES_ACTIVITIES_FITNESS: 'CommonTraitId' = 258765 - SIM_PREFERENCE_LIKES_ACTIVITIES_GARDENING: 'CommonTraitId' = 264181 - SIM_PREFERENCE_LIKES_ACTIVITIES_GUITAR: 'CommonTraitId' = 264197 - SIM_PREFERENCE_LIKES_ACTIVITIES_HANDINESS: 'CommonTraitId' = 264182 - SIM_PREFERENCE_LIKES_ACTIVITIES_KNITTING: 'CommonTraitId' = 274574 - SIM_PREFERENCE_LIKES_ACTIVITIES_MEDIA_PRODUCTION: 'CommonTraitId' = 264183 - SIM_PREFERENCE_LIKES_ACTIVITIES_MISCHIEF: 'CommonTraitId' = 264184 - SIM_PREFERENCE_LIKES_ACTIVITIES_MIXOLOGY: 'CommonTraitId' = 264185 - SIM_PREFERENCE_LIKES_ACTIVITIES_NECTAR_MAKING: 'CommonTraitId' = 339783 - SIM_PREFERENCE_LIKES_ACTIVITIES_PAINTING: 'CommonTraitId' = 258766 - SIM_PREFERENCE_LIKES_ACTIVITIES_PHOTOGRAPHY: 'CommonTraitId' = 264186 - SIM_PREFERENCE_LIKES_ACTIVITIES_PIANO: 'CommonTraitId' = 264198 - SIM_PREFERENCE_LIKES_ACTIVITIES_PIPE_ORGAN: 'CommonTraitId' = 264199 - SIM_PREFERENCE_LIKES_ACTIVITIES_PROGRAMMING: 'CommonTraitId' = 264187 - SIM_PREFERENCE_LIKES_ACTIVITIES_ROBOTICS: 'CommonTraitId' = 264189 - SIM_PREFERENCE_LIKES_ACTIVITIES_ROCKET_SCIENCE: 'CommonTraitId' = 264191 - SIM_PREFERENCE_LIKES_ACTIVITIES_ROCK_CLIMBING: 'CommonTraitId' = 264190 - SIM_PREFERENCE_LIKES_ACTIVITIES_ROMANCE_SKILL: 'CommonTraitId' = 395732 - SIM_PREFERENCE_LIKES_ACTIVITIES_SINGING: 'CommonTraitId' = 264200 - SIM_PREFERENCE_LIKES_ACTIVITIES_SKIING: 'CommonTraitId' = 264192 - SIM_PREFERENCE_LIKES_ACTIVITIES_SNOWBOARDING: 'CommonTraitId' = 264193 - SIM_PREFERENCE_LIKES_ACTIVITIES_VIDEO_GAMING: 'CommonTraitId' = 258767 - SIM_PREFERENCE_LIKES_ACTIVITIES_VIOLIN: 'CommonTraitId' = 258768 - SIM_PREFERENCE_LIKES_ACTIVITIES_WELLNESS: 'CommonTraitId' = 269262 - SIM_PREFERENCE_LIKES_ACTIVITIES_WRITING: 'CommonTraitId' = 264195 - SIM_PREFERENCE_LIKES_CHARACTERISTIC_AMBITIONLESS: 'CommonTraitId' = 305973 - SIM_PREFERENCE_LIKES_CHARACTERISTIC_ARGUMENTATIVE: 'CommonTraitId' = 305945 - SIM_PREFERENCE_LIKES_CHARACTERISTIC_CEREBRAL: 'CommonTraitId' = 305970 - SIM_PREFERENCE_LIKES_CHARACTERISTIC_EGOTISTICAL: 'CommonTraitId' = 305948 - SIM_PREFERENCE_LIKES_CHARACTERISTIC_EMOTIONAL_DECISION_MAKER: 'CommonTraitId' = 305947 - SIM_PREFERENCE_LIKES_CHARACTERISTIC_FUNNY: 'CommonTraitId' = 305969 - SIM_PREFERENCE_LIKES_CHARACTERISTIC_HARD_WORKER: 'CommonTraitId' = 305972 - SIM_PREFERENCE_LIKES_CHARACTERISTIC_HIGH_ENERGY: 'CommonTraitId' = 305964 - SIM_PREFERENCE_LIKES_CHARACTERISTIC_HOME_BODY: 'CommonTraitId' = 305965 - SIM_PREFERENCE_LIKES_CHARACTERISTIC_HOMEBODY: 'CommonTraitId' = SIM_PREFERENCE_LIKES_CHARACTERISTIC_HOME_BODY - SIM_PREFERENCE_LIKES_CHARACTERISTIC_IDEALIST: 'CommonTraitId' = 305946 - SIM_PREFERENCE_LIKES_CHARACTERISTIC_KID_ENTHUSIAST: 'CommonTraitId' = 305960 - SIM_PREFERENCE_LIKES_CHARACTERISTIC_MISCHIEVOUS: 'CommonTraitId' = 305968 - SIM_PREFERENCE_LIKES_CHARACTERISTIC_NATURE_ENTHUSIAST: 'CommonTraitId' = 305967 - SIM_PREFERENCE_LIKES_CHARACTERISTIC_OPTIMIST: 'CommonTraitId' = 305971 - SIM_PREFERENCE_LIKES_CHARACTERISTIC_PESSIMIST: 'CommonTraitId' = 305944 - SIM_PREFERENCE_LIKES_CHARACTERISTIC_PET_ENTHUSIAST: 'CommonTraitId' = 305961 - SIM_PREFERENCE_LIKES_CHARACTERISTIC_ROMANCE_ENTHUSIAST: 'CommonTraitId' = 305949 - SIM_PREFERENCE_LIKES_CHARACTERISTIC_SPIRITED: 'CommonTraitId' = 305966 - SIM_PREFERENCE_LIKES_COLOR_BLACK: 'CommonTraitId' = 258213 - SIM_PREFERENCE_LIKES_COLOR_BLUE: 'CommonTraitId' = 258214 - SIM_PREFERENCE_LIKES_COLOR_BROWN: 'CommonTraitId' = 258215 - SIM_PREFERENCE_LIKES_COLOR_GRAY: 'CommonTraitId' = 258216 - SIM_PREFERENCE_LIKES_COLOR_GREEN: 'CommonTraitId' = 258217 - SIM_PREFERENCE_LIKES_COLOR_ORANGE: 'CommonTraitId' = 257862 - SIM_PREFERENCE_LIKES_COLOR_PINK: 'CommonTraitId' = 258218 - SIM_PREFERENCE_LIKES_COLOR_PURPLE: 'CommonTraitId' = 258219 - SIM_PREFERENCE_LIKES_COLOR_RED: 'CommonTraitId' = 257863 - SIM_PREFERENCE_LIKES_COLOR_WHITE: 'CommonTraitId' = 258220 - SIM_PREFERENCE_LIKES_COLOR_YELLOW: 'CommonTraitId' = 257864 - SIM_PREFERENCE_LIKES_COMMUNICATION_AFFECTION: 'CommonTraitId' = 306474 - SIM_PREFERENCE_LIKES_COMMUNICATION_ARGUMENTS: 'CommonTraitId' = 306473 - SIM_PREFERENCE_LIKES_COMMUNICATION_COMPLAINTS: 'CommonTraitId' = 306479 - SIM_PREFERENCE_LIKES_COMMUNICATION_COMPLIMENTS: 'CommonTraitId' = 306464 - SIM_PREFERENCE_LIKES_COMMUNICATION_DECEPTION: 'CommonTraitId' = 306471 - SIM_PREFERENCE_LIKES_COMMUNICATION_DEEP_THOUGHTS: 'CommonTraitId' = 306465 - SIM_PREFERENCE_LIKES_COMMUNICATION_FLIRTATION: 'CommonTraitId' = 306463 - SIM_PREFERENCE_LIKES_COMMUNICATION_GOSSIP: 'CommonTraitId' = 306478 - SIM_PREFERENCE_LIKES_COMMUNICATION_HOBBIES: 'CommonTraitId' = 306476 - SIM_PREFERENCE_LIKES_COMMUNICATION_INTERESTS: 'CommonTraitId' = 306477 - SIM_PREFERENCE_LIKES_COMMUNICATION_JOKES: 'CommonTraitId' = 306469 - SIM_PREFERENCE_LIKES_COMMUNICATION_MALICIOUS: 'CommonTraitId' = 306472 - SIM_PREFERENCE_LIKES_COMMUNICATION_PHYSICAL_INTIMACY: 'CommonTraitId' = 306462 - SIM_PREFERENCE_LIKES_COMMUNICATION_POTTY_HUMOR: 'CommonTraitId' = 306468 - SIM_PREFERENCE_LIKES_COMMUNICATION_PRANKS: 'CommonTraitId' = 306470 - SIM_PREFERENCE_LIKES_COMMUNICATION_SILLY_BEHAVIOR: 'CommonTraitId' = 306467 - SIM_PREFERENCE_LIKES_COMMUNICATION_SMALL_TALK: 'CommonTraitId' = 306475 - SIM_PREFERENCE_LIKES_COMMUNICATION_STORIES: 'CommonTraitId' = 306466 - SIM_PREFERENCE_LIKES_DECOR_ART_DECO: 'CommonTraitId' = 325843 - SIM_PREFERENCE_LIKES_DECOR_BASICS: 'CommonTraitId' = 257870 - SIM_PREFERENCE_LIKES_DECOR_BOHO: 'CommonTraitId' = 257889 - SIM_PREFERENCE_LIKES_DECOR_CONTEMPORARY: 'CommonTraitId' = 257871 - SIM_PREFERENCE_LIKES_DECOR_COSMOLUX: 'CommonTraitId' = 257890 - SIM_PREFERENCE_LIKES_DECOR_CUTE: 'CommonTraitId' = 325848 - SIM_PREFERENCE_LIKES_DECOR_FRENCH_COUNTRY: 'CommonTraitId' = 257892 - SIM_PREFERENCE_LIKES_DECOR_GARDEN: 'CommonTraitId' = 257893 - SIM_PREFERENCE_LIKES_DECOR_GOTHIC_FARMHOUSE: 'CommonTraitId' = 257894 - SIM_PREFERENCE_LIKES_DECOR_INDUSTRIAL: 'CommonTraitId' = 325841 - SIM_PREFERENCE_LIKES_DECOR_ISLAND: 'CommonTraitId' = 257895 - SIM_PREFERENCE_LIKES_DECOR_LUXE: 'CommonTraitId' = 325847 - SIM_PREFERENCE_LIKES_DECOR_MISSION: 'CommonTraitId' = 257896 - SIM_PREFERENCE_LIKES_DECOR_MODERN: 'CommonTraitId' = 257897 - SIM_PREFERENCE_LIKES_DECOR_PATIO: 'CommonTraitId' = 257872 - SIM_PREFERENCE_LIKES_DECOR_QUEEN_ANNE: 'CommonTraitId' = 257898 - SIM_PREFERENCE_LIKES_DECOR_SCANDINAVIAN_CONTEMPORARY: 'CommonTraitId' = 258203 - SIM_PREFERENCE_LIKES_DECOR_SHABBY: 'CommonTraitId' = 326011 - SIM_PREFERENCE_LIKES_DECOR_SUBURBAN_CONTEMPORARY: 'CommonTraitId' = 257900 - SIM_PREFERENCE_LIKES_DECOR_TUDOR: 'CommonTraitId' = 257901 - SIM_PREFERENCE_LIKES_DECOR_VINTAGE: 'CommonTraitId' = 325845 - SIM_PREFERENCE_LIKES_FASHION_BASICS: 'CommonTraitId' = 272670 - SIM_PREFERENCE_LIKES_FASHION_BOHO: 'CommonTraitId' = 283161 - SIM_PREFERENCE_LIKES_FASHION_COUNTRY: 'CommonTraitId' = 283162 - SIM_PREFERENCE_LIKES_FASHION_HIPSTER: 'CommonTraitId' = 283164 - SIM_PREFERENCE_LIKES_FASHION_OUTDOORSY: 'CommonTraitId' = 283165 - SIM_PREFERENCE_LIKES_FASHION_POLISHED: 'CommonTraitId' = 283166 - SIM_PREFERENCE_LIKES_FASHION_PREPPY: 'CommonTraitId' = 283167 - SIM_PREFERENCE_LIKES_FASHION_ROCKER: 'CommonTraitId' = 283168 - SIM_PREFERENCE_LIKES_FASHION_STREETWEAR: 'CommonTraitId' = 283169 - SIM_PREFERENCE_LIKES_MUSIC_ALTERNATIVE: 'CommonTraitId' = 258269 - SIM_PREFERENCE_LIKES_MUSIC_AMERICANA: 'CommonTraitId' = 259041 - SIM_PREFERENCE_LIKES_MUSIC_BACKYARD: 'CommonTraitId' = 259015 - SIM_PREFERENCE_LIKES_MUSIC_BAROQUE: 'CommonTraitId' = 259017 - SIM_PREFERENCE_LIKES_MUSIC_BATUU: 'CommonTraitId' = 346279 - SIM_PREFERENCE_LIKES_MUSIC_BLUES: 'CommonTraitId' = 258270 - SIM_PREFERENCE_LIKES_MUSIC_BRAZILLIAN: 'CommonTraitId' = 346280 - SIM_PREFERENCE_LIKES_MUSIC_CLASSICAL: 'CommonTraitId' = 258271 - SIM_PREFERENCE_LIKES_MUSIC_COTTAGE_CORE: 'CommonTraitId' = 274594 - SIM_PREFERENCE_LIKES_MUSIC_DJ: 'CommonTraitId' = 267539 - SIM_PREFERENCE_LIKES_MUSIC_EASY_LISTENING: 'CommonTraitId' = 259014 - SIM_PREFERENCE_LIKES_MUSIC_ELECTRONICA: 'CommonTraitId' = 258272 - SIM_PREFERENCE_LIKES_MUSIC_FOCUS: 'CommonTraitId' = 259043 - SIM_PREFERENCE_LIKES_MUSIC_HIP_HOP: 'CommonTraitId' = 258273 - SIM_PREFERENCE_LIKES_MUSIC_ISLAND: 'CommonTraitId' = 259040 - SIM_PREFERENCE_LIKES_MUSIC_JAPANESE_FOLK: 'CommonTraitId' = 259047 - SIM_PREFERENCE_LIKES_MUSIC_JAZZ: 'CommonTraitId' = 259024 - SIM_PREFERENCE_LIKES_MUSIC_KIDS: 'CommonTraitId' = 258274 - SIM_PREFERENCE_LIKES_MUSIC_LATIN: 'CommonTraitId' = 259032 - SIM_PREFERENCE_LIKES_MUSIC_LATIN_POP: 'CommonTraitId' = 259031 - SIM_PREFERENCE_LIKES_MUSIC_LULLABIES: 'CommonTraitId' = 258275 - SIM_PREFERENCE_LIKES_MUSIC_METAL: 'CommonTraitId' = 259045 - SIM_PREFERENCE_LIKES_MUSIC_NEW_AGE: 'CommonTraitId' = 259016 - SIM_PREFERENCE_LIKES_MUSIC_NU_DISCO: 'CommonTraitId' = 259029 - SIM_PREFERENCE_LIKES_MUSIC_OLDIES: 'CommonTraitId' = 312569 - SIM_PREFERENCE_LIKES_MUSIC_POP: 'CommonTraitId' = 258276 - SIM_PREFERENCE_LIKES_MUSIC_RANCH: 'CommonTraitId' = 334823 - SIM_PREFERENCE_LIKES_MUSIC_RETRO: 'CommonTraitId' = 258277 - SIM_PREFERENCE_LIKES_MUSIC_RNB: 'CommonTraitId' = 343176 - SIM_PREFERENCE_LIKES_MUSIC_ROMANCE: 'CommonTraitId' = 258278 - SIM_PREFERENCE_LIKES_MUSIC_SINGER_SONGWRITER: 'CommonTraitId' = 259030 - SIM_PREFERENCE_LIKES_MUSIC_SPOOKY: 'CommonTraitId' = 258279 - SIM_PREFERENCE_LIKES_MUSIC_STRANGE_TUNES: 'CommonTraitId' = 259039 - SIM_PREFERENCE_LIKES_MUSIC_SUMMER_STRUT: 'CommonTraitId' = 259038 - SIM_PREFERENCE_LIKES_MUSIC_S_POP: 'CommonTraitId' = 258280 - SIM_PREFERENCE_LIKES_MUSIC_TWEEN_POP: 'CommonTraitId' = 259026 - SIM_PREFERENCE_LIKES_MUSIC_WINTER_HOLIDAY: 'CommonTraitId' = 258281 - SIM_PREFERENCE_LIKES_MUSIC_WORLD: 'CommonTraitId' = 259028 - SIM_PREFERENCE_NO_OPINION_ACTIVITIES_ACTING: 'CommonTraitId' = 266840 - SIM_PREFERENCE_NO_OPINION_ACTIVITIES_BAKING: 'CommonTraitId' = 266818 - SIM_PREFERENCE_NO_OPINION_ACTIVITIES_BOWLING: 'CommonTraitId' = 266834 - SIM_PREFERENCE_NO_OPINION_ACTIVITIES_COMEDY: 'CommonTraitId' = 266799 - SIM_PREFERENCE_NO_OPINION_ACTIVITIES_COOKING: 'CommonTraitId' = 266800 - SIM_PREFERENCE_NO_OPINION_ACTIVITIES_CROSS_STITCH: 'CommonTraitId' = 274576 - SIM_PREFERENCE_NO_OPINION_ACTIVITIES_DANCING: 'CommonTraitId' = 266823 - SIM_PREFERENCE_NO_OPINION_ACTIVITIES_DEBATING: 'CommonTraitId' = 266843 - SIM_PREFERENCE_NO_OPINION_ACTIVITIES_DJ_MIXING: 'CommonTraitId' = 266833 - SIM_PREFERENCE_NO_OPINION_ACTIVITIES_EQUESTRIAN_SKILL: 'CommonTraitId' = 339800 - SIM_PREFERENCE_NO_OPINION_ACTIVITIES_FISHING: 'CommonTraitId' = 266801 - SIM_PREFERENCE_NO_OPINION_ACTIVITIES_FITNESS: 'CommonTraitId' = 266802 - SIM_PREFERENCE_NO_OPINION_ACTIVITIES_GARDENING: 'CommonTraitId' = 266803 - SIM_PREFERENCE_NO_OPINION_ACTIVITIES_GUITAR: 'CommonTraitId' = 266804 - SIM_PREFERENCE_NO_OPINION_ACTIVITIES_HANDINESS: 'CommonTraitId' = 266805 - SIM_PREFERENCE_NO_OPINION_ACTIVITIES_KNITTING: 'CommonTraitId' = 274577 - SIM_PREFERENCE_NO_OPINION_ACTIVITIES_MEDIA_PRODUCTION: 'CommonTraitId' = 266842 - SIM_PREFERENCE_NO_OPINION_ACTIVITIES_MISCHIEF: 'CommonTraitId' = 266806 - SIM_PREFERENCE_NO_OPINION_ACTIVITIES_MIXOLOGY: 'CommonTraitId' = 266809 - SIM_PREFERENCE_NO_OPINION_ACTIVITIES_NECTAR_MAKING: 'CommonTraitId' = 339799 - SIM_PREFERENCE_NO_OPINION_ACTIVITIES_PAINTING: 'CommonTraitId' = 266810 - SIM_PREFERENCE_NO_OPINION_ACTIVITIES_PHOTOGRAPHY: 'CommonTraitId' = 266819 - SIM_PREFERENCE_NO_OPINION_ACTIVITIES_PIANO: 'CommonTraitId' = 266811 - SIM_PREFERENCE_NO_OPINION_ACTIVITIES_PIPE_ORGAN: 'CommonTraitId' = 266838 - SIM_PREFERENCE_NO_OPINION_ACTIVITIES_PROGRAMMING: 'CommonTraitId' = 266812 - SIM_PREFERENCE_NO_OPINION_ACTIVITIES_ROBOTICS: 'CommonTraitId' = 266844 - SIM_PREFERENCE_NO_OPINION_ACTIVITIES_ROCKET_SCIENCE: 'CommonTraitId' = 266813 - SIM_PREFERENCE_NO_OPINION_ACTIVITIES_ROCK_CLIMBING: 'CommonTraitId' = 266845 - SIM_PREFERENCE_NO_OPINION_ACTIVITIES_SINGING: 'CommonTraitId' = 266839 - SIM_PREFERENCE_NO_OPINION_ACTIVITIES_SKIING: 'CommonTraitId' = 266846 - SIM_PREFERENCE_NO_OPINION_ACTIVITIES_SNOWBOARDING: 'CommonTraitId' = 266847 - SIM_PREFERENCE_NO_OPINION_ACTIVITIES_VIDEO_GAMING: 'CommonTraitId' = 261875 - SIM_PREFERENCE_NO_OPINION_ACTIVITIES_VIOLIN: 'CommonTraitId' = 266815 - SIM_PREFERENCE_NO_OPINION_ACTIVITIES_WELLNESS: 'CommonTraitId' = 266816 - SIM_PREFERENCE_NO_OPINION_ACTIVITIES_WRITING: 'CommonTraitId' = 266817 - SIM_PREFERENCE_NO_OPINION_CHARACTERISTIC_AMBITIONLESS: 'CommonTraitId' = 316490 - SIM_PREFERENCE_NO_OPINION_CHARACTERISTIC_ARGUMENTATIVE: 'CommonTraitId' = 316491 - SIM_PREFERENCE_NO_OPINION_CHARACTERISTIC_CEREBRAL: 'CommonTraitId' = 316517 - SIM_PREFERENCE_NO_OPINION_CHARACTERISTIC_EGOTISTICAL: 'CommonTraitId' = 316518 - SIM_PREFERENCE_NO_OPINION_CHARACTERISTIC_EMOTIONAL_DECISION_MAKER: 'CommonTraitId' = 316519 - SIM_PREFERENCE_NO_OPINION_CHARACTERISTIC_FUNNY: 'CommonTraitId' = 316520 - SIM_PREFERENCE_NO_OPINION_CHARACTERISTIC_HARD_WORKER: 'CommonTraitId' = 316521 - SIM_PREFERENCE_NO_OPINION_CHARACTERISTIC_HIGH_ENERGY: 'CommonTraitId' = 316522 - SIM_PREFERENCE_NO_OPINION_CHARACTERISTIC_HOMEBODY: 'CommonTraitId' = 316523 - SIM_PREFERENCE_NO_OPINION_CHARACTERISTIC_IDEALIST: 'CommonTraitId' = 316524 - SIM_PREFERENCE_NO_OPINION_CHARACTERISTIC_KID_ENTHUSIAST: 'CommonTraitId' = 316492 - SIM_PREFERENCE_NO_OPINION_CHARACTERISTIC_MISCHIEVOUS: 'CommonTraitId' = 316493 - SIM_PREFERENCE_NO_OPINION_CHARACTERISTIC_NATURE_ENTHUSIAST: 'CommonTraitId' = 316494 - SIM_PREFERENCE_NO_OPINION_CHARACTERISTIC_OPTIMIST: 'CommonTraitId' = 316495 - SIM_PREFERENCE_NO_OPINION_CHARACTERISTIC_PESSIMIST: 'CommonTraitId' = 316496 - SIM_PREFERENCE_NO_OPINION_CHARACTERISTIC_PET_ENTHUSIAST: 'CommonTraitId' = 316497 - SIM_PREFERENCE_NO_OPINION_CHARACTERISTIC_ROMANCE_ENTHUSIAST: 'CommonTraitId' = 316515 - SIM_PREFERENCE_NO_OPINION_CHARACTERISTIC_SPIRITED: 'CommonTraitId' = 316516 - SIM_PREFERENCE_NO_OPINION_COMMUNICATION_AFFECTION: 'CommonTraitId' = 312878 - SIM_PREFERENCE_NO_OPINION_COMMUNICATION_ARGUMENTS: 'CommonTraitId' = 312879 - SIM_PREFERENCE_NO_OPINION_COMMUNICATION_COMPLAINTS: 'CommonTraitId' = 312898 - SIM_PREFERENCE_NO_OPINION_COMMUNICATION_COMPLIMENTS: 'CommonTraitId' = 312899 - SIM_PREFERENCE_NO_OPINION_COMMUNICATION_DECEPTION: 'CommonTraitId' = 312900 - SIM_PREFERENCE_NO_OPINION_COMMUNICATION_DEEP_THOUGHTS: 'CommonTraitId' = 312901 - SIM_PREFERENCE_NO_OPINION_COMMUNICATION_FLIRTATION: 'CommonTraitId' = 312902 - SIM_PREFERENCE_NO_OPINION_COMMUNICATION_GOSSIP: 'CommonTraitId' = 312903 - SIM_PREFERENCE_NO_OPINION_COMMUNICATION_HOBBIES: 'CommonTraitId' = 312904 - SIM_PREFERENCE_NO_OPINION_COMMUNICATION_INTERESTS: 'CommonTraitId' = 312905 - SIM_PREFERENCE_NO_OPINION_COMMUNICATION_JOKES: 'CommonTraitId' = 312880 - SIM_PREFERENCE_NO_OPINION_COMMUNICATION_MALICIOUS: 'CommonTraitId' = 312881 - SIM_PREFERENCE_NO_OPINION_COMMUNICATION_PHYSICAL_INTIMACY: 'CommonTraitId' = 312882 - SIM_PREFERENCE_NO_OPINION_COMMUNICATION_POTTY_HUMOR: 'CommonTraitId' = 312883 - SIM_PREFERENCE_NO_OPINION_COMMUNICATION_PRANKS: 'CommonTraitId' = 312894 - SIM_PREFERENCE_NO_OPINION_COMMUNICATION_SILLY_BEHAVIOR: 'CommonTraitId' = 312895 - SIM_PREFERENCE_NO_OPINION_COMMUNICATION_SMALL_TALK: 'CommonTraitId' = 312896 - SIM_PREFERENCE_NO_OPINION_COMMUNICATION_STORIES: 'CommonTraitId' = 312897 - SIM_PREFERENCE_NO_OPINION_FASHION_BASICS: 'CommonTraitId' = 272672 - SIM_PREFERENCE_NO_OPINION_FASHION_BOHO: 'CommonTraitId' = 283171 - SIM_PREFERENCE_NO_OPINION_FASHION_COUNTRY: 'CommonTraitId' = 283172 - SIM_PREFERENCE_NO_OPINION_FASHION_HIPSTER: 'CommonTraitId' = 283173 - SIM_PREFERENCE_NO_OPINION_FASHION_OUTDOORSY: 'CommonTraitId' = 283174 - SIM_PREFERENCE_NO_OPINION_FASHION_POLISHED: 'CommonTraitId' = 283175 - SIM_PREFERENCE_NO_OPINION_FASHION_PREPPY: 'CommonTraitId' = 283184 - SIM_PREFERENCE_NO_OPINION_FASHION_ROCKER: 'CommonTraitId' = 283186 - SIM_PREFERENCE_NO_OPINION_FASHION_STREETWEAR: 'CommonTraitId' = 283188 - SIM_PREFERENCE_NO_OPINION_MUSIC_ALL: 'CommonTraitId' = 266000 - SIM_PREFERENCE_NO_OPINION_VIDEO_GAMING: 'CommonTraitId' = 266814 - SIM_REPUTATION_HOST: 'CommonTraitId' = 195566 - SINCERE: 'CommonTraitId' = 26899 - SKILL_IMAGINATION_1: 'CommonTraitId' = 156834 - SKILL_IMAGINATION_2: 'CommonTraitId' = 156835 - SKILL_IMAGINATION_3: 'CommonTraitId' = 156836 - SKILL_IMAGINATION_4: 'CommonTraitId' = 156837 - SKILL_IMAGINATION_5: 'CommonTraitId' = 156838 - SLEIGHT_OF_HAND: 'CommonTraitId' = 238656 - SLOB: 'CommonTraitId' = 16860 - SMART_HUB_WAKE_UP_ROUTINE_DAILY_AFFIRMATION: 'CommonTraitId' = 203984 - SMART_HUB_WAKE_UP_ROUTINE_DAILY_JOKE: 'CommonTraitId' = 203993 - SMART_HUB_WAKE_UP_ROUTINE_DAILY_NEWS: 'CommonTraitId' = 204005 - SNOB: 'CommonTraitId' = 9620 - SNOOPING_MENACE: 'CommonTraitId' = 350399 - SNOOPING_SAFE_KEEPER: 'CommonTraitId' = 350400 - SNOWBOARDING_GOOFY: 'CommonTraitId' = 252108 - SNOW_SPORTS_SLOPE_INTENSITY_HIGH: 'CommonTraitId' = 249604 - SNOW_SPORTS_SLOPE_INTENSITY_LOW: 'CommonTraitId' = 249602 - SNOW_SPORTS_SLOPE_INTENSITY_MED: 'CommonTraitId' = 249603 - SNOW_SPORTS_SLOPE_SLED_ARMS_UP: 'CommonTraitId' = 253763 - SNOW_SPORTS_SLOPE_SNOWBOARDING_RECORD_VIDEO: 'CommonTraitId' = 250347 - SOCCER_TEAM_PRO_SPORTS: 'CommonTraitId' = 226864 - SOCIALLY_AWKWARD: 'CommonTraitId' = 272629 - SOCIALLY_GIFTED: 'CommonTraitId' = 29622 - SOCIAL_MEDIA_APPLICATION_DISABLE: 'CommonTraitId' = 298846 - SOCIAL_MEDIA_NOTIFICATION_DISABLE: 'CommonTraitId' = 298867 - SPECIAL_NPC_AGNON: 'CommonTraitId' = 239021 - SPECIAL_NPC_GUIDRY: 'CommonTraitId' = 252849 - SPECIAL_NPC_HONDO: 'CommonTraitId' = 238708 - SPECIAL_NPC_IS_FTUE_ROOMMATE: 'CommonTraitId' = 200832 - SPECIAL_NPC_KYLO_REN: 'CommonTraitId' = 238970 - SPECIAL_NPC_REY: 'CommonTraitId' = 238969 - SPECIAL_NPC_SAMMY_GARCIA: 'CommonTraitId' = 376258 - SPECIAL_NPC_THERING_BEAR: 'CommonTraitId' = 369735 - SPECIAL_NPC_VI: 'CommonTraitId' = 239020 - SPECIAL_NP_CS_BABY_ARIEL: 'CommonTraitId' = 202424 - SPECIAL_NP_CS_GAMES_COM_LOVE_INTEREST: 'CommonTraitId' = 123110 - SPECIES_CAT: 'CommonTraitId' = 144685 - SPECIES_DOG: 'CommonTraitId' = 131194 - SPECIES_EXTENDED_LARGE_DOGS: 'CommonTraitId' = 173557 - SPECIES_EXTENDED_SMALL_DOGS: 'CommonTraitId' = 173556 - SPECIES_FOX: 'CommonTraitId' = 259921 - SPECIES_HORSE: 'CommonTraitId' = 308723 - SPECIES_HUMAN: 'CommonTraitId' = 151039 - SPEED_CLEANER: 'CommonTraitId' = 26639 - SPEED_READER: 'CommonTraitId' = 32621 - SPELLCASTER_PRE_MADE: 'CommonTraitId' = 221486 - SPICE_HOUND: 'CommonTraitId' = 146103 - SQUEAMISH: 'CommonTraitId' = 102336 - STEEL_BLADDER: 'CommonTraitId' = 26391 - STORM_CHASER: 'CommonTraitId' = 185795 - STOVES_AND_GRILLS_MASTER: 'CommonTraitId' = 104880 - STRANGER_VILLE_ACTIVELY_POSSESSED_OVERLAY: 'CommonTraitId' = 203163 - STRANGER_VILLE_EXAMINED_LAB_DOOR: 'CommonTraitId' = 201957 - STRANGER_VILLE_HAS_ASKED_AROUND: 'CommonTraitId' = 205285 - STRANGER_VILLE_HAS_DEFEATED_MOTHER_PLANT: 'CommonTraitId' = 206106 - STRANGER_VILLE_HAS_OPENED_DOOR: 'CommonTraitId' = 203165 - STRANGER_VILLE_HAS_SEEN_MOTHER_PLANT: 'CommonTraitId' = 206105 - STRANGER_VILLE_INFECTED: 'CommonTraitId' = 201407 - STRANGER_VILLE_VACCINATED: 'CommonTraitId' = 207348 - STRANGER_VILLE_VETERAN_HERMIT: 'CommonTraitId' = 203142 - STRANGE_TOWN_AGENT: 'CommonTraitId' = 201990 - STRANGE_TOWN_CONSPIRACIST: 'CommonTraitId' = 201991 - STRANGE_TOWN_CURIO_SHOP: 'CommonTraitId' = 204106 - STRANGE_TOWN_MILITARY: 'CommonTraitId' = 201988 - STRANGE_TOWN_NPC_PRE_MADE_SIM: 'CommonTraitId' = 207204 - STRANGE_TOWN_SCIENTIST: 'CommonTraitId' = 201989 - SUMMIT_LOCAL: 'CommonTraitId' = 246366 - SUPER_GREEN_THUMB: 'CommonTraitId' = 35511 - SUPER_PARENT_ROLE_MODEL: 'CommonTraitId' = 165025 - SUPREME_AUTHORITY: 'CommonTraitId' = 238655 - SURPRISE_HOLIDAY_DISCOUNT_DAY: 'CommonTraitId' = 181915 - SURPRISE_HOLIDAY_PIRATE_DAY: 'CommonTraitId' = 184130 - SURVIVALIST: 'CommonTraitId' = 108876 - SURVIVAL_INSTINCT: 'CommonTraitId' = 249731 - TAIL_STYLE_DOWN: 'CommonTraitId' = 128513 - TAIL_STYLE_UP: 'CommonTraitId' = 128514 - TEEN: 'CommonTraitId' = 34317 - TEEN_PRANKS_PRANKSTER: 'CommonTraitId' = 292269 - TEMPERATURE_BURNING_MAN: 'CommonTraitId' = 183508 - TEMPERATURE_COLD_ACCLIMATION: 'CommonTraitId' = 183505 - TEMPERATURE_HEAT_ACCLIMATION: 'CommonTraitId' = 183506 - TEMPERATURE_ICE_MAN: 'CommonTraitId' = 183507 - TEMPORARY_STAY_GUEST_HIDDEN: 'CommonTraitId' = 303296 - TEMPORARY_STAY_HAD_INFANT_INTRO_HIDDEN: 'CommonTraitId' = 324274 - TEMPORARY_STAY_RECENTLY_ARRIVED_HIDDEN: 'CommonTraitId' = 323019 - THE_KNACK: 'CommonTraitId' = 27328 - THE_MASTER: 'CommonTraitId' = 155323 - TODDLER: 'CommonTraitId' = 133125 - TODDLER_ANGELIC: 'CommonTraitId' = 140740 - TODDLER_CHARMER: 'CommonTraitId' = 140742 - TODDLER_CLINGY: 'CommonTraitId' = 140744 - TODDLER_FUSSY: 'CommonTraitId' = 140739 - TODDLER_HAPPY: 'CommonTraitId' = 216611 - TODDLER_INDEPENDENT: 'CommonTraitId' = 140746 - TODDLER_INQUISITIVE: 'CommonTraitId' = 140745 - TODDLER_PERSONALITY_AGGRESSIVE_HIDDEN: 'CommonTraitId' = 306521 - TODDLER_PERSONALITY_AGGRESSIVE_VISIBLE: 'CommonTraitId' = 319855 - TODDLER_PERSONALITY_AUDIO_LOVER_HIDDEN: 'CommonTraitId' = 306525 - TODDLER_PERSONALITY_AUDIO_LOVER_VISIBLE: 'CommonTraitId' = 319856 - TODDLER_PERSONALITY_BOOK_LOVER_HIDDEN: 'CommonTraitId' = 306524 - TODDLER_PERSONALITY_BOOK_LOVER_VISIBLE: 'CommonTraitId' = 319865 - TODDLER_PERSONALITY_DESTRUCTIVE_HIDDEN: 'CommonTraitId' = 306522 - TODDLER_PERSONALITY_DESTRUCTIVE_VISIBLE: 'CommonTraitId' = 319866 - TODDLER_PERSONALITY_EARLY_RISER_HIDDEN: 'CommonTraitId' = 306528 - TODDLER_PERSONALITY_EARLY_RISER_VISIBLE: 'CommonTraitId' = 319867 - TODDLER_PERSONALITY_GOOD_APPETITE_HIDDEN: 'CommonTraitId' = 306531 - TODDLER_PERSONALITY_GOOD_APPETITE_VISIBLE: 'CommonTraitId' = 319868 - TODDLER_PERSONALITY_HATES_BED_TIME_HIDDEN: 'CommonTraitId' = 306527 - TODDLER_PERSONALITY_HATES_BED_TIME_VISIBLE: 'CommonTraitId' = 319869 - TODDLER_PERSONALITY_HATES_CARRY_HIDDEN: 'CommonTraitId' = 306532 - TODDLER_PERSONALITY_HATES_CARRY_VISIBLE: 'CommonTraitId' = 319870 - TODDLER_PERSONALITY_HATES_WAKE_UP_HIDDEN: 'CommonTraitId' = 306533 - TODDLER_PERSONALITY_HATES_WAKE_UP_VISIBLE: 'CommonTraitId' = 319871 - TODDLER_PERSONALITY_HEAVY_SLEEPER_HIDDEN: 'CommonTraitId' = 306534 - TODDLER_PERSONALITY_HEAVY_SLEEPER_VISIBLE: 'CommonTraitId' = 319872 - TODDLER_PERSONALITY_LIGHT_SLEEPER_HIDDEN: 'CommonTraitId' = 306535 - TODDLER_PERSONALITY_LIGHT_SLEEPER_VISIBLE: 'CommonTraitId' = 319857 - TODDLER_PERSONALITY_LOVES_CARRY_HIDDEN: 'CommonTraitId' = 306536 - TODDLER_PERSONALITY_LOVES_CARRY_VISIBLE: 'CommonTraitId' = 319858 - TODDLER_PERSONALITY_LOVES_WAKE_UP_HIDDEN: 'CommonTraitId' = 306537 - TODDLER_PERSONALITY_LOVES_WAKE_UP_VISIBLE: 'CommonTraitId' = 319859 - TODDLER_PERSONALITY_MESSY_EATER_HIDDEN: 'CommonTraitId' = 306523 - TODDLER_PERSONALITY_MESSY_EATER_VISIBLE: 'CommonTraitId' = 319860 - TODDLER_PERSONALITY_PICKY_EATER_HIDDEN: 'CommonTraitId' = 306526 - TODDLER_PERSONALITY_PICKY_EATER_VISIBLE: 'CommonTraitId' = 319861 - TODDLER_PERSONALITY_RUNS_AWAY_HIDDEN: 'CommonTraitId' = 306529 - TODDLER_PERSONALITY_RUNS_AWAY_VISIBLE: 'CommonTraitId' = 319862 - TODDLER_PERSONALITY_SINGER_HIDDEN: 'CommonTraitId' = 306530 - TODDLER_PERSONALITY_SINGER_VISIBLE: 'CommonTraitId' = 319863 - TODDLER_PERSONALITY_WATER_LOVER_HIDDEN: 'CommonTraitId' = 305298 - TODDLER_PERSONALITY_WATER_LOVER_VISIBLE: 'CommonTraitId' = 319864 - TODDLER_SILLY: 'CommonTraitId' = 140743 - TODDLER_TOP_NOTCH: 'CommonTraitId' = 216610 - TODDLER_WILD: 'CommonTraitId' = 140741 - TOP_NOTCH_TODDLER: 'CommonTraitId' = 143156 - TOP_RIDER_HAS_WON_ULTIMATE_CHAMPIONSHIP_HIDDEN: 'CommonTraitId' = 332409 - TOWN_MASCOT: 'CommonTraitId' = 249203 - TRUE_MASTER: 'CommonTraitId' = 155322 - UMBRELLA_PREFERENCE_ADULT_1: 'CommonTraitId' = 185828 - UMBRELLA_PREFERENCE_ADULT_10: 'CommonTraitId' = 185837 - UMBRELLA_PREFERENCE_ADULT_11: 'CommonTraitId' = 185838 - UMBRELLA_PREFERENCE_ADULT_12: 'CommonTraitId' = 185839 - UMBRELLA_PREFERENCE_ADULT_2: 'CommonTraitId' = 185829 - UMBRELLA_PREFERENCE_ADULT_3: 'CommonTraitId' = 185830 - UMBRELLA_PREFERENCE_ADULT_4: 'CommonTraitId' = 185831 - UMBRELLA_PREFERENCE_ADULT_5: 'CommonTraitId' = 185832 - UMBRELLA_PREFERENCE_ADULT_6: 'CommonTraitId' = 185833 - UMBRELLA_PREFERENCE_ADULT_7: 'CommonTraitId' = 185834 - UMBRELLA_PREFERENCE_ADULT_8: 'CommonTraitId' = 185835 - UMBRELLA_PREFERENCE_ADULT_9: 'CommonTraitId' = 185836 - UMBRELLA_PREFERENCE_CHILD_1: 'CommonTraitId' = 185881 - UMBRELLA_PREFERENCE_CHILD_10: 'CommonTraitId' = 185890 - UMBRELLA_PREFERENCE_CHILD_11: 'CommonTraitId' = 185891 - UMBRELLA_PREFERENCE_CHILD_12: 'CommonTraitId' = 185892 - UMBRELLA_PREFERENCE_CHILD_2: 'CommonTraitId' = 185882 - UMBRELLA_PREFERENCE_CHILD_3: 'CommonTraitId' = 185883 - UMBRELLA_PREFERENCE_CHILD_4: 'CommonTraitId' = 185884 - UMBRELLA_PREFERENCE_CHILD_5: 'CommonTraitId' = 185885 - UMBRELLA_PREFERENCE_CHILD_6: 'CommonTraitId' = 185886 - UMBRELLA_PREFERENCE_CHILD_7: 'CommonTraitId' = 185887 - UMBRELLA_PREFERENCE_CHILD_8: 'CommonTraitId' = 185888 - UMBRELLA_PREFERENCE_CHILD_9: 'CommonTraitId' = 185889 - UMBRELLA_USER: 'CommonTraitId' = 188000 - UNFLIRTY: 'CommonTraitId' = 132589 - UNIVERSITY_DEGREE_ART_HISTORY_BA: 'CommonTraitId' = 218112 - UNIVERSITY_DEGREE_ART_HISTORY_BA_HONORS: 'CommonTraitId' = 218113 - UNIVERSITY_DEGREE_ART_HISTORY_BS: 'CommonTraitId' = 218114 - UNIVERSITY_DEGREE_ART_HISTORY_BS_HONORS: 'CommonTraitId' = 218115 - UNIVERSITY_DEGREE_BARTENDER: 'CommonTraitId' = 219807 - UNIVERSITY_DEGREE_BIOLOGY_BA: 'CommonTraitId' = 218117 - UNIVERSITY_DEGREE_BIOLOGY_BA_HONORS: 'CommonTraitId' = 218118 - UNIVERSITY_DEGREE_BIOLOGY_BS: 'CommonTraitId' = 218119 - UNIVERSITY_DEGREE_BIOLOGY_BS_HONORS: 'CommonTraitId' = 218120 - UNIVERSITY_DEGREE_COMMUNICATIONS_BA: 'CommonTraitId' = 218122 - UNIVERSITY_DEGREE_COMMUNICATIONS_BA_HONORS: 'CommonTraitId' = 218123 - UNIVERSITY_DEGREE_COMMUNICATIONS_BS: 'CommonTraitId' = 218124 - UNIVERSITY_DEGREE_COMMUNICATIONS_BS_HONORS: 'CommonTraitId' = 218125 - UNIVERSITY_DEGREE_COMPUTER_SCIENCE_BA: 'CommonTraitId' = 218127 - UNIVERSITY_DEGREE_COMPUTER_SCIENCE_BA_HONORS: 'CommonTraitId' = 218128 - UNIVERSITY_DEGREE_COMPUTER_SCIENCE_BS: 'CommonTraitId' = 218129 - UNIVERSITY_DEGREE_COMPUTER_SCIENCE_BS_HONORS: 'CommonTraitId' = 218130 - UNIVERSITY_DEGREE_CULINARY_ARTS_BA: 'CommonTraitId' = 218165 - UNIVERSITY_DEGREE_CULINARY_ARTS_BA_HONORS: 'CommonTraitId' = 218166 - UNIVERSITY_DEGREE_CULINARY_ARTS_BS: 'CommonTraitId' = 218167 - UNIVERSITY_DEGREE_CULINARY_ARTS_BS_HONORS: 'CommonTraitId' = 218168 - UNIVERSITY_DEGREE_DRAMA_BA: 'CommonTraitId' = 218170 - UNIVERSITY_DEGREE_DRAMA_BA_HONORS: 'CommonTraitId' = 218171 - UNIVERSITY_DEGREE_DRAMA_BS: 'CommonTraitId' = 218172 - UNIVERSITY_DEGREE_DRAMA_BS_HONORS: 'CommonTraitId' = 218173 - UNIVERSITY_DEGREE_ECONOMICS_BA: 'CommonTraitId' = 211507 - UNIVERSITY_DEGREE_ECONOMICS_BA_HONORS: 'CommonTraitId' = 218054 - UNIVERSITY_DEGREE_ECONOMICS_BS: 'CommonTraitId' = 218052 - UNIVERSITY_DEGREE_ECONOMICS_BS_HONORS: 'CommonTraitId' = 218053 - UNIVERSITY_DEGREE_FINE_ART_BA: 'CommonTraitId' = 218176 - UNIVERSITY_DEGREE_FINE_ART_BA_HONORS: 'CommonTraitId' = 218177 - UNIVERSITY_DEGREE_FINE_ART_BS: 'CommonTraitId' = 218178 - UNIVERSITY_DEGREE_FINE_ART_BS_HONORS: 'CommonTraitId' = 218179 - UNIVERSITY_DEGREE_HIGHER_EDUCATION: 'CommonTraitId' = 227102 - UNIVERSITY_DEGREE_HISTORY_BA: 'CommonTraitId' = 218182 - UNIVERSITY_DEGREE_HISTORY_BA_HONORS: 'CommonTraitId' = 218183 - UNIVERSITY_DEGREE_HISTORY_BS: 'CommonTraitId' = 218184 - UNIVERSITY_DEGREE_HISTORY_BS_HONORS: 'CommonTraitId' = 218185 - UNIVERSITY_DEGREE_LANGUAGE_AND_LITERATURE_BA: 'CommonTraitId' = 218187 - UNIVERSITY_DEGREE_LANGUAGE_AND_LITERATURE_BA_HONORS: 'CommonTraitId' = 218188 - UNIVERSITY_DEGREE_LANGUAGE_AND_LITERATURE_BS: 'CommonTraitId' = 218189 - UNIVERSITY_DEGREE_LANGUAGE_AND_LITERATURE_BS_HONORS: 'CommonTraitId' = 218190 - UNIVERSITY_DEGREE_PHYSICS_BA: 'CommonTraitId' = 218192 - UNIVERSITY_DEGREE_PHYSICS_BA_HONORS: 'CommonTraitId' = 218193 - UNIVERSITY_DEGREE_PHYSICS_BS: 'CommonTraitId' = 218194 - UNIVERSITY_DEGREE_PHYSICS_BS_HONORS: 'CommonTraitId' = 218195 - UNIVERSITY_DEGREE_PSYCHOLOGY_BA: 'CommonTraitId' = 218198 - UNIVERSITY_DEGREE_PSYCHOLOGY_BA_HONORS: 'CommonTraitId' = 218199 - UNIVERSITY_DEGREE_PSYCHOLOGY_BS: 'CommonTraitId' = 218200 - UNIVERSITY_DEGREE_PSYCHOLOGY_BS_HONORS: 'CommonTraitId' = 218201 - UNIVERSITY_DEGREE_VILLAINY_BA: 'CommonTraitId' = 218203 - UNIVERSITY_DEGREE_VILLAINY_BA_HONORS: 'CommonTraitId' = 218204 - UNIVERSITY_DEGREE_VILLAINY_BS: 'CommonTraitId' = 218205 - UNIVERSITY_DEGREE_VILLAINY_BS_HONORS: 'CommonTraitId' = 218206 - UNIVERSITY_ENROLLMENT_HAS_SEEN_ENROLLMENT_INFO: 'CommonTraitId' = 230113 - UNIVERSITY_HAS_EARNED_DEGREE_ART_HISTORY: 'CommonTraitId' = 230321 - UNIVERSITY_HAS_EARNED_DEGREE_BIOLOGY: 'CommonTraitId' = 230322 - UNIVERSITY_HAS_EARNED_DEGREE_COMMUNICATIONS: 'CommonTraitId' = 230324 - UNIVERSITY_HAS_EARNED_DEGREE_COMPUTER_SCIENCE: 'CommonTraitId' = 230325 - UNIVERSITY_HAS_EARNED_DEGREE_CULINARY_ARTS: 'CommonTraitId' = 230326 - UNIVERSITY_HAS_EARNED_DEGREE_DRAMA: 'CommonTraitId' = 230328 - UNIVERSITY_HAS_EARNED_DEGREE_ECONOMICS: 'CommonTraitId' = 230329 - UNIVERSITY_HAS_EARNED_DEGREE_FINE_ART: 'CommonTraitId' = 230330 - UNIVERSITY_HAS_EARNED_DEGREE_HISTORY: 'CommonTraitId' = 230331 - UNIVERSITY_HAS_EARNED_DEGREE_LANGUAGE_AND_LITERATURE: 'CommonTraitId' = 230332 - UNIVERSITY_HAS_EARNED_DEGREE_PHYSICS: 'CommonTraitId' = 230333 - UNIVERSITY_HAS_EARNED_DEGREE_PSYCHOLOGY: 'CommonTraitId' = 230334 - UNIVERSITY_HAS_EARNED_DEGREE_TYPE_ARTS: 'CommonTraitId' = 230337 - UNIVERSITY_HAS_EARNED_DEGREE_TYPE_HONORS: 'CommonTraitId' = 230336 - UNIVERSITY_HAS_EARNED_DEGREE_VILLAINY: 'CommonTraitId' = 230335 - UNIVERSITY_STUDENT: 'CommonTraitId' = 228185 - UNSTOPPABLE_FAME: 'CommonTraitId' = 192900 - UNTROUBLED: 'CommonTraitId' = 283156 - VALUED_CUSTOMER: 'CommonTraitId' = 27947 - VEGETARIAN: 'CommonTraitId' = 132627 - VILLAGER_HELP_CRITTER_TENDER_GOT_MUSHROOM_MASH_ONCE: 'CommonTraitId' = 267609 - VILLAGER_HELP_ON_QUEST_AGATHA_CRUMPLEBOTTOM: 'CommonTraitId' = 267179 - VILLAGER_HELP_ON_QUEST_AGATHA_CRUMPLEBOTTOM_2: 'CommonTraitId' = 268881 - VILLAGER_HELP_ON_QUEST_AGNES_CRUMPLEBOTTOM: 'CommonTraitId' = 268149 - VILLAGER_HELP_ON_QUEST_AGNES_CRUMPLEBOTTOM_2: 'CommonTraitId' = 268792 - VILLAGER_HELP_ON_QUEST_CRITTER_TENDER: 'CommonTraitId' = 267515 - VILLAGER_HELP_ON_QUEST_FOOD_SHORT: 'CommonTraitId' = 266038 - VILLAGER_HELP_ON_QUEST_GARDEN_SHORT: 'CommonTraitId' = 265857 - VILLAGER_HELP_ON_QUEST_GROCERY_DELIVERY: 'CommonTraitId' = 267385 - VILLAGER_HELP_ON_QUEST_GROCERY_OWNER: 'CommonTraitId' = 267229 - VILLAGER_HELP_ON_QUEST_LIVESTOCK_LONG: 'CommonTraitId' = 265644 - VILLAGER_HELP_ON_QUEST_LIVESTOCK_SHORT: 'CommonTraitId' = 265676 - VILLAGER_HELP_ON_QUEST_MAYOR: 'CommonTraitId' = 267405 - VILLAGER_HELP_ON_QUEST_PUB_OWNER: 'CommonTraitId' = 267454 - VILLAGER_HELP_ON_QUEST_SOCIAL_MEDIUM: 'CommonTraitId' = 268151 - VILLAGER_HELP_ON_QUEST_SOCIAL_SHORT: 'CommonTraitId' = 268150 - VILLAGER_HELP_ON_QUEST_WILD_ANIMAL_FOOD_LONG: 'CommonTraitId' = 266229 - VILLAGER_HELP_ON_QUEST_WILD_ANIMAL_SHORT: 'CommonTraitId' = 265875 - WALK_BY_WITCH_BROOM: 'CommonTraitId' = 218416 - WALK_STYLE_CREEPY: 'CommonTraitId' = 155564 - WALK_STYLE_DEFAULT: 'CommonTraitId' = 9094 - WALK_STYLE_ENERGETIC: 'CommonTraitId' = 98760 - WALK_STYLE_FEMININE: 'CommonTraitId' = 29593 - WALK_STYLE_FOX: 'CommonTraitId' = 261220 - WALK_STYLE_GOOFY: 'CommonTraitId' = 29600 - WALK_STYLE_PERKY: 'CommonTraitId' = 9095 - WALK_STYLE_SLEEPY: 'CommonTraitId' = 98757 - WALK_STYLE_SNOOTY: 'CommonTraitId' = 9096 - WALK_STYLE_SWAGGER: 'CommonTraitId' = 9293 - WALK_STYLE_TOUGH: 'CommonTraitId' = 29594 - WATERPROOF: 'CommonTraitId' = 185794 - WEB_MASTER: 'CommonTraitId' = 27772 - WEDDING_TRADITION_BOUQUET_TOSS: 'CommonTraitId' = 276253 - WEDDING_TRADITION_COUPLE_CAKE_CUT: 'CommonTraitId' = 276251 - WEDDING_TRADITION_FIRST_DANCE: 'CommonTraitId' = 276252 - WEDDING_TRADITION_GROUP_DANCE: 'CommonTraitId' = 280624 - WEDDING_TRADITION_HAD_BOUQUET: 'CommonTraitId' = 276255 - WEDDING_TRADITION_HAD_WEDDING_CAKE: 'CommonTraitId' = 276254 - WEDDING_TRADITION_RING_EXCHANGE: 'CommonTraitId' = 276249 - WEDDING_TRADITION_SPOUSAL_KISS: 'CommonTraitId' = 276248 - WEDDING_TRADITION_WALKED_DOWN_AISLE: 'CommonTraitId' = 276250 - WEDDING_WORLD_NPC_ARNESSA_THEBE: 'CommonTraitId' = 278728 - WEDDING_WORLD_NPC_CAMILLE_SOTO: 'CommonTraitId' = 278733 - WEDDING_WORLD_NPC_DOMINIQUE_SOTO: 'CommonTraitId' = 278734 - WEDDING_WORLD_NPC_FAIZ_JALEEL: 'CommonTraitId' = 278735 - WEDDING_WORLD_NPC_GRETA_LAURENT: 'CommonTraitId' = 278725 - WEDDING_WORLD_NPC_HECTOR_LAURENT: 'CommonTraitId' = 278724 - WEDDING_WORLD_NPC_HILARY_LAURENT: 'CommonTraitId' = 278727 - WEDDING_WORLD_NPC_JACE_LAURENT: 'CommonTraitId' = 278726 - WEDDING_WORLD_NPC_LUCIA_MARKOVIC: 'CommonTraitId' = 278730 - WEDDING_WORLD_NPC_MATEO_MARKOVIC: 'CommonTraitId' = 278729 - WEDDING_WORLD_NPC_TOMI_MARKOVIC: 'CommonTraitId' = 278731 - WELLNESS_CALMING_AURA: 'CommonTraitId' = 270903 - WELLNESS_CLEAR_PERSPECTIVE: 'CommonTraitId' = 270902 - WELLNESS_MOMENT_OF_CLARITY: 'CommonTraitId' = 272283 - WELLNESS_SELF_CARE_EXPERTISE: 'CommonTraitId' = 270904 - WELLNESS_SPA_MEMBERSHIP: 'CommonTraitId' = 270900 - WEREWOLF_BOOK_READ_PETER_BARKER_1: 'CommonTraitId' = 298879 - WEREWOLF_BOOK_READ_PETER_BARKER_2: 'CommonTraitId' = 298880 - WEREWOLF_BOOK_READ_PETER_BARKER_3: 'CommonTraitId' = 298889 - WEREWOLF_BOOK_READ_PETER_BARKER_4: 'CommonTraitId' = 298890 - WEREWOLF_BOOK_READ_SECRET_1: 'CommonTraitId' = 298882 - WEREWOLF_BOOK_READ_SECRET_2: 'CommonTraitId' = 298883 - WEREWOLF_BOOK_READ_SECRET_3: 'CommonTraitId' = 298884 - WEREWOLF_BOOK_READ_SECRET_4: 'CommonTraitId' = 298885 - WEREWOLF_BOOK_READ_VULFGANG_1: 'CommonTraitId' = 298891 - WEREWOLF_BOOK_READ_VULFGANG_2: 'CommonTraitId' = 298892 - WEREWOLF_BOOK_READ_VULFGANG_3: 'CommonTraitId' = 298893 - WEREWOLF_BOOK_READ_VULFGANG_4: 'CommonTraitId' = 298881 - WEREWOLF_INTEREST_DONT_WANT: 'CommonTraitId' = 293565 - WEREWOLF_INTEREST_WANT: 'CommonTraitId' = 293564 - WEREWOLF_PACK_A: 'CommonTraitId' = 284944 - WEREWOLF_PACK_ALLIANCE_FEUD_ALLIANCE: 'CommonTraitId' = 289716 - WEREWOLF_PACK_ALLIANCE_FEUD_FEUD: 'CommonTraitId' = 289723 - WEREWOLF_PACK_ALLIANCE_FEUD_NEUTRAL: 'CommonTraitId' = 289741 - WEREWOLF_PACK_A_LEADER: 'CommonTraitId' = 284985 - WEREWOLF_PACK_A_MEMBER: 'CommonTraitId' = 285566 - WEREWOLF_PACK_B: 'CommonTraitId' = 284945 - WEREWOLF_PACK_B_LEADER: 'CommonTraitId' = 284986 - WEREWOLF_PACK_B_MEMBER: 'CommonTraitId' = 285567 - WEREWOLF_PACK_DISCIPLINE_PROBATION: 'CommonTraitId' = 286781 - WEREWOLF_PACK_DISCIPLINE_REPORT_TO_LEADER: 'CommonTraitId' = 286782 - WEREWOLF_PACK_DISCIPLINE_WARNING: 'CommonTraitId' = 297602 - WEREWOLF_PACK_FRIEND_A: 'CommonTraitId' = 286986 - WEREWOLF_PACK_FRIEND_A_REPORT_TO_LEADER: 'CommonTraitId' = 287050 - WEREWOLF_PACK_FRIEND_B: 'CommonTraitId' = 286987 - WEREWOLF_PACK_FRIEND_B_REPORT_TO_LEADER: 'CommonTraitId' = 287051 - WEREWOLF_PACK_LEADER_HAS_NOT_REDECORATED: 'CommonTraitId' = 293513 - WEREWOLF_PACK_REPORT_TO_LEADER_OTHER: 'CommonTraitId' = 290934 - WISE: 'CommonTraitId' = 341151 - WITH_NANNY: 'CommonTraitId' = 105483 - WOLF_TOWN_ADVENTURE_KNOWS_SCULPTURE_SECRET: 'CommonTraitId' = 288791 - WOLF_TOWN_NPC_CELENE_LOPEZ: 'CommonTraitId' = 288301 - WOLF_TOWN_NPC_GREG: 'CommonTraitId' = 288294 - WOLF_TOWN_NPC_JACOB_VOLKOV: 'CommonTraitId' = 288299 - WOLF_TOWN_NPC_KRISTOPHER_VOLKOV: 'CommonTraitId' = 288297 - WOLF_TOWN_NPC_LILY_ZHU: 'CommonTraitId' = 288303 - WOLF_TOWN_NPC_LOU_HOWELL: 'CommonTraitId' = 288302 - WOLF_TOWN_NPC_RORY_OAKLOW: 'CommonTraitId' = 288298 - WOLF_TOWN_NPC_WOLFGANG_WILDER: 'CommonTraitId' = 288300 - WOLF_TOWN_PORTAL_UNLOCK_PORTAL_MINE: 'CommonTraitId' = 288386 - WOLF_TOWN_PORTAL_UNLOCK_PORTAL_SEWER: 'CommonTraitId' = 288387 - WOLF_TOWN_PORTAL_UNLOCK_PORTAL_SEWER_MINE: 'CommonTraitId' = 288388 - WORLDLY_KNOWLEDGE: 'CommonTraitId' = 249732 - WORLD_RENOWNED_ACTOR: 'CommonTraitId' = 193531 - YOUNG_ADULT: 'CommonTraitId' = 34318 diff --git a/Scripts/s4ap/sims4communitylib/enums/types/__init__.py b/Scripts/s4ap/sims4communitylib/enums/types/__init__.py deleted file mode 100644 index 3251898..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/types/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" \ No newline at end of file diff --git a/Scripts/s4ap/sims4communitylib/enums/types/component_types.py b/Scripts/s4ap/sims4communitylib/enums/types/component_types.py deleted file mode 100644 index 8fb1c8e..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/types/component_types.py +++ /dev/null @@ -1,94 +0,0 @@ -""" -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 -""" -from typing import Any - - -class CommonComponentType: - """Various component types of vanilla Sims 4 - - Components are essentially just Tuning files in package files. - - """ - def _get_component_type(*args) -> Any: - try: - import objects.components.types as component_types - return getattr(component_types, args[0]) - except KeyError: - return args[0] - - ANIMATION: 'CommonComponentType' = _get_component_type('ANIMATION_COMPONENT') - AUDIO: 'CommonComponentType' = _get_component_type('AUDIO_COMPONENT') - EFFECTS: 'CommonComponentType' = _get_component_type('EFFECTS_COMPONENT') - FOOTPRINT: 'CommonComponentType' = _get_component_type('FOOTPRINT_COMPONENT') - GAMEPLAY: 'CommonComponentType' = _get_component_type('GAMEPLAY_COMPONENT') - LIVE_DRAG: 'CommonComponentType' = _get_component_type('LIVE_DRAG_COMPONENT') - POSITION: 'CommonComponentType' = _get_component_type('POSITION_COMPONENT') - RENDER: 'CommonComponentType' = _get_component_type('RENDER_COMPONENT') - ROUTING: 'CommonComponentType' = _get_component_type('ROUTING_COMPONENT') - SIM: 'CommonComponentType' = _get_component_type('SIM_COMPONENT') - VIDEO: 'CommonComponentType' = _get_component_type('VIDEO_COMPONENT') - AFFORDANCE_TUNING: 'CommonComponentType' = _get_component_type('AFFORDANCE_TUNING_COMPONENT') - ANIMATION_OVERLAY: 'CommonComponentType' = _get_component_type('ANIMATION_OVERLAY_COMPONENT') - AUTONOMY: 'CommonComponentType' = _get_component_type('AUTONOMY_COMPONENT') - AWARENESS: 'CommonComponentType' = _get_component_type('AWARENESS_COMPONENT') - BUFF: 'CommonComponentType' = _get_component_type('BUFF_COMPONENT') - CAMERA_VIEW: 'CommonComponentType' = _get_component_type('CAMERA_VIEW_COMPONENT') - CANVAS: 'CommonComponentType' = _get_component_type('CANVAS_COMPONENT') - CARRYABLE: 'CommonComponentType' = _get_component_type('CARRYABLE_COMPONENT') - CARRYING: 'CommonComponentType' = _get_component_type('CARRYING_COMPONENT') - CHANNEL: 'CommonComponentType' = _get_component_type('CHANNEL_COMPONENT') - CENSOR_GRID: 'CommonComponentType' = _get_component_type('CENSOR_GRID_COMPONENT') - COLLECTABLE: 'CommonComponentType' = _get_component_type('COLLECTABLE_COMPONENT') - CONSUMABLE: 'CommonComponentType' = _get_component_type('CONSUMABLE_COMPONENT') - CRAFTING: 'CommonComponentType' = _get_component_type('CRAFTING_COMPONENT') - CRAFTING_STATION: 'CommonComponentType' = _get_component_type('CRAFTING_STATION_COMPONENT') - CURFEW: 'CommonComponentType' = _get_component_type('CURFEW_COMPONENT') - ENSEMBLE: 'CommonComponentType' = _get_component_type('ENSEMBLE_COMPONENT') - ENVIRONMENT_SCORE: 'CommonComponentType' = _get_component_type('ENVIRONMENT_SCORE_COMPONENT') - FLOWING_PUDDLE: 'CommonComponentType' = _get_component_type('FLOWING_PUDDLE_COMPONENT') - FOCUS: 'CommonComponentType' = _get_component_type('FOCUS_COMPONENT') - GAME: 'CommonComponentType' = _get_component_type('GAME_COMPONENT') - GARDENING: 'CommonComponentType' = _get_component_type('GARDENING_COMPONENT') - IDLE: 'CommonComponentType' = _get_component_type('IDLE_COMPONENT') - INVENTORY: 'CommonComponentType' = _get_component_type('INVENTORY_COMPONENT') - INVENTORY_ITEM: 'CommonComponentType' = _get_component_type('INVENTORY_ITEM_COMPONENT') - LIGHTING: 'CommonComponentType' = _get_component_type('LIGHTING_COMPONENT') - LINE_OF_SIGHT: 'CommonComponentType' = _get_component_type('LINE_OF_SIGHT_COMPONENT') - LINKED_OBJECT: 'CommonComponentType' = _get_component_type('LINKED_OBJECT_COMPONENT') - LIVE_DRAG_TARGET: 'CommonComponentType' = _get_component_type('LIVE_DRAG_TARGET_COMPONENT') - MANNEQUIN: 'CommonComponentType' = _get_component_type('MANNEQUIN_COMPONENT') - NAME: 'CommonComponentType' = _get_component_type('NAME_COMPONENT') - NEW_OBJECT: 'CommonComponentType' = _get_component_type('NEW_OBJECT_COMPONENT') - OBJECT_AGE: 'CommonComponentType' = _get_component_type('OBJECT_AGE_COMPONENT') - OBJECT_RELATIONSHIP: 'CommonComponentType' = _get_component_type('OBJECT_RELATIONSHIP_COMPONENT') - OBJECT_ROUTING: 'CommonComponentType' = _get_component_type('OBJECT_ROUTING_COMPONENT') - OBJECT_TELEPORTATION: 'CommonComponentType' = _get_component_type('OBJECT_TELEPORTATION_COMPONENT') - OWNABLE: 'CommonComponentType' = _get_component_type('OWNABLE_COMPONENT') - PARENT_TO_SIM_HEAD: 'CommonComponentType' = _get_component_type('PARENT_TO_SIM_HEAD_COMPONENT') - PORTAL: 'CommonComponentType' = _get_component_type('PORTAL_COMPONENT') - PORTAL_ANIMATION: 'CommonComponentType' = _get_component_type('PORTAL_ANIMATION_COMPONENT') - PORTAL_LOCKING: 'CommonComponentType' = _get_component_type('PORTAL_LOCKING_COMPONENT') - PROXIMITY: 'CommonComponentType' = _get_component_type('PROXIMITY_COMPONENT') - SEASON_AWARE: 'CommonComponentType' = _get_component_type('SEASON_AWARE_COMPONENT') - SLOT: 'CommonComponentType' = _get_component_type('SLOT_COMPONENT') - SPAWN_POINT: 'CommonComponentType' = _get_component_type('SPAWN_POINT_COMPONENT') - SPAWNER: 'CommonComponentType' = _get_component_type('SPAWNER_COMPONENT') - STATE: 'CommonComponentType' = _get_component_type('STATE_COMPONENT') - STATISTIC: 'CommonComponentType' = _get_component_type('STATISTIC_COMPONENT') - STORED_OBJECT_INFO: 'CommonComponentType' = _get_component_type('STORED_OBJECT_INFO_COMPONENT') - STORED_SIM_INFO: 'CommonComponentType' = _get_component_type('STORED_SIM_INFO_COMPONENT') - TIME_OF_DAY: 'CommonComponentType' = _get_component_type('TIME_OF_DAY_COMPONENT') - TOOLTIP: 'CommonComponentType' = _get_component_type('TOOLTIP_COMPONENT') - TOPIC: 'CommonComponentType' = _get_component_type('TOPIC_COMPONENT') - FISHING_LOCATION: 'CommonComponentType' = _get_component_type('FISHING_LOCATION_COMPONENT') - WAITING_LINE: 'CommonComponentType' = _get_component_type('WAITING_LINE_COMPONENT') - DISPLAY: 'CommonComponentType' = _get_component_type('DISPLAY_COMPONENT') - RETAIL: 'CommonComponentType' = _get_component_type('RETAIL_COMPONENT') - STOLEN: 'CommonComponentType' = _get_component_type('STOLEN_COMPONENT') - EXAMPLE: 'CommonComponentType' = _get_component_type('EXAMPLE_COMPONENT') - WEATHER_AWARE: 'CommonComponentType' = _get_component_type('WEATHER_AWARE_COMPONENT') diff --git a/Scripts/s4ap/sims4communitylib/enums/venues_enum.py b/Scripts/s4ap/sims4communitylib/enums/venues_enum.py deleted file mode 100644 index 4fadb89..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/venues_enum.py +++ /dev/null @@ -1,56 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonVenueType(CommonInt): - """Identifiers for vanilla venue types. - - """ - INVALID: 'CommonVenueType' = 0 - ACTING_STUDIO: 'CommonVenueType' = 190058 - ARTS_CENTER: 'CommonVenueType' = 144206 - BAR: 'CommonVenueType' = 16869 - CAFE: 'CommonVenueType' = 122247 - CHALET_GARDENS: 'CommonVenueType' = 125223 - CLUB: 'CommonVenueType' = 16870 - DOCTOR_CLINIC: 'CommonVenueType' = 110576 - FOREST_PARK: 'CommonVenueType' = 107453 - GENERIC: 'CommonVenueType' = 9279 - GYM: 'CommonVenueType' = 16873 - HERMIT: 'CommonVenueType' = 105591 - HIDDEN_ALIEN_WORLD: 'CommonVenueType' = 111611 - HIDDEN_CAVE: 'CommonVenueType' = 98133 - HIDDEN_GLADE: 'CommonVenueType' = 98132 - KARAOKE: 'CommonVenueType' = 137844 - LIBRARY: 'CommonVenueType' = 16874 - LOUNGE: 'CommonVenueType' = 16875 - MUSEUM: 'CommonVenueType' = 16876 - MYSHUNO_MEADOWS: 'CommonVenueType' = 138380 - NATURAL_POOL: 'CommonVenueType' = 175123 - OCEAN_BLUFF: 'CommonVenueType' = 125071 - PARK: 'CommonVenueType' = 25847 - PENTHOUSE: 'CommonVenueType' = 149495 - PENTHOUSE_EP08: 'CommonVenueType' = 227304 - POLICE_STATION: 'CommonVenueType' = 109774 - POOL: 'CommonVenueType' = 123794 - RELAXATION_CENTER: 'CommonVenueType' = 118135 - RENTABLE_CABIN: 'CommonVenueType' = 103675 - RENTABLE_JUNGLE: 'CommonVenueType' = 173833 - RENTABLE_UNIVERSITY_HOUSING: 'CommonVenueType' = 208182 - RESIDENTIAL: 'CommonVenueType' = 28614 - RESIDENTIAL_TINY_HOME: 'CommonVenueType' = 229251 - RESTAURANT: 'CommonVenueType' = 130713 - RETAIL: 'CommonVenueType' = 105157 - RUINS: 'CommonVenueType' = 123132 - SCIENTIST_LAB: 'CommonVenueType' = 107487 - TEMPLE: 'CommonVenueType' = 173492 - UNIVERSITY_STUDENT_COMMONS_ARTS: 'CommonVenueType' = 218857 - UNIVERSITY_STUDENT_COMMONS_SCIENCE: 'CommonVenueType' = 218858 - VET: 'CommonVenueType' = 158847 - VISITORS_ALLOWED: 'CommonVenueType' = 98817 diff --git a/Scripts/s4ap/sims4communitylib/enums/whims_enum.py b/Scripts/s4ap/sims4communitylib/enums/whims_enum.py deleted file mode 100644 index 518ee8d..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/whims_enum.py +++ /dev/null @@ -1,242 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonWhimSetId(CommonInt): - """Identifiers for vanilla whim sets. - - """ - INVALID: 'CommonWhimSetId' = 0 - APARTMENT_PROBLEMS: 'CommonWhimSetId' = 142026 - APARTMENTS_INDOORS_GO_OUTSIDE: 'CommonWhimSetId' = 142732 - APARTMENTS_LOT_TRAITS: 'CommonWhimSetId' = 142085 - APARTMENTS_NEIGHBOR_SITUATION_COMPLAIN_ABOUT_NOISE: 'CommonWhimSetId' = 140901 - APARTMENTS_NEIGHBOR_SITUATION_GIVE_KEY: 'CommonWhimSetId' = 140954 - ASP_ANIMAL_FRIEND_OF_THE_ANIMALS: 'CommonWhimSetId' = 172197 - ASP_ATHLETIC_BODYBUILDER: 'CommonWhimSetId' = 97876 - ASP_CREATIVITY_MUSICAL: 'CommonWhimSetId' = 97877 - ASP_CREATIVITY_PAINTER: 'CommonWhimSetId' = 97878 - ASP_CREATIVITY_WRITER: 'CommonWhimSetId' = 97879 - ASP_DEVIANCE_ENEMY: 'CommonWhimSetId' = 97880 - ASP_DEVIANCE_MISCHIEF: 'CommonWhimSetId' = 97881 - ASP_FAMILY_HAPPY_FAMILY: 'CommonWhimSetId' = 97882 - ASP_FAMILY_SUCCESSFUL: 'CommonWhimSetId' = 97885 - ASP_FOOD_BARTENDER: 'CommonWhimSetId' = 97883 - ASP_FOOD_CHEF: 'CommonWhimSetId' = 97884 - ASP_FORTUNE_MANSION: 'CommonWhimSetId' = 97886 - ASP_FORTUNE_WEALTHY: 'CommonWhimSetId' = 97887 - ASP_KNOWLEDGE_COMPUTER: 'CommonWhimSetId' = 97898 - ASP_KNOWLEDGE_NERD: 'CommonWhimSetId' = 97897 - ASP_KNOWLEDGE_RENAISSANCE: 'CommonWhimSetId' = 97896 - ASP_LOCATION_CITY_LIFE: 'CommonWhimSetId' = 144970 - ASP_LOVE_HOPEFUL_ROMANTIC: 'CommonWhimSetId' = 97895 - ASP_LOVE_SOUL_MATE: 'CommonWhimSetId' = 97894 - ASP_NATURE_ANGLING: 'CommonWhimSetId' = 97893 - ASP_NATURE_BOTANIST: 'CommonWhimSetId' = 97892 - ASP_NATURE_CURATOR: 'CommonWhimSetId' = 97890 - ASP_NATURE_OUTDOORS: 'CommonWhimSetId' = 108794 - ASP_POPULARITY_FRIEND: 'CommonWhimSetId' = 97889 - ASP_POPULARITY_JOKE_STAR: 'CommonWhimSetId' = 97891 - ASP_POPULARITY_LEADER_OF_THE_PACK: 'CommonWhimSetId' = 122936 - ASP_POPULARITY_PARTY: 'CommonWhimSetId' = 97888 - BAKING: 'CommonWhimSetId' = 115144 - BAR: 'CommonWhimSetId' = 129728 - BARTENDING: 'CommonWhimSetId' = 31709 - BEING_IN_CLUB: 'CommonWhimSetId' = 125284 - BLUFFS: 'CommonWhimSetId' = 129737 - BONFIRE: 'CommonWhimSetId' = 125676 - BUBBLE_BLOWER: 'CommonWhimSetId' = 143236 - BUSH: 'CommonWhimSetId' = 131179 - BUY_CITY_REGION: 'CommonWhimSetId' = 144959 - BUY_ADVANCED: 'CommonWhimSetId' = 105598 - BUY_BASICS: 'CommonWhimSetId' = 36954 - CAFE: 'CommonWhimSetId' = 124371 - CAMPFIRE: 'CommonWhimSetId' = 104505 - CAREER_ACTIVIST_CHARITY: 'CommonWhimSetId' = 136429 - CAREER_ACTIVIST_MAIN: 'CommonWhimSetId' = 136434 - CAREER_ACTIVIST_POLITICS: 'CommonWhimSetId' = 136428 - CAREER_ASTRONAUT: 'CommonWhimSetId' = 35096 - CAREER_ATHLETIC: 'CommonWhimSetId' = 110186 - CAREER_BUSINESS: 'CommonWhimSetId' = 110187 - CAREER_CRIMINAL: 'CommonWhimSetId' = 35100 - CAREER_CRITIC_ARTS: 'CommonWhimSetId' = 136200 - CAREER_CRITIC_BASIC: 'CommonWhimSetId' = 136198 - CAREER_CRITIC_FOOD: 'CommonWhimSetId' = 136199 - CAREER_CULINARY: 'CommonWhimSetId' = 35101 - CAREER_DETECTIVE: 'CommonWhimSetId' = 114617 - CAREER_DOCTOR: 'CommonWhimSetId' = 114611 - CAREER_ENTERTAINER: 'CommonWhimSetId' = 35102 - CAREER_PAINTER: 'CommonWhimSetId' = 106085 - CAREER_SCIENTIST: 'CommonWhimSetId' = 107573 - CAREER_SECRET_AGENT: 'CommonWhimSetId' = 35103 - CAREER_SOCIAL_MEDIA_INTERNET_PERSONALITY: 'CommonWhimSetId' = 135648 - CAREER_SOCIAL_MEDIA_MAIN: 'CommonWhimSetId' = 135647 - CAREER_SOCIAL_MEDIA_PUBLIC_RELATIONS: 'CommonWhimSetId' = 135649 - CAREER_TECH_GURU: 'CommonWhimSetId' = 35104 - CAREER_WRITER: 'CommonWhimSetId' = 35099 - CHALET: 'CommonWhimSetId' = 129738 - CHARISMA: 'CommonWhimSetId' = 32927 - CHILD_CREATIVE: 'CommonWhimSetId' = 34693 - CHILD_MENTAL: 'CommonWhimSetId' = 34689 - CHILD_MONSTER_UNDER_THE_BED: 'CommonWhimSetId' = 136480 - CHILD_MOTOR: 'CommonWhimSetId' = 34670 - CHILD_SOCIAL: 'CommonWhimSetId' = 34685 - CHILD_TEEN_HOMEWORK: 'CommonWhimSetId' = 75518 - CLOSET: 'CommonWhimSetId' = 125548 - CLUB: 'CommonWhimSetId' = 129729 - COLLECTION_SET: 'CommonWhimSetId' = 38419 - COMEDY: 'CommonWhimSetId' = 35061 - COOKING: 'CommonWhimSetId' = 31708 - DANCE_FLOOR_ON_LOT: 'CommonWhimSetId' = 129758 - DANCE_FLOOR_OWNED: 'CommonWhimSetId' = 129762 - DANCING_SKILL: 'CommonWhimSetId' = 128197 - DARES: 'CommonWhimSetId' = 121308 - DARTBOARD: 'CommonWhimSetId' = 129777 - DJ_BOOTH_ON_LOT: 'CommonWhimSetId' = 124412 - DJ_BOOTH_OWNED: 'CommonWhimSetId' = 124410 - EMOTION_ANGRY: 'CommonWhimSetId' = 25426 - EMOTION_BORED: 'CommonWhimSetId' = 25422 - EMOTION_CONFIDENT: 'CommonWhimSetId' = 25424 - EMOTION_DAZED: 'CommonWhimSetId' = 25423 - EMOTION_EMBARRASSED: 'CommonWhimSetId' = 25427 - EMOTION_ENERGIZED: 'CommonWhimSetId' = 25384 - EMOTION_FLIRTY: 'CommonWhimSetId' = 25386 - EMOTION_FOCUSED: 'CommonWhimSetId' = 38413 - EMOTION_HAPPY: 'CommonWhimSetId' = 25383 - EMOTION_INSPIRED: 'CommonWhimSetId' = 25378 - EMOTION_PLAYFUL: 'CommonWhimSetId' = 25421 - EMOTION_SAD: 'CommonWhimSetId' = 25425 - EMOTION_STRESSED: 'CommonWhimSetId' = 25428 - ENEMIES: 'CommonWhimSetId' = 28028 - ENEMY_PROGRESS: 'CommonWhimSetId' = 32646 - FESTIVALS_BLOSSOM: 'CommonWhimSetId' = 142968 - FESTIVALS_FLEA_MARKET: 'CommonWhimSetId' = 142969 - FESTIVALS_FOOD: 'CommonWhimSetId' = 142970 - FESTIVALS_LAMP: 'CommonWhimSetId' = 142971 - FESTIVALS_LOGIC: 'CommonWhimSetId' = 142967 - FISHING: 'CommonWhimSetId' = 77374 - FITNESS: 'CommonWhimSetId' = 33091 - FOOSBALL_TABLE: 'CommonWhimSetId' = 125726 - FRIEND_PROGRESS: 'CommonWhimSetId' = 28013 - FRIENDSHIP: 'CommonWhimSetId' = 28026 - GARDENING: 'CommonWhimSetId' = 33150 - GHOST: 'CommonWhimSetId' = 102667 - GUITAR: 'CommonWhimSetId' = 34339 - HANDINESS: 'CommonWhimSetId' = 35063 - HAS_TRAIT_ACTIVE: 'CommonWhimSetId' = 34777 - HAS_TRAIT_AMBITIOUS: 'CommonWhimSetId' = 34778 - HAS_TRAIT_ART_LOVER: 'CommonWhimSetId' = 34779 - HAS_TRAIT_BOOKWORM: 'CommonWhimSetId' = 34780 - HAS_TRAIT_BRO: 'CommonWhimSetId' = 34781 - HAS_TRAIT_CAT_LOVER: 'CommonWhimSetId' = 157994 - HAS_TRAIT_CHEERFUL: 'CommonWhimSetId' = 34782 - HAS_TRAIT_CHILDISH: 'CommonWhimSetId' = 34783 - HAS_TRAIT_CLUMSY: 'CommonWhimSetId' = 34784 - HAS_TRAIT_COMMITMENTPHOBE: 'CommonWhimSetId' = 34785 - HAS_TRAIT_COMPASSIONATE: 'CommonWhimSetId' = 160864 - HAS_TRAIT_CREATIVE: 'CommonWhimSetId' = 34786 - HAS_TRAIT_DANCE_MACHINE: 'CommonWhimSetId' = 126091 - HAS_TRAIT_DOG_LOVER: 'CommonWhimSetId' = 157995 - HAS_TRAIT_EVIL: 'CommonWhimSetId' = 34787 - HAS_TRAIT_FAMILY_ORIENTED: 'CommonWhimSetId' = 34788 - HAS_TRAIT_FOODIE: 'CommonWhimSetId' = 28155 - HAS_TRAIT_GEEK: 'CommonWhimSetId' = 34790 - HAS_TRAIT_GENIUS: 'CommonWhimSetId' = 34791 - HAS_TRAIT_GLOOMY: 'CommonWhimSetId' = 34792 - HAS_TRAIT_GLUTTON: 'CommonWhimSetId' = 34793 - HAS_TRAIT_GOOD: 'CommonWhimSetId' = 34794 - HAS_TRAIT_GOOD_CHILD: 'CommonWhimSetId' = 155380 - HAS_TRAIT_GOOFBALL: 'CommonWhimSetId' = 34795 - HAS_TRAIT_GOOFBALL_CHILD: 'CommonWhimSetId' = 155382 - HAS_TRAIT_HATES_CHILDREN: 'CommonWhimSetId' = 34796 - HAS_TRAIT_HOTHEADED: 'CommonWhimSetId' = 34797 - HAS_TRAIT_INSANE: 'CommonWhimSetId' = 34798 - HAS_TRAIT_INSIDER: 'CommonWhimSetId' = 125440 - HAS_TRAIT_IRRESPONSIBLE: 'CommonWhimSetId' = 163674 - HAS_TRAIT_JEALOUSY: 'CommonWhimSetId' = 127089 - HAS_TRAIT_KLEPTOMANIAC: 'CommonWhimSetId' = 131919 - HAS_TRAIT_LAZY: 'CommonWhimSetId' = 34799 - HAS_TRAIT_LIFE_SKILLS_ARGUMENTATIVE: 'CommonWhimSetId' = 163188 - HAS_TRAIT_LIFE_SKILLS_BAD_MANNERS: 'CommonWhimSetId' = 160852 - HAS_TRAIT_LIFE_SKILLS_GOOD_MANNERS: 'CommonWhimSetId' = 160845 - HAS_TRAIT_LIFE_SKILLS_MEDIATOR: 'CommonWhimSetId' = 163189 - HAS_TRAIT_LIKES_FRUITCAKE: 'CommonWhimSetId' = 120193 - HAS_TRAIT_LONER: 'CommonWhimSetId' = 34800 - HAS_TRAIT_LOVES_OUTDOORS: 'CommonWhimSetId' = 34801 - HAS_TRAIT_MATERIALISTIC: 'CommonWhimSetId' = 34802 - HAS_TRAIT_MEAN: 'CommonWhimSetId' = 34803 - HAS_TRAIT_MELT_MASTER: 'CommonWhimSetId' = 132360 - HAS_TRAIT_MUSIC_LOVER: 'CommonWhimSetId' = 34804 - HAS_TRAIT_NEAT: 'CommonWhimSetId' = 26090 - HAS_TRAIT_OUTGOING: 'CommonWhimSetId' = 34806 - HAS_TRAIT_PERFECTIONIST: 'CommonWhimSetId' = 34807 - HAS_TRAIT_RESPONSIBLE: 'CommonWhimSetId' = 163573 - HAS_TRAIT_ROMANTIC: 'CommonWhimSetId' = 28154 - HAS_TRAIT_SELF_ASSURED: 'CommonWhimSetId' = 34808 - HAS_TRAIT_SLOB: 'CommonWhimSetId' = 34809 - HAS_TRAIT_SNOB: 'CommonWhimSetId' = 34810 - HAS_TRAIT_SQUEAMISH: 'CommonWhimSetId' = 102729 - HAS_TRAIT_UNCONTROLLED_EMOTION_: 'CommonWhimSetId' = 166098 - HAS_TRAIT_UNFEELING: 'CommonWhimSetId' = 160957 - HAS_TRAIT_UNFLIRTY: 'CommonWhimSetId' = 132586 - HAS_TRAIT_VAMPIRE: 'CommonWhimSetId' = 153501 - HAS_TRAIT_VEGETARIAN: 'CommonWhimSetId' = 132630 - HERBALISM: 'CommonWhimSetId' = 105193 - HORSESHOES: 'CommonWhimSetId' = 106043 - INCENSE: 'CommonWhimSetId' = 119380 - KARAOKE_MACHINE: 'CommonWhimSetId' = 148669 - LOGIC: 'CommonWhimSetId' = 34444 - MISCHIEF: 'CommonWhimSetId' = 34448 - NEW_ROMANCE: 'CommonWhimSetId' = 28027 - NEW_ROMANCE_PLUS: 'CommonWhimSetId' = 32523 - NOT_VAMPIRE: 'CommonWhimSetId' = 154203 - PAINTING: 'CommonWhimSetId' = 35064 - PARENTING: 'CommonWhimSetId' = 164174 - PARENT_TO_BABY: 'CommonWhimSetId' = 97290 - PARENT_TO_CHILD: 'CommonWhimSetId' = 32933 - PARENT_TO_TODDLER: 'CommonWhimSetId' = 155375 - PARTNERS: 'CommonWhimSetId' = 28017 - PET_CAT_OWNER: 'CommonWhimSetId' = 159319 - PET_DOG_OWNER: 'CommonWhimSetId' = 159318 - PET_OWNER: 'CommonWhimSetId' = 169589 - PHOTOGRAPHY: 'CommonWhimSetId' = 112131 - PIANO: 'CommonWhimSetId' = 34340 - PIPE_ORGAN: 'CommonWhimSetId' = 151435 - POOL: 'CommonWhimSetId' = 129736 - POOLS: 'CommonWhimSetId' = 103901 - PROGRAMMING: 'CommonWhimSetId' = 35070 - RELAXATION_CENTER: 'CommonWhimSetId' = 121106 - RESTAURANT: 'CommonWhimSetId' = 131257 - ROCKET_SCIENCE: 'CommonWhimSetId' = 35072 - RUINS: 'CommonWhimSetId' = 129739 - SICKNESS_SYMPTOMS_CURE: 'CommonWhimSetId' = 111514 - SINGING: 'CommonWhimSetId' = 140016 - SOCIAL_MEET_NEW: 'CommonWhimSetId' = 25464 - STEREO_RADIO_CHANNELS: 'CommonWhimSetId' = 146257 - TEENS: 'CommonWhimSetId' = 117896 - TELEVISION_CHANNELS: 'CommonWhimSetId' = 146256 - TENT: 'CommonWhimSetId' = 105274 - TODDLER_CHAOS_SET: 'CommonWhimSetId' = 154890 - TODDLER_GROWTH_SET: 'CommonWhimSetId' = 154892 - TODDLER_NURTURING_SET: 'CommonWhimSetId' = 154914 - TODDLER_TRAIT_ANGELIC_SET: 'CommonWhimSetId' = 154893 - TODDLER_TRAIT_CHARMER_SET: 'CommonWhimSetId' = 154900 - TODDLER_TRAIT_CLINGY_SET: 'CommonWhimSetId' = 154894 - TODDLER_TRAIT_FUSSY_SET: 'CommonWhimSetId' = 154899 - TODDLER_TRAIT_INDEPENDENT_SET: 'CommonWhimSetId' = 154898 - TODDLER_TRAIT_INQUISITIVE_SET: 'CommonWhimSetId' = 154896 - TODDLER_TRAIT_SILLY_SET: 'CommonWhimSetId' = 154897 - TODDLER_TRAIT_WILD_SET: 'CommonWhimSetId' = 154895 - TREADMILL_ROCK_CLIMBING_WALL_OWNED: 'CommonWhimSetId' = 167506 - VET: 'CommonWhimSetId' = 170146 - VET_VENDING_MACHINE: 'CommonWhimSetId' = 176348 - VIDEO_GAMING: 'CommonWhimSetId' = 34449 - VIOLIN: 'CommonWhimSetId' = 34341 - WELLNESS: 'CommonWhimSetId' = 118587 - WRITING: 'CommonWhimSetId' = 35073 diff --git a/Scripts/s4ap/sims4communitylib/enums/world_types_enum.py b/Scripts/s4ap/sims4communitylib/enums/world_types_enum.py deleted file mode 100644 index 8a21283..0000000 --- a/Scripts/s4ap/sims4communitylib/enums/world_types_enum.py +++ /dev/null @@ -1,84 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonWorldTypeId(CommonInt): - """Identifiers for various vanilla world types. - - """ - INVALID: 'CommonWorldTypeId' = 0 - ACQUISITION_BUTTE: 'CommonWorldTypeId' = 23279 - ARTS_QUARTER: 'CommonWorldTypeId' = 121286 - SPICE_MARKET: 'CommonWorldTypeId' = 117423 - BEDROCK_STRAIT: 'CommonWorldTypeId' = 23278 - BELOMISIA_JUNGLE: 'CommonWorldTypeId' = 179659 - BG_DEBUG_MEGALOTS_TEST_WORLD: 'CommonWorldTypeId' = 117183 - BRIDGEVIEW: 'CommonWorldTypeId' = 93560 - BUSINESS_DISTRICT: 'CommonWorldTypeId' = 100125 - CAVALIER_COVE: 'CommonWorldTypeId' = 164436 - CHIRON_ONE_LOT_CLIFF_TEST_WORLD: 'CommonWorldTypeId' = 21147 - CHIRON_ONE_LOT_HILL: 'CommonWorldTypeId' = 21148 - CHIRON_ONE_LOT_TEST_WORLD: 'CommonWorldTypeId' = 21145 - COURTYARD_LANE: 'CommonWorldTypeId' = 20382 - DEADGRASS_ISLE: 'CommonWorldTypeId' = 164437 - DESERT_BLOOM: 'CommonWorldTypeId' = 42521 - DISCOVER_JUNGLE_SECRETS: 'CommonWorldTypeId' = 188795 - EP01_ALIEN_WORLD_01: 'CommonWorldTypeId' = 72720 - EP01_CIVIC_CENTER_01: 'CommonWorldTypeId' = 72467 - EP01_CIVIC_CENTER_02: 'CommonWorldTypeId' = 88225 - EP01_SCIENCE_LAB_01: 'CommonWorldTypeId' = 72721 - EP02_CHALET_GARDEN_01: 'CommonWorldTypeId' = 107138 - EP02_ISLAND_BLUFF_01: 'CommonWorldTypeId' = 106836 - EP02_OLD_TOWN_01: 'CommonWorldTypeId' = 100127 - EP02_OLD_TOWN_RUINS_01: 'CommonWorldTypeId' = 103613 - EP07_RESORT_ISLAND: 'CommonWorldTypeId' = 207075 - EP07_LOCAL_ISLAND_01: 'CommonWorldTypeId' = 208803 - EP07_NATURAL_ISLAND_01: 'CommonWorldTypeId' = 212324 - FASHION_DISTRICT: 'CommonWorldTypeId' = 120336 - FORGOTTEN_GROTTO: 'CommonWorldTypeId' = 47905 - FOUNDRY_COVE: 'CommonWorldTypeId' = 20384 - GALLERY_LOT_BUILD_WORLD: 'CommonWorldTypeId' = 62773 - GD_WARD_VENUE_01: 'CommonWorldTypeId' = 36244 - GP01_CAMPGROUND_01: 'CommonWorldTypeId' = 65991 - GP01_FOREST_01: 'CommonWorldTypeId' = 65996 - GP01_HERMIT_DWELLING_01: 'CommonWorldTypeId' = 65997 - GP04_VAMPIRE_WORLD_01: 'CommonWorldTypeId' = 146194 - GP07_CRATER_BASE_01: 'CommonWorldTypeId' = 208774 - GP07_DOWNTOWN_01: 'CommonWorldTypeId' = 208775 - GP07_OUTSKIRTS_01: 'CommonWorldTypeId' = 208823 - GP08_MAGIC_REALM_01: 'CommonWorldTypeId' = 222658 - GP08_VILLAGE_01: 'CommonWorldTypeId' = 222659 - ISLAND: 'CommonWorldTypeId' = 100126 - LLAMA_LAGOON: 'CommonWorldTypeId' = 93559 - LOT_1: 'CommonWorldTypeId' = 31580 - MAGALOG_9_LOT_WORLD: 'CommonWorldTypeId' = 62772 - MAGNOLIA_BLOSSOM: 'CommonWorldTypeId' = 42525 - MIRAGE_PARK: 'CommonWorldTypeId' = 201096 - MYSHUNO_MEADOWS: 'CommonWorldTypeId' = 132618 - OLD_TOWN: 'CommonWorldTypeId' = 101536 - PARCHED_PROSPECT: 'CommonWorldTypeId' = 23280 - PENDULA_VIEW: 'CommonWorldTypeId' = 20383 - PLUMBOB_PICTURES: 'CommonWorldTypeId' = 197665 - PUERTO_LLAMANTE_MARKETPLACE: 'CommonWorldTypeId' = 176581 - RETAIL_LOT_NAME_PLACEHOLDER: 'CommonWorldTypeId' = 72719 - RIDGELINE_DRIVE: 'CommonWorldTypeId' = 93558 - RURAL_VILLAGE: 'CommonWorldTypeId' = 100124 - SABLE_SQUARE: 'CommonWorldTypeId' = 164438 - SAGE_ESTATES: 'CommonWorldTypeId' = 20381 - SEASONS_ART_TEST_WORLD: 'CommonWorldTypeId' = 175243 - SKYWARD_PALMS: 'CommonWorldTypeId' = 23281 - SO_CACTUS_VENUS_01: 'CommonWorldTypeId' = 36256 - SO_RBH_CAVE_01: 'CommonWorldTypeId' = 45699 - SQE_EMPTY_LOT_AREA_TEST_WORLD: 'CommonWorldTypeId' = 21143 - SQE_GAMEPLAY_PROFILE_AREA3_TEST_WORLD: 'CommonWorldTypeId' = 21146 - STARLIGHT_BOULEVARD: 'CommonWorldTypeId' = 201098 - SYLVAN_GLADE: 'CommonWorldTypeId' = 47906 - THE_PINNACLES: 'CommonWorldTypeId' = 201097 - UPTOWN: 'CommonWorldTypeId' = 118767 - WHISKERMANS_WHARF: 'CommonWorldTypeId' = 164435 diff --git a/Scripts/s4ap/sims4communitylib/events/__init__.py b/Scripts/s4ap/sims4communitylib/events/__init__.py deleted file mode 100644 index 3251898..0000000 --- a/Scripts/s4ap/sims4communitylib/events/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" \ No newline at end of file diff --git a/Scripts/s4ap/sims4communitylib/events/build_buy/__init__.py b/Scripts/s4ap/sims4communitylib/events/build_buy/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/events/build_buy/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/events/build_buy/common_build_buy_event_dispatcher.py b/Scripts/s4ap/sims4communitylib/events/build_buy/common_build_buy_event_dispatcher.py deleted file mode 100644 index 1960616..0000000 --- a/Scripts/s4ap/sims4communitylib/events/build_buy/common_build_buy_event_dispatcher.py +++ /dev/null @@ -1,65 +0,0 @@ -""" -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 -""" -from typing import Any - -from s4ap.sims4communitylib.events.build_buy.events.build_buy_enter import S4CLBuildBuyEnterEvent -from s4ap.sims4communitylib.events.build_buy.events.build_buy_exit import S4CLBuildBuyExitEvent -from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from s4ap.sims4communitylib.logging.has_class_log import HasClassLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.common_service import CommonService -from s4ap.sims4communitylib.utils.common_injection_utils import CommonInjectionUtils -from zone import Zone - - -class CommonBuildBuyEventDispatcherService(CommonService, HasClassLog): - """A service that dispatches Build/Buy events. - - .. warning:: Do not use this service directly to listen for events!\ - Use the :class:`.CommonEventRegistry` to listen for dispatched events. - - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - return ModInfo.get_identity() - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 's4cl_build_buy_event_dispatcher' - - def _on_build_buy_enter(self, zone: Zone, *_, **__): - return CommonEventRegistry.get().dispatch(S4CLBuildBuyEnterEvent(zone)) - - def _on_build_buy_exit(self, zone: Zone, *_, **__): - return CommonEventRegistry.get().dispatch(S4CLBuildBuyExitEvent(zone)) - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), Zone, Zone.on_build_buy_enter.__name__) -def _common_build_buy_enter(original, self, *args, **kwargs) -> Any: - try: - result = original(self, *args, **kwargs) - except Exception as ex: - CommonBuildBuyEventDispatcherService.get_log().format_error_with_message('An error occurred when performing Zone.on_build_buy_enter. (This exception is not caused by S4CL, but rather caught)', owner=self, argles=args, kwargles=kwargs, exception=ex) - return - CommonBuildBuyEventDispatcherService.get()._on_build_buy_enter(self, *args, **kwargs) - return result - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), Zone, Zone.on_build_buy_exit.__name__) -def _common_build_buy_exit(original, self, *args, **kwargs) -> Any: - try: - result = original(self, *args, **kwargs) - except Exception as ex: - CommonBuildBuyEventDispatcherService.get_log().format_error_with_message('An error occurred when performing Zone.on_build_buy_exit. (This exception is not caused by S4CL, but rather caught)', owner=self, argles=args, kwargles=kwargs, exception=ex) - return - CommonBuildBuyEventDispatcherService.get()._on_build_buy_exit(self, *args, **kwargs) - return result diff --git a/Scripts/s4ap/sims4communitylib/events/build_buy/events/__init__.py b/Scripts/s4ap/sims4communitylib/events/build_buy/events/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/events/build_buy/events/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/events/build_buy/events/build_buy_enter.py b/Scripts/s4ap/sims4communitylib/events/build_buy/events/build_buy_enter.py deleted file mode 100644 index 20e46d2..0000000 --- a/Scripts/s4ap/sims4communitylib/events/build_buy/events/build_buy_enter.py +++ /dev/null @@ -1,51 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent -from zone import Zone - - -class S4CLBuildBuyEnterEvent(CommonEvent): - """S4CLBuildBuyEnterEvent(zone) - - An event that occurs upon entering Build/Buy on a lot. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity().name) - def handle_event(event_data: S4CLBuildBuyEnterEvent): - pass - - :param zone: The zone the player has entered Build/Buy on. - :type zone: Zone - """ - - def __init__(self, zone: Zone): - self._zone = zone - - @property - def zone(self) -> Zone: - """The zone the event occurred on. - - :return: The zone the event occurred on. - :rtype: Zone - """ - return self._zone diff --git a/Scripts/s4ap/sims4communitylib/events/build_buy/events/build_buy_exit.py b/Scripts/s4ap/sims4communitylib/events/build_buy/events/build_buy_exit.py deleted file mode 100644 index b175337..0000000 --- a/Scripts/s4ap/sims4communitylib/events/build_buy/events/build_buy_exit.py +++ /dev/null @@ -1,51 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent -from zone import Zone - - -class S4CLBuildBuyExitEvent(CommonEvent): - """S4CLBuildBuyEnterEvent(zone) - - An event that occurs upon exiting Build/Buy on a lot. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity().name) - def handle_event(event_data: S4CLBuildBuyExitEvent): - pass - - :param zone: The zone the player has exited Build/Buy on. - :type zone: Zone - """ - - def __init__(self, zone: Zone): - self._zone = zone - - @property - def zone(self) -> Zone: - """The zone the event occurred on. - - :return: The zone the event occurred on. - :rtype: Zone - """ - return self._zone diff --git a/Scripts/s4ap/sims4communitylib/events/event_handling/__init__.py b/Scripts/s4ap/sims4communitylib/events/event_handling/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/events/event_handling/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/events/event_handling/common_event.py b/Scripts/s4ap/sims4communitylib/events/event_handling/common_event.py deleted file mode 100644 index 84db0c8..0000000 --- a/Scripts/s4ap/sims4communitylib/events/event_handling/common_event.py +++ /dev/null @@ -1,25 +0,0 @@ -""" -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 -""" - - -class CommonEvent: - """ A custom event, for use with the :class:`.CommonEventHandler`. """ - @property - def event_name(self) -> str: - """The name of this event. - - :return: The name of the event. - :rtype: str - """ - return self.__class__.__name__ - - def __str__(self) -> str: - return 'CommonEvent[Name:{}]'.format(self.event_name) - - def __repr__(self) -> str: - return 'common_event_name_{}'.format(self.event_name) diff --git a/Scripts/s4ap/sims4communitylib/events/event_handling/common_event_handler.py b/Scripts/s4ap/sims4communitylib/events/event_handling/common_event_handler.py deleted file mode 100644 index f9a073d..0000000 --- a/Scripts/s4ap/sims4communitylib/events/event_handling/common_event_handler.py +++ /dev/null @@ -1,100 +0,0 @@ -""" -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 -""" -import inspect -from typing import Callable, Any, Union - -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity - - -class CommonEventHandler: - """CommonEventHandler(mod_identifier, event_function) - - Handles events. - - :param mod_identifier: The name or identity of the mod handling events. - :type mod_identifier: Union[str, CommonModIdentity] - :param event_function: The function this handler invokes. - :type event_function: Callable[[CommonEvent], Any] - :exception RuntimeError: When event_function is None. - :exception TypeError: When event_function is not a callable function. - :exception AssertionError: When the event_function is missing the event_data argument, when the event_function contains a self or cls argument, or when more than one argument is found. - """ - def __init__(self, mod_identifier: Union[str, CommonModIdentity], event_function: Callable[[CommonEvent], Any]): - if event_function is None: - raise RuntimeError('Required parameter \'event_function\' required for event function from mod: {}'.format(repr(mod_identifier))) - if not inspect.isfunction(event_function): - raise TypeError('\'event_function\' with name \'{}\' was not a callable function. Mod Name: \'{}\''.format(event_function.__name__, repr(mod_identifier))) - function_signature = inspect.signature(event_function) - if function_signature.parameters is None or len(function_signature.parameters) == 0 or len(function_signature.parameters) > 1: - raise AssertionError('Event Function has an incorrect number of parameters, Mod Name: \'{}\' Func Name: \'{}\''.format(repr(mod_identifier), event_function.__name__)) - if 'event_data' not in function_signature.parameters: - raise AssertionError('Event Function \'{}\' is missing the required argument with name \'event_data\'') - if 'self' in function_signature.parameters or 'cls' in function_signature.parameters: - raise AssertionError('Event functions must be static methods. Mod Name: \'{}\', Function: \'{}\''.format(repr(mod_identifier), event_function.__name__)) - from s4ap.sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils - self._mod_name = CommonModIdentityUtils.determine_mod_name_from_identifier(mod_identifier) - self._event_function = event_function - self._event_type = function_signature.parameters['event_data'].annotation - - @property - def mod_name(self) -> str: - """The name of the mod this event handler was created for. - - :return: The name of the Mod that owns this handler. - :rtype: str - """ - return self._mod_name - - @property - def event_function(self) -> Callable[[CommonEvent], Any]: - """The action to take upon receiving an event. - - :return: The function that handles events. - :rtype: Callable[[CommonEvent], Any] - """ - return self._event_function - - @property - def event_type(self) -> type: - """The class type of events this Event Handler will handle. - - :return: The types of events the handler handles. - :rtype: type - """ - return self._event_type - - def can_handle_event(self, event: CommonEvent) -> bool: - """can_handle_event(event) - - Determine if this event handler can handle the type of the event. - - :param event: The event to check. - :type event: CommonEvent - :return: True, if this handler can handle the event. False, if not. - :rtype: bool - """ - return isinstance(event, self.event_type) - - def handle_event(self, event: CommonEvent) -> bool: - """handle_event(event) - - Handle the event data. - - :param event: The event to handle. - :type event: CommonEvent - :return: True, if the event was successful. False, if not. - :rtype: bool - """ - return self.event_function(event) - - def __repr__(self) -> str: - return 'mod_name_{}_function_{}_event_type_{}'.format(self.mod_name, self.event_function.__name__, self.event_type.__name__) - - def __str__(self) -> str: - return 'CommonEventHandler Mod Name: \'{}\' Function: \'{}\' Event Type: \'{}\''.format(self.mod_name, self.event_function.__name__, self.event_type.__name__) diff --git a/Scripts/s4ap/sims4communitylib/events/event_handling/common_event_registry.py b/Scripts/s4ap/sims4communitylib/events/event_handling/common_event_registry.py deleted file mode 100644 index 135aaa4..0000000 --- a/Scripts/s4ap/sims4communitylib/events/event_handling/common_event_registry.py +++ /dev/null @@ -1,78 +0,0 @@ -""" -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 -""" -from typing import List, Callable, Any, Union -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent -from s4ap.sims4communitylib.events.event_handling.common_event_handler import CommonEventHandler -from s4ap.sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.common_service import CommonService - - -class CommonEventRegistry(CommonService): - """Register event listeners and dispatch events to any that are registered. - - """ - - def __init__(self) -> None: - self._event_handlers: List[CommonEventHandler] = [] - - @staticmethod - def handle_events(mod_identifier: Union[str, CommonModIdentity]) -> Callable[[Callable[[CommonEvent], bool]], Callable[[CommonEvent], bool]]: - """handle_events(mod_identifier) - - Decorate functions with this static method to register that function to handle an event. - - :warning:: Event functions MUST be decorated with staticmethod and must only have a single argument with the name 'event_data' (Errors will be thrown upon loading the game otherwise) - - :param mod_identifier: The name or identity of the mod the class is being registered for. - :type mod_identifier: Union[str, CommonModIdentity] - :return: A callable function wrapped to handle events. - :rtype: Callable[[Callable[[CommonEvent], bool]], Callable[[CommonEvent], bool]] - """ - def _wrapper(event_function: Callable[[CommonEvent], bool]) -> Callable[..., Any]: - CommonEventRegistry.get()._register_event_handler(mod_identifier, event_function) - return event_function - return _wrapper - - def _register_event_handler(self, mod_identifier: Union[str, CommonModIdentity], event_function: Callable[[CommonEvent], bool]): - event_handler = CommonEventHandler(mod_identifier, event_function) - self._event_handlers.append(event_handler) - - def dispatch(self, event: CommonEvent) -> bool: - """dispatch(event) - - Dispatch an event to any event handlers listening for it. - - .. note:: If any listeners return False or None when they handle the event, the total result of dispatch will be False as well. - - :param event: An instance of an Event to dispatch to listeners. - :type event: CommonEvent - :return: True, if the Event was dispatched to all listeners successfully. False, if any listeners failed to handle the event. - :rtype: bool - """ - return self._dispatch(event) - - def _dispatch(self, event: CommonEvent) -> bool: - event_handlers = list(self._event_handlers) - result = True - try: - for event_handler in event_handlers: - if not event_handler.can_handle_event(event): - continue - try: - handle_result = event_handler.handle_event(event) - if not handle_result: - result = False - except Exception as ex: - CommonExceptionHandler.log_exception(event_handler.mod_name, 'Error occurred when attempting to handle event type \'{}\' via event handler \'{}\''.format(type(event), str(event_handler)), exception=ex) - continue - except Exception as ex: - CommonExceptionHandler.log_exception(ModInfo.get_identity(), 'Failed to dispatch event \'{}\''.format(event), exception=ex) - return False - return result diff --git a/Scripts/s4ap/sims4communitylib/events/game_object/__init__.py b/Scripts/s4ap/sims4communitylib/events/game_object/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/events/game_object/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/events/game_object/common_game_object_event_dispatcher.py b/Scripts/s4ap/sims4communitylib/events/game_object/common_game_object_event_dispatcher.py deleted file mode 100644 index 92a6aed..0000000 --- a/Scripts/s4ap/sims4communitylib/events/game_object/common_game_object_event_dispatcher.py +++ /dev/null @@ -1,131 +0,0 @@ -""" -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 -""" -from typing import Any - -from objects.game_object import GameObject -from objects.script_object import ScriptObject -from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from s4ap.sims4communitylib.events.game_object.events.game_object_added_to_inventory import S4CLGameObjectAddedToInventoryEvent -from s4ap.sims4communitylib.events.game_object.events.game_object_pre_despawned import S4CLGameObjectPreDespawnedEvent -from s4ap.sims4communitylib.events.game_object.events.game_object_pre_deleted import S4CLGameObjectPreDeletedEvent -from s4ap.sims4communitylib.events.game_object.events.game_object_initialized import S4CLGameObjectInitializedEvent -from s4ap.sims4communitylib.events.game_object.events.game_object_loaded import S4CLGameObjectLoadedEvent -from s4ap.sims4communitylib.events.game_object.events.game_object_pre_removed_from_inventory import \ - S4CLGameObjectPreRemovedFromInventoryEvent -from s4ap.sims4communitylib.events.game_object.events.game_object_spawned import S4CLGameObjectSpawnedEvent -from s4ap.sims4communitylib.events.game_object.events.game_object_added_to_game_object_inventory import \ - S4CLGameObjectAddedToGameObjectInventoryEvent -from s4ap.sims4communitylib.events.game_object.events.game_object_pre_removed_from_game_object_inventory import \ - S4CLGameObjectPreRemovedFromGameObjectInventoryEvent -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.common_service import CommonService -from s4ap.sims4communitylib.utils.common_injection_utils import CommonInjectionUtils - - -class CommonGameObjectEventDispatcherService(CommonService): - """A service that dispatches Game Object events (Init, Spawn, Destroy, etc.). - - .. warning:: Do not use this service directly to listen for events!\ - Use the :class:`.CommonEventRegistry` to listen for dispatched events. - - """ - - def _on_game_object_init(self, game_object: GameObject, *_, **__) -> bool: - return CommonEventRegistry.get().dispatch(S4CLGameObjectInitializedEvent(game_object)) - - def _on_game_object_load(self, game_object: GameObject, *_, **__) -> bool: - from s4ap.sims4communitylib.events.zone_spin.common_zone_spin_event_dispatcher import CommonZoneSpinEventDispatcher - if CommonZoneSpinEventDispatcher.get().game_loading: - return False - return CommonEventRegistry.get().dispatch(S4CLGameObjectLoadedEvent(game_object)) - - def _on_game_object_spawned(self, game_object: GameObject, *_, **__) -> bool: - return CommonEventRegistry.get().dispatch(S4CLGameObjectSpawnedEvent(game_object)) - - def _on_game_object_despawned(self, game_object: GameObject, *_, **__) -> bool: - return CommonEventRegistry.get().dispatch(S4CLGameObjectPreDespawnedEvent(game_object)) - - def _on_game_object_destroy(self, game_object: GameObject, *_, **__) -> bool: - return CommonEventRegistry.get().dispatch(S4CLGameObjectPreDeletedEvent(game_object)) - - def _on_game_object_added_to_inventory(self, game_object: GameObject, *_, **__) -> bool: - return CommonEventRegistry.get().dispatch(S4CLGameObjectAddedToInventoryEvent(game_object)) - - def _on_game_object_pre_removed_from_inventory(self, game_object: GameObject, *_, **__) -> bool: - return CommonEventRegistry.get().dispatch(S4CLGameObjectPreRemovedFromInventoryEvent(game_object)) - - def _on_game_object_added_to_game_object_inventory(self, game_object: GameObject, added_object: GameObject) -> None: - CommonEventRegistry.get().dispatch(S4CLGameObjectAddedToGameObjectInventoryEvent(game_object, added_object)) - - def _on_game_object_pre_removed_from_game_object_inventory(self, game_object: GameObject, removed_object: GameObject) -> None: - CommonEventRegistry.get().dispatch(S4CLGameObjectPreRemovedFromGameObjectInventoryEvent(game_object, removed_object)) - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), GameObject, GameObject.__init__.__name__, handle_exceptions=False) -def _common_on_game_object_init(original, self, *args, **kwargs) -> Any: - result = original(self, *args, **kwargs) - CommonGameObjectEventDispatcherService.get()._on_game_object_init(self, *args, **kwargs) - return result - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), GameObject, GameObject.load_object.__name__, handle_exceptions=False) -def _common_on_game_object_load(original, self, *args, **kwargs) -> Any: - result = original(self, *args, **kwargs) - CommonGameObjectEventDispatcherService.get()._on_game_object_load(self, *args, **kwargs) - return result - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), GameObject, GameObject.destroy.__name__, handle_exceptions=False) -def _common_on_game_object_load(original, self, *args, **kwargs) -> Any: - CommonGameObjectEventDispatcherService.get()._on_game_object_destroy(self, *args, **kwargs) - result = original(self, *args, **kwargs) - return result - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), GameObject, GameObject.on_add.__name__) -def _common_on_game_object_added(original, self, *args, **kwargs) -> Any: - result = original(self, *args, **kwargs) - CommonGameObjectEventDispatcherService.get()._on_game_object_spawned(self, *args, **kwargs) - return result - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), GameObject, GameObject.on_remove.__name__) -def _common_on_game_object_removed(original, self, *args, **kwargs) -> Any: - CommonGameObjectEventDispatcherService.get()._on_game_object_despawned(self, *args, **kwargs) - result = original(self, *args, **kwargs) - return result - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), GameObject, GameObject.on_added_to_inventory.__name__) -def _common_on_game_object_added_to_inventory(original, self, *args, **kwargs) -> Any: - result = original(self, *args, **kwargs) - CommonGameObjectEventDispatcherService.get()._on_game_object_added_to_inventory(self, *args, **kwargs) - return result - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), GameObject, GameObject.on_removed_from_inventory.__name__) -def _common_on_game_object_removed_from_inventory(original, self, *args, **kwargs) -> Any: - CommonGameObjectEventDispatcherService.get()._on_game_object_pre_removed_from_inventory(self, *args, **kwargs) - result = original(self, *args, **kwargs) - return result - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), GameObject, GameObject.on_object_added_to_inventory.__name__, handle_exceptions=False) -def _common_on_game_object_added_to_game_object_inventory(original, self: GameObject, obj: ScriptObject, *args, **kwargs): - result = original(self, obj, *args, **kwargs) - if isinstance(obj, GameObject): - CommonGameObjectEventDispatcherService.get()._on_game_object_added_to_game_object_inventory(self, obj) - return result - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), GameObject, GameObject.on_object_removed_from_inventory.__name__, handle_exceptions=False) -def _common_on_game_object_removed_from_game_object_inventory(original, self: GameObject, obj: ScriptObject, *args, **kwargs): - if isinstance(obj, GameObject): - CommonGameObjectEventDispatcherService.get()._on_game_object_pre_removed_from_game_object_inventory(self, obj) - result = original(self, obj, *args, **kwargs) - return result diff --git a/Scripts/s4ap/sims4communitylib/events/game_object/events/__init__.py b/Scripts/s4ap/sims4communitylib/events/game_object/events/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/events/game_object/events/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_added_to_game_object_inventory.py b/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_added_to_game_object_inventory.py deleted file mode 100644 index d91b1b6..0000000 --- a/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_added_to_game_object_inventory.py +++ /dev/null @@ -1,83 +0,0 @@ -""" -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 -""" -from objects.game_object import GameObject -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent -from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils - - -class S4CLGameObjectAddedToGameObjectInventoryEvent(CommonEvent): - """S4CLGameObjectAddedToGameObjectInventoryEvent(game_object, added_game_object) - - An event that occurs when a GameObject is added to the inventory of another Game Object. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity()) - def handle_event(event_data: S4CLGameObjectAddedToGameObjectInventoryEvent): - pass - - :param game_object: The Game Object that changed. - :type game_object: GameObject - :param added_game_object: The Object that was added to the inventory of the Game Object. - :type added_game_object: GameObject - """ - - def __init__(self, game_object: GameObject, added_game_object: GameObject): - self._game_object = game_object - self._added_game_object = added_game_object - - @property - def game_object(self) -> GameObject: - """The Game Object that had the Game Object added to its inventory. - - :return: The Game Object that had the Game Object added to its inventory. - :rtype: GameObject - """ - return self._game_object - - @property - def added_game_object(self) -> GameObject: - """The Game Object that was added. - - :return: The Game Object that was added. - :rtype: GameObject - """ - return self._added_game_object - - @property - def added_game_object_id(self) -> int: - """The decimal identifier of the Game Object that was added. - - :return: The decimal identifier of the Game Object that was added. - :rtype: int - """ - return CommonObjectUtils.get_object_id(self.added_game_object) - - @property - def added_game_object_guid(self) -> int: - """The guid identifier of the Game Object that was added. - - :return: The guid identifier of the Game Object that was added. - :rtype: int - """ - # noinspection PyTypeChecker - return CommonObjectUtils.get_object_guid(self.added_game_object) diff --git a/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_added_to_inventory.py b/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_added_to_inventory.py deleted file mode 100644 index a77d052..0000000 --- a/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_added_to_inventory.py +++ /dev/null @@ -1,51 +0,0 @@ -""" -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 -""" -from objects.game_object import GameObject -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent - - -class S4CLGameObjectAddedToInventoryEvent(CommonEvent): - """S4CLGameObjectAddedToInventoryEvent(game_object) - - An event that occurs after a Game Object has been added to the inventory of something. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity().name) - def handle_event(event_data: S4CLGameObjectAddedToInventoryEvent): - pass - - :param game_object: The Object has been added to the inventory of something. - :type game_object: GameObject - """ - - def __init__(self, game_object: GameObject): - self._game_object = game_object - - @property - def game_object(self) -> GameObject: - """The Game Object that was added to the inventory. - - :return: The Game Object that was added to the inventory. - :rtype: GameObject - """ - return self._game_object diff --git a/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_initialized.py b/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_initialized.py deleted file mode 100644 index ebffa40..0000000 --- a/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_initialized.py +++ /dev/null @@ -1,51 +0,0 @@ -""" -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 -""" -from objects.game_object import GameObject -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent - - -class S4CLGameObjectInitializedEvent(CommonEvent): - """S4CLGameObjectInitializedEvent(game_object) - - An event that occurs after a Game Object has been initialized. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity().name) - def handle_event(event_data: S4CLGameObjectInitializedEvent): - pass - - :param game_object: The Game Object that was initialized. - :type game_object: GameObject - """ - - def __init__(self, game_object: GameObject): - self._game_object = game_object - - @property - def game_object(self) -> GameObject: - """The Game Object that was initialized. - - :return: The Game Object that was initialized. - :rtype: GameObject - """ - return self._game_object diff --git a/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_loaded.py b/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_loaded.py deleted file mode 100644 index 1dcc216..0000000 --- a/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_loaded.py +++ /dev/null @@ -1,51 +0,0 @@ -""" -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 -""" -from objects.game_object import GameObject -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent - - -class S4CLGameObjectLoadedEvent(CommonEvent): - """S4CLGameObjectLoadedEvent(game_object) - - An event that occurs after a Game Object has been loaded. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity().name) - def handle_event(event_data: S4CLGameObjectLoadedEvent): - pass - - :param game_object: The Game Object that was loaded. - :type game_object: GameObject - """ - - def __init__(self, game_object: GameObject): - self._game_object = game_object - - @property - def game_object(self) -> GameObject: - """The Game Object that was loaded. - - :return: The Game Object that was loaded. - :rtype: GameObject - """ - return self._game_object diff --git a/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_deleted.py b/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_deleted.py deleted file mode 100644 index d10db85..0000000 --- a/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_deleted.py +++ /dev/null @@ -1,51 +0,0 @@ -""" -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 -""" -from objects.game_object import GameObject -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent - - -class S4CLGameObjectPreDeletedEvent(CommonEvent): - """S4CLGameObjectPreDeletedEvent(game_object) - - An event that occurs before a Game Object has been deleted. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity().name) - def handle_event(event_data: S4CLGameObjectPreDeletedEvent): - pass - - :param game_object: The Game Object that will be deleted. - :type game_object: GameObject - """ - - def __init__(self, game_object: GameObject): - self._game_object = game_object - - @property - def game_object(self) -> GameObject: - """The Game Object that will be deleted. - - :return: The Game Object that will be deleted. - :rtype: GameObject - """ - return self._game_object diff --git a/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_despawned.py b/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_despawned.py deleted file mode 100644 index b68ba51..0000000 --- a/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_despawned.py +++ /dev/null @@ -1,51 +0,0 @@ -""" -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 -""" -from objects.game_object import GameObject -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent - - -class S4CLGameObjectPreDespawnedEvent(CommonEvent): - """S4CLGameObjectPreDespawnedEvent(game_object) - - An event that occurs before an Object is despawned. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity().name) - def handle_event(event_data: S4CLGameObjectPreDespawnedEvent): - pass - - :param game_object: The Game Object that will be despawned. - :type game_object: GameObject - """ - - def __init__(self, game_object: GameObject): - self._game_object = game_object - - @property - def game_object(self) -> GameObject: - """The Game Object that will be despawned. - - :return: The Game Object that will be despawned. - :rtype: GameObject - """ - return self._game_object diff --git a/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_removed_from_game_object_inventory.py b/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_removed_from_game_object_inventory.py deleted file mode 100644 index e066a41..0000000 --- a/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_removed_from_game_object_inventory.py +++ /dev/null @@ -1,83 +0,0 @@ -""" -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 -""" -from objects.game_object import GameObject -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent -from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils - - -class S4CLGameObjectPreRemovedFromGameObjectInventoryEvent(CommonEvent): - """S4CLGameObjectPreRemovedFromGameObjectInventoryEvent(game_object, removed_game_object) - - An event that occurs before a Game Object is removed from the inventory of another Game Object. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity()) - def handle_event(event_data: S4CLGameObjectPreRemovedFromGameObjectInventoryEvent): - pass - - :param game_object: The Game Object that changed. - :type game_object: GameObject - :param removed_game_object: The Object that was removed from the inventory of the Game Object. - :type removed_game_object: GameObject - """ - - def __init__(self, game_object: GameObject, removed_game_object: GameObject): - self._game_object = game_object - self._removed_game_object = removed_game_object - - @property - def game_object(self) -> GameObject: - """The Game Object that is having the Game Object removed from its inventory. - - :return: The Game Object that is having the Game Object removed from its inventory. - :rtype: GameObject - """ - return self._game_object - - @property - def removed_game_object(self) -> GameObject: - """The Game Object that is being removed. - - :return: The Game Object that is being removed. - :rtype: GameObject - """ - return self._removed_game_object - - @property - def removed_game_object_id(self) -> int: - """The decimal identifier of the Game Object that is being removed. - - :return: The decimal identifier of the Game Object that is being removed. - :rtype: int - """ - return CommonObjectUtils.get_object_id(self.removed_game_object) - - @property - def removed_game_object_guid(self) -> int: - """The guid identifier of the Game Object that is being removed. - - :return: The guid identifier of the Game Object that is being removed. - :rtype: int - """ - # noinspection PyTypeChecker - return CommonObjectUtils.get_object_guid(self.removed_game_object) diff --git a/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_removed_from_inventory.py b/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_removed_from_inventory.py deleted file mode 100644 index beefe98..0000000 --- a/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_pre_removed_from_inventory.py +++ /dev/null @@ -1,51 +0,0 @@ -""" -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 -""" -from objects.game_object import GameObject -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent - - -class S4CLGameObjectPreRemovedFromInventoryEvent(CommonEvent): - """S4CLGameObjectPreRemovedFromInventoryEvent(game_object) - - An event that occurs before a Game Object has been removed from the inventory of something. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity().name) - def handle_event(event_data: S4CLGameObjectPreRemovedFromInventoryEvent): - pass - - :param game_object: The Game Object that will be removed from the inventory of something. - :type game_object: GameObject - """ - - def __init__(self, game_object: GameObject): - self._game_object = game_object - - @property - def game_object(self) -> GameObject: - """The Game Object that will be removed from the inventory. - - :return: The Game Object that will be removed from the inventory. - :rtype: GameObject - """ - return self._game_object diff --git a/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_spawned.py b/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_spawned.py deleted file mode 100644 index f7c3191..0000000 --- a/Scripts/s4ap/sims4communitylib/events/game_object/events/game_object_spawned.py +++ /dev/null @@ -1,51 +0,0 @@ -""" -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 -""" -from objects.game_object import GameObject -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent - - -class S4CLGameObjectSpawnedEvent(CommonEvent): - """S4CLGameObjectSpawnedEvent(game_object) - - An event that occurs after a Game Object has been spawned. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity().name) - def handle_event(event_data: S4CLGameObjectSpawnedEvent): - pass - - :param game_object: The Game Object that was spawned. - :type game_object: GameObject - """ - - def __init__(self, game_object: GameObject): - self._game_object = game_object - - @property - def game_object(self) -> GameObject: - """The Game Object that was spawned. - - :return: The Game Object that was spawned. - :rtype: GameObject - """ - return self._game_object diff --git a/Scripts/s4ap/sims4communitylib/events/interaction/__init__.py b/Scripts/s4ap/sims4communitylib/events/interaction/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/events/interaction/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/events/interaction/common_interaction_event_dispatcher.py b/Scripts/s4ap/sims4communitylib/events/interaction/common_interaction_event_dispatcher.py deleted file mode 100644 index 7d645e8..0000000 --- a/Scripts/s4ap/sims4communitylib/events/interaction/common_interaction_event_dispatcher.py +++ /dev/null @@ -1,497 +0,0 @@ -""" -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 -""" -import os -from pprint import pformat -from typing import Union, Any -from interactions.base.interaction import Interaction -from interactions.base.mixer_interaction import MixerInteraction -from interactions.base.super_interaction import SuperInteraction -from interactions.interaction_finisher import FinishingType -from interactions.interaction_queue import InteractionQueue -from interactions.utils.outcome import InteractionOutcome -from interactions.utils.outcome_enums import OutcomeResult -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from s4ap.sims4communitylib.events.interaction.events.interaction_cancelled import S4CLInteractionCancelledEvent -from s4ap.sims4communitylib.events.interaction.events.interaction_outcome import S4CLInteractionOutcomeEvent -from s4ap.sims4communitylib.events.interaction.events.interaction_post_queued import S4CLInteractionPostQueuedEvent -from s4ap.sims4communitylib.events.interaction.events.interaction_pre_run import S4CLInteractionPreRunEvent -from s4ap.sims4communitylib.events.interaction.events.interaction_queued import S4CLInteractionQueuedEvent -from s4ap.sims4communitylib.events.interaction.events.interaction_run import S4CLInteractionRunEvent -from s4ap.sims4communitylib.events.interaction.events.interaction_started import S4CLInteractionStartedEvent -from s4ap.sims4communitylib.events.interaction.events.mixer_interaction_cancelled import S4CLMixerInteractionCancelledEvent -from s4ap.sims4communitylib.events.interaction.events.super_interaction_cancelled import S4CLSuperInteractionCancelledEvent -from s4ap.sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler -from s4ap.sims4communitylib.logging.has_log import HasLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.common_service import CommonService -from s4ap.sims4communitylib.utils.common_injection_utils import CommonInjectionUtils -from s4ap.sims4communitylib.utils.resources.common_interaction_utils import CommonInteractionUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - -ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' - -# If on Read The Docs, create fake versions of extended objects to fix the error of inheriting from multiple MockObjects. -if ON_RTD: - # noinspection PyMissingOrEmptyDocstring - class Timeline: - pass - -if not ON_RTD: - from scheduling import Timeline - - -class CommonInteractionEventDispatcherService(CommonService, HasLog): - """A service that dispatches interaction events (Run, Queued, Performed, etc.). - - .. warning:: Do not use this service directly to listen for events!\ - Use the :class:`.CommonEventRegistry` to listen for dispatched events. - - """ - - # noinspection PyMissingOrEmptyDocstring - @property - def mod_identity(self) -> CommonModIdentity: - return ModInfo.get_identity() - - # noinspection PyUnusedLocal - def _on_interaction_pre_run(self, interaction_queue: InteractionQueue, timeline: Timeline, interaction: Interaction, *_, **__) -> Union[bool, None]: - if interaction is None or interaction.sim is None: - return None - try: - if not CommonEventRegistry().dispatch(S4CLInteractionPreRunEvent(interaction, interaction_queue, timeline)): - return False - except Exception as ex: - CommonExceptionHandler.log_exception( - None, - 'Error occurred while running _on_interaction_pre_run for interaction {} with short name \'{}\' and display name {}. (This exception is not caused by S4CL, but rather caught) Args: {}, Kwargs: {}' - .format( - pformat(interaction), - CommonInteractionUtils.get_interaction_short_name(interaction), - CommonInteractionUtils.get_interaction_display_name(interaction), - _, - __ - ), - exception=ex - ) - return None - - # noinspection PyUnusedLocal - def _on_interaction_run(self, interaction_queue: InteractionQueue, timeline: Timeline, interaction: Interaction, run_result: bool, *_, **__) -> None: - if interaction is None or interaction.sim is None: - return None - try: - CommonEventRegistry().dispatch(S4CLInteractionRunEvent(interaction, interaction_queue, run_result)) - except Exception as ex: - CommonExceptionHandler.log_exception( - None, - 'Error occurred while running _on_interaction_run for interaction {} with short name \'{}\' and display name {}. (This exception is not caused by S4CL, but rather caught) Original Run Result: {}, Args: {}, Kwargs: {}'.format( - pformat(interaction), - CommonInteractionUtils.get_interaction_short_name(interaction), - CommonInteractionUtils.get_interaction_display_name(interaction), - str(run_result), - _, - __ - ), - exception=ex - ) - return None - - # noinspection PyUnusedLocal - def _on_interaction_started(self, interaction: Interaction, *_, **__) -> None: - if interaction is None or interaction.sim is None: - return None - try: - source_sim_info = CommonSimUtils.get_sim_info(interaction.sim) - target = interaction.target - CommonEventRegistry().dispatch(S4CLInteractionStartedEvent(interaction, source_sim_info, target)) - except Exception as ex: - CommonExceptionHandler.log_exception( - None, - 'Error occurred while running _on_interaction_started for interaction {} with short name \'{}\' and display name {}. (This exception is not caused by S4CL, but rather caught) Args: {}, Kwargs: {}'.format( - pformat(interaction), - CommonInteractionUtils.get_interaction_short_name(interaction), - CommonInteractionUtils.get_interaction_display_name(interaction), - _, - __ - ), - exception=ex - ) - return None - - def _on_interaction_queued(self, interaction_queue: InteractionQueue, interaction: Interaction, *_, **__) -> Union[CommonTestResult, None]: - if interaction is None or interaction.sim is None: - return None - try: - if not CommonEventRegistry().dispatch(S4CLInteractionQueuedEvent(interaction, interaction_queue)): - return CommonTestResult(False, reason='Interaction \'{}\' Failed to Queue'.format(pformat(interaction))) - except Exception as ex: - CommonExceptionHandler.log_exception( - None, - 'Error occurred while running _on_interaction_queued for interaction {} with short name \'{}\' and display name {}. (This exception is not caused by S4CL, but rather caught) Args: {}, Kwargs: {}'.format( - pformat(interaction), - CommonInteractionUtils.get_interaction_short_name(interaction), - CommonInteractionUtils.get_interaction_display_name(interaction), - _, - __ - ), - exception=ex - ) - return None - - def _on_interaction_post_queued(self, interaction_queue: InteractionQueue, interaction: Interaction, queue_result: CommonTestResult, *_, **__) -> None: - if interaction is None or interaction.sim is None: - return None - try: - CommonEventRegistry().dispatch(S4CLInteractionPostQueuedEvent(interaction, interaction_queue, queue_result)) - except Exception as ex: - CommonExceptionHandler.log_exception( - None, - 'Error occurred while running _on_interaction_post_queued for interaction {} with short name \'{}\' and display name {}. (This exception is not caused by S4CL, but rather caught) Queue Result: {}, Args: {}, Kwargs: {}'.format( - pformat(interaction), - CommonInteractionUtils.get_interaction_short_name(interaction), - CommonInteractionUtils.get_interaction_display_name(interaction), - queue_result, - _, - __ - ), - exception=ex - ) - return None - - def _on_interaction_outcome(self, interaction: Interaction, outcome: InteractionOutcome, result: OutcomeResult) -> None: - if interaction.sim is None: - return None - try: - CommonEventRegistry().dispatch(S4CLInteractionOutcomeEvent(interaction, outcome, result)) - except Exception as ex: - CommonExceptionHandler.log_exception( - None, - 'Error occurred while running _on_interaction_outcome for interaction {} with short name \'{}\' and display name {}. (This exception is not caused by S4CL, but rather caught) Outcome: {}, Result: {}'.format( - pformat(interaction), - CommonInteractionUtils.get_interaction_short_name(interaction), - CommonInteractionUtils.get_interaction_display_name(interaction), - outcome, - result - ), - exception=ex - ) - return None - - def _on_interaction_cancelled(self, interaction: Interaction, finishing_type: FinishingType, cancel_reason_msg: str, ignore_must_run: bool=False, **__) -> None: - if finishing_type is None: - return None - try: - CommonEventRegistry().dispatch(S4CLInteractionCancelledEvent(interaction, finishing_type, cancel_reason_msg, ignore_must_run=ignore_must_run, **__)) - except Exception as ex: - CommonExceptionHandler.log_exception( - None, - 'Error occurred while running _on_interaction_cancelled for interaction {} with short name \'{}\' and display name {}. (This exception is not caused by S4CL, but rather caught) Finishing Type: {}, Cancel Reason: {}, Ignore Must Run: {}, Kwargs: {}'.format( - pformat(interaction), - CommonInteractionUtils.get_interaction_short_name(interaction), - CommonInteractionUtils.get_interaction_display_name(interaction), - finishing_type, - cancel_reason_msg, - ignore_must_run, - __ - ), - exception=ex - ) - return None - - def _on_mixer_interaction_cancelled(self, interaction: MixerInteraction, finishing_type: FinishingType, cancel_reason_msg: str, **__) -> None: - if finishing_type is None: - return None - try: - CommonEventRegistry().dispatch(S4CLMixerInteractionCancelledEvent(interaction, finishing_type, cancel_reason_msg, **__)) - except Exception as ex: - CommonExceptionHandler.log_exception( - None, - 'Error occurred while running _on_mixer_interaction_cancelled for interaction {} with short name \'{}\' and display name {}. (This exception is not caused by S4CL, but rather caught) Finishing Type: {}, Cancel Reason: {}, Kwargs: {}'.format( - pformat(interaction), - CommonInteractionUtils.get_interaction_short_name(interaction), - CommonInteractionUtils.get_interaction_display_name(interaction), - finishing_type, - cancel_reason_msg, - __ - ), - exception=ex - ) - return None - - def _on_super_interaction_cancelled(self, interaction: SuperInteraction, finishing_type: FinishingType, cancel_reason_msg: str, **__) -> None: - if interaction is None or finishing_type is None: - return None - try: - CommonEventRegistry().dispatch(S4CLSuperInteractionCancelledEvent(interaction, finishing_type, cancel_reason_msg, **__)) - except Exception as ex: - CommonExceptionHandler.log_exception( - None, - 'Error occurred while running _on_super_interaction_cancelled for interaction {} with short name \'{}\' and display name {}. (This exception is not caused by S4CL, but rather caught) Finishing Type: {}, Cancel Reason: {}, Kwargs: {}'.format( - pformat(interaction), - CommonInteractionUtils.get_interaction_short_name(interaction), - CommonInteractionUtils.get_interaction_display_name(interaction), - finishing_type, - cancel_reason_msg, - __ - ), - exception=ex - ) - return None - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), InteractionQueue, InteractionQueue.run_interaction_gen.__name__) -def _common_on_interaction_run(original, self, timeline: Timeline, interaction: Interaction, *_, **__) -> bool: - try: - result = CommonInteractionEventDispatcherService()._on_interaction_pre_run(self, timeline, interaction, *_, **__) - if result is None or result: - try: - original_result = original(self, timeline, interaction, *_, **__) - except Exception as ex: - CommonExceptionHandler.log_exception( - None, - 'Error occurred while running _on_interaction_run for interaction {} with short name \'{}\' and display name {}. (This exception is not caused by S4CL, but rather caught) Args: {}, Kwargs: {}'.format( - pformat(interaction), - CommonInteractionUtils.get_interaction_short_name(interaction), - CommonInteractionUtils.get_interaction_display_name(interaction), - _, - __ - ), - exception=ex - ) - return False - CommonInteractionEventDispatcherService()._on_interaction_run(self, timeline, interaction, original_result, *_, **__) - return original_result - return result - except Exception as ex: - CommonExceptionHandler.log_exception( - ModInfo.get_identity(), - 'Error occurred while running _on_interaction_run for interaction {} with short name \'{}\' and display name {}. Args: {}, Kwargs: {}'.format( - pformat(interaction), - CommonInteractionUtils.get_interaction_short_name(interaction), - CommonInteractionUtils.get_interaction_display_name(interaction), - _, - __ - ), - exception=ex - ) - return False - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), Interaction, Interaction._trigger_interaction_start_event.__name__) -def _common_on_interaction_started(original, self, *_, **__) -> bool: - try: - try: - original_result = original(self, *_, **__) - except Exception as ex: - CommonExceptionHandler.log_exception( - None, - 'Error occurred while running _trigger_interaction_start_event for interaction {} with short name \'{}\' and display name {}. (This exception is not caused by S4CL, but rather caught) Args: {}, Kwargs: {}'.format( - pformat(self), - CommonInteractionUtils.get_interaction_short_name(self), - CommonInteractionUtils.get_interaction_display_name(self), - _, - __ - ), - exception=ex - ) - return False - CommonInteractionEventDispatcherService()._on_interaction_started(self, *_, **__) - return original_result - except Exception as ex: - CommonExceptionHandler.log_exception( - ModInfo.get_identity(), - 'Error occurred while running _trigger_interaction_start_event for interaction {} with short name \'{}\' and display name {}. Args: {}, Kwargs: {}'.format( - pformat(self), - CommonInteractionUtils.get_interaction_short_name(self), - CommonInteractionUtils.get_interaction_display_name(self), - _, - __ - ), - exception=ex - ) - return False - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), InteractionQueue, InteractionQueue.append.__name__) -def _common_on_interaction_queued(original, self, interaction: Interaction, *_, **__) -> CommonTestResult: - try: - result = CommonInteractionEventDispatcherService()._on_interaction_queued(self, interaction, *_, **__) - if result is None or result: - try: - original_result = original(self, interaction, *_, **__) - except Exception as ex: - CommonExceptionHandler.log_exception( - None, - 'Error occurred while running _on_interaction_queued for interaction {} with short name \'{}\' and display name {}. (This exception is not caused by S4CL, but rather caught) Args: {}, Kwargs: {}'.format( - pformat(interaction), - CommonInteractionUtils.get_interaction_short_name(interaction), - CommonInteractionUtils.get_interaction_display_name(interaction), - _, - __ - ), - exception=ex - ) - return CommonTestResult.NONE - original_result: CommonTestResult = CommonTestResult.convert_from_vanilla(original_result) - CommonInteractionEventDispatcherService()._on_interaction_post_queued(self, interaction, original_result, *_, **__) - return original_result - return result - except Exception as ex: - CommonExceptionHandler.log_exception( - ModInfo.get_identity(), - 'Error occurred while running _on_interaction_queued for interaction {} with short name \'{}\' and display name {}. Args: {}, Kwargs: {}'.format( - pformat(interaction), - CommonInteractionUtils.get_interaction_short_name(interaction), - CommonInteractionUtils.get_interaction_display_name(interaction), - _, - __ - ), - exception=ex - ) - return CommonTestResult(False, reason='Interaction \'{}\' with short name \'{}\' Failed to Queue'.format( - pformat(interaction), - CommonInteractionUtils.get_interaction_short_name(interaction) - )) - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), Interaction, Interaction.store_result_for_outcome.__name__) -def _common_on_interaction_outcome(original, self, *_, **__) -> Any: - try: - CommonInteractionEventDispatcherService()._on_interaction_outcome(self, *_, **__) - except Exception as ex: - CommonExceptionHandler.log_exception( - ModInfo.get_identity(), - 'Error occurred while running _on_interaction_outcome for interaction {} with short name \'{}\' and display name {}. Args: {}, Kwargs: {}'.format( - pformat(self), - CommonInteractionUtils.get_interaction_short_name(self), - CommonInteractionUtils.get_interaction_display_name(self), - _, - __ - ), - exception=ex - ) - - try: - return original(self, *_, **__) - except Exception as ex: - CommonExceptionHandler.log_exception( - None, - 'Error occurred while running _on_interaction_outcome for interaction {} with short name \'{}\' and display name {}. (This exception is not caused by S4CL, but rather caught) Args: {}, Kwargs: {}'.format( - pformat(self), - CommonInteractionUtils.get_interaction_short_name(self), - CommonInteractionUtils.get_interaction_display_name(self), - _, - __ - ), - exception=ex - ) - return False - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), Interaction, Interaction.cancel.__name__) -def _common_on_interaction_cancelled(original, self, *_, **__) -> Any: - try: - CommonInteractionEventDispatcherService()._on_interaction_cancelled(self, *_, **__) - except Exception as ex: - CommonExceptionHandler.log_exception( - ModInfo.get_identity(), - 'Error occurred while running _on_interaction_cancelled for interaction {} with short name \'{}\' and display name {}. Args: {}, Kwargs: {}'.format( - pformat(self), - CommonInteractionUtils.get_interaction_short_name(self), - CommonInteractionUtils.get_interaction_display_name(self), - _, - __ - ), - exception=ex - ) - - try: - return original(self, *_, **__) - except Exception as ex: - CommonExceptionHandler.log_exception( - None, - 'Error occurred while running _on_interaction_cancelled for interaction {} with short name \'{}\' and display name {}. (This exception is not caused by S4CL, but rather caught) Args: {}, Kwargs: {}'.format( - pformat(self), - CommonInteractionUtils.get_interaction_short_name(self), - CommonInteractionUtils.get_interaction_display_name(self), - _, - __ - ), - exception=ex - ) - return False - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), MixerInteraction, MixerInteraction.cancel.__name__) -def _common_on_mixer_interaction_cancelled(original, self, *_, **__) -> Any: - try: - CommonInteractionEventDispatcherService()._on_mixer_interaction_cancelled(self, *_, **__) - except Exception as ex: - CommonExceptionHandler.log_exception( - ModInfo.get_identity(), - 'Error occurred while running _on_mixer_interaction_cancelled for interaction {} with short name \'{}\' and display name {}. Args: {}, Kwargs: {}'.format( - pformat(self), - CommonInteractionUtils.get_interaction_short_name(self), - CommonInteractionUtils.get_interaction_display_name(self), - _, - __ - ), - exception=ex - ) - - try: - return original(self, *_, **__) - except Exception as ex: - CommonExceptionHandler.log_exception( - None, - 'Error occurred while running _on_mixer_interaction_cancelled for interaction {} with short name \'{}\' and display name {}. (This exception is not caused by S4CL, but rather caught) Args: {}, Kwargs: {}'.format( - pformat(self), - CommonInteractionUtils.get_interaction_short_name(self), - CommonInteractionUtils.get_interaction_display_name(self), - _, - __ - ), - exception=ex - ) - return False - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), SuperInteraction, SuperInteraction.cancel.__name__) -def _common_on_super_interaction_cancelled(original, self, *_, **__) -> Any: - try: - CommonInteractionEventDispatcherService()._on_super_interaction_cancelled(self, *_, **__) - except Exception as ex: - CommonExceptionHandler.log_exception( - ModInfo.get_identity(), - 'Error occurred while running _on_super_interaction_cancelled for interaction {} with short name \'{}\' and display name {}. Args: {}, Kwargs: {}'.format( - pformat(self), - CommonInteractionUtils.get_interaction_short_name(self), - CommonInteractionUtils.get_interaction_display_name(self), - _, - __ - ), - exception=ex - ) - - try: - return original(self, *_, **__) - except Exception as ex: - CommonExceptionHandler.log_exception( - None, - 'Error occurred while running _on_super_interaction_cancelled for interaction {} with short name \'{}\' and display name {}. (This exception is not caused by S4CL, but rather caught) Args: {}, Kwargs: {}'.format( - pformat(self), - CommonInteractionUtils.get_interaction_short_name(self), - CommonInteractionUtils.get_interaction_display_name(self), - _, - __ - ), - exception=ex - ) - return None diff --git a/Scripts/s4ap/sims4communitylib/events/interaction/events/__init__.py b/Scripts/s4ap/sims4communitylib/events/interaction/events/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/events/interaction/events/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_cancelled.py b/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_cancelled.py deleted file mode 100644 index 5996a07..0000000 --- a/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_cancelled.py +++ /dev/null @@ -1,102 +0,0 @@ -""" -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 -""" -from typing import Any, Dict -from interactions.base.interaction import Interaction -from interactions.interaction_finisher import FinishingType -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent - - -class S4CLInteractionCancelledEvent(CommonEvent): - """S4CLInteractionCancelledEvent(interaction, finishing_type, cancel_reason, ignore_must_run=False, **kwargs) - - An event that occurs upon an interaction being cancelled. - - .. note:: This event fires BEFORE the interaction is actually cancelled. Like a Pre-Cancel. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name or identity of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity()) - def handle_event(event_data: S4CLInteractionCancelledEvent) -> bool: - # Return True from here to signify the event listener ran successfully. Return False or None here to signify the event listener failed to run successfully. - return True - - :param interaction: The interaction that is being cancelled. - :type interaction: Interaction - :param finishing_type: The finishing type of the interaction. - :type finishing_type: FinishingType - :param cancel_reason_msg: The reason the interaction was cancelled. - :type cancel_reason_msg: str - :param ignore_must_run: If True, interactions flagged as "Must Run" will be ignored. Default is False. - :type ignore_must_run: bool, optional - """ - - def __init__(self, interaction: Interaction, finishing_type: FinishingType, cancel_reason: str, ignore_must_run: bool=False, **kwargs): - self._interaction = interaction - self._finishing_type = finishing_type - self._cancel_reason = cancel_reason - self._ignore_must_run = ignore_must_run - self._kwargs = kwargs - - @property - def interaction(self) -> Interaction: - """The interaction that is being cancelled. - - :return: The interaction that is being cancelled. - :rtype: Interaction - """ - return self._interaction - - @property - def finishing_type(self) -> FinishingType: - """The finishing type of the interaction. - - :return: The finishing type of the interaction. - :rtype: FinishingType - """ - return self._finishing_type - - @property - def cancel_reason(self) -> str: - """The reason the interaction was cancelled. - - :return: The reason the interaction was cancelled. - :rtype: str - """ - return self._cancel_reason - - @property - def ignore_must_run(self) -> bool: - """Whether or not interactions flagged as "Must Run" will be cancelled. - - :return: If True, interactions flagged as "Must Run" will be cancelled. If False, interactions flagged as "Must Run" will not be cancelled. - :rtype: bool - """ - return self._ignore_must_run - - @property - def keyword_arguments(self) -> Dict[str, Any]: - """Keyword arguments sent to the cancelled interaction. - - :return: Keyword arguments sent to the cancelled interaction. - :rtype: Dict[str, Any] - """ - return self._kwargs diff --git a/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_outcome.py b/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_outcome.py deleted file mode 100644 index 2bf3382..0000000 --- a/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_outcome.py +++ /dev/null @@ -1,94 +0,0 @@ -""" -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 -""" -from interactions.base.interaction import Interaction -from interactions.utils.outcome import InteractionOutcome -from interactions.utils.outcome_enums import OutcomeResult -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent - - -class S4CLInteractionOutcomeEvent(CommonEvent): - """S4CLInteractionOutcomeEvent(interaction, outcome, outcome_result) - - An event that occurs after a Sim has performed an interaction. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name or identity of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity()) - def handle_event(event_data: S4CLInteractionOutcomeEvent) -> bool: - # Return True from here to signify the event listener ran successfully. Return False or None here to signify the event listener failed to run. - return True - - :param interaction: The interaction that was performed. - :type interaction: Interaction - :param outcome: The outcome of the interaction that was performed. - :type outcome: InteractionOutcome - :param outcome_result: The result of the interaction that was performed. - :type outcome_result: OutcomeResult - """ - - def __init__(self, interaction: Interaction, outcome: InteractionOutcome, outcome_result: OutcomeResult): - self._interaction = interaction - self._outcome = outcome - self._outcome_result = outcome_result - - @property - def interaction(self) -> Interaction: - """The interaction that was performed. - - :return: The interaction that was performed. - :rtype: Interaction - """ - return self._interaction - - @property - def outcome(self) -> InteractionOutcome: - """The outcome of the interaction that was performed. - - :return: The outcome of the interaction that was performed. - :rtype: InteractionOutcome - """ - return self._outcome - - @property - def outcome_result(self) -> OutcomeResult: - """The result of the interaction that was performed. - - :return: The result of the interaction that was performed. - :rtype: OutcomeResult - """ - return self._outcome_result - - def is_success(self) -> bool: - """Determine if the outcome was a success. - - :return: True, if the interaction was performed successfully. False, if the interaction was not performed successfully. - :rtype: bool - """ - return self.outcome_result == OutcomeResult.SUCCESS - - def is_failure(self) -> bool: - """Determine if the outcome was a failure. - - :return: True, if the interaction was not performed successfully. False, if the interaction was performed successfully. - :rtype: bool - """ - return self.outcome_result == OutcomeResult.FAILURE diff --git a/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_post_queued.py b/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_post_queued.py deleted file mode 100644 index 58ea8eb..0000000 --- a/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_post_queued.py +++ /dev/null @@ -1,80 +0,0 @@ -""" -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 -""" -from interactions.base.interaction import Interaction -from interactions.interaction_queue import InteractionQueue -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent - - -class S4CLInteractionPostQueuedEvent(CommonEvent): - """S4CLInteractionPostQueuedEvent(interaction, interaction_queue, queue_result) - - An event that occurs after a Sim adds an interaction to their interaction queue. - - .. note:: This event fires AFTER the interaction is actually queued. Like a Post-Queue. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name or identity of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity()) - def handle_event(event_data: S4CLInteractionPostQueuedEvent) -> bool: - # Return True here to signify the event listener ran successfully. Return False or None here to signify the event listener failed to run. - return True - - :param interaction: The interaction that was queued. - :type interaction: Interaction - :param interaction_queue: The interaction queue of the Sim. - :type interaction_queue: InteractionQueue - :param queue_result: The result of the interaction being Queued. - :type queue_result: CommonTestResult - """ - - def __init__(self, interaction: Interaction, interaction_queue: InteractionQueue, queue_result: CommonTestResult): - self._interaction = interaction - self._interaction_queue = interaction_queue - self._queue_result = queue_result - - @property - def interaction(self) -> Interaction: - """The interaction that was queued. - - :return: The interaction that was queued. - :rtype: Interaction - """ - return self._interaction - - @property - def interaction_queue(self) -> InteractionQueue: - """The interaction queue of the Sim that queued the interaction. - - :return: The interaction queue of the Sim that queued the interaction. - :rtype: InteractionQueue - """ - return self._interaction_queue - - @property - def queue_result(self) -> CommonTestResult: - """The result of the interaction being Queued. - - :return: The result of the interaction being Queued. - :rtype: CommonTestResult - """ - return self._queue_result diff --git a/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_pre_run.py b/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_pre_run.py deleted file mode 100644 index cb4b165..0000000 --- a/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_pre_run.py +++ /dev/null @@ -1,91 +0,0 @@ -""" -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 -""" -import os -from interactions.base.interaction import Interaction -from interactions.interaction_queue import InteractionQueue -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent - -ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' - -# If on Read The Docs, create fake versions of extended objects to fix the error of inheriting from multiple MockObjects. -if ON_RTD: - # noinspection PyMissingOrEmptyDocstring - class Timeline: - pass - -if not ON_RTD: - from scheduling import Timeline - - -class S4CLInteractionPreRunEvent(CommonEvent): - """S4CLInteractionPreRunEvent(interaction, interaction_queue, timeline) - - An event that occurs upon a Sim running an interaction. - - .. note:: This event fires BEFORE the interaction is actually run. Like a Pre-Run. If False or None is returned from any of the listeners of this event, the interaction will be prevented from running; All subsequent listeners will still receive the event, but their return will be ignored. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name or identity of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity()) - def handle_event(event_data: S4CLInteractionPreRunEvent) -> bool: - # Return True here to allow the interaction to run and to signify the event listener ran successfully. Return False or None here to prevent the interaction from being run or to signify the event listener failed to run. - return True - - :param interaction: The interaction that is being run. - :type interaction: Interaction - :param interaction_queue: The interaction queue of the Sim. - :type interaction_queue: InteractionQueue - :param timeline: The timeline of the interaction. - :type timeline: Timeline - """ - - def __init__(self, interaction: Interaction, interaction_queue: InteractionQueue, timeline: Timeline): - self._interaction = interaction - self._interaction_queue = interaction_queue - self._timeline = timeline - - @property - def interaction(self) -> Interaction: - """The interaction that is being run. - - :return: The interaction that is being run. - :rtype: Interaction - """ - return self._interaction - - @property - def interaction_queue(self) -> InteractionQueue: - """The interaction queue of the Sim that is running the interaction. - - :return: The interaction queue of the Sim that is running the interaction. - :rtype: InteractionQueue - """ - return self._interaction_queue - - @property - def timeline(self) -> Timeline: - """The timeline of the interaction. - - :return: The timeline of the interaction. - :rtype: Timeline - """ - return self._timeline diff --git a/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_queued.py b/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_queued.py deleted file mode 100644 index db84024..0000000 --- a/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_queued.py +++ /dev/null @@ -1,84 +0,0 @@ -""" -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 -""" -from typing import Union - -from interactions.base.interaction import Interaction -from interactions.interaction_queue import InteractionQueue -from sims.sim import Sim -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - - -class S4CLInteractionQueuedEvent(CommonEvent): - """S4CLInteractionQueuedEvent(interaction, interaction_queue) - - An event that occurs upon a Sim adding an interaction to their interaction queue. - - .. note:: This event fires BEFORE the interaction is actually queued. Like a Pre-Queue. If False or None is returned from any of the listeners of this event, the interaction will be prevented from queuing; All subsequent listeners will still receive the event, but their return will be ignored. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name or identity of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity()) - def handle_event(event_data: S4CLInteractionQueuedEvent) -> bool: - # Return True here to allow the interaction to queue and to signify the event listener ran successfully. Return False or None here to prevent the interaction from being queued or to signify the event listener failed to run. - return True - - :param interaction: The interaction that is being queued. - :type interaction: Interaction - :param interaction_queue: The interaction queue of the Sim. - :type interaction_queue: InteractionQueue - """ - - def __init__(self, interaction: Interaction, interaction_queue: InteractionQueue): - self._interaction = interaction - self._interaction_queue = interaction_queue - - @property - def queuing_sim(self) -> Union[Sim, None]: - """The Sim that is putting the interaction into their queue.""" - if self._interaction is None: - return None - return self._interaction.context.sim - - @property - def queuing_sim_info(self) -> Union[SimInfo, None]: - """The SimInfo of the Sim that is putting the interaction into their queue.""" - return CommonSimUtils.get_sim_info(self.queuing_sim) - - @property - def interaction(self) -> Interaction: - """The interaction that is being queued. - - :return: The interaction that was queued. - :rtype: Interaction - """ - return self._interaction - - @property - def interaction_queue(self) -> InteractionQueue: - """The interaction queue of the Sim that is queuing the interaction. - - :return: The interaction queue of the Sim that is queuing the interaction. - :rtype: InteractionQueue - """ - return self._interaction_queue diff --git a/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_run.py b/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_run.py deleted file mode 100644 index b6fff56..0000000 --- a/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_run.py +++ /dev/null @@ -1,79 +0,0 @@ -""" -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 -""" -from interactions.base.interaction import Interaction -from interactions.interaction_queue import InteractionQueue -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent - - -class S4CLInteractionRunEvent(CommonEvent): - """S4CLInteractionRunEvent(interaction, interaction_queue, run_result) - - An event that occurs after a Sim has run an interaction. - - .. note:: This event fires AFTER the interaction is actually run. Like a Post-Run. If False or None is returned from any of the listeners of this event, the interaction will be prevented from running; All subsequent listeners will still receive the event, but their return will be ignored. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name or identity of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity()) - def handle_event(event_data: S4CLInteractionRunEvent) -> bool: - # Return True here to signify the event listener ran successfully. Return False or None here to signify the event listener failed to run. - return True - - :param interaction: The interaction that was run. - :type interaction: Interaction - :param interaction_queue: The interaction queue of the Sim. - :type interaction_queue: InteractionQueue - :param run_result: The result of the interaction being run. - :type run_result: bool - """ - - def __init__(self, interaction: Interaction, interaction_queue: InteractionQueue, run_result: bool): - self._interaction = interaction - self._interaction_queue = interaction_queue - self._run_result = run_result - - @property - def interaction(self) -> Interaction: - """The interaction that was run. - - :return: The interaction that was run. - :rtype: Interaction - """ - return self._interaction - - @property - def interaction_queue(self) -> InteractionQueue: - """The interaction queue of the Sim that ran the interaction. - - :return: The interaction queue of the Sim ran the interaction. - :rtype: InteractionQueue - """ - return self._interaction_queue - - @property - def run_result(self) -> bool: - """The result of the interaction being run. - - :return: True, if the interaction was run successfully. False, if not. - :rtype: bool - """ - return self._run_result diff --git a/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_started.py b/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_started.py deleted file mode 100644 index 77ce0a5..0000000 --- a/Scripts/s4ap/sims4communitylib/events/interaction/events/interaction_started.py +++ /dev/null @@ -1,71 +0,0 @@ -""" -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 -""" -from typing import Any - -from interactions.base.interaction import Interaction -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent - - -class S4CLInteractionStartedEvent(CommonEvent): - """S4CLInteractionStartedEvent(interaction, sim_info, target) - - An event that occurs when a Sim has started an interaction. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name or identity of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity()) - def handle_event(event_data: S4CLInteractionStartedEvent) -> bool: - # Return True here to signify the event listener ran successfully. Return False or None here to signify the event listener failed to run. - return True - - :param interaction: The interaction that was run. - :type interaction: Interaction - :param sim_info: The Sim doing the interaction. - :type sim_info: SimInfo - :param target: The Target of the interaction. - :type target: Any - """ - - def __init__(self, interaction: Interaction, sim_info: SimInfo, target: Any): - self._sim_info = sim_info - self._target = target - self._interaction = interaction - - @property - def interaction(self) -> Interaction: - """The interaction that was run. - - :return: The interaction that was run. - :rtype: Interaction - """ - return self._interaction - - @property - def sim_info(self) -> SimInfo: - """The Sim that started the interaction.""" - return self._sim_info - - @property - def target(self) -> Any: - """The target of the interaction.""" - return self._target diff --git a/Scripts/s4ap/sims4communitylib/events/interaction/events/mixer_interaction_cancelled.py b/Scripts/s4ap/sims4communitylib/events/interaction/events/mixer_interaction_cancelled.py deleted file mode 100644 index d585335..0000000 --- a/Scripts/s4ap/sims4communitylib/events/interaction/events/mixer_interaction_cancelled.py +++ /dev/null @@ -1,90 +0,0 @@ -""" -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 -""" -from typing import Any, Dict -from interactions.base.mixer_interaction import MixerInteraction -from interactions.interaction_finisher import FinishingType -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent - - -class S4CLMixerInteractionCancelledEvent(CommonEvent): - """S4CLMixerInteractionCancelledEvent(interaction, finishing_type, cancel_reason_msg, **kwargs) - - An event that occurs upon a mixer interaction being cancelled. - - .. note:: This event fires BEFORE the mixer interaction is actually cancelled. Like a Pre-Cancel. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name or identity of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity()) - def handle_event(event_data: S4CLMixerInteractionCancelledEvent) -> bool: - # Return True from here to signify the event listener ran successfully. Return False or None here to signify the event listener failed to run successfully. - return True - - :param interaction: The mixer interaction that is being cancelled. - :type interaction: MixerInteraction - :param finishing_type: The finishing type of the interaction. - :type finishing_type: FinishingType - :param cancel_reason_msg: The reason the interaction was cancelled. - :type cancel_reason_msg: str - """ - - def __init__(self, interaction: MixerInteraction, finishing_type: FinishingType, cancel_reason: str, **kwargs): - self._interaction = interaction - self._finishing_type = finishing_type - self._cancel_reason = cancel_reason - self._kwargs = kwargs - - @property - def interaction(self) -> MixerInteraction: - """The mixer interaction that is being cancelled. - - :return: The mixer interaction that is being cancelled. - :rtype: MixerInteraction - """ - return self._interaction - - @property - def finishing_type(self) -> FinishingType: - """The finishing type of the interaction. - - :return: The finishing type of the interaction. - :rtype: FinishingType - """ - return self._finishing_type - - @property - def cancel_reason(self) -> str: - """The reason the interaction was cancelled. - - :return: The reason the interaction was cancelled. - :rtype: str - """ - return self._cancel_reason - - @property - def keyword_arguments(self) -> Dict[str, Any]: - """Keyword arguments sent to the cancelled interaction. - - :return: Keyword arguments sent to the cancelled interaction. - :rtype: Dict[str, Any] - """ - return self._kwargs diff --git a/Scripts/s4ap/sims4communitylib/events/interaction/events/super_interaction_cancelled.py b/Scripts/s4ap/sims4communitylib/events/interaction/events/super_interaction_cancelled.py deleted file mode 100644 index 2228482..0000000 --- a/Scripts/s4ap/sims4communitylib/events/interaction/events/super_interaction_cancelled.py +++ /dev/null @@ -1,90 +0,0 @@ -""" -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 -""" -from typing import Any, Dict -from interactions.base.super_interaction import SuperInteraction -from interactions.interaction_finisher import FinishingType -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent - - -class S4CLSuperInteractionCancelledEvent(CommonEvent): - """S4CLSuperInteractionCancelledEvent(interaction, finishing_type, cancel_reason_msg, **kwargs) - - An event that occurs upon a super interaction being cancelled. - - .. note:: This event fires BEFORE the super interaction is actually cancelled. Like a Pre-Cancel. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name or identity of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity()) - def handle_event(event_data: S4CLSuperInteractionCancelledEvent) -> bool: - # Return True from here to signify the event listener ran successfully. Return False or None here to signify the event listener failed to run successfully. - return True - - :param interaction: The super interaction that is being cancelled. - :type interaction: SuperInteraction - :param finishing_type: The finishing type of the interaction. - :type finishing_type: FinishingType - :param cancel_reason_msg: The reason the interaction was cancelled. - :type cancel_reason_msg: str - """ - - def __init__(self, interaction: SuperInteraction, finishing_type: FinishingType, cancel_reason: str, **kwargs): - self._interaction = interaction - self._finishing_type = finishing_type - self._cancel_reason = cancel_reason - self._kwargs = kwargs - - @property - def interaction(self) -> SuperInteraction: - """The super interaction that is being cancelled. - - :return: The super interaction that is being cancelled. - :rtype: SuperInteraction - """ - return self._interaction - - @property - def finishing_type(self) -> FinishingType: - """The finishing type of the interaction. - - :return: The finishing type of the interaction. - :rtype: FinishingType - """ - return self._finishing_type - - @property - def cancel_reason(self) -> str: - """The reason the interaction was cancelled. - - :return: The reason the interaction was cancelled. - :rtype: str - """ - return self._cancel_reason - - @property - def keyword_arguments(self) -> Dict[str, Any]: - """Keyword arguments sent to the cancelled interaction. - - :return: Keyword arguments sent to the cancelled interaction. - :rtype: Dict[str, Any] - """ - return self._kwargs diff --git a/Scripts/s4ap/sims4communitylib/events/interval/__init__.py b/Scripts/s4ap/sims4communitylib/events/interval/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/events/interval/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/events/interval/common_interval_event_service.py b/Scripts/s4ap/sims4communitylib/events/interval/common_interval_event_service.py deleted file mode 100644 index 200a063..0000000 --- a/Scripts/s4ap/sims4communitylib/events/interval/common_interval_event_service.py +++ /dev/null @@ -1,241 +0,0 @@ -""" -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 -""" -from typing import Callable, Any, List, Union -from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from s4ap.sims4communitylib.events.zone_update.events.zone_update_event import S4CLZoneUpdateEvent -from s4ap.sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.common_service import CommonService - - -class CommonIntervalDispatcher: - """CommonIntervalDispatcher(mod_identifier, milliseconds, listening_func, run_once=False) - - A dispatcher that invokes a callback based on the amount of time passed. - - .. note:: The dispatcher will only keep track of the amount of time passed while the game was not paused.\ - It will never dispatch while the game is paused. - - :param mod_identifier: The name or identity of the mod the dispatcher belongs to. - :type mod_identifier: Union[str, CommonModIdentity] - :param milliseconds: The number of milliseconds that need to pass before `listening_func` will be invoked. - :type milliseconds: int - :param listening_func: A callback invoked after an amount of time has passed. - :type listening_func: Callable[..., Any] - :param run_once: If set to True, the dispatcher will only invoke `listening_func` once before it stops listening.\ - If set to False, the dispatcher will invoke `listening_func` every time the specified number of milliseconds has passed. - :type run_once: bool - """ - def __init__(self, mod_identifier: Union[str, CommonModIdentity], milliseconds: int, listening_func: Callable[..., Any], run_once: bool=False): - from s4ap.sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils - self._mod_name = CommonModIdentityUtils.determine_mod_name_from_identifier(mod_identifier) - self._minimum_milliseconds_to_dispatch = milliseconds - self._listening_func = listening_func - self.total_milliseconds_passed = 0.0 - self._run_once = run_once - - @property - def total_milliseconds_passed(self) -> float: - """The amount of time in milliseconds that has passed since the dispatcher started keeping track. - - :return: The amount of time in milliseconds that has passed since the dispatcher started keeping track. - :rtype: float - """ - return self._total_milliseconds_passed - - @total_milliseconds_passed.setter - def total_milliseconds_passed(self, milliseconds: float): - self._total_milliseconds_passed = milliseconds - - @property - def minimum_milliseconds_to_dispatch(self) -> int: - """The minimum amount of time in milliseconds that must pass before `listening_func` will be run. - - :return: The minimum amount of time in milliseconds that must pass before `listening_func` will be run. - :rtype: int - """ - return self._minimum_milliseconds_to_dispatch - - @minimum_milliseconds_to_dispatch.setter - def minimum_milliseconds_to_dispatch(self, val: int): - self._minimum_milliseconds_to_dispatch = val - - @property - def mod_name(self) -> str: - """The name of the mod the dispatcher belongs to. - - :return: The name of the mod the dispatcher belongs to. - :rtype: str - """ - return self._mod_name - - @property - def listening_func_name(self) -> str: - """The name of the function waiting for invocation. - - :return: The name of the function waiting for invocation. - :rtype: str - """ - return self._listening_func.__name__ - - @property - def run_once(self) -> bool: - """Determine if the dispatch will run only once. - - :return: True, if the dispatcher will only run once. False, if the dispatcher runs more than once. - :rtype: bool - """ - return self._run_once - - def try_dispatch(self, milliseconds_since_last_update: int) -> bool: - """Attempt to run the dispatcher. - - :param milliseconds_since_last_update: The amount of time in milliseconds that has passed since the last update. - :type milliseconds_since_last_update: int - :return: True, if the event was run. False, if the event was not run or not enough time has passed. - :rtype: bool - """ - self.total_milliseconds_passed += milliseconds_since_last_update - if self.total_milliseconds_passed < self.minimum_milliseconds_to_dispatch: - return False - self.total_milliseconds_passed = max(0.0, self.total_milliseconds_passed - self.minimum_milliseconds_to_dispatch) - self._listening_func() - return True - - -class CommonIntervalEventRegistry(CommonService): - """A registry that will run functions based on an amount of time. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - # This is an example showing how you may register your functions to run on intervals. - class ExampleIntervalListener: - # This function will run only once, after 200 milliseconds have passed. It will then stop listening. - @staticmethod - @CommonIntervalEventRegistry.run_once(ModInfo.get_identity().name, milliseconds=200) - def _example_run_once(): - pass - - # This function will run every 500 milliseconds. It will continue listening until the game is closed or until it is manually unregistered. - @staticmethod - @CommonIntervalEventRegistry.run_every(ModInfo.get_identity().name, milliseconds=500) - def _example_run_every(): - pass - - """ - - def __init__(self) -> None: - self._registered_interval_trackers: List[CommonIntervalDispatcher] = [] - - @staticmethod - def run_every(mod_identifier: Union[str, CommonModIdentity], milliseconds: int=1500) -> Callable[..., Callable[..., Any]]: - """run_every(mod_identifier, milliseconds=1500) - - Register a function to run in intervals of the specified time. - - .. note:: The function will run in intervals every time the amount of time has occurred. - - :param mod_identifier: The name or identity of the mod registering the listener. - :type mod_identifier: Union[str, CommonModIdentity] - :param milliseconds: The amount of time in milliseconds that must pass before the decorated function will be run. - :type milliseconds: int - :return: A callable function wrapped that runs in intervals. - :rtype: Callable[..., Callable[..., Any]] - """ - def _wrapper(listening_func) -> Callable[..., Any]: - CommonIntervalEventRegistry.get()._add_tracker(mod_identifier, milliseconds, listening_func) - return listening_func - return _wrapper - - @staticmethod - def run_once(mod_identifier: Union[str, CommonModIdentity], milliseconds: int=1500) -> Callable[..., Callable[..., Any]]: - """run_once(mod_identifier, milliseconds=1500) - - Register a function to run a single time after a certain amount of time. - - .. note:: A function decorated with this decorator will only run once. - - :param mod_identifier: The name or identity of the mod registering the listener. - :type mod_identifier: Union[str, CommonModIdentity] - :param milliseconds: The amount of time in milliseconds that must pass before the decorated function will be run. - :type milliseconds: int - :return: A callable function wrapped to run once. - :rtype: Callable[..., Callable[..., Any]] - """ - - def _wrapper(listening_func) -> Any: - CommonIntervalEventRegistry.get()._add_tracker(mod_identifier, milliseconds, listening_func, run_once=True) - return listening_func - return _wrapper - - def register_dispatcher(self, mod_identity: CommonModIdentity, milliseconds: int, listening_func: Callable[..., Any], run_once: bool=False) -> Union[CommonIntervalDispatcher, None]: - """register_dispatcher(mod_identity, milliseconds, listening_func, run_once=False) - - Manually register a new dispatcher to the registry. - - :param mod_identity: The identity of the mod that owns the interval dispatcher. - :type mod_identity: CommonModIdentity - :param milliseconds: How much time before the dispatcher runs the first time as well as how much time before it runs again. - :type milliseconds: int - :param listening_func: The function to invoke after the set amount of time. - :type listening_func: Callable[..., Any] - :param run_once: If True, the dispatcher will run a single time, then be removed from the registry. If False, the dispatcher will continue running after the specified milliseconds and will repeat. Default is False. - :type run_once: bool, optional - :return: A dispatcher that will trigger after a set amount of time or None if an error occurs while registering a dispatcher. - :rtype: Union[CommonIntervalDispatcher, None] - """ - if milliseconds <= 0: - CommonExceptionHandler.log_exception(mod_identity, 'Failed to registry an interval dispatcher. The specified milliseconds must be above zero.') - return None - return self._add_tracker(mod_identity, milliseconds, listening_func, run_once=run_once) - - def _add_tracker(self, mod_identifier: Union[str, CommonModIdentity], milliseconds: int, listening_func: Callable[..., Any], run_once: bool=False) -> CommonIntervalDispatcher: - dispatcher = CommonIntervalDispatcher(mod_identifier, milliseconds, listening_func, run_once=run_once) - self._registered_interval_trackers.append(dispatcher) - return dispatcher - - def _attempt_to_dispatch(self, milliseconds_since_last_update: int): - interval_trackers = list(self._registered_interval_trackers) - for interval_tracker in interval_trackers: - try: - interval_tracker.try_dispatch(milliseconds_since_last_update) - except Exception as ex: - CommonExceptionHandler.log_exception(interval_tracker.mod_name, 'Error occurred when attempting to dispatch listener \'{}\''.format(interval_tracker.listening_func_name), exception=ex) - try: - if interval_tracker.run_once: - self._registered_interval_trackers.remove(interval_tracker) - except Exception as ex: - CommonExceptionHandler.log_exception(interval_tracker.mod_name, 'Error occurred when attempting to unregister listener \'{}\''.format(interval_tracker.listening_func_name), exception=ex) - - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity()) - def _update_game_tick_on_zone_update(event_data: S4CLZoneUpdateEvent) -> bool: - from s4ap.sims4communitylib.events.zone_spin.common_zone_spin_event_dispatcher import CommonZoneSpinEventDispatcher - if event_data.is_paused or CommonZoneSpinEventDispatcher().game_loading: - return False - CommonIntervalEventRegistry.get()._attempt_to_dispatch(event_data.ticks_since_last_update) - return True - - -# noinspection PyMissingOrEmptyDocstring -class ExampleIntervalListener: - # This function will run once after 200 milliseconds have passed. Then it stops listening. - @staticmethod - # @CommonIntervalEventRegistry.run_once(ModInfo.get_identity().name, milliseconds=200) - def _example_run_once() -> None: - pass - - # This function will run every 500 milliseconds. It will continue listening until the game is closed or until it is manually unregistered. - @staticmethod - # @CommonIntervalEventRegistry.run_every(ModInfo.get_identity().name, milliseconds=500) - def _example_run_every() -> None: - pass diff --git a/Scripts/s4ap/sims4communitylib/events/save/__init__.py b/Scripts/s4ap/sims4communitylib/events/save/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/events/save/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/events/save/common_save_event_dispatcher.py b/Scripts/s4ap/sims4communitylib/events/save/common_save_event_dispatcher.py deleted file mode 100644 index 121643f..0000000 --- a/Scripts/s4ap/sims4communitylib/events/save/common_save_event_dispatcher.py +++ /dev/null @@ -1,66 +0,0 @@ -""" -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 -""" -import os - -from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from s4ap.sims4communitylib.events.save.events.save_loaded import S4CLSaveLoadedEvent -from s4ap.sims4communitylib.events.save.events.save_saved import S4CLSaveSavedEvent -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.common_service import CommonService -from s4ap.sims4communitylib.utils.common_injection_utils import CommonInjectionUtils - -ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' - -if ON_RTD: - # noinspection PyMissingOrEmptyDocstring - class SaveGameData: - pass - -if not ON_RTD: - from services.persistence_service import SaveGameData - - -class CommonSaveEventDispatcher(CommonService): - """A service that dispatches save file save/load events. - - .. warning:: Do not use this service directly to listen for events!\ - Use the :class:`.CommonEventRegistry` to listen for dispatched events. - - """ - def __init__(self) -> None: - self._current_save_slot_guid = None - - def _on_game_save(self, save_game_data: SaveGameData): - CommonEventRegistry.get().dispatch(S4CLSaveSavedEvent(save_game_data)) - - def _on_save_loaded(self) -> None: - from s4ap.sims4communitylib.utils.save_load.common_save_utils import CommonSaveUtils - current_save_slot_guid = CommonSaveUtils().get_save_slot_guid() - if self._current_save_slot_guid is None: - self._current_save_slot_guid = current_save_slot_guid - CommonEventRegistry.get().dispatch(S4CLSaveLoadedEvent()) - elif self._current_save_slot_guid != current_save_slot_guid: - self._current_save_slot_guid = current_save_slot_guid - CommonEventRegistry.get().dispatch(S4CLSaveLoadedEvent()) - - -if not ON_RTD: - from game_services import GameServiceManager - from services.persistence_service import PersistenceService, SaveGameData - - @CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), PersistenceService, PersistenceService.save_game_gen.__name__, handle_exceptions=False) - def _common_save_game_gen(original, self: PersistenceService, timeline, save_game_data: SaveGameData, send_save_message: bool=True, **kwargs): - if send_save_message: - CommonSaveEventDispatcher.get()._on_game_save(save_game_data) - return original(self, timeline, save_game_data, send_save_message=send_save_message, **kwargs) - - @CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), GameServiceManager, GameServiceManager.on_all_households_and_sim_infos_loaded.__name__, handle_exceptions=False) - def _common_save_game_loaded(original, self: GameServiceManager, *args, **kwargs): - result = original(self, *args, **kwargs) - CommonSaveEventDispatcher()._on_save_loaded() - return result diff --git a/Scripts/s4ap/sims4communitylib/events/save/events/__init__.py b/Scripts/s4ap/sims4communitylib/events/save/events/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/events/save/events/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/events/save/events/save_loaded.py b/Scripts/s4ap/sims4communitylib/events/save/events/save_loaded.py deleted file mode 100644 index 5ed0b9b..0000000 --- a/Scripts/s4ap/sims4communitylib/events/save/events/save_loaded.py +++ /dev/null @@ -1,37 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent - - -class S4CLSaveLoadedEvent(CommonEvent): - """S4CLSaveLoadedEvent(save_slot_data) - - An event that occurs upon a Save being loaded (After it has been loaded). - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity().name) - def handle_event(event_data: S4CLSaveLoadedEvent): - pass - - """ - pass diff --git a/Scripts/s4ap/sims4communitylib/events/save/events/save_saved.py b/Scripts/s4ap/sims4communitylib/events/save/events/save_saved.py deleted file mode 100644 index f2ba969..0000000 --- a/Scripts/s4ap/sims4communitylib/events/save/events/save_saved.py +++ /dev/null @@ -1,61 +0,0 @@ -""" -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 -""" -from typing import Any - -from services.persistence_service import SaveGameData -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent - - -class S4CLSaveSavedEvent(CommonEvent): - """S4CLSaveSavedEvent(save_slot_data) - - An event that occurs upon a Save being saved (Before it has been saved). - - .. note:: This event will only occur when the Player manually saves the game. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity().name) - def handle_event(event_data: S4CLSaveSavedEvent): - pass - - :param save_game_data: The data that will be saved. - :type save_game_data: SaveGameData - """ - - def __init__(self, save_game_data: SaveGameData): - self._save_game_data = save_game_data - - @property - def save_game_data(self) -> Any: - """The game data that will be saved.""" - return self._save_game_data - - @property - def save_slot_name(self) -> str: - """The name of the save slot.""" - return self.save_game_data.slot_name - - @property - def save_slot_id(self) -> int: - """The id of the save slot.""" - return self.save_game_data.slot_id diff --git a/Scripts/s4ap/sims4communitylib/events/sim/__init__.py b/Scripts/s4ap/sims4communitylib/events/sim/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/events/sim/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/events/sim/common_sim_event_dispatcher.py b/Scripts/s4ap/sims4communitylib/events/sim/common_sim_event_dispatcher.py deleted file mode 100644 index cf321cf..0000000 --- a/Scripts/s4ap/sims4communitylib/events/sim/common_sim_event_dispatcher.py +++ /dev/null @@ -1,385 +0,0 @@ -""" -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 -""" -from typing import Any, Tuple, Union - -from buffs.buff import Buff -from interactions.utils.death import DeathTracker, DeathType -from objects.components.buff_component import BuffComponent -from objects.game_object import GameObject -from objects.script_object import ScriptObject -from relationships.relationship_objects.relationship import Relationship -from relationships.relationship_bit import RelationshipBit -from relationships.data.relationship_data import RelationshipData -from sims.aging.aging_mixin import AgingMixin -from sims.occult.occult_enums import OccultType -from sims.occult.occult_tracker import OccultTracker -from sims.outfits.outfit_enums import OutfitCategory -from sims.sim import Sim -from sims.sim_info import SimInfo -from sims.sim_info_types import Age -from sims.sim_spawner import SimSpawner -from s4ap.sims4communitylib.enums.common_age import CommonAge -from s4ap.sims4communitylib.enums.common_death_types import CommonDeathType -from s4ap.sims4communitylib.enums.common_gender import CommonGender -from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from s4ap.sims4communitylib.events.sim.events.sim_added_occult_type import S4CLSimAddedOccultTypeEvent -from s4ap.sims4communitylib.events.sim.events.sim_after_set_current_outfit import S4CLSimAfterSetCurrentOutfitEvent -from s4ap.sims4communitylib.events.sim.events.sim_buff_added import S4CLSimBuffAddedEvent -from s4ap.sims4communitylib.events.sim.events.sim_buff_removed import S4CLSimBuffRemovedEvent -from s4ap.sims4communitylib.events.sim.events.sim_changed_age import S4CLSimChangedAgeEvent -from s4ap.sims4communitylib.events.sim.events.sim_changed_gender_options_body_frame import S4CLSimChangedGenderOptionsBodyFrameEvent -from s4ap.sims4communitylib.events.sim.events.sim_changed_gender_options_breasts import \ - S4CLSimChangedGenderOptionsBreastsEvent -from s4ap.sims4communitylib.events.sim.events.sim_changed_gender_options_can_impregnate import \ - S4CLSimChangedGenderOptionsCanImpregnateEvent -from s4ap.sims4communitylib.events.sim.events.sim_changed_gender_options_can_reproduce import \ - S4CLSimChangedGenderOptionsCanReproduceEvent -from s4ap.sims4communitylib.events.sim.events.sim_changed_gender_options_clothing_preference import S4CLSimChangedGenderOptionsClothingPreferenceEvent -from s4ap.sims4communitylib.events.sim.events.sim_changed_gender import S4CLSimChangedGenderEvent -from s4ap.sims4communitylib.events.sim.events.sim_changed_occult_type import S4CLSimChangedOccultTypeEvent -from s4ap.sims4communitylib.events.sim.events.sim_changed_gender_options_can_be_impregnated import S4CLSimChangedGenderOptionsCanBeImpregnatedEvent -from s4ap.sims4communitylib.events.sim.events.sim_changed_gender_options_toilet_usage import S4CLSimChangedGenderOptionsToiletUsageEvent -from s4ap.sims4communitylib.events.sim.events.sim_changing_occult_type import S4CLSimChangingOccultTypeEvent -from s4ap.sims4communitylib.events.sim.events.sim_died import S4CLSimDiedEvent -from s4ap.sims4communitylib.events.sim.events.sim_pre_despawned import S4CLSimPreDespawnedEvent -from s4ap.sims4communitylib.events.sim.events.sim_initialized import S4CLSimInitializedEvent -from s4ap.sims4communitylib.events.sim.events.sim_loaded import S4CLSimLoadedEvent -from s4ap.sims4communitylib.events.sim.events.game_object_added_to_sim_inventory import S4CLGameObjectAddedToSimInventoryEvent -from s4ap.sims4communitylib.events.sim.events.game_object_pre_removed_from_sim_inventory import S4CLGameObjectPreRemovedFromSimInventoryEvent -from s4ap.sims4communitylib.events.sim.events.sim_relationship_bit_added import S4CLSimRelationshipBitAddedEvent -from s4ap.sims4communitylib.events.sim.events.sim_relationship_bit_removed import S4CLSimRelationshipBitRemovedEvent -from s4ap.sims4communitylib.events.sim.events.sim_removed_occult_type import S4CLSimRemovedOccultTypeEvent -from s4ap.sims4communitylib.events.sim.events.sim_revived import S4CLSimRevivedEvent -from s4ap.sims4communitylib.events.sim.events.sim_set_current_outfit import S4CLSimSetCurrentOutfitEvent -from s4ap.sims4communitylib.events.sim.events.sim_skill_leveled_up import S4CLSimSkillLeveledUpEvent -from s4ap.sims4communitylib.events.sim.events.sim_spawned import S4CLSimSpawnedEvent -from s4ap.sims4communitylib.events.sim.events.sim_trait_added import S4CLSimTraitAddedEvent -from s4ap.sims4communitylib.events.sim.events.sim_trait_removed import S4CLSimTraitRemovedEvent -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.common_service import CommonService -from s4ap.sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils -from s4ap.sims4communitylib.utils.common_injection_utils import CommonInjectionUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from statistics.skill import Skill -from traits.trait_tracker import TraitTracker -from traits.traits import Trait - - -class CommonSimEventDispatcherService(CommonService): - """A service that dispatches Sim events (Init, Spawn, Add Occult, Remove Occult, Change Gender, etc.). - - .. warning:: Do not use this service directly to listen for events!\ - Use the :class:`.CommonEventRegistry` to listen for dispatched events. - - """ - - def _on_sim_change_gender(self, sim_info: SimInfo) -> bool: - from s4ap.sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils - new_gender = CommonGender.get_gender(sim_info) - if CommonGenderUtils.is_male_gender(new_gender): - # If they are now Male, it means they used to be Female. - old_gender = CommonGender.FEMALE - else: - # If they are now Female, it means they used to be Male. - old_gender = CommonGender.MALE - return CommonEventRegistry.get().dispatch(S4CLSimChangedGenderEvent(sim_info, old_gender, new_gender)) - - def _on_sim_change_gender_options_breasts(self, sim_info: SimInfo) -> bool: - return CommonEventRegistry.get().dispatch(S4CLSimChangedGenderOptionsBreastsEvent(sim_info)) - - def _on_sim_change_gender_options_toilet_usage(self, sim_info: SimInfo) -> bool: - return CommonEventRegistry.get().dispatch(S4CLSimChangedGenderOptionsToiletUsageEvent(sim_info)) - - def _on_sim_change_gender_options_body_frame(self, sim_info: SimInfo) -> bool: - return CommonEventRegistry.get().dispatch(S4CLSimChangedGenderOptionsBodyFrameEvent(sim_info)) - - def _on_sim_change_gender_options_clothing_preference(self, sim_info: SimInfo) -> bool: - return CommonEventRegistry.get().dispatch(S4CLSimChangedGenderOptionsClothingPreferenceEvent(sim_info)) - - def _on_sim_change_gender_options_can_impregnate(self, sim_info: SimInfo) -> bool: - return CommonEventRegistry.get().dispatch(S4CLSimChangedGenderOptionsCanImpregnateEvent(sim_info)) - - def _on_sim_change_gender_options_can_be_impregnated(self, sim_info: SimInfo) -> bool: - return CommonEventRegistry.get().dispatch(S4CLSimChangedGenderOptionsCanBeImpregnatedEvent(sim_info)) - - def _on_sim_change_gender_options_can_reproduce(self, sim_info: SimInfo) -> bool: - return CommonEventRegistry.get().dispatch(S4CLSimChangedGenderOptionsCanReproduceEvent(sim_info)) - - def _on_sim_init(self, sim_info: SimInfo, *_, **__) -> bool: - return CommonEventRegistry.get().dispatch(S4CLSimInitializedEvent(sim_info)) - - def _on_sim_load(self, sim_info: SimInfo, *_, **__) -> bool: - from s4ap.sims4communitylib.events.zone_spin.common_zone_spin_event_dispatcher import CommonZoneSpinEventDispatcher - if CommonZoneSpinEventDispatcher.get().game_loading: - return False - return CommonEventRegistry.get().dispatch(S4CLSimLoadedEvent(sim_info)) - - def _on_sim_spawned(self, sim_info: SimInfo, *_, **__) -> bool: - from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - return CommonEventRegistry.get().dispatch(S4CLSimSpawnedEvent(CommonSimUtils.get_sim_info(sim_info))) - - def _on_sim_died(self, sim_info: SimInfo, death_type: CommonDeathType, is_off_lot_death: bool, *_, **__) -> bool: - return CommonEventRegistry.get().dispatch(S4CLSimDiedEvent(sim_info, death_type, is_off_lot_death)) - - def _on_sim_revived(self, sim_info: SimInfo, previous_death_type: CommonDeathType, *_, **__) -> bool: - return CommonEventRegistry.get().dispatch(S4CLSimRevivedEvent(sim_info, previous_death_type)) - - def _pre_sim_despawned(self, sim_info: SimInfo, *_, **__) -> bool: - return CommonEventRegistry.get().dispatch(S4CLSimPreDespawnedEvent(sim_info)) - - def _on_sim_change_age(self, sim_info: SimInfo, new_age: Age, current_age: Age) -> bool: - from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - return CommonEventRegistry.get().dispatch(S4CLSimChangedAgeEvent(CommonSimUtils.get_sim_info(sim_info), CommonAge.convert_from_vanilla(current_age), CommonAge.convert_from_vanilla(new_age))) - - def _on_sim_add_occult_type(self, occult_tracker: OccultTracker, occult_type: OccultType) -> bool: - sim_info = occult_tracker._sim_info - return CommonEventRegistry.get().dispatch(S4CLSimAddedOccultTypeEvent(sim_info, occult_type, occult_tracker)) - - def _on_sim_changing_occult_type(self, occult_tracker: OccultTracker, occult_type: OccultType, *_, **__) -> bool: - sim_info = occult_tracker._sim_info - return CommonEventRegistry.get().dispatch(S4CLSimChangingOccultTypeEvent(sim_info, occult_type, occult_tracker)) - - def _on_sim_changed_occult_type(self, occult_tracker: OccultTracker, occult_type: OccultType, *_, **__) -> bool: - sim_info = occult_tracker._sim_info - return CommonEventRegistry.get().dispatch(S4CLSimChangedOccultTypeEvent(sim_info, occult_type, occult_tracker)) - - def _on_sim_remove_occult_type(self, occult_tracker: OccultTracker, occult_type: OccultType) -> bool: - sim_info = occult_tracker._sim_info - return CommonEventRegistry.get().dispatch(S4CLSimRemovedOccultTypeEvent(sim_info, occult_type, occult_tracker)) - - def _on_sim_trait_added(self, trait_tracker: TraitTracker, trait: Trait, *_, **__) -> None: - sim_info = trait_tracker.get_sim_info_from_provider() - if sim_info is None: - return - CommonEventRegistry.get().dispatch(S4CLSimTraitAddedEvent(sim_info, trait, trait_tracker)) - - def _on_sim_trait_removed(self, trait_tracker: TraitTracker, trait: Trait, *_, **__) -> None: - sim_info = trait_tracker.get_sim_info_from_provider() - if sim_info is None: - return - CommonEventRegistry.get().dispatch(S4CLSimTraitRemovedEvent(sim_info, trait, trait_tracker)) - - def _on_sim_buff_added(self, buff: Buff, sim_id: int) -> None: - sim_info = CommonSimUtils.get_sim_info(sim_id) - if sim_info is None: - return - CommonEventRegistry.get().dispatch(S4CLSimBuffAddedEvent(sim_info, buff)) - - def _on_sim_buff_removed(self, buff: Buff, sim_id: int) -> None: - sim_info = CommonSimUtils.get_sim_info(sim_id) - if sim_info is None: - return - CommonEventRegistry.get().dispatch(S4CLSimBuffRemovedEvent(sim_info, buff)) - - def _on_sim_set_current_outfit(self, sim_info: SimInfo, outfit_category_and_index: Tuple[OutfitCategory, int]) -> None: - from s4ap.sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils - CommonEventRegistry.get().dispatch(S4CLSimSetCurrentOutfitEvent(sim_info, CommonOutfitUtils.get_current_outfit(sim_info), outfit_category_and_index)) - - def _after_sim_set_current_outfit(self, sim_info: SimInfo, previous_outfit_category_and_index: Tuple[OutfitCategory, int], outfit_category_and_index: Tuple[OutfitCategory, int]) -> None: - CommonEventRegistry.get().dispatch(S4CLSimAfterSetCurrentOutfitEvent(sim_info, previous_outfit_category_and_index, outfit_category_and_index)) - - def _on_skill_leveled_up(self, skill: Skill, old_skill_level: int, new_skill_level: int) -> None: - if skill.tracker is None or skill.tracker._owner is None: - return - sim_info = CommonSimUtils.get_sim_info(skill.tracker._owner) - CommonEventRegistry.get().dispatch(S4CLSimSkillLeveledUpEvent(sim_info, skill, old_skill_level, new_skill_level)) - - def _on_object_added_to_sim_inventory(self, sim: Sim, added_game_object: GameObject) -> None: - sim_info = CommonSimUtils.get_sim_info(sim) - if sim_info is None: - return - CommonEventRegistry.get().dispatch(S4CLGameObjectAddedToSimInventoryEvent(sim_info, added_game_object)) - - def _on_object_removed_from_sim_inventory(self, sim: Sim, removed_game_object: GameObject) -> None: - sim_info = CommonSimUtils.get_sim_info(sim) - if sim_info is None: - return - CommonEventRegistry.get().dispatch(S4CLGameObjectPreRemovedFromSimInventoryEvent(sim_info, removed_game_object)) - - def _on_relationship_bit_added(self, sim_id_a: int, sim_id_b: int, relationship_bit: RelationshipBit) -> None: - sim_info_a = CommonSimUtils.get_sim_info(sim_id_a) - if sim_info_a is None: - return - sim_info_b = CommonSimUtils.get_sim_info(sim_id_b) - if sim_info_b is None: - return - CommonEventRegistry.get().dispatch(S4CLSimRelationshipBitAddedEvent(sim_info_a, sim_info_b, relationship_bit)) - - def _on_relationship_bit_removed(self, sim_id_a: int, sim_id_b: int, relationship_bit: RelationshipBit) -> None: - sim_info_a = CommonSimUtils.get_sim_info(sim_id_a) - if sim_info_a is None: - return - sim_info_b = CommonSimUtils.get_sim_info(sim_id_b) - if sim_info_b is None: - return - CommonEventRegistry.get().dispatch(S4CLSimRelationshipBitRemovedEvent(sim_info_a, sim_info_b, relationship_bit)) - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), SimInfo, SimInfo.__init__.__name__, handle_exceptions=False) -def _common_on_sim_init(original, self, *args, **kwargs) -> Any: - result = original(self, *args, **kwargs) - CommonSimEventDispatcherService.get()._on_sim_init(self, *args, **kwargs) - return result - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), SimInfo, SimInfo.load_sim_info.__name__, handle_exceptions=False) -def _common_on_sim_load(original, self, *args, **kwargs) -> Any: - result = original(self, *args, **kwargs) - CommonSimEventDispatcherService.get()._on_sim_load(self, *args, **kwargs) - return result - - -# noinspection PyUnusedLocal -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), SimSpawner, SimSpawner.spawn_sim.__name__, handle_exceptions=False) -def _common_on_sim_spawn(original, cls, *args, **kwargs) -> Any: - result = original(*args, **kwargs) - if result: - CommonSimEventDispatcherService.get()._on_sim_spawned(*args, **kwargs) - return result - - -# noinspection PyUnusedLocal -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), Sim, Sim.destroy.__name__, handle_exceptions=False) -def _common_on_sim_despawn(original, self, *args, **kwargs) -> Any: - CommonSimEventDispatcherService.get()._pre_sim_despawned(CommonSimUtils.get_sim_info(self), *args, **kwargs) - return original(self, *args, **kwargs) - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), DeathTracker, DeathTracker.set_death_type.__name__) -def _common_on_sim_set_death_type(original, self, death_type: Union[DeathType, None], is_off_lot_death: bool = False, *_, **__) -> Any: - previous_death_type = self._death_type - original_result = original(self, death_type, is_off_lot_death=is_off_lot_death, *_, **__) - if death_type is None and previous_death_type is None: - return original_result - - sim_info = CommonSimUtils.get_sim_info(self._sim_info) - if death_type is None: - CommonSimEventDispatcherService.get()._on_sim_revived(sim_info, CommonDeathType.convert_from_vanilla(previous_death_type)) - else: - if previous_death_type is None: - CommonSimEventDispatcherService.get()._on_sim_died(sim_info, CommonDeathType.convert_from_vanilla(death_type), is_off_lot_death) - return original_result - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), DeathTracker, DeathTracker.clear_death_type.__name__) -def _common_on_sim_clear_death_type(original, self, *_, **__) -> Any: - previous_death_type = self._death_type - original_result = original(self, *_, **__) - if previous_death_type is None: - return original_result - sim_info = CommonSimUtils.get_sim_info(self._sim_info) - CommonSimEventDispatcherService.get()._on_sim_revived(sim_info, CommonDeathType.convert_from_vanilla(previous_death_type)) - return original_result - - -# noinspection PyUnusedLocal -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), Skill, Skill.on_skill_level_up.__name__, handle_exceptions=False) -def _common_on_sim_skill_level_up(original, self, *args, **kwargs) -> Any: - result = original(self, *args, **kwargs) - if result: - CommonSimEventDispatcherService.get()._on_skill_leveled_up(self, *args, **kwargs) - return result - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), AgingMixin, AgingMixin.change_age.__name__, handle_exceptions=False) -def _common_on_sim_change_age(original, self, *args, **kwargs) -> Any: - result = original(self, *args, **kwargs) - CommonSimEventDispatcherService.get()._on_sim_change_age(self, *args, **kwargs) - return result - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), OccultTracker, OccultTracker.add_occult_type.__name__, handle_exceptions=False) -def _common_on_sim_add_occult_type(original, self, *args, **kwargs) -> Any: - result = original(self, *args, **kwargs) - CommonSimEventDispatcherService.get()._on_sim_add_occult_type(self, *args, **kwargs) - return result - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), OccultTracker, OccultTracker.switch_to_occult_type.__name__, handle_exceptions=False) -def _common_on_sim_change_occult_type(original, self, *args, **kwargs) -> Any: - CommonSimEventDispatcherService.get()._on_sim_changing_occult_type(self, *args, **kwargs) - result = original(self, *args, **kwargs) - CommonSimEventDispatcherService.get()._on_sim_changed_occult_type(self, *args, **kwargs) - return result - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), OccultTracker, OccultTracker.remove_occult_type.__name__, handle_exceptions=False) -def _common_on_sim_remove_occult_type(original, self, *args, **kwargs) -> Any: - result = original(self, *args, **kwargs) - CommonSimEventDispatcherService.get()._on_sim_remove_occult_type(self, *args, **kwargs) - return result - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), SimInfo, SimInfo.set_current_outfit.__name__, handle_exceptions=False) -def _common_on_sim_set_current_outfit(original, self, *args, **kwargs) -> Any: - old_outfit_category_and_index = CommonOutfitUtils.get_current_outfit(self) - CommonSimEventDispatcherService.get()._on_sim_set_current_outfit(self, *args, **kwargs) - result = original(self, *args, **kwargs) - CommonSimEventDispatcherService.get()._after_sim_set_current_outfit(self, old_outfit_category_and_index, *args, **kwargs) - return result - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), TraitTracker, TraitTracker._add_trait.__name__, handle_exceptions=False) -def _common_on_sim_trait_added(original, self: TraitTracker, *args, **kwargs): - result = original(self, *args, **kwargs) - CommonSimEventDispatcherService.get()._on_sim_trait_added(self, *args, **kwargs) - return result - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), TraitTracker, TraitTracker._remove_trait.__name__, handle_exceptions=False) -def _common_on_sim_trait_removed(original, self: TraitTracker, *args, **kwargs): - result = original(self, *args, **kwargs) - CommonSimEventDispatcherService.get()._on_sim_trait_removed(self, *args, **kwargs) - return result - - -@CommonEventRegistry.handle_events(ModInfo.get_identity()) -def _common_register_buff_added_or_removed_on_sim_spawned(event_data: S4CLSimSpawnedEvent) -> bool: - from s4ap.sims4communitylib.utils.sims.common_buff_utils import CommonBuffUtils - buff_component: BuffComponent = CommonBuffUtils.get_buff_component(event_data.sim_info) - if not buff_component: - return False - - dispatcher_service = CommonSimEventDispatcherService() - if dispatcher_service._on_sim_buff_added not in buff_component.on_buff_added: - buff_component.on_buff_added.append(dispatcher_service._on_sim_buff_added) - - if dispatcher_service._on_sim_buff_removed not in buff_component.on_buff_removed: - buff_component.on_buff_removed.append(dispatcher_service._on_sim_buff_removed) - return True - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), Sim, Sim.on_object_added_to_inventory.__name__, handle_exceptions=False) -def _common_on_object_added_to_sim_inventory(original, self: Sim, obj: ScriptObject, *args, **kwargs): - result = original(self, obj, *args, **kwargs) - if isinstance(obj, GameObject): - CommonSimEventDispatcherService.get()._on_object_added_to_sim_inventory(self, obj) - return result - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), Sim, Sim.on_object_removed_from_inventory.__name__, handle_exceptions=False) -def _common_on_object_removed_from_sim_inventory(original, self: Sim, obj: ScriptObject, *args, **kwargs): - if isinstance(obj, GameObject): - CommonSimEventDispatcherService.get()._on_object_removed_from_sim_inventory(self, obj) - result = original(self, obj, *args, **kwargs) - return result - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), Relationship, Relationship.add_relationship_bit.__name__) -def _common_on_add_relationship_bit(original, self: Relationship, actor_sim_id: int, target_sim_id: int, bit_to_add: RelationshipBit, *_, **__): - result = original(self, actor_sim_id, target_sim_id, bit_to_add, *_, **__) - CommonSimEventDispatcherService()._on_relationship_bit_added(actor_sim_id, target_sim_id, bit_to_add) - return result - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), RelationshipData, RelationshipData.remove_bit.__name__) -def _common_on_remove_relationship_bit(original, self: RelationshipData, bit: RelationshipBit, *_, **__): - result = original(self, bit, *_, **__) - (actor_sim_id, target_sim_id) = self._sim_ids() - CommonSimEventDispatcherService()._on_relationship_bit_removed(actor_sim_id, target_sim_id, bit) - return result diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/__init__.py b/Scripts/s4ap/sims4communitylib/events/sim/events/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/game_object_added_to_sim_inventory.py b/Scripts/s4ap/sims4communitylib/events/sim/events/game_object_added_to_sim_inventory.py deleted file mode 100644 index e47747e..0000000 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/game_object_added_to_sim_inventory.py +++ /dev/null @@ -1,83 +0,0 @@ -""" -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 -""" -from objects.game_object import GameObject -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent -from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils - - -class S4CLGameObjectAddedToSimInventoryEvent(CommonEvent): - """S4CLGameObjectAddedToSimInventoryEvent(sim_info, added_game_object) - - An event that occurs when a Game Object is added to the inventory of a Sim. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity()) - def handle_event(event_data: S4CLGameObjectAddedToSimInventoryEvent): - pass - - :param sim_info: The Sim that changed. - :type sim_info: SimInfo - :param added_game_object: The Game Object that was added to the inventory of the Sim. - :type added_game_object: GameObject - """ - - def __init__(self, sim_info: SimInfo, added_game_object: GameObject): - self._sim_info = sim_info - self._added_game_object = added_game_object - - @property - def sim_info(self) -> SimInfo: - """The Sim that received the added object. - - :return: The Sim that received the added object. - :rtype: SimInfo - """ - return self._sim_info - - @property - def added_game_object(self) -> GameObject: - """The Game Object that was added. - - :return: The Game Object that was added. - :rtype: GameObject - """ - return self._added_game_object - - @property - def added_game_object_id(self) -> int: - """The decimal identifier of the Game Object that was added. - - :return: The decimal identifier of the Game Object that was added. - :rtype: int - """ - return CommonObjectUtils.get_object_id(self.added_game_object) - - @property - def added_object_guid(self) -> int: - """The guid identifier of the Game Object that was added. - - :return: The guid identifier of the Game Object that was added. - :rtype: int - """ - return CommonObjectUtils.get_object_guid(self.added_game_object) diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/game_object_pre_removed_from_sim_inventory.py b/Scripts/s4ap/sims4communitylib/events/sim/events/game_object_pre_removed_from_sim_inventory.py deleted file mode 100644 index 2f1a405..0000000 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/game_object_pre_removed_from_sim_inventory.py +++ /dev/null @@ -1,84 +0,0 @@ -""" -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 -""" -from objects.game_object import GameObject -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent -from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils - - -class S4CLGameObjectPreRemovedFromSimInventoryEvent(CommonEvent): - """S4CLGameObjectPreRemovedFromSimInventoryEvent(sim_info, removed_game_object) - - An event that occurs before a Game Object is removed from the inventory of a Sim. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity()) - def handle_event(event_data: S4CLGameObjectPreRemovedFromSimInventoryEvent): - pass - - :param sim_info: The Sim that changed. - :type sim_info: SimInfo - :param removed_game_object: The Game Object that was removed from the inventory of the Sim. - :type removed_game_object: GameObject - """ - - def __init__(self, sim_info: SimInfo, removed_game_object: GameObject): - self._sim_info = sim_info - self._removed_game_object = removed_game_object - - @property - def sim_info(self) -> SimInfo: - """The Sim that is having the object removed. - - :return: The Sim that is having the object removed. - :rtype: SimInfo - """ - return self._sim_info - - @property - def removed_game_object(self) -> GameObject: - """The Game Object that is being removed. - - :return: The Game Object that is being removed. - :rtype: GameObject - """ - return self._removed_game_object - - @property - def removed_game_object_id(self) -> int: - """The decimal identifier of the Game Object that was removed. - - :return: The decimal identifier of the Game Object that was removed. - :rtype: int - """ - return CommonObjectUtils.get_object_id(self.removed_game_object) - - @property - def removed_game_object_guid(self) -> int: - """The guid identifier of the Game Object that was removed. - - :return: The guid identifier of the Game Object that was removed. - :rtype: int - """ - # noinspection PyTypeChecker - return CommonObjectUtils.get_object_guid(self.removed_game_object) diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_added_occult_type.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_added_occult_type.py deleted file mode 100644 index 0b225b3..0000000 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_added_occult_type.py +++ /dev/null @@ -1,77 +0,0 @@ -""" -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 -""" -from sims.occult.occult_enums import OccultType -from sims.occult.occult_tracker import OccultTracker -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent - - -class S4CLSimAddedOccultTypeEvent(CommonEvent): - """S4CLSimAddedOccultTypeEvent(sim_info, occult_type, occult_tracker) - - An event that occurs when an OccultType has been added to a Sim. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity().name) - def handle_event(event_data: S4CLSimAddedOccultTypeEvent): - pass - - :param sim_info: The Sim the Occult Type was added to. - :type sim_info: SimInfo - :param occult_type: The OccultType that was added. - :type occult_type: OccultType - :param occult_tracker: A tracker that keeps track of the occult status of the Sim. - :type occult_tracker: OccultTracker - """ - - def __init__(self, sim_info: SimInfo, occult_type: OccultType, occult_tracker: OccultTracker): - self._sim_info = sim_info - self._occult_type = occult_type - self._occult_tracker = occult_tracker - - @property - def sim_info(self) -> SimInfo: - """The Sim the OccultType was added to. - - :return: The Sim the OccultType was added to. - :rtype: SimInfo - """ - return self._sim_info - - @property - def occult_type(self) -> OccultType: - """The OccultType that was added. - - :return: The OccultType that was added. - :rtype: OccultType - """ - return self._occult_type - - @property - def occult_tracker(self) -> OccultTracker: - """A tracker that keeps track of the occult status of the Sim. - - :return: A tracker that keeps track of the occult status of the Sim. - :rtype: OccultTracker - """ - return self._occult_tracker diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_after_set_current_outfit.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_after_set_current_outfit.py deleted file mode 100644 index 7f7cf59..0000000 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_after_set_current_outfit.py +++ /dev/null @@ -1,66 +0,0 @@ -""" -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 -""" -from typing import Tuple - -from sims.outfits.outfit_enums import OutfitCategory -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent - - -class S4CLSimAfterSetCurrentOutfitEvent(CommonEvent): - """S4CLSimAfterSetCurrentOutfitEvent(sim_info, old_outfit_category_and_index, new_outfit_category_and_index) - - An event that occurs after the current outfit of a Sim is set. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity().name) - def handle_event(event_data: S4CLSimAfterSetCurrentOutfitEvent): - pass - - :param sim_info: The Sim that changed. - :type sim_info: SimInfo - :param old_outfit_category_and_index: The outfit category and index for the outfit the Sim has changed from. - :type old_outfit_category_and_index: Tuple[OutfitCategory, int] - :param new_outfit_category_and_index: The outfit category and index for the outfit the Sim has changed to. - :type new_outfit_category_and_index: Tuple[OutfitCategory, int] - """ - - def __init__(self, sim_info: SimInfo, old_outfit_category_and_index: Tuple[OutfitCategory, int], new_outfit_category_and_index: Tuple[OutfitCategory, int]): - self._sim_info = sim_info - self._old_outfit_category_and_index = old_outfit_category_and_index - self._new_outfit_category_and_index = new_outfit_category_and_index - - @property - def sim_info(self) -> SimInfo: - """The Sim that changed.""" - return self._sim_info - - @property - def old_outfit_category_and_index(self) -> Tuple[OutfitCategory, int]: - """The outfit category and index for the outfit the Sim has changed from.""" - return self._old_outfit_category_and_index - - @property - def new_outfit_category_and_index(self) -> Tuple[OutfitCategory, int]: - """The outfit category and index for the outfit the Sim has changed to.""" - return self._new_outfit_category_and_index diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_buff_added.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_buff_added.py deleted file mode 100644 index 9901792..0000000 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_buff_added.py +++ /dev/null @@ -1,74 +0,0 @@ -""" -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 -""" -from buffs.buff import Buff -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent -from s4ap.sims4communitylib.utils.sims.common_buff_utils import CommonBuffUtils - - -class S4CLSimBuffAddedEvent(CommonEvent): - """S4CLSimBuffAddedEvent(sim_info, buff) - - An event that occurs when a Buff is added to a Sim. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity()) - def handle_event(event_data: S4CLSimBuffAddedEvent): - pass - - :param sim_info: The Sim that changed. - :type sim_info: SimInfo - :param buff: The Buff that was added. - :type buff: Buff - """ - - def __init__(self, sim_info: SimInfo, buff: Buff): - self._sim_info = sim_info - self._buff = buff - - @property - def sim_info(self) -> SimInfo: - """The Sim that received the buff. - - :return: The Sim that received the buff. - :rtype: SimInfo - """ - return self._sim_info - - @property - def buff(self) -> Buff: - """The Buff that was added. - - :return: The Buff that was added. - :rtype: Buff - """ - return self._buff - - @property - def buff_id(self) -> int: - """The decimal identifier of the Buff. - - :return: The decimal identifier of the Buff. - :rtype: int - """ - return CommonBuffUtils.get_buff_id(self.buff) diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_buff_removed.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_buff_removed.py deleted file mode 100644 index ba54d93..0000000 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_buff_removed.py +++ /dev/null @@ -1,74 +0,0 @@ -""" -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 -""" -from buffs.buff import Buff -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent -from s4ap.sims4communitylib.utils.sims.common_buff_utils import CommonBuffUtils - - -class S4CLSimBuffRemovedEvent(CommonEvent): - """S4CLSimBuffRemovedEvent(sim_info, buff) - - An event that occurs when a Buff is removed from a Sim. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity()) - def handle_event(event_data: S4CLSimBuffRemovedEvent): - pass - - :param sim_info: The Sim that changed. - :type sim_info: SimInfo - :param buff: The Buff that was removed. - :type buff: Buff - """ - - def __init__(self, sim_info: SimInfo, buff: Buff): - self._sim_info = sim_info - self._buff = buff - - @property - def sim_info(self) -> SimInfo: - """The Sim that lost the buff. - - :return: The Sim that lost the buff. - :rtype: SimInfo - """ - return self._sim_info - - @property - def buff(self) -> Buff: - """The Buff that was removed. - - :return: The Buff that was removed. - :rtype: Buff - """ - return self._buff - - @property - def buff_id(self) -> int: - """The decimal identifier of the Buff. - - :return: The decimal identifier of the Buff. - :rtype: int - """ - return CommonBuffUtils.get_buff_id(self.buff) diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_age.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_age.py deleted file mode 100644 index e13f8e1..0000000 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_age.py +++ /dev/null @@ -1,66 +0,0 @@ -""" -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 -""" -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.enums.common_age import CommonAge -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent - - -class S4CLSimChangedAgeEvent(CommonEvent): - """S4CLSimChangedAgeEvent(sim_info, old_age, new_age) - - An event that occurs when a Sim has changed their current Age. - - .. note:: This can occur when a Child Sim becomes a Teen Sim, a Teen Sim becomes a Child Sim, etc. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity().name) - def handle_event(event_data: S4CLSimChangedAgeEvent): - pass - - :param sim_info: The Sim that changed. - :type sim_info: SimInfo - :param old_age: The age the Sim has changed from. - :type old_age: CommonAge - :param new_age: The age the Sim has changed to. - :type new_age: CommonAge - """ - - def __init__(self, sim_info: SimInfo, old_age: CommonAge, new_age: CommonAge): - self._sim_info = sim_info - self._old_age = old_age - self._new_age = new_age - - @property - def sim_info(self) -> SimInfo: - """The Sim that changed.""" - return self._sim_info - - @property - def old_age(self) -> CommonAge: - """The age the Sim has changed from.""" - return self._old_age - - @property - def new_age(self) -> CommonAge: - """The age the Sim has changed to.""" - return self._new_age diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender.py deleted file mode 100644 index 939695b..0000000 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender.py +++ /dev/null @@ -1,64 +0,0 @@ -""" -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 -""" -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.enums.common_gender import CommonGender -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent - - -class S4CLSimChangedGenderEvent(CommonEvent): - """S4CLSimChangedGenderEvent(sim_info, old_gender, new_gender) - - An event that occurs when a Sim has changed their current gender. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity().name) - def handle_event(event_data: S4CLSimChangedGenderEvent): - pass - - :param sim_info: The Sim that changed. - :type sim_info: SimInfo - :param old_gender: The gender the Sim has changed from. - :type old_gender: CommonGender - :param new_gender: The gender the Sim has changed to. - :type new_gender: CommonGender - """ - - def __init__(self, sim_info: SimInfo, old_gender: CommonGender, new_gender: CommonGender): - self._sim_info = sim_info - self._old_gender = old_gender - self._new_gender = new_gender - - @property - def sim_info(self) -> SimInfo: - """The Sim that changed.""" - return self._sim_info - - @property - def old_gender(self) -> CommonGender: - """The gender the Sim has changed from.""" - return self._old_gender - - @property - def new_gender(self) -> CommonGender: - """The gender the Sim has changed to.""" - return self._new_gender diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_body_frame.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_body_frame.py deleted file mode 100644 index 75d51ca..0000000 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_body_frame.py +++ /dev/null @@ -1,51 +0,0 @@ -""" -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 -""" -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent - - -class S4CLSimChangedGenderOptionsBodyFrameEvent(CommonEvent): - """S4CLSimChangedGenderOptionsBodyFrameEvent(sim_info) - - An event that occurs when a Sim has changed their body frame. i.e. Masculine to Feminine or vice verse - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity()) - def handle_event(event_data: S4CLSimChangedGenderOptionsBodyFrameEvent): - pass - - :param sim_info: The Sim that changed. - :type sim_info: SimInfo - """ - - def __init__(self, sim_info: SimInfo): - self._sim_info = sim_info - - @property - def sim_info(self) -> SimInfo: - """The Sim that changed. - - :return: The Sim that changed. - :rtype: SimInfo - """ - return self._sim_info diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_breasts.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_breasts.py deleted file mode 100644 index 69199a4..0000000 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_breasts.py +++ /dev/null @@ -1,51 +0,0 @@ -""" -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 -""" -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent - - -class S4CLSimChangedGenderOptionsBreastsEvent(CommonEvent): - """S4CLSimChangedGenderOptionsBreastsEvent(sim_info) - - An event that occurs when a Sim has changed whether or not they have breasts. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity()) - def handle_event(event_data: S4CLSimChangedGenderOptionsBreastsEvent): - pass - - :param sim_info: The Sim that changed. - :type sim_info: SimInfo - """ - - def __init__(self, sim_info: SimInfo): - self._sim_info = sim_info - - @property - def sim_info(self) -> SimInfo: - """The Sim that changed. - - :return: The Sim that changed. - :rtype: SimInfo - """ - return self._sim_info diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_can_be_impregnated.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_can_be_impregnated.py deleted file mode 100644 index dada074..0000000 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_can_be_impregnated.py +++ /dev/null @@ -1,51 +0,0 @@ -""" -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 -""" -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent - - -class S4CLSimChangedGenderOptionsCanBeImpregnatedEvent(CommonEvent): - """S4CLSimChangedGenderOptionsCanBeImpregnatedEvent(sim_info) - - An event that occurs when a Human Sim has changed whether they can be impregnated by other Sims or not. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity().name) - def handle_event(event_data: S4CLSimChangedGenderOptionsCanBeImpregnatedEvent): - pass - - :param sim_info: The Sim that changed. - :type sim_info: SimInfo - """ - - def __init__(self, sim_info: SimInfo): - self._sim_info = sim_info - - @property - def sim_info(self) -> SimInfo: - """The Sim that changed. - - :return: The Sim that changed. - :rtype: SimInfo - """ - return self._sim_info diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_can_impregnate.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_can_impregnate.py deleted file mode 100644 index b9043fc..0000000 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_can_impregnate.py +++ /dev/null @@ -1,51 +0,0 @@ -""" -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 -""" -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent - - -class S4CLSimChangedGenderOptionsCanImpregnateEvent(CommonEvent): - """S4CLSimChangedGenderOptionsCanImpregnateEvent(sim_info) - - An event that occurs when a Human Sim has changed whether they can impregnate other Sims or not. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity().name) - def handle_event(event_data: S4CLSimChangedGenderOptionsCanImpregnateEvent): - pass - - :param sim_info: The Sim that changed. - :type sim_info: SimInfo - """ - - def __init__(self, sim_info: SimInfo): - self._sim_info = sim_info - - @property - def sim_info(self) -> SimInfo: - """The Sim that changed. - - :return: The Sim that changed. - :rtype: SimInfo - """ - return self._sim_info diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_can_reproduce.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_can_reproduce.py deleted file mode 100644 index 1853ab9..0000000 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_can_reproduce.py +++ /dev/null @@ -1,51 +0,0 @@ -""" -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 -""" -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent - - -class S4CLSimChangedGenderOptionsCanReproduceEvent(CommonEvent): - """S4CLSimChangedGenderOptionsCanReproduceEvent(sim_info) - - An event that occurs when a Pet Sim has changed whether they can reproduce or not. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity().name) - def handle_event(event_data: S4CLSimChangedGenderOptionsCanReproduceEvent): - pass - - :param sim_info: The Sim that changed. - :type sim_info: SimInfo - """ - - def __init__(self, sim_info: SimInfo): - self._sim_info = sim_info - - @property - def sim_info(self) -> SimInfo: - """The Sim that changed. - - :return: The Sim that changed. - :rtype: SimInfo - """ - return self._sim_info diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_clothing_preference.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_clothing_preference.py deleted file mode 100644 index a78b66d..0000000 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_clothing_preference.py +++ /dev/null @@ -1,51 +0,0 @@ -""" -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 -""" -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent - - -class S4CLSimChangedGenderOptionsClothingPreferenceEvent(CommonEvent): - """S4CLSimChangedGenderOptionsClothingPreferenceEvent(sim_info) - - An event that occurs when a Sim has changed their clothing preference. i.e. Menswear to Womenswear or vice verse - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity().name) - def handle_event(event_data: S4CLSimChangedGenderOptionsClothingPreferenceEvent): - pass - - :param sim_info: The Sim that changed. - :type sim_info: SimInfo - """ - - def __init__(self, sim_info: SimInfo): - self._sim_info = sim_info - - @property - def sim_info(self) -> SimInfo: - """The Sim that changed. - - :return: The Sim that changed. - :rtype: SimInfo - """ - return self._sim_info diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_toilet_usage.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_toilet_usage.py deleted file mode 100644 index dc48691..0000000 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_gender_options_toilet_usage.py +++ /dev/null @@ -1,51 +0,0 @@ -""" -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 -""" -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent - - -class S4CLSimChangedGenderOptionsToiletUsageEvent(CommonEvent): - """S4CLSimChangedGenderOptionsToiletUsageEvent(sim_info) - - An event that occurs when a Sim has changed the way they use the toilet. i.e. Toilet Standing to Toilet Sitting or Toilet Sitting to Toilet Standing. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity().name) - def handle_event(event_data: S4CLSimChangedGenderOptionsToiletUsageEvent): - pass - - :param sim_info: The Sim that changed. - :type sim_info: SimInfo - """ - - def __init__(self, sim_info: SimInfo): - self._sim_info = sim_info - - @property - def sim_info(self) -> SimInfo: - """The Sim that changed. - - :return: The Sim that changed. - :rtype: SimInfo - """ - return self._sim_info diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_occult_type.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_occult_type.py deleted file mode 100644 index 666223a..0000000 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changed_occult_type.py +++ /dev/null @@ -1,79 +0,0 @@ -""" -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 -""" -from sims.occult.occult_enums import OccultType -from sims.occult.occult_tracker import OccultTracker -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent - - -class S4CLSimChangedOccultTypeEvent(CommonEvent): - """S4CLSimChangedOccultTypeEvent(sim_info, occult_type, occult_tracker) - - An event that occurs when a Sim has changed their current OccultType. - - .. note:: This can occur when an Alien Sim changes between their Disguised form and their True form. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity().name) - def handle_event(event_data: S4CLSimChangedOccultTypeEvent): - pass - - :param sim_info: The Sim that changed OccultTypes. - :type sim_info: SimInfo - :param occult_type: The OccultType the Sim has changed to. - :type occult_type: OccultType - :param occult_tracker: A tracker that keeps track of the occult status of the Sim. - :type occult_tracker: OccultTracker - """ - - def __init__(self, sim_info: SimInfo, occult_type: OccultType, occult_tracker: OccultTracker): - self._sim_info = sim_info - self._occult_type = occult_type - self._occult_tracker = occult_tracker - - @property - def sim_info(self) -> SimInfo: - """The Sim that changed OccultTypes. - - :return: The Sim that changed OccultTypes. - :rtype: SimInfo - """ - return self._sim_info - - @property - def occult_type(self) -> OccultType: - """The OccultType the Sim has changed to. - - :return: The OccultType the Sim has changed to. - :rtype: OccultType - """ - return self._occult_type - - @property - def occult_tracker(self) -> OccultTracker: - """A tracker that keeps track of the occult status of the Sim. - - :return: A tracker that keeps track of the occult status of the Sim. - :rtype: OccultTracker - """ - return self._occult_tracker diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changing_occult_type.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changing_occult_type.py deleted file mode 100644 index 76169ea..0000000 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_changing_occult_type.py +++ /dev/null @@ -1,79 +0,0 @@ -""" -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 -""" -from sims.occult.occult_enums import OccultType -from sims.occult.occult_tracker import OccultTracker -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent - - -class S4CLSimChangingOccultTypeEvent(CommonEvent): - """S4CLSimChangingOccultTypeEvent(sim_info, occult_type, occult_tracker) - - An event that occurs when a Sim is changing their current OccultType. (But before they have changed!) - - .. note:: This can occur when an Alien Sim changes between their Disguised form and their True form or when a Mermaid changes from their Non-Mermaid form to their Mermaid form. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity().name) - def handle_event(event_data: S4CLSimChangingOccultTypeEvent): - pass - - :param sim_info: The Sim that changing OccultTypes. - :type sim_info: SimInfo - :param occult_type: The OccultType the Sim is changing to. - :type occult_type: OccultType - :param occult_tracker: A tracker that keeps track of the occult status of the Sim. - :type occult_tracker: OccultTracker - """ - - def __init__(self, sim_info: SimInfo, occult_type: OccultType, occult_tracker: OccultTracker): - self._sim_info = sim_info - self._occult_type = occult_type - self._occult_tracker = occult_tracker - - @property - def sim_info(self) -> SimInfo: - """The Sim that changed OccultTypes. - - :return: The Sim that changed OccultTypes. - :rtype: SimInfo - """ - return self._sim_info - - @property - def occult_type(self) -> OccultType: - """The OccultType the Sim is changing to. - - :return: The OccultType the Sim is changing to. - :rtype: OccultType - """ - return self._occult_type - - @property - def occult_tracker(self) -> OccultTracker: - """A tracker that keeps track of the occult status of the Sim. - - :return: A tracker that keeps track of the occult status of the Sim. - :rtype: OccultTracker - """ - return self._occult_tracker diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_died.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_died.py deleted file mode 100644 index 864e071..0000000 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_died.py +++ /dev/null @@ -1,68 +0,0 @@ -""" -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 -""" -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.enums.common_death_types import CommonDeathType -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent - - -class S4CLSimDiedEvent(CommonEvent): - """S4CLSimDiedEvent(sim_info, death_type, died_off_lot) - - An event that occurs when a Sim has died. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity().name) - def handle_event(event_data: S4CLSimDiedEvent): - pass - - :param sim_info: The Sim that died. - :type sim_info: SimInfo - :param death_type: The type of Death that befell the Sim. - :type death_type: CommonDeathType - :param died_off_lot: True, if the Sim died off the active lot. False, if not. - :type died_off_lot: bool - """ - - def __init__(self, sim_info: SimInfo, death_type: CommonDeathType, died_off_lot: bool): - self._sim_info = sim_info - self._death_type = death_type - self._died_off_lot = died_off_lot - - @property - def sim_info(self) -> SimInfo: - """The Sim that died. - - :return: The Sim that died. - :rtype: SimInfo - """ - return self._sim_info - - @property - def death_type(self) -> CommonDeathType: - """The type of Death that befell the Sim.""" - return self._death_type - - @property - def died_off_lot(self) -> bool: - """True, if the Sim died off the active lot. False, if not.""" - return self._died_off_lot diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_initialized.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_initialized.py deleted file mode 100644 index 1783e3b..0000000 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_initialized.py +++ /dev/null @@ -1,51 +0,0 @@ -""" -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 -""" -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent - - -class S4CLSimInitializedEvent(CommonEvent): - """S4CLSimInitializedEvent(sim_info) - - An event that occurs after a Sim has been initialized. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity().name) - def handle_event(event_data: S4CLSimInitializedEvent): - pass - - :param sim_info: The Sim that was initialized. - :type sim_info: SimInfo - """ - - def __init__(self, sim_info: SimInfo): - self._sim_info = sim_info - - @property - def sim_info(self) -> SimInfo: - """The Sim that was initialized. - - :return: The Sim that was initialized. - :rtype: SimInfo - """ - return self._sim_info diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_loaded.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_loaded.py deleted file mode 100644 index 95d2dd9..0000000 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_loaded.py +++ /dev/null @@ -1,51 +0,0 @@ -""" -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 -""" -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent - - -class S4CLSimLoadedEvent(CommonEvent): - """S4CLSimLoadedEvent(sim_info) - - An event that occurs after a Sim has been loaded. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity().name) - def handle_event(event_data: S4CLSimLoadedEvent): - pass - - :param sim_info: The Sim that was loaded. - :type sim_info: SimInfo - """ - - def __init__(self, sim_info: SimInfo): - self._sim_info = sim_info - - @property - def sim_info(self) -> SimInfo: - """The Sim that was loaded. - - :return: The Sim that was loaded. - :rtype: SimInfo - """ - return self._sim_info diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_pre_despawned.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_pre_despawned.py deleted file mode 100644 index e24ee14..0000000 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_pre_despawned.py +++ /dev/null @@ -1,51 +0,0 @@ -""" -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 -""" -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent - - -class S4CLSimPreDespawnedEvent(CommonEvent): - """S4CLSimPreDespawnedEvent(sim_info) - - An event that occurs when a Sim is being despawned. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity().name) - def handle_event(event_data: S4CLSimPreDespawnedEvent): - pass - - :param sim_info: The Sim that is being despawned. - :type sim_info: SimInfo - """ - - def __init__(self, sim_info: SimInfo): - self._sim_info = sim_info - - @property - def sim_info(self) -> SimInfo: - """The Sim that is being despawned. - - :return: The Sim that is being despawned. - :rtype: SimInfo - """ - return self._sim_info diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_relationship_bit_added.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_relationship_bit_added.py deleted file mode 100644 index cc07e81..0000000 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_relationship_bit_added.py +++ /dev/null @@ -1,86 +0,0 @@ -""" -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 -""" -from relationships.relationship_bit import RelationshipBit -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent - - -class S4CLSimRelationshipBitAddedEvent(CommonEvent): - """S4CLSimRelationshipBitAddedEvent(sim_info_a, sim_info_b, relationship_bit) - - An event that occurs when a Relationship Bit is added from Sim A to Sim B. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity()) - def handle_event(event_data: S4CLSimRelationshipBitAddedEvent): - pass - - :param sim_info_a: The Sim with the relationship bit toward Sim B. - :type sim_info_a: SimInfo - :param sim_info_b: The Sim with the relationship bit from Sim A. - :type sim_info_b: SimInfo - :param relationship_bit: The RelationshipBit that was added. - :type relationship_bit: RelationshipBit - """ - - def __init__(self, sim_info_a: SimInfo, sim_info_b: SimInfo, relationship_bit: RelationshipBit): - self._sim_info_a = sim_info_a - self._sim_info_b = sim_info_b - self._relationship_bit = relationship_bit - - @property - def sim_info_a(self) -> SimInfo: - """The Sim that has a Relationship Bit toward Sim B. - - :return: The Sim that has a Relationship Bit toward Sim B. - :rtype: SimInfo - """ - return self._sim_info_a - - @property - def sim_info_b(self) -> SimInfo: - """The Sim that has a Relationship Bit from Sim A. - - :return: The Sim that has a Relationship Bit from Sim A. - :rtype: SimInfo - """ - return self._sim_info_b - - @property - def relationship_bit(self) -> RelationshipBit: - """The RelationshipBit that was added. - - :return: The RelationshipBit that was added. - :rtype: RelationshipBit - """ - return self._relationship_bit - - @property - def relationship_bit_id(self) -> int: - """The decimal identifier of the RelationshipBit. - - :return: The decimal identifier of the RelationshipBit. - :rtype: int - """ - from s4ap.sims4communitylib.utils.sims.common_relationship_utils import CommonRelationshipUtils - return CommonRelationshipUtils.get_relationship_bit_guid(self.relationship_bit) diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_relationship_bit_removed.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_relationship_bit_removed.py deleted file mode 100644 index 41e33fa..0000000 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_relationship_bit_removed.py +++ /dev/null @@ -1,86 +0,0 @@ -""" -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 -""" -from relationships.relationship_bit import RelationshipBit -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent - - -class S4CLSimRelationshipBitRemovedEvent(CommonEvent): - """S4CLSimRelationshipBitRemovedEvent(sim_info_a, sim_info_b, relationship_bit) - - An event that occurs when a Relationship Bit is removed from Sim A to Sim B. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity()) - def handle_event(event_data: S4CLSimRelationshipBitRemovedEvent): - pass - - :param sim_info_a: The Sim with the relationship bit toward Sim B. - :type sim_info_a: SimInfo - :param sim_info_b: The Sim with the relationship bit from Sim A. - :type sim_info_b: SimInfo - :param relationship_bit: The RelationshipBit that was removed. - :type relationship_bit: RelationshipBit - """ - - def __init__(self, sim_info_a: SimInfo, sim_info_b: SimInfo, relationship_bit: RelationshipBit): - self._sim_info_a = sim_info_a - self._sim_info_b = sim_info_b - self._relationship_bit = relationship_bit - - @property - def sim_info_a(self) -> SimInfo: - """The Sim that has a Relationship Bit toward Sim B. - - :return: The Sim that has a Relationship Bit toward Sim B. - :rtype: SimInfo - """ - return self._sim_info_a - - @property - def sim_info_b(self) -> SimInfo: - """The Sim that has a Relationship Bit from Sim A. - - :return: The Sim that has a Relationship Bit from Sim A. - :rtype: SimInfo - """ - return self._sim_info_b - - @property - def relationship_bit(self) -> RelationshipBit: - """The RelationshipBit that was removed. - - :return: The RelationshipBit that was removed. - :rtype: RelationshipBit - """ - return self._relationship_bit - - @property - def relationship_bit_id(self) -> int: - """The decimal identifier of the RelationshipBit. - - :return: The decimal identifier of the RelationshipBit. - :rtype: int - """ - from s4ap.sims4communitylib.utils.sims.common_relationship_utils import CommonRelationshipUtils - return CommonRelationshipUtils.get_relationship_bit_guid(self.relationship_bit) diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_removed_occult_type.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_removed_occult_type.py deleted file mode 100644 index 8977712..0000000 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_removed_occult_type.py +++ /dev/null @@ -1,77 +0,0 @@ -""" -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 -""" -from sims.occult.occult_enums import OccultType -from sims.occult.occult_tracker import OccultTracker -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent - - -class S4CLSimRemovedOccultTypeEvent(CommonEvent): - """S4CLSimRemovedOccultTypeEvent(sim_info, occult_type, occult_tracker) - - An event that occurs when an OccultType has been removed from a Sim. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity().name) - def handle_event(event_data: S4CLSimRemovedOccultTypeEvent): - pass - - :param sim_info: The Sim the Occult Type was removed from. - :type sim_info: SimInfo - :param occult_type: The OccultType that was removed. - :type occult_type: OccultType - :param occult_tracker: A tracker that keeps track of the occult status of the Sim. - :type occult_tracker: OccultTracker - """ - - def __init__(self, sim_info: SimInfo, occult_type: OccultType, occult_tracker: OccultTracker): - self._sim_info = sim_info - self._occult_type = occult_type - self._occult_tracker = occult_tracker - - @property - def sim_info(self) -> SimInfo: - """The Sim the OccultType was removed from. - - :return: The Sim the OccultType was removed from. - :rtype: SimInfo - """ - return self._sim_info - - @property - def occult_type(self) -> OccultType: - """The OccultType that was removed. - - :return: The OccultType that was removed. - :rtype: OccultType - """ - return self._occult_type - - @property - def occult_tracker(self) -> OccultTracker: - """A tracker that keeps track of the occult status of the Sim. - - :return: A tracker that keeps track of the occult status of the Sim. - :rtype: OccultTracker - """ - return self._occult_tracker diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_revived.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_revived.py deleted file mode 100644 index bb6a3b7..0000000 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_revived.py +++ /dev/null @@ -1,56 +0,0 @@ -""" -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 -""" -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.enums.common_death_types import CommonDeathType -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent - - -class S4CLSimRevivedEvent(CommonEvent): - """S4CLSimRevivedEvent(sim_info, previous_death_type) - - An event that occurs when a Sim has been revived after having previously been dead. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity().name) - def handle_event(event_data: S4CLSimRevivedEvent): - pass - - :param sim_info: The Sim that was revived. - :type sim_info: SimInfo - :param previous_death_type: The type of Death that befell the Sim before they were revived. - :type previous_death_type: CommonDeathType - """ - - def __init__(self, sim_info: SimInfo, previous_death_type: CommonDeathType): - self._sim_info = sim_info - self._previous_death_type = previous_death_type - - @property - def sim_info(self) -> SimInfo: - """The Sim that was revived.""" - return self._sim_info - - @property - def previous_death_type(self) -> CommonDeathType: - """The type of Death that befell the Sim before they were revived.""" - return self._previous_death_type diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_set_current_outfit.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_set_current_outfit.py deleted file mode 100644 index 6c3a67b..0000000 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_set_current_outfit.py +++ /dev/null @@ -1,66 +0,0 @@ -""" -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 -""" -from typing import Tuple - -from sims.outfits.outfit_enums import OutfitCategory -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent - - -class S4CLSimSetCurrentOutfitEvent(CommonEvent): - """S4CLSimSetCurrentOutfitEvent(sim_info, old_outfit_category_and_index, new_outfit_category_and_index) - - An event that occurs when the current outfit of a Sim is being set. (Before it is actually set) - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity().name) - def handle_event(event_data: S4CLSimSetCurrentOutfitEvent): - pass - - :param sim_info: The Sim that changed. - :type sim_info: SimInfo - :param old_outfit_category_and_index: The outfit category and index for the outfit the Sim is changing from. - :type old_outfit_category_and_index: Tuple[OutfitCategory, int] - :param new_outfit_category_and_index: The outfit category and index for the outfit the Sim is changing to. - :type new_outfit_category_and_index: Tuple[OutfitCategory, int] - """ - - def __init__(self, sim_info: SimInfo, old_outfit_category_and_index: Tuple[OutfitCategory, int], new_outfit_category_and_index: Tuple[OutfitCategory, int]): - self._sim_info = sim_info - self._old_outfit_category_and_index = old_outfit_category_and_index - self._new_outfit_category_and_index = new_outfit_category_and_index - - @property - def sim_info(self) -> SimInfo: - """The Sim that is changing.""" - return self._sim_info - - @property - def old_outfit_category_and_index(self) -> Tuple[OutfitCategory, int]: - """The outfit category and index for the outfit the Sim is changing from.""" - return self._old_outfit_category_and_index - - @property - def new_outfit_category_and_index(self) -> Tuple[OutfitCategory, int]: - """The outfit category and index for the outfit the Sim is changing to.""" - return self._new_outfit_category_and_index diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_skill_leveled_up.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_skill_leveled_up.py deleted file mode 100644 index f4f6c3e..0000000 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_skill_leveled_up.py +++ /dev/null @@ -1,78 +0,0 @@ -""" -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 -""" -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent -from s4ap.sims4communitylib.utils.resources.common_skill_utils import CommonSkillUtils -from statistics.skill import Skill - - -class S4CLSimSkillLeveledUpEvent(CommonEvent): - """S4CLSimSkillLeveledUpEvent(sim_info, skill, old_skill_level, new_skill_level) - - An event that occurs when a Sim levels up in a Skill. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity()) - def handle_event(event_data: S4CLSimSkillLeveledUpEvent): - pass - - :param sim_info: The Sim that changed. - :type sim_info: SimInfo - :param skill: The Skill that was leveled up. - :type skill: Skill - :param old_skill_level: The level the Sim was at before leveling up. - :type old_skill_level: int - :param new_skill_level: The level the Sim will be after leveling up. - :type new_skill_level: int - """ - - def __init__(self, sim_info: SimInfo, skill: Skill, old_skill_level: int, new_skill_level: int): - self._sim_info = sim_info - self._skill = skill - self._old_skill_level = old_skill_level - self._new_skill_level = new_skill_level - - @property - def new_skill_level(self) -> int: - """The level the Sim will be after leveling up.""" - return self._new_skill_level - - @property - def old_skill_level(self) -> int: - """The level the Sim was at before leveling up.""" - return self._old_skill_level - - @property - def sim_info(self) -> SimInfo: - """The Sim that leveled up in a Skill.""" - return self._sim_info - - @property - def skill(self) -> Skill: - """The Skill that was leveled up.""" - return self._skill - - @property - def skill_id(self) -> int: - """The decimal identifier of the Skill.""" - return CommonSkillUtils.get_skill_id(self.skill) diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_spawned.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_spawned.py deleted file mode 100644 index 2afdd58..0000000 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_spawned.py +++ /dev/null @@ -1,51 +0,0 @@ -""" -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 -""" -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent - - -class S4CLSimSpawnedEvent(CommonEvent): - """S4CLSimSpawnedEvent(sim_info) - - An event that occurs after a Sim has been spawned. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity().name) - def handle_event(event_data: S4CLSimSpawnedEvent): - pass - - :param sim_info: The Sim that was spawned. - :type sim_info: SimInfo - """ - - def __init__(self, sim_info: SimInfo): - self._sim_info = sim_info - - @property - def sim_info(self) -> SimInfo: - """The Sim that was spawned. - - :return: The Sim that was spawned. - :rtype: SimInfo - """ - return self._sim_info diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_trait_added.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_trait_added.py deleted file mode 100644 index 1aa584e..0000000 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_trait_added.py +++ /dev/null @@ -1,87 +0,0 @@ -""" -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 -""" -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent -from s4ap.sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils -from traits.trait_tracker import TraitTracker -from traits.traits import Trait - - -class S4CLSimTraitAddedEvent(CommonEvent): - """S4CLSimTraitAddedEvent(sim_info, trait, trait_tracker) - - An event that occurs when a Trait is added to a Sim. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity()) - def handle_event(event_data: S4CLSimTraitAddedEvent): - pass - - :param sim_info: The Sim that changed. - :type sim_info: SimInfo - :param trait: The Trait that was added. - :type trait: Trait - :param trait_tracker: The Trait Tracker being added to. - :type trait_tracker: TraitTracker - """ - - def __init__(self, sim_info: SimInfo, trait: Trait, trait_tracker: TraitTracker): - self._sim_info = sim_info - self._trait = trait - self._trait_tracker = trait_tracker - - @property - def sim_info(self) -> SimInfo: - """The Sim that received the trait. - - :return: The Sim that received the trait. - :rtype: SimInfo - """ - return self._sim_info - - @property - def trait(self) -> Trait: - """The Trait that was added. - - :return: The Trait that was added. - :rtype: Trait - """ - return self._trait - - @property - def trait_tracker(self) -> TraitTracker: - """The Trait Tracker being added to. - - :return: The Trait Tracker being added to. - :rtype: TraitTracker - """ - return self._trait_tracker - - @property - def trait_id(self) -> int: - """The decimal identifier of the Trait. - - :return: The decimal identifier of the Trait. - :rtype: int - """ - return CommonTraitUtils.get_trait_id(self.trait) diff --git a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_trait_removed.py b/Scripts/s4ap/sims4communitylib/events/sim/events/sim_trait_removed.py deleted file mode 100644 index 6080bb2..0000000 --- a/Scripts/s4ap/sims4communitylib/events/sim/events/sim_trait_removed.py +++ /dev/null @@ -1,87 +0,0 @@ -""" -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 -""" -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent -from s4ap.sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils -from traits.trait_tracker import TraitTracker -from traits.traits import Trait - - -class S4CLSimTraitRemovedEvent(CommonEvent): - """S4CLSimTraitRemovedEvent(sim_info, trait, trait_tracker) - - An event that occurs when a Trait is removed from a Sim. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity()) - def handle_event(event_data: S4CLSimTraitRemovedEvent): - pass - - :param sim_info: The Sim that changed. - :type sim_info: SimInfo - :param trait: The Trait that was removed. - :type trait: Trait - :param trait_tracker: The Trait Tracker being removed from. - :type trait_tracker: TraitTracker - """ - - def __init__(self, sim_info: SimInfo, trait: Trait, trait_tracker: TraitTracker): - self._sim_info = sim_info - self._trait = trait - self._trait_tracker = trait_tracker - - @property - def sim_info(self) -> SimInfo: - """The Sim that lost the trait. - - :return: The Sim that lost the trait. - :rtype: SimInfo - """ - return self._sim_info - - @property - def trait(self) -> Trait: - """The Trait that was removed. - - :return: The Trait that was removed. - :rtype: Trait - """ - return self._trait - - @property - def trait_tracker(self) -> TraitTracker: - """The Trait Tracker being removed from. - - :return: The Trait Tracker being removed from. - :rtype: TraitTracker - """ - return self._trait_tracker - - @property - def trait_id(self) -> int: - """The decimal identifier of the Trait. - - :return: The decimal identifier of the Trait. - :rtype: int - """ - return CommonTraitUtils.get_trait_id(self.trait) diff --git a/Scripts/s4ap/sims4communitylib/events/zone_spin/__init__.py b/Scripts/s4ap/sims4communitylib/events/zone_spin/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/events/zone_spin/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/events/zone_spin/common_zone_spin_event_dispatcher.py b/Scripts/s4ap/sims4communitylib/events/zone_spin/common_zone_spin_event_dispatcher.py deleted file mode 100644 index 2d7ecd9..0000000 --- a/Scripts/s4ap/sims4communitylib/events/zone_spin/common_zone_spin_event_dispatcher.py +++ /dev/null @@ -1,114 +0,0 @@ -""" -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 -""" -from typing import Any - -from server.client import Client -from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from s4ap.sims4communitylib.events.zone_spin.events.zone_early_load import S4CLZoneEarlyLoadEvent -from s4ap.sims4communitylib.events.zone_spin.events.zone_late_load import S4CLZoneLateLoadEvent -from s4ap.sims4communitylib.events.zone_spin.events.zone_manager_start_event import S4CLZoneManagerStartEvent -from s4ap.sims4communitylib.events.zone_spin.events.zone_post_load import \ - S4CLZonePostLoadEvent -from s4ap.sims4communitylib.events.zone_spin.events.zone_save import S4CLZoneSaveEvent -from s4ap.sims4communitylib.events.zone_spin.events.zone_teardown import S4CLZoneTeardownEvent -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.common_service import CommonService -from s4ap.sims4communitylib.utils.common_injection_utils import CommonInjectionUtils -from zone import Zone -from zone_manager import ZoneManager - - -class CommonZoneSpinEventDispatcher(CommonService): - """A service that dispatches zone spin events (Teardown, Save, Early/Late Load). - - .. warning:: Do not use this service directly to listen for events!\ - Use the :class:`.CommonEventRegistry` to listen for dispatched events. - - """ - def __init__(self: 'CommonZoneSpinEventDispatcher'): - self._game_loaded = False - self._game_loading = True - - @property - def game_loaded(self) -> bool: - """Determine if the game has loaded. - - :return: True, if the game has loaded. False, if the game has not loaded. - :rtype: bool - """ - return self._game_loaded - - @property - def game_loading(self) -> bool: - """Determine if the game is loading. - - :return: True, if the game is currently loading. False, if the game is not currently loading. - :rtype: bool - """ - return self._game_loading - - def _on_early_zone_load(self, zone: Zone): - CommonEventRegistry.get().dispatch(S4CLZoneEarlyLoadEvent(zone, game_loaded=self.game_loaded, game_loading=self.game_loading)) - - def _on_late_zone_load(self, zone: Zone, household_id: int, active_sim_id: int): - CommonEventRegistry.get().dispatch(S4CLZoneLateLoadEvent(zone, household_id, active_sim_id, game_loaded=self.game_loaded, game_loading=self.game_loading)) - self._game_loaded = True - self._game_loading = False - - def _on_zone_teardown(self, zone: Zone, client: Client): - CommonEventRegistry.get().dispatch(S4CLZoneTeardownEvent(zone, client, game_loaded=self.game_loaded, game_loading=self.game_loading)) - self._game_loading = True - - def _on_zone_save(self, zone: Zone, save_slot_data: Any = None): - CommonEventRegistry.get().dispatch(S4CLZoneSaveEvent(zone, save_slot_data=save_slot_data, game_loaded=self.game_loaded, game_loading=self.game_loading)) - - def _on_loading_screen_animation_finished(self, zone: Zone): - CommonEventRegistry.get().dispatch(S4CLZonePostLoadEvent(zone, game_loaded=self.game_loaded, game_loading=self.game_loading)) - - def _on_zone_manager_start(self, zone_manager: ZoneManager): - CommonEventRegistry.get().dispatch(S4CLZoneManagerStartEvent(zone_manager)) - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), Zone, Zone.load_zone.__name__, handle_exceptions=False) -def _common_on_early_zone_load(original, self: Zone, *args, **kwargs): - result = original(self, *args, **kwargs) - CommonZoneSpinEventDispatcher.get()._on_early_zone_load(self) - return result - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), Zone, Zone.do_zone_spin_up.__name__, handle_exceptions=False) -def _common_on_late_zone_load(original, self: Zone, *args, **kwargs): - result = original(self, *args, **kwargs) - CommonZoneSpinEventDispatcher.get()._on_late_zone_load(self, *args, **kwargs) - return result - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), Zone, Zone.on_teardown.__name__, handle_exceptions=False) -def _common_on_zone_teardown(original, self: Zone, client): - CommonZoneSpinEventDispatcher.get()._on_zone_teardown(self, client) - return original(self, client) - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), Zone, Zone.save_zone.__name__, handle_exceptions=False) -def _common_on_zone_save(original, self: Zone, *args, **kwargs): - CommonZoneSpinEventDispatcher.get()._on_zone_save(self, *args, **kwargs) - return original(self, *args, **kwargs) - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), Zone, Zone.on_loading_screen_animation_finished.__name__, handle_exceptions=False) -def _common_on_loading_screen_animation_finished(original, self: Zone, *args, **kwargs): - original_result = original(self, *args, **kwargs) - CommonZoneSpinEventDispatcher.get()._on_loading_screen_animation_finished(self) - return original_result - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), ZoneManager, ZoneManager.start.__name__, handle_exceptions=False) -def _common_on_zone_manager_start(original, self: ZoneManager, *args, **kwargs): - original_result = original(self, *args, **kwargs) - CommonZoneSpinEventDispatcher.get()._on_zone_manager_start(self) - return original_result diff --git a/Scripts/s4ap/sims4communitylib/events/zone_spin/events/__init__.py b/Scripts/s4ap/sims4communitylib/events/zone_spin/events/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/events/zone_spin/events/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_early_load.py b/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_early_load.py deleted file mode 100644 index 736ac45..0000000 --- a/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_early_load.py +++ /dev/null @@ -1,77 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent -from zone import Zone - - -class S4CLZoneEarlyLoadEvent(CommonEvent): - """S4CLZoneEarlyLoadEvent(zone, game_loaded=False, game_loading=False) - - An event that occurs when a Zone has loaded. - - .. note:: This event occurs before the :class:`.S4CLZoneLateLoadEvent` - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity().name) - def handle_event(event_data: S4CLZoneEarlyLoadEvent): - pass - - :param zone: The Zone that was loaded. - :type zone: Zone - :param game_loaded: A value indicating if the game has been loaded. - :type game_loaded: bool - :param game_loading: A value indicating if the game is currently loading. - :type game_loading: bool - """ - - def __init__(self, zone: Zone, game_loaded: bool=False, game_loading: bool=False): - self._zone = zone - self._game_loaded = game_loaded - self._game_loading = game_loading - - @property - def zone(self) -> Zone: - """The Zone that was loaded. - - :return: The Zone that was loaded. - :rtype: Zone - """ - return self._zone - - @property - def game_loaded(self) -> bool: - """Determine if the game has loaded. - - :return: True, if the game has loaded. False, if the game has not loaded. - :rtype: bool - """ - return self._game_loaded - - @property - def game_loading(self) -> bool: - """Determine if the game is loading. - - :return: True, if the game is currently loading. False, if the game is not currently loading. - :rtype: bool - """ - return self._game_loading diff --git a/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_late_load.py b/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_late_load.py deleted file mode 100644 index 9d4a330..0000000 --- a/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_late_load.py +++ /dev/null @@ -1,101 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent -from zone import Zone - - -class S4CLZoneLateLoadEvent(CommonEvent): - """S4CLZoneLateLoadEvent(zone, household_id, active_sim_id, game_loaded=False, game_loading=False) - - An event that occurs when a Zone has finished spinning up. - - .. note:: This event occurs after the :class:`.S4CLZoneEarlyLoadEvent` and before the :class:`.S4CLZoneFinishedLoadEvent` - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity().name) - def handle_event(event_data: S4CLZoneLateLoadEvent): - pass - - :param zone: The Zone that has finished spinning up. - :type zone: Zone - :param household_id: The identifier of the Household that owns the Zone. - :type household_id: int - :param active_sim_id: The identifier of the Active Sim. - :type active_sim_id: int - :param game_loaded: A value indicating if the game has been loaded. - :type game_loaded: bool - :param game_loading: A value indicating if the game is currently loading. - :type game_loading: bool - """ - - def __init__(self, zone: Zone, household_id: int, active_sim_id: int, game_loaded: bool=False, game_loading: bool=False): - self._zone = zone - self._household_id = household_id - self._active_sim_id = active_sim_id - self._game_loaded = game_loaded - self._game_loading = game_loading - - @property - def zone(self) -> Zone: - """The Zone that has finished spinning up. - - :return: The Zone that has finished spinning up. - :rtype: Zone - """ - return self._zone - - @property - def household_id(self) -> int: - """The identifier of the Household that owns the Zone. - - :return: The identifier of the Household that owns the Zone. - :rtype: int - """ - return self._household_id - - @property - def active_sim_id(self) -> int: - """The identifier of the Active Sim. - - :return: The identifier of the Active Sim. - :rtype: int - """ - return self._active_sim_id - - @property - def game_loaded(self) -> bool: - """Determine if the game has loaded. - - :return: True, if the game has loaded. False, if the game has not loaded. - :rtype: bool - """ - return self._game_loaded - - @property - def game_loading(self) -> bool: - """Determine if the game is loading. - - :return: True, if the game is currently loading. False, if the game is not currently loading. - :rtype: bool - """ - return self._game_loading diff --git a/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_manager_start_event.py b/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_manager_start_event.py deleted file mode 100644 index 6998352..0000000 --- a/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_manager_start_event.py +++ /dev/null @@ -1,51 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent -from zone_manager import ZoneManager - - -class S4CLZoneManagerStartEvent(CommonEvent): - """S4CLZoneManagerStartEvent(zone_manager) - - An event that occurs after the Zone Manager is started. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity().name) - def handle_event(event_data: S4CLZoneManagerStartEvent): - pass - - :param zone_manager: The Zone Manager. - :type zone_manager: ZoneManager - """ - - def __init__(self, zone_manager: ZoneManager): - self._zone_manager = zone_manager - - @property - def zone_manager(self) -> ZoneManager: - """The Zone Manager - - :return: The Zone Manager. - :rtype: ZoneManager - """ - return self._zone_manager \ No newline at end of file diff --git a/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_post_load.py b/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_post_load.py deleted file mode 100644 index 9157efa..0000000 --- a/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_post_load.py +++ /dev/null @@ -1,75 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent -from zone import Zone - - -class S4CLZonePostLoadEvent(CommonEvent): - """S4CLZonePostLoadEvent(zone, game_loaded=False, game_loading=False) - - An event that occurs when the Zone has finished loading and the loading screen is no longer visible. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity().name) - def handle_event(event_data: S4CLZonePostLoadEvent): - pass - - :param zone: The Zone that was loaded. - :type zone: Zone - :param game_loaded: A value indicating if the game has been loaded. - :type game_loaded: bool - :param game_loading: A value indicating if the game is currently loading. - :type game_loading: bool - """ - - def __init__(self, zone: Zone, game_loaded: bool=False, game_loading: bool=False): - self._zone = zone - self._game_loaded = game_loaded - self._game_loading = game_loading - - @property - def zone(self) -> Zone: - """The Zone that was loaded. - - :return: The Zone that was loaded. - :rtype: Zone - """ - return self._zone - - @property - def game_loaded(self) -> bool: - """Determine if the game has loaded at least once. - - :return: True, if the game has loaded at least once. False, if the game has not loaded. - :rtype: bool - """ - return self._game_loaded - - @property - def game_loading(self) -> bool: - """Determine if the game is loading. - - :return: True, if the game is currently loading. False, if the game is not currently loading. - :rtype: bool - """ - return self._game_loading diff --git a/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_save.py b/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_save.py deleted file mode 100644 index 6c70938..0000000 --- a/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_save.py +++ /dev/null @@ -1,93 +0,0 @@ -""" -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 -""" -from typing import Any - -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent -from zone import Zone - - -class S4CLZoneSaveEvent(CommonEvent): - """S4CLZoneSaveEvent(zone, save_slot_data=None, game_loaded=False, game_loading=False) - - An event that occurs upon a Zone being saved (Before it has been saved). - - .. note:: This event can occur when the Player is saving the game, switching save files, or traveling to a new zone. - - .. warning:: This event will also occur when the Player closes the game without saving. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity().name) - def handle_event(event_data: S4CLZoneSaveEvent): - pass - - :param zone: The Zone being saved. - :type zone: Zone - :param save_slot_data: The data that will be saved. - :type save_slot_data: Any - :param game_loaded: A value indicating if the game has been loaded. - :type game_loaded: bool - :param game_loading: A value indicating if the game is currently loading. - :type game_loading: bool - """ - - def __init__(self, zone: Zone, save_slot_data: Any=None, game_loaded: bool=False, game_loading: bool=False): - self._zone = zone - self._save_slot_data = save_slot_data - self._game_loaded = game_loaded - self._game_loading = game_loading - - @property - def zone(self) -> Zone: - """The Zone being saved. - - :return: The Zone being saved. - :rtype: Zone - """ - return self._zone - - @property - def save_slot_data(self) -> Any: - """The data that will be saved. - - :return: The data that will be saved. - :rtype: Any - """ - return self._save_slot_data - - @property - def game_loaded(self) -> bool: - """Determine if the game has loaded. - - :return: True, if the game has loaded. False, if the game has not loaded. - :rtype: bool - """ - return self._game_loaded - - @property - def game_loading(self) -> bool: - """Determine if the game is loading. - - :return: True, if the game is currently loading. False, if the game is not currently loading. - :rtype: bool - """ - return self._game_loading diff --git a/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_teardown.py b/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_teardown.py deleted file mode 100644 index 32faa73..0000000 --- a/Scripts/s4ap/sims4communitylib/events/zone_spin/events/zone_teardown.py +++ /dev/null @@ -1,92 +0,0 @@ -""" -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 -""" -from server.client import Client -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent -from zone import Zone - - -class S4CLZoneTeardownEvent(CommonEvent): - """S4CLZoneTeardownEvent(zone, client, game_loaded=False, game_loading=False) - - An event that occurs upon a Zone being saved (Before it has been torn down). - - .. note:: This event can occur when the Player travels to another lot. - - .. warning:: This event will also occur when the Player closes the game without saving. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity().name) - def handle_event(event_data: S4CLZoneTeardownEvent): - pass - - :param zone: The Zone being torn down. - :type zone: Zone - :param client: An instance of the Client. - :type client: Client - :param game_loaded: A value indicating if the game has been loaded. - :type game_loaded: bool - :param game_loading: A value indicating if the game is currently loading. - :type game_loading: bool - """ - - def __init__(self, zone: Zone, client: Client, game_loaded: bool=False, game_loading: bool=False): - self._zone = zone - self._client = client - self._game_loaded = game_loaded - self._game_loading = game_loading - - @property - def zone(self) -> Zone: - """The Zone being torn down. - - :return: The Zone being torn down. - :rtype: Zone - """ - return self._zone - - @property - def client(self) -> Client: - """An instance of the Client. - - :return: An instance of the Client. - :rtype: Client - """ - return self._client - - @property - def game_loaded(self) -> bool: - """Determine if the game has loaded. - - :return: True, if the game has loaded. False, if the game has not loaded. - :rtype: bool - """ - return self._game_loaded - - @property - def game_loading(self) -> bool: - """Determine if the game is loading. - - :return: True, if the game is currently loading. False, if the game is not currently loading. - :rtype: bool - """ - return self._game_loading diff --git a/Scripts/s4ap/sims4communitylib/events/zone_update/__init__.py b/Scripts/s4ap/sims4communitylib/events/zone_update/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/events/zone_update/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/events/zone_update/common_zone_update_event_dispatcher.py b/Scripts/s4ap/sims4communitylib/events/zone_update/common_zone_update_event_dispatcher.py deleted file mode 100644 index 83001be..0000000 --- a/Scripts/s4ap/sims4communitylib/events/zone_update/common_zone_update_event_dispatcher.py +++ /dev/null @@ -1,81 +0,0 @@ -""" -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 -""" -import math -from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from s4ap.sims4communitylib.events.zone_update.events.zone_update_event import S4CLZoneUpdateEvent -from s4ap.sims4communitylib.logging.has_log import HasLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.common_service import CommonService -from s4ap.sims4communitylib.utils.common_injection_utils import CommonInjectionUtils -from s4ap.sims4communitylib.utils.common_time_utils import CommonTimeUtils -from zone import Zone - - -class CommonZoneUpdateEventDispatcherService(CommonService, HasLog): - """A service that dispatches zone update events. - - .. warning:: Do not use this service directly to listen for events!\ - Use the :class:`.CommonEventRegistry` to listen for dispatched events. - - """ - - # noinspection PyMissingOrEmptyDocstring - @property - def mod_identity(self) -> CommonModIdentity: - return ModInfo.get_identity() - - def __init__(self: 'CommonZoneUpdateEventDispatcherService'): - super().__init__() - self._last_absolute_ticks = 0 - self._ticks_since_last_zone_update = 0 - self._ticks_since_last_zone_update_error = 0 - - @property - def ticks_since_last_zone_update(self) -> int: - """The amount of time that has passed since the last zone update. - - :return: The amount of time that has passed in milliseconds - :rtype: int - """ - return self._ticks_since_last_zone_update - - @ticks_since_last_zone_update.setter - def ticks_since_last_zone_update(self, val: int): - self._ticks_since_last_zone_update = val - - def _update_ticks(self, diff_ticks: int): - if diff_ticks > 5000: - diff_ticks = 5000 - ideal_diff_ticks = diff_ticks * CommonTimeUtils.get_clock_speed_scale() + self._ticks_since_last_zone_update_error - rounded_ticks = math.floor(ideal_diff_ticks + 0.5) - ticks_error = ideal_diff_ticks - rounded_ticks - self._ticks_since_last_zone_update_error += max(min(ticks_error, 1), -1) - self.ticks_since_last_zone_update = rounded_ticks - - def _on_zone_update(self, zone: Zone, absolute_ticks: int): - try: - if not zone.is_zone_running: - return False - is_paused = CommonTimeUtils.game_is_paused() - if not is_paused: - diff_ticks = absolute_ticks - self._last_absolute_ticks - if diff_ticks < 0: - return False - self._update_ticks(diff_ticks) - self._last_absolute_ticks = absolute_ticks - return CommonEventRegistry.get().dispatch(S4CLZoneUpdateEvent(zone, is_paused, self.ticks_since_last_zone_update)) - except Exception as ex: - self.log.error('Failed to run internal method \'{}\' at \'{}\'.'.format(CommonZoneUpdateEventDispatcherService._on_zone_update.__name__, Zone.update.__name__), exception=ex) - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity().name, Zone, Zone.update.__name__, handle_exceptions=False) -def _common_zone_update(original, self: Zone, *_, **__): - result = original(self, *_, **__) - CommonZoneUpdateEventDispatcherService.get()._on_zone_update(self, *_, **__) - return result diff --git a/Scripts/s4ap/sims4communitylib/events/zone_update/events/__init__.py b/Scripts/s4ap/sims4communitylib/events/zone_update/events/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/events/zone_update/events/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/events/zone_update/events/zone_update_event.py b/Scripts/s4ap/sims4communitylib/events/zone_update/events/zone_update_event.py deleted file mode 100644 index 6897aa8..0000000 --- a/Scripts/s4ap/sims4communitylib/events/zone_update/events/zone_update_event.py +++ /dev/null @@ -1,77 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.events.event_handling.common_event import CommonEvent -from zone import Zone - - -class S4CLZoneUpdateEvent(CommonEvent): - """S4CLZoneUpdateEvent(zone, is_paused, ticks_since_last_update) - - An event that occurs when a Zone has been updated. - - .. note:: This event can occur while the game is paused. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry - from s4ap.sims4communitylib.modinfo import ModInfo - - class ExampleEventListener: - - # In order to listen to an event, your function must match these criteria: - # - The function is static (staticmethod). - # - The first and only required argument has the name "event_data". - # - The first and only required argument has the Type Hint for the event you are listening for. - # - The argument passed to "handle_events" is the name of your Mod. - @staticmethod - @CommonEventRegistry.handle_events(ModInfo.get_identity().name) - def handle_event(event_data: S4CLZoneUpdateEvent): - pass - - :param zone: The Zone that was updated. - :type zone: Zone - :param is_paused: A value indicating if the game was paused during the dispatching of this event. - :type is_paused: bool - :param ticks_since_last_update: The number of ticks since the last zone update in milliseconds. - :type ticks_since_last_update: int - """ - - def __init__(self, zone: Zone, is_paused: bool, ticks_since_last_update: int): - self._zone = zone - self._is_paused = is_paused - self._ticks_since_last_update = ticks_since_last_update - - @property - def zone(self) -> Zone: - """The Zone that was updated. - - :return: The Zone that was updated. - :rtype: Zone - """ - return self._zone - - @property - def is_paused(self) -> bool: - """Determine if the game was paused during the update. - - :return: True, if the game was paused. False, if the game was not paused. - :rtype: bool - """ - return self._is_paused - - @property - def ticks_since_last_update(self) -> int: - """The number of ticks in milliseconds since the last zone update. - - :return: The number of ticks in milliseconds since the last zone update. - :rtype: int - """ - return self._ticks_since_last_update diff --git a/Scripts/s4ap/sims4communitylib/examples/__init__.py b/Scripts/s4ap/sims4communitylib/examples/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/examples/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/examples/common_example_apply_bare_feet_buff.py b/Scripts/s4ap/sims4communitylib/examples/common_example_apply_bare_feet_buff.py deleted file mode 100644 index c85713b..0000000 --- a/Scripts/s4ap/sims4communitylib/examples/common_example_apply_bare_feet_buff.py +++ /dev/null @@ -1,140 +0,0 @@ -""" -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 -""" -from typing import Tuple - -from buffs.appearance_modifier.appearance_modifier import AppearanceModifier -from buffs.buff import Buff -from sims.sim_info import SimInfo -from sims4.tuning.tunable import TunableList, TunableTuple, TunableVariant, OptionalTunable -from s4ap.sims4communitylib.classes.appearance_modifiers.common_attach_cas_parts_appearance_modifier import \ - CommonAttachCASPartsAppearanceModifier -from s4ap.sims4communitylib.dtos.common_cas_part import CommonCASPart -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.utils.cas.common_cas_utils import CommonCASUtils -from s4ap.sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils -from s4ap.sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils -from s4ap.sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils -from tunable_multiplier import TunableMultiplier - - -class CommonExampleApplyBareFeetAppearanceModifier(AppearanceModifier): - """An appearance modifier that applies bare feet to a Sim.""" - - class CommonAttachBareFeetModifier(CommonAttachCASPartsAppearanceModifier): - """Apply bare feet to a Sim.""" - # noinspection PyMissingOrEmptyDocstring - @property - def mod_identity(self) -> CommonModIdentity: - return ModInfo.get_identity() - - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - return 'common_example_apply_bare_feet' - - def _get_cas_parts( - self, - source_sim_info: SimInfo, - modified_sim_info: SimInfo, - original_unmodified_sim_info: SimInfo, - random_seed: int - ) -> Tuple[CommonCASPart]: - # Human - # yfShoes_Nude - adult_human_female_bare_feet_id = 6543 - # ymShoes_Nude - adult_human_male_bare_feet_id = 6563 - # cuShoes_Nude - child_human_bare_feet_id = 22018 - # puShoes_Nude - toddler_human_bare_feet_id = 132818 - - # Dog - # adShoes_Nude - adult_large_dog_bare_feet_id = 125251 - # alShoes_Nude - adult_small_dog_bare_feet_id = 148839 - # cdShoes_Nude - child_dog_bare_feet_id = 158046 - - # Cat - # acShoes_Nude - adult_cat_bare_feet_id = 150367 - # ccShoes_Nude - child_cat_bare_feet_id = 164111 - - # Fox - adult_fox_bare_feet_id = 277492 - - # Horse - adult_horse_bare_feet_id = 337140 - child_horse_bare_feet_id = 343457 - - bare_feet_cas_part_id = None - if CommonAgeUtils.is_teen_adult_or_elder(original_unmodified_sim_info): - if CommonSpeciesUtils.is_human(original_unmodified_sim_info): - if CommonGenderUtils.is_female(original_unmodified_sim_info): - bare_feet_cas_part_id = adult_human_female_bare_feet_id - elif CommonGenderUtils.is_male(original_unmodified_sim_info): - bare_feet_cas_part_id = adult_human_male_bare_feet_id - elif CommonSpeciesUtils.is_large_dog(original_unmodified_sim_info): - bare_feet_cas_part_id = adult_large_dog_bare_feet_id - elif CommonSpeciesUtils.is_small_dog(original_unmodified_sim_info): - bare_feet_cas_part_id = adult_small_dog_bare_feet_id - elif CommonSpeciesUtils.is_cat(original_unmodified_sim_info): - bare_feet_cas_part_id = adult_cat_bare_feet_id - elif CommonSpeciesUtils.is_fox(original_unmodified_sim_info): - bare_feet_cas_part_id = adult_fox_bare_feet_id - elif CommonSpeciesUtils.is_horse(original_unmodified_sim_info): - bare_feet_cas_part_id = adult_horse_bare_feet_id - elif CommonAgeUtils.is_child(original_unmodified_sim_info): - if CommonSpeciesUtils.is_human(original_unmodified_sim_info): - bare_feet_cas_part_id = child_human_bare_feet_id - elif CommonSpeciesUtils.is_large_dog(original_unmodified_sim_info) or CommonSpeciesUtils.is_small_dog(original_unmodified_sim_info): - bare_feet_cas_part_id = child_dog_bare_feet_id - elif CommonSpeciesUtils.is_cat(original_unmodified_sim_info): - bare_feet_cas_part_id = child_cat_bare_feet_id - elif CommonSpeciesUtils.is_horse(original_unmodified_sim_info): - bare_feet_cas_part_id = child_horse_bare_feet_id - elif CommonAgeUtils.is_toddler(original_unmodified_sim_info): - bare_feet_cas_part_id = toddler_human_bare_feet_id - - if bare_feet_cas_part_id is None: - return tuple() - - return CommonCASPart(bare_feet_cas_part_id, CommonCASUtils.get_body_type_of_cas_part(bare_feet_cas_part_id)), - - # We override the original "appearance_modifiers" to so we can insert our custom appearance modifier. - FACTORY_TUNABLES = { - 'appearance_modifiers': TunableList( - description='\n The specific appearance modifiers to use for this buff.\n ', - tunable=TunableList( - description='\n A tunable list of weighted modifiers. When applying modifiers\n one of the modifiers in this list will be applied. The weight\n will be used to run a weighted random selection.\n ', - tunable=TunableTuple( - description='\n A Modifier to apply and weight for the weighted random \n selection.\n ', - modifier=TunableVariant( - custom_bare_feet_modifier=CommonAttachBareFeetModifier.TunableFactory(), - ), - weight=TunableMultiplier.TunableFactory( - description='\n A weight with testable multipliers that is used to \n determine how likely this entry is to be picked when \n selecting randomly.\n ' - ) - ) - ) - ) - } - - -# We use this buff in a Buff tuning and then apply the buff to the Sim. -class CommonExampleApplyBareFeetBuff(Buff): - """A buff that applies bare feet to a Sim.""" - - # We override the original "appearance_modifier" to so we can insert our custom appearance modifier. - INSTANCE_TUNABLES = { - 'appearance_modifier': OptionalTunable(CommonExampleApplyBareFeetAppearanceModifier.TunableFactory()), - } diff --git a/Scripts/s4ap/sims4communitylib/exceptions/__init__.py b/Scripts/s4ap/sims4communitylib/exceptions/__init__.py deleted file mode 100644 index 3251898..0000000 --- a/Scripts/s4ap/sims4communitylib/exceptions/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" \ No newline at end of file diff --git a/Scripts/s4ap/sims4communitylib/exceptions/common_exceptions_handler.py b/Scripts/s4ap/sims4communitylib/exceptions/common_exceptions_handler.py deleted file mode 100644 index f56c56a..0000000 --- a/Scripts/s4ap/sims4communitylib/exceptions/common_exceptions_handler.py +++ /dev/null @@ -1,102 +0,0 @@ -""" -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 -""" -from functools import wraps -from typing import Any, Callable, Union -from s4ap.sims4communitylib.exceptions.common_stacktrace_utils import CommonStacktraceUtil -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.utils.common_date_utils import CommonRealDateUtils -from s4ap.sims4communitylib.utils.common_io_utils import CommonIOUtils - - -class CommonExceptionHandler: - """A class for catching and logging exceptions to a file on the system. - - """ - - @staticmethod - def log_exception(mod_identifier: Union[str, CommonModIdentity, None], exception_message: str, exception: Exception=None, custom_file_path: str=None) -> bool: - """log_exception(mod_identifier, exception_message, exception=None, custom_file_path=None) - - Manually log an exception with a custom message. - - :param mod_identifier: The name or identity of the mod logging the exception. - :type mod_identifier: Union[str, CommonModIdentity] - :param exception_message: A message to provide more information about the exception. - :type exception_message: str - :param exception: The exception being logged. Default is None. - :type exception: Exception, optional - :param custom_file_path: A custom file path relative to The Sims 4 folder. Example: Value is 'fake_path/to/directory', the final path would be 'The Sims 4/fake_path/to_directory'. Default is None. - :type custom_file_path: str, optional - :return: True, if the message was successfully logged. False, if the message was not successfully logged. - :rtype: bool - """ - from s4ap.sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils - mod_identifier = CommonModIdentityUtils.determine_mod_name_from_identifier(mod_identifier) - exceptions = CommonStacktraceUtil.get_full_stack_trace() - stack_trace = '{}{} -> {}: {}\n'.format(''.join(exceptions), exception_message, type(exception).__name__, exception) - from s4ap.sims4communitylib.utils.common_log_registry import CommonLogUtils - file_path = CommonLogUtils.get_exceptions_file_path(mod_identifier, custom_file_path=custom_file_path) - result = CommonExceptionHandler._log_stacktrace(mod_identifier, stack_trace, file_path) - if result: - CommonExceptionHandler._notify_exception_occurred(file_path, mod_identifier=mod_identifier) - return result - - @staticmethod - def catch_exceptions(mod_identifier: Union[str, CommonModIdentity], fallback_return: Any=None) -> Callable[..., Any]: - """catch_exceptions(mod_identifier, fallback_return=None) - - Automatically catch exceptions thrown by the decorated function, log them to a file, and notify the player about the exception. - - .. note:: Decorate functions with this decorator to catch and log exceptions - - :param mod_identifier: The name or identity of the mod catching exceptions. - :type mod_identifier: Union[str, CommonModIdentity] - :param fallback_return: A value to return upon an exception being caught. Default is None. - :type fallback_return: Any, optional - :return: A function wrapped to catch and log exceptions. - :rtype: Callable[..., Any] - """ - from s4ap.sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils - mod_identifier = CommonModIdentityUtils.determine_mod_name_from_identifier(mod_identifier) - - def _catch_exception(exception_function: Callable[..., Any]): - @wraps(exception_function) - def _wrapper(*args, **kwargs) -> Any: - try: - return exception_function(*args, **kwargs) - except Exception as ex: - CommonExceptionHandler.log_exception(mod_identifier, 'Exception caught while invoking: {}'.format(exception_function.__name__), exception=ex) - return fallback_return - return _wrapper - return _catch_exception - - @staticmethod - def _log_stacktrace(mod_identifier: Union[str, CommonModIdentity], _traceback: str, file_path: str) -> bool: - from s4ap.sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils - mod_identifier = CommonModIdentityUtils.determine_mod_name_from_identifier(mod_identifier) - exception_traceback_text = '[{}] {} {}\n'.format(mod_identifier, CommonRealDateUtils.get_current_date_string(), _traceback) - return CommonIOUtils.write_to_file(file_path, exception_traceback_text, ignore_errors=True) - - @staticmethod - def _notify_exception_occurred(file_path: str, mod_identifier: Union[str, CommonModIdentity]=None): - from ui.ui_dialog_notification import UiDialogNotification - from s4ap.sims4communitylib.notifications.common_basic_notification import CommonBasicNotification - from s4ap.sims4communitylib.enums.strings_enum import CommonStringId - from s4ap.sims4communitylib.events.zone_spin.common_zone_spin_event_dispatcher import CommonZoneSpinEventDispatcher - if not CommonZoneSpinEventDispatcher.get().game_loaded: - return - from s4ap.sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils - mod_identifier = CommonModIdentityUtils.determine_mod_name_from_identifier(mod_identifier) - basic_notification = CommonBasicNotification( - CommonStringId.EXCEPTION_OCCURRED_TITLE_FOR_MOD, - CommonStringId.EXCEPTION_OCCURRED_TEXT, - title_tokens=(mod_identifier,), - description_tokens=(file_path,), - urgency=UiDialogNotification.UiDialogNotificationUrgency.URGENT - ) - basic_notification.show() diff --git a/Scripts/s4ap/sims4communitylib/exceptions/common_stacktrace_utils.py b/Scripts/s4ap/sims4communitylib/exceptions/common_stacktrace_utils.py deleted file mode 100644 index 68483f7..0000000 --- a/Scripts/s4ap/sims4communitylib/exceptions/common_stacktrace_utils.py +++ /dev/null @@ -1,73 +0,0 @@ -""" -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 -""" -import sys -import traceback -from collections import namedtuple -from typing import Union, Any, List - -# The following was tweaked slightly from the publicly made available, copyright free code here: https://stackoverflow.com/questions/13210436/get-full-traceback -from s4ap.sims4communitylib.utils.common_collection_utils import CommonCollectionUtils - -FullTraceback = namedtuple('FullTraceback', ('tb_frame', 'tb_lineno', 'tb_next')) - - -class CommonStacktraceUtil: - """Utilities for accessing the full stack trace of your application. - - """ - @staticmethod - def current_stack(skip: int=0) -> Any: - """Retrieve the current stack - - :param skip: The number of lines to skip - :return: A collection of the current stack. - """ - cur_frame = None - try: - 1/0 - except ZeroDivisionError: - cur_frame = sys.exc_info()[2].tb_frame - for i in range(skip + 2): - cur_frame = cur_frame.f_back - stack_trace = [] - while cur_frame is not None: - stack_trace.append((cur_frame, cur_frame.f_lineno)) - cur_frame = cur_frame.f_back - return stack_trace - - @staticmethod - def _extend_traceback(tb, stack) -> FullTraceback: - """Extend traceback with stack info. - - """ - head = tb - for traceback_frame, traceback_line_number in stack: - head = FullTraceback(traceback_frame, traceback_line_number, head) - return head - - @staticmethod - def full_exception_info() -> Union[type, Any, FullTraceback]: - """Like sys.exc_info, but includes the full traceback. - - """ - exception_type, exception_value, exception_traceback = sys.exc_info() - full_traceback = CommonStacktraceUtil._extend_traceback(exception_traceback, CommonStacktraceUtil.current_stack(1)) - return exception_type, exception_value, full_traceback - - @staticmethod - def get_full_stack_trace() -> List[str]: - """Retrieve the full stacktrace from the current stack. - - :return: A collection of stack trace strings. - """ - exception_info = CommonStacktraceUtil.full_exception_info() - if CommonCollectionUtils.is_collection(exception_info): - exceptions = traceback.format_exception(*exception_info) - else: - exceptions = traceback.format_stack() - return exceptions diff --git a/Scripts/s4ap/sims4communitylib/exceptions/generic_error_handling.py b/Scripts/s4ap/sims4communitylib/exceptions/generic_error_handling.py deleted file mode 100644 index 07419df..0000000 --- a/Scripts/s4ap/sims4communitylib/exceptions/generic_error_handling.py +++ /dev/null @@ -1,34 +0,0 @@ -""" -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 -""" -from pprint import pformat - -from broadcasters.broadcaster import Broadcaster -from s4ap.sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.utils.common_injection_utils import CommonInjectionUtils -from s4ap.sims4communitylib.utils.resources.common_interaction_utils import CommonInteractionUtils - - -# Some interactions cause an error in this function, this is here to catch those errors and provide more information about them. -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), Broadcaster, Broadcaster.apply_broadcaster_effect.__name__, handle_exceptions=False) -def _common_broadcaster_apply(original, self: Broadcaster, *_, **__) -> None: - try: - return original(self, *_, **__) - except Exception as ex: - if self.interaction is not None: - interaction = self.interaction - # noinspection PyTypeChecker - CommonExceptionHandler.log_exception(None, 'Error occurred while running apply_broadcaster_effect for broadcaster {} for interaction {} with short name {} and display name {} (This exception is not caused by S4CL, but rather caught)'.format(pformat(self), pformat(interaction), CommonInteractionUtils.get_interaction_short_name(interaction), CommonInteractionUtils.get_interaction_display_name(interaction)), exception=ex) - elif self.broadcasting_object is not None: - broadcasting_object = self.broadcasting_object - # noinspection PyTypeChecker - CommonExceptionHandler.log_exception(None, 'Error occurred while running apply_broadcaster_effect for broadcaster {} from object {} (This exception is not caused by S4CL, but rather caught)'.format(pformat(self), pformat(broadcasting_object)), exception=ex) - else: - # noinspection PyTypeChecker - CommonExceptionHandler.log_exception(None, 'Error occurred while running apply_broadcaster_effect for broadcaster {} (This exception is not caused by S4CL, but rather caught)'.format(pformat(self)), exception=ex) - return None diff --git a/Scripts/s4ap/sims4communitylib/logging/__init__.py b/Scripts/s4ap/sims4communitylib/logging/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/logging/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/logging/_has_s4cl_class_log.py b/Scripts/s4ap/sims4communitylib/logging/_has_s4cl_class_log.py deleted file mode 100644 index 36ea009..0000000 --- a/Scripts/s4ap/sims4communitylib/logging/_has_s4cl_class_log.py +++ /dev/null @@ -1,28 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.logging.has_class_log import HasClassLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo - - -class _HasS4CLClassLog(HasClassLog): - """_HasS4CLClassLog() - - .. note:: This class should only be used by S4CL itself, do not inherit from this class in your own mods! - - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - return ModInfo.get_identity() - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - raise NotImplementedError() diff --git a/Scripts/s4ap/sims4communitylib/logging/_has_s4cl_log.py b/Scripts/s4ap/sims4communitylib/logging/_has_s4cl_log.py deleted file mode 100644 index ad77de9..0000000 --- a/Scripts/s4ap/sims4communitylib/logging/_has_s4cl_log.py +++ /dev/null @@ -1,28 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.logging.has_log import HasLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo - - -class _HasS4CLLog(HasLog): - """_HasS4CLLog() - - .. note:: This class should only be used by S4CL itself, do not inherit from this class in your own mods! - - """ - - # noinspection PyMissingOrEmptyDocstring - @property - def mod_identity(self) -> CommonModIdentity: - return ModInfo.get_identity() - - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - raise NotImplementedError() diff --git a/Scripts/s4ap/sims4communitylib/logging/_logging_commands.py b/Scripts/s4ap/sims4communitylib/logging/_logging_commands.py deleted file mode 100644 index 67ca379..0000000 --- a/Scripts/s4ap/sims4communitylib/logging/_logging_commands.py +++ /dev/null @@ -1,156 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ - CommonConsoleCommandArgument -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.common_log_registry import CommonLogRegistry - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.enable_log', - 'Enable a log. Once enabled, any code that uses the functions of the log will starting logging their messages to "The Sims 4/mod_logs/modname_Messages.txt"', - command_arguments=( - CommonConsoleCommandArgument('log_name', 'Text', 'The name of a log to enable.'), - CommonConsoleCommandArgument('mod_name', 'Text', 'The name of the mod to enable the log for. If a log is not available for a mod, but you know it exists, specify this argument to enable it without having to wait for the log itself to be used in the code first. If not specified, then the log will be enabled for all mods.', is_optional=True, default_value='All Mods'), - ), - command_aliases=( - 's4clib.enablelog', - ) -) -def _common_command_enable_log(output: CommonConsoleCommandOutput, log_name: str, mod_name: str=None): - if log_name is None: - output('ERROR: No log name specified (See all logs via "s4clib.logs" command)') - return - if mod_name is None: - output(f'Attempting to enable log \'{log_name}\'.') - else: - output(f'Attempting to enable log \'{log_name}\' for mod \'{mod_name}\'.') - if CommonLogRegistry.get().log_exists(log_name, mod_identifier=mod_name) or mod_name is not None: - if CommonLogRegistry.get().enable_logs(log_name, mod_identifier=mod_name): - if mod_name is None: - output(f'SUCCESS: Log \'{log_name}\' was successfully enabled.') - else: - output(f'SUCCESS: Log \'{log_name}\' was successfully enabled for mod \'{mod_name}\'.') - else: - if mod_name is None: - output(f'FAILED: Failed to enable log \'{log_name}\'. Do you need to specify a mod name?') - else: - output(f'FAILED: Failed to enable log \'{log_name}\' for mod \'{mod_name}\'.') - else: - if mod_name is None: - output(f'ERROR: No log found with name \'{log_name}\'.') - else: - output(f'ERROR: No log found with name \'{log_name}\' for mod \'{mod_name}\'.') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.disable_log', - 'Disable a log. Once disabled, any code that uses the functions of the log will stop logging their messages to "The Sims 4/mod_logs/modname_Messages.txt"', - command_arguments=( - CommonConsoleCommandArgument('log_name', 'Text', 'The name of a log to disable.'), - CommonConsoleCommandArgument('mod_name', 'Text', 'The name of the mod to disable the log for. If not specified, then the log will be disabled for all mods.', is_optional=True, default_value='All Mods'), - ), - command_aliases=( - 's4clib.disablelog', - ) -) -def _common_command_disable_log(output: CommonConsoleCommandOutput, log_name: str, mod_name: str=None): - if log_name is None: - output('specify a log name (See all logs via "s4clib.logs" command)') - return - if mod_name is None: - output(f'Attempting to disable log \'{log_name}\'.') - else: - output(f'Attempting to disable log \'{log_name}\' for mod \'{mod_name}\'.') - if CommonLogRegistry().log_exists(log_name, mod_identifier=mod_name): - if CommonLogRegistry().disable_logs(log_name, mod_identifier=mod_name): - if mod_name is None: - output(f'SUCCESS: Log \'{log_name}\' was successfully disabled.') - else: - output(f'SUCCESS: Log \'{log_name}\' was successfully disabled for mod \'{mod_name}\'.') - else: - if mod_name is None: - output(f'Failed to disable log \'{log_name}\'. Do you need to specify a mod name?') - else: - output(f'Failed to disable log \'{log_name}\' for mod \'{mod_name}\'.') - else: - if mod_name is None: - output(f'ERROR: Log \'{log_name}\' did not exist.') - else: - output(f'ERROR: Log \'{log_name}\' did not exist for mod \'{mod_name}\'.') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.disable_all_logs', - 'Disable all logs.', - command_arguments=( - CommonConsoleCommandArgument('mod_name', 'Text', 'The name of the mod to disable logs for. If not specified, then logs will be disabled for all mods.', is_optional=True, default_value='All Mods'), - ), - command_aliases=( - 's4clib.disablealllogs', - ) -) -def _common_command_disable_all_logs(output: CommonConsoleCommandOutput, mod_name: str=None): - if mod_name is None: - output('Disabling all logs.') - else: - output(f'Disabling all logs for mod \'{mod_name}\'.') - CommonLogRegistry.get().disable_all_logs(mod_identifier=mod_name) - if mod_name is None: - output(f'SUCCESS: All logs successfully disabled.') - else: - output(f'SUCCESS: All logs for mod \'{mod_name}\' successfully disabled.') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.enablealllogs', - 'Enable all logs.', - command_arguments=( - CommonConsoleCommandArgument('mod_name', 'Text', 'The name of the mod to enable logs for. If not specified, then logs will be enabled for all mods.', is_optional=True, default_value='All Mods'), - ), - command_aliases=( - 's4clib.enablealllogs', - ) -) -def _common_command_enable_all_logs(output: CommonConsoleCommandOutput, mod_name: str=None): - if mod_name is None: - output(f'Attempting to enable all logs.') - else: - output(f'Attempting to enable log for mod \'{mod_name}\'.') - CommonLogRegistry.get().enable_all_logs(mod_identifier=mod_name) - if mod_name is None: - output(f'SUCCESS: All logs successfully enabled.') - else: - output(f'SUCCESS: All logs for mod \'{mod_name}\' successfully enabled.') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.logs', - 'Print a list of all available logs.', - command_arguments=( - CommonConsoleCommandArgument('mod_name', 'Text', 'If specified, all logs related to the specified mod will be listed. If not specified, all logs will be listed.', is_optional=True, default_value=None), - ) -) -def _common_command_show_all_logs(output: CommonConsoleCommandOutput, mod_name: str=None): - log_names = CommonLogRegistry.get().get_registered_log_names(mod_identifier=mod_name) - if log_names is None: - return - if not log_names: - if mod_name is None: - output(f'FAILED: No mods have registered any logs') - else: - output(f'FAILED: \'{mod_name} has not registered any logs') - return - for log_name in log_names: - output(str(log_name)) diff --git a/Scripts/s4ap/sims4communitylib/logging/has_class_log.py b/Scripts/s4ap/sims4communitylib/logging/has_class_log.py deleted file mode 100644 index daed666..0000000 --- a/Scripts/s4ap/sims4communitylib/logging/has_class_log.py +++ /dev/null @@ -1,132 +0,0 @@ -""" -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 -""" -from typing import TYPE_CHECKING - -from s4ap.sims4communitylib.logging.has_log import HasLog -from s4ap.sims4communitylib.mod_support.has_class_mod_identity import HasClassModIdentity -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity - -if TYPE_CHECKING: - from s4ap.sims4communitylib.utils.common_log_registry import CommonLog, CommonLogRegistry - - -class HasClassLog(HasClassModIdentity, HasLog): - """HasClassLog() - - An inheritable class that will add a log and mod identity to a class. - - .. note:: This class inherits from :class:`.HasLog` and may be used as an alternative to it. - - """ - def __init__(self) -> None: - super().__init__() - HasLog.__init__(self) - - # noinspection PyMissingOrEmptyDocstring - @property - def mod_identity(self) -> CommonModIdentity: - return self.__class__.get_mod_identity() - - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - return self.__class__.get_log_identifier() - - # noinspection PyMissingOrEmptyDocstring - @property - def verbose_log_identifier(self) -> str: - return self.__class__.get_verbose_log_identifier() - - # noinspection PyMissingOrEmptyDocstring - @property - def log(self) -> 'CommonLog': - return self.__class__.get_log() - - # noinspection PyMissingOrEmptyDocstring - @property - def verbose_log(self) -> 'CommonLog': - return self.__class__.get_verbose_log() - - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - """get_mod_identity() - - Retrieve the identity of the mod that owns the class. - - .. warning:: Override this function with the :class:`.CommonModIdentity` of your mod. - - This is a *MUST* override to allow for proper Exception Handling and Logging! - - :return: An instance of CommonModIdentity - :rtype: CommonModIdentity - :exception NotImplementedError: Thrown when the function is not implemented. - """ - raise NotImplementedError(f'Missing \'{cls.__name__}.get_mod_identity\'.') - - @classmethod - def get_log(cls) -> 'CommonLog': - """get_log() - - Retrieve a log for the class. - - .. note:: This function uses the :func:`~get_mod_identity` and :func:`~get_log_identifier` functions when logging. - - :return: An instance of CommonLog - :rtype: CommonLog - """ - from s4ap.sims4communitylib.utils.common_log_registry import CommonLogRegistry - if not hasattr(cls, '_log') or getattr(cls, '_log', None) is None: - setattr(cls, '_log', CommonLogRegistry().register_log(cls.get_mod_identity(), cls.get_log_identifier())) - if not hasattr(cls, '_verbose_log') or getattr(cls, '_verbose_log', None) is None: - setattr(cls, '_verbose_log', CommonLogRegistry().register_log(cls.get_mod_identity(), cls.get_verbose_log_identifier())) - return getattr(cls, '_log', None) - - @classmethod - def get_verbose_log(cls) -> 'CommonLog': - """get_verbose_log() - - Retrieve a verbose log for the class. - - .. note:: This function uses the :func:`~get_mod_identity` and :func:`~get_verbose_log_identifier` functions when logging. - - .. note:: This log can be used to log extra details that you don't want to appear when using the non verbose log. - - :return: An instance of CommonLog - :rtype: CommonLog - """ - from s4ap.sims4communitylib.utils.common_log_registry import CommonLogRegistry - if not hasattr(cls, '_verbose_log') or getattr(cls, '_verbose_log', None) is None: - setattr(cls, '_verbose_log', CommonLogRegistry().register_log(cls.get_mod_identity(), cls.get_verbose_log_identifier())) - return getattr(cls, '_verbose_log', None) - - @classmethod - def get_log_identifier(cls) -> str: - """get_log_identifier() - - A string identifier for the log of the class. - - .. note:: This is the text that will appear when logging messages. - - :return: The identifier for the log - :rtype: str - """ - return cls.__name__ - - @classmethod - def get_verbose_log_identifier(cls) -> str: - """get_verbose_log_identifier() - - A string identifier for the log of the class. - - .. note:: This is the text that will appear when logging messages. - - :return: The identifier for the log - :rtype: str - """ - log_identifier = cls.get_log_identifier() - return f'{log_identifier}_verbose' diff --git a/Scripts/s4ap/sims4communitylib/logging/has_log.py b/Scripts/s4ap/sims4communitylib/logging/has_log.py deleted file mode 100644 index d5f3525..0000000 --- a/Scripts/s4ap/sims4communitylib/logging/has_log.py +++ /dev/null @@ -1,93 +0,0 @@ -""" -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 -""" -from typing import TYPE_CHECKING, Union -from s4ap.sims4communitylib.mod_support.has_mod_identity import HasModIdentity -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity - -if TYPE_CHECKING: - from s4ap.sims4communitylib.utils.common_log_registry import CommonLog, CommonLogRegistry - - -class HasLog(HasModIdentity): - """HasLog() - - An inheritable class that will add a log and mod identity to a class. - - """ - def __init__(self) -> None: - self._log: Union['CommonLog', None] = None - self._verbose_log: Union['CommonLog', None] = None - self._mod_identity: Union[CommonModIdentity, None] = None - - @property - def mod_identity(self) -> CommonModIdentity: - """The identity of the mod that owns this property - - .. warning:: Override this property with the :class:`.CommonModIdentity` of your mod. - - This is a *MUST* override to allow for proper Exception Handling and Logging! - - :return: An instance of CommonModIdentity - :rtype: CommonModIdentity - :exception NotImplementedError: Thrown when the property is not implemented. - """ - raise NotImplementedError(f'Missing \'{self.__class__.__name__}.mod_identity\'.') - - @property - def verbose_log(self) -> 'CommonLog': - """The verbose log for instances of the class. - - .. note:: It uses the `mod_identity` and `verbose_log_identifier` when logging. - - .. note:: This log can be used to log extra details that you don't want to appear when using the non verbose log. - - :return: An instance of CommonLog - :rtype: CommonLog - """ - if self._verbose_log is None: - from s4ap.sims4communitylib.utils.common_log_registry import CommonLogRegistry - self._verbose_log = CommonLogRegistry.get().register_log(self.mod_identity, self.verbose_log_identifier) - return self._verbose_log - - @property - def log(self) -> 'CommonLog': - """The log for instances of the class. - - .. note:: It uses the `mod_identity` and `log_identifier` when logging. - - :return: An instance of CommonLog - :rtype: CommonLog - """ - if self._log is None: - from s4ap.sims4communitylib.utils.common_log_registry import CommonLogRegistry - self._log = CommonLogRegistry.get().register_log(self.mod_identity, self.log_identifier) - if self._verbose_log is None: - self._verbose_log = CommonLogRegistry.get().register_log(self.mod_identity, self.verbose_log_identifier) - return self._log - - @property - def log_identifier(self) -> str: - """A string identifier for the log used by instances of the class. - - .. note:: This is the message identifier that will appear when logging messages. - - :return: The identifier of the log - :rtype: str - """ - return self.__class__.__name__ - - @property - def verbose_log_identifier(self) -> str: - """A string identifier for the verbose log used by instances of the class. - - .. note:: This is the message identifier that will appear when logging messages. - - :return: The identifier of the verbose log - :rtype: str - """ - return f'{self.log_identifier}_verbose' diff --git a/Scripts/s4ap/sims4communitylib/logging/vanilla_logging.py b/Scripts/s4ap/sims4communitylib/logging/vanilla_logging.py deleted file mode 100644 index a2e754a..0000000 --- a/Scripts/s4ap/sims4communitylib/logging/vanilla_logging.py +++ /dev/null @@ -1,211 +0,0 @@ -""" -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 -""" -from typing import Any - -from sims4.log import Logger -from s4ap.sims4communitylib.classes.time.common_stop_watch import CommonStopWatch -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.s4cl_configuration import S4CLConfiguration -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.services.common_service import CommonService -from s4ap.sims4communitylib.utils.common_injection_utils import CommonInjectionUtils -from s4ap.sims4communitylib.utils.common_log_registry import CommonLogRegistry, CommonLog -from s4ap.sims4communitylib.utils.misc.common_text_utils import CommonTextUtils - - -class _CommonVanillaLogOverride(CommonService): - def __init__(self) -> None: - self.logs_enabled = S4CLConfiguration().enable_vanilla_logging - self.logs = list() - self.stop_watches = dict() - self.last_time = dict() - - def get_log(self, log_name: str) -> CommonLog: - """ Get a log for a log name. """ - _log = CommonLogRegistry().register_log(f'{log_name}_S4CLVanillaLog', 'log', 'vanilla_logs') - _log.enable() - self.logs.append(_log) - return _log - - def _format_message(self, message, *args, owner=None, **__) -> str: - to_log_message = message - if args: - to_log_message = to_log_message.format(*args) - if owner: - to_log_message = f'[{owner}] {to_log_message}' - return to_log_message - - def enable_logs(self) -> None: - """ Enable logs. """ - self.logs_enabled = True - - def disable_logs(self) -> None: - """ Disable logs. """ - self.logs_enabled = False - - def _log(self, log_name: str, message: str, *args, level, owner=None, **kwargs) -> Any: - if not self.logs_enabled: - return - message = self._append_time(log_name, message) - _log = _CommonVanillaLogOverride().get_log(log_name) - to_log_message = _CommonVanillaLogOverride()._format_message(message, *args, owner=owner, **kwargs) - _log.debug(f'{level}: {to_log_message}') - - def _debug(self, log_name: str, message: str, *args, owner=None, **kwargs) -> Any: - if not self.logs_enabled: - return - message = self._append_time(log_name, message) - _log = _CommonVanillaLogOverride().get_log(log_name) - to_log_message = _CommonVanillaLogOverride()._format_message(message, *args, owner=owner, **kwargs) - _log.debug(to_log_message) - - def _info(self, log_name: str, message: str, *args, owner=None, **kwargs) -> Any: - if not self.logs_enabled: - return - message = self._append_time(log_name, message) - _log = _CommonVanillaLogOverride().get_log(log_name) - to_log_message = _CommonVanillaLogOverride()._format_message(message, *args, owner=owner, **kwargs) - _log.info(to_log_message) - - def _warn(self, log_name: str, message: str, *args, owner=None, **kwargs) -> Any: - if not self.logs_enabled: - return - message = self._append_time(log_name, message) - _log = _CommonVanillaLogOverride().get_log(log_name) - to_log_message = _CommonVanillaLogOverride()._format_message(message, *args, owner=owner, **kwargs) - _log.warn(to_log_message) - - def _error(self, log_name: str, message: str, *args, owner=None, **kwargs) -> Any: - if not self.logs_enabled: - return - message = self._append_time(log_name, message) - _log = _CommonVanillaLogOverride().get_log(log_name) - to_log_message = _CommonVanillaLogOverride()._format_message(message, *args, owner=owner, **kwargs) - _log.error(to_log_message + ' (This exception is not caused by S4CL, but rather caught)') - - def _exception(self, log_name: str, message: str, *args, exc: Exception = None, owner=None, **kwargs) -> Any: - if not self.logs_enabled: - return - message = self._append_time(log_name, message) - _log = _CommonVanillaLogOverride().get_log(log_name) - to_log_message = _CommonVanillaLogOverride()._format_message(message, *args, owner=owner, **kwargs) - _log.error(to_log_message + ' (This exception is not caused by S4CL, but rather caught)', exception=exc, throw=True) - - def _append_time(self, log_name: str, message: str) -> str: - stop_watch = self._get_stop_watch(log_name) - interval = stop_watch.interval_milliseconds() - if log_name not in self.last_time: - self.last_time[log_name] = interval - compare_time = 0 - else: - last_time = self.last_time[log_name] - compare_time = interval - last_time - self.last_time[log_name] = interval - interval_str = CommonTextUtils.to_truncated_decimal(interval) - compare_time_str = CommonTextUtils.to_truncated_decimal(compare_time) - return f'{interval_str}ms +{compare_time_str}ms {message}' - - def _get_stop_watch(self, log_name: str) -> CommonStopWatch: - if log_name not in self.stop_watches: - stop_watch = CommonStopWatch() - stop_watch.start() - self.stop_watches[log_name] = stop_watch - return self.stop_watches[log_name] - - def _clear_log_times(self) -> None: - stop_watches = list(self.stop_watches.values()) - self.stop_watches.clear() - self.stop_watches.clear() - self.last_time.clear() - for stop_watch in stop_watches: - stop_watch.stop() - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.enable_vanilla_logs', - 'Enable the Vanilla Logs. Vanilla Logs are useful for discovering previously unknown exceptions and messages being logged by the game itself. Vanilla logs appear under "The Sims 4/mod_logs/vanilla_logs"', - command_aliases=( - 's4clib.enablevanillalogs', - ) -) -def _common_enable_vanilla_logs(output: CommonConsoleCommandOutput): - output('Enabling the Vanilla Logs.') - if _CommonVanillaLogOverride().logs_enabled: - output('The Vanilla Logs are already enabled.') - return - _CommonVanillaLogOverride()._clear_log_times() - _CommonVanillaLogOverride().enable_logs() - output('Vanilla Logs are now enabled.') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.disable_vanilla_logs', - 'Disable the Vanilla Logs.', - command_aliases=( - 's4clib.disablevanillalogs', - ) -) -def _common_disable_vanilla_logs(output: CommonConsoleCommandOutput): - output('Disabling the Vanilla Logs.') - if not _CommonVanillaLogOverride().logs_enabled: - output('The Vanilla Logs are already disabled.') - return - _CommonVanillaLogOverride().disable_logs() - _CommonVanillaLogOverride()._clear_log_times() - output('Vanilla Logs are now disabled.') - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), Logger, 'log', handle_exceptions=False) -def _common_logger_log(original, self, message, *args, level, owner=None, **kwargs) -> Any: - log_name = self.group - _CommonVanillaLogOverride()._log(log_name, message, *args, level, owner=owner or self.default_owner, **kwargs) - return original(self, message, *args, level, owner=owner, **kwargs) - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), Logger, 'debug', handle_exceptions=False) -def _common_logger_debug(original, self, message, *args, owner=None, **kwargs) -> Any: - log_name = self.group - _CommonVanillaLogOverride()._debug(log_name, message, *args, owner=owner or self.default_owner, **kwargs) - return original(self, message, *args, owner=owner, **kwargs) - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), Logger, 'info', handle_exceptions=False) -def _common_logger_info(original, self, message, *args, owner=None, **kwargs) -> Any: - log_name = self.group - _CommonVanillaLogOverride()._info(log_name, message, *args, owner=owner or self.default_owner, **kwargs) - return original(self, message, *args, owner=owner, **kwargs) - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), Logger, 'warn', handle_exceptions=False) -def _common_logger_warn(original, self, message, *args, owner=None, **kwargs) -> Any: - log_name = self.group - _CommonVanillaLogOverride()._warn(log_name, message, *args, owner=owner or self.default_owner, **kwargs) - return original(self, message, *args, owner=owner, **kwargs) - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), Logger, 'error', handle_exceptions=False) -def _common_logger_error(original, self, message, *args, owner=None, **kwargs) -> Any: - log_name = self.group - _CommonVanillaLogOverride()._error(log_name, message, *args, owner=owner or self.default_owner, **kwargs) - return original(self, message, *args, owner=owner, **kwargs) - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), Logger, 'exception', handle_exceptions=False) -def _common_logger_exception(original, self, message, *args, exc=None, owner=None, **kwargs) -> Any: - log_name = self.group - _CommonVanillaLogOverride()._exception(log_name, message, *args, exc=exc, owner=owner or self.default_owner, **kwargs) - return original(self, message, *args, exc=exc, owner=owner, **kwargs) - - -@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.clear_log_times', 'Clear the stop watches for the vanilla logs', show_with_help_command=False) -def _common_clear_log_times(output: CommonConsoleCommandOutput): - output('Clearing Vanilla Logs log times.') - _CommonVanillaLogOverride()._clear_log_times() diff --git a/Scripts/s4ap/sims4communitylib/mod_support/__init__.py b/Scripts/s4ap/sims4communitylib/mod_support/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/mod_support/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/mod_support/common_mod_info.py b/Scripts/s4ap/sims4communitylib/mod_support/common_mod_info.py deleted file mode 100644 index 70e7458..0000000 --- a/Scripts/s4ap/sims4communitylib/mod_support/common_mod_info.py +++ /dev/null @@ -1,85 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.services.common_service import CommonService - - -class CommonModInfo(CommonService): - """Provide information about your mod. - - For information on what each of the properties represents, see :class:`.CommonModIdentity` - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from s4ap.sims4communitylib.mod_support.common_mod_info import CommonModInfo - - # This is how the sims4communitylib.modinfo.ModInfo implementation works. - class ModInfo(CommonModInfo): - _FILE_PATH: str = str(__file__) - - @property - def _name(self) -> str: - return 'Sims4CommunityLib' - - @property - def _author(self) -> str: - return 'ColonolNutty' - - @property - def _base_namespace(self) -> str: - return 'sims4communitylib' - - @property - def _file_path(self) -> str: - return ModInfo._FILE_PATH - - @property - def _version(self) -> str: - return '3.5.6' - - """ - @classmethod - def get_identity(cls) -> CommonModIdentity: - """The identity of a mod - - .. note:: It contains information about a mod such as Mod Name, Mod Author,\ - the script base namespace, and the file path to your mod. - - :return: The identity of a mod. - :rtype: CommonModIdentity - """ - identity_property_name = '_MOD_IDENTITY' - mod_identity = getattr(cls, identity_property_name, None) - if mod_identity is None: - mod_info: CommonModInfo = cls.get() - mod_identity = CommonModIdentity(mod_info._name, mod_info._author, mod_info._base_namespace, mod_info._file_path, mod_info._version) - setattr(cls, identity_property_name, mod_identity) - return mod_identity - - @property - def _name(self) -> str: - raise NotImplementedError(f'Missing \'{self.__class__.__name__}._name\'.') - - @property - def _author(self) -> str: - raise NotImplementedError(f'Missing \'{self.__class__.__name__}._author\'.') - - @property - def _base_namespace(self) -> str: - raise NotImplementedError(f'Missing \'{self.__class__.__name__}._base_namespace\'.') - - @property - def _file_path(self) -> str: - raise NotImplementedError(f'Missing \'{self.__class__.__name__}._file_path\'.') - - @property - def _version(self) -> str: - return '1.0' diff --git a/Scripts/s4ap/sims4communitylib/mod_support/has_class_mod_identity.py b/Scripts/s4ap/sims4communitylib/mod_support/has_class_mod_identity.py deleted file mode 100644 index 8804a1b..0000000 --- a/Scripts/s4ap/sims4communitylib/mod_support/has_class_mod_identity.py +++ /dev/null @@ -1,33 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.mod_support.has_mod_identity import HasModIdentity -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity - - -class HasClassModIdentity(HasModIdentity): - """An inheritable class that provides Mod Info for a class. - - .. note:: This class inherits from :class:`.HasModIdentity` and may be used as an alternative to it. - - """ - # noinspection PyMissingOrEmptyDocstring - @property - def mod_identity(self) -> CommonModIdentity: - return self.__class__.get_mod_identity() - - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - """The identity of a mod. - - .. note:: It contains information about a mod such as Mod Name, Mod Author,\ - the script base namespace, and the file path to your mod. - - :return: The identity of a mod. - :rtype: CommonModIdentity - """ - raise NotImplementedError(f'Missing \'{cls.get_mod_identity.__name__}\'.') diff --git a/Scripts/s4ap/sims4communitylib/mod_support/has_mod_identity.py b/Scripts/s4ap/sims4communitylib/mod_support/has_mod_identity.py deleted file mode 100644 index 9fabb88..0000000 --- a/Scripts/s4ap/sims4communitylib/mod_support/has_mod_identity.py +++ /dev/null @@ -1,26 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity - - -class HasModIdentity: - """An inheritable class that provides Mod Info for a class. - - """ - @property - def mod_identity(self) -> CommonModIdentity: - """The identity of a mod. - - .. note:: It contains information about a mod such as Mod Name, Mod Author,\ - the script base namespace, and the file path to your mod. - - :return: The identity of a mod. - :rtype: CommonModIdentity - :exception NotImplementedError: Thrown when the property is not implemented. - """ - raise NotImplementedError('Missing \'{}.mod_identity\'.'.format(self.__class__.__name__)) diff --git a/Scripts/s4ap/sims4communitylib/mod_support/mod_identity.py b/Scripts/s4ap/sims4communitylib/mod_support/mod_identity.py deleted file mode 100644 index a95be05..0000000 --- a/Scripts/s4ap/sims4communitylib/mod_support/mod_identity.py +++ /dev/null @@ -1,108 +0,0 @@ -""" -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 -""" -from typing import Union - - -class CommonModIdentity: - """CommonModIdentity(name, author, base_namespace, file_path) - - The identity of a mod - - .. note:: It contains information about a mod such as Mod Name, Mod Author,\ - the script base namespace, and the file path to your mod. - - :param name: The name of a mod. - :type name: str - :param author: The author of a mod. - :type author: str - :param base_namespace: The base namespace of the `.ts4script` file of a mod. - :type base_namespace: str - :param file_path: The path to the ts4script file of a mod. - :type file_path: str - """ - def __init__(self, name: str, author: str, base_namespace: str, file_path: str, version: str): - self._name = name.replace(' ', '_') - self._author = author - self._base_namespace = base_namespace - self._script_file_path = file_path - self._version = version - - @property - def name(self) -> str: - """The name of a mod. - - .. note:: The name should not contain spaces. - - :return: The name of a mod. - :rtype: str - """ - return str(self._name) - - @property - def author(self) -> str: - """The author of a mod. - - :return: The name of the author of a mod. - :rtype: str - """ - return str(self._author) - - @property - def base_namespace(self) -> str: - """The base namespace of the `.ts4script` file of a mod. - - .. note:: S4CL has the base namespace of `sims4communitylib`. - - :return: The base script namespace of a mod. - :rtype: str - """ - return str(self._base_namespace) - - @property - def file_path(self) -> str: - """The path to the ts4script file of a mod. - - .. note:: - - A good override value can be `__file__`, it will retrieve the file path automatically,\ - assuming the inheriting class is at the root of the mod. - - :return: The file path to a mod. - :rtype: str - """ - return str(self._script_file_path) - - @property - def version(self) -> str: - """The version a mod is currently at. - - :return: The version of a mod. The Default value is '1.0'. - :rtype: str - """ - return str(self._version) - - @staticmethod - def _get_mod_name(mod_identifier: Union[str, 'CommonModIdentity']) -> Union[str, None]: - from s4ap.sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils - return CommonModIdentityUtils.determine_mod_name_from_identifier(mod_identifier) - - def __eq__(self, other: 'CommonModIdentity') -> bool: - if isinstance(other, str): - return self.name == other - if not isinstance(other, CommonModIdentity): - return False - return self.name == other.name - - def __hash__(self) -> int: - return hash(self.name) - - def __repr__(self) -> str: - return 'mod_{}_version_{}_author_{}_namespace_{}'.format(self.name, self.version.replace('.', '_').replace('/', '_').replace('\\', '_'), self.author, self.base_namespace) - - def __str__(self) -> str: - return 'Identity:\n Mod Name: {}\n Version: {}\n Mod Author: {}\n Base Namespace: {}\n Path To Mod: {}'.format(self.name, self.version, self.author, self.base_namespace, self.file_path) diff --git a/Scripts/s4ap/sims4communitylib/modinfo.py b/Scripts/s4ap/sims4communitylib/modinfo.py deleted file mode 100644 index b9c9819..0000000 --- a/Scripts/s4ap/sims4communitylib/modinfo.py +++ /dev/null @@ -1,35 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.mod_support.common_mod_info import CommonModInfo - - -class ModInfo(CommonModInfo): - """Contains details related to the mod itself. - - """ - _FILE_PATH: str = str(__file__) - - @property - def _name(self) -> str: - return 'Sims4CommunityLib' - - @property - def _author(self) -> str: - return 'ColonolNutty' - - @property - def _base_namespace(self) -> str: - return 'sims4communitylib' - - @property - def _file_path(self) -> str: - return ModInfo._FILE_PATH - - @property - def _version(self) -> str: - return '3.10' diff --git a/Scripts/s4ap/sims4communitylib/notifications/__init__.py b/Scripts/s4ap/sims4communitylib/notifications/__init__.py deleted file mode 100644 index 3251898..0000000 --- a/Scripts/s4ap/sims4communitylib/notifications/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" \ No newline at end of file diff --git a/Scripts/s4ap/sims4communitylib/notifications/common_basic_notification.py b/Scripts/s4ap/sims4communitylib/notifications/common_basic_notification.py deleted file mode 100644 index 71ff3b2..0000000 --- a/Scripts/s4ap/sims4communitylib/notifications/common_basic_notification.py +++ /dev/null @@ -1,177 +0,0 @@ -""" -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 -""" -from typing import Any, Union, Tuple, Iterator -from distributor.shared_messages import IconInfoData -from protocolbuffers.Localization_pb2 import LocalizedString -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from ui.ui_dialog import UiDialogResponse -from ui.ui_dialog_notification import UiDialogNotification - - -class CommonBasicNotification: - """CommonBasicNotification(\ - title_identifier,\ - description_identifier,\ - title_tokens=(),\ - description_tokens=(),\ - urgency=UiDialogNotification.UiDialogNotificationUrgency.DEFAULT,\ - information_level=UiDialogNotification.UiDialogNotificationLevel.SIM,\ - expand_behavior=UiDialogNotification.UiDialogNotificationExpandBehavior.USER_SETTING,\ - visual_type=UiDialogNotification.UiDialogNotificationVisualType.INFORMATION,\ - ui_responses=()\ - ) - - A basic notification. - - .. note:: Notifications are the messages that appear at the top right in-game. - - .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_basic_notification` in the in-game console. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - # Will display a test dialog. - def _common_testing_show_basic_notification(): - # LocalizedStrings within other LocalizedStrings - title_tokens = ( - CommonLocalizationUtils.create_localized_string( - CommonStringId.TESTING_SOME_TEXT_FOR_TESTING, - text_color=CommonLocalizedStringColor.BLUE - ), - ) - 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 - ), - ) - dialog = CommonBasicNotification( - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - title_tokens=title_tokens, - description_tokens=description_tokens, - urgency=UiDialogNotification.UiDialogNotificationUrgency.URGENT - ) - dialog.show() - - :param title_identifier: The title to display in the dialog. - :type title_identifier: Union[int, str, LocalizedString, CommonStringId] - :param description_identifier: The description to display in the dialog. - :type description_identifier: Union[int, str, LocalizedString, CommonStringId] - :param title_tokens: Tokens to format into the title. - :type title_tokens: Iterator[Any], optional - :param description_tokens: Tokens to format into the description. - :type description_tokens: Iterator[Any], optional - :param urgency: The urgency to which the notification will appear. (URGENT makes it orange) Default is Default (Blue). - :type urgency: UiDialogNotification.UiDialogNotificationUrgency, optional - :param information_level: The information level of the notification. Default is Sim. - :type information_level: UiDialogNotification.UiDialogNotificationLevel, optional - :param expand_behavior: Specify how the notification will expand. Default is User Setting. - :type expand_behavior: UiDialogNotification.UiDialogNotificationExpandBehavior, optional - :param visual_type: How the notification should appear. Default is Information - :type visual_type: UiDialogNotification.UiDialogNotificationVisualType, optional - :param ui_responses: A collection of UI Responses that may be performed within the notification. - :type ui_responses: Tuple[UiDialogResponse], optional - """ - def __init__( - self, - title_identifier: Union[int, str, LocalizedString, CommonStringId], - description_identifier: Union[int, str, LocalizedString, CommonStringId], - title_tokens: Iterator[Any] = (), - description_tokens: Iterator[Any] = (), - urgency: UiDialogNotification.UiDialogNotificationUrgency = UiDialogNotification.UiDialogNotificationUrgency.DEFAULT, - information_level: UiDialogNotification.UiDialogNotificationLevel = UiDialogNotification.UiDialogNotificationLevel.SIM, - expand_behavior: UiDialogNotification.UiDialogNotificationExpandBehavior = UiDialogNotification.UiDialogNotificationExpandBehavior.USER_SETTING, - visual_type: UiDialogNotification.UiDialogNotificationVisualType = UiDialogNotification.UiDialogNotificationVisualType.INFORMATION, - ui_responses: Tuple[UiDialogResponse] = () - ): - self.title = CommonLocalizationUtils.create_localized_string(title_identifier, tokens=tuple(title_tokens)) - self.description = CommonLocalizationUtils.create_localized_string(description_identifier, tokens=tuple(description_tokens)) - self.visual_type = visual_type - self.urgency = urgency - self.information_level = information_level - self.expand_behavior = expand_behavior - self.ui_responses = ui_responses - - def show(self, icon: IconInfoData = None, secondary_icon: IconInfoData = None): - """show(icon=None, secondary_icon=None) - - Show the notification to the player. - - :param icon: The first icon that will display in the notification. - :type icon: IconInfoData, optional - :param secondary_icon: The second icon that will display in the notification. - :type secondary_icon: IconInfoData, optional - """ - _notification = self._create_dialog() - if _notification is None: - return - - _notification.show_dialog( - icon_override=icon, - secondary_icon_override=secondary_icon - ) - - def _create_dialog(self) -> Union[UiDialogNotification, None]: - """_create_dialog() - - Create a dialog for use in :func:``show`. - - .. note:: Override this method with any arguments you want to. - """ - 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 - ) - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_testing.show_basic_notification', - 'Show an example of CommonBasicNotification.' -) -def _common_testing_show_basic_notification(output: CommonConsoleCommandOutput): - output('Showing test basic notification.') - - # LocalizedStrings within other LocalizedStrings - title_tokens = ( - CommonLocalizationUtils.create_localized_string( - CommonStringId.TESTING_SOME_TEXT_FOR_TESTING, - text_color=CommonLocalizedStringColor.BLUE - ), - ) - 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 - ), - ) - dialog = CommonBasicNotification( - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN, - title_tokens=title_tokens, - description_tokens=description_tokens, - urgency=UiDialogNotification.UiDialogNotificationUrgency.URGENT - ) - dialog.show() diff --git a/Scripts/s4ap/sims4communitylib/persistence/__init__.py b/Scripts/s4ap/sims4communitylib/persistence/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/persistence/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/persistence/common_game_object_data_storage.py b/Scripts/s4ap/sims4communitylib/persistence/common_game_object_data_storage.py deleted file mode 100644 index bfef0f8..0000000 --- a/Scripts/s4ap/sims4communitylib/persistence/common_game_object_data_storage.py +++ /dev/null @@ -1,230 +0,0 @@ -""" -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 -""" -import sys -from pprint import pformat -from typing import Dict, Any, Callable -from typing import Union -from objects.game_object import GameObject -from s4ap.sims4communitylib.classes.serialization.common_serializable import CommonSerializable -from s4ap.sims4communitylib.logging.has_class_log import HasClassLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils -from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils - - -class _CommonGameObjectDataStorageMetaclass(type): - _game_object_storage_instances: Dict[str, Dict[int, '_CommonGameObjectDataStorageMetaclass']] = dict() - - def __call__(cls, game_object: GameObject): - mod_identity = cls.get_mod_identity() - game_object_id = CommonObjectUtils.get_object_id(game_object) - mod_name = mod_identity.name - if mod_name is None: - return None - identifier = f'{mod_name}_{cls.__name__}' - if identifier not in cls._game_object_storage_instances: - cls._game_object_storage_instances[identifier] = dict() - if game_object_id not in cls._game_object_storage_instances[identifier]: - cls._game_object_storage_instances[identifier][game_object_id] = super(_CommonGameObjectDataStorageMetaclass, cls).__call__(game_object) - stored_obj = cls._game_object_storage_instances[identifier][game_object_id] - if stored_obj.__class__.__name__ != cls.__name__: - cls._game_object_storage_instances[identifier][game_object_id] = super(_CommonGameObjectDataStorageMetaclass, cls).__call__(game_object) - return cls._game_object_storage_instances[identifier][game_object_id] - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(mcs) -> CommonModIdentity: - raise NotImplementedError() - - @classmethod - def clear_instances(mcs, mod_identity: CommonModIdentity) -> None: - """Clear the cached instances of this type of Object Storage.""" - mod_name = mod_identity.name - if mod_name is None: - return - identifier = f'{mod_name}_{mcs.__name__}' - if identifier in _CommonGameObjectDataStorageMetaclass._game_object_storage_instances: - del _CommonGameObjectDataStorageMetaclass._game_object_storage_instances[identifier] - - -class _CommonGameObjectDataStorage(HasClassLog, metaclass=_CommonGameObjectDataStorageMetaclass): - def __init__(self, game_object: GameObject): - super().__init__() - if not CommonTypeUtils.is_game_object(game_object): - raise AssertionError('game_object was not of type GameObject! {}'.format(game_object)) - self._game_object_id = CommonObjectUtils.get_object_id(game_object) - self._game_object = game_object - self._data: Dict[str, Any] = dict() - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - raise NotImplementedError('Missing \'{}\' inside {}.'.format(cls.get_mod_identity.__name__, cls.__class__)) - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return '{}_game_object_data_storage'.format(cls.get_mod_identity().base_namespace) - - @property - def game_object(self) -> GameObject: - """The GameObject the storage applies to. - - :return: An instance of an Object. - :rtype: GameObject - """ - return self._game_object - - @property - def game_object_id(self) -> int: - """The decimal identifier of the GameObject. - - :return: The decimal identifier of the GameObject. - :rtype: int - """ - return self._game_object_id - - def get_data(self, default: Any=None, key: str=None, encode: Callable[[Any], Any]=None, decode: Callable[[Any], Any]=None) -> Union[Any, None]: - """get_data(default=None, key=None, encode=None, decode=None) - - Retrieve stored data. - - :param default: The default data to return. The default value is None. - :type default: Dict[Any, Any], optional - :param key: The key for the data. If None, the name of the calling function will be used. - :type key: str, optional - :param encode: If specified, the data will be encoded using this function and the result will be the new data stored. Default is None. - :type encode: Callable[[Any], Any], optional - :param decode: If specified, the data will be decoded using this function and the result will be the new result of "get_data". Default is None. - :type decode: Callable[[Any], Any], optional - :return: The stored data. - :rtype: Union[Any, None] - """ - # noinspection PyUnresolvedReferences - key = key or str(sys._getframe(1).f_code.co_name) - if key not in self._data: - self.log.format_with_message('Key not found in data.', key=key, data=self._data) - if default is not None: - if encode is not None: - self._data[key] = encode(default) - else: - self._data[key] = default - return default - data = self._data.get(key) - if decode is not None and not isinstance(data, CommonSerializable): - decoded = decode(data) - if isinstance(data, CommonSerializable): - self._data[key] = decoded - return decoded - return data - - def set_data(self, value: Any, key: str=None, encode: Callable[[Any], Any]=None): - """set_data(value, key=None, encode=None) - - Set stored data. - - :param value: The value of the data. - :type value: Any - :param key: The key for the data. If None, the name of the calling function will be used. - :type key: str, optional - :param encode: If specified, the data will be encoded using this function and the result will be the new data stored. Default is None. - :type encode: Callable[[Any], Any], optional - """ - # noinspection PyUnresolvedReferences - key = key or str(sys._getframe(1).f_code.co_name) - if encode is not None: - value = encode(value) - self._data[key] = value - - def remove_data(self, key: str=None): - """remove_data(key=None) - - Remove stored data. - - :param key: The key for the data. If None, the name of the calling function will be used. - :type key: str, optional - """ - # noinspection PyUnresolvedReferences - key = key or str(sys._getframe(1).f_code.co_name) - if key not in self._data: - self.log.format_with_message('Key not found in data.', key=key, data=self._data) - return - del self._data[key] - - def __repr__(self) -> str: - return ''.join(['{}: {}\n'.format(pformat(key), pformat(value)) for (key, value) in self._data.items()]) - - def __str__(self) -> str: - return self.__repr__() - - -class CommonGameObjectDataStorage(_CommonGameObjectDataStorage): - """CommonGameObjectDataStorage(game_object) - - A wrapper for Object instances that allows storing of data. - - .. warning:: Data stored within is not persisted when closing and reopening the game! - .. warning:: DO NOT CREATE THIS CLASS DIRECTLY, IT IS ONLY MEANT TO INHERIT FROM! - - :Example usage: - - .. highlight:: python - .. code-block:: python - - # Inherit from CommonGameObjectDataStorage - class _ExampleGameObjectDataStorage(CommonGameObjectDataStorage): - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - # !!!Override with the CommonModIdentity of your own mod!!! - from s4ap.sims4communitylib.modinfo import ModInfo - return ModInfo.get_identity() - - @property - def example_property_one(self) -> bool: - # Could also be written self.get_data(default=False, key='example_property_one') and it would do the same thing. - return self.get_data(default=False) - - @example_property_one.setter - def example_property_one(self, value: bool): - # Could also be written self.set_data(value, key='example_property_one') and it would do the same thing. - self.set_data(value) - - :param game_object: An instance of an Object. - :type game_object: GameObject - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - raise NotImplementedError('Missing \'{}\' inside {}.'.format(cls.get_mod_identity.__name__, cls.__class__)) - - def __init__(self, game_object: GameObject): - super().__init__(game_object) - if self.__class__.__name__ is CommonGameObjectDataStorage.__name__: - raise RuntimeError('{} cannot be created directly. You must inherit from it to create an instance of it.'.format(self.__class__.__name__)) - - -# noinspection PyMissingOrEmptyDocstring -class _ExampleGameObjectDataStorage(CommonGameObjectDataStorage): - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - # !!!Override with the CommonModIdentity of your own mod!!! - from s4ap.sims4communitylib.modinfo import ModInfo - return ModInfo.get_identity() - - @property - def example_property_one(self) -> bool: - # Could also be written self.get_data(default=False, key='example_property_one') and it would do the same thing. - return self.get_data(default=False) - - @example_property_one.setter - def example_property_one(self, value: bool): - # Could also be written self.set_data(value, key='example_property_one') and it would do the same thing. - self.set_data(value) diff --git a/Scripts/s4ap/sims4communitylib/persistence/common_persisted_game_object_data_storage.py b/Scripts/s4ap/sims4communitylib/persistence/common_persisted_game_object_data_storage.py deleted file mode 100644 index 48093f2..0000000 --- a/Scripts/s4ap/sims4communitylib/persistence/common_persisted_game_object_data_storage.py +++ /dev/null @@ -1,156 +0,0 @@ -""" -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 -""" -from typing import Dict, Any, Tuple, Type - -from objects.game_object import GameObject -from s4ap.sims4communitylib.classes.serialization.common_serializable import CommonSerializable -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.persistence.data_management.common_data_manager import CommonDataManager -from s4ap.sims4communitylib.persistence.data_stores.common_data_store import CommonDataStore -from s4ap.sims4communitylib.persistence.common_game_object_data_storage import CommonGameObjectDataStorage -from s4ap.sims4communitylib.persistence.data_stores.common_game_object_data_store import CommonGameObjectDataStore - - -class CommonPersistedGameObjectDataStorage(CommonGameObjectDataStorage): - """CommonPersistedGameObjectDataStorage(game_object) - - A wrapper for Game Object instances that allows storing of data and persisting it between saves. - - .. warning:: Data stored within will be persisted for a Save even when closing and reopening the game! - .. warning:: DO NOT CREATE THIS CLASS DIRECTLY, IT IS ONLY MEANT TO INHERIT FROM! - - :Example usage: - - .. highlight:: python - .. code-block:: python - - # Inherit from CommonPersistedGameObjectDataStorage - class ExamplePersistedGameObjectDataStorage(CommonPersistedGameObjectDataStorage): - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - # !!!Override with the CommonModIdentity of your own mod!!! - from s4ap.sims4communitylib.modinfo import ModInfo - return ModInfo.get_identity() - - @property - def example_property_one(self) -> bool: - # Could also be written self.get_data(default=False, key='example_property_one') and it would do the same thing. - return self.get_data(default=False) - - @example_property_one.setter - def example_property_one(self, value: bool): - # Could also be written self.set_data(value, key='example_property_one') and it would do the same thing. - self.set_data(value) - - :param game_object: An instance of a GameObject - :type game_object: GameObject - """ - def __init__(self, game_object: GameObject): - super().__init__(game_object) - if self.__class__.__name__ is CommonPersistedGameObjectDataStorage.__name__: - raise RuntimeError('{} cannot be created directly. You must inherit from it to create an instance of it.'.format(self.__class__.__name__)) - from s4ap.sims4communitylib.persistence.data_management.common_data_manager_registry import CommonDataManagerRegistry - self._data_manager_registry = CommonDataManagerRegistry() - self.__data_manager: CommonDataManager = None - self._data = self._load_persisted_data() - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - raise NotImplementedError('Missing \'{}\' inside {}.'.format(cls.get_mod_identity.__name__, cls.__class__)) - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 'common_persisted_game_object_data_storage' - - @property - def data_store_type(self) -> Type[CommonDataStore]: - """data_store_type() - - The type of data store used for saving and loading data. - - :return: The type of the data store to use when saving and loading data. - :rtype: Type[CommonDataStore] - """ - return CommonGameObjectDataStore - - @property - def whitelist_property_names(self) -> Tuple[str]: - """ - If a property is within this list, it will be persisted when saving. By default all properties are whitelisted. - - :return: A collection of property names. - :rtype: Tuple[str] - """ - return tuple(self._data.keys()) - - @property - def blacklist_property_names(self) -> Tuple[str]: - """ - If a property is within this list, it will not be persisted when saving. By default no properties are blacklisted. - - :return: A collection of property names. - :rtype: Tuple[str] - """ - return tuple() - - @property - def _persist_empty_values(self) -> bool: - return False - - @property - def _data_manager(self) -> CommonDataManager: - if self.__data_manager is None: - self.__data_manager = self._data_manager_registry.locate_data_manager(self.mod_identity) - if self.__data_manager is None: - raise RuntimeError('Failed to locate a data manager for {}, maybe you forgot to register one?'.format(self.mod_identity.name)) - return self.__data_manager - - def customize_data_pre_save(self, data: Dict[str, Any]) -> Dict[str, Any]: - """customize_data_pre_save(data) - - A hook that allows customization of data before it is persisted/saved. - - :param data: The data intending to be saved, it is available for customization. - :type data: Dict[str, Any] - :return: The customized data. - :rtype: Dict[str, Any] - """ - data_to_save = dict(data) - for (key, value) in data_to_save.items(): - if not hasattr(self, key): - del data[key] - return data - - def _save_persisted_data(self) -> None: - data_to_save = dict() - for data_property_name in self._data.keys(): - if data_property_name not in self.whitelist_property_names or data_property_name in self.blacklist_property_names: - continue - data = self._data[data_property_name] - if self._persist_empty_values: - data_to_save[data_property_name] = data.serialize() if isinstance(data, CommonSerializable) else data - else: - if data is None or (data != 0 and not isinstance(data, bool) and not data): - continue - serialized_data = data.serialize() if isinstance(data, CommonSerializable) else data - if data is None or (serialized_data != 0 and not isinstance(data, bool) and not serialized_data): - continue - data_to_save[data_property_name] = serialized_data - data_to_save = self.customize_data_pre_save(data_to_save) - if data_to_save is None: - return - if not self._persist_empty_values: - if not data_to_save: - self._data_manager.get_data_store_by_type(self.data_store_type).remove_data_by_key(str(self.game_object_id)) - return - self._data_manager.get_data_store_by_type(self.data_store_type).set_value_by_key(str(self.game_object_id), data_to_save) - - def _load_persisted_data(self) -> Dict[str, Any]: - return self._data_manager.get_data_store_by_type(self.data_store_type).get_value_by_key(str(self.game_object_id)) diff --git a/Scripts/s4ap/sims4communitylib/persistence/common_persisted_sim_data_storage.py b/Scripts/s4ap/sims4communitylib/persistence/common_persisted_sim_data_storage.py deleted file mode 100644 index 3f99f1c..0000000 --- a/Scripts/s4ap/sims4communitylib/persistence/common_persisted_sim_data_storage.py +++ /dev/null @@ -1,157 +0,0 @@ -""" -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 -""" -from typing import Dict, Any, Tuple, Type - -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.classes.serialization.common_serializable import CommonSerializable -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.persistence.data_management.common_data_manager import CommonDataManager -from s4ap.sims4communitylib.persistence.data_stores.common_data_store import CommonDataStore -from s4ap.sims4communitylib.persistence.common_sim_data_storage import CommonSimDataStorage -from s4ap.sims4communitylib.persistence.data_stores.common_sim_data_store import CommonSimDataStore - - -class CommonPersistedSimDataStorage(CommonSimDataStorage): - """CommonPersistedSimDataStorage(sim_info) - - A wrapper for Sim instances that allows storing of data and persisting it between saves. - - .. warning:: Data stored within will be persisted for a Save even when closing and reopening the game! - .. warning:: DO NOT CREATE THIS CLASS DIRECTLY, IT IS ONLY MEANT TO INHERIT FROM! - - :Example usage: - - .. highlight:: python - .. code-block:: python - - # Inherit from CommonPersistedSimDataStorage - class ExamplePersistedSimDataStorage(CommonPersistedSimDataStorage): - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - # !!!Override with the CommonModIdentity of your own mod!!! - from s4ap.sims4communitylib.modinfo import ModInfo - return ModInfo.get_identity() - - @property - def example_property_one(self) -> bool: - # Could also be written self.get_data(default=False, key='example_property_one') and it would do the same thing. - return self.get_data(default=False) - - @example_property_one.setter - def example_property_one(self, value: bool): - # Could also be written self.set_data(value, key='example_property_one') and it would do the same thing. - self.set_data(value) - - :param sim_info: The SimInfo of a Sim. - :type sim_info: SimInfo - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - raise NotImplementedError('Missing \'{}\' inside {}.'.format(cls.get_mod_identity.__name__, cls.__class__)) - - def __init__(self, sim_info: SimInfo): - super().__init__(sim_info) - if self.__class__.__name__ is CommonPersistedSimDataStorage.__name__: - raise RuntimeError('{} cannot be created directly. You must inherit from it to create an instance of it.'.format(self.__class__.__name__)) - from s4ap.sims4communitylib.persistence.data_management.common_data_manager_registry import CommonDataManagerRegistry - self._data_manager_registry = CommonDataManagerRegistry() - self.__data_manager: CommonDataManager = None - self._data = self._load_persisted_data() - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 'common_persisted_sim_data_storage' - - @property - def data_store_type(self) -> Type[CommonDataStore]: - """data_store_type() - - The type of data store used for saving and loading data. - - :return: The type of the data store to use when saving and loading data. - :rtype: Type[CommonDataStore] - """ - return CommonSimDataStore - - @property - def whitelist_property_names(self) -> Tuple[str]: - """ - If a property is within this list, it will be persisted when saving. By default all properties are whitelisted. - - :return: A collection of property names. - :rtype: Tuple[str] - """ - return tuple(self._data.keys()) - - @property - def blacklist_property_names(self) -> Tuple[str]: - """ - If a property is within this list, it will not be persisted when saving. By default no properties are blacklisted. - - :return: A collection of property names. - :rtype: Tuple[str] - """ - return tuple() - - @property - def _data_manager(self) -> CommonDataManager: - if self.__data_manager is None: - self.__data_manager = self._data_manager_registry.locate_data_manager(self.mod_identity) - if self.__data_manager is None: - raise RuntimeError('Failed to locate a data manager for {}, maybe you forgot to register one?'.format(self.mod_identity.name)) - return self.__data_manager - - @property - def _persist_empty_values(self) -> bool: - return False - - def customize_data_pre_save(self, data: Dict[str, Any]) -> Dict[str, Any]: - """customize_data_pre_save(data) - - A hook that allows customization of data before it is persisted/saved. - - :param data: The data intending to be saved, it is available for customization. - :type data: Dict[str, Any] - :return: The customized data. - :rtype: Dict[str, Any] - """ - data_to_save = dict(data) - for (key, value) in data_to_save.items(): - if not hasattr(self, key): - del data[key] - return data - - def _save_persisted_data(self) -> None: - data_to_save = dict() - for data_property_name in self._data.keys(): - if data_property_name not in self.whitelist_property_names or data_property_name in self.blacklist_property_names: - continue - data = self._data[data_property_name] - if self._persist_empty_values: - data_to_save[data_property_name] = data.serialize() if isinstance(data, CommonSerializable) else data - else: - if data is None or (data != 0 and not isinstance(data, bool) and not data): - continue - serialized_data = data.serialize() if isinstance(data, CommonSerializable) else data - if data is None or (serialized_data != 0 and not isinstance(data, bool) and not serialized_data): - continue - data_to_save[data_property_name] = serialized_data - data_to_save = self.customize_data_pre_save(data_to_save) - if data_to_save is None: - return - if not self._persist_empty_values: - if not data_to_save: - self._data_manager.get_data_store_by_type(self.data_store_type).remove_data_by_key(str(self.sim_id)) - return - self._data_manager.get_data_store_by_type(self.data_store_type).set_value_by_key(str(self.sim_id), data_to_save) - - def _load_persisted_data(self) -> Dict[str, Any]: - return self._data_manager.get_data_store_by_type(self.data_store_type).get_value_by_key(str(self.sim_id)) diff --git a/Scripts/s4ap/sims4communitylib/persistence/common_sim_data_storage.py b/Scripts/s4ap/sims4communitylib/persistence/common_sim_data_storage.py deleted file mode 100644 index 5b53447..0000000 --- a/Scripts/s4ap/sims4communitylib/persistence/common_sim_data_storage.py +++ /dev/null @@ -1,234 +0,0 @@ -""" -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 -""" -import sys -from pprint import pformat -from typing import Dict, Any, Callable -from typing import Union -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.classes.serialization.common_serializable import CommonSerializable -from s4ap.sims4communitylib.logging.has_class_log import HasClassLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - - -class _CommonSimDataStorageMetaclass(type): - _sim_storage_instances: Dict[str, Dict[int, '_CommonSimDataStorageMetaclass']] = {} - - def __call__(cls, sim_info: SimInfo): - mod_identity = cls.get_mod_identity() - sim_id = CommonSimUtils.get_sim_id(sim_info) - mod_name = mod_identity.name - if mod_name is None: - return None - identifier = f'{mod_name}_{cls.__name__}' - if identifier not in cls._sim_storage_instances: - cls._sim_storage_instances[identifier] = dict() - if sim_id not in cls._sim_storage_instances[identifier]: - cls._sim_storage_instances[identifier][sim_id] = super(_CommonSimDataStorageMetaclass, cls).__call__(sim_info) - stored_obj = cls._sim_storage_instances[identifier][sim_id] - if stored_obj.__class__.__name__ != cls.__name__: - cls._sim_storage_instances[identifier][sim_id] = super(_CommonSimDataStorageMetaclass, cls).__call__(sim_info) - return cls._sim_storage_instances[identifier][sim_id] - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(mcs) -> CommonModIdentity: - raise NotImplementedError() - - @classmethod - def clear_instances(mcs, mod_identity: CommonModIdentity) -> None: - """Clear the cached instances of this type of Sim Storage.""" - mod_name = mod_identity.name - if mod_name is None: - return - identifier = f'{mod_name}_{mcs.__name__}' - if identifier in _CommonSimDataStorageMetaclass._sim_storage_instances: - del _CommonSimDataStorageMetaclass._sim_storage_instances[identifier] - - -class _CommonSimDataStorage(HasClassLog, metaclass=_CommonSimDataStorageMetaclass): - def __init__(self, sim_info: SimInfo): - super().__init__() - if not CommonTypeUtils.is_sim_info(sim_info) and not CommonTypeUtils.is_sim_info_base_wrapper(sim_info): - raise AssertionError('sim_info was not of type SimInfo! {}'.format(sim_info if sim_info is None else type(sim_info))) - self._sim_id = CommonSimUtils.get_sim_id(sim_info) - self._sim_info = sim_info - self._data: Dict[str, Any] = dict() - if sim_info is not None: - from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils - sim_name = CommonSimNameUtils.get_full_name(sim_info) - if sim_name is not None: - self._data['sim_name'] = sim_name - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - raise NotImplementedError('Missing \'{}\' inside {}.'.format(cls.get_mod_identity.__name__, cls.__class__)) - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return '{}_sim_data_storage'.format(cls.get_mod_identity().base_namespace) - - @property - def sim_info(self) -> SimInfo: - """The SimInfo of a Sim. - - :return: The SimInfo of a Sim. - :rtype: SimInfo - """ - return self._sim_info - - @property - def sim_id(self) -> int: - """The decimal identifier of a Sim. - - :return: The decimal identifier of a Sim. - :rtype: int - """ - return self._sim_id - - def get_data(self, default: Any=None, key: str=None, encode: Callable[[Any], Any]=None, decode: Callable[[Any], Any]=None) -> Union[Any, None]: - """get_data(default=None, key=None, encode=None, decode=None) - - Retrieve stored data. - - :param default: The default data to return. The default value is None. - :type default: Dict[Any, Any], optional - :param key: The key for the data. If None, the name of the calling function will be used. - :type key: str, optional - :param encode: If specified, the data will be encoded using this function and the result will be the new data stored. Default is None. - :type encode: Callable[[Any], Any], optional - :param decode: If specified, the data will be decoded using this function and the result will be the new result of "get_data". Default is None. - :type decode: Callable[[Any], Any], optional - :return: The stored data. - :rtype: Union[Any, None] - """ - # noinspection PyUnresolvedReferences - key = key or str(sys._getframe(1).f_code.co_name) - if key not in self._data: - self.log.format_with_message('Key not found in data. Setting to default value.', sim=self.sim_info, key=key, data=self._data, default=default) - if default is not None: - if encode is not None: - self._data[key] = encode(default) - else: - self._data[key] = default - return default - data = self._data.get(key) - if decode is not None and not isinstance(data, CommonSerializable): - decoded = decode(data) - if isinstance(data, CommonSerializable): - self._data[key] = decoded - return decoded - return data - - def set_data(self, value: Any, key: str=None, encode: Callable[[Any], Any]=None): - """set_data(value, key=None, encode=None) - - Set stored data. - - :param value: The value of the data. - :type value: Any - :param key: The key for the data. If None, the name of the calling function will be used. - :type key: str, optional - :param encode: If specified, the data will be encoded using this function and the result will be the new data stored. Default is None. - :type encode: Callable[[Any], Any], optional - """ - # noinspection PyUnresolvedReferences - key = key or str(sys._getframe(1).f_code.co_name) - if encode is not None: - value = encode(value) - self._data[key] = value - - def remove_data(self, key: str=None): - """remove_data(key=None) - - Remove stored data. - - :param key: The key for the data. If None, the name of the calling function will be used. - :type key: str, optional - """ - # noinspection PyUnresolvedReferences - key = key or str(sys._getframe(1).f_code.co_name) - if key not in self._data: - self.log.format_with_message('Key not found in data. Not removing it.', sim=self.sim_info, key=key, data=self._data) - return - del self._data[key] - - def __repr__(self) -> str: - return ''.join(['{}: {}\n'.format(pformat(key), pformat(value)) for (key, value) in self._data.items()]) - - def __str__(self) -> str: - return self.__repr__() - - -class CommonSimDataStorage(_CommonSimDataStorage): - """CommonSimDataStorage(sim_info) - - A wrapper for Sim instances that allows storing of data. - - .. warning:: Data stored within is not persisted when closing and reopening the game! - .. warning:: DO NOT CREATE THIS CLASS DIRECTLY, IT IS ONLY MEANT TO INHERIT FROM! - - :Example usage: - - .. highlight:: python - .. code-block:: python - - # Inherit from CommonSimDataStorage - class _ExampleSimDataStorage(CommonSimDataStorage): - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - # !!!Override with the CommonModIdentity of your own mod!!! - from s4ap.sims4communitylib.modinfo import ModInfo - return ModInfo.get_identity() - - @property - def example_property_one(self) -> bool: - # Could also be written self.get_data(default=False, key='example_property_one') and it would do the same thing. - return self.get_data(default=False) - - @example_property_one.setter - def example_property_one(self, value: bool): - # Could also be written self.set_data(value, key='example_property_one') and it would do the same thing. - self.set_data(value) - - :param sim_info: The SimInfo of a Sim. - :type sim_info: SimInfo - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - raise NotImplementedError('Missing \'{}\' inside {}.'.format(cls.get_mod_identity.__name__, cls.__class__)) - - def __init__(self, sim_info: SimInfo): - super().__init__(sim_info) - if self.__class__.__name__ is CommonSimDataStorage.__name__: - raise RuntimeError('{} cannot be created directly. You must inherit from it to create an instance of it.'.format(self.__class__.__name__)) - - -# noinspection PyMissingOrEmptyDocstring -class _ExampleSimDataStorage(CommonSimDataStorage): - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - # !!!Override with the CommonModIdentity of your own mod!!! - from s4ap.sims4communitylib.modinfo import ModInfo - return ModInfo.get_identity() - - @property - def example_property_one(self) -> bool: - # Could also be written self.get_data(default=False, key='example_property_one') and it would do the same thing. - return self.get_data(default=False) - - @example_property_one.setter - def example_property_one(self, value: bool): - # Could also be written self.set_data(value, key='example_property_one') and it would do the same thing. - self.set_data(value) diff --git a/Scripts/s4ap/sims4communitylib/persistence/data_management/__init__.py b/Scripts/s4ap/sims4communitylib/persistence/data_management/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/persistence/data_management/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/persistence/data_management/common_data_manager.py b/Scripts/s4ap/sims4communitylib/persistence/data_management/common_data_manager.py deleted file mode 100644 index 3d18877..0000000 --- a/Scripts/s4ap/sims4communitylib/persistence/data_management/common_data_manager.py +++ /dev/null @@ -1,232 +0,0 @@ -""" -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 -""" -from typing import Dict, Any, Type, Tuple - -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.logging.has_log import HasLog -from s4ap.sims4communitylib.persistence.data_stores.common_data_store import CommonDataStore -from s4ap.sims4communitylib.persistence.persistence_services.common_persistence_service import CommonPersistenceService - - -class CommonDataManager(HasLog): - """CommonDataManager() - - Manage a storage of data. - - """ - # noinspection PyMissingOrEmptyDocstring - @property - def mod_identity(self) -> CommonModIdentity: - return super().mod_identity - - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - return super().log_identifier - - def __init__(self, identifier: str=None) -> None: - super().__init__() - self._identifier = identifier - self.__data_store_data = None - self.__data_stores = dict() - self._loaded = False - self._can_be_saved = True - self._persistence_service = None - - @property - def _can_be_saved(self) -> bool: - return self.__can_be_saved - - @_can_be_saved.setter - def _can_be_saved(self, val: bool): - self.__can_be_saved = val - - @property - def persistence_services(self) -> Tuple[CommonPersistenceService]: - """A collection of services that save and load data for the manager using the Mod Identity of the manager. - - .. note:: The precedence of data being loaded/saved is in the order you return them in.\ - For example, with (CommonHiddenHouseholdPersistenceService, CommonFilePersistenceService), data loaded via the file will override data loaded via the hidden household - - :return: A collection of persistence services. - :rtype: Tuple[CommonPersistenceService] - """ - raise NotImplementedError() - - @property - def _data_store_data(self) -> Dict[str, Dict[str, Any]]: - """ - Data stores owned by a Mod in serializable form organized by identifiers. - - .. note:: The Key is the identifier of a setting collection. The value is the library of settings related to the setting collection. - - :return: Data stores in serializable form organized by a Sub Name. - :rtype: Dict[str, Dict[str, Any]] - """ - if not self._loaded or self.__data_store_data is None: - self.load() - return self.__data_store_data - - @property - def _data_stores(self) -> Dict[str, CommonDataStore]: - """ - - Data stores owned by a Mod organized by identifiers - - .. note:: The Key is the identifier of a setting collection. The value is the library of settings related to the setting collection. - - :return: Data stores owned by a Mod organized by identifiers - :rtype: Dict[str, CommonDataStore] - """ - return self.__data_stores - - def get_data_store_by_type(self, data_store_type: Type[CommonDataStore]) -> CommonDataStore: - """get_data_store_by_type(data_store_type) - - Retrieve a data store by its type. - - .. note:: This will also add the data store using the type if it does not exist already. - - :param data_store_type: The type of data store. - :type data_store_type: Type[CommonDataStore] - :return: The data store. - :rtype: CommonDataStore - """ - name = data_store_type.get_identifier() - if name in self._data_stores: - return self._data_stores[name] - default_data_store: CommonDataStore = data_store_type() - if name not in self._data_store_data: - self._data_store_data[name] = dict() - - default_data_store.update_data(self._data_store_data[name]) - self.log.format_with_message('Created data store', name=default_data_store.get_identifier()) - self._data_store_data[name] = default_data_store.get_store_data_for_persistence() - self._data_stores[name] = default_data_store - return self._data_stores[name] - - def load(self) -> None: - """load() - - Load data into the data manager. - """ - if self._loaded: - return - try: - self.log.debug('Loading data.') - self.__data_store_data = self._load() - self._loaded = True - except Exception as ex: - self.log.error('Error occurred while loading data \'{}\'.'.format(self.__repr__()), exception=ex) - self.__data_store_data = dict() - self._loaded = True - - def reload(self) -> None: - """reload() - - Reloads data into the data manager. - """ - self._loaded = False - self.load() - - def save(self) -> bool: - """save() - - Save data from the data manager. - - :return: True, if save was successful. False, if not. - :rtype: bool - """ - try: - self.log.debug('Saving data.') - # Update global data with data from the data stores. - for (name, data_store) in self._data_stores.items(): - data_store: CommonDataStore = data_store - self._data_store_data[name] = data_store.get_store_data_for_persistence() - return self._save() - except Exception as ex: - self.log.error('Error occurred while saving data \'{}\'.'.format(self.__repr__()), exception=ex) - return False - - def clear(self) -> None: - """clear() - - Clear all data from the data manager. - """ - self.__data_store_data = dict() - self.__data_stores = dict() - self._loaded = False - - def remove_all_data(self, prevent_save: bool=False) -> bool: - """remove_all_data(prevent_save=False) - - Reset the data store to default values and remove persisted files. - - :param prevent_save: If True, when the game is saved, the data will not be persisted. - :type prevent_save: bool - :return: True, if all data was successfully removed. False, if not. - :rtype: bool - """ - try: - self.__data_store_data = dict() - self.__data_stores = dict() - if prevent_save: - self._can_be_saved = False - return self._remove() - except Exception as ex: - self.log.error('Error while resetting settings.', exception=ex) - return False - - def remove_data_store_by_name(self, name: str) -> bool: - """remove_data_store_by_name(name) - - Remove a data store by its name. - - :param name: The name of a data store. - :param name: str - :return: True, if successfully removed. False, if not. - :rtype: bool - """ - if name in self._data_stores: - del self._data_stores[name] - if name in self._data_store_data: - del self._data_store_data[name] - return True - - def _load(self) -> Dict[str, Dict[str, Any]]: - data = dict() - for persistence_service in self.persistence_services: - loaded_data = persistence_service.load(self.mod_identity, identifier=self._identifier) - self.log.format_with_message('Loaded data.', loaded_data=loaded_data) - data.update(loaded_data) - return data - - def _save(self) -> bool: - if not self._can_be_saved: - return False - success = True - self.log.format_with_message('Save data.', save_data=self._data_store_data) - for persistence_service in self.persistence_services: - success = persistence_service.save(self.mod_identity, self._data_store_data, identifier=self._identifier) - if not success: - success = False - return success - - def _remove(self) -> bool: - success = True - for persistence_service in self.persistence_services: - success = persistence_service.remove(self.mod_identity, identifier=self._identifier) - if not success: - success = False - return success - - def __repr__(self) -> str: - return self.__str__() - - def __str__(self) -> str: - return 'Data Manager: \'{}\'\n Data Stores:\n{}'.format(repr(self.mod_identity), self._data_stores) diff --git a/Scripts/s4ap/sims4communitylib/persistence/data_management/common_data_manager_registry.py b/Scripts/s4ap/sims4communitylib/persistence/data_management/common_data_manager_registry.py deleted file mode 100644 index 1e01291..0000000 --- a/Scripts/s4ap/sims4communitylib/persistence/data_management/common_data_manager_registry.py +++ /dev/null @@ -1,189 +0,0 @@ -""" -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 -""" -from typing import Union, Dict, Any, Type, Callable - -from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from s4ap.sims4communitylib.events.save.events.save_loaded import S4CLSaveLoadedEvent -from s4ap.sims4communitylib.events.save.events.save_saved import S4CLSaveSavedEvent -from s4ap.sims4communitylib.logging.has_class_log import HasClassLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.persistence.data_management.common_data_manager import CommonDataManager -from s4ap.sims4communitylib.services.common_service import CommonService - - -class CommonDataManagerRegistry(CommonService, HasClassLog): - """CommonDataManagerRegistry() - - A registry that maintains data managers for saving and loading of data. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - from typing import Tuple - from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity - from s4ap.sims4communitylib.persistence.data_management.common_data_manager import CommonDataManager - from s4ap.sims4communitylib.persistence.data_management.common_data_manager_registry import CommonDataManagerRegistry - from s4ap.sims4communitylib.persistence.persistence_services.common_persistence_service import CommonPersistenceService - - - # This attribute will register the data manager to the registry. - # @CommonDataManagerRegistry.common_data_manager() - # Passing an identifier argument will give a unique identifier to the data manager, but it isn't required unless you have multiple managers for your mod. - @CommonDataManagerRegistry.common_data_manager(identifier='I_am_unique') - class ExampleDataManager(CommonDataManager): - # noinspection PyMissingOrEmptyDocstring - @property - def mod_identity(self) -> CommonModIdentity: - # !!! Override this property using your own CommonModIdentity !!! - return ModInfo.get_identity() - - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - return 'the_example_data_manager' - - # noinspection PyMissingOrEmptyDocstring - @property - def persistence_services(self) -> Tuple[CommonPersistenceService]: - from s4ap.sims4communitylib.persistence.persistence_services.common_hidden_household_persistence_service import \ - CommonHiddenHouseholdPersistenceService - from s4ap.sims4communitylib.persistence.persistence_services.common_file_persistence_service import \ - CommonFilePersistenceService - # The order matters. The later services will override data loaded from the earlier services. In the follow, any data loaded from the file will override any matching data that was loaded from the hidden household. - result: Tuple[CommonPersistenceService] = ( - # Having this will result in the data being saved to a hidden household. - CommonHiddenHouseholdPersistenceService(), - # Having this will result in the data also being saved to a file at saves\\mod_name\\do_not_remove_mod_name_author_I_am_unique_id_1234_guid_5435.json (Notice that "I_am_unique" becomes a part of the file name because it was specified as the identifier) - CommonFilePersistenceService() - ) - return result - - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - return ModInfo.get_identity() - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 'common_data_manager_registry' - - def __init__(self) -> None: - super().__init__() - self._data_managers: Dict[str, CommonDataManager] = dict() - - @staticmethod - def common_data_manager(identifier: str = None) -> Callable[[Type[CommonDataManager]], Any]: - """common_data_manager(identifier=None) - - An attribute that will register the decorated data manager to the registry. - - :param identifier: If you need to distinguish two different data managers for your mod, this will be the unique identifier. Default is None. - :type identifier: str, optional - """ - def _inner_test_class(cls: Type[CommonDataManager]) -> Any: - nonlocal identifier - if identifier is None: - if hasattr(cls, 'get_identifier'): - identifier = cls.get_identifier() - CommonDataManagerRegistry()._register_data_manager(cls(identifier=identifier), identifier=identifier) - return cls - return _inner_test_class - - def _register_data_manager(self, data_manager: CommonDataManager, identifier: str = None): - self.log.format_with_message('Registering data store.', data_store=data_manager) - formatted_identifier = self._format_identifier(data_manager.mod_identity, identifier=identifier) - if formatted_identifier not in self._data_managers: - self._data_managers[formatted_identifier] = data_manager - - def save_data(self) -> None: - """save_data() - - Save the data of all data managers. - - """ - self.log.debug('Saving data managers.') - from s4ap.sims4communitylib.persistence.common_game_object_data_storage import _CommonGameObjectDataStorageMetaclass - for (mod_name, data_storage_library) in _CommonGameObjectDataStorageMetaclass._game_object_storage_instances.items(): - data_storage_library: Dict[int, '_CommonGameObjectDataStorageMetaclass'] = data_storage_library - for data_storage in data_storage_library.values(): - if hasattr(data_storage, '_save_persisted_data'): - data_storage._save_persisted_data() - from s4ap.sims4communitylib.persistence.common_sim_data_storage import _CommonSimDataStorageMetaclass - for (mod_name, data_storage_library) in _CommonSimDataStorageMetaclass._sim_storage_instances.items(): - data_storage_library: Dict[int, '_CommonSimDataStorageMetaclass'] = data_storage_library - for data_storage in data_storage_library.values(): - if hasattr(data_storage, '_save_persisted_data'): - data_storage._save_persisted_data() - for data_manager in self._data_managers.values(): - self.log.format_with_message('Saving data manager', data_manager=data_manager) - data_manager.save() - self.log.debug('Done saving data managers.') - - def clear_data(self) -> None: - """clear_data() - - Clear all data managers in the registry. - """ - self.log.debug('Clearing data managers.') - from s4ap.sims4communitylib.persistence.common_game_object_data_storage import _CommonGameObjectDataStorageMetaclass - _CommonGameObjectDataStorageMetaclass._game_object_storage_instances = dict() - from s4ap.sims4communitylib.persistence.common_sim_data_storage import _CommonSimDataStorageMetaclass - _CommonSimDataStorageMetaclass._sim_storage_instances = dict() - for data_manager in self._data_managers.values(): - try: - self.log.format_with_message('Saving data manager', data_manager=data_manager) - data_manager.clear() - except Exception as ex: - self.log.format_error_with_message('Failed to clear data manager. An error occurred.', data_manager=data_manager, exception=ex) - self.log.debug('Done clearing data managers.') - - def locate_data_manager(self, mod_identity: CommonModIdentity, identifier: str = None) -> Union[CommonDataManager, None]: - """locate_data_manager(mod_identity, identifier=None) - - Locate a data manager for a mod. - - :param mod_identity: The identity of the Mod. - :type mod_identity: CommonModIdentity - :param identifier: If you distinguished your data manager with an identifier when registering it, provide it here to locate the correct data manager, otherwise leave it as None. Default is None. - :type identifier: str, optional - :return: The data manager for the specified mod with the specified identifier (if specified) or None if not found. - :rtype: Union[CommonDataManager, None] - """ - formatted_identifier = self._format_identifier(mod_identity, identifier=identifier) - self.log.format_with_message('Attempting to locate data manager.', identifier=formatted_identifier) - if formatted_identifier not in self._data_managers: - self.log.format_with_message(f'Data manager not registered for mod \'{mod_identity.name}\', adding the default data manager.') - return None - self.log.debug('Located data manager.') - return self._data_managers[formatted_identifier] - - def _format_identifier(self, mod_identity: CommonModIdentity, identifier: str = None) -> str: - if identifier is None: - return repr(mod_identity) - else: - return f'{repr(mod_identity)}_{identifier}' - - -# noinspection PyUnusedLocal -@CommonEventRegistry.handle_events(ModInfo.get_identity()) -def _common_save_data_on_save_saved(event_data: S4CLSaveSavedEvent) -> bool: - CommonDataManagerRegistry().save_data() - return True - - -# noinspection PyUnusedLocal -@CommonEventRegistry.handle_events(ModInfo.get_identity()) -def _common_clear_data_on_save_loaded(event_data: S4CLSaveLoadedEvent) -> bool: - CommonDataManagerRegistry().clear_data() - return True diff --git a/Scripts/s4ap/sims4communitylib/persistence/data_stores/__init__.py b/Scripts/s4ap/sims4communitylib/persistence/data_stores/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/persistence/data_stores/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/persistence/data_stores/common_data_store.py b/Scripts/s4ap/sims4communitylib/persistence/data_stores/common_data_store.py deleted file mode 100644 index b622125..0000000 --- a/Scripts/s4ap/sims4communitylib/persistence/data_stores/common_data_store.py +++ /dev/null @@ -1,223 +0,0 @@ -""" -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 -""" -from typing import Dict, Any, Callable, Tuple - -from s4ap.sims4communitylib.classes.serialization.common_serializable import CommonSerializable - - -class CommonDataStore: - """CommonDataStore() - - Manage a subset of data. - """ - _VERSION = 'version' - - def __init__(self) -> None: - self._storage = dict(self._default_data) - - @classmethod - def get_identifier(cls) -> str: - """ The identifier of the data store. """ - raise NotImplementedError(f'Missing get_identifier class method in \'{cls.__name__}\'.') - - @property - def _version(self) -> int: - raise NotImplementedError(f'Missing _version property in \'{self.__class__.__name__}\'.') - - @property - def _default_data(self) -> Dict[str, Any]: - raise NotImplementedError(f'Missing _default_data property in \'{self.__class__.__name__}\'') - - @property - def _storage(self) -> Dict[str, Any]: - """ - A storage of data organized by identifiers. - - :return: A storage of data organized by identifiers. - :rtype: Dict[str, Any] - """ - return self.__storage - - @_storage.setter - def _storage(self, value: Dict[str, Any]): - self.__storage = value - - @property - def _persist_empty_values(self) -> bool: - return False - - @property - def whitelist_property_names(self) -> Tuple[str]: - """ - If a property is within this list, it will be persisted when saving. By default all properties are whitelisted. - - :return: A collection of property names. - :rtype: Tuple[str] - """ - return tuple(self._storage.keys()) - - @property - def blacklist_property_names(self) -> Tuple[str]: - """ - If a property is within this list, it will not be persisted when saving. By default no properties are blacklisted. - - :return: A collection of property names. - :rtype: Tuple[str] - """ - return tuple() - - def set_value_by_key(self, key: str, value: Any, encode: Callable[[Any], Any]=None): - """set_value_by_key(key, value, encode=None) - - Set data in storage by its key. - - :param key: An identifier. - :type key: str - :param value: A value. - :type value: Any - :param encode: If specified, the data will be encoded using this function and the result will be the new data stored. Default is None. - :type encode: Callable[[Any], Any], optional - """ - if encode is not None: - value = encode(value) - self._storage[key] = value - - def get_value_by_key(self, key: str, encode: Callable[[Any], Any]=None, decode: Callable[[Any], Any]=None) -> Any: - """get_value_by_key(key, encode=None, decode=None) - - Get data from storage by its key. - - :param key: An identifier. - :type key: str - :param encode: If specified, the data will be encoded using this function and the result will be the new data stored. Default is None. - :type encode: Callable[[Any], Any], optional - :param decode: If specified, the data will be decoded using this function and the result will be the new result of "get_data". Default is None. - :type decode: Callable[[Any], Any], optional - :return: The value assigned to the key or the default value if not found. - :rtype: Any - """ - if key not in self._storage: - default_val = self.get_default_value_by_key(key) - if default_val is not None: - if encode is not None: - self._storage[key] = encode(default_val) - else: - self._storage[key] = default_val - return default_val - data = self._storage.get(key) - if decode is not None and not isinstance(data, CommonSerializable): - decoded = decode(data) - if isinstance(data, CommonSerializable): - self._storage[key] = decoded - return decoded - return data - - def get_default_value_by_key(self, key: str) -> Any: - """get_default_value_by_key(key) - - Get the default value - - :param key: An identifier. - :type key: str - :return: The default value associated with the specified key or None if no default value has been provided for the specified key. - :rtype: Any - """ - if key not in self._default_data: - return None - return self._default_data[key] - - def remove_data_by_key(self, key: str) -> bool: - """remove_data_by_key(key) - - Remove data from storage. - - :param key: An identifier. - :type key: str - :return: True, if the data with the specified identifier is removed successfully. False, if not. - :rtype: bool - """ - if key not in self._storage: - return False - del self._storage[key] - return True - - def update_data(self, data: Dict[str, Any]): - """update_data(data) - - Replace the data contained within the data store. - - :param data: A library of data. - :type data: Dict[str, Any] - """ - - version_name = self.__class__._VERSION - - if data is None or not data: - self._storage = dict(self._default_data) - if version_name not in self._storage: - self._storage[version_name] = self._version - return - - if version_name not in data or int(data[version_name]) != int(self._version): - new_data = dict(data) - default_data = dict(self._default_data) - for (default_data_key, default_data_value) in default_data.items(): - # If Data has the key, we don't want to override it. Keep the old data. - if default_data_key in new_data: - continue - new_data[default_data_key] = default_data[default_data_key] - new_data[version_name] = self._version - data = new_data - - self._storage = data - - def customize_data_pre_save(self, data: Dict[str, Any]) -> Dict[str, Any]: - """customize_data_pre_save(data) - - A hook that allows customization of data before it is persisted/saved. - - :param data: The data intending to be saved, it is available for customization. - :type data: Dict[str, Any] - :return: The customized data. - :rtype: Dict[str, Any] - """ - return data - - def get_store_data_for_persistence(self) -> Dict[str, Any]: - """get_store_data_for_persistence() - - :return: The data of this data store, but in an easy to serialize format. - :rtype: Dict[str, Any] - """ - data_to_save = dict() - for data_property_name in self._storage.keys(): - if data_property_name not in self.whitelist_property_names or data_property_name in self.blacklist_property_names: - continue - data = self._storage[data_property_name] - if self._persist_empty_values: - data_to_save[data_property_name] = data.serialize() if isinstance(data, CommonSerializable) else data - else: - if data is None or (data != 0 and not isinstance(data, bool) and not data): - continue - serialized_data = data.serialize() if isinstance(data, CommonSerializable) else data - if data is None or (serialized_data != 0 and not isinstance(data, bool) and not serialized_data): - continue - data_to_save[data_property_name] = serialized_data - data_to_save = self.customize_data_pre_save(data_to_save) - if data_to_save is None: - return dict() - if not self._persist_empty_values: - if not data_to_save: - return dict() - return data_to_save - - def __repr__(self) -> str: - return self.__class__.get_identifier() - - def __str__(self) -> str: - return 'Data Store: \'{}\'\n Storage:\n{}'.format(str(self.__class__.get_identifier()), self._storage) diff --git a/Scripts/s4ap/sims4communitylib/persistence/data_stores/common_game_object_data_store.py b/Scripts/s4ap/sims4communitylib/persistence/data_stores/common_game_object_data_store.py deleted file mode 100644 index 37f9200..0000000 --- a/Scripts/s4ap/sims4communitylib/persistence/data_stores/common_game_object_data_store.py +++ /dev/null @@ -1,30 +0,0 @@ -""" -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 -""" -from typing import Dict, Any -from s4ap.sims4communitylib.persistence.data_stores.common_data_store import CommonDataStore - - -class CommonGameObjectDataStore(CommonDataStore): - """ A store of Game Object Data. """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_identifier(cls) -> str: - return 'game_object_data' - - @property - def _version(self) -> int: - return 1 - - @property - def _default_data(self) -> Dict[str, Any]: - return dict() - - # noinspection PyMissingOrEmptyDocstring - def get_default_value_by_key(self, key: str) -> Any: - return dict() diff --git a/Scripts/s4ap/sims4communitylib/persistence/data_stores/common_sim_data_store.py b/Scripts/s4ap/sims4communitylib/persistence/data_stores/common_sim_data_store.py deleted file mode 100644 index f38adb6..0000000 --- a/Scripts/s4ap/sims4communitylib/persistence/data_stores/common_sim_data_store.py +++ /dev/null @@ -1,30 +0,0 @@ -""" -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 -""" -from typing import Dict, Any -from s4ap.sims4communitylib.persistence.data_stores.common_data_store import CommonDataStore - - -class CommonSimDataStore(CommonDataStore): - """ A store of Sim Data. """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_identifier(cls) -> str: - return 'sim_data' - - @property - def _version(self) -> int: - return 1 - - @property - def _default_data(self) -> Dict[str, Any]: - return dict() - - # noinspection PyMissingOrEmptyDocstring - def get_default_value_by_key(self, key: str) -> Any: - return dict() diff --git a/Scripts/s4ap/sims4communitylib/persistence/persistence_services/__init__.py b/Scripts/s4ap/sims4communitylib/persistence/persistence_services/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/persistence/persistence_services/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_file_persistence_service.py b/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_file_persistence_service.py deleted file mode 100644 index 1191d63..0000000 --- a/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_file_persistence_service.py +++ /dev/null @@ -1,120 +0,0 @@ -""" -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 -""" -import os -from typing import Dict, Any - -from s4ap.sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.persistence.persistence_services.common_persistence_service import CommonPersistenceService -from s4ap.sims4communitylib.utils.common_json_io_utils import CommonJSONIOUtils -from s4ap.sims4communitylib.utils.save_load.common_save_utils import CommonSaveUtils - - -class CommonFilePersistenceService(CommonPersistenceService): - """CommonFilePersistenceService(per_save=True, per_save_slot=False, folder_name=None, custom_file_name=None, data_folder_path=None) - - A service that persists data into a file and loads data from a file on the system. - - :param per_save: If True, the data will persist for each Game Save file (Set "per_save_slot" to True to persist per save SLOT as well!). If False, the data will persist for all Game Save files. Default is True. - :type per_save: bool, optional - :param per_save_slot: If True, the data will persist for each Save slot. If False, the data will persist for each Game file only. Default is False. (This argument requires "per_save" to be True as well!) - :type per_save_slot: bool, optional - :param folder_name: Use to specify a custom file path after the normal file path, example: "The Sims 4/Mods/mod_data//". Default is None. - :type folder_name: str, optional - :param custom_file_name: Use to specify a custom name for the loaded and saved file. example: "The Sims 4/Mods/mod_data//" and if "folder_name" is specified: "The Sims 4/Mods/mod_data///". Default is None. - :type custom_file_name; str, optional - :param data_folder_path: Use to specify a custom folder path at the top level for which to save/load data to/from. Default is "Mods/mod_data". - :type data_folder_path: str, optional - """ - - def __init__(self, per_save: bool=True, per_save_slot: bool=False, folder_name: str=None, custom_file_name: str=None, data_folder_path: str=None) -> None: - super().__init__() - self._per_save = per_save - self._per_save_slot = per_save_slot - self._folder_name = folder_name - self._custom_file_name = custom_file_name - from s4ap.sims4communitylib.utils.common_log_utils import CommonLogUtils - self._data_folder_path = data_folder_path or CommonLogUtils.get_mod_data_location_path() - - # noinspection PyMissingOrEmptyDocstring - def load(self, mod_identity: CommonModIdentity, identifier: str=None) -> Dict[str, Any]: - file_path = self._file_path(mod_identity, identifier=identifier) - if not file_path: - return dict() - - self.log.format_with_message('Loading data.', mod=mod_identity, file_path=file_path) - - if not os.path.exists(file_path): - self.log.format_with_message('No data was found at path.', mod=mod_identity, file_path=file_path) - return dict() - - loaded_data: Dict[str, Any] = CommonJSONIOUtils.load_from_file(file_path) - if loaded_data is None: - return dict() - self.log.format_with_message('Done loading data.', mod=mod_identity, file_path=file_path, loaded_data=loaded_data) - return loaded_data - - # noinspection PyMissingOrEmptyDocstring - def save(self, mod_identity: CommonModIdentity, data: Dict[str, Any], identifier: str=None) -> bool: - if not data: - return False - file_path = self._file_path(mod_identity, identifier=identifier) - if not file_path: - return False - - self.log.format_with_message('Loading data.', mod=mod_identity, file_path=file_path) - - os.makedirs(os.path.dirname(file_path), exist_ok=True) - if os.path.exists(file_path): - self.log.debug('File existed already, removing the existing one.') - os.rename(file_path, file_path + '.Old') - - try: - result = CommonJSONIOUtils.write_to_file(file_path, data) - self.log.format_with_message('Done saving data.', file_path=file_path) - except Exception as ex: - CommonExceptionHandler.log_exception(mod_identity, 'Failed to save data', exception=ex) - if os.path.exists(file_path + '.Old'): - os.rename(file_path + '.Old', file_path) - return False - if result and os.path.exists(file_path + '.Old'): - os.remove(file_path + '.Old') - return result - - # noinspection PyMissingOrEmptyDocstring - def remove(self, mod_identity: CommonModIdentity, identifier: str=None) -> bool: - file_path = self._file_path(mod_identity, identifier=identifier) - - self.log.format_with_message('Loading data.', mod=mod_identity, file_path=file_path) - - if os.path.exists(file_path): - self.log.debug('File existed already, removing the existing one.') - os.remove(file_path) - - self.log.format_with_message('Data deleted successfully.', file_path=file_path) - return not os.path.exists(file_path) - - def _file_path(self, mod_identity: CommonModIdentity, identifier: str=None) -> str: - data_name = self._format_data_name(mod_identity, identifier=identifier) - folder_path = os.path.join(self._data_folder_path, mod_identity.base_namespace.lower()) - if self._folder_name is not None: - folder_path = os.path.join(folder_path, self._folder_name) - if self._custom_file_name is not None: - return os.path.join(folder_path, self._custom_file_name) - if self._per_save: - save_slot_guid = CommonSaveUtils.get_save_slot_guid() - from s4ap.sims4communitylib.s4cl_configuration import S4CLConfiguration - if self._per_save_slot or S4CLConfiguration().persist_mod_data_per_save_slot: - save_slot_id = CommonSaveUtils.get_save_slot_id() - if save_slot_id == 0: - return '' - return os.path.join(folder_path, f'{data_name}_id_{save_slot_id}_guid_{save_slot_guid}.json') - else: - return os.path.join(folder_path, f'{data_name}_guid_{save_slot_guid}.json') - else: - return os.path.join(folder_path, f'{data_name}.json') diff --git a/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_folder_persistence_service.py b/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_folder_persistence_service.py deleted file mode 100644 index d5f5142..0000000 --- a/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_folder_persistence_service.py +++ /dev/null @@ -1,152 +0,0 @@ -""" -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 -""" -import os -from typing import Dict, Any - -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.persistence.persistence_services.common_persistence_service import CommonPersistenceService -from s4ap.sims4communitylib.utils.common_collection_utils import CommonCollectionUtils -from s4ap.sims4communitylib.utils.common_json_io_utils import CommonJSONIOUtils -from s4ap.sims4communitylib.utils.common_log_registry import CommonLogRegistry - - -class CommonFolderPersistenceService(CommonPersistenceService): - """CommonFolderPersistenceService(main_file_name='main.json', combined_file_name='combined.json', allow_duplicates_in_collections=False, data_folder_path=None) - - A service that persists data to a file within a folder on the system. It also loads all data from a folder on the system while loading the main file last. - - :param main_file_name: A file that will be loaded after the other files in the folder specified by folder_name. Default is 'main.json'. - :type main_file_name: str, optional - :param combined_file_name: The name of the file to persist data to when saving. Default is combined.json - :type combined_file_name: str, optional - :param allow_duplicates_in_collections: When loading the dictionary data and merging it, if set to True, duplicate values will be allowed to exist within collections within those dictionaries. Default is False. - :type allow_duplicates_in_collections: bool, optional - :param data_folder_path: Use to specify a custom folder path at the top level for which to save/load data to/from. Default is "Mods/mod_data". - :type data_folder_path: str, optional - :param create_combined_file: If True, after reading through all json files, a combined.json file will be created that will include all other json data. If false, a combined.json file will not be created. Default is false. - :type create_combined_file: bool, optional - """ - - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - return 'common_folder_persistence_service' - - def __init__( - self, - main_file_name: str='main.json', - combined_file_name: str='combined.json', - allow_duplicates_in_collections: bool=False, - data_folder_path: str=None, - create_combined_file: bool=False - ) -> None: - super().__init__() - self._main_file_name = main_file_name - self._combined_file_name = combined_file_name - self._allow_duplicates_in_collections = allow_duplicates_in_collections - from s4ap.sims4communitylib.utils.common_log_utils import CommonLogUtils - self._data_folder_path = data_folder_path or CommonLogUtils.get_mod_data_location_path() - from s4ap.sims4communitylib.s4cl_configuration import S4CLConfiguration - self._create_combined_file = create_combined_file or S4CLConfiguration().create_combined_json - - # noinspection PyMissingOrEmptyDocstring - def load(self, mod_identity: CommonModIdentity, identifier: str=None) -> Dict[str, Any]: - # mod_folder_persistence_service - log = CommonLogRegistry().register_log(mod_identity, '{}_{}'.format(mod_identity.base_namespace, self.log_identifier)) - folder_path = self._folder_path(mod_identity, identifier=identifier) - - log.format_with_message('Loading data.', mod=mod_identity, folder_path=folder_path) - - if not os.path.exists(folder_path): - log.format_with_message('No folder was found at path.', mod=mod_identity, folder_path=folder_path) - return dict() - file_names = list() - - main_file_path = os.path.join(folder_path, self._main_file_name) - loaded_main_data: Dict[str, Any] = CommonJSONIOUtils.load_from_file(main_file_path) - if loaded_main_data is None: - log.format_with_message('Missing main data!', main_file_path=main_file_path) - loaded_main_data = dict() - - file_names.append(self._main_file_name) - - if self._create_combined_file: - combined_file_path = os.path.join(folder_path, self._combined_file_name) - loaded_combined_data: Dict[str, Any] = CommonJSONIOUtils.load_from_file(combined_file_path) - else: - loaded_combined_data = None - - def _on_file_read_failure(file_path: str, ex: Exception): - log.error('Failed to read file with path {}'.format(file_path), exception=ex) - return True - - loaded_data: Dict[str, Dict[str, Any]] = CommonJSONIOUtils.load_from_folder( - folder_path, - skip_file_names=(self._main_file_name, self._combined_file_name), - on_file_read_failure=_on_file_read_failure - ) - if loaded_data is None: - return dict() - complete_data = dict() - for (key, val) in loaded_data.items(): - file_names.append(key) - complete_data = CommonCollectionUtils.merge_dict(complete_data, val, prefer_source_values=True, allow_duplicates_in_collections=self._allow_duplicates_in_collections) - if self._create_combined_file: - if loaded_combined_data is not None: - complete_data = CommonCollectionUtils.merge_dict(loaded_combined_data, complete_data, prefer_source_values=True, allow_duplicates_in_collections=self._allow_duplicates_in_collections) - complete_data = CommonCollectionUtils.merge_dict(complete_data, loaded_main_data, prefer_source_values=True, allow_duplicates_in_collections=self._allow_duplicates_in_collections) - log.format_with_message('Done loading data.', mod=mod_identity, folder_path=folder_path, complete_data=complete_data, file_names=file_names) - complete_data['loaded_file_names'] = file_names - return complete_data - - # noinspection PyMissingOrEmptyDocstring - def save(self, mod_identity: CommonModIdentity, data: Dict[str, Any], identifier: str=None) -> bool: - # mod_folder_persistence_service - log = CommonLogRegistry().register_log(mod_identity, '{}_{}'.format(mod_identity.base_namespace, self.log_identifier)) - folder_path = self._folder_path(mod_identity, identifier=identifier) - data_to_save = data.copy() - - if self._create_combined_file: - file_path = os.path.join(folder_path, self._combined_file_name) - log.format_with_message('Loading data.', mod=mod_identity, file_path=file_path) - if 'loaded_file_names' in data_to_save: - del data_to_save['loaded_file_names'] - - os.makedirs(folder_path, exist_ok=True) - if os.path.exists(file_path): - log.debug('File existed already, removing the existing one.') - os.remove(file_path) - - result = CommonJSONIOUtils.write_to_file(file_path, data_to_save) - log.format_with_message('Done saving data.', file_path=file_path) - return result - return True - - # noinspection PyMissingOrEmptyDocstring - def remove(self, mod_identity: CommonModIdentity, identifier: str=None) -> bool: - # mod_folder_persistence_service - log = CommonLogRegistry().register_log(mod_identity, '{}_{}'.format(mod_identity.base_namespace, self.log_identifier)) - folder_path = self._folder_path(mod_identity, identifier=identifier) - - if self._create_combined_file: - file_path = os.path.join(folder_path, self._combined_file_name) - log.format_with_message('Removing data.', mod=mod_identity, file_path=file_path) - - if os.path.exists(file_path): - log.debug('Data existed, removing it.') - os.remove(file_path) - - log.format_with_message('Data deleted successfully.', file_path=file_path) - return not os.path.exists(file_path) - return True - - def _folder_path(self, mod_identity: CommonModIdentity, identifier: str=None) -> str: - folder_path = os.path.join(self._data_folder_path, mod_identity.base_namespace.lower()) - if identifier is not None: - folder_path = os.path.join(folder_path, identifier) - return folder_path diff --git a/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_hidden_household_persistence_service.py b/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_hidden_household_persistence_service.py deleted file mode 100644 index 3266275..0000000 --- a/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_hidden_household_persistence_service.py +++ /dev/null @@ -1,118 +0,0 @@ -""" -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 -""" -import json -from typing import Dict, Any - -from sims.household import Household -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.persistence.persistence_services.common_persistence_service import CommonPersistenceService -from s4ap.sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils - - -class CommonHiddenHouseholdPersistenceService(CommonPersistenceService): - """CommonHiddenHouseholdPersistenceService() - - A service that persists data into a hidden household. (This data is per save file, it won't carry to other Saves) - """ - - # noinspection PyMissingOrEmptyDocstring - def load(self, mod_identity: CommonModIdentity, identifier: str=None) -> Dict[str, Any]: - data_name = self._format_data_name(mod_identity, identifier=identifier) - all_households = tuple(CommonHouseholdUtils.get_all_households_generator()) - if not all_households: - raise Exception(f'Households have not been loaded yet, but data with name {data_name} is attempting to be loaded! Please try to use the data after the households have been loaded instead. (Households are available when the S4CLZoneLateLoadEvent event is dispatched)') - - self.log.format_with_message('Loading data.', data_name=data_name) - loaded_data: Dict[str, Any] = None - loaded_household: Household = None - - def _load_data_from_household(household: Household) -> Dict[str, Any]: - # noinspection PyPropertyAccess - _household_name = household.name - # noinspection PyPropertyAccess - self.log.format_with_message('Attempting to read data stored within household.', household_name=_household_name, household_id=household.id) - # noinspection PyPropertyAccess - raw_data = household.description - if not raw_data: - self.log.format_with_message('No raw data found, returning default data.', data=household) - return dict() - self.log.debug('Data found, attempting to parse data.') - return json.loads(raw_data) - - self.log.format_with_message('Attempting to locate data by exact name', data_name=data_name) - located_household = CommonHouseholdUtils.locate_household_by_name(data_name) - if located_household is not None: - self.log.format_with_message('Located data with exact name.', data_name=data_name) - loaded_data = _load_data_from_household(located_household) - if loaded_data is not None: - loaded_household = located_household - - self.log.format_with_message('Attempting to locate data containing name.', data_name=data_name) - for persisted_household in CommonHouseholdUtils.locate_households_by_name_generator(data_name, allow_partial_match=True): - if persisted_household is None or (loaded_household is not None and persisted_household is loaded_household): - self.log.debug('Household does not match.') - continue - # noinspection PyPropertyAccess - household_name = persisted_household.name - if loaded_data is not None: - # noinspection PyPropertyAccess - self.log.format_with_message('Duplicate household found, attempting to remove duplicate.', household_name=household_name, household_id=persisted_household.id) - if CommonHouseholdUtils.delete_household(persisted_household): - self.log.format_with_message('Successfully deleted duplicate household.', household_name=household_name) - else: - self.log.format_with_message('Failed to delete duplicate household.', household_name=household_name) - continue - loaded_data = _load_data_from_household(persisted_household) - if loaded_data is not None: - loaded_household = persisted_household - if loaded_data is None: - return dict() - self.log.format_with_message('Done loading data.', data_name=data_name, loaded_data=loaded_data) - return loaded_data - - # noinspection PyMissingOrEmptyDocstring - def save(self, mod_identity: CommonModIdentity, data: Dict[str, Any], identifier: str=None) -> bool: - data_name = self._format_data_name(mod_identity, identifier=identifier) - self.log.format_with_message('Saving data.', data_name=data_name) - self.log.format_with_message('Attempting to locate data.', data_name=data_name) - persisted_data_storage = CommonHouseholdUtils.locate_household_by_name(data_name) - if persisted_data_storage is None: - self.log.debug('No persisted data found, creating new persisted data.') - persisted_data_storage = CommonHouseholdUtils.create_empty_household(as_hidden_household=True) - if persisted_data_storage is None: - self.log.debug('Failed to persisted data.') - return False - self.log.debug('Persisted data created successfully. Setting properties.') - persisted_data_storage.name = data_name - persisted_data_storage.creator_id = 0 - persisted_data_storage.creator_name = data_name - persisted_data_storage.creator_uuid = b'' - else: - self.log.format_with_message('Found persisted data. Attempting to save data.', data=persisted_data_storage) - self.log.format_with_message('Attempting to save data.', data=persisted_data_storage) - try: - self.log.format(data_being_saved=data) - json_save_data = json.dumps(data) - persisted_data_storage.description = json_save_data - except Exception as ex: - self.log.format_error_with_message('Failed to save data.', data_name=data_name, exception=ex) - raise ex - self.log.format_with_message('Done saving data.', data_name=data_name) - return True - - # noinspection PyMissingOrEmptyDocstring - def remove(self, mod_identity: CommonModIdentity, identifier: str=None) -> bool: - data_name = self._format_data_name(mod_identity, identifier=identifier) - self.log.format_with_message('Removing data.', data_name=data_name) - self.log.format_with_message('Attempting to remove data.', data_name=data_name) - result = CommonHouseholdUtils.delete_households_with_name(data_name, allow_partial_match=True) - if not result: - self.log.format_with_message('Failed to delete data.', data_name=data_name) - return result - self.log.format_with_message('Data deleted successfully.', data_name=data_name) - return result diff --git a/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_individual_folder_persistence_service.py b/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_individual_folder_persistence_service.py deleted file mode 100644 index 574ab5a..0000000 --- a/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_individual_folder_persistence_service.py +++ /dev/null @@ -1,114 +0,0 @@ -""" -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 -""" -import os -from typing import Dict, Any - -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.persistence.persistence_services.common_persistence_service import CommonPersistenceService -from s4ap.sims4communitylib.utils.common_json_io_utils import CommonJSONIOUtils -from s4ap.sims4communitylib.utils.common_log_registry import CommonLogRegistry - - -class CommonIndividualFolderPersistenceService(CommonPersistenceService): - """CommonIndividualFolderPersistenceService(main_file_name='main.json', combined_file_name='combined.json', allow_duplicates_in_collections=False, data_folder_path=None) - - A service that persists data to a file within a folder on the system. It also loads all data from a folder on the system while loading the main file last. - - :param main_file_name: A file that will be loaded after the other files in the folder specified by folder_name. Default is 'main.json'. - :type main_file_name: str, optional - :param data_folder_path: Use to specify a custom folder path at the top level for which to save/load data to/from. Default is "Mods/mod_data". - :type data_folder_path: str, optional - """ - - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - return 'common_individual_folder_persistence_service' - - def __init__( - self, - main_file_name: str = 'main.json', - data_folder_path: str = None - ) -> None: - super().__init__() - self._main_file_name = main_file_name - from s4ap.sims4communitylib.utils.common_log_utils import CommonLogUtils - self._data_folder_path = data_folder_path or CommonLogUtils.get_mod_data_location_path() - - # noinspection PyMissingOrEmptyDocstring - def load(self, mod_identity: CommonModIdentity, identifier: str = None) -> Dict[str, Dict[str, Any]]: - # mod_folder_persistence_service - log = CommonLogRegistry().register_log(mod_identity, f'{mod_identity.base_namespace}_{self.log_identifier}') - folder_path = self._folder_path(mod_identity, identifier=identifier) - - log.format_with_message('Loading data.', mod=mod_identity, folder_path=folder_path, identifier=identifier) - - if not os.path.exists(folder_path): - log.format_with_message('No folder was found at path.', mod=mod_identity, folder_path=folder_path) - return dict() - file_names = list() - - main_file_path = os.path.join(folder_path, self._main_file_name) - loaded_main_data: Dict[str, Any] = CommonJSONIOUtils.load_from_file(main_file_path) - if loaded_main_data is None: - log.format_with_message('Missing main data!', main_file_path=main_file_path) - loaded_main_data = dict() - - file_names.append(self._main_file_name) - - def _on_file_read_failure(file_path: str, ex: Exception): - log.error(f'Failed to read file with path {file_path}', exception=ex) - return True - - loaded_data: Dict[str, Dict[str, Any]] = CommonJSONIOUtils.load_from_folder( - folder_path, - skip_file_names=(self._main_file_name,), - on_file_read_failure=_on_file_read_failure - ) - log.format_with_message('Got loaded data.', loaded_data=loaded_data) - if loaded_data is None: - return dict() - data_by_file_name: Dict[str, Dict[str, Any]] = dict() - for (key, val) in loaded_data.items(): - data_by_file_name[key] = val - file_names.append(key) - data_by_file_name[self._main_file_name] = loaded_main_data - log.format_with_message('Done loading data.', mod=mod_identity, folder_path=folder_path, complete_data=data_by_file_name, file_names=file_names) - return data_by_file_name - - # noinspection PyMissingOrEmptyDocstring - def save(self, mod_identity: CommonModIdentity, data: Dict[str, Dict[str, Any]], identifier: str = None) -> bool: - # mod_folder_persistence_service - log = CommonLogRegistry().register_log(mod_identity, f'{mod_identity.base_namespace}_{self.log_identifier}') - folder_path = self._folder_path(mod_identity, identifier=identifier) - for (file_name, file_data) in data.items(): - if file_name == 'main.json': - continue - file_path = os.path.join(folder_path, file_name) - log.format_with_message('Loading data.', mod=mod_identity, file_path=file_path) - - os.makedirs(folder_path, exist_ok=True) - if os.path.exists(file_path): - log.debug('File existed already, removing the existing one.') - os.remove(file_path) - - result = CommonJSONIOUtils.write_to_file(file_path, file_data) - log.format_with_message('Done saving data.', file_path=file_path) - if not result: - log.format_with_message('Failed to save data.', file_path=file_path, data=file_data) - return True - - # noinspection PyMissingOrEmptyDocstring - def remove(self, mod_identity: CommonModIdentity, identifier: str = None) -> bool: - return True - - def _folder_path(self, mod_identity: CommonModIdentity, identifier: str = None) -> str: - folder_path = os.path.join(self._data_folder_path, mod_identity.base_namespace.lower()) - if identifier is not None: - folder_path = os.path.join(folder_path, identifier) - return folder_path diff --git a/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_persistence_service.py b/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_persistence_service.py deleted file mode 100644 index 490c262..0000000 --- a/Scripts/s4ap/sims4communitylib/persistence/persistence_services/common_persistence_service.py +++ /dev/null @@ -1,85 +0,0 @@ -""" -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 -""" -from typing import Dict, Any - -from s4ap.sims4communitylib.logging.has_log import HasLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo - - -class CommonPersistenceService(HasLog): - """CommonPersistenceService() - - A service used to persist data. - - """ - - # noinspection PyMissingOrEmptyDocstring - @property - def mod_identity(self) -> CommonModIdentity: - return ModInfo.get_identity() - - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - return 'common_persistence_service' - - def __init__(self) -> None: - super().__init__() - if self.__class__.__name__ == CommonPersistenceService.__name__: - raise RuntimeError('{} cannot be created directly. You must inherit from it to create an instance of it.'.format(self.__class__.__name__)) - - def _format_data_name(self, mod_identity: CommonModIdentity, identifier: str=None) -> str: - if identifier is not None: - return '{}_{}'.format(mod_identity.base_namespace, identifier.replace(' ', '_')).lower() - else: - return '{}_main'.format(mod_identity.base_namespace).lower() - - def load(self, mod_identity: CommonModIdentity, identifier: str=None) -> Dict[str, Any]: - """load(mod_identity, identifier=None) - - Load persisted data for the specified Mod Identity. - - :param mod_identity: The identity of the mod that data is being loaded for. - :type mod_identity: CommonModIdentity - :param identifier: If set, the identifier will be used to make the data name even more unique. Don't set it if you don't need to! Default is None. - :type identifier: str, optional - :return: A library of data. - :rtype: Dict[str, Any] - """ - raise NotImplementedError() - - def save(self, mod_identity: CommonModIdentity, data: Dict[str, Any], identifier: str=None) -> bool: - """save(mod_identity, data, identifier=None) - - Save persisted data for the specified Mod Identity. - - :param mod_identity: The identity of the mod that data is being saved for. - :type mod_identity: CommonModIdentity - :param data: The data being persisted. - :type data: Dict[str, Any] - :param identifier: If set, the identifier will be used to make the data name even more unique. Don't set it if you don't need to! Default is None. - :type identifier: str, optional - :return: True, if the data was persisted successfully. False, if not. - :rtype: bool - """ - raise NotImplementedError() - - def remove(self, mod_identity: CommonModIdentity, identifier: str=None) -> bool: - """remove(mod_identity) - - Removed persisted data for the specified Mod Identity. - - :param mod_identity: The identity of the mod that data is being removed for. - :type mod_identity: CommonModIdentity - :param identifier: If set, the identifier will be used to make the data name even more unique. Don't set it if you don't need to! Default is None. - :type identifier: str, optional - :return: True, if the data was removed successfully. False, if not. - :rtype: bool - """ - raise NotImplementedError() diff --git a/Scripts/s4ap/sims4communitylib/s4cl_commands.py b/Scripts/s4ap/sims4communitylib/s4cl_commands.py deleted file mode 100644 index 5ce92ee..0000000 --- a/Scripts/s4ap/sims4communitylib/s4cl_commands.py +++ /dev/null @@ -1,87 +0,0 @@ -""" -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 -""" -from objects.game_object import GameObject -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ - CommonConsoleCommandArgument -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.common_log_registry import CommonLogRegistry -from s4ap.sims4communitylib.utils.misc.common_fire_utils import CommonFireUtils -from s4ap.sims4communitylib.utils.objects.common_object_location_utils import CommonObjectLocationUtils -from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils -from s4ap.sims4communitylib.utils.sims.common_sim_location_utils import CommonSimLocationUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from s4ap.sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils - -log = CommonLogRegistry().register_log(ModInfo.get_identity(), 's4cl_commands') -log.enable() - - -@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.the_mother_calls', 'Invokes the mothers call.', show_with_help_command=False) -def _common_the_mother_calls(output: CommonConsoleCommandOutput): - output('She calls and you must listen! Who shall answer the call?') - sim_count = 0 - # trait_Strangerville_Infected - trait_id = 201407 - output(f'The call has begun, who shall answer it?') - for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): - if CommonTraitUtils.has_trait(sim_info, trait_id): - continue - if CommonTraitUtils.add_trait(sim_info, trait_id): - sim_count += 1 - output(f'{sim_count} Sim(s) have answered the call.') - - -@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.come_to_me_now', 'Formally request all objects in the area to come to the active Sim.', show_with_help_command=False) -def _common_come_to_me_now(output: CommonConsoleCommandOutput): - sim_info = CommonSimUtils.get_active_sim_info() - new_location = CommonSimLocationUtils.get_location(sim_info) - object_count = 0 - output(f'Attempting to request all objects to come to {sim_info}.') - for game_object in CommonObjectUtils.get_instance_for_all_game_objects_generator(): - # noinspection PyBroadException - try: - CommonObjectLocationUtils.set_location(game_object, new_location) - object_count += 1 - except: - continue - output(f'{object_count} Object(s) came to {sim_info}.') - - -@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.burn_it_all', 'Some Sims just want to see the world burn.', show_with_help_command=False) -def _common_burn_it_all(output: CommonConsoleCommandOutput): - object_count = 0 - output(f'Do you smell smoke?') - for game_object in CommonObjectUtils.get_instance_for_all_game_objects_generator(): - # noinspection PyBroadException - try: - if CommonFireUtils.spawn_fires_on_object(game_object): - object_count += 1 - except: - continue - output(f'{object_count} Object(s) have been set ablaze. You might want to run now.') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.burn_it', - 'Some Sims just want to see the world burn.', - command_arguments=( - CommonConsoleCommandArgument('game_object', 'Decimal ID', 'The Decimal Identifier of the object to spawn a fire at.'), - ), - show_with_help_command=False -) -def _common_burn_it(output: CommonConsoleCommandOutput, game_object: GameObject): - output(f'Do you smell smoke?') - if not CommonFireUtils.is_fire_allowed_at_location(CommonObjectLocationUtils.get_location(game_object)): - output(f'Fires are not allowed on the object. {game_object}.') - return - if CommonFireUtils.spawn_fires_on_object(game_object): - output(f'{game_object} has been set ablaze. You might want to run now.') - else: - output(f'For some reason {game_object} failed to catch fire.') diff --git a/Scripts/s4ap/sims4communitylib/s4cl_configuration.py b/Scripts/s4ap/sims4communitylib/s4cl_configuration.py deleted file mode 100644 index 45cf240..0000000 --- a/Scripts/s4ap/sims4communitylib/s4cl_configuration.py +++ /dev/null @@ -1,130 +0,0 @@ -""" -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 -""" -import os -from typing import Tuple, Dict, List, Any - -from s4ap.sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler -from s4ap.sims4communitylib.logging.has_log import HasLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.modinfo import ModInfo -from s4ap.sims4communitylib.services.common_service import CommonService -from s4ap.sims4communitylib.utils.common_json_io_utils import CommonJSONIOUtils -from s4ap.sims4communitylib.utils.common_log_registry import CommonMessageType -from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils - -ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' - - -class S4CLConfiguration(HasLog, CommonService): - """ Manages configuration via the sims4communitylib.config file. """ - _CONFIGURATION_FILE_NAME = 'sims4communitylib.config' - if not ON_RTD: - _DEFAULT_CONFIG_DATA = { - 'enable_vanilla_logging': False, - 'enable_extra_shift_click_menus': True, - 'persist_mod_data_per_save_slot': False, - 'create_combined_json': False, - 'max_output_file_size_in_bytes': 524288000, - 'enable_logs': { - 'example_log_that_is_enabled': ['DEBUG', 'WARN'] - } - } - else: - _DEFAULT_CONFIG_DATA = dict() - - # noinspection PyMissingOrEmptyDocstring - @property - def mod_identity(self) -> CommonModIdentity: - return ModInfo.get_identity() - - def __init__(self) -> None: - self._config_data = dict() - super().__init__() - self._config_data: Dict[str, Any] = S4CLConfiguration._DEFAULT_CONFIG_DATA.copy() - try: - file_path = os.path.dirname(os.path.dirname(os.path.dirname(self.mod_identity.file_path.rstrip('/').rstrip('\\')))) - full_file_path = os.path.join(file_path, S4CLConfiguration._CONFIGURATION_FILE_NAME) - try: - if os.path.exists(full_file_path): - existing_config_data = CommonJSONIOUtils.load_from_file(full_file_path) or dict() - if 'enable_logs_result' in existing_config_data: - del existing_config_data['enable_logs_result'] - self._config_data.update(existing_config_data) - CommonJSONIOUtils.write_to_file(full_file_path, self._config_data) - else: - CommonJSONIOUtils.write_to_file(full_file_path, self._config_data) - except Exception as ex: - CommonExceptionHandler.log_exception(self.mod_identity, 'Failed to read the configuration file named {} at path "{}"!'.format(S4CLConfiguration._CONFIGURATION_FILE_NAME, full_file_path), exception=ex) - if not os.path.exists(full_file_path): - # noinspection PyBroadException - try: - CommonJSONIOUtils.write_to_file(full_file_path, self._config_data) - except: - pass - except Exception as ex: - CommonExceptionHandler.log_exception(self.mod_identity, 'Failed to format the file path to the S4CL configuration file.', exception=ex) - - @property - def persist_mod_data_per_save_slot(self) -> bool: - """Whether or not mod_data should include the save slot id within the persisted data file names. If False, only the Guid will be present in the file names. This value will also have an effect on loading files too!""" - if self._config_data is None or not self._config_data: - return False - return self._config_data.get('persist_mod_data_per_save_slot', False) - - @property - def enable_vanilla_logging(self) -> bool: - """ Whether or not vanilla logging should be enabled. """ - if self._config_data is None or not self._config_data: - return False - return self._config_data.get('enable_vanilla_logging', False) - - @property - def max_output_file_size_in_bytes(self) -> int: - """ The maximum size a file created by S4CL can be in bytes. """ - if self._config_data is None or not self._config_data: - return False - return self._config_data.get('max_output_file_size_in_bytes', 524288000) - - @property - def enable_extra_shift_click_menus(self) -> bool: - """ Whether or not to enable the SHIFT+CLICK menu in places that normally do not have a SHIFT+CLICK menu due to the ignorance of the SHIFT key. i.e. Relationship Panel, Phone, and Inventory. """ - if self._config_data is None or not self._config_data: - return False - return self._config_data.get('enable_extra_shift_click_menus', False) - - @property - def create_combined_json(self) -> bool: - """ Whether or not to create a combined.json file when reading through folders. """ - if self._config_data is None or not self._config_data: - return False - return self._config_data.get('create_combined_json', False) - - @property - def enable_logs(self) -> Dict[str, Tuple[CommonMessageType]]: - """ Logs to enable before loading The Sims 4. """ - if self._config_data is None or not self._config_data: - return dict() - if 'enable_logs_result' in self._config_data: - return self._config_data.get('enable_logs_result', dict()) - enable_logs = self._config_data.get('enable_logs', dict()) - enable_logs_result: Dict[str, Tuple[CommonMessageType]] = dict() - try: - for (key, message_type_strings) in enable_logs.items(): - message_types: List[CommonMessageType] = list() - for message_type_string in message_type_strings: - message_type: CommonMessageType = CommonResourceUtils.get_enum_by_name(message_type_string, CommonMessageType, default_value=CommonMessageType.INVALID) - if message_type is None: - continue - message_types.append(message_type) - if message_types: - enable_logs_result[key] = tuple(message_types) - except Exception as ex: - CommonExceptionHandler.log_exception(self.mod_identity, 'Error occurred while parsing the enable_logs configuration value.', exception=ex) - return dict() - self._config_data['enable_logs_result'] = enable_logs_result - return enable_logs_result diff --git a/Scripts/s4ap/sims4communitylib/services/__init__.py b/Scripts/s4ap/sims4communitylib/services/__init__.py deleted file mode 100644 index 3251898..0000000 --- a/Scripts/s4ap/sims4communitylib/services/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" \ No newline at end of file diff --git a/Scripts/s4ap/sims4communitylib/services/commands/__init__.py b/Scripts/s4ap/sims4communitylib/services/commands/__init__.py deleted file mode 100644 index 3251898..0000000 --- a/Scripts/s4ap/sims4communitylib/services/commands/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" \ No newline at end of file diff --git a/Scripts/s4ap/sims4communitylib/services/commands/common_console_command.py b/Scripts/s4ap/sims4communitylib/services/commands/common_console_command.py deleted file mode 100644 index 5d3785a..0000000 --- a/Scripts/s4ap/sims4communitylib/services/commands/common_console_command.py +++ /dev/null @@ -1,664 +0,0 @@ -""" -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 -""" -import inspect -from functools import wraps -from typing import Any, Dict, Union, Iterator, Tuple, Type, List, TYPE_CHECKING - -from objects.game_object import GameObject -from sims.sim_info import SimInfo -from sims4.commands import CommandType, CommandRestrictionFlags, Output, CustomParam -from sims4.common import Pack -from s4ap.sims4communitylib.logging.has_class_log import HasClassLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.services.common_service import CommonService -from singletons import UNSET - -if TYPE_CHECKING: - from s4ap.sims4communitylib.utils.common_log_registry import CommonLog - - -class CommonConsoleCommandArgument: - """CommonConsoleCommandArgument(arg_name, arg_type_name, arg_description, is_optional=False, default_value=None) - - An object that describes details about an argument that is used in a command. - - :param arg_name: A name to display for the argument. - :type arg_name: str - :param arg_type_name: Text to display that represents the type of the argument. - :type arg_type_name: str - :param arg_description: Text that describes what the argument is for. - :type arg_description: str - :param is_optional: Whether or not the argument is optional or required to be specified in the command. Default is False. - :type is_optional: bool, optional - :param default_value: If the argument is optional, this is the default value that will be used for the argument. Default is None. - :type default_value: Any, optional - """ - def __init__(self, arg_name: str, arg_type_name: str, arg_description: str, is_optional: bool=False, default_value: Any=None): - self.arg_name = arg_name - self.arg_type_name = arg_type_name - self.arg_description = arg_description or 'No Description Provided' - self.is_optional = is_optional or (default_value is not None) - self.default_value = default_value - - def __repr__(self) -> str: - name = self.arg_name - if self.is_optional: - default_value = self.default_value - name = f'[{name}={default_value}]' - else: - name = f'{name}' - return name - - def __str__(self) -> str: - repr_result = self.__repr__() - arg_type_name = self.arg_type_name - description = self.arg_description - return f'{repr_result} ({arg_type_name}) - {description}' - - -class CommonConsoleCommandOptionalArgument(CommonConsoleCommandArgument): - """CommonConsoleCommandArgument(arg_name, arg_type_name, arg_description, default_value) - - An object that describes details about an Optional argument that is used in a command. - - :param arg_name: A name to display for the argument. - :type arg_name: str - :param arg_type_name: Text to display that represents the type of the argument. - :type arg_type_name: str - :param arg_description: Text that describes what the argument is for. - :type arg_description: str - :param default_value: This is the default value that will be used for the argument. - :type default_value: Any - """ - def __init__(self, arg_name: str, arg_type_name: str, arg_description: str, default_value: Any): - super().__init__(arg_name, arg_type_name, arg_description, is_optional=True, default_value=default_value) - - -class CommonConsoleCommandRequiredArgument(CommonConsoleCommandArgument): - """CommonConsoleCommandArgument(arg_name, arg_type_name, arg_description) - - An object that describes details about a Required argument that is used in a command. - - :param arg_name: A name to display for the argument. - :type arg_name: str - :param arg_type_name: Text to display that represents the type of the argument. - :type arg_type_name: str - :param arg_description: Text that describes what the argument is for. - :type arg_description: str - """ - def __init__(self, arg_name: str, arg_type_name: str, arg_description: str): - super().__init__(arg_name, arg_type_name, arg_description, is_optional=False) - - -class _CommonConsoleCommandMetaclass(type): - def __call__( - cls, - mod_identity: CommonModIdentity, - command_name: str, - command_description: str, - command_aliases: Iterator[str]=(), - command_arguments: Iterator[CommonConsoleCommandArgument]=(), - command_type: CommandType=CommandType.Live, - command_restriction_flags: CommandRestrictionFlags=CommandRestrictionFlags.UNRESTRICTED, - required_pack_flags: Pack=None, - console_type: CommandType=None, - show_with_help_command: bool=True - ) -> Union['_CommonConsoleCommandMetaclass', None]: - mod_name = mod_identity.name - if mod_name is None: - return None - command = CommonConsoleCommandService().get_command_by_mod_and_name(mod_identity, command_name) - if command is None: - command = super(_CommonConsoleCommandMetaclass, cls).__call__( - mod_identity, - command_name, - command_description, - command_aliases=command_aliases, - command_arguments=command_arguments, - command_type=command_type, - command_restriction_flags=command_restriction_flags, - required_pack_flags=required_pack_flags, - console_type=console_type, - show_with_help_command=show_with_help_command - ) - CommonConsoleCommandService()._add_command(command) - return CommonConsoleCommandService().command(mod_identity, command_name, *command_aliases, command_type=command_type, command_restriction_flags=command_restriction_flags, required_pack_flags=required_pack_flags, console_type=console_type) - - -class CommonConsoleCommand(metaclass=_CommonConsoleCommandMetaclass): - """CommonConsoleCommand(\ - mod_identity,\ - command_name,\ - command_description,\ - command_aliases=(),\ - command_arguments=(),\ - command_type=CommandType.Live,\ - command_restriction_flags=CommandRestrictionFlags.UNRESTRICTED,\ - required_pack_flags=None,\ - console_type=None,\ - show_with_help_command=True\ - ) - - Used to indicate a command that can be run in the CTRL+SHIFT+C console. - - .. note:: When a command is created, a Help command is also created for your Mod using the mod_identity.name (If it does not already exist) ".help". Use this command to display all commands that have been registered using CommonConsoleCommand. - - .. note:: To see an example command, run the command :class:`s4clib_testing.example_command` in the in-game console. - .. note:: If the command_name contains underscores, a variant of the command_name without underscores will be added to command_aliases. i.e. 's4cl.do_thing' will be added as 's4cl.dothing' to command_aliases. - .. note:: If any command_aliases contain underscores, variants of those command_aliases without underscores will be added to command_aliases. i.e. 's4cl.do_the_thing' will be added as 's4cl.dothething' to command_aliases. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - @CommonConsoleCommand(ModInfo.get_identity(), 's4clib_testing.example_command', 'Print an example message', command_aliases=('s4clib_testing.examplecommand',), command_arguments=(CommonConsoleCommandArgument('thing_to_print', 'Text or Num', 'If specified, this value will be printed to the console. Default is "24".'),)) - def _common_testing_do_example_command(output: Output, thing_to_print: str='24'): - output(f'Here is what to print: {thing_to_print}') - - :param mod_identity: The identity of the mod that owns this command. - :type mod_identity: CommonModIdentity - :param command_name: The name of the command. This name can be used to run this command in the console. - :type command_name: str - :param command_description: Text that describes the purpose of this command and what it does. - :type command_description: str - :param command_aliases: Alternative names for the command that can be used to run this command in the console. Default is no aliases. - :type command_aliases: Iterator[str], optional - :param command_arguments: Command arguments that are used to describe details about the arguments of the command. Default is no arguments described. - :type command_arguments: Iterator[CommonConsoleCommandArgument], optional - :param command_type: The type of command, most of the time you will want it to be CommandType.Live. Default is CommandType.Live. - :type command_type: CommandType, optional - :param command_restriction_flags: Flags that indicate restrictions of the command. Default is CommandRestrictionFlags.UNRESTRICTED. - :type command_restriction_flags: CommandRestrictionFlags, optional - :param required_pack_flags: Flags to indicate what Game Packs are required in order for this command to be available. If set to None, no Game Packs will be required to run this command. Default is None. - :type required_pack_flags: Pack, optional - :param console_type: The type of console the command may be run in. If set to None, the default console will be used. Default is None. - :type console_type: CommandType, optional - :param show_with_help_command: If True, this command will appear when a player does ".help". If False, it will not appear when a player does ".help" but will still appear when they do ".help ". Default is True. - :type show_with_help_command: bool, optional - """ - def __init__( - self, - mod_identity: CommonModIdentity, - command_name: str, - command_description: str, - command_aliases: Iterator[str] = (), - command_arguments: Iterator[CommonConsoleCommandArgument] = (), - command_type: CommandType = CommandType.Live, - command_restriction_flags: CommandRestrictionFlags = CommandRestrictionFlags.UNRESTRICTED, - required_pack_flags: Pack = None, - console_type: CommandType = None, - show_with_help_command: bool = True - ) -> None: - self.mod_identity = mod_identity - self.command_name = command_name - command_without_underscores = command_name.replace('_', '') - new_command_aliases = list(command_aliases) - if command_without_underscores != command_name and command_without_underscores not in command_aliases: - new_command_aliases.append(command_without_underscores) - for command_alias in command_aliases: - command_alias_without_underscores = command_alias.replace('_', '') - if command_alias_without_underscores != command_alias and command_alias_without_underscores not in command_aliases: - new_command_aliases.append(command_alias_without_underscores) - command_aliases = new_command_aliases - self.command_aliases = tuple(command_aliases) - self.command_description = command_description - self.command_type = command_type - self.command_restriction_flags = command_restriction_flags - self.required_pack_flags = required_pack_flags - self.console_type = console_type - self.show_with_help_command = show_with_help_command - self.command_arguments: Dict[str, CommonConsoleCommandArgument] = { - arg.arg_name: arg - for arg in command_arguments - if arg.arg_name is not None - } - - @property - def arguments(self) -> Tuple[CommonConsoleCommandArgument]: - """The arguments of the command.""" - return tuple(self.command_arguments.values()) - - def __call__(self, *args, **kwargs) -> Any: - # noinspection PyUnresolvedReferences - return super().__call__(self, *args, **kwargs) - - def __repr__(self) -> str: - arg_str = ' '.join([repr(command_argument) for command_argument in self.arguments]) - name = self.command_name - description = self.command_description - return f'{name} {arg_str} - {description}' - - def __str__(self) -> str: - arg_str = '\n '.join([str(command_argument) for command_argument in self.arguments]) - name = self.command_name - description = self.command_description - return f'{name} - {description}\n {arg_str}' - - -class CommonConsoleCommandService(CommonService, HasClassLog): - """A service for creating and managing console commands.""" - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - return ModInfo.get_identity() - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 'common_console_command_service' - - def __init__(self) -> None: - super().__init__() - self._commands_by_mod_name: Dict[str, Dict[str, CommonConsoleCommand]] = dict() - - def _add_command(self, command: CommonConsoleCommand) -> None: - """Add a command to the library of commands.""" - mod_identity = command.mod_identity - mod_name = CommonModIdentity._get_mod_name(mod_identity.name).lower() - if mod_name not in self._commands_by_mod_name: - self._commands_by_mod_name[mod_name] = dict() - self._commands_by_mod_name[mod_name][command.command_name] = command - - self._create_help_command(mod_identity) - - def _help_command_name(self, mod_identity: CommonModIdentity) -> str: - mod_name = CommonModIdentity._get_mod_name(mod_identity.name).lower() - return f'{mod_name}.help' - - def _create_help_command(self, mod_identity: CommonModIdentity) -> None: - from s4ap.sims4communitylib.utils.common_log_registry import CommonLogRegistry - help_log = CommonLogRegistry().register_log(mod_identity, f'{mod_identity.name}_help') - mod_name = CommonModIdentity._get_mod_name(mod_identity.name).lower() - if mod_name not in self._commands_by_mod_name: - self._commands_by_mod_name[mod_name] = dict() - - help_command_name = self._help_command_name(mod_identity) - if help_command_name not in self._commands_by_mod_name[mod_name]: - @CommonConsoleCommand( - mod_identity, - help_command_name, - f'Show commands for the {mod_identity.name} mod.', - command_arguments=( - CommonConsoleCommandOptionalArgument('command_name', 'Text', f'If set, "{help_command_name}" will print the details of the instead of all commands. Example: "{help_command_name} {help_command_name}"', default_value=None), - )) - def _common_help_command(output: CommonConsoleCommandOutput, command_name: str=None): - try: - help_log.enable() - output('--------------------') - help_log.debug('--------------------') - output(f'NOTE: The following details have also been logged to "The Sims 4/mod_logs/_Messages.txt", in case not all data is shown.') - if command_name: - _command = CommonConsoleCommandService().get_command_by_mod_and_name(mod_identity, command_name) - if _command is None: - output(f'No command found with name. {command_name}') - help_log.debug(f'No command found with name. {command_name}') - else: - command_str = str(_command) - output(command_str) - help_log.debug(command_str) - else: - output(f'{mod_identity.name} Commands:') - output('- Angle Brackets (<>) means the argument is Required and must be provided when running the command') - output('- Square Brackets ([]) means the argument is Optional and does not need to be provided when running the command.') - output('- The "=..." part of an argument indicates the default value of that argument IF NOT SPECIFIED when invoking the command.') - output(f'- For specific details about a command, run the command like so "{help_command_name} "') - output(' ') - help_log.debug(f'{mod_identity.name} Commands:') - help_log.debug('- Angle Brackets (<>) means the argument is Required and must be provided when running the command') - help_log.debug('- Square Brackets ([]) means the argument is Optional and does not need to be provided when running the command.') - help_log.debug('- The "=..." part of an argument indicates the default value of that argument IF NOT SPECIFIED when invoking the command.') - help_log.debug(f'- For specific details about a command, run the command like so "{help_command_name} "') - help_log.debug(' ') - for (_command_name, _command) in sorted(list(CommonConsoleCommandService().get_commands_by_mod(mod_identity).items()), key=lambda x: x[0]): - _command: CommonConsoleCommand = _command - if not _command.show_with_help_command: - continue - command_repr = repr(_command) - output(command_repr) - help_log.debug(command_repr) - output('--------------------') - help_log.debug('--------------------') - output(f'NOTE: The above details have also been logged to "The Sims 4/mod_logs/_Messages.txt", in case not all data is shown.') - finally: - help_log.disable() - - def get_commands_by_mod(self, mod_identity: CommonModIdentity) -> Dict[str, CommonConsoleCommand]: - """Retrieve the commands available for a mod.""" - mod_name = CommonModIdentity._get_mod_name(mod_identity.name).lower() - if mod_name not in self._commands_by_mod_name: - return dict() - return self._commands_by_mod_name[mod_name] - - def get_command_by_mod_and_name(self, mod_identity: CommonModIdentity, command_name: str) -> Union[CommonConsoleCommand, None]: - """Retrieve the commands available for a mod.""" - mod_name = CommonModIdentity._get_mod_name(mod_identity.name).lower() - if mod_name not in self._commands_by_mod_name or command_name not in self._commands_by_mod_name[mod_name]: - return None - return self._commands_by_mod_name[mod_name][command_name] - - @classmethod - def command(cls, mod_identity: CommonModIdentity, *command_aliases: str, command_type: CommandType=CommandType.Live, command_restriction_flags: CommandRestrictionFlags=CommandRestrictionFlags.UNRESTRICTED, required_pack_flags: Pack=None, console_type: CommandType=None) -> Any: - """Create a command.""" - from s4ap.sims4communitylib.utils.common_log_registry import CommonLogRegistry - log = CommonLogRegistry().register_log(mod_identity, f'{mod_identity.name}_command_log') - _command = cls._command(log, *command_aliases, command_type=command_type, command_restrictions=command_restriction_flags, pack=required_pack_flags, console_type=console_type) - - help_command_name = CommonConsoleCommandService()._help_command_name(mod_identity) - - def _wrapped_command(func) -> Any: - # command_name = command_aliases[0] - full_arg_spec = inspect.getfullargspec(func) - - @wraps(func) - def _wrapped_func(output: CommonConsoleCommandOutput, *_, _connection: int=None, _account: int=None, **__): - try: - if '_account' in full_arg_spec.args or '_account' in full_arg_spec.kwonlyargs: - __['_account'] = _account - if '_connection' in full_arg_spec.args or '_connection' in full_arg_spec.kwonlyargs: - __['_connection'] = _connection - # output(f'Running command "{command_name}"') - command_result = func(output, *_, **__) - # output(f'Command "{command_name}" finished running.') - return command_result - except Exception as ex: - log.error(f'An exception occurred while running command. {func.__name__}', exception=ex) - output(f'Error: "{ex}"') - - result = _command(_wrapped_func, func, help_command_name) - return result - - return _wrapped_command - - # noinspection PyMissingTypeHints - @classmethod - def _command(cls, log: 'CommonLog', *aliases: str, command_type: CommandType=CommandType.DebugOnly, command_restrictions: CommandRestrictionFlags=CommandRestrictionFlags.UNRESTRICTED, pack: Pack=None, console_type: CommandType=None): - # noinspection PyBroadException - try: - import sims4.common - import paths - import sims4.telemetry - except: - # noinspection PyUnusedLocal - def _named_command(wrapped_func, original_func, help_command_name) -> Any: - return - return _named_command - - from sims4.commands import CommandType, \ - is_command_available, cheats_writer, TELEMETRY_FIELD_NAME, TELEMETRY_FIELD_ARGS, TELEMETRY_HOOK_COMMAND, CustomParam, \ - prettify_usage, register - if console_type is not None and not paths.IS_DESKTOP: - relevant_type = console_type - else: - relevant_type = command_type - if console_type is not None: - most_limited_type = min(command_type, console_type) - else: - most_limited_type = command_type - - def _is_valid_command() -> bool: - if relevant_type == CommandType.DebugOnly: - return False - elif pack and not sims4.common.are_packs_available(pack): - return False - return True - - def _named_command(wrapped_func, original_func, help_command_name) -> Any: - if not _is_valid_command(): - return - name = aliases[0] - arguments = inspect.signature(original_func).parameters - num_of_arguments = len(arguments) - 1 - num_of_required_arguments = len([v for k, v in arguments.items() if v.default is inspect.Parameter.empty]) - 1 - full_arg_spec = inspect.getfullargspec(original_func) - spec_args = [_arg for _arg in full_arg_spec.args] - arg_names: Tuple[str, ...] = tuple([arg_name for (arg_name, (k, v)) in zip(spec_args, arguments.items()) if arg_name != 'output' and v.default is inspect.Parameter.empty]) - kwarg_parameters_by_name = {arg_name: v.default for (arg_name, (k, v)) in zip(spec_args, arguments.items()) if arg_name != 'output' and v.default is not inspect.Parameter.empty} - - def _invoke_command(*args: str, _session_id: int=0, **kwargs): - output = CommonConsoleCommandOutput(_session_id) - try: - if not is_command_available(relevant_type): - return False - args = cls._parse_arguments(full_arg_spec, tuple(args), arg_names, kwarg_parameters_by_name, kwargs, output) - if args is None: - output('No args specified.') - return False - if len(args) + len(kwargs) > num_of_arguments: - output('Too many arguments were passed in.') - output(f'Use the help command "{help_command_name} {name}" to see what arguments are needed!') - return False - if len(args) < num_of_required_arguments: - num_of_args = len(args) - output(f'Missing some arguments. Specified Args: {num_of_args}, Required Args: {num_of_required_arguments}') - output(f'Use the help command "{help_command_name} {name}" to see what arguments are required!') - return False - kwargs['_account'] = _session_id - kwargs['_connection'] = _session_id - if relevant_type == CommandType.Cheat: - with sims4.telemetry.begin_hook(cheats_writer, TELEMETRY_HOOK_COMMAND) as hook: - hook.write_string(TELEMETRY_FIELD_NAME, name) - hook.write_string(TELEMETRY_FIELD_ARGS, str(args)) - cls.get_log().format_with_message('Invoking the command now.', command_name=name, with_args=args, with_kwargs=kwargs) - return wrapped_func(output, *args, **kwargs) - except Exception as ex: - output(f'ERROR: {ex}') - if (full_arg_spec.varargs is None or full_arg_spec.varkw is None) and any(inspect.isclass(arg_type) and isinstance(arg_type, type) and issubclass(arg_type, CustomParam) for arg_type in full_arg_spec.annotations.values()): - log.format_error_with_message(f'Command "{name}" has CustomParams, consider adding *args and **kwargs to your command params', exception=ex) - else: - log.error(f'Error executing command {name}', exception=ex) - raise ex - - _invoke_command.__name__ = 'invoke_command ({})'.format(name) - # noinspection PyDeprecation - usage = prettify_usage(str.format(inspect.formatargspec(*full_arg_spec))) - description = '' - for alias in aliases: - register(alias, command_restrictions, _invoke_command, description, usage, most_limited_type) - return wrapped_func - - return _named_command - - @classmethod - def _clean_arguments(cls, args: Tuple[str]) -> Tuple[Tuple[str], Dict[str, str]]: - cleaned_args: List[str] = list() - cleaned_kwargs: Dict[str, Any] = dict() - - def _add_cleaned_arg_value(_cleaned_arg) -> None: - if '=' in _cleaned_arg: - split_val = _cleaned_arg.split('=') - cleaned_kwargs[split_val[0]] = split_val[1] - else: - cleaned_args.append(_cleaned_arg) - - cls.get_log().format_with_message('Cleaning args.', args=args) - - waiting_for_match_arg: Union[str, None] = None - for arg_val in args: - if waiting_for_match_arg is not None: - if '=' in arg_val: - # The start of a new argument, thus ending the previous one. - _add_cleaned_arg_value(waiting_for_match_arg) - waiting_for_match_arg = arg_val - elif '"' in arg_val: - # The end value that results in the complete argument. - waiting_for_match_arg += arg_val.replace('"', '') - _add_cleaned_arg_value(waiting_for_match_arg) - waiting_for_match_arg = None - continue - else: - # A continuation of the argument we are waiting for. - waiting_for_match_arg += arg_val - continue - - if '"' in arg_val: - # The start of an argument that has multiple values. - waiting_for_match_arg = arg_val.replace('"', '') - continue - - _add_cleaned_arg_value(arg_val) - - if waiting_for_match_arg is not None: - # If we are still waiting for an argument, we'll just put it at the end. - _add_cleaned_arg_value(waiting_for_match_arg) - cls.get_log().format_with_message('Cleaned up args.', args=args, cleaned_args=cleaned_args, cleaned_kwargs=cleaned_kwargs) - return tuple(cleaned_args), cleaned_kwargs - - @classmethod - def _parse_arguments(cls, full_arg_spec: inspect.FullArgSpec, args: Tuple[str], arg_names: Tuple[str], kwargs_by_name, kwargs: Dict[str, Any], output: Union[CommonConsoleCommandOutput, Output]): - (cleaned_args, cleaned_kwargs) = cls._clean_arguments(args) - - from s4ap.sims4communitylib.services.commands.common_console_command_parameters import CommonConsoleCommandParameter,\ - CommonOptionalSimInfoConsoleCommandParameter, CommonRequiredGameObjectConsoleCommandParameter, \ - CommonRequiredSimInfoConsoleCommandParameter - arg_length = len(cleaned_args) - new_args = list() - unassigned_cleaned_args = list(cleaned_args) - if len(cleaned_args) > len(arg_names): - # If there are more specified arguments than there are actual arguments, we chop off the extra specified arguments to be used as kwargs instead. - unassigned_cleaned_args = list(cleaned_args[len(arg_names):]) - cleaned_args = list(cleaned_args[:len(arg_names)]) - elif len(cleaned_args) <= len(arg_names): - arg_names = arg_names[:len(cleaned_args)] - unassigned_cleaned_args = list() - for (name, cleaned_arg_value, index) in zip(arg_names, cleaned_args, range(len(arg_names))): - if index >= arg_length: - continue - arg_type = full_arg_spec.annotations.get(name) - arg_values = cleaned_arg_value.split(' ') - if inspect.isclass(arg_type) and ((isinstance(arg_type, type) and issubclass(arg_type, CustomParam)) or arg_type is SimInfo or issubclass(arg_type, SimInfo) or arg_type is GameObject or issubclass(arg_type, GameObject)): - if arg_type is SimInfo or issubclass(arg_type, SimInfo): - arg_value = CommonRequiredSimInfoConsoleCommandParameter.get_value(output, *arg_values) - elif arg_type is GameObject or issubclass(arg_type, GameObject): - arg_value = CommonRequiredGameObjectConsoleCommandParameter.get_value(output, *arg_values) - elif arg_type is CommonConsoleCommandParameter or issubclass(arg_type, CommonConsoleCommandParameter): - arg_value = arg_type.get_value(output, *arg_values) - else: - arg_value = arg_type.get_arg_count_and_value(*arg_values)[1] - - if arg_value is UNSET: - new_args.append(arg_type(*arg_values)) - else: - new_args.append(arg_value) - - elif arg_type is not None: - new_args.append(cls._parse_arg(arg_type, cleaned_arg_value, name, None, output)) - - if full_arg_spec.varargs is not None: - arg_type = full_arg_spec.annotations.get(full_arg_spec.varargs) - if arg_type is not None: - name = full_arg_spec.varargs - for arg_value in unassigned_cleaned_args: - new_args.append(cls._parse_arg(arg_type, arg_value, name, None, output)) - - cls.get_log().format_with_message('Finished parsing arg values', unassigned_cleaned_args=unassigned_cleaned_args, kwargs_by_name=kwargs_by_name) - - for (kwarg_name, kwarg_default_val) in kwargs_by_name.items(): - if kwarg_name not in cleaned_kwargs or cleaned_kwargs[kwarg_name] is None: - if not unassigned_cleaned_args: - if kwarg_default_val is not None: - kwargs[kwarg_name] = kwarg_default_val - continue - kwarg_values = () - else: - kwarg_values = unassigned_cleaned_args.pop(0).split(' ') - else: - kwarg_values = cleaned_kwargs[kwarg_name].split(' ') - - kwarg_type = full_arg_spec.annotations.get(kwarg_name) - if inspect.isclass(kwarg_type) and ((isinstance(kwarg_type, type) and issubclass(kwarg_type, CustomParam)) or kwarg_type is SimInfo or issubclass(kwarg_type, SimInfo) or kwarg_type is GameObject or issubclass(kwarg_type, GameObject)): - if kwarg_type is SimInfo or issubclass(kwarg_type, SimInfo): - kwarg_value = CommonOptionalSimInfoConsoleCommandParameter.get_value(output, *kwarg_values) - elif kwarg_type is GameObject or issubclass(kwarg_type, GameObject): - kwarg_value = CommonRequiredGameObjectConsoleCommandParameter.get_value(output, *kwarg_values) - elif kwarg_type is CommonConsoleCommandParameter or issubclass(kwarg_type, CommonConsoleCommandParameter): - kwarg_value = kwarg_type.get_value(output, *kwarg_values) - else: - (_, kwarg_value) = kwarg_type.get_arg_count_and_value(*kwarg_values) - - if kwarg_value is UNSET: - kwargs[kwarg_name] = kwarg_type(*kwarg_values) - else: - kwargs[kwarg_name] = kwarg_value - - elif kwarg_type is not None: - kwargs[kwarg_name] = cls._parse_arg(kwarg_type, ' '.join(kwarg_values), kwarg_name, kwarg_default_val, output) - cls.get_log().format_with_message('Finished parsing arguments.', args=new_args, kwargs=kwargs) - return new_args - - @classmethod - def _parse_arg(cls, arg_type: Type, arg_value: Any, name: str, default_value: Any, output: Output) -> Any: - from sims4.commands import CustomParam, BOOL_TRUE, BOOL_FALSE - arg_type_name = arg_type.__name__ if hasattr(arg_type, '__name__') else name - if isinstance(arg_value, str): - if arg_type is bool: - lower_arg_value = arg_value.lower() - if lower_arg_value in BOOL_TRUE: - return True - elif lower_arg_value in BOOL_FALSE: - return False - else: - output(f'ERROR: Invalid entry specified for bool {name}: {arg_value} (Expected one of {BOOL_TRUE} for True, or one of {BOOL_FALSE} for False.)') - raise ValueError('invalid literal for boolean parameter') - else: - from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - from s4ap.sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags - if inspect.isclass(arg_type) and (arg_type is CommonInt or arg_type is CommonIntFlags or issubclass(arg_type, CommonInt) or issubclass(arg_type, CommonIntFlags)): - if arg_value is not None: - from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils - result = CommonResourceUtils.get_enum_by_name(arg_value.upper(), arg_type, default_value=default_value) - if result is None: - # noinspection PyUnresolvedReferences,PyTypeChecker - valid_values = ', '.join([val.name for val in arg_type.values]) - output(f'ERROR: {arg_value} is not a valid {arg_type_name}. Valid {arg_type_name}: {valid_values}') - return None - return result - elif arg_type is float: - # noinspection PyBroadException - try: - return float(arg_value) - except: - output(f'ERROR: Failed to parse float value {arg_value} as {arg_type_name}. Value is not a {arg_type_name}.') - return default_value - elif arg_type is int or arg_value.isnumeric(): - # noinspection PyBroadException - try: - return int(arg_value, base=0) - except: - output(f'ERROR: Failed to parse int value {arg_value} as {arg_type_name}. Value is not an {arg_type_name}.') - return default_value - elif arg_type is str and not arg_value: - return default_value - elif inspect.isclass(arg_type) and ((isinstance(arg_type, type) and issubclass(arg_type, CustomParam)) or arg_type is SimInfo or issubclass(arg_type, SimInfo) or arg_type is GameObject or issubclass(arg_type, GameObject)): - pass - else: - try: - return arg_type(arg_value) - except ValueError as ex: - output(f'ERROR: Failed to parse value {arg_value} as {arg_type_name}: {ex}') - return default_value - except Exception as ex: - output(f'ERROR: Failed to parse custom value {arg_value} as {arg_type_name}: {ex}') - raise ex - return arg_value - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_testing.example_command', - 'Print an example message', - command_aliases=('s4clib_testing.alternativeexamplecommand',), - command_arguments=( - CommonConsoleCommandArgument('thing_to_print', 'Text or Num', 'If specified, this value will be printed to the console.', is_optional=True, default_value='example message'), - ) -) -def _common_testing_do_example_command(output: CommonConsoleCommandOutput, thing_to_print: str = 'example message'): - output(f'Here is what to print: {thing_to_print}') diff --git a/Scripts/s4ap/sims4communitylib/services/commands/common_console_command_output.py b/Scripts/s4ap/sims4communitylib/services/commands/common_console_command_output.py deleted file mode 100644 index 7f61bfc..0000000 --- a/Scripts/s4ap/sims4communitylib/services/commands/common_console_command_output.py +++ /dev/null @@ -1,60 +0,0 @@ -""" -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 -""" -from typing import Union - -from objects.game_object import GameObject -from server_commands.argument_helpers import OptionalTargetParam, RequiredTargetParam -from sims.sim_info import SimInfo -from sims4.commands import CheatOutput - - -class CommonConsoleCommandOutput(CheatOutput): - """An output object used when writing text to the console.""" - @property - def connection(self) -> int: - """The connection id to the console.""" - return self._context - - def get_sim(self, target: Union[OptionalTargetParam, RequiredTargetParam]) -> Union[SimInfo, None]: - """get_sim(target) - - Retrieve an instance of a Sim referenced by an OptionalTargetParam or RequiredTargetParam. - - :param target: A target param. - :type target: Union[OptionalTargetParam, RequiredTargetParam] - :return: An instance of the Sim that matches the target or None if not found. - :rtype: Union[Sim, None] - """ - from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - from server_commands.argument_helpers import get_optional_target - sim = get_optional_target(target, self.connection) - sim_info = CommonSimUtils.get_sim_info(sim) - if sim_info is None: - self(f'Failed, Sim {target} did not exist.') - return - return sim_info - - def get_object(self, target: Union[OptionalTargetParam, RequiredTargetParam]) -> Union[GameObject, None]: - """get_object(target) - - Retrieve an instance of a Game Object referenced by an OptionalTargetParam or RequiredTargetParam. - - :param target: A target param. - :type target: Union[OptionalTargetParam, RequiredTargetParam] - :return: An instance of the Sim that matches the target or None if not found. - :rtype: Union[Sim, None] - """ - if isinstance(target, OptionalTargetParam): - from server_commands.argument_helpers import get_optional_target - game_object = get_optional_target(target, self.connection) - else: - game_object: GameObject = target - if game_object is None: - self(f'Failed, Game Object {target} did not exist.') - return - return game_object diff --git a/Scripts/s4ap/sims4communitylib/services/commands/common_console_command_parameters.py b/Scripts/s4ap/sims4communitylib/services/commands/common_console_command_parameters.py deleted file mode 100644 index 3fb7e88..0000000 --- a/Scripts/s4ap/sims4communitylib/services/commands/common_console_command_parameters.py +++ /dev/null @@ -1,151 +0,0 @@ -""" -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 -""" -from typing import Union, Tuple, Any - -from objects.game_object import GameObject -from sims.sim_info import SimInfo -from sims4.commands import CustomParam -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput - - -class CommonConsoleCommandParameter(CustomParam): - """A custom console command parameter.""" - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_value(cls, output: CommonConsoleCommandOutput, *args: str) -> Any: - return cls.get_arg_count_and_value(output, *args)[1] - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_arg_count_and_value(cls, output: CommonConsoleCommandOutput, *args: str) -> Tuple[int, Any]: - return super().get_arg_count_and_value(*args) - - -class CommonRequiredSimInfoConsoleCommandParameter(CommonConsoleCommandParameter): - """A param that requires a Sim ID, a Sims First Name, or a Sims First and Last Name of a Sim to be specified.""" - - @classmethod - def _get_target_id(cls, arg) -> Union[int, None]: - try: - int_val = int(arg, 0) - except ValueError: - int_val = None - return int_val - - @classmethod - def get_value(cls, output: CommonConsoleCommandOutput, *args: str) -> SimInfo: - """Retrieve the number of arguments taken and the value returned.""" - from singletons import UNSET - from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils - if len(args) == 0: - return UNSET - sim_id = cls._get_target_id(args[0]) - if sim_id: - sim_info_from_id = CommonSimUtils.get_sim_info(sim_id) - if sim_info_from_id is not None: - return sim_info_from_id - else: - output(f'ERROR: Failed to locate Sim with id {args[0]}') - - if len(args) >= 2 and isinstance(args[1], str): - first_name = args[0].lower() - last_name = args[1].lower() - for _sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): - if CommonSimNameUtils.get_first_name(_sim_info).lower() != first_name: - continue - lower_last_name = CommonSimNameUtils.get_last_name(_sim_info).lower() - if lower_last_name == last_name: - return _sim_info - if lower_last_name == '': - return _sim_info - - if len(args) >= 1 and isinstance(args[0], str): - first_name = args[0].lower() - for _sim_info in CommonSimUtils.get_sim_info_for_all_sims_with_first_name_generator(first_name): - return _sim_info - output(f'ERROR: Failed to locate Sim with first name {args[0]}') - return super().get_value(output, *args) - - def __new__(cls, output: CommonConsoleCommandOutput, *args: str) -> Union[SimInfo, None]: - from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils - if len(args) == 0: - return None - int_val = cls._get_target_id(args[0]) - if int_val is not None: - sim_info = CommonSimUtils.get_sim_info(int_val) - if sim_info is not None: - return sim_info - - first_name = args[0] - last_name = '' if len(args) == 1 else args[1] - for sim_info in CommonSimUtils.get_sim_info_for_all_sims_with_first_name_generator(first_name): - if last_name == '': - return sim_info - lower_last_name = CommonSimNameUtils.get_last_name(sim_info).lower() - if lower_last_name == last_name: - return sim_info - return None - - -class CommonOptionalSimInfoConsoleCommandParameter(CommonRequiredSimInfoConsoleCommandParameter): - """A param that optionally requires a Sim ID, a Sims First Name, or a Sims First and Last Name of a Sim to be specified. If not provided, the active SimInfo will be supplied instead.""" - - @classmethod - def get_value(cls, output: CommonConsoleCommandOutput, *args: str) -> SimInfo: - """Retrieve the number of arguments taken and the value returned.""" - from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - sim_info = super().get_value(output, *args) - from singletons import UNSET - if sim_info is UNSET: - return CommonSimUtils.get_active_sim_info() - return sim_info - - def __new__(cls, output: CommonConsoleCommandOutput, *args: str) -> Union[SimInfo, None]: - from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - return super().__new__(cls, output, *args) or CommonSimUtils.get_active_sim_info() - - -class CommonRequiredGameObjectConsoleCommandParameter(CommonConsoleCommandParameter): - """A param that requires the ID of a Game Object to specified.""" - - @classmethod - def _get_target_id(cls, arg: str) -> Union[int, None]: - try: - int_val = int(arg, 0) - except ValueError: - int_val = None - return int_val - - @classmethod - def get_value(cls, output: CommonConsoleCommandOutput, *args: str) -> GameObject: - """Retrieve the number of arguments taken and the value returned.""" - from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils - from singletons import UNSET - if len(args) == 0: - return UNSET - obj_id = cls._get_target_id(args[0]) - if obj_id: - game_object = CommonObjectUtils.get_game_object(obj_id) - if game_object is not None: - return game_object - output(f'Failed to locate Object with id {args[0]}') - return super().get_value(output, *args) - - def __new__(cls, output: CommonConsoleCommandOutput, *args: str) -> Union[GameObject, None]: - from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils - from singletons import UNSET - if len(args) == 0: - return UNSET - int_val = cls._get_target_id(args[0]) - if int_val is not None: - game_object = CommonObjectUtils.get_game_object(int_val) - if game_object is not None: - return game_object - return None diff --git a/Scripts/s4ap/sims4communitylib/services/common_service.py b/Scripts/s4ap/sims4communitylib/services/common_service.py deleted file mode 100644 index 410cd63..0000000 --- a/Scripts/s4ap/sims4communitylib/services/common_service.py +++ /dev/null @@ -1,52 +0,0 @@ -""" -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 -""" -from typing import TypeVar, Any - -ServiceType = TypeVar('ServiceType', bound=object) - - -class _Singleton(type): - def __init__(cls, *args, **kwargs) -> None: - super(_Singleton, cls).__init__(*args, **kwargs) - cls._instances = {} - - def __call__(cls, *args, **kwargs) -> 'CommonService': - if cls not in cls._instances: - cls._instances[cls] = super(_Singleton, cls).__call__(*args, **kwargs) - return cls._instances[cls] - - -class CommonService(metaclass=_Singleton): - """An inheritable class that turns a class into a singleton, create an instance by invoking :func:`~get`. - - - :Example usage: - - .. highlight:: python - .. code-block:: python - - class ExampleService(CommonService): - @property - def first_value(self) -> str: - return 'yes' - - # ExampleService.get() returns an instance of ExampleService. - # Calling ExampleService.get() again, will return the same instance. - ExampleService.get().first_value - - """ - @classmethod - def get(cls: Any, *_, **__) -> 'CommonService': - """get() - - Retrieve an instance of the service - - :return: An instance of the service - :rtype: The type of the inheriting class - """ - return cls(*_, **__) diff --git a/Scripts/s4ap/sims4communitylib/services/interactions/__init__.py b/Scripts/s4ap/sims4communitylib/services/interactions/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/services/interactions/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/services/interactions/interaction_registration_service.py b/Scripts/s4ap/sims4communitylib/services/interactions/interaction_registration_service.py deleted file mode 100644 index f84c12d..0000000 --- a/Scripts/s4ap/sims4communitylib/services/interactions/interaction_registration_service.py +++ /dev/null @@ -1,337 +0,0 @@ -""" -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 -""" -from typing import Tuple, Iterator, Callable, Any -from interactions.base.interaction import Interaction -from objects.script_object import ScriptObject -from services.terrain_service import TerrainService -from sims.sim import Sim -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt -from s4ap.sims4communitylib.logging._has_s4cl_log import _HasS4CLLog -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.common_service import CommonService -from s4ap.sims4communitylib.utils.common_injection_utils import CommonInjectionUtils -from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils - - -class CommonInteractionType(CommonInt): - """The type of object/area to add interactions to. - - """ - ON_TERRAIN_LOAD: 'CommonInteractionType' = ... - ON_OCEAN_LOAD: 'CommonInteractionType' = ... - ON_SCRIPT_OBJECT_LOAD: 'CommonInteractionType' = ... - ADD_PRE_ROLL_SUPER_INTERACTION_ON_SCRIPT_OBJECT_LOAD: 'CommonInteractionType' = ... - ADD_TO_SIM_RELATIONSHIP_PANEL_INTERACTIONS: 'CommonInteractionType' = ... - ADD_TO_SIM_PHONE_INTERACTIONS: 'CommonInteractionType' = ... - - -class CommonInteractionHandler: - """An interaction handler that adds interactions to script objects, the terrain, or the ocean. - - """ - def __init__(self) -> None: - self._cached_interactions_to_add = None - - @property - def interactions_to_add(self) -> Tuple[int]: - """A collection of interaction identifiers being added by the interaction handler. - - :return: A collection of interaction identifiers. - :rtype: Tuple[int] - """ - raise NotImplementedError() - - def _interactions_to_add_gen(self) -> Iterator[Interaction]: - if self._cached_interactions_to_add is not None: - yield from self._cached_interactions_to_add - else: - cached_interactions = list() - from s4ap.sims4communitylib.utils.resources.common_interaction_utils import CommonInteractionUtils - affordance_manager = CommonInteractionUtils.get_instance_manager() - for affordance_id in self.interactions_to_add: - affordance_instance = affordance_manager.get(affordance_id) - if affordance_instance is None: - continue - yield affordance_instance - cached_interactions.append(affordance_instance) - self._cached_interactions_to_add = cached_interactions - - -class CommonScriptObjectInteractionHandler(CommonInteractionHandler): - """An inheritable class that enables registration of interactions to script objects. - - .. note:: Script Objects can be both Sims and Furniture. - - :Example usage: - - .. highlight:: python - .. code-block:: python - - # In this example, the interaction `sim-chat` will be added to any script object that is a `Sim`. - @CommonInteractionRegistry.register_interaction_handler(CommonInteractionType.ON_SCRIPT_OBJECT_LOAD) - class ExampleInteractionHandler(CommonScriptObjectInteractionHandler): - @property - def interactions_to_add(self) -> Tuple[int]: - # Interaction Ids - # These are the decimal identifiers of the interactions from a package file. - from s4ap.sims4communitylib.enums.interactions_enum import CommonInteractionId - return tuple([int(CommonInteractionId.SIM_CHAT), 2]) - - def should_add(self, script_object: ScriptObject, *args, **kwargs) -> bool: - # Verify it is the object your are expecting. Return True, if it is. - # In this case we are adding these interactions to Sims. - from sims.sim import Sim - return isinstance(script_object, Sim) - - """ - @property - def interactions_to_add(self) -> Tuple[int]: - """A collection of interactions that will be added to the script objects that pass the :func:`~should_add` check. - - :return: A collection of interaction decimal identifiers. - :rtype: Tuple[int] - """ - raise NotImplementedError() - - def should_add(self, script_object: ScriptObject, *args, **kwargs) -> bool: - """should_add(script_object, args, kwargs) - - Determine whether to add the interactions of this handler to the script object. - - :param script_object: An object of type ScriptObject - :param script_object: ScriptObject - :return: True if the interactions specified by `interactions_to_add` should be added to the `script_object`. False if not. - :rtype: bool - """ - raise NotImplementedError() - - -class CommonInteractionRegistry(CommonService, _HasS4CLLog): - """Manage the registration of interactions to script objects, terrain, sims, etc. - - .. note:: Take a look at :class:`.CommonScriptObjectInteractionHandler` for more info and an example of usage. - - """ - - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - return 'common_interaction_registry' - - def __init__(self) -> None: - super().__init__() - self._interaction_handlers = { - CommonInteractionType.ON_TERRAIN_LOAD: list(), - CommonInteractionType.ON_OCEAN_LOAD: list(), - CommonInteractionType.ON_SCRIPT_OBJECT_LOAD: list(), - CommonInteractionType.ADD_PRE_ROLL_SUPER_INTERACTION_ON_SCRIPT_OBJECT_LOAD: list(), - CommonInteractionType.ADD_TO_SIM_RELATIONSHIP_PANEL_INTERACTIONS: list(), - CommonInteractionType.ADD_TO_SIM_PHONE_INTERACTIONS: list() - } - - def on_script_object_add(self, script_object: ScriptObject, *args, **kwargs): - """on_script_object_add(script_object, *args, **kwargs) - - A hook that occurs upon a Script Object being added. - - :param script_object: The script object being added. - :type script_object: ScriptObject - """ - script_object_type = type(script_object) - self.log.format_with_message('Adding interactions for type', script_object_type=script_object_type) - if not hasattr(script_object_type, '_super_affordances'): - self.verbose_log.format_with_message('Object did not have super affordances.', script_object=script_object_type) - return - new_super_affordances = list() - for interaction_handler in self._interaction_handlers[CommonInteractionType.ON_SCRIPT_OBJECT_LOAD]: - if hasattr(interaction_handler, 'should_add') and not interaction_handler.should_add(script_object, *args, **kwargs): - continue - for interaction_instance in interaction_handler._interactions_to_add_gen(): - if interaction_instance in new_super_affordances or interaction_instance in script_object_type._super_affordances: - self.verbose_log.format_with_message('Interaction was already found in the interactions list.', script_object_type=script_object_type, interaction_instance=interaction_instance) - continue - new_super_affordances.append(interaction_instance) - self.log.format_with_message('Adding super affordances to object.', script_object=script_object, script_object_type=script_object_type, new_super_affordances=new_super_affordances) - script_object_type._super_affordances += tuple(new_super_affordances) - new_script_object_super_affordances = list() - for new_super_affordance in new_super_affordances: - if new_super_affordance in script_object._super_affordances: - continue - new_script_object_super_affordances.append(new_super_affordance) - script_object._super_affordances += tuple(new_script_object_super_affordances) - - def register_pre_roll_super_interactions_on_script_object_add(self, script_object: ScriptObject, *args, **kwargs): - """register_pre_roll_super_interactions_on_script_object_add(script_object, *args, **kwargs) - - A hook that occurs upon a Script Object being added. - - :param script_object: The script object being added. - :type script_object: ScriptObject - """ - script_object_type = type(script_object) - self.log.format_with_message('Adding pre roll super interactions for type', script_object_type=script_object_type) - if not hasattr(script_object_type, '_preroll_super_affordances'): - self.verbose_log.format_with_message('Object did not have super affordances.', script_object=script_object_type) - return - new_preroll_super_affordances = list() - for interaction_handler in self._interaction_handlers[CommonInteractionType.ADD_PRE_ROLL_SUPER_INTERACTION_ON_SCRIPT_OBJECT_LOAD]: - if hasattr(interaction_handler, 'should_add') and not interaction_handler.should_add(script_object, *args, **kwargs): - continue - for interaction_instance in interaction_handler._interactions_to_add_gen(): - if interaction_instance in new_preroll_super_affordances or interaction_instance in script_object_type._preroll_super_affordances: - self.verbose_log.format_with_message('Interaction was already found in the interactions list.', script_object_type=script_object_type, interaction_instance=interaction_instance) - continue - new_preroll_super_affordances.append(interaction_instance) - self.log.format_with_message('Adding super affordances to object.', script_object=script_object, script_object_type=script_object_type, new_preroll_super_affordances=new_preroll_super_affordances) - script_object_type._preroll_super_affordances += tuple(new_preroll_super_affordances) - new_script_object_preroll_super_affordances = list() - for new_super_affordance in new_preroll_super_affordances: - if new_super_affordance in script_object._preroll_super_affordances: - continue - new_script_object_preroll_super_affordances.append(new_super_affordance) - script_object._preroll_super_affordances += tuple(new_script_object_preroll_super_affordances) - - def _on_sim_relationship_panel_load(self, sim: Sim, *args, **kwargs): - sim_class = type(sim) - if not hasattr(sim_class, '_relation_panel_affordances'): - return - new_relationship_panel_affordances = list() - for interaction_handler in self._interaction_handlers[CommonInteractionType.ADD_TO_SIM_RELATIONSHIP_PANEL_INTERACTIONS]: - if hasattr(interaction_handler, 'should_add') and not interaction_handler.should_add(sim, *args, **kwargs): - continue - for interaction_instance in interaction_handler._interactions_to_add_gen(): - if interaction_instance in new_relationship_panel_affordances or interaction_instance in sim_class._relation_panel_affordances: - continue - new_relationship_panel_affordances.append(interaction_instance) - sim_class._relation_panel_affordances += tuple(new_relationship_panel_affordances) - - def _on_sim_phone_load(self, sim: Sim, *args, **kwargs): - sim_class = type(sim) - if not hasattr(sim_class, '_phone_affordances'): - return - new_phone_affordances_affordances = list() - for interaction_handler in self._interaction_handlers[CommonInteractionType.ADD_TO_SIM_PHONE_INTERACTIONS]: - if hasattr(interaction_handler, 'should_add') and not interaction_handler.should_add(sim, *args, **kwargs): - continue - for interaction_instance in interaction_handler._interactions_to_add_gen(): - if interaction_instance in new_phone_affordances_affordances or interaction_instance in sim_class._phone_affordances: - continue - new_phone_affordances_affordances.append(interaction_instance) - sim_class._phone_affordances += tuple(new_phone_affordances_affordances) - - def on_terrain_load(self, terrain_service: TerrainService, *_, **__): - """on_terrain_load(terrain_service, *_, **__) - - A hook that occurs upon the Terrain loading - - :param terrain_service: The terrain service - :type terrain_service: TerrainService - """ - new_super_affordances = list() - for interaction_handler in self._interaction_handlers[CommonInteractionType.ON_TERRAIN_LOAD]: - for interaction_instance in interaction_handler._interactions_to_add_gen(): - if interaction_instance in new_super_affordances or interaction_instance in terrain_service.TERRAIN_DEFINITION.cls._super_affordances: - continue - new_super_affordances.append(interaction_instance) - new_terrain_definition_class = terrain_service.TERRAIN_DEFINITION.cls - new_terrain_definition_class._super_affordances += tuple(new_super_affordances) - terrain_service.TERRAIN_DEFINITION.set_class(new_terrain_definition_class) - - def on_ocean_load(self, terrain_service: TerrainService, *_, **__): - """on_ocean_load(terrain_service, *_, **__) - - A hook that occurs upon the Ocean loading - - :param terrain_service: The terrain service - :type terrain_service: TerrainService - """ - new_super_affordances = list() - for interaction_handler in self._interaction_handlers[CommonInteractionType.ON_OCEAN_LOAD]: - for interaction_instance in interaction_handler._interactions_to_add_gen(): - if interaction_instance in new_super_affordances or interaction_instance in terrain_service.OCEAN_DEFINITION.cls._super_affordances: - continue - new_super_affordances.append(interaction_instance) - new_ocean_definition_class = terrain_service.OCEAN_DEFINITION.cls - new_ocean_definition_class._super_affordances += tuple(new_super_affordances) - terrain_service.OCEAN_DEFINITION.set_class(new_ocean_definition_class) - - def register_handler(self, handler: CommonInteractionHandler, interaction_type: CommonInteractionType): - """register_handler(handler, interaction_type) - - Manually register an interaction handler. - - .. note:: It is recommended to decorate classes with :func:`~register_interaction_handler`\ - instead of manually registering interaction handlers. - - :param handler: The interaction handler being registered. - :type handler: CommonInteractionHandler - :param interaction_type: The type of place the interactions will show up. - :type interaction_type: CommonInteractionType - """ - self._interaction_handlers[interaction_type].append(handler) - - @staticmethod - def register_interaction_handler(interaction_type: CommonInteractionType) -> Callable[..., Any]: - """register_interaction_handler(interaction_type) - - Decorate a class to register that class as an interaction handler. - - .. note:: Take a look at :class:`.CommonScriptObjectInteractionHandler` for more info and example usage. - - :param interaction_type: The type of place the interactions will show up. - :type interaction_type: CommonInteractionType - :return: A wrapped function. - :rtype: Callable[..., Any] - """ - def _wrapper(interaction_handler) -> CommonInteractionHandler: - CommonInteractionRegistry().register_handler(interaction_handler(), interaction_type) - return interaction_handler - return _wrapper - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), ScriptObject, ScriptObject.on_add.__name__, handle_exceptions=False) -def _common_script_object_on_add(original, self, *args, **kwargs) -> Any: - result = original(self, *args, **kwargs) - CommonInteractionRegistry().on_script_object_add(self, *args, **kwargs) - CommonInteractionRegistry().register_pre_roll_super_interactions_on_script_object_add(self, *args, **kwargs) - if CommonTypeUtils.is_sim_instance(self): - CommonInteractionRegistry()._on_sim_relationship_panel_load(self, *args, **kwargs) - CommonInteractionRegistry()._on_sim_phone_load(self, *args, **kwargs) - return result - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), TerrainService, TerrainService.start.__name__, handle_exceptions=False) -def _common_terrain_service_start(original, self, *args, **kwargs) -> Any: - result = original(self, *args, **kwargs) - CommonInteractionRegistry().on_terrain_load(self, *args, **kwargs) - return result - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), TerrainService, TerrainService.on_zone_load.__name__, handle_exceptions=False) -def _common_terrain_service_on_zone_load(original, self, *args, **kwargs) -> Any: - result = original(self, *args, **kwargs) - CommonInteractionRegistry().on_ocean_load(self, *args, **kwargs) - return result - - -# noinspection PyMissingOrEmptyDocstring -# @CommonInteractionRegistry.register_interaction_handler(CommonInteractionType.ON_SCRIPT_OBJECT_LOAD) -class ExampleInteractionHandler(CommonScriptObjectInteractionHandler): - @property - def interactions_to_add(self) -> Tuple[int]: - # Interaction Ids - # These are the decimal identifiers of the interactions from a package file. - from s4ap.sims4communitylib.enums.interactions_enum import CommonInteractionId - # noinspection PyTypeChecker - return tuple([int(CommonInteractionId.SIM_CHAT), 2]) - - def should_add(self, script_object: ScriptObject, *args, **kwargs) -> bool: - # Verify it is the object your are expecting. Return True, if it is. - # In this case we are adding these interactions to Sims. - from sims.sim import Sim - return isinstance(script_object, Sim) diff --git a/Scripts/s4ap/sims4communitylib/services/resources/__init__.py b/Scripts/s4ap/sims4communitylib/services/resources/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/services/resources/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/services/resources/common_instance_manager_modification_registry.py b/Scripts/s4ap/sims4communitylib/services/resources/common_instance_manager_modification_registry.py deleted file mode 100644 index b0b46fb..0000000 --- a/Scripts/s4ap/sims4communitylib/services/resources/common_instance_manager_modification_registry.py +++ /dev/null @@ -1,75 +0,0 @@ -""" -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 -""" -from typing import Callable, Any, Type, List - -from sims4.tuning.instance_manager import InstanceManager -from s4ap.sims4communitylib.logging._has_s4cl_log import _HasS4CLLog -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.common_service import CommonService -from s4ap.sims4communitylib.services.resources.modification_handlers.common_instance_manager_modification_handler import \ - CommonInstanceManagerModificationHandler -from s4ap.sims4communitylib.utils.common_injection_utils import CommonInjectionUtils - - -class CommonInstanceManagerModificationRegistry(CommonService, _HasS4CLLog): - """A registry containing handlers that manipulate and modify instance managers. - - """ - - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - return 'common_instance_manager_modification_registry' - - def __init__(self) -> None: - super().__init__() - self._handlers: List[CommonInstanceManagerModificationHandler] = list() - - def _try_modify(self, instance_manager: InstanceManager): - for handler in self._handlers: - try: - if handler.should_apply_modifications(instance_manager): - handler.apply_modifications(instance_manager) - except Exception as ex: - self.log.format_error_with_message('An error occurred while applying modification.', handler=handler, exception=ex) - - def register_handler(self, handler: CommonInstanceManagerModificationHandler): - """register_handler(handler) - - Manually register a handler. - - .. note:: It is recommended to decorate classes with :func:`~register_modification_handler`\ - instead of manually registering handlers. - - :param handler: The handler being registered. - :type handler: CommonInstanceManagerModificationHandler - """ - if handler in self._handlers: - return - self._handlers.append(handler) - - @staticmethod - def register_modification_handler() -> Callable[..., Any]: - """register_modification_handler() - - Decorate a class with this to register that class as a modification handler. - """ - def _wrapper(_handler: Type[CommonInstanceManagerModificationHandler]) -> Type[CommonInstanceManagerModificationHandler]: - if not issubclass(_handler, CommonInstanceManagerModificationHandler): - raise AssertionError( - f'{_handler} is not an instance of {CommonInstanceManagerModificationHandler.__name__}') - CommonInstanceManagerModificationRegistry().register_handler(_handler()) - return _handler - return _wrapper - - -@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), InstanceManager, InstanceManager.load_data_into_class_instances.__name__, handle_exceptions=False) -def _common_modify_instance_manager_on_load_data(original, self: InstanceManager, *_, **__) -> Any: - result = original(self, *_, **__) - CommonInstanceManagerModificationRegistry()._try_modify(self) - return result diff --git a/Scripts/s4ap/sims4communitylib/services/resources/common_posture_constraint_service.py b/Scripts/s4ap/sims4communitylib/services/resources/common_posture_constraint_service.py deleted file mode 100644 index a4fc3f6..0000000 --- a/Scripts/s4ap/sims4communitylib/services/resources/common_posture_constraint_service.py +++ /dev/null @@ -1,80 +0,0 @@ -""" -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 -""" -from typing import Iterator, Union - -from interactions.constraints import Constraint, _ConstraintSet, Nowhere -from s4ap.sims4communitylib.services.common_service import CommonService - - -class CommonPostureConstraintService(CommonService): - """CommonPostureConstraintService() - - Utilities for providing and manipulating posture constraints of Sims. - """ - - def __init__(self) -> None: - self._stand_or_swim = None - - @property - def stand(self) -> Constraint: - """ A posture constraint for a Sim to stand at a target. - - :return: An instance of a Constraint. - :rtype: Constraint - """ - from animation.posture_manifest_constants import STAND_AT_NONE_CONSTRAINT - return STAND_AT_NONE_CONSTRAINT - - @property - def stand_at_none(self) -> Constraint: - """ A posture constraint for a Sim to stand at no target. - - :return: An instance of a Constraint. - :rtype: Constraint - """ - from animation.posture_manifest_constants import STAND_AT_NONE_CONSTRAINT - return STAND_AT_NONE_CONSTRAINT - - @property - def swim_at_none(self) -> Constraint: - """ A posture constraint for a Sim to swim at no target. - - :return: An instance of a Constraint. - :rtype: Constraint - """ - from animation.posture_manifest_constants import SWIM_AT_NONE_CONSTRAINT - return SWIM_AT_NONE_CONSTRAINT - - @property - def stand_or_swim_at_none(self) -> Constraint: - """ A posture constraint for a Sim to stand at a target or to swim at no target. - - :return: An instance of a Constraint. - :rtype: Constraint - """ - if self._stand_or_swim is None: - self._stand_or_swim = CommonPostureConstraintService.combine_constraints((self.stand_at_none, self.swim_at_none), debug_name='Stand-Or-Swim@None') - return self._stand_or_swim - - @staticmethod - def combine_constraints(constraints: Iterator[Constraint], fallback_constraints: Iterator[Constraint]=(), debug_name: str='Combined') -> Union[_ConstraintSet, Constraint, Nowhere]: - """combine_constraints(constraints, fallback_constraints=(), debug_name='Combined') - - Attempt to combine similar constraints into a constraint set. - - :param constraints: A collection of Constraints. - :type constraints: Iterator[Constraint] - :param fallback_constraints: A collection of Constraints to choose from as a fallback when the primary constraints fail to combine. Default is an empty collection. - :type fallback_constraints: Iterator[Constraint], optional - :param debug_name: The name of the constraint set being created. Default is 'Combined'. - :type debug_name: str, optional - :return: A constraint set containing the specified constraints, a Constraint chosen from one of the specified fallback constraints, or Nowhere when everything else fails. - :rtype: Union[_ConstraintSet, Constraint, Nowhere] - """ - from interactions.constraints import create_constraint_set - return create_constraint_set(tuple(constraints), invalid_constraints=tuple(fallback_constraints), debug_name=debug_name) diff --git a/Scripts/s4ap/sims4communitylib/services/resources/modification_handlers/__init__.py b/Scripts/s4ap/sims4communitylib/services/resources/modification_handlers/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/services/resources/modification_handlers/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/services/resources/modification_handlers/common_add_interactions_to_affordance_lists_handler.py b/Scripts/s4ap/sims4communitylib/services/resources/modification_handlers/common_add_interactions_to_affordance_lists_handler.py deleted file mode 100644 index bf0e80c..0000000 --- a/Scripts/s4ap/sims4communitylib/services/resources/modification_handlers/common_add_interactions_to_affordance_lists_handler.py +++ /dev/null @@ -1,54 +0,0 @@ -""" -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 -""" -from sims4.resources import Types -from sims4.tuning.instance_manager import InstanceManager -from typing import Tuple - -from s4ap.sims4communitylib.classes.mixins.common_affordance_lists_mixin import \ - CommonAffordanceListsMixin -from s4ap.sims4communitylib.classes.mixins.common_interactions_mixin import \ - CommonInteractionsMixin -from s4ap.sims4communitylib.services.resources.modification_handlers.common_instance_manager_modification_handler import \ - CommonInstanceManagerModificationHandler - - -class CommonAddInteractionsToAffordanceListsModificationHandler(CommonInstanceManagerModificationHandler, CommonInteractionsMixin, CommonAffordanceListsMixin): - """A handler that will add interactions to affordance lists.""" - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def instance_manager_type(cls) -> Types: - return Types.SNIPPET - - # noinspection PyMissingOrEmptyDocstring - @property - def interaction_ids(self) -> Tuple[int]: - raise NotImplementedError() - - # noinspection PyMissingOrEmptyDocstring - @property - def affordance_list_ids(self) -> Tuple[int]: - raise NotImplementedError() - - def __init__(self, *_, **__) -> None: - super().__init__(*_, **__) - CommonInteractionsMixin.__init__(self) - CommonAffordanceListsMixin.__init__(self) - - # noinspection PyMissingOrEmptyDocstring - def apply_modifications(self, instance_manager: InstanceManager): - instances = self._load_instances_from_manager(instance_manager, self.affordance_list_ids) - for instance in instances: - new_interactions = list() - for interaction_instance_to_add in self._interaction_instances_gen(): - if interaction_instance_to_add in instance.value: - continue - new_interactions.append(interaction_instance_to_add) - if not new_interactions: - continue - instance.value += tuple(new_interactions) diff --git a/Scripts/s4ap/sims4communitylib/services/resources/modification_handlers/common_instance_manager_modification_handler.py b/Scripts/s4ap/sims4communitylib/services/resources/modification_handlers/common_instance_manager_modification_handler.py deleted file mode 100644 index fd1b570..0000000 --- a/Scripts/s4ap/sims4communitylib/services/resources/modification_handlers/common_instance_manager_modification_handler.py +++ /dev/null @@ -1,50 +0,0 @@ -""" -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 -""" -from typing import Tuple, Any - -from sims4.resources import Types -from sims4.tuning.instance_manager import InstanceManager - - -class CommonInstanceManagerModificationHandler: - """A modification handler that will modify an instance manager. - - """ - @classmethod - def instance_manager_type(cls) -> Types: - """The type of instances this handler modifies.""" - raise NotImplementedError() - - def should_apply_modifications(self, instance_manager: InstanceManager) -> bool: - """should_apply_modifications(instance_manager) - - Whether or not this handler should apply its modifications to an Instance Manager. - - :param instance_manager: The instance manager to check. - :type instance_manager: InstanceManager - :return: True, if this handler should apply its modifications. False, if not. - :rtype: bool - """ - return self.__class__.instance_manager_type() == instance_manager.TYPE - - def apply_modifications(self, instance_manager: InstanceManager): - """apply_modifications(instance_manager) - - Apply modifications to an Instance Manager. - - :param instance_manager: The instance manager to modify. - :type instance_manager: InstanceManager - """ - raise NotImplementedError() - - def _load_instances_from_manager(self, instance_manager: InstanceManager, instance_ids: Tuple[int]) -> Tuple[Any]: - instances = list() - for (key, cls) in tuple(instance_manager._tuned_classes.items()): - if key.instance in instance_ids: - instances.append(cls) - return tuple(instances) diff --git a/Scripts/s4ap/sims4communitylib/services/sim/__init__.py b/Scripts/s4ap/sims4communitylib/services/sim/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/services/sim/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/services/sim/cas/__init__.py b/Scripts/s4ap/sims4communitylib/services/sim/cas/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/services/sim/cas/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/services/sim/cas/common_sim_outfit_io.py b/Scripts/s4ap/sims4communitylib/services/sim/cas/common_sim_outfit_io.py deleted file mode 100644 index aad2d7a..0000000 --- a/Scripts/s4ap/sims4communitylib/services/sim/cas/common_sim_outfit_io.py +++ /dev/null @@ -1,396 +0,0 @@ -""" -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 -""" -from typing import Tuple, FrozenSet, Dict, List, Union - -from cas.cas import OutfitData -from protocolbuffers import S4Common_pb2, Outfits_pb2 -from sims.outfits.outfit_enums import OutfitCategory, BodyType -from sims.sim_info import SimInfo -from sims.sim_info_base_wrapper import SimInfoBaseWrapper -from s4ap.sims4communitylib.enums.common_body_slot import CommonBodySlot -from s4ap.sims4communitylib.logging.has_log import HasLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils -from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils -from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils - - -class CommonSimOutfitIO(HasLog): - """CommonSimOutfitIO(sim_info, outfit_category_and_index=None, override_outfit_parts=None) - - Make changes to an outfit of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: Union[SimInfo, SimInfoBaseWrapper] - :param outfit_category_and_index: The OutfitCategory and Index of the Outfit being written to or read from. Default is the current outfit of the Sim. - :type outfit_category_and_index: Tuple[OutfitCategory, int], optional - :param initial_outfit_parts: A library of body types and cas parts to use in place of the normal parts of their outfit. If set to None, OutfitParts will be loaded from the specified OutfitCategory and Index. Default is None. - :type initial_outfit_parts: Dict[BodyType, int], optional - :param mod_identity: The identity of the mod making changes. Default is None. Optional, but highly recommended! - :type mod_identity: CommonModIdentity, optional - """ - # noinspection PyMissingOrEmptyDocstring - @property - def mod_identity(self) -> CommonModIdentity: - return self._mod_identity - - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - return 'common_sim_outfit_io' - - def __init__(self, sim_info: Union[SimInfo, SimInfoBaseWrapper], outfit_category_and_index: Tuple[OutfitCategory, int]=None, initial_outfit_parts: Dict[BodyType, int]=None, mod_identity: CommonModIdentity=None): - super().__init__() - self._mod_identity = mod_identity - self.log.enable_logging_extra_sim_details() - self._sim_info = sim_info - self._current_outfit_category_and_index = CommonOutfitUtils.get_current_outfit(sim_info) - self._outfit_category_and_index: Tuple[OutfitCategory, int] = (CommonOutfitUtils.convert_value_to_outfit_category(outfit_category_and_index[0]), outfit_category_and_index[1]) if outfit_category_and_index is not None else self._current_outfit_category_and_index - self._outfit_data: OutfitData = None - self._outfit_parts: Dict[BodyType, int] = None - self._original_outfit_data: FrozenSet[int] = None - self._outfit_body_types: List[Union[BodyType, int]] = list() - self._outfit_part_ids: List[int] = list() - if not CommonOutfitUtils.has_outfit(self._sim_info, self._outfit_category_and_index): - self.log.format_warn_with_message('Sim did not have the specified outfit category and index!', sim=self._sim_info, outfit_category_and_index=self._outfit_category_and_index) - self._load(initial_outfit_parts=initial_outfit_parts) - - @property - def sim_info(self) -> Union[SimInfo, SimInfoBaseWrapper]: - """ The Sim to apply Outfit changes to. - - :return: An instance of a Sim. - :rtype: Union[SimInfo, SimInfoBaseWrapper] - """ - return self._sim_info - - @property - def outfit_category_and_index(self) -> Tuple[OutfitCategory, int]: - """ The OutfitCategory and Index of the Outfit being written to. - - :return: The OutfitCategory and Index of the Outfit being written to. - :rtype: Tuple[OutfitCategory, int] - """ - return self._outfit_category_and_index - - @property - def outfit_parts(self) -> Dict[Union[BodyType, int], int]: - """A library of Body Types to CAS Part Ids""" - return self._to_outfit_dictionary(self.body_types, self.cas_part_ids) - - @property - def cas_part_ids(self) -> Tuple[int]: - """The decimal identifiers of CAS Parts attached to the outfit. - - :return: A collection of decimal identifiers of CAS Parts attached to the outfit. - :rtype: Tuple[int] - """ - return tuple(self._outfit_part_ids) - - @property - def body_types(self) -> Tuple[Union[BodyType, int]]: - """The body types attached to the outfit. - - :return: A collection of body types attached to the outfit. - :rtype: Tuple[Union[BodyType, int]] - """ - return tuple(self._outfit_body_types) - - def is_body_type_attached(self, body_type: Union[BodyType, int]) -> bool: - """is_body_type_attached(body_type) - - Determine if the specified BodyType is attached to the outfit. - - :param body_type: The BodyType to look for. - :type body_type: Union[BodyType, int] - :return: True, if the specified BodyType is attached to the outfit. False, if not. - :rtype: bool - """ - return self.is_any_body_type_attached((body_type,)) - - def is_any_body_type_attached(self, body_types: Tuple[Union[BodyType, int]]) -> bool: - """is_any_body_type_attached(body_types) - - Determine if any of the specified BodyTypes are attached to the outfit. - - :param body_types: The BodyType to look for. - :type body_types: Union[BodyType, int] - :return: True, if any of the specified BodyTypes are attached to the outfit. False, if not. - :rtype: bool - """ - for body_type in body_types: - for outfit_body_type in self._outfit_body_types: - if int(body_type) == int(outfit_body_type): - return True - return False - - def is_cas_part_attached(self, cas_part_id: int) -> bool: - """is_cas_part_attached(cas_part_id) - - Determine if the specified CAS Part is attached to the outfit. - - :param cas_part_id: The decimal identifier of a CAS Part. - :type cas_part_id: int - :return: True, if the specified CAS Part is attached to the outfit. False, if not. - :rtype: bool - """ - return self.is_any_cas_part_attached((cas_part_id,)) - - def is_any_cas_part_attached(self, cas_part_ids: Tuple[int]) -> bool: - """is_any_cas_part_attached(cas_part_ids) - - Determine if any of the specified CAS Parts are attached to the outfit. - - :param cas_part_ids: A collection of decimal identifiers of CAS Parts. - :type cas_part_ids: Tuple[int] - :return: True, if any of the specified CAS Parts are attached to the outfit. False, if not. - :rtype: bool - """ - return any((int(cas_part_id) in self._outfit_part_ids for cas_part_id in cas_part_ids)) - - def get_body_type_cas_part_is_attached_to(self, cas_part_id: int) -> int: - """get_body_type_cas_part_is_attached_to(cas_part_id) - - Retrieve the Body Type the specified CAS Part is attached to. - - :param cas_part_id: The decimal identifier of a CAS Part. - :type cas_part_id: int - :return: The Body Type the specified CAS Part was located at or -1 if the Outfit does not have the CAS Part or the CAS Part is empty. - :rtype: Union[int, BodyType] - """ - for (_body_type, _cas_part_id) in zip(self.body_types, self.cas_part_ids): - if int(_cas_part_id) == int(cas_part_id): - return _body_type - self.log.format_with_message('CAS Part not found.', cas_part_id=cas_part_id) - return -1 - - def get_cas_part_at_body_type(self, body_type: Union[CommonBodySlot, BodyType, int]) -> int: - """get_cas_part_at_body_type(body_type) - - Retrieve the CAS Part located at the specified body type. - - :param body_type: The BodyType to look at. - :type body_type: Union[CommonBodySlot, BodyType, int] - :return: The decimal identifier of the CAS Part located at the specified body part or -1 if the Outfit does not have the body type or the body type is empty. - :rtype: int - """ - for (_body_type, _cas_part_id) in zip(self.body_types, self.cas_part_ids): - if int(_body_type) == int(body_type): - return _cas_part_id - self.log.format_with_message('Body type not found.', body_type=body_type) - return -1 - - def attach_cas_part(self, cas_part_id: int, body_type: Union[BodyType, int]=BodyType.NONE) -> bool: - """attach_cas_part(cas_part_id, body_type=BodyType.NONE) - - Attach a CAS Part to the specified body type. - - ..note:: This will override the CAS Part located at the body type, if there is one. - - :param cas_part_id: The decimal identifier of a CAS Part. - :type cas_part_id: int - :param body_type: The BodyType the CAS Part will be attached to. Default is the BodyType of the CAS Part - :type body_type: Union[BodyType, int], optional - :return: True, if the CAS Part was attached successfully. False, if not. - :rtype: bool - """ - from s4ap.sims4communitylib.utils.cas.common_cas_utils import CommonCASUtils - if cas_part_id == -1 or cas_part_id is None: - self.log.format_error_with_message('Attempted to attach a negative or None CAS Part to the outfit of a Sim!', sim=self.sim_info, body_type=body_type, cas_part_id=cas_part_id, outfit_category_and_index=self._outfit_category_and_index) - return False - if body_type == BodyType.NONE: - body_type = CommonCASUtils.get_body_type_of_cas_part(cas_part_id) - self.log.format_with_message('Attempting to attach cas part to body type.', cas_part=cas_part_id, body_type=body_type) - if self.is_body_type_attached(body_type): - self.detach_body_type(body_type) - self.log.format_with_message('Attaching CAS Part.', cas_part=cas_part_id, body_type=body_type) - self._outfit_body_types.append(body_type) - self._outfit_part_ids.append(cas_part_id) - self.log.format_with_message('Finished adding cas part to body type.', cas_part=cas_part_id, body_type=body_type) - return True - - def detach_cas_part(self, cas_part_id: int) -> bool: - """detach_cas_part(cas_part_id) - - Detach a CAS Part from all body types of the Outfit. - - :param cas_part_id: The decimal identifier of a CAS Part. - :type cas_part_id: int - :return: True, if the CAS Part was erased from all body types successfully. False, if not. - :rtype: bool - """ - self.log.format_with_message('Attempting to detach cas part', cas_part=cas_part_id, current_body_types=self._outfit_body_types, current_cas_parts=self._outfit_body_types) - new_body_types = list() - new_part_ids = list() - for (_body_type, _cas_part_id) in zip(self.body_types, self.cas_part_ids): - if int(_cas_part_id) == int(cas_part_id): - self.log.format_with_message('Detaching CAS Part.', cas_part=cas_part_id) - continue - self.log.format_with_message('Keeping CAS Part.', cas_part=cas_part_id, other_cas_part=_cas_part_id) - new_body_types.append(_body_type) - new_part_ids.append(_cas_part_id) - self._outfit_body_types = new_body_types - self._outfit_part_ids = new_part_ids - return True - - def detach_body_type(self, body_type: Union[BodyType, int]) -> bool: - """detach_body_type(body_type) - - Detach the BodyType including the CAS Part attached to it from the outfit. - - :param body_type: The BodyType being detached. - :type body_type: Union[BodyType, int] - :return: True, if the Body Type was detached from the outfit successfully. False, if not. - :rtype: bool - """ - self.log.format_with_message('Attempting to detach body type', body_type=body_type) - self.log.format(current_body_types=self._outfit_body_types) - new_body_types = list() - new_part_ids = list() - for (_body_type, _cas_part_id) in zip(self.body_types, self.cas_part_ids): - if int(_body_type) == int(body_type): - self.log.format_with_message('Detaching body type', body_type=body_type) - continue - self.log.format_with_message('Keeping body type.', body_type=body_type, other_body_type=_body_type) - new_body_types.append(_body_type) - new_part_ids.append(_cas_part_id) - self._outfit_body_types = new_body_types - self._outfit_part_ids = new_part_ids - return True - - def apply( - self, - resend_outfits_after_apply: bool=True, - change_sim_to_outfit_after_apply: bool=True, - apply_to_all_outfits_in_same_category: bool=False, - apply_to_outfit_category_and_index: Tuple[OutfitCategory, int]=None - ) -> bool: - """apply(resend_outfits_after_apply=True, change_sim_to_outfit_after_apply=True, apply_to_all_outfits_in_same_category=False, apply_to_outfit_category_and_index=None) - - Apply all changes made to the Outfit. - - :param resend_outfits_after_apply: If set to True, the outfits of the Sim will be re-sent after changes have been applied. Default is True. - :type resend_outfits_after_apply: bool, optional - :param change_sim_to_outfit_after_apply: If set to True, the Sim will change to the outfit after the outfit is updated. Default is True. - :type change_sim_to_outfit_after_apply: bool, optional - :param apply_to_all_outfits_in_same_category: If set to True, changes will be applied to all Outfits in the same category. If set to False, changes will only be applied to the outfit provided at initialization. Default is False. - :type apply_to_all_outfits_in_same_category: bool, optional - :param apply_to_outfit_category_and_index: The OutfitCategory and Index to apply changes to. If set to None, it will be the OutfitCategory and Index provided at initialization. Default is None. - :type apply_to_outfit_category_and_index: Tuple[OutfitCategory, int], optional - :return: True, if changes were applied successfully. False, if not. - :rtype: bool - """ - sim_name = CommonSimNameUtils.get_full_name(self.sim_info) - self.log.format_with_message( - 'Applying changes to outfit', - sim=sim_name, - resend_outfits=resend_outfits_after_apply, - change_to_outfit=change_sim_to_outfit_after_apply, - initial_outfit_category_and_index=self.outfit_category_and_index, - apply_to_all_outfits_in_same_category=apply_to_all_outfits_in_same_category, - apply_to_outfit_category_and_index=apply_to_outfit_category_and_index - ) - apply_to_outfit_category_and_index = apply_to_outfit_category_and_index or self.outfit_category_and_index - outfit_to_apply_to_data = CommonOutfitUtils.get_outfit_data(self.sim_info, outfit_category_and_index=apply_to_outfit_category_and_index) - outfit_to_apply_to_parts = CommonOutfitUtils.get_outfit_parts(self.sim_info, outfit_category_and_index=apply_to_outfit_category_and_index) - outfit_to_apply_to_original_data: FrozenSet[int] = frozenset(outfit_to_apply_to_parts.items()) - saved_outfits = self.sim_info.save_outfits() - self.log.format_with_message('Applying Outfit IO Changes to outfits', sim=self.sim_info, outfits=saved_outfits.outfits, outfit_part_ids=self._outfit_part_ids, outfit_body_types=self._outfit_body_types) - for saved_outfit in saved_outfits.outfits: - if int(saved_outfit.category) != int(apply_to_outfit_category_and_index[0]): - self.log.format_with_message('Ignoring saved outfit due to wrong category.', sim=self.sim_info, outfit_category=saved_outfit.category, expected_category=apply_to_outfit_category_and_index[0]) - continue - - if not apply_to_all_outfits_in_same_category: - self.log.format_with_message('Changes are not being applied to all outfits in the same category.', sim=self.sim_info, outfit_category_and_index=apply_to_outfit_category_and_index) - # noinspection PyUnresolvedReferences - saved_outfit_data = self._to_outfit_data(saved_outfit.body_types_list.body_types, saved_outfit.parts.ids) - self.log.format_with_message('Checking if sub outfit data matches', saved_outfit_data=saved_outfit_data) - if int(saved_outfit.outfit_id) != int(outfit_to_apply_to_data.outfit_id) or saved_outfit_data != outfit_to_apply_to_original_data: - self.log.format_with_message('Sub outfit data did not match!', saved_outfit_id=saved_outfit.outfit_id, self_outfit_id=outfit_to_apply_to_data.outfit_id, saved_outfit_data=saved_outfit_data, original_outfit_data=outfit_to_apply_to_original_data) - continue - else: - self.log.format_with_message('Sub outfit matches.', saved_outfit_id=saved_outfit.outfit_id, self_outfit_id=outfit_to_apply_to_data.outfit_id, saved_outfit_data=saved_outfit_data, original_outfit_data=outfit_to_apply_to_original_data) - - saved_outfit.parts = S4Common_pb2.IdList() - # noinspection PyUnresolvedReferences - saved_outfit.parts.ids.extend(self._outfit_part_ids) - saved_outfit.body_types_list = Outfits_pb2.BodyTypesList() - # noinspection PyUnresolvedReferences - saved_outfit.body_types_list.body_types.extend([int(body_type) for body_type in self._outfit_body_types]) - # noinspection PyUnresolvedReferences - saved_outfit_data = self._to_outfit_data(saved_outfit.body_types_list.body_types, saved_outfit.parts.ids) - self.log.format_with_message('Changes made.', saved_outfit_data=saved_outfit_data) - if not apply_to_all_outfits_in_same_category: - self.log.format_with_message('Skipping the other outfit indexes, since we do not want to apply to all outfits in the same category.', sim=self.sim_info, outfit_category_and_index_applied_to=apply_to_outfit_category_and_index) - break - - self.sim_info._base.outfits = saved_outfits.SerializeToString() - if change_sim_to_outfit_after_apply: - self.sim_info._base.outfit_type_and_index = apply_to_outfit_category_and_index - else: - self.sim_info._base.outfit_type_and_index = self._current_outfit_category_and_index - self.log.format_with_message('Finished applying outfit changes.', sim=self.sim_info, outfit_category_and_index_applid_to=apply_to_outfit_category_and_index) - if resend_outfits_after_apply: - CommonOutfitUtils.refresh_outfit(self.sim_info, outfit_category_and_index=self._current_outfit_category_and_index) - return CommonOutfitUtils.resend_outfits(self.sim_info) - return True - - def _load(self, initial_outfit_parts: Dict[BodyType, int]=None) -> bool: - target_sim_name = CommonSimNameUtils.get_full_name(self.sim_info) - self._outfit_parts = CommonOutfitUtils.get_outfit_parts(self.sim_info, outfit_category_and_index=self._outfit_category_and_index) or dict() - self._original_outfit_data: FrozenSet[int] = frozenset(self._outfit_parts.items()) - if initial_outfit_parts is not None: - cleaned_initial_outfit_parts = self._clean_outfit_parts(initial_outfit_parts) - - self._outfit_body_types = list(cleaned_initial_outfit_parts.keys()) - self._outfit_part_ids = list(initial_outfit_parts.values()) - else: - if self._outfit_parts is None: - self.log.format_error_with_message('No outfit parts for available Sim \'{}\' and Outfit Category and Index {}'.format(target_sim_name, self._outfit_category_and_index), initial_outfit_parts=initial_outfit_parts, throw=True) - return False - self._outfit_parts = self._clean_outfit_parts(self._outfit_parts) - - self._outfit_body_types: List[Union[BodyType, int]] = list(self._outfit_parts.keys()) - self._outfit_part_ids: List[int] = list(self._outfit_parts.values()) - if len(self._outfit_body_types) != len(self._outfit_part_ids): - self.log.format_error_with_message('\'{}\': The number of cas parts did not match the number of body types for Outfit Category and Index {}.'.format(target_sim_name, self._outfit_category_and_index), outfit_category_and_index=self.outfit_category_and_index, outfit_parts=self._outfit_parts, throw=True) - return False - return True - - def _clean_outfit_parts(self, outfit_parts: Dict[Union[BodyType, int], int]) -> Dict[Union[BodyType, int], int]: - cleaned_outfit_parts = dict() - for (body_type, cas_part_id) in outfit_parts.items(): - if (not isinstance(body_type, int) and not isinstance(body_type, BodyType)) or not isinstance(cas_part_id, int): - self.log.format_error_with_message('outfit_body_parts contains non-integer variables body_type: {} cas_part_id: {}.'.format(body_type, cas_part_id), sim=self.sim_info, body_type=body_type, cas_part_id=cas_part_id, outfit_parts=outfit_parts) - continue - if cas_part_id == -1 or cas_part_id is None: - self.log.format_with_message('Ignoring body_type with negative or None cas_part_id.', sim=self.sim_info, outfit_category_and_index=self.outfit_category_and_index, body_type=body_type, cas_part_id=cas_part_id) - continue - # noinspection PyUnresolvedReferences - if isinstance(body_type, int) and body_type in BodyType.value_to_name: - # noinspection PyUnresolvedReferences - new_body_type = CommonResourceUtils.get_enum_by_name(BodyType.value_to_name[body_type], BodyType, default_value=-1) - if new_body_type == -1: - new_body_type = body_type - else: - new_body_type = body_type - cleaned_outfit_parts[new_body_type] = cas_part_id - return cleaned_outfit_parts - - def _to_outfit_dictionary(self, body_types: Tuple[Union[BodyType, int]], part_ids: Tuple[int]) -> Dict[Union[BodyType, int], int]: - return dict(zip(list(body_types), list(part_ids))) - - def _to_outfit_data(self, body_types: Tuple[Union[BodyType, int]], part_ids: Tuple[int]) -> FrozenSet[Union[BodyType, int]]: - return frozenset(dict(zip(list(body_types), list(part_ids))).items()) - - def __repr__(self) -> str: - return self.__str__() - - def __str__(self) -> str: - return f'<{self.__class__.__name__}: OCI: {self.outfit_category_and_index}, Parts: {self._outfit_parts}>' diff --git a/Scripts/s4ap/sims4communitylib/services/sim/cas/common_temporary_sim_clone_in_cas_service.py b/Scripts/s4ap/sims4communitylib/services/sim/cas/common_temporary_sim_clone_in_cas_service.py deleted file mode 100644 index 6adc3fb..0000000 --- a/Scripts/s4ap/sims4communitylib/services/sim/cas/common_temporary_sim_clone_in_cas_service.py +++ /dev/null @@ -1,283 +0,0 @@ -""" -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 -""" -import services -from typing import List, Callable, Dict, Tuple -from sims.outfits.outfit_enums import OutfitCategory, BodyType -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from s4ap.sims4communitylib.events.sim.events.sim_set_current_outfit import S4CLSimSetCurrentOutfitEvent -from s4ap.sims4communitylib.events.zone_spin.events.zone_late_load import S4CLZoneLateLoadEvent -from s4ap.sims4communitylib.logging.has_log import HasLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ - CommonConsoleCommandArgument -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.services.common_service import CommonService -from s4ap.sims4communitylib.services.sim.cas.common_sim_outfit_io import CommonSimOutfitIO -from s4ap.sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from s4ap.sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils -from s4ap.sims4communitylib.utils.sims.common_sim_location_utils import CommonSimLocationUtils -from s4ap.sims4communitylib.utils.sims.common_sim_spawn_utils import CommonSimSpawnUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - - -class CommonEditSimCloneInCASResponseHandle: - """CommonEditSimCloneInCASResponseHandle(\ - sim_clone_id,\ - on_outfit_modified=CommonFunctionUtils.noop,\ - on_finished=CommonFunctionUtils.noop,\ - ) - - A handle for when changes are made (or not made) to a temporary Sim Clone. - - :param sim_clone_id: The decimal identifier of the Sim clone the handle is for. - :type sim_clone_id: int - :param on_outfit_modified: A callback invoked when the outfit of the Sim Clone is modified. It will receive the Sim Clone object itself as well as an Outfit IO for easy retrieval of outfit parts. Default is Noop. - :type on_outfit_modified: Callable[[SimInfo, CommonSimOutfitIO], None], optional - :param on_finished: A callback invoked when the outfit is either modified or not. Default is noop. - :type on_finished: Callable[[], None], optional - """ - - def __init__( - self, - sim_clone_id: int, - on_outfit_modified: Callable[[SimInfo, CommonSimOutfitIO], None]=CommonFunctionUtils.noop, - on_finished: Callable[[], None]=CommonFunctionUtils.noop - ): - self.sim_clone_id = sim_clone_id - self.on_outfit_modified = on_outfit_modified - self.on_finished = on_finished - - -class CommonEditSimCloneInCASService(CommonService, HasLog): - """CommonEditSimCloneInCASService() - - A service that will create a Sim clone, open CAS with that Sim clone for edit, invoke callbacks when the outfit of the Sim clone is modified, and finally delete the Sim clone. - - """ - - # noinspection PyMissingOrEmptyDocstring - @property - def mod_identity(self) -> CommonModIdentity: - return ModInfo.get_identity() - - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - return 'common_edit_sim_clone_in_cas_service' - - def __init__(self, outfit_category_and_index: Tuple[OutfitCategory, int]=(OutfitCategory.EVERYDAY, 0)) -> None: - super().__init__() - self._sim_clone_response_handle_library: Dict[int, CommonEditSimCloneInCASResponseHandle] = dict() - self._sim_clone_sim_ids_awaiting_destruction: List[int] = list() - self._outfit_category_and_index = outfit_category_and_index - - def modify_sim_clone_for_sim( - self, - sim_info: SimInfo, - setup_outfit: Callable[[CommonSimOutfitIO], None]=CommonFunctionUtils.noop, - on_outfit_modified: Callable[[SimInfo, CommonSimOutfitIO], None]=CommonFunctionUtils.noop, - on_finished: Callable[[], None]=CommonFunctionUtils.noop - ) -> None: - """modify_sim_clone_for_sim() - - Modify a Clone of a Sim in CAS - - """ - self.modify_sim_clone(sim_info, setup_outfit=setup_outfit, on_outfit_modified=on_outfit_modified, on_finished=on_finished) - - def modify_sim_clone( - self, - source_sim_info: SimInfo, - setup_outfit: Callable[[CommonSimOutfitIO], None]=CommonFunctionUtils.noop, - on_outfit_modified: Callable[[SimInfo, CommonSimOutfitIO], None]=CommonFunctionUtils.noop, - on_finished: Callable[[], None]=CommonFunctionUtils.noop - ) -> None: - """Create a temporary Sim clone, open cas with it, and invoke callbacks when the Sim clone outfit is modified.""" - if source_sim_info is None: - self.log.error('No Sim was specified for cloning!') - return - if on_outfit_modified is None: - self.log.error('Missing on_outfit_modified.') - return - if self._sim_clone_sim_ids_awaiting_destruction: - sim_clone_sim_ids_awaiting_destruction = tuple(self._sim_clone_sim_ids_awaiting_destruction) - for _sim_clone_sim_id in sim_clone_sim_ids_awaiting_destruction: - _clone_sim_info = CommonSimUtils.get_sim_info(_sim_clone_sim_id) - if _clone_sim_info is None: - continue - if CommonSimSpawnUtils.delete_sim(_clone_sim_info, source=f'{self.mod_identity.name} Destroy Old Sim Clone', cause='Sim Clone is Old'): - if _sim_clone_sim_id in self._sim_clone_sim_ids_awaiting_destruction: - self._sim_clone_sim_ids_awaiting_destruction.remove(_sim_clone_sim_id) - # if CommonOccultUtils.has_any_occult(source_sim_info): - # CommonOccultUtils.switch_to_occult_form(source_sim_info, CommonOccultType.NON_OCCULT) - - clone_sim_info = CommonSimSpawnUtils.clone_sim(source_sim_info, add_to_household=True) - if clone_sim_info is None: - self.log.format_error('Failed to create Clone Sim.') - return - try: - clone_household_id = CommonHouseholdUtils.get_household_id(clone_sim_info) - CommonSimSpawnUtils.spawn_sim(clone_sim_info, location=CommonSimLocationUtils.get_location(source_sim_info)) - self._delete_other_outfits(clone_sim_info) - sim_clone_sim_id = CommonSimUtils.get_sim_id(clone_sim_info) - clone_sim_info.skin_tone = source_sim_info.skin_tone - clone_sim_info.skin_tone_val_shift = source_sim_info.skin_tone_val_shift - - self.verbose_log.format_with_message('Current Sim clone outfit', outfit_parts=CommonOutfitUtils.get_outfit_parts(clone_sim_info)) - self._setup_sim_clone_outfit(clone_sim_info, CommonOutfitUtils.get_outfit_parts(source_sim_info, outfit_category_and_index=(OutfitCategory.BATHING, 0)), setup_outfit) - client = services.client_manager().get_first_client() - self.log.format_with_message('Adding Sim Id to response handle library', sim_id=sim_clone_sim_id, sim=clone_sim_info) - self._sim_clone_response_handle_library[sim_clone_sim_id] = CommonEditSimCloneInCASResponseHandle(sim_clone_sim_id, on_outfit_modified=on_outfit_modified, on_finished=on_finished) - if client is not None: - import sims4.commands - sims4.commands.client_cheat('cas.fulleditmode', client.id) - sims4.commands.client_cheat('sims.exit2cas {} {} {}'.format(sim_clone_sim_id, clone_household_id, CommonSimUtils.get_sim_info(source_sim_info)), client.id) - except Exception as ex: - self.log.error('An error occurred when trying to display clone Sim.', exception=ex) - if clone_sim_info is not None: - CommonSimSpawnUtils.delete_sim(clone_sim_info, source=f'{self.mod_identity.name} Destroy Sim Clone due to error', cause='Deleting Sim Clone due to error') - - def _setup_sim_clone_outfit( - self, - clone_sim_info: SimInfo, - initial_outfit_parts: Dict[BodyType, int], - setup_outfit: Callable[[CommonSimOutfitIO], None]=CommonFunctionUtils.noop - ): - self.log.format_with_message('Setting up Sim clone outfit', sim_clone_sim_info=clone_sim_info, initial_outfit_parts=initial_outfit_parts, outfit_category_and_index=CommonOutfitUtils.get_current_outfit(clone_sim_info)) - # noinspection PyTypeChecker - outfit_io = CommonSimOutfitIO(clone_sim_info, outfit_category_and_index=self._outfit_category_and_index, initial_outfit_parts=initial_outfit_parts, mod_identity=self.mod_identity) - if setup_outfit is not None: - setup_outfit(outfit_io) - - # from s4ap.sims4communitylib.utils.sims.common_occult_utils import CommonOccultUtils - # if CommonOccultUtils.has_any_occult(clone_sim_info): - # CommonOccultUtils.switch_to_occult_form(clone_sim_info, OccultType.HUMAN) - if outfit_io.apply(apply_to_all_outfits_in_same_category=True, apply_to_outfit_category_and_index=self._outfit_category_and_index): - clone_sim_info.on_outfit_generated(*self._outfit_category_and_index) - clone_sim_info.set_outfit_dirty(self._outfit_category_and_index[0]) - clone_sim_info.set_current_outfit(self._outfit_category_and_index) - - def _on_sim_clone_outfit_changed( - self, - clone_sim_info: SimInfo, - outfit_category_and_index: Tuple[OutfitCategory, int] - ) -> None: - clone_sim_id = CommonSimUtils.get_sim_id(clone_sim_info) - if clone_sim_id not in self._sim_clone_response_handle_library: - self.log.format_with_message('No response handle found waiting for Sim clone outfit change.', clone_sim_id=clone_sim_id, sim=clone_sim_info) - return - self.log.format_with_message( - 'Sim Clone outfit changed', - sim_clone_id=clone_sim_id, - clone_sim_info=clone_sim_info, - outfit_category_and_index=outfit_category_and_index - ) - # noinspection PyTypeChecker - outfit_io = CommonSimOutfitIO(clone_sim_info, mod_identity=ModInfo.get_identity(), outfit_category_and_index=self._outfit_category_and_index) - - sim_clone_response_handle = self._sim_clone_response_handle_library[clone_sim_id] - try: - if sim_clone_response_handle is None: - self.log.format_with_message('No response handle found. Done handling on outfit changed', clone_sim_id=clone_sim_id) - return - self.log.format_with_message('Response handle found, invoking Sim clone callback', clone_sim_id=clone_sim_id) - sim_clone_response_handle.on_outfit_modified(clone_sim_info, outfit_io) - except Exception as ex: - self.log.error('Error occurred while invoking Sim clone callback', exception=ex) - finally: - if clone_sim_id not in self._sim_clone_sim_ids_awaiting_destruction: - self._sim_clone_sim_ids_awaiting_destruction.append(clone_sim_id) - - def _clean_up_sim_clones(self) -> None: - for (sim_clone_id, response_handle) in self._sim_clone_response_handle_library.items(): - sim_clone_sim_info = CommonSimUtils.get_sim_info(sim_clone_id) - if sim_clone_sim_info is not None: - self._on_sim_clone_outfit_changed(sim_clone_sim_info, CommonOutfitUtils.get_current_outfit(sim_clone_sim_info)) - - if not self._sim_clone_sim_ids_awaiting_destruction: - self.log.debug('No sim_clones were awaiting destruction') - return - - sim_clone_ids_awaiting_destruction = tuple(self._sim_clone_sim_ids_awaiting_destruction) - for sim_clone_sim_id in sim_clone_ids_awaiting_destruction: - self.log.format_with_message('Cleaning up Sim clone.', sim_clone_id=sim_clone_sim_id) - if sim_clone_sim_id in self._sim_clone_response_handle_library: - sim_clone_response_handle = self._sim_clone_response_handle_library[sim_clone_sim_id] - try: - if sim_clone_response_handle is not None: - self.log.format_with_message('Calling response handle on finished.', sim_clone_id=sim_clone_sim_id) - if sim_clone_response_handle.on_finished is not None: - sim_clone_response_handle.on_finished() - except Exception as ex: - self.log.error('An error occurred while invoking on finished.', exception=ex) - finally: - del self._sim_clone_response_handle_library[sim_clone_sim_id] - - clone_sim_info = CommonSimUtils.get_sim_info(sim_clone_sim_id) - if clone_sim_info is None: - self.log.format_with_message('Sim Clone SimInfo not found.', sim_clone_id=sim_clone_sim_id) - continue - - self.log.format_with_message('Destroying Sim Clone.', sim_clone_id=sim_clone_sim_id) - - if CommonSimSpawnUtils.delete_sim(clone_sim_info, source=self.mod_identity.name, cause=f'{self.mod_identity.name}: Sim Clone is being cleaned up'): - if sim_clone_sim_id in self._sim_clone_sim_ids_awaiting_destruction: - self._sim_clone_sim_ids_awaiting_destruction.remove(sim_clone_sim_id) - - def _delete_other_outfits(self, sim_info: SimInfo): - from sims.outfits.outfit_tracker import OutfitTrackerMixin - outfits: OutfitTrackerMixin = sim_info.get_outfits() - current_outfit = CommonOutfitUtils.get_current_outfit(sim_info) - for outfit_category in CommonOutfitUtils.get_all_outfit_categories(): - for outfit_index in range(CommonOutfitUtils.get_maximum_number_of_outfits_for_category(outfit_category)): - outfit = (outfit_category, outfit_index) - if outfit_category in (self._outfit_category_and_index[0], OutfitCategory.BATHING, OutfitCategory.SPECIAL) and outfit_index == 0: - self.log.format_with_message('Skipping first outfit.', sim=sim_info, outfit=outfit) - continue - if not CommonOutfitUtils.has_outfit(sim_info, outfit): - self.log.format_with_message('Sim did not have outfit.', sim=sim_info, outfit=outfit) - continue - outfits.remove_outfit(outfit_category, outfit_index=outfit_index) - self.log.format_with_message('Removed outfit.', sim=sim_info, outfit=outfit) - sim_info.appearance_tracker.evaluate_appearance_modifiers() - CommonOutfitUtils.resend_outfits(sim_info) - CommonOutfitUtils.set_current_outfit(sim_info, current_outfit) - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.modify_sim_clone', - 'Create a Clone of a Sim and open CAS to modify them.', - command_arguments=( - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to create and modify a clone of.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.modifysimclone', - ) -) -def _s4clib_modify_sim_clone(output: CommonConsoleCommandOutput, sim_info: SimInfo=None): - if sim_info is None: - return - output(f'Modifying a clone of Sim \'{sim_info}\' in CAS.') - CommonEditSimCloneInCASService().modify_sim_clone_for_sim(sim_info) - output('Done') - - -# noinspection PyUnusedLocal -@CommonEventRegistry.handle_events(ModInfo.get_identity()) -def _common_clean_sim_clones_on_zone_load(event_data: S4CLZoneLateLoadEvent): - CommonEditSimCloneInCASService()._clean_up_sim_clones() - - -@CommonEventRegistry.handle_events(ModInfo.get_identity()) -def _common_sim_clone_on_outfit_change(event_data: S4CLSimSetCurrentOutfitEvent) -> bool: - CommonEditSimCloneInCASService()._on_sim_clone_outfit_changed(event_data.sim_info, event_data.new_outfit_category_and_index) - return True diff --git a/Scripts/s4ap/sims4communitylib/systems/__init__.py b/Scripts/s4ap/sims4communitylib/systems/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/systems/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/systems/caching/__init__.py b/Scripts/s4ap/sims4communitylib/systems/caching/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/systems/caching/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/systems/caching/common_serializable_object_cache.py b/Scripts/s4ap/sims4communitylib/systems/caching/common_serializable_object_cache.py deleted file mode 100644 index df3a0b3..0000000 --- a/Scripts/s4ap/sims4communitylib/systems/caching/common_serializable_object_cache.py +++ /dev/null @@ -1,69 +0,0 @@ -""" -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 -""" -from typing import Union, Dict, Any, Type, Tuple, TypeVar, Generic, List - -from s4ap.sims4communitylib.classes.serialization.common_serializable import CommonSerializable - -CommonSerializableObjectCacheType = TypeVar('CommonSerializableObjectCacheType', bound=CommonSerializable) - - -class CommonSerializableObjectCache(CommonSerializable, Generic[CommonSerializableObjectCacheType]): - """A cache of serializable objects.""" - - def __init__(self, cached_objects: Tuple[CommonSerializableObjectCacheType], checksums: Dict[str, int]): - self._cached_objects = cached_objects - self._checksums = checksums - - @property - def cached_objects(self) -> Tuple[CommonSerializableObjectCacheType]: - """Cached objects""" - return self._cached_objects - - @property - def cached_checksums(self) -> Dict[str, int]: - """Cached checksums, these are used to check if the cache needs updating.""" - return self._checksums - - # noinspection PyMissingOrEmptyDocstring - def serialize(self: 'CommonSerializableObjectCache') -> Union[str, Dict[str, Any]]: - data = dict() - data['cached_checksums'] = self._checksums - data['cached_objects'] = [cached_object.serialize() for cached_object in self.cached_objects] - return data - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def deserialize( - cls: Type['CommonSerializableObjectCache'], - data: Union[str, Dict[str, Any]] - ) -> Union['CommonSerializableObjectCache', None]: - checksums = data.get('cached_checksums', None) - if checksums is None: - return None - cached_objects_data = data.get('cached_objects', tuple()) - - if not cached_objects_data: - return None - - cached_objects: List[CommonSerializableObjectCacheType] = list() - for object_data in cached_objects_data: - cached_object = cls._deserialize_object(object_data) - if cached_object is None: - continue - cached_objects.append(cached_object) - if not cached_objects: - return None - - return cls( - tuple(cached_objects), - checksums - ) - - @classmethod - def _deserialize_object(cls, data: Union[str, Dict[str, Any]]) -> Union[CommonSerializableObjectCacheType, None]: - return CommonSerializableObjectCacheType.deserialize(data) diff --git a/Scripts/s4ap/sims4communitylib/systems/caching/common_serializable_object_cache_service.py b/Scripts/s4ap/sims4communitylib/systems/caching/common_serializable_object_cache_service.py deleted file mode 100644 index 56c3654..0000000 --- a/Scripts/s4ap/sims4communitylib/systems/caching/common_serializable_object_cache_service.py +++ /dev/null @@ -1,104 +0,0 @@ -""" -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 -""" -import os -from typing import Union, Generic, TypeVar, Tuple, Dict, Any - -from s4ap.sims4communitylib.systems.caching.common_serializable_object_cache import CommonSerializableObjectCache -from s4ap.sims4communitylib.classes.serialization.common_serializable import CommonSerializable -from s4ap.sims4communitylib.logging.has_log import HasLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.services.common_service import CommonService -from s4ap.sims4communitylib.utils.common_io_utils import CommonIOUtils -from s4ap.sims4communitylib.utils.common_json_io_utils import CommonJSONIOUtils -from s4ap.sims4communitylib.utils.common_log_utils import CommonLogUtils - - -CommonSerializableObjectCacheType = TypeVar('CommonSerializableObjectCacheType', bound=CommonSerializableObjectCache[CommonSerializable]) - - -class CommonSerializableObjectCacheService(CommonService, HasLog, Generic[CommonSerializableObjectCacheType]): - """A service that manages a cache of serializable objects.""" - - # noinspection PyMissingOrEmptyDocstring - @property - def mod_identity(self) -> CommonModIdentity: - raise NotImplementedError() - - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - return 'common_serializable_object_cache_service' - - @property - def _cache_file_name(self) -> str: - raise NotImplementedError() - - def __init__(self) -> None: - super().__init__() - self._cache = None - - def cache_needs_update(self, new_checksum_data: Any) -> bool: - """Determine if the cache needs to be updated or not.""" - cache = self.load_from_cache() - if cache is None or not cache.cached_checksums: - return False - (snippet_name, snippet_id, new_checksum) = new_checksum_data - checksums = cache.cached_checksums - key = f'{snippet_name}-{snippet_id}' - if checksums.get(key, -1) != new_checksum: - return True - return False - - def save_to_cache(self, cache: CommonSerializableObjectCacheType) -> None: - """Save a cache of data.""" - file_path = self._get_cache_file_path() - folder_path = self._get_cache_folder_path() - if os.path.exists(file_path): - CommonIOUtils.delete_file(file_path) - - if not os.path.exists(folder_path): - os.makedirs(folder_path, exist_ok=True) - - CommonJSONIOUtils.write_to_file(file_path, cache.serialize()) - self._cache = cache - - def load_from_cache(self) -> Union[CommonSerializableObjectCacheType, None]: - """Load the cached data.""" - if self._cache is not None: - return self._cache - file_path = self._get_cache_file_path() - if os.path.exists(file_path): - self._cache = self._deserialize_cache(CommonJSONIOUtils.load_from_file(file_path)) - else: - self._cache = None - return self._cache - - def clear_cache(self) -> None: - """Clear the cached data""" - file_path = self._get_cache_file_path() - if os.path.exists(file_path): - CommonIOUtils.delete_file(file_path) - self._cache = None - - def _get_cache_folder_path(self) -> str: - return os.path.join(CommonLogUtils.get_mod_data_location_path(), self.mod_identity.base_namespace.lower(), 'caches') - - def _get_cache_file_path(self) -> str: - return os.path.join(self._get_cache_folder_path(), f'{self._cache_file_name}_cache.json') - - def _deserialize_cache(self, data: Union[str, Dict[str, Any]]) -> CommonSerializableObjectCacheType: - return CommonSerializableObjectCacheType[CommonSerializable].deserialize(data) - - def create_cache(self, objects: Tuple[CommonSerializable], checksums: Tuple[Any]) -> CommonSerializableObjectCacheType: - """ - Create a new cache. - """ - checksum_data = dict() - for (snippet_name, snippet_id, checksum_value) in checksums: - checksum_data[f'{snippet_name}-{snippet_id}'] = checksum_value - return CommonSerializableObjectCache[CommonSerializable](objects, checksum_data) diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/__init__.py b/Scripts/s4ap/sims4communitylib/systems/item_query/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/systems/item_query/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/common_loaded_item_query_registry.py b/Scripts/s4ap/sims4communitylib/systems/item_query/common_loaded_item_query_registry.py deleted file mode 100644 index 0e6fb8b..0000000 --- a/Scripts/s4ap/sims4communitylib/systems/item_query/common_loaded_item_query_registry.py +++ /dev/null @@ -1,545 +0,0 @@ -""" -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 -""" -import collections -from typing import List, Dict, Any, Tuple, Set, Callable, Union, Iterator, TypeVar, Generic - -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.systems.item_query.item_tests.common_loaded_item_test import CommonLoadedItemTest -from s4ap.sims4communitylib.systems.item_query.query.common_loaded_item_filter_request import CommonLoadedItemFilterRequest -from s4ap.sims4communitylib.systems.item_query.query.common_loaded_item_organizer import CommonLoadedItemOrganizer -from s4ap.sims4communitylib.systems.item_query.dtos.common_loaded_item import CommonLoadedItem -from s4ap.sims4communitylib.systems.item_query.common_loaded_item_registry import CommonLoadedItemRegistry -from s4ap.sims4communitylib.classes.time.common_stop_watch import CommonStopWatch -from s4ap.sims4communitylib.events.zone_spin.events.zone_early_load import S4CLZoneEarlyLoadEvent -from s4ap.sims4communitylib.events.zone_spin.events.zone_late_load import S4CLZoneLateLoadEvent -from s4ap.sims4communitylib.logging.has_log import HasLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.notifications.common_basic_notification import CommonBasicNotification -from s4ap.sims4communitylib.services.common_service import CommonService -from s4ap.sims4communitylib.systems.item_query.enums.common_query_method_type import CommonQueryMethodType -from s4ap.sims4communitylib.utils.misc.common_text_utils import CommonTextUtils - -CommonLoadedItemType = TypeVar('CommonLoadedItemType', bound=CommonLoadedItem) - - -class CommonLoadedItemQueryRegistry(CommonService, HasLog, Generic[CommonLoadedItemType]): - """ Registry handling item queries. """ - - # noinspection PyMissingOrEmptyDocstring - @property - def mod_identity(self) -> CommonModIdentity: - raise NotImplementedError() - - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - raise NotImplementedError() - - def __init__(self) -> None: - super().__init__() - self._collecting = False - self.item_library = collections.defaultdict(set) - self.__item_organizers: List[CommonLoadedItemOrganizer] = list() - self._all: List[CommonLoadedItemType] = list() - self._total = 0 - self._total_valid = 0 - self._total_invalid = 0 - self._duplicates = 0 - - @property - def _registry(self) -> CommonLoadedItemRegistry: - raise NotImplementedError() - - @property - def _item_organizers(self) -> List[CommonLoadedItemOrganizer]: - return self.__item_organizers - - @property - def _item_name(self) -> str: - return 'item' - - @property - def collecting(self) -> bool: - """Determine if items are being collected.""" - return self._collecting - - @property - def item_library(self) -> Dict[Tuple[Any, Any], Set[str]]: - """ A library of items organized by filter keys. """ - return self._item_library - - @item_library.setter - def item_library(self, value: Dict[Tuple[Any, Any], Set[str]]): - self._item_library = value - - @property - def total(self) -> int: - """The total number of items that were looked at""" - return self._total - - @property - def total_invalid(self) -> int: - """The total number of items that were invalid.""" - return self._total_invalid - - @property - def total_valid(self) -> int: - """The total number of items that were valid.""" - return self._total_valid - - @property - def duplicates(self) -> int: - """The total number of items that were valid.""" - return self._duplicates - - def add_item_organizer( - self, - item_organizer_init: Callable[[Any], CommonLoadedItemOrganizer], - key_type: Any - ): - """ Add an item organizer. """ - self._item_organizers.append(item_organizer_init(key_type)) - - def has_items(self, requests: Tuple[CommonLoadedItemFilterRequest]) -> bool: - """ Determine if items exist for queries. """ - if self.log.enabled: - self.log.format_with_message(f'Checking if has {self._item_name}s', queries=requests) - for _ in self.get_items_gen(requests): - return True - return False - - def get_items_gen(self, requests: Tuple[CommonLoadedItemFilterRequest]) -> Iterator[CommonLoadedItemType]: - """ Retrieve items matching the requests. """ - if self.log.enabled: - self.log.format_with_message(f'Getting {self._item_name}s', requests=requests) - if self._collecting: - return tuple() - for request in requests: - yield from self._query_items(request, request.item_tests) - if self.verbose_log.enabled: - self.verbose_log.debug(f'Finished locating {self._item_name}s') - - def _run_tests(self, item: CommonLoadedItemType, item_tests: Iterator[CommonLoadedItemTest]) -> CommonTestResult: - for _item_test in item_tests: - _result = _item_test.test_item(item) - if not _result: - return _result - return CommonTestResult.TRUE - - def _query_items(self, request: CommonLoadedItemFilterRequest, item_tests: Iterator[CommonLoadedItemTest]) -> Iterator[CommonLoadedItemType]: - if self.log.enabled: - self.log.format_with_message(f'Querying for {self._item_name}s using query', query=request, item_tests=item_tests) - item_tests = tuple(item_tests) - all_keys = request.include_all_keys - any_keys = request.include_any_keys - exclude_keys = request.exclude_keys - match_at_least_one_key_sets = request.must_match_at_least_one_key_sets - found_item_identifiers = None - - def _convert_found_items(_found_identifiers: Set[str]) -> Iterator[CommonLoadedItemType]: - count = 0 - for _item_identifier in _found_identifiers: - _item = self._registry.locate_by_identifier(_item_identifier) - if _item is None: - continue - _passes_tests = self._run_tests(_item, item_tests) - if not _passes_tests: - if self.log.is_enabled: - self.log.format_with_message(f'{self._item_name} failed item test', item=_item.short_name, reason=_passes_tests.reason) - continue - count += 1 - yield _item - - if self.log.enabled: - self.log.debug(f'After item tests keys {count}') - - if self.log.enabled: - self.log.format_with_message('Using match_at_least_one_sets', match_at_least_one_sets=match_at_least_one_key_sets) - if match_at_least_one_key_sets: - self.verbose_log.format_with_message('Has match at least one sets.', match_at_least_one_sets=match_at_least_one_key_sets) - found_all_matching = False - for match_at_least_one_key_set in match_at_least_one_key_sets: - if self.log.enabled: - self.log.format_with_message('Attempting to locate a match for set.', match_at_least_one_set=match_at_least_one_key_set) - found_matching = False - total_matching_items = None - for match_at_least_one_key in match_at_least_one_key_set: - if match_at_least_one_key is None: - continue - if match_at_least_one_key.key not in self.item_library: - # One of the Match At Least One keys is not within the Item library! This means no Items pass the Match At Least One keys. - if self.log.enabled: - self.log.format_with_message(f'Match At Least One Key not found within the {self._item_name} library, meaning there are no {self._item_name}s available for it! Skipping this key.', key=match_at_least_one_key.key) - continue - new_found_items = self.item_library[match_at_least_one_key.key] - if total_matching_items is not None: - if self.log.enabled: - self.log.debug(f'Looking for key {match_at_least_one_key}') - before_intersect_match_at_least_one_count = len(total_matching_items) - self.log.format_with_message(f'Before intersect for match_at_least_one_keys {before_intersect_match_at_least_one_count}', match=match_at_least_one_key) - if len(new_found_items) != 0: - found_matching = True - new_found_items = total_matching_items | new_found_items - if self.log.enabled: - after_intersect_match_at_least_one_count = len(new_found_items) - self.log.format_with_message(f'After intersect for match_at_least_one_keys {after_intersect_match_at_least_one_count}', match=match_at_least_one_key) - total_matching_items = new_found_items - else: - if self.log.enabled: - new_found_match_at_least_one_count = len(new_found_items) - self.log.format_with_message(f'Found with match_at_least_one_keys {new_found_match_at_least_one_count}', match=match_at_least_one_key) - if new_found_items is not None and len(new_found_items) != 0: - found_matching = True - total_matching_items = new_found_items - - if not found_matching or not total_matching_items: - if self.log.enabled: - self.log.format_with_message(f'No {self._item_name}s found for match_at_least_one_set.', match_at_least_one_set=match_at_least_one_key_set) - return tuple() - self.verbose_log.format_with_message('Located a match for set, combining it with what currently exists.', match_at_least_one_set=match_at_least_one_key_set) - if found_item_identifiers is not None: - if self.log.enabled: - self.log.debug(f'Connecting set {match_at_least_one_key_set}') - total_count_before = len(total_matching_items) - self.log.debug(f'Before intersect for match_at_least_one_set {total_count_before}') - if len(total_matching_items) != 0: - found_all_matching = True - total_matching_items = found_item_identifiers & total_matching_items - if self.log.enabled: - total_count_after = len(total_matching_items) - self.log.debug(f'After intersect for match_at_least_one_set {total_count_after}') - found_item_identifiers = total_matching_items - else: - if self.log.enabled: - total_count_after = len(total_matching_items) - self.log.debug(f'Found with match_at_least_ones {total_count_after}') - if total_matching_items is not None and len(total_matching_items) != 0: - found_all_matching = True - found_item_identifiers = total_matching_items - if not found_all_matching: - if self.log.enabled: - self.log.format_with_message(f'No {self._item_name}s found for match_at_least_one_set', match_at_least_one_sets=match_at_least_one_key_sets) - return tuple() - - self.log.format_with_message('Using all_keys', all_keys=all_keys) - for include_all_key in all_keys: - if include_all_key is None: - continue - if include_all_key.key not in self.item_library: - # One of All keys is not within the item library! This means no items match ALL keys. - if self.log.enabled: - self.log.format_with_message(f'All Key not found within the {self._item_name} library, meaning there are no {self._item_name}s available for it! Skipping this key.', key=include_all_key.key) - return tuple() - new_found_items = self.item_library[include_all_key.key] - if found_item_identifiers is not None: - if self.log.enabled: - before_intersect_all_count = len(found_item_identifiers) - self.log.format_with_message(f'Before intersect for all_keys {before_intersect_all_count}', include_all_key=include_all_key) - new_found_items = found_item_identifiers & new_found_items - if self.log.enabled: - after_intersect_all_count = len(new_found_items) - self.log.format_with_message(f'After intersect for all_keys {after_intersect_all_count}', include_all_key=include_all_key) - else: - if self.log.enabled: - new_match_all_count = len(new_found_items) - self.log.format_with_message(f'Found with all_keys {new_match_all_count}', include_all_key=include_all_key) - - found_item_identifiers = new_found_items - - if found_item_identifiers is None and all_keys: - if self.log.enabled: - self.log.format_with_message(f'No {self._item_name}s found for all_keys.', all_keys=all_keys) - return tuple() - - if self.log.enabled: - after_all_keys = len(found_item_identifiers) if found_item_identifiers is not None else 0 - self.log.debug(f'After all_keys {after_all_keys}') - if self.verbose_log.enabled: - if found_item_identifiers is not None: - found_all_items: List[str] = list() - for anim_identifier in found_item_identifiers: - item = self._registry.locate_by_identifier(anim_identifier) - if item is None: - continue - found_all_items.append(item.short_name) - self.verbose_log.format_with_message(f'Found {self._item_name}s via all keys', items=found_all_items) - - self.log.format_with_message('Using any_keys', any_keys=any_keys) - found_items_via_any_keys = set() - for include_any_key in any_keys: - if include_any_key is None: - continue - if include_any_key.key not in self.item_library: - if self.log.enabled: - self.log.format_with_message(f'Any Key not found within the {self._item_name} library, meaning there are no {self._item_name}s available for it! Skipping this key.', key=include_any_key.key) - continue - found_items_via_any_keys = found_items_via_any_keys | self.item_library[include_any_key.key] - - if self.log.enabled: - found_any_keys_count = len(found_items_via_any_keys) if found_items_via_any_keys is not None else 0 - self.log.debug(f'Found {self._item_name}s via any {found_any_keys_count}') - - if self.verbose_log.enabled: - found_any_items: List[str] = list() - for anim_identifier in found_items_via_any_keys: - item = self._registry.locate_by_identifier(anim_identifier) - if item is None: - continue - found_any_items.append(item.short_name) - self.verbose_log.format_with_message(f'Found {self._item_name}s via any keys', items=found_any_items) - - if found_item_identifiers is None: - if self.log.enabled: - self.log.debug(f'No {self._item_name}s found for all_keys.') - if not all_keys: - self.log.debug('Returning any keys.') - yield from _convert_found_items(found_items_via_any_keys) - return tuple() - else: - query_type = request.query_type - if not any_keys and (query_type == CommonQueryMethodType.ALL_INTERSECT_ANY or query_type == CommonQueryMethodType.ALL_INTERSECT_ANY_MUST_HAVE_ONE): - query_type = CommonQueryMethodType.ALL_PLUS_ANY - if query_type == CommonQueryMethodType.ALL_PLUS_ANY: - found_item_identifiers = found_item_identifiers | found_items_via_any_keys - elif query_type == CommonQueryMethodType.ALL_INTERSECT_ANY: - found_item_identifiers = found_item_identifiers & found_items_via_any_keys - - if query_type == CommonQueryMethodType.ALL_PLUS_ANY_MUST_HAVE_ONE: - if not found_items_via_any_keys: - return tuple() - found_item_identifiers = found_item_identifiers | found_items_via_any_keys - elif query_type == CommonQueryMethodType.ALL_INTERSECT_ANY_MUST_HAVE_ONE: - if not found_items_via_any_keys: - return tuple() - found_item_identifiers = found_item_identifiers & found_items_via_any_keys - - if found_item_identifiers is None or not found_item_identifiers: - if self.log.enabled: - self.log.debug(f'No found {self._item_name}s after combining any keys. All Keys: {all_keys} Any Keys: {any_keys}') - return tuple() - - if self.log.enabled: - after_any_keys_count = len(found_item_identifiers) - self.log.debug(f'After any keys {after_any_keys_count}') - - self.log.format_with_message('Using exclude', exclude_keys=exclude_keys) - for exclude_key in exclude_keys: - if exclude_key is None: - continue - exclude_key = exclude_key.key - if exclude_key not in self.item_library: - continue - to_exclude_items = self.item_library[exclude_key] - if self.log.enabled: - before_found_item_count = len(found_item_identifiers) - before_to_exclude_item_count = len(to_exclude_items) - self.log.debug(f'Before exclude key {exclude_key} {before_found_item_count} to exclude {before_to_exclude_item_count}') - found_item_identifiers = found_item_identifiers - to_exclude_items - if self.log.enabled: - after_found_item_count = len(found_item_identifiers) - after_to_exclude_item_count = len(to_exclude_items) - self.log.debug(f'After exclude key {exclude_key} {after_found_item_count} to exclude {after_to_exclude_item_count}') - - if self.log.enabled: - after_exclude_item_count = len(found_item_identifiers) - self.log.debug(f'After exclude {after_exclude_item_count}') - stop_watch = CommonStopWatch() - stop_watch.start() - yield from _convert_found_items(found_item_identifiers) - - if self.log.enabled: - time_taken = CommonTextUtils.to_truncated_decimal(stop_watch.stop_milliseconds()) - self.log.format_with_message(f'Finished running loaded item tests in {time_taken}ms') - else: - stop_watch.stop() - - def get_all(self) -> Tuple[CommonLoadedItemType]: - """ Get all items. """ - if self._collecting: - return tuple() - return tuple(self._all) - - def _organize(self, items: Tuple[CommonLoadedItemType]): - if self.log.enabled: - self.log.debug(f'Collecting {self._item_name}s Query Data...') - self.item_library.clear() - new_item_library = dict() - item_organizers = tuple(self._item_organizers) - for item in items: - item.clear_cached_data() - if self.log.enabled: - self.log.format_with_message(f'Handling keys for {self._item_name}', item=item.short_name) - item_identifier = item.identifier - item_keys = list() - for item_organizer in item_organizers: - if not item_organizer.applies(item): - continue - item_key_type = item_organizer.key_type - for item_key_value in item_organizer.get_key_values(item): - item_key = (item_key_type, item_key_value) - item_keys.append(item_key) - if item_key not in new_item_library: - new_item_library[item_key] = set() - if item_identifier in new_item_library[item_key]: - continue - new_item_library[item_key].add(item_identifier) - if self.log.enabled: - self.log.format_with_message(f'Applied keys to {self._item_name}.', name=item.short_name, keys=item_keys) - - if self.log.enabled: - self.log.format_with_message(f'Completed collecting {self._item_name} Query Data.', item_library=new_item_library) - self.item_library = new_item_library - - def trigger_collection(self, show_loading_notification: bool = True) -> None: - """trigger_collection(show_loading_notification=True) - - Trigger the action code to collect all items and organize them by a number of keys. - - :param show_loading_notification: If set to True, the Loading Item's notification will be shown. If set to False, the Loading Item's notification will not be shown. Default is True. - :type show_loading_notification: bool, optional - """ - def _recollect_data() -> None: - try: - if not self._registry.loaded or self._registry.loading: - def _on_finished_loading() -> None: - self.trigger_collection(show_loading_notification=False) - - if show_loading_notification: - CommonBasicNotification( - self._loading_items_title(), - self._loading_items_description() - ).show() - self._registry.register_on_finished_loading_callback(_on_finished_loading) - self._registry.load() - return - - number_of_items = self._collect() - if number_of_items == -1: - return - CommonBasicNotification( - self._finished_loading_title(), - self._finished_loading_description(), - description_tokens=(str(self.total_valid), str(self.total), str(self.duplicates), str(self.total_invalid)) - ).show() - except Exception as ex: - self.log.error(f'Error occurred while collecting {self._item_name}s.', exception=ex) - finally: - self._collecting = False - - _recollect_data() - - def _collect(self) -> int: - if self._collecting: - return -1 - self._collecting = True - try: - # noinspection PyTypeChecker - self._all: Tuple[CommonLoadedItemType] = tuple(self._registry.loaded_items.values()) - self._total = self._registry.total - self._total_valid = self._registry.total_valid - self._total_invalid = self._registry.total_invalid - self._duplicates = self._registry.duplicates - self.log.format_with_message( - f'Loaded {self._item_name}s', - all_list=self._all - ) - enabled = self.log.enabled - self.log.enable() - after_load_time = CommonTextUtils.to_truncated_decimal(self._registry.total_time) - loaded_items_count = len(self._all) - self.log.debug(f'Took {after_load_time}ms to collect {loaded_items_count} {self._item_name}s.') - if not enabled: - self.log.disable() - stop_watch = CommonStopWatch() - stop_watch.start() - self._organize(self._all) - self._collecting = False - self.log.enable() - time_taken = CommonTextUtils.to_truncated_decimal(stop_watch.stop_milliseconds()) - after_organize_time = time_taken - found_count = len(self._all) - self.log.debug(f'Took {after_organize_time}ms to organize {found_count} {self._item_name}s') - if not enabled: - self.log.disable() - if self.log.enabled: - found_all_count = len(self._all) - self.log.debug(f'Loaded {found_all_count} {self._item_name}s.') - return len(self._all) - except Exception as ex: - self.log.error(f'Error occurred while collecting {self._item_name}s.', exception=ex) - return -1 - finally: - self._collecting = False - - @classmethod - def register_item_organizer(cls, key_type: Any) -> Callable[[Any], Any]: - """ Register an item organizer. """ - return cls()._register_item_organizer(key_type) - - def _register_item_organizer(self, key_type: Any) -> Callable[[Any], Any]: - def _method_wrapper(item_filter: Callable[[int], CommonLoadedItemOrganizer]): - self.add_item_organizer(item_filter, key_type) - return item_filter - return _method_wrapper - - @classmethod - def _should_show_finished_loading_notification(cls) -> bool: - return True - - @classmethod - def _finished_loading_title(cls) -> Union[int, str]: - raise NotImplementedError() - - @classmethod - def _finished_loading_description(cls) -> Union[int, str]: - raise NotImplementedError() - - @classmethod - def _loading_items_title(cls) -> Union[int, str]: - raise NotImplementedError() - - @classmethod - def _loading_items_description(cls) -> Union[int, str]: - raise NotImplementedError() - - @classmethod - def _load_items_on_zone_early_load(cls, event_data: S4CLZoneEarlyLoadEvent, show_loading_notification: bool = False): - if event_data.game_loaded: - # If the game is already loaded, we've already loaded the data once. - return False - cls().trigger_collection(show_loading_notification=show_loading_notification) - return True - - @classmethod - def _load_items_on_zone_late_load(cls, event_data: S4CLZoneLateLoadEvent, show_loading_notification: bool = True): - if event_data.game_loaded: - # If the game is already loaded, we've already loaded the data once. - return False - cls().trigger_collection(show_loading_notification=show_loading_notification) - return True - - @classmethod - def _notify_items_loaded_on_zone_late_load(cls, event_data: S4CLZoneLateLoadEvent): - if event_data.game_loaded: - # If the game is already loaded, we've already notified about the data once. - return False - if not cls().collecting and cls._should_show_finished_loading_notification(): - CommonBasicNotification( - cls._finished_loading_title(), - cls._finished_loading_description(), - description_tokens=(str(cls().total_valid), str(cls().total), str(cls().duplicates), str(cls().total_invalid)) - ).show() - return True - - @classmethod - def _show_item_loading_notification_on_first_update(cls) -> None: - if cls().collecting: - CommonBasicNotification( - cls._loading_items_title(), - cls._loading_items_description() - ).show() diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/common_loaded_item_registry.py b/Scripts/s4ap/sims4communitylib/systems/item_query/common_loaded_item_registry.py deleted file mode 100644 index 9caf626..0000000 --- a/Scripts/s4ap/sims4communitylib/systems/item_query/common_loaded_item_registry.py +++ /dev/null @@ -1,269 +0,0 @@ -""" -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 -""" -from threading import Thread -from typing import Iterator, Dict, List, Union, TypeVar, Generic, Tuple, Any - -from s4ap.sims4communitylib.systems.item_query.persistence.common_loaded_item_cache import CommonLoadedItemCache -from s4ap.sims4communitylib.systems.item_query.persistence.common_loaded_item_cache_service import \ - CommonLoadedItemCacheService -from s4ap.sims4communitylib.systems.item_query.item_loaders.common_base_item_loader import CommonBaseItemLoader -from s4ap.sims4communitylib.systems.item_query.dtos.common_loaded_item import CommonLoadedItem -from sims4.callback_utils import CallableList -from s4ap.sims4communitylib.classes.time.common_stop_watch import CommonStopWatch -from s4ap.sims4communitylib.logging.has_log import HasLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.services.common_service import CommonService - -CommonLoadedItemType = TypeVar('CommonLoadedItemType', bound=CommonLoadedItem) - - -class CommonLoadedItemRegistry(CommonService, HasLog, Generic[CommonLoadedItemType]): - """ A registry that contains loaded items. """ - - # noinspection PyMissingOrEmptyDocstring - @property - def mod_identity(self) -> CommonModIdentity: - raise NotImplementedError() - - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - raise NotImplementedError() - - def __init__(self) -> None: - super().__init__() - self._loaded = False - self.item_loaders = list() - self.loaded_items = None - self._total = 0 - self._total_valid = 0 - self._total_invalid = 0 - self._total_time = 0.0 - self._duplicates = 0 - self._loading = False - self._load_thread: Union[Thread, None] = None - self._on_finished_loading_callback = CallableList() - - @property - def loaded(self) -> bool: - """True, if the registry has finished loading.""" - return self._loaded - - @property - def loading(self) -> bool: - """True, if the registry is currently loading.""" - return self._loading - - @property - def total(self) -> int: - """The total number of items that were found""" - return self._total - - @property - def total_invalid(self) -> int: - """The total number of items that were invalid.""" - return self._total_invalid - - @property - def total_valid(self) -> int: - """The total number of items that were valid.""" - return self._total_valid - - @property - def item_loaders(self) -> List[CommonBaseItemLoader]: - """Loaders that load items.""" - return self._item_loaders - - @property - def duplicates(self) -> int: - """The total number of duplicate items that were found.""" - return self._duplicates - - @property - def total_time(self) -> float: - """The total time the registry took to load in milliseconds.""" - return self._total_time - - @item_loaders.setter - def item_loaders(self, value: List[CommonBaseItemLoader]): - self._item_loaders = value - - def register_on_finished_loading_callback(self, callback) -> None: - """Finished loading callback.""" - if callback not in self._on_finished_loading_callback: - self._on_finished_loading_callback.append(callback) - - @property - def loaded_items(self) -> Dict[str, CommonLoadedItemType]: - """A library of items organized by their identifiers.""" - return self._loaded_items - - @loaded_items.setter - def loaded_items(self, value: Dict[str, CommonLoadedItemType]): - self._loaded_items = value - - def add_item_loader(self, item_loader: CommonBaseItemLoader) -> bool: - """ Add a loader of items. """ - if item_loader in self.item_loaders: - return False - self.item_loaders.append(item_loader) - return True - - def add_item(self, item: CommonLoadedItemType) -> bool: - """add_item(item) - - Add an Item to the registry. - - :param item: An instance of an Item - :type item: CommonLoadedItemType - :return: True, if the item was successfully added. False, if not. - :rtype: bool - """ - if not self.loaded or self.loading: - def _add_on_finished_loading() -> None: - _unique_id = item.identifier - if _unique_id in self.loaded_items: - return - self.loaded_items[_unique_id] = item - return - - self.register_on_finished_loading_callback(_add_on_finished_loading) - self.load() - return True - unique_id = item.identifier - if unique_id in self.loaded_items: - return False - self.loaded_items[unique_id] = item - return True - - def load(self) -> None: - """ Load data. """ - if self._loaded or self._loading: - self.log.format_with_message('Not loading because already loaded.', loaded=self._loaded, loading=self._loading) - return - try: - self._loading = True - - should_use_cache = self._should_use_cache() - - stop_watch = CommonStopWatch() - stop_watch.start() - self._total_time = 0.0 - self._total = 0 - self._total_valid = 0 - self._total_invalid = 0 - items_library: Dict[str, CommonLoadedItemType] = dict() - if not should_use_cache or self._update_cache(): - self.log.debug(f'Clearing {self.__class__.__name__} cache.') - self._clear_cache() - - loaded_items_cache = self._load_from_cache() - if should_use_cache and loaded_items_cache is not None: - items: Tuple[CommonLoadedItem, ...] = loaded_items_cache.cached_objects - self._total = len(items) - self._total_valid = self._total - should_verify = True - else: - items: Tuple[CommonLoadedItem, ...] = tuple(self._load()) - cache_service = self._get_cache_service() - if cache_service is not None: - self._save_to_cache(cache_service.create_cache(items, self._get_checksums())) - should_verify = False - - self._duplicates = 0 - for item in items: - if should_verify and not item.verify(): - self._total_valid -= 1 - self._total_invalid += 1 - continue - identifier = item.identifier - if identifier in items_library: - self._duplicates += 1 - self._total_valid -= 1 - continue - self._add_additional_item_data(item) - items_library[identifier] = item - - self.loaded_items = items_library - self._loaded = True - self._load_thread = None - self._loading = False - self._total_time = stop_watch.stop_milliseconds() - self._on_finished_loading_callback() - self._on_finished_loading_callback.clear() - self.log.debug('Finished loading items.') - except Exception as ex: - self.log.error('Error occurred while loading items.', exception=ex) - - def _should_use_cache(self) -> bool: - return True - - def _save_to_cache(self, item_cache: CommonLoadedItemCache[CommonLoadedItemType]): - cache_service = self._get_cache_service() - if cache_service is None: - return - return cache_service.save_to_cache(item_cache) - - def _load_from_cache(self) -> Union[CommonLoadedItemCache[CommonLoadedItemType], None]: - cache_service = self._get_cache_service() - if cache_service is None: - return - return cache_service.load_from_cache() - - def _clear_cache(self) -> None: - cache_service = self._get_cache_service() - if cache_service is None: - return - return cache_service.clear_cache() - - def _get_cache_service(self) -> Union[CommonLoadedItemCacheService[CommonLoadedItemType], None]: - return None - - def locate_by_identifier(self, identifier: str) -> Union[CommonLoadedItemType, None]: - """Locate an item by an identifier.""" - if identifier is None: - return None - return self.loaded_items.get(identifier, None) - - def _get_checksums(self) -> Tuple[Any]: - checksums: List[Any] = list() - for item_loader in self.item_loaders: - for new_checksum_data in item_loader.get_checksum_data_gen(): - checksums.append(new_checksum_data) - return tuple(checksums) - - def _update_cache(self) -> bool: - cache_service = self._get_cache_service() - if cache_service is None: - self.log.debug(f'No cache service found. {self.__class__.__name__}') - return False - for item_loader in self.item_loaders: - for new_checksum_data in item_loader.get_checksum_data_gen(): - if cache_service.cache_needs_update(new_checksum_data): - self.log.debug(f'Found a checksum that was different. {self.__class__.__name__} {new_checksum_data}') - return True - self.log.debug(f'Cache does not need update. {self.__class__.__name__}') - return False - - def _load(self) -> Iterator[CommonLoadedItemType]: - total_invalid = 0 - total_valid = 0 - for item_loader in self.item_loaders: - for item in item_loader.load(): - if item is None: - total_valid -= 1 - total_invalid += 1 - continue - yield item - self.log.format_with_message('Done loading for loader.', loader=item_loader) - self._total += item_loader.total - self._total_valid += item_loader.total_valid + total_valid - self._total_invalid += item_loader.total_invalid + total_invalid - - def _add_additional_item_data(self, item: CommonLoadedItemType) -> None: - raise NotImplementedError() diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/dtos/__init__.py b/Scripts/s4ap/sims4communitylib/systems/item_query/dtos/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/systems/item_query/dtos/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/dtos/common_loaded_item.py b/Scripts/s4ap/sims4communitylib/systems/item_query/dtos/common_loaded_item.py deleted file mode 100644 index 4ca9ac9..0000000 --- a/Scripts/s4ap/sims4communitylib/systems/item_query/dtos/common_loaded_item.py +++ /dev/null @@ -1,198 +0,0 @@ -""" -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 -""" -from typing import Union, Tuple, Any, Set, Iterator, Dict, Type - -from s4ap.sims4communitylib.classes.serialization.common_serializable import CommonSerializable -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.logging.has_class_log import HasClassLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.utils.common_log_registry import CommonLog - - -class CommonLoadedItem(CommonSerializable, HasClassLog): - """ Contains information about an item that was loaded from a Snippet. """ - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - raise NotImplementedError() - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - raise NotImplementedError() - - def __init__( - self, - tags: Set[Any], - is_original: bool = False - ): - super().__init__() - HasClassLog.__init__(self) - self._tags = tuple(tags) - if is_original: - self._original = self - else: - self._original = self.clone() - self.is_original = is_original - # These are set to None initially to prevent the item from not being able to find them. - self._identifier = None - self._identifiers_backwards_compatible = None - self._identifier = self._get_identifier().lower().strip() - self._identifiers_backwards_compatible = tuple([identifier.lower().strip() for identifier in self._get_backwards_compatible_identifiers()]) - - @property - def original(self) -> 'CommonLoadedItem': - """The original unmodified item.""" - return self._original - - @property - def identifier(self) -> str: - """ The identifier of the item. """ - return self._identifier - - @property - def identifiers_backwards_compatible(self) -> Tuple[str]: - """ The backwards compatible identifier of the item. """ - return self._identifiers_backwards_compatible - - def _get_backwards_compatible_identifiers(self) -> Tuple[str]: - """Create a collection of old hashed identifiers for the item, in case the original identifier changes.""" - return tuple() - - def _get_identifier(self) -> str: - """ Creates a hashed identifier for the item. """ - raise NotImplementedError() - - @property - def short_name(self) -> str: - """ A short name for the item. """ - return self.identifier - - @property - def is_available(self) -> bool: - """Determine if the item is available.""" - return True - - @property - def tags(self) -> Tuple[Any]: - """ A collection of tags that apply to the item. """ - return self._tags - - @tags.setter - def tags(self, value: Iterator[Any]): - self._tags = tuple(value) - - def has_tag(self, tag: Any) -> bool: - """ Determine if the item has a tag. """ - return tag in self.tags - - def has_any_tags(self, tags: Iterator[Any]) -> CommonTestResult: - """ Determine if the item has any of the specified tags. """ - for tag in tags: - if self.has_tag(tag): - return CommonTestResult(True, reason=f'Has tag {tag}') - tags_text = ', '.join([str(tag) for tag in tags]) - return CommonTestResult(False, reason=f'Missing tags {tags_text}') - - def has_all_tags(self, tags: Iterator[Any]) -> CommonTestResult: - """ Determine if the item has all the specified tags. """ - for tag in tags: - if not self.has_tag(tag): - return CommonTestResult(False, reason=f'Missing tag {tag}') - return CommonTestResult.TRUE - - def add_tag(self, tag: Any): - """ Add a tag to the item. """ - new_tags = list(self._tags) - if tag not in new_tags: - new_tags.append(tag) - self._tags = tuple(new_tags) - - def add_tags(self, tags: Iterator[Any]): - """ Add tags to the item. """ - new_tags = list(self._tags) - for tag in tags: - if tag not in new_tags: - new_tags.append(tag) - self._tags = tuple(new_tags) - - def replace_tag(self, tag_to_remove: Any, tag_to_add: Any): - """ Replace one tag with another on the item. """ - self.remove_tags((tag_to_remove,)) - self.add_tags((tag_to_add,)) - - def remove_tag(self, tag: Any): - """ Remove a tag from the item. """ - return self.remove_tags((tag, )) - - def remove_tags(self, tags: Iterator[Any]): - """ Remove tags from the item. """ - new_tags = list(self._tags) - for tag in tags: - if tag in new_tags: - new_tags.remove(tag) - self._tags = tuple(new_tags) - - def verify(self) -> CommonTestResult: - """Verify the item.""" - raise NotImplementedError() - - def clone(self) -> 'CommonLoadedItem': - """Clone the item.""" - raise NotImplementedError() - - def __eq__(self, other: 'CommonLoadedItem') -> bool: - if not isinstance(other, CommonLoadedItem): - return False - return self.identifier == other.identifier - - def __hash__(self) -> int: - return hash((str(self.identifier),)) - - def __repr__(self) -> str: - tags_str = ', '.join((tag.name if hasattr(tag, 'name') else tag for tag in self.tags)) - return f'ID: {self.identifier}' \ - f'\nTags: ({tags_str})' - - def __str__(self) -> str: - return self.__repr__() - - @classmethod - def load_from_package( - cls, - package_item: Any, - tuning_name: str, - log: CommonLog - ) -> Union['CommonLoadedItem', None]: - """load_from_package(package_item, tuning_name, log) - - Load an item from a package. - - :param package_item: A package item. - :type package_item: Any - :param tuning_name: The name of the tuning being read from. - :type tuning_name: str - :param log: A log for warnings. - :type log: CommonLog - :return: An item or None if an error occurs. - :rtype: Union[CommonLoadedItem, None] - """ - raise NotImplementedError() - - def clear_cached_data(self) -> None: - """Clear cached data.""" - pass - - # noinspection PyMissingOrEmptyDocstring - def serialize(self: 'CommonLoadedItem') -> Union[str, Dict[str, Any]]: - raise NotImplementedError() - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def deserialize(cls: Type['CommonLoadedItem'], data: Union[str, Dict[str, Any]]) -> Union['CommonLoadedItem', None]: - raise NotImplementedError() diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/enums/__init__.py b/Scripts/s4ap/sims4communitylib/systems/item_query/enums/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/systems/item_query/enums/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/enums/common_query_method_type.py b/Scripts/s4ap/sims4communitylib/systems/item_query/enums/common_query_method_type.py deleted file mode 100644 index aa770af..0000000 --- a/Scripts/s4ap/sims4communitylib/systems/item_query/enums/common_query_method_type.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt - - -class CommonQueryMethodType(CommonInt): - """ Various methods to query for items. """ - ALL_PLUS_ANY: 'CommonQueryMethodType' = ... - ALL_INTERSECT_ANY: 'CommonQueryMethodType' = ... - ALL_PLUS_ANY_MUST_HAVE_ONE: 'CommonQueryMethodType' = ... - ALL_INTERSECT_ANY_MUST_HAVE_ONE: 'CommonQueryMethodType' = ... diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/item_loaders/__init__.py b/Scripts/s4ap/sims4communitylib/systems/item_query/item_loaders/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/systems/item_query/item_loaders/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/item_loaders/common_base_item_loader.py b/Scripts/s4ap/sims4communitylib/systems/item_query/item_loaders/common_base_item_loader.py deleted file mode 100644 index 72efc0c..0000000 --- a/Scripts/s4ap/sims4communitylib/systems/item_query/item_loaders/common_base_item_loader.py +++ /dev/null @@ -1,106 +0,0 @@ -""" -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 -""" -from typing import Tuple, Iterator, Any, Union, TypeVar, Generic - -from s4ap.sims4communitylib.systems.item_query.dtos.common_loaded_item import CommonLoadedItem -from sims4.resources import Types -from s4ap.sims4communitylib.logging.has_log import HasLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.services.common_service import CommonService -from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils - -CommonLoadedItemType = TypeVar('CommonLoadedItemType', bound=CommonLoadedItem) - - -class CommonBaseItemLoader(CommonService, HasLog, Generic[CommonLoadedItemType]): - """ Loads items. """ - - # noinspection PyMissingOrEmptyDocstring - @property - def mod_identity(self) -> CommonModIdentity: - raise NotImplementedError() - - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - raise NotImplementedError() - - @property - def snippet_names(self) -> Tuple[str]: - """ The names of snippets containing items. """ - raise NotImplementedError() - - def __init__(self) -> None: - super().__init__() - self._total = 0 - self._total_valid = 0 - self._total_invalid = 0 - - @property - def total(self) -> int: - """The total number of items that were looked at""" - return self._total - - @property - def total_valid(self) -> int: - """The total number of items that were valid.""" - return self._total_valid - - @property - def total_invalid(self) -> int: - """The total number of items that were invalid.""" - return self._total_invalid - - def get_checksum_data_gen(self) -> Iterator[Tuple[str, int, int]]: - """Generate checksums.""" - raise NotImplementedError() - - def load(self) -> Iterator[CommonLoadedItemType]: - """load() - - Loads all items. - - :return: An iterator of the valid items. - :rtype: Iterator[Any] - """ - self._total = 0 - self._total_valid = 0 - self._total_invalid = 0 - snippet_names: Tuple[str] = self.snippet_names - for item_package in CommonResourceUtils.load_instances_with_any_tags(Types.SNIPPET, snippet_names): - tuning_name = item_package.__name__ - try: - items = tuple(self._load(item_package, tuning_name)) - - total = 0 - total_valid = 0 - total_invalid = 0 - - for item in items: - total += 1 - - if item is None: - total_invalid += 1 - continue - verify_result = item.verify() - if verify_result: - total_valid += 1 - yield item - else: - self.log.warn(f'{item.short_name} was not valid. Reason: {verify_result}') - total_invalid += 1 - - self._total += total - self._total_valid += total_valid - self._total_invalid += total_invalid - self.log.warn(f'Loaded {tuning_name}, Valid: {total_valid}, Total Invalid: {total_invalid}, Total: {total}') - except Exception as ex: - self.log.error(f'An error occurred while parsing items from snippet \'{tuning_name}\'', exception=ex) - - def _load(self, package_item: Any, tuning_name: str) -> Tuple[Union[CommonLoadedItemType, None]]: - raise NotImplementedError() diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/item_tests/__init__.py b/Scripts/s4ap/sims4communitylib/systems/item_query/item_tests/__init__.py deleted file mode 100644 index 3251898..0000000 --- a/Scripts/s4ap/sims4communitylib/systems/item_query/item_tests/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" \ No newline at end of file diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/item_tests/common_loaded_item_is_available_test.py b/Scripts/s4ap/sims4communitylib/systems/item_query/item_tests/common_loaded_item_is_available_test.py deleted file mode 100644 index cebe621..0000000 --- a/Scripts/s4ap/sims4communitylib/systems/item_query/item_tests/common_loaded_item_is_available_test.py +++ /dev/null @@ -1,32 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.systems.item_query.dtos.common_loaded_item import CommonLoadedItem -from s4ap.sims4communitylib.systems.item_query.item_tests.common_loaded_item_test import CommonLoadedItemTest -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo - - -class CommonLoadedItemIsAvailableTest(CommonLoadedItemTest[CommonLoadedItem]): - """ Test for an item is available. """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - return ModInfo.get_identity() - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 'common_loaded_item_is_available' - - # noinspection PyMissingOrEmptyDocstring - def test_item(self, item: CommonLoadedItem) -> CommonTestResult: - if not item.is_available: - return CommonTestResult(False, reason='Item is not available.') - return CommonTestResult.TRUE diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/item_tests/common_loaded_item_is_not_available_test.py b/Scripts/s4ap/sims4communitylib/systems/item_query/item_tests/common_loaded_item_is_not_available_test.py deleted file mode 100644 index 41467b3..0000000 --- a/Scripts/s4ap/sims4communitylib/systems/item_query/item_tests/common_loaded_item_is_not_available_test.py +++ /dev/null @@ -1,32 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.systems.item_query.dtos.common_loaded_item import CommonLoadedItem -from s4ap.sims4communitylib.systems.item_query.item_tests.common_loaded_item_test import CommonLoadedItemTest -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo - - -class CommonLoadedItemIsNotAvailableTest(CommonLoadedItemTest[CommonLoadedItem]): - """ Test for an item to not be available. """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - return ModInfo.get_identity() - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 'common_loaded_item_is_not_available' - - # noinspection PyMissingOrEmptyDocstring - def test_item(self, item: CommonLoadedItem) -> CommonTestResult: - if item.is_available: - return CommonTestResult(False, reason='Item is available.') - return CommonTestResult.TRUE diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/item_tests/common_loaded_item_test.py b/Scripts/s4ap/sims4communitylib/systems/item_query/item_tests/common_loaded_item_test.py deleted file mode 100644 index aecfd22..0000000 --- a/Scripts/s4ap/sims4communitylib/systems/item_query/item_tests/common_loaded_item_test.py +++ /dev/null @@ -1,34 +0,0 @@ -""" -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 -""" -from typing import TypeVar, Generic - -from s4ap.sims4communitylib.systems.item_query.dtos.common_loaded_item import CommonLoadedItem -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.logging.has_class_log import HasClassLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity - - -CommonLoadedItemType = TypeVar('CommonLoadedItemType', bound=CommonLoadedItem) - - -class CommonLoadedItemTest(HasClassLog, Generic[CommonLoadedItemType]): - """ A test that is run to test a loaded item. """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - raise NotImplementedError() - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - raise NotImplementedError() - - def test_item(self, item: CommonLoadedItemType) -> CommonTestResult: - """Test an item for a match.""" - raise NotImplementedError() diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/persistence/__init__.py b/Scripts/s4ap/sims4communitylib/systems/item_query/persistence/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/systems/item_query/persistence/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/persistence/common_loaded_item_cache.py b/Scripts/s4ap/sims4communitylib/systems/item_query/persistence/common_loaded_item_cache.py deleted file mode 100644 index ee4b9f4..0000000 --- a/Scripts/s4ap/sims4communitylib/systems/item_query/persistence/common_loaded_item_cache.py +++ /dev/null @@ -1,18 +0,0 @@ -""" -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 -""" -from typing import TypeVar, Generic - -from s4ap.sims4communitylib.systems.item_query.dtos.common_loaded_item import CommonLoadedItem -from s4ap.sims4communitylib.systems.caching.common_serializable_object_cache import CommonSerializableObjectCache - -CommonLoadedItemCacheType = TypeVar('CommonLoadedItemCacheType', bound=CommonLoadedItem) - - -class CommonLoadedItemCache(CommonSerializableObjectCache[CommonLoadedItemCacheType], Generic[CommonLoadedItemCacheType]): - """A cache of Loaded Items.""" - pass diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/persistence/common_loaded_item_cache_service.py b/Scripts/s4ap/sims4communitylib/systems/item_query/persistence/common_loaded_item_cache_service.py deleted file mode 100644 index 8bdd353..0000000 --- a/Scripts/s4ap/sims4communitylib/systems/item_query/persistence/common_loaded_item_cache_service.py +++ /dev/null @@ -1,45 +0,0 @@ -""" -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 -""" -from typing import Generic, TypeVar, Tuple, Union, Dict, Any - -from s4ap.sims4communitylib.systems.item_query.dtos.common_loaded_item import CommonLoadedItem -from s4ap.sims4communitylib.systems.item_query.persistence.common_loaded_item_cache import CommonLoadedItemCache -from s4ap.sims4communitylib.systems.caching.common_serializable_object_cache_service import \ - CommonSerializableObjectCacheService -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity - - -CommonLoadedItemCacheType = TypeVar('CommonLoadedItemCacheType', bound=CommonLoadedItemCache[CommonLoadedItem]) - - -class CommonLoadedItemCacheService(CommonSerializableObjectCacheService[CommonLoadedItemCacheType], Generic[CommonLoadedItemCacheType]): - """A service that manages a cache of Loaded Items.""" - - # noinspection PyMissingOrEmptyDocstring - @property - def mod_identity(self) -> CommonModIdentity: - raise NotImplementedError() - - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - return 'common_loaded_item_cache_service' - - @property - def _cache_file_name(self) -> str: - raise NotImplementedError() - - def _deserialize_cache(self, data: Union[str, Dict[str, Any]]) -> CommonLoadedItemCacheType: - raise NotImplementedError() - - # noinspection PyMissingOrEmptyDocstring - def create_cache(self, objects: Tuple[CommonLoadedItem], checksums: Tuple[Any]) -> CommonLoadedItemCacheType: - checksum_data = dict() - for (snippet_name, snippet_id, checksum_value) in checksums: - checksum_data[f'{snippet_name}-{snippet_id}'] = checksum_value - return CommonLoadedItemCacheType[Any](objects, checksum_data) diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/query/__init__.py b/Scripts/s4ap/sims4communitylib/systems/item_query/query/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/systems/item_query/query/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_filter.py b/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_filter.py deleted file mode 100644 index 6d0c32c..0000000 --- a/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_filter.py +++ /dev/null @@ -1,93 +0,0 @@ -""" -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 -""" -from typing import Tuple, Union, TypeVar, Generic - -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt -from s4ap.sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags -from s4ap.sims4communitylib.systems.item_query.query.common_loaded_item_key import CommonLoadedItemKey -from s4ap.sims4communitylib.logging.has_log import HasLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity - -ItemKeyType = TypeVar('ItemKeyType', int, CommonInt, CommonIntFlags) - - -class CommonLoadedItemFilter(HasLog, Generic[ItemKeyType]): - """ A filter for use when querying loaded items. """ - - # noinspection PyMissingOrEmptyDocstring - @property - def mod_identity(self) -> CommonModIdentity: - raise NotImplementedError() - - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - raise NotImplementedError() - - def __init__( - self, - match_all: bool, - match_at_least_one: bool = False, - exclude: bool = False, - key_type: ItemKeyType = None - ): - super().__init__() - self._match_all = match_all - self._match_at_least_one = match_at_least_one - self._exclude = exclude - self._key_type = key_type - - @property - def _match_text(self) -> str: - match_text = '' - if self.match_all and not self.exclude: - match_text = 'has all' - if self.match_at_least_one and not self.exclude: - match_text = 'has any' - if self.exclude: - match_text = 'has none' - return match_text - - @property - def key_type(self) -> Union[ItemKeyType, None]: - """ The type of keys produced by this filter. """ - return self._key_type - - @property - def match_all(self) -> bool: - """ - Determine if we should match all (True) the keys or any (False) of them. - """ - return self._match_all - - @property - def exclude(self) -> bool: - """ - Determine if we should not have any of the keys. - """ - return self._exclude - - @property - def match_at_least_one(self) -> bool: - """ - Determine if we should match at least one key. - """ - return self._match_at_least_one - - def get_keys(self) -> Tuple[CommonLoadedItemKey]: - """ Retrieve the keys of this filter. """ - return tuple() - - def __repr__(self) -> str: - return self.__str__() - - def __str__(self) -> str: - match_text = self._match_text - if self._key_type is None: - return f'{self.__class__.__name__}, {match_text}' - return f'{self._key_type.name}, {match_text}' diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_filter_request.py b/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_filter_request.py deleted file mode 100644 index 388105e..0000000 --- a/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_filter_request.py +++ /dev/null @@ -1,131 +0,0 @@ -""" -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 -""" -from pprint import pformat -from typing import Tuple, Callable, List, TypeVar, Generic, Iterator - -from s4ap.sims4communitylib.systems.item_query.enums.common_query_method_type import CommonQueryMethodType -from s4ap.sims4communitylib.systems.item_query.item_tests.common_loaded_item_test import CommonLoadedItemTest -from s4ap.sims4communitylib.systems.item_query.query.common_loaded_item_key import CommonLoadedItemKey -from s4ap.sims4communitylib.systems.item_query.query.common_loaded_item_filter import CommonLoadedItemFilter - -CommonLoadedItemFilterType = TypeVar('CommonLoadedItemFilterType', bound=CommonLoadedItemFilter) -CommonLoadedItemTestType = TypeVar('CommonLoadedItemTestType', bound=CommonLoadedItemTest) -CommonLoadedItemKeyType = TypeVar('CommonLoadedItemKeyType', bound=CommonLoadedItemKey) - - -class CommonLoadedItemFilterRequest(Generic[CommonLoadedItemFilterType, CommonLoadedItemTestType, CommonLoadedItemKeyType]): - """ A request used to locate things. """ - def __init__( - self, - item_filters: Iterator[CommonLoadedItemFilterType], - item_tests: Iterator[CommonLoadedItemTestType], - query_type: CommonQueryMethodType = CommonQueryMethodType.ALL_INTERSECT_ANY - ): - self._item_filters = tuple(item_filters) - self._item_tests = tuple(item_tests) - self._query_type = query_type - self._include_all_keys = None - self._include_any_keys = None - self._exclude_keys = None - self._must_match_at_least_one_key_sets = None - - @property - def query_type(self) -> CommonQueryMethodType: - """ The method used to query items. """ - return self._query_type - - @property - def item_tests(self) -> Tuple[CommonLoadedItemTestType]: - """Tests to run on items.""" - return self._item_tests - - @property - def item_filters(self) -> Tuple[CommonLoadedItemFilterType]: - """Filters used to filter items.""" - return self._item_filters - - @property - def include_all_keys(self) -> Tuple[CommonLoadedItemKeyType]: - """ Must have all these keys to match. """ - if self._include_all_keys is not None: - return self._include_all_keys - - def _include_item_filter(_item_filter: CommonLoadedItemFilterType) -> bool: - return _item_filter.match_all and not _item_filter.exclude - - self._include_all_keys = self._get_item_keys(_include_item_filter) - return self._include_all_keys - - @property - def include_any_keys(self) -> Tuple[CommonLoadedItemKeyType]: - """ Must have any of these keys to match. """ - if self._include_any_keys is not None: - return self._include_any_keys - - def _include_item_filter(_item_filter: CommonLoadedItemFilterType) -> bool: - return not _item_filter.match_all and not _item_filter.exclude and not _item_filter.match_at_least_one - - self._include_any_keys = self._get_item_keys(_include_item_filter) - return self._include_any_keys - - @property - def exclude_keys(self) -> Tuple[CommonLoadedItemKeyType]: - """ Must NOT have any of these keys to match. """ - if self._exclude_keys is not None: - return self._exclude_keys - - def _include_item_filter(_item_filter: CommonLoadedItemFilterType) -> bool: - return _item_filter.exclude - - self._exclude_keys = self._get_item_keys(_include_item_filter) - return self._exclude_keys - - @property - def must_match_at_least_one_key_sets(self) -> Tuple[Tuple[CommonLoadedItemKeyType]]: - """ Must match at least one of these keys. """ - if self._must_match_at_least_one_key_sets is not None: - return self._must_match_at_least_one_key_sets - - def _get_match_at_least_one_item_filter_sets() -> Tuple[Tuple[CommonLoadedItemKeyType]]: - item_keys: List[Tuple[CommonLoadedItemKeyType]] = list() - for _item_filter in self._item_filters: - if _item_filter.exclude or not _item_filter.match_at_least_one: - continue - item_keys.append(_item_filter.get_keys()) - return tuple(item_keys) - - self._must_match_at_least_one_key_sets = _get_match_at_least_one_item_filter_sets() - return self._must_match_at_least_one_key_sets - - def _get_item_keys(self, include_item_filter_callback: Callable[[CommonLoadedItemFilterType], bool]) -> Tuple[CommonLoadedItemKeyType]: - item_keys: List[CommonLoadedItemKeyType] = [] - for _item_filter in self._item_filters: - if not include_item_filter_callback(_item_filter): - continue - for item_key in _item_filter.get_keys(): - item_keys.append(item_key) - return tuple(item_keys) - - def __repr__(self) -> str: - return '{}:\n' \ - 'Include All: {}\n' \ - 'Include Any: {}\n' \ - 'Exclude All: {}\n' \ - 'Match One Sets: {}\n' \ - 'Query Type: {}'\ - .format( - self.__class__.__name__, - pformat(self.include_all_keys), - pformat(self.include_any_keys), - pformat(self.exclude_keys), - pformat(self.must_match_at_least_one_key_sets), - pformat(self.query_type) - ) - - def __str__(self) -> str: - return self.__repr__() diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_key.py b/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_key.py deleted file mode 100644 index a0e4b9d..0000000 --- a/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_key.py +++ /dev/null @@ -1,42 +0,0 @@ -""" -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 -""" -from typing import Any, Tuple, TypeVar, Generic - -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt -from s4ap.sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags - -ItemKeyType = TypeVar('ItemKeyType', int, CommonInt, CommonIntFlags) - - -class CommonLoadedItemKey(Generic[ItemKeyType]): - """ A key for a loaded item. """ - def __init__(self, key_type: ItemKeyType, value: Any): - self._key_type = key_type - self._value = value - self._key = (key_type, value) - - @property - def key_type(self) -> ItemKeyType: - """ The type of key. """ - return self._key_type - - @property - def value(self) -> Any: - """ The value. """ - return self._value - - @property - def key(self) -> Tuple[ItemKeyType, Any]: - """ The combination of the type and value. """ - return self._key - - def __repr__(self) -> str: - return str(self.key) - - def __str__(self) -> str: - return self.__repr__() diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_organizer.py b/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_organizer.py deleted file mode 100644 index 3cd0fd1..0000000 --- a/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_organizer.py +++ /dev/null @@ -1,35 +0,0 @@ -""" -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 -""" -from typing import Any, Tuple, Generic, TypeVar - -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt -from s4ap.sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags -from s4ap.sims4communitylib.systems.item_query.dtos.common_loaded_item import CommonLoadedItem - -CommonLoadedItemKeyType = TypeVar('CommonLoadedItemKeyType', int, CommonInt, CommonIntFlags) -CommonLoadedItemType = TypeVar('CommonLoadedItemType', bound=CommonLoadedItem) - - -class CommonLoadedItemOrganizer(Generic[CommonLoadedItemKeyType, CommonLoadedItemType]): - """ An organizer of items. """ - def __init__(self, key_type: CommonLoadedItemKeyType): - self._key_type = key_type - - @property - def key_type(self) -> CommonLoadedItemKeyType: - """ The type of keys this organizer produces. """ - return self._key_type - - def get_key_values(self, item: CommonLoadedItemType) -> Tuple[Any]: - """ Retrieve key values for this organizer. """ - raise NotImplementedError - - # noinspection PyUnusedLocal - def applies(self, item: CommonLoadedItemType) -> bool: - """ Determine if this organizer applies to an item. """ - return True diff --git a/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_query_utils.py b/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_query_utils.py deleted file mode 100644 index 0d23f04..0000000 --- a/Scripts/s4ap/sims4communitylib/systems/item_query/query/common_loaded_item_query_utils.py +++ /dev/null @@ -1,160 +0,0 @@ -""" -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 -""" -import random -from typing import Tuple, Iterator, Union, Generic, TypeVar - -from s4ap.sims4communitylib.systems.item_query.item_tests.common_loaded_item_test import CommonLoadedItemTest -from s4ap.sims4communitylib.systems.item_query.item_tests.common_loaded_item_is_available_test import \ - CommonLoadedItemIsAvailableTest -from s4ap.sims4communitylib.systems.item_query.query.common_loaded_item_filter import CommonLoadedItemFilter - -from s4ap.sims4communitylib.systems.item_query.enums.common_query_method_type import CommonQueryMethodType -from s4ap.sims4communitylib.systems.item_query.dtos.common_loaded_item import CommonLoadedItem -from s4ap.sims4communitylib.systems.item_query.common_loaded_item_query_registry import CommonLoadedItemQueryRegistry -from s4ap.sims4communitylib.logging.has_log import HasLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.systems.item_query.query.common_loaded_item_filter_request import CommonLoadedItemFilterRequest - -CommonLoadedItemType = TypeVar('CommonLoadedItemType', bound=CommonLoadedItem) - - -class CommonLoadedItemQueryUtils(HasLog, Generic[CommonLoadedItemType]): - """ Query for items using various filter configurations. """ - - # noinspection PyMissingOrEmptyDocstring - @property - def mod_identity(self) -> CommonModIdentity: - raise NotImplementedError() - - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - raise NotImplementedError() - - @property - def _query_registry(self) -> CommonLoadedItemQueryRegistry: - raise NotImplementedError() - - def get_all(self) -> Tuple[CommonLoadedItemType]: - """ Get all items. """ - return self._query_registry.get_all() - - def locate_by_identifier(self, identifier: str) -> Union[CommonLoadedItemType, None]: - """ Locate a CAS Part by its identifier. """ - return self._query_registry._registry.locate_by_identifier(identifier) - - def create_filter_request( - self, - item_filters: Tuple[CommonLoadedItemFilter], - item_tests: Iterator[CommonLoadedItemTest], - query_type: CommonQueryMethodType = CommonQueryMethodType.ALL_INTERSECT_ANY - ) -> CommonLoadedItemFilterRequest: - """ Create a filter request for items. """ - return CommonLoadedItemFilterRequest(item_filters, item_tests, query_type=query_type) - - def has_for_filters( - self, - item_filters: Tuple[CommonLoadedItemFilter], - item_tests: Iterator[CommonLoadedItemTest], - query_type: CommonQueryMethodType = CommonQueryMethodType.ALL_INTERSECT_ANY - ) -> bool: - """Determine if any items are available that match filters.""" - filter_request = self.create_filter_request(item_filters, item_tests, query_type=query_type) - return self._query_registry.has_items((filter_request, )) - - def get_for_filters_gen( - self, - item_filters: Tuple[CommonLoadedItemFilter], - item_tests: Iterator[CommonLoadedItemTest], - query_type: CommonQueryMethodType = CommonQueryMethodType.ALL_INTERSECT_ANY - ) -> Iterator[CommonLoadedItemType]: - """ Get all items matching filters. """ - self.log.format_with_message( - 'Getting items that match filters', - item_filters=item_filters, - item_tests=item_tests, - query_type=query_type - ) - filter_request = self.create_filter_request(item_filters, item_tests, query_type=query_type) - query_result = self._query_registry.get_items_gen((filter_request,)) - had_items = False - for item in query_result: - had_items = True - yield item - if not had_items: - self.log.debug('No items found matching filters.') - - def get_random_for_filters( - self, - item_filters: Tuple[CommonLoadedItemFilter], - item_tests: Tuple[CommonLoadedItemTest], - query_type: CommonQueryMethodType = CommonQueryMethodType.ALL_INTERSECT_ANY - ) -> Union[CommonLoadedItemType, None]: - """Get a random item that matches filters.""" - if not self.has_for_filters( - item_filters, - item_tests, - query_type=query_type - ): - return None - - items = tuple(self.get_for_filters_gen( - item_filters, - item_tests, - query_type=query_type - )) - if not items: - return None - return random.choice(items) - - def has_available_for_filters( - self, - item_filters: Tuple[CommonLoadedItemFilter], - item_tests: Iterator[CommonLoadedItemTest], - query_type: CommonQueryMethodType = CommonQueryMethodType.ALL_INTERSECT_ANY - ) -> bool: - """Determine if any items are available that match filters and are marked as being available.""" - item_tests: Tuple[CommonLoadedItemTest, ...] = ( - CommonLoadedItemIsAvailableTest(), - *item_tests - ) - return self.has_for_filters( - item_filters, - item_tests, - query_type=query_type - ) - - def get_available_for_filters_gen( - self, - item_filters: Tuple[CommonLoadedItemFilter], - item_tests: Tuple[CommonLoadedItemTest], - query_type: CommonQueryMethodType = CommonQueryMethodType.ALL_INTERSECT_ANY - ) -> Iterator[CommonLoadedItemType]: - """Get all items matching filters that are marked as being available.""" - item_tests: Tuple[CommonLoadedItemTest, ...] = ( - CommonLoadedItemIsAvailableTest(), - *item_tests - ) - yield from self.get_for_filters_gen( - item_filters, - item_tests, - query_type=query_type - ) - - def get_random_from_available_for_filters( - self, - item_filters: Tuple[CommonLoadedItemFilter], - item_tests: Tuple[CommonLoadedItemTest], - query_type: CommonQueryMethodType = CommonQueryMethodType.ALL_INTERSECT_ANY - ) -> Union[CommonLoadedItemType, None]: - """Get a random item that matches filters and is marked as being available.""" - item_tests: Tuple[CommonLoadedItemTest, ...] = ( - CommonLoadedItemIsAvailableTest(), - *item_tests - ) - return self.get_random_for_filters(item_filters, item_tests, query_type=query_type) diff --git a/Scripts/s4ap/sims4communitylib/systems/settings/__init__.py b/Scripts/s4ap/sims4communitylib/systems/settings/__init__.py deleted file mode 100644 index 3251898..0000000 --- a/Scripts/s4ap/sims4communitylib/systems/settings/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" \ No newline at end of file diff --git a/Scripts/s4ap/sims4communitylib/systems/settings/common_setting_utils.py b/Scripts/s4ap/sims4communitylib/systems/settings/common_setting_utils.py deleted file mode 100644 index c912548..0000000 --- a/Scripts/s4ap/sims4communitylib/systems/settings/common_setting_utils.py +++ /dev/null @@ -1,112 +0,0 @@ -""" -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 -""" -from typing import Any, Tuple, Callable, TypeVar, Type, Generic - -from s4ap.sims4communitylib.classes.enums.common_versioned_enum_value_collection import CommonVersionedEnumValueCollection -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt -from s4ap.sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags -from s4ap.sims4communitylib.enums.enumtypes.common_versioned_int import CommonVersionedInt -from s4ap.sims4communitylib.enums.enumtypes.common_versioned_int_flags import CommonVersionedIntFlags -from s4ap.sims4communitylib.systems.settings.common_settings_data_store import CommonSettingsDataStore -from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils - -SettingEnumType = TypeVar('SettingEnumType', CommonInt, CommonIntFlags, CommonVersionedInt, CommonVersionedIntFlags) -SettingDataStoreType = TypeVar('SettingDataStoreType', bound=CommonSettingsDataStore) -SettingEnumValueCollectionType = TypeVar('SettingEnumValueCollectionType', bound=CommonVersionedEnumValueCollection) - - -class CommonSettingUtils(Generic[SettingDataStoreType]): - """ Utilities for settings. """ - @classmethod - def get_enum_tuple_setting(cls, key: str, enum_type: Type[SettingEnumType], invalid_enum_value: SettingEnumType) -> Tuple[SettingEnumType]: - """ Retrieve a setting that is a collection of enum values. """ - result: Tuple[SettingEnumType] = cls._get_tuple_enum_value(key, enum_type, invalid_enum_value) - return result - - @classmethod - def set_enum_tuple_setting(cls, key: str, value: Tuple[SettingEnumType]): - """ Set a setting that is a collection of enum values. """ - cls._set_tuple_enum_value(key, value) - - @classmethod - def get_enum_value_collection_setting(cls, key: str, enum_value_collection_type: Type[SettingEnumValueCollectionType]) -> SettingEnumValueCollectionType: - """ Retrieve an enum value collection setting. """ - result: SettingEnumValueCollectionType = cls._get_enum_value_collection(key, enum_value_collection_type) - return result - - @classmethod - def set_enum_value_collection_setting(cls, key: str, value: SettingEnumValueCollectionType): - """ Set an enum value collection setting. """ - cls._set_enum_value_collection(key, value) - - @classmethod - def _get_enum_value_collection(cls, key: str, enum_value_collection_type: Type[SettingEnumValueCollectionType]) -> SettingEnumValueCollectionType: - enum_value_collection = cls.get_value( - key, - encode=lambda _enum_data: _enum_data.serialize(), - decode=lambda _enum_data: enum_value_collection_type.deserialize(_enum_data) or cls._data_store().get_default_value_by_key(key) - ) - if not enum_value_collection: - return cls._data_store().get_default_value_by_key(key) - return enum_value_collection - - @classmethod - def _set_enum_value_collection(cls, key: str, value: SettingEnumValueCollectionType) -> None: - cls.set_value( - key, - value, - encode=lambda _enum_value: _enum_value.serialize(), - ) - - @classmethod - def _get_enum_value(cls, key: str, enum_type: Type[SettingEnumType], invalid_enum_value: SettingEnumType) -> SettingEnumType: - return cls.get_value( - key, - encode=lambda _enum_val: _enum_val.name, - decode=lambda _enum_str: CommonResourceUtils.get_enum_by_name(_enum_str, enum_type, default_value=invalid_enum_value) - ) - - @classmethod - def _set_enum_value(cls, key: str, value: SettingEnumType): - return cls.set_value( - key, - value, - encode=lambda _enum_val: _enum_val.name, - ) - - @classmethod - def _get_tuple_enum_value(cls, key: str, enum_type: Type[SettingEnumType], invalid_enum_value: SettingEnumType) -> Tuple[SettingEnumType]: - enum_val_list = cls.get_value( - key, - encode=lambda _enum_val_list: [_enum_val.name if hasattr(_enum_val, 'name') else _enum_val for _enum_val in _enum_val_list], - decode=lambda _str_val_list: [CommonResourceUtils.get_enum_by_name(enum_str, enum_type, default_value=invalid_enum_value) if isinstance(enum_str, str) else enum_str for enum_str in _str_val_list] - ) - result: Tuple[SettingEnumType, ...] = tuple([enum_val for enum_val in enum_val_list if enum_val != invalid_enum_value]) - return result - - @classmethod - def _set_tuple_enum_value(cls, key: str, value: Tuple[SettingEnumType]) -> None: - cls.set_value( - key, - value, - encode=lambda _enum_list: [enum_value.name for enum_value in _enum_list], - ) - - @classmethod - def get_value(cls, key: str, encode: Callable[[Any], Any] = None, decode: Callable[[Any], Any] = None) -> Any: - """Get a value using an encoding and decoding.""" - return cls._data_store().get_value_by_key(key, encode=encode, decode=decode) - - @classmethod - def set_value(cls, key: str, value: Any, encode: Callable[[Any], Any] = None) -> Any: - """Set a value using an encoding and decoding.""" - return cls._data_store().set_value_by_key(key, value, encode=encode) - - @classmethod - def _data_store(cls) -> SettingDataStoreType: - raise NotImplementedError() diff --git a/Scripts/s4ap/sims4communitylib/systems/settings/common_settings_data_manager.py b/Scripts/s4ap/sims4communitylib/systems/settings/common_settings_data_manager.py deleted file mode 100644 index 60b4df5..0000000 --- a/Scripts/s4ap/sims4communitylib/systems/settings/common_settings_data_manager.py +++ /dev/null @@ -1,41 +0,0 @@ -""" -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 -""" -from typing import Tuple -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.persistence.data_management.common_data_manager import CommonDataManager -from s4ap.sims4communitylib.persistence.persistence_services.common_persistence_service import CommonPersistenceService - - -class CommonSettingsDataManager(CommonDataManager): - """ Manage a storage of settings data. """ - @classmethod - def get_identifier(cls) -> str: - """Retrieve the identifier of the data manager. This identifier is used in the name of the settings file.""" - if hasattr(cls, 'IDENTIFIER'): - return cls.IDENTIFIER - raise NotImplementedError() - - # noinspection PyMissingOrEmptyDocstring - @property - def mod_identity(self) -> CommonModIdentity: - raise NotImplementedError() - - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - raise NotImplementedError() - - # noinspection PyMissingOrEmptyDocstring - @property - def persistence_services(self) -> Tuple[CommonPersistenceService]: - from s4ap.sims4communitylib.persistence.persistence_services.common_file_persistence_service import \ - CommonFilePersistenceService - result: Tuple[CommonPersistenceService] = ( - CommonFilePersistenceService(per_save=False), - ) - return result diff --git a/Scripts/s4ap/sims4communitylib/systems/settings/common_settings_data_manager_utils.py b/Scripts/s4ap/sims4communitylib/systems/settings/common_settings_data_manager_utils.py deleted file mode 100644 index 1620f13..0000000 --- a/Scripts/s4ap/sims4communitylib/systems/settings/common_settings_data_manager_utils.py +++ /dev/null @@ -1,61 +0,0 @@ -""" -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 -""" -from typing import Type, Union, Dict, Any, TypeVar - -from s4ap.sims4communitylib.logging.has_log import HasLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.persistence.data_management.common_data_manager_registry import CommonDataManagerRegistry -from s4ap.sims4communitylib.persistence.data_stores.common_data_store import CommonDataStore -from s4ap.sims4communitylib.services.common_service import CommonService -from s4ap.sims4communitylib.systems.settings.common_settings_data_manager import CommonSettingsDataManager - -CommonDataStoreType = TypeVar('CommonDataStoreType', bound=CommonDataStore) - - -class CommonSettingsDataManagerUtils(CommonService, HasLog): - """ Utilities to manage settings data. """ - - # noinspection PyMissingOrEmptyDocstring - @property - def mod_identity(self) -> CommonModIdentity: - raise NotImplementedError() - - # noinspection PyMissingOrEmptyDocstring - @property - def log_identifier(self) -> str: - raise NotImplementedError() - - @property - def _data_manager_type(self) -> Type[CommonSettingsDataManager]: - raise NotImplementedError() - - def __init__(self) -> None: - super().__init__() - self.__data_manager: Union[CommonSettingsDataManager, None] = None - - @property - def _data_manager(self) -> CommonSettingsDataManager: - """ The data manager containing data. """ - if self.__data_manager is None: - self.__data_manager = CommonDataManagerRegistry().locate_data_manager(self.mod_identity, identifier=self._data_manager_type.get_identifier()) - return self.__data_manager - - def _get_data_store(self, data_store_type: Type[CommonDataStoreType]) -> Union[CommonDataStoreType, None]: - return self._data_manager.get_data_store_by_type(data_store_type) - - def get_all_data(self) -> Dict[str, Dict[str, Any]]: - """ Get all data. """ - return self._data_manager._data_store_data - - def save(self) -> bool: - """ Save data. """ - return self._data_manager.save() - - def reset(self, prevent_save: bool = False) -> bool: - """ Reset data. """ - return self._data_manager.remove_all_data(prevent_save=prevent_save) diff --git a/Scripts/s4ap/sims4communitylib/systems/settings/common_settings_data_store.py b/Scripts/s4ap/sims4communitylib/systems/settings/common_settings_data_store.py deleted file mode 100644 index 9de1ec3..0000000 --- a/Scripts/s4ap/sims4communitylib/systems/settings/common_settings_data_store.py +++ /dev/null @@ -1,35 +0,0 @@ -""" -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 -""" -from typing import Any, Dict - -from s4ap.sims4communitylib.persistence.data_stores.common_data_store import CommonDataStore - - -class CommonSettingsDataStore(CommonDataStore): - """ Manages main settings for CM. """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_identifier(cls) -> str: - raise NotImplementedError() - - @property - def _version(self) -> int: - """This version indicates the current version of the default data. Changing this value will cause all settings to be wiped and replaced with the default data.""" - raise NotImplementedError() - - @property - def _default_data(self) -> Dict[str, Any]: - """ The data used as a default for the settings. """ - return { - self.__class__._VERSION: self._version, - **self._build_default_data() - }.copy() - - def _build_default_data(self) -> Dict[str, Any]: - raise NotImplementedError() diff --git a/Scripts/s4ap/sims4communitylib/testing/__init__.py b/Scripts/s4ap/sims4communitylib/testing/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/testing/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/testing/common_assertion_utils.py b/Scripts/s4ap/sims4communitylib/testing/common_assertion_utils.py deleted file mode 100644 index 6b7bd64..0000000 --- a/Scripts/s4ap/sims4communitylib/testing/common_assertion_utils.py +++ /dev/null @@ -1,282 +0,0 @@ -""" -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 -""" -from typing import Any, List, Union, Tuple, Callable, Dict - -from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.utils.common_collection_utils import CommonCollectionUtils - - -class CommonAssertionUtils: - """Utilities for used to assert within tests. They can be used outside tests if need be. - - """ - @staticmethod - def are_equal(value_one: Any, value_two: Any, message: str='') -> bool: - """are_equal(value_one, value_two, message='') - - Assert two values are equal to each other. - - If the values are both collections, then the values contained within will be asserted to be equal. - - .. note:: The order of the values in each collection is asserted. - - :param value_one: The first value. - :type value_one: Any - :param value_two: The second value. - :type value_two: Any - :param message: A custom message to include when the assertion fails. Default is Empty String. - :type message: str, optional - :return: True, if the assertion succeeds. - :rtype: bool - :exception AssertionError: when the assertion fails. - """ - if CommonCollectionUtils.is_collection(value_one) or CommonCollectionUtils.is_collection(value_two): - return CommonAssertionUtils.lists_are_equal(value_one, value_two, message=message) - if value_one != value_two: - raise AssertionError(f'{message}: expected\n {value_one}\n to be equal to\n {value_two}') - return True - - @staticmethod - def are_similar(value_one: Any, value_two: Any, message: str='') -> bool: - """are_similar(value_one, value_two, message='') - - Assert two values are similar. - - If the values are both collections, then the values contained within will be asserted to be similar. - - .. note:: The order of the values in each collection is ignored. - - :param value_one: The first value. - :type value_one: Any - :param value_two: The second value. - :type value_two: Any - :param message: A custom message to include when the assertion fails. Default is Empty String. - :type message: str, optional - :return: True, if the assertion succeeds. - :rtype: bool - :exception AssertionError: when the assertion fails. - """ - if CommonCollectionUtils.is_collection(value_one) or CommonCollectionUtils.is_collection(value_two): - return CommonAssertionUtils.list_contents_are_same(value_one, value_two, message=message) - if value_one != value_two: - raise AssertionError(f'{message}: expected\n {value_one}\n to be similar to\n {value_two}') - return True - - @staticmethod - def lists_are_equal(list_one: Union[Tuple[Any], List[Any]], list_two: Union[Tuple[Any], List[Any]], message: str='') -> bool: - """lists_are_equal(list_one, list_two, message='') - - Assert two collections contain tbe exact same values. - - .. note:: The order of the values in each collection will be asserted. - - :param list_one: The first value. (Can be any collection type) - :type list_one: Union[Tuple[Any], List[Any]] - :param list_two: The second value. (Can be any collection type) - :type list_two: Union[Tuple[Any], List[Any]] - :param message: A custom message to include when the assertion fails. Default is Empty String. - :type message: str, optional - :return: True, if the assertion succeeds. - :rtype: bool - :exception AssertionError: when the assertion fails. - """ - if not CommonCollectionUtils.is_collection(list_one): - raise AssertionError(f'{message}: expected\n {list_one}\n to be equal to\n {list_two}') - if not CommonCollectionUtils.is_collection(list_two): - raise AssertionError(f'{message}: expected\n {list_one}\n to be equal to\n {list_two}') - if len(list_one) != len(list_two): - raise AssertionError(f'{message}: expected\n {list_one}\n to be equal to\n {list_two}') - if isinstance(list_one, set) or isinstance(list_two, set): - return list_one == list_two - current_idx = 0 - while current_idx < len(list_one): - item_one = list_one[current_idx] - item_two = list_two[current_idx] - if item_one != item_two: - raise AssertionError(f'{message}: expected\n {list_one}\n to be equal to\n {list_two}\n Difference:\n {item_one}\n should be\n {item_two}\n at index {current_idx}') - current_idx += 1 - return True - - @staticmethod - def list_contents_are_same(list_one: Union[Tuple[Any], List[Any]], list_two: Union[Tuple[Any], List[Any]], message: str='') -> bool: - """list_contents_are_same(list_one, list_two, message='') - - Assert the values contained within two collections are the same. - - .. note:: The order of the values in each collection is ignored. - - :param list_one: The first value. (Can be any collection type) - :type list_one: Union[Tuple[Any], List[Any]] - :param list_two: The second value. (Can be any collection type) - :type list_two: Union[Tuple[Any], List[Any]] - :param message: A custom message to include when the assertion fails. Default is Empty String. - :type message: str, optional - :return: True, if the assertion succeeds. - :rtype: bool - :exception AssertionError: when the assertion fails. - """ - if not CommonCollectionUtils.is_collection(list_one): - raise AssertionError(f'{message}: {list_one} is not a collection') - if not CommonCollectionUtils.is_collection(list_two): - raise AssertionError(f'{message}: {list_two} is not a collection') - if len(list_one) != len(list_two): - raise AssertionError(f'{message}: expected\n {list_one}\n to be equal to\n {list_two}') - for item_one in list_one: - if item_one not in list_two: - raise AssertionError(f'{message}: expected\n {list_one}\n contents to be equal to\n {list_two}\n {item_one} not found in\n {list_two}') - for item_one in list_two: - if item_one not in list_one: - raise AssertionError(f'{message}: expected\n {list_one}\n contents to be equal to\n {list_two}\n {item_one} not found in\n {list_one}') - return True - - @staticmethod - def is_true(value: Union[bool, CommonTestResult, CommonExecutionResult], message: str='') -> bool: - """is_true(value, message='') - - Assert a value is True. - - :param value: The value being asserted. - :type value: Union[bool, CommonTestResult, CommonExecutionResult] - :param message: A custom message to include when the assertion fails. Default is Empty String. - :type message: str, optional - :return: True if the value is True. - :rtype: bool - :exception AssertionError: when the assertion fails. - """ - if isinstance(value, CommonTestResult) or isinstance(value, CommonExecutionResult): - if value.result is not True: - raise AssertionError(f'{message} {value.reason}: expected True, but was {value.result}') - return True - if value is not True: - raise AssertionError(f'{message}: expected True, but was {value}') - return True - - @staticmethod - def is_false(value: Union[bool, CommonTestResult, CommonExecutionResult], message: str='') -> bool: - """is_false(value, message='') - - Assert value is False. - - :param value: The value being asserted. - :type value: Union[bool, CommonTestResult, CommonExecutionResult] - :param message: A custom message to include when the assertion fails. - :type message: str, optional - :return: True if the value is False. - :rtype: bool - :exception AssertionError: when the assertion fails. - """ - if isinstance(value, CommonTestResult) or isinstance(value, CommonExecutionResult): - if value.result is not False: - raise AssertionError(f'{message} {value.reason}: expected False, but was {value.result}') - return True - if value is not False: - raise AssertionError(f'{message}: expected False, but was {value}') - return True - - @staticmethod - def has_length(value: Union[Tuple[Any], List[Any]], expected_length: int, message: str='') -> bool: - """has_length(value, expected_length, message='') - - Assert a collection has the specified length. - - :param value: The collection being asserted. (Any collection that works with `len()` can be used) - :type value: Union[Tuple[Any], List[Any]] - :param expected_length: The length expected of the collection. - :type expected_length: int - :param message: A custom message to include when the assertion fails. Default is Empty String. - :type message: str, optional - :return: True if the length matches. - :rtype: bool - :exception AssertionError: when the assertion fails. - """ - if not CommonCollectionUtils.is_collection(value): - raise AssertionError(f'{message}: expected collection {value} to have length {expected_length}, but was not a collection') - if len(value) != expected_length: - raise AssertionError(f'{message}: expected collection {value} to have length {expected_length}, but was {len(value)}') - return True - - @staticmethod - def contains(collection: Union[Tuple[Any], List[Any], Dict[Any, Any]], value: Any, message: str='') -> bool: - """contains(collection, value, message='') - - Assert a value is contained within a collection - - :param collection: The collection being checked (Any collection that works with `len()` can be used) - :type collection: Union[Tuple[Any], List[Any], Dict[Any, Any]] - :param value: The value being located. - :type value: Any - :param message: A custom message to include when the assertion fails. Default is Empty String. - :type message: str, optional - :return: True, if the value is contained within the collection. False, if it is not. - :rtype: bool - :exception AssertionError: when the assertion fails. - """ - if value not in collection: - raise AssertionError(f'{message}: expected {collection} to contain {value}, but it did not.') - return True - - @staticmethod - def not_contains(collection: Union[Tuple[Any], List[Any], Dict[Any, Any]], value: Any, message: str='') -> bool: - """not_contains(collection, value, message='') - - Assert a value is NOT contained within a collection - - :param collection: The collection being checked (Any collection that works with `len()` can be used) - :type collection: Union[Tuple[Any], List[Any], Dict[Any, Any]] - :param value: The value being located. - :type value: Any - :param message: A custom message to include when the assertion fails. Default is Empty String. - :type message: str, optional - :return: True, if the value is NOT contained within the collection. False, if it is. - :rtype: bool - :exception AssertionError: when the assertion fails. - """ - if value in collection: - raise AssertionError(f'{message}: expected {collection} to not contain {value}, but it did.') - return True - - @staticmethod - def throws(callback: Callable[..., Any], message: str='') -> Exception: - """throws(callback, message='') - - Assert calling a function will raise an Exception. - - :param callback: The function to invoke. - :type callback: Callable[..., Any] - :param message: A custom message to include when the assertion fails. Default is Empty String. - :type message: str, optional - :return: The exception that was thrown. - :rtype: Exception - :exception AssertionError: when the assertion fails. - """ - try: - callback() - except Exception as ex: - return ex - raise AssertionError(f'{message}: expected function to throw an exception, but it did not.') - - @staticmethod - def not_throws(callback: Callable[..., Any], message: str='') -> bool: - """not_throws(callback, message='') - - Assert calling a function will not raise an Exception. - - :param callback: The function to invoke. - :type callback: Callable[..., Any] - :param message: A custom message to include when the assertion fails. Default is Empty String. - :type message: str, optional - :return: True, if the assertion was successful. - :rtype: bool - :exception AssertionError: when the assertion fails. - """ - try: - callback() - except Exception as ex: - raise AssertionError(f'{message}: expected function to not throw an exception, but it did. Exception: {ex}') - return True diff --git a/Scripts/s4ap/sims4communitylib/testing/common_test_service.py b/Scripts/s4ap/sims4communitylib/testing/common_test_service.py deleted file mode 100644 index 9c752e0..0000000 --- a/Scripts/s4ap/sims4communitylib/testing/common_test_service.py +++ /dev/null @@ -1,345 +0,0 @@ -""" -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 -""" -from typing import Callable, Any, Dict, List, Union, Tuple -from functools import wraps -from traceback import format_exc -from s4ap.sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.common_service import CommonService -# This try catch is here for when tests are being run via PyCharm rather than from in-game. -try: - from s4ap.sims4communitylib.utils.common_log_registry import CommonLogRegistry - - community_test_log_log = CommonLogRegistry().register_log(ModInfo.get_identity(), 'community_test_log') - community_test_log_log.enable() - - def _community_test_log(val: str): - community_test_log_log.debug(val) -except ModuleNotFoundError: - # noinspection PyMissingOrEmptyDocstring - class CommonLogRegistry: - - @classmethod - def get(cls, *_, **__) -> 'CommonLogRegistry': - pass - - def register_log(self) -> None: - pass - - def _community_test_log(_: str): - pass - - -class CommonTestResultType: - """Use to identify the results of running a test. - - """ - FAILED = 'FAILED' - SUCCESS = 'SUCCESS' - - -class CommonTestService(CommonService): - """Use to register and run python tests. - - :Example Test Registration: - - .. highlight:: python - .. code-block:: python - - @CommonTestService.test_class('mod_name') - class TestClass: - # Important that it is a static method, you won't get a cls or self value passed in, so don't expect one! - @staticmethod - @CommonTestService.test(1, 1, expected_value=2) - @CommonTestService.test(2, 1, expected_value=3) - def example_add_test(one: int, two: int, expected_value: int=24): - result = one + two - CommonAssertionUtils.are_equal(result, expected_value, message='{} plus {} did not equal {}!'.format(one, two, expected_value)) - - """ - def __init__(self) -> None: - self._tests_by_mod_identity = dict() - self._test_count = 0 - - def add_test(self, mod_identity: CommonModIdentity, test_name: str, test_function: Callable[..., Any], class_name: str=None): - """add_test(mod_identity, test_name, test_function, class_name=None) - - Register a test with the specified name and class name. - - :param mod_identity: The identity of the mod the test is for. - :type mod_identity: CommonModIdentity - :param test_name: The name of the test. - :type test_name: str - :param test_function: The test itself. - :type test_function: Callable[..., Any] - :param class_name: The name of the class the test is contained within. - :type class_name: str - """ - if class_name is None: - class_name = 'generic' - else: - class_name = class_name.lower() - class_tests_by_name = self.get_test_library_by_mod(mod_identity) - class_tests = class_tests_by_name.get(class_name, list()) - class_tests.append((test_name, test_function)) - self._test_count += 1 - class_tests_by_name[class_name] = class_tests - self._tests_by_mod_identity[mod_identity] = class_tests_by_name - - @property - def total_test_count(self) -> int: - """Get a count of the number of tests. - - :return: The number of registered tests. - :rtype: int - """ - return self._test_count - - @property - def all_tests(self) -> Dict[str, Dict[str, Any]]: - """Get all registered tests. - - :return: A dictionary of tests by mod name. - :rtype: Dict[str, Dict[str, Any]] - """ - return self._tests_by_mod_identity - - def get_tests_by_class_name(self, class_name: str) -> List[Any]: - """get_tests_by_class_name(class_name) - - Retrieve tests by their class name. - - :param class_name: The name of the class to locate tests for. - :type class_name: str - :return: A list of tests matching the class name. - :rtype: List[Any] - """ - class_tests = list() - for (_, class_tests_by_class_name) in self._tests_by_mod_identity.items(): - class_tests.extend(class_tests_by_class_name.get(class_name, list())) - return class_tests - - def get_test_library_by_mod(self, mod_identifier: Union[str, CommonModIdentity]) -> Dict[str, Any]: - """get_test_library_by_mod(mod_identifier) - - Retrieve a library of tests for a Mod organized by class name. - - :param mod_identifier: The name or identity of the mod to search tests for. - :param mod_identifier: Union[str, CommonModIdentity] - :return: A library of tests for the specified Mod organized by class name. - :rtype: Dict[str, Any] - """ - from s4ap.sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils - mod_name = CommonModIdentityUtils.determine_mod_name_from_identifier(mod_identifier, include_version=False).lower() - for (mod_identity, tests_by_class_name) in self._tests_by_mod_identity.items(): - lower_mod_name = CommonModIdentityUtils.determine_mod_name_from_identifier(mod_identity, include_version=False).lower() - if lower_mod_name == mod_name: - return tests_by_class_name - return dict() - - def get_tests_by_mod_name(self, mod_identifier: Union[str, CommonModIdentity]) -> Tuple[Any]: - """get_tests_by_mod_name(mod_name) - - Retrieve tests by a mod name. - - :param mod_identifier: The name or identity of the mod that owns the tests within the class. - :param mod_identifier: Union[str, CommonModIdentity] - :return: A collection of tests for the specified Mod. - :rtype: Tuple[Any] - """ - from s4ap.sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils - mod_name = CommonModIdentityUtils.determine_mod_name_from_identifier(mod_identifier, include_version=False).lower() - class_tests_by_class_name = self._tests_by_mod_identity.get(mod_name, dict()) - all_tests: List[Any] = list() - for (_, tests) in class_tests_by_class_name.items(): - all_tests.extend(tests) - return tuple(all_tests) - - @classmethod - def _format_test_result(cls, test_result: str, test_name: str, stacktrace: str=None): - return 'TEST {}: {} {}\n'.format(test_result, test_name, stacktrace or '') - - @staticmethod - def test_class(mod_identity: CommonModIdentity) -> Any: - """test_class(mod_identity) - - Decorate a class with this to register a class as containing tests. - - :param mod_identity: The identity of the mod that owns the tests within the class. - :param mod_identity: CommonModIdentity - :return: A class wrapped to run tests. - :rtype: Any - """ - @CommonExceptionHandler.catch_exceptions(mod_identity) - def _inner_test_class(cls) -> Any: - name_of_class = cls.__name__ - if CommonLogRegistry is not None: - cls.test_log_log = CommonLogRegistry().register_log(mod_identity, name_of_class) - cls.test_log_log.enable() - cls.test_log = lambda val: cls.test_log_log.debug(val) - else: - cls.test_log = lambda val: print(val) - for method_name in dir(cls): - method = getattr(cls, method_name) - if not hasattr(method, 'is_test'): - continue - - def _test_function(class_name, test_name, test_method, *_, **__) -> None: - @wraps(test_method) - def _wrapper(*args, **kwargs) -> str: - arguments = (_ + args) - new_test_name = '{} (Arguments: {}, Keyword Arguments: {})'.format(test_name, arguments, (kwargs, __)) - # noinspection PyBroadException - try: - test_method(*(_ + args), **kwargs, **__) - cls.test_log(CommonTestService._format_test_result(CommonTestResultType.SUCCESS, new_test_name)) - except AssertionError: - cls.test_log(CommonTestService._format_test_result(CommonTestResultType.FAILED, new_test_name, stacktrace=format_exc())) - return CommonTestResultType.FAILED - except Exception: - cls.test_log(CommonTestService._format_test_result(CommonTestResultType.FAILED, new_test_name, stacktrace=format_exc())) - return CommonTestResultType.FAILED - return CommonTestResultType.SUCCESS - CommonTestService.get().add_test(mod_identity, test_name, _wrapper, class_name=class_name) - if hasattr(method, 'test_parameters') and len(method.test_parameters) > 0: - idx = 1 - for test_args, test_kwargs in method.test_parameters: - _test_function(name_of_class, '{} {}'.format(method_name, str(idx)), method, *test_args, **test_kwargs) - idx += 1 - else: - _test_function(name_of_class, method_name, method) - return cls - return _inner_test_class - - @staticmethod - def test(*args, **kwargs) -> Callable[..., Any]: - """test(args, kwargs) - - Decorate a function with this to register that function as a test. - When the test is run, it will be sent the specified arguments and keyword arguments. - - .. warning:: The function being registered MUST be a staticmethod. - - :param args: The arguments that will be sent to the function upon run. - :type args: Any - :param kwargs: The keyword arguments that will be sent to the function upon run. - :type kwargs: Any - :return: A function wrapped to run a test upon invocation. - :rtype: Callable[..., Any] - """ - def _test_func(test_function) -> Any: - test_function.is_test = True - if not hasattr(test_function, 'test_parameters'): - test_function.test_parameters = list() - test_function.test_parameters.append((args, kwargs)) - return test_function - return _test_func - - def run_tests(self, class_names: Tuple[str]=tuple(), callback: Callable[..., Any]=print): - """run_tests(class_names=tuple(), callback=print) - - Run all tests for the specified classes names. - - :param class_names: A collection of classes to run tests for. - :type class_names: Tuple[str] - :param callback: Any time a message needs to be printed or logged, it will be sent to this callback. Default is print. - :type callback: Callable[str, Any] - """ - return self._run_tests(mod_identifier=None, class_names=class_names, callback=callback) - - def run_tests_by_mod_name(self, mod_identifier: Union[str, CommonModIdentity], class_names: Tuple[str]=tuple(), callback: Callable[..., Any]=print): - """run_tests_by_mod_name(mod_identifier, class_names=tuple(), callback=print) - - Run all tests for the specified classes names for a specific Mod. - - :param mod_identifier: The name or identity of the mod to run tests for. - :param mod_identifier: Union[str, CommonModIdentity] - :param class_names: A collection of classes to run tests for. Default is all tests. - :type class_names: Tuple[str], optional - :param callback: Any time a message needs to be printed or logged, it will be sent to this callback. Default is print. - :type callback: Callable[str, Any] - """ - return self._run_tests(mod_identifier=mod_identifier, class_names=class_names, callback=callback) - - def _run_tests(self, mod_identifier: Union[str, CommonModIdentity]=None, class_names: Tuple[str]=tuple(), callback: Callable[..., Any]=print): - total_run_test_count = 0 - total_failed_test_count = 0 - from s4ap.sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils - if mod_identifier: - to_run_mod_name = CommonModIdentityUtils.determine_mod_name_from_identifier(mod_identifier, include_version=False).lower() - else: - to_run_mod_name = None - for (mod_identity, class_tests_by_class_name) in self.all_tests.items(): - mod_name = mod_identity.name - if to_run_mod_name: - from s4ap.sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils - cleaned_mod_name = CommonModIdentityUtils.determine_mod_name_from_identifier(mod_identity, include_version=False).lower() - if cleaned_mod_name != to_run_mod_name: - continue - mod_log = CommonLogRegistry().register_log(mod_identity, 'test_log') - try: - mod_log.enable() - callback(f'Running Tests for mod \'{mod_name}\'') - mod_log.debug(f'Running Tests for mod \'{mod_name}\'') - for (class_name, tests) in class_tests_by_class_name.items(): - if class_names and class_name not in class_names: - continue - class_log = CommonLogRegistry().register_log(mod_identity, class_name) - try: - class_log.enable() - callback(f'Running Tests for class \'{class_name}\'') - class_log.debug(f'Running Tests for class \'{class_name}\'') - total_test_count = len(tests) - failed_test_count = 0 - current_test_count = 0 - for test_name, test in tests: - total_run_test_count += 1 - current_test_count += 1 - result = test() - if result == CommonTestResultType.FAILED: - failed_test_count += 1 - total_failed_test_count += 1 - callback(f'{current_test_count} of {total_test_count} {result} {test_name}') - class_log.debug(f'{current_test_count} of {total_test_count} {result} {test_name}') - total_passed = total_test_count-failed_test_count - callback(f'{total_passed} of {total_test_count} tests Succeeded for class \'{class_name}\'\n') - class_log.debug(f'{total_passed} of {total_test_count} tests Succeeded for class \'{class_name}\'\n') - finally: - class_log.disable() - total_run_passed = total_run_test_count-total_failed_test_count - callback(f'{total_run_passed} of {total_run_test_count} total tests Succeeded') - mod_log.debug(f'{total_run_passed} of {total_run_test_count} total tests Succeeded') - finally: - mod_log.disable() - - -try: - from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ - CommonConsoleCommandArgument - from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput - - @CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.run_tests', - 'Run any tests that are registered with S4CL (Only useful to mod authors)', - command_arguments=( - CommonConsoleCommandArgument('class_name', 'Text', 'If specified, only the tests located within the class matching this name will be run. If not specified, all registered tests will run.', is_optional=True, default_value='All Tests'), - CommonConsoleCommandArgument('mod_name', 'Text', 'If specified, only the tests registered by the mod with this name will be run. If not specified, all registered tests by all mods will run.', is_optional=True, default_value='All Mods'), - ) - ) - def _common_run_tests(output: CommonConsoleCommandOutput, class_name: str=None, mod_name: str=None): - class_names = tuple() - if class_name is not None: - class_names = (class_name,) - if mod_name is not None: - CommonTestService().run_tests_by_mod_name(mod_name, class_names, callback=output) - else: - CommonTestService.get().run_tests(class_names, callback=output) -except ModuleNotFoundError: - pass diff --git a/Scripts/s4ap/sims4communitylib/utils/__init__.py b/Scripts/s4ap/sims4communitylib/utils/__init__.py deleted file mode 100644 index 3251898..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" \ No newline at end of file diff --git a/Scripts/s4ap/sims4communitylib/utils/cas/__init__.py b/Scripts/s4ap/sims4communitylib/utils/cas/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/cas/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/utils/cas/common_cas_utils.py b/Scripts/s4ap/sims4communitylib/utils/cas/common_cas_utils.py deleted file mode 100644 index dbd2fa6..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/cas/common_cas_utils.py +++ /dev/null @@ -1,975 +0,0 @@ -""" -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 -""" -import os -from typing import Tuple, Union, Iterator, Dict, List - -from sims4.utils import classproperty -from s4ap.sims4communitylib.classes.time.common_stop_watch import CommonStopWatch -from s4ap.sims4communitylib.dtos.common_cas_part import CommonCASPart -from s4ap.sims4communitylib.enums.common_body_slot import CommonBodySlot -from s4ap.sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ - CommonConsoleCommandArgument -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.services.sim.cas.common_sim_outfit_io import CommonSimOutfitIO -from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils - -ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' - -if ON_RTD: - # noinspection PyMissingOrEmptyDocstring - class OutfitCategory: - - @classproperty - def value_to_name(self) -> Dict['OutfitCategory', str]: - pass - - # noinspection PyMissingOrEmptyDocstring - class BodyType: - NONE = 0 - - @classproperty - def value_to_name(self) -> Dict['BodyType', str]: - pass - - @classproperty - def name_to_value(self) -> Dict[str, 'BodyType']: - pass - - # noinspection PyMissingOrEmptyDocstring - class SimInfo: - pass - -if not ON_RTD: - from sims.outfits.outfit_enums import OutfitCategory, BodyType - from sims.sim_info import SimInfo - - -class CommonCASUtils(_HasS4CLClassLog): - """Utilities for manipulating the CAS parts of Sims. - - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 'common_cas_utils' - - @staticmethod - def is_cas_part_loaded(cas_part_id: int) -> bool: - """is_cas_part_loaded(cas_part_id) - - Determine if a CAS part is loaded within the game. - - .. note:: If the CAS part is part of a package that is not installed, it will be considered as not loaded. - - .. note:: A CAS part is considered as "loaded" when the BodyType it has can be found within the sims.outfits.outfit_enums.BodyType enum. - - :param cas_part_id: The Decimal identifier of a CAS part. - :type cas_part_id: int - :return: True if the CAS part is loaded within the game, False if not. - :rtype: bool - """ - body_type = CommonCASUtils.get_body_type_of_cas_part(cas_part_id) - return body_type is not None and body_type > 0 - - @staticmethod - def get_body_type_of_cas_part(cas_part_id: int) -> Union[BodyType, int]: - """get_body_type_of_cas_part(cas_part_id) - - Retrieve the BodyType of a CAS part. - - .. note:: Some Body Types don't appear in the BodyType enum. - - :param cas_part_id: The decimal identifier of a CAS part. - :type cas_part_id: int - :return: The default BodyType of the CAS part or an int if the Body Type is not within the BodyType enum. - :rtype: Union[BodyType, int] - """ - from cas.cas import get_caspart_bodytype - body_type = get_caspart_bodytype(cas_part_id) - if isinstance(body_type, int) and body_type in BodyType.value_to_name: - new_body_type = CommonResourceUtils.get_enum_by_name(BodyType.value_to_name[body_type], BodyType, default_value=None) - if new_body_type is not None: - body_type = new_body_type - return body_type - - @staticmethod - def get_body_type_by_name(name: str, default_body_type: Union[BodyType, None] = BodyType.NONE) -> BodyType: - """get_body_type_by_name(name, default_value=BodyType.NONE) - - Retrieve an BodyType by name. - - :param name: The name of a body type. - :type name: str - :param default_body_type: The default body type to use if a body type is not found using the specified name. Default is BodyType.NONE - :type default_body_type: Union[BodyType, None], optional - :return: The BodyType with the specified name or the default body type if no body type was found using the specified name. - :rtype: BodyType - """ - upper_case_name = str(name).upper().strip() - return CommonResourceUtils.get_enum_by_name(upper_case_name, BodyType, default_value=default_body_type) - - @staticmethod - def convert_value_to_body_type(value: Union[BodyType, int]) -> Union[BodyType, int]: - """convert_value_to_body_type(value) - - Retrieve an BodyType by value. - - :param value: The value of a body type. - :type value: Union[BodyType, int] - :return: The BodyType with the specified value or the specified value if no BodyType was found. - :rtype: Union[BodyType, int] - """ - if isinstance(value, BodyType): - return value - if value in BodyType.value_to_name: - return CommonResourceUtils.get_enum_by_name(BodyType.value_to_name[value], BodyType, default_value=value) - return value - - @classmethod - def attach_cas_part_to_sim(cls, sim_info: SimInfo, cas_part_id: int, body_type: Union[BodyType, int] = None, outfit_category_and_index: Union[Tuple[OutfitCategory, int], None] = None, **__) -> bool: - """attach_cas_part_to_sim(sim_info, cas_part_id, body_type=None, outfit_category_and_index=None, **__) - - Add a CAS part at the specified BodyType to the Sims outfit. - - :param sim_info: The SimInfo of a Sim to add the CAS part to. - :type sim_info: SimInfo - :param cas_part_id: The decimal identifier of a CAS part to attach to the Sim. - :type cas_part_id: int - :param body_type: The BodyType the CAS part will be attached to. If no value is provided, the BodyType of the CAS part itself will be used. Default is None. - :type body_type: Union[BodyType, int], optional - :param outfit_category_and_index: The outfit category and index of the Sims outfit to modify. If no value is provided, the Sims current outfit will be used. - :type outfit_category_and_index: Union[Tuple[OutfitCategory, int], None], optional - :return: True if the CAS part was successfully attached to the Sim. False if the CAS part was not successfully attached to the Sim. - :rtype: bool - """ - if cas_part_id == -1 or cas_part_id is None: - raise RuntimeError('No cas_part_id was provided.') - - cls.get_log().format_with_message('Attempting to attach CAS part to Sim', sim=sim_info, cas_part_id=cas_part_id, body_type=body_type, outfit_category_and_index=outfit_category_and_index) - cas_part = CommonCASPart(cas_part_id, body_type=body_type if body_type != BodyType.NONE else None) - return cls.attach_cas_part_to_outfit_of_sim(sim_info, cas_part, outfit_category_and_index=outfit_category_and_index) - - @classmethod - def attach_cas_part_to_all_outfits_of_sim(cls, sim_info: SimInfo, cas_part: CommonCASPart) -> bool: - """attach_cas_part_to_all_outfits_of_sim(sim_info, cas_part) - - Attach a CAS part to all outfits of a Sim. - - :param sim_info: The SimInfo of a Sim to modify. - :type sim_info: SimInfo - :param cas_part: The CAS Part to attach. - :type cas_part: CommonCASPart - :return: True, if the CAS part was successfully attached to the Sim. False, if not. - :rtype: bool - """ - return cls.attach_cas_parts_to_all_outfits_of_sim(sim_info, (cas_part,)) - - @classmethod - def attach_cas_parts_to_all_outfits_of_sim(cls, sim_info: SimInfo, cas_parts: Iterator[CommonCASPart]) -> bool: - """attach_cas_parts_to_all_outfits_of_sim(sim_info, cas_parts) - - Attach a collection of CAS Parts to all outfits of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param cas_parts: A collection of CAS Parts to attach. - :type cas_parts: Iterator[CommonCASPart] - :return: True, if all CAS Parts were successfully attached to the Sim. False, if not. - """ - _log = cls.get_log() - cas_parts_by_body_type = dict() - for cas_part in cas_parts: - cas_parts_by_body_type[int(CommonBodySlot.convert_to_vanilla(cas_part.body_type))] = cas_part - cas_part_body_types = [int(CommonBodySlot.convert_to_vanilla(cas_part.body_type)) for cas_part in cas_parts] - from s4ap.sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils - current_outfit = CommonOutfitUtils.get_current_outfit(sim_info) - from protocolbuffers import S4Common_pb2, Outfits_pb2 - saved_outfits = sim_info.save_outfits() - for saved_outfit in saved_outfits.outfits: - # noinspection PyUnresolvedReferences - saved_outfit_parts = dict(zip(list(saved_outfit.body_types_list.body_types), list(saved_outfit.parts.ids))) - body_types = list() - part_ids = list() - handled_body_types: List[int] = list() - _log.format_with_message('Before modify parts.', outfit_category=saved_outfit.category, body_types=tuple(saved_outfit_parts.keys()), part_ids=tuple(saved_outfit_parts.values())) - for (body_type, part_id) in saved_outfit_parts.items(): - body_type_int = int(body_type) - if body_type_int in cas_parts_by_body_type: - # Remove the existing body types that match the ones we are replacing. - handled_body_types.append(body_type_int) - part = cas_parts_by_body_type[body_type_int] - _log.format_with_message('Replacing body type with CAS Part', original_body_type=body_type, cas_part=part, original_part_id=part_id) - body_types.append(CommonBodySlot.convert_to_vanilla(part.body_type)) - part_ids.append(part.cas_part_id) - continue - _log.format_with_message('Keeping body type.', original_body_type=body_type, cas_part_body_types=cas_part_body_types, original_part_id=part_id) - body_types.append(body_type) - part_ids.append(part_id) - - # Adding the rest of the CAS Parts. - _log.format_with_message('Adding the rest of the CAS Parts.', body_types=body_types, part_ids=part_ids, cas_parts_by_body_type=cas_parts_by_body_type, handled_body_types=handled_body_types) - for cas_part in cas_parts_by_body_type.values(): - cas_part_body_type = CommonBodySlot.convert_to_vanilla(cas_part.body_type) - if int(cas_part_body_type) in handled_body_types: - continue - body_types.append(cas_part_body_type) - part_ids.append(cas_part.cas_part_id) - - _log.format_with_message('After modify parts.', outfit_category=saved_outfit.category, body_types=body_types, part_ids=part_ids) - - # Save the parts. - saved_outfit.parts = S4Common_pb2.IdList() - # noinspection PyUnresolvedReferences - saved_outfit.parts.ids.extend(part_ids) - saved_outfit.body_types_list = Outfits_pb2.BodyTypesList() - # noinspection PyUnresolvedReferences - saved_outfit.body_types_list.body_types.extend([int(body_type) for body_type in body_types]) - sim_info._base.outfits = saved_outfits.SerializeToString() - sim_info._base.outfit_type_and_index = current_outfit - sim_info.resend_outfits() - sim_info.on_outfit_generated(*current_outfit) - sim_info.set_outfit_dirty(current_outfit[0]) - sim_info.set_current_outfit(current_outfit) - return True - - @classmethod - def attach_cas_part_to_outfit_of_sim(cls, sim_info: SimInfo, cas_part: CommonCASPart, outfit_category_and_index: Tuple[OutfitCategory, int] = None) -> bool: - """attach_cas_part_to_outfit_of_sim(sim_info, cas_part, outfit_category_and_index=None) - - Attach a CAS part to an outfit of a Sim. - - :param sim_info: The SimInfo of a Sim to modify. - :type sim_info: SimInfo - :param cas_part: The CAS Part to attach. - :type cas_part: CommonCASPart - :return: True, if the CAS part was successfully attached to the Sim. False, if not. - :param outfit_category_and_index: The outfit category and index of the Sims outfit to modify. If no value is provided, the Sims current outfit will be used. Default is current outfit. - :type outfit_category_and_index: Union[Tuple[OutfitCategory, int], None], optional - :return: True, if the CAS part was successfully attached to the outfit of the Sim. False, if not. - :rtype: bool - """ - return cls.attach_cas_parts_to_outfit_of_sim(sim_info, (cas_part,), outfit_category_and_index=outfit_category_and_index) - - @classmethod - def attach_cas_parts_to_outfit_of_sim(cls, sim_info: SimInfo, cas_parts: Iterator[CommonCASPart], outfit_category_and_index: Tuple[OutfitCategory, int] = None, set_outfit: bool = True) -> bool: - """attach_cas_parts_to_outfit_of_sim(sim_info, cas_parts, outfit_category_and_index=None) - - Attach CAS parts to an outfit of a Sim. - - :param sim_info: The SimInfo of a Sim to modify. - :type sim_info: SimInfo - :param cas_parts: A collection of CAS Parts to attach. - :type cas_parts: Iterator[CommonCASPart] - :param outfit_category_and_index: The outfit category and index of the Sims outfit to modify. If no value is provided, the Sims current outfit will be used. Default is current outfit. - :type outfit_category_and_index: Union[Tuple[OutfitCategory, int], None], optional - :return: True, if the CAS parts were successfully attached to the Sim. False, if not. - :rtype: bool - """ - stop_watch = CommonStopWatch() - try: - stop_watch.start() - from s4ap.sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils - current_outfit = CommonOutfitUtils.get_current_outfit(sim_info) - if outfit_category_and_index is None: - outfit_category_and_index = current_outfit - existing_outfit_data = sim_info.get_outfit(outfit_category_and_index[0], outfit_category_and_index[1]) - cas_part_body_types = [int(CommonBodySlot.convert_to_vanilla(cas_part.body_type)) for cas_part in cas_parts] - from protocolbuffers import S4Common_pb2, Outfits_pb2 - saved_outfits = sim_info.save_outfits() - cls.get_log().format_with_message('Got Saved Outfits', time_milliseconds=stop_watch.interval_milliseconds()) - for saved_outfit in saved_outfits.outfits: - if int(saved_outfit.outfit_id) != int(existing_outfit_data.outfit_id): - continue - # noinspection PyUnresolvedReferences - saved_outfit_parts = dict(zip(list(saved_outfit.body_types_list.body_types), list(saved_outfit.parts.ids))) - body_types = list() - part_ids = list() - for (body_type, part_id) in saved_outfit_parts.items(): - if int(body_type) in cas_part_body_types: - # Remove the existing body types that match the ones we are replacing. - continue - body_types.append(body_type) - part_ids.append(part_id) - - # Add the new cas parts and their body types. - for cas_part in cas_parts: - body_types.append(CommonBodySlot.convert_to_vanilla(cas_part.body_type)) - part_ids.append(cas_part.cas_part_id) - - # Save the parts. - saved_outfit.parts = S4Common_pb2.IdList() - # noinspection PyUnresolvedReferences - saved_outfit.parts.ids.extend(part_ids) - saved_outfit.body_types_list = Outfits_pb2.BodyTypesList() - # noinspection PyUnresolvedReferences - saved_outfit.body_types_list.body_types.extend([int(body_type) for body_type in body_types]) - cls.get_log().format_with_message('Finished updating Saved Outfits. Setting outfits.', time_milliseconds=stop_watch.interval_milliseconds()) - sim_info._base.outfits = saved_outfits.SerializeToString() - sim_info._base.outfit_type_and_index = current_outfit - sim_info.resend_outfits() - cls.get_log().format_with_message('Finished resending outfits.', time_milliseconds=stop_watch.interval_milliseconds()) - sim_info.on_outfit_generated(*current_outfit) - sim_info.set_outfit_dirty(current_outfit[0]) - sim_info.set_current_outfit(current_outfit) - cls.get_log().format_with_message('Finished setting current outfit.', time_milliseconds=stop_watch.interval_milliseconds()) - return True - finally: - stop_watch.stop() - - @classmethod - def detach_cas_part_from_all_outfits_of_sim(cls, sim_info: SimInfo, cas_part: CommonCASPart) -> bool: - """detach_cas_part_from_all_outfits_of_sim(sim_info, cas_part) - - Detach a CAS Part from all outfits of a Sim. - - :param sim_info: The SimInfo of a Sim to modify. - :type sim_info: SimInfo - :param cas_part: A CAS Part to detach. - :type cas_part: CommonCASPart - :return: True, if the CAS Part was successfully detached from all outfits of the Sim. False, if not. - """ - return cls.detach_cas_parts_from_all_outfits_of_sim(sim_info, (cas_part,)) - - @classmethod - def detach_cas_parts_from_all_outfits_of_sim(cls, sim_info: SimInfo, cas_parts: Iterator[CommonCASPart]) -> bool: - """detach_cas_parts_from_all_outfits_of_sim(sim_info, cas_parts) - - Detach a collection of CAS Parts from all outfits of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param cas_parts: A collection of CAS Parts to detach. - :type cas_parts: Iterator[CommonCASPart] - :return: True, if all CAS Parts were successfully detached from all outfits of the Sim. False, if not. - """ - _log = cls.get_log() - cas_part_ids = tuple([cas_part.cas_part_id for cas_part in cas_parts]) - from s4ap.sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils - current_outfit = CommonOutfitUtils.get_current_outfit(sim_info) - from protocolbuffers import S4Common_pb2, Outfits_pb2 - saved_outfits = sim_info.save_outfits() - for saved_outfit in saved_outfits.outfits: - # noinspection PyUnresolvedReferences - saved_outfit_parts = dict(zip(list(saved_outfit.body_types_list.body_types), list(saved_outfit.parts.ids))) - body_types = list() - part_ids = list() - _log.format_with_message('Before modify parts.', outfit_category=saved_outfit.category, body_types=tuple(saved_outfit_parts.keys()), part_ids=tuple(saved_outfit_parts.values())) - for (body_type, part_id) in saved_outfit_parts.items(): - if part_id in cas_part_ids: - # Remove cas_part_ids - continue - _log.format_with_message('Keeping body type.', original_body_type=body_type, original_part_id=part_id) - body_types.append(body_type) - part_ids.append(part_id) - - _log.format_with_message('After modify parts.', outfit_category=saved_outfit.category, body_types=body_types, part_ids=part_ids) - - # Save the parts. - saved_outfit.parts = S4Common_pb2.IdList() - # noinspection PyUnresolvedReferences - saved_outfit.parts.ids.extend(part_ids) - saved_outfit.body_types_list = Outfits_pb2.BodyTypesList() - # noinspection PyUnresolvedReferences - saved_outfit.body_types_list.body_types.extend([int(body_type) for body_type in body_types]) - sim_info._base.outfits = saved_outfits.SerializeToString() - sim_info._base.outfit_type_and_index = current_outfit - sim_info.resend_outfits() - sim_info.on_outfit_generated(*current_outfit) - sim_info.set_outfit_dirty(current_outfit[0]) - sim_info.set_current_outfit(current_outfit) - return True - - @classmethod - def detach_cas_part_from_outfit_of_sim(cls, sim_info: SimInfo, cas_part: CommonCASPart, outfit_category_and_index: Tuple[OutfitCategory, int] = None) -> bool: - """detach_cas_part_from_outfit_of_sim(sim_info, cas_part, outfit_category_and_index=None) - - Detach a CAS part from an outfit of a Sim. - - :param sim_info: The SimInfo of a Sim to modify. - :type sim_info: SimInfo - :param cas_part: A CAS Part to detach. - :type cas_part: CommonCASPart - :param outfit_category_and_index: The outfit category and index of the Sims outfit to modify. If no value is provided, the Sims current outfit will be used. Default is current outfit. - :type outfit_category_and_index: Union[Tuple[OutfitCategory, int], None], optional - :return: True, if the CAS part was successfully detached from the outfit of the Sim. False, if not. - :rtype: bool - """ - return cls.detach_cas_parts_from_outfit_of_sim(sim_info, (cas_part,), outfit_category_and_index=outfit_category_and_index) - - @classmethod - def detach_cas_parts_from_outfit_of_sim(cls, sim_info: SimInfo, cas_parts: Iterator[CommonCASPart], outfit_category_and_index: Tuple[OutfitCategory, int] = None) -> bool: - """detach_cas_parts_from_outfit_of_sim(sim_info, cas_parts, outfit_category_and_index=None) - - Detach CAS parts from an outfit of a Sim. - - :param sim_info: The SimInfo of a Sim to modify. - :type sim_info: SimInfo - :param cas_parts: A collection of CAS Parts to detach. - :type cas_parts: Iterator[CommonCASPart] - :param outfit_category_and_index: The outfit category and index of the Sims outfit to modify. If no value is provided, the Sims current outfit will be used. Default is current outfit. - :type outfit_category_and_index: Union[Tuple[OutfitCategory, int], None], optional - :return: True, if the CAS parts were successfully detached from the outfit of the Sim. False, if not. - :rtype: bool - """ - from s4ap.sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils - current_outfit = CommonOutfitUtils.get_current_outfit(sim_info) - if outfit_category_and_index is None: - outfit_category_and_index = current_outfit - existing_outfit_data = sim_info.get_outfit(outfit_category_and_index[0], outfit_category_and_index[1]) - cas_part_ids = [cas_part.cas_part_id for cas_part in cas_parts] - from protocolbuffers import S4Common_pb2, Outfits_pb2 - saved_outfits = sim_info.save_outfits() - for saved_outfit in saved_outfits.outfits: - if int(saved_outfit.outfit_id) != int(existing_outfit_data.outfit_id): - continue - # noinspection PyUnresolvedReferences - saved_outfit_parts = dict(zip(list(saved_outfit.body_types_list.body_types), list(saved_outfit.parts.ids))) - body_types = list() - part_ids = list() - for (body_type, part_id) in saved_outfit_parts.items(): - if part_id in cas_part_ids: - # Remove the CAS Part Id. - continue - body_types.append(body_type) - part_ids.append(part_id) - - # Save the parts. - saved_outfit.parts = S4Common_pb2.IdList() - # noinspection PyUnresolvedReferences - saved_outfit.parts.ids.extend(part_ids) - saved_outfit.body_types_list = Outfits_pb2.BodyTypesList() - # noinspection PyUnresolvedReferences - saved_outfit.body_types_list.body_types.extend([int(body_type) for body_type in body_types]) - sim_info._base.outfits = saved_outfits.SerializeToString() - sim_info._base.outfit_type_and_index = current_outfit - sim_info.resend_outfits() - sim_info.on_outfit_generated(*current_outfit) - sim_info.set_outfit_dirty(current_outfit[0]) - sim_info.set_current_outfit(current_outfit) - return True - - # noinspection PyUnusedLocal - @classmethod - def detach_cas_part_from_sim(cls, sim_info: SimInfo, cas_part_id: int, body_type: Union[BodyType, int, None] = None, outfit_category_and_index: Union[Tuple[OutfitCategory, int], None] = None, **__) -> bool: - """detach_cas_part_from_sim(sim_info, cas_part_id, body_type=None, outfit_category_and_index=None, **__) - - Remove a CAS part at the specified BodyType from the Sims outfit. - - :param sim_info: The SimInfo of a Sim to remove the CAS part from. - :type sim_info: SimInfo - :param cas_part_id: The decimal identifier of a CAS part to detach from the Sim. - :type cas_part_id: int - :param body_type: The BodyType the CAS part will be detached from. If BodyType.NONE is provided, the BodyType of the CAS Part itself will be used. If set to None, the CAS part will be removed from all BodyTypes. Default is None. - :type body_type: Union[BodyType, int, None], optional - :param outfit_category_and_index: The outfit category and index of the Sims outfit to modify. If no value is provided, the Sims current outfit will be used. Default is current outfit. - :type outfit_category_and_index: Union[Tuple[OutfitCategory, int], None], optional - :return: True if the CAS part was successfully detached from the Sim. False if the CAS part was not successfully detached from the Sim. - :rtype: bool - """ - if cas_part_id == -1 or cas_part_id is None: - raise RuntimeError('No cas_part_id was provided.') - cas_part = CommonCASPart(cas_part_id, body_type=body_type if body_type != BodyType.NONE else None) - return cls.detach_cas_part_from_outfit_of_sim(sim_info, cas_part, outfit_category_and_index=outfit_category_and_index) - - @classmethod - def detach_body_type_from_all_outfits_of_sim(cls, sim_info: SimInfo, body_type_to_remove: Union[BodyType, int]): - """detach_body_type_from_all_outfits_of_sim(sim_info, body_type_to_remove) - - Detach a body type from all outfits of a Sim. - - :param sim_info: The SimInfo of a Sim to modify. - :type sim_info: SimInfo - :param body_type_to_remove: The body type to remove. - :type body_type_to_remove: Union[BodyType, int] - """ - return cls.detach_body_types_from_all_outfits_of_sim(sim_info, (body_type_to_remove,)) - - @classmethod - def detach_body_types_from_all_outfits_of_sim(cls, sim_info: SimInfo, body_types_to_remove: Iterator[Union[BodyType, int]]): - """detach_body_types_from_all_outfits_of_sim(sim_info, body_types_to_remove) - - Detach body types from all outfits of a Sim. - - :param sim_info: The SimInfo of a Sim to modify. - :type sim_info: SimInfo - :param body_types_to_remove: A collection of body types to remove. - :type body_types_to_remove: Iterator[Union[BodyType, int]] - """ - body_types_to_remove = tuple([int(body_type) for body_type in body_types_to_remove]) - from protocolbuffers import S4Common_pb2, Outfits_pb2 - saved_outfits = sim_info.save_outfits() - for saved_outfit in saved_outfits.outfits: - # noinspection PyUnresolvedReferences - saved_outfit_parts = dict(zip(list(saved_outfit.body_types_list.body_types), list(saved_outfit.parts.ids))) - body_types = list() - part_ids = list() - # Remove existing body type and its associated part that matches the one we are replacing. - for (body_type, part_id) in saved_outfit_parts.items(): - if int(body_type) in body_types_to_remove: - # Remove body type. - continue - body_types.append(body_type) - part_ids.append(part_id) - - # Save the parts. - saved_outfit.parts = S4Common_pb2.IdList() - # noinspection PyUnresolvedReferences - saved_outfit.parts.ids.extend(part_ids) - saved_outfit.body_types_list = Outfits_pb2.BodyTypesList() - # noinspection PyUnresolvedReferences - saved_outfit.body_types_list.body_types.extend(body_types) - sim_info._base.outfits = saved_outfits.SerializeToString() - - @classmethod - def detach_body_type_from_outfit_of_sim(cls, sim_info: SimInfo, body_type_to_remove: Union[BodyType, int], outfit_category_and_index: Tuple[OutfitCategory, int] = None) -> bool: - """detach_body_type_from_outfit_of_sim(sim_info, body_type_to_remove, outfit_category_and_index=None) - - Detach the CAS Part at a specific body type from an outfit of a Sim. - - :param sim_info: The SimInfo of a Sim to modify. - :type sim_info: SimInfo - :param body_type_to_remove: The body type to remove. - :type body_type_to_remove: Union[BodyType, int] - :param outfit_category_and_index: The outfit category and index of the Sims outfit to modify. If no value is provided, the Sims current outfit will be used. Default is current outfit. - :type outfit_category_and_index: Union[Tuple[OutfitCategory, int], None], optional - :return: True, if the body type was successfully detached from the outfit of the Sim. False, if not. - :rtype: bool - """ - return cls.detach_body_types_from_outfit_of_sim(sim_info, (body_type_to_remove,), outfit_category_and_index=outfit_category_and_index) - - @classmethod - def detach_body_types_from_outfit_of_sim(cls, sim_info: SimInfo, body_types_to_remove: Iterator[Union[BodyType, int]], outfit_category_and_index: Tuple[OutfitCategory, int] = None) -> bool: - """detach_body_types_from_outfit_of_sim(sim_info, body_types_to_remove, outfit_category_and_index=None) - - Detach any CAS Parts at specific body types from an outfit of a Sim. - - :param sim_info: The SimInfo of a Sim to modify. - :type sim_info: SimInfo - :param body_types_to_remove: A collection of body types to remove. - :type body_types_to_remove: Iterator[Union[BodyType, int]] - :param outfit_category_and_index: The outfit category and index of the Sims outfit to modify. If no value is provided, the Sims current outfit will be used. Default is current outfit. - :type outfit_category_and_index: Union[Tuple[OutfitCategory, int], None], optional - :return: True, if the body types were successfully detached from the outfit of the Sim. False, if not. - :rtype: bool - """ - from s4ap.sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils - current_outfit = CommonOutfitUtils.get_current_outfit(sim_info) - if outfit_category_and_index is None: - outfit_category_and_index = current_outfit - existing_outfit_data = sim_info.get_outfit(outfit_category_and_index[0], outfit_category_and_index[1]) - body_types_to_remove = tuple([int(body_type) for body_type in body_types_to_remove]) - from protocolbuffers import S4Common_pb2, Outfits_pb2 - saved_outfits = sim_info.save_outfits() - for saved_outfit in saved_outfits.outfits: - if int(saved_outfit.outfit_id) != int(existing_outfit_data.outfit_id): - continue - # noinspection PyUnresolvedReferences - saved_outfit_parts = dict(zip(list(saved_outfit.body_types_list.body_types), list(saved_outfit.parts.ids))) - body_types = list() - part_ids = list() - for (body_type, part_id) in saved_outfit_parts.items(): - if int(body_type) in body_types_to_remove: - # Remove body type. - continue - body_types.append(body_type) - part_ids.append(part_id) - - # Save the parts. - saved_outfit.parts = S4Common_pb2.IdList() - # noinspection PyUnresolvedReferences - saved_outfit.parts.ids.extend(part_ids) - saved_outfit.body_types_list = Outfits_pb2.BodyTypesList() - # noinspection PyUnresolvedReferences - saved_outfit.body_types_list.body_types.extend(body_types) - sim_info._base.outfits = saved_outfits.SerializeToString() - sim_info._base.outfit_type_and_index = current_outfit - sim_info.resend_outfits() - return True - - @classmethod - def has_cas_part_attached(cls, sim_info: SimInfo, cas_part_id: int, body_type: Union[BodyType, int, None] = None, outfit_category_and_index: Tuple[OutfitCategory, int] = None, mod_identity: CommonModIdentity = None) -> bool: - """has_cas_part_attached(sim_info, cas_part_id, body_type=None, outfit_category_and_index=None, mod_identity=None) - - Determine if a Sim has the specified CAS part attached to their outfit. - - :param sim_info: The SimInfo of the Sim to check. - :type sim_info: SimInfo - :param cas_part_id: A decimal identifier of the CAS part to locate. - :type cas_part_id: int - :param body_type: The BodyType the CAS part will be located at. If BodyType.NONE is provided, the body type of the CAS Part itself will be used. If set to None, the CAS part will be located within any BodyType. Default is None. - :type body_type: Union[BodyType, int, None], optional - :param outfit_category_and_index: The outfit category and index of the Sims outfit to check. Default is the Sims current outfit. - :type outfit_category_and_index: Union[Tuple[OutfitCategory, int], None], optional - :param mod_identity: The identity of the mod performing the function. Default is None. Optional, but highly recommended! - :type mod_identity: CommonModIdentity, optional - :return: True, if the Sims outfit contain the specified CAS part. False, if the Sims outfit does not contain the specified CAS part. - :rtype: bool - """ - cls.get_log().format_with_message('Checking if CAS part is attached to Sim.', sim=sim_info, cas_part_id=cas_part_id, body_type=body_type, outfit_category_and_index=outfit_category_and_index) - outfit_io = CommonSimOutfitIO(sim_info, outfit_category_and_index=outfit_category_and_index, mod_identity=mod_identity) - if body_type is None: - return outfit_io.is_cas_part_attached(cas_part_id) - if body_type == BodyType.NONE: - body_type = CommonCASUtils.get_body_type_of_cas_part(cas_part_id) - return outfit_io.get_cas_part_at_body_type(body_type) == cas_part_id - - @staticmethod - def has_any_cas_part_attached_to_body_type(sim_info: SimInfo, body_type: Union[BodyType, int], outfit_category_and_index: Tuple[OutfitCategory, int] = None, mod_identity: CommonModIdentity = None) -> bool: - """has_any_cas_part_attached_to_body_type(sim_info, body_type, outfit_category_and_index=None, mod_identity=None) - - Determine if a Sim has a CAS Part attached to a BodyType. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param body_type: A BodyType to check. - :type body_type: Union[BodyType, int] - :param outfit_category_and_index: An outfit category and index of the outfit. Default is None, which is whatever outfit a Sim is currently wearing. - :type outfit_category_and_index: Tuple[OutfitCategory, int], optional - :param mod_identity: The identity of the mod performing the function. Default is None. Optional, but highly recommended! - :type mod_identity: CommonModIdentity, optional - :return: True, if the Sim has any CAS Part attached to the specified BodyType for the specified outfit. False, it not. - :rtype: bool - """ - return CommonCASUtils.get_cas_part_id_at_body_type(sim_info, body_type, outfit_category_and_index=outfit_category_and_index, mod_identity=mod_identity) != -1 - - @classmethod - def get_body_type_cas_part_is_attached_to(cls, sim_info: SimInfo, cas_part_id: int, outfit_category_and_index: Tuple[OutfitCategory, int] = None, mod_identity: CommonModIdentity = None) -> Union[BodyType, int]: - """get_body_type_cas_part_is_attached_to(sim_info, cas_part_id, outfit_category_and_index=None, mod_identity=None) - - Retrieve the BodyType that a CAS part is attached to within a Sims outfit. - - :param sim_info: The SimInfo of the Sim to check. - :type sim_info: SimInfo - :param cas_part_id: A decimal identifier of the CAS part to locate. - :type cas_part_id: int - :param outfit_category_and_index: The outfit category and index of the Sims outfit to check. If None, the current outfit of the Sim will be used. - :type outfit_category_and_index: Tuple[OutfitCategory, int], optional - :param mod_identity: The identity of the mod performing the function. Default is None. Optional, but highly recommended! - :type mod_identity: CommonModIdentity, optional - :return: The BodyType the specified CAS part id is attached to or BodyType.NONE if the CAS part is not found or the Sim does not have body parts for their outfit. - :rtype: Union[BodyType, int] - """ - cls.get_log().format_with_message('Retrieving BodyType for CAS part.', sim=sim_info, cas_part_id=cas_part_id, outfit_category_and_index=outfit_category_and_index) - outfit_io = CommonSimOutfitIO(sim_info, outfit_category_and_index=outfit_category_and_index, mod_identity=mod_identity) - return outfit_io.get_body_type_cas_part_is_attached_to(cas_part_id) - - @classmethod - def get_cas_part_id_at_body_type(cls, sim_info: SimInfo, body_type: Union[BodyType, int], outfit_category_and_index: Tuple[OutfitCategory, int] = None, mod_identity: CommonModIdentity = None) -> int: - """get_cas_part_id_at_body_type(sim_info, body_type, outfit_category_and_index=None, mod_identity=None) - - Retrieve the CAS part identifier attached to the specified BodyType within a Sims outfit. - - :param sim_info: The SimInfo of the Sim to check. - :type sim_info: SimInfo - :param body_type: The BodyType to check. - :type body_type: Union[BodyType, int] - :param outfit_category_and_index: The outfit category and index of the Sims outfit to check. Default is the Sims current outfit. - :type outfit_category_and_index: Tuple[OutfitCategory, int], optional - :param mod_identity: The identity of the mod performing the function. Default is None. Optional, but highly recommended! - :type mod_identity: CommonModIdentity, optional - :return: The CAS part identifier attached to the specified BodyType or -1 if the BodyType is not found. - :rtype: int - """ - cls.get_log().format_with_message('Checking if CAS part is attached to Sim.', sim=sim_info, body_type=body_type, outfit_category_and_index=outfit_category_and_index) - outfit_io = CommonSimOutfitIO(sim_info, outfit_category_and_index=outfit_category_and_index, mod_identity=mod_identity) - return outfit_io.get_cas_part_at_body_type(body_type) - - @staticmethod - def get_skin_tone(sim_info: SimInfo) -> int: - """get_skin_tone(sim_info) - - Retrieve the id for the Skin Tone of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The decimal identifier of the skin tone of the specified Sim. - :rtype: int - """ - return sim_info.skin_tone - - @staticmethod - def get_skin_tone_value_shift(sim_info: SimInfo) -> int: - """get_skin_tone_value_shift(sim_info) - - Retrieve the value shift for the Skin Tone of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The value shift for the Skin Tone of a Sim. - :rtype: int - """ - return sim_info.skin_tone_val_shift - - @staticmethod - def set_skin_tone(sim_info: SimInfo, skin_tone: int): - """set_skin_tone(sim_info, skin_tone) - - Set the skin tone of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param skin_tone: The decimal identifier of the skin tone to set the Sim to. - :type skin_tone: int - """ - sim_info.skin_tone = skin_tone - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.attach_cas_part_to_all_outfits', - 'Attach a CAS Part to all outfits of a Sim. This is a permanent change to all of their outfits!', - command_arguments=( - CommonConsoleCommandArgument('cas_part_id', 'Decimal Identifier', 'The decimal identifier of the CAS Part to attach.'), - CommonConsoleCommandArgument('body_type', 'Body Type Name or Number', 'The body type to attach the CAS Part to. If not specified the body type of the CAS Part itself will be used.', is_optional=True, default_value='CAS Part Default Body Type'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to attach the CAS Part to.', is_optional=True, default_value='Active Sim') - ), - command_aliases=( - 's4clib.attachcasparttoalloutfits', - ) -) -def _s4clib_attach_cas_part_to_all_outfits(output: CommonConsoleCommandOutput, cas_part_id: int, body_type: str = 'any', sim_info: SimInfo = None): - if sim_info is None: - return - if cas_part_id < 0: - output('ERROR: CAS Part must be a positive number.') - return - if not CommonCASUtils.is_cas_part_loaded(cas_part_id): - output(f'ERROR: No CAS Part was found with id: {cas_part_id}') - return - if body_type is None: - output('ERROR: No Body Type specified.') - return - if body_type == 'any': - body_type_value = BodyType.NONE - elif isinstance(body_type, int): - body_type_value = body_type - elif isinstance(body_type, str) and body_type.isnumeric(): - try: - body_type_value = int(body_type) - except ValueError: - output(f'ERROR: The specified body type is neither a number nor the name of a BodyType {body_type}') - return - else: - body_type_value = CommonResourceUtils.get_enum_by_name(body_type.upper(), BodyType, default_value=BodyType.NONE) - if body_type_value == BodyType.NONE: - output(f'ERROR: The specified body type is neither a number nor the name of a BodyType {body_type}') - return - - output(f'Attempting to attach CAS Part \'{cas_part_id}\' to Sim {sim_info} at body location {body_type_value}') - cas_part = CommonCASPart(cas_part_id, body_type=body_type_value) - if CommonCASUtils.attach_cas_parts_to_all_outfits_of_sim(sim_info, (cas_part,)): - output(f'SUCCESS: CAS Part has been successfully attached to Sim {sim_info}.') - else: - output(f'FAILED: CAS Part failed to attach to Sim {sim_info}.') - output('Done attaching CAS Part to the Sim.') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.attach_cas_part', - 'Attach a CAS Part to a Sim. This is a permanent change to their current outfit!', - command_arguments=( - CommonConsoleCommandArgument('cas_part_id', 'Decimal Identifier', 'The decimal identifier of the CAS Part to attach.'), - CommonConsoleCommandArgument('body_type', 'Body Type Name or Number', 'The body type to attach the CAS Part to. If not specified the body type of the CAS Part itself will be used.', is_optional=True, default_value='CAS Part Default Body Type'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to attach the CAS Part to.', is_optional=True, default_value='Active Sim') - ), - command_aliases=( - 's4clib.attachcaspart', - ) -) -def _s4clib_attach_cas_part(output: CommonConsoleCommandOutput, cas_part_id: int, body_type: str = 'any', sim_info: SimInfo = None): - if sim_info is None: - return - if cas_part_id < 0: - output('ERROR: CAS Part must be a positive number.') - return - if not CommonCASUtils.is_cas_part_loaded(cas_part_id): - output(f'ERROR: No CAS Part was found with id: {cas_part_id}') - return - if body_type is None: - output('ERROR: No Body Type specified.') - return - if body_type == 'any': - body_type_value = BodyType.NONE - elif isinstance(body_type, int): - body_type_value = body_type - elif isinstance(body_type, str) and body_type.isnumeric(): - try: - body_type_value = int(body_type) - except ValueError: - output(f'ERROR: The specified body type is neither a number nor the name of a BodyType {body_type}') - return - else: - body_type_value = CommonResourceUtils.get_enum_by_name(body_type.upper(), CommonBodySlot, default_value=None) - if body_type_value is None: - body_type_value = CommonResourceUtils.get_enum_by_name(body_type.upper(), BodyType, default_value=BodyType.NONE) - if body_type_value == BodyType.NONE: - output(f'ERROR: The specified body type is neither a number nor the name of a BodyType {body_type}') - return - - if body_type_value == BodyType.NONE: - body_type_value = CommonCASUtils.get_body_type_of_cas_part(cas_part_id) - - output(f'Attempting to attach CAS Part \'{cas_part_id}\' to Sim {sim_info} at body location {body_type_value}') - if CommonCASUtils.attach_cas_part_to_sim(sim_info, cas_part_id, body_type=body_type_value): - output(f'SUCCESS: CAS Part has been successfully attached to Sim {sim_info}.') - else: - output(f'FAILED: CAS Part failed to attach to Sim {sim_info}.') - output('Done attaching CAS Part to the Sim.') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.detach_cas_part', - 'Detach a CAS Part from a Sim. This is a permanent change to their current outfit!', - command_arguments=( - CommonConsoleCommandArgument('cas_part_id', 'Decimal Identifier', 'The decimal identifier of the CAS Part to detach.'), - CommonConsoleCommandArgument('body_type', 'Body Type Name or Number', 'The body type to detach the CAS Part from. If not specified the CAS part will be removed from any body types it is attached to on the Sim.', is_optional=True, default_value='All Body Types'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to detach the CAS Part from.', is_optional=True, default_value='Active Sim') - ), - command_aliases=( - 's4clib.detachcaspart', - ) -) -def _s4clib_detach_cas_part(output: CommonConsoleCommandOutput, cas_part_id: int, body_type: str = 'all', sim_info: SimInfo = None): - if sim_info is None: - return - if cas_part_id < 0: - output('ERROR: CAS Part Id must be a positive number.') - return - if not CommonCASUtils.is_cas_part_loaded(cas_part_id): - output(f'ERROR: No CAS Part was found with id: {cas_part_id}') - return - if body_type is None: - output('ERROR: No Body Type was specified.') - return - if body_type == 'all': - body_type_value = None - elif isinstance(body_type, int): - body_type_value = body_type - elif isinstance(body_type, str) and body_type.isnumeric(): - try: - body_type_value = int(body_type) - except ValueError: - output(f'ERROR: The specified body type is neither a number nor the name of a BodyType {body_type}') - return - else: - body_type_value = CommonResourceUtils.get_enum_by_name(body_type.upper(), CommonBodySlot, default_value=None) - if body_type_value is None: - body_type_value = CommonResourceUtils.get_enum_by_name(body_type.upper(), BodyType, default_value=BodyType.NONE) - - if body_type_value == BodyType.NONE: - body_type_value = CommonCASUtils.get_body_type_of_cas_part(cas_part_id) - output(f'Attempting to detach CAS Part \'{cas_part_id}\' from Sim {sim_info} at Body Type(s) {body_type}') - if CommonCASUtils.detach_cas_part_from_sim(sim_info, cas_part_id, body_type=body_type_value): - output(f'SUCCESS: CAS Part has been successfully detached from Sim {sim_info}.') - else: - output(f'FAILED: CAS Part failed to detach from Sim {sim_info}.') - output('Done detaching CAS Part from the Sim.') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.print_cas_part_at_body_type', - 'Print the Decimal Identifier of the CAS Part located at a specified Body Type on the current outfit of a Sim.', - command_arguments=( - CommonConsoleCommandArgument('body_type', 'Body Type Name or Number', 'The Body Type on the Sim to check.'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to check.', is_optional=True, default_value='Active Sim') - ) -) -def _s4clib_print_cas_part_at_body_type(output: CommonConsoleCommandOutput, body_type: str, sim_info: SimInfo = None): - if sim_info is None: - return - if body_type is None: - output('ERROR: No Body Type was specified.') - return - if isinstance(body_type, int): - body_type_value = body_type - elif isinstance(body_type, str) and not body_type.isnumeric(): - body_type_value = CommonResourceUtils.get_enum_by_name(body_type.upper(), BodyType, default_value=BodyType.NONE) - if body_type_value == BodyType.NONE: - output(f'ERROR: The specified body type is neither a number nor the name of a BodyType {body_type}') - return - else: - try: - body_type_value = int(body_type) - except ValueError: - output(f'ERROR: The specified body type is neither a number nor the name of a BodyType {body_type}') - return - output(f'Attempting to Print the ID of the CAS Part located at body type {body_type} on the outfit of {sim_info}.') - cas_part_id = CommonCASUtils.get_cas_part_id_at_body_type(sim_info, body_type_value) - output(f'Finished locating CAS Part Id. Sim: {sim_info} Body Type: {body_type}: CAS Part Id: {cas_part_id}') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.is_cas_part_available', - 'Determine if a CAS Part is available by its Decimal Identifier.', - command_arguments=( - CommonConsoleCommandArgument('cas_part_id', 'Decimal Identifier', 'The CAS Part to check.'), - ) -) -def _s4clib_is_cas_part_available(output: CommonConsoleCommandOutput, cas_part_id: int): - if cas_part_id is None: - output('ERROR: No CAS Part was specified!') - return - output(f'Checking if CAS Part with Id {cas_part_id} is available.') - if CommonCASUtils.is_cas_part_loaded(cas_part_id): - body_type = CommonCASUtils.get_body_type_of_cas_part(cas_part_id) - output(f'SUCCESS: The CAS Part with id {cas_part_id} is available with body location {body_type}.') - else: - output(f'FAILED: The CAS Part with id {cas_part_id} is not available.') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.print_skin_tone', - 'Print the Id of the Skin Tone of a Sim.', - command_arguments=( - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to retrieve the information from.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.printskintone', - ) -) -def _common_print_skin_tone(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): - if sim_info is None: - output('ERROR: Failed, no Sim was specified or the specified Sim was not found!') - return - output(f'Attempting to print the Skin Tone of Sim {sim_info}.') - output(f'Sim: {sim_info}') - skin_tone_id = CommonCASUtils.get_skin_tone(sim_info) - output(f'Skin Tone: {skin_tone_id}') - skin_tone_value_shift = CommonCASUtils.get_skin_tone_value_shift(sim_info) - output(f'Skin Tone Value Shift: {skin_tone_value_shift}') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.set_skin_tone', - 'Change the Skin Tone of a Sim to a specified Skin Tone.', - command_arguments=( - CommonConsoleCommandArgument('skin_tone_id', 'Decimal Identifier', 'The decimal identifier of the Skin Tone to change the Sim to.'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to change the Skin Tone of.', is_optional=True, default_value='Active Sim') - ), - command_aliases=( - 's4clib.setskintone', - ) -) -def _common_set_skin_tone(output: CommonConsoleCommandOutput, skin_tone_id: int, sim_info: SimInfo = None): - if sim_info is None: - output('ERROR: Failed, no Sim was specified or the specified Sim was not found!') - return - output(f'Attempting to set the skin tone of Sim {sim_info} to \'{skin_tone_id}\'.') - CommonCASUtils.set_skin_tone(sim_info, skin_tone_id) - output(f'Done setting the Skin Tone of the Sim {sim_info}.') diff --git a/Scripts/s4ap/sims4communitylib/utils/cas/common_outfit_utils.py b/Scripts/s4ap/sims4communitylib/utils/cas/common_outfit_utils.py deleted file mode 100644 index 387682d..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/cas/common_outfit_utils.py +++ /dev/null @@ -1,1466 +0,0 @@ -""" -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 -""" -import os - -from animation.arb import Arb -from buffs.appearance_modifier.appearance_modifier import AppearanceModifier -from buffs.appearance_modifier.appearance_modifier_type import AppearanceModifierType -from buffs.appearance_modifier.appearance_tracker import ModifierInfo -from cas.cas import OutfitData -from sims.outfits.outfit_enums import OutfitCategory, BodyType, OutfitFilterFlag, BodyTypeFlag -from sims.sim_info import SimInfo -from sims.sim_info_base_wrapper import SimInfoBaseWrapper -from sims4.utils import classproperty -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.enums.buffs_enum import CommonBuffId -from s4ap.sims4communitylib.enums.tags_enum import CommonGameTag -from s4ap.sims4communitylib.logging.has_class_log import HasClassLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ - CommonConsoleCommandArgument -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.common_log_registry import CommonLogRegistry -from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils -from s4ap.sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils -from s4ap.sims4communitylib.utils.sims.common_buff_utils import CommonBuffUtils -from singletons import DEFAULT -from typing import Tuple, Union, Dict, Callable, Iterator, Set - -ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' - -if ON_RTD: - # noinspection PyMissingOrEmptyDocstring - class OutfitCategory: - - @classproperty - def value_to_name(self) -> Dict['OutfitCategory', str]: - pass - - @classproperty - def name_to_value(self) -> Dict[str, 'OutfitCategory']: - pass - - # noinspection PyMissingOrEmptyDocstring - class BodyType: - NONE = 0 - - @classproperty - def value_to_name(self) -> Dict['BodyType', str]: - pass - - @classproperty - def name_to_value(self) -> Dict[str, 'BodyType']: - pass - - # noinspection PyMissingOrEmptyDocstring - class SimInfo: - pass - -if not ON_RTD: - from sims.outfits.outfit_enums import OutfitCategory, BodyType - from sims.sim_info import SimInfo - - -class CommonOutfitUtils(HasClassLog): - """Utilities for handling Sim outfits. - - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - return ModInfo.get_identity() - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 'common_outfit_utils' - - @classmethod - def has_permission_to_change_to_nude(cls, sim_info: SimInfo) -> CommonTestResult: - """has_permission_to_change_to_nude(sim_info) - - Determine if a Sim has permission to change to their Nude (Bathing) outfit. - - .. note:: In the vanilla game, only Adult and Elder Sims have permission to change to Nude. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of the test. True, if the test passes. False, if the test fails. - :rtype: CommonTestResult - """ - if not CommonAgeUtils.is_teen_adult_or_elder(sim_info): - return CommonTestResult(False, reason=f'{sim_info} does not have permission to change to Nude. They are neither an Adult nor Elder Sim.') - return CommonTestResult(True, reason=f'{sim_info} has permission to change to their Nude outfit.') - - @classmethod - def is_every_day_category(cls, 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 int(outfit_category) == int(OutfitCategory.EVERYDAY) - - @classmethod - def is_formal_category(cls, 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 int(outfit_category) == int(OutfitCategory.FORMAL) - - @classmethod - def is_athletic_category(cls, 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 int(outfit_category) == int(OutfitCategory.ATHLETIC) - - @classmethod - def is_sleep_category(cls, 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 int(outfit_category) == int(OutfitCategory.SLEEP) - - @classmethod - def is_party_category(cls, 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 int(outfit_category) == int(OutfitCategory.PARTY) - - @classmethod - def is_bathing_category(cls, 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 int(outfit_category) == int(OutfitCategory.BATHING) - - @classmethod - def is_career_category(cls, 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 int(outfit_category) == int(OutfitCategory.CAREER) - - @classmethod - def is_situation_category(cls, 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 int(outfit_category) == int(OutfitCategory.SITUATION) - - @classmethod - def is_special_category(cls, 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 int(outfit_category) == int(OutfitCategory.SPECIAL) - - @classmethod - def is_swimwear_category(cls, 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 int(outfit_category) == int(OutfitCategory.SWIMWEAR) - - @classmethod - def is_hot_weather_category(cls, 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 int(outfit_category) == int(OutfitCategory.HOTWEATHER) - except: - return False - - @classmethod - def is_cold_weather_category(cls, 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 int(outfit_category) == int(OutfitCategory.COLDWEATHER) - except: - return False - - @classmethod - def is_batuu_category(cls, 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 int(outfit_category) == int(OutfitCategory.BATUU) - except: - return False - - @classmethod - def get_all_outfit_categories(cls) -> 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) - - @classmethod - def is_wearing_everyday_outfit(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper]) -> 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: Union[SimInfo, SimInfoBaseWrapper] - :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)) - - @classmethod - def is_wearing_formal_outfit(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper]) -> 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: Union[SimInfo, SimInfoBaseWrapper] - :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)) - - @classmethod - def is_wearing_athletic_outfit(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper]) -> 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: Union[SimInfo, SimInfoBaseWrapper] - :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)) - - @classmethod - def is_wearing_sleep_outfit(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper]) -> 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: Union[SimInfo, SimInfoBaseWrapper] - :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)) - - @classmethod - def is_wearing_party_outfit(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper]) -> 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: Union[SimInfo, SimInfoBaseWrapper] - :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)) - - @classmethod - def is_wearing_bathing_outfit(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper]) -> 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: Union[SimInfo, SimInfoBaseWrapper] - :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)) - - @classmethod - def is_wearing_career_outfit(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper]) -> 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: Union[SimInfo, SimInfoBaseWrapper] - :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)) - - @classmethod - def is_wearing_situation_outfit(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper]) -> 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: Union[SimInfo, SimInfoBaseWrapper] - :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)) - - @classmethod - def is_wearing_special_outfit(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper]) -> 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: Union[SimInfo, SimInfoBaseWrapper] - :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)) - - @classmethod - def is_wearing_swimwear_outfit(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper]) -> 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: Union[SimInfo, SimInfoBaseWrapper] - :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)) - - @classmethod - def is_wearing_hot_weather_outfit(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper]) -> 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: Union[SimInfo, SimInfoBaseWrapper] - :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)) - - @classmethod - def is_wearing_cold_weather_outfit(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper]) -> 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: Union[SimInfo, SimInfoBaseWrapper] - :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)) - - @classmethod - def is_wearing_batuu_outfit(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper]) -> 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: Union[SimInfo, SimInfoBaseWrapper] - :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)) - - @classmethod - def is_wearing_towel(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper]) -> CommonTestResult: - """is_wearing_towel(sim_info) - - Determine if a Sim is currently wearing a towel. - - :param sim_info: The Sim to check. - :type sim_info: Union[SimInfo, SimInfoBaseWrapper] - :return: The result of testing. True, if the sim is wearing a towel. False, if not. - :rtype: CommonTestResult - """ - return CommonBuffUtils.has_buff(sim_info, CommonBuffId.IS_WEARING_TOWEL) - - @classmethod - def get_outfit_category_by_name(cls, name: str, default_category: Union[OutfitCategory, None] = OutfitCategory.CURRENT_OUTFIT) -> OutfitCategory: - """get_outfit_category_by_name(name, default_value=OutfitCategory.CURRENT_OUTFIT) - - Retrieve an OutfitCategory by name. - - :param name: The name of an outfit category. - :type name: str - :param default_category: The default outfit category to use if the outfit category is not found using the specified name. Default is OutfitCategory.CURRENT_OUTFIT. - :type default_category: Union[OutfitCategory, None], optional - :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=default_category) - - @classmethod - def convert_value_to_outfit_category(cls, value: Union[OutfitCategory, int]) -> Union[OutfitCategory, int]: - """convert_value_to_outfit_category(value) - - Retrieve an OutfitCategory by value. - - :param value: The value of an outfit category. - :type value: Union[OutfitCategory, int] - :return: The OutfitCategory with the specified value or the specified value if no OutfitCategory was found. - :rtype: Union[OutfitCategory, int] - """ - if isinstance(value, OutfitCategory): - return value - if value in OutfitCategory.value_to_name: - return CommonResourceUtils.get_enum_by_name(OutfitCategory.value_to_name[value], OutfitCategory, default_value=value) - return value - - @classmethod - def get_current_outfit_category(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper]) -> 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: Union[SimInfo, SimInfoBaseWrapper] - :return: The OutfitCategory of the current outfit a Sim is wearing. - :rtype: OutfitCategory - """ - return CommonOutfitUtils.get_current_outfit(sim_info)[0] - - @classmethod - def get_current_outfit_index(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper]) -> 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: Union[SimInfo, SimInfoBaseWrapper] - :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] - - @classmethod - def get_current_outfit(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper]) -> 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: Union[SimInfo, SimInfoBaseWrapper] - :return: The OutfitCategory and index of the current outfit a Sim is wearing. - :rtype: Tuple[OutfitCategory, int] - """ - if sim_info is None: - return OutfitCategory.EVERYDAY, 0 - current_outfit = sim_info.get_current_outfit() - # noinspection PyBroadException - try: - current_outfit_category = cls.convert_value_to_outfit_category(current_outfit[0]) - except: - current_outfit_category = current_outfit[0] - if current_outfit_category is None: - current_outfit_category = current_outfit[0] - return current_outfit_category, current_outfit[1] - - @classmethod - def get_appearance_modifiers_gen(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper], appearance_modifier_type: AppearanceModifierType, include_appearance_modifier_callback: Callable[[ModifierInfo], bool] = None) -> Iterator[AppearanceModifier]: - """get_appearance_modifiers_gen(sim_info, appearance_modifier_type, include_appearance_modifier_callback=None) - - Retrieve the appearance modifiers of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: Union[SimInfo, SimInfoBaseWrapper] - :param appearance_modifier_type: The type of appearance modifiers to retrieve. - :type appearance_modifier_type: AppearanceModifierType - :param include_appearance_modifier_callback: If an appearance modifier matches this callback, then it will be returned. Default is None. - :type include_appearance_modifier_callback: Callable[[ModifierInfo], bool], optional - :return: A collection of appearance modifiers. - :rtype: Iterator[AppearanceModifier] - """ - if sim_info is None: - return tuple() - if not hasattr(sim_info, 'appearance_tracker') or sim_info.appearance_tracker is None: - return tuple() - if appearance_modifier_type is None: - return - active_appearance_modifier_info_library: Dict[AppearanceModifierType, Tuple[ModifierInfo]] = sim_info.appearance_tracker._active_appearance_modifier_infos - if active_appearance_modifier_info_library is None: - return tuple() - if appearance_modifier_type not in active_appearance_modifier_info_library: - return tuple() - modifier_info_list = active_appearance_modifier_info_library[appearance_modifier_type] - if not modifier_info_list: - return tuple() - for modifier_info in modifier_info_list: - if modifier_info is None: - continue - if include_appearance_modifier_callback is not None and not include_appearance_modifier_callback(modifier_info): - continue - yield modifier_info.modifier - - @classmethod - def get_outfit_data(cls, sim_info: Union[Union[SimInfo, SimInfoBaseWrapper], SimInfoBaseWrapper], outfit_category_and_index: Union[Tuple[OutfitCategory, int], None] = None) -> Union[OutfitData, None]: - """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: Union[SimInfo, SimInfoBaseWrapper] - :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 or None if the Sim does not have the specified outfit. - :rtype: Union[OutfitData, None] - """ - if outfit_category_and_index is None: - outfit_category_and_index = CommonOutfitUtils.get_current_outfit(sim_info) - if not cls.has_outfit(sim_info, outfit_category_and_index): - return None - return sim_info.get_outfit(outfit_category_and_index[0], outfit_category_and_index[1]) - - @classmethod - def has_cas_part_attached(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper], 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: Union[SimInfo, SimInfoBaseWrapper] - :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) - - @classmethod - def has_any_cas_parts_attached(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper], 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: Union[SimInfo, SimInfoBaseWrapper] - :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 - - @classmethod - def get_outfit_parts(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper], outfit_category_and_index: Union[Tuple[OutfitCategory, int], None] = None) -> Dict[Union[BodyType, int], 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: Union[SimInfo, SimInfoBaseWrapper] - :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. If an outfit does not exist, an empty dict will be returned. - :rtype: Dict[Union[BodyType, int], int] - """ - if outfit_category_and_index is None: - outfit_category_and_index = CommonOutfitUtils.get_current_outfit(sim_info) - if not cls.has_outfit(sim_info, outfit_category_and_index): - return dict() - 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))) - - @classmethod - def refresh_outfit(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper], outfit_category_and_index: Union[Tuple[OutfitCategory, int], None] = None): - """refresh_outfit(sim_info, outfit_category_and_index=None) - - Refresh the outfit of a Sim. - - :param sim_info: The info of a Sim. - :type sim_info: Union[SimInfo, SimInfoBaseWrapper] - :param outfit_category_and_index: The OutfitCategory and index to refresh. Default is the Sims current outfit. - :type outfit_category_and_index: Tuple[OutfitCategory, int], optional - """ - if outfit_category_and_index is None: - outfit_category_and_index = CommonOutfitUtils.get_current_outfit(sim_info) - if not cls.has_outfit(sim_info, outfit_category_and_index): - return - cls.trigger_outfit_generated(sim_info, outfit_category_and_index) - cls.set_outfit_dirty(sim_info, outfit_category_and_index[0]) - cls.set_current_outfit(sim_info, outfit_category_and_index) - - @classmethod - def trigger_outfit_generated(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper], outfit_category_and_index: Tuple[OutfitCategory, int]): - """trigger_outfit_generated(sim_info, outfit_category_and_index) - - Trigger the outfit generated callbacks for a Sim with an OutfitCategory and Index. - - :param sim_info: The info of a Sim. - :type sim_info: Union[SimInfo, SimInfoBaseWrapper] - :param outfit_category_and_index: The OutfitCategory and index to send. - :type outfit_category_and_index: Tuple[OutfitCategory, int] - """ - sim_info.on_outfit_generated(*outfit_category_and_index) - - @classmethod - def set_current_outfit(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper], 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: Union[SimInfo, SimInfoBaseWrapper] - :param outfit_category_and_index: The OutfitCategory and index to change to. - :type outfit_category_and_index: Tuple[OutfitCategory, int] - """ - arb = Arb() - sim_info.try_set_current_outfit(outfit_category_and_index, arb=arb) - - @classmethod - def set_outfit_dirty(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper], 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: Union[SimInfo, SimInfoBaseWrapper] - :param outfit_category: The OutfitCategory being flagged. - :type outfit_category: OutfitCategory - """ - sim_info.set_outfit_dirty(outfit_category) - - @classmethod - def set_outfit_clean(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper], 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: Union[SimInfo, SimInfoBaseWrapper] - :param outfit_category: The OutfitCategory being flagged. - :type outfit_category: OutfitCategory - """ - sim_info.clear_outfit_dirty(outfit_category) - - @classmethod - def generate_outfit( - cls, - sim_info: Union[SimInfo, SimInfoBaseWrapper], - outfit_category_and_index: Tuple[OutfitCategory, int], - tag_list: Tuple[CommonGameTag] = (), - outfit_filter_flag: OutfitFilterFlag = DEFAULT, - body_type_flags: BodyTypeFlag = DEFAULT, - ignore_if_exists: bool = False, - **kwargs - ) -> bool: - """generate_outfit(\ - sim_info,\ - outfit_category_and_index,\ - tag_list=(),\ - outfit_filter_flag=DEFAULT,\ - body_type_flags=DEFAULT,\ - ignore_if_exists=False,\ - **kwargs\ - ) - - 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: Union[SimInfo, SimInfoBaseWrapper] - :param outfit_category_and_index: The OutfitCategory and Index of the outfit to generate. - :type outfit_category_and_index: Tuple[OutfitCategory, int] - :param tag_list: A collection of tags to match CAS Parts to. Default is any tag. - :type tag_list: Tuple[CommonGameTag], optional - :param outfit_filter_flag: Flags to filter CAS Parts with. Default is no flags. - :type outfit_filter_flag: OutfitFilterFlag, optional - :param body_type_flags: Flags to filter CAS Parts with. Default is no flags. - :type body_type_flags: BodyTypeFlag, optional - :param ignore_if_exists: If set to True, the outfit will not be generated if an outfit already exists at the specified Outfit Category and Index. - :return: True, if an outfit was generated successfully. False, if not. - :rtype: bool - """ - - if ignore_if_exists and CommonOutfitUtils.has_outfit(sim_info, outfit_category_and_index): - cls.get_log().format_with_message('Outfit already existed, no need to generate it!', sim=sim_info, outfit_category_and_index=outfit_category_and_index) - return False - - outfit_category = outfit_category_and_index[0] - outfit_index = outfit_category_and_index[1] - return sim_info.generate_outfit(outfit_category, outfit_index=outfit_index, tag_list=tag_list, filter_flag=outfit_filter_flag, body_type_flags=body_type_flags, **kwargs) - - @classmethod - def copy_outfit(cls, mod_identity: CommonModIdentity, sim_info: SimInfo, from_outfit_category_and_index: Tuple[OutfitCategory, int], to_outfit_category_and_index: Tuple[OutfitCategory, int], change_sim_to_outfit_after_apply: bool = False) -> bool: - """copy_outfit(mod_identity, sim_info, from_outfit_category_and_index, to_outfit_category_and_index, change_sim_to_outfit_after_apply=False) - - Copy one Outfit of a Sim to another Outfit of the same Sim. - - :param mod_identity: The identity of the mod copying the outfit. - :type mod_identity: CommonModIdentity - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param from_outfit_category_and_index: The Outfit Category and Index to copy CAS Parts from. - :type from_outfit_category_and_index: Tuple[OutfitCategory, int] - :param to_outfit_category_and_index: The Outfit Category and Index to copy CAS Parts to. - :type to_outfit_category_and_index: Tuple[OutfitCategory, int] - :param change_sim_to_outfit_after_apply: Set to True to change the Sim to the outfit after the changes are applied. Default is False. - :type change_sim_to_outfit_after_apply: bool, optional - :return: True, if CAS Parts were copied successfully. False, if not. - :rtype: bool - """ - from s4ap.sims4communitylib.services.sim.cas.common_sim_outfit_io import CommonSimOutfitIO - outfit_io = CommonSimOutfitIO(sim_info, outfit_category_and_index=from_outfit_category_and_index, mod_identity=mod_identity) - return outfit_io.apply(change_sim_to_outfit_after_apply=change_sim_to_outfit_after_apply, apply_to_all_outfits_in_same_category=False, apply_to_outfit_category_and_index=to_outfit_category_and_index) - - @classmethod - def regenerate_outfit(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper], outfit_category_and_index: Tuple[OutfitCategory, int]) -> None: - """regenerate_outfit(sim_info, outfit_category_and_index) - - Delete and regenerate an outfit of a Sim. - - .. note:: If the Sim does not have the specified outfit to regenerate, it will be generated instead. - - :param sim_info: An instance of a Sim. - :type sim_info: Union[SimInfo, SimInfoBaseWrapper] - :param outfit_category_and_index: The OutfitCategory and index to regenerate for the Sim. - :type outfit_category_and_index: Tuple[OutfitCategory, int] - """ - current_outfit = CommonOutfitUtils.get_current_outfit(sim_info) - outfit_flags = OutfitFilterFlag.USE_EXISTING_IF_APPROPRIATE & OutfitFilterFlag.USE_VALID_FOR_LIVE_RANDOM - tags = tuple() - from s4ap.sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils - if CommonSimGenderOptionUtils.prefers_menswear(sim_info): - tags = (CommonGameTag.GENDER_APPROPRIATE_MALE,) - elif CommonSimGenderOptionUtils.prefers_womenswear(sim_info): - tags = (CommonGameTag.GENDER_APPROPRIATE_FEMALE,) - outfit = outfit_category_and_index - cls.get_log().format_with_message('Generating outfit', outfit=outfit) - generate_result = CommonOutfitUtils.generate_outfit(sim_info, outfit, outfit_filter_flag=outfit_flags, tag_list=tags) - cls.get_log().format_with_message('Finished generating outfit', outfit=outfit, generate_result=generate_result, outfit_flags=outfit_flags, tags=tags) - sim_info.appearance_tracker.evaluate_appearance_modifiers() - CommonOutfitUtils.resend_outfits(sim_info) - CommonOutfitUtils.set_current_outfit(sim_info, current_outfit) - - @classmethod - def regenerate_all_outfits(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper]) -> None: - """regenerate_all_outfits(sim_info) - - Delete and regenerate all outfits for a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: Union[SimInfo, SimInfoBaseWrapper] - """ - current_outfit = CommonOutfitUtils.get_current_outfit(sim_info) - outfit_flags = OutfitFilterFlag.USE_EXISTING_IF_APPROPRIATE & OutfitFilterFlag.USE_VALID_FOR_LIVE_RANDOM - tags = tuple() - from s4ap.sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils - if CommonSimGenderOptionUtils.prefers_menswear(sim_info): - tags = (CommonGameTag.GENDER_APPROPRIATE_MALE,) - elif CommonSimGenderOptionUtils.prefers_womenswear(sim_info): - tags = (CommonGameTag.GENDER_APPROPRIATE_FEMALE,) - for outfit_category in CommonOutfitUtils.get_all_outfit_categories(): - for outfit_index in range(cls.get_maximum_number_of_outfits_for_category(outfit_category)): - outfit = (outfit_category, outfit_index) - if not CommonOutfitUtils.has_outfit(sim_info, outfit): - cls.get_log().format_with_message('Sim did not have outfit.', sim=sim_info, outfit=outfit) - continue - cls.get_log().format_with_message('Generating outfit', outfit=outfit) - generate_result = CommonOutfitUtils.generate_outfit(sim_info, outfit, outfit_filter_flag=outfit_flags, tag_list=tags) - cls.get_log().format_with_message('Finished generating outfit', outfit=outfit, generate_result=generate_result, outfit_flags=outfit_flags, tags=tags) - sim_info.appearance_tracker.evaluate_appearance_modifiers() - CommonOutfitUtils.resend_outfits(sim_info) - CommonOutfitUtils.set_current_outfit(sim_info, current_outfit) - - @classmethod - def resend_outfits(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper]) -> 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: Union[SimInfo, SimInfoBaseWrapper] - :return: True, if outfits were resent successfully. False, if not. - :rtype: bool - """ - sim_info.resend_outfits() - return True - - @classmethod - def get_maximum_number_of_outfits_for_category(cls, outfit_category: OutfitCategory) -> int: - """get_maximum_number_of_outfits_for_category(outfit_category) - - Retrieve the maximum number of outfits allowed for an outfit category. - - :param outfit_category: The outfit category to check. - :type outfit_category: OutfitCategory - :return: The maximum number of Outfits a Sim may have within the specified outfit category. - :rtype: int - """ - if outfit_category is None: - return 0 - from sims.outfits.outfit_utils import get_maximum_outfits_for_category - return get_maximum_outfits_for_category(outfit_category) - - @classmethod - def get_previous_outfit(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper], 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: Union[SimInfo, SimInfoBaseWrapper] - :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 - - @classmethod - def remove_previous_outfit(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper]): - """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: Union[SimInfo, SimInfoBaseWrapper] - """ - sim_info.set_previous_outfit(None, force=True) - - @classmethod - def get_all_outfit_category_and_indexes(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper], include_outfit_categories: Tuple[OutfitCategory] = ()) -> Tuple[Tuple[OutfitCategory, int]]: - """get_all_outfit_category_and_indexes(sim_info, include_outfit_categories=()) - - Retrieve a collection of outfit category and index for each outfit available to a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: Union[SimInfo, SimInfoBaseWrapper] - :param include_outfit_categories: A collection of outfit categories to include. If empty, all outfit categories will be included. Default is empty. - :type include_outfit_categories: Tuple[OutfitCategory], optional - :return: A collection of outfit category and index for each outfit available to a Sim. - :rtype: Tuple[Tuple[OutfitCategory, int]] - """ - outfits = sim_info.get_outfits() - outfit_list = list() - for (outfit_category, _outfit_list) in outfits.get_all_outfits(): - outfit_category: OutfitCategory = outfit_category - if include_outfit_categories and outfit_category not in include_outfit_categories: - continue - for (outfit_index, _) in enumerate(_outfit_list): - outfit_index: int = outfit_index - outfit_list.append((outfit_category, outfit_index)) - return tuple(outfit_list) - - @classmethod - def has_outfit(cls, sim_info: Union[Union[SimInfo, SimInfoBaseWrapper], SimInfoBaseWrapper], 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: Union[Union[SimInfo, SimInfoBaseWrapper], SimInfoBaseWrapper] - :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) - - @classmethod - def update_outfits(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper]) -> bool: - """update_outfits(sim_info) - - Update all outfits of a Sim. - - :param sim_info: The Sim to update outfits for. - :type sim_info: Union[SimInfo, SimInfoBaseWrapper] - :return: True, if the outfits were updated successfully. False, if not. - :rtype: bool - """ - sim_info.on_outfit_changed(sim_info, CommonOutfitUtils.get_current_outfit(sim_info), CommonOutfitUtils.get_current_outfit(sim_info)) - CommonOutfitUtils.resend_outfits(sim_info) - sim_info.appearance_tracker.evaluate_appearance_modifiers() - return True - - @classmethod - def has_tag_on_outfit(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper], tag: Union[int, CommonGameTag], outfit_category_and_index: Union[Tuple[OutfitCategory, int], None] = None) -> bool: - """has_tag_on_outfit(sim_info, tag, outfit_category_and_index=None) - - Determine if the Outfit of a Sim has the specified tag. - - :param sim_info: An instance of a Sim. - :type sim_info: Union[SimInfo, SimInfoBaseWrapper] - :param tag: A tag to locate. - :type tag: Union[int, CommonGameTag] - :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: True, if the Outfit of the Sim has the specified tag. False, if not. - :rtype: bool - """ - return CommonOutfitUtils.has_any_tags_on_outfit(sim_info, (tag, ), outfit_category_and_index=outfit_category_and_index) - - @classmethod - def has_any_tags_on_outfit(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper], tags: Iterator[Union[int, CommonGameTag]], outfit_category_and_index: Union[Tuple[OutfitCategory, int], None] = None) -> bool: - """has_any_tags_on_outfit(sim_info, tags, outfit_category_and_index=None) - - Determine if the Outfit of a Sim has any of the specified tags. - - :param sim_info: An instance of a Sim. - :type sim_info: Union[SimInfo, SimInfoBaseWrapper] - :param tags: A collection of tags to locate. - :type tags: Iterator[Union[int, CommonGameTag]] - :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: True, if the Outfit of the Sim has any of the specified tags. False, if not. - :rtype: bool - """ - if sim_info is None: - return False - if not tags: - return False - outfit_tags = CommonOutfitUtils.get_all_outfit_tags(sim_info, outfit_category_and_index=outfit_category_and_index) - for tag in tags: - if tag in outfit_tags: - return True - return False - - @classmethod - def has_all_tags_on_outfit(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper], tags: Iterator[Union[int, CommonGameTag]], outfit_category_and_index: Union[Tuple[OutfitCategory, int], None] = None) -> bool: - """has_all_tags_on_outfit(sim_info, tags, outfit_category_and_index=None) - - Determine if the Outfit of a Sim has all of the specified tags. - - :param sim_info: An instance of a Sim. - :type sim_info: Union[SimInfo, SimInfoBaseWrapper] - :param tags: A collection of tags to locate. - :type tags: Iterator[Union[int, CommonGameTag]] - :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: True, if the Outfit of the Sim has all of the specified tags. False, if not. - :rtype: bool - """ - if sim_info is None: - return False - if not tags: - return False - outfit_tags = CommonOutfitUtils.get_all_outfit_tags(sim_info, outfit_category_and_index=outfit_category_and_index) - for tag in tags: - if tag not in outfit_tags: - return False - return True - - @classmethod - def get_all_outfit_tags(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper], outfit_category_and_index: Union[Tuple[OutfitCategory, int], None] = None) -> Tuple[CommonGameTag]: - """get_all_outfit_tags(sim_info, outfit_category_and_index=None) - - Retrieve a collection of game tags that apply to the outfit of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: Union[SimInfo, SimInfoBaseWrapper] - :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 collection of Game Tags that apply to the outfit of a Sim. - :rtype: Tuple[CommonGameTag] - """ - if sim_info is None: - return tuple() - combined_game_tags = list() - for game_tags in CommonOutfitUtils.get_outfit_tags_by_cas_part_id(sim_info, outfit_category_and_index=outfit_category_and_index).values(): - for game_tag in game_tags: - if game_tag not in combined_game_tags: - combined_game_tags.append(game_tag) - return tuple(combined_game_tags) - - @classmethod - def get_outfit_tags_by_cas_part_id(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper], outfit_category_and_index: Union[Tuple[OutfitCategory, int], None] = None) -> Dict[int, Set[CommonGameTag]]: - """get_outfit_tags_by_cas_part_id(sim_info, outfit_category_and_index=None) - - Retrieve the game tags of the outfit of a Sim grouped by CAS Part Id. - - :param sim_info: An instance of a Sim. - :type sim_info: Union[SimInfo, SimInfoBaseWrapper] - :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 library of Game Tags grouped by CAS Part Id. - :rtype: Dict[int, Tuple[CommonGameTag]] - """ - if sim_info is None: - return dict() - from cas.cas import get_tags_from_outfit - outfit_category_and_index = outfit_category_and_index or CommonOutfitUtils.get_current_outfit(sim_info) - # noinspection PyBroadException - try: - return get_tags_from_outfit(sim_info._base, outfit_category_and_index[0], outfit_category_and_index[1]) - except: - return dict() - - @classmethod - def _print_outfit(cls, sim_info: SimInfo, outfit_category: OutfitCategory, outfit_index: int, output: CommonConsoleCommandOutput): - from s4ap.sims4communitylib.services.sim.cas.common_sim_outfit_io import CommonSimOutfitIO - if not isinstance(outfit_category, OutfitCategory): - # noinspection PyBroadException - try: - outfit_category = CommonResourceUtils.get_enum_by_int_value(int(outfit_category), OutfitCategory, default_value=outfit_category) - except: - output(f'ERROR: Failed to parse {outfit_category} as OutfitCategory.') - return - - # noinspection PyBroadException - if hasattr(outfit_category, 'name'): - outfit_category_name = outfit_category.name - else: - outfit_category_name = outfit_category - - output(f'Outfit Info for outfit ({outfit_category_name}, {outfit_index}) of Sim {sim_info}') - outfit_commands_log.debug(f'Outfit Info for outfit ({outfit_category_name}, {outfit_index}) of Sim {sim_info}') - outfit_io = CommonSimOutfitIO(sim_info, outfit_category_and_index=(outfit_category, outfit_index)) - output(f'------Outfit: ({outfit_category_name}, {outfit_index})------') - outfit_commands_log.debug(f'------Outfit: ({outfit_category_name}, {outfit_index})------') - for (body_type, cas_part_id) in zip(outfit_io.body_types, outfit_io.cas_part_ids): - body_type_value = int(body_type) - if not isinstance(body_type, BodyType): - # noinspection PyBroadException - try: - body_type = CommonResourceUtils.get_enum_by_int_value(int(body_type), BodyType, default_value=body_type) - except: - output(f' {str(body_type)} ({body_type_value}): {cas_part_id}') - outfit_commands_log.debug(f'{str(body_type)} ({body_type_value}): {cas_part_id}') - continue - if hasattr(body_type, 'name'): - body_type_name = body_type.name - else: - body_type_name = str(body_type) - output(f' {body_type_name} ({body_type_value}): {cas_part_id}') - outfit_commands_log.debug(f'{body_type_name} ({body_type_value}): {cas_part_id}') - output('----------------------------') - output('-') - outfit_commands_log.debug('----------------------------') - outfit_commands_log.debug('-') - - @classmethod - def _parse_outfit_category_and_index_from_str(cls, output: CommonConsoleCommandOutput, outfit_category: str, outfit_index: int, sim_info: SimInfo = None, check_for_missing_outfit: bool = True, outfit_category_required: bool = False) -> Union[Tuple[OutfitCategory, int], None]: - outfit_category_value_names = ', '.join(OutfitCategory.name_to_value.keys()) - if outfit_category is None: - if outfit_category_required: - output(f'ERROR: Outfit Category not specified. Valid OutfitCategory: ({outfit_category_value_names})') - return None - if outfit_index <= 0: - output('ERROR: Outfit Index must be a value above Zero.') - return None - if not outfit_category.isnumeric(): - outfit_category_value = CommonResourceUtils.get_enum_by_name(outfit_category.upper(), OutfitCategory, default_value=None) - if outfit_category_value is None: - output(f'ERROR: No Outfit Category existed with name {outfit_category}. Valid OutfitCategory: ({outfit_category_value_names})') - return - else: - try: - outfit_category_value = int(outfit_category) - except ValueError: - output(f'ERROR: The specified outfit category is neither a number nor the name of an OutfitCategory {outfit_category}. Valid OutfitCategory: ({outfit_category_value_names})') - return - outfit_category_value = CommonResourceUtils.get_enum_by_int_value(outfit_category_value, OutfitCategory, default_value=None) - if outfit_category_value is None: - output(f'ERROR: No Outfit Category existed with value {outfit_category}. Valid OutfitCategory: ({outfit_category_value_names})') - return - - outfit_category_and_index = (outfit_category_value, outfit_index) - if check_for_missing_outfit and sim_info is not None: - if not CommonOutfitUtils.has_outfit(sim_info, outfit_category_and_index): - output(f'ERROR: The Sim {sim_info} did not have the specified outfit {outfit_category_and_index[0].name} at index {outfit_category_and_index[1]}') - return - return outfit_category_and_index - - -outfit_commands_log = CommonLogRegistry().register_log(ModInfo.get_identity(), 's4cl_outfit_commands') -outfit_commands_log.enable() - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_testing.print_all_outfit_categories', - 'Print a list of all outfit categories that are available to Sims.' -) -def _s4clib_testing_print_all_outfit_categories(output: CommonConsoleCommandOutput): - output('Printing all outfit categories.') - outfit_categories_name_str = ', '.join([outfit_category.name if hasattr(outfit_category, 'name') else str(outfit_category) for outfit_category in CommonOutfitUtils.get_all_outfit_categories()]) - output(f'Outfit categories: {outfit_categories_name_str}') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_testing.print_outfit_tags', - 'Print a list of all Game Tags applied to the outfit of a Sim.', - command_arguments=( - CommonConsoleCommandArgument('outfit_category', 'Value or Name', 'The Value or Name of the Outfit Category to check.', is_optional=True, default_value='Current Outfit'), - CommonConsoleCommandArgument('outfit_index', 'Positive Number', 'The index of the outfit to check. This value does nothing if an Outfit Category is not specified.', is_optional=True, default_value=1), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to check.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib_testing.printoutfittags', - ) -) -def _s4clib_testing_print_outfit_tags(output: CommonConsoleCommandOutput, outfit_category: str = None, outfit_index: int = 1, sim_info: SimInfo = None): - if sim_info is None: - return - outfit_category_and_index = CommonOutfitUtils._parse_outfit_category_and_index_from_str(output, outfit_category=outfit_category, outfit_index=outfit_index, sim_info=sim_info) - if outfit_category_and_index is None: - outfit_category_and_index = CommonOutfitUtils.get_current_outfit(sim_info) - - output(f'Attempting to print all game tags of outfit ({outfit_category_and_index[0].name}, {outfit_category_and_index[1]}) for Sim {sim_info}.') - outfit_commands_log.debug(f'Printing all game tags of outfit ({outfit_category_and_index[0].name}, {outfit_category_and_index[1]}) for Sim {sim_info}.') - outfit_commands_log.debug(f'-------Game Tags For Outfit Category: ({outfit_category_and_index[0].name}, {outfit_category_and_index[1]})-------') - tag_values = CommonOutfitUtils.get_all_outfit_tags(sim_info, outfit_category_and_index=outfit_category_and_index) - cleaned_tag_names = list() - for tag_value in tag_values: - if isinstance(tag_value, CommonGameTag): - tag = tag_value - else: - tag = CommonResourceUtils.get_enum_by_int_value(int(tag_value), CommonGameTag, default_value=tag_value) - cleaned_tag_names.append(tag.name if hasattr(tag, 'name') else str(tag)) - - sorted_tag_names = sorted(cleaned_tag_names) - tags_str = ', '.join(sorted_tag_names) - output(f'Game Tags: {tags_str}') - for sorted_tag_name in sorted_tag_names: - outfit_commands_log.debug(str(sorted_tag_name)) - outfit_commands_log.debug(f'--------------------------------') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_testing.print_outfit_tags_by_cas_part', - 'Print a list of the Game Tags applied to each CAS Part in the outfit of a Sim.', - command_arguments=( - CommonConsoleCommandArgument('outfit_category', 'Value or Name', 'The Value or Name of the Outfit Category to check.', is_optional=True, default_value='Current Outfit'), - CommonConsoleCommandArgument('outfit_index', 'Positive Number', 'The index of the outfit to check. This value does nothing if an Outfit Category is not specified.', is_optional=True, default_value=1), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to check.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib_testing.printoutfittagsbycaspart', - ) -) -def _s4clib_testing_print_outfit_tags_by_cas_part(output: CommonConsoleCommandOutput, outfit_category: str = None, outfit_index: int = 1, sim_info: SimInfo = None): - from s4ap.sims4communitylib.utils.cas.common_cas_utils import CommonCASUtils - if sim_info is None: - return - outfit_category_and_index = CommonOutfitUtils._parse_outfit_category_and_index_from_str(output, outfit_category=outfit_category, outfit_index=outfit_index, sim_info=sim_info) - if outfit_category_and_index is None: - outfit_category_and_index = CommonOutfitUtils.get_current_outfit(sim_info) - output(f'Attempting to print game tags for each CAS Part in outfit ({outfit_category_and_index[0].name}, {outfit_category_and_index[1]}) for Sim {sim_info}.') - outfit_commands_log.debug(f'Printing all game tags for each CAS Part in outfit ({outfit_category_and_index[0].name}, {outfit_category_and_index[1]}) for Sim {sim_info}.') - outfit_commands_log.debug(f'-------Game Tags For CAS Parts of Outfit Category: ({outfit_category_and_index[0].name}, {outfit_category_and_index[1]})-------') - tags_by_cas_part_id = CommonOutfitUtils.get_outfit_tags_by_cas_part_id(sim_info, outfit_category_and_index=outfit_category_and_index) - for (cas_part_id, tag_values) in tags_by_cas_part_id.items(): - output(f'CAS Part Id: {cas_part_id}') - body_type_val = int(CommonCASUtils.get_body_type_cas_part_is_attached_to(sim_info, cas_part_id)) - body_type = CommonResourceUtils.get_enum_by_int_value(body_type_val, BodyType, default_value=None) - if body_type is None: - body_type = str(body_type_val) - body_type_str = body_type.name if hasattr(body_type, 'name') else str(body_type) - output(f'Body Type: {body_type_str}') - cleaned_tag_names = list() - for tag_value in tag_values: - if isinstance(tag_value, CommonGameTag): - tag = tag_value - else: - tag = CommonResourceUtils.get_enum_by_int_value(int(tag_value), CommonGameTag, default_value=None) - if tag is None: - tag = str(tag_value) - cleaned_tag_names.append(tag.name if hasattr(tag, 'name') else str(tag)) - sorted_tag_names = sorted(cleaned_tag_names) - tags_str = ', '.join(sorted_tag_names) - output(f'Game Tags: {tags_str}') - outfit_commands_log.debug( - f'---ID: {cas_part_id} (BodyType: {body_type_str})---') - for sorted_tag_name in sorted_tag_names: - outfit_commands_log.debug(str(sorted_tag_name)) - outfit_commands_log.debug(f'---------') - - outfit_commands_log.debug(f'--------------------------------') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.print_previous_outfit', - 'Print information about the previous outfit a Sim was wearing.', - command_arguments=( - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to check.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.printpreviousoutfit', - ) -) -def _s4clib_print_previous_outfit(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): - if sim_info is None: - output('ERROR: Failed, no Sim was specified or the specified Sim was not found!') - return - previous_outfit = CommonOutfitUtils.get_previous_outfit(sim_info, default_outfit_category_and_index=tuple()) - if not previous_outfit: - output(f'FAILED: No information about the previous outfit was found for {sim_info}') - return - output(f'Previous Outfit Info for {sim_info}') - outfit_commands_log.debug(f'Previous Outfit Info for {sim_info}') - CommonOutfitUtils._print_outfit(sim_info, previous_outfit[0], previous_outfit[1], output) - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.print_outfit', - 'Print information about an outfit a Sim has.', - command_arguments=( - CommonConsoleCommandArgument('outfit_category', 'Value or Name', 'The Value or Name of the Outfit Category to check.', is_optional=True, default_value='Current Outfit'), - CommonConsoleCommandArgument('outfit_index', 'Positive Number', 'The index of the outfit to check. This value does nothing if an Outfit Category is not specified.', is_optional=True, default_value=1), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to check.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.printoutfit', - ) -) -def _s4clib_print_outfit(output: CommonConsoleCommandOutput, outfit_category: str = None, outfit_index: int = 1, sim_info: SimInfo = None): - if sim_info is None: - output('Failed, no Sim was specified or the specified Sim was not found!') - return - outfit_category_and_index = CommonOutfitUtils._parse_outfit_category_and_index_from_str(output, outfit_category, outfit_index=outfit_index, sim_info=sim_info) - if outfit_category_and_index is None: - outfit_category_and_index = CommonOutfitUtils.get_current_outfit(sim_info) - CommonOutfitUtils._print_outfit(sim_info, outfit_category_and_index[0], outfit_category_and_index[1], output) - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.print_outfits', - 'Print information about all outfits of a Sim.', - command_arguments=( - CommonConsoleCommandArgument('show_missing_outfit_info', 'True or False', 'If True, information about the outfits a Sim does not have will be displayed.', is_optional=True, default_value=False), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to print the outfits of.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.printoutfits', - ) -) -def _s4clib_print_outfits(output: CommonConsoleCommandOutput, show_missing_outfit_info: bool = False, sim_info: SimInfo = None): - if sim_info is None: - output('ERROR: no Sim was specified or the specified Sim was not found!') - return - current_outfit = CommonOutfitUtils.get_current_outfit(sim_info) - current_outfit_category = current_outfit[0] - if not isinstance(current_outfit_category, OutfitCategory): - # noinspection PyBroadException - try: - current_outfit_category = CommonResourceUtils.get_enum_by_int_value(int(current_outfit_category), OutfitCategory, default_value=current_outfit_category) - except: - output(f'ERROR: Failed to parse {current_outfit_category} as Outfit Category.') - return - - # noinspection PyBroadException - if hasattr(current_outfit_category, 'name'): - current_outfit_category_name = current_outfit_category.name - else: - current_outfit_category_name = current_outfit_category - - output(f'Outfit Info for {sim_info}, Current Outfit: ({current_outfit_category_name}, {current_outfit[1]})') - outfit_commands_log.debug(f'Outfit Info for {sim_info}, Current Outfit: ({current_outfit_category_name}, {current_outfit[1]})') - output('------') - outfit_commands_log.debug('------') - for outfit_category in CommonOutfitUtils.get_all_outfit_categories(): - # noinspection PyBroadException - try: - outfit_category_name = outfit_category.name - except: - outfit_category_name = outfit_category - - for outfit_index in range(CommonOutfitUtils.get_maximum_number_of_outfits_for_category(outfit_category)): - if not CommonOutfitUtils.has_outfit(sim_info, (outfit_category, outfit_index)): - if show_missing_outfit_info: - output(f'MISSING: Sim {sim_info} did not have outfit ({outfit_category_name}, {outfit_index})') - outfit_commands_log.debug(f'MISSING: Sim {sim_info} did not have outfit ({outfit_category_name}, {outfit_index})') - continue - CommonOutfitUtils._print_outfit(sim_info, outfit_category, outfit_index, output) - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.generate_outfit', - 'Generate an outfit for a Sim.', - command_arguments=( - CommonConsoleCommandArgument('outfit_category', 'Value or Name', 'The Value or Name of the Outfit Category to generate.'), - CommonConsoleCommandArgument('outfit_index', 'Positive Number', 'The index of the outfit to generate.'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to generate an outfit for.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.generateoutfit', - ) -) -def _s4clib_generate_outfit(output: CommonConsoleCommandOutput, outfit_category: str = None, outfit_index_val: int = 1, sim_info: SimInfo = None): - outfit_category_and_index = CommonOutfitUtils._parse_outfit_category_and_index_from_str(output, outfit_category, outfit_index_val, sim_info=sim_info, check_for_missing_outfit=False, outfit_category_required=True) - if outfit_category_and_index is None: - return - if sim_info is None: - output('ERROR: No Sim was specified or the specified Sim was not found!') - return - outfit_category_value = outfit_category_and_index[0] - outfit_category_name = outfit_category_value.name - outfit_index = outfit_category_and_index[1] - output(f'Attempting to generate outfit ({outfit_category_name}, {outfit_index}) for Sim {sim_info}') - if CommonOutfitUtils.has_outfit(sim_info, (outfit_category_value, outfit_index)): - output(f'FAILED: Sim {sim_info} already has an outfit ({outfit_category_name}, {outfit_index})') - return - generated = CommonOutfitUtils.generate_outfit(sim_info, (outfit_category_value, outfit_index)) - if generated: - output(f'SUCCESS: Outfit ({outfit_category_name}, {outfit_index}) has been successfully generated for Sim {sim_info}.') - else: - output(f'FAILED: Outfit ({outfit_category_name}, {outfit_index}) failed to generate for Sim {sim_info}.') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.regenerate_outfit', - 'Regenerate an outfit of a Sim.', - command_arguments=( - CommonConsoleCommandArgument('outfit_category', 'Value or Name', 'The Value or Name of the Outfit Category to regenerate.', is_optional=True, default_value='Current Outfit'), - CommonConsoleCommandArgument('outfit_index', 'Positive Number', 'The index of the outfit to regenerate. This value does nothing if an Outfit Category is not specified.', is_optional=True, default_value=1), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to regenerate the outfit of.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.regenerateoutfit', - ) -) -def _common_regenerate_outfit(output: CommonConsoleCommandOutput, outfit_category: str = None, outfit_index: int = 1, sim_info: SimInfo = None): - outfit_category_and_index = CommonOutfitUtils._parse_outfit_category_and_index_from_str(output, outfit_category, outfit_index, sim_info=sim_info) - if outfit_category_and_index is None: - return - if sim_info is None: - output('ERROR: No Sim was specified or the specified Sim was not found!') - return - output(f'Attempting to regenerate the current outfit of {sim_info}') - CommonOutfitUtils.regenerate_outfit(sim_info, outfit_category_and_index) - output(f'Done regenerating the current outfit of {sim_info}') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.regenerate_all_outfits', - 'Regenerate all outfits of a Sim.', - command_arguments=( - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to regenerate the outfit of.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.regeneratealloutfits', - ) -) -def _common_regenerate_all_outfits(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): - if sim_info is None: - output('ERROR: No Sim was specified or the specified Sim was not found!') - return - output(f'Attempting to regenerate all outfits for {sim_info}') - CommonOutfitUtils.regenerate_all_outfits(sim_info) - output(f'Done regenerating all outfits for {sim_info}.') diff --git a/Scripts/s4ap/sims4communitylib/utils/common_collection_utils.py b/Scripts/s4ap/sims4communitylib/utils/common_collection_utils.py deleted file mode 100644 index f8c6815..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/common_collection_utils.py +++ /dev/null @@ -1,260 +0,0 @@ -""" -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 -""" -import itertools -from typing import List, Any, Dict, Union, Tuple, Set - - -class CommonCollectionUtils: - """Utilities for collections. - - """ - @staticmethod - def is_collection(obj: Any) -> bool: - """is_collection(obj) - - Determine if an object is a collection or not. - - :param obj: An object. - :type obj: Any - :return: True, if the object is a collection, False, if not. - :rtype: bool - """ - if obj is None: - return False - return isinstance(obj, list)\ - or isinstance(obj, tuple)\ - or isinstance(obj, set)\ - or isinstance(obj, frozenset)\ - or isinstance(obj, dict) - - @staticmethod - def lists_are_equal(list_one: Union[Tuple[Any], List[Any]], list_two: Union[Tuple[Any], List[Any]]) -> bool: - """lists_are_equal(list_one, list_two) - - Determine if two collections contain tbe exact same values. - - .. note:: The order of the values in each collection will be asserted. - - :param list_one: The first value. (Can be any collection type) - :type list_one: Union[Tuple[Any], List[Any]] - :param list_two: The second value. (Can be any collection type) - :type list_two: Union[Tuple[Any], List[Any]] - :return: True, if both lists are exactly the same. False, if not. - :rtype: bool - """ - if not CommonCollectionUtils.is_collection(list_one): - return False - if not CommonCollectionUtils.is_collection(list_two): - return False - if len(list_one) != len(list_two): - return False - if isinstance(list_one, set) or isinstance(list_two, set): - return list_one == list_two - current_idx = 0 - while current_idx < len(list_one): - item_one = list_one[current_idx] - item_two = list_two[current_idx] - if item_one != item_two: - return False - current_idx += 1 - return True - - @staticmethod - def intersects(list_one: List[Any], *list_items: Any) -> bool: - """intersects(list_one, *list_items) - - Determine if a list contains any of the specified items. - - :param list_one: The list being checked. - :type list_one: List[Any] - :param list_items: An iterator of items being searched for. - :type list_items: Any - :return: True, if the list contains any of the specified items. False, if not. - :rtype: bool - """ - if list_one is None or list_items is None: - return False - for list_item in list_items: - for item in list_item: - if item in list_one: - return True - return False - - @staticmethod - def add_to_dict_if_not_exist(dictionary_one: Dict[Any, Any], dictionary_two: Dict[Any, Any]) -> Dict[Any, Any]: - """add_to_dict_if_not_exist(dictionary_one, dictionary_two) - - Combine two dictionaries. - - .. note:: If a key already exists in the first dictionary, the value from the second dictionary is ignored. - - :param dictionary_one: The first dictionary. - :type dictionary_one: Dict[Any, Any] - :param dictionary_two: The second dictionary. - :type dictionary_two: Dict[Any, Any] - :return: A new combined dictionary. - :rtype: Dict[Any, Any] - """ - if dictionary_one is None or dictionary_two is None: - return dict() - has_new_keys = False - new_dict = dict() - for (to_add_key, to_add_value) in dictionary_two.items(): - if to_add_key in dictionary_one: - continue - has_new_keys = True - new_dict[to_add_key] = to_add_value - if not has_new_keys: - return dictionary_one - for (key, value) in dictionary_one.items(): - new_dict[key] = value - return new_dict - - @staticmethod - def flatten(to_flatten: Any) -> Union[Any, List[Any]]: - """flatten(to_flatten) - - Flatten a collection of collections to a single list or itself if already flattened. - - :param to_flatten: A collection of items. - :type to_flatten: Any - :return: A single flattened list or `to_flatten` if already flattened. - :rtype: Union[Any, List[Any]] - """ - if not CommonCollectionUtils.is_collection(to_flatten): - return to_flatten - flat_list = list() - for value in to_flatten: - flat_list.append(CommonCollectionUtils.flatten(value)) - return flat_list - - @staticmethod - def create_possible_combinations(items: Union[List[Any], Tuple[Any]], items_per_combination: int) -> Set[Tuple[Any]]: - """create_possible_combinations(items, items_per_combination) - - Create a collection of all possible combinations of the specified items. - - .. note:: Example: With items: [1, 2, 3] and combination_length: 2 the result will be: {(1, 2), (1, 3), (2, 3)} - - :param items: A collection of items to create combinations from. - :type items: Union[List[Any], Tuple[Any]] - :param items_per_combination: The number of items in each combination. - :type items_per_combination: int - :return: A collection of combinations - :rtype: Set[Tuple[Any]] - """ - possible_combinations = set() - combinations = itertools.combinations(items, items_per_combination) - for combination in combinations: - (is_processed, new_combination_sets) = CommonCollectionUtils._process_item_sets(combination) - if is_processed: - for new_combination_set in new_combination_sets: - possible_combinations.add(tuple(new_combination_set)) - else: - possible_combinations.add(tuple(combination)) - return possible_combinations - - @staticmethod - def merge_dict(destination: Dict[Any, Any], source: Dict[Any, Any], prefer_source_values: bool=True, allow_duplicates_in_collections: bool=True) -> Dict[Any, Any]: - """merge_dict(destination, source, prefer_source_values=True, allow_duplicates_in_collections=True) - - Merge a source dictionary into a destination dictionary. The destination will not be modified! - - :param destination: The dictionary to use as the destination. Source will be merged into this. - :type destination: Dict[Any, Any] - :param source: The dictionary to use as the source. Destination will have this merged into itself. - :type source: Dict[Any, Any] - :param prefer_source_values: When an entry is found within both the destination and the source, setting it to True will prefer to overwrite the destination value with the source value, setting this to False will prefer to use the destination value. Default is True. - :type prefer_source_values: bool, optional - :param allow_duplicates_in_collections: When a collection is found within both dictionaries, setting this to True will allow duplicate entries, setting it to False will not allow duplicate entries. Default is True. - :type allow_duplicates_in_collections: bool, optional - :return: A dictionary containing the source merged into the destination. - :rtype: Dict[Any, Any] - """ - merged = destination.copy() - for (source_key, source_val) in source.items(): - source_val = source[source_key] - if source_key in merged: - destination_val = merged[source_key] - if isinstance(source_val, dict) and isinstance(destination_val, dict): - merged[source_key] = CommonCollectionUtils.merge_dict(destination_val, source_val, allow_duplicates_in_collections=allow_duplicates_in_collections) - elif CommonCollectionUtils.is_collection(source_val) and CommonCollectionUtils.is_collection(destination_val): - if allow_duplicates_in_collections: - if prefer_source_values: - merged[source_key] = ( - *source_val, - *destination_val - ) - else: - merged[source_key] = ( - *destination_val, - *source_val - ) - else: - new_collection = list(destination_val) - for val in source_val: - if val not in new_collection: - new_collection.append(val) - merged[source_key] = tuple(new_collection) - elif source_val == destination_val: - continue - else: - if prefer_source_values: - merged[source_key] = source_val - else: - merged[source_key] = source_val - return merged - - @staticmethod - def _process_item_sets(item_set: Union[Tuple[Any], List[Any], Set[Any]]) -> Tuple[bool, Union[Set[Any], List[Any]]]: - item_sets = [] - # Item count 2 - # I1, T1 - # ((I1, I2), T1) - # ((I1, I2), (T1, T2)) - # Item count 3 - # I1, T1, K1 - # ((I1, I2), T1, K1) - # ((I1, I2), (T1, T2), K1) - # ((I1, I2), (T1, T2), (K1, K2)) - has_unprocessed = False - unprocessed_item_sets = [] - idx = 0 - for item in item_set: - if isinstance(item, tuple) or isinstance(item, list) or isinstance(item, set): - has_unprocessed = True - elements_before = item_set[:idx] - elements_after = item_set[idx + 1:] - for items_in_set in item: - current_set = [] - for element_before in elements_before: - current_set.append(element_before) - current_set.append(items_in_set) - for element_after in elements_after: - current_set.append(element_after) - unprocessed_item_sets.append(current_set) - break - idx += 1 - if len(unprocessed_item_sets) > 0: - item_sets = [] - for unprocessed_item_set in unprocessed_item_sets: - (is_processed, result) = CommonCollectionUtils._process_item_sets(unprocessed_item_set) - if is_processed: - for new_item_set in result: - item_sets.append(new_item_set) - else: - item_sets.append(unprocessed_item_set) - return True, item_sets - if not has_unprocessed: - if isinstance(item_set, list) or isinstance(item_set, tuple): - new_item_set = set() - for item in item_set: - new_item_set.add(item) - return False, new_item_set - return False, item_set - return True, item_sets diff --git a/Scripts/s4ap/sims4communitylib/utils/common_component_utils.py b/Scripts/s4ap/sims4communitylib/utils/common_component_utils.py deleted file mode 100644 index 4a6317c..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/common_component_utils.py +++ /dev/null @@ -1,79 +0,0 @@ -""" -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 -""" -from typing import Union, TypeVar, Type - -from objects.components import ComponentContainer, Component -from s4ap.sims4communitylib.enums.types.component_types import CommonComponentType - - -CommonExpectedReturnType = TypeVar('CommonExpectedReturnType', bound=Component) - - -class CommonComponentUtils: - """Utilities for handling components of component containers. - - """ - @staticmethod - def has_component(component_container: ComponentContainer, component_type: CommonComponentType) -> bool: - """has_component(component_container, component_type) - - Determine if a ComponentContainer has a component of the specified type. - - :param component_container: The ComponentContainer to check. - :type component_container: ComponentContainer - :param component_type: The type of component to locate. - :type component_type: CommonComponentType - :return: True, if the ComponentContainer contains a component of the specified type. False, if not. - :rtype: bool - """ - if component_type is None or not isinstance(component_container, ComponentContainer) or not hasattr(component_container, 'has_component'): - return False - return component_container.has_component(component_type) - - # noinspection PyUnusedLocal - @staticmethod - def get_component(component_container: ComponentContainer, component_type: CommonComponentType, add_dynamic: bool = False, return_type: Type[CommonExpectedReturnType] = Component) -> Union[CommonExpectedReturnType, None]: - """get_component(component_container, component_type, add_dynamic=False, return_type=Component) - - Retrieve a component from a ComponentContainer. - - :param component_container: The ComponentContainer to retrieve a component from. - :type component_container: ComponentContainer - :param component_type: The type of component being retrieved. - :type component_type: CommonComponentType - :param add_dynamic: If True, the component will be added dynamically. If False, the component will not be added dynamically. Default is False. - :type add_dynamic: bool, optional - :param return_type: The type of the returned value. (This is to make type hinting more accurate). It is not actually used in the function. Default is Component. - :type return_type: Type[CommonExpectedReturnType], optional - :return: An object of type Component, or None if the specified component type is not found. - :rtype: Union[CommonExpectedReturnType, None] - """ - if component_type is None or not isinstance(component_container, ComponentContainer) or not hasattr(component_container, 'get_component'): - return None - if add_dynamic and not component_container.has_component(component_type): - return CommonComponentUtils.add_dynamic_component(component_container, component_type) - return component_container.get_component(component_type) - - @staticmethod - def add_dynamic_component(component_container: ComponentContainer, component_type: CommonComponentType) -> Union[Component, None]: - """add_dynamic_component(component_container, component_type) - - Add a dynamic component to a ComponentContainer. - - :param component_container: The ComponentContainer to add to. - :type component_container: ComponentContainer - :param component_type: The type of component being added. - :type component_type: CommonComponentType - :return: The added Component or None - :rtype: Union[Component, None] - """ - if component_type is None or not hasattr(component_container, 'add_dynamic_component') or not hasattr(component_container, 'get_component'): - return None - if not component_container.add_dynamic_component(component_type): - return None - return component_container.get_component(component_type) diff --git a/Scripts/s4ap/sims4communitylib/utils/common_date_utils.py b/Scripts/s4ap/sims4communitylib/utils/common_date_utils.py deleted file mode 100644 index ca906b6..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/common_date_utils.py +++ /dev/null @@ -1,37 +0,0 @@ -""" -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 -""" -from datetime import datetime - - -class CommonRealDateUtils: - """A utility for managing real life date and time. - - .. note:: This utility is used to handle the Real Time and not the Game Time. - - """ - @staticmethod - def get_current_date_time() -> datetime: - """get_current_date_time() - - Retrieve the current date and time. - - :return: The current real date and time. - :rtype: datetime - """ - return datetime.now() - - @staticmethod - def get_current_date_string() -> str: - """get_current_date_string() - - Retrieve the current date as a pre-formatted string. - - :return: The string representation of the current real date. - :rtype: str - """ - return str(datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')) diff --git a/Scripts/s4ap/sims4communitylib/utils/common_function_utils.py b/Scripts/s4ap/sims4communitylib/utils/common_function_utils.py deleted file mode 100644 index d472345..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/common_function_utils.py +++ /dev/null @@ -1,245 +0,0 @@ -""" -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 -""" -from typing import Any, Callable, Iterator, Union - -from s4ap.sims4communitylib.classes.testing.common_enqueue_result import CommonEnqueueResult -from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.utils.common_log_registry import CommonLog - - -class CommonFunctionUtils: - """Utilities for manipulating functions. - - """ - - @staticmethod - def noop(*_, **__) -> None: - """noop(*_, **__) - - An empty function that does nothing. Useful when you need something to do nothing. - - .. note:: Use this when you want something to do nothing. - - """ - pass - - @staticmethod - def noop_execution_result(*_, **__) -> CommonExecutionResult: - """noop_execution_result(*_, **__) - - An empty function that does nothing but return :func:`CommonExecutionResult.NONE`. Useful when you need something to simply return CommonExecutionResult.NONE. - - .. note:: Use this when you want something to simply return CommonExecutionResult.NONE. - - :return: Returns CommonExecutionResult.NONE. - :rtype: CommonExecutionResult - """ - return CommonExecutionResult.NONE - - @staticmethod - def noop_test_result(*_, **__) -> CommonTestResult: - """noop_test_result(*_, **__) - - An empty function that does nothing but return :func:`CommonTestResult.NONE`. Useful when you need something to simply return CommonTestResult.NONE. - - .. note:: Use this when you want something to simply return CommonTestResult.NONE. - - :return: Returns CommonTestResult.NONE. - :rtype: CommonTestResult - """ - return CommonTestResult.NONE - - @staticmethod - def noop_enqueue(*_, **__) -> CommonEnqueueResult: - """noop_enqueue(*_, **__) - - An empty function that does nothing but return :func:`CommonEnqueueResult.NONE`. Useful when you need something to simply return CommonEnqueueResult.NONE. - - .. note:: Use this when you want something to simply return CommonEnqueueResult.NONE. - - :return: Returns CommonEnqueueResult.NONE. - :rtype: CommonEnqueueResult - """ - return CommonEnqueueResult.NONE - - @staticmethod - def noop_true(*_, **__) -> bool: - """noop_true(*_, **__) - - An empty function that does nothing but return True. Useful when you need something to simply return True. - - .. note:: Use this when you want something to simply return True. - - :return: Returns True. - :rtype: bool - """ - return True - - @staticmethod - def noop_false(*_, **__) -> bool: - """noop_false(*_, **__) - - An empty function that does nothing but return False. Useful when you need something to simply return False. - - .. note:: Use this when you want something to simply return False. - - :return: Returns False. - :rtype: bool - """ - return False - - @staticmethod - def print_arguments(log: CommonLog, func_identifier: str = 'NO_IDENTIFIER_SPECIFIED') -> Callable[..., Any]: - """print_arguments(log, func_identifier='NO_IDENTIFIER_SPECIFIED') - - Create a function that will log the arguments and keyword arguments it receives - - :param log: The log to print the arguments to. - :type log: CommonLog - :param func_identifier: An identifier for the function to determine which function was invoked - :type func_identifier: str - :return: A function that will print the arguments sent to it when the original function is invoked. - :rtype: Callable[..., Any] - """ - - def _print_arguments(*_: Any, **__: Any): - log.enable() - log.format_with_message(f'print_arguments invoked for identifier \'{func_identifier}\':', argles=_, kwargles=__) - log.disable() - - return _print_arguments - - @staticmethod - def safe_run(mod_identity: CommonModIdentity, primary_function: Callable[..., Any], fallback_function: Callable[..., Any], *args: Any, **kwargs: Any) -> Any: - """safe_run(mod_identity, primary_function, fallback_function, *args, **kwargs) - - Safely run a function, if the primary function throws an exception, the fallback function will be run instead. - - :param mod_identity: The identity of the mod running a function safely. - :type mod_identity: CommonModIdentity - :param primary_function: The primary function to safely run. - :type primary_function: Callable[..., Any] - :param fallback_function: A function called when the primary function throws an exception. - :type fallback_function: Callable[..., Any] - :param args: Arguments to pass to both the primary function and fallback function. - :type args: Any - :param kwargs: Keyword Arguments to pass to both the primary function and fallback function. - :type kwargs: Any - :return: The result of either the primary function or the fallback function if the primary threw an exception. - :rtype: Any - """ - try: - if primary_function is None: - if fallback_function is None: - return - return fallback_function(*args, **kwargs) - return primary_function(*args, **kwargs) - except Exception as ex: - # noinspection PyBroadException - try: - from s4ap.sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler - CommonExceptionHandler.log_exception( - mod_identity, - f'Error occurred while running \'{primary_function.__name__}\'', - exception=ex - ) - except Exception: - pass - # noinspection PyBroadException - try: - if fallback_function is None: - return - return fallback_function(*args, **kwargs) - except: - pass - - @staticmethod - def run_predicates_as_one(predicate_functions: Iterator[Callable[..., Union[bool, CommonExecutionResult, CommonTestResult]]], all_must_pass: bool = True) -> Callable[..., Union[bool, CommonExecutionResult, CommonTestResult]]: - """run_predicates_as_one(predicate_functions, all_must_pass=True) - - Wrap all predicate functions into a single predicate function. (See returned value for more information). - - .. note:: - - If `all_must_pass` is True a wrapped function that will return a value of: - - - True, if all predicates resulted in a True value. - - False, if any predicates resulted in a False value. - - If `all_must_pass` is False a wrapped function that will return a value of: - - - True, if any predicates resulted in a True value. - - False, if all predicates resulted in a False value. - - :param predicate_functions: The predicate functions to run as one. - :type predicate_functions: Iterator[Callable[..., bool]] - :param all_must_pass: If True, all the predicates must return a True value. If False, any of the predicates must return a True value. - :type all_must_pass: bool, optional - :return: The result of running all functions. - :rtype: bool - """ - def _wrapper(*_: Any, **__: Any): - if all_must_pass: - for primary_function in predicate_functions: - if primary_function is None: - continue - if not primary_function(*_, **__): - return False - return True - else: - for primary_function in predicate_functions: - if primary_function is None: - continue - if primary_function(*_, **__): - return True - return False - _wrapper.__name__ = ', '.join([func.__name__ for func in predicate_functions if func is not None]) - return _wrapper - - @staticmethod - def run_predicate_with_reversed_result(predicate_function: Callable[..., Union[bool, CommonExecutionResult, CommonTestResult]]) -> Callable[..., Union[bool, CommonExecutionResult, CommonTestResult]]: - """run_predicate_with_reversed_result(predicate_function) - - Wrap the specified predicate function and reverse the result of it when the function is invoked. - - :param predicate_function: The predicate function to reverse the result of. - :type predicate_function: Callable[..., bool] - :return: A function that will reverse the result of `predicate_function` upon invocation. - :rtype: Callable[..., bool] - """ - def _wrapper(*_: Any, **__: Any) -> Any: - if predicate_function is None: - return False - result = predicate_function(*_, **__) - if isinstance(result, CommonExecutionResult) or isinstance(result, CommonTestResult): - return result.reverse_result() - return not result - if predicate_function is not None: - _wrapper.__name__ = predicate_function.__name__ - return _wrapper - - @staticmethod - def run_with_arguments(primary_function: Callable[..., Any], *args: Any, **kwargs: Any) -> Callable[..., Any]: - """run_with_arguments(primary_function, *args, **kwargs) - - Wrap a function and run it with additional arguments when something invokes it. - - :param primary_function: The function that will be run. - :type primary_function: Callable[..., Any] - :return: A function that will send extra arguments upon invocation. - :rtype: Callable[..., Any] - """ - def _wrapper(*_: Any, **__: Any) -> Any: - if primary_function is None: - return False - return primary_function(*_, *args, **__, **kwargs) - if primary_function is not None: - _wrapper.__name__ = primary_function.__name__ - return _wrapper diff --git a/Scripts/s4ap/sims4communitylib/utils/common_icon_utils.py b/Scripts/s4ap/sims4communitylib/utils/common_icon_utils.py deleted file mode 100644 index bed6755..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/common_icon_utils.py +++ /dev/null @@ -1,189 +0,0 @@ -""" -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 -""" -from typing import Any, Union -from sims4.resources import Types -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt -from s4ap.sims4communitylib.enums.icons_enum import CommonIconId -from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils - - -class CommonIconUtils: - """Utilities for loading icons. - - """ - @classmethod - def load_arrow_right_icon(cls) -> Any: - """load_arrow_right_icon() - - Get the Resource Key for the ARROW_RIGHT_ICON. - - :return: An identifier for the icon. - :rtype: Any - """ - return cls.load_icon_by_id(CommonIconId.S4CLIB_ARROW_RIGHT_ICON) - - @classmethod - def load_arrow_left_icon(cls) -> Any: - """load_arrow_left_icon() - - Get the Resource Key for the ARROW_LEFT_ICON. - - :return: An identifier for the icon. - :rtype: Any - """ - return cls.load_icon_by_id(CommonIconId.S4CLIB_ARROW_LEFT_ICON) - - @classmethod - def load_arrow_navigate_into_icon(cls) -> Any: - """load_arrow_navigate_into_icon() - - Get the Resource Key for the ARROW_NAVIGATE_INTO_ICON. - - :return: An identifier for the icon. - :rtype: Any - """ - return cls.load_icon_by_id(CommonIconId.S4CLIB_ARROW_NAVIGATE_INTO_ICON) - - @classmethod - def load_question_mark_icon(cls) -> Any: - """load_question_mark_icon() - - Get the Resource Key for the QUESTION_MARK_ICON. - - :return: An identifier for the icon. - :rtype: Any - """ - return cls.load_icon_by_id(CommonIconId.S4CLIB_QUESTION_MARK_ICON) - - @classmethod - def load_checked_square_icon(cls) -> Any: - """load_checked_square_icon() - - Get the Resource Key for the CHECKED_SQUARE_ICON. - - :return: An identifier for the icon. - :rtype: Any - """ - return cls.load_icon_by_id(CommonIconId.S4CLIB_CHECKED_SQUARE_ICON) - - @classmethod - def load_checked_circle_icon(cls) -> Any: - """load_checked_circle_icon() - - Get the Resource Key for the CHECKED_CIRCLE_ICON. - - :return: An identifier for the icon. - :rtype: Any - """ - return cls.load_icon_by_id(CommonIconId.S4CLIB_CHECKED_CIRCLE_ICON) - - @classmethod - def load_unchecked_square_icon(cls) -> Any: - """load_unchecked_square_icon() - - Get the Resource Key for the UNCHECKED_SQUARE_ICON. - - :return: An identifier for the icon. - :rtype: Any - """ - return cls.load_icon_by_id(CommonIconId.S4CLIB_UNCHECKED_SQUARE_ICON) - - @classmethod - def load_x_icon(cls) -> Any: - """load_x_icon() - - Get the Resource Key for the X_ICON. - - :return: An identifier for the icon. - :rtype: Any - """ - return cls.load_icon_by_id(CommonIconId.S4CLIB_X_ICON) - - @classmethod - def load_six_sided_dice_icon(cls) -> Any: - """load_six_sided_dice_icon() - - Get the Resource Key for the SIX_SIDED_DICE_ICON. - - :return: An identifier for the icon. - :rtype: Any - """ - return cls.load_icon_by_id(CommonIconId.S4CLIB_SIX_SIDED_DICE_ICON) - - @classmethod - def load_blank_square_icon(cls) -> Any: - """load_blank_square_icon() - - Get the Resource Key for the BLANK_SQUARE_ICON. - - :return: An identifier for the icon. - :rtype: Any - """ - return cls.load_icon_by_id(CommonIconId.S4CLIB_BLANK_SQUARE_ICON) - - @classmethod - def load_text_prev_icon(cls) -> Any: - """load_text_prev_icon() - - Get the Resource Key for the TEXT_PREV_SQUARE_ICON. - - :return: An identifier for the icon. - :rtype: Any - """ - return cls.load_icon_by_id(CommonIconId.S4CLIB_TEXT_PREV_SQUARE_ICON) - - @classmethod - def load_text_next_icon(cls) -> Any: - """load_text_next_icon() - - Get the Resource Key for the TEXT_NEXT_SQUARE_ICON. - - :return: An identifier for the icon. - :rtype: Any - """ - return cls.load_icon_by_id(CommonIconId.S4CLIB_TEXT_NEXT_SQUARE_ICON) - - @classmethod - def load_unfilled_circle_icon(cls) -> Any: - """load_unfilled_circle_icon() - - Get the Resource Key for the UNFILLED_CIRCLE_ICON. - - :return: An identifier for the icon. - :rtype: Any - """ - return cls.load_icon_by_id(CommonIconId.S4CLIB_UNFILLED_CIRCLE_ICON) - - @classmethod - def load_filled_circle_icon(cls) -> Any: - """load_filled_circle_icon() - - Get the Resource Key for the FILLED_CIRCLE_ICON. - - :return: An identifier for the icon. - :rtype: Any - """ - return cls.load_icon_by_id(CommonIconId.S4CLIB_FILLED_CIRCLE_ICON) - - @classmethod - def load_icon_by_id(cls, icon: Union[int, CommonIconId, CommonInt]) -> Union[Any, None]: - """load_icon_by_id(icon) - - Load an instance of an Icon by its identifier. - - :param icon: The identifier of an Icon. - :type icon: Union[int, CommonIconId, CommonInt] - :return: An instance of an Icon matching the decimal identifier or None if not found. - :rtype: Union[Any, None] - """ - return CommonResourceUtils.get_resource_key(Types.PNG, icon) - - @staticmethod - def _load_icon(icon_id: Union[int, CommonIconId]) -> Any: - """Obsolete, please use load_icon_by_id instead.""" - return CommonIconUtils.load_icon_by_id(icon_id) diff --git a/Scripts/s4ap/sims4communitylib/utils/common_injection_utils.py b/Scripts/s4ap/sims4communitylib/utils/common_injection_utils.py deleted file mode 100644 index 594924a..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/common_injection_utils.py +++ /dev/null @@ -1,417 +0,0 @@ -""" -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 -""" -import os -from functools import wraps -from typing import Any, Callable, TYPE_CHECKING - -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity - -if TYPE_CHECKING: - from s4ap.sims4communitylib.utils.common_log_registry import CommonLog -ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' - - -class _TypeChecking: - # noinspection PyMissingTypeHints,PyMissingOrEmptyDocstring - @classmethod - def class_method(cls): - pass - - # noinspection PyMissingTypeHints,PyMissingOrEmptyDocstring - def self_method(self): - pass - - # noinspection PyPropertyDefinition,PyMissingTypeHints,PyMissingOrEmptyDocstring - @property - def property_type(self): - pass - - # noinspection PyMissingTypeHints,PyMissingOrEmptyDocstring - @staticmethod - def static_method(): - pass - - -ClassMethodType = type(_TypeChecking.class_method) -SelfMethodType = type(_TypeChecking.self_method) -StaticMethodType = type(_TypeChecking.static_method) -PropertyType = type(_TypeChecking.property_type) - - -class CommonInjectionUtils: - """Utilities to inject custom functionality into functions. - - """ - @staticmethod - def inject_into(target_object: Any, target_function_name: str) -> Callable: - """inject_into(target_object, target_function_name) - - .. warning:: This function is DEPRECATED.\ - Use :func:`~inject_safely_into` instead. - - """ - # noinspection PyTypeChecker - return CommonInjectionUtils.inject_safely_into(None, target_object, target_function_name) - - @staticmethod - def inject_safely_into(mod_identity: CommonModIdentity, target_object: Any, target_function_name: str, handle_exceptions: bool = True) -> Callable: - """inject_safely_into(mod_identity, target_object, target_function_name, handle_exceptions=True) - - A decorator used to inject code into a function. - It will run the original function should any problems occur. - If handle_exceptions is True, it will catch and log exceptions. - - :Example of cls usage: - - .. highlight:: python - .. code-block:: python - - # cls usage - @CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), SimSpawner, SimSpawner.spawn_sim._name__) - def do_custom_spawn_sim(original, cls, *args, **kwargs): - return original(*args, **kwargs) - - :Example of self usage: - - .. highlight:: python - .. code-block:: python - - # Self usage - @CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), SimInfo, SimInfo.load_sim_info.__name__) - def do_custom_load_sim_info(original, self, *args, **kwargs): - return original(self, *args, **kwargs) - - .. note:: - - Injection WILL work on - - - Functions decorated with 'property' - - Functions decorated with 'classmethod' - - Functions decorated with 'staticmethod' - - Functions with 'cls' or 'self' as the first argument. - - .. note:: - - Injection WILL NOT work on - - - Global functions, i.e. Functions not contained within a class. - - Global variables, i.e. Variables not contained within a class or function. - - :param mod_identity: The identity of the Mod that is injecting custom code. - :type mod_identity: CommonModIdentity - :param target_object: The class that contains the target function. - :type target_object: Any - :param target_function_name: The name of the function being injected to. - :type target_function_name: str - :param handle_exceptions: If set to True, any exceptions thrown by the wrapped function will be handled. If set to False, any exceptions thrown by the wrapped function will not be caught. Default is True. - :type handle_exceptions: bool, optional - :return: A wrapped function. - :rtype: Callable - """ - if ON_RTD: - def _injected(wrap_function) -> Any: - return wrap_function - return _injected - - if handle_exceptions: - def _function_wrapper(original_function, new_function: Callable[..., Any]) -> Any: - # noinspection PyBroadException - try: - if isinstance(original_function, ClassMethodType): - original_function_func = original_function.__func__ - - # noinspection PyDecorator - @wraps(original_function) - def _wrapped_class_function(cls, *args, **kwargs) -> Any: - try: - # noinspection PyMissingTypeHints - def _do_original(*_, **__): - return original_function_func(cls, *_, **__) - - return new_function(_do_original, cls, *args, **kwargs) - except Exception as ex: - # noinspection PyBroadException - try: - from s4ap.sims4communitylib.exceptions.common_exceptions_handler import \ - CommonExceptionHandler - CommonExceptionHandler.log_exception(mod_identity, 'Error occurred while injecting into function \'{}\' of class \'{}\''.format(new_function.__name__, target_object.__name__), exception=ex) - except Exception: - pass - return original_function_func(cls, *args, **kwargs) - return classmethod(_wrapped_class_function) - - if isinstance(original_function, SelfMethodType): - @wraps(original_function) - def _wrapped_self_function(self, *args, **kwargs) -> Any: - try: - return new_function(original_function, self, *args, **kwargs) - except Exception as ex: - # noinspection PyBroadException - try: - from s4ap.sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler - CommonExceptionHandler.log_exception(mod_identity, 'Error occurred while injecting into function \'{}\' of class \'{}\''.format(new_function.__name__, target_object.__name__), exception=ex) - except Exception: - pass - return original_function(self, *args, **kwargs) - - return _wrapped_self_function - - if isinstance(original_function, PropertyType): - # noinspection PyTypeChecker - @wraps(original_function) - def _wrapped_property_function(self, *args, **kwargs) -> Any: - try: - return new_function(original_function.fget, self, *args, **kwargs) - except Exception as ex: - # noinspection PyBroadException - try: - from s4ap.sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler - CommonExceptionHandler.log_exception(mod_identity, 'Error occurred while injecting into function \'{}\' of class \'{}\''.format(new_function.__name__, target_object.__name__), exception=ex) - except Exception: - pass - return original_function(self, *args, **kwargs) - - return property(_wrapped_property_function) - - if isinstance(original_function, StaticMethodType): - original_function_func = original_function.__func__ - - # noinspection PyDecorator - @wraps(original_function) - def _wrapped_static_function(*args, **kwargs) -> Any: - try: - # noinspection PyMissingTypeHints - def _do_original(*_, **__): - return original_function_func(*_, **__) - - return new_function(_do_original, *args, **kwargs) - except Exception as ex: - # noinspection PyBroadException - try: - from s4ap.sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler - CommonExceptionHandler.log_exception(mod_identity, 'Error occurred while injecting into function \'{}\' of class \'{}\''.format(new_function.__name__, target_object.__name__), exception=ex) - except Exception: - pass - return original_function_func(*args, **kwargs) - - return staticmethod(_wrapped_static_function) - - @wraps(original_function) - def _wrapped_other_function(*args, **kwargs) -> Any: - try: - return new_function(original_function, *args, **kwargs) - except Exception as ex: - # noinspection PyBroadException - try: - from s4ap.sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler - CommonExceptionHandler.log_exception(mod_identity, 'Error occurred while injecting into function \'{}\' of class \'{}\''.format(new_function.__name__, target_object.__name__), exception=ex) - except Exception: - pass - return original_function(*args, **kwargs) - - return _wrapped_other_function - except: - def _func(*_, **__) -> Any: - pass - return _func - else: - def _function_wrapper(original_function, new_function: Callable[..., Any]) -> Any: - # noinspection PyBroadException - try: - if isinstance(original_function, ClassMethodType): - original_function_func = original_function.__func__ - - # noinspection PyDecorator - @wraps(original_function) - def _wrapped_class_function(cls, *args, **kwargs) -> Any: - # noinspection PyMissingTypeHints - def _do_original(*_, **__): - return original_function_func(cls, *_, **__) - - return new_function(_do_original, cls, *args, **kwargs) - return classmethod(_wrapped_class_function) - - if isinstance(original_function, SelfMethodType): - @wraps(original_function) - def _wrapped_self_function(self, *args, **kwargs) -> Any: - return new_function(original_function, self, *args, **kwargs) - - return _wrapped_self_function - - if isinstance(original_function, PropertyType): - # noinspection PyTypeChecker - @wraps(original_function) - def _wrapped_property_function(self, *args, **kwargs) -> Any: - return new_function(original_function.fget, self, *args, **kwargs) - - return property(_wrapped_property_function) - - if isinstance(original_function, StaticMethodType): - original_function_func = original_function.__func__ - - # noinspection PyDecorator - @wraps(original_function) - def _wrapped_static_function(*args, **kwargs) -> Any: - # noinspection PyMissingTypeHints - def _do_original(*_, **__): - return original_function_func(*_, **__) - - return new_function(_do_original, *args, **kwargs) - - return staticmethod(_wrapped_static_function) - - @wraps(original_function) - def _wrapped_other_function(*args, **kwargs) -> Any: - return new_function(original_function, *args, **kwargs) - - return _wrapped_other_function - except: - def _func(*_, **__) -> Any: - pass - return _func - - def _injected(wrap_function) -> Any: - original_function = getattr(target_object, str(target_function_name)) - setattr(target_object, str(target_function_name), _function_wrapper(original_function, wrap_function)) - return wrap_function - return _injected - - @staticmethod - def inject_safely_into_function(mod_identity: CommonModIdentity, target_object: Any, target_function_name: str, callback: Callable[..., Any], replace_return: bool = False, handle_exceptions: bool = True) -> Callable: - """inject_safely_into_function(mod_identity, target_object, target_function_name, callback, replace_return=False, handle_exceptions=True) - - A decorator used to inject code into a function. - It will run the original function should any problems occur. - If handle_exceptions is True, it will catch and log exceptions. - - :Example of cls usage: - - .. highlight:: python - .. code-block:: python - - # cls usage - @CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), SimSpawner, SimSpawner.spawn_sim._name__) - def do_custom_spawn_sim(original, cls, *args, **kwargs): - return original(*args, **kwargs) - - :Example of self usage: - - .. highlight:: python - .. code-block:: python - - # Self usage - @CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), SimInfo, SimInfo.load_sim_info.__name__) - def do_custom_load_sim_info(original, self, *args, **kwargs): - return original(self, *args, **kwargs) - - .. note:: - - Injection WILL work on - - - Functions decorated with 'property' - - Functions decorated with 'classmethod' - - Functions decorated with 'staticmethod' - - Functions with 'cls' or 'self' as the first argument. - - .. note:: - - Injection WILL NOT work on - - - Global functions, i.e. Functions not contained within a class. - - Global variables, i.e. Variables not contained within a class or function. - - :param mod_identity: The identity of the Mod that is injecting custom code. - :type mod_identity: CommonModIdentity - :param target_object: The class that contains the target function. - :type target_object: Any - :param target_function_name: The name of the function being injected to. - :type target_function_name: str - :param callback: When the injected function is invoked, this callback will be invoked. - :type callback: Callable[..., Any] - :param replace_return: If True, the returned result of the callback argument will replace the returned result of the original function. If False, the callback will be invoked, but the result of invoking the original function will be returned. Default is False. - :type replace_return: bool, optional - :param handle_exceptions: If set to True, any exceptions thrown by the wrapped function will be handled. If set to False, any exceptions thrown by the wrapped function will not be caught. Default is True. - :type handle_exceptions: bool, optional - :return: A wrapped function. - :rtype: Callable - """ - - @CommonInjectionUtils.inject_safely_into(mod_identity, target_object, target_function_name, handle_exceptions=handle_exceptions) - def _inject_and_invoke_callback(original, *args, **kwargs) -> Any: - callback_result = callback(*args, **kwargs) - if replace_return: - return callback_result - return original(*args, **kwargs) - - return _inject_and_invoke_callback - - @staticmethod - def inject_and_print_arguments(mod_identity: CommonModIdentity, target_object: Any, target_function_name: str, log: 'CommonLog', log_stack_trace: bool = False, handle_exceptions: bool = True) -> Callable: - """inject_and_print_arguments(mod_identity, target_object, target_function_name, log, log_stack_trace=False, handle_exceptions=True) - - A decorator used to inject code into a function and print any arguments or keyword arguments passed to it. - - .. note:: See documentation of :func:`~inject_safely_into` for more details about the arguments and keyword arguments. - - :Example of cls usage: - - .. highlight:: python - .. code-block:: python - - # cls usage - @CommonInjectionUtils.inject_and_print_arguments(ModInfo.get_identity(), SimSpawner, SimSpawner.spawn_sim._name__) - - :Example of self usage: - - .. highlight:: python - .. code-block:: python - - # Self usage - @CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), SimInfo, SimInfo.load_sim_info.__name__) - def do_custom_load_sim_info(original, self, *args, **kwargs): - return original(self, *args, **kwargs) - - .. note:: - - Injection WILL work on - - - Functions decorated with 'property' - - Functions decorated with 'classmethod' - - Functions decorated with 'staticmethod' - - Functions with 'cls' or 'self' as the first argument. - - .. note:: - - Injection WILL NOT work on - - - Global functions, i.e. Functions not contained within a class. - - Global variables, i.e. Variables not contained within a class or function. - - :param mod_identity: The identity of the Mod that is injecting custom code. - :type mod_identity: CommonModIdentity - :param target_object: The class that contains the target function. - :type target_object: Any - :param target_function_name: The name of the function being injected to. - :type target_function_name: str - :param log: The log being printed to when the injected function is invoked. The arguments and keyword arguments sent to the function will be printed. - :type log: CommonLog - :param log_stack_trace: If True, the stack trace will be logged in addition to the arguments and keyword arguments. If False, the stack trace will not be logged. Default is False. - :type log_stack_trace: bool, optional - :param handle_exceptions: If set to True, any exceptions thrown by the wrapped function will be handled. If set to False, any exceptions thrown by the wrapped function will not be caught. Default is True. - :type handle_exceptions: bool, optional - :return: A wrapped function. - :rtype: Callable - """ - @CommonInjectionUtils.inject_safely_into(mod_identity, target_object, target_function_name, handle_exceptions=handle_exceptions) - def _inject_and_print(original, *args, **kwargs) -> Any: - log.format_with_message('{}.{}'.format(target_object, target_function_name), argles=args, kwargles=kwargs) - if log_stack_trace: - log.log_stack() - return original(*args, **kwargs) - - return _inject_and_print diff --git a/Scripts/s4ap/sims4communitylib/utils/common_io_utils.py b/Scripts/s4ap/sims4communitylib/utils/common_io_utils.py deleted file mode 100644 index 1a7348d..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/common_io_utils.py +++ /dev/null @@ -1,119 +0,0 @@ -""" -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 -""" -import os -import shutil -from typing import Union - - -class CommonIOUtils: - """Utilities for reading/writing to and from files. - - """ - @staticmethod - def delete_file(file_path: str, ignore_errors: bool=False) -> bool: - """delete_file(file_path, ignore_errors=False) - - Delete a file. - - :param file_path: The file to delete. - :type file_path: str - :param ignore_errors: If True, any exceptions thrown will be ignored (Useful in preventing infinite loops) - :type ignore_errors: bool, optional - :return: True if successful. False if not. - :rtype: bool - """ - if file_path is None: - return False - try: - if os.path.exists(file_path): - os.remove(file_path) - except Exception as ex: - if ignore_errors: - return False - raise ex - return True - - @staticmethod - def delete_directory(directory_path: str, ignore_errors: bool=False) -> bool: - """delete_directory(directory_path, ignore_errors=False) - - Delete a directory. - - :param directory_path: The folder to delete. - :type directory_path: str - :param ignore_errors: If True, any exceptions thrown will be ignored (Useful in preventing infinite loops) - :type ignore_errors: bool, optional - :return: True if successful. False if not. - :rtype: bool - """ - if directory_path is None: - return False - try: - if os.path.exists(directory_path): - shutil.rmtree(directory_path) - except Exception as ex: - if ignore_errors: - return False - raise ex - return True - - @staticmethod - def write_to_file(file_path: str, data: str, buffering: int=1, encoding: str='utf-8', ignore_errors: bool=False, remove_if_exists: bool=False) -> bool: - """write_to_file(file_path, data, buffering=1, encoding='utf-8', ignore_errors=False, remove_if_exists=False) - - Write string data to a file. - - :param file_path: The file to write to. - :type file_path: str - :param data: The data to write. - :type data: str - :param buffering: See the built-in python :func:`~open` function documentation for more details. - :type buffering: int, optional - :param encoding: See the built-in python :func:`~open` function documentation for more details. - :type encoding: str, optional - :param ignore_errors: If True, any exceptions thrown will be ignored (Useful in preventing infinite loops) - :type ignore_errors: bool, optional - :param remove_if_exists: If True and the File exists already, it will be deleted before writing the data. If False and the File exists already, the data will be appended to the end of it. Default is False. - :type remove_if_exists: bool, optional - :return: True if successful. False if not. - :rtype: bool - """ - if file_path is None or data is None: - return False - try: - if remove_if_exists: - CommonIOUtils.delete_file(file_path, ignore_errors=ignore_errors) - with open(file_path, mode='a', buffering=buffering, encoding=encoding) as opened_file: - opened_file.write(data) - opened_file.flush() - opened_file.close() - except Exception as ex: - if ignore_errors: - return False - raise ex - return True - - @staticmethod - def load_from_file(file_path: str, buffering: int=1, encoding: str='utf-8') -> Union[str, None]: - """load_from_file(file_path, buffering=1, encoding='utf-8') - - Load string data from a file. - - :param file_path: The file to read from. - :type file_path: str - :param buffering: See the built-in python :func:`~open` function documentation for more details. - :type buffering: int, optional - :param encoding: See the built-in python :func:`~open` function documentation for more details. - :type encoding: str, optional - :return: The contents of the file as a string or None if an error occurred. - :rtype: Union[str, None] - """ - if not os.path.isfile(file_path): - return None - with open(file_path, mode='r', buffering=buffering, encoding=encoding) as file: - return file.read() diff --git a/Scripts/s4ap/sims4communitylib/utils/common_json_io_utils.py b/Scripts/s4ap/sims4communitylib/utils/common_json_io_utils.py deleted file mode 100644 index fb207b1..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/common_json_io_utils.py +++ /dev/null @@ -1,155 +0,0 @@ -""" -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 -""" -import json -import os -from json import JSONEncoder, JSONDecoder -from os import DirEntry -from typing import Union, Any, Iterator, Dict, Type, Callable - -from s4ap.sims4communitylib.classes.serialization.common_serializable import CommonSerializable -from s4ap.sims4communitylib.utils.common_io_utils import CommonIOUtils - - -class CommonJSONIOUtils: - """Utilities for reading/writing JSON data to and from files.""" - @staticmethod - def write_to_file(file_path: str, obj: Any, buffering: int=1, encoding: str='utf-8', encoder_class: Type[JSONEncoder]=None) -> bool: - """write_to_file(file_path, obj, buffering=1, encoding='utf-8', encoder_class=None) - - Serialize an object to a file as JSON. - - :param file_path: The file to write to. - :type file_path: str - :param obj: The object to write as JSON. - :type obj: Any - :param buffering: See the built-in python :func:`~open` function documentation for more details. - :type buffering: int, optional - :param encoding: See the built-in python :func:`~open` function documentation for more details. - :type encoding: str, optional - :param encoder_class: Specify a custom JSON encoder class to use in place of the default serialization. Default is None. - :type encoder_class: Type[JSONEncoder], optional - :return: True if successful. False if not. - :rtype: bool - """ - if file_path is None or obj is None: - return False - dir_name = os.path.dirname(file_path) - temp_file_name = 'temp' + os.path.basename(file_path) - temp_file_path = os.path.join(dir_name, temp_file_name) - if encoder_class is not None: - json_obj = json.dumps(obj, cls=encoder_class, indent=2) - else: - json_obj = json.dumps(obj, default=lambda o: o.serialize() if isinstance(o, CommonSerializable) else o.__dict__ if hasattr(o, '__dict__') else o, indent=2) - - with open(temp_file_path, mode='w+', buffering=buffering, encoding=encoding) as file: - file.write(json_obj) - file.flush() - - # File is empty. - if os.stat(temp_file_path).st_size != 0: - if os.path.exists(file_path): - os.remove(file_path) - os.rename(temp_file_path, file_path) - else: - os.remove(temp_file_path) - raise Exception(f'Failed to write file {file_path}, it wrote empty for some reason!') - return True - - @staticmethod - def load_from_file(file_path: str, buffering: int=1, encoding: str='utf-8', decoder_class: Type[JSONDecoder]=None, object_hook: Callable[[Dict[str, Any]], Any]=None) -> Union[Any, None]: - """load_from_file(file_path, buffering=1, encoding='utf-8', decoder_class=None, object_hook=None) - - Deserialize an object from a JSON file. - - :param file_path: The file to read from. - :type: file_path: str - :param buffering: See the built-in python :func:`~open` function documentation for more details. - :type buffering: int, optional - :param encoding: See the built-in python :func:`~open` function documentation for more details. - :type encoding: str, optional - :param decoder_class: Specify a custom JSON decoder class to use in place of the default deserialization. Default is None. - :type decoder_class: Type[JSONDecoder], optional - :param object_hook: A callable that will be called whenever a dictionary appears while decoding JSON. It can be used to create custom objects from data. Default is None. - :type object_hook: Callable[[Dict[str, Any]], Any], optional - :return: The contents of the file as an object or None if an error occurred. - :rtype: Union[Any, None] - """ - try: - file_contents: str = CommonIOUtils.load_from_file(file_path, buffering=buffering, encoding=encoding) - if file_contents is None: - return None - if len(file_contents) == 0: - return None - return json.loads(file_contents, cls=decoder_class, object_hook=object_hook) - except Exception as ex: - raise Exception(f'Failed to read file {file_path}, it is either corrupted, or happened to be locked at the time of trying to read it.') from ex - - @staticmethod - def load_from_folder( - folder_path: str, - skip_file_names: Iterator[str]=(), - buffering: int=1, - encoding: str='utf-8', - decoder_class: Type[JSONDecoder]=None, - object_hook: Callable[[Dict[str, Any]], Any]=None, - on_file_read_failure: Callable[[str, Exception], bool]=lambda *_, **__: True - ) -> Union[Dict[str, Any], None]: - """load_from_folder(\ - folder_path,\ - skip_file_names=(),\ - buffering=1,\ - encoding='utf-8',\ - decoder_class=None,\ - object_hook=None,\ - on_file_read_failure=lambda \*_, \*\*__: True\ - ) - - Deserialize objects from a folder containing JSON files. - - :param folder_path: The folder to read from. - :type: folder_path: str - :param skip_file_names: A collection of file names to ignore. Default is an empty collection. - :type skip_file_names: Iterator[str], optional - :param buffering: See the built-in python :func:`~open` function documentation for more details. - :type buffering: int, optional - :param encoding: See the built-in python :func:`~open` function documentation for more details. - :type encoding: str, optional - :param decoder_class: Specify a custom JSON decoder class to use in place of the default deserialization. Default is None. - :type decoder_class: Type[JSONDecoder], optional - :param object_hook: A callable that will be called whenever a dictionary appears while decoding JSON. It can be used to create custom objects from data. Default is None. - :type object_hook: Callable[[Dict[str, Any]], Any], optional - :param on_file_read_failure: When a file fails to read due to an exception, this callback will be called. If the callback returns False, no more files will be read. If the callback returns True, the rest of the files will continue to be read. Default is a callback that returns True. - :type on_file_read_failure: Callable[[str, Exception], bool], optional - :return: A dictionary of the contents of each file within the specified folder organized by file name or None if the folder path does not exist. - :rtype: Union[Dict[str, Any], None] - """ - if not os.path.exists(folder_path): - return None - if skip_file_names is None: - skip_file_names = tuple() - skip_file_names = tuple(skip_file_names) - skip_file_names = ( - *skip_file_names, - '.DS_Store', - 'desktop.ini' - ) - data = dict() - for entry in os.scandir(folder_path): - entry: DirEntry = entry - if not entry.is_file() or entry.name is None or entry.name in skip_file_names: - continue - try: - file_contents: str = CommonJSONIOUtils.load_from_file(entry.path, buffering=buffering, encoding=encoding, decoder_class=decoder_class, object_hook=object_hook) - except Exception as ex: - if not on_file_read_failure(entry.path, ex): - break - continue - if file_contents is None: - continue - data[entry.name] = file_contents - return data diff --git a/Scripts/s4ap/sims4communitylib/utils/common_keyboard_utils.py b/Scripts/s4ap/sims4communitylib/utils/common_keyboard_utils.py deleted file mode 100644 index 213413b..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/common_keyboard_utils.py +++ /dev/null @@ -1,161 +0,0 @@ -""" -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 -""" -import os - -from s4ap.sims4communitylib.enums.common_key import CommonKey -from s4ap.sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.utils.common_log_registry import CommonLogRegistry - -log = CommonLogRegistry().register_log(ModInfo.get_identity(), 'common_keyboard_utils') -# noinspection PyBroadException -try: - if os.name == 'nt': - import _s4cl_ctypes_module - _user32 = _s4cl_ctypes_module.WinDLL('user32', use_last_error=True) - if _user32 is not None: - _user32.GetKeyState.restype = _s4cl_ctypes_module.c_uint16 - - def _can_detect_key_state_for_current_os() -> bool: - return _user32 is not None - - def _is_holding_key_down(key: CommonKey) -> bool: - key_code = _translate_to_key_code(key) - if key_code == -1: - log.format_with_message('No Key Code found to check for Pressed (Windows)', key=key) - return False - key_state = _user32.GetKeyState(key_code) - key_state_has_value = key_state & 0x8000 - result = bool(key_state_has_value) - log.format_with_message('Is Key Pressed (Windows)', key=key, key_code=key_code, key_state=key_state, key_state_has_value=key_state_has_value, result=result) - return result - - def _is_key_toggled_on(key: CommonKey): - key_code = _translate_to_key_code(key) - if key_code == -1: - log.format_with_message('No Key Code found to check for Toggled On (Windows)', key=key) - return False - key_state = _user32.GetKeyState(key_code) - key_state_has_value = key_state & 0x0001 - result = bool(key_state_has_value) - log.format_with_message('Is Key Toggled On (Windows)', key=key, key_code=key_code, key_state=key_state, key_state_has_value=key_state_has_value, result=result) - return result - - def _translate_to_key_code(key: CommonKey) -> int: - if isinstance(key, int): - return key - if key is None: - return -1 - try: - if isinstance(key, CommonKey): - letter_key = key.name.replace('KEY_', '') - if len(letter_key) != 1: - return int(key) - - virtual_key = _user32.VkKeyScanW(ord(letter_key)) - if virtual_key == -1: - return int(key) - - mapped_virtual_key = _user32.MapVirtualKeyW(virtual_key & 255, 0) - mapped_scan_key = _user32.MapVirtualKeyW(mapped_virtual_key & 255, 1) - if mapped_scan_key == 0: - return int(key) - return mapped_scan_key - except Exception as ex: - CommonExceptionHandler.log_exception(ModInfo.get_identity(), 'An error occurred while translating key to key code. {}'.format(key.name), exception=ex) - return int(key) - else: - # noinspection PyUnresolvedReferences, PyPackageRequirements - import Quartz as _Quartz - - def _can_detect_key_state_for_current_os() -> bool: - return _Quartz.CGEventSourceKeyState is not None - - def _is_holding_key_down(key: CommonKey) -> bool: - key_code = _translate_to_key_code(key) - if key_code == -1: - log.format_with_message('No Key Code found to check for Pressed or Toggled On (Mac)', key=key) - return False - result = bool(_Quartz.CGEventSourceKeyState(_Quartz.kCGEventSourceStateHIDSystemState, key_code)) - log.format_with_message('Is Key Pressed or Toggled On (Mac)', key=key, key_code=key_code, result=result) - return result - - def _is_key_toggled_on(key: CommonKey): - return _is_holding_key_down(key) - - def _translate_to_key_code(key: CommonKey) -> int: - if key is None: - return -1 - return int(key) -except: - def _can_detect_key_state_for_current_os() -> bool: - return False - - def _is_holding_key_down(_: CommonKey) -> bool: - return False - - def _is_key_toggled_on(_: CommonKey) -> bool: - return False - - def _translate_to_key_code(key: CommonKey) -> int: - if key is None: - return -1 - return int(key) - - -class CommonKeyboardUtils: - """Utilities for manipulating the keyboard.""" - @staticmethod - def can_detect_key_state_for_current_os() -> bool: - """can_detect_key_state_for_current_os() - - Determine if CommonKeyboardUtils can detect the state of a key on the keyboard for the current Operating System. - - :return: True, if CommonKeyboardUtils can detect the state of a key on the keyboard for the current Operating System. False, if not. - :rtype: bool - """ - return _can_detect_key_state_for_current_os() - - @staticmethod - def is_holding_key_down(key: CommonKey) -> bool: - """is_holding_key_down(key) - - Determine if the player is holding a keyboard key down. - - :param key: The Key to check. - :type key: CommonKey - :return: True, if the player is holding the specified key down. False, if not. - :rtype: bool - """ - return _is_holding_key_down(key) - - @staticmethod - def key_is_toggled_on(key: CommonKey) -> bool: - """key_is_toggled_on(key) - - Determine if the player has a key set to the ON state, such as the CAPS LOCK key. - - :param key: The Key to check. - :type key: CommonKey - :return: True, if the player has the specified key set to the ON state. False, if not. - :rtype: bool - """ - return _is_key_toggled_on(key) - - @staticmethod - def translate_to_key_code(key: CommonKey) -> int: - """translate_to_key_code(key) - - Translate a Key to its Key Code counterpart. - - :param key: The Key to convert. - :type key: CommonKey - :return: The integer representation of the specified key or -1 if not found. - :rtype: int - """ - return _translate_to_key_code(key) diff --git a/Scripts/s4ap/sims4communitylib/utils/common_log_registry.py b/Scripts/s4ap/sims4communitylib/utils/common_log_registry.py deleted file mode 100644 index 13682b9..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/common_log_registry.py +++ /dev/null @@ -1,818 +0,0 @@ -""" -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 -""" -import os -from typing import List, Dict, Any, Union, Tuple, Iterator -from pprint import pformat - -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt -from s4ap.sims4communitylib.exceptions.common_stacktrace_utils import CommonStacktraceUtil -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.common_service import CommonService -from s4ap.sims4communitylib.utils.common_io_utils import CommonIOUtils -from s4ap.sims4communitylib.utils.common_log_utils import CommonLogUtils - -_log = None - - -class CommonMessageType(CommonInt): - """Message types for use when logging. - - """ - INVALID: 'CommonMessageType' = 0 - ERROR: 'CommonMessageType' = 1 - WARN: 'CommonMessageType' = 2 - DEBUG: 'CommonMessageType' = 3 - INFO: 'CommonMessageType' = 4 - - -class CommonLog: - """CommonLog(mod_identifier, log_name, custom_file_path=None) - - A class used to log messages. - - :param mod_identifier: The name or identity of the Mod that owns the log. - :type mod_identifier: Union[str, CommonModIdentity] - :param log_name: The name of the log, used when enabling/disabling logs via commands - :type log_name: str - :param custom_file_path: A custom file path relative to The Sims 4 folder. Example: Value is 'fake_path/to/directory', the final path would be 'The Sims 4/fake_path/to_directory'. Default is None. - :type custom_file_path: str, optional - """ - def __init__(self, mod_identifier: Union[str, CommonModIdentity], log_name: str, custom_file_path: str = None): - self._log_name = log_name - from s4ap.sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils - self._mod_name = CommonModIdentityUtils.determine_mod_name_from_identifier(mod_identifier) - self._custom_file_path = custom_file_path - self._enabled_message_types = tuple() - self._should_log_extra_sim_details = False - - def debug(self, message: str): - """debug(message) - - Log a message with message type DEBUG. - - :param message: The message to log. - :type message: str - """ - if self.is_enabled(CommonMessageType.DEBUG): - self._log_message(CommonMessageType.DEBUG, message) - - def info(self, message: str): - """info(message) - - Log a message with message type INFO. - - :param message: The message to log. - :type message: str - """ - if self.is_enabled(CommonMessageType.INFO): - self._log_message(CommonMessageType.INFO, message) - - def format_info(self, *args: Any, update_tokens: bool = True, **kwargs: Any): - """format_info(*args, update_tokens=True, **kwargs) - - Log a non-descriptive message containing pformatted arguments and keyword arguments with message type INFO. - - :param update_tokens: If set to True, when an arg or kwarg value is a Sim or SimInfo, it will be converted to their name before format occurs. Default is True. - :type update_tokens: bool, optional - :param args: Arguments to format into the message. - :type args: Any - :param kwargs: Keyword Arguments to format into the message. - :type kwargs: Any - """ - self.format(*args, message_type=CommonMessageType.INFO, update_tokens=update_tokens, **kwargs) - - def format_info_with_message(self, message: str, *args, update_tokens: bool = True, **kwargs): - """format_info_with_message(message, *args, update_tokens=True, **kwargs) - - Log a message containing pformatted arguments and keyword arguments with message type INFO. - - :param message: The message to log. - :type message: str - :param update_tokens: If set to True, when an arg or kwarg value is a Sim or SimInfo, it will be converted to their name before format occurs. Default is True. - :type update_tokens: bool, optional - :param args: Arguments to format into the message. - :type args: Any - :param kwargs: Keyword Arguments to format into the message. - :type kwargs: Any - """ - self.format_with_message(message, *args, message_type=CommonMessageType.INFO, update_tokens=update_tokens, **kwargs) - - def format( - self, - *args, - message_type: CommonMessageType = CommonMessageType.DEBUG, - update_tokens: bool = True, - **kwargs - ): - """format(*args, message_type=CommonMessageType.DEBUG, update_tokens=True, **kwargs) - - Log a non-descriptive message containing pformatted arguments and keyword arguments with the specified message type. - - :param message_type: The MessageType of the logged message. Default is CommonMessageType.DEBUG. - :type message_type: CommonMessageType, optional - :param update_tokens: If set to True, when an arg or kwarg value is a Sim or SimInfo, it will be converted to their name before format occurs. Default is True. - :type update_tokens: bool, optional - :param args: Arguments to format into the message. - :type args: Any - :param kwargs: Keyword Arguments to format into the message. - :type kwargs: Any - """ - if self.is_enabled(message_type): - if update_tokens: - args = self._update_args(*args) - kwargs = self._update_kwargs(**kwargs) - if args and kwargs: - self._log_message(message_type, '{}, {}'.format(pformat(args), pformat(kwargs))) - elif args: - self._log_message(message_type, '{}'.format(pformat(args))) - else: - self._log_message(message_type, '{}'.format(pformat(kwargs))) - - def format_with_message( - self, - message: str, - *args, - message_type: CommonMessageType = CommonMessageType.DEBUG, - update_tokens: bool = True, - **kwargs - ): - """format_with_message(message, *args, message_type=CommonMessageType.DEBUG, update_tokens=True, **kwargs) - - Log a message containing pformatted arguments and keyword arguments with the specified message type. - - :param message: The message to log. - :type message: str - :param message_type: The type of message being logged. Default is CommonMessageType.DEBUG. - :type message_type: CommonMessageType, optional - :param update_tokens: If set to True, when an arg or kwarg value is a Sim or SimInfo, it will be converted to their name before format occurs. Default is True. - :type update_tokens: bool, optional - :param args: Arguments to format into the message. - :type args: Any - :param kwargs: Keyword Arguments to format into the message. - :type kwargs: Any - """ - if self.is_enabled(message_type): - if update_tokens: - args = self._update_args(*args) - kwargs = self._update_kwargs(**kwargs) - if args and kwargs: - self._log_message(message_type, '{} {}, {}'.format(message, pformat(args), pformat(kwargs))) - elif args: - self._log_message(message_type, '{} {}'.format(message, pformat(args))) - elif kwargs: - self._log_message(message_type, '{} {}'.format(message, pformat(kwargs))) - else: - self._log_message(message_type, message) - - def warn(self, message: str): - """warn(message) - - Log a message with message type WARN. - - :param message: The message to log. - :type message: str - """ - if self.is_enabled(CommonMessageType.WARN): - self._log_message(CommonMessageType.WARN, message) - - def format_warn(self, *args: Any, update_tokens: bool = True, **kwargs: Any): - """format_warn(*args, update_tokens=True, **kwargs) - - Log a non-descriptive message containing pformatted arguments and keyword arguments with message type WARN. - - :param update_tokens: If set to True, when an arg or kwarg value is a Sim or SimInfo, it will be converted to their name before format occurs. Default is True. - :type update_tokens: bool, optional - :param args: Arguments to format into the message. - :type args: Any - :param kwargs: Keyword Arguments to format into the message. - :type kwargs: Any - """ - self.format(*args, message_type=CommonMessageType.WARN, update_tokens=update_tokens, **kwargs) - - def format_warn_with_message(self, message: str, *args, update_tokens: bool = True, **kwargs): - """format_warn_with_message(message, *args, update_tokens=True, **kwargs) - - Log a message containing pformatted arguments and keyword arguments with message type WARN. - - :param message: The message to log. - :type message: str - :param update_tokens: If set to True, when an arg or kwarg value is a Sim or SimInfo, it will be converted to their name before format occurs. Default is True. - :type update_tokens: bool, optional - :param args: Arguments to format into the message. - :type args: Any - :param kwargs: Keyword Arguments to format into the message. - :type kwargs: Any - """ - self.format_with_message(message, *args, message_type=CommonMessageType.WARN, update_tokens=update_tokens, **kwargs) - - def error( - self, - message: str, - message_type: CommonMessageType = CommonMessageType.ERROR, - exception: Exception = None, - throw: bool = True, - stack_trace: List[str] = None - ): - """error(message, message_type=CommonMessageType.ERROR, exception=None, throw=True, stack_trace=None) - - Log an error message with the specified message type - - :param message: The message to log. - :type message: str - :param message_type: The message type of the error message. Default is CommonMessageType.ERROR. - :type message_type: CommonMessageType, optional - :param exception: The exception that occurred. Default is None. - :type exception: Exception, optional - :param stack_trace: The stack trace leading to the exception, if not supplied, a stack trace will be gathered for you. Default is None. - :type stack_trace: List[str], optional - :param throw: If set to True, the exception will be rethrown. - :type throw: bool, optional - """ - if throw: - stack_trace = stack_trace or CommonStacktraceUtil.get_full_stack_trace() - self._log_error(message, exception=exception, stack_trace=stack_trace) - self._log_message(message_type, message) - if exception is not None: - self._log_message(message_type, pformat(exception)) - - def format_error( - self, - *args, - exception: Exception = None, - throw: bool = True, - update_tokens: bool = True, - stack_trace: List[str] = None, - **kwargs - ): - """format_error(*args, exception=None, throw=True, update_tokens=True, stack_trace=None, **kwargs) - - Log a non-descriptive error message containing pformatted arguments and keyword arguments. - - :param exception: The exception that occurred. - :type exception: Exception, optional - :param throw: If set to True, the exception will be rethrown. - :type throw: bool, optional - :param update_tokens: If set to True, when an arg or kwarg value is a Sim or SimInfo, it will be converted to their name before format occurs. Default is True. - :type update_tokens: bool, optional - :param stack_trace: The stack trace leading to the exception, if not supplied, a stack trace will be gathered for you. Default is None. - :type stack_trace: List[str], optional - :param args: Arguments to format into the message. - :type args: Any - :param kwargs: Keyword Arguments to format into the message. - :type kwargs: Any - """ - if update_tokens: - args = self._update_args(*args) - kwargs = self._update_kwargs(**kwargs) - stack_trace = stack_trace or CommonStacktraceUtil.get_full_stack_trace() - if args and kwargs: - self.error('{}, {}'.format(pformat(args), pformat(kwargs)), exception=exception, throw=throw, stack_trace=stack_trace) - elif args: - self.error('{}'.format(pformat(args)), exception=exception, throw=throw, stack_trace=stack_trace) - else: - self.error('{}'.format(pformat(kwargs)), exception=exception, throw=throw, stack_trace=stack_trace) - - def format_error_with_message( - self, - message: str, - *args, - exception: Exception = None, - throw: bool = True, - update_tokens: bool = True, - stack_trace: List[str] = None, - **kwargs - ): - """format_error_with_message(\ - message,\ - *args,\ - exception=None,\ - throw=True,\ - update_tokens=True,\ - stack_trace=None,\ - **kwargs\ - ) - - Log an error message containing pformatted arguments and keyword arguments. - - :param message: The message to log. - :type message: str - :param exception: The exception that occurred. Default is None. - :type exception: Exception, None - :param throw: If set to True, the exception will be rethrown. Default is True. - :type throw: bool, optional - :param update_tokens: If set to True, when an arg or kwarg value is a Sim or SimInfo, it will be converted to their name before format occurs. Default is True. - :type update_tokens: bool, optional - :param stack_trace: The stack trace leading to the exception, if not supplied, a stack trace will be gathered for you. Default is None. - :type stack_trace: List[str], optional - :param args: Arguments to format into the message. - :type args: Any - :param kwargs: Keyword Arguments to format into the message. - :type kwargs: Any - """ - if update_tokens: - args = self._update_args(*args) - kwargs = self._update_kwargs(**kwargs) - stack_trace = stack_trace or CommonStacktraceUtil.get_full_stack_trace() - if args and kwargs: - self.error('{} {}, {}'.format(message, pformat(args), pformat(kwargs)), exception=exception, throw=throw, stack_trace=stack_trace) - elif args: - self.error('{} {}'.format(message, pformat(args)), exception=exception, throw=throw, stack_trace=stack_trace) - elif kwargs: - self.error('{} {}'.format(message, pformat(kwargs)), exception=exception, throw=throw, stack_trace=stack_trace) - else: - self.error(message, exception=exception, throw=throw, stack_trace=stack_trace) - - def log_stack(self) -> None: - """log_stack() - - Log the current stack trace and the calling frames - - .. note:: The best use for this is to find the path of invocation to the location this function is called at. - - """ - if not self.is_enabled(CommonMessageType.DEBUG): - return - import inspect - current_frame = inspect.currentframe() - calling_frame = inspect.getouterframes(current_frame, 2) - self.format(calling_frame) - - def enable( - self, - message_types: Iterator[CommonMessageType] = ( - CommonMessageType.WARN, - CommonMessageType.DEBUG, - CommonMessageType.INFO - ), - enable_logging_extra_sim_details: bool = False - ) -> None: - """enable(\ - message_types=(CommonMessageType.WARN, CommonMessageType.DEBUG, CommonMessageType.INFO),\ - enable_extra_sim_details=False\ - ) - - Enable the log or specific types of logs. - - :param message_types: The types of messages to enable for logging. Default message types are Info, Debug, and Warn. - :rtype message_types: Tuple[CommonMessageTypes], optional - :param enable_logging_extra_sim_details: If True, when a Sim is being logged, extra Sim details, such as Sim Type and Current Sim Type, will be logged in addition to their name and id. If False, only their name and id will be logged. Default is False. - :type enable_logging_extra_sim_details: bool, optional - """ - self._enabled_message_types = message_types or tuple() - if enable_logging_extra_sim_details: - self.enable_logging_extra_sim_details() - - def enable_logging_extra_sim_details(self) -> None: - """enable_logging_extra_sim_details() - - Enable the logging of extra Sim details, when logging a Sim, such as Sim Type and Sim Current Type. - """ - self._should_log_extra_sim_details = True - - def disable_logging_extra_sim_details(self) -> None: - """disable_logging_extra_sim_details() - - Disable the logging of extra Sim details when logging a Sim, such as Sim Type and Sim Current Type. - """ - self._should_log_extra_sim_details = False - - def disable(self) -> None: - """disable() - - Disable the log - - """ - self._enabled_message_types = tuple() - self.disable_logging_extra_sim_details() - - @property - def enabled(self) -> bool: - """Determine whether the log is enabled or not. - - .. note:: All logs are disabled by default. - - :return: True, if the log is enabled. False, if the log is disabled. - :rtype: bool - """ - return any(self._enabled_message_types) - - @property - def name(self) -> str: - """The identifier of this log. - - :return: A string identifier. - :rtype: str - """ - return self._log_name - - @property - def mod_name(self) -> str: - """The name of the mod that owns the log. - - :return: The name of the mod that owns the log - :rtype: str - """ - return self._mod_name - - @property - def messages_file_path(self) -> str: - """The file path messages are logged to. - - :return: The file path messages are logged to. - :rtype: str - """ - return CommonLogUtils.get_message_file_path(self.mod_name, custom_file_path=self._custom_file_path) - - @property - def exceptions_file_path(self) -> str: - """The file path exceptions are logged to. - - :return: The file path exceptions are logged to. - :rtype: str - """ - return CommonLogUtils.get_exceptions_file_path(self.mod_name, custom_file_path=self._custom_file_path) - - def is_enabled(self, message_type: CommonMessageType) -> bool: - """is_enabled(message_type) - - Determine if a message type is enabled for logging. - - :param message_type: The type of messages to check for allowance. - :type message_type: CommonMessageType - :return: True, if the specified message type is enabled for logging. False, if not. - :rtype: bool - """ - return message_type in self._enabled_message_types - - def _log_message(self, message_type: CommonMessageType, message: str): - from s4ap.sims4communitylib.utils.common_date_utils import CommonRealDateUtils - from s4ap.sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler - current_date_time = CommonRealDateUtils.get_current_date_string() - new_message = '{} {}: [{}]: {}\n'.format(current_date_time, getattr(message_type, 'name', str(message_type)), self.name, message) - try: - from s4ap.sims4communitylib.utils.common_io_utils import CommonIOUtils - file_path = self.messages_file_path - os.makedirs(os.path.dirname(file_path), exist_ok=True) - CommonIOUtils.write_to_file(file_path, new_message, ignore_errors=True) - except Exception as ex: - CommonExceptionHandler.log_exception(self.mod_name, 'Error occurred while attempting to log message: {}'.format(pformat(message)), exception=ex, custom_file_path=self._custom_file_path) - - def _log_error(self, message: str, exception: Exception = None, stack_trace: List[str] = None): - from s4ap.sims4communitylib.utils.common_date_utils import CommonRealDateUtils - from s4ap.sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler - try: - exceptions = stack_trace or CommonStacktraceUtil.get_full_stack_trace() - if exception is not None: - stack_trace_message = '{}{} -> {}: {}\n'.format(''.join(exceptions), message, type(exception).__name__, exception) - else: - stack_trace_message = '{}{}\n'.format(''.join(exceptions), message) - file_path = self.exceptions_file_path - os.makedirs(os.path.dirname(file_path), exist_ok=True) - exception_traceback_text = '[{}] {} {}\n'.format(self.mod_name, CommonRealDateUtils.get_current_date_string(), stack_trace_message) - result = CommonIOUtils.write_to_file(file_path, exception_traceback_text, ignore_errors=True) - if result: - CommonExceptionHandler._notify_exception_occurred(file_path, mod_identifier=self.mod_name) - except Exception as ex: - CommonExceptionHandler.log_exception(self.mod_name, 'Error occurred while attempting to log message: {}'.format(pformat(message)), exception=ex, custom_file_path=self._custom_file_path) - - def _update_args(self, *args: Any) -> Tuple[Any]: - if not args: - return args - from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils - from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils - from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - new_args: List[Any] = list() - for arg in args: - if CommonTypeUtils.is_sim_or_sim_info(arg) or CommonTypeUtils.is_sim_info_base_wrapper(arg): - obj_type_acronym = 'Unknown' - if CommonTypeUtils.is_sim_info(arg): - obj_type_acronym = 'SI' - elif CommonTypeUtils.is_sim_instance(arg): - obj_type_acronym = 'S' - elif CommonTypeUtils.is_sim_info_base_wrapper(arg): - obj_type_acronym = 'SIBW' - if self._should_log_extra_sim_details: - from s4ap.sims4communitylib.utils.sims.common_sim_type_utils import CommonSimTypeUtils - sim_info = CommonSimUtils.get_sim_info(arg) - sim_types = tuple(CommonSimTypeUtils.get_all_sim_types_gen(sim_info, combine_teen_young_adult_and_elder_age=False, combine_child_dog_types=False)) - current_sim_type = CommonSimTypeUtils.determine_sim_type(sim_info, combine_teen_young_adult_and_elder_age=False, combine_child_dog_types=False, use_current_occult_type=True) - new_args.append('{} ({}, ({}), C:{}) [{}]'.format(CommonSimNameUtils.get_full_name(arg), str(CommonSimUtils.get_sim_id(arg)), ', '.join([sim_type.name for sim_type in sim_types]), current_sim_type.name, obj_type_acronym)) - else: - new_args.append('{} ({}) [{}]'.format(CommonSimNameUtils.get_full_name(arg), str(CommonSimUtils.get_sim_id(arg)), obj_type_acronym)) - else: - new_args.append(arg) - return tuple(new_args) - - def _update_kwargs(self, **kwargs: Any) -> Dict[str, Any]: - if not kwargs: - return kwargs - new_kwargs: Dict[str, Any] = dict() - from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils - from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils - from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - for (key, val) in kwargs.items(): - if CommonTypeUtils.is_sim_or_sim_info(val) or CommonTypeUtils.is_sim_info_base_wrapper(val): - obj_type_acronym = 'UnknownType' - if CommonTypeUtils.is_sim_info(val): - obj_type_acronym = 'SI' - elif CommonTypeUtils.is_sim_instance(val): - obj_type_acronym = 'S' - elif CommonTypeUtils.is_sim_info_base_wrapper(val): - obj_type_acronym = 'SIBW' - - if self._should_log_extra_sim_details: - from s4ap.sims4communitylib.utils.sims.common_sim_type_utils import CommonSimTypeUtils - sim_info = CommonSimUtils.get_sim_info(val) - sim_types = tuple(CommonSimTypeUtils.get_all_sim_types_gen(sim_info, combine_teen_young_adult_and_elder_age=False, combine_child_dog_types=False)) - current_sim_type = CommonSimTypeUtils.determine_sim_type(sim_info, combine_teen_young_adult_and_elder_age=False, combine_child_dog_types=False, use_current_occult_type=True) - new_kwargs[key] = '{} ({}, ({}), C:{}) [{}]'.format(CommonSimNameUtils.get_full_name(val), str(CommonSimUtils.get_sim_id(val)), ', '.join([sim_type.name for sim_type in sim_types]), current_sim_type.name, obj_type_acronym) - else: - new_kwargs[key] = '{} ({}) [{}]'.format(CommonSimNameUtils.get_full_name(val), str(CommonSimUtils.get_sim_id(val)), obj_type_acronym) - else: - new_kwargs[key] = val - return new_kwargs - - -class CommonLogRegistry(CommonService): - """CommonLogRegistry() - - Used to register logs. - - .. note:: To register your own logs, please use :func:`~get` to create a CommonLogRegistry (CommonLogRegistry.get()). - - - :Example Usage: - - .. highlight:: python - .. code-block:: python - - # Register the log, Logs will appear in a file titled "MOD_NAME_Messages.txt" and messages logged using this log will be prefixed with "s4cl_log_name" - log = CommonLogRegistry.get().register_log('MOD_NAME', 's4cl_log_name') - # Enable the log, if not enabled, messages will not be logged. - log.enable() - # Log a message - log.debug('Printing a message to the log.') - # Disable the log - log.disable() - - # The MOD_NAME_Messages.txt file will contain the "Printing a message to the log." message. - - .. note:: - - Available Commands: - - - `s4clib.enable_log` or `s4clib.enablelog` - - `s4clib.disable_log` or `s4clib.disablelog` - - `s4clib.disable_all_logs` or `s4clib.disablealllogs` - - `s4clib.logs` - - """ - def __init__(self) -> None: - self._registered_logs: Dict[str, Dict[str, CommonLog]] = dict() - self._delete_old_log_files() - - def get_registered_log_names(self, mod_identifier: Union[str, CommonModIdentity] = None) -> List[str]: - """get_registered_log_names() - - Retrieve the names of all registered logs. - - :param mod_identifier: The name or identifier of the mod the log is registered for. Default is None. - :type mod_identifier: Union[str, CommonModIdentity], optional - :return: A collection of registered logs. - :rtype: List[str] - """ - if self._registered_logs is None: - return list() - if mod_identifier is None: - log_names = [] - for log_mod_name in self._registered_logs: - for log_name in self._registered_logs[log_mod_name]: - log_names.append(log_name) - return log_names - else: - mod_name = CommonModIdentity._get_mod_name(mod_identifier) - mod_name = mod_name.lower() - if mod_name not in self._registered_logs: - return list() - return list(self._registered_logs[mod_name].keys()) - - def register_log(self, mod_identifier: Union[str, CommonModIdentity], log_name: str, custom_file_path: str = None) -> CommonLog: - """register_log(mod_identifier, log_name, custom_file_path: str=None) - - Create and register a log with the specified name. - - .. note:: If `log_name` matches the name of a Log already registered, that log will be returned rather than creating a new Log. - - :param mod_identifier: The name or identifier of the mod the log is registered for. - :type mod_identifier: Union[str, CommonModIdentity] - :param log_name: The name of the log. - :type log_name: str - :param custom_file_path: A custom file path relative to The Sims 4 folder. Example: Value is 'fake_path/to/directory', the final path would be 'The Sims 4/fake_path/to_directory'. Default is None. - :type custom_file_path: str, optional - :return: An object of type CommonLog - :rtype: CommonLog - """ - if self._registered_logs is None: - self._registered_logs = dict() - mod_name = CommonModIdentity._get_mod_name(mod_identifier) - mod_name = mod_name.lower() - first_time_log = False - # Dict[str, Dict[str, CommonLog]] - if mod_name not in self._registered_logs: - first_time_log = True - self._registered_logs[mod_name] = dict() - # Dict[str, CommonLog] - if log_name in self._registered_logs[mod_name]: - return self._registered_logs[mod_name][log_name] - log = CommonLog(mod_identifier, log_name, custom_file_path=custom_file_path) - from s4ap.sims4communitylib.s4cl_configuration import S4CLConfiguration - if log_name in S4CLConfiguration().enable_logs: - log.enable(message_types=S4CLConfiguration().enable_logs[log_name]) - self._registered_logs[mod_name][log_name] = log - if first_time_log: - if mod_identifier is not None: - if _log is not None: - _log.enable() - if isinstance(mod_identifier, CommonModIdentity): - _log.debug(f'{mod_identifier.name} Version "{mod_identifier.version}" detected.') - else: - _log.debug(f'{mod_identifier} detected.') - _log.disable() - else: - current_game_version = CommonLogUtils.get_sims_4_game_version() - log.enable() - log.debug(f'The Sims 4 Game Version "{current_game_version}" detected.') - if isinstance(mod_identifier, CommonModIdentity): - log.debug(f'{mod_identifier.name} Version "{mod_identifier.version}" detected.') - else: - log.debug(f'{mod_identifier} detected.') - log.disable() - return log - - def _delete_old_log_files(self) -> None: - from s4ap.sims4communitylib.utils.common_io_utils import CommonIOUtils - files_to_delete = ( - os.path.join(CommonLogUtils.get_sims_documents_location_path(), 'mod_logs'), - ) - for file_to_delete in files_to_delete: - # noinspection PyBroadException - try: - if os.path.isfile(file_to_delete): - CommonIOUtils.delete_file(file_to_delete, ignore_errors=True) - else: - CommonIOUtils.delete_directory(file_to_delete, ignore_errors=True) - except: - continue - - # noinspection PyUnusedLocal - def log_exists(self, log_name: str, mod_identifier: Union[str, CommonModIdentity] = None) -> bool: - """log_exists(log_name, mod_identifier=None) - - Determine if logs exist with the specified name. - - :param log_name: The name of the log to locate. - :type log_name: str - :param mod_identifier: The name or identity of the mod the log belongs to. Default is None. - :type mod_identifier: Union[str, CommonModIdentity], optional - :return: True, if a handler exists with the specified name. - :rtype: bool - """ - if self._registered_logs is None: - return False - if mod_identifier is None: - for log_mod_name in self._registered_logs: - if log_name not in self._registered_logs[log_mod_name]: - continue - return True - else: - mod_name = CommonModIdentity._get_mod_name(mod_identifier) - mod_name = mod_name.lower() - return mod_name in self._registered_logs and log_name in self._registered_logs[mod_name] - - # noinspection PyUnusedLocal - def enable_logs(self, log_name: str, mod_identifier: Union[str, CommonModIdentity] = None) -> bool: - """enable_logs(log_name, mod_identifier=None) - - Enable all logs with the specified name. - - :param log_name: The name of the logs to enable. - :type log_name: str - :param mod_identifier: The name or identity of the mod the log belongs to. Default is None. - :type mod_identifier: Union[str, CommonModIdentity], optional - :return: True, if successful. False, if not. - :rtype: bool - """ - if self._registered_logs is None: - self._registered_logs = dict() - if mod_identifier is None: - for log_mod_name in self._registered_logs: - if log_name not in self._registered_logs[log_mod_name]: - continue - log = self._registered_logs[log_mod_name][log_name] - log.enable() - else: - mod_name = CommonModIdentity._get_mod_name(mod_identifier) - mod_name = mod_name.lower() - if mod_name not in self._registered_logs: - return False - if log_name not in self._registered_logs[mod_name]: - log = self.register_log(mod_name, log_name) - if log is not None: - log.enable() - return True - return False - self._registered_logs[mod_name][log_name].enable() - return True - - # noinspection PyUnusedLocal - def disable_logs(self, log_name: str, mod_identifier: Union[str, CommonModIdentity] = None) -> bool: - """disable_logs(log_name, mod_identifier=None) - - Disable all logs with the specified name. - - :param log_name: The name of the logs to disable. - :type log_name: str - :param mod_identifier: The name or identity of the mod to disable logs for. Default is None. - :type mod_identifier: Union[str, CommonModIdentity], optional - :return: True, if successful. False, if not. - :rtype: bool - """ - if self._registered_logs is None: - self._registered_logs = dict() - if mod_identifier is None: - for log_mod_name in self._registered_logs: - if log_name not in self._registered_logs[log_mod_name]: - continue - log = self._registered_logs[log_mod_name][log_name] - log.disable() - else: - mod_name = CommonModIdentity._get_mod_name(mod_identifier) - mod_name = mod_name.lower() - if mod_name not in self._registered_logs: - return False - if log_name not in self._registered_logs[mod_name]: - return False - self._registered_logs[mod_name][log_name].disable() - return True - - # noinspection PyUnusedLocal - def enable_all_logs(self, mod_identifier: Union[str, CommonModIdentity] = None) -> bool: - """enable_all_logs(mod_identifier=None) - - Enable all logs from logging - - :param mod_identifier: The name or identity of the mod to enable logs for. Default is None. - :type mod_identifier: Union[str, CommonModIdentity], optional - :return: True, if successful. False, if not. - :rtype: bool - """ - if self._registered_logs is None: - self._registered_logs = dict() - if mod_identifier is None: - for log_mod_name in self._registered_logs: - for log_name in self._registered_logs[log_mod_name]: - self._registered_logs[log_mod_name][log_name].enable() - else: - mod_name = CommonModIdentity._get_mod_name(mod_identifier) - mod_name = mod_name.lower() - if mod_name not in self._registered_logs: - return False - for log_name in self._registered_logs[mod_name]: - self._registered_logs[mod_name][log_name].enable() - return True - - # noinspection PyUnusedLocal - def disable_all_logs(self, mod_identifier: Union[str, CommonModIdentity] = None) -> bool: - """disable_all_logs(mod_identifier=None) - - Disable all logs from logging - - :param mod_identifier: The name or identity of the mod to disable logs for. Default is None. - :type mod_identifier: Union[str, CommonModIdentity], optional - :return: True, if successful. False, if not. - :rtype: bool - """ - if self._registered_logs is None: - self._registered_logs = dict() - if mod_identifier is None: - for log_mod_name in self._registered_logs: - for log_name in self._registered_logs[log_mod_name]: - self._registered_logs[log_mod_name][log_name].disable() - else: - mod_name = CommonModIdentity._get_mod_name(mod_identifier) - mod_name = mod_name.lower() - if mod_name not in self._registered_logs: - return False - for log_name in self._registered_logs[mod_name]: - self._registered_logs[mod_name][log_name].disable() - return True - - -# noinspection PyRedeclaration -_log = CommonLogRegistry().register_log(ModInfo.get_identity(), 's4cl_log_registry') diff --git a/Scripts/s4ap/sims4communitylib/utils/common_log_utils.py b/Scripts/s4ap/sims4communitylib/utils/common_log_utils.py deleted file mode 100644 index 253385a..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/common_log_utils.py +++ /dev/null @@ -1,206 +0,0 @@ -""" -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 -""" -import os -from typing import Union - -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity - - -class CommonLogUtils: - """Utilities for retrieving the paths used for logging. - - """ - - @staticmethod - def get_sims_4_game_version() -> str: - """get_sims_4_game_version() - - Retrieve the current game version of Sims 4. - - :return: The current game version of Sims 4. - :rtype: str - """ - the_sims_4_folder = CommonLogUtils.get_sims_documents_location_path() - filename = os.path.join(the_sims_4_folder, 'GameVersion.txt') - import re - with open(filename, 'rb') as fp: - v = fp.read().decode(errors='ignore') # convert b to str and ignore errors - v = re.sub(r'[^0-9.]', '', v) # in case of UTF-8 characters which survived 'ignore': replace everything with '' except of '0-9' and '.' - return v - - @staticmethod - def get_exceptions_file_path(mod_identifier: Union[str, CommonModIdentity], custom_file_path: str=None) -> str: - """get_exceptions_file_path(mod_identifier, custom_file_path=None) - - Retrieve the file path to the Exceptions file used for logging error messages. - - :param mod_identifier: The name or identity of the mod requesting the file path. - :type mod_identifier: Union[str, CommonModIdentity] - :param custom_file_path: A custom file path relative to The Sims 4 folder. Example: Value is 'fake_path/to/directory', the final path would be 'The Sims 4/fake_path/to_directory'. Default is None. - :type custom_file_path: str, optional - :return: A file path to the Exceptions file. - :rtype: str - """ - return CommonLogUtils._get_file_name(mod_identifier, 'Exceptions', custom_file_path=custom_file_path) - - @staticmethod - def get_message_file_path(mod_identifier: Union[str, CommonModIdentity], custom_file_path: str=None) -> str: - """get_message_file_path(mod_identifier, custom_file_path=None) - - Retrieve the file path to the Messages file used for logging info/debug messages. - - :param mod_identifier: The name of the mod requesting the file path. - :type mod_identifier: Union[str, CommonModIdentity] - :param custom_file_path: A custom file path relative to The Sims 4 folder. Example: Value is 'fake_path/to/directory', the final path would be 'The Sims 4/fake_path/to_directory'. Default is None. - :type custom_file_path: str, optional - :return: A file path to the Messages file. - :rtype: str - """ - return CommonLogUtils._get_file_name(mod_identifier, 'Messages', custom_file_path=custom_file_path) - - @staticmethod - def get_old_exceptions_file_path(mod_identifier: Union[str, CommonModIdentity], custom_file_path: str=None) -> str: - """get_old_exceptions_file_path(mod_identifier, custom_file_path=None) - - Retrieve the file path to the Old Exceptions file used as the overflow when the main Exception file becomes too large. - - :param mod_identifier: The name or identity of the mod requesting the file path. - :type mod_identifier: Union[str, CommonModIdentity] - :param custom_file_path: A custom file path relative to The Sims 4 folder. Example: Value is 'fake_path/to/directory', the final path would be 'The Sims 4/fake_path/to_directory'. Default is None. - :type custom_file_path: str, optional - :return: A file path to the Old Exceptions file. - :rtype: str - """ - return CommonLogUtils._get_old_file_path_name(mod_identifier, 'Exceptions', custom_file_path=custom_file_path) - - @staticmethod - def get_old_message_file_path(mod_identifier: Union[str, CommonModIdentity], custom_file_path: str=None) -> str: - """get_old_message_file_path(mod_identifier, custom_file_path=None) - - Retrieve the file path to the Old Messages file used as the overflow when the main Messages file becomes too large. - - :param mod_identifier: The name of the mod requesting the file path. - :type mod_identifier: Union[str, CommonModIdentity] - :param custom_file_path: A custom file path relative to The Sims 4 folder. Example: Value is 'fake_path/to/directory', the final path would be 'The Sims 4/fake_path/to_directory'. Default is None. - :type custom_file_path: str, optional - :return: A file path to the Old Messages file. - :rtype: str - """ - return CommonLogUtils._get_old_file_path_name(mod_identifier, 'Messages', custom_file_path=custom_file_path) - - @staticmethod - def get_sims_documents_location_path() -> str: - """get_sims_documents_location_path() - - Retrieve the full path of the folder 'Documents\Electronic Arts\The Sims 4' - - :return: The file path to 'Documents\Electronic Arts\The Sims 4' folder. - :rtype: str - """ - # return os.environ['TS4_MODS_FOLDER'] - documents_path = os.path.dirname(CommonLogUtils.get_mods_location_path()) - if os.path.exists(documents_path): - return documents_path - from s4ap.sims4communitylib.modinfo import ModInfo - root_file = os.path.normpath(os.path.dirname(os.path.realpath(ModInfo.get_identity().file_path))).replace(os.sep, '/') - root_file_split = root_file.split('/') - if 'Mods' not in root_file_split: - return '' - file_path = '' - # noinspection PyTypeChecker - exit_index = len(root_file_split) - root_file_split.index('Mods') - for index in range(0, len(root_file_split) - exit_index): - file_path = os.path.join(file_path + os.sep, str(root_file_split[index])) - return file_path - - @staticmethod - def get_mods_location_path() -> str: - """get_sims_mods_location_path() - - Retrieve the full path of the folder 'Documents\Electronic Arts\The Sims 4\Mods' - - :return: The file path to 'Documents\Electronic Arts\The Sims 4\Mods' folder. - :rtype: str - """ - current_file_path = os.path.dirname(os.path.abspath(__file__)) - mods_folder = os.path.join(current_file_path.partition(f"{os.sep}Mods{os.sep}")[0], 'Mods') - return mods_folder - - @staticmethod - def get_mod_logs_location_path() -> str: - """get_mod_logs_location_path() - - Retrieve the full path of the folder 'Documents\Electronic Arts\The Sims 4\mod_logs' - - :return: The file path to 'Documents\Electronic Arts\The Sims 4\mod_logs' folder. - :rtype: str - """ - sims_documents_location = CommonLogUtils.get_sims_documents_location_path() - if sims_documents_location == '': - return '' - return os.path.join(sims_documents_location, 'mod_logs') - - @staticmethod - def get_mod_data_location_path() -> str: - """get_mod_data_location_path() - - Retrieve the full path of the folder 'Documents\Electronic Arts\The Sims 4\Mods\mod_data' - - :return: The file path to 'Documents\Electronic Arts\The Sims 4\Mods\mod_data' folder. - :rtype: str - """ - mods_location = CommonLogUtils.get_mods_location_path() - if mods_location == '': - return '' - return os.path.join(mods_location, 'mod_data') - - @staticmethod - def _get_file_name(mod_identifier: Union[str, CommonModIdentity], file_name: str, custom_file_path: str=None) -> str: - from s4ap.sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils - mod_identifier = CommonModIdentityUtils.determine_mod_name_from_identifier(mod_identifier) - file_path = CommonLogUtils.get_mod_logs_location_path() - file_name = '{}_{}.txt'.format(mod_identifier, file_name) - if not os.path.exists(file_path): - os.makedirs(file_path, exist_ok=True) - if custom_file_path is not None: - file_path = os.path.join(file_path, custom_file_path) - current_file = os.path.join(file_path, file_name) - try: - if os.path.exists(current_file) and CommonLogUtils._file_is_too_big(current_file): - new_file_name = file_name.replace('.txt', '') - old_file_name = None - for x in range(20): - old_file_name = 'Old_{}_{}.txt'.format(new_file_name, x) - if not os.path.exists(os.path.join(file_path, old_file_name)): - break - if old_file_name is None: - return current_file - old_file_path = os.path.join(file_path, old_file_name) - if os.path.exists(old_file_path): - os.remove(old_file_path) - os.rename(current_file, old_file_path) - except PermissionError: - pass - return current_file - - @staticmethod - def _get_old_file_path_name(mod_identifier: Union[str, CommonModIdentity], file_name: str, custom_file_path: str=None) -> str: - from s4ap.sims4communitylib.utils.misc.common_mod_identity_utils import CommonModIdentityUtils - mod_identifier = CommonModIdentityUtils.determine_mod_name_from_identifier(mod_identifier) - file_path = CommonLogUtils.get_mod_logs_location_path() - old_file_name = 'Old_{}_{}.txt'.format(mod_identifier, file_name) - if not os.path.exists(file_path): - os.makedirs(file_path, exist_ok=True) - if custom_file_path is not None: - file_path = os.path.join(file_path, custom_file_path) - return os.path.join(file_path, old_file_name) - - @staticmethod - def _file_is_too_big(file_path: str) -> bool: - from s4ap.sims4communitylib.s4cl_configuration import S4CLConfiguration - return os.path.getsize(file_path) > S4CLConfiguration().max_output_file_size_in_bytes diff --git a/Scripts/s4ap/sims4communitylib/utils/common_math_utils.py b/Scripts/s4ap/sims4communitylib/utils/common_math_utils.py deleted file mode 100644 index 59f63dc..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/common_math_utils.py +++ /dev/null @@ -1,97 +0,0 @@ -""" -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 -""" -import math -import sims4.math as sims_math - -from s4ap.sims4communitylib.classes.math.common_vector3 import CommonVector3 - - -class CommonMathUtils: - """ Utilities for math operations. """ - - @staticmethod - def calculate_degrees_between_positions(position_one: CommonVector3, position_two: CommonVector3) -> float: - """calculate_degrees_between_positions(position_one, position_two) - - Calculate the degrees between two positions. - - :param position_one: An instance of a Vector. - :type position_one: CommonVector3 - :param position_two: An instance of a Vector. - :type position_two: CommonVector3 - :return: The degrees between the specified Vectors. - :rtype: float - """ - return CommonMathUtils.radian_to_degrees(math.atan2(position_two.x - position_one.x, position_two.z - position_one.z)) - - @staticmethod - def radian_to_degrees(radian: float) -> float: - """radian_to_degrees(radian) - - Translate Radian to Degrees. - - :param radian: The value to convert. - :type radian: float - :return: The value as Degrees. - :rtype: float - """ - return radian * 180.0 / math.pi - - @staticmethod - def degrees_to_radian(degrees: float) -> float: - """degrees_to_radian(degrees) - - Translate Degrees to Radian. - - :param degrees: The value to convert. - :type degrees: float - :return: The value as Radian. - :rtype: float - """ - return degrees * math.pi / 180.0 - - @staticmethod - def calculate_distance(position_one: CommonVector3, position_two: CommonVector3, flatten_positions: bool=True) -> float: - """calculate_distance(position_one, position_two, flatten_positions=True) - - Calculate the distance between two vectors. - - :param position_one: An instance of a Vector. - :type position_one: CommonVector3 - :param position_two: An instance of a Vector. - :type position_two: CommonVector3 - :param flatten_positions: If True, both Vectors will be flattened before calculations will occur. Default is True. - :type flatten_positions: bool, optional - :return: The distance between the two specified vectors. - :rtype: float - """ - if flatten_positions: - position_one = CommonVector3.flatten(position_one) - position_two = CommonVector3.flatten(position_one) - return CommonVector3.distance_between(position_one, position_two) - - @staticmethod - def calculate_offset_from_degrees(position: CommonVector3, degrees: float, length: float) -> CommonVector3: - """calculate_offset_from_degrees(position, degrees, length) - - Calculate an offset vector based on the forward axis from a vector. - - :param position: The original position. - :type position: CommonVector3 - :param degrees: Amount of degrees to offset. - :type degrees: float - :param length: The length of the offset. - :type length: float - :return: The vector offset. - :rtype: CommonVector3 - """ - offset_vector = sims_math.FORWARD_AXIS - # noinspection PyUnresolvedReferences - offset_vector = CommonQuaternion.from_degrees(degrees).transform_vector(offset_vector) - offset_vector = sims_math.vector_normalize(offset_vector) * length - return position + offset_vector diff --git a/Scripts/s4ap/sims4communitylib/utils/common_resource_utils.py b/Scripts/s4ap/sims4communitylib/utils/common_resource_utils.py deleted file mode 100644 index 03d48db..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/common_resource_utils.py +++ /dev/null @@ -1,437 +0,0 @@ -""" -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 -""" -import services -from io import BytesIO -from typing import ItemsView, Any, Union, Tuple, Type, ValuesView, Dict, TypeVar, List -try: - from sims4.resources import ResourceLoader, Types - from sims4.tuning.instance_manager import InstanceManager - from sims4.tuning.merged_tuning_manager import get_manager - from sims4.tuning.dynamic_enum import DynamicEnumLocked, DynamicEnum - # noinspection PyUnresolvedReferences - from sims4.tuning.serialization import ETreeTuningLoader - from sims4.tuning.tunable_base import LoadingTags -except: - # noinspection PyMissingOrEmptyDocstring - class Types: - pass - - # noinspection PyMissingOrEmptyDocstring - class ResourceLoader: - pass - - # noinspection PyMissingOrEmptyDocstring - class InstanceManager: - pass - - # noinspection PyMissingTypeHints,PyMissingOrEmptyDocstring - def get_manager(): - pass - - # noinspection PyMissingOrEmptyDocstring - class DynamicEnumLocked: - pass - - # noinspection PyMissingOrEmptyDocstring - class DynamicEnum: - pass - - # noinspection PyMissingOrEmptyDocstring - class ETreeTuningLoader: - pass - - # noinspection PyMissingOrEmptyDocstring - class LoadingTags: - pass - -from s4ap.sims4communitylib.classes.common_resource_key import CommonResourceKey -from s4ap.sims4communitylib.enums.enumtypes.common_int import Int, CommonInt -from s4ap.sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity - -CommonEnumTypeValueType = TypeVar('CommonEnumTypeValueType', int, CommonInt, CommonIntFlags, Int, DynamicEnum, DynamicEnumLocked) - -CommonExpectedReturnType = TypeVar('CommonExpectedReturnType', bound=Any) - - -class CommonResourceUtils: - """Utilities for retrieving the Tuning files and instances of various resources. (Objects, Snippets, Statistics, etc.). - - """ - - # noinspection PyUnusedLocal - @staticmethod - def load_instance(instance_type: Types, instance_id: int, return_type: Type[CommonExpectedReturnType] = Any) -> CommonExpectedReturnType: - """load_instance(instance_type, instance_id, return_type=Any) - - Load an instance of the specified type. - - :Example Usage 1: - - .. highlight:: python - .. code-block:: python - - # This will retrieve an instance for the Confident mood and will be of type statistics.mood.Mood - mood_instance = CommonResourceUtils.load_instance(Types.MOOD, CommonMoodId.CONFIDENT) - - :Example Usage 2: - - .. highlight:: python - .. code-block:: python - - # This will retrieve an instance for the Walk Style Angry buff and will be of type buffs.buff.Buff - buff_instance = CommonResourceUtils.load_instance(Types.BUFF, CommonBuffId.WALK_STYLE_ANGRY) - - :param instance_type: The type of instance being loaded. - :type instance_type: Types - :param instance_id: The decimal identifier of an instance. - :type instance_id: int - :param return_type: The type of the returned value. (This is to make type hinting more accurate). It is not actually used in the function. Default is Any. - :type return_type: Type[CommonExpectedReturnType], optional - :return: An instance of the specified type or None if no instance was found. - :rtype: Any - """ - instance_manager = CommonResourceUtils.get_instance_manager(instance_type) - return CommonResourceUtils.load_instance_from_manager(instance_manager, instance_id) - - # noinspection PyUnusedLocal - @staticmethod - def load_instance_from_manager(instance_manager: InstanceManager, instance_id: int, return_type: Type[CommonExpectedReturnType] = Any) -> CommonExpectedReturnType: - """load_instance_from_manager(instance_manager, instance_id, return_type=Any) - - Load an instance from the specified InstanceManager. - - :param instance_manager: The InstanceManager an instance will be loaded from. - :type instance_manager: InstanceManager - :param instance_id: The decimal identifier of an instance. - :type instance_id: int - :param return_type: The type of the returned value. (This is to make type hinting more accurate). It is not actually used in the function. Default is Any. - :type return_type: Type[CommonExpectedReturnType], optional - :return: An instance of the specified type or None if no instance was found. - :rtype: Any - """ - return instance_manager.get(instance_id) - - # noinspection PyUnusedLocal - @staticmethod - def load_all_instances(instance_type: Types, return_type: Type[CommonExpectedReturnType] = Any) -> ItemsView[str, CommonExpectedReturnType]: - """load_all_instances(instance_type, return_type=Any) - - Load all instances of the specified type. - - :param instance_type: The type of instances being loaded. - :type instance_type: Types - :param return_type: The type of the returned value. (This is to make type hinting more accurate). It is not actually used in the function. Default is Any. - :type return_type: Type[CommonExpectedReturnType], optional - :return: An items view of all instances of the specified type. (Resource Key, Instance) - :rtype: ItemsView[str, Any] - """ - return CommonResourceUtils.get_instance_manager(instance_type).types.items() - - # noinspection PyUnusedLocal - @staticmethod - def load_all_instances_as_guid_to_instance(instance_type: Types, return_type: Type[CommonExpectedReturnType] = Any) -> Dict[int, CommonExpectedReturnType]: - """load_all_instances_as_guid_to_instance(instance_type, return_type=Any) - - Load all instances of the specified type and convert it to a dictionary mapping of GUID to Instance. - - :param instance_type: The type of instances being loaded. - :type instance_type: Types - :param return_type: The type of the returned value. (This is to make type hinting more accurate). It is not actually used in the function. Default is Any. - :type return_type: Type[CommonExpectedReturnType], optional - :return: A dictionary of instance GUID to instances of the specified type. - :rtype: Dict[int, Any] - """ - return dict([(value_key.instance, value) for (value_key, value) in CommonResourceUtils.load_all_instances(instance_type)]) - - # noinspection PyUnusedLocal - @staticmethod - def load_all_instance_types(instance_type: Types, return_type: Type[CommonExpectedReturnType] = Any) -> Dict[str, CommonExpectedReturnType]: - """load_all_instance_types(instance_type, return_type=Any) - - Load all instances of the specified type. - - :param instance_type: The type of instances being loaded. - :type instance_type: Types - :param return_type: The type of the returned value. (This is to make type hinting more accurate). It is not actually used in the function. Default is Any. - :type return_type: Type[CommonExpectedReturnType], optional - :return: A dictionary of resource keys to Instances of the specified type. - :rtype: Dict[str, Any] - """ - return CommonResourceUtils.get_instance_manager(instance_type).types - - # noinspection PyUnusedLocal - @staticmethod - def load_all_instance_values(instance_type: Types, return_type: Type[CommonExpectedReturnType] = Any) -> ValuesView[CommonExpectedReturnType]: - """load_all_instance_values(instance_type, return_type=Any) - - Load all instance values of the specified type. - - :param instance_type: The type of instances being loaded. - :type instance_type: Types - :param return_type: The type of the returned value. (This is to make type hinting more accurate). It is not actually used in the function. Default is Any. - :type return_type: Type[CommonExpectedReturnType], optional - :return: All instance values of the specified type. - :rtype: ValuesView[Any] - """ - return CommonResourceUtils.get_instance_manager(instance_type).types.values() - - @staticmethod - def get_instance_manager(instance_manager_type: Types) -> Union[InstanceManager, None]: - """get_instance_manager(instance_manager_type) - - Get an InstanceManager for the specified type. - - :param instance_manager_type: The type of InstanceManager to get. - :type instance_manager_type: Types - :return: An InstanceManager for the specified type, or None if no InstanceManager is found. - :rtype: Union[InstanceManager, None] - """ - return services.get_instance_manager(instance_manager_type) - - @staticmethod - def get_resource_key(resource_type: Types, resource_key: Union[int, str]) -> CommonResourceKey: - """get_resource_key(resource_type, resource_key) - - Retrieve the resource key of a resource in the format: 00000000(Type):00000000(Group):00000000000000000(Instance Guid) - - .. note:: - - Possible Usages: - - - Retrieve the identifier of an Icon to display next to an Interaction in the Pie Menu. - - Retrieve the identifier of an Image for display in Dialogs or Notifications. - - :Example Usage: - - .. highlight:: python - .. code-block:: python - - # This will retrieve the key for the image with identifier 1234 - icon_resource_key = CommonResourceUtils.get_resource_key(Types.PNG, 1234) - - :param resource_type: The type of resource being loaded. - :type resource_type: Types - :param resource_key: The decimal identifier or string resource key of the resource. - :type resource_key: Union[int, str] - :return: The resource key of an instance or None if no instance was found. - :rtype: CommonResourceKey - """ - from sims4.resources import get_resource_key, ResourceKeyWrapper - key = get_resource_key(resource_key, resource_type) - if isinstance(key, str) and ':' in key: - # noinspection PyBroadException - try: - key = CommonResourceKey.from_resource_key(ResourceKeyWrapper(key)) - return key - except: - return key - result = CommonResourceKey.from_resource_key(key) - return result - - @staticmethod - def load_instances_with_any_tags(resource_type: Types, tags: Tuple[str], return_type: Type[CommonExpectedReturnType] = Any) -> Tuple[CommonExpectedReturnType]: - """load_instances_with_any_tags(resource_type, tags, return_type=Any) - - Retrieve all resources that contain the specified tag names within their tuning file. - - .. note:: - - Possible Usages: - - - Load all Snippet files containing properties with any of the specified tags. - - :param resource_type: The type of resource being loaded. - :type resource_type: Types - :param tags: A collection of tag names to locate within a tuning file. - :type tags: Tuple[str] - :param return_type: The type of the returned value. (This is to make type hinting more accurate). It is not actually used in the function. Default is Any. - :type return_type: Type[CommonExpectedReturnType], optional - :return: A collection of resources that contain any of the specified tags. - :rtype: Tuple[Any] - """ - instances: List[CommonExpectedReturnType] = [] - for (_, instance_class) in CommonResourceUtils.load_all_instances(resource_type, return_type=return_type): - for tag in tags: - if not hasattr(instance_class, tag): - continue - instances.append(instance_class) - break - return tuple(instances) - - @staticmethod - def get_enum_by_name(name: str, enum_type: Type[CommonEnumTypeValueType], default_value: CommonEnumTypeValueType = None) -> CommonEnumTypeValueType: - """get_enum_by_name(name, enum_type, default_value=None) - - Retrieve an enum value by its name. - - :param name: The name of the enum value to retrieve. - :type name: str - :param enum_type: The type of enum to retrieve. - :type enum_type: Any - :param default_value: The default value to return if an enum value was not found using the specified name. Default is None. - :type default_value: Any, optional - :return: The enum value with a name matching the specified name. - :rtype: Any - """ - if hasattr(enum_type, name): - return getattr(enum_type, name) - # noinspection PyBroadException - try: - # noinspection PyTypeChecker - if name in enum_type: - return enum_type[name] - except: - pass - if hasattr(enum_type, 'name_to_value') and name in enum_type.name_to_value: - return enum_type.name_to_value.get(name) - return default_value - - @staticmethod - def get_enum_by_int_value(value: int, enum_type: Type[CommonEnumTypeValueType], default_value: CommonEnumTypeValueType = None) -> CommonEnumTypeValueType: - """get_enum_by_int_value(value, enum_type, default_value=None) - - Retrieve an enum value by its value. - - :param value: The integer value of the enum value to retrieve. - :type value: int - :param enum_type: The type of enum to retrieve. - :type enum_type: Any - :param default_value: The default value to return if an enum value was not found using the specified name. Default is None. - :type default_value: Any, optional - :return: The enum value with a value matching the specified value or the default value if not found. - :rtype: Any - """ - if hasattr(enum_type, 'value_to_name') and value in enum_type.value_to_name: - return CommonResourceUtils.get_enum_by_name(enum_type.value_to_name[value], enum_type, default_value=default_value) - return default_value - - @staticmethod - def convert_str_to_fnv32(text: str, seed: int = 2166136261, high_bit: bool = True) -> int: - """convert_str_to_fnv32(text, seed=2166136261, high_bit=True) - - Convert a text string into an FNV32 decimal identifier. - - :param text: The text to convert. - :type text: str - :param seed: A seed to use when converting. Default value is 2166136261. - :type seed: int - :param high_bit: If True, the high FNV bit will be returned. If False, a low FNV bit will be returned. - :type high_bit: bool - :return: The text converted to a FNV32 decimal identifier. - :rtype: int - """ - fnv_hash = CommonResourceUtils._str_to_fnv(text, seed, 16777619, 4294967296) - if high_bit: - fnv_hash |= 2147483648 - return fnv_hash - - @staticmethod - def convert_str_to_fnv64(text: str, seed: int = 14695981039346656037, high_bit: bool = True) -> int: - """convert_str_to_fnv64(text, seed=14695981039346656037, high_bit=True) - - Convert a text string into an FNV64 decimal identifier. - - :param text: The text to convert. - :type text: str - :param seed: A seed to use when converting. Default value is 14695981039346656037. - :type seed: int - :param high_bit: If True, a high bit version of the FNV bit will be returned. If False, a low bit version of the FNV bit will be returned. - :type high_bit: bool - :return: The text converted to an FNV64 decimal identifier. - :rtype: int - """ - fnv_hash = CommonResourceUtils._str_to_fnv(text, seed, 1099511628211, 18446744073709551616) - if high_bit: - fnv_hash |= 9223372036854775808 - return fnv_hash - - @staticmethod - def register_tuning(mod_identity: CommonModIdentity, class_type: Type, tuning_type: Types, tuning_id: int, tuning_contents: str): - """register_tuning(mod_identity, class_type, tuning_type, tuning_identifier, tuning_contents) - - Dynamically register a tuning instance. - - :param mod_identity: The identity of the mod registering the tuning. - :type mod_identity: CommonModIdentity - :param class_type: The type of class being registered. - :type class_type: Type - :param tuning_type: The type of tuning being registered. - :type tuning_type: Types - :param tuning_id: The decimal identifier of the tuning being registered. - :type tuning_id: int - :param tuning_contents: The xml contents of the tuning. - :type tuning_contents: str - """ - from sims4.resources import TYPE_RES_DICT - tuning_instance_key = CommonResourceUtils.get_resource_key(tuning_type, tuning_id) - # noinspection PyArgumentList - tuning_loader = ETreeTuningLoader(class_type, '[{}] Dynamic Instance: {}'.format(mod_identity.name.replace(' ', '_'), class_type), loading_tag=LoadingTags.Instance) - # noinspection PyUnresolvedReferences - tuning_loader.feed(BytesIO(tuning_contents.encode('utf-8'))) - if tuning_instance_key.type in TYPE_RES_DICT: - res_ext = TYPE_RES_DICT[tuning_instance_key.type] - mtg = get_manager() - # noinspection PyUnresolvedReferences - mtg._tuning_resources[res_ext][tuning_instance_key.instance] = tuning_loader.root - else: - # noinspection PyUnresolvedReferences - cls = tuning_loader.module - tuning_manage = CommonResourceUtils.get_instance_manager(tuning_type) - tuning_manage.register_tuned_class(cls, tuning_instance_key) - - @staticmethod - def _str_to_fnv(text: str, seed: int, prime: int, size: int) -> int: - string_bytes = text.lower().encode(encoding='utf-8') - hash_value = seed - for byte in string_bytes: - hash_value = hash_value * prime % size - hash_value = hash_value ^ byte - return hash_value - - @staticmethod - def load_resource_bytes(resource_key: CommonResourceKey, silent_fail: bool = True) -> BytesIO: - """load_resource_bytes(resource_key, silent_fail=True) - - Retrieve the bytes of a resource. - - :param resource_key: The key of the resource. - :type resource_key: CommonResourceKey - :param silent_fail: Set to True to ignore errors if they occur. Set to False to throw errors when they occur. Default is True. - :type silent_fail: bool, optional - :return: An Input Output Byte reader/writer for the resource. - :rtype: BytesIO - """ - return ResourceLoader(resource_key).load(silent_fail=silent_fail) - - @staticmethod - def load_resource_bytes_by_name(resource_type: Types, resource_name: str, has_fnv64_identifier: bool = True, has_high_bit_identifier: bool = False) -> Union[BytesIO, None]: - """load_resource_bytes_by_name(resource_type, resource_name, fnv64=True, high_bit=False) - - Load the bytes of a resource into a Bytes Reader. - - .. note:: This function will only work if the instance key/decimal identifier of the resource equates to the name of the resource. - - :param resource_type: The type of resource being loaded. - :type resource_type: Types - :param resource_name: The tuning name of the resource. - :type resource_name: str - :param has_fnv64_identifier: Set to True to indicate the resource uses a 64 bit identifier. Set to False to indicate the resource uses a 32 bit identifier. Default is True. - :type has_fnv64_identifier: bool, optional - :param has_high_bit_identifier: Set to True to indicate the resource uses a high bit identifier. Set to False to indicate the resource uses a low bit identifier. Default is False. - :type has_high_bit_identifier: bool, optional - :return: An Input Output Byte reader/writer for the resource or None if a problem occurs. - :rtype: Union[BytesIO, None] - """ - conversion_func = CommonResourceUtils.convert_str_to_fnv32 - if has_fnv64_identifier: - conversion_func = CommonResourceUtils.convert_str_to_fnv64 - resource_key = CommonResourceUtils.get_resource_key(resource_type, conversion_func(resource_name, high_bit=has_high_bit_identifier)) - if resource_key is None: - return None - return CommonResourceUtils.load_resource_bytes(resource_key) diff --git a/Scripts/s4ap/sims4communitylib/utils/common_time_utils.py b/Scripts/s4ap/sims4communitylib/utils/common_time_utils.py deleted file mode 100644 index 3703bf1..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/common_time_utils.py +++ /dev/null @@ -1,592 +0,0 @@ -""" -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 -""" - -import clock -import services -from clock import ClockSpeedMode, GameClock, ClockSpeedMultiplierType -from date_and_time import DateAndTime, TimeSpan -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ - CommonConsoleCommandArgument -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from time_service import TimeService - - -class CommonTimeUtils: - """Utilities for handling the in-game Time, also known as Sim Time. - - """ - @staticmethod - def pause_the_game() -> bool: - """pause_the_game() - - Pause the game. - - :return: True, if successful. False, if not. - :rtype: bool - """ - return CommonTimeUtils.set_clock_speed(ClockSpeedMode.PAUSED) - - @staticmethod - def game_is_paused() -> bool: - """game_is_paused() - - Determine if the game is paused. - - :return: True, if the game is paused. False, if not. - :rtype: bool - """ - return CommonTimeUtils.game_is_running_at_speed(ClockSpeedMode.PAUSED) - - @staticmethod - def game_is_running_at_speed(clock_speed: ClockSpeedMode) -> bool: - """game_is_running_at_speed(clock_speed) - - Determine if the game is running at the specified speed. - - :param clock_speed: The speed to change the game time to. - :type clock_speed: ClockSpeedMode - :return: True, if the game is running at the specified speed. False, if not. - :rtype: bool - """ - return CommonTimeUtils.get_clock_speed() == clock_speed - - @staticmethod - def set_game_speed_normal() -> bool: - """set_game_speed_normal() - - Change the speed of the game clock to Normal speed. - - :return: True, if successful. False, if not. - :rtype: bool - """ - return CommonTimeUtils.set_clock_speed(ClockSpeedMode.NORMAL) - - @staticmethod - def set_game_speed_to_speed_two() -> bool: - """set_game_speed_to_speed_two() - - Change the speed of the game clock to Speed Two. - - :return: True, if successful. False, if not. - :rtype: bool - """ - return CommonTimeUtils.set_clock_speed(ClockSpeedMode.SPEED2) - - @staticmethod - def set_game_speed_to_speed_three() -> bool: - """set_game_speed_to_speed_three() - - Change the speed of the game clock to Speed Three. - - :return: True, if successful. False, if not. - :rtype: bool - """ - return CommonTimeUtils.set_clock_speed(ClockSpeedMode.SPEED3) - - @staticmethod - def set_game_speed_to_interaction_startup_speed() -> bool: - """set_game_speed_to_interaction_startup_speed() - - Change the speed of the game clock to Interaction Startup Speed. - - :return: True, if successful. False, if not. - :rtype: bool - """ - return CommonTimeUtils.set_clock_speed(ClockSpeedMode.INTERACTION_STARTUP_SPEED) - - @staticmethod - def set_game_speed_to_super_speed_three() -> bool: - """set_game_speed_to_super_speed_three() - - Change the speed of the game clock to Super Speed Three. - - :return: True, if successful. False, if not. - :rtype: bool - """ - return CommonTimeUtils.set_clock_speed(ClockSpeedMode.SUPER_SPEED3) - - @staticmethod - def get_clock_speed() -> ClockSpeedMode: - """get_clock_speed() - - Retrieve the current clock speed. - - :return: The current speed of the game clock. - :rtype: ClockSpeedMode - """ - return CommonTimeUtils.get_game_clock().clock_speed - - @staticmethod - def get_clock_speed_scale() -> ClockSpeedMultiplierType: - """get_clock_speed_scale() - - Retrieve the current clock speed multiplier. - - :return: The current speed multiplier of the game clock. - :rtype: ClockSpeedMultiplierType - """ - return CommonTimeUtils.get_game_clock().current_clock_speed_scale() - - @staticmethod - def set_clock_speed(clock_speed: ClockSpeedMode) -> bool: - """set_clock_speed(clock_speed) - - Set the clock speed. - - :param clock_speed: The speed to set the game clock to. - :type clock_speed: ClockSpeedMode - :return: True, if successful. False, if not. - :rtype: bool - """ - return CommonTimeUtils.get_game_clock().set_clock_speed(clock_speed) - - @staticmethod - def set_current_time(hours: int, minutes: int, seconds: int): - """set_current_time(hours, minutes, seconds) - - Set the current time. - - :param hours: The hour of the day to set the time to. - :type hours: int - :param minutes: The minute of the hour to set the time to. - :type minutes: int - :param seconds: The second of the minute to set the time to. - :type seconds: int - """ - CommonTimeUtils.get_game_clock().set_game_time(hours, minutes, seconds) - - @staticmethod - def advance_current_time(hours: int = 0, minutes: int = 0, seconds: int = 0): - """advance_current_time(hours=0, minutes=0, seconds=0) - - Advance the current time by the specified amounts. - - :param hours: The number of hours to advance. - :type hours: int, optional - :param minutes: The number of minutes to advance. - :type minutes: int, optional - :param seconds: The number of seconds to advance. - :type seconds: int, optional - """ - CommonTimeUtils.get_game_clock().advance_game_time(hours=hours, minutes=minutes, seconds=seconds) - - @staticmethod - def get_current_date_and_time() -> DateAndTime: - """get_current_date_and_time() - - Retrieve the current date and time. - - :return: The current date and time. - :rtype: DateAndTime - """ - return services.time_service().sim_now - - @staticmethod - def get_current_second(date_and_time: DateAndTime = None) -> int: - """get_current_second(date_and_time) - - Retrieve the current Sim second of the minute. - - :param date_and_time: The date and time to retrieve the value from. If not specified, the current date and time will be used. Default is None. - :type date_and_time: DateAndTime, optional - :return: The current Sim second of the minute. - :rtype: int - """ - if date_and_time is None: - date_and_time = CommonTimeUtils.get_current_date_and_time() - return int(date_and_time.second()) - - @staticmethod - def get_current_minute(date_and_time: DateAndTime = None) -> int: - """get_current_minute(date_and_time) - - Retrieve the current Sim minute of the hour. - - :param date_and_time: The date and time to retrieve the value from. If not specified, the current date and time will be used. Default is None. - :type date_and_time: DateAndTime, optional - :return: The current Sim minute of the hour. - :rtype: int - """ - if date_and_time is None: - date_and_time = CommonTimeUtils.get_current_date_and_time() - return int(date_and_time.minute()) - - @staticmethod - def get_current_hour(date_and_time: DateAndTime = None) -> int: - """get_current_hour(date_and_time) - - Retrieve the current Sim hour of the day in military time. - - :param date_and_time: The date and time to retrieve the value from. If not specified, the current date and time will be used. Default is None. - :type date_and_time: DateAndTime, optional - :return: The current Sim hour of the day in military time. - :rtype: int - """ - if date_and_time is None: - date_and_time = CommonTimeUtils.get_current_date_and_time() - return int(date_and_time.hour()) - - @staticmethod - def get_current_day(date_and_time: DateAndTime = None) -> int: - """get_current_day(date_and_time) - - Retrieve the current Sim day of the month. - - :param date_and_time: The date and time to retrieve the value from. If not specified, the current date and time will be used. Default is None. - :type date_and_time: DateAndTime, optional - :return: The current Sim day of the month. - :rtype: int - """ - if date_and_time is None: - date_and_time = CommonTimeUtils.get_current_date_and_time() - return int(date_and_time.day()) - - @staticmethod - def get_current_week(date_and_time: DateAndTime = None) -> int: - """get_current_week(date_and_time) - - Retrieve the current Sim week of the month. - - :param date_and_time: The date and time to retrieve the value from. If not specified, the current date and time will be used. Default is None. - :type date_and_time: DateAndTime, optional - :return: The current Sim week of the month. - :rtype: int - """ - if date_and_time is None: - date_and_time = CommonTimeUtils.get_current_date_and_time() - return int(date_and_time.week()) - - @staticmethod - def get_total_ticks(date_and_time: DateAndTime = None) -> int: - """get_total_ticks(date_and_time) - - Retrieve the total Sim ticks since the start of the day. - - :param date_and_time: The date and time to retrieve the value from. If not specified, the current date and time will be used. Default is None. - :type date_and_time: DateAndTime, optional - :return: The total number of Sim ticks in milliseconds since the start of the day. - :rtype: int - """ - if date_and_time is None: - date_and_time = CommonTimeUtils.get_current_date_and_time() - return int(date_and_time.absolute_ticks()) - - @staticmethod - def get_total_seconds(date_and_time: DateAndTime = None) -> float: - """get_total_seconds(date_and_time) - - Retrieve the total Sim seconds since the start of the day. - - :param date_and_time: The date and time to retrieve the value from. If not specified, the current date and time will be used. Default is None. - :type date_and_time: DateAndTime, optional - :return: The total number of Sim seconds since the start of the day. - :rtype: int - """ - if date_and_time is None: - date_and_time = CommonTimeUtils.get_current_date_and_time() - return int(date_and_time.absolute_seconds()) - - @staticmethod - def get_total_minutes(date_and_time: DateAndTime = None) -> float: - """get_total_minutes(date_and_time) - - Retrieve the total Sim minutes since the start of the day. - - :param date_and_time: The date and time to retrieve the value from. If not specified, the current date and time will be used. Default is None. - :type date_and_time: DateAndTime, optional - :return: The total number of Sim minutes since the start of the day. - :rtype: int - """ - if date_and_time is None: - date_and_time = CommonTimeUtils.get_current_date_and_time() - return int(date_and_time.absolute_minutes()) - - @staticmethod - def get_total_hours(date_and_time: DateAndTime = None) -> float: - """get_total_hours(date_and_time) - - Retrieve the total Sim hours since the start of the day in military time. - - :param date_and_time: The date and time to retrieve the value from. If not specified, the current date and time will be used. Default is None. - :type date_and_time: DateAndTime, optional - :return: The total number of Sim hours since the start of the day in military time. - :rtype: int - """ - if date_and_time is None: - date_and_time = CommonTimeUtils.get_current_date_and_time() - return int(date_and_time.absolute_hours()) - - @staticmethod - def get_total_days(date_and_time: DateAndTime = None) -> float: - """get_total_days(date_and_time) - - Retrieve the total Sim days since the start of the season. - - :param date_and_time: The date and time to retrieve the value from. If not specified, the current date and time will be used. Default is None. - :type date_and_time: DateAndTime, optional - :return: The total number of Sim days since the start of the season. - :rtype: int - """ - if date_and_time is None: - date_and_time = CommonTimeUtils.get_current_date_and_time() - return int(date_and_time.absolute_days()) - - @staticmethod - def get_total_weeks(date_and_time: DateAndTime = None) -> float: - """get_total_weeks(date_and_time) - - Retrieve the total Sim weeks since the start of the season. - - :param date_and_time: The date and time to retrieve the value from. If not specified, the current date and time will be used. Default is None. - :type date_and_time: DateAndTime, optional - :return: The total number of Sim weeks since the start of the season. - :rtype: int - """ - if date_and_time is None: - date_and_time = CommonTimeUtils.get_current_date_and_time() - return int(date_and_time.absolute_weeks()) - - @staticmethod - def get_day_of_week(date_and_time: DateAndTime = None) -> int: - """get_day_of_week(date_and_time) - - Retrieve the current day of the week. - - :param date_and_time: The date and time to retrieve the value from. If not specified, the current date and time will be used. Default is None. - :type date_and_time: DateAndTime, optional - :return: The current day of the week. 0-6 - :rtype: int - """ - if date_and_time is None: - date_and_time = CommonTimeUtils.get_current_date_and_time() - return int(date_and_time.day()) - - @staticmethod - def create_interval_from_sim_seconds(seconds: int) -> TimeSpan: - """create_interval_from_sim_seconds(seconds) - - Create a time span interval that spans from the current Sim time to a number of Sim seconds in the future. - - :param seconds: A number of Sim seconds in the future the time span will indicate. - :type seconds: int - :return: A time span that will occur a number of Sim seconds in the future. - :rtype: TimeSpan - """ - return clock.interval_in_sim_seconds(seconds) - - @staticmethod - def create_interval_from_sim_minutes(minutes: int) -> TimeSpan: - """create_interval_from_sim_minutes(minutes) - - Create a time span interval that spans from the current Sim time to a number of Sim minutes in the future. - - :param minutes: A number of Sim minutes in the future the time span will indicate. - :type minutes: int - :return: A time span that will occur a number of Sim minutes in the future. - :rtype: TimeSpan - """ - return clock.interval_in_sim_minutes(minutes) - - @staticmethod - def create_interval_from_sim_hours(hours: int) -> TimeSpan: - """create_interval_from_sim_hours(hours) - - Create a time span interval that spans from the current Sim time to a number of Sim hours in the future. - - :param hours: A number of Sim hours in the future the time span will indicate. - :type hours: int - :return: A time span that will occur a number of Sim hours in the future. - :rtype: TimeSpan - """ - return clock.interval_in_sim_hours(hours) - - @staticmethod - def interval_in_sim_days(days: int) -> TimeSpan: - """interval_in_sim_days(days) - - Create a time span interval that spans from the current Sim time to a number of Sim days in the future. - - :param days: A number of Sim days in the future the time span will indicate. - :type days: int - :return: A time span that will occur a number of Sim days in the future. - :rtype: TimeSpan - """ - return clock.interval_in_sim_days(days) - - @staticmethod - def interval_in_sim_weeks(weeks: int) -> TimeSpan: - """interval_in_sim_weeks(weeks) - - Create a time span interval that spans from the current Sim time to a number of Sim weeks in the future. - - :param weeks: A number of Sim weeks in the future the time span will indicate. - :type weeks: int - :return: A time span that will occur a number of Sim weeks in the future. - :rtype: TimeSpan - """ - return clock.interval_in_sim_weeks(weeks) - - @staticmethod - def create_time_span(minutes: int = 0, hours: int = 0, days: int = 0) -> TimeSpan: - """create_time_span(minutes=0, hours=0, days=0) - - Create a time span that spans from the current Sim time to a number of Sim minutes, hours, or days in the future. - - :param minutes: A number of Sim minutes in the future the time span will indicate. Default is 0 Sim minutes. - :type minutes: int, optional - :param hours: A number of Sim hours in the future the time span will indicate. Default is 0 Sim hours. - :type hours: int, optional - :param days: A number of Sim days in the future the time span will indicate. Default is 0 Sim days. - :type days: int, optional - :return: A time span that will occur a number of Sim minutes, hours, or days in the future. - :rtype: TimeSpan - """ - from date_and_time import create_time_span - return create_time_span(days=days, hours=hours, minutes=minutes) - - @staticmethod - def create_date_and_time(minutes: int = 0, hours: int = 0, days: int = 0) -> DateAndTime: - """create_date_and_time(minutes=0, hours=0, days=0) - - Create a date and time that takes place a number of Sim minutes, hours, or days in the future. - - :param minutes: A number of Sim minutes in the future the date and time will be set at. Default is 0 Sim minutes. - :type minutes: int, optional - :param hours: A number of Sim hours in the future the date and time will be set at. Default is 0 Sim hours. - :type hours: int, optional - :param days: A number of Sim days in the future the date and time will be set at. Default is 0 Sim days. - :type days: int, optional - :return: A date and time that will occur a number of Sim minutes, hours, or days in the future. - :rtype: DateAndTime - """ - from date_and_time import create_date_and_time - return create_date_and_time(days=days, hours=hours, minutes=minutes) - - @staticmethod - def convert_milliseconds_to_seconds(milliseconds: float) -> float: - """convert_milliseconds_to_seconds(milliseconds) - - Convert Milliseconds to Seconds. - - :param milliseconds: The value to convert. - :type milliseconds: float - :return: The converted value in seconds. - :rtype: float - """ - from date_and_time import MILLISECONDS_PER_SECOND - if MILLISECONDS_PER_SECOND <= 0: - return milliseconds/1000 - return milliseconds/MILLISECONDS_PER_SECOND - - @staticmethod - def convert_seconds_to_milliseconds(seconds: float) -> float: - """convert_seconds_to_milliseconds(milliseconds) - - Convert Seconds to Milliseconds. - - :param seconds: The value to convert. - :type seconds: float - :return: The converted value in milliseconds. - :rtype: float - """ - from date_and_time import MILLISECONDS_PER_SECOND - if MILLISECONDS_PER_SECOND <= 0: - return seconds * 1000 - return seconds * MILLISECONDS_PER_SECOND - - @staticmethod - def is_sun_out() -> bool: - """is_sun_out() - - Determine if the Sun is currently out. - - :return: True, if the sun is out. False, if not. - :rtype: bool - """ - return CommonTimeUtils.get_time_service().is_sun_out() - - @staticmethod - def is_day_time(date_and_time: DateAndTime = None) -> bool: - """is_day_time(date_and_time=None) - - Determine if it is currently Day Time. - - :param date_and_time: A date and time to check. If not specified, the current time will be used instead. Default is unspecified. - :type date_and_time: DateAndTime, optional - :return: True, if it is day time. False, if not. - :rtype: bool - """ - return CommonTimeUtils.get_time_service().is_day_time(time=date_and_time) - - @staticmethod - def is_night_time(date_and_time: DateAndTime = None) -> bool: - """is_night_time(date_and_time=None) - - Determine if it is currently Night Time. - - :param date_and_time: A date and time to check. If not specified, the current time will be used instead. Default is unspecified. - :type date_and_time: DateAndTime, optional - :return: True, if it is night time. False, if not. - :rtype: bool - """ - return not CommonTimeUtils.is_day_time(date_and_time=date_and_time) - - @staticmethod - def get_time_service() -> TimeService: - """get_time_service() - - Get an instance of the TimeService. - - :return: An instance of the Time Service. - :rtype: TimeService - """ - return services.time_service() - - @staticmethod - def get_game_clock() -> GameClock: - """get_game_clock() - - Get an instance of the GameClock. - - :return: An instance of the game clock. - :rtype: GameClock - """ - return services.game_clock_service() - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.pause_game', - 'Pause the game.' -) -def _s4clib_pause_game(output: CommonConsoleCommandOutput): - output('Attempting to pause the game.') - CommonTimeUtils.pause_the_game() - output('Game paused successfully.') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.advance_time', - 'Advance the time in-game.', - command_arguments=( - CommonConsoleCommandArgument('seconds', 'Positive Number', 'The number of seconds to advance time by. Default is 0.', is_optional=True, default_value=0), - CommonConsoleCommandArgument('minutes', 'Positive Number', 'The number of minutes to advance time by. Default is 0.', is_optional=True, default_value=0), - CommonConsoleCommandArgument('hours', 'Positive Number', 'The number of hours to advance time by. Default is 0.', is_optional=True, default_value=0), - ) -) -def _s4clib_advance_time( - output: CommonConsoleCommandOutput, - seconds: int = 0, - minutes: int = 0, - hours: int = 0 -): - output(f'Attempting to advance time by {hours}h {minutes}m {seconds}s') - CommonTimeUtils.advance_current_time(hours=hours, minutes=minutes, seconds=seconds) - output('Finished advancing time.') diff --git a/Scripts/s4ap/sims4communitylib/utils/common_type_utils.py b/Scripts/s4ap/sims4communitylib/utils/common_type_utils.py deleted file mode 100644 index cb1fc17..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/common_type_utils.py +++ /dev/null @@ -1,271 +0,0 @@ -""" -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 -""" -from typing import Any -from sims.sim import Sim -from sims.sim_info import SimInfo -from sims.sim_info_base_wrapper import SimInfoBaseWrapper -from sims4.math import Location -from objects.game_object import GameObject -from objects.script_object import ScriptObject - - -class CommonTypeUtils: - """Utilities for determining the type of an object. - - """ - @staticmethod - def is_sim_or_sim_info(obj: Any) -> bool: - """is_sim_or_sim_info(obj) - - Determine if an object is either of type Sim or type SimInfo - - :param obj: The object to check. - :type obj: Any - :return: True, if it is. False, if it is not. - :rtype: bool - """ - return CommonTypeUtils.is_sim_instance(obj) or CommonTypeUtils.is_sim_info(obj) - - @staticmethod - def is_sim_instance(obj: Any) -> bool: - """is_sim_instance(obj) - - Determine if an object is of type Sim - - :param obj: The object to check. - :type obj: Any - :return: True, if it is. False, if it is not. - :rtype: bool - """ - return isinstance(obj, Sim) - - @staticmethod - def is_sim_info(obj: Any) -> bool: - """is_sim_info(obj) - - Determine if an object is of type SimInfo - - :param obj: The object to check. - :type obj: Any - :return: True, if it is. False, if it is not. - :rtype: bool - """ - return isinstance(obj, SimInfo) - - @staticmethod - def is_sim_info_base_wrapper(obj: Any) -> bool: - """is_sim_info_base_wrapper(obj) - - Determine if an object is of type SimInfo - - :param obj: The object to check. - :type obj: Any - :return: True, if it is. False, if it is not. - :rtype: bool - """ - return isinstance(obj, SimInfoBaseWrapper) - - @staticmethod - def is_script_object(obj: Any) -> bool: - """is_script_object(obj) - - Determine if an object is of type ScriptObject - - .. note:: GameObjects, Terrain, and Sims are all ScriptObjects. Try also :func:`~is_game_object`, :func:`~is_terrain`, and :func:`~is_sim_instance` - - :param obj: The object to check. - :type obj: Any - :return: True, if it is. False, if it is not. - :rtype: bool - """ - return isinstance(obj, ScriptObject) - - @staticmethod - def is_game_object(obj: Any) -> bool: - """is_game_object(obj) - - Determine if an object is of type GameObject - - :param obj: The object to check. - :type obj: Any - :return: True, if it is. False, if it is not. - :rtype: bool - """ - return isinstance(obj, GameObject) - - @staticmethod - def is_terrain(obj: Any) -> bool: - """is_terrain(obj) - - Determine if an object is of type Terrain - - :param obj: The object to check. - :type obj: Any - :return: True, if it is. False, if it is not. - :rtype: bool - """ - from objects.terrain import Terrain - return isinstance(obj, Terrain) - - @staticmethod - def is_land(obj: Any) -> bool: - """is_land(obj) - - Determine if an object is of type Terrain or TerrainPoint. - - :param obj: The object to check. - :type obj: Any - :return: True, if it is. False, if it is not. - :rtype: bool - """ - return CommonTypeUtils.is_terrain(obj) or CommonTypeUtils.is_terrain_point(obj) - - @staticmethod - def is_water(obj: Any) -> bool: - """is_water(obj) - - Determine if an object is of type Ocean, OceanPoint, SwimmingPool, or PoolPoint. - - :param obj: The object to check. - :type obj: Any - :return: True, if it is. False, if it is not. - :rtype: bool - """ - return CommonTypeUtils.is_ocean(obj) or CommonTypeUtils.is_ocean_point(obj) or CommonTypeUtils.is_swimming_pool(obj) or CommonTypeUtils.is_pool_point(obj) - - @staticmethod - def is_ocean(obj: Any) -> bool: - """is_ocean(obj) - - Determine if an object is of type Ocean. - - :param obj: The object to check. - :type obj: Any - :return: True, if it is. False, if it is not. - :rtype: bool - """ - try: - from objects.pools.ocean import Ocean - except ModuleNotFoundError: - return False - return isinstance(obj, Ocean) - - @staticmethod - def is_swimming_pool(obj: Any) -> bool: - """is_swimming_pool(obj) - - Determine if an object is of type SwimmingPool. - - :param obj: The object to check. - :type obj: Any - :return: True, if it is. False, if it is not. - :rtype: bool - """ - from s4ap.sims4communitylib.utils.objects.common_object_type_utils import CommonObjectTypeUtils - return CommonObjectTypeUtils.is_swimming_pool(obj) - - @staticmethod - def is_door(obj: Any) -> bool: - """is_door(obj) - - Determine if an Object is of type Door - - :param obj: The object to check. - :type obj: Any - :return: True, if it is. False, if it is not. - :rtype: bool - """ - from s4ap.sims4communitylib.utils.objects.common_object_type_utils import CommonObjectTypeUtils - return CommonObjectTypeUtils.is_door(obj) - - @staticmethod - def is_location(obj: Any) -> bool: - """is_location(obj) - - Determine if an object is of type Location. - - :param obj: The object to check. - :type obj: Any - :return: True, if it is. False, if it is not. - :rtype: bool - """ - from s4ap.sims4communitylib.classes.math.common_location import CommonLocation - return isinstance(obj, Location) or isinstance(obj, CommonLocation) - - @staticmethod - def is_location_point(obj: Any) -> bool: - """is_location_point(obj) - - Determine if an object is of type _LocationPoint. - - :param obj: The object to check. - :type obj: Any - :return: True, if it is. False, if it is not. - :rtype: bool - """ - from objects.terrain import _LocationPoint - return isinstance(obj, _LocationPoint) - - @staticmethod - def is_terrain_point(obj: Any) -> bool: - """is_terrain_point(obj) - - Determine if an object is of type TerrainPoint. - - :param obj: The object to check. - :type obj: Any - :return: True, if it is. False, if it is not. - :rtype: bool - """ - from objects.terrain import TerrainPoint - return isinstance(obj, TerrainPoint) - - @staticmethod - def is_ocean_point(obj: Any) -> bool: - """is_ocean_point(obj) - - Determine if an object is of type OceanPoint. - - :param obj: The object to check. - :type obj: Any - :return: True, if it is. False, if it is not. - :rtype: bool - """ - try: - from objects.terrain import OceanPoint - except ModuleNotFoundError: - return False - return isinstance(obj, OceanPoint) - - @staticmethod - def is_pool_point(obj: Any) -> bool: - """is_pool_point(obj) - - Determine if an object is of type PoolPoint. - - :param obj: The object to check. - :type obj: Any - :return: True, if it is. False, if it is not. - :rtype: bool - """ - from objects.terrain import PoolPoint - return isinstance(obj, PoolPoint) - - @staticmethod - def is_pool_seat(obj: Any) -> bool: - """is_pool_seat(obj) - - Determine if an Object is a Pool Seat. - - :param obj: An instance of an Object. - :type: Any - :return: True, if the Object is a Pool Seat. False, if not. - :rtype: bool - """ - from s4ap.sims4communitylib.utils.objects.common_object_type_utils import CommonObjectTypeUtils - return CommonObjectTypeUtils.is_swimming_pool_seat(obj) diff --git a/Scripts/s4ap/sims4communitylib/utils/common_weather_utils.py b/Scripts/s4ap/sims4communitylib/utils/common_weather_utils.py deleted file mode 100644 index 71758e1..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/common_weather_utils.py +++ /dev/null @@ -1,308 +0,0 @@ -""" -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 -""" -from typing import Iterator, Union - -from objects.game_object import GameObject -from server_commands.argument_helpers import TunableInstanceParam -from sims.sim_info import SimInfo -from sims4.resources import Types -from s4ap.sims4communitylib.enums.common_cloud_type import CommonCloudType -from s4ap.sims4communitylib.enums.common_temperature import CommonTemperature -from s4ap.sims4communitylib.enums.common_weather_effect_type import CommonWeatherEffectType -from s4ap.sims4communitylib.enums.common_weather_event_ids import CommonWeatherEventId -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ - CommonConsoleCommandArgument -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.common_time_utils import CommonTimeUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from weather.weather_enums import PrecipitationType, WeatherEffectType -from weather.weather_event import WeatherEvent -from weather.weather_service import WeatherService - - -class CommonWeatherUtils: - """Utilities for manipulating the weather. - - """ - - @classmethod - def weather_effect_is_active(cls, weather_effect_type: CommonWeatherEffectType) -> bool: - """weather_effect_is_active(weather_effect_type) - - Determine if the specified weather effect is currently active. - - :param weather_effect_type: The weather effect to check for. - :type weather_effect_type: CommonWeatherEffectType - :return: True, if the weather is active. False, if it is not. - :rtype: bool - """ - return cls.weather_effects_are_active((weather_effect_type,)) - - @classmethod - def weather_effects_are_active(cls, weather_effect_types: Iterator[CommonWeatherEffectType]) -> bool: - """weather_effects_are_active(weather_effect_types) - - Determine if any of the specified weather effects are currently active. - - :param weather_effect_types: An iterator of weather effects to check for. - :type weather_effect_types: Iterator[CommonWeatherEffectType] - :return: True, if any of the weathers is active. False, if none of the weathers are active. - :rtype: bool - """ - weather_service: WeatherService = cls.get_weather_service() - if weather_service is None: - return False - for weather_effect_type in weather_effect_types: - if not bool(weather_service.get_weather_element_value(weather_effect_type, default=0.0)): - continue - return True - return False - - @classmethod - def current_temperature_is_cold_or_freezing(cls) -> bool: - """current_temperature_is_cold_or_freezing() - - Determine if the current temperature is cold or freezing. - - :return: True, if the current temperature contains cold or freezing. False, if not. - :rtype: bool - """ - current_temperature = cls.get_current_temperature() - return current_temperature == CommonTemperature.COLD or current_temperature == CommonTemperature.FREEZING - - @classmethod - def current_weather_contains_thunder_or_lightning(cls) -> bool: - """current_weather_contains_thunder_or_lightning() - - Determine if the current weather contains lightning or thunder. - - :return: True, if the current weather contains thunder or lightning. False, if not. - :rtype: bool - """ - return cls.weather_effects_are_active((CommonWeatherEffectType.LIGHTNING, CommonWeatherEffectType.THUNDER)) - - @classmethod - def get_current_temperature(cls) -> CommonTemperature: - """get_current_temperature() - - Retrieve the current temperature. - - :return: The current temperature. - :rtype: CommonTemperature - """ - weather_service = cls.get_weather_service() - if weather_service is not None: - return CommonTemperature.convert_from_vanilla(weather_service.get_weather_element_value(CommonWeatherEffectType.TEMPERATURE, default=CommonTemperature.WARM)) - return CommonTemperature.WARM - - @classmethod - def get_current_wind_speed(cls) -> int: - """get_current_wind_speed() - - Retrieve the current wind speed. - - :return: The current speed of the wind. - :rtype: int - """ - weather_service = cls.get_weather_service() - if weather_service is None: - return 0 - return weather_service.get_weather_element_value(WeatherEffectType.WIND, time=CommonTimeUtils.get_current_date_and_time()) - - @classmethod - def get_current_precipitation_level(cls, precipitation_type: PrecipitationType) -> int: - """get_current_precipitation_level(precipitation_type) - - Retrieve the current precipitation level. - - :param precipitation_type: The type of precipitation to get. - :type precipitation_type: PrecipitationType - :return: The current precipitation level. - :rtype: int - """ - weather_service = cls.get_weather_service() - if weather_service is None: - return 0 - return weather_service.get_weather_element_value(precipitation_type, time=CommonTimeUtils.get_current_date_and_time()) - - @classmethod - def get_current_lightning_level(cls) -> int: - """get_current_lightning_level() - - Retrieve the current lightning level. - - :return: The current lightning level. - :rtype: int - """ - weather_service = cls.get_weather_service() - if weather_service is None: - return 0 - return weather_service.get_weather_element_value(WeatherEffectType.LIGHTNING, time=CommonTimeUtils.get_current_date_and_time()) - - @classmethod - def get_weather_cloud_type(cls) -> CommonCloudType: - """get_weather_cloud_type() - - Retrieve the current cloud type. - - :return: The current cloud type or CLEAR if weather is not available. - :rtype: CommonCloudType - """ - weather_service = cls.get_weather_service() - if weather_service is None: - return CommonCloudType.CLEAR - for cloud_type in CommonCloudType.get_all(): - vanilla_cloud_type = CommonCloudType.convert_to_vanilla(cloud_type) - if not weather_service.get_weather_element_value(vanilla_cloud_type, default=0.0): - continue - return cloud_type - return CommonCloudType.CLEAR - - @classmethod - def start_weather_event(cls, weather_event: Union[int, CommonWeatherEventId, WeatherEvent], duration_in_hours: int) -> None: - """start_weather_event(weather_event, duration_in_hours) - - Start a weather event. Essentially changing the current weather. - - :param weather_event: The identifier of the weather event to start. - :type weather_event: Union[int, CommonWeatherEventId, WeatherEvent] - :param duration_in_hours: The number of Sim hours to run the weather event for. - :type duration_in_hours: int - """ - weather_service = cls.get_weather_service() - if weather_service is None: - return - weather_event = cls.load_weather_event_by_id(weather_event) - weather_service.start_weather_event(weather_event, duration_in_hours) - - @classmethod - def get_weather_service(cls) -> Union[WeatherService, None]: - """get_weather_service() - - Retrieve the service that handles the weather. - - :return: An instance of the service for handling weather or None if there is no weather service. - :rtype: Union[WeatherService, None] - """ - import services - if not hasattr(services, 'weather_service'): - return None - return services.weather_service() - - @classmethod - def load_weather_event_by_id(cls, weather_event: Union[int, CommonWeatherEventId, WeatherEvent]) -> Union[WeatherEvent, None]: - """load_weather_event_by_id(weather_event) - - Load an instance of a Weather Event by its identifier. - - :param weather_event: The identifier of a Weather Event. - :type weather_event: Union[int, CommonWeatherEventId, WeatherEvent] - :return: An instance of a WeatherEvent matching the decimal identifier or None if not found. - :rtype: Union[WeatherEvent, None] - """ - if isinstance(weather_event, WeatherEvent): - return weather_event - # noinspection PyBroadException - try: - weather_event: int = int(weather_event) - except: - # noinspection PyTypeChecker - weather_event: WeatherEvent = weather_event - return weather_event - - from sims4.resources import Types - from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils - return CommonResourceUtils.load_instance(Types.WEATHER_EVENT, weather_event) - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.clear_weather', - 'Change the weather to clear, with sunny skies!', - command_arguments=( - CommonConsoleCommandArgument('duration_in_hours', 'Number', 'The number of Sim hours the weather should last.', is_optional=True, default_value='6 Hours'), - ) -) -def _common_set_weather(output: CommonConsoleCommandOutput, duration_in_hours: int=6): - output(f'Changing the weather to clear') - CommonWeatherUtils.start_weather_event(CommonWeatherEventId.CLEAR, duration_in_hours) - return True - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.change_weather', - 'Set the weather', - command_arguments=( - CommonConsoleCommandArgument('weather', 'Weather Id or Tuning Name', 'The decimal identifier or Tuning Name of the Weather to add.'), - CommonConsoleCommandArgument('duration_in_hours', 'Number', 'The number of Sim hours the weather should last.', is_optional=True, default_value='6 Hours'), - ) -) -def _common_set_weather(output: CommonConsoleCommandOutput, weather: TunableInstanceParam(Types.WEATHER_EVENT), duration_in_hours: int=6): - if not weather or isinstance(weather, int) or isinstance(weather, float) or isinstance(weather, str): - output(f'Weather \'{weather}\' was not found.') - return False - output(f'Changing the weather to {weather}') - CommonWeatherUtils.start_weather_event(weather, duration_in_hours) - return True - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.smite_sim', - 'A Sim will be struck by the power of Zeus.', - command_aliases=( - 's4clib.smite_me', - ), - command_arguments=( - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance id or name of a Sim to smite.', is_optional=True, default_value='Active Sim'), - ) -) -def _common_smite_sim(output: CommonConsoleCommandOutput, sim_info: SimInfo=None): - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - output(f'Sim was not found nearby. {sim_info}') - return - output(f'Smiting Sim {sim_info} with the power of Zeus.') - from weather.lightning import LightningStrike - LightningStrike.strike_sim(sim_to_strike=sim) - return True - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.smite_object', - 'An object will be struck by the power of Zeus.', - command_aliases=( - 's4clib.smite_it', - ), - command_arguments=( - CommonConsoleCommandArgument('game_object', 'Object Id or Name', 'The instance id or name of an Object to smite.'), - ) -) -def _common_smite_object(output: CommonConsoleCommandOutput, game_object: GameObject): - output(f'Smiting Object {game_object} with the power of Zeus.') - from weather.lightning import LightningStrike - LightningStrike.strike_object(obj_to_strike=game_object) - return True - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.angry_zeus', - 'Zeus be Angry.' -) -def _common_smite_object(output: CommonConsoleCommandOutput, zeus_fury_count: int=100): - output(f'Zeus be angry, I hope your Sims are indoors!') - from weather.lightning import LightningStrike - count = 0 - while count <= zeus_fury_count: - LightningStrike.perform_active_lightning_strike() - count += 1 - return True diff --git a/Scripts/s4ap/sims4communitylib/utils/effects/__init__.py b/Scripts/s4ap/sims4communitylib/utils/effects/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/effects/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/utils/effects/common_visual_effect_commands.py b/Scripts/s4ap/sims4communitylib/utils/effects/common_visual_effect_commands.py deleted file mode 100644 index 53824ce..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/effects/common_visual_effect_commands.py +++ /dev/null @@ -1,192 +0,0 @@ -""" -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 -""" -from typing import Dict, List - -import clock -from date_and_time import TimeSpan -from objects.game_object import GameObject -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from s4ap.sims4communitylib.events.zone_spin.events.zone_teardown import S4CLZoneTeardownEvent -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommandArgument, \ - CommonConsoleCommand -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.services.common_service import CommonService -from s4ap.sims4communitylib.classes.effects.common_visual_effect import CommonVisualEffect -from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils -from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - - -class _CommonVisualEffectCommandService(CommonService): - def __init__(self) -> None: - super().__init__() - self._running_effects_list: Dict[int, List[CommonVisualEffect]] = dict() - - # noinspection PyMissingOrEmptyDocstring - def play_visual_effect( - self, - target: GameObject, - effect_name: str, - joint_bone_name: str = 'b__Head__', - time_span: TimeSpan = None, - target_joint_bone_name: str = None, - **kwargs - ): - effect = CommonVisualEffect( - ModInfo.get_identity(), - target, - effect_name, - joint_bone_name=joint_bone_name, - target_joint_bone_name=target_joint_bone_name, - **kwargs - ) - - if CommonTypeUtils.is_sim_or_sim_info(target): - # noinspection PyTypeChecker - object_id = CommonSimUtils.get_sim_id(target) - else: - object_id = CommonObjectUtils.get_object_id(target) - - def _on_end(_effect: CommonVisualEffect): - if object_id in self._running_effects_list and _effect in self._running_effects_list[object_id]: - self._running_effects_list[object_id].remove(_effect) - - effect.start(time_span=time_span, on_end=_on_end) - if object_id not in self._running_effects_list: - self._running_effects_list[object_id] = list() - self._running_effects_list[object_id].append(effect) - - # noinspection PyMissingOrEmptyDocstring - def stop_all_visual_effects(self, target: GameObject = None) -> None: - if target is None: - for (object_id, effects) in tuple(self._running_effects_list.items()): - for effect in effects: - effect.stop() - self._running_effects_list[object_id].remove(effect) - else: - if CommonTypeUtils.is_sim_or_sim_info(target): - # noinspection PyTypeChecker - object_id = CommonSimUtils.get_sim_id(target) - else: - object_id = CommonObjectUtils.get_object_id(target) - - if object_id not in self._running_effects_list: - return - - for effect in tuple(self._running_effects_list[object_id]): - effect.stop() - self._running_effects_list[object_id].remove(effect) - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.play_visual_effect', - 'Play a VFX on a Sim. Run `s4clib.stop_all_visual_effects` to stop the visual effect.', - command_arguments=( - CommonConsoleCommandArgument('effect_name', 'Text', 'The name of an effect to play.'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Id or Name of a Sim to attach the VFX to.', is_optional=True, default_value='Active Sim'), - CommonConsoleCommandArgument('sim_minutes_until_end', 'Number', 'The number of Sim Minutes to play the effect for before it auto stops.', is_optional=True, default_value='Effect default length'), - CommonConsoleCommandArgument('joint_bone_name', 'Text', 'The name of the bone or joint to attach the effect to on the source object.', is_optional=True, default_value='b__Head__'), - CommonConsoleCommandArgument('target_joint_bone_name', 'Text', 'The name of the bone or joint to attach the effect to on the target object.', is_optional=True, default_value=None), - ) -) -def _common_play_visual_effect( - output: CommonConsoleCommandOutput, - effect_name: str, - sim_info: SimInfo = None, - sim_minutes_until_end: int = None, - joint_bone_name: str = 'b__Head__', - target_joint_bone_name: str = None -): - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - output(f'FAILED: Sim {sim_info} was not found nearby.') - return False - output(f'Running VFX {effect_name} on Sim {sim_info}') - - time_span = None - if sim_minutes_until_end is not None: - time_span = clock.interval_in_sim_minutes(sim_minutes_until_end) - _CommonVisualEffectCommandService().play_visual_effect(sim, effect_name, joint_bone_name=joint_bone_name, target_joint_bone_name=target_joint_bone_name, time_span=time_span) - output(f'Started effect {effect_name} on Sim {sim_info}') - return True - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.play_visual_effect_object', - 'Play a VFX on an Object. Run `s4clib.stop_all_visual_effects` to stop the visual effect.', - command_arguments=( - CommonConsoleCommandArgument('effect_name', 'Text', 'The name of an effect to play.'), - CommonConsoleCommandArgument('game_object', 'Instance Id of Object', 'The instance id of an Object to attach the VFX to.'), - CommonConsoleCommandArgument('sim_minutes_until_end', 'Number', 'The number of Sim Minutes to play the effect for before it auto stops.', is_optional=True, default_value='Effect default length'), - CommonConsoleCommandArgument('joint_bone_name', 'Text', 'The name of the bone or joint to attach the effect to on the source object.', is_optional=True, default_value='b__Head__'), - CommonConsoleCommandArgument('target_joint_bone_name', 'Text', 'The name of the bone or joint to attach the effect to on the target object.', is_optional=True, default_value=None), - ) -) -def _common_play_visual_effect( - output: CommonConsoleCommandOutput, - effect_name: str, - game_object: GameObject, - sim_minutes_until_end: int = None, - joint_bone_name: str = 'b__Root__', - target_joint_bone_name: str = None -): - output(f'Running VFX {effect_name} on Game Object {game_object}') - - time_span = None - if sim_minutes_until_end is not None: - time_span = clock.interval_in_sim_minutes(sim_minutes_until_end) - _CommonVisualEffectCommandService().play_visual_effect(game_object, effect_name, joint_bone_name=joint_bone_name, target_joint_bone_name=target_joint_bone_name, time_span=time_span) - output(f'Started effect {effect_name} on Game Object {game_object}') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.stop_visual_effects_sim', - 'Stop all running effects that were started via `s4clib.play_visual_effect` on a Sim.', - command_arguments=( - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Id or Name of a Sim to attach the VFX to.', is_optional=True, default_value='Active Sim'), - ) -) -def _common_stop_debug_visual_effects_on_sim(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): - output(f'Stopping all debug added VFX on {sim_info}.') - _CommonVisualEffectCommandService().stop_all_visual_effects(target=sim_info) - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.stop_visual_effects_object', - 'Stop all running effects that were started via `s4clib.play_visual_effect` on a Game Object.', - command_arguments=( - CommonConsoleCommandArgument('game_object', 'Instance Id of Object', 'The instance id of an Object to attach the VFX to.'), - ) -) -def _common_stop_debug_visual_effects_on_object(output: CommonConsoleCommandOutput, game_object: GameObject): - if not isinstance(game_object, GameObject): - return False - output(f'Stopping all debug added VFX on {game_object}.') - _CommonVisualEffectCommandService().stop_all_visual_effects(target=game_object) - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.stop_all_visual_effects', - 'Stop all running effects that were started via `s4clib.play_visual_effect`.' -) -def _common_stop_all_debug_visual_effects(output: CommonConsoleCommandOutput): - output('Stopping all debug added VFX.') - _CommonVisualEffectCommandService().stop_all_visual_effects() - - -# noinspection PyUnusedLocal -@CommonEventRegistry.handle_events(ModInfo.get_identity()) -def _common_stop_all_debug_visual_effects_on_zone_teardown(event_data: S4CLZoneTeardownEvent): - _CommonVisualEffectCommandService().stop_all_visual_effects() diff --git a/Scripts/s4ap/sims4communitylib/utils/environment/__init__.py b/Scripts/s4ap/sims4communitylib/utils/environment/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/environment/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/utils/environment/common_business_utils.py b/Scripts/s4ap/sims4communitylib/utils/environment/common_business_utils.py deleted file mode 100644 index 1fe034b..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/environment/common_business_utils.py +++ /dev/null @@ -1,80 +0,0 @@ -""" -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 -""" -from typing import Union - -from business.business_funds import BusinessFunds -from business.business_manager import BusinessManager -from business.business_service import BusinessService - - -class CommonBusinessUtils: - """Utilities for manipulating Businesses.""" - @classmethod - def get_business_manager_for_current_zone(cls) -> BusinessManager: - """get_business_manager_for_current_zone() - - Retrieve a Business Manager for the current Zone. - - :return: A Business Manager for the current zone. - :rtype: BusinessManager - """ - from s4ap.sims4communitylib.utils.location.common_location_utils import CommonLocationUtils - return cls.get_business_manager_by_zone_id(CommonLocationUtils.get_current_zone_id()) - - @classmethod - def get_business_manager_by_zone_id(cls, zone_id: int) -> BusinessManager: - """get_business_manager_by_zone_id(zone_id) - - Retrieve a Business Manager for a Zone. - - :param zone_id: The identifier of the Zone to retrieve a Business Manager from. - :type zone_id: int - :return: A Business Manager for the specified zone. - :rtype: BusinessManager - """ - return cls.get_business_service().get_business_manager_for_zone(zone_id=zone_id) - - @classmethod - def get_business_funds_for_current_zone(cls) -> Union[BusinessFunds, None]: - """get_business_funds_for_current_zone() - - Retrieve the Funds object that manages the Simoleons for the Business of the current Zone. - - :return: The BusinessFunds object of the Business at the current Zone or None if the current Zone did not have a Business. - :rtype: Union[BusinessFunds, None] - """ - from s4ap.sims4communitylib.utils.location.common_location_utils import CommonLocationUtils - return cls.get_business_funds_by_zone_id(CommonLocationUtils.get_current_zone_id()) - - @classmethod - def get_business_funds_by_zone_id(cls, zone_id: int) -> Union[BusinessFunds, None]: - """get_business_funds_by_zone_id(zone_id) - - Retrieve the Funds object that manages the Simoleons for the Business of a Zone. - - :param zone_id: The identifier of the Zone to retrieve a Business from. Default is the current zone. - :type zone_id: int, optional - :return: The BusinessFunds object of the Business at the specified zone or None if the specified Zone did not have a Business. - :rtype: Union[BusinessFunds, None] - """ - business_manager = CommonBusinessUtils.get_business_manager_by_zone_id(zone_id) - if business_manager is None: - return - return business_manager.funds - - @classmethod - def get_business_service(cls) -> BusinessService: - """get_business_service() - - Retrieve an instance of the Business Service. - - :return: An instance of the Business Service. - :rtype: BusinessService - """ - import services - return services.business_service() diff --git a/Scripts/s4ap/sims4communitylib/utils/environment/common_civic_policy_utils.py b/Scripts/s4ap/sims4communitylib/utils/environment/common_civic_policy_utils.py deleted file mode 100644 index 083e537..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/environment/common_civic_policy_utils.py +++ /dev/null @@ -1,455 +0,0 @@ -""" -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 -""" -from typing import Union, Tuple - -from civic_policies.base_civic_policy import BaseCivicPolicy -from civic_policies.street_civic_policy import StreetCivicPolicy -from civic_policies.street_civic_policy_provider import StreetProvider -from s4ap.sims4communitylib.enums.common_civic_policy_status_type import CommonCivicPolicyStatusType -from s4ap.sims4communitylib.enums.common_street_civic_policy_ids import CommonStreetCivicPolicyId -from s4ap.sims4communitylib.enums.common_venue_civic_policy_ids import CommonVenueCivicPolicyId -from s4ap.sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.location.common_location_utils import CommonLocationUtils -from venues.civic_policies.venue_civic_policy import VenueCivicPolicy -from venues.civic_policies.venue_civic_policy_provider import VenueCivicPolicyProvider - - -class CommonCivicPolicyUtils(_HasS4CLClassLog): - """Utilities for manipulating civic policies.""" - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 'common_civic_policy_utils' - - @classmethod - def is_free_love_enacted(cls) -> bool: - """is_free_love_enacted() - - Determine if the Free Love civic policy has been enacted in the current zone. - - :return: True, if the policy is enacted. False, if not. - :rtype: bool - """ - return cls.is_policy_enacted_in_current_zone(CommonStreetCivicPolicyId.SKILL_BASED_FREE_LOVE) - - @classmethod - def is_policy_enacted_in_zone(cls, zone_id: int, policy: Union[int, CommonVenueCivicPolicyId, CommonStreetCivicPolicyId, BaseCivicPolicy]) -> bool: - """is_policy_enacted_in_zone(zone_id, policy) - - Determine if a Policy is currently enacted in a Zone. - - :param zone_id: The identifier of the Zone to check. - :type zone_id: int - :param policy: The policy to look for. - :type policy: Union[int, CommonVenueCivicPolicyId, CommonStreetCivicPolicyId, BaseCivicPolicy] - :return: True, if the specified policy is currently enacted in a Zone. False, if not. - :rtype: bool - """ - return cls.is_policy_in_zone(zone_id, policy, CommonCivicPolicyStatusType.ENACTED) - - @classmethod - def is_policy_balloted_in_zone(cls, zone_id: int, policy: Union[int, CommonVenueCivicPolicyId, CommonStreetCivicPolicyId, BaseCivicPolicy]) -> bool: - """is_policy_balloted_in_zone(zone_id, policy) - - Determine if a Policy is currently balloted in a Zone. - - :param zone_id: The identifier of the Zone to check. - :type zone_id: int - :param policy: The policy to look for. - :type policy: Union[int, CommonVenueCivicPolicyId, CommonStreetCivicPolicyId, BaseCivicPolicy] - :return: True, if the specified policy is currently balloted in a Zone. False, if not. - :rtype: bool - """ - return cls.is_policy_in_zone(zone_id, policy, CommonCivicPolicyStatusType.BALLOTED) - - @classmethod - def is_policy_up_for_repeal_in_zone(cls, zone_id: int, policy: Union[int, CommonVenueCivicPolicyId, CommonStreetCivicPolicyId, BaseCivicPolicy]) -> bool: - """is_up_for_repeal_in_zone(zone_id, policy) - - Determine if a Policy is currently up for repeal in a Zone. - - :param zone_id: The identifier of the Zone to check. - :type zone_id: int - :param policy: The policy to look for. - :type policy: Union[int, CommonVenueCivicPolicyId, CommonStreetCivicPolicyId, BaseCivicPolicy] - :return: True, if the specified policy is currently up for repeal in a Zone. False, if not. - :rtype: bool - """ - return cls.is_policy_in_zone(zone_id, policy, CommonCivicPolicyStatusType.UP_FOR_REPEAL) - - @classmethod - def is_dormant_in_zone(cls, zone_id: int, policy: Union[int, CommonVenueCivicPolicyId, CommonStreetCivicPolicyId, BaseCivicPolicy]) -> bool: - """is_dormant_in_zone(zone_id, policy) - - Determine if a Policy is currently up for repeal in a Zone. - - :param zone_id: The identifier of the Zone to check. - :type zone_id: int - :param policy: The policy to look for. - :type policy: Union[int, CommonVenueCivicPolicyId, CommonStreetCivicPolicyId, BaseCivicPolicy] - :return: True, if the specified policy is currently up for repeal in a Zone. False, if not. - :rtype: bool - """ - return cls.is_policy_in_zone(zone_id, policy, CommonCivicPolicyStatusType.DORMANT) - - @classmethod - def is_policy_enacted_in_current_zone(cls, policy: Union[int, CommonVenueCivicPolicyId, CommonStreetCivicPolicyId, BaseCivicPolicy]) -> bool: - """is_policy_enacted_in_current_zone(policy) - - Determine if a Policy is currently enacted in the current Zone. - - :param policy: The policy to look for. - :type policy: Union[int, CommonVenueCivicPolicyId, CommonStreetCivicPolicyId, BaseCivicPolicy] - :return: True, if the specified policy is currently enacted in the current Zone. False, if not. - :rtype: bool - """ - return cls.is_policy_in_zone(CommonLocationUtils.get_current_zone_id(), policy, CommonCivicPolicyStatusType.ENACTED) - - @classmethod - def is_policy_balloted_in_current_zone(cls, policy: Union[int, CommonVenueCivicPolicyId, CommonStreetCivicPolicyId, BaseCivicPolicy]) -> bool: - """is_policy_balloted_in_current_zone(policy) - - Determine if a Policy is currently balloted in the current Zone. - - :param policy: The policy to look for. - :type policy: Union[int, CommonVenueCivicPolicyId, CommonStreetCivicPolicyId, BaseCivicPolicy] - :return: True, if the specified policy is currently balloted in the current Zone. False, if not. - :rtype: bool - """ - return cls.is_policy_in_zone(CommonLocationUtils.get_current_zone_id(), policy, CommonCivicPolicyStatusType.BALLOTED) - - @classmethod - def is_policy_up_for_repeal_in_current_zone(cls, policy: Union[int, CommonVenueCivicPolicyId, CommonStreetCivicPolicyId, BaseCivicPolicy]) -> bool: - """is_up_for_repeal_in_current_zone(policy) - - Determine if a Policy is currently up for repeal in the current Zone. - - :param policy: The policy to look for. - :type policy: Union[int, CommonVenueCivicPolicyId, CommonStreetCivicPolicyId, BaseCivicPolicy] - :return: True, if the specified policy is currently up for repeal in the current Zone. False, if not. - :rtype: bool - """ - return cls.is_policy_in_zone(CommonLocationUtils.get_current_zone_id(), policy, CommonCivicPolicyStatusType.UP_FOR_REPEAL) - - @classmethod - def is_dormant_in_current_zone(cls, policy: Union[int, CommonVenueCivicPolicyId, CommonStreetCivicPolicyId, BaseCivicPolicy]) -> bool: - """is_dormant_in_current_zone(policy) - - Determine if a Policy is currently up for repeal in the current Zone. - - :param policy: The policy to look for. - :type policy: Union[int, CommonVenueCivicPolicyId, CommonStreetCivicPolicyId, BaseCivicPolicy] - :return: True, if the specified policy is currently up for repeal in the current Zone. False, if not. - :rtype: bool - """ - return cls.is_policy_in_zone(CommonLocationUtils.get_current_zone_id(), policy, CommonCivicPolicyStatusType.DORMANT) - - @classmethod - def is_policy_in_zone(cls, zone_id: int, policy: Union[int, CommonVenueCivicPolicyId, CommonStreetCivicPolicyId, BaseCivicPolicy], policy_status: CommonCivicPolicyStatusType) -> bool: - """is_policy_in_current_zone(zone_id, policy, policy_status) - - Determine if a Policy has a specific Status in a Zone. - - :param zone_id: The identifier of the Zone to check. - :type zone_id: int - :param policy: The policy to look for. - :type policy: Union[int, CommonVenueCivicPolicyId, CommonStreetCivicPolicyId, BaseCivicPolicy] - :param policy_status: The status of the policies to check. - :type policy_status: CommonCivicPolicyStatusType - :return: True, if the specified policy has the specified status in a Zone. False, if not. - :rtype: bool - """ - policy = cls.load_civic_policy_by_id(policy) - if policy is None: - return False - if isinstance(policy, StreetCivicPolicy): - policies = cls.get_street_civic_policies_by_zone_id(zone_id, policy_status) - elif isinstance(policy, VenueCivicPolicy): - policies = cls.get_venue_civic_policies_by_zone_id(zone_id, policy_status) - else: - return False - return policy in policies - - @classmethod - def is_policy_in_current_zone(cls, policy: Union[int, CommonVenueCivicPolicyId, CommonStreetCivicPolicyId, BaseCivicPolicy], policy_status: CommonCivicPolicyStatusType) -> bool: - """is_policy_in_current_zone(policy, policy_status) - - Determine if a Policy has a specific Status in the current Zone. - - :param policy: The policy to look for. - :type policy: Union[int, CommonVenueCivicPolicyId, CommonStreetCivicPolicyId, BaseCivicPolicy] - :param policy_status: The status of the policies to check. - :type policy_status: CommonCivicPolicyStatusType - :return: True, if the specified policy has the specified status in the current Zone. False, if not. - :rtype: bool - """ - return cls.is_policy_in_zone(CommonLocationUtils.get_current_zone_id(), policy, policy_status) - - @classmethod - def get_street_civic_policies_by_zone_id(cls, zone_id: int, policy_status: CommonCivicPolicyStatusType) -> Tuple[StreetCivicPolicy]: - """get_street_civic_policies_by_zone_id(zone_id, policy_status) - - Retrieve Street Civic Policies with the specifies status from the specified zone. - - :param zone_id: The identifier of the Zone to retrieve the civic policies from. - :type zone_id: int - :param policy_status: The status of the policies to look for. - :type policy_status: CommonCivicPolicyStatusType - :return: A collection of Street Civic Policies with the specified status from the specified zone. - :rtype: Tuple[StreetCivicPolicy] - """ - provider = CommonCivicPolicyUtils.get_street_civic_policy_provider_by_zone_id(zone_id) - if provider is None: - return tuple() - if policy_status == CommonCivicPolicyStatusType.ENACTED: - return provider.get_enacted_policies() - if policy_status == CommonCivicPolicyStatusType.BALLOTED: - return provider.get_balloted_policies() - if policy_status == CommonCivicPolicyStatusType.UP_FOR_REPEAL: - return provider.get_up_for_repeal_policies() - if policy_status == CommonCivicPolicyStatusType.DORMANT: - return provider.get_dormant_policies() - return tuple() - - @classmethod - def get_street_civic_policies_in_current_zone(cls, policy_status: CommonCivicPolicyStatusType) -> Tuple[StreetCivicPolicy]: - """get_street_civic_policies_in_current_zone(policy_status) - - Retrieve Street Civic Policies with the specifies status from the current zone. - - :param policy_status: The status of the policies to look for. - :type policy_status: CommonCivicPolicyStatusType - :return: A collection of Street Civic Policies with the specified status from the current zone. - :rtype: Tuple[StreetCivicPolicy] - """ - return cls.get_street_civic_policies_by_zone_id(CommonLocationUtils.get_current_zone_id(), policy_status) - - @classmethod - def get_street_civic_policy_provider_for_current_zone(cls) -> Union[StreetProvider, None]: - """get_street_civic_policy_provider_for_current_zone(zone_id) - - Retrieve the Street Civic Policy Provider for the current Zone. - - :return: The Street Civic Policy Provider for the current Zone or None if the street service is unavailable or there is no street for the current Zone. - :rtype: Union[StreetProvider, None] - """ - return cls.get_street_civic_policy_provider_by_zone_id(CommonLocationUtils.get_current_zone_id()) - - @classmethod - def get_street_civic_policy_provider_by_world_id(cls, world_id: int) -> Union[StreetProvider, None]: - """get_street_civic_policy_provider_by_world_id(zone_id) - - Retrieve the Street Civic Policy Provider for a World. - - :param world_id: The identifier of the World to retrieve the civic policy provider from. - :type world_id: int - :return: The Street Civic Policy Provider for the specified World or None if the street service is unavailable or there is no street for the specified World. - :rtype: Union[StreetProvider, None] - """ - street_service = CommonLocationUtils.get_street_service() - if street_service is None: - return None - street = CommonLocationUtils.get_street_by_world_id(world_id) - if street is None: - return None - return street_service.get_provider(street) - - @classmethod - def get_street_civic_policy_provider_by_zone_id(cls, zone_id: int) -> Union[StreetProvider, None]: - """get_street_civic_policy_provider_by_zone_id(zone_id) - - Retrieve the Street Civic Policy Provider for a Zone. - - :param zone_id: The identifier of the Zone to retrieve the civic policy provider from. - :type zone_id: int - :return: The Street Civic Policy Provider for the specified Zone or None if the street service is unavailable or there is no street for the specified Zone. - :rtype: Union[StreetProvider, None] - """ - street_service = CommonLocationUtils.get_street_service() - if street_service is None: - return None - street = CommonLocationUtils.get_street_by_zone_id(zone_id) - if street is None: - return None - return street_service.get_provider(street) - - @classmethod - def get_venue_civic_policies_by_zone_id(cls, zone_id: int, policy_status: CommonCivicPolicyStatusType) -> Tuple[VenueCivicPolicy]: - """get_venue_civic_policies_by_zone_id(zone_id, policy_status) - - Retrieve Venue Civic Policies with the specifies status from the specified zone. - - :param zone_id: The identifier of the Zone to retrieve the civic policies from. - :type zone_id: int - :param policy_status: The status of the policies to look for. - :type policy_status: CommonCivicPolicyStatusType - :return: A collection of Venue Civic Policies with the specified status from the specified zone. - :rtype: Tuple[VenueCivicPolicy] - """ - provider = CommonCivicPolicyUtils.get_venue_civic_policy_provider_by_zone_id(zone_id) - if provider is None: - return tuple() - if policy_status == CommonCivicPolicyStatusType.ENACTED: - return provider.get_enacted_policies() - if policy_status == CommonCivicPolicyStatusType.BALLOTED: - return provider.get_balloted_policies() - if policy_status == CommonCivicPolicyStatusType.UP_FOR_REPEAL: - return provider.get_up_for_repeal_policies() - if policy_status == CommonCivicPolicyStatusType.DORMANT: - return provider.get_dormant_policies() - return tuple() - - @classmethod - def get_venue_civic_policies_in_current_zone(cls, policy_status: CommonCivicPolicyStatusType) -> Tuple[VenueCivicPolicy]: - """get_venue_civic_policies_in_current_zone(policy_status) - - Retrieve Venue Civic Policies with the specifies status from the current zone. - - :param policy_status: The status of the policies to look for. - :type policy_status: CommonCivicPolicyStatusType - :return: A collection of Venue Civic Policies with the specified status from the current zone. - :rtype: Tuple[VenueCivicPolicy] - """ - return cls.get_venue_civic_policies_by_zone_id(CommonLocationUtils.get_current_zone_id(), policy_status) - - @classmethod - def get_venue_civic_policy_provider_for_current_zone(cls) -> Union[VenueCivicPolicyProvider, None]: - """get_venue_civic_policy_provider_for_current_zone() - - Retrieve the Venue Civic Policy Provider for a Zone. - - :return: The Venue Civic Policy Provider for the current Zone or None if the current Zone does not have a venue. - :rtype: Union[VenueCivicPolicyProvider, None] - """ - return cls.get_venue_civic_policy_provider_by_zone_id(CommonLocationUtils.get_current_zone_id()) - - @classmethod - def get_venue_civic_policy_provider_by_zone_id(cls, zone_id: int) -> Union[VenueCivicPolicyProvider, None]: - """get_venue_civic_policy_provider_by_zone_id(zone_id) - - Retrieve the Venue Civic Policy Provider for a Zone. - - :param zone_id: The identifier of the Zone to retrieve the civic policy provider from. - :type zone_id: int - :return: The Venue Civic Policy Provider for the specified Zone or None if the specified Zone does not have a venue. - :rtype: Union[VenueCivicPolicyProvider, None] - """ - venue = CommonLocationUtils.get_venue_by_zone_id(zone_id) - if venue is None: - return None - return venue.civic_policy_provider - - @classmethod - def load_civic_policy_by_id(cls, policy: Union[int, CommonVenueCivicPolicyId, CommonStreetCivicPolicyId, BaseCivicPolicy]) -> Union[BaseCivicPolicy, None]: - """load_civic_policy_by_id(policy) - - Load an instance of a Civic Policy by its identifier. - - :param policy: The identifier of a Civic Policy. - :type policy: Union[int, CommonVenueCivicPolicyId, CommonStreetCivicPolicyId, BaseCivicPolicy] - :return: An instance of a Civic Policy matching the decimal identifier or None if not found. - :rtype: Union[BaseCivicPolicy, None] - """ - if isinstance(policy, BaseCivicPolicy): - return policy - # noinspection PyBroadException - try: - # noinspection PyCallingNonCallable - policy_instance = policy() - if isinstance(policy_instance, BaseCivicPolicy): - # noinspection PyTypeChecker - return policy - except: - pass - # noinspection PyBroadException - try: - policy: int = int(policy) - except: - # noinspection PyTypeChecker - policy: BaseCivicPolicy = policy - return policy - - from sims4.resources import Types - from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils - return CommonResourceUtils.load_instance(Types.SNIPPET, policy) - - -@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.print_enacted_street_policies', 'Print a list of enacted policies.') -def _common_print_street_civic_policies(output: CommonConsoleCommandOutput, policy_status: CommonCivicPolicyStatusType): - log = CommonCivicPolicyUtils.get_log() - try: - log.enable() - provider = CommonCivicPolicyUtils.get_street_civic_policy_provider_for_current_zone() - policies = provider.get_enacted_policies(tuning=True) - output(f'------------{policy_status.name} Street Civic Policies------------') - log.debug(f'------------{policy_status.name} Street Civic Policies------------') - for policy in policies: - output(f'Policy: {policy}') - log.format_with_message(f'Policy: {policy}') - output('------------------------------------------------------') - log.debug('------------------------------------------------------') - finally: - log.disable() - - -@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.print_enacted_street_policies', 'Print a list of enacted policies.') -def _common_print_enacted_street_policies(output: CommonConsoleCommandOutput): - log = CommonCivicPolicyUtils.get_log() - try: - log.enable() - provider = CommonCivicPolicyUtils.get_street_civic_policy_provider_for_current_zone() - policies = provider.get_enacted_policies(tuning=True) - output('------------Enacted Street Civic Policies------------') - log.debug('------------Enacted Street Civic Policies------------') - for policy in policies: - output(f'Policy: {policy}') - log.format_with_message(f'Policy: {policy}') - output('------------------------------------------------------') - log.debug('------------------------------------------------------') - finally: - log.disable() - - -@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.print_balloted_street_policies', 'Print a list of balloted policies.') -def _common_print_balloted_street_policies(output: CommonConsoleCommandOutput): - log = CommonCivicPolicyUtils.get_log() - try: - log.enable() - provider = CommonCivicPolicyUtils.get_street_civic_policy_provider_for_current_zone() - policies = provider.get_balloted_policies(tuning=True) - output('------------Balloted Street Civic Policies------------') - log.debug('------------Balloted Street Civic Policies------------') - for policy in policies: - output(f'Policy: {policy}') - log.format_with_message(f'Policy: {policy}') - output('------------------------------------------------------') - log.debug('------------------------------------------------------') - finally: - log.disable() - - -@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.print_dormant_street_policies', 'Print a list of dormant policies.') -def _common_print_dormant_street_policies(output: CommonConsoleCommandOutput): - log = CommonCivicPolicyUtils.get_log() - try: - log.enable() - provider = CommonCivicPolicyUtils.get_street_civic_policy_provider_for_current_zone() - policies = provider.get_dormant_policies(tuning=True) - output('------------Dormant Street Civic Policies------------') - log.debug('------------Dormant Street Civic Policies------------') - for policy in policies: - output(f'Policy: {policy}') - log.format_with_message(f'Policy: {policy}') - output('------------------------------------------------------') - log.debug('------------------------------------------------------') - finally: - log.disable() diff --git a/Scripts/s4ap/sims4communitylib/utils/localization/__init__.py b/Scripts/s4ap/sims4communitylib/utils/localization/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/localization/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/utils/localization/common_localization_utils.py b/Scripts/s4ap/sims4communitylib/utils/localization/common_localization_utils.py deleted file mode 100644 index c1ac40e..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/localization/common_localization_utils.py +++ /dev/null @@ -1,245 +0,0 @@ -""" -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 -""" -from typing import Union, Any, Iterator - -from protocolbuffers.Localization_pb2 import LocalizedString -from sims4.localization import LocalizationHelperTuning, _create_localized_string, create_tokens, \ - TunableLocalizedStringFactory -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.utils.localization.common_localized_string_colors import CommonLocalizedStringColor -from s4ap.sims4communitylib.utils.localization.common_localized_string_separators import CommonLocalizedStringSeparator - - -class CommonLocalizationUtils: - """Utilities for handling localization strings. - - .. note:: Localized Strings are the python equivalent of values within a StringTable. - - """ - class LocalizedTooltip(TunableLocalizedStringFactory._Wrapper): - """CommonLocalizationUtils.LocalizedTooltip(string_id, *tokens) - - A LocalizedTooltip used when displaying tooltips. - - :param string_id: The text that will display in the tooltip. - :type string_id: Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator] - :param tokens: A collection of objects to format into the `string_id` - :type tokens: Any - """ - def __init__(self, string_id: Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator], *tokens: Any): - super().__init__(string_id) - self._tokens = tokens - - def __call__(self, *_) -> LocalizedString: - return CommonLocalizationUtils.create_localized_string(self._string_id, tokens=self._tokens) - - @staticmethod - def create_localized_tooltip(tooltip_text: Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator], tooltip_tokens: Iterator[Any]=()) -> 'LocalizedTooltip': - """create_localized_tooltip(tooltip_text, tooltip_tokens=()) - - Create a LocalizedTooltip use this when you wish to display a tooltip on various things. - - :param tooltip_text: The text that will be displayed. - :type tooltip_text: Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator] - :param tooltip_tokens: A collection of objects to format into the localized string. (They can be anything. LocalizedString, str, int, SimInfo, just to name a few) - :type tooltip_tokens: Iterator[Any], optional - :return: A tooltip ready for display. - :rtype: LocalizedTooltip - """ - if isinstance(tooltip_text, CommonLocalizationUtils.LocalizedTooltip): - return tooltip_text - return CommonLocalizationUtils.LocalizedTooltip(tooltip_text, *tuple(tooltip_tokens)) - - @staticmethod - def create_localized_string(identifier: Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator], tokens: Iterator[Any] = (), localize_tokens: bool = True, text_color: CommonLocalizedStringColor = CommonLocalizedStringColor.DEFAULT) -> LocalizedString: - """create_localized_string(identifier, tokens=(), localize_tokens=True, text_color=CommonLocalizedStringColor.DEFAULT) - - Create a LocalizedString formatted with the specified tokens. - - :param identifier: An identifier to locate a LocalizedString with, text that will be turned into a LocalizedString, or a LocalizedString itself. - :type identifier: Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator] - :param tokens: A collection of objects to format into the localized string. (They can be anything. LocalizedString, str, int, SimInfo, just to name a few) - :type tokens: Iterator[Any] - :param localize_tokens: If True, the specified tokens will be localized. If False, the specified tokens will be formatted into the LocalizedString as they are. Default is True - :type localize_tokens: bool - :param text_color: The color the text will be when displayed. - :type text_color: CommonLocalizedStringColor - :return: A localized string ready for display. - :rtype: LocalizedString - """ - if identifier is None: - return CommonLocalizationUtils.create_localized_string(CommonStringId.STRING_NOT_FOUND_WITH_IDENTIFIER, tokens=('None',), text_color=text_color) - if localize_tokens: - tokens = tuple(CommonLocalizationUtils._normalize_tokens(*tokens)) - if isinstance(identifier, LocalizedString) and hasattr(identifier, 'tokens'): - create_tokens(identifier.tokens, tokens) - return CommonLocalizationUtils.colorize(identifier, text_color=text_color) - if isinstance(identifier, TunableLocalizedStringFactory._Wrapper): - if isinstance(identifier._string_id, str): - string_id = CommonLocalizationUtils.create_from_string(identifier._string_id) - else: - string_id = CommonLocalizationUtils.create_from_int(identifier._string_id, *tuple(tokens)) - return CommonLocalizationUtils.colorize(string_id, text_color=text_color) - if isinstance(identifier, int): - return CommonLocalizationUtils.colorize(CommonLocalizationUtils.create_from_int(identifier, *tuple(tokens)), text_color=text_color) - if hasattr(identifier, 'sim_info'): - return identifier.sim_info - if hasattr(identifier, 'get_sim_info'): - return identifier.get_sim_info() - if isinstance(identifier, str): - return CommonLocalizationUtils.create_localized_string(CommonLocalizationUtils.create_from_string(identifier), tokens=tokens, text_color=text_color) - return CommonLocalizationUtils.create_localized_string(str(identifier), tokens=tokens, text_color=text_color) - - @staticmethod - def combine_localized_strings(identifier_list: Iterator[Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator]], separator: CommonLocalizedStringSeparator=CommonLocalizedStringSeparator.NO_SEPARATOR) -> LocalizedString: - """combine_localized_strings(identifier_list, separator=CommonLocalizedStringSeparator.NO_SEPARATOR) - - Combine multiple localized strings by a separator. - - :param identifier_list: A collection of identifiers to locate LocalizedStrings with, text that will be turned into a LocalizedString and combined with the other strings in the collection. - :type identifier_list: Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator] - :param separator: The separator to use when combining the strings. Default is to combine all of the strings by no separator, i.e. an empty space. - :type separator: CommonLocalizedStringSeparator, optional - :return: A localized string with all Localized Strings combined by the specified separator. - :rtype: LocalizedString - """ - localized = None - for identifier in identifier_list: - if localized is None: - localized = identifier - else: - localized = CommonLocalizationUtils.create_localized_string(separator, tokens=(localized, identifier)) - return localized - - @staticmethod - def combine_localized_strings_with_comma_space_and(identifier_list: Iterator[Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator]]) -> LocalizedString: - """combine_localized_strings_with_comma_space_and(identifier_list) - - Combine multiple localized strings and formulate a string that is of format "{0.String}", "{0.String} and {1.String}", or "{0.String}, and {1.String}". With {0.String} being the first strings in the collection and {1.String} being the last string in the collection. - - .. note:: Example: ['one'] will turn into "one". ['one', 'two'] will turn into "one and two". ['one', 'two', 'three'] will turn into "one, two, and three". - - :param identifier_list: A collection of identifiers to combine. - :type identifier_list: Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator] - :return: A localized string with all Localized Strings combined with a "comma space and" separator. - :rtype: LocalizedString - """ - identifier_list = tuple(identifier_list) - if not identifier_list: - return CommonStringId.S4CL_NONE - - if len(identifier_list) <= 1: - return CommonLocalizationUtils.combine_localized_strings(identifier_list, separator=CommonLocalizedStringSeparator.COMMA_SPACE) - - last_tag_text = identifier_list[-1] - combined_tags_text = CommonLocalizationUtils.combine_localized_strings(identifier_list[:-1], separator=CommonLocalizedStringSeparator.COMMA_SPACE) - if len(identifier_list) == 2: - return CommonLocalizationUtils.combine_localized_strings((combined_tags_text, last_tag_text), separator=CommonLocalizedStringSeparator.AND) - else: - return CommonLocalizationUtils.combine_localized_strings((combined_tags_text, last_tag_text), separator=CommonLocalizedStringSeparator.COMMA_SPACE_AND) - - @staticmethod - def combine_localized_strings_with_comma_space_or(identifier_list: Iterator[Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator]]) -> LocalizedString: - """combine_localized_strings_with_comma_space_or(identifier_list) - - Combine multiple localized strings and formulate a string that is of format "{0.String}", "{0.String} or {1.String}", or "{0.String}, or {1.String}". With {0.String} being the first strings in the collection and {1.String} being the last string in the collection. - - .. note:: Example: ['one'] will turn into "one". ['one', 'two'] will turn into "one or two". ['one', 'two', 'three'] will turn into "one, two, or three". - - :param identifier_list: A collection of identifiers to combine. - :type identifier_list: Union[int, str, LocalizedString, CommonStringId, CommonLocalizedStringSeparator] - :return: A localized string with all Localized Strings combined with a "comma space or" separator. - :rtype: LocalizedString - """ - identifier_list = tuple(identifier_list) - if not identifier_list: - return CommonStringId.S4CL_NONE - - if len(identifier_list) <= 1: - return CommonLocalizationUtils.combine_localized_strings(identifier_list, separator=CommonLocalizedStringSeparator.COMMA_SPACE) - - last_tag_text = identifier_list[-1] - combined_tags_text = CommonLocalizationUtils.combine_localized_strings(identifier_list[:-1], separator=CommonLocalizedStringSeparator.COMMA_SPACE) - if len(identifier_list) == 2: - return CommonLocalizationUtils.combine_localized_strings((combined_tags_text, last_tag_text), separator=CommonLocalizedStringSeparator.OR) - else: - return CommonLocalizationUtils.combine_localized_strings((combined_tags_text, last_tag_text), separator=CommonLocalizedStringSeparator.COMMA_SPACE_OR) - - @staticmethod - def create_from_string(string_text: str) -> LocalizedString: - """create_from_string(string_text) - - Create a LocalizedString from a string. - - :param string_text: The string to localize. The resulting LocalizedString will be '{0.String}' - :type string_text: str - :return: A LocalizedString created from the specified string. - :rtype: LocalizedString - """ - return LocalizationHelperTuning.get_raw_text(string_text) - - @staticmethod - def create_from_int(identifier: int, *tokens: Any) -> LocalizedString: - """create_from_int(identifier, *tokens) - - Locate a LocalizedString by an identifier and format tokens into it. - - :param identifier: A decimal number that identifies an existing LocalizedString. - :type identifier: int - :param tokens: A collection of objects to format into the LocalizedString. (Example types: LocalizedString, str, int, etc.) - :type tokens: Iterator[Any] - :return: A LocalizedString with the specified tokens formatted into it. - :rtype: LocalizedString - """ - return _create_localized_string(identifier, *tokens) - - @staticmethod - def colorize(localized_string: LocalizedString, text_color: CommonLocalizedStringColor=CommonLocalizedStringColor.DEFAULT) -> LocalizedString: - """colorize(localized_string, text_color=CommonLocalizedStringColor.DEFAULT) - - Set the text color of a LocalizedString. - - :param localized_string: The LocalizedString to set the text color of. - :type localized_string: LocalizedString - :param text_color: The text will become this color. - :type text_color: CommonLocalizedStringColor - :return: A LocalizedString with text in the specified color. - :rtype: LocalizedString - """ - if text_color == CommonLocalizedStringColor.DEFAULT: - return localized_string - if not hasattr(text_color, 'value'): - return localized_string - return CommonLocalizationUtils.create_localized_string(text_color.value, tokens=(localized_string,)) - - @staticmethod - def get_localized_string_hash(localized_string: LocalizedString) -> int: - """get_localized_string_hash(localized_string) - - Retrieve the hash value of a Localized String. - - :param localized_string: An instance of a Localized String. - :type localized_string: LocalizedString - :return: The hash value of the Localized String or 0 if a problem occurs. - :rtype: int - """ - if localized_string is None: - return 0 - # noinspection PyBroadException - try: - # noinspection PyUnresolvedReferences - return localized_string.hash - except: - return 0 - - @staticmethod - def _normalize_tokens(*tokens: Any) -> Iterator[LocalizedString]: - new_tokens = [] - for token in tokens: - new_tokens.append(CommonLocalizationUtils.create_localized_string(token)) - return tuple(new_tokens) diff --git a/Scripts/s4ap/sims4communitylib/utils/localization/common_localized_string_colors.py b/Scripts/s4ap/sims4communitylib/utils/localization/common_localized_string_colors.py deleted file mode 100644 index 76bab68..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/localization/common_localized_string_colors.py +++ /dev/null @@ -1,23 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId - - -class CommonLocalizedStringColor(CommonInt): - """Used to set the text color of LocalizedString. - - See the :func:`.CommonLocalizationUtils.colorize` function for more details. - - """ - DEFAULT: 'CommonLocalizedStringColor' = -1 - BLUE: 'CommonLocalizedStringColor' = CommonStringId.TEXT_WITH_BLUE_COLOR - GREEN: 'CommonLocalizedStringColor' = CommonStringId.TEXT_WITH_GREEN_COLOR - RED: 'CommonLocalizedStringColor' = CommonStringId.TEXT_WITH_RED_COLOR - YELLOW: 'CommonLocalizedStringColor' = CommonStringId.TEXT_WITH_YELLOW_COLOR - ORANGE: 'CommonLocalizedStringColor' = CommonStringId.TEXT_WITH_ORANGE_COLOR diff --git a/Scripts/s4ap/sims4communitylib/utils/localization/common_localized_string_separators.py b/Scripts/s4ap/sims4communitylib/utils/localization/common_localized_string_separators.py deleted file mode 100644 index dab62d5..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/localization/common_localized_string_separators.py +++ /dev/null @@ -1,65 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId - - -class CommonLocalizedStringSeparator(CommonInt): - """Used to separate multiple LocalizedString. - - See the :func:`.CommonLocalizationUtils.combine_localized_strings` function for more details. - - .. note:: The values are as follows: - - NO_SEPARATOR = "StringString" - AND = "{String} and {String}" - ARE = "String are String" - COLON_SPACE = "String: String" - COMMA_SPACE = "String, String" - COMMA_SPACE_AND = "{String}, and {String}" - COMMA_SPACE_OR = "{String}, or {String}" - HYPHEN = "String-String" - IS = "String is String" - NEWLINE = "String\nString" - NEWLINE_NEWLINE = "String\n\nString" - OR = "String or String" - PLUS = "String+String" - SPACE = "String String" - SPACE_PARENTHESIS_SURROUNDED = "String (String)" - - """ - # {String}{String} - NO_SEPARATOR: 'CommonLocalizedStringSeparator' = CommonStringId.S4CL_COMBINE_TWO_STRINGS - # {String} and {String} - AND: 'CommonLocalizedStringSeparator' = CommonStringId.S4CL_STRING_AND_STRING - # {String} are {String} - ARE: 'CommonLocalizedStringSeparator' = CommonStringId.S4CL_STRING_ARE_STRING - # {String}: {String} - COLON_SPACE: 'CommonLocalizedStringSeparator' = CommonStringId.STRING_COLON_SPACE_STRING - # {String}, {String} - COMMA_SPACE: 'CommonLocalizedStringSeparator' = CommonStringId.STRING_COMMA_SPACE_STRING - # {String}, and {String} - COMMA_SPACE_AND: 'CommonLocalizedStringSeparator' = CommonStringId.S4CL_STRING_COMMA_SPACE_AND_STRING - # {String}, or {String} - COMMA_SPACE_OR: 'CommonLocalizedStringSeparator' = CommonStringId.S4CL_STRING_COMMA_SPACE_OR_STRING - # {String}-{String} - HYPHEN: 'CommonLocalizedStringSeparator' = CommonStringId.STRING_HYPHEN_STRING - # {String} is {String} - IS: 'CommonLocalizedStringSeparator' = CommonStringId.S4CL_STRING_IS_STRING - # {String}\n{String} - NEWLINE: 'CommonLocalizedStringSeparator' = CommonStringId.STRING_NEWLINE_STRING - # {String}\n\n{String} - NEWLINE_NEWLINE: 'CommonLocalizedStringSeparator' = CommonStringId.STRING_NEWLINE_NEWLINE_STRING - # {String} or {String} - OR: 'CommonLocalizedStringSeparator' = CommonStringId.S4CL_STRING_OR_STRING - # {String}+{String} - PLUS: 'CommonLocalizedStringSeparator' = CommonStringId.S4CL_STRING_PLUS_STRING - # {String} {String} - SPACE: 'CommonLocalizedStringSeparator' = CommonStringId.STRING_SPACE_STRING - # {String} ({String}) - SPACE_PARENTHESIS_SURROUNDED: 'CommonLocalizedStringSeparator' = CommonStringId.STRING_SPACE_PARENTHESIS_SURROUNDED_STRING diff --git a/Scripts/s4ap/sims4communitylib/utils/location/__init__.py b/Scripts/s4ap/sims4communitylib/utils/location/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/location/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/utils/location/common_location_utils.py b/Scripts/s4ap/sims4communitylib/utils/location/common_location_utils.py deleted file mode 100644 index ad43342..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/location/common_location_utils.py +++ /dev/null @@ -1,979 +0,0 @@ -""" -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 -""" -import services - -from typing import Tuple, Union, Any, Dict, List - -import build_buy -from civic_policies.street_civic_policy_service import StreetService -from s4ap.sims4communitylib.classes.math.common_location import CommonLocation -from s4ap.sims4communitylib.classes.math.common_surface_identifier import CommonSurfaceIdentifier -from s4ap.sims4communitylib.classes.math.common_vector3 import CommonVector3 -from s4ap.sims4communitylib.enums.common_region_id import CommonRegionId -from world.region import Region -from world.street import Street - -try: - import _buildbuy -except ImportError: - # noinspection SpellCheckingInspection - _buildbuy = build_buy -from sims4.resources import Types -from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils -from venues.venue_tuning import Venue, VenueTypes -from world.lot import Lot -from zone import Zone -from zone_modifier.zone_modifier import ZoneModifier - - -class CommonLocationUtils: - """Utilities for manipulating locations and lots. - - To manipulate the location of Sims, see :class:`.CommonSimLocationUtils`. - To manipulate the location of Objects, see :class:`.CommonObjectLocationUtils`. - - """ - - @classmethod - def get_current_region(cls) -> Region: - """get_current_region() - - Retrieve the current region. - - :return: The current region. - :rtype: Region - """ - return services.current_region() - - @classmethod - def get_current_region_id(cls) -> int: - """get_current_region_id() - - Retrieve the id of the current region. - - :return: The id of the current region. - :rtype: int - """ - region = cls.get_current_region() - return cls.get_region_id(region) - - @classmethod - def get_region_id(cls, region: Region) -> int: - """get_region_id(region) - - Retrieve the id of a region. - - :return: The id of a region. - :rtype: int - """ - if region is None: - return 0 - return getattr(region, 'guid64', 0) - - @classmethod - def is_current_region(cls, region: Union[int, CommonRegionId, Region]) -> bool: - """is_current_region(region) - - Determine if a region is the current one. - - :param region: The region to check. - :type region: Union[int, CommonRegionId, Region] - :return: True, if the specified region is the current one. False, if not. - :rtype: bool - """ - region = cls.load_region_by_id(region) - if region is None: - return False - return region == cls.get_current_region() - - @classmethod - def load_region_by_id(cls, region: Union[int, CommonRegionId, Region]) -> Union[Region, None]: - """load_region_by_id(region) - - Load an instance of a Region by its identifier. - - :param region: The identifier of a Region. - :type region: Union[int, CommonRegionId, Region] - :return: An instance of a Region matching the decimal identifier or None if not found. - :rtype: Union[Region, None] - """ - if region is None: - return None - if isinstance(region, Region): - return region - # noinspection PyBroadException - try: - # noinspection PyCallingNonCallable - region_instance = region() - if isinstance(region_instance, Region): - # noinspection PyTypeChecker - return region - except: - pass - # noinspection PyBroadException - try: - region: int = int(region) - except: - # noinspection PyTypeChecker - region: Region = region - return region - - from sims4.resources import Types - from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils - return CommonResourceUtils.load_instance(Types.REGION, region) - - @staticmethod - def get_lot_corners(lot: Lot) -> Tuple[Any]: - """get_lot_corners(lot) - - Retrieve the corners of a Lot. - - :return: A collection of corners of the specified Lot. - :rtype: Tuple[Any] - """ - return tuple(lot.corners) - - @staticmethod - def get_lot_corners_of_current_lot() -> Tuple[Any]: - """get_lot_corners_of_current_lot() - - Retrieve the corners of the current Lot. - - :return: A collection of corners on the current Lot. - :rtype: Tuple[Any] - """ - return CommonLocationUtils.get_lot_corners(CommonLocationUtils.get_current_lot()) - - @staticmethod - def get_zone_id(zone: Zone) -> int: - """get_zone_id(zone) - - Retrieve the identifier of the specified Zone. - - :param zone: The Zone to get the identifier of. - :type zone: Zone - :return: The identifier of the specified Zone. - :rtype: int - """ - return zone.id - - @staticmethod - def get_zone(zone_id: int, allow_unloaded_zones: bool = False) -> Zone: - """get_zone(zone_id, allow_unloaded_zones=False) - - Retrieve the Zone matching an identifier. - - :param zone_id: The decimal identifier of a Zone. - :type zone_id: int - :param allow_unloaded_zones: If set to True, Zones that are currently not loaded (or have not been loaded) will be considered. If set to False, Zones that have yet to be loaded will not be considered. Default is False. - :type allow_unloaded_zones: bool, optional - :return: The Zone with the specified zone id or None if it was not found. - :rtype: Zone - """ - return services.get_zone(zone_id, allow_uninstantiated_zones=allow_unloaded_zones) - - @staticmethod - def get_zone_lot(zone: Zone) -> Union[Lot, None]: - """get_zone_lot(zone) - - Retrieve the lot of a Zone. - - :param zone: An instance of a Zone. - :type zone: Zone - :return: The Lot within the specified Zone or None if a problem occurs. - :rtype: Union[Lot, None] - """ - if zone is None: - return None - return zone.lot - - @staticmethod - def get_current_zone_plex_id() -> int: - """get_current_zone_plex_id() - - Retrieve the plex id of the current zone. - - .. note:: A plex id is basically a Room location. - - :return: The ID of the current zone plex or 0 if the current zone does not have a plex id. - :rtype: int - """ - from services import get_plex_service - return get_plex_service().get_active_zone_plex_id() or 0 - - @staticmethod - def get_plex_id_for_zone(zone: Zone) -> int: - """get_plex_id_for_zone(zone) - - Retrieve the plex id for a Zone. - - :return: The Plex ID of the specified zone or -1 if it was not found. - :rtype: int - """ - zone_id = CommonLocationUtils.get_zone_id(zone) - return CommonLocationUtils.get_plex_id(zone_id) - - @staticmethod - def get_plex_id(zone_id: int) -> int: - """get_plex_id(zone_id) - - Retrieve the plex id of a Zone. - - :return: The Plex ID of the specified zone or 0 if it was not found. - :rtype: int - """ - plex_service = services.get_plex_service() - if zone_id not in plex_service._zone_to_master_map: - return 0 - (_, plex_id) = plex_service._zone_to_master_map[zone_id] - if plex_id == -1: - return 0 - return plex_id - - @staticmethod - def get_all_block_ids(zone_id: int) -> Tuple[int]: - """get_all_block_ids(zone_id) - - Retrieve a collection of all Block ids for a Zone. - - :param zone_id: The id of the Zone to retrieve the block ids of. - :type zone_id: int - :return: A collection of block ids. - :rtype: Tuple[int] - """ - plex_id = CommonLocationUtils.get_plex_id(zone_id) - if plex_id == -1: - return tuple() - # noinspection PyArgumentList - return tuple(_buildbuy.get_all_block_polygons(zone_id, plex_id).keys()) - - @staticmethod - def get_block_id_in_zone(zone_id: int, position: CommonVector3, surface_level: int) -> int: - """get_block_id_in_zone(zone_id, position, level) - - Retrieve the id of the block containing the position within a specified Zone. - - .. note:: A Block is the same thing as a Room. This information can be used to determine which Room something is located in as well. - - .. note:: The entirety of Outside has a room id of 0. - - :param zone_id: The zone to search. - :type zone_id: int - :param position: An instance of a vector. - :type position: CommonVector3 - :param surface_level: The surface level of the position. - :type surface_level: int - :return: The id of the block containing the position. - :rtype: int - """ - return CommonLocationUtils.get_block_id(zone_id, position, surface_level) - - @staticmethod - def get_block_id_in_current_zone(position: CommonVector3, surface_level: int) -> int: - """get_block_id_in_current_zone(position, level) - - Retrieve the id of the block containing the position. - - .. note:: A Block is the same thing as a Room. This information can be used to determine which Room something is located in as well. - - .. note:: The entirety of Outside has a room id of 0. - - :param position: An instance of a vector. - :type position: CommonVector3 - :param surface_level: The surface level of the position. - :type surface_level: int - :return: The id of the block containing the position. - :rtype: int - """ - return CommonLocationUtils.get_block_id(CommonLocationUtils.get_current_zone_id(), position, surface_level) - - @staticmethod - def get_all_block_ids_in_current_zone() -> Tuple[int]: - """get_all_block_ids_in_current_zone() - - Retrieve a collection of all Block Identifiers for the current zone. - - .. note:: A Block Id is essentially an identifier for a Room. - - :return: A collection of block decimal identifiers. - :rtype: Tuple[int] - """ - return tuple(CommonLocationUtils.get_all_block_polygons_of_current_zone().keys()) - - @staticmethod - def get_all_block_polygons_of_current_zone() -> Dict[int, Tuple[Tuple[List[CommonVector3]]]]: - """get_all_block_polygons_of_current_zone() - - Retrieve all block polygons for the current Zone. - - :return: A dictionary of polygons for the current Zone with the Block Ids as the key. - :rtype: Dict[int, Tuple[Tuple[Polygon]]] - """ - # noinspection PyArgumentList - return _buildbuy.get_all_block_polygons(CommonLocationUtils.get_current_zone_id(), CommonLocationUtils.get_current_zone_plex_id()) - - @staticmethod - def get_all_block_polygons(zone_id: int) -> Dict[int, Tuple[Tuple[List[CommonVector3]]]]: - """get_all_block_polygons(zone_id) - - Retrieve all block polygons for a Zone. - - .. note:: A Block is essentially just a Room. - - :param zone_id: A decimal identifier of a Zone. - :type zone_id: int - :return: A collection of polygons for the specified Zone. - :rtype: Dict[int, Tuple[Tuple[List[CommonVector3]]]] - """ - plex_id = CommonLocationUtils.get_plex_id(zone_id) - if plex_id == -1: - return dict() - # noinspection PyArgumentList - return _buildbuy.get_all_block_polygons(zone_id, plex_id) - - @staticmethod - def get_block_id(zone_id: int, position: CommonVector3, surface_level: int) -> int: - """get_block_id(zone_id, position, surface_level) - - Retrieve the decimal identifier of the block containing the position. - - :param zone_id: The decimal identifier of a Zone. - :type zone_id: int - :param position: An instance of a vector. - :type position: CommonVector3 - :param surface_level: The surface level of the position. - :type surface_level: int - :return: A decimal identifier of the block containing the position. - :rtype: int - """ - return build_buy.get_block_id(zone_id, position, surface_level) - - @staticmethod - def get_lot_id(lot: Lot) -> int: - """get_lot_id(lot) - - Retrieve the decimal identifier of a Lot. - - :param lot: An instance of a Lot. - :type lot: Lot - :return: The decimal identifier of the specified lot or -1 if a problem occurs. - :rtype: int - """ - if lot is None: - return -1 - return lot.lot_id - - @staticmethod - def get_current_zone() -> Zone: - """get_current_zone() - - Retrieve the current zone. - - :return: The current Zone - :rtype: Zone - """ - return services.current_zone() - - @staticmethod - def get_current_zone_id() -> int: - """get_current_zone_id() - - Retrieve the current zone id. - - :return: The identifier of the current Zone. - :rtype: int - """ - return services.current_zone_id() - - @staticmethod - def get_current_lot() -> Lot: - """get_current_lot() - - Retrieve the current lot. - - :return: The current Lot. - :rtype: Lot - """ - return services.active_lot() - - @staticmethod - def get_current_lot_id() -> int: - """get_current_lot_id() - - Retrieve the decimal identifier of the current Lot. - - :return: The decimal identifier of the current Lot or -1 if a problem occurs. - :rtype: int - """ - return services.active_lot_id() or -1 - - @staticmethod - def is_location_outside_current_lot(location: CommonLocation) -> bool: - """is_location_outside_current_lot(location) - - Determine if a location is outside of the current lot or not. - - :param location: The Location to check. - :type location: CommonLocation - :return: True, if the location is outside of the current lot. False, if not. - :rtype: bool - """ - return CommonLocationUtils.is_location_outside_lot(location, CommonLocationUtils.get_current_zone_id()) - - @staticmethod - def is_location_outside_lot(location: CommonLocation, zone_id: int) -> bool: - """is_location_outside_lot(location, lot_id) - - Determine if a location is outside of the Lot with the specified identifier. - - :param location: The Location to check. - :type location: CommonLocation - :param zone_id: The identifier of a Zone to check for the Location to be outside of. - :type zone_id: int - :return: True, if location is outside of the Lot with the specified lot_id. False, if not. - :rtype: bool - """ - try: - # noinspection PyTypeChecker,PyArgumentList - return _buildbuy.is_location_outside(zone_id, location.transform.translation, location.routing_surface.secondary_id) - except RuntimeError: - return False - - @staticmethod - def is_position_on_current_lot(position: CommonVector3) -> bool: - """is_position_on_current_lot(position) - - Determine if a sim is on the current lot. - - :param position: The position to check. - :type position: CommonVector3 - :return: True, if the specified position is within the bounds of the current lot. False, if not. - :rtype: bool - """ - return position is not None and services.active_lot().is_position_on_lot(position) - - @staticmethod - def is_position_within_range_of_position(position_a: CommonVector3, position_b: CommonVector3, distance_in_squares: float) -> bool: - """is_position_within_range_of_position(position_a, position_b, distance_in_squares) - - Determine if Position A is within a certain distance of Position B. - - :param position_a: The first position. - :type position_a: CommonVector3 - :param position_b: The second position. - :type position_b: CommonVector3 - :param distance_in_squares: A unit measured in squares. 1 square is the size of 1 square in the Build/Buy mode visual grid. For comparison, a dining chair would be 1 square by 1 square. 0.5 would be half a square, or half a dining chair. - :type distance_in_squares: float - :return: True, if the distance between Position A and Position B is less than or equal to the specified distance in squares. False, if not. - :return: bool - """ - from s4ap.sims4communitylib.utils.common_math_utils import CommonMathUtils - distance_between_positions = CommonMathUtils.calculate_distance(position_a, position_b, flatten_positions=False) - return distance_between_positions <= distance_in_squares - - @staticmethod - def is_location_within_range_of_location(location_a: CommonLocation, location_b: CommonLocation, distance_in_squares: float) -> bool: - """is_location_within_range_of_location(location_a, location_b, distance_in_squares) - - Determine if Location A is within a certain distance of Location B. - - :param location_a: The first location. - :type location_a: CommonLocation - :param location_b: The second location. - :type location_b: CommonLocation - :param distance_in_squares: A unit measured in squares. 1 square is the size of 1 square in the Build/Buy mode visual grid. For comparison, a dining chair would be 1 square by 1 square. 0.5 would be half a square, or half a dining chair. - :type distance_in_squares: float - :return: True, if the distance between Location A and Location B is less than or equal to the specified distance in squares. False, if not. - :return: bool - """ - position_a = location_a.transform.translation - position_b = location_b.transform.translation - return CommonLocationUtils.is_position_within_range_of_position(position_a, position_b, distance_in_squares) - - @staticmethod - def get_lot_traits(zone_id: int) -> Tuple[ZoneModifier]: - """get_lot_traits(lot_id) - - Retrieve the Lot Traits of a Lot with the specified identifier. - - :param zone_id: The lot to retrieve the traits of. - :type zone_id: int - :return: A collection of Lot Traits for the specified lot. - :rtype: Tuple[ZoneModifier] - """ - return tuple(services.get_zone_modifier_service().get_zone_modifiers(zone_id)) - - @staticmethod - def get_lot_traits_of_current_lot() -> Tuple[ZoneModifier]: - """get_lot_traits_of_current_lot() - - Retrieve the Lot Traits of the Current Lot. - - :return: A collection of Lot Traits for the current lot. - :rtype: Tuple[ZoneModifier] - """ - return CommonLocationUtils.get_lot_traits(CommonLocationUtils.get_current_zone_id()) - - @staticmethod - def current_lot_has_trait(lot_trait_id: int) -> bool: - """current_lot_has_trait(lot_trait_id) - - Determine if the Current Lot has the specified Lot Trait. - - :param lot_trait_id: The trait to look for. - :type lot_trait_id: int - :return: True, if the current lot has the specified trait. False, if not. - :rtype: bool - """ - return CommonLocationUtils.lot_has_trait(CommonLocationUtils.get_current_zone_id(), lot_trait_id) - - @staticmethod - def current_lot_has_any_traits(lot_trait_ids: Tuple[int]) -> bool: - """current_lot_has_any_traits(lot_trait_ids) - - Determine if the Current Lot has any of the specified Lot Traits. - - :param lot_trait_ids: A collection of traits to look for. - :type lot_trait_ids: Tuple[int] - :return: True, if the current lot has any of the specified traits. False, if not. - :rtype: bool - """ - return CommonLocationUtils.lot_has_any_traits(CommonLocationUtils.get_current_zone_id(), lot_trait_ids) - - @staticmethod - def current_lot_has_all_traits(lot_trait_ids: Tuple[int]) -> bool: - """current_lot_has_all_traits(lot_trait_ids) - - Determine if the Current Lot has all of the specified Lot Traits. - - :param lot_trait_ids: A collection of traits to look for. - :type lot_trait_ids: Tuple[int] - :return: True, if the current lot has all of the specified traits. False, if not. - :rtype: bool - """ - return CommonLocationUtils.lot_has_all_traits(CommonLocationUtils.get_current_zone_id(), lot_trait_ids) - - @staticmethod - def lot_has_trait(zone_id: int, lot_trait_id: int) -> bool: - """lot_has_trait(zone_id, lot_trait_id) - - Determine if a Lot has the specified Lot Trait. - - :param zone_id: The identifier of the zone to check. - :type zone_id: int - :param lot_trait_id: The trait to look for. - :type lot_trait_id: int - :return: True, if the specified lot has the specified trait. False, if not. - :rtype: bool - """ - return CommonLocationUtils.lot_has_all_traits(zone_id, (lot_trait_id,)) - - @staticmethod - def lot_has_any_traits(zone_id: int, lot_trait_ids: Tuple[int]) -> bool: - """lot_has_any_traits(zone_id, lot_trait_ids) - - Determine if a Lot has any of the specified Lot Traits. - - :param zone_id: The identifier of the zone to check. - :type zone_id: int - :param lot_trait_ids: A collection of traits to look for. - :type lot_trait_ids: Tuple[int] - :return: True, if the specified lot has any of the specified traits. False, if not. - :rtype: bool - """ - target_lot_trait_ids = [getattr(lot_trait, 'guid64', None) for lot_trait in CommonLocationUtils.get_lot_traits(zone_id)] - for lot_trait_id in lot_trait_ids: - if lot_trait_id in target_lot_trait_ids: - return True - return False - - @staticmethod - def lot_has_all_traits(zone_id: int, lot_trait_ids: Tuple[int]) -> bool: - """lot_has_all_traits(zone_id, lot_trait_ids) - - Determine if a Lot has all of the specified Lot Traits. - - :param zone_id: The identifier of the zone to check. - :type zone_id: int - :param lot_trait_ids: A collection of traits to look for. - :type lot_trait_ids: Tuple[int] - :return: True, if the specified lot has all of the specified traits. False, if not. - :rtype: bool - """ - target_lot_trait_ids = [getattr(lot_trait, 'guid64', None) for lot_trait in CommonLocationUtils.get_lot_traits(zone_id)] - if not target_lot_trait_ids: - return False - for lot_trait_id in lot_trait_ids: - if lot_trait_id in target_lot_trait_ids: - continue - return False - return True - - @classmethod - def get_current_venue(cls) -> Venue: - """get_current_venue() - - Retrieve the current venue. - - :return: The current venue. - :rtype: Venue - """ - return services.get_current_venue() - - @classmethod - def get_current_venue_id(cls) -> int: - """get_current_venue_id() - - Retrieve the id of the current venue. - - :return: The id of the current venue. - :rtype: int - """ - venue = cls.get_current_venue() - return cls.get_venue_id(venue) - - @classmethod - def get_venue_id(cls, venue: Venue) -> int: - """get_venue_id(venue) - - Retrieve the id of a venue. - - :return: The id of a venue. - :rtype: int - """ - if venue is None: - return 0 - return getattr(venue, 'guid64', 0) - - @classmethod - def load_venue_by_guid(cls, venue: Union[int, Venue]) -> Union[Venue, None]: - """load_venue_by_guid(venue) - - Load an instance of a Region by its identifier. - - :param venue: The identifier of a Venue. - :type venue: Union[int, Venue] - :return: An instance of a Venue matching the decimal identifier or None if not found. - :rtype: Union[Venue, None] - """ - if venue is None: - return None - if isinstance(venue, Venue): - return venue - # noinspection PyBroadException - try: - # noinspection PyCallingNonCallable - venue_instance = venue() - if isinstance(venue_instance, Venue): - # noinspection PyTypeChecker - return venue - except: - pass - # noinspection PyBroadException - try: - venue: int = int(venue) - except: - # noinspection PyTypeChecker - venue: Venue = venue - return venue - - from sims4.resources import Types - from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils - return CommonResourceUtils.load_instance(Types.VENUE, venue) - - @classmethod - def get_current_venue_type(cls) -> VenueTypes: - """get_current_venue_type() - - Retrieve the type of the current venue. - - :return: The VenueType of the current lot. - :rtype: VenueTypes - """ - return cls.get_venue_type_by_zone_id(CommonLocationUtils.get_current_zone_id()) - - @classmethod - def get_venue_of_current_lot(cls) -> Venue: - """get_venue_of_current_lot() - - Retrieve a Venue for the current lot. - - :return: The Venue of the current lot. - :rtype: Venue - """ - return cls.get_venue_by_zone_id(CommonLocationUtils.get_current_zone_id()) - - @classmethod - def get_venue_type_by_zone_id(cls, zone_id: int) -> VenueTypes: - """get_venue_type_by_zone_id() - - Retrieve the Venue type of a Zone. - - :return: The VenueType of the specified Zone. - :rtype: VenueTypes - """ - return build_buy.get_current_venue(zone_id) - - @classmethod - def get_venue_by_zone_id(cls, zone_id: int) -> Venue: - """get_venue_by_zone_id(zone_id) - - Retrieve the Venue for a Zone. - - :param zone_id: The identifier of a Zone. - :type zone_id: int - :return: The Venue instance for the specified Zone. - :rtype: Venue - """ - return CommonResourceUtils.load_instance(Types.VENUE, cls.get_venue_type_by_zone_id(zone_id)) - - @staticmethod - def is_current_venue_residential() -> bool: - """is_current_venue_residential() - - Determine if a venue is residential. - - :return: True, if the venue of the current lot is residential. False, if not. - :rtype: bool - """ - venue_instance = CommonLocationUtils.get_venue_of_current_lot() - if venue_instance is None: - return False - # noinspection PyUnresolvedReferences - return venue_instance.residential - - @staticmethod - def current_venue_requires_player_greeting() -> bool: - """current_venue_requires_player_greeting() - - Determine if the current venue requires player greeting. - - :return: True, if the venue of the current lot requires the player to be greeted. False, if not. - :rtype: bool - """ - venue_instance = CommonLocationUtils.get_venue_of_current_lot() - if venue_instance is None: - return False - return venue_instance.requires_visitation_rights - - @staticmethod - def current_venue_allows_role_state_routing() -> bool: - """current_venue_allows_role_state_routing() - - Determine if the current venue allows routing for role states. - - :return: True, if the venue of the current lot allows routing by role state. False, if not. - :rtype: bool - """ - venue_instance = CommonLocationUtils.get_venue_of_current_lot() - if venue_instance is None: - return False - # noinspection PyUnresolvedReferences - return venue_instance.allow_rolestate_routing_on_navmesh - - @staticmethod - def is_position_on_lot(position: CommonVector3, lot: Lot) -> bool: - """is_position_on_lot(position, lot) - - Determine if a Position is located on a Lot. - - :param position: An instance of a CommonVector - :type position: CommonVector3 - :param lot: An instance of a Lot. - :type lot: Lot - :return: True, if the Sim is on the specified Lot. False, if not. - :rtype: bool - """ - return position is not None and lot.is_position_on_lot(position) - - @staticmethod - def can_location_be_routed_to(location: CommonLocation) -> bool: - """can_location_be_routed_to(location) - - Determine if a location can be routed to by a Sim. - - :param location: The location to check. - :type location: CommonLocation - :return: True, if the location can be routed to by a Sim. False, it not. - :rtype: bool - """ - return CommonLocationUtils.can_position_be_routed_to(location.transform.translation, location.routing_surface) - - @staticmethod - def can_position_be_routed_to(position: CommonVector3, surface_identifier: CommonSurfaceIdentifier) -> bool: - """can_position_be_routed_to(position, surface_identifier) - - Determine if a position and surface can be routed to by a Sim. - - :param position: The position to check. - :type position: CommonVector3 - :param surface_identifier: The surface to check. - :type surface_identifier: CommonSurfaceIdentifier - :return: True, if the position can be routed to by a Sim. False, it not. - :rtype: bool - """ - from routing import test_point_placement_in_navmesh - return test_point_placement_in_navmesh(surface_identifier, position) - - @staticmethod - def get_surface_height_at(x: float, z: float, routing_surface: CommonSurfaceIdentifier) -> float: - """get_surface_height_at(x, z, routing_surface) - - Calculate the height of a surface. - - :param x: The x position of the surface. - :type x: float - :param z: The z position of the surface. - :type z: float - :param routing_surface: The surface. - :type routing_surface: CommonSurfaceIdentifier - :return: The height of the surface. - :rtype: float - """ - # noinspection PyUnresolvedReferences - return services.terrain_service.terrain_object().get_routing_surface_height_at(x, z, routing_surface) - - @staticmethod - def get_current_zone_world_id() -> int: - """get_current_zone_world_id() - - Retrieve the world id of the current Zone. - - :return: The world id of the current Zone. - :rtype: int - """ - return CommonLocationUtils.get_zone_world_id(CommonLocationUtils.get_current_zone_id()) - - @staticmethod - def get_current_zone_world_description_id() -> int: - """get_current_zone_world_description_id() - - Retrieve the world description id of the current Zone. - - :return: The world description id of the current Zone. - :rtype: int - """ - return CommonLocationUtils.get_zone_world_description_id(CommonLocationUtils.get_current_zone_id()) - - @staticmethod - def get_zone_world_id(zone_id: int) -> int: - """get_zone_world_id(zone_id) - - Retrieve the world id of the a Zone. - - :param zone_id: The decimal identifier of a Zone. - :type zone_id: int - :return: The world id of the specified Zone. - :rtype: int - """ - return services.get_persistence_service().get_world_id_from_zone(zone_id) - - @staticmethod - def get_zone_world_description_id(zone_id: int) -> int: - """get_zone_world_description_id(zone_id) - - Retrieve the world description id of the a Zone. - - :param zone_id: The decimal identifier of a Zone. - :type zone_id: int - :return: The world description id of the the specified Zone. - :rtype: int - """ - return services.get_world_description_id(CommonLocationUtils.get_zone_world_id(zone_id)) - - @staticmethod - def apply_surface_level_to_position(position: CommonVector3, surface_identifier: CommonSurfaceIdentifier) -> CommonVector3: - """apply_surface_level_to_position(game_object, interaction_context=None) - - Get the position of the surface of an Object. - - :param position: The position to update. - :type position: CommonVector3 - :param surface_identifier: The surface identifier to apply. - :type surface_identifier: CommonSurfaceIdentifier - :return: The position with a surface level applied. - :rtype: CommonVector3 - """ - position = CommonVector3.from_vector3(position) - surface_identifier = CommonSurfaceIdentifier.from_surface_identifier(surface_identifier) - position = CommonVector3(position.x, CommonLocationUtils.get_surface_height_at(position.x, position.z, surface_identifier), position.z) - return CommonVector3.from_vector3(position) - - @classmethod - def get_current_world_id(cls) -> int: - """get_current_world_id() - - Retrieve the identifier of the World which the current Zone is in. - - :return: The identifier of the World which the current Zone is in. - :rtype: int - """ - return cls.get_world_id_by_zone_id(CommonLocationUtils.get_current_zone_id()) - - @classmethod - def get_world_id_by_zone_id(cls, zone_id: int) -> int: - """get_world_id_by_zone_id(zone_id) - - Retrieve the identifier of the World which a Zone is in. - - :param zone_id: The identifier of the zone to use. - :type zone_id: int - :return: The identifier of the World which a Zone is in. - :rtype: int - """ - return services.get_persistence_service().get_world_id_from_zone(zone_id) - - @classmethod - def get_street_service(cls) -> StreetService: - """get_street_service() - - Retrieve an instance of the street service. - - :return: An instance of the street service. - :rtype: StreetService - """ - return services.street_service() - - @classmethod - def get_street_of_current_zone(cls) -> Street: - """get_street_from_current_zone() - - Retrieve a Street instance using the current Zone. - - :return: The Street instance for the current Zone. - :rtype: Street - """ - return cls.get_street_by_zone_id(CommonLocationUtils.get_current_zone_id()) - - @classmethod - def get_street_by_zone_id(cls, zone_id: int) -> Street: - """get_street_by_zone_id(zone_id) - - Retrieve the Street instance for a Zone. - - :param zone_id: The identifier of the Zone to use. - :type zone_id: int - :return: The Street instance of the specified zone. - :rtype: Street - """ - from world.street import get_street_instance_from_zone_id - return get_street_instance_from_zone_id(zone_id) - - @classmethod - def get_street_by_world_id(cls, world_id: int) -> Street: - """get_street_by_world_id(world_id) - - Retrieve a Street instance using a World Id. - - :param world_id: The identifier of the World to use. - :type world_id: int - :return: The Street instance of the specified World. - :rtype: Street - """ - from world.street import get_street_instance_from_world_id - return get_street_instance_from_world_id(world_id) diff --git a/Scripts/s4ap/sims4communitylib/utils/location/common_terrain_utils.py b/Scripts/s4ap/sims4communitylib/utils/location/common_terrain_utils.py deleted file mode 100644 index e103846..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/location/common_terrain_utils.py +++ /dev/null @@ -1,14 +0,0 @@ -""" -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 -""" - -from s4ap.sims4communitylib.utils.terrain.common_terrain_location_utils import CommonTerrainLocationUtils as NewCommonTerrainLocationUtils - - -class CommonTerrainUtils(NewCommonTerrainLocationUtils): - """An obsolete utility for manipulating terrain location. Use CommonTerrainLocationUtils from s4ap.sims4communitylib.utils.terrain.common_terrain_location_utils instead.""" - pass diff --git a/Scripts/s4ap/sims4communitylib/utils/location/common_travel_utils.py b/Scripts/s4ap/sims4communitylib/utils/location/common_travel_utils.py deleted file mode 100644 index 987fa61..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/location/common_travel_utils.py +++ /dev/null @@ -1,80 +0,0 @@ -""" -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 -""" -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils - - -class CommonTravelUtils: - """Utilities for moving Sims around. - - """ - - @staticmethod - def get_travel_group_id(sim_info: SimInfo) -> int: - """get_travel_group_id(sim_info) - - Retrieve a decimal identifier for the Travel Group of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The decimal identifier of the Travel Group of the Sim or -1 if a problem occurs. - :rtype: int - """ - if sim_info is None: - return -1 - return sim_info.travel_group_id - - @staticmethod - def travel_to_lot(sim_info: SimInfo, lot_id: int): - """travel_to_lot(sim_info, lot_id) - - Travel with the specified Sim to the Lot with the specified identifier. - - :param sim_info: The Sim to travel with. - :type sim_info: SimInfo - :param lot_id: The identifier of the lot to travel to. - :type lot_id: int - """ - sim_info.send_travel_switch_to_zone_op(zone_id=lot_id) - - @staticmethod - def travel_to_zone(sim_info: SimInfo, zone_id: int): - """travel_to_zone(sim_info, zone_id) - - Travel with the specified Sim to a Zone. - - :param sim_info: The Sim to travel with. - :type sim_info: SimInfo - :param zone_id: The identifier of the zone to travel to. - :type zone_id: int - """ - sim_info.send_travel_switch_to_zone_op(zone_id=zone_id) - - @staticmethod - def travel_to_home_lot_of(sim_info: SimInfo): - """travel_to_home_lot_of(sim_info) - - Travel to the home lot of a Sim. - - :param sim_info: The owner of the home lot to travel to. - :type sim_info: SimInfo - """ - lot_id = CommonHouseholdUtils.get_household_zone_id(sim_info) - CommonTravelUtils.travel_to_lot(sim_info, lot_id) - - @staticmethod - def travel_to_home_lot_of_active_sim(sim_info: SimInfo): - """travel_to_home_lot_of_active_sim(sim_info) - - Travel with the specified Sim to the home lot of the Active Sim. - - :param sim_info: The Sim to travel with. - :type sim_info: SimInfo - """ - lot_id = CommonHouseholdUtils.get_household_home_zone_id(CommonHouseholdUtils.get_active_household()) - CommonTravelUtils.travel_to_lot(sim_info, lot_id) diff --git a/Scripts/s4ap/sims4communitylib/utils/math/__init__.py b/Scripts/s4ap/sims4communitylib/utils/math/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/math/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/utils/math/common_bitwise_utils.py b/Scripts/s4ap/sims4communitylib/utils/math/common_bitwise_utils.py deleted file mode 100644 index 162e2b7..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/math/common_bitwise_utils.py +++ /dev/null @@ -1,110 +0,0 @@ -""" -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 -""" -from typing import Union, Tuple, TypeVar - -from s4ap.sims4communitylib.enums.enumtypes.common_int_flags import CommonIntFlags -from s4ap.sims4communitylib.utils.common_collection_utils import CommonCollectionUtils - -CommonEnumFlagsTypeValueType = TypeVar('CommonEnumFlagsTypeValueType', int, CommonIntFlags) - - -class CommonBitwiseUtils: - """Utilities for performing bitwise operations, so you do not have to remember how they are done.""" - - @staticmethod - def add_flags(value: CommonEnumFlagsTypeValueType, flags: Union[CommonEnumFlagsTypeValueType, Tuple[CommonEnumFlagsTypeValueType]]) -> CommonEnumFlagsTypeValueType: - """add_flags(value, flags) - - Add Flags to a value. - - :param value: A flags enum or an integer. - :type value: CommonEnumFlagsTypeValueType - :param flags: A flags enum, an integer, or a collection of flags enums or integers. - :type flags: Union[CommonIntFlags, int, Tuple[CommonEnumFlagsTypeValueType]] - :return: The new value. - :rtype: CommonEnumFlagsTypeValueType - """ - if CommonCollectionUtils.is_collection(value): - for _flags in flags: - value = CommonBitwiseUtils.add_flags(value, _flags) - return value - return value | flags - - @staticmethod - def remove_flags(value: CommonEnumFlagsTypeValueType, flags: Union[CommonIntFlags, int, Tuple[CommonEnumFlagsTypeValueType]]) -> CommonEnumFlagsTypeValueType: - """remove_flags(value, flags) - - Remove Flags from a value. - - :param value: A flags enum or an integer. - :type value: CommonEnumFlagsTypeValueType - :param flags: A flags enum, an integer, or a collection of flags enums or integers. - :type flags: Union[CommonIntFlags, int, Tuple[CommonEnumFlagsTypeValueType]] - :return: The new value. - :rtype: CommonEnumFlagsTypeValueType - """ - if CommonCollectionUtils.is_collection(flags): - for _flags in flags: - value = CommonBitwiseUtils.remove_flags(value, _flags) - return value - return value & ~flags - - @staticmethod - def contains_all_flags(value: CommonEnumFlagsTypeValueType, flags: Union[CommonIntFlags, int, Tuple[CommonEnumFlagsTypeValueType]]) -> bool: - """contains_all_flags(value, flags) - - Determine if all of the Flags are found within a value. - - :param value: A flags enum or an integer. - :type value: CommonEnumFlagsTypeValueType - :param flags: A flags enum, an integer, or a collection of flags enums or integers. - :type flags: Union[CommonIntFlags, int, Tuple[CommonEnumFlagsTypeValueType]] - :return: True, if all of the specified Flags are found within the value. False, if not. - :rtype: bool - """ - if CommonCollectionUtils.is_collection(flags): - for _flags in flags: - if not CommonBitwiseUtils.contains_all_flags(value, _flags): - return False - return True - return flags == (flags & value) - - @staticmethod - def contains_any_flags(value: CommonEnumFlagsTypeValueType, flags: Union[CommonIntFlags, int, Tuple[CommonEnumFlagsTypeValueType]]) -> bool: - """contains_any_flags(value, flags) - - Determine if any of the Flags are found within a value. - - :param value: A flags enum or an integer. - :type value: CommonEnumFlagsTypeValueType - :param flags: A flags enum, an integer, or a collection of flags enums or integers. - :type flags: Union[CommonIntFlags, int, Tuple[CommonEnumFlagsTypeValueType]] - :return: True, if any of the specified Flags are found within the value. False, if not. - :rtype: bool - """ - if CommonCollectionUtils.is_collection(flags): - for _flags in flags: - if CommonBitwiseUtils.contains_any_flags(value, _flags): - return True - return False - return (flags & value) != 0 - - @staticmethod - def contains_no_flags(value: CommonEnumFlagsTypeValueType, flags: Union[CommonIntFlags, int, Tuple[CommonEnumFlagsTypeValueType]]) -> bool: - """contains_no_flags(value, flags) - - Determine if none of the Flags are found within a value. - - :param value: A flags enum or an integer. - :type value: CommonEnumFlagsTypeValueType - :param flags: A flags enum, an integer, or a collection of flags enums or integers. - :type flags: Union[CommonIntFlags, int, Tuple[CommonEnumFlagsTypeValueType]] - :return: True, if none of the specified Flags are found within the value. False, if not. - :rtype: bool - """ - return not CommonBitwiseUtils.contains_any_flags(value, flags) diff --git a/Scripts/s4ap/sims4communitylib/utils/misc/__init__.py b/Scripts/s4ap/sims4communitylib/utils/misc/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/misc/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/utils/misc/common_camera_utils.py b/Scripts/s4ap/sims4communitylib/utils/misc/common_camera_utils.py deleted file mode 100644 index 7c04438..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/misc/common_camera_utils.py +++ /dev/null @@ -1,141 +0,0 @@ -""" -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 -""" -from typing import Union - -from objects.game_object import GameObject -from server.client import Client -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.classes.math.common_vector3 import CommonVector3 -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ - CommonConsoleCommandArgument -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - - -class CommonCameraUtils: - """ Utilities for controlling the camera. """ - @classmethod - def start_focus(cls, target: Union[SimInfo, GameObject, CommonVector3], follow: bool=True, client: Client=None) -> bool: - """start_focus(target, follow=True, client=None) - - Focus the player camera on something. - - :param target: The Target SimInfo, Game Object, or Position to focus the camera on. - :type target: Union[Sim, GameObject, CommonVector3] - :param follow: If True, the camera will follow the object after focusing on it. If False, the camera will not follow the object after focusing on it. Default is True. - :type follow: bool, optional - :param client: The client to focus on the Sim. If None, the active client will be used. Default is None. - :type client: Client, optional - :return: True, if the camera was focused on the specified target. - """ - if CommonTypeUtils.is_sim_or_sim_info(target): - cls.start_focus_on_sim(target, follow=follow, client=client) - elif CommonTypeUtils.is_game_object(target): - cls.start_focus_on_object(target, follow=follow) - elif isinstance(target, CommonVector3): - cls.start_focus_on_position(target, client=client) - else: - return False - return True - - @classmethod - def start_focus_on_sim(cls, sim_info: SimInfo, follow: bool=True, client: Client=None) -> None: - """start_focus_on_sim(sim_info, follow=True, client=None) - - Focus the player camera on a Sim. - - :param sim_info: The SimInfo of the Sim to focus the camera on. - :type sim_info: SimInfo - :param follow: If True, the camera will follow the object after focusing on it. If False, the camera will not follow the object after focusing on it. Default is True. - :type follow: bool, optional - :param client: The client to focus on the Sim. If None, the active client will be used. Default is None. - :type client: Client, optional - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return - from camera import focus_on_sim - focus_on_sim(sim=sim, follow=follow, client=client) - - @classmethod - def start_focus_on_position(cls, position: CommonVector3, client: Client=None) -> None: - """start_focus_on_position(position, client=None) - - Focus the player camera on a position. - - :param position: The position to focus the camera on. - :type position: CommonVector3 - :param client: The client to focus on the position. If None, the active client will be used. Default is None. - :type client: Client, optional - """ - from camera import focus_on_position - focus_on_position(position, client=client) - - @classmethod - def start_focus_on_object(cls, game_object: GameObject, follow: bool=True) -> None: - """start_focus_on_object(game_object, follow=True) - - Focus the player camera on a game object. - - :param game_object: The object to focus on. - :type game_object: GameObject - :param follow: If True, the camera will follow the object after focusing on it. If False, the camera will not follow the object after focusing on it. Default is True. - :type follow: bool, optional - """ - from camera import focus_on_object - focus_on_object(object=game_object, follow=follow) - - @classmethod - def stop_focus_on_object(cls, game_object: GameObject): - """stop_focus_on_object(game_object) - - Stop focusing the player camera on a game object. - - :param game_object: The object to stop focusing on. - :type game_object: GameObject - """ - from camera import cancel_focus - cancel_focus(object=game_object) - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.focus_on_object', - 'Move the camera to focus on an object.', - command_arguments=( - CommonConsoleCommandArgument('game_object', 'Game Object Id', 'The instance id of the object to focus on.'), - ) -) -def _common_focus_on_object_command(output: CommonConsoleCommandOutput, game_object: GameObject): - if game_object is None: - return - output(f'Attempting to focus the camera on object {game_object}.') - if CommonCameraUtils.start_focus(game_object): - output(f'SUCCESS: Successfully focused the camera on object {game_object}.') - else: - output(f'FAILED: Failed to focus the camera on object {game_object}.') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.focus_on_sim', - 'Move the camera to focus on a Sim.', - command_arguments=( - CommonConsoleCommandArgument('sim_info', 'Sim Name or Id', 'The instance id of the Sim to focus on.'), - ) -) -def _common_focus_on_sim_command(output: CommonConsoleCommandOutput, sim_info: SimInfo): - if sim_info is None: - return - output(f'Attempting to focus the camera on Sim {sim_info}.') - if CommonCameraUtils.start_focus(sim_info): - output(f'SUCCESS: Successfully focused the camera on Sim {sim_info}.') - else: - output(f'FAILED: Failed to focus the camera on Sim {sim_info}.') diff --git a/Scripts/s4ap/sims4communitylib/utils/misc/common_fire_utils.py b/Scripts/s4ap/sims4communitylib/utils/misc/common_fire_utils.py deleted file mode 100644 index 78bed94..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/misc/common_fire_utils.py +++ /dev/null @@ -1,134 +0,0 @@ -""" -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 -""" -from typing import Union, Tuple - -from objects.fire.fire import Fire -from objects.game_object import GameObject -from services.fire_service import FireService -from s4ap.sims4communitylib.classes.math.common_location import CommonLocation - - -class CommonFireUtils: - """Utilities for manipulating fires.""" - - @classmethod - def has_active_fires(cls) -> bool: - """has_active_fires() - - Determine if Fires are currently blazing. - - :return: True, if fires are currently blazing somewhere. False, if not. - :rtype: bool - """ - fire_service = cls.get_fire_service() - if fire_service is None: - return False - return fire_service.fire_is_active - - @classmethod - def get_all_active_fires(cls) -> Tuple[Fire]: - """get_all_active_fires() - - Retrieve an instance of all active Fires. - - :return: A collection of fires currently active. - :rtype: Tuple[Fire] - """ - fire_service = cls.get_fire_service() - if fire_service is None: - return tuple() - return fire_service.fire_is_active - - @classmethod - def spawn_scorch_marks_at_location(cls, location: CommonLocation) -> bool: - """spawn_scorch_marks_at_location(location) - - Spawn scorch marks at a location. - - :param location: The location to spawn the scorch marks at. - :type location: CommonLocation - :return: True, if scorch marks were spawned successfully. False, if not. - :rtype: bool - """ - fire_service = cls.get_fire_service() - if fire_service is None: - return False - position = location.transform.translation - surface_id = location.routing_surface.secondary_id - return fire_service.add_scorch_mark(position, surface_id) - - @classmethod - def despawn_scorch_marks_at_location(cls, location: CommonLocation) -> bool: - """despawn_scorch_marks_at_location(location) - - Despawn scorch marks at a location. - - :param location: The location to despawn the scorch marks at. - :type location: CommonLocation - :return: True, if scorch marks were despawned successfully. False, if not. - :rtype: bool - """ - fire_service = cls.get_fire_service() - if fire_service is None: - return False - position = location.transform.translation - surface_id = location.routing_surface.secondary_id - return fire_service.remove_scorch_mark(position, surface_id) - - @classmethod - def is_fire_allowed_at_location(cls, location: CommonLocation, run_placement_tests: bool = True) -> bool: - """is_fire_allowed_at_location(location, run_placement_tests=True) - - Determine if Fires are allowed to be placed at a Location. - - :param location: The location to check. - :type location: CommonLocation - :param run_placement_tests: Set True to run placement tests for the fire. Set False to exclude running placement tests for the fire. Default is True. - :type run_placement_tests: bool, optional - :return: True, if fire can be spawned as the specified location. False, if not. - :rtype: bool - """ - transform = location.transform - routing_surface = location.routing_surface - fire_service = cls.get_fire_service() - if fire_service is None: - return False - return fire_service.is_fire_allowed(transform, routing_surface, run_placement_tests=run_placement_tests) - - @classmethod - def spawn_fires_on_object(cls, game_object: GameObject, number_of_fires: int = 1) -> bool: - """spawn_fires_on_object(game_object, number_of_fires=1) - - Spawn a number of fires on an object. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :param number_of_fires: The number of fires to spawn on the Object. Must be above zero. Default is 1. - :type number_of_fires: int, optional - :return: True, if fires have been spawned successfully. False, if not. - :rtype: bool - """ - if number_of_fires <= 0: - raise AssertionError('The number of fires to spawn must be above zero.') - fire_service = cls.get_fire_service() - if fire_service is None: - return False - fire_service.spawn_fire_at_object(game_object) - return True - - @classmethod - def get_fire_service(cls) -> Union[FireService, None]: - """get_fire_service() - - Retrieve the service that manages Fires. - - :return: A service that manages fires or None if not found. - :rtype: Union[FireService, None] - """ - import services - return services.get_fire_service() diff --git a/Scripts/s4ap/sims4communitylib/utils/misc/common_game_client_utils.py b/Scripts/s4ap/sims4communitylib/utils/misc/common_game_client_utils.py deleted file mode 100644 index bb10857..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/misc/common_game_client_utils.py +++ /dev/null @@ -1,104 +0,0 @@ -""" -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 -""" -from typing import Union - -import services -from server.client import Client -from server.clientmanager import ClientManager -from sims.household import Household - - -class CommonGameClientUtils: - """ Utilities for getting information about the game client. """ - - @staticmethod - def get_first_game_client() -> Union[Client, None]: - """get_first_game_client() - - Retrieve an instance of the first available Game Client. - - :return: An instance of the first available Game Client or None if not found. - :rtype: Union[Client, None] - """ - client_manager = CommonGameClientUtils.get_game_client_manager() - if client_manager is None: - return None - return client_manager.get_first_client() - - @staticmethod - def get_first_game_client_id() -> Union[int, None]: - """get_first_game_client_id() - - Retrieve the id of the first available Game Client. - - :return: The id of the first available Game Client or None if not found. - :rtype: Union[int, None] - """ - client_manager = CommonGameClientUtils.get_game_client_manager() - if client_manager is None: - return None - return client_manager.get_first_client_id() - - @staticmethod - def get_game_client_by_household(household: Household) -> Union[Client, None]: - """get_game_client_by_household(household) - - Locate a Game Client by a Household. - - :return: The Game Client that matches the specified Household or None if not found. - :rtype: Union[Client, None] - """ - if household is None: - return None - client_manager = CommonGameClientUtils.get_game_client_manager() - if client_manager is None: - return None - return client_manager.get_client_by_household(household) - - @staticmethod - def get_game_client_by_household_id(household_id: int) -> Union[Client, None]: - """get_game_client_by_household_id(household_id) - - Locate a Game Client by a Household Id. - - :return: The Game Client that matches the specified Household Id or None if not found. - :rtype: Union[Client, None] - """ - if household_id is None: - return None - client_manager = CommonGameClientUtils.get_game_client_manager() - if client_manager is None: - return None - return client_manager.get_client_by_household_id(household_id) - - @staticmethod - def get_game_client_by_account_id(account_id: int) -> Union[Client, None]: - """get_game_client_by_account_id(account_id) - - Locate a Game Client by an Account Id. - - :return: The Game Client that matches the specified Account Id or None if not found. - :rtype: Union[Client, None] - """ - if account_id is None: - return None - client_manager = CommonGameClientUtils.get_game_client_manager() - if client_manager is None: - return None - return client_manager.get_client_by_account(account_id) - - @staticmethod - def get_game_client_manager() -> ClientManager: - """get_game_client_manager() - - Retrieve the manager that manages the Game Clients for the game. - - :return: The manager that manages the Game Clients for the game. - :rtype: ClientManager - """ - return services.client_manager() diff --git a/Scripts/s4ap/sims4communitylib/utils/misc/common_mod_identity_utils.py b/Scripts/s4ap/sims4communitylib/utils/misc/common_mod_identity_utils.py deleted file mode 100644 index f7f18eb..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/misc/common_mod_identity_utils.py +++ /dev/null @@ -1,37 +0,0 @@ -""" -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 -""" -from typing import Union, TYPE_CHECKING - -if TYPE_CHECKING: - from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity - - -class CommonModIdentityUtils: - """Utilities for manipulating CommonModIdentity. - - """ - @classmethod - def determine_mod_name_from_identifier(cls, identifier: Union[str, 'CommonModIdentity'], include_version: bool=True) -> str: - """determine_mod_name_from_identifier(mod_identifier, include_version=True) - - Determine the name of a Mod using a mod identifier. - - :param identifier: The identifier of a Mod. - :type identifier: Union[str, 'CommonModIdentity'] - :param include_version: If True and the identifier is a CommonModIdentity object, the version will be included in the mod name. If False, it will not be. - :return: The name of the Mod or 'Unknown_Mod' if the name could not be determined. - :rtype: str - """ - from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity - if identifier is None: - return 'Unknown_Mod' - if isinstance(identifier, CommonModIdentity): - return identifier.name.replace(' ', '_').replace(':', '_').replace('//', '_').replace('\\', '_') + (('_' + identifier.version.replace(':', '_').replace('//', '_').replace('\\', '_')) if identifier.version is not None and include_version else '') - if isinstance(identifier, str): - return identifier.replace(' ', '_').replace(':', '_').replace('//', '_').replace('\\', '_') - return str(identifier).replace(' ', '_').replace(':', '_').replace('//', '_').replace('\\', '_') diff --git a/Scripts/s4ap/sims4communitylib/utils/misc/common_text_utils.py b/Scripts/s4ap/sims4communitylib/utils/misc/common_text_utils.py deleted file mode 100644 index 1681a4c..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/misc/common_text_utils.py +++ /dev/null @@ -1,70 +0,0 @@ -""" -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 -""" - - -class CommonTextUtils: - """Utilities for manipulating text.""" - @staticmethod - def capitalize(value: str) -> str: - """capitalize(value) - - Capitalize the first character of a value. - - :param value: The value to modify. - :type value: str - :return: The text, but with the first character capitalized. - :rtype: str - """ - if not value: - return value - return value[:1].upper() + value[1:] - - @staticmethod - def proper_case_hex(hex_value: str) -> str: - """proper_case_hex(hex_value) - - Modify the casing of a hex value so that everything after the "0x" portion is capitalized. - - :param hex_value: The value to modify. - :type hex_value: str - :return: The value, but with everything after the "0x" portion capitalized. - :rtype: str - """ - if not hex_value: - return hex_value - return hex_value[:2] + hex_value[2:].upper() - - @staticmethod - def convert_to_hex32_string(value: int) -> str: - """convert_to_hex32_string(value) - - Convert a value into a 32 bit hexadecimal string. This function will keep any leading or trailing zeros. - - :param value: The value to convert. - :type value: int - :return: The value as a Hexadecimal string. - :rtype: str - """ - if value is None: - raise AssertionError('value was None!') - return f'0x{value:08X}' - - @staticmethod - def to_truncated_decimal(value: float, num_of_decimal_points: int = 2) -> str: - """to_truncated_decimal(value, num_of_decimal_points=2) - - Create a string of a float value with a number of decimal points truncated. - - :param value: The value to truncate. - :type value: float - :param num_of_decimal_points: The number of decimal places to leave in the string. Default is 2. - :type num_of_decimal_points: int, optional - :return: A string representation of the value truncated to the number of decimal places. - :rtype: str - """ - return f'{value:.{num_of_decimal_points}f}' diff --git a/Scripts/s4ap/sims4communitylib/utils/objects/__init__.py b/Scripts/s4ap/sims4communitylib/utils/objects/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/objects/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_household_utils.py b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_household_utils.py deleted file mode 100644 index dea711d..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_household_utils.py +++ /dev/null @@ -1,47 +0,0 @@ -""" -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 -""" -from objects.game_object import GameObject - - -class CommonObjectHouseholdUtils: - """Utilities for manipulating Household ownership of Objects. - - """ - - @staticmethod - def set_owning_household_id(game_object: GameObject, household_id: int) -> bool: - """set_owning_household_id(game_object, household_id) - - Set the Household that owns the Object. - .. note: THIS FUNCTION IS OBSOLETE PLEASE USE See :class:`.CommonObjectOwnershipUtils` for updated functions. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :param household_id: The decimal identifier of a Household. - :type household_id: int - :return: True, if the Household was successfully set as the owner. False, if not. - :rtype: bool - """ - from s4ap.sims4communitylib.utils.objects.common_object_ownership_utils import CommonObjectOwnershipUtils - return CommonObjectOwnershipUtils.set_owning_household_id(game_object, household_id) - - @staticmethod - def get_owning_household_id(game_object: GameObject) -> int: - """get_owning_household_id(game_object) - - Retrieve the decimal identifier of the Household that owns the Object. - - .. note: THIS FUNCTION IS OBSOLETE PLEASE USE See :class:`.CommonObjectOwnershipUtils` for updated functions. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: The decimal identifier of the Household that owns the object. - :rtype: int - """ - from s4ap.sims4communitylib.utils.objects.common_object_ownership_utils import CommonObjectOwnershipUtils - return CommonObjectOwnershipUtils.get_owning_household_id(game_object) diff --git a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_interaction_utils.py b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_interaction_utils.py deleted file mode 100644 index bebcd60..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_interaction_utils.py +++ /dev/null @@ -1,326 +0,0 @@ -""" -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 -""" -from pprint import pformat -from typing import Callable, Iterator, List, Union -from interactions.base.interaction import Interaction -from objects.game_object import GameObject -from objects.script_object import ScriptObject -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.logging.has_class_log import HasClassLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.notifications.common_basic_notification import CommonBasicNotification -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ - CommonConsoleCommandArgument -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.common_log_utils import CommonLogUtils -from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils -from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils -from s4ap.sims4communitylib.utils.resources.common_interaction_utils import CommonInteractionUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - - -class CommonObjectInteractionUtils(HasClassLog): - """Utilities for manipulating the interactions of Objects. - - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - return ModInfo.get_identity() - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 'common_object_interaction_utils' - - @staticmethod - def get_all_interactions_registered_to_object_gen(script_object: ScriptObject, include_interaction_callback: Callable[[Interaction], bool] = None) -> Iterator[Interaction]: - """get_all_interactions_registered_to_object_gen(script_object, include_interaction_callback=None) - - Retrieve all interactions that are registered to an object. - - :param script_object: An instance of a ScriptObject - :type script_object: ScriptObject - :param include_interaction_callback: If the result of this callback is True, the Interaction will be included in the results. If set to None, All Interactions will be included. Default is None. - :type include_interaction_callback: Callable[[Interaction], bool], optional - :return: An iterator of Interactions that pass the include callback filter. - :rtype: Iterator[Interaction] - """ - if script_object is None or not hasattr(script_object, '_super_affordances') or not script_object._super_affordances: - return tuple() - interactions = ( - *script_object._super_affordances, - ) - if hasattr(script_object, '_phone_affordances'): - interactions = ( - *interactions, - *script_object._phone_affordances - ) - if hasattr(script_object, '_relation_panel_affordances'): - interactions = ( - *interactions, - *script_object._relation_panel_affordances - ) - for interaction in interactions: - interaction: Interaction = interaction - if include_interaction_callback is not None and not include_interaction_callback(interaction): - continue - yield interaction - - @classmethod - def add_super_interaction_to_object(cls, script_object: ScriptObject, interaction_guid: int): - """add_super_interaction_to_object(script_object, interaction_guid) - - Add a super interaction to an object. - - :param script_object: The object to add the interaction to. - :type script_object: ScriptObject - :param interaction_guid: The GUID of the interaction to add. - :type interaction_guid: int - """ - return cls.add_super_interactions_to_object(script_object, (interaction_guid,)) - - @classmethod - def add_super_interactions_to_object(cls, script_object: ScriptObject, interaction_guids: Iterator[int]): - """add_super_interactions_to_object(script_object, interaction_guids) - - Add super interactions to an object. - - :param script_object: The object to add the interaction to. - :type script_object: ScriptObject - :param interaction_guids: The GUIDs of the interactions to add. - :type interaction_guids: Iterator[int] - """ - script_object_type = type(script_object) - cls.get_log().format_with_message('Adding interactions for type', script_object_type=script_object_type) - if not hasattr(script_object_type, '_super_affordances'): - cls.get_verbose_log().format_with_message('Object did not have super affordances.', script_object=script_object_type) - return - super_interactions_to_add = list() - affordance_manager = CommonInteractionUtils.get_instance_manager() - for affordance_id in interaction_guids: - affordance_instance = affordance_manager.get(affordance_id) - if affordance_instance is None: - continue - super_interactions_to_add.append(affordance_instance) - - new_super_affordances = list() - for super_interaction_instance in super_interactions_to_add: - if super_interaction_instance in new_super_affordances or super_interaction_instance in script_object_type._super_affordances: - cls.get_verbose_log().format_with_message('Interaction was already found in the interactions list.', script_object_type=script_object_type, interaction_instance=super_interaction_instance) - continue - new_super_affordances.append(super_interaction_instance) - if new_super_affordances: - cls.get_log().format_with_message('Adding super affordances to object.', script_object=script_object, script_object_type=script_object_type, new_super_affordances=new_super_affordances) - script_object_type._super_affordances += tuple(new_super_affordances) - else: - cls.get_log().format_with_message('No super affordances to add.', script_object=script_object, script_object_type=script_object_type, new_super_affordances=new_super_affordances) - - new_script_object_super_affordances = list() - for new_super_affordance in super_interactions_to_add: - if new_super_affordance in script_object._super_affordances: - continue - new_script_object_super_affordances.append(new_super_affordance) - if new_script_object_super_affordances: - script_object._super_affordances += tuple(new_script_object_super_affordances) - - @classmethod - def remove_super_interaction_from_terrain(cls, interaction_identifier: Union[int, Interaction]): - """remove_super_interaction_from_terrain(interaction_identifier) - - Remove a super interaction from the terrain. - - :param interaction_identifier: The GUID or instance of the interaction to remove. - :type interaction_identifier: Union[int, Interaction] - """ - return cls.remove_super_interactions_from_terrain((interaction_identifier,)) - - @classmethod - def remove_super_interactions_from_terrain(cls, interaction_identifiers: Iterator[Union[int, Interaction]]): - """remove_super_interactions_from_terrain(interaction_identifiers) - - Remove a super interaction from the terrain. - - :param interaction_identifiers: The GUIDs or instances of the interactions to remove. - :type interaction_identifiers: Iterator[Union[int, Interaction]] - """ - from services import get_terrain_service - terrain_service = get_terrain_service() - - interactions_to_remove = list() - for interaction_id in interaction_identifiers: - interaction = CommonInteractionUtils.load_interaction_by_id(interaction_id) - if interaction is not None: - interactions_to_remove.append(interaction) - - if not interactions_to_remove: - return None - - new_terrain_definition_class = terrain_service.TERRAIN_DEFINITION.cls - new_super_affordances = list() - current_super_affordances_list = list(new_terrain_definition_class._super_affordances) - for super_interaction in current_super_affordances_list: - if super_interaction in interactions_to_remove: - continue - new_super_affordances.append(super_interaction) - new_terrain_definition_class._super_affordances = tuple(new_super_affordances) - terrain_service.TERRAIN_DEFINITION.set_class(new_terrain_definition_class) - - @classmethod - def remove_super_interaction_from_ocean(cls, interaction_identifier: Union[int, Interaction]): - """remove_super_interaction_from_ocean(interaction_identifier) - - Remove a super interaction from the ocean. - - :param interaction_identifier: The GUID or instance of the interaction to remove. - :type interaction_identifier: Union[int, Interaction] - """ - return cls.remove_super_interactions_from_ocean((interaction_identifier,)) - - @classmethod - def remove_super_interactions_from_ocean(cls, interaction_identifiers: Iterator[Union[int, Interaction]]): - """remove_super_interactions_from_ocean(interaction_identifiers) - - Remove a super interaction from the ocean. - - :param interaction_identifiers: The GUIDs of the interactions or instances to remove. - :type interaction_identifiers: Iterator[Union[int, Interaction]] - """ - from services import get_terrain_service - terrain_service = get_terrain_service() - - interactions_to_remove = list() - for interaction_guid in interaction_identifiers: - interaction = CommonInteractionUtils.load_interaction_by_id(interaction_guid) - if interaction is not None: - interactions_to_remove.append(interaction) - - new_ocean_definition_class = terrain_service.OCEAN_DEFINITION.cls - new_super_affordances = list() - current_super_affordances_list = list(new_ocean_definition_class._super_affordances) - for super_interaction in current_super_affordances_list: - if super_interaction in interactions_to_remove: - continue - new_super_affordances.append(super_interaction) - new_ocean_definition_class._super_affordances = tuple(new_super_affordances) - terrain_service.OCEAN_DEFINITION.set_class(new_ocean_definition_class) - - @classmethod - def remove_super_interaction_from_object(cls, script_object: ScriptObject, interaction_guid: int): - """remove_super_interaction_from_object(script_object, interaction_guid) - - Remove a super interaction from an object. - - :param script_object: The object to remove the interaction from. - :type script_object: ScriptObject - :param interaction_guid: The GUID of the interaction to remove. - :type interaction_guid: int - """ - return cls.remove_super_interactions_from_object(script_object, (interaction_guid,)) - - @classmethod - def remove_super_interactions_from_object(cls, script_object: ScriptObject, interaction_guids: Iterator[int]): - """remove_super_interactions_from_object(script_object, interaction_guids) - - Remove a super interaction from an object. - - :param script_object: The object to remove the interaction from. - :type script_object: ScriptObject - :param interaction_guids: The GUIDs of the interactions to remove. - :type interaction_guids: Iterator[int] - """ - script_object_type = type(script_object) - cls.get_log().format_with_message('Removing interactions for type', script_object_type=script_object_type) - if not hasattr(script_object_type, '_super_affordances'): - cls.get_verbose_log().format_with_message('Object did not have super affordances.', script_object=script_object_type) - return - new_super_affordances = list(script_object_type._super_affordances) - current_super_affordances_list = list(script_object_type._super_affordances) - for super_interaction in current_super_affordances_list: - super_interaction_id = CommonInteractionUtils.get_interaction_id(super_interaction) - if super_interaction_id not in interaction_guids: - continue - new_super_affordances.remove(super_interaction) - script_object_type._super_affordances = tuple(new_super_affordances) - - new_object_super_affordances = list(script_object._super_affordances) - current_object_super_affordances_list = list(script_object._super_affordances) - for obj_super_interaction in current_object_super_affordances_list: - obj_super_interaction_id = CommonInteractionUtils.get_interaction_id(obj_super_interaction) - if obj_super_interaction_id not in interaction_guids: - continue - new_object_super_affordances.remove(obj_super_interaction) - script_object._super_affordances = tuple(new_object_super_affordances) - - @classmethod - def _log_all_interactions(cls, target_object: ScriptObject): - log = cls.get_log() - log.enable() - object_id = CommonObjectUtils.get_object_id(target_object) if target_object is not None else -1 - definition_id = -1 - if CommonTypeUtils.is_sim_or_sim_info(target_object): - # noinspection PyTypeChecker - object_id = CommonSimUtils.get_sim_id(target_object) - elif CommonTypeUtils.is_game_object(target_object): - # noinspection PyTypeChecker - definition = CommonObjectUtils.get_game_object_definition(target_object) - if definition is not None: - definition_id = definition.id - log.debug(f'Interactions that can be performed on \'{target_object}\' id:{object_id} def_id:{definition_id}:') - interactions = CommonObjectInteractionUtils.get_all_interactions_registered_to_object_gen(target_object) - # noinspection PyTypeChecker - target_object: GameObject = target_object - interaction_short_names: List[str] = list() - for interaction in interactions: - interaction: Interaction = interaction - try: - interaction_short_name = CommonInteractionUtils.get_interaction_short_name(interaction) - interaction_id = CommonInteractionUtils.get_interaction_id(interaction) - interaction_short_names.append(f'{interaction_short_name} ({interaction_id})') - except Exception as ex: - log.error('Problem while attempting to handle interaction {}'.format(pformat(interaction)), exception=ex) - continue - for component in target_object.components: - if not hasattr(component, 'component_super_affordances_gen'): - continue - for affordance in component.component_super_affordances_gen(): - try: - interaction_short_name = CommonInteractionUtils.get_interaction_short_name(affordance) - interaction_id = CommonInteractionUtils.get_interaction_id(affordance) - interaction_short_names.append(f'{interaction_short_name} ({interaction_id})') - except Exception as ex: - log.error(f'Problem while attempting to handle affordance {pformat(affordance)}', exception=ex) - continue - - sorted_short_names = sorted(interaction_short_names, key=lambda x: x) - log.format(interactions=sorted_short_names) - log.debug('Done Logging Available Interactions.') - log.disable() - CommonBasicNotification( - CommonStringId.S4CL_LOG_ALL_INTERACTIONS, - CommonStringId.S4CL_DONE_LOGGING_ALL_INTERACTIONS, - description_tokens=(CommonLogUtils.get_message_file_path(cls.get_mod_identity()), ) - ).show() - return True - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_testing.print_object_interactions', - 'Log all interactions an object has.', - command_arguments=( - CommonConsoleCommandArgument('game_object', 'Game Object Id', 'The instance id of the game object to check.'), - ) -) -def _s4clib_testing_print_all_interactions(output: CommonConsoleCommandOutput, game_object: GameObject): - if game_object is None: - return - output(f'Logging interactions of {game_object}') - CommonObjectInteractionUtils._log_all_interactions(game_object) diff --git a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_inventory_utils.py b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_inventory_utils.py deleted file mode 100644 index b66c87b..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_inventory_utils.py +++ /dev/null @@ -1,214 +0,0 @@ -""" -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 -""" -from typing import Callable, Iterator, Union -from interactions.base.create_object_interaction import ObjectDefinition -from objects.components.object_inventory_component import ObjectInventoryComponent -from objects.game_object import GameObject -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.classes.math.common_location import CommonLocation -from s4ap.sims4communitylib.enums.types.component_types import CommonComponentType -from s4ap.sims4communitylib.utils.common_component_utils import CommonComponentUtils -from s4ap.sims4communitylib.utils.objects.common_object_spawn_utils import CommonObjectSpawnUtils -from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils - - -class CommonObjectInventoryUtils: - """ Utilities for manipulating the inventory of Objects. """ - @staticmethod - def has_inventory(game_object: GameObject) -> bool: - """has_inventory(game_object) - - Determine if an Object has an inventory. - - :param game_object: An instance of a Game Object. - :type game_object: GameObject - :return: True, if the Sim has an inventory. False, if not. - :rtype: bool - """ - return CommonObjectInventoryUtils._get_inventory(game_object) is not None - - @staticmethod - def get_all_objects_in_inventory_gen(game_object: GameObject, include_object_callback: Callable[[GameObject], bool]=None) -> Iterator[GameObject]: - """get_all_objects_in_inventory_gen(game_object, include_object_callback=None) - - Retrieve all Objects in the inventory of an Object. - - :param game_object: An instance of a Game Object. - :type game_object: GameObject - :param include_object_callback: If the result of this callback is True, the object will be included in the results. If set to None, All objects in the inventory will be included. - :type include_object_callback: Callable[[int], bool], optional - :return: An iterator containing the decimal identifiers for the objects in the inventory of an Object. - :rtype: Iterator[GameObject] - """ - inventory_component: ObjectInventoryComponent = CommonObjectInventoryUtils._get_inventory(game_object) - if inventory_component is None: - return tuple() - if include_object_callback is None: - for inventory_object in inventory_component: - yield inventory_object - else: - for inventory_object in inventory_component: - if include_object_callback(inventory_object): - yield inventory_object - - @staticmethod - def move_object_to_inventory(game_object_container: GameObject, game_object_to_move: GameObject) -> bool: - """move_object_to_inventory(game_object_container, game_object_to_move) - - Move an Object to the inventory of an Object container. - - :param game_object_container: The Object container to receive the moved Object. - :type game_object_container: GameObject - :param game_object_to_move: The Object to move. - :type game_object_to_move: GameObject - :return: True, if the object was successfully moved to the inventory of the specified Object container. False, if not. - :rtype: bool - """ - if game_object_container is None or game_object_to_move is None: - return False - inventory_component = CommonObjectInventoryUtils._get_inventory(game_object_container) - if inventory_component is None: - return False - from s4ap.sims4communitylib.utils.objects.common_object_ownership_utils import CommonObjectOwnershipUtils - CommonObjectOwnershipUtils.set_owning_household_id(game_object_to_move, CommonObjectOwnershipUtils.get_owning_household_id(game_object_container)) - return inventory_component.player_try_add_object(game_object_to_move) - - @staticmethod - def add_to_inventory(game_object: GameObject, object_id: int, count: int=1) -> bool: - """add_to_inventory(game_object, object_definition_id, count=1) - - Add a number of Newly Created Objects to the Inventory of an Object. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :param object_id: The decimal identifier of an Object. - :type object_id: int - :param count: The number of the specified Object to add. Default is 1. - :type count: int, optional - :return: True, if the count of the specified Object were added successfully. False, it not. - :rtype: bool - """ - inventory_component: ObjectInventoryComponent = CommonObjectInventoryUtils._get_inventory(game_object) - if inventory_component is None: - return False - - def _post_create(_game_object: GameObject) -> bool: - return CommonObjectInventoryUtils.move_object_to_inventory(game_object, _game_object) - - success = True - for _ in range(count): - game_object = CommonObjectSpawnUtils.spawn_object_on_lot(object_id, CommonLocation.empty(), post_object_spawned_callback=_post_create) - if game_object is None: - success = False - return success - - @staticmethod - def remove_from_inventory_by_id(game_object: GameObject, object_id: int, count: int = 1) -> bool: - """remove_from_inventory_by_id(game_object, object_id, count=1) - - Remove a number of Objects by their Id from the inventory of an Object. - - :param game_object: The Object to remove Objects from. - :type game_object: GameObject - :param object_id: The decimal identifier of an Object. - :type object_id: int - :param count: The amount of the Object to remove. Default is 1. - :type count: int, optional - :return: True, if the count of the specified Object were removed successfully. False, if not. - """ - inventory_component: ObjectInventoryComponent = CommonObjectInventoryUtils._get_inventory(game_object) - if inventory_component is None: - return False - return inventory_component.try_remove_object_by_id(object_id, count=count) - - @staticmethod - def remove_from_inventory_by_definition(game_object: GameObject, object_definition: ObjectDefinition, count: int = 1) -> bool: - """remove_from_inventory(game_object, object_id, count=1) - - Remove a number of Objects from the inventory of an Object. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :param object_definition: The definition of an Object. - :type object_definition: ObjectDefinition - :param count: The amount of the Object to remove. Default is 1. - :type count: int, optional - :return: True, if the count of the specified Object were removed successfully. False, if not. - """ - def _include_object_callback(_game_object: GameObject) -> bool: - return _game_object.definition == object_definition - - inventory_objects = CommonObjectInventoryUtils.get_all_objects_in_inventory_gen(game_object, include_object_callback=_include_object_callback) - for inventory_object in inventory_objects: - object_id = CommonObjectUtils.get_object_id(inventory_object) - if CommonObjectInventoryUtils.remove_from_inventory_by_id(game_object, object_id, count=count): - return True - return False - - @staticmethod - def get_count_of_object_in_inventory(game_object: GameObject, object_id: int) -> int: - """get_count_of_object_in_inventory(game_object, object_id) - - Count the number of an Object in the inventory of an Object. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :param object_id: The decimal identifier of an object. - :type object_id: int - :return: The number of a particular Object found in the inventory of the specified Object. - :type: int - """ - inventory_component: ObjectInventoryComponent = CommonObjectInventoryUtils._get_inventory(game_object) - if inventory_component is None: - return 0 - object_definition = CommonObjectUtils.get_object_definition(object_id) - return inventory_component.get_count(object_definition) - - @staticmethod - def open_inventory(game_object: GameObject) -> None: - """open_inventory(game_object) - - Open the inventory of an Object. - - :param game_object: The Object to open the inventory of. - :type game_object: GameObject - """ - if game_object is None: - return - inventory_component: ObjectInventoryComponent = CommonObjectInventoryUtils._get_inventory(game_object) - if inventory_component is None: - return - inventory_component.open_ui_panel() - - @staticmethod - def set_ownership_of_all_items_in_object_inventory_to_sim(game_object: GameObject, sim_info: SimInfo) -> bool: - """set_ownership_of_all_items_in_object_inventory_to_sim(game_object, sim_info) - - Change the ownership status of all items in the inventory of an Object to be owned by the household of a Sim. - - :param game_object: The objects in the inventory of this Object will become owned by the household of the Sim - :type game_object: GameObject - :param sim_info: The household of this Sim will be the new owner for all items in the inventory of the Object. - :type sim_info: SimInfo - :return: True, if ownership was transferred successfully. False, if not. - :rtype: bool - """ - if game_object is None or sim_info is None: - return False - inventory_component: ObjectInventoryComponent = CommonObjectInventoryUtils._get_inventory(game_object) - if inventory_component is None: - return False - - from s4ap.sims4communitylib.utils.objects.common_object_ownership_utils import CommonObjectOwnershipUtils - for inventory_object in inventory_component: - CommonObjectOwnershipUtils.set_owning_sim(inventory_object, sim_info) - return True - - @staticmethod - def _get_inventory(game_object: GameObject) -> Union[ObjectInventoryComponent, None]: - return CommonComponentUtils.get_component(game_object, CommonComponentType.INVENTORY) diff --git a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_location_utils.py b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_location_utils.py deleted file mode 100644 index 536e582..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_location_utils.py +++ /dev/null @@ -1,389 +0,0 @@ -""" -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 -""" -from objects.game_object import GameObject -from typing import Union -from objects.components.live_drag_component import LiveDragComponent -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.classes.math.common_location import CommonLocation -from s4ap.sims4communitylib.classes.math.common_quaternion import CommonQuaternion -from s4ap.sims4communitylib.classes.math.common_surface_identifier import CommonSurfaceIdentifier -from s4ap.sims4communitylib.classes.math.common_vector3 import CommonVector3 -from s4ap.sims4communitylib.enums.types.component_types import CommonComponentType -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ - CommonConsoleCommandArgument -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.common_component_utils import CommonComponentUtils -from s4ap.sims4communitylib.utils.location.common_location_utils import CommonLocationUtils -from s4ap.sims4communitylib.utils.objects.common_object_type_utils import CommonObjectTypeUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from world.lot import Lot - - -class CommonObjectLocationUtils: - """Utilities for manipulating the location and draggability of Objects. - - """ - - @staticmethod - def enable_object_drag_in_live_mode(game_object: GameObject) -> bool: - """enable_object_drag_in_live_mode(game_object) - - Enable the draggability of an Object in Live Mode. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if successful. False, if not. - :rtype: bool - """ - if game_object is None: - return False - live_drag_component: LiveDragComponent = CommonComponentUtils.get_component(game_object, CommonComponentType.LIVE_DRAG) - if live_drag_component is None: - return False - live_drag_component._set_can_live_drag(True) - return True - - @staticmethod - def disable_object_drag_in_live_mode(game_object: GameObject) -> bool: - """disable_object_drag_in_live_mode(game_object) - - Disable the draggability an Object in Live Mode. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if successful. False, if not. - :rtype: bool - """ - if game_object is None: - return False - live_drag_component: LiveDragComponent = CommonComponentUtils.get_component(game_object, CommonComponentType.LIVE_DRAG) - if live_drag_component is None: - return False - live_drag_component._set_can_live_drag(False) - return True - - @staticmethod - def is_within_range_of_position(game_object: GameObject, position: CommonVector3, distance_in_squares: float) -> bool: - """is_within_range_of_position(game_object, position, distance_in_squares) - - Determine if a Game Object is within a certain distance of a Position. - - :param game_object: The object to check. - :type game_object: GameObject - :param position: A position. - :type position: CommonVector3 - :param distance_in_squares: A unit measured in squares. 1 square is the size of 1 square in the Build/Buy mode visual grid. For comparison, a dining chair would be 1 square by 1 square. 0.5 would be half a square, or half a dining chair. - :type distance_in_squares: float - :return: True, if the distance between the Object and the Position is less than or equal to the specified distance in squares. False, if not. - :return: bool - """ - object_position = CommonObjectLocationUtils.get_position(game_object) - if object_position is None: - return False - return CommonLocationUtils.is_position_within_range_of_position(object_position, position, distance_in_squares) - - @staticmethod - def is_within_range_of_location(game_object: GameObject, location: CommonLocation, distance_in_squares: float) -> bool: - """is_within_range_of_location(game_object, location, distance_in_squares) - - Determine if a Game Object is within a certain distance of a Location. - - :param game_object: The object to check. - :type game_object: GameObject - :param location: A location. - :type location: CommonLocation - :param distance_in_squares: A unit measured in squares. 1 square is the size of 1 square in the Build/Buy mode visual grid. For comparison, a dining chair would be 1 square by 1 square. 0.5 would be half a square, or half a dining chair. - :type distance_in_squares: float - :return: True, if the distance between the Object and the Location is less than or equal to the specified distance in squares. False, if not. - :return: bool - """ - object_location = CommonObjectLocationUtils.get_location(game_object) - if object_location is None: - return False - return CommonLocationUtils.is_location_within_range_of_location(object_location, location, distance_in_squares) - - @staticmethod - def is_on_current_lot(game_object: GameObject) -> bool: - """is_on_current_lot(game_object) - - Determine if a Sim is on the active Lot. - - :param game_object: The object to check. - :type game_object: GameObject - :return: True, if the Object is on the active Lot. False, if not. - :rtype: bool - """ - active_lot = CommonLocationUtils.get_current_lot() - return CommonObjectLocationUtils.is_on_lot(game_object, active_lot) - - @staticmethod - def is_on_lot(game_object: GameObject, lot: Lot) -> bool: - """is_on_lot(sim_info, lot) - - Determine if a Game Object is on a Lot. - - :param game_object: The object to check. - :type game_object: GameObject - :param lot: An instance of a Lot. - :type lot: Lot - :return: True, if the Object is on the specified Lot. False, if not. - :rtype: bool - """ - object_position = CommonObjectLocationUtils.get_position(game_object) - if object_position is None: - return False - return CommonLocationUtils.is_position_on_lot(object_position, lot) - - @staticmethod - def can_drag_object_in_live_mode(game_object: GameObject) -> bool: - """can_live_drag(game_object) - - Determine if an Object can be dragged in Live Mode. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if the Object can be dragged in Live Mode. False, if not. - :rtype: bool - """ - if game_object is None: - return False - live_drag_component: LiveDragComponent = CommonComponentUtils.get_component(game_object, CommonComponentType.LIVE_DRAG) - if live_drag_component is None: - return False - return live_drag_component.can_live_drag - - @staticmethod - def set_location(game_object: GameObject, location: CommonLocation) -> bool: - """set_location(game_object, location) - - Set the location of an Object. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :param location: The location to put the Object. - :type location: CommonLocation - :return: True, if successful. False, if not. - :rtype: bool - """ - if game_object is None or location is None: - return False - game_object.location = location - return True - - @staticmethod - def get_location(game_object: GameObject) -> Union[CommonLocation, None]: - """get_location(game_object) - - Retrieve the location of an Object. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: The location of the Object or None if the Object does not have a location. - :rtype: Union[CommonLocation, None] - """ - if game_object is None: - return None - return CommonLocation.from_location(game_object.location) - - @staticmethod - def get_position(game_object: GameObject) -> Union[CommonVector3, None]: - """get_position(game_object) - - Retrieve the position of an Object. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: The position of the Object or None if the Object does not have a position. - :rtype: CommonVector3 - """ - if game_object is None: - return None - # noinspection PyBroadException - try: - return CommonVector3.from_vector3(game_object.position) - except: - return None - - @staticmethod - def get_bone_position(game_object: GameObject, bone_name: str) -> Union[CommonVector3, None]: - """get_bone_position(game_object, bone_name) - - Retrieve the position of a joint bone on an Object. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :param bone_name: The name of the bone to retrieve the position of. - :type bone_name: str - :return: The position of the Object or None if the Object does not have the specified bone. - :rtype: Union[CommonVector3, None] - """ - # noinspection PyBroadException - try: - return CommonVector3.from_vector3(game_object.get_joint_transform_for_joint(bone_name).translation) - except: - return None - - @staticmethod - def get_root_position(game_object: GameObject) -> CommonVector3: - """get_root_position(game_object) - - Calculate the position of an Object based off of the position of it's Root bone. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: The position of the Object based off of the position of it's Root bone. - :rtype: CommonVector3 - """ - object_position = CommonObjectLocationUtils.get_bone_position(game_object, bone_name='b__ROOT__') or CommonObjectLocationUtils.get_position(game_object) - if object_position is not None and CommonObjectTypeUtils.is_window(game_object): - # For whatever reason, windows have a Y coordinate of -0.0. We fix it here. - object_position = CommonVector3(object_position.x, CommonLocationUtils.get_surface_height_at(object_position.x, object_position.z, CommonObjectLocationUtils.get_routing_surface(game_object)), object_position.z) - return object_position - - @staticmethod - def get_forward_vector(game_object: GameObject) -> CommonVector3: - """get_forward_vector(game_object) - - Retrieve the forward vector of an Object. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: The forward vector of the Object. - :rtype: CommonVector3 - """ - return CommonVector3.from_vector3(game_object.forward) - - @staticmethod - def get_orientation(game_object: GameObject) -> CommonQuaternion: - """get_orientation(game_object) - - Retrieve the orientation of an Object. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: The orientation of the Object. - :rtype: CommonQuaternion - """ - return CommonQuaternion.from_quaternion(game_object.orientation) - - @staticmethod - def get_orientation_degrees(game_object: GameObject) -> float: - """get_orientation_in_degrees(game_object) - - Retrieve the orientation of an Object in degrees. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: The orientation of the Object represented in degrees. - :rtype: float - """ - return CommonQuaternion.to_degrees(CommonObjectLocationUtils.get_orientation(game_object)) - - @staticmethod - def get_routing_surface(game_object: GameObject) -> Union[CommonSurfaceIdentifier, None]: - """get_routing_surface(game_object) - - Retrieve the routing surface of an Object. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: The routing surface of the object or None if a problem occurs. - :rtype: Union[CommonSurfaceIdentifier, None] - """ - if game_object is None: - return None - return CommonSurfaceIdentifier.from_surface_identifier(game_object.routing_surface) - - @staticmethod - def get_surface_level(game_object: GameObject) -> int: - """get_surface_level(game_object) - - Retrieve the surface level of an Object. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: The surface level of the object. - :rtype: int - """ - if game_object is None: - return 0 - routing_surface = CommonObjectLocationUtils.get_routing_surface(game_object) - if not routing_surface: - return 0 - return routing_surface.secondary_id - - @staticmethod - def can_be_routed_to(game_object: GameObject) -> bool: - """can_be_routed_to(game_object) - - Determine if an Object can be routed to by Sims. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if the Object can be routed to by Sims. False, it not. - :rtype: bool - """ - position = CommonObjectLocationUtils.get_position(game_object) + CommonObjectLocationUtils.get_forward_vector(game_object) - routing_surface = CommonObjectLocationUtils.get_routing_surface(game_object) - return CommonLocationUtils.can_position_be_routed_to(position, routing_surface) - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.move_object_to_sim', - 'Move a game object to the current location of a Sim.', - command_arguments=( - CommonConsoleCommandArgument('game_object', 'Game Object Instance Id', 'The instance id of a game object to move.'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to move the object to.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.moveobjecttosim', - ) -) -def _common_move_object_to_sim(output: CommonConsoleCommandOutput, game_object: GameObject, sim_info: SimInfo = None): - if sim_info is None: - output('ERROR: No Sim was specified or the specified Sim was not found!') - return - if game_object is None: - output('ERROR: No object was specified or the specified Game Object was not found.') - return - output(f'Attempting to move object {game_object} to Sim {sim_info}.') - from s4ap.sims4communitylib.utils.sims.common_sim_location_utils import CommonSimLocationUtils - if CommonObjectLocationUtils.set_location(game_object, CommonSimLocationUtils.get_location(sim_info)): - output(f'SUCCESS: Object {game_object} was moved successfully to Sim {sim_info}.') - else: - output(f'FAILED: Object {game_object} failed to move to Sim {sim_info}') - output(f'Done moving object {game_object}.') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.print_bone_position_on_sim', - 'Print the position of a bone on a Sim.', - command_arguments=( - CommonConsoleCommandArgument('bone_name', 'Text', 'The name of a bone on the rig.'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of a Sim.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.printbonepositiononsim', - ) -) -def _common_print_bone_position(output: CommonConsoleCommandOutput, bone_name: str, sim_info: SimInfo = None): - if sim_info is None: - output('ERROR: No Sim was specified or the specified Sim was not found!') - return - if bone_name is None: - output('ERROR: No bone name was specified.') - return - sim = CommonSimUtils.get_sim_instance(sim_info) - bone_position = CommonObjectLocationUtils.get_bone_position(sim, bone_name) - if bone_position is None: - output(f'Bone {bone_name} not found on Sim {sim_info}.') - else: - output(f'Got bone position. X: {bone_position.x} Y: {bone_position.y} Z: {bone_position.z}') diff --git a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_lock_utils.py b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_lock_utils.py deleted file mode 100644 index 1c5f685..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_lock_utils.py +++ /dev/null @@ -1,198 +0,0 @@ -""" -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 -""" -from typing import Union, Callable, Iterator - -from objects.components.locking_components import BaseLockingComponent -from objects.components.portal_lock_data import LockResult, IndividualSimDoorLockData -from objects.components.portal_locking_enums import LockPriority, LockSide, ClearLock -from objects.doors.door import Door -from objects.game_object import GameObject -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.enums.types.component_types import CommonComponentType -from s4ap.sims4communitylib.utils.common_component_utils import CommonComponentUtils -from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils -from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils - - -class CommonObjectLockUtils: - """ Utilities for manipulating the locking component of Objects, such as the ones found on Doors. """ - - @staticmethod - def is_door_locked_for_sim( - door: Door, - sim_info: SimInfo - ) -> bool: - """is_door_locked_for_sim(door, sim_info) - - Determine if a Door is locked for a Sim. - - :param door: An instance of a Door. - :type door: Door - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: True, if the Door is locked for the specified Sim. False, if not. - :rtype: bool - """ - return bool(CommonObjectLockUtils.test_door_lock_for_sim(door, sim_info)) - - @staticmethod - def test_door_lock_for_sim( - door: Door, - sim_info: SimInfo - ) -> LockResult: - """test_door_lock_for_sim(door, sim_info) - - Determine if a door is locked for a Sim. - - :param door: An instance of a Door. - :type door: Door - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of the door being locked and which side it is on. - :rtype: bool - """ - if not CommonTypeUtils.is_door(door): - return LockResult(False) - if not CommonComponentUtils.has_component(door, CommonComponentType.PORTAL_LOCKING): - return LockResult(False) - return door.test_lock(sim_info) - - @staticmethod - def lock_door( - door: Door, - sim_info_list: Iterator[SimInfo], - lock_sides: LockSide=LockSide.LOCK_BOTH, - lock_priority: LockPriority=LockPriority.PLAYER_LOCK, - clear_existing_locks: ClearLock=ClearLock.CLEAR_OTHER_LOCK_TYPES, - replace_same_lock_type: bool=False - ) -> bool: - """lock_door(\ - door,\ - sim_info_list,\ - lock_priority=LockPriority.PLAYER_LOCK,\ - lock_sides=LockSide.LOCK_BOTH,\ - clear_existing_locks=ClearLock.CLEAR_OTHER_LOCK_TYPES,\ - replace_same_lock_type=False\ - ) - - Lock a Door for Sims. - - :param door: An instance of a Door. - :type door: Door - :param sim_info_list: A collection of Sims to lock the door for. - :type sim_info_list: Iterator[SimInfo] - :param lock_priority: The priority of the lock being locked. Default is LockPriority.PLAYER_LOCK. - :type lock_priority: LockPriority, optional - :param lock_sides: The side(s) of the door to lock. Default is Both Sides. - :type lock_sides: LockSide, optional - :param clear_existing_locks: The other types of locks to clear from the door when locking it. Default is ClearLock.CLEAR_OTHER_LOCK_TYPES. - :type clear_existing_locks: ClearLock, optional - :param replace_same_lock_type: Set to True to replace lock types that are the same. Set to False to keep lock types that are the same. Default is False. - :type replace_same_lock_type: bool, optional - :return: True, if the Door was locked successfully. False, if not. - :rtype: bool - """ - if not CommonTypeUtils.is_door(door): - return False - if not CommonComponentUtils.has_component(door, CommonComponentType.PORTAL_LOCKING): - return False - for sim_info in sim_info_list: - lock_data = IndividualSimDoorLockData(lock_sim=sim_info, lock_priority=lock_priority, lock_sides=lock_sides, should_persist=True) - door.add_lock_data(lock_data, replace_same_lock_type=replace_same_lock_type, clear_existing_locks=clear_existing_locks) - - @staticmethod - def unlock_door( - door: Door, - sim_info_list: Iterator[SimInfo], - unlock_sides: LockSide=LockSide.LOCK_BOTH, - lock_priority: LockPriority=LockPriority.PLAYER_LOCK, - clear_existing_locks: ClearLock=ClearLock.CLEAR_NONE - ) -> bool: - """unlock_door(\ - door,\ - sim_info_list,\ - lock_priority=LockPriority.PLAYER_LOCK,\ - unlock_sides=LockSide.LOCK_BOTH,\ - clear_existing_locks=ClearLock.CLEAR_NONE,\ - replace_same_lock_type=False\ - ) - - Unlock a Door for Sims. - - :param door: An instance of a Door. - :type door: Door - :param sim_info_list: A collection of Sims to lock the door for. - :type sim_info_list: Iterator[SimInfo] - :param lock_priority: The priority of the lock being unlocked. Default is LockPriority.PLAYER_LOCK. - :type lock_priority: LockPriority, optional - :param unlock_sides: The side(s) of the door to unlock. Default is Both Sides. - :type unlock_sides: LockSide, optional - :param clear_existing_locks: The other types of locks to clear from the door when unlocking it. Default is ClearLock.CLEAR_NONE. - :type clear_existing_locks: ClearLock, optional - :return: True, if the Door was unlocked successfully. False, if not. - :rtype: bool - """ - if not CommonTypeUtils.is_door(door): - return False - if not CommonComponentUtils.has_component(door, CommonComponentType.PORTAL_LOCKING): - return False - for sim_info in sim_info_list: - lock_data = IndividualSimDoorLockData(unlock_sim=sim_info, lock_priority=lock_priority, lock_sides=unlock_sides, should_persist=True) - door.add_lock_data(lock_data, replace_same_lock_type=False, clear_existing_locks=clear_existing_locks) - - @staticmethod - def refresh_portal_locks_on_all_objects(include_object_callback: Callable[[GameObject], bool]= None) -> bool: - """refresh_portal_locks_on_all_objects(include_object_callback=None) - - Refresh the Portal Locks on all Objects. - - :param include_object_callback: If the result of this callback is True, the Object will be have it's locks refreshed. If set to None, All Objects will have their locks refreshed. Default is None. - :type include_object_callback: Callable[[GameObject], bool], optional - :return: True, if the locks on all Objects were successfully refreshed. False, if not. - :rtype: bool - """ - all_successful = True - for game_object in CommonObjectUtils.get_instance_for_all_game_objects_generator(include_object_callback=include_object_callback): - if not CommonObjectLockUtils.refresh_portal_locks(game_object): - all_successful = False - return all_successful - - @staticmethod - def refresh_portal_locks(game_object: GameObject) -> bool: - """refresh_portal_locks(game_object) - - Refresh the Portal Locks of an Object. - - .. note:: If an Object cannot be locked, this function will do nothing. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if locks were refreshed successfully. False, if not. - :rtype: bool - """ - locking_component: BaseLockingComponent = CommonObjectLockUtils.get_portal_locking_component(game_object) - if locking_component is None: - return False - locking_component.refresh_locks() - return True - - @staticmethod - def get_portal_locking_component(game_object: GameObject) -> Union[BaseLockingComponent, None]: - """get_portal_locking_component(game_object) - - Retrieve the Portal Locking component of an Object. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: The Portal Locking component of the Object or None if an error occurs. - :rtype: Union[BaseLockingComponent, None] - """ - if game_object is None: - return None - result: BaseLockingComponent = CommonComponentUtils.get_component(game_object, CommonComponentType.PORTAL_LOCKING) - return result diff --git a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_ownership_utils.py b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_ownership_utils.py deleted file mode 100644 index 10bbedf..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_ownership_utils.py +++ /dev/null @@ -1,141 +0,0 @@ -""" -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 -""" -from typing import Union - -from objects.components.ownable_component import OwnableComponent -from objects.game_object import GameObject -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ - CommonConsoleCommandArgument -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - - -class CommonObjectOwnershipUtils: - """Utilities for manipulating the ownership of Objects. - - """ - - @staticmethod - def set_owning_household_id(game_object: GameObject, household_id: int) -> bool: - """set_owning_household_id(game_object, household_id) - - Set the Household that owns the Object. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :param household_id: The decimal identifier of a Household. - :type household_id: int - :return: True, if the Household was successfully set as the owner. False, if not. - :rtype: bool - """ - if game_object is None or household_id == -1: - return False - game_object.set_household_owner_id(household_id) - return True - - @staticmethod - def get_owning_household_id(game_object: GameObject) -> int: - """get_owning_household_id(game_object) - - Retrieve the decimal identifier of the Household that owns the Object. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: The decimal identifier of the Household that owns the object. - :rtype: int - """ - if game_object is None: - return -1 - return game_object.get_household_owner_id() - - @staticmethod - def set_owning_sim(game_object: GameObject, sim_info: SimInfo, make_sim_sole_owner: bool = True) -> bool: - """set_owning_sim(game_object, sim_info, make_sim_sole_owner=True) - - Change the ownership of an Object to become owned by the household of a Sim and optional by the Sim themselves. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param make_sim_sole_owner: If True, the Sim will become the sole owner in their household of the Object (In addition to the household owning it). If False, only the household will own the Object. Default is True. - :type make_sim_sole_owner: bool, optional - :return: True, if ownership was transferred successfully. False, if not. - :rtype: bool - """ - if game_object is None or sim_info is None: - return False - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return False - game_object.update_ownership(sim, make_sim_owner=make_sim_sole_owner) - return True - - @staticmethod - def get_owning_sim(game_object: GameObject) -> Union[SimInfo, None]: - """get_owning_sim(game_object) - - Retrieve the Sim that owns an Object, if a Sim owns the Object. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: The SimInfo of the Sim that owns the specified Object or None if no Sim owns the Object. - :rtype: Union[SimInfo, None] - """ - if game_object is None: - return None - ownable_component: OwnableComponent = CommonObjectOwnershipUtils.get_ownable_component(game_object) - if ownable_component is None: - return None - return CommonSimUtils.get_sim_info(ownable_component.get_sim_owner_id()) - - @staticmethod - def get_ownable_component(game_object: GameObject) -> Union[OwnableComponent, None]: - """get_ownable_component(game_object) - - Retrieve the Ownable Component of an Object if it has one. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: The OwnableComponent of the Object or None if no OwnableComponent was found. - :rtype: Union[OwnableComponent, None] - """ - if game_object is None: - return None - if not hasattr(game_object, 'ownable_component'): - return None - return game_object.ownable_component - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.change_ownership', - 'Change the owner of an object to a Sim.', - command_arguments=( - CommonConsoleCommandArgument('game_object', 'Game Object Instance Id', 'The instance id of a game object to change.'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to become the new owner.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.changeownership', - ) -) -def _common_change_ownership(output: CommonConsoleCommandOutput, game_object: GameObject, sim_info: SimInfo = None): - if sim_info is None: - output('ERROR: No Sim was specified or the specified Sim was not found!') - return - if game_object is None: - output('ERROR: No object was specified or the specified Game Object was not found.') - return - output(f'Attempting to change the owner of object {game_object} to Sim {sim_info}.') - if CommonObjectOwnershipUtils.set_owning_sim(game_object, sim_info, make_sim_sole_owner=True): - output(f'SUCCESS: Object {game_object} successfully owned by Sim {sim_info}.') - else: - output(f'FAILED: Object {game_object} failed to change ownership to Sim {sim_info}.') - output(f'Done changing the ownership of object {game_object}.') diff --git a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_reservation_utils.py b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_reservation_utils.py deleted file mode 100644 index 2803658..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_reservation_utils.py +++ /dev/null @@ -1,190 +0,0 @@ -""" -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 -""" -from typing import Union, Tuple, List, Iterator - -from objects.components.slot_component import SlotComponent -from objects.game_object import GameObject -from objects.part import Part -from objects.prop_object import BasicPropObject -from reservation.reservation_handler import _ReservationHandler -from reservation.reservation_result import ReservationResult -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.enums.common_slot_type import CommonSlotType -from s4ap.sims4communitylib.enums.types.component_types import CommonComponentType -from s4ap.sims4communitylib.utils.common_component_utils import CommonComponentUtils -from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - - -class CommonObjectReservationUtils: - """ Utilities for object reservations. """ - @staticmethod - def is_in_use(game_object: GameObject) -> bool: - """is_in_use(game_object) - - Determine if an Object is in use. - - :param game_object: An instance of an object. - :type game_object: GameObject - :return: True, if the object is in use. False, if not. - :rtype: bool - """ - if game_object is None: - return False - return game_object.self_or_part_in_use - - @staticmethod - def is_in_use_by(game_object: GameObject, sim_info: SimInfo) -> bool: - """is_in_use_by(game_object, sim_info) - - Determine if an Object is in use by the specified Sim. - - :param game_object: An instance of an object. - :type game_object: GameObject - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: True, if the object is in use by the specified Sim. False, if not. - :rtype: bool - """ - if game_object is None: - return False - from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return False - return game_object.in_use_by(sim) - - @staticmethod - def get_sims_using_object(game_object: GameObject) -> Tuple[SimInfo]: - """get_sims_using_object(game_object) - - Retrieve a collection of Sims using the object. - - :param game_object: An instance of an object. - :type game_object: GameObject - :return: A collection of Sims using the object. - :rtype: Tuple[SimInfo] - """ - from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - if game_object is None: - return tuple() - sim_info_user_list: List[SimInfo] = [] - for sim in game_object.get_users(sims_only=True): - sim_info_user_list.append(CommonSimUtils.get_sim_info(sim)) - return tuple(sim_info_user_list) - - @staticmethod - def can_be_reserved_by(game_object: GameObject, sim_info: SimInfo) -> bool: - """can_be_reserved_by(game_object, sim_info) - - Determine if an object can be reserved by the Sim. - - :param game_object: An instance of an object. - :type game_object: GameObject - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: True, if the object can be reserved. False, if not. - :rtype: bool - """ - reservation_sim_info_list = CommonObjectReservationUtils.get_sims_using_object(game_object) - if len(reservation_sim_info_list) > 1: - return False - if len(reservation_sim_info_list) == 1 and sim_info not in reservation_sim_info_list: - return False - return True - - @staticmethod - def has_all_free_slots(game_object: GameObject, slot_types: Iterator[CommonSlotType]=()) -> bool: - """has_all_free_slots(game_object, slot_types=()) - - Determine if an Object has all of the specified slots available for use. - - :param game_object: An instance of an object. - :type game_object: GameObject - :param slot_types: A collection of CommonSlotTypes. Default is an empty collection. - :type slot_types: Tuple[CommonSlotTypes], optional - :return: True, if all of the specified slots are free on the Object. False, if not. - :rtype: bool - """ - slot_types = tuple(slot_types) - game_object = CommonObjectUtils.get_root_parent(game_object) - slot_component: SlotComponent = CommonComponentUtils.get_component(game_object, CommonComponentType.SLOT) - if slot_component is None: - return True - for runtime_slot in slot_component.get_runtime_slots_gen(): - if runtime_slot.empty: - continue - if not slot_types: - return False - if not runtime_slot.slot_types: - continue - for slot_type in runtime_slot.slot_types: - if slot_type.__name__ in slot_types: - return False - return True - - @staticmethod - def begin_reservation(reservation_handler: _ReservationHandler) -> ReservationResult: - """begin_reservation(reservation_handler) - - Begin reservation for the specified reservation handler. - - :param reservation_handler: The reservation handler to start. - :type reservation_handler: _ReservationHandler - :return: The result of beginning the reservation. - :rtype: ReservationResult - """ - if reservation_handler is None: - return ReservationResult(False, 'No reservation handler specified.') - result = reservation_handler.begin_reservation() - if isinstance(result, bool): - return ReservationResult(result, 'Failed to reserve the object for some reason.') - return result - - @staticmethod - def end_reservation(reservation_handler: _ReservationHandler) -> ReservationResult: - """end_reservation(reservation_handler) - - End reservation for the specified reservation handler. - - :param reservation_handler: The reservation handler to end. - :type reservation_handler: _ReservationHandler - :return: The result of ending the reservation. - :rtype: bool - """ - if reservation_handler is None: - return ReservationResult(False, 'No reservation handler specified.') - return reservation_handler.end_reservation() - - @staticmethod - def create_reservation_handler( - object_instance: Union[GameObject, Part, BasicPropObject], - sim_info: SimInfo, - **kwargs - ) -> Union[_ReservationHandler, None]: - """create_reservation_handler(object_instance, sim_info, **kwargs) - - Create a reservation handler for a Sim to reserve an object. - - :param object_instance: An instance of an object. - :type object_instance: Union[GameObject, Part, BasicPropObject] - :param sim_info: An instance of a Sim. This Sim will be reserving the object. - :type sim_info: SimInfo - :param kwargs: Keyword arguments used when creating the reservation handler. - :type kwargs: Any - :return: An instance of a Reservation Handler or None if a problem occurs. - :rtype: Union[_ReservationHandler, None] - """ - if object_instance is None or sim_info is None: - return None - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return None - if not hasattr(object_instance, 'get_reservation_handler'): - return None - return object_instance.get_reservation_handler(sim, **kwargs) diff --git a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_slot_utils.py b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_slot_utils.py deleted file mode 100644 index 823f2e2..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_slot_utils.py +++ /dev/null @@ -1,197 +0,0 @@ -""" -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 -""" -from typing import Tuple, Union, List, Callable, Iterator - -from objects.base_object import BaseObject -from objects.components.slot_component import SlotComponent -from objects.game_object import GameObject -from objects.script_object import ScriptObject -from objects.slots import SlotType -from s4ap.sims4communitylib.dtos.common_object_containment_slot import CommonObjectContainmentSlot -from s4ap.sims4communitylib.enums.common_slot_type import CommonSlotType -from s4ap.sims4communitylib.enums.types.component_types import CommonComponentType -from s4ap.sims4communitylib.utils.common_component_utils import CommonComponentUtils -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils - -from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils - - -class CommonObjectSlotUtils: - """Utilities for manipulating object slots.""" - @classmethod - def get_containment_slots(cls, game_object: GameObject) -> Tuple[CommonObjectContainmentSlot]: - """get_containment_slots(game_object) - - Retrieve the containment slots of an object. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: A collection of containment slots on the specified object. - :rtype: Tuple[CommonObjectContainmentSlot] - """ - # noinspection PyTypeChecker - game_object: GameObject = CommonObjectUtils.get_root_parent(game_object) - slot_component = cls.get_slot_component(game_object) - if slot_component is None: - return tuple() - containment_slot_list: List[CommonObjectContainmentSlot] = list() - for (slot_hash, slot_types) in tuple(slot_component.get_containment_slot_infos()): - containment_slot_list.append(CommonObjectContainmentSlot(slot_hash, slot_types)) - return tuple(containment_slot_list) - - @classmethod - def get_slot_component(cls, game_object: GameObject) -> Union[SlotComponent, None]: - """get_slot_component(game_object) - - Retrieve the SlotComponent of an Object. - - :param game_object: An instance of an object. - :type game_object: GameObject - :return: The SlotComponent of the object or None if not found. - :rtype: bool - """ - if not CommonComponentUtils.has_component(game_object, CommonComponentType.SLOT): - return None - # noinspection PyTypeChecker - slot_component: SlotComponent = CommonComponentUtils.get_component(game_object, CommonComponentType.SLOT) - return slot_component - - @classmethod - def get_slot_name(cls, slot: SlotType) -> str: - """get_slot_name(slot) - - Retrieve the name of a slot. - - :param slot: The slot to use. - :type slot: SlotType - :return: The name of the slot or 'No Slot Name' if a problem occurs. - :rtype: str - """ - if slot is None: - return 'No Slot Name' - return slot.__name__ - - @classmethod - def get_first_connected_object_by_slot_name( - cls, - script_object: ScriptObject, - slot_name: CommonSlotType, - include_object_callback: Callable[[ScriptObject], bool] = None - ) -> Union[ScriptObject, None]: - """get_first_connected_object_by_slot_name(script_object, slot_name, include_object_callback=None) - - Get the first connected object by slot. - - .. note:: If only the first object found matching the slot type will be returned. - - :param script_object: The Object to locate connections with. - :type script_object: ScriptObject - :param slot_name: The name of the slot to locate a connected object at. - :type slot_name: CommonSlotType - :param include_object_callback: If the result of this callback is True, the Object will be included in the results. If set to None, All Objects will be included. Default is None. - :type include_object_callback: Callable[[ScriptObject], bool], optional - :return: The object connected to the specified object at the specified slot or None if no object is found. - :rtype: Union[ScriptObject, None] - """ - for child in cls.get_connected_objects_by_slot_name_gen( - script_object, - slot_name, - include_object_callback=include_object_callback - ): - return child - return None - - @classmethod - def get_connected_objects_by_slot_name_gen( - cls, - script_object: ScriptObject, - slot_name: CommonSlotType, - include_object_callback: Callable[[ScriptObject], bool] = None - ) -> Iterator[ScriptObject]: - """get_connected_objects_by_slot_generator(script_object, slot_name, include_object_callback=None) - - Get all connected objects by slot. - - :param script_object: The Object to locate connections with. - :type script_object: ScriptObject - :param slot_name: The name of the slot to locate a connected objects at. - :type slot_name: CommonSlotType - :param include_object_callback: If the result of this callback is True, the Object will be included in the results. If set to None, All Objects will be included. Default is None. - :type include_object_callback: Callable[[ScriptObject], bool], optional - :return: An iterator of objects connected to the specified object at the specified slot. - :rtype: Iterator[ScriptObject] - """ - if script_object is None: - return tuple() - - slot_name_str = str(slot_name) - with_slot_in_front_of_name = f'slot_{slot_name}' - - def _has_slot_name(_connected_object: ScriptObject) -> bool: - if not _connected_object.parent_slot: - return False - for _connected_object_slot_type in _connected_object.parent_slot.slot_types: - if cls.get_slot_name(_connected_object_slot_type) in (slot_name_str, with_slot_in_front_of_name): - return True - return False - - if include_object_callback is not None: - include_object_callback = CommonFunctionUtils.run_predicates_as_one((_has_slot_name, include_object_callback)) - else: - include_object_callback = _has_slot_name - - for connected_object in CommonObjectSlotUtils.get_all_connected_objects_gen( - script_object, - include_object_callback=include_object_callback - ): - yield connected_object - - @classmethod - def get_all_connected_objects_gen( - cls, - script_object: ScriptObject, - include_self: bool = False, - direct_connections_only: bool = False, - include_object_callback: Callable[[ScriptObject], bool] = None - ) -> Iterator[BaseObject]: - """get_all_connected_objects_generator(\ - script_object,\ - include_self=False,\ - direct_connections_only=False,\ - include_object_callback=None\ - ) - - Retrieve all objects connected to the specified Object. - - :param script_object: The Object to locate connections with. - :type script_object: ScriptObject - :param include_self: If True, then script_object will be included in the results. If False, script_object will not be included in the results. Default is False. - :type include_self: bool, optional - :param direct_connections_only: If True, then only directly connected objects will be included in the results. If False, all connected objects as well as all objects connected to those objects recursively will be included in the results. - :type direct_connections_only: bool, optional - :param include_object_callback: If the result of this callback is True, the Object will be included in the results. If set to None, All Objects will be included. Default is None. - :type include_object_callback: Callable[[ScriptObject], bool], optional - :return: An iterator of Objects connected to the specified Object. - :rtype: Iterator[BaseObject] - """ - if direct_connections_only: - if include_self: - yield script_object - for connected_object in script_object.children: - if connected_object is None: - continue - if include_object_callback is not None and not include_object_callback(connected_object): - continue - yield connected_object - else: - for connected_object in script_object.children_recursive_gen(include_self=include_self): - if connected_object is None: - continue - if include_object_callback is not None and not include_object_callback(connected_object): - continue - yield connected_object diff --git a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_spawn_utils.py b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_spawn_utils.py deleted file mode 100644 index 8de2aa2..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_spawn_utils.py +++ /dev/null @@ -1,462 +0,0 @@ -""" -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 -""" -import random -from objects.object_enums import ItemLocation -from sims.sim_info import SimInfo -from typing import Any, Callable, Union, Tuple, Iterator -from s4ap.sims4communitylib.classes.math.common_location import CommonLocation -from s4ap.sims4communitylib.classes.math.common_transform import CommonTransform -from s4ap.sims4communitylib.classes.math.common_vector3 import CommonVector3 -from s4ap.sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog -from s4ap.sims4communitylib.modinfo import ModInfo -from carry.carry_postures import CarryingObject -from objects.game_object import GameObject -from objects.object_enums import ResetReason -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ - CommonConsoleCommandArgument -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.objects.common_object_ownership_utils import CommonObjectOwnershipUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - - -class CommonObjectSpawnUtils(_HasS4CLClassLog): - """Utilities for creating, spawning, and despawning Objects. - - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 'common_object_spawn_utils' - - @classmethod - def create_object( - cls, - object_definition_id: int, - on_object_initialize_callback: Callable[[GameObject], Any] = None, - post_object_spawned_callback: Callable[[GameObject], Any] = None, - location_type: ItemLocation = ItemLocation.ON_LOT, - **kwargs - ) -> Union[GameObject, None]: - """create_object(\ - object_definition_id,\ - on_object_initialize_callback=None,\ - post_object_spawned_callback=None,\ - location_type=ItemLocation.ON_LOT,\ - **kwargs\ - ) - - Create an Object. - - :param object_definition_id: The decimal identifier of the definition of an Object. - :type object_definition_id: int - :param on_object_initialize_callback: Called when initializing the Object. - :type on_object_initialize_callback: Callable[[GameObject], Any], optional - :param post_object_spawned_callback: Called after the Object was added. - :type post_object_spawned_callback: Callable[[GameObject], Any], optional - :param location_type: The location the object is intended to be spawned at. Default is on the lot. - :type location_type: ItemLocation, optional - :return: An instance of the created Object or None if not successfully created. - :rtype: GameObject - """ - from objects.system import create_object - return create_object( - object_definition_id, - init=on_object_initialize_callback, - post_add=post_object_spawned_callback, - loc_type=location_type, - **kwargs - ) - - @classmethod - def spawn_object_on_lot( - cls, - object_definition_id: int, - location: CommonLocation, - on_object_initialize_callback: Callable[[GameObject], Any] = None, - post_object_spawned_callback: Callable[[GameObject], Any] = None, - **kwargs - ) -> Union[GameObject, None]: - """spawn_object_on_lot(\ - object_definition_id,\ - location,\ - on_object_initialize_callback=None,\ - post_object_spawned_callback=None,\ - **kwargs\ - ) - - Spawn an Object on the current lot. - - :param object_definition_id: The decimal identifier of the definition of an Object. - :type object_definition_id: int - :param location: The location to spawn the Object at. - :type location: CommonLocation - :param on_object_initialize_callback: Called when initializing the Object. - :type on_object_initialize_callback: Callable[[GameObject], Any], optional - :param post_object_spawned_callback: Called after the Object was added to the lot. - :type post_object_spawned_callback: Callable[[GameObject], Any], optional - :return: An instance of the spawned Object or None if not successfully spawned. - :rtype: GameObject - """ - from s4ap.sims4communitylib.utils.objects.common_object_location_utils import CommonObjectLocationUtils - game_object = cls.create_object( - object_definition_id, - on_object_initialize_callback=on_object_initialize_callback, - post_object_spawned_callback=post_object_spawned_callback, - location_type=ItemLocation.ON_LOT, - **kwargs - ) - if game_object is None: - return None - CommonObjectLocationUtils.set_location(game_object, location) - return game_object - - @classmethod - def spawn_object_near_location( - cls, - object_definition_id: int, - location: CommonLocation, - radius: int = 1, - on_object_initialize_callback: Callable[[GameObject], Any] = None, - post_object_spawned_callback: Callable[[GameObject], Any] = None, - **kwargs - ) -> GameObject: - """spawn_object_near_location(\ - object_definition_id,\ - location,\ - radius=1,\ - on_object_initialize_callback=None,\ - post_object_spawned_callback=None,\ - **kwargs - ) - - Spawn an Object near a location. - - :param object_definition_id: The decimal identifier of the definition of an Object. - :type object_definition_id: int - :param location: The location to spawn the Object at. - :type location: CommonLocation - :param radius: The radius at which the object may spawn in with the location at the center. Default is 1 square out. - :type radius: int, optional - :param on_object_initialize_callback: Called when initializing the Object. - :type on_object_initialize_callback: Callable[[GameObject], Any], optional - :param post_object_spawned_callback: Called after the Object was added to the lot. - :type post_object_spawned_callback: Callable[[GameObject], Any], optional - :return: An instance of the spawned Object or None if not successfully spawned. - :rtype: GameObject - """ - if location is None: - raise AssertionError('location was found to be None!') - current_translation = location.transform.translation - x = int(current_translation.x) - min_x = x - radius - max_x = x + radius - new_x = random.randint(min_x, max_x) - z = int(current_translation.z) - min_z = z - radius - max_z = z + radius - new_z = random.randint(min_z, max_z) - new_translation = CommonVector3(new_x, current_translation.y, new_z) - new_transform = CommonTransform( - new_translation, - location.transform.orientation - ) - parent_ref = None - if location.parent_ref is not None and hasattr(location.parent_ref, 'provided_routing_surface'): - parent_ref = location.parent_ref - new_location = CommonLocation( - new_transform, - location.routing_surface, - parent_ref=parent_ref, - joint_name_or_hash=location.joint_name_or_hash, - slot_hash=location.slot_hash - ) - return CommonObjectSpawnUtils.spawn_object_on_lot( - object_definition_id, - new_location, - on_object_initialize_callback=on_object_initialize_callback, - post_object_spawned_callback=post_object_spawned_callback, - **kwargs - ) - - @classmethod - def destroy_object(cls, game_object: GameObject, source: Any = None, cause: str = None, **kwargs) -> bool: - """destroy_object(game_object, source=None, cause=None, **kwargs) - - Destroy an Object. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :param source: The source of the destruction. - :type source: str, optional - :param cause: The cause of the destruction. - :type cause: str, optional - :return: True, if the Object was successfully destroyed. False, if not. - :rtype: bool - """ - if game_object is None: - return False - if game_object.is_in_inventory(): - inventory = game_object.get_inventory() - if inventory is None or inventory.owner is None: - game_object.destroy(source=source, cause=cause, **kwargs) - else: - from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils - object_id = CommonObjectUtils.get_object_id(game_object) - if game_object.is_in_sim_inventory(): - sim_info = CommonSimUtils.get_sim_info(inventory.owner) - from s4ap.sims4communitylib.utils.sims.common_sim_inventory_utils import CommonSimInventoryUtils - CommonSimInventoryUtils.remove_from_inventory(sim_info, object_id, count=1) - else: - inventory_game_object = CommonObjectUtils.get_game_object(inventory.owner) - from s4ap.sims4communitylib.utils.objects.common_object_inventory_utils import CommonObjectInventoryUtils - CommonObjectInventoryUtils.remove_from_inventory_by_id(inventory_game_object, object_id, count=1) - else: - game_object.destroy(source=source, cause=cause, **kwargs) - return True - - @classmethod - def schedule_object_for_destroy(cls, game_object: GameObject, source: Any = None, cause: str = None, on_destroyed: Callable[[], None] = None, **kwargs) -> bool: - """schedule_object_for_destroy(game_object, source=None, cause=None, on_destroyed=None, **kwargs) - - Schedule an Object to be destroyed. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :param source: The source of the destruction. Default is None. - :type source: str, optional - :param cause: The cause of the destruction. Default is None. - :type cause: str, optional - :param on_destroyed: A callback that occurs after the Object is destroyed. Default is None. - :type on_destroyed: Callable[[], None], optional - :return: True, if the Object was successfully scheduled for destruction. False, if not. - :rtype: bool - """ - if game_object is None: - return False - if game_object.is_in_inventory(): - inventory = game_object.get_inventory() - if inventory is None or inventory.owner is None: - game_object.schedule_destroy_asap(post_delete_func=on_destroyed, source=source, cause=cause, **kwargs) - else: - from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils - object_id = CommonObjectUtils.get_object_id(game_object) - if game_object.is_in_sim_inventory(): - sim_info = CommonSimUtils.get_sim_info(inventory.owner) - from s4ap.sims4communitylib.utils.sims.common_sim_inventory_utils import CommonSimInventoryUtils - CommonSimInventoryUtils.remove_from_inventory(sim_info, object_id, count=1) - else: - inventory_game_object = CommonObjectUtils.get_game_object(inventory.owner) - from s4ap.sims4communitylib.utils.objects.common_object_inventory_utils import CommonObjectInventoryUtils - CommonObjectInventoryUtils.remove_from_inventory_by_id(inventory_game_object, object_id, count=1) - else: - game_object.schedule_destroy_asap(post_delete_func=on_destroyed, source=source, cause=cause, **kwargs) - return True - - @classmethod - def soft_reset( - cls, - game_object: GameObject, - reset_reason: ResetReason = ResetReason.RESET_EXPECTED, - hard_reset_on_exception: bool = False, - source: Any = None, - cause: str = 'S4CL Soft Reset' - ) -> bool: - """soft_reset(game_object, reset_reason=ResetReason.RESET_EXPECTED, hard_reset_on_exception=False, source=None, cause=None) - - Perform a soft reset on an Object. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :param reset_reason: The reason for the reset. Default is ResetReason.RESET_EXPECTED. - :type reset_reason: ResetReason, optional - :param hard_reset_on_exception: If set to True, a hard reset of the Object will be attempted upon an error occurring. If set to False, nothing will occur if the reset failed. Default is False. - :type hard_reset_on_exception: bool, optional - :param source: The source of the reset. Default is the GameObject. - :type source: Any, optional - :param cause: The cause of the reset. Default is 'S4CL Soft Reset'. - :type cause: Any, optional - :return: True, if the reset was successful. False, if not. - :rtype: bool - """ - if game_object is None: - return True - # noinspection PyBroadException - try: - if game_object.parent is not None and game_object.parent.is_sim and not game_object.parent.posture_state.is_carrying(game_object): - CarryingObject.snap_to_good_location_on_floor( - game_object, - starting_transform=game_object.parent.transform, - starting_routing_surface=game_object.parent.routing_surface - ) - location = game_object.location - game_object.on_reset_send_op(reset_reason) - game_object.location = location - game_object.resend_location() - if game_object.routing_component is not None: - game_object.routing_component.on_reset_internal_state(reset_reason) - if game_object.idle_component is not None: - game_object.idle_component._refresh_active_idle() - if game_object.linked_object_component is not None: - game_object.linked_object_component._relink(update_others=True) - return True - except: - if hard_reset_on_exception: - return CommonObjectSpawnUtils.hard_reset(game_object, reset_reason=reset_reason, source=source, cause=cause) - return False - - @classmethod - def hard_reset(cls, game_object: GameObject, reset_reason: ResetReason = ResetReason.RESET_EXPECTED, source: Any = None, cause: str = 'S4CL Hard Reset') -> bool: - """hard_reset(game_object, reset_reason=ResetReason.RESET_EXPECTED, source=None, cause=None) - - Perform a hard reset on an Object. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :param reset_reason: The reason for the reset. Default is ResetReason.RESET_EXPECTED. - :type reset_reason: ResetReason, optional - :param source: The source of the reset. Default is the GameObject. - :type source: Any, optional - :param cause: The cause of the reset. Default is 'S4CL Hard Reset'. - :type cause: Any, optional - :return: True, if the reset was successful. False, if not. - :rtype: bool - """ - if game_object is None: - return True - # noinspection PyBroadException - try: - game_object.reset(reset_reason, source=source or game_object, cause=cause) - return True - except: - return False - - @classmethod - def fade_in(cls, game_object: GameObject, fade_duration: float = 1.0, immediate: bool = False, additional_channels: Iterator[Tuple[int, int, int]] = None): - """fade_in(game_object, fade_duration=1.0, immediate=False, additional_channels=None) - - Change the opacity of an Object from invisible to visible. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :param fade_duration: The number of milliseconds the fade effect should take to complete. Default is 1.0. - :type fade_duration: float, optional - :param immediate: If set to True, fade in will occur immediately. Default is False. - :type immediate: bool, optional - :param additional_channels: A collection of additional channels. The order of the inner tuple is Manager Id, Object Id, and Mask. Default is None. - :type additional_channels: Iterator[Tuple[int, int, int]], optional - """ - if game_object is None: - return - game_object.fade_in(fade_duration=fade_duration, immediate=immediate, additional_channels=additional_channels) - - @classmethod - def fade_out(cls, game_object: GameObject, fade_duration: float = 1.0, immediate: bool = False, additional_channels: Iterator[Tuple[int, int, int]] = None): - """fade_out(game_object, fade_duration=1.0, immediate=False, additional_channels=None) - - Change the opacity of an Object from visible to invisible. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :param fade_duration: The number of milliseconds the fade effect should take to complete. Default is 1.0. - :type fade_duration: float, optional - :param immediate: If set to True, fade out will occur immediately. Default is False. - :type immediate: bool, optional - :param additional_channels: A collection of additional channels. The order of the inner tuple is Manager Id, Object Id, and Mask. Default is None. - :type additional_channels: Iterator[Tuple[int, int, int]], optional - """ - if game_object is None: - return - game_object.fade_out(fade_duration=fade_duration, immediate=immediate, additional_channels=additional_channels) - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.spawn_object', - 'Spawn a Game Object at the feet of a Sim.', - command_arguments=( - CommonConsoleCommandArgument('object_definition_id', 'Decimal Identifier', 'The decimal identifier of the Object Definition for the object to spawn.'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to spawn the object at.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.spawnobject', - ) -) -def _common_spawn_object(output: CommonConsoleCommandOutput, object_definition_id: int, sim_info: SimInfo = None): - if object_definition_id <= 0: - output('ERROR: object_definition_id must be a positive number above zero.') - return - output('Attempting to spawn object on the current lot with id \'{}\'.'.format(object_definition_id)) - from s4ap.sims4communitylib.utils.sims.common_sim_location_utils import CommonSimLocationUtils - from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils - sim_location = CommonSimLocationUtils.get_location(sim_info) - game_object = CommonObjectSpawnUtils.spawn_object_on_lot(object_definition_id, sim_location) - if game_object is not None: - game_object_id = CommonObjectUtils.get_object_id(game_object) - CommonObjectSpawnUtils.get_log().enable() - CommonObjectSpawnUtils.get_log().debug(f'Object {game_object} spawned successfully. Can you see it? Object Id: {game_object_id}') - CommonObjectSpawnUtils.get_log().disable() - output(f'SUCCESS: Object {game_object} spawned successfully. Can you see it? Object Id: {game_object_id}') - from s4ap.sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils - CommonObjectOwnershipUtils.set_owning_household_id(game_object, CommonHouseholdUtils.get_household_id(sim_info)) - else: - output(f'ERROR: Failed to spawn object with definition id {object_definition_id}.') - output(f'Done spawning object {game_object}.') - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.fade_in_object', - 'Fade In an object.', - command_arguments=( - CommonConsoleCommandArgument('game_object', 'Game Object Instance Id', 'The instance id of a game object to fade in.'), - ), - command_aliases=( - 's4clib.fadeinobject', - ) -) -def _common_fade_in_object(output: CommonConsoleCommandOutput, game_object: GameObject): - if game_object is None: - return - game_object_str = str(game_object) - output(f'Attempting to fade in object \'{game_object_str}\'.') - - if CommonObjectSpawnUtils.fade_in(game_object, immediate=True): - output('Successfully faded in object.') - else: - output('Failed to fade in object.') - return True - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.destroy_object', - 'Destroy/Delete a game object.', - command_arguments=( - CommonConsoleCommandArgument('game_object', 'Game Object Instance Id', 'The instance id of a game object to destroy/delete.'), - ), - command_aliases=( - 's4clib.destroyobject', - ) -) -def _common_destroy_object(output: CommonConsoleCommandOutput, game_object: GameObject): - if game_object is None: - return - game_object_str = str(game_object) - output(f'Attempting to destroy object \'{game_object_str}\'.') - - def _on_destroyed() -> None: - output(f'SUCCESS: Object {game_object_str} successfully destroyed.') - - if CommonObjectSpawnUtils.schedule_object_for_destroy(game_object, source='S4CL Command', cause='S4CL Command', on_destroyed=_on_destroyed): - output(f'Successfully scheduled object {game_object} for destruction. Please wait.') - else: - output(f'FAILED: Failed to schedule object {game_object} for destruction.') - output(f'Done destroying or scheduling the destruction of object {game_object}.') diff --git a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_state_utils.py b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_state_utils.py deleted file mode 100644 index b8b1e5e..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_state_utils.py +++ /dev/null @@ -1,734 +0,0 @@ -""" -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 -""" -from typing import Union, Tuple, Dict - -from event_testing.resolver import SingleObjectResolver -from event_testing.tests import TestSetInstance -from objects.components.state import StateComponent, ObjectStateValue, ObjectState -from objects.game_object import GameObject -from server_commands.argument_helpers import TunableInstanceParam -from sims4.resources import Types -from s4ap.sims4communitylib.enums.common_object_state_ids import CommonObjectStateId -from s4ap.sims4communitylib.enums.common_object_state_value_ids import CommonObjectStateValueId -from s4ap.sims4communitylib.enums.common_object_quality import CommonObjectQuality -from s4ap.sims4communitylib.enums.statistics_enum import CommonStatisticId -from s4ap.sims4communitylib.enums.types.component_types import CommonComponentType -from s4ap.sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ - CommonConsoleCommandArgument -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.common_component_utils import CommonComponentUtils -from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils -from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils -from statistics.commodity import Commodity -from statistics.commodity_tracker import CommodityTracker - - -class CommonObjectStateUtils(_HasS4CLClassLog): - """ Utilities for manipulating the state of Objects. """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 'common_object_state_utils' - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - return ModInfo.get_identity() - - @staticmethod - def has_poor_quality(game_object: GameObject) -> bool: - """has_poor_quality(game_object) - - Determine if an object has poor quality. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if the specified Object has poor quality. False, if not. - :rtype: bool - """ - object_state = CommonObjectStateUtils.get_current_object_state(game_object, CommonObjectStateId.QUALITY) - return CommonObjectStateUtils.get_object_state_value_guid(object_state) == CommonObjectStateValueId.QUALITY_POOR - - @staticmethod - def has_normal_quality(game_object: GameObject) -> bool: - """has_normal_quality(game_object) - - Determine if an object has normal quality. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if the specified Object has normal quality. False, if not. - :rtype: bool - """ - object_state = CommonObjectStateUtils.get_current_object_state(game_object, CommonObjectStateId.QUALITY) - return CommonObjectStateUtils.get_object_state_value_guid(object_state) == CommonObjectStateValueId.QUALITY_NORMAL - - @staticmethod - def has_outstanding_quality(game_object: GameObject) -> bool: - """has_outstanding_quality(game_object) - - Determine if an object has outstanding quality. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if the specified Object has outstanding quality. False, if not. - :rtype: bool - """ - object_state = CommonObjectStateUtils.get_current_object_state(game_object, CommonObjectStateId.QUALITY) - return CommonObjectStateUtils.get_object_state_value_guid(object_state) == CommonObjectStateValueId.QUALITY_OUTSTANDING - - @staticmethod - def get_quality(game_object: GameObject) -> Union[CommonObjectQuality, None]: - """get_quality(game_object) - - Retrieve the Quality of an Object. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: The CommonObjectQuality that represents the quality of the Object, or None if the quality could not be determined. - :rtype: Union[CommonObjectQuality, None] - """ - if CommonObjectStateUtils.has_poor_quality(game_object): - return CommonObjectQuality.POOR - if CommonObjectStateUtils.has_normal_quality(game_object): - return CommonObjectQuality.NORMAL - if CommonObjectStateUtils.has_outstanding_quality(game_object): - return CommonObjectQuality.OUTSTANDING - return None - - @staticmethod - def get_quality_state(game_object: GameObject) -> Union[ObjectStateValue, None]: - """get_quality_state(game_object) - - Retrieve the Quality State of an Object. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: The quality state of the Object or None when not found. - :rtype: Union[ObjectStateValue, None] - """ - return CommonObjectStateUtils.get_current_object_state(game_object, CommonObjectStateId.QUALITY) - - @staticmethod - def set_quality(game_object: GameObject, quality: CommonObjectQuality) -> None: - """set_quality(game_object, quality) - - Set the quality of an object. - - :param game_object: The object to modify. - :type game_object: GameObject - :param quality: The quality to set. - :type quality: CommonObjectQuality - """ - quality_state = CommonObjectStateUtils.convert_quality_to_object_state_value(quality) - if quality_state is None: - return None - CommonObjectStateUtils.set_object_state(game_object, quality_state) - - @staticmethod - def convert_quality_to_object_state_value(value: 'CommonObjectQuality') -> Union[ObjectStateValue, None]: - """convert_quality_to_object_state_value(value) - - Convert CommonObjectQuality to an ObjectStateValue. - - :param value: The value to convert. - :type value: CommonObjectQuality - :return: The value translated to an ObjectStateValue, or None if the value could not be translated. - :rtype: Union[ObjectStateValue, None] - """ - if value is None: - return None - mapping: Dict[CommonObjectQuality, CommonObjectStateValueId] = { - CommonObjectQuality.POOR: CommonObjectStateValueId.QUALITY_POOR, - CommonObjectQuality.NORMAL: CommonObjectStateValueId.QUALITY_NORMAL, - CommonObjectQuality.OUTSTANDING: CommonObjectStateValueId.QUALITY_OUTSTANDING, - } - quality_state_value_id = mapping.get(value, None) - if quality_state_value_id is None: - return None - return CommonObjectStateUtils.load_object_state_value_by_id(quality_state_value_id) - - @staticmethod - def convert_quality_from_object_state_value(value: ObjectStateValue) -> Union['CommonObjectQuality', None]: - """convert_quality_from_object_state_value(value) - - Convert an ObjectStateValue to a matching CommonObjectQuality value. - - :param value: An instance of ObjectStateValue - :type value: ObjectStateValue - :return: The specified ObjectStateValue translated to CommonObjectQuality or None if the value could not be translated. - :rtype: Union['CommonObjectQuality', None] - """ - if value is None: - return None - if isinstance(value, CommonObjectQuality): - return value - mapping: Dict[int, CommonObjectQuality] = { - CommonObjectStateValueId.QUALITY_POOR: CommonObjectQuality.POOR, - CommonObjectStateValueId.QUALITY_NORMAL: CommonObjectQuality.NORMAL, - CommonObjectStateValueId.QUALITY_OUTSTANDING: CommonObjectQuality.OUTSTANDING, - } - object_state_value_id = CommonObjectStateUtils.get_object_state_value_guid(value) - return mapping.get(object_state_value_id, None) - - @staticmethod - def can_become_broken(game_object: GameObject) -> bool: - """can_become_broken(game_object) - - Determine if an Object is able to break. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if the specified Object is able to break. False, if not. - :rtype: bool - """ - if game_object is None or not hasattr(game_object, 'commodity_tracker'): - return False - if CommonTypeUtils.is_sim_or_sim_info(game_object): - return False - commodity: Commodity = CommonResourceUtils.load_instance(Types.STATISTIC, int(CommonStatisticId.OBJECT_BROKENNESS)) - commodity_tracker: CommodityTracker = game_object.commodity_tracker - if commodity_tracker is None: - return False - return commodity_tracker.has_statistic(commodity) - - @staticmethod - def can_become_dirty(game_object: GameObject) -> bool: - """can_become_dirty(game_object) - - Determine if an Object is able to get dirty. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if the specified Object is able to get dirty. False, if not. - :rtype: bool - """ - if game_object is None or not hasattr(game_object, 'commodity_tracker'): - return False - if CommonTypeUtils.is_sim_or_sim_info(game_object): - return False - commodity: Commodity = CommonResourceUtils.load_instance(Types.STATISTIC, int(CommonStatisticId.DIRTINESS)) - commodity_tracker: CommodityTracker = game_object.commodity_tracker - if commodity_tracker is None: - return False - return commodity_tracker.has_statistic(commodity) - - @staticmethod - def is_broken(game_object: GameObject) -> bool: - """is_broken(game_object) - - Determine if an Object is broken. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if the specified Object is broken. False, if not. - :rtype: bool - """ - if game_object is None or not hasattr(game_object, 'commodity_tracker'): - return False - if CommonTypeUtils.is_sim_or_sim_info(game_object): - return False - # testSet_StateBroken - test_set_instance: TestSetInstance = CommonResourceUtils.load_instance(Types.SNIPPET, 33738) - # noinspection PyUnresolvedReferences - tests: CompoundTestList = test_set_instance.test - resolver = SingleObjectResolver(game_object) - result = tests.run_tests(resolver) - return bool(result) - - @staticmethod - def is_dirty(game_object: GameObject) -> bool: - """is_dirty(game_object) - - Determine if an Object is dirty. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if the specified Object is dirty. False, if not. - :rtype: bool - """ - if game_object is None or not hasattr(game_object, 'commodity_tracker'): - return False - commodity: Commodity = CommonResourceUtils.load_instance(Types.STATISTIC, int(CommonStatisticId.DIRTINESS)) - commodity_tracker: CommodityTracker = game_object.commodity_tracker - if commodity_tracker is None: - return False - if not commodity_tracker.has_statistic(commodity): - return False - return commodity_tracker.get_value(commodity) == commodity.min_value - - @staticmethod - def break_object(game_object: GameObject) -> bool: - """break_object(game_object) - - Break an Object. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if the specified Object has been broken. False, if not. - :rtype: bool - """ - if game_object is None or not hasattr(game_object, 'commodity_tracker'): - return False - commodity: Commodity = CommonResourceUtils.load_instance(Types.STATISTIC, int(CommonStatisticId.OBJECT_BROKENNESS)) - commodity_tracker: CommodityTracker = game_object.commodity_tracker - if commodity_tracker is None: - return False - if not commodity_tracker.has_statistic(commodity): - return False - return commodity_tracker.set_min(commodity) - - @staticmethod - def fix_object(game_object: GameObject) -> bool: - """fix_object(game_object) - - Fix an Object. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if the specified Object has been fixed. False, if not. - :rtype: bool - """ - if game_object is None or not hasattr(game_object, 'commodity_tracker'): - return False - commodity: Commodity = CommonResourceUtils.load_instance(Types.STATISTIC, int(CommonStatisticId.OBJECT_BROKENNESS)) - commodity_tracker: CommodityTracker = game_object.commodity_tracker - if commodity_tracker is None: - return False - if not commodity_tracker.has_statistic(commodity): - return False - return commodity_tracker.set_max(commodity) - - @staticmethod - def make_dirty(game_object: GameObject) -> bool: - """make_dirty(game_object) - - Make an Object dirty. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if the specified Object has been made dirty. False, if not. - :rtype: bool - """ - if game_object is None or not hasattr(game_object, 'commodity_tracker'): - return False - commodity: Commodity = CommonResourceUtils.load_instance(Types.STATISTIC, int(CommonStatisticId.DIRTINESS)) - commodity_tracker: CommodityTracker = game_object.commodity_tracker - if commodity_tracker is None: - return False - if not commodity_tracker.has_statistic(commodity): - return False - return commodity_tracker.set_min(commodity) - - @staticmethod - def make_clean(game_object: GameObject) -> bool: - """make_clean(game_object) - - Make an Object clean. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if the specified Object has been made clean. False, if not. - :rtype: bool - """ - if game_object is None or not hasattr(game_object, 'commodity_tracker'): - return False - commodity: Commodity = CommonResourceUtils.load_instance(Types.STATISTIC, int(CommonStatisticId.DIRTINESS)) - commodity_tracker: CommodityTracker = game_object.commodity_tracker - if commodity_tracker is None: - return False - if not commodity_tracker.has_statistic(commodity): - return False - return commodity_tracker.set_max(commodity) - - @classmethod - def is_object_usable(cls, game_object: GameObject) -> bool: - """is_object_usable(game_object) - - Determine if an Object is in a usable state. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if the specified Object is in a usable state. False, if not. - :rtype: bool - """ - if game_object is None: - return False - state_component: StateComponent = cls.get_object_state_component(game_object) - if state_component is None: - return False - return bool(state_component.is_object_usable) - - @classmethod - def get_object_states(cls, game_object: GameObject) -> Tuple[ObjectStateValue]: - """get_object_states(game_object) - - Retrieve the state values of an Object. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: A collection of ObjectStateValues. - :rtype: Tuple[ObjectStateValue] - """ - if game_object is None: - return tuple() - state_component: StateComponent = cls.get_object_state_component(game_object) - if state_component is None: - return tuple() - return tuple(state_component.values()) - - @classmethod - def has_any_object_states(cls, game_object: GameObject, object_state_ids: Tuple[int]) -> bool: - """has_any_object_states(game_object, object_state_ids) - - Determine if an Object has any of the specified object states. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :param object_state_ids: A collection of decimal identifiers for object states. - :type object_state_ids: Tuple[int] - :return: True, if the object has any of the specified object states. False, if not. - :rtype: bool - """ - state_component: StateComponent = cls.get_object_state_component(game_object) - if state_component is None: - return False - if not object_state_ids: - return False - for state_value in state_component.values(): - if CommonObjectStateUtils.get_object_state_value_guid(state_value) in object_state_ids: - return True - return False - - @classmethod - def has_all_object_states(cls, game_object: GameObject, object_state_ids: Tuple[int]) -> bool: - """has_all_object_states(game_object, object_state_ids) - - Determine if an Object has all of the specified object states. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :param object_state_ids: A collection of decimal identifiers for object states. - :type object_state_ids: Tuple[int] - :return: True, if the object has all of the specified object states. False, if not. - :rtype: bool - """ - state_component: StateComponent = cls.get_object_state_component(game_object) - if state_component is None: - return False - if not object_state_ids: - return False - for state_value in state_component.values(): - if CommonObjectStateUtils.get_object_state_value_guid(state_value) not in object_state_ids: - return False - return True - - @classmethod - def get_object_state_guid(cls, object_state: ObjectState) -> Union[int, None]: - """get_object_state_guid(object_state) - - Retrieve the GUID of an object state. (Not to be confused with the instance id) - - :param object_state: An instance of an object state. - :type object_state: ObjectState - :return: The GUID of the state or None if no identifier is found. - :rtype: Union[int, None] - """ - return cls.get_object_state_value_guid(object_state) - - @classmethod - def get_object_state_value_guid(cls, object_state_value: ObjectStateValue) -> Union[int, None]: - """get_object_state_value_guid(object_state_value) - - Retrieve the GUID of an object state. (Not to be confused with the instance id) - - :param object_state_value: An instance of an object state. - :type object_state_value: ObjectStateValue - :return: The GUID of the state value or None if no identifier is found. - :rtype: Union[int, None] - """ - if object_state_value is None: - return None - return getattr(object_state_value, 'guid64', None) - - @staticmethod - def get_object_state_component(game_object: GameObject) -> Union[StateComponent, None]: - """get_object_state_component(game_object) - - Retrieve the State Component of an Object. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: The State Component of the specified Object or None if no state component is found. - :rtype: Union[StateComponent, None] - """ - if game_object is None: - return None - return CommonComponentUtils.get_component(game_object, CommonComponentType.STATE) - - @classmethod - def get_object_state_items(cls, game_object: GameObject) -> Dict[ObjectState, ObjectStateValue]: - """get_object_state_items(game_object) - - Retrieve all Object States of an objects. - - :param game_object: The object to check. - :type game_object: GameObject - :return: A mapping of Object State to the current value of the object state. - :rtype: Dict[ObjectState, ObjectStateValue] - """ - # noinspection PyTypeChecker - state_component: StateComponent = CommonObjectStateUtils.get_object_state_component(game_object) - if state_component is None: - cls.get_log().format_with_message('Object did not have a state component.', script_object=game_object) - return dict() - return state_component._states - - @classmethod - def has_object_state(cls, game_object: GameObject, object_state_identifier: Union[int, CommonObjectStateId, CommonObjectStateValueId, ObjectState, ObjectStateValue]) -> bool: - """has_object_state(game_object, object_state_identifier) - - Determine if an Object has an object state available. - - :param game_object: The Object to check. - :type game_object: GameObject - :param object_state_identifier: The identifier of the state to check. - :type object_state_identifier: Union[int, CommonObjectStateId, CommonObjectStateValueId, ObjectState, ObjectStateValue] - :return: True, if the Object has the specified object state as one of its available states (Not if the specified value is what the state on the object is set to). False, if not. - :rtype: bool - """ - if object_state_identifier is None: - cls.get_log().format_with_message('Specified object state identifier was None.', game_object=game_object, object_state_identifier=object_state_identifier) - return False - object_states = cls.get_object_state_items(game_object) - object_state = cls.load_object_state_by_id(object_state_identifier) - object_state_value = cls.load_object_state_value_by_id(object_state_identifier) - if object_state is None and object_state_value is not None: - object_state = object_state_value.state - else: - object_state = object_state.state - return object_state in object_states - - @classmethod - def has_object_state_value(cls, game_object: GameObject, object_state_value_identifier: Union[int, CommonObjectStateValueId, ObjectStateValue]) -> bool: - """has_object_state_value(game_object, object_state_value_identifier) - - Determine if an Object has a state set to an Object State Value - - :param game_object: The Object to check. - :type game_object: GameObject - :param object_state_value_identifier: The identifier of the object state value to check. - :type object_state_value_identifier: Union[int, CommonObjectStateValueId, ObjectStateValue] - :return: True, if the Object has the specified object state value set. False, if not. - :rtype: bool - """ - if object_state_value_identifier is None: - cls.get_log().format_with_message('Specified object state value identifier was None.', game_object=game_object, object_state_value_identifier=object_state_value_identifier) - return False - # noinspection PyTypeChecker - state_component: StateComponent = CommonObjectStateUtils.get_object_state_component(game_object) - if state_component is None: - cls.get_log().format_with_message('Object did not have a state component.', game_object=game_object, object_state_value_identifier=object_state_value_identifier) - return False - object_state_value = cls.load_object_state_value_by_id(object_state_value_identifier) - if object_state_value is None: - cls.get_log().format_with_message('Failed to locate object state value.', game_object=game_object, object_state_identifier=object_state_value_identifier) - return False - cls.get_log().format_with_message('Checking if object has state value.', target=game_object, state=object_state_value.state, state_value=object_state_value) - state_value = cls.get_current_object_state(game_object, object_state_value.state) - return cls.get_object_state_value_guid(state_value) == cls.get_object_state_value_guid(object_state_value) - - @classmethod - def set_object_state(cls, game_object: GameObject, object_state_value: Union[int, CommonObjectStateValueId, ObjectStateValue]): - """set_object_state(script_object, object_state) - - Set the object state of an Object. - - :param game_object: The Object to modify. - :type game_object: GameObject - :param object_state_value: The state to set. - :type object_state_value: Union[int, CommonObjectStateValueId, ObjectStateValue] - """ - if not cls.has_object_state(game_object, object_state_value): - cls.get_log().format_with_message('Object did not have the required state.') - return None - # noinspection PyTypeChecker - state_component: StateComponent = CommonObjectStateUtils.get_object_state_component(game_object) - if state_component is None: - cls.get_log().format_with_message('Object did not have a state component.', script_object=game_object, object_state=object_state_value) - return - object_state_value = cls.load_object_state_value_by_id(object_state_value) - if object_state_value is None: - cls.get_log().format_with_message('Failed to locate object state.', game_object=game_object, object_state_value=object_state_value) - return - cls.get_log().format_with_message('Setting state of object to value.', target=game_object, state=object_state_value.state, state_value=object_state_value) - state_component.set_state(object_state_value.state, object_state_value) - - @classmethod - def is_object_in_state(cls, game_object: GameObject, object_state_value: Union[int, CommonObjectStateValueId, ObjectStateValue]) -> bool: - """is_object_in_state(game_object, object_state_value) - - Determine if an object is in a state. - - :param game_object: The object to check. - :type game_object: GameObject - :param object_state_value: The object state value to check. - :type object_state_value: Union[int, CommonObjectStateValueId, ObjectStateValue] - :return: True, if the state of an object has the specified object state value. False, if not. - :rtype: bool - """ - object_state_value = cls.load_object_state_value_by_id(object_state_value) - if object_state_value is None: - return False - current_object_state_value = cls.get_current_object_state(game_object, object_state_value.state) - if current_object_state_value is None: - return False - return current_object_state_value == object_state_value - - @classmethod - def get_current_object_state(cls, game_object: GameObject, object_state: Union[int, CommonObjectStateId, ObjectState]) -> Union[ObjectStateValue, None]: - """get_current_object_state(game_object, object_state) - - Get the value of a state on an Object. - - :param game_object: The Object to change. - :type game_object: GameObject - :param object_state: The state to use. - :type object_state: Union[int, CommonObjectStateId, ObjectState] - :return: The value of the specified state on an Object or None if a problem occurs. - :rtype: Union[ObjectStateValue, None] - """ - # noinspection PyTypeChecker - state_component: StateComponent = CommonObjectStateUtils.get_object_state_component(game_object) - if state_component is None: - return None - object_state = cls.load_object_state_by_id(object_state) - if object_state is None: - return None - return state_component.get_state(object_state) - - @classmethod - def load_object_state_by_id(cls, object_state: Union[int, CommonObjectStateId, ObjectState]) -> Union[ObjectState, None]: - """load_object_state_by_id(object_state_value) - - Load an instance of an Object State by its identifier. - - :param object_state: The identifier of an Object State. - :type object_state: Union[int, CommonObjectStateId, ObjectState] - :return: An instance of an Object State Value matching the decimal identifier or None if not found. - :rtype: Union[ObjectState, None] - """ - if isinstance(object_state, ObjectStateValue): - return object_state - # noinspection PyBroadException - try: - object_state: int = int(object_state) - except: - # noinspection PyTypeChecker - object_state: ObjectState = object_state - return object_state - - from sims4.resources import Types - from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils - result = CommonResourceUtils.load_instance(Types.OBJECT_STATE, object_state) - return result - - @classmethod - def load_object_state_value_by_id(cls, object_state_value: Union[int, CommonObjectStateValueId, ObjectStateValue]) -> Union[ObjectStateValue, None]: - """load_object_state_value_by_id(object_state_value) - - Load an instance of an Object State Value by its identifier. - - :param object_state_value: The identifier of an Object State Value. - :type object_state_value: Union[int, CommonObjectStateValueId, ObjectStateValue] - :return: An instance of an Object State Value matching the decimal identifier or None if not found. - :rtype: Union[ObjectStateValue, None] - """ - if isinstance(object_state_value, ObjectStateValue): - return object_state_value - # noinspection PyBroadException - try: - object_state_value: int = int(object_state_value) - except: - # noinspection PyTypeChecker - object_state_value: ObjectStateValue = object_state_value - return object_state_value - - from sims4.resources import Types - from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils - result = CommonResourceUtils.load_instance(Types.OBJECT_STATE, object_state_value) - return result - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_testing.print_object_states', - 'Print all states of an object.', - command_arguments=( - CommonConsoleCommandArgument('game_object', 'Obj Id', 'The object to check.'), - ) -) -def _common_print_object_states(output: CommonConsoleCommandOutput, game_object: GameObject) -> bool: - log = CommonObjectStateUtils.get_log() - try: - log.enable() - object_state_values_by_object_state = CommonObjectStateUtils.get_object_state_items(game_object) - output(f'Printing game tags of {game_object}') - log.debug(f'------------------Object states for {game_object}------------------') - for (object_state, object_state_value) in object_state_values_by_object_state.items(): - object_state_value_guid = CommonObjectStateUtils.get_object_state_value_guid(object_state_value) - log.debug(f'[{object_state}]: Current: {object_state_value} ({object_state_value_guid})') - object_state: ObjectState = object_state - log.debug(f'----------{object_state} Valid Values----------') - for obj_state_value in object_state.values: - obj_state_value_guid = CommonObjectStateUtils.get_object_state_value_guid(obj_state_value) - log.debug(f'-- {obj_state_value} ({obj_state_value_guid})') - log.debug('-------------------') - log.debug('--------------------------------------------------------------------') - output('Done') - return True - finally: - log.disable() - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.set_object_state', - 'Set the state of an object.', - command_arguments=( - CommonConsoleCommandArgument('game_object', 'Obj Id', 'The object to set the state of.'), - CommonConsoleCommandArgument('object_state', 'Object State Id Or Name', 'The state to set the object to.'), - ) -) -def _common_set_object_state(output: CommonConsoleCommandOutput, game_object: GameObject, object_state: TunableInstanceParam(Types.OBJECT_STATE)) -> bool: - output('Setting object state.') - if not CommonObjectStateUtils.has_object_state(game_object, object_state): - output(f'Object {game_object} does not have state {object_state}.') - return False - CommonObjectStateUtils.set_object_state(game_object, object_state) - output('Done setting object state.') - return True - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.modify_object_state', - 'Modify the state of an object.', - command_arguments=( - CommonConsoleCommandArgument('game_object', 'Obj Id', 'The object to set the state of.'), - ) -) -def _common_modify_object_state(output: CommonConsoleCommandOutput, game_object: GameObject) -> bool: - output(f'Opening dialog to modify object state of {game_object}.') - from s4ap.sims4communitylib.debug.dialogs.common_change_object_state_dialog import CommonChangeObjectStateDialog - CommonChangeObjectStateDialog(game_object).open() - return True diff --git a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_tag_utils.py b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_tag_utils.py deleted file mode 100644 index d96e832..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_tag_utils.py +++ /dev/null @@ -1,167 +0,0 @@ -""" -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 -""" -from distributor.shared_messages import IconInfoData -from objects.game_object import GameObject -from typing import Tuple, Set, Union, Iterator, List - -from objects.script_object import ScriptObject -from s4ap.sims4communitylib.enums.tags_enum import CommonGameTag -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.notifications.common_basic_notification import CommonBasicNotification -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ - CommonConsoleCommandArgument -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.common_log_registry import CommonLogRegistry -from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils - - -class CommonObjectTagUtils: - """Utilities for manipulating the tags of objects. - - """ - - @classmethod - def has_game_tag(cls, game_object: Union[GameObject, ScriptObject], tag: Union[int, CommonGameTag]) -> bool: - """has_game_tag(game_object, tag) - - Determine if an Object has the specified tag. - - :param game_object: An instance of an Object. - :type game_object: Union[GameObject, ScriptObject] - :param tag: A tag to locate. - :type tag: Union[int, CommonGameTag] - :return: True, if the Object has the specified tag. False, if not. - :rtype: bool - """ - return CommonObjectTagUtils.has_game_tags(game_object, (tag,)) - - @classmethod - def has_game_tags(cls, game_object: Union[GameObject, ScriptObject], tags: Iterator[Union[int, CommonGameTag]]) -> bool: - """has_game_tags(game_object, tags) - - Determine if an Object has any of the specified tags. - - :param game_object: An instance of an Object. - :type game_object: Union[GameObject, ScriptObject] - :param tags: A collection of tags to locate. - :type tags: Iterator[Union[int, CommonGameTag]] - :return: True, if the Object has any of the specified tags. False, if not. - :rtype: bool - """ - if game_object is None or not hasattr(game_object, 'has_any_tag'): - return False - return game_object.has_any_tag(tuple(tags)) - - @classmethod - def get_game_tags(cls, game_object: Union[GameObject, ScriptObject]) -> Set[int]: - """get_game_tags(game_object) - - Retrieve the tags of an Object. - - :param game_object: An instance of an Object. - :type game_object: Union[GameObject, ScriptObject] - :return: A collection of tags the Object has. - :rtype: Set[int] - """ - if game_object is None or not hasattr(game_object, 'get_tags'): - return set() - return game_object.get_tags() - - @classmethod - def add_game_tags(cls, game_object: Union[GameObject, ScriptObject], tags: Tuple[Union[int, CommonGameTag]], persist: bool = False) -> bool: - """add_game_tags(game_object, tags, persist=False) - - Add tags to an Object. - - :param game_object: An instance of an Object. - :type game_object: Union[GameObject, ScriptObject] - :param tags: A collection of Game Tags to add. - :type tags: Tuple[Union[int, CommonGameTag]] - :param persist: If True, the Tags will persist to all instances of the Object. If False, the Tags will persist only to the specified Object. Default is False. - :type persist: bool, optional - :return: True, if the Tags were successfully added. False, if not. - :rtype: bool - """ - if game_object is None or not hasattr(game_object, 'append_tags'): - return False - game_object.append_tags(set(tags), persist=persist) - return True - - @classmethod - def remove_game_tags(cls, game_object: Union[GameObject, ScriptObject], tags: Tuple[Union[int, CommonGameTag]]) -> bool: - """remove_game_tags(game_object, tags) - - Remove tags from an Object. - - :param game_object: An instance of an Object. - :type game_object: Union[GameObject, ScriptObject] - :param tags: A collection of Game Tags to remove. - :type tags: Tuple[Union[int, CommonGameTag]] - :return: True, if the Tags were successfully removed. False, if not. - :rtype: bool - """ - if game_object is None or not hasattr(game_object, 'remove_dynamic_tags'): - return False - game_object.remove_dynamic_tags(set(tags)) - return True - - @classmethod - def _print_game_tags(cls, game_object: Union[GameObject, ScriptObject]) -> None: - obj_tags_list: List[str] = list() - for obj_tag in CommonObjectTagUtils.get_game_tags(game_object): - if not isinstance(obj_tag, CommonGameTag): - # noinspection PyTypeChecker - obj_tag = CommonResourceUtils.get_enum_by_int_value(obj_tag, CommonGameTag, default_value=obj_tag) - - if hasattr(obj_tag, 'name'): - obj_tag_name = obj_tag.name - else: - obj_tag_name = 'Unknown' - - obj_tags_list.append(f'{obj_tag_name} ({int(obj_tag)})') - - obj_tags_list = sorted(obj_tags_list, key=lambda x: x) - obj_tag_list_names = ',\n'.join(obj_tags_list) - text = '' - text += f'Game Tags:\n{obj_tag_list_names}\n\n' - from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils - game_object_id = CommonObjectUtils.get_object_id(game_object) - log.debug(f'Object {game_object} Tags ({game_object_id})') - log.debug(text) - CommonBasicNotification( - CommonLocalizationUtils.create_localized_string(f'Object {game_object} Tags ({game_object_id})'), - CommonLocalizationUtils.create_localized_string(text) - ).show( - icon=IconInfoData(obj_instance=game_object) - ) - - -log = CommonLogRegistry().register_log(ModInfo.get_identity(), 's4cl_object_tag_utils') -log.enable() - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_testing.print_game_tags', - 'Print a list of Game Tags on a Game Object.', - command_arguments=( - CommonConsoleCommandArgument('game_object', 'Game Object Instance Id', 'The instance id of a game object to check.'), - ), - command_aliases=( - 's4clib_testing.printgametags', - ) -) -def _common_print_game_tags(output: CommonConsoleCommandOutput, game_object: GameObject): - if game_object is None: - return - - output(f'Printing game tags of {game_object}') - CommonObjectTagUtils._print_game_tags(game_object) - output('------------------------------------') diff --git a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_type_utils.py b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_type_utils.py deleted file mode 100644 index d053a5a..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_type_utils.py +++ /dev/null @@ -1,482 +0,0 @@ -""" -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 -""" -from objects.game_object import GameObject -from objects.pools.pool import SwimmingPool -from objects.pools.pool_seat import PoolSeat -from s4ap.sims4communitylib.enums.tags_enum import CommonGameTag -from s4ap.sims4communitylib.utils.objects.common_object_tag_utils import CommonObjectTagUtils - - -class CommonObjectTypeUtils: - """ Utilities for determining the type of an object. """ - @staticmethod - def is_window(game_object: GameObject) -> bool: - """is_window(game_object) - - Determine if an Object is a window. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if the Object is a Window. False, if not. - :rtype: bool - """ - if not isinstance(game_object, GameObject): - return False - from s4ap.sims4communitylib.enums.tags_enum import CommonGameTag - from s4ap.sims4communitylib.utils.objects.common_object_tag_utils import CommonObjectTagUtils - return CommonObjectTagUtils.has_game_tags(game_object, (CommonGameTag.BUILD_WINDOW, )) - - @staticmethod - def is_toilet(game_object: GameObject) -> bool: - """is_toilet(game_object) - - Determine if an Object is a Toilet. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if the Object is a Toilet. False, if not. - :rtype: bool - """ - if not isinstance(game_object, GameObject): - return False - return CommonObjectTagUtils.has_game_tags(game_object, ( - CommonGameTag.FUNC_TOILET, - CommonGameTag.FUNC_PUBLIC_BATHROOM, - CommonGameTag.FUNC_TOILET_TALKING - )) - - @staticmethod - def is_loveseat(game_object: GameObject) -> bool: - """is_loveseat(game_object) - - Determine if an Object is a Loveseat. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if the Object is a Loveseat. False, if not. - :rtype: bool - """ - if not isinstance(game_object, GameObject): - return False - return CommonObjectTagUtils.has_game_tags(game_object, (CommonGameTag.BUY_CAT_SS_LOVE_SEAT, )) - - @staticmethod - def is_bed(game_object: GameObject) -> bool: - """is_bed(game_object) - - Determine if an Object is a Bed. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if the Object is a Bed. False, if not. - :rtype: bool - """ - if not isinstance(game_object, GameObject): - return False - return CommonObjectTagUtils.has_game_tags(game_object, ( - CommonGameTag.FUNC_BED, - CommonGameTag.FUNC_DOUBLE_BED, - CommonGameTag.FUNC_SINGLE_BED, - CommonGameTag.FUNC_TODDLER_BED, - CommonGameTag.FUNC_BED_KID, - CommonGameTag.FUNC_PET_BED, - CommonGameTag.BUY_CAT_SS_BED, - CommonGameTag.BUY_CAT_SS_BED_SINGLE, - CommonGameTag.BUY_CAT_SS_BED_DOUBLE, - CommonGameTag.BUY_CAT_SS_PET_BED, - CommonGameTag.FUNC_DOCTOR_OBJECT_EXAM_BED, - CommonGameTag.FUNC_ACTOR_CAREER_HOSPITAL_EXAM_BED - )) - - @staticmethod - def is_human_sim_bed(game_object: GameObject) -> bool: - """is_human_sim_bed(game_object) - - Determine if an Object is a Bed for Human Sims. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if the Object is a Bed for Human Sims. False, if not. - :rtype: bool - """ - if not isinstance(game_object, GameObject): - return False - return CommonObjectTagUtils.has_game_tags(game_object, ( - CommonGameTag.FUNC_BED, - CommonGameTag.FUNC_DOUBLE_BED, - CommonGameTag.FUNC_SINGLE_BED, - CommonGameTag.FUNC_TODDLER_BED, - CommonGameTag.FUNC_BED_KID - )) - - @staticmethod - def is_pet_sim_bed(game_object: GameObject) -> bool: - """is_pet_sim_bed(game_object) - - Determine if an Object is a Bed for Pet Sims. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if the Object is a Bed for Pet Sims. False, if not. - :rtype: bool - """ - if not isinstance(game_object, GameObject): - return False - return CommonObjectTagUtils.has_game_tags(game_object, ( - CommonGameTag.FUNC_BED, - CommonGameTag.FUNC_PET_BED, - CommonGameTag.BUY_CAT_SS_BED_SINGLE, - CommonGameTag.BUY_CAT_SS_BED_DOUBLE, - CommonGameTag.BUY_CAT_SS_PET_BED, - )) - - @staticmethod - def is_adult_bed(game_object: GameObject) -> bool: - """is_adult_bed(game_object) - - Determine if an Object is a Bed for Adult Sims. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if the Object is a Bed for Adult Sims. False, if not. - :rtype: bool - """ - if not isinstance(game_object, GameObject): - return False - return CommonObjectTagUtils.has_game_tags(game_object, ( - CommonGameTag.FUNC_BED, - CommonGameTag.FUNC_DOUBLE_BED, - CommonGameTag.FUNC_SINGLE_BED - )) - - @staticmethod - def is_child_bed(game_object: GameObject) -> bool: - """is_adult_bed(game_object) - - Determine if an Object is a Bed for Child Sims. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if the Object is a Bed for Child Sims. False, if not. - :rtype: bool - """ - if not isinstance(game_object, GameObject): - return False - return CommonObjectTagUtils.has_game_tags(game_object, ( - CommonGameTag.FUNC_BED, - CommonGameTag.FUNC_BED_KID, - )) - - @staticmethod - def is_toddler_bed(game_object: GameObject) -> bool: - """is_toddler_bed(game_object) - - Determine if an Object is a Bed for Toddler Sims. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if the Object is a Bed for Toddler Sims. False, if not. - :rtype: bool - """ - if not isinstance(game_object, GameObject): - return False - return CommonObjectTagUtils.has_game_tags(game_object, ( - CommonGameTag.FUNC_TODDLER_BED, - )) - - @staticmethod - def is_single_bed(game_object: GameObject) -> bool: - """is_single_bed(game_object) - - Determine if an Object is a Single Bed. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if the Object is a Single Bed. False, if not. - :rtype: bool - """ - if not isinstance(game_object, GameObject): - return False - return CommonObjectTagUtils.has_game_tags(game_object, ( - CommonGameTag.FUNC_SINGLE_BED, - CommonGameTag.BUY_CAT_SS_BED_SINGLE - )) - - @staticmethod - def is_double_bed(game_object: GameObject) -> bool: - """is_double_bed(game_object) - - Determine if an Object is a Double Bed. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if the Object is a Double Bed. False, if not. - :rtype: bool - """ - if not isinstance(game_object, GameObject): - return False - return CommonObjectTagUtils.has_game_tags(game_object, ( - CommonGameTag.FUNC_DOUBLE_BED, - CommonGameTag.BUY_CAT_SS_BED_DOUBLE - )) - - @staticmethod - def is_light(game_object: GameObject) -> bool: - """is_light(game_object) - - Determine if an Object is a Light. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if the Object is a Light. False, if not. - :rtype: bool - """ - if not isinstance(game_object, GameObject): - return False - return CommonObjectTagUtils.has_game_tags(game_object, ( - CommonGameTag.BUY_CAT_LD_WALL_LIGHT, - CommonGameTag.BUY_CAT_LD_OUTDOOR_LIGHT, - CommonGameTag.BUY_CAT_LD_CEILING_LIGHT, - CommonGameTag.BUY_CAT_LD_NIGHT_LIGHT, - CommonGameTag.BUY_CAT_LD_MISC_LIGHT, - CommonGameTag.FUNC_LIGHT_NON_ELECTRIC, - CommonGameTag.FUNC_POOL_LIGHT, - CommonGameTag.FUNC_BUSINESS_LIGHT, - CommonGameTag.FUNC_LASER_LIGHT, - CommonGameTag.FUNC_RETAIL_NEON_LIGHT, - CommonGameTag.STYLE_FESTIVAL_LIGHT, - CommonGameTag.FUNC_HOLIDAY_FESTIVE_LIGHTING - )) - - @staticmethod - def is_stair(game_object: GameObject) -> bool: - """is_stair(game_object) - - Determine if an Object is a Stair. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if the Object is a Stair. False, if not. - :rtype: bool - """ - if not isinstance(game_object, GameObject): - return False - return CommonObjectTagUtils.has_game_tags(game_object, ( - CommonGameTag.BUILD_STAIR, - )) - - @staticmethod - def is_door(game_object: GameObject) -> bool: - """is_door(game_object) - - Determine if an Object is a Door. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if the Object is a Door. False, if not. - :rtype: bool - """ - if not isinstance(game_object, GameObject): - return False - from objects.doors.door import Door - return isinstance(game_object, Door) or CommonObjectTagUtils.has_game_tags(game_object, ( - CommonGameTag.BUILD_DOOR, - CommonGameTag.BUILD_DOOR_SINGLE, - CommonGameTag.BUILD_DOOR_DOUBLE, - CommonGameTag.FUNC_GATE, - CommonGameTag.BUILD_GATE, - CommonGameTag.BUILD_GATE_SINGLE, - CommonGameTag.BUILD_GATE_DOUBLE, - CommonGameTag.FUNC_TEMPLE_GATE, - CommonGameTag.FUNC_ACTOR_CAREER_CELL_DOOR, - CommonGameTag.FUNC_LAB_DOOR, - CommonGameTag.FUNC_VAULT_DOOR, - CommonGameTag.FUNC_ACTOR_CAREER_STUDIO_DOOR_PRIVATE, - CommonGameTag.FUNC_INVESTIGATION_SEALED_DOOR_HALLWAY, - CommonGameTag.FUNC_INVESTIGATION_SEALED_DOOR_MOTHER_PLANT - )) - - @staticmethod - def is_fence(game_object: GameObject) -> bool: - """is_fence(game_object) - - Determine if an Object is a Fence. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if the Object is a Door. False, if not. - :rtype: bool - """ - if not isinstance(game_object, GameObject): - return False - return CommonObjectTypeUtils.is_door(game_object) and CommonObjectTagUtils.has_game_tags(game_object, ( - CommonGameTag.BUILD_FENCE, - )) - - @staticmethod - def is_swimming_pool(game_object: GameObject) -> bool: - """is_swimming_pool(game_object) - - Determine if an Object is a Swimming Pool. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if the Object is a Swimming Pool. False, if not. - :rtype: bool - """ - if not isinstance(game_object, GameObject): - return False - return isinstance(game_object, SwimmingPool) - - @staticmethod - def is_swimming_pool_seat(game_object: GameObject) -> bool: - """is_swimming_pool_seat(game_object) - - Determine if an Object is a Swimming Pool Seat. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if the Object is a Swimming Pool Seat. False, if not. - :rtype: bool - """ - if not isinstance(game_object, GameObject): - return False - return isinstance(game_object, PoolSeat) - - @staticmethod - def is_cow(game_object: GameObject) -> bool: - """is_cow(game_object) - - Determine if an Object is a Cow. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if the Object is a Cow. False, if not. - :rtype: bool - """ - return CommonObjectTagUtils.has_game_tags(game_object, (CommonGameTag.FUNC_COW, CommonGameTag.FUNC_ANIMAL_OBJECT_LIVESTOCK_COW)) - - @staticmethod - def is_dolphin(game_object: GameObject) -> bool: - """is_dolphin(game_object) - - Determine if an Object is a Dolphin. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if the Object is a Dolphin. False, if not. - :rtype: bool - """ - return CommonObjectTagUtils.has_game_tags(game_object, ( - CommonGameTag.FUNC_DOLPHIN_ALBINO, - CommonGameTag.FUNC_DOLPHIN_MERFOLK, - CommonGameTag.FUNC_DOLPHIN_SPAWNER, - CommonGameTag.FUNC_DOLPHIN_STANDARD - )) - - @staticmethod - def is_llama(game_object: GameObject) -> bool: - """is_llama(game_object) - - Determine if an Object is a Llama. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if the Object is a Llama. False, if not. - :rtype: bool - """ - return CommonObjectTagUtils.has_game_tags(game_object, (CommonGameTag.FUNC_LLAMA, CommonGameTag.FUNC_ANIMAL_OBJECT_LIVESTOCK_LLAMA)) - - @staticmethod - def is_livestock(game_object: GameObject) -> bool: - """is_livestock(game_object) - - Determine if an Object is considered to be Livestock. - - .. note:: Objects considered to be Livestock are Llamas and Cows. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if the Object is Livestock. False, if not. - :rtype: bool - """ - return CommonObjectTypeUtils.is_cow(game_object) or CommonObjectTypeUtils.is_llama(game_object) or CommonObjectTagUtils.has_game_tags(game_object, (CommonGameTag.FUNC_ANIMAL_OBJECT_LIVESTOCK,)) - - @staticmethod - def is_hen(game_object: GameObject) -> bool: - """is_hen(game_object) - - Determine if an Object is a Hen. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if the Object is a Hen. False, if not. - :rtype: bool - """ - return CommonObjectTagUtils.has_game_tags(game_object, (CommonGameTag.FUNC_HEN, CommonGameTag.FUNC_ANIMAL_OBJECT_LIVESTOCK_CHICKEN_HEN)) - - @staticmethod - def is_rooster(game_object: GameObject) -> bool: - """is_rooster(game_object) - - Determine if an Object is a Rooster. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if the Object is a Rooster. False, if not. - :rtype: bool - """ - return CommonObjectTagUtils.has_game_tags(game_object, (CommonGameTag.FUNC_ROOSTER, CommonGameTag.FUNC_ANIMAL_OBJECT_LIVESTOCK_CHICKEN_ROOSTER)) - - @staticmethod - def is_chicken(game_object: GameObject) -> bool: - """is_chicken(game_object) - - Determine if an Object is a Chicken. - - .. note:: A Chicken is either a Hen or Rooster. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if the Object is a Chicken. False, if not. - :rtype: bool - """ - return CommonObjectTypeUtils.is_hen(game_object) or CommonObjectTypeUtils.is_rooster(game_object) or CommonObjectTagUtils.has_game_tags(game_object, (CommonGameTag.FUNC_ANIMAL_OBJECT_LIVESTOCK_CHICKEN, )) - - @staticmethod - def is_rabbit(game_object: GameObject) -> bool: - """is_rabbit(game_object) - - Determine if an Object is a Rabbit. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if the Object is a Rabbit. False, if not. - :rtype: bool - """ - return CommonObjectTagUtils.has_game_tags(game_object, (CommonGameTag.FUNC_ANIMAL_OBJECT_WILD_RABBIT,)) - - @staticmethod - def is_vacuum_cleaner(game_object: GameObject) -> bool: - """is_vacuum_cleaner(game_object) - - Determine if an Object is a Vacuum Cleaner. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if the Object is a Vacuum Cleaner. False, if not. - :rtype: bool - """ - return CommonObjectTagUtils.has_game_tags(game_object, ( - CommonGameTag.FUNC_VACUUM_CLEANER, - CommonGameTag.FUNC_VACUUM_CLEANER_HANDHELD, - CommonGameTag.FUNC_VACUUM_CLEANER_HIGH, - CommonGameTag.FUNC_VACUUM_CLEANER_LOW, - CommonGameTag.FUNC_VACUUM_CLEANER_MED, - CommonGameTag.FUNC_VACUUM_CLEANER_UPRIGHT - )) diff --git a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_utils.py b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_utils.py deleted file mode 100644 index a14c3ee..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_utils.py +++ /dev/null @@ -1,314 +0,0 @@ -""" -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 -""" -from objects.base_object import BaseObject -from typing import Callable, Iterator, Union -import services -from objects.definition import Definition -from objects.game_object import GameObject -from objects.object_manager import ObjectManager -from objects.script_object import ScriptObject -from s4ap.sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils - - -class CommonObjectUtils(_HasS4CLClassLog): - """Utilities for retrieving Objects in various ways. - - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 'common_object_utils' - - @classmethod - def create_unique_identifier(cls, game_object: GameObject) -> int: - """create_unique_identifier(game_object) - - Create a unique identifier for an Object. - - .. note:: The unique identifier will be the same for all objects of the same type. For Example, with two The Ambassador toilets they will have the same unique identifier. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: An identifier that uniquely identifies a specific type of Object. - :rtype: int - """ - guid64 = cls.get_object_guid(game_object) - catalog_name = cls.get_catalog_name(game_object) - hash_value = 0x09D05916 ^ min(guid64, catalog_name) - hash_value = (((0x000F4243 * hash_value) >> 4) & 0x0FFFFFFF) ^ max(guid64, catalog_name) - hash_value = abs(hash_value ^ 2) - return hash_value - - @classmethod - def get_object_id(cls, object_instance: BaseObject) -> int: - """get_object_id(object_instance) - - Retrieve the decimal identifier of an Object. - - :param object_instance: An instance of an Object. - :type object_instance: BaseObject - :return: The decimal identifier of the BaseObject or -1 if the id could not be gained. - :rtype: int - """ - if object_instance is None: - return -1 - return object_instance.id or getattr(object_instance, 'id', -1) - - @classmethod - def get_object_guid(cls, game_object: GameObject) -> int: - """get_object_guid(game_object) - - Retrieve the GUID of an Object. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: The GUID of the specified Object or -1 if it does not have one. - :rtype: int - """ - if game_object is None or not hasattr(game_object, 'guid64'): - return -1 - return getattr(game_object, 'guid64', -1) - - @classmethod - def get_object_definition(cls, game_object: Union[int, GameObject], pack_safe: bool = False, get_fallback_definition_id: bool = True) -> Definition: - """get_object_definition(game_object, pack_safe=False, get_fallback_definition_id=True) - - Retrieve the definition for an Object. - - :param game_object: The decimal identifier of an Object or a Game Object. - :type game_object: Union[int, GameObject] - :param pack_safe: If true, objects will be searched for keeping package safety in mind. Default is False. - :type pack_safe: bool, optional - :param get_fallback_definition_id: Set True, to locate a fallback definition id. Default is True. - :type get_fallback_definition_id: bool, optional - :return: The definition of the object with the id. - :rtype: Definition - """ - game_object_instance = cls.get_game_object(game_object) - if game_object_instance is not None: - if hasattr(game_object_instance, 'definition') and game_object_instance.definition is not None: - return game_object_instance.definition - if hasattr(game_object, 'definition') and game_object.definition is not None: - return game_object.definition - return services.definition_manager().get(game_object, pack_safe=pack_safe, get_fallback_definition_id=get_fallback_definition_id) - - @classmethod - def get_object_definition_id(cls, game_object: Union[int, GameObject], pack_safe: bool = False, get_fallback_definition_id: bool = True) -> Union[int, None]: - """get_object_definition_id(game_object, pack_safe=False, get_fallback_definition_id=True) - - Retrieve the definition for an Object. - - :param game_object: The decimal identifier of an Object or a Game Object. - :type game_object: Union[int, GameObject] - :param pack_safe: If true, objects will be searched for keeping package safety in mind. Default is False. - :type pack_safe: bool, optional - :param get_fallback_definition_id: Set True, to locate a fallback definition id. Default is True. - :type get_fallback_definition_id: bool, optional - :return: The id of the definition of the object with the id. - :rtype: Union[int, None] - """ - definition = cls.get_object_definition(game_object, pack_safe=pack_safe, get_fallback_definition_id=get_fallback_definition_id) - if definition is None: - return None - return definition.id - - @classmethod - def get_game_object_definition(cls, game_object: GameObject, pack_safe: bool = False, get_fallback_definition_id: bool = True) -> Union[Definition, None]: - """get_game_object_definition(game_object, pack_safe=False, get_fallback_definition_id=True) - - Retrieve the definition for an Object. - - :param game_object: An instance of a GameObject. - :type game_object: GameObject - :param pack_safe: If true, objects will be searched for keeping package safety in mind. Default is False. - :type pack_safe: bool, optional - :param get_fallback_definition_id: Set True, to locate a fallback definition id. Default is True. - :type get_fallback_definition_id: bool, optional - :return: The definition of the Game Object or None if no definition is found. - :rtype: Definition - """ - if game_object is None: - return None - if hasattr(game_object, 'definition') and game_object.definition is not None: - return game_object.definition - game_object_id = cls.get_object_id(game_object) - if game_object_id is None or game_object_id == -1: - return None - return services.definition_manager().get(game_object_id, pack_safe=pack_safe, get_fallback_definition_id=get_fallback_definition_id) - - @classmethod - def get_game_object_definition_id(cls, game_object: GameObject, pack_safe: bool = False, get_fallback_definition_id: bool = True) -> Union[int, None]: - """get_game_object_definition(game_object, pack_safe=False, get_fallback_definition_id=True) - - Retrieve the definition for an Object. - - :param game_object: An instance of a GameObject. - :type game_object: GameObject - :param pack_safe: If true, objects will be searched for keeping package safety in mind. Default is False. - :type pack_safe: bool, optional - :param get_fallback_definition_id: Set True, to locate a fallback definition id. Default is True. - :type get_fallback_definition_id: bool, optional - :return: The id of the definition of the Game Object or None if no definition is found. - :rtype: Union[int, None] - """ - definition = cls.get_game_object_definition(game_object, pack_safe=pack_safe, get_fallback_definition_id=get_fallback_definition_id) - if definition is None: - return None - return definition.id - - @classmethod - def get_catalog_name(cls, game_object: GameObject) -> int: - """get_catalog_name(game_object) - - Retrieve the catalog name identifier of an Object. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: The decimal identifier of the catalog name of an Object or -1 if no catalog name is found. - :rtype: int - """ - if game_object is None: - return -1 - return game_object.catalog_name - - @classmethod - def get_game_object(cls, game_object_id: int) -> GameObject: - """get_game_object(game_object_id) - - Retrieve an instance of an Object in the game world. - - :param game_object_id: The decimal identifier of an Object. - :type game_object_id: int - :return: An instance of an Object or None if not found. - :rtype: GameObject - """ - return cls.get_game_object_manager().get(game_object_id) - - @classmethod - def has_root_parent(cls, object_instance: ScriptObject) -> bool: - """has_root_parent(object_instance) - - Determine if an Object has a root parent. - - :param object_instance: An instance of an Object. - :type object_instance: ScriptObject - :return: True, if the Object has a root parent. False, if not. - :rtype: bool - """ - if object_instance is None: - return False - return object_instance.parent is not None - - @classmethod - def get_root_parent(cls, object_instance: ScriptObject) -> Union[ScriptObject, None]: - """get_root_parent(object_instance) - - Retrieve the root parent of an Object. - - :param object_instance: An instance of an Object. - :type object_instance: ScriptObject - :return: The root parent of the Object or None if a problem occurs. - :rtype: Union[ScriptObject, None] - """ - if object_instance is None or object_instance.parent is None: - return object_instance - return cls.get_root_parent(object_instance.parent) or object_instance - - @classmethod - def get_instance_for_all_game_objects_generator( - cls, - include_object_callback: Callable[[GameObject], bool] = None - ) -> Iterator[GameObject]: - """get_instance_for_all_objects_generator(include_object_callback=None) - - Retrieve an instance for each and every Object in the game world. - - :param include_object_callback: If the result of this callback is True, the Object will be included in the\ - results. If set to None, All Objects will be included. - :type include_object_callback: Callable[[GameObject], bool], optional - :return: An iterator of all Objects matching the `include_object_callback` filter. - :rtype: Iterator[GameObject] - """ - game_object_list = tuple(cls.get_game_object_manager().get_all()) - for game_object in game_object_list: - if game_object is None: - continue - if include_object_callback is not None and not include_object_callback(game_object): - continue - yield game_object - - @classmethod - def get_instance_for_all_visible_game_objects_generator( - cls, - include_object_callback: Callable[[GameObject], bool] = None - ) -> Iterator[GameObject]: - """get_instance_for_all_visible_objects_generator(include_object_callback=None) - - Retrieve an instance for each and every visible Object in the game world. - - :param include_object_callback: If the result of this callback is True, the Object will be included in the results. If set to None, All Objects will be included. - :type include_object_callback: Callable[[GameObject], bool], optional - :return: An iterator of all Objects matching the `include_object_callback` filter. - :rtype: Iterator[GameObject] - """ - def _is_visible(_game_object: GameObject) -> bool: - return not _game_object.is_hidden() - - include_object_callback = CommonFunctionUtils.run_predicates_as_one((_is_visible, include_object_callback)) - - for game_object in cls.get_instance_for_all_game_objects_generator( - include_object_callback=include_object_callback - ): - yield game_object - - @classmethod - def get_game_object_manager(cls) -> ObjectManager: - """get_game_object_manager() - - Retrieve the manager that manages all Game Objects in a game world. - - :return: The manager that manages all Game Objects in a game world. - :rtype: ObjectManager - """ - return services.object_manager() - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_testing.print_objects', - 'Print a list of all objects.' -) -def _s4cl_testing_log_all_objects(output: CommonConsoleCommandOutput): - log = CommonObjectUtils.get_log() - try: - log.enable() - output(f'Printing a list of all objects.') - log.debug(f'Printing a list of all objects.') - all_objects_str_list = list() - for game_object in CommonObjectUtils.get_instance_for_all_game_objects_generator(): - object_id = CommonObjectUtils.get_object_id(game_object) - from s4ap.sims4communitylib.utils.objects.common_object_location_utils import CommonObjectLocationUtils - object_location = CommonObjectLocationUtils.get_location(game_object) - from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils - if CommonTypeUtils.is_sim_or_sim_info(game_object): - all_objects_str_list.append(f'Sim {game_object} ({object_id}): Loc: {object_location}') - else: - all_objects_str_list.append(f'Object {game_object} ({object_id}): Loc: {object_location}') - - all_objects_str_list = sorted(all_objects_str_list) - for all_objects_str in all_objects_str_list: - output(all_objects_str) - log.debug(all_objects_str) - log.debug('Done printing a list of all objects.') - finally: - log.disable() diff --git a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_visibility_utils.py b/Scripts/s4ap/sims4communitylib/utils/objects/common_object_visibility_utils.py deleted file mode 100644 index 8a69f56..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/objects/common_object_visibility_utils.py +++ /dev/null @@ -1,82 +0,0 @@ -""" -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 -""" -from objects.game_object import GameObject -from objects.persistence_groups import PersistenceGroups - - -class CommonObjectVisibilityUtils: - """Utilities for manipulating the visibility and persistence of Objects. - - """ - - @staticmethod - def set_opacity(game_object: GameObject, opacity: int) -> bool: - """set_opacity(game_object, opacity) - - Set the opacity of an Object. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :param opacity: Determines how opaque the Object will be. - :type opacity: int - :return: True, if successful. False, if not. - :rtype: bool - """ - if game_object is None or opacity is None: - return False - game_object.opacity = opacity - return True - - @staticmethod - def get_opacity(game_object: GameObject) -> int: - """get_opacity(game_object) - - Retrieve the opacity of an Object. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: How opaque the Object is. - :rtype: int - """ - if game_object is None: - return 0 - # noinspection PyPropertyAccess - return game_object.opacity - - @staticmethod - def set_persistence_group(game_object: GameObject, persistence_group: PersistenceGroups) -> bool: - """set_persistence_group(game_object, persistence_group) - - Set the persistence group of an Object. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :param persistence_group: The PersistenceGroup of the Object. - :type persistence_group: PersistenceGroups - :return: True, if successful. False, if not. - :rtype: bool - """ - if game_object is None or persistence_group is None: - return False - game_object.persistence_group = persistence_group - return True - - @staticmethod - def get_persistence_group(game_object: GameObject) -> PersistenceGroups: - """get_persistence_group(game_object) - - Retrieve the persistence group of an Object. - - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: The persistence group of the Object. - :rtype: PersistenceGroups, optional - """ - if game_object is None: - return PersistenceGroups.NONE - return game_object.persistence_group diff --git a/Scripts/s4ap/sims4communitylib/utils/resources/__init__.py b/Scripts/s4ap/sims4communitylib/utils/resources/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/resources/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/utils/resources/common_club_utils.py b/Scripts/s4ap/sims4communitylib/utils/resources/common_club_utils.py deleted file mode 100644 index 8acc828..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/resources/common_club_utils.py +++ /dev/null @@ -1,78 +0,0 @@ -""" -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 -""" -from typing import Iterator, Callable - -import services -from clubs.club import Club -from clubs.club_tuning import ClubRule -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils - - -class CommonClubUtils: - """ Utilities for manipulating Clubs. """ - - @staticmethod - def get_clubs_currently_gathering_gen(include_club_callback: Callable[[Club], bool] = CommonFunctionUtils.noop_true) -> Iterator[Club]: - """get_clubs_currently_gathering_gen(include_club_callback=CommonFunctionUtils.noop_true) - - Retrieve all Clubs that are currently hosting a gathering. - - :param include_club_callback: If the result of this callback is True, the Club will be included in the results. The default callback will allow all. - :type include_club_callback: Callable[[Club], bool], optional - :return: An iterator of all Clubs that are currently gathering and that pass the include callback filter. - :rtype: Iterator[Club] - """ - from clubs.club_service import ClubService - club_service: ClubService = services.get_club_service() - if club_service is None: - return tuple() - for club in club_service.clubs_to_gatherings_map.keys(): - if club is None or not include_club_callback(club): - continue - yield club - - @staticmethod - def get_club_members_gen(club: Club, include_club_member_callback: Callable[[SimInfo], bool] = CommonFunctionUtils.noop_true) -> Iterator[SimInfo]: - """get_club_members_gen(club, include_club_member_callback=CommonFunctionUtils.noop_true) - - Retrieve the SimInfo of all members who are a part of a Club. - - :param club: An instance of a Club. - :type club: Club - :param include_club_member_callback: If the result of this callback is True, the Club Member will be included in the results. The default callback will allow all. - :type include_club_member_callback: Callable[[SimInfo], bool], optional - :return: An iterator of all Sims in a Club that pass the include callback filter. - :rtype: Iterator[SimInfo] - """ - from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - for member_sim in club.members: - sim_info = CommonSimUtils.get_sim_info(member_sim) - if not include_club_member_callback(sim_info): - continue - yield sim_info - - @staticmethod - def get_club_rules_gen(club: Club, include_club_rule_callback: Callable[[SimInfo], bool] = CommonFunctionUtils.noop_true) -> Iterator[ClubRule]: - """get_club_rules_gen(club, include_club_rule_callback=CommonFunctionUtils.noop_true) - - Retrieve all Club Rules of a Club. - - :param club: An instance of a Club. - :type club: Club - :param include_club_rule_callback: If the result of this callback is True, the Club Rule will be included in the results. The default callback will allow all. - :type include_club_rule_callback: Callable[[ClubRule], bool], optional - :return: An iterator of all Club Rules for the specified Club that pass the include callback filter. - :rtype: Iterator[ClubRule] - """ - if club is None: - return tuple() - for club_rule in club.rules: - if club_rule is None or not include_club_rule_callback(club_rule): - continue - yield club_rule diff --git a/Scripts/s4ap/sims4communitylib/utils/resources/common_game_pack_utils.py b/Scripts/s4ap/sims4communitylib/utils/resources/common_game_pack_utils.py deleted file mode 100644 index 2a595f1..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/resources/common_game_pack_utils.py +++ /dev/null @@ -1,68 +0,0 @@ -""" -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 -""" -from typing import Tuple - -from sims4.common import Pack - - -class CommonGamePackUtils: - """ Utilities for checking various information about Game Packs and their availability. """ - - @staticmethod - def has_game_pack_available(game_pack: Pack) -> bool: - """has_game_pack_available(game_pack) - - Whether or not the specified Game Pack is available. - - :param game_pack: The Game Pack to check for. - :type game_pack: Pack - :return: True, if the specified Game Pack is available. False, if not. - :rtype: bool - """ - from sims4.common import is_available_pack - return is_available_pack(game_pack) - - @staticmethod - def has_game_packs_available(game_packs: Tuple[Pack]) -> bool: - """has_game_packs_available(game_packs) - - Whether or not the specified Game Pack is available. - - :param game_packs: The Game Packs to check for. - :type game_packs: Tuple[Pack] - :return: True, if all of the specified Game Packs are available. False, if any of them are not available. - :rtype: bool - """ - from sims4.common import are_packs_available - return are_packs_available(game_packs) - - @staticmethod - def get_available_game_packs() -> Tuple[Pack]: - """get_available_game_packs() - - Retrieve a collection of all available Game Packs. - - :return: A collection of all Game Packs currently available and installed. - :rtype: Tuple[Pack] - """ - from sims4.common import get_available_packs - return tuple(get_available_packs()) - - @staticmethod - def get_game_pack_name(game_pack: Pack) -> str: - """get_game_pack_name(game_pack) - - Retrieve the name of a Game Pack. - - :param game_pack: The Game Pack to retrieve the name of. - :type game_pack: Pack - :return: The name of the Game Pack or if not available. - :rtype: str - """ - from sims4.common import get_pack_name - return get_pack_name(game_pack) diff --git a/Scripts/s4ap/sims4communitylib/utils/resources/common_interaction_utils.py b/Scripts/s4ap/sims4communitylib/utils/resources/common_interaction_utils.py deleted file mode 100644 index 2e69c45..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/resources/common_interaction_utils.py +++ /dev/null @@ -1,434 +0,0 @@ -""" -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 -""" -from typing import Union, Iterator, Any, Tuple, List - -from interactions.base.immediate_interaction import ImmediateSuperInteraction -from interactions.base.interaction import Interaction -from interactions.base.mixer_interaction import MixerInteraction -from interactions.base.super_interaction import SuperInteraction -from interactions.context import InteractionContext -from interactions.interaction_instance_manager import InteractionInstanceManager -from interactions.social.social_mixer_interaction import SocialMixerInteraction -from interactions.social.social_super_interaction import SocialSuperInteraction -from protocolbuffers.Localization_pb2 import LocalizedString -from server.pick_info import PickInfo -from s4ap.sims4communitylib.classes.math.common_surface_identifier import CommonSurfaceIdentifier -from s4ap.sims4communitylib.classes.math.common_vector3 import CommonVector3 -from s4ap.sims4communitylib.enums.interactions_enum import CommonInteractionId -from s4ap.sims4communitylib.enums.tags_enum import CommonGameTag -from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils -from s4ap.sims4communitylib.utils.location.common_location_utils import CommonLocationUtils -from tag import Tag - - -class CommonInteractionUtils: - """Utilities for manipulating Interactions. - - """ - - @staticmethod - def has_any_static_commodities(interaction: Interaction, static_commodity_ids: Iterator[int]) -> bool: - """has_any_static_commodities(interaction, static_commodity_ids) - - Determine if an interaction has any of the specified static commodities. - - :param interaction: An instance of an interaction. - :type interaction: Interaction - :param static_commodity_ids: A collection of static commodity ids. - :type static_commodity_ids: Iterator[int], optional - :return: True, if the interaction has any of the specified static commodities. False, if not. - :rtype: bool - """ - interaction_commodities = interaction.static_commodities - if not interaction_commodities: - return False - static_commodity_ids = tuple(static_commodity_ids) - if not static_commodity_ids: - return True - for static_commodity_id in static_commodity_ids: - for interaction_commodity in interaction_commodities: - interaction_commodity_id = getattr(interaction_commodity, 'guid64', None) - if static_commodity_id == interaction_commodity_id: - return True - return False - - @staticmethod - def has_all_static_commodities(interaction: Interaction, static_commodity_ids: Iterator[int]) -> bool: - """has_all_static_commodities(interaction, static_commodity_ids) - - Determine if an interaction has all the specified static commodities. - - :param interaction: An instance of an interaction. - :type interaction: Interaction - :param static_commodity_ids: A collection of static commodity ids. - :type static_commodity_ids: Iterator[int], optional - :return: True, if the interaction has all the specified static commodities. False, if not. - :rtype: bool - """ - interaction_commodities = interaction.static_commodities - if not interaction_commodities: - return False - static_commodity_ids = tuple(static_commodity_ids) - if not static_commodity_ids: - return True - for static_commodity_id in static_commodity_ids: - has_commodity = False - for interaction_commodity in interaction_commodities: - interaction_commodity_id = getattr(interaction_commodity, 'guid64', None) - if static_commodity_id == interaction_commodity_id: - has_commodity = True - break - if not has_commodity: - return False - return True - - @staticmethod - def has_any_appropriateness_tags(interaction: Interaction, appropriateness_tags: Iterator[CommonGameTag]) -> bool: - """has_any_appropriateness_tags(interaction, appropriateness_tags) - - Determine if an interaction has Appropriateness Tags - - :param interaction: An instance of an interaction. - :type interaction: Interaction - :param appropriateness_tags: A collection of appropriateness tags. - :type appropriateness_tags: Iterator[CommonGameTag] - :return: True, if the Interaction has any of the specified appropriateness tags. False, if not. - :rtype: bool - """ - if interaction.appropriateness_tags is None: - return False - appropriateness_tags = tuple(appropriateness_tags) - if not appropriateness_tags: - return False - for appropriateness_tag in interaction.appropriateness_tags: - appropriateness_tag_converted = CommonResourceUtils.get_enum_by_int_value(int(appropriateness_tag), CommonGameTag, default_value=int(appropriateness_tag)) - if appropriateness_tag_converted is None: - continue - if appropriateness_tag_converted in appropriateness_tags: - return True - return False - - @staticmethod - def has_all_appropriateness_tags(interaction: Interaction, appropriateness_tags: Iterator[CommonGameTag]) -> bool: - """has_all_appropriateness_tags(interaction, appropriateness_tags) - - Determine if an interaction has Appropriateness Tags - - :param interaction: An instance of an interaction. - :type interaction: Interaction - :param appropriateness_tags: A collection of appropriateness tags. - :type appropriateness_tags: Iterator[CommonGameTag] - :return: True, if the Interaction has all the specified appropriateness tags. False, if not. - :rtype: bool - """ - if interaction.appropriateness_tags is None: - return False - if not appropriateness_tags: - return False - interaction_appropriateness_tags = interaction.appropriateness_tags - for appropriateness_tag in tuple(appropriateness_tags): - tag = CommonResourceUtils.get_enum_by_int_value(int(appropriateness_tag), Tag, default_value=int(appropriateness_tag)) - if tag not in interaction_appropriateness_tags: - return False - return True - - @staticmethod - def get_pick_info_from_interaction_context(interaction_context: InteractionContext) -> Union[PickInfo, None]: - """get_pick_info_from_interaction_context(interaction_context) - - Retrieve the pick info of an interaction context. - - :param interaction_context: An interaction context. - :type interaction_context: InteractionContext - :return: The pick info of the interaction context or None, if not found. - :rtype: PickInfo - """ - if interaction_context is None or interaction_context.pick is None: - return None - return interaction_context.pick - - @staticmethod - def get_picked_routing_surface_from_interaction_context(interaction_context: InteractionContext) -> Union[CommonSurfaceIdentifier, None]: - """get_picked_routing_surface_from_interaction_context(interaction_context) - - Retrieve the picked routing surface from an interaction context. - - :param interaction_context: An interaction context. - :type interaction_context: InteractionContext - :return: The picked routing surface from the interaction context or None if a problem occurs. - :rtype: Union[CommonSurfaceIdentifier, None] - """ - pick_info = CommonInteractionUtils.get_pick_info_from_interaction_context(interaction_context) - if pick_info is None: - return None - return CommonSurfaceIdentifier.from_surface_identifier(pick_info.routing_surface) - - @staticmethod - def get_picked_position_from_interaction_context(interaction_context: InteractionContext) -> Union[CommonVector3, None]: - """get_picked_position_from_interaction_context(interaction_context) - - Retrieve the picked position from an interaction context. - - :param interaction_context: An interaction context. - :type interaction_context: InteractionContext - :return: The picked position from the interaction context or None if a problem occurs. - :rtype: Union[CommonVector3, None] - """ - pick_info = CommonInteractionUtils.get_pick_info_from_interaction_context(interaction_context) - if pick_info is None: - return None - return CommonVector3.from_vector3(pick_info.location) - - @staticmethod - def get_picked_routing_position_from_interaction_context(interaction_context: InteractionContext) -> Union[CommonVector3, None]: - """get_picked_routing_position_from_interaction_context(interaction_context) - - Retrieve the picked routing position from an interaction context. - - :param interaction_context: An interaction context. - :type interaction_context: InteractionContext - :return: The picked routing position with the routing surface applied to it from the interaction context or None if a problem occurs. - :rtype: Union[CommonVector3, None] - """ - pick_info = CommonInteractionUtils.get_pick_info_from_interaction_context(interaction_context) - if pick_info is None: - return None - picked_position = CommonVector3.from_vector3(pick_info.location) - picked_routing_surface = CommonSurfaceIdentifier.from_surface_identifier(pick_info.routing_surface) - picked_position.y = CommonLocationUtils.get_surface_height_at(picked_position.x, picked_position.z, picked_routing_surface) - return picked_position - - @staticmethod - def get_picked_routing_surface_level_from_interaction_context(interaction_context: InteractionContext) -> Union[int, None]: - """get_picked_routing_surface_level_from_interaction_context(interaction_context) - - Retrieve the picked routing surface level from an interaction context. - - :param interaction_context: An interaction context. - :type interaction_context: InteractionContext - :return: The picked routing surface level from the interaction context or None if a problem occurs. - :rtype: Union[int, None] - """ - routing_surface = CommonInteractionUtils.get_picked_routing_surface_from_interaction_context(interaction_context) - if routing_surface is None: - return None - return routing_surface.secondary_id - - @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_mixer_interaction(interaction: Interaction) -> bool: - """is_mixer_interaction(interaction) - - Determine if an interaction is a Mixer interaction. - - :param interaction: An instance of an Interaction. - :type interaction: Interaction - :return: True, if the interaction is a Mixer interaction. False, if not. - """ - if interaction is None: - return False - return isinstance(interaction, MixerInteraction) - - @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 - if isinstance(interaction, SocialMixerInteraction): - return True - if not hasattr(interaction, 'is_social'): - 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 - if isinstance(interaction, SuperInteraction): - return True - if not hasattr(interaction, 'is_super'): - return False - return interaction.is_super - - @staticmethod - def is_immediate_super_interaction(interaction: Interaction) -> bool: - """is_immediate_super_interaction(interaction) - - Determine if an interaction is an Immediate Super interaction. - - :param interaction: An instance of an Interaction. - :type interaction: Interaction - :return: True, if the interaction is an Immediate Super interaction. False, if not. - """ - if interaction is None: - return False - return isinstance(interaction, ImmediateSuperInteraction) - - @staticmethod - def is_social_super_interaction(interaction: Interaction) -> bool: - """is_social_super_interaction(interaction) - - Determine if an interaction is a Social Super interaction. - - :param interaction: An instance of an Interaction. - :type interaction: Interaction - :return: True, if the interaction is a Social Super interaction. False, if not. - """ - if interaction is None: - return False - return isinstance(interaction, SocialSuperInteraction) - - @staticmethod - 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 s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils - if interaction is None or interaction.display_name is None: - return None - display_name_string_id = interaction.display_name._string_id - if not display_name_string_id: - return None - return CommonLocalizationUtils.create_localized_string(display_name_string_id, tokens=tuple(tokens)) - - @staticmethod - 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.__name__ or interaction.__class__.__name__ - except: - # noinspection PyBroadException - try: - return interaction.__name__ - except: - # noinspection PyBroadException - try: - return interaction.__class__.__name__ - except: - return '' - - @staticmethod - 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] = list() - 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 - def load_interaction_by_id(interaction_id: Union[int, CommonInteractionId, Interaction]) -> Union[Interaction, None]: - """load_interaction_by_id(interaction_id) - - Load an instance of an Interaction by its decimal identifier. - - :param interaction_id: The decimal identifier of an Interaction. - :type interaction_id: Union[int, CommonInteractionId, Interaction] - :return: An instance of an Interaction matching the decimal identifier or None if not found. - :rtype: Union[Interaction, None] - """ - if isinstance(interaction_id, Interaction): - return interaction_id - # noinspection PyBroadException - try: - # noinspection PyCallingNonCallable - interaction_instance = interaction_id() - if isinstance(interaction_instance, Interaction): - # noinspection PyTypeChecker - return interaction_id - except: - pass - # noinspection PyBroadException - try: - interaction_id: int = int(interaction_id) - except: - # noinspection PyTypeChecker - interaction_id: Interaction = interaction_id - return interaction_id - - from sims4.resources import Types - from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils - return CommonResourceUtils.load_instance(Types.INTERACTION, interaction_id) - - @staticmethod - def get_instance_manager() -> InteractionInstanceManager: - """get_instance_manager() - - Retrieve the instance manager that manages all tunables for interactions. - - :return: The instance manager that manages all tunables for interactions. - :rtype: InteractionInstanceManager - """ - from sims4.resources import Types - from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils - # noinspection PyTypeChecker - return CommonResourceUtils.get_instance_manager(Types.INTERACTION) diff --git a/Scripts/s4ap/sims4communitylib/utils/resources/common_loot_action_utils.py b/Scripts/s4ap/sims4communitylib/utils/resources/common_loot_action_utils.py deleted file mode 100644 index e75cb3a..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/resources/common_loot_action_utils.py +++ /dev/null @@ -1,105 +0,0 @@ -""" -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 -""" -from typing import Union, Tuple - -from event_testing.resolver import Resolver -from interactions.utils.loot import LootActions - - -class CommonLootActionUtils: - """Utilities for manipulating Loot Actions.""" - @staticmethod - def apply_loot_actions_using_resolver(loot_actions: LootActions, resolver: Resolver) -> bool: - """apply_loot_actions_using_resolver(loot_actions, resolver) - - Apply loot actions using a resolver. - - :param loot_actions: The loot actions to apply. - :type loot_actions: LootActions - :param resolver: A resolver used in various ways by loot actions. The resolver could be a SingleSimResolver, which will attempt to apply the loot to a single Sim, a DoubleSimResolver, which will attempt to apply to two Sims, or various other types of resolvers. - :type resolver: Resolver - :return: True, if the loot actions applied successfully. False, if not. - :rtype: bool - """ - if loot_actions is None: - return False - loot_actions.apply_to_resolver(resolver) - return True - - @staticmethod - def apply_loot_actions_by_id_using_resolver(loot_actions_id: int, resolver: Resolver) -> bool: - """apply_loot_actions_by_id_using_resolver(loot_actions_id, resolver) - - Apply loot actions by id using a resolver. - - :param loot_actions_id: The decimal identifier of a loot actions instance to apply. - :type loot_actions_id: int - :param resolver: A resolver used in various ways by loot actions. The resolver could be a SingleSimResolver, which will attempt to apply the loot to a single Sim, a DoubleSimResolver, which will attempt to apply to two Sims, or various other types of resolvers. - :type resolver: Resolver - :return: True, if the loot actions applied successfully. False, if not. - :rtype: bool - """ - loot_actions = CommonLootActionUtils.load_loot_actions_by_id(loot_actions_id) - if loot_actions is None: - return False - loot_actions.apply_to_resolver(resolver) - return True - - @staticmethod - def apply_loot_actions_by_ids_using_resolver(loot_actions_ids: Tuple[int], resolver: Resolver) -> bool: - """apply_loot_actions_by_ids_using_resolver(loot_actions_ids, resolver) - - Apply loot actions by their ids using a resolver. - - :param loot_actions_ids: A collection of decimal identifiers of LootActions instances to apply. - :type loot_actions_ids: Tuple[int] - :param resolver: A resolver used in various ways by loot actions. The resolver could be a SingleSimResolver, which will attempt to apply the loot to a single Sim, a DoubleSimResolver, which will attempt to apply to two Sims, or various other types of resolvers. - :type resolver: Resolver - :return: True, if at least one of the loot actions applied successfully. False, if not. - :rtype: bool - """ - has_applied_at_least_one = False - for loot_actions_id in loot_actions_ids: - loot_actions = CommonLootActionUtils.load_loot_actions_by_id(loot_actions_id) - if loot_actions is None: - continue - loot_actions.apply_to_resolver(resolver) - has_applied_at_least_one = True - return has_applied_at_least_one - - @staticmethod - def load_loot_actions_by_id(loot_actions_id: Union[int, LootActions]) -> Union[LootActions, None]: - """load_loot_actions_by_id(loot_actions_id) - - Load a Loot Actions instance by its decimal identifier. - - :param loot_actions_id: The decimal identifier of a LootActions instance. - :type loot_actions_id: Union[int, LootActions] - :return: An instance of a Loot Actions matching the decimal identifier or None if not found. - :rtype: Union[LootActions, None] - """ - if isinstance(loot_actions_id, LootActions): - return loot_actions_id - # noinspection PyBroadException - try: - # noinspection PyCallingNonCallable - loot_actions_instance = loot_actions_id() - if isinstance(loot_actions_instance, LootActions): - return loot_actions_id - except: - pass - # noinspection PyBroadException - try: - loot_actions_id: int = int(loot_actions_id) - except: - loot_actions_id: LootActions = loot_actions_id - return loot_actions_id - - from sims4.resources import Types - from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils - return CommonResourceUtils.load_instance(Types.ACTION, loot_actions_id) diff --git a/Scripts/s4ap/sims4communitylib/utils/resources/common_recipe_utils.py b/Scripts/s4ap/sims4communitylib/utils/resources/common_recipe_utils.py deleted file mode 100644 index 0648982..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/resources/common_recipe_utils.py +++ /dev/null @@ -1,128 +0,0 @@ -""" -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 -""" -from crafting.recipe import Recipe -from typing import Callable, Iterator, Union, Tuple, List - -from sims4.resources import Types -from s4ap.sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog - - -class CommonRecipeUtils(_HasS4CLClassLog): - """Utilities for manipulating Recipes in various ways. - - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 'common_recipe_utils' - - @staticmethod - def get_recipe_guid(recipe_identifier: Union[int, Recipe]) -> Union[int, None]: - """get_recipe_guid(recipe_identifier) - - Retrieve the GUID of a Recipe. - - :param recipe_identifier: The identifier or instance of a Recipe. - :type recipe_identifier: Union[int, Recipe] - :return: The decimal identifier of the Recipe or None if the Recipe does not have an id. - :rtype: Union[int, None] - """ - if isinstance(recipe_identifier, int): - return recipe_identifier - return getattr(recipe_identifier, 'guid64', None) - - @staticmethod - def get_short_name(recipe: Recipe) -> Union[str, None]: - """get_short_name(recipe) - - Retrieve the Short Name of a Recipe. - - :param recipe: An instance of a Recipe. - :type recipe: Recipe - :return: The short name of a Recipe or None if a problem occurs. - :rtype: Union[str, None] - """ - if recipe is None: - return None - # noinspection PyBroadException - try: - return recipe.__class__.__name__ - except: - return '' - - @staticmethod - def get_short_names(recipes: Iterator[Recipe]) -> Tuple[str]: - """get_short_names(recipes) - - Retrieve the Short Names of a collection of Recipes. - - :param recipes: A collection of Recipe instances. - :type recipes: Iterator[Recipe] - :return: A collection of short names of all Recipe instances. - :rtype: Tuple[str] - """ - if recipes is None or not recipes: - return tuple() - short_names: List[str] = [] - for recipe in recipes: - # noinspection PyBroadException - try: - short_name = CommonRecipeUtils.get_short_name(recipe) - if not short_name: - continue - except: - continue - short_names.append(short_name) - return tuple(short_names) - - @staticmethod - def get_all_recipes_gen(include_recipe_callback: Callable[[Recipe], bool] = None) -> Iterator[Recipe]: - """get_all_recipes_gen(include_recipe_callback=None) - - Retrieve all Recipes. - - :param include_recipe_callback: If the result of this callback is True, the Recipe will be included in the results. If set to None, All Recipes will be included. - :type include_recipe_callback: Callable[[Recipe], bool], optional - :return: An iterator of Recipes that pass the specified include_recipe_callback. - :rtype: Iterator[Recipe] - """ - from s4ap.sims4communitylib.utils.resources.common_statistic_utils import CommonStatisticUtils - statistic_manager = CommonStatisticUtils.get_statistic_instance_manager() - for recipe in statistic_manager.get_ordered_types(only_subclasses_of=Recipe): - recipe: Recipe = recipe - recipe_id = CommonRecipeUtils.get_recipe_guid(recipe) - if recipe_id is None: - continue - if include_recipe_callback is not None and not include_recipe_callback(recipe): - continue - yield recipe - - @staticmethod - def load_recipe_by_guid(value_id: Union[int, Recipe]) -> Union[Recipe, None]: - """load_recipe_by_guid(recipe_id) - - Load an instance of a Recipe by a GUID. - - :param value_id: The GUID of a Recipe. - :type value_id: Union[int, Recipe] - :return: An instance of a Recipe matching the decimal identifier or None if not found. - :rtype: Union[Recipe, None] - """ - if isinstance(value_id, Recipe) or hasattr(value_id, 'is_recipe'): - return value_id - # noinspection PyBroadException - try: - value_id: int = int(value_id) - except: - # noinspection PyTypeChecker - value_id: Recipe = value_id - return value_id - - from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils - return CommonResourceUtils.load_instance(Types.RECIPE, value_id) diff --git a/Scripts/s4ap/sims4communitylib/utils/resources/common_situation_utils.py b/Scripts/s4ap/sims4communitylib/utils/resources/common_situation_utils.py deleted file mode 100644 index b808191..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/resources/common_situation_utils.py +++ /dev/null @@ -1,329 +0,0 @@ -""" -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 -""" -from typing import Union, Iterator, Tuple, List, Type - -import services -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.enums.situations_enum import CommonSituationId -from s4ap.sims4communitylib.enums.tags_enum import CommonGameTag -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from situations.situation import Situation -from situations.situation_job import SituationJob -from situations.situation_manager import SituationManager - - -class CommonSituationUtils: - """Utilities for manipulating Situations. - - """ - - @staticmethod - def get_situation_id(situation_identifier: Union[int, Situation]) -> Union[int, None]: - """get_situation_id(situation_identifier) - - Retrieve the decimal identifier of a Situation. - - :param situation_identifier: The identifier or instance of a Situation. - :type situation_identifier: Union[int, Situation] - :return: The decimal identifier of the Situation or None if the Situation does not have an id. - :rtype: Union[int, None] - """ - if isinstance(situation_identifier, int): - return situation_identifier - if not hasattr(situation_identifier, 'id'): - return -1 - return situation_identifier.id or getattr(situation_identifier, 'id', -1) - - @staticmethod - def get_situation_guid(situation_identifier: Union[int, Situation]) -> int: - """get_situation_guid(situation_identifier) - - Retrieve the GUID of a Situation. - - :param situation_identifier: The identifier or instance of a Situation. - :type situation_identifier: Union[int, Situation] - :return: The GUID of the specified Situation or -1 if it does not have one. - :rtype: int - """ - if situation_identifier is None: - return -1 - if isinstance(situation_identifier, int): - return situation_identifier - if not hasattr(situation_identifier, 'guid64'): - return -1 - return getattr(situation_identifier, 'guid64', -1) - - @staticmethod - def get_situation_job_guid(situation_job_identifier: Union[int, SituationJob]) -> int: - """get_situation_job_guid(situation_job_identifier) - - Retrieve the GUID of a Situation Job. - - :param situation_job_identifier: The identifier or instance of a Situation Job. - :type situation_job_identifier: Union[int, SituationJob] - :return: The GUID of the specified Situation or -1 if it does not have one. - :rtype: int - """ - if situation_job_identifier is None: - return -1 - if isinstance(situation_job_identifier, int): - return situation_job_identifier - if not hasattr(situation_job_identifier, 'guid64'): - return -1 - return getattr(situation_job_identifier, 'guid64', -1) - - @staticmethod - def get_situation_name(situation: Situation) -> Union[str, None]: - """get_situation_name(situation) - - Retrieve the Name of a Situation. - - :param situation: An instance of a Situation. - :type situation: Situation - :return: The short name of a Situation or None if a problem occurs. - :rtype: Union[str, None] - """ - if situation is None: - return None - # noinspection PyBroadException - try: - return situation.__class__.__name__ or '' - except: - return '' - - @staticmethod - def get_situation_names(situations: Iterator[Situation]) -> Tuple[str]: - """get_situation_names(situations) - - Retrieve the Names of a collection of Situation. - - :param situations: A collection of Situation instances. - :type situations: Iterator[Situation] - :return: A collection of names for all specified Situations. - :rtype: Tuple[str] - """ - if situations is None or not situations: - return tuple() - names: List[str] = [] - for situation in situations: - # noinspection PyBroadException - try: - name = CommonSituationUtils.get_situation_name(situation) - if not name: - continue - except: - continue - names.append(name) - return tuple(names) - - @staticmethod - def get_situation_manager_for_zone(zone_id: int=None) -> SituationManager: - """get_situation_manager_for_zone(zone_id=None) - - Retrieve the situation manager for a zone. - - :param zone_id: The zone to retrieve the situation manager of. Default is None, which is the current zone. - :type zone_id: int, optional - :return: The situation manager for the specified zone. - :rtype: SituationManager - """ - return services.get_zone_situation_manager(zone_id=zone_id) - - @staticmethod - def get_sim_info_for_all_sims_in_situation(situation: Situation) -> Tuple[SimInfo]: - """get_sim_info_for_all_sims_in_situation(situation) - - Retrieve a SimInfo object for all Sims in a Situation. - - :param situation: A situation - :type situation: Situation - :return: A collection of SimInfo for all Sims in the situation. - :rtype: Tuple[SimInfo] - """ - if situation is None: - return tuple() - result: Tuple[SimInfo] = tuple([CommonSimUtils.get_sim_info(_sim) for _sim in situation.all_sims_in_situation_gen()]) - return result - - @staticmethod - def get_sim_info_for_all_sims_in_running_situations_by_type(situation_type: Type[Situation]) -> Tuple[SimInfo]: - """get_sim_info_for_all_sims_in_running_situations_by_type(situation_type) - - Retrieve a SimInfo object for all Sims in a Situation. - - :param situation_type: The type of situation to locate. - :type situation_type: Type[Situation] - :return: A collection of SimInfo for all Sims in the situations that match the specified type. - :rtype: Tuple[SimInfo] - """ - sim_info_list: List[SimInfo] = list() - for situation in CommonSituationUtils.locate_running_situations_by_type(situation_type): - for sim in tuple(situation.all_sims_in_situation_gen()): - sim_info = CommonSimUtils.get_sim_info(sim) - if sim_info is None: - continue - sim_info_list.append(sim_info) - return tuple(sim_info_list) - - @staticmethod - def locate_running_situation_by_id(situation_id: Union[int, CommonSituationId, Situation], zone_id: int=None) -> Union[Situation, None]: - """locate_situation_by_id(situation_id, zone_id=None) - - Locate a running Situation from a Zone by its id. - - :param situation_id: The decimal identifier of a Situation. (Not to be confused with the instance id) - :type situation_id: Union[int, CommonSituationId, Situation] - :param zone_id: The zone to retrieve the situation from. Default is None, which is the current zone. - :type zone_id: int, optional - :return: The situation from the specified zone that matches the specified id or None if not found. - :rtype: Union[Situation, None] - """ - if isinstance(situation_id, Situation): - return situation_id - situation_manager = CommonSituationUtils.get_situation_manager_for_zone(zone_id=zone_id) - return situation_manager.get(situation_id) - - @staticmethod - def locate_first_running_situation_by_type(situation_type: Type[Situation], zone_id: int=None) -> Union[Situation, None]: - """locate_first_running_situation_by_type(situation_type, zone_id=None) - - Locate the first running Situation from a Zone by its Type. - - :param situation_type: The type of situation to search for. - :type situation_type: Type[Situation] - :param zone_id: The zone to locate the situations in. Default is None, which is the current zone. - :type zone_id: int, optional - :return: A collection of situations from the specified zone that have the specified tag. - :rtype: Tuple[Situation] - """ - situations = CommonSituationUtils.locate_running_situations_by_type(situation_type, zone_id=zone_id) - if situations: - return next(iter(situations)) - return None - - @staticmethod - def locate_first_running_situation_by_tag(tag: CommonGameTag, zone_id: int=None) -> Union[Situation, None]: - """locate_first_running_situation_by_tag(situation_type, zone_id=None) - - Locate the first running Situation from a Zone by a tag. - - :param tag: A tag to search for the situation with. - :type tag: CommonGameTag - :param zone_id: The zone to locate the situations in. Default is None, which is the current zone. - :type zone_id: int, optional - :return: A collection of situations from the specified zone that have the specified tag. - :rtype: Tuple[Situation] - """ - situations = CommonSituationUtils.locate_running_situations_by_tag(tag, zone_id=zone_id) - if situations: - return next(iter(situations)) - return None - - @staticmethod - def locate_first_running_situation_by_tags(tags: Iterator[CommonGameTag], zone_id: int=None) -> Union[Situation, None]: - """locate_first_running_situation_by_tag(situation_type, zone_id=None) - - Locate the first running Situation from a Zone by a collection of tags. - - :param tags: A list of tags to search for the situation with. - :type tags: Iterator[CommonGameTag] - :param zone_id: The zone to locate the situations in. Default is None, which is the current zone. - :type zone_id: int, optional - :return: A collection of situations from the specified zone that have the specified tag. - :rtype: Tuple[Situation] - """ - situations = CommonSituationUtils.locate_running_situations_by_tags(tags, zone_id=zone_id) - if situations: - return next(iter(situations)) - return None - - @staticmethod - def locate_running_situations_by_type(situation_type: Type[Situation], zone_id: int=None) -> Tuple[Situation]: - """locate_running_situations_by_type(situation_type, zone_id=None) - - Locate all running Situations in a Zone by Type. - - :param situation_type: The type of situation to search for. - :type situation_type: Type[Situation] - :param zone_id: The zone to locate the situations in. Default is None, which is the current zone. - :type zone_id: int, optional - :return: A collection of situations from the specified zone that have the specified tag. - :rtype: Tuple[Situation] - """ - if situation_type is None: - return tuple() - situation_manager = CommonSituationUtils.get_situation_manager_for_zone(zone_id=zone_id) - return tuple(situation_manager.get_situations_by_type(situation_type)) - - @staticmethod - def locate_running_situations_by_tag(tag: CommonGameTag, zone_id: int=None) -> Tuple[Situation]: - """locate_running_situations_by_tag(tag, zone_id=None) - - Locate all running Situations in a Zone by a tag. - - :param tag: A tag to search for situations with. - :type tag: CommonGameTag - :param zone_id: The zone to locate the situations in. Default is None, which is the current zone. - :type zone_id: int, optional - :return: A collection of situations from the specified zone that have the specified tag. - :rtype: Tuple[Situation] - """ - if tag is None: - return tuple() - return CommonSituationUtils.locate_running_situations_by_tags((tag,), zone_id=zone_id) - - @staticmethod - def locate_running_situations_by_tags(tags: Iterator[CommonGameTag], zone_id: int=None) -> Tuple[Situation]: - """locate_running_situations_by_tags(tags, zone_id=None) - - Locate all running Situations in a Zone by a collection of tags. - - :param tags: A list of tags to search for situations with. - :type tags: Iterator[CommonGameTag] - :param zone_id: The zone to locate the situations in. Default is None, which is the current zone. - :type zone_id: int, optional - :return: A collection of situations from the specified zone that have any of the specified tags. - :rtype: Tuple[Situation] - """ - tags = tuple(tags) - if not tags: - return tuple() - situation_manager: SituationManager = CommonSituationUtils.get_situation_manager_for_zone(zone_id=zone_id) - return tuple(situation_manager.get_situations_by_tags(set(tags))) - - @staticmethod - def load_situation_by_id(situation_guid: Union[int, CommonSituationId, Situation]) -> Union[Situation, None]: - """load_situation_by_id(situation_id) - - Load an instance of a Situation by its decimal identifier (GUID). - - :param situation_guid: The decimal identifier of a Situation. (Not to be confused with the instance id) - :type situation_guid: Union[int, CommonSituationId, Situation] - :return: An instance of a Situation matching the decimal identifier or None if not found. - :rtype: Union[Situation, None] - """ - if isinstance(situation_guid, Situation): - return situation_guid - # noinspection PyBroadException - try: - # noinspection PyCallingNonCallable - situation_instance = situation_guid() - if isinstance(situation_instance, Situation): - return situation_guid - except: - pass - # noinspection PyBroadException - try: - situation_guid: int = int(situation_guid) - except: - situation_guid: Situation = situation_guid - return situation_guid - - from sims4.resources import Types - from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils - return CommonResourceUtils.load_instance(Types.SITUATION, situation_guid) diff --git a/Scripts/s4ap/sims4communitylib/utils/resources/common_skill_utils.py b/Scripts/s4ap/sims4communitylib/utils/resources/common_skill_utils.py deleted file mode 100644 index 41e1574..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/resources/common_skill_utils.py +++ /dev/null @@ -1,121 +0,0 @@ -""" -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 -""" -from typing import Union, Iterator, Tuple, List, Callable -from s4ap.sims4communitylib.enums.skills_enum import CommonSkillId -from statistics.skill import Skill - - -class CommonSkillUtils: - """Utilities for manipulating Skills. - - """ - - @staticmethod - def get_skill_id(skill_identifier: Union[int, Skill]) -> Union[int, None]: - """get_skill_id(skill_identifier) - - Retrieve the decimal identifier of a Skill. - - :param skill_identifier: The identifier or instance of a Skill. - :type skill_identifier: Union[int, Skill] - :return: The decimal identifier of the Skill or None if the Skill does not have an id. - :rtype: Union[int, None] - """ - if isinstance(skill_identifier, int): - return skill_identifier - return getattr(skill_identifier, 'guid64', None) - - @staticmethod - def get_short_name(skill: Skill) -> Union[str, None]: - """get_short_name(skill) - - Retrieve the Short Name of a Skill. - - :param skill: An instance of a Skill. - :type skill: Skill - :return: The short name of a Skill or None if a problem occurs. - :rtype: Union[str, None] - """ - if skill is None: - return None - # noinspection PyBroadException - try: - return skill.__class__.__name__ - except: - return '' - - @staticmethod - def get_short_names(skills: Iterator[Skill]) -> Tuple[str]: - """get_short_names(skills) - - Retrieve the Short Names of a collection of Skills. - - :param skills: A collection of Skill instances. - :type skills: Iterator[Skill] - :return: A collection of short names of all Skill instances. - :rtype: Tuple[str] - """ - if skills is None or not skills: - return tuple() - short_names: List[str] = [] - for skill in skills: - # noinspection PyBroadException - try: - short_name = CommonSkillUtils.get_short_name(skill) - if not short_name: - continue - except: - continue - short_names.append(short_name) - return tuple(short_names) - - @staticmethod - def get_all_skills_gen(include_skill_callback: Callable[[Skill], bool] = None) -> Iterator[Skill]: - """get_all_skills_gen(include_skill_callback=None) - - Retrieve all Skills. - - :param include_skill_callback: If the result of this callback is True, the Skill will be included in the results. If set to None, All Skills will be included. - :type include_skill_callback: Callable[[Skill], bool], optional - :return: An iterator of Skills that pass the specified include_skill_callback. - :rtype: Iterator[Skill] - """ - from s4ap.sims4communitylib.utils.resources.common_statistic_utils import CommonStatisticUtils - statistic_manager = CommonStatisticUtils.get_statistic_instance_manager() - for skill in statistic_manager.get_ordered_types(only_subclasses_of=Skill): - skill: Skill = skill - skill_id = CommonSkillUtils.get_skill_id(skill) - if skill_id is None: - continue - if include_skill_callback is not None and not include_skill_callback(skill): - continue - yield skill - - @staticmethod - def load_skill_by_id(skill_id: Union[int, CommonSkillId, Skill]) -> Union[Skill, None]: - """load_skill_by_id(skill_id) - - Load an instance of a Skill by its decimal identifier. - - :param skill_id: The decimal identifier of a Skill. - :type skill_id: Union[int, CommonSkillId, Skill] - :return: An instance of a Skill matching the decimal identifier or None if not found. - :rtype: Union[Skill, None] - """ - if isinstance(skill_id, Skill) or hasattr(skill_id, 'is_skill'): - return skill_id - # noinspection PyBroadException - try: - skill_id: int = int(skill_id) - except: - # noinspection PyTypeChecker - skill_id: Skill = skill_id - return skill_id - - from s4ap.sims4communitylib.utils.resources.common_statistic_utils import CommonStatisticUtils - return CommonStatisticUtils.load_statistic_by_id(skill_id) diff --git a/Scripts/s4ap/sims4communitylib/utils/resources/common_statistic_utils.py b/Scripts/s4ap/sims4communitylib/utils/resources/common_statistic_utils.py deleted file mode 100644 index 52c8bba..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/resources/common_statistic_utils.py +++ /dev/null @@ -1,131 +0,0 @@ -""" -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 -""" -from typing import Union - -from s4ap.sims4communitylib.enums.statistics_enum import CommonStatisticId -from statistics.base_statistic import BaseStatistic -from statistics.statistic_instance_manager import StatisticInstanceManager - - -class CommonStatisticUtils: - """Utilities for manipulating Statistics. - - """ - @staticmethod - def get_statistic_initial_value(statistic_id: Union[int, CommonStatisticId, BaseStatistic]) -> 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: Union[int, CommonStatisticId, BaseStatistic] - :return: The initial value of the statistic. - :rtype: float - """ - statistic_instance = CommonStatisticUtils.load_statistic_by_id(statistic_id) - if statistic_instance is None: - return -1.0 - if hasattr(statistic_instance, 'get_initial_value'): - return statistic_instance.get_initial_value() - return statistic_instance.default_value - - @staticmethod - def get_statistic_min_value(statistic_id: Union[int, CommonStatisticId, BaseStatistic]) -> 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: Union[int, CommonStatisticId, BaseStatistic] - :return: The minimum value of the statistic. - :rtype: float - """ - statistic_instance = CommonStatisticUtils.load_statistic_by_id(statistic_id) - if statistic_instance is None: - return -1.0 - return statistic_instance.min_value - - @staticmethod - def get_statistic_max_value(statistic_id: Union[int, CommonStatisticId, BaseStatistic]) -> 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: Union[int, CommonStatisticId, BaseStatistic] - :return: The maximum value of the statistic. - :rtype: float - """ - statistic_instance = CommonStatisticUtils.load_statistic_by_id(statistic_id) - if statistic_instance is None: - return -1.0 - return statistic_instance.max_value - - @staticmethod - def get_statistic_id(statistic_identifier: Union[int, BaseStatistic]) -> Union[int, None]: - """get_statistic_id(statistic_identifier) - - Retrieve the decimal identifier of a Statistic. - - :param statistic_identifier: The identifier or instance of a Statistic. - :type statistic_identifier: Union[int, BaseStatistic] - :return: The decimal identifier of the Statistic or None if the Statistic does not have an id. - :rtype: Union[int, None] - """ - if isinstance(statistic_identifier, int): - return statistic_identifier - if hasattr(statistic_identifier, 'id'): - return statistic_identifier.id - return getattr(statistic_identifier, 'guid64', None) - - @staticmethod - def load_statistic_by_id(statistic_id: Union[int, CommonStatisticId, BaseStatistic]) -> Union[BaseStatistic, None]: - """load_statistic_by_id(statistic_id) - - Load an instance of a Statistic by its decimal identifier. - - :param statistic_id: The decimal identifier of a Statistic. - :type statistic_id: Union[int, CommonStatisticId, BaseStatistic] - :return: An instance of a Statistic matching the decimal identifier or None if not found. - :rtype: Union[BaseStatistic, None] - """ - if isinstance(statistic_id, BaseStatistic): - return statistic_id - # noinspection PyBroadException - try: - # noinspection PyCallingNonCallable - statistic_instance = statistic_id() - if isinstance(statistic_instance, BaseStatistic): - return statistic_id - except: - pass - # noinspection PyBroadException - try: - statistic_id: int = int(statistic_id) - except: - # noinspection PyTypeChecker - statistic_id: BaseStatistic = statistic_id - return statistic_id - - from sims4.resources import Types - from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils - return CommonResourceUtils.load_instance(Types.STATISTIC, statistic_id) or CommonResourceUtils.load_instance(Types.STATIC_COMMODITY, statistic_id) - - @staticmethod - def get_statistic_instance_manager() -> StatisticInstanceManager: - """get_statistic_instance_manager() - - Retrieve the manager that manages all Statistics. - - :return: The manager that manages all Statistics. - :rtype: StatisticInstanceManager - """ - from sims4.resources import Types - from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils - # noinspection PyTypeChecker - return CommonResourceUtils.get_instance_manager(Types.STATISTIC) diff --git a/Scripts/s4ap/sims4communitylib/utils/save_load/__init__.py b/Scripts/s4ap/sims4communitylib/utils/save_load/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/save_load/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/utils/save_load/common_save_utils.py b/Scripts/s4ap/sims4communitylib/utils/save_load/common_save_utils.py deleted file mode 100644 index a8d08a8..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/save_load/common_save_utils.py +++ /dev/null @@ -1,56 +0,0 @@ -""" -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 -""" -import services -from typing import Any - - -class CommonSaveUtils: - """ Utilities for managing save files. """ - @staticmethod - def get_save_slot_guid() -> int: - """get_save_slot_guid() - - Retrieve the guid identifier for the current save slot. - - :return: The GUID identifier for the current save slot. - :return: int - """ - return services.get_persistence_service().get_save_slot_proto_guid() - - @staticmethod - def get_save_slot() -> Any: - """get_save_slot() - - Retrieve the current save slot. - - :return: The current save slot. - :return: Any - """ - return services.get_persistence_service().get_save_slot_proto_buff() - - @staticmethod - def get_save_slot_id() -> int: - """get_save_slot_id() - - Retrieve the identifier for the current save slot. - - :return: The identifier for the current save slot. - :return: int - """ - return CommonSaveUtils.get_save_slot().slot_id - - @staticmethod - def get_save_account() -> Any: - """get_save_account() - - Retrieve the current save account. - - :return: The current save account. - :return: Any - """ - return services.get_persistence_service().get_account_proto_buff() diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/__init__.py b/Scripts/s4ap/sims4communitylib/utils/sims/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_age_species_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_age_species_utils.py deleted file mode 100644 index c975355..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_age_species_utils.py +++ /dev/null @@ -1,446 +0,0 @@ -""" -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 -""" -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils -from s4ap.sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils - - -class CommonAgeSpeciesUtils: - """Utilities for checking the Age and Species of Sims. - - """ - @staticmethod - def is_baby_human(sim_info: SimInfo) -> bool: - """is_baby_human(sim_info) - - Determine if a sim is a Baby Human. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is a Baby Human. False, if the Sim is not. - :rtype: bool - """ - return CommonAgeUtils.is_baby(sim_info) and CommonSpeciesUtils.is_human(sim_info) - - @staticmethod - def is_toddler_human(sim_info: SimInfo) -> bool: - """is_toddler_human(sim_info) - - Determine if a sim is a Toddler Human. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is a Toddler Human. False, if the Sim is not. - :rtype: bool - """ - return CommonAgeUtils.is_toddler(sim_info) and CommonSpeciesUtils.is_human(sim_info) - - @staticmethod - def is_child_human(sim_info: SimInfo) -> bool: - """is_child_human(sim_info) - - Determine if a sim is a Child Human. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is a Child Human. False, if the Sim is not. - :rtype: bool - """ - return CommonAgeUtils.is_child(sim_info) and CommonSpeciesUtils.is_human(sim_info) - - @staticmethod - def is_teen_human(sim_info: SimInfo) -> bool: - """is_teen_human(sim_info) - - Determine if a sim is a Teen Human. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is a Teen Human. False, if the Sim is not. - :rtype: bool - """ - return CommonAgeUtils.is_teen(sim_info) and CommonSpeciesUtils.is_human(sim_info) - - @staticmethod - def is_young_adult_human(sim_info: SimInfo) -> bool: - """is_young_adult_human(sim_info) - - Determine if a sim is a Young Adult Human. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is a Young Adult Human. False, if the Sim is not. - :rtype: bool - """ - return CommonAgeUtils.is_young_adult(sim_info) and CommonSpeciesUtils.is_human(sim_info) - - @staticmethod - def is_mature_adult_human(sim_info: SimInfo) -> bool: - """is_mature_adult_human(sim_info) - - Determine if a sim is an Adult Human. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is an Adult Human. False, if the Sim is not. - :rtype: bool - """ - return CommonAgeUtils.is_mature_adult(sim_info) and CommonSpeciesUtils.is_human(sim_info) - - @staticmethod - def is_elder_human(sim_info: SimInfo) -> bool: - """is_elder_human(sim_info) - - Determine if a sim is an Elder Human. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is an Elder Human. False, if the Sim is not. - :rtype: bool - """ - return CommonAgeUtils.is_elder(sim_info) and CommonSpeciesUtils.is_human(sim_info) - - @staticmethod - def is_adult_human(sim_info: SimInfo) -> bool: - """is_adult_human(sim_info) - - Determine if a sim is a Young Adult or Adult Human. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is a Young Adult or Adult Human. False, if the Sim is not. - :rtype: bool - """ - return CommonAgeUtils.is_adult(sim_info) and CommonSpeciesUtils.is_human(sim_info) - - @staticmethod - def is_baby_or_toddler_human(sim_info: SimInfo) -> bool: - """is_baby_or_toddler_human(sim_info) - - Determine if a sim is a Baby or Toddler Human. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is a Baby or Toddler Human. False, if the Sim is not. - :rtype: bool - """ - return CommonAgeUtils.is_baby_or_toddler(sim_info) and CommonSpeciesUtils.is_human(sim_info) - - @staticmethod - def is_child_or_teen_human(sim_info: SimInfo) -> bool: - """is_child_or_teen_human(sim_info) - - Determine if a sim is a Child or Teen Human. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is a Child or Teen Human. False, if the Sim is not. - :rtype: bool - """ - return CommonAgeUtils.is_child_or_teen(sim_info) and CommonSpeciesUtils.is_human(sim_info) - - @staticmethod - def is_toddler_or_child_human(sim_info: SimInfo) -> bool: - """is_toddler_or_child_human(sim_info) - - Determine if a sim is a Toddler or Child Human. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is a Toddler or Child Human. False, if the Sim is not. - :rtype: bool - """ - return CommonAgeUtils.is_toddler_or_child(sim_info) and CommonSpeciesUtils.is_human(sim_info) - - @staticmethod - def is_baby_toddler_or_child_human(sim_info: SimInfo) -> bool: - """is_baby_toddler_or_child_human(sim_info) - - Determine if a sim is a Baby, Toddler, or Child Human. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is a Baby, Toddler, or Child Human. False, if the Sim is not. - :rtype: bool - """ - return CommonAgeUtils.is_baby_toddler_or_child(sim_info) and CommonSpeciesUtils.is_human(sim_info) - - @staticmethod - def is_teen_or_young_adult_human(sim_info: SimInfo) -> bool: - """is_teen_or_young_adult_human(sim_info) - - Determine if a sim is a Teen or Young Adult Human. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is a Teen or Young Adult Human. False, if the Sim is not. - :rtype: bool - """ - return CommonAgeUtils.is_teen_or_young_adult(sim_info) and CommonSpeciesUtils.is_human(sim_info) - - @staticmethod - def is_teen_or_adult_human(sim_info: SimInfo) -> bool: - """is_teen_or_adult_human(sim_info) - - Determine if a sim is a Teen, Young Adult, or Adult Human. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is a Teen, Young Adult, or Adult Human. False, if the Sim is not. - :rtype: bool - """ - return CommonAgeUtils.is_teen_or_adult(sim_info) and CommonSpeciesUtils.is_human(sim_info) - - @staticmethod - def is_mature_adult_or_elder_human(sim_info: SimInfo) -> bool: - """is_mature_adult_or_elder_human(sim_info) - - Determine if a sim is a Adult or Elder Human. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is a Adult or Elder Human. False, if the Sim is not. - :rtype: bool - """ - return CommonAgeUtils.is_mature_adult_or_elder(sim_info) and CommonSpeciesUtils.is_human(sim_info) - - @staticmethod - def is_teen_adult_or_elder_human(sim_info: SimInfo) -> bool: - """is_teen_adult_or_elder_human(sim_info) - - Determine if a sim is a Teen, Young Adult, Adult, or Elder Human. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is a Teen, Young Adult, Adult, or Elder Human. False, if the Sim is not. - :rtype: bool - """ - return CommonAgeUtils.is_teen_adult_or_elder(sim_info) and CommonSpeciesUtils.is_human(sim_info) - - @staticmethod - def is_child_pet(sim_info: SimInfo) -> bool: - """is_child_pet(sim_info) - - Determine if a sim is a Child Pet (Cat, Small Dog, Large Dog). - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is a Child Pet (Cat, Small Dog, Large Dog). False, if the Sim is not. - :rtype: bool - """ - return CommonAgeUtils.is_child(sim_info) and CommonSpeciesUtils.is_pet(sim_info) - - @staticmethod - def is_adult_pet(sim_info: SimInfo) -> bool: - """is_adult_pet(sim_info) - - Determine if a sim is an Adult Pet (Cat, Small Dog, Large Dog). - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is an Adult Pet (Cat, Small Dog, Large Dog). False, if the Sim is not. - :rtype: bool - """ - return CommonAgeUtils.is_adult(sim_info) and CommonSpeciesUtils.is_pet(sim_info) - - @staticmethod - def is_elder_pet(sim_info: SimInfo) -> bool: - """is_elder_pet(sim_info) - - Determine if a sim is an Elder Pet (Cat, Small Dog, Large Dog). - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is an Elder Pet (Cat, Small Dog, Large Dog). False, if the Sim is not. - :rtype: bool - """ - return CommonAgeUtils.is_elder(sim_info) and CommonSpeciesUtils.is_pet(sim_info) - - @staticmethod - def is_old_pet(sim_info: SimInfo) -> bool: - """is_old_pet(sim_info) - - Determine if a sim is an Adult or Elder Pet (Cat, Small Dog, Large Dog). - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is an Adult or Elder Pet (Cat, Small Dog, Large Dog). False, if the Sim is not. - :rtype: bool - """ - return CommonAgeUtils.is_adult_or_elder(sim_info) and CommonSpeciesUtils.is_pet(sim_info) - - @staticmethod - def is_child_animal(sim_info: SimInfo) -> bool: - """is_child_animal(sim_info) - - Determine if a sim is a Child Animal (Cat, Small Dog, Large Dog, Fox). - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is a Child Animal (Cat, Small Dog, Large Dog, Fox). False, if the Sim is not. - :rtype: bool - """ - return CommonAgeUtils.is_child(sim_info) and CommonSpeciesUtils.is_animal(sim_info) - - @staticmethod - def is_adult_animal(sim_info: SimInfo) -> bool: - """is_adult_animal(sim_info) - - Determine if a sim is an Adult Animal (Cat, Small Dog, Large Dog, Fox). - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is an Adult Pet (Cat, Small Dog, Large Dog, Fox). False, if the Sim is not. - :rtype: bool - """ - return CommonAgeUtils.is_adult(sim_info) and CommonSpeciesUtils.is_animal(sim_info) - - @staticmethod - def is_elder_animal(sim_info: SimInfo) -> bool: - """is_elder_animal(sim_info) - - Determine if a sim is an Elder Pet (Cat, Small Dog, Large Dog, Fox). - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is an Elder Pet (Cat, Small Dog, Large Dog, Fox). False, if the Sim is not. - :rtype: bool - """ - return CommonAgeUtils.is_elder(sim_info) and CommonSpeciesUtils.is_animal(sim_info) - - @staticmethod - def is_old_animal(sim_info: SimInfo) -> bool: - """is_old_animal(sim_info) - - Determine if a Sim is an Adult or Elder Animal (Cat, Small Dog, Large Dog, Fox). - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is an Adult or Elder Animal (Cat, Small Dog, Large Dog, Fox). False, if the Sim is not. - :rtype: bool - """ - return CommonAgeUtils.is_adult_or_elder(sim_info) and CommonSpeciesUtils.is_animal(sim_info) - - @staticmethod - def is_adult_human_or_pet(sim_info: SimInfo) -> bool: - """is_adult_human_or_pet(sim_info) - - Determine if a sim is a Young Adult, Adult, or Elder Human or an Adult Pet (Cat, Small Dog, Large Dog). - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is a Young Adult, Adult, or Elder Human or an Adult Pet (Cat, Small Dog, Large Dog). False, if the Sim is not. - :rtype: bool - """ - return CommonAgeSpeciesUtils.is_adult_human(sim_info) or CommonAgeSpeciesUtils.is_adult_pet(sim_info) - - @staticmethod - def is_elder_human_or_pet(sim_info: SimInfo) -> bool: - """is_elder_human_or_pet(sim_info) - - Determine if a sim is an Elder Human or Pet (Cat, Small Dog, Large Dog). - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is an Elder Human or Pet (Cat, Small Dog, Large Dog). False, if the Sim is not. - :rtype: bool - """ - return CommonAgeSpeciesUtils.is_elder_human(sim_info) or CommonAgeSpeciesUtils.is_elder_pet(sim_info) - - @staticmethod - def is_young_human_or_pet(sim_info: SimInfo) -> bool: - """is_young_human_or_pet(sim_info) - - Determine if a sim is a Baby, Toddler, or Child Human or a Child Pet (Cat, Small Dog, Large Dog). - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is a Baby, Toddler, or Child Human or a Child Pet (Cat, Small Dog, Large Dog). False, if the Sim is not. - :rtype: bool - """ - return CommonAgeSpeciesUtils.is_baby_toddler_or_child_human(sim_info) or CommonAgeSpeciesUtils.is_child_pet(sim_info) - - @staticmethod - def is_old_human_or_pet(sim_info: SimInfo) -> bool: - """is_old_human_or_pet(sim_info) - - Determine if a sim is a Teen, Young Adult, Adult, or Elder Human or an Adult or Elder Pet (Cat, Small Dog, Large Dog). - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is a Teen, Young Adult, Adult, or Elder Human or an Adult or Elder Pet (Cat, Small Dog, Large Dog). False, if the Sim is not. - :rtype: bool - """ - return CommonAgeSpeciesUtils.is_teen_adult_or_elder_human(sim_info) or CommonAgeSpeciesUtils.is_old_pet(sim_info) - - @staticmethod - def is_adult_human_or_animal(sim_info: SimInfo) -> bool: - """is_adult_human_or_animal(sim_info) - - Determine if a sim is a Young Adult, Adult, or Elder Human or an Adult Animal (Cat, Small Dog, Large Dog, Fox). - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is a Young Adult, Adult, or Elder Human or an Adult Animal (Cat, Small Dog, Large Dog, Fox). False, if the Sim is not. - :rtype: bool - """ - return CommonAgeSpeciesUtils.is_adult_human(sim_info) or CommonAgeSpeciesUtils.is_adult_animal(sim_info) - - @staticmethod - def is_elder_human_or_animal(sim_info: SimInfo) -> bool: - """is_elder_human_or_animal(sim_info) - - Determine if a sim is an Elder Human or Animal (Cat, Small Dog, Large Dog, Fox). - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is an Elder Human or Animal (Cat, Small Dog, Large Dog, Fox). False, if the Sim is not. - :rtype: bool - """ - return CommonAgeSpeciesUtils.is_elder_human(sim_info) or CommonAgeSpeciesUtils.is_elder_animal(sim_info) - - @staticmethod - def is_young_human_or_animal(sim_info: SimInfo) -> bool: - """is_young_human_or_animal(sim_info) - - Determine if a sim is a Baby, Toddler, or Child Human or a Child Animal (Cat, Small Dog, Large Dog, Fox). - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is a Baby, Toddler, or Child Human or a Child Animal (Cat, Small Dog, Large Dog, Fox). False, if the Sim is not. - :rtype: bool - """ - return CommonAgeSpeciesUtils.is_baby_toddler_or_child_human(sim_info) or CommonAgeSpeciesUtils.is_child_animal(sim_info) - - @staticmethod - def is_old_human_or_animal(sim_info: SimInfo) -> bool: - """is_old_human_or_animal(sim_info) - - Determine if a sim is a Teen, Young Adult, Adult, or Elder Human or an Adult or Elder Animal (Cat, Small Dog, Large Dog, Fox). - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is a Teen, Young Adult, Adult, or Elder Human or an Adult or Elder Animal (Cat, Small Dog, Large Dog, Fox). False, if the Sim is not. - :rtype: bool - """ - return CommonAgeSpeciesUtils.is_teen_adult_or_elder_human(sim_info) or CommonAgeSpeciesUtils.is_old_animal(sim_info) - - @staticmethod - def are_same_age_and_species(sim_info: SimInfo, other_sim_info: SimInfo) -> bool: - """are_same_age_and_species(sim_info, other_sim_info) - - Determine if two Sims are the same Age and the same Species. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :param other_sim_info: The other Sim to compare to. - :type other_sim_info: SimInfo - :return: True, if both Sims are the same Age and Species. False, if they are not. - :rtype: bool - """ - return CommonAgeUtils.are_same_age(sim_info, other_sim_info) and CommonSpeciesUtils.are_same_species(sim_info, other_sim_info) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_age_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_age_utils.py deleted file mode 100644 index 76a797e..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_age_utils.py +++ /dev/null @@ -1,1103 +0,0 @@ -""" -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 -""" -import random -from typing import Union, Iterator - -import services -from event_testing.test_events import TestEvent -from sims.sim_info import SimInfo -from sims.sim_info_types import Age, Species, SpeciesExtended -from s4ap.sims4communitylib.enums.common_age import CommonAge -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ - CommonConsoleCommandArgument -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput - - -class CommonAgeUtils: - """Utilities for manipulating Ages of Sims. - - """ - @classmethod - def get_age(cls, sim_info: SimInfo, exact_age: bool = False) -> Union[Age, int, None]: - """get_age(sim_info, exact_age=False) - - Retrieve the Age of a Sim. - - :param sim_info: The Sim to get the Age of. - :type sim_info: SimInfo - :param exact_age: If set to True, the exact age of the Sim will be returned (Age 24 will be returned as 24). If set to False, the age of the Sim rounded to the nearest Age value will be returned. (Age 24 will be returned as Age.YOUNGADULT). Default is False. - :type exact_age: bool, optional - :return: The Age of the Sim or None if a problem occurs. - :rtype: Union[Age, None] - """ - if sim_info is None: - return None - age: Union[Age, None] = None - if hasattr(sim_info, 'age'): - # noinspection PyPropertyAccess - age = sim_info.age - elif hasattr(sim_info, 'sim_info') and hasattr(sim_info.sim_info, '_base') and hasattr(sim_info.sim_info._base, 'age') and exact_age: - age = sim_info.sim_info._base.age - elif hasattr(sim_info, '_base') and hasattr(sim_info._base, 'age'): - age = sim_info._base.age - elif hasattr(sim_info, 'sim_info') and hasattr(sim_info.sim_info, '_base') and hasattr(sim_info.sim_info._base, 'age') and exact_age: - age = sim_info.sim_info._base.age - elif hasattr(sim_info, 'sim_info') and hasattr(sim_info.sim_info, 'age'): - age = sim_info.sim_info.age - if age is None: - return None - if exact_age: - return age - return cls.convert_to_approximate_age(age) - - @classmethod - def get_birth_age(cls, sim_info: SimInfo) -> Age: - """get_birth_age(sim_info) - - Retrieve the Age that New Sims will be, if they are born from a specified Sim. - - .. note:: Human Sims start at the BABY age. Pet Sims (Large Dog, Small Dog, Cat, Horse) start at the CHILD age. Fox Sims start at the ADULT age. - - :param sim_info: The info of a Sim. - :type sim_info: SimInfo - :return: The Age that New Sims will be, if they are born from the specified Sim. - :rtype: Age - """ - return sim_info.get_birth_age() - - @classmethod - def get_birth_age_from_species(cls, species: Union[Species, SpeciesExtended, int]) -> Union[Age, None]: - """get_birth_age_from_species(species) - - Retrieve the Age that New Sims will be, if they are born with a specified Species. - - .. note:: The HUMAN species starts at the BABY age. The Pet species (Large Dog, Small Dog, Cat, Horse) start at the CHILD age. The FOX species starts at the ADULT age. - - :param species: The species to retrieve information for. - :type species: Union[Species, SpeciesExtended, int] - :return: The Age that New Sims will be, if they are born with the specified Species or None if an Age is not found for the specified Species. - :rtype: Union[Age, None] - """ - from sims.aging.aging_tuning import AgingTuning - cleaned_species = species - if cleaned_species == SpeciesExtended.SMALLDOG: - cleaned_species = Species.DOG - cleaned_species = Species(cleaned_species) - if cleaned_species in AgingTuning.AGING_DATA: - aging_data = AgingTuning.get_aging_data(cleaned_species) - return aging_data.get_birth_age() - - if species == SpeciesExtended.HUMAN: - return Age.BABY - - if species == SpeciesExtended.FOX: - return Age.ADULT - - from s4ap.sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils - if CommonSpeciesUtils.is_animal_species(species) or species == SpeciesExtended.SMALLDOG: - return Age.CHILD - return None - - @classmethod - def convert_to_approximate_age(cls, age: Union[CommonAge, Age, int]) -> Age: - """convert_to_approximate_age(age) - - Convert an age to an approximate Age value. - - :param age: An Age. - :type age: Union[CommonAge, Age, int] - :return: The specified Age converted into an approximate Age value. - :rtype: Age - """ - if isinstance(age, CommonAge): - return CommonAge.convert_to_vanilla(age) - if isinstance(age, Age): - return age - age: int = int(age) - if int(age) == int(Age.INFANT): - return Age.INFANT - if int(Age.BABY) <= age < int(Age.INFANT): - return Age.BABY - if int(Age.INFANT) <= age < int(Age.TODDLER): - return Age.INFANT - if int(Age.TODDLER) <= age < int(Age.CHILD): - return Age.TODDLER - if int(Age.CHILD) <= age < int(Age.TEEN): - return Age.CHILD - if int(Age.TEEN) <= age < int(Age.YOUNGADULT): - return Age.TEEN - if int(Age.YOUNGADULT) <= age < int(Age.ADULT): - return Age.YOUNGADULT - if int(Age.ADULT) <= age < int(Age.ELDER): - return Age.ADULT - if int(Age.ELDER) <= age: - return Age.ELDER - return Age.INFANT - - @classmethod - def get_total_days_sim_has_been_in_their_current_age(cls, sim_info: SimInfo) -> float: - """get_total_days_sim_has_been_in_their_current_age(sim_info) - - Retrieve the total number of days a Sim has been in their current Age. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: A total number of days the specified Sim has been in their current Age. - :rtype: float - """ - return sim_info.age_progress - - @classmethod - def get_percentage_total_days_sim_has_been_in_their_current_age(cls, sim_info: SimInfo) -> float: - """get_percentage_total_days_sim_has_been_in_their_current_age(sim_info) - - Retrieve the percentage total days a Sim has been in their current age. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The percentage total days the specified Sim has been in their current age. - :rtype: float - """ - return sim_info.age_progress/sim_info._age_time*sim_info.AGE_PROGRESS_BAR_FACTOR - - @classmethod - def get_total_days_until_sim_ages_up(cls, sim_info: SimInfo) -> int: - """get_total_days_until_sim_ages_up(sim_info) - - Retrieve the total number of days a Sim has left until they age up. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The total number of days the specified Sim has left until they age up. - :rtype: int - """ - return sim_info.days_until_ready_to_age() - - @classmethod - def get_total_days_to_age_up(cls, sim_info: SimInfo) -> float: - """get_total_days_to_age_up(sim_info) - - Retrieve the total number of days required for the next age of a Sim to be required. (Not to be confused with the amount of days they have left) - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The total number of days required for the specified Sim to reach their next age. - :rtype: float - """ - sim_age = cls.get_age(sim_info, exact_age=False) - age_transition_data = sim_info.get_age_transition_data(sim_age) - return sim_info._age_time/age_transition_data.get_age_duration(sim_info) - - @classmethod - def set_total_days_sim_has_been_in_their_current_age(cls, sim_info: SimInfo, days: float) -> None: - """set_total_days_sim_has_been_in_their_current_age(sim_info, days) - - Set the total number of days of progress made towards the next age of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param days: The total number of days the Sim has been in their current age. - :type days: float - """ - delta_age = days - new_age_value = min(delta_age, sim_info._age_time) - sim_info._set_age_progress(new_age_value - sim_info.FILL_AGE_PROGRESS_BAR_BUFFER) - - @classmethod - def set_percentage_total_days_sim_has_been_in_their_current_age(cls, sim_info: SimInfo, percentage_progress: float) -> None: - """set_percentage_total_days_sim_has_been_in_their_current_age(sim_info, percentage_progress) - - Set the percentage total days a Sim has been in their current age. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param percentage_progress: A percentage total days a Sim has been in their current age. - :type percentage_progress: int - """ - if percentage_progress < 0: - percentage_progress *= -1 - delta_age = cls.get_total_days_to_age_up(sim_info) * (percentage_progress / 100) - new_age_value = min(delta_age, sim_info._age_time) - sim_info._set_age_progress(new_age_value - sim_info.FILL_AGE_PROGRESS_BAR_BUFFER) - - @classmethod - def set_age(cls, sim_info: SimInfo, age: Union[CommonAge, Age, int]) -> bool: - """set_age(sim_info, age) - - Set the Age of a Sim. - - :param sim_info: The Sim to set the Age of. - :type sim_info: SimInfo - :param age: The Age to set the Sim to. - :type age: Union[CommonAge, Age, int] - :return: True, if the Age was set successfully. False, if not. - :rtype: bool - """ - from sims4.resources import Types - from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils - age = cls.convert_to_approximate_age(age) - if age is None: - return False - current_age = cls.get_age(sim_info, exact_age=False) - approximate_age = cls.convert_to_approximate_age(age) - if current_age is None: - return False - if current_age == approximate_age: - return True - sim_info.change_age(age, current_age) - services.get_event_manager().process_event(TestEvent.AgedUp, sim_info=sim_info) - school_data = sim_info.get_school_data() - if school_data is not None: - school_data.update_school_data(sim_info, create_homework=True) - if sim_info.is_npc: - if sim_info.is_child or sim_info.is_teen: - available_aspirations = [] - aspiration_track_manager = CommonResourceUtils.get_instance_manager(Types.ASPIRATION_TRACK) - aspiration_tracker = sim_info.aspiration_tracker - for aspiration_track in aspiration_track_manager.types.values(): - track_available = not aspiration_track.is_hidden_unlockable - if aspiration_tracker is not None: - track_available = aspiration_tracker.is_aspiration_track_visible(aspiration_track) - if track_available: - if sim_info.is_child and hasattr(aspiration_track, 'is_child_aspiration_track') and aspiration_track.is_child_aspiration_track: - available_aspirations.append(aspiration_track) - elif sim_info.is_teen: - available_aspirations.append(aspiration_track) - if available_aspirations: - sim_info.primary_aspiration = random.choice(available_aspirations) - number_of_empty_trait_slots = sim_info.trait_tracker.empty_slot_number - if number_of_empty_trait_slots: - # noinspection PyUnresolvedReferences - available_traits = [trait for trait in services.trait_manager().types.values() if trait.is_personality_trait] - while number_of_empty_trait_slots > 0 and available_traits: - trait = random.choice(available_traits) - available_traits.remove(trait) - if sim_info.trait_tracker.can_add_trait(trait) and sim_info.add_trait(trait): - number_of_empty_trait_slots -= 1 - age_transition = sim_info.get_age_transition_data(age) - age_transition.apply_aging_transition_loot(sim_info) - sim_info._create_additional_statistics() - sim_info._apply_life_skill_traits() - sim_info._relationship_tracker.update_compatibilities() - return cls.get_age(sim_info) == age or cls.get_age(sim_info, exact_age=True) == age - - @classmethod - def are_same_age(cls, sim_info: SimInfo, other_sim_info: SimInfo) -> bool: - """are_same_age(sim_info, other_sim_info) - - Determine if two Sims are the same Age. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :param other_sim_info: The other Sim to compare to. - :type other_sim_info: SimInfo - :return: True, if both Sims are the same Age. - :rtype: bool - """ - return int(cls.get_age(sim_info)) == int(cls.get_age(other_sim_info)) - - @classmethod - def is_younger_than(cls, sim_info: SimInfo, age: Union[CommonAge, Age, int], or_equal: bool = False) -> bool: - """is_younger_than(sim_info, age, or_equal=False) - - Determine if a Sim is younger than the specified Age. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :param age: The age to check with. - :type age: Union[CommonAge, Age, int] - :param or_equal: If True, the age check will be younger than or equal to. If False, the age check will be younger than. - :type or_equal: bool - :return: True, if the Sim is younger than the specified Age or equal to the specified age if `or_equal` is True. False, if not. - :rtype: bool - """ - age = int(age) - sim_age = int(cls.get_age(sim_info)) - if or_equal: - return sim_age <= age - return sim_age < age - - @classmethod - def is_older_than(cls, sim_info: SimInfo, age: Union[CommonAge, Age, int], or_equal: bool = False) -> bool: - """is_older_than(sim_info, age, or_equal=False) - - Determine if a Sim is older than the specified Age. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :param age: The age to check with. - :type age: Union[CommonAge, Age, int] - :param or_equal: If True, the age check will be older than or equal to. If False, the Age check will be older than. - :type or_equal: bool - :return: True, if the Sim is older than the specified Age or equal to the specified Age if `or_equal` is True. False, if not. - :rtype: bool - """ - age = age - sim_age = cls.get_age(sim_info) - if or_equal: - return sim_age >= age - return sim_age > age - - @classmethod - def is_baby_age(cls, age: Union[CommonAge, Age, int]) -> bool: - """is_baby_age(age) - - Determine if an Age is a Baby. - - :param age: The age to check. - :type age: Union[CommonAge, Age, int] - :return: True, if it is. False, if it is not. - :rtype: bool - """ - if age is None: - return False - if isinstance(age, CommonAge): - age = CommonAge.convert_to_vanilla(age) - return age == Age.BABY - - @classmethod - def is_infant_age(cls, age: Union[CommonAge, Age, int]) -> bool: - """is_infant_age(age) - - Determine if an Age is an Infant. - - :param age: The age to check. - :type age: Union[CommonAge, Age, int] - :return: True, if it is. False, if it is not. - :rtype: bool - """ - if age is None: - return False - if isinstance(age, CommonAge): - age = CommonAge.convert_to_vanilla(age) - return age == Age.INFANT - - @classmethod - def is_toddler_age(cls, age: Union[CommonAge, Age, int]) -> bool: - """is_toddler_age(age) - - Determine if an Age is a Toddler. - - :param age: The age to check. - :type age: Union[CommonAge, Age, int] - :return: True, if it is. False, if it is not. - :rtype: bool - """ - if age is None: - return False - if isinstance(age, CommonAge): - age = CommonAge.convert_to_vanilla(age) - return age == Age.TODDLER - - @classmethod - def is_child_age(cls, age: Union[CommonAge, Age, int]) -> bool: - """is_child_age(age) - - Determine if an Age is a Child. - - :param age: The age to check. - :type age: Union[CommonAge, Age, int] - :return: True, if it is. False, if it is not. - :rtype: bool - """ - if age is None: - return False - if isinstance(age, CommonAge): - age = CommonAge.convert_to_vanilla(age) - return age == Age.CHILD - - @classmethod - def is_teen_age(cls, age: Union[CommonAge, Age, int]) -> bool: - """is_teen_age(age) - - Determine if an Age is a Teen. - - :param age: The age to check. - :type age: Union[CommonAge, Age, int] - :return: True, if it is. False, if it is not. - :rtype: bool - """ - if age is None: - return False - if isinstance(age, CommonAge): - age = CommonAge.convert_to_vanilla(age) - return age == Age.TEEN - - @classmethod - def is_adult_age(cls, age: Union[CommonAge, Age, int]) -> bool: - """is_adult_age(age) - - Determine if an Age is a Young Adult or an Adult. - - :param age: The age to check. - :type age: Union[CommonAge, Age, int] - :return: True, if it is. False, if it is not. - :rtype: bool - """ - return cls.is_young_adult_age(age) or cls.is_mature_adult_age(age) - - @classmethod - def is_young_adult_age(cls, age: Union[CommonAge, Age, int]) -> bool: - """is_young_adult_age(age) - - Determine if an Age is a Young Adult. - - :param age: The age to check. - :type age: Union[CommonAge, Age, int] - :return: True, if it is. False, if it is not. - :rtype: bool - """ - if age is None: - return False - if isinstance(age, CommonAge): - age = CommonAge.convert_to_vanilla(age) - return age == Age.YOUNGADULT - - @classmethod - def is_mature_adult_age(cls, age: Union[CommonAge, Age, int]) -> bool: - """is_mature_adult_age(age) - - Determine if an Age is an Adult. - - :param age: The age to check. - :type age: Union[CommonAge, Age, int] - :return: True, if it is. False, if it is not. - :rtype: bool - """ - if age is None: - return False - if isinstance(age, CommonAge): - age = CommonAge.convert_to_vanilla(age) - return age == Age.ADULT - - @classmethod - def is_elder_age(cls, age: Union[CommonAge, Age, int]) -> bool: - """is_elder_age(age) - - Determine if an Age is an Elder. - - :param age: The age to check. - :type age: Union[CommonAge, Age, int] - :return: True, if it is. False, if it is not. - :rtype: bool - """ - if age is None: - return False - if isinstance(age, CommonAge): - age = CommonAge.convert_to_vanilla(age) - return age == Age.ELDER - - @classmethod - def is_baby_or_toddler_age(cls, age: Union[CommonAge, Age, int]) -> bool: - """is_baby_or_toddler_age(age) - - Determine if an age is Baby or Toddler. - - :param age: The age to check. - :type age: Union[CommonAge, Age, int] - :return: True, if it is. False, if it is not. - :rtype: bool - """ - return cls.is_baby_age(age) or cls.is_toddler_age(age) - - @classmethod - def is_baby_infant_or_toddler_age(cls, age: Union[CommonAge, Age, int]) -> bool: - """is_baby_infant_or_toddler_age(age) - - Determine if an age is Baby or Toddler. - - :param age: The age to check. - :type age: Union[CommonAge, Age, int] - :return: True, if it is. False, if it is not. - :rtype: bool - """ - return cls.is_baby_age(age) or cls.is_infant_age(age) or cls.is_toddler_age(age) - - @classmethod - def is_baby_toddler_or_child_age(cls, age: Union[CommonAge, Age, int]) -> bool: - """is_baby_toddler_or_child_age(age) - - Determine if an age is Baby, Toddler, or Child. - - :param age: The age to check. - :type age: Union[CommonAge, Age, int] - :return: True, if it is. False, if it is not. - :rtype: bool - """ - return cls.is_baby_age(age) or cls.is_toddler_age(age) or cls.is_child_age(age) - - @classmethod - def is_baby_infant_toddler_or_child_age(cls, age: Union[CommonAge, Age, int]) -> bool: - """is_baby_infant_toddler_or_child_age(age) - - Determine if an age is Baby, Infant, Toddler, or Child. - - :param age: The age to check. - :type age: Union[CommonAge, Age, int] - :return: True, if it is. False, if it is not. - :rtype: bool - """ - return cls.is_baby_age(age) or cls.is_infant_age(age) or cls.is_toddler_age(age) or cls.is_child_age(age) - - @classmethod - def is_toddler_or_child_age(cls, age: Union[CommonAge, Age, int]) -> bool: - """is_toddler_or_child_age(age) - - Determine if an age is Toddler or Child. - - :param age: The age to check. - :type age: Union[CommonAge, Age, int] - :return: True, if it is. False, if it is not. - :rtype: bool - """ - return cls.is_toddler_age(age) or cls.is_child_age(age) - - @classmethod - def is_child_or_teen_age(cls, age: Union[CommonAge, Age, int]) -> bool: - """is_child_or_teen_age(age) - - Determine if an age is Child or Teen. - - :param age: The age to check. - :type age: Union[CommonAge, Age, int] - :return: True, if it is. False, if it is not. - :rtype: bool - """ - return cls.is_child_age(age) or cls.is_teen_age(age) - - @classmethod - def is_teen_or_young_adult_age(cls, age: Union[CommonAge, Age, int]) -> bool: - """is_teen_or_young_adult_age(age) - - Determine if an age is Teen or Young Adult. - - :param age: The age to check. - :type age: Union[CommonAge, Age, int] - :return: True, if it is. False, if it is not. - :rtype: bool - """ - return cls.is_teen_age(age) or cls.is_young_adult_age(age) - - @classmethod - def is_teen_or_adult_age(cls, age: Union[CommonAge, Age, int]) -> bool: - """is_teen_or_adult_age(age) - - Determine if an age is Teen, Young Adult, or Adult. - - :param age: The age to check. - :type age: Union[CommonAge, Age, int] - :return: True, if it is. False, if it is not. - :rtype: bool - """ - return cls.is_teen_age(age) or cls.is_adult_age(age) - - @classmethod - def is_teen_adult_or_elder_age(cls, age: Union[CommonAge, Age, int]) -> bool: - """is_teen_adult_or_elder_age(age) - - Determine if an age is Teen, Young Adult, Adult, or Elder. - - :param age: The age to check. - :type age: Union[CommonAge, Age, int] - :return: True, if it is. False, if it is not. - :rtype: bool - """ - return cls.is_teen_age(age) or cls.is_adult_age(age) or cls.is_elder_age(age) - - @classmethod - def is_adult_or_elder_age(cls, age: Union[CommonAge, Age, int]) -> bool: - """is_adult_or_elder_age(age) - - Determine if an age is Young Adult, Adult, or Elder. - - :param age: The age to check. - :type age: Union[CommonAge, Age, int] - :return: True, if it is. False, if it is not. - :rtype: bool - """ - return cls.is_adult_age(age) or cls.is_elder_age(age) - - @classmethod - def is_mature_adult_or_elder_age(cls, age: Union[CommonAge, Age, int]) -> bool: - """is_mature_adult_or_elder_age(age) - - Determine if an age is Adult or Elder. - - :param age: The age to check. - :type age: Union[CommonAge, Age, int] - :return: True, if it is. False, if it is not. - :rtype: bool - """ - return cls.is_mature_adult_age(age) or cls.is_elder_age(age) - - @classmethod - def is_baby(cls, sim_info: SimInfo) -> bool: - """is_baby(sim_info) - - Determine if a Sim is a Baby. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is. False, if the Sim is not. - :rtype: bool - """ - return cls.is_baby_age(cls.get_age(sim_info)) - - @classmethod - def is_infant(cls, sim_info: SimInfo) -> bool: - """is_infant(sim_info) - - Determine if a Sim is an Infant. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is. False, if the Sim is not. - :rtype: bool - """ - return cls.is_infant_age(cls.get_age(sim_info)) - - @classmethod - def is_toddler(cls, sim_info: SimInfo) -> bool: - """is_toddler(sim_info) - - Determine if a Sim is a Toddler. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is. False, if the Sim is not. - :rtype: bool - """ - return cls.is_toddler_age(cls.get_age(sim_info)) - - @classmethod - def is_child(cls, sim_info: SimInfo) -> bool: - """is_child(sim_info) - - Determine if a Sim is a Child. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is. False, if the Sim is not. - :rtype: bool - """ - return cls.is_child_age(cls.get_age(sim_info)) - - @classmethod - def is_teen(cls, sim_info: SimInfo) -> bool: - """is_teen(sim_info) - - Determine if a Sim is a Teen. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is. False, if the Sim is not. - :rtype: bool - """ - return cls.is_teen_age(cls.get_age(sim_info)) - - @classmethod - def is_young_adult(cls, sim_info: SimInfo) -> bool: - """is_young_adult(sim_info) - - Determine if a Sim is a Young Adult. - - .. note:: This function does not determine whether they are an Adult or not. Use "is_adult" to check for both. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is. False, if the Sim is not. - :rtype: bool - """ - return cls.is_young_adult_age(cls.get_age(sim_info)) - - @classmethod - def is_mature_adult(cls, sim_info: SimInfo) -> bool: - """is_mature_adult(sim_info) - - Determine if a Sim is an Adult. - - .. note:: This function does not determine whether they are a Young Adult or not. Use 'is_adult' to check for both. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is. False, if the Sim is not. - :rtype: bool - """ - return cls.is_mature_adult_age(cls.get_age(sim_info)) - - @classmethod - def is_elder(cls, sim_info: SimInfo) -> bool: - """is_elder(sim_info) - - Determine if a Sim is an Elder. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is. False, if the Sim is not. - :rtype: bool - """ - return cls.is_elder_age(cls.get_age(sim_info)) - - @classmethod - def is_adult(cls, sim_info: SimInfo) -> bool: - """is_adult(sim_info) - - Determine if a Sim is either a Young Adult or an Adult. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is. False, if the Sim is not. - :rtype: bool - """ - return cls.is_adult_age(cls.get_age(sim_info)) - - @classmethod - def is_baby_or_toddler(cls, sim_info: SimInfo) -> bool: - """is_baby_or_toddler(sim_info) - - Determine if a Sim is a Baby or a Toddler. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is. False, if the Sim is not. - :rtype: bool - """ - return cls.is_baby_or_toddler_age(cls.get_age(sim_info)) - - @classmethod - def is_baby_infant_or_toddler(cls, sim_info: SimInfo) -> bool: - """is_baby_infant_or_toddler(sim_info) - - Determine if a Sim is a Baby, Infant, or a Toddler. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is. False, if the Sim is not. - :rtype: bool - """ - return cls.is_baby_infant_or_toddler_age(cls.get_age(sim_info)) - - @classmethod - def is_toddler_or_child(cls, sim_info: SimInfo) -> bool: - """is_toddler_or_child(sim_info) - - Determine if a Sim is a Toddler or a Child. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is. False, if the Sim is not. - :rtype: bool - """ - return cls.is_toddler_or_child_age(cls.get_age(sim_info)) - - @classmethod - def is_baby_toddler_or_child(cls, sim_info: SimInfo) -> bool: - """is_baby_toddler_or_child(sim_info) - - Determine if a Sim is a Baby, a Toddler, or a Child. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is. False, if the Sim is not. - :rtype: bool - """ - return cls.is_baby_toddler_or_child_age(cls.get_age(sim_info)) - - @classmethod - def is_baby_infant_toddler_or_child(cls, sim_info: SimInfo) -> bool: - """is_baby_infant_toddler_or_child(sim_info) - - Determine if a Sim is a Baby, Infant, a Toddler, or a Child. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is. False, if the Sim is not. - :rtype: bool - """ - return cls.is_baby_infant_toddler_or_child_age(cls.get_age(sim_info)) - - @classmethod - def is_child_or_teen(cls, sim_info: SimInfo) -> bool: - """is_child_or_teen(sim_info) - - Determine if a Sim is a Child or a Teen. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is. False, if the Sim is not. - :rtype: bool - """ - return cls.is_child_or_teen_age(cls.get_age(sim_info)) - - @classmethod - def is_teen_or_young_adult(cls, sim_info: SimInfo) -> bool: - """is_teen_or_young_adult(sim_info) - - Determine if a Sim is a Teen or a Young Adult. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is. False, if the Sim is not. - :rtype: bool - """ - return cls.is_teen_or_young_adult_age(cls.get_age(sim_info)) - - @classmethod - def is_teen_or_adult(cls, sim_info: SimInfo) -> bool: - """is_teen_or_adult(sim_info) - - Determine if a Sim is a Teen, a Young Adult, or an Adult. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is. False, if the Sim is not. - :rtype: bool - """ - return cls.is_teen_or_adult_age(cls.get_age(sim_info)) - - @classmethod - def is_teen_adult_or_elder(cls, sim_info: SimInfo) -> bool: - """is_teen_adult_or_elder(sim_info) - - Determine if a Sim is a Teen, a Young Adult, an Adult, or an Elder. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is. False, if the Sim is not. - :rtype: bool - """ - return cls.is_teen_adult_or_elder_age(cls.get_age(sim_info)) - - @classmethod - def is_adult_or_elder(cls, sim_info: SimInfo) -> bool: - """is_adult_or_elder(sim_info) - - Determine if a Sim is a Young Adult, an Adult, or an Elder. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is. False, if the Sim is not. - :rtype: bool - """ - return cls.is_adult_or_elder_age(cls.get_age(sim_info)) - - @classmethod - def is_mature_adult_or_elder(cls, sim_info: SimInfo) -> bool: - """is_mature_adult_or_elder(sim_info) - - Determine if a Sim is an Adult or an Elder. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is. False, if the Sim is not. - :rtype: bool - """ - return cls.is_mature_adult_or_elder_age(cls.get_age(sim_info)) - - # Obsolete Functionality - - @classmethod - def is_baby_child_or_toddler(cls, sim_info: SimInfo) -> bool: - """is_baby_child_or_toddler(sim_info) - - .. warning:: Obsolete: Don't use this function. Use the :func:'~is_baby_toddler_or_child' function instead. - - """ - return cls.is_baby_toddler_or_child(sim_info) - - @classmethod - def is_age_available_for_sim(cls, sim_info: SimInfo, age: CommonAge) -> bool: - """is_age_available_for_sim(sim_info, age) - - Determine if an Age is available for a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param age: The age to check. - :type age: CommonAge - :return: True, if the specified Age is available for the specified Sim. False, if not. - :rtype: bool - """ - if sim_info is None or age == CommonAge.INVALID: - return False - from sims.aging.aging_data import AgingData - aging_data: AgingData = sim_info.get_aging_data() - if aging_data is None: - return False - vanilla_age = CommonAge.convert_to_vanilla(age) - if vanilla_age is None: - return False - # noinspection PyBroadException - try: - # noinspection PyUnresolvedReferences - aging_data_ages = aging_data.ages - return vanilla_age in aging_data_ages - except: - return False - - @classmethod - def has_age(cls, sim_info: SimInfo, age: Union[CommonAge, Age, int], exact_age: bool = False) -> bool: - """has_age(sim_info, age, exact_age=False) - - Determine if a Sim has a matching Age. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param age: The age to check. - :type age: Union[CommonAge, Age, int] - :param exact_age: If True, the Sims exact age will be used. If False, the Sims approximate age will be used. In most cases, this should be False. Default is False. - :type exact_age: bool, optional - :return: True, if the age of the specified Sim matches the specified age. False, if not. - :rtype: bool - """ - current_age = cls.get_age(sim_info, exact_age=exact_age) - if current_age is None: - return False - return int(current_age) == int(age) - - @classmethod - def has_any_age(cls, sim_info: SimInfo, ages: Iterator[Union[CommonAge, Age, int]], exact_age: bool = False) -> bool: - """has_any_age(sim_info, ages, exact_age=False) - - Determine if a Sim has an Age matching any of the specified Ages. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param ages: The ages to check. - :type ages: Iterator[Union[CommonAge, Age, int]] - :param exact_age: If True, the Sims exact age will be used. If False, the Sims approximate age will be used. In most cases, this should be False. Default is False. - :type exact_age: bool, optional - :return: True, if the age of the specified Sim matches any of the specified ages. False, if not. - :rtype: bool - """ - current_age = cls.get_age(sim_info, exact_age=exact_age) - if current_age is None: - return False - for age in ages: - if int(current_age) == int(age): - return True - return False - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.set_age_progress_percentage', - 'Set the percentage of total days a Sim has been in their current age.', - command_arguments=( - CommonConsoleCommandArgument('progress_percentage', 'Decimal Percentage', 'The percentage of total days to set the Age Progress of the Sim. Values are 0.0 to 100.0'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance id or name of a Sim to change.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.setageprogresspercentage', - ) -) -def _common_set_age_progress_percentage(output: CommonConsoleCommandOutput, progress_percentage: float, sim_info: SimInfo = None): - if sim_info is None: - output('ERROR: No Sim was specified or the specified Sim was not found!') - return - output(f'Attempting to set the age progress of {sim_info} to {progress_percentage}%') - if CommonAgeUtils.set_percentage_total_days_sim_has_been_in_their_current_age(sim_info, progress_percentage): - output(f'SUCCESS: Successfully set the age progress of Sim {sim_info} to {progress_percentage}%') - else: - output(f'FAILED: Failed to set the age progress of Sim {sim_info} to {progress_percentage}%') - output(f'Done setting the age progress of Sim {sim_info} to {progress_percentage}%') - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.randomize_age_progress', - 'Randomize the progress made towards the next age of a Sim.', - command_arguments=( - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance id or name of a Sim to change.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.randomizeageprogress', - ) -) -def _common_randomize_age_progress(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): - if sim_info is None: - output('ERROR: No Sim was specified or the specified Sim was not found!') - return - progress = CommonAgeUtils.get_total_days_to_age_up(sim_info) * random.random() - percentage_progress = (progress / CommonAgeUtils.get_total_days_to_age_up(sim_info)) * 100 - output(f'Attempting to randomize the age progress of {sim_info} to {percentage_progress}%') - CommonAgeUtils.set_percentage_total_days_sim_has_been_in_their_current_age(sim_info, percentage_progress) - output(f'Done randomizing the age progress of Sim {sim_info} to {percentage_progress}%') - return True - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.set_age', - 'Set the age of a Sim.', - command_arguments=( - CommonConsoleCommandArgument('age', 'CommonAge', f'The age to set the Sim to. Valid Ages: {CommonAge.get_comma_separated_names_string()}'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance id or name of a Sim to change.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.setage', - ) -) -def _common_set_age(output: CommonConsoleCommandOutput, age: CommonAge, sim_info: SimInfo = None): - if age is None: - return - if sim_info is None: - output('ERROR: No Sim was specified or the specified Sim was not found!') - return - age_name = age.name - output(f'Setting the age of {sim_info} to {age_name}') - if CommonAgeUtils.set_age(sim_info, age): - output(f'SUCCESS: Successfully set the age of Sim {sim_info} to {age_name}') - else: - output(f'FAILED: Failed to set the age of Sim {sim_info} to {age_name}') - output(f'Done setting the age of Sim {sim_info} to {age_name}') - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.print_sim_age', - 'Print information about the Age of a Sim.', - command_arguments=( - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance id or name of a Sim to check.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.printsimage', - ) -) -def _common_print_sim_age(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): - if sim_info is None: - output('ERROR: No Sim was specified or the specified Sim was not found!') - return - output(f'Attempting to print Age Info for Sim {sim_info}.') - if hasattr(sim_info, '_base') and hasattr(sim_info._base, 'age'): - output(f'_base.age {sim_info._base.age}') - if hasattr(sim_info, 'age'): - # noinspection PyPropertyAccess - output(f'age {sim_info.age}') - if hasattr(sim_info, 'sim_info') and hasattr(sim_info.sim_info, '_base') and hasattr(sim_info.sim_info._base, 'age'): - output(f'sim_info._base.age {sim_info.sim_info._base.age}') - if hasattr(sim_info, 'sim_info') and hasattr(sim_info.sim_info, 'age'): - output(f'sim_info.age {sim_info.sim_info.age}') - get_age_result = CommonAgeUtils.get_age(sim_info) - output(f'Approximate Age: {get_age_result}') - get_age_exact_result = CommonAgeUtils.get_age(sim_info, exact_age=True) - output(f'Exact Age: {get_age_exact_result}') - total_days_has_been_in_current_age = CommonAgeUtils.get_total_days_sim_has_been_in_their_current_age(sim_info) - output(f'Age Progress: {total_days_has_been_in_current_age}') - percentage_total_days_sim_has_been_in_current_age = CommonAgeUtils.get_percentage_total_days_sim_has_been_in_their_current_age(sim_info) - output(f'Age Progress (In Days): {percentage_total_days_sim_has_been_in_current_age}') - total_days_until_sim_ages_up = CommonAgeUtils.get_total_days_until_sim_ages_up(sim_info) - output(f'Days Until Ready To Age: {total_days_until_sim_ages_up}') - total_days_to_age_up = CommonAgeUtils.get_total_days_to_age_up(sim_info) - output(f'Max Total Days To Age Up: {total_days_to_age_up}') - output(f'Done printing Age Info for Sim {sim_info}.') diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_buff_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_buff_utils.py deleted file mode 100644 index 076eea4..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_buff_utils.py +++ /dev/null @@ -1,592 +0,0 @@ -""" -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 -""" -from typing import Union, List, Tuple, Iterator - -from buffs.buff import Buff -from distributor.shared_messages import IconInfoData -from objects.components.buff_component import BuffComponent -from protocolbuffers.Localization_pb2 import LocalizedString -from server_commands.argument_helpers import TunableInstanceParam -from sims.sim_info import SimInfo -from sims4.resources import Types -from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.enums.buffs_enum import CommonBuffId -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.enums.types.component_types import CommonComponentType -from s4ap.sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.notifications.common_basic_notification import CommonBasicNotification -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ - CommonConsoleCommandArgument -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.common_component_utils import CommonComponentUtils -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - - -class CommonBuffUtils(_HasS4CLClassLog): - """Utilities for manipulating Buffs on Sims. - - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 'common_buff_utils' - - @classmethod - def has_fertility_boosting_buff(cls, sim_info: SimInfo) -> CommonTestResult: - """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: The result of testing. True, if they have any fertility boosting buffs. False, if not. - :rtype: CommonTestResult - """ - 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 cls.has_any_buffs(sim_info, buff_ids) - - @classmethod - def has_morning_person_buff(cls, sim_info: SimInfo) -> CommonTestResult: - """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: The result of testing. True, if they have any morning person buffs. False, if not. - :rtype: CommonTestResult - """ - buff_ids = ( - CommonBuffId.TRAIT_MORNING_PERSON, - CommonBuffId.TRAIT_MORNING_PERSON_ACTIVE, - CommonBuffId.TRAIT_MORNING_PERSON_CHECK_ACTIVE - ) - return cls.has_any_buffs(sim_info, buff_ids) - - @classmethod - def has_night_owl_buff(cls, sim_info: SimInfo) -> CommonTestResult: - """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: The result of testing. True, if they have any night owl buffs. False, if not. - :rtype: CommonTestResult - """ - buff_ids = ( - CommonBuffId.TRAIT_NIGHT_OWL, - CommonBuffId.TRAIT_NIGHT_OWL_ACTIVE, - CommonBuffId.TRAIT_NIGHT_OWL_CHECK_ACTIVE - ) - return cls.has_any_buffs(sim_info, buff_ids) - - @classmethod - def has_buff(cls, sim_info: SimInfo, *buff: Union[int, CommonBuffId, Buff]) -> CommonTestResult: - """has_buff(sim_info, buff) - - Determine if the Sim has a Buff. - - :param sim_info: The Sim being checked. - :type sim_info: SimInfo - :param buff: The buff to check for. - :type buff: Union[int, CommonBuffId, Buff] - :return: The result of testing. True, if the Sim has the specified buff. False, if not. - :rtype: CommonTestResult - """ - return cls.has_any_buffs(sim_info, buff) - - @classmethod - def has_any_buffs(cls, sim_info: SimInfo, buffs: Iterator[Union[int, CommonBuffId, Buff]]) -> CommonTestResult: - """has_any_buffs(sim_info, buffs) - - Determine if the Sim has any of the specified buffs. - - :param sim_info: The Sim being checked. - :type sim_info: SimInfo - :param buffs: An iterator of buffs to check for. - :type buffs: Iterator[Union[int, CommonBuffId, Buff]] - :return: The result of testing. True, if the Sim has any of the specified buffs. False, if not. - :rtype: CommonTestResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - if not buffs: - return CommonTestResult(False, reason='No buffs were specified.') - if not CommonComponentUtils.has_component(sim_info, CommonComponentType.BUFF): - return CommonTestResult(False, reason=f'Target Sim {sim_info} did not have a Buff Component.') - from objects.components.buff_component import BuffComponent - buff_component: BuffComponent = CommonComponentUtils.get_component(sim_info, CommonComponentType.BUFF) - for buff in buffs: - _buff = cls.load_buff_by_id(buff) - cls.get_log().format_with_message('Got the buff', buff=_buff) - if _buff is None: - continue - if buff_component.has_buff(_buff): - return CommonTestResult(True, reason=f'{sim_info} has buff {_buff}.') - return CommonTestResult(False, reason=f'{sim_info} does not have any buff(s) {buffs}.') - - @classmethod - def has_all_buffs(cls, sim_info: SimInfo, buffs: Iterator[Union[int, CommonBuffId, Buff]]) -> CommonTestResult: - """has_all_buffs(sim_info, buffs) - - Determine if the Sim has all of the specified buffs. - - :param sim_info: The Sim being checked. - :type sim_info: SimInfo - :param buffs: An iterator of buffs to check for. - :type buffs: Iterator[Union[int, CommonBuffId, Buff]] - :return: The result of testing. True, if the Sim has all of the specified buffs. False, if not. - :rtype: CommonTestResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - if not buffs: - return CommonTestResult(False, reason='No buffs were specified.') - if not CommonComponentUtils.has_component(sim_info, CommonComponentType.BUFF): - return CommonTestResult(False, reason=f'Target Sim {sim_info} did not have a Buff Component.') - from objects.components.buff_component import BuffComponent - buff_component: BuffComponent = CommonComponentUtils.get_component(sim_info, CommonComponentType.BUFF, return_type=BuffComponent) - for buff in buffs: - _buff = cls.load_buff_by_id(buff) - cls.get_log().format_with_message('Got the buff', buff=_buff) - if _buff is None: - continue - if not buff_component.has_buff(_buff): - return CommonTestResult(False, reason=f'{sim_info} does not have buff {_buff}.') - return CommonTestResult(True, reason=f'{sim_info} has all buffs {buffs}.') - - @classmethod - def get_buffs(cls, 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: - raise AssertionError('Argument sim_info was None') - 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 - - @classmethod - def get_buff_ids(cls, sim_info: SimInfo) -> List[int]: - """get_buff_ids(sim_info) - - Retrieve decimal identifiers for all Buffs of a Sim. - - :param sim_info: The Sim to checked. - :type sim_info: SimInfo - :return: A collection of Buff identifiers on a Sim. - :rtype: List[int] - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - if not CommonComponentUtils.has_component(sim_info, CommonComponentType.BUFF): - return list() - buff_ids = list() - sim_buffs = cls.get_buffs(sim_info) - for buff in sim_buffs: - buff_id = cls.get_buff_id(buff) - if buff_id is None: - continue - buff_ids.append(buff_id) - return buff_ids - - @classmethod - def add_buff(cls, sim_info: SimInfo, *buff: Union[int, CommonBuffId], buff_reason: Union[int, str, LocalizedString, CommonStringId] = None) -> CommonExecutionResult: - """add_buff(sim_info, buff, buff_reason=None) - - Add a Buff to a Sim. - - :param sim_info: The Sim to add the buff to. - :type sim_info: SimInfo - :param buff: The buff being added. - :type buff: Union[int, CommonBuffId, Buff] - :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, CommonStringId], optional - :return: The result of adding the buffs. True, if the specified buff was successfully added. False, if not. - :rtype: CommonExecutionResult - """ - return cls.add_buffs(sim_info, buff, buff_reason=buff_reason) - - @classmethod - def add_buffs(cls, sim_info: SimInfo, buffs: Iterator[Union[int, CommonBuffId, Buff]], buff_reason: Union[int, str, LocalizedString, CommonStringId] = None) -> CommonExecutionResult: - """add_buffs(sim_info, buffs, buff_reason=None) - - Add Buffs to a Sim. - - :param sim_info: The Sim to add the specified buffs to. - :type sim_info: SimInfo - :param buffs: An iterator of identifiers of buffs being added. - :type buffs: Iterator[Union[int, CommonBuffId, Buff]] - :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, CommonStringId], optional - :return: The result of adding the buffs. True, if all of the specified buffs were successfully added. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - if not CommonComponentUtils.has_component(sim_info, CommonComponentType.BUFF): - cls.get_log().format_with_message('Failed to add Buff to Sim. They did not have a Buff component!', buffs=buffs, sim=sim_info, buff_reason=buff_reason) - return CommonExecutionResult(False, reason=f'Target Sim {sim_info} did not have a Buff Component.') - localized_buff_reason = None - if buff_reason is not None: - localized_buff_reason = CommonLocalizationUtils.create_localized_string(buff_reason) - has_any_loaded = False - success = True - failed_to_add_buffs = list() - for buff_id in buffs: - buff = cls.load_buff_by_id(buff_id) - if buff is None: - cls.get_log().format_with_message('No buff found using identifier.', buffs=buffs, sim=sim_info, buff_reason=buff_reason, buff_id=buff_id) - failed_to_add_buffs.append(buff_id) - continue - has_any_loaded = True - add_result = sim_info.add_buff_from_op(buff, buff_reason=localized_buff_reason) - if not add_result: - cls.get_log().format_with_message('Failed to add buff.', buff=buff, sim=sim_info, buff_reason=buff_reason, reason=add_result) - success = False - failed_to_add_buffs.append(buff) - else: - cls.get_log().format_with_message('Successfully added buff.', buff=buff, sim=sim_info, buff_reason=buff_reason) - cls.get_log().format_with_message('Finished adding buffs to Sim.', buffs=buffs, sim=sim_info, buff_reason=buff_reason, success=success, has_any_loaded=has_any_loaded, failed_to_add_buffs=failed_to_add_buffs) - if not success: - failed_to_add_buffs_str = ', '.join([cls.get_buff_name(buff) or str(buff) if isinstance(buff, Buff) else str(buff) for buff in failed_to_add_buffs]) - return CommonExecutionResult(False, reason=f'Failed to add buffs. {failed_to_add_buffs_str}') - if not has_any_loaded: - return CommonExecutionResult(True, reason='Finished "adding" buffs, but none of the specified buffs were loaded.') - return CommonExecutionResult.TRUE - - @classmethod - def remove_buff(cls, sim_info: SimInfo, *buff: Union[int, CommonBuffId, Buff]) -> CommonExecutionResult: - """remove_buff(sim_info, buff) - - Remove a Buff from a Sim. - - :param sim_info: The Sim to remove the buff from. - :type sim_info: SimInfo - :param buff: The buff being removed. - :type buff: Union[int, CommonBuffId, Buff] - :return: The result of removing the buff. True, if the buff was successfully removed. False, if not. - :rtype: CommonExecutionResult - """ - return cls.remove_buffs(sim_info, buff) - - @classmethod - def remove_buffs(cls, sim_info: SimInfo, buffs: Iterator[Union[int, CommonBuffId, Buff]]) -> CommonExecutionResult: - """remove_buffs(sim_info, buffs) - - Remove Buffs from a Sim. - - :param sim_info: The Sim to remove the specified buffs from. - :type sim_info: SimInfo - :param buffs: An iterator of identifiers of buffs being removed. - :type buffs: Iterator[Union[int, CommonBuffId, Buff]] - :return: The result of removing the buffs. True, if all of the specified buffs were successfully removed. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - if not CommonComponentUtils.has_component(sim_info, CommonComponentType.BUFF): - return CommonExecutionResult(False, reason=f'Target Sim {sim_info} did not have a Buff Component.') - has_any_loaded = False - success = True - failed_to_remove_buffs = list() - for buff_id in buffs: - buff = cls.load_buff_by_id(buff_id) - if buff is None: - failed_to_remove_buffs.append(buff_id) - continue - if not cls.has_buff(sim_info, buff_id): - continue - has_any_loaded = True - sim_info.remove_buff_by_type(buff) - if cls.has_buff(sim_info, buff): - failed_to_remove_buffs.append(buff) - success = False - - if not success: - failed_to_remove_buffs_str = ', '.join([cls.get_buff_name(buff) or str(buff) if isinstance(buff, Buff) else str(buff) for buff in failed_to_remove_buffs]) - return CommonExecutionResult(False, reason=f'Failed to remove buffs. {failed_to_remove_buffs_str}') - if not has_any_loaded: - return CommonExecutionResult(True, reason='Finished "removing" buffs, but none of the specified buffs were loaded.') - return CommonExecutionResult.TRUE - - @classmethod - def get_buff_id(cls, buff_identifier: Union[int, Buff]) -> Union[int, None]: - """get_buff_id(buff_identifier) - - Retrieve the GUID (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) - - @classmethod - def get_buff_name(cls, 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 - return str(buff) - - @classmethod - def get_buff_names(cls, 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 = cls.get_buff_name(buff) - if not name: - continue - except: - continue - names.append(name) - return tuple(names) - - @classmethod - def get_buff_component(cls, sim_info: SimInfo) -> Union[BuffComponent, None]: - """get_buff_component(sim_info) - - Retrieve the buff component of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The buff component of the Sim or None if not found. - :rtype: Union[BuffComponent, None] - """ - if not CommonComponentUtils.has_component(sim_info, CommonComponentType.BUFF): - return None - result: BuffComponent = CommonComponentUtils.get_component(sim_info, CommonComponentType.BUFF) - return result - - @classmethod - def is_buff_available(cls, buff: Union[int, CommonBuffId, Buff]) -> bool: - """is_buff_available(buff) - - Determine if a Buff is available for use. - - .. note:: If the Buff is part of a package that is not installed, it will be considered as not available. - - :param buff: The buff to check for. - :type buff: Union[int, CommonBuffId, Buff] - :return: True, if the Buff is available for use. False, if not. - :rtype: bool - """ - return cls.load_buff_by_id(buff) is not None - - @classmethod - def load_buff_by_id(cls, buff: Union[int, CommonBuffId, Buff]) -> Union[Buff, None]: - """load_buff_by_id(buff) - - Load an instance of a Buff by its identifier. - - :param buff: The identifier of a Buff. - :type buff: Union[int, CommonBuffId, Buff] - :return: An instance of a Buff matching the decimal identifier or None if not found. - :rtype: Union[Buff, None] - """ - if isinstance(buff, Buff): - return buff - # noinspection PyBroadException - try: - # noinspection PyCallingNonCallable - buff_instance = buff() - if isinstance(buff_instance, Buff): - # noinspection PyTypeChecker - return buff - except: - pass - # noinspection PyBroadException - try: - buff: int = int(buff) - except: - # noinspection PyTypeChecker - buff: Buff = buff - return buff - - from sims4.resources import Types - from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils - return CommonResourceUtils.load_instance(Types.BUFF, buff) - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.add_buff', - 'Add a buff to a Sim.', - command_arguments=( - CommonConsoleCommandArgument('buff', 'Buff Id or Tuning Name', 'The decimal identifier or Tuning Name of the Buff to add.'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance id or name of a Sim to add the buff to.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.addbuff', - ) -) -def _common_add_buff(output: CommonConsoleCommandOutput, buff: TunableInstanceParam(Types.BUFF), sim_info: SimInfo = None, buff_reason: str = None): - if buff is None or isinstance(buff, str): - return - if sim_info is None: - return - output(f'Adding buff {buff} to Sim {sim_info}') - result = CommonBuffUtils.add_buff(sim_info, buff, buff_reason=buff_reason) - if result: - output(f'SUCCESS: Successfully added buff {buff} to Sim {sim_info}: {result.reason}') - else: - output(f'FAILED: Failed to add buff {buff} to Sim {sim_info}: {result.reason}') - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.remove_buff', - 'Remove a buff from a Sim.', - command_arguments=( - CommonConsoleCommandArgument('buff', 'Buff Id or Tuning Name', 'The decimal identifier or Tuning Name of the Buff to remove.'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance id or name of a Sim to remove the buff from.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.removebuff', - ) -) -def _common_remove_buff(output: CommonConsoleCommandOutput, buff: TunableInstanceParam(Types.BUFF), sim_info: SimInfo = None): - if buff is None: - return - if sim_info is None: - return - output(f'Removing buff {buff} from Sim {sim_info}') - result = CommonBuffUtils.remove_buff(sim_info, buff) - if result: - output(f'SUCCESS: Successfully removed buff {buff} from Sim {sim_info}: {result.reason}') - else: - output(f'FAILED: Failed to remove buff {buff} from Sim {sim_info}: {result.reason}') - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_testing.print_buffs', - 'Print a list of all buffs on a Sim.', - command_arguments=( - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance id or name of a Sim to check.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib_testing.printbuffs', - ) -) -def _common_print_buffs_on_sim(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): - if sim_info is None: - return - log = CommonBuffUtils.get_log() - try: - log.enable() - output(f'Attempting to print buffs on Sim {sim_info}') - buff_strings: List[str] = list() - for buff in CommonBuffUtils.get_buffs(sim_info): - buff_name = CommonBuffUtils.get_buff_name(buff) - buff_id = CommonBuffUtils.get_buff_id(buff) - buff_strings.append(f'{buff_name} ({buff_id})') - - buff_strings = sorted(buff_strings, key=lambda x: x) - sim_buffs = ', '.join(buff_strings) - text = '' - text += f'Buffs:\n{sim_buffs}\n\n' - sim_id = CommonSimUtils.get_sim_id(sim_info) - log.debug(f'{sim_info} Buffs ({sim_id})') - log.debug(text) - CommonBasicNotification( - CommonLocalizationUtils.create_localized_string(f'{sim_info} Buffs ({sim_id})'), - CommonLocalizationUtils.create_localized_string(text) - ).show( - icon=IconInfoData(obj_instance=CommonSimUtils.get_sim_instance(sim_info)) - ) - finally: - log.disable() - -# log = CommonLogRegistry().register_log(ModInfo.get_identity(), 'buff_not_properly_adding_log') -# -# @CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), BuffComponent, BuffComponent._can_add_buff_type.__name__) -# def _common_can_add_buff_type(original, self, buff_type): -# if not buff_type.can_add(self.owner): -# log.format_with_message(f'Cannot add buff {buff_type}. Can Add') -# return (False, None) -# mood = buff_type.mood_type -# if mood is not None and mood.excluding_traits is not None and self.owner.trait_tracker.has_any_trait(mood.excluding_traits): -# log.format_with_message(f'Cannot add buff {buff_type}. MOOD', mood=mood, mood_excluding_traits=mood.excluding_traits) -# return (False, None) -# if buff_type.exclusive_index is None: -# log.format_with_message(f'Can add buff {buff_type}. Exclusive Index') -# return (True, None) -# for conflicting_buff_type in self._active_buffs: -# if conflicting_buff_type is buff_type: -# pass -# elif conflicting_buff_type.exclusive_index == buff_type.exclusive_index: -# if buff_type.exclusive_weight < conflicting_buff_type.exclusive_weight: -# log.format_with_message(f'Cannot add buff {buff_type}. Conflicting buff.', buff_weight=buff_type.exclusive_weight, conflicting_buff_weight=conflicting_buff_type.exclusive_weight) -# return (False, None) -# log.format_with_message(f'Cannot add buff {buff_type}. Conflicting buff 23432.', conflicting_buff_type=conflicting_buff_type) -# return (True, conflicting_buff_type) -# log.format_with_message(f'Can add buff {buff_type}.') -# return (True, None) \ No newline at end of file diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_career_level_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_career_level_utils.py deleted file mode 100644 index 22f87de..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_career_level_utils.py +++ /dev/null @@ -1,50 +0,0 @@ -""" -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 -""" -from typing import Union - -from careers.career_tuning import CareerLevel - - -class CommonCareerLevelUtils: - """ Utilities for manipulating Career Levels. """ - - @staticmethod - def load_career_level_by_guid(career_level_identifier: Union[int, CareerLevel]) -> Union[CareerLevel, None]: - """load_career_level_by_guid(career_level_identifier) - - Load an instance of a CareerLevel by its identifier. - - :param career_level_identifier: The identifier of a CareerLevel. - :type career_level_identifier: Union[int, CareerLevel] - :return: An instance of a CareerLevel matching the decimal identifier or None if not found. - :rtype: Union[CareerLevel, None] - """ - if career_level_identifier is None: - return None - if isinstance(career_level_identifier, CareerLevel): - return career_level_identifier - # noinspection PyBroadException - try: - # noinspection PyCallingNonCallable - career_level_instance = career_level_identifier() - if isinstance(career_level_instance, CareerLevel): - # noinspection PyTypeChecker - return career_level_identifier - except: - pass - # noinspection PyBroadException - try: - career_level_identifier: int = int(career_level_identifier) - except: - # noinspection PyTypeChecker - career_level_identifier: CareerLevel = career_level_identifier - return career_level_identifier - - from sims4.resources import Types - from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils - return CommonResourceUtils.load_instance(Types.CAREER_LEVEL, career_level_identifier) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_career_track_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_career_track_utils.py deleted file mode 100644 index cb58cb5..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_career_track_utils.py +++ /dev/null @@ -1,199 +0,0 @@ -""" -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 -""" -import random -from typing import Union, Iterator, Callable, Tuple, List - -from careers.career_tuning import TunableCareerTrack, CareerLevel - - -class CommonCareerTrackUtils: - """ Utilities for manipulating Career Tracks. """ - @classmethod - def get_branches(cls, career_track: TunableCareerTrack, include_sub_branches: bool=False) -> Tuple[TunableCareerTrack]: - """get_branches(career_track, include_sub_branches=True) - - Retrieve a collection of all Career Tracks that branch off of a Career Track and if specified, the branches those branches branch off to. - - :param career_track: A Career Track. - :type career_track: TunableCareerTrack - :param include_sub_branches: If True, all branches will be checked for their own branches and those branches will be included recursively. If False, only the top level branches will be included. Default is False. - :type include_sub_branches: bool, optional - :return: A collection of all Career Tracks that branch off from the specified Career Track. - :rtype: Tuple[TunableCareerTrack] - """ - if career_track is None: - return tuple() - if include_sub_branches: - # noinspection PyUnresolvedReferences - if hasattr(career_track, 'branches') and career_track.branches is not None: - career_track_branches: List[TunableCareerTrack] = list(career_track.branches) - for sub_career_track in career_track_branches: - sub_branches = cls.get_branches(sub_career_track, include_sub_branches=include_sub_branches) - if not sub_branches: - continue - career_track_branches.extend(sub_branches) - return tuple(career_track_branches) - else: - # noinspection PyUnresolvedReferences - if hasattr(career_track, 'branches') and career_track.branches is not None: - return tuple(career_track.branches) - return tuple() - - @classmethod - def get_career_levels(cls, career_track: TunableCareerTrack, include_branches: bool=False) -> Tuple[CareerLevel]: - """get_career_levels(career_track, include_branches=False) - - Retrieve a collection of all career levels under a Career Track. - - :param career_track: A Career Track. - :type career_track: TunableCareerTrack - :param include_branches: If True, all career levels from Career Track branches will be included in the result. If False, only the career levels available for the specified Career Track will be included in the result. Default is False. - :rtype: include_branches: bool, optional - :return: A collection of all Career Levels under the Career Track. - :rtype: Tuple[CareerLevel] - """ - if career_track is None: - return tuple() - if include_branches: - # noinspection PyUnresolvedReferences - if hasattr(career_track, 'career_levels') and career_track.career_levels is not None: - career_levels: List[CareerLevel] = list(career_track.career_levels) - branches = cls.get_branches(career_track) - for branch_career_track in branches: - sub_career_levels = cls.get_career_levels(branch_career_track, include_branches=include_branches) - if not sub_career_levels: - continue - career_levels.extend(sub_career_levels) - return tuple(career_levels) - else: - # noinspection PyUnresolvedReferences - if hasattr(career_track, 'career_levels') and career_track.career_levels is not None: - return tuple(career_track.career_levels) - return tuple() - - @classmethod - def get_career_level_by_index(cls, career_track: TunableCareerTrack, index: int) -> Union[CareerLevel, None]: - """get_career_level_by_index(career_track, index) - - Retrieve a Career Level within a Career Track by its index. - - :param career_track: A Career Track. - :type career_track: TunableCareerTrack - :param index: The index of the career level to retrieve. (Career Levels start at 1 instead of zero!) - :type index: int - :return: The career level found at the specified index or None if not found. - :rtype: Union[CareerLevel, None] - """ - career_levels = cls.get_career_levels(career_track) - if index > len(career_levels): - return None - return career_levels[index] - - @classmethod - def get_career_track_guid(cls, career_track: TunableCareerTrack) -> Union[int, None]: - """get_career_track_guid(career_track) - - Retrieve the Guid64 identifier of a career_track. - - :param career_track: An instance of a Career Track. - :type career_track: TunableCareerTrack - :return: The Guid64 identifier of the specified Career Track. - :rtype: Union[int, None] - """ - if career_track is None: - return None - return getattr(career_track, 'guid64', None) - - @staticmethod - def load_career_track_by_guid(career_track_identifier: Union[int, TunableCareerTrack]) -> Union[TunableCareerTrack, None]: - """load_career_track_by_guid(career_track_identifier) - - Load an instance of a CareerTrack by its identifier. - - :param career_track_identifier: The identifier of a CareerTrack. - :type career_track_identifier: Union[int, TunableCareerTrack] - :return: An instance of a Career Track matching the decimal identifier or None if not found. - :rtype: Union[TunableCareerTrack, None] - """ - if career_track_identifier is None: - return None - if isinstance(career_track_identifier, TunableCareerTrack): - return career_track_identifier - # noinspection PyBroadException - try: - # noinspection PyCallingNonCallable - career_track_instance = career_track_identifier() - if isinstance(career_track_instance, TunableCareerTrack): - # noinspection PyTypeChecker - return career_track_identifier - except: - pass - # noinspection PyBroadException - try: - career_track_identifier: int = int(career_track_identifier) - except: - # noinspection PyTypeChecker - career_track_identifier: TunableCareerTrack = career_track_identifier - return career_track_identifier - - from sims4.resources import Types - from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils - return CommonResourceUtils.load_instance(Types.CAREER_TRACK, career_track_identifier) - - @staticmethod - def get_all_career_tracks_generator(include_career_track_callback: Callable[[TunableCareerTrack], bool]=None) -> Iterator[TunableCareerTrack]: - """get_all_career_tracks_generator(include_career_callback=None) - - Retrieve all Career Tracks. - - :param include_career_track_callback: If the result of this callback is True, the Career will be included in the results. If set to None, All Careers will be included. Default is None. - :type include_career_track_callback: Callable[[TunableCareerTrack], bool], optional - :return: An iterator of Careers matching `include_career_track_callback` - :rtype: Iterator[TunableCareerTrack] - """ - from sims4.resources import Types - from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils - for (_, career_track) in CommonResourceUtils.load_all_instances(Types.CAREER_TRACK): - if include_career_track_callback is not None and not include_career_track_callback(career_track): - continue - yield career_track - - @classmethod - def determine_entry_level_into_career_track_by_user_level(cls, career_track: TunableCareerTrack, desired_user_level: int) -> Tuple[Union[int, None], Union[int, None], Union[TunableCareerTrack, None]]: - """determine_entry_level_into_career_track_by_user_level(career_track, desired_user_level) - - Pick a Career Track level and Career Track from a user level. - - :param career_track: The Career Track to locate a Career Level in. - :type career_track: TunableCareerTrack - :param desired_user_level: The desired user level within the Career Track. - :type desired_user_level: int - :return: The index of the Career Level for the Career Track (or branch Career Track) used, the level of the user in that Career Track, and the Career Track itself. - :rtype: Tuple[int, int, TunableCareerTrack] - """ - if career_track is None: - return None, None, None - track = career_track - track_start_level = 1 - - while True: - track_length = len(cls.get_career_levels(track)) - level = desired_user_level - track_start_level - if level < track_length: - user_level = track_start_level + level - return level, user_level, track - - branches = cls.get_branches(track) - if not branches: - # The exit path. When we run out of branches to check we'll just return the last info found. - level = track_length - 1 - user_level = track_start_level + level - return level, user_level, track - - track_start_level += track_length - track = random.choice(branches) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_career_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_career_utils.py deleted file mode 100644 index 2a419df..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_career_utils.py +++ /dev/null @@ -1,252 +0,0 @@ -""" -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 -""" -from typing import Union, Iterator, Callable, Tuple, List - -from careers.career_location import CareerLocation -from careers.career_tuning import Career, TunableCareerTrack, CareerLevel -from sims4.tuning.instance_manager import InstanceManager - - -class CommonCareerUtils: - """ Utilities for manipulating Careers. """ - @classmethod - def get_career_levels(cls, career: Career, include_branches: bool = False) -> Tuple[CareerLevel]: - """get_career_levels(career, include_branches=False) - - Retrieve Career Levels available for a Career. - - :param career: A career. - :type career: Career - :param include_branches: If True, all career levels from Career Tracks the starting track branches into will be included in the result. If False, only the career levels available for the starting Track will be included in the result. Default is False. - :rtype: include_branches: bool, optional - :return: A collection of Career Levels available for the specified Career. - :rtype: Tuple[CareerLevel] - """ - if career is None: - return tuple() - - from s4ap.sims4communitylib.utils.sims.common_career_track_utils import CommonCareerTrackUtils - return CommonCareerTrackUtils.get_career_levels(career.start_track, include_branches=include_branches) - - @classmethod - def get_starting_career_track(cls, career: Career) -> Union[TunableCareerTrack, None]: - """get_starting_career_track(career) - - Retrieve the starting Career Track of a Career. - - :param career: A career. - :type career: Career - :return: The starting Career Track of the Career or None if not found. - :rtype: Union[TunableCareerTrack, None] - """ - if career is None: - return None - return career.start_track - - @classmethod - def get_all_career_tracks(cls, career: Career) -> Tuple[TunableCareerTrack]: - """get_all_career_tracks(career) - - Retrieve all Career Tracks available for a Career, including all branching Career Tracks. - - :param career: A career. - :type career: Career - :return: A collection of Career Levels available for the specified Career. - :rtype: Tuple[CareerLevel] - """ - if career is None: - return tuple() - - career_tracks: List[TunableCareerTrack] = list() - career_tracks.append(career.start_track) - from s4ap.sims4communitylib.utils.sims.common_career_track_utils import CommonCareerTrackUtils - branch_career_tracks = CommonCareerTrackUtils.get_branches(career.start_track, include_sub_branches=True) - if branch_career_tracks: - career_tracks.extend(branch_career_tracks) - return tuple(career_tracks) - - @classmethod - def get_career_id(cls, career: Career) -> int: - """get_career_id(career) - - Retrieve the instance identifier of a Career. - - :param career: An instance of a Career. - :type career: Career - :return: The instance identifier of the specified Career or -1 if a problem occurs. - :rtype: int - """ - if career is None: - return -1 - if not hasattr(career, 'id') or not isinstance(career, Career): - return -1 - return career.id or getattr(career, 'id', -1) - - @classmethod - def get_career_guid(cls, career: Career) -> Union[int, None]: - """get_career_guid(career) - - Retrieve the Guid64 identifier of a career. - - :param career: An instance of a Career. - :type career: Career - :return: The Guid64 identifier of the specified Career. - :rtype: Union[int, None] - """ - if career is None: - return None - return getattr(career, 'guid64', None) - - @classmethod - def get_career_location(cls, career: Career) -> Union[CareerLocation, None]: - """get_career_location(career) - - Retrieve the workplace location of a career. - - :param career: An instance of a Career. - :type career: Career - :return: The location the Career is set to occur at. - :rtype: Union[CareerLocation, None] - """ - if career is None: - return None - return career.get_career_location() - - @classmethod - def get_career_location_zone_id(cls, career: Career) -> int: - """get_career_location_zone_id(career) - - Retrieve the zone id of a Career where it is set to occur at. - - :param career: An instance of a Career. - :type career: Career - :return: The instance identifier of the zone the career is set to occur at. - :rtype: int - """ - if career is None: - return 0 - career_location = cls.get_career_location(career) - if career_location is None: - return 0 - return career_location.get_zone_id() - - @staticmethod - def load_career_by_guid(career: Union[int, Career]) -> Union[Career, None]: - """load_career_by_guid(career) - - Load an instance of a Career by its identifier. - - :param career: The identifier of a Career. - :type career: Union[int, Career] - :return: An instance of a Career matching the decimal identifier or None if not found. - :rtype: Union[Career, None] - """ - if career is None: - return None - if isinstance(career, Career): - return career - # noinspection PyBroadException - try: - # noinspection PyCallingNonCallable - career_instance = career() - if isinstance(career_instance, Career): - # noinspection PyTypeChecker - return career - except: - pass - # noinspection PyBroadException - try: - career: int = int(career) - except: - # noinspection PyTypeChecker - career: Career = career - return career - - from sims4.resources import Types - from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils - return CommonResourceUtils.load_instance(Types.CAREER, career) - - @staticmethod - def get_all_careers_generator(include_career_callback: Callable[[Career], bool] = None) -> Iterator[Career]: - """get_all_careers_generator(include_career_callback=None) - - Retrieve all Careers. - - :param include_career_callback: If the result of this callback is True, the Career will be included in the results. If set to None, All Careers will be included. Default is None. - :type include_career_callback: Callable[[Career], bool], optional - :return: An iterator of Careers matching `include_career_callback` - :rtype: Iterator[Career] - """ - from sims4.resources import Types - from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils - for (_, career) in CommonResourceUtils.load_all_instances(Types.CAREER): - if include_career_callback is not None and not include_career_callback(career): - continue - yield career - - @staticmethod - def determine_entry_level_into_career_from_user_level(career: Career, desired_user_level: int) -> Tuple[Union[int, None], Union[int, None], Union[TunableCareerTrack, None]]: - """get_career_entry_level_from_user_level(career, desired_user_level) - - Pick a career level and career track from a user level. - - :param career: The career to retrieve a career track from. - :type career: Career - :param desired_user_level: The user level desired to be given to a Sim. - :type desired_user_level: int - :return: The career level for the career track (or branch career track) used, the level of the user in that career track, and the career track itself. - :rtype: Tuple[int, int, TunableCareerTrack] - """ - if career is None: - return None, None, None - track = CommonCareerUtils.get_starting_career_track(career) - from s4ap.sims4communitylib.utils.sims.common_career_track_utils import CommonCareerTrackUtils - return CommonCareerTrackUtils.determine_entry_level_into_career_track_by_user_level(track, desired_user_level) - - @staticmethod - def get_work_performance(career: Career) -> float: - """get_work_performance(career) - - Add an amount to the work performance of a career. - - :param career: The career to modify. - :type career: Career - :return: The amount of work performance acquired in the specified Career. - :rtype: float - """ - if career is None: - return 0.0 - return career.work_performance - - @staticmethod - def modify_work_performance(career: Career, amount: int): - """modify_work_performance(career, amount) - - Modify the work performance acquired in a Career. - - :param career: The career to modify. - :type career: Career - :param amount: The amount of work performance to apply to the Career. - :type amount: int - """ - if career is None: - return - career.add_work_performance(amount) - - @staticmethod - def get_instance_manager() -> InstanceManager: - """get_instance_manager() - - Retrieve the instance manager for careers. - - :return: The instance manager for careers. - :rtype: InteractionInstanceManager - """ - from sims4.resources import Types - from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils - return CommonResourceUtils.get_instance_manager(Types.CAREER) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_gender_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_gender_utils.py deleted file mode 100644 index 0a1a033..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_gender_utils.py +++ /dev/null @@ -1,240 +0,0 @@ -""" -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 -""" -from typing import Union - -from sims.sim_info import SimInfo -from sims.sim_info_types import Gender -from s4ap.sims4communitylib.enums.common_gender import CommonGender -from s4ap.sims4communitylib.enums.traits_enum import CommonTraitId -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ - CommonConsoleCommandArgument -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils -from s4ap.sims4communitylib.utils.sims.common_sim_voice_utils import CommonSimVoiceUtils -from s4ap.sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils - - -class CommonGenderUtils: - """Utilities for manipulating Genders of Sims. - - """ - @staticmethod - def get_gender(sim_info: SimInfo) -> Union[Gender, None]: - """get_gender(sim_info) - - Retrieve the Gender of a Sim. - - :param sim_info: The Sim to retrieve the gender of. - :type sim_info: SimInfo - :return: The Gender of the Sim or None if a problem occurs. - :rtype: Union[Gender, None] - """ - if sim_info is None: - return None - if hasattr(sim_info, 'gender'): - # noinspection PyPropertyAccess - return sim_info.gender - if hasattr(sim_info, 'sim_info') and hasattr(sim_info.sim_info, 'gender'): - return sim_info.sim_info.gender - return None - - @staticmethod - def set_gender(sim_info: SimInfo, gender: Union[Gender, CommonGender, int]) -> bool: - """set_gender(sim_info, gender) - - Set the Gender of a Sim. - - :param sim_info: The Sim to set the Gender of. - :type sim_info: SimInfo - :param gender: The Gender to set the Sim to. - :type gender: Union[Gender, CommonGender, int] - :return: True, if the Gender of the Sim was set successfully. False, if not. - :rtype: bool - """ - gender = CommonGender.convert_to_vanilla(gender) - if gender is None: - return False - sim_info.gender = gender - if gender == Gender.MALE: - new_trait_id = CommonTraitId.GENDER_MALE - CommonTraitUtils.remove_trait(sim_info, CommonTraitId.GENDER_FEMALE) - else: - new_trait_id = CommonTraitId.GENDER_FEMALE - CommonTraitUtils.remove_trait(sim_info, CommonTraitId.GENDER_MALE) - CommonTraitUtils.add_trait(sim_info, new_trait_id) - from s4ap.sims4communitylib.events.sim.common_sim_event_dispatcher import CommonSimEventDispatcherService - CommonSimEventDispatcherService()._on_sim_change_gender(sim_info) - return True - - @staticmethod - def swap_gender(sim_info: SimInfo, update_gender_options: bool=True, update_voice: bool=True, update_outfits: bool=True) -> bool: - """swap_gender(sim_info, update_gender_options=True, update_voice=True, update_outfits=True) - - Swap the Gender of a Sim to it's opposite. i.e. Change a Sim from Male to Female or from Female to Male. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param update_gender_options: If True, gender option traits such as Toilet Usage, Clothing Preference, Pregnancy, and Body Frame will be updated to reflect the vanilla settings for each gender\ - For example, if a Human Sim is swapping from Female to Male, their gender options will be updated to Toilet Standing, Cannot Be Impregnated, Can Impregnate, Mens Wear clothing preference, and Masculine Frame.\ - If False, gender option traits will not be updated.\ - Default is True. - :type update_gender_options: bool, optional - :param update_voice: If True, the voice of the Sim will be updated to a default voice for the gender being swapped to. If False, the voice of the Sim will remain unchanged. Default is True. - :type update_voice: bool, optional - :param update_outfits: If True, the outfits of the Sim will be regenerated to match the gender options of the Sim. If False, the outfits of the Sim will not be regenerated. Default is True. - :param update_outfits: bool, optional - :return: True, if the Gender of the Sim was swapped successfully. False, if not. - :rtype: bool - """ - from s4ap.sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils - result = False - frame = CommonSimGenderOptionUtils.has_masculine_frame(sim_info).result - prefers_menswear = CommonSimGenderOptionUtils.prefers_menswear(sim_info).result - can_impregnate = CommonSimGenderOptionUtils.can_impregnate(sim_info).result - can_be_impregnated = CommonSimGenderOptionUtils.can_be_impregnated(sim_info).result - can_reproduce = CommonSimGenderOptionUtils.can_reproduce(sim_info).result - voice_pitch = CommonSimVoiceUtils.get_voice_pitch(sim_info) - voice_actor = CommonSimVoiceUtils.get_voice_actor(sim_info) - uses_toilet_standing = CommonSimGenderOptionUtils.uses_toilet_standing(sim_info).result - has_breasts = CommonSimGenderOptionUtils.has_breasts(sim_info).result - saved_outfits = sim_info.save_outfits() - current_outfit = CommonOutfitUtils.get_current_outfit(sim_info) - if CommonGenderUtils.is_male(sim_info): - result = CommonGenderUtils.set_gender(sim_info, CommonGender.FEMALE) - if update_voice: - CommonSimVoiceUtils.set_to_default_female_voice(sim_info) - if update_gender_options: - CommonSimGenderOptionUtils.update_gender_options_to_vanilla_female(sim_info) - if update_outfits: - CommonOutfitUtils.regenerate_all_outfits(sim_info) - elif CommonGenderUtils.is_female(sim_info): - result = CommonGenderUtils.set_gender(sim_info, CommonGender.MALE) - if update_voice: - CommonSimVoiceUtils.set_to_default_male_voice(sim_info) - if update_gender_options: - CommonSimGenderOptionUtils.update_gender_options_to_vanilla_male(sim_info) - if update_outfits: - CommonOutfitUtils.regenerate_all_outfits(sim_info) - - if not update_voice: - CommonSimVoiceUtils.set_voice_pitch(sim_info, voice_pitch) - CommonSimVoiceUtils.set_voice_actor(sim_info, voice_actor) - - if not update_gender_options: - CommonSimGenderOptionUtils.update_body_frame(sim_info, frame) - CommonSimGenderOptionUtils.update_clothing_preference(sim_info, prefers_menswear) - CommonSimGenderOptionUtils.update_can_impregnate(sim_info, can_impregnate) - CommonSimGenderOptionUtils.update_can_be_impregnated(sim_info, can_be_impregnated) - CommonSimGenderOptionUtils.update_can_reproduce(sim_info, can_reproduce) - CommonSimGenderOptionUtils.update_toilet_usage(sim_info, uses_toilet_standing) - CommonSimGenderOptionUtils.update_has_breasts(sim_info, has_breasts) - - if not update_outfits: - sim_info.load_outfits(saved_outfits) - CommonOutfitUtils.resend_outfits(sim_info) - CommonOutfitUtils.set_current_outfit(sim_info, current_outfit) - return result - - @staticmethod - def are_same_gender(sim_info: SimInfo, other_sim_info: SimInfo) -> bool: - """are_same_gender(sim_info, other_sim_info) - - Determine if two Sims are the same Gender. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :param other_sim_info: The Sim to compare to. - :type other_sim_info: SimInfo - :return: True, if both Sims are the same Gender. False, if not. - :rtype: bool - """ - gender_a = CommonGenderUtils.get_gender(sim_info) - if gender_a is None: - return False - gender_b = CommonGenderUtils.get_gender(other_sim_info) - if gender_b is None: - return False - return int(gender_a) == int(gender_b) - - @staticmethod - def is_female_gender(gender: Union[Gender, CommonGender, int]) -> bool: - """is_female_gender(gender) - - Determine if a Gender is Female. - - :param gender: The gender to check. - :type gender: Union[Gender, CommonGender, int] - :return: True, if the gender is female. False, if the gender is not female. - :rtype: bool - """ - if gender is None: - return False - return int(gender) == int(Gender.FEMALE) - - @staticmethod - def is_male_gender(gender: Union[Gender, CommonGender, int]) -> bool: - """is_male_gender(gender) - - Determine if a Gender is Male. - - :param gender: The gender to check. - :type gender: Union[Gender, CommonGender, int] - :return: True, if the gender is male. False, if the gender is not male. - :rtype: bool - """ - if gender is None: - return False - return int(gender) == int(Gender.MALE) - - @staticmethod - def is_female(sim_info: SimInfo) -> bool: - """is_female(sim_info) - - Determine if a Sim is Female. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is female. False, if the Sim is not female. - :rtype: bool - """ - return CommonGenderUtils.is_female_gender(CommonGenderUtils.get_gender(sim_info)) - - @staticmethod - def is_male(sim_info: SimInfo) -> bool: - """is_male(sim_info) - - Determine if a Sim is Male. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is male. False, if the Sim is not male. - :rtype: bool - """ - return CommonGenderUtils.is_male_gender(CommonGenderUtils.get_gender(sim_info)) - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.swap_gender', - 'Swap the gender of a Sim.', - command_arguments=( - CommonConsoleCommandArgument('update_gender_options', 'True or False', 'If True, gender options will be updated to vanilla gender options for the gender they are swapping to.', is_optional=True, default_value='True'), - CommonConsoleCommandArgument('update_voice', 'True or False', 'If True, voice of the Sim will be updated to a default voice for the gender they are swapping to.', is_optional=True, default_value='True'), - CommonConsoleCommandArgument('update_outfits', 'True or False', 'If True, outfits of the Sim will be regenerated to reflect the gender they are swapping to.', is_optional=True, default_value='True'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or decimal identifier of the Sim to use.', is_optional=True, default_value='Active Sim'), - ) -) -def _common_swap_gender(output: CommonConsoleCommandOutput, sim_info: SimInfo = None, update_gender_options: bool = True, update_voice: bool = True, update_outfits: bool = True) -> bool: - output(f'Swapping the gender of Sim {sim_info}.') - result = CommonGenderUtils.swap_gender(sim_info, update_gender_options=update_gender_options, update_voice=update_voice, update_outfits=update_outfits) - if result: - output('Success!') - else: - output('Failed!') - return True diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_household_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_household_utils.py deleted file mode 100644 index d8d3110..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_household_utils.py +++ /dev/null @@ -1,747 +0,0 @@ -""" -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 -""" -from typing import Union, Iterator - -import services -from sims.household import Household -from sims.sim_info import SimInfo -from sims.sim_spawner import SimSpawner -from s4ap.sims4communitylib.logging.has_class_log import HasClassLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ - CommonConsoleCommandArgument -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from world.lot import Lot -from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils -from s4ap.sims4communitylib.utils.sims.common_sim_state_utils import CommonSimStateUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - - -class CommonHouseholdUtils(HasClassLog): - """Utilities for manipulating households. - - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - return ModInfo.get_identity() - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 'common_household_utils' - - @classmethod - def get_active_household(cls) -> Union[Household, None]: - """get_active_household() - - Retrieve the Household of the Active Sim. - - :return: The Household of the Active Sim or None if no household is found. - :rtype: Union[Household, None] - """ - return services.active_household() - - @classmethod - def get_active_household_id(cls) -> int: - """get_active_household_id() - - Retrieve an identifier for the Household of the Active Sim. - - :return: The identifier of the Household of the Active Sim. - :rtype: int - """ - return cls.get_id(cls.get_active_household()) - - @classmethod - def get_household_zone_id(cls, sim_info: SimInfo) -> int: - """get_household_zone_id(sim_info) - - Retrieve an zone identifier for the home Lot of the specified Sim. - - :param sim_info: The Sim to retrieve the household Lot id of. - :type sim_info: SimInfo - :return: The zone identifier of the Household the Sim belongs to. - :rtype: int - """ - household = cls.get_household(sim_info) - return cls.get_household_home_zone_id(household) - - @classmethod - def get_household_lot_id(cls, sim_info: SimInfo) -> int: - """get_household_lot_id(sim_info) - - Retrieve an identifier for the home Lot of a Sim. - - :param sim_info: The Sim to retrieve the household Lot id of. - :type sim_info: SimInfo - :return: The identifier of the Household Lot for the Sim. - :rtype: int - """ - household = cls.get_household(sim_info) - return cls.get_household_home_lot_id(household) - - @classmethod - def get_household_home_zone_id(cls, household: Household) -> int: - """get_household_home_zone_id(household) - - Retrieve the home zone identifier for a Household. - - :param household: An instance of a Household. - :type household: Household - :return: The home zone identifier of the specified Household or -1 if a problem occurs. - :rtype: int - """ - if household is None: - return -1 - # noinspection PyTypeChecker - return household.home_zone_id - - @classmethod - def get_household_home_lot_id(cls, household: Household) -> int: - """get_household_home_lot_id(household) - - Retrieve the decimal identifier of the home Lot for a Household. - - :param household: An instance of a Household. - :type household: Household - :return: The home zone identifier of the specified Household or -1 if a problem occurs. - :rtype: int - """ - from s4ap.sims4communitylib.utils.location.common_location_utils import CommonLocationUtils - if household is None: - return -1 - home_zone_id = cls.get_household_home_zone_id(household) - if home_zone_id == -1: - return -1 - home_zone = CommonLocationUtils.get_zone(home_zone_id, allow_unloaded_zones=True) - if home_zone is None or not home_zone.is_instantiated: - return home_zone_id or -1 - lot = CommonLocationUtils.get_zone_lot(home_zone) - if lot is None: - return home_zone_id or -1 - return CommonLocationUtils.get_lot_id(lot) - - @classmethod - def get_sim_info_of_all_sims_in_active_household_generator(cls) -> Iterator[SimInfo]: - """get_sim_info_of_all_sims_in_active_household_generator() - - Retrieve a collection of Sims that are a part of the active household. - - :return: An iterator of Sims in the active household. - :rtype: Iterator[SimInfo] - """ - household = cls.get_active_household() - for sim_info in cls.get_sim_info_of_all_sims_in_household_generator(household): - yield sim_info - - @classmethod - def get_sim_info_of_all_sims_in_household_generator(cls, household: Household) -> Iterator[SimInfo]: - """get_sim_info_of_all_sims_in_household_generator(household) - - Retrieve a collection of Sims that are a part of the active household. - - :param household: The Household to retrieve Sims from. - :type household: Household - :return: An iterator of Sims in the specified Household. - :rtype: Iterator[SimInfo] - """ - if household is None: - return tuple() - for sim_info in list(household.sim_info_gen()): - if sim_info is None: - continue - yield sim_info - - @classmethod - def get_number_of_sims_in_household(cls, household: Household) -> int: - """get_number_of_sims_in_household(household) - - Determine the number of Sims in the specified Household. - - :param household: An instance of a Household. - :type household: Household - :return: The number of Sims in the specified Household. - :rtype: int - """ - if household is None: - return 0 - return len(tuple(cls.get_sim_info_of_all_sims_in_household_generator(household))) - - @classmethod - def get_number_of_sims_in_household_of_sim(cls, sim_info: SimInfo) -> int: - """get_number_of_sims_in_household_of_sim(sim_info) - - Determine the number of Sims in the household of the specified Sim. - - :param sim_info: An instance of a Sim. - :type: sim_info: SimInfo - :return: The number of Sims in the household of the specified Sim. - :rtype: int - """ - return cls.get_number_of_sims_in_household(cls.get_household(sim_info)) - - @classmethod - def is_part_of_active_household(cls, sim_info: SimInfo) -> bool: - """is_part_of_active_household(sim_info) - - Determine if a Sim is part of the active household. - - :return: True, if the Sim is part of the Active Household. False, if not. - :rtype: bool - """ - return sim_info in cls.get_sim_info_of_all_sims_in_active_household_generator() - - @classmethod - def is_part_of_a_single_sim_household(cls, sim_info: SimInfo) -> bool: - """is_part_of_a_single_sim_household(sim_info) - - Determine if a Sim is the only Sim in their Household (Single Sim Household). - - :param sim_info: An instance of a Sim. - :type: sim_info: SimInfo - :return: True, if specified Sim is the only Sim in their Household (Single Sim Household). False, if not. - :rtype: bool - """ - return cls.get_number_of_sims_in_household_of_sim(sim_info) == 1 - - @classmethod - def is_alone_on_home_lot(cls, sim_info: SimInfo) -> bool: - """is_alone_on_home_lot(sim_info) - - Determine if a Sim is alone on their home lot. - - :param sim_info: An instance of a Sim. - :type: sim_info: SimInfo - :return: True, if the Sim is on their home lot and alone. False, if not. - :rtype: bool - """ - from s4ap.sims4communitylib.utils.sims.common_sim_location_utils import CommonSimLocationUtils - return cls.is_part_of_a_single_sim_household(sim_info) and CommonSimLocationUtils.is_at_home(sim_info) - - @classmethod - def get_all_households_generator(cls) -> Iterator[Household]: - """get_all_households_generator() - - Retrieve a collection of all households. - - :return: An iterator of all Households. - :rtype: Iterator[Household] - """ - household_list = tuple(services.household_manager().get_all()) - for household in household_list: - if household is None: - continue - yield household - - @classmethod - def locate_household_by_id(cls, household_id: int) -> Union[Household, None]: - """locate_household_by_id(household_id) - - Locate a household with the specified id. - - :param household_id: The decimal identifier of a Household. - :type household_id: int - :return: The Household with an identifier matching the specified identifier or None if no Household was found. - :rtype: Union[Household, None] - """ - # noinspection PyBroadException - try: - return services.household_manager().get(household_id) - except: - return None - - @classmethod - def locate_household_by_name(cls, name: str, allow_partial_match: bool = False, create_on_missing: bool = False, starting_funds: int = 0, as_hidden_household: bool = False) -> Union[Household, None]: - """locate_household_by_name(name, allow_partial_match=False, create_on_missing=False, starting_funds=0, as_hidden_household=False) - - Locate a household with the specified name. - - :param name: The name of a household to locate. - :type name: str - :param allow_partial_match: If True, households only need to contain the name to match. - :type allow_partial_match: bool, optional - :param create_on_missing: If True, a household will be created if one isn't found with the specified name. - :type create_on_missing: bool, optional - :param starting_funds: If a household is created, this will be the starting funds of that household. - :type starting_funds: int, optional - :param as_hidden_household: If True, the created household will be hidden. - :type as_hidden_household: bool, optional - :return: A Household with the specified name or None if no household is found. - :rtype: Union[Household, None] - """ - log = cls.get_log() - for household in cls.locate_households_by_name_generator(name, allow_partial_match=allow_partial_match): - if household is None: - continue - return household - if not create_on_missing: - log.debug('No household found matching name \'{}\'.'.format(name)) - return None - log.debug('No household found, creating one.') - return cls.create_empty_household(starting_funds=starting_funds, as_hidden_household=as_hidden_household) - - @classmethod - def locate_households_by_name_generator(cls, name: str, allow_partial_match: bool = False) -> Iterator[Household]: - """locate_households_by_name_generator(name, allow_partial_match=False) - - Locate all households with the specified name. - - :param name: The name of the households to locate. - :type name: str - :param allow_partial_match: If True, households only need to contain the name to match. - :type allow_partial_match: bool, optional - :return: An iterator of Households with the specified name. - :rtype: Iterator[Household] - """ - log = cls.get_log() - if allow_partial_match: - log.debug('Locating households containing name: \'{}\''.format(name)) - else: - log.debug('Locating households with name: \'{}\''.format(name)) - for household in cls.get_all_households_generator(): - if household is None: - continue - # noinspection PyPropertyAccess - household_name = household.name - # noinspection PyPropertyAccess - log.debug('Checking household \'{}\' for match.'.format(household_name)) - if household_name is None: - continue - if allow_partial_match: - if name not in household_name: - log.debug('Household name did not match.') - continue - elif household_name != name: - log.debug('Household name did not match.') - continue - log.debug('Located household.') - yield household - - @classmethod - def create_empty_household(cls, starting_funds: int = 0, as_hidden_household: bool = False) -> Household: - """create_empty_household(starting_funds=0, as_hidden_household=False) - - Create an empty household. - - :param starting_funds: The funds the Household will start with. - :type starting_funds: int, optional - :param as_hidden_household: If True, the created household will be hidden. - :type as_hidden_household: bool, optional - :return: The created Household - :rtype: Household - """ - household = Household(SimSpawner._get_default_account(), starting_funds=starting_funds) - if as_hidden_household: - household.set_to_hidden() - services.household_manager().add(household) - return household - - @classmethod - def add_sim_to_active_household(cls, sim_info: SimInfo, destroy_if_empty_household: bool = True) -> bool: - """add_sim_to_active_household(sim_info, destroy_if_empty_household=True) - - Add a Sim to the Active Sims household. - - :param sim_info: The Sim to add. - :type sim_info: SimInfo - :param destroy_if_empty_household: If True, if the Sim comes from a household containing only them, then it will be destroyed after they are moved. - :type destroy_if_empty_household: bool, optional - :return: True, if the Sim was added to the active household successfully. False, if not. - :rtype: bool - """ - target_sim_info = CommonSimUtils.get_active_sim_info() - return cls.add_sim_to_target_household(sim_info, target_sim_info, destroy_if_empty_household=destroy_if_empty_household) - - @classmethod - def add_sim_to_target_household(cls, sim_info: SimInfo, target_sim_info: SimInfo, destroy_if_empty_household: bool = True) -> bool: - """add_sim_to_active_household(sim_info, destroy_if_empty_household=True) - - Add a Sim to the Household of the Target Sim. - - :param sim_info: The Sim to add. - :type sim_info: SimInfo - :param target_sim_info: This Sim will receive the Sim to their Household. - :type target_sim_info: SimInfo - :param destroy_if_empty_household: If True, if the Sim comes from a household containing only them, then it will be destroyed after they are moved. - :type destroy_if_empty_household: bool, optional - :return: True, if the Sim was added to the household of the target successfully. False, if not. - :rtype: bool - """ - log = cls.get_log() - log.info('Adding Sim to target Sim household.') - destination_household = target_sim_info.household - log.format_info('Adding Sim to household of target sim', sim=CommonSimNameUtils.get_full_name(sim_info), target_sim=CommonSimNameUtils.get_full_name(target_sim_info), destination_household=destination_household) - return cls.move_sim_to_household(sim_info, household_id=destination_household.id, destroy_if_empty_household=destroy_if_empty_household) - - @classmethod - def move_sim_to_household(cls, sim_info: SimInfo, household_id: int = None, destroy_if_empty_household: bool = True) -> bool: - """move_sim_to_household(sim_info, household_id=None, destroy_if_empty_household=True) - - Move a Sim to the specified household or a new household if no Household is specified. - - :param sim_info: The Sim to add. - :type sim_info: SimInfo - :param household_id: The identifier of the Household to add the Sim to. - :type household_id: int - :param destroy_if_empty_household: If True, if the Sim comes from a household containing only them, then it will be destroyed after they are moved. - :type destroy_if_empty_household: bool, optional - :return: True, if the Sim was added to the Household successfully. False, if not. - :rtype: bool - """ - active_sim_info = CommonSimUtils.get_active_sim_info() - active_household = services.active_household() - starting_household = sim_info.household - log = cls.get_log() - log.format_info('Moving a Sim to a new household.', sim=CommonSimNameUtils.get_full_name(sim_info), household_id=household_id, starting_household=starting_household) - if household_id is None: - log.info('No destination household specified, creating a household for the sim.') - destination_household = services.household_manager().create_household(sim_info.account) - else: - log.info('Household was specified, getting household of the sim.') - destination_household = services.household_manager().get(household_id) - if destination_household is None: - raise AssertionError('Destination Household not specified!') - log.format_info('Destination household acquired', destination_household=destination_household) - if CommonSimStateUtils.is_hidden(sim_info): - log.info('Making hidden Sim visible.') - services.hidden_sim_service().unhide_sim(sim_info.id) - if starting_household is destination_household: - raise AssertionError('The Sim being moved is already in the destination household.') - log.info('Removing Sim from the starting household.') - starting_household.remove_sim_info(sim_info, destroy_if_empty_household=destroy_if_empty_household) - log.info('Adding Sim to the destination household.') - destination_household.add_sim_info_to_household(sim_info) - client = services.client_manager().get_first_client() - if destination_household is active_household: - log.info('The destination household is the active household. Changing the Sim to be selectable.') - client.add_selectable_sim_info(sim_info) - else: - log.info('The destination household is different from the active household. Removing the selectability of the sim.') - if active_sim_info is sim_info: - client.set_next_sim() - client.remove_selectable_sim_info(sim_info) - if sim_info.career_tracker is not None: - log.info('Removing invalid careers.') - sim_info.career_tracker.remove_invalid_careers() - log.info('Invalid careers removed.') - sim = sim_info.get_sim_instance() - if sim is not None: - log.info('Updating sims intended position on the active Lot.') - sim.update_intended_position_on_active_lot(update_ui=True) - situation_manager = services.get_zone_situation_manager() - log.info('Removing Sim from currently active situations.') - for situation in situation_manager.get_situations_sim_is_in(sim): - if destination_household is active_household and situation.is_user_facing: - pass - else: - log.format_info('Removing situation', situation_id=situation.id) - situation_manager.remove_sim_from_situation(sim, situation.id) - log.info('Done removing situations. Updating daycare service information.') - services.daycare_service().on_sim_spawn(sim_info) - log.info('Done moving Sim to household.') - return True - - @classmethod - def has_free_household_slots(cls, sim_info: SimInfo) -> bool: - """has_free_household_slots(sim_info) - - Determine if the Household of the specified Sim has any free Sim slots. - - .. note:: Max household slots in vanilla Sims 4 is 8 sims. - - :param sim_info: The Sim whose household will be checked. - :type sim_info: SimInfo - :return: True, if there are free slots for new Sims in the Household of the specified Sim. False, if not. - :rtype: bool - """ - return cls.get_free_household_slots(sim_info) > 0 - - @classmethod - def get_free_household_slots(cls, sim_info: SimInfo) -> int: - """get_free_household_slots(sim_info) - - Retrieve the number of free household slots in the Household of the specified Sim. - - .. note:: Max household slots in vanilla Sims 4 is 8 sims. - - :param sim_info: The Sim whose household will be checked. - :type sim_info: SimInfo - :return: The number of free household slots or -1 if no Household is found for the specified Sim. - :rtype: int - """ - household = cls.get_household(sim_info) - if household is None: - return -1 - return household.free_slot_count - - @classmethod - def get_household_members_gen(cls, sim_info: SimInfo) -> Iterator[SimInfo]: - """get_household_members_gen(sim_info) - - Retrieve the Sims within the household of a Sim. - - .. note:: The result will include the specified Sim as well. - - :param sim_info: The info of a Sim. - :type sim_info: SimInfo - :return: An iterator of Sims within the household of the specified Sim. - :rtype: Iterator[SimInfo] - """ - household = cls.get_household(sim_info) - if household is None: - yield sim_info - else: - yield from cls.get_household_members_from_household_gen(household) - - @classmethod - def get_household_members_from_household_gen(cls, household: Household) -> Iterator[SimInfo]: - """get_household_members_from_household_gen(sim_info) - - Retrieve the Sims within a Household. - - :param household: An instance of a Household - :type household: Household - :return: An iterator of Sims within the specified household. - :rtype: Iterator[SimInfo] - """ - if household is None: - return tuple() - - for household_member_sim_info in household: - yield CommonSimUtils.get_sim_info(household_member_sim_info) - - @classmethod - def get_household(cls, sim_info: SimInfo) -> Union[Household, None]: - """get_household(sim_info) - - Retrieve the household of a Sim. - - :param sim_info: The Sim whose household will be retrieved. - :type sim_info: SimInfo - :return: The Household of the specified Sim or None if no household is found. - :rtype: Union[Household, None] - """ - if not cls.has_household(sim_info): - return None - return services.household_manager().get(sim_info.household.id) - - @classmethod - def get_household_id(cls, sim_info: SimInfo) -> int: - """get_household_id(sim_info) - - Retrieve an identifier for the Household a Sim is a part of. - - :param sim_info: The Sim whose household will be retrieved. - :type sim_info: SimInfo - :return: The identifier of the Household of the specified Sim or `0` if no household is found. - :rtype: int - """ - return cls.get_id(cls.get_household(sim_info)) - - @classmethod - def get_id(cls, household: Household) -> int: - """get_id(household) - - Retrieve the decimal identifier of a Household. - - :param household: An instance of a Household. - :type: Household - :return: The identifier of the Household or `0` if an error occurs. - :rtype: int - """ - if household is None: - return 0 - return household.id - - @classmethod - def has_household(cls, sim_info: SimInfo) -> bool: - """has_household(sim_info) - - Determine if the Sim is part of a Household. - - :param sim_info: The Sim whose household will be checked. - :type sim_info: SimInfo - :return: True, if the Sim is part of a Household. False, if not. - :rtype: bool - """ - return hasattr(sim_info, 'household') and sim_info.household is not None - - @classmethod - def is_in_same_household(cls, sim_info: SimInfo, target_sim_info: SimInfo) -> bool: - """is_in_same_household(sim_info, target_sim_info) - - Determine if two Sims are in the same household. - - :param sim_info: The Sim whose household will be checked. - :type sim_info: SimInfo - :param target_sim_info: The Target whose household will be checked. - :type target_sim_info: SimInfo - :return: True, if the Sim is part of same Household as the Target Sim. False, if not. - :rtype: bool - """ - household = cls.get_household(sim_info) - if household is None: - return False - target_household = cls.get_household(target_sim_info) - if target_household is None: - return False - return household is target_household - - @classmethod - def get_household_owning_current_lot(cls) -> Union[Household, None]: - """get_household_owning_current_lot() - - Retrieve the Household that owns the current Lot. - - :return: A decimal identifier of the Household that owns the current Lot or None if no Household owns the current Lot. - :rtype: Union[Household, None] - """ - household_id = cls.get_household_id_owning_current_lot() - if household_id is None or household_id == -1: - return None - return cls.locate_household_by_id(household_id) - - @classmethod - def get_household_id_owning_current_lot(cls) -> int: - """get_household_id_owning_current_lot() - - Retrieve the decimal identifier of the Household that owns the current Lot. - - :return: A decimal identifier of the Household that owns the current Lot or -1 if a problem occurs. - :rtype: int - """ - household_id = services.owning_household_id_of_active_lot() - if household_id is None: - return -1 - return household_id - - @classmethod - def get_household_owning_lot(cls, lot: Lot) -> Union[Household, None]: - """get_household_owning_lot(lot) - - Retrieve the Household that owns a Lot. - - :param lot: An instance of a Lot. - :type lot: Lot - :return: A decimal identifier of the Household that owns the specified Lot or None if no Household owns the specified Lot. - :rtype: Union[Household, None] - """ - household_id = cls.get_household_id_owning_lot(lot) - if household_id is None or household_id == -1: - return None - return cls.locate_household_by_id(household_id) - - @classmethod - def get_household_id_owning_lot(cls, lot: Lot) -> int: - """get_household_id_owning_lot(lot) - - Retrieve the decimal identifier of the Household that owns a Lot. - - :param lot: An instance of a Lot. - :type lot: Lot - :return: A decimal identifier of the Household that owns the specified Lot or -1 if a problem occurs. - :rtype: int - """ - if lot is None: - return -1 - return lot.owner_household_id - - @classmethod - def delete_household(cls, household: Household) -> bool: - """delete_household(household) - - Delete the specified household from the game. - - :param household: The Household to delete - :type household: Household - :return: True, if the Household was deleted successfully. False, if not. - :rtype: bool - """ - services.get_persistence_service().del_household_proto_buff(household.id) - services.household_manager().remove(household) - return True - - @classmethod - def delete_households_with_name(cls, name: str, allow_partial_match: bool = False) -> bool: - """delete_households_with_name(name, allow_partial_match=False) - - Delete all households with the specified name. - - :param name: The name of the households to delete. - :type name: str - :param allow_partial_match: If True, households only need to contain the name to match. - :type allow_partial_match: bool - :return: True, if Households were deleted successfully. False, if not. - :rtype: bool - """ - log = cls.get_log() - if allow_partial_match: - log.debug('Attempting to delete households containing name \'{}\'.'.format(name)) - else: - log.debug('Attempting to delete households with name \'{}\'.'.format(name)) - all_completed = True - for household in cls.locate_households_by_name_generator(name, allow_partial_match=allow_partial_match): - if household is None: - continue - result = cls.delete_household(household) - if not result: - all_completed = False - return all_completed - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.add_to_household', - 'Add a Sim to the household of another Sim.', - command_arguments=( - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance id or name of a Sim to add to the household.'), - CommonConsoleCommandArgument('target_household_sim_info', 'Sim Id or Name', 'The instance id or name of a Sim. The other Sim (sim_info) will be added to this Sims household.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.addtohousehold', - ) -) -def _common_command_add_to_my_household(output: CommonConsoleCommandOutput, sim_info: SimInfo = None, target_household_sim_info: SimInfo = None): - if sim_info is None: - return - if target_household_sim_info is None: - return - output(f'Attempting to move {sim_info} to the household of {target_household_sim_info}.') - result = CommonHouseholdUtils.add_sim_to_active_household(sim_info) - if result: - output(f'SUCCESS: Successfully moved {sim_info} to the household of {target_household_sim_info}.') - else: - output(f'FAILED: Failed to move {sim_info} to the household of {target_household_sim_info}.') - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.remove_from_household', - 'Remove a Sim from the household they are in and put them into their own household.', - command_arguments=( - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance id or name of a Sim to remove from their household.'), - ), - command_aliases=( - 's4clib.removefromhousehold', - ) -) -def _common_command_remove_from_my_household(output: CommonConsoleCommandOutput, sim_info: SimInfo): - if sim_info is None: - return - output(f'Attempting to move {sim_info} out of their current household.') - empty_household = CommonHouseholdUtils.create_empty_household() - result = CommonHouseholdUtils.move_sim_to_household(sim_info, household_id=empty_household.id, destroy_if_empty_household=True) - if result: - output(f'SUCCESS: Successfully removed {sim_info} from their current household.') - else: - output(f'FAILED: Failed to remove {sim_info} from their current household.') diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_mood_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_mood_utils.py deleted file mode 100644 index 1b204a9..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_mood_utils.py +++ /dev/null @@ -1,277 +0,0 @@ -""" -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 -""" -from sims.sim_info import SimInfo -from statistics.mood import Mood -from s4ap.sims4communitylib.enums.moods_enum import CommonMoodId - - -class CommonMoodUtils: - """Utilities for manipulating Sim moods. - - """ - @staticmethod - def is_angry(sim_info: SimInfo) -> bool: - """is_angry(sim_info) - - Determine if a Sim is angry. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is the Mood. False, if the Sim is not. - :rtype: bool - """ - return CommonMoodUtils.has_mood(sim_info, CommonMoodId.ANGRY) - - @staticmethod - def is_bored(sim_info: SimInfo) -> bool: - """is_bored(sim_info) - - Determine if a Sim is bored. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is the Mood. False, if the Sim is not. - :rtype: bool - """ - return CommonMoodUtils.has_mood(sim_info, CommonMoodId.BORED) - - @staticmethod - def is_confident(sim_info: SimInfo) -> bool: - """is_confident(sim_info) - - Determine if a Sim is confident. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is the Mood. False, if the Sim is not. - :rtype: bool - """ - return CommonMoodUtils.has_mood(sim_info, CommonMoodId.CONFIDENT) - - @staticmethod - def is_dazed(sim_info: SimInfo) -> bool: - """is_dazed(sim_info) - - Determine if a Sim is dazed. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is the Mood. False, if the Sim is not. - :rtype: bool - """ - return CommonMoodUtils.has_mood(sim_info, CommonMoodId.DAZED) - - @staticmethod - def is_embarrassed(sim_info: SimInfo) -> bool: - """is_embarrassed(sim_info) - - Determine if a Sim is embarrassed. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is the Mood. False, if the Sim is not. - :rtype: bool - """ - return CommonMoodUtils.has_mood(sim_info, CommonMoodId.EMBARRASSED) - - @staticmethod - def is_energized(sim_info: SimInfo) -> bool: - """is_energized(sim_info) - - Determine if a Sim is energized. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is the Mood. False, if the Sim is not. - :rtype: bool - """ - return CommonMoodUtils.has_mood(sim_info, CommonMoodId.ENERGIZED) - - @staticmethod - def is_fine(sim_info: SimInfo) -> bool: - """is_fine(sim_info) - - Determine if a Sim is fine. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is the Mood. False, if the Sim is not. - :rtype: bool - """ - return CommonMoodUtils.has_mood(sim_info, CommonMoodId.FINE) - - @staticmethod - def is_flirty(sim_info: SimInfo) -> bool: - """is_flirty(sim_info) - - Determine if a Sim is flirty. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is the Mood. False, if the Sim is not. - :rtype: bool - """ - return CommonMoodUtils.has_mood(sim_info, CommonMoodId.FLIRTY) - - @staticmethod - def is_focused(sim_info: SimInfo) -> bool: - """is_focused(sim_info) - - Determine if a Sim is focused. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is the Mood. False, if the Sim is not. - :rtype: bool - """ - return CommonMoodUtils.has_mood(sim_info, CommonMoodId.FOCUSED) - - @staticmethod - def is_happy(sim_info: SimInfo) -> bool: - """is_happy(sim_info) - - Determine if a Sim is happy. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is the Mood. False, if the Sim is not. - :rtype: bool - """ - return CommonMoodUtils.has_mood(sim_info, CommonMoodId.HAPPY) - - @staticmethod - def is_inspired(sim_info: SimInfo) -> bool: - """is_inspired(sim_info) - - Determine if a Sim is inspired. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is the Mood. False, if the Sim is not. - :rtype: bool - """ - return CommonMoodUtils.has_mood(sim_info, CommonMoodId.INSPIRED) - - @staticmethod - def is_playful(sim_info: SimInfo) -> bool: - """is_playful(sim_info) - - Determine if a Sim is playful. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is the Mood. False, if the Sim is not. - :rtype: bool - """ - return CommonMoodUtils.has_mood(sim_info, CommonMoodId.PLAYFUL) - - @staticmethod - def is_sad(sim_info: SimInfo) -> bool: - """is_sad(sim_info) - - Determine if a Sim is sad. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is the Mood. False, if the Sim is not. - :rtype: bool - """ - return CommonMoodUtils.has_mood(sim_info, CommonMoodId.SAD) - - @staticmethod - def is_stressed(sim_info: SimInfo) -> bool: - """is_stressed(sim_info) - - Determine if a Sim is stressed. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is the Mood. False, if the Sim is not. - :rtype: bool - """ - return CommonMoodUtils.has_mood(sim_info, CommonMoodId.STRESSED) - - @staticmethod - def is_uncomfortable(sim_info: SimInfo) -> bool: - """is_uncomfortable(sim_info) - - Determine if a Sim is uncomfortable. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is the Mood. False, if the Sim is not. - :rtype: bool - """ - return CommonMoodUtils.has_mood(sim_info, CommonMoodId.UNCOMFORTABLE) - - @staticmethod - def is_possessed(sim_info: SimInfo) -> bool: - """is_possessed(sim_info) - - Determine if a Sim is possessed. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is the Mood. False, if the Sim is not. - :rtype: bool - """ - return CommonMoodUtils.has_mood(sim_info, CommonMoodId.POSSESSED) - - @staticmethod - def is_sleeping(sim_info: SimInfo) -> bool: - """is_sleeping(sim_info) - - Determine if a Sim is sleeping. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is the Mood. False, if the Sim is not. - :rtype: bool - """ - return CommonMoodUtils.has_mood(sim_info, CommonMoodId.SLEEPING) - - @staticmethod - def has_mood(sim_info: SimInfo, mood_id: CommonMoodId) -> bool: - """has_mood(sim_info, mood_id) - - Determine if a Sim has the specified mood. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :param mood_id: The identifier of the Mood to check for. - :type mood_id: CommonMoodId - :return: True, if the Sim has the specified Mood. False, if the Sim does not. - :rtype: bool - """ - return CommonMoodUtils.get_current_mood_id(sim_info) == mood_id - - @staticmethod - def get_current_mood(sim_info: SimInfo) -> Mood: - """get_current_mood(sim_info) - - Retrieve the current mood for the specified Sim. - - :param sim_info: The Sim to retrieve the mood of. - :type sim_info: SimInfo - :return: The current Mood of the Sim. - :rtype: Mood - """ - return sim_info.get_mood() - - @staticmethod - def get_current_mood_id(sim_info: SimInfo) -> int: - """get_current_mood_id(sim_info) - - Retrieve an identifier of the current mood for the specified Sim. - - :param sim_info: The Sim to retrieve the mood identifier of. - :type sim_info: SimInfo - :return: The identifier of the current Mood of the Sim. - :rtype: int - """ - return getattr(CommonMoodUtils.get_current_mood(sim_info), 'guid64', -1) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_occult_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_occult_utils.py deleted file mode 100644 index 4073be8..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_occult_utils.py +++ /dev/null @@ -1,1876 +0,0 @@ -""" -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 -""" -import random -from typing import Iterator, Tuple, Union - -from sims.occult.occult_enums import OccultType -from sims.sim_info import SimInfo -from sims.sim_info_base_wrapper import SimInfoBaseWrapper -from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.dtos.common_cas_part import CommonCASPart -from s4ap.sims4communitylib.enums.buffs_enum import CommonBuffId -from s4ap.sims4communitylib.enums.common_bucks_types import CommonBucksType -from s4ap.sims4communitylib.enums.common_occult_type import CommonOccultType -from s4ap.sims4communitylib.enums.traits_enum import CommonTraitId -from s4ap.sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ - CommonConsoleCommandArgument -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.cas.common_cas_utils import CommonCASUtils -from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils -from s4ap.sims4communitylib.utils.sims.common_buff_utils import CommonBuffUtils -from s4ap.sims4communitylib.utils.sims.common_sim_appearance_modifier_utils import CommonSimAppearanceModifierUtils -from s4ap.sims4communitylib.utils.sims.common_sim_bucks_utils import CommonSimBucksUtils -from s4ap.sims4communitylib.utils.sims.common_sim_loot_action_utils import CommonSimLootActionUtils -from s4ap.sims4communitylib.utils.sims.common_sim_spell_utils import CommonSimSpellUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from s4ap.sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils -try: - from traits.trait_type import TraitType -except ModuleNotFoundError: - from traits.traits import TraitType - - -class CommonOccultUtils(_HasS4CLClassLog): - """Utilities for manipulating the Occults of Sims. - - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 'common_occult_utils' - - @classmethod - def get_all_occult_types_for_sim_gen(cls, sim_info: SimInfo) -> Iterator[OccultType]: - """get_all_occult_types_for_sim_gen(sim_info) - - Retrieve a generator of OccultType for all Occults of a Sim. - - .. note:: Results include the occult type of the sim_info specified.\ - If they are Human by default, the Human occult type will be included. - - :param sim_info: The Sim to locate the Occults of. - :type sim_info: SimInfo - :return: An iterator of OccultType for all occults of the Sim. (Results will not include Occult Types not within the OccultTypes enum, such as Skeleton, Robot, and Ghost! Use :class:`.CommonSimOccultTypeUtils` for more accurate results.) - :rtype: Iterator[OccultType] - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - yield OccultType.HUMAN - sim_occult_types = CommonOccultUtils._get_occult_types(sim_info) - for occult_type in OccultType.values: - if occult_type == OccultType.HUMAN: - continue - if sim_occult_types & occult_type: - yield occult_type - - @classmethod - def get_sim_info_for_all_occults_gen(cls, sim_info: SimInfo, exclude_occult_types: Iterator[OccultType]) -> Iterator[SimInfo]: - """get_sim_info_for_all_occults_gen(sim_info, exclude_occult_types) - - Retrieve a generator of SimInfo objects for all Occults of a sim. - - .. note:: Results include the occult type of the sim_info specified.\ - If they are Human by default, the Human occult Sim info will be included. - - :param sim_info: The Sim to locate the Occults of. - :type sim_info: SimInfo - :param exclude_occult_types: A collection of OccultTypes to exclude from the resulting SimInfo list. - :type exclude_occult_types: Iterator[OccultType] - :return: An iterator of Sims for all occult types of the Sim. - :rtype: Iterator[SimInfo] - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - exclude_occult_types: Tuple[OccultType] = tuple(exclude_occult_types) - yield sim_info - current_occult_type = CommonOccultUtils.get_current_occult_type(sim_info) - for occult_type in OccultType.values: - if occult_type in exclude_occult_types: - continue - if occult_type == current_occult_type: - continue - occult_sim_info: SimInfo = CommonOccultUtils.get_occult_sim_info(sim_info, occult_type) - if occult_sim_info is None: - continue - yield occult_sim_info - - @classmethod - def has_any_occult(cls, sim_info: SimInfo) -> CommonTestResult: - """has_any_occult(sim_info) - - Determine if a Sim has any Occult Types. - - :param sim_info: The Sim to locate the Occults of. - :type sim_info: SimInfo - :return: The result of testing. True, if the specified Sim has any Non-Human Occult Types. False, if not. - :rtype: CommonTestResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - from s4ap.sims4communitylib.utils.sims.common_sim_occult_type_utils import CommonSimOccultTypeUtils - occult_type = CommonSimOccultTypeUtils.determine_occult_type(sim_info) - if occult_type not in (CommonOccultType.NON_OCCULT, CommonOccultType.NONE): - return CommonTestResult(True, reason=f'Sim had an occult type. {occult_type}') - return CommonTestResult(False, reason=f'Sim did not have an occult type. {occult_type}') - - @classmethod - def has_occult_type(cls, sim_info: SimInfo, occult_type: OccultType) -> CommonTestResult: - """has_occult_type(sim_info, occult_type) - - Determine if a Sim has an Occult Type. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param occult_type: The Occult Type to check. - :type occult_type: OccultType - :return: The result of testing. True, if the Sim has the specified Occult Type. False, if not. - :rtype: CommonTestResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - if bool(CommonOccultUtils._get_occult_types(sim_info) & occult_type): - return CommonTestResult(True, reason=f'Sim had occult type {occult_type}.') - return CommonTestResult(False, reason=f'Sim did not have occult type {occult_type}') - - @classmethod - def has_occult_sim_info(cls, sim_info: SimInfo, occult_type: OccultType) -> CommonTestResult: - """has_occult_sim_info(sim_info, occult_type) - - Determine if a Sim has a SimInfo for an Occult. - - :param sim_info: The Sim to locate the Occults of. - :type sim_info: SimInfo - :param occult_type: The Occult Type to check. - :type occult_type: OccultType - :return: The result of testing. True, if a SimInfo is available for the specified Occult for the Sim. False, if not. - :rtype: CommonTestResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - if not hasattr(sim_info, 'occult_tracker') or sim_info.occult_tracker is None: - return CommonTestResult(False, reason='Sim did not have an occult tracker, thus they did not have any occult types.') - if sim_info.occult_tracker.has_occult_type(occult_type): - return CommonTestResult(True, reason=f'Sim had a Sim Info for {occult_type}.') - return CommonTestResult(False, reason=f'Sim did not have a Sim Info {occult_type}') - - @classmethod - def get_current_occult_sim_info(cls, sim_info: SimInfo) -> Union[SimInfo, SimInfoBaseWrapper, None]: - """get_current_occult_sim_info(sim_info) - - Retrieve the SimInfo for the Occult the Sim is currently. - - :param sim_info: The Sim to locate the Occults of. - :type sim_info: SimInfo - :return: The SimInfo of the Sim or the SimInfoBaseWrapper for the Occult they are (If they are currently an occult). - :rtype: Union[SimInfo, SimInfoBaseWrapper, None] - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - current_occult_type = CommonOccultUtils.get_current_occult_type(sim_info) - return CommonOccultUtils.get_occult_sim_info(sim_info, current_occult_type) - - @classmethod - def get_occult_sim_info(cls, sim_info: SimInfo, occult_type: OccultType) -> Union[SimInfo, SimInfoBaseWrapper]: - """get_occult_sim_info(sim_info, occult_type) - - Retrieve the SimInfo for an Occult of a Sim. - - :param sim_info: The Sim to locate the Occults of. - :type sim_info: SimInfo - :param occult_type: The Occult Type to retrieve the SimInfo of. - :type occult_type: OccultType - :return: The SimInfo of the Sim or the SimInfoBaseWrapper for the specified Occult or the original Sim Info, if the Sim did not have the occult type. - :rtype: Union[SimInfo, SimInfoBaseWrapper, None] - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - if not hasattr(sim_info, 'occult_tracker') or sim_info.occult_tracker is None: - return sim_info - occult_sim_info = sim_info.occult_tracker.get_occult_sim_info(occult_type) - return occult_sim_info - - @classmethod - def add_occult(cls, sim_info: SimInfo, occult_type: CommonOccultType) -> CommonExecutionResult: - """add_occult(sim_info, occult_type) - - Add an Occult Type to a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param occult_type: The occult type to add. - :type occult_type: CommonOccultType - :return: The result of adding the occult. True, if the specified Occult Type has been added to the Sim. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - is_occult_available_result = CommonOccultUtils.is_occult_available(occult_type) - if not is_occult_available_result: - return is_occult_available_result - occult_type_add_mappings = { - CommonOccultType.ALIEN: CommonOccultUtils.add_alien_occult, - CommonOccultType.MERMAID: CommonOccultUtils.add_mermaid_occult, - CommonOccultType.PLANT_SIM: CommonOccultUtils.add_plant_sim_occult, - CommonOccultType.ROBOT: CommonOccultUtils.add_robot_occult, - CommonOccultType.SCARECROW: CommonOccultUtils.add_scarecrow_occult, - CommonOccultType.SKELETON: CommonOccultUtils.add_skeleton_occult, - CommonOccultType.VAMPIRE: CommonOccultUtils.add_vampire_occult, - CommonOccultType.WITCH: CommonOccultUtils.add_witch_occult, - CommonOccultType.WEREWOLF: CommonOccultUtils.add_werewolf_occult - } - if occult_type not in occult_type_add_mappings: - return CommonExecutionResult(False, reason=f'The specified occult type did not have an add function. {occult_type.name}') - return occult_type_add_mappings[occult_type](sim_info) - - @classmethod - def remove_occult(cls, sim_info: SimInfo, occult_type: CommonOccultType) -> CommonExecutionResult: - """remove_occult(sim_info, occult_type) - - Remove an Occult Type from a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param occult_type: The occult type to remove. - :type occult_type: CommonOccultType - :return: The result of removing the occult. True, if the specified Occult Type has been removed from the Sim. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - is_occult_available_result = CommonOccultUtils.is_occult_available(occult_type) - if not is_occult_available_result: - return is_occult_available_result.reverse_result() - occult_type_remove_mappings = { - CommonOccultType.ALIEN: CommonOccultUtils.remove_alien_occult, - CommonOccultType.MERMAID: CommonOccultUtils.remove_mermaid_occult, - CommonOccultType.PLANT_SIM: CommonOccultUtils.remove_plant_sim_occult, - CommonOccultType.ROBOT: CommonOccultUtils.remove_robot_occult, - CommonOccultType.SCARECROW: CommonOccultUtils.remove_scarecrow_occult, - CommonOccultType.SKELETON: CommonOccultUtils.remove_skeleton_occult, - CommonOccultType.VAMPIRE: CommonOccultUtils.remove_vampire_occult, - CommonOccultType.WITCH: CommonOccultUtils.remove_witch_occult, - CommonOccultType.WEREWOLF: CommonOccultUtils.remove_werewolf_occult - } - if occult_type not in occult_type_remove_mappings: - return CommonExecutionResult(False, reason=f'The specified occult type did not have a remove function, meaning it has not been implemented yet. {occult_type.name}') - return occult_type_remove_mappings[occult_type](sim_info) - - @classmethod - def add_alien_occult(cls, sim_info: SimInfo) -> CommonExecutionResult: - """add_alien_occult(sim_info) - - Add the Alien Occult Type to a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of adding the Alien occult. True, if the Sim has successfully become an Alien. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - is_alien_available_result = CommonOccultUtils.is_alien_occult_available() - if not is_alien_available_result: - return is_alien_available_result - is_alien_result = CommonOccultUtils.is_alien(sim_info) - if is_alien_result: - return is_alien_result - loot_action_ids: Tuple[int, ...] = ( - # loot_Occult_AlienAdd - 103256, - # loot_Occult_AlienSwitch - 103254 - ) - # noinspection PyPropertyAccess - physique = sim_info.physique - # noinspection PyPropertyAccess - facial_attributes = sim_info.facial_attributes - # noinspection PyPropertyAccess - voice_pitch = sim_info.voice_pitch - # noinspection PyPropertyAccess - voice_actor = sim_info.voice_actor - # noinspection PyPropertyAccess - voice_effect = sim_info.voice_effect - # noinspection PyPropertyAccess - skin_tone = sim_info.skin_tone - flags = sim_info.flags - pelt_layers = None - if hasattr(sim_info, 'pelt_layers'): - # noinspection PyPropertyAccess - pelt_layers = sim_info.pelt_layers - base_trait_ids = None - if hasattr(sim_info, 'base_trait_ids'): - base_trait_ids = list(sim_info.base_trait_ids) - # noinspection PyPropertyAccess - genetic_data_b = sim_info.genetic_data - if hasattr(genetic_data_b, 'SerializeToString'): - genetic_data_b = genetic_data_b.SerializeToString() - result = CommonSimLootActionUtils.apply_loot_actions_by_ids_to_sim(loot_action_ids, sim_info) - human_sim_info = sim_info.occult_tracker.get_occult_sim_info(OccultType.HUMAN) - human_sim_info.physique = physique - human_sim_info.facial_attributes = facial_attributes - human_sim_info.voice_pitch = voice_pitch - human_sim_info.voice_actor = voice_actor - human_sim_info.voice_effect = voice_effect - human_sim_info.skin_tone = skin_tone - human_sim_info.flags = flags - if pelt_layers is not None: - human_sim_info.pelt_layers = pelt_layers - if base_trait_ids is not None: - human_sim_info.base_trait_ids = list(base_trait_ids) - if hasattr(human_sim_info.genetic_data, 'MergeFromString'): - human_sim_info.genetic_data.MergeFromString(genetic_data_b) - else: - human_sim_info.genetic_data = genetic_data_b - if result: - return CommonExecutionResult.TRUE - return CommonExecutionResult.FALSE - - @classmethod - def remove_alien_occult(cls, sim_info: SimInfo) -> CommonExecutionResult: - """remove_alien_occult(sim_info) - - Remove the Alien Occult Type from a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of removing the alien occult. True, if the Alien Occult Type has been successfully removed from the specified Sim. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - is_alien_available_result = CommonOccultUtils.is_alien_occult_available() - if not is_alien_available_result: - return is_alien_available_result.reverse_result() - is_alien_result = CommonOccultUtils.is_alien(sim_info) - if not is_alien_result: - return is_alien_result.reverse_result() - CommonOccultUtils.switch_to_occult_form(sim_info, OccultType.HUMAN) - sim_info.occult_tracker.remove_occult_type(OccultType.ALIEN) - return CommonExecutionResult.TRUE - - @classmethod - def add_mermaid_occult(cls, sim_info: SimInfo) -> CommonExecutionResult: - """add_mermaid_occult(sim_info) - - Add the Mermaid Occult Type to a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of adding the mermaid occult. True, if the Sim has successfully become a Mermaid. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - is_mermaid_available_result = CommonOccultUtils.is_mermaid_occult_available() - if not is_mermaid_available_result: - return is_mermaid_available_result - is_mermaid_result = CommonOccultUtils.is_mermaid(sim_info) - if is_mermaid_result: - return is_mermaid_result - # loot_Mermaid_DebugAdd - add_loot_action_id = 205399 - if CommonSimLootActionUtils.apply_loot_actions_by_id_to_sim(add_loot_action_id, sim_info): - return CommonExecutionResult.TRUE - return CommonExecutionResult.FALSE - - @classmethod - def remove_mermaid_occult(cls, sim_info: SimInfo) -> CommonExecutionResult: - """remove_mermaid_occult(sim_info) - - Remove the Mermaid Occult Type from a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of removing the mermaid occult. True, if the Mermaid Occult Type has been successfully removed from the specified Sim. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - is_mermaid_available_result = CommonOccultUtils.is_mermaid_occult_available() - if not is_mermaid_available_result: - return is_mermaid_available_result.reverse_result() - is_mermaid_result = CommonOccultUtils.is_mermaid(sim_info) - if not is_mermaid_result: - return is_mermaid_result.reverse_result() - traits: Tuple[Union[int, CommonTraitId], ...] = ( - CommonTraitId.OCCULT_MERMAID_MERMAID_FORM, - CommonTraitId.OCCULT_MERMAID_DISCOVERED, - CommonTraitId.OCCULT_MERMAID_TEMPORARY_DISCOVERED, - CommonTraitId.OCCULT_MERMAID_TYAE, - CommonTraitId.OCCULT_MERMAID, - ) - CommonOccultUtils.switch_to_occult_form(sim_info, OccultType.HUMAN) - return CommonTraitUtils.remove_traits(sim_info, traits) - - @classmethod - def add_plant_sim_occult(cls, sim_info: SimInfo) -> CommonExecutionResult: - """add_plant_sim_occult(sim_info) - - Add the Plant Sim Occult Type to a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of adding the Plant Sim occult. True, if the Sim has successfully become a Plant Sim. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - is_plant_sim_available_result = CommonOccultUtils.is_plant_sim_occult_available() - if not is_plant_sim_available_result: - return is_plant_sim_available_result - # loot_Buff_PlantSims_BecomePlantSim - add_loot_action_id = 163440 - if CommonSimLootActionUtils.apply_loot_actions_by_id_to_sim(add_loot_action_id, sim_info): - return CommonExecutionResult.TRUE - return CommonExecutionResult.FALSE - - @classmethod - def remove_plant_sim_occult(cls, sim_info: SimInfo) -> CommonExecutionResult: - """remove_plant_sim_occult(sim_info) - - Remove the Plant Sim Occult Type from a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of removing the Plant Sim occult. True, if the Plant Sim Occult Type has been successfully removed from the specified Sim. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - is_plant_sim_available_result = CommonOccultUtils.is_plant_sim_occult_available() - if not is_plant_sim_available_result: - return is_plant_sim_available_result.reverse_result() - remove_result = CommonBuffUtils.remove_buff(sim_info, CommonBuffId.PLANT_SIMS_MAIN_VISIBLE) - if not remove_result: - return remove_result - return CommonExecutionResult.TRUE - - @classmethod - def add_robot_occult(cls, sim_info: SimInfo) -> CommonExecutionResult: - """add_robot_occult(sim_info) - - Add the Robot Occult Type to a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of adding the robot occult. True, if the Sim has successfully become a Robot. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - is_robot_available_result = CommonOccultUtils.is_robot_occult_available() - if not is_robot_available_result: - return is_robot_available_result - is_robot_result = CommonOccultUtils.is_robot(sim_info) - if is_robot_result: - return is_robot_result - return CommonTraitUtils.add_trait(sim_info, CommonTraitId.OCCULT_ROBOT) - - @classmethod - def remove_robot_occult(cls, sim_info: SimInfo) -> CommonExecutionResult: - """remove_robot_occult(sim_info) - - Remove the Robot Occult Type from a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of removing the robot occult. True, if the Robot Occult Type has been successfully removed from the specified Sim. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - is_robot_available_result = CommonOccultUtils.is_robot_occult_available() - if not is_robot_available_result: - return is_robot_available_result.reverse_result() - is_robot_result = CommonOccultUtils.is_robot(sim_info) - if not is_robot_result: - return is_robot_result.reverse_result() - return CommonTraitUtils.remove_trait(sim_info, CommonTraitId.OCCULT_ROBOT) - - @classmethod - def add_scarecrow_occult(cls, sim_info: SimInfo) -> CommonExecutionResult: - """add_scarecrow_occult(sim_info) - - Add the Scarecrow Occult Type to a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of adding the Scarecrow occult. True, if the Sim has successfully become a Scarecrow. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - is_scarecrow_available_result = CommonOccultUtils.is_scarecrow_occult_available() - if not is_scarecrow_available_result: - return is_scarecrow_available_result - is_scarecrow_result = CommonOccultUtils.is_scarecrow(sim_info) - if is_scarecrow_result: - return is_scarecrow_result - - if not CommonTraitUtils.add_trait(sim_info, CommonTraitId.SCARECROW): - return CommonTestResult(False, reason=f'Failed to add scarecrow trait to {sim_info}.') - - scarecrow_cas_part_ids = ( - # yuBody_EP05ScareCrow_Gray - 198149, - # yuBody_EP05ScareCrow_Red - 198148, - # yuBody_EP05ScareCrow_Purple - 198147 - ) - chosen_id = random.choice(scarecrow_cas_part_ids) - from s4ap.sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils - if CommonCASUtils.attach_cas_part_to_all_outfits_of_sim(sim_info, CommonCASPart(chosen_id)): - current_outfit_category_and_index = CommonOutfitUtils.get_current_outfit(sim_info) - CommonOutfitUtils.trigger_outfit_generated(sim_info, current_outfit_category_and_index) - CommonOutfitUtils.set_outfit_dirty(sim_info, current_outfit_category_and_index[0]) - CommonOutfitUtils.set_current_outfit(sim_info, current_outfit_category_and_index) - return CommonExecutionResult(True, reason=f'{sim_info} is now a Scarecrow.') - CommonSimAppearanceModifierUtils.evaluate_appearance_modifiers(sim_info) - return CommonExecutionResult(False, reason=f'Failed to turn {sim_info} into a Scarecrow.') - - @classmethod - def remove_scarecrow_occult(cls, sim_info: SimInfo) -> CommonExecutionResult: - """remove_scarecrow_occult(sim_info) - - Remove the Scarecrow Occult Type from a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of removing the Scarecrow occult. True, if the Scarecrow Occult Type has been successfully removed from the specified Sim. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - is_scarecrow_available_result = CommonOccultUtils.is_scarecrow_occult_available() - if not is_scarecrow_available_result: - return is_scarecrow_available_result.reverse_result() - is_scarecrow_result = CommonOccultUtils.is_scarecrow(sim_info) - if not is_scarecrow_result: - return is_scarecrow_result.reverse_result() - scarecrow_cas_parts = ( - # yuBody_EP05ScareCrow_Gray - CommonCASPart(198149), - # yuBody_EP05ScareCrow_Red - CommonCASPart(198148), - # yuBody_EP05ScareCrow_Purple - CommonCASPart(198147) - ) - - from s4ap.sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils - if CommonCASUtils.detach_cas_parts_from_all_outfits_of_sim(sim_info, scarecrow_cas_parts): - current_outfit_category_and_index = CommonOutfitUtils.get_current_outfit(sim_info) - CommonOutfitUtils.trigger_outfit_generated(sim_info, current_outfit_category_and_index) - CommonOutfitUtils.set_outfit_dirty(sim_info, current_outfit_category_and_index[0]) - CommonOutfitUtils.set_current_outfit(sim_info, current_outfit_category_and_index) - return CommonTraitUtils.remove_trait(sim_info, CommonTraitId.SCARECROW) - - @classmethod - def add_skeleton_occult(cls, sim_info: SimInfo) -> CommonExecutionResult: - """add_skeleton_occult(sim_info) - - Add the Skeleton Occult Type to a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of adding the Skeleton occult. True, if the Sim has successfully become a Skeleton. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - is_skeleton_available_result = CommonOccultUtils.is_skeleton_occult_available() - if not is_skeleton_available_result: - return is_skeleton_available_result - is_skeleton_result = CommonOccultUtils.is_skeleton(sim_info) - if is_skeleton_result: - return is_skeleton_result - # loot_Skeleton_Add - add_loot_id = 175969 - if CommonSimLootActionUtils.apply_loot_actions_by_id_to_sim(add_loot_id, sim_info): - return CommonExecutionResult.TRUE - return CommonExecutionResult.FALSE - - @classmethod - def remove_skeleton_occult(cls, sim_info: SimInfo) -> CommonExecutionResult: - """remove_skeleton_occult(sim_info) - - Remove the Skeleton Occult Type from a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of removing the Skeleton occult. True, if the Skeleton Occult Type has been successfully removed from the specified Sim. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - is_skeleton_available_result = CommonOccultUtils.is_skeleton_occult_available() - if not is_skeleton_available_result: - return is_skeleton_available_result.reverse_result() - is_skeleton_result = CommonOccultUtils.is_skeleton(sim_info) - if not is_skeleton_result: - return is_skeleton_result.reverse_result() - # loot_Skeleton_Remove - remove_loot_id = 175975 - if CommonSimLootActionUtils.apply_loot_actions_by_id_to_sim(remove_loot_id, sim_info): - return CommonExecutionResult.TRUE - return CommonExecutionResult.FALSE - - @classmethod - def add_vampire_occult(cls, sim_info: SimInfo) -> CommonExecutionResult: - """add_vampire_occult(sim_info) - - Add the Vampire Occult Type to a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of adding the Vampire occult. True, if the Sim has successfully become a Vampire. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - is_vampire_available_result = CommonOccultUtils.is_vampire_occult_available() - if not is_vampire_available_result: - return is_vampire_available_result - is_vampire_result = CommonOccultUtils.is_vampire(sim_info) - if is_vampire_result: - return is_vampire_result - # loot_VampireCreation_NewVampire - add_loot_id = 149538 - if CommonSimLootActionUtils.apply_loot_actions_by_id_to_sim(add_loot_id, sim_info): - return CommonExecutionResult.TRUE - return CommonExecutionResult.FALSE - - @classmethod - def remove_vampire_occult(cls, sim_info: SimInfo) -> CommonExecutionResult: - """remove_vampire_occult(sim_info) - - Remove the Vampire Occult Type from a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of removing the Vampire occult. True, if the Vampire Occult Type has been successfully removed from the specified Sim. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - is_vampire_available_result = CommonOccultUtils.is_vampire_occult_available() - if not is_vampire_available_result: - return is_vampire_available_result.reverse_result() - is_vampire_result = CommonOccultUtils.is_vampire(sim_info) - if not is_vampire_result: - is_vampire_result.reverse_result() - loot_action_ids: Tuple[int, ...] = ( - # loot_VampireCure_RemoveVampirism - 150170, - # loot_Life_ResetProgress - 31238 - ) - result = CommonSimLootActionUtils.apply_loot_actions_by_ids_to_sim(loot_action_ids, sim_info) - if result: - CommonSimBucksUtils.remove_all_perks(sim_info, CommonBucksType.VAMPIRE_POWER, reason='Vampire removed', remove_perk_points=True) - CommonSimBucksUtils.remove_all_perks(sim_info, CommonBucksType.VAMPIRE_WEAKNESS, reason='Vampire removed', remove_perk_points=True) - return CommonExecutionResult.TRUE - return CommonExecutionResult.FALSE - - @classmethod - def add_witch_occult(cls, sim_info: SimInfo) -> CommonExecutionResult: - """add_witch_occult(sim_info) - - Add the Witch Occult Type to a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of adding the Witch occult. True, if the Sim has successfully become a Witch. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - is_witch_available_result = CommonOccultUtils.is_witch_occult_available() - if not is_witch_available_result: - return is_witch_available_result - is_witch_result = CommonOccultUtils.is_witch(sim_info) - if is_witch_result: - return is_witch_result - # loot_WitchOccult_AddOccult - add_loot_id = 215080 - if CommonSimLootActionUtils.apply_loot_actions_by_id_to_sim(add_loot_id, sim_info): - return CommonExecutionResult.TRUE - return CommonExecutionResult.FALSE - - @classmethod - def remove_witch_occult(cls, sim_info: SimInfo) -> CommonExecutionResult: - """remove_witch_occult(sim_info) - - Remove the Witch Occult Type from a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of removing the Witch occult. True, if the Witch Occult Type has been successfully removed from the specified Sim. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - is_witch_available_result = CommonOccultUtils.is_witch_occult_available() - if not is_witch_available_result: - is_witch_available_result.reverse_result() - is_witch_result = CommonOccultUtils.is_witch(sim_info) - if not is_witch_result: - return is_witch_result.reverse_result() - # loot_WitchOccult_RemoveOccult - remove_loot_id = 215274 - result = CommonSimLootActionUtils.apply_loot_actions_by_id_to_duo_sims(remove_loot_id, sim_info, sim_info) - if result: - CommonSimBucksUtils.remove_all_perks(sim_info, CommonBucksType.WITCH_PERK, reason='Witch removed', remove_perk_points=True) - CommonSimSpellUtils.remove_all_spells(sim_info) - return CommonExecutionResult.TRUE - return CommonExecutionResult.FALSE - - @classmethod - def add_werewolf_occult(cls, sim_info: SimInfo) -> CommonExecutionResult: - """add_werewolf_occult(sim_info) - - Add the Werewolf Occult Type to a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of adding the Werewolf occult. True, if the Sim has successfully become a Werewolf. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - is_werewolf_available_result = CommonOccultUtils.is_werewolf_occult_available() - if not is_werewolf_available_result: - return is_werewolf_available_result - is_werewolf_result = CommonOccultUtils.is_werewolf(sim_info) - if is_werewolf_result: - return is_werewolf_result - # loot_Werewolf_AddOccultTrait - add_loot_id = 290058 - if CommonSimLootActionUtils.apply_loot_actions_by_id_to_sim(add_loot_id, sim_info): - return CommonExecutionResult.TRUE - return CommonExecutionResult.FALSE - - @classmethod - def remove_werewolf_occult(cls, sim_info: SimInfo) -> CommonExecutionResult: - """remove_werewolf_occult(sim_info) - - Remove the Werewolf Occult Type from a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of removing the Werewolf occult. True, if the Werewolf Occult Type has been successfully removed from the specified Sim. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - is_werewolf_available_result = CommonOccultUtils.is_werewolf_occult_available() - if not is_werewolf_available_result: - return is_werewolf_available_result.reverse_result() - is_werewolf_result = CommonOccultUtils.is_werewolf(sim_info) - if not is_werewolf_result: - return is_werewolf_result.reverse_result() - # loot_WerewolfCreation_WerewolfCure - remove_loot_id = 291816 - result = CommonSimLootActionUtils.apply_loot_actions_by_id_to_sim(remove_loot_id, sim_info) - if result: - CommonSimBucksUtils.remove_all_perks(sim_info, CommonBucksType.WEREWOLF_ABILITY, reason='Werewolf removed', remove_perk_points=True) - return CommonExecutionResult.TRUE - return CommonExecutionResult.FALSE - - @classmethod - def add_all_occults(cls, sim_info: SimInfo) -> CommonExecutionResult: - """add_all_occults(sim_info) - - Add all Occult Types to a Sim. i.e. Make them an Alien, a Vampire, a Witch, etc. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of adding all occult types. True, if all Occult Types were successfully added to the specified Sim. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - switch_to_non_occult_form_result = CommonOccultUtils.switch_to_occult_form(sim_info, OccultType.HUMAN) - if not switch_to_non_occult_form_result: - return switch_to_non_occult_form_result - for occult_type in CommonOccultType.get_all(exclude_occult_types=(CommonOccultType.NON_OCCULT, CommonOccultType.GHOST, CommonOccultType.PLANT_SIM, CommonOccultType.ROBOT, CommonOccultType.SKELETON)): - if not CommonOccultUtils.is_occult_available(occult_type): - continue - add_result = CommonOccultUtils.add_occult(sim_info, occult_type) - if not add_result: - return add_result - return CommonExecutionResult.TRUE - - @classmethod - def remove_all_occults(cls, sim_info: SimInfo) -> CommonExecutionResult: - """remove_all_occults(sim_info) - - Remove all Occult Types from a Sim. i.e. Make them a Non-Occult only. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of removing all occult types. True, if all Occult Types were successfully removed from the specified Sim. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - switch_to_non_occult_form_result = CommonOccultUtils.switch_to_occult_form(sim_info, OccultType.HUMAN) - if not switch_to_non_occult_form_result: - return switch_to_non_occult_form_result - for occult_type in CommonOccultType.get_all(exclude_occult_types=(CommonOccultType.NON_OCCULT, CommonOccultType.GHOST, CommonOccultType.PLANT_SIM)): - if not CommonOccultUtils.is_occult_available(occult_type): - continue - remove_result = CommonOccultUtils.remove_occult(sim_info, occult_type) - if not remove_result: - return remove_result - - if CommonOccultUtils.is_occult_available(CommonOccultType.GHOST): - remove_result = CommonOccultUtils.remove_occult(sim_info, CommonOccultType.GHOST) - if not remove_result: - return remove_result - - if CommonOccultUtils.is_occult_available(CommonOccultType.PLANT_SIM): - remove_result = CommonOccultUtils.remove_occult(sim_info, CommonOccultType.PLANT_SIM) - if not remove_result: - return remove_result - return CommonExecutionResult.TRUE - - @classmethod - def switch_to_occult_form(cls, sim_info: SimInfo, occult_type: Union[OccultType, CommonOccultType]) -> CommonExecutionResult: - """switch_to_occult_form(sim_info, occult_type) - - Switch a Sim to an Occult Form. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param occult_type: The type of Occult to switch to. - :type occult_type: Union[OccultType, CommonOccultType] - :return: The result of switching a Sim to an occult form. True, if the Sim successfully switched to the specified Occult Type. False, if the Sim failed to switch to the specified Occult Type or if they do not have that Occult Type to switch to. - :rtype: CommonExecutionResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - if isinstance(occult_type, CommonOccultType): - vanilla_occult_type = CommonOccultType.convert_to_vanilla(occult_type) - if vanilla_occult_type is None: - return CommonExecutionResult(False, reason=f'Sim failed to switch to occult type {occult_type.name}') - else: - vanilla_occult_type = occult_type - # noinspection PyPropertyAccess - sim_info.occult_tracker.set_pending_occult_type(vanilla_occult_type) - sim_info.occult_tracker.switch_to_occult_type(vanilla_occult_type) - return CommonExecutionResult.TRUE - - @classmethod - def is_vampire(cls, sim_info: SimInfo) -> CommonTestResult: - """is_vampire(sim_info) - - Determine if a Sim is a Vampire. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim is a Vampire. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - is_vampire_available_result = CommonOccultUtils.is_vampire_occult_available() - if not is_vampire_available_result: - return is_vampire_available_result - return CommonTraitUtils.has_trait(sim_info, CommonTraitId.OCCULT_VAMPIRE) or CommonOccultUtils.has_occult_type(sim_info, OccultType.VAMPIRE) - - @classmethod - def is_alien(cls, sim_info: SimInfo) -> CommonTestResult: - """is_alien(sim_info) - - Determine if a Sim is an Alien. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim is an Alien. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - is_alien_available_result = CommonOccultUtils.is_alien_occult_available() - if not is_alien_available_result: - return is_alien_available_result - return CommonTraitUtils.has_trait(sim_info, CommonTraitId.OCCULT_ALIEN) or CommonOccultUtils.has_occult_type(sim_info, OccultType.ALIEN) - - @classmethod - def is_plant_sim(cls, sim_info: SimInfo) -> CommonTestResult: - """is_plant_sim(sim_info) - - Determine if a Sim is a Plant Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim is a Plant Sim. False, if not. - :rtype: CommonTestResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - is_plant_sim_available_result = CommonOccultUtils.is_plant_sim_occult_available() - if not is_plant_sim_available_result: - return is_plant_sim_available_result - return CommonTraitUtils.has_trait(sim_info, CommonTraitId.PLANT_SIM) - - @classmethod - def is_ghost(cls, sim_info: SimInfo) -> CommonTestResult: - """is_ghost(sim_info) - - Determine if a Sim is a Ghost. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim is a Ghost. False, if not. - :rtype: CommonTestResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - is_ghost_available_result = CommonOccultUtils.is_ghost_occult_available() - if not is_ghost_available_result: - return is_ghost_available_result - equipped_sim_traits = CommonTraitUtils.get_equipped_traits(sim_info) - for trait in equipped_sim_traits: - if CommonTraitUtils.is_ghost_trait(trait): - return CommonTestResult.TRUE - return CommonTestResult(False, reason=f'Sim is not a ghost.') - - @classmethod - def is_scarecrow(cls, sim_info: SimInfo) -> CommonTestResult: - """is_scarecrow(sim_info) - - Determine if a Sim is a Scarecrow. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim is a Scarecrow. False, if not. - :rtype: CommonTestResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - is_scarecrow_available_result = CommonOccultUtils.is_scarecrow_occult_available() - if not is_scarecrow_available_result: - return is_scarecrow_available_result - if CommonTraitUtils.has_trait(sim_info, CommonTraitId.SCARECROW): - return CommonTestResult(True, reason=f'{sim_info} is a Scarecrow.') - return CommonTestResult(False, reason=f'{sim_info} is not a Scarecrow.') - - @classmethod - def is_robot(cls, sim_info: SimInfo) -> CommonTestResult: - """is_robot(sim_info) - - Determine if a Sim is a Robot. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim is a Robot. False, if not. - :rtype: CommonTestResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - is_robot_available_result = CommonOccultUtils.is_robot_occult_available() - if not is_robot_available_result: - return is_robot_available_result - equipped_sim_traits = CommonTraitUtils.get_equipped_traits(sim_info) - for trait in equipped_sim_traits: - trait_type = getattr(trait, 'trait_type', -1) - if trait_type == TraitType.ROBOT: - return CommonTestResult.TRUE - return CommonTestResult(False, reason=f'Sim is not a robot.') - - @classmethod - def is_skeleton(cls, sim_info: SimInfo) -> CommonTestResult: - """is_skeleton(sim_info) - - Determine if a Sim is a Skeleton. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim is the a Skeleton. False, if not. - :rtype: CommonTestResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - is_skeleton_available_result = CommonOccultUtils.is_skeleton_occult_available() - if not is_skeleton_available_result: - return is_skeleton_available_result - equipped_sim_traits = CommonTraitUtils.get_equipped_traits(sim_info) - skeleton_trait_ids = { - CommonTraitId.HIDDEN_SKELETON, - CommonTraitId.HIDDEN_SKELETON_SERVICE_SKELETON, - CommonTraitId.HIDDEN_SKELETON_TEMPLE_SKELETON - } - for trait in equipped_sim_traits: - trait_id = CommonTraitUtils.get_trait_id(trait) - if trait_id in skeleton_trait_ids: - return CommonTestResult.TRUE - return CommonTestResult(False, reason=f'Sim is not a skeleton.') - - @classmethod - def is_werewolf(cls, sim_info: SimInfo) -> CommonTestResult: - """is_werewolf(sim_info) - - Determine if a Sim is a Werewolf - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim is a Werewolf. False, if not. - :rtype: CommonTestResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - is_werewolf_available_result = CommonOccultUtils.is_werewolf_occult_available() - if not is_werewolf_available_result: - return is_werewolf_available_result - if CommonOccultUtils._has_occult_trait(sim_info, CommonTraitId.OCCULT_WEREWOLF): - return CommonTestResult(True, reason=f'Sim had the Werewolf occult trait.') - if CommonOccultUtils.has_occult_type(sim_info, OccultType.WEREWOLF): - return CommonTestResult(True, reason=f'Sim had the Werewolf occult type.') - return CommonTestResult(False, reason=f'Sim ') - - @classmethod - def is_witch(cls, sim_info: SimInfo) -> CommonTestResult: - """is_witch(sim_info) - - Determine if a Sim is a Witch - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim is a Witch. False, if not. - :rtype: CommonTestResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - is_witch_available_result = CommonOccultUtils.is_witch_occult_available() - if not is_witch_available_result: - return is_witch_available_result - if CommonOccultUtils._has_occult_trait(sim_info, CommonTraitId.OCCULT_WITCH): - return CommonTestResult(True, reason=f'Sim had the Witch occult trait.') - if CommonOccultUtils.has_occult_type(sim_info, OccultType.WITCH): - return CommonTestResult(True, reason=f'Sim had the Witch occult type.') - return CommonTestResult(False, reason=f'Sim is not a Witch.') - - @classmethod - def is_mermaid(cls, sim_info: SimInfo) -> CommonTestResult: - """is_mermaid(sim_info) - - Determine if a Sim is a Mermaid - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim is a Mermaid. False, if not. - :rtype: CommonTestResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - is_mermaid_available_result = CommonOccultUtils.is_mermaid_occult_available() - if not is_mermaid_available_result: - return is_mermaid_available_result - if CommonOccultUtils._has_occult_trait(sim_info, CommonTraitId.OCCULT_MERMAID): - return CommonTestResult(True, reason=f'Sim had the Mermaid occult trait.') - if CommonOccultUtils.has_occult_type(sim_info, OccultType.MERMAID): - return CommonTestResult(True, reason=f'Sim had the Mermaid occult type.') - return CommonTestResult(False, reason=f'Sim is not a Witch.') - - @classmethod - def is_in_mermaid_form(cls, sim_info: SimInfo) -> CommonTestResult: - """is_in_mermaid_form(sim_info) - - Determine if a Sim is in Mermaid Form (The Sim has a visible Tail). - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim has their Mermaid tail out. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - is_mermaid_available_result = CommonOccultUtils.is_mermaid_occult_available() - if not is_mermaid_available_result: - return is_mermaid_available_result - if CommonOccultUtils.get_current_occult_type(sim_info) == OccultType.MERMAID: - return CommonTestResult(True, reason=f'Sim is currently in Mermaid Form.') - return CommonTestResult(False, reason=f'Sim is not in Mermaid Form.') - - @classmethod - def is_mermaid_in_mermaid_form(cls, sim_info: SimInfo) -> CommonTestResult: - """is_mermaid_in_mermaid_form(sim_info) - - Determine if a Sim is a Mermaid and is in Mermaid Form (Their Tail is visible). - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim is a Mermaid with their tail out. False, if not. - :rtype: CommonTestResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - is_mermaid_available_result = CommonOccultUtils.is_mermaid_occult_available() - if not is_mermaid_available_result: - return is_mermaid_available_result - is_mermaid_result = CommonOccultUtils.is_mermaid(sim_info) - if not is_mermaid_result: - return is_mermaid_result - is_in_mermaid_form_result = CommonOccultUtils.is_in_mermaid_form(sim_info) - if not is_in_mermaid_form_result: - return is_in_mermaid_form_result - return CommonTestResult.TRUE - - @classmethod - def is_currently_human(cls, sim_info: SimInfo) -> CommonExecutionResult: - """is_currently_human(sim_info) - - Determine if a Sim is currently in their Human form (regardless of their Occult type). - - .. note:: The Human Occult is not the same as the Human Species! This means that Pets can have a "Human" Occult as their Non-Occult. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim is currently a Human. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - return CommonOccultUtils.is_currently_a_non_occult(sim_info) - - @classmethod - def is_currently_a_non_occult(cls, sim_info: SimInfo) -> CommonExecutionResult: - """is_currently_a_non_occult(sim_info) - - Determine if a Sim is currently in a Non-Occult form (regardless of their Occult type). - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim is currently in their Non-Occult form. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - if not hasattr(OccultType, 'HUMAN'): - return CommonExecutionResult(False, reason='Humans do not exist. They are a myth! (At least in this persons game)') - current_occult = CommonOccultUtils.get_current_occult_type(sim_info) - if current_occult == OccultType.HUMAN: - return CommonExecutionResult(True, reason='Sim is currently a Human.') - return CommonExecutionResult(False, reason='Sim is not currently a Human.') - - @classmethod - def is_currently_a_mermaid(cls, sim_info: SimInfo) -> CommonTestResult: - """is_currently_a_mermaid(sim_info) - - Determine if a Sim is currently in a Mermaid form. (Not disguised) - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim is currently in their Mermaid form. False, if not. - :rtype: CommonTestResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - return CommonOccultUtils.is_in_mermaid_form(sim_info) - - @classmethod - def is_currently_a_robot(cls, sim_info: SimInfo) -> CommonTestResult: - """is_currently_a_robot(sim_info) - - Determine if a Sim is currently in their Robot form. - - .. note:: In base game, if a Sim is a Robot then they are automatically in their Robot Form, since Robots do not have an alternative form. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim is currently in their Robot form. False, if not. - :rtype: CommonTestResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - return CommonOccultUtils.is_robot(sim_info) - - @classmethod - def is_currently_a_scarecrow(cls, sim_info: SimInfo) -> CommonTestResult: - """is_currently_a_scarecrow(sim_info) - - Determine if a Sim is currently in their Scarecrow form. - - .. note:: In base game, if a Sim is a Scarecrow then they are automatically in their Scarecrow Form, since Scarecrows do not have an alternative form. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim is currently in their Scarecrow form. False, if not. - :rtype: CommonTestResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - return CommonOccultUtils.is_scarecrow(sim_info) - - @classmethod - def is_currently_a_skeleton(cls, sim_info: SimInfo) -> CommonTestResult: - """is_currently_a_skeleton(sim_info) - - Determine if a Sim is currently in their Skeleton form. - - .. note:: In base game, if a Sim is a Skeleton then they are automatically in their Skeleton Form, since Skeletons do not have an alternative form. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim is currently in their Skeleton form. False, if not. - :rtype: CommonTestResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - return CommonOccultUtils.is_skeleton(sim_info) - - @classmethod - def is_currently_a_plant_sim(cls, sim_info: SimInfo) -> CommonTestResult: - """is_currently_a_plant_sim(sim_info) - - Determine if a Sim is currently in their Plant Sim form. - - .. note:: In base game, if a Sim is a Plant Sim then they are automatically in their Plant Sim Form, since Plant Sims do not have an alternative form. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim is currently in their Plant Sim form. False, if not. - :rtype: CommonTestResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - return CommonOccultUtils.is_plant_sim(sim_info) - - @classmethod - def is_currently_a_ghost(cls, sim_info: SimInfo) -> CommonTestResult: - """is_currently_a_ghost(sim_info) - - Determine if a Sim is currently in their Ghost form. - - .. note:: In base game, if a Sim is a Ghost then they are automatically in their Ghost Form, since Ghosts do not have an alternative form. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim is currently in their Ghost form. False, if not. - :rtype: CommonTestResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - return CommonOccultUtils.is_ghost(sim_info) - - @classmethod - def is_currently_a_vampire(cls, sim_info: SimInfo) -> CommonTestResult: - """is_currently_a_vampire(sim_info) - - Determine if a Sim is currently in their Vampire form. (Not disguised) - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim is currently in their Vampire form. False, if not. - :rtype: CommonTestResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - is_vampire_available_result = CommonOccultUtils.is_vampire_occult_available() - if not is_vampire_available_result: - return is_vampire_available_result - if CommonOccultUtils.get_current_occult_type(sim_info) == OccultType.VAMPIRE: - return CommonTestResult(True, reason='Sim is currently a Vampire.') - return CommonTestResult(False, reason='Sim is not currently a Vampire.') - - @classmethod - def is_currently_an_alien(cls, sim_info: SimInfo) -> CommonTestResult: - """is_currently_an_alien(sim_info) - - Determine if a Sim is currently in their Alien form. (Not disguised) - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim is currently in their Alien form. False, if not. - :rtype: CommonTestResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - is_alien_available_result = CommonOccultUtils.is_alien_occult_available() - if not is_alien_available_result: - return is_alien_available_result - if CommonOccultUtils.get_current_occult_type(sim_info) == OccultType.ALIEN: - return CommonTestResult(True, reason='Sim is currently an Alien.') - return CommonTestResult(False, reason='Sim is not currently an Alien.') - - @classmethod - def is_currently_a_werewolf(cls, sim_info: SimInfo) -> CommonTestResult: - """is_currently_a_werewolf(sim_info) - - Determine if a Sim is currently in their Werewolf form. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim is currently in their Werewolf form. False, if not. - :rtype: CommonTestResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - return CommonTraitUtils.has_trait(sim_info, CommonTraitId.OCCULT_WEREWOLF_WEREFORM) - - @classmethod - def is_currently_a_witch(cls, sim_info: SimInfo) -> CommonTestResult: - """is_currently_a_witch(sim_info) - - Determine if a Sim is currently in their Witch form. (Not disguised) - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim is currently in their Witch form. False, if not. - :rtype: CommonTestResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - is_witch_available_result = CommonOccultUtils.is_witch_occult_available() - if not is_witch_available_result: - return is_witch_available_result - if CommonOccultUtils.get_current_occult_type(sim_info) == OccultType.WITCH: - return CommonTestResult(True, reason='Sim is currently a Witch.') - return CommonTestResult(False, reason='Sim is not currently a Witch.') - - @classmethod - def get_sim_info_of_all_occults_gen(cls, sim_info: SimInfo, *exclude_occult_types: OccultType) -> Iterator[SimInfo]: - """get_sim_info_of_all_occults_gen(sim_info, *exclude_occult_types) - - Retrieve a generator of SimInfo objects for all Occults of a sim. - - .. warning:: Obsolete, please use :func:`~get_sim_info_for_all_occults_gen` instead. - - :param sim_info: The Sim to locate the Occults of. - :type sim_info: SimInfo - :param exclude_occult_types: A collection of OccultTypes to exclude from the resulting SimInfo list. - :type exclude_occult_types: OccultType - :return: An iterator of Sims for all occult types of the Sim. - :rtype: Iterator[SimInfo] - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - return CommonOccultUtils.get_sim_info_for_all_occults_gen(sim_info, exclude_occult_types) - - @classmethod - def has_full_body_cas_part_assigned_to_current_occult_of(cls, sim_info: SimInfo) -> CommonTestResult: - """has_full_body_cas_part_assigned_to_occult(sim_info) - - Determine if the Sim is currently an occult that has a Full Body CAS Part associated with it. Such as a Skeleton (Skeleton Part) or Robot (Humanoid Bot Frame). - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of the test. True, if the Sim is currently an occult with a full body outfit. False, if not. - :rtype: CommonTestResult - """ - current_occult_type = CommonOccultType.determine_current_occult_type(sim_info) - return cls.occult_has_full_body_cas_part(current_occult_type) - - @classmethod - def occult_has_full_body_cas_part(cls, occult_type: CommonOccultType) -> CommonTestResult: - """occult_has_full_body_cas_part(occult_type) - - Determine an occult type has a Full Body CAS Part associated with it. Such as a Skeleton (Skeleton Part) or Robot (Humanoid Bot Frame). - - :param occult_type: The occult type to check. - :type occult_type: CommonOccultType - :return: The result of the test. True, if the occult type has a full body outfit associated with it. False, if not. - :rtype: CommonTestResult - """ - if occult_type in (CommonOccultType.ROBOT, CommonOccultType.SKELETON, CommonOccultType.SCARECROW): - return CommonTestResult.TRUE - return CommonTestResult.FALSE - - @classmethod - def _has_occult_trait(cls, sim_info: SimInfo, trait_id: Union[int, CommonTraitId]) -> bool: - return CommonOccultUtils._has_occult_traits(sim_info, (trait_id,)) - - @classmethod - def _has_occult_traits(cls, sim_info: SimInfo, trait_ids: Iterator[Union[int, CommonTraitId]]) -> bool: - if sim_info is None: - return False - equipped_traits = CommonTraitUtils.get_equipped_traits(sim_info) - for equipped_trait in equipped_traits: - trait_id = CommonTraitUtils.get_trait_id(equipped_trait) - if trait_id in trait_ids: - return True - return False - - @classmethod - def get_current_occult_type(cls, sim_info: SimInfo) -> Union[OccultType, None]: - """get_current_occult_type(sim_info) - - Retrieve the current occult type of the Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The current occult type of the Sim or None if the Sim does not have a current occult type. - :rtype: Union[OccultType, None] - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - if not hasattr(sim_info, 'current_occult_types'): - if not hasattr(sim_info, '_base') or not hasattr(sim_info._base, 'current_occult_types'): - return None - return OccultType(sim_info._base.current_occult_types) - # noinspection PyPropertyAccess - return OccultType(sim_info.current_occult_types) - - @classmethod - def is_occult_available(cls, occult_type: CommonOccultType) -> CommonTestResult: - """is_occult_available(occult_type) - - Determine if an Occult is available for us. - - .. note:: An Occult is available for use usually when it exists in a persons game, such as the WITCH occult existing only when someone has the Realm Of Magic DLC, but does not exist otherwise. - - :param occult_type: An occult type. - :type occult_type: CommonOccultType - :return: The result of testing. True, if the occult is available for use. False, if not. - :rtype: CommonTestResult - """ - if occult_type == CommonOccultType.NON_OCCULT: - return CommonTestResult(True, reason='Obviously the Non Occult "occult type" is available, what did you expect?') - occult_type_mappings = { - CommonOccultType.ALIEN: CommonOccultUtils.is_alien_occult_available, - CommonOccultType.MERMAID: CommonOccultUtils.is_mermaid_occult_available, - CommonOccultType.ROBOT: CommonOccultUtils.is_robot_occult_available, - CommonOccultType.SCARECROW: CommonOccultUtils.is_scarecrow_occult_available, - CommonOccultType.SKELETON: CommonOccultUtils.is_skeleton_occult_available, - CommonOccultType.VAMPIRE: CommonOccultUtils.is_vampire_occult_available, - CommonOccultType.WITCH: CommonOccultUtils.is_witch_occult_available, - CommonOccultType.PLANT_SIM: CommonOccultUtils.is_plant_sim_occult_available, - CommonOccultType.GHOST: CommonOccultUtils.is_ghost_occult_available, - CommonOccultType.WEREWOLF: CommonOccultUtils.is_werewolf_occult_available, - } - if occult_type not in occult_type_mappings: - return CommonTestResult(False, reason=f'Occult Type {occult_type} is not available because it is not a valid occult type.') - return occult_type_mappings[occult_type]() - - @classmethod - def is_alien_occult_available(cls) -> CommonTestResult: - """is_alien_occult_available() - - Determine if the Alien Occult is available. - - :return: The result of testing. True, if the Alien Occult is available. False, if not. - :rtype: CommonTestResult - """ - if not hasattr(OccultType, 'ALIEN'): - return CommonTestResult(False, reason='Aliens do not exist. They are a myth! (At least in this persons game, OccultType did not contain ALIEN)') - if not CommonTraitUtils.is_trait_available(CommonTraitId.OCCULT_ALIEN): - return CommonTestResult(False, reason='The Alien trait is not available.') - return CommonTestResult.TRUE - - @classmethod - def is_mermaid_occult_available(cls) -> CommonTestResult: - """is_mermaid_occult_available() - - Determine if the Mermaid Occult is available. - - :return: The result of testing. True, if the Mermaid Occult is available.. False, if not. - :rtype: CommonTestResult - """ - if not hasattr(OccultType, 'MERMAID'): - return CommonTestResult(False, reason='Mermaids do not exist. They are a myth! (At least in this persons game, OccultType did not contain MERMAID)') - if not CommonTraitUtils.is_trait_available(CommonTraitId.OCCULT_MERMAID): - return CommonTestResult(False, reason='The Mermaid trait is not available.') - return CommonTestResult.TRUE - - @classmethod - def is_robot_occult_available(cls) -> CommonTestResult: - """is_robot_occult_available() - - Determine if the Robot Occult is available. - - :return: The result of testing. True, if the Robot Occult is available.. False, if not. - :rtype: CommonTestResult - """ - if not hasattr(TraitType, 'ROBOT'): - return CommonTestResult(False, reason='Robots do not exist. They are a myth! (At least in this persons game, TraitType did not contain ROBOT)') - if not CommonTraitUtils.is_trait_available(CommonTraitId.OCCULT_ROBOT): - return CommonTestResult(False, reason='The Robot trait is not available.') - return CommonTestResult.TRUE - - @classmethod - def is_scarecrow_occult_available(cls) -> CommonTestResult: - """is_scarecrow_occult_available() - - Determine if the Scarecrow Occult is available. - - :return: The result of testing. True, if the Scarecrow Occult is available.. False, if not. - :rtype: CommonTestResult - """ - if not CommonTraitUtils.is_trait_available(CommonTraitId.SCARECROW): - return CommonTestResult(False, reason='The Scarecrow trait is not available.') - return CommonTestResult.TRUE - - @classmethod - def is_skeleton_occult_available(cls) -> CommonTestResult: - """is_skeleton_occult_available() - - Determine if the Skeleton Occult is available. - - :return: The result of testing. True, if the Skeleton Occult is available.. False, if not. - :rtype: CommonTestResult - """ - if not CommonTraitUtils.is_trait_available(CommonTraitId.HIDDEN_SKELETON): - return CommonTestResult(False, reason='The Skeleton trait is not available.') - return CommonTestResult.TRUE - - @classmethod - def is_vampire_occult_available(cls) -> CommonTestResult: - """is_vampire_occult_available() - - Determine if the Vampire Occult is available. - - :return: The result of testing. True, if the Vampire Occult is available.. False, if not. - :rtype: CommonTestResult - """ - if not hasattr(OccultType, 'VAMPIRE'): - return CommonTestResult(False, reason='Vampires do not exist. They are a myth! (At least in this persons game, OccultType did not contain VAMPIRE)') - if not CommonTraitUtils.is_trait_available(CommonTraitId.OCCULT_VAMPIRE): - return CommonTestResult(False, reason='The Vampire trait is not available.') - return CommonTestResult.TRUE - - @classmethod - def is_witch_occult_available(cls) -> CommonTestResult: - """is_witch_occult_available() - - Determine if the Witch Occult is available. - - :return: The result of testing. True, if the Witch Occult is available.. False, if not. - :rtype: CommonTestResult - """ - if not hasattr(OccultType, 'WITCH'): - return CommonTestResult(False, reason='Witches do not exist. They are a myth! (At least in this persons game, OccultType did not contain WITCH)') - if not CommonTraitUtils.is_trait_available(CommonTraitId.OCCULT_WITCH): - return CommonTestResult(False, reason='The Witch trait is not available.') - return CommonTestResult.TRUE - - @classmethod - def is_plant_sim_occult_available(cls) -> CommonTestResult: - """is_plant_sim_occult_available() - - Determine if the Plant Sim Occult is available. - - :return: The result of testing. True, if the Plant Sim Occult is available.. False, if not. - :rtype: CommonTestResult - """ - if not CommonTraitUtils.is_trait_available(CommonTraitId.PLANT_SIM): - return CommonTestResult(False, reason='The Plant Sim trait is not available.') - return CommonTestResult.TRUE - - @classmethod - def is_werewolf_occult_available(cls) -> CommonTestResult: - """is_werewolf_occult_available() - - Determine if the Werewolf Occult is available. - - :return: The result of testing. True, if the Werewolf Occult is available.. False, if not. - :rtype: CommonTestResult - """ - if not hasattr(OccultType, 'WEREWOLF'): - return CommonTestResult(False, reason='Werewolves do not exist. They are a myth! (At least in this persons game, OccultType did not contain WEREWOLF)') - if not CommonTraitUtils.is_trait_available(CommonTraitId.OCCULT_WEREWOLF): - return CommonTestResult(False, reason='The Werewolf trait is not available.') - return CommonTestResult.TRUE - - @classmethod - def is_ghost_occult_available(cls) -> CommonTestResult: - """is_ghost_occult_available() - - Determine if the Ghost Occult is available. - - :return: The result of testing. True, if the Ghost Occult is available.. False, if not. - :rtype: CommonTestResult - """ - if not hasattr(TraitType, 'GHOST'): - return CommonTestResult(False, reason='Ghosts do not exist. They are a myth! (At least in this persons game, TraitType did not contain GHOST)') - ghost_traits = ( - CommonTraitId.GHOST_ANGER, - CommonTraitId.GHOST_ANIMAL_OBJECTS_KILLER_CHICKEN, - CommonTraitId.GHOST_ANIMAL_OBJECTS_KILLER_RABBIT, - CommonTraitId.GHOST_BEETLE, - CommonTraitId.GHOST_CAULDRON_POTION_IMMORTALITY_FAILURE, - CommonTraitId.GHOST_CLIMBING_ROUTE, - CommonTraitId.GHOST_COW_PLANT, - CommonTraitId.GHOST_CURSES_NIGHT_STALKER_STALKER, - CommonTraitId.GHOST_DEATH_FLOWER, - CommonTraitId.GHOST_DROWN, - CommonTraitId.GHOST_ELDER_EXHAUSTION, - CommonTraitId.GHOST_ELECTROCUTION, - CommonTraitId.GHOST_EMBARRASSMENT, - CommonTraitId.GHOST_FIRE, - CommonTraitId.GHOST_FLIES, - CommonTraitId.GHOST_FROZEN, - CommonTraitId.GHOST_HUNGER, - CommonTraitId.GHOST_LAUGHTER, - CommonTraitId.GHOST_LIGHTNING, - CommonTraitId.GHOST_MOTHER_PLANT, - CommonTraitId.GHOST_MURPHY_BED, - CommonTraitId.GHOST_OLD_AGE, - CommonTraitId.GHOST_OVERHEAT, - CommonTraitId.GHOST_POISON, - CommonTraitId.GHOST_PUFFER_FISH, - CommonTraitId.GHOST_RISEN, - CommonTraitId.GHOST_RODENT_DISEASE, - CommonTraitId.GHOST_SEANCE_TABLE, - CommonTraitId.GHOST_STEAM, - CommonTraitId.GHOST_VAMPIRE_SUN, - CommonTraitId.GHOST_VENDING_MACHINE, - CommonTraitId.GHOST_WITCH_OVERLOAD - ) - for ghost_trait in ghost_traits: - if CommonTraitUtils.is_trait_available(ghost_trait): - return CommonTestResult.TRUE - return CommonTestResult(False, reason='No Ghost traits were available.') - - @classmethod - def _get_occult_types(cls, sim_info: SimInfo) -> OccultType: - if not hasattr(sim_info, 'occult_types'): - if not hasattr(sim_info, '_base') or not hasattr(sim_info._base, 'occult_types'): - return CommonOccultUtils.get_current_occult_type(sim_info) or OccultType.HUMAN - return sim_info._base.occult_types - # noinspection PyPropertyAccess - return sim_info.occult_types - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.switch_sim_to_occult', - 'Switch a Sim to an Occult form (If they have it)', - command_arguments=( - CommonConsoleCommandArgument('occult_type', 'CommonOccultType', f'The name of an Occult Type to switch the form of the Sim to. Valid Values: {CommonOccultType.get_comma_separated_names_string()}'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance Id or name of the Sim that will switch forms.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.switchsimtooccult', - 's4clib.switchoccult', - 's4clib.switch_occult', - 's4clib.switch_occult_type', - 's4clib.switchocculttype' - ) -) -def _common_switch_sim_to_occult(output: CommonConsoleCommandOutput, occult_type: CommonOccultType, sim_info: SimInfo = None): - if sim_info is None: - return - if occult_type is None: - return - occult_type_name = occult_type.name - output(f'Attempting to switch Sim {sim_info} to their {occult_type_name} form.') - result = CommonOccultUtils.switch_to_occult_form(sim_info, occult_type) - if result: - output(f'SUCCESS: Successfully switched Sim {sim_info} to their {occult_type_name} form: {result}') - else: - output(f'FAILED: Failed to switch Sim {sim_info} to their {occult_type_name} form: {result}') - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.add_all_occults_to_sim', - f'Add all Occult Types to a Sim. They will have all available Occult types added to them: {CommonOccultType.get_comma_separated_names_string(exclude_occult_types=(CommonOccultType.NON_OCCULT, CommonOccultType.GHOST, CommonOccultType.PLANT_SIM))}', - command_arguments=( - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance Id or name of the Sim to add the occults to.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.addalloccultstosim', - 's4clib.add_all_occults', - 's4clib.addalloccults', - 's4clib.add_all_occults_type', - 's4clib.addalloccultstype', - ) -) -def _common_add_all_occults_to_sim(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): - if sim_info is None: - return - output(f'Attempting to add all occults to Sim {sim_info}') - result = CommonOccultUtils.add_all_occults(sim_info) - if result: - output(f'SUCCESS: Successfully added all occults to Sim {sim_info}: {result}') - else: - output(f'FAILED: Failed to add all occults to Sim {sim_info}: {result}') - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.remove_all_occults_from_sim', - f'Remove all Occult Types from a Sim. They will have all available Occult Types removed from them: {CommonOccultType.get_comma_separated_names_string(exclude_occult_types=(CommonOccultType.NON_OCCULT, CommonOccultType.GHOST, CommonOccultType.PLANT_SIM))}', - command_arguments=( - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance Id or name of the Sim to remove the occults from.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.removealloccultsfromsim', - 's4clib.remove_all_occults', - 's4clib.removealloccults', - 's4clib.remove_all_occults_type', - 's4clib.removealloccultstype', - ) -) -def _common_remove_all_occults_from_sim(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): - if sim_info is None: - return - output(f'Attempting to remove all occults from Sim {sim_info}') - result = CommonOccultUtils.remove_all_occults(sim_info) - if result: - output(f'SUCCESS: Successfully removeed all occults from Sim {sim_info}: {result}') - else: - output(f'FAILED: Failed to remove all occults from Sim {sim_info}: {result}') - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.add_occult_to_sim', - 'Add an Occult Type to a Sim.', - command_arguments=( - CommonConsoleCommandArgument('occult_type', 'CommonOccultType', f'The name of an Occult Type to add to the Sim. Valid Values: {CommonOccultType.get_comma_separated_names_string(exclude_occult_types=(CommonOccultType.NON_OCCULT, CommonOccultType.GHOST))}'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance Id or name of the Sim to add the occult to.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.addocculttosim', - 's4clib.add_occult', - 's4clib.addoccult', - 's4clib.add_occult_type', - 's4clib.addocculttype', - ) -) -def _common_add_occult_to_sim(output: CommonConsoleCommandOutput, occult_type: CommonOccultType, sim_info: SimInfo = None): - if sim_info is None: - return - if occult_type is None: - return - occult_type_name = occult_type.name - output(f'Attempting to add occult {occult_type_name} to Sim {sim_info}') - result = CommonOccultUtils.add_occult(sim_info, occult_type) - if result: - output(f'SUCCESS: Successfully added occult {occult_type_name} to Sim {sim_info}: {result}') - else: - output(f'FAILED: Failed to add occult {occult_type_name} to Sim {sim_info}: {result}') - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.remove_occult_from_sim', - 'Remove an Occult Type from a Sim.', - command_arguments=( - CommonConsoleCommandArgument('occult_type', 'CommonOccultType', f'The name of an Occult Type to remove from the Sim. Valid Values: {CommonOccultType.get_comma_separated_names_string(exclude_occult_types=(CommonOccultType.NON_OCCULT, CommonOccultType.GHOST))}'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance Id or name of the Sim to remove the occult from.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.removeoccultfromsim', - 's4clib.remove_occult', - 's4clib.removeoccult', - 's4clib.remove_occult_type', - 's4clib.removeocculttype', - ) -) -def _common_remove_occult_from_sim(output: CommonConsoleCommandOutput, occult_type: CommonOccultType, sim_info: SimInfo = None): - if sim_info is None: - return - if occult_type is None: - return - occult_type_name = occult_type.name - output(f'Attempting to remove occult {occult_type_name} from Sim {sim_info}') - result = CommonOccultUtils.remove_occult(sim_info, occult_type) - if result: - output(f'SUCCESS: Successfully removed occult {occult_type_name} from Sim {sim_info}: {result}') - else: - output(f'FAILED: Failed to remove occult {occult_type_name} from Sim {sim_info}: {result}') - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.remove_all_occults_from_sim', - 'Remove all Occult Types from a Sim.', - command_arguments=( - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance Id or name of the Sim to remove the occult types from.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.removealloccultsfromsim', - 's4clib.remove_all_occults', - 's4clib.removealloccults', - 's4clib.remove_all_occult_types', - 's4clib.removeallocculttypes', - ) -) -def _common_remove_all_occults_from_sim(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): - if sim_info is None: - return - output(f'Attempting to remove all occult types from Sim {sim_info}.') - result = CommonOccultUtils.remove_all_occults(sim_info) - if result: - output(f'SUCCESS: Successfully removed all occult types from Sim {sim_info}: {result}') - else: - output(f'FAILED: Failed to remove all occult types from Sim {sim_info}: {result}') - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_dev.print_vanilla_occults', - 'Print a list of all vanilla OccultType values a Sim has.', - command_arguments=( - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance Id or name of the Sim to print the occult types of.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib_dev.printvanillaoccults', - ), - show_with_help_command=False -) -def _s4clib_testing_print_vanilla_occult_types_for_sim(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): - if sim_info is None: - return - occult_types_str = ', '.join([occult_type.name if hasattr(occult_type, 'name') else str(occult_type) for occult_type in CommonOccultUtils._get_occult_types(sim_info)]) - output(f'Occult Types: {occult_types_str}') - current_occult_types_str = ', '.join([occult_type.name if hasattr(occult_type, 'name') else str(occult_type) for occult_type in CommonOccultUtils.get_current_occult_type(sim_info)]) - output(f'Current Occult Types: {current_occult_types_str}') - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_testing.print_occult_sim_infos', - 'Print information about the Occult Sim Infos of a Sim for each occult type they have.', - command_arguments=( - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance Id or name of the Sim to check.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib_testing.printoccultsiminfos', - ) -) -def _common_print_occult_sim_infos(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): - if sim_info is None: - return - output(f'Attempting to print Occult Information for Sim {sim_info}') - for occult_type in OccultType.values: - occult_type_name = occult_type.name - occult_sim_info = CommonOccultUtils.get_occult_sim_info(sim_info, occult_type) - if occult_sim_info is None: - output(f'Occult Sim Info[{occult_type_name}]: None') - continue - occult_sim_id = CommonSimUtils.get_sim_id(occult_sim_info) - obj_type_acronym = 'UnknownType' - if CommonTypeUtils.is_sim_info(occult_sim_info): - obj_type_acronym = 'SI' - elif CommonTypeUtils.is_sim_instance(occult_sim_info): - obj_type_acronym = 'S' - elif CommonTypeUtils.is_sim_info_base_wrapper(occult_sim_info): - obj_type_acronym = 'SIBW' - from s4ap.sims4communitylib.utils.sims.common_sim_type_utils import CommonSimTypeUtils - sim_types = tuple(CommonSimTypeUtils.get_all_sim_types_gen(occult_sim_info, combine_teen_young_adult_and_elder_age=False, combine_child_dog_types=False)) - sim_types_str = ', '.join([sim_type.name for sim_type in sim_types]) - current_sim_type = CommonSimTypeUtils.determine_sim_type(occult_sim_info, combine_teen_young_adult_and_elder_age=False, combine_child_dog_types=False, use_current_occult_type=True) - current_sim_type_name = current_sim_type.name - output(f'Occult Sim Info [{occult_type_name}]: {occult_sim_info} ({occult_sim_id}, ({sim_types_str}), C:{current_sim_type_name}) [{obj_type_acronym}]') diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_phone_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_phone_utils.py deleted file mode 100644 index 4014522..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_phone_utils.py +++ /dev/null @@ -1,77 +0,0 @@ -""" -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 -""" -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.location.common_location_utils import CommonLocationUtils - - -class CommonPhoneUtils: - """ Utilities for manipulating the Phone. """ - @staticmethod - def silence_phone() -> None: - """silence_phone() - - Silence the phone. - """ - CommonPhoneUtils._set_phone_is_silenced(True) - - @staticmethod - def unsilence_phone() -> None: - """unsilence_phone() - - Unsilence the phone. - """ - CommonPhoneUtils._set_phone_is_silenced(False) - - @staticmethod - def phone_is_silenced() -> bool: - """phone_is_silenced() - - Determine if the phone is silenced. - - :return: True, if the Phone is silenced. False, if not. - :rtype: bool - """ - # noinspection PyUnresolvedReferences - return CommonLocationUtils.get_current_zone().ui_dialog_service.is_phone_silenced - - @staticmethod - def _set_phone_is_silenced(is_silenced: bool): - # noinspection PyUnresolvedReferences - CommonLocationUtils.get_current_zone().ui_dialog_service._set_is_phone_silenced(is_silenced) - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.silence_phone', - 'Turn on the silent mode for the phone.', - command_aliases=( - 's4clib.silencephone', - ) -) -def _common_silence_phone(output: CommonConsoleCommandOutput): - output('Silencing Phone') - CommonPhoneUtils.silence_phone() - output('Done') - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.unsilence_phone', - 'Turn off the silent mode for the phone.', - command_aliases=( - 's4clib.unsilencephone', - ) -) -def _common_unsilence_phone(output: CommonConsoleCommandOutput): - output('Unsilencing Phone') - CommonPhoneUtils.unsilence_phone() - output('Done') diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_rabbit_hole_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_rabbit_hole_utils.py deleted file mode 100644 index 7648acf..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_rabbit_hole_utils.py +++ /dev/null @@ -1,61 +0,0 @@ -""" -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 -""" -from typing import Union - -import services -from rabbit_hole.rabbit_hole import RabbitHole -from services.rabbit_hole_service import RabbitHoleService - - -class CommonRabbitHoleUtils: - """Utilities for manipulating rabbit holes.""" - - @classmethod - def get_rabbit_hole_service(cls) -> RabbitHoleService: - """get_rabbit_hole_service() - - Retrieve an instance of the Rabbit Hole Service. - - :return: The service that manages rabbit holes. - :rtype: RabbitHoleService - """ - return services.get_rabbit_hole_service() - - @classmethod - def load_rabbit_hole_by_id(cls, rabbit_hole: Union[int, RabbitHole]) -> Union[RabbitHole, None]: - """load_rabbit_hole_by_id(rabbit_hole) - - Load an instance of a Rabbit Hole by its identifier. - - :param rabbit_hole: The identifier of a Rabbit Hole. - :type rabbit_hole: Union[int, RabbitHole] - :return: An instance of a Rabbit Hole matching the decimal identifier or None if not found. - :rtype: Union[RabbitHole, None] - """ - if isinstance(rabbit_hole, RabbitHole): - return rabbit_hole - # noinspection PyBroadException - try: - # noinspection PyCallingNonCallable - rabbit_hole_instance = rabbit_hole() - if isinstance(rabbit_hole_instance, RabbitHole): - # noinspection PyTypeChecker - return rabbit_hole - except: - pass - # noinspection PyBroadException - try: - rabbit_hole: int = int(rabbit_hole) - except: - # noinspection PyTypeChecker - rabbit_hole: RabbitHole = rabbit_hole - return rabbit_hole - - from sims4.resources import Types - from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils - return CommonResourceUtils.load_instance(Types.RABBIT_HOLE, rabbit_hole) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_relationship_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_relationship_utils.py deleted file mode 100644 index f1bb60a..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_relationship_utils.py +++ /dev/null @@ -1,1128 +0,0 @@ -""" -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 -""" -from typing import Iterator, Union, Tuple - -from relationships.relationship_objects.relationship import Relationship -from relationships.relationship_bit import RelationshipBit -from relationships.relationship_track import RelationshipTrack -from server_commands.argument_helpers import TunableInstanceParam -from sims.sim_info import SimInfo -from sims4.resources import Types -from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.enums.relationship_bits_enum import CommonRelationshipBitId -from s4ap.sims4communitylib.enums.relationship_tracks_enum import CommonRelationshipTrackId -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ - CommonConsoleCommandArgument -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.common_log_registry import CommonLogRegistry -from s4ap.sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from s4ap.sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils - - -class CommonRelationshipUtils: - """Utilities for manipulating relationship bits, tracks, etc. - - """ - @classmethod - def has_met(cls, sim_info: SimInfo, target_sim_info: SimInfo) -> bool: - """has_met(sim_info, target_sim_info) - - Determine if a Sim has met the Target Sim. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :param target_sim_info: The Target Sim to check. - :type target_sim_info: SimInfo - :return: True, if both Sims have met each other. False, if not. - :rtype: bool - """ - return cls.has_relationship_bit_with_sim(sim_info, target_sim_info, CommonRelationshipBitId.HAS_MET) - - @classmethod - def are_blood_relatives(cls, sim_info_a: SimInfo, sim_info_b: SimInfo) -> bool: - """are_blood_relatives(sim_info_a, sim_info_b) - - Determine if two Sims are blood relatives. - - :param sim_info_a: An instance of a Sim. - :type sim_info_a: SimInfo - :param sim_info_b: An instance of a Sim. - :type sim_info_b: SimInfo - :return: True, if Sim A is blood relative of Sim B. False, if not. - :rtype: bool - """ - if sim_info_a is None or sim_info_b is None: - return False - return not sim_info_a.incest_prevention_test(sim_info_b) - - @classmethod - def is_romantically_committed_to_any_sims(cls, sim_info: SimInfo) -> bool: - """is_romantically_committed_to_any_sims(sim_info) - - Determine if the Sim is romantically committed to any Sims. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is romantically committed to any Sims. False, if not. - :rtype: bool - """ - return any(cls.get_sim_info_of_all_sims_romantically_committed_to_generator(sim_info)) - - @classmethod - def is_friendly_with(cls, sim_info: SimInfo, target_sim_info: SimInfo) -> bool: - """is_friendly_with(sim_info, target_sim_info) - - Determine if a Sim is friendly with a Target Sim. - - .. note:: By default, a Sim is friendly with another Sim when their Friendship relationship is at or above 30. If both Sims are Animals, they are friendly with each other if they have the Friendly relationship bit. - - :param sim_info: The info of a Sim. - :type sim_info: SimInfo - :param target_sim_info: The info of a Sim. - :type target_sim_info: SimInfo - :return: True, if the Sim is friendly with the Target Sim. False, if not. - :rtype: bool - """ - if CommonSpeciesUtils.is_animal(sim_info) and CommonSpeciesUtils.is_animal(target_sim_info): - return cls.has_relationship_bit_with_sim(sim_info, target_sim_info, CommonRelationshipBitId.PET_TO_PET_FRIENDLY)\ - or cls.has_relationship_bit_with_sim(target_sim_info, sim_info, CommonRelationshipBitId.PET_TO_PET_FRIENDLY) - return cls.get_friendship_level(sim_info, target_sim_info) >= 30 - - @classmethod - def is_romantic_with(cls, sim_info: SimInfo, target_sim_info: SimInfo) -> bool: - """is_romantic_with(sim_info, target_sim_info) - - Determine if a Sim is romantic with a Target Sim. - - .. note:: By default, a Sim is romantic with another Sim when their Romance relationship is at or above 30. - - :param sim_info: The info of a Sim. - :type sim_info: SimInfo - :param target_sim_info: The info of a Sim. - :type target_sim_info: SimInfo - :return: True, if the Sim is romantic with the Target Sim. False, if not. - :rtype: bool - """ - return cls.get_romance_level(sim_info, target_sim_info) >= 30 - - @classmethod - def get_romantically_committed_relationship_bits(cls) -> Tuple[CommonRelationshipBitId]: - """get_romantically_committed_relationship_bits() - - Retrieve a collection of relationship bits that signify two Sims are in a committed relationship. - - :return: A collection of relationship bits. - :rtype: Tuple[CommonRelationshipBitId] - """ - result: Tuple[CommonRelationshipBitId, ...] = ( - CommonRelationshipBitId.ROMANTIC_ENGAGED, - CommonRelationshipBitId.ROMANTIC_GETTING_MARRIED, - CommonRelationshipBitId.ROMANTIC_MARRIED, - CommonRelationshipBitId.ROMANTIC_PROMISED, - CommonRelationshipBitId.ROMANTIC_SIGNIFICANT_OTHER, - CommonRelationshipBitId.SEXUAL_ORIENTATION_WOOHOO_PARTNERS - ) - return result - - @classmethod - def is_romantically_committed_to(cls, sim_info: SimInfo, target_sim_info: SimInfo) -> bool: - """is_romantically_committed_to(sim_info, target_sim_info) - - Determine if a Sim is romantically committed to the Target Sim. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :param target_sim_info: The Target Sim to check. - :type target_sim_info: SimInfo - :return: True, if the Sim is romantically committed to the Target Sim. False, if not. - :rtype: bool - """ - return target_sim_info in cls.get_sim_info_of_all_sims_romantically_committed_to_generator(sim_info) - - @classmethod - def get_friendship_level(cls, sim_info: SimInfo, target_sim_info: SimInfo) -> float: - """get_friendship_level(sim_info, target_sim_info) - - Retrieve the level of Friendship between two Sims. - - .. note:: The return will be "0.0" if a friendship relationship track is not found. - - :param sim_info: The Sim to use. - :type sim_info: SimInfo - :param target_sim_info: The Target Sim to use. - :type target_sim_info: SimInfo - :return: The current level of friendship between two Sims. - :rtype: float - """ - track_id = cls.get_friendship_relationship_track(sim_info, target_sim_info) - if track_id is None: - return 0.0 - return cls.get_relationship_level_of_sims(sim_info, target_sim_info, track_id) - - @classmethod - def set_friendship_level(cls, sim_info: SimInfo, target_sim_info: SimInfo, level: float): - """set_friendship_level(sim_info, target_sim_info, level) - - Set the level of Friendship between two Sims. - - :param sim_info: The Sim to use. - :type sim_info: SimInfo - :param target_sim_info: The Target Sim to use. - :type target_sim_info: SimInfo - :param level: The new level of relationship between the Sims. - :type level: float - """ - track_id = cls.get_friendship_relationship_track(sim_info, target_sim_info) - if track_id is None: - return - cls.set_relationship_level_of_sims(sim_info, target_sim_info, track_id, level) - - @classmethod - def get_romance_level(cls, sim_info: SimInfo, target_sim_info: SimInfo) -> float: - """get_romance_level(sim_info, target_sim_info) - - Retrieve the level of Romance between two Sims. - - .. note:: The return will be "0.0" if a romance relationship track is not found. - - :param sim_info: The Sim to use. - :type sim_info: SimInfo - :param target_sim_info: The Target Sim to use. - :type target_sim_info: SimInfo - :return: The current level of romance between two Sims. - :rtype: float - """ - track_id = cls.get_romance_relationship_track(sim_info, target_sim_info) - if track_id is None: - return 0.0 - return cls.get_relationship_level_of_sims(sim_info, target_sim_info, track_id) - - @classmethod - def set_romance_level(cls, sim_info: SimInfo, target_sim_info: SimInfo, level: float): - """set_romance_level(sim_info, target_sim_info, level) - - Set the level of Romance between two Sims. - - :param sim_info: The Sim to use. - :type sim_info: SimInfo - :param target_sim_info: The Target Sim to use. - :type target_sim_info: SimInfo - :param level: The new level of relationship between the Sims. - :type level: float - """ - track_id = cls.get_romance_relationship_track(sim_info, target_sim_info) - if track_id is None: - return - cls.set_relationship_level_of_sims(sim_info, target_sim_info, track_id, level) - - @classmethod - def calculate_average_relationship_level(cls, sim_info: SimInfo, target_sim_info: SimInfo) -> float: - """calculate_average_relationship_level(sim_info, target_sim_info) - - Calculate an average level for Friendship and Romance between two Sims. - - .. note:: Math: (Friendship Level + Romance Level)/2 - - .. note:: - - Example Levels: - Friendship Level: 10 - Romance Level: 20 - Average: 15 - - :param sim_info: The Sim to use. - :type sim_info: SimInfo - :param target_sim_info: The Target Sim to use. - :type target_sim_info: SimInfo - :return: The average level of friendship and romance between two Sims. - :rtype: float - """ - return (cls.get_friendship_level(sim_info, target_sim_info) + cls.get_romance_level(sim_info, target_sim_info)) / 2 - - @classmethod - def has_permission_for_romantic_relationships(cls, sim_info: SimInfo) -> CommonTestResult: - """has_permission_for_romantic_relationships(sim_info) - - Determine if a Sim has permission to have romantic relationships with other Sims. - - .. note:: In the vanilla game, only Teen, Adult, and Elder Sims have permission for romantic relationships. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of the test. True, if the test passes. False, if the test fails. - :rtype: CommonTestResult - """ - if not CommonAgeUtils.is_teen_adult_or_elder(sim_info): - return CommonTestResult(False, reason=f'{sim_info} does not have permission for romantic relationships. They are neither a Teen, Adult, nor Elder Sim.') - return CommonTestResult(True, reason=f'{sim_info} has permission for romantic relationships.') - - @classmethod - def has_permission_for_romantic_relationship_with(cls, sim_info_a: SimInfo, sim_info_b: SimInfo) -> CommonTestResult: - """Determine if two Sims are allowed to have a Romantic relationship together.""" - sim_a_permission_result = cls.has_permission_for_romantic_relationships(sim_info_a) - if not sim_a_permission_result: - return CommonTestResult(False, reason=f'{sim_info_a} does not have permission for a romantic relationship with {sim_info_b}. {sim_a_permission_result}') - sim_b_permission_result = cls.has_permission_for_romantic_relationships(sim_info_b) - if not sim_b_permission_result: - return CommonTestResult(False, reason=f'{sim_info_a} does not have permission for a romantic relationship with {sim_info_b}. {sim_b_permission_result}') - if cls.are_blood_relatives(sim_info_a, sim_info_b): - return CommonTestResult(False, reason=f'{sim_info_a} does not have permission for a romantic relationship with {sim_info_b}. {sim_info_a} is a blood relative of {sim_info_b}.') - if not CommonSpeciesUtils.are_same_species(sim_info_a, sim_info_b): - return CommonTestResult(False, reason=f'{sim_info_a} does not have permission for a romantic relationship with {sim_info_b}. {sim_info_a} and {sim_info_b} are not the same species.') - if CommonAgeUtils.is_teen(sim_info_a) and CommonAgeUtils.is_teen(sim_info_b): - return CommonTestResult(True, reason=f'{sim_info_a} has permission for a romantic relationship with {sim_info_b}.') - if CommonAgeUtils.is_teen(sim_info_a): - if not CommonAgeUtils.is_teen(sim_info_b): - return CommonTestResult(False, reason=f'{sim_info_a} does not have permission for a romantic relationship with {sim_info_b}. {sim_info_a} is a Teen Sim and {sim_info_b} is an Adult or Elder Sim.') - elif CommonAgeUtils.is_teen(sim_info_b): - return CommonTestResult(False, reason=f'{sim_info_a} does not have permission for a romantic relationship with {sim_info_b}. {sim_info_a} is an Adult or Elder Sim and {sim_info_b} is a Teen Sim.') - return CommonTestResult(True, reason=f'{sim_info_a} has permission for a romantic relationship with {sim_info_b}.') - - @classmethod - def has_permission_to_be_blood_relative_of(cls, sim_info_a: SimInfo, sim_info_b: SimInfo) -> CommonTestResult: - """has_permission_to_be_blood_relative_of(sim_info_a, sim_info_b) - - Determine if Sim A has permission to be a Blood Relative of Sim B. (Such as Mother, Daughter, etc.) - - .. note:: In the vanilla game, only Sims of the same species have permission to be Blood Relatives. - - :param sim_info_a: An instance of a Sim. - :type sim_info_a: SimInfo - :param sim_info_b: An instance of a Sim. - :type sim_info_b: SimInfo - :return: The result of the test. True, if the test passes. False, if the test fails. - :rtype: CommonTestResult - """ - if not CommonSpeciesUtils.are_same_species(sim_info_a, sim_info_b): - return CommonTestResult(False, reason=f'{sim_info_a} does not have permission to be a Blood Relative of {sim_info_b}. {sim_info_a} and {sim_info_b} are not the same species.') - return CommonTestResult(True, reason=f'{sim_info_a} has permission to be a Blood Relative of {sim_info_b}.') - - @classmethod - def has_relationship_bit_with_any_sims( - cls, - sim_info: SimInfo, - relationship_bit_id: Union[int, CommonRelationshipBitId], - instanced_only: bool = True - ) -> bool: - """has_relationship_bit_with_any_sims(sim_info, relationship_bit_id, instance_only=True) - - Determine if a Sim has the specified relationship bit with any Sims. - - :param sim_info: The Sim to use. - :type sim_info: SimInfo - :param relationship_bit_id: The identifier of the Relationship Bit to check for. - :type relationship_bit_id: Union[int, CommonRelationshipBitId] - :param instanced_only: If True, only Sims that are currently loaded will be valid. - :type instanced_only: bool, optional - :return: True, if the Sim has the specified Relationship Bit with any Sims. False, if not. - :rtype: bool - """ - return any(cls.get_sim_info_of_all_sims_with_relationship_bit_generator(sim_info, relationship_bit_id, instanced_only=instanced_only)) - - @classmethod - def has_relationship_bits_with_any_sims( - cls, - sim_info: SimInfo, - relationship_bit_ids: Iterator[int], - instanced_only: bool = True - ) -> bool: - """has_relationship_bits_with_any_sims(sim_info, relationship_bit_ids, instanced_only=True) - - Determine if a Sim has the specified relationship bits with any Sims. - - :param sim_info: The Sim to use. - :type sim_info: SimInfo - :param relationship_bit_ids: A collection of identifier of Relationship Bits to check for. - :type relationship_bit_ids: int - :param instanced_only: If True, only Sims that are currently loaded will be valid. - :type instanced_only: bool, optional - :return: True, if the Sim has any of the specified Relationship Bits with any Sims. False, if not. - :rtype: bool - """ - return any(cls.get_sim_info_of_all_sims_with_relationship_bits_generator(sim_info, relationship_bit_ids, instanced_only=instanced_only)) - - @classmethod - def has_relationship_bit_with_sim( - cls, - sim_info: SimInfo, - target_sim_info: SimInfo, - relationship_bit_id: Union[int, CommonRelationshipBitId], - ) -> bool: - """has_relationship_bit_with_sim(sim_info, target_sim_info, relationship_bit_id) - - Determine if two Sims have the specified relationship bit with each other. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :param target_sim_info: The Target Sim of the relationship bit (The target is especially important for Unidirectional/One Way Relationship Bits). - :type target_sim_info: SimInfo - :param relationship_bit_id: The identifier of the Relationship Bit to check for. - :type relationship_bit_id: Union[int, CommonRelationshipBitId] - :return: True, if the Sim has the specified Relationship Bit with the Target Sim. False, if not. - :rtype: bool - """ - return cls.has_relationship_bits_with_sim(sim_info, target_sim_info, (relationship_bit_id,)) - - @classmethod - def has_relationship_bits_with_sim( - cls, - sim_info: SimInfo, - target_sim_info: SimInfo, - relationship_bit_ids: Iterator[Union[int, CommonRelationshipBitId]], - ) -> bool: - """has_relationship_bits_with_sim(sim_info, target_sim_info, relationship_bit_ids) - - Determine if two sims have any of the specified relationship bits with each other. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :param target_sim_info: The Target Sim of the relationship bit (The target is especially important for Unidirectional/One Way Relationship Bits). - :type target_sim_info: SimInfo - :param relationship_bit_ids: A collection of identifier of Relationship Bits to check for. - :type relationship_bit_ids: Iterator[Union[int, CommonRelationshipBitId]] - :return: True, if the Sim has any of the specified Relationship Bits with the Target Sim. False, if not. - :rtype: bool - """ - target_sim_id = CommonSimUtils.get_sim_id(target_sim_info) - relationship_bits = sim_info.relationship_tracker.get_all_bits(target_sim_id) - for relationship_bit in relationship_bits: - relationship_bit_id = getattr(relationship_bit, 'guid64', None) - if relationship_bit_id in relationship_bit_ids: - return True - return False - - @classmethod - def get_relationship_level_of_sims( - cls, - sim_info: SimInfo, - target_sim_info: SimInfo, - relationship_track_id: Union[int, CommonRelationshipTrackId] - ) -> float: - """get_relationship_level_of_sims(sim_info, target_sim_info, relationship_track_id) - - Retrieve the level of a relationship track between two sims. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :param target_sim_info: The Target Sim of the relationship track. - :type target_sim_info: SimInfo - :param relationship_track_id: An identifier for a Relationship Track to retrieve. - :type relationship_track_id: Union[int, CommonRelationshipTrackId] - :return: The current level between two Sims for the specified Relationship Track. - :rtype: float - """ - relationship_track = cls.load_relationship_track_by_id(relationship_track_id) - if relationship_track is None: - return 0.0 - target_sim_id = CommonSimUtils.get_sim_id(target_sim_info) - return sim_info.relationship_tracker.get_relationship_score(target_sim_id, relationship_track) - - @classmethod - def change_relationship_level_of_sims( - cls, - sim_info: SimInfo, - target_sim_info: SimInfo, - relationship_track_id: Union[int, CommonRelationshipTrackId], - level: float - ) -> bool: - """change_relationship_level_of_sims(sim_info, target_sim_info, relationship_track_id, level) - - Change the level of a relationship track between two Sims. - - :param sim_info: The sim that owns the relationship track. - :type sim_info: SimInfo - :param target_sim_info: The target of the relationship track. - :type target_sim_info: SimInfo - :param relationship_track_id: The identifier of the Relationship Track to change. - :type relationship_track_id: : Union[int, CommonRelationshipTrackId] - :param level: The amount to add to the relationship track (Can be positive or negative). - :type level: float - :return: True, if the relationship track was changed successfully. False, if not. - :rtype: bool - """ - relationship_track = cls.load_relationship_track_by_id(relationship_track_id) - if relationship_track is None: - return False - target_sim_id = CommonSimUtils.get_sim_id(target_sim_info) - sim_info.relationship_tracker.add_relationship_score(target_sim_id, level, relationship_track) - return True - - @classmethod - def set_relationship_level_of_sims( - cls, - sim_info: SimInfo, - target_sim_info: SimInfo, - relationship_track_id: Union[int, CommonRelationshipTrackId], - level: float - ) -> bool: - """set_relationship_level_of_sims(sim_info, target_sim_info, relationship_track_id, level) - - Set the level of a relationship track between two Sims. - - :param sim_info: The sim that owns the relationship track. - :type sim_info: SimInfo - :param target_sim_info: The target of the relationship track. - :type target_sim_info: SimInfo - :param relationship_track_id: The identifier of the Relationship Track to set. - :type relationship_track_id: : Union[int, CommonRelationshipTrackId] - :param level: The amount to set the relationship track to (Can be positive or negative). - :type level: float - :return: True, if the relationship track was set successfully. False, if not. - :rtype: bool - """ - relationship_track = cls.load_relationship_track_by_id(relationship_track_id) - if relationship_track is None: - return False - target_sim_id = CommonSimUtils.get_sim_id(target_sim_info) - sim_info.relationship_tracker.set_relationship_score(target_sim_id, level, relationship_track) - return True - - @classmethod - def get_relationships_gen(cls, sim_info: SimInfo) -> Iterator[Relationship]: - """get_relationships_gen(sim_info) - - Retrieve all relationships a Sim has with other Sims. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: An iterator of Relationships a Sim has with other Sims. - :rtype: Iterator[Relationship] - """ - if not hasattr(sim_info, 'relationship_tracker') or not sim_info.relationship_tracker: - return tuple() - for relationship in sim_info.relationship_tracker: - yield relationship - - @classmethod - def add_relationship_bit( - cls, - sim_info: SimInfo, - target_sim_info: SimInfo, - relationship_bit_id: Union[int, CommonRelationshipBitId] - ) -> CommonExecutionResult: - """add_relationship_bit(sim_info, target_sim_info, relationship_bit_id) - - Add a relationship bit between two sims. - - .. note:: - - If the relationship bit is UNIDIRECTIONAL, it will only be added to sim_info in the direction of the Target. - i.e. Sim will have relationship bit towards Target, but Target will not have relationship bit towards Sim. - - One example is the Caregiver relationship: - - - Sim is caregiver of Target. - - Target is being cared for by Sim. - - :param sim_info: The source Sim of the Relationship Bit. - :type sim_info: SimInfo - :param target_sim_info: The target Sim of the Relationship Bit. - :type target_sim_info: SimInfo - :param relationship_bit_id: The identifier of the Relationship Bit to add. - :type relationship_bit_id: Union[int, CommonRelationshipBitId] - :return: True, if the relationship bit was added successfully. False, if not. - :rtype: CommonExecutionResult - """ - relationship_bit_instance = cls.load_relationship_bit_by_id(relationship_bit_id) - if relationship_bit_instance is None: - return CommonExecutionResult(False, f'Failed to locate relationship bit {relationship_bit_id}') - target_sim_id = CommonSimUtils.get_sim_id(target_sim_info) - relationship_tracker = sim_info.relationship_tracker - if relationship_tracker is None: - return CommonExecutionResult(False, f'{sim_info} did not have a relationship tracker.') - relationship_tracker.add_relationship_bit(target_sim_id, relationship_bit_instance) - return CommonExecutionResult.TRUE - - @classmethod - def remove_relationship_bit( - cls, - sim_info: SimInfo, - target_sim_info: SimInfo, - relationship_bit_id: Union[int, CommonRelationshipBitId] - ) -> CommonExecutionResult: - """remove_relationship_bit(sim_info, target_sim_info, relationship_bit_id) - - Remove a relationship bit between two sims. - - .. note:: - - If the relationship bit is UNIDIRECTIONAL, it will only be removed from sim_info in the direction of the Target. - i.e. Sim will have no longer have relationship bit towards Target, but Target will still have relationship bit towards Sim. - - One example is the Caregiver relationship: - - - Sim is caregiver of Target. - - Target is being cared for by Sim. - - :param sim_info: The source Sim of the Relationship Bit. - :type sim_info: SimInfo - :param target_sim_info: The target Sim of the Relationship Bit. - :type target_sim_info: SimInfo - :param relationship_bit_id: The identifier of the Relationship Bit to remove. - :type relationship_bit_id: Union[int, CommonRelationshipBitId] - :return: True, if the relationship bit was removed successfully. False, if not. - :rtype: CommonExecutionResult - """ - relationship_bit_instance = cls.load_relationship_bit_by_id(relationship_bit_id) - if relationship_bit_instance is None: - return CommonExecutionResult(False, f'Failed to locate relationship bit {relationship_bit_id}') - target_sim_id = CommonSimUtils.get_sim_id(target_sim_info) - relationship_tracker = sim_info.relationship_tracker - if relationship_tracker is None: - return CommonExecutionResult(False, f'{sim_info} did not have a relationship tracker.') - relationship_tracker.remove_relationship_bit(target_sim_id, relationship_bit_instance) - return CommonExecutionResult.TRUE - - @classmethod - def remove_relationship_bit_from_all( - cls, - sim_info: SimInfo, - relationship_bit_id: Union[int, CommonRelationshipBitId] - ) -> bool: - """remove_relationship_bit_from_all(sim_info, relationship_bit_id) - - Remove a relationship bit between a Sim and all other Sims. - - .. note:: - - If the relationship bit is UNIDIRECTIONAL, it will only be removed from sim_info in the direction of the Target. - i.e. Sim will have no longer have relationship bit towards Target, but Target will still have relationship bit towards Sim. - - One example is the Caregiver relationship: - - - Sim is caregiver of Target. - - Target is being cared for by Sim. - - :param sim_info: The source Sim of the Relationship Bit. - :type sim_info: SimInfo - :param relationship_bit_id: The identifier of the Relationship Bit to remove. - :type relationship_bit_id: Union[int, CommonRelationshipBitId] - :return: True, if the relationship bit was removed successfully. False, if not. - :rtype: bool - """ - relationship_bit_instance = cls.load_relationship_bit_by_id(relationship_bit_id) - if relationship_bit_instance is None: - return False - sim_id_a = CommonSimUtils.get_sim_id(sim_info) - for relationship in cls.get_relationships_gen(sim_info): - sim_id_b = relationship.get_other_sim_id(sim_id_a) - if relationship.has_bit(sim_id_a, relationship_bit_instance): - relationship.remove_bit(sim_id_a, sim_id_b, relationship_bit_instance) - return True - - @classmethod - def get_sim_info_of_all_sims_with_relationship_bit_generator(cls, sim_info: SimInfo, relationship_bit_id: Union[int, CommonRelationshipBitId], instanced_only: bool = True) -> Iterator[SimInfo]: - """get_sim_info_of_all_sims_with_relationship_bit_generator(sim_info, relationship_bit_id, instanced_only=True) - - Retrieve an Iterator of SimInfo for all Sims that have the specified relationship bit with the specified Sim. - - .. note:: - - For UNIDIRECTIONAL relationship bits, the direction is sim_info has relationship bit with target_sim_info - - Caregiver example: - - - The Caregiver has a relationship bit pointed at Toddler (The Caregiver would show "caregiving ward" when hovering over the Toddler in the relationships panel) - - The Toddler would NOT have the relationship bit. - - Sim is Caregiver of Toddler. - - :param sim_info: The Sim to locate the relationship bit on. - :type sim_info: SimInfo - :param relationship_bit_id: The identifier of the relationship bit to locate connections with. - :type relationship_bit_id: Union[int, CommonRelationshipBitId] - :param instanced_only: If True, only Sims that are currently loaded will be returned. - :type instanced_only: bool, optional - :return: An iterator of Sims that have the specified relationship bit with the specified Sim. - :rtype: Iterator[SimInfo] - """ - return cls.get_sim_info_of_all_sims_with_relationship_bits_generator(sim_info, (relationship_bit_id, ), instanced_only=instanced_only) - - @classmethod - def get_sim_info_of_all_sims_with_relationship_bits_generator(cls, sim_info: SimInfo, relationship_bit_ids: Iterator[Union[int, CommonRelationshipBitId]], instanced_only: bool = True) -> Iterator[SimInfo]: - """get_sim_info_of_all_sims_with_relationship_bits_generator(sim_info, relationship_bit_ids, instanced_only=True) - - Retrieve an Iterator of SimInfo for all Sims that have the specified relationship bits with the specified Sim. - - .. note:: - - For UNIDIRECTIONAL relationship bits, the direction is sim_info has relationship bit with target_sim_info - Caregiver example: - - - The Caregiver has a relationship bit pointed at Toddler (The Caregiver would show "caregiving ward" when hovering over the toddler in the relationships panel) - - The toddler would NOT have the relationship bit. - - Sim is Caregiver of Toddler. - - :param sim_info: The Sim to locate relationship bits on. - :type sim_info: SimInfo - :param relationship_bit_ids: A collection of identifiers for relationship bits to locate connections with. - :type relationship_bit_ids: Iterator[Union[int, CommonRelationshipBitId]] - :param instanced_only: If True, only Sims that are currently loaded will be returned. - :type instanced_only: bool, optional - :return: An iterator of Sims that have any of the specified relationship bits with the specified Sim. - :rtype: Iterator[SimInfo] - """ - if sim_info is None: - return tuple() - sim_id = CommonSimUtils.get_sim_id(sim_info) - for relationship in sim_info.relationship_tracker: - if relationship.sim_id_a != sim_id: - target_sim_id = relationship.sim_id_a - else: - target_sim_id = relationship.sim_id_b - target_sim_info = CommonSimUtils.get_sim_info(target_sim_id) - if target_sim_info is None: - continue - if instanced_only and CommonSimUtils.get_sim_instance(target_sim_info) is None: - continue - for relationship_bit_id in relationship_bit_ids: - relationship_bit_instance = cls.load_relationship_bit_by_id(relationship_bit_id) - if relationship_bit_instance is None: - continue - if relationship.has_bit(sim_id, relationship_bit_instance): - yield target_sim_info - break - - @classmethod - def has_positive_romantic_combo_relationship_bit_with(cls, sim_info: SimInfo, target_sim_info: SimInfo) -> bool: - """has_positive_romantic_combo_relationship_bit_with(sim_info, target_sim_info) - - Determine if a Sim has a positive romantic combo with the Target Sim. - - .. note:: - - Positive Romantic Combo Relationship Bits: - - - Soul Mates - - Lovers - - Sweethearts - - Love Birds - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :param target_sim_info: The Target Sim to check. - :type target_sim_info: SimInfo - :return: True, if the Sims have positive romantic combo relationship bits with each other. False, if not. - :rtype: bool - """ - return cls.has_relationship_bits_with_sim(sim_info, target_sim_info, ( - CommonRelationshipBitId.ROMANTIC_COMBO_SOUL_MATES, - CommonRelationshipBitId.ROMANTIC_COMBO_LOVERS, - CommonRelationshipBitId.ROMANTIC_COMBO_SWEETHEARTS, - CommonRelationshipBitId.ROMANTIC_COMBO_LOVEBIRDS - )) - - @classmethod - def get_sim_info_of_all_sims_romantically_committed_to_generator(cls, sim_info: SimInfo, instanced_only: bool = True) -> Iterator[SimInfo]: - """get_sim_info_of_all_sims_romantically_committed_to_generator(sim_info, instanced_only=True) - - Retrieve a SimInfo object for all Sims romantically committed with the specified Sim. - - .. note:: - - Romantic Commitments: - - - Married - - Getting Married - - Engaged - - Significant Other - - Promised - - - :param sim_info: The Sim to locate romantically involved Sims with. - :type sim_info: SimInfo - :param instanced_only: If True, only Sims that are currently loaded will be returned. - :type instanced_only: bool, optional - :return: An iterator of Sims the specified Sim is romantically committed to. - :rtype: Iterator[SimInfo] - """ - romance_relationship_ids = cls.get_romantically_committed_relationship_bits() - for target_sim_info in cls.get_sim_info_of_all_sims_with_relationship_bits_generator(sim_info, romance_relationship_ids, instanced_only=instanced_only): - yield target_sim_info - - @classmethod - def get_friendship_relationship_track(cls, sim_info_a: SimInfo, sim_info_b: SimInfo) -> Union[CommonRelationshipTrackId, None]: - """get_friendship_relationship_track(sim_info_a, sim_info_b) - - Get an appropriate Friendship Relationship track between Sim A and Sim B. - - :param sim_info_a: An instance of a Sim. - :type sim_info_a: SimInfo - :param sim_info_b: An instance of a Sim. - :type sim_info_b: SimInfo - :return: The decimal identifier of the Friendship Relationship Track appropriate for Sim A to have with Sim B or None if not found. - :rtype: Union[CommonRelationshipTrackId, None] - """ - if CommonSpeciesUtils.is_human(sim_info_a): - if CommonSpeciesUtils.is_animal(sim_info_b): - return CommonRelationshipTrackId.SIM_TO_PET_FRIENDSHIP - elif CommonSpeciesUtils.is_human(sim_info_b): - return CommonRelationshipTrackId.FRIENDSHIP - elif CommonSpeciesUtils.is_animal(sim_info_a): - if CommonSpeciesUtils.is_animal(sim_info_b): - return None - elif CommonSpeciesUtils.is_human(sim_info_b): - return CommonRelationshipTrackId.SIM_TO_PET_FRIENDSHIP - return None - - @classmethod - def get_romance_relationship_track(cls, sim_info_a: SimInfo, sim_info_b: SimInfo) -> Union[CommonRelationshipTrackId, None]: - """get_romance_relationship_track(sim_info_a, sim_info_b) - - Get an appropriate Romance Relationship track between Sim A and Sim B. - - :param sim_info_a: An instance of a Sim. - :type sim_info_a: SimInfo - :param sim_info_b: An instance of a Sim. - :type sim_info_b: SimInfo - :return: The decimal identifier of the Romance Relationship Track appropriate for Sim A to have with Sim B or None if not found. - :rtype: Union[CommonRelationshipTrackId, None] - """ - if CommonSpeciesUtils.is_human(sim_info_a) and CommonSpeciesUtils.is_human(sim_info_b): - return CommonRelationshipTrackId.ROMANCE - return None - - @classmethod - def load_relationship_bit_by_id(cls, relationship_bit: Union[int, CommonRelationshipBitId, RelationshipBit]) -> Union[RelationshipBit, None]: - """load_relationship_bit_by_id(relationship_bit) - - Load an instance of a Relationship Bit by its identifier. - - :param relationship_bit: The identifier of a Relationship Bit. - :type relationship_bit: Union[int, CommonRelationshipBitId, RelationshipBit] - :return: An instance of a Relationship Bit matching the decimal identifier or None if not found. - :rtype: Union[RelationshipBit, None] - """ - if isinstance(relationship_bit, RelationshipBit): - return relationship_bit - # noinspection PyBroadException - try: - # noinspection PyCallingNonCallable - relationship_bit_instance = relationship_bit() - if isinstance(relationship_bit_instance, RelationshipBit): - # noinspection PyTypeChecker - return relationship_bit - except: - pass - # noinspection PyBroadException - try: - relationship_bit: int = int(relationship_bit) - except: - # noinspection PyTypeChecker - relationship_bit: RelationshipBit = relationship_bit - return relationship_bit - - from sims4.resources import Types - from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils - return CommonResourceUtils.load_instance(Types.RELATIONSHIP_BIT, relationship_bit) - - @classmethod - def load_relationship_track_by_id(cls, relationship_track: Union[int, CommonRelationshipTrackId, RelationshipTrack]) -> Union[RelationshipTrack, None]: - """load_relationship_track_by_id(relationship_track) - - Load an instance of a Relationship Track by its identifier. - - :param relationship_track: The identifier of a Relationship Track. - :type relationship_track: Union[int, CommonRelationshipTrackId, RelationshipTrack] - :return: An instance of a Relationship Track matching the decimal identifier or None if not found. - :rtype: Union[RelationshipTrack, None] - """ - if isinstance(relationship_track, RelationshipTrack): - return relationship_track - # noinspection PyBroadException - try: - # noinspection PyCallingNonCallable - relationship_track_instance = relationship_track() - if isinstance(relationship_track_instance, RelationshipTrack): - # noinspection PyTypeChecker - return relationship_track - except: - pass - # noinspection PyBroadException - try: - relationship_track: int = int(relationship_track) - except: - # noinspection PyTypeChecker - relationship_track: RelationshipTrack = relationship_track - return relationship_track - - from sims4.resources import Types - from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils - return CommonResourceUtils.load_instance(Types.STATISTIC, relationship_track) - - @classmethod - def get_relationship_bit_guid(cls, relationship_bit: Union[int, RelationshipBit]) -> Union[int, None]: - """get_relationship_bit_guid(relationship_bit) - - Retrieve the GUID (Decimal Identifier) of a RelationshipBit. - - :param relationship_bit: The identifier or instance of a RelationshipBit. - :type relationship_bit: Union[int, RelationshipBit] - :return: The decimal identifier of the RelationshipBit or None if the RelationshipBit does not have an id. - :rtype: Union[int, None] - """ - if isinstance(relationship_bit, int): - return relationship_bit - return getattr(relationship_bit, 'guid64', None) - - -log = CommonLogRegistry().register_log(ModInfo.get_identity(), 'common_relationship_commands') -log.enable() - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.remove_relationship_bit', - 'Remove a relationship bit from a Sim.', - command_arguments=( - CommonConsoleCommandArgument('relationship_bit', 'Relationship Bit Id or Tuning Name', 'The decimal identifier or Tuning Name of the Relationship Bit to remove.'), - CommonConsoleCommandArgument('source_sim_info', 'Sim Id or Name', 'The instance id or name of the Sim to remove the relationship bit from as the source.', is_optional=True, default_value='Active Sim'), - CommonConsoleCommandArgument('target_sim_info', 'Sim Id or Name', 'The instance id or name of the Sim to remove the relationship bit from as the target of the relationship bit. If not specified, the relationship bit will be removed regardless of target.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.remove_rel_bit', - ) -) -def _common_remove_relationship_bit( - output: CommonConsoleCommandOutput, - relationship_bit: TunableInstanceParam(Types.RELATIONSHIP_BIT), - source_sim_info: SimInfo = None, - target_sim_info: SimInfo = None, -): - if isinstance(relationship_bit, str): - output(f'ERROR: Invalid relationship bit specified \'{relationship_bit}\' or it was not found.') - return False - if target_sim_info is None: - output('ERROR: No Target was specified!') - return False - if source_sim_info is target_sim_info: - output(f'Attempting to remove relationship bit {relationship_bit} between {source_sim_info} for all other Sims.') - if not CommonRelationshipUtils.remove_relationship_bit_from_all(source_sim_info, relationship_bit): - output(f'FAILURE: Failed to remove relationship bit {relationship_bit} between {source_sim_info} for all other Sims.') - return False - else: - output(f'Attempting to remove relationship bit {relationship_bit} between {source_sim_info} and {target_sim_info}') - if not CommonRelationshipUtils.remove_relationship_bit(source_sim_info, target_sim_info, relationship_bit): - output(f'FAILURE: Failed to remove relationship bit {relationship_bit} between {source_sim_info} and {target_sim_info}.') - return False - output(f'SUCCESS: Successfully removed relationship bit {relationship_bit} between {source_sim_info} and {target_sim_info}.') - return True - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_testing.print_relationship_bits', - 'Print a list of all relationship bits a Sim has with other Sims.', - command_arguments=( - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance id or name of the Sim to check.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib_testing.printrelationshipbits', - 's4clib_testing.print_rel_bits', - 's4clib_testing.printrelbits' - ) -) -def _common_print_relationship_bits(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): - if sim_info is None: - return - output(f'Printing relationship bits of Sim {sim_info} with other Sims.') - log.debug(f'Printing relationship bits of Sim {sim_info} with other Sims.') - sim_id_a = CommonSimUtils.get_sim_id(sim_info) - text = '' - for relationship in sim_info.relationship_tracker: - sim_info_b = relationship.get_other_sim_info(sim_id_a) - try: - bi_direction_bits = relationship._bi_directional_relationship_data._bits - inner_text = f'\n---------------------Relationship ({sim_info} to {sim_info_b})---------------------' - if bi_direction_bits: - inner_text += '\n Bi-Directional Bits:' - for (key, value) in bi_direction_bits.items(): - bit_type = type(value) - inner_text += f'\n - {key.__name__} ({bit_type.__mro__[1].__name__})' - inner_text += '\n' - - sim_a_relationship_bits = relationship._sim_a_relationship_data._bits - if sim_a_relationship_bits: - inner_text += f'\n Unidirectional Bits Sim A (What {sim_info_b} is to {sim_info}):' - for (key, value) in sim_a_relationship_bits.items(): - bit_type = type(value) - inner_text += f'\n - {key.__name__} ({bit_type.__mro__[1].__name__})' - inner_text += '\n' - - sim_b_relationship_bits = relationship._sim_b_relationship_data._bits - if sim_b_relationship_bits: - inner_text += f'\n Unidirectional Bits Sim B (What {sim_info} is to {sim_info_b}):' - for (key, value) in sim_b_relationship_bits.items(): - bit_type = type(value) - inner_text += f'\n - {key.__name__} ({bit_type.__mro__[1].__name__})' - inner_text += '\n' - output(inner_text) - text += inner_text - except Exception as ex: - output(f'An error occurred when handling relationship bits for Sims {sim_info} to {sim_info_b} for relationship {relationship}: {ex}') - log.format_error_with_message('Failed to print relationships', sim_info=sim_info, sim_info_b=sim_info_b, relationship=relationship, exception=ex) - log.debug(text) - output('Done') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.meet_everyone', - 'Add the Has Met Relationship Bit between all Sim.' -) -def _common_meet_everyone(output: CommonConsoleCommandOutput): - output('Attempting to make everyone meet everyone.') - sim_pair_count = 0 - for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): - for target_sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): - if sim_info is target_sim_info: - continue - if CommonRelationshipUtils.has_met(sim_info, target_sim_info): - continue - sim_pair_count += 1 - CommonRelationshipUtils.add_relationship_bit(sim_info, target_sim_info, CommonRelationshipBitId.HAS_MET) - CommonRelationshipUtils.add_relationship_bit(target_sim_info, sim_info, CommonRelationshipBitId.HAS_MET) - output(f'Done adding the Has Met relationship bit to {sim_pair_count} Sim pair(s).') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.unmeet_everyone', - 'Remove the Has Met Relationship Bit between all Sims.', -) -def _common_unmeet_everyone(output: CommonConsoleCommandOutput): - output('Attempting to make everyone unmeet everyone.') - sim_pair_count = 0 - for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): - for target_sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): - if sim_info is target_sim_info: - continue - if not CommonRelationshipUtils.has_met(sim_info, target_sim_info): - continue - sim_pair_count += 1 - CommonRelationshipUtils.remove_relationship_bit(sim_info, target_sim_info, CommonRelationshipBitId.HAS_MET) - CommonRelationshipUtils.remove_relationship_bit(target_sim_info, sim_info, CommonRelationshipBitId.HAS_MET) - output(f'Done removing the Has Met relationship from {sim_pair_count} Sim pair(s).') - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.add_relationship_bit', - 'Add a relationship bit from Sim A to Sim B.', - command_arguments=( - CommonConsoleCommandArgument('relationship_bit', 'Name or Id', 'The name or id of a relationship bit to add.'), - CommonConsoleCommandArgument('sim_a', 'Name or Id', 'The name of the first Sim. The relationship bit will be added from Sim A to Sim B.'), - CommonConsoleCommandArgument('sim_b', 'Name or Id', 'The name of the second Sim. The relationship bit will be added from Sim A to Sim B.') - ), - command_aliases=( - 's4clib.add_rel_bit', - 's4clib.addrelationshipbit', - 's4clib.addrelbit' - ) -) -def _common_add_relationship_bit(output: CommonConsoleCommandOutput, relationship_bit: TunableInstanceParam(Types.RELATIONSHIP_BIT), sim_info_a: SimInfo, sim_info_b: SimInfo): - if isinstance(relationship_bit, str): - output(f'ERROR: Invalid relationship bit specified \'{relationship_bit}\' or it was not found.') - return False - if sim_info_b is None: - output('ERROR: No Target was specified!') - return False - if sim_info_a is sim_info_b: - output('ERROR: Cannot add a relationship bit to the same Sim.') - return False - output(f'Attempting to add relationship bit {relationship_bit} from {sim_info_a} to {sim_info_b}.') - result = CommonRelationshipUtils.add_relationship_bit(sim_info_a, sim_info_b, relationship_bit) - if result: - output(f'SUCCESS: Successfully added relationship bit {relationship_bit} between {sim_info_a} and {sim_info_b}.') - else: - output(f'FAILURE: Failed to add relationship bit {relationship_bit} between {sim_info_a} and {sim_info_b}. {result}') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.reset_relationships', - 'Reset the relationships of a Sim to all other Sims that they have met. Both Friendship and Romance will be set to zero.', - command_arguments=( - CommonConsoleCommandArgument('sim_info', 'Name or Id', 'The name or ID of a Sim. Default is the Active Sim.', is_optional=True, default_value='Active Sim'), - ), -) -def _common_reset_relationships(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): - output(f'Attempting to reset the relationships of {sim_info}.') - sim_pair_count = 0 - for target_sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): - if sim_info is target_sim_info: - continue - if not CommonRelationshipUtils.has_met(sim_info, target_sim_info): - continue - sim_pair_count += 1 - CommonRelationshipUtils.set_friendship_level(sim_info, target_sim_info, 0) - CommonRelationshipUtils.set_romance_level(sim_info, target_sim_info, 0) - output(f'Done resetting the relationships of {sim_pair_count} Sim pair(s).') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.reset_all_relationships', - 'Set the relationships of all Sims to zero with all other Sims that they have already met. Both Friendship and Romance will be set to zero.' -) -def _common_reset_all_relationships(output: CommonConsoleCommandOutput): - output('Attempting to reset the relationships between all Sims.') - sim_pair_count = 0 - for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): - for target_sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): - if sim_info is target_sim_info: - continue - if not CommonRelationshipUtils.has_met(sim_info, target_sim_info): - continue - sim_pair_count += 1 - CommonRelationshipUtils.set_friendship_level(sim_info, target_sim_info, 0) - CommonRelationshipUtils.set_romance_level(sim_info, target_sim_info, 0) - output(f'Done resetting the relationships of {sim_pair_count} Sim pair(s).') - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.set_relationship_level', - 'Set the level of a relationship from Sim A to Sim B.', - command_arguments=( - CommonConsoleCommandArgument('relationship_track', 'Name or Id', 'The name or id of a relationship track to modify.'), - CommonConsoleCommandArgument('sim_a', 'Name or Id', 'The name of the first Sim. The relationship track will be modified from Sim A to Sim B.'), - CommonConsoleCommandArgument('sim_b', 'Name or Id', 'The name of the second Sim. The relationship track will be modified from Sim A to Sim B.'), - CommonConsoleCommandArgument('amount', 'Number', 'The amount of value to set.') - ), - command_aliases=( - 's4clib.setrelationshiplevel', - ) -) -def _common_set_relationship_level( - output: CommonConsoleCommandOutput, - relationship_track: TunableInstanceParam(Types.STATISTIC), - sim_info_a: SimInfo, - sim_info_b: SimInfo, - amount: float -): - if isinstance(relationship_track, str): - output(f'ERROR: Invalid relationship track specified \'{relationship_track}\' or it was not found.') - return False - if sim_info_b is None: - output('ERROR: No Target was specified!') - return False - if sim_info_a is sim_info_b: - output('ERROR: Cannot modify relationship level to the same Sim.') - return False - output(f'Attempting to modify relationship level of {relationship_track} from {sim_info_a} to {sim_info_b} to level {amount}.') - result = CommonRelationshipUtils.set_relationship_level_of_sims(sim_info_a, sim_info_b, relationship_track, amount) - if result: - output(f'SUCCESS: Successfully modified relationship level of {relationship_track} between {sim_info_a} and {sim_info_b}.') - else: - output(f'FAILURE: Failed to modify relationship level of {relationship_track} between {sim_info_a} and {sim_info_b}. {result}') diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_appearance_modifier_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_appearance_modifier_utils.py deleted file mode 100644 index f69afc9..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_appearance_modifier_utils.py +++ /dev/null @@ -1,219 +0,0 @@ -""" -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 -""" -from typing import Union, Type, Iterator, Any, Callable - -from buffs.appearance_modifier.appearance_modifier import AppearanceModifier -from buffs.appearance_modifier.appearance_tracker import AppearanceTracker, ModifierInfo -from cas.cas import OutfitOverrideOptionFlags -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.enums.common_appearance_modifier_priority import CommonAppearanceModifierPriority -from s4ap.sims4communitylib.enums.common_appearance_modifier_type import CommonAppearanceModifierType - - -class CommonSimAppearanceModifierUtils: - """Utilities for manipulating the appearance modifiers of Sims. - - """ - @staticmethod - def get_appearance_tracker(sim_info: SimInfo) -> Union[AppearanceTracker, None]: - """get_appearance_tracker(sim_info) - - Retrieve the appearance tracker of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The appearance tracker for the Sim or None if not found. - :rtype: Union[AppearanceTracker, None] - """ - if sim_info is None: - return None - if sim_info.appearance_tracker is None: - return None - return sim_info.appearance_tracker - - @staticmethod - def has_any_appearance_modifiers(sim_info: SimInfo) -> bool: - """has_any_appearance_modifiers(sim_info) - - Determine if a Sim has any appearance modifiers applied to them. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: True, if the Sim has any appearance modifiers applied to them. False, if not. - :rtype: bool - """ - return any(CommonSimAppearanceModifierUtils.get_appearance_modifiers_gen(sim_info)) - - @staticmethod - def has_any_appearance_modifiers_with_guid(sim_info: SimInfo, modifier_guid: int) -> bool: - """has_any_appearance_modifiers_with_guid(sim_info, modifier_guid) - - Determine if a Sim has any appearance modifiers applied to them with a specified GUID. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param modifier_guid: The GUID of the modifier to search for. - :type modifier_guid: int - :return: True, if the Sim has any appearance modifiers applied to them with the specified GUID. False, if not. - :rtype: bool - """ - return any(CommonSimAppearanceModifierUtils.get_appearance_modifiers_by_guid_gen(sim_info, modifier_guid)) - - @staticmethod - def has_any_appearance_modifiers_of_type(sim_info: SimInfo, modifier_type: Type[AppearanceModifier.BaseAppearanceModification]) -> bool: - """has_any_appearance_modifiers_of_type(sim_info, modifier_type) - - Determine if a Sim has any appearance modifiers applied to them of a specified type. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param modifier_type: The type of modifier to search for. - :type modifier_type: Type[AppearanceModifier.BaseAppearanceModification] - :return: True, if the Sim has any appearance modifiers applied to them of the specified type. False, if not. - :rtype: bool - """ - return any(CommonSimAppearanceModifierUtils.get_appearance_modifiers_by_type_gen(sim_info, modifier_type)) - - @staticmethod - def get_appearance_modifiers_by_guid_gen(sim_info: SimInfo, modifier_guid: int) -> Iterator[ModifierInfo]: - """get_appearance_modifiers_by_guid_gen(sim_info, modifier_guid) - - Retrieve the appearance modifiers applied to a Sim that have the specified GUID. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param modifier_guid: The GUID of the modifiers to search for. - :type modifier_guid: int - :return: An iterator of Appearance Modifiers that have the specified GUID. - :rtype: Iterator[ModifierInfo] - """ - def _matches(_modifier_type: Any, _appearance_modifier: ModifierInfo) -> bool: - return _appearance_modifier.guid == modifier_guid - - yield from CommonSimAppearanceModifierUtils.get_appearance_modifiers_gen(sim_info, include_appearance_modifier=_matches) - - @staticmethod - def get_appearance_modifiers_by_type_gen(sim_info: SimInfo, modifier_type: Type[AppearanceModifier.BaseAppearanceModification]) -> Iterator[ModifierInfo]: - """get_appearance_modifiers_by_type_gen(sim_info, modifier_type) - - Retrieve the appearance modifiers applied to a Sim that match a specified type. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param modifier_type: The type of the modifiers to search for. - :type modifier_type: Type[AppearanceModifier.BaseAppearanceModification] - :return: An iterator of Appearance Modifiers that match the specified type. - :rtype: Iterator[ModifierInfo] - """ - def _matches(_modifier_type: Any, _appearance_modifier: ModifierInfo) -> bool: - return isinstance(_appearance_modifier.modifier, modifier_type) - - yield from CommonSimAppearanceModifierUtils.get_appearance_modifiers_gen(sim_info, include_appearance_modifier=_matches) - - @staticmethod - def get_appearance_modifiers_gen(sim_info: SimInfo, include_appearance_modifier: Callable[[CommonAppearanceModifierType, ModifierInfo], bool] = None) -> Iterator[ModifierInfo]: - """get_appearance_modifiers_gen(sim_info, include_appearance_modifier=None) - - Retrieve the appearance modifiers applied to a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param include_appearance_modifier: If the result of this callback is True, the Appearance Modifier will be included in the results. If set to None, All Appearance Modifiers will be included. Default is None. - :type include_appearance_modifier: Callable[[CommonAppearanceModifierType, ModifierInfo], bool], optional - :return: An iterator of all Appearance Modifiers applied to the Sim that match the `include_appearance_modifier` filter. - :rtype: Iterator[ModifierInfo] - """ - appearance_tracker = CommonSimAppearanceModifierUtils.get_appearance_tracker(sim_info) - if appearance_tracker is None: - return tuple() - if appearance_tracker._active_appearance_modifier_infos is None: - return tuple() - for (modifier_type, appearance_modifiers) in appearance_tracker._active_appearance_modifier_infos.items(): - for appearance_modifier in appearance_modifiers: - if include_appearance_modifier is not None and not include_appearance_modifier(modifier_type, appearance_modifier): - continue - yield appearance_modifier - return tuple() - - @staticmethod - def add_appearance_modifier( - sim_info: SimInfo, - modifier: AppearanceModifier.BaseAppearanceModification, - modifier_guid: int, - priority: CommonAppearanceModifierPriority = CommonAppearanceModifierPriority.TRANSFORMED, - apply_to_all_outfits: bool = True, - additional_flags: OutfitOverrideOptionFlags = OutfitOverrideOptionFlags.DEFAULT, - source: Any = None - ) -> None: - """add_appearance_modifier(\ - sim_info,\ - modifier,\ - modifier_guid,\ - priority=CommonAppearanceModifierPriority.TRANSFORMED,\ - apply_to_all_outfits=True,\ - additional_flags=OutfitOverrideOptionFlags.DEFAULT,\ - source=None\ - ) - - Determine if a Sim has any appearance modifiers applied to them of a specified type. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param modifier: The Appearance Modifier to apply. - :type modifier: AppearanceModifier.BaseAppearanceModification - :param modifier_guid: The GUID of the appearance modifier being applied. - :type modifier_guid: int - :param priority: The priority of the appearance modifier. This determines which types of appearance modifiers can override this modifier and which ones this modifier overrides. Default is CommonAppearanceModifierPriority.TRANSFORMED. - :type priority: CommonAppearanceModifierPriority, optional - :param apply_to_all_outfits: If True, the appearance modifier will apply to all outfits. If False, the appearance modifier will only apply the current outfit of the Sim. Default is True. - :type apply_to_all_outfits: bool, optional - :param additional_flags: Additional flags for overriding outfit parts. Default is OutfitOverrideOptionFlags.DEFAULT. - :type additional_flags: OutfitOverrideOptionFlags, optional - :param source: The source of the appearance modifier. Default is None. - :type source: Any, optional - """ - appearance_tracker = sim_info.appearance_tracker - if isinstance(modifier, tuple): - if len(modifier) > 1: - modifier = appearance_tracker._choose_modifier(modifier) - else: - modifier = modifier[0].modifier - vanilla_priority = CommonAppearanceModifierPriority.convert_to_vanilla(priority) - appearance_tracker.add_appearance_modifier(modifier, modifier_guid, vanilla_priority, apply_to_all_outfits, source=source, additional_flags=additional_flags) - - @staticmethod - def remove_appearance_modifiers_by_guid(sim_info: SimInfo, modifier_guid: int, source: str = 'S4CL Removal') -> None: - """remove_appearance_modifiers_by_guid(sim_info, modifier_guid, source='S4CL Removal') - - Remove appearance modifiers from a Sim by their GUID. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param modifier_guid: The GUID of the modifiers to remove. - :type modifier_guid: int - :param source: The source of the removal. Default is "S4CL Removal". - :type source: str, optional - """ - appearance_tracker = CommonSimAppearanceModifierUtils.get_appearance_tracker(sim_info) - if appearance_tracker is None: - return - appearance_tracker.remove_appearance_modifiers(modifier_guid, source=source) - - @staticmethod - def evaluate_appearance_modifiers(sim_info: SimInfo) -> None: - """evaluate_appearance_modifiers(sim_info) - - Force evaluate the appearance modifiers of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - """ - appearance_tracker = CommonSimAppearanceModifierUtils.get_appearance_tracker(sim_info) - if appearance_tracker is None: - return - appearance_tracker.evaluate_appearance_modifiers() diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_autonomy_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_autonomy_utils.py deleted file mode 100644 index ec2f329..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_autonomy_utils.py +++ /dev/null @@ -1,143 +0,0 @@ -""" -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 -""" -from autonomy.settings import AutonomyState -from objects.game_object import GameObject -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.enums.common_object_preference_tag import CommonObjectPreferenceTag -from s4ap.sims4communitylib.enums.types.component_types import CommonComponentType -from s4ap.sims4communitylib.utils.common_component_utils import CommonComponentUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - - -class CommonSimAutonomyUtils: - """ Utilities for manipulating the autonomy of Sims. """ - - @staticmethod - def get_autonomy_state(sim_info: SimInfo) -> AutonomyState: - """get_autonomy_state_setting(sim_info) - - Retrieve the current autonomy state of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - """ - from autonomy.autonomy_component import AutonomyComponent - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return AutonomyState.UNDEFINED - autonomy_component: AutonomyComponent = CommonComponentUtils.get_component(sim, CommonComponentType.AUTONOMY) - if autonomy_component is None or not hasattr(autonomy_component, 'get_autonomy_state_setting'): - return AutonomyState.UNDEFINED - return autonomy_component.get_autonomy_state_setting() - - @staticmethod - def has_disabled_autonomy(sim_info: SimInfo) -> bool: - """has_disabled_autonomy(sim_info) - - Determine if the autonomy state of a Sim is set to Disabled. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: True, if the autonomy state of the Sim is set to Disabled. False, if not. - :rtype: bool - """ - return CommonSimAutonomyUtils.has_autonomy_state(sim_info, AutonomyState.DISABLED) - - @staticmethod - def has_limited_autonomy(sim_info: SimInfo) -> bool: - """has_limited_autonomy(sim_info) - - Determine if the autonomy state of a Sim is set to Limited Only. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: True, if the autonomy state of the Sim is set to Limited Only. False, if not. - :rtype: bool - """ - return CommonSimAutonomyUtils.has_autonomy_state(sim_info, AutonomyState.LIMITED_ONLY) - - @staticmethod - def has_medium_autonomy(sim_info: SimInfo) -> bool: - """has_medium_autonomy(sim_info) - - Determine if the autonomy state of a Sim is set to Medium. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: True, if the autonomy state of the Sim is set to Medium. False, if not. - :rtype: bool - """ - return CommonSimAutonomyUtils.has_autonomy_state(sim_info, AutonomyState.MEDIUM) - - @staticmethod - def has_full_autonomy(sim_info: SimInfo) -> bool: - """has_full_autonomy(sim_info) - - Determine if the autonomy state of a Sim is set to Full. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: True, if the autonomy state of the Sim is set to Full. False, if not. - :rtype: bool - """ - return CommonSimAutonomyUtils.has_autonomy_state(sim_info, AutonomyState.FULL) - - @staticmethod - def has_autonomy_state(sim_info: SimInfo, autonomy_state: AutonomyState) -> bool: - """has_autonomy_state(sim_info, autonomy_state) - - Determine if the autonomy state of a Sim matches an autonomy state. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param autonomy_state: An autonomy state. - :type autonomy_state: AutonomyState - :return: True, if the autonomy state of the Sim matches the specified autonomy state. False, if not. - :rtype: bool - """ - return CommonSimAutonomyUtils.get_autonomy_state(sim_info) == autonomy_state - - @staticmethod - def has_scoring_preference_for_object(sim_info: SimInfo, preference_tag: CommonObjectPreferenceTag, game_object: GameObject) -> bool: - """has_scoring_preference_for_object(sim_info, preference_tag, game_object) - - Determine if a Sim will have a scoring preference for an Object when searching for Objects to use with a Tag. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param preference_tag: The tag to look for preference with. - :type preference_tag: CommonObjectPreferenceTag - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if the Sim will have a scoring preference to use the specified Object when searching for Objects to use with the specified Tag. False, if not. - :rtype: bool - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None or game_object is None: - return False - return sim.is_object_scoring_preferred(preference_tag, game_object) - - @staticmethod - def has_use_preference_for_object(sim_info: SimInfo, preference_tag: CommonObjectPreferenceTag, game_object: GameObject) -> bool: - """has_use_preference_for_object(sim_info, preference_tag, game_object) - - Determine if a Sim will have a preference for an Object when searching for Objects to use with a Tag. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param preference_tag: The tag to look for preference with. - :type preference_tag: CommonObjectPreferenceTag - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if the Sim will prefer to use the specified Object when searching for Objects to use with the specified Tag. False, if not. - :rtype: bool - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None or game_object is None: - return False - return sim.is_object_use_preferred(preference_tag, game_object) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_body_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_body_utils.py deleted file mode 100644 index e59d8a3..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_body_utils.py +++ /dev/null @@ -1,190 +0,0 @@ -""" -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 -""" -from typing import Tuple - -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ - CommonConsoleCommandArgument -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - - -class CommonSimBodyUtils: - """Utilities for manipulating the body of Sims. - - """ - - @staticmethod - def get_wading_size(sim_info: SimInfo) -> Tuple[int, int]: - """get_wading_size(sim_info) - - Retrieve the size of a Sim if they were to wade in an Ocean of water. - - .. note:: This function is obsolete. Please use :func:`~get_ocean_wading_size` instead. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: A tuple indicating the x and y wading size of a Sim from their origin point. - :rtype: Tuple[int, int] - """ - return CommonSimBodyUtils.get_ocean_wading_size(sim_info) - - @staticmethod - def get_ocean_wading_size(sim_info: SimInfo) -> Tuple[int, int]: - """get_ocean_wading_size(sim_info) - - Retrieve the size of a Sim if they were to wade in an Ocean of water. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: A tuple indicating the x and y Ocean wading size of a Sim from their origin point. - :rtype: Tuple[int, int] - """ - # noinspection PyBroadException - try: - from world.ocean_tuning import OceanTuning - except: - return 0, 0 - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return 0, 0 - wading_interval = OceanTuning.get_actor_wading_interval(sim) - if wading_interval is None: - return 0, 0 - return wading_interval.lower_bound, wading_interval.upper_bound - - @staticmethod - def get_pond_wading_size(sim_info: SimInfo) -> Tuple[int, int]: - """get_wading_size(sim_info) - - Retrieve the size of a Sim if they were to wade in a pond of water. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: A tuple indicating the x and y Pond wading size of a Sim from their origin point. - :rtype: Tuple[int, int] - """ - # noinspection PyBroadException - try: - from objects.pools.pond_utils import PondUtils - except: - return 0, 0 - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return 0, 0 - wading_interval = PondUtils.get_actor_wading_interval(sim) - if wading_interval is None: - return 0, 0 - return wading_interval.lower_bound, wading_interval.upper_bound - - @classmethod - def set_fit_level(cls, sim_info: SimInfo, level: float): - """set_fit_level(sim_info, level) - - Set the Fit level of a Sim. - - :param sim_info: The Sim to modify. - :type sim_info: SimInfo - :param level: The Fit level to set the Sim to. - :type level: float - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - from objects.components.consumable_component import ConsumableComponent - sim.commodity_tracker.set_value(ConsumableComponent.FIT_COMMODITY, level) - sim_info._sim_ref().needs_fitness_update = True - sim_info.update_fitness_state() - - @classmethod - def get_fit_level(cls, sim_info: SimInfo) -> float: - """get_fit_level(sim_info) - - Get the Fit level of a Sim. - - :param sim_info: The Sim to modify. - :type sim_info: SimInfo - :return: The Fit level of the Sim. - :rtype: float - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - from objects.components.consumable_component import ConsumableComponent - return sim.commodity_tracker.get_value(ConsumableComponent.FIT_COMMODITY) - - @classmethod - def set_fat_level(cls, sim_info: SimInfo, level: float): - """set_fat_level(sim_info, level) - - Set the Fat level of a Sim. - - :param sim_info: The Sim to modify. - :type sim_info: SimInfo - :param level: The Fat level to set the Sim to. - :type level: float - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - from objects.components.consumable_component import ConsumableComponent - sim.commodity_tracker.set_value(ConsumableComponent.FAT_COMMODITY, level) - sim_info._sim_ref().needs_fitness_update = True - sim_info.update_fitness_state() - - @classmethod - def get_fat_level(cls, sim_info: SimInfo) -> float: - """get_fat_level(sim_info) - - Get the Fat level of a Sim. - - :param sim_info: The Sim to modify. - :type sim_info: SimInfo - :return: The Fat level of the Sim. - :rtype: float - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - from objects.components.consumable_component import ConsumableComponent - return sim.commodity_tracker.get_value(ConsumableComponent.FAT_COMMODITY) - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4cl.set_fit', - 'Set the Fit level of a Sim.', - command_arguments=( - CommonConsoleCommandArgument('level', 'Number', 'The Fit level to set the Sim to.', is_optional=False), - CommonConsoleCommandArgument('sim_info', 'Name or ID', 'The name or ID of the Sim to modify.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4cl.set_fit_level', - ) -) -def _common_set_fit_level(output: CommonConsoleCommandOutput, level: float, sim_info: SimInfo = None): - if sim_info is None: - output(f'No Sim found with {sim_info}') - return - output(f'Setting Fit level of {sim_info} to {level}.') - CommonSimBodyUtils.set_fit_level(sim_info, level) - output('Done') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4cl.set_fat', - 'Set the Fat level of a Sim.', - command_arguments=( - CommonConsoleCommandArgument('level', 'Number', 'The Fat level to set the Sim to.', is_optional=False), - CommonConsoleCommandArgument('sim_info', 'Name or ID', 'The name or ID of the Sim to modify.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4cl.set_fat_level', - ) -) -def _common_set_fat_level(output: CommonConsoleCommandOutput, level: float, sim_info: SimInfo = None): - if sim_info is None: - output(f'No Sim found with {sim_info}') - return - output(f'Setting Fat level of {sim_info} to {level}.') - CommonSimBodyUtils.set_fat_level(sim_info, level) - output('Done') diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_bucks_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_bucks_utils.py deleted file mode 100644 index f42ea61..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_bucks_utils.py +++ /dev/null @@ -1,785 +0,0 @@ -""" -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 -""" -from typing import Union, Iterator - -from bucks.bucks_enums import BucksType -from bucks.bucks_perk import BucksPerk -from bucks.bucks_tracker import BucksTrackerBase -from bucks.bucks_utils import BucksUtils -from server_commands.argument_helpers import TunableInstanceParam -from sims.sim_info import SimInfo -from sims4.resources import Types -from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.enums.common_bucks_types import CommonBucksType -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ - CommonConsoleCommandArgument -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - - -class CommonSimBucksUtils: - """Utilities for bucks. """ - @classmethod - def add_all_perks(cls, sim_info: SimInfo, bucks_type: Union[CommonBucksType, BucksType], no_cost: bool = True, **__) -> CommonExecutionResult: - """remove_all_perks(sim_info, bucks_type, refund_cost=True, **__) - - Add all Perks of a specified Bucks type to a Sim. - - .. note:: A Sim needs to be spawned before their perks can be added. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param bucks_type: The Bucks associated with the perks being added. - :type bucks_type: Union[CommonBucksType, BucksType] - :param no_cost: Set True to unlock the perk without spending perk points. Set False to spend perk points to unlock the perk.. Default is False - :type no_cost: bool, optional - :return: The result of executing the function. True, if successful. False, if not. - :rtype: CommonExecutionResult - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return CommonExecutionResult(False, reason=f'{sim_info} is not currently spawned. They need to be spawned before all of their perks can be locked.') - bucks_tracker: BucksTrackerBase = cls.get_bucks_tracker(sim_info, bucks_type, add_if_none=True) - if bucks_tracker is None: - return CommonExecutionResult(False, reason=f'{sim_info} does not have a tracker for the specified bucks. {bucks_type}') - for perk in cls.get_locked_perks_gen(sim_info, bucks_type): - if cls.has_perk_unlocked(sim_info, perk): - return CommonExecutionResult(True, reason=f'Perk {perk} is already unlocked.') - perk = cls.load_perk_by_guid(perk) - if perk is None: - return CommonExecutionResult(False, reason=f'Failed to locate perk by id {perk}') - modified_for_cost = False - if no_cost: - if not cls.can_afford_perk(sim_info, perk): - unlock_cost = cls.get_perk_unlock_cost(perk) - modify_result = cls.modify_bucks(sim_info, bucks_type, unlock_cost, reason='Perk being unlocked at no cost.') - if not modify_result: - return modify_result - modified_for_cost = True - elif not cls.can_afford_perk(sim_info, perk): - continue - if bucks_tracker.pay_for_and_unlock_perk(perk): - if not modified_for_cost: - unlock_cost = cls.get_perk_unlock_cost(perk) - modify_result = cls.modify_bucks(sim_info, bucks_type, unlock_cost, reason='Perk being unlocked at no cost.') - if not modify_result: - return modify_result - return CommonExecutionResult.TRUE - - @classmethod - def remove_all_perks(cls, sim_info: SimInfo, bucks_type: Union[CommonBucksType, BucksType], refund_cost: bool = True, reason: str = None, remove_perk_points: bool = False, **__) -> CommonExecutionResult: - """remove_all_perks(sim_info, bucks_type, refund_cost=True, reason=None, remove_perk_points=False, **__) - - Remove all Perks of a specified Bucks type from a Sim. - - .. note:: A Sim needs to be spawned before their perks can be removed. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param bucks_type: The Bucks associated with the perks being removed. - :type bucks_type: Union[CommonBucksType, BucksType] - :param refund_cost: Set True to refund the cost of all unlocked perks. Set False to give no perk points back. Default is True - :type refund_cost: bool, optional - :param reason: The reason the perks are being removed. Default is None. - :type reason: str, optional - :param remove_perk_points: Set True to remove all perk points in addition to all the perks. Set False to remove only the perks. If this is True, refund_cost will be ignored. Default is False. - :type remove_perk_points: bool, optional - :return: The result of executing the function. True, if successful. False, if not. - :rtype: CommonExecutionResult - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return CommonExecutionResult(False, reason=f'{sim_info} is not currently spawned. They need to be spawned before all of their perks can be removed.') - vanilla_bucks_type = CommonBucksType.convert_to_vanilla(bucks_type) - if vanilla_bucks_type is None: - return CommonExecutionResult(False, reason=f'Bucks Type {bucks_type} was not valid.') - bucks_tracker: BucksTrackerBase = cls.get_bucks_tracker(sim_info, bucks_type, add_if_none=False) - if bucks_tracker is None: - return CommonExecutionResult(False, reason=f'{sim_info} does not have a tracker for the specified bucks. {bucks_type}') - bucks_tracker.lock_all_perks(vanilla_bucks_type, refund_cost=refund_cost or remove_perk_points) - if remove_perk_points: - cls.set_bucks(sim_info, bucks_type, 0, reason=reason, **__) - return CommonExecutionResult.TRUE - - @classmethod - def lock_all_perks(cls, sim_info: SimInfo, bucks_type: Union[CommonBucksType, BucksType], refund_cost: bool = True) -> CommonExecutionResult: - """lock_all_perks(sim_info, bucks_type, refund_cost=True) - - Lock all perks of a specific Bucks type for a Sim. - - .. note:: A Sim needs to be spawned before their perks can be locked. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param bucks_type: The Bucks associated with the perks being locked. - :type bucks_type: Union[CommonBucksType, BucksType] - :param refund_cost: Set True to refund the cost of all unlocked perks. Set False to give no perk points back. Default is True - :type refund_cost: bool, optional - :return: The result of executing the function. True, if successful. False, if not. - :rtype: CommonExecutionResult - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return CommonExecutionResult(False, reason=f'{sim_info} is not currently spawned. They need to be spawned before all of their perks can be locked.') - vanilla_bucks_type = CommonBucksType.convert_to_vanilla(bucks_type) - if vanilla_bucks_type is None: - return CommonExecutionResult(False, reason=f'Bucks Type {bucks_type} was not valid.') - bucks_tracker: BucksTrackerBase = cls.get_bucks_tracker(sim_info, bucks_type, add_if_none=True) - if bucks_tracker is None: - return CommonExecutionResult(False, reason=f'{sim_info} does not have a tracker for the specified bucks. {bucks_type}') - bucks_tracker.lock_all_perks(vanilla_bucks_type, refund_cost=refund_cost) - return CommonExecutionResult.TRUE - - @classmethod - def has_perk_unlocked(cls, sim_info: SimInfo, perk: Union[BucksPerk, int]) -> CommonTestResult: - """has_perk_unlocked(sim_info, perk) - - Determine if a Sim has a perk unlocked. - - .. note:: A Sim needs to be spawned to check this. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param perk: The perk to lock. - :type perk: Union[BucksPerk, int] - :return: The result of the test. True, if the test passed. False, if the test failed. - :rtype: CommonTestResult - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return CommonTestResult(False, reason=f'{sim_info} is not currently spawned. They need to be spawned before all of their perks can be locked.') - perk = cls.load_perk_by_guid(perk) - if perk is None: - return CommonTestResult(False, reason=f'Failed to locate perk by id {perk}') - bucks_type = cls.get_perk_bucks_type(perk) - if bucks_type is None: - return CommonTestResult(False, reason=f'Bucks Type {bucks_type} was not valid.') - bucks_tracker: BucksTrackerBase = cls.get_bucks_tracker(sim_info, bucks_type, add_if_none=True) - if bucks_tracker is None: - return CommonTestResult(False, reason=f'{sim_info} does not have a tracker for the specified bucks. {bucks_type}') - if bucks_tracker.is_perk_unlocked(perk): - return CommonTestResult(True, reason=f'{sim_info} has perk {perk} unlocked.') - return CommonTestResult(False, reason=f'{sim_info} does not have perk {perk} unlocked.') - - @classmethod - def has_perk_locked(cls, sim_info: SimInfo, perk: Union[BucksPerk, int]) -> CommonTestResult: - """has_perk_locked(sim_info, perk) - - Determine if a Sim has a perk locked. - - .. note:: The Sim being checked needs to be spawned. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param perk: The perk to check. - :type perk: Union[BucksPerk, int] - :return: The result of the test. True, if the test passed. False, if the test failed. - :rtype: CommonTestResult - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return CommonTestResult(False, reason=f'{sim_info} is not currently spawned. They need to be spawned before all of their perks can be locked.') - perk = cls.load_perk_by_guid(perk) - if perk is None: - return CommonTestResult(False, reason=f'Failed to locate perk by id {perk}') - bucks_type = cls.get_perk_bucks_type(perk) - if bucks_type is None: - return CommonTestResult(False, reason=f'Bucks Type {bucks_type} was not valid.') - bucks_tracker: BucksTrackerBase = cls.get_bucks_tracker(sim_info, bucks_type, add_if_none=True) - if bucks_tracker is None: - return CommonTestResult(False, reason=f'{sim_info} does not have a tracker for the specified bucks. {bucks_type}') - if not bucks_tracker.is_perk_unlocked(perk): - return CommonTestResult(True, reason=f'{sim_info} has perk {perk} locked.') - return CommonTestResult(False, reason=f'{sim_info} does not have perk {perk} locked.') - - @classmethod - def lock_perk(cls, sim_info: SimInfo, perk: Union[BucksPerk, int], refund_cost: bool = True) -> CommonExecutionResult: - """lock_perk(sim_info, perk, refund_cost=True) - - Lock a perk for a Sim. - - .. note:: A Sim needs to be spawned before their perks can be locked. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param perk: The perk to lock. - :type perk: Union[BucksPerk, int] - :param refund_cost: Set True to refund the cost of the perk. Set False to give no perk points back. Default is True - :type refund_cost: bool, optional - :return: The result of executing the function. True, if successful. False, if not. - :rtype: CommonExecutionResult - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return CommonExecutionResult(False, reason=f'{sim_info} is not currently spawned. They need to be spawned before all of their perks can be locked.') - perk = cls.load_perk_by_guid(perk) - if perk is None: - return CommonExecutionResult(False, reason=f'Failed to locate perk by id {perk}') - bucks_type = cls.get_perk_bucks_type(perk) - if bucks_type is None: - return CommonExecutionResult(False, reason=f'Bucks Type {bucks_type} was not valid.') - bucks_tracker: BucksTrackerBase = cls.get_bucks_tracker(sim_info, bucks_type, add_if_none=True) - if bucks_tracker is None: - return CommonExecutionResult(False, reason=f'{sim_info} does not have a tracker for the specified bucks. {bucks_type}') - bucks_tracker.lock_perk(perk, refund_cost=refund_cost) - return CommonExecutionResult.TRUE - - @classmethod - def unlock_perk(cls, sim_info: SimInfo, perk: Union[BucksPerk, int], no_cost: bool = False) -> CommonExecutionResult: - """unlock_perk(sim_info, perk, no_cost=True) - - Unlock a perk. - - .. note:: A Sim needs to be spawned before their perks can be unlocked. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param perk: The perk to lock. - :type perk: Union[BucksPerk, int] - :param no_cost: Set True to unlock the perk without spending perk points. Set False to spend perk points to unlock the perk.. Default is False - :type no_cost: bool, optional - :return: The result of executing the function. True, if successful. False, if not. - :rtype: CommonExecutionResult - """ - if cls.has_perk_unlocked(sim_info, perk): - return CommonExecutionResult(True, reason=f'Perk {perk} is already unlocked.') - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return CommonExecutionResult(False, reason=f'{sim_info} is not currently spawned. They need to be spawned before all of their perks can be locked.') - perk = cls.load_perk_by_guid(perk) - if perk is None: - return CommonExecutionResult(False, reason=f'Failed to locate perk by id {perk}') - bucks_type = cls.get_perk_bucks_type(perk) - if bucks_type is None: - return CommonExecutionResult(False, reason=f'Bucks Type {bucks_type} was not valid.') - bucks_tracker: BucksTrackerBase = cls.get_bucks_tracker(sim_info, bucks_type, add_if_none=True) - if bucks_tracker is None: - return CommonExecutionResult(False, reason=f'{sim_info} does not have a tracker for the specified bucks. {bucks_type}') - if cls.has_perk_unlocked(sim_info, perk): - return CommonExecutionResult(True, reason=f'Perk {perk} is already unlocked.') - modified_for_cost = False - if no_cost: - if not cls.can_afford_perk(sim_info, perk): - unlock_cost = cls.get_perk_unlock_cost(perk) - modify_result = cls.modify_bucks(sim_info, bucks_type, unlock_cost, reason='Perk being unlocked at no cost.') - if not modify_result: - return modify_result - modified_for_cost = True - elif not cls.can_afford_perk(sim_info, perk): - return CommonExecutionResult(False, reason=f'{sim_info} cannot afford perk {perk}.') - if bucks_tracker.pay_for_and_unlock_perk(perk): - if not modified_for_cost: - unlock_cost = cls.get_perk_unlock_cost(perk) - modify_result = cls.modify_bucks(sim_info, bucks_type, unlock_cost, reason='Perk being unlocked at no cost.') - if not modify_result: - return modify_result - return CommonExecutionResult.TRUE - - @classmethod - def can_afford_perk(cls, sim_info: SimInfo, perk: Union[BucksPerk, int]) -> CommonTestResult: - """can_afford_perk(sim_info, perk) - - Determine if a Sim can afford to purchase a perk. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param perk: The perk to check. - :type perk: Union[BucksPerk, int] - :return: The result of the test. True, if the perk can be afforded by the Sim. False, if not. - :rtype: CommonTestResult - """ - perk = cls.load_perk_by_guid(perk) - if perk is None: - return CommonTestResult(False, reason=f'Failed to locate perk by id {perk}') - bucks_type = cls.get_perk_bucks_type(perk) - if bucks_type == CommonBucksType.INVALID: - return CommonTestResult(False, reason=f'Failed to determine the bucks type of the perk {perk}') - bucks_tracker: BucksTrackerBase = cls.get_bucks_tracker(sim_info, bucks_type, add_if_none=False) - if bucks_tracker is None: - return CommonTestResult(False, reason=f'{sim_info} does not have a tracker for the specified bucks. {bucks_type}') - bucks_amount = cls.get_bucks_amount(sim_info, bucks_type) - perk_cost = cls.get_perk_unlock_cost(perk) - if bucks_amount < perk_cost: - return CommonTestResult(False, reason=f'{sim_info} cannot afford perk {perk}.') - return CommonTestResult(True, reason=f'{sim_info} can afford perk {perk}.') - - @classmethod - def get_available_perks_gen(cls, sim_info: SimInfo, bucks_type: Union[CommonBucksType, BucksType]) -> Iterator[BucksPerk]: - """get_available_perks_gen(sim_info, bucks_type) - - Retrieve all available Perks for the specified Bucks Type and Sim. - - .. note:: A Sim needs to be spawned before perks can be checked. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param bucks_type: The Bucks associated with the perks being returned. - :type bucks_type: Union[CommonBucksType, BucksType] - :return: An iterator of Bucks Perks available to a Sim, regardless of locked status. - :rtype: Iterator[BucksPerk] - """ - vanilla_bucks_type = CommonBucksType.convert_to_vanilla(bucks_type) - if vanilla_bucks_type is None: - return tuple() - bucks_tracker: BucksTrackerBase = cls.get_bucks_tracker(sim_info, bucks_type, add_if_none=True) - if bucks_tracker is None: - return tuple() - yield from bucks_tracker.all_perks_of_type_gen(vanilla_bucks_type) - - @classmethod - def get_locked_perks_gen(cls, sim_info: SimInfo, bucks_type: Union[CommonBucksType, BucksType]) -> Iterator[BucksPerk]: - """get_locked_perks_gen(sim_info, bucks_type) - - Retrieve all Perks for the specified Bucks Type a Sim has locked. - - .. note:: A Sim needs to be spawned before perks can be checked. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param bucks_type: The Bucks associated with the perks being returned. - :type bucks_type: Union[CommonBucksType, BucksType] - :return: An iterator of Bucks Perks that are locked for a Sim. - :rtype: Iterator[BucksPerk] - """ - vanilla_bucks_type = CommonBucksType.convert_to_vanilla(bucks_type) - if vanilla_bucks_type is None: - return tuple() - bucks_tracker: BucksTrackerBase = cls.get_bucks_tracker(sim_info, bucks_type, add_if_none=True) - if bucks_tracker is None: - return tuple() - yield from bucks_tracker.all_perks_of_type_with_lock_state_gen(vanilla_bucks_type, True) - - @classmethod - def get_unlocked_perks_gen(cls, sim_info: SimInfo, bucks_type: Union[CommonBucksType, BucksType]) -> Iterator[BucksPerk]: - """get_unlocked_perks_gen(sim_info, bucks_type) - - Retrieve all Perks for the specified Bucks Type a Sim has unlocked. - - .. note:: A Sim needs to be spawned before perks can be checked. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param bucks_type: The Bucks associated with the perks being returned. - :type bucks_type: Union[CommonBucksType, BucksType] - :return: An iterator of Bucks Perks that are unlocked for a Sim. - :rtype: Iterator[BucksPerk] - """ - vanilla_bucks_type = CommonBucksType.convert_to_vanilla(bucks_type) - if vanilla_bucks_type is None: - return tuple() - bucks_tracker: BucksTrackerBase = cls.get_bucks_tracker(sim_info, bucks_type, add_if_none=True) - if bucks_tracker is None: - return tuple() - yield from bucks_tracker.all_perks_of_type_with_lock_state_gen(vanilla_bucks_type, False) - - @classmethod - def get_bucks_amount(cls, sim_info: SimInfo, bucks_type: Union[CommonBucksType, BucksType]) -> int: - """get_bucks_amount(sim_info, bucks_type) - - Retrieve the number of available bucks to a Sim. - - .. note:: A Sim needs to be spawned before bucks can be checked. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param bucks_type: The Bucks associated with the amount to return. - :type bucks_type: Union[CommonBucksType, BucksType] - :return: The number of available bucks to a Sim for the specified Bucks Type or 0 if the Sim is not spawned, the bucks type does not exist, or a bucks tracker is not found. - :rtype: int - """ - vanilla_bucks_type = CommonBucksType.convert_to_vanilla(bucks_type) - if vanilla_bucks_type is None: - return 0 - bucks_tracker: BucksTrackerBase = cls.get_bucks_tracker(sim_info, bucks_type, add_if_none=False) - if bucks_tracker is None: - return 0 - return bucks_tracker.get_bucks_amount_for_type(vanilla_bucks_type) - - @classmethod - def modify_bucks(cls, sim_info: SimInfo, bucks_type: Union[CommonBucksType, BucksType], amount: int, reason: str = None, **__) -> CommonExecutionResult: - """modify_bucks(sim_info, bucks_type, amount, reason=None, **__) - - Modify the number of points available for a specific Bucks Type. - - .. note:: A Sim needs to be spawned before their Bucks can be modified. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param bucks_type: The Bucks associated with the perk points. - :type bucks_type: Union[CommonBucksType, BucksType] - :param amount: The amount of points that will be added/removed from the Sim. - :type amount: int - :param reason: The reason the perk points are being modified. Default is None. - :type reason: str, optional - :return: The result of executing the function. True, if successful. False, if not. - :rtype: CommonExecutionResult - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return CommonExecutionResult(False, reason=f'{sim_info} is not currently spawned. They need to be spawned before their perk points can be modified.') - vanilla_bucks_type = CommonBucksType.convert_to_vanilla(bucks_type) - if vanilla_bucks_type is None: - return CommonExecutionResult(False, reason=f'Bucks Type {bucks_type} was not valid.') - bucks_tracker: BucksTrackerBase = cls.get_bucks_tracker(sim_info, bucks_type, add_if_none=True) - if bucks_tracker is None: - return CommonExecutionResult(False, reason=f'{sim_info} does not have a tracker for the specified bucks. {bucks_type}') - current_bucks_count = cls.get_bucks_amount(sim_info, bucks_type) - if amount < 0 and ((amount * -1) > current_bucks_count): - amount = -current_bucks_count - bucks_tracker.try_modify_bucks(vanilla_bucks_type, amount, reason=reason, **__) - return CommonExecutionResult.TRUE - - @classmethod - def set_bucks(cls, sim_info: SimInfo, bucks_type: Union[CommonBucksType, BucksType], amount: int, reason: str = None, **__) -> CommonExecutionResult: - """set_bucks(sim_info, bucks_type, amount, reason=None, **__) - - Set the amount of Bucks available to a Sim. - - .. note:: A Sim needs to be spawned before their Bucks can be modified. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param bucks_type: The Bucks associated with the perk points. - :type bucks_type: Union[CommonBucksType, BucksType] - :param amount: The amount of points that will be available to the Sim. The value should be at or above zero. - :type amount: int - :param reason: The reason the perk points are being modified. Default is None. - :type reason: str, optional - :return: The result of executing the function. True, if successful. False, if not. - :rtype: CommonExecutionResult - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return CommonExecutionResult(False, reason=f'{sim_info} is not currently spawned. They need to be spawned before their perk points can be modified.') - vanilla_bucks_type = CommonBucksType.convert_to_vanilla(bucks_type) - if vanilla_bucks_type is None: - return CommonExecutionResult(False, reason=f'Bucks Type {bucks_type} was not valid.') - bucks_tracker: BucksTrackerBase = cls.get_bucks_tracker(sim_info, bucks_type, add_if_none=True) - if bucks_tracker is None: - return CommonExecutionResult(False, reason=f'{sim_info} does not have a tracker for the specified bucks. {bucks_type}') - if amount < 0: - amount = 0 - current_bucks_amount = cls.get_bucks_amount(sim_info, bucks_type) - if current_bucks_amount > 0: - bucks_tracker.try_modify_bucks(vanilla_bucks_type, -current_bucks_amount, reason=reason) - bucks_tracker.try_modify_bucks(vanilla_bucks_type, amount, reason=reason, **__) - return CommonExecutionResult.TRUE - - @classmethod - def get_perk_unlock_cost(cls, perk: Union[BucksPerk, int]) -> int: - """get_perk_unlock_cost(sim_info, perk) - - Retrieve the amount of points a perk costs to unlock. - - :param perk: The identifier or instance of a Perk. - :type perk: Union[BucksPerk, int] - :return: The amount of points the perk costs to unlock. - :rtype: int - """ - perk = cls.load_perk_by_guid(perk) - if perk is None: - return 0 - if hasattr(perk, 'unlock_cost'): - return perk.unlock_cost - return 0 - - @classmethod - def get_perk_bucks_type(cls, perk: Union[BucksPerk, int]) -> CommonBucksType: - """get_perk_bucks_type(sim_info, perk) - - Retrieve the Bucks Type associated with a Perk. - - :param perk: The identifier or instance of a Perk. - :type perk: Union[BucksPerk, int] - :return: The type of bucks the perk is associated to. - :rtype: CommonBucksType - """ - perk = cls.load_perk_by_guid(perk) - if perk is None: - return CommonBucksType.INVALID - if hasattr(perk, 'associated_bucks_type'): - return CommonBucksType.convert_from_vanilla(perk.associated_bucks_type) - return CommonBucksType.INVALID - - @classmethod - def get_bucks_tracker(cls, sim_info: SimInfo, bucks_type: Union[CommonBucksType, BucksType], add_if_none: bool = False) -> Union[BucksTrackerBase, None]: - """get_bucks_tracker(sim_info, bucks_type, add_if_none=False) - - Retrieve the tracker on a Sim for a specified bucks type. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param bucks_type: The type of tracker to retrieve. - :type bucks_type: Union[CommonBucksType, BucksType] - :param add_if_none: Set True, to add the tracker to the Sim when it does not exist. Set False to only return the tracker if it exists. Default is False. - :type add_if_none: bool, optional - :return: The tracker on the Sim associated with the specified Bucks Type or None when not found. - :rtype: Union[BucksTrackerBase, None] - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return None - vanilla_bucks_type = CommonBucksType.convert_to_vanilla(bucks_type) - if vanilla_bucks_type is None: - return None - return BucksUtils.get_tracker_for_bucks_type(vanilla_bucks_type, owner_id=sim.id, add_if_none=add_if_none) - - @classmethod - def load_perk_by_guid(cls, perk: Union[int, BucksPerk]) -> Union[BucksPerk, None]: - """load_perk_by_guid(perk) - - Load an instance of a Bucks Perk by its GUID. - - :param perk: The decimal identifier of a Bucks Perk. - :type perk: Union[int, BucksPerk] - :return: An instance of a Bucks Perk matching the decimal identifier or None if not found. - :rtype: Union[BucksPerk, None] - """ - if isinstance(perk, BucksPerk): - return perk - # noinspection PyBroadException - try: - # noinspection PyCallingNonCallable - perk_instance = perk() - if isinstance(perk_instance, BucksPerk): - # noinspection PyTypeChecker - return perk - except: - pass - # noinspection PyBroadException - try: - perk: int = int(perk) - except: - # noinspection PyTypeChecker - perk: BucksPerk = perk - return perk - - from sims4.resources import Types - from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils - return CommonResourceUtils.load_instance(Types.BUCKS_PERK, perk) - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.set_bucks', - 'Set the number of Bucks a Sim has.', - command_arguments=( - CommonConsoleCommandArgument('bucks_type', 'CommonBucksType', 'The type of bucks to modify.'), - CommonConsoleCommandArgument('amount', 'Number', 'The number of Bucks to set. If below zero, this value will become zero.'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Id or Name of a Sim to modify.', - is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.set_perk_points', - ) -) -def _common_set_bucks( - output: CommonConsoleCommandOutput, - bucks_type: CommonBucksType, - amount: int, - sim_info: SimInfo = None -): - output(f'Setting {bucks_type.name} Bucks to {amount} for Sim {sim_info}') - result = CommonSimBucksUtils.set_bucks(sim_info, bucks_type, amount, reason='S4CL Console Command') - if result: - output(f'Successfully set {bucks_type.name} Bucks to {amount} for Sim {sim_info}') - else: - output(f'Failed to set {bucks_type.name} Bucks {amount} for Sim {sim_info}. Reason: {result.reason}') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.add_bucks', - 'Add Bucks to a Sim.', - command_arguments=( - CommonConsoleCommandArgument('bucks_type', 'CommonBucksType', 'The type of bucks to modify.'), - CommonConsoleCommandArgument('amount', 'Number', 'The number of Bucks to add.'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Id or Name of a Sim to modify.', - is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.add_perk_points', - ) -) -def _common_add_bucks( - output: CommonConsoleCommandOutput, - bucks_type: CommonBucksType, - amount: int, - sim_info: SimInfo = None -): - if bucks_type is None: - return False - output(f'Adding {amount} {bucks_type.name} Bucks to Sim {sim_info}') - result = CommonSimBucksUtils.modify_bucks(sim_info, bucks_type, amount, reason='S4CL Console Command') - if result: - output(f'Successfully added {amount} {bucks_type.name} Bucks to Sim {sim_info}') - else: - output(f'Failed to add {amount} {bucks_type.name} Bucks to Sim {sim_info}. Reason: {result.reason}') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.remove_bucks', - 'Add Bucks from a Sim.', - command_arguments=( - CommonConsoleCommandArgument('bucks_type', 'CommonBucksType', 'The type of bucks to modify.'), - CommonConsoleCommandArgument('amount', 'Number', 'The number of Bucks to remove.'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Id or Name of a Sim to modify.', - is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.remove_perk_points', - ) -) -def _common_remove_bucks( - output: CommonConsoleCommandOutput, - bucks_type: CommonBucksType, - amount: int, - sim_info: SimInfo = None -): - if bucks_type is None: - return False - output(f'Removing {amount} {bucks_type.name} Bucks from Sim {sim_info}') - result = CommonSimBucksUtils.modify_bucks(sim_info, bucks_type, -amount, reason='S4CL Console Command') - if result: - output(f'Successfully removed {amount} {bucks_type.name} Bucks from Sim {sim_info}') - else: - output(f'Failed to remove {amount} {bucks_type.name} Bucks from Sim {sim_info}. Reason: {result.reason}') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.unlock_perk', - 'Unlock a Bucks perk for a Sim.', - command_arguments=( - CommonConsoleCommandArgument('perk', 'Perk Id or Tuning Name', 'The decimal identifier or name of a perk to unlock.'), - CommonConsoleCommandArgument('no_cost', 'True or False', 'If True, the perk will be unlocked for free. If False, the perk will be unlocked using points (The Sim must have enough points).', is_optional=True, default_value=True), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Id or Name of a Sim to modify.', - is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.add_perk', - ) -) -def _common_add_perks( - output: CommonConsoleCommandOutput, - perk: TunableInstanceParam(Types.BUCKS_PERK), - no_cost: bool = True, - sim_info: SimInfo = None -): - if isinstance(perk, str): - output(f'No perk found for {perk}') - return False - cost_text = ' at No Cost' if no_cost else '' - output(f'Unlocking perk {perk} for Sim {sim_info}{cost_text}.') - result = CommonSimBucksUtils.unlock_perk(sim_info, perk, no_cost=no_cost) - if result: - output(f'Successfully unlocked perk {perk} for Sim {sim_info}.') - else: - output(f'Failed to unlock perk {perk} for Sim {sim_info}. Reason: {result.reason}') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.lock_perk', - 'Lock a Bucks Perk for a Sim.', - command_arguments=( - CommonConsoleCommandArgument('perk', 'Perk Id or Tuning Name', - 'The decimal identifier or name of a perk to lock.'), - CommonConsoleCommandArgument('refund_cost', 'True or False', - 'If True, the cost to unlock the perk will be refunded to the Sim. If False, the cost of to unlock the perk will not be refunded.', - is_optional=True, default_value=True), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Id or Name of a Sim to modify.', - is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.remove_perk', - ) -) -def _common_remove_perk( - output: CommonConsoleCommandOutput, - perk: TunableInstanceParam(Types.BUCKS_PERK), - refund_cost: bool = True, - sim_info: SimInfo = None -): - if isinstance(perk, str): - output(f'No perk found for {perk}') - return False - cost_text = ' at No Cost' if refund_cost else '' - output(f'Unlocking perk {perk} for Sim {sim_info}{cost_text}.') - result = CommonSimBucksUtils.lock_perk(sim_info, perk, refund_cost=refund_cost) - if result: - output(f'Successfully unlocked perk {perk} for Sim {sim_info}.') - else: - output(f'Failed to unlock perk {perk} for Sim {sim_info}. Reason: {result.reason}') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.lock_all_perks', - 'Lock all Bucks Perk for a Sim.', - command_arguments=( - CommonConsoleCommandArgument('bucks_type', 'CommonBucksType', 'The type of bucks to remove the perks of.'), - CommonConsoleCommandArgument('refund_cost', 'True or False', - 'If True, the cost to unlock the perks will be refunded to the Sim. If False, the cost of to unlock the perks will not be refunded.', - is_optional=True, default_value=True), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Id or Name of a Sim to modify.', - is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.remove_all_perks', - ) -) -def _common_remove_all_perks( - output: CommonConsoleCommandOutput, - bucks_type: CommonBucksType, - refund_cost: bool = True, - sim_info: SimInfo = None -): - if bucks_type is None: - return False - cost_text = ' and refunding the Cost' if refund_cost else '' - output(f'Locking all perks for Sim {sim_info}{cost_text}.') - result = CommonSimBucksUtils.remove_all_perks(sim_info, bucks_type, refund_cost=refund_cost) - if result: - output(f'Successfully locked all {bucks_type.name} perk for Sim {sim_info}.') - else: - output(f'Failed to lock all {bucks_type.name} perks for Sim {sim_info}. Reason: {result.reason}') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.unlock_all_perks', - 'Unlock all Bucks Perk for a Sim.', - command_arguments=( - CommonConsoleCommandArgument('bucks_type', 'CommonBucksType', 'The type of bucks to add the perks of.'), - CommonConsoleCommandArgument('no_cost', 'True or False', 'If True, the perk will be unlocked for free. If False, the perk will be unlocked using points (The Sim must have enough points).', is_optional=True, default_value=True), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Id or Name of a Sim to modify.', - is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.add_all_perks', - ) -) -def _common_add_all_perks( - output: CommonConsoleCommandOutput, - bucks_type: CommonBucksType, - no_cost: bool = True, - sim_info: SimInfo = None -): - if bucks_type is None: - return False - cost_text = ' at No Cost' if no_cost else '' - output(f'Unlocking all {bucks_type.name} perks for Sim {sim_info}{cost_text}.') - result = CommonSimBucksUtils.add_all_perks(sim_info, bucks_type, no_cost=no_cost) - if result: - output(f'Successfully unlocked all {bucks_type.name} perks for Sim {sim_info}.') - else: - output(f'Failed to unlock all {bucks_type.name} perks for Sim {sim_info}. Reason: {result.reason}') diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_career_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_career_utils.py deleted file mode 100644 index 93c4567..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_career_utils.py +++ /dev/null @@ -1,965 +0,0 @@ -""" -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 -""" -import random -from typing import Union, Callable, Iterator, Tuple - -import services -from careers.career_enums import CareerShiftType, CareerCategory -from careers.career_event import CareerEvent -from careers.career_history import CareerHistory -from careers.career_tracker import CareerTracker -from careers.career_tuning import Career, CareerLevel, TunableCareerTrack -from event_testing.resolver import SingleSimResolver -from rewards.reward_enums import RewardType -from server_commands.argument_helpers import TunableInstanceParam -from sims.sim_info import SimInfo -from sims4.resources import Types -from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ - CommonConsoleCommandArgument -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.common_time_utils import CommonTimeUtils -from s4ap.sims4communitylib.utils.location.common_location_utils import CommonLocationUtils -from s4ap.sims4communitylib.utils.sims.common_career_track_utils import CommonCareerTrackUtils -from s4ap.sims4communitylib.utils.sims.common_career_utils import CommonCareerUtils -from s4ap.sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils -from s4ap.sims4communitylib.utils.sims.common_sim_type_utils import CommonSimTypeUtils -from s4ap.sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils -from singletons import DEFAULT - - -class CommonSimCareerUtils(_HasS4CLClassLog): - """ Utilities for manipulating the Careers of Sims. """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 'common_sim_career_utils' - - @classmethod - def get_career_by_category(cls, sim_info: SimInfo, career_category: CareerCategory) -> Union[Career, None]: - """get_career_by_category(sim_info, career_category) - - Retrieve the career of a Sim by its career category. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param career_category: The category to retrieve the career of. - :type career_category: CareerCategory - :return: A career matching the career category specified or None if not found. - :rtype: Union[Career, None] - """ - career_tracker = cls.get_career_tracker(sim_info) - if career_tracker is None: - return None - return next(career_tracker.get_careers_by_category_gen(career_category)) - - @classmethod - def get_all_careers_for_sim_gen(cls, sim_info: SimInfo, include_career_callback: Callable[[Career], bool]=None) -> Iterator[Career]: - """get_all_careers_for_sim_gen(sim_info, include_career_callback=None) - - Retrieve all Careers of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param include_career_callback: If the result of this callback is True, the Career of the Sim will be included in the results. If set to None, All Careers of the Sim will be included. Default is None. - :type include_career_callback: Callable[[Career], bool], optional - :return: An iterator of all Careers matching the `include_career_callback` filter. - :rtype: Iterator[Career] - """ - if sim_info is None: - return tuple() - career_tracker = cls.get_career_tracker(sim_info) - if career_tracker is None: - return tuple() - for career in career_tracker.careers.values(): - if include_career_callback is not None and not include_career_callback(career): - continue - yield career - - @classmethod - def has_career(cls, sim_info: SimInfo, career_identifier: Union[int, Career]) -> bool: - """has_career_by_guid(sim_info, career) - - Determine if a Sim has a Career. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param career_identifier: The Guid64 identifier of a Career, the decimal identifier of a Career, or a Career instance. - :type career_identifier: Union[int, Career] - :return: True, if the Sim has the specified Career. False, if not. - :rtype: bool - """ - return cls.get_career(sim_info, career_identifier) is not None - - @classmethod - def get_career(cls, sim_info: SimInfo, career_identifier: Union[int, Career]) -> Union[Career, None]: - """get_career(sim_info, career_identifier) - - Retrieve the Career of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param career_identifier: The Guid64 identifier of a Career, the decimal identifier of a Career, or a Career instance. - :type career_identifier: Union[int, Career] - :return: The career of the Sim that matches the identifier or None if not found. - :rtype: Union[Career, None] - """ - if sim_info is None or career_identifier is None: - return None - if not isinstance(career_identifier, Career): - cls.get_log().format_with_message('Identifier was not a Career instance. Attempting to load it now.', career_identifier=career_identifier) - career_identifier = CommonCareerUtils.load_career_by_guid(career_identifier) - career_guid = CommonCareerUtils.get_career_guid(career_identifier) - career_id = CommonCareerUtils.get_career_id(career_identifier) - if career_guid is None and career_id is None: - return None - cls.get_log().format_with_message('Checking for career info.', career_identifier=career_identifier, career_guid=career_guid, career_id=career_id) - career_tracker = cls.get_career_tracker(sim_info) - if career_tracker is None: - return None - for career in cls.get_all_careers_for_sim_gen(sim_info): - if (career_guid is not None and career_guid != -1 and CommonCareerUtils.get_career_guid(career) == career_guid)\ - or (career_id is not None and career_id != -1 and CommonCareerUtils.get_career_id(career) == career_id)\ - or career is career_identifier: - cls.get_log().format_with_message('Successfully found career.', career=career, career_identifier=career_identifier, career_guid=career_guid, career_id=career_id, checked_career_guid=CommonCareerUtils.get_career_guid(career), checked_career_id=CommonCareerUtils.get_career_id(career)) - return career - cls.get_log().format_with_message('Failed to locate career.', career_identifier=career_identifier, career_guid=career_guid, career_id=career_id) - return None - - @classmethod - def has_career_at_current_zone(cls, sim_info: SimInfo) -> bool: - """has_career_at_current_zone(sim_info) - - Determine if a Sim has a Career at the current zone. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: True, if the Sim has a Career at the current zone. False, if not. - :rtype: bool - """ - return cls.get_career_at_current_zone(sim_info) - - @classmethod - def get_career_at_current_zone(cls, sim_info: SimInfo) -> Union[Career, None]: - """get_career_at_current_zone(sim_info) - - Retrieve the Career of a Sim that has its location set to the current zone. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: True, if the Sim works at the current zone. False, if not. - :rtype: bool - """ - if sim_info is None: - return None - current_zone_id = CommonLocationUtils.get_current_zone_id() - for career in cls.get_all_careers_for_sim_gen(sim_info): - career_zone_id = CommonCareerUtils.get_career_location_zone_id(career) - if career_zone_id == 0: - continue - if career_zone_id == current_zone_id: - return career - return None - - @classmethod - def is_at_work(cls, sim_info: SimInfo) -> bool: - """is_at_work(sim_info) - - Determine if a Sim is currently at work. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: True, if the Sim is currently at work for any of their careers. False, if not. - :rtype: bool - """ - for career in cls.get_all_careers_for_sim_gen(sim_info): - if career.currently_at_work: - return True - return False - - @classmethod - def has_career_tracker(cls, sim_info: SimInfo) -> bool: - """has_career_tracker(sim_info) - - Determine if a Sim has a career tracker or not. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: True, if the Sim has a career tracker. False, if not. - :rtype: bool - """ - return cls.get_career_tracker(sim_info) is not None - - @classmethod - def get_career_tracker(cls, sim_info: SimInfo) -> Union[CareerTracker, None]: - """get_career_tracker(sim_info) - - Retrieve a career tracker for a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The career tracker of the Sim or None if not found. - :rtype: Union[CareerTracker, None] - """ - if sim_info is None: - return None - # noinspection PyTypeChecker - return sim_info.career_tracker - - @classmethod - def is_taking_part_in_active_career_event(cls, sim_info: SimInfo) -> bool: - """is_taking_part_in_active_career_event(sim_info) - - Determine if a Sim is taking part in an active career event. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: True, if the Sim is taking part in an active career event. False, if not. - :rtype: bool - """ - if sim_info is None: - return False - return any(career.is_at_active_event for career in sim_info.careers.values()) - - @classmethod - def is_sim_household_part_of_active_career_event(cls, sim_info: SimInfo) -> bool: - """is_household_part_of_active_career_event(sim_info) - - Determine if any members of a Sims Household are part of an active career event. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: True, if any members of the Sims Household are taking part in an active career event. False, if not. - :rtype: bool - """ - if sim_info is None: - return False - household = CommonHouseholdUtils.get_household(sim_info) - for sim_info in CommonHouseholdUtils.get_sim_info_of_all_sims_in_household_generator(household): - if cls.is_taking_part_in_active_career_event(sim_info): - return True - return False - - @classmethod - def attend_career(cls, career: Career, allow_career_events: bool=True) -> CommonExecutionResult: - """attend_career(career, allow_career_events=True) - - Start a career without running any career events (If they are an active career). - - :param career: The career to mark. - :type career: Career - :param allow_career_events: If True, a career event will be started for active careers. If False, a career event will not be started for active careers. No effect on non active careers. Default is True. - :rtype: allow_career_events: bool, optional - :return: Tbe result of the action. - :rtype: CommonExecutionResult - """ - if allow_career_events and career.is_active: - return cls.start_active_career_on_current_lot(career) - - if services.get_persistence_service().is_save_locked(): - return CommonExecutionResult(False, reason='Currently save locked.') - if not services.get_career_service().enabled: - return CommonExecutionResult(False, reason='Career service is not enabled.') - from date_and_time import create_time_span - start_time = CommonTimeUtils.get_current_date_and_time() - end_time = start_time + create_time_span(hours=10) - - if start_time > end_time: - return CommonExecutionResult(False, reason='Start time is greater than end time.') - - career._at_work = False - career._career_session_extended = False - gig = career.get_current_gig() - if gig is not None: - gig.prep_time_end() - - career._current_work_start = start_time - career._current_work_end = end_time - career._current_work_duration = career._current_work_end - career._current_work_start - career._create_work_session_alarms() - career.resend_at_work_info() - if gig is None or gig.odd_job_tuning is None: - tracker = career._sim_info.get_tracker(career.WORK_SESSION_PERFORMANCE_CHANGE) - if tracker is not None: - career._sim_info.add_statistic(career.WORK_SESSION_PERFORMANCE_CHANGE, career.WORK_SESSION_PERFORMANCE_CHANGE.initial_value) - - if career.is_school_career and not career._sim_info.is_npc: - career.reset_homework_help() - - career.active_days_worked_statistic.add_value(1) - career.resend_at_work_info() - career.attend_work(start_tones=False) - from careers.career_base import TELEMETRY_WORKDAY_TYPE_ACTIVE - career._send_workday_info_telemetry(TELEMETRY_WORKDAY_TYPE_ACTIVE) - return CommonExecutionResult.TRUE - - @classmethod - def start_active_career_on_current_lot(cls, career: Career, career_event: CareerEvent=None) -> CommonExecutionResult: - """start_active_career_on_current_lot(career, career_event=None) - - Start a career event on the current lot for an Active career. - - .. note:: This function only works if the Career is flagged as an Active Career (is_active in the Tuning). - - :param career: The career to begin. - :type career: Career - :param career_event: The career event to trigger. If set to None, a random career event will be chosen from the career. Default is None. - :type career_event: CareerEvent, optional - :return: Tbe result of the action. - :rtype: CommonExecutionResult - """ - if career is None: - raise AssertionError('career was None.') - if not career.is_active: - return CommonExecutionResult(False, reason='Career is not an active career.') - if services.get_persistence_service().is_save_locked(): - return CommonExecutionResult(False, reason='Currently save locked.') - if not services.get_career_service().enabled: - return CommonExecutionResult(False, reason='Career service is not enabled.') - from date_and_time import create_time_span - start_time = CommonTimeUtils.get_current_date_and_time() - end_time = start_time + create_time_span(hours=10) - - if start_time > end_time: - return CommonExecutionResult(False, reason='Start time is greater than end time.') - - career._at_work = False - career._career_session_extended = False - gig = career.get_current_gig() - if gig is not None: - gig.prep_time_end() - - career._current_work_start = start_time - career._current_work_end = end_time - career._current_work_duration = career._current_work_end - career._current_work_start - career._create_work_session_alarms() - career.resend_at_work_info() - if gig is None or gig.odd_job_tuning is None: - tracker = career._sim_info.get_tracker(career.WORK_SESSION_PERFORMANCE_CHANGE) - if tracker is not None: - career._sim_info.add_statistic(career.WORK_SESSION_PERFORMANCE_CHANGE, career.WORK_SESSION_PERFORMANCE_CHANGE.initial_value) - if career.is_school_career and not career._sim_info.is_npc: - career.reset_homework_help() - - if career._sim_info.is_npc: - return CommonExecutionResult(False, reason='Sim is an NPC, NPCs are not allowed to start active careers.') - - import careers.career_base - current_gig = career.get_current_gig() - if career_event is None: - if career._sim_info in careers.career_base._career_event_overrides: - career_event = careers.career_base._career_event_overrides.pop(career._sim_info) - elif current_gig is not None and current_gig.career_events: - career_event = current_gig.get_random_gig_event() - else: - career._prune_stale_career_event_cooldowns() - resolver = SingleSimResolver(career._sim_info) - available_events = tuple(event for event in career.career_events if career.is_career_event_on_cooldown(event) or event.tests.run_tests(resolver)) - if not available_events: - return CommonExecutionResult(False, reason='No events were available.') - household = career._sim_info.household - for sim_info in household.sim_info_gen(): - if cls.is_taking_part_in_active_career_event(sim_info): - return CommonExecutionResult(False, reason='Sim is already at the active event.') - career_event = random.choice(available_events) - - career.on_career_event_accepted(career_event) - return CommonExecutionResult.TRUE - - @classmethod - def randomize_career( - cls, - sim_info: SimInfo, - randomize_career_level: bool = True, - remove_all_existing_careers: bool = True, - randomize_agency: bool = True, - use_career_history: bool = True, - force_out_of_retirement: bool = True, - force_quit_previous_jobs: bool = True, - check_availability: bool = True - ) -> CommonExecutionResult: - """set_random_career(\ - sim_info,\ - choose_random_career_level=True,\ - remove_all_existing_careers=True,\ - randomize_agent=True,\ - use_career_history=True,\ - force_out_of_retirement=False,\ - force_quit_previous_jobs=False,\ - check_availability=True\ - ) - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param randomize_career_level: If True, a random Career Level will be chosen in addition to the Career. If False, the Career Level will be dictated by the Sim that is joining. Default is True. - :type randomize_career_level: bool, optional - :param remove_all_existing_careers: If True, all careers the Sim is currently a part of will be removed. If False, the existing careers of the Sim will not be removed. Default is False. - :type remove_all_existing_careers: bool, optional - :param randomize_agency: If True, a random agency from available agencies will be randomly chosen for a Career that has agencies upon being added. If False, the "Select An Agency" dialog will appear. Default is True. - :type randomize_agency: bool, optional - :param force_out_of_retirement: If True, the Sim will be forced out of retirement without prompting the player. If False, a dialog will prompt the player to choose whether or not to come out of retirement. Default is False. - :type force_out_of_retirement: bool, optional - :param force_quit_previous_jobs: If True, the Sim will be forced to quit all of their previous jobs. If False, a confirmation will display that will prompt the player whether this should happen or not. Default is False. - :type force_quit_previous_jobs: bool, optional - :param use_career_history: If True, then the career history of the Sim will be used when adding the Career. If False, then the career history of the Sim will not be used when adding the Career. Default is True. - :type use_career_history: bool, optional - :param check_availability: If True, every career will be checked for availability before becoming available. If False, every career regardless of availability will be selectable. Default is True. WARNING: A Career that is not allowed for a Sim may be chosen if this is set to False! - :type check_availability: bool, optional - :return: The result of setting their career. - :rtype: CommonExecutionResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - if remove_all_existing_careers: - cls.remove_careers(sim_info) - - def _career_is_available(_career: Career) -> bool: - if not check_availability: - return True - return bool(cls.is_career_available_for_sim(sim_info, _career, from_join=True)) - - all_careers = tuple(CommonCareerUtils.get_all_careers_generator(include_career_callback=_career_is_available)) - if not all_careers: - return CommonExecutionResult(False, reason='No careers found to be available for Sim.') - cls.get_log().format_with_message('Found all available careers.', careers=sorted([f'{career.__name__} ({CommonCareerUtils.get_career_guid(career)})' for career in all_careers], key=lambda x: x)) - chosen_career = random.choice(all_careers) - career_level = None - if randomize_career_level: - career_levels = CommonCareerUtils.get_career_levels(chosen_career) - if career_levels: - career_level = random.choice(career_levels) - result = cls.add_career(sim_info, chosen_career, randomize_agency=randomize_agency, career_level=career_level, use_career_history=use_career_history, force_out_of_retirement=force_out_of_retirement, force_quit_previous_jobs=force_quit_previous_jobs) - if not result: - return result - return CommonExecutionResult(True, reason=f'{chosen_career.__name__}') - - @classmethod - def is_career_available_for_sim(cls, sim_info: SimInfo, career: Career, from_join: bool=False) -> CommonTestResult: - """is_career_available_for_sim(sim_info, career, from_join=False) - - Determine if a Career is available for a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param career: A career. - :type career: Career - :param from_join: Use to flag whether the career is planned to be tested as though the Sim is joining it. Default is False. - :type from_join: bool, optional - :return: The result of testing for availability. True, if the Career is available for the specified Sim. False, if not. - :rtype: CommonTestResult - """ - # noinspection PyTypeChecker - non_playable_career_ids: Tuple[int] = ( - 223698, # University_BaseCareer - 231099, # career_Batuu - 207004, # career_OddJob - 209979, # university_CourseSlot_A - 209984, # university_CourseSlot_B - 209988, # university_CourseSlot_C - 209989, # university_CourseSlot_D - 260893, # careers_VillagerHelp - 206791, # careers_Adult_Freelancer_No_Agency - ) - # noinspection PyTypeChecker - allowed_non_displayed_career_ids: Tuple[int] = ( - 205686, # career_Adult_Freelancer_Artist - 207568, # careers_Adult_Freelancer_Agency_Programmer - 207579, # careers_Adult_Freelancer_Agency_Writer - 214782, # careers_Adult_Freelancer_Agency_Fashion_Photographer - 232809, # careers_Adult_Freelancer_Agency_Maker - 252593, # careers_Adult_Freelancer_Agency_ParanormalInvestigator - ) - if not CommonSimTypeUtils.is_non_player_sim(sim_info): - if 'npc' in career.__name__.lower(): - return CommonTestResult(False, reason='The Career is an NPC career and the Sim is not an NPC.') - career_guid = CommonCareerUtils.get_career_guid(career) - if career_guid in non_playable_career_ids: - return CommonTestResult(False, reason='Career is non playable.') - valid_result = career.is_valid_career(sim_info=sim_info, from_join=from_join) - if not valid_result: - return valid_result - if career_guid not in allowed_non_displayed_career_ids: - if from_join and not career.show_career_in_join_career_picker: - return CommonTestResult(False, reason='Career is not joinable through normal means.') - return CommonTestResult.TRUE - - @classmethod - def add_career( - cls, - sim_info: SimInfo, - career_identifier: Union[int, Career], - remove_all_existing_careers: bool = False, - randomize_agency: bool = True, - use_career_history: bool = True, - force_out_of_retirement: bool = False, - force_quit_previous_jobs: bool = False, - show_confirmation_dialog: bool = False, - user_level: int = None, - career_level: CareerLevel = None, - give_skipped_rewards: bool = True, - defer_rewards: bool = False, - show_post_quit_message: bool = True, - schedule_shift_override: CareerShiftType = CareerShiftType.ALL_DAY, - show_join_message: bool = True, - disallowed_reward_types: Tuple[RewardType] = (), - force_rewards_to_sim_info_inventory: bool = False, - defer_first_assignment: bool = False, - schedule_init_only: bool = False, - allow_outfit_generation: bool = True - ) -> CommonExecutionResult: - """add_career(\ - sim_info,\ - career_identifier,\ - remove_all_existing_careers=False,\ - randomize_agency=True,\ - use_career_history=True,\ - force_out_of_retirement=False,\ - force_quit_previous_jobs=False,\ - show_confirmation_dialog=False,\ - user_level=None,\ - career_level=None,\ - give_skipped_rewards=True,\ - defer_rewards=False,\ - show_post_quit_message=True,\ - schedule_shift_override=CareerShiftType.ALL_DAY,\ - show_join_message=True,\ - disallowed_reward_types=(),\ - force_rewards_to_sim_info_inventory=False,\ - defer_first_assignment=False,\ - schedule_init_only=False,\ - allow_outfit_generation=True\ - ) - - Add a Career to a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param career_identifier: The Guid64 identifier of a Career, the decimal identifier of a Career, or a Career instance. - :type career_identifier: Union[int, Career] - :param remove_all_existing_careers: If True, all careers the Sim is currently a part of will be removed. If False, the existing careers of the Sim will not be removed. Default is False. - :type remove_all_existing_careers: bool, optional - :param randomize_agency: If True, a random agency from available agencies will be randomly chosen for a Career that has agencies upon being added. If False, the "Select An Agency" dialog will appear. Default is True. - :type randomize_agency: bool, optional - :param use_career_history: If True, then the career history of the Sim will be used when adding the Career. If False, then the career history of the Sim will not be used when adding the Career. Default is True. - :type use_career_history: bool, optional - :param force_out_of_retirement: If True, the Sim will be forced out of retirement without prompting the player. If False, a dialog will prompt the player to choose whether or not to come out of retirement. Default is False. - :type force_out_of_retirement: bool, optional - :param force_quit_previous_jobs: If True, the Sim will be forced to quit all of their previous jobs. If False, a confirmation will display that will prompt the player whether this should happen or not. Default is False. - :type force_quit_previous_jobs: bool, optional - :param show_confirmation_dialog: Show Confirmation Dialog. Default is False. - :type show_confirmation_dialog: bool, optional - :param user_level: The level of the career track to assign to the Sim upon joining the career. Default is None. - :type user_level: int, optional - :param career_level: The Career Level to set the Sim to upon joining the career. Default is None. - :type career_level: CareerLevel, optional - :param give_skipped_rewards: If True, any rewards skipped due to the career level skips will be given to the Sim upon joining the career. If False, no rewards will be given for career levels before the one they join into. Default is True. - :type give_skipped_rewards: bool, optional - :param defer_rewards: If True, rewards will be deferred until later. If False, rewards will be given immediately. Default is False. - :type defer_rewards: bool, optional - :param show_post_quit_message: If True, the quit message for their existing career before switching will be displayed. If False, the quit message will not be displayed. Default is True. - :type show_post_quit_message: bool, optional - :param schedule_shift_override: An override for the Sims shift schedule. Default is CareerShiftType.ALL_DAY. - :type schedule_shift_override: CareerShiftType, optional - :param show_join_message: If True, the joined career message will be displayed after joining the career. If False, the join message will not be displayed. Default is True. - :type show_join_message: bool, optional - :param disallowed_reward_types: A collection of rewards types not allowed to be collected by the Sim that is joining. If empty, all rewards will be allowed to be rewarded. Default is empty. - :type disallowed_reward_types: Tuple[RewardType], optional - :param force_rewards_to_sim_info_inventory: If True, rewards will be forced in the inventory of the joining Sim. If False, rewards will be sent to their intended locations as specified by the career. Default is False. - :type force_rewards_to_sim_info_inventory: bool, optional - :param defer_first_assignment: If True, the first assignment upon joining the career will be delayed until later. If False, the first assignment will not be delayed. Default is False. - :type defer_first_assignment: bool, optional - :param schedule_init_only: If True, Shift schedule will only be initialized. If False, Shift schedule will be setup fully. Default is False. - :type schedule_init_only: bool, optional - :param allow_outfit_generation: If True, an outfit for the career will be generated upon join. If False, an outfit will not be generated. Default is True. - :type allow_outfit_generation: bool, optional - :return: The result of adding the Career or the reason why it was not properly added. - :rtype: CommonExecutionResult - """ - if sim_info is None or career_identifier is None: - return CommonExecutionResult(False, reason=f'Sim or Career Identifier was None Sim: {sim_info} ID: {career_identifier}.') - if remove_all_existing_careers: - cls.remove_careers(sim_info) - career = CommonCareerUtils.load_career_by_guid(career_identifier) - career_tracker = cls.get_career_tracker(sim_info) - if career_tracker is None: - return CommonExecutionResult(False, reason=f'The Sim did not have a career tracker. {sim_info}') - if career_tracker.has_career_by_uid(CommonCareerUtils.get_career_guid(career)): - cls.get_log().format_with_message('Sim already had the specified career.', sim=sim_info, career=career) - return CommonExecutionResult.TRUE - - picked_track: Union[TunableCareerTrack, None] = None - if career_level is None and user_level is not None: - (career_level_index, _, picked_track) = CommonCareerUtils.determine_entry_level_into_career_from_user_level(career, user_level) - picked_track: TunableCareerTrack = picked_track - career_level = CommonCareerTrackUtils.get_career_level_by_index(picked_track, career_level_index) - elif career_level is None: - entry_level_values = tuple(cls.determine_entry_level_into_career_for_sim(sim_info, career, use_career_history=use_career_history)) - cls.get_log().format_with_message('Got entry level values', entry_level_values=entry_level_values) - if len(entry_level_values) == 1: - entry_level_values = entry_level_values[0] - (career_level_index, _, picked_track) = entry_level_values - picked_track: TunableCareerTrack = picked_track - career_level = CommonCareerTrackUtils.get_career_level_by_index(picked_track, career_level_index) - cls.get_log().format_with_message('Got career level.', career_level=career_level_index, returned_user_level=_, picked_track=picked_track) - - if career_level is None: - cls.get_log().format_with_message('No career level found.', sim=sim_info, career_history=career_tracker.career_history, career=career) - return CommonExecutionResult(False, reason=f'Failed to locate career level for Sim {sim_info}, Career {career}, and Career History {career_tracker.career_history}.') - - cls.get_log().format_with_message('Adding new career.', picked_track=picked_track, career_level=career_level, sim=sim_info, career=career) - new_career = career_level.career(sim_info) - return cls._add_career( - career_tracker, - new_career, - randomize_agency=randomize_agency, - use_career_history=use_career_history, - force_out_of_retirement=force_out_of_retirement, - force_quit_previous_jobs=force_quit_previous_jobs, - show_confirmation_dialog=show_confirmation_dialog, - user_level_override=user_level, - career_level_override=career_level, - give_skipped_rewards=give_skipped_rewards, - defer_rewards=defer_rewards, - post_quit_msg=show_post_quit_message, - schedule_shift_override=schedule_shift_override, - show_join_msg=show_join_message, - disallowed_reward_types=disallowed_reward_types, - force_rewards_to_sim_info_inventory=force_rewards_to_sim_info_inventory, - defer_first_assignment=defer_first_assignment, - schedule_init_only=schedule_init_only, - allow_outfit_generation=allow_outfit_generation - ) - - @classmethod - def _add_career( - cls, - career_tracker: CareerTracker, - new_career: Career, - randomize_agency: bool = True, - use_career_history: bool = True, - force_out_of_retirement: bool = False, - force_quit_previous_jobs: bool = False, - show_confirmation_dialog = False, - user_level_override: int = None, - career_level_override: CareerLevel = None, - give_skipped_rewards: bool = True, - defer_rewards: bool = False, - post_quit_msg: bool = True, - schedule_shift_override = CareerShiftType.ALL_DAY, - show_join_msg: bool = True, - disallowed_reward_types: Tuple[RewardType] = (), - force_rewards_to_sim_info_inventory: bool = False, - defer_first_assignment: bool = False, - schedule_init_only: bool = False, - allow_outfit_generation: bool = True - ) -> CommonExecutionResult: - if show_confirmation_dialog: - (level, _, track) = new_career.get_career_entry_data(career_history=career_tracker._career_history, user_level_override=user_level_override, career_level_override=career_level_override) - career_level_tuning = CommonCareerTrackUtils.get_career_level_by_index(track, level) - if career_tracker._retirement is not None: - def _on_unretire_confirmation_dialog_response(dialog, _disallowed_reward_types: Tuple[RewardType]=disallowed_reward_types) -> None: - if not dialog.accepted: - return - cls._add_career( - career_tracker, - new_career, - randomize_agency=randomize_agency, - use_career_history=use_career_history, - force_out_of_retirement=True, - force_quit_previous_jobs=force_quit_previous_jobs, - show_confirmation_dialog=show_confirmation_dialog, - user_level_override=user_level_override, - career_level_override=career_level_override, - give_skipped_rewards=give_skipped_rewards, - defer_rewards=defer_rewards, - post_quit_msg=post_quit_msg, - schedule_shift_override=schedule_shift_override, - show_join_msg=show_join_msg, - disallowed_reward_types=_disallowed_reward_types, - force_rewards_to_sim_info_inventory=force_rewards_to_sim_info_inventory, - defer_first_assignment=defer_first_assignment, - schedule_init_only=schedule_init_only, - allow_outfit_generation=allow_outfit_generation - ) - - if not force_out_of_retirement: - career_tracker._retirement.send_dialog(Career.UNRETIRE_DIALOG, career_level_tuning.get_title(career_tracker._sim_info), icon_override=DEFAULT, on_response=lambda dialog: _on_unretire_confirmation_dialog_response(dialog)) - cls.get_log().format_with_message('Sim is retired.') - return CommonExecutionResult(False, reason='Sim was retired.') - - if new_career.can_quit: - def _on_quit_confirmation_dialog_response(dialog, _disallowed_reward_types: Tuple[RewardType]=disallowed_reward_types) -> None: - if not dialog.accepted: - return - cls._add_career( - career_tracker, - new_career, - randomize_agency=randomize_agency, - use_career_history=use_career_history, - force_out_of_retirement=force_out_of_retirement, - force_quit_previous_jobs=True, - show_confirmation_dialog=show_confirmation_dialog, - user_level_override=user_level_override, - career_level_override=career_level_override, - give_skipped_rewards=give_skipped_rewards, - defer_rewards=defer_rewards, - post_quit_msg=post_quit_msg, - schedule_shift_override=schedule_shift_override, - show_join_msg=show_join_msg, - disallowed_reward_types=_disallowed_reward_types, - force_rewards_to_sim_info_inventory=force_rewards_to_sim_info_inventory, - defer_first_assignment=defer_first_assignment, - schedule_init_only=schedule_init_only, - allow_outfit_generation=allow_outfit_generation - ) - - quittable_careers = career_tracker.get_quittable_careers(schedule_shift_type=schedule_shift_override) - if quittable_careers and not force_quit_previous_jobs: - career = next(iter(quittable_careers.values())) - switch_jobs_dialog = Career.SWITCH_JOBS_DIALOG - if len(quittable_careers) > 1: - switch_jobs_dialog = Career.SWITCH_MANY_JOBS_DIALOG - career.send_career_message(switch_jobs_dialog, career_level_tuning.get_title(career_tracker._sim_info), icon_override=DEFAULT, on_response=lambda dialog: _on_quit_confirmation_dialog_response(dialog, _disallowed_reward_types=(RewardType.MONEY,))) - cls.get_log().format_with_message('Sim has quittable careers. Too many jobs!') - return CommonExecutionResult(False, reason='Sim had existing jobs, they need to be quit before.') - - cls.get_log().format_with_message('Doing end retirement.') - career_tracker.end_retirement() - career_tracker.remove_custom_career_data(send_update=False) - if new_career.guid64 in career_tracker._careers: - cls.get_log().format_with_message('Attempting to add career that Sim is already in.', career=new_career, sim=career_tracker._sim_info) - return CommonExecutionResult(False, reason='Sim already had the career.') - if new_career.can_quit: - career_tracker.quit_quittable_careers(post_quit_msg=post_quit_msg, schedule_shift_type=schedule_shift_override) - career_tracker._careers[new_career.guid64] = new_career - result = cls._join_career( - new_career, - randomize_agency=randomize_agency, - career_history=career_tracker._career_history if use_career_history else None, - user_level_override=user_level_override, - career_level_override=career_level_override, - give_skipped_rewards=give_skipped_rewards, - defer_rewards=defer_rewards, - schedule_shift_override=schedule_shift_override, - show_join_msg=show_join_msg, - disallowed_reward_types=disallowed_reward_types, - force_rewards_to_sim_info_inventory=force_rewards_to_sim_info_inventory, - defer_first_assignment=defer_first_assignment, - schedule_init_only=schedule_init_only, - allow_outfit_generation=allow_outfit_generation - ) - if not result: - return result - career_tracker.resend_career_data() - career_tracker.update_affordance_caches() - if career_tracker._on_promoted not in new_career.on_promoted: - new_career.on_promoted.append(career_tracker._on_promoted) - if career_tracker._on_demoted not in new_career.on_demoted: - new_career.on_demoted.append(career_tracker._on_demoted) - return CommonExecutionResult.TRUE - - @classmethod - def remove_careers( - cls, - sim_info: SimInfo, - show_post_quit_message: bool = False, - update_ui_after_remove: bool = True, - include_career_callback: Callable[[Career], bool] = None - ) -> None: - """remove_careers(\ - sim_info,\ - show_post_quit_message=False,\ - update_ui_after_remove=True,\ - include_career_callback=None\ - ) - - Remove Careers of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param show_post_quit_message: If True, the post quit message will show for each removed Career. If False, no post quit message will show for each removed Career. Default is False. - :type show_post_quit_message: bool, optional - :param update_ui_after_remove: If True, the UI will be updated after the Career is removed. If False, the UI will not be updated. Default is True. - :type update_ui_after_remove: bool, optional - :param include_career_callback: If the result of this callback is True, the Career of the Sim will be removed. If set to None, All Careers of the Sim will be removed. Default is None. - :type include_career_callback: Callable[[Career], bool], optional - """ - career_tracker = cls.get_career_tracker(sim_info) - if career_tracker is None: - return - to_remove_career_uids = list() - for (career_uid, career) in career_tracker.careers.items(): - if include_career_callback is not None and not include_career_callback(career): - continue - to_remove_career_uids.append(career_uid) - - for career_uid in to_remove_career_uids: - career_tracker.remove_career(career_uid, post_quit_msg=show_post_quit_message, update_ui=update_ui_after_remove) - - @classmethod - def _join_career( - cls, - career: Career, - randomize_agency: bool = True, - career_history: CareerHistory = None, - user_level_override: int = None, - career_level_override: int = None, - give_skipped_rewards: bool = True, - defer_rewards: bool = False, - schedule_shift_override: CareerShiftType = CareerShiftType.ALL_DAY, - show_join_msg: bool = True, - disallowed_reward_types: Tuple[RewardType] = (), - force_rewards_to_sim_info_inventory: bool = False, - defer_first_assignment: bool = False, - schedule_init_only: bool = False, - allow_outfit_generation: bool = True - ) -> CommonExecutionResult: - (new_level, new_user_level, current_track) = career.get_career_entry_data(career_history=career_history, user_level_override=user_level_override, career_level_override=career_level_override) - if defer_rewards: - career.defer_player_rewards() - career._current_track = current_track - career._join_time = services.time_service().sim_now - career._level = new_level - career._user_level = new_user_level - career._current_shift_type = schedule_shift_override - if career_history is not None: - career._load_days_worked_commodities(career_history, current_track) - career._reset_career_objectives(career._current_track, new_level) - starting_level = career._sim_info.career_tracker.get_highest_level_reached(career.guid64) - career._sim_info.career_tracker.update_history(career) - career.career_start(schedule_init_only=schedule_init_only, allow_outfit_generation=allow_outfit_generation) - career._setup_assignments_for_career_joined(defer_assignment=defer_first_assignment) - resolver = SingleSimResolver(career._sim_info) - for loot in career.current_level_tuning.loot_on_join: - if randomize_agency: - loot_guid = getattr(loot, 'guid64', None) - if loot_guid is None: - continue - # loot_Buff_ActorCareer_NewJob - if loot_guid == 192996: - agents_available = tuple(career.current_level_tuning.agents_available) - if agents_available: - chosen_agent = random.choice(agents_available) - if CommonTraitUtils.add_trait(career.sim_info, CommonTraitUtils.get_trait_id(chosen_agent)): - continue - loot.apply_to_resolver(resolver) - if give_skipped_rewards: - career._give_rewards_for_skipped_levels(starting_level=starting_level, disallowed_reward_types=disallowed_reward_types, force_rewards_to_sim_info_inventory=force_rewards_to_sim_info_inventory) - from careers.career_base import TELEMETRY_HOOK_CAREER_START - career._send_telemetry(TELEMETRY_HOOK_CAREER_START) - join_career_notification = career.career_messages.join_career_notification - if show_join_msg and career.display_career_info and join_career_notification is not None: - (_, first_work_time, _) = career.get_next_work_time() - career.send_career_message(join_career_notification, first_work_time) - career.add_coworker_relationship_bit() - career._add_career_knowledge() - return CommonExecutionResult.TRUE - - @classmethod - def determine_entry_level_into_career_for_sim( - cls, - sim_info: SimInfo, - career: Career, - use_career_history: bool = True - ) -> Tuple[Union[int, None], Union[int, None], Union[TunableCareerTrack, None]]: - """determine_entry_level_into_career_for_sim(sim_info, career, use_career_history=True) - - Determine the entry level into a Career for a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param career: The career to retrieve an entry level of. - :type career: Career - :param use_career_history: If True, then the career history of the Sim will be used when adding the Career. If False, then the career history of the Sim will not be used when adding the Career. Default is True. - :type use_career_history: bool, optional - :return: The career level for the career track (or branch career track) used, the level of the user in that career track, and the career track itself. - :rtype: Tuple[int, int, TunableCareerTrack] - """ - if sim_info is None: - return None, None, None - if use_career_history: - career_tracker = cls.get_career_tracker(sim_info) - if career_tracker is None: - return None, None, None - career_history = career_tracker.career_history - else: - career_history = None - return career.get_career_entry_level(career_history=career_history, resolver=SingleSimResolver(sim_info)) - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.has_career', - 'Check if a Sim has a career.', - command_arguments=( - CommonConsoleCommandArgument('career', 'Name or Decimal Id', 'The name or id of a career to check.'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of a Sim.', is_optional=True, default_value='Active Sim'), - ) -) -def _common_has_career(output: CommonConsoleCommandOutput, career: TunableInstanceParam(Types.CAREER), sim_info: SimInfo=None): - if sim_info is None: - return - output(f'Checking {sim_info} to see if they have career {career}') - if career is None: - output(f'Failed, Career does not exist.') - return False - if CommonSimCareerUtils.has_career(sim_info, career): - output(f'SUCCESS: Sim has the career.') - else: - output(f'FAILED: Sim does not have the career.') - return True - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.add_career', - 'Add a career to a Sim.', - command_arguments=( - CommonConsoleCommandArgument('career', 'Name or Decimal Id', 'The name or id of a career to add.'), - CommonConsoleCommandArgument('user_level', 'Number', 'The Career Level to put the Sim into for the Career.', is_optional=True, default_value='Starting Level'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of a Sim.', is_optional=True, default_value='Active Sim'), - ) -) -def _common_add_career(output: CommonConsoleCommandOutput, career: TunableInstanceParam(Types.CAREER), user_level: int=None, sim_info: SimInfo=None): - if sim_info is None: - return - output(f'Attempting to add career {career}') - if career is None: - output(f'Failed, Career does not exist.') - return False - output('Adding career') - result = CommonSimCareerUtils.add_career(sim_info, career, user_level=user_level, randomize_agency=True, use_career_history=False, show_confirmation_dialog=False) - if result: - output(f'SUCCESS: Career added.') - else: - output(f'FAILED: Failed to add career. {result.reason}') - return True - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.randomize_career', - 'Give a random career to a Sim.', - command_arguments=( - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of a Sim.', is_optional=True, default_value='Active Sim'), - ) -) -def _common_randomize_career(output: CommonConsoleCommandOutput, sim_info: SimInfo=None): - if sim_info is None: - return - output(f'Attempting to randomize career for Sim {sim_info}') - result = CommonSimCareerUtils.randomize_career(sim_info, remove_all_existing_careers=True, randomize_agency=True, use_career_history=False) - if result: - output(f'SUCCESS: Career randomized to {result.reason}') - else: - output(f'FAILED: Failed to randomize career. {result.reason}') - return True diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_club_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_club_utils.py deleted file mode 100644 index 6c5fead..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_club_utils.py +++ /dev/null @@ -1,126 +0,0 @@ -""" -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 -""" -from typing import Iterator, Callable, Union - -import services -from clubs.club import Club -from clubs.club_gathering_situation import ClubGatheringSituation -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - - -class CommonSimClubUtils: - """ Utilities for manipulating the Clubs of Sims. """ - - @staticmethod - def is_engaged_in_club_gathering(sim_info: SimInfo) -> bool: - """is_engaged_in_club_gathering(sim_info) - - Determine if a Sim is engaged in a Club Gathering. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: True, if the Sim is engaged in a Club Gathering. False, if not. - :rtype: bool - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return False - club_service = services.get_club_service() - if club_service is None: - return False - return sim in club_service.sims_to_gatherings_map - - @staticmethod - def get_current_club_gathering(sim_info: SimInfo) -> Union[ClubGatheringSituation, None]: - """get_current_club_gathering(sim_info) - - Retrieve the Club Gathering a Sim is currently taking part in. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The Club Gathering the specified Sim is a part of or None if the Sim is not a part of any Club Gathering. - :rtype: Union[ClubGatheringSituation, None] - """ - if sim_info is None: - return None - club_service = services.get_club_service() - if club_service is None: - return None - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return None - return club_service.sims_to_gatherings_map.get(sim) - - @staticmethod - def get_clubs_gen(sim_info: SimInfo, include_club_callback: Callable[[Club], bool] = CommonFunctionUtils.noop_true) -> Iterator[Club]: - """get_clubs_gen(sim_info, include_club_callback=CommonFunctionUtils.noop_true) - - Retrieve all Clubs a Sim is a part of. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param include_club_callback: If the result of this callback is True, the Club will be included in the results. The default callback will allow all. - :type include_club_callback: Callable[[Club], bool], optional - :return: An iterator of all Clubs the specified Sim is a part of and that pass the include callback filter. - :rtype: Iterator[Club] - """ - if sim_info is None: - return tuple() - club_service = services.get_club_service() - if club_service is None: - return tuple() - for club in club_service.get_clubs_for_sim_info(sim_info): - if club is None or not include_club_callback(club): - continue - yield club - - @staticmethod - def get_clubs_currently_gathering_gen(sim_info: SimInfo, include_club_callback: Callable[[Club], bool] = CommonFunctionUtils.noop_true) -> Iterator[Club]: - """get_clubs_currently_gathering_gen(include_club_callback=CommonFunctionUtils.noop_true) - - Retrieve all Clubs the Sim is in that are currently hosting a gathering. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param include_club_callback: If the result of this callback is True, the Club will be included in the results. The default callback will allow all. - :type include_club_callback: Callable[[Club], bool], optional - :return: An iterator of all Clubs the Sim is in that are currently gathering and that pass the include_club_callback filter. - :rtype: Iterator[Club] - """ - if sim_info is None: - return tuple() - club_service = services.get_club_service() - if club_service is None: - return tuple() - sim_clubs = club_service.get_clubs_for_sim_info(sim_info) - for club in sim_clubs: - club_gathering = club_service.clubs_to_gatherings_map.get(club) - if club_gathering is None or not include_club_callback(club): - continue - yield club - - @staticmethod - def are_part_of_same_club_gathering(sim_info_a: SimInfo, sim_info_b: SimInfo) -> bool: - """are_part_of_same_club_gathering(sim_info_a, sim_info_b) - - Determine if two Sims are at the same Club Gathering - - :param sim_info_a: An instance of a Sim. - :type sim_info_a: SimInfo - :param sim_info_b: An instance of a Sim. - :type sim_info_b: SimInfo - :return: True, if Sim A is taking part in the same Club Gathering as Sim B. False, if not. - :rtype: bool - """ - sim_a_club_gathering = CommonSimClubUtils.get_current_club_gathering(sim_info_a) - sim_b_club_gathering = CommonSimClubUtils.get_current_club_gathering(sim_info_b) - if sim_a_club_gathering is None or sim_b_club_gathering is None: - return False - return sim_a_club_gathering == sim_b_club_gathering diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_crafting_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_crafting_utils.py deleted file mode 100644 index bd20294..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_crafting_utils.py +++ /dev/null @@ -1,104 +0,0 @@ -""" -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 -""" -from random import Random -from typing import Union, Callable - -from objects.game_object import GameObject -from sims.sim import Sim -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.enums.common_object_quality import CommonObjectQuality -from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils -from s4ap.sims4communitylib.utils.objects.common_object_state_utils import CommonObjectStateUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - - -class CommonSimCraftingUtils: - """ Utilities for crafting various things. """ - @staticmethod - def create_from_recipe( - crafting_sim_info: SimInfo, - recipe_id: int, - inventory_target: Union[GameObject, Sim] = None, - set_target_as_owner: bool = True, - quality: CommonObjectQuality = None, - owning_household_id_override: int = None, - post_add: Callable[[GameObject], None] = None, - seeded_random: Random = None - ) -> Union[GameObject, None]: - """create_from_recipe(\ - crafting_sim_info,\ - recipe_id,\ - inventory_target=None,\ - set_target_as_owner=True,\ - owning_household_id_override=None,\ - post_add=None,\ - seeded_random=None,\ - ) - - Craft an item made by a Sim using a recipe and placing it in the inventory of an object or a Sim. - - .. note:: inventory_target must have an inventory_component attribute. - - :param crafting_sim_info: The name of this Sim will appear on the crafted object as being the crafter. - :type crafting_sim_info: SimInfo - :param recipe_id: The decimal identifier of a recipe for the object being created. - :type recipe_id: int - :param inventory_target: If set, the crafted object will be placed in the inventory of this object. If not set, the crafted object will be placed in the inventory of the Sim that crafted it. Default is None. - :type inventory_target: Union[GameObject, Sim] - :param set_target_as_owner: If True, the inventory where the crafted item will be placed will become the owner of the crafted item. If False, the crafted item will be owned by the one who created it. Default is True. - :type set_target_as_owner: bool, optional - :param owning_household_id_override: An override for which household to set as the owner of the crafted object. If not specified, then the crafting Sim will be the owner. If set_target_as_owner is True, then the target will be the owner regardless of what this argument is set to. Default is None. - :type owning_household_id_override: int, optional - :param post_add: A callback invoked when the object is created. Default is None. - :type post_add: Callable[[GameObject], None], optional - :param seeded_random: An instance of Random that will be used in various aspects of the created object. Default is None. - :type seeded_random: Random, optional - :param quality: The quality of the output object. Default is None. - :type quality: CommonObjectQuality, optional - :return: The crafted item, created from the specified recipe by the specified Sim, or None if an error occurs. - :rtype: Union[GameObject, None] - """ - if inventory_target is not None and not hasattr(inventory_target, 'inventory_component'): - raise AttributeError('The specified inventory_target did not have an inventory component.') - crafting_sim = CommonSimUtils.get_sim_instance(crafting_sim_info) - if crafting_sim is None: - return None - from s4ap.sims4communitylib.utils.resources.common_recipe_utils import CommonRecipeUtils - recipe = CommonRecipeUtils.load_recipe_by_guid(recipe_id) - try: - from crafting.crafting_interactions import create_craftable - from s4ap.sims4communitylib.utils.objects.common_object_ownership_utils import CommonObjectOwnershipUtils - from s4ap.sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils - quality_state = CommonObjectStateUtils.convert_quality_to_object_state_value(quality) - if set_target_as_owner: - if CommonTypeUtils.is_sim_or_sim_info(inventory_target): - owning_sim_info = CommonSimUtils.get_sim_info(inventory_target) if inventory_target is not None else crafting_sim_info - owning_household_id_override = CommonHouseholdUtils.get_household_id(owning_sim_info) - elif inventory_target is not None: - owning_household_id_override = CommonObjectOwnershipUtils.get_owning_household_id(inventory_target) - crafted_item = create_craftable( - recipe, - crafting_sim, - inventory_owner=inventory_target, - place_in_inventory=True, - quality=quality_state, - owning_household_id_override=owning_household_id_override, - post_add=post_add, - seeded_random=seeded_random - ) - if crafted_item is not None: - if set_target_as_owner: - if CommonTypeUtils.is_sim_or_sim_info(inventory_target): - owning_sim_info = CommonSimUtils.get_sim_info(inventory_target) if inventory_target is not None else crafting_sim_info - CommonObjectOwnershipUtils.set_owning_sim(crafted_item, owning_sim_info) - elif inventory_target is not None: - owning_household_id = CommonObjectOwnershipUtils.get_owning_household_id(inventory_target) - CommonObjectOwnershipUtils.set_owning_household_id(crafted_item, owning_household_id) - return crafted_item - except ImportError: - return None diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_currency_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_currency_utils.py deleted file mode 100644 index d53965c..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_currency_utils.py +++ /dev/null @@ -1,140 +0,0 @@ -""" -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 -""" -from typing import Union - -from sims.funds import FamilyFunds -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from s4ap.sims4communitylib.enums.common_currency_modify_reasons import CommonCurrencyModifyReason -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ - CommonConsoleCommandArgument -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput - - -class CommonSimCurrencyUtils: - """Utilities for modifying various currency types of Sims. - - """ - @classmethod - def can_afford_simoleons(cls, sim_info: SimInfo, amount: int) -> bool: - """can_afford_simoleons(sim_info, amount) - - Determine if a Sim can afford an amount of simoleons. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param amount: The amount of simoleons to check. - :type amount: int - :return: True, if the household of the Sim can afford the simoleon amount. False, if not. - :rtype: bool - """ - household_funds = cls.get_household_funds(sim_info) - if household_funds is None: - return False - return household_funds.can_afford(amount) - - @classmethod - def add_simoleons_to_household(cls, sim_info: SimInfo, amount: int, reason: CommonCurrencyModifyReason, **kwargs) -> CommonExecutionResult: - """add_simoleons_to_household(sim_info, amount, reason, **kwargs) - - Add an amount of simoleons to the Household of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param amount: The amount of simoleons to add. - :type amount: int - :param reason: The reason the simoleons are being added. - :type reason: CommonCurrencyModifyReason - :return: True, if simoleons were added successfully. False, if not. - :rtype: bool - """ - household_funds = cls.get_household_funds(sim_info) - if household_funds is None: - return CommonExecutionResult(False, reason='The Sim was not a part of a household that has funds.') - household_funds.add(amount, reason, **kwargs) - return CommonExecutionResult.TRUE - - @classmethod - def remove_simoleons_from_household(cls, sim_info: SimInfo, amount: int, reason: CommonCurrencyModifyReason, require_full_amount: bool=True, **kwargs) -> float: - """remove_simoleons_from_household(sim_info, amount, reason, require_full_amount=True, **kwargs) - - Remove an amount of simoleons from the Household of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param amount: The amount of simoleons to add. - :type amount: int - :param reason: The reason the simoleons are being removed. - :type reason: CommonCurrencyModifyReason - :param require_full_amount: If True, then the Sim must have the full amount for the removal to be successful. If False, the Sim does not require the full amount. Default is True. - :type require_full_amount: bool, optional - :return: The amount of simoleons removed from the household of the specified Sim. This amount may be lower than the specified amount, if the Sim did not have enough simoleons for removal. - :rtype: float - """ - household_funds = cls.get_household_funds(sim_info) - if household_funds is None: - return 0.0 - return household_funds.try_remove_amount(amount, reason, require_full_amount=require_full_amount, **kwargs) - - @classmethod - def get_household_funds(cls, sim_info: SimInfo) -> Union[FamilyFunds, None]: - """get_household_funds(sim_info) - - Retrieve the Funds object that manages the Household Simoleons for the Household of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The FamilyFunds object of the Household of the specified Sim or None if the Sim did not have a Household. - :rtype: Union[FamilyFunds, None] - """ - from s4ap.sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils - household = CommonHouseholdUtils.get_household(sim_info) - if household is None: - return None - return household.funds - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.add_simoleons', - 'Add simoleons to a household.', - command_arguments=( - CommonConsoleCommandArgument('amount', 'Number', 'The amount of money to add to the household.'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of a Sim.', is_optional=True, default_value='Active Sim'), - ) -) -def _common_add_simoleons(output: CommonConsoleCommandOutput, amount: int, sim_info: SimInfo=None): - if sim_info is None: - return False - result = CommonSimCurrencyUtils.add_simoleons_to_household(sim_info, amount, CommonCurrencyModifyReason.CHEAT) - if result: - output(f'SUCCESS: Successfully added currency to Sim {sim_info}') - return True - output(f'FAILED: Failed to add currency to Sim {sim_info}. {result.reason}') - return False - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.remove_simoleons', - 'Remove simoleons from a household.', - command_arguments=( - CommonConsoleCommandArgument('amount', 'Number', 'The amount of money to remove from the household.'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of a Sim.', is_optional=True, default_value='Active Sim'), - ) -) -def _common_add_simoleons(output: CommonConsoleCommandOutput, amount: int, sim_info: SimInfo=None): - if sim_info is None: - return False - result = CommonSimCurrencyUtils.add_simoleons_to_household(sim_info, amount, CommonCurrencyModifyReason.CHEAT) - if result: - output(f'SUCCESS: Successfully removed currency from Sim {sim_info}') - return True - output(f'FAILED: Failed to remove currency from Sim {sim_info}. {result.reason}') - return False diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_death_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_death_utils.py deleted file mode 100644 index 48b2d83..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_death_utils.py +++ /dev/null @@ -1,472 +0,0 @@ -""" -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 -""" -import random -from typing import Union, Callable, Iterator, Dict - -from interactions.utils.death import DeathType, DeathTracker -from objects.game_object import GameObject -from sims.ghost import Ghost -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.classes.math.common_location import CommonLocation -from s4ap.sims4communitylib.classes.math.common_transform import CommonTransform -from s4ap.sims4communitylib.classes.math.common_vector3 import CommonVector3 -from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.enums.common_death_types import CommonDeathType -from s4ap.sims4communitylib.enums.common_region_id import CommonRegionId -from s4ap.sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ - CommonConsoleCommandArgument -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from s4ap.sims4communitylib.utils.common_time_utils import CommonTimeUtils -from s4ap.sims4communitylib.utils.location.common_location_utils import CommonLocationUtils -from s4ap.sims4communitylib.utils.objects.common_object_spawn_utils import CommonObjectSpawnUtils -from s4ap.sims4communitylib.utils.objects.common_object_state_utils import CommonObjectStateUtils -from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils -from s4ap.sims4communitylib.utils.resources.common_interaction_utils import CommonInteractionUtils -from s4ap.sims4communitylib.utils.sims.common_buff_utils import CommonBuffUtils -from s4ap.sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils -from s4ap.sims4communitylib.utils.sims.common_occult_utils import CommonOccultUtils -from s4ap.sims4communitylib.utils.sims.common_sim_interaction_utils import CommonSimInteractionUtils -from s4ap.sims4communitylib.utils.sims.common_sim_location_utils import CommonSimLocationUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from s4ap.sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils -from s4ap.sims4communitylib.utils.time.common_alarm_utils import CommonAlarmUtils - - -class CommonSimDeathUtils(_HasS4CLClassLog): - """Utilities for manipulating the body of Sims. - - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 'common_sim_death_utils' - - @classmethod - def is_dead(cls, sim_info: SimInfo) -> CommonTestResult: - """is_dead(sim_info) - - Determine if a Sim is dead. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of the test. True, if it passes. False, if it fails. - :rtype: CommonTestResult - """ - if cls.get_death_type(sim_info) != CommonDeathType.NONE: - return CommonTestResult(True, reason=f'{sim_info} is dead.') - return CommonTestResult(False, reason=f'{sim_info} is not dead.') - - @classmethod - def get_sim_info_for_all_dead_sims_generator( - cls, - death_type: Union[CommonDeathType, DeathType] = None, - include_sim_callback: Callable[[SimInfo], Union[bool, CommonExecutionResult, CommonTestResult]] = None - ) -> Iterator[SimInfo]: - """get_sim_info_for_all_dead_sims_generator(death_type=None, include_sim_callback=None) - - Retrieve a SimInfo object for each and every Dead Sim. - - :param death_type: If specified, only Sims with this type of death will be returned, otherwise all Sims will be returned. - :type death_type: Union[CommonDeathType, DeathType], optional - :param include_sim_callback: If the result of this callback is True, the sim will be included in the results. If set to None, All sims will be included. - :type include_sim_callback: Callable[[SimInfo], bool], optional - :return: An iterator of all Sims matching the `include_sim_callback` filter. - :rtype: Iterator[SimInfo] - """ - if death_type is not None: - death_type = CommonDeathType.convert_from_vanilla(death_type) - - for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(include_sim_callback=include_sim_callback): - if sim_info is None: - continue - is_dead_result = cls.is_dead(sim_info) - if not is_dead_result: - continue - death_tracker = cls.get_death_tracker(sim_info) - if death_tracker is None: - _death_type = None - else: - _death_type = death_tracker.death_type - if death_type is not None and death_type != CommonDeathType.NONE: - sim_death_type = cls.get_death_type(sim_info) - if sim_death_type == CommonDeathType.NONE: - continue - if sim_death_type != death_type: - continue - yield sim_info - - @classmethod - def kill_sim( - cls, - sim_info: SimInfo, - death_type: Union[CommonDeathType, DeathType] - ) -> CommonExecutionResult: - """kill_sim(sim_info, death_type) - - Kill a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param death_type: The type of death to invoke upon the Sim. - :type death_type: Union[CommonDeathType, DeathType] - :return: The result of executing the function. True, if successful. False, if not. - :rtype: CommonExecutionResult - """ - if CommonSimUtils.get_sim_instance(sim_info) is None: - is_off_lot_death = True - else: - is_off_lot_death = False - death_tracker = cls.get_death_tracker(sim_info) - if death_tracker is None: - return CommonExecutionResult(False, reason=f'{sim_info} did not have a death tracker.') - if cls.is_dead(sim_info): - return CommonExecutionResult(True, reason=f'{sim_info} is already dead.') - if death_tracker.is_ghost: - return CommonExecutionResult(False, reason=f'{sim_info} is already a ghost.') - death_type = CommonDeathType.convert_from_vanilla(death_type) - if not is_off_lot_death: - def _on_object_spawned(_death_object: Union[GameObject, None]) -> None: - if _death_object is None: - return - death_interaction_id = cls.get_death_interaction(sim_info, death_type) - if death_interaction_id: - enqueue_result = CommonSimInteractionUtils.queue_interaction(sim_info, death_interaction_id, target=_death_object) - if not enqueue_result: - cls.get_log().format_error_with_message(f'Failed to kill {sim_info} via {death_type.name}.', result=enqueue_result) - else: - cls.get_log().format_with_message('Successfully queued death interaction.', result=enqueue_result) - - death_object = cls._spawn_death_related_object(sim_info, death_type, _on_object_spawned) - if death_object is not None: - def _on_destroy_alarm_triggered(_) -> None: - CommonObjectSpawnUtils.schedule_object_for_destroy(death_object) - - time_until_object_destroy = CommonTimeUtils.create_time_span(hours=1) - CommonAlarmUtils.schedule_alarm(CommonSimDeathUtils, time_until_first_occurrence=time_until_object_destroy, on_alarm_triggered_callback=_on_destroy_alarm_triggered) - return CommonExecutionResult.TRUE - - sim_household = CommonHouseholdUtils.get_household(sim_info) - death_tracker.set_death_type(CommonDeathType.convert_to_vanilla(death_type), is_off_lot_death=is_off_lot_death) - Ghost.make_ghost_if_needed(sim_info) - if sim_household is not None: - CommonHouseholdUtils.move_sim_to_household(sim_info, household_id=CommonHouseholdUtils.get_id(sim_household)) - return CommonExecutionResult.TRUE - - @classmethod - def _spawn_death_related_object(cls, sim_info: SimInfo, death_type: CommonDeathType, on_object_spawned: Callable[[Union[GameObject, None]], None]) -> Union[GameObject, None]: - mapping: Dict[CommonDeathType, int] = { - CommonDeathType.COW_PLANT: 22481, # cowplantGEN_01 - CommonDeathType.MURPHY_BED: 235916, # bedMurphy_SP16GEN_set1 - CommonDeathType.MOTHER_PLANT: 208953, # motherPlant_GP07GEN - } - - chosen_object_definition_id = mapping.get(death_type, None) - - vending_machine_ids = ( - 293171, # object_VendingMachine_HighSchool - 256973, # object_VendingMachine_Gachapon_Default - 256971, # vendingMachine_ColdDrinkAndSnack - 256970, # vendingMachine_HotFoodAndDrink - ) - - if death_type == CommonDeathType.VENDING_MACHINE: - chosen_object_definition_id = random.choice(vending_machine_ids) - - if chosen_object_definition_id is None or chosen_object_definition_id == 0: - on_object_spawned(None) - return None - - def _on_spawned(_game_object: GameObject): - if _game_object is None: - on_object_spawned(None) - return - - if death_type == CommonDeathType.MURPHY_BED: - murphy_bed_open_state = 228113 # murphy_Bed_Values_Open - CommonObjectStateUtils.set_object_state(_game_object, murphy_bed_open_state) - - if death_type == CommonDeathType.COW_PLANT: - cow_plant_mature_state = 32491 # Cowplant_GrowthState_Mature - CommonObjectStateUtils.set_object_state(_game_object, cow_plant_mature_state) - cow_plant_hungry_state = 15231 # Hunger_3_Hungry - CommonObjectStateUtils.set_object_state(_game_object, cow_plant_hungry_state) - CommonBuffUtils.add_buff(sim_info, 12396) # Buff_Drained - on_object_spawned(_game_object) - - location = CommonSimLocationUtils.get_location(sim_info) - loc_transform = location.transform - loc_translation = loc_transform.translation - new_transform = CommonVector3(loc_translation.x + 1, loc_translation.y, loc_translation.z) - spawn_location = CommonLocation(CommonTransform(new_transform, loc_transform.orientation), location.routing_surface) - - spawned_object = CommonObjectSpawnUtils.spawn_object_on_lot(chosen_object_definition_id, spawn_location, post_object_spawned_callback=_on_spawned) - if spawned_object is None: - on_object_spawned(None) - return None - return spawned_object - - @classmethod - def get_death_interaction(cls, sim_info: SimInfo, death_type: CommonDeathType) -> Union[int, None]: - """get_death_interaction(sim_info, death_type) - - Retrieve an appropriate death interaction for the Sim to die by. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param death_type: The type of death slated for the Sim. - :type death_type: CommonDeathType - :return: The decimal identifier of the interaction appropriate for the Sim to play a death animation with or None if not found. - :rtype: int - """ - mapping: Dict[CommonDeathType, int] = { - CommonDeathType.ANGER: 9252, # death_Anger - CommonDeathType.CLIMBING_ROUTE: 250185, # death_ClimbingRoute - CommonDeathType.DEATH_FLOWER_ARRANGEMENT: 190745, # death_ElderExhaustion_DeathFlower - CommonDeathType.ELDER_EXHAUSTION: 9316, # death_ElderExhaustion - CommonDeathType.EMBARRASSMENT: 32314, # death_Embarrassment - CommonDeathType.FIRE: 77372, # death_Fire - CommonDeathType.FLIES: 231091, # death_Flies - CommonDeathType.FROZEN: 182162, # death_Frozen - CommonDeathType.HUNGER: 13299, # death_Hunger - CommonDeathType.KILLER_CHICKEN: 267938, # death_AnimalObjects_Chicken_DeadOnGround - CommonDeathType.KILLER_RABBIT: 259988, # death_AnimalObjects_KillerRabbit - CommonDeathType.LAUGHTER: 9297, # death_Laughter - CommonDeathType.LIGHTNING: 186301, # death_Electrocution_Lightning - CommonDeathType.METEORITE: 286935, # death_Meteorite - CommonDeathType.MOTHER_PLANT: 204098, # death_MotherPlant - CommonDeathType.MURPHY_BED: 231080, # death_MurphyBed_NoLoveseat - CommonDeathType.OVERHEAT: 183022, # death_Overheat - CommonDeathType.POISON: 176190, # death_Poison - CommonDeathType.PUFFERFISH: 143418, # death_Initiator_Pufferfish - CommonDeathType.RODENT_DISEASE: 181916, # death_RodentDisease - CommonDeathType.STEAM: 119504, # death_SteamRoom - # Stink Bomb does not have an associated interaction. - # CommonDeathType.STINK_BOMB: 0, - CommonDeathType.SUN: 151542, # death_Vampire_Sun - # Urban Myth is reserved for Sims that are already a ghost. - # CommonDeathType.URBAN_MYTH: 0, - CommonDeathType.VENDING_MACHINE: 249705, # death_VendingMachine - CommonDeathType.WITCH_OVERLOAD: 216969, # death_WitchOverload - } - - if death_type == CommonDeathType.OLD_AGE: - if CommonSpeciesUtils.is_human(sim_info): - if CommonOccultUtils.is_robot(sim_info): - return 220401 # death_Solo_HumanoidRobot - return 13300 # death_OldAge - elif CommonSpeciesUtils.is_cat(sim_info): - return 159835 # death_OldAge_Cat - elif CommonSpeciesUtils.is_dog(sim_info): - return 159868 # death_OldAge_Dog - elif CommonSpeciesUtils.is_horse(sim_info): - return 321074 # death_OldAge_Horse - else: - return 265869 # death_OldAge_Fox - - if death_type == CommonDeathType.COW_PLANT: - if CommonOccultUtils.is_robot(sim_info): - return 229340 # death_Cowplant_HumanoidRobot - return 13298 # death_Cowplant - - # 220401, # death_Solo_HumanoidRobot - # 132535, # death_Pufferfish_SeatedAtSurface - # 132534, # death_Pufferfish - # 132609, # Death_Pufferfish_Seated - - ocean_drown_id = 211504 # Death_Drowning_Ocean - drown_interaction_ids = ( - 103463, # death_Drown - ocean_drown_id, - ) - if death_type == CommonDeathType.DROWN: - if CommonInteractionUtils.load_interaction_by_id(ocean_drown_id) is None: - return 103463 # death_Drown - return random.choice(drown_interaction_ids) - - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is not None: - if death_type == CommonDeathType.ELECTROCUTION: - if CommonLocationUtils.is_current_region(CommonRegionId.JUNGLE): - return 182673 # death_Electrocution_Jungle - if sim.is_outside: - return 186301 # death_Electrocution_Lightning - if CommonOccultUtils.is_robot(sim_info): - return 228257 # humanoid_Robots_ElectricOverload_Death - return 8650 # death_Electrocution - - # 284361 - # 284362 - # - # 98476 # rescueNeglectedChild - # 155605 # rescueNeglectedToddler - # 103810 # death_Netherworld - return mapping.get(death_type, None) - - @classmethod - def revive_sim(cls, sim_info: SimInfo) -> CommonExecutionResult: - """revive_sim(sim_info) - - Revive a Dead Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of executing the function. True, if successful. False, if not. - :rtype: CommonExecutionResult - """ - death_tracker = cls.get_death_tracker(sim_info) - if death_tracker is None: - return CommonExecutionResult(False, reason=f'{sim_info} did not have a death tracker.') - if death_tracker.death_type is None: - return CommonExecutionResult(True, reason=f'{sim_info} is not dead.') - urn_object_id = Ghost.get_urnstone_for_sim_id(CommonSimUtils.get_sim_id(sim_info)) - death_tracker.clear_death_type() - Ghost.remove_ghost_from_sim(sim_info) - game_object = CommonObjectUtils.get_game_object(urn_object_id) - CommonObjectSpawnUtils.schedule_object_for_destroy(game_object) - return CommonExecutionResult.TRUE - - @classmethod - def get_death_type(cls, sim_info: SimInfo) -> CommonDeathType: - """get_death_type(sim_info) - - Retrieve the type of Death the Sim was faced with. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The type of death the Sim succumbed to or NONE if the Sim is not dead. - :rtype: CommonDeathType - """ - death_tracker = cls.get_death_tracker(sim_info) - if death_tracker is None: - return CommonDeathType.NONE - return CommonDeathType.convert_from_vanilla(death_tracker.death_type) - - @classmethod - def get_death_tracker(cls, sim_info: SimInfo) -> Union[DeathTracker, None]: - """get_death_tracker(sim_info) - - Retrieve the death tracker for a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The death tracker for the Sim or None if not found. - :rtype: Union[DeathTracker, None] - """ - if sim_info is None: - return None - return sim_info.death_tracker - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.print_death', - 'Print information about a Sim and their death.', - command_arguments=( - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to modify.', is_optional=True, default_value='Active Sim'), - ) -) -def _common_print_death(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): - if not CommonSimDeathUtils.is_dead(sim_info): - output(f'Sim {sim_info} is not dead.') - return - death_type = CommonSimDeathUtils.get_death_type(sim_info) - if death_type == CommonDeathType.NONE: - output(f'Sim {sim_info} died in an unknown way.') - return - output(f'Sim {sim_info} died via {death_type.name}') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.kill_sim', - 'Greet a Sim with the Kiss of Death.', - command_arguments=( - CommonConsoleCommandArgument('death_type', 'Name of Death Type', 'The type of death to bring upon a Sim.', is_optional=True, default_value='Random'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to modify.', is_optional=True, default_value='Active Sim'), - ) -) -def _common_kill_all_sims(output: CommonConsoleCommandOutput, death_type: CommonDeathType = CommonDeathType.NONE, sim_info: SimInfo = None): - if death_type == CommonDeathType.NONE: - death_type = CommonDeathType.convert_from_vanilla(DeathType.get_random_death_type()) - household_count = CommonHouseholdUtils.get_number_of_sims_in_household_of_sim(sim_info) - if household_count == 1: - output('Bad things can happen when you kill the only member of a Household!') - return False - output(f'Killing Sim {sim_info} with death {death_type.name}.') - result = CommonSimDeathUtils.kill_sim(sim_info, death_type) - if result: - output(f'Successfully killed {sim_info} with death {death_type.name}.') - else: - output(f'Failed to kill {sim_info} with death {death_type.name}. Reason: {result}') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.kill_all_sims', - 'Greet all Sims with the Kiss of Death.', - command_arguments=( - CommonConsoleCommandArgument('death_type', 'Name of Death Type', 'The type of death to bring upon the Sims.', is_optional=True, default_value='Random'), - ) -) -def _common_kill_sim(output: CommonConsoleCommandOutput, death_type: CommonDeathType = CommonDeathType.NONE): - output(f'Killing Sims.') - kill_count = 0 - saved_count = 0 - for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(include_sim_callback=CommonFunctionUtils.run_predicate_with_reversed_result(CommonSimDeathUtils.is_dead)): - household_count = CommonHouseholdUtils.get_number_of_sims_in_household_of_sim(sim_info) - if household_count == 1: - saved_count += 1 - continue - if death_type == CommonDeathType.NONE: - death_type_override = CommonDeathType.convert_from_vanilla(DeathType.get_random_death_type()) - else: - death_type_override = death_type - result = CommonSimDeathUtils.kill_sim(sim_info, death_type_override) - if result: - kill_count += 1 - else: - saved_count += 1 - output(f'{kill_count} Sim(s) have met with a terrible fate.') - output(f'{saved_count} Sim(s) were spared a terrible fate.') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.revive_sim', - 'Revive a Sim and stop them being a ghost.', - command_arguments=( - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to modify.', is_optional=True, default_value='Active Sim'), - ) -) -def _common_revive_sim(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): - output(f'Reviving Sim {sim_info}.') - result = CommonSimDeathUtils.revive_sim(sim_info) - if result: - output(f'Successfully revived {sim_info}.') - else: - output(f'Failed to revive {sim_info}. Reason: {result}') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.revive_all_sims', - 'Revive all Sims and stop them from being spooky.' -) -def _common_revive_sim(output: CommonConsoleCommandOutput): - output(f'Reviving All Sims.') - revive_count = 0 - for sim_info in CommonSimDeathUtils.get_sim_info_for_all_dead_sims_generator(): - result = CommonSimDeathUtils.revive_sim(sim_info) - if result: - revive_count += 1 - output(f'{revive_count} Sim(s) have been blessed with life anew.') diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_demographic_type_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_demographic_type_utils.py deleted file mode 100644 index a74a9f6..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_demographic_type_utils.py +++ /dev/null @@ -1,407 +0,0 @@ -""" -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 -""" -from typing import Tuple, TYPE_CHECKING, Dict, List, Callable, Union, Iterator - -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog -from s4ap.sims4communitylib.utils.math.common_bitwise_utils import CommonBitwiseUtils -from s4ap.sims4communitylib.utils.sims.common_sim_occult_type_utils import CommonSimOccultTypeUtils -from s4ap.sims4communitylib.utils.sims.common_sim_type_utils import CommonSimTypeUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - -if TYPE_CHECKING: - from s4ap.sims4communitylib.enums.common_age import CommonAge - from s4ap.sims4communitylib.enums.common_gender import CommonGender - from s4ap.sims4communitylib.enums.common_species import CommonSpecies - from s4ap.sims4communitylib.enums.common_occult_type import CommonOccultType - from s4ap.sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType - - -class CommonSimDemographicTypeUtils(_HasS4CLClassLog): - """ Utilities for Sim Demographic types. """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 'common_sim_demographic_type_utils' - - @classmethod - def determine_sim_demographic_flags(cls, sim_info: SimInfo) -> 'CommonSimDemographicType': - """Determine the demographics of a Sim as flags.""" - from s4ap.sims4communitylib.enums.common_age import CommonAge - from s4ap.sims4communitylib.enums.common_gender import CommonGender - from s4ap.sims4communitylib.enums.common_species import CommonSpecies - value: 'CommonSimDemographicType' = cls.convert_from_age(CommonAge.get_age(sim_info)) - value = CommonBitwiseUtils.add_flags(value, cls.convert_from_species(CommonSpecies.get_species(sim_info))) - value = CommonBitwiseUtils.add_flags(value, cls.convert_from_gender(CommonGender.get_gender(sim_info))) - value = CommonBitwiseUtils.add_flags(value, cls.convert_from_occult_type(CommonSimOccultTypeUtils.determine_current_occult_type(sim_info))) - return value - - @classmethod - def determine_sim_demographics(cls, sim_info: SimInfo) -> Tuple['CommonSimDemographicType']: - """Determine the demographics of a Sim as a collection.""" - from s4ap.sims4communitylib.enums.common_age import CommonAge - from s4ap.sims4communitylib.enums.common_gender import CommonGender - from s4ap.sims4communitylib.enums.common_species import CommonSpecies - from s4ap.sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType - values: List['CommonSimDemographicType'] = list() - values.append(cls.convert_from_species(CommonSpecies.get_species(sim_info))) - values.append(cls.convert_from_age(CommonAge.get_age(sim_info))) - values.append(cls.convert_from_gender(CommonGender.get_gender(sim_info))) - values.append(cls.convert_from_occult_type(CommonSimOccultTypeUtils.determine_current_occult_type(sim_info))) - if CommonSimUtils.is_active_sim(sim_info): - values.append(CommonSimDemographicType.CURRENTLY_CONTROLLED) - if CommonSimTypeUtils.is_non_player_sim(sim_info): - values.append(CommonSimDemographicType.NON_HOUSEHOLD) - if CommonSimTypeUtils.is_player_sim(sim_info): - values.append(CommonSimDemographicType.HOUSEHOLD) - return tuple(values) - - @classmethod - def is_sim_contained_in_demographic_flags(cls, sim_info: SimInfo, demographic_flags: 'CommonSimDemographicType', match_all: bool = True) -> bool: - """is_sim_contained_in_demographic_flags(sim_info, demographic_flags, match_all=True) - - Determine if a Sim is contained in demographic flags. - - :param sim_info: The info of a Sim. - :type sim_info: SimInfo - :param demographic_flags: The flags of Sim Demographics to match. - :type demographic_flags: CommonSimDemographicType - :param match_all: If True, the Sim must be a match for all specified demographic flags. If False, the Sim can match any of the demographic flags. Default is True. - :type match_all: bool, optional - :return: True, if the Sim matches all (or any) of the Demographic Flags. False, if not. - :rtype: bool - """ - sim_demographic_flags = cls.determine_sim_demographic_flags(sim_info) - # from s4ap.sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType - # if CommonBitwiseUtils.contains_any_flags(demographic_flags, CommonSimDemographicType.get_all_flags(exclude_values=(CommonSimDemographicType.CURRENTLY_CONTROLLED, CommonSimDemographicType.CONTROLLED, CommonSimDemographicType.HOUSEHOLD, CommonSimDemographicType.NON_HOUSEHOLD))): - # demographic_flags must contain all the values from sim_demographic_flags. If WEREWOLF was not in demographic_flags but was in sim_demographic_flags, then this would return False. - if match_all: - if not CommonBitwiseUtils.contains_all_flags(demographic_flags, sim_demographic_flags): - cls.get_log().format_with_message('Sim failed to match all flags', sim=sim_info, demographic_flags=demographic_flags, sim_demographic_flags=sim_demographic_flags) - return False - else: - if not CommonBitwiseUtils.contains_any_flags(demographic_flags, sim_demographic_flags): - cls.get_log().format_with_message('Sim failed to match any flags', sim=sim_info, demographic_flags=demographic_flags, sim_demographic_flags=sim_demographic_flags) - return False - - # # Handle the non mutually exclusive flags. - # from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - # if CommonBitwiseUtils.contains_all_flags(demographic_flags, CommonSimDemographicType.CURRENTLY_CONTROLLED) and CommonSimUtils.is_active_sim(sim_info): - # cls.get_log().format_with_message('Sim passed controlled flags', sim=sim_info, demographic_flags=demographic_flags, sim_demographic_flags=sim_demographic_flags) - # return True - # if CommonBitwiseUtils.contains_all_flags(demographic_flags, CommonSimDemographicType.CONTROLLED) and CommonSimUtils.is_active_sim(sim_info): - # cls.get_log().format_with_message('Sim passed controlled flags', sim=sim_info, demographic_flags=demographic_flags, sim_demographic_flags=sim_demographic_flags) - # return True - # if CommonBitwiseUtils.contains_all_flags(demographic_flags, CommonSimDemographicType.HOUSEHOLD) and CommonSimTypeUtils.is_player_sim(sim_info): - # cls.get_log().format_with_message('Sim passed household flags', sim=sim_info, demographic_flags=demographic_flags, sim_demographic_flags=sim_demographic_flags) - # return True - # if CommonBitwiseUtils.contains_all_flags(demographic_flags, CommonSimDemographicType.NON_HOUSEHOLD) and CommonSimTypeUtils.is_non_player_sim(sim_info): - # cls.get_log().format_with_message('Sim passed non household flags', sim=sim_info, demographic_flags=demographic_flags, sim_demographic_flags=sim_demographic_flags) - # return True - cls.get_log().format_with_message('Sim passed all flags', sim=sim_info, demographic_flags=demographic_flags, sim_demographic_flags=sim_demographic_flags) - return True - - @classmethod - def is_sim_contained_in_demographics(cls, sim_info: SimInfo, demographics: Tuple['CommonSimDemographicType'], match_all: bool = True) -> bool: - """is_sim_contained_in_demographic_flags(sim_info, demographics, match_all=True) - - Determine if a Sim is contained in a collection of Sim demographics. - - :param sim_info: The info of a Sim. - :type sim_info: SimInfo - :param demographics: A collection of Sim Demographics to match. - :type demographics: Tuple[CommonSimDemographicType] - :param match_all: If True, the Sim must be a match for all specified demographics. If False, the Sim can match any of the demographics. Default is True. - :type match_all: bool, optional - :return: True, if the Sim matches all (or any) of the Demographics. False, if not. - :rtype: bool - """ - sim_demographics = cls.determine_sim_demographics(sim_info) - - # # Handle the non mutually exclusive flags. - # from s4ap.sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType - # from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - # if CommonSimDemographicType.CURRENTLY_CONTROLLED in demographics and CommonSimUtils.is_active_sim(sim_info): - # cls.get_log().format_with_message('Sim passed controlled flags', sim=sim_info, demographics=demographics, sim_demographics=sim_demographics) - # return True - # if CommonSimDemographicType.CONTROLLED in demographics and CommonSimUtils.is_active_sim(sim_info): - # cls.get_log().format_with_message('Sim passed controlled flags', sim=sim_info, demographics=demographics, sim_demographics=sim_demographics) - # return True - # if CommonSimDemographicType.NON_HOUSEHOLD in demographics and CommonSimTypeUtils.is_non_player_sim(sim_info): - # cls.get_log().format_with_message('Sim passed non household flags', sim=sim_info, demographics=demographics, sim_demographics=sim_demographics) - # return True - # if CommonSimDemographicType.HOUSEHOLD in demographics and CommonSimTypeUtils.is_player_sim(sim_info): - # cls.get_log().format_with_message('Sim passed household flags', sim=sim_info, demographics=demographics, sim_demographics=sim_demographics) - # return True - - # demographics must contain all the values from sim_demographics. If WEREWOLF was not in demographics but was in sim_demographics, then this would return False. - if match_all: - for sim_demographic in sim_demographics: - if sim_demographic not in demographics: - cls.get_log().format_with_message('Sim failed all flags', sim=sim_info, demographics=demographics, sim_demographics=sim_demographics, missing_sim_demographic=sim_demographic) - return False - cls.get_log().format_with_message('Sim passed all flags', sim=sim_info, demographics=demographics, sim_demographics=sim_demographics) - return True - else: - for sim_demographic in sim_demographics: - if sim_demographic in demographics: - cls.get_log().format_with_message('Sim passed flags', sim=sim_info, demographics=demographics, sim_demographics=sim_demographics, matching_sim_demographic=sim_demographic) - return True - cls.get_log().format_with_message('Sim failed all flags', sim=sim_info, demographics=demographics, sim_demographics=sim_demographics) - return False - - @classmethod - def convert_to_age(cls, value: 'CommonSimDemographicType') -> 'CommonAge': - """Convert a value to an Age value.""" - from s4ap.sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType - from s4ap.sims4communitylib.enums.common_age import CommonAge - mapping: Dict[CommonSimDemographicType, CommonAge] = { - CommonSimDemographicType.BABY: CommonAge.BABY, - CommonSimDemographicType.INFANT: CommonAge.INFANT, - CommonSimDemographicType.TODDLER: CommonAge.TODDLER, - CommonSimDemographicType.CHILD: CommonAge.CHILD, - CommonSimDemographicType.TEEN: CommonAge.TEEN, - CommonSimDemographicType.YOUNG_ADULT: CommonAge.YOUNGADULT, - CommonSimDemographicType.ADULT: CommonAge.ADULT, - CommonSimDemographicType.ELDER: CommonAge.ELDER - } - return mapping.get(value, CommonAge.INVALID) - - @classmethod - def convert_from_age(cls, value: 'CommonAge') -> 'CommonSimDemographicType': - """Convert a value to a Sim demographic value.""" - from s4ap.sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType - from s4ap.sims4communitylib.enums.common_age import CommonAge - mapping: Dict[CommonAge, CommonSimDemographicType] = { - CommonAge.BABY: CommonSimDemographicType.BABY, - CommonAge.INFANT: CommonSimDemographicType.INFANT, - CommonAge.TODDLER: CommonSimDemographicType.TODDLER, - CommonAge.CHILD: CommonSimDemographicType.CHILD, - CommonAge.TEEN: CommonSimDemographicType.TEEN, - CommonAge.YOUNGADULT: CommonSimDemographicType.YOUNG_ADULT, - CommonAge.ADULT: CommonSimDemographicType.ADULT, - CommonAge.ELDER: CommonSimDemographicType.ELDER - } - return mapping.get(value, CommonSimDemographicType.NONE) - - @classmethod - def convert_to_gender(cls, value: 'CommonSimDemographicType') -> 'CommonGender': - """Convert a value to a Gender value.""" - from s4ap.sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType - from s4ap.sims4communitylib.enums.common_gender import CommonGender - mapping: Dict[CommonSimDemographicType, CommonGender] = { - CommonSimDemographicType.MALE: CommonGender.MALE, - CommonSimDemographicType.FEMALE: CommonGender.FEMALE - } - return mapping.get(value, CommonGender.INVALID) - - @classmethod - def convert_from_gender(cls, value: 'CommonGender') -> 'CommonSimDemographicType': - """Convert a value to a Sim demographic value.""" - from s4ap.sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType - from s4ap.sims4communitylib.enums.common_gender import CommonGender - mapping: Dict[CommonGender, CommonSimDemographicType] = { - CommonGender.MALE: CommonSimDemographicType.MALE, - CommonGender.FEMALE: CommonSimDemographicType.FEMALE - } - return mapping.get(value, CommonSimDemographicType.NONE) - - @classmethod - def convert_to_species(cls, value: 'CommonSimDemographicType') -> 'CommonSpecies': - """Convert a value to a Species value.""" - from s4ap.sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType - from s4ap.sims4communitylib.enums.common_species import CommonSpecies - mapping: Dict[CommonSimDemographicType, CommonSpecies] = { - CommonSimDemographicType.HUMAN: CommonSpecies.HUMAN, - CommonSimDemographicType.SMALL_DOG: CommonSpecies.SMALL_DOG, - CommonSimDemographicType.LARGE_DOG: CommonSpecies.LARGE_DOG, - CommonSimDemographicType.CAT: CommonSpecies.CAT, - CommonSimDemographicType.FOX: CommonSpecies.FOX, - CommonSimDemographicType.HORSE: CommonSpecies.HORSE, - } - return mapping.get(value, CommonSpecies.INVALID) - - @classmethod - def convert_from_species(cls, value: 'CommonSpecies') -> 'CommonSimDemographicType': - """Convert a value to a Sim demographic value.""" - from s4ap.sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType - from s4ap.sims4communitylib.enums.common_species import CommonSpecies - mapping: Dict[CommonSpecies, CommonSimDemographicType] = { - CommonSpecies.HUMAN: CommonSimDemographicType.HUMAN, - CommonSpecies.SMALL_DOG: CommonSimDemographicType.SMALL_DOG, - CommonSpecies.LARGE_DOG: CommonSimDemographicType.LARGE_DOG, - CommonSpecies.CAT: CommonSimDemographicType.CAT, - CommonSpecies.FOX: CommonSimDemographicType.FOX, - CommonSpecies.HORSE: CommonSimDemographicType.HORSE, - } - return mapping.get(value, CommonSimDemographicType.NONE) - - @classmethod - def convert_to_occult_type(cls, value: 'CommonSimDemographicType') -> 'CommonOccultType': - """Convert a value to an Occult Type value.""" - from s4ap.sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType - from s4ap.sims4communitylib.enums.common_occult_type import CommonOccultType - mapping: Dict[CommonSimDemographicType, CommonOccultType] = { - CommonSimDemographicType.ALIEN: CommonOccultType.ALIEN, - CommonSimDemographicType.MERMAID: CommonOccultType.MERMAID, - CommonSimDemographicType.ROBOT: CommonOccultType.ROBOT, - CommonSimDemographicType.SKELETON: CommonOccultType.SKELETON, - CommonSimDemographicType.VAMPIRE: CommonOccultType.VAMPIRE, - CommonSimDemographicType.WITCH: CommonOccultType.WITCH, - CommonSimDemographicType.PLANT: CommonOccultType.PLANT_SIM, - CommonSimDemographicType.GHOST: CommonOccultType.GHOST, - CommonSimDemographicType.WEREWOLF: CommonOccultType.WEREWOLF, - CommonSimDemographicType.NON_OCCULT: CommonOccultType.NON_OCCULT, - } - return mapping.get(value, CommonOccultType.NONE) - - @classmethod - def convert_from_occult_type(cls, value: 'CommonOccultType') -> 'CommonSimDemographicType': - """Convert a value to a Sim demographic value.""" - from s4ap.sims4communitylib.enums.common_sim_demographic_types import CommonSimDemographicType - from s4ap.sims4communitylib.enums.common_occult_type import CommonOccultType - mapping: Dict[CommonOccultType, CommonSimDemographicType] = { - CommonOccultType.ALIEN: CommonSimDemographicType.ALIEN, - CommonOccultType.MERMAID: CommonSimDemographicType.MERMAID, - CommonOccultType.ROBOT: CommonSimDemographicType.ROBOT, - CommonOccultType.SKELETON: CommonSimDemographicType.SKELETON, - CommonOccultType.VAMPIRE: CommonSimDemographicType.VAMPIRE, - CommonOccultType.WITCH: CommonSimDemographicType.WITCH, - CommonOccultType.PLANT_SIM: CommonSimDemographicType.PLANT, - CommonOccultType.GHOST: CommonSimDemographicType.GHOST, - CommonOccultType.WEREWOLF: CommonSimDemographicType.WEREWOLF, - CommonOccultType.NON_OCCULT: CommonSimDemographicType.NON_OCCULT, - } - return mapping.get(value, CommonSimDemographicType.NONE) - - @classmethod - def get_all_sims_matching_demographics( - cls, - sim_demographics: Tuple['CommonSimDemographicType'], - include_sim_callback: Callable[[SimInfo], Union[bool, CommonExecutionResult, CommonTestResult]] = None, - instanced_only: bool = True - ) -> Iterator[SimInfo]: - """get_all_sims_matching_demographics(\ - sim_demographics,\ - include_sim_callback=None,\ - instanced_only=True\ - ) - - Get all Sims matching a collection of Sim Demographics. - - :param sim_demographics: A collection of Sim demographics to match on. - :type sim_demographics: Tuple[CommonSimDemographicType] - :param include_sim_callback: If the result of this callback is True, the Sim will be available in the results. If set to None, All Sims will be available in the results. - :type include_sim_callback: Callable[[SimInfo], bool], optional - :param instanced_only: If True, only Sims that are currently loaded will be available in the results. Default is True. - :type instanced_only: bool, optional - :return: A generator of Sims matching the specified demographics. - :rtype: Iterator[SimInfo] - """ - if instanced_only: - sim_info_gen = CommonSimUtils.get_instanced_sim_info_for_all_sims_generator(include_sim_callback=include_sim_callback) - else: - sim_info_gen = CommonSimUtils.get_sim_info_for_all_sims_generator(include_sim_callback=include_sim_callback) - for sim_info in sim_info_gen: - if cls.is_sim_contained_in_demographics(sim_info, sim_demographics): - yield sim_info - - @classmethod - def get_all_sims_matching_demographic_flags( - cls, - sim_demographic_flags: 'CommonSimDemographicType', - include_sim_callback: Callable[[SimInfo], Union[bool, CommonExecutionResult, CommonTestResult]] = None, - instanced_only: bool = True - ) -> Iterator[SimInfo]: - """get_all_sims_matching_demographic_flags(\ - sim_demographic_flags,\ - include_sim_callback=None,\ - instanced_only=True\ - ) - - Get all Sims matching Sim Demographics Flags. - - :param sim_demographic_flags: Flags of Sim Demographics to match on. - :type sim_demographic_flags: CommonSimDemographicType - :param include_sim_callback: If the result of this callback is True, the Sim will be available in the results. If set to None, All Sims will be available in the results. - :type include_sim_callback: Callable[[SimInfo], bool], optional - :param instanced_only: If True, only Sims that are currently loaded will be available in the results. Default is True. - :type instanced_only: bool, optional - :return: A generator of Sims matching the specified demographics. - :rtype: Iterator[SimInfo] - """ - if instanced_only: - sim_info_gen = CommonSimUtils.get_instanced_sim_info_for_all_sims_generator(include_sim_callback=include_sim_callback) - else: - sim_info_gen = CommonSimUtils.get_sim_info_for_all_sims_generator(include_sim_callback=include_sim_callback) - for sim_info in sim_info_gen: - if cls.is_sim_contained_in_demographic_flags(sim_info, sim_demographic_flags): - yield sim_info - - @classmethod - def perform_action_on_sims_matching_demographics( - cls, - sim_demographics: Tuple['CommonSimDemographicType'], - action: Callable[[SimInfo], None], - include_sim_callback: Callable[[SimInfo], Union[bool, CommonExecutionResult, CommonTestResult]] = None, - instanced_only: bool = True - ): - """perform_action_on_sims_matching_demographics(\ - sim_demographics,\ - action,\ - include_sim_callback=None,\ - instanced_only=True\ - ) - - Perform an action on all Sims matching a collection of Sim Demographics. - - :param sim_demographics: A collection of Sim demographics to match on. - :type sim_demographics: Tuple[CommonSimDemographicType] - :param action: A function invoked on each matching Sim. - :type action: Callable[[SimInfo], None] - :param include_sim_callback: If the result of this callback is True, the Sim will be available to have the action performed on them. If set to None, All Sims will be available to have the action performed on them. - :type include_sim_callback: Callable[[SimInfo], bool], optional - :param instanced_only: If True, only Sims that are currently loaded will be available. Default is True. - :type instanced_only: bool, optional - """ - for sim_info in cls.get_all_sims_matching_demographics(sim_demographics, include_sim_callback=include_sim_callback, instanced_only=instanced_only): - if cls.is_sim_contained_in_demographics(sim_info, sim_demographics): - action(sim_info) - - @classmethod - def perform_action_on_sims_matching_demographic_flags( - cls, - sim_demographic_flags: 'CommonSimDemographicType', - action: Callable[[SimInfo], None], - include_sim_callback: Callable[[SimInfo], Union[bool, CommonExecutionResult, CommonTestResult]] = None, - instanced_only: bool = True - ): - """perform_action_on_sims_matching_demographic_flags(\ - sim_demographic_flags,\ - action,\ - include_sim_callback=None,\ - instanced_only=True\ - ) - - Perform an action on all Sims matching Sim Demographics Flags. - - :param sim_demographic_flags: Flags of Sim Demographics to match on. - :type sim_demographic_flags: CommonSimDemographicType - :param action: A function invoked on each matching Sim. - :type action: Callable[[SimInfo], None] - :param include_sim_callback: If the result of this callback is True, the Sim will be available to have the action performed on them. If set to None, All Sims will be available to have the action performed on them. - :type include_sim_callback: Callable[[SimInfo], bool], optional - :param instanced_only: If True, only Sims that are currently loaded will be available to have the action performed on them. Default is True. - :type instanced_only: bool, optional - """ - for sim_info in cls.get_all_sims_matching_demographic_flags(sim_demographic_flags, include_sim_callback=include_sim_callback, instanced_only=instanced_only): - if cls.is_sim_contained_in_demographic_flags(sim_info, sim_demographic_flags): - action(sim_info) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_gender_option_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_gender_option_utils.py deleted file mode 100644 index 560b3b0..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_gender_option_utils.py +++ /dev/null @@ -1,879 +0,0 @@ -""" -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 -""" -from typing import Union - -from sims.global_gender_preference_tuning import ExploringOptionsStatus, GlobalGenderPreferenceTuning -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.enums.traits_enum import CommonTraitId -from s4ap.sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog -from s4ap.sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils -from s4ap.sims4communitylib.utils.sims.common_sim_voice_utils import CommonSimVoiceUtils -from s4ap.sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils -from s4ap.sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils -from traits.traits import Trait - - -class CommonSimGenderOptionUtils(_HasS4CLClassLog): - """Utilities for manipulating the Gender Options of Sims. - - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 'common_sim_gender_option_utils' - - @staticmethod - def has_masculine_frame(sim_info: SimInfo) -> CommonTestResult: - """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: The result of testing. True, if the Sim does. False, if the Sim does not. - :rtype: CommonTestResult - """ - return CommonTraitUtils.has_trait(sim_info, CommonTraitId.GENDER_OPTIONS_FRAME_MASCULINE) - - @staticmethod - def has_feminine_frame(sim_info: SimInfo) -> CommonTestResult: - """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: The result of testing. True, if the Sim does. False, if the Sim does not. - :rtype: CommonTestResult - """ - return CommonTraitUtils.has_trait(sim_info, CommonTraitId.GENDER_OPTIONS_FRAME_FEMININE) - - @staticmethod - def prefers_menswear(sim_info: SimInfo) -> CommonTestResult: - """prefers_menswear(sim_info) - - Determine if a sim prefers Mens Clothing. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim does. False, if the Sim does not. - :rtype: CommonTestResult - """ - return CommonTraitUtils.has_trait(sim_info, CommonTraitId.GENDER_OPTIONS_CLOTHING_MENS_WEAR) - - @staticmethod - def prefers_womenswear(sim_info: SimInfo) -> CommonTestResult: - """prefers_womenswear(sim_info) - - Determine if a sim prefers Womens Clothing. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim does. False, if the Sim does not. - :rtype: CommonTestResult - """ - return CommonTraitUtils.has_trait(sim_info, CommonTraitId.GENDER_OPTIONS_CLOTHING_WOMENS_WEAR) - - @staticmethod - def can_impregnate(sim_info: SimInfo) -> CommonTestResult: - """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: The result of testing. True, if the Sim can impregnate other Sims. False, if the Sim can not impregnate other Sims. - :rtype: CommonTestResult - """ - from s4ap.sims4communitylib.utils.sims.common_sim_pregnancy_utils import CommonSimPregnancyUtils - return CommonSimPregnancyUtils.can_impregnate(sim_info) - - @staticmethod - def can_not_impregnate(sim_info: SimInfo) -> CommonTestResult: - """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: The result of testing. True, if the Sim can not impregnate other Sims. False, if the Sim can impregnate other Sims. - :rtype: CommonTestResult - """ - can_impregnate_result = CommonSimGenderOptionUtils.can_impregnate(sim_info) - return can_impregnate_result.reverse_result() - - @staticmethod - def can_be_impregnated(sim_info: SimInfo) -> CommonTestResult: - """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: The result of testing. True, if the Sim can be impregnated. False, if the Sim can not be impregnated. - :rtype: CommonTestResult - """ - from s4ap.sims4communitylib.utils.sims.common_sim_pregnancy_utils import CommonSimPregnancyUtils - return CommonSimPregnancyUtils.can_be_impregnated(sim_info) - - @staticmethod - def can_not_be_impregnated(sim_info: SimInfo) -> CommonTestResult: - """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: The result of testing. True, if the Sim can not be impregnated. False, if the Sim can be impregnated. - :rtype: CommonTestResult - """ - can_be_impregnated_result = CommonSimGenderOptionUtils.can_be_impregnated(sim_info) - return can_be_impregnated_result.reverse_result() - - @staticmethod - def can_create_pregnancy(sim_info: SimInfo) -> CommonTestResult: - """can_create_pregnancy(sim_info) - - Determine if a Sim can either impregnate, be impregnated, or can reproduce. - - .. note:: Will return False if the Sim can both impregnate and not impregnate,\ - if the Sim can both be impregnated and not be impregnated\ - or if the Sim can both reproduce and not reproduce. - - .. note:: A Sim can impregnate when they can either impregnate other Sims, can be impregnated by other Sims, or if they are a Pet, can reproduce. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim can create pregnancies. False, if the Sim can not create pregnancies. - :rtype: CommonTestResult - """ - return CommonTraitUtils.can_impregnate(sim_info) or CommonTraitUtils.can_be_impregnated(sim_info) or CommonTraitUtils.can_reproduce(sim_info) - - @staticmethod - def can_reproduce(sim_info: SimInfo) -> CommonTestResult: - """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: The result of testing. True, if the Sim can reproduce. False, if the Sim can not reproduce. - :rtype: CommonTestResult - """ - if CommonTraitUtils.has_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_NOT_REPRODUCE): - return CommonTestResult(False, reason=f'Sim has the Cannot Reproduce trait.') - if CommonSimGenderOptionUtils.can_not_impregnate(sim_info) and CommonSimGenderOptionUtils.can_not_be_impregnated(sim_info): - return CommonTestResult(False, reason=f'Sim can neither impregnate nor be impregnated.') - if CommonTraitUtils.has_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_REPRODUCE): - return CommonTestResult(True, reason=f'Sim has the Can Reproduce trait.') - can_impregnate_result = CommonSimGenderOptionUtils.can_impregnate(sim_info) - if can_impregnate_result: - return can_impregnate_result - can_be_impregnated_result = CommonSimGenderOptionUtils.can_be_impregnated(sim_info) - if can_be_impregnated_result: - return can_be_impregnated_result - return CommonTestResult(False, reason=f'Sim can neither impregnate nor be impregnated.') - - @staticmethod - def can_not_reproduce(sim_info: SimInfo) -> CommonTestResult: - """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: The result of testing. True, if the Sim can not reproduce. False, if the Sim can reproduce. - :rtype: CommonTestResult - """ - can_reproduce_result = CommonSimGenderOptionUtils.can_reproduce(sim_info) - return can_reproduce_result.reverse_result() - - @staticmethod - def uses_toilet_standing(sim_info: SimInfo) -> CommonTestResult: - """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: The result of testing. True, if the Sim uses toilets while standing. False, if the Sim does not use toilets while standing. - :rtype: CommonTestResult - """ - toilet_standing_trait = CommonSimGenderOptionUtils.determine_toilet_standing_trait(sim_info) - if toilet_standing_trait is None: - return CommonTestResult(False, reason='No toilet standing trait was found for Sim.') - return CommonTraitUtils.has_trait(sim_info, toilet_standing_trait) - - @staticmethod - def uses_toilet_sitting(sim_info: SimInfo) -> CommonTestResult: - """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: The result of testing. True, if the Sim uses toilets while sitting. False, if the Sim does not use toilets while sitting. - :rtype: CommonTestResult - """ - toilet_sitting_trait = CommonSimGenderOptionUtils.determine_toilet_sitting_trait(sim_info) - if toilet_sitting_trait is None: - return CommonTestResult(False, reason='No toilet sitting trait was found for Sim.') - return CommonTraitUtils.has_trait(sim_info, toilet_sitting_trait) - - @staticmethod - def has_breasts(sim_info: SimInfo) -> CommonTestResult: - """has_breasts(sim_info) - - Determine if a Sim has breasts. - - .. note:: This will True if breasts are being forced on the Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim has breasts. False, if not. - :rtype: CommonTestResult - """ - if CommonGenderUtils.is_female(sim_info): - if CommonTraitUtils.has_trait(sim_info, CommonTraitId.BREASTS_FORCE_OFF): - return CommonTestResult(False, reason=f'Sim does not have breasts. They are Female and have the Breasts Force Off trait.') - else: - return CommonTestResult(True, reason=f'Sim has breasts. They are Female and they do not have the Breasts Force Off trait.') - if CommonGenderUtils.is_male(sim_info): - if CommonTraitUtils.has_trait(sim_info, CommonTraitId.BREASTS_FORCE_ON): - return CommonTestResult(True, reason=f'Sim has breasts. They are Male and they have the Breasts Force On trait.') - else: - return CommonTestResult(False, reason=f'Sim does not have breasts. They are Male and they do not have the Breasts Force On trait.') - return CommonTestResult(False, reason=f'Sim does not have breasts. They are neither Male nor Female.') - - @staticmethod - def update_gender_options_to_vanilla_male(sim_info: SimInfo, return_on_failure: bool = False) -> CommonExecutionResult: - """update_gender_options_to_vanilla_male(sim_info, return_on_failure=False) - - Update a Sim to the vanilla Sims 4 default gender options for Male Sims. (Masculine, Menswear Preference, etc.) - - .. note:: This will change the following things: Body Frame (Masculine), Clothing Preference (Masculine), Can Be Impregnated (False), Can Impregnate (True), Can Reproduce (True), Toilet Usage Posture (Standing), Voice Actor (MALE). - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param return_on_failure: If True, if any update attempt fails, the function will return that result. If False, any failures will be ignored. Default is False. - :type return_on_failure: bool, optional - :return: The result of updating. True, if successful. False, if not. - :rtype: CommonExecutionResult - """ - update_body_frame_result = CommonSimGenderOptionUtils.update_body_frame(sim_info, True) - if return_on_failure and not update_body_frame_result: - return update_body_frame_result - update_clothing_preference_result = CommonSimGenderOptionUtils.update_clothing_preference(sim_info, True) - if return_on_failure and not update_clothing_preference_result: - return update_clothing_preference_result - update_can_be_impregnated_result = CommonSimGenderOptionUtils.update_can_be_impregnated(sim_info, False) - if return_on_failure and not update_can_be_impregnated_result: - return update_can_be_impregnated_result - update_can_impregnate_result = CommonSimGenderOptionUtils.update_can_impregnate(sim_info, True) - if return_on_failure and not update_can_impregnate_result: - return update_can_impregnate_result - update_can_reproduce_result = CommonSimGenderOptionUtils.update_can_reproduce(sim_info, True) - if return_on_failure and not update_can_reproduce_result: - return update_can_reproduce_result - update_toilet_usage_result = CommonSimGenderOptionUtils.update_toilet_usage(sim_info, True) - if return_on_failure and not update_toilet_usage_result: - return update_toilet_usage_result - set_male_voice_result = CommonSimVoiceUtils.set_to_default_male_voice(sim_info) - if return_on_failure and not set_male_voice_result: - return set_male_voice_result - return CommonExecutionResult.TRUE - - @staticmethod - def update_gender_options_to_vanilla_female(sim_info: SimInfo, return_on_failure: bool = False) -> CommonExecutionResult: - """update_gender_options_to_vanilla_female(sim_info, return_on_failure=False) - - Update a Sim to the vanilla Sims 4 default gender options for Female Sims. (Feminine, Womenswear Preference, etc.) - - .. note:: This will change the following things: Body Frame (Feminine), Clothing Preference (Feminine), Can Be Impregnated (True), Can Impregnate (False), Can Reproduce (True), Toilet Usage Posture (Sitting), Voice Actor (FEMALE). - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param return_on_failure: If True, if any update attempt fails, the function will return that result. If False, any failures will be ignored. Default is False. - :type return_on_failure: bool, optional - :return: The result of updating. True, if successful. False, if not. - :rtype: CommonExecutionResult - """ - update_body_frame_result = CommonSimGenderOptionUtils.update_body_frame(sim_info, False) - if return_on_failure and not update_body_frame_result: - return update_body_frame_result - update_clothing_preference_result = CommonSimGenderOptionUtils.update_clothing_preference(sim_info, False) - if return_on_failure and not update_clothing_preference_result: - return update_clothing_preference_result - update_can_be_impregnated_result = CommonSimGenderOptionUtils.update_can_be_impregnated(sim_info, True) - if return_on_failure and not update_can_be_impregnated_result: - return update_can_be_impregnated_result - update_can_impregnate_result = CommonSimGenderOptionUtils.update_can_impregnate(sim_info, False) - if return_on_failure and not update_can_impregnate_result: - return update_can_impregnate_result - update_can_reproduce_result = CommonSimGenderOptionUtils.update_can_reproduce(sim_info, True) - if return_on_failure and not update_can_reproduce_result: - return update_can_reproduce_result - update_toilet_usage_result = CommonSimGenderOptionUtils.update_toilet_usage(sim_info, False) - if return_on_failure and not update_toilet_usage_result: - return update_toilet_usage_result - set_female_voice_result = CommonSimVoiceUtils.set_to_default_female_voice(sim_info) - if return_on_failure and not set_female_voice_result: - return set_female_voice_result - return CommonExecutionResult.TRUE - - @staticmethod - def update_has_breasts(sim_info: SimInfo, has_breasts: bool) -> CommonExecutionResult: - """update_has_breasts(sim_info, has_breasts) - - Give or Take Away the breasts of a Sim. - - .. note:: Will only update Human Sims. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param has_breasts: If True, the Sim will be given breasts.\ - If False, the Sim will not longer have breasts. - :type has_breasts: bool - :return: The result of updating. True, if the state of a Sim having breasts or not was changed. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - from s4ap.sims4communitylib.events.sim.common_sim_event_dispatcher import CommonSimEventDispatcherService - CommonTraitUtils.remove_trait(sim_info, CommonTraitId.BREASTS_FORCE_OFF) - CommonTraitUtils.remove_trait(sim_info, CommonTraitId.BREASTS_FORCE_ON) - if has_breasts: - if CommonGenderUtils.is_male(sim_info): - add_trait_result = CommonTraitUtils.add_trait(sim_info, CommonTraitId.BREASTS_FORCE_ON) - if not add_trait_result: - return add_trait_result - CommonSimEventDispatcherService()._on_sim_change_gender_options_breasts(sim_info) - else: - if CommonGenderUtils.is_female(sim_info): - add_trait_result = CommonTraitUtils.add_trait(sim_info, CommonTraitId.BREASTS_FORCE_OFF) - if not add_trait_result: - return add_trait_result - CommonSimEventDispatcherService()._on_sim_change_gender_options_breasts(sim_info) - return CommonExecutionResult.TRUE - - @staticmethod - def update_body_frame(sim_info: SimInfo, masculine: bool) -> CommonExecutionResult: - """update_body_frame(sim_info, masculine) - - Update the Body Frame of a Sim. - - .. note:: Will only update Human Sims. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param masculine: If True, the Sim will get a Masculine frame.\ - If False, the Sim will get a Feminine frame. - :type masculine: bool - :return: The result of updating. True, if successful. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - if not CommonSpeciesUtils.is_human(sim_info): - return CommonExecutionResult(False, reason=f'Sim is not Human.') - if masculine: - CommonTraitUtils.remove_trait(sim_info, CommonTraitId.GENDER_OPTIONS_FRAME_FEMININE) - add_trait_result = CommonTraitUtils.add_trait(sim_info, CommonTraitId.GENDER_OPTIONS_FRAME_MASCULINE) - if not add_trait_result: - return add_trait_result - else: - CommonTraitUtils.remove_trait(sim_info, CommonTraitId.GENDER_OPTIONS_FRAME_MASCULINE) - add_trait_result = CommonTraitUtils.add_trait(sim_info, CommonTraitId.GENDER_OPTIONS_FRAME_FEMININE) - if not add_trait_result: - return add_trait_result - from s4ap.sims4communitylib.events.sim.common_sim_event_dispatcher import CommonSimEventDispatcherService - CommonSimEventDispatcherService()._on_sim_change_gender_options_body_frame(sim_info) - return CommonExecutionResult.TRUE - - @staticmethod - def update_clothing_preference(sim_info: SimInfo, prefer_menswear: bool) -> CommonExecutionResult: - """update_clothing_preference(sim_info, prefer_menswear) - - Update the Clothing Preference of a Sim. - - .. note:: Will only update Human Sims. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param prefer_menswear: If True, the Sim will prefer Menswear.\ - If False, the Sim will prefer Womenswear. - :type prefer_menswear: bool - :return: The result of updating. True, if successful. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - if not CommonSpeciesUtils.is_human(sim_info): - return CommonExecutionResult(False, reason=f'Sim is not Human.') - if prefer_menswear: - CommonTraitUtils.remove_trait(sim_info, CommonTraitId.GENDER_OPTIONS_CLOTHING_WOMENS_WEAR) - add_trait_result = CommonTraitUtils.add_trait(sim_info, CommonTraitId.GENDER_OPTIONS_CLOTHING_MENS_WEAR) - if not add_trait_result: - return add_trait_result - else: - CommonTraitUtils.remove_trait(sim_info, CommonTraitId.GENDER_OPTIONS_CLOTHING_MENS_WEAR) - add_trait_result = CommonTraitUtils.add_trait(sim_info, CommonTraitId.GENDER_OPTIONS_CLOTHING_WOMENS_WEAR) - if not add_trait_result: - return add_trait_result - from s4ap.sims4communitylib.events.sim.common_sim_event_dispatcher import CommonSimEventDispatcherService - CommonSimEventDispatcherService()._on_sim_change_gender_options_clothing_preference(sim_info) - return CommonExecutionResult.TRUE - - @staticmethod - def update_can_be_impregnated(sim_info: SimInfo, can_be_impregnated: bool) -> CommonExecutionResult: - """update_can_be_impregnated(sim_info, can_be_impregnated) - - Update a Sims ability to be impregnated by other Sims. - - .. note:: Will only update Human Sims. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param can_be_impregnated: If True, the Sim will have the ability to be impregnated.\ - If False, the Sim will not have the ability to be impregnated. - :type can_be_impregnated: bool - :return: The result of updating. True, if successful. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - from s4ap.sims4communitylib.utils.sims.common_sim_pregnancy_utils import CommonSimPregnancyUtils - can_be_impregnated_trait = CommonSimPregnancyUtils.determine_can_be_impregnated_trait(sim_info) - can_not_be_impregnated_trait = CommonSimPregnancyUtils.determine_can_not_be_impregnated_trait(sim_info) - if can_be_impregnated_trait is None: - return CommonExecutionResult(False, reason=f'No Can Be Impregnated trait was found for Sim {sim_info}') - if can_not_be_impregnated_trait is None: - return CommonExecutionResult(False, reason=f'No Can Not Be Impregnated trait was found for Sim {sim_info}') - if can_be_impregnated: - CommonTraitUtils.remove_trait(sim_info, can_not_be_impregnated_trait) - add_trait_result = CommonTraitUtils.add_trait(sim_info, can_be_impregnated_trait) - if not add_trait_result: - return add_trait_result - if not CommonSpeciesUtils.is_horse(sim_info): - CommonTraitUtils.remove_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_NOT_REPRODUCE) - add_trait_result = CommonTraitUtils.add_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_REPRODUCE) - if not add_trait_result: - return add_trait_result - else: - CommonTraitUtils.remove_trait(sim_info, can_be_impregnated_trait) - add_trait_result = CommonTraitUtils.add_trait(sim_info, can_not_be_impregnated_trait) - if not add_trait_result: - return add_trait_result - if not CommonSimPregnancyUtils.can_impregnate(sim_info): - if not CommonSpeciesUtils.is_horse(sim_info): - CommonTraitUtils.remove_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_REPRODUCE) - add_trait_result = CommonTraitUtils.add_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_NOT_REPRODUCE) - if not add_trait_result: - return add_trait_result - from s4ap.sims4communitylib.events.sim.common_sim_event_dispatcher import CommonSimEventDispatcherService - CommonSimEventDispatcherService()._on_sim_change_gender_options_can_be_impregnated(sim_info) - return CommonExecutionResult.TRUE - - @staticmethod - def update_can_impregnate(sim_info: SimInfo, can_impregnate: bool) -> CommonExecutionResult: - """update_can_impregnate(sim_info, can_impregnate) - - Update a Sims ability to impregnate other Sims. - - .. note:: Will only update Human Sims. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param can_impregnate: If True, the Sim will have the ability to impregnate other Sims.\ - If False, the Sim will not have the ability to impregnate other Sims. - :type can_impregnate: bool - :return: The result of updating. True, if successful. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - from s4ap.sims4communitylib.utils.sims.common_sim_pregnancy_utils import CommonSimPregnancyUtils - can_impregnate_trait = CommonSimPregnancyUtils.determine_can_impregnate_trait(sim_info) - can_not_impregnate_trait = CommonSimPregnancyUtils.determine_can_not_impregnate_trait(sim_info) - if can_impregnate_trait is None: - return CommonExecutionResult(False, reason=f'No Can Impregnate trait was found for Sim {sim_info}') - if can_not_impregnate_trait is None: - return CommonExecutionResult(False, reason=f'No Can Not Impregnate trait was found for Sim {sim_info}') - if can_impregnate: - CommonTraitUtils.remove_trait(sim_info, can_not_impregnate_trait) - add_trait_result = CommonTraitUtils.add_trait(sim_info, can_impregnate_trait) - if not add_trait_result: - return add_trait_result - if not CommonSpeciesUtils.is_horse(sim_info): - CommonTraitUtils.remove_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_NOT_REPRODUCE) - add_trait_result = CommonTraitUtils.add_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_REPRODUCE) - if not add_trait_result: - return add_trait_result - else: - CommonTraitUtils.remove_trait(sim_info, can_impregnate_trait) - add_trait_result = CommonTraitUtils.add_trait(sim_info, can_not_impregnate_trait) - if not add_trait_result: - return add_trait_result - if not CommonSimPregnancyUtils.can_be_impregnated(sim_info): - if not CommonSpeciesUtils.is_horse(sim_info): - CommonTraitUtils.remove_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_REPRODUCE) - add_trait_result = CommonTraitUtils.add_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_NOT_REPRODUCE) - if not add_trait_result: - return add_trait_result - from s4ap.sims4communitylib.events.sim.common_sim_event_dispatcher import CommonSimEventDispatcherService - CommonSimEventDispatcherService()._on_sim_change_gender_options_can_impregnate(sim_info) - return CommonExecutionResult.TRUE - - @staticmethod - def update_can_reproduce(sim_info: SimInfo, can_reproduce: bool) -> CommonExecutionResult: - """update_can_reproduce(sim_info, can_reproduce) - - Update a Sims ability to reproduce. - - .. note:: Will only update Pet Sims. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param can_reproduce: If True, the Sim will have the ability to reproduce.\ - If False, the Sim will not have the ability to reproduce. - :type can_reproduce: bool - :return: The result of updating. True, if successful. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - if not CommonSpeciesUtils.is_animal(sim_info): - return CommonExecutionResult(False, reason=f'Sim is not an Animal.') - if can_reproduce: - if not CommonSpeciesUtils.is_horse(sim_info): - CommonTraitUtils.remove_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_NOT_REPRODUCE) - add_trait_result = CommonTraitUtils.add_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_REPRODUCE) - if not add_trait_result: - return add_trait_result - if CommonGenderUtils.is_male(sim_info): - update_can_impregnate_result = CommonSimGenderOptionUtils.update_can_impregnate(sim_info, True) - if not update_can_impregnate_result: - return update_can_impregnate_result - update_can_be_impregnated_result = CommonSimGenderOptionUtils.update_can_be_impregnated(sim_info, False) - if not update_can_be_impregnated_result: - return update_can_be_impregnated_result - else: - update_can_impregnate_result = CommonSimGenderOptionUtils.update_can_impregnate(sim_info, False) - if not update_can_impregnate_result: - return update_can_impregnate_result - update_can_be_impregnated_result = CommonSimGenderOptionUtils.update_can_be_impregnated(sim_info, True) - if not update_can_be_impregnated_result: - return update_can_be_impregnated_result - else: - CommonTraitUtils.remove_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_REPRODUCE) - if not CommonSpeciesUtils.is_horse(sim_info): - add_trait_result = CommonTraitUtils.add_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_NOT_REPRODUCE) - if not add_trait_result: - return add_trait_result - if CommonGenderUtils.is_male(sim_info): - update_can_impregnate_result = CommonSimGenderOptionUtils.update_can_impregnate(sim_info, False) - if not update_can_impregnate_result: - return update_can_impregnate_result - update_can_be_impregnated_result = CommonSimGenderOptionUtils.update_can_be_impregnated(sim_info, False) - if not update_can_be_impregnated_result: - return update_can_be_impregnated_result - else: - update_can_impregnate_result = CommonSimGenderOptionUtils.update_can_impregnate(sim_info, False) - if not update_can_impregnate_result: - return update_can_impregnate_result - update_can_be_impregnated_result = CommonSimGenderOptionUtils.update_can_be_impregnated(sim_info, False) - if not update_can_be_impregnated_result: - return update_can_be_impregnated_result - from s4ap.sims4communitylib.events.sim.common_sim_event_dispatcher import CommonSimEventDispatcherService - CommonSimEventDispatcherService()._on_sim_change_gender_options_can_reproduce(sim_info) - return CommonExecutionResult.TRUE - - @staticmethod - def update_toilet_usage(sim_info: SimInfo, uses_toilet_standing: bool) -> CommonExecutionResult: - """update_toilet_usage(sim_info, uses_toilet_standing) - - Update how a Sim uses the toilet. i.e. Toilet Standing or Toilet Sitting. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param uses_toilet_standing: If True, the Sim will use toilets while standing and will not use toilets while sitting.\ - If False, the Sim will use toilets while sitting and will not use toilets while standing. - :type uses_toilet_standing: bool - :return: The result of updating toilet use posture. True, if successful. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - toilet_standing = CommonSimGenderOptionUtils.determine_toilet_standing_trait(sim_info) - toilet_sitting = CommonSimGenderOptionUtils.determine_toilet_sitting_trait(sim_info) - - if toilet_standing is None: - return CommonExecutionResult(False, reason='No toilet standing trait was found for Sim.') - - if toilet_sitting is None: - return CommonExecutionResult(False, reason='No toilet sitting trait was found for Sim.') - - CommonTraitUtils.remove_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_UNKNOWN) - if uses_toilet_standing: - CommonTraitUtils.remove_trait(sim_info, toilet_sitting) - add_trait_result = CommonTraitUtils.add_trait(sim_info, toilet_standing) - if not add_trait_result: - return add_trait_result - else: - CommonTraitUtils.remove_trait(sim_info, toilet_standing) - add_trait_result = CommonTraitUtils.add_trait(sim_info, toilet_sitting) - if not add_trait_result: - return add_trait_result - from s4ap.sims4communitylib.events.sim.common_sim_event_dispatcher import CommonSimEventDispatcherService - CommonSimEventDispatcherService()._on_sim_change_gender_options_toilet_usage(sim_info) - return CommonExecutionResult.TRUE - - @staticmethod - def set_can_use_toilet_standing(sim_info: SimInfo, can_use_toilet_standing: bool) -> CommonExecutionResult: - """set_can_use_toilet_standing(sim_info, can_use_toilet_standing) - - Set whether a Sim can use a toilet while standing or not. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param can_use_toilet_standing: Whether or not the Sim will be able to use a toilet while standing. - :type can_use_toilet_standing: bool - :return: The result of setting toilet use posture. True, if successful set. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - toilet_standing = CommonSimGenderOptionUtils.determine_toilet_standing_trait(sim_info) - - if toilet_standing is None: - return CommonExecutionResult(False, reason='No toilet standing trait was found for Sim.') - - if can_use_toilet_standing and not CommonTraitUtils.has_trait(sim_info, toilet_standing): - CommonTraitUtils.remove_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_UNKNOWN) - add_trait_result = CommonTraitUtils.add_trait(sim_info, toilet_standing) - if not add_trait_result: - return add_trait_result - elif CommonTraitUtils.has_trait(sim_info, toilet_standing): - CommonTraitUtils.remove_trait(sim_info, toilet_standing) - if not CommonSimGenderOptionUtils.uses_toilet_sitting(sim_info): - add_trait_result = CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_UNKNOWN) - if not add_trait_result: - return add_trait_result - - from s4ap.sims4communitylib.events.sim.common_sim_event_dispatcher import CommonSimEventDispatcherService - CommonSimEventDispatcherService()._on_sim_change_gender_options_toilet_usage(sim_info) - return CommonExecutionResult.TRUE - - @staticmethod - def set_can_use_toilet_sitting(sim_info: SimInfo, can_use_toilet_sitting: bool) -> CommonExecutionResult: - """set_can_use_toilet_sitting(sim_info, can_use_toilet_sitting) - - Set whether a Sim can use a toilet while sitting or not. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param can_use_toilet_sitting: Whether or not the Sim will be able to use a toilet while sitting. - :type can_use_toilet_sitting: bool - :return: The result of setting toilet use posture. True, if successful set. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - toilet_sitting = CommonSimGenderOptionUtils.determine_toilet_sitting_trait(sim_info) - - if toilet_sitting is None: - return CommonExecutionResult(False, reason='No toilet sitting trait was found for Sim.') - - if can_use_toilet_sitting and not CommonTraitUtils.has_trait(sim_info, toilet_sitting): - CommonTraitUtils.remove_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_UNKNOWN) - add_trait_result = CommonTraitUtils.add_trait(sim_info, toilet_sitting) - if not add_trait_result: - return add_trait_result - elif CommonTraitUtils.has_trait(sim_info, toilet_sitting): - CommonTraitUtils.remove_trait(sim_info, toilet_sitting) - if not CommonSimGenderOptionUtils.uses_toilet_standing(sim_info): - add_trait_result = CommonTraitUtils.add_trait(sim_info, CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_UNKNOWN) - if not add_trait_result: - return add_trait_result - - from s4ap.sims4communitylib.events.sim.common_sim_event_dispatcher import CommonSimEventDispatcherService - CommonSimEventDispatcherService()._on_sim_change_gender_options_toilet_usage(sim_info) - return CommonExecutionResult.TRUE - - @staticmethod - def determine_toilet_standing_trait(sim_info: SimInfo) -> Union[CommonTraitId, None]: - """determine_toilet_standing_trait(sim_info) - - Determine the trait that would indicate a Sim uses the toilet while standing. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The trait that would indicate the Sim uses the toilet while standing or None if no trait is found. - :rtype: Union[CommonTraitId, None] - """ - if CommonSpeciesUtils.is_human(sim_info): - return CommonTraitId.GENDER_OPTIONS_TOILET_STANDING - elif CommonSpeciesUtils.is_large_dog(sim_info): - return CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_LARGE_DOG - elif CommonSpeciesUtils.is_small_dog(sim_info): - return CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_SMALL_DOG - elif CommonSpeciesUtils.is_cat(sim_info): - return CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_CAT - elif CommonSpeciesUtils.is_fox(sim_info): - return CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_FOX - elif CommonSpeciesUtils.is_horse(sim_info): - return CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_STANDING_HORSE - return None - - @staticmethod - def determine_toilet_sitting_trait(sim_info: SimInfo) -> Union[CommonTraitId, None]: - """determine_toilet_sitting_trait(sim_info) - - Determine the trait that would indicate a Sim uses the toilet while sitting. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The trait that would indicate the Sim uses the toilet while sitting or None if no trait is found. - :rtype: Union[CommonTraitId, None] - """ - if CommonSpeciesUtils.is_human(sim_info): - return CommonTraitId.GENDER_OPTIONS_TOILET_SITTING - elif CommonSpeciesUtils.is_large_dog(sim_info): - return CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_LARGE_DOG - elif CommonSpeciesUtils.is_small_dog(sim_info): - return CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_SMALL_DOG - elif CommonSpeciesUtils.is_cat(sim_info): - return CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_CAT - elif CommonSpeciesUtils.is_fox(sim_info): - return CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_FOX - elif CommonSpeciesUtils.is_horse(sim_info): - return CommonTraitId.S4CL_GENDER_OPTIONS_TOILET_SITTING_HORSE - return None - - @classmethod - def is_exploring_sexuality(cls, sim_info: SimInfo) -> CommonTestResult: - """is_exploring_sexuality(sim_info) - - Determine if a Sim is open to exploring their sexuality. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of the test. True, if the test passes. False, if not. - :rtype: CommonTestResult - """ - return cls.has_sexuality_exploration_status(sim_info, ExploringOptionsStatus.EXPLORING) - - @classmethod - def is_not_exploring_sexuality(cls, sim_info: SimInfo) -> CommonTestResult: - """is_not_exploring_sexuality(sim_info) - - Determine if a Sim is not open to exploring their sexuality. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of the test. True, if the test passes. False, if not. - :rtype: CommonTestResult - """ - return cls.has_sexuality_exploration_status(sim_info, ExploringOptionsStatus.NOT_EXPLORING) - - @classmethod - def has_sexuality_exploration_status(cls, sim_info: SimInfo, sexuality_status: ExploringOptionsStatus) -> CommonTestResult: - """has_sexuality_exploration_status(sim_info, sexuality_status) - - Determine if a Sim has the specified exploration status for their sexuality. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param sexuality_status: The exploration status to check for. - :type sexuality_status: ExploringOptionsStatus - :return: The result of the test. True, if the test passes. False, if not. - :rtype: CommonTestResult - """ - if sim_info is None: - return CommonTestResult(False, reason=f'{sim_info} is None!') - exploring_sexuality_trait = cls.get_sexuality_status_trait(sim_info, sexuality_status) - if CommonTraitUtils.has_trait(sim_info, exploring_sexuality_trait): - if sexuality_status == ExploringOptionsStatus.EXPLORING: - return CommonTestResult(True, reason=f'{sim_info} is open to exploring their sexuality.') - else: - return CommonTestResult(True, reason=f'{sim_info} is not open to exploring their sexuality.') - if sexuality_status == ExploringOptionsStatus.EXPLORING: - return CommonTestResult(False, reason=f'{sim_info} is not open to exploring their sexuality.') - else: - return CommonTestResult(False, reason=f'{sim_info} is open to exploring their sexuality.') - - @classmethod - def set_is_exploring_sexuality(cls, sim_info: SimInfo, is_exploring: bool) -> CommonExecutionResult: - """set_is_exploring_sexuality(sim_info, is_exploring) - - Set whether a Sim is open to explore their sexuality or not. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param is_exploring: Set True if the Sim should be set to Exploring. Set False if the Sim should be set to Not Exploring. - :type is_exploring: bool - """ - if sim_info is None: - return CommonTestResult(False, reason=f'{sim_info} is None!') - - if is_exploring: - cls.get_log().format_with_message('Setting Sim to exploring sexuality.', sim=sim_info, is_exploring=is_exploring) - sexuality_status = ExploringOptionsStatus.EXPLORING - opposite_sexuality_status = ExploringOptionsStatus.NOT_EXPLORING - else: - cls.get_log().format_with_message('Setting Sim to not exploring sexuality.', sim=sim_info, is_exploring=is_exploring) - sexuality_status = ExploringOptionsStatus.NOT_EXPLORING - opposite_sexuality_status = ExploringOptionsStatus.EXPLORING - - to_remove_trait = cls.get_sexuality_status_trait(sim_info, opposite_sexuality_status) - to_add_trait = cls.get_sexuality_status_trait(sim_info, sexuality_status) - cls.get_log().format_with_message('Got exploring sexuality traits.', sim=sim_info, to_remove_trait=to_remove_trait, to_add_trait=to_add_trait) - remove_result = CommonTraitUtils.remove_trait(sim_info, to_remove_trait) - if not remove_result: - cls.get_log().format_with_message('Failed to remove exploring sexuality trait.', sim=sim_info, to_remove_trait=to_remove_trait, remove_result=remove_result) - return remove_result - add_result = CommonTraitUtils.add_trait(sim_info, to_add_trait) - cls.get_log().format_with_message('Finished adding exploring sexuality trait.', sim=sim_info, to_add_trait=to_add_trait, add_result=add_result) - return add_result - - # noinspection PyUnusedLocal - @classmethod - def get_sexuality_status_trait(cls, sim_info: SimInfo, sexuality_status: ExploringOptionsStatus) -> Union[Trait, None]: - """get_sexuality_status_trait(sim_info, sexuality_status) - - Retrieve the trait associated with a sexuality status. - - :param sim_info: An instance of the Sim to receive or be checked for the trait. - :type sim_info: SimInfo - :param sexuality_status: The sexuality status to look for. - :type sexuality_status: ExploringOptionsStatus - :return: The trait associated with the specified sexuality status or None if not found. - :rtype: Union[Trait, None] - """ - return GlobalGenderPreferenceTuning.EXPLORING_SEXUALITY_TRAITS_MAPPING.get(sexuality_status, None) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_gender_preference_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_gender_preference_utils.py deleted file mode 100644 index a4ee140..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_gender_preference_utils.py +++ /dev/null @@ -1,485 +0,0 @@ -""" -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 -""" -from typing import Tuple, Union - -from sims.global_gender_preference_tuning import GlobalGenderPreferenceTuning, GenderPreferenceType -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from s4ap.sims4communitylib.enums.common_gender import CommonGender -from s4ap.sims4communitylib.enums.common_gender_preference_type import CommonGenderPreferenceType -from s4ap.sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ - CommonConsoleCommandArgument -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from s4ap.sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils - - -class CommonSimGenderPreferenceUtils: - """ Utilities for Sim gender preferences. """ - LOW_PREFERENCE_THRESHOLD = 20 - HIGH_PREFERENCE_THRESHOLD = 80 - - @classmethod - def set_preference_for_gender(cls, sim_info: SimInfo, gender: CommonGender, is_attracted_to_gender: Union[bool, None], preference_type: Union[CommonGenderPreferenceType, GenderPreferenceType] = CommonGenderPreferenceType.ROMANTIC) -> CommonExecutionResult: - """set_preference_for_gender(sim_info, gender, is_attracted_to_gender, preference_type=CommonGenderPreferenceType.ROMANTIC) - - Set the preference a Sim has for a gender. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param gender: An instance of a gender. - :type gender: CommonGender - :param is_attracted_to_gender: True, if you want the Sim to be attracted to the gender. False, if you want the Sim to NOT be attracted to the gender. None, if you want the Sim to have no preferences. - :type is_attracted_to_gender: Union[bool, None] - :param preference_type: The type of preference to use. Default is CommonGenderPreferenceType.ROMANTIC. - :type preference_type: Union[CommonGenderPreferenceType, GenderPreferenceType], optional - :return: True, if successfully set. False, it not. - :rtype: CommonExecutionResult - """ - if preference_type == CommonGenderPreferenceType.ROMANTIC or preference_type == GenderPreferenceType.ROMANTIC: - attraction_traits_map = GlobalGenderPreferenceTuning.ROMANTIC_PREFERENCE_TRAITS_MAPPING - else: - attraction_traits_map = GlobalGenderPreferenceTuning.WOOHOO_PREFERENCE_TRAITS_MAPPING - vanilla_gender = CommonGender.convert_to_vanilla(gender) - if is_attracted_to_gender is None: - traits_to_remove = ( - attraction_traits_map[vanilla_gender].not_attracted_trait, - attraction_traits_map[vanilla_gender].is_attracted_trait - ) - return CommonTraitUtils.remove_traits(sim_info, traits_to_remove) - - if is_attracted_to_gender: - trait_to_remove = attraction_traits_map[vanilla_gender].not_attracted_trait - trait_to_add = attraction_traits_map[vanilla_gender].is_attracted_trait - else: - trait_to_remove = attraction_traits_map[vanilla_gender].is_attracted_trait - trait_to_add = attraction_traits_map[vanilla_gender].not_attracted_trait - remove_result = CommonTraitUtils.remove_trait(sim_info, trait_to_remove) - if not remove_result: - return remove_result - add_result = CommonTraitUtils.add_trait(sim_info, trait_to_add) - if not add_result: - return add_result - gender_preference_stat_type = GlobalGenderPreferenceTuning.GENDER_PREFERENCE.get(vanilla_gender) - if is_attracted_to_gender: - new_value = gender_preference_stat_type.max_value - else: - new_value = gender_preference_stat_type.min_value - sim_info.set_stat_value(gender_preference_stat_type, new_value) - return CommonExecutionResult.TRUE - - @classmethod - def set_gender_preference_amount(cls, sim_info: SimInfo, gender: CommonGender, amount: int, preference_type: Union[CommonGenderPreferenceType, GenderPreferenceType] = CommonGenderPreferenceType.ROMANTIC) -> bool: - """set_gender_preference_amount(sim_info, gender, amount, preference_type=CommonGenderPreferenceType.ROMANTIC) - - Set the amount a Sim prefers the specified gender. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param gender: An instance of a gender. - :type gender: CommonGender - :param amount: The amount the Sim prefers the specified gender. - :type amount: int - :param preference_type: The type of preference to use. Default is CommonGenderPreferenceType.ROMANTIC. - :type preference_type: Union[CommonGenderPreferenceType, GenderPreferenceType], optional - :return: True, if successfully set. False, it not. - :rtype: bool - """ - if amount > 0: - is_attracted_to_gender = True - elif amount < 0: - is_attracted_to_gender = False - else: - is_attracted_to_gender = None - if cls.set_preference_for_gender(sim_info, gender, is_attracted_to_gender, preference_type=preference_type): - return True - return False - - @classmethod - def get_gender_preference_amount(cls, sim_info: SimInfo, gender: CommonGender, preference_type: Union[CommonGenderPreferenceType, GenderPreferenceType] = CommonGenderPreferenceType.ROMANTIC) -> int: - """get_gender_preference_value(sim_info, gender, preference_type=CommonGenderPreferenceType.ROMANTIC) - - Retrieve the amount a Sim prefers the specified gender. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param gender: An instance of a gender. - :type gender: CommonGender - :param preference_type: The type of preference to use. Default is CommonGenderPreferenceType.ROMANTIC. - :type preference_type: Union[CommonGenderPreferenceType, GenderPreferenceType], optional - :return: The amount the Sim prefers the specified gender. - :rtype: int - """ - if cls.has_preference_for_gender(sim_info, gender, preference_type=preference_type): - return 100 - return 0 - - @classmethod - def get_default_preferred_genders(cls, sim_info: SimInfo) -> Tuple[CommonGender]: - """get_default_preferred_genders(sim_info) - - Retrieve a collection of default gender preferences. - - .. note:: By default Male Sims prefer Female Sims and Female Sims prefer Male Sims. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: A collection of the default preferred genders. - :rtype: Tuple[CommonGender] - """ - from s4ap.sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils - if CommonGenderUtils.is_male(sim_info): - return CommonGender.FEMALE, - return CommonGender.MALE, - - @classmethod - def has_preference_for_gender(cls, sim_info: SimInfo, gender: CommonGender, like_threshold: int = None, love_threshold: int = None, preference_type: Union[CommonGenderPreferenceType, GenderPreferenceType] = CommonGenderPreferenceType.ROMANTIC) -> bool: - """has_preference_for_gender(sim_info, gender, like_threshold=None, love_threshold=None, preference_type=CommonGenderPreferenceType.ROMANTIC) - - Determine if a Sim has a preference for the specified gender. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param gender: An instance of a CommonGender. - :type gender: CommonGender - :param like_threshold: A value indicating a low amount of preference. Default is CommonSimGenderPreferenceUtils.LOW_PREFERENCE_THRESHOLD. (This argument is obsolete, do not use) - :type like_threshold: int, optional - :param love_threshold: A value indicating a high amount of preference. Default is CommonSimGenderPreferenceUtils.HIGH_PREFERENCE_THRESHOLD. (This argument is obsolete, do not use) - :type love_threshold: int, optional - :param preference_type: The type of preference to use. Default is CommonGenderPreferenceType.ROMANTIC. - :type preference_type: Union[CommonGenderPreferenceType, GenderPreferenceType], optional - :return: True, if the Sim has a preference for the specified gender. False, if not. - :rtype: bool - """ - preferences = cls.determine_preferred_genders( - sim_info, - like_threshold=like_threshold, - love_threshold=love_threshold, - preference_type=preference_type, - ) - return gender in preferences - - @classmethod - def has_preference_for(cls, sim_info: SimInfo, target_sim_info: SimInfo, like_threshold: int = None, love_threshold: int = None, preference_type: Union[CommonGenderPreferenceType, GenderPreferenceType] = CommonGenderPreferenceType.ROMANTIC) -> bool: - """has_preference_for(sim_info, target_sim_info, like_threshold=None, love_threshold=None, preference_type=CommonGenderPreferenceType.ROMANTIC) - - Determine if a Sim has a preference for another Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param target_sim_info: An instance of a Sim. - :type target_sim_info: SimInfo - :param like_threshold: A value indicating a low amount of preference. Default is CommonSimGenderPreferenceUtils.LOW_PREFERENCE_THRESHOLD. (This argument is obsolete, do not use) - :type like_threshold: int, optional - :param love_threshold: A value indicating a high amount of preference. Default is CommonSimGenderPreferenceUtils.HIGH_PREFERENCE_THRESHOLD. (This argument is obsolete, do not use) - :type love_threshold: int, optional - :param preference_type: The type of preference to use. Default is CommonGenderPreferenceType.ROMANTIC. - :type preference_type: Union[CommonGenderPreferenceType, GenderPreferenceType], optional - :return: True, if the Source Sim has a preference for the Target Sim. False, if not. - :rtype: bool - """ - return cls.has_preference_for_gender( - sim_info, - CommonGender.get_gender(target_sim_info), - like_threshold=like_threshold, - love_threshold=love_threshold, - preference_type=preference_type, - ) - - # noinspection PyUnusedLocal - @classmethod - def determine_preferred_genders(cls, sim_info: SimInfo, like_threshold: int = None, love_threshold: int = None, preference_type: Union[CommonGenderPreferenceType, GenderPreferenceType] = CommonGenderPreferenceType.ROMANTIC) -> Tuple[CommonGender]: - """determine_preferred_genders(sim_info, like_threshold=None, love_threshold=None, preference_type=CommonGenderPreferenceType.ROMANTIC) - - Determine which genders a Sim prefers. - - .. note:: - - The math is as follows (The first match will return): - - - Default Gender Preferences = MALE_PREF < like_threshold and FEMALE_PREF < like_threshold - - Prefers both Genders = absolute(MALE_PREF - FEMALE_PREF) <= love_threshold - - Prefers Male = MALE_PREF > FEMALE_PREF - - Prefers Female = FEMALE_PREF > MALE_PREF - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param like_threshold: A value indicating a low amount of preference. Default is cls.LOW_PREFERENCE_THRESHOLD. (This argument is obsolete, do not use) - :type like_threshold: int, optional - :param love_threshold: A value indicating a high amount of preference. Default is cls.HIGH_PREFERENCE_THRESHOLD. (This argument is obsolete, do not use) - :type love_threshold: int, optional - :param preference_type: The type of preference to use. Default is CommonGenderPreferenceType.ROMANTIC. - :type preference_type: Union[CommonGenderPreferenceType, GenderPreferenceType], optional - :return: A collection of CommonGenders the specified Sim prefers. - :rtype: Tuple[CommonGender] - """ - preferred_genders = list() - vanilla_preference_type = CommonGenderPreferenceType.convert_to_vanilla(preference_type) - for gender in sim_info.get_attracted_genders(vanilla_preference_type): - preferred_genders.append(CommonGender.convert_from_vanilla(gender)) - return tuple(preferred_genders) - - @classmethod - def set_to_default_gender_preferences(cls, sim_info: SimInfo) -> None: - """set_to_default_gender_preferences(sim_info) - - Set a Sim to the default gender preferences. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - """ - default_attracted_to_genders = cls.get_default_preferred_genders(sim_info) - for gender in CommonGender.get_all(): - if gender in default_attracted_to_genders: - cls.set_preference_for_gender(sim_info, gender, True, preference_type=CommonGenderPreferenceType.ROMANTIC) - cls.set_preference_for_gender(sim_info, gender, True, preference_type=CommonGenderPreferenceType.WOOHOO) - else: - cls.set_preference_for_gender(sim_info, gender, False, preference_type=CommonGenderPreferenceType.ROMANTIC) - cls.set_preference_for_gender(sim_info, gender, False, preference_type=CommonGenderPreferenceType.WOOHOO) - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.set_world_sexually_exploring', - 'Set all Sims to be sexually exploring in their Sexual Orientation.', - command_arguments=( - CommonConsoleCommandArgument('is_sexually_exploring', 'True or False', 'If True, all Sims will be sexually exploring. If False, all Sims will NOT be sexually exploring.'), - ) -) -def _common_set_world_sexually_exploring(output: CommonConsoleCommandOutput, is_sexually_exploring: bool): - if is_sexually_exploring: - output('Attempting to set all Sims to be Sexually Exporing in their Sexual Orientation.') - else: - output('Attempting to set all Sims to be Not Sexually Exporing in their Sexual Orientation.') - for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): - from s4ap.sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils - CommonSimGenderOptionUtils.set_is_exploring_sexuality(sim_info, is_sexually_exploring) - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.set_gender_pref', - 'Set the gender preference amount of a Sim towards a Gender.', - command_arguments=( - CommonConsoleCommandArgument('gender', 'CommonGender', f'The gender to change the preference of the Sim for. Valid Values: {CommonGender.get_comma_separated_names_string()}'), - CommonConsoleCommandArgument('is_attracted_to_gender', 'True or False', 'If True, the Sim will be attracted to the specified Gender. If False, the Sim will no longer be attracted to the gender.'), - CommonConsoleCommandArgument('preference_type', 'ROMANTIC or WOOHOO', 'The type of preference being updated.', is_optional=True, default_value='ROMANTIC'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance id or name of the Sim to change.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.setgenderpref', - 's4clib.set_gender_preference', - 's4clib.setgenderpreference', - ) -) -def _common_set_gender_pref(output: CommonConsoleCommandOutput, gender: CommonGender, is_attracted_to_gender: bool, preference_type: CommonGenderPreferenceType = CommonGenderPreferenceType.ROMANTIC, sim_info: SimInfo = None): - if gender is None: - return - if sim_info is None: - return - gender_name = gender.name - output(f'Attempting to set the {preference_type.name} gender preference of Sim {sim_info} for gender {gender_name} to {is_attracted_to_gender}') - if CommonSimGenderPreferenceUtils.set_preference_for_gender(sim_info, gender, is_attracted_to_gender, preference_type=preference_type): - output(f'SUCCESS: Successfully set the {preference_type.name} gender preference of Sim {sim_info} for gender {gender_name} to {is_attracted_to_gender}') - else: - output(f'FAILED: Failed to set the {preference_type.name} gender preference of Sim {sim_info} for gender {gender_name} to {is_attracted_to_gender}') - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.set_gender_pref_of_all_sims', - 'Set the gender preference amount of all Sims towards a Gender.', - command_arguments=( - CommonConsoleCommandArgument('gender', 'CommonGender', f'The gender to change the preferences of the Sims for. Valid Values: {CommonGender.get_comma_separated_names_string()}'), - CommonConsoleCommandArgument('is_attracted_to_gender', 'True or False', 'If True, all Female Sims will be attracted to the specified Gender. If False, all Female Sims will no longer be attracted to the gender.'), - CommonConsoleCommandArgument('preference_type', 'ROMANTIC or WOOHOO', 'The type of preference being updated.', is_optional=True, default_value='ROMANTIC') - ), - command_aliases=( - 's4clib.setgenderprefofallsims', - 's4clib.setgenderpreferenceofallsims', - 's4clib.set_gender_preference_of_all_sims', - 's4clib.set_all_gender_preferences', - 's4clib.setallgenderpreferences', - ) -) -def _common_set_gender_pref_of_all_sims(output: CommonConsoleCommandOutput, gender: CommonGender, is_attracted_to_gender: bool, preference_type: CommonGenderPreferenceType = CommonGenderPreferenceType.ROMANTIC): - if gender is None: - return - gender_name = gender.name - count_of_sims_changed = 0 - output(f'Setting {preference_type.name} gender preference of all Sims for gender {gender_name} to {is_attracted_to_gender}') - for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): - try: - if CommonSimGenderPreferenceUtils.set_preference_for_gender(sim_info, gender, is_attracted_to_gender, preference_type=preference_type): - count_of_sims_changed += 1 - except Exception as ex: - CommonExceptionHandler.log_exception(ModInfo.get_identity(), f'Failed to set {preference_type.name} gender preference of Sim {sim_info} for gender {gender_name} to {is_attracted_to_gender}', exception=ex) - output(f'ERROR: Failed to set {preference_type.name} gender preference of Sim {sim_info} for gender {gender} to {is_attracted_to_gender}. Exception: {ex}') - output(f'Updated the Gender Preferences of {count_of_sims_changed} Sims.') - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.set_gender_pref_of_all_female_sims', - 'Set the gender preference amount of all Female Sims towards a Gender.', - command_arguments=( - CommonConsoleCommandArgument('gender', 'CommonGender', f'The gender to change the preferences of the Sims for. Valid Values: {CommonGender.get_comma_separated_names_string()}'), - CommonConsoleCommandArgument('is_attracted_to_gender', 'True or False', 'If True, all Female Sims will be attracted to the specified Gender. If False, all Female Sims will no longer be attracted to the gender.'), - CommonConsoleCommandArgument('preference_type', 'ROMANTIC or WOOHOO', 'The type of preference being updated.', is_optional=True, default_value='ROMANTIC') - ), - command_aliases=( - 's4clib.setgenderprefofallfemalesims', - 's4clib.setgenderpreferenceofallfemalesims', - 's4clib.set_gender_preference_of_all_female_sims', - 's4clib.set_all_female_gender_preferences', - 's4clib.setallfemalegenderpreferences', - ) -) -def _common_set_gender_pref_of_all_female_sims(output: CommonConsoleCommandOutput, gender: CommonGender, is_attracted_to_gender: bool, preference_type: CommonGenderPreferenceType = CommonGenderPreferenceType.ROMANTIC): - if gender is None: - return - gender_name = gender.name - sim_count = 0 - output(f'Setting {preference_type.name} gender preference of all Female Sims for gender {gender_name} to {is_attracted_to_gender}') - from s4ap.sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils - for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(include_sim_callback=CommonGenderUtils.is_female): - try: - if CommonSimGenderPreferenceUtils.set_preference_for_gender(sim_info, gender, is_attracted_to_gender, preference_type=preference_type): - sim_count += 1 - except Exception as ex: - CommonExceptionHandler.log_exception(ModInfo.get_identity(), f'Failed to set {preference_type.name} gender preference of Sim {sim_info} for gender {gender_name} to {is_attracted_to_gender}.', exception=ex) - output(f'Failed to set {preference_type.name} gender preference of Sim {sim_info} for gender {gender_name} to {is_attracted_to_gender}. Exception: {ex}') - output(f'Updated Gender Preferences of {sim_count} Sims.') - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.set_gender_pref_of_all_male_sims', - 'Set the gender preference of all Male Sims towards a Gender.', - command_arguments=( - CommonConsoleCommandArgument('gender', 'CommonGender', f'The gender to change the preferences of the Sims for. Valid Values: {CommonGender.get_comma_separated_names_string()}'), - CommonConsoleCommandArgument('is_attracted_to_gender', 'True or False', 'If True, all Male Sims will be attracted to the specified Gender. If False, all Male Sims will no longer be attracted to the gender.'), - CommonConsoleCommandArgument('preference_type', 'ROMANTIC or WOOHOO', 'The type of preference being updated.', is_optional=True, default_value='ROMANTIC') - ), - command_aliases=( - 's4clib.setgenderprefofallmalesims', - 's4clib.setgenderpreferenceofallmalesims', - 's4clib.set_gender_preference_of_all_male_sims', - 's4clib.set_all_male_gender_preferences', - 's4clib.setallmalegenderpreferences', - ) -) -def _common_set_gender_pref_of_all_male_sims(output: CommonConsoleCommandOutput, gender: CommonGender, is_attracted_to_gender: bool, preference_type: CommonGenderPreferenceType = CommonGenderPreferenceType.ROMANTIC): - if gender is None: - return - gender_name = gender.name - sim_count = 0 - output(f'Setting {preference_type.name} gender preference of all Male Sims for gender {gender_name} to {is_attracted_to_gender}') - from s4ap.sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils - for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(include_sim_callback=CommonGenderUtils.is_male): - try: - if CommonSimGenderPreferenceUtils.set_preference_for_gender(sim_info, gender, is_attracted_to_gender, preference_type=preference_type): - sim_count += 1 - except Exception as ex: - CommonExceptionHandler.log_exception(ModInfo.get_identity(), f'Failed to set {preference_type.name} gender preference of Sim {sim_info} for gender {gender_name} to {is_attracted_to_gender}.', exception=ex) - output(f'Failed to set {preference_type.name} gender preference of Sim {sim_info} for gender {gender_name} to {is_attracted_to_gender}. Exception: {ex}') - output(f'Updated Gender Preferences of {sim_count} Sims.') - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.print_gender_pref', - 'Print the gender preference amount a Sim has towards a Gender.', - command_arguments=( - CommonConsoleCommandArgument('gender', 'CommonGender', f'The gender to change the preference of the Sim for. Valid Values: {CommonGender.get_comma_separated_names_string()}'), - CommonConsoleCommandArgument('preference_type', 'ROMANTIC or WOOHOO', 'The type of preference being checked.', is_optional=True, default_value='ROMANTIC'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance id or name of the Sim to change.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.printgenderpref', - 's4clib.print_gender_preference', - 's4clib.printgenderpreference', - ) -) -def _common_get_gender_pref(output: CommonConsoleCommandOutput, gender: CommonGender, preference_type: CommonGenderPreferenceType = CommonGenderPreferenceType.ROMANTIC, sim_info: SimInfo = None): - if gender is None: - return - if sim_info is None: - return - gender_name = gender.name - preference_percentage_amount = CommonSimGenderPreferenceUtils.get_gender_preference_amount(sim_info, gender, preference_type=preference_type) - output(f'{sim_info} has a {preference_percentage_amount}% preference for gender {gender_name}') - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.print_preferred_genders', - 'Print preferred genders a Sim is attracted to.', - command_arguments=( - CommonConsoleCommandArgument('preference_type', 'ROMANTIC or WOOHOO', 'The type of preference being checked.', is_optional=True, default_value='ROMANTIC'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance id or name of the Sim to change.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.printpreferredgenders', - ) -) -def _common_get_gender_pref(output: CommonConsoleCommandOutput, preference_type: CommonGenderPreferenceType = CommonGenderPreferenceType.ROMANTIC, sim_info: SimInfo = None): - if sim_info is None: - return - preferred_genders = CommonSimGenderPreferenceUtils.determine_preferred_genders(sim_info, preference_type=preference_type) - output(f'{sim_info} has a {preference_type.name} gender preference for genders {preferred_genders}') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.apply_default_gender_pref', - 'Apply the default Gender preferences for ROMANTIC and WOOHOO preference types to a Sim.', - command_arguments=( - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance id or name of the Sim to change.', is_optional=True, default_value='Active Sim'), - ), -) -def _s4clib_apply_default_gender_pref_to_sim(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): - if sim_info is None: - return - output(f'Attempting to update the gender preferences to their default values for {sim_info}.') - # noinspection PyBroadException - try: - CommonSimGenderPreferenceUtils.set_to_default_gender_preferences(sim_info) - except: - output(f'Failed to update Sim {sim_info}. They were most likely culled out or unavailable.') - return True - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.apply_default_gender_pref_to_all_sims', - 'Apply the default Gender preference for ROMANTIC and WOOHOO preference types to all Sims using their Gender.' -) -def _s4clib_apply_default_gender_pref_to_all_sims(output: CommonConsoleCommandOutput): - output('Attempting to update the gender preferences to their default values for all Sims.') - sim_count = 0 - for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): - # noinspection PyBroadException - try: - if sim_info is None: - continue - CommonSimGenderPreferenceUtils.set_to_default_gender_preferences(sim_info) - sim_count += 1 - except: - output(f'Failed to update Sim {sim_info}. They were most likely culled out or unavailable.') - output(f'Updated Gender Preferences of {sim_count} Sim(s).') - return True diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_genealogy_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_genealogy_utils.py deleted file mode 100644 index 12d8733..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_genealogy_utils.py +++ /dev/null @@ -1,572 +0,0 @@ -""" -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 -""" -from typing import Union, Tuple - -from sims.genealogy_tracker import GenealogyTracker, FamilyRelationshipIndex -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.enums.relationship_bits_enum import CommonRelationshipBitId -from s4ap.sims4communitylib.utils.sims.common_relationship_utils import CommonRelationshipUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - - -class CommonSimGenealogyUtils: - """Utilities for managing and manipulating the Genealogy of Sims.""" - @staticmethod - def get_genealogy_tracker(sim_info: SimInfo) -> Union[GenealogyTracker, None]: - """get_genealogy_tracker(sim_info) - - Retrieve the Genealogy Tracker for a Sim. - - .. note: A Genealogy Tracker is essentially just the Family Tree Tracker of the Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The genealogy tracker of the Sim or None if not found. - :rtype: Union[GenealogyTracker, None] - """ - if sim_info is None: - return None - return sim_info._genealogy_tracker - - @staticmethod - def set_as_father_of(sim_info: SimInfo, new_child_sim_info: SimInfo, propagate: bool=False) -> bool: - """set_as_father_of(sim_info, new_child_sim_info, propagate=False) - - Set a Sim to be the Father of another Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param new_child_sim_info: The new child of Sim A. - :type new_child_sim_info: SimInfo - :param propagate: If set to True, the grandparent relations will also be updated. Default is False. - :type propagate: bool, optional - :return: True, if the relation was set successfully. False, if not. - :rtype: bool - """ - genealogy_tracker = CommonSimGenealogyUtils.get_genealogy_tracker(new_child_sim_info) - if genealogy_tracker is None: - return False - if propagate: - genealogy_tracker.set_and_propagate_family_relation(FamilyRelationshipIndex.FATHER, sim_info) - else: - genealogy_tracker.set_family_relation(FamilyRelationshipIndex.FATHER, CommonSimUtils.get_sim_id(sim_info)) - return True - - @staticmethod - def set_as_mother_of(sim_info: SimInfo, new_child_sim_info: SimInfo, propagate: bool=False) -> bool: - """set_as_mother_of(sim_info, new_child_sim_info, propagate=False) - - Set a Sim to be the Mother of another Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param new_child_sim_info: The new child of Sim A. - :type new_child_sim_info: SimInfo - :param propagate: If set to True, the grandparent relations will also be updated. Default is False. - :type propagate: bool, optional - :return: True, if the relation was set successfully. False, if not. - :rtype: bool - """ - genealogy_tracker = CommonSimGenealogyUtils.get_genealogy_tracker(new_child_sim_info) - if genealogy_tracker is None: - return False - if propagate: - genealogy_tracker.set_and_propagate_family_relation(FamilyRelationshipIndex.MOTHER, sim_info) - else: - genealogy_tracker.set_family_relation(FamilyRelationshipIndex.MOTHER, CommonSimUtils.get_sim_id(sim_info)) - return True - - @staticmethod - def set_as_fathers_father_of(sim_info: SimInfo, new_grandchild_sim_info: SimInfo) -> bool: - """set_as_fathers_father_of(sim_info, new_fathers_father_sim_info) - - Set a Sim to be the Fathers Father of another Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param new_grandchild_sim_info: The new grandchild of Sim A. - :type new_grandchild_sim_info: SimInfo - :return: True, if the relation was set successfully. False, if not. - :rtype: bool - """ - genealogy_tracker = CommonSimGenealogyUtils.get_genealogy_tracker(new_grandchild_sim_info) - if genealogy_tracker is None: - return False - genealogy_tracker.set_and_propagate_family_relation(FamilyRelationshipIndex.FATHERS_FATHER, sim_info) - return True - - @staticmethod - def set_as_fathers_mother_of(sim_info: SimInfo, new_grandchild_sim_info: SimInfo) -> bool: - """set_as_fathers_mother_of(sim_info, new_grandchild_sim_info) - - Retrieve the Father of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param new_grandchild_sim_info: The new grandchild of Sim A. - :type new_grandchild_sim_info: SimInfo - :return: True, if the relation was set successfully. False, if not. - :rtype: bool - """ - genealogy_tracker = CommonSimGenealogyUtils.get_genealogy_tracker(new_grandchild_sim_info) - if genealogy_tracker is None: - return False - genealogy_tracker.set_family_relation(FamilyRelationshipIndex.FATHERS_MOM, sim_info) - return True - - @staticmethod - def set_as_mothers_father_of(sim_info: SimInfo, new_grandchild_sim_info: SimInfo) -> bool: - """set_as_mothers_father_of(sim_info, new_grandchild_sim_info) - - Retrieve the Father of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param new_grandchild_sim_info: The new grandchild of Sim A. - :type new_grandchild_sim_info: SimInfo - :return: True, if the relation was set successfully. False, if not. - :rtype: bool - """ - genealogy_tracker = CommonSimGenealogyUtils.get_genealogy_tracker(new_grandchild_sim_info) - if genealogy_tracker is None: - return False - genealogy_tracker.set_and_propagate_family_relation(FamilyRelationshipIndex.MOTHERS_FATHER, sim_info) - return True - - @staticmethod - def set_as_mothers_mother_of(sim_info: SimInfo, new_grandchild_sim_info: SimInfo) -> bool: - """set_as_mothers_mother_of(sim_info, new_grandchild_sim_info) - - Retrieve the Father of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param new_grandchild_sim_info: The new grandchild of Sim A. - :type new_grandchild_sim_info: SimInfo - :return: True, if the relation was set successfully. False, if not. - :rtype: bool - """ - genealogy_tracker = CommonSimGenealogyUtils.get_genealogy_tracker(new_grandchild_sim_info) - if genealogy_tracker is None: - return False - genealogy_tracker.set_and_propagate_family_relation(FamilyRelationshipIndex.MOTHERS_MOM, sim_info) - return True - - @staticmethod - def get_father_sim_info(sim_info: SimInfo) -> Union[SimInfo, None]: - """get_father_sim_info(sim_info) - - Retrieve the Father of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The father of the Sim or None if the Sim does not have a father. - :rtype: Union[SimInfo, None] - """ - return CommonSimGenealogyUtils._retrieve_relation_sim_info(sim_info, FamilyRelationshipIndex.FATHER) - - @staticmethod - def get_mother_sim_info(sim_info: SimInfo) -> Union[SimInfo, None]: - """get_mother_sim_info(sim_info) - - Retrieve the Mother of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The mother of the Sim or None if the Sim does not have a mother. - :rtype: Union[SimInfo, None] - """ - return CommonSimGenealogyUtils._retrieve_relation_sim_info(sim_info, FamilyRelationshipIndex.MOTHER) - - @staticmethod - def get_mothers_mother_sim_info(sim_info: SimInfo) -> Union[SimInfo, None]: - """get_mothers_mother_sim_info(sim_info) - - Retrieve the Grandmother of a Sim on their mothers side. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The grandmother of the Sim on their mothers side or None if the Sim does not have a mother or their mother does not have a mother. - :rtype: Union[SimInfo, None] - """ - return CommonSimGenealogyUtils._retrieve_relation_sim_info(sim_info, FamilyRelationshipIndex.MOTHERS_MOM) - - @staticmethod - def get_mothers_father_sim_info(sim_info: SimInfo) -> Union[SimInfo, None]: - """get_mothers_father_sim_info(sim_info) - - Retrieve the Grandfather of a Sim on their mothers side. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The grandfather of the Sim on their mothers side or None if the Sim does not have a mother or their mother does not have a father. - :rtype: Union[SimInfo, None] - """ - return CommonSimGenealogyUtils._retrieve_relation_sim_info(sim_info, FamilyRelationshipIndex.MOTHERS_FATHER) - - @staticmethod - def get_fathers_mother_sim_info(sim_info: SimInfo) -> Union[SimInfo, None]: - """get_fathers_mother_sim_info(sim_info) - - Retrieve the Grandmother of a Sim on their fathers side. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The grandmother of the Sim on their fathers side or None if the Sim does not have a father or their father does not have a mother. - :rtype: Union[SimInfo, None] - """ - return CommonSimGenealogyUtils._retrieve_relation_sim_info(sim_info, FamilyRelationshipIndex.FATHERS_MOM) - - @staticmethod - def get_fathers_father_sim_info(sim_info: SimInfo) -> Union[SimInfo, None]: - """get_fathers_father_sim_info(sim_info) - - Retrieve the Grandfather of a Sim on their fathers side. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The grandfather of the Sim on their fathers side or None if the Sim does not have a father or their father does not have a mother. - :rtype: Union[SimInfo, None] - """ - return CommonSimGenealogyUtils._retrieve_relation_sim_info(sim_info, FamilyRelationshipIndex.FATHERS_FATHER) - - @staticmethod - def remove_family_relations_with(sim_info_a: SimInfo, sim_info_b: SimInfo, remove_from_family_tree: bool=True) -> bool: - """remove_family_relations_with(sim_info_a, sim_info_b, remove_from_family_tree=True) - - Remove the family relations Sim A has with Sim B and the family relations Sim B has with Sim A. - - :param sim_info_a: An instance of a Sim. - :type sim_info_a: SimInfo - :param sim_info_b: The Sim to remove from the family of Sim A. - :type sim_info_b: SimInfo - :param remove_from_family_tree: If True, Sim A will remove Sim B from their family tree as well. If False, the family tree of Sim A will not be modified. Default is True. - :type remove_from_family_tree: bool, optional - :return: True, if the family relations between the Sims was removed successfully. False, if not. - :rtype: bool - """ - if remove_from_family_tree: - if CommonSimGenealogyUtils.is_father_of(sim_info_a, sim_info_b): - CommonSimGenealogyUtils.remove_father_relation(sim_info_b) - if CommonSimGenealogyUtils.is_mother_of(sim_info_a, sim_info_b): - CommonSimGenealogyUtils.remove_mother_relation(sim_info_b) - if CommonSimGenealogyUtils.is_fathers_father_of(sim_info_a, sim_info_b): - CommonSimGenealogyUtils.remove_fathers_father_relation(sim_info_b) - if CommonSimGenealogyUtils.is_fathers_mother_of(sim_info_a, sim_info_b): - CommonSimGenealogyUtils.remove_fathers_mother_relation(sim_info_b) - if CommonSimGenealogyUtils.is_mothers_father_of(sim_info_a, sim_info_b): - CommonSimGenealogyUtils.remove_mothers_father_relation(sim_info_b) - if CommonSimGenealogyUtils.is_mothers_mother_of(sim_info_a, sim_info_b): - CommonSimGenealogyUtils.remove_mothers_mother_relation(sim_info_b) - - # noinspection PyTypeChecker - relationship_bit_ids: Tuple[CommonRelationshipBitId] = ( - CommonRelationshipBitId.FAMILY_AUNT_UNCLE, - CommonRelationshipBitId.FAMILY_SON_DAUGHTER, - CommonRelationshipBitId.FAMILY_COUSIN, - CommonRelationshipBitId.FAMILY_PARENT, - CommonRelationshipBitId.FAMILY_GRANDCHILD, - CommonRelationshipBitId.FAMILY_GRANDPARENT, - CommonRelationshipBitId.FAMILY_HUSBAND_WIFE, - CommonRelationshipBitId.FAMILY_NIECE_NEPHEW, - CommonRelationshipBitId.FAMILY_BROTHER_SISTER, - CommonRelationshipBitId.FAMILY_STEP_SIBLING - ) - - for relationship_bit_id in relationship_bit_ids: - CommonRelationshipUtils.remove_relationship_bit(sim_info_a, sim_info_b, relationship_bit_id) - return True - - @staticmethod - def remove_father_relation(sim_info: SimInfo) -> bool: - """remove_father_relation(sim_info) - - Remove the Father of a Sim from their Family Tree. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: True, if the father of the Sim has been removed. False, if not. - :rtype: bool - """ - genealogy_tracker = CommonSimGenealogyUtils.get_genealogy_tracker(sim_info) - if genealogy_tracker is None: - return False - genealogy_tracker.clear_family_relation(FamilyRelationshipIndex.FATHER) - return True - - @staticmethod - def remove_mother_relation(sim_info: SimInfo) -> bool: - """remove_mother_relation(sim_info) - - Remove the Mother of a Sim from their Family Tree. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: True, if the mother of the Sim has been removed. False, if not. - :rtype: bool - """ - genealogy_tracker = CommonSimGenealogyUtils.get_genealogy_tracker(sim_info) - if genealogy_tracker is None: - return False - genealogy_tracker.clear_family_relation(FamilyRelationshipIndex.MOTHER) - return True - - @staticmethod - def remove_fathers_father_relation(sim_info: SimInfo) -> bool: - """remove_fathers_father_relation(sim_info) - - Remove the relation of a Sim to their Grandfather on their fathers side from their Family Tree. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: True, if the grandfather of the Sim has been removed. False, if not. - :rtype: bool - """ - genealogy_tracker = CommonSimGenealogyUtils.get_genealogy_tracker(sim_info) - if genealogy_tracker is None: - return False - genealogy_tracker.clear_family_relation(FamilyRelationshipIndex.FATHERS_FATHER) - return True - - @staticmethod - def remove_fathers_mother_relation(sim_info: SimInfo) -> bool: - """remove_fathers_mother_relation(sim_info) - - Remove the relation of a Sim to their Grandmother on their fathers side from their Family Tree. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: True, if the grandmother of the Sim has been removed. False, if not. - :rtype: bool - """ - genealogy_tracker = CommonSimGenealogyUtils.get_genealogy_tracker(sim_info) - if genealogy_tracker is None: - return False - genealogy_tracker.clear_family_relation(FamilyRelationshipIndex.FATHERS_MOM) - return True - - @staticmethod - def remove_mothers_father_relation(sim_info: SimInfo) -> bool: - """remove_mothers_father_relation(sim_info) - - Remove the Father of the Mother of a Sim from their Family Tree. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: True, if the father of the mother of the Sim has been removed. False, if not. - :rtype: bool - """ - genealogy_tracker = CommonSimGenealogyUtils.get_genealogy_tracker(sim_info) - if genealogy_tracker is None: - return False - genealogy_tracker.clear_family_relation(FamilyRelationshipIndex.MOTHERS_FATHER) - return True - - @staticmethod - def remove_mothers_mother_relation(sim_info: SimInfo) -> bool: - """remove_mothers_mother_relation(sim_info) - - Remove the relation of a Sim to their Grandmother on their mothers side from their Family Tree. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: True, if the grandmother of the Sim has been removed. False, if not. - :rtype: bool - """ - genealogy_tracker = CommonSimGenealogyUtils.get_genealogy_tracker(sim_info) - if genealogy_tracker is None: - return False - genealogy_tracker.clear_family_relation(FamilyRelationshipIndex.MOTHERS_MOM) - return True - - @staticmethod - def is_father_of(sim_info_a: SimInfo, sim_info_b: SimInfo) -> bool: - """is_father_of(sim_info_a, sim_info_b) - - Determine if Sim A is the father of Sim B. - - :param sim_info_a: An instance of a Sim. - :type sim_info_a: SimInfo - :param sim_info_b: An instance of a Sim. - :type sim_info_b: SimInfo - :return: True, if Sim A is the father of Sim B. False, if not. - :rtype: bool - """ - parent_sim_info_b = CommonSimGenealogyUtils.get_father_sim_info(sim_info_b) - return sim_info_a is parent_sim_info_b - - @staticmethod - def is_mother_of(sim_info_a: SimInfo, sim_info_b: SimInfo) -> bool: - """is_mother_of(sim_info_a, sim_info_b) - - Determine if Sim A is the mother of Sim B. - - :param sim_info_a: An instance of a Sim. - :type sim_info_a: SimInfo - :param sim_info_b: An instance of a Sim. - :type sim_info_b: SimInfo - :return: True, if Sim A is the mother of Sim B. False, if not. - :rtype: bool - """ - parent_sim_info_b = CommonSimGenealogyUtils.get_mother_sim_info(sim_info_b) - return sim_info_a is parent_sim_info_b - - @staticmethod - def is_fathers_father_of(sim_info_a: SimInfo, sim_info_b: SimInfo) -> bool: - """is_fathers_father_of(sim_info_a, sim_info_b) - - Determine if Sim A is the grandfather of Sim B on the fathers side of Sim B. - - :param sim_info_a: An instance of a Sim. - :type sim_info_a: SimInfo - :param sim_info_b: An instance of a Sim. - :type sim_info_b: SimInfo - :return: True, if Sim A is the grandfather of Sim B on their fathers side. False, if not. - :rtype: bool - """ - grand_parent_sim_info_b = CommonSimGenealogyUtils.get_fathers_father_sim_info(sim_info_b) - return sim_info_a is grand_parent_sim_info_b - - @staticmethod - def is_fathers_mother_of(sim_info_a: SimInfo, sim_info_b: SimInfo) -> bool: - """is_fathers_mother_of(sim_info_a, sim_info_b) - - Determine if Sim A is the grandmother of Sim B on the fathers side of Sim B. - - :param sim_info_a: An instance of a Sim. - :type sim_info_a: SimInfo - :param sim_info_b: An instance of a Sim. - :type sim_info_b: SimInfo - :return: True, if Sim A is the grandmother of Sim B on their fathers side. False, if not. - :rtype: bool - """ - grand_parent_sim_info_b = CommonSimGenealogyUtils.get_fathers_mother_sim_info(sim_info_b) - return sim_info_a is grand_parent_sim_info_b - - @staticmethod - def is_mothers_father_of(sim_info_a: SimInfo, sim_info_b: SimInfo) -> bool: - """is_mothers_father_of(sim_info_a, sim_info_b) - - Determine if Sim A is the grandfather of Sim B on the mothers side of Sim B. - - :param sim_info_a: An instance of a Sim. - :type sim_info_a: SimInfo - :param sim_info_b: An instance of a Sim. - :type sim_info_b: SimInfo - :return: True, if Sim A is the grandfather of Sim B on their mothers side. False, if not. - :rtype: bool - """ - grand_parent_sim_info_b = CommonSimGenealogyUtils.get_mothers_father_sim_info(sim_info_b) - return sim_info_a is grand_parent_sim_info_b - - @staticmethod - def is_mothers_mother_of(sim_info_a: SimInfo, sim_info_b: SimInfo) -> bool: - """is_mothers_mother_of(sim_info_a, sim_info_b) - - Determine if Sim A is the grandmother of Sim B on the mothers side of Sim B. - - :param sim_info_a: An instance of a Sim. - :type sim_info_a: SimInfo - :param sim_info_b: An instance of a Sim. - :type sim_info_b: SimInfo - :return: True, if Sim A is the grandmother of Sim B on their mothers side. False, if not. - :rtype: bool - """ - grand_parent_sim_info_b = CommonSimGenealogyUtils.get_mothers_mother_sim_info(sim_info_b) - return sim_info_a is grand_parent_sim_info_b - - @staticmethod - def has_father(sim_info: SimInfo) -> bool: - """has_father(sim_info) - - Determine if a Sim has a father. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: True, if the Sim has a father. False, if not. - :rtype: bool - """ - return CommonSimGenealogyUtils.get_father_sim_info(sim_info) is not None - - @staticmethod - def has_mother(sim_info: SimInfo) -> bool: - """has_mother(sim_info) - - Determine if Sim A is the mother of Sim B. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: True, if the Sim has a mother. False, if not. - :rtype: bool - """ - return CommonSimGenealogyUtils.get_mother_sim_info(sim_info) is not None - - @staticmethod - def has_grandfather_on_fathers_side(sim_info: SimInfo) -> bool: - """has_grandfather_on_fathers_side(sim_info) - - Determine if a Sim has a grandfather on the fathers side. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: True, if the Sim has a grandfather on the fathers side. False, if not. - :rtype: bool - """ - return CommonSimGenealogyUtils.get_fathers_father_sim_info(sim_info) is not None - - @staticmethod - def has_grandmother_on_fathers_side(sim_info: SimInfo) -> bool: - """has_grandmother_on_fathers_side(sim_info) - - Determine if a Sim has a grandmother on the fathers side. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: True, if the Sim has a grandmother on the fathers side. False, if not. - :rtype: bool - """ - return CommonSimGenealogyUtils.get_fathers_mother_sim_info(sim_info) is not None - - @staticmethod - def has_grandfather_on_mothers_side(sim_info: SimInfo) -> bool: - """has_grandfather_on_mothers_side(sim_info) - - Determine if a Sim has a grandfather on the mothers side. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: True, if the Sim has a grandfather on the mothers side. False, if not. - :rtype: bool - """ - return CommonSimGenealogyUtils.get_mothers_father_sim_info(sim_info) is not None - - @staticmethod - def has_grandmother_on_mothers_side(sim_info: SimInfo) -> bool: - """has_grandmother_on_mothers_side(sim_info) - - Determine if a Sim has a grandmother on the mothers side. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: True, if the Sim has a grandmother on the mothers side. False, if not. - :rtype: bool - """ - return CommonSimGenealogyUtils.get_mothers_mother_sim_info(sim_info) is not None - - @staticmethod - def _retrieve_relation_sim_info(sim_info: SimInfo, relationship_index: FamilyRelationshipIndex) -> Union[SimInfo, None]: - return CommonSimUtils.get_sim_info(CommonSimGenealogyUtils._retrieve_relation_sim_id(sim_info, relationship_index)) - - @staticmethod - def _retrieve_relation_sim_id(sim_info: SimInfo, relationship_index: FamilyRelationshipIndex) -> Union[SimInfo, None]: - genealogy_tracker = CommonSimGenealogyUtils.get_genealogy_tracker(sim_info) - if genealogy_tracker is None: - return None - if relationship_index not in genealogy_tracker._family_relations: - return None - return genealogy_tracker.get_relation(relationship_index) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_interaction_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_interaction_utils.py deleted file mode 100644 index 7394928..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_interaction_utils.py +++ /dev/null @@ -1,1419 +0,0 @@ -""" -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 -""" -from typing import Iterator, Union, Any, Callable, List - -from distributor.shared_messages import IconInfoData -from interactions.aop import AffordanceObjectPair -from interactions.base.interaction import Interaction -from interactions.base.super_interaction import SuperInteraction -from interactions.context import InteractionSource, InteractionContext, QueueInsertStrategy -from interactions.interaction_finisher import FinishingType -from interactions.priority import Priority -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.classes.testing.common_enqueue_result import CommonEnqueueResult -from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.enums.interactions_enum import CommonInteractionId -from s4ap.sims4communitylib.logging.has_class_log import HasClassLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.notifications.common_basic_notification import CommonBasicNotification -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ - CommonConsoleCommandArgument -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from s4ap.sims4communitylib.utils.resources.common_interaction_utils import CommonInteractionUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from s4ap.sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils - - -class CommonSimInteractionUtils(HasClassLog): - """Utilities for manipulating the interactions of Sims. - - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - return ModInfo.get_identity() - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 'common_sim_interaction_utils' - - @classmethod - def is_sitting(cls, sim_info: SimInfo) -> bool: - """is_sitting(sim_info) - - Determine if a Sim is currently sitting. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is sitting. False, if not. - :rtype: bool - """ - interactions = ( - CommonInteractionId.SIT_PASSIVE, - CommonInteractionId.SEATING_SIT, - CommonInteractionId.SEATING_SIT_CTYAE, - CommonInteractionId.SEATING_SIT_RESTAURANT_RALLY_ONLY, - CommonInteractionId.SEATING_SIT_SINGLE, - CommonInteractionId.SEATING_SIT_TODDLER_BED, - CommonInteractionId.SEATING_SIT_POST_GRAND_MEAL_WAIT_ENJOY_COMPANY, - CommonInteractionId.SEATING_SIT_DIRECTOR_CHAIR, - CommonInteractionId.SEATING_SIT_HAIR_MAKE_UP_CHAIR, - ) - return cls.has_interactions_running_or_queued(sim_info, interactions) - - @classmethod - def is_standing(cls, sim_info: SimInfo) -> bool: - """is_standing(sim_info) - - Determine if a Sim is standing. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is standing. False, if not. - :rtype: bool - """ - interactions = ( - CommonInteractionId.STAND_PASSIVE, - CommonInteractionId.SIM_STAND, - CommonInteractionId.SIM_STAND_EXCLUSIVE, - CommonInteractionId.DOG_STAND, - CommonInteractionId.DOG_STAND_PASSIVE, - CommonInteractionId.CAT_STAND, - CommonInteractionId.CAT_STAND_PASSIVE - ) - return cls.has_interactions_running_or_queued(sim_info, interactions) - - @classmethod - def is_swimming(cls, sim_info: SimInfo) -> bool: - """is_swimming(sim_info) - - Determine if a Sim is swimming. - - .. note: Cats cannot swim. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is swimming. False, if not. - :rtype: bool - """ - interactions = ( - CommonInteractionId.SIM_SWIM, - CommonInteractionId.DOG_SWIM, - CommonInteractionId.DOG_SWIM_PASSIVE - ) - return cls.has_interactions_running_or_queued(sim_info, interactions) - - @staticmethod - def apply_pressure_to_next_interaction_of(sim_info: SimInfo): - """apply_pressure_to_next_interaction_of(sim_info) - - Apply pressure to the interaction queue of a Sim for their next interaction. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None or sim.queue is None: - return - sim.queue._apply_next_pressure() - - @classmethod - def get_swim_interaction(cls, sim_info: SimInfo) -> Union[int, CommonInteractionId]: - """get_swim_interaction(sim_info) - - Retrieve a Swim interaction appropriate for a Sim. - - .. note:: Cats do not have an appropriate Swim interaction. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The decimal identifier of an interaction appropriate for the Sim or -1 if no interaction was found to be appropriate. - :rtype: Union[int, CommonInteractionId] - """ - if CommonSpeciesUtils.is_human(sim_info): - return CommonInteractionId.SIM_SWIM - elif CommonSpeciesUtils.is_dog(sim_info): - return CommonInteractionId.DOG_SWIM - # Cats don't have a swim interaction. Because they cannot swim. - return -1 - - @classmethod - def get_stand_interaction(cls, sim_info: SimInfo) -> Union[int, CommonInteractionId]: - """get_stand_interaction(sim_info) - - Retrieve a Stand interaction appropriate for a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The decimal identifier of a Stand interaction appropriate for the Sim or -1 if no Stand interaction was found to be appropriate. - :rtype: Union[int, CommonInteractionId] - """ - from s4ap.sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils - if CommonSpeciesUtils.is_human(sim_info): - return CommonInteractionId.SIM_STAND - elif CommonSpeciesUtils.is_dog(sim_info): - return CommonInteractionId.DOG_STAND - elif CommonSpeciesUtils.is_cat(sim_info): - return CommonInteractionId.CAT_STAND - elif CommonSpeciesUtils.is_fox(sim_info): - return CommonInteractionId.FOX_STAND - elif CommonSpeciesUtils.is_horse(sim_info): - return CommonInteractionId.HORSE_STAND - return -1 - - @classmethod - def get_stand_passive_interaction(cls, sim_info: SimInfo) -> Union[int, CommonInteractionId]: - """get_stand_passive_interaction(sim_info) - - Retrieve a Stand Passive interaction appropriate for a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The decimal identifier of a Stand Passive interaction appropriate for the Sim or -1 if no Stand interaction was found to be appropriate. - :rtype: Union[int, CommonInteractionId] - """ - from s4ap.sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils - if CommonSpeciesUtils.is_human(sim_info): - return CommonInteractionId.STAND_PASSIVE - elif CommonSpeciesUtils.is_dog(sim_info): - return CommonInteractionId.DOG_STAND_PASSIVE - elif CommonSpeciesUtils.is_cat(sim_info): - return CommonInteractionId.CAT_STAND_PASSIVE - elif CommonSpeciesUtils.is_fox(sim_info): - return CommonInteractionId.FOX_STAND_PASSIVE - elif CommonSpeciesUtils.is_horse(sim_info): - return CommonInteractionId.HORSE_STAND_PASSIVE - return -1 - - @classmethod - def lock_interaction_queue(cls, sim_info: SimInfo): - """lock_interaction_queue(sim_info) - - Lock the interaction queue of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None or sim.queue is None: - return - sim.queue.lock() - - @classmethod - def unlock_interaction_queue(cls, sim_info: SimInfo): - """unlock_interaction_queue(sim_info) - - Unlock the interaction queue of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None or sim.queue is None: - return - sim.queue.unlock() - - @classmethod - def has_interaction_running_or_queued(cls, sim_info: SimInfo, interaction_id: Union[int, CommonInteractionId]) -> bool: - """has_interaction_running_or_queued(sim_info, interaction_id) - - Determine if a Sim has the specified interaction running or in their interaction queue. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :param interaction_id: The identifier of the interaction to check for. - :type interaction_id: Union[int, CommonInteractionId] - :return: True, if the Sim has the specified interaction running or queued. False, if not. - :rtype: bool - """ - return cls.has_interactions_running_or_queued(sim_info, (interaction_id, )) - - @classmethod - def has_interaction_running(cls, sim_info: SimInfo, interaction_id: Union[int, CommonInteractionId]) -> bool: - """has_interaction_running(sim_info, interaction_id) - - Determine if a Sim is running the specified interaction. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :param interaction_id: The identifier of the interaction to check for. - :type interaction_id: Union[int, CommonInteractionId] - :return: True, if the Sim has the specified interaction running. False, if not. - :rtype: bool - """ - return cls.has_interactions_running(sim_info, (interaction_id, )) - - @classmethod - def has_interaction_queued(cls, sim_info: SimInfo, interaction_id: Union[int, CommonInteractionId]) -> bool: - """has_interaction_queued(sim_info, interaction_id) - - Determine if a Sim is running the specified interaction. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :param interaction_id: The identifier of the interaction to check for. - :type interaction_id: Union[int, CommonInteractionId] - :return: True, if the Sim has the specified interaction queued. False, if not. - :rtype: bool - """ - return cls.has_interactions_queued(sim_info, (interaction_id, )) - - @classmethod - def has_interactions_running_or_queued(cls, sim_info: SimInfo, interaction_ids: Iterator[Union[int, CommonInteractionId]]) -> bool: - """has_interactions_running_or_queued(sim_info, interaction_ids) - - Determine if a Sim has any of the specified interactions running or in their interaction queue. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :param interaction_ids: An iterator of identifiers of the interactions to check for. - :type interaction_ids: Union[int, CommonInteractionId] - :return: True, if the Sim has any of the specified interactions running or queued. False, if not. - :rtype: bool - """ - for interaction in cls.get_queued_or_running_interactions_gen(sim_info): - interaction_id = CommonInteractionUtils.get_interaction_id(interaction) - if interaction_id in interaction_ids: - return True - return False - - @classmethod - def has_interactions_running(cls, sim_info: SimInfo, interaction_ids: Iterator[int]) -> bool: - """has_interactions_running(sim_info, interaction_ids) - - Determine if a Sim is running any of the specified interactions. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :param interaction_ids: An iterator of identifiers of the interactions to check for. - :type interaction_ids: Union[int, CommonInteractionId] - :return: True, if the Sim has any of the specified interactions running. False, if not. - :rtype: bool - """ - for interaction in cls.get_running_interactions_gen(sim_info): - interaction_id = CommonInteractionUtils.get_interaction_id(interaction) - if interaction_id in interaction_ids: - return True - return False - - @classmethod - def has_interactions_queued(cls, sim_info: SimInfo, interaction_ids: Iterator[int]) -> bool: - """has_interactions_queued(sim_info, interaction_ids) - - Determine if a Sim has any of the specified interactions in their interaction queue. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :param interaction_ids: An iterator of identifiers of the interactions to check for. - :type interaction_ids: Union[int, CommonInteractionId] - :return: True, if the Sim has any of the specified interactions queued. False, if not. - :rtype: bool - """ - for interaction in cls.get_queued_interactions_gen(sim_info): - interaction_id = CommonInteractionUtils.get_interaction_id(interaction) - if interaction_id in interaction_ids: - return True - return False - - @classmethod - def cancel_all_queued_or_running_interactions( - cls, - sim_info: SimInfo, - cancel_reason: str, - finishing_type: FinishingType = FinishingType.USER_CANCEL, - include_interaction_callback: Callable[[Interaction], bool] = None, - **kwargs - ) -> bool: - """cancel_all_queued_or_running_interactions(\ - sim_info,\ - cancel_reason,\ - finishing_type=FinishingType.USER_CANCEL,\ - include_interaction_callback=None,\ - source=None,\ - **kwargs\ - ) - - Cancel all interactions that a Sim currently has queued or is currently running. - - :param sim_info: An instance of a Sim - :type sim_info: SimInfo - :param cancel_reason: The reason for the cancellation. - :type cancel_reason: str - :param finishing_type: The type of finish to finish the interaction with. Default is FinishingType.USER_CANCEL. - :type finishing_type: FinishingType, optional - :param include_interaction_callback: If the result of this callback is True, the Interaction will be cancelled. If set to None, All interactions will be cancelled. Default is None. - :type include_interaction_callback: Callable[[Interaction], bool], optional - :return: True, if all queued and running Interactions that pass the "include" callback were successfully cancelled. False, if not. - :rtype: bool - """ - queued_result = cls.cancel_all_queued_interactions( - sim_info, - cancel_reason, - finishing_type=finishing_type, - include_interaction_callback=include_interaction_callback, - **kwargs - ) - if not queued_result: - return False - running_result = cls.cancel_all_running_interactions( - sim_info, - cancel_reason, - finishing_type=finishing_type, - include_interaction_callback=include_interaction_callback, - **kwargs - ) - if not running_result: - return False - return True - - @classmethod - def cancel_all_running_interactions( - cls, - sim_info: SimInfo, - cancel_reason: str, - finishing_type: FinishingType = FinishingType.USER_CANCEL, - include_interaction_callback: Callable[[Interaction], bool] = None, - **kwargs - ) -> bool: - """cancel_all_running_interactions(\ - sim_info,\ - cancel_reason,\ - finishing_type=FinishingType.USER_CANCEL,\ - include_interaction_callback=None,\ - source=None,\ - **kwargs\ - ) - - Cancel all interactions that a Sim is currently running. - - :param sim_info: An instance of a Sim - :type sim_info: SimInfo - :param cancel_reason: The reason for the cancellation. - :type cancel_reason: str - :param finishing_type: The type of finish to finish the interaction with. Default is FinishingType.USER_CANCEL. - :type finishing_type: FinishingType, optional - :param include_interaction_callback: If the result of this callback is True, the Interaction will be cancelled. If set to None, all interactions will be cancelled. Default is None. - :type include_interaction_callback: Callable[[Interaction], bool], optional - :return: True, if all running interactions were successfully cancelled. False, if not. - :rtype: bool - """ - for interaction in tuple(cls.get_running_interactions_gen(sim_info, include_interaction_callback=include_interaction_callback)): - cls.cancel_interaction(interaction, cancel_reason, finishing_type=finishing_type, **kwargs) - return True - - @classmethod - def cancel_all_queued_interactions( - cls, - sim_info: SimInfo, - cancel_reason: str, - finishing_type: FinishingType = FinishingType.USER_CANCEL, - include_interaction_callback: Callable[[Interaction], bool] = None, - **kwargs - ) -> bool: - """cancel_all_queued_interactions(\ - sim_info,\ - cancel_reason,\ - finishing_type=FinishingType.USER_CANCEL,\ - include_interaction_callback=None,\ - **kwargs\ - ) - - Cancel all interactions that a Sim currently has queued. - - :param sim_info: An instance of a Sim - :type sim_info: SimInfo - :param cancel_reason: The reason for the cancellation. - :type cancel_reason: str - :param finishing_type: The type of finish to finish the interaction with. Default is FinishingType.USER_CANCEL. - :type finishing_type: FinishingType, optional - :param include_interaction_callback: If the result of this callback is True, the Interaction will be cancelled. If set to None, all interactions will be cancelled. Default is None. - :type include_interaction_callback: Callable[[Interaction], bool], optional - :return: True, if all queued interactions were successfully cancelled. False, if not. - :rtype: bool - """ - for interaction in tuple(cls.get_queued_interactions_gen(sim_info, include_interaction_callback=include_interaction_callback)): - cls.cancel_interaction(interaction, cancel_reason, finishing_type=finishing_type, **kwargs) - return True - - @classmethod - def cancel_interaction( - cls, - interaction: Interaction, - cancel_reason: str, - finishing_type: FinishingType = FinishingType.USER_CANCEL, - **kwargs - ) -> bool: - """cancel_interaction(\ - interaction,\ - cancel_reason,\ - finishing_type=FinishingType.USER_CANCEL,\ - **kwargs\ - ) - - Cancel an interaction. - - :param interaction: The interaction to cancel. - :type interaction: Interaction - :param cancel_reason: The reason for the cancellation. - :type cancel_reason: str - :param finishing_type: The type of finish to finish the interaction with. Default is FinishingType.USER_CANCEL. - :type finishing_type: FinishingType, optional - :return: True, if the interaction was cancelled successfully. False, if not. - :rtype: bool - """ - if isinstance(interaction, SuperInteraction): - immediate = kwargs.get('immediate', False) - ignore_must_run = kwargs.get('ignore_must_run', False) - carry_cancel_override = kwargs.get('carry_cancel_override', None) - return interaction.cancel( - finishing_type, - cancel_reason, - immediate=immediate, - ignore_must_run=ignore_must_run, - carry_cancel_override=carry_cancel_override - ) - return interaction.cancel(finishing_type, cancel_reason, **kwargs) - - @classmethod - def get_queued_or_running_interactions_gen(cls, sim_info: SimInfo, include_interaction_callback: Callable[[Interaction], bool] = None) -> Iterator[Interaction]: - """get_queued_or_running_interactions_gen(sim_info, include_interaction_callback=None) - - Retrieve all interactions that a Sim has queued or is currently running. - - :param sim_info: An instance of a Sim - :type sim_info: SimInfo - :param include_interaction_callback: If the result of this callback is True, the Interaction will be included in the results. If set to None, all interactions will be included. Default is None. - :type include_interaction_callback: Callable[[Interaction], bool], optional - :return: An iterator of all queued or running Interactions that pass the include callback filter. - :rtype: Iterator[Interaction] - """ - yield from cls.get_queued_interactions_gen(sim_info, include_interaction_callback=include_interaction_callback) - yield from cls.get_running_interactions_gen(sim_info, include_interaction_callback=include_interaction_callback) - - @classmethod - def get_running_interactions_gen(cls, sim_info: SimInfo, include_interaction_callback: Callable[[Interaction], bool] = None) -> Iterator[Interaction]: - """get_running_interactions_gen(sim_info, include_interaction_callback=None) - - Retrieve all interactions that a Sim is currently running. - - :param sim_info: An instance of a Sim - :type sim_info: SimInfo - :param include_interaction_callback: If the result of this callback is True, the Interaction will be included in the results. If set to None, all interactions will be included. Default is None. - :type include_interaction_callback: Callable[[Interaction], bool], optional - :return: An iterator of all running Interactions that pass the include callback filter. - :rtype: Iterator[Interaction] - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return tuple() - if sim.si_state is None: - return tuple() - for interaction in tuple(sim.si_state): - if include_interaction_callback is not None and not include_interaction_callback(interaction): - continue - yield interaction - - @classmethod - def get_queued_interactions_gen(cls, sim_info: SimInfo, include_interaction_callback: Callable[[Interaction], bool] = None) -> Iterator[Interaction]: - """get_queued_interactions_gen(sim_info, include_interaction_callback=None) - - Retrieve all interactions that a Sim currently has queued. - - :param sim_info: An instance of a Sim - :type sim_info: SimInfo - :param include_interaction_callback: If the result of this callback is True, the Interaction will be included in the results. If set to None, All interactions will be included. Default is None. - :type include_interaction_callback: Callable[[Interaction], bool], optional - :return: An iterator of all queued Interactions that pass the include callback filter. - :rtype: Iterator[Interaction] - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return tuple() - if sim.queue is None: - return tuple() - for interaction in tuple(sim.queue): - if include_interaction_callback is not None and not include_interaction_callback(interaction): - continue - yield interaction - - @classmethod - def queue_interaction( - cls, - sim_info: SimInfo, - interaction_id: Union[int, CommonInteractionId], - social_super_interaction_id: Union[int, CommonInteractionId] = None, - target: Any = None, - picked_object: Any = None, - interaction_context: InteractionContext = None, - skip_if_running: bool = False, - **kwargs - ) -> CommonEnqueueResult: - """queue_interaction(\ - sim_info,\ - interaction_id,\ - social_super_interaction_id=None,\ - target=None,\ - picked_object=None,\ - interaction_context=None,\ - skip_if_running=False,\ - **kwargs\ - ) - - Push an Interaction into the queue of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param interaction_id: The decimal identifier of an interaction. - :type interaction_id: Union[int, CommonInteractionId] - :param social_super_interaction_id: The decimal identifier of a social super interaction to queue the interaction under. Default is None - :type social_super_interaction_id: Union[int, CommonInteractionId], optional - :param target: The target of the interaction. Default is None. - :type target: Any, optional - :param interaction_context: The context to queue the interaction with. See also :func:`~create_interaction_context`. Default is None. - :type interaction_context: InteractionContext, optional - :param picked_object: The picked object of the interaction. Default is None. - :type picked_object: Any, optional - :param skip_if_running: If True, the interaction will not be queued, if it is already queued or running. If False, the interaction will be queued, even if it is already queued or running. - :return: The result of pushing the interaction to the queue of a Sim. - :rtype: CommonEnqueueResult - """ - log = cls.get_log() - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - log.format_with_message('No Sim instance for Sim.', sim=sim_info) - return CommonEnqueueResult(CommonTestResult(False, reason=f'No Sim instance for Sim {sim_info}'), CommonExecutionResult.NONE) - if sim.si_state is None: - log.format_with_message('No Super Interaction State available for Sim.', sim=sim_info) - return CommonEnqueueResult(CommonTestResult(False, reason=f'No Super Interaction State available for Sim {sim_info}'), CommonExecutionResult.NONE) - if sim.queue is None: - log.format_with_message('No Queue found for Sim.', sim=sim_info) - return CommonEnqueueResult(CommonTestResult(False, reason=f'No Queue found for Sim {sim_info}'), CommonExecutionResult.NONE) - # noinspection PyPropertyAccess - if sim.posture_state is None: - log.format_with_message('No Posture State found for Sim.', sim=sim_info) - return CommonEnqueueResult(CommonTestResult(False, reason=f'No Posture State found for Sim {sim_info}'), CommonExecutionResult.NONE) - if sim.posture is None: - log.format_with_message('No Posture found for Sim.', sim=sim_info) - return CommonEnqueueResult(CommonTestResult(False, reason=f'No Posture found for Sim {sim_info}'), CommonExecutionResult.NONE) - - interaction_instance = CommonInteractionUtils.load_interaction_by_id(interaction_id) - if interaction_instance is None: - log.format_with_message('No interaction found with id.', id=interaction_id) - return CommonEnqueueResult(CommonTestResult.TRUE, CommonExecutionResult(False, reason=f'No interaction was found with id {interaction_id}.')) - - if skip_if_running and cls.has_interaction_running_or_queued(sim_info, interaction_id): - log.debug('Skipping queue because it is already running.') - return CommonEnqueueResult(CommonTestResult.TRUE, CommonExecutionResult(False, reason=f'Interaction was already running or queued {interaction_id}.')) - - interaction_context = interaction_context or cls.create_interaction_context( - sim_info, - insert_strategy=QueueInsertStrategy.LAST - ) - - if CommonInteractionUtils.is_super_interaction(interaction_instance): - log.debug('Is super.') - return cls.queue_super_interaction( - sim_info, - interaction_id, - target=target, - picked_object=picked_object, - interaction_context=interaction_context, - **kwargs - ) - - if CommonInteractionUtils.is_social_mixer_interaction(interaction_instance): - log.debug('Is social mixer') - return cls.queue_social_mixer_interaction( - sim_info, - interaction_id, - social_super_interaction_id, - target=target, - picked_object=picked_object, - interaction_context=interaction_context, - **kwargs - ) - - log.debug('Is mixer') - return cls.queue_mixer_interaction( - sim_info, - interaction_id, - target=target, - interaction_context=interaction_context - ) - - @classmethod - def queue_super_interaction( - cls, - sim_info: SimInfo, - super_interaction_id: Union[int, CommonInteractionId], - target: Any = None, - picked_object: Any = None, - interaction_context: InteractionContext = None, - **kwargs - ) -> CommonEnqueueResult: - """queue_super_interaction(\ - sim_info,\ - super_interaction_id,\ - target=None,\ - picked_object=None,\ - interaction_context=None,\ - **kwargs\ - ) - - Push a Super Interaction into the queue of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param super_interaction_id: The decimal identifier of a super interaction. - :type super_interaction_id: Union[int, CommonInteractionId] - :param target: The target of the interaction. Default is None. - :type target: Any, optional - :param picked_object: The picked object of the interaction. Default is None. - :type picked_object: Any, optional - :param interaction_context: The context to queue the interaction with. See also :func:`~create_interaction_context`. Default is None. - :type interaction_context: InteractionContext, optional - :return: The result of pushing the interaction to the queue of a Sim. - :rtype: CommonEnqueueResult - """ - log = cls.get_log() - log.format_with_message('Pushing super interaction', sim=sim_info, interaction_id=super_interaction_id, target=target, interaction_context=interaction_context) - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - log.format_with_message('No sim instance for super interaction.', sim=sim_info) - return CommonEnqueueResult(CommonTestResult(False, reason=f'No Sim instance for Sim {sim_info}'), CommonExecutionResult.NONE) - - if target is not None and CommonTypeUtils.is_sim_or_sim_info(target): - target = CommonSimUtils.get_sim_instance(target) - - interaction_context = interaction_context or cls.create_interaction_context(sim_info) - super_interaction_instance = CommonInteractionUtils.load_interaction_by_id(super_interaction_id) - if super_interaction_instance is None: - log.format_with_message('No super interaction instance found for id.', super_interaction_id=super_interaction_id) - return CommonEnqueueResult(CommonTestResult.TRUE, CommonExecutionResult(False, reason=f'No super interaction was found with id {super_interaction_id}.')) - - result = sim.push_super_affordance( - super_interaction_instance, - target, - interaction_context, - picked_object=picked_object or target, - **kwargs - ) - if not result: - log.format_with_message('Failed to push super interaction.', result=result) - return result - - @classmethod - def queue_social_mixer_interaction( - cls, - sim_info: SimInfo, - social_mixer_interaction_id: Union[int, CommonInteractionId], - social_super_interaction_id: Union[int, CommonInteractionId], - target: SimInfo = None, - picked_object: Any = None, - interaction_context: InteractionContext = None, - **kwargs - ) -> CommonEnqueueResult: - """queue_social_mixer_interaction(\ - sim_info,\ - social_mixer_interaction_id,\ - social_super_interaction_id,\ - target=None,\ - picked_object=None,\ - interaction_context=None,\ - **kwargs\ - ) - - Push a Social Mixer Interaction into the queue of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param social_mixer_interaction_id: The decimal identifier of a social mixer interaction. - :type social_mixer_interaction_id: Union[int, CommonInteractionId] - :param social_super_interaction_id: The decimal identifier of a social super interaction to queue the social mixer interaction under. - :type social_super_interaction_id: Union[int, CommonInteractionId] - :param target: The target of the interaction. Default is None. - :type target: Any, optional - :param picked_object: The picked object of the interaction. Default is None. - :type picked_object: Any, optional - :param interaction_context: The context to queue the interaction with. See also :func:`~create_interaction_context`. Default is None. - :type interaction_context: InteractionContext, optional - :return: The result of pushing the interaction to the queue of a Sim. - :rtype: CommonEnqueueResult - """ - log = cls.get_log() - if social_super_interaction_id is not None and social_mixer_interaction_id is None: - log.format_with_message('Interaction was actually a Super interaction!', sim=sim_info, super_interaction_id=social_super_interaction_id) - return cls.queue_super_interaction( - sim_info, - social_super_interaction_id, - target=target, - picked_object=picked_object, - interaction_context=interaction_context, - **kwargs - ) - - social_super_interaction_id: Union[int, CommonInteractionId, None] = social_super_interaction_id - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - log.format_with_message('No sim instance for super interaction.', sim=sim_info) - return CommonEnqueueResult(CommonTestResult(False, reason=f'No Sim instance for Sim {sim_info}'), CommonExecutionResult.NONE) - - social_mixer_affordance_instance = CommonInteractionUtils.load_interaction_by_id(social_mixer_interaction_id) - if social_mixer_affordance_instance is None: - log.format_with_message('No social mixer affordance instance found with id.', interaction_id=social_mixer_interaction_id) - return CommonEnqueueResult(CommonTestResult.TRUE, CommonExecutionResult(False, reason=f'No social mixer interaction was found with id {social_mixer_interaction_id}.')) - - interaction_context = interaction_context or cls.create_interaction_context(sim_info) - # noinspection PyTypeChecker - super_affordance_instance = CommonInteractionUtils.load_interaction_by_id(social_super_interaction_id) - if super_affordance_instance is None: - def _get_existing_social_super_interaction(si_iter) -> Interaction: - for si in si_iter: - if si.super_affordance != super_affordance_instance: - continue - if si.social_group is None: - continue - target_sim = CommonSimUtils.get_sim_instance(target) - if target_sim is not None and target_sim not in si.social_group: - continue - log.format_with_message('Got existing super', existing_super=si.super_interaction) - return si.super_interaction - - log.debug('No super affordance found with id.') - super_interaction = _get_existing_social_super_interaction(sim.si_state) or _get_existing_social_super_interaction(sim.queue) - if super_interaction is None: - si_result = cls.queue_interaction( - sim_info, - social_super_interaction_id, - target=target, - picked_object=picked_object or target, - interaction_context=interaction_context, - **kwargs - ) - if not si_result: - log.format_with_message('Failed to locate existing super interaction.', super_interaction=super_interaction) - return CommonEnqueueResult(CommonTestResult.TRUE, CommonExecutionResult(False, reason='No Existing Super Interaction was found.')) - log.format_with_message('Found si result', si_result=si_result) - super_interaction = si_result.interaction - log.format_with_message('Found si interaction', si_interaction=super_interaction) - else: - log.format_with_message('Located existing super interaction.', existing_super=super_interaction) - - pick = interaction_context.pick if interaction_context.pick is not None else super_interaction.context.pick - log.format_with_message('Found pick', pick=pick) - interaction_context = super_interaction.context.clone_for_continuation( - super_interaction, - insert_strategy=interaction_context.insert_strategy, - source_interaction_id=super_interaction.id, - source_interaction_sim_id=CommonSimUtils.get_sim_id(sim_info), - pick=pick, - picked_object=picked_object, - must_run_next=interaction_context.must_run_next, - **kwargs - ) - else: - super_interaction = None - - aop = AffordanceObjectPair( - social_mixer_affordance_instance, - target, - super_affordance_instance, - super_interaction, - picked_object=picked_object or target, - push_super_on_prepare=True, - **kwargs - ) - result = aop.test_and_execute(interaction_context) - if not result: - log.format_with_message('Failed to queue social mixer interaction', result=result) - return result - - @classmethod - def queue_mixer_interaction( - cls, - sim_info: SimInfo, - mixer_interaction_id: Union[int, CommonInteractionId], - target: Any = None, - interaction_context: InteractionContext = None, - **kwargs - ) -> CommonEnqueueResult: - """queue_mixer_interaction(\ - sim_info,\ - mixer_interaction_id,\ - target=None,\ - interaction_context=None,\ - **kwargs\ - ) - - Push a Mixer Interaction into the Queue of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param mixer_interaction_id: The decimal identifier of a mixer interaction. - :type mixer_interaction_id: Union[int, CommonInteractionId] - :param target: The target of the interaction. Default is None. - :type target: Any, optional - :param interaction_context: The context to queue the interaction with. See also :func:`~create_interaction_context`. Default is None. - :type interaction_context: InteractionContext, optional - :return: The result of pushing the interaction to the queue of a Sim. - :rtype: CommonEnqueueResult - """ - log = cls.get_log() - log.format_with_message( - 'Attempting to queue mixer interaction.', - sim=sim_info, - target=target, - mixer_interaction_id=mixer_interaction_id, - interaction_context=interaction_context - ) - from autonomy.content_sets import get_valid_aops_gen - - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - log.format_with_message('No sim instance for mixer interaction.', sim=sim_info) - return CommonEnqueueResult(CommonTestResult(False, reason=f'No Sim instance for Sim {sim_info}'), CommonExecutionResult.NONE) - if sim.si_state is None: - log.format_with_message('No Super Interaction State available for Sim.', sim=sim_info) - return CommonEnqueueResult(CommonTestResult(False, reason=f'No Super Interaction State available for Sim {sim_info}'), CommonExecutionResult.NONE) - if sim.queue is None: - log.format_with_message('No Queue found for Sim.', sim=sim_info) - return CommonEnqueueResult(CommonTestResult(False, reason=f'No Queue found for Sim {sim_info}'), CommonExecutionResult.NONE) - # noinspection PyPropertyAccess - if sim.posture_state is None: - log.format_with_message('No Posture State found for Sim.', sim=sim_info) - return CommonEnqueueResult(CommonTestResult(False, reason=f'No Posture State found for Sim {sim_info}'), CommonExecutionResult.NONE) - if sim.posture is None: - log.format_with_message('No Posture found for Sim.', sim=sim_info) - return CommonEnqueueResult(CommonTestResult(False, reason=f'No Posture found for Sim {sim_info}'), CommonExecutionResult.NONE) - mixer_interaction_instance = CommonInteractionUtils.load_interaction_by_id(mixer_interaction_id) - if mixer_interaction_instance is None: - log.debug('No mixer interaction instance found.') - return CommonEnqueueResult(CommonTestResult.TRUE, CommonExecutionResult(False, reason=f'No mixer interaction found {mixer_interaction_id}')) - if target is not None and CommonTypeUtils.is_sim_or_sim_info(target): - target = CommonSimUtils.get_sim_instance(target) - source_interaction = sim.posture.source_interaction - if source_interaction is None: - log.debug('Sim did not have a source interaction.') - return CommonEnqueueResult(CommonTestResult.TRUE, CommonExecutionResult(False, reason=f'No source interaction found on Sim {sim_info}')) - - if hasattr(mixer_interaction_instance, 'lock_out_time') and mixer_interaction_instance.lock_out_time: - log.debug('Using Sim specific lock out time.') - sim_specific_lockout = mixer_interaction_instance.lock_out_time.target_based_lock_out - else: - log.debug('Not using Sim specific lock out time.') - sim_specific_lockout = False - - if sim_specific_lockout and sim.is_sub_action_locked_out(mixer_interaction_instance): - log.debug('Sim was locked out of performing the mixer interaction.') - return CommonEnqueueResult(CommonTestResult(False, reason=f'{sim_info} is currently locked out of doing the mixer interaction, they must wait before they can do it again.'), CommonExecutionResult.NONE) - - super_interaction_instance = source_interaction.super_affordance - interaction_context = interaction_context or cls.create_interaction_context(sim_info) - for (aop, test_result) in get_valid_aops_gen( - target, - mixer_interaction_instance, - super_interaction_instance, - source_interaction, - interaction_context, - False, - push_super_on_prepare=False - ): - test_result: CommonTestResult = CommonTestResult.convert_from_vanilla(test_result) - if test_result is None or test_result.result: - log.format_with_message('Failed to queue using affordance.', aop=aop, affordance=aop.affordance) - continue - interaction_constraint = aop.constraint_intersection(sim=sim, posture_state=None) - # noinspection PyPropertyAccess - posture_constraint = sim.posture_state.posture_constraint_strict - constraint_intersection = interaction_constraint.intersect(posture_constraint) - if not constraint_intersection.valid: - log.format_with_message('Constraint interaction was invalid.', constraint_intersection=constraint_intersection) - continue - log.format_with_message('Executing interaction using Aop.', aop=aop, affordance=aop.affordance) - return aop.execute(interaction_context, **kwargs) - - @classmethod - def test_interaction( - cls, - sim_info: SimInfo, - interaction_id: Union[int, CommonInteractionId], - social_super_interaction_id: Union[int, CommonInteractionId] = None, - target: Any = None, - picked_object: Any = None, - interaction_context: InteractionContext = None, - **kwargs - ) -> CommonTestResult: - """test_interaction(\ - sim_info,\ - interaction_id,\ - social_super_interaction_id=None,\ - target=None,\ - picked_object=None,\ - interaction_context,\ - skip_if_running=False,\ - **kwargs\ - ) - - Test to see if an Interaction can be pushed into the queue of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param interaction_id: The decimal identifier of an interaction. - :type interaction_id: Union[int, CommonInteractionId] - :param social_super_interaction_id: The decimal identifier of a social super interaction to queue the interaction under. Default is None - :type social_super_interaction_id: Union[int, CommonInteractionId], optional - :param target: The target of the interaction. Default is None. - :type target: Any, optional - :param picked_object: The picked object of the interaction. Default is None. - :type picked_object: Any, optional - :param interaction_context: The context to queue the interaction with. See also :func:`~create_interaction_context`. Default is None. - :type interaction_context: InteractionContext, optional - :return: The result of testing a push of the interaction to the queue of a Sim. - :rtype: CommonTestResult - """ - log = cls.get_log() - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - log.format_with_message('No Sim instance for Sim.', sim=sim_info) - return CommonTestResult(False, reason=f'No Sim instance for Sim {sim_info}') - if sim.si_state is None: - log.format_with_message('No Super Interaction State available for Sim.', sim=sim_info) - return CommonTestResult(False, reason=f'No Super Interaction State available for Sim {sim_info}') - if sim.queue is None: - log.format_with_message('No Queue found for Sim.', sim=sim_info) - return CommonTestResult(False, reason=f'No Queue found for Sim {sim_info}') - # noinspection PyPropertyAccess - if sim.posture_state is None: - log.format_with_message('No Posture State found for Sim.', sim=sim_info) - return CommonTestResult(False, reason=f'No Posture State found for Sim {sim_info}') - if sim.posture is None: - log.format_with_message('No Posture found for Sim.', sim=sim_info) - return CommonTestResult(False, reason=f'No Posture found for Sim {sim_info}') - - interaction_instance = CommonInteractionUtils.load_interaction_by_id(interaction_id) - if interaction_instance is None: - log.format_with_message('No interaction found with id.', id=interaction_id) - return CommonTestResult(False, reason=f'No mixer interaction found {interaction_id}') - - interaction_context = interaction_context or cls.create_interaction_context( - sim_info, - insert_strategy=QueueInsertStrategy.LAST - ) - - if CommonInteractionUtils.is_super_interaction(interaction_instance): - log.debug('Is super.') - return cls.test_super_interaction( - sim_info, - interaction_id, - target=target, - picked_object=picked_object, - interaction_context=interaction_context, - **kwargs - ) - - if CommonInteractionUtils.is_social_mixer_interaction(interaction_instance): - log.debug('Is social mixer') - return cls.test_social_mixer_interaction( - sim_info, - interaction_id, - social_super_interaction_id, - target=target, - picked_object=picked_object, - interaction_context=interaction_context, - **kwargs - ) - - log.debug('Is mixer') - return cls.test_mixer_interaction( - sim_info, - interaction_id, - target=target, - interaction_context=interaction_context - ) - - @classmethod - def test_super_interaction( - cls, - sim_info: SimInfo, - super_interaction_id: Union[int, CommonInteractionId], - target: Any = None, - picked_object: Any = None, - interaction_context: InteractionContext = None, - **kwargs - ) -> CommonTestResult: - """test_super_interaction(\ - sim_info,\ - super_interaction_id,\ - target=None,\ - picked_object=None,\ - interaction_context=None,\ - **kwargs\ - ) - - Test to see if a Super Interaction can be pushed into the queue of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param super_interaction_id: The decimal identifier of a super interaction. - :type super_interaction_id: Union[int, CommonInteractionId] - :param target: The target of the interaction. Default is None. - :type target: Any, optional - :param picked_object: The picked object of the interaction. Default is None. - :type picked_object: Any, optional - :param interaction_context: The context to queue the interaction with. See also :func:`~create_interaction_context`. Default is None. - :type interaction_context: InteractionContext, optional - :return: The result of testing a push of the interaction to the queue of a Sim. - :rtype: CommonTestResult - """ - log = cls.get_log() - log.format_with_message('Testing super interaction', sim=sim_info, interaction_id=super_interaction_id, target=target, interaction_context=interaction_context) - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - log.debug('No sim instance for super interaction.') - return CommonTestResult(False, reason=f'No Sim instance for Sim {sim_info}') - - super_interaction_instance = CommonInteractionUtils.load_interaction_by_id(super_interaction_id) - if super_interaction_instance is None: - log.format_with_message('No super interaction instance found for id.', super_interaction_id=super_interaction_id) - return CommonTestResult(False, reason=f'No super interaction found {super_interaction_id}') - - if target is not None and CommonTypeUtils.is_sim_or_sim_info(target): - target = CommonSimUtils.get_sim_instance(target) - - interaction_context = interaction_context or cls.create_interaction_context(sim_info) - - return CommonTestResult.convert_from_vanilla(sim.test_super_affordance( - super_interaction_instance, - target, - interaction_context, - picked_object=picked_object or target, - **kwargs - )) - - @classmethod - def test_social_mixer_interaction( - cls, - sim_info: SimInfo, - social_mixer_interaction_id: Union[int, CommonInteractionId], - social_super_interaction_id: Union[int, CommonInteractionId], - target: SimInfo = None, - picked_object: Any = None, - interaction_context: InteractionContext = None, - **kwargs - ) -> CommonTestResult: - """test_social_mixer_interaction(\ - sim_info,\ - social_mixer_interaction_id,\ - social_super_interaction_id,\ - target=None,\ - picked_object=None,\ - interaction_context=None,\ - **kwargs\ - ) - - Test to see if a Social Mixer Interaction can be pushed into the queue of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param social_mixer_interaction_id: The decimal identifier of a social mixer interaction. - :type social_mixer_interaction_id: Union[int, CommonInteractionId] - :param social_super_interaction_id: The decimal identifier of a social super interaction to queue the social mixer interaction under. - :type social_super_interaction_id: Union[int, CommonInteractionId] - :param target: The target of the interaction. Default is None. - :type target: Any, optional - :param picked_object: The picked object of the interaction. Default is None. - :type picked_object: Any, optional - :param interaction_context: The context to queue the interaction with. See also :func:`~create_interaction_context`. Default is None. - :type interaction_context: InteractionContext, optional - :return: The result of testing a push of the interaction to the queue of a Sim. - :rtype: CommonTestResult - """ - log = cls.get_log() - if social_super_interaction_id is not None and social_mixer_interaction_id is None: - log.format_with_message('Interaction was actually a Super interaction!', sim=sim_info, super_interaction_id=social_super_interaction_id) - return cls.queue_super_interaction( - sim_info, - social_super_interaction_id, - target=target, - picked_object=picked_object, - interaction_context=interaction_context, - **kwargs - ) - - social_super_interaction_id: Union[int, CommonInteractionId, None] = social_super_interaction_id - sim = CommonSimUtils.get_sim_instance(sim_info) - social_mixer_affordance_instance = CommonInteractionUtils.load_interaction_by_id(social_mixer_interaction_id) - if social_mixer_affordance_instance is None: - log.debug('No social mixer affordance instance found with id.') - return CommonEnqueueResult(CommonTestResult.TRUE, CommonExecutionResult(False, reason=f'No social mixer interaction found {social_mixer_interaction_id}')) - - interaction_context = interaction_context or cls.create_interaction_context(sim_info) - # noinspection PyTypeChecker - super_affordance_instance = CommonInteractionUtils.load_interaction_by_id(social_super_interaction_id) - if super_affordance_instance is None: - def _get_existing_social_super_interaction(si_iter) -> Interaction: - for si in si_iter: - if si.super_affordance != super_affordance_instance: - continue - if si.social_group is None: - continue - target_sim = CommonSimUtils.get_sim_instance(target) - if target_sim is not None and target_sim not in si.social_group: - continue - log.format_with_message('Got existing super', existing_super=si.super_interaction) - return si.super_interaction - - log.debug('No super affordance found with id.') - super_interaction = _get_existing_social_super_interaction(sim.si_state) or _get_existing_social_super_interaction(sim.queue) - if super_interaction is None: - si_result = cls.queue_interaction( - sim_info, - social_super_interaction_id, - target=target, - picked_object=picked_object or target, - interaction_context=interaction_context, - **kwargs - ) - if not si_result: - log.format_with_message('Failed to locate existing super interaction.', super_interaction=super_interaction) - return CommonEnqueueResult(CommonTestResult.TRUE, CommonExecutionResult(False, reason='No Existing Super Interaction was found.')) - log.format_with_message('Found si result', si_result=si_result) - super_interaction = si_result.interaction - log.format_with_message('Found si interaction', si_interaction=super_interaction) - else: - log.format_with_message('Located existing super interaction.', existing_super=super_interaction) - - pick = interaction_context.pick if interaction_context.pick is not None else super_interaction.context.pick - log.format_with_message('Found pick', pick=pick) - interaction_context = super_interaction.context.clone_for_continuation( - super_interaction, - insert_strategy=interaction_context.insert_strategy, - source_interaction_id=super_interaction.id, - source_interaction_sim_id=CommonSimUtils.get_sim_id(sim_info), - pick=pick, - picked_object=picked_object, - must_run_next=interaction_context.must_run_next, - **kwargs - ) - else: - super_interaction = None - - aop = AffordanceObjectPair( - social_mixer_affordance_instance, - target, - super_affordance_instance, - super_interaction, - picked_object=picked_object or target, - push_super_on_prepare=True, - **kwargs - ) - return CommonTestResult.convert_from_vanilla(aop.test(interaction_context)) - - @classmethod - def test_mixer_interaction( - cls, - sim_info: SimInfo, - mixer_interaction_id: Union[int, CommonInteractionId], - target: Any = None, - interaction_context: InteractionContext = None, - **kwargs - ) -> CommonTestResult: - """test_mixer_interaction(\ - sim_info,\ - mixer_interaction_id,\ - target=None,\ - interaction_context=None,\ - **kwargs\ - ) - - Test to see if a Mixer Interaction can be pushed into the Queue of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param mixer_interaction_id: The decimal identifier of a mixer interaction. - :type mixer_interaction_id: Union[int, CommonInteractionId] - :param target: The target of the interaction. Default is None. - :type target: Any, optional - :param interaction_context: The context to queue the interaction with. See also :func:`~create_interaction_context`. Default is None. - :type interaction_context: InteractionContext, optional - :return: The result of testing a push of the interaction to the queue of a Sim. - :rtype: CommonTestResult - """ - log = cls.get_log() - log.format_with_message( - 'Attempting to test mixer interaction.', - sim=sim_info, - target=target, - mixer_interaction_id=mixer_interaction_id, - interaction_context=interaction_context - ) - from autonomy.content_sets import get_valid_aops_gen - - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - log.format_with_message('No Sim instance for Sim.', sim=sim_info) - return CommonTestResult(False, reason=f'No Sim instance for Sim {sim_info}') - if sim.posture is None: - log.format_with_message('No Posture found for Sim.', sim=sim_info) - return CommonTestResult(False, reason=f'No Posture found for Sim {sim_info}') - - if target is not None and CommonTypeUtils.is_sim_or_sim_info(target): - target = CommonSimUtils.get_sim_instance(target) - mixer_interaction_instance = CommonInteractionUtils.load_interaction_by_id(mixer_interaction_id) - if mixer_interaction_instance is None: - log.format_with_message('No mixer interaction instance found.', mixer_interaction_id=mixer_interaction_id) - return CommonTestResult(False, reason=f'No mixer interaction found {mixer_interaction_id}') - source_interaction = sim.posture.source_interaction - if source_interaction is None: - log.debug('Sim did not have a source interaction.') - return CommonTestResult(False, reason=f'No source interaction found on Sim {sim_info}') - if hasattr(mixer_interaction_instance, 'lock_out_time') and mixer_interaction_instance.lock_out_time: - log.debug('Using Sim specific lock out time.') - sim_specific_lockout = mixer_interaction_instance.lock_out_time.target_based_lock_out - else: - log.debug('Not using Sim specific lock out time.') - sim_specific_lockout = False - - if sim_specific_lockout and sim.is_sub_action_locked_out(mixer_interaction_instance): - log.debug('Sim was locked out of performing the mixer interaction.') - return CommonTestResult(False, reason=f'{sim_info} is currently locked out of doing the mixer interaction, they must wait before they can do it again.') - - super_interaction_instance = source_interaction.super_affordance - interaction_context = interaction_context or cls.create_interaction_context(sim_info) - for (aop, test_result) in get_valid_aops_gen( - target, - mixer_interaction_instance, - super_interaction_instance, - source_interaction, - interaction_context, - False, - push_super_on_prepare=False - ): - test_result = CommonTestResult.convert_from_vanilla(test_result) - if test_result is None or test_result.result: - log.format_with_message('Failed to queue using affordance.', aop=aop, affordance=aop.affordance) - continue - interaction_constraint = aop.constraint_intersection(sim=sim, posture_state=None) - # noinspection PyPropertyAccess - posture_constraint = sim.posture_state.posture_constraint_strict - constraint_intersection = interaction_constraint.intersect(posture_constraint) - if not constraint_intersection.valid: - log.format_with_message('Constraint interaction was invalid.', constraint_intersection=constraint_intersection) - continue - log.format_with_message('Executing interaction using Aop.', aop=aop, affordance=aop.affordance) - return aop.test(interaction_context, **kwargs) - - @classmethod - def create_interaction_context( - cls, - sim_info: SimInfo, - interaction_source: InteractionSource = InteractionContext.SOURCE_SCRIPT_WITH_USER_INTENT, - priority: Priority = Priority.High, - run_priority: Union[Priority, None] = Priority.High, - insert_strategy: QueueInsertStrategy = QueueInsertStrategy.NEXT, - must_run_next: bool = False, - **kwargs - ) -> Union[InteractionContext, None]: - """create_interaction_context(\ - sim_info,\ - interaction_source=InteractionContext.SOURCE_SCRIPT_WITH_USER_INTENT,\ - priority=Priority.High,\ - run_priority=Priority.High,\ - insert_strategy=QueueInsertStrategy.NEXT,\ - must_run_next=False,\ - **kwargs\ - ) - - Create an InteractionContext. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param interaction_source: The source of the interaction. Default is InteractionContext.SOURCE_SCRIPT_WITH_USER_INTENT. - :type interaction_source: InteractionSource, optional - :param priority: The priority of the interaction. Default is Priority.High. - :type priority: Priority, optional - :param run_priority: The priority of running the interaction. Default is Priority.High. - :type run_priority: Union[Priority, None], optional - :param insert_strategy: The insert strategy for the interaction. Default is QueueInsertStrategy.NEXT. - :type insert_strategy: QueueInsertStrategy, optional - :param must_run_next: If True, the interaction will run next. Default is False. - :type must_run_next: bool, optional - :return: An interaction context for use with interactions or None if a problem occurs. - :rtype: Union[InteractionContext, None] - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return None - return InteractionContext( - sim, - interaction_source, - priority, - run_priority=run_priority, - insert_strategy=insert_strategy, - must_run_next=must_run_next, - **kwargs - ) - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_testing.print_running_interactions', - 'Print a list of all interactions a Sim is running.', - command_arguments=( - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance Id or name of the Sim to check.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib_testing.printrunninginteractions', - ) -) -def _common_show_running_interactions(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): - if sim_info is None: - return - log = CommonSimInteractionUtils.get_log() - try: - log.enable() - output(f'Attempting to print all running and queued interactions of Sim {sim_info}') - from s4ap.sims4communitylib.utils.resources.common_interaction_utils import CommonInteractionUtils - running_interaction_strings: List[str] = list() - for interaction in CommonSimInteractionUtils.get_running_interactions_gen(sim_info): - interaction_name = CommonInteractionUtils.get_interaction_short_name(interaction) or interaction.__class__.__name__ - interaction_id = CommonInteractionUtils.get_interaction_id(interaction) - running_interaction_strings.append(f'{interaction_name} ({interaction_id})') - - running_interaction_strings = sorted(running_interaction_strings, key=lambda x: x) - running_interaction_names = ', '.join(running_interaction_strings) - - queued_interaction_strings: List[str] = list() - for interaction in CommonSimInteractionUtils.get_queued_interactions_gen(sim_info): - interaction_name = CommonInteractionUtils.get_interaction_short_name(interaction) or interaction.__class__.__name__ - interaction_id = CommonInteractionUtils.get_interaction_id(interaction) - queued_interaction_strings.append(f'{interaction_name} ({interaction_id})') - - queued_interaction_strings = sorted(queued_interaction_strings, key=lambda x: x) - queued_interaction_names = ', '.join(queued_interaction_strings) - text = '' - text += f'Running Interactions:\n{running_interaction_names}\n\n' - text += f'Queued Interactions:\n{queued_interaction_names}\n\n' - sim_id = CommonSimUtils.get_sim_id(sim_info) - log.debug(f'{sim_info} Interactions ({sim_id})') - log.debug(text) - CommonBasicNotification( - CommonLocalizationUtils.create_localized_string(f'{sim_info} Interactions ({sim_id})'), - CommonLocalizationUtils.create_localized_string(text) - ).show( - icon=IconInfoData(obj_instance=CommonSimUtils.get_sim_instance(sim_info)) - ) - finally: - log.disable() diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_inventory_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_inventory_utils.py deleted file mode 100644 index deb4fc8..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_inventory_utils.py +++ /dev/null @@ -1,396 +0,0 @@ -""" -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 -""" -from typing import Callable, Iterator, Union, Tuple -from interactions.base.create_object_interaction import ObjectDefinition -from objects.components.sim_inventory_component import SimInventoryComponent -from objects.game_object import GameObject -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.classes.math.common_location import CommonLocation -from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from s4ap.sims4communitylib.enums.types.component_types import CommonComponentType -from s4ap.sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ - CommonConsoleCommandArgument -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.common_component_utils import CommonComponentUtils -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from s4ap.sims4communitylib.utils.objects.common_object_spawn_utils import CommonObjectSpawnUtils -from s4ap.sims4communitylib.utils.objects.common_object_utils import CommonObjectUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - - -class CommonSimInventoryUtils(_HasS4CLClassLog): - """ Utilities for manipulating the inventory of Sims. """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 's4cl_sim_inventory_utils' - - @classmethod - def has_inventory(cls, sim_info: SimInfo) -> bool: - """has_inventory(sim_info) - - Determine if a Sim has an inventory. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: True, if the Sim has an inventory. False, if not. - :rtype: bool - """ - return cls.get_inventory(sim_info) is not None - - @classmethod - def get_inventory(cls, sim_info: SimInfo) -> Union[SimInventoryComponent, None]: - """get_inventory(sim_info) - - Retrieve the inventory of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The inventory component of the Sim or None if not found. - :rtype: Union[SimInventoryComponent, None] - """ - return cls._get_inventory(sim_info) - - @classmethod - def get_objects_in_inventory_by_definition_ids_gen(cls, sim_info: SimInfo, object_definition_ids: Tuple[int], include_object_callback: Callable[[GameObject], bool] = None) -> Iterator[GameObject]: - """get_objects_in_inventory_by_definition_id_gen(sim_info, object_definition_ids, include_object_callback=None) - - Retrieve all Objects in the inventory of a Sim that match the definition ids. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param object_definition_ids: The Definition IDs of the objects to locate. - :type object_definition_ids: Tuple[int] - :param include_object_callback: If the result of this callback is True, the object will be included in the results. If set to None, All objects in the inventory will be included. - :type include_object_callback: Callable[[int], bool], optional - :return: An iterator containing the decimal identifiers for the objects in the inventory of a Sim. - :rtype: Iterator[GameObject] - """ - log = cls.get_log() - log.format_with_message('Getting objects in inventory', sim=sim_info, object_definition_ids=object_definition_ids) - for game_object in cls.get_all_objects_in_inventory_gen(sim_info, include_object_callback=include_object_callback): - definition_id = CommonObjectUtils.get_object_definition_id(game_object) - log.format_with_message('Got definition id.', definition_id=definition_id, game_object=game_object) - if definition_id in object_definition_ids: - log.format_with_message('Definition found in objects.', definition_id=definition_id) - yield game_object - else: - log.format_with_message('Definition not found.', definition_id=definition_id) - - @classmethod - def get_objects_in_inventory_by_definition_id_gen(cls, sim_info: SimInfo, object_definition_id: int, include_object_callback: Callable[[GameObject], bool] = None) -> Iterator[GameObject]: - """get_objects_in_inventory_by_definition_id_gen(sim_info, object_definition_id, include_object_callback=None) - - Retrieve all Objects in the inventory of a Sim that match the definition id. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param object_definition_id: The Definition ID of the objects to locate. - :type object_definition_id: int - :param include_object_callback: If the result of this callback is True, the object will be included in the results. If set to None, All objects in the inventory will be included. - :type include_object_callback: Callable[[int], bool], optional - :return: An iterator containing the decimal identifiers for the objects in the inventory of a Sim. - :rtype: Iterator[GameObject] - """ - yield from cls.get_objects_in_inventory_by_definition_ids_gen(sim_info, (object_definition_id,), include_object_callback=include_object_callback) - - @classmethod - def get_all_objects_in_inventory_gen(cls, sim_info: SimInfo, include_object_callback: Callable[[GameObject], bool] = None) -> Iterator[GameObject]: - """get_all_objects_in_inventory_gen(sim_info, include_object_callback=None) - - Retrieve all Objects in the inventory of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param include_object_callback: If the result of this callback is True, the object will be included in the results. If set to None, All objects in the inventory will be included. - :type include_object_callback: Callable[[int], bool], optional - :return: An iterator containing the decimal identifiers for the objects in the inventory of a Sim. - :rtype: Iterator[GameObject] - """ - inventory_component: SimInventoryComponent = cls.get_inventory(sim_info) - if inventory_component is None: - return tuple() - if include_object_callback is None: - for inventory_object in inventory_component: - yield inventory_object - else: - for inventory_object in inventory_component: - if include_object_callback(inventory_object): - yield inventory_object - - @classmethod - def add_to_inventory(cls, sim_info: SimInfo, object_definition_id: int, count: int = 1, on_added: Callable[[GameObject], None] = CommonFunctionUtils.noop) -> CommonExecutionResult: - """add_to_inventory(sim_info, object_definition_id, count=1, on_added=CommonFunctionUtils.noop) - - Add a number of Newly Created Objects to the Inventory of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param object_definition_id: The decimal identifier of an Object. - :type object_definition_id: int - :param count: The number of the specified Object to add. Default is 1. - :type count: int, optional - :param on_added: A callback invoked when the object is added to the inventory. - :type on_added: Callable[[GameObject], None] - :return: True, if the count of the specified Object were added successfully. False, it not. - :rtype: CommonExecutionResult - """ - if not CommonSimInventoryUtils.has_inventory(sim_info): - return CommonExecutionResult(False, reason=f'{sim_info} has no inventory.') - - def _post_create(_game_object: GameObject) -> bool: - move_result = CommonSimInventoryUtils.move_object_to_inventory(sim_info, _game_object) - on_added(_game_object) - return move_result - - success = CommonExecutionResult.TRUE - count = int(count) - for _ in range(count): - game_object = CommonObjectSpawnUtils.spawn_object_on_lot(object_definition_id, CommonLocation.empty(), post_object_spawned_callback=_post_create) - if game_object is None: - success = CommonExecutionResult(False, reason=f'Failed to create object {object_definition_id}') - return success - - @classmethod - def remove_from_inventory(cls, sim_info: SimInfo, object_id: int, count: int = 1) -> bool: - """remove_from_inventory(sim_info, object_id, count=1) - - Remove a number of Objects from the inventory of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param object_id: The decimal identifier of an Object. - :type object_id: int - :param count: The amount of the Object to remove. Default is 1. - :type count: int, optional - :return: True, if the count of the specified Object were removed successfully. False, if not. - """ - inventory_component: SimInventoryComponent = cls.get_inventory(sim_info) - if inventory_component is None: - return False - return inventory_component.try_remove_object_by_id(object_id, count=count) - - @classmethod - def remove_from_inventory_by_definition(cls, sim_info: SimInfo, object_definition: ObjectDefinition, count: int = 1) -> bool: - """remove_from_inventory(sim_info, object_id, count=1) - - Remove a number of Objects from the inventory of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param object_definition: The definition of an Object. - :type object_definition: ObjectDefinition - :param count: The amount of the Object to remove. Default is 1. - :type count: int, optional - :return: True, if the count of the specified Object were removed successfully. False, if not. - """ - def _include_object_callback(_game_object: GameObject) -> bool: - return _game_object.definition == object_definition - - inventory_objects = CommonSimInventoryUtils.get_all_objects_in_inventory_gen(sim_info, include_object_callback=_include_object_callback) - for inventory_object in inventory_objects: - object_id = CommonObjectUtils.get_object_id(inventory_object) - if CommonSimInventoryUtils.remove_from_inventory(sim_info, object_id, count=count): - return True - return False - - @classmethod - def move_object_to_inventory(cls, sim_info: SimInfo, game_object: GameObject) -> bool: - """move_object_to_inventory(sim_info, game_object) - - Move an Object to the inventory of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param game_object: An instance of an Object. - :type game_object: GameObject - :return: True, if the object was successfully moved to the inventory of the specified Sim. False, if not. - :rtype: bool - """ - inventory_component: SimInventoryComponent = cls.get_inventory(sim_info) - if inventory_component is None: - return False - from s4ap.sims4communitylib.utils.objects.common_object_ownership_utils import CommonObjectOwnershipUtils - CommonObjectOwnershipUtils.set_owning_sim(game_object, sim_info) - return inventory_component.player_try_add_object(game_object) - - @classmethod - def move_objects_to_inventory(cls, sim_info: SimInfo, game_objects: Tuple[GameObject]) -> bool: - """move_objects_to_inventory(sim_info, game_objects) - - Move Objects to the inventory of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param game_objects: A collection of Object instances. - :type game_objects: GameObject - :return: True, if all objects were successfully moved to the inventory of the specified Sim. False, if not. - :rtype: bool - """ - if not game_objects: - return False - successfully_moved_all = True - for game_object in game_objects: - if not CommonSimInventoryUtils.move_object_to_inventory(sim_info, game_object): - successfully_moved_all = False - return successfully_moved_all - - @classmethod - def get_count_of_object_in_inventory(cls, sim_info: SimInfo, object_id: int) -> int: - """get_count_of_object_in_inventory(sim_info, object_id) - - Count the number of an Object in the inventory of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param object_id: The decimal identifier of an object. - :type object_id: int - :return: The number of the specified Object in the inventory of the specified Sim. - :type: int - """ - inventory_component: SimInventoryComponent = cls.get_inventory(sim_info) - if inventory_component is None: - return 0 - object_definition = CommonObjectUtils.get_object_definition(object_id) - return inventory_component.get_count(object_definition) - - @classmethod - def make_inventory_visible(cls, sim_info: SimInfo) -> bool: - """make_inventory_visible(sim_info) - - Change the flags of the inventory of a Sim so that it becomes visible to the player. - - .. note:: A Sim needs to be Instances in order to have an inventory to make visible. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: True, if the inventory of the specified Sim was made visible. False, if not. - :rtype: bool - """ - if sim_info is None: - return False - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return False - inventory_component: SimInventoryComponent = cls.get_inventory(sim_info) - if inventory_component is None: - return False - if inventory_component.visible_storage is None: - return False - inventory_component.visible_storage.allow_ui = True - inventory_component.publish_inventory_items() - sim.ui_manager.refresh_ui_data() - return True - - @classmethod - def make_inventory_hidden(cls, sim_info: SimInfo) -> bool: - """make_inventory_hidden(sim_info) - - Change the flags of the inventory of a Sim so that it becomes hidden to the player. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: True, if the inventory of the specified Sim was made hidden. False, if not. - :rtype: bool - """ - if sim_info is None: - return False - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return True - inventory_component: SimInventoryComponent = cls.get_inventory(sim_info) - if inventory_component is None: - return True - if inventory_component.visible_storage is None: - return True - inventory_component.visible_storage.allow_ui = False - inventory_component.publish_inventory_items() - sim.ui_manager.refresh_ui_data() - return True - - @classmethod - def open_inventory(cls, sim_info: SimInfo) -> None: - """open_inventory(sim_info) - - Open the inventory of a Sim. - - :param sim_info: The Sim to open the inventory of. - :type sim_info: SimInfo - """ - if sim_info is None: - return - inventory_component: SimInventoryComponent = cls.get_inventory(sim_info) - if inventory_component is None: - return - if not CommonSimInventoryUtils.make_inventory_visible(sim_info): - return - inventory_component.open_ui_panel() - - @classmethod - def set_ownership_of_all_items_in_sim_inventory_to_sim(cls, sim_info_a: SimInfo, sim_info_b: SimInfo) -> bool: - """set_ownership_of_all_items_in_sim_inventory_to_sim(sim_info_a, sim_info_b) - - Change the ownership status of all items in the inventory of Sim A to be owned by the household of Sim B - - :param sim_info_a: The objects in the inventory of this Sim will become owned by the household of Sim B - :type sim_info_a: SimInfo - :param sim_info_b: The household of this Sim will be the new owner for all items in the inventory of Sim A. - :type sim_info_b: SimInfo - :return: True, if ownership was transferred successfully. False, if not. - :rtype: bool - """ - if sim_info_a is None or sim_info_b is None: - return False - if not CommonSimInventoryUtils.make_inventory_visible(sim_info_a): - return False - inventory_component: SimInventoryComponent = cls.get_inventory(sim_info_a) - if inventory_component is None: - return False - from s4ap.sims4communitylib.utils.objects.common_object_ownership_utils import CommonObjectOwnershipUtils - for inventory_object in inventory_component: - inventory_object: GameObject = inventory_object - CommonObjectOwnershipUtils.set_owning_sim(inventory_object, sim_info_b) - return True - - @classmethod - def _get_inventory(cls, sim_info: SimInfo) -> Union[SimInventoryComponent, None]: - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return None - return CommonComponentUtils.get_component(sim, CommonComponentType.INVENTORY) - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.add_object_to_inventory', - 'Add an Object to the inventory of a Sim.', - command_arguments=( - CommonConsoleCommandArgument('object_definition_id', 'Decimal Identifier', 'The decimal identifier of the Object Definition for the object to add.'), - CommonConsoleCommandArgument('count', 'Positive Number', 'The number of objects to add.', is_optional=True, default_value=1), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to add the object to.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.addtosim', - ) -) -def _s4clib_testing_add_object_to_inventory(output: CommonConsoleCommandOutput, object_definition_id: int, count: int = 1, sim_info: SimInfo = None): - if object_definition_id < 0: - output('ERROR: Object Definition Id must be a positive number.') - return - if count <= 0: - output('ERROR: count must be greater than zero.') - return - output(f'Attempting to add object with definition id \'{object_definition_id}\' to the inventory of Sim {sim_info}.') - if CommonSimInventoryUtils.add_to_inventory(sim_info, object_definition_id, count): - output(f'SUCCESS: Successfully added object with definition id {object_definition_id} to Sim {sim_info}') - else: - output(f'FAILED: Failed to add object with definition id {object_definition_id} to Sim {sim_info}') - output('Done adding object to the inventory of the Sim.') diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_location_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_location_utils.py deleted file mode 100644 index ab3d750..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_location_utils.py +++ /dev/null @@ -1,770 +0,0 @@ -""" -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 -""" -import os - -from typing import Union - -from objects.script_object import ScriptObject -from s4ap.sims4communitylib.classes.math.common_location import CommonLocation -from s4ap.sims4communitylib.classes.math.common_quaternion import CommonQuaternion -from s4ap.sims4communitylib.classes.math.common_routing_location import CommonRoutingLocation -from s4ap.sims4communitylib.classes.math.common_surface_identifier import CommonSurfaceIdentifier -from s4ap.sims4communitylib.classes.math.common_transform import CommonTransform -from s4ap.sims4communitylib.classes.math.common_vector3 import CommonVector3 -from s4ap.sims4communitylib.classes.testing.common_enqueue_result import CommonEnqueueResult -from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ - CommonConsoleCommandArgument -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.location.common_location_utils import CommonLocationUtils -from s4ap.sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils -from s4ap.sims4communitylib.utils.sims.common_sim_interaction_utils import CommonSimInteractionUtils -from s4ap.sims4communitylib.utils.sims.common_sim_type_utils import CommonSimTypeUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - - -ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' - -if ON_RTD: - # noinspection PyMissingOrEmptyDocstring - class AutonomyComponent: - pass - - # noinspection PyMissingOrEmptyDocstring - class TestResult: - pass - - # noinspection PyMissingOrEmptyDocstring - class RoutingContext: - pass - - # noinspection PyMissingOrEmptyDocstring - class PickType: - pass - - # noinspection PyMissingOrEmptyDocstring - class FGLSearchFlagsDefault: - pass - - # noinspection PyMissingOrEmptyDocstring - class FGLSearchFlag: - STAY_IN_CURRENT_BLOCK = 0 - - # noinspection PyMissingOrEmptyDocstring - class Lot: - pass - - # noinspection PyMissingOrEmptyDocstring - class SimInfo: - pass - -if not ON_RTD: - from autonomy.autonomy_component import AutonomyComponent - import routing - from routing import RoutingContext - import objects.terrain - from server.pick_info import PickType - from placement import FGLSearchFlagsDefault, FGLSearchFlag - from world.lot import Lot - from sims.sim_info import SimInfo - - -class CommonSimLocationUtils: - """Utilities for manipulating the locations of Sims. - - """ - @staticmethod - def get_position(sim_info: SimInfo) -> Union[CommonVector3, None]: - """get_position(sim_info) - - Retrieve the current position of a Sim. - - :param sim_info: The Sim to get the position of. - :type sim_info: SimInfo - :return: The current position of the Sim or None if the Sim does not have a position. - :rtype: Union[CommonVector3, None] - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return None - # noinspection PyBroadException - try: - return CommonVector3.from_vector3(sim.position) - except: - return None - - @staticmethod - def set_location(sim_info: SimInfo, location: CommonLocation) -> bool: - """set_location(sim_info, location) - - Set the location of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param location: The location to put the Sim. - :type location: CommonLocation - :return: True, if the location of the Sim is successfully set. False, if not. - :rtype: bool - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None or location is None: - return False - # noinspection PyBroadException - try: - sim.location = location - except: - return False - return True - - @staticmethod - def get_location(sim_info: SimInfo) -> Union[CommonLocation, None]: - """get_location(sim_info) - - Retrieve the current location of a Sim. - - :param sim_info: The Sim to get the location of. - :type sim_info: SimInfo - :return: The current location of the Sim or None if the Sim does not have a location. - :rtype: Union[CommonLocation, None] - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return None - # noinspection PyBroadException - try: - return CommonLocation.from_location(sim.location) - except: - return None - - @staticmethod - def get_routing_location(sim_info: SimInfo) -> Union[CommonRoutingLocation, None]: - """get_routing_location(sim_info) - - Retrieve a routing location for the current location of a Sim. - - :param sim_info: The Sim to get the location of. - :type sim_info: SimInfo - :return: The routing location for the current location of the Sim or None if the Sim does not have a location. - :rtype: Union[CommonRoutingLocation, None] - """ - sim_location = CommonSimLocationUtils.get_location(sim_info) - if sim_location is None: - return None - return CommonRoutingLocation(sim_location.transform.translation, orientation=sim_location.transform.orientation, routing_surface=sim_location.routing_surface) - - @staticmethod - def get_orientation(sim_info: SimInfo) -> CommonQuaternion: - """get_orientation(sim_info) - - Retrieve the orientation of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The orientation of the Sim. - :rtype: CommonQuaternion - """ - if sim_info is None: - return CommonQuaternion.empty() - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return CommonQuaternion.empty() - return CommonQuaternion.from_quaternion(sim.orientation) - - @staticmethod - def get_orientation_degrees(sim_info: SimInfo) -> float: - """get_orientation_degrees(sim_info) - - Retrieve the orientation of a Sim represented in degrees. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The orientation of the Sim represented in degrees. - :rtype: float - """ - return CommonQuaternion.to_degrees(CommonSimLocationUtils.get_orientation(sim_info)) - - @staticmethod - def get_routing_surface(sim_info: SimInfo) -> Union[CommonSurfaceIdentifier, None]: - """get_routing_surface(sim_info) - - Retrieve the Routing Surface Identifier of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The Routing Surface Identifier of the specified Sim or None if a problem occurs. - :rtype: Union[CommonSurfaceIdentifier, None] - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return None - - return CommonSurfaceIdentifier.from_surface_identifier(sim.routing_surface) - - @staticmethod - def get_surface_level(sim_info: SimInfo) -> int: - """get_surface_level(sim_info) - - Retrieve the Surface Level of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The Surface Level of the specified Sim or 0 if a problem occurs. - :rtype: int - """ - routing_surface = CommonSimLocationUtils.get_routing_surface(sim_info) - if routing_surface is None: - return 0 - return routing_surface.secondary_id - - @staticmethod - def get_forward_vector(sim_info: SimInfo) -> CommonVector3: - """get_forward_vector(sim_info) - - Retrieve the forward vector of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The forward vector of the Sim. - :rtype: CommonVector3 - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return CommonVector3.empty() - return CommonVector3.from_vector3(sim.forward) - - @staticmethod - def get_routing_context(sim_info: SimInfo) -> Union[RoutingContext, None]: - """get_routing_context(sim_info) - - Retrieve the routing context of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The routing context of the specified Sim or None if an error occurs. - :rtype: Union[RoutingContext, None] - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return None - return sim.routing_context - - @staticmethod - def can_swim_at_location(sim_info: SimInfo, location: CommonLocation) -> bool: - """can_swim_at_location(sim_info, location) - - Determine if a Sim can swim at the specified location. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :param location: The Location to check. - :type location: CommonLocation - :return: True, if the Sim can swim at the specified location. False, if not. - :rtype: bool - """ - if location is None: - return False - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return False - return sim.should_be_swimming_at_position(location.transform.translation, location.routing_surface.secondary_id) - - @staticmethod - def can_swim_at_current_location(sim_info: SimInfo) -> bool: - """can_swim_at_current_location(sim_info) - - Determine if a Sim can swim at their current location. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim can swim at their current location. False, if not. - :rtype: bool - """ - location = CommonSimLocationUtils.get_location(sim_info) - return CommonSimLocationUtils.can_swim_at_location(sim_info, location) - - @staticmethod - def can_route_to_location(sim_info: SimInfo, location: CommonLocation) -> bool: - """can_route_to_location(sim_info, location) - - Determine if a Sim can route to a Location. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param location: The location to route to. - :type location: CommonLocation - :return: True, if the Sim can route to the specified Location. False, if not. - :rtype: bool - """ - sim_routing_location = CommonSimLocationUtils.get_routing_location(sim_info) - if sim_routing_location is None: - return False - sim_routing_context = CommonSimLocationUtils.get_routing_context(sim_info) - if sim_routing_context is None: - return False - return routing.test_connectivity_pt_pt(sim_routing_location, CommonRoutingLocation.from_location(location), sim_routing_context) - - @staticmethod - def can_route_to_position(sim_info: SimInfo, position: CommonVector3, routing_surface: CommonSurfaceIdentifier, orientation: CommonQuaternion = CommonQuaternion.empty()) -> bool: - """can_route_to_position(sim_info, position, routing_surface) - - Determine if a Sim can route to a Location. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param position: The position to route to. - :type position: CommonVector3 - :param routing_surface: The routing surface of the target. - :type routing_surface: CommonSurfaceIdentifier - :param orientation: The orientation of the position. Default is CommonQuaternion.empty(). - :type orientation: CommonQuaternion, optional - :return: True, if the Sim can route to the specified Position. False, if not. - :rtype: bool - """ - location = CommonLocation( - CommonTransform( - position, - orientation or CommonQuaternion.empty() - ), - routing_surface - ) - return CommonSimLocationUtils.can_route_to_location(sim_info, location) - - @staticmethod - def can_route_to_object(sim_info: SimInfo, script_object: ScriptObject) -> bool: - """can_route_to_object(sim_info, game_object) - - Determine if a Sim can route to an Object. - - .. note:: This function will account for locked doors as well. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param script_object: The Object to check. - :type script_object: ScriptObject - :return: True, if the Sim can route to the Object. False, if not. - :rtype: bool - """ - if sim_info is None or script_object is None: - return False - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return False - if sim.posture is None: - return False - return script_object.is_connected(sim) - - # noinspection PyUnusedLocal - @staticmethod - def can_route_to_sim(sim_info_a: SimInfo, sim_info_b: SimInfo) -> bool: - """can_route_to_sim(sim_info, game_object) - - Determine if Sim A can route to Sim B. - - :param sim_info_a: The Sim that would be routing to Sim B. - :type sim_info_a: SimInfo - :param sim_info_b: The Sim that Sim A would be routing to. - :type sim_info_b: SimInfo - :return: True, if Sim A can route to Sim B. False, if not. - :rtype: bool - """ - if sim_info_a is None or sim_info_b is None: - return False - sim_b = CommonSimUtils.get_sim_instance(sim_info_b) - if sim_b is None: - return False - return CommonSimLocationUtils.can_route_to_object(sim_info_a, sim_b) - - @staticmethod - def is_within_range_of_position(sim_info: SimInfo, position: CommonVector3, distance_in_squares: float) -> bool: - """is_within_range_of_position(sim_info, position, distance_in_squares) - - Determine if a Sim is within a certain distance of a Position. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :param position: A position. - :type position: CommonVector3 - :param distance_in_squares: A unit measured in squares. 1 square is the size of 1 square in the Build/Buy mode visual grid. For comparison, a dining chair would be 1 square by 1 square. 0.5 would be half a square, or half a dining chair. - :type distance_in_squares: float - :return: True, if the distance between the Sim and the Position is less than or equal to the specified distance in squares. False, if not. - :return: bool - """ - sim_position = CommonSimLocationUtils.get_position(sim_info) - if sim_position is None: - return False - return CommonLocationUtils.is_position_within_range_of_position(sim_position, position, distance_in_squares) - - @staticmethod - def is_within_range_of_location(sim_info: SimInfo, location: CommonLocation, distance_in_squares: float) -> bool: - """is_within_range_of_location(sim_info, location, distance_in_squares) - - Determine if a Sim is within a certain distance of a Location. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :param location: A location. - :type location: CommonLocation - :param distance_in_squares: A unit measured in squares. 1 square is the size of 1 square in the Build/Buy mode visual grid. For comparison, a dining chair would be 1 square by 1 square. 0.5 would be half a square, or half a dining chair. - :type distance_in_squares: float - :return: True, if the distance between the Sim and the Location is less than or equal to the specified distance in squares. False, if not. - :return: bool - """ - sim_location = CommonSimLocationUtils.get_location(sim_info) - if sim_location is None: - return False - return CommonLocationUtils.is_location_within_range_of_location(sim_location, location, distance_in_squares) - - @staticmethod - def is_on_current_lot(sim_info: SimInfo) -> bool: - """is_on_current_lot(sim_info) - - Determine if a Sim is on the active Lot. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is on the active Lot. False, if not. - :rtype: bool - """ - active_lot = CommonLocationUtils.get_current_lot() - return CommonSimLocationUtils.is_on_lot(sim_info, active_lot) - - @staticmethod - def is_on_lot(sim_info: SimInfo, lot: Lot) -> bool: - """is_on_lot(sim_info, lot) - - Determine if a Sim is on a Lot. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param lot: An instance of a Lot. - :type lot: Lot - :return: True, if the Sim is on the specified Lot. False, if not. - :rtype: bool - """ - sim_position = CommonSimLocationUtils.get_position(sim_info) - if sim_position is None: - return False - return CommonLocationUtils.is_position_on_lot(sim_position, lot) - - @staticmethod - def is_renting_current_lot(sim_info: SimInfo) -> bool: - """is_renting_current_lot(sim_info) - - Determine if a Sim is renting the current lot. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is renting the active lot. False, if not. - :rtype: bool - """ - return sim_info.is_renting_zone(CommonLocationUtils.get_current_zone_id()) - - @staticmethod - def is_at_home(sim_info: SimInfo) -> bool: - """is_at_home(sim_info) - - Determine if a Sim is on their home Lot. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is on their home Lot. False, if not. - :rtype: bool - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None or not CommonHouseholdUtils.has_household(sim_info): - return False - return sim.on_home_lot or (CommonLocationUtils.get_current_zone_id() == CommonHouseholdUtils.get_household_zone_id(sim_info) and CommonSimLocationUtils.is_on_current_lot(sim_info)) - - @staticmethod - def is_outside(sim_info: SimInfo) -> bool: - """is_outside(sim_info) - - Determine if a Sim is currently outside. - - :param sim_info: The info of a Sim. - :type sim_info: SimInfo - :return: True, if the Sim is outside. False, if not. - :rtype: bool - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return False - return sim.is_outside - - @classmethod - def is_inside(cls, sim_info: SimInfo) -> bool: - """is_inside(sim_info) - - Determine if a Sim is currently inside. - - :param sim_info: The info of a Sim. - :type sim_info: SimInfo - :return: True, if the Sim is inside. False, if not. - :rtype: bool - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return False - return not sim.is_outside - - @classmethod - def is_inside_building(cls, sim_info: SimInfo) -> bool: - """is_inside_building(sim_info) - - Determine if a Sim is currently inside a building. - - :param sim_info: The info of a Sim. - :type sim_info: SimInfo - :return: True, if the Sim is inside a building. False, if not. - :rtype: bool - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return False - return not sim.is_inside_building - - @classmethod - def is_in_shade(cls, sim_info: SimInfo) -> bool: - """is_in_shade(sim_info) - - Determine if a Sim is currently in the shade. - - :param sim_info: The info of a Sim. - :type sim_info: SimInfo - :return: True, if the Sim is in the shade. False, if not. - :rtype: bool - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return False - return not sim.is_in_shade - - @staticmethod - def send_to_position(sim_info: SimInfo, position: CommonVector3, level: int, go_here_interaction_id: int = None) -> CommonEnqueueResult: - """send_to_position(sim_info, position, level, go_here_interaction_id=None) - - Send a Sim to the specified position. - - :param sim_info: The Sim to send. - :type sim_info: SimInfo - :param position: The position to send the sim to. - :type position: CommonVector3 - :param level: The level at which the position is located. - :type level: int - :param go_here_interaction_id: If supplied, this interaction will be used instead of the vanilla Go Here interaction. Default is None. - :type go_here_interaction_id: int, optional - :return: The result of sending the Sim to the specified position. - :rtype: CommonEnqueueResult - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return CommonEnqueueResult(CommonTestResult(False, reason='No Sim was specified to be sent.'), CommonExecutionResult.NONE) - from server_commands.sim_commands import _build_terrain_interaction_target_and_context, CommandTuning - if position is None: - return CommonEnqueueResult(CommonTestResult(False, reason='No Position specified to send the Sim to!'), CommonExecutionResult.NONE) - routing_surface = CommonSurfaceIdentifier.empty(secondary_id=level) - (target, context) = _build_terrain_interaction_target_and_context(sim, position, routing_surface, PickType.PICK_TERRAIN, objects.terrain.TerrainPoint) - if go_here_interaction_id is not None: - return CommonSimInteractionUtils.queue_interaction(sim_info, go_here_interaction_id, target=target, interaction_context=context) - return sim.push_super_affordance(CommandTuning.TERRAIN_GOHERE_AFFORDANCE, target, context) - - @staticmethod - def send_near_position(sim_info: SimInfo, position: CommonVector3, level: int, go_here_interaction_id: int = None, position_search_flags: FGLSearchFlag = FGLSearchFlag.STAY_IN_CURRENT_BLOCK) -> CommonEnqueueResult: - """send_near_position(sim_info, position, level, go_here_interaction_id=None, position_search_flags=FGLSearchFlag.STAY_IN_CURRENT_BLOCK) - - Send a Sim near the specified position. - - :param sim_info: The Sim to send. - :type sim_info: SimInfo - :param position: The position to send the sim to. - :type position: CommonVector3 - :param level: The level at which the position is located. - :type level: int - :param go_here_interaction_id: If supplied, this interaction will be used instead of the vanilla Go Here interaction. Default is None. - :type go_here_interaction_id: int, optional - :param position_search_flags: Flags used when locating a nearby position. Default is FGLSearchFlag.STAY_IN_CURRENT_BLOCK, which will limit the search to the current Room. - :type position_search_flags: FGLSearchFlag, optional - :return: The result of sending the Sim near the specified position. - :rtype: CommonEnqueueResult - """ - if position is None: - return CommonEnqueueResult(CommonTestResult(False, reason='No Position specified to send the Sim to!'), CommonExecutionResult.NONE) - - transform = CommonTransform(position, CommonQuaternion.empty()) - location = CommonLocation(transform, CommonSurfaceIdentifier.empty(secondary_id=level)) - return CommonSimLocationUtils.send_near_location(sim_info, location, go_here_interaction_id=go_here_interaction_id, location_search_flags=position_search_flags) - - @staticmethod - def send_to_location(sim_info: SimInfo, location: CommonLocation, go_here_interaction_id: int = None) -> CommonEnqueueResult: - """send_to_location(sim_info, location, go_here_interaction_id=None) - - Send a Sim to the specified location. - - :param sim_info: The Sim to send. - :type sim_info: SimInfo - :param location: The location to send the sim near to. - :type location: CommonLocation - :param go_here_interaction_id: If supplied, this interaction will be used instead of the vanilla Go Here interaction. Default is None. - :type go_here_interaction_id: int, optional - :return: The result of sending the Sim to the specified location. - :rtype: CommonEnqueueResult - """ - if location is None: - return CommonEnqueueResult(CommonTestResult(False, reason='No Location specified to send the Sim to!'), CommonExecutionResult.NONE) - - position = location.transform.translation - level = location.routing_surface.secondary_id - return CommonSimLocationUtils.send_to_position(sim_info, position, level, go_here_interaction_id=go_here_interaction_id) - - @staticmethod - def send_near_location(sim_info: SimInfo, location: CommonLocation, go_here_interaction_id: int = None, location_search_flags: FGLSearchFlag = FGLSearchFlag.STAY_IN_CURRENT_BLOCK) -> CommonEnqueueResult: - """send_near_location(sim_info, location, go_here_interaction_id=None, location_search_flags=FGLSearchFlag.STAY_IN_CURRENT_BLOCK) - - Send a Sim near the specified location. - - :param sim_info: The Sim to send. - :type sim_info: SimInfo - :param location: The location to send the sim near to. - :type location: CommonLocation - :param go_here_interaction_id: If supplied, this interaction will be used instead of the vanilla Go Here interaction. Default is None. - :type go_here_interaction_id: int, optional - :param location_search_flags: Flags used when locating a nearby location. Default is FGLSearchFlag.STAY_IN_CURRENT_BLOCK, which will limit the search to the current Room. - :type location_search_flags: FGLSearchFlag, optional - :return: The result of sending the Sim near the specified location. - :rtype: CommonEnqueueResult - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return CommonEnqueueResult(CommonTestResult(False, reason='No Sim was specified to be sent.'), CommonExecutionResult.NONE) - if location is None: - return CommonEnqueueResult(CommonTestResult(False, reason='No Location specified to send the Sim to!'), CommonExecutionResult.NONE) - from placement import find_good_location, create_starting_location, create_fgl_context_for_sim - routing_surface = location.routing_surface - starting_location = create_starting_location(transform=location.transform, routing_surface=routing_surface) - fgl_context = create_fgl_context_for_sim(starting_location, sim, search_flags=(FGLSearchFlagsDefault | location_search_flags) if location_search_flags is not None and location_search_flags != FGLSearchFlag.NONE else FGLSearchFlagsDefault) - (position, orientation) = find_good_location(fgl_context) - if position is None or orientation is None: - fgl_context = create_fgl_context_for_sim(starting_location, sim) - (position, orientation) = find_good_location(fgl_context) - if position is not None and orientation is not None: - transform = CommonTransform(position, orientation) - location = CommonLocation(transform, starting_location.routing_surface) - - position = location.transform.translation - level = location.routing_surface.secondary_id - return CommonSimLocationUtils.send_to_position(sim_info, position, level, go_here_interaction_id=go_here_interaction_id) - - @staticmethod - def is_allowed_on_current_lot(sim_info: SimInfo) -> bool: - """is_allowed_on_current_lot(sim_info) - - Determine if a Sim is allowed on the current lot. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is allowed on the current lot. False, if not. - :rtype: bool - """ - from s4ap.sims4communitylib.utils.common_component_utils import CommonComponentUtils - from s4ap.sims4communitylib.enums.types.component_types import CommonComponentType - from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - if CommonSimLocationUtils.is_at_home(sim_info): - return True - if CommonSimLocationUtils.is_renting_current_lot(sim_info): - return True - if CommonSimTypeUtils.is_player_sim(sim_info) and (CommonLocationUtils.current_venue_allows_role_state_routing() or not CommonLocationUtils.current_venue_requires_player_greeting()): - return True - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return False - # noinspection PyTypeChecker - autonomy_component: AutonomyComponent = CommonComponentUtils.get_component(sim, CommonComponentType.AUTONOMY) - if autonomy_component is None or not hasattr(autonomy_component, 'active_roles'): - return False - for role_state_instance in autonomy_component.active_roles(): - if CommonSimTypeUtils.is_non_player_sim(sim_info): - if role_state_instance._portal_disallowance_tags or not role_state_instance._allow_npc_routing_on_active_lot: - return False - elif role_state_instance._portal_disallowance_tags: - return False - return True - - @classmethod - def get_current_room_id(cls, sim_info: SimInfo) -> int: - """get_current_room_id(sim_info) - - Retrieve the id of the room a Sim is currently in. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The id of the room the Sim is currently in or -1 if their room is not found. - :rtype: int - """ - if sim_info is None: - return -1 - return CommonLocationUtils.get_block_id_in_current_zone( - CommonSimLocationUtils.get_position(sim_info), - CommonSimLocationUtils.get_surface_level(sim_info) - ) - - @classmethod - def are_in_same_room(cls, sim_info_a: SimInfo, sim_info_b: SimInfo) -> bool: - """are_in_same_room(sim_info_a, sim_info_b) - - Determine if two Sims are in the same room. - - .. note:: The entirety of "Outside" is considered the same "Room", so if both Sims are outside, this function will return True. - - :param sim_info_a: An instance of a Sim. - :type sim_info_a: SimInfo - :param sim_info_b: An instance of a Sim. - :type sim_info_b: SimInfo - :return: True, if Sim A is in the same room as Sim B. False, if not. - :rtype: bool - """ - if sim_info_a is None or sim_info_b is None: - return False - source_block_id = cls.get_current_room_id(sim_info_a) - target_block_id = cls.get_current_room_id(sim_info_b) - return source_block_id == target_block_id - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_testing.print_room_id', - 'Print the id of the room the Sim is currently in.', - command_arguments=( - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to check.', is_optional=True, default_value='Active Sim'), - ), - show_with_help_command=False -) -def _common_print_room_id(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): - room_id = CommonSimLocationUtils.get_current_room_id(sim_info) - output(f'The current room id of {sim_info} is: {room_id}') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_testing.print_is_inside', - 'Print whether a Sim is considered as being inside or not.', - command_arguments=( - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to check.', is_optional=True, default_value='Active Sim'), - ), - show_with_help_command=False -) -def _common_print_room_id(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): - output(f'Printing whether {sim_info} is inside building or not.') - if sim_info is None: - return - sim = CommonSimUtils.get_sim_instance(sim_info) - is_inside_building = sim.is_inside_building - output(f'{sim_info} is Inside Building? {is_inside_building}') - interaction_counts_as_inside = sim._is_running_interaction_counts_as_inside() - output(f'{sim_info} has interaction counts as inside? {interaction_counts_as_inside}.') diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_loot_action_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_loot_action_utils.py deleted file mode 100644 index 4f93806..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_loot_action_utils.py +++ /dev/null @@ -1,124 +0,0 @@ -""" -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 -""" -from typing import Tuple - -from event_testing.resolver import SingleSimResolver, DoubleSimResolver -from interactions.utils.loot import LootActions -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.utils.resources.common_loot_action_utils import CommonLootActionUtils - - -class CommonSimLootActionUtils: - """Utilities for manipulating Loot Actions for Sims.""" - @staticmethod - def apply_loot_actions_to_sim(loot_actions: LootActions, sim_info: SimInfo) -> bool: - """apply_loot_actions_to_sim(loot_actions, sim_info) - - Apply loot actions to a Sim. - - :param loot_actions: The loot actions to apply. - :type loot_actions: LootActions - :param sim_info: The Sim to apply the loot actions to. - :type sim_info: SimInfo - :return: True, if the loot actions applied successfully. False, if not. - :rtype: bool - """ - if sim_info is None: - return False - return CommonLootActionUtils.apply_loot_actions_using_resolver(loot_actions, SingleSimResolver(sim_info)) - - @staticmethod - def apply_loot_actions_by_id_to_sim(loot_actions_id: int, sim_info: SimInfo) -> bool: - """apply_loot_actions_by_id_to_sim(loot_actions_id, sim_info) - - Apply loot actions to a Sim. - - :param loot_actions_id: The decimal identifier of a loot actions instance to apply. - :type loot_actions_id: int - :param sim_info: The Sim to apply the loot actions to. - :type sim_info: SimInfo - :return: True, if the loot actions applied successfully. False, if not. - :rtype: bool - """ - if sim_info is None: - return False - return CommonLootActionUtils.apply_loot_actions_by_id_using_resolver(loot_actions_id, SingleSimResolver(sim_info)) - - @staticmethod - def apply_loot_actions_by_ids_to_sim(loot_actions_ids: Tuple[int], sim_info: SimInfo) -> bool: - """apply_loot_actions_by_ids_to_sim(loot_actions_ids, sim_info) - - Apply loot actions to a Sim. - - :param loot_actions_ids: The decimal identifiers of the loot actions to apply. - :type loot_actions_ids: Tuple[int] - :param sim_info: The Sim to apply the loot actions to. - :type sim_info: SimInfo - :return: True, if the loot actions applied successfully. False, if not. - :rtype: bool - """ - if sim_info is None: - return False - return CommonLootActionUtils.apply_loot_actions_by_ids_using_resolver(loot_actions_ids, SingleSimResolver(sim_info)) - - @staticmethod - def apply_loot_actions_to_duo_sims(loot_actions: LootActions, sim_info_actor: SimInfo, sim_info_target: SimInfo) -> bool: - """apply_loot_actions_to_duo_sims(loot_actions, sim_info_actor, sim_info_target) - - Apply loot actions to two Sims at once. - - :param loot_actions: The loot actions to apply. - :type loot_actions: LootActions - :param sim_info_actor: The Actor Sim to apply the loot actions to. - :type sim_info_actor: SimInfo - :param sim_info_target: The Target Sim to apply the loot actions to. - :type sim_info_target: SimInfo - :return: True, if the loot actions applied successfully. False, if not. - :rtype: bool - """ - if sim_info_actor is None or sim_info_target is None: - return False - return CommonLootActionUtils.apply_loot_actions_using_resolver(loot_actions, DoubleSimResolver(sim_info_actor, sim_info_target)) - - @staticmethod - def apply_loot_actions_by_id_to_duo_sims(loot_actions_id: int, sim_info_actor: SimInfo, sim_info_target: SimInfo) -> bool: - """apply_loot_actions_by_id_to_duo_sims(loot_actions_id, sim_info_actor, sim_info_target) - - Apply loot actions by decimal identifier to two Sims at once. - - :param loot_actions_id: The decimal identifier of a loot actions instance to apply. - :type loot_actions_id: int - :param sim_info_actor: The Actor Sim to apply the loot actions to. - :type sim_info_actor: SimInfo - :param sim_info_target: The Target Sim to apply the loot actions to. - :type sim_info_target: SimInfo - :return: True, if the loot actions applied successfully. False, if not. - :rtype: bool - """ - if sim_info_actor is None or sim_info_target is None: - return False - return CommonLootActionUtils.apply_loot_actions_by_id_using_resolver(loot_actions_id, DoubleSimResolver(sim_info_actor, sim_info_target)) - - @staticmethod - def apply_loot_actions_by_ids_to_duo_sims(loot_actions_ids: Tuple[int], sim_info_actor: SimInfo, sim_info_target: SimInfo) -> bool: - """apply_loot_actions_by_id_to_duo_sims(loot_actions_ids, sim_info_actor, sim_info_target) - - Apply loot actions by decimal identifiers to two Sims at once. - - :param loot_actions_ids: The decimal identifiers of the loot actions to apply. - :type loot_actions_ids: Tuple[int] - :param sim_info_actor: The Actor Sim to apply the loot actions to. - :type sim_info_actor: SimInfo - :param sim_info_target: The Target Sim to apply the loot actions to. - :type sim_info_target: SimInfo - :return: True, if the loot actions applied successfully. False, if not. - :rtype: bool - """ - if sim_info_actor is None or sim_info_target is None: - return False - return CommonLootActionUtils.apply_loot_actions_by_ids_using_resolver(loot_actions_ids, DoubleSimResolver(sim_info_actor, sim_info_target)) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_motive_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_motive_utils.py deleted file mode 100644 index baadb57..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_motive_utils.py +++ /dev/null @@ -1,646 +0,0 @@ -""" -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 -""" -from typing import Dict, Union - -import services -from server_commands.argument_helpers import TunableInstanceParam -from sims.sim_info import SimInfo -from sims4 import commands -from sims4.resources import Types -from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.enums.common_species import CommonSpecies -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt -from s4ap.sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ - CommonConsoleCommandArgument -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.sims.common_occult_utils import CommonOccultUtils -from s4ap.sims4communitylib.utils.sims.common_sim_statistic_utils import CommonSimStatisticUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from s4ap.sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils -from s4ap.sims4communitylib.enums.motives_enum import CommonMotiveId - - -class CommonSimMotiveUtils(_HasS4CLClassLog): - """Utilities for Sim motives. - - .. note:: Motives are just another name for Sim Needs (Bladder, Hunger, Energy, etc.) - - """ - _MOTIVE_MAPPINGS: Dict[Union[CommonMotiveId, CommonInt, int], Dict[CommonSpecies, Union[CommonMotiveId, CommonInt, int]]] = None - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 'common_sim_motive_utils' - - @classmethod - def has_motive(cls, sim_info: SimInfo, motive_id: Union[CommonMotiveId, CommonInt, int]) -> CommonTestResult: - """has_motive(sim_info, motive_id) - - Determine if a Sim has the specified Motive. - - .. note:: For example, you could use this to determine if a Sim has a vampire power level. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :param motive_id: The identifier of the Motive to look for. - :type motive_id: Union[CommonMotiveId, CommonInt, int] - :return: The result of testing if the Sim has the motive. True, if the Sim has the specified Motive. False, if not. - :rtype: CommonTestResult - """ - if sim_info is None: - cls.get_log().format_with_message('sim_info was None!', motive_id=motive_id, sim=sim_info) - return CommonTestResult(False, reason='sim_info was None.') - mapped_motive_id: int = cls._map_motive_id(sim_info, motive_id) - if mapped_motive_id == -1: - cls.get_log().format_with_message('Failed to map motive id!', motive_id=motive_id, sim=sim_info) - return CommonTestResult(False, reason=f'Sim did not have a mapped motive {motive_id}') - cls.get_log().format_with_message('Mapped motive id, checking if Sim has the motive.', motive_id=motive_id, mapped_motive_id=mapped_motive_id, sim=sim_info) - return CommonSimStatisticUtils.has_statistic(sim_info, mapped_motive_id) - - @classmethod - def set_motive_level(cls, sim_info: SimInfo, motive_id: Union[CommonMotiveId, CommonInt, int], level: float) -> CommonExecutionResult: - """set_motive_level(sim_info, motive_id, level) - - Set the current level of a Motive on a Sim. - - :param sim_info: The Sim to modify. - :type sim_info: SimInfo - :param motive_id: The identifier of the Motive to change. - :type motive_id: Union[CommonMotiveId, CommonInt, int] - :param level: The amount to set the motive level to. - :type level: float - :return: The result of setting the motive level. True, if the specified Motive was changed successfully. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - cls.get_log().format_with_message('sim_info was None!', motive_id=motive_id, sim=sim_info) - return CommonExecutionResult(False, reason='sim_info was None.') - mapped_motive_id: int = cls._map_motive_id(sim_info, motive_id) - if mapped_motive_id == -1: - cls.get_log().format_with_message('Failed to map motive id!', motive_id=motive_id, sim=sim_info) - return CommonExecutionResult(False, reason=f'Sim did not have motive {motive_id}') - cls.get_log().format_with_message('Mapped motive id, setting the level for it on Sim.', motive_id=motive_id, mapped_motive_id=mapped_motive_id, level=level, sim=sim_info) - return CommonSimStatisticUtils.set_statistic_value(sim_info, mapped_motive_id, level, add=True) - - @classmethod - def get_motive_level(cls, sim_info: SimInfo, motive_id: Union[CommonMotiveId, CommonInt, int]) -> float: - """get_motive_level(sim_info, motive_id, amount) - - Retrieve the current level of a Motive of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param motive_id: The identifier of the Motive to get the value of. - :type motive_id: Union[CommonMotiveId, CommonInt, int] - :return: The current level of the motive for the specified Sim. - :rtype: float - """ - return cls._get_motive_level(sim_info, motive_id) - - @classmethod - def increase_motive_level(cls, sim_info: SimInfo, motive_id: Union[CommonMotiveId, CommonInt, int], amount: float) -> CommonExecutionResult: - """increase_motive_level(sim_info, motive_id, amount) - - Increase the current level of a Motive of a Sim. - - :param sim_info: The Sim to modify. - :type sim_info: SimInfo - :param motive_id: The identifier of the Motive to change. - :type motive_id: Union[CommonMotiveId, CommonInt, int] - :param amount: The amount to increase the motive by. - :type amount: float - :return: The result of increasing motive level. True, if the specified Motive was changed successfully. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - cls.get_log().format_with_message('sim_info was None!', motive_id=motive_id, sim=sim_info) - return CommonExecutionResult(False, reason='sim_info was None.') - mapped_motive_id: int = cls._map_motive_id(sim_info, motive_id) - if mapped_motive_id == -1: - cls.get_log().format_with_message('Failed to map motive id!', motive_id=motive_id, sim=sim_info) - return CommonExecutionResult(False, reason=f'The motive {motive_id} did not map to any known motive for the Sim {sim_info}.') - cls.get_log().format_with_message('Mapped motive id, Adding to it for Sim.', motive_id=motive_id, mapped_motive_id=mapped_motive_id, amount=amount, sim=sim_info) - return CommonSimStatisticUtils.add_statistic_value(sim_info, mapped_motive_id, amount, add=True) - - @classmethod - def decrease_motive_level(cls, sim_info: SimInfo, motive_id: Union[CommonMotiveId, CommonInt, int], amount: float) -> CommonExecutionResult: - """decrease_motive_level(sim_info, motive_id, amount) - - Decrease the current level of a Motive of a Sim. - - :param sim_info: The Sim to modify. - :type sim_info: SimInfo - :param motive_id: The identifier of the Motive to change. - :type motive_id: Union[CommonMotiveId, CommonInt, int] - :param amount: The amount to decrease the motive by. - :type amount: float - :return: The result of decreasing motive level. True, if the specified Motive was changed successfully. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - cls.get_log().format_with_message('sim_info was None!', motive_id=motive_id, sim=sim_info) - return CommonExecutionResult(False, reason='sim_info was None.') - mapped_motive_id: int = cls._map_motive_id(sim_info, motive_id) - if mapped_motive_id == -1: - cls.get_log().format_with_message('Failed to map motive id!', motive_id=motive_id, sim=sim_info) - return CommonExecutionResult(False, reason=f'The motive {motive_id} did not map to any known motive for the Sim {sim_info}.') - cls.get_log().format_with_message('Mapped motive id, Subtracting from it for Sim.', motive_id=motive_id, mapped_motive_id=mapped_motive_id, amount=amount, sim=sim_info) - return CommonSimStatisticUtils.add_statistic_value(sim_info, mapped_motive_id, amount * -1.0, add=True) - - @classmethod - def get_hunger_level(cls, sim_info: SimInfo) -> float: - """get_hunger_level(sim_info) - - Retrieve the hunger level of a Sim. - - :param sim_info: The Sim to get the level of. - :type sim_info: SimInfo - :return: The current level of the Motive of the Sim. - :rtype: float - """ - if sim_info is None: - cls.get_log().format_with_message('sim_info was None!', sim=sim_info) - return False - motive_level = cls._get_motive_level(sim_info, CommonMotiveId.HUNGER) - if motive_level is None: - cls.get_log().format_with_message('Sim did not have motive HUNGER.', sim=sim_info) - return 0.0 - return motive_level - - @classmethod - def get_hygiene_level(cls, sim_info: SimInfo) -> float: - """get_hygiene_level(sim_info) - - Retrieve the hygiene level of a Sim. - - :param sim_info: The Sim to get the level of. - :type sim_info: SimInfo - :return: The current level of the Motive of the Sim. - :rtype: float - """ - if sim_info is None: - cls.get_log().format_with_message('sim_info was None!', sim=sim_info) - return False - motive_level = cls._get_motive_level(sim_info, CommonMotiveId.HYGIENE) - if motive_level is None: - cls.get_log().format_with_message('Sim did not have motive HYGIENE.', sim=sim_info) - return 0.0 - return motive_level - - @classmethod - def get_energy_level(cls, sim_info: SimInfo) -> float: - """get_energy_level(sim_info) - - Retrieve the energy level of a Sim. - - :param sim_info: The Sim to get the level of. - :type sim_info: SimInfo - :return: The current level of the Motive of the Sim. - :rtype: float - """ - if sim_info is None: - cls.get_log().format_with_message('sim_info was None!', sim=sim_info) - return False - motive_level = cls._get_motive_level(sim_info, CommonMotiveId.ENERGY) - if motive_level is None: - cls.get_log().format_with_message('Sim did not have motive ENERGY.', sim=sim_info) - return 0.0 - return motive_level - - @classmethod - def get_bladder_level(cls, sim_info: SimInfo) -> float: - """get_bladder_level(sim_info) - - Retrieve the bladder level of a Sim. - - :param sim_info: The Sim to get the level of. - :type sim_info: SimInfo - :return: The current level of the Motive of the Sim. - :rtype: float - """ - if sim_info is None: - cls.get_log().format_with_message('sim_info was None!', sim=sim_info) - return False - motive_level = cls._get_motive_level(sim_info, CommonMotiveId.BLADDER) - if motive_level is None: - return 0.0 - return motive_level - - @classmethod - def has_bowels(cls, sim_info: SimInfo) -> CommonTestResult: - """has_bowels(sim_info) - - Determine if a Sim has bowels. - - .. note:: Human Sims do not have Bowels. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of the test. True, if the Sim has bowels. False, if not. - :rtype: CommonTestResult - """ - return cls.has_motive(sim_info, CommonMotiveId.BOWEL) - - @classmethod - def get_bowels_level(cls, sim_info: SimInfo) -> float: - """get_bowels_level(sim_info) - - Retrieve the bowel level of a Sim. - - .. note:: Human Sims do not have Bowels. (As hard as that is to believe) - - :param sim_info: The Sim to get the level of. - :type sim_info: SimInfo - :return: The current level of the Motive of the Sim. - :rtype: float - """ - if CommonSpeciesUtils.is_human(sim_info): - cls.get_log().format_with_message('Sim did not have motive BOWELS.', sim=sim_info) - return 0.0 - return cls._get_motive_level(sim_info, CommonMotiveId.BOWEL) - - @classmethod - def get_social_level(cls, sim_info: SimInfo) -> float: - """get_social_level(sim_info) - - Retrieve the social level of a Sim. - - :param sim_info: The Sim to get the level of. - :type sim_info: SimInfo - :return: The current level of the Motive of the Sim. - :rtype: float - """ - motive_level = cls._get_motive_level(sim_info, CommonMotiveId.SOCIAL) - if motive_level is None: - cls.get_log().format_with_message('Sim did not have motive SOCIAL.', sim=sim_info) - return 0.0 - return motive_level - - @classmethod - def get_fun_level(cls, sim_info: SimInfo) -> float: - """get_fun_level(sim_info) - - Retrieve the fun level of a Sim. - - :param sim_info: The Sim to get the level of. - :type sim_info: SimInfo - :return: The current level of the Motive of the Sim. - :rtype: float - """ - motive_level = cls._get_motive_level(sim_info, CommonMotiveId.FUN) - if motive_level is None: - cls.get_log().format_with_message('Sim did not have motive FUN.', sim=sim_info) - return 0.0 - return motive_level - - @classmethod - def get_robot_charge_level(cls, sim_info: SimInfo) -> float: - """get_robot_charge_level(sim_info) - - Retrieve the charge level of a Sim. - - :param sim_info: The Sim to get the level of. - :type sim_info: SimInfo - :return: The current level of the Motive of the Sim or `0.0` if the Sim is not a Robot. - :rtype: float - """ - if not CommonOccultUtils.is_robot(sim_info): - cls.get_log().format_with_message('Sim is not a Robot.', sim=sim_info) - return 0.0 - return cls._get_motive_level(sim_info, CommonMotiveId.SERVO_CHARGE) - - @classmethod - def get_robot_durability_level(cls, sim_info: SimInfo) -> float: - """get_robot_durability_level(sim_info) - - Retrieve the durability level of a Sim. - - :param sim_info: The Sim to get the level of. - :type sim_info: SimInfo - :return: The current level of the Motive of the Sim or `0.0` if the Sim is not a Robot. - :rtype: float - """ - if not CommonOccultUtils.is_robot(sim_info): - cls.get_log().format_with_message('Sim is not a Robot.', sim=sim_info) - return 0.0 - return cls._get_motive_level(sim_info, CommonMotiveId.SERVO_DURABILITY) - - @classmethod - def get_vampire_power_level(cls, sim_info: SimInfo) -> float: - """get_vampire_power_level(sim_info) - - Retrieve the vampire power level of a Sim. - - :param sim_info: The Sim to get the level of. - :type sim_info: SimInfo - :return: The current level of the Motive of the Sim or `0.0` if the Sim is not a Vampire. - :rtype: float - """ - if not CommonOccultUtils.is_vampire(sim_info): - cls.get_log().format_with_message('Sim is not a Vampire.', sim=sim_info) - return 0.0 - return cls._get_motive_level(sim_info, CommonMotiveId.VAMPIRE_POWER) - - @classmethod - def get_vampire_thirst_level(cls, sim_info: SimInfo) -> float: - """get_vampire_thirst_level(sim_info) - - Retrieve the vampire thirst level of a Sim. - - :param sim_info: The Sim to get the level of. - :type sim_info: SimInfo - :return: The current level of the Motive of the Sim or `0.0` if the Sim is not a Vampire. - :rtype: float - """ - if not CommonOccultUtils.is_vampire(sim_info): - cls.get_log().format_with_message('Sim is not a Vampire.', sim=sim_info) - return 0.0 - return cls._get_motive_level(sim_info, CommonMotiveId.VAMPIRE_THIRST) - - @classmethod - def get_plant_sim_water_level(cls, sim_info: SimInfo) -> float: - """get_plant_sim_water_level(sim_info) - - Retrieve the plant sim water level of a Sim. - - :param sim_info: The Sim to get the level of. - :type sim_info: SimInfo - :return: The current level of the Motive of the Sim or `0.0` if the Sim is not a Plant Sim. - :rtype: float - """ - if not CommonOccultUtils.is_plant_sim(sim_info): - cls.get_log().format_with_message('Sim is not a Plant Sim.', sim=sim_info) - return 0.0 - return cls._get_motive_level(sim_info, CommonMotiveId.PLANT_SIM_WATER) - - @classmethod - def get_mermaid_hydration_level(cls, sim_info: SimInfo) -> float: - """get_mermaid_hydration_level(sim_info) - - Retrieve the hydration level of a Sim. - - .. note:: This level is basically the Hygiene motive. - - :param sim_info: The Sim to get the level of. - :type sim_info: SimInfo - :return: The current level of the Motive of the Sim or `0.0` if the Sim is not a Mermaid. - :rtype: float - """ - if not CommonOccultUtils.is_mermaid(sim_info): - cls.get_log().format_with_message('Sim is not a Mermaid.', sim=sim_info) - return 0.0 - return cls._get_motive_level(sim_info, CommonMotiveId.MERMAID_HYDRATION) - - @classmethod - def get_witch_magic_level(cls, sim_info: SimInfo) -> float: - """get_witch_magic_level(sim_info) - - Retrieve the magic level of a Sim. - - :param sim_info: The Sim to get the level of. - :type sim_info: SimInfo - :return: The current level of the Motive of the Sim or `0.0` if the Sim is not a Witch. - :rtype: float - """ - if sim_info is None: - cls.get_log().format_with_message('sim_info was None!', sim=sim_info) - return 0.0 - if not CommonOccultUtils.is_witch(sim_info): - cls.get_log().format_with_message('Sim is not a Witch.', sim=sim_info) - return 0.0 - return cls._get_motive_level(sim_info, CommonMotiveId.WITCH_MAGIC) - - @classmethod - def is_motive_locked(cls, sim_info: SimInfo, motive_id: Union[CommonMotiveId, CommonInt, int]) -> CommonTestResult: - """is_motive_locked(sim_info, motive_id) - - Determine if a Motive is locked for a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param motive_id: The identifier of the motive to check. - :type motive_id: Union[CommonMotiveId, CommonInt, int] - :return: The result of the test. True, if the specified Motive is locked for the Sim. False, if not. - :rtype: CommonTestResult - """ - mapped_motive_id: int = cls._map_motive_id(sim_info, motive_id) - if mapped_motive_id == -1: - cls.get_log().format_with_message('Failed to map motive id!', motive_id=motive_id, sim=sim_info) - return CommonTestResult(False, reason=f'The motive {motive_id} did not map to any known motive for the Sim {sim_info}.') - motive_instance = CommonSimStatisticUtils.get_statistic(sim_info, mapped_motive_id) - if motive_instance is None: - return CommonTestResult(False, reason=f'No motive found for id {mapped_motive_id}.') - if sim_info.is_locked(motive_instance): - return CommonTestResult(True, reason=f'Motive {mapped_motive_id} is locked for Sim {sim_info}') - return CommonTestResult(False, reason=f'Motive {mapped_motive_id} is not locked for Sim {sim_info}') - - @classmethod - def set_all_motives_max(cls, sim_info: SimInfo) -> CommonExecutionResult: - """set_all_motives_max(sim_info) - - Set all Motives for a Sim to their maximum values. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of setting all motives to max. True, if successful. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - return CommonExecutionResult(False, reason='sim_info was None.') - client_id = services.client_manager().get_first_client_id() - commands.execute('stats.fill_commodities {}'.format(CommonSimUtils.get_sim_id(sim_info)), client_id) - return CommonExecutionResult(True, reason=f'Successfully set all motives to their max levels for Sim {sim_info}') - - @classmethod - def _get_motive_level(cls, sim_info: SimInfo, motive_id: Union[CommonMotiveId, CommonInt, int]) -> float: - if sim_info is None: - cls.get_log().format_with_message('sim_info was None!', motive_id=motive_id, sim=sim_info) - return 0.0 - mapped_motive_id: int = cls._map_motive_id(sim_info, motive_id) - if mapped_motive_id == -1: - cls.get_log().format_with_message('Failed to map the motive id.', motive_id=motive_id, sim=sim_info) - return 0.0 - cls.get_log().format_with_message('Mapped motive id, attempting to get motive value.', motive_id=motive_id, mapped_motive_id=mapped_motive_id, sim=sim_info) - return CommonSimStatisticUtils.get_statistic_value(sim_info, mapped_motive_id) - - @classmethod - def get_motive_id_for_sim(cls, sim_info: SimInfo, motive_id: Union[CommonMotiveId, CommonInt, int]) -> Union[CommonMotiveId, CommonInt, int]: - """get_motive_id_for_sim(sim_info, motive_id) - - Translate a motive ID to one that the Sim would have. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param motive_id: The motive to translate. - :type motive_id: Union[CommonMotiveId, CommonInt, int] - :return: The mapped motive id. - :rtype: Union[CommonMotiveId, CommonInt, int] - """ - result = cls._map_motive_id(sim_info, motive_id) - if result == -1: - return motive_id - return result - - @classmethod - def _map_motive_id(cls, sim_info: SimInfo, motive_id: Union[CommonMotiveId, CommonInt, int]) -> Union[CommonMotiveId, CommonInt, int]: - motive_mappings = cls._get_motive_mappings() - if motive_id not in motive_mappings: - return motive_id - motive_species_mapping: Dict[CommonSpecies, CommonMotiveId] = motive_mappings[motive_id] - - species = CommonSpecies.get_species(sim_info) - return motive_species_mapping.get(species, motive_id) - - @classmethod - def _get_motive_mappings(cls) -> Dict[Union[CommonMotiveId, CommonInt, int], Dict[CommonSpecies, Union[CommonMotiveId, CommonInt, int]]]: - if CommonSimMotiveUtils._MOTIVE_MAPPINGS is not None: - return CommonSimMotiveUtils._MOTIVE_MAPPINGS - - CommonSimMotiveUtils._MOTIVE_MAPPINGS = { - CommonMotiveId.HUNGER: { - CommonSpecies.HUMAN: CommonMotiveId.HUNGER, - CommonSpecies.CAT: CommonMotiveId.PET_CAT_HUNGER, - CommonSpecies.LARGE_DOG: CommonMotiveId.PET_DOG_HUNGER, - CommonSpecies.SMALL_DOG: CommonMotiveId.PET_DOG_HUNGER, - CommonSpecies.FOX: CommonMotiveId.HUNGER, - CommonSpecies.HORSE: CommonMotiveId.PET_HORSE_HUNGER - }, - CommonMotiveId.HYGIENE: { - CommonSpecies.HUMAN: CommonMotiveId.HYGIENE, - CommonSpecies.CAT: CommonMotiveId.PET_CAT_HYGIENE, - CommonSpecies.LARGE_DOG: CommonMotiveId.PET_DOG_HYGIENE, - CommonSpecies.SMALL_DOG: CommonMotiveId.PET_DOG_HYGIENE, - CommonSpecies.FOX: CommonMotiveId.ANIMAL_FOX_HYGIENE, - CommonSpecies.HORSE: CommonMotiveId.PET_HORSE_HYGIENE - }, - CommonMotiveId.MERMAID_HYDRATION: { - CommonSpecies.HUMAN: CommonMotiveId.HYGIENE, - CommonSpecies.CAT: CommonMotiveId.PET_CAT_HYGIENE, - CommonSpecies.LARGE_DOG: CommonMotiveId.PET_DOG_HYGIENE, - CommonSpecies.SMALL_DOG: CommonMotiveId.PET_DOG_HYGIENE, - CommonSpecies.FOX: CommonMotiveId.HYGIENE, - CommonSpecies.HORSE: CommonMotiveId.PET_HORSE_HYGIENE - }, - CommonMotiveId.ENERGY: { - CommonSpecies.HUMAN: CommonMotiveId.ENERGY, - CommonSpecies.CAT: CommonMotiveId.PET_CAT_ENERGY, - CommonSpecies.LARGE_DOG: CommonMotiveId.PET_DOG_ENERGY, - CommonSpecies.SMALL_DOG: CommonMotiveId.PET_DOG_ENERGY, - CommonSpecies.FOX: CommonMotiveId.ENERGY, - CommonSpecies.HORSE: CommonMotiveId.PET_HORSE_ENERGY - }, - CommonMotiveId.BLADDER: { - CommonSpecies.HUMAN: CommonMotiveId.BLADDER, - CommonSpecies.CAT: CommonMotiveId.PET_CAT_BLADDER, - CommonSpecies.LARGE_DOG: CommonMotiveId.PET_DOG_BLADDER, - CommonSpecies.SMALL_DOG: CommonMotiveId.PET_DOG_BLADDER, - CommonSpecies.FOX: CommonMotiveId.ANIMAL_FOX_BLADDER, - CommonSpecies.HORSE: CommonMotiveId.PET_HORSE_BLADDER - }, - CommonMotiveId.BOWEL: { - CommonSpecies.HUMAN: CommonMotiveId.BOWEL, - CommonSpecies.CAT: CommonMotiveId.PET_CAT_BOWEL, - CommonSpecies.LARGE_DOG: CommonMotiveId.PET_DOG_BOWEL, - CommonSpecies.SMALL_DOG: CommonMotiveId.PET_DOG_BOWEL, - CommonSpecies.FOX: CommonMotiveId.BOWEL, - CommonSpecies.HORSE: CommonMotiveId.BOWEL - }, - CommonMotiveId.SOCIAL: { - CommonSpecies.HUMAN: CommonMotiveId.SOCIAL, - CommonSpecies.CAT: CommonMotiveId.PET_CAT_AFFECTION, - CommonSpecies.LARGE_DOG: CommonMotiveId.PET_DOG_AFFECTION, - CommonSpecies.SMALL_DOG: CommonMotiveId.PET_DOG_AFFECTION, - CommonSpecies.FOX: CommonMotiveId.SOCIAL, - CommonSpecies.HORSE: CommonMotiveId.PET_HORSE_SOCIAL - }, - CommonMotiveId.FUN: { - CommonSpecies.HUMAN: CommonMotiveId.FUN, - CommonSpecies.CAT: CommonMotiveId.PET_CAT_PLAY, - CommonSpecies.LARGE_DOG: CommonMotiveId.PET_DOG_PLAY, - CommonSpecies.SMALL_DOG: CommonMotiveId.PET_DOG_PLAY, - CommonSpecies.FOX: CommonMotiveId.FUN, - CommonSpecies.HORSE: CommonMotiveId.PET_HORSE_FUN - } - } - return CommonSimMotiveUtils._MOTIVE_MAPPINGS - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.print_motive_level', - 'Print the current level of a Motive for a Sim.', - command_arguments=( - CommonConsoleCommandArgument('motive', 'Motive Id or Tuning Name', 'The tuning name or decimal identifier of a Motive.'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to check.', is_optional=True, default_value='Active Sim'), - ) -) -def _common_print_motive_level(output: CommonConsoleCommandOutput, motive: TunableInstanceParam(Types.STATISTIC), sim_info: SimInfo = None): - if motive is None: - output('ERROR: No Motive specified or Motive did not exist!') - return - if sim_info is None: - output('Failed, no Sim was specified or the specified Sim was not found!') - return - output(f'Printing motive level of Motive {motive} for Sim {sim_info}') - motive_level = CommonSimMotiveUtils.get_motive_level(sim_info, motive) - output(f'Motive Level of {motive}: {motive_level}') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.set_motive_level', - 'Set the current level of a Motive for a Sim.', - command_arguments=( - CommonConsoleCommandArgument('motive', 'Motive Id or Tuning Name', 'The tuning name or decimal identifier of a Motive.'), - CommonConsoleCommandArgument('level', 'Decimal Number', 'The amount to set the motive level to between -100 and 100.'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to change.', is_optional=True, default_value='Active Sim'), - ) -) -def _common_set_motive_level(output: CommonConsoleCommandOutput, motive: TunableInstanceParam(Types.STATISTIC), level: float, sim_info: SimInfo = None): - if motive is None: - output('ERROR: Failed, Motive not specified or Motive did not exist! s4clib.set_motive_level [opt_sim=None]') - return - if sim_info is None: - return - output(f'Attempting to set motive {motive} for Sim {sim_info} to {level}') - if CommonSimMotiveUtils.set_motive_level(sim_info, motive, level): - output(f'SUCCESS: Successfully set the motive level of motive {motive} for Sim {sim_info} to {level}.') - else: - output(f'FAILED: Failed to set motive level of motive {motive} for Sim {sim_info} to {level}.') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.max_all_motives', - 'Set all Motive Levels to their maximum for a Sim.', - command_arguments=( - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to change.', is_optional=True, default_value='Active Sim'), - ) -) -def _common_max_all_motives(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): - if sim_info is None: - return - CommonSimMotiveUtils.set_all_motives_max(sim_info) - output(f'SUCCESS: Maxed the motives of {sim_info}.') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.max_world_motives', - 'Set all Motive Levels to their maximum for all Sims.' -) -def _common_max_world_motives(output: CommonConsoleCommandOutput): - sim_count = 0 - for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): - CommonSimMotiveUtils.set_all_motives_max(sim_info) - sim_count += 1 - output('Maxed the motives of {} Sim(s).'.format(sim_count)) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_name_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_name_utils.py deleted file mode 100644 index a7e1ab6..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_name_utils.py +++ /dev/null @@ -1,284 +0,0 @@ -""" -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 -""" -from typing import Tuple - -from sims.sim_info import SimInfo -from sims.sim_spawner import SimSpawner -from sims.sim_spawner_enums import SimNameType -from s4ap.sims4communitylib.enums.common_gender import CommonGender -from s4ap.sims4communitylib.enums.common_sim_name_type import CommonSimNameType -from s4ap.sims4communitylib.enums.common_species import CommonSpecies -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ - CommonConsoleCommandArgument -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.misc.common_text_utils import CommonTextUtils - - -class CommonSimNameUtils: - """Utilities for manipulating the name of Sims. - - """ - @staticmethod - def has_name(sim_info: SimInfo) -> bool: - """has_name(sim_info) - - Determine if a Sim has a name. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: True, if the specified Sim has a name. False, if not. - :rtype: bool - """ - if sim_info is None: - return False - return CommonSimNameUtils.get_full_name(sim_info) != '' - - @staticmethod - def set_first_name(sim_info: SimInfo, first_name: str): - """set_first_name(sim_info, first_name) - - Retrieve the First Name of a Sim. - - :param sim_info: The Sim to set the first name of. - :type sim_info: SimInfo - :param first_name: The first name you want the Sim to have. - :type first_name: str - """ - if sim_info is None or not hasattr(sim_info, 'first_name'): - return - sim_info.first_name = first_name - - @staticmethod - def set_last_name(sim_info: SimInfo, last_name: str): - """set_last_name(sim_info, last_name) - - Retrieve the Last Name of a Sim. - - :param sim_info: The Sim to set the last name of. - :type sim_info: SimInfo - :param last_name: The last name you want the Sim to have. - :type last_name: str - """ - if sim_info is None or not hasattr(sim_info, 'last_name'): - return - sim_info.last_name = last_name - - @staticmethod - def get_first_name(sim_info: SimInfo) -> str: - """get_first_name(sim_info) - - Retrieve the First Name of a Sim. - - :param sim_info: The Sim to retrieve the first name of. - :type sim_info: SimInfo - :return: The first name of the specified Sim. - :rtype: str - """ - if sim_info is None or not hasattr(sim_info, 'first_name'): - return '' - return getattr(sim_info, 'first_name') - - @staticmethod - def get_last_name(sim_info: SimInfo) -> str: - """get_last_name(sim_info) - - Retrieve the Last Name of a Sim. - - :param sim_info: The Sim to retrieve the last name of. - :type sim_info: SimInfo - :return: The last name of the specified Sim. - :rtype: str - """ - if sim_info is None or not hasattr(sim_info, 'last_name'): - return '' - return getattr(sim_info, 'last_name') - - @staticmethod - def get_full_name(sim_info: SimInfo) -> str: - """get_full_name(sim_info) - - Retrieve the full name of a Sim. - - .. note:: Resulting Full Name: '{First} {Last}' - - :param sim_info: The Sim to retrieve the full name of. - :type sim_info: SimInfo - :return: The full name of the specified Sim. - :rtype: str - """ - full_name = '{} {}'.format(CommonSimNameUtils.get_first_name(sim_info), CommonSimNameUtils.get_last_name(sim_info)).strip() - if full_name == '': - full_name = 'No Name' - return full_name - - @staticmethod - def get_full_names(sim_info_list: Tuple[SimInfo]) -> Tuple[str]: - """get_full_names(sim_info_list) - - Retrieve a collection of full names for the specified Sims. - - .. note:: Resulting Full Names: ('{First} {Last}', '{First} {Last}', '{First} {Last}', ...) - - :param sim_info_list: A collection of Sims - :type sim_info_list: Tuple[SimInfo] - :return: A collection of full names of the specified Sims. - :rtype: Tuple[str] - """ - result: Tuple[str] = tuple([CommonSimNameUtils.get_full_name(sim_info) for sim_info in sim_info_list]) - return result - - @staticmethod - def create_random_first_name(gender: CommonGender, species: CommonSpecies=CommonSpecies.HUMAN, sim_name_type: CommonSimNameType=CommonSimNameType.DEFAULT) -> str: - """create_random_first_name(gender, species=CommonSpecies.HUMAN, sim_name_type=CommonSimNameType.DEFAULT) - - Create a random first name. - - :param gender: A gender. - :type gender: CommonGender - :param species: A species. Default is HUMAN. - :type species: CommonSpecies, optional - :param sim_name_type: The Sim Name Type determines from which list of names to randomize the name from. Default is CommonSimNameType.DEFAULT. - :type sim_name_type: CommonSimNameType, optional - :return: A random first name. - :rtype: str - """ - vanilla_gender = CommonGender.convert_to_vanilla(gender) - vanilla_species = CommonSpecies.convert_to_vanilla(species) - vanilla_sim_name_type = CommonSimNameType.convert_to_vanilla(sim_name_type) - return SimSpawner.get_random_first_name(vanilla_gender, species=vanilla_species, sim_name_type_override=vanilla_sim_name_type) - - @staticmethod - def create_random_last_name(gender: CommonGender, species: CommonSpecies=CommonSpecies.HUMAN, sim_name_type: CommonSimNameType=CommonSimNameType.DEFAULT) -> str: - """create_random_last_name(gender, species=CommonSpecies.HUMAN, sim_name_type=CommonSimNameType.DEFAULT) - - Create a random last name. - - :param gender: A gender. - :type gender: CommonGender - :param species: A species. Default is HUMAN. - :type species: CommonSpecies, optional - :param sim_name_type: The Sim Name Type determines from which list of names to randomize the name from. Default is CommonSimNameType.DEFAULT. - :type sim_name_type: CommonSimNameType, optional - :return: A random last name. - :rtype: str - """ - account = SimSpawner._get_default_account() - vanilla_gender = CommonGender.convert_to_vanilla(gender) - vanilla_species = CommonSpecies.convert_to_vanilla(species) - vanilla_sim_name_type = CommonSimNameType.convert_to_vanilla(sim_name_type) - language = SimSpawner._get_language_for_locale(account.locale) - family_name = SimSpawner._get_random_last_name(language, sim_name_type=vanilla_sim_name_type) - if sim_name_type == SimNameType.DEFAULT: - last_name = SimSpawner.get_last_name(family_name, vanilla_gender, species=vanilla_species) - else: - from s4ap.sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils - last_name = SimSpawner._get_family_name_for_gender(language, family_name, CommonGenderUtils.is_female_gender(gender), sim_name_type=vanilla_sim_name_type) - return last_name - - -@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.randomize_name', 'Randomize the first and last names of a Sim.', command_arguments=( - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to change the first and last names of.'), - CommonConsoleCommandArgument('sim_name_type', 'CommonSimNameType', f'Determines from which list of names to randomize the name from. Valid Values: {CommonSimNameType.get_comma_separated_names_string()}'), -)) -def _common_randomize_name(output: CommonConsoleCommandOutput, sim_info: SimInfo=None, sim_name_type: CommonSimNameType=CommonSimNameType.DEFAULT): - if sim_info is None: - return - gender = CommonGender.get_gender(sim_info) - species = CommonSpecies.get_species(sim_info) - first_name = CommonSimNameUtils.create_random_first_name(gender, species=species, sim_name_type=sim_name_type) - first_name = CommonTextUtils.capitalize(first_name) - output(f'Setting the first name of Sim {sim_info} to {first_name}') - CommonSimNameUtils.set_first_name(sim_info, first_name) - last_name = CommonSimNameUtils.create_random_last_name(gender, species=species, sim_name_type=sim_name_type) - last_name = CommonTextUtils.capitalize(last_name) - output(f'Setting the last name of Sim {sim_info} to {last_name}') - CommonSimNameUtils.set_last_name(sim_info, last_name) - - -@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.set_first_name', 'Set the first name of a Sim.', command_arguments=( - CommonConsoleCommandArgument('first_name', 'Text', 'The first name to give to the Sim.'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to change the first name of.'), -)) -def _common_set_first_name(output: CommonConsoleCommandOutput, first_name: str, sim_info: SimInfo=None): - if sim_info is None: - output('Failed, no Sim was specified or the specified Sim was not found!') - return - if not first_name: - output(f'Failed, \'{first_name}\' is not a valid first name.') - return - first_name = CommonTextUtils.capitalize(first_name) - output(f'Setting the first name of Sim {sim_info} to {first_name}') - CommonSimNameUtils.set_first_name(sim_info, first_name) - - -@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.randomize_first_name', 'Randomize the first name of a Sim.', command_arguments=( - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to change the first name of.'), - CommonConsoleCommandArgument('sim_name_type', 'CommonSimNameType', f'Determines from which list of names to randomize the name from. Valid Values: {CommonSimNameType.get_comma_separated_names_string()}'), -)) -def _common_randomize_first_name(output: CommonConsoleCommandOutput, sim_info: SimInfo=None, sim_name_type: CommonSimNameType=CommonSimNameType.DEFAULT): - if sim_info is None: - output('Failed, no Sim was specified or the specified Sim was not found!') - return - gender = CommonGender.get_gender(sim_info) - species = CommonSpecies.get_species(sim_info) - first_name = CommonSimNameUtils.create_random_first_name(gender, species=species, sim_name_type=sim_name_type) - first_name = CommonTextUtils.capitalize(first_name) - output(f'Setting the first name of Sim {sim_info} to {first_name}') - CommonSimNameUtils.set_first_name(sim_info, first_name) - - -@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.set_last_name', 'Set the last name of a Sim.', command_arguments=( - CommonConsoleCommandArgument('last_name', 'Text', 'The last name to give to the Sim.'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to change the last name of.'), -)) -def _common_set_last_name(output: CommonConsoleCommandOutput, last_name: str, sim_info: SimInfo=None): - if sim_info is None: - output('Failed, no Sim was specified or the specified Sim was not found!') - return - last_name = CommonTextUtils.capitalize(last_name) - output(f'Setting the last name of Sim {sim_info} to {last_name}') - CommonSimNameUtils.set_last_name(sim_info, last_name) - - -@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.randomize_last_name', 'Randomize the last name of a Sim.', command_arguments=( - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to change the last name of.'), - CommonConsoleCommandArgument('sim_name_type', 'CommonSimNameType', f'Determines from which list of names to randomize the name from. Valid Values: {CommonSimNameType.get_comma_separated_names_string()}'), -)) -def _common_randomize_last_name(output: CommonConsoleCommandOutput, sim_info: SimInfo=None, sim_name_type: CommonSimNameType=CommonSimNameType.DEFAULT): - if sim_info is None: - output('Failed, no Sim was specified or the specified Sim was not found!') - return - gender = CommonGender.get_gender(sim_info) - species = CommonSpecies.get_species(sim_info) - last_name = CommonSimNameUtils.create_random_last_name(gender, species=species, sim_name_type=sim_name_type) - last_name = CommonTextUtils.capitalize(last_name) - output(f'Setting the last name of Sim {sim_info} to {last_name}') - CommonSimNameUtils.set_last_name(sim_info, last_name) - - -@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.set_name', 'Set the full name of a Sim.', command_arguments=( - CommonConsoleCommandArgument('first_name', 'Text', 'The first name to give to the Sim.'), - CommonConsoleCommandArgument('last_name', 'Text', 'The last name to give to the Sim.'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Sim to change the first and last name of.'), -)) -def _common_set_name(output: CommonConsoleCommandOutput, first_name: str, last_name: str, sim_info: SimInfo=None): - if sim_info is None: - output('Failed, no Sim was specified or the specified Sim was not found!') - return - if not first_name: - output(f'Failed, \'{first_name}\' is not a valid first name.') - return - if not last_name: - output(f'Failed, \'{last_name}\' is not a valid last name.') - return - first_name = CommonTextUtils.capitalize(first_name) - last_name = CommonTextUtils.capitalize(last_name) - output(f'Setting the name of Sim {sim_info} to {first_name} {last_name}') - CommonSimNameUtils.set_first_name(sim_info, first_name) - CommonSimNameUtils.set_last_name(sim_info, last_name) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_occult_type_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_occult_type_utils.py deleted file mode 100644 index 6babbe9..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_occult_type_utils.py +++ /dev/null @@ -1,265 +0,0 @@ -""" -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 -""" -from typing import Iterator, Union, Dict, Callable - -from sims.occult.occult_enums import OccultType -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.enums.common_occult_type import CommonOccultType -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ - CommonConsoleCommandArgument -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils - - -class CommonSimOccultTypeUtils: - """Utilities for determining the type of Occult a Sim is. i.e. Alien, Vampire, Ghost, etc. - - """ - @staticmethod - def get_all_occult_types_for_sim_gen(sim_info: SimInfo) -> Iterator[CommonOccultType]: - """get_all_occult_types_for_sim_gen(sim_info) - - Retrieve a generator of CommonOccultType for all Occults of a Sim. - - .. note:: Results include the occult type of the sim_info specified.\ - If they are Human by default, the Human occult type will be included. - - :param sim_info: The Sim to locate the Occults of. - :type sim_info: SimInfo - :return: An iterator of Occult Types for all occults of the Sim. - :rtype: Iterator[CommonOccultType] - """ - if sim_info is None: - return tuple() - yield CommonOccultType.NON_OCCULT - for occult_type in CommonOccultType.get_all(exclude_occult_types=(CommonOccultType.NONE, CommonOccultType.NON_OCCULT)): - if CommonSimOccultTypeUtils.is_occult_type(sim_info, occult_type): - yield occult_type - - @staticmethod - def has_any_occult(sim_info: SimInfo) -> bool: - """has_any_occult(sim_info) - - Determine if a Sim has any Occult Types. (Not including NON_OCCULT) - - :param sim_info: The Sim to locate the Occults of. - :type sim_info: SimInfo - :return: True, if the specified Sim has any Non-Human Occult Types. False, if not. - :rtype: bool - """ - for occult_type in CommonSimOccultTypeUtils.get_all_occult_types_for_sim_gen(sim_info): - if occult_type in (CommonOccultType.NONE, CommonOccultType.NON_OCCULT): - continue - return True - return False - - @staticmethod - def is_occult_type(sim_info: SimInfo, occult_type: CommonOccultType) -> CommonTestResult: - """is_occult_type(sim_info, occult_type) - - Determine if a Sim is an Occult Type. - - .. note:: To check if a Sim is currently an occult type use :func:`~is_currently_occult_type` instead. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param occult_type: The Occult Type to check. - :type occult_type: OccultType - :return: The result of the test. True, if the Sim is the specified Occult Type. False, if not. - :rtype: CommonTestResult - """ - if occult_type == CommonOccultType.NONE: - raise AssertionError('Cannot check if Sim is a NONE occult!'.format(CommonSimNameUtils.get_full_name(sim_info))) - if occult_type == CommonOccultType.NON_OCCULT: - # Every Sim is always a Non-Occult - return CommonTestResult.TRUE - from s4ap.sims4communitylib.utils.sims.common_occult_utils import CommonOccultUtils - occult_type_mappings: Dict[CommonOccultType, Callable[[SimInfo], CommonTestResult]] = { - CommonOccultType.ALIEN: CommonOccultUtils.is_alien, - CommonOccultType.MERMAID: CommonOccultUtils.is_mermaid, - CommonOccultType.ROBOT: CommonOccultUtils.is_robot, - CommonOccultType.SCARECROW: CommonOccultUtils.is_scarecrow, - CommonOccultType.SKELETON: CommonOccultUtils.is_skeleton, - CommonOccultType.VAMPIRE: CommonOccultUtils.is_vampire, - CommonOccultType.WITCH: CommonOccultUtils.is_witch, - CommonOccultType.PLANT_SIM: CommonOccultUtils.is_plant_sim, - CommonOccultType.GHOST: CommonOccultUtils.is_ghost, - CommonOccultType.WEREWOLF: CommonOccultUtils.is_werewolf - } - if occult_type not in occult_type_mappings: - return CommonTestResult(False, reason=f'A check for the specified occult type was not found. {occult_type}.') - return occult_type_mappings[occult_type](sim_info) - - @staticmethod - def is_currently_occult_type(sim_info: SimInfo, occult_type: CommonOccultType) -> CommonTestResult: - """is_currently_occult_type(sim_info, occult_type) - - Determine if a Sim is currently an Occult Type. - - .. note:: To check if a Sim is an occult type (Whether current or not) use :func:`~is_occult_type` instead. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param occult_type: The Occult Type to check. - :type occult_type: OccultType - :return: True, if the Sim is currently the specified Occult Type. False, if not. - :rtype: bool - """ - if occult_type == CommonOccultType.NONE: - raise AssertionError('Cannot check if Sim is currently a NONE occult!'.format(CommonSimNameUtils.get_full_name(sim_info))) - from s4ap.sims4communitylib.utils.sims.common_occult_utils import CommonOccultUtils - occult_type_mappings: Dict[CommonOccultType, Callable[[SimInfo], CommonTestResult]] = { - CommonOccultType.ALIEN: CommonOccultUtils.is_currently_an_alien, - CommonOccultType.MERMAID: CommonOccultUtils.is_currently_a_mermaid, - CommonOccultType.ROBOT: CommonOccultUtils.is_currently_a_robot, - CommonOccultType.SCARECROW: CommonOccultUtils.is_currently_a_scarecrow, - CommonOccultType.SKELETON: CommonOccultUtils.is_currently_a_skeleton, - CommonOccultType.VAMPIRE: CommonOccultUtils.is_currently_a_vampire, - CommonOccultType.WITCH: CommonOccultUtils.is_currently_a_witch, - CommonOccultType.PLANT_SIM: CommonOccultUtils.is_currently_a_plant_sim, - CommonOccultType.GHOST: CommonOccultUtils.is_currently_a_ghost, - CommonOccultType.WEREWOLF: CommonOccultUtils.is_currently_a_werewolf - } - if occult_type not in occult_type_mappings: - return CommonTestResult(False, reason=f'A check for the specified occult type was not found. {occult_type}.') - return occult_type_mappings[occult_type](sim_info) - - @staticmethod - def determine_occult_type(sim_info: SimInfo) -> CommonOccultType: - """determine_occult_type(sim_info) - - Determine the type of Occult a Sim is. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The CommonOccultType that represents what a Sim is. - :rtype: CommonOccultType - """ - from s4ap.sims4communitylib.utils.sims.common_occult_utils import CommonOccultUtils - if CommonOccultUtils.is_robot(sim_info): - return CommonOccultType.ROBOT - elif CommonOccultUtils.is_scarecrow(sim_info): - return CommonOccultType.SCARECROW - elif CommonOccultUtils.is_skeleton(sim_info): - return CommonOccultType.SKELETON - elif CommonOccultUtils.is_alien(sim_info): - return CommonOccultType.ALIEN - elif CommonOccultUtils.is_ghost(sim_info): - return CommonOccultType.GHOST - elif CommonOccultUtils.is_mermaid(sim_info): - return CommonOccultType.MERMAID - elif CommonOccultUtils.is_plant_sim(sim_info): - return CommonOccultType.PLANT_SIM - elif CommonOccultUtils.is_vampire(sim_info): - return CommonOccultType.VAMPIRE - elif CommonOccultUtils.is_witch(sim_info): - return CommonOccultType.WITCH - elif CommonOccultUtils.is_werewolf(sim_info): - return CommonOccultType.WEREWOLF - return CommonOccultType.NON_OCCULT - - @staticmethod - def determine_current_occult_type(sim_info: SimInfo) -> CommonOccultType: - """determine_current_occult_type(sim_info) - - Determine the type of Occult a Sim is currently appearing as. - i.e. A mermaid with their tail out would currently be a MERMAID. But a Mermaid Sim with no tail out would currently be a CommonOccultType.NONE - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The CommonOccultType the Sim is currently appearing as, or CommonOccultType.NONE if they are not appearing as any Occult or are appearing as their HUMAN disguise/occult. - :rtype: CommonOccultType - """ - from s4ap.sims4communitylib.utils.sims.common_occult_utils import CommonOccultUtils - if CommonOccultUtils.is_currently_a_mermaid(sim_info) or CommonOccultUtils.is_mermaid_in_mermaid_form(sim_info): - return CommonOccultType.MERMAID - elif CommonOccultUtils.is_robot(sim_info): - return CommonOccultType.ROBOT - elif CommonOccultUtils.is_currently_a_scarecrow(sim_info): - return CommonOccultType.SCARECROW - elif CommonOccultUtils.is_currently_a_vampire(sim_info): - return CommonOccultType.VAMPIRE - elif CommonOccultUtils.is_currently_a_werewolf(sim_info): - return CommonOccultType.WEREWOLF - elif CommonOccultUtils.is_currently_a_witch(sim_info): - return CommonOccultType.WITCH - elif CommonOccultUtils.is_currently_an_alien(sim_info): - return CommonOccultType.ALIEN - elif CommonOccultUtils.is_plant_sim(sim_info): - return CommonOccultType.PLANT_SIM - elif CommonOccultUtils.is_ghost(sim_info): - return CommonOccultType.GHOST - elif CommonOccultUtils.is_skeleton(sim_info): - return CommonOccultType.SKELETON - return CommonOccultType.NON_OCCULT - - @staticmethod - def convert_to_vanilla(occult_type: 'CommonOccultType') -> Union[OccultType, None]: - """convert_to_vanilla(occult_type) - - Convert CommonOccultType into OccultType. - - .. note:: Not all CommonOccultTypes have an OccultType to convert to! They will return None in those cases! (Ghost, Plant Sim, Robot, Skeleton) - - :param occult_type: An instance of a CommonOccultType - :type occult_type: CommonOccultType - :return: The specified CommonOccultType translated to OccultType, or None if the value could not be translated. - :rtype: Union[OccultType, None] - """ - return CommonSimOccultTypeUtils.convert_custom_type_to_vanilla(occult_type) - - @staticmethod - def convert_custom_type_to_vanilla(occult_type: 'CommonOccultType') -> Union[OccultType, None]: - """convert_custom_type_to_vanilla(occult_type) - - Convert a CommonOccultType into OccultType. - - .. note:: Not all CommonOccultType values have a matching OccultType! None will be returned in these cases! (Ghost, Plant Sim, Robot, Skeleton) - - :param occult_type: An instance of a CommonOccultType - :type occult_type: CommonOccultType - :return: The specified CommonOccultType translated to OccultType, or None if the value could not be translated. - :rtype: Union[OccultType, None] - """ - if occult_type is None or occult_type == CommonOccultType.NONE: - return None - if isinstance(occult_type, OccultType): - return occult_type - conversion_mapping: Dict[CommonOccultType, OccultType] = { - CommonOccultType.NON_OCCULT: OccultType.HUMAN, - CommonOccultType.ALIEN: OccultType.ALIEN if hasattr(OccultType, 'ALIEN') else None, - CommonOccultType.MERMAID: OccultType.MERMAID if hasattr(OccultType, 'MERMAID') else None, - CommonOccultType.VAMPIRE: OccultType.VAMPIRE if hasattr(OccultType, 'VAMPIRE') else None, - CommonOccultType.WITCH: OccultType.WITCH if hasattr(OccultType, 'WITCH') else None, - CommonOccultType.WEREWOLF: OccultType.WEREWOLF if hasattr(OccultType, 'WEREWOLF') else None - } - return conversion_mapping.get(occult_type, None) - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.print_custom_occults', - 'Print a list of all custom CommonOccultTypes a Sim has.', - command_arguments=( - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance Id or name of the Sim to print the occult types of.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.printcustomoccults', - ) -) -def _common_print_custom_occult_types_for_sim(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): - if sim_info is None: - return - occult_types_str = ', '.join([occult_type.name if hasattr(occult_type, 'name') else str(occult_type) for occult_type in CommonSimOccultTypeUtils.get_all_occult_types_for_sim_gen(sim_info)]) - output(f'Occult Types: {occult_types_str}') - current_occult_type = CommonSimOccultTypeUtils.determine_current_occult_type(sim_info) - current_occult_type_str = current_occult_type.name if hasattr(current_occult_type, 'name') else str(current_occult_type) - output(f'Current Occult Type: {current_occult_type_str}') diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_plumbob_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_plumbob_utils.py deleted file mode 100644 index 0a9b923..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_plumbob_utils.py +++ /dev/null @@ -1,143 +0,0 @@ -""" -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 -""" -from interactions.utils.plumbbob import unslot_plumbbob, reslot_plumbbob -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.classes.math.common_vector3 import CommonVector3 -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ - CommonConsoleCommandArgument -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - - -class CommonSimPlumbobSlot: - """CommonSimPlumbobSlot(offset_position, bone_name='b__ROOT__', balloon_offset_position=CommonVector3.empty()) - - Used to place a Plumbob. - - :param offset_position: The position of the plumbob. - :type offset_position: CommonVector3 - :param bone_name: The name of the bone to slot the Plumbob to. Default is 'b__ROOT__' - :type bone_name: str, optional - :param balloon_offset_position: The position of the Balloon above Sims heads. Default is CommonVector3.empty(). - :type balloon_offset_position: CommonVector3, optional - """ - def __init__(self, offset_position: CommonVector3, bone_name: str='b__ROOT__', balloon_offset_position: CommonVector3=CommonVector3.empty()): - self._offset_position = offset_position - self._bone_name = bone_name - self._balloon_offset_position = balloon_offset_position - - @property - def bone_name(self) -> str: - """ The name of a Bone. - - :return: The name of a Bone. - :rtype: str - """ - return self._bone_name - - @property - def offset(self) -> CommonVector3: - """ The offset position of the Plumbob. - - :return: The offset of the Plumbob - :rtype: CommonVector3 - """ - return self._offset_position - - @property - def balloon_offset(self) -> CommonVector3: - """ The offset position of the Balloon. - - :return: The offset of the Balloon - :rtype: CommonVector3 - """ - return self._balloon_offset_position - - -class CommonSimPlumbobUtils: - """ Utilities for manipulating the Plumbob of a Sim. """ - @staticmethod - def hide_plumbob(sim_info: SimInfo): - """hide_plumbob(sim_info) - - Hide the plumbob of a Sim. - - .. note:: If the plumbob of the Sim is already hidden, this function will do nothing. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - """ - CommonSimPlumbobUtils.set_plumbob_position(sim_info, CommonVector3(-1000, -1000, -1000)) - - @staticmethod - def show_plumbob(sim_info: SimInfo): - """show_plumbob(sim_info) - - Show the plumbob of a Sim. - - .. note:: If the plumbob of the Sim is already shown, this function will do nothing. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - """ - CommonSimPlumbobUtils.reset_plumbob_position(sim_info) - - @staticmethod - def set_plumbob_position(sim_info: SimInfo, position: CommonVector3, bone_name: str='b__ROOT__', balloon_position: CommonVector3=CommonVector3.empty()): - """set_plumbob_position(sim_info, position, bone_name='b__ROOT__', balloon_position=CommonVector3.empty()) - - Set the position of the Plumbob for a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param position: The position to set the plumbob to. - :type position: CommonVector3 - :param bone_name: The name of the bone to slot the Plumbob to. Default is 'b__ROOT__' - :type bone_name: str, optional - :param balloon_position: The position of the Balloon above Sims heads. Default is CommonVector3.empty(). - :type balloon_position: CommonVector3, optional - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return - reslot_plumbbob(sim, CommonSimPlumbobSlot(position, bone_name=bone_name, balloon_offset_position=balloon_position)) - - @staticmethod - def reset_plumbob_position(sim_info: SimInfo): - """reset_plumbob_position(sim_info) - - Reset the position of the Plumbob for a Sim to it's original position. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return - unslot_plumbbob(sim) - - -@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.hide_plumbob', 'Hide the plumbob above a Sim.', command_arguments=( - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to hide the plumbob of.', is_optional=True, default_value='Active Sim'), -)) -def _common_hide_plumbob(output: CommonConsoleCommandOutput, sim_info: SimInfo=None): - if sim_info is None: - return - output(f'Hiding plumbob for Sim {sim_info}') - CommonSimPlumbobUtils().hide_plumbob(sim_info) - - -@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.show_plumbob', 'Show the plumbob above a Sim.', command_arguments=( - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to show the plumbob of.', is_optional=True, default_value='Active Sim'), -)) -def _common_show_plumbob(output: CommonConsoleCommandOutput, sim_info: SimInfo=None): - if sim_info is None: - return - output(f'Showing plumbob for Sim {sim_info}') - CommonSimPlumbobUtils().show_plumbob(sim_info) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_posture_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_posture_utils.py deleted file mode 100644 index da738e5..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_posture_utils.py +++ /dev/null @@ -1,266 +0,0 @@ -""" -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 -""" -from typing import Tuple, Union, Any - -from postures.posture import Posture -from postures.posture_state import PostureState -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.enums.common_posture_id import CommonPostureId -from s4ap.sims4communitylib.enums.enumtypes.common_int import CommonInt -from s4ap.sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - - -class CommonSimPostureUtils(_HasS4CLClassLog): - """Utilities for managing the posture of Sims.""" - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 'common_sim_posture_utils' - - @classmethod - def has_posture(cls, sim_info: SimInfo, posture: Union[int, CommonPostureId, Posture, CommonInt]) -> CommonTestResult: - """has_posture(sim_info, posture) - - Determine if a Sim has a posture. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param posture: The identifier of the posture to check. - :type posture: Union[int, CommonPostureId, Posture, CommonInt] - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return CommonTestResult(False, reason=f'Posture test failed because the {sim_info} is non-instantiated.') - posture_instance = cls.load_posture_by_id(posture) - if posture_instance is None: - return CommonTestResult(False, reason=f'No posture was found with id.') - for aspect in cls.get_posture_aspects(sim_info): - if not posture_instance.multi_sim and aspect.posture_type is posture_instance: - return CommonTestResult.TRUE - return CommonTestResult(False, reason=f'{sim_info} does not have posture {posture_instance}.') - - @classmethod - def has_posture_with_sim(cls, sim_info: SimInfo, target_sim_info: SimInfo, posture: Union[int, CommonPostureId, Posture, CommonInt]) -> CommonTestResult: - """has_posture_with_sim(sim_info, target_sim_info, posture) - - Determine if a Sim has a posture with another Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param target_sim_info: An instance of another Sim. - :type target_sim_info: SimInfo - :param posture: The identifier of the posture to check. - :type posture: Union[int, CommonPostureId, Posture, CommonInt] - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return CommonTestResult(False, reason=f'Posture test failed because the {sim_info} is non-instantiated.') - target_sim = CommonSimUtils.get_sim_instance(target_sim_info) - if target_sim is None: - return CommonTestResult(False, reason=f'Posture test failed because the {target_sim_info} is non-instantiated.') - posture_instance = cls.load_posture_by_id(posture) - if posture_instance is None: - return CommonTestResult(False, reason=f'No posture was found with id.') - for aspect in cls.get_posture_aspects(sim_info): - if aspect.posture_type is posture_instance and (not posture_instance.multi_sim or aspect.linked_sim is target_sim): - break - return CommonTestResult(False, reason=f'{sim_info} does not have posture {posture_instance}.') - - @classmethod - def can_sim_be_picked_up(cls, sim_info: SimInfo) -> CommonTestResult: - """can_be_picked_up(sim_info) - - Determine if a Sim can be picked up. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: True, if the Sim can be picked up. False, it not. - :rtype: bool - """ - from s4ap.sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils - from s4ap.sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils - if CommonSpeciesUtils.is_fox(sim_info) or CommonSpeciesUtils.is_small_dog(sim_info) or CommonSpeciesUtils.is_cat(sim_info): - cls.get_log().format_with_message('Success, Sim is a fox, small dog, or cat and thus may be picked up.', sim=sim_info) - return CommonTestResult.TRUE - if CommonSpeciesUtils.is_animal(sim_info) and CommonAgeUtils.is_child(sim_info): - cls.get_log().format_with_message('Success, Sim is a child animal and thus may be picked up.', sim=sim_info) - return CommonTestResult.TRUE - if CommonSpeciesUtils.is_human(sim_info) and (CommonAgeUtils.is_toddler(sim_info) or CommonAgeUtils.is_baby(sim_info)): - cls.get_log().format_with_message('Success, Sim is a toddler or baby human and thus may be picked up.', sim=sim_info) - return CommonTestResult.TRUE - from s4ap.sims4communitylib.enums.strings_enum import CommonStringId - return CommonTestResult(False, reason=f'{sim_info} cannot be picked up.', tooltip_text=CommonStringId.S4CL_SIM_CANNOT_BE_PICKED_UP, tooltip_tokens=(sim_info,)) - - @classmethod - def is_on_container_supporting_posture(cls, sim_info: SimInfo, posture: Union[int, CommonPostureId, Posture, CommonInt]) -> CommonTestResult: - """is_on_container_supporting_posture(sim_info, posture) - - Determine if the container a Sim is interacting with has a posture. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param posture: The identifier of the posture to check. - :type posture: Union[int, CommonPostureId, Posture, CommonInt] - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return CommonTestResult(False, reason=f'Posture test failed because the {sim_info} is non-instantiated.') - posture_instance = cls.load_posture_by_id(posture) - if posture_instance is None: - return CommonTestResult(False, reason=f'No posture was found with id.') - container = cls.get_posture_target(sim_info) - if container is None or not container.is_part: - sim_posture = cls.get_posture(sim_info) - return CommonTestResult(False, reason=f'Posture container for {sim_posture} is None or not a part') - parts = {container} - parts.update(container.get_overlapping_parts()) - for container_part in parts: - if container_part.supports_posture_type(posture_instance): - return CommonTestResult.TRUE - return CommonTestResult(False, reason=f'Posture container {container} does not support {posture_instance}') - - @classmethod - def is_on_container_supporting_posture_with_sim(cls, sim_info: SimInfo, target_sim_info: SimInfo, posture: Union[int, CommonPostureId, Posture, CommonInt]) -> CommonTestResult: - """is_on_container_supporting_posture(sim_info, target_sim_info, posture) - - Determine if the container a Sim is interacting with has a posture that supports another Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param target_sim_info: An instance of another Sim. - :type target_sim_info: SimInfo - :param posture: The identifier of the posture to check. - :type posture: Union[int, CommonPostureId, Posture, CommonInt] - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return CommonTestResult(False, reason=f'Posture test failed because the {sim_info} is non-instantiated.') - target_sim = CommonSimUtils.get_sim_instance(target_sim_info) - if target_sim is None: - return CommonTestResult(False, reason=f'Posture test failed because the {target_sim_info} is non-instantiated.') - posture_instance = cls.load_posture_by_id(posture) - if posture_instance is None: - return CommonTestResult(False, reason=f'No posture was found with id.') - container = cls.get_posture_target(sim_info) - if container is None or not container.is_part: - sim_posture = cls.get_posture(sim_info) - return CommonTestResult(False, reason=f'Posture container for {sim_posture} is None or not a part') - parts = {container} - parts.update(container.get_overlapping_parts()) - if not any(container_parts.supports_posture_type(posture_instance) for container_parts in parts): - return CommonTestResult(False, reason=f'Posture container {container} does not support {posture_instance}') - if posture_instance.multi_sim: - if target_sim is None: - return CommonTestResult(False, reason=f'Posture test failed because the target is None') - if target_sim is None: - return CommonTestResult(False, reason=f'Posture test failed because the target is non-instantiated.') - if not container.has_adjacent_part(target_sim): - return CommonTestResult(False, reason=f'Posture container {container} requires an adjacent part for {target_sim} since {posture_instance} is multi-Sim') - return CommonTestResult.TRUE - - @classmethod - def get_posture_target(cls, sim_info: SimInfo) -> Union[Any, None]: - """get_posture_target(sim_info) - - Retrieve the target of the posture of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The target of the posture of a Sim. - :rtype: Union[Any, None] - """ - posture = cls.get_posture(sim_info) - if posture is None: - return None - return posture.target - - @classmethod - def get_posture(cls, sim_info: SimInfo) -> Union[Posture, None]: - """get_posture(sim_info) - - Retrieve the posture of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The posture of a Sim. - :rtype: Union[Posture, None] - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return None - return sim.posture - - @classmethod - def get_posture_aspects(cls, sim_info: SimInfo) -> Tuple[Posture]: - """get_posture_aspects(sim_info) - - Retrieve the posture aspects of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The aspects of the posture of the Sim. - :rtype: Tuple[Posture] - """ - posture_state = cls.get_posture_state(sim_info) - if posture_state is None: - return tuple() - return posture_state.aspects - - @classmethod - def get_posture_state(cls, sim_info: SimInfo) -> Union[PostureState, None]: - """get_posture_state(sim_info) - - Retrieve the posture aspects of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The posture state of a Sim. - :rtype: Union[PostureState, None] - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return None - # noinspection PyPropertyAccess - return sim.posture_state - - @classmethod - def load_posture_by_id(cls, posture: Union[int, CommonPostureId, Posture, CommonInt]) -> Union[Posture, None]: - """load_posture_by_id(posture) - - Load an instance of a Posture by its identifier. - - :param posture: The identifier of a Posture. - :type posture: Union[int, CommonPostureId, Posture, CommonInt] - :return: An instance of a Posture matching the decimal identifier or None if not found. - :rtype: Union[Posture, None] - """ - if isinstance(posture, Posture): - return posture - # noinspection PyBroadException - try: - # noinspection PyCallingNonCallable - posture_instance = posture() - if isinstance(posture_instance, Posture): - # noinspection PyTypeChecker - return posture - except: - pass - # noinspection PyBroadException - try: - posture: int = int(posture) - except: - # noinspection PyTypeChecker - posture: Posture = posture - return posture - - from sims4.resources import Types - from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils - return CommonResourceUtils.load_instance(Types.POSTURE, posture) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_pregnancy_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_pregnancy_utils.py deleted file mode 100644 index 44ca51d..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_pregnancy_utils.py +++ /dev/null @@ -1,622 +0,0 @@ -""" -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 -""" -from typing import Union -from sims.pregnancy.pregnancy_enums import PregnancyOrigin -from sims.pregnancy.pregnancy_tracker import PregnancyTracker -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.enums.buffs_enum import CommonBuffId -from s4ap.sims4communitylib.enums.common_object_state_value_ids import CommonObjectStateValueId -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.enums.traits_enum import CommonTraitId -from s4ap.sims4communitylib.logging.has_class_log import HasClassLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ - CommonConsoleCommandArgument -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.objects.common_object_state_utils import CommonObjectStateUtils -from s4ap.sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils -from s4ap.sims4communitylib.utils.sims.common_buff_utils import CommonBuffUtils -from s4ap.sims4communitylib.utils.sims.common_relationship_utils import CommonRelationshipUtils -from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from s4ap.sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils -from s4ap.sims4communitylib.enums.statistics_enum import CommonStatisticId -from s4ap.sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils -from s4ap.sims4communitylib.utils.sims.common_sim_statistic_utils import CommonSimStatisticUtils -from statistics.commodity import Commodity - - -class CommonSimPregnancyUtils(HasClassLog): - """Utilities for manipulating the pregnancy status of Sims. - - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - return ModInfo.get_identity() - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 'common_sim_pregnancy_utils' - - @classmethod - def is_pregnant(cls, sim_info: SimInfo) -> bool: - """is_pregnant(sim_info) - - Determine if the a Sim is pregnant. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the specified Sim is pregnant. False, if not. - :rtype: bool - """ - pregnancy_tracker = cls._get_pregnancy_tracker(sim_info) - if pregnancy_tracker is None: - return False - return pregnancy_tracker.is_pregnant - - @classmethod - def has_permission_for_pregnancies(cls, sim_info: SimInfo) -> CommonTestResult: - """has_permission_for_pregnancies(sim_info) - - Determine if a Sim has the permissions to cause a Pregnancy or to become Pregnant. (Regardless of traits) - - .. note:: In the vanilla game, only Adult and Elder Sims have permission for pregnancies. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of the test. True, if the test passes. False, if the test fails. - :rtype: CommonTestResult - """ - if CommonAgeUtils.is_adult_or_elder(sim_info): - return CommonTestResult(True, reason=f'{sim_info} has permission to engage in pregnancy. They are either an Adult or an Elder Sim.') - return CommonTestResult(False, reason=f'{sim_info} does not have permission to engage in pregnancy. They are neither an Adult nor an Elder Sim.') - - @classmethod - def has_permission_for_pregnancies_with(cls, sim_info_a: SimInfo, sim_info_b: SimInfo) -> CommonTestResult: - """has_permission_for_pregnancies_with(sim_info_a, sim_info_b) - - Determine if Sim A has the permissions to cause a Pregnancy with Sim B or to become pregnant from Sim B. - - .. note:: In the vanilla game, only Adult and Elder Sims of the same species have permission for pregnancies with each other. - - :param sim_info_a: An instance of a Sim. (Sim A) - :type sim_info_a: SimInfo - :param sim_info_b: An instance of a Sim. (Sim B) - :type sim_info_b: SimInfo - :return: The result of the test. True, if the test passes. False, if the test fails. - :rtype: CommonTestResult - """ - sim_a_has_permission = cls.has_permission_for_pregnancies(sim_info_a) - if not sim_a_has_permission: - return CommonTestResult(False, reason=f'{sim_info_a} does not have permission for pregnancies with {sim_info_b}. {sim_a_has_permission}') - sim_b_has_permission = cls.has_permission_for_pregnancies(sim_info_b) - if not sim_b_has_permission: - return CommonTestResult(False, reason=f'{sim_info_a} does not have permission for pregnancies with {sim_info_b}. {sim_b_has_permission}') - if not CommonSpeciesUtils.are_same_species(sim_info_a, sim_info_b): - # If both Sims are dogs, that is an ok combination, even though their species do not match. - if not CommonSpeciesUtils.is_dog(sim_info_a) or not CommonSpeciesUtils.is_dog(sim_info_b): - return CommonTestResult(False, reason=f'{sim_info_a} does not have permission for pregnancies with {sim_info_b}. {sim_info_a} and {sim_info_b} are not the same species.') - romantic_relationships_result = CommonRelationshipUtils.has_permission_for_romantic_relationship_with(sim_info_a, sim_info_b) - if not romantic_relationships_result: - return CommonTestResult(False, reason=f'{sim_info_a} does not have permission for pregnancies with {sim_info_b}. {romantic_relationships_result}') - return CommonTestResult(True, reason=f'{sim_info_a} has permission for pregnancies with {sim_info_b}.') - - @classmethod - def get_pregnancy_partner(cls, sim_info: SimInfo) -> Union[SimInfo, None]: - """get_pregnancy_partner(sim_info) - - Retrieve the Sim that caused a Sim to become pregnant. - - :param sim_info: The Sim to get the partner of. - :type sim_info: SimInfo - :return: The Sim that impregnated the specified Sim or None if not found. - :rtype: Union[SimInfo, None] - """ - pregnancy_tracker = cls._get_pregnancy_tracker(sim_info) - if pregnancy_tracker is None: - return None - partner_sim = pregnancy_tracker.get_partner() - if partner_sim is None: - return None - return CommonSimUtils.get_sim_info(partner_sim) - - @classmethod - def start_pregnancy(cls, 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 = cls._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, single_sim_is_allowed=sim_info is partner_sim_info) - pregnancy_tracker.clear_pregnancy_visuals() - pregnancy_stat = cls.determine_pregnancy_statistic(sim_info) - if pregnancy_stat is not None: - CommonSimStatisticUtils.set_statistic_value(sim_info, pregnancy_stat, 1.0) - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is not None: - CommonObjectStateUtils.set_object_state(sim, CommonObjectStateValueId.PREGNANT_NOT_SHOWING) - return True - - @classmethod - def induce_labor_in_sim(cls, sim_info: SimInfo) -> bool: - """induce_labor(sim_info) - - Induce Labor in a pregnant Sim. - - :param sim_info: The Sim to go into labor. - :type sim_info: SimInfo - :return: True, if labor was induced successfully. False, if not. - """ - if sim_info is None or not cls.is_pregnant(sim_info): - return False - pregnancy_stat = cls.determine_pregnancy_statistic(sim_info) - if pregnancy_stat is not None: - CommonSimStatisticUtils.set_statistic_value(sim_info, pregnancy_stat, 100.0) - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is not None: - CommonObjectStateUtils.set_object_state(sim, CommonObjectStateValueId.PREGNANT_IN_LABOR) - buff_id = cls.get_in_labor_buff(sim_info) - if buff_id != -1: - result = CommonBuffUtils.add_buff(sim_info, buff_id, buff_reason=CommonStringId.S4CL_BUFF_REASON_FROM_DEBUG) - return result.result - return True - - @classmethod - def clear_pregnancy(cls, 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 = cls._get_pregnancy_tracker(sim_info) - if pregnancy_tracker is None: - return False - sim_info.pregnancy_tracker.clear_pregnancy() - pregnancy_stat = cls.determine_pregnancy_statistic(sim_info) - if pregnancy_stat is not None: - CommonSimStatisticUtils.remove_statistic(sim_info, pregnancy_stat) - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is not None: - CommonObjectStateUtils.set_object_state(sim, CommonObjectStateValueId.PREGNANT_NOT_PREGNANT) - return True - - @classmethod - def can_be_impregnated(cls, sim_info: SimInfo) -> CommonTestResult: - """can_be_impregnated(sim_info) - - Determine if a Sim can be impregnated. - - :param sim_info: The Sim being checked. - :type sim_info: SimInfo - :return: The result of testing. True, if they can. False, if they cannot. - :rtype: CommonTestResult - """ - from s4ap.sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils - from s4ap.sims4communitylib.enums.traits_enum import CommonTraitId - can_be_impregnated_trait = cls.determine_can_be_impregnated_trait(sim_info) - can_not_be_impregnated_trait = cls.determine_can_not_be_impregnated_trait(sim_info) - if can_be_impregnated_trait is None: - return CommonTestResult(False, reason=f'No Can Be Impregnated trait was found for Sim {sim_info}.') - if can_not_be_impregnated_trait is None: - return CommonTestResult(False, reason=f'No Cannot Be Impregnated trait was found for Sim {sim_info}.') - if CommonSpeciesUtils.is_animal(sim_info): - if not CommonSpeciesUtils.is_horse(sim_info): - if CommonTraitUtils.has_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_NOT_REPRODUCE): - return CommonTestResult(False, reason=f'Animal Sim {sim_info} had the Cannot Reproduce trait.') - if not CommonTraitUtils.has_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_REPRODUCE): - return CommonTestResult(False, reason=f'Animal Sim {sim_info} did not have the Can Reproduce trait.') - - if CommonTraitUtils.has_trait(sim_info, can_not_be_impregnated_trait): - return CommonTestResult(False, reason=f'Sim had the Cannot Be Impregnated trait.') - if not CommonTraitUtils.has_trait(sim_info, can_be_impregnated_trait): - return CommonTestResult(False, reason=f'Sim did not have the Can Be Impregnated trait.') - return CommonTestResult(True, reason=f'Sim can be impregnated by other Sims.') - - @classmethod - def can_impregnate(cls, sim_info: SimInfo) -> CommonTestResult: - """can_impregnate(sim_info) - - Determine if a Sim can impregnate other sims. - - :param sim_info: The Sim being checked. - :type sim_info: SimInfo - :return: The result of testing. True, if they can. False, if they cannot. - :rtype: CommonTestResult - """ - from s4ap.sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils - from s4ap.sims4communitylib.enums.traits_enum import CommonTraitId - can_impregnate_trait = cls.determine_can_impregnate_trait(sim_info) - can_not_impregnate_trait = cls.determine_can_not_impregnate_trait(sim_info) - if can_impregnate_trait is None: - return CommonTestResult(False, reason=f'No Can Impregnate trait was found for Sim {sim_info}.') - if can_not_impregnate_trait is None: - return CommonTestResult(False, reason=f'No Cannot Impregnate trait was found for Sim {sim_info}.') - if CommonSpeciesUtils.is_animal(sim_info): - if not CommonSpeciesUtils.is_horse(sim_info): - if CommonTraitUtils.has_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_NOT_REPRODUCE): - return CommonTestResult(False, reason=f'Sim had the Cannot Reproduce trait.') - if not CommonTraitUtils.has_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_REPRODUCE): - return CommonTestResult(False, reason=f'Sim did not have the Can Reproduce trait.') - - if CommonTraitUtils.has_trait(sim_info, can_not_impregnate_trait): - return CommonTestResult(False, reason=f'Sim had the Cannot Impregnate trait.') - if not CommonTraitUtils.has_trait(sim_info, can_impregnate_trait): - return CommonTestResult(False, reason=f'Sim did not have the Can Impregnate trait') - return CommonTestResult(True, reason=f'Sim can impregnate other Sims.') - - @classmethod - def get_partner_of_pregnant_sim(cls, 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 = cls._get_pregnancy_tracker(sim_info) - if pregnancy_tracker is None: - return None - return pregnancy_tracker.get_partner() - - @classmethod - def set_pregnancy_progress(cls, sim_info: SimInfo, value: float): - """set_pregnancy_progress(sim_info, value) - - Set the pregnancy progress of a Sim. - - :param sim_info: The Sim being checked. - :type sim_info: SimInfo - :param value: The value to set the progress to. - :type value: float - :return: The current progress of the pregnancy of a Sim. - :rtype: float - """ - if value > 100.0: - value = 100.0 - if value < 0.0: - value = 0.0 - pregnancy_tracker = cls._get_pregnancy_tracker(sim_info) - if pregnancy_tracker is None or not cls.is_pregnant(sim_info): - return - 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: Commodity = statistic_tracker.get_statistic(pregnancy_commodity_type, add=False) - if not pregnancy_commodity: - return - pregnancy_commodity.set_value(value) - - @classmethod - def get_pregnancy_progress(cls, 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 = cls._get_pregnancy_tracker(sim_info) - if pregnancy_tracker is None or not cls.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() - - @classmethod - def get_pregnancy_rate(cls, 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 = cls._get_pregnancy_tracker(sim_info) - if pregnancy_tracker is None: - return 0.0 - return pregnancy_tracker.PREGNANCY_RATE - - @classmethod - def get_in_labor_buff(cls, 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] - """ - log = cls.get_log() - from s4ap.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 - elif CommonSpeciesUtils.is_horse(sim_info): - log.debug('\'{}\' is a Horse.'.format(sim_name)) - if is_female: - log.debug('\'{}\' is Female.'.format(sim_name)) - return CommonBuffId.PREGNANCY_IN_LABOR_PET_HORSE - log.debug('No appropriate Buff located to induce labor in \'{}\'.'.format(sim_name)) - return -1 - - @classmethod - def get_pregnancy_tracker(cls, sim_info: SimInfo) -> Union[PregnancyTracker, None]: - """get_pregnancy_tracker(sim_info) - - Retrieve the tracker for tracking pregnancy of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The pregnancy tracker for the Sim or None if the Sim does not have a pregnancy tracker. - :rtype: Union[PregnancyTracker, None] - """ - return cls._get_pregnancy_tracker(sim_info) - - @classmethod - def _get_pregnancy_tracker(cls, sim_info: SimInfo) -> Union[PregnancyTracker, None]: - if sim_info is None: - return None - return sim_info.pregnancy_tracker - - @classmethod - def determine_pregnancy_statistic(cls, sim_info: SimInfo) -> Union[CommonStatisticId, None]: - """determine_pregnancy_statistic(sim_info) - - Determine the statistic that would indicate the pregnancy progress of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The statistic that would indicate the pregnancy progress of the Sim or None if no trait is found. - :rtype: Union[CommonStatisticId, None] - """ - if CommonSpeciesUtils.is_human(sim_info): - return CommonStatisticId.PREGNANCY - elif CommonSpeciesUtils.is_large_dog(sim_info): - return CommonStatisticId.PREGNANCY_DOG - elif CommonSpeciesUtils.is_small_dog(sim_info): - return CommonStatisticId.PREGNANCY_DOG - elif CommonSpeciesUtils.is_cat(sim_info): - return CommonStatisticId.PREGNANCY_CAT - elif CommonSpeciesUtils.is_fox(sim_info): - return CommonStatisticId.PREGNANCY - elif CommonSpeciesUtils.is_horse(sim_info): - return CommonStatisticId.PREGNANCY_HORSE - return None - - @classmethod - def determine_can_impregnate_trait(cls, sim_info: SimInfo) -> Union[CommonTraitId, None]: - """determine_can_impregnate_trait(sim_info) - - Determine the trait that would indicate a Sim can impregnate other Sims. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The trait that would indicate the Sim can impregnate other Sims or None if no trait is found. - :rtype: Union[CommonTraitId, None] - """ - if CommonSpeciesUtils.is_human(sim_info): - return CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE - elif CommonSpeciesUtils.is_large_dog(sim_info): - return CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_LARGE_DOG - elif CommonSpeciesUtils.is_small_dog(sim_info): - return CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_SMALL_DOG - elif CommonSpeciesUtils.is_cat(sim_info): - return CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_CAT - elif CommonSpeciesUtils.is_fox(sim_info): - return CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_FOX - elif CommonSpeciesUtils.is_horse(sim_info): - return CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE_HORSE - return None - - @classmethod - def determine_can_not_impregnate_trait(cls, sim_info: SimInfo) -> Union[CommonTraitId, None]: - """determine_can_not_impregnate_trait(sim_info) - - Determine the trait that would indicate a Sim can not impregnate other Sims. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The trait that would indicate the Sim can not impregnate other Sims or None if no trait is found. - :rtype: Union[CommonTraitId, None] - """ - if CommonSpeciesUtils.is_human(sim_info): - return CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE - elif CommonSpeciesUtils.is_large_dog(sim_info): - return CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_LARGE_DOG - elif CommonSpeciesUtils.is_small_dog(sim_info): - return CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_SMALL_DOG - elif CommonSpeciesUtils.is_cat(sim_info): - return CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_CAT - elif CommonSpeciesUtils.is_fox(sim_info): - return CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_FOX - elif CommonSpeciesUtils.is_horse(sim_info): - return CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE_HORSE - return None - - @classmethod - def determine_can_be_impregnated_trait(cls, sim_info: SimInfo) -> Union[CommonTraitId, None]: - """determine_can_be_impregnated_trait(sim_info) - - Determine the trait that would indicate a Sim can be impregnated by other Sims. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The trait that would indicate the Sim can be impregnated by other Sims or None if no trait is found. - :rtype: Union[CommonTraitId, None] - """ - if CommonSpeciesUtils.is_human(sim_info): - return CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED - elif CommonSpeciesUtils.is_large_dog(sim_info): - return CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_LARGE_DOG - elif CommonSpeciesUtils.is_small_dog(sim_info): - return CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_SMALL_DOG - elif CommonSpeciesUtils.is_cat(sim_info): - return CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_CAT - elif CommonSpeciesUtils.is_fox(sim_info): - return CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_FOX - elif CommonSpeciesUtils.is_horse(sim_info): - return CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED_HORSE - return None - - @classmethod - def determine_can_not_be_impregnated_trait(cls, sim_info: SimInfo) -> Union[CommonTraitId, None]: - """determine_can_not_be_impregnated_trait(sim_info) - - Determine the trait that would indicate a Sim can not be impregnated by other Sims. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The trait that would indicate the Sim can not be impregnated by other Sims or None if no trait is found. - :rtype: Union[CommonTraitId, None] - """ - if CommonSpeciesUtils.is_human(sim_info): - return CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED - elif CommonSpeciesUtils.is_large_dog(sim_info): - return CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_LARGE_DOG - elif CommonSpeciesUtils.is_small_dog(sim_info): - return CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_SMALL_DOG - elif CommonSpeciesUtils.is_cat(sim_info): - return CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_CAT - elif CommonSpeciesUtils.is_fox(sim_info): - return CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_FOX - elif CommonSpeciesUtils.is_horse(sim_info): - return CommonTraitId.S4CL_GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED_HORSE - return None - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.print_pregnancy_partner', - 'Print the Sim that got a Sim pregnant. If they are pregnant.', - command_arguments=( - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to change.', is_optional=True, default_value='Active Sim'), - ), -) -def _common_print_pregnancy_partner(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): - if sim_info is None: - return - output(f'Attempting to print the pregnancy partner of {sim_info}.') - partner_sim_info = CommonSimPregnancyUtils.get_pregnancy_partner(sim_info) - if partner_sim_info is None: - output(f'No Sim found to have impregnated {sim_info}.') - else: - output(f'{partner_sim_info} is the Sim that impregnated {sim_info}.') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.stop_pregnancy', - 'End the pregnancy of a Sim. Does your Sim have trouble with pregnancy? Then Stop It!', - command_arguments=( - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to change.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.pregnancy_begone', - ) -) -def _common_command_stop_pregnancy(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): - if sim_info is None: - return - output(f'Attempting to stop the pregnancy of {sim_info}.') - result = CommonSimPregnancyUtils.clear_pregnancy(sim_info) - if result: - output(f'SUCCESS: Successfully stopped the pregnancy of {sim_info}.') - else: - output(f'FAILED: Failed to stop the pregnancy of {sim_info}.') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.set_pregnancy_progress', - 'Set the progress of a Sims pregnancy.', - command_arguments=( - CommonConsoleCommandArgument('value', 'Percentage', 'The percentage of progress.'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to change.', is_optional=True, default_value='Active Sim'), - ), -) -def _common_command_set_pregnancy_progress(output: CommonConsoleCommandOutput, value: float, sim_info: SimInfo = None): - if sim_info is None: - return - output(f'Attempting to set pregnancy progress of {sim_info} to {value}.') - if not CommonSimPregnancyUtils.is_pregnant(sim_info): - output(f'{sim_info} is not pregnant.') - return - CommonSimPregnancyUtils.set_pregnancy_progress(sim_info, value) - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.stop_all_pregnancies', - 'End the pregnancy of all Sims. Wipe away those pregnancies like they never happened.', - command_aliases=( - 's4clib.pregnancies_begone', - ) -) -def _common_command_stop_all_pregnancies(output: CommonConsoleCommandOutput): - output('Attempting to stop the pregnancies of all available Sims. This may take awhile.') - sim_count = 0 - for sim_info in CommonSimUtils.get_instanced_sim_info_for_all_sims_generator(include_sim_callback=CommonSimPregnancyUtils.is_pregnant): - # noinspection PyBroadException - try: - if not CommonSimPregnancyUtils.clear_pregnancy(sim_info): - output(f'FAILED: Failed to stop pregnancy of {sim_info}') - continue - output(f'SUCCESS: Successfully stopped pregnancy of {sim_info}') - sim_count += 1 - except Exception as ex: - output(f'ERROR: Failed to stop the pregnancy of {sim_info}. {ex}') - output(f'Stopped the pregnancies of {sim_count} Sim(s)') diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_rabbit_hole_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_rabbit_hole_utils.py deleted file mode 100644 index 84a17b6..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_rabbit_hole_utils.py +++ /dev/null @@ -1,102 +0,0 @@ -""" -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 -""" -from typing import Callable, Union - -from rabbit_hole.rabbit_hole import RabbitHole -from services.rabbit_hole_service import RabbitHoleService -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.utils.sims.common_rabbit_hole_utils import CommonRabbitHoleUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - - -class CommonSimRabbitHoleUtils: - """Utilities for manipulating Rabbit Holes for Sims.""" - @classmethod - def get_first_rabbit_hole_id_for_sim(cls, sim_info: SimInfo) -> Union[int, None]: - """get_rabbit_hole_id(sim_info) - - Retrieve the id of the rabbit hole a Sim is in. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The id of the first rabbit hole the Sim is in or None if not found. - :rtype: Union[int, None] - """ - sim_id = CommonSimUtils.get_sim_id(sim_info) - rabbit_hole_service = CommonRabbitHoleUtils.get_rabbit_hole_service() - rabbit_hole_id = rabbit_hole_service.get_head_rabbit_hole_id(sim_id) - if rabbit_hole_id is None or rabbit_hole_id < 0: - return None - return rabbit_hole_id - - @classmethod - def put_sim_into_rabbit_hole(cls, sim_info: SimInfo, rabbit_hole: Union[RabbitHole, int], on_exit_rabbit_hole_callback: Callable[[SimInfo, bool], None] = None) -> CommonTestResult: - """put_sim_into_rabbit_hole(sim_info, rabbit_hole_identifier, on_exit_rabbit_hole_callback=None) - - Put a Sim into a Rabbit Hole. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param rabbit_hole: The identifier of a rabbit hole to put the Sim into. - :type rabbit_hole: Union[RabbitHole, int] - :param on_exit_rabbit_hole_callback: A callback invoked upon the Sim leaving the rabbit hole. Default is None. - :type on_exit_rabbit_hole_callback: Callable[[SimInfo, bool], None] - :return: A result indicating the success of putting the Sim into the rabbit hole. - :rtype: CommonTestResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - rabbit_hole = CommonRabbitHoleUtils.load_rabbit_hole_by_id(rabbit_hole) - if rabbit_hole is None: - return CommonTestResult(False, reason='RabbitHole was None.') - - sim_id = CommonSimUtils.get_sim_id(sim_info) - existing_rabbit_hole_id = cls.get_first_rabbit_hole_id_for_sim(sim_info) - if existing_rabbit_hole_id is not None: - return CommonTestResult(False, reason='Sim is already in a rabbit hole.') - rabbit_hole_service = CommonRabbitHoleUtils.get_rabbit_hole_service() - rabbit_hole_id = rabbit_hole_service.put_sim_in_managed_rabbithole(sim_info, rabbit_hole_type=rabbit_hole) - - if rabbit_hole_id is not None: - if on_exit_rabbit_hole_callback is not None: - def _on_exit_rabbit_hole(canceled: bool = False): - on_exit_rabbit_hole_callback(sim_info, canceled) - rabbit_hole_service.remove_rabbit_hole_expiration_callback(sim_id, rabbit_hole_id, _on_exit_rabbit_hole) - - rabbit_hole_service.set_rabbit_hole_expiration_callback(sim_id, rabbit_hole_id, _on_exit_rabbit_hole) - return CommonTestResult.TRUE - return CommonTestResult(False, reason='Failed to put the Sim into the rabbit hole.') - - @classmethod - def try_remove_sim_from_rabbit_hole(cls, sim_info: SimInfo, on_remove_from_rabbit_hole_result_callback: Callable[[SimInfo, bool], None] = None) -> CommonTestResult: - """try_remove_sim_from_rabbit_hole(sim_info, on_remove_from_rabbit_hole_result_callback=None) - - Remove a Sim from a rabbit hole. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param on_remove_from_rabbit_hole_result_callback: A callback invoked upon the Sim being removed from the rabbit hole. Default is None. - :type on_remove_from_rabbit_hole_result_callback: Callable[[SimInfo, bool], None] - :return: A result indicating the success of the removal. - :rtype: CommonTestResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - existing_rabbit_hold_id = cls.get_first_rabbit_hole_id_for_sim(sim_info) - if existing_rabbit_hold_id is None: - return CommonTestResult.TRUE - rabbit_hole_service: RabbitHoleService = CommonRabbitHoleUtils.get_rabbit_hole_service() - - def _remove_from_rabbit_hole_callback(result: bool): - if on_remove_from_rabbit_hole_result_callback is not None: - on_remove_from_rabbit_hole_result_callback(sim_info, result) - - sim_id = CommonSimUtils.get_sim_id(sim_info) - rabbit_hole_service.try_remove_sim_from_rabbit_hole(sim_id, existing_rabbit_hold_id, callback=_remove_from_rabbit_hole_callback) - return CommonTestResult.TRUE diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_relationship_expectation_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_relationship_expectation_utils.py deleted file mode 100644 index 0fd37ab..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_relationship_expectation_utils.py +++ /dev/null @@ -1,223 +0,0 @@ -""" -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 -""" -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.enums.traits_enum import CommonTraitId -from s4ap.sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils - - -class CommonSimRelationshipExpectationUtils: - """ Utilities for Sim relationship expectations. """ - @classmethod - def is_open_to_change(cls, sim_info: SimInfo) -> CommonTestResult: - """is_open_to_change(sim_info) - - Determine if the jealousy triggers of a Sim can be changed through talking. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of the test. True, if the test passes. False, if not. - :rtype: CommonTestResult - """ - if CommonTraitUtils.has_trait(sim_info, CommonTraitId.RELATIONSHIP_EXPECTATIONS_OPEN_TO_CHANGE_NO): - return CommonTestResult(False, reason=f'{sim_info} is not open to relationship expectation changes.') - return CommonTraitUtils.has_trait(sim_info, CommonTraitId.RELATIONSHIP_EXPECTATIONS_OPEN_TO_CHANGE_YES) - - @classmethod - def is_not_open_to_change(cls, sim_info: SimInfo) -> CommonTestResult: - """is_not_open_to_change(sim_info) - - Determine if the jealousy triggers of a Sim can not be changed through talking. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of the test. True, if the test passes. False, if not. - :rtype: CommonTestResult - """ - if CommonTraitUtils.has_trait(sim_info, CommonTraitId.RELATIONSHIP_EXPECTATIONS_OPEN_TO_CHANGE_YES): - return CommonTestResult(False, reason=f'{sim_info} is open to relationship expectation changes.') - return CommonTraitUtils.has_trait(sim_info, CommonTraitId.RELATIONSHIP_EXPECTATIONS_OPEN_TO_CHANGE_NO) - - @classmethod - def set_open_to_change(cls, sim_info: SimInfo, is_open_to_change: bool) -> CommonExecutionResult: - """set_open_to_change(sim_info, is_open_to_change) - - Set if the jealousy triggers of a Sim can be changed through talking. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param is_open_to_change: Set True to indicate a Sim is open to change. Set False, if not. - :type is_open_to_change: bool - :return: The result of the test. True, if the test passes. False, if not. - :rtype: CommonTestResult - """ - if is_open_to_change: - to_remove_trait = CommonTraitId.RELATIONSHIP_EXPECTATIONS_OPEN_TO_CHANGE_NO - to_add_trait = CommonTraitId.RELATIONSHIP_EXPECTATIONS_OPEN_TO_CHANGE_YES - else: - to_remove_trait = CommonTraitId.RELATIONSHIP_EXPECTATIONS_OPEN_TO_CHANGE_YES - to_add_trait = CommonTraitId.RELATIONSHIP_EXPECTATIONS_OPEN_TO_CHANGE_NO - CommonTraitUtils.remove_trait(sim_info, to_remove_trait) - return CommonTraitUtils.add_trait(sim_info, to_add_trait) - - @classmethod - def has_emotional_exclusivity(cls, sim_info: SimInfo) -> CommonTestResult: - """has_emotional_exclusivity(sim_info) - - Determine if the Sim has emotional exclusivity. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of the test. True, if the test passes. False, if not. - :rtype: CommonTestResult - """ - if CommonTraitUtils.has_trait(sim_info, CommonTraitId.RELATIONSHIP_EXPECTATIONS_EMOTIONAL_EXCLUSIVITY_NO): - return CommonTestResult(False, reason=f'{sim_info} does not have emotional exclusivity.') - return CommonTraitUtils.has_trait(sim_info, CommonTraitId.RELATIONSHIP_EXPECTATIONS_EMOTIONAL_EXCLUSIVITY_YES) - - @classmethod - def does_not_have_emotional_exclusivity(cls, sim_info: SimInfo) -> CommonTestResult: - """does_not_have_emotional_exclusivity(sim_info) - - Determine if the Sim does not have emotional exclusivity. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of the test. True, if the test passes. False, if not. - :rtype: CommonTestResult - """ - if CommonTraitUtils.has_trait(sim_info, CommonTraitId.RELATIONSHIP_EXPECTATIONS_EMOTIONAL_EXCLUSIVITY_YES): - return CommonTestResult(False, reason=f'{sim_info} has emotional exclusivity.') - return CommonTraitUtils.has_trait(sim_info, CommonTraitId.RELATIONSHIP_EXPECTATIONS_EMOTIONAL_EXCLUSIVITY_NO) - - @classmethod - def set_emotional_exclusivity(cls, sim_info: SimInfo, has_emotional_exclusivity: bool) -> CommonExecutionResult: - """set_emotional_exclusivity(sim_info, has_emotional_exclusivity) - - Set if a Sim has emotional exclusivity with their partner. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param has_emotional_exclusivity: Set True to indicate a Sim has emotional exclusivity with their partner. Set False, if not. - :type has_emotional_exclusivity: bool - :return: The result of the test. True, if the test passes. False, if not. - :rtype: CommonTestResult - """ - if has_emotional_exclusivity: - to_remove_trait = CommonTraitId.RELATIONSHIP_EXPECTATIONS_EMOTIONAL_EXCLUSIVITY_NO - to_add_trait = CommonTraitId.RELATIONSHIP_EXPECTATIONS_EMOTIONAL_EXCLUSIVITY_YES - else: - to_remove_trait = CommonTraitId.RELATIONSHIP_EXPECTATIONS_EMOTIONAL_EXCLUSIVITY_YES - to_add_trait = CommonTraitId.RELATIONSHIP_EXPECTATIONS_EMOTIONAL_EXCLUSIVITY_NO - CommonTraitUtils.remove_trait(sim_info, to_remove_trait) - return CommonTraitUtils.add_trait(sim_info, to_add_trait) - - @classmethod - def has_physical_exclusivity(cls, sim_info: SimInfo) -> CommonTestResult: - """has_physical_exclusivity(sim_info) - - Determine if the Sim has physical exclusivity. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of the test. True, if the test passes. False, if not. - :rtype: CommonTestResult - """ - if CommonTraitUtils.has_trait(sim_info, CommonTraitId.RELATIONSHIP_EXPECTATIONS_PHYSICAL_EXCLUSIVITY_NO): - return CommonTestResult(False, reason=f'{sim_info} does not have physical exclusivity.') - return CommonTraitUtils.has_trait(sim_info, CommonTraitId.RELATIONSHIP_EXPECTATIONS_PHYSICAL_EXCLUSIVITY_YES) - - @classmethod - def does_not_have_physical_exclusivity(cls, sim_info: SimInfo) -> CommonTestResult: - """does_not_have_physical_exclusivity(sim_info) - - Determine if the Sim does not have physical exclusivity. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of the test. True, if the test passes. False, if not. - :rtype: CommonTestResult - """ - if CommonTraitUtils.has_trait(sim_info, CommonTraitId.RELATIONSHIP_EXPECTATIONS_PHYSICAL_EXCLUSIVITY_YES): - return CommonTestResult(False, reason=f'{sim_info} has physical exclusivity.') - return CommonTraitUtils.has_trait(sim_info, CommonTraitId.RELATIONSHIP_EXPECTATIONS_PHYSICAL_EXCLUSIVITY_NO) - - @classmethod - def set_physical_exclusivity(cls, sim_info: SimInfo, has_physical_exclusivity: bool) -> CommonExecutionResult: - """set_physical_exclusivity(sim_info, has_physical_exclusivity) - - Set if a Sim has physical exclusivity with their partner. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param has_physical_exclusivity: Set True to indicate a Sim has physical exclusivity with their partner. Set False, if not. - :type has_physical_exclusivity: bool - :return: The result of the test. True, if the test passes. False, if not. - :rtype: CommonTestResult - """ - if has_physical_exclusivity: - to_remove_trait = CommonTraitId.RELATIONSHIP_EXPECTATIONS_PHYSICAL_EXCLUSIVITY_NO - to_add_trait = CommonTraitId.RELATIONSHIP_EXPECTATIONS_PHYSICAL_EXCLUSIVITY_YES - else: - to_remove_trait = CommonTraitId.RELATIONSHIP_EXPECTATIONS_PHYSICAL_EXCLUSIVITY_YES - to_add_trait = CommonTraitId.RELATIONSHIP_EXPECTATIONS_PHYSICAL_EXCLUSIVITY_NO - CommonTraitUtils.remove_trait(sim_info, to_remove_trait) - return CommonTraitUtils.add_trait(sim_info, to_add_trait) - - @classmethod - def has_woohoo_exclusivity(cls, sim_info: SimInfo) -> CommonTestResult: - """has_woohoo_exclusivity(sim_info) - - Determine if the Sim has woohoo exclusivity. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of the test. True, if the test passes. False, if not. - :rtype: CommonTestResult - """ - if CommonTraitUtils.has_trait(sim_info, CommonTraitId.RELATIONSHIP_EXPECTATIONS_WOOHOO_EXCLUSIVITY_NO): - return CommonTestResult(False, reason=f'{sim_info} does not have woohoo exclusivity.') - return CommonTraitUtils.has_trait(sim_info, CommonTraitId.RELATIONSHIP_EXPECTATIONS_WOOHOO_EXCLUSIVITY_YES) - - @classmethod - def does_not_have_woohoo_exclusivity(cls, sim_info: SimInfo) -> CommonTestResult: - """does_not_have_woohoo_exclusivity(sim_info) - - Determine if the Sim does not have woohoo exclusivity. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of the test. True, if the test passes. False, if not. - :rtype: CommonTestResult - """ - if CommonTraitUtils.has_trait(sim_info, CommonTraitId.RELATIONSHIP_EXPECTATIONS_WOOHOO_EXCLUSIVITY_YES): - return CommonTestResult(False, reason=f'{sim_info} has woohoo exclusivity.') - return CommonTraitUtils.has_trait(sim_info, CommonTraitId.RELATIONSHIP_EXPECTATIONS_WOOHOO_EXCLUSIVITY_NO) - - @classmethod - def set_woohoo_exclusivity(cls, sim_info: SimInfo, has_woohoo_exclusivity: bool) -> CommonExecutionResult: - """set_woohoo_exclusivity(sim_info, has_woohoo_exclusivity) - - Set if a Sim has woohoo exclusivity with their partner. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param has_woohoo_exclusivity: Set True to indicate a Sim has woohoo exclusivity with their partner. Set False, if not. - :type has_woohoo_exclusivity: bool - :return: The result of the test. True, if the test passes. False, if not. - :rtype: CommonTestResult - """ - if has_woohoo_exclusivity: - to_remove_trait = CommonTraitId.RELATIONSHIP_EXPECTATIONS_WOOHOO_EXCLUSIVITY_NO - to_add_trait = CommonTraitId.RELATIONSHIP_EXPECTATIONS_WOOHOO_EXCLUSIVITY_YES - else: - to_remove_trait = CommonTraitId.RELATIONSHIP_EXPECTATIONS_WOOHOO_EXCLUSIVITY_YES - to_add_trait = CommonTraitId.RELATIONSHIP_EXPECTATIONS_WOOHOO_EXCLUSIVITY_NO - CommonTraitUtils.remove_trait(sim_info, to_remove_trait) - return CommonTraitUtils.add_trait(sim_info, to_add_trait) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_routing_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_routing_utils.py deleted file mode 100644 index 142a385..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_routing_utils.py +++ /dev/null @@ -1,123 +0,0 @@ -""" -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 -""" -from interactions.context import InteractionContext -from objects.terrain import Terrain -from server.pick_info import PickType -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.classes.math.common_surface_identifier import CommonSurfaceIdentifier -from s4ap.sims4communitylib.classes.math.common_vector3 import CommonVector3 - -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.utils.common_type_utils import CommonTypeUtils -from s4ap.sims4communitylib.utils.location.common_location_utils import CommonLocationUtils -from s4ap.sims4communitylib.utils.location.common_terrain_utils import CommonTerrainUtils -from s4ap.sims4communitylib.utils.resources.common_interaction_utils import CommonInteractionUtils -from s4ap.sims4communitylib.utils.sims.common_sim_body_utils import CommonSimBodyUtils -from s4ap.sims4communitylib.utils.terrain.common_terrain_location_utils import CommonTerrainLocationUtils - - -class CommonSimRoutingUtils: - """ Utilities for manipulating the Routing of Sims. """ - - @staticmethod - def can_route_to_pick_target_of_interaction_context(sim_info: SimInfo, interaction_context: InteractionContext) -> CommonTestResult: - """can_route_to_pick_target_of_interaction_context(sim_info, interaction_context) - - Determine whether a Sim can route to a the picked target of an interaction context or not. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param interaction_context: An interaction context. - :type interaction_context: InteractionContext - :return: The result of running the test. True, if the Sim can route. False, if they cannot route. - :rtype: CommonTestResult - """ - pick_info = CommonInteractionUtils.get_pick_info_from_interaction_context(interaction_context) - if pick_info is None: - return CommonTestResult(False, reason='Missing PickInfo') - if not isinstance(pick_info.pick_type, PickType): - return CommonTestResult(False, reason=f'PickInfo {pick_info} did not have a pick type of type PickType {pick_info.pick_type}') - - pick_target = pick_info.target - if pick_target is None: - position = CommonVector3.from_vector3(pick_info.location) - routing_surface = CommonSurfaceIdentifier.from_surface_identifier(pick_info.routing_surface) - else: - position = CommonVector3.from_vector3(pick_info.location) - routing_surface = CommonSurfaceIdentifier.from_surface_identifier(pick_info.routing_surface) - - if CommonTypeUtils.is_water(pick_target): - swim_at_position_test_result = CommonSimRoutingUtils.can_swim_at_position(sim_info, position, routing_surface) - if not swim_at_position_test_result: - return swim_at_position_test_result - - if position is None or routing_surface is None: - return CommonTestResult(False, reason=f'Failed to locate positional data for pick info {pick_info}.') - - if not CommonLocationUtils.can_position_be_routed_to(position, routing_surface): - return CommonTestResult(False, reason=f'Pick Target cannot be routed to by Sim {sim_info}.') - return CommonTestResult(True, reason=f'Pick Target can be routed to by Sim {sim_info}.') - - @staticmethod - def can_route_to_terrain(sim_info: SimInfo, terrain_object: Terrain) -> CommonTestResult: - """can_route_to_terrain(sim_info, terrain_object) - - Determine whether a Sim can route to a terrain object or not. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param terrain_object: The terrain object to check. - :type terrain_object: Terrain - :return: The result of running the test. True, if the Sim can route. False, if they cannot route. - :rtype: CommonTestResult - """ - position = CommonTerrainLocationUtils.get_position(terrain_object) - routing_surface = CommonTerrainLocationUtils.get_routing_surface(terrain_object) - if position is None or routing_surface is None: - return CommonTestResult(False, reason=f'No position or routing surface found for terrain. {terrain_object}') - - if CommonTypeUtils.is_water(terrain_object): - swim_at_position_test_result = CommonSimRoutingUtils.can_swim_at_position(sim_info, position, routing_surface) - if not swim_at_position_test_result: - return swim_at_position_test_result - if not CommonLocationUtils.can_position_be_routed_to(position, routing_surface): - return CommonTestResult(False, reason=f'Terrain {terrain_object} cannot be routed to by Sim {sim_info}.') - return CommonTestResult(True, reason=f'Terrain {terrain_object} can be routed to by Sim {sim_info}.') - - @staticmethod - def can_swim_at_position(sim_info: SimInfo, position: CommonVector3, routing_surface: CommonSurfaceIdentifier) -> CommonTestResult: - """can_swim_at_position(sim_info, position, routing_surface) - - Determine whether a Sim can swim to a target position or not. - - .. note:: This function assumes the target position is Ocean, a Pond, or a Swimming Pool. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param position: The position to check. - :type position: CommonVector3 - :param routing_surface: The routing surface to check. - :type routing_surface: CommonSurfaceIdentifier - :return: The result of running the test. True, if the Sim can swim at the position. False, if they cannot. - :rtype: CommonTestResult - """ - if position is None or routing_surface is None: - from routing.walkstyle.wading_tests import WadingIntervalTest - water_height = WadingIntervalTest.WATER_DEPTH_ON_LAND - else: - water_height = CommonTerrainUtils.get_water_depth_at(position.x, position.z, surface_level=routing_surface.secondary_id) - - import build_buy - if bool(build_buy.get_pond_id(position)): - (lower_bound, upper_bound) = CommonSimBodyUtils.get_pond_wading_size(sim_info) - else: - (lower_bound, upper_bound) = CommonSimBodyUtils.get_ocean_wading_size(sim_info) - - if water_height <= upper_bound: - return CommonTestResult(False, reason=f'Water is too shallow ({water_height}) for Sim {sim_info} ({lower_bound}, {upper_bound})') - return CommonTestResult(True, reason=f'Sim can swim at position.') diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_situation_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_situation_utils.py deleted file mode 100644 index e156636..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_situation_utils.py +++ /dev/null @@ -1,607 +0,0 @@ -""" -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 -""" -import services -from typing import Callable, Iterator, Union, List, Tuple, Type - -from distributor.shared_messages import IconInfoData -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.enums.situations_enum import CommonSituationId -from s4ap.sims4communitylib.enums.tags_enum import CommonGameTag -from s4ap.sims4communitylib.logging.has_class_log import HasClassLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.notifications.common_basic_notification import CommonBasicNotification -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ - CommonConsoleCommandArgument -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from s4ap.sims4communitylib.utils.resources.common_situation_utils import CommonSituationUtils -from situations.dynamic_situation_goal_tracker import DynamicSituationGoalTracker -from situations.situation import Situation -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from situations.situation_goal import SituationGoal -from situations.situation_goal_targeted_sim import SituationGoalTargetedSim -from situations.situation_goal_tracker import SituationGoalTracker -from situations.situation_guest_list import SituationInvitationPurpose, SituationGuestList, SituationGuestInfo -from situations.situation_job import SituationJob -from whims.whim_set import WhimSetBaseMixin - - -class CommonSimSituationUtils(HasClassLog): - """Utilities for manipulating the Situations of Sims. - - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - return ModInfo.get_identity() - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 'common_sim_situation_utils' - - @staticmethod - def has_situation(sim_info: SimInfo, situation_guid: Union[int, CommonSituationId]) -> bool: - """has_situation(sim_info, situation_guid) - - Determine if a Sim is involved in the specified Situation. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param situation_guid: The GUID of a Situation. - :type situation_guid: Union[int, CommonSituationId] - :return: True, if the Sim is involved in the specified Situation. False, if not. - :rtype: bool - """ - if sim_info is None: - return False - return situation_guid in CommonSimSituationUtils.get_situation_guids(sim_info) - - # noinspection SpellCheckingInspection - @staticmethod - def has_situations(sim_info: SimInfo, situation_guids: Iterator[Union[int, CommonSituationId]]) -> bool: - """has_situations(sim_info, situation_guids) - - Determine if a Sim is involved in any of the specified Situations. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param situation_guids: The GUID of Situations. - :type situation_guids: Iterator[Union[int, CommonSituationId]] - :return: True, if the Sim has any of the specified situations. False, if not. - :rtype: bool - """ - if sim_info is None: - return False - for situation_guid in CommonSimSituationUtils.get_situation_guids(sim_info): - if situation_guid in situation_guids: - return True - return False - - @staticmethod - def has_situation_job(sim_info: SimInfo, situation_job_id: int) -> bool: - """has_situation_job(sim_info, situation_job_id) - - Determine if a Sim has been assigned a situation job. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param situation_job_id: The situation job to check for. - :type situation_job_id: int - :return: True, if the Sim has the specified situation job. False, if not. - :rtype: bool - """ - return CommonSimSituationUtils.has_situation_jobs(sim_info, (situation_job_id,)) - - @staticmethod - def has_situation_jobs(sim_info: SimInfo, situation_job_ids: Tuple[int]) -> bool: - """has_situation_jobs(sim_info, situation_job_ids) - - Determine if a Sim has been assigned any specified situation jobs. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param situation_job_ids: The situation jobs to check for. - :type situation_job_ids: Tuple[int] - :return: True, if the Sim has any of the specified situation jobs. False, if not. - :rtype: bool - """ - sim_situations = CommonSimSituationUtils.get_situations(sim_info) - for situation in sim_situations: - for situation_job in situation.all_jobs_gen(): - situation_job_id = CommonSituationUtils.get_situation_job_guid(situation_job) - if situation_job_id < 0: - continue - if situation_job_id in situation_job_ids: - return True - return False - - @staticmethod - def has_leave_situation(sim_info: SimInfo) -> bool: - """has_situation_jobs(sim_info, situation_job_ids) - - Determine if a Sim is currently involved in a leaving situation. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: True, if the Sim is currently involved in a leaving situation. False, if not. - :rtype: bool - """ - leave_tags: Tuple[CommonGameTag] = (CommonGameTag.ROLE_LEAVE,) - return CommonSimSituationUtils.has_situations(sim_info, (CommonSituationId.LEAVE, )) or CommonSimSituationUtils.is_in_situations_with_any_tags(sim_info, leave_tags) - - @staticmethod - def is_assigned_situation_job(sim_info: SimInfo, situation_job_id: int) -> bool: - """is_assigned_situation_job(sim_info, situation_job_id) - - Determine if a Sim is currently assigned a situation job. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param situation_job_id: The decimal identifier of a Situation Job. - :type situation_job_id: int - :return: True, if the Sim is assigned the specified situation job. False, if not. - :rtype: bool - """ - return CommonSimSituationUtils.is_assigned_situation_jobs(sim_info, (situation_job_id, )) - - @staticmethod - def is_assigned_situation_jobs(sim_info: SimInfo, situation_job_ids: Tuple[int]) -> bool: - """is_assigned_situation_jobs(sim_info, situation_job_ids) - - Determine if a Sim is currently assigned any of the specified situation jobs. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param situation_job_ids: A collection of decimal identifier for Situation Jobs. - :type situation_job_ids: Tuple[int] - :return: True, if the Sim is assigned any of the specified situation jobs. False, if not. - :rtype: bool - """ - sim_situations = CommonSimSituationUtils.get_situations(sim_info) - for situation in sim_situations: - for situation_job in situation.all_jobs_gen(): - situation_job_id = getattr(situation_job, 'guid64', None) - if situation_job_id in situation_job_ids: - return True - return False - - @staticmethod - def is_in_situations_with_tag(sim_info: SimInfo, tag: CommonGameTag) -> bool: - """is_in_situations_with_tag(sim_info, tag) - - Determine if a Sim is currently in a situation with a tag. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param tag: A tag to check for. - :type tag: CommonGameTag - :return: True, if the Sim is involved in any situations with any of the specified tags. False, if not. - :rtype: bool - """ - return CommonSimSituationUtils.is_in_situations_with_any_tags(sim_info, (tag,)) - - @staticmethod - def is_in_situations_with_any_tags(sim_info: SimInfo, tags: Tuple[CommonGameTag]) -> bool: - """is_in_situations_with_any_tags(sim_info, tags) - - Determine if a Sim is currently in a situation with any of the specified tags. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param tags: A collection of game tags. - :type tags: Tuple[CommonGameTag] - :return: True, if the Sim is involved in any situations with any of the specified tags. False, if not. - :rtype: bool - """ - tags = set(tags) - situations = CommonSimSituationUtils.get_situations(sim_info) - for tag in tags: - for situation in situations: - if tag in getattr(situation, 'tags', tuple()): - return True - for situation_job in situation.all_jobs_gen(): - if tag in getattr(situation_job, 'tags', tuple()): - return True - return False - - @staticmethod - def is_in_situations_of_type(sim_info: SimInfo, situation_type: Type[Situation]) -> bool: - """is_in_situations_of_type(sim_info, situation_type) - - Determine if a Sim is currently in a situation that is of the a specific type. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param situation_type: The type of situation to check. - :type situation_type: Type[Situation] - :return: True, if the Sim is involved in any situations with any of the specified tags. False, if not. - :rtype: bool - """ - return any(CommonSimSituationUtils.get_running_situations_sim_is_in_by_type(sim_info, situation_type)) - - @staticmethod - def make_sim_leave(sim_info: SimInfo): - """make_sim_leave(sim_info) - - Make a Sim leave the current lot. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - """ - if sim_info is None: - return - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return - services.get_zone_situation_manager().make_sim_leave(sim) - - @staticmethod - def remove_sim_from_situation(sim_info: SimInfo, situation_id: int) -> bool: - """remove_sim_from_situation(sim_info, situation_id) - - Remove a Sim from a Situation. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param situation_id: The instance identifier of the Situation to remove the Sim from. - :type situation_id: int - :return: True, if the Sim was successfully removed from the situation. False, if not. - :rtype: bool - """ - situation_manager = services.get_zone_situation_manager() - if sim_info is None or situation_id is None: - return False - situation_manager.remove_sim_from_situation(sim_info, situation_id) - return True - - @staticmethod - def create_visit_situation(sim_info: SimInfo, duration_override_in_sim_seconds: int = None, visit_situation_override: Situation = None): - """create_visit_situation(sim_info, duration_override_in_sim_seconds=None, visit_situation_override=None) - - Create a visit situation for a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param duration_override_in_sim_seconds: An override in Sim seconds for the visit to last. Default is None. - :type duration_override_in_sim_seconds: int, optional - :param visit_situation_override: An instance of a Situation to use for the Visit. If not specified, the default visit situation will be used. Default is None. - :type visit_situation_override: Situation, optional - """ - if sim_info is None: - return - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return - services.get_zone_situation_manager().create_visit_situation(sim, duration_override=duration_override_in_sim_seconds, visit_type_override=visit_situation_override) - - @staticmethod - def create_situation_for_sim( - sim_info: SimInfo, - situation_type: Type[Situation], - creation_source: str, - invite_only: bool = True, - user_facing: bool = False, - situation_job: SituationJob = None, - purpose: SituationInvitationPurpose = SituationInvitationPurpose.INVITED, - **__ - ) -> int: - """create_situation_for_sim(\ - sim_info,\ - situation_type,\ - creation_source,\ - invite_only=True,\ - user_facing=False,\ - situation_job=None,\ - purpose=SituationInvitationPurpose.INVITED,\ - **__\ - ) - - Create a situation and put a Sim in it. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param situation_type: The type of situation to create. - :type situation_type: Type[Situation] - :param invite_only: If True, the situation will be invitation only. Default is True. - :type invite_only: bool, optional - :param user_facing: If True, the situation will be visible to the player (Like an Active Situation would be). If False, it will not be visible. Default is False. - :type user_facing: bool, optional - :param situation_job: The Situation Job to assign to the Sim upon situation creation. Default is whatever the situation specifies as the default job. - :type situation_job: SituationJob, optional - :param creation_source: The source of creation. - :type creation_source: str - :param purpose: The purpose of the situation. Default is SituationInvitationPurpose.INVITED. - :type purpose: SituationInvitationPurpose, optional - :return: The identifier of the situation that was created or 0 if an error occurs. - :rtype: int - """ - if sim_info is None: - raise AssertionError('sim_info was None!') - from s4ap.sims4communitylib.utils.resources.common_situation_utils import CommonSituationUtils - situation_manager = CommonSituationUtils.get_situation_manager_for_zone() - guest_list = SituationGuestList(invite_only=invite_only) - guest_info = SituationGuestInfo.construct_from_purpose(CommonSimUtils.get_sim_id(sim_info), situation_job or situation_type.default_job(), purpose) - guest_list.add_guest_info(guest_info) - situation_id = situation_manager.create_situation(situation_type, guest_list=guest_list, user_facing=user_facing, creation_source=creation_source, **__) - if not situation_id: - return 0 - return situation_id - - @staticmethod - def complete_situation_goal(sim_info: SimInfo, situation_goal_id: int, target_sim_info: SimInfo = None, score_override: int = None, start_cooldown: bool = True): - """complete_situation_goal(sim_info, situation_goal_id, target_sim_info=None, score_override=None, start_cooldown=True) - - Complete a situation goal for a Sim using the specified Target Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param situation_goal_id: The decimal identifier of a Situation Goal to mark as completed. - :type situation_goal_id: int - :param target_sim_info: A target used in the completion of the situation goal. Default is None. - :type target_sim_info: SimInfo, optional - :param score_override: An alternative score to award to the Sim instead of the score specified by the goal. Default is None. - :type score_override: int, optional - :param start_cooldown: Whether or not to start a cooldown for the situation. Default is True. - :type start_cooldown: bool, optional - """ - from s4ap.sims4communitylib.utils.sims.common_whim_utils import CommonWhimUtils - if target_sim_info is not None: - if CommonSimUtils.get_sim_instance(target_sim_info) is None: - return - goal_instances: List[Union[SituationGoal, SituationGoalTargetedSim, WhimSetBaseMixin]] = [] - goal_instances.extend(CommonSimSituationUtils.get_situation_goals(sim_info)) - goal_instances.extend(CommonWhimUtils.get_current_whims(sim_info)) - for goal_instance in goal_instances: - if goal_instance.guid64 != situation_goal_id: - continue - goal_instance.force_complete(target_sim=CommonSimUtils.get_sim_instance(target_sim_info), score_override=score_override, start_cooldown=start_cooldown) - - # noinspection SpellCheckingInspection - @staticmethod - def get_guids_of_all_running_situations_for_sim(sim_info: SimInfo) -> Tuple[int]: - """get_guids_of_all_running_situations_for_sim(sim_info) - - Retrieve GUIDs for all Situations a Sim is involved in. - - :param sim_info: The sim to check. - :type sim_info: SimInfo - :return: A collection of Situation GUIDs the specified Sim is involved in. - :rtype: Tuple[int] - """ - situation_guids = [] - for situation in CommonSimSituationUtils.get_situations(sim_info): - situation_guid = CommonSituationUtils.get_situation_guid(situation) - if situation_guid is None and situation_guid != -1: - continue - situation_guids.append(situation_guid) - return tuple(situation_guids) - - @staticmethod - def get_situations(sim_info: SimInfo, include_situation_callback: Callable[[Situation], bool] = None) -> Iterator[Situation]: - """get_situations(sim_info, include_situation_callback=None) - - Retrieve all Situations that a Sim is currently involved in. - - :param sim_info: An instance of a Sim - :type sim_info: SimInfo - :param include_situation_callback: If the result of this callback is True, the Situation will be included in the results. If set to None, All situations will be included. Default is None. - :type include_situation_callback: Callable[[Situation], bool], optional - :return: An iterator of Situations that pass the include callback filter. - :rtype: Iterator[Situation] - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return - situations = tuple(services.get_zone_situation_manager().get_situations_sim_is_in(sim)) - if sim is None or not situations: - return tuple() - for situation in situations: - if include_situation_callback is not None and not include_situation_callback(situation): - continue - yield situation - - @staticmethod - def get_first_running_situation_sim_is_in_by_type(sim_info: SimInfo, situation_type: Type[Situation]) -> Union[Situation, None]: - """get_first_running_situation_sim_is_in_by_type(sim_info, situation_type) - - Retrieve the first Situation that a Sim is currently involved in that is a specific type. - - :param sim_info: An instance of a Sim - :type sim_info: SimInfo - :param situation_type: A situation type to locate a situation with. - :type situation_type: Type[Situation] - :return: A situation the Sim is involved in that is of the specified type or None if not found. - :rtype: Union[Situation, None] - """ - for situation in CommonSimSituationUtils.get_running_situations_sim_is_in_by_type(sim_info, situation_type): - return situation - return None - - @staticmethod - def get_first_running_situation_sim_is_in_by_tag(sim_info: SimInfo, tag: CommonGameTag) -> Union[Situation, None]: - """get_first_running_situation_sim_is_in_by_tag(sim_info, tag) - - Retrieve the first Situation that a Sim is currently involved in that has a tag. - - :param sim_info: An instance of a Sim - :type sim_info: SimInfo - :param tag: The tag to locate a situation with. - :type tag: CommonGameTag - :return: A situation the Sim is involved in that has the specified tag or None if not found. - :rtype: Union[Situation, None] - """ - for situation in CommonSimSituationUtils.get_running_situations_sim_is_in_by_tag(sim_info, tag): - return situation - return None - - @staticmethod - def get_running_situations_sim_is_in_by_tag(sim_info: SimInfo, tag: CommonGameTag) -> Tuple[Situation]: - """get_running_situations_sim_is_in_by_tag(sim_info, tag) - - Retrieve all Situations that a Sim is currently involved in that have the specified tag. - - :param sim_info: An instance of a Sim - :type sim_info: SimInfo - :param tag: The tag to locate situations with. - :type tag: CommonGameTag - :return: An iterator of Situations the Sim is running that have the specified tag. - :rtype: Iterator[Situation] - """ - def _situation_has_tag(_situation: Situation) -> bool: - if hasattr(_situation, 'tags'): - return tag in _situation.tags - return False - - return tuple(CommonSimSituationUtils.get_situations(sim_info, include_situation_callback=_situation_has_tag)) - - @staticmethod - def get_running_situations_sim_is_in_by_tags(sim_info: SimInfo, tags: Tuple[CommonGameTag]) -> Tuple[Situation]: - """get_running_situations_sim_is_in_by_tag(sim_info, tags) - - Retrieve all Situations that a Sim is currently involved in that have the specified tag. - - :param sim_info: An instance of a Sim - :type sim_info: SimInfo - :param tags: A collection of tags to locate situations with. Matching situations will have at least one of these tags. - :type tags: Iterator[CommonGameTag] - :return: An iterator of Situations the Sim is running that have any of the specified tags. - :rtype: Iterator[Situation] - """ - matching_situations: List[Situation] = list() - for tag in tags: - for situation in CommonSimSituationUtils.get_running_situations_sim_is_in_by_tag(sim_info, tag): - if situation not in matching_situations: - matching_situations.append(situation) - return tuple(matching_situations) - - @staticmethod - def get_running_situations_sim_is_in_by_type(sim_info: SimInfo, situation_type: Type[Situation]) -> Tuple[Situation]: - """get_running_situations_sim_is_in_by_type(sim_info, situation_type) - - Retrieve all Situations that a Sim is currently involved in that match the specified type. - - :param sim_info: An instance of a Sim - :type sim_info: SimInfo - :param situation_type: A situation type to locate situations with. - :type situation_type: Type[Situation] - :return: An iterator of Situations the Sim is running that are of the specified type. - :rtype: Iterator[Situation] - """ - def _situation_is_of_type(_situation: Situation) -> bool: - return isinstance(_situation, situation_type) - - return tuple(CommonSimSituationUtils.get_situations(sim_info, include_situation_callback=_situation_is_of_type)) - - @staticmethod - def get_situation_ids(sim_info: SimInfo) -> List[int]: - """get_situation_ids(sim_info) - - Retrieve decimal identifiers for all Situations a Sim is involved in. - - :param sim_info: The sim to check. - :type sim_info: SimInfo - :return: A collection of Situation decimal identifiers the specified Sim is involved in. - :rtype: List[int] - """ - situation_ids = [] - for situation in CommonSimSituationUtils.get_situations(sim_info): - situation_id = CommonSituationUtils.get_situation_id(situation) - if situation_id is None and situation_id != -1: - continue - situation_ids.append(situation_id) - return situation_ids - - # noinspection SpellCheckingInspection - @staticmethod - def get_situation_guids(sim_info: SimInfo) -> List[int]: - """get_situation_guids(sim_info) - - Retrieve GUIDs for all Situations a Sim is involved in. - - :param sim_info: The sim to check. - :type sim_info: SimInfo - :return: A collection of Situation GUIDs the specified Sim is involved in. - :rtype: List[int] - """ - situation_guids = [] - for situation in CommonSimSituationUtils.get_situations(sim_info): - situation_guid = CommonSituationUtils.get_situation_guid(situation) - if situation_guid is None and situation_guid != -1: - continue - situation_guids.append(situation_guid) - return situation_guids - - @staticmethod - def get_situation_goals(sim_info: SimInfo) -> Tuple[Union[SituationGoal, SituationGoalTargetedSim]]: - """get_situation_goals(sim_info) - - Retrieve the goals of all situations a Sim is currently in. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The situation goals of all Situations the Sim is currently involved in. - :rtype: Tuple[Union[SituationGoal, SituationGoalTargetedSim]] - """ - goal_instances: List[Union[SituationGoal, SituationGoalTargetedSim]] = [] - for situation in CommonSimSituationUtils.get_situations(sim_info): - goal_tracker = situation._get_goal_tracker() - if goal_tracker is None: - continue - if isinstance(goal_tracker, SituationGoalTracker): - if goal_tracker._realized_minor_goals is not None: - goal_instances.extend(goal_tracker._realized_minor_goals.keys()) - if goal_tracker._realized_main_goal is not None: - goal_instances.insert(0, goal_tracker._realized_main_goal) - elif isinstance(goal_tracker, DynamicSituationGoalTracker): - goal_instances.extend(goal_tracker.goals) - return tuple(goal_instances) - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_testing.print_situations', - 'Print a list of all situations a Sim is in.', - command_arguments=( - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to check.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib_testing.printsituations', - ) -) -def _common_show_running_situations(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): - if sim_info is None: - return - log = CommonSimSituationUtils.get_log() - try: - log.enable() - output(f'Attempting to print all running situations of Sim {sim_info}') - situation_strings: List[str] = list() - for situation in CommonSimSituationUtils.get_situations(sim_info): - situation_name = CommonSituationUtils.get_situation_name(situation) - situation_id = CommonSituationUtils.get_situation_id(situation) - situation_strings.append(f'{situation_name} ({situation_id})') - - situation_strings = sorted(situation_strings, key=lambda x: x) - sim_situations = ', '.join(situation_strings) - text = '' - text += f'Situations:\n{sim_situations}\n\n' - sim_id = CommonSimUtils.get_sim_id(sim_info) - log.debug(f'{sim_info} Situations ({sim_id})') - log.debug(text) - CommonBasicNotification( - CommonLocalizationUtils.create_localized_string(f'{sim_info} Situations ({sim_id})'), - CommonLocalizationUtils.create_localized_string(text) - ).show( - icon=IconInfoData(obj_instance=CommonSimUtils.get_sim_instance(sim_info)) - ) - finally: - log.disable() diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_skill_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_skill_utils.py deleted file mode 100644 index d43dccf..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_skill_utils.py +++ /dev/null @@ -1,409 +0,0 @@ -""" -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 -""" -from typing import Union, Iterator - -from server_commands.argument_helpers import TunableInstanceParam -from sims.sim_info import SimInfo -from sims4.resources import Types -from s4ap.sims4communitylib.enums.skills_enum import CommonSkillId -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ - CommonConsoleCommandArgument -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.resources.common_skill_utils import CommonSkillUtils -from statistics.skill import Skill - - -class CommonSimSkillUtils: - """Utilities for manipulating the Skills of Sims. - - """ - @staticmethod - def has_skill(sim_info: SimInfo, skill: Union[int, CommonSkillId, Skill]) -> bool: - """has_skill(sim_info, skill) - - Determine if a Sim has a Skill. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :param skill: The identifier of the Skill to check. - :type skill: Union[int, CommonSkillId, Skill] - :return: True, if the Sim has the skill. False, if the Sim does not. - :rtype: bool - """ - return CommonSimSkillUtils.get_skill(sim_info, skill, add=False) is not None - - # noinspection PyUnusedLocal - @staticmethod - def set_current_skill_level(sim_info: SimInfo, skill: Union[int, CommonSkillId, Skill], level: float, add: bool = True) -> bool: - """set_current_skill_level(sim_info, skill, level, add=True) - - Set the current skill level of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param skill: The decimal identifier of a Skill. - :type skill: Union[int, CommonSkillId, Skill] - :param level: The level to set the skill to. - :type skill: Union[int, CommonSkillId, Skill] - :param add: OBSOLETE AND IGNORED ARGUMENT! When setting the skill level for a Sim, the Skill will always be added first. - :type add: bool, optional - :return: True, if successful. False, if not successful, the skill does not exist, or the skill is not valid for the Sim. - :rtype: bool - """ - sim_skill: Skill = CommonSimSkillUtils.get_skill(sim_info, skill, add=add) - if sim_skill is None: - return False - new_skill_experience = sim_skill.convert_from_user_value(level) - sim_skill.set_value(new_skill_experience) - return True - - @staticmethod - def set_current_skill_level_to_max(sim_info: SimInfo, skill: Union[int, CommonSkillId, Skill]) -> bool: - """set_current_skill_level_to_max(sim_info, skill, add=True) - - Set the current skill level of a Sim to its maximum value. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param skill: The decimal identifier of a Skill. - :type skill: Union[int, CommonSkillId, Skill] - :return: True, if successful. False, if not successful, the skill does not exist, or the skill is not valid for the Sim. - :rtype: bool - """ - skill: Skill = CommonSkillUtils.load_skill_by_id(skill) - if skill is None: - return False - return CommonSimSkillUtils.set_current_skill_level(sim_info, skill, skill.max_level) - - @staticmethod - def get_current_skill_level(sim_info: SimInfo, skill: Union[int, CommonSkillId, Skill], use_effective_skill_level: bool = True) -> float: - """get_current_skill_level(\ - sim_info,\ - skill,\ - use_effective_skill_level=True\ - ) - - Retrieve the current skill level of a Sim for a Skill. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param skill: The decimal identifier of a Skill. - :type skill: Union[int, CommonSkillId, Skill] - :param use_effective_skill_level: If True, any skill modifiers will be taken into account, such as buffs, traits, etc. If False, the skill level without modifiers will be returned. True only works if the Sim is instanced. Default is True. - :type use_effective_skill_level: bool, optional - :return: The current level the Sim is at for the specified Skill or 0.0 if the Skill is either not available or the Sim does not have it. - :rtype: float - """ - skill: Skill = CommonSkillUtils.load_skill_by_id(skill) - if skill is None: - return 0.0 - skill_or_skill_type = sim_info.get_statistic(skill, add=False) or skill - if use_effective_skill_level and sim_info.is_instanced(): - skill_level: float = sim_info.get_effective_skill_level(skill_or_skill_type) - else: - skill_level: float = skill_or_skill_type.get_user_value() - return skill_level - - @staticmethod - def is_at_max_skill_level(sim_info: SimInfo, skill: Union[int, CommonSkillId, Skill], use_effective_skill_level: bool = True) -> bool: - """is_at_max_skill_level(\ - sim_info,\ - skill,\ - use_effective_skill_level=True\ - ) - - Determine if a Sim has reached the Maximum Level of a Skill. - - .. note:: Max level depends on the skill itself. Each skill can have a different max level. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :param skill: The identifier of the Skill to check. - :type skill: Union[int, CommonSkillId, Skill] - :param use_effective_skill_level: If True, any skill modifiers will be taken into account, such as buffs, traits, etc. If False, the skill level without modifiers will be returned. True only works if the Sim is instanced. Default is True. - :type use_effective_skill_level: bool, optional - :return: True, if the Sim has the skill at the maximum level. False, if the Sim does not. - :rtype: bool - """ - skill: Skill = CommonSkillUtils.load_skill_by_id(skill) - if skill is None: - return False - sim_skill_level = CommonSimSkillUtils.get_current_skill_level( - sim_info, - skill, - use_effective_skill_level=use_effective_skill_level - ) - return sim_skill_level >= skill.max_level - - @staticmethod - def remove_skill(sim_info: SimInfo, skill: Union[int, CommonSkillId, Skill]) -> bool: - """remove_skill(sim_info, skill) - - Remove a Skill from the specified Sim. - - :param sim_info: The Sim to modify. - :type sim_info: SimInfo - :param skill: The identifier of the Skill to remove. - :type skill: Union[int, CommonSkillId, Skill] - :return: True, if the skill was removed successfully. False, if not. - :rtype: bool - """ - skill: Skill = CommonSkillUtils.load_skill_by_id(skill) - if skill is None: - return False - sim_info.remove_statistic(skill) - return True - - @staticmethod - def set_progress_toward_max_skill_level(sim_info: SimInfo, skill: Union[int, CommonSkillId, Skill], value: float, add: bool = True) -> bool: - """set_progress_toward_max_skill_level(sim_info, skill, value, add=True) - - Set the amount of progress a Sim has made toward the max level of a Skill. - - :param sim_info: The Sim to modify. - :type sim_info: SimInfo - :param skill: The identifier of the Skill to set. - :type skill: Union[int, CommonSkillId, Skill] - :param value: The amount to add. - :type value: Union[int, CommonSkillId, Skill] - :param add: If True, the skill will be added to the Sim before it is modified. - :type add: bool, optional - :return: True, if successful. False, if not. - :rtype: bool - """ - sim_skill: Skill = CommonSimSkillUtils.get_skill(sim_info, skill, add=add) - if sim_skill is None: - return False - sim_skill.set_value(value) - return True - - @staticmethod - def get_progress_toward_max_skill_level(sim_info: SimInfo, skill: Union[int, CommonSkillId, Skill], add: bool = True) -> float: - """get_progress_toward_max_skill_level(sim_info, skill, add=True) - - Retrieve the amount of progress a Sim has made toward the max level of a Skill. - - :param sim_info: The Sim to modify. - :type sim_info: SimInfo - :param skill: The identifier of the Skill to modify. - :type skill: Union[int, CommonSkillId, Skill] - :param add: If True, the skill will be added to the Sim before it is modified. - :type add: bool, optional - :return: True, if successful. False, if not. - :rtype: bool - """ - sim_skill: Skill = CommonSimSkillUtils.get_skill(sim_info, skill, add=add) - if sim_skill is None: - return False - sim_skill.get_value() - return True - - @staticmethod - def change_progress_toward_max_skill_level(sim_info: SimInfo, skill: Union[int, CommonSkillId, Skill], value: float, add: bool = True) -> bool: - """change_progress_toward_max_skill_level(sim_info, skill, value, add=True) - - Modify the amount of progress a Sim has made toward the max level of a Skill. - - :param sim_info: The Sim to modify. - :type sim_info: SimInfo - :param skill: The identifier of the Skill to modify. - :type skill: Union[int, CommonSkillId, Skill] - :param value: The level to add or subtract to/from the skill. - :type value: Union[int, CommonSkillId, Skill] - :param add: If True, the skill will be added to the Sim before it is modified. - :type add: bool, optional - :return: True, if successful. False, if not. - :rtype: bool - """ - sim_skill: Skill = CommonSimSkillUtils.get_skill(sim_info, skill, add=add) - if sim_skill is None: - return False - sim_skill.add_value(value) - return True - - @staticmethod - def change_progress_toward_next_skill_level(sim_info: SimInfo, skill: Union[int, CommonSkillId, Skill], value: float, add: bool = True) -> bool: - """change_progress_toward_next_skill_level(sim_info, skill, value, add=True) - - Modify the amount of progress a Sim has made toward the next level of a Skill. - - :param sim_info: The Sim to modify. - :type sim_info: SimInfo - :param skill: The identifier of the Skill to modify. - :type skill: Union[int, CommonSkillId, Skill] - :param value: The level to add or subtract to/from the skill. - :type value: Union[int, CommonSkillId, Skill] - :param add: If True, the skill will be added to the Sim before it is modified. - :type add: bool, optional - :return: True, if successful. False, if not. - :rtype: bool - """ - return CommonSimSkillUtils.change_progress_toward_max_skill_level(sim_info, skill, value, add=add) - - @staticmethod - def get_progress_toward_next_skill_level(sim_info: SimInfo, skill: Union[int, CommonSkillId, Skill], add: bool = False) -> float: - """get_progress_toward_next_skill_level(sim_info, skill, add=False) - - Retrieve the amount of progress a Sim has made toward the next level of a Skill. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :param skill: The identifier of the Skill to use. - :type skill: Union[int, CommonSkillId, Skill] - :param add: If True, the skill will be added to the Sim before it is checked. - :type add: bool, optional - :return: The progress to the next level of the specified Skill or `-1.0` if a problem occurs. - :rtype: float - """ - skill = CommonSimSkillUtils.get_skill(sim_info, skill, add=add) - if skill is None: - return -1.0 - current_skill_level = skill.get_user_value() - current_skill_experience = skill.get_value() - experience_for_level = skill.get_skill_value_for_level(current_skill_level) - experience_for_next_level = skill.get_skill_value_for_level(current_skill_level + 1) - experience_for_level - if experience_for_level > 0.0 and experience_for_next_level > 0.0: - return (current_skill_experience - experience_for_level) / experience_for_next_level - return 0.0 - - @staticmethod - def translate_skill_progress(sim_info: SimInfo, skill_from: Union[int, CommonSkillId, Skill], skill_to: Union[int, CommonSkillId, Skill], add: bool = True) -> bool: - """translate_skill_progress(sim_info, skill_from, skill_to, add=True) - - Translate the total progress of one Skill to the total progress of another Skill for the specified Sim. - - :param sim_info: The Sim to modify. - :type sim_info: SimInfo - :param skill_from: The identifier of the Skill being changed. - :type skill_from: Union[int, CommonSkillId, Skill] - :param skill_to: The identifier of the Skill being translated to. - :type skill_to: Union[int, CommonSkillId, Skill] - :param add: If True, the skill will be added to the Sim before it is modified. - :type add: bool, optional - :return: True, if successful. False, if not. - :rtype: bool - """ - skill_level_value_from = CommonSimSkillUtils.get_progress_toward_next_skill_level(sim_info, skill_from) - skill_to = CommonSimSkillUtils.get_skill(sim_info, skill_to, add=add) - if skill_to is None: - return False - level = skill_to.get_user_value() - value_for_level = skill_to.get_skill_value_for_level(level) - value_for_next_level = skill_to.get_skill_value_for_level(level + 1) - value_for_level - level_of_new_skill = value_for_level + value_for_next_level * skill_level_value_from - return CommonSimSkillUtils.set_progress_toward_max_skill_level(sim_info, skill_to, level_of_new_skill) - - @staticmethod - def get_skill(sim_info: SimInfo, skill: Union[int, CommonSkillId, Skill], add: bool = True) -> Union[Skill, None]: - """get_skill(sim_info, skill, add=True) - - Retrieve a Skill for the specified Sim. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :param skill: The identifier of the Skill to use. - :type skill: Union[int, CommonSkillId, Skill] - :param add: If True, the skill will be added to the Sim before it is checked. - :type add: bool, optional - :return: An instance of a Skill of the Sim or None if the Skill does not exist. - :rtype: Union[Skill, None] - """ - skill: Skill = CommonSkillUtils.load_skill_by_id(skill) - if skill is None: - return None - return sim_info.get_statistic(skill, add=add) - - @staticmethod - def get_all_skills_available_for_sim_gen(sim_info: SimInfo) -> Iterator[Skill]: - """get_all_skills_available_for_sim_gen(sim_info) - - Retrieve all Skills available to a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: An iterator of Skills that are available for the specified Sim. - :rtype: Iterator[Skill] - """ - from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return tuple() - - def _is_skill_available_for_sim(skill: Skill) -> bool: - return skill.can_add(sim) - - yield from CommonSkillUtils.get_all_skills_gen(include_skill_callback=_is_skill_available_for_sim) - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.print_skill_level', - 'Print information about the skill level of a Sim for a Skill.', - command_arguments=( - CommonConsoleCommandArgument('skill', 'Skill Id or Tuning Name', 'The tuning name or decimal identifier of a skill.'), - CommonConsoleCommandArgument('use_effective_skill_level', 'True or False', 'If True, the skill level of the Sim will take into account any modifiers that are applied to them. If False, the skill level will be determined without modifiers.', is_optional=True, default_value=True), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to check.', is_optional=True, default_value='Active Sim'), - ) -) -def _common_get_skill_level(output: CommonConsoleCommandOutput, skill: TunableInstanceParam(Types.STATISTIC), use_effective_skill_level: bool = True, sim_info: SimInfo = None): - if skill is None: - output('ERROR: Failed, Skill not specified or Skill did not exist!') - return - if sim_info is None: - return - output(f'Attempting to print skill level for skill {skill} with use_effective_skill_level {use_effective_skill_level} for Sim {sim_info}') - skill_value = CommonSimSkillUtils.get_current_skill_level(sim_info, skill, use_effective_skill_level=use_effective_skill_level) - output(f'Skill Level: {skill_value}') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.set_skill_level', - 'Set the current skill level of a Skill for a Sim.', - command_arguments=( - CommonConsoleCommandArgument('skill', 'Skill Id or Tuning Name', 'The tuning name or decimal identifier of a skill.'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to change.', is_optional=True, default_value='Active Sim'), - ) -) -def _common_set_skill_level(output: CommonConsoleCommandOutput, skill: TunableInstanceParam(Types.STATISTIC), level: int, sim_info: SimInfo = None): - if sim_info is None: - return - if skill is None: - output('ERROR: Skill not specified or the specified Skill did not exist!') - return - if level < 0: - output('ERROR: level must be a positive number or zero.') - return - output(f'Attempting to set the skill level for skill {skill} to level {level} for Sim {sim_info}') - if CommonSimSkillUtils.set_current_skill_level(sim_info, skill, level): - output(f'SUCCESS: Successfully set the skill level of skill {skill} for Sim {sim_info}.') - else: - output(f'FAILED: Failed to set the skill level of skill {skill} for Sim {sim_info}.') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.remove_skill', - 'Remove a skill from a Sim (effectively set it to zero)', - command_arguments=( - CommonConsoleCommandArgument('skill', 'Skill Id or Tuning Name', 'The tuning name or decimal identifier of a skill.'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to change.', is_optional=True, default_value='Active Sim'), - ) -) -def _common_remove_skill(output: CommonConsoleCommandOutput, skill: TunableInstanceParam(Types.STATISTIC), sim_info: SimInfo = None): - if skill is None: - output('ERROR: Skill not specified or the specified Skill did not exist!') - return - if sim_info is None: - return - output(f'Removing skill {skill} from Sim {sim_info}') - if CommonSimSkillUtils.remove_skill(sim_info, skill): - output(f'SUCCESS: Successfully removed skill {skill} from Sim {sim_info}.') - else: - output(f'FAILED: Failed to remove skill {skill} from Sim {sim_info}.') diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_spawn_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_spawn_utils.py deleted file mode 100644 index ec556d8..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_spawn_utils.py +++ /dev/null @@ -1,3082 +0,0 @@ -""" -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 -""" -import os -import random -import time - -from typing import Union, Tuple, Callable, Any, Iterator, Dict, List - -import indexed_manager -from bucks.bucks_tracker import PerkData -from protocolbuffers import Outfits_pb2, S4Common_pb2 -from protocolbuffers.S4Common_pb2 import SimPronoun -from sims.ghost import Ghost -from sims.occult.occult_enums import OccultType -from sims.outfits.outfit_enums import OutfitCategory, BodyType, SpecialOutfitIndex -from sims.outfits.outfit_tuning import OutfitTuning -from sims.sim_info_lod import SimInfoLODLevel -from sims.sim_info_types import SpeciesExtended, SimSerializationOption -from sims4.resources import Types -from s4ap.sims4communitylib.classes.math.common_surface_identifier import CommonSurfaceIdentifier -from s4ap.sims4communitylib.enums.common_age import CommonAge -from s4ap.sims4communitylib.enums.common_bucks_types import CommonBucksType -from s4ap.sims4communitylib.enums.common_death_types import CommonDeathType -from s4ap.sims4communitylib.enums.common_gender import CommonGender -from s4ap.sims4communitylib.enums.common_species import CommonSpecies -from s4ap.sims4communitylib.enums.strings_enum import CommonStringId -from s4ap.sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ - CommonConsoleCommandArgument -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.cas.common_cas_utils import CommonCASUtils -from s4ap.sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils -from s4ap.sims4communitylib.utils.common_date_utils import CommonRealDateUtils -from s4ap.sims4communitylib.utils.common_log_registry import CommonLogRegistry -from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils -from s4ap.sims4communitylib.utils.common_time_utils import CommonTimeUtils -from s4ap.sims4communitylib.utils.math.common_bitwise_utils import CommonBitwiseUtils -from s4ap.sims4communitylib.utils.resources.common_game_pack_utils import CommonGamePackUtils -from s4ap.sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils -from s4ap.sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils -from s4ap.sims4communitylib.utils.sims.common_sim_death_utils import CommonSimDeathUtils -from s4ap.sims4communitylib.utils.sims.common_sim_location_utils import CommonSimLocationUtils -from s4ap.sims4communitylib.classes.math.common_location import CommonLocation -from s4ap.sims4communitylib.classes.math.common_vector3 import CommonVector3 -from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from s4ap.sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils -from statistics.commodity import Commodity -from statistics.life_skill_statistic import LifeSkillStatistic -from statistics.ranked_statistic import RankedStatistic -from statistics.skill import Skill -from statistics.trait_statistic import TraitStatisticStates, TraitStatistic - -ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' - -if not ON_RTD: - import build_buy - try: - import _buildbuy - except ImportError: - # noinspection SpellCheckingInspection - _buildbuy = build_buy - import services - from interactions.interaction_finisher import FinishingType - from sims.household import Household - from sims.sim_info import SimInfo - from sims.sim_spawner import SimCreator, SimSpawner - from animation.posture_manifest import Hand - from interactions.si_state import SIState - from objects.object_enums import ResetReason - from postures import posture_graph - from postures.posture_specs import PostureSpecVariable - from postures.posture_state import PostureState -else: - # noinspection PyMissingOrEmptyDocstring - class FinishingType: - pass - - # noinspection PyMissingOrEmptyDocstring - class Household: - pass - - # noinspection PyMissingOrEmptyDocstring - class SimInfo: - pass - - # noinspection PyMissingOrEmptyDocstring - class SimCreator: - pass - - # noinspection PyMissingOrEmptyDocstring - class SimSpawner: - pass - - # noinspection PyMissingOrEmptyDocstring - class Command: - pass - - # noinspection PyMissingOrEmptyDocstring - class CommandType: - pass - - # noinspection PyMissingOrEmptyDocstring - class CheatOutput: - pass - - # noinspection PyMissingOrEmptyDocstring - class Hand: - pass - - # noinspection PyMissingOrEmptyDocstring - class SIState: - pass - - # noinspection PyMissingOrEmptyDocstring - class ResetReason: - RESET_EXPECTED = 0 - - # noinspection PyMissingOrEmptyDocstring,PyMissingTypeHints - def posture_graph(*_, **__): - pass - - # noinspection PyMissingOrEmptyDocstring,PyMissingTypeHints - def get_origin_spec(*_, **__): - pass - - # noinspection PyMissingOrEmptyDocstring - class PostureSpecVariable: - pass - - # noinspection PyMissingOrEmptyDocstring - class PostureState: - pass - -log = CommonLogRegistry().register_log(ModInfo.get_identity(), 's4cl_spawn_utils') - - -class CommonSimSpawnUtils: - """Utilities for creating, spawning, despawning, and resetting Sims. - - """ - - @classmethod - def create_sim_info( - cls, - species: CommonSpecies, - gender: CommonGender = None, - age: CommonAge = None, - first_name: str = None, - last_name: str = None, - trait_ids: Tuple[int] = (), - household: Household = None, - source: str = 'testing' - ) -> Union[SimInfo, None]: - """create_sim_info(\ - species,\ - gender=None,\ - age=None,\ - first_name=None,\ - last_name=None,\ - trait_ids=(),\ - household=None,\ - source='testing'\ - ) - - Create SimInfo for a Sim. - - :param species: The species to create a SimInfo for. - :type species: CommonSpecies - :param gender: The gender of the created Sim. Default is None. - :type gender: CommonGender, optional - :param age: The age of the created Sim. Default is None. - :type age: CommonAge, optional - :param first_name: The First Name of the created Sim. Default is random name. - :type first_name: str, optional - :param last_name: The Last Name of the created Sim. Default is random name. - :type last_name: str, optional - :param trait_ids: The decimal identifiers of the Traits to add to the created Sim. Default is an empty collection. - :type trait_ids: Tuple[int], optional - :param household: The household to place the created Sim in. If None, the Sim will be placed in a hidden household. Default is None. - :type household: Household, optional - :param source: The reason for the Sims creation. Default is 'testing'. - :type source: str, optional - :return: The SimInfo of the created Sim or None if the Sim failed to be created. - :rtype: SimInfo - """ - return cls._create_sim_info( - species, - gender=gender, - age=age, - first_name=first_name, - last_name=last_name, - trait_ids=trait_ids, - household=household, - source=source - ) - - @classmethod - def create_human_sim_info( - cls, - gender: CommonGender = None, - age: CommonAge = None, - first_name: str = None, - last_name: str = None, - trait_ids: Tuple[int] = (), - household: Household = None, - source: str = 'testing' - ) -> Union[SimInfo, None]: - """create_human_sim_info(\ - gender=None,\ - age=None,\ - first_name=None,\ - last_name=None,\ - trait_ids=(),\ - household=None,\ - source='testing'\ - ) - - Create SimInfo for a Human Sim. - - :param gender: The gender of the created Sim. Default is None. - :type gender: CommonGender, optional - :param age: The age of the created Sim. Default is None. - :type age: CommonAge, optional - :param first_name: The First Name of the created Sim. Default is random name. - :type first_name: str, optional - :param last_name: The Last Name of the created Sim. Default is random name. - :type last_name: str, optional - :param trait_ids: The decimal identifiers of the Traits to add to the created Sim. Default is an empty collection. - :type trait_ids: Tuple[int], optional - :param household: The household to place the created Sim in. If None, the Sim will be placed in a hidden household. Default is None. - :type household: Household, optional - :param source: The reason for the Sims creation. Default is 'testing'. - :type source: str, optional - :return: The SimInfo of the created Sim or None if the Sim failed to be created. - :rtype: SimInfo - """ - return cls._create_sim_info( - CommonSpecies.HUMAN, - gender=gender, - age=age, - first_name=first_name, - last_name=last_name, - trait_ids=trait_ids, - household=household, - source=source - ) - - @classmethod - def create_large_dog_sim_info( - cls, - gender: CommonGender = None, - age: CommonAge = None, - first_name: str = None, - last_name: str = None, - trait_ids: Tuple[int] = (), - household: Household = None, - source: str = 'testing' - ) -> Union[SimInfo, None]: - """create_large_dog_sim_info(\ - gender=None,\ - age=None,\ - first_name=None,\ - last_name=None,\ - trait_ids=(),\ - household=None,\ - source='testing'\ - ) - - Create SimInfo for a Large Dog Sim. - - :param gender: The gender of the created Sim. Default is None. - :type gender: CommonGender, optional - :param age: The age of the created Sim. Default is None. - :type age: CommonAge, optional - :param first_name: The First Name of the created Sim. Default is random name. - :type first_name: str, optional - :param last_name: The Last Name of the created Sim. Default is random name. - :type last_name: str, optional - :param trait_ids: The decimal identifiers of the Traits to add to the created Sim. Default is an empty collection. - :type trait_ids: Tuple[int], optional - :param household: The household to place the created Sim in. If None, the Sim will be placed in a hidden household. Default is None. - :type household: Household, optional - :param source: The reason for the Sims creation. Default is 'testing'. - :type source: str, optional - :return: The SimInfo of the created Sim or None if the Sim failed to be created. - :rtype: SimInfo - """ - return cls._create_sim_info( - CommonSpecies.LARGE_DOG, - gender=gender, - age=age, - first_name=first_name, - last_name=last_name, - trait_ids=trait_ids, - household=household, - source=source - ) - - @classmethod - def create_small_dog_sim_info( - cls, - gender: CommonGender = None, - age: CommonAge = None, - first_name: str = None, - last_name: str = None, - trait_ids: Tuple[int] = (), - household: Household = None, - source: str = 'testing' - ) -> Union[SimInfo, None]: - """create_small_dog_sim_info(\ - gender=None,\ - age=None,\ - first_name='',\ - last_name='',\ - trait_ids=(),\ - household=None,\ - source='testing'\ - ) - - Create SimInfo for a Small Dog Sim. - - :param gender: The gender of the created Sim. Default is None. - :type gender: CommonGender, optional - :param age: The age of the created Sim. Default is None. - :type age: CommonAge, optional - :param first_name: The First Name of the created Sim. Default is random name. - :type first_name: str, optional - :param last_name: The Last Name of the created Sim. Default is random name. - :type last_name: str, optional - :param trait_ids: The decimal identifiers of the Traits to add to the created Sim. Default is an empty collection. - :type trait_ids: Tuple[int], optional - :param household: The household to place the created Sim in. If None, the Sim will be placed in a hidden household. Default is None. - :type household: Household, optional - :param source: The reason for the Sims creation. Default is 'testing'. - :type source: str, optional - :return: The SimInfo of the created Sim or None if the Sim failed to be created. - :rtype: SimInfo - """ - return cls._create_sim_info( - CommonSpecies.SMALL_DOG, - gender=gender, - age=age, - first_name=first_name, - last_name=last_name, - trait_ids=trait_ids, - household=household, - source=source - ) - - @classmethod - def create_cat_sim_info( - cls, - gender: CommonGender = None, - age: CommonAge = None, - first_name: str = None, - last_name: str = None, - trait_ids: Tuple[int] = (), - household: Household = None, - source: str = 'testing' - ) -> Union[SimInfo, None]: - """create_cat_sim_info(\ - gender=None,\ - age=None,\ - first_name='',\ - last_name='',\ - trait_ids=(),\ - household=None,\ - source='testing'\ - ) - - Create SimInfo for a Cat Sim. - - :param gender: The gender of the created Sim. Default is None. - :type gender: CommonGender, optional - :param age: The age of the created Sim. Default is None. - :type age: CommonAge, optional - :param first_name: The First Name of the created Sim. Default is random name. - :type first_name: str, optional - :param last_name: The Last Name of the created Sim. Default is random name. - :type last_name: str, optional - :param trait_ids: The decimal identifiers of the Traits to add to the created Sim. Default is an empty collection. - :type trait_ids: Tuple[int], optional - :param household: The household to place the created Sim in. If None, the Sim will be placed in a hidden household. Default is None. - :type household: Household, optional - :param source: The reason for the Sims creation. Default is 'testing'. - :type source: str, optional - :return: The SimInfo of the created Sim or None if the Sim failed to be created. - :rtype: SimInfo - """ - return cls._create_sim_info( - CommonSpecies.CAT, - gender=gender, - age=age, - first_name=first_name, - last_name=last_name, - trait_ids=trait_ids, - household=household, - source=source - ) - - @classmethod - def create_fox_sim_info( - cls, - gender: CommonGender = None, - age: CommonAge = None, - first_name: str = None, - last_name: str = None, - trait_ids: Tuple[int] = (), - household: Household = None, - source: str = 'testing' - ) -> Union[SimInfo, None]: - """create_fox_sim_info(\ - gender=None,\ - age=None,\ - first_name='',\ - last_name='',\ - trait_ids=(),\ - household=None,\ - source='testing'\ - ) - - Create SimInfo for a Fox Sim. - - :param gender: The gender of the created Sim. Default is None. - :type gender: CommonGender, optional - :param age: The age of the created Sim. Default is None. - :type age: CommonAge, optional - :param first_name: The First Name of the created Sim. Default is random name. - :type first_name: str, optional - :param last_name: The Last Name of the created Sim. Default is random name. - :type last_name: str, optional - :param trait_ids: The decimal identifiers of the Traits to add to the created Sim. Default is an empty collection. - :type trait_ids: Tuple[int], optional - :param household: The household to place the created Sim in. If None, the Sim will be placed in a hidden household. Default is None. - :type household: Household, optional - :param source: The reason for the Sims creation. Default is 'testing'. - :type source: str, optional - :return: The SimInfo of the created Sim or None if the Sim failed to be created. - :rtype: SimInfo - """ - return cls._create_sim_info( - CommonSpecies.FOX, - gender=gender, - age=age, - first_name=first_name, - last_name=last_name, - trait_ids=trait_ids, - household=household, - source=source - ) - - @classmethod - def create_horse_sim_info( - cls, - gender: CommonGender = None, - age: CommonAge = None, - first_name: str = None, - last_name: str = None, - trait_ids: Tuple[int] = (), - household: Household = None, - source: str = 'testing' - ) -> Union[SimInfo, None]: - """create_horse_sim_info(\ - gender=None,\ - age=None,\ - first_name='',\ - last_name='',\ - trait_ids=(),\ - household=None,\ - source='testing'\ - ) - - Create SimInfo for a Horse Sim. - - :param gender: The gender of the created Sim. Default is None. - :type gender: CommonGender, optional - :param age: The age of the created Sim. Default is None. - :type age: CommonAge, optional - :param first_name: The First Name of the created Sim. Default is random name. - :type first_name: str, optional - :param last_name: The Last Name of the created Sim. Default is random name. - :type last_name: str, optional - :param trait_ids: The decimal identifiers of the Traits to add to the created Sim. Default is an empty collection. - :type trait_ids: Tuple[int], optional - :param household: The household to place the created Sim in. If None, the Sim will be placed in a hidden household. Default is None. - :type household: Household, optional - :param source: The reason for the Sims creation. Default is 'testing'. - :type source: str, optional - :return: The SimInfo of the created Sim or None if the Sim failed to be created. - :rtype: SimInfo - """ - return cls._create_sim_info( - CommonSpecies.HORSE, - gender=gender, - age=age, - first_name=first_name, - last_name=last_name, - trait_ids=trait_ids, - household=household, - source=source - ) - - @classmethod - def _create_sim_info( - cls, - species: CommonSpecies, - gender: CommonGender = None, - age: CommonAge = None, - first_name: str = None, - first_name_key: int = 0, - last_name: str = None, - last_name_key: int = 0, - full_name_key: int = 0, - breed_name: str = '', - breed_name_key: int = 0, - trait_ids: Iterator[int] = (), - household: Household = None, - source: str = 'testing' - ) -> Union[SimInfo, None]: - from s4ap.sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils - household = household or CommonHouseholdUtils.create_empty_household(as_hidden_household=True) - vanilla_gender = CommonGender.convert_to_vanilla(gender) - vanilla_age = CommonAge.convert_to_vanilla(age) - vanilla_species = CommonSpecies.convert_to_vanilla(species) - if vanilla_species is None or vanilla_species == SpeciesExtended.INVALID: - raise AssertionError(f'Invalid species specified for SimInfo creation! {species}') - first_name = first_name or CommonSimNameUtils.create_random_first_name(gender, species=species) - last_name = last_name or CommonSimNameUtils.create_random_last_name(gender, species=species) - traits = tuple([CommonTraitUtils.load_trait_by_id(trait_id) for trait_id in trait_ids if CommonTraitUtils.load_trait_by_id(trait_id) is not None]) - from s4ap.sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils - sim_creator = SimCreator( - gender=vanilla_gender, - age=vanilla_age, - species=vanilla_species, - first_name=first_name, - first_name_key=first_name_key, - last_name=last_name, - last_name_key=last_name_key, - full_name_key=full_name_key, - traits=traits, - breed_name=breed_name if breed_name else 'Custom Breed' if CommonSpeciesUtils.is_animal_species(vanilla_species) else '', - breed_name_key=breed_name_key if breed_name_key else CommonStringId.S4CL_CUSTOM_BREED if CommonSpeciesUtils.is_animal_species(vanilla_species) else 0, - ) - (sim_info_list, _) = SimSpawner.create_sim_infos((sim_creator,), household=household, generate_deterministic_sim=True, creation_source=source) - if not sim_info_list: - return None - return sim_info_list[0] - - @classmethod - def spawn_sim( - cls, - sim_info: SimInfo, - location: CommonLocation = None, - position: CommonVector3 = None, - **kwargs - ) -> bool: - """spawn_sim(sim_info, location=None, position=None, **kwargs) - - Spawn a Sim. - - ..note:: Do not provide sim_position or sim_location in kwargs as they are already specified as location and position. - - :param sim_info: The Sim to Spawn. - :type sim_info: SimInfo - :param location: The location to spawn the Sim at. Default is None. - :type location: CommonLocation, optional - :param position: The position to spawn the Sim at. Default is None. - :type position: CommonVector3, optional - :return: True, if the Sim was spawned successfully. False, if not. - :rtype: bool - """ - if sim_info is None: - return False - if CommonSimUtils.get_sim_instance(sim_info) is not None: - return True - from s4ap.sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils - if CommonAgeUtils.is_baby(sim_info): - # Sim is baby, they spawn differently. - from sims.baby.baby_utils import create_and_place_baby - position_to_spawn_at = None - routing_surface_to_spawn = None - if position is not None: - position_to_spawn_at = position - routing_surface_to_spawn = CommonSurfaceIdentifier.empty() - if location is not None: - position_to_spawn_at = location.transform.translation - routing_surface_to_spawn = location.routing_surface - if position_to_spawn_at is None or routing_surface_to_spawn is None: - return False - create_and_place_baby(sim_info, position=position_to_spawn_at, routing_surface=routing_surface_to_spawn) - else: - SimSpawner.spawn_sim(sim_info, sim_location=location, sim_position=position, **kwargs) - - household = CommonHouseholdUtils.get_household(sim_info) - if household and CommonSimUtils.get_sim_instance(sim_info) is None: - sim_info.inject_into_inactive_zone(household.home_zone_id) - return True - - @classmethod - def spawn_sim_at_active_sim_location( - cls, - sim_info: SimInfo, - **kwargs - ) -> bool: - """spawn_sim_at_active_sim_location(sim_info, **kwargs) - - Spawn a Sim at the location of the Active Sim. - - :param sim_info: The Sim to Spawn. - :type sim_info: SimInfo - :return: True, if the Sim was spawned successfully. False, if not. - :rtype: bool - """ - from s4ap.sims4communitylib.utils.sims.common_sim_location_utils import CommonSimLocationUtils - from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - active_sim_info = CommonSimUtils.get_active_sim_info() - active_location = CommonSimLocationUtils.get_location(active_sim_info) - active_position = None - if active_location is None: - active_position = CommonSimLocationUtils.get_position(active_sim_info) - return cls.spawn_sim(sim_info, location=active_location, position=active_position, **kwargs) - - @classmethod - def clone_sim( - cls, - source_sim_info: SimInfo, - add_to_household: bool = True, - household_override: Household = None - ) -> Union[SimInfo, None]: - """clone_sim(source_sim_info, add_to_household=True, household_override=None) - - Clone a Sim and add them to the household of source_sim_info. - - :param source_sim_info: The Sim to clone. - :type source_sim_info: SimInfo - :param add_to_household: If True, the Sim will be added to the household of "source_sim_info". If False, the Sim will be cloned into their own household. Default is True. - :type add_to_household: bool, optional - :param household_override: If specified, this household will be the one the cloned Sim will be added to. Default is None. - :type household_override: Household, optional - :return: The cloned Sim Info or None if cloning failed. - :rtype: Union[SimInfo, None] - """ - from s4ap.sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils - if household_override is not None: - household = household_override - else: - if add_to_household: - household = CommonHouseholdUtils.get_household(source_sim_info) - if household is None: - raise Exception(f'No household was specified from source Sim {source_sim_info} with household {household}!') - else: - household = CommonHouseholdUtils.create_empty_household() - household_id = CommonHouseholdUtils.get_id(household) - species = CommonSpecies.get_species(source_sim_info) - gender = CommonGender.get_gender(source_sim_info) - vanilla_gender = CommonGender.convert_to_vanilla(gender) - clone_sim_data = cls._build_sim_data(source_sim_info) - clone_sim_info = cls._load_sim_data(clone_sim_data, trait_ids=tuple(source_sim_info.trait_tracker.equipped_traits), household=household, source='cloning sim') - # clone_sim_info = cls.create_sim_info( - # species=species, - # gender=gender, - # age=CommonAge.get_age(source_sim_info), - # first_name=SimSpawner.get_random_first_name(vanilla_gender, source_sim_info.species), - # last_name=source_sim_info._base.last_name, - # trait_ids=tuple(source_sim_info.trait_tracker.equipped_traits), - # household=household, - # source='cloning' - # ) - if clone_sim_info is None: - return None - # try: - # source_sim_proto = source_sim_info.save_sim(for_cloning=True) - # clone_sim_id = clone_sim_info.sim_id - # source_first_name = source_sim_info._base.first_name - # source_last_name = source_sim_info._base.last_name - # source_breed_name = source_sim_info._base.breed_name - # source_first_name_key = source_sim_info._base.first_name_key - # source_last_name_key = source_sim_info._base.last_name_key - # source_full_name_key = source_sim_info._base.full_name_key - # source_breed_name_key = source_sim_info._base.breed_name_key - # clone_first_name = clone_sim_info._base.first_name - # clone_last_name = clone_sim_info._base.last_name - # clone_breed_name = clone_sim_info._base.breed_name - # clone_first_name_key = clone_sim_info._base.first_name_key - # clone_last_name_key = clone_sim_info._base.last_name_key - # clone_full_name_key = clone_sim_info._base.full_name_key - # clone_breed_name_key = clone_sim_info._base.breed_name_key - # clone_sim_info.load_sim_info(source_sim_proto, is_clone=True, default_lod=SimInfoLODLevel.FULL) - # clone_sim_info.sim_id = clone_sim_id - # clone_sim_info._base.first_name = clone_first_name or source_first_name - # clone_sim_info._base.last_name = clone_last_name or source_last_name - # clone_sim_info._base.breed_name = clone_breed_name or source_breed_name - # clone_sim_info._base.first_name_key = clone_first_name_key or source_first_name_key - # clone_sim_info._base.last_name_key = clone_last_name_key or source_last_name_key - # clone_sim_info._base.full_name_key = clone_full_name_key or source_full_name_key - # clone_sim_info._base.breed_name_key = clone_breed_name_key or source_breed_name_key - # clone_sim_info._household_id = household_id - # source_trait_tracker = source_sim_info.trait_tracker - # clone_trait_tracker = clone_sim_info.trait_tracker - # for trait in clone_trait_tracker.personality_traits: - # if not source_trait_tracker.has_trait(trait): - # clone_sim_info.remove_trait(trait) - # for trait in clone_trait_tracker.gender_option_traits: - # if not source_trait_tracker.has_trait(trait): - # clone_sim_info.remove_trait(trait) - # CommonSimUtils.get_sim_info_manager().set_default_genealogy(sim_infos=(clone_sim_info,)) - # clone_sim_info.set_default_data() - # clone_sim_info.save_sim() - # household.save_data() - # if not household.is_active_household: - # clone_sim_info.request_lod(SimInfoLODLevel.BASE) - # clone_sim_info.resend_physical_attributes() - # except Exception as ex: - # cls.delete_sim(clone_sim_info) - # raise ex - return clone_sim_info - - # Load - @classmethod - def _load_sim_data( - cls, - sim_save_data: Dict[str, Any], - trait_ids: Tuple[int] = (), - household: Household = None, - source: str = 'testing' - ) -> Union[SimInfo, None]: - """load_sim_data(\ - sim_save_data,\ - trait_ids=(),\ - household=None,\ - source='testing'\ - ) - - Create a Sim Info from a dictionary of data. - - :param sim_save_data: - :param trait_ids: - :param household: - :param source: - :return: - """ - species_str: str = sim_save_data.get('species', None) - if species_str is None: - return None - species = CommonResourceUtils.get_enum_by_name(species_str, CommonSpecies, default_value=None) - if species is None: - return None - gender_str = sim_save_data.get('gender', None) - if gender_str is None: - return None - gender = CommonResourceUtils.get_enum_by_name(gender_str, CommonGender, default_value=None) - if gender is None: - return None - age_str = sim_save_data.get('age', None) - if age_str is None: - return None - age = CommonResourceUtils.get_enum_by_name(age_str, CommonAge, default_value=None) - if age is None: - return None - first_name: str = sim_save_data.get('first_name', None) - last_name: str = sim_save_data.get('last_name', None) - from s4ap.sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils - household = household or CommonHouseholdUtils.create_empty_household(as_hidden_household=True) - vanilla_gender = CommonGender.convert_to_vanilla(gender) - vanilla_age = CommonAge.convert_to_vanilla(age) - vanilla_species = CommonSpecies.convert_to_vanilla(species) - if vanilla_species is None or vanilla_species == SpeciesExtended.INVALID: - log.format_with_message('The required pack for Sim was not available.', species=species) - return None - first_name = first_name or CommonSimNameUtils.create_random_first_name(gender, species=species) - last_name = last_name or CommonSimNameUtils.create_random_last_name(gender, species=species) - traits = tuple([CommonTraitUtils.load_trait_by_id(trait_id) for trait_id in trait_ids if CommonTraitUtils.load_trait_by_id(trait_id) is not None]) - from s4ap.sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils - breed_name = sim_save_data.get('breed_name', '') - first_name_key = sim_save_data.get('first_name_key', 0) - last_name_key = sim_save_data.get('last_name_key', 0) - full_name_key = sim_save_data.get('full_name_key', 0) - breed_name_key = sim_save_data.get('breed_name_key', 0) - sim_creator = SimCreator( - gender=vanilla_gender, - age=vanilla_age, - species=vanilla_species, - first_name=first_name, - first_name_key=first_name_key, - last_name=last_name, - last_name_key=last_name_key, - full_name_key=full_name_key, - traits=traits, - breed_name=breed_name if breed_name else 'Custom Breed' if CommonSpeciesUtils.is_animal_species(vanilla_species) else '', - breed_name_key=breed_name_key if breed_name_key else 0x599432EA if CommonSpeciesUtils.is_animal_species(vanilla_species) else 0 - ) - (sim_info_list, _) = SimSpawner.create_sim_infos((sim_creator,), household=household, generate_deterministic_sim=True, creation_source=source) - if not sim_info_list: - return None - sim_info: SimInfo = sim_info_list[0] - - time_stamp = time.time() - sim_info._base.species = vanilla_species - # noinspection PyPropertyAccess - extended_species = sim_info.extended_species - sim_info._species = SpeciesExtended.get_species(extended_species) - required_pack = SpeciesExtended.get_required_pack(extended_species) - if required_pack is not None and not CommonGamePackUtils.has_game_pack_available(required_pack): - log.format_with_message('The required pack for Sim was not available.', species=extended_species) - return None - species_def = None - if indexed_manager.capture_load_times: - species_def = sim_info.get_sim_definition(sim_info.species) - if species_def not in indexed_manager.object_load_times: - indexed_manager.object_load_times[species_def] = indexed_manager.ObjectLoadData() - - lod_str = sim_save_data.get('lod', None) - if lod_str is not None: - lod = CommonResourceUtils.get_enum_by_name(lod_str, SimInfoLODLevel, default_value=SimInfoLODLevel.BACKGROUND) - else: - lod = SimInfoLODLevel.BACKGROUND - sim_info._lod = lod - sim_info._initialize_sim_info_trackers(sim_info._lod) - skip_load = False - if gender == CommonGender.MALE or gender == CommonGender.FEMALE: - sim_info._base.gender = vanilla_gender - sim_info._base.age = vanilla_age - from sims.sim_info import lod_logger - from sims.sim_info import INJECT_LOD_NAME_IN_CALLSTACK - if not INJECT_LOD_NAME_IN_CALLSTACK: - cls._load_sim_info(sim_info, sim_save_data, skip_load, household) - time_elapsed = time.time() - time_stamp - if indexed_manager.capture_load_times: - indexed_manager.object_load_times[species_def].time_spent_loading += time_elapsed - indexed_manager.object_load_times[species_def].loads += 1 - lod_logger.info('Loaded {} with lod {} in {} seconds.', sim_info.full_name, sim_info._lod.name, time_elapsed) - from s4ap.sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils - current_outfit = CommonOutfitUtils.get_current_outfit(sim_info) - sim_info.outfit_type_and_index = current_outfit - sim_info.resend_outfits() - return sim_info - from sims4.profiler_utils import create_custom_named_profiler_function - name_f = create_custom_named_profiler_function('Load LOD {} SimInfo'.format(sim_info._lod.name)) - name_f(lambda: cls._load_sim_info(sim_info, sim_save_data, skip_load, household)) - if indexed_manager.capture_load_times: - time_elapsed = time.time() - time_stamp - indexed_manager.object_load_times[species_def].time_spent_loading += time_elapsed - indexed_manager.object_load_times[species_def].loads += 1 - lod_logger.info('Loaded {} with lod {} in {} seconds.', sim_info.full_name, sim_info._lod.name, time_elapsed) - from s4ap.sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils - current_outfit = CommonOutfitUtils.get_current_outfit(sim_info) - sim_info._base.outfit_type_and_index = current_outfit - sim_info.resend_outfits() - sim_info.on_outfit_generated(*current_outfit) - sim_info.set_outfit_dirty(current_outfit[0]) - sim_info.set_current_outfit(current_outfit) - sim_info._set_fit_fat() - return sim_info - - @classmethod - def _load_sim_info( - cls, - sim_info: SimInfo, - sim_save_data: Dict[str, Any], - skip_load: bool, - household: Household - ) -> None: - species_str: str = sim_save_data.get('species', None) - if species_str is None: - return None - species = CommonResourceUtils.get_enum_by_name(species_str, CommonSpecies, default_value=None) - if species is None: - return None - gender_str = sim_save_data.get('gender', None) - if gender_str is None: - return None - gender = CommonResourceUtils.get_enum_by_name(gender_str, CommonGender, default_value=None) - if gender is None: - return None - age_str = sim_save_data.get('age', None) - if age_str is None: - return None - age = CommonResourceUtils.get_enum_by_name(age_str, CommonAge, default_value=None) - if age is None: - return None - first_name: str = sim_save_data.get('first_name', None) - last_name: str = sim_save_data.get('last_name', None) - vanilla_species = CommonSpecies.convert_to_vanilla(species) - if vanilla_species is None or vanilla_species == SpeciesExtended.INVALID: - log.format_with_message('The required pack for Sim was not available.', species=species) - return None - first_name = first_name or CommonSimNameUtils.create_random_first_name(gender, species=species) - last_name = last_name or CommonSimNameUtils.create_random_last_name(gender, species=species) - breed_name = sim_save_data.get('breed_name', '') - first_name_key = sim_save_data.get('first_name_key', 0) - last_name_key = sim_save_data.get('last_name_key', 0) - full_name_key = sim_save_data.get('full_name_key', 0) - breed_name_key = sim_save_data.get('breed_name_key', 0) - - sim_info._base.first_name = first_name - sim_info._base.last_name = last_name - sim_info._base.breed_name = breed_name - sim_info._base.first_name_key = first_name_key - sim_info._base.last_name_key = last_name_key - sim_info._base.full_name_key = full_name_key - sim_info._base.breed_name_key = breed_name_key - - pronouns = sim_save_data.get('pronouns_data', None) - if pronouns is not None: - cls._load_pronouns_data(sim_info._base, pronouns) - - from objects.components.consumable_component import ConsumableComponent - sim_info.commodity_tracker.set_value(ConsumableComponent.FAT_COMMODITY, sim_save_data.get('fat')) - sim_info.commodity_tracker.set_value(ConsumableComponent.FIT_COMMODITY, sim_save_data.get('fit')) - - sim_info._household_id = CommonHouseholdUtils.get_id(household) - sim_info._serialization_option = SimSerializationOption.UNDECLARED - physical_attributes = sim_save_data.get('physical_attributes', None) - if physical_attributes is not None: - cls._load_physical_attributes(sim_info, physical_attributes) - sim_info.custom_texture = sim_save_data.get('custom_texture', 0) - - # noinspection SpellCheckingInspection - sim_info.do_first_sim_info_load_fixups = True - sim_info._get_fit_fat() - - # if sim_attribute_data is not None: - # sim_info.set_trait_ids_on_base(trait_ids_override=list(set(itertools.chain(sim_attribute_data.trait_tracker.trait_ids, sim_info.trait_ids)))) - - age_progress = sim_save_data.get('age_progress', 0) - sim_info._age_progress.set_value(age_progress) - - primary_aspiration_id = sim_save_data.get('primary_aspiration', 0) - primary_aspiration = CommonResourceUtils.load_instance(Types.ASPIRATION_TRACK, primary_aspiration_id) - if primary_aspiration is not None: - sim_info._primary_aspiration = primary_aspiration - - outfit_data = sim_save_data.get('outfit_data', None) - if outfit_data is not None: - cls._load_outfit_data(sim_info._base, outfit_data) - - initial_fitness_value = sim_save_data.get('initial_fitness_value', None) - if initial_fitness_value is not None: - sim_info._initial_fitness_value = initial_fitness_value - - # if sim_attribute_data is not None: - # sim_info._relationship_tracker.load(sim_attribute_data.relationship_tracker.relationships) - # sim_info._genealogy_tracker.load_genealogy(sim_attribute_data.genealogy_tracker) - - death_data = sim_save_data.get('death_data', None) - if death_data is not None: - cls._load_death_data(sim_info, death_data) - - sim_occult_data = sim_save_data.get('occult_data', None) - if sim_occult_data is not None: - cls._load_occult_data(sim_info, sim_occult_data) - # if sim_proto.significant_other != 0: - # sim_info.update_spouse_sim_id(sim_proto.significant_other) - # if sim_proto.fiance != 0: - # sim_info.update_fiance_sim_id(sim_proto.fiance) - Ghost.make_ghost_if_needed(sim_info) - - # sim_info._build_buy_unlocks = set() - # old_unlocks = set(list(sim_proto.gameplay_data.build_buy_unlocks)) - # for unlock in old_unlocks: - # if isinstance(unlock, int): - # key = sims4.resources.Key(Types.OBJCATALOG, unlock, 0) - # sim_info._build_buy_unlocks.add(key) - # if hasattr(sim_proto.gameplay_data, 'build_buy_unlock_list'): - # for key_proto in sim_proto.gameplay_data.build_buy_unlock_list.resource_keys: - # key = sims4.resources.Key(key_proto.type, key_proto.instance, key_proto.group) - # sim_info._build_buy_unlocks.add(key) - if not CommonAgeUtils.is_baby_or_toddler(sim_info): - available_aspirations = list() - aspiration_track_manager = CommonResourceUtils.get_instance_manager(Types.ASPIRATION_TRACK) - for aspiration_track in aspiration_track_manager.types.values(): - if aspiration_track.is_hidden_unlockable or aspiration_track.is_valid_for_sim(sim_info): - available_aspirations.append(aspiration_track) - sim_info._primary_aspiration = random.choice(available_aspirations) - - # sim_info._cached_inventory_value = sim_proto.gameplay_data.inventory_value - # if sim_info._primary_aspiration is None or sim_info._primary_aspiration.is_available() or sim_info.is_human and skip_load or sim_info._away_action_tracker is not None: - # sim_info._away_action_tracker.load_away_action_info_from_proto(sim_proto.gameplay_data.away_action_tracker) - # sim_info.spawn_point_id = sim_proto.gameplay_data.spawn_point_id if sim_proto.gameplay_data.HasField('spawn_point_id') else None - # sim_info.spawn_point_option = SpawnPointOption(sim_proto.gameplay_data.spawn_point_option) if sim_proto.gameplay_data.HasField('spawn_point_option') else SpawnPointOption.SPAWN_ANY_POINT_WITH_CONSTRAINT_TAGS - # sim_info.spawner_tags = [] - # if sim_proto.gameplay_data.HasField('time_alive'): - # time_alive = TimeSpan(sim_proto.gameplay_data.time_alive) - # else: - # time_alive = None - sim_info.load_time_alive(None) - # for spawner_tag in sim_proto.gameplay_data.spawner_tags: - # sim_info.spawner_tags.append(tag.Tag(spawner_tag)) - try: - sim_info.Buffs.load_in_progress = True - sim_info.commodity_tracker.load_in_progress = True - sim_info.on_base_characteristic_changed() - with services.relationship_service().suppress_client_updates_context_manager(): - trait_data = sim_save_data.get('trait_data', None) - if trait_data: - cls._load_trait_data(sim_info, trait_data, skip_load) - finally: - sim_info.Buffs.load_in_progress = False - sim_info.commodity_tracker.load_in_progress = False - - sim_info._create_additional_statistics() - # if sim_info._whim_tracker is not None: - # sim_info._whim_tracker.cache_whim_goal_proto(sim_proto.gameplay_data.whim_tracker, skip_load=skip_load) - # if sim_info._satisfaction_tracker is not None: - # sim_info._satisfaction_tracker.set_satisfaction_points(sim_proto.gameplay_data.whim_bucks, SetWhimBucks.LOAD) - current_outfit_info = sim_save_data.get('current_outfit_info', None) - if current_outfit_info is not None: - current_outfit_category_str = current_outfit_info.get('outfit_category', 'EVERYDAY') - current_outfit_category = CommonResourceUtils.get_enum_by_name(current_outfit_category_str, OutfitCategory, default_value=OutfitCategory.EVERYDAY) - current_outfit_index = current_outfit_info.get('outfit_index', 0) - sim_info._set_current_outfit_without_distribution((current_outfit_category, current_outfit_index)) - - # sim_info._load_inventory(sim_proto, skip_load) - additional_bonus_days = sim_save_data.get('additional_bonus_days', 0) - sim_info._additional_bonus_days = additional_bonus_days - - favorite_recipe_ids = sim_save_data.get('favorite_recipe_ids', None) - if favorite_recipe_ids is not None: - recipe_manager = CommonResourceUtils.get_instance_manager(Types.RECIPE) - for recipe_id in favorite_recipe_ids: - recipe = recipe_manager.get(recipe_id) - if recipe is not None: - sim_info.set_favorite_recipe(recipe) - - # if sim_proto.gameplay_data.zone_time_stamp.HasField('time_sim_was_saved'): - # sim_info._time_sim_was_saved = DateAndTime(sim_proto.gameplay_data.zone_time_stamp.time_sim_was_saved) - # if skip_load or sim_proto.gameplay_data.zone_time_stamp.game_time_expire != 0: - # sim_info.game_time_bring_home = sim_proto.gameplay_data.zone_time_stamp.game_time_expire - - try: - sim_info.Buffs.load_in_progress = True - sim_info._blacklisted_statistics_cache = sim_info.get_blacklisted_statistics() - - sim_statistic_data = sim_save_data.get('statistics_data', None) - if sim_statistic_data is not None: - cls._load_statistic_data(sim_info, sim_statistic_data, skip_load) - - sim_commodity_data = sim_save_data.get('commodity_data', None) - if sim_commodity_data is not None: - cls._load_commodity_data(sim_info, sim_commodity_data, skip_load) - - if sim_info.is_human: - trait_statistic_data = sim_save_data.get('trait_statistic_data', None) - if trait_statistic_data is not None: - cls._load_trait_statistic_data(sim_info, trait_statistic_data) - - if sim_commodity_data is not None: - skill_data = sim_commodity_data.get('skills', None) - if skill_data: - skills_to_check_for_unlocks = [commodity for commodity in sim_info.commodity_tracker.get_all_commodities() if commodity.unlocks_skills_on_max() and len(commodity.skill_unlocks_on_max) > 0] - if skills_to_check_for_unlocks: - cls._update_unlock_skills(sim_info, skills_to_check_for_unlocks, skill_data) - - suntan_data = sim_save_data.get('suntan_data', None) - if suntan_data is not None: - cls._load_suntan_data(sim_info, suntan_data) - - # sim_info._pregnancy_tracker.load(sim_attribute_data.pregnancy_tracker) - appearance_data = sim_save_data.get('appearance_data', None) - if appearance_data is not None: - cls._load_appearance_data(sim_info, appearance_data) - - # if sim_attribute_data.HasField('sickness_tracker'): - # sim_info.sickness_tracker.load_sickness_tracker_data(sim_attribute_data.sickness_tracker) - # if sim_info.has_sickness_tracking(): - # sim_info.current_sickness.on_sim_info_loaded(sim_info) - # if sim_attribute_data.HasField('stored_object_info_component'): - # component_def = objects.components.types.STORED_OBJECT_INFO_COMPONENT - # if sim_info.add_dynamic_component(component_def): - # stored_object_info_component = sim_info.get_component(component_def) - # stored_object_info_component.load_stored_object_info(sim_attribute_data.stored_object_info_component) - # for entry in sim_attribute_data.object_preferences.preferences: - # sim_info._autonomy_scoring_preferences[entry.tag] = entry.object_id - # for entry in sim_attribute_data.object_ownership.owned_object: - # sim_info._autonomy_use_preferences[entry.tag] = entry.object_id - # sim_info._career_tracker.load(sim_attribute_data.sim_careers, skip_load=skip_load) - # if sim_info._adventure_tracker is not None: - # sim_info._adventure_tracker.load(sim_attribute_data.adventure_tracker) - # if sim_info._notebook_tracker is not None: - # sim_info._notebook_tracker.load_notebook(sim_attribute_data.notebook_tracker) - # if sim_info._royalty_tracker is not None and not skip_load: - # sim_info._royalty_tracker.load(sim_attribute_data.royalty_tracker) - # if sim_info._unlock_tracker is not None: - # skip_load = skip_load and not is_clone - # sim_info._unlock_tracker.load_unlock(sim_attribute_data.unlock_tracker, skip_load=skip_load) - # if sim_info._relic_tracker is not None and not skip_load: - # sim_info._relic_tracker.load(sim_attribute_data.relic_tracker) - # if sim_info._lifestyle_brand_tracker is not None and not skip_load: - # sim_info._lifestyle_brand_tracker.load(sim_attribute_data.lifestyle_brand_tracker) - # if sim_info._favorites_tracker is not None and not skip_load: - # sim_info._favorites_tracker.load(sim_attribute_data.favorites_tracker) - # if sim_info._degree_tracker is not None: - # sim_info.degree_tracker.load(sim_attribute_data.degree_tracker) - # if sim_info._organization_tracker is not None and not skip_load: - # sim_info._organization_tracker.load(sim_attribute_data.organization_tracker) - # if sim_info._fixup_tracker is not None and not skip_load: - # sim_info._fixup_tracker.load(sim_attribute_data.fixup_tracker) - # if sim_info._story_progression_tracker is not None and not skip_load: - # sim_info._story_progression_tracker.load(sim_attribute_data.story_progression_tracker) - # if sim_info._lunar_effect_tracker is not None and not skip_load: - # sim_info._lunar_effect_tracker.load_lunar_effects(sim_attribute_data.lunar_effect_tracker) - except Exception as ex: - log.error(f'Failed to load attributes for sim {sim_info._base.first_name}.', exception=ex, throw=False) - finally: - sim_info._blacklisted_statistics_cache = None - sim_info.Buffs.load_in_progress = False - - sim_info._setup_fitness_commodities() - sim_info._trait_tracker.fixup_gender_preference_statistics() - sim_info._add_gender_preference_listeners() - - # if sim_info._serialization_option != SimSerializationOption.UNDECLARED: - # world_coord = sims4.math.Transform() - # location = sim_proto.gameplay_data.location - # world_coord.translation = sims4.math.Vector3(location.x, location.y, location.z) - # world_coord.orientation = sims4.math.Quaternion(location.rot_x, location.rot_y, location.rot_z, location.rot_w) - # sim_info._transform_on_load = world_coord - # sim_info._level_on_load = location.level - # sim_info._surface_id_on_load = location.surface_id - - # sim_info._si_state = gameplay_serialization.SuperInteractionSaveState() - # if skip_load or sim_proto.gameplay_data.HasField('location') and sim_proto.gameplay_data.HasField('interaction_state'): - # sim_info._has_loaded_si_state = True - # sim_info._si_state.MergeFrom(sim_proto.gameplay_data.interaction_state) - - services.sim_info_manager().add_sim_info_if_not_in_manager(sim_info) - - bucks_data = sim_save_data.get('bucks_data', None) - if bucks_data is not None: - cls._load_bucks_data(sim_info, bucks_data) - - # if sim_proto.gameplay_data.HasField('gameplay_options'): - # sim_info._gameplay_options = sim_proto.gameplay_data.gameplay_options - # if sim_info.get_gameplay_option(SimInfoGameplayOptions.FORCE_CURRENT_ALLOW_FAME_SETTING) and not sim_info.get_gameplay_option(SimInfoGameplayOptions.ALLOW_FAME): - # sim_info.allow_fame = False - # elif sim_info.get_gameplay_option(SimInfoGameplayOptions.FREEZE_FAME): - # sim_info.set_freeze_fame(True, force=True) - # for squad_member_id in sim_proto.gameplay_data.squad_members: - # sim_info.add_sim_info_id_to_squad(squad_member_id) - # if sim_proto.gameplay_data.HasField('vehicle_id'): - # sim_info._vehicle_id = sim_proto.gameplay_data.vehicle_id - sim_info._post_load() - - @classmethod - def _load_bucks_data( - cls, - sim_info: SimInfo, - sim_bucks_data: Dict[str, Any], - ): - bucks_tracker = sim_info.get_bucks_tracker(add_if_none=True) - - bucks_perk_manager = CommonResourceUtils.get_instance_manager(Types.BUCKS_PERK) - for bucks_data in sim_bucks_data.get('bucks', tuple()): - bucks_type_str = bucks_data.get('bucks_type', None) - if bucks_type_str is None: - continue - bucks_type = CommonResourceUtils.get_enum_by_name(bucks_type_str, CommonBucksType, default_value=None) - if bucks_type is None: - continue - bucks_amount = bucks_data.get('amount', 0) - - if bucks_amount >= 0: - vanilla_bucks_type = CommonBucksType.convert_to_vanilla(bucks_type) - bucks_tracker.try_modify_bucks(vanilla_bucks_type, bucks_amount, allow_distribute=False, from_load=True) - - for perk_data in bucks_data.get('perk_data', tuple()): - perk_id = perk_data.get('perk_id', None) - if perk_id is None: - continue - perk_ref = bucks_perk_manager.get(perk_id) - if perk_ref is None: - log.format_with_message('Trying to load unavailable BUCKS_PERK resource', perk_id=perk_id) - continue - unlock_reason = perk_data.get('unlock_reason', None) - if unlock_reason is not None: - unlocked_by = bucks_perk_manager.get(unlock_reason) - else: - unlocked_by = None - timestamp = CommonTimeUtils.get_current_date_and_time() - currently_unlocked = perk_data.get('currently_unlocked', False) - bucks_tracker._unlocked_perks[perk_ref.associated_bucks_type][perk_ref] = PerkData(unlocked_by, timestamp, currently_unlocked) - if currently_unlocked: - bucks_tracker._award_buffs(perk_ref) - bucks_tracker._award_traits(perk_ref) - time_left = perk_data.get('time_left', None) - if time_left is not None: - bucks_tracker._set_up_temporary_perk_timer(perk_ref, time_left) - - @classmethod - def _load_trait_data( - cls, - sim_info: SimInfo, - sim_trait_data: Dict[str, Any], - skip_load: bool - ): - from traits.trait_quirks import add_quirks - trait_tracker = sim_info._trait_tracker - saved_trait_ids = sim_trait_data.get('trait_ids', tuple()) - trait_manager = CommonResourceUtils.get_instance_manager(Types.TRAIT) - try: - trait_tracker._load_in_progress = True - trait_tracker._sim_info._update_age_trait(trait_tracker._sim_info.age) - pre_made_sim_needing_fixup = bool(trait_tracker._sim_info.sim_template_id) - for trait_instance_id in saved_trait_ids: - trait = trait_manager.get(trait_instance_id, None) - if trait is None: - continue - if not trait_tracker._has_valid_lod(trait): - if trait.min_lod_value == SimInfoLODLevel.ACTIVE: - if trait_tracker._delayed_active_lod_traits is None: - trait_tracker._delayed_active_lod_traits = list() - trait_tracker._delayed_active_lod_traits.append(trait) - if skip_load and not (pre_made_sim_needing_fixup or trait.allow_from_gallery): - continue - else: - trait_tracker._sim_info.add_trait(trait) - elif skip_load and not (pre_made_sim_needing_fixup or trait.allow_from_gallery): - continue - else: - trait_tracker._sim_info.add_trait(trait) - if trait_tracker.personality_traits or not trait_tracker._sim_info.is_baby: - possible_traits = [trait for trait in trait_manager.types.values() if trait.is_personality_trait and trait_tracker.can_add_trait(trait)] - if possible_traits: - chosen_trait = random.choice(possible_traits) - trait_tracker._add_trait(chosen_trait) - trait_tracker._add_default_gender_option_traits() - add_quirks(trait_tracker._sim_info) - trait_tracker._sim_info.on_all_traits_loaded() - finally: - trait_tracker._load_in_progress = False - - @classmethod - def _load_outfit_data( - cls, - sim_info: SimInfo, - outfit_data_external: Dict[str, Any] - ): - outfits_msg = Outfits_pb2.OutfitList() - parsed_outfits = list() - for (outfit_category_name, outfit_data_list) in outfit_data_external.items(): - outfit_category = CommonResourceUtils.get_enum_by_name(outfit_category_name, OutfitCategory, default_value=None) - if outfit_category is None: - continue - for outfit_data in outfit_data_list: - outfit = Outfits_pb2.OutfitData() - outfit.category = int(outfit_category) - part_data_list = outfit_data.get('part_data_list', None) - if part_data_list is None: - continue - body_types = list() - part_ids = list() - part_color_shifts = list() - added_parts = False - for part_data in part_data_list: - body_type = part_data.get('body_type', None) - part_id = part_data.get('part_id', None) - part_color_shift = part_data.get('part_color_shift', None) - if body_type is None or part_id is None or part_color_shift is None: - continue - if not CommonCASUtils.is_cas_part_loaded(part_id)\ - and int(body_type) in ( - int(BodyType.LOWER_BODY), - int(BodyType.UPPER_BODY), - int(BodyType.FULL_BODY), - int(BodyType.SHOES) - ): - added_parts = False - break - added_parts = True - body_types.append(body_type) - part_ids.append(part_id) - part_color_shifts.append(part_color_shift) - - if not added_parts: - continue - - outfit.body_types_list = Outfits_pb2.BodyTypesList() - # noinspection PyUnresolvedReferences - outfit.body_types_list.body_types.extend(body_types) - outfit.parts = S4Common_pb2.IdList() - # noinspection PyUnresolvedReferences - outfit.parts.ids.extend(part_ids) - outfit.part_shifts = Outfits_pb2.ColorShiftList() - # noinspection PyUnresolvedReferences - outfit.part_shifts.color_shift.extend(part_color_shifts) - - # noinspection PyUnresolvedReferences - outfit.outfit_id = outfit_data.get('outfit_id') - # noinspection PyUnresolvedReferences - outfit.outfit_flags = outfit_data.get('outfit_flags') - # noinspection PyUnresolvedReferences - outfit.outfit_flags_high = outfit_data.get('outfit_flags_high') - outfit.title = outfit_data.get('title') - outfit.match_hair_style = outfit_data.get('match_hair_style') - outfit.created = outfit_data.get('created') - parsed_outfits.append(outfit) - - # noinspection PyUnresolvedReferences - outfits_msg.outfits.extend(parsed_outfits) - - try: - sim_info.outfits = outfits_msg.SerializeToString() - except Exception as ex: - log.format_error_with_message('An error occurred when attempting to load outfit data for Slave.', outfit_data_external=outfit_data_external, exception=ex) - - @classmethod - def _update_unlock_skills( - cls, - sim_info: SimInfo, - skills: Iterator[Skill], - sim_loading_skills: List[Dict[str, Any]] - ): - open_set = set(skills) - closed_set = set() - while open_set: - current_skill = open_set.pop() - closed_set.add(current_skill) - if not current_skill.reached_max_level: - continue - - for skill_to_unlock in current_skill.skill_unlocks_on_max: - if skill_to_unlock not in closed_set: - sim_info.commodity_tracker.add_statistic(skill_to_unlock, force_add=True) - skill_data_objects = [sdo for sdo in sim_loading_skills if sdo.get('stat_id', 0) == skill_to_unlock.guid64] - cls._load_commodity_tracker_data(sim_info, skill_data_objects) - open_set.add(skill_to_unlock) - - @classmethod - def _load_commodity_tracker_data( - cls, - sim_info: SimInfo, - statistics_data: List[Dict[str, Any]], - skip_load=False, - update_affordance_cache=True - ): - commodity_tracker = sim_info.commodity_tracker - statistic_manager = CommonResourceUtils.get_instance_manager(Types.STATISTIC) - try: - commodity_tracker.load_in_progress = True - owner_lod = commodity_tracker._owner.lod if isinstance(commodity_tracker._owner, SimInfo) else None - for statistic_data in statistics_data: - stat_id = statistic_data.get('stat_id', 0) - if stat_id == 0: - continue - stat_value = statistic_data.get('stat_value', 0) - commodity_class = statistic_manager.get(stat_id) - if commodity_class is None: - log.format_with_message('Trying to load unavailable STATISTIC resource', skill_id=stat_id) - continue - elif not commodity_class.persisted: - log.format_with_message('Trying to load unavailable STATISTIC resource', skill_id=stat_id) - continue - elif commodity_tracker.statistics_to_skip_load is not None and commodity_class in commodity_tracker.statistics_to_skip_load: - continue - elif commodity_class.is_skill and stat_value == commodity_class.initial_value: - continue - elif skip_load and commodity_class.remove_on_convergence: - log.format_with_message('Not loading skill because load is not required.', commodity_class=commodity_class) - continue - elif not commodity_tracker._should_add_commodity_from_gallery(commodity_class, skip_load): - continue - elif owner_lod is not None and owner_lod < commodity_class.min_lod_value: - if commodity_class.min_lod_value >= SimInfoLODLevel.ACTIVE: - if commodity_tracker._delayed_active_lod_statistics is None: - commodity_tracker._delayed_active_lod_statistics = list() - commodity_tracker._delayed_active_lod_statistics.append((stat_id, stat_value)) - commodity_tracker.set_value(commodity_class, stat_value, from_load=True) - # if commodity_class.is_commodity: - # stat = commodity_tracker.get_statistic(commodity_class) - # if stat is not None: - # stat.force_apply_buff_on_start_up = data.apply_buff_on_start_up - # if data.buff_reason.hash: - # stat.force_buff_reason = Localization_pb2.LocalizedString() - # stat.force_buff_reason.MergeFrom(data.buff_reason) - # stat.load_time_of_last_value_change(data) - # elif commodity_class.is_ranked: - # stat = commodity_tracker.get_statistic(commodity_class) - # if stat is not None: - # stat._initial_loots_awarded = data.initial_loots_awarded - # stat._inclusive_rank_threshold = data.inclusive_rank_threshold - # stat.set_level_and_rank() - # stat.highest_level = data.highest_level - # stat.load_time_of_last_value_change(data) - # stat.fixup_callbacks_during_load() - continue - else: - commodity_tracker.set_value(commodity_class, stat_value, from_load=True) - # if commodity_class.is_commodity: - # stat = commodity_tracker.get_statistic(commodity_class) - # if stat is not None: - # stat.force_apply_buff_on_start_up = data.apply_buff_on_start_up - # if data.buff_reason.hash: - # stat.force_buff_reason = Localization_pb2.LocalizedString() - # stat.force_buff_reason.MergeFrom(data.buff_reason) - # stat.load_time_of_last_value_change(data) - # elif commodity_class.is_ranked: - # stat = commodity_tracker.get_statistic(commodity_class) - # if stat is not None: - # stat._initial_loots_awarded = data.initial_loots_awarded - # stat._inclusive_rank_threshold = data.inclusive_rank_threshold - # stat.set_level_and_rank() - # stat.highest_level = data.highest_level - # stat.load_time_of_last_value_change(data) - # stat.fixup_callbacks_during_load() - continue - finally: - commodity_tracker.statistics_to_skip_load = None - commodity_tracker.load_in_progress = False - if update_affordance_cache: - commodity_tracker.update_affordance_caches() - - @classmethod - def _load_appearance_data( - cls, - sim_info: SimInfo, - sim_appearance_data: Dict[str, Any] - ): - appearance_tracker = sim_info.appearance_tracker - for appearance_item_data in sim_appearance_data.get('appearance_items', tuple()): - guid = appearance_item_data.get('guid', None) - if guid is None: - continue - seed = appearance_item_data.get('seed', None) - if seed is None: - continue - appearance_tracker.add_persistent_appearance_modifier_data(guid, seed) - - @classmethod - def _load_suntan_data( - cls, - sim_info: SimInfo, - sim_suntan_data: Dict[str, Any] - ): - suntan_tracker = sim_info._suntan_tracker - suntan_tracker._tan_level = sim_suntan_data.get('tan_level', 0) - - suntan_parts = sim_suntan_data.get('suntan_parts', tuple()) - if suntan_parts: - if suntan_tracker._outfit_part_data_list is None: - suntan_tracker._outfit_part_data_list = [] - else: - suntan_tracker._outfit_part_data_list.clear() - - for part_data in suntan_parts: - part_id = part_data.get('part_id', None) - if part_id is None: - continue - body_type_value = part_data.get('body_type', None) - if body_type_value is None: - continue - body_type = CommonCASUtils.convert_value_to_body_type(body_type_value) - suntan_tracker._outfit_part_data_list.append((part_id, body_type)) - - @classmethod - def _load_trait_statistic_data( - cls, - sim_info: SimInfo, - sim_statistic_data: Dict[str, Any] - ): - trait_statistic_tracker = sim_info.trait_statistic_tracker - if trait_statistic_tracker._statistics is None: - return None - trait_statistic_data = dict() - trait_statistics = list() - for statistic in sorted(list(trait_statistic_tracker._statistics.values()), key=lambda x: x.guid64 if x is not None and hasattr(x, 'guid64') else 0): - stat_data = dict() - stat_id = statistic.guid64 - if stat_id is None or stat_id == 0: - continue - stat_data['stat_id'] = stat_id - stat_data['stat_value'] = statistic.get_value() - stat_data['stat_state'] = statistic._state.name - if statistic._neglect_buff_index is not None: - stat_data['neglect_buff_index'] = statistic._neglect_buff_index - stat_data['value_added'] = statistic._value_added - if statistic._max_daily_cap is not None: - stat_data['max_daily_cap'] = statistic._max_daily_cap - if statistic._min_daily_cap is not None: - stat_data['min_daily_cap'] = statistic._min_daily_cap - trait_statistics.append(stat_data) - if trait_statistics: - trait_statistic_data['trait_statistics'] = trait_statistics - if not trait_statistic_data: - return None - - statistic_manager = CommonResourceUtils.get_instance_manager(Types.STATISTIC) - for trait_statistic_data in sim_statistic_data.get('trait_statistics', tuple()): - stat_id = trait_statistic_data.get('stat_id', None) - if stat_id is None: - continue - stat_value = trait_statistic_data.get('stat_value', None) - if stat_value is None: - continue - statistic_type = statistic_manager.get(stat_id) - if statistic_type is None: - continue - trait_state_name = trait_statistic_data.get('stat_state', None) - if trait_state_name is None: - continue - trait_state = CommonResourceUtils.get_enum_by_name(trait_state_name, TraitStatisticStates, default_value=None) - if trait_state is None: - continue - if trait_statistic_tracker.owner.lod >= statistic_type.min_lod_value: - stat: TraitStatistic = trait_statistic_tracker.add_statistic(statistic_type, from_load=True) - if stat is None: - continue - stat.set_value(stat_value, ignore_caps=True) - stat._state = trait_state - neglect_buff_index = trait_statistic_data.get('neglect_buff_index', None) - if neglect_buff_index is not None: - stat._neglect_buff_index = neglect_buff_index - if stat._state >= TraitStatisticStates.UNLOCKED: - # noinspection PyUnresolvedReferences - trait_data = stat.trait_data - else: - # noinspection PyUnresolvedReferences - trait_data = stat.opposing_trait_data - try: - neglect_buff_data = trait_data.neglect_buffs[stat._neglect_buff_index] - stat._neglect_buff_handle = stat.tracker.owner.add_buff(neglect_buff_data.buff_type, buff_reason=neglect_buff_data.buff_reason) - except Exception as ex: - log.format_error_with_message(f'Stat: {stat} Current State: {stat._state} should not have neglect buff index set: {stat._neglect_buff_index}', exception=ex, throw=False) - stat._neglect_buff_index = None - stat._value_added = trait_statistic_data.get('value_added', 0) - max_daily_cap = trait_statistic_data.get('max_daily_cap', None) - if max_daily_cap is not None: - stat._max_daily_cap = max_daily_cap - min_daily_cap = trait_statistic_data.get('min_daily_cap', None) - if min_daily_cap is not None: - stat._min_daily_cap = min_daily_cap - - stat.startup_statistic(from_load=True) - # noinspection PyUnresolvedReferences - if stat._state >= TraitStatisticStates.UNLOCKED: - # noinspection PyUnresolvedReferences - if not stat.tracker.owner.has_trait(stat.trait_data.trait): - # noinspection PyUnresolvedReferences - stat.tracker.owner.add_trait(stat.trait_data.trait) - # noinspection PyUnresolvedReferences - elif stat._state <= TraitStatisticStates.OPPOSING_UNLOCKED and not stat.tracker.owner.has_trait(stat.opposing_trait_data.trait): - # noinspection PyUnresolvedReferences - stat.tracker.owner.add_trait(stat.opposing_trait_data.trait) - - if statistic_type.min_lod_value == SimInfoLODLevel.ACTIVE: - if trait_statistic_tracker._delayed_active_lod_statistics is None: - trait_statistic_tracker._delayed_active_lod_statistics = list() - trait_statistic_tracker._delayed_active_lod_statistics.append((stat_id, stat_value)) - - elif statistic_type.min_lod_value == SimInfoLODLevel.ACTIVE: - if trait_statistic_tracker._delayed_active_lod_statistics is None: - trait_statistic_tracker._delayed_active_lod_statistics = list() - trait_statistic_tracker._delayed_active_lod_statistics.append((stat_id, stat_value)) - - @classmethod - def _load_statistic_data( - cls, - sim_info: SimInfo, - sim_statistic_data: Dict[str, Any], - skip_load: bool - ): - statistic_tracker = sim_info.statistic_tracker - try: - statistics_manager = CommonResourceUtils.get_instance_manager(Types.STATISTIC) - owner_lod = statistic_tracker._owner.lod if isinstance(statistic_tracker._owner, SimInfo) else None - for statistics_data in sim_statistic_data.get('statistics', tuple()): - stat_id = statistics_data.get('stat_id', None) - if stat_id is None: - continue - stat_value = statistics_data.get('stat_value', None) - stat_cls = statistics_manager.get(stat_id) - if stat_cls is not None: - if not statistic_tracker._should_add_commodity_from_gallery(stat_cls, skip_load): - continue - elif not stat_cls.persisted: - continue - elif statistic_tracker.statistics_to_skip_load is not None and stat_cls in statistic_tracker.statistics_to_skip_load: - continue - elif owner_lod is not None and owner_lod < stat_cls.min_lod_value: - if stat_cls.min_lod_value == SimInfoLODLevel.ACTIVE: - if statistic_tracker._delayed_active_lod_statistics is None: - statistic_tracker._delayed_active_lod_statistics = list() - statistic_tracker._delayed_active_lod_statistics.append((stat_id, stat_value)) - if stat_value is not None: - statistic_tracker.set_value(stat_cls, stat_value, from_load=True) - else: - if statistic_tracker._statistics is None: - statistic_tracker._statistics = {} - if stat_cls not in statistic_tracker._statistics: - statistic_tracker._statistics[stat_cls] = None - log.format_with_message('Trying to load unavailable STATISTIC resource', stat_id=stat_id) - else: - if stat_value is not None: - statistic_tracker.set_value(stat_cls, stat_value, from_load=True) - else: - if statistic_tracker._statistics is None: - statistic_tracker._statistics = {} - if stat_cls not in statistic_tracker._statistics: - statistic_tracker._statistics[stat_cls] = None - log.format_with_message('Trying to load unavailable STATISTIC resource', stat_id=stat_id) - else: - log.format_with_message('Trying to load unavailable STATISTIC resource', stat_id=stat_id) - finally: - statistic_tracker.statistics_to_skip_load = None - statistic_tracker.check_for_unneeded_initial_statistics() - - @classmethod - def _load_commodity_data( - cls, - sim_info: SimInfo, - sim_commodity_data: Dict[str, Any], - skip_load: bool - ): - commodity_tracker = sim_info.commodity_tracker - - cls._load_commodity_tracker_data(sim_info, sim_commodity_data.get('commodities', tuple()), skip_load=skip_load, update_affordance_cache=False) - if sim_info.lod > SimInfoLODLevel.BASE: - for commodity in tuple(commodity_tracker): - if commodity.has_auto_satisfy_value(): - commodity.set_to_auto_satisfy_value() - cls._load_commodity_tracker_data(sim_info, sim_commodity_data.get('other_statistics', tuple()), update_affordance_cache=False) - cls._load_commodity_tracker_data(sim_info, sim_commodity_data.get('skills', tuple()), update_affordance_cache=False) - cls._load_commodity_tracker_data(sim_info, sim_commodity_data.get('ranked_statistics', tuple()), update_affordance_cache=True) - - @classmethod - def _load_occult_data( - cls, - sim_info: SimInfo, - sim_occult_data: Dict[str, Any] - ): - occult_tracker = sim_info._occult_tracker - occult_types_list = sim_occult_data.get('occult_types', tuple()) - occult_types = None - for occult_type_value in occult_types_list: - vanilla_occult_type = cls._to_occult_type(occult_type_value) - if vanilla_occult_type is None: - continue - if occult_types is None: - occult_types = vanilla_occult_type - else: - occult_types = CommonBitwiseUtils.add_flags(occult_types, vanilla_occult_type) - - occult_tracker._sim_info.occult_types = occult_types or OccultType.HUMAN - - current_occult_types_list = sim_occult_data.get('current_occult_types', tuple()) - current_occult_types = None - for current_occult_type_value in current_occult_types_list: - vanilla_current_occult_type = cls._to_occult_type(current_occult_type_value) - if vanilla_current_occult_type is None: - continue - if current_occult_types is None: - current_occult_types = vanilla_current_occult_type - else: - current_occult_types = CommonBitwiseUtils.add_flags(occult_types, vanilla_current_occult_type) - - occult_tracker._sim_info.current_occult_types = current_occult_types or OccultType.HUMAN - - pending_occult_type_value = sim_occult_data.get('pending_occult_type', None) - - if pending_occult_type_value is not None: - pending_occult_type = cls._to_occult_type(pending_occult_type_value) - if pending_occult_type is not None: - occult_tracker._pending_occult_type = pending_occult_type - - occult_tracker._occult_form_available = sim_occult_data.get('occult_form_available', True) - - occult_data_map = dict() - for (occult_type_str, occult_type_data) in sim_occult_data.get('occult_info_by_occult_type', dict()).items(): - if occult_type_str is None: - continue - occult_type = cls._to_occult_type(occult_type_str) - if occult_type is None: - continue - - occult_type_data['occult_type'] = occult_type - - occult_data_map[occult_type] = occult_type_data - - for occult_type in OccultType: - if occult_type != OccultType.HUMAN and occult_type not in occult_tracker.OCCULT_DATA: - occult_tracker._sim_info.occult_types &= ~occult_type - if occult_tracker._sim_info.current_occult_types == occult_type: - occult_tracker._sim_info.current_occult_types = OccultType.HUMAN - if occult_tracker._pending_occult_type == occult_type: - occult_tracker._pending_occult_type = None - elif occult_type in occult_data_map: - sim_info_occult_data = occult_data_map[occult_type] - occult_tracker_sim_info = occult_tracker._generate_sim_info(sim_info_occult_data.get('occult_type'), generate_new=False) - outfits_data = sim_info_occult_data.get('occult_outfit_data', None) - physical_attributes = sim_info_occult_data.get('occult_physical_attributes', None) - if occult_type == occult_tracker._sim_info.current_occult_types: - if outfits_data is not None: - cls._load_outfit_data(sim_info, outfits_data) - if physical_attributes is not None: - cls._load_physical_attributes(sim_info, physical_attributes) - else: - if outfits_data is not None: - cls._load_outfit_data(occult_tracker_sim_info._base, outfits_data) - if physical_attributes is not None: - cls._load_physical_attributes(occult_tracker_sim_info._base, physical_attributes) - elif occult_type != OccultType.HUMAN and occult_tracker.has_occult_type(occult_type) and occult_type == occult_tracker._sim_info.current_occult_types: - occult_tracker._generate_sim_info(occult_type, generate_new=False) - - @classmethod - def _to_occult_type(cls, value: Union[str, int]) -> Union[OccultType, None]: - if isinstance(value, str): - return CommonResourceUtils.get_enum_by_name(value, OccultType, default_value=None) - elif isinstance(value, int): - return CommonResourceUtils.get_enum_by_int_value(value, OccultType, default_value=None) - return None - - @classmethod - def _load_death_data( - cls, - sim_info: SimInfo, - sim_death_data: Dict[str, Any] - ): - death_type_str = sim_death_data.get('death_type', None) - if death_type_str is None: - return - death_type = CommonResourceUtils.get_enum_by_name(death_type_str, CommonDeathType, default_value=None) - if death_type is None: - return - death_tracker = CommonSimDeathUtils.get_death_tracker(sim_info) - death_tracker._death_type = CommonDeathType.convert_to_vanilla(death_type) - death_tracker._death_time = CommonTimeUtils.get_current_date_and_time() - - @classmethod - def _load_physical_attributes( - cls, - sim_info: SimInfo, - physical_attributes_data: Dict[str, Any] - ): - try: - physique = physical_attributes_data.get('physique', None) - if physique is not None: - sim_info.physique = physique - - facial_attributes = physical_attributes_data.get('facial_attributes', None) - if facial_attributes is not None: - cls._load_facial_attribute_data(sim_info, facial_attributes) - - sim_info.voice_pitch = physical_attributes_data.get('voice_pitch', 0) - sim_info.voice_actor = physical_attributes_data.get('voice_actor', 0) - sim_info.voice_effect = physical_attributes_data.get('voice_effect', 0) - sim_info.skin_tone = physical_attributes_data.get('skin_tone', 0) - sim_info.skin_tone_val_shift = physical_attributes_data.get('skin_tone_val_shift', 0) - - sim_info.flags = physical_attributes_data.get('flags', 0) - - pelt_layers = physical_attributes_data.get('pelt_layers', None) - if pelt_layers is not None: - cls._load_pelt_layer_data(sim_info, pelt_layers) - - base_trait_ids = physical_attributes_data.get('base_trait_ids', None) - if base_trait_ids is not None: - sim_info.base_trait_ids = list(base_trait_ids) - - genetic_data = physical_attributes_data.get('genetics_data', None) - if genetic_data is not None: - cls._load_genetics_data(sim_info, genetic_data) - except Exception as ex: - log.error('Failed to save physical attributes', exception=ex, throw=False) - - @classmethod - def _load_pelt_layer_data(cls, sim_info: SimInfo, sim_pelt_layers_data: Dict[str, Any]): - pelt_layer_data = Outfits_pb2.PeltLayerDataList() - layers = list() - for layer_data in sim_pelt_layers_data.get('layers', tuple()): - layer = Outfits_pb2.PeltLayerData() - layer.color = layer_data.get('color') - layer.layer_id = layer_data.get('layer_id') - layers.append(layer) - # noinspection PyUnresolvedReferences - pelt_layer_data.layers.extend(layers) - sim_info.pelt_layers = pelt_layer_data.SerializeToString() - - @classmethod - def _load_facial_attribute_data(cls, sim_info: SimInfo, facial_attributes_data: Dict[str, Any]): - from protocolbuffers.PersistenceBlobs_pb2 import BlobSimFacialCustomizationData - facial_attributes = BlobSimFacialCustomizationData() - - face_modifiers = list() - for face_modifier in facial_attributes_data.get('face_modifiers', tuple()): - modifier = BlobSimFacialCustomizationData().Modifier() - modifier.key = face_modifier.get('modifier_key') - modifier.amount = face_modifier.get('modifier_value') - face_modifiers.append(modifier) - - # noinspection PyUnresolvedReferences - facial_attributes.face_modifiers.extend(face_modifiers) - - body_modifiers = list() - for body_modifier in facial_attributes_data.get('body_modifiers', tuple()): - modifier = BlobSimFacialCustomizationData().Modifier() - modifier.key = body_modifier.get('modifier_key') - modifier.amount = body_modifier.get('modifier_value') - body_modifiers.append(modifier) - - # noinspection PyUnresolvedReferences - facial_attributes.body_modifiers.extend(body_modifiers) - - sculpts = list() - for sculpt in facial_attributes_data.get('sculpts', tuple()): - sculpt: int = sculpt - sculpts.append(sculpt) - - # noinspection PyUnresolvedReferences - facial_attributes.sculpts.extend(sculpts) - - sim_info.facial_attributes = facial_attributes.SerializeToString() - - @classmethod - def _load_genetics_data(cls, sim_info: SimInfo, sim_genetics_data: Dict[str, Any]): - genetic_data = Outfits_pb2.GeneticData() - - genetic_data.physique = sim_genetics_data.get('physique') - genetic_data.voice_actor = sim_genetics_data.get('voice_actor') - genetic_data.voice_pitch = sim_genetics_data.get('voice_pitch') - - from protocolbuffers.PersistenceBlobs_pb2 import BlobSimFacialCustomizationData - facial_attributes = BlobSimFacialCustomizationData() - - sculpt_and_modifiers_data = sim_genetics_data.get('sculpts_and_modifiers', dict()) - - face_modifiers = list() - # noinspection PyUnresolvedReferences - for face_modifier in sculpt_and_modifiers_data.get('face_modifiers', tuple()): - modifier = BlobSimFacialCustomizationData().Modifier() - modifier.key = face_modifier.get('modifier_key') - modifier.amount = face_modifier.get('modifier_value') - face_modifiers.append(modifier) - - # noinspection PyUnresolvedReferences - facial_attributes.face_modifiers.extend(face_modifiers) - - body_modifiers = list() - # noinspection PyUnresolvedReferences - for body_modifier in sculpt_and_modifiers_data.get('body_modifiers', tuple()): - modifier = BlobSimFacialCustomizationData().Modifier() - modifier.key = body_modifier.get('modifier_key') - modifier.amount = body_modifier.get('modifier_value') - body_modifiers.append(modifier) - - # noinspection PyUnresolvedReferences - facial_attributes.body_modifiers.extend(body_modifiers) - - sculpts = list() - # noinspection PyUnresolvedReferences - for sculpt in sculpt_and_modifiers_data.get('sculpts', tuple()): - sculpt: int = sculpt - sculpts.append(sculpt) - - # noinspection PyUnresolvedReferences - facial_attributes.sculpts.extend(sculpts) - - genetic_data.sculpts_and_mods_attr = facial_attributes.SerializeToString() - - growth_parts_items = list() - # noinspection PyUnresolvedReferences - for part in sim_genetics_data.get('growth_parts_items', tuple()): # RepeatedCompositeContainer - # noinspection PyUnresolvedReferences - part_id = part.get('part_id', None) - # noinspection PyUnresolvedReferences - part_body_type = part.get('part_body_type', None) - # noinspection PyUnresolvedReferences - part_color_shift = part.get('part_color_shift', None) - if part_id is None or part_body_type is None or part_color_shift is None: - continue - - part_item = Outfits_pb2.PartData() - part_item.id = part_id - part_item.body_type = part_body_type - part_item.color_shift = part_color_shift - growth_parts_items.append(part_item) - - genetic_data.growth_parts_list = Outfits_pb2.PartDataList() - if growth_parts_items: - # noinspection PyUnresolvedReferences - genetic_data.growth_parts_list.parts.extend(growth_parts_items) - - parts_items = list() - # noinspection PyUnresolvedReferences - for part in sim_genetics_data.get('parts_items', tuple()): # RepeatedCompositeContainer - # noinspection PyUnresolvedReferences - part_id = part.get('part_id', None) - # noinspection PyUnresolvedReferences - part_body_type = part.get('part_body_type', None) - # noinspection PyUnresolvedReferences - part_color_shift = part.get('part_color_shift', None) - if part_id is None or part_body_type is None or part_color_shift is None: - continue - - part_item = Outfits_pb2.PartData() - part_item.id = part_id - part_item.body_type = part_body_type - part_item.color_shift = part_color_shift - parts_items.append(part_item) - - genetic_data.parts_list = Outfits_pb2.PartDataList() - # noinspection PyUnresolvedReferences - genetic_data.parts_list.parts.extend(parts_items) - - sim_info.genetic_data = genetic_data.SerializeToString() - - @classmethod - def _load_pronouns_data(cls, sim_info: SimInfo, sim_pronouns_data: Dict[str, Any]): - from protocolbuffers import S4Common_pb2 - pronouns_list = S4Common_pb2.SimPronounList() - pronouns = list() - # noinspection PyUnresolvedReferences - for sim_pronoun in sim_pronouns_data.get('pronouns'): # RepeatedCompositeContainer - pronoun = SimPronoun() - pronoun.pronoun = sim_pronoun.get('pronoun') - pronoun.case = sim_pronoun.get('pronoun_case') - pronouns.append(pronoun) - - # noinspection PyUnresolvedReferences - pronouns_list.pronouns.extend(pronouns) - sim_info.pronouns = pronouns_list.SerializeToString() - - # Save - @classmethod - def _build_sim_data(cls, sim_info: SimInfo) -> Dict[str, Any]: - """build_sim_data(sim_info) - - Convert a SimInfo object into a serializable dictionary of data. - - :param sim_info: - :return: - """ - sim_save_data = dict() - sim_info._set_fit_fat() - sim_save_data['physical_attributes'] = cls._build_physical_attributes(sim_info) - - sim_save_data['first_name'] = sim_info._base.first_name - sim_save_data['last_name'] = sim_info._base.last_name - sim_save_data['breed_name'] = sim_info._base.breed_name - sim_save_data['first_name_key'] = sim_info._base.first_name_key - sim_save_data['last_name_key'] = sim_info._base.last_name_key - sim_save_data['full_name_key'] = sim_info._base.full_name_key - sim_save_data['breed_name_key'] = sim_info._base.breed_name_key - sim_save_data['gender'] = CommonGender.get_gender(sim_info).name - sim_save_data['species'] = CommonSpecies.get_species(sim_info).name - sim_save_data['age'] = CommonAge.get_age(sim_info).name - sim_save_data['custom_texture'] = sim_info._base.custom_texture - sim_save_data['pronouns_data'] = cls._build_pronouns(sim_info._base) - from objects.components.consumable_component import ConsumableComponent - sim_save_data['fat'] = sim_info.commodity_tracker.get_value(ConsumableComponent.FAT_COMMODITY) - sim_save_data['fit'] = sim_info.commodity_tracker.get_value(ConsumableComponent.FIT_COMMODITY) - - sim_save_data['lod'] = sim_info._get_persisted_lod().name - - sim_save_data['outfit_data'] = cls._build_outfit_data(sim_info._base) - - sim_save_data['occult_data'] = cls._build_occult_data(sim_info) - death_data = cls._build_death_data(sim_info) - if death_data is not None: - sim_save_data['death_data'] = death_data - - # attributes_save.genealogy_tracker = sim_info._genealogy_tracker.save_genealogy() - # attributes_save.pregnancy_tracker = sim_info._pregnancy_tracker.save() - # attributes_save.sim_careers = sim_info._career_tracker.save() - sim_save_data['trait_data'] = cls._build_trait_data(sim_info) - # for (tag, obj_id) in sim_info._autonomy_scoring_preferences.items(): - # with ProtocolBufferRollback(attributes_save.object_preferences.preferences) as entry: - # entry.tag = tag - # entry.object_id = obj_id - # for (tag, obj_id) in sim_info._autonomy_use_preferences.items(): - # with ProtocolBufferRollback(attributes_save.object_ownership.owned_object) as entry: - # entry.tag = tag - # entry.object_id = obj_id - # stored_object_info_component = cls.get_component(objects.components.types.STORED_OBJECT_INFO_COMPONENT) - # if stored_object_info_component is not None: - # attributes_save.stored_object_info_component = stored_object_info_component.get_save_data() - commodity_data = cls._build_commodity_data(sim_info) - if commodity_data is not None: - sim_save_data['commodity_data'] = commodity_data - statistics_data = cls._build_statistics_data(sim_info) - if statistics_data is not None: - sim_save_data['statistics_data'] = statistics_data - - if sim_info.is_human: - trait_statistic_data = cls._build_trait_statistic_data(sim_info) - if trait_statistic_data is not None: - sim_save_data['trait_statistic_data'] = trait_statistic_data - sim_save_data['suntan_data'] = cls._build_suntan_data(sim_info) - - # if sim_info._familiar_tracker is not None: - # attributes_save.familiar_tracker = sim_info._familiar_tracker.save() - # if sim_info._favorites_tracker is not None: - # favorites_save = sim_info._favorites_tracker.save() - # if sim_info.get_sim_instance() is None and old_attributes_save is not None: - # favorites_save.stack_favorites.extend(old_attributes_save.favorites_tracker.stack_favorites) - # attributes_save.favorites_tracker = favorites_save - # if sim_info._aspiration_tracker is not None: - # sim_info._aspiration_tracker.save(attributes_save.event_data_tracker) - # if sim_info._unlock_tracker is not None: - # attributes_save.unlock_tracker = sim_info._unlock_tracker.save_unlock() - # if sim_info._notebook_tracker is not None: - # attributes_save.notebook_tracker = sim_info._notebook_tracker.save_notebook() - # if sim_info._adventure_tracker is not None: - # attributes_save.adventure_tracker = sim_info._adventure_tracker.save() - # if sim_info._royalty_tracker is not None: - # attributes_save.royalty_tracker = sim_info._royalty_tracker.save() - # if sim_info._relic_tracker is not None: - # attributes_save.relic_tracker = sim_info._relic_tracker.save() - # if sim_info._sickness_tracker is not None: - # if sim_info._sickness_tracker.should_persist_data(): - # attributes_save.sickness_tracker = sim_info._sickness_tracker.sickness_tracker_save_data() - # if sim_info._lifestyle_brand_tracker is not None: - # attributes_save.lifestyle_brand_tracker = sim_info._lifestyle_brand_tracker.save() - # if sim_info._degree_tracker is not None: - # attributes_save.degree_tracker = sim_info._degree_tracker.save() - # if sim_info._organization_tracker is not None: - # attributes_save.organization_tracker = sim_info._organization_tracker.save() - # if sim_info._fixup_tracker is not None: - # attributes_save.fixup_tracker = sim_info._fixup_tracker.save() - - sim_save_data['appearance_data'] = cls._build_appearance_data(sim_info) - - # if sim_info._story_progression_tracker is not None: - # story_progression_data = SimObjectAttributes_pb2.PersistableStoryProgressionTracker() - # sim_info._story_progression_tracker.save(story_progression_data) - # attributes_save.story_progression_tracker = story_progression_data - # if sim_info._lunar_effect_tracker is not None and sim_info._lunar_effect_tracker.has_data_to_save: - # lunar_effect_data = SimObjectAttributes_pb2.PersistableLunarEffectTracker() - # sim_info._lunar_effect_tracker.save_lunar_effects(lunar_effect_data) - # attributes_save.lunar_effect_tracker = lunar_effect_data - - sim_save_data['age_progress'] = sim_info._age_progress.get_value() - sim_save_data['primary_aspiration'] = sim_info._primary_aspiration.guid64 if sim_info._primary_aspiration is not None else 0 - - current_outfit_info = dict() - # noinspection PyPropertyAccess - current_outfit = sim_info.get_current_outfit() - if current_outfit is None: - (outfit_type, outfit_index) = (OutfitCategory.EVERYDAY, 0) - else: - (outfit_type, outfit_index) = current_outfit - if outfit_index == SpecialOutfitIndex.DEFAULT: - previous_outfit = sim_info.get_previous_outfit() - if previous_outfit is None: - (outfit_type, outfit_index) = (OutfitCategory.EVERYDAY, 0) - else: - (outfit_type, outfit_index) = previous_outfit - if outfit_type == OutfitCategory.SPECIAL and outfit_type == OutfitCategory.BATHING: - outfit_type = OutfitCategory.EVERYDAY - outfit_index = 0 - outfit_category_tuning = OutfitTuning.OUTFIT_CATEGORY_TUNING.get(outfit_type) - outfit_type = CommonOutfitUtils.convert_value_to_outfit_category(outfit_type) - if outfit_category_tuning.save_outfit_category is None: - current_outfit_info['outfit_category'] = outfit_type.name - else: - current_outfit_info['outfit_category'] = outfit_category_tuning.save_outfit_category.name - current_outfit_info['outfit_index'] = outfit_index - sim_save_data['current_outfit_info'] = current_outfit_info - - sim_save_data['additional_bonus_days'] = sim_info._additional_bonus_days - sim_save_data['saved_at_time'] = CommonRealDateUtils.get_current_date_string() - - if sim_info._initial_fitness_value is not None: - sim_save_data['initial_fitness_value'] = sim_info._initial_fitness_value - - favorite_recipe_ids = list() - for recipe in sim_info._favorite_recipes: - favorite_recipe_ids.append(recipe.guid64) - if favorite_recipe_ids: - sim_save_data['favorite_recipe_ids'] = favorite_recipe_ids - - if sim_info._bucks_tracker is not None: - sim_save_data['bucks_data'] = cls._build_bucks_data(sim_info) - return sim_save_data - - @classmethod - def _build_facial_attributes(cls, sim_info: SimInfo) -> Dict[str, Any]: - facial_attributes_data = dict() - from protocolbuffers.PersistenceBlobs_pb2 import BlobSimFacialCustomizationData - facial_attributes = BlobSimFacialCustomizationData() - # noinspection PyPropertyAccess - facial_attributes.MergeFromString(sim_info.facial_attributes) - - face_modifiers = list() - # noinspection PyUnresolvedReferences - for face_modifier in facial_attributes.face_modifiers: - face_modifier_key = face_modifier.key - face_modifier_value = face_modifier.amount - face_modifier_data = dict() - face_modifier_data['modifier_key'] = face_modifier_key - face_modifier_data['modifier_value'] = face_modifier_value - face_modifiers.append(face_modifier_data) - facial_attributes_data['face_modifiers'] = face_modifiers - - body_modifiers = list() - # noinspection PyUnresolvedReferences - for body_modifier in facial_attributes.body_modifiers: - body_modifier_key = body_modifier.key - body_modifier_value = body_modifier.amount - body_modifier_data = dict() - body_modifier_data['modifier_key'] = body_modifier_key - body_modifier_data['modifier_value'] = body_modifier_value - body_modifiers.append(body_modifier_data) - facial_attributes_data['body_modifiers'] = body_modifiers - - sculpts = list() - # noinspection PyUnresolvedReferences - for sculpt in facial_attributes.sculpts: - sculpt: int = sculpt - sculpts.append(sculpt) - facial_attributes_data['sculpts'] = sculpts - return facial_attributes_data - - @classmethod - def _build_pronouns(cls, sim_info: SimInfo) -> Dict[str, Any]: - sim_pronouns_data = dict() - from protocolbuffers import S4Common_pb2 - pronouns_list = S4Common_pb2.SimPronounList() - pronouns_list.MergeFromString(sim_info.pronouns) - pronouns_data = list() - # noinspection PyUnresolvedReferences - for sim_pronoun in pronouns_list.pronouns: # RepeatedCompositeContainer - sim_pronoun: SimPronoun = sim_pronoun - # noinspection PyUnresolvedReferences - pronoun = sim_pronoun.pronoun - # noinspection PyUnresolvedReferences - case = sim_pronoun.case - pronoun_info = dict() - pronoun_info['pronoun'] = pronoun - pronoun_info['pronoun_case'] = case - pronouns_data.append(pronoun_info) - sim_pronouns_data['pronouns'] = pronouns_data - return sim_pronouns_data - - @classmethod - def _build_pelt_layers(cls, sim_info: SimInfo) -> Dict[str, Any]: - sim_pelt_layers_data = dict() - pelt_layer_data = Outfits_pb2.PeltLayerDataList() - # noinspection PyPropertyAccess - pelt_layer_data.MergeFromString(sim_info.pelt_layers) - pelt_layers = list() - # noinspection PyUnresolvedReferences - for layer in pelt_layer_data.layers: - layer: Outfits_pb2.PeltLayerData = layer - layer_data = dict() - # noinspection PyUnresolvedReferences - color = layer.color - # noinspection PyUnresolvedReferences - layer_id = layer.layer_id - layer_data['color'] = color - layer_data['layer_id'] = layer_id - pelt_layers.append(layer_data) - - sim_pelt_layers_data['layers'] = pelt_layers - return sim_pelt_layers_data - - @classmethod - def _build_bucks_data(cls, sim_info: SimInfo) -> Dict[str, Any]: - bucks_tracker = sim_info._bucks_tracker - sim_bucks_data = dict() - bucks_list = list() - for bucks_type in CommonBucksType.get_all(): - vanilla_bucks_type = CommonBucksType.convert_to_vanilla(bucks_type) - bucks_data = dict() - bucks_data['bucks_type'] = bucks_type.name - bucks_data['amount'] = bucks_tracker._bucks.get(vanilla_bucks_type, 0) - bucks_perk_data = list() - for (perk, perk_data) in bucks_tracker._unlocked_perks[vanilla_bucks_type].items(): - unlocked_perks_data = dict() - unlocked_perks_data['perk_id'] = perk.guid64 - unlocked_perks_data['currently_unlocked'] = perk_data.currently_unlocked - if perk_data.unlocked_by is not None: - unlocked_perks_data['unlock_reason'] = perk_data.unlocked_by.guid64 - if perk in bucks_tracker._inactive_perk_timers[vanilla_bucks_type]: - unlocked_perks_data['time_left'] = bucks_tracker._inactive_perk_timers[vanilla_bucks_type][perk] - bucks_perk_data.append(unlocked_perks_data) - bucks_data['perk_data'] = bucks_perk_data - bucks_list.append(bucks_data) - sim_bucks_data['bucks'] = bucks_list - return sim_bucks_data - - @classmethod - def _build_appearance_data(cls, sim_info: SimInfo) -> Dict[str, Any]: - appearance_tracker = sim_info.appearance_tracker - appearance_data = dict() - appearance_items = list() - for (guid, seed) in sorted(list(appearance_tracker._persisted_appearance_data.items()), key=lambda x: x[0]): - appearance_item_data = dict() - appearance_item_data['guid'] = guid - appearance_item_data['seed'] = seed - appearance_items.append(appearance_item_data) - appearance_data['appearance_items'] = appearance_items - return appearance_data - - @classmethod - def _build_suntan_data(cls, sim_info: SimInfo) -> Dict[str, Any]: - suntan_tracker = sim_info._suntan_tracker - suntan_data = dict() - suntan_parts = list() - suntan_data['tan_level'] = suntan_tracker._tan_level - if suntan_tracker._outfit_part_data_list is not None: - for (part_id, body_type) in suntan_tracker._outfit_part_data_list: - part_tan_data = dict() - part_tan_data['part_id'] = part_id - part_tan_data['body_type'] = int(body_type) - suntan_parts.append(part_tan_data) - suntan_data['suntan_parts'] = suntan_parts - return suntan_data - - @classmethod - def _build_trait_statistic_data(cls, sim_info: SimInfo) -> Union[Dict[str, Any], None]: - trait_statistic_tracker = sim_info.trait_statistic_tracker - if trait_statistic_tracker._statistics is None: - return None - trait_statistic_data = dict() - trait_statistics = list() - for statistic in sorted(list(trait_statistic_tracker._statistics.values()), key=lambda x: x.guid64 if x is not None and hasattr(x, 'guid64') else 0): - stat_data = dict() - stat_id = statistic.guid64 - if stat_id is None or stat_id == 0: - continue - stat_data['stat_id'] = stat_id - stat_data['stat_value'] = statistic.get_value() - stat_data['stat_state'] = statistic._state.name - if statistic._neglect_buff_index is not None: - stat_data['neglect_buff_index'] = statistic._neglect_buff_index - stat_data['value_added'] = statistic._value_added - if statistic._max_daily_cap is not None: - stat_data['max_daily_cap'] = statistic._max_daily_cap - if statistic._min_daily_cap is not None: - stat_data['min_daily_cap'] = statistic._min_daily_cap - trait_statistics.append(stat_data) - if trait_statistics: - trait_statistic_data['trait_statistics'] = trait_statistics - if not trait_statistic_data: - return None - return trait_statistic_data - - @classmethod - def _build_statistics_data(cls, sim_info: SimInfo) -> Union[Dict[str, Any], None]: - statistics_tracker = sim_info.statistic_tracker - statistics_tracker.check_for_unneeded_initial_statistics() - if statistics_tracker._statistics is None: - return None - statistics_data = dict() - stat_list = list() - for (stat_type, stat) in sorted(list(statistics_tracker._statistics.items()), key=lambda x: x[0].guid64 if x[0] is not None and hasattr(x[0], 'guid64') else 0): - if not stat_type.persisted: - continue - try: - if stat is None or not hasattr(stat_type, 'guid64'): - continue - stat_id = stat_type.guid64 - if stat_id is None or stat_id == 0: - continue - current_value = stat.get_saved_value() - stat_data = dict() - stat_data['stat_id'] = stat_id - stat_data['stat_value'] = current_value - stat_list.append(stat_data) - except Exception as ex: - log.error(f'thrown while trying to save stat {stat}', exception=ex, throw=False) - continue - if not stat_list: - return None - statistics_data['statistics'] = stat_list - return statistics_data - - @classmethod - def _build_commodity_data(cls, sim_info: SimInfo) -> Union[Dict[str, Any], None]: - sim_commodity_data = dict() - commodities = list() - skills = list() - ranked_statistics = list() - other_statistics = list() - commodity_tracker = sim_info.commodity_tracker - - for stat in sorted(list(commodity_tracker._statistics_values_gen()), key=lambda x: x.guid64 if x is not None and hasattr(x, 'guid64') else 0): - if not stat.persisted: - continue - - stat_id = stat.guid64 - if stat_id is None or stat_id == 0: - continue - current_value = stat.get_saved_value() - statistic_data = dict() - statistic_data['stat_id'] = stat_id - statistic_data['stat_value'] = current_value - - if stat.is_skill or isinstance(stat, Skill) or isinstance(stat, LifeSkillStatistic): - # noinspection PyUnresolvedReferences - if hasattr(stat, 'initial_value') and current_value == stat.initial_value: - continue - skills.append(statistic_data) - continue - - if stat.is_commodity or isinstance(stat, Commodity): - commodities.append(statistic_data) - continue - - if stat.is_ranked or isinstance(stat, RankedStatistic): - ranked_statistics.append(statistic_data) - continue - - other_statistics.append(statistic_data) - - if commodities: - sim_commodity_data['commodities'] = commodities - if skills: - sim_commodity_data['skills'] = skills - if ranked_statistics: - sim_commodity_data['ranked_statistics'] = ranked_statistics - if other_statistics: - sim_commodity_data['other_statistics'] = other_statistics - - if not sim_commodity_data: - return None - return sim_commodity_data - - @classmethod - def _build_trait_data(cls, sim_info: SimInfo) -> Union[Dict[str, Any], None]: - trait_tracker = sim_info._trait_tracker - trait_ids = [trait.guid64 for trait in trait_tracker._equipped_traits if trait.persistable] - if trait_tracker._delayed_active_lod_traits is not None: - trait_ids.extend(trait.guid64 for trait in trait_tracker._delayed_active_lod_traits) - trait_data = dict() - trait_data['trait_ids'] = trait_ids - return trait_data - - @classmethod - def _build_death_data(cls, sim_info: SimInfo) -> Union[Dict[str, Any], None]: - death_type = CommonSimDeathUtils.get_death_type(sim_info) - if death_type == CommonDeathType.NONE: - return None - sim_death_data = dict() - sim_death_data['death_type'] = death_type.name - return sim_death_data - - @classmethod - def _build_occult_data(cls, sim_info: SimInfo) -> Dict[str, Any]: - sim_occult_data = dict() - occult_tracker = sim_info._occult_tracker - occult_tracker_sim_info = occult_tracker._sim_info - sim_occult_types = occult_tracker_sim_info.occult_types - occult_types = list() - for occult_type_val in OccultType.list_values_from_flags(sim_occult_types): - occult_type_type = CommonResourceUtils.get_enum_by_int_value(int(occult_type_val), OccultType, default_value=None) - if occult_type_type is None or not hasattr(occult_type_type, 'name'): - continue - occult_types.append(occult_type_type.name) - sim_occult_data['occult_types'] = occult_types - current_occult_types = list() - for current_occult_type_val in OccultType.list_values_from_flags(occult_tracker_sim_info.current_occult_types): - current_occult_type_type = CommonResourceUtils.get_enum_by_int_value(int(current_occult_type_val), OccultType, default_value=None) - if current_occult_type_type is None or not hasattr(current_occult_type_type, 'name'): - continue - current_occult_types.append(current_occult_type_type.name) - sim_occult_data['current_occult_types'] = current_occult_types - occult_form_available = occult_tracker._occult_form_available - sim_occult_data['occult_form_available'] = occult_form_available - if occult_tracker._pending_occult_type is not None: - pending_occult_type = occult_tracker._pending_occult_type - if pending_occult_type is not None and pending_occult_type != 0: - pending_occult_type_type = CommonResourceUtils.get_enum_by_int_value(int(pending_occult_type), OccultType, default_value=None) - if pending_occult_type_type is not None and hasattr(pending_occult_type_type, 'name'): - sim_occult_data['pending_occult_type'] = pending_occult_type_type.name - - sim_occult_types_data = dict() - for (occult_type, occult_sim_info) in occult_tracker._sim_info_map.items(): - occult_type_type = CommonResourceUtils.get_enum_by_int_value(int(occult_type), OccultType, default_value=None) - if occult_type_type is None or not hasattr(occult_type_type, 'name'): - continue - occult_type_data = dict() - occult_tracker._copy_shared_attributes(sim_info, occult_type, occult_tracker._sim_info, occult_tracker._sim_info.current_occult_types) - occult_type_data['occult_type'] = occult_type_type.name - occult_type_data['occult_outfit_data'] = cls._build_outfit_data(occult_sim_info._base) - occult_type_data['occult_physical_attributes'] = cls._build_physical_attributes(occult_sim_info) - sim_occult_types_data[occult_type_type.name] = occult_type_data - sim_occult_data['occult_info_by_occult_type'] = sim_occult_types_data - return sim_occult_data - - @classmethod - def _build_outfit_data(cls, sim_info: SimInfo) -> Dict[str, Any]: - outfits_msg = Outfits_pb2.OutfitList() - outfits_msg.ParseFromString(sim_info.outfits) - - outfits_by_category = dict() - # noinspection PyUnresolvedReferences - for outfit in outfits_msg.outfits: # RepeatedCompositeContainer - outfit: Outfits_pb2.OutfitData = outfit - # noinspection PyUnresolvedReferences - category: OutfitCategory = CommonOutfitUtils.convert_value_to_outfit_category(outfit.category) - if not isinstance(category, OutfitCategory): - continue - if category.name not in outfits_by_category: - outfits_by_category[category.name] = list() - outfits_list = outfits_by_category[category.name] - outfit_data = dict() - # noinspection PyUnresolvedReferences - body_types_list: Outfits_pb2.BodyTypesList = outfit.body_types_list - # noinspection PyUnresolvedReferences - body_types = body_types_list.body_types - # noinspection PyUnresolvedReferences - parts: S4Common_pb2.IdList = outfit.parts - # noinspection PyUnresolvedReferences - part_ids = parts.ids - part_data_list = list() - # noinspection PyUnresolvedReferences - part_shifts: Outfits_pb2.ColorShiftList = outfit.part_shifts - # noinspection PyUnresolvedReferences - part_shift_colors = part_shifts.color_shift - parts_info = zip(body_types, part_ids, part_shift_colors) - for (body_type, part_id, part_color_shift) in parts_info: - part_data = dict() - part_data['body_type'] = body_type - part_data['part_id'] = part_id - part_data['part_color_shift'] = part_color_shift - part_data_list.append(part_data) - - outfit_data['part_data_list'] = part_data_list - # noinspection PyUnresolvedReferences - outfit_id: int = outfit.outfit_id - # noinspection PyUnresolvedReferences - outfit_flags: int = outfit.outfit_flags - # noinspection PyUnresolvedReferences - outfit_flags_high: int = outfit.outfit_flags_high - # noinspection PyUnresolvedReferences - title: str = outfit.title - # noinspection PyUnresolvedReferences - match_hair_style: bool = outfit.match_hair_style - # noinspection PyUnresolvedReferences - created: int = outfit.created - outfit_data['outfit_id'] = outfit_id - outfit_data['category'] = category.name - outfit_data['outfit_flags'] = outfit_flags - outfit_data['outfit_flags_high'] = outfit_flags_high - outfit_data['title'] = title - outfit_data['match_hair_style'] = match_hair_style - outfit_data['created'] = created - outfit_data['outfit_index'] = len(outfits_list) - outfits_list.append(outfit_data) - outfits_by_category[category.name] = outfits_list - return outfits_by_category - - @classmethod - def _build_physical_attributes(cls, sim_info: SimInfo) -> Dict[str, Any]: - physical_attributes_data = dict() - # noinspection PyPropertyAccess - physical_attributes_data['physique'] = sim_info.physique - - # noinspection PyPropertyAccess - physical_attributes_data['voice_pitch'] = sim_info.voice_pitch - # noinspection PyPropertyAccess - physical_attributes_data['voice_actor'] = sim_info.voice_actor - # noinspection PyPropertyAccess - physical_attributes_data['voice_effect'] = sim_info.voice_effect - # noinspection PyPropertyAccess - physical_attributes_data['skin_tone'] = sim_info.skin_tone - # noinspection PyPropertyAccess - physical_attributes_data['skin_tone_val_shift'] = sim_info.skin_tone_val_shift - - physical_attributes_data['facial_attributes'] = cls._build_facial_attributes(sim_info) - - physical_attributes_data['flags'] = sim_info.flags - if hasattr(sim_info, 'pelt_layers'): - physical_attributes_data['pelt_layers'] = cls._build_pelt_layers(sim_info) - - if hasattr(sim_info, 'base_trait_ids'): - # originally a tuple, convert it to a tuple when setting it! - physical_attributes_data['base_trait_ids'] = sorted(list(sim_info.base_trait_ids), key=lambda x: x) - - physical_attributes_data['genetics_data'] = cls._build_genetics_data(sim_info) - return physical_attributes_data - - @classmethod - def _build_genetics_data(cls, sim_info: SimInfo) -> Dict[str, Any]: - sim_genetics_data = dict() - genetic_data = Outfits_pb2.GeneticData() - # noinspection PyPropertyAccess - genetic_data.MergeFromString(sim_info.genetic_data) - # noinspection PyUnresolvedReferences - growth_parts_list: Outfits_pb2.PartDataList = genetic_data.growth_parts_list - # noinspection PyUnresolvedReferences - parts_list: Outfits_pb2.PartDataList = genetic_data.parts_list - # noinspection PyUnresolvedReferences - physique: str = genetic_data.physique - sculpts_and_modifier_data = dict() - from protocolbuffers.PersistenceBlobs_pb2 import BlobSimFacialCustomizationData - facial_attributes = BlobSimFacialCustomizationData() - # noinspection PyUnresolvedReferences - facial_attributes.MergeFromString(genetic_data.sculpts_and_mods_attr) - - face_modifiers = list() - # noinspection PyUnresolvedReferences - for face_modifier in facial_attributes.face_modifiers: - face_modifier_key = face_modifier.key - face_modifier_value = face_modifier.amount - face_modifier_data = dict() - face_modifier_data['modifier_key'] = face_modifier_key - face_modifier_data['modifier_value'] = face_modifier_value - face_modifiers.append(face_modifier_data) - sculpts_and_modifier_data['face_modifiers'] = face_modifiers - - body_modifiers = list() - # noinspection PyUnresolvedReferences - for body_modifier in facial_attributes.body_modifiers: - body_modifier_key = body_modifier.key - body_modifier_value = body_modifier.amount - body_modifier_data = dict() - body_modifier_data['modifier_key'] = body_modifier_key - body_modifier_data['modifier_value'] = body_modifier_value - body_modifiers.append(body_modifier_data) - sculpts_and_modifier_data['body_modifiers'] = body_modifiers - - sculpts = list() - # noinspection PyUnresolvedReferences - for sculpt in facial_attributes.sculpts: - sculpt: int = sculpt - sculpts.append(sculpt) - sculpts_and_modifier_data['sculpts'] = sculpts - - sim_genetics_data['sculpts_and_modifiers'] = sculpts_and_modifier_data - - # noinspection PyUnresolvedReferences - voice_actor: int = genetic_data.voice_actor - # noinspection PyUnresolvedReferences - voice_pitch: float = genetic_data.voice_pitch - growth_parts_items = list() - # noinspection PyUnresolvedReferences - for part in growth_parts_list.parts: # RepeatedCompositeContainer - part: Outfits_pb2.PartData = part - # noinspection PyUnresolvedReferences - part_id = part.id - # noinspection PyUnresolvedReferences - part_body_type = part.body_type - # noinspection PyUnresolvedReferences - part_color_shift = part.color_shift - growth_part_item = dict() - growth_part_item['part_id'] = part_id - growth_part_item['part_body_type'] = part_body_type - growth_part_item['part_color_shift'] = part_color_shift - growth_parts_items.append(growth_part_item) - - sim_genetics_data['growth_parts_items'] = growth_parts_items - - parts_items = list() - # noinspection PyUnresolvedReferences - for part in parts_list.parts: # RepeatedCompositeContainer - part: Outfits_pb2.PartData = part - # noinspection PyUnresolvedReferences - part_id = part.id - # noinspection PyUnresolvedReferences - part_body_type = part.body_type - # noinspection PyUnresolvedReferences - part_color_shift = part.color_shift - part_item = dict() - part_item['part_id'] = part_id - part_item['part_body_type'] = part_body_type - part_item['part_color_shift'] = part_color_shift - parts_items.append(part_item) - sim_genetics_data['parts_items'] = parts_items - - sim_genetics_data['physique'] = physique - sim_genetics_data['voice_actor'] = voice_actor - sim_genetics_data['voice_pitch'] = voice_pitch - return sim_genetics_data - - @classmethod - def despawn_sim( - cls, - sim_info: SimInfo, - source: str = None, - cause: str = None, - **kwargs - ) -> bool: - """despawn_sim(sim_info, source=None, cause=None, **kwargs) - - Despawn a Sim. - - :param sim_info: The Sim to despawn. - :type sim_info: SimInfo - :param source: The source of the destruction. Default is None. - :type source: str, optional - :param cause: The cause of the destruction. Default is None. - :type cause: str, optional - :return: True, if the Sim was despawn successfully. False, if not. - :rtype: bool - """ - if sim_info is None: - return False - from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return True - cause = cause or 'Sim despawned.' - if cls.hard_reset(sim_info, reset_reason=ResetReason.BEING_DESTROYED, source=cls, cause='S4CL Despawn'): - sim.destroy(source=source, cause=cause, **kwargs) - return True - - @classmethod - def schedule_sim_for_despawn( - cls, - sim_info: SimInfo, - source: str = None, - cause: str = None, - on_despawn: Callable[[], None] = None, - **kwargs - ) -> bool: - """schedule_sim_for_despawn(sim_info, source=None, cause=None, on_despawn=None, **kwargs) - - Schedule a Sim to be despawned. - - :param sim_info: The Sim to despawn. - :type sim_info: SimInfo - :param source: The source of the destruction. Default is None. - :type source: str, optional - :param cause: The cause of the destruction. Default is None. - :type cause: str, optional - :param on_despawn: A callback that occurs after the Sim is despawned. Default is None. - :type on_despawn: Callable[[], None], optional - :return: True, if the Object was successfully scheduled for destruction. False, if not. - :rtype: bool - """ - if sim_info is None: - return False - from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - if on_despawn is not None: - on_despawn() - return True - cause = cause or 'Sim despawned.' - sim.schedule_destroy_asap(post_delete_func=on_despawn, source=source, cause=cause, **kwargs) - return True - - @classmethod - def delete_sim(cls, sim_info: SimInfo, source: str = None, cause: str = None, **kwargs) -> bool: - """delete_sim(sim_info, source=None, cause=None, **kwargs) - - Delete a Sim. - - :param sim_info: The Sim to delete. - :type sim_info: SimInfo - :param source: The source of the destruction. Default is None. - :type source: str, optional - :param cause: The cause of the destruction. Default is None. - :type cause: str, optional - :return: True, if the Sim was deleted successfully. False, if not. - :rtype: bool - """ - if not cls.despawn_sim(sim_info, source=source, cause=cause, **kwargs): - return False - client = services.client_manager().get_first_client() - if sim_info.household is not None and hasattr(sim_info.household, 'refresh_aging_updates'): - client.remove_selectable_sim_info(sim_info) - household = sim_info.household or CommonHouseholdUtils.create_empty_household() - sim_info.remove_permanently(household=household) - return True - - @classmethod - def soft_reset( - cls, - sim_info: SimInfo, - reset_reason: ResetReason = ResetReason.RESET_EXPECTED, - hard_reset_on_exception: bool = False, - source: Any = None, - cause: str = 'S4CL Soft Reset' - ) -> bool: - """soft_reset(\ - sim_info,\ - reset_reason=ResetReason.RESET_EXPECTED,\ - hard_reset_on_exception=False,\ - source=None,\ - cause='S4CL Soft Reset'\ - ) - - Perform a soft reset on a Sim. - - :param sim_info: An instance of an Sim. - :type sim_info: SimInfo - :param reset_reason: The reason for the reset. Default is ResetReason.RESET_EXPECTED. - :type reset_reason: ResetReason, optional - :param hard_reset_on_exception: If set to True, a hard reset of the Object will be attempted upon an error occurring.\ - If set to False, nothing will occur if the reset failed. Default is False. - :type hard_reset_on_exception: bool, optional - :param source: The source of the reset. Default is the GameObject. - :type source: Any, optional - :param cause: Text indicating the cause of the reset. Default is 'S4CL Hard Reset'. - :type cause: str, optional - :return: True, if the reset was successful. False, if not. - :rtype: bool - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return True - # noinspection PyBroadException - try: - # noinspection PyArgumentList - if sim._should_be_swimming() or _buildbuy.is_location_pool(services.current_zone_id(), sim.position, sim.location.level): - posture_type = posture_graph.SIM_SWIM_POSTURE_TYPE - else: - posture_type = posture_graph.SIM_DEFAULT_POSTURE_TYPE - - if sim.queue is not None: - for interaction in sim.queue: - interaction.cancel(FinishingType.KILLED, '{} sim.queue'.format(cause)) - sim.queue.on_reset() - sim.queue.unlock() - - if sim.si_state is not None: - for interaction in sim.si_state: - interaction.cancel(FinishingType.KILLED, '{} sim.si_state'.format(cause)) - # noinspection PyBroadException - try: - sim.si_state.on_reset() - except: - sim._si_state = SIState(sim) - sim.si_state.on_reset() - else: - sim._si_state = SIState(sim) - sim.si_state.on_reset() - - if sim.ui_manager is not None: - sim.ui_manager.remove_all_interactions() - - sim.socials_locked = False - sim.last_affordance = None - sim.two_person_social_transforms.clear() - sim.on_reset_send_op(reset_reason) - # noinspection PyPropertyAccess - if sim.posture_state is not None: - # noinspection PyPropertyAccess - posture_state = sim.posture_state - if posture_state._primitive is not None: - # noinspection PyPropertyAccess - posture_state._primitive._prev_posture = None - # noinspection PyPropertyAccess - posture_state.on_reset(reset_reason) - - sim._stop_animation_interaction() - sim.asm_auto_exit.clear() - sim._start_animation_interaction() - from postures.posture_specs import get_origin_spec - # noinspection PyBroadException - try: - sim.posture_state = PostureState(sim, None, get_origin_spec(posture_type), {PostureSpecVariable.HAND: (Hand.LEFT,)}) - except: - sim.posture_state = PostureState(sim, None, get_origin_spec(posture_graph.SIM_DEFAULT_POSTURE_TYPE), {PostureSpecVariable.HAND: (Hand.LEFT,)}) - - sim._posture_target_refs.clear() - sim.run_full_autonomy_next_ping() - return True - except: - if hard_reset_on_exception: - return cls.hard_reset(sim_info, reset_reason, source=source, cause=cause) - return False - - @classmethod - def hard_reset( - cls, - sim_info: SimInfo, - reset_reason: ResetReason = ResetReason.RESET_EXPECTED, - source: Any = None, - cause: str = 'S4CL Hard Reset' - ) -> bool: - """hard_reset( - sim_info,\ - reset_reason=ResetReason.RESET_EXPECTED,\ - source=None,\ - cause='S4CL Hard Reset'\ - ) - - Perform a hard reset on a SimInfo. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param reset_reason: The reason for the reset. Default is ResetReason.RESET_EXPECTED. - :type reset_reason: ResetReason, optional - :param source: The source of the reset. Default is None. - :type source: Any, optional - :param cause: Text indicating the cause of the reset. Default is 'S4CL Hard Reset'. - :type cause: str, optional - :return: True, if the reset was successful. False, if not. - :rtype: bool - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return True - - # noinspection PyBroadException - try: - sim.reset(reset_reason, source=source or sim_info, cause=cause) - return True - except: - return False - - @classmethod - def fade_in( - cls, - sim_info: SimInfo, - fade_duration: float = 1.0, - immediate: bool = False, - additional_channels: Iterator[Tuple[int, int, int]] = None - ): - """fade_in(sim_info, fade_duration=1.0, immediate=False, additional_channels=None) - - Fade a Sim to become visible. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param fade_duration: The number of milliseconds the fade effect should take to complete. Default is 1.0. - :type fade_duration: float, optional - :param immediate: If set to True, fade in will occur immediately. Default is False. - :type immediate: bool, optional - :param additional_channels: A collection of additional channels. The order of the inner tuple is Manager Id, Sim Id, and Mask. Default is None. - :type additional_channels: Iterator[Tuple[int, int, int]], optional - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return - sim.fade_in(fade_duration=fade_duration, immediate=immediate, additional_channels=additional_channels) - - @classmethod - def fade_out( - cls, - sim_info: SimInfo, - fade_duration: float = 1.0, - immediate: bool = False, - additional_channels: Iterator[Tuple[int, int, int]] = None - ): - """fade_out(sim_info, fade_duration=1.0, immediate=False, additional_channels=None) - - Fade a Sim to become invisible. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param fade_duration: The number of milliseconds the fade effect should take to complete. Default is 1.0. - :type fade_duration: float, optional - :param immediate: If set to True, fade out will occur immediately. Default is False. - :type immediate: bool, optional - :param additional_channels: A collection of additional channels. The order of the inner tuple is Manager Id, Sim Id, and Mask. Default is None. - :type additional_channels: Iterator[Tuple[int, int, int]], optional - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return - sim.fade_out(fade_duration=fade_duration, immediate=immediate, additional_channels=additional_channels) - - -@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.spawn_sims', 'Spawn Sims of a certain species, gender, and age.', command_arguments=( - CommonConsoleCommandArgument('species', 'CommonSpecies', - f'The spawned Sims will have this species. Valid species include: {CommonSpecies.get_comma_separated_names_string()}', is_optional=False), - CommonConsoleCommandArgument('count', 'Number', 'The number of Sims to spawn.', is_optional=True, default_value=1), - CommonConsoleCommandArgument('gender', 'CommonGender', - f'The spawned Sims will have this gender. Valid genders include: {CommonGender.get_comma_separated_names_string()}', is_optional=True, default_value=CommonGender.MALE.name if hasattr(CommonGender.MALE, 'name') else CommonGender.MALE), - CommonConsoleCommandArgument('age', 'CommonAge', - f'The spawned Sims will have this age. Valid ages include: {CommonAge.get_comma_separated_names_string()}', is_optional=True, default_value=CommonAge.ADULT.name if hasattr(CommonAge.ADULT, 'name') else CommonAge.ADULT) -)) -def _s4cl_spawn_sims(output: CommonConsoleCommandOutput, species: CommonSpecies, count: int = 1, gender: CommonGender = CommonGender.MALE, age: CommonAge = CommonAge.ADULT): - if species is None: - return - if gender == CommonGender.INVALID or not isinstance(gender, CommonGender): - output(f'ERROR: {gender} is not a valid gender. Valid Genders: ({CommonGender.get_comma_separated_names_string()})') - return - if age == CommonAge.INVALID or not isinstance(age, CommonAge): - output(f'ERROR: {age} is not a valid age. Valid Ages: ({CommonAge.get_comma_separated_names_string()})') - return - if count <= 0: - output('ERROR: Please enter a count above zero.') - return - output(f'Spawning {count} {species.name} Sim(s) of Gender: {gender.name} and Age: {age.name}.') - try: - active_sim_info = CommonSimUtils.get_active_sim_info() - active_sim_location = CommonSimLocationUtils.get_location(active_sim_info) - for x in range(count): - created_sim_info = CommonSimSpawnUtils.create_sim_info(species, gender=gender, age=age) - CommonSimSpawnUtils.spawn_sim(created_sim_info, location=active_sim_location) - except Exception as ex: - CommonExceptionHandler.log_exception(ModInfo.get_identity(), f'Error spawning Sims {count} Sim(s) of Species: {species.name}, Gender: {gender.name}, and Age: {age.name}.', exception=ex) - output('An error occurred while spawning Sim(s).') - output(f'Done Spawning {count} {species.name} Sim(s) of Gender: {gender.name} and Age: {age.name}.') - output('If the space around your Sim was too crowded for a new Sim to spawn, you may locate the spawned Sim(s) in front of the lot.') - - -@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.spawn_human_sims', 'Spawn Human Sims of a certain gender and age.', command_arguments=( - CommonConsoleCommandArgument('count', 'Number', 'The number of Sims to spawn.', is_optional=True, default_value=1), - CommonConsoleCommandArgument('gender', 'CommonGender', - f'The spawned Sims will have this gender. Valid genders include: {CommonGender.get_comma_separated_names_string()}', is_optional=True, default_value=CommonGender.MALE.name if hasattr(CommonGender.MALE, 'name') else CommonGender.MALE), - CommonConsoleCommandArgument('age', 'CommonAge', - f'The spawned Sims will have this age. Valid ages include: {CommonAge.get_comma_separated_names_string()}', is_optional=True, default_value=CommonAge.ADULT.name if hasattr(CommonAge.ADULT, 'name') else CommonAge.ADULT) -)) -def _s4cl_spawn_human_sims(output: CommonConsoleCommandOutput, count: int = 1, gender: CommonGender = CommonGender.MALE, age: CommonAge = CommonAge.ADULT): - return _s4cl_spawn_sims(output, CommonSpecies.HUMAN, count=count, gender=gender, age=age) - - -@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.spawn_large_dog_sims', 'Spawn Large Dog Sims of a certain gender and age.', command_arguments=( - CommonConsoleCommandArgument('count', 'Number', 'The number of Sims to spawn.', is_optional=True, default_value=1), - CommonConsoleCommandArgument('gender', 'CommonGender', - f'The spawned Sims will have this gender. Valid genders include: {CommonGender.get_comma_separated_names_string()}', is_optional=True, default_value=CommonGender.MALE.name if hasattr(CommonGender.MALE, 'name') else CommonGender.MALE), - CommonConsoleCommandArgument('age', 'CommonAge', - f'The spawned Sims will have this age. Valid ages include: {CommonAge.get_comma_separated_names_string()}', is_optional=True, default_value=CommonAge.ADULT.name if hasattr(CommonAge.ADULT, 'name') else CommonAge.ADULT) -)) -def _s4cl_spawn_large_dog_sims(output: CommonConsoleCommandOutput, count: int = 1, gender: CommonGender = CommonGender.MALE, age: CommonAge = CommonAge.ADULT): - return _s4cl_spawn_sims(output, CommonSpecies.LARGE_DOG, count=count, gender=gender, age=age) - - -@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.spawn_small_dog_sims', 'Spawn Small Dog Sims of a certain gender and age.', command_arguments=( - CommonConsoleCommandArgument('count', 'Number', 'The number of Sims to spawn.', is_optional=True, default_value=1), - CommonConsoleCommandArgument('gender', 'CommonGender', - f'The spawned Sims will have this gender. Valid genders include: {CommonGender.get_comma_separated_names_string()}', is_optional=True, default_value=CommonGender.MALE.name if hasattr(CommonGender.MALE, 'name') else CommonGender.MALE), - CommonConsoleCommandArgument('age', 'CommonAge', - f'The spawned Sims will have this age. Valid ages include: {CommonAge.get_comma_separated_names_string()}', is_optional=True, default_value=CommonAge.ADULT.name if hasattr(CommonAge.ADULT, 'name') else CommonAge.ADULT) -)) -def _s4cl_spawn_small_dog_sims(output: CommonConsoleCommandOutput, count: int = 1, gender: CommonGender = CommonGender.MALE, age: CommonAge = CommonAge.ADULT): - return _s4cl_spawn_sims(output, CommonSpecies.SMALL_DOG, count=count, gender=gender, age=age) - - -@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.spawn_cat_sims', 'Spawn Cat Sims of a certain gender and age.', command_arguments=( - CommonConsoleCommandArgument('count', 'Number', 'The number of Sims to spawn.', is_optional=True, default_value=1), - CommonConsoleCommandArgument('gender', 'CommonGender', - f'The spawned Sims will have this gender. Valid genders include: {CommonGender.get_comma_separated_names_string()}', is_optional=True, default_value=CommonGender.MALE.name if hasattr(CommonGender.MALE, 'name') else CommonGender.MALE), - CommonConsoleCommandArgument('age', 'CommonAge', - f'The spawned Sims will have this age. Valid ages include: {CommonAge.get_comma_separated_names_string()}', is_optional=True, default_value=CommonAge.ADULT.name if hasattr(CommonAge.ADULT, 'name') else CommonAge.ADULT) -)) -def _s4cl_spawn_cat_sims(output: CommonConsoleCommandOutput, count: int = 1, gender: CommonGender = CommonGender.MALE, age: CommonAge = CommonAge.ADULT): - return _s4cl_spawn_sims(output, CommonSpecies.CAT, count=count, gender=gender, age=age) - - -@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.spawn_fox_sims', 'Spawn Fox Sims of a certain gender and age.', command_arguments=( - CommonConsoleCommandArgument('count', 'Number', 'The number of Sims to spawn.', is_optional=True, default_value=1), - CommonConsoleCommandArgument('gender', 'CommonGender', - f'The spawned Sims will have this gender. Valid genders include: {CommonGender.get_comma_separated_names_string()}', is_optional=True, default_value=CommonGender.MALE.name if hasattr(CommonGender.MALE, 'name') else CommonGender.MALE), - CommonConsoleCommandArgument('age', 'CommonAge', - f'The spawned Sims will have this age. Valid ages include: {CommonAge.get_comma_separated_names_string()}', is_optional=True, default_value=CommonAge.ADULT.name if hasattr(CommonAge.ADULT, 'name') else CommonAge.ADULT) -)) -def _s4cl_spawn_fox_sims(output: CommonConsoleCommandOutput, count: int = 1, gender: CommonGender = CommonGender.MALE, age: CommonAge = CommonAge.ADULT): - return _s4cl_spawn_sims(output, CommonSpecies.FOX, count=count, gender=gender, age=age) - - -@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.spawn_horse_sims', 'Spawn Horse Sims of a certain gender and age.', command_arguments=( - CommonConsoleCommandArgument('count', 'Number', 'The number of Sims to spawn.', is_optional=True, default_value=1), - CommonConsoleCommandArgument('gender', 'CommonGender', - f'The spawned Sims will have this gender. Valid genders include: {CommonGender.get_comma_separated_names_string()}', is_optional=True, default_value=CommonGender.MALE.name if hasattr(CommonGender.MALE, 'name') else CommonGender.MALE), - CommonConsoleCommandArgument('age', 'CommonAge', - f'The spawned Sims will have this age. Valid ages include: {CommonAge.get_comma_separated_names_string()}', is_optional=True, default_value=CommonAge.ADULT.name if hasattr(CommonAge.ADULT, 'name') else CommonAge.ADULT) -)) -def _s4cl_spawn_horse_sims(output: CommonConsoleCommandOutput, count: int = 1, gender: CommonGender = CommonGender.MALE, age: CommonAge = CommonAge.ADULT): - return _s4cl_spawn_sims(output, CommonSpecies.HORSE, count=count, gender=gender, age=age) - - -@CommonConsoleCommand(ModInfo.get_identity(), 's4clib.spawn_random_sims', 'Spawn a random number of Sims.', command_arguments=( - CommonConsoleCommandArgument('count', 'Number', 'The number of Sims to spawn.', is_optional=True, default_value=5), -)) -def _s4clib_spawn_random_sims(output: CommonConsoleCommandOutput, count: int = 5): - _s4cl_spawn_human_sims(output, count=count, gender=CommonGender.MALE, age=CommonAge.TODDLER) - _s4cl_spawn_human_sims(output, count=count, gender=CommonGender.MALE, age=CommonAge.CHILD) - _s4cl_spawn_human_sims(output, count=count, gender=CommonGender.MALE, age=CommonAge.ADULT) - - _s4cl_spawn_human_sims(output, count=count, gender=CommonGender.FEMALE, age=CommonAge.TODDLER) - _s4cl_spawn_human_sims(output, count=count, gender=CommonGender.FEMALE, age=CommonAge.CHILD) - _s4cl_spawn_human_sims(output, count=count, gender=CommonGender.FEMALE, age=CommonAge.ADULT) - - _s4cl_spawn_large_dog_sims(output, count=count, gender=CommonGender.MALE, age=CommonAge.CHILD) - _s4cl_spawn_large_dog_sims(output, count=count, gender=CommonGender.MALE, age=CommonAge.ADULT) - - _s4cl_spawn_large_dog_sims(output, count=count, gender=CommonGender.FEMALE, age=CommonAge.CHILD) - _s4cl_spawn_large_dog_sims(output, count=count, gender=CommonGender.FEMALE, age=CommonAge.ADULT) - - _s4cl_spawn_small_dog_sims(output, count=count, gender=CommonGender.MALE, age=CommonAge.CHILD) - _s4cl_spawn_small_dog_sims(output, count=count, gender=CommonGender.MALE, age=CommonAge.ADULT) - - _s4cl_spawn_small_dog_sims(output, count=count, gender=CommonGender.FEMALE, age=CommonAge.CHILD) - _s4cl_spawn_small_dog_sims(output, count=count, gender=CommonGender.FEMALE, age=CommonAge.ADULT) - - _s4cl_spawn_cat_sims(output, count=count, gender=CommonGender.MALE, age=CommonAge.CHILD) - _s4cl_spawn_cat_sims(output, count=count, gender=CommonGender.MALE, age=CommonAge.ADULT) - - _s4cl_spawn_cat_sims(output, count=count, gender=CommonGender.FEMALE, age=CommonAge.CHILD) - _s4cl_spawn_cat_sims(output, count=count, gender=CommonGender.FEMALE, age=CommonAge.ADULT) - - _s4cl_spawn_fox_sims(output, count=count, gender=CommonGender.MALE, age=CommonAge.ADULT) - _s4cl_spawn_fox_sims(output, count=count, gender=CommonGender.FEMALE, age=CommonAge.ADULT) - - _s4cl_spawn_horse_sims(output, count=count, gender=CommonGender.MALE, age=CommonAge.CHILD) - _s4cl_spawn_horse_sims(output, count=count, gender=CommonGender.FEMALE, age=CommonAge.ADULT) - - -@CommonConsoleCommand(ModInfo.get_identity(), 's4clib_testing.spawn_sims', 'Spawn a number of Sims of each species.', command_arguments=( - CommonConsoleCommandArgument('count', 'Number', 'The number of Sims to spawn.', is_optional=True, default_value=1), - CommonConsoleCommandArgument('gender', 'CommonGender', - f'The spawned Sims will have this gender. Valid genders include: {CommonGender.get_comma_separated_names_string()}', is_optional=True, default_value=CommonGender.MALE.name if hasattr(CommonGender.MALE, 'name') else CommonGender.MALE), - CommonConsoleCommandArgument('age', 'CommonAge', - f'The spawned Sims will have this age. Valid ages include: {CommonAge.get_comma_separated_names_string()}', is_optional=True, default_value=CommonAge.ADULT.name if hasattr(CommonAge.ADULT, 'name') else CommonAge.ADULT) -)) -def _s4clib_spawn_random_sims(output: CommonConsoleCommandOutput, count: int = 1, gender: CommonGender = CommonGender.MALE, age: CommonAge = CommonAge.ADULT): - for species in CommonSpecies.get_all(): - _s4cl_spawn_sims(output, species=species, count=count, gender=gender, age=age) - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.purge_self', - 'Delete the active Sim. WARNING: Not recommended in single Sim households, since you cannot do interactions without an active Sim!' -) -def _s4cl_purge_self(output: CommonConsoleCommandOutput): - active_sim_info = CommonSimUtils.get_active_sim_info() - output(f'Purging the active Sim ({active_sim_info}) from existence.') - return CommonSimSpawnUtils.delete_sim(active_sim_info) - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.purge_sim', - 'Purge a Sim, essentially deleting them.', - command_arguments=( - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to purge.', is_optional=False), - ) -) -def _s4cl_purge_sim(output: CommonConsoleCommandOutput, sim_info: SimInfo): - if sim_info is None: - return - if sim_info is CommonSimUtils.get_active_sim_info(): - output('Failed, If you want to purge the active Sim, use "s4clib.purge_self" instead.') - return - output(f'Purging Sim from existence {sim_info}') - CommonSimSpawnUtils.delete_sim(sim_info, source='Player', cause='Command Purged') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.be_alone', - 'Purge all Sims except the active Sim from the neighborhood.' -) -def _s4cl_be_alone(output: CommonConsoleCommandOutput): - active_sim_info = CommonSimUtils.get_active_sim_info() - output('Purging everyone but your active Sim.') - sim_count = 0 - sim_info_list = tuple(CommonSimUtils.get_sim_info_for_all_sims_generator()) - for sim_info in sim_info_list: - if sim_info is active_sim_info: - continue - CommonSimSpawnUtils.delete_sim(sim_info, source='Player', cause='Command Purged') - sim_count += 1 - output(f'Purged {sim_count} Sims') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.purge_neighborhood', - 'Purge all Sims including the active Sim from the neighborhood, essentially making your neighborhood a ghost town. WARNING: Only use this for fun, since you cannot do interactions without an active Sim!' -) -def _s4cl_purge_neighborhood(output: CommonConsoleCommandOutput): - output('Purging all Sims') - sim_count = 0 - sim_info_list = tuple(CommonSimUtils.get_sim_info_for_all_sims_generator()) - for sim_info in sim_info_list: - CommonSimSpawnUtils.delete_sim(sim_info, source='Player', cause='Command Purged') - sim_count += 1 - output(f'Purged {sim_count} Sims') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.purge_non_household', - 'Purge all Sims outside of the active household.' -) -def _s4cl_purge_non_household(output: CommonConsoleCommandOutput): - output('Purging all Sims outside of the Active Household.') - sim_count = 0 - sim_info_list = tuple(CommonSimUtils.get_sim_info_for_all_sims_generator()) - from s4ap.sims4communitylib.utils.sims.common_household_utils import CommonHouseholdUtils - for sim_info in sim_info_list: - if CommonHouseholdUtils.is_part_of_active_household(sim_info): - continue - CommonSimSpawnUtils.delete_sim(sim_info, source='Player', cause='Command Purged') - sim_count += 1 - output(f'Purged {sim_count} Sims') diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_spell_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_spell_utils.py deleted file mode 100644 index 6e37472..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_spell_utils.py +++ /dev/null @@ -1,302 +0,0 @@ -""" -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 -""" -from typing import Union, Tuple - -from server_commands.argument_helpers import TunableInstanceParam -from sims.sim_info import SimInfo -from sims4.resources import Types -from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ - CommonConsoleCommandArgument -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils -from spells.spells import Spell - - -class CommonSimSpellUtils: - """Utilities for unlocking and locking things, usually learned things such as Spells. """ - @classmethod - def add_spell(cls, sim_info: SimInfo, spell: Union[int, Spell], mark_as_new: bool = True) -> CommonExecutionResult: - """add_spell(sim_info, spell, mark_as_new=True) - - Make a Sim learn a Spell. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param spell: The spell to add. - :type spell: Union[int, Spell] - :param mark_as_new: Set True to mark the Spell as being new. Set False to refrain from marking the spell as new. Default is True. - :type mark_as_new: bool, optional - :return: The result of executing the function. True, if successful. False, if not. - :rtype: CommonExecutionResult - """ - return cls.add_spells(sim_info, (spell,), mark_as_new=mark_as_new) - - @classmethod - def add_spells(cls, sim_info: SimInfo, spells: Tuple[Union[int, Spell]], mark_as_new: bool = True) -> CommonExecutionResult: - """add_spells(sim_info, spells, mark_as_new=True) - - Make a Sim learn Spells. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param spells: A collection of spells to add. - :type spells: Tuple[Union[int, Spell]] - :param mark_as_new: Set True to mark the Spells as being new. Set False to refrain from marking the spells as new. Default is True. - :type mark_as_new: bool, optional - :return: The result of executing the function. True, if successful. False, if not. - :rtype: CommonExecutionResult - """ - from s4ap.sims4communitylib.utils.sims.common_sim_unlock_utils import CommonSimUnlockUtils - unlock_tracker = CommonSimUnlockUtils.get_unlock_tracker(sim_info) - if unlock_tracker is None: - return CommonExecutionResult(False, reason=f'Failed to locate the unlock tracker for {sim_info}') - for spell in spells: - spell_id = spell - spell = cls.load_spell_by_id(spell) - if spell is None: - return CommonExecutionResult(False, reason=f'Spell not found by id {spell_id}.') - unlock_tracker.add_unlock(spell, None, mark_as_new=mark_as_new) - return CommonExecutionResult.TRUE - - @classmethod - def add_all_spells(cls, sim_info: SimInfo) -> CommonExecutionResult: - """add_all_spells(sim_info) - - Make a Sim learn all Spells. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of executing the function. True, if successful. False, if not. - :rtype: CommonExecutionResult - """ - from s4ap.sims4communitylib.utils.sims.common_sim_unlock_utils import CommonSimUnlockUtils - unlock_tracker = CommonSimUnlockUtils.get_unlock_tracker(sim_info) - if unlock_tracker is None: - return CommonExecutionResult(False, reason=f'Failed to locate the unlock tracker for {sim_info}') - spells: Tuple[Spell] = tuple(CommonResourceUtils.load_all_instance_values(Types.SPELL, return_type=Spell)) - return cls.add_spells(sim_info, spells) - - @classmethod - def remove_spell(cls, sim_info: SimInfo, spell: Union[int, Spell]) -> CommonExecutionResult: - """remove_spell(sim_info, spell) - - Make a Sim unlearn a Spell. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param spell: The spell to remove. - :type spell: Union[int, Spell] - :return: The result of executing the function. True, if successful. False, if not. - :rtype: CommonExecutionResult - """ - return cls.remove_spells(sim_info, (spell,)) - - @classmethod - def remove_spells(cls, sim_info: SimInfo, spells: Tuple[Union[int, Spell]]) -> CommonExecutionResult: - """remove_spells(sim_info, spells) - - Make a Sim unlearn Spells. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param spells: A collection of spells to remove. - :type spells: Tuple[Union[int, Spell]] - :return: The result of executing the function. True, if successful. False, if not. - :rtype: CommonExecutionResult - """ - from s4ap.sims4communitylib.utils.sims.common_sim_unlock_utils import CommonSimUnlockUtils - unlock_tracker = CommonSimUnlockUtils.get_unlock_tracker(sim_info) - if unlock_tracker is None: - return CommonExecutionResult(False, reason=f'Failed to locate the unlock tracker for {sim_info}') - for spell in spells: - spell_id = spell - spell = cls.load_spell_by_id(spell) - if spell is None: - return CommonExecutionResult(False, reason=f'Spell not found by id {spell_id}.') - found_unlock = None - for unlock in unlock_tracker._unlocks: - if unlock.tuning_class == spell: - found_unlock = unlock - break - if not found_unlock: - return CommonExecutionResult(False, reason=f'Sim did not have spell {spell} unlocked.') - unlock_tracker._unlocks.remove(found_unlock) - if spell in unlock_tracker._marked_new_unlocks: - unlock_tracker._marked_new_unlocks.remove(spell) - (provided_super_affordances, provided_target_affordances) = unlock_tracker._get_provided_super_affordances_from_unlock(spell) - if provided_super_affordances: - if unlock_tracker._super_affordances_cache is not None: - for provided_super_affordance in provided_super_affordances: - if provided_super_affordance in unlock_tracker._super_affordances_cache: - unlock_tracker._super_affordances_cache.remove(provided_super_affordance) - if provided_target_affordances: - if unlock_tracker._target_provided_affordances_cache is not None: - for provided_target_affordance in provided_target_affordances: - if provided_target_affordance in unlock_tracker._target_provided_affordances_cache: - unlock_tracker._target_provided_affordances_cache.remove(provided_target_affordance) - return CommonExecutionResult.TRUE - - @classmethod - def remove_all_spells(cls, sim_info: SimInfo) -> CommonExecutionResult: - """remove_all_spells(sim_info) - - Make a Sim unlearn all Spells. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of executing the function. True, if successful. False, if not. - :rtype: CommonExecutionResult - """ - from s4ap.sims4communitylib.utils.sims.common_sim_unlock_utils import CommonSimUnlockUtils - unlock_tracker = CommonSimUnlockUtils.get_unlock_tracker(sim_info) - if unlock_tracker is None: - return CommonExecutionResult(False, reason=f'Failed to locate the unlock tracker for {sim_info}') - spells: Tuple[Spell] = tuple(CommonResourceUtils.load_all_instance_values(Types.SPELL, return_type=Spell)) - return cls.remove_spells(sim_info, spells) - - @classmethod - def load_spell_by_id(cls, spell: Union[int, Spell]) -> Union[Spell, None]: - """load_spell_by_id(spell) - - Load an instance of a Spell by its decimal identifier. - - :param spell: The identifier of a Spell. - :type spell: Union[int, CommonSpellId, Spell] - :return: An instance of a Spell matching the decimal identifier or None if not found. - :rtype: Union[Spell, None] - """ - if isinstance(spell, Spell): - return spell - # noinspection PyBroadException - try: - # noinspection PyCallingNonCallable - spell_instance = spell() - if isinstance(spell_instance, Spell): - # noinspection PyTypeChecker - return spell - except: - pass - # noinspection PyBroadException - try: - spell: int = int(spell) - except: - # noinspection PyTypeChecker - spell: Spell = spell - return spell - - from sims4.resources import Types - from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils - return CommonResourceUtils.load_instance(Types.SPELL, spell) - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.add_spell', - 'Add a Spell to a Sim.', - command_arguments=( - CommonConsoleCommandArgument('spell', 'Spell Id or Tuning Name', 'The decimal identifier or name of a spell to add.'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Id or Name of a Sim to modify.', - is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.unlock_spell', - 's4clib.learn_spell', - ) -) -def _common_add_spell( - output: CommonConsoleCommandOutput, - spell: TunableInstanceParam(Types.SPELL), - sim_info: SimInfo = None -): - output(f'Adding spell {spell} to Sim {sim_info}') - result = CommonSimSpellUtils.add_spell(sim_info, spell) - if result: - output(f'Successfully added spell {spell} to Sim {sim_info}') - else: - output(f'Failed to add spell {spell} to Sim {sim_info}. Reason: {result.reason}') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.remove_spell', - 'Remove a Spell from a Sim.', - command_arguments=( - CommonConsoleCommandArgument('spell', 'Spell Id or Tuning Name', 'The decimal identifier or name of a spell to remove.'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Id or Name of a Sim to modify.', - is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.lock_spell', - 's4clib.unlearn_spell', - ) -) -def _common_add_spell( - output: CommonConsoleCommandOutput, - spell: TunableInstanceParam(Types.SPELL), - sim_info: SimInfo = None -): - output(f'Removing spell {spell} from Sim {sim_info}') - result = CommonSimSpellUtils.remove_spell(sim_info, spell) - if result: - output(f'Successfully removed spell {spell} from Sim {sim_info}') - else: - output(f'Failed to remove spell {spell} from Sim {sim_info}. Reason: {result.reason}') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.add_all_spells', - 'Add all Spells to a Sim.', - command_arguments=( - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Id or Name of a Sim to modify.', - is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.add_spells', - 's4clib.unlock_all_spells', - 's4clib.learn_spells', - ) -) -def _common_add_all_spells( - output: CommonConsoleCommandOutput, - sim_info: SimInfo = None -): - output(f'Removing all spells to Sim {sim_info}') - result = CommonSimSpellUtils.add_all_spells(sim_info) - if result: - output(f'Successfully added all spells to Sim {sim_info}') - else: - output(f'Failed to add all spells to Sim {sim_info}. Reason: {result.reason}') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.remove_all_spells', - 'Remove all Spells from a Sim.', - command_arguments=( - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The Id or Name of a Sim to modify.', - is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.remove_spells', - 's4clib.lock_all_spells', - 's4clib.unlearn_all_spells', - ) -) -def _common_remove_all_spells( - output: CommonConsoleCommandOutput, - sim_info: SimInfo = None -): - output(f'Removing all spells from Sim {sim_info}') - result = CommonSimSpellUtils.remove_all_spells(sim_info) - if result: - output(f'Successfully removed all spells from Sim {sim_info}') - else: - output(f'Failed to remove all spells from Sim {sim_info}. Reason: {result.reason}') diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_state_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_state_utils.py deleted file mode 100644 index 8ab7670..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_state_utils.py +++ /dev/null @@ -1,104 +0,0 @@ -""" -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 -""" -import services -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.enums.buffs_enum import CommonBuffId -from s4ap.sims4communitylib.utils.sims.common_buff_utils import CommonBuffUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - - -class CommonSimStateUtils: - """Utilities for checking the state of a sim. - - """ - @staticmethod - def is_dying(sim_info: SimInfo) -> CommonTestResult: - """is_dying(sim_info) - - Determine if a Sim is currently dying. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim is dying. False, if the Sim is not dying. - :rtype: CommonTestResult - """ - return CommonBuffUtils.has_buff(sim_info, CommonBuffId.SIM_IS_DYING) - - @staticmethod - def is_wearing_towel(sim_info: SimInfo) -> CommonTestResult: - """is_wearing_towel(sim_info) - - Determine if a Sim is wearing a towel. - - ..warning:: Obsolete: Use :func:`~is_wearing_towel` in :class:`.CommonOutfitUtils` instead. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the sim is wearing a towel. False, if not. - :rtype: CommonTestResult - """ - from s4ap.sims4communitylib.utils.cas.common_outfit_utils import CommonOutfitUtils - return CommonOutfitUtils.is_wearing_towel(sim_info) - - @staticmethod - def is_in_sunlight(sim_info: SimInfo) -> bool: - """is_in_sunlight(sim_info) - - Determine if a Sim is in sunlight. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is in sunlight. False, if the Sim is not in sunlight. - :rtype: bool - """ - from s4ap.sims4communitylib.utils.common_time_utils import CommonTimeUtils - sim = CommonSimUtils.get_sim_instance(sim_info) - return CommonTimeUtils.get_time_service().is_in_sunlight(sim) - - @staticmethod - def is_leaving_zone(sim_info: SimInfo) -> bool: - """is_leaving_zone(sim_info) - - Determine if a Sim is currently leaving the zone. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is leaving the zone. False, if the Sim is not leaving the zone. - :rtype: bool - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - return sim is not None and services.sim_spawner_service().sim_is_leaving(sim) - - @staticmethod - def is_hidden(sim_info: SimInfo) -> bool: - """is_hidden(sim_info) - - Determine if a Sim is hidden. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is hidden. False, if the Sim is not hidden. - :rtype: bool - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - sim_id = CommonSimUtils.get_sim_id(sim_info) - return sim_id is None or sim is None or services.hidden_sim_service().is_hidden(sim_id) or sim.is_hidden() or sim.opacity == 0 - - @staticmethod - def is_visible(sim_info: SimInfo) -> bool: - """is_visible(sim_info) - - Determine if a Sim is visible. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is visible. False, if the Sim is not visible. - :rtype: bool - """ - return not CommonSimStateUtils.is_hidden(sim_info) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_statistic_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_statistic_utils.py deleted file mode 100644 index f166e7e..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_statistic_utils.py +++ /dev/null @@ -1,621 +0,0 @@ -""" -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 -""" -from typing import Union, Iterator - -from distributor.shared_messages import IconInfoData -from objects.components.statistic_component import StatisticComponent -from server_commands.argument_helpers import TunableInstanceParam -from sims.sim_info import SimInfo -from sims4.resources import Types -from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.enums.statistics_enum import CommonStatisticId -from s4ap.sims4communitylib.enums.types.component_types import CommonComponentType -from s4ap.sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.notifications.common_basic_notification import CommonBasicNotification -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ - CommonConsoleCommandArgument -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.common_component_utils import CommonComponentUtils -from s4ap.sims4communitylib.utils.common_log_registry import CommonLogRegistry -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from s4ap.sims4communitylib.utils.resources.common_statistic_utils import CommonStatisticUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from statistics.base_statistic import BaseStatistic - - -class CommonSimStatisticUtils(_HasS4CLClassLog): - """Utilities for manipulating the Statistics of Sims. - - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 'common_sim_statistic_utils' - - @classmethod - def has_statistic(cls, sim_info: SimInfo, statistic: Union[int, CommonStatisticId, BaseStatistic]) -> CommonTestResult: - """has_statistic(sim_info, statistic) - - Determine if a Sim has any of the specified Statistics. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :param statistic: The identifier of the statistic to check. - :type statistic: Union[int, CommonStatisticId, BaseStatistic] - :return: True, if the Sim has any of the statistics. False, if not. - :rtype: bool - """ - statistic = cls.get_statistic(sim_info, statistic, add=False) - if statistic is not None: - return CommonTestResult(True, reason=f'Sim had statistic {statistic}.') - return CommonTestResult(False, reason=f'Sim did not have statistic {statistic}.') - - @classmethod - def has_statistics(cls, sim_info: SimInfo, statistics: Iterator[Union[int, CommonStatisticId, BaseStatistic]]) -> CommonTestResult: - """has_statistics(sim_info, statistics) - - Determine if a Sim has any of the specified Statistics. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :param statistics: An iterator of identifiers for statistics to check. - :type statistics: Iterator[Union[int, CommonStatisticId, BaseStatistic]] - :return: True, if the Sim has any of the specified statistics. False, if not. - :rtype: bool - """ - for statistic in statistics: - result = cls.has_statistic(sim_info, statistic) - if result: - return result - return CommonTestResult(False, reason=f'Sim did not have any of the specified statistics.') - - # noinspection PyUnusedLocal - @classmethod - def is_statistic_locked(cls, sim_info: SimInfo, statistic: Union[int, CommonStatisticId, BaseStatistic], add_dynamic: bool=False, add: bool= False) -> CommonTestResult: - """is_statistic_locked(sim_info, statistic, add_dynamic=False, 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: The identifier of the statistic to check. - :type statistic: Union[int, CommonStatisticId, BaseStatistic] - :param add_dynamic: OBSOLETE: Add the statistic component to the Sim. This argument is no longer used and will be ignored. - :type add_dynamic: bool, optional - :param add: Whether or not to add the statistic to the Sim. - :type add: bool, optional - :return: The result of checking if the statistic is locked or not. True, if the statistic is locked. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - cls.get_log().format_with_message('sim_info was None!', statistic=statistic, sim=sim_info) - return CommonTestResult(False, reason='sim_info was None.') - statistic_id = CommonStatisticUtils.get_statistic_id(statistic) - if statistic_id is None: - cls.get_log().format_with_message('No statistic found when checking locked.', statistic=statistic, sim=sim_info) - return CommonTestResult(False, reason='The specified statistic did not exist.') - statistic_instance = cls.get_statistic(sim_info, statistic_id, add=add) - if statistic_instance is None: - cls.get_log().format_with_message('No statistic found on Sim when checking locked.', statistic=statistic, statistic_id=statistic_id, sim=sim_info) - return CommonTestResult(False, reason=f'Sim did not have statistic {statistic}.') - if sim_info.is_locked(statistic_instance): - return CommonTestResult(True, reason='Statistic is locked.') - return CommonTestResult(False, reason='Statistic is not locked.') - - @classmethod - def get_statistic_level(cls, sim_info: SimInfo, statistic: Union[int, CommonStatisticId, BaseStatistic]) -> float: - """get_statistic_level(sim_info, statistic) - - Retrieve the User Value of a Statistic for the specified Sim. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :param statistic: The identifier of the statistic to retrieve the user value of. - :type statistic: Union[int, CommonStatisticId, BaseStatistic] - :return: The value of the statistic, `-1.0` if the statistic is not found. - :rtype: float - """ - statistic_instance = cls.get_statistic(sim_info, statistic) - if statistic_instance is None: - cls.get_log().format_with_message('No statistic found on Sim when getting level.', statistic=statistic, sim=sim_info) - return -1.0 - return statistic_instance.get_user_value() - - # noinspection PyUnusedLocal - @classmethod - def get_statistic(cls, sim_info: SimInfo, statistic: Union[int, CommonStatisticId, BaseStatistic], add_dynamic: bool=False, add: bool=False) -> Union[BaseStatistic, None]: - """get_statistic(sim_info, statistic, statistic, add_dynamic=False, add=False) - - Retrieve a Statistic for the specified Sim. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :param statistic: The identifier of the statistic to retrieve of. - :type statistic: Union[int, CommonStatisticId, BaseStatistic] - :param add_dynamic: OBSOLETE: Add the statistic component to the Sim. This argument is no longer used and will be ignored. - :type add_dynamic: bool, optional - :param add: Whether or not to 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: - cls.get_log().format_with_message('sim_info was None!', statistic=statistic, sim=sim_info) - return None - statistic_instance = CommonStatisticUtils.load_statistic_by_id(statistic) - if statistic_instance is None: - cls.get_log().format_with_message('No statistic found when loading statistic by id.', statistic=statistic, sim=sim_info) - return None - if sim_info.get_tracker(statistic_instance) is None: - return None - return sim_info.get_statistic(statistic_instance, add=add) - - # noinspection PyUnusedLocal - @classmethod - def get_statistic_value(cls, sim_info: SimInfo, statistic: Union[int, CommonStatisticId, BaseStatistic], add_dynamic: bool=False, add: bool=False) -> float: - """get_statistic_value(sim_info, statistic, add_dynamic=False, 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: The identifier of the statistic to retrieve the value of. - :type statistic: Union[int, CommonStatisticId, BaseStatistic] - :param add_dynamic: OBSOLETE: Add the statistic component to the Sim. This argument is no longer used and will be ignored. - :type add_dynamic: bool, optional - :param add: Whether or not to add the statistic to the Sim. This argument is no longer used and will be ignored. - :type add: bool, optional - :return: The value of the statistic, `-1.0` if the statistic is not found. - :rtype: float - """ - if sim_info is None: - cls.get_log().format_with_message('sim_info was None!', statistic=statistic, sim=sim_info) - return -1.0 - statistic_instance = CommonStatisticUtils.load_statistic_by_id(statistic) - if statistic_instance is None: - cls.get_log().format_with_message('No statistic found on Sim when getting statistic value.', statistic=statistic, sim=sim_info) - return -1.0 - try: - if not CommonComponentUtils.has_component(sim_info, CommonComponentType.STATISTIC): - if not add: - return -1.0 - else: - CommonComponentUtils.add_dynamic_component(sim_info, CommonComponentType.STATISTIC) - statistic_component: StatisticComponent = CommonComponentUtils.get_component(sim_info, CommonComponentType.STATISTIC, add_dynamic=add_dynamic) - if statistic_component is None: - return -1.0 - return statistic_component.get_stat_value(statistic_instance) - except Exception as ex: - cls.get_log().format_error_with_message('An error occurred while getting statistic value.', sim_info=sim_info, sim_type=type(sim_info), has_get_stat_value=hasattr(sim_info, 'get_stat_value'), get_stat_value=sim_info.get_stat_value, exception=ex, update_tokens=False) - - # noinspection PyUnusedLocal - @classmethod - def set_statistic_value(cls, sim_info: SimInfo, statistic: Union[int, CommonStatisticId, BaseStatistic], value: float, add_dynamic: bool=True, add: bool=True) -> CommonExecutionResult: - """set_statistic_value(sim_info, statistic, 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: The identifier of the statistic to add a value to. - :type statistic: Union[int, CommonStatisticId, BaseStatistic] - :param value: The amount to add. - :type value: float - :param add_dynamic: OBSOLETE: Add the statistic component to the Sim. This argument is no longer used and will be ignored. - :type add_dynamic: bool, optional - :param add: Whether or not to add the statistic to the Sim. - :type add: bool, optional - :return: The result of setting the statistic value. True, if successful. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - cls.get_log().format_with_message('sim_info was None!', statistic=statistic, sim=sim_info) - return CommonExecutionResult(False, reason='sim_info was None.') - result = cls.is_statistic_locked(sim_info, statistic, add=add) - if result: - cls.get_log().format_with_message('Statistic is locked and thus cannot be set.', statistic=statistic, sim=sim_info) - return result - statistic_instance = CommonStatisticUtils.load_statistic_by_id(statistic) - if statistic_instance is None: - cls.get_log().format_with_message('No statistic found when setting value.', statistic=statistic, sim=sim_info) - return CommonExecutionResult(False, reason='The specified statistic did not exist.') - sim_info.set_stat_value(statistic_instance, value) - return CommonExecutionResult.TRUE - - # noinspection PyUnusedLocal - @classmethod - def set_statistic_level(cls, sim_info: SimInfo, statistic: Union[int, CommonStatisticId, BaseStatistic], value: float, add: bool=True) -> CommonExecutionResult: - """set_statistic_level(sim_info, statistic, value, add_dynamic=True, add=True) - - Set the Level of a Statistic for the specified Sim. - - :param sim_info: The Sim to modify. - :type sim_info: SimInfo - :param statistic: The identifier of the statistic to add a user value to. - :type statistic: Union[int, CommonStatisticId, BaseStatistic] - :param value: The level to set the statistic to. - :type value: float - :param add: Whether or not to add the statistic to the Sim. - :type add: bool, optional - :return: The result of setting the statistic level. True, if successful. False, if not successful. - :rtype: CommonExecutionResult - """ - return cls.set_statistic_user_value(sim_info, statistic, value, add=add) - - # noinspection PyUnusedLocal - @classmethod - def set_statistic_user_value(cls, sim_info: SimInfo, statistic: Union[int, CommonStatisticId, BaseStatistic], value: float, add_dynamic: bool=True, add: bool=True) -> CommonExecutionResult: - """set_statistic_user_value(sim_info, statistic, 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: The identifier of the statistic to add a user value to. - :type statistic: Union[int, CommonStatisticId, BaseStatistic] - :param value: The user value to set the statistic to. - :type value: float - :param add_dynamic: OBSOLETE: Add the statistic component to the Sim. This argument is no longer used and will be ignored. - :type add_dynamic: bool, optional - :param add: Whether or not to 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: - cls.get_log().format_with_message('sim_info was None!', statistic=statistic, sim=sim_info) - return CommonExecutionResult(False, reason='sim_info was None.') - result = cls.is_statistic_locked(sim_info, statistic, add=add) - if result: - cls.get_log().format_with_message('Statistic is locked and thus cannot be set.', statistic=statistic, sim=sim_info) - return result - statistic_instance = cls.get_statistic(sim_info, statistic, add=add) - if statistic_instance is None: - cls.get_log().format_with_message('No statistic found on Sim when setting statistic user value.', statistic=statistic, sim=sim_info) - return CommonExecutionResult(False, reason='The specified statistic did not exist.') - statistic_instance.set_user_value(value) - return CommonExecutionResult(True, reason=f'Statistic {statistic} level successfully set on Sim {sim_info}.') - - # noinspection PyUnusedLocal - @classmethod - def add_statistic_value(cls, sim_info: SimInfo, statistic: Union[int, CommonStatisticId, BaseStatistic], value: float, add_dynamic: bool=True, add: bool=True) -> CommonExecutionResult: - """add_statistic_value(sim_info, statistic, 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: The identifier of the statistic to add a value to. - :type statistic: Union[int, CommonStatisticId, BaseStatistic] - :param value: The amount to add. - :type value: float - :param add_dynamic: OBSOLETE: Add the statistic component to the Sim. This argument is no longer used and will be ignored. - :type add_dynamic: bool, optional - :param add: Whether or not to add the statistic to the Sim. - :type add: bool, optional - :return: The result of setting the statistic value. True, if successful. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - return cls.set_statistic_value(sim_info, statistic, cls.get_statistic_value(sim_info, statistic) + value, add=add) - - @classmethod - def remove_statistic(cls, sim_info: SimInfo, statistic: Union[int, CommonStatisticId, BaseStatistic]) -> bool: - """remove_statistic(sim_info, statistic) - - Remove a Statistic from the specified Sim. - - :param sim_info: The Sim to modify. - :type sim_info: SimInfo - :param statistic: The identifier of the statistic to remove. - :type statistic: Union[int, CommonStatisticId, BaseStatistic] - :return: True, if successful. False, if not successful. - :rtype: bool - """ - if sim_info is None: - cls.get_log().format_with_message('sim_info was None!', statistic=statistic, sim=sim_info) - return False - statistic = CommonStatisticUtils.load_statistic_by_id(statistic) - if statistic is None: - cls.get_log().format_with_message('No statistic found on Sim when removing statistic.', statistic=statistic, sim=sim_info) - return True - sim_info.remove_statistic(statistic) - return True - - # noinspection PyUnusedLocal - @classmethod - def add_statistic_modifier(cls, sim_info: SimInfo, statistic: Union[int, CommonStatisticId, BaseStatistic], value: float, add_dynamic: bool=True, add: bool=True): - """add_statistic_modifier(sim_info, statistic, 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: The identifier of the statistic containing the modifier. - :type statistic: Union[int, CommonStatisticId, BaseStatistic] - :param value: The modifier to add. - :type value: float - :param add_dynamic: OBSOLETE: Add the statistic component to the Sim. This argument is no longer used and will be ignored. - :type add_dynamic: bool, optional - :param add: Whether or not to add the statistic to the Sim. - :type add: bool, optional - """ - if sim_info is None: - cls.get_log().format_with_message('sim_info was None!', statistic=statistic, sim=sim_info) - return None - statistic = CommonStatisticUtils.load_statistic_by_id(statistic) - if statistic is None: - cls.get_log().format_with_message('No statistic found on Sim.', statistic=statistic, sim=sim_info) - return None - stat = sim_info.get_statistic(statistic) - if stat is None: - return - stat.add_statistic_modifier(value) - return None - - # noinspection PyUnusedLocal - @classmethod - def remove_statistic_modifier(cls, sim_info: SimInfo, statistic: Union[int, CommonStatisticId, BaseStatistic], value: float, add_dynamic: bool=True, add: bool=True) -> bool: - """remove_statistic_modifier(sim_info, statistic, value, add_dynamic=True, add=True) - - Remove a Modifier from a Sim by value. - - :param sim_info: The Sim to modify. - :type sim_info: SimInfo - :param statistic: The identifier of the statistic to remove the modifier from. - :type statistic: Union[int, CommonStatisticId, BaseStatistic] - :param value: The modifier to remove. - :type value: float - :param add_dynamic: OBSOLETE: Add the statistic component to the Sim. This argument is no longer used and will be ignored. - :type add_dynamic: bool, optional - :param add: Whether or not to 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: - cls.get_log().format_with_message('sim_info was None!', statistic=statistic, sim=sim_info) - return False - statistic_instance = cls.get_statistic(sim_info, statistic, add=add) - if statistic_instance is None: - cls.get_log().format_with_message('No statistic found on Sim.', statistic=statistic, sim=sim_info) - return False - statistic_instance.remove_statistic_modifier(value) - return True - - @classmethod - def remove_statistic_modifier_by_handle_id(cls, sim_info: SimInfo, modifier_handle_id: int) -> bool: - """remove_statistic_modifier_by_handle_id(sim_info, modifier_handle_id) - - Remove a Statistic Modifier from a Sim by a handle id. - - :param sim_info: The Sim to modify. - :type sim_info: SimInfo - :param modifier_handle_id: The handle id for the statistic modifier being removed. - :type modifier_handle_id: int - :return: True, if the modifier was removed successfully. False, if not. - :rtype: bool - """ - if sim_info is None: - cls.get_log().format_with_message('sim_info was None!', modifier_handle=modifier_handle_id, sim=sim_info) - return False - return sim_info.remove_statistic_modifier(modifier_handle_id) - - # noinspection PyUnusedLocal - @classmethod - def remove_all_statistic_modifiers_for_statistic(cls, sim_info: SimInfo, statistic: Union[int, CommonStatisticId, BaseStatistic], add_dynamic: bool=True, add: bool=True) -> bool: - """remove_all_statistic_modifiers_for_statistic(sim_info, statistic, 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: The identifier of the statistic to remove modifiers from. - :type statistic: Union[int, CommonStatisticId, BaseStatistic] - :param add_dynamic: OBSOLETE: Add the statistic component to the Sim. This argument is no longer used and will be ignored. - :type add_dynamic: bool, optional - :param add: Whether or not to 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: - cls.get_log().format_with_message('sim_info was None!', statistic=statistic, sim=sim_info) - return False - statistic_instance = cls.get_statistic(sim_info, statistic, add=add) - if statistic_instance is None: - cls.get_log().format_with_message('No statistic found on Sim.', statistic=statistic, sim=sim_info) - return False - if not hasattr(statistic_instance, '_statistic_modifiers') or statistic_instance._statistic_modifiers is None: - return False - for value in list(statistic_instance._statistic_modifiers): - statistic_instance.remove_statistic_modifier(value) - return True - - -commands_log = CommonLogRegistry().register_log(ModInfo.get_identity(), 's4cl_statistic_commands') -commands_log.enable() - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.print_statistic_value', - 'Print the value of a statistic on a Sim.', - command_arguments=( - CommonConsoleCommandArgument('statistic', 'Statistic Id or Tuning Name', 'The tuning name or decimal identifier of a Statistic.'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to check.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.print_stat_value', - 's4clib.printstatvalue', - 's4clib.printstatisticvalue' - ) -) -def _common_print_statistic_value(output: CommonConsoleCommandOutput, statistic: TunableInstanceParam(Types.STATISTIC), sim_info: SimInfo=None): - if statistic is None: - output('ERROR: No Statistic specified or the specified Statistic did not exist!') - return - if sim_info is None: - return - output(f'Attempting to get statistic {statistic} on Sim {sim_info}.') - statistic_value = CommonSimStatisticUtils.get_statistic_value(sim_info, CommonStatisticUtils.get_statistic_id(statistic)) - output(f'Got statistic value of {statistic_value} of {statistic} on Sim {sim_info}.') - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.set_statistic_value', - 'Set the value of a statistic on a Sim.', - command_arguments=( - CommonConsoleCommandArgument('statistic', 'Statistic Id or Tuning Name', 'The tuning name or decimal identifier of a Statistic.'), - CommonConsoleCommandArgument('value', 'Decimal Number', 'The value to set the statistic to.'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to change.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.set_stat_value', - 's4clib.setstatvalue', - 's4clib.setstatisticvalue' - ) -) -def _common_set_statistic_value(output: CommonConsoleCommandOutput, statistic: TunableInstanceParam(Types.STATISTIC), value: float, sim_info: SimInfo=None): - if statistic is None: - output('ERROR: No Statistic specified or the specified Statistic did not exist!') - return - if sim_info is None: - return - output(f'Attempting to set statistic {statistic} on Sim {sim_info} to value {value}.') - if CommonSimStatisticUtils.set_statistic_value(sim_info, CommonStatisticUtils.get_statistic_id(statistic), value): - output(f'SUCCESS: Successfully set statistic {statistic} of Sim {sim_info} to value {value}.') - else: - output(f'FAILED: Failed to set statistic {statistic} of Sim {sim_info} to value {value}') - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.set_statistic_level', - 'Set the user level of a statistic on a Sim (User level should be set instead of setting value for statistics that belong to a Sim, such as Motives or Skills).', - command_arguments=( - CommonConsoleCommandArgument('statistic', 'Statistic Id or Tuning Name', 'The tuning name or decimal identifier of a Statistic.'), - CommonConsoleCommandArgument('level', 'Decimal Number', 'The level to set the statistic to.'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to change.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.set_statistic_user_value', - 's4clib.set_stat_level', - 's4clib.setstatlevel', - 's4clib.setstatisticlevel' - ) -) -def _common_set_statistic_user_value(output: CommonConsoleCommandOutput, statistic: TunableInstanceParam(Types.STATISTIC), level: float, sim_info: SimInfo=None): - if statistic is None: - output('ERROR: No Statistic specified or the specified Statistic did not exist!') - return - if sim_info is None: - return - output(f'Attempting to set statistic {statistic} on Sim {sim_info} to user level {level}.') - if CommonSimStatisticUtils.set_statistic_user_value(sim_info, statistic, level): - output(f'SUCCESS: Successfully set statistic {statistic} on Sim {sim_info} to user level {level}.') - else: - output(f'FAILED: Failed to set statistic {statistic} on Sim {sim_info} to user level {level}.') - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.print_statistic_level', - 'Print the user level of a statistic on a Sim (User level should be printed instead of the value for statistics that belong to a Sim, such as Motives or Skills).', - command_arguments=( - CommonConsoleCommandArgument('statistic', 'Statistic Id or Tuning Name', 'The tuning name or decimal identifier of a Statistic.'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to check.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.print_statistic_user_value', - 's4clib.print_stat_level', - 's4clib.printstatlevel', - 's4clib.printstatisticlevel' - ) -) -def _common_print_statistic_user_value(output: CommonConsoleCommandOutput, statistic: TunableInstanceParam(Types.STATISTIC), sim_info: SimInfo=None): - if statistic is None: - output('ERROR: No Statistic specified or the specified Statistic did not exist!') - return - if sim_info is None: - return - output(f'Attempting to print statistic {statistic} on Sim {sim_info}.') - level = CommonSimStatisticUtils.get_statistic_level(sim_info, CommonStatisticUtils.get_statistic_id(statistic)) - output(f'Got statistic level of {level} of {statistic} on Sim {sim_info}.') - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.remove_statistic', - 'Remove a Statistic or Commodity from a Sim.', - command_arguments=( - CommonConsoleCommandArgument('statistic', 'Statistic Id or Tuning Name', 'The tuning name or decimal identifier of a Statistic or Commodity.'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to change.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.remove_commodity', - 's4clib.remove_stat', - 's4clib.removestat', - 's4clib.removestatistic' - ) -) -def _common_remove_statistic(output: CommonConsoleCommandOutput, statistic: TunableInstanceParam(Types.STATISTIC), sim_info: SimInfo=None): - if statistic is None: - output('ERROR: No Statistic specified or the specified Statistic did not exist!') - return - if sim_info is None: - return - output(f'Attempting to remove statistic {statistic} from Sim {sim_info}.') - if CommonSimStatisticUtils.remove_statistic(sim_info, CommonStatisticUtils.get_statistic_id(statistic)): - output(f'SUCCESS: Successfully removed statistic {statistic} from Sim {sim_info}.') - else: - output(f'FAILED: Failed to remove statistic {statistic} from Sim {sim_info}.') - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_testing.print_static_commodities', - 'Print a list of a Static Commodities on a Sim.', - command_arguments=( - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to check.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib_testing.printstaticcommodities', - ) -) -def _common_print_static_commodities(output: CommonConsoleCommandOutput, sim_info: SimInfo=None): - log = CommonSimStatisticUtils.get_log() - try: - log.enable() - output(f'Printing static commodities of Sim {sim_info}') - text = '' - for stat in list(sim_info.static_commodity_tracker): - statistic_id = CommonStatisticUtils.get_statistic_id(stat) - text += f'{stat} ({statistic_id})\n' - sim_id = CommonSimUtils.get_sim_id(sim_info) - log.debug(f'{sim_info} Static Commodities ({sim_id})') - log.debug(text) - CommonBasicNotification( - CommonLocalizationUtils.create_localized_string(f'{sim_info} Static Commodities ({sim_id})'), - CommonLocalizationUtils.create_localized_string(text) - ).show( - icon=IconInfoData(obj_instance=CommonSimUtils.get_sim_instance(sim_info)) - ) - finally: - log.disable() diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_type_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_type_utils.py deleted file mode 100644 index 1ca927c..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_type_utils.py +++ /dev/null @@ -1,2603 +0,0 @@ -""" -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 -""" -from typing import Dict, Iterator -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.enums.common_age import CommonAge -from s4ap.sims4communitylib.enums.common_occult_type import CommonOccultType -from s4ap.sims4communitylib.enums.common_species import CommonSpecies -from s4ap.sims4communitylib.enums.sim_type import CommonSimType -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ - CommonConsoleCommandArgument -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.sims.common_occult_utils import CommonOccultUtils - - -class CommonSimTypeUtils: - """Utilities for determining the type of a Sim. i.e. Player, NPC, Service, etc. - - """ - _CHILD_DOG_SIM_TYPE_MAPPING: Dict[CommonSimType, CommonSimType] = { - CommonSimType.CHILD_SMALL_DOG: CommonSimType.CHILD_DOG, - CommonSimType.CHILD_SMALL_DOG_VAMPIRE: CommonSimType.CHILD_DOG_VAMPIRE, - CommonSimType.CHILD_SMALL_DOG_GHOST: CommonSimType.CHILD_DOG_GHOST, - CommonSimType.CHILD_SMALL_DOG_ALIEN: CommonSimType.CHILD_DOG_ALIEN, - CommonSimType.CHILD_SMALL_DOG_MERMAID: CommonSimType.CHILD_DOG_MERMAID, - CommonSimType.CHILD_SMALL_DOG_WITCH: CommonSimType.CHILD_DOG_WITCH, - CommonSimType.CHILD_SMALL_DOG_ROBOT: CommonSimType.CHILD_DOG_ROBOT, - CommonSimType.CHILD_SMALL_DOG_SCARECROW: CommonSimType.CHILD_DOG_SCARECROW, - CommonSimType.CHILD_SMALL_DOG_SKELETON: CommonSimType.CHILD_DOG_SKELETON, - CommonSimType.CHILD_SMALL_DOG_PLANT_SIM: CommonSimType.CHILD_DOG_PLANT_SIM, - CommonSimType.CHILD_SMALL_DOG_WEREWOLF: CommonSimType.CHILD_DOG_WEREWOLF, - - CommonSimType.CHILD_LARGE_DOG: CommonSimType.CHILD_DOG, - CommonSimType.CHILD_LARGE_DOG_VAMPIRE: CommonSimType.CHILD_DOG_VAMPIRE, - CommonSimType.CHILD_LARGE_DOG_GHOST: CommonSimType.CHILD_DOG_GHOST, - CommonSimType.CHILD_LARGE_DOG_ALIEN: CommonSimType.CHILD_DOG_ALIEN, - CommonSimType.CHILD_LARGE_DOG_MERMAID: CommonSimType.CHILD_DOG_MERMAID, - CommonSimType.CHILD_LARGE_DOG_WITCH: CommonSimType.CHILD_DOG_WITCH, - CommonSimType.CHILD_LARGE_DOG_ROBOT: CommonSimType.CHILD_DOG_ROBOT, - CommonSimType.CHILD_LARGE_DOG_SCARECROW: CommonSimType.CHILD_DOG_SCARECROW, - CommonSimType.CHILD_LARGE_DOG_SKELETON: CommonSimType.CHILD_DOG_SKELETON, - CommonSimType.CHILD_LARGE_DOG_PLANT_SIM: CommonSimType.CHILD_DOG_PLANT_SIM, - CommonSimType.CHILD_LARGE_DOG_WEREWOLF: CommonSimType.CHILD_DOG_WEREWOLF, - } - - _SIM_TO_SIM_TYPE_MAPPING: Dict[CommonSpecies, Dict[CommonAge, Dict[CommonOccultType, CommonSimType]]] = { - CommonSpecies.HUMAN: { - CommonAge.ELDER: { - CommonOccultType.NON_OCCULT: CommonSimType.ELDER_HUMAN, - CommonOccultType.VAMPIRE: CommonSimType.ELDER_HUMAN_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.ELDER_HUMAN_GHOST, - CommonOccultType.ALIEN: CommonSimType.ELDER_HUMAN_ALIEN, - CommonOccultType.MERMAID: CommonSimType.ELDER_HUMAN_MERMAID, - CommonOccultType.WITCH: CommonSimType.ELDER_HUMAN_WITCH, - CommonOccultType.ROBOT: CommonSimType.ELDER_HUMAN_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.ELDER_HUMAN_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.ELDER_HUMAN_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.ELDER_HUMAN_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.ELDER_HUMAN_WEREWOLF, - }, - CommonAge.ADULT: { - CommonOccultType.NON_OCCULT: CommonSimType.ADULT_HUMAN, - CommonOccultType.VAMPIRE: CommonSimType.ADULT_HUMAN_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.ADULT_HUMAN_GHOST, - CommonOccultType.ALIEN: CommonSimType.ADULT_HUMAN_ALIEN, - CommonOccultType.MERMAID: CommonSimType.ADULT_HUMAN_MERMAID, - CommonOccultType.WITCH: CommonSimType.ADULT_HUMAN_WITCH, - CommonOccultType.ROBOT: CommonSimType.ADULT_HUMAN_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.ADULT_HUMAN_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.ADULT_HUMAN_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.ADULT_HUMAN_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.ADULT_HUMAN_WEREWOLF, - }, - CommonAge.YOUNGADULT: { - CommonOccultType.NON_OCCULT: CommonSimType.YOUNG_ADULT_HUMAN, - CommonOccultType.VAMPIRE: CommonSimType.YOUNG_ADULT_HUMAN_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.YOUNG_ADULT_HUMAN_GHOST, - CommonOccultType.ALIEN: CommonSimType.YOUNG_ADULT_HUMAN_ALIEN, - CommonOccultType.MERMAID: CommonSimType.YOUNG_ADULT_HUMAN_MERMAID, - CommonOccultType.WITCH: CommonSimType.YOUNG_ADULT_HUMAN_WITCH, - CommonOccultType.ROBOT: CommonSimType.YOUNG_ADULT_HUMAN_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.YOUNG_ADULT_HUMAN_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.YOUNG_ADULT_HUMAN_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.YOUNG_ADULT_HUMAN_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.YOUNG_ADULT_HUMAN_WEREWOLF, - }, - CommonAge.TEEN: { - CommonOccultType.NON_OCCULT: CommonSimType.TEEN_HUMAN, - CommonOccultType.VAMPIRE: CommonSimType.TEEN_HUMAN_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.TEEN_HUMAN_GHOST, - CommonOccultType.ALIEN: CommonSimType.TEEN_HUMAN_ALIEN, - CommonOccultType.MERMAID: CommonSimType.TEEN_HUMAN_MERMAID, - CommonOccultType.WITCH: CommonSimType.TEEN_HUMAN_WITCH, - CommonOccultType.ROBOT: CommonSimType.TEEN_HUMAN_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.TEEN_HUMAN_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.TEEN_HUMAN_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.TEEN_HUMAN_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.TEEN_HUMAN_WEREWOLF, - }, - CommonAge.CHILD: { - CommonOccultType.NON_OCCULT: CommonSimType.CHILD_HUMAN, - CommonOccultType.VAMPIRE: CommonSimType.CHILD_HUMAN_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.CHILD_HUMAN_GHOST, - CommonOccultType.ALIEN: CommonSimType.CHILD_HUMAN_ALIEN, - CommonOccultType.MERMAID: CommonSimType.CHILD_HUMAN_MERMAID, - CommonOccultType.WITCH: CommonSimType.CHILD_HUMAN_WITCH, - CommonOccultType.ROBOT: CommonSimType.CHILD_HUMAN_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.CHILD_HUMAN_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.CHILD_HUMAN_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.CHILD_HUMAN_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.CHILD_HUMAN_WEREWOLF, - }, - CommonAge.TODDLER: { - CommonOccultType.NON_OCCULT: CommonSimType.TODDLER_HUMAN, - CommonOccultType.VAMPIRE: CommonSimType.TODDLER_HUMAN_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.TODDLER_HUMAN_GHOST, - CommonOccultType.ALIEN: CommonSimType.TODDLER_HUMAN_ALIEN, - CommonOccultType.MERMAID: CommonSimType.TODDLER_HUMAN_MERMAID, - CommonOccultType.WITCH: CommonSimType.TODDLER_HUMAN_WITCH, - CommonOccultType.ROBOT: CommonSimType.TODDLER_HUMAN_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.TODDLER_HUMAN_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.TODDLER_HUMAN_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.TODDLER_HUMAN_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.TODDLER_HUMAN_WEREWOLF, - }, - CommonAge.INFANT: { - CommonOccultType.NON_OCCULT: CommonSimType.INFANT_HUMAN, - CommonOccultType.VAMPIRE: CommonSimType.INFANT_HUMAN_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.INFANT_HUMAN_GHOST, - CommonOccultType.ALIEN: CommonSimType.INFANT_HUMAN_ALIEN, - CommonOccultType.MERMAID: CommonSimType.INFANT_HUMAN_MERMAID, - CommonOccultType.WITCH: CommonSimType.INFANT_HUMAN_WITCH, - CommonOccultType.ROBOT: CommonSimType.INFANT_HUMAN_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.INFANT_HUMAN_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.INFANT_HUMAN_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.INFANT_HUMAN_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.INFANT_HUMAN_WEREWOLF, - }, - CommonAge.BABY: { - CommonOccultType.NON_OCCULT: CommonSimType.BABY_HUMAN, - CommonOccultType.VAMPIRE: CommonSimType.BABY_HUMAN_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.BABY_HUMAN_GHOST, - CommonOccultType.ALIEN: CommonSimType.BABY_HUMAN_ALIEN, - CommonOccultType.MERMAID: CommonSimType.BABY_HUMAN_MERMAID, - CommonOccultType.WITCH: CommonSimType.BABY_HUMAN_WITCH, - CommonOccultType.ROBOT: CommonSimType.BABY_HUMAN_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.BABY_HUMAN_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.BABY_HUMAN_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.BABY_HUMAN_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.BABY_HUMAN_WEREWOLF, - } - }, - CommonSpecies.SMALL_DOG: { - CommonAge.ELDER: { - CommonOccultType.NON_OCCULT: CommonSimType.ELDER_SMALL_DOG, - CommonOccultType.VAMPIRE: CommonSimType.ELDER_SMALL_DOG_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.ELDER_SMALL_DOG_GHOST, - CommonOccultType.ALIEN: CommonSimType.ELDER_SMALL_DOG_ALIEN, - CommonOccultType.MERMAID: CommonSimType.ELDER_SMALL_DOG_MERMAID, - CommonOccultType.WITCH: CommonSimType.ELDER_SMALL_DOG_WITCH, - CommonOccultType.ROBOT: CommonSimType.ELDER_SMALL_DOG_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.ELDER_SMALL_DOG_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.ELDER_SMALL_DOG_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.ELDER_SMALL_DOG_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.ELDER_SMALL_DOG_WEREWOLF, - }, - CommonAge.ADULT: { - CommonOccultType.NON_OCCULT: CommonSimType.ADULT_SMALL_DOG, - CommonOccultType.VAMPIRE: CommonSimType.ADULT_SMALL_DOG_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.ADULT_SMALL_DOG_GHOST, - CommonOccultType.ALIEN: CommonSimType.ADULT_SMALL_DOG_ALIEN, - CommonOccultType.MERMAID: CommonSimType.ADULT_SMALL_DOG_MERMAID, - CommonOccultType.WITCH: CommonSimType.ADULT_SMALL_DOG_WITCH, - CommonOccultType.ROBOT: CommonSimType.ADULT_SMALL_DOG_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.ADULT_SMALL_DOG_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.ADULT_SMALL_DOG_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.ADULT_SMALL_DOG_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.ADULT_SMALL_DOG_WEREWOLF, - }, - CommonAge.YOUNGADULT: { - CommonOccultType.NON_OCCULT: CommonSimType.ADULT_SMALL_DOG, - CommonOccultType.VAMPIRE: CommonSimType.ADULT_SMALL_DOG_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.ADULT_SMALL_DOG_GHOST, - CommonOccultType.ALIEN: CommonSimType.ADULT_SMALL_DOG_ALIEN, - CommonOccultType.MERMAID: CommonSimType.ADULT_SMALL_DOG_MERMAID, - CommonOccultType.WITCH: CommonSimType.ADULT_SMALL_DOG_WITCH, - CommonOccultType.ROBOT: CommonSimType.ADULT_SMALL_DOG_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.ADULT_SMALL_DOG_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.ADULT_SMALL_DOG_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.ADULT_SMALL_DOG_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.ADULT_SMALL_DOG_WEREWOLF, - }, - CommonAge.TEEN: { - CommonOccultType.NON_OCCULT: CommonSimType.ADULT_SMALL_DOG, - CommonOccultType.VAMPIRE: CommonSimType.ADULT_SMALL_DOG_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.ADULT_SMALL_DOG_GHOST, - CommonOccultType.ALIEN: CommonSimType.ADULT_SMALL_DOG_ALIEN, - CommonOccultType.MERMAID: CommonSimType.ADULT_SMALL_DOG_MERMAID, - CommonOccultType.WITCH: CommonSimType.ADULT_SMALL_DOG_WITCH, - CommonOccultType.ROBOT: CommonSimType.ADULT_SMALL_DOG_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.ADULT_SMALL_DOG_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.ADULT_SMALL_DOG_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.ADULT_SMALL_DOG_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.ADULT_SMALL_DOG_WEREWOLF, - }, - CommonAge.CHILD: { - CommonOccultType.NON_OCCULT: CommonSimType.CHILD_SMALL_DOG, - CommonOccultType.VAMPIRE: CommonSimType.CHILD_SMALL_DOG_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.CHILD_SMALL_DOG_GHOST, - CommonOccultType.ALIEN: CommonSimType.CHILD_SMALL_DOG_ALIEN, - CommonOccultType.MERMAID: CommonSimType.CHILD_SMALL_DOG_MERMAID, - CommonOccultType.WITCH: CommonSimType.CHILD_SMALL_DOG_WITCH, - CommonOccultType.ROBOT: CommonSimType.CHILD_SMALL_DOG_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.CHILD_SMALL_DOG_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.CHILD_SMALL_DOG_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.CHILD_SMALL_DOG_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.CHILD_SMALL_DOG_WEREWOLF, - }, - CommonAge.TODDLER: { - CommonOccultType.NON_OCCULT: CommonSimType.CHILD_SMALL_DOG, - CommonOccultType.VAMPIRE: CommonSimType.CHILD_SMALL_DOG_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.CHILD_SMALL_DOG_GHOST, - CommonOccultType.ALIEN: CommonSimType.CHILD_SMALL_DOG_ALIEN, - CommonOccultType.MERMAID: CommonSimType.CHILD_SMALL_DOG_MERMAID, - CommonOccultType.WITCH: CommonSimType.CHILD_SMALL_DOG_WITCH, - CommonOccultType.ROBOT: CommonSimType.CHILD_SMALL_DOG_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.CHILD_SMALL_DOG_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.CHILD_SMALL_DOG_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.CHILD_SMALL_DOG_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.CHILD_SMALL_DOG_WEREWOLF, - }, - CommonAge.INFANT: { - CommonOccultType.NON_OCCULT: CommonSimType.CHILD_SMALL_DOG, - CommonOccultType.VAMPIRE: CommonSimType.CHILD_SMALL_DOG_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.CHILD_SMALL_DOG_GHOST, - CommonOccultType.ALIEN: CommonSimType.CHILD_SMALL_DOG_ALIEN, - CommonOccultType.MERMAID: CommonSimType.CHILD_SMALL_DOG_MERMAID, - CommonOccultType.WITCH: CommonSimType.CHILD_SMALL_DOG_WITCH, - CommonOccultType.ROBOT: CommonSimType.CHILD_SMALL_DOG_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.CHILD_SMALL_DOG_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.CHILD_SMALL_DOG_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.CHILD_SMALL_DOG_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.CHILD_SMALL_DOG_WEREWOLF, - }, - CommonAge.BABY: { - CommonOccultType.NON_OCCULT: CommonSimType.CHILD_SMALL_DOG, - CommonOccultType.VAMPIRE: CommonSimType.CHILD_SMALL_DOG_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.CHILD_SMALL_DOG_GHOST, - CommonOccultType.ALIEN: CommonSimType.CHILD_SMALL_DOG_ALIEN, - CommonOccultType.MERMAID: CommonSimType.CHILD_SMALL_DOG_MERMAID, - CommonOccultType.WITCH: CommonSimType.CHILD_SMALL_DOG_WITCH, - CommonOccultType.ROBOT: CommonSimType.CHILD_SMALL_DOG_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.CHILD_SMALL_DOG_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.CHILD_SMALL_DOG_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.CHILD_SMALL_DOG_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.CHILD_SMALL_DOG_WEREWOLF, - } - }, - CommonSpecies.LARGE_DOG: { - CommonAge.ELDER: { - CommonOccultType.NON_OCCULT: CommonSimType.ELDER_LARGE_DOG, - CommonOccultType.VAMPIRE: CommonSimType.ELDER_LARGE_DOG_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.ELDER_LARGE_DOG_GHOST, - CommonOccultType.ALIEN: CommonSimType.ELDER_LARGE_DOG_ALIEN, - CommonOccultType.MERMAID: CommonSimType.ELDER_LARGE_DOG_MERMAID, - CommonOccultType.WITCH: CommonSimType.ELDER_LARGE_DOG_WITCH, - CommonOccultType.ROBOT: CommonSimType.ELDER_LARGE_DOG_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.ELDER_LARGE_DOG_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.ELDER_LARGE_DOG_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.ELDER_LARGE_DOG_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.ELDER_LARGE_DOG_WEREWOLF, - }, - CommonAge.ADULT: { - CommonOccultType.NON_OCCULT: CommonSimType.ADULT_LARGE_DOG, - CommonOccultType.VAMPIRE: CommonSimType.ADULT_LARGE_DOG_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.ADULT_LARGE_DOG_GHOST, - CommonOccultType.ALIEN: CommonSimType.ADULT_LARGE_DOG_ALIEN, - CommonOccultType.MERMAID: CommonSimType.ADULT_LARGE_DOG_MERMAID, - CommonOccultType.WITCH: CommonSimType.ADULT_LARGE_DOG_WITCH, - CommonOccultType.ROBOT: CommonSimType.ADULT_LARGE_DOG_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.ADULT_LARGE_DOG_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.ADULT_LARGE_DOG_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.ADULT_LARGE_DOG_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.ADULT_LARGE_DOG_WEREWOLF, - }, - CommonAge.YOUNGADULT: { - CommonOccultType.NON_OCCULT: CommonSimType.ADULT_LARGE_DOG, - CommonOccultType.VAMPIRE: CommonSimType.ADULT_LARGE_DOG_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.ADULT_LARGE_DOG_GHOST, - CommonOccultType.ALIEN: CommonSimType.ADULT_LARGE_DOG_ALIEN, - CommonOccultType.MERMAID: CommonSimType.ADULT_LARGE_DOG_MERMAID, - CommonOccultType.WITCH: CommonSimType.ADULT_LARGE_DOG_WITCH, - CommonOccultType.ROBOT: CommonSimType.ADULT_LARGE_DOG_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.ADULT_LARGE_DOG_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.ADULT_LARGE_DOG_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.ADULT_LARGE_DOG_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.ADULT_LARGE_DOG_WEREWOLF, - }, - CommonAge.TEEN: { - CommonOccultType.NON_OCCULT: CommonSimType.ADULT_LARGE_DOG, - CommonOccultType.VAMPIRE: CommonSimType.ADULT_LARGE_DOG_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.ADULT_LARGE_DOG_GHOST, - CommonOccultType.ALIEN: CommonSimType.ADULT_LARGE_DOG_ALIEN, - CommonOccultType.MERMAID: CommonSimType.ADULT_LARGE_DOG_MERMAID, - CommonOccultType.WITCH: CommonSimType.ADULT_LARGE_DOG_WITCH, - CommonOccultType.ROBOT: CommonSimType.ADULT_LARGE_DOG_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.ADULT_LARGE_DOG_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.ADULT_LARGE_DOG_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.ADULT_LARGE_DOG_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.ADULT_LARGE_DOG_WEREWOLF, - }, - CommonAge.CHILD: { - CommonOccultType.NON_OCCULT: CommonSimType.CHILD_LARGE_DOG, - CommonOccultType.VAMPIRE: CommonSimType.CHILD_LARGE_DOG_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.CHILD_LARGE_DOG_GHOST, - CommonOccultType.ALIEN: CommonSimType.CHILD_LARGE_DOG_ALIEN, - CommonOccultType.MERMAID: CommonSimType.CHILD_LARGE_DOG_MERMAID, - CommonOccultType.WITCH: CommonSimType.CHILD_LARGE_DOG_WITCH, - CommonOccultType.ROBOT: CommonSimType.CHILD_LARGE_DOG_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.CHILD_LARGE_DOG_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.CHILD_LARGE_DOG_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.CHILD_LARGE_DOG_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.CHILD_LARGE_DOG_WEREWOLF, - }, - CommonAge.TODDLER: { - CommonOccultType.NON_OCCULT: CommonSimType.CHILD_LARGE_DOG, - CommonOccultType.VAMPIRE: CommonSimType.CHILD_LARGE_DOG_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.CHILD_LARGE_DOG_GHOST, - CommonOccultType.ALIEN: CommonSimType.CHILD_LARGE_DOG_ALIEN, - CommonOccultType.MERMAID: CommonSimType.CHILD_LARGE_DOG_MERMAID, - CommonOccultType.WITCH: CommonSimType.CHILD_LARGE_DOG_WITCH, - CommonOccultType.ROBOT: CommonSimType.CHILD_LARGE_DOG_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.CHILD_LARGE_DOG_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.CHILD_LARGE_DOG_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.CHILD_LARGE_DOG_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.CHILD_LARGE_DOG_WEREWOLF, - }, - CommonAge.INFANT: { - CommonOccultType.NON_OCCULT: CommonSimType.CHILD_LARGE_DOG, - CommonOccultType.VAMPIRE: CommonSimType.CHILD_LARGE_DOG_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.CHILD_LARGE_DOG_GHOST, - CommonOccultType.ALIEN: CommonSimType.CHILD_LARGE_DOG_ALIEN, - CommonOccultType.MERMAID: CommonSimType.CHILD_LARGE_DOG_MERMAID, - CommonOccultType.WITCH: CommonSimType.CHILD_LARGE_DOG_WITCH, - CommonOccultType.ROBOT: CommonSimType.CHILD_LARGE_DOG_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.CHILD_LARGE_DOG_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.CHILD_LARGE_DOG_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.CHILD_LARGE_DOG_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.CHILD_LARGE_DOG_WEREWOLF, - }, - CommonAge.BABY: { - CommonOccultType.NON_OCCULT: CommonSimType.CHILD_LARGE_DOG, - CommonOccultType.VAMPIRE: CommonSimType.CHILD_LARGE_DOG_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.CHILD_LARGE_DOG_GHOST, - CommonOccultType.ALIEN: CommonSimType.CHILD_LARGE_DOG_ALIEN, - CommonOccultType.MERMAID: CommonSimType.CHILD_LARGE_DOG_MERMAID, - CommonOccultType.WITCH: CommonSimType.CHILD_LARGE_DOG_WITCH, - CommonOccultType.ROBOT: CommonSimType.CHILD_LARGE_DOG_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.CHILD_LARGE_DOG_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.CHILD_LARGE_DOG_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.CHILD_LARGE_DOG_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.CHILD_LARGE_DOG_WEREWOLF, - } - }, - CommonSpecies.CAT: { - CommonAge.ELDER: { - CommonOccultType.NON_OCCULT: CommonSimType.ELDER_CAT, - CommonOccultType.VAMPIRE: CommonSimType.ELDER_CAT_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.ELDER_CAT_GHOST, - CommonOccultType.ALIEN: CommonSimType.ELDER_CAT_ALIEN, - CommonOccultType.MERMAID: CommonSimType.ELDER_CAT_MERMAID, - CommonOccultType.WITCH: CommonSimType.ELDER_CAT_WITCH, - CommonOccultType.ROBOT: CommonSimType.ELDER_CAT_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.ELDER_CAT_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.ELDER_CAT_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.ELDER_CAT_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.ELDER_CAT_WEREWOLF, - }, - CommonAge.ADULT: { - CommonOccultType.NON_OCCULT: CommonSimType.ADULT_CAT, - CommonOccultType.VAMPIRE: CommonSimType.ADULT_CAT_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.ADULT_CAT_GHOST, - CommonOccultType.ALIEN: CommonSimType.ADULT_CAT_ALIEN, - CommonOccultType.MERMAID: CommonSimType.ADULT_CAT_MERMAID, - CommonOccultType.WITCH: CommonSimType.ADULT_CAT_WITCH, - CommonOccultType.ROBOT: CommonSimType.ADULT_CAT_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.ADULT_CAT_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.ADULT_CAT_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.ADULT_CAT_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.ADULT_CAT_WEREWOLF, - }, - CommonAge.YOUNGADULT: { - CommonOccultType.NON_OCCULT: CommonSimType.ADULT_CAT, - CommonOccultType.VAMPIRE: CommonSimType.ADULT_CAT_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.ADULT_CAT_GHOST, - CommonOccultType.ALIEN: CommonSimType.ADULT_CAT_ALIEN, - CommonOccultType.MERMAID: CommonSimType.ADULT_CAT_MERMAID, - CommonOccultType.WITCH: CommonSimType.ADULT_CAT_WITCH, - CommonOccultType.ROBOT: CommonSimType.ADULT_CAT_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.ADULT_CAT_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.ADULT_CAT_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.ADULT_CAT_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.ADULT_CAT_WEREWOLF, - }, - CommonAge.TEEN: { - CommonOccultType.NON_OCCULT: CommonSimType.ADULT_CAT, - CommonOccultType.VAMPIRE: CommonSimType.ADULT_CAT_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.ADULT_CAT_GHOST, - CommonOccultType.ALIEN: CommonSimType.ADULT_CAT_ALIEN, - CommonOccultType.MERMAID: CommonSimType.ADULT_CAT_MERMAID, - CommonOccultType.WITCH: CommonSimType.ADULT_CAT_WITCH, - CommonOccultType.ROBOT: CommonSimType.ADULT_CAT_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.ADULT_CAT_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.ADULT_CAT_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.ADULT_CAT_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.ADULT_CAT_WEREWOLF, - }, - CommonAge.CHILD: { - CommonOccultType.NON_OCCULT: CommonSimType.CHILD_CAT, - CommonOccultType.VAMPIRE: CommonSimType.CHILD_CAT_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.CHILD_CAT_GHOST, - CommonOccultType.ALIEN: CommonSimType.CHILD_CAT_ALIEN, - CommonOccultType.MERMAID: CommonSimType.CHILD_CAT_MERMAID, - CommonOccultType.WITCH: CommonSimType.CHILD_CAT_WITCH, - CommonOccultType.ROBOT: CommonSimType.CHILD_CAT_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.CHILD_CAT_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.CHILD_CAT_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.CHILD_CAT_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.CHILD_CAT_WEREWOLF, - }, - CommonAge.TODDLER: { - CommonOccultType.NON_OCCULT: CommonSimType.CHILD_CAT, - CommonOccultType.VAMPIRE: CommonSimType.CHILD_CAT_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.CHILD_CAT_GHOST, - CommonOccultType.ALIEN: CommonSimType.CHILD_CAT_ALIEN, - CommonOccultType.MERMAID: CommonSimType.CHILD_CAT_MERMAID, - CommonOccultType.WITCH: CommonSimType.CHILD_CAT_WITCH, - CommonOccultType.ROBOT: CommonSimType.CHILD_CAT_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.CHILD_CAT_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.CHILD_CAT_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.CHILD_CAT_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.CHILD_CAT_WEREWOLF, - }, - CommonAge.INFANT: { - CommonOccultType.NON_OCCULT: CommonSimType.CHILD_CAT, - CommonOccultType.VAMPIRE: CommonSimType.CHILD_CAT_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.CHILD_CAT_GHOST, - CommonOccultType.ALIEN: CommonSimType.CHILD_CAT_ALIEN, - CommonOccultType.MERMAID: CommonSimType.CHILD_CAT_MERMAID, - CommonOccultType.WITCH: CommonSimType.CHILD_CAT_WITCH, - CommonOccultType.ROBOT: CommonSimType.CHILD_CAT_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.CHILD_CAT_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.CHILD_CAT_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.CHILD_CAT_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.CHILD_CAT_WEREWOLF, - }, - CommonAge.BABY: { - CommonOccultType.NON_OCCULT: CommonSimType.CHILD_CAT, - CommonOccultType.VAMPIRE: CommonSimType.CHILD_CAT_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.CHILD_CAT_GHOST, - CommonOccultType.ALIEN: CommonSimType.CHILD_CAT_ALIEN, - CommonOccultType.MERMAID: CommonSimType.CHILD_CAT_MERMAID, - CommonOccultType.WITCH: CommonSimType.CHILD_CAT_WITCH, - CommonOccultType.ROBOT: CommonSimType.CHILD_CAT_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.CHILD_CAT_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.CHILD_CAT_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.CHILD_CAT_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.CHILD_CAT_WEREWOLF, - } - }, - CommonSpecies.FOX: { - CommonAge.ELDER: { - CommonOccultType.NON_OCCULT: CommonSimType.ELDER_FOX, - CommonOccultType.VAMPIRE: CommonSimType.ELDER_FOX_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.ELDER_FOX_GHOST, - CommonOccultType.ALIEN: CommonSimType.ELDER_FOX_ALIEN, - CommonOccultType.MERMAID: CommonSimType.ELDER_FOX_MERMAID, - CommonOccultType.WITCH: CommonSimType.ELDER_FOX_WITCH, - CommonOccultType.ROBOT: CommonSimType.ELDER_FOX_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.ELDER_FOX_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.ELDER_FOX_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.ELDER_FOX_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.ELDER_FOX_WEREWOLF, - }, - CommonAge.ADULT: { - CommonOccultType.NON_OCCULT: CommonSimType.ADULT_FOX, - CommonOccultType.VAMPIRE: CommonSimType.ADULT_FOX_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.ADULT_FOX_GHOST, - CommonOccultType.ALIEN: CommonSimType.ADULT_FOX_ALIEN, - CommonOccultType.MERMAID: CommonSimType.ADULT_FOX_MERMAID, - CommonOccultType.WITCH: CommonSimType.ADULT_FOX_WITCH, - CommonOccultType.ROBOT: CommonSimType.ADULT_FOX_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.ADULT_FOX_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.ADULT_FOX_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.ADULT_FOX_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.ADULT_FOX_WEREWOLF, - }, - CommonAge.YOUNGADULT: { - CommonOccultType.NON_OCCULT: CommonSimType.ADULT_FOX, - CommonOccultType.VAMPIRE: CommonSimType.ADULT_FOX_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.ADULT_FOX_GHOST, - CommonOccultType.ALIEN: CommonSimType.ADULT_FOX_ALIEN, - CommonOccultType.MERMAID: CommonSimType.ADULT_FOX_MERMAID, - CommonOccultType.WITCH: CommonSimType.ADULT_FOX_WITCH, - CommonOccultType.ROBOT: CommonSimType.ADULT_FOX_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.ADULT_FOX_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.ADULT_FOX_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.ADULT_FOX_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.ADULT_FOX_WEREWOLF, - }, - CommonAge.TEEN: { - CommonOccultType.NON_OCCULT: CommonSimType.ADULT_FOX, - CommonOccultType.VAMPIRE: CommonSimType.ADULT_FOX_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.ADULT_FOX_GHOST, - CommonOccultType.ALIEN: CommonSimType.ADULT_FOX_ALIEN, - CommonOccultType.MERMAID: CommonSimType.ADULT_FOX_MERMAID, - CommonOccultType.WITCH: CommonSimType.ADULT_FOX_WITCH, - CommonOccultType.ROBOT: CommonSimType.ADULT_FOX_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.ADULT_FOX_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.ADULT_FOX_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.ADULT_FOX_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.ADULT_FOX_WEREWOLF, - }, - CommonAge.CHILD: { - CommonOccultType.NON_OCCULT: CommonSimType.CHILD_FOX, - CommonOccultType.VAMPIRE: CommonSimType.CHILD_FOX_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.CHILD_FOX_GHOST, - CommonOccultType.ALIEN: CommonSimType.CHILD_FOX_ALIEN, - CommonOccultType.MERMAID: CommonSimType.CHILD_FOX_MERMAID, - CommonOccultType.WITCH: CommonSimType.CHILD_FOX_WITCH, - CommonOccultType.ROBOT: CommonSimType.CHILD_FOX_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.CHILD_FOX_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.CHILD_FOX_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.CHILD_FOX_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.CHILD_FOX_WEREWOLF, - }, - CommonAge.TODDLER: { - CommonOccultType.NON_OCCULT: CommonSimType.CHILD_FOX, - CommonOccultType.VAMPIRE: CommonSimType.CHILD_FOX_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.CHILD_FOX_GHOST, - CommonOccultType.ALIEN: CommonSimType.CHILD_FOX_ALIEN, - CommonOccultType.MERMAID: CommonSimType.CHILD_FOX_MERMAID, - CommonOccultType.WITCH: CommonSimType.CHILD_FOX_WITCH, - CommonOccultType.ROBOT: CommonSimType.CHILD_FOX_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.CHILD_FOX_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.CHILD_FOX_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.CHILD_FOX_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.CHILD_FOX_WEREWOLF, - }, - CommonAge.INFANT: { - CommonOccultType.NON_OCCULT: CommonSimType.CHILD_FOX, - CommonOccultType.VAMPIRE: CommonSimType.CHILD_FOX_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.CHILD_FOX_GHOST, - CommonOccultType.ALIEN: CommonSimType.CHILD_FOX_ALIEN, - CommonOccultType.MERMAID: CommonSimType.CHILD_FOX_MERMAID, - CommonOccultType.WITCH: CommonSimType.CHILD_FOX_WITCH, - CommonOccultType.ROBOT: CommonSimType.CHILD_FOX_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.CHILD_FOX_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.CHILD_FOX_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.CHILD_FOX_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.CHILD_FOX_WEREWOLF, - }, - CommonAge.BABY: { - CommonOccultType.NON_OCCULT: CommonSimType.CHILD_FOX, - CommonOccultType.VAMPIRE: CommonSimType.CHILD_FOX_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.CHILD_FOX_GHOST, - CommonOccultType.ALIEN: CommonSimType.CHILD_FOX_ALIEN, - CommonOccultType.MERMAID: CommonSimType.CHILD_FOX_MERMAID, - CommonOccultType.WITCH: CommonSimType.CHILD_FOX_WITCH, - CommonOccultType.ROBOT: CommonSimType.CHILD_FOX_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.CHILD_FOX_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.CHILD_FOX_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.CHILD_FOX_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.CHILD_FOX_WEREWOLF, - } - }, - CommonSpecies.HORSE: { - CommonAge.ELDER: { - CommonOccultType.NON_OCCULT: CommonSimType.ELDER_HORSE, - CommonOccultType.VAMPIRE: CommonSimType.ELDER_HORSE_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.ELDER_HORSE_GHOST, - CommonOccultType.ALIEN: CommonSimType.ELDER_HORSE_ALIEN, - CommonOccultType.MERMAID: CommonSimType.ELDER_HORSE_MERMAID, - CommonOccultType.WITCH: CommonSimType.ELDER_HORSE_WITCH, - CommonOccultType.ROBOT: CommonSimType.ELDER_HORSE_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.ELDER_HORSE_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.ELDER_HORSE_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.ELDER_HORSE_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.ELDER_HORSE_WEREWOLF, - }, - CommonAge.ADULT: { - CommonOccultType.NON_OCCULT: CommonSimType.ADULT_HORSE, - CommonOccultType.VAMPIRE: CommonSimType.ADULT_HORSE_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.ADULT_HORSE_GHOST, - CommonOccultType.ALIEN: CommonSimType.ADULT_HORSE_ALIEN, - CommonOccultType.MERMAID: CommonSimType.ADULT_HORSE_MERMAID, - CommonOccultType.WITCH: CommonSimType.ADULT_HORSE_WITCH, - CommonOccultType.ROBOT: CommonSimType.ADULT_HORSE_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.ADULT_HORSE_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.ADULT_HORSE_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.ADULT_HORSE_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.ADULT_HORSE_WEREWOLF, - }, - CommonAge.YOUNGADULT: { - CommonOccultType.NON_OCCULT: CommonSimType.ADULT_HORSE, - CommonOccultType.VAMPIRE: CommonSimType.ADULT_HORSE_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.ADULT_HORSE_GHOST, - CommonOccultType.ALIEN: CommonSimType.ADULT_HORSE_ALIEN, - CommonOccultType.MERMAID: CommonSimType.ADULT_HORSE_MERMAID, - CommonOccultType.WITCH: CommonSimType.ADULT_HORSE_WITCH, - CommonOccultType.ROBOT: CommonSimType.ADULT_HORSE_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.ADULT_HORSE_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.ADULT_HORSE_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.ADULT_HORSE_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.ADULT_HORSE_WEREWOLF, - }, - CommonAge.TEEN: { - CommonOccultType.NON_OCCULT: CommonSimType.ADULT_HORSE, - CommonOccultType.VAMPIRE: CommonSimType.ADULT_HORSE_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.ADULT_HORSE_GHOST, - CommonOccultType.ALIEN: CommonSimType.ADULT_HORSE_ALIEN, - CommonOccultType.MERMAID: CommonSimType.ADULT_HORSE_MERMAID, - CommonOccultType.WITCH: CommonSimType.ADULT_HORSE_WITCH, - CommonOccultType.ROBOT: CommonSimType.ADULT_HORSE_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.ADULT_HORSE_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.ADULT_HORSE_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.ADULT_HORSE_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.ADULT_HORSE_WEREWOLF, - }, - CommonAge.CHILD: { - CommonOccultType.NON_OCCULT: CommonSimType.CHILD_HORSE, - CommonOccultType.VAMPIRE: CommonSimType.CHILD_HORSE_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.CHILD_HORSE_GHOST, - CommonOccultType.ALIEN: CommonSimType.CHILD_HORSE_ALIEN, - CommonOccultType.MERMAID: CommonSimType.CHILD_HORSE_MERMAID, - CommonOccultType.WITCH: CommonSimType.CHILD_HORSE_WITCH, - CommonOccultType.ROBOT: CommonSimType.CHILD_HORSE_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.CHILD_HORSE_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.CHILD_HORSE_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.CHILD_HORSE_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.CHILD_HORSE_WEREWOLF, - }, - CommonAge.TODDLER: { - CommonOccultType.NON_OCCULT: CommonSimType.CHILD_HORSE, - CommonOccultType.VAMPIRE: CommonSimType.CHILD_HORSE_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.CHILD_HORSE_GHOST, - CommonOccultType.ALIEN: CommonSimType.CHILD_HORSE_ALIEN, - CommonOccultType.MERMAID: CommonSimType.CHILD_HORSE_MERMAID, - CommonOccultType.WITCH: CommonSimType.CHILD_HORSE_WITCH, - CommonOccultType.ROBOT: CommonSimType.CHILD_HORSE_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.CHILD_HORSE_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.CHILD_HORSE_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.CHILD_HORSE_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.CHILD_HORSE_WEREWOLF, - }, - CommonAge.INFANT: { - CommonOccultType.NON_OCCULT: CommonSimType.CHILD_HORSE, - CommonOccultType.VAMPIRE: CommonSimType.CHILD_HORSE_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.CHILD_HORSE_GHOST, - CommonOccultType.ALIEN: CommonSimType.CHILD_HORSE_ALIEN, - CommonOccultType.MERMAID: CommonSimType.CHILD_HORSE_MERMAID, - CommonOccultType.WITCH: CommonSimType.CHILD_HORSE_WITCH, - CommonOccultType.ROBOT: CommonSimType.CHILD_HORSE_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.CHILD_HORSE_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.CHILD_HORSE_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.CHILD_HORSE_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.CHILD_HORSE_WEREWOLF, - }, - CommonAge.BABY: { - CommonOccultType.NON_OCCULT: CommonSimType.CHILD_HORSE, - CommonOccultType.VAMPIRE: CommonSimType.CHILD_HORSE_VAMPIRE, - CommonOccultType.GHOST: CommonSimType.CHILD_HORSE_GHOST, - CommonOccultType.ALIEN: CommonSimType.CHILD_HORSE_ALIEN, - CommonOccultType.MERMAID: CommonSimType.CHILD_HORSE_MERMAID, - CommonOccultType.WITCH: CommonSimType.CHILD_HORSE_WITCH, - CommonOccultType.ROBOT: CommonSimType.CHILD_HORSE_ROBOT, - CommonOccultType.SCARECROW: CommonSimType.CHILD_HORSE_SCARECROW, - CommonOccultType.SKELETON: CommonSimType.CHILD_HORSE_SKELETON, - CommonOccultType.PLANT_SIM: CommonSimType.CHILD_HORSE_PLANT_SIM, - CommonOccultType.WEREWOLF: CommonSimType.CHILD_HORSE_WEREWOLF, - } - } - } - _SIM_TYPE_TO_SIGNATURE_MAPPING: Dict[CommonSimType, str] = { - # Human - # Elder - CommonSimType.ELDER_HUMAN: 'ElHu', - CommonSimType.ELDER_HUMAN_VAMPIRE: 'ElHuVa', - CommonSimType.ELDER_HUMAN_GHOST: 'ElHuGh', - CommonSimType.ELDER_HUMAN_ALIEN: 'ElHuAl', - CommonSimType.ELDER_HUMAN_MERMAID: 'ElHuMer', - CommonSimType.ELDER_HUMAN_WITCH: 'ElHuWi', - CommonSimType.ELDER_HUMAN_ROBOT: 'ElHuRo', - CommonSimType.ELDER_HUMAN_SCARECROW: 'ElHuScrw', - CommonSimType.ELDER_HUMAN_SKELETON: 'ElHuSk', - CommonSimType.ELDER_HUMAN_PLANT_SIM: 'ElHuPls', - CommonSimType.ELDER_HUMAN_WEREWOLF: 'ElHuWerWlf', - # Adult - CommonSimType.ADULT_HUMAN: 'AdHu', - CommonSimType.ADULT_HUMAN_VAMPIRE: 'AdHuVa', - CommonSimType.ADULT_HUMAN_GHOST: 'AdHuGh', - CommonSimType.ADULT_HUMAN_ALIEN: 'AdHuAl', - CommonSimType.ADULT_HUMAN_MERMAID: 'AdHuMer', - CommonSimType.ADULT_HUMAN_WITCH: 'AdHuWi', - CommonSimType.ADULT_HUMAN_ROBOT: 'AdHuRo', - CommonSimType.ADULT_HUMAN_SCARECROW: 'AdHuScrw', - CommonSimType.ADULT_HUMAN_SKELETON: 'AdHuSk', - CommonSimType.ADULT_HUMAN_PLANT_SIM: 'AdHuPls', - CommonSimType.ADULT_HUMAN_WEREWOLF: 'AdHuWerWlf', - # Young Adult - CommonSimType.YOUNG_ADULT_HUMAN: 'YadHu', - CommonSimType.YOUNG_ADULT_HUMAN_VAMPIRE: 'YadHuVa', - CommonSimType.YOUNG_ADULT_HUMAN_GHOST: 'YadHuGh', - CommonSimType.YOUNG_ADULT_HUMAN_ALIEN: 'YadHuAl', - CommonSimType.YOUNG_ADULT_HUMAN_MERMAID: 'YadHuMer', - CommonSimType.YOUNG_ADULT_HUMAN_WITCH: 'YadHuWi', - CommonSimType.YOUNG_ADULT_HUMAN_ROBOT: 'YadHuRo', - CommonSimType.YOUNG_ADULT_HUMAN_SCARECROW: 'YadHuScrw', - CommonSimType.YOUNG_ADULT_HUMAN_SKELETON: 'YadHuSk', - CommonSimType.YOUNG_ADULT_HUMAN_PLANT_SIM: 'YadHuPls', - CommonSimType.YOUNG_ADULT_HUMAN_WEREWOLF: 'YadHuWerWlf', - # Teen - CommonSimType.TEEN_HUMAN: 'TnHu', - CommonSimType.TEEN_HUMAN_VAMPIRE: 'TnHuVa', - CommonSimType.TEEN_HUMAN_GHOST: 'TnHuGh', - CommonSimType.TEEN_HUMAN_ALIEN: 'TnHuAl', - CommonSimType.TEEN_HUMAN_MERMAID: 'TnHuMer', - CommonSimType.TEEN_HUMAN_WITCH: 'TnHuWi', - CommonSimType.TEEN_HUMAN_ROBOT: 'TnHuRo', - CommonSimType.TEEN_HUMAN_SCARECROW: 'TnHuScrw', - CommonSimType.TEEN_HUMAN_SKELETON: 'TnHuSk', - CommonSimType.TEEN_HUMAN_PLANT_SIM: 'TnHuPls', - CommonSimType.TEEN_HUMAN_WEREWOLF: 'TnHuWerWlf', - # Child - CommonSimType.CHILD_HUMAN: 'ChldHu', - CommonSimType.CHILD_HUMAN_VAMPIRE: 'ChldHuVa', - CommonSimType.CHILD_HUMAN_GHOST: 'ChldHuGh', - CommonSimType.CHILD_HUMAN_ALIEN: 'ChldHuAl', - CommonSimType.CHILD_HUMAN_MERMAID: 'ChldHuMer', - CommonSimType.CHILD_HUMAN_WITCH: 'ChldHuWi', - CommonSimType.CHILD_HUMAN_ROBOT: 'ChldHuRo', - CommonSimType.CHILD_HUMAN_SCARECROW: 'ChldHuScrw', - CommonSimType.CHILD_HUMAN_SKELETON: 'ChldHuSk', - CommonSimType.CHILD_HUMAN_PLANT_SIM: 'ChldHuPls', - CommonSimType.CHILD_HUMAN_WEREWOLF: 'ChldHuWerWlf', - # Toddler - CommonSimType.TODDLER_HUMAN: 'TdlrHu', - CommonSimType.TODDLER_HUMAN_VAMPIRE: 'TdlrHuVa', - CommonSimType.TODDLER_HUMAN_GHOST: 'TdlrHuGh', - CommonSimType.TODDLER_HUMAN_ALIEN: 'TdlrHuAl', - CommonSimType.TODDLER_HUMAN_MERMAID: 'TdlrHuMer', - CommonSimType.TODDLER_HUMAN_WITCH: 'TdlrHuWi', - CommonSimType.TODDLER_HUMAN_ROBOT: 'TdlrHuRo', - CommonSimType.TODDLER_HUMAN_SCARECROW: 'TdlrHuScrw', - CommonSimType.TODDLER_HUMAN_SKELETON: 'TdlrHuSk', - CommonSimType.TODDLER_HUMAN_PLANT_SIM: 'TdlrHuPls', - CommonSimType.TODDLER_HUMAN_WEREWOLF: 'TdlrHuWerWlf', - # Infant - CommonSimType.INFANT_HUMAN: 'InfntHu', - CommonSimType.INFANT_HUMAN_VAMPIRE: 'InfntHuVa', - CommonSimType.INFANT_HUMAN_GHOST: 'InfntHuGh', - CommonSimType.INFANT_HUMAN_ALIEN: 'InfntHuAl', - CommonSimType.INFANT_HUMAN_MERMAID: 'InfntHuMer', - CommonSimType.INFANT_HUMAN_WITCH: 'InfntHuWi', - CommonSimType.INFANT_HUMAN_ROBOT: 'InfntHuRo', - CommonSimType.INFANT_HUMAN_SCARECROW: 'InfntHuScrw', - CommonSimType.INFANT_HUMAN_SKELETON: 'InfntHuSk', - CommonSimType.INFANT_HUMAN_PLANT_SIM: 'InfntHuPls', - CommonSimType.INFANT_HUMAN_WEREWOLF: 'InfntHuWerWlf', - # Baby - CommonSimType.BABY_HUMAN: 'BbyHu', - CommonSimType.BABY_HUMAN_VAMPIRE: 'BbyHuVa', - CommonSimType.BABY_HUMAN_GHOST: 'BbyHuGh', - CommonSimType.BABY_HUMAN_ALIEN: 'BbyHuAl', - CommonSimType.BABY_HUMAN_MERMAID: 'BbyHuMer', - CommonSimType.BABY_HUMAN_WITCH: 'BbyHuWi', - CommonSimType.BABY_HUMAN_ROBOT: 'BbyHuRo', - CommonSimType.BABY_HUMAN_SCARECROW: 'BbyHuScrw', - CommonSimType.BABY_HUMAN_SKELETON: 'BbyHuSk', - CommonSimType.BABY_HUMAN_PLANT_SIM: 'BbyHuPls', - CommonSimType.BABY_HUMAN_WEREWOLF: 'BbyHuWerWlf', - - # Child Dog - CommonSimType.CHILD_DOG: 'ChldDg', - CommonSimType.CHILD_DOG_VAMPIRE: 'ChldDgVa', - CommonSimType.CHILD_DOG_GHOST: 'ChldDgGh', - CommonSimType.CHILD_DOG_ALIEN: 'ChldDgAl', - CommonSimType.CHILD_DOG_MERMAID: 'ChldDgMer', - CommonSimType.CHILD_DOG_WITCH: 'ChldDgWi', - CommonSimType.CHILD_DOG_ROBOT: 'ChldDgRo', - CommonSimType.CHILD_DOG_SCARECROW: 'ChldDgScrw', - CommonSimType.CHILD_DOG_SKELETON: 'ChldDgSk', - CommonSimType.CHILD_DOG_PLANT_SIM: 'ChldDgPls', - CommonSimType.CHILD_DOG_WEREWOLF: 'ChldDgWerWlf', - - # Small Dog - # Elder - CommonSimType.ELDER_SMALL_DOG: 'ElSd', - CommonSimType.ELDER_SMALL_DOG_VAMPIRE: 'ElSdVa', - CommonSimType.ELDER_SMALL_DOG_GHOST: 'ElSdGh', - CommonSimType.ELDER_SMALL_DOG_ALIEN: 'ElSdAl', - CommonSimType.ELDER_SMALL_DOG_MERMAID: 'ElSdMer', - CommonSimType.ELDER_SMALL_DOG_WITCH: 'ElSdWi', - CommonSimType.ELDER_SMALL_DOG_ROBOT: 'ElSdRo', - CommonSimType.ELDER_SMALL_DOG_SCARECROW: 'ElSdScrw', - CommonSimType.ELDER_SMALL_DOG_SKELETON: 'ElSdSk', - CommonSimType.ELDER_SMALL_DOG_PLANT_SIM: 'ElSdPls', - CommonSimType.ELDER_SMALL_DOG_WEREWOLF: 'ElSdWerWlf', - # Adult - CommonSimType.ADULT_SMALL_DOG: 'AdSd', - CommonSimType.ADULT_SMALL_DOG_VAMPIRE: 'AdSdVa', - CommonSimType.ADULT_SMALL_DOG_GHOST: 'AdSdGh', - CommonSimType.ADULT_SMALL_DOG_ALIEN: 'AdSdAl', - CommonSimType.ADULT_SMALL_DOG_MERMAID: 'AdSdMer', - CommonSimType.ADULT_SMALL_DOG_WITCH: 'AdSdWi', - CommonSimType.ADULT_SMALL_DOG_ROBOT: 'AdSdRo', - CommonSimType.ADULT_SMALL_DOG_SCARECROW: 'AdSdScrw', - CommonSimType.ADULT_SMALL_DOG_SKELETON: 'AdSdSk', - CommonSimType.ADULT_SMALL_DOG_PLANT_SIM: 'AdSdPls', - CommonSimType.ADULT_SMALL_DOG_WEREWOLF: 'AdSdWerWlf', - # Child - CommonSimType.CHILD_SMALL_DOG: 'ChldSd', - CommonSimType.CHILD_SMALL_DOG_VAMPIRE: 'ChldSdVa', - CommonSimType.CHILD_SMALL_DOG_GHOST: 'ChldSdGh', - CommonSimType.CHILD_SMALL_DOG_ALIEN: 'ChldSdAl', - CommonSimType.CHILD_SMALL_DOG_MERMAID: 'ChldSdMer', - CommonSimType.CHILD_SMALL_DOG_WITCH: 'ChldSdWi', - CommonSimType.CHILD_SMALL_DOG_ROBOT: 'ChldSdRo', - CommonSimType.CHILD_SMALL_DOG_SCARECROW: 'ChldSdScrw', - CommonSimType.CHILD_SMALL_DOG_SKELETON: 'ChldSdSk', - CommonSimType.CHILD_SMALL_DOG_PLANT_SIM: 'ChldSdPls', - CommonSimType.CHILD_SMALL_DOG_WEREWOLF: 'ChldSdWerWlf', - - # Large Dog - # Elder - CommonSimType.ELDER_LARGE_DOG: 'ElLd', - CommonSimType.ELDER_LARGE_DOG_VAMPIRE: 'ElLdVa', - CommonSimType.ELDER_LARGE_DOG_GHOST: 'ElLdGh', - CommonSimType.ELDER_LARGE_DOG_ALIEN: 'ElLdAl', - CommonSimType.ELDER_LARGE_DOG_MERMAID: 'ElLdMer', - CommonSimType.ELDER_LARGE_DOG_WITCH: 'ElLdWi', - CommonSimType.ELDER_LARGE_DOG_ROBOT: 'ElLdRo', - CommonSimType.ELDER_LARGE_DOG_SCARECROW: 'ElLdScrw', - CommonSimType.ELDER_LARGE_DOG_SKELETON: 'ElLdSk', - CommonSimType.ELDER_LARGE_DOG_PLANT_SIM: 'ElLdPls', - CommonSimType.ELDER_LARGE_DOG_WEREWOLF: 'ElLdWerWlf', - # Adult - CommonSimType.ADULT_LARGE_DOG: 'AdLd', - CommonSimType.ADULT_LARGE_DOG_VAMPIRE: 'AdLdVa', - CommonSimType.ADULT_LARGE_DOG_GHOST: 'AdLdGh', - CommonSimType.ADULT_LARGE_DOG_ALIEN: 'AdLdAl', - CommonSimType.ADULT_LARGE_DOG_MERMAID: 'AdLdMer', - CommonSimType.ADULT_LARGE_DOG_WITCH: 'AdLdWi', - CommonSimType.ADULT_LARGE_DOG_ROBOT: 'AdLdRo', - CommonSimType.ADULT_LARGE_DOG_SCARECROW: 'AdLdScrw', - CommonSimType.ADULT_LARGE_DOG_SKELETON: 'AdLdSk', - CommonSimType.ADULT_LARGE_DOG_PLANT_SIM: 'AdLdPls', - CommonSimType.ADULT_LARGE_DOG_WEREWOLF: 'AdLdWerWlf', - # Child - CommonSimType.CHILD_LARGE_DOG: 'ChldLd', - CommonSimType.CHILD_LARGE_DOG_VAMPIRE: 'ChldLdVa', - CommonSimType.CHILD_LARGE_DOG_GHOST: 'ChldLdGh', - CommonSimType.CHILD_LARGE_DOG_ALIEN: 'ChldLdAl', - CommonSimType.CHILD_LARGE_DOG_MERMAID: 'ChldLdMer', - CommonSimType.CHILD_LARGE_DOG_WITCH: 'ChldLdWi', - CommonSimType.CHILD_LARGE_DOG_ROBOT: 'ChldLdRo', - CommonSimType.CHILD_LARGE_DOG_SCARECROW: 'ChldLdScrw', - CommonSimType.CHILD_LARGE_DOG_SKELETON: 'ChldLdSk', - CommonSimType.CHILD_LARGE_DOG_PLANT_SIM: 'ChldLdPls', - CommonSimType.CHILD_LARGE_DOG_WEREWOLF: 'ChldLdWerWlf', - - # Cat - # Elder - CommonSimType.ELDER_CAT: 'ElCat', - CommonSimType.ELDER_CAT_VAMPIRE: 'ElCatVa', - CommonSimType.ELDER_CAT_GHOST: 'ElCatGh', - CommonSimType.ELDER_CAT_ALIEN: 'ElCatAl', - CommonSimType.ELDER_CAT_MERMAID: 'ElCatMer', - CommonSimType.ELDER_CAT_WITCH: 'ElCatWi', - CommonSimType.ELDER_CAT_ROBOT: 'ElCatRo', - CommonSimType.ELDER_CAT_SCARECROW: 'ElCatScrw', - CommonSimType.ELDER_CAT_SKELETON: 'ElCatSk', - CommonSimType.ELDER_CAT_PLANT_SIM: 'ElCatPls', - CommonSimType.ELDER_CAT_WEREWOLF: 'ElCatWerWlf', - # Adult - CommonSimType.ADULT_CAT: 'AdCat', - CommonSimType.ADULT_CAT_VAMPIRE: 'AdCatVa', - CommonSimType.ADULT_CAT_GHOST: 'AdCatGh', - CommonSimType.ADULT_CAT_ALIEN: 'AdCatAl', - CommonSimType.ADULT_CAT_MERMAID: 'AdCatMer', - CommonSimType.ADULT_CAT_WITCH: 'AdCatWi', - CommonSimType.ADULT_CAT_ROBOT: 'AdCatRo', - CommonSimType.ADULT_CAT_SCARECROW: 'AdCatScrw', - CommonSimType.ADULT_CAT_SKELETON: 'AdCatSk', - CommonSimType.ADULT_CAT_PLANT_SIM: 'AdCatPls', - CommonSimType.ADULT_CAT_WEREWOLF: 'AdCatWerWlf', - # Child - CommonSimType.CHILD_CAT: 'ChldCat', - CommonSimType.CHILD_CAT_VAMPIRE: 'ChldCatVa', - CommonSimType.CHILD_CAT_GHOST: 'ChldCatGh', - CommonSimType.CHILD_CAT_ALIEN: 'ChldCatAl', - CommonSimType.CHILD_CAT_MERMAID: 'ChldCatMer', - CommonSimType.CHILD_CAT_WITCH: 'ChldCatWi', - CommonSimType.CHILD_CAT_ROBOT: 'ChldCatRo', - CommonSimType.CHILD_CAT_SCARECROW: 'ChldCatScrw', - CommonSimType.CHILD_CAT_SKELETON: 'ChldCatSk', - CommonSimType.CHILD_CAT_PLANT_SIM: 'ChldCatPls', - CommonSimType.CHILD_CAT_WEREWOLF: 'ChldCatWerWlf', - - # Fox - # Elder - CommonSimType.ELDER_FOX: 'ElFox', - CommonSimType.ELDER_FOX_VAMPIRE: 'ElFoxVa', - CommonSimType.ELDER_FOX_GHOST: 'ElFoxGh', - CommonSimType.ELDER_FOX_ALIEN: 'ElFoxAl', - CommonSimType.ELDER_FOX_MERMAID: 'ElFoxMer', - CommonSimType.ELDER_FOX_WITCH: 'ElFoxWi', - CommonSimType.ELDER_FOX_ROBOT: 'ElFoxRo', - CommonSimType.ELDER_FOX_SCARECROW: 'ElFoxScrw', - CommonSimType.ELDER_FOX_SKELETON: 'ElFoxSk', - CommonSimType.ELDER_FOX_PLANT_SIM: 'ElFoxPls', - CommonSimType.ELDER_FOX_WEREWOLF: 'ElFoxWerWlf', - # Adult - CommonSimType.ADULT_FOX: 'AdFox', - CommonSimType.ADULT_FOX_VAMPIRE: 'AdFoxVa', - CommonSimType.ADULT_FOX_GHOST: 'AdFoxGh', - CommonSimType.ADULT_FOX_ALIEN: 'AdFoxAl', - CommonSimType.ADULT_FOX_MERMAID: 'AdFoxMer', - CommonSimType.ADULT_FOX_WITCH: 'AdFoxWi', - CommonSimType.ADULT_FOX_ROBOT: 'AdFoxRo', - CommonSimType.ADULT_FOX_SCARECROW: 'AdFoxScrw', - CommonSimType.ADULT_FOX_SKELETON: 'AdFoxSk', - CommonSimType.ADULT_FOX_PLANT_SIM: 'AdFoxPls', - CommonSimType.ADULT_FOX_WEREWOLF: 'AdFoxWerWlf', - # Child - CommonSimType.CHILD_FOX: 'ChldFox', - CommonSimType.CHILD_FOX_VAMPIRE: 'ChldFoxVa', - CommonSimType.CHILD_FOX_GHOST: 'ChldFoxGh', - CommonSimType.CHILD_FOX_ALIEN: 'ChldFoxAl', - CommonSimType.CHILD_FOX_MERMAID: 'ChldFoxMer', - CommonSimType.CHILD_FOX_WITCH: 'ChldFoxWi', - CommonSimType.CHILD_FOX_ROBOT: 'ChldFoxRo', - CommonSimType.CHILD_FOX_SCARECROW: 'ChldFoxScrw', - CommonSimType.CHILD_FOX_SKELETON: 'ChldFoxSk', - CommonSimType.CHILD_FOX_PLANT_SIM: 'ChldFoxPls', - CommonSimType.CHILD_FOX_WEREWOLF: 'ChldFoxWerWlf', - - # Horse - # Elder - CommonSimType.ELDER_HORSE: 'ElHrs', - CommonSimType.ELDER_HORSE_VAMPIRE: 'ElHrsVa', - CommonSimType.ELDER_HORSE_GHOST: 'ElHrsGh', - CommonSimType.ELDER_HORSE_ALIEN: 'ElHrsAl', - CommonSimType.ELDER_HORSE_MERMAID: 'ElHrsMer', - CommonSimType.ELDER_HORSE_WITCH: 'ElHrsWi', - CommonSimType.ELDER_HORSE_ROBOT: 'ElHrsRo', - CommonSimType.ELDER_HORSE_SCARECROW: 'ElHrsScrw', - CommonSimType.ELDER_HORSE_SKELETON: 'ElHrsSk', - CommonSimType.ELDER_HORSE_PLANT_SIM: 'ElHrsPls', - CommonSimType.ELDER_HORSE_WEREWOLF: 'ElHrsWerWlf', - # Adult - CommonSimType.ADULT_HORSE: 'AdHrs', - CommonSimType.ADULT_HORSE_VAMPIRE: 'AdHrsVa', - CommonSimType.ADULT_HORSE_GHOST: 'AdHrsGh', - CommonSimType.ADULT_HORSE_ALIEN: 'AdHrsAl', - CommonSimType.ADULT_HORSE_MERMAID: 'AdHrsMer', - CommonSimType.ADULT_HORSE_WITCH: 'AdHrsWi', - CommonSimType.ADULT_HORSE_ROBOT: 'AdHrsRo', - CommonSimType.ADULT_HORSE_SCARECROW: 'AdHrsScrw', - CommonSimType.ADULT_HORSE_SKELETON: 'AdHrsSk', - CommonSimType.ADULT_HORSE_PLANT_SIM: 'AdHrsPls', - CommonSimType.ADULT_HORSE_WEREWOLF: 'AdHrsWerWlf', - # Child - CommonSimType.CHILD_HORSE: 'ChldHrs', - CommonSimType.CHILD_HORSE_VAMPIRE: 'ChldHrsVa', - CommonSimType.CHILD_HORSE_GHOST: 'ChldHrsGh', - CommonSimType.CHILD_HORSE_ALIEN: 'ChldHrsAl', - CommonSimType.CHILD_HORSE_MERMAID: 'ChldHrsMer', - CommonSimType.CHILD_HORSE_WITCH: 'ChldHrsWi', - CommonSimType.CHILD_HORSE_ROBOT: 'ChldHrsRo', - CommonSimType.CHILD_HORSE_SCARECROW: 'ChldHrsScrw', - CommonSimType.CHILD_HORSE_SKELETON: 'ChldHrsSk', - CommonSimType.CHILD_HORSE_PLANT_SIM: 'ChldHrsPls', - CommonSimType.CHILD_HORSE_WEREWOLF: 'ChldHrsWerWlf', - } - - _OCCULT_SIM_TYPE_TO_NON_OCCULT_SIM_TYPE_MAPPING: Dict[CommonSimType, CommonSimType] = { - # Human - # Elder - CommonSimType.ELDER_HUMAN: CommonSimType.ELDER_HUMAN, - CommonSimType.ELDER_HUMAN_VAMPIRE: CommonSimType.ELDER_HUMAN, - CommonSimType.ELDER_HUMAN_GHOST: CommonSimType.ELDER_HUMAN, - CommonSimType.ELDER_HUMAN_ALIEN: CommonSimType.ELDER_HUMAN, - CommonSimType.ELDER_HUMAN_MERMAID: CommonSimType.ELDER_HUMAN, - CommonSimType.ELDER_HUMAN_WITCH: CommonSimType.ELDER_HUMAN, - CommonSimType.ELDER_HUMAN_ROBOT: CommonSimType.ELDER_HUMAN, - CommonSimType.ELDER_HUMAN_SCARECROW: CommonSimType.ELDER_HUMAN, - CommonSimType.ELDER_HUMAN_SKELETON: CommonSimType.ELDER_HUMAN, - CommonSimType.ELDER_HUMAN_PLANT_SIM: CommonSimType.ELDER_HUMAN, - CommonSimType.ELDER_HUMAN_WEREWOLF: CommonSimType.ELDER_HUMAN, - # Adult - CommonSimType.ADULT_HUMAN: CommonSimType.ADULT_HUMAN, - CommonSimType.ADULT_HUMAN_VAMPIRE: CommonSimType.ADULT_HUMAN, - CommonSimType.ADULT_HUMAN_GHOST: CommonSimType.ADULT_HUMAN, - CommonSimType.ADULT_HUMAN_ALIEN: CommonSimType.ADULT_HUMAN, - CommonSimType.ADULT_HUMAN_MERMAID: CommonSimType.ADULT_HUMAN, - CommonSimType.ADULT_HUMAN_WITCH: CommonSimType.ADULT_HUMAN, - CommonSimType.ADULT_HUMAN_ROBOT: CommonSimType.ADULT_HUMAN, - CommonSimType.ADULT_HUMAN_SCARECROW: CommonSimType.ADULT_HUMAN, - CommonSimType.ADULT_HUMAN_SKELETON: CommonSimType.ADULT_HUMAN, - CommonSimType.ADULT_HUMAN_PLANT_SIM: CommonSimType.ADULT_HUMAN, - CommonSimType.ADULT_HUMAN_WEREWOLF: CommonSimType.ADULT_HUMAN, - # Young Adult - CommonSimType.YOUNG_ADULT_HUMAN: CommonSimType.YOUNG_ADULT_HUMAN, - CommonSimType.YOUNG_ADULT_HUMAN_VAMPIRE: CommonSimType.YOUNG_ADULT_HUMAN, - CommonSimType.YOUNG_ADULT_HUMAN_GHOST: CommonSimType.YOUNG_ADULT_HUMAN, - CommonSimType.YOUNG_ADULT_HUMAN_ALIEN: CommonSimType.YOUNG_ADULT_HUMAN, - CommonSimType.YOUNG_ADULT_HUMAN_MERMAID: CommonSimType.YOUNG_ADULT_HUMAN, - CommonSimType.YOUNG_ADULT_HUMAN_WITCH: CommonSimType.YOUNG_ADULT_HUMAN, - CommonSimType.YOUNG_ADULT_HUMAN_ROBOT: CommonSimType.YOUNG_ADULT_HUMAN, - CommonSimType.YOUNG_ADULT_HUMAN_SCARECROW: CommonSimType.YOUNG_ADULT_HUMAN, - CommonSimType.YOUNG_ADULT_HUMAN_SKELETON: CommonSimType.YOUNG_ADULT_HUMAN, - CommonSimType.YOUNG_ADULT_HUMAN_PLANT_SIM: CommonSimType.YOUNG_ADULT_HUMAN, - CommonSimType.YOUNG_ADULT_HUMAN_WEREWOLF: CommonSimType.YOUNG_ADULT_HUMAN, - # Teen - CommonSimType.TEEN_HUMAN: CommonSimType.TEEN_HUMAN, - CommonSimType.TEEN_HUMAN_VAMPIRE: CommonSimType.TEEN_HUMAN, - CommonSimType.TEEN_HUMAN_GHOST: CommonSimType.TEEN_HUMAN, - CommonSimType.TEEN_HUMAN_ALIEN: CommonSimType.TEEN_HUMAN, - CommonSimType.TEEN_HUMAN_MERMAID: CommonSimType.TEEN_HUMAN, - CommonSimType.TEEN_HUMAN_WITCH: CommonSimType.TEEN_HUMAN, - CommonSimType.TEEN_HUMAN_ROBOT: CommonSimType.TEEN_HUMAN, - CommonSimType.TEEN_HUMAN_SCARECROW: CommonSimType.TEEN_HUMAN, - CommonSimType.TEEN_HUMAN_SKELETON: CommonSimType.TEEN_HUMAN, - CommonSimType.TEEN_HUMAN_PLANT_SIM: CommonSimType.TEEN_HUMAN, - CommonSimType.TEEN_HUMAN_WEREWOLF: CommonSimType.TEEN_HUMAN, - # Child - CommonSimType.CHILD_HUMAN: CommonSimType.CHILD_HUMAN, - CommonSimType.CHILD_HUMAN_VAMPIRE: CommonSimType.CHILD_HUMAN, - CommonSimType.CHILD_HUMAN_GHOST: CommonSimType.CHILD_HUMAN, - CommonSimType.CHILD_HUMAN_ALIEN: CommonSimType.CHILD_HUMAN, - CommonSimType.CHILD_HUMAN_MERMAID: CommonSimType.CHILD_HUMAN, - CommonSimType.CHILD_HUMAN_WITCH: CommonSimType.CHILD_HUMAN, - CommonSimType.CHILD_HUMAN_ROBOT: CommonSimType.CHILD_HUMAN, - CommonSimType.CHILD_HUMAN_SCARECROW: CommonSimType.CHILD_HUMAN, - CommonSimType.CHILD_HUMAN_SKELETON: CommonSimType.CHILD_HUMAN, - CommonSimType.CHILD_HUMAN_PLANT_SIM: CommonSimType.CHILD_HUMAN, - CommonSimType.CHILD_HUMAN_WEREWOLF: CommonSimType.CHILD_HUMAN, - # Toddler - CommonSimType.TODDLER_HUMAN: CommonSimType.TODDLER_HUMAN, - CommonSimType.TODDLER_HUMAN_VAMPIRE: CommonSimType.TODDLER_HUMAN, - CommonSimType.TODDLER_HUMAN_GHOST: CommonSimType.TODDLER_HUMAN, - CommonSimType.TODDLER_HUMAN_ALIEN: CommonSimType.TODDLER_HUMAN, - CommonSimType.TODDLER_HUMAN_MERMAID: CommonSimType.TODDLER_HUMAN, - CommonSimType.TODDLER_HUMAN_WITCH: CommonSimType.TODDLER_HUMAN, - CommonSimType.TODDLER_HUMAN_ROBOT: CommonSimType.TODDLER_HUMAN, - CommonSimType.TODDLER_HUMAN_SCARECROW: CommonSimType.TODDLER_HUMAN, - CommonSimType.TODDLER_HUMAN_SKELETON: CommonSimType.TODDLER_HUMAN, - CommonSimType.TODDLER_HUMAN_PLANT_SIM: CommonSimType.TODDLER_HUMAN, - CommonSimType.TODDLER_HUMAN_WEREWOLF: CommonSimType.TODDLER_HUMAN, - # Infant - CommonSimType.INFANT_HUMAN: CommonSimType.INFANT_HUMAN, - CommonSimType.INFANT_HUMAN_VAMPIRE: CommonSimType.INFANT_HUMAN, - CommonSimType.INFANT_HUMAN_GHOST: CommonSimType.INFANT_HUMAN, - CommonSimType.INFANT_HUMAN_ALIEN: CommonSimType.INFANT_HUMAN, - CommonSimType.INFANT_HUMAN_MERMAID: CommonSimType.INFANT_HUMAN, - CommonSimType.INFANT_HUMAN_WITCH: CommonSimType.INFANT_HUMAN, - CommonSimType.INFANT_HUMAN_ROBOT: CommonSimType.INFANT_HUMAN, - CommonSimType.INFANT_HUMAN_SCARECROW: CommonSimType.INFANT_HUMAN, - CommonSimType.INFANT_HUMAN_SKELETON: CommonSimType.INFANT_HUMAN, - CommonSimType.INFANT_HUMAN_PLANT_SIM: CommonSimType.INFANT_HUMAN, - CommonSimType.INFANT_HUMAN_WEREWOLF: CommonSimType.INFANT_HUMAN, - - # Baby - CommonSimType.BABY_HUMAN: CommonSimType.BABY_HUMAN, - CommonSimType.BABY_HUMAN_VAMPIRE: CommonSimType.BABY_HUMAN, - CommonSimType.BABY_HUMAN_GHOST: CommonSimType.BABY_HUMAN, - CommonSimType.BABY_HUMAN_ALIEN: CommonSimType.BABY_HUMAN, - CommonSimType.BABY_HUMAN_MERMAID: CommonSimType.BABY_HUMAN, - CommonSimType.BABY_HUMAN_WITCH: CommonSimType.BABY_HUMAN, - CommonSimType.BABY_HUMAN_ROBOT: CommonSimType.BABY_HUMAN, - CommonSimType.BABY_HUMAN_SCARECROW: CommonSimType.BABY_HUMAN, - CommonSimType.BABY_HUMAN_SKELETON: CommonSimType.BABY_HUMAN, - CommonSimType.BABY_HUMAN_PLANT_SIM: CommonSimType.BABY_HUMAN, - CommonSimType.BABY_HUMAN_WEREWOLF: CommonSimType.BABY_HUMAN, - - # Dog - # Child - CommonSimType.CHILD_DOG: CommonSimType.CHILD_DOG, - CommonSimType.CHILD_DOG_VAMPIRE: CommonSimType.CHILD_DOG, - CommonSimType.CHILD_DOG_GHOST: CommonSimType.CHILD_DOG, - CommonSimType.CHILD_DOG_ALIEN: CommonSimType.CHILD_DOG, - CommonSimType.CHILD_DOG_MERMAID: CommonSimType.CHILD_DOG, - CommonSimType.CHILD_DOG_WITCH: CommonSimType.CHILD_DOG, - CommonSimType.CHILD_DOG_ROBOT: CommonSimType.CHILD_DOG, - CommonSimType.CHILD_DOG_SCARECROW: CommonSimType.CHILD_DOG, - CommonSimType.CHILD_DOG_SKELETON: CommonSimType.CHILD_DOG, - CommonSimType.CHILD_DOG_PLANT_SIM: CommonSimType.CHILD_DOG, - CommonSimType.CHILD_DOG_WEREWOLF: CommonSimType.CHILD_DOG, - - # Small Dog - # Elder - CommonSimType.ELDER_SMALL_DOG: CommonSimType.ELDER_SMALL_DOG, - CommonSimType.ELDER_SMALL_DOG_VAMPIRE: CommonSimType.ELDER_SMALL_DOG, - CommonSimType.ELDER_SMALL_DOG_GHOST: CommonSimType.ELDER_SMALL_DOG, - CommonSimType.ELDER_SMALL_DOG_ALIEN: CommonSimType.ELDER_SMALL_DOG, - CommonSimType.ELDER_SMALL_DOG_MERMAID: CommonSimType.ELDER_SMALL_DOG, - CommonSimType.ELDER_SMALL_DOG_WITCH: CommonSimType.ELDER_SMALL_DOG, - CommonSimType.ELDER_SMALL_DOG_ROBOT: CommonSimType.ELDER_SMALL_DOG, - CommonSimType.ELDER_SMALL_DOG_SCARECROW: CommonSimType.ELDER_SMALL_DOG, - CommonSimType.ELDER_SMALL_DOG_SKELETON: CommonSimType.ELDER_SMALL_DOG, - CommonSimType.ELDER_SMALL_DOG_PLANT_SIM: CommonSimType.ELDER_SMALL_DOG, - CommonSimType.ELDER_SMALL_DOG_WEREWOLF: CommonSimType.ELDER_SMALL_DOG, - # Adult - CommonSimType.ADULT_SMALL_DOG: CommonSimType.ADULT_SMALL_DOG, - CommonSimType.ADULT_SMALL_DOG_VAMPIRE: CommonSimType.ADULT_SMALL_DOG, - CommonSimType.ADULT_SMALL_DOG_GHOST: CommonSimType.ADULT_SMALL_DOG, - CommonSimType.ADULT_SMALL_DOG_ALIEN: CommonSimType.ADULT_SMALL_DOG, - CommonSimType.ADULT_SMALL_DOG_MERMAID: CommonSimType.ADULT_SMALL_DOG, - CommonSimType.ADULT_SMALL_DOG_WITCH: CommonSimType.ADULT_SMALL_DOG, - CommonSimType.ADULT_SMALL_DOG_ROBOT: CommonSimType.ADULT_SMALL_DOG, - CommonSimType.ADULT_SMALL_DOG_SCARECROW: CommonSimType.ADULT_SMALL_DOG, - CommonSimType.ADULT_SMALL_DOG_SKELETON: CommonSimType.ADULT_SMALL_DOG, - CommonSimType.ADULT_SMALL_DOG_PLANT_SIM: CommonSimType.ADULT_SMALL_DOG, - CommonSimType.ADULT_SMALL_DOG_WEREWOLF: CommonSimType.ADULT_SMALL_DOG, - # Child - CommonSimType.CHILD_SMALL_DOG: CommonSimType.CHILD_SMALL_DOG, - CommonSimType.CHILD_SMALL_DOG_VAMPIRE: CommonSimType.CHILD_SMALL_DOG, - CommonSimType.CHILD_SMALL_DOG_GHOST: CommonSimType.CHILD_SMALL_DOG, - CommonSimType.CHILD_SMALL_DOG_ALIEN: CommonSimType.CHILD_SMALL_DOG, - CommonSimType.CHILD_SMALL_DOG_MERMAID: CommonSimType.CHILD_SMALL_DOG, - CommonSimType.CHILD_SMALL_DOG_WITCH: CommonSimType.CHILD_SMALL_DOG, - CommonSimType.CHILD_SMALL_DOG_ROBOT: CommonSimType.CHILD_SMALL_DOG, - CommonSimType.CHILD_SMALL_DOG_SCARECROW: CommonSimType.CHILD_SMALL_DOG, - CommonSimType.CHILD_SMALL_DOG_SKELETON: CommonSimType.CHILD_SMALL_DOG, - CommonSimType.CHILD_SMALL_DOG_PLANT_SIM: CommonSimType.CHILD_SMALL_DOG, - CommonSimType.CHILD_SMALL_DOG_WEREWOLF: CommonSimType.CHILD_SMALL_DOG, - - # Large Dog - # Elder - CommonSimType.ELDER_LARGE_DOG: CommonSimType.ELDER_LARGE_DOG, - CommonSimType.ELDER_LARGE_DOG_VAMPIRE: CommonSimType.ELDER_LARGE_DOG, - CommonSimType.ELDER_LARGE_DOG_GHOST: CommonSimType.ELDER_LARGE_DOG, - CommonSimType.ELDER_LARGE_DOG_ALIEN: CommonSimType.ELDER_LARGE_DOG, - CommonSimType.ELDER_LARGE_DOG_MERMAID: CommonSimType.ELDER_LARGE_DOG, - CommonSimType.ELDER_LARGE_DOG_WITCH: CommonSimType.ELDER_LARGE_DOG, - CommonSimType.ELDER_LARGE_DOG_ROBOT: CommonSimType.ELDER_LARGE_DOG, - CommonSimType.ELDER_LARGE_DOG_SCARECROW: CommonSimType.ELDER_LARGE_DOG, - CommonSimType.ELDER_LARGE_DOG_SKELETON: CommonSimType.ELDER_LARGE_DOG, - CommonSimType.ELDER_LARGE_DOG_PLANT_SIM: CommonSimType.ELDER_LARGE_DOG, - CommonSimType.ELDER_LARGE_DOG_WEREWOLF: CommonSimType.ELDER_LARGE_DOG, - # Adult - CommonSimType.ADULT_LARGE_DOG: CommonSimType.ADULT_LARGE_DOG, - CommonSimType.ADULT_LARGE_DOG_VAMPIRE: CommonSimType.ADULT_LARGE_DOG, - CommonSimType.ADULT_LARGE_DOG_GHOST: CommonSimType.ADULT_LARGE_DOG, - CommonSimType.ADULT_LARGE_DOG_ALIEN: CommonSimType.ADULT_LARGE_DOG, - CommonSimType.ADULT_LARGE_DOG_MERMAID: CommonSimType.ADULT_LARGE_DOG, - CommonSimType.ADULT_LARGE_DOG_WITCH: CommonSimType.ADULT_LARGE_DOG, - CommonSimType.ADULT_LARGE_DOG_ROBOT: CommonSimType.ADULT_LARGE_DOG, - CommonSimType.ADULT_LARGE_DOG_SCARECROW: CommonSimType.ADULT_LARGE_DOG, - CommonSimType.ADULT_LARGE_DOG_SKELETON: CommonSimType.ADULT_LARGE_DOG, - CommonSimType.ADULT_LARGE_DOG_PLANT_SIM: CommonSimType.ADULT_LARGE_DOG, - CommonSimType.ADULT_LARGE_DOG_WEREWOLF: CommonSimType.ADULT_LARGE_DOG, - # Child - CommonSimType.CHILD_LARGE_DOG: CommonSimType.CHILD_LARGE_DOG, - CommonSimType.CHILD_LARGE_DOG_VAMPIRE: CommonSimType.CHILD_LARGE_DOG, - CommonSimType.CHILD_LARGE_DOG_GHOST: CommonSimType.CHILD_LARGE_DOG, - CommonSimType.CHILD_LARGE_DOG_ALIEN: CommonSimType.CHILD_LARGE_DOG, - CommonSimType.CHILD_LARGE_DOG_MERMAID: CommonSimType.CHILD_LARGE_DOG, - CommonSimType.CHILD_LARGE_DOG_WITCH: CommonSimType.CHILD_LARGE_DOG, - CommonSimType.CHILD_LARGE_DOG_ROBOT: CommonSimType.CHILD_LARGE_DOG, - CommonSimType.CHILD_LARGE_DOG_SCARECROW: CommonSimType.CHILD_LARGE_DOG, - CommonSimType.CHILD_LARGE_DOG_SKELETON: CommonSimType.CHILD_LARGE_DOG, - CommonSimType.CHILD_LARGE_DOG_PLANT_SIM: CommonSimType.CHILD_LARGE_DOG, - CommonSimType.CHILD_LARGE_DOG_WEREWOLF: CommonSimType.CHILD_LARGE_DOG, - - # Cat - # Elder - CommonSimType.ELDER_CAT: CommonSimType.ELDER_CAT, - CommonSimType.ELDER_CAT_VAMPIRE: CommonSimType.ELDER_CAT, - CommonSimType.ELDER_CAT_GHOST: CommonSimType.ELDER_CAT, - CommonSimType.ELDER_CAT_ALIEN: CommonSimType.ELDER_CAT, - CommonSimType.ELDER_CAT_MERMAID: CommonSimType.ELDER_CAT, - CommonSimType.ELDER_CAT_WITCH: CommonSimType.ELDER_CAT, - CommonSimType.ELDER_CAT_ROBOT: CommonSimType.ELDER_CAT, - CommonSimType.ELDER_CAT_SCARECROW: CommonSimType.ELDER_CAT, - CommonSimType.ELDER_CAT_SKELETON: CommonSimType.ELDER_CAT, - CommonSimType.ELDER_CAT_PLANT_SIM: CommonSimType.ELDER_CAT, - CommonSimType.ELDER_CAT_WEREWOLF: CommonSimType.ELDER_CAT, - # Adult - CommonSimType.ADULT_CAT: CommonSimType.ADULT_CAT, - CommonSimType.ADULT_CAT_VAMPIRE: CommonSimType.ADULT_CAT, - CommonSimType.ADULT_CAT_GHOST: CommonSimType.ADULT_CAT, - CommonSimType.ADULT_CAT_ALIEN: CommonSimType.ADULT_CAT, - CommonSimType.ADULT_CAT_MERMAID: CommonSimType.ADULT_CAT, - CommonSimType.ADULT_CAT_WITCH: CommonSimType.ADULT_CAT, - CommonSimType.ADULT_CAT_ROBOT: CommonSimType.ADULT_CAT, - CommonSimType.ADULT_CAT_SCARECROW: CommonSimType.ADULT_CAT, - CommonSimType.ADULT_CAT_SKELETON: CommonSimType.ADULT_CAT, - CommonSimType.ADULT_CAT_PLANT_SIM: CommonSimType.ADULT_CAT, - CommonSimType.ADULT_CAT_WEREWOLF: CommonSimType.ADULT_CAT, - # Child - CommonSimType.CHILD_CAT: CommonSimType.CHILD_CAT, - CommonSimType.CHILD_CAT_VAMPIRE: CommonSimType.CHILD_CAT, - CommonSimType.CHILD_CAT_GHOST: CommonSimType.CHILD_CAT, - CommonSimType.CHILD_CAT_ALIEN: CommonSimType.CHILD_CAT, - CommonSimType.CHILD_CAT_MERMAID: CommonSimType.CHILD_CAT, - CommonSimType.CHILD_CAT_WITCH: CommonSimType.CHILD_CAT, - CommonSimType.CHILD_CAT_ROBOT: CommonSimType.CHILD_CAT, - CommonSimType.CHILD_CAT_SCARECROW: CommonSimType.CHILD_CAT, - CommonSimType.CHILD_CAT_SKELETON: CommonSimType.CHILD_CAT, - CommonSimType.CHILD_CAT_PLANT_SIM: CommonSimType.CHILD_CAT, - CommonSimType.CHILD_CAT_WEREWOLF: CommonSimType.CHILD_CAT, - - # Fox - # Elder - CommonSimType.ELDER_FOX: CommonSimType.ELDER_FOX, - CommonSimType.ELDER_FOX_VAMPIRE: CommonSimType.ELDER_FOX, - CommonSimType.ELDER_FOX_GHOST: CommonSimType.ELDER_FOX, - CommonSimType.ELDER_FOX_ALIEN: CommonSimType.ELDER_FOX, - CommonSimType.ELDER_FOX_MERMAID: CommonSimType.ELDER_FOX, - CommonSimType.ELDER_FOX_WITCH: CommonSimType.ELDER_FOX, - CommonSimType.ELDER_FOX_ROBOT: CommonSimType.ELDER_FOX, - CommonSimType.ELDER_FOX_SCARECROW: CommonSimType.ELDER_FOX, - CommonSimType.ELDER_FOX_SKELETON: CommonSimType.ELDER_FOX, - CommonSimType.ELDER_FOX_PLANT_SIM: CommonSimType.ELDER_FOX, - CommonSimType.ELDER_FOX_WEREWOLF: CommonSimType.ELDER_FOX, - # Adult - CommonSimType.ADULT_FOX: CommonSimType.ADULT_FOX, - CommonSimType.ADULT_FOX_VAMPIRE: CommonSimType.ADULT_FOX, - CommonSimType.ADULT_FOX_GHOST: CommonSimType.ADULT_FOX, - CommonSimType.ADULT_FOX_ALIEN: CommonSimType.ADULT_FOX, - CommonSimType.ADULT_FOX_MERMAID: CommonSimType.ADULT_FOX, - CommonSimType.ADULT_FOX_WITCH: CommonSimType.ADULT_FOX, - CommonSimType.ADULT_FOX_ROBOT: CommonSimType.ADULT_FOX, - CommonSimType.ADULT_FOX_SCARECROW: CommonSimType.ADULT_FOX, - CommonSimType.ADULT_FOX_SKELETON: CommonSimType.ADULT_FOX, - CommonSimType.ADULT_FOX_PLANT_SIM: CommonSimType.ADULT_FOX, - CommonSimType.ADULT_FOX_WEREWOLF: CommonSimType.ADULT_FOX, - # Child - CommonSimType.CHILD_FOX: CommonSimType.CHILD_FOX, - CommonSimType.CHILD_FOX_VAMPIRE: CommonSimType.CHILD_FOX, - CommonSimType.CHILD_FOX_GHOST: CommonSimType.CHILD_FOX, - CommonSimType.CHILD_FOX_ALIEN: CommonSimType.CHILD_FOX, - CommonSimType.CHILD_FOX_MERMAID: CommonSimType.CHILD_FOX, - CommonSimType.CHILD_FOX_WITCH: CommonSimType.CHILD_FOX, - CommonSimType.CHILD_FOX_ROBOT: CommonSimType.CHILD_FOX, - CommonSimType.CHILD_FOX_SCARECROW: CommonSimType.CHILD_FOX, - CommonSimType.CHILD_FOX_SKELETON: CommonSimType.CHILD_FOX, - CommonSimType.CHILD_FOX_PLANT_SIM: CommonSimType.CHILD_FOX, - CommonSimType.CHILD_FOX_WEREWOLF: CommonSimType.CHILD_FOX, - - # Horse - # Elder - CommonSimType.ELDER_HORSE: CommonSimType.ELDER_HORSE, - CommonSimType.ELDER_HORSE_VAMPIRE: CommonSimType.ELDER_HORSE, - CommonSimType.ELDER_HORSE_GHOST: CommonSimType.ELDER_HORSE, - CommonSimType.ELDER_HORSE_ALIEN: CommonSimType.ELDER_HORSE, - CommonSimType.ELDER_HORSE_MERMAID: CommonSimType.ELDER_HORSE, - CommonSimType.ELDER_HORSE_WITCH: CommonSimType.ELDER_HORSE, - CommonSimType.ELDER_HORSE_ROBOT: CommonSimType.ELDER_HORSE, - CommonSimType.ELDER_HORSE_SCARECROW: CommonSimType.ELDER_HORSE, - CommonSimType.ELDER_HORSE_SKELETON: CommonSimType.ELDER_HORSE, - CommonSimType.ELDER_HORSE_PLANT_SIM: CommonSimType.ELDER_HORSE, - CommonSimType.ELDER_HORSE_WEREWOLF: CommonSimType.ELDER_HORSE, - # Adult - CommonSimType.ADULT_HORSE: CommonSimType.ADULT_HORSE, - CommonSimType.ADULT_HORSE_VAMPIRE: CommonSimType.ADULT_HORSE, - CommonSimType.ADULT_HORSE_GHOST: CommonSimType.ADULT_HORSE, - CommonSimType.ADULT_HORSE_ALIEN: CommonSimType.ADULT_HORSE, - CommonSimType.ADULT_HORSE_MERMAID: CommonSimType.ADULT_HORSE, - CommonSimType.ADULT_HORSE_WITCH: CommonSimType.ADULT_HORSE, - CommonSimType.ADULT_HORSE_ROBOT: CommonSimType.ADULT_HORSE, - CommonSimType.ADULT_HORSE_SCARECROW: CommonSimType.ADULT_HORSE, - CommonSimType.ADULT_HORSE_SKELETON: CommonSimType.ADULT_HORSE, - CommonSimType.ADULT_HORSE_PLANT_SIM: CommonSimType.ADULT_HORSE, - CommonSimType.ADULT_HORSE_WEREWOLF: CommonSimType.ADULT_HORSE, - # Child - CommonSimType.CHILD_HORSE: CommonSimType.CHILD_HORSE, - CommonSimType.CHILD_HORSE_VAMPIRE: CommonSimType.CHILD_HORSE, - CommonSimType.CHILD_HORSE_GHOST: CommonSimType.CHILD_HORSE, - CommonSimType.CHILD_HORSE_ALIEN: CommonSimType.CHILD_HORSE, - CommonSimType.CHILD_HORSE_MERMAID: CommonSimType.CHILD_HORSE, - CommonSimType.CHILD_HORSE_WITCH: CommonSimType.CHILD_HORSE, - CommonSimType.CHILD_HORSE_ROBOT: CommonSimType.CHILD_HORSE, - CommonSimType.CHILD_HORSE_SCARECROW: CommonSimType.CHILD_HORSE, - CommonSimType.CHILD_HORSE_SKELETON: CommonSimType.CHILD_HORSE, - CommonSimType.CHILD_HORSE_PLANT_SIM: CommonSimType.CHILD_HORSE, - CommonSimType.CHILD_HORSE_WEREWOLF: CommonSimType.CHILD_HORSE, - } - - _OCCULT_SIM_TYPE_TO_OCCULT_TYPE_MAPPING: Dict[CommonSimType, CommonOccultType] = { - # Human - # Elder - CommonSimType.ELDER_HUMAN: CommonOccultType.NON_OCCULT, - CommonSimType.ELDER_HUMAN_VAMPIRE: CommonOccultType.VAMPIRE, - CommonSimType.ELDER_HUMAN_GHOST: CommonOccultType.GHOST, - CommonSimType.ELDER_HUMAN_ALIEN: CommonOccultType.ALIEN, - CommonSimType.ELDER_HUMAN_MERMAID: CommonOccultType.MERMAID, - CommonSimType.ELDER_HUMAN_WITCH: CommonOccultType.WITCH, - CommonSimType.ELDER_HUMAN_ROBOT: CommonOccultType.ROBOT, - CommonSimType.ELDER_HUMAN_SCARECROW: CommonOccultType.SCARECROW, - CommonSimType.ELDER_HUMAN_SKELETON: CommonOccultType.SKELETON, - CommonSimType.ELDER_HUMAN_PLANT_SIM: CommonOccultType.PLANT_SIM, - CommonSimType.ELDER_HUMAN_WEREWOLF: CommonOccultType.WEREWOLF, - # Adult - CommonSimType.ADULT_HUMAN: CommonOccultType.NON_OCCULT, - CommonSimType.ADULT_HUMAN_VAMPIRE: CommonOccultType.VAMPIRE, - CommonSimType.ADULT_HUMAN_GHOST: CommonOccultType.GHOST, - CommonSimType.ADULT_HUMAN_ALIEN: CommonOccultType.ALIEN, - CommonSimType.ADULT_HUMAN_MERMAID: CommonOccultType.MERMAID, - CommonSimType.ADULT_HUMAN_WITCH: CommonOccultType.WITCH, - CommonSimType.ADULT_HUMAN_ROBOT: CommonOccultType.ROBOT, - CommonSimType.ADULT_HUMAN_SCARECROW: CommonOccultType.SCARECROW, - CommonSimType.ADULT_HUMAN_SKELETON: CommonOccultType.SKELETON, - CommonSimType.ADULT_HUMAN_PLANT_SIM: CommonOccultType.PLANT_SIM, - CommonSimType.ADULT_HUMAN_WEREWOLF: CommonOccultType.WEREWOLF, - # Young Adult - CommonSimType.YOUNG_ADULT_HUMAN: CommonOccultType.NON_OCCULT, - CommonSimType.YOUNG_ADULT_HUMAN_VAMPIRE: CommonOccultType.VAMPIRE, - CommonSimType.YOUNG_ADULT_HUMAN_GHOST: CommonOccultType.GHOST, - CommonSimType.YOUNG_ADULT_HUMAN_ALIEN: CommonOccultType.ALIEN, - CommonSimType.YOUNG_ADULT_HUMAN_MERMAID: CommonOccultType.MERMAID, - CommonSimType.YOUNG_ADULT_HUMAN_WITCH: CommonOccultType.WITCH, - CommonSimType.YOUNG_ADULT_HUMAN_ROBOT: CommonOccultType.ROBOT, - CommonSimType.YOUNG_ADULT_HUMAN_SCARECROW: CommonOccultType.SCARECROW, - CommonSimType.YOUNG_ADULT_HUMAN_SKELETON: CommonOccultType.SKELETON, - CommonSimType.YOUNG_ADULT_HUMAN_PLANT_SIM: CommonOccultType.PLANT_SIM, - CommonSimType.YOUNG_ADULT_HUMAN_WEREWOLF: CommonOccultType.WEREWOLF, - # Teen - CommonSimType.TEEN_HUMAN: CommonOccultType.NON_OCCULT, - CommonSimType.TEEN_HUMAN_VAMPIRE: CommonOccultType.VAMPIRE, - CommonSimType.TEEN_HUMAN_GHOST: CommonOccultType.GHOST, - CommonSimType.TEEN_HUMAN_ALIEN: CommonOccultType.ALIEN, - CommonSimType.TEEN_HUMAN_MERMAID: CommonOccultType.MERMAID, - CommonSimType.TEEN_HUMAN_WITCH: CommonOccultType.WITCH, - CommonSimType.TEEN_HUMAN_ROBOT: CommonOccultType.ROBOT, - CommonSimType.TEEN_HUMAN_SCARECROW: CommonOccultType.SCARECROW, - CommonSimType.TEEN_HUMAN_SKELETON: CommonOccultType.SKELETON, - CommonSimType.TEEN_HUMAN_PLANT_SIM: CommonOccultType.PLANT_SIM, - CommonSimType.TEEN_HUMAN_WEREWOLF: CommonOccultType.WEREWOLF, - # Child - CommonSimType.CHILD_HUMAN: CommonOccultType.NON_OCCULT, - CommonSimType.CHILD_HUMAN_VAMPIRE: CommonOccultType.VAMPIRE, - CommonSimType.CHILD_HUMAN_GHOST: CommonOccultType.GHOST, - CommonSimType.CHILD_HUMAN_ALIEN: CommonOccultType.ALIEN, - CommonSimType.CHILD_HUMAN_MERMAID: CommonOccultType.MERMAID, - CommonSimType.CHILD_HUMAN_WITCH: CommonOccultType.WITCH, - CommonSimType.CHILD_HUMAN_ROBOT: CommonOccultType.ROBOT, - CommonSimType.CHILD_HUMAN_SCARECROW: CommonOccultType.SCARECROW, - CommonSimType.CHILD_HUMAN_SKELETON: CommonOccultType.SKELETON, - CommonSimType.CHILD_HUMAN_PLANT_SIM: CommonOccultType.PLANT_SIM, - CommonSimType.CHILD_HUMAN_WEREWOLF: CommonOccultType.WEREWOLF, - # Toddler - CommonSimType.TODDLER_HUMAN: CommonOccultType.NON_OCCULT, - CommonSimType.TODDLER_HUMAN_VAMPIRE: CommonOccultType.VAMPIRE, - CommonSimType.TODDLER_HUMAN_GHOST: CommonOccultType.GHOST, - CommonSimType.TODDLER_HUMAN_ALIEN: CommonOccultType.ALIEN, - CommonSimType.TODDLER_HUMAN_MERMAID: CommonOccultType.MERMAID, - CommonSimType.TODDLER_HUMAN_WITCH: CommonOccultType.WITCH, - CommonSimType.TODDLER_HUMAN_ROBOT: CommonOccultType.ROBOT, - CommonSimType.TODDLER_HUMAN_SCARECROW: CommonOccultType.SCARECROW, - CommonSimType.TODDLER_HUMAN_SKELETON: CommonOccultType.SKELETON, - CommonSimType.TODDLER_HUMAN_PLANT_SIM: CommonOccultType.PLANT_SIM, - CommonSimType.TODDLER_HUMAN_WEREWOLF: CommonOccultType.WEREWOLF, - # Infant - CommonSimType.INFANT_HUMAN: CommonOccultType.NON_OCCULT, - CommonSimType.INFANT_HUMAN_VAMPIRE: CommonOccultType.VAMPIRE, - CommonSimType.INFANT_HUMAN_GHOST: CommonOccultType.GHOST, - CommonSimType.INFANT_HUMAN_ALIEN: CommonOccultType.ALIEN, - CommonSimType.INFANT_HUMAN_MERMAID: CommonOccultType.MERMAID, - CommonSimType.INFANT_HUMAN_WITCH: CommonOccultType.WITCH, - CommonSimType.INFANT_HUMAN_ROBOT: CommonOccultType.ROBOT, - CommonSimType.INFANT_HUMAN_SCARECROW: CommonOccultType.SCARECROW, - CommonSimType.INFANT_HUMAN_SKELETON: CommonOccultType.SKELETON, - CommonSimType.INFANT_HUMAN_PLANT_SIM: CommonOccultType.PLANT_SIM, - CommonSimType.INFANT_HUMAN_WEREWOLF: CommonOccultType.WEREWOLF, - # Baby - CommonSimType.BABY_HUMAN: CommonOccultType.NON_OCCULT, - CommonSimType.BABY_HUMAN_VAMPIRE: CommonOccultType.VAMPIRE, - CommonSimType.BABY_HUMAN_GHOST: CommonOccultType.GHOST, - CommonSimType.BABY_HUMAN_ALIEN: CommonOccultType.ALIEN, - CommonSimType.BABY_HUMAN_MERMAID: CommonOccultType.MERMAID, - CommonSimType.BABY_HUMAN_WITCH: CommonOccultType.WITCH, - CommonSimType.BABY_HUMAN_ROBOT: CommonOccultType.ROBOT, - CommonSimType.BABY_HUMAN_SCARECROW: CommonOccultType.SCARECROW, - CommonSimType.BABY_HUMAN_SKELETON: CommonOccultType.SKELETON, - CommonSimType.BABY_HUMAN_PLANT_SIM: CommonOccultType.PLANT_SIM, - CommonSimType.BABY_HUMAN_WEREWOLF: CommonOccultType.WEREWOLF, - - # Dog - # Child - CommonSimType.CHILD_DOG: CommonOccultType.NON_OCCULT, - CommonSimType.CHILD_DOG_VAMPIRE: CommonOccultType.VAMPIRE, - CommonSimType.CHILD_DOG_GHOST: CommonOccultType.GHOST, - CommonSimType.CHILD_DOG_ALIEN: CommonOccultType.ALIEN, - CommonSimType.CHILD_DOG_MERMAID: CommonOccultType.MERMAID, - CommonSimType.CHILD_DOG_WITCH: CommonOccultType.WITCH, - CommonSimType.CHILD_DOG_ROBOT: CommonOccultType.ROBOT, - CommonSimType.CHILD_DOG_SCARECROW: CommonOccultType.SCARECROW, - CommonSimType.CHILD_DOG_SKELETON: CommonOccultType.SKELETON, - CommonSimType.CHILD_DOG_PLANT_SIM: CommonOccultType.PLANT_SIM, - CommonSimType.CHILD_DOG_WEREWOLF: CommonOccultType.WEREWOLF, - - # Small Dog - # Elder - CommonSimType.ELDER_SMALL_DOG: CommonOccultType.NON_OCCULT, - CommonSimType.ELDER_SMALL_DOG_VAMPIRE: CommonOccultType.VAMPIRE, - CommonSimType.ELDER_SMALL_DOG_GHOST: CommonOccultType.GHOST, - CommonSimType.ELDER_SMALL_DOG_ALIEN: CommonOccultType.ALIEN, - CommonSimType.ELDER_SMALL_DOG_MERMAID: CommonOccultType.MERMAID, - CommonSimType.ELDER_SMALL_DOG_WITCH: CommonOccultType.WITCH, - CommonSimType.ELDER_SMALL_DOG_ROBOT: CommonOccultType.ROBOT, - CommonSimType.ELDER_SMALL_DOG_SCARECROW: CommonOccultType.SCARECROW, - CommonSimType.ELDER_SMALL_DOG_SKELETON: CommonOccultType.SKELETON, - CommonSimType.ELDER_SMALL_DOG_PLANT_SIM: CommonOccultType.PLANT_SIM, - CommonSimType.ELDER_SMALL_DOG_WEREWOLF: CommonOccultType.WEREWOLF, - # Adult - CommonSimType.ADULT_SMALL_DOG: CommonOccultType.NON_OCCULT, - CommonSimType.ADULT_SMALL_DOG_VAMPIRE: CommonOccultType.VAMPIRE, - CommonSimType.ADULT_SMALL_DOG_GHOST: CommonOccultType.GHOST, - CommonSimType.ADULT_SMALL_DOG_ALIEN: CommonOccultType.ALIEN, - CommonSimType.ADULT_SMALL_DOG_MERMAID: CommonOccultType.MERMAID, - CommonSimType.ADULT_SMALL_DOG_WITCH: CommonOccultType.WITCH, - CommonSimType.ADULT_SMALL_DOG_ROBOT: CommonOccultType.ROBOT, - CommonSimType.ADULT_SMALL_DOG_SCARECROW: CommonOccultType.SCARECROW, - CommonSimType.ADULT_SMALL_DOG_SKELETON: CommonOccultType.SKELETON, - CommonSimType.ADULT_SMALL_DOG_PLANT_SIM: CommonOccultType.PLANT_SIM, - CommonSimType.ADULT_SMALL_DOG_WEREWOLF: CommonOccultType.WEREWOLF, - # Child - CommonSimType.CHILD_SMALL_DOG: CommonOccultType.NON_OCCULT, - CommonSimType.CHILD_SMALL_DOG_VAMPIRE: CommonOccultType.VAMPIRE, - CommonSimType.CHILD_SMALL_DOG_GHOST: CommonOccultType.GHOST, - CommonSimType.CHILD_SMALL_DOG_ALIEN: CommonOccultType.ALIEN, - CommonSimType.CHILD_SMALL_DOG_MERMAID: CommonOccultType.MERMAID, - CommonSimType.CHILD_SMALL_DOG_WITCH: CommonOccultType.WITCH, - CommonSimType.CHILD_SMALL_DOG_ROBOT: CommonOccultType.ROBOT, - CommonSimType.CHILD_SMALL_DOG_SCARECROW: CommonOccultType.SCARECROW, - CommonSimType.CHILD_SMALL_DOG_SKELETON: CommonOccultType.SKELETON, - CommonSimType.CHILD_SMALL_DOG_PLANT_SIM: CommonOccultType.PLANT_SIM, - CommonSimType.CHILD_SMALL_DOG_WEREWOLF: CommonOccultType.WEREWOLF, - - # Large Dog - # Elder - CommonSimType.ELDER_LARGE_DOG: CommonOccultType.NON_OCCULT, - CommonSimType.ELDER_LARGE_DOG_VAMPIRE: CommonOccultType.VAMPIRE, - CommonSimType.ELDER_LARGE_DOG_GHOST: CommonOccultType.GHOST, - CommonSimType.ELDER_LARGE_DOG_ALIEN: CommonOccultType.ALIEN, - CommonSimType.ELDER_LARGE_DOG_MERMAID: CommonOccultType.MERMAID, - CommonSimType.ELDER_LARGE_DOG_WITCH: CommonOccultType.WITCH, - CommonSimType.ELDER_LARGE_DOG_ROBOT: CommonOccultType.ROBOT, - CommonSimType.ELDER_LARGE_DOG_SCARECROW: CommonOccultType.SCARECROW, - CommonSimType.ELDER_LARGE_DOG_SKELETON: CommonOccultType.SKELETON, - CommonSimType.ELDER_LARGE_DOG_PLANT_SIM: CommonOccultType.PLANT_SIM, - CommonSimType.ELDER_LARGE_DOG_WEREWOLF: CommonOccultType.WEREWOLF, - # Adult - CommonSimType.ADULT_LARGE_DOG: CommonOccultType.NON_OCCULT, - CommonSimType.ADULT_LARGE_DOG_VAMPIRE: CommonOccultType.VAMPIRE, - CommonSimType.ADULT_LARGE_DOG_GHOST: CommonOccultType.GHOST, - CommonSimType.ADULT_LARGE_DOG_ALIEN: CommonOccultType.ALIEN, - CommonSimType.ADULT_LARGE_DOG_MERMAID: CommonOccultType.MERMAID, - CommonSimType.ADULT_LARGE_DOG_WITCH: CommonOccultType.WITCH, - CommonSimType.ADULT_LARGE_DOG_ROBOT: CommonOccultType.ROBOT, - CommonSimType.ADULT_LARGE_DOG_SCARECROW: CommonOccultType.SCARECROW, - CommonSimType.ADULT_LARGE_DOG_SKELETON: CommonOccultType.SKELETON, - CommonSimType.ADULT_LARGE_DOG_PLANT_SIM: CommonOccultType.PLANT_SIM, - CommonSimType.ADULT_LARGE_DOG_WEREWOLF: CommonOccultType.WEREWOLF, - # Child - CommonSimType.CHILD_LARGE_DOG: CommonOccultType.NON_OCCULT, - CommonSimType.CHILD_LARGE_DOG_VAMPIRE: CommonOccultType.VAMPIRE, - CommonSimType.CHILD_LARGE_DOG_GHOST: CommonOccultType.GHOST, - CommonSimType.CHILD_LARGE_DOG_ALIEN: CommonOccultType.ALIEN, - CommonSimType.CHILD_LARGE_DOG_MERMAID: CommonOccultType.MERMAID, - CommonSimType.CHILD_LARGE_DOG_WITCH: CommonOccultType.WITCH, - CommonSimType.CHILD_LARGE_DOG_ROBOT: CommonOccultType.ROBOT, - CommonSimType.CHILD_LARGE_DOG_SCARECROW: CommonOccultType.SCARECROW, - CommonSimType.CHILD_LARGE_DOG_SKELETON: CommonOccultType.SKELETON, - CommonSimType.CHILD_LARGE_DOG_PLANT_SIM: CommonOccultType.PLANT_SIM, - CommonSimType.CHILD_LARGE_DOG_WEREWOLF: CommonOccultType.WEREWOLF, - - # Cat - # Elder - CommonSimType.ELDER_CAT: CommonOccultType.NON_OCCULT, - CommonSimType.ELDER_CAT_VAMPIRE: CommonOccultType.VAMPIRE, - CommonSimType.ELDER_CAT_GHOST: CommonOccultType.GHOST, - CommonSimType.ELDER_CAT_ALIEN: CommonOccultType.ALIEN, - CommonSimType.ELDER_CAT_MERMAID: CommonOccultType.MERMAID, - CommonSimType.ELDER_CAT_WITCH: CommonOccultType.WITCH, - CommonSimType.ELDER_CAT_ROBOT: CommonOccultType.ROBOT, - CommonSimType.ELDER_CAT_SCARECROW: CommonOccultType.SCARECROW, - CommonSimType.ELDER_CAT_SKELETON: CommonOccultType.SKELETON, - CommonSimType.ELDER_CAT_PLANT_SIM: CommonOccultType.PLANT_SIM, - CommonSimType.ELDER_CAT_WEREWOLF: CommonOccultType.WEREWOLF, - # Adult - CommonSimType.ADULT_CAT: CommonOccultType.NON_OCCULT, - CommonSimType.ADULT_CAT_VAMPIRE: CommonOccultType.VAMPIRE, - CommonSimType.ADULT_CAT_GHOST: CommonOccultType.GHOST, - CommonSimType.ADULT_CAT_ALIEN: CommonOccultType.ALIEN, - CommonSimType.ADULT_CAT_MERMAID: CommonOccultType.MERMAID, - CommonSimType.ADULT_CAT_WITCH: CommonOccultType.WITCH, - CommonSimType.ADULT_CAT_ROBOT: CommonOccultType.ROBOT, - CommonSimType.ADULT_CAT_SCARECROW: CommonOccultType.SCARECROW, - CommonSimType.ADULT_CAT_SKELETON: CommonOccultType.SKELETON, - CommonSimType.ADULT_CAT_PLANT_SIM: CommonOccultType.PLANT_SIM, - CommonSimType.ADULT_CAT_WEREWOLF: CommonOccultType.WEREWOLF, - # Child - CommonSimType.CHILD_CAT: CommonOccultType.NON_OCCULT, - CommonSimType.CHILD_CAT_VAMPIRE: CommonOccultType.VAMPIRE, - CommonSimType.CHILD_CAT_GHOST: CommonOccultType.GHOST, - CommonSimType.CHILD_CAT_ALIEN: CommonOccultType.ALIEN, - CommonSimType.CHILD_CAT_MERMAID: CommonOccultType.MERMAID, - CommonSimType.CHILD_CAT_WITCH: CommonOccultType.WITCH, - CommonSimType.CHILD_CAT_ROBOT: CommonOccultType.ROBOT, - CommonSimType.CHILD_CAT_SCARECROW: CommonOccultType.SCARECROW, - CommonSimType.CHILD_CAT_SKELETON: CommonOccultType.SKELETON, - CommonSimType.CHILD_CAT_PLANT_SIM: CommonOccultType.PLANT_SIM, - CommonSimType.CHILD_CAT_WEREWOLF: CommonOccultType.WEREWOLF, - - # Fox - # Elder - CommonSimType.ELDER_FOX: CommonOccultType.NON_OCCULT, - CommonSimType.ELDER_FOX_VAMPIRE: CommonOccultType.VAMPIRE, - CommonSimType.ELDER_FOX_GHOST: CommonOccultType.GHOST, - CommonSimType.ELDER_FOX_ALIEN: CommonOccultType.ALIEN, - CommonSimType.ELDER_FOX_MERMAID: CommonOccultType.MERMAID, - CommonSimType.ELDER_FOX_WITCH: CommonOccultType.WITCH, - CommonSimType.ELDER_FOX_ROBOT: CommonOccultType.ROBOT, - CommonSimType.ELDER_FOX_SCARECROW: CommonOccultType.SCARECROW, - CommonSimType.ELDER_FOX_SKELETON: CommonOccultType.SKELETON, - CommonSimType.ELDER_FOX_PLANT_SIM: CommonOccultType.PLANT_SIM, - CommonSimType.ELDER_FOX_WEREWOLF: CommonOccultType.WEREWOLF, - # Adult - CommonSimType.ADULT_FOX: CommonOccultType.NON_OCCULT, - CommonSimType.ADULT_FOX_VAMPIRE: CommonOccultType.VAMPIRE, - CommonSimType.ADULT_FOX_GHOST: CommonOccultType.GHOST, - CommonSimType.ADULT_FOX_ALIEN: CommonOccultType.ALIEN, - CommonSimType.ADULT_FOX_MERMAID: CommonOccultType.MERMAID, - CommonSimType.ADULT_FOX_WITCH: CommonOccultType.WITCH, - CommonSimType.ADULT_FOX_ROBOT: CommonOccultType.ROBOT, - CommonSimType.ADULT_FOX_SCARECROW: CommonOccultType.SCARECROW, - CommonSimType.ADULT_FOX_SKELETON: CommonOccultType.SKELETON, - CommonSimType.ADULT_FOX_PLANT_SIM: CommonOccultType.PLANT_SIM, - CommonSimType.ADULT_FOX_WEREWOLF: CommonOccultType.WEREWOLF, - # Child - CommonSimType.CHILD_FOX: CommonOccultType.NON_OCCULT, - CommonSimType.CHILD_FOX_VAMPIRE: CommonOccultType.VAMPIRE, - CommonSimType.CHILD_FOX_GHOST: CommonOccultType.GHOST, - CommonSimType.CHILD_FOX_ALIEN: CommonOccultType.ALIEN, - CommonSimType.CHILD_FOX_MERMAID: CommonOccultType.MERMAID, - CommonSimType.CHILD_FOX_WITCH: CommonOccultType.WITCH, - CommonSimType.CHILD_FOX_ROBOT: CommonOccultType.ROBOT, - CommonSimType.CHILD_FOX_SCARECROW: CommonOccultType.SCARECROW, - CommonSimType.CHILD_FOX_SKELETON: CommonOccultType.SKELETON, - CommonSimType.CHILD_FOX_PLANT_SIM: CommonOccultType.PLANT_SIM, - CommonSimType.CHILD_FOX_WEREWOLF: CommonOccultType.WEREWOLF, - - # Horse - # Elder - CommonSimType.ELDER_HORSE: CommonOccultType.NON_OCCULT, - CommonSimType.ELDER_HORSE_VAMPIRE: CommonOccultType.VAMPIRE, - CommonSimType.ELDER_HORSE_GHOST: CommonOccultType.GHOST, - CommonSimType.ELDER_HORSE_ALIEN: CommonOccultType.ALIEN, - CommonSimType.ELDER_HORSE_MERMAID: CommonOccultType.MERMAID, - CommonSimType.ELDER_HORSE_WITCH: CommonOccultType.WITCH, - CommonSimType.ELDER_HORSE_ROBOT: CommonOccultType.ROBOT, - CommonSimType.ELDER_HORSE_SCARECROW: CommonOccultType.SCARECROW, - CommonSimType.ELDER_HORSE_SKELETON: CommonOccultType.SKELETON, - CommonSimType.ELDER_HORSE_PLANT_SIM: CommonOccultType.PLANT_SIM, - CommonSimType.ELDER_HORSE_WEREWOLF: CommonOccultType.WEREWOLF, - # Adult - CommonSimType.ADULT_HORSE: CommonOccultType.NON_OCCULT, - CommonSimType.ADULT_HORSE_VAMPIRE: CommonOccultType.VAMPIRE, - CommonSimType.ADULT_HORSE_GHOST: CommonOccultType.GHOST, - CommonSimType.ADULT_HORSE_ALIEN: CommonOccultType.ALIEN, - CommonSimType.ADULT_HORSE_MERMAID: CommonOccultType.MERMAID, - CommonSimType.ADULT_HORSE_WITCH: CommonOccultType.WITCH, - CommonSimType.ADULT_HORSE_ROBOT: CommonOccultType.ROBOT, - CommonSimType.ADULT_HORSE_SCARECROW: CommonOccultType.SCARECROW, - CommonSimType.ADULT_HORSE_SKELETON: CommonOccultType.SKELETON, - CommonSimType.ADULT_HORSE_PLANT_SIM: CommonOccultType.PLANT_SIM, - CommonSimType.ADULT_HORSE_WEREWOLF: CommonOccultType.WEREWOLF, - # Child - CommonSimType.CHILD_HORSE: CommonOccultType.NON_OCCULT, - CommonSimType.CHILD_HORSE_VAMPIRE: CommonOccultType.VAMPIRE, - CommonSimType.CHILD_HORSE_GHOST: CommonOccultType.GHOST, - CommonSimType.CHILD_HORSE_ALIEN: CommonOccultType.ALIEN, - CommonSimType.CHILD_HORSE_MERMAID: CommonOccultType.MERMAID, - CommonSimType.CHILD_HORSE_WITCH: CommonOccultType.WITCH, - CommonSimType.CHILD_HORSE_ROBOT: CommonOccultType.ROBOT, - CommonSimType.CHILD_HORSE_SCARECROW: CommonOccultType.SCARECROW, - CommonSimType.CHILD_HORSE_SKELETON: CommonOccultType.SKELETON, - CommonSimType.CHILD_HORSE_PLANT_SIM: CommonOccultType.PLANT_SIM, - CommonSimType.CHILD_HORSE_WEREWOLF: CommonOccultType.WEREWOLF, - } - - _OCCULT_SIM_TYPE_TO_AGE_MAPPING: Dict[CommonSimType, CommonAge] = { - # Human - # Elder - CommonSimType.ELDER_HUMAN: CommonAge.ELDER, - CommonSimType.ELDER_HUMAN_VAMPIRE: CommonAge.ELDER, - CommonSimType.ELDER_HUMAN_GHOST: CommonAge.ELDER, - CommonSimType.ELDER_HUMAN_ALIEN: CommonAge.ELDER, - CommonSimType.ELDER_HUMAN_MERMAID: CommonAge.ELDER, - CommonSimType.ELDER_HUMAN_WITCH: CommonAge.ELDER, - CommonSimType.ELDER_HUMAN_ROBOT: CommonAge.ELDER, - CommonSimType.ELDER_HUMAN_SCARECROW: CommonAge.ELDER, - CommonSimType.ELDER_HUMAN_SKELETON: CommonAge.ELDER, - CommonSimType.ELDER_HUMAN_PLANT_SIM: CommonAge.ELDER, - CommonSimType.ELDER_HUMAN_WEREWOLF: CommonAge.ELDER, - # Adult - CommonSimType.ADULT_HUMAN: CommonAge.ADULT, - CommonSimType.ADULT_HUMAN_VAMPIRE: CommonAge.ADULT, - CommonSimType.ADULT_HUMAN_GHOST: CommonAge.ADULT, - CommonSimType.ADULT_HUMAN_ALIEN: CommonAge.ADULT, - CommonSimType.ADULT_HUMAN_MERMAID: CommonAge.ADULT, - CommonSimType.ADULT_HUMAN_WITCH: CommonAge.ADULT, - CommonSimType.ADULT_HUMAN_ROBOT: CommonAge.ADULT, - CommonSimType.ADULT_HUMAN_SCARECROW: CommonAge.ADULT, - CommonSimType.ADULT_HUMAN_SKELETON: CommonAge.ADULT, - CommonSimType.ADULT_HUMAN_PLANT_SIM: CommonAge.ADULT, - CommonSimType.ADULT_HUMAN_WEREWOLF: CommonAge.ADULT, - # Young Adult - CommonSimType.YOUNG_ADULT_HUMAN: CommonAge.YOUNGADULT, - CommonSimType.YOUNG_ADULT_HUMAN_VAMPIRE: CommonAge.YOUNGADULT, - CommonSimType.YOUNG_ADULT_HUMAN_GHOST: CommonAge.YOUNGADULT, - CommonSimType.YOUNG_ADULT_HUMAN_ALIEN: CommonAge.YOUNGADULT, - CommonSimType.YOUNG_ADULT_HUMAN_MERMAID: CommonAge.YOUNGADULT, - CommonSimType.YOUNG_ADULT_HUMAN_WITCH: CommonAge.YOUNGADULT, - CommonSimType.YOUNG_ADULT_HUMAN_ROBOT: CommonAge.YOUNGADULT, - CommonSimType.YOUNG_ADULT_HUMAN_SCARECROW: CommonAge.YOUNGADULT, - CommonSimType.YOUNG_ADULT_HUMAN_SKELETON: CommonAge.YOUNGADULT, - CommonSimType.YOUNG_ADULT_HUMAN_PLANT_SIM: CommonAge.YOUNGADULT, - CommonSimType.YOUNG_ADULT_HUMAN_WEREWOLF: CommonAge.YOUNGADULT, - # Teen - CommonSimType.TEEN_HUMAN: CommonAge.TEEN, - CommonSimType.TEEN_HUMAN_VAMPIRE: CommonAge.TEEN, - CommonSimType.TEEN_HUMAN_GHOST: CommonAge.TEEN, - CommonSimType.TEEN_HUMAN_ALIEN: CommonAge.TEEN, - CommonSimType.TEEN_HUMAN_MERMAID: CommonAge.TEEN, - CommonSimType.TEEN_HUMAN_WITCH: CommonAge.TEEN, - CommonSimType.TEEN_HUMAN_ROBOT: CommonAge.TEEN, - CommonSimType.TEEN_HUMAN_SCARECROW: CommonAge.TEEN, - CommonSimType.TEEN_HUMAN_SKELETON: CommonAge.TEEN, - CommonSimType.TEEN_HUMAN_PLANT_SIM: CommonAge.TEEN, - CommonSimType.TEEN_HUMAN_WEREWOLF: CommonAge.TEEN, - # Child - CommonSimType.CHILD_HUMAN: CommonAge.CHILD, - CommonSimType.CHILD_HUMAN_VAMPIRE: CommonAge.CHILD, - CommonSimType.CHILD_HUMAN_GHOST: CommonAge.CHILD, - CommonSimType.CHILD_HUMAN_ALIEN: CommonAge.CHILD, - CommonSimType.CHILD_HUMAN_MERMAID: CommonAge.CHILD, - CommonSimType.CHILD_HUMAN_WITCH: CommonAge.CHILD, - CommonSimType.CHILD_HUMAN_ROBOT: CommonAge.CHILD, - CommonSimType.CHILD_HUMAN_SCARECROW: CommonAge.CHILD, - CommonSimType.CHILD_HUMAN_SKELETON: CommonAge.CHILD, - CommonSimType.CHILD_HUMAN_PLANT_SIM: CommonAge.CHILD, - CommonSimType.CHILD_HUMAN_WEREWOLF: CommonAge.CHILD, - # Toddler - CommonSimType.TODDLER_HUMAN: CommonAge.TODDLER, - CommonSimType.TODDLER_HUMAN_VAMPIRE: CommonAge.TODDLER, - CommonSimType.TODDLER_HUMAN_GHOST: CommonAge.TODDLER, - CommonSimType.TODDLER_HUMAN_ALIEN: CommonAge.TODDLER, - CommonSimType.TODDLER_HUMAN_MERMAID: CommonAge.TODDLER, - CommonSimType.TODDLER_HUMAN_WITCH: CommonAge.TODDLER, - CommonSimType.TODDLER_HUMAN_ROBOT: CommonAge.TODDLER, - CommonSimType.TODDLER_HUMAN_SCARECROW: CommonAge.TODDLER, - CommonSimType.TODDLER_HUMAN_SKELETON: CommonAge.TODDLER, - CommonSimType.TODDLER_HUMAN_PLANT_SIM: CommonAge.TODDLER, - CommonSimType.TODDLER_HUMAN_WEREWOLF: CommonAge.TODDLER, - # Infant - CommonSimType.INFANT_HUMAN: CommonAge.INFANT, - CommonSimType.INFANT_HUMAN_VAMPIRE: CommonAge.INFANT, - CommonSimType.INFANT_HUMAN_GHOST: CommonAge.INFANT, - CommonSimType.INFANT_HUMAN_ALIEN: CommonAge.INFANT, - CommonSimType.INFANT_HUMAN_MERMAID: CommonAge.INFANT, - CommonSimType.INFANT_HUMAN_WITCH: CommonAge.INFANT, - CommonSimType.INFANT_HUMAN_ROBOT: CommonAge.INFANT, - CommonSimType.INFANT_HUMAN_SCARECROW: CommonAge.INFANT, - CommonSimType.INFANT_HUMAN_SKELETON: CommonAge.INFANT, - CommonSimType.INFANT_HUMAN_PLANT_SIM: CommonAge.INFANT, - CommonSimType.INFANT_HUMAN_WEREWOLF: CommonAge.INFANT, - # Baby - CommonSimType.BABY_HUMAN: CommonAge.BABY, - CommonSimType.BABY_HUMAN_VAMPIRE: CommonAge.BABY, - CommonSimType.BABY_HUMAN_GHOST: CommonAge.BABY, - CommonSimType.BABY_HUMAN_ALIEN: CommonAge.BABY, - CommonSimType.BABY_HUMAN_MERMAID: CommonAge.BABY, - CommonSimType.BABY_HUMAN_WITCH: CommonAge.BABY, - CommonSimType.BABY_HUMAN_ROBOT: CommonAge.BABY, - CommonSimType.BABY_HUMAN_SCARECROW: CommonAge.BABY, - CommonSimType.BABY_HUMAN_SKELETON: CommonAge.BABY, - CommonSimType.BABY_HUMAN_PLANT_SIM: CommonAge.BABY, - CommonSimType.BABY_HUMAN_WEREWOLF: CommonAge.BABY, - - # Dog - # Child - CommonSimType.CHILD_DOG: CommonAge.CHILD, - CommonSimType.CHILD_DOG_VAMPIRE: CommonAge.CHILD, - CommonSimType.CHILD_DOG_GHOST: CommonAge.CHILD, - CommonSimType.CHILD_DOG_ALIEN: CommonAge.CHILD, - CommonSimType.CHILD_DOG_MERMAID: CommonAge.CHILD, - CommonSimType.CHILD_DOG_WITCH: CommonAge.CHILD, - CommonSimType.CHILD_DOG_ROBOT: CommonAge.CHILD, - CommonSimType.CHILD_DOG_SCARECROW: CommonAge.CHILD, - CommonSimType.CHILD_DOG_SKELETON: CommonAge.CHILD, - CommonSimType.CHILD_DOG_PLANT_SIM: CommonAge.CHILD, - CommonSimType.CHILD_DOG_WEREWOLF: CommonAge.CHILD, - - # Small Dog - # Elder - CommonSimType.ELDER_SMALL_DOG: CommonAge.ELDER, - CommonSimType.ELDER_SMALL_DOG_VAMPIRE: CommonAge.ELDER, - CommonSimType.ELDER_SMALL_DOG_GHOST: CommonAge.ELDER, - CommonSimType.ELDER_SMALL_DOG_ALIEN: CommonAge.ELDER, - CommonSimType.ELDER_SMALL_DOG_MERMAID: CommonAge.ELDER, - CommonSimType.ELDER_SMALL_DOG_WITCH: CommonAge.ELDER, - CommonSimType.ELDER_SMALL_DOG_ROBOT: CommonAge.ELDER, - CommonSimType.ELDER_SMALL_DOG_SCARECROW: CommonAge.ELDER, - CommonSimType.ELDER_SMALL_DOG_SKELETON: CommonAge.ELDER, - CommonSimType.ELDER_SMALL_DOG_PLANT_SIM: CommonAge.ELDER, - CommonSimType.ELDER_SMALL_DOG_WEREWOLF: CommonAge.ELDER, - # Adult - CommonSimType.ADULT_SMALL_DOG: CommonAge.ADULT, - CommonSimType.ADULT_SMALL_DOG_VAMPIRE: CommonAge.ADULT, - CommonSimType.ADULT_SMALL_DOG_GHOST: CommonAge.ADULT, - CommonSimType.ADULT_SMALL_DOG_ALIEN: CommonAge.ADULT, - CommonSimType.ADULT_SMALL_DOG_MERMAID: CommonAge.ADULT, - CommonSimType.ADULT_SMALL_DOG_WITCH: CommonAge.ADULT, - CommonSimType.ADULT_SMALL_DOG_ROBOT: CommonAge.ADULT, - CommonSimType.ADULT_SMALL_DOG_SCARECROW: CommonAge.ADULT, - CommonSimType.ADULT_SMALL_DOG_SKELETON: CommonAge.ADULT, - CommonSimType.ADULT_SMALL_DOG_PLANT_SIM: CommonAge.ADULT, - CommonSimType.ADULT_SMALL_DOG_WEREWOLF: CommonAge.ADULT, - # Child - CommonSimType.CHILD_SMALL_DOG: CommonAge.CHILD, - CommonSimType.CHILD_SMALL_DOG_VAMPIRE: CommonAge.CHILD, - CommonSimType.CHILD_SMALL_DOG_GHOST: CommonAge.CHILD, - CommonSimType.CHILD_SMALL_DOG_ALIEN: CommonAge.CHILD, - CommonSimType.CHILD_SMALL_DOG_MERMAID: CommonAge.CHILD, - CommonSimType.CHILD_SMALL_DOG_WITCH: CommonAge.CHILD, - CommonSimType.CHILD_SMALL_DOG_ROBOT: CommonAge.CHILD, - CommonSimType.CHILD_SMALL_DOG_SCARECROW: CommonAge.CHILD, - CommonSimType.CHILD_SMALL_DOG_SKELETON: CommonAge.CHILD, - CommonSimType.CHILD_SMALL_DOG_PLANT_SIM: CommonAge.CHILD, - CommonSimType.CHILD_SMALL_DOG_WEREWOLF: CommonAge.CHILD, - - # Large Dog - # Elder - CommonSimType.ELDER_LARGE_DOG: CommonAge.ELDER, - CommonSimType.ELDER_LARGE_DOG_VAMPIRE: CommonAge.ELDER, - CommonSimType.ELDER_LARGE_DOG_GHOST: CommonAge.ELDER, - CommonSimType.ELDER_LARGE_DOG_ALIEN: CommonAge.ELDER, - CommonSimType.ELDER_LARGE_DOG_MERMAID: CommonAge.ELDER, - CommonSimType.ELDER_LARGE_DOG_WITCH: CommonAge.ELDER, - CommonSimType.ELDER_LARGE_DOG_ROBOT: CommonAge.ELDER, - CommonSimType.ELDER_LARGE_DOG_SCARECROW: CommonAge.ELDER, - CommonSimType.ELDER_LARGE_DOG_SKELETON: CommonAge.ELDER, - CommonSimType.ELDER_LARGE_DOG_PLANT_SIM: CommonAge.ELDER, - CommonSimType.ELDER_LARGE_DOG_WEREWOLF: CommonAge.ELDER, - # Adult - CommonSimType.ADULT_LARGE_DOG: CommonAge.ADULT, - CommonSimType.ADULT_LARGE_DOG_VAMPIRE: CommonAge.ADULT, - CommonSimType.ADULT_LARGE_DOG_GHOST: CommonAge.ADULT, - CommonSimType.ADULT_LARGE_DOG_ALIEN: CommonAge.ADULT, - CommonSimType.ADULT_LARGE_DOG_MERMAID: CommonAge.ADULT, - CommonSimType.ADULT_LARGE_DOG_WITCH: CommonAge.ADULT, - CommonSimType.ADULT_LARGE_DOG_ROBOT: CommonAge.ADULT, - CommonSimType.ADULT_LARGE_DOG_SCARECROW: CommonAge.ADULT, - CommonSimType.ADULT_LARGE_DOG_SKELETON: CommonAge.ADULT, - CommonSimType.ADULT_LARGE_DOG_PLANT_SIM: CommonAge.ADULT, - CommonSimType.ADULT_LARGE_DOG_WEREWOLF: CommonAge.ADULT, - # Child - CommonSimType.CHILD_LARGE_DOG: CommonAge.CHILD, - CommonSimType.CHILD_LARGE_DOG_VAMPIRE: CommonAge.CHILD, - CommonSimType.CHILD_LARGE_DOG_GHOST: CommonAge.CHILD, - CommonSimType.CHILD_LARGE_DOG_ALIEN: CommonAge.CHILD, - CommonSimType.CHILD_LARGE_DOG_MERMAID: CommonAge.CHILD, - CommonSimType.CHILD_LARGE_DOG_WITCH: CommonAge.CHILD, - CommonSimType.CHILD_LARGE_DOG_ROBOT: CommonAge.CHILD, - CommonSimType.CHILD_LARGE_DOG_SCARECROW: CommonAge.CHILD, - CommonSimType.CHILD_LARGE_DOG_SKELETON: CommonAge.CHILD, - CommonSimType.CHILD_LARGE_DOG_PLANT_SIM: CommonAge.CHILD, - CommonSimType.CHILD_LARGE_DOG_WEREWOLF: CommonAge.CHILD, - - # Cat - # Elder - CommonSimType.ELDER_CAT: CommonAge.ELDER, - CommonSimType.ELDER_CAT_VAMPIRE: CommonAge.ELDER, - CommonSimType.ELDER_CAT_GHOST: CommonAge.ELDER, - CommonSimType.ELDER_CAT_ALIEN: CommonAge.ELDER, - CommonSimType.ELDER_CAT_MERMAID: CommonAge.ELDER, - CommonSimType.ELDER_CAT_WITCH: CommonAge.ELDER, - CommonSimType.ELDER_CAT_ROBOT: CommonAge.ELDER, - CommonSimType.ELDER_CAT_SCARECROW: CommonAge.ELDER, - CommonSimType.ELDER_CAT_SKELETON: CommonAge.ELDER, - CommonSimType.ELDER_CAT_PLANT_SIM: CommonAge.ELDER, - CommonSimType.ELDER_CAT_WEREWOLF: CommonAge.ELDER, - # Adult - CommonSimType.ADULT_CAT: CommonAge.ADULT, - CommonSimType.ADULT_CAT_VAMPIRE: CommonAge.ADULT, - CommonSimType.ADULT_CAT_GHOST: CommonAge.ADULT, - CommonSimType.ADULT_CAT_ALIEN: CommonAge.ADULT, - CommonSimType.ADULT_CAT_MERMAID: CommonAge.ADULT, - CommonSimType.ADULT_CAT_WITCH: CommonAge.ADULT, - CommonSimType.ADULT_CAT_ROBOT: CommonAge.ADULT, - CommonSimType.ADULT_CAT_SCARECROW: CommonAge.ADULT, - CommonSimType.ADULT_CAT_SKELETON: CommonAge.ADULT, - CommonSimType.ADULT_CAT_PLANT_SIM: CommonAge.ADULT, - CommonSimType.ADULT_CAT_WEREWOLF: CommonAge.ADULT, - # Child - CommonSimType.CHILD_CAT: CommonAge.CHILD, - CommonSimType.CHILD_CAT_VAMPIRE: CommonAge.CHILD, - CommonSimType.CHILD_CAT_GHOST: CommonAge.CHILD, - CommonSimType.CHILD_CAT_ALIEN: CommonAge.CHILD, - CommonSimType.CHILD_CAT_MERMAID: CommonAge.CHILD, - CommonSimType.CHILD_CAT_WITCH: CommonAge.CHILD, - CommonSimType.CHILD_CAT_ROBOT: CommonAge.CHILD, - CommonSimType.CHILD_CAT_SCARECROW: CommonAge.CHILD, - CommonSimType.CHILD_CAT_SKELETON: CommonAge.CHILD, - CommonSimType.CHILD_CAT_PLANT_SIM: CommonAge.CHILD, - CommonSimType.CHILD_CAT_WEREWOLF: CommonAge.CHILD, - - # Fox - # Elder - CommonSimType.ELDER_FOX: CommonAge.ELDER, - CommonSimType.ELDER_FOX_VAMPIRE: CommonAge.ELDER, - CommonSimType.ELDER_FOX_GHOST: CommonAge.ELDER, - CommonSimType.ELDER_FOX_ALIEN: CommonAge.ELDER, - CommonSimType.ELDER_FOX_MERMAID: CommonAge.ELDER, - CommonSimType.ELDER_FOX_WITCH: CommonAge.ELDER, - CommonSimType.ELDER_FOX_ROBOT: CommonAge.ELDER, - CommonSimType.ELDER_FOX_SCARECROW: CommonAge.ELDER, - CommonSimType.ELDER_FOX_SKELETON: CommonAge.ELDER, - CommonSimType.ELDER_FOX_PLANT_SIM: CommonAge.ELDER, - CommonSimType.ELDER_FOX_WEREWOLF: CommonAge.ELDER, - # Adult - CommonSimType.ADULT_FOX: CommonAge.ADULT, - CommonSimType.ADULT_FOX_VAMPIRE: CommonAge.ADULT, - CommonSimType.ADULT_FOX_GHOST: CommonAge.ADULT, - CommonSimType.ADULT_FOX_ALIEN: CommonAge.ADULT, - CommonSimType.ADULT_FOX_MERMAID: CommonAge.ADULT, - CommonSimType.ADULT_FOX_WITCH: CommonAge.ADULT, - CommonSimType.ADULT_FOX_ROBOT: CommonAge.ADULT, - CommonSimType.ADULT_FOX_SCARECROW: CommonAge.ADULT, - CommonSimType.ADULT_FOX_SKELETON: CommonAge.ADULT, - CommonSimType.ADULT_FOX_PLANT_SIM: CommonAge.ADULT, - CommonSimType.ADULT_FOX_WEREWOLF: CommonAge.ADULT, - # Child - CommonSimType.CHILD_FOX: CommonAge.CHILD, - CommonSimType.CHILD_FOX_VAMPIRE: CommonAge.CHILD, - CommonSimType.CHILD_FOX_GHOST: CommonAge.CHILD, - CommonSimType.CHILD_FOX_ALIEN: CommonAge.CHILD, - CommonSimType.CHILD_FOX_MERMAID: CommonAge.CHILD, - CommonSimType.CHILD_FOX_WITCH: CommonAge.CHILD, - CommonSimType.CHILD_FOX_ROBOT: CommonAge.CHILD, - CommonSimType.CHILD_FOX_SCARECROW: CommonAge.CHILD, - CommonSimType.CHILD_FOX_SKELETON: CommonAge.CHILD, - CommonSimType.CHILD_FOX_PLANT_SIM: CommonAge.CHILD, - CommonSimType.CHILD_FOX_WEREWOLF: CommonAge.CHILD, - - # Horse - # Elder - CommonSimType.ELDER_HORSE: CommonAge.ELDER, - CommonSimType.ELDER_HORSE_VAMPIRE: CommonAge.ELDER, - CommonSimType.ELDER_HORSE_GHOST: CommonAge.ELDER, - CommonSimType.ELDER_HORSE_ALIEN: CommonAge.ELDER, - CommonSimType.ELDER_HORSE_MERMAID: CommonAge.ELDER, - CommonSimType.ELDER_HORSE_WITCH: CommonAge.ELDER, - CommonSimType.ELDER_HORSE_ROBOT: CommonAge.ELDER, - CommonSimType.ELDER_HORSE_SCARECROW: CommonAge.ELDER, - CommonSimType.ELDER_HORSE_SKELETON: CommonAge.ELDER, - CommonSimType.ELDER_HORSE_PLANT_SIM: CommonAge.ELDER, - CommonSimType.ELDER_HORSE_WEREWOLF: CommonAge.ELDER, - # Adult - CommonSimType.ADULT_HORSE: CommonAge.ADULT, - CommonSimType.ADULT_HORSE_VAMPIRE: CommonAge.ADULT, - CommonSimType.ADULT_HORSE_GHOST: CommonAge.ADULT, - CommonSimType.ADULT_HORSE_ALIEN: CommonAge.ADULT, - CommonSimType.ADULT_HORSE_MERMAID: CommonAge.ADULT, - CommonSimType.ADULT_HORSE_WITCH: CommonAge.ADULT, - CommonSimType.ADULT_HORSE_ROBOT: CommonAge.ADULT, - CommonSimType.ADULT_HORSE_SCARECROW: CommonAge.ADULT, - CommonSimType.ADULT_HORSE_SKELETON: CommonAge.ADULT, - CommonSimType.ADULT_HORSE_PLANT_SIM: CommonAge.ADULT, - CommonSimType.ADULT_HORSE_WEREWOLF: CommonAge.ADULT, - # Child - CommonSimType.CHILD_HORSE: CommonAge.CHILD, - CommonSimType.CHILD_HORSE_VAMPIRE: CommonAge.CHILD, - CommonSimType.CHILD_HORSE_GHOST: CommonAge.CHILD, - CommonSimType.CHILD_HORSE_ALIEN: CommonAge.CHILD, - CommonSimType.CHILD_HORSE_MERMAID: CommonAge.CHILD, - CommonSimType.CHILD_HORSE_WITCH: CommonAge.CHILD, - CommonSimType.CHILD_HORSE_ROBOT: CommonAge.CHILD, - CommonSimType.CHILD_HORSE_SCARECROW: CommonAge.CHILD, - CommonSimType.CHILD_HORSE_SKELETON: CommonAge.CHILD, - CommonSimType.CHILD_HORSE_PLANT_SIM: CommonAge.CHILD, - CommonSimType.CHILD_HORSE_WEREWOLF: CommonAge.CHILD, - } - - _OCCULT_SIM_TYPE_TO_SPECIES_MAPPING: Dict[CommonSimType, CommonSpecies] = { - # Human - # Elder - CommonSimType.ELDER_HUMAN: CommonSpecies.HUMAN, - CommonSimType.ELDER_HUMAN_VAMPIRE: CommonSpecies.HUMAN, - CommonSimType.ELDER_HUMAN_GHOST: CommonSpecies.HUMAN, - CommonSimType.ELDER_HUMAN_ALIEN: CommonSpecies.HUMAN, - CommonSimType.ELDER_HUMAN_MERMAID: CommonSpecies.HUMAN, - CommonSimType.ELDER_HUMAN_WITCH: CommonSpecies.HUMAN, - CommonSimType.ELDER_HUMAN_ROBOT: CommonSpecies.HUMAN, - CommonSimType.ELDER_HUMAN_SCARECROW: CommonSpecies.HUMAN, - CommonSimType.ELDER_HUMAN_SKELETON: CommonSpecies.HUMAN, - CommonSimType.ELDER_HUMAN_PLANT_SIM: CommonSpecies.HUMAN, - CommonSimType.ELDER_HUMAN_WEREWOLF: CommonSpecies.HUMAN, - # Adult - CommonSimType.ADULT_HUMAN: CommonSpecies.HUMAN, - CommonSimType.ADULT_HUMAN_VAMPIRE: CommonSpecies.HUMAN, - CommonSimType.ADULT_HUMAN_GHOST: CommonSpecies.HUMAN, - CommonSimType.ADULT_HUMAN_ALIEN: CommonSpecies.HUMAN, - CommonSimType.ADULT_HUMAN_MERMAID: CommonSpecies.HUMAN, - CommonSimType.ADULT_HUMAN_WITCH: CommonSpecies.HUMAN, - CommonSimType.ADULT_HUMAN_ROBOT: CommonSpecies.HUMAN, - CommonSimType.ADULT_HUMAN_SCARECROW: CommonSpecies.HUMAN, - CommonSimType.ADULT_HUMAN_SKELETON: CommonSpecies.HUMAN, - CommonSimType.ADULT_HUMAN_PLANT_SIM: CommonSpecies.HUMAN, - CommonSimType.ADULT_HUMAN_WEREWOLF: CommonSpecies.HUMAN, - # Young Adult - CommonSimType.YOUNG_ADULT_HUMAN: CommonSpecies.HUMAN, - CommonSimType.YOUNG_ADULT_HUMAN_VAMPIRE: CommonSpecies.HUMAN, - CommonSimType.YOUNG_ADULT_HUMAN_GHOST: CommonSpecies.HUMAN, - CommonSimType.YOUNG_ADULT_HUMAN_ALIEN: CommonSpecies.HUMAN, - CommonSimType.YOUNG_ADULT_HUMAN_MERMAID: CommonSpecies.HUMAN, - CommonSimType.YOUNG_ADULT_HUMAN_WITCH: CommonSpecies.HUMAN, - CommonSimType.YOUNG_ADULT_HUMAN_ROBOT: CommonSpecies.HUMAN, - CommonSimType.YOUNG_ADULT_HUMAN_SCARECROW: CommonSpecies.HUMAN, - CommonSimType.YOUNG_ADULT_HUMAN_SKELETON: CommonSpecies.HUMAN, - CommonSimType.YOUNG_ADULT_HUMAN_PLANT_SIM: CommonSpecies.HUMAN, - CommonSimType.YOUNG_ADULT_HUMAN_WEREWOLF: CommonSpecies.HUMAN, - # Teen - CommonSimType.TEEN_HUMAN: CommonSpecies.HUMAN, - CommonSimType.TEEN_HUMAN_VAMPIRE: CommonSpecies.HUMAN, - CommonSimType.TEEN_HUMAN_GHOST: CommonSpecies.HUMAN, - CommonSimType.TEEN_HUMAN_ALIEN: CommonSpecies.HUMAN, - CommonSimType.TEEN_HUMAN_MERMAID: CommonSpecies.HUMAN, - CommonSimType.TEEN_HUMAN_WITCH: CommonSpecies.HUMAN, - CommonSimType.TEEN_HUMAN_ROBOT: CommonSpecies.HUMAN, - CommonSimType.TEEN_HUMAN_SCARECROW: CommonSpecies.HUMAN, - CommonSimType.TEEN_HUMAN_SKELETON: CommonSpecies.HUMAN, - CommonSimType.TEEN_HUMAN_PLANT_SIM: CommonSpecies.HUMAN, - CommonSimType.TEEN_HUMAN_WEREWOLF: CommonSpecies.HUMAN, - # Child - CommonSimType.CHILD_HUMAN: CommonSpecies.HUMAN, - CommonSimType.CHILD_HUMAN_VAMPIRE: CommonSpecies.HUMAN, - CommonSimType.CHILD_HUMAN_GHOST: CommonSpecies.HUMAN, - CommonSimType.CHILD_HUMAN_ALIEN: CommonSpecies.HUMAN, - CommonSimType.CHILD_HUMAN_MERMAID: CommonSpecies.HUMAN, - CommonSimType.CHILD_HUMAN_WITCH: CommonSpecies.HUMAN, - CommonSimType.CHILD_HUMAN_ROBOT: CommonSpecies.HUMAN, - CommonSimType.CHILD_HUMAN_SCARECROW: CommonSpecies.HUMAN, - CommonSimType.CHILD_HUMAN_SKELETON: CommonSpecies.HUMAN, - CommonSimType.CHILD_HUMAN_PLANT_SIM: CommonSpecies.HUMAN, - CommonSimType.CHILD_HUMAN_WEREWOLF: CommonSpecies.HUMAN, - # Toddler - CommonSimType.TODDLER_HUMAN: CommonSpecies.HUMAN, - CommonSimType.TODDLER_HUMAN_VAMPIRE: CommonSpecies.HUMAN, - CommonSimType.TODDLER_HUMAN_GHOST: CommonSpecies.HUMAN, - CommonSimType.TODDLER_HUMAN_ALIEN: CommonSpecies.HUMAN, - CommonSimType.TODDLER_HUMAN_MERMAID: CommonSpecies.HUMAN, - CommonSimType.TODDLER_HUMAN_WITCH: CommonSpecies.HUMAN, - CommonSimType.TODDLER_HUMAN_ROBOT: CommonSpecies.HUMAN, - CommonSimType.TODDLER_HUMAN_SCARECROW: CommonSpecies.HUMAN, - CommonSimType.TODDLER_HUMAN_SKELETON: CommonSpecies.HUMAN, - CommonSimType.TODDLER_HUMAN_PLANT_SIM: CommonSpecies.HUMAN, - CommonSimType.TODDLER_HUMAN_WEREWOLF: CommonSpecies.HUMAN, - # Infant - CommonSimType.INFANT_HUMAN: CommonSpecies.HUMAN, - CommonSimType.INFANT_HUMAN_VAMPIRE: CommonSpecies.HUMAN, - CommonSimType.INFANT_HUMAN_GHOST: CommonSpecies.HUMAN, - CommonSimType.INFANT_HUMAN_ALIEN: CommonSpecies.HUMAN, - CommonSimType.INFANT_HUMAN_MERMAID: CommonSpecies.HUMAN, - CommonSimType.INFANT_HUMAN_WITCH: CommonSpecies.HUMAN, - CommonSimType.INFANT_HUMAN_ROBOT: CommonSpecies.HUMAN, - CommonSimType.INFANT_HUMAN_SCARECROW: CommonSpecies.HUMAN, - CommonSimType.INFANT_HUMAN_SKELETON: CommonSpecies.HUMAN, - CommonSimType.INFANT_HUMAN_PLANT_SIM: CommonSpecies.HUMAN, - CommonSimType.INFANT_HUMAN_WEREWOLF: CommonSpecies.HUMAN, - # Baby - CommonSimType.BABY_HUMAN: CommonSpecies.HUMAN, - CommonSimType.BABY_HUMAN_VAMPIRE: CommonSpecies.HUMAN, - CommonSimType.BABY_HUMAN_GHOST: CommonSpecies.HUMAN, - CommonSimType.BABY_HUMAN_ALIEN: CommonSpecies.HUMAN, - CommonSimType.BABY_HUMAN_MERMAID: CommonSpecies.HUMAN, - CommonSimType.BABY_HUMAN_WITCH: CommonSpecies.HUMAN, - CommonSimType.BABY_HUMAN_ROBOT: CommonSpecies.HUMAN, - CommonSimType.BABY_HUMAN_SCARECROW: CommonSpecies.HUMAN, - CommonSimType.BABY_HUMAN_SKELETON: CommonSpecies.HUMAN, - CommonSimType.BABY_HUMAN_PLANT_SIM: CommonSpecies.HUMAN, - CommonSimType.BABY_HUMAN_WEREWOLF: CommonSpecies.HUMAN, - - # Dog - # Small Dog - # Elder - CommonSimType.ELDER_SMALL_DOG: CommonSpecies.SMALL_DOG, - CommonSimType.ELDER_SMALL_DOG_VAMPIRE: CommonSpecies.SMALL_DOG, - CommonSimType.ELDER_SMALL_DOG_GHOST: CommonSpecies.SMALL_DOG, - CommonSimType.ELDER_SMALL_DOG_ALIEN: CommonSpecies.SMALL_DOG, - CommonSimType.ELDER_SMALL_DOG_MERMAID: CommonSpecies.SMALL_DOG, - CommonSimType.ELDER_SMALL_DOG_WITCH: CommonSpecies.SMALL_DOG, - CommonSimType.ELDER_SMALL_DOG_ROBOT: CommonSpecies.SMALL_DOG, - CommonSimType.ELDER_SMALL_DOG_SCARECROW: CommonSpecies.SMALL_DOG, - CommonSimType.ELDER_SMALL_DOG_SKELETON: CommonSpecies.SMALL_DOG, - CommonSimType.ELDER_SMALL_DOG_PLANT_SIM: CommonSpecies.SMALL_DOG, - CommonSimType.ELDER_SMALL_DOG_WEREWOLF: CommonSpecies.SMALL_DOG, - # Adult - CommonSimType.ADULT_SMALL_DOG: CommonSpecies.SMALL_DOG, - CommonSimType.ADULT_SMALL_DOG_VAMPIRE: CommonSpecies.SMALL_DOG, - CommonSimType.ADULT_SMALL_DOG_GHOST: CommonSpecies.SMALL_DOG, - CommonSimType.ADULT_SMALL_DOG_ALIEN: CommonSpecies.SMALL_DOG, - CommonSimType.ADULT_SMALL_DOG_MERMAID: CommonSpecies.SMALL_DOG, - CommonSimType.ADULT_SMALL_DOG_WITCH: CommonSpecies.SMALL_DOG, - CommonSimType.ADULT_SMALL_DOG_ROBOT: CommonSpecies.SMALL_DOG, - CommonSimType.ADULT_SMALL_DOG_SCARECROW: CommonSpecies.SMALL_DOG, - CommonSimType.ADULT_SMALL_DOG_SKELETON: CommonSpecies.SMALL_DOG, - CommonSimType.ADULT_SMALL_DOG_PLANT_SIM: CommonSpecies.SMALL_DOG, - CommonSimType.ADULT_SMALL_DOG_WEREWOLF: CommonSpecies.SMALL_DOG, - # Child - CommonSimType.CHILD_SMALL_DOG: CommonSpecies.SMALL_DOG, - CommonSimType.CHILD_SMALL_DOG_VAMPIRE: CommonSpecies.SMALL_DOG, - CommonSimType.CHILD_SMALL_DOG_GHOST: CommonSpecies.SMALL_DOG, - CommonSimType.CHILD_SMALL_DOG_ALIEN: CommonSpecies.SMALL_DOG, - CommonSimType.CHILD_SMALL_DOG_MERMAID: CommonSpecies.SMALL_DOG, - CommonSimType.CHILD_SMALL_DOG_WITCH: CommonSpecies.SMALL_DOG, - CommonSimType.CHILD_SMALL_DOG_ROBOT: CommonSpecies.SMALL_DOG, - CommonSimType.CHILD_SMALL_DOG_SCARECROW: CommonSpecies.SMALL_DOG, - CommonSimType.CHILD_SMALL_DOG_SKELETON: CommonSpecies.SMALL_DOG, - CommonSimType.CHILD_SMALL_DOG_PLANT_SIM: CommonSpecies.SMALL_DOG, - CommonSimType.CHILD_SMALL_DOG_WEREWOLF: CommonSpecies.SMALL_DOG, - - # Child - CommonSimType.CHILD_DOG: CommonSpecies.LARGE_DOG, - CommonSimType.CHILD_DOG_VAMPIRE: CommonSpecies.LARGE_DOG, - CommonSimType.CHILD_DOG_GHOST: CommonSpecies.LARGE_DOG, - CommonSimType.CHILD_DOG_ALIEN: CommonSpecies.LARGE_DOG, - CommonSimType.CHILD_DOG_MERMAID: CommonSpecies.LARGE_DOG, - CommonSimType.CHILD_DOG_WITCH: CommonSpecies.LARGE_DOG, - CommonSimType.CHILD_DOG_ROBOT: CommonSpecies.LARGE_DOG, - CommonSimType.CHILD_DOG_SCARECROW: CommonSpecies.LARGE_DOG, - CommonSimType.CHILD_DOG_SKELETON: CommonSpecies.LARGE_DOG, - CommonSimType.CHILD_DOG_PLANT_SIM: CommonSpecies.LARGE_DOG, - CommonSimType.CHILD_DOG_WEREWOLF: CommonSpecies.LARGE_DOG, - - # Large Dog - # Elder - CommonSimType.ELDER_LARGE_DOG: CommonSpecies.LARGE_DOG, - CommonSimType.ELDER_LARGE_DOG_VAMPIRE: CommonSpecies.LARGE_DOG, - CommonSimType.ELDER_LARGE_DOG_GHOST: CommonSpecies.LARGE_DOG, - CommonSimType.ELDER_LARGE_DOG_ALIEN: CommonSpecies.LARGE_DOG, - CommonSimType.ELDER_LARGE_DOG_MERMAID: CommonSpecies.LARGE_DOG, - CommonSimType.ELDER_LARGE_DOG_WITCH: CommonSpecies.LARGE_DOG, - CommonSimType.ELDER_LARGE_DOG_ROBOT: CommonSpecies.LARGE_DOG, - CommonSimType.ELDER_LARGE_DOG_SCARECROW: CommonSpecies.LARGE_DOG, - CommonSimType.ELDER_LARGE_DOG_SKELETON: CommonSpecies.LARGE_DOG, - CommonSimType.ELDER_LARGE_DOG_PLANT_SIM: CommonSpecies.LARGE_DOG, - CommonSimType.ELDER_LARGE_DOG_WEREWOLF: CommonSpecies.LARGE_DOG, - # Adult - CommonSimType.ADULT_LARGE_DOG: CommonSpecies.LARGE_DOG, - CommonSimType.ADULT_LARGE_DOG_VAMPIRE: CommonSpecies.LARGE_DOG, - CommonSimType.ADULT_LARGE_DOG_GHOST: CommonSpecies.LARGE_DOG, - CommonSimType.ADULT_LARGE_DOG_ALIEN: CommonSpecies.LARGE_DOG, - CommonSimType.ADULT_LARGE_DOG_MERMAID: CommonSpecies.LARGE_DOG, - CommonSimType.ADULT_LARGE_DOG_WITCH: CommonSpecies.LARGE_DOG, - CommonSimType.ADULT_LARGE_DOG_ROBOT: CommonSpecies.LARGE_DOG, - CommonSimType.ADULT_LARGE_DOG_SCARECROW: CommonSpecies.LARGE_DOG, - CommonSimType.ADULT_LARGE_DOG_SKELETON: CommonSpecies.LARGE_DOG, - CommonSimType.ADULT_LARGE_DOG_PLANT_SIM: CommonSpecies.LARGE_DOG, - CommonSimType.ADULT_LARGE_DOG_WEREWOLF: CommonSpecies.LARGE_DOG, - # Child - CommonSimType.CHILD_LARGE_DOG: CommonSpecies.LARGE_DOG, - CommonSimType.CHILD_LARGE_DOG_VAMPIRE: CommonSpecies.LARGE_DOG, - CommonSimType.CHILD_LARGE_DOG_GHOST: CommonSpecies.LARGE_DOG, - CommonSimType.CHILD_LARGE_DOG_ALIEN: CommonSpecies.LARGE_DOG, - CommonSimType.CHILD_LARGE_DOG_MERMAID: CommonSpecies.LARGE_DOG, - CommonSimType.CHILD_LARGE_DOG_WITCH: CommonSpecies.LARGE_DOG, - CommonSimType.CHILD_LARGE_DOG_ROBOT: CommonSpecies.LARGE_DOG, - CommonSimType.CHILD_LARGE_DOG_SCARECROW: CommonSpecies.LARGE_DOG, - CommonSimType.CHILD_LARGE_DOG_SKELETON: CommonSpecies.LARGE_DOG, - CommonSimType.CHILD_LARGE_DOG_PLANT_SIM: CommonSpecies.LARGE_DOG, - CommonSimType.CHILD_LARGE_DOG_WEREWOLF: CommonSpecies.LARGE_DOG, - - # Cat - # Elder - CommonSimType.ELDER_CAT: CommonSpecies.CAT, - CommonSimType.ELDER_CAT_VAMPIRE: CommonSpecies.CAT, - CommonSimType.ELDER_CAT_GHOST: CommonSpecies.CAT, - CommonSimType.ELDER_CAT_ALIEN: CommonSpecies.CAT, - CommonSimType.ELDER_CAT_MERMAID: CommonSpecies.CAT, - CommonSimType.ELDER_CAT_WITCH: CommonSpecies.CAT, - CommonSimType.ELDER_CAT_ROBOT: CommonSpecies.CAT, - CommonSimType.ELDER_CAT_SCARECROW: CommonSpecies.CAT, - CommonSimType.ELDER_CAT_SKELETON: CommonSpecies.CAT, - CommonSimType.ELDER_CAT_PLANT_SIM: CommonSpecies.CAT, - CommonSimType.ELDER_CAT_WEREWOLF: CommonSpecies.CAT, - # Adult - CommonSimType.ADULT_CAT: CommonSpecies.CAT, - CommonSimType.ADULT_CAT_VAMPIRE: CommonSpecies.CAT, - CommonSimType.ADULT_CAT_GHOST: CommonSpecies.CAT, - CommonSimType.ADULT_CAT_ALIEN: CommonSpecies.CAT, - CommonSimType.ADULT_CAT_MERMAID: CommonSpecies.CAT, - CommonSimType.ADULT_CAT_WITCH: CommonSpecies.CAT, - CommonSimType.ADULT_CAT_ROBOT: CommonSpecies.CAT, - CommonSimType.ADULT_CAT_SCARECROW: CommonSpecies.CAT, - CommonSimType.ADULT_CAT_SKELETON: CommonSpecies.CAT, - CommonSimType.ADULT_CAT_PLANT_SIM: CommonSpecies.CAT, - CommonSimType.ADULT_CAT_WEREWOLF: CommonSpecies.CAT, - # Child - CommonSimType.CHILD_CAT: CommonSpecies.CAT, - CommonSimType.CHILD_CAT_VAMPIRE: CommonSpecies.CAT, - CommonSimType.CHILD_CAT_GHOST: CommonSpecies.CAT, - CommonSimType.CHILD_CAT_ALIEN: CommonSpecies.CAT, - CommonSimType.CHILD_CAT_MERMAID: CommonSpecies.CAT, - CommonSimType.CHILD_CAT_WITCH: CommonSpecies.CAT, - CommonSimType.CHILD_CAT_ROBOT: CommonSpecies.CAT, - CommonSimType.CHILD_CAT_SCARECROW: CommonSpecies.CAT, - CommonSimType.CHILD_CAT_SKELETON: CommonSpecies.CAT, - CommonSimType.CHILD_CAT_PLANT_SIM: CommonSpecies.CAT, - CommonSimType.CHILD_CAT_WEREWOLF: CommonSpecies.CAT, - - # Fox - # Elder - CommonSimType.ELDER_FOX: CommonSpecies.FOX, - CommonSimType.ELDER_FOX_VAMPIRE: CommonSpecies.FOX, - CommonSimType.ELDER_FOX_GHOST: CommonSpecies.FOX, - CommonSimType.ELDER_FOX_ALIEN: CommonSpecies.FOX, - CommonSimType.ELDER_FOX_MERMAID: CommonSpecies.FOX, - CommonSimType.ELDER_FOX_WITCH: CommonSpecies.FOX, - CommonSimType.ELDER_FOX_ROBOT: CommonSpecies.FOX, - CommonSimType.ELDER_FOX_SCARECROW: CommonSpecies.FOX, - CommonSimType.ELDER_FOX_SKELETON: CommonSpecies.FOX, - CommonSimType.ELDER_FOX_PLANT_SIM: CommonSpecies.FOX, - CommonSimType.ELDER_FOX_WEREWOLF: CommonSpecies.FOX, - # Adult - CommonSimType.ADULT_FOX: CommonSpecies.FOX, - CommonSimType.ADULT_FOX_VAMPIRE: CommonSpecies.FOX, - CommonSimType.ADULT_FOX_GHOST: CommonSpecies.FOX, - CommonSimType.ADULT_FOX_ALIEN: CommonSpecies.FOX, - CommonSimType.ADULT_FOX_MERMAID: CommonSpecies.FOX, - CommonSimType.ADULT_FOX_WITCH: CommonSpecies.FOX, - CommonSimType.ADULT_FOX_ROBOT: CommonSpecies.FOX, - CommonSimType.ADULT_FOX_SCARECROW: CommonSpecies.FOX, - CommonSimType.ADULT_FOX_SKELETON: CommonSpecies.FOX, - CommonSimType.ADULT_FOX_PLANT_SIM: CommonSpecies.FOX, - CommonSimType.ADULT_FOX_WEREWOLF: CommonSpecies.FOX, - # Child - CommonSimType.CHILD_FOX: CommonSpecies.FOX, - CommonSimType.CHILD_FOX_VAMPIRE: CommonSpecies.FOX, - CommonSimType.CHILD_FOX_GHOST: CommonSpecies.FOX, - CommonSimType.CHILD_FOX_ALIEN: CommonSpecies.FOX, - CommonSimType.CHILD_FOX_MERMAID: CommonSpecies.FOX, - CommonSimType.CHILD_FOX_WITCH: CommonSpecies.FOX, - CommonSimType.CHILD_FOX_ROBOT: CommonSpecies.FOX, - CommonSimType.CHILD_FOX_SCARECROW: CommonSpecies.FOX, - CommonSimType.CHILD_FOX_SKELETON: CommonSpecies.FOX, - CommonSimType.CHILD_FOX_PLANT_SIM: CommonSpecies.FOX, - CommonSimType.CHILD_FOX_WEREWOLF: CommonSpecies.FOX, - - # Horse - # Elder - CommonSimType.ELDER_HORSE: CommonSpecies.HORSE, - CommonSimType.ELDER_HORSE_VAMPIRE: CommonSpecies.HORSE, - CommonSimType.ELDER_HORSE_GHOST: CommonSpecies.HORSE, - CommonSimType.ELDER_HORSE_ALIEN: CommonSpecies.HORSE, - CommonSimType.ELDER_HORSE_MERMAID: CommonSpecies.HORSE, - CommonSimType.ELDER_HORSE_WITCH: CommonSpecies.HORSE, - CommonSimType.ELDER_HORSE_ROBOT: CommonSpecies.HORSE, - CommonSimType.ELDER_HORSE_SCARECROW: CommonSpecies.HORSE, - CommonSimType.ELDER_HORSE_SKELETON: CommonSpecies.HORSE, - CommonSimType.ELDER_HORSE_PLANT_SIM: CommonSpecies.HORSE, - CommonSimType.ELDER_HORSE_WEREWOLF: CommonSpecies.HORSE, - # Adult - CommonSimType.ADULT_HORSE: CommonSpecies.HORSE, - CommonSimType.ADULT_HORSE_VAMPIRE: CommonSpecies.HORSE, - CommonSimType.ADULT_HORSE_GHOST: CommonSpecies.HORSE, - CommonSimType.ADULT_HORSE_ALIEN: CommonSpecies.HORSE, - CommonSimType.ADULT_HORSE_MERMAID: CommonSpecies.HORSE, - CommonSimType.ADULT_HORSE_WITCH: CommonSpecies.HORSE, - CommonSimType.ADULT_HORSE_ROBOT: CommonSpecies.HORSE, - CommonSimType.ADULT_HORSE_SCARECROW: CommonSpecies.HORSE, - CommonSimType.ADULT_HORSE_SKELETON: CommonSpecies.HORSE, - CommonSimType.ADULT_HORSE_PLANT_SIM: CommonSpecies.HORSE, - CommonSimType.ADULT_HORSE_WEREWOLF: CommonSpecies.HORSE, - # Child - CommonSimType.CHILD_HORSE: CommonSpecies.HORSE, - CommonSimType.CHILD_HORSE_VAMPIRE: CommonSpecies.HORSE, - CommonSimType.CHILD_HORSE_GHOST: CommonSpecies.HORSE, - CommonSimType.CHILD_HORSE_ALIEN: CommonSpecies.HORSE, - CommonSimType.CHILD_HORSE_MERMAID: CommonSpecies.HORSE, - CommonSimType.CHILD_HORSE_WITCH: CommonSpecies.HORSE, - CommonSimType.CHILD_HORSE_ROBOT: CommonSpecies.HORSE, - CommonSimType.CHILD_HORSE_SCARECROW: CommonSpecies.HORSE, - CommonSimType.CHILD_HORSE_SKELETON: CommonSpecies.HORSE, - CommonSimType.CHILD_HORSE_PLANT_SIM: CommonSpecies.HORSE, - CommonSimType.CHILD_HORSE_WEREWOLF: CommonSpecies.HORSE, - } - - @staticmethod - def is_non_player_sim(sim_info: SimInfo) -> bool: - """is_non_player_sim(sim_info) - - Determine if a Sim is a Non Player Sim. - - .. note:: An NPC Sim is a sim that is not a part of the active household. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is an NPC. False, if not. - :rtype: bool - """ - if sim_info is None: - raise AssertionError('Sim Info was None!') - # noinspection PyTypeChecker - return sim_info.is_npc - - @staticmethod - def is_player_sim(sim_info: SimInfo) -> bool: - """is_player_sim(sim_info) - - Determine if a Sim is a Player Sim. - - .. note:: A Player Sim is a Sim that is a part of the active household. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is a Player Sim. False, if not. - :rtype: bool - """ - if sim_info is None: - raise AssertionError('Sim Info was None!') - return not CommonSimTypeUtils.is_non_player_sim(sim_info) - - @staticmethod - def is_played_sim(sim_info: SimInfo) -> bool: - """is_played_sim(sim_info) - - Determine if a Sim is a Played Sim. - - .. note:: This does not indicate if a Sim is a Player Sim or Non Player Sim. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is a Played Sim. False, if not. - :rtype: bool - """ - if sim_info is None: - raise AssertionError('Sim Info was None!') - return sim_info.is_played_sim - - @staticmethod - def is_service_sim(sim_info: SimInfo) -> CommonTestResult: - """Determine if a Sim is a Service Sim. - - .. note:: - - Service Sims: - - - Butler - - Chalet - - City Repair - - Forest Ranger - - Gardener - - Grim Reaper - - Maid - - Mailman - - Massage Therapist - - Master Fisherman - - Master Gardener - - Master Herbalist - - Nanny - - Pizza Delivery - - Repairman - - Restaurant Critic - - Statue Busker - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim is a Service Sim. False, if not. - :rtype: CommonTestResult - """ - if sim_info is None: - raise AssertionError('Sim Info was None!') - from s4ap.sims4communitylib.enums.traits_enum import CommonTraitId - from s4ap.sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils - trait_ids = ( - CommonTraitId.IS_BUTLER, - CommonTraitId.IS_CHALET_GARDENS_GHOST, - CommonTraitId.IS_CITY_REPAIR, - CommonTraitId.IS_FOREST_RANGER, - CommonTraitId.IS_GARDENER, - CommonTraitId.IS_GARDENER_SERVICE, - CommonTraitId.IS_GRIM_REAPER, - CommonTraitId.IS_MAID, - CommonTraitId.IS_MAILMAN, - CommonTraitId.IS_MASSAGE_THERAPIST, - CommonTraitId.IS_MASTER_FISHERMAN, - CommonTraitId.IS_MASTER_GARDENER, - CommonTraitId.IS_MASTER_HERBALIST, - CommonTraitId.IS_NANNY, - CommonTraitId.IS_PIZZA_DELIVERY, - CommonTraitId.IS_REPAIR, - CommonTraitId.IS_RESTAURANT_CRITIC, - CommonTraitId.IS_STATUE_BUSKER - ) - return CommonTraitUtils.has_any_traits(sim_info, trait_ids) - - @staticmethod - def is_batuu_alien(sim_info: SimInfo) -> CommonTestResult: - """Determine if a Sim is a Batuu Alien. - - .. note:: - - Alien Sims: - - - Bith - - Twilek - - Weequay - - Abednedo - - Mirialan - - Zabrak - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim is a Batuu Alien. False, if not. - :rtype: CommonTestResult - """ - if sim_info is None: - raise AssertionError('Sim Info was None!') - from s4ap.sims4communitylib.enums.traits_enum import CommonTraitId - from s4ap.sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils - trait_ids = ( - CommonTraitId.BATUU_ALIEN_BITH, # trait_Batuu_Alien_Bith - CommonTraitId.BATUU_ALIEN_TWILEK, # trait_Batuu_Alien_Twilek - CommonTraitId.BATUU_ALIEN_WEEQUAY, # trait_Batuu_Alien_Weequay - CommonTraitId.BATUU_ALIEN_ABEDNEDO, # trait_Batuu_Alien_Abednedo - CommonTraitId.BATUU_ALIEN_MIRIALAN, # trait_Batuu_Alien_Mirialan - CommonTraitId.BATUU_ALIEN_ZABRAK, # trait_Batuu_Alien_Zabrak - ) - return CommonTraitUtils.has_any_traits(sim_info, trait_ids) - - @staticmethod - def is_occult(sim_info: SimInfo, combine_teen_young_adult_and_elder_age: bool = True, combine_child_dog_types: bool = True) -> bool: - """is_occult(sim_info, combine_teen_young_adult_and_elder_age=True, combine_child_dog_types=True) - - Determine if a Sim has an Occult Sim Type. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param combine_teen_young_adult_and_elder_age: See description of CommonSimTypeUtils.determine_sim_type. Default is True. - :type combine_teen_young_adult_and_elder_age: bool, optional - :param combine_child_dog_types: See description of CommonSimTypeUtils.determine_sim_type. Default is True. - :type combine_child_dog_types: bool, optional - :return: True, if the specified Sim has an Occult Sim Type. False, if not. - :rtype: bool - """ - if sim_info is None: - raise AssertionError('Sim Info was None!') - sim_type = CommonSimTypeUtils.determine_sim_type( - sim_info, - combine_teen_young_adult_and_elder_age=combine_teen_young_adult_and_elder_age, - combine_child_dog_types=combine_child_dog_types - ) - return CommonSimTypeUtils.is_occult_type(sim_type) - - @staticmethod - def is_occult_type(sim_type: CommonSimType) -> bool: - """is_occult_type(sim_type) - - Determine if a Sim Type is for an Occult Sim. - - :param sim_type: A Sim Type. - :type sim_type: CommonSimType - :return: True, if the Sim Type is for an Occult Sim. False, if not. - :rtype: bool - """ - # If the sim_type is an Occult, it will change to its Human variant, thus making them not equal and proving it was an occult. If the sim type is Human, it will not change. - return CommonSimTypeUtils.convert_to_non_occult_variant(sim_type) != sim_type - - @staticmethod - def get_all_sim_types_gen(sim_info: SimInfo, combine_teen_young_adult_and_elder_age: bool = True, combine_child_dog_types: bool = True) -> Iterator[CommonSimType]: - """get_all_sim_types_gen(sim_info, combine_teen_young_adult_and_elder_age=True, combine_child_dog_types=True) - - Determine all types a Sim is based on their Age, Species, and Occult Types. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param combine_teen_young_adult_and_elder_age: If set to True, Teen, Young Adult, Adult, and Elder, will all receive an ADULT denoted Sim Type instead of TEEN, YOUNG_ADULT, ADULT, and ELDER respectively. i.e. A Human Teen Sim would be denoted as ADULT_HUMAN. - If set to False, they will receive their own Sim Types. i.e. A Human Teen Sim would be denoted as TEEN_HUMAN. Default is True. - :type combine_teen_young_adult_and_elder_age: bool, optional - :param combine_child_dog_types: If set to True, the Child Dog Sim Types will be combined into a single Sim Type, i.e. CHILD_DOG. If set to False, the Child Dog Sim Types will be returned as their more specific values. i.e. CHILD_LARGE_DOG, CHILD_SMALL_DOG, etc. Default is True. - :type combine_child_dog_types: bool, optional - :return: An iterator of all types the Sim is. - :rtype: Iterator[CommonSimType] - """ - if sim_info is None: - raise AssertionError('Sim Info was None!') - species = CommonSpecies.get_species(sim_info) - age = CommonAge.get_age(sim_info) - from s4ap.sims4communitylib.utils.sims.common_sim_occult_type_utils import CommonSimOccultTypeUtils - for occult_type in CommonSimOccultTypeUtils.get_all_occult_types_for_sim_gen(sim_info): - if CommonOccultUtils.is_robot(sim_info) and occult_type == CommonOccultType.NON_OCCULT: - continue - yield CommonSimTypeUtils.determine_sim_type_for_species_age_occult(species, age, occult_type, combine_teen_young_adult_and_elder_age=combine_teen_young_adult_and_elder_age, combine_child_dog_types=combine_child_dog_types) - - @staticmethod - def determine_sim_type( - sim_info: SimInfo, - combine_teen_young_adult_and_elder_age: bool = True, - combine_child_dog_types: bool = True, - use_current_occult_type: bool = False - ) -> CommonSimType: - """determine_sim_type(sim_info, combine_teen_young_adult_and_elder_age=True, combine_child_dog_types=True, use_current_occult_type=False) - - Determine the type of Sim a Sim is based on their Age, Species, and Occult Type. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param combine_teen_young_adult_and_elder_age: If set to True, Teen, Young Adult, Adult, and Elder, will all receive an ADULT denoted Sim Type instead of TEEN, YOUNG_ADULT, ADULT, and ELDER respectively. i.e. A Human Teen Sim would be denoted as ADULT_HUMAN. - If set to False, they will receive their own Sim Types. i.e. A Human Teen Sim would be denoted as TEEN_HUMAN. Default is True. - :type combine_teen_young_adult_and_elder_age: bool, optional - :param combine_child_dog_types: If set to True, the Child Dog Sim Types will be combined into a single Sim Type, i.e. CHILD_DOG. If set to False, the Child Dog Sim Types will be returned as their more specific values. i.e. CHILD_LARGE_DOG, CHILD_SMALL_DOG, etc. Default is True. - :type combine_child_dog_types: bool, optional - :param use_current_occult_type: If set to True, the Sims current occult type will be used, for example an Adult Human Mermaid with no tail would return ADULT_HUMAN instead of ADULT_HUMAN_MERMAID. If set to False, the Sims occult type will be used (whether current or not), for example an Adult Human Mermaid wearing or not wearing their tail would return ADULT_HUMAN_MERMAID. Default is False. - :param use_current_occult_type: bool, optional - :return: The type of Sim the Sim is or NONE if no type was found for the Sim. - :rtype: CommonSimType - """ - if sim_info is None: - raise AssertionError('Sim Info was None!') - species = CommonSpecies.get_species(sim_info) - age = CommonAge.get_age(sim_info) - if use_current_occult_type: - occult_type = CommonOccultType.determine_current_occult_type(sim_info) - else: - occult_type = CommonOccultType.determine_occult_type(sim_info) - sim_type = CommonSimTypeUtils.determine_sim_type_for_species_age_occult(species, age, occult_type, combine_teen_young_adult_and_elder_age=combine_teen_young_adult_and_elder_age, combine_child_dog_types=combine_child_dog_types) - return sim_type - - @staticmethod - def determine_sim_type_for_species_age_occult( - species: CommonSpecies, - age: CommonAge, - occult_type: CommonOccultType, - combine_teen_young_adult_and_elder_age: bool = True, - combine_child_dog_types: bool = True - ) -> CommonSimType: - """determine_sim_type_for_species_age_occult(\ - species,\ - age,\ - occult_type,\ - combine_teen_young_adult_and_elder_age=True,\ - combine_child_dog_types=True,\ - use_current_occult_type=False\ - ) - - Determine the type of Sim a Sim is based on their Age, Species, and Occult Type. - - :param species: A CommonSpecies. - :type species: CommonSpecies - :param age: An Age. - :type age: CommonAge - :param occult_type: An Occult Type. - :type occult_type: CommonOccultType - :param combine_teen_young_adult_and_elder_age: If set to True, Teen, Young Adult, Adult, and Elder, will all receive an ADULT denoted Sim Type instead of TEEN, YOUNG_ADULT, ADULT, and ELDER respectively. i.e. If True, a Human Teen Sim would be denoted as ADULT_HUMAN. - If set to False, they will receive their own Sim Types. i.e. If False, a Human Teen Sim would be denoted as TEEN_HUMAN. Default is True. - :type combine_teen_young_adult_and_elder_age: bool, optional - :param combine_child_dog_types: If set to True, the Child Dog Sim Types will be combined into a single Sim Type, i.e. CHILD_DOG. If set to False, the Child Dog Sim Types will be returned as their more specific values. i.e. CHILD_LARGE_DOG, CHILD_SMALL_DOG, etc. Default is True. - :type combine_child_dog_types: bool, optional - :return: The type of Sim the Sim is or CommonSimType.NONE if no type was found for the Sim. - :rtype: CommonSimType - """ - if age is None or species is None or occult_type is None: - return CommonSimType.NONE - - if combine_teen_young_adult_and_elder_age and age in (CommonAge.TEEN, CommonAge.YOUNGADULT, CommonAge.ADULT, CommonAge.ELDER): - age = CommonAge.ADULT - - if species not in CommonSimTypeUtils._SIM_TO_SIM_TYPE_MAPPING\ - or age not in CommonSimTypeUtils._SIM_TO_SIM_TYPE_MAPPING[species]\ - or occult_type not in CommonSimTypeUtils._SIM_TO_SIM_TYPE_MAPPING[species][age]: - return CommonSimType.NONE - - sim_type = CommonSimTypeUtils._SIM_TO_SIM_TYPE_MAPPING[species][age][occult_type] - if combine_child_dog_types and sim_type in CommonSimTypeUtils._CHILD_DOG_SIM_TYPE_MAPPING: - return CommonSimTypeUtils._CHILD_DOG_SIM_TYPE_MAPPING[sim_type] - return sim_type - - @staticmethod - def convert_sim_type_to_occult_type(sim_type: CommonSimType) -> CommonOccultType: - """convert_sim_type_to_occult_type(sim_type) - - Break down a Sim Type and return the resulting Occult Type associated with it. - - :param sim_type: A Sim Type. - :type sim_type: CommonSimType - :return: The occult type associated with the Sim Type. - :rtype: CommonOccultType - """ - return CommonSimTypeUtils._OCCULT_SIM_TYPE_TO_OCCULT_TYPE_MAPPING.get(sim_type, CommonOccultType.NONE) - - @staticmethod - def convert_sim_type_to_age(sim_type: CommonSimType) -> CommonAge: - """convert_sim_type_to_age(sim_type) - - Break down a Sim Type and return the resulting Age associated with it. - - :param sim_type: A Sim Type. - :type sim_type: CommonSimType - :return: The age associated with the Sim Type. - :rtype: CommonAge - """ - return CommonSimTypeUtils._OCCULT_SIM_TYPE_TO_AGE_MAPPING.get(sim_type, CommonAge.INVALID) - - @staticmethod - def convert_sim_type_to_species(sim_type: CommonSimType) -> CommonSpecies: - """convert_sim_type_to_species(sim_type) - - Break down a Sim Type and return the resulting Species associated with it. - - :param sim_type: A Sim Type. - :type sim_type: CommonSimType - :return: The species associated with the Sim Type. - :rtype: CommonSpecies - """ - return CommonSimTypeUtils._OCCULT_SIM_TYPE_TO_SPECIES_MAPPING.get(sim_type, CommonSpecies.INVALID) - - @staticmethod - def are_same_age_and_species(sim_type_one: CommonSimType, sim_type_two: CommonSimType) -> bool: - """are_same_age_and_species(sim_type_one, sim_type_two) - - Determine if two Sim Types are comprised of the same Age and Species. - - :param sim_type_one: An instance of a Sim Type. - :type sim_type_one: CommonSimType - :param sim_type_two: An instance of a Sim Type. - :type sim_type_two: CommonSimType - :return: True, if both Sim types are the same Age and Species, ignoring Occult Types. False, if not. - :rtype: bool - """ - if sim_type_one == sim_type_two: - return True - return CommonSimTypeUtils.convert_to_non_occult_variant(sim_type_one) == CommonSimTypeUtils.convert_to_non_occult_variant(sim_type_two) - - @staticmethod - def convert_to_signature(sim_type: CommonSimType) -> str: - """convert_to_signature(sim_type) - - Convert a Sim Type to a unique signature. - - :param sim_type: The sim type to convert. - :type sim_type: CommonSimType - :return: A string signature that uniquely represents the Sim Type or the name of the Sim Type, if no unique signature is found. - :rtype: str - """ - if sim_type not in CommonSimTypeUtils._SIM_TYPE_TO_SIGNATURE_MAPPING: - return sim_type.name - return CommonSimTypeUtils._SIM_TYPE_TO_SIGNATURE_MAPPING[sim_type] - - @staticmethod - def convert_to_non_occult_variant(sim_type: CommonSimType) -> CommonSimType: - """convert_sim_type_to_non_occult_variant(sim_type) - - Convert an Occult sim type to a Non-Occult Sim Type. - - :param sim_type: The Sim Type to convert. - :type sim_type: CommonSimType - :return: The Non-Occult variant of the Sim Type or itself, if no Non-Occult variant is found. - :rtype: CommonSimType - """ - if sim_type not in CommonSimTypeUtils._OCCULT_SIM_TYPE_TO_NON_OCCULT_SIM_TYPE_MAPPING: - return sim_type - return CommonSimTypeUtils._OCCULT_SIM_TYPE_TO_NON_OCCULT_SIM_TYPE_MAPPING[sim_type] - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.print_sim_types', - 'Print a list of all Sim Types a Sim matches to.', - command_arguments=( - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to check.', is_optional=True, default_value='Active Sim'), - CommonConsoleCommandArgument('combine_teen_young_adult_and_elder_age', 'True or False', 'If True, Teen, Young Adult, and Elder will come out with the same Sim Type as an Adult Sim would. (No effect on Sims that do not fall into these ages)', is_optional=True, default_value=False), - CommonConsoleCommandArgument('combine_child_dog_types', 'True or False', 'If True, Child Small Dog and Child Large Dog will come out as a singular Sim Type of Child Dog. (No effect on Sims that are not Child Dogs)', is_optional=True, default_value=False), - ), -) -def _common_print_sim_types_for_sim(output: CommonConsoleCommandOutput, sim_info: SimInfo = None, combine_teen_young_adult_and_elder_age: bool = False, combine_child_dog_types: bool = False): - if sim_info is None: - return - output(f'Printing all Sim Types of Sim {sim_info}:') - for sim_type in CommonSimTypeUtils.get_all_sim_types_gen(sim_info, combine_teen_young_adult_and_elder_age=combine_teen_young_adult_and_elder_age, combine_child_dog_types=combine_child_dog_types): - sim_type_name = sim_type.name - output(f'- {sim_type_name}') diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_unlock_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_unlock_utils.py deleted file mode 100644 index a9c4b3c..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_unlock_utils.py +++ /dev/null @@ -1,28 +0,0 @@ -""" -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 -""" -from typing import Union -from sims.sim_info import SimInfo -from sims.unlock_tracker import UnlockTracker - - -class CommonSimUnlockUtils: - """Utilities for unlocks. """ - @classmethod - def get_unlock_tracker(cls, sim_info: SimInfo) -> Union[UnlockTracker, None]: - """get_unlock_tracker(sim_info) - - Retrieve tracker for unlocks for a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The tracker for unlocks for the Sim or None if not found. - :rtype: Union[UnlockTracker, None] - """ - if sim_info is None: - return None - return sim_info.unlock_tracker diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_utils.py deleted file mode 100644 index def8317..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_utils.py +++ /dev/null @@ -1,362 +0,0 @@ -""" -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 -""" -import services -from typing import Iterator, Callable, Union - -from objects import HiddenReasonFlag, ALL_HIDDEN_REASONS -from sims.sim import Sim -from sims.sim_info import SimInfo -from sims.sim_info_base_wrapper import SimInfoBaseWrapper -from sims.sim_info_manager import SimInfoManager -from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ - CommonConsoleCommandArgument -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.common_function_utils import CommonFunctionUtils -from s4ap.sims4communitylib.utils.misc.common_game_client_utils import CommonGameClientUtils - - -class CommonSimUtils: - """Utilities for retrieving Sims in different ways. - - .. note:: - - Available commands: - - - `s4clib_testing.display_name_of_currently_active_sim` - - `s4clib_testing.display_names_of_all_sims` - - """ - @classmethod - def get_active_sim(cls) -> Union[Sim, None]: - """get_active_sim() - - Retrieve a Sim object of the Currently Active Sim. - - .. note:: The Active Sim is the Sim with the Plumbob above their head. - - :return: An instance of the Active Sim or None if not found. - :rtype: Union[Sim, None] - """ - client = CommonGameClientUtils.get_first_game_client() - if client is None: - return None - return client.active_sim - - @classmethod - def get_active_sim_id(cls) -> int: - """get_active_sim_id() - - Retrieve the decimal identifier for the Currently Active Sim. - - .. note:: The Active Sim is the Sim with the Plumbob above their head. - - :return: The decimal identifier of the active Sim or -1 if the active Sim does not have an id or if no active Sim was found. - :rtype: int - """ - active_sim_info = cls.get_active_sim_info() - if active_sim_info is None: - return -1 - return cls.get_sim_id(active_sim_info) - - @classmethod - def get_active_sim_info(cls) -> Union[SimInfo, None]: - """get_active_sim_info() - - Retrieve a SimInfo object of the Currently Active Sim. - - :return: The SimInfo of the Active Sim or None if not found. - :rtype: Union[SimInfo, None] - """ - client = CommonGameClientUtils.get_first_game_client() - if client is None: - return None - # noinspection PyPropertyAccess - return client.active_sim_info - - @classmethod - def is_active_sim(cls, sim_info: SimInfo) -> bool: - """is_active_sim(sim_info) - - Determine if a Sim is the active Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: True, if the specified Sim is the active Sim. False, if not. - :rtype: bool - """ - return cls.get_active_sim_info() is sim_info - - @classmethod - def get_sim_info_of_sim_with_name(cls, first_name: str, last_name: str) -> Union[SimInfo, None]: - """get_sim_info_of_sim_with_name(first_name, last_name) - - Retrieve a SimInfo object for the first Sim with the specified First and Last Name. - - :param first_name: A first name to look for. - :type first_name: str - :param last_name: A last name to look for. - :type last_name: str - :return: The first Sim found with the specified first and last name or None if no Sim is found. - :rtype: Union[SimInfo, None] - """ - for sim_info in cls.get_sim_info_for_all_sims_with_name_generator(first_name, last_name): - return sim_info - return None - - @classmethod - def get_sim_info_for_all_sims_with_last_name_generator(cls, last_name: str) -> Iterator[SimInfo]: - """get_sim_info_for_all_sims_with_last_name_generator(last_name) - - Retrieve a SimInfo object for each and every Sim with the specified Last Name. - - :param last_name: A last name to look for. - :type last_name: str - :return: An iterator of Sims found with the specified last name. - :rtype: Iterator[SimInfo] - """ - from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils - last_name = last_name.lower() - - def _has_last_name(sim_info: SimInfo) -> bool: - return CommonSimNameUtils.get_last_name(sim_info).lower() == last_name - - return cls.get_sim_info_for_all_sims_generator(include_sim_callback=_has_last_name) - - @classmethod - def get_sim_info_for_all_sims_with_first_name_generator(cls, first_name: str) -> Iterator[SimInfo]: - """get_sim_info_for_all_sims_with_first_name_generator(first_name) - - Retrieve a SimInfo object for each and every Sim with the specified First Name. - - :param first_name: A first name to look for. - :type first_name: str - :return: An iterator of Sims found with the specified first name. - :rtype: Iterator[SimInfo] - """ - from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils - first_name = first_name.lower() - - def _has_first_name(sim_info: SimInfo) -> bool: - return CommonSimNameUtils.get_first_name(sim_info).lower() == first_name - - return cls.get_sim_info_for_all_sims_generator(include_sim_callback=_has_first_name) - - @classmethod - def get_sim_info_for_all_sims_with_name_generator(cls, first_name: str, last_name: str) -> Iterator[SimInfo]: - """get_sim_info_for_all_sims_with_name_generator(first_name, last_name) - - Retrieve a SimInfo object for each and every Sim with the specified First and Last Name. - - :param first_name: A first name to look for. - :type first_name: str - :param last_name: A last name to look for. - :type last_name: str - :return: An iterator of Sims found with the specified first and last name. - :rtype: Iterator[SimInfo] - """ - from s4ap.sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils - first_name = first_name.lower() - last_name = last_name.lower() - - def _has_first_and_last_name(sim_info: SimInfo) -> bool: - return CommonSimNameUtils.get_first_name(sim_info).lower() == first_name and CommonSimNameUtils.get_last_name(sim_info).lower() == last_name - - return cls.get_sim_info_for_all_sims_generator(include_sim_callback=_has_first_and_last_name) - - @classmethod - def get_all_sims_generator( - cls, - include_sim_callback: Callable[[SimInfo], Union[bool, CommonExecutionResult, CommonTestResult]] = None, - allow_hidden_flags: HiddenReasonFlag = ALL_HIDDEN_REASONS - ) -> Iterator[Sim]: - """get_all_sims_generator(include_sim_callback=None, allow_hidden_flags=ALL_HIDDEN_REASONS) - - Retrieve a Sim object for each and every Sim (including hidden Sims). - - :param include_sim_callback: If the result of this callback is True, the Sim will be included in the results. If set to None, All Sims will be included. - :type include_sim_callback: Callable[[SimInfo], bool], optional - :param allow_hidden_flags: Flags to indicate the types of hidden Sims to consider as being instanced. Default is ALL_HIDDEN_REASONS - :type allow_hidden_flags: HiddenReasonFlag, optional - :return: An iterator of all Sims matching the `include_sim_callback` filter. - :rtype: Iterator[Sim] - """ - for sim_info in cls.get_sim_info_for_all_sims_generator(include_sim_callback=include_sim_callback): - sim_instance = sim_info.get_sim_instance(allow_hidden_flags=allow_hidden_flags) - if sim_instance is None: - continue - yield sim_instance - - @classmethod - def get_sim_info_for_all_sims_generator( - cls, - include_sim_callback: Callable[[SimInfo], Union[bool, CommonExecutionResult, CommonTestResult]] = None - ) -> Iterator[SimInfo]: - """get_sim_info_for_all_sims_generator(include_sim_callback=None) - - Retrieve a SimInfo object for each and every Sim. - - :param include_sim_callback: If the result of this callback is True, the Sim will be included in the results. If set to None, All Sims will be included. - :type include_sim_callback: Callable[[SimInfo], bool], optional - :return: An iterator of all Sims matching the `include_sim_callback` filter. - :rtype: Iterator[SimInfo] - """ - sim_info_list = tuple(cls.get_sim_info_manager().get_all()) - for sim_info in sim_info_list: - if sim_info is None: - continue - if include_sim_callback is not None and not include_sim_callback(sim_info): - continue - yield sim_info - - @classmethod - def get_instanced_sim_info_for_all_sims_generator( - cls, - include_sim_callback: Callable[[SimInfo], Union[bool, CommonExecutionResult, CommonTestResult]] = None, - allow_hidden_flags: HiddenReasonFlag = ALL_HIDDEN_REASONS - ) -> Iterator[SimInfo]: - """get_instanced_sim_info_for_all_sims_generator(\ - include_sim_callback=None,\ - allow_hidden_flags=HiddenReasonFlag.NONE\ - ) - - Retrieve a SimInfo object for each and every Sim. - - .. note:: Only SimInfo with a Sim instance (:func:`~get_sim_instance`) will be returned. - - :param include_sim_callback: If the result of this callback is True, the Sim will be included in the results. If set to None, All Sims will be included. - :type include_sim_callback: Callable[[SimInfo], bool], optional - :param allow_hidden_flags: Flags to indicate the types of hidden Sims to consider as being instanced. Default is ALL_HIDDEN_REASONS - :type allow_hidden_flags: HiddenReasonFlag, optional - :return: An iterator of all Sims matching the `include_sim_callback` filter. - :rtype: Iterator[SimInfo] - """ - def _is_instanced(_sim_info: SimInfo) -> bool: - return _sim_info.get_sim_instance(allow_hidden_flags=allow_hidden_flags) is not None - - include_sim_callback = CommonFunctionUtils.run_predicates_as_one((_is_instanced, include_sim_callback)) - for sim_info in cls.get_sim_info_for_all_sims_generator(include_sim_callback=include_sim_callback): - yield sim_info - - @classmethod - def get_sim_id(cls, sim_identifier: Union[int, Sim, SimInfo, SimInfoBaseWrapper]) -> int: - """get_sim_id(sim_identifier) - - Retrieve a SimId (int) from a Sim identifier. - - :param sim_identifier: The identifier or instance of a Sim. - :type sim_identifier: Union[int, Sim, SimInfo, SimInfoBaseWrapper] - :return: The decimal identifier for the Sim instance or 0 if a problem occurs. - :rtype: int - """ - if sim_identifier is None: - return 0 - if isinstance(sim_identifier, int): - return sim_identifier - if isinstance(sim_identifier, Sim): - return sim_identifier.sim_id - if isinstance(sim_identifier, SimInfo): - return sim_identifier.id - if isinstance(sim_identifier, SimInfoBaseWrapper): - return sim_identifier.id - return 0 - - @classmethod - def get_sim_info( - cls, - sim_identifier: Union[int, Sim, SimInfo, SimInfoBaseWrapper] - ) -> Union[SimInfo, SimInfoBaseWrapper, None]: - """get_sim_info(sim_identifier) - - Retrieve a SimInfo instance from a Sim identifier. - - :param sim_identifier: The identifier or instance of a Sim to use. - :type sim_identifier: Union[int, Sim, SimInfo, SimInfoBaseWrapper] - :return: The SimInfo of the specified Sim instance or None if SimInfo is not found. - :rtype: Union[SimInfo, SimInfoBaseWrapper, None] - """ - if sim_identifier is None or isinstance(sim_identifier, SimInfo): - return sim_identifier - if isinstance(sim_identifier, SimInfoBaseWrapper): - return sim_identifier.get_sim_info() - if isinstance(sim_identifier, Sim): - return sim_identifier.sim_info - if isinstance(sim_identifier, int): - return cls.get_sim_info_manager().get(sim_identifier) - return sim_identifier - - @classmethod - def get_sim_instance( - cls, - sim_identifier: Union[int, Sim, SimInfo], - allow_hidden_flags: HiddenReasonFlag = ALL_HIDDEN_REASONS - ) -> Union[Sim, None]: - """get_sim_instance(sim_identifier, allow_hidden_flags=HiddenReasonFlag.NONE) - - Retrieve a Sim instance from a Sim identifier. - - :param sim_identifier: The identifier or instance of a Sim to use. - :type sim_identifier: Union[int, Sim, SimInfo] - :param allow_hidden_flags: Flags to indicate the types of hidden Sims to consider as being instanced. Default is ALL_HIDDEN_REASONS - :type allow_hidden_flags: HiddenReasonFlag, optional - :return: The instance of the specified Sim or None if no instance was found. - :rtype: Union[Sim, None] - """ - if sim_identifier is None or isinstance(sim_identifier, Sim): - return sim_identifier - if isinstance(sim_identifier, SimInfo): - return sim_identifier.get_sim_instance(allow_hidden_flags=allow_hidden_flags) - if isinstance(sim_identifier, int): - sim_info = cls.get_sim_info_manager().get(sim_identifier) - if sim_info is None: - return None - return cls.get_sim_instance(sim_info, allow_hidden_flags=allow_hidden_flags) - if isinstance(sim_identifier, SimInfoBaseWrapper): - return sim_identifier.get_sim_instance(allow_hidden_flags=allow_hidden_flags) - return sim_identifier - - @classmethod - def get_sim_info_manager(cls) -> SimInfoManager: - """get_sim_info_manager() - - Retrieve the manager that manages the Sim Info of all Sims in a game world. - - :return: The manager that manages the Sim Info of all Sims in a game world. - :rtype: SimInfoManager - """ - return services.sim_info_manager() - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_testing.print_name_of_sim', - 'Print the first and last name of a Sim.', - command_arguments=( - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance identifier of a Sim.', is_optional=True, default_value='Active Sim'), - ) -) -def _s4clib_testing_print_name_of_sim(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): - # noinspection PyPropertyAccess - output(f'First Name: {sim_info.first_name} Last Name: \'{sim_info.last_name}\'') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_testing.print_names_of_all_sims', - 'Print a list of the first and last names of all Sims.' -) -def _s4clib_testing_print_names_of_all_sims(output: CommonConsoleCommandOutput): - output('Printing the names of all Sims (This may take awhile).') - current_count = 1 - for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): - # noinspection PyPropertyAccess - output(f'{current_count}: First: \'{sim_info.first_name}\' Last: \'{sim_info.last_name}\'') - current_count += 1 - output('Done showing the names of all Sims.') diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_voice_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_voice_utils.py deleted file mode 100644 index 2251602..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_voice_utils.py +++ /dev/null @@ -1,462 +0,0 @@ -""" -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 -""" -from typing import Union, Dict, List, Tuple -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.enums.common_age import CommonAge -from s4ap.sims4communitylib.enums.common_gender import CommonGender -from s4ap.sims4communitylib.enums.common_species import CommonSpecies -from s4ap.sims4communitylib.enums.common_voice_actor_type import CommonVoiceActorType -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommand, \ - CommonConsoleCommandArgument -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.common_log_registry import CommonLogRegistry -from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils -from s4ap.sims4communitylib.utils.sims.common_sim_type_utils import CommonSimTypeUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - - -class CommonSimVoiceUtils: - """Utilities for manipulating the Voice of Sims. - - """ - - @staticmethod - def has_voice_actor(sim_info: SimInfo, voice_actor: Union[int, CommonVoiceActorType]) -> CommonTestResult: - """has_voice_actor(sim_info, voice_actor) - - Determine if a Sim has a specified voice actor. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param voice_actor: The voice actor to check. - :type voice_actor: Union[int, CommonVoiceActorType] - :return: The result of testing. True, if the Sim has the specified voice actor. False, if not. - :rtype: CommonTestResult - """ - if CommonSimVoiceUtils.get_voice_actor(sim_info): - return CommonTestResult.TRUE - voice_actor_str = voice_actor.name if hasattr(voice_actor, 'name') else str(voice_actor) - return CommonTestResult(False, reason=f'Sim did not have voice actor {voice_actor_str}') - - @staticmethod - def has_voice_pitch(sim_info: SimInfo, voice_pitch: float) -> CommonTestResult: - """has_voice_pitch(sim_info, voice_pitch) - - Determine if a Sim has a specified voice pitch. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param voice_pitch: The voice pitch to check. - :type voice_pitch: float - :return: The result of testing. True, if the Sim has the specified voice pitch. False, if not. - :rtype: CommonTestResult - """ - if CommonSimVoiceUtils.get_voice_pitch(sim_info) == voice_pitch: - return CommonTestResult.TRUE - return CommonTestResult(False, reason=f'Sim did not have voice pitch {voice_pitch}') - - @staticmethod - def get_voice_pitch(sim_info: SimInfo) -> float: - """get_voice_pitch(sim_info) - - Retrieve the Pitch of the Voice of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: A value that represents the pitch of the voice of a Sim. The value can range from -1.0 to 1.0 - :rtype: float - """ - # noinspection PyPropertyAccess - return sim_info.voice_pitch - - @staticmethod - def set_voice_pitch(sim_info: SimInfo, voice_pitch: float) -> CommonExecutionResult: - """set_voice_pitch(sim_info, voice_pitch) - - Set the Pitch of the Voice of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param voice_pitch: The value to set the voice pitch to, from -1.0 to 1.0. - :type voice_pitch: float - :return: The result of setting the voice pitch of the Sim. True, if successful. False, if not. - :rtype: CommonExecutionResult - """ - sim_info.voice_pitch = voice_pitch - return CommonExecutionResult.TRUE - - @staticmethod - def get_voice_actor(sim_info: SimInfo) -> Union[int, CommonVoiceActorType]: - """get_voice_actor(sim_info) - - Retrieve the Actor of the Voice of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: A value that represents the voice actor of a Sim. - :rtype: int - """ - # noinspection PyPropertyAccess - voice_actor = sim_info.voice_actor - if voice_actor not in CommonVoiceActorType.value_to_name: - return voice_actor - - return CommonResourceUtils.get_enum_by_name(CommonVoiceActorType.value_to_name[voice_actor].upper(), CommonVoiceActorType, default_value=voice_actor) - - @staticmethod - def set_voice_actor(sim_info: SimInfo, voice_actor: Union[int, CommonVoiceActorType]) -> CommonExecutionResult: - """set_voice_actor(sim_info, voice_actor) - - Set the Voice Actor of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param voice_actor: The voice actor to set the Sim to have. - :type voice_actor: Union[int, CommonVoiceActorType] - :return: The result of setting the voice actor. True, if successful. False, if not. - :rtype: CommonExecutionResult - """ - sim_info.voice_actor = int(voice_actor) - return CommonExecutionResult.TRUE - - @staticmethod - def set_to_default_voice(sim_info: SimInfo) -> CommonExecutionResult: - """set_to_default_voice(sim_info) - - Set the voice of a Sim to the default for their Age, Gender, and Species. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of setting the voice of the Sim to their default voice. True, if successful. False, if not. - :rtype: CommonExecutionResult - """ - from s4ap.sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils - if CommonGenderUtils.is_male(sim_info): - return CommonSimVoiceUtils.set_to_default_male_voice(sim_info) - else: - return CommonSimVoiceUtils.set_to_default_female_voice(sim_info) - - @staticmethod - def set_to_default_male_voice(sim_info: SimInfo) -> CommonExecutionResult: - """set_to_default_male_voice(sim_info) - - Set the voice of a Sim to the default male voice for their Age and Species. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of setting the voice of the Sim to the default male voice. True, if successful. False, if not. - :rtype: CommonExecutionResult - """ - from s4ap.sims4communitylib.utils.sims.common_age_species_utils import CommonAgeSpeciesUtils - from s4ap.sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils - from s4ap.sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils - if CommonAgeSpeciesUtils.is_teen_adult_or_elder_human(sim_info): - return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.ADULT_HUMAN_MASCULINE_1) - elif CommonAgeSpeciesUtils.is_child_human(sim_info): - return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.CHILD_HUMAN_AMBIGUOUS_1) - elif CommonAgeSpeciesUtils.is_toddler_human(sim_info): - return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.TODDLER_HUMAN_AMBIGUOUS_1) - elif CommonSpeciesUtils.is_large_dog(sim_info) and CommonAgeUtils.is_teen_adult_or_elder(sim_info): - return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.ADULT_DOG_AMBIGUOUS_1) - elif CommonSpeciesUtils.is_large_dog(sim_info) and CommonAgeUtils.is_child(sim_info): - return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.CHILD_DOG_AMBIGUOUS_1) - elif CommonSpeciesUtils.is_small_dog(sim_info) and CommonAgeUtils.is_teen_adult_or_elder(sim_info): - return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.ADULT_DOG_AMBIGUOUS_1) - elif CommonSpeciesUtils.is_small_dog(sim_info) and CommonAgeUtils.is_child(sim_info): - return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.CHILD_DOG_AMBIGUOUS_1) - elif CommonSpeciesUtils.is_cat(sim_info) and CommonAgeUtils.is_teen_adult_or_elder(sim_info): - return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.ADULT_CAT_AMBIGUOUS_1) - elif CommonSpeciesUtils.is_cat(sim_info) and CommonAgeUtils.is_child(sim_info): - return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.CHILD_CAT_AMBIGUOUS_1) - elif CommonSpeciesUtils.is_fox(sim_info) and CommonAgeUtils.is_teen_adult_or_elder(sim_info): - return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.ADULT_FOX_AMBIGUOUS_1) - elif CommonSpeciesUtils.is_horse(sim_info) and CommonAgeUtils.is_teen_adult_or_elder(sim_info): - return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.ADULT_HORSE_AMBIGUOUS_1) - elif CommonSpeciesUtils.is_horse(sim_info) and CommonAgeUtils.is_child(sim_info): - return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.CHILD_HORSE_AMBIGUOUS_1) - return CommonExecutionResult(False, reason=f'Failed to locate a default male voice actor for Sim {sim_info}') - - @staticmethod - def set_to_default_female_voice(sim_info: SimInfo) -> CommonExecutionResult: - """set_to_default_female_voice(sim_info) - - Set the voice of a Sim to the default female voice for their Age and Species. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The result of setting the voice of the Sim to the default female voice. True, if successful. False, if not. - :rtype: CommonExecutionResult - """ - from s4ap.sims4communitylib.utils.sims.common_age_species_utils import CommonAgeSpeciesUtils - from s4ap.sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils - from s4ap.sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils - if CommonAgeSpeciesUtils.is_teen_adult_or_elder_human(sim_info): - return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.ADULT_HUMAN_FEMININE_1) - elif CommonAgeSpeciesUtils.is_child_human(sim_info): - return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.CHILD_HUMAN_AMBIGUOUS_1) - elif CommonAgeSpeciesUtils.is_toddler_human(sim_info): - return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.TODDLER_HUMAN_AMBIGUOUS_1) - elif CommonSpeciesUtils.is_large_dog(sim_info) and CommonAgeUtils.is_teen_adult_or_elder(sim_info): - return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.ADULT_DOG_AMBIGUOUS_1) - elif CommonSpeciesUtils.is_large_dog(sim_info) and CommonAgeUtils.is_child(sim_info): - return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.CHILD_DOG_AMBIGUOUS_1) - elif CommonSpeciesUtils.is_small_dog(sim_info) and CommonAgeUtils.is_teen_adult_or_elder(sim_info): - return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.ADULT_DOG_AMBIGUOUS_1) - elif CommonSpeciesUtils.is_small_dog(sim_info) and CommonAgeUtils.is_child(sim_info): - return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.CHILD_DOG_AMBIGUOUS_1) - elif CommonSpeciesUtils.is_cat(sim_info) and CommonAgeUtils.is_teen_adult_or_elder(sim_info): - return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.ADULT_CAT_AMBIGUOUS_1) - elif CommonSpeciesUtils.is_cat(sim_info) and CommonAgeUtils.is_child(sim_info): - return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.CHILD_CAT_AMBIGUOUS_1) - elif CommonSpeciesUtils.is_fox(sim_info) and CommonAgeUtils.is_teen_adult_or_elder(sim_info): - return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.ADULT_FOX_AMBIGUOUS_1) - elif CommonSpeciesUtils.is_horse(sim_info) and CommonAgeUtils.is_teen_adult_or_elder(sim_info): - return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.ADULT_HORSE_AMBIGUOUS_1) - elif CommonSpeciesUtils.is_horse(sim_info) and CommonAgeUtils.is_child(sim_info): - return CommonSimVoiceUtils.set_voice_actor(sim_info, CommonVoiceActorType.CHILD_HORSE_AMBIGUOUS_1) - return CommonExecutionResult(False, reason=f'Failed to locate a default female voice actor for Sim {sim_info}') - - @staticmethod - def determine_available_voice_types(sim_info: SimInfo) -> Tuple[CommonVoiceActorType]: - """determine_available_voice_types(sim_info) - - Retrieve a collection of Voice Actor Types that are available for a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: A collection of voice actor types available for the Sim. - :rtype: Tuple[CommonVoiceActorType] - """ - from s4ap.sims4communitylib.utils.sims.common_age_species_utils import CommonAgeSpeciesUtils - from s4ap.sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils - from s4ap.sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils - if CommonAgeSpeciesUtils.is_teen_adult_or_elder_human(sim_info): - # noinspection PyTypeChecker - result: Tuple[CommonVoiceActorType] = ( - CommonVoiceActorType.MUTE, - CommonVoiceActorType.ADULT_HUMAN_AMBIGUOUS_1, - CommonVoiceActorType.ADULT_HUMAN_FEMININE_1, - CommonVoiceActorType.ADULT_HUMAN_FEMININE_2, - CommonVoiceActorType.ADULT_HUMAN_MASCULINE_1, - CommonVoiceActorType.ADULT_HUMAN_MASCULINE_2, - CommonVoiceActorType.ADULT_HUMAN_MASCULINE_3, - CommonVoiceActorType.KYLO_REN_1, - CommonVoiceActorType.REY_1, - CommonVoiceActorType.HONDO_OHNAKA_1, - ) - elif CommonAgeSpeciesUtils.is_child_human(sim_info): - # noinspection PyTypeChecker - result: Tuple[CommonVoiceActorType] = ( - CommonVoiceActorType.MUTE, - CommonVoiceActorType.CHILD_HUMAN_AMBIGUOUS_1, - CommonVoiceActorType.CHILD_HUMAN_AMBIGUOUS_2, - CommonVoiceActorType.KYLO_REN_1, - CommonVoiceActorType.REY_1, - CommonVoiceActorType.HONDO_OHNAKA_1, - ) - elif CommonAgeSpeciesUtils.is_toddler_human(sim_info): - # noinspection PyTypeChecker - result: Tuple[CommonVoiceActorType] = ( - CommonVoiceActorType.MUTE, - CommonVoiceActorType.TODDLER_HUMAN_AMBIGUOUS_1, - ) - elif CommonSpeciesUtils.is_large_dog(sim_info) and CommonAgeUtils.is_teen_adult_or_elder(sim_info): - # noinspection PyTypeChecker - result: Tuple[CommonVoiceActorType] = ( - CommonVoiceActorType.MUTE, - CommonVoiceActorType.ADULT_DOG_AMBIGUOUS_1, - CommonVoiceActorType.ADULT_DOG_AMBIGUOUS_2, - CommonVoiceActorType.ADULT_DOG_AMBIGUOUS_3, - CommonVoiceActorType.ADULT_DOG_AMBIGUOUS_4 - ) - elif CommonSpeciesUtils.is_large_dog(sim_info) and CommonAgeUtils.is_child(sim_info): - # noinspection PyTypeChecker - result: Tuple[CommonVoiceActorType] = ( - CommonVoiceActorType.MUTE, - CommonVoiceActorType.CHILD_DOG_AMBIGUOUS_1, - ) - elif CommonSpeciesUtils.is_small_dog(sim_info) and CommonAgeUtils.is_teen_adult_or_elder(sim_info): - # noinspection PyTypeChecker - result: Tuple[CommonVoiceActorType] = ( - CommonVoiceActorType.MUTE, - CommonVoiceActorType.ADULT_DOG_AMBIGUOUS_1, - CommonVoiceActorType.ADULT_DOG_AMBIGUOUS_2, - CommonVoiceActorType.ADULT_DOG_AMBIGUOUS_3, - CommonVoiceActorType.ADULT_DOG_AMBIGUOUS_4 - ) - elif CommonSpeciesUtils.is_small_dog(sim_info) and CommonAgeUtils.is_child(sim_info): - # noinspection PyTypeChecker - result: Tuple[CommonVoiceActorType] = ( - CommonVoiceActorType.MUTE, - CommonVoiceActorType.CHILD_DOG_AMBIGUOUS_1, - ) - elif CommonSpeciesUtils.is_cat(sim_info) and CommonAgeUtils.is_teen_adult_or_elder(sim_info): - # noinspection PyTypeChecker - result: Tuple[CommonVoiceActorType] = ( - CommonVoiceActorType.MUTE, - CommonVoiceActorType.ADULT_CAT_AMBIGUOUS_1, - CommonVoiceActorType.ADULT_CAT_AMBIGUOUS_2, - ) - elif CommonSpeciesUtils.is_cat(sim_info) and CommonAgeUtils.is_child(sim_info): - # noinspection PyTypeChecker - result: Tuple[CommonVoiceActorType] = ( - CommonVoiceActorType.MUTE, - CommonVoiceActorType.CHILD_CAT_AMBIGUOUS_1, - ) - elif CommonSpeciesUtils.is_fox(sim_info) and CommonAgeUtils.is_teen_adult_or_elder(sim_info): - # noinspection PyTypeChecker - result: Tuple[CommonVoiceActorType] = ( - CommonVoiceActorType.MUTE, - CommonVoiceActorType.ADULT_FOX_AMBIGUOUS_1, - ) - elif CommonSpeciesUtils.is_horse(sim_info) and CommonAgeUtils.is_teen_adult_or_elder(sim_info): - # noinspection PyTypeChecker - result: Tuple[CommonVoiceActorType] = ( - CommonVoiceActorType.MUTE, - CommonVoiceActorType.ADULT_HORSE_AMBIGUOUS_1, - ) - elif CommonSpeciesUtils.is_horse(sim_info) and CommonAgeUtils.is_child(sim_info): - # noinspection PyTypeChecker - result: Tuple[CommonVoiceActorType] = ( - CommonVoiceActorType.MUTE, - CommonVoiceActorType.CHILD_HORSE_AMBIGUOUS_1, - ) - else: - result: Tuple[CommonVoiceActorType] = ( - CommonVoiceActorType.MUTE, - ) - return result - - -log = CommonLogRegistry().register_log(ModInfo.get_identity(), 'common_voice_actor_log') -log.enable() - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.print_voice', - 'Print information about the voice of a Sim.', - command_arguments=( - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to check.', is_optional=True, default_value='Active Sim'), - ), -) -def _common_print_voice_pitch(output: CommonConsoleCommandOutput, sim_info: SimInfo=None): - if sim_info is None: - return - voice_pitch = CommonSimVoiceUtils.get_voice_pitch(sim_info) - voice_actor = CommonSimVoiceUtils.get_voice_actor(sim_info) - voice_actor_name = voice_actor.name if hasattr(voice_actor, 'name') else voice_actor - log.debug(f'Voice info about {sim_info}') - log.debug(f'Voice Pitch: {voice_pitch}') - log.debug(f'Voice Actor: {voice_actor_name}') - output(f'Voice info about {sim_info}') - output(f'Voice Pitch: {voice_pitch}') - output(f'Voice Actor: {voice_actor_name}') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.set_voice_pitch', - 'Set the pitch of a Sims voice.', - command_arguments=( - CommonConsoleCommandArgument('voice_pitch', 'Decimal Identifier', 'The voice pitch to set the voice of the Sim to.'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to change.', is_optional=True, default_value='Active Sim'), - ) -) -def _common_set_voice_pitch(output: CommonConsoleCommandOutput, voice_pitch: float, sim_info: SimInfo=None): - if sim_info is None: - return - if voice_pitch is None: - return - result = CommonSimVoiceUtils.set_voice_pitch(sim_info, voice_pitch) - if result: - log.format_with_message('Set voice pitch', sim=sim_info, voice_pitch=voice_pitch, result=result) - output(f'SUCCESS: Successfully set the voice pitch of Sim {sim_info} to {voice_pitch}: {result}') - else: - log.format_with_message('Set voice pitch', sim=sim_info, voice_pitch=voice_pitch, result=result) - output(f'FAILED: Failed to set the voice pitch of Sim {sim_info} to {voice_pitch}: {result}') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.set_voice_actor', - 'Set the voice actor of a Sims voice.', - command_arguments=( - CommonConsoleCommandArgument('voice_actor', 'CommonVoiceActorType', f'The voice actor to change the Sim to. Valid Voice Actors: ({CommonVoiceActorType.get_comma_separated_names_string()})'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to change.', is_optional=True, default_value='Active Sim'), - ) -) -def _common_set_voice_actor(output: CommonConsoleCommandOutput, voice_actor: CommonVoiceActorType, sim_info: SimInfo=None): - if voice_actor is None: - return - if sim_info is None: - return - voice_actor_name = voice_actor.name - output(f'Attempting to set the voice actor of {sim_info} to {voice_actor_name}.') - result = CommonSimVoiceUtils.set_voice_actor(sim_info, voice_actor) - if result: - output(f'SUCCESS: Successfully set the voice actor of {sim_info} to {voice_actor_name}: {result}') - else: - output(f'FAILED: Failed to set the voice actor of {sim_info} to {voice_actor_name}: {result}') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.set_voice_actor_custom', - 'Set the voice actor of a Sims voice to a custom voice. NOTE: Success does not mean that it truly succeeded, much of the time the Sim will become Mute instead.', - command_arguments=( - CommonConsoleCommandArgument('voice_actor_id', 'int', 'The id of the voice actor to change the Sim to.'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The name or instance id of the Sim to change.', is_optional=True, default_value='Active Sim'), - ) -) -def _common_set_voice_actor_custom(output: CommonConsoleCommandOutput, voice_actor_id: int, sim_info: SimInfo=None): - if voice_actor_id is None: - return - if sim_info is None: - return - output(f'Attempting to set the voice actor of {sim_info} to {voice_actor_id}.') - result = CommonSimVoiceUtils.set_voice_actor(sim_info, voice_actor_id) - if result: - output(f'SUCCESS: Successfully set the voice actor of {sim_info} to {voice_actor_id}: {result}') - else: - output(f'FAILED: Failed to set the voice actor of {sim_info} to {voice_actor_id}: {result}') - - -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_dev.print_all_voice_actors', - 'Print a list of all available Voice Actors (It entirely depends on all of the Sims available in the game though)', - show_with_help_command=False -) -def _common_get_all_voice_actors(output: CommonConsoleCommandOutput): - output('Printing all voice actors.') - sim_count = 0 - duplicate_count = 0 - voice_actor_by_age: Dict[(CommonAge, CommonSpecies, CommonGender), List[Union[int, CommonVoiceActorType]]] = dict() - for sim_info in CommonSimUtils.get_sim_info_for_all_sims_generator(): - sim_type = CommonSimTypeUtils.determine_sim_type(sim_info) - gender = CommonGender.get_gender(sim_info) - key = (sim_type.name, gender.name) - if key not in voice_actor_by_age: - voice_actor_by_age[key] = list() - voice_actor_list = voice_actor_by_age[key] - voice_actor = CommonSimVoiceUtils.get_voice_actor(sim_info) - sim_count += 1 - if voice_actor in voice_actor_list: - duplicate_count += 1 - continue - log.format_with_message('Adding voice actor from Sim', sim=sim_info, voice_actor=voice_actor.name if isinstance(voice_actor, CommonVoiceActorType) else voice_actor) - voice_actor_list.append(voice_actor) - voice_actor_by_age[key] = voice_actor_list - log.format_with_message('Voice Actor', voice_actors=voice_actor_by_age, sim_count=sim_count, duplicate_count=duplicate_count) - for (_key, _voice_actor) in voice_actor_by_age.items(): - voice_actor_name = _voice_actor.name if isinstance(_voice_actor, CommonVoiceActorType) else _voice_actor - output(f'Voice Actor {_key} = {voice_actor_name}') diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_walkstyle_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_walkstyle_utils.py deleted file mode 100644 index c9ed591..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_sim_walkstyle_utils.py +++ /dev/null @@ -1,62 +0,0 @@ -""" -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 -""" -from typing import Union -from routing.walkstyle.walkstyle_tuning import Walkstyle -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - - -class CommonSimWalkstyleUtils(_HasS4CLClassLog): - """Utilities for manipulating the Walkstyle of Sims. - - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 'common_sim_walkstyle_utils' - - @classmethod - def get_default_walkstyle(cls, sim_info: SimInfo) -> Union[Walkstyle, None]: - """get_default_walkstyle(sim_info) - - Retrieve the default walkstyle of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The default walkstyle of a Sim or None if the Sim is not available or has no default walk style. - :rtype: Union[Walkstyle, None] - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return None - return sim.routing_component.get_default_walkstyle() - - @classmethod - def get_current_walkstyle(cls, sim_info: SimInfo) -> Union[Walkstyle, None]: - """get_current_walkstyle(sim_info) - - Retrieve the current walkstyle of a Sim. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :return: The current walkstyle of the Sim or None when not found. - :rtype: Union[Walkstyle, None] - """ - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return None - routing_component = sim.routing_component - if routing_component is None: - return None - path = routing_component.current_path - if path: - return routing_component.get_walkstyle_for_path(routing_component.current_path) - - return cls.get_default_walkstyle(sim_info) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_species_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_species_utils.py deleted file mode 100644 index 995fd81..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_species_utils.py +++ /dev/null @@ -1,336 +0,0 @@ -""" -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 -""" -from typing import Union - -from sims.sim_info import SimInfo -from sims.sim_info_types import Species, SpeciesExtended -from s4ap.sims4communitylib.enums.traits_enum import CommonTraitId -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.utils.common_log_registry import CommonLogRegistry -from s4ap.sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils - -log = CommonLogRegistry.get().register_log(ModInfo.get_identity(), 'common_species_utils') - - -class CommonSpeciesUtils: - """Utilities for manipulating and checking the Species of Sims. - - """ - @classmethod - def get_species(cls, sim_info: SimInfo) -> Union[Species, SpeciesExtended, None]: - """get_species(sim_info) - - Retrieve the Species of a sim. - - :param sim_info: The Sim to get the Species of. - :type sim_info: SimInfo - :return: The Species of the Sim or None if the Sim does not have a Species. - :rtype: Union[Species, SpeciesExtended, None] - """ - if sim_info is None: - return None - if hasattr(sim_info, 'species'): - return sim_info.species - if hasattr(sim_info, 'sim_info') and hasattr(sim_info.sim_info, 'species'): - return sim_info.sim_info.species - return None - - @classmethod - def set_species(cls, sim_info: SimInfo, species: Union[Species, SpeciesExtended, int]) -> bool: - """set_species(sim_info, species) - - Set the Species of a sim. - - :param sim_info: The Sim to set the Species of. - :type sim_info: SimInfo - :param species: The Species to set the Sim to. - :type species: Union[Species, SpeciesExtended, int] - :return: True, if successful. False, if not. - :rtype: bool - """ - sim_info.species = species - return True - - @classmethod - def are_same_species(cls, sim_info: SimInfo, other_sim_info: SimInfo) -> bool: - """are_same_species(sim_info, other_sim_info) - - Determine if two sims are of the same species. - - .. note:: Extended Species are also compared (Large Dog, Small Dog, etc.) - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :param other_sim_info: The Sim to compare to. - :type other_sim_info: SimInfo - :return: True, if both Sims are the same species. False, if not. - :rtype: bool - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - if other_sim_info is None: - raise AssertionError('Argument other_sim_info was None') - from s4ap.sims4communitylib.enums.common_species import CommonSpecies - species_one = CommonSpecies.get_species(sim_info) - species_two = CommonSpecies.get_species(other_sim_info) - log.format(species_one=species_one, species_two=species_two, sim_one=sim_info, other_sim_info=other_sim_info) - return species_one == species_two - - @classmethod - def is_human_species(cls, species: Union[Species, SpeciesExtended, int]) -> bool: - """is_human_species(species) - - Determine if a Species is a Human. - - :param species: The Species to check. - :type species: Union[Species, SpeciesExtended, int] - :return: True, if the Species is Human. False, if not. - :rtype: bool - """ - if not hasattr(Species, 'HUMAN'): - return False - return species == Species.HUMAN or species == SpeciesExtended.HUMAN - - @classmethod - def is_pet_species(cls, species: Union[Species, SpeciesExtended, int]) -> bool: - """is_pet_species(species) - - Determine if a Species is a Pet. - - :param species: The Species to check. - :type species: Union[Species, SpeciesExtended, int] - :return: True, if the Species is a Pet Species (Large Dog, Small Dog, Cat). False, if not. - :rtype: bool - """ - return cls.is_dog_species(species) or cls.is_cat_species(species) or cls.is_horse_species(species) - - @classmethod - def is_animal_species(cls, species: Union[Species, SpeciesExtended, int]) -> bool: - """is_animal_species(species) - - Determine if a Species is an Animal. - - :param species: The Species to check. - :type species: Union[Species, SpeciesExtended, int] - :return: True, if the Species is an Animal Species (Large Dog, Small Dog, Cat, or Fox). False, if not. - :rtype: bool - """ - return cls.is_pet_species(species) or cls.is_fox_species(species) - - @classmethod - def is_dog_species(cls, species: Union[Species, SpeciesExtended, int]) -> bool: - """is_dog_species(species) - - Determine if a Species is a Dog. - - :param species: The Species to check. - :type species: Union[Species, SpeciesExtended, int] - :return: True, if the Species is a Dog Species (Large Dog, Small Dog). False, if not. - :rtype: bool - """ - return cls.is_large_dog_species(species) or cls.is_small_dog_species(species) - - @classmethod - def is_large_dog_species(cls, species: Union[Species, SpeciesExtended, int]) -> bool: - """is_large_dog_species(species) - - Determine if a Species is a Large Dog. - - :param species: The Species to check. - :type species: Union[Species, SpeciesExtended, int] - :return: True, if the Species is a Large Dog Species. False, if not. - :rtype: bool - """ - if hasattr(Species, 'DOG'): - if species == Species.DOG or species == SpeciesExtended.DOG: - return True - return False - - @classmethod - def is_small_dog_species(cls, species: Union[Species, SpeciesExtended, int]) -> bool: - """is_small_dog_species(species) - - Determine if a Species is a Small Dog. - - :param species: The Species to check. - :type species: Union[Species, SpeciesExtended, int] - :return: True, if the Species is a Small Dog Species. False, if not. - :rtype: bool - """ - if hasattr(SpeciesExtended, 'SMALLDOG'): - if species == SpeciesExtended.SMALLDOG: - return True - return False - - @classmethod - def is_cat_species(cls, species: Union[Species, SpeciesExtended, int]) -> bool: - """is_cat_species(species) - - Determine if a Species is a Cat. - - :param species: The Species to check. - :type species: Union[Species, SpeciesExtended, int] - :return: True, if the Species is a Cat Species. False, if not. - :rtype: bool - """ - if not hasattr(Species, 'CAT'): - return False - return species == Species.CAT or species == SpeciesExtended.CAT - - @classmethod - def is_fox_species(cls, species: Union[Species, SpeciesExtended, int]) -> bool: - """is_fox_species(species) - - Determine if a Species is a Fox. - - :param species: The Species to check. - :type species: Union[Species, SpeciesExtended, int] - :return: True, if the Species is a Fox Species. False, if not. - :rtype: bool - """ - if not hasattr(Species, 'FOX'): - return False - return species == Species.FOX or species == SpeciesExtended.FOX - - @classmethod - def is_horse_species(cls, species: Union[Species, SpeciesExtended, int]) -> bool: - """is_horse_species(species) - - Determine if a Species is a Horse. - - :param species: The Species to check. - :type species: Union[Species, SpeciesExtended, int] - :return: True, if the Species is a Horse Species. False, if not. - :rtype: bool - """ - if not hasattr(Species, 'HORSE'): - return False - return species == Species.HORSE or species == SpeciesExtended.HORSE - - @classmethod - def is_dog(cls, sim_info: SimInfo) -> bool: - """is_dog(sim_info) - - Determine if a Sim is a Dog. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is a Dog (Large Dog, Small Dog). False, if not. - :rtype: bool - """ - return cls.is_dog_species(cls.get_species(sim_info)) - - @classmethod - def is_human(cls, sim_info: SimInfo) -> bool: - """is_human(sim_info) - - Determine if a Sim is a Human. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is a Human. False, if not. - :rtype: bool - """ - return cls.is_human_species(cls.get_species(sim_info)) - - @classmethod - def is_pet(cls, sim_info: SimInfo) -> bool: - """is_pet(sim_info) - - Determine if a Sim is a Pet. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is a Pet (Large Dog, Small Dog, Cat). False, if not. - :rtype: bool - """ - return cls.is_pet_species(cls.get_species(sim_info)) - - @classmethod - def is_animal(cls, sim_info: SimInfo) -> bool: - """is_animal(sim_info) - - Determine if a Sim is an Animal. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is an Animal (Large Dog, Small Dog, Cat, Fox). False, if not. - :rtype: bool - """ - return cls.is_animal_species(cls.get_species(sim_info)) - - @classmethod - def is_large_dog(cls, sim_info: SimInfo) -> bool: - """is_large_dog(sim_info) - - Determine if a Sim is a Large Dog. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is a Large Dog. False, if not. - :rtype: bool - """ - from s4ap.sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils - from s4ap.sims4communitylib.enums.traits_enum import CommonTraitId - return cls.is_dog_species(cls.get_species(sim_info)) and CommonTraitUtils.has_trait(sim_info, CommonTraitId.SPECIES_EXTENDED_LARGE_DOGS) - - @classmethod - def is_small_dog(cls, sim_info: SimInfo) -> bool: - """is_small_dog(sim_info) - - Determine if a Sim is a Small Dog. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is a Small Dog. False, if not. - :rtype: bool - """ - from s4ap.sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils - from s4ap.sims4communitylib.enums.traits_enum import CommonTraitId - return cls.is_dog_species(cls.get_species(sim_info)) and CommonTraitUtils.has_trait(sim_info, CommonTraitId.SPECIES_EXTENDED_SMALL_DOGS) - - @classmethod - def is_cat(cls, sim_info: SimInfo) -> bool: - """is_cat(sim_info) - - Determine if a Sim is a Cat. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is a Cat. False, if not. - :rtype: bool - """ - from s4ap.sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils - from s4ap.sims4communitylib.enums.traits_enum import CommonTraitId - return cls.is_cat_species(cls.get_species(sim_info)) or CommonTraitUtils.has_trait(sim_info, CommonTraitId.SPECIES_CAT) - - @classmethod - def is_fox(cls, sim_info: SimInfo) -> bool: - """is_fox(sim_info) - - Determine if a Sim is a Fox. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is a Fox. False, if not. - :rtype: bool - """ - return cls.is_fox_species(cls.get_species(sim_info)) or CommonTraitUtils.has_trait(sim_info, CommonTraitId.SPECIES_FOX) - - @classmethod - def is_horse(cls, sim_info: SimInfo) -> bool: - """is_horse(sim_info) - - Determine if a Sim is a Horse. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: True, if the Sim is a Horse. False, if not. - :rtype: bool - """ - return cls.is_horse_species(cls.get_species(sim_info)) or CommonTraitUtils.has_trait(sim_info, CommonTraitId.SPECIES_HORSE) diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_trait_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_trait_utils.py deleted file mode 100644 index 0acc1eb..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_trait_utils.py +++ /dev/null @@ -1,1655 +0,0 @@ -""" -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 -""" -from typing import List, Union, Callable, Iterator, Tuple - -from distributor.shared_messages import IconInfoData -from relationships.relationship_tracker import RelationshipTracker -from relationships.sim_knowledge import SimKnowledge -from server_commands.argument_helpers import TunableInstanceParam -from sims.pregnancy.pregnancy_offspring_data import PregnancyOffspringData -from sims.sim_info import SimInfo -from sims.sim_info_base_wrapper import SimInfoBaseWrapper -from sims4.resources import Types -from s4ap.sims4communitylib.classes.testing.common_execution_result import CommonExecutionResult -from s4ap.sims4communitylib.classes.testing.common_test_result import CommonTestResult -from s4ap.sims4communitylib.enums.traits_enum import CommonTraitId -from s4ap.sims4communitylib.logging._has_s4cl_class_log import _HasS4CLClassLog -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.notifications.common_basic_notification import CommonBasicNotification -from s4ap.sims4communitylib.services.commands.common_console_command import CommonConsoleCommandArgument, \ - CommonConsoleCommand -from s4ap.sims4communitylib.services.commands.common_console_command_output import CommonConsoleCommandOutput -from s4ap.sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils -from traits.traits import Trait - - -class CommonTraitUtils(_HasS4CLClassLog): - """Utilities for manipulating Traits on Sims. - - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 'common_trait_utils' - - @classmethod - def is_player(cls, sim_info: SimInfo) -> CommonTestResult: - """is_player(sim_info) - - Determine if a Sim has the Player trait. - - .. note:: This does not indicate whether the Sim is one of the Players Sims, it simply indicates if they have the trait that makes other Sims less jealous. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - return cls.has_trait(sim_info, CommonTraitId.PLAYER) - - @classmethod - def is_special_npc(cls, sim_info: SimInfo) -> CommonTestResult: - """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: The result of testing. True, if the Sim is a special NPC. False, if the Sim is not a Special NPC. - :rtype: CommonTestResult - """ - traits = ( - CommonTraitId.HIDDEN_IS_EVENT_NPC_CHALLENGE, - CommonTraitId.IS_GRIM_REAPER, - CommonTraitId.SCARECROW, - CommonTraitId.FLOWER_BUNNY - ) - return cls.has_any_traits(sim_info, traits) - - @classmethod - def is_active(cls, sim_info: SimInfo) -> CommonTestResult: - """is_active(sim_info) - - Determine if a Sim is active. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - return cls.has_trait(sim_info, CommonTraitId.ACTIVE) - - @classmethod - def is_aggressive_pet(cls, sim_info: SimInfo) -> CommonTestResult: - """is_aggressive_pet(sim_info) - - Determine if a pet Sim is Aggressive. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - traits = ( - CommonTraitId.PET_AGGRESSIVE_DOG, - CommonTraitId.PET_AGGRESSIVE_CAT - ) - return cls.has_any_traits(sim_info, traits) - - @classmethod - def is_alluring(cls, sim_info: SimInfo) -> CommonTestResult: - """is_alluring(sim_info) - - Determine if a Sim is Alluring. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - return cls.has_trait(sim_info, CommonTraitId.ALLURING) - - @classmethod - def is_antiseptic(cls, sim_info: SimInfo) -> CommonTestResult: - """is_antiseptic(sim_info) - - Determine if a Sim is Antiseptic. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - return cls.has_trait(sim_info, CommonTraitId.ANTISEPTIC) - - @classmethod - def is_bro(cls, sim_info: SimInfo) -> CommonTestResult: - """is_bro(sim_info) - - Determine if a Sim is a Bro. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - return cls.has_trait(sim_info, CommonTraitId.BRO) - - @classmethod - def is_carefree(cls, sim_info: SimInfo) -> CommonTestResult: - """is_carefree(sim_info) - - Determine if a Sim is Care Free. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - return cls.has_trait(sim_info, CommonTraitId.CAREFREE) - - @classmethod - def is_cat_lover(cls, sim_info: SimInfo) -> CommonTestResult: - """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: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - return cls.has_trait(sim_info, CommonTraitId.CAT_LOVER) - - @classmethod - def is_dog_lover(cls, sim_info: SimInfo) -> CommonTestResult: - """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: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - return cls.has_trait(sim_info, CommonTraitId.DOG_LOVER) - - @classmethod - def is_clumsy(cls, sim_info: SimInfo) -> CommonTestResult: - """is_clumsy(sim_info) - - Determine if a Sim is Clumsy. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - return cls.has_trait(sim_info, CommonTraitId.CLUMSY) - - @classmethod - def is_dastardly(cls, sim_info: SimInfo) -> CommonTestResult: - """is_dastardly(sim_info) - - Determine if a Sim is Dastardly. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - return cls.has_trait(sim_info, CommonTraitId.DASTARDLY) - - @classmethod - def is_criminal(cls, sim_info: SimInfo) -> CommonTestResult: - """is_criminal(sim_info) - - Determine if a Sim is a Criminal. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - traits = ( - CommonTraitId.DETECTIVE_CAREER_CRIMINAL, - CommonTraitId.DETECTIVE_CAREER_POLICE_STATION_CRIMINAL_NPC - ) - return cls.has_any_traits(sim_info, traits) - - @classmethod - def is_evil(cls, sim_info: SimInfo) -> CommonTestResult: - """is_evil(sim_info) - - Determine if a Sim is Evil. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - traits = ( - CommonTraitId.EVIL, - CommonTraitId.EVIL_BEGONIA_SCENT - ) - return cls.has_any_traits(sim_info, traits) - - @classmethod - def is_fertile(cls, sim_info: SimInfo) -> CommonTestResult: - """is_fertile(sim_info) - - Determine if a Sim is Fertile. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - return cls.has_trait(sim_info, CommonTraitId.FERTILE) - - @classmethod - def is_friendly_pet(cls, sim_info: SimInfo) -> CommonTestResult: - """is_friendly_pet(sim_info) - - Determine if a pet Sim is Friendly. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - traits = ( - CommonTraitId.PET_FRIENDLY_DOG, - CommonTraitId.PET_FRIENDLY_CAT - ) - return cls.has_any_traits(sim_info, traits) - - @classmethod - def is_geek(cls, sim_info: SimInfo) -> CommonTestResult: - """is_geek(sim_info) - - Determine if a Sim is a geek. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - return cls.has_trait(sim_info, CommonTraitId.GEEK) - - @classmethod - def is_genius(cls, sim_info: SimInfo) -> CommonTestResult: - """is_genius(sim_info) - - Determine if a Sim is a Genius. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - return cls.has_trait(sim_info, CommonTraitId.GENIUS) - - @classmethod - def is_good(cls, sim_info: SimInfo) -> CommonTestResult: - """is_good(sim_info) - - Determine if a Sim is Good. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - return cls.has_trait(sim_info, CommonTraitId.GOOD) - - @classmethod - def is_glutton(cls, sim_info: SimInfo) -> CommonTestResult: - """is_glutton(sim_info) - - Determine if a Sim is a Glutton. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - return cls.is_glutton_human(sim_info) or cls.is_glutton_pet(sim_info) - - @classmethod - def is_glutton_human(cls, sim_info: SimInfo) -> CommonTestResult: - """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: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - return cls.has_trait(sim_info, CommonTraitId.GLUTTON) - - @classmethod - def is_glutton_pet(cls, sim_info: SimInfo) -> CommonTestResult: - """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: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - traits = ( - CommonTraitId.PET_GLUTTON_DOG, - CommonTraitId.PET_GLUTTON_CAT - ) - return cls.has_any_traits(sim_info, traits) - - @classmethod - def is_gregarious(cls, sim_info: SimInfo) -> CommonTestResult: - """is_gregarious(sim_info) - - Determine if a Sim is Gregarious. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - return cls.has_trait(sim_info, CommonTraitId.GREGARIOUS) - - @classmethod - def is_hot_headed(cls, sim_info: SimInfo) -> CommonTestResult: - """is_hot_headed(sim_info) - - Determine if a Sim is Hot Headed. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - return cls.has_trait(sim_info, CommonTraitId.HOT_HEADED) - - @classmethod - def is_hunter_pet(cls, sim_info: SimInfo) -> CommonTestResult: - """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: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - traits = ( - CommonTraitId.PET_HUNTER_DOG, - CommonTraitId.PET_HUNTER_CAT - ) - return cls.has_any_traits(sim_info, traits) - - @classmethod - def is_incredibly_friendly(cls, sim_info: SimInfo) -> CommonTestResult: - """is_incredibly_friendly(sim_info) - - Determine if a Sim is Incredibly Friendly. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - return cls.has_trait(sim_info, CommonTraitId.INCREDIBLY_FRIENDLY) - - @classmethod - def is_insane(cls, sim_info: SimInfo) -> CommonTestResult: - """is_insane(sim_info) - - Determine if a Sim is Insane. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - return cls.has_trait(sim_info, CommonTraitId.INSANE) - - @classmethod - def is_insider(cls, sim_info: SimInfo) -> CommonTestResult: - """is_insider(sim_info) - - Determine if a Sim is an Insider. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - return cls.has_trait(sim_info, CommonTraitId.INSIDER) - - @classmethod - def is_loyal_pet(cls, sim_info: SimInfo) -> CommonTestResult: - """is_loyal_pet(sim_info) - - Determine if a pet Sim is Loyal. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - traits = ( - CommonTraitId.PET_LOYAL_DOG, - CommonTraitId.PET_LOYAL_CAT - ) - return cls.has_any_traits(sim_info, traits) - - @classmethod - def is_mean(cls, sim_info: SimInfo) -> CommonTestResult: - """is_mean(sim_info) - - Determine if a Sim is Mean. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - return cls.has_trait(sim_info, CommonTraitId.MEAN) - - @classmethod - def is_mentor(cls, sim_info: SimInfo) -> CommonTestResult: - """is_mentor(sim_info) - - Determine if a Sim is a Mentor. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - return cls.has_trait(sim_info, CommonTraitId.MENTOR) - - @classmethod - def is_morning_person(cls, sim_info: SimInfo) -> CommonTestResult: - """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: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - return cls.has_trait(sim_info, CommonTraitId.MORNING_PERSON) - - @classmethod - def is_naughty_pet(cls, sim_info: SimInfo) -> CommonTestResult: - """is_naughty_pet(sim_info) - - Determine if a pet Sim is Naughty. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - traits = ( - CommonTraitId.PET_NAUGHTY_DOG, - CommonTraitId.PET_NAUGHTY_CAT - ) - return cls.has_any_traits(sim_info, traits) - - @classmethod - def is_neat(cls, sim_info: SimInfo) -> CommonTestResult: - """is_neat(sim_info) - - Determine if a Sim is neat. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - return cls.has_trait(sim_info, CommonTraitId.NEAT) - - @classmethod - def is_night_owl(cls, sim_info: SimInfo) -> CommonTestResult: - """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: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - traits = ( - CommonTraitId.NIGHT_OWL, - CommonTraitId.NIGHT_OWL_CRYSTAL_HELMET - ) - return cls.has_any_traits(sim_info, traits) - - @classmethod - def is_lazy(cls, sim_info: SimInfo) -> CommonTestResult: - """is_lazy(sim_info) - - Determine if a Sim is Lazy. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - return cls.has_trait(sim_info, CommonTraitId.LAZY) - - @classmethod - def is_loner(cls, sim_info: SimInfo) -> CommonTestResult: - """is_loner(sim_info) - - Determine if a Sim is a Loner. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - return cls.has_trait(sim_info, CommonTraitId.LONER) - - @classmethod - def is_love_guru(cls, sim_info: SimInfo) -> CommonTestResult: - """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: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - return cls.has_trait(sim_info, CommonTraitId.LOVE_GURU) - - @classmethod - def is_self_absorbed(cls, sim_info: SimInfo) -> CommonTestResult: - """is_self_absorbed(sim_info) - - Determine if a Sim is Self Absorbed. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - return cls.has_trait(sim_info, CommonTraitId.SELF_ABSORBED) - - @classmethod - def is_self_assured(cls, sim_info: SimInfo) -> CommonTestResult: - """is_self_assured(sim_info) - - Determine if a Sim is Self Assured. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - return cls.has_trait(sim_info, CommonTraitId.SELF_ASSURED) - - @classmethod - def is_service_sim(cls, sim_info: SimInfo) -> CommonTestResult: - """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 s4ap.sims4communitylib.utils.sims.common_sim_type_utils import CommonSimTypeUtils - return CommonSimTypeUtils.is_service_sim(sim_info) - - @classmethod - def is_shameless(cls, sim_info: SimInfo) -> CommonTestResult: - """is_shameless(sim_info) - - Determine if a Sim is Shameless. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - return cls.has_trait(sim_info, CommonTraitId.SHAMELESS) - - @classmethod - def is_sincere(cls, sim_info: SimInfo) -> CommonTestResult: - """is_sincere(sim_info) - - Determine if a Sim is Sincere. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - return cls.has_trait(sim_info, CommonTraitId.SINCERE) - - @classmethod - def is_skittish_pet(cls, sim_info: SimInfo) -> CommonTestResult: - """is_skittish_pet(sim_info) - - Determine if a pet Sim is Skittish. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - traits = ( - CommonTraitId.PET_SKITTISH_DOG, - CommonTraitId.PET_SKITTISH_CAT - ) - return cls.has_any_traits(sim_info, traits) - - @classmethod - def is_slob(cls, sim_info: SimInfo) -> CommonTestResult: - """is_slob(sim_info) - - Determine if a Sim is a Slob. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - return cls.has_trait(sim_info, CommonTraitId.SLOB) - - @classmethod - def is_snob(cls, sim_info: SimInfo) -> CommonTestResult: - """is_snob(sim_info) - - Determine if a Sim is a Snob. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - return cls.has_trait(sim_info, CommonTraitId.SNOB) - - @classmethod - def is_squeamish(cls, sim_info: SimInfo) -> CommonTestResult: - """is_squeamish(sim_info) - - Determine if a Sim is Squeamish. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - return cls.has_trait(sim_info, CommonTraitId.SQUEAMISH) - - @classmethod - def is_survivalist(cls, sim_info: SimInfo) -> CommonTestResult: - """is_survivalist(sim_info) - - Determine if a Sim is a Survivalist. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - return cls.has_trait(sim_info, CommonTraitId.SURVIVALIST) - - @classmethod - def is_unflirty(cls, sim_info: SimInfo) -> CommonTestResult: - """is_unflirty(sim_info) - - Determine if a Sim is Unflirty. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim has the Trait. False, if the Sim does not have the Trait. - :rtype: CommonTestResult - """ - return cls.has_trait(sim_info, CommonTraitId.UNFLIRTY) - - @classmethod - def hates_children(cls, sim_info: SimInfo) -> CommonTestResult: - """hates_children(sim_info) - - Determine if a Sim Hates Children. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim has the Hates Children trait. False, if not. - :rtype: CommonTestResult - """ - return cls.has_trait(sim_info, CommonTraitId.HATES_CHILDREN) - - @classmethod - def has_animal_attraction(cls, sim_info: SimInfo) -> CommonTestResult: - """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: The result of testing. True, if the Sim has the Trait. False, if not. - :rtype: CommonTestResult - """ - return cls.has_trait(sim_info, CommonTraitId.ANIMAL_ATTRACTION) - - @classmethod - def has_animal_whisperer(cls, sim_info: SimInfo) -> CommonTestResult: - """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: The result of testing. True, if the Sim has the Trait. False, if not. - :rtype: CommonTestResult - """ - return cls.has_trait(sim_info, CommonTraitId.ANIMAL_WHISPERER) - - @classmethod - def has_challenge_kindness_ambassador(cls, sim_info: SimInfo) -> CommonTestResult: - """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: The result of testing. True, if the Sim has challenged the kindness ambassador. False, if not. - :rtype: CommonTestResult - """ - return cls.has_trait(sim_info, CommonTraitId.CHALLENGE_KINDNESS_AMBASSADOR) - - @classmethod - def has_commitment_issues(cls, sim_info: SimInfo) -> CommonTestResult: - """has_commitment_issues(sim_info) - - Determine if a Sim has Commitment Issues. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim has the Trait. False, if not. - :rtype: CommonTestResult - """ - return cls.has_trait(sim_info, CommonTraitId.COMMITMENT_ISSUES) - - @classmethod - def has_masculine_frame(cls, sim_info: SimInfo) -> CommonTestResult: - """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: The result of testing. True, if the Sim has a masculine frame. False, if not. - :rtype: CommonTestResult - """ - from s4ap.sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils - return CommonSimGenderOptionUtils.has_masculine_frame(sim_info) - - @classmethod - def has_feminine_frame(cls, sim_info: SimInfo) -> CommonTestResult: - """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: The result of testing. True, if the Sim has a feminine frame. False, if not. - :rtype: CommonTestResult - """ - from s4ap.sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils - return CommonSimGenderOptionUtils.has_feminine_frame(sim_info) - - @classmethod - def prefers_menswear(cls, sim_info: SimInfo) -> CommonTestResult: - """prefers_menswear(sim_info) - - Determine if a Sim prefers Mens Clothing. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim prefers menswear. False, if not. - :rtype: CommonTestResult - """ - from s4ap.sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils - return CommonSimGenderOptionUtils.prefers_menswear(sim_info) - - @classmethod - def prefers_womenswear(cls, sim_info: SimInfo) -> CommonTestResult: - """prefers_womenswear(sim_info) - - Determine if a Sim prefers Womens Clothing. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim prefers womenswear. False, if not. - :rtype: CommonTestResult - """ - from s4ap.sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils - return CommonSimGenderOptionUtils.prefers_womenswear(sim_info) - - @classmethod - def can_impregnate(cls, sim_info: SimInfo) -> CommonTestResult: - """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: The result of testing. True, if the Sim can impregnate other Sims. False, if not. - :rtype: CommonTestResult - """ - from s4ap.sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils - return CommonSimGenderOptionUtils.can_impregnate(sim_info) - - @classmethod - def can_not_impregnate(cls, sim_info: SimInfo) -> CommonTestResult: - """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: The result of testing. True, if the Sim can not impregnate other Sims. False, if not. - :rtype: CommonTestResult - """ - from s4ap.sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils - return CommonSimGenderOptionUtils.can_not_impregnate(sim_info) - - @classmethod - def can_be_impregnated(cls, sim_info: SimInfo) -> CommonTestResult: - """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: The result of testing. True, if the Sim can be impregnated. False, if not. - :rtype: CommonTestResult - """ - from s4ap.sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils - return CommonSimGenderOptionUtils.can_be_impregnated(sim_info) - - @classmethod - def can_not_be_impregnated(cls, sim_info: SimInfo) -> CommonTestResult: - """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: The result of testing. True, if the Sim can not be impregnated. False, if not. - :rtype: CommonTestResult - """ - from s4ap.sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils - return CommonSimGenderOptionUtils.can_not_be_impregnated(sim_info) - - @classmethod - def can_create_pregnancy(cls, sim_info: SimInfo) -> CommonTestResult: - """can_create_pregnancy(sim_info) - - Determine if a Sim can either impregnate, be impregnated, or can reproduce. - - .. note:: Will return False if the Sim can both impregnate and not impregnate,\ - if the Sim can both be impregnated and not be impregnated\ - or if the Sim can both reproduce and not reproduce. - - .. note:: A Sim can impregnate when they can either impregnate other Sims, can be impregnated by other Sims, or if they are a Pet, can reproduce. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :return: The result of testing. True, if the Sim can create pregnancies. False, if not. - :rtype: CommonTestResult - """ - from s4ap.sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils - return CommonSimGenderOptionUtils.can_create_pregnancy(sim_info) - - @classmethod - def can_reproduce(cls, sim_info: SimInfo) -> CommonTestResult: - """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: The result of testing. True, if the Sim can reproduce. False, if not. - :rtype: CommonTestResult - """ - from s4ap.sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils - return CommonSimGenderOptionUtils.can_reproduce(sim_info) - - @classmethod - def can_not_reproduce(cls, sim_info: SimInfo) -> CommonTestResult: - """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: The result of testing. True, if the Sim can not reproduce. False, if not. - :rtype: CommonTestResult - """ - from s4ap.sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils - return CommonSimGenderOptionUtils.can_not_reproduce(sim_info) - - @classmethod - def uses_toilet_standing(cls, sim_info: SimInfo) -> CommonTestResult: - """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: The result of testing. True, if the Sim uses toilets while standing. False, if not. - :rtype: CommonTestResult - """ - from s4ap.sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils - return CommonSimGenderOptionUtils.uses_toilet_standing(sim_info) - - @classmethod - def uses_toilet_sitting(cls, sim_info: SimInfo) -> CommonTestResult: - """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: The result of testing. True, if the Sim uses toilets while sitting. False, if not. - :rtype: CommonTestResult - """ - from s4ap.sims4communitylib.utils.sims.common_sim_gender_option_utils import CommonSimGenderOptionUtils - return CommonSimGenderOptionUtils.uses_toilet_sitting(sim_info) - - @classmethod - def is_ghost_trait(cls, trait_identifier: Union[int, CommonTraitId, Trait]) -> bool: - """is_ghost_trait(trait_identifier) - - Determine if a trait is a Ghost trait. - - :param trait_identifier: An identifier of a trait. - :type trait_identifier: Union[int, CommonTraitId, Trait] - :return: True, if the specified trait is a ghost trait. False, if not. - """ - trait = cls.load_trait_by_id(trait_identifier) - if trait is None: - return False - return getattr(trait, 'is_ghost_trait', None) is True - - @classmethod - def has_trait(cls, sim_info: SimInfo, *trait: Union[int, CommonTraitId, Trait]) -> CommonTestResult: - """has_trait(sim_info, trait) - - Determine if a Sim has a Trait. - - :param sim_info: The Sim to check. - :type sim_info: SimInfo - :param trait: The trait to check for. - :type trait: Union[int, CommonTraitId, Trait] - :return: The result of testing. True, if the Sim has the specified trait. False, if not. - :rtype: CommonTestResult - """ - if isinstance(sim_info, SimInfo): - for _trait in trait: - __trait = cls.load_trait_by_id(_trait) - if __trait is None: - continue - if sim_info.has_trait(__trait): - return CommonTestResult(True, reason=f'{sim_info} has trait {__trait}.') - elif isinstance(sim_info, SimInfoBaseWrapper): - sim_info: SimInfoBaseWrapper = sim_info - any_traits = cls.get_trait_ids(sim_info) - if not any_traits: - return CommonTestResult(False, reason=f'{sim_info} does not have any traits.') - for _trait in trait: - __trait = cls.get_trait_id(_trait) - if __trait is None: - continue - if _trait in any_traits: - return CommonTestResult(True, reason=f'{sim_info} has trait {__trait}.') - elif isinstance(sim_info, PregnancyOffspringData): - sim_info: PregnancyOffspringData = sim_info - any_traits = [cls.get_trait_id(trait) for trait in sim_info.traits] - if not any_traits: - return CommonTestResult(False, reason=f'{sim_info} does not have any traits.') - for _trait in trait: - __trait = cls.get_trait_id(_trait) - if __trait is None: - continue - if _trait in any_traits: - return CommonTestResult(True, reason=f'{sim_info} has trait {__trait}.') - return CommonTestResult(False, reason=f'{sim_info} does not have trait(s) {trait}') - - @classmethod - def has_any_traits(cls, sim_info: SimInfo, traits: Iterator[Union[int, CommonTraitId, Trait]]) -> CommonTestResult: - """has_any_traits(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 traits: An iterator of identifiers of Traits. - :type traits: Iterator[Union[int, CommonTraitId, Trait]] - :return: The result of testing. True, if the Sim has any of the specified traits. False, if not. - :rtype: CommonTestResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - if not traits: - return CommonTestResult(False, reason='No traits were specified.') - if isinstance(sim_info, SimInfo): - for trait in traits: - _trait = cls.load_trait_by_id(trait) - if _trait is None: - continue - if sim_info.has_trait(_trait): - return CommonTestResult(True, reason=f'{sim_info} has trait {_trait}.') - elif isinstance(sim_info, SimInfoBaseWrapper): - sim_info: SimInfoBaseWrapper = sim_info - any_traits = cls.get_trait_ids(sim_info) - if not any_traits: - return CommonTestResult(False, reason=f'{sim_info} does not have any traits.') - for _trait in traits: - __trait = cls.get_trait_id(_trait) - if __trait is None: - continue - if _trait in any_traits: - return CommonTestResult(True, reason=f'{sim_info} has trait {__trait}.') - elif isinstance(sim_info, PregnancyOffspringData): - sim_info: PregnancyOffspringData = sim_info - any_traits = [cls.get_trait_id(trait) for trait in sim_info.traits] - if not any_traits: - return CommonTestResult(False, reason=f'{sim_info} does not have any traits.') - for _trait in traits: - __trait = cls.get_trait_id(_trait) - if __trait is None: - continue - if _trait in any_traits: - return CommonTestResult(True, reason=f'{sim_info} has trait {__trait}.') - return CommonTestResult(False, reason=f'{sim_info} does not have any trait(s) {traits}.') - - @classmethod - def has_all_traits(cls, sim_info: SimInfo, traits: Iterator[Union[int, CommonTraitId, Trait]]) -> CommonTestResult: - """has_all_traits(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 traits: An iterator of identifiers of Traits. - :type traits: Iterator[Union[int, CommonTraitId, Trait]] - :return: The result of testing. True, if the Sim has any of the specified traits. False, if not. - :rtype: CommonTestResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - if not traits: - return CommonTestResult(False, reason='No traits were specified.') - if isinstance(sim_info, SimInfo): - for trait in traits: - _trait = cls.load_trait_by_id(trait) - if _trait is None: - continue - if not sim_info.has_trait(_trait): - return CommonTestResult(False, reason=f'{sim_info} does not have trait {_trait}.') - elif isinstance(sim_info, SimInfoBaseWrapper): - sim_info: SimInfoBaseWrapper = sim_info - any_traits = cls.get_trait_ids(sim_info) - if not any_traits: - return CommonTestResult(False, reason=f'{sim_info} does not have any traits.') - for _trait in traits: - __trait = cls.get_trait_id(_trait) - if __trait is None: - continue - if _trait not in any_traits: - return CommonTestResult(False, reason=f'{sim_info} does not have trait {_trait}.') - elif isinstance(sim_info, PregnancyOffspringData): - sim_info: PregnancyOffspringData = sim_info - any_traits = cls.get_trait_ids(sim_info) - if not any_traits: - return CommonTestResult(False, reason=f'{sim_info} does not have any traits.') - for _trait in traits: - __trait = cls.get_trait_id(_trait) - if __trait is None: - continue - if _trait not in any_traits: - return CommonTestResult(False, reason=f'{sim_info} does not have trait {_trait}.') - return CommonTestResult(True, reason=f'{sim_info} has all traits {traits}.') - - @classmethod - def is_conflicting_trait(cls, sim_info: SimInfo, trait_id: Union[int, CommonTraitId, Trait]) -> CommonTestResult: - """is_conflicting_trait(sim_info, trait_id) - - Determine if a Trait conflicts with any of the Sims current Traits. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param trait_id: The identifier of the trait to check. - :type trait_id: int - :return: The result of testing. True, if the specified Trait conflicts with any Traits the Sim currently has. False, if not. - :rtype: CommonTestResult - """ - trait_to_check = cls.load_trait_by_id(trait_id) - if trait_to_check is None: - return CommonTestResult(False, reason=f'Trait {trait_id} did not exist, thus it cannot conflict.') - from traits.trait_tracker import TraitTracker - trait_tracker: TraitTracker = sim_info.trait_tracker - return trait_tracker.is_conflicting(trait_to_check) - - @classmethod - def get_trait_ids(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper, PregnancyOffspringData]) -> 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: Union[SimInfo, SimInfoBaseWrapper, PregnancyOffspringData] - :return: A collection of Trait identifiers on a Sim. - :rtype: List[int] - """ - trait_ids = list() - if isinstance(sim_info, SimInfo) or isinstance(sim_info, PregnancyOffspringData): - for trait in cls.get_traits(sim_info): - trait_id = cls.get_trait_id(trait) - if trait_id is None: - continue - trait_ids.append(trait_id) - elif isinstance(sim_info, SimInfoBaseWrapper): - return list(sim_info._get_trait_ids()) - return trait_ids - - @classmethod - def get_traits(cls, sim_info: Union[SimInfo, SimInfoBaseWrapper, PregnancyOffspringData]) -> List[Trait]: - """get_traits(sim_info) - - Retrieve all Traits of a Sim. - - :param sim_info: The Sim to check. - :type sim_info: Union[SimInfo, SimInfoBaseWrapper, PregnancyOffspringData] - :return: A collection of Traits on a Sim. - :rtype: List[int] - """ - if isinstance(sim_info, SimInfo): - if not hasattr(sim_info, 'get_traits'): - return list() - traits = list(sim_info.get_traits()) - if traits: - return traits - if not hasattr(sim_info, '_base'): - return traits - return list([cls.load_trait_by_id(trait_id) for trait_id in (*sim_info._base.trait_ids, *sim_info._base.base_trait_ids) if cls.load_trait_by_id(trait_id) is not None]) - elif isinstance(sim_info, PregnancyOffspringData): - return sim_info.traits - elif isinstance(sim_info, SimInfoBaseWrapper): - return [cls.load_trait_by_id(trait_id) for trait_id in cls.get_trait_ids(sim_info)] - return list() - - @classmethod - def get_trait_name(cls, 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 trait.__class__.__name__ - except: - # noinspection PyBroadException - try: - return trait.__class__.__name__ - except: - return '' - - @classmethod - def get_trait_names(cls, 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 = cls.get_trait_name(trait) - if not name: - continue - except: - continue - names.append(name) - return tuple(names) - - @classmethod - def get_equipped_traits(cls, 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'): - if hasattr(sim_info, '_base'): - return list([cls.load_trait_by_id(trait_id) for trait_id in (*sim_info._base.trait_ids, *sim_info._base.base_trait_ids) if cls.load_trait_by_id(trait_id) is not None]) - return list() - return list(sim_info.trait_tracker.equipped_traits) - - @classmethod - def add_trait(cls, sim_info: SimInfo, *trait: Union[int, CommonTraitId, Trait]) -> CommonExecutionResult: - """add_trait(sim_info, trait) - - Add a Trait to a Sim. - - :param sim_info: The Sim to add the specified traits to. - :type sim_info: SimInfo - :param trait: The trait being added. - :type trait: Union[int, CommonTraitId, Trait] - :return: The result of adding the trait. True, if the trait was successfully added to the Sim. False, if not. - :rtype: CommonExecutionResult - """ - return cls.add_traits(sim_info, trait) - - @classmethod - def add_traits(cls, sim_info: SimInfo, traits: Iterator[Union[int, CommonTraitId, Trait]]) -> CommonExecutionResult: - """add_traits(sim_info, traits) - - Add Traits to a Sim. - - :param sim_info: The Sim to add the specified traits to. - :type sim_info: SimInfo - :param traits: An iterator of identifiers of traits being added. - :type traits: Iterator[Union[int, CommonTraitId, Trait]] - :return: The result of adding the traits. True, if all specified traits were successfully added to the Sim. False, if not. - :rtype: CommonExecutionResult - """ - if sim_info is None: - raise AssertionError('Argument sim_info was None') - has_any = False - success = True - failed_to_add_traits = list() - for trait_id in traits: - trait = cls.load_trait_by_id(trait_id) - if trait is None: - cls.get_log().format_with_message('Failed to load trait by its id.', sim=sim_info, trait_id=trait_id) - failed_to_add_traits.append(trait_id) - continue - has_any = True - if cls.has_trait(sim_info, trait): - cls.get_log().format_with_message('Sim already had trait.', sim=sim_info, trait=trait) - continue - cls.get_log().format_with_message('Attempting to add trait', sim=sim_info, trait=trait, trait_id=trait_id) - add_result = sim_info.add_trait(trait) - if not add_result: - cls.get_log().format_with_message('Failed to add trait.', sim=sim_info, trait=trait, trait_id=trait_id, reason=add_result) - success = False - failed_to_add_traits.append(trait) - else: - cls.get_log().format_with_message('Successfully added trait.', sim=sim_info, trait=trait, trait_id=trait_id) - if not success: - failed_to_add_traits_str = ', '.join([cls.get_trait_name(trait) or str(trait) if isinstance(trait, Trait) else str(trait) for trait in failed_to_add_traits]) - return CommonExecutionResult(False, reason=f'Failed to add traits to {sim_info}. {failed_to_add_traits_str}') - if not has_any: - return CommonExecutionResult(True, reason=f'Finished "adding" traits to {sim_info}, but none of the specified traits were loaded.') - return CommonExecutionResult.TRUE - - @classmethod - def remove_trait(cls, sim_info: SimInfo, *trait: Union[int, CommonTraitId, Trait]) -> CommonExecutionResult: - """remove_trait(sim_info, trait) - - Remove a Trait from a Sim. - - :param sim_info: The Sim to remove the specified traits from. - :type sim_info: SimInfo - :param trait: The trait being removed. - :type trait: Union[int, CommonTraitId, Trait] - :return: The result of removing the trait. True, if the trait was successfully removed from the Sim. False, if not. - :rtype: CommonExecutionResult - """ - return cls.remove_traits(sim_info, trait) - - @classmethod - def remove_traits(cls, sim_info: SimInfo, traits: Iterator[Union[int, CommonTraitId, Trait]]) -> CommonExecutionResult: - """remove_traits(sim_info, traits) - - Remove Traits from a Sim. - - :param sim_info: The Sim to remove the specified traits from. - :type sim_info: SimInfo - :param traits: An iterator of Trait identifiers of traits being removed. - :type traits: Iterator[Union[int, CommonTraitId, Trait]] - :return: The result of removing the traits. True, if all specified traits were successfully removed from the Sim. False, if not. - :rtype: CommonExecutionResult - """ - has_any_loaded = False - success = True - failed_to_remove_traits = list() - for trait_id in traits: - trait = cls.load_trait_by_id(trait_id) - if trait is None: - failed_to_remove_traits.append(trait_id) - continue - # If the Sim does not have the trait, the remove_trait function will return False. We check if they have it before attempting, so we don't run into this. - if not cls.has_trait(sim_info, trait): - continue - has_any_loaded = True - if not sim_info.remove_trait(trait): - failed_to_remove_traits.append(trait) - success = False - - if not success: - failed_to_remove_traits_str = ', '.join([cls.get_trait_name(trait) or str(trait) if isinstance(trait, Trait) else str(trait) for trait in failed_to_remove_traits]) - return CommonExecutionResult(False, reason=f'Failed to remove traits. {failed_to_remove_traits_str}') - if not has_any_loaded: - return CommonExecutionResult(True, reason='Finished "removing" traits, but none of the specified traits were loaded.') - return CommonExecutionResult.TRUE - - @classmethod - def swap_traits(cls, sim_info: SimInfo, trait_id_one: Union[int, CommonTraitId, Trait], trait_id_two: Union[int, CommonTraitId, Trait]) -> CommonExecutionResult: - """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: Union[int, CommonTraitId, Trait] - :param trait_id_two: The second trait to remove/add - :type trait_id_two: Union[int, CommonTraitId, Trait] - :return: The result of swapping traits. True, if the Traits were swapped successfully. False, if neither Trait exists on a Sim or the traits were not swapped successfully. - :rtype: CommonExecutionResult - """ - # Has Trait One - if cls.has_trait(sim_info, trait_id_one): - cls.remove_trait(sim_info, trait_id_one) - if not cls.has_trait(sim_info, trait_id_two): - return cls.add_trait(sim_info, trait_id_two) - return CommonExecutionResult.TRUE - # Has Trait Two - elif cls.has_trait(sim_info, trait_id_two): - cls.remove_trait(sim_info, trait_id_two) - if not cls.has_trait(sim_info, trait_id_one): - return cls.add_trait(sim_info, trait_id_one) - return CommonExecutionResult.TRUE - return CommonExecutionResult(False, reason=f'Sim had neither Trait One {trait_id_one} nor Trait Two {trait_id_two}.') - - @classmethod - def add_trait_to_all_sims(cls, trait_id: Union[int, CommonTraitId, Trait], 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: Union[int, CommonTraitId, Trait] - :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 cls.has_trait(sim_info, trait_id): - continue - cls.add_trait(sim_info, trait_id) - - @classmethod - def remove_trait_from_all_sims(cls, trait_id: Union[int, CommonTraitId, Trait], 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: Union[int, CommonTraitId, Trait] - :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 cls.has_trait(sim_info, trait_id): - continue - cls.remove_trait(sim_info, trait_id) - - @classmethod - def get_trait_id(cls, 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) - - @classmethod - def is_trait_available(cls, trait: Union[int, CommonTraitId, Trait]) -> bool: - """is_trait_available(trait) - - Determine if a Trait is available for use. - - .. note:: If the Trait is part of a package that is not installed, it will be considered as not available. - - :param trait: The trait to check for. - :type trait: Union[int, CommonTraitId, Trait] - :return: True, if the Trait is available for use. False, if not. - :rtype: bool - """ - return cls.load_trait_by_id(trait) is not None - - @classmethod - def load_trait_by_id(cls, trait: Union[int, CommonTraitId, Trait]) -> Union[Trait, None]: - """load_trait_by_id(trait) - - Load an instance of a Trait by its identifier. - - :param trait: The identifier of a Trait. - :type trait: Union[int, CommonTraitId, Trait] - :return: An instance of a Trait matching the decimal identifier or None if not found. - :rtype: Union[Trait, None] - """ - if isinstance(trait, Trait): - return trait - # noinspection PyBroadException - try: - # noinspection PyCallingNonCallable - trait_instance = trait() - if isinstance(trait_instance, Trait): - # noinspection PyTypeChecker - return trait - except: - pass - # noinspection PyBroadException - try: - trait: int = int(trait) - except: - # noinspection PyTypeChecker - trait: Trait = trait - return trait - - from sims4.resources import Types - from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils - return CommonResourceUtils.load_instance(Types.TRAIT, trait) - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.print_known_traits', - 'Print a list of all personality, occult, and other types of traits Sim A knows about Sim B. (For example Sim A could know that Sim B is Childish)', - command_arguments=( - CommonConsoleCommandArgument('sim_info_a', 'Sim Id or Name', 'The instance id or name of a Sim to check.', is_optional=True, default_value='Active Sim'), - CommonConsoleCommandArgument('sim_info_b', 'Sim Id or Name', 'The instance id or name of a Sim to check.', is_optional=True, default_value='Active Sim'), - ) -) -def _common_print_known_traits(output: CommonConsoleCommandOutput, sim_info_a: SimInfo = None, sim_info_b: SimInfo = None): - if sim_info_a is None: - return - if sim_info_b is None: - return - if sim_info_a is sim_info_b: - output('ERROR: Sim A knows all traits about Sim B, because Sim A IS Sim B. Please specify at least one other Sim for either Sim A or Sim B when running this command!') - return - output(f'Attempting to print the traits that Sim A knows about Sim B.') - sim_id_b = CommonSimUtils.get_sim_id(sim_info_b) - relationship_tracker: RelationshipTracker = sim_info_a.relationship_tracker - knowledge: SimKnowledge = relationship_tracker.get_knowledge(sim_id_b, initialize=False) - if knowledge.known_traits is None and knowledge.known_traits: - output('SUCCESS: Sim A knows zero traits about Sim B.') - return - output(f'Traits that Sim A {sim_info_a} knows about Sim B {sim_info_b}:') - for trait in knowledge.known_traits: - output(f'- {trait}') - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.add_trait', - 'Add a trait to a Sim.', - command_arguments=( - CommonConsoleCommandArgument('trait', 'Trait Id or Tuning Name', 'The decimal identifier or Tuning Name of the Trait to add.'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance id or name of a Sim to add the trait to.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.addtrait', - ) -) -def _common_add_trait(output: CommonConsoleCommandOutput, trait: TunableInstanceParam(Types.TRAIT), sim_info: SimInfo = None): - if trait is None: - return - if sim_info is None: - return - output(f'Adding trait {trait} to Sim {sim_info}') - result = CommonTraitUtils.add_trait(sim_info, trait) - if result: - output(f'SUCCESS: Successfully added trait {trait} to Sim {sim_info}: {result.reason}') - else: - output(f'FAILED: Failed to add trait {trait} to Sim {sim_info}. {result.reason}') - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib.remove_trait', - 'Remove a trait from a Sim.', - command_arguments=( - CommonConsoleCommandArgument('trait', 'Trait Id or Tuning Name', 'The decimal identifier or Tuning Name of the Trait to remove.'), - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance id or name of a Sim to remove the trait from.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib.removetrait', - ) -) -def _common_remove_trait(output: CommonConsoleCommandOutput, trait: TunableInstanceParam(Types.TRAIT), sim_info: SimInfo = None): - if trait is None: - return - if sim_info is None: - return - output(f'Removing trait {trait} from Sim {sim_info}') - result = CommonTraitUtils.remove_trait(sim_info, trait) - if result: - output(f'SUCCESS: Successfully removed trait {trait} from Sim {sim_info}: {result.reason}') - else: - output(f'FAILED: Failed to remove trait {trait} from Sim {sim_info}: {result.reason}') - - -# noinspection SpellCheckingInspection -@CommonConsoleCommand( - ModInfo.get_identity(), - 's4clib_testing.print_traits', - 'Print a list of all traits on a Sim.', - command_arguments=( - CommonConsoleCommandArgument('sim_info', 'Sim Id or Name', 'The instance id or name of a Sim to check.', is_optional=True, default_value='Active Sim'), - ), - command_aliases=( - 's4clib_testing.printtraits', - ) -) -def _common_show_traits(output: CommonConsoleCommandOutput, sim_info: SimInfo = None): - if sim_info is None: - return - log = CommonTraitUtils.get_log() - try: - log.enable() - output(f'Showing traits of Sim {sim_info}') - trait_strings: List[str] = list() - for trait in CommonTraitUtils.get_traits(sim_info): - trait_name = CommonTraitUtils.get_trait_name(trait) - trait_id = CommonTraitUtils.get_trait_id(trait) - trait_strings.append(f'{trait_name} ({trait_id})') - - trait_strings = sorted(trait_strings, key=lambda x: x) - sim_traits = ', '.join(trait_strings) - text = '' - text += f'Traits:\n{sim_traits}\n\n' - sim_id = CommonSimUtils.get_sim_id(sim_info) - log.debug(f'{sim_info} Traits ({sim_id})') - log.debug(text) - CommonBasicNotification( - CommonLocalizationUtils.create_localized_string(f'{sim_info} Traits ({sim_id})'), - CommonLocalizationUtils.create_localized_string(text) - ).show( - icon=IconInfoData(obj_instance=CommonSimUtils.get_sim_instance(sim_info)) - ) - finally: - log.disable() diff --git a/Scripts/s4ap/sims4communitylib/utils/sims/common_whim_utils.py b/Scripts/s4ap/sims4communitylib/utils/sims/common_whim_utils.py deleted file mode 100644 index 0053d15..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/sims/common_whim_utils.py +++ /dev/null @@ -1,36 +0,0 @@ -""" -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 -""" -from typing import Tuple, List - -from sims.sim_info import SimInfo -from whims.whim_set import WhimSetBaseMixin - - -class CommonWhimUtils: - """Utilities for manipulating the Whims of Sims. - - """ - @staticmethod - def get_current_whims(sim_info: SimInfo) -> Tuple[WhimSetBaseMixin]: - """get_current_whims(sim_info) - - Retrieve the current Whims of the specified Sim. - - :param sim_info: The Sim to get the Whim Sets of. - :type sim_info: SimInfo - :return: A collection of Whims Sets for the specified Sim. - :rtype: Tuple[WhimSetBaseMixin] - """ - whims_tracker = sim_info.whim_tracker - if whims_tracker is None: - return tuple() - goal_instances: List[WhimSetBaseMixin] = [] - for whim_data in whims_tracker.get_active_whim_data(): - if whim_data.whim is not None: - goal_instances.append(whim_data.whim) - return tuple(goal_instances) diff --git a/Scripts/s4ap/sims4communitylib/utils/terrain/__init__.py b/Scripts/s4ap/sims4communitylib/utils/terrain/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/terrain/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/utils/terrain/common_terrain_interaction_utils.py b/Scripts/s4ap/sims4communitylib/utils/terrain/common_terrain_interaction_utils.py deleted file mode 100644 index fb24aa0..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/terrain/common_terrain_interaction_utils.py +++ /dev/null @@ -1,58 +0,0 @@ -""" -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 -""" -from typing import Tuple, Union -from interactions.context import InteractionContext -from objects.terrain import TerrainPoint -from routing import SurfaceType -from server.pick_info import PickType -from sims.sim_info import SimInfo -from s4ap.sims4communitylib.classes.math.common_surface_identifier import CommonSurfaceIdentifier -from s4ap.sims4communitylib.classes.math.common_vector3 import CommonVector3 -from s4ap.sims4communitylib.logging.has_class_log import HasClassLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils - - -class CommonTerrainInteractionUtils(HasClassLog): - """Utilities for manipulating the interactions of Terrain. - - """ - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - return ModInfo.get_identity() - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 'common_terrain_interaction_utils' - - @staticmethod - def build_terrain_point_and_interaction_context_from_sim_and_position(sim_info: SimInfo, target_position: CommonVector3, target_surface_level: int) -> Tuple[Union[TerrainPoint, None], Union[InteractionContext, None]]: - """build_terrain_point_and_interaction_context_from_sim_and_position(sim_info, position, target_surface_level) - - Build a target and a context for the terrain. - - :param sim_info: An instance of a Sim. - :type sim_info: SimInfo - :param target_position: The target position. - :type target_position: CommonVector3 - :param target_surface_level: The surface level at the target position. - :type target_surface_level: int - :return: A tuple of the terrain point and the interaction context created from the position and surface level for the Sim or (None, None) if an error occurs. - :rtype: Tuple[Union[TerrainPoint, None], Union[InteractionContext, None]] - """ - from s4ap.sims4communitylib.utils.location.common_location_utils import CommonLocationUtils - from server_commands.sim_commands import _build_terrain_interaction_target_and_context - sim = CommonSimUtils.get_sim_instance(sim_info) - if sim is None: - return None, None - routing_surface = CommonSurfaceIdentifier(CommonLocationUtils.get_current_zone_id(), secondary_id=target_surface_level, surface_type=SurfaceType.SURFACETYPE_WORLD) - return _build_terrain_interaction_target_and_context(sim, target_position, routing_surface, PickType.PICK_TERRAIN, TerrainPoint) diff --git a/Scripts/s4ap/sims4communitylib/utils/terrain/common_terrain_location_utils.py b/Scripts/s4ap/sims4communitylib/utils/terrain/common_terrain_location_utils.py deleted file mode 100644 index 6844cd1..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/terrain/common_terrain_location_utils.py +++ /dev/null @@ -1,68 +0,0 @@ -""" -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 -""" -from typing import Union - -from objects.terrain import Terrain -from s4ap.sims4communitylib.classes.math.common_surface_identifier import CommonSurfaceIdentifier -from s4ap.sims4communitylib.classes.math.common_vector3 import CommonVector3 - - -class CommonTerrainLocationUtils: - """Utilities for manipulating the locational data of Terrain.""" - - @staticmethod - def get_water_depth_at(x: float, z: float, surface_level: int=0) -> float: - """get_water_depth_at(x, z, surface_level=0) - - Determine the water depth at the specified coordinates. - - :param x: The X coordinate. - :type x: float - :param z: The Z coordinate. - :type z: float - :param surface_level: The surface level. Default is 0. - :type surface_level: int, optional - :return: The depth of the water at the specified coordinates. - :rtype: float - """ - from terrain import get_water_depth - return get_water_depth(x, z, level=surface_level) - - @staticmethod - def get_position(terrain_object: Terrain) -> Union[CommonVector3, None]: - """get_position(terrain_object) - - Retrieve the position of a Terrain Object. - - :param terrain_object: An instance of a Terrain object. - :type terrain_object: Terrain - :return: The position of the Object or None if the Object does not have a position. - :rtype: CommonVector3 - """ - if terrain_object is None: - return None - # noinspection PyBroadException - try: - return CommonVector3.from_vector3(terrain_object.position) - except: - return None - - @staticmethod - def get_routing_surface(terrain_object: Terrain) -> Union[CommonSurfaceIdentifier, None]: - """get_routing_surface(game_object) - - Retrieve the routing surface of a Terrain Object. - - :param terrain_object: An instance of a Terrain Object. - :type terrain_object: Terrain - :return: The routing surface of the object or None if a problem occurs. - :rtype: Union[CommonSurfaceIdentifier, None] - """ - if terrain_object is None: - return None - return CommonSurfaceIdentifier.from_surface_identifier(terrain_object.routing_surface) diff --git a/Scripts/s4ap/sims4communitylib/utils/terrain/common_terrain_utils.py b/Scripts/s4ap/sims4communitylib/utils/terrain/common_terrain_utils.py deleted file mode 100644 index 8a5b438..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/terrain/common_terrain_utils.py +++ /dev/null @@ -1,12 +0,0 @@ -""" -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 -""" - - -class CommonTerrainUtils: - """ Utilities for manipulating the Terrain. """ - pass diff --git a/Scripts/s4ap/sims4communitylib/utils/time/__init__.py b/Scripts/s4ap/sims4communitylib/utils/time/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/time/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/utils/time/common_alarm_utils.py b/Scripts/s4ap/sims4communitylib/utils/time/common_alarm_utils.py deleted file mode 100644 index edf3c01..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/time/common_alarm_utils.py +++ /dev/null @@ -1,181 +0,0 @@ -""" -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 -""" -import os -from typing import Callable, Any, Union -from s4ap.sims4communitylib.classes.time.common_alarm_handle import CommonAlarmHandle -from s4ap.sims4communitylib.logging.has_class_log import HasClassLog -from s4ap.sims4communitylib.mod_support.mod_identity import CommonModIdentity -from s4ap.sims4communitylib.modinfo import ModInfo -from s4ap.sims4communitylib.utils.common_time_utils import CommonTimeUtils - -ON_RTD = os.environ.get('READTHEDOCS', None) == 'True' - -if ON_RTD: - # noinspection PyMissingOrEmptyDocstring - class Timeline: - pass - - # noinspection PyMissingOrEmptyDocstring - class TimeSpan: - pass - -if not ON_RTD: - from scheduling import Timeline - from date_and_time import TimeSpan - - -class CommonAlarmUtils(HasClassLog): - """Utilities for manipulating alarms.""" - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_mod_identity(cls) -> CommonModIdentity: - return ModInfo.get_identity() - - # noinspection PyMissingOrEmptyDocstring - @classmethod - def get_log_identifier(cls) -> str: - return 'common_alarm_utils' - - @classmethod - def schedule_alarm( - cls, - alarm_owner: Any, - time_until_first_occurrence: TimeSpan, - on_alarm_triggered_callback: Callable[['CommonAlarmHandle'], None], - should_repeat: bool = False, - time_until_repeat: TimeSpan = None, - accurate_repeat: bool = True, - persist_across_zone_loads: bool = False, - timeline: Timeline = None - ) -> Union['CommonAlarmHandle', None]: - """schedule_alarm(\ - alarm_owner,\ - time_until_next_occurrence,\ - callback,\ - should_repeat=False,\ - time_until_repeat=None,\ - accurate_repeat=True,\ - persist_across_zone_loads=False,\ - timeline=None\ - ) - - Schedule an alarm that will trigger a callback after a set amount of time. - - :param alarm_owner: The owner of the alarm. - :type alarm_owner: Any - :param time_until_first_occurrence: The time until the alarm triggers. - :type time_until_first_occurrence: TimeSpan - :param on_alarm_triggered_callback: When the alarm is triggered at the specified time, this callback will be invoked with the alarm handle. - :type on_alarm_triggered_callback: Callable[['CommonAlarmHandle'], None] - :param should_repeat: If True, the alarm will repeat on the specified interval. If False, the alarm will only trigger once. Default is False. - :type should_repeat: bool, optional - :param time_until_repeat: The amount of time that must pass before the alarm will trigger again. This only comes into play after being triggered once. Default is None. - :type time_until_repeat: TimeSpan, optional - :param accurate_repeat: Whether or not the initial time should be based on the now time or the future time. Default is the Now time. - :type accurate_repeat: bool, optional - :param persist_across_zone_loads: If True, the alarm will persist when loading a new zone. If False, the alarm will be canceled upon changing zones. Default is False. - :type persist_across_zone_loads: bool, optional - :param timeline: The timeline to use when determining the alarm trigger time as well as the initial time of the alarm. Default is Sim Timeline. - :type timeline: Timeline, optional - :return: The created alarm handle or None if the Time service is not currently available or a problem occurs. - :rtype: Union[CommonAlarmHandle, None] - """ - if timeline is None: - time_service = CommonTimeUtils.get_time_service() - if time_service.sim_timeline is None: - return None - timeline = time_service.sim_timeline - - if accurate_repeat: - initial_time = timeline.now - else: - initial_time = timeline.future - - def _on_alarm_triggered(handle: CommonAlarmHandle): - try: - on_alarm_triggered_callback(handle) - except Exception as ex: - cls.get_log().format_error(f'An exception occurred when triggering alarm callback for {alarm_owner}.', alarm_owner=alarm_owner, exception=ex) - - return CommonAlarmHandle( - alarm_owner, - _on_alarm_triggered, - timeline, - initial_time + time_until_first_occurrence, - should_repeat=should_repeat, - time_until_repeat=time_until_repeat or time_until_first_occurrence, - accurate_repeat=accurate_repeat, - persist_across_zone_loads=persist_across_zone_loads - ) - - @classmethod - def schedule_daily_alarm( - cls, - alarm_owner: Any, - hour: int, - minute: int, - on_alarm_triggered: Callable[[CommonAlarmHandle], None], - persist_across_zone_loads: bool = False - ) -> CommonAlarmHandle: - """schedule_daily_alarm(\ - alarm_owner,\ - hour,\ - minute,\ - on_alarm_triggered,\ - persist_across_zone_loads=False\ - ) - - Schedule an alarm that will repeat once a day, every day. - - :param alarm_owner: The owner of the alarm. - :type alarm_owner: Any - :param hour: The hour of the day to trigger the alarm at. - :type hour: int - :param minute: The minute of the hour to trigger the alarm at. - :type minute: int - :param on_alarm_triggered: A callback invoked when the alarm is triggered. - :type on_alarm_triggered: Callable[[CommonAlarmHandle], None] - :param persist_across_zone_loads: If True, the alarm will persist when loading a new zone. If False, the alarm will be canceled upon changing zones. Default is False. - :type persist_across_zone_loads: bool, optional - :return: The scheduled alarm or None if a problem occurs. - :rtype: CommonAlarmHandle - """ - from date_and_time import create_date_and_time, sim_ticks_per_day - now = CommonTimeUtils.get_current_date_and_time() - alarm_time_of_day = create_date_and_time(hours=hour, minutes=minute) - alarm_next_trigger_time = now.time_till_next_day_time(alarm_time_of_day) - if alarm_next_trigger_time.in_ticks() == 0: - alarm_next_trigger_time += TimeSpan(sim_ticks_per_day()) - - repeat_interval = TimeSpan(sim_ticks_per_day()) - - return cls.schedule_alarm( - alarm_owner, - alarm_next_trigger_time, - on_alarm_triggered, - time_until_repeat=repeat_interval, - should_repeat=True, - persist_across_zone_loads=persist_across_zone_loads - ) - - @classmethod - def cancel_alarm(cls, alarm_handle: CommonAlarmHandle) -> bool: - """cancel_alarm(alarm_handle) - - Cancel an alarm so that it will no longer occur. - - :param alarm_handle: The handle of the alarm to cancel. - :type alarm_handle: CommonAlarmHandle - :return: True, if the alarm was cancelled successfully. False, if not. - :rtype: bool - """ - if alarm_handle is None: - return False - alarm_handle.cancel() - return True diff --git a/Scripts/s4ap/sims4communitylib/utils/whims/__init__.py b/Scripts/s4ap/sims4communitylib/utils/whims/__init__.py deleted file mode 100644 index cbf2b63..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/whims/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -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 -""" diff --git a/Scripts/s4ap/sims4communitylib/utils/whims/common_satisfaction_reward_store_item.py b/Scripts/s4ap/sims4communitylib/utils/whims/common_satisfaction_reward_store_item.py deleted file mode 100644 index b4e3c79..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/whims/common_satisfaction_reward_store_item.py +++ /dev/null @@ -1,35 +0,0 @@ -""" -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 -""" -from rewards.reward import Reward - -try: - from satisfaction.satisfaction_tracker import SatisfactionTracker -except: - from whims.whims_tracker import WhimsTracker - - SatisfactionTracker = WhimsTracker - # noinspection PyUnresolvedReferences - setattr(SatisfactionTracker, 'SatisfactionAwardTypes', WhimsTracker.WhimAwardTypes) - - -class CommonSatisfactionRewardStoreItem: - """CommonSatisfactionRewardStoreItem(reward, reward_cost, reward_type) - - A wrapper for Reward Store Items. - - :param reward: An instance of a Reward. - :type reward: Reward - :param reward_cost: The amount of Satisfaction Reward Points the Reward costs. - :type reward_cost: int - :param reward_type: The type of the Reward. - :type reward_type: SatisfactionTracker.SatisfactionAwardTypes - """ - def __init__(self, reward: Reward, reward_cost: int, reward_type: SatisfactionTracker.SatisfactionAwardTypes): - self.reward = reward - self.reward_cost = reward_cost - self.reward_type = reward_type diff --git a/Scripts/s4ap/sims4communitylib/utils/whims/common_satisfaction_reward_store_utils.py b/Scripts/s4ap/sims4communitylib/utils/whims/common_satisfaction_reward_store_utils.py deleted file mode 100644 index 2aa7a96..0000000 --- a/Scripts/s4ap/sims4communitylib/utils/whims/common_satisfaction_reward_store_utils.py +++ /dev/null @@ -1,172 +0,0 @@ -""" -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 -""" -from typing import Tuple, Dict, Callable, Iterator - -import sims4.collections -from rewards.reward import Reward -from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils -from s4ap.sims4communitylib.utils.whims.common_satisfaction_reward_store_item import CommonSatisfactionRewardStoreItem - -# noinspection PyBroadException -try: - from satisfaction.satisfaction_tracker import SatisfactionTracker -except: - from whims.whims_tracker import WhimsTracker - - SatisfactionTracker = WhimsTracker - # noinspection PyUnresolvedReferences - SatisfactionTracker.SatisfactionAwardTypes = WhimsTracker.WhimAwardTypes - - -class CommonSatisfactionRewardStoreUtils: - """Utilities for manipulating the Satisfaction Rewards Store. - - """ - @staticmethod - def add_reward_trait_to_rewards_store(reward_trait_definition_id: int, reward_point_cost: int) -> bool: - """add_reward_trait_to_rewards_store(reward_trait_definition_id, reward_point_cost) - - Add a Reward Trait to the Satisfaction Rewards Store. - - :param reward_trait_definition_id: The decimal identifier of a Reward Trait. - :type reward_trait_definition_id: int - :param reward_point_cost: The amount of Satisfaction Reward Points the Reward Trait will cost the Sim to receive. - :type reward_point_cost: int - :return: True, if the Trait was added to the Rewards Store successfully. False, if not. - :rtype: bool - """ - return CommonSatisfactionRewardStoreUtils._add_reward_to_rewards_store(reward_trait_definition_id, reward_point_cost, SatisfactionTracker.SatisfactionAwardTypes.TRAIT) - - @staticmethod - def add_reward_buff_to_rewards_store(reward_buff_definition_id: int, reward_point_cost: int) -> bool: - """add_reward_buff_to_rewards_store(reward_buff_definition_id, reward_point_cost) - - Add a Reward Buff to the Satisfaction Rewards Store. - - :param reward_buff_definition_id: The decimal identifier of a Reward Buff. - :type reward_buff_definition_id: int - :param reward_point_cost: The amount of Satisfaction Reward Points the Reward Buff will cost the Sim to receive. - :type reward_point_cost: int - :return: True, if the Reward Buff was added to the Rewards Store successfully. False, if not. - :rtype: bool - """ - return CommonSatisfactionRewardStoreUtils._add_reward_to_rewards_store(reward_buff_definition_id, reward_point_cost, SatisfactionTracker.SatisfactionAwardTypes.BUFF) - - @staticmethod - def add_reward_object_to_rewards_store(reward_object_definition_id: int, reward_point_cost: int) -> bool: - """add_reward_object_to_rewards_store(reward_object_definition_id, reward_point_cost) - - Add a Reward Object to the Satisfaction Rewards Store. - - :param reward_object_definition_id: The decimal identifier of a Reward Object. - :type reward_object_definition_id: int - :param reward_point_cost: The amount of Satisfaction Reward Points the Reward Object will cost the Sim to receive. - :type reward_point_cost: int - :return: True, if the Reward Object was added to the Rewards Store successfully. False, if not. - :rtype: bool - """ - return CommonSatisfactionRewardStoreUtils._add_reward_to_rewards_store(reward_object_definition_id, reward_point_cost, SatisfactionTracker.SatisfactionAwardTypes.OBJECT) - - @staticmethod - def add_reward_cas_part_to_rewards_store(reward_cas_part_definition_id: int, reward_point_cost: int) -> bool: - """add_reward_cas_part_to_rewards_store(reward_cas_part_definition_id, reward_point_cost) - - Add a Reward CAS Part to the Satisfaction Rewards Store. - - :param reward_cas_part_definition_id: The decimal identifier of a Reward CAS Part. - :type reward_cas_part_definition_id: int - :param reward_point_cost: The amount of Satisfaction Reward Points the Reward CAS Part will cost the Sim to receive. - :type reward_point_cost: int - :return: True, if the Reward CAS Part was added to the Rewards Store successfully. False, if not. - :rtype: bool - """ - return CommonSatisfactionRewardStoreUtils._add_reward_to_rewards_store(reward_cas_part_definition_id, reward_point_cost, SatisfactionTracker.SatisfactionAwardTypes.CASPART) - - @staticmethod - def remove_reward_from_rewards_store(reward_item_definition_id: int) -> bool: - """remove_reward_from_rewards_store(reward_item_definition_id) - - Remove a Reward Item from the Satisfaction Rewards Store. - - :param reward_item_definition_id: The decimal identifier of a Reward Item. - :type reward_item_definition_id: int - :return: True, if the Reward Item was removed from the Rewards Store successfully. False, if not. - :rtype: bool - """ - return CommonSatisfactionRewardStoreUtils._remove_reward_from_rewards_store(reward_item_definition_id) - - @staticmethod - def get_all_satisfaction_reward_store_items_generator( - include_satisfaction_reward_callback: Callable[[CommonSatisfactionRewardStoreItem], bool]=None - ) -> Iterator[CommonSatisfactionRewardStoreItem]: - """get_all_satisfaction_reward_store_items_generator(include_satisfaction_reward_callback=None) - - Retrieve all Satisfaction Rewards in the Satisfaction Rewards Store. - - :param include_satisfaction_reward_callback: If the result of this callback is True, the Satisfaction Reward\ - and Satisfaction Reward Data (Cost, Award Type), will be included in the results. If set to None, All Satisfaction Rewards will be included. - :type include_satisfaction_reward_callback: Callable[[CommonRewardStoreItem]], bool], optional - :return: All items from the satisfaction reward store. - :rtype: Iterator[CommonSatisfactionRewardStoreItem] - """ - satisfaction_reward_store_items: Dict[Reward, Tuple[int, SatisfactionTracker.SatisfactionAwardTypes]] = dict(SatisfactionTracker.SATISFACTION_STORE_ITEMS) - for (reward, data) in satisfaction_reward_store_items.items(): - reward_cost = data.cost - reward_type = CommonResourceUtils.get_enum_by_int_value(int(data.award_type), SatisfactionTracker.SatisfactionAwardTypes, default_value=None) - reward_store_item = CommonSatisfactionRewardStoreItem(reward, reward_cost, reward_type) - if include_satisfaction_reward_callback is not None and not include_satisfaction_reward_callback(reward_store_item): - continue - yield reward_store_item - - @staticmethod - def _add_reward_to_rewards_store(reward_definition_id: int, reward_point_cost: int, reward_type: SatisfactionTracker.SatisfactionAwardTypes) -> bool: - sim_reward_instance = CommonSatisfactionRewardStoreUtils._load_reward_instance(reward_definition_id) - if sim_reward_instance is None: - return False - sim_reward_data_immutable_slots_cls = sims4.collections.make_immutable_slots_class(['cost', 'award_type']) - reward_data = sim_reward_data_immutable_slots_cls(dict(cost=reward_point_cost, award_type=reward_type)) - store_items = dict(SatisfactionTracker.SATISFACTION_STORE_ITEMS) - store_items[sim_reward_instance] = reward_data - SatisfactionTracker.SATISFACTION_STORE_ITEMS = sims4.collections.FrozenAttributeDict(store_items) - return True - - @staticmethod - def _remove_reward_from_rewards_store(reward_definition_id: int) -> bool: - sim_reward_instance = CommonSatisfactionRewardStoreUtils._load_reward_instance(reward_definition_id) - if sim_reward_instance is None: - return False - store_items = dict(SatisfactionTracker.SATISFACTION_STORE_ITEMS) - if sim_reward_instance in store_items: - del store_items[sim_reward_instance] - SatisfactionTracker.SATISFACTION_STORE_ITEMS = sims4.collections.FrozenAttributeDict(store_items) - return True - - @staticmethod - def _load_reward_instance(reward_definition_id: int) -> Reward: - if isinstance(reward_definition_id, Reward): - return reward_definition_id - # noinspection PyBroadException - try: - # noinspection PyCallingNonCallable - reward_definition_id_instance = reward_definition_id() - if isinstance(reward_definition_id_instance, Reward): - # noinspection PyTypeChecker - return reward_definition_id - except: - pass - # noinspection PyBroadException - try: - reward_definition_id: int = int(reward_definition_id) - except: - # noinspection PyTypeChecker - reward_definition_id: Reward = reward_definition_id - return reward_definition_id - - from sims4.resources import Types - from s4ap.sims4communitylib.utils.common_resource_utils import CommonResourceUtils - return CommonResourceUtils.load_instance(Types.REWARD, reward_definition_id) diff --git a/Scripts/s4ap/utils/s4ap_generic_utils.py b/Scripts/s4ap/utils/s4ap_generic_utils.py index 2f62bdb..70a6878 100644 --- a/Scripts/s4ap/utils/s4ap_generic_utils.py +++ b/Scripts/s4ap/utils/s4ap_generic_utils.py @@ -1,13 +1,14 @@ import services from typing import Any, Callable, Optional, Union + from lot51_core.utils.dialog import DialogHelper from s4ap.modinfo import ModInfo from s4ap.utils.s4ap_sim_utils import S4APSimUtils from services.persistence_service import SaveGameData from sims.sim_info import SimInfo from sims4.resources import Types -from s4ap.sims4communitylib.events.zone_spin.common_zone_spin_event_dispatcher import CommonZoneSpinEventDispatcher -from s4ap.sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler +from sims4communitylib.events.zone_spin.common_zone_spin_event_dispatcher import CommonZoneSpinEventDispatcher +from sims4communitylib.exceptions.common_exceptions_handler import CommonExceptionHandler from s4ap.utils.s4ap_save_utils import S4APSaveUtils from sims4.localization import LocalizationHelperTuning from ui.ui_dialog import UiDialogOkCancel diff --git a/Scripts/s4ap/utils/s4ap_phone_utils.py b/Scripts/s4ap/utils/s4ap_phone_utils.py index d6f80ce..07f1fc5 100644 --- a/Scripts/s4ap/utils/s4ap_phone_utils.py +++ b/Scripts/s4ap/utils/s4ap_phone_utils.py @@ -14,8 +14,8 @@ from services import get_instance_manager from sims4.localization import LocalizationHelperTuning from sims4.resources import Types -from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from s4ap.sims4communitylib.events.sim.events.sim_trait_added import S4CLSimTraitAddedEvent +from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry +from sims4communitylib.events.sim.events.sim_trait_added import S4CLSimTraitAddedEvent from ui.ui_dialog_notification import UiDialogNotification from ui.ui_dialog_picker import ObjectPickerRow, UiObjectPicker diff --git a/Scripts/s4ap/utils/s4ap_reset_utils.py b/Scripts/s4ap/utils/s4ap_reset_utils.py index 352190a..6da2ca9 100644 --- a/Scripts/s4ap/utils/s4ap_reset_utils.py +++ b/Scripts/s4ap/utils/s4ap_reset_utils.py @@ -6,7 +6,7 @@ from server_commands.argument_helpers import TunableInstanceParam from sims4.localization import LocalizationHelperTuning from sims4.resources import Types -from s4ap.sims4communitylib.enums.traits_enum import CommonTraitId +from sims4communitylib.enums.traits_enum import CommonTraitId from ui.ui_dialog_notification import UiDialogNotification logger = S4APLogger.get_log() diff --git a/Scripts/s4ap/utils/s4ap_skill_utils.py b/Scripts/s4ap/utils/s4ap_skill_utils.py index 72c7810..3a61544 100644 --- a/Scripts/s4ap/utils/s4ap_skill_utils.py +++ b/Scripts/s4ap/utils/s4ap_skill_utils.py @@ -1,7 +1,5 @@ import re -import services -from typing import Callable, Iterator, Union from s4ap.enums.S4APLocalization import S4APTraitId from s4ap.events.skill_events import SimSkillLeveledUpEvent from s4ap.logging.s4ap_logger import S4APLogger @@ -11,9 +9,8 @@ from s4ap.utils.s4ap_sim_utils import S4APSimUtils from server_commands.argument_helpers import TunableInstanceParam from sims4.resources import Types +from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry from s4ap.utils.s4ap_skill_utils_class import S4APSkillUtils -from s4ap.sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry -from statistics.skill import Skill logger = S4APLogger.get_log() logger.enable() diff --git a/custom_scripts_for_decompile/generated/key b/custom_scripts_for_decompile/generated/key deleted file mode 100644 index 91e5fddf6e42d699a7a9284262cdcc928ccd4662..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 256 zcmV+b0ssDbX$%=XmK_*X85n*;FMwLKhiXAf1IGKL425sTwZrWiZoNvm_>Q(7MU^mw zboUtqanJ>40)q@n(>PkA)>qON?Qq4cPxdb`(3b3J!5o%geUuWB<1yBrpyg#*ivcUK znx0R>OfwYyiB%v`I@V^s@~l65T+w(TA1P*-Tbzp1;)CTDh~%w6_+^nY!+43i!{=C( zi4GxYS2 Date: Sat, 6 Sep 2025 16:35:53 -0600 Subject: [PATCH 076/134] ugh merging made everything bad worse fuck --- Scripts/s4ap/logging/s4ap_logger.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/s4ap/logging/s4ap_logger.py b/Scripts/s4ap/logging/s4ap_logger.py index 79853d5..b98178b 100644 --- a/Scripts/s4ap/logging/s4ap_logger.py +++ b/Scripts/s4ap/logging/s4ap_logger.py @@ -7,7 +7,7 @@ from sims4communitylib.logging.has_class_log import HasClassLog from sims4communitylib.mod_support.mod_identity import CommonModIdentity from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils -from lot51_core.utils import DialogHelper +from lot51_core.utils.dialog import DialogHelper class S4APLogger(HasClassLog): From 16d4b40953eb1d307191a64a62395446d24de90e Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Sat, 6 Sep 2025 20:50:45 -0600 Subject: [PATCH 077/134] add package file extracted --- ...882!00000000!F1C680E09B12C2B6.DSTImage.dds | Bin 0 -> 262272 bytes ...PieMenuCategory2.PieMenuCategoryTuning.xml | 5 ++ ...1.Cactus_S4AP_BE5K5G6HW52.ActionTuning.xml | 11 ++++ ...7.Cactus_S4AP_2S3LJ6AQOL2.ActionTuning.xml | 10 +++ ...A.Cactus_S4AP_UUV20239GU2.ActionTuning.xml | 11 ++++ ...0000!00566BE2CD18DAFC.English .StringTable | Bin 0 -> 785 bytes ...0000!02566BE2CD18DAFC.Chinese .StringTable | Bin 0 -> 785 bytes ...000000!03566BE2CD18DAFC.Czech .StringTable | Bin 0 -> 785 bytes ...00000!04566BE2CD18DAFC.Danish .StringTable | Bin 0 -> 785 bytes ...000000!05566BE2CD18DAFC.Dutch .StringTable | Bin 0 -> 785 bytes ...0000!06566BE2CD18DAFC.Finnish .StringTable | Bin 0 -> 785 bytes ...00000!07566BE2CD18DAFC.French .StringTable | Bin 0 -> 785 bytes ...00000!08566BE2CD18DAFC.German .StringTable | Bin 0 -> 785 bytes ...0000!0B566BE2CD18DAFC.Italian .StringTable | Bin 0 -> 785 bytes ...000!0C566BE2CD18DAFC.Japanese .StringTable | Bin 0 -> 785 bytes ...00000!0D566BE2CD18DAFC.Korean .StringTable | Bin 0 -> 785 bytes ...BE2CD18DAFC.Norwegian Nynorsk .StringTable | Bin 0 -> 785 bytes ...00000!0F566BE2CD18DAFC.Polish .StringTable | Bin 0 -> 785 bytes ...00000!10566BE2CD18DAFC.Unknown.StringTable | Bin 0 -> 785 bytes ...0!11566BE2CD18DAFC.Portuguese .StringTable | Bin 0 -> 785 bytes ...0000!12566BE2CD18DAFC.Russian .StringTable | Bin 0 -> 785 bytes ...0000!13566BE2CD18DAFC.Spanish .StringTable | Bin 0 -> 785 bytes ...0000!15566BE2CD18DAFC.Swedish .StringTable | Bin 0 -> 785 bytes ...6!0000000088B5FBB8.Constructor.SimData.xml | 31 +++++++++ ...6!0000000089032333.Constructor.SimData.xml | 31 +++++++++ ...6!000000008A606580.Constructor.SimData.xml | 31 +++++++++ ...6!000000008E00A8E2.Constructor.SimData.xml | 31 +++++++++ ...6!00000000942950EC.Constructor.SimData.xml | 31 +++++++++ ...6!00000000ACEC4762.Constructor.SimData.xml | 31 +++++++++ ...6!00000000B0C1684A.Constructor.SimData.xml | 31 +++++++++ ...6!00000000B4713A54.Constructor.SimData.xml | 31 +++++++++ ...6!00000000B629BB49.Constructor.SimData.xml | 31 +++++++++ ...6!00000000BB971053.Constructor.SimData.xml | 31 +++++++++ ...6!00000000C8D1ECF5.Constructor.SimData.xml | 31 +++++++++ ...6!00000000D037694E.Constructor.SimData.xml | 31 +++++++++ ...6!00000000D51559C9.Constructor.SimData.xml | 31 +++++++++ ...6!00000000D6BFC3D1.Constructor.SimData.xml | 31 +++++++++ ...6!00000000D79B9065.Constructor.SimData.xml | 31 +++++++++ ...6!00000000D888EB85.Constructor.SimData.xml | 31 +++++++++ ...6!00000000DA4F627F.Constructor.SimData.xml | 31 +++++++++ ...6!00000000DAF19D9B.Constructor.SimData.xml | 31 +++++++++ ...6!00000000E330058C.Constructor.SimData.xml | 31 +++++++++ ...6!00000000E9CA5D38.Constructor.SimData.xml | 31 +++++++++ ...6!00000000EA1784B3.Constructor.SimData.xml | 31 +++++++++ ...6!00000000F3563747.Constructor.SimData.xml | 31 +++++++++ ...6!00000000F93B00FF.Constructor.SimData.xml | 31 +++++++++ ...6!00000000FEB64AAE.Constructor.SimData.xml | 31 +++++++++ ...C!000000008494610E.Constructor.SimData.xml | 60 ++++++++++++++++++ ...C!0000000085944434.Constructor.SimData.xml | 60 ++++++++++++++++++ ...C!00000000D04CC916.Constructor.SimData.xml | 60 ++++++++++++++++++ ...C!00000000D04CC917.Constructor.SimData.xml | 60 ++++++++++++++++++ ...C!00000000D04CC918.Constructor.SimData.xml | 60 ++++++++++++++++++ ...C!00000000D04CC919.Constructor.SimData.xml | 60 ++++++++++++++++++ ...C!00000000D04CC91A.Constructor.SimData.xml | 60 ++++++++++++++++++ ...C!00000000D04CC91B.Constructor.SimData.xml | 60 ++++++++++++++++++ ...C!00000000D04CC91C.Constructor.SimData.xml | 60 ++++++++++++++++++ ...C!00000000D04CC91D.Constructor.SimData.xml | 60 ++++++++++++++++++ ...C!00000000D04CC91E.Constructor.SimData.xml | 60 ++++++++++++++++++ ...C!00000000D04CC91F.Constructor.SimData.xml | 60 ++++++++++++++++++ ...C!00000000D14CCAF0.Constructor.SimData.xml | 60 ++++++++++++++++++ ...C!00000000D14CCAF1.Constructor.SimData.xml | 60 ++++++++++++++++++ ...C!00000000D14CCAF2.Constructor.SimData.xml | 60 ++++++++++++++++++ ...C!00000000D14CCAF3.Constructor.SimData.xml | 60 ++++++++++++++++++ ...C!00000000D14CCAF4.Constructor.SimData.xml | 60 ++++++++++++++++++ ...C!00000000D14CCAF6.Constructor.SimData.xml | 60 ++++++++++++++++++ ...C!00000000D301A22C.Constructor.SimData.xml | 60 ++++++++++++++++++ ...C!00000000D7924B70.Constructor.SimData.xml | 60 ++++++++++++++++++ ...C!00000000D7924B71.Constructor.SimData.xml | 60 ++++++++++++++++++ ...C!00000000D7924B72.Constructor.SimData.xml | 60 ++++++++++++++++++ ...C!00000000D7924B73.Constructor.SimData.xml | 60 ++++++++++++++++++ ...C!00000000D7924B76.Constructor.SimData.xml | 60 ++++++++++++++++++ ...C!00000000D7924B77.Constructor.SimData.xml | 60 ++++++++++++++++++ ...C!00000000D7924B7C.Constructor.SimData.xml | 60 ++++++++++++++++++ ...C!00000000D7924B7D.Constructor.SimData.xml | 60 ++++++++++++++++++ ...7!00000000A85DB38B.Constructor.SimData.xml | 27 ++++++++ ...B8.Cactus_S4AP_Trait21:Buff.BuffTuning.xml | 21 ++++++ ...33.Cactus_S4AP_Trait24:Buff.BuffTuning.xml | 18 ++++++ ...80.Cactus_S4AP_Trait14:Buff.BuffTuning.xml | 21 ++++++ ...8E2.Cactus_S4AP_Trait5:Buff.BuffTuning.xml | 21 ++++++ ...0EC.Cactus_S4AP_Trait3:Buff.BuffTuning.xml | 21 ++++++ ...62.Cactus_S4AP_Trait23:Buff.BuffTuning.xml | 18 ++++++ ...4A.Cactus_S4AP_Trait16:Buff.BuffTuning.xml | 21 ++++++ ...54.Cactus_S4AP_Trait10:Buff.BuffTuning.xml | 21 ++++++ ...B49.Cactus_S4AP_Trait4:Buff.BuffTuning.xml | 18 ++++++ ...53.Cactus_S4AP_Trait19:Buff.BuffTuning.xml | 21 ++++++ ...ECF5.Cactus_S4AP_Trait:Buff.BuffTuning.xml | 21 ++++++ ...4E.Cactus_S4AP_Trait12:Buff.BuffTuning.xml | 21 ++++++ ...C9.Cactus_S4AP_Trait22:Buff.BuffTuning.xml | 18 ++++++ ...D1.Cactus_S4AP_Trait17:Buff.BuffTuning.xml | 21 ++++++ ...065.Cactus_S4AP_Trait8:Buff.BuffTuning.xml | 21 ++++++ ...85.Cactus_S4AP_Trait13:Buff.BuffTuning.xml | 21 ++++++ ...27F.Cactus_S4AP_Trait6:Buff.BuffTuning.xml | 21 ++++++ ...9B.Cactus_S4AP_Trait11:Buff.BuffTuning.xml | 21 ++++++ ...8C.Cactus_S4AP_Trait18:Buff.BuffTuning.xml | 21 ++++++ ...D38.Cactus_S4AP_Trait7:Buff.BuffTuning.xml | 21 ++++++ ...4B3.Cactus_S4AP_Trait2:Buff.BuffTuning.xml | 21 ++++++ ...47.Cactus_S4AP_Trait15:Buff.BuffTuning.xml | 21 ++++++ ...FF.Cactus_S4AP_Trait20:Buff.BuffTuning.xml | 21 ++++++ ...AAE.Cactus_S4AP_Trait9:Buff.BuffTuning.xml | 21 ++++++ ...actus_S4AP_ResyncLocations.TraitTuning.xml | 14 ++++ ...actus_S4AP_ShowYamlOptions.TraitTuning.xml | 14 ++++ ...4CC916.Cactus_S4AP_Trait19.TraitTuning.xml | 19 ++++++ ...4CC917.Cactus_S4AP_Trait18.TraitTuning.xml | 19 ++++++ ...4CC918.Cactus_S4AP_Trait17.TraitTuning.xml | 19 ++++++ ...4CC919.Cactus_S4AP_Trait16.TraitTuning.xml | 19 ++++++ ...4CC91A.Cactus_S4AP_Trait15.TraitTuning.xml | 19 ++++++ ...4CC91B.Cactus_S4AP_Trait14.TraitTuning.xml | 19 ++++++ ...4CC91C.Cactus_S4AP_Trait13.TraitTuning.xml | 19 ++++++ ...4CC91D.Cactus_S4AP_Trait12.TraitTuning.xml | 19 ++++++ ...4CC91E.Cactus_S4AP_Trait11.TraitTuning.xml | 19 ++++++ ...4CC91F.Cactus_S4AP_Trait10.TraitTuning.xml | 19 ++++++ ...4CCAF0.Cactus_S4AP_Trait22.TraitTuning.xml | 19 ++++++ ...4CCAF1.Cactus_S4AP_Trait23.TraitTuning.xml | 19 ++++++ ...4CCAF2.Cactus_S4AP_Trait20.TraitTuning.xml | 19 ++++++ ...4CCAF3.Cactus_S4AP_Trait21.TraitTuning.xml | 19 ++++++ ...4CCAF4.Cactus_S4AP_Trait26.TraitTuning.xml | 14 ++++ ...4CCAF6.Cactus_S4AP_Trait24.TraitTuning.xml | 19 ++++++ ...D301A22C.Cactus_S4AP_Trait.TraitTuning.xml | 19 ++++++ ...7924B70.Cactus_S4AP_Trait4.TraitTuning.xml | 19 ++++++ ...7924B71.Cactus_S4AP_Trait5.TraitTuning.xml | 19 ++++++ ...7924B72.Cactus_S4AP_Trait6.TraitTuning.xml | 19 ++++++ ...7924B73.Cactus_S4AP_Trait7.TraitTuning.xml | 19 ++++++ ...7924B76.Cactus_S4AP_Trait2.TraitTuning.xml | 19 ++++++ ...7924B77.Cactus_S4AP_Trait3.TraitTuning.xml | 19 ++++++ ...7924B7C.Cactus_S4AP_Trait8.TraitTuning.xml | 19 ++++++ ...7924B7D.Cactus_S4AP_Trait9.TraitTuning.xml | 19 ++++++ ...mlOptionsInteraction.InteractionTuning.xml | 52 +++++++++++++++ ...ractionExperimental2.InteractionTuning.xml | 52 +++++++++++++++ ...LocationsInteraction.InteractionTuning.xml | 52 +++++++++++++++ 129 files changed, 3574 insertions(+) create mode 100644 Package/Cactus_S4AP (package source)/00B2D882!00000000!F1C680E09B12C2B6.DSTImage.dds create mode 100644 Package/Cactus_S4AP (package source)/03E9D964!00000000!00000000A85DB38B.Cactus_S4AP_PieMenuCategory2.PieMenuCategoryTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/0C772E27!00000000!000000009952F751.Cactus_S4AP_BE5K5G6HW52.ActionTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/0C772E27!00000000!00000000BCFDFDC7.Cactus_S4AP_2S3LJ6AQOL2.ActionTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/0C772E27!00000000!00000000C26EC7CA.Cactus_S4AP_UUV20239GU2.ActionTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/220557DA!00000000!00566BE2CD18DAFC.English .StringTable create mode 100644 Package/Cactus_S4AP (package source)/220557DA!00000000!02566BE2CD18DAFC.Chinese .StringTable create mode 100644 Package/Cactus_S4AP (package source)/220557DA!00000000!03566BE2CD18DAFC.Czech .StringTable create mode 100644 Package/Cactus_S4AP (package source)/220557DA!00000000!04566BE2CD18DAFC.Danish .StringTable create mode 100644 Package/Cactus_S4AP (package source)/220557DA!00000000!05566BE2CD18DAFC.Dutch .StringTable create mode 100644 Package/Cactus_S4AP (package source)/220557DA!00000000!06566BE2CD18DAFC.Finnish .StringTable create mode 100644 Package/Cactus_S4AP (package source)/220557DA!00000000!07566BE2CD18DAFC.French .StringTable create mode 100644 Package/Cactus_S4AP (package source)/220557DA!00000000!08566BE2CD18DAFC.German .StringTable create mode 100644 Package/Cactus_S4AP (package source)/220557DA!00000000!0B566BE2CD18DAFC.Italian .StringTable create mode 100644 Package/Cactus_S4AP (package source)/220557DA!00000000!0C566BE2CD18DAFC.Japanese .StringTable create mode 100644 Package/Cactus_S4AP (package source)/220557DA!00000000!0D566BE2CD18DAFC.Korean .StringTable create mode 100644 Package/Cactus_S4AP (package source)/220557DA!00000000!0E566BE2CD18DAFC.Norwegian Nynorsk .StringTable create mode 100644 Package/Cactus_S4AP (package source)/220557DA!00000000!0F566BE2CD18DAFC.Polish .StringTable create mode 100644 Package/Cactus_S4AP (package source)/220557DA!00000000!10566BE2CD18DAFC.Unknown.StringTable create mode 100644 Package/Cactus_S4AP (package source)/220557DA!00000000!11566BE2CD18DAFC.Portuguese .StringTable create mode 100644 Package/Cactus_S4AP (package source)/220557DA!00000000!12566BE2CD18DAFC.Russian .StringTable create mode 100644 Package/Cactus_S4AP (package source)/220557DA!00000000!13566BE2CD18DAFC.Spanish .StringTable create mode 100644 Package/Cactus_S4AP (package source)/220557DA!00000000!15566BE2CD18DAFC.Swedish .StringTable create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!0000000088B5FBB8.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!0000000089032333.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!000000008A606580.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!000000008E00A8E2.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000942950EC.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000ACEC4762.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000B0C1684A.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000B4713A54.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000B629BB49.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000BB971053.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000C8D1ECF5.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000D037694E.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000D51559C9.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000D6BFC3D1.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000D79B9065.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000D888EB85.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000DA4F627F.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000DAF19D9B.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000E330058C.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000E9CA5D38.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000EA1784B3.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000F3563747.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000F93B00FF.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000FEB64AAE.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!000000008494610E.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!0000000085944434.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC916.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC917.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC918.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC919.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91A.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91B.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91C.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91D.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91E.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91F.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF0.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF1.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF2.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF3.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF4.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF6.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D301A22C.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B70.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B71.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B72.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B73.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B76.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B77.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B7C.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B7D.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!00E9D967!00000000A85DB38B.Constructor.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!0000000088B5FBB8.Cactus_S4AP_Trait21:Buff.BuffTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!0000000089032333.Cactus_S4AP_Trait24:Buff.BuffTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!000000008A606580.Cactus_S4AP_Trait14:Buff.BuffTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!000000008E00A8E2.Cactus_S4AP_Trait5:Buff.BuffTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!00000000942950EC.Cactus_S4AP_Trait3:Buff.BuffTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!00000000ACEC4762.Cactus_S4AP_Trait23:Buff.BuffTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!00000000B0C1684A.Cactus_S4AP_Trait16:Buff.BuffTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!00000000B4713A54.Cactus_S4AP_Trait10:Buff.BuffTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!00000000B629BB49.Cactus_S4AP_Trait4:Buff.BuffTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!00000000BB971053.Cactus_S4AP_Trait19:Buff.BuffTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!00000000C8D1ECF5.Cactus_S4AP_Trait:Buff.BuffTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D037694E.Cactus_S4AP_Trait12:Buff.BuffTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D51559C9.Cactus_S4AP_Trait22:Buff.BuffTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D6BFC3D1.Cactus_S4AP_Trait17:Buff.BuffTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D79B9065.Cactus_S4AP_Trait8:Buff.BuffTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D888EB85.Cactus_S4AP_Trait13:Buff.BuffTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!00000000DA4F627F.Cactus_S4AP_Trait6:Buff.BuffTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!00000000DAF19D9B.Cactus_S4AP_Trait11:Buff.BuffTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!00000000E330058C.Cactus_S4AP_Trait18:Buff.BuffTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!00000000E9CA5D38.Cactus_S4AP_Trait7:Buff.BuffTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!00000000EA1784B3.Cactus_S4AP_Trait2:Buff.BuffTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!00000000F3563747.Cactus_S4AP_Trait15:Buff.BuffTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!00000000F93B00FF.Cactus_S4AP_Trait20:Buff.BuffTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!00000000FEB64AAE.Cactus_S4AP_Trait9:Buff.BuffTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!000000008494610E.Cactus_S4AP_ResyncLocations.TraitTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!0000000085944434.Cactus_S4AP_ShowYamlOptions.TraitTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC916.Cactus_S4AP_Trait19.TraitTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC917.Cactus_S4AP_Trait18.TraitTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC918.Cactus_S4AP_Trait17.TraitTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC919.Cactus_S4AP_Trait16.TraitTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91A.Cactus_S4AP_Trait15.TraitTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91B.Cactus_S4AP_Trait14.TraitTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91C.Cactus_S4AP_Trait13.TraitTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91D.Cactus_S4AP_Trait12.TraitTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91E.Cactus_S4AP_Trait11.TraitTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91F.Cactus_S4AP_Trait10.TraitTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF0.Cactus_S4AP_Trait22.TraitTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF1.Cactus_S4AP_Trait23.TraitTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF2.Cactus_S4AP_Trait20.TraitTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF3.Cactus_S4AP_Trait21.TraitTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF4.Cactus_S4AP_Trait26.TraitTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF6.Cactus_S4AP_Trait24.TraitTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D301A22C.Cactus_S4AP_Trait.TraitTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B70.Cactus_S4AP_Trait4.TraitTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B71.Cactus_S4AP_Trait5.TraitTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B72.Cactus_S4AP_Trait6.TraitTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B73.Cactus_S4AP_Trait7.TraitTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B76.Cactus_S4AP_Trait2.TraitTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B77.Cactus_S4AP_Trait3.TraitTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B7C.Cactus_S4AP_Trait8.TraitTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B7D.Cactus_S4AP_Trait9.TraitTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/E882D22F!00000000!00000000A07795F4.Cactus_S4AP_ShowYamlOptionsInteraction.InteractionTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/E882D22F!00000000!00000000C5690C31.Cactus_S4AP_SuperInteractionExperimental2.InteractionTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/E882D22F!00000000!00000000FE6A648E.Cactus_S4AP_ResyncLocationsInteraction.InteractionTuning.xml diff --git a/Package/Cactus_S4AP (package source)/00B2D882!00000000!F1C680E09B12C2B6.DSTImage.dds b/Package/Cactus_S4AP (package source)/00B2D882!00000000!F1C680E09B12C2B6.DSTImage.dds new file mode 100644 index 0000000000000000000000000000000000000000..dab1e4756d649c6f68bad85804610b815c4b8a4e GIT binary patch literal 262272 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 F{{gkGYFhvR literal 0 HcmV?d00001 diff --git a/Package/Cactus_S4AP (package source)/03E9D964!00000000!00000000A85DB38B.Cactus_S4AP_PieMenuCategory2.PieMenuCategoryTuning.xml b/Package/Cactus_S4AP (package source)/03E9D964!00000000!00000000A85DB38B.Cactus_S4AP_PieMenuCategory2.PieMenuCategoryTuning.xml new file mode 100644 index 0000000..58ce299 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/03E9D964!00000000!00000000A85DB38B.Cactus_S4AP_PieMenuCategory2.PieMenuCategoryTuning.xml @@ -0,0 +1,5 @@ + + + 0x85992464 + 2f7d0004:00000000:f1c680e09b12c2b6 + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/0C772E27!00000000!000000009952F751.Cactus_S4AP_BE5K5G6HW52.ActionTuning.xml b/Package/Cactus_S4AP (package source)/0C772E27!00000000!000000009952F751.Cactus_S4AP_BE5K5G6HW52.ActionTuning.xml new file mode 100644 index 0000000..2aeb814 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/0C772E27!00000000!000000009952F751.Cactus_S4AP_BE5K5G6HW52.ActionTuning.xml @@ -0,0 +1,11 @@ + + + + + + 2224316686 + Actor + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/0C772E27!00000000!00000000BCFDFDC7.Cactus_S4AP_2S3LJ6AQOL2.ActionTuning.xml b/Package/Cactus_S4AP (package source)/0C772E27!00000000!00000000BCFDFDC7.Cactus_S4AP_2S3LJ6AQOL2.ActionTuning.xml new file mode 100644 index 0000000..a35e572 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/0C772E27!00000000!00000000BCFDFDC7.Cactus_S4AP_2S3LJ6AQOL2.ActionTuning.xml @@ -0,0 +1,10 @@ + + + + + + 3511470836 + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/0C772E27!00000000!00000000C26EC7CA.Cactus_S4AP_UUV20239GU2.ActionTuning.xml b/Package/Cactus_S4AP (package source)/0C772E27!00000000!00000000C26EC7CA.Cactus_S4AP_UUV20239GU2.ActionTuning.xml new file mode 100644 index 0000000..4133735 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/0C772E27!00000000!00000000C26EC7CA.Cactus_S4AP_UUV20239GU2.ActionTuning.xml @@ -0,0 +1,11 @@ + + + + + + 2241086516 + Actor + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/220557DA!00000000!00566BE2CD18DAFC.English .StringTable b/Package/Cactus_S4AP (package source)/220557DA!00000000!00566BE2CD18DAFC.English .StringTable new file mode 100644 index 0000000000000000000000000000000000000000..74712d49ee73c9c8d69de0c890299282755f6db8 GIT binary patch literal 785 zcmZuvPe>L)9Q{>vDooP~FR=$ff(p{gQwIgf;FF@QgQps1=i42=*_mZ#_WO3hs}Thq zx@1L2c%=W?W};L5qeV&%9E%9t}AGfg8#iR4Sux1ek1^u7zfr=SzA5|wi7 z)C5LW%1l4B(#4VrgwDt) zNG-KKgYKIU*;Yss!GxdVm!9o;3x_O@MM%6HJu}+>xoe$v1PG<1*xkOIhd%xS(U=n;;_zNA@+vK6xn!MTgvkpfsC{0+R6{dt^ zV#$S-uWj=-*)0N-R_T-xEJUMxfX!D2*Wj4teG$u$=>OTrbE{8xOF3Xt-ua=YO&OVT zooY^$vWBx0&*$NAE{LQ@cBe?ZSd)50_^9gAskc8C8!bt7x$$yswO#e7a6n1j8u&v?FW^A_YuxNFsQE6jTukBs rNvc9*C%fm)-!AaTbXY07Px=;%HX@3+u)|*8!zm*>ER9n{7>c5Q+Ic3@ literal 0 HcmV?d00001 diff --git a/Package/Cactus_S4AP (package source)/220557DA!00000000!02566BE2CD18DAFC.Chinese .StringTable b/Package/Cactus_S4AP (package source)/220557DA!00000000!02566BE2CD18DAFC.Chinese .StringTable new file mode 100644 index 0000000000000000000000000000000000000000..74712d49ee73c9c8d69de0c890299282755f6db8 GIT binary patch literal 785 zcmZuvPe>L)9Q{>vDooP~FR=$ff(p{gQwIgf;FF@QgQps1=i42=*_mZ#_WO3hs}Thq zx@1L2c%=W?W};L5qeV&%9E%9t}AGfg8#iR4Sux1ek1^u7zfr=SzA5|wi7 z)C5LW%1l4B(#4VrgwDt) zNG-KKgYKIU*;Yss!GxdVm!9o;3x_O@MM%6HJu}+>xoe$v1PG<1*xkOIhd%xS(U=n;;_zNA@+vK6xn!MTgvkpfsC{0+R6{dt^ zV#$S-uWj=-*)0N-R_T-xEJUMxfX!D2*Wj4teG$u$=>OTrbE{8xOF3Xt-ua=YO&OVT zooY^$vWBx0&*$NAE{LQ@cBe?ZSd)50_^9gAskc8C8!bt7x$$yswO#e7a6n1j8u&v?FW^A_YuxNFsQE6jTukBs rNvc9*C%fm)-!AaTbXY07Px=;%HX@3+u)|*8!zm*>ER9n{7>c5Q+Ic3@ literal 0 HcmV?d00001 diff --git a/Package/Cactus_S4AP (package source)/220557DA!00000000!03566BE2CD18DAFC.Czech .StringTable b/Package/Cactus_S4AP (package source)/220557DA!00000000!03566BE2CD18DAFC.Czech .StringTable new file mode 100644 index 0000000000000000000000000000000000000000..74712d49ee73c9c8d69de0c890299282755f6db8 GIT binary patch literal 785 zcmZuvPe>L)9Q{>vDooP~FR=$ff(p{gQwIgf;FF@QgQps1=i42=*_mZ#_WO3hs}Thq zx@1L2c%=W?W};L5qeV&%9E%9t}AGfg8#iR4Sux1ek1^u7zfr=SzA5|wi7 z)C5LW%1l4B(#4VrgwDt) zNG-KKgYKIU*;Yss!GxdVm!9o;3x_O@MM%6HJu}+>xoe$v1PG<1*xkOIhd%xS(U=n;;_zNA@+vK6xn!MTgvkpfsC{0+R6{dt^ zV#$S-uWj=-*)0N-R_T-xEJUMxfX!D2*Wj4teG$u$=>OTrbE{8xOF3Xt-ua=YO&OVT zooY^$vWBx0&*$NAE{LQ@cBe?ZSd)50_^9gAskc8C8!bt7x$$yswO#e7a6n1j8u&v?FW^A_YuxNFsQE6jTukBs rNvc9*C%fm)-!AaTbXY07Px=;%HX@3+u)|*8!zm*>ER9n{7>c5Q+Ic3@ literal 0 HcmV?d00001 diff --git a/Package/Cactus_S4AP (package source)/220557DA!00000000!04566BE2CD18DAFC.Danish .StringTable b/Package/Cactus_S4AP (package source)/220557DA!00000000!04566BE2CD18DAFC.Danish .StringTable new file mode 100644 index 0000000000000000000000000000000000000000..74712d49ee73c9c8d69de0c890299282755f6db8 GIT binary patch literal 785 zcmZuvPe>L)9Q{>vDooP~FR=$ff(p{gQwIgf;FF@QgQps1=i42=*_mZ#_WO3hs}Thq zx@1L2c%=W?W};L5qeV&%9E%9t}AGfg8#iR4Sux1ek1^u7zfr=SzA5|wi7 z)C5LW%1l4B(#4VrgwDt) zNG-KKgYKIU*;Yss!GxdVm!9o;3x_O@MM%6HJu}+>xoe$v1PG<1*xkOIhd%xS(U=n;;_zNA@+vK6xn!MTgvkpfsC{0+R6{dt^ zV#$S-uWj=-*)0N-R_T-xEJUMxfX!D2*Wj4teG$u$=>OTrbE{8xOF3Xt-ua=YO&OVT zooY^$vWBx0&*$NAE{LQ@cBe?ZSd)50_^9gAskc8C8!bt7x$$yswO#e7a6n1j8u&v?FW^A_YuxNFsQE6jTukBs rNvc9*C%fm)-!AaTbXY07Px=;%HX@3+u)|*8!zm*>ER9n{7>c5Q+Ic3@ literal 0 HcmV?d00001 diff --git a/Package/Cactus_S4AP (package source)/220557DA!00000000!05566BE2CD18DAFC.Dutch .StringTable b/Package/Cactus_S4AP (package source)/220557DA!00000000!05566BE2CD18DAFC.Dutch .StringTable new file mode 100644 index 0000000000000000000000000000000000000000..74712d49ee73c9c8d69de0c890299282755f6db8 GIT binary patch literal 785 zcmZuvPe>L)9Q{>vDooP~FR=$ff(p{gQwIgf;FF@QgQps1=i42=*_mZ#_WO3hs}Thq zx@1L2c%=W?W};L5qeV&%9E%9t}AGfg8#iR4Sux1ek1^u7zfr=SzA5|wi7 z)C5LW%1l4B(#4VrgwDt) zNG-KKgYKIU*;Yss!GxdVm!9o;3x_O@MM%6HJu}+>xoe$v1PG<1*xkOIhd%xS(U=n;;_zNA@+vK6xn!MTgvkpfsC{0+R6{dt^ zV#$S-uWj=-*)0N-R_T-xEJUMxfX!D2*Wj4teG$u$=>OTrbE{8xOF3Xt-ua=YO&OVT zooY^$vWBx0&*$NAE{LQ@cBe?ZSd)50_^9gAskc8C8!bt7x$$yswO#e7a6n1j8u&v?FW^A_YuxNFsQE6jTukBs rNvc9*C%fm)-!AaTbXY07Px=;%HX@3+u)|*8!zm*>ER9n{7>c5Q+Ic3@ literal 0 HcmV?d00001 diff --git a/Package/Cactus_S4AP (package source)/220557DA!00000000!06566BE2CD18DAFC.Finnish .StringTable b/Package/Cactus_S4AP (package source)/220557DA!00000000!06566BE2CD18DAFC.Finnish .StringTable new file mode 100644 index 0000000000000000000000000000000000000000..74712d49ee73c9c8d69de0c890299282755f6db8 GIT binary patch literal 785 zcmZuvPe>L)9Q{>vDooP~FR=$ff(p{gQwIgf;FF@QgQps1=i42=*_mZ#_WO3hs}Thq zx@1L2c%=W?W};L5qeV&%9E%9t}AGfg8#iR4Sux1ek1^u7zfr=SzA5|wi7 z)C5LW%1l4B(#4VrgwDt) zNG-KKgYKIU*;Yss!GxdVm!9o;3x_O@MM%6HJu}+>xoe$v1PG<1*xkOIhd%xS(U=n;;_zNA@+vK6xn!MTgvkpfsC{0+R6{dt^ zV#$S-uWj=-*)0N-R_T-xEJUMxfX!D2*Wj4teG$u$=>OTrbE{8xOF3Xt-ua=YO&OVT zooY^$vWBx0&*$NAE{LQ@cBe?ZSd)50_^9gAskc8C8!bt7x$$yswO#e7a6n1j8u&v?FW^A_YuxNFsQE6jTukBs rNvc9*C%fm)-!AaTbXY07Px=;%HX@3+u)|*8!zm*>ER9n{7>c5Q+Ic3@ literal 0 HcmV?d00001 diff --git a/Package/Cactus_S4AP (package source)/220557DA!00000000!07566BE2CD18DAFC.French .StringTable b/Package/Cactus_S4AP (package source)/220557DA!00000000!07566BE2CD18DAFC.French .StringTable new file mode 100644 index 0000000000000000000000000000000000000000..74712d49ee73c9c8d69de0c890299282755f6db8 GIT binary patch literal 785 zcmZuvPe>L)9Q{>vDooP~FR=$ff(p{gQwIgf;FF@QgQps1=i42=*_mZ#_WO3hs}Thq zx@1L2c%=W?W};L5qeV&%9E%9t}AGfg8#iR4Sux1ek1^u7zfr=SzA5|wi7 z)C5LW%1l4B(#4VrgwDt) zNG-KKgYKIU*;Yss!GxdVm!9o;3x_O@MM%6HJu}+>xoe$v1PG<1*xkOIhd%xS(U=n;;_zNA@+vK6xn!MTgvkpfsC{0+R6{dt^ zV#$S-uWj=-*)0N-R_T-xEJUMxfX!D2*Wj4teG$u$=>OTrbE{8xOF3Xt-ua=YO&OVT zooY^$vWBx0&*$NAE{LQ@cBe?ZSd)50_^9gAskc8C8!bt7x$$yswO#e7a6n1j8u&v?FW^A_YuxNFsQE6jTukBs rNvc9*C%fm)-!AaTbXY07Px=;%HX@3+u)|*8!zm*>ER9n{7>c5Q+Ic3@ literal 0 HcmV?d00001 diff --git a/Package/Cactus_S4AP (package source)/220557DA!00000000!08566BE2CD18DAFC.German .StringTable b/Package/Cactus_S4AP (package source)/220557DA!00000000!08566BE2CD18DAFC.German .StringTable new file mode 100644 index 0000000000000000000000000000000000000000..74712d49ee73c9c8d69de0c890299282755f6db8 GIT binary patch literal 785 zcmZuvPe>L)9Q{>vDooP~FR=$ff(p{gQwIgf;FF@QgQps1=i42=*_mZ#_WO3hs}Thq zx@1L2c%=W?W};L5qeV&%9E%9t}AGfg8#iR4Sux1ek1^u7zfr=SzA5|wi7 z)C5LW%1l4B(#4VrgwDt) zNG-KKgYKIU*;Yss!GxdVm!9o;3x_O@MM%6HJu}+>xoe$v1PG<1*xkOIhd%xS(U=n;;_zNA@+vK6xn!MTgvkpfsC{0+R6{dt^ zV#$S-uWj=-*)0N-R_T-xEJUMxfX!D2*Wj4teG$u$=>OTrbE{8xOF3Xt-ua=YO&OVT zooY^$vWBx0&*$NAE{LQ@cBe?ZSd)50_^9gAskc8C8!bt7x$$yswO#e7a6n1j8u&v?FW^A_YuxNFsQE6jTukBs rNvc9*C%fm)-!AaTbXY07Px=;%HX@3+u)|*8!zm*>ER9n{7>c5Q+Ic3@ literal 0 HcmV?d00001 diff --git a/Package/Cactus_S4AP (package source)/220557DA!00000000!0B566BE2CD18DAFC.Italian .StringTable b/Package/Cactus_S4AP (package source)/220557DA!00000000!0B566BE2CD18DAFC.Italian .StringTable new file mode 100644 index 0000000000000000000000000000000000000000..74712d49ee73c9c8d69de0c890299282755f6db8 GIT binary patch literal 785 zcmZuvPe>L)9Q{>vDooP~FR=$ff(p{gQwIgf;FF@QgQps1=i42=*_mZ#_WO3hs}Thq zx@1L2c%=W?W};L5qeV&%9E%9t}AGfg8#iR4Sux1ek1^u7zfr=SzA5|wi7 z)C5LW%1l4B(#4VrgwDt) zNG-KKgYKIU*;Yss!GxdVm!9o;3x_O@MM%6HJu}+>xoe$v1PG<1*xkOIhd%xS(U=n;;_zNA@+vK6xn!MTgvkpfsC{0+R6{dt^ zV#$S-uWj=-*)0N-R_T-xEJUMxfX!D2*Wj4teG$u$=>OTrbE{8xOF3Xt-ua=YO&OVT zooY^$vWBx0&*$NAE{LQ@cBe?ZSd)50_^9gAskc8C8!bt7x$$yswO#e7a6n1j8u&v?FW^A_YuxNFsQE6jTukBs rNvc9*C%fm)-!AaTbXY07Px=;%HX@3+u)|*8!zm*>ER9n{7>c5Q+Ic3@ literal 0 HcmV?d00001 diff --git a/Package/Cactus_S4AP (package source)/220557DA!00000000!0C566BE2CD18DAFC.Japanese .StringTable b/Package/Cactus_S4AP (package source)/220557DA!00000000!0C566BE2CD18DAFC.Japanese .StringTable new file mode 100644 index 0000000000000000000000000000000000000000..74712d49ee73c9c8d69de0c890299282755f6db8 GIT binary patch literal 785 zcmZuvPe>L)9Q{>vDooP~FR=$ff(p{gQwIgf;FF@QgQps1=i42=*_mZ#_WO3hs}Thq zx@1L2c%=W?W};L5qeV&%9E%9t}AGfg8#iR4Sux1ek1^u7zfr=SzA5|wi7 z)C5LW%1l4B(#4VrgwDt) zNG-KKgYKIU*;Yss!GxdVm!9o;3x_O@MM%6HJu}+>xoe$v1PG<1*xkOIhd%xS(U=n;;_zNA@+vK6xn!MTgvkpfsC{0+R6{dt^ zV#$S-uWj=-*)0N-R_T-xEJUMxfX!D2*Wj4teG$u$=>OTrbE{8xOF3Xt-ua=YO&OVT zooY^$vWBx0&*$NAE{LQ@cBe?ZSd)50_^9gAskc8C8!bt7x$$yswO#e7a6n1j8u&v?FW^A_YuxNFsQE6jTukBs rNvc9*C%fm)-!AaTbXY07Px=;%HX@3+u)|*8!zm*>ER9n{7>c5Q+Ic3@ literal 0 HcmV?d00001 diff --git a/Package/Cactus_S4AP (package source)/220557DA!00000000!0D566BE2CD18DAFC.Korean .StringTable b/Package/Cactus_S4AP (package source)/220557DA!00000000!0D566BE2CD18DAFC.Korean .StringTable new file mode 100644 index 0000000000000000000000000000000000000000..74712d49ee73c9c8d69de0c890299282755f6db8 GIT binary patch literal 785 zcmZuvPe>L)9Q{>vDooP~FR=$ff(p{gQwIgf;FF@QgQps1=i42=*_mZ#_WO3hs}Thq zx@1L2c%=W?W};L5qeV&%9E%9t}AGfg8#iR4Sux1ek1^u7zfr=SzA5|wi7 z)C5LW%1l4B(#4VrgwDt) zNG-KKgYKIU*;Yss!GxdVm!9o;3x_O@MM%6HJu}+>xoe$v1PG<1*xkOIhd%xS(U=n;;_zNA@+vK6xn!MTgvkpfsC{0+R6{dt^ zV#$S-uWj=-*)0N-R_T-xEJUMxfX!D2*Wj4teG$u$=>OTrbE{8xOF3Xt-ua=YO&OVT zooY^$vWBx0&*$NAE{LQ@cBe?ZSd)50_^9gAskc8C8!bt7x$$yswO#e7a6n1j8u&v?FW^A_YuxNFsQE6jTukBs rNvc9*C%fm)-!AaTbXY07Px=;%HX@3+u)|*8!zm*>ER9n{7>c5Q+Ic3@ literal 0 HcmV?d00001 diff --git a/Package/Cactus_S4AP (package source)/220557DA!00000000!0E566BE2CD18DAFC.Norwegian Nynorsk .StringTable b/Package/Cactus_S4AP (package source)/220557DA!00000000!0E566BE2CD18DAFC.Norwegian Nynorsk .StringTable new file mode 100644 index 0000000000000000000000000000000000000000..74712d49ee73c9c8d69de0c890299282755f6db8 GIT binary patch literal 785 zcmZuvPe>L)9Q{>vDooP~FR=$ff(p{gQwIgf;FF@QgQps1=i42=*_mZ#_WO3hs}Thq zx@1L2c%=W?W};L5qeV&%9E%9t}AGfg8#iR4Sux1ek1^u7zfr=SzA5|wi7 z)C5LW%1l4B(#4VrgwDt) zNG-KKgYKIU*;Yss!GxdVm!9o;3x_O@MM%6HJu}+>xoe$v1PG<1*xkOIhd%xS(U=n;;_zNA@+vK6xn!MTgvkpfsC{0+R6{dt^ zV#$S-uWj=-*)0N-R_T-xEJUMxfX!D2*Wj4teG$u$=>OTrbE{8xOF3Xt-ua=YO&OVT zooY^$vWBx0&*$NAE{LQ@cBe?ZSd)50_^9gAskc8C8!bt7x$$yswO#e7a6n1j8u&v?FW^A_YuxNFsQE6jTukBs rNvc9*C%fm)-!AaTbXY07Px=;%HX@3+u)|*8!zm*>ER9n{7>c5Q+Ic3@ literal 0 HcmV?d00001 diff --git a/Package/Cactus_S4AP (package source)/220557DA!00000000!0F566BE2CD18DAFC.Polish .StringTable b/Package/Cactus_S4AP (package source)/220557DA!00000000!0F566BE2CD18DAFC.Polish .StringTable new file mode 100644 index 0000000000000000000000000000000000000000..74712d49ee73c9c8d69de0c890299282755f6db8 GIT binary patch literal 785 zcmZuvPe>L)9Q{>vDooP~FR=$ff(p{gQwIgf;FF@QgQps1=i42=*_mZ#_WO3hs}Thq zx@1L2c%=W?W};L5qeV&%9E%9t}AGfg8#iR4Sux1ek1^u7zfr=SzA5|wi7 z)C5LW%1l4B(#4VrgwDt) zNG-KKgYKIU*;Yss!GxdVm!9o;3x_O@MM%6HJu}+>xoe$v1PG<1*xkOIhd%xS(U=n;;_zNA@+vK6xn!MTgvkpfsC{0+R6{dt^ zV#$S-uWj=-*)0N-R_T-xEJUMxfX!D2*Wj4teG$u$=>OTrbE{8xOF3Xt-ua=YO&OVT zooY^$vWBx0&*$NAE{LQ@cBe?ZSd)50_^9gAskc8C8!bt7x$$yswO#e7a6n1j8u&v?FW^A_YuxNFsQE6jTukBs rNvc9*C%fm)-!AaTbXY07Px=;%HX@3+u)|*8!zm*>ER9n{7>c5Q+Ic3@ literal 0 HcmV?d00001 diff --git a/Package/Cactus_S4AP (package source)/220557DA!00000000!10566BE2CD18DAFC.Unknown.StringTable b/Package/Cactus_S4AP (package source)/220557DA!00000000!10566BE2CD18DAFC.Unknown.StringTable new file mode 100644 index 0000000000000000000000000000000000000000..74712d49ee73c9c8d69de0c890299282755f6db8 GIT binary patch literal 785 zcmZuvPe>L)9Q{>vDooP~FR=$ff(p{gQwIgf;FF@QgQps1=i42=*_mZ#_WO3hs}Thq zx@1L2c%=W?W};L5qeV&%9E%9t}AGfg8#iR4Sux1ek1^u7zfr=SzA5|wi7 z)C5LW%1l4B(#4VrgwDt) zNG-KKgYKIU*;Yss!GxdVm!9o;3x_O@MM%6HJu}+>xoe$v1PG<1*xkOIhd%xS(U=n;;_zNA@+vK6xn!MTgvkpfsC{0+R6{dt^ zV#$S-uWj=-*)0N-R_T-xEJUMxfX!D2*Wj4teG$u$=>OTrbE{8xOF3Xt-ua=YO&OVT zooY^$vWBx0&*$NAE{LQ@cBe?ZSd)50_^9gAskc8C8!bt7x$$yswO#e7a6n1j8u&v?FW^A_YuxNFsQE6jTukBs rNvc9*C%fm)-!AaTbXY07Px=;%HX@3+u)|*8!zm*>ER9n{7>c5Q+Ic3@ literal 0 HcmV?d00001 diff --git a/Package/Cactus_S4AP (package source)/220557DA!00000000!11566BE2CD18DAFC.Portuguese .StringTable b/Package/Cactus_S4AP (package source)/220557DA!00000000!11566BE2CD18DAFC.Portuguese .StringTable new file mode 100644 index 0000000000000000000000000000000000000000..74712d49ee73c9c8d69de0c890299282755f6db8 GIT binary patch literal 785 zcmZuvPe>L)9Q{>vDooP~FR=$ff(p{gQwIgf;FF@QgQps1=i42=*_mZ#_WO3hs}Thq zx@1L2c%=W?W};L5qeV&%9E%9t}AGfg8#iR4Sux1ek1^u7zfr=SzA5|wi7 z)C5LW%1l4B(#4VrgwDt) zNG-KKgYKIU*;Yss!GxdVm!9o;3x_O@MM%6HJu}+>xoe$v1PG<1*xkOIhd%xS(U=n;;_zNA@+vK6xn!MTgvkpfsC{0+R6{dt^ zV#$S-uWj=-*)0N-R_T-xEJUMxfX!D2*Wj4teG$u$=>OTrbE{8xOF3Xt-ua=YO&OVT zooY^$vWBx0&*$NAE{LQ@cBe?ZSd)50_^9gAskc8C8!bt7x$$yswO#e7a6n1j8u&v?FW^A_YuxNFsQE6jTukBs rNvc9*C%fm)-!AaTbXY07Px=;%HX@3+u)|*8!zm*>ER9n{7>c5Q+Ic3@ literal 0 HcmV?d00001 diff --git a/Package/Cactus_S4AP (package source)/220557DA!00000000!12566BE2CD18DAFC.Russian .StringTable b/Package/Cactus_S4AP (package source)/220557DA!00000000!12566BE2CD18DAFC.Russian .StringTable new file mode 100644 index 0000000000000000000000000000000000000000..74712d49ee73c9c8d69de0c890299282755f6db8 GIT binary patch literal 785 zcmZuvPe>L)9Q{>vDooP~FR=$ff(p{gQwIgf;FF@QgQps1=i42=*_mZ#_WO3hs}Thq zx@1L2c%=W?W};L5qeV&%9E%9t}AGfg8#iR4Sux1ek1^u7zfr=SzA5|wi7 z)C5LW%1l4B(#4VrgwDt) zNG-KKgYKIU*;Yss!GxdVm!9o;3x_O@MM%6HJu}+>xoe$v1PG<1*xkOIhd%xS(U=n;;_zNA@+vK6xn!MTgvkpfsC{0+R6{dt^ zV#$S-uWj=-*)0N-R_T-xEJUMxfX!D2*Wj4teG$u$=>OTrbE{8xOF3Xt-ua=YO&OVT zooY^$vWBx0&*$NAE{LQ@cBe?ZSd)50_^9gAskc8C8!bt7x$$yswO#e7a6n1j8u&v?FW^A_YuxNFsQE6jTukBs rNvc9*C%fm)-!AaTbXY07Px=;%HX@3+u)|*8!zm*>ER9n{7>c5Q+Ic3@ literal 0 HcmV?d00001 diff --git a/Package/Cactus_S4AP (package source)/220557DA!00000000!13566BE2CD18DAFC.Spanish .StringTable b/Package/Cactus_S4AP (package source)/220557DA!00000000!13566BE2CD18DAFC.Spanish .StringTable new file mode 100644 index 0000000000000000000000000000000000000000..74712d49ee73c9c8d69de0c890299282755f6db8 GIT binary patch literal 785 zcmZuvPe>L)9Q{>vDooP~FR=$ff(p{gQwIgf;FF@QgQps1=i42=*_mZ#_WO3hs}Thq zx@1L2c%=W?W};L5qeV&%9E%9t}AGfg8#iR4Sux1ek1^u7zfr=SzA5|wi7 z)C5LW%1l4B(#4VrgwDt) zNG-KKgYKIU*;Yss!GxdVm!9o;3x_O@MM%6HJu}+>xoe$v1PG<1*xkOIhd%xS(U=n;;_zNA@+vK6xn!MTgvkpfsC{0+R6{dt^ zV#$S-uWj=-*)0N-R_T-xEJUMxfX!D2*Wj4teG$u$=>OTrbE{8xOF3Xt-ua=YO&OVT zooY^$vWBx0&*$NAE{LQ@cBe?ZSd)50_^9gAskc8C8!bt7x$$yswO#e7a6n1j8u&v?FW^A_YuxNFsQE6jTukBs rNvc9*C%fm)-!AaTbXY07Px=;%HX@3+u)|*8!zm*>ER9n{7>c5Q+Ic3@ literal 0 HcmV?d00001 diff --git a/Package/Cactus_S4AP (package source)/220557DA!00000000!15566BE2CD18DAFC.Swedish .StringTable b/Package/Cactus_S4AP (package source)/220557DA!00000000!15566BE2CD18DAFC.Swedish .StringTable new file mode 100644 index 0000000000000000000000000000000000000000..74712d49ee73c9c8d69de0c890299282755f6db8 GIT binary patch literal 785 zcmZuvPe>L)9Q{>vDooP~FR=$ff(p{gQwIgf;FF@QgQps1=i42=*_mZ#_WO3hs}Thq zx@1L2c%=W?W};L5qeV&%9E%9t}AGfg8#iR4Sux1ek1^u7zfr=SzA5|wi7 z)C5LW%1l4B(#4VrgwDt) zNG-KKgYKIU*;Yss!GxdVm!9o;3x_O@MM%6HJu}+>xoe$v1PG<1*xkOIhd%xS(U=n;;_zNA@+vK6xn!MTgvkpfsC{0+R6{dt^ zV#$S-uWj=-*)0N-R_T-xEJUMxfX!D2*Wj4teG$u$=>OTrbE{8xOF3Xt-ua=YO&OVT zooY^$vWBx0&*$NAE{LQ@cBe?ZSd)50_^9gAskc8C8!bt7x$$yswO#e7a6n1j8u&v?FW^A_YuxNFsQE6jTukBs rNvc9*C%fm)-!AaTbXY07Px=;%HX@3+u)|*8!zm*>ER9n{7>c5Q+Ic3@ literal 0 HcmV?d00001 diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!0000000088B5FBB8.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!0000000088B5FBB8.Constructor.SimData.xml new file mode 100644 index 0000000..7cd75cd --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!0000000088B5FBB8.Constructor.SimData.xml @@ -0,0 +1,31 @@ + + + + + FD04E3BE-00000000-8AF8B916CF64C646 + FD04E3BE-00000000-3BF33216A25546EA + 0x00000000 + 0x00000000 + 00B2D882-00000000-30F0846C783606F9 + 0 + 0 + 0x00000000 + 1 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!0000000089032333.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!0000000089032333.Constructor.SimData.xml new file mode 100644 index 0000000..7cd75cd --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!0000000089032333.Constructor.SimData.xml @@ -0,0 +1,31 @@ + + + + + FD04E3BE-00000000-8AF8B916CF64C646 + FD04E3BE-00000000-3BF33216A25546EA + 0x00000000 + 0x00000000 + 00B2D882-00000000-30F0846C783606F9 + 0 + 0 + 0x00000000 + 1 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!000000008A606580.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!000000008A606580.Constructor.SimData.xml new file mode 100644 index 0000000..7cd75cd --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!000000008A606580.Constructor.SimData.xml @@ -0,0 +1,31 @@ + + + + + FD04E3BE-00000000-8AF8B916CF64C646 + FD04E3BE-00000000-3BF33216A25546EA + 0x00000000 + 0x00000000 + 00B2D882-00000000-30F0846C783606F9 + 0 + 0 + 0x00000000 + 1 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!000000008E00A8E2.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!000000008E00A8E2.Constructor.SimData.xml new file mode 100644 index 0000000..7cd75cd --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!000000008E00A8E2.Constructor.SimData.xml @@ -0,0 +1,31 @@ + + + + + FD04E3BE-00000000-8AF8B916CF64C646 + FD04E3BE-00000000-3BF33216A25546EA + 0x00000000 + 0x00000000 + 00B2D882-00000000-30F0846C783606F9 + 0 + 0 + 0x00000000 + 1 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000942950EC.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000942950EC.Constructor.SimData.xml new file mode 100644 index 0000000..7cd75cd --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000942950EC.Constructor.SimData.xml @@ -0,0 +1,31 @@ + + + + + FD04E3BE-00000000-8AF8B916CF64C646 + FD04E3BE-00000000-3BF33216A25546EA + 0x00000000 + 0x00000000 + 00B2D882-00000000-30F0846C783606F9 + 0 + 0 + 0x00000000 + 1 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000ACEC4762.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000ACEC4762.Constructor.SimData.xml new file mode 100644 index 0000000..7cd75cd --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000ACEC4762.Constructor.SimData.xml @@ -0,0 +1,31 @@ + + + + + FD04E3BE-00000000-8AF8B916CF64C646 + FD04E3BE-00000000-3BF33216A25546EA + 0x00000000 + 0x00000000 + 00B2D882-00000000-30F0846C783606F9 + 0 + 0 + 0x00000000 + 1 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000B0C1684A.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000B0C1684A.Constructor.SimData.xml new file mode 100644 index 0000000..7cd75cd --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000B0C1684A.Constructor.SimData.xml @@ -0,0 +1,31 @@ + + + + + FD04E3BE-00000000-8AF8B916CF64C646 + FD04E3BE-00000000-3BF33216A25546EA + 0x00000000 + 0x00000000 + 00B2D882-00000000-30F0846C783606F9 + 0 + 0 + 0x00000000 + 1 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000B4713A54.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000B4713A54.Constructor.SimData.xml new file mode 100644 index 0000000..7cd75cd --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000B4713A54.Constructor.SimData.xml @@ -0,0 +1,31 @@ + + + + + FD04E3BE-00000000-8AF8B916CF64C646 + FD04E3BE-00000000-3BF33216A25546EA + 0x00000000 + 0x00000000 + 00B2D882-00000000-30F0846C783606F9 + 0 + 0 + 0x00000000 + 1 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000B629BB49.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000B629BB49.Constructor.SimData.xml new file mode 100644 index 0000000..7cd75cd --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000B629BB49.Constructor.SimData.xml @@ -0,0 +1,31 @@ + + + + + FD04E3BE-00000000-8AF8B916CF64C646 + FD04E3BE-00000000-3BF33216A25546EA + 0x00000000 + 0x00000000 + 00B2D882-00000000-30F0846C783606F9 + 0 + 0 + 0x00000000 + 1 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000BB971053.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000BB971053.Constructor.SimData.xml new file mode 100644 index 0000000..7cd75cd --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000BB971053.Constructor.SimData.xml @@ -0,0 +1,31 @@ + + + + + FD04E3BE-00000000-8AF8B916CF64C646 + FD04E3BE-00000000-3BF33216A25546EA + 0x00000000 + 0x00000000 + 00B2D882-00000000-30F0846C783606F9 + 0 + 0 + 0x00000000 + 1 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000C8D1ECF5.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000C8D1ECF5.Constructor.SimData.xml new file mode 100644 index 0000000..7cd75cd --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000C8D1ECF5.Constructor.SimData.xml @@ -0,0 +1,31 @@ + + + + + FD04E3BE-00000000-8AF8B916CF64C646 + FD04E3BE-00000000-3BF33216A25546EA + 0x00000000 + 0x00000000 + 00B2D882-00000000-30F0846C783606F9 + 0 + 0 + 0x00000000 + 1 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000D037694E.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000D037694E.Constructor.SimData.xml new file mode 100644 index 0000000..7cd75cd --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000D037694E.Constructor.SimData.xml @@ -0,0 +1,31 @@ + + + + + FD04E3BE-00000000-8AF8B916CF64C646 + FD04E3BE-00000000-3BF33216A25546EA + 0x00000000 + 0x00000000 + 00B2D882-00000000-30F0846C783606F9 + 0 + 0 + 0x00000000 + 1 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000D51559C9.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000D51559C9.Constructor.SimData.xml new file mode 100644 index 0000000..7cd75cd --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000D51559C9.Constructor.SimData.xml @@ -0,0 +1,31 @@ + + + + + FD04E3BE-00000000-8AF8B916CF64C646 + FD04E3BE-00000000-3BF33216A25546EA + 0x00000000 + 0x00000000 + 00B2D882-00000000-30F0846C783606F9 + 0 + 0 + 0x00000000 + 1 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000D6BFC3D1.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000D6BFC3D1.Constructor.SimData.xml new file mode 100644 index 0000000..7cd75cd --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000D6BFC3D1.Constructor.SimData.xml @@ -0,0 +1,31 @@ + + + + + FD04E3BE-00000000-8AF8B916CF64C646 + FD04E3BE-00000000-3BF33216A25546EA + 0x00000000 + 0x00000000 + 00B2D882-00000000-30F0846C783606F9 + 0 + 0 + 0x00000000 + 1 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000D79B9065.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000D79B9065.Constructor.SimData.xml new file mode 100644 index 0000000..7cd75cd --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000D79B9065.Constructor.SimData.xml @@ -0,0 +1,31 @@ + + + + + FD04E3BE-00000000-8AF8B916CF64C646 + FD04E3BE-00000000-3BF33216A25546EA + 0x00000000 + 0x00000000 + 00B2D882-00000000-30F0846C783606F9 + 0 + 0 + 0x00000000 + 1 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000D888EB85.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000D888EB85.Constructor.SimData.xml new file mode 100644 index 0000000..7cd75cd --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000D888EB85.Constructor.SimData.xml @@ -0,0 +1,31 @@ + + + + + FD04E3BE-00000000-8AF8B916CF64C646 + FD04E3BE-00000000-3BF33216A25546EA + 0x00000000 + 0x00000000 + 00B2D882-00000000-30F0846C783606F9 + 0 + 0 + 0x00000000 + 1 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000DA4F627F.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000DA4F627F.Constructor.SimData.xml new file mode 100644 index 0000000..7cd75cd --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000DA4F627F.Constructor.SimData.xml @@ -0,0 +1,31 @@ + + + + + FD04E3BE-00000000-8AF8B916CF64C646 + FD04E3BE-00000000-3BF33216A25546EA + 0x00000000 + 0x00000000 + 00B2D882-00000000-30F0846C783606F9 + 0 + 0 + 0x00000000 + 1 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000DAF19D9B.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000DAF19D9B.Constructor.SimData.xml new file mode 100644 index 0000000..7cd75cd --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000DAF19D9B.Constructor.SimData.xml @@ -0,0 +1,31 @@ + + + + + FD04E3BE-00000000-8AF8B916CF64C646 + FD04E3BE-00000000-3BF33216A25546EA + 0x00000000 + 0x00000000 + 00B2D882-00000000-30F0846C783606F9 + 0 + 0 + 0x00000000 + 1 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000E330058C.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000E330058C.Constructor.SimData.xml new file mode 100644 index 0000000..7cd75cd --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000E330058C.Constructor.SimData.xml @@ -0,0 +1,31 @@ + + + + + FD04E3BE-00000000-8AF8B916CF64C646 + FD04E3BE-00000000-3BF33216A25546EA + 0x00000000 + 0x00000000 + 00B2D882-00000000-30F0846C783606F9 + 0 + 0 + 0x00000000 + 1 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000E9CA5D38.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000E9CA5D38.Constructor.SimData.xml new file mode 100644 index 0000000..7cd75cd --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000E9CA5D38.Constructor.SimData.xml @@ -0,0 +1,31 @@ + + + + + FD04E3BE-00000000-8AF8B916CF64C646 + FD04E3BE-00000000-3BF33216A25546EA + 0x00000000 + 0x00000000 + 00B2D882-00000000-30F0846C783606F9 + 0 + 0 + 0x00000000 + 1 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000EA1784B3.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000EA1784B3.Constructor.SimData.xml new file mode 100644 index 0000000..7cd75cd --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000EA1784B3.Constructor.SimData.xml @@ -0,0 +1,31 @@ + + + + + FD04E3BE-00000000-8AF8B916CF64C646 + FD04E3BE-00000000-3BF33216A25546EA + 0x00000000 + 0x00000000 + 00B2D882-00000000-30F0846C783606F9 + 0 + 0 + 0x00000000 + 1 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000F3563747.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000F3563747.Constructor.SimData.xml new file mode 100644 index 0000000..7cd75cd --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000F3563747.Constructor.SimData.xml @@ -0,0 +1,31 @@ + + + + + FD04E3BE-00000000-8AF8B916CF64C646 + FD04E3BE-00000000-3BF33216A25546EA + 0x00000000 + 0x00000000 + 00B2D882-00000000-30F0846C783606F9 + 0 + 0 + 0x00000000 + 1 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000F93B00FF.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000F93B00FF.Constructor.SimData.xml new file mode 100644 index 0000000..7cd75cd --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000F93B00FF.Constructor.SimData.xml @@ -0,0 +1,31 @@ + + + + + FD04E3BE-00000000-8AF8B916CF64C646 + FD04E3BE-00000000-3BF33216A25546EA + 0x00000000 + 0x00000000 + 00B2D882-00000000-30F0846C783606F9 + 0 + 0 + 0x00000000 + 1 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000FEB64AAE.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000FEB64AAE.Constructor.SimData.xml new file mode 100644 index 0000000..7cd75cd --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000FEB64AAE.Constructor.SimData.xml @@ -0,0 +1,31 @@ + + + + + FD04E3BE-00000000-8AF8B916CF64C646 + FD04E3BE-00000000-3BF33216A25546EA + 0x00000000 + 0x00000000 + 00B2D882-00000000-30F0846C783606F9 + 0 + 0 + 0x00000000 + 1 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!000000008494610E.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!000000008494610E.Constructor.SimData.xml new file mode 100644 index 0000000..806fe0d --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!000000008494610E.Constructor.SimData.xml @@ -0,0 +1,60 @@ + + + + + + 4 + 8 + 16 + 32 + 64 + 0 + 0 + 0 + + + + 00000000-00000000-0000000000000000 + + 00000000-00000000-0000000000000000 + None + + 0x85F13D03 + + 00B2D882-00000000-30F0846C783606F9 + + 1 + 0 + 0 + + + 0x00000000 + 0x00000000 + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!0000000085944434.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!0000000085944434.Constructor.SimData.xml new file mode 100644 index 0000000..831b410 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!0000000085944434.Constructor.SimData.xml @@ -0,0 +1,60 @@ + + + + + + 4 + 8 + 16 + 32 + 64 + 0 + 0 + 0 + + + + 00000000-00000000-0000000000000000 + + 00000000-00000000-0000000000000000 + None + + 0x8698D66E + + 00B2D882-00000000-30F0846C783606F9 + + 1 + 0 + 0 + + + 0x00000000 + 0x00000000 + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC916.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC916.Constructor.SimData.xml new file mode 100644 index 0000000..1210ba2 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC916.Constructor.SimData.xml @@ -0,0 +1,60 @@ + + + + + + 4 + 8 + 16 + 32 + 64 + 0 + 0 + 0 + + + + 00000000-00000000-0000000000000000 + + 00000000-00000000-0000000000000000 + None + + 0xFDF5799A + + 00B2D882-00000000-30F0846C783606F9 + + 1 + 0 + 0 + + + 0x00000000 + 0x00000000 + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC917.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC917.Constructor.SimData.xml new file mode 100644 index 0000000..212001e --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC917.Constructor.SimData.xml @@ -0,0 +1,60 @@ + + + + + + 4 + 8 + 16 + 32 + 64 + 0 + 0 + 0 + + + + 00000000-00000000-0000000000000000 + + 00000000-00000000-0000000000000000 + None + + 0xF2F9F5BD + + 00B2D882-00000000-30F0846C783606F9 + + 1 + 0 + 0 + + + 0x00000000 + 0x00000000 + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC918.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC918.Constructor.SimData.xml new file mode 100644 index 0000000..409a218 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC918.Constructor.SimData.xml @@ -0,0 +1,60 @@ + + + + + + 4 + 8 + 16 + 32 + 64 + 0 + 0 + 0 + + + + 00000000-00000000-0000000000000000 + + 00000000-00000000-0000000000000000 + None + + 0xF8762C55 + + 00B2D882-00000000-30F0846C783606F9 + + 1 + 0 + 0 + + + 0x00000000 + 0x00000000 + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC919.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC919.Constructor.SimData.xml new file mode 100644 index 0000000..0e976a3 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC919.Constructor.SimData.xml @@ -0,0 +1,60 @@ + + + + + + 4 + 8 + 16 + 32 + 64 + 0 + 0 + 0 + + + + 00000000-00000000-0000000000000000 + + 00000000-00000000-0000000000000000 + None + + 0x8836B113 + + 00B2D882-00000000-30F0846C783606F9 + + 1 + 0 + 0 + + + 0x00000000 + 0x00000000 + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91A.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91A.Constructor.SimData.xml new file mode 100644 index 0000000..9f6fffd --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91A.Constructor.SimData.xml @@ -0,0 +1,60 @@ + + + + + + 4 + 8 + 16 + 32 + 64 + 0 + 0 + 0 + + + + 00000000-00000000-0000000000000000 + + 00000000-00000000-0000000000000000 + None + + 0x92619FF2 + + 00B2D882-00000000-30F0846C783606F9 + + 1 + 0 + 0 + + + 0x00000000 + 0x00000000 + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91B.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91B.Constructor.SimData.xml new file mode 100644 index 0000000..a839dfd --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91B.Constructor.SimData.xml @@ -0,0 +1,60 @@ + + + + + + 4 + 8 + 16 + 32 + 64 + 0 + 0 + 0 + + + + 00000000-00000000-0000000000000000 + + 00000000-00000000-0000000000000000 + None + + 0xDBE5EAB6 + + 00B2D882-00000000-30F0846C783606F9 + + 1 + 0 + 0 + + + 0x00000000 + 0x00000000 + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91C.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91C.Constructor.SimData.xml new file mode 100644 index 0000000..f4162db --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91C.Constructor.SimData.xml @@ -0,0 +1,60 @@ + + + + + + 4 + 8 + 16 + 32 + 64 + 0 + 0 + 0 + + + + 00000000-00000000-0000000000000000 + + 00000000-00000000-0000000000000000 + None + + 0xD8E6D160 + + 00B2D882-00000000-30F0846C783606F9 + + 1 + 0 + 0 + + + 0x00000000 + 0x00000000 + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91D.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91D.Constructor.SimData.xml new file mode 100644 index 0000000..71f4e1e --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91D.Constructor.SimData.xml @@ -0,0 +1,60 @@ + + + + + + 4 + 8 + 16 + 32 + 64 + 0 + 0 + 0 + + + + 00000000-00000000-0000000000000000 + + 00000000-00000000-0000000000000000 + None + + 0xEA0CB8F8 + + 00B2D882-00000000-30F0846C783606F9 + + 1 + 0 + 0 + + + 0x00000000 + 0x00000000 + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91E.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91E.Constructor.SimData.xml new file mode 100644 index 0000000..6ef1b7c --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91E.Constructor.SimData.xml @@ -0,0 +1,60 @@ + + + + + + 4 + 8 + 16 + 32 + 64 + 0 + 0 + 0 + + + + 00000000-00000000-0000000000000000 + + 00000000-00000000-0000000000000000 + None + + 0xB5B059A3 + + 00B2D882-00000000-30F0846C783606F9 + + 1 + 0 + 0 + + + 0x00000000 + 0x00000000 + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91F.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91F.Constructor.SimData.xml new file mode 100644 index 0000000..c0fd4be --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91F.Constructor.SimData.xml @@ -0,0 +1,60 @@ + + + + + + 4 + 8 + 16 + 32 + 64 + 0 + 0 + 0 + + + + 00000000-00000000-0000000000000000 + + 00000000-00000000-0000000000000000 + None + + 0x9874E78A + + 00B2D882-00000000-30F0846C783606F9 + + 1 + 0 + 0 + + + 0x00000000 + 0x00000000 + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF0.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF0.Constructor.SimData.xml new file mode 100644 index 0000000..988a803 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF0.Constructor.SimData.xml @@ -0,0 +1,60 @@ + + + + + + 4 + 8 + 16 + 32 + 64 + 0 + 0 + 0 + + + + 00000000-00000000-0000000000000000 + + 00000000-00000000-0000000000000000 + None + + 0xC88E7C72 + + 00B2D882-00000000-30F0846C783606F9 + + 1 + 0 + 0 + + + 0x00000000 + 0x00000000 + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF1.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF1.Constructor.SimData.xml new file mode 100644 index 0000000..abe0a01 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF1.Constructor.SimData.xml @@ -0,0 +1,60 @@ + + + + + + 4 + 8 + 16 + 32 + 64 + 0 + 0 + 0 + + + + 00000000-00000000-0000000000000000 + + 00000000-00000000-0000000000000000 + None + + 0x97101441 + + 00B2D882-00000000-30F0846C783606F9 + + 1 + 0 + 0 + + + 0x00000000 + 0x00000000 + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF2.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF2.Constructor.SimData.xml new file mode 100644 index 0000000..e3215b6 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF2.Constructor.SimData.xml @@ -0,0 +1,60 @@ + + + + + + 4 + 8 + 16 + 32 + 64 + 0 + 0 + 0 + + + + 00000000-00000000-0000000000000000 + + 00000000-00000000-0000000000000000 + None + + 0xCDDB6620 + + 00B2D882-00000000-30F0846C783606F9 + + 1 + 0 + 0 + + + 0x00000000 + 0x00000000 + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF3.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF3.Constructor.SimData.xml new file mode 100644 index 0000000..7a9f9ce --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF3.Constructor.SimData.xml @@ -0,0 +1,60 @@ + + + + + + 4 + 8 + 16 + 32 + 64 + 0 + 0 + 0 + + + + 00000000-00000000-0000000000000000 + + 00000000-00000000-0000000000000000 + None + + 0xC97977CA + + 00B2D882-00000000-30F0846C783606F9 + + 1 + 0 + 0 + + + 0x00000000 + 0x00000000 + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF4.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF4.Constructor.SimData.xml new file mode 100644 index 0000000..c46748e --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF4.Constructor.SimData.xml @@ -0,0 +1,60 @@ + + + + + + 4 + 8 + 16 + 32 + 64 + 0 + 0 + 0 + + + + 00000000-00000000-0000000000000000 + + 00000000-00000000-0000000000000000 + None + + 0xB2D63767 + + 00B2D882-00000000-30F0846C783606F9 + + 1 + 0 + 0 + + + 0x00000000 + 0x00000000 + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF6.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF6.Constructor.SimData.xml new file mode 100644 index 0000000..ab59efb --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF6.Constructor.SimData.xml @@ -0,0 +1,60 @@ + + + + + + 4 + 8 + 16 + 32 + 64 + 0 + 0 + 0 + + + + 00000000-00000000-0000000000000000 + + 00000000-00000000-0000000000000000 + None + + 0xE8455F9F + + 00B2D882-00000000-30F0846C783606F9 + + 1 + 0 + 0 + + + 0x00000000 + 0x00000000 + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D301A22C.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D301A22C.Constructor.SimData.xml new file mode 100644 index 0000000..1de34e9 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D301A22C.Constructor.SimData.xml @@ -0,0 +1,60 @@ + + + + + + 4 + 8 + 16 + 32 + 64 + 0 + 0 + 0 + + + + 00000000-00000000-0000000000000000 + + 00000000-00000000-0000000000000000 + None + + 0xBE01AC49 + + 00B2D882-00000000-30F0846C783606F9 + + 1 + 0 + 0 + + + 0x00000000 + 0x00000000 + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B70.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B70.Constructor.SimData.xml new file mode 100644 index 0000000..3bc18ba --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B70.Constructor.SimData.xml @@ -0,0 +1,60 @@ + + + + + + 4 + 8 + 16 + 32 + 64 + 0 + 0 + 0 + + + + 00000000-00000000-0000000000000000 + + 00000000-00000000-0000000000000000 + None + + 0xA1E5B19B + + 00B2D882-00000000-30F0846C783606F9 + + 1 + 0 + 0 + + + 0x00000000 + 0x00000000 + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B71.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B71.Constructor.SimData.xml new file mode 100644 index 0000000..9e2be1a --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B71.Constructor.SimData.xml @@ -0,0 +1,60 @@ + + + + + + 4 + 8 + 16 + 32 + 64 + 0 + 0 + 0 + + + + 00000000-00000000-0000000000000000 + + 00000000-00000000-0000000000000000 + None + + 0xC9249D53 + + 00B2D882-00000000-30F0846C783606F9 + + 1 + 0 + 0 + + + 0x00000000 + 0x00000000 + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B72.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B72.Constructor.SimData.xml new file mode 100644 index 0000000..a36a941 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B72.Constructor.SimData.xml @@ -0,0 +1,60 @@ + + + + + + 4 + 8 + 16 + 32 + 64 + 0 + 0 + 0 + + + + 00000000-00000000-0000000000000000 + + 00000000-00000000-0000000000000000 + None + + 0xE3298B37 + + 00B2D882-00000000-30F0846C783606F9 + + 1 + 0 + 0 + + + 0x00000000 + 0x00000000 + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B73.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B73.Constructor.SimData.xml new file mode 100644 index 0000000..4ad65a9 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B73.Constructor.SimData.xml @@ -0,0 +1,60 @@ + + + + + + 4 + 8 + 16 + 32 + 64 + 0 + 0 + 0 + + + + 00000000-00000000-0000000000000000 + + 00000000-00000000-0000000000000000 + None + + 0xDD6F11B5 + + 00B2D882-00000000-30F0846C783606F9 + + 1 + 0 + 0 + + + 0x00000000 + 0x00000000 + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B76.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B76.Constructor.SimData.xml new file mode 100644 index 0000000..8eb5e3a --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B76.Constructor.SimData.xml @@ -0,0 +1,60 @@ + + + + + + 4 + 8 + 16 + 32 + 64 + 0 + 0 + 0 + + + + 00000000-00000000-0000000000000000 + + 00000000-00000000-0000000000000000 + None + + 0xB9274531 + + 00B2D882-00000000-30F0846C783606F9 + + 1 + 0 + 0 + + + 0x00000000 + 0x00000000 + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B77.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B77.Constructor.SimData.xml new file mode 100644 index 0000000..5453c65 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B77.Constructor.SimData.xml @@ -0,0 +1,60 @@ + + + + + + 4 + 8 + 16 + 32 + 64 + 0 + 0 + 0 + + + + 00000000-00000000-0000000000000000 + + 00000000-00000000-0000000000000000 + None + + 0xFBBCD468 + + 00B2D882-00000000-30F0846C783606F9 + + 1 + 0 + 0 + + + 0x00000000 + 0x00000000 + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B7C.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B7C.Constructor.SimData.xml new file mode 100644 index 0000000..0dab6bb --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B7C.Constructor.SimData.xml @@ -0,0 +1,60 @@ + + + + + + 4 + 8 + 16 + 32 + 64 + 0 + 0 + 0 + + + + 00000000-00000000-0000000000000000 + + 00000000-00000000-0000000000000000 + None + + 0xDBD7E3BC + + 00B2D882-00000000-30F0846C783606F9 + + 1 + 0 + 0 + + + 0x00000000 + 0x00000000 + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B7D.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B7D.Constructor.SimData.xml new file mode 100644 index 0000000..446f402 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B7D.Constructor.SimData.xml @@ -0,0 +1,60 @@ + + + + + + 4 + 8 + 16 + 32 + 64 + 0 + 0 + 0 + + + + 00000000-00000000-0000000000000000 + + 00000000-00000000-0000000000000000 + None + + 0xDDFC2DE9 + + 00B2D882-00000000-30F0846C783606F9 + + 1 + 0 + 0 + + + 0x00000000 + 0x00000000 + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!00E9D967!00000000A85DB38B.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!00E9D967!00000000A85DB38B.Constructor.SimData.xml new file mode 100644 index 0000000..dd1b0f4 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!00E9D967!00000000A85DB38B.Constructor.SimData.xml @@ -0,0 +1,27 @@ + + + + + 0 + 0x85992464 + 0 + 00B2D882-00000000-F1C680E09B12C2B6 + 0 + 0 + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!0000000088B5FBB8.Cactus_S4AP_Trait21:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!0000000088B5FBB8.Cactus_S4AP_Trait21:Buff.BuffTuning.xml new file mode 100644 index 0000000..86ce2db --- /dev/null +++ b/Package/Cactus_S4AP (package source)/6017E896!00000000!0000000088B5FBB8.Cactus_S4AP_Trait21:Buff.BuffTuning.xml @@ -0,0 +1,21 @@ + + + + + + + + + 105774 + + INCREASE + 0 + + + + + + + + False + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!0000000089032333.Cactus_S4AP_Trait24:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!0000000089032333.Cactus_S4AP_Trait24:Buff.BuffTuning.xml new file mode 100644 index 0000000..122785c --- /dev/null +++ b/Package/Cactus_S4AP (package source)/6017E896!00000000!0000000089032333.Cactus_S4AP_Trait24:Buff.BuffTuning.xml @@ -0,0 +1,18 @@ + + + + + + + + + Skill_All + 4 + + + + + + + False + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!000000008A606580.Cactus_S4AP_Trait14:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!000000008A606580.Cactus_S4AP_Trait14:Buff.BuffTuning.xml new file mode 100644 index 0000000..d243ad4 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/6017E896!00000000!000000008A606580.Cactus_S4AP_Trait14:Buff.BuffTuning.xml @@ -0,0 +1,21 @@ + + + + + + + + + 16707 + + INCREASE + 0 + + + + + + + + False + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!000000008E00A8E2.Cactus_S4AP_Trait5:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!000000008E00A8E2.Cactus_S4AP_Trait5:Buff.BuffTuning.xml new file mode 100644 index 0000000..d846435 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/6017E896!00000000!000000008E00A8E2.Cactus_S4AP_Trait5:Buff.BuffTuning.xml @@ -0,0 +1,21 @@ + + + + + + + + + 16709 + + INCREASE + 0 + + + + + + + + False + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000942950EC.Cactus_S4AP_Trait3:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000942950EC.Cactus_S4AP_Trait3:Buff.BuffTuning.xml new file mode 100644 index 0000000..650e159 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000942950EC.Cactus_S4AP_Trait3:Buff.BuffTuning.xml @@ -0,0 +1,21 @@ + + + + + + + + + 16706 + + INCREASE + 0 + + + + + + + + False + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000ACEC4762.Cactus_S4AP_Trait23:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000ACEC4762.Cactus_S4AP_Trait23:Buff.BuffTuning.xml new file mode 100644 index 0000000..8c0c634 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000ACEC4762.Cactus_S4AP_Trait23:Buff.BuffTuning.xml @@ -0,0 +1,18 @@ + + + + + + + + + Skill_All + 3.5 + + + + + + + False + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000B0C1684A.Cactus_S4AP_Trait16:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000B0C1684A.Cactus_S4AP_Trait16:Buff.BuffTuning.xml new file mode 100644 index 0000000..af45d16 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000B0C1684A.Cactus_S4AP_Trait16:Buff.BuffTuning.xml @@ -0,0 +1,21 @@ + + + + + + + + + 16708 + + INCREASE + 0 + + + + + + + + False + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000B4713A54.Cactus_S4AP_Trait10:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000B4713A54.Cactus_S4AP_Trait10:Buff.BuffTuning.xml new file mode 100644 index 0000000..44115f5 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000B4713A54.Cactus_S4AP_Trait10:Buff.BuffTuning.xml @@ -0,0 +1,21 @@ + + + + + + + + + 16659 + + INCREASE + 0 + + + + + + + + False + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000B629BB49.Cactus_S4AP_Trait4:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000B629BB49.Cactus_S4AP_Trait4:Buff.BuffTuning.xml new file mode 100644 index 0000000..c815dec --- /dev/null +++ b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000B629BB49.Cactus_S4AP_Trait4:Buff.BuffTuning.xml @@ -0,0 +1,18 @@ + + + + + + + + + Skill_All + 2.5 + + + + + + + False + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000BB971053.Cactus_S4AP_Trait19:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000BB971053.Cactus_S4AP_Trait19:Buff.BuffTuning.xml new file mode 100644 index 0000000..821728d --- /dev/null +++ b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000BB971053.Cactus_S4AP_Trait19:Buff.BuffTuning.xml @@ -0,0 +1,21 @@ + + + + + + + + + 16712 + + INCREASE + 0 + + + + + + + + False + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000C8D1ECF5.Cactus_S4AP_Trait:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000C8D1ECF5.Cactus_S4AP_Trait:Buff.BuffTuning.xml new file mode 100644 index 0000000..fb56119 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000C8D1ECF5.Cactus_S4AP_Trait:Buff.BuffTuning.xml @@ -0,0 +1,21 @@ + + + + + + + + + 16698 + + INCREASE + 0 + + + + + + + + False + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D037694E.Cactus_S4AP_Trait12:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D037694E.Cactus_S4AP_Trait12:Buff.BuffTuning.xml new file mode 100644 index 0000000..a8e7ce2 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D037694E.Cactus_S4AP_Trait12:Buff.BuffTuning.xml @@ -0,0 +1,21 @@ + + + + + + + + + 16701 + + INCREASE + 0 + + + + + + + + False + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D51559C9.Cactus_S4AP_Trait22:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D51559C9.Cactus_S4AP_Trait22:Buff.BuffTuning.xml new file mode 100644 index 0000000..c3d6ef8 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D51559C9.Cactus_S4AP_Trait22:Buff.BuffTuning.xml @@ -0,0 +1,18 @@ + + + + + + + + + Skill_All + 3 + + + + + + + False + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D6BFC3D1.Cactus_S4AP_Trait17:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D6BFC3D1.Cactus_S4AP_Trait17:Buff.BuffTuning.xml new file mode 100644 index 0000000..8903995 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D6BFC3D1.Cactus_S4AP_Trait17:Buff.BuffTuning.xml @@ -0,0 +1,21 @@ + + + + + + + + + 16703 + + INCREASE + 0 + + + + + + + + False + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D79B9065.Cactus_S4AP_Trait8:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D79B9065.Cactus_S4AP_Trait8:Buff.BuffTuning.xml new file mode 100644 index 0000000..5b3024f --- /dev/null +++ b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D79B9065.Cactus_S4AP_Trait8:Buff.BuffTuning.xml @@ -0,0 +1,21 @@ + + + + + + + + + 16705 + + INCREASE + 0 + + + + + + + + False + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D888EB85.Cactus_S4AP_Trait13:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D888EB85.Cactus_S4AP_Trait13:Buff.BuffTuning.xml new file mode 100644 index 0000000..a141395 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D888EB85.Cactus_S4AP_Trait13:Buff.BuffTuning.xml @@ -0,0 +1,21 @@ + + + + + + + + + 16704 + + INCREASE + 0 + + + + + + + + False + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000DA4F627F.Cactus_S4AP_Trait6:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000DA4F627F.Cactus_S4AP_Trait6:Buff.BuffTuning.xml new file mode 100644 index 0000000..334f68c --- /dev/null +++ b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000DA4F627F.Cactus_S4AP_Trait6:Buff.BuffTuning.xml @@ -0,0 +1,21 @@ + + + + + + + + + 16713 + + INCREASE + 0 + + + + + + + + False + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000DAF19D9B.Cactus_S4AP_Trait11:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000DAF19D9B.Cactus_S4AP_Trait11:Buff.BuffTuning.xml new file mode 100644 index 0000000..8488d81 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000DAF19D9B.Cactus_S4AP_Trait11:Buff.BuffTuning.xml @@ -0,0 +1,21 @@ + + + + + + + + + 16700 + + INCREASE + 0 + + + + + + + + False + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000E330058C.Cactus_S4AP_Trait18:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000E330058C.Cactus_S4AP_Trait18:Buff.BuffTuning.xml new file mode 100644 index 0000000..21eae92 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000E330058C.Cactus_S4AP_Trait18:Buff.BuffTuning.xml @@ -0,0 +1,21 @@ + + + + + + + + + 16710 + + INCREASE + 0 + + + + + + + + False + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000E9CA5D38.Cactus_S4AP_Trait7:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000E9CA5D38.Cactus_S4AP_Trait7:Buff.BuffTuning.xml new file mode 100644 index 0000000..f61e716 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000E9CA5D38.Cactus_S4AP_Trait7:Buff.BuffTuning.xml @@ -0,0 +1,21 @@ + + + + + + + + + 16699 + + INCREASE + 0 + + + + + + + + False + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000EA1784B3.Cactus_S4AP_Trait2:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000EA1784B3.Cactus_S4AP_Trait2:Buff.BuffTuning.xml new file mode 100644 index 0000000..2baf427 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000EA1784B3.Cactus_S4AP_Trait2:Buff.BuffTuning.xml @@ -0,0 +1,21 @@ + + + + + + + + + 16702 + + INCREASE + 0 + + + + + + + + False + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000F3563747.Cactus_S4AP_Trait15:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000F3563747.Cactus_S4AP_Trait15:Buff.BuffTuning.xml new file mode 100644 index 0000000..a52f0b9 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000F3563747.Cactus_S4AP_Trait15:Buff.BuffTuning.xml @@ -0,0 +1,21 @@ + + + + + + + + + 16695 + + INCREASE + 0 + + + + + + + + False + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000F93B00FF.Cactus_S4AP_Trait20:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000F93B00FF.Cactus_S4AP_Trait20:Buff.BuffTuning.xml new file mode 100644 index 0000000..f9dc0a1 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000F93B00FF.Cactus_S4AP_Trait20:Buff.BuffTuning.xml @@ -0,0 +1,21 @@ + + + + + + + + + 16714 + + INCREASE + 0 + + + + + + + + False + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000FEB64AAE.Cactus_S4AP_Trait9:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000FEB64AAE.Cactus_S4AP_Trait9:Buff.BuffTuning.xml new file mode 100644 index 0000000..621a979 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000FEB64AAE.Cactus_S4AP_Trait9:Buff.BuffTuning.xml @@ -0,0 +1,21 @@ + + + + + + + + + 39397 + + INCREASE + 0 + + + + + + + + False + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!000000008494610E.Cactus_S4AP_ResyncLocations.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!000000008494610E.Cactus_S4AP_ResyncLocations.TraitTuning.xml new file mode 100644 index 0000000..5d608f1 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!000000008494610E.Cactus_S4AP_ResyncLocations.TraitTuning.xml @@ -0,0 +1,14 @@ + + + 0x85F13D03 + + ADULT + CHILD + ELDER + TEEN + YOUNGADULT + + 2f7d0004:00000000:30f0846c783606f9 + 0x85F13D03 + HIDDEN + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!0000000085944434.Cactus_S4AP_ShowYamlOptions.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!0000000085944434.Cactus_S4AP_ShowYamlOptions.TraitTuning.xml new file mode 100644 index 0000000..f07f9a1 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!0000000085944434.Cactus_S4AP_ShowYamlOptions.TraitTuning.xml @@ -0,0 +1,14 @@ + + + 0x8698D66E + + ADULT + CHILD + ELDER + TEEN + YOUNGADULT + + 2f7d0004:00000000:30f0846c783606f9 + 0x8698D66E + HIDDEN + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC916.Cactus_S4AP_Trait19.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC916.Cactus_S4AP_Trait19.TraitTuning.xml new file mode 100644 index 0000000..fb429e6 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC916.Cactus_S4AP_Trait19.TraitTuning.xml @@ -0,0 +1,19 @@ + + + 0xFDF5799A + + ADULT + CHILD + ELDER + TEEN + YOUNGADULT + + 2f7d0004:00000000:30f0846c783606f9 + 0xFDF5799A + HIDDEN + + + 3147239507 + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC917.Cactus_S4AP_Trait18.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC917.Cactus_S4AP_Trait18.TraitTuning.xml new file mode 100644 index 0000000..50554cb --- /dev/null +++ b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC917.Cactus_S4AP_Trait18.TraitTuning.xml @@ -0,0 +1,19 @@ + + + 0xF2F9F5BD + + ADULT + CHILD + ELDER + TEEN + YOUNGADULT + + 2f7d0004:00000000:30f0846c783606f9 + 0xF2F9F5BD + HIDDEN + + + 3811575180 + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC918.Cactus_S4AP_Trait17.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC918.Cactus_S4AP_Trait17.TraitTuning.xml new file mode 100644 index 0000000..bf106b3 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC918.Cactus_S4AP_Trait17.TraitTuning.xml @@ -0,0 +1,19 @@ + + + 0xF8762C55 + + ADULT + CHILD + ELDER + TEEN + YOUNGADULT + + 2f7d0004:00000000:30f0846c783606f9 + 0xF8762C55 + HIDDEN + + + 3602891729 + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC919.Cactus_S4AP_Trait16.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC919.Cactus_S4AP_Trait16.TraitTuning.xml new file mode 100644 index 0000000..4a637ce --- /dev/null +++ b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC919.Cactus_S4AP_Trait16.TraitTuning.xml @@ -0,0 +1,19 @@ + + + 0x8836B113 + + ADULT + CHILD + ELDER + TEEN + YOUNGADULT + + 2f7d0004:00000000:30f0846c783606f9 + 0x8836B113 + HIDDEN + + + 2965465162 + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91A.Cactus_S4AP_Trait15.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91A.Cactus_S4AP_Trait15.TraitTuning.xml new file mode 100644 index 0000000..6ab9445 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91A.Cactus_S4AP_Trait15.TraitTuning.xml @@ -0,0 +1,19 @@ + + + 0x92619FF2 + + ADULT + CHILD + ELDER + TEEN + YOUNGADULT + + 2f7d0004:00000000:30f0846c783606f9 + 0x92619FF2 + HIDDEN + + + 4082513735 + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91B.Cactus_S4AP_Trait14.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91B.Cactus_S4AP_Trait14.TraitTuning.xml new file mode 100644 index 0000000..af4020a --- /dev/null +++ b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91B.Cactus_S4AP_Trait14.TraitTuning.xml @@ -0,0 +1,19 @@ + + + 0xDBE5EAB6 + + ADULT + CHILD + ELDER + TEEN + YOUNGADULT + + 2f7d0004:00000000:30f0846c783606f9 + 0xDBE5EAB6 + HIDDEN + + + 2321573248 + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91C.Cactus_S4AP_Trait13.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91C.Cactus_S4AP_Trait13.TraitTuning.xml new file mode 100644 index 0000000..6f8eae8 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91C.Cactus_S4AP_Trait13.TraitTuning.xml @@ -0,0 +1,19 @@ + + + 0xD8E6D160 + + ADULT + CHILD + ELDER + TEEN + YOUNGADULT + + 2f7d0004:00000000:30f0846c783606f9 + 0xD8E6D160 + HIDDEN + + + 3632851845 + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91D.Cactus_S4AP_Trait12.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91D.Cactus_S4AP_Trait12.TraitTuning.xml new file mode 100644 index 0000000..6943766 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91D.Cactus_S4AP_Trait12.TraitTuning.xml @@ -0,0 +1,19 @@ + + + 0xEA0CB8F8 + + ADULT + CHILD + ELDER + TEEN + YOUNGADULT + + 2f7d0004:00000000:30f0846c783606f9 + 0xEA0CB8F8 + HIDDEN + + + 3493292366 + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91E.Cactus_S4AP_Trait11.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91E.Cactus_S4AP_Trait11.TraitTuning.xml new file mode 100644 index 0000000..fb8a9e3 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91E.Cactus_S4AP_Trait11.TraitTuning.xml @@ -0,0 +1,19 @@ + + + 0xB5B059A3 + + ADULT + CHILD + ELDER + TEEN + YOUNGADULT + + 2f7d0004:00000000:30f0846c783606f9 + 0xB5B059A3 + HIDDEN + + + 3673267611 + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91F.Cactus_S4AP_Trait10.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91F.Cactus_S4AP_Trait10.TraitTuning.xml new file mode 100644 index 0000000..6de6e05 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91F.Cactus_S4AP_Trait10.TraitTuning.xml @@ -0,0 +1,19 @@ + + + 0x9874E78A + + ADULT + CHILD + ELDER + TEEN + YOUNGADULT + + 2f7d0004:00000000:30f0846c783606f9 + 0x9874E78A + HIDDEN + + + 3027319380 + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF0.Cactus_S4AP_Trait22.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF0.Cactus_S4AP_Trait22.TraitTuning.xml new file mode 100644 index 0000000..f6481eb --- /dev/null +++ b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF0.Cactus_S4AP_Trait22.TraitTuning.xml @@ -0,0 +1,19 @@ + + + 0xC88E7C72 + + ADULT + CHILD + ELDER + TEEN + YOUNGADULT + + 2f7d0004:00000000:30f0846c783606f9 + 0xC88E7C72 + HIDDEN + + + 3574946249 + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF1.Cactus_S4AP_Trait23.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF1.Cactus_S4AP_Trait23.TraitTuning.xml new file mode 100644 index 0000000..8480583 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF1.Cactus_S4AP_Trait23.TraitTuning.xml @@ -0,0 +1,19 @@ + + + 0x97101441 + + ADULT + CHILD + ELDER + TEEN + YOUNGADULT + + 2f7d0004:00000000:30f0846c783606f9 + 0x97101441 + HIDDEN + + + 2901165922 + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF2.Cactus_S4AP_Trait20.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF2.Cactus_S4AP_Trait20.TraitTuning.xml new file mode 100644 index 0000000..64cf832 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF2.Cactus_S4AP_Trait20.TraitTuning.xml @@ -0,0 +1,19 @@ + + + 0xCDDB6620 + + ADULT + CHILD + ELDER + TEEN + YOUNGADULT + + 2f7d0004:00000000:30f0846c783606f9 + 0xCDDB6620 + HIDDEN + + + 4181393663 + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF3.Cactus_S4AP_Trait21.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF3.Cactus_S4AP_Trait21.TraitTuning.xml new file mode 100644 index 0000000..c5d7495 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF3.Cactus_S4AP_Trait21.TraitTuning.xml @@ -0,0 +1,19 @@ + + + 0xC97977CA + + ADULT + CHILD + ELDER + TEEN + YOUNGADULT + + 2f7d0004:00000000:30f0846c783606f9 + 0xC97977CA + HIDDEN + + + 2293627832 + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF4.Cactus_S4AP_Trait26.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF4.Cactus_S4AP_Trait26.TraitTuning.xml new file mode 100644 index 0000000..cb29666 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF4.Cactus_S4AP_Trait26.TraitTuning.xml @@ -0,0 +1,14 @@ + + + 0xB2D63767 + + ADULT + CHILD + ELDER + TEEN + YOUNGADULT + + 2f7d0004:00000000:30f0846c783606f9 + 0xB2D63767 + HIDDEN + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF6.Cactus_S4AP_Trait24.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF6.Cactus_S4AP_Trait24.TraitTuning.xml new file mode 100644 index 0000000..207f0ff --- /dev/null +++ b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF6.Cactus_S4AP_Trait24.TraitTuning.xml @@ -0,0 +1,19 @@ + + + 0xE8455F9F + + ADULT + CHILD + ELDER + TEEN + YOUNGADULT + + 2f7d0004:00000000:30f0846c783606f9 + 0xE8455F9F + HIDDEN + + + 2298684211 + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D301A22C.Cactus_S4AP_Trait.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D301A22C.Cactus_S4AP_Trait.TraitTuning.xml new file mode 100644 index 0000000..5532253 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D301A22C.Cactus_S4AP_Trait.TraitTuning.xml @@ -0,0 +1,19 @@ + + + 0xBE01AC49 + + ADULT + CHILD + ELDER + TEEN + YOUNGADULT + + 2f7d0004:00000000:30f0846c783606f9 + 0xBE01AC49 + HIDDEN + + + 3369200885 + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B70.Cactus_S4AP_Trait4.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B70.Cactus_S4AP_Trait4.TraitTuning.xml new file mode 100644 index 0000000..27fa318 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B70.Cactus_S4AP_Trait4.TraitTuning.xml @@ -0,0 +1,19 @@ + + + 0xA1E5B19B + + ADULT + CHILD + ELDER + TEEN + YOUNGADULT + + 2f7d0004:00000000:30f0846c783606f9 + 0xA1E5B19B + HIDDEN + + + 3056188233 + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B71.Cactus_S4AP_Trait5.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B71.Cactus_S4AP_Trait5.TraitTuning.xml new file mode 100644 index 0000000..04b200c --- /dev/null +++ b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B71.Cactus_S4AP_Trait5.TraitTuning.xml @@ -0,0 +1,19 @@ + + + 0xC9249D53 + + ADULT + CHILD + ELDER + TEEN + YOUNGADULT + + 2f7d0004:00000000:30f0846c783606f9 + 0xC9249D53 + HIDDEN + + + 2382407906 + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B72.Cactus_S4AP_Trait6.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B72.Cactus_S4AP_Trait6.TraitTuning.xml new file mode 100644 index 0000000..3614793 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B72.Cactus_S4AP_Trait6.TraitTuning.xml @@ -0,0 +1,19 @@ + + + 0xE3298B37 + + ADULT + CHILD + ELDER + TEEN + YOUNGADULT + + 2f7d0004:00000000:30f0846c783606f9 + 0xE3298B37 + HIDDEN + + + 3662635647 + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B73.Cactus_S4AP_Trait7.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B73.Cactus_S4AP_Trait7.TraitTuning.xml new file mode 100644 index 0000000..8ef8d41 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B73.Cactus_S4AP_Trait7.TraitTuning.xml @@ -0,0 +1,19 @@ + + + 0xDD6F11B5 + + ADULT + CHILD + ELDER + TEEN + YOUNGADULT + + 2f7d0004:00000000:30f0846c783606f9 + 0xDD6F11B5 + HIDDEN + + + 3922353464 + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B76.Cactus_S4AP_Trait2.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B76.Cactus_S4AP_Trait2.TraitTuning.xml new file mode 100644 index 0000000..9ceca76 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B76.Cactus_S4AP_Trait2.TraitTuning.xml @@ -0,0 +1,19 @@ + + + 0xB9274531 + + ADULT + CHILD + ELDER + TEEN + YOUNGADULT + + 2f7d0004:00000000:30f0846c783606f9 + 0xB9274531 + HIDDEN + + + 3927409843 + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B77.Cactus_S4AP_Trait3.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B77.Cactus_S4AP_Trait3.TraitTuning.xml new file mode 100644 index 0000000..b5852b2 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B77.Cactus_S4AP_Trait3.TraitTuning.xml @@ -0,0 +1,19 @@ + + + 0xFBBCD468 + + ADULT + CHILD + ELDER + TEEN + YOUNGADULT + + 2f7d0004:00000000:30f0846c783606f9 + 0xFBBCD468 + HIDDEN + + + 2485735660 + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B7C.Cactus_S4AP_Trait8.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B7C.Cactus_S4AP_Trait8.TraitTuning.xml new file mode 100644 index 0000000..b329259 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B7C.Cactus_S4AP_Trait8.TraitTuning.xml @@ -0,0 +1,19 @@ + + + 0xDBD7E3BC + + ADULT + CHILD + ELDER + TEEN + YOUNGADULT + + 2f7d0004:00000000:30f0846c783606f9 + 0xDBD7E3BC + HIDDEN + + + 3617296485 + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B7D.Cactus_S4AP_Trait9.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B7D.Cactus_S4AP_Trait9.TraitTuning.xml new file mode 100644 index 0000000..a509c7e --- /dev/null +++ b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B7D.Cactus_S4AP_Trait9.TraitTuning.xml @@ -0,0 +1,19 @@ + + + 0xDDFC2DE9 + + ADULT + CHILD + ELDER + TEEN + YOUNGADULT + + 2f7d0004:00000000:30f0846c783606f9 + 0xDDFC2DE9 + HIDDEN + + + 4273359534 + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/E882D22F!00000000!00000000A07795F4.Cactus_S4AP_ShowYamlOptionsInteraction.InteractionTuning.xml b/Package/Cactus_S4AP (package source)/E882D22F!00000000!00000000A07795F4.Cactus_S4AP_ShowYamlOptionsInteraction.InteractionTuning.xml new file mode 100644 index 0000000..d60b2d1 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/E882D22F!00000000!00000000A07795F4.Cactus_S4AP_ShowYamlOptionsInteraction.InteractionTuning.xml @@ -0,0 +1,52 @@ + + + 2824713099 + + + + + + 3262040010 + + + + + + False + + + + + 2f7d0004:00000000:25eea5cdba6a6fd6 + + + + + INVALID + + + + + + + + Actor + + + + + + + + + Object + + + + + + + False + 0xFD327C75 + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/E882D22F!00000000!00000000C5690C31.Cactus_S4AP_SuperInteractionExperimental2.InteractionTuning.xml b/Package/Cactus_S4AP (package source)/E882D22F!00000000!00000000C5690C31.Cactus_S4AP_SuperInteractionExperimental2.InteractionTuning.xml new file mode 100644 index 0000000..4b2a853 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/E882D22F!00000000!00000000C5690C31.Cactus_S4AP_SuperInteractionExperimental2.InteractionTuning.xml @@ -0,0 +1,52 @@ + + + 2824713099 + + + + + + 3170762183 + + + + + + False + + + + + 2f7d0004:00000000:25eea5cdba6a6fd6 + + + + + INVALID + + + + + + + + Actor + + + + + + + + + Object + + + + + + + False + 0xA3CF48C3 + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/E882D22F!00000000!00000000FE6A648E.Cactus_S4AP_ResyncLocationsInteraction.InteractionTuning.xml b/Package/Cactus_S4AP (package source)/E882D22F!00000000!00000000FE6A648E.Cactus_S4AP_ResyncLocationsInteraction.InteractionTuning.xml new file mode 100644 index 0000000..e39b57f --- /dev/null +++ b/Package/Cactus_S4AP (package source)/E882D22F!00000000!00000000FE6A648E.Cactus_S4AP_ResyncLocationsInteraction.InteractionTuning.xml @@ -0,0 +1,52 @@ + + + 2824713099 + + + + + + 2572351313 + + + + + + False + + + + + 2f7d0004:00000000:25eea5cdba6a6fd6 + + + + + INVALID + + + + + + + + Actor + + + + + + + + + Object + + + + + + + False + 0x85F13D03 + + \ No newline at end of file From 28177b683027b7fe6cf4bab14b195b4d051319a9 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Sat, 6 Sep 2025 21:15:03 -0600 Subject: [PATCH 078/134] add new dancing skill trait --- ...C.Cactus_S4AP_LockDancing:Buff.SimData.xml | 33 +++++++++ ....Cactus_S4AP_Trait_LockDancing.SimData.xml | 69 +++++++++++++++++++ ...6DB798A7C.Cactus_S4AP_LockDancing:Buff.xml | 16 +++++ ...AA6F0CF6.Cactus_S4AP_Trait_LockDancing.xml | 18 +++++ 4 files changed, 136 insertions(+) create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!83246516DB798A7C.Cactus_S4AP_LockDancing:Buff.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!A951AD6CAA6F0CF6.Cactus_S4AP_Trait_LockDancing.SimData.xml create mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!83246516DB798A7C.Cactus_S4AP_LockDancing:Buff.xml create mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!A951AD6CAA6F0CF6.Cactus_S4AP_Trait_LockDancing.xml diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!83246516DB798A7C.Cactus_S4AP_LockDancing:Buff.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!83246516DB798A7C.Cactus_S4AP_LockDancing:Buff.SimData.xml new file mode 100644 index 0000000..b672c28 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!83246516DB798A7C.Cactus_S4AP_LockDancing:Buff.SimData.xml @@ -0,0 +1,33 @@ + + + + + 00000000-00000000-0000000000000000 + 00000000-00000000-0000000000000000 + 0x00000000 + 0x00000000 + 00000000-00000000-0000000000000000 + 0 + 0 + 0x00000000 + 0x00000000 + 1 + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!A951AD6CAA6F0CF6.Cactus_S4AP_Trait_LockDancing.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!A951AD6CAA6F0CF6.Cactus_S4AP_Trait_LockDancing.SimData.xml new file mode 100644 index 0000000..7dffc2a --- /dev/null +++ b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!A951AD6CAA6F0CF6.Cactus_S4AP_Trait_LockDancing.SimData.xml @@ -0,0 +1,69 @@ + + + + + + 1 + 2 + 4 + 8 + 16 + 32 + 64 + + + + 0 + 00000000-00000000-0000000000000000 + None + 00000000-00000000-0000000000000000 + None + 0 + + + 0x00000000 + + + 00000000-00000000-0000000000000000 + + 0 + + + + 0x00000000 + 0x00000000 + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!83246516DB798A7C.Cactus_S4AP_LockDancing:Buff.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!83246516DB798A7C.Cactus_S4AP_LockDancing:Buff.xml new file mode 100644 index 0000000..55856ee --- /dev/null +++ b/Package/Cactus_S4AP (package source)/6017E896!00000000!83246516DB798A7C.Cactus_S4AP_LockDancing:Buff.xml @@ -0,0 +1,16 @@ + + + + + + + + + 128145 + + + + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!A951AD6CAA6F0CF6.Cactus_S4AP_Trait_LockDancing.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!A951AD6CAA6F0CF6.Cactus_S4AP_Trait_LockDancing.xml new file mode 100644 index 0000000..f41773f --- /dev/null +++ b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!A951AD6CAA6F0CF6.Cactus_S4AP_Trait_LockDancing.xml @@ -0,0 +1,18 @@ + + + + BABY + TODDLER + CHILD + TEEN + YOUNGADULT + ADULT + ELDER + + + + 9449789066976004732 + + + HIDDEN + \ No newline at end of file From a761fbc3d4acfb46ac1adf8f806f0ecb80f94b3c Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Sat, 6 Sep 2025 21:16:04 -0600 Subject: [PATCH 079/134] new dancing skil trait in the package --- Package/Cactus_S4AP.package | Bin 65263 -> 67642 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/Package/Cactus_S4AP.package b/Package/Cactus_S4AP.package index c11878c604c297dbe09e6639907af9e09d9bdcae..19a8229c3dc12a106fa530661595b4d9c691322e 100644 GIT binary patch delta 3393 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 delta 1050 zcmXZXZD?0z7zXgO^WU`EGu_|OOw{AcBq^S>DZ?3wVkUbzn$U|@Vy0A7k4>{sv|vn^ zQBSdXdH(k_Q;7(1k0mCOg=8Q0?SO0qLiDlJ4+r}qXw5mVo4mN;cir5d?w|Xr{~0Uw z%}aWs|Ff$8ez{MH4&LZ5H}uc0=IHuksnmI+QSS>!dakRQo7t`tn+GNy`$Xq`ei6RF=Y% z@Du_Wc^WzSdl?F{XgSPS5_hbCC0#3#lKs!Xk>OSFCkJH)Gl?@LfGe;~Q~*N0N5&AY_Jv~9Oob=w|E)txiW4%%kGe>Bq#Y(@scGr+y>3`tY|> zs14tVnLx`Y#j2A}NvhTbacb@N;?)PwNKhx9m0YbkCxu!%FJ>aG`bn%henC=o>=$wB Z=tc3ge)M7#oq00q?vARXm9JDq_W;SHTIT=& From 6015f8c2b3eb231d1d9bc1a17f26ce0bc0ae8164 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Sat, 6 Sep 2025 21:36:41 -0600 Subject: [PATCH 080/134] do more tweaking of the new trait --- ...0000!00566BE2CD18DAFC.English .StringTable | Bin 785 -> 808 bytes ...C.Cactus_S4AP_LockDancing:Buff.SimData.xml | 20 +++--- ....Cactus_S4AP_Trait_LockDancing.SimData.xml | 66 +++++++++--------- ...actus_S4AP_LockDancing:Buff.BuffTuning.xml | 17 +++++ ...!0000000000000000.S4SMergedPackageManifest | Bin 0 -> 2224 bytes Package/Cactus_S4AP.package | Bin 67642 -> 68086 bytes 6 files changed, 60 insertions(+), 43 deletions(-) create mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!83246516DB798A7C.Cactus_S4AP_LockDancing:Buff.BuffTuning.xml create mode 100644 Package/Cactus_S4AP (package source)/7FB6AD8A!00000000!0000000000000000.S4SMergedPackageManifest diff --git a/Package/Cactus_S4AP (package source)/220557DA!00000000!00566BE2CD18DAFC.English .StringTable b/Package/Cactus_S4AP (package source)/220557DA!00000000!00566BE2CD18DAFC.English .StringTable index 74712d49ee73c9c8d69de0c890299282755f6db8..5bbc9768e077c3e7763e7dc49db6e1de4888a068 100644 GIT binary patch delta 51 zcmbQpwt`J4IK;_^m4QK?0R|#B3jJpif4)q4JA(j2PJVKBN@8AeW?p)6c4kfv04Dtn A_y7O^ delta 27 ccmZ3%HjzyzIK;_^m4QKy0R}ua3jJpS07Mo9yZ`_I diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!83246516DB798A7C.Cactus_S4AP_LockDancing:Buff.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!83246516DB798A7C.Cactus_S4AP_LockDancing:Buff.SimData.xml index b672c28..0a9a146 100644 --- a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!83246516DB798A7C.Cactus_S4AP_LockDancing:Buff.SimData.xml +++ b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!83246516DB798A7C.Cactus_S4AP_LockDancing:Buff.SimData.xml @@ -17,16 +17,16 @@ - - - - - - - - - - + + + + + + + + + + diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!A951AD6CAA6F0CF6.Cactus_S4AP_Trait_LockDancing.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!A951AD6CAA6F0CF6.Cactus_S4AP_Trait_LockDancing.SimData.xml index 7dffc2a..d529a85 100644 --- a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!A951AD6CAA6F0CF6.Cactus_S4AP_Trait_LockDancing.SimData.xml +++ b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!A951AD6CAA6F0CF6.Cactus_S4AP_Trait_LockDancing.SimData.xml @@ -11,8 +11,8 @@ 32 64 - - + + 0 00000000-00000000-0000000000000000 None @@ -20,49 +20,49 @@ None 0 - + 0x00000000 - - + + 00000000-00000000-0000000000000000 - + 0 - - + + 0x00000000 0x00000000 4 - + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!83246516DB798A7C.Cactus_S4AP_LockDancing:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!83246516DB798A7C.Cactus_S4AP_LockDancing:Buff.BuffTuning.xml new file mode 100644 index 0000000..b48c088 --- /dev/null +++ b/Package/Cactus_S4AP (package source)/6017E896!00000000!83246516DB798A7C.Cactus_S4AP_LockDancing:Buff.BuffTuning.xml @@ -0,0 +1,17 @@ + + + + + + + + + 128145 + + + + + + + False + \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/7FB6AD8A!00000000!0000000000000000.S4SMergedPackageManifest b/Package/Cactus_S4AP (package source)/7FB6AD8A!00000000!0000000000000000.S4SMergedPackageManifest new file mode 100644 index 0000000000000000000000000000000000000000..03302bc89f96a5102e39150bd5204434e2814ba9 GIT binary patch literal 2224 zcmZA2T}V@57{Kx4R|PIJLucP$MF_2$S&O=g0?8yb#VC+Db(mJ0&Y2ZPVhUy<5>|u+ z(M=W=ktKmaWTZI>vZ&M$!fs~mqNOdOtoBNOdV2=r^>@zs?>Xn}Fe8kAugLJ9vElc2 zM~Szl+MbubEvF&Osq?j0!i%x)WrJU>={wq+)Y?C0AJl!kZ-2gN%x=Uv+8g!#nEh5$ z`BSx@&l`I3=#BCPzqv@QSREhon~mgwtQTrK^Dv+H;K%)DwVxi-Px`Wk^d8e^*a{}~ z9@8%p^D+I`z|b?j$MkEiM!eGJWBRT}^GChM^hb7`d#m@De#45W(|V8TL*n`|eQ`$M zrru-vpy)CEz`n%SdXMQpiyqSla#Gv%9@E!~>&NtGW7dDrdrWT@-yf!Twsp+hU!EUK zUnk~c`rYNWndg%p(=QeCG5yY-)NcL!F@2?&kLmNbRNd2iOut;r$MhYSgQI$n>6eKf z(>Hx;9@cwIzeMzy{$z3XfAcZDM_fOqzn$6rOP`PFPlz7V=fz*_(R)mvB+ehx|2DRM z*LzI=MLhqQzTR2XqW747v6zqPTT3fuuAkr2DKQUo{N_U6ggy^5uUgzMOrLq+@g2R# z^b5uLV*2q;qgC%QeU+Gx>Cbc(cB;N~WFktfSnV$xnJ|3)u3oi$_1apKTKlJ`AL`Ei zw&#-WpQFjo#}5`5qkCgg)b_uQ6pj*(7LE~~B|KYrj&Q87NqDYsobWv1c;WfN3Bn76 z6S3bqn0+m!qOD>0uDU%&cW*++`})2hUKQR};&D2>ZjasNIPA1|Yh2~7GK=$QrQ74R sSZy0^Y1Z^jwzTN*fgzLo#-Ure*ZF6T`Eu)8j=f8At~|w$Ddyq$1KK>(ZU6uP literal 0 HcmV?d00001 diff --git a/Package/Cactus_S4AP.package b/Package/Cactus_S4AP.package index 19a8229c3dc12a106fa530661595b4d9c691322e..63a7a77f7ce24dc605c68203aef7d438d1981214 100644 GIT binary patch literal 68086 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%0Ai44Mo@56yl>|vY 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 P{38?q6k*)qKm7jzpl>#n literal 67642 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 Date: Sat, 6 Sep 2025 21:51:03 -0600 Subject: [PATCH 081/134] update french string tables, and stuff --- ...00000!07566BE2CD18DAFC.French .StringTable | Bin 785 -> 875 bytes ...tus_S4AP_Trait_LockDancing.TraitTuning.xml | 21 ++++++++++++++++++ Package/Cactus_S4AP.package | Bin 68086 -> 68100 bytes 3 files changed, 21 insertions(+) create mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!A951AD6CAA6F0CF6.Cactus_S4AP_Trait_LockDancing.TraitTuning.xml diff --git a/Package/Cactus_S4AP (package source)/220557DA!00000000!07566BE2CD18DAFC.French .StringTable b/Package/Cactus_S4AP (package source)/220557DA!00000000!07566BE2CD18DAFC.French .StringTable index 74712d49ee73c9c8d69de0c890299282755f6db8..12a3549bfea707fc0fe6e3b3ff3c84b3fb100b03 100644 GIT binary patch delta 370 zcmbQp_L{9eIK;_^m4QKy0R|Q^F)) + + 0xB723A6E7 + + BABY + TODDLER + CHILD + TEEN + YOUNGADULT + ADULT + ELDER + + 0xB723A6E7 + HIDDEN + + + 9449789066976004732 + + + + \ No newline at end of file diff --git a/Package/Cactus_S4AP.package b/Package/Cactus_S4AP.package index 63a7a77f7ce24dc605c68203aef7d438d1981214..42a26ab2afd609bd7b2bd879a476bc9a817965f4 100644 GIT binary patch delta 2676 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 H5)S(p>UX`^ delta 2432 zcmZY9X*kqt1IO_hCNony)i9RqOb8)mRF)WP5!ErLlTz7L&PZd@XqiYVBHMKHjHO6a z9LpF&)+v)^vSqD7WQ%69@0|H}o>$NF=Kj3+UH|L8?(6zq|F8tad^{q?9F8flAo$ag zxpAhxk`|Jj{)?E<`&m<>Y7cg_b>qZ__eaI}Mxa!8sP3>*kLQ(g2m1I1`;aB+Z;oO_ z@Py5BqAr_sOdS5>tFaT4PQTcOO9@4MjgZums_aSe5QHk_K29;3xh<&j?-SqGa`;PH zJ*-Hynj}v=JA_5e#cA$SJKYgq1gL`ICCVpn9`p>kMHOkZZ zYVMDDwv2<^ya*-PNa=7`jTgH!CYSf)L5~6(SGdo%Z+=8yMt@SVFzR}h_uC-T})j{8hKs2SJxzTC1(u-{qyLP~I*&$8))!ZZg)P>uQ zUB(v^qjYJPUdP$zsrT9#v9f676U^%TBZ2)#&qS70DYE;Xl`j`eyG+z=HICqiH~5bz z-#Y)v4O3TV7g8R9Rwa(%Vb%(0DSFsvT{UN^`aM#3k(b%-d*hnCp19+`J`udPLN^d| zHfKMzHa~ZzH1o|U?jRZuLhLOETUABxQ}Gg*K@o!sQXJBtV%$-D{1eYIo)&j`D#7pvw)p&crvp<))CI!94G~cs?*`ap!O>@FWPnrpdo4J1*2;v%&t`?2^Q8C82;h1iaTW+JYk367c`=^{+_yv zx0`g9sGhB#pT^YkXflUu3t$h$_AIYXwkVjEq_=x)m+0A3`l!_@{c^}g<1E!B-U|^$ zzRO)3-sqxin4qgRUggq?lQqlZJ1WcV{oQL2xP@}o?cd8D>25RGI39V-DWB7HpKF5J zC~m@2-wfQy(Us@H^;e>9?sg6amxEfP)!q@bGqy2|m8o)Nv?|gkenoL>snT6!cm+XW zlp(Nv2r3QYiB;`%3(}WeT}N9(uE-=`PJCuSDqqTp59a@p!4sDSOads|{IWl5kzn5{Palt(uF|75+Cg&DaWxY3FPJSWB zB_kM()tM?&zOf-}69yU`0GHK|^e_t8c4Qahi2YAB^8g2pchXGj(mGL?pf_N|Gz?%nUTGCqQ z5g8;Q2Lw-+Y!$#-Cpc6xM@3v$wm8CX&e5ldB&Qyma>(Fw8vDYB{PGW#Ug-A8t10}>Pufm`8{B-7 zr$Fi>ojJag(L5I1mzD@s<7(wfA+IO>TTPk<=iGO)H7m8%v?3<0b1quWJEL)d^sAcB zV~YH7S}IfxyiAap`>PuA*xxzMX1=^IH``X%Q%h0u&jpc(9BLO2?7nhpuf_AtJh7+Q zYBlL`S3Y}%HK>->*V-s!i8?lMrA;TB)W1wuBx+ieMiAlHBGiX1x+Rhe$vBOg5rZoi z?Mz%e2lSi0352ueVoihH$G%vetoLrisF@s>Z%0pU3VO4^2-_?ww#!jx^5c{>N^K{b z+8=*3L1%c&BD3dao;EY4cpm-VGrT&)fVQ%Nb(2V%u=jTq92`wOV_+%>8u&dm zV)d!X;sLAec65c#(%#^FEu%Vw;~M;-`AE%T!pJT}DYEfJZwYa)pDwDXPKVp@YPB0P_R3%wO!z&t4*@Jf zI4lA~2x~xuI14BcG(d-l04#`b&;gMR<{;hz>?R>-Ula|KBf{~L2n Date: Sat, 6 Sep 2025 21:52:49 -0600 Subject: [PATCH 082/134] fix gitignore to not include the thingy thing yk --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 68b295e..af3bbb1 100644 --- a/.gitignore +++ b/.gitignore @@ -55,3 +55,4 @@ settings.py Pipfile .DS_Store # Project exclude paths +/Libraries/core-library/lot51_core/* From 48736f4761848c3b415b1e60145b0ea84c377039 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Mon, 8 Sep 2025 16:41:16 -0600 Subject: [PATCH 083/134] update package --- Package/Cactus_S4AP.package | Bin 68100 -> 319600 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/Package/Cactus_S4AP.package b/Package/Cactus_S4AP.package index 42a26ab2afd609bd7b2bd879a476bc9a817965f4..5776eed599045a60d0d7fa41c266682d0bbd77d6 100644 GIT binary patch delta 255285 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 delta 5045 zcmZ{n3pkb88h}5y(M%h;Z%QOhDU(V?u8q?nbdx4ib6hH#5(#r6gWt9G7~{CBHkmZ8 zDTY!b5f#yKMikkm)6i)|DUn@n+gWR0*z&Lacs!f;TWh`RTi;s$`Uh?)N2f?9Y?Ra) zNmNu$)R9I%6aWNqT+)0uJ2^7ziYJ#JJEL)wr(QJY{8wd4Sf?smYGSbPMhiWNFAtJYPIm1 zy*7h7zASLpsQZVG-0nTSQC&+N!<3#=a&c8jmP}q9d!KKP!pWykipC5=SB)o+8UAF4 zTD;`2hFWBAXHj{hJq5hdSGQbHL)iv}B+Ugo=+fxL#S&#e-&I`l(Vg{VJzlRau^ z<1?a%{?O{ris$~$>C#BHWQIvSH{QXESl-G)Eu8eNQU~7;ALMSlvQ9?`EplsA!x zK&!r0=AcD;lq(t{FEPs|?0$NiAO4<@WlixqN-HM^YX-D-RY&zzXSJ3sLzXs!^BWA~ zZgN(j@xHj^=J0Yd=hf&+1T;)1jlScti*kIB{Px^&k4E3(eAkpWts5HI7b>-u{4MN^ ztc|OdMX_nH>jv8_s|4hzd&xMl&FoRm6$fp`(`_Ti8>^dLT5|mFMq63;*HC>y&!gQm zG)smHD)%Kjl&$@}w$`aZ=Bd1E@^~wIAh_@AU%M?-QWu$Im_(W+nZyQZy!G!^z4PFX zW_RkH)pstk4*cM(T(4NXC|-7qar?xzHHBt>JX1&yQw|>OHrHm4M*TT_e)sE=y&3D| z%bNUa3j^Ca3%yf=UlwpQPdWLn@>yZzsS($?bx&eny{%I~&xf0los^Xg#bkFjA0Lfs zt9ZRYUY2?4nK8$__2{qeTHLQty+Z7za$L7lA9wWaf+U2O%mJ|8D*=WrkuOB>U25RZ zQc?g6#It1ty#9&XeGy-~DJ4cBU7}ffK83$3egdG2LJv#N4wc`R5^aQrkd%P%3<&`b zuG_nd@x+ba8|Ldio!MSoWi{jQUFW$1l^mf;+6#4ep$Y{LZdbP*kONRf1K3MW55Rq) z&X2)7NFHD-;`%}^J{M-gmgc((0BVT$&$qz4Z$Llu-wpX)=Jhoi=5jNZkkwqD2W*YyG;GA zTtJUo(!&Vz>$}MU+GvI{Uz4{X<_q?S2~gCH{>G3-0>e|frV&*b1q~7 z%&)pm7a@hO4&nkaFIkTtyOT43dH+7LzydUY=>f6;=8hgy8KC%g7jXe<|8`EmLGn3( z`KfQo0{&=?A084+fUX8G?>#Ka06PCZ&cJ2+avsB*EP%O=4_P1-4d8Q>EP#2WuTX#z zUb)0G;50A&MvfnO2{5nlCkv>d6w7``-iDZK|5G49iSB&j0+V1iVjV~pz}z{AEHH@9 z`d?0vYXI{b!F&N~>e4AL5bo(7``-|<0OmuXWP$l;h8xk+lCET!JBMQdYWmhIert{Q z@ZtqW0?Z{`px>bx#6$y(qo-wx*g++_6=NO|GgalYYRtr?vG>9$RAcD;p}q0ofNL!B z31-jfgSoha(?vwiz&!0T zk;`G8QbOeN;~a|FlvGL#P{17|Tp{v#n8%kBxgzFq*NI$doI(Mys6q&9sEj*cRT8-> z<|nIW^2o<%M(C5L>y_|g_5JP9xA=dC^M8W`i1?r3b#JNiS|v6Pa9so8;ULW~GSTa` z_a(;yF2lF5dl0|~6`7;t^e(|CortTx1IR^dobb{6y_%<9R7mWJ&Kq2S1*pBVSbHvd Ty+>S?AJG0Dzzzj?2?PEQcAB;Z From e2b9c039dbb8b727a6f04ac985e06fbfb832f76f Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Mon, 8 Sep 2025 16:46:03 -0600 Subject: [PATCH 084/134] rename Trait17 to LockProgramming --- ...0000000!00000000D04CC918.Cactus_S4AP_Trait17.TraitTuning.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC918.Cactus_S4AP_Trait17.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC918.Cactus_S4AP_Trait17.TraitTuning.xml index bf106b3..1d5c1fa 100644 --- a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC918.Cactus_S4AP_Trait17.TraitTuning.xml +++ b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC918.Cactus_S4AP_Trait17.TraitTuning.xml @@ -1,5 +1,5 @@ - + 0xF8762C55 ADULT From 8ad3736d28d513f777e6c5cab2b4b1f614b3c51e Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 12 Sep 2025 18:21:18 -0600 Subject: [PATCH 085/134] fix the rename of Trait17 --- ...000D6BFC3D1.Cactus_S4AP_LockProgramming:Buff.BuffTuning.xml} | 2 +- ...0000000D04CC918.Cactus_S4AP_LockProgramming.TraitTuning.xml} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename Package/Cactus_S4AP (package source)/{6017E896!00000000!00000000D6BFC3D1.Cactus_S4AP_Trait17:Buff.BuffTuning.xml => 6017E896!00000000!00000000D6BFC3D1.Cactus_S4AP_LockProgramming:Buff.BuffTuning.xml} (95%) rename Package/Cactus_S4AP (package source)/{CB5FDDC7!00000000!00000000D04CC918.Cactus_S4AP_Trait17.TraitTuning.xml => CB5FDDC7!00000000!00000000D04CC918.Cactus_S4AP_LockProgramming.TraitTuning.xml} (100%) diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D6BFC3D1.Cactus_S4AP_Trait17:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D6BFC3D1.Cactus_S4AP_LockProgramming:Buff.BuffTuning.xml similarity index 95% rename from Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D6BFC3D1.Cactus_S4AP_Trait17:Buff.BuffTuning.xml rename to Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D6BFC3D1.Cactus_S4AP_LockProgramming:Buff.BuffTuning.xml index 8903995..e0a9538 100644 --- a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D6BFC3D1.Cactus_S4AP_Trait17:Buff.BuffTuning.xml +++ b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D6BFC3D1.Cactus_S4AP_LockProgramming:Buff.BuffTuning.xml @@ -1,5 +1,5 @@ - + diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC918.Cactus_S4AP_Trait17.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC918.Cactus_S4AP_LockProgramming.TraitTuning.xml similarity index 100% rename from Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC918.Cactus_S4AP_Trait17.TraitTuning.xml rename to Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC918.Cactus_S4AP_LockProgramming.TraitTuning.xml From ddef4356afcc1d57aadb4a165cc5b4508b0520be Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 12 Sep 2025 18:23:47 -0600 Subject: [PATCH 086/134] actually update the package so we can release --- Package/Cactus_S4AP.package | Bin 319600 -> 319615 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/Package/Cactus_S4AP.package b/Package/Cactus_S4AP.package index 5776eed599045a60d0d7fa41c266682d0bbd77d6..8d98bf6b3f70b73dd27dfdeb10a35ed37e676928 100644 GIT binary patch delta 4521 zcmZ{n4K$V68i3!!LCMdN-;z|AhKOcFsd34TL4=g48AROtg^=iHzT-FKy2{UYC%H{z zYG$gb7#Y+^E%H+_6X~>6>P~17!?R6q9);edsXFcDy_p{&q?!CWnxK8~| zoqDbvr|7bMl45zRnj0tYQh-K^yUG!F6%P5zkgx1jcNMPf4JJWw_*i>biiJk{D}{qc zauq@<^agE8%2udw7X%L;(Dl+avRoBd(t6cDTm4M)(D6~Gck+$%@Q{;Y+a;ISt=u;M zglKKszxC*x;T-y*TuDZ+u0!zo^~k9^G4nX8Pdhq-nYN?TVKu6jtAG69EIW0~(Bzu_ ziUJ>R7r*~TMHUt-F)%&Ub<)N0v%<^wdEZ8^e}4YuK379M`xm@VEDEbZ-EN2O)(;=L zr?0uSed?%Eq`<==>`un{w4Snm@9eHPl5AF7^LSl&K;IA6j}=Qt^Y<=YXc8vByrjT@ zy==PCHL~_fi{KPLU^4NqtnssRN<%I-P2`jwDDUiB^~Wx`(x6E{14gs7Wmu1C{d)X` z@`Fi}0T+Gmkj|Q28b^LE+@EilAlT#4O_HN?O@Bad!{VHQD@eMMh z|0VeoWBZa)^A~H?y>^XD@Jmoj>)xmtYIgej-~N%#tJk$G{%1~1P=LW|Guv)E$H*sF zrj7rKGO)SyrR~b0i)a5+u6l^cv9g+8(>w9S+7szdtkVY#hYUgrFPspVHFy|QfA5fA zHznV7j!9&*?{RN22O4&GkN0Tv;phfO?mAGHrK5|FZS?x2>*zMmUZeX-|Q+pl{K$|qs z%Xwb_`FCmn%P0a)*4su~)d4ig{Vq}jkoRav3NV~m0t?9qS84(1Py~=Wl4Q{Y{v2q( z9kKvGo!tMa6anN17fJ{)B*l^$FfHNydRtf2z;9AAfc()SxgheJP zFiz&U?E`uZAn#pH&p@El!1=i*0K-J!xfB896NHP3oDmh7q`(O2z|oX0fZW%NF3_}H zvx6}Q7@}kV`5ucI0cK{7Bn5^^2i2=YQy^^>Aiwt!U0}e&IDf>FUIWPGtV9Bgc%4fM z>?d>VWi49A(rN&C$Ql4c$}-HBvv{6uBPwEP%MkggbwUB=?M5RhpiP$9zpz1dn-CT=ovu%(i50jhmE9wJ{h6)7Wy(o?(R(&C@LNiL~o-PA@UR-vi@lqSWG%- z`;0Dtymvdj2-AMg=u-TGo&n_gj4xea5$Pbpk1l{bg`CW^!-xsoEGP@0?*qu0p91Lu zF=USAgG3{cRs+a&gXtN#=u$atyPGaRI5X`PLKiqpIye2qSXorycU- zW3%Tt=wZJs-ix23<-X_2@&JA!Q}~+v7r!^`e%Sw(`{e`7Cx_k1nJHerazA;KAp1Xl znj0hQqYD5UNCW1xFA(y^si|74LV#+*m8Edc|9O2iO!#ey`vpF7%kbuB;oD$RpmV2+ z1yCeK_#x3oK@ndeyg&vosQ(IJni#6hx(UB}GX(41d49ImlbfsQt}D-ptxRChaO=e47oxSQ+C6HVI=DjBl~0F;>O6 zp1pxF592zv2V*siud|#dB%Y6PExQzBb&RW7dlEC67*~<0lN@_;*A-#n&n^qg?OWBd zxw1z1moNMU4v6_ve#1y*{rn>2ejfp!58PP~^br?4za3YK`c8v941Y{=>nZcDI>U zTwp{OIK2Y+h9oO@W{VKNR%!(srX0#jd^9)$u!uC^Bhdi9Qi%E7Q2=Mc!)7=a4x4v{ zXUFz;ovF>KDvI+O15kY^%Xj!wRwyWLAIM{_@Vz(S4i|Ju170%?NIr_-d+(vUT+k={ I)lB*QA1Z<)p#T5? delta 1492 zcmXZcdr(vb6bA6S>;?`k$z2fe0jQ`sKG18J&k{v3HEl1UiJA*aK1j_=CW?@0hKriR zbw@uDk+ias@o@vg2F*tXWutP{^+B?v#F#OVH${B(x}W2j`Q~?K&Ybh-`R_!?of9Di z@s>^6=rw_ud)6j;f}{I+!WKLFl^(9hse5oT(`spd;|K3sS6na)hkACJySAZ|jvt#iTTX}ZDy0ROgvSoGMlC=XPj=8?hTJT6n z`sA;0dS$VZ=RNB2@3~BGJUb}p?9AAFN6?-_;XTL4`iJB@vl^=6kW-KOM&;l)Qhgz>Gu~x*`Z7-ih(Rtfx$F|?YQ-!Cce}DY) zi9krYt&=}{@3YWrY@K>V{Pb!~_aH$Cvj`vDvIxSM85SYCYDTiX&h=!I^P$f{t+7S< z%?yS{6_LA9e&0D@P;UrC-L$O(???IB!y(g@2q;wP2$gy|L!*1UK&N*jVNm~Qh!;$I zcY{Pnc85&!W1!GoJ)qK)y`a$p&qJq=d&8iPJ`gXO#`S|ld-R7)l~^d$Jpd}*Cqbjz z2SKNeFTkLW;vil!?J@)s9XJ#+%^e1XdWJ)#6(gb1GcQ4>;iF*C0r3#Mrb%NU(fJ9G zY57`VbH+^5U-m~R3TApflT*%pwODFP-*@)XtW5>Y1(!ev~wZEI@5+iNVK^KGHoh` zLT{HqrMGrNqm7?JrwyOOplx43^qIDP1&Q7*g-nh8Q0Sirq0(jz8f_|rPH!KEL2p$+ ztT%1^77}f!giLQ7gYs0Bj=BSlW*X3G#61`^t`*|1wy5CT`-0H^n)QQ(R_l{L@IRih BP*(r| From 0a79ac539cb18eb8a576228b962ca3ce8fa088f9 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 12 Sep 2025 18:26:02 -0600 Subject: [PATCH 087/134] update version --- Scripts/s4ap/modinfo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/s4ap/modinfo.py b/Scripts/s4ap/modinfo.py index 09ebe7c..a109834 100644 --- a/Scripts/s4ap/modinfo.py +++ b/Scripts/s4ap/modinfo.py @@ -14,7 +14,7 @@ def _name(self) -> str: @property def _version(self) -> str: # Mod version - return '0.3.0-rc2' + return '0.3.0.beta1' @property def _author(self) -> str: From a1ddc7e5445d38fb9c962ee66a70f7bc6da6672b Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Sun, 21 Sep 2025 14:11:47 -0600 Subject: [PATCH 088/134] =?UTF-8?q?beta=201=20mod=20doesn't=20work=20for?= =?UTF-8?q?=20the=20phone=20app=20=F0=9F=98=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Scripts/s4ap/utils/s4ap_phone_utils.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Scripts/s4ap/utils/s4ap_phone_utils.py b/Scripts/s4ap/utils/s4ap_phone_utils.py index 07f1fc5..09c09fc 100644 --- a/Scripts/s4ap/utils/s4ap_phone_utils.py +++ b/Scripts/s4ap/utils/s4ap_phone_utils.py @@ -70,9 +70,10 @@ def _handle_show_max_skills_phone(event_data: S4CLSimTraitAddedEvent): )) option += 1 - picker = UiObjectPicker.TunableFactory().default - picker.title = LocalizationHelperTuning.get_raw_text('Max Possible Skills') - picker.text = LocalizationHelperTuning.get_raw_text('The highest you can level your skills to.') + picker = UiObjectPicker.TunableFactory().default( + title=LocalizationHelperTuning.get_raw_text('Max Possible Skills'), + text=LocalizationHelperTuning.get_raw_text('The highest you can level your skills to.') + ) # Add the ObjectPickerRow objects directly for row in options: From 60446aa48e05cc3ecd82bc5f10f2a6276115045f Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Mon, 22 Sep 2025 10:40:05 -0600 Subject: [PATCH 089/134] we're working on figuring out how to unscrew the picker without s4cl (i had to add the old function back to figure out how the hell it worked) --- Scripts/s4ap/utils/s4ap_phone_utils.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Scripts/s4ap/utils/s4ap_phone_utils.py b/Scripts/s4ap/utils/s4ap_phone_utils.py index 09c09fc..07bd1e3 100644 --- a/Scripts/s4ap/utils/s4ap_phone_utils.py +++ b/Scripts/s4ap/utils/s4ap_phone_utils.py @@ -14,6 +14,7 @@ from services import get_instance_manager from sims4.localization import LocalizationHelperTuning from sims4.resources import Types +from sims4communitylib.dialogs.choose_object_dialog import CommonChooseObjectDialog from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry from sims4communitylib.events.sim.events.sim_trait_added import S4CLSimTraitAddedEvent from ui.ui_dialog_notification import UiDialogNotification @@ -70,6 +71,13 @@ def _handle_show_max_skills_phone(event_data: S4CLSimTraitAddedEvent): )) option += 1 + # dialog = CommonChooseObjectDialog( + # 'Max Possible Skills', + # 'The highest you can level your skills to.', + # choices=options + # ) + # dialog.show(on_chosen=_on_chosen) + picker = UiObjectPicker.TunableFactory().default( title=LocalizationHelperTuning.get_raw_text('Max Possible Skills'), text=LocalizationHelperTuning.get_raw_text('The highest you can level your skills to.') From a8b307e7fe7c96760d7479f0bb5c58f306fb35d5 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Mon, 22 Sep 2025 10:40:58 -0600 Subject: [PATCH 090/134] add back another piece of old code from the stable thing --- Scripts/s4ap/utils/s4ap_phone_utils.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Scripts/s4ap/utils/s4ap_phone_utils.py b/Scripts/s4ap/utils/s4ap_phone_utils.py index 07bd1e3..a401143 100644 --- a/Scripts/s4ap/utils/s4ap_phone_utils.py +++ b/Scripts/s4ap/utils/s4ap_phone_utils.py @@ -71,6 +71,10 @@ def _handle_show_max_skills_phone(event_data: S4CLSimTraitAddedEvent): )) option += 1 + # def _on_chosen(_, outcome: CommonChoiceOutcome): + # if outcome == CommonChoiceOutcome.CHOICE_MADE: + # dialog.show(on_chosen=_on_chosen) + # dialog = CommonChooseObjectDialog( # 'Max Possible Skills', # 'The highest you can level your skills to.', From 4c9d0e1ffb0abfb33475ece50d3d92872a771561 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Mon, 22 Sep 2025 11:14:43 -0600 Subject: [PATCH 091/134] do some wrapping, hopefully this works --- Scripts/s4ap/utils/s4ap_dialog_utils.py | 88 +++++++++++++++++++++++++ Scripts/s4ap/utils/s4ap_phone_utils.py | 29 +++----- 2 files changed, 96 insertions(+), 21 deletions(-) create mode 100644 Scripts/s4ap/utils/s4ap_dialog_utils.py diff --git a/Scripts/s4ap/utils/s4ap_dialog_utils.py b/Scripts/s4ap/utils/s4ap_dialog_utils.py new file mode 100644 index 0000000..4d263ff --- /dev/null +++ b/Scripts/s4ap/utils/s4ap_dialog_utils.py @@ -0,0 +1,88 @@ +import services +from s4ap.utils.s4ap_localization_utils import S4APLocalizationUtils +from sims4.resources import Types, get_resource_key +from ui.ui_dialog import UiDialogOk, UiDialogOkCancel +from ui.ui_dialog_picker import ObjectPickerRow, ObjectPickerType, UiObjectPicker + +class S4APDialog: + class OkCancelDialog: + + def __init__(self, sim, title=str(), text=str(), text_ok=String.OK, text_cancel=String.CANCEL, + has_cancel_button=False, callback=None): + self.sim = sim + self.title = S4APLocalizationUtils.localize(title) + self.text = S4APLocalizationUtils.localize(text) + self.text_ok = S4APLocalizationUtils.localize(text_ok) + self.text_cancel = S4APLocalizationUtils.localize(text_cancel) + self.has_cancel_button = has_cancel_button + self.callback = callback + + def show_dialog(self): + if self.has_cancel_button: + dialog = UiDialogOkCancel.TunableFactory().default(self.sim, text=lambda *args, **kwargs: self.text, + title=lambda *args, **kwargs: self.title, + text_ok=lambda *args, **kwargs: self.text_ok, + text_cancel=lambda *args, **kwargs: self.text_cancel) + else: + dialog = UiDialogOk.TunableFactory().default(self.sim, text=lambda *args, **kwargs: self.text, + title=lambda *args, **kwargs: self.title, + text_ok=lambda *args, **kwargs: self.text_ok) + if self.callback is not None: + dialog.add_listener(self._internal_callback) + dialog.show_dialog() + + def _internal_callback(self, dialog): + if dialog.accepted: + self.callback() + + class ObjectPickerDialog: + + def __init__(self, sim=None, title=str(), text=str(), picker_rows=None, min_selectable=1, max_selectable=1, + is_sortable=False, picker_type=ObjectPickerType.OBJECT, callback=None): + self.sim = sim + self.title = S4APLocalizationUtils.localize(title) + self.text = S4APLocalizationUtils.localize(text) + self.picker_rows = picker_rows if picker_rows else [] + self.min_selectable = min_selectable + self.max_selectable = max_selectable + self.is_sortable = is_sortable + self.picker_type = picker_type + self.callback = callback + + def show_dialog(self): + object_picker = UiObjectPicker.TunableFactory().default(self.sim, text=lambda *args, **kwargs: self.text, + title=lambda *args, **kwargs: self.title, + min_selectable=self.min_selectable, + max_selectable=self.max_selectable, + is_sortable=self.is_sortable, + picker_type=self.picker_type) + for picker_row in self.picker_rows: + if picker_row is not None: + if isinstance(picker_row, ObjectPickerRow): + object_picker.add_row(picker_row) + else: + object_picker.add_row(picker_row.get_object_picker_row()) + if self.callback: + object_picker.add_listener(self._internal_callback) + object_picker.show_dialog() + + def _internal_callback(self, dialog): + result_tags = dialog.get_result_tags() + for tag in result_tags: + self.callback(result_tag=tag) + + @staticmethod + def create_picker_row(option_id, title=str(), text=str(), rarity_text=str(), object_id=None, def_id=None, + icon_id=None, tag=None, is_enable=True): + name = S4APLocalizationUtils.localize(title) + row_description = S4APLocalizationUtils.localize(text) + rarity_text = S4APLocalizationUtils.localize(rarity_text) + if icon_id is not None: + icon = get_resource_key(icon_id, Types.PNG) + else: + icon = None + if tag is None: + tag = option_id + return ObjectPickerRow(option_id=option_id, name=name, row_description=row_description, + rarity_text=rarity_text, object_id=object_id, def_id=def_id, icon=icon, tag=tag, + count=0, is_enable=is_enable) \ No newline at end of file diff --git a/Scripts/s4ap/utils/s4ap_phone_utils.py b/Scripts/s4ap/utils/s4ap_phone_utils.py index a401143..02f392d 100644 --- a/Scripts/s4ap/utils/s4ap_phone_utils.py +++ b/Scripts/s4ap/utils/s4ap_phone_utils.py @@ -7,6 +7,7 @@ from s4ap.modinfo import ModInfo from s4ap.persistance.ap_session_data_store import S4APSessionStoreUtils from s4ap.utils.s4ap_career_utils import S4APCareerUtils +from s4ap.utils.s4ap_dialog_utils import S4APDialog from s4ap.utils.s4ap_generic_utils import S4APUtils from s4ap.utils.s4ap_household_utils import S4APHouseholdUtils from s4ap.utils.s4ap_skill_utils_class import S4APSkillUtils @@ -71,30 +72,16 @@ def _handle_show_max_skills_phone(event_data: S4CLSimTraitAddedEvent): )) option += 1 - # def _on_chosen(_, outcome: CommonChoiceOutcome): - # if outcome == CommonChoiceOutcome.CHOICE_MADE: - # dialog.show(on_chosen=_on_chosen) + sim = event_data.sim_info.get_sim_instance() - # dialog = CommonChooseObjectDialog( - # 'Max Possible Skills', - # 'The highest you can level your skills to.', - # choices=options - # ) - # dialog.show(on_chosen=_on_chosen) - - picker = UiObjectPicker.TunableFactory().default( - title=LocalizationHelperTuning.get_raw_text('Max Possible Skills'), - text=LocalizationHelperTuning.get_raw_text('The highest you can level your skills to.') + picker = S4APDialog.ObjectPickerDialog( + sim=sim, + title='Max Possible Skills', + text='The highest you can level your skills to.', + picker_rows=options ) - # Add the ObjectPickerRow objects directly - for row in options: - picker.add_row(row.option_id, row.name, icon_resource_key=row.icon) - - def _on_chosen(dialog, option_id): - pass # no action needed - - picker.show(_on_chosen) + picker.show_dialog() @CommonEventRegistry.handle_events(ModInfo.get_identity()) def _resync_locations(event_data: S4CLSimTraitAddedEvent): From 0de5907832ff5f7c8932e5dc6b8e072ccfbde998 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Mon, 22 Sep 2025 11:17:28 -0600 Subject: [PATCH 092/134] this should now work... hopefully --- Scripts/s4ap/utils/s4ap_phone_utils.py | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/Scripts/s4ap/utils/s4ap_phone_utils.py b/Scripts/s4ap/utils/s4ap_phone_utils.py index 02f392d..fcb097c 100644 --- a/Scripts/s4ap/utils/s4ap_phone_utils.py +++ b/Scripts/s4ap/utils/s4ap_phone_utils.py @@ -194,20 +194,13 @@ def _show_aspiration_and_career(event_data: S4CLSimTraitAddedEvent): (3, LocalizationHelperTuning.get_raw_text(display), 5906963266871873908) ] - # Create the picker - picker = UiObjectPicker.TunableFactory().default - - # Set title and description - picker.title = LocalizationHelperTuning.get_raw_text('Your Yaml Options Plus Skill Multiplier') - picker.text = LocalizationHelperTuning.get_raw_text('Options + Skill Multiplier') - - # Add the rows - for opt_id, name, icon_id in options: - icon = get_instance_manager(Types.PNG).get(icon_id) - picker.add_row(opt_id, name, icon_resource_key=icon) + sim = event_data.sim_info.get_sim_instance() - # Show dialog - def _on_chosen(dialog, option_id): - pass # player chose something, no need to do anything about it + picker = S4APDialog.ObjectPickerDialog( + sim=sim, + title='Your Yaml Options Plus Skill Multiplier', + text='Options + Skill Multiplier', + picker_rows=options + ) - picker.show(_on_chosen) + picker.show_dialog() From 02c74d58fa8bd9e5bb6e62c2c3f98c584971d8b6 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Mon, 22 Sep 2025 11:18:00 -0600 Subject: [PATCH 093/134] clean up imports in phone file --- Scripts/s4ap/utils/s4ap_phone_utils.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Scripts/s4ap/utils/s4ap_phone_utils.py b/Scripts/s4ap/utils/s4ap_phone_utils.py index fcb097c..4debfd5 100644 --- a/Scripts/s4ap/utils/s4ap_phone_utils.py +++ b/Scripts/s4ap/utils/s4ap_phone_utils.py @@ -12,14 +12,11 @@ from s4ap.utils.s4ap_household_utils import S4APHouseholdUtils from s4ap.utils.s4ap_skill_utils_class import S4APSkillUtils from server_commands.argument_helpers import TunableInstanceParam -from services import get_instance_manager from sims4.localization import LocalizationHelperTuning from sims4.resources import Types -from sims4communitylib.dialogs.choose_object_dialog import CommonChooseObjectDialog from sims4communitylib.events.event_handling.common_event_registry import CommonEventRegistry from sims4communitylib.events.sim.events.sim_trait_added import S4CLSimTraitAddedEvent -from ui.ui_dialog_notification import UiDialogNotification -from ui.ui_dialog_picker import ObjectPickerRow, UiObjectPicker +from ui.ui_dialog_picker import ObjectPickerRow logger = S4APLogger.get_log() logger.enable() From 22557d9ced7eee822350ae89ee7576a37377c4e0 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Mon, 22 Sep 2025 11:22:53 -0600 Subject: [PATCH 094/134] do a bit more fixing to actually get it fully working --- Scripts/s4ap/enums/S4APLocalization.py | 27 +++++++++++++++++++++++++ Scripts/s4ap/utils/s4ap_dialog_utils.py | 3 ++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/Scripts/s4ap/enums/S4APLocalization.py b/Scripts/s4ap/enums/S4APLocalization.py index 5a45870..9b84246 100644 --- a/Scripts/s4ap/enums/S4APLocalization.py +++ b/Scripts/s4ap/enums/S4APLocalization.py @@ -1,3 +1,4 @@ +import enum from enum import Int class S4APTraitId(Int): @@ -393,3 +394,29 @@ def get_career_name(self, hash_value, level): for career_location in careers_list: if career in career_location: return career_location + +class String(enum.Int): + OK = 3648501874 + CANCEL = 2355984940 + ADD_TRAIT = 737074377 + ADD_SKILL = 516063206 + ADD_RELATIONSHIP = 1393271393 + ADD_LIFESTYLE = 666206482 + ADD_MILESTONE = 2190602227 + ADD_RELATIONSHIP_BIT = 2197328290 + FAME = 665568034 + REPUTATION = 3247584227 + SCOUNDREL_REPUTATION = 3826991979 + FIRST_ORDER_REPUTATION = 1733028007 + RESISTANCE_REPUTATION = 572995340 + SET_SEASON = 1871615250 + SET_WEATHER = 1988769465 + SET_LUNAR_PHASE = 3446235888 + SIM_STATS = 4063537848 + ADD_SENTIMENT = 2794433223 + STAR_RATING = 3236879271 + DEATH = 3055219676 + TRAITS = 4246723338 + ROMANTIC_ATTRACTION = 3896804997 + ROMANTIC_SATISFACTION = 3982568517 + UNFINISHED_BUSINESS = 792487778 \ No newline at end of file diff --git a/Scripts/s4ap/utils/s4ap_dialog_utils.py b/Scripts/s4ap/utils/s4ap_dialog_utils.py index 4d263ff..89d29c1 100644 --- a/Scripts/s4ap/utils/s4ap_dialog_utils.py +++ b/Scripts/s4ap/utils/s4ap_dialog_utils.py @@ -1,4 +1,5 @@ import services +from s4ap.enums import S4APLocalization from s4ap.utils.s4ap_localization_utils import S4APLocalizationUtils from sims4.resources import Types, get_resource_key from ui.ui_dialog import UiDialogOk, UiDialogOkCancel @@ -7,7 +8,7 @@ class S4APDialog: class OkCancelDialog: - def __init__(self, sim, title=str(), text=str(), text_ok=String.OK, text_cancel=String.CANCEL, + def __init__(self, sim, title=str(), text=str(), text_ok=S4APLocalization.String.OK, text_cancel=S4APLocalization.String.CANCEL, has_cancel_button=False, callback=None): self.sim = sim self.title = S4APLocalizationUtils.localize(title) From 23887a480e9ed8b64a1c53d6a5e7d62193b10223 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Mon, 22 Sep 2025 11:28:18 -0600 Subject: [PATCH 095/134] update the version of the mod --- Scripts/s4ap/modinfo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/s4ap/modinfo.py b/Scripts/s4ap/modinfo.py index a109834..b97c20f 100644 --- a/Scripts/s4ap/modinfo.py +++ b/Scripts/s4ap/modinfo.py @@ -14,7 +14,7 @@ def _name(self) -> str: @property def _version(self) -> str: # Mod version - return '0.3.0.beta1' + return '0.3.0.beta2' @property def _author(self) -> str: From 515f91ed3da22baa70bca9bd4eeb7fadf8973caa Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Mon, 22 Sep 2025 11:37:28 -0600 Subject: [PATCH 096/134] we're using the core library for the ok dialog... i didn't need this --- Scripts/s4ap/enums/S4APLocalization.py | 26 --------------------- Scripts/s4ap/utils/s4ap_dialog_utils.py | 31 ------------------------- 2 files changed, 57 deletions(-) diff --git a/Scripts/s4ap/enums/S4APLocalization.py b/Scripts/s4ap/enums/S4APLocalization.py index 9b84246..8a11501 100644 --- a/Scripts/s4ap/enums/S4APLocalization.py +++ b/Scripts/s4ap/enums/S4APLocalization.py @@ -394,29 +394,3 @@ def get_career_name(self, hash_value, level): for career_location in careers_list: if career in career_location: return career_location - -class String(enum.Int): - OK = 3648501874 - CANCEL = 2355984940 - ADD_TRAIT = 737074377 - ADD_SKILL = 516063206 - ADD_RELATIONSHIP = 1393271393 - ADD_LIFESTYLE = 666206482 - ADD_MILESTONE = 2190602227 - ADD_RELATIONSHIP_BIT = 2197328290 - FAME = 665568034 - REPUTATION = 3247584227 - SCOUNDREL_REPUTATION = 3826991979 - FIRST_ORDER_REPUTATION = 1733028007 - RESISTANCE_REPUTATION = 572995340 - SET_SEASON = 1871615250 - SET_WEATHER = 1988769465 - SET_LUNAR_PHASE = 3446235888 - SIM_STATS = 4063537848 - ADD_SENTIMENT = 2794433223 - STAR_RATING = 3236879271 - DEATH = 3055219676 - TRAITS = 4246723338 - ROMANTIC_ATTRACTION = 3896804997 - ROMANTIC_SATISFACTION = 3982568517 - UNFINISHED_BUSINESS = 792487778 \ No newline at end of file diff --git a/Scripts/s4ap/utils/s4ap_dialog_utils.py b/Scripts/s4ap/utils/s4ap_dialog_utils.py index 89d29c1..48501bd 100644 --- a/Scripts/s4ap/utils/s4ap_dialog_utils.py +++ b/Scripts/s4ap/utils/s4ap_dialog_utils.py @@ -1,40 +1,9 @@ import services -from s4ap.enums import S4APLocalization from s4ap.utils.s4ap_localization_utils import S4APLocalizationUtils from sims4.resources import Types, get_resource_key -from ui.ui_dialog import UiDialogOk, UiDialogOkCancel from ui.ui_dialog_picker import ObjectPickerRow, ObjectPickerType, UiObjectPicker class S4APDialog: - class OkCancelDialog: - - def __init__(self, sim, title=str(), text=str(), text_ok=S4APLocalization.String.OK, text_cancel=S4APLocalization.String.CANCEL, - has_cancel_button=False, callback=None): - self.sim = sim - self.title = S4APLocalizationUtils.localize(title) - self.text = S4APLocalizationUtils.localize(text) - self.text_ok = S4APLocalizationUtils.localize(text_ok) - self.text_cancel = S4APLocalizationUtils.localize(text_cancel) - self.has_cancel_button = has_cancel_button - self.callback = callback - - def show_dialog(self): - if self.has_cancel_button: - dialog = UiDialogOkCancel.TunableFactory().default(self.sim, text=lambda *args, **kwargs: self.text, - title=lambda *args, **kwargs: self.title, - text_ok=lambda *args, **kwargs: self.text_ok, - text_cancel=lambda *args, **kwargs: self.text_cancel) - else: - dialog = UiDialogOk.TunableFactory().default(self.sim, text=lambda *args, **kwargs: self.text, - title=lambda *args, **kwargs: self.title, - text_ok=lambda *args, **kwargs: self.text_ok) - if self.callback is not None: - dialog.add_listener(self._internal_callback) - dialog.show_dialog() - - def _internal_callback(self, dialog): - if dialog.accepted: - self.callback() class ObjectPickerDialog: From 5dd74aa5c3b51d348411f2ca1119c801db7d85a2 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Mon, 22 Sep 2025 11:39:08 -0600 Subject: [PATCH 097/134] remove old code --- Scripts/s4ap/utils/s4ap_generic_utils.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/Scripts/s4ap/utils/s4ap_generic_utils.py b/Scripts/s4ap/utils/s4ap_generic_utils.py index 70a6878..b292dca 100644 --- a/Scripts/s4ap/utils/s4ap_generic_utils.py +++ b/Scripts/s4ap/utils/s4ap_generic_utils.py @@ -104,16 +104,5 @@ def _on_response(dialog_instance: UiDialogOkCancel): ok_text, callback=_on_response ) - # dialog = UiDialogOkCancel.TunableFactory().default( - # active_sim, - # title=title, - # text=text, - # ok_text=ok_text, - # cancel_text=cancel_text - # ) - - - # dialog.add_listener(_on_response) - # dialog.show_dialog() return dialog \ No newline at end of file From 12bee48b77dc362e450e239edf2e9dd85cfa425b Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Mon, 22 Sep 2025 11:43:08 -0600 Subject: [PATCH 098/134] use core library for some of these notifications --- Scripts/s4ap/events/checks/send_check_event.py | 3 ++- Scripts/s4ap/events/items/receive_item_event.py | 3 ++- Scripts/s4ap/utils/s4ap_phone_utils.py | 3 ++- Scripts/s4ap/utils/s4ap_reset_utils.py | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Scripts/s4ap/events/checks/send_check_event.py b/Scripts/s4ap/events/checks/send_check_event.py index 3ec4fb6..2f8ebd5 100644 --- a/Scripts/s4ap/events/checks/send_check_event.py +++ b/Scripts/s4ap/events/checks/send_check_event.py @@ -1,3 +1,4 @@ +from lot51_core.utils.dialog import DialogHelper from s4ap.events.Utils.send_location_event import SendLocationEvent from s4ap.jsonio.s4ap_json import print_json, read_json from s4ap.logging.s4ap_logger import S4APLogger @@ -35,7 +36,7 @@ def _handle_send_check_event(event_data: SendLocationEvent): if event_data.location_name not in json_list["Locations"]: json_list["Locations"].append(event_data.location_name) print_json(json_list, 'locations_cached.json') - S4APUtils.show_basic_notification( + DialogHelper.create_notification( 'Saving on check', event_data.location_name ) diff --git a/Scripts/s4ap/events/items/receive_item_event.py b/Scripts/s4ap/events/items/receive_item_event.py index 42e376c..66be2af 100644 --- a/Scripts/s4ap/events/items/receive_item_event.py +++ b/Scripts/s4ap/events/items/receive_item_event.py @@ -1,5 +1,6 @@ import time +from lot51_core.utils.dialog import DialogHelper from protocolbuffers import Consts_pb2 from s4ap.enums.S4APLocalization import S4APTraitId @@ -180,7 +181,7 @@ def handle_items(self, items): @staticmethod def show_received_notification(items, players, locations): - S4APUtils.show_basic_notification( + DialogHelper.create_notification( 'Received Items', '\n'.join( [f'{item} from {player} ({location})' for item, player, location in zip(items, players, locations)])) diff --git a/Scripts/s4ap/utils/s4ap_phone_utils.py b/Scripts/s4ap/utils/s4ap_phone_utils.py index 4debfd5..bdd10c5 100644 --- a/Scripts/s4ap/utils/s4ap_phone_utils.py +++ b/Scripts/s4ap/utils/s4ap_phone_utils.py @@ -1,6 +1,7 @@ import re from aspirations.aspiration_types import AspriationType +from lot51_core.utils.dialog import DialogHelper from s4ap.enums.S4APLocalization import S4APTraitId, HashLookup, S4APBaseGameSkills from s4ap.jsonio.s4ap_json import print_json from s4ap.logging.s4ap_logger import S4APLogger @@ -146,7 +147,7 @@ def _resync_locations(event_data: S4CLSimTraitAddedEvent): locations.append(milestone_display_name) print_json(locations, 'locations_cached.json') print_json(True, 'sync.json') - S4APUtils.show_basic_notification( + DialogHelper.create_notification( 'Locations Resynced', '' ) diff --git a/Scripts/s4ap/utils/s4ap_reset_utils.py b/Scripts/s4ap/utils/s4ap_reset_utils.py index 6da2ca9..a8a53de 100644 --- a/Scripts/s4ap/utils/s4ap_reset_utils.py +++ b/Scripts/s4ap/utils/s4ap_reset_utils.py @@ -1,3 +1,4 @@ +from lot51_core.utils.dialog import DialogHelper from s4ap.enums.S4APLocalization import S4APTraitId from s4ap.logging.s4ap_logger import S4APLogger from s4ap.utils.s4ap_generic_utils import S4APUtils @@ -19,7 +20,7 @@ def reset_all_skills(self): sim_info.remove_statistic(skill) def show_reset_notif(self): - S4APUtils.show_basic_notification( + DialogHelper.create_notification( 'Progress Reset Completed', "Your Sim's skills have been successfully reset. Please switch to a different sim or leave the lot and revisit to ensure the changes are visible in the UI." ) From c7d7c30468ef895df83b697c94d470d69b2808d7 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Mon, 22 Sep 2025 11:47:45 -0600 Subject: [PATCH 099/134] make them actually show properly --- Scripts/s4ap/events/checks/send_check_event.py | 2 +- Scripts/s4ap/events/items/receive_item_event.py | 2 +- Scripts/s4ap/logging/s4ap_logger.py | 2 +- Scripts/s4ap/utils/s4ap_phone_utils.py | 2 +- Scripts/s4ap/utils/s4ap_reset_utils.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Scripts/s4ap/events/checks/send_check_event.py b/Scripts/s4ap/events/checks/send_check_event.py index 2f8ebd5..6f6076b 100644 --- a/Scripts/s4ap/events/checks/send_check_event.py +++ b/Scripts/s4ap/events/checks/send_check_event.py @@ -39,5 +39,5 @@ def _handle_send_check_event(event_data: SendLocationEvent): DialogHelper.create_notification( 'Saving on check', event_data.location_name - ) + ).show_dialog() S4APUtils.trigger_autosave() diff --git a/Scripts/s4ap/events/items/receive_item_event.py b/Scripts/s4ap/events/items/receive_item_event.py index 66be2af..ba01995 100644 --- a/Scripts/s4ap/events/items/receive_item_event.py +++ b/Scripts/s4ap/events/items/receive_item_event.py @@ -184,4 +184,4 @@ def show_received_notification(items, players, locations): DialogHelper.create_notification( 'Received Items', '\n'.join( - [f'{item} from {player} ({location})' for item, player, location in zip(items, players, locations)])) + [f'{item} from {player} ({location})' for item, player, location in zip(items, players, locations)])).show_dialog() diff --git a/Scripts/s4ap/logging/s4ap_logger.py b/Scripts/s4ap/logging/s4ap_logger.py index b98178b..7e9fc27 100644 --- a/Scripts/s4ap/logging/s4ap_logger.py +++ b/Scripts/s4ap/logging/s4ap_logger.py @@ -25,7 +25,7 @@ def show_loaded_notification() -> None: DialogHelper.create_notification( S4APLocalizationUtils.localize(S4APStringId.S4AP_LOADED), 'Loaded Sims 4 Archipelago Mod (' + ModInfo.get_identity().version + ')' - ) + ).show_dialog() # S4APUtils.show_basic_notification( # S4APLocalizationUtils.localize(S4APStringId.S4AP_LOADED), # 'Loaded Sims 4 Archipelago Mod (' + ModInfo.get_identity().version + ')' diff --git a/Scripts/s4ap/utils/s4ap_phone_utils.py b/Scripts/s4ap/utils/s4ap_phone_utils.py index bdd10c5..ccaf9da 100644 --- a/Scripts/s4ap/utils/s4ap_phone_utils.py +++ b/Scripts/s4ap/utils/s4ap_phone_utils.py @@ -150,7 +150,7 @@ def _resync_locations(event_data: S4CLSimTraitAddedEvent): DialogHelper.create_notification( 'Locations Resynced', '' - ) + ).show_dialog() @CommonEventRegistry.handle_events(ModInfo.get_identity()) def _show_aspiration_and_career(event_data: S4CLSimTraitAddedEvent): diff --git a/Scripts/s4ap/utils/s4ap_reset_utils.py b/Scripts/s4ap/utils/s4ap_reset_utils.py index a8a53de..fc58955 100644 --- a/Scripts/s4ap/utils/s4ap_reset_utils.py +++ b/Scripts/s4ap/utils/s4ap_reset_utils.py @@ -23,7 +23,7 @@ def show_reset_notif(self): DialogHelper.create_notification( 'Progress Reset Completed', "Your Sim's skills have been successfully reset. Please switch to a different sim or leave the lot and revisit to ensure the changes are visible in the UI." - ) + ).show_dialog() def remove_all_s4ap_traits(self): # Get all traits from the base class CommonTraitId From f377d8f8d5a3aa9c860c787df2172240f8bf13a1 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Fri, 26 Sep 2025 13:01:16 -0600 Subject: [PATCH 100/134] add slot checking to ensure bleed doesn't happen --- Scripts/s4ap/jsonio/auto_parse_json.py | 3 ++- Scripts/s4ap/persistance/ap_data_store.py | 2 ++ Scripts/s4ap/persistance/ap_session_data_store.py | 13 +++++++++---- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/Scripts/s4ap/jsonio/auto_parse_json.py b/Scripts/s4ap/jsonio/auto_parse_json.py index e610c45..bae6fa2 100644 --- a/Scripts/s4ap/jsonio/auto_parse_json.py +++ b/Scripts/s4ap/jsonio/auto_parse_json.py @@ -75,10 +75,11 @@ def parse_message(data): slot_name = data["name"] goal = data["goal"] career = data["career"] + slot = data["slot"] data_store = S4APSessionStoreUtils() data_store.save_goal_and_career(goal, career) if data_store.check_session_values(host_name=host, port=port, seed_name=seed_name, - player=slot_name): + player=slot_name, slot=slot): # if settings don't match then cancels cancel = True print_json({}) diff --git a/Scripts/s4ap/persistance/ap_data_store.py b/Scripts/s4ap/persistance/ap_data_store.py index 9a5f6c5..f653c7e 100644 --- a/Scripts/s4ap/persistance/ap_data_store.py +++ b/Scripts/s4ap/persistance/ap_data_store.py @@ -16,6 +16,7 @@ class S4APSettings: SENDERS = 'senders' # The players who sent the item GOAL = 'goal' # the goal of the game CAREER = 'career' # the chosen career for logic + SLOT = 'slot' # From RoomInfo and if set checked to ensure bleeding doesn't happen (the slot number of the slot) class S4APGenericDataStore(CommonDataStore): """ Manager of generic stuff. """ @@ -48,4 +49,5 @@ def _default_data(self) -> Dict[str, Any]: S4APSettings.SENDERS: None, S4APSettings.GOAL: None, S4APSettings.CAREER: None, + S4APSettings.SLOT: None, }.copy() diff --git a/Scripts/s4ap/persistance/ap_session_data_store.py b/Scripts/s4ap/persistance/ap_session_data_store.py index b82ca1f..d4761ad 100644 --- a/Scripts/s4ap/persistance/ap_session_data_store.py +++ b/Scripts/s4ap/persistance/ap_session_data_store.py @@ -21,7 +21,7 @@ class S4APSessionStoreUtils: def __init__(self) -> None: self._data_manager = S4APDataManagerUtils() - def check_session_values(self, host_name: str, port: str, seed_name: str, player: str) -> bool: + def check_session_values(self, host_name: str, port: str, seed_name: str, player: str, slot: int) -> bool: """ Check session store to make sure it's the same settings as before and send a warning otherwise :returns True, if settings don't exist or equal those that were used before """ if self._get_value(S4APSettings.SEED_NAME) is not None: # Check if Seed was previously saved @@ -29,7 +29,8 @@ def check_session_values(self, host_name: str, port: str, seed_name: str, player if self._get_value(S4APSettings.SEED_NAME) != seed_name or \ self._get_value(S4APSettings.HOST_NAME) != host_name or \ self._get_value(S4APSettings.PORT_NUMBER) != port or \ - self._get_value(S4APSettings.PLAYER) != player: # Settings don't match + self._get_value(S4APSettings.PLAYER) != player or \ + self._get_value(S4APSettings.SLOT): # Settings don't match logger.warn("AP session data mismatch") def _cancel_chosen(_: UiDialogOkCancel): @@ -43,7 +44,7 @@ def _ok_chosen(_: UiDialogOkCancel): reset.remove_all_s4ap_traits() reset.show_reset_notif() S4APDataManagerUtils.get().reset() - self.save_seed_values(host_name, port, seed_name, player) + self.save_seed_values(host_name, port, seed_name, player, slot) print_json({}, 'items.json') print_json(True, 'sync.json') print_json({}, 'locations_cached.json') @@ -123,12 +124,13 @@ def check_index_value(self, index: str) -> bool: self.set_index_value(index) return False - def save_seed_values(self, host_name: str, port: str, seed_name: str, player: str): + def save_seed_values(self, host_name: str, port: str, seed_name: str, player: str, slot: int): """ Overwrite Session specific values. """ self._set_value(S4APSettings.SEED_NAME, seed_name) self._set_value(S4APSettings.HOST_NAME, host_name) self._set_value(S4APSettings.PORT_NUMBER, port) self._set_value(S4APSettings.PLAYER, player) + self._set_value(S4APSettings.SLOT, slot) S4APUtils.trigger_autosave() logger.debug("Session data saved successfully") @@ -169,6 +171,9 @@ def get_goal(self) -> str: def get_career(self) -> set: return self._get_value(S4APSettings.CAREER) + def get_slot(self) -> int: + return self._get_value(S4APSettings.SLOT) + def _get_value(self, key: str) -> Any: generic_settings_data_store: S4APGenericDataStore = self._data_manager.get_generic_settings_data() return generic_settings_data_store.get_value_by_key(key) From b9a6b8f2efbe4853319a71c607a0d2b4b8b9d6c9 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Thu, 4 Dec 2025 15:29:05 -0700 Subject: [PATCH 101/134] fix the comparison --- Scripts/s4ap/persistance/ap_session_data_store.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Scripts/s4ap/persistance/ap_session_data_store.py b/Scripts/s4ap/persistance/ap_session_data_store.py index d4761ad..936048c 100644 --- a/Scripts/s4ap/persistance/ap_session_data_store.py +++ b/Scripts/s4ap/persistance/ap_session_data_store.py @@ -30,7 +30,7 @@ def check_session_values(self, host_name: str, port: str, seed_name: str, player self._get_value(S4APSettings.HOST_NAME) != host_name or \ self._get_value(S4APSettings.PORT_NUMBER) != port or \ self._get_value(S4APSettings.PLAYER) != player or \ - self._get_value(S4APSettings.SLOT): # Settings don't match + self._get_value(S4APSettings.SLOT) != slot: # Settings don't match logger.warn("AP session data mismatch") def _cancel_chosen(_: UiDialogOkCancel): @@ -82,7 +82,7 @@ def _ok_chosen(_: UiDialogOkCancel): print_json(True, 'sync.json') print_json({}, 'locations_cached.json') CommonEventRegistry.get().dispatch(AllowReceiveItems(True)) - self.save_seed_values(host_name, port, seed_name, player) + self.save_seed_values(host_name, port, seed_name, player, slot) return False def _cancel_chosen(_: UiDialogOkCancel): From 41d88e5e63b4a3dc0be41e6fa85df71220d3c1a6 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Thu, 4 Dec 2025 15:29:58 -0700 Subject: [PATCH 102/134] remove the unused import --- Scripts/s4ap/enums/S4APLocalization.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Scripts/s4ap/enums/S4APLocalization.py b/Scripts/s4ap/enums/S4APLocalization.py index 8a11501..5a45870 100644 --- a/Scripts/s4ap/enums/S4APLocalization.py +++ b/Scripts/s4ap/enums/S4APLocalization.py @@ -1,4 +1,3 @@ -import enum from enum import Int class S4APTraitId(Int): From 895d640e55bfb63ca7f5e2c42af9b66d6ae5153b Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Thu, 4 Dec 2025 15:31:39 -0700 Subject: [PATCH 103/134] oops fix the missing import --- Scripts/s4ap/utils/s4ap_career_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/s4ap/utils/s4ap_career_utils.py b/Scripts/s4ap/utils/s4ap_career_utils.py index 7ed14a5..9325db7 100644 --- a/Scripts/s4ap/utils/s4ap_career_utils.py +++ b/Scripts/s4ap/utils/s4ap_career_utils.py @@ -1,6 +1,6 @@ from careers.career_tuning import Career, CareerLevel, TunableCareerTrack from random import random -from typing import Callable, Iterator, Tuple, Union +from typing import Callable, Iterator, Tuple, Union, List from services import get_instance_manager from sims.sim_info import SimInfo from sims4.resources import Types From eef0778428a46407d89067775cebc2a75a67aecf Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Thu, 4 Dec 2025 17:25:10 -0700 Subject: [PATCH 104/134] start applying coderabbit feedback --- Scripts/s4ap/utils/s4ap_generic_utils.py | 2 +- Scripts/s4ap/utils/s4ap_sim_currency_utils.py | 3 +-- Scripts/s4ap/utils/s4ap_sim_utils.py | 2 +- Scripts/s4ap/utils/s4ap_trait_utils.py | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Scripts/s4ap/utils/s4ap_generic_utils.py b/Scripts/s4ap/utils/s4ap_generic_utils.py index b292dca..ba927cf 100644 --- a/Scripts/s4ap/utils/s4ap_generic_utils.py +++ b/Scripts/s4ap/utils/s4ap_generic_utils.py @@ -38,7 +38,7 @@ def trigger_autosave(*_) -> bool: return False @staticmethod - def load_instance(self, instance_type: Types, instance_id: int): + def load_instance(instance_type: Types, instance_id: int): """Load a resource instance (Trait, Buff, Mood, etc.) directly from the game.""" instance_manager = services.get_instance_manager(instance_type) if instance_manager is None: diff --git a/Scripts/s4ap/utils/s4ap_sim_currency_utils.py b/Scripts/s4ap/utils/s4ap_sim_currency_utils.py index e1aea1e..cf6e19e 100644 --- a/Scripts/s4ap/utils/s4ap_sim_currency_utils.py +++ b/Scripts/s4ap/utils/s4ap_sim_currency_utils.py @@ -1,5 +1,4 @@ from sims.sim_info import SimInfo -from protocolbuffers import Consts_pb2 class S4APSimCurrencyUtils: @@ -10,7 +9,7 @@ def add_simoleons_to_household(cls, sim_info: SimInfo, amount: int, reason: int, :param sim_info: The Sim whose household to modify. :param amount: The number of simoleons to add (negative values will subtract). - :param reason: A string reason for the funds change (for notifications/logs). + :param reason: A string reason for the funds change (from Consts_pb2). :return: True if successful, False otherwise. """ if sim_info is None or sim_info.household is None: diff --git a/Scripts/s4ap/utils/s4ap_sim_utils.py b/Scripts/s4ap/utils/s4ap_sim_utils.py index 68b9a10..9dead04 100644 --- a/Scripts/s4ap/utils/s4ap_sim_utils.py +++ b/Scripts/s4ap/utils/s4ap_sim_utils.py @@ -10,7 +10,7 @@ class S4APSimUtils: @staticmethod def get_sim_first_name(sim_info: SimInfo): - if sim_info is None or not hasattr('first_name'): + if sim_info is None or not hasattr(sim_info, 'first_name'): return '' return getattr(sim_info, 'first_name') diff --git a/Scripts/s4ap/utils/s4ap_trait_utils.py b/Scripts/s4ap/utils/s4ap_trait_utils.py index 7b71c88..8ff23a3 100644 --- a/Scripts/s4ap/utils/s4ap_trait_utils.py +++ b/Scripts/s4ap/utils/s4ap_trait_utils.py @@ -35,7 +35,7 @@ def load_trait_by_id(cls, trait) -> Optional['Trait']: try: trait_id = int(trait) - except Exception: + except (TypeError, ValueError): return None return S4APUtils.load_instance(Types.TRAIT, trait_id) \ No newline at end of file From d0967d20beba9d7fc59c819421105ca0601ef532 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Thu, 4 Dec 2025 17:27:54 -0700 Subject: [PATCH 105/134] more coderabbit feedback --- Scripts/s4ap/utils/s4ap_save_utils.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Scripts/s4ap/utils/s4ap_save_utils.py b/Scripts/s4ap/utils/s4ap_save_utils.py index 007cf4b..23209d6 100644 --- a/Scripts/s4ap/utils/s4ap_save_utils.py +++ b/Scripts/s4ap/utils/s4ap_save_utils.py @@ -1,4 +1,4 @@ -from typing import Any +from typing import Any, Union import services @@ -13,10 +13,13 @@ def get_save_slot() -> Any: :return: The current save slot. :return: Any """ - return services.get_persistence_service().get_save_slot_proto_buff() + persistence_service = services.get_persistence_service() + if persistence_service is None: + return None + return persistence_service.get_save_slot_proto_buff() @staticmethod - def get_save_slot_id() -> int: + def get_save_slot_id() -> Union[int, None]: """get_save_slot_id() Retrieve the identifier for the current save slot. @@ -24,4 +27,7 @@ def get_save_slot_id() -> int: :return: The identifier for the current save slot. :return: int """ - return S4APSaveUtils.get_save_slot().slot_id \ No newline at end of file + save_slot = S4APSaveUtils.get_save_slot() + if save_slot is None: + return None + return save_slot.slot_id \ No newline at end of file From ccd412fa1203ff550b95a6b7807aef945ef40dbe Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 16 Dec 2025 09:23:19 -0700 Subject: [PATCH 106/134] move package source to new repo (submodule will be added soon) --- ...882!00000000!F1C680E09B12C2B6.DSTImage.dds | Bin 262272 -> 0 bytes ...PieMenuCategory2.PieMenuCategoryTuning.xml | 5 -- ...1.Cactus_S4AP_BE5K5G6HW52.ActionTuning.xml | 11 --- ...7.Cactus_S4AP_2S3LJ6AQOL2.ActionTuning.xml | 10 --- ...A.Cactus_S4AP_UUV20239GU2.ActionTuning.xml | 11 --- ...0000!00566BE2CD18DAFC.English .StringTable | Bin 808 -> 0 bytes ...0000!02566BE2CD18DAFC.Chinese .StringTable | Bin 785 -> 0 bytes ...000000!03566BE2CD18DAFC.Czech .StringTable | Bin 785 -> 0 bytes ...00000!04566BE2CD18DAFC.Danish .StringTable | Bin 785 -> 0 bytes ...000000!05566BE2CD18DAFC.Dutch .StringTable | Bin 785 -> 0 bytes ...0000!06566BE2CD18DAFC.Finnish .StringTable | Bin 785 -> 0 bytes ...00000!07566BE2CD18DAFC.French .StringTable | Bin 875 -> 0 bytes ...00000!08566BE2CD18DAFC.German .StringTable | Bin 785 -> 0 bytes ...0000!0B566BE2CD18DAFC.Italian .StringTable | Bin 785 -> 0 bytes ...000!0C566BE2CD18DAFC.Japanese .StringTable | Bin 785 -> 0 bytes ...00000!0D566BE2CD18DAFC.Korean .StringTable | Bin 785 -> 0 bytes ...BE2CD18DAFC.Norwegian Nynorsk .StringTable | Bin 785 -> 0 bytes ...00000!0F566BE2CD18DAFC.Polish .StringTable | Bin 785 -> 0 bytes ...00000!10566BE2CD18DAFC.Unknown.StringTable | Bin 785 -> 0 bytes ...0!11566BE2CD18DAFC.Portuguese .StringTable | Bin 785 -> 0 bytes ...0000!12566BE2CD18DAFC.Russian .StringTable | Bin 785 -> 0 bytes ...0000!13566BE2CD18DAFC.Spanish .StringTable | Bin 785 -> 0 bytes ...0000!15566BE2CD18DAFC.Swedish .StringTable | Bin 785 -> 0 bytes ...6!0000000088B5FBB8.Constructor.SimData.xml | 31 -------- ...6!0000000089032333.Constructor.SimData.xml | 31 -------- ...6!000000008A606580.Constructor.SimData.xml | 31 -------- ...6!000000008E00A8E2.Constructor.SimData.xml | 31 -------- ...6!00000000942950EC.Constructor.SimData.xml | 31 -------- ...6!00000000ACEC4762.Constructor.SimData.xml | 31 -------- ...6!00000000B0C1684A.Constructor.SimData.xml | 31 -------- ...6!00000000B4713A54.Constructor.SimData.xml | 31 -------- ...6!00000000B629BB49.Constructor.SimData.xml | 31 -------- ...6!00000000BB971053.Constructor.SimData.xml | 31 -------- ...6!00000000C8D1ECF5.Constructor.SimData.xml | 31 -------- ...6!00000000D037694E.Constructor.SimData.xml | 31 -------- ...6!00000000D51559C9.Constructor.SimData.xml | 31 -------- ...6!00000000D6BFC3D1.Constructor.SimData.xml | 31 -------- ...6!00000000D79B9065.Constructor.SimData.xml | 31 -------- ...6!00000000D888EB85.Constructor.SimData.xml | 31 -------- ...6!00000000DA4F627F.Constructor.SimData.xml | 31 -------- ...6!00000000DAF19D9B.Constructor.SimData.xml | 31 -------- ...6!00000000E330058C.Constructor.SimData.xml | 31 -------- ...6!00000000E9CA5D38.Constructor.SimData.xml | 31 -------- ...6!00000000EA1784B3.Constructor.SimData.xml | 31 -------- ...6!00000000F3563747.Constructor.SimData.xml | 31 -------- ...6!00000000F93B00FF.Constructor.SimData.xml | 31 -------- ...6!00000000FEB64AAE.Constructor.SimData.xml | 31 -------- ...C.Cactus_S4AP_LockDancing:Buff.SimData.xml | 33 --------- ...C!000000008494610E.Constructor.SimData.xml | 60 --------------- ...C!0000000085944434.Constructor.SimData.xml | 60 --------------- ...C!00000000D04CC916.Constructor.SimData.xml | 60 --------------- ...C!00000000D04CC917.Constructor.SimData.xml | 60 --------------- ...C!00000000D04CC918.Constructor.SimData.xml | 60 --------------- ...C!00000000D04CC919.Constructor.SimData.xml | 60 --------------- ...C!00000000D04CC91A.Constructor.SimData.xml | 60 --------------- ...C!00000000D04CC91B.Constructor.SimData.xml | 60 --------------- ...C!00000000D04CC91C.Constructor.SimData.xml | 60 --------------- ...C!00000000D04CC91D.Constructor.SimData.xml | 60 --------------- ...C!00000000D04CC91E.Constructor.SimData.xml | 60 --------------- ...C!00000000D04CC91F.Constructor.SimData.xml | 60 --------------- ...C!00000000D14CCAF0.Constructor.SimData.xml | 60 --------------- ...C!00000000D14CCAF1.Constructor.SimData.xml | 60 --------------- ...C!00000000D14CCAF2.Constructor.SimData.xml | 60 --------------- ...C!00000000D14CCAF3.Constructor.SimData.xml | 60 --------------- ...C!00000000D14CCAF4.Constructor.SimData.xml | 60 --------------- ...C!00000000D14CCAF6.Constructor.SimData.xml | 60 --------------- ...C!00000000D301A22C.Constructor.SimData.xml | 60 --------------- ...C!00000000D7924B70.Constructor.SimData.xml | 60 --------------- ...C!00000000D7924B71.Constructor.SimData.xml | 60 --------------- ...C!00000000D7924B72.Constructor.SimData.xml | 60 --------------- ...C!00000000D7924B73.Constructor.SimData.xml | 60 --------------- ...C!00000000D7924B76.Constructor.SimData.xml | 60 --------------- ...C!00000000D7924B77.Constructor.SimData.xml | 60 --------------- ...C!00000000D7924B7C.Constructor.SimData.xml | 60 --------------- ...C!00000000D7924B7D.Constructor.SimData.xml | 60 --------------- ....Cactus_S4AP_Trait_LockDancing.SimData.xml | 69 ------------------ ...7!00000000A85DB38B.Constructor.SimData.xml | 27 ------- ...B8.Cactus_S4AP_Trait21:Buff.BuffTuning.xml | 21 ------ ...33.Cactus_S4AP_Trait24:Buff.BuffTuning.xml | 18 ----- ...80.Cactus_S4AP_Trait14:Buff.BuffTuning.xml | 21 ------ ...8E2.Cactus_S4AP_Trait5:Buff.BuffTuning.xml | 21 ------ ...0EC.Cactus_S4AP_Trait3:Buff.BuffTuning.xml | 21 ------ ...62.Cactus_S4AP_Trait23:Buff.BuffTuning.xml | 18 ----- ...4A.Cactus_S4AP_Trait16:Buff.BuffTuning.xml | 21 ------ ...54.Cactus_S4AP_Trait10:Buff.BuffTuning.xml | 21 ------ ...B49.Cactus_S4AP_Trait4:Buff.BuffTuning.xml | 18 ----- ...53.Cactus_S4AP_Trait19:Buff.BuffTuning.xml | 21 ------ ...ECF5.Cactus_S4AP_Trait:Buff.BuffTuning.xml | 21 ------ ...4E.Cactus_S4AP_Trait12:Buff.BuffTuning.xml | 21 ------ ...C9.Cactus_S4AP_Trait22:Buff.BuffTuning.xml | 18 ----- ...s_S4AP_LockProgramming:Buff.BuffTuning.xml | 21 ------ ...065.Cactus_S4AP_Trait8:Buff.BuffTuning.xml | 21 ------ ...85.Cactus_S4AP_Trait13:Buff.BuffTuning.xml | 21 ------ ...27F.Cactus_S4AP_Trait6:Buff.BuffTuning.xml | 21 ------ ...9B.Cactus_S4AP_Trait11:Buff.BuffTuning.xml | 21 ------ ...8C.Cactus_S4AP_Trait18:Buff.BuffTuning.xml | 21 ------ ...D38.Cactus_S4AP_Trait7:Buff.BuffTuning.xml | 21 ------ ...4B3.Cactus_S4AP_Trait2:Buff.BuffTuning.xml | 21 ------ ...47.Cactus_S4AP_Trait15:Buff.BuffTuning.xml | 21 ------ ...FF.Cactus_S4AP_Trait20:Buff.BuffTuning.xml | 21 ------ ...AAE.Cactus_S4AP_Trait9:Buff.BuffTuning.xml | 21 ------ ...actus_S4AP_LockDancing:Buff.BuffTuning.xml | 17 ----- ...6DB798A7C.Cactus_S4AP_LockDancing:Buff.xml | 16 ---- ...!0000000000000000.S4SMergedPackageManifest | Bin 2224 -> 0 bytes ...actus_S4AP_ResyncLocations.TraitTuning.xml | 14 ---- ...actus_S4AP_ShowYamlOptions.TraitTuning.xml | 14 ---- ...4CC916.Cactus_S4AP_Trait19.TraitTuning.xml | 19 ----- ...4CC917.Cactus_S4AP_Trait18.TraitTuning.xml | 19 ----- ...actus_S4AP_LockProgramming.TraitTuning.xml | 19 ----- ...4CC919.Cactus_S4AP_Trait16.TraitTuning.xml | 19 ----- ...4CC91A.Cactus_S4AP_Trait15.TraitTuning.xml | 19 ----- ...4CC91B.Cactus_S4AP_Trait14.TraitTuning.xml | 19 ----- ...4CC91C.Cactus_S4AP_Trait13.TraitTuning.xml | 19 ----- ...4CC91D.Cactus_S4AP_Trait12.TraitTuning.xml | 19 ----- ...4CC91E.Cactus_S4AP_Trait11.TraitTuning.xml | 19 ----- ...4CC91F.Cactus_S4AP_Trait10.TraitTuning.xml | 19 ----- ...4CCAF0.Cactus_S4AP_Trait22.TraitTuning.xml | 19 ----- ...4CCAF1.Cactus_S4AP_Trait23.TraitTuning.xml | 19 ----- ...4CCAF2.Cactus_S4AP_Trait20.TraitTuning.xml | 19 ----- ...4CCAF3.Cactus_S4AP_Trait21.TraitTuning.xml | 19 ----- ...4CCAF4.Cactus_S4AP_Trait26.TraitTuning.xml | 14 ---- ...4CCAF6.Cactus_S4AP_Trait24.TraitTuning.xml | 19 ----- ...D301A22C.Cactus_S4AP_Trait.TraitTuning.xml | 19 ----- ...7924B70.Cactus_S4AP_Trait4.TraitTuning.xml | 19 ----- ...7924B71.Cactus_S4AP_Trait5.TraitTuning.xml | 19 ----- ...7924B72.Cactus_S4AP_Trait6.TraitTuning.xml | 19 ----- ...7924B73.Cactus_S4AP_Trait7.TraitTuning.xml | 19 ----- ...7924B76.Cactus_S4AP_Trait2.TraitTuning.xml | 19 ----- ...7924B77.Cactus_S4AP_Trait3.TraitTuning.xml | 19 ----- ...7924B7C.Cactus_S4AP_Trait8.TraitTuning.xml | 19 ----- ...7924B7D.Cactus_S4AP_Trait9.TraitTuning.xml | 19 ----- ...tus_S4AP_Trait_LockDancing.TraitTuning.xml | 21 ------ ...AA6F0CF6.Cactus_S4AP_Trait_LockDancing.xml | 18 ----- ...mlOptionsInteraction.InteractionTuning.xml | 52 ------------- ...ractionExperimental2.InteractionTuning.xml | 52 ------------- ...LocationsInteraction.InteractionTuning.xml | 52 ------------- 136 files changed, 3748 deletions(-) delete mode 100644 Package/Cactus_S4AP (package source)/00B2D882!00000000!F1C680E09B12C2B6.DSTImage.dds delete mode 100644 Package/Cactus_S4AP (package source)/03E9D964!00000000!00000000A85DB38B.Cactus_S4AP_PieMenuCategory2.PieMenuCategoryTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/0C772E27!00000000!000000009952F751.Cactus_S4AP_BE5K5G6HW52.ActionTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/0C772E27!00000000!00000000BCFDFDC7.Cactus_S4AP_2S3LJ6AQOL2.ActionTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/0C772E27!00000000!00000000C26EC7CA.Cactus_S4AP_UUV20239GU2.ActionTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/220557DA!00000000!00566BE2CD18DAFC.English .StringTable delete mode 100644 Package/Cactus_S4AP (package source)/220557DA!00000000!02566BE2CD18DAFC.Chinese .StringTable delete mode 100644 Package/Cactus_S4AP (package source)/220557DA!00000000!03566BE2CD18DAFC.Czech .StringTable delete mode 100644 Package/Cactus_S4AP (package source)/220557DA!00000000!04566BE2CD18DAFC.Danish .StringTable delete mode 100644 Package/Cactus_S4AP (package source)/220557DA!00000000!05566BE2CD18DAFC.Dutch .StringTable delete mode 100644 Package/Cactus_S4AP (package source)/220557DA!00000000!06566BE2CD18DAFC.Finnish .StringTable delete mode 100644 Package/Cactus_S4AP (package source)/220557DA!00000000!07566BE2CD18DAFC.French .StringTable delete mode 100644 Package/Cactus_S4AP (package source)/220557DA!00000000!08566BE2CD18DAFC.German .StringTable delete mode 100644 Package/Cactus_S4AP (package source)/220557DA!00000000!0B566BE2CD18DAFC.Italian .StringTable delete mode 100644 Package/Cactus_S4AP (package source)/220557DA!00000000!0C566BE2CD18DAFC.Japanese .StringTable delete mode 100644 Package/Cactus_S4AP (package source)/220557DA!00000000!0D566BE2CD18DAFC.Korean .StringTable delete mode 100644 Package/Cactus_S4AP (package source)/220557DA!00000000!0E566BE2CD18DAFC.Norwegian Nynorsk .StringTable delete mode 100644 Package/Cactus_S4AP (package source)/220557DA!00000000!0F566BE2CD18DAFC.Polish .StringTable delete mode 100644 Package/Cactus_S4AP (package source)/220557DA!00000000!10566BE2CD18DAFC.Unknown.StringTable delete mode 100644 Package/Cactus_S4AP (package source)/220557DA!00000000!11566BE2CD18DAFC.Portuguese .StringTable delete mode 100644 Package/Cactus_S4AP (package source)/220557DA!00000000!12566BE2CD18DAFC.Russian .StringTable delete mode 100644 Package/Cactus_S4AP (package source)/220557DA!00000000!13566BE2CD18DAFC.Spanish .StringTable delete mode 100644 Package/Cactus_S4AP (package source)/220557DA!00000000!15566BE2CD18DAFC.Swedish .StringTable delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!0000000088B5FBB8.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!0000000089032333.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!000000008A606580.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!000000008E00A8E2.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000942950EC.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000ACEC4762.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000B0C1684A.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000B4713A54.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000B629BB49.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000BB971053.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000C8D1ECF5.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000D037694E.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000D51559C9.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000D6BFC3D1.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000D79B9065.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000D888EB85.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000DA4F627F.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000DAF19D9B.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000E330058C.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000E9CA5D38.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000EA1784B3.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000F3563747.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000F93B00FF.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000FEB64AAE.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!83246516DB798A7C.Cactus_S4AP_LockDancing:Buff.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!000000008494610E.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!0000000085944434.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC916.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC917.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC918.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC919.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91A.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91B.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91C.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91D.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91E.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91F.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF0.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF1.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF2.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF3.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF4.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF6.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D301A22C.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B70.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B71.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B72.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B73.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B76.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B77.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B7C.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B7D.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!A951AD6CAA6F0CF6.Cactus_S4AP_Trait_LockDancing.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/545AC67A!00E9D967!00000000A85DB38B.Constructor.SimData.xml delete mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!0000000088B5FBB8.Cactus_S4AP_Trait21:Buff.BuffTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!0000000089032333.Cactus_S4AP_Trait24:Buff.BuffTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!000000008A606580.Cactus_S4AP_Trait14:Buff.BuffTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!000000008E00A8E2.Cactus_S4AP_Trait5:Buff.BuffTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!00000000942950EC.Cactus_S4AP_Trait3:Buff.BuffTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!00000000ACEC4762.Cactus_S4AP_Trait23:Buff.BuffTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!00000000B0C1684A.Cactus_S4AP_Trait16:Buff.BuffTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!00000000B4713A54.Cactus_S4AP_Trait10:Buff.BuffTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!00000000B629BB49.Cactus_S4AP_Trait4:Buff.BuffTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!00000000BB971053.Cactus_S4AP_Trait19:Buff.BuffTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!00000000C8D1ECF5.Cactus_S4AP_Trait:Buff.BuffTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D037694E.Cactus_S4AP_Trait12:Buff.BuffTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D51559C9.Cactus_S4AP_Trait22:Buff.BuffTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D6BFC3D1.Cactus_S4AP_LockProgramming:Buff.BuffTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D79B9065.Cactus_S4AP_Trait8:Buff.BuffTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D888EB85.Cactus_S4AP_Trait13:Buff.BuffTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!00000000DA4F627F.Cactus_S4AP_Trait6:Buff.BuffTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!00000000DAF19D9B.Cactus_S4AP_Trait11:Buff.BuffTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!00000000E330058C.Cactus_S4AP_Trait18:Buff.BuffTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!00000000E9CA5D38.Cactus_S4AP_Trait7:Buff.BuffTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!00000000EA1784B3.Cactus_S4AP_Trait2:Buff.BuffTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!00000000F3563747.Cactus_S4AP_Trait15:Buff.BuffTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!00000000F93B00FF.Cactus_S4AP_Trait20:Buff.BuffTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!00000000FEB64AAE.Cactus_S4AP_Trait9:Buff.BuffTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!83246516DB798A7C.Cactus_S4AP_LockDancing:Buff.BuffTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/6017E896!00000000!83246516DB798A7C.Cactus_S4AP_LockDancing:Buff.xml delete mode 100644 Package/Cactus_S4AP (package source)/7FB6AD8A!00000000!0000000000000000.S4SMergedPackageManifest delete mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!000000008494610E.Cactus_S4AP_ResyncLocations.TraitTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!0000000085944434.Cactus_S4AP_ShowYamlOptions.TraitTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC916.Cactus_S4AP_Trait19.TraitTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC917.Cactus_S4AP_Trait18.TraitTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC918.Cactus_S4AP_LockProgramming.TraitTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC919.Cactus_S4AP_Trait16.TraitTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91A.Cactus_S4AP_Trait15.TraitTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91B.Cactus_S4AP_Trait14.TraitTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91C.Cactus_S4AP_Trait13.TraitTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91D.Cactus_S4AP_Trait12.TraitTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91E.Cactus_S4AP_Trait11.TraitTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91F.Cactus_S4AP_Trait10.TraitTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF0.Cactus_S4AP_Trait22.TraitTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF1.Cactus_S4AP_Trait23.TraitTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF2.Cactus_S4AP_Trait20.TraitTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF3.Cactus_S4AP_Trait21.TraitTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF4.Cactus_S4AP_Trait26.TraitTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF6.Cactus_S4AP_Trait24.TraitTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D301A22C.Cactus_S4AP_Trait.TraitTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B70.Cactus_S4AP_Trait4.TraitTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B71.Cactus_S4AP_Trait5.TraitTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B72.Cactus_S4AP_Trait6.TraitTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B73.Cactus_S4AP_Trait7.TraitTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B76.Cactus_S4AP_Trait2.TraitTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B77.Cactus_S4AP_Trait3.TraitTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B7C.Cactus_S4AP_Trait8.TraitTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B7D.Cactus_S4AP_Trait9.TraitTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!A951AD6CAA6F0CF6.Cactus_S4AP_Trait_LockDancing.TraitTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!A951AD6CAA6F0CF6.Cactus_S4AP_Trait_LockDancing.xml delete mode 100644 Package/Cactus_S4AP (package source)/E882D22F!00000000!00000000A07795F4.Cactus_S4AP_ShowYamlOptionsInteraction.InteractionTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/E882D22F!00000000!00000000C5690C31.Cactus_S4AP_SuperInteractionExperimental2.InteractionTuning.xml delete mode 100644 Package/Cactus_S4AP (package source)/E882D22F!00000000!00000000FE6A648E.Cactus_S4AP_ResyncLocationsInteraction.InteractionTuning.xml diff --git a/Package/Cactus_S4AP (package source)/00B2D882!00000000!F1C680E09B12C2B6.DSTImage.dds b/Package/Cactus_S4AP (package source)/00B2D882!00000000!F1C680E09B12C2B6.DSTImage.dds deleted file mode 100644 index dab1e4756d649c6f68bad85804610b815c4b8a4e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 262272 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 F{{gkGYFhvR diff --git a/Package/Cactus_S4AP (package source)/03E9D964!00000000!00000000A85DB38B.Cactus_S4AP_PieMenuCategory2.PieMenuCategoryTuning.xml b/Package/Cactus_S4AP (package source)/03E9D964!00000000!00000000A85DB38B.Cactus_S4AP_PieMenuCategory2.PieMenuCategoryTuning.xml deleted file mode 100644 index 58ce299..0000000 --- a/Package/Cactus_S4AP (package source)/03E9D964!00000000!00000000A85DB38B.Cactus_S4AP_PieMenuCategory2.PieMenuCategoryTuning.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - 0x85992464 - 2f7d0004:00000000:f1c680e09b12c2b6 - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/0C772E27!00000000!000000009952F751.Cactus_S4AP_BE5K5G6HW52.ActionTuning.xml b/Package/Cactus_S4AP (package source)/0C772E27!00000000!000000009952F751.Cactus_S4AP_BE5K5G6HW52.ActionTuning.xml deleted file mode 100644 index 2aeb814..0000000 --- a/Package/Cactus_S4AP (package source)/0C772E27!00000000!000000009952F751.Cactus_S4AP_BE5K5G6HW52.ActionTuning.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - 2224316686 - Actor - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/0C772E27!00000000!00000000BCFDFDC7.Cactus_S4AP_2S3LJ6AQOL2.ActionTuning.xml b/Package/Cactus_S4AP (package source)/0C772E27!00000000!00000000BCFDFDC7.Cactus_S4AP_2S3LJ6AQOL2.ActionTuning.xml deleted file mode 100644 index a35e572..0000000 --- a/Package/Cactus_S4AP (package source)/0C772E27!00000000!00000000BCFDFDC7.Cactus_S4AP_2S3LJ6AQOL2.ActionTuning.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - 3511470836 - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/0C772E27!00000000!00000000C26EC7CA.Cactus_S4AP_UUV20239GU2.ActionTuning.xml b/Package/Cactus_S4AP (package source)/0C772E27!00000000!00000000C26EC7CA.Cactus_S4AP_UUV20239GU2.ActionTuning.xml deleted file mode 100644 index 4133735..0000000 --- a/Package/Cactus_S4AP (package source)/0C772E27!00000000!00000000C26EC7CA.Cactus_S4AP_UUV20239GU2.ActionTuning.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - 2241086516 - Actor - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/220557DA!00000000!00566BE2CD18DAFC.English .StringTable b/Package/Cactus_S4AP (package source)/220557DA!00000000!00566BE2CD18DAFC.English .StringTable deleted file mode 100644 index 5bbc9768e077c3e7763e7dc49db6e1de4888a068..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 808 zcmZuvPe>I(9R5{wDoWFePAw!zP(fOG@}M9UJSo~byi*Oc^LB?fJG0EpzPAfrjVS2Q zB`ZQg=+q$t`vcacO9l}^Sn%*9W_e2xj1roi-F*l;$M5_7zVDm)#=SaR*$r?M%2VA5 z5Rdh3Krgs~XgXCCGUrmHso=`F%wpxZb;_7C8Z%8JMv3I}6E~rA>-4U{-{a5$SBOeE zb}9lREAsxr=P5XnkB_2+hH+R(R!D;|b?roB9lC)DT#uyiB??2zeU+JhY^HN16$qV? zQIJ|{brRh(A+oKICV~k+$1gtH@ecM|9E*^6IeL1e_f3KNG1W*~jmhgHKcNfq`<+LW zJHtXK?VL%5x;yT}!L3aHsk4b3yZd3gt^OqVI{O#)S#OhvVr%kt?awM4vY<3!iB^~r zj)^5_7r(X4+hn&0Oj@N=Mz9d|@&VRg?_GhzmiI+0L!vjckEWNNY?rdnq`bYXCrlZc za*b+El(L3X)#o#CAQwc^BfNCF@#V+&f(Q`zXnSMe&hf?K=^9ip%B{|?lm8al@+v4* z9;Ry>MPUu<5#ghDmrkwqsn}>rs>_X+D@(0*j|vBr)U1I&F#iJf9 z4v?fOM0T=k`rNGok4%ScW%qHv=G4WQU}2iU>ndwEXngt0I?&I4*Pj E2mEC(_W%F@ diff --git a/Package/Cactus_S4AP (package source)/220557DA!00000000!02566BE2CD18DAFC.Chinese .StringTable b/Package/Cactus_S4AP (package source)/220557DA!00000000!02566BE2CD18DAFC.Chinese .StringTable deleted file mode 100644 index 74712d49ee73c9c8d69de0c890299282755f6db8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 785 zcmZuvPe>L)9Q{>vDooP~FR=$ff(p{gQwIgf;FF@QgQps1=i42=*_mZ#_WO3hs}Thq zx@1L2c%=W?W};L5qeV&%9E%9t}AGfg8#iR4Sux1ek1^u7zfr=SzA5|wi7 z)C5LW%1l4B(#4VrgwDt) zNG-KKgYKIU*;Yss!GxdVm!9o;3x_O@MM%6HJu}+>xoe$v1PG<1*xkOIhd%xS(U=n;;_zNA@+vK6xn!MTgvkpfsC{0+R6{dt^ zV#$S-uWj=-*)0N-R_T-xEJUMxfX!D2*Wj4teG$u$=>OTrbE{8xOF3Xt-ua=YO&OVT zooY^$vWBx0&*$NAE{LQ@cBe?ZSd)50_^9gAskc8C8!bt7x$$yswO#e7a6n1j8u&v?FW^A_YuxNFsQE6jTukBs rNvc9*C%fm)-!AaTbXY07Px=;%HX@3+u)|*8!zm*>ER9n{7>c5Q+Ic3@ diff --git a/Package/Cactus_S4AP (package source)/220557DA!00000000!03566BE2CD18DAFC.Czech .StringTable b/Package/Cactus_S4AP (package source)/220557DA!00000000!03566BE2CD18DAFC.Czech .StringTable deleted file mode 100644 index 74712d49ee73c9c8d69de0c890299282755f6db8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 785 zcmZuvPe>L)9Q{>vDooP~FR=$ff(p{gQwIgf;FF@QgQps1=i42=*_mZ#_WO3hs}Thq zx@1L2c%=W?W};L5qeV&%9E%9t}AGfg8#iR4Sux1ek1^u7zfr=SzA5|wi7 z)C5LW%1l4B(#4VrgwDt) zNG-KKgYKIU*;Yss!GxdVm!9o;3x_O@MM%6HJu}+>xoe$v1PG<1*xkOIhd%xS(U=n;;_zNA@+vK6xn!MTgvkpfsC{0+R6{dt^ zV#$S-uWj=-*)0N-R_T-xEJUMxfX!D2*Wj4teG$u$=>OTrbE{8xOF3Xt-ua=YO&OVT zooY^$vWBx0&*$NAE{LQ@cBe?ZSd)50_^9gAskc8C8!bt7x$$yswO#e7a6n1j8u&v?FW^A_YuxNFsQE6jTukBs rNvc9*C%fm)-!AaTbXY07Px=;%HX@3+u)|*8!zm*>ER9n{7>c5Q+Ic3@ diff --git a/Package/Cactus_S4AP (package source)/220557DA!00000000!04566BE2CD18DAFC.Danish .StringTable b/Package/Cactus_S4AP (package source)/220557DA!00000000!04566BE2CD18DAFC.Danish .StringTable deleted file mode 100644 index 74712d49ee73c9c8d69de0c890299282755f6db8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 785 zcmZuvPe>L)9Q{>vDooP~FR=$ff(p{gQwIgf;FF@QgQps1=i42=*_mZ#_WO3hs}Thq zx@1L2c%=W?W};L5qeV&%9E%9t}AGfg8#iR4Sux1ek1^u7zfr=SzA5|wi7 z)C5LW%1l4B(#4VrgwDt) zNG-KKgYKIU*;Yss!GxdVm!9o;3x_O@MM%6HJu}+>xoe$v1PG<1*xkOIhd%xS(U=n;;_zNA@+vK6xn!MTgvkpfsC{0+R6{dt^ zV#$S-uWj=-*)0N-R_T-xEJUMxfX!D2*Wj4teG$u$=>OTrbE{8xOF3Xt-ua=YO&OVT zooY^$vWBx0&*$NAE{LQ@cBe?ZSd)50_^9gAskc8C8!bt7x$$yswO#e7a6n1j8u&v?FW^A_YuxNFsQE6jTukBs rNvc9*C%fm)-!AaTbXY07Px=;%HX@3+u)|*8!zm*>ER9n{7>c5Q+Ic3@ diff --git a/Package/Cactus_S4AP (package source)/220557DA!00000000!05566BE2CD18DAFC.Dutch .StringTable b/Package/Cactus_S4AP (package source)/220557DA!00000000!05566BE2CD18DAFC.Dutch .StringTable deleted file mode 100644 index 74712d49ee73c9c8d69de0c890299282755f6db8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 785 zcmZuvPe>L)9Q{>vDooP~FR=$ff(p{gQwIgf;FF@QgQps1=i42=*_mZ#_WO3hs}Thq zx@1L2c%=W?W};L5qeV&%9E%9t}AGfg8#iR4Sux1ek1^u7zfr=SzA5|wi7 z)C5LW%1l4B(#4VrgwDt) zNG-KKgYKIU*;Yss!GxdVm!9o;3x_O@MM%6HJu}+>xoe$v1PG<1*xkOIhd%xS(U=n;;_zNA@+vK6xn!MTgvkpfsC{0+R6{dt^ zV#$S-uWj=-*)0N-R_T-xEJUMxfX!D2*Wj4teG$u$=>OTrbE{8xOF3Xt-ua=YO&OVT zooY^$vWBx0&*$NAE{LQ@cBe?ZSd)50_^9gAskc8C8!bt7x$$yswO#e7a6n1j8u&v?FW^A_YuxNFsQE6jTukBs rNvc9*C%fm)-!AaTbXY07Px=;%HX@3+u)|*8!zm*>ER9n{7>c5Q+Ic3@ diff --git a/Package/Cactus_S4AP (package source)/220557DA!00000000!06566BE2CD18DAFC.Finnish .StringTable b/Package/Cactus_S4AP (package source)/220557DA!00000000!06566BE2CD18DAFC.Finnish .StringTable deleted file mode 100644 index 74712d49ee73c9c8d69de0c890299282755f6db8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 785 zcmZuvPe>L)9Q{>vDooP~FR=$ff(p{gQwIgf;FF@QgQps1=i42=*_mZ#_WO3hs}Thq zx@1L2c%=W?W};L5qeV&%9E%9t}AGfg8#iR4Sux1ek1^u7zfr=SzA5|wi7 z)C5LW%1l4B(#4VrgwDt) zNG-KKgYKIU*;Yss!GxdVm!9o;3x_O@MM%6HJu}+>xoe$v1PG<1*xkOIhd%xS(U=n;;_zNA@+vK6xn!MTgvkpfsC{0+R6{dt^ zV#$S-uWj=-*)0N-R_T-xEJUMxfX!D2*Wj4teG$u$=>OTrbE{8xOF3Xt-ua=YO&OVT zooY^$vWBx0&*$NAE{LQ@cBe?ZSd)50_^9gAskc8C8!bt7x$$yswO#e7a6n1j8u&v?FW^A_YuxNFsQE6jTukBs rNvc9*C%fm)-!AaTbXY07Px=;%HX@3+u)|*8!zm*>ER9n{7>c5Q+Ic3@ diff --git a/Package/Cactus_S4AP (package source)/220557DA!00000000!07566BE2CD18DAFC.French .StringTable b/Package/Cactus_S4AP (package source)/220557DA!00000000!07566BE2CD18DAFC.French .StringTable deleted file mode 100644 index 12a3549bfea707fc0fe6e3b3ff3c84b3fb100b03..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 875 zcmZ`%J!lj`6n-jJiY6K~Ho8SXL=Bjjq*6HLP{Ak|EmG+)JGc9|`B`RWFL#hOA_^8Z zMn!_A5-f}mQHVBaj36RN6pmCO{-iSyh-kpQx!ofk-oiHDH{Z{^H$#_Co!<(uAF}W9 zW`KCKXB|#Lu24W4GVO6@yo-@VC5<;s1oxOtFmEvC79)<7SQcx~XWnTgqS+^wNy?0z zAHNR!TAOS+@pB9gz$IoXl7?DIG-*^`M4V72n6zg0?1xD>{IAOeEHM(7n*zN-QbrMr zD@RIe&;eZ0Vx(1|i4Z6QQ$)_+ja23`Dpa;cMq$NKD-+}nv^$l+vf?VJ?dz4~h)__Hz3&>~(yg zVl9~6$Uc}_deo|GPj}zVZ+0BooVb8iGGkn!$>C?yu&eG#w9jM~cJ1TWFDVfc>0?7N zaO==wI>r(zj?(%3IQnOyVQ<3B<$h&#JzZW2eWn7^*sE8lzE2e+8f~U{vAk4m?9|W@ zS-}Ma1M|XLZ<3`TV!>+k>JrNSA++n}#-WY6y MoKA8h#z_?Y1+Vr^)Bpeg diff --git a/Package/Cactus_S4AP (package source)/220557DA!00000000!08566BE2CD18DAFC.German .StringTable b/Package/Cactus_S4AP (package source)/220557DA!00000000!08566BE2CD18DAFC.German .StringTable deleted file mode 100644 index 74712d49ee73c9c8d69de0c890299282755f6db8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 785 zcmZuvPe>L)9Q{>vDooP~FR=$ff(p{gQwIgf;FF@QgQps1=i42=*_mZ#_WO3hs}Thq zx@1L2c%=W?W};L5qeV&%9E%9t}AGfg8#iR4Sux1ek1^u7zfr=SzA5|wi7 z)C5LW%1l4B(#4VrgwDt) zNG-KKgYKIU*;Yss!GxdVm!9o;3x_O@MM%6HJu}+>xoe$v1PG<1*xkOIhd%xS(U=n;;_zNA@+vK6xn!MTgvkpfsC{0+R6{dt^ zV#$S-uWj=-*)0N-R_T-xEJUMxfX!D2*Wj4teG$u$=>OTrbE{8xOF3Xt-ua=YO&OVT zooY^$vWBx0&*$NAE{LQ@cBe?ZSd)50_^9gAskc8C8!bt7x$$yswO#e7a6n1j8u&v?FW^A_YuxNFsQE6jTukBs rNvc9*C%fm)-!AaTbXY07Px=;%HX@3+u)|*8!zm*>ER9n{7>c5Q+Ic3@ diff --git a/Package/Cactus_S4AP (package source)/220557DA!00000000!0B566BE2CD18DAFC.Italian .StringTable b/Package/Cactus_S4AP (package source)/220557DA!00000000!0B566BE2CD18DAFC.Italian .StringTable deleted file mode 100644 index 74712d49ee73c9c8d69de0c890299282755f6db8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 785 zcmZuvPe>L)9Q{>vDooP~FR=$ff(p{gQwIgf;FF@QgQps1=i42=*_mZ#_WO3hs}Thq zx@1L2c%=W?W};L5qeV&%9E%9t}AGfg8#iR4Sux1ek1^u7zfr=SzA5|wi7 z)C5LW%1l4B(#4VrgwDt) zNG-KKgYKIU*;Yss!GxdVm!9o;3x_O@MM%6HJu}+>xoe$v1PG<1*xkOIhd%xS(U=n;;_zNA@+vK6xn!MTgvkpfsC{0+R6{dt^ zV#$S-uWj=-*)0N-R_T-xEJUMxfX!D2*Wj4teG$u$=>OTrbE{8xOF3Xt-ua=YO&OVT zooY^$vWBx0&*$NAE{LQ@cBe?ZSd)50_^9gAskc8C8!bt7x$$yswO#e7a6n1j8u&v?FW^A_YuxNFsQE6jTukBs rNvc9*C%fm)-!AaTbXY07Px=;%HX@3+u)|*8!zm*>ER9n{7>c5Q+Ic3@ diff --git a/Package/Cactus_S4AP (package source)/220557DA!00000000!0C566BE2CD18DAFC.Japanese .StringTable b/Package/Cactus_S4AP (package source)/220557DA!00000000!0C566BE2CD18DAFC.Japanese .StringTable deleted file mode 100644 index 74712d49ee73c9c8d69de0c890299282755f6db8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 785 zcmZuvPe>L)9Q{>vDooP~FR=$ff(p{gQwIgf;FF@QgQps1=i42=*_mZ#_WO3hs}Thq zx@1L2c%=W?W};L5qeV&%9E%9t}AGfg8#iR4Sux1ek1^u7zfr=SzA5|wi7 z)C5LW%1l4B(#4VrgwDt) zNG-KKgYKIU*;Yss!GxdVm!9o;3x_O@MM%6HJu}+>xoe$v1PG<1*xkOIhd%xS(U=n;;_zNA@+vK6xn!MTgvkpfsC{0+R6{dt^ zV#$S-uWj=-*)0N-R_T-xEJUMxfX!D2*Wj4teG$u$=>OTrbE{8xOF3Xt-ua=YO&OVT zooY^$vWBx0&*$NAE{LQ@cBe?ZSd)50_^9gAskc8C8!bt7x$$yswO#e7a6n1j8u&v?FW^A_YuxNFsQE6jTukBs rNvc9*C%fm)-!AaTbXY07Px=;%HX@3+u)|*8!zm*>ER9n{7>c5Q+Ic3@ diff --git a/Package/Cactus_S4AP (package source)/220557DA!00000000!0D566BE2CD18DAFC.Korean .StringTable b/Package/Cactus_S4AP (package source)/220557DA!00000000!0D566BE2CD18DAFC.Korean .StringTable deleted file mode 100644 index 74712d49ee73c9c8d69de0c890299282755f6db8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 785 zcmZuvPe>L)9Q{>vDooP~FR=$ff(p{gQwIgf;FF@QgQps1=i42=*_mZ#_WO3hs}Thq zx@1L2c%=W?W};L5qeV&%9E%9t}AGfg8#iR4Sux1ek1^u7zfr=SzA5|wi7 z)C5LW%1l4B(#4VrgwDt) zNG-KKgYKIU*;Yss!GxdVm!9o;3x_O@MM%6HJu}+>xoe$v1PG<1*xkOIhd%xS(U=n;;_zNA@+vK6xn!MTgvkpfsC{0+R6{dt^ zV#$S-uWj=-*)0N-R_T-xEJUMxfX!D2*Wj4teG$u$=>OTrbE{8xOF3Xt-ua=YO&OVT zooY^$vWBx0&*$NAE{LQ@cBe?ZSd)50_^9gAskc8C8!bt7x$$yswO#e7a6n1j8u&v?FW^A_YuxNFsQE6jTukBs rNvc9*C%fm)-!AaTbXY07Px=;%HX@3+u)|*8!zm*>ER9n{7>c5Q+Ic3@ diff --git a/Package/Cactus_S4AP (package source)/220557DA!00000000!0E566BE2CD18DAFC.Norwegian Nynorsk .StringTable b/Package/Cactus_S4AP (package source)/220557DA!00000000!0E566BE2CD18DAFC.Norwegian Nynorsk .StringTable deleted file mode 100644 index 74712d49ee73c9c8d69de0c890299282755f6db8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 785 zcmZuvPe>L)9Q{>vDooP~FR=$ff(p{gQwIgf;FF@QgQps1=i42=*_mZ#_WO3hs}Thq zx@1L2c%=W?W};L5qeV&%9E%9t}AGfg8#iR4Sux1ek1^u7zfr=SzA5|wi7 z)C5LW%1l4B(#4VrgwDt) zNG-KKgYKIU*;Yss!GxdVm!9o;3x_O@MM%6HJu}+>xoe$v1PG<1*xkOIhd%xS(U=n;;_zNA@+vK6xn!MTgvkpfsC{0+R6{dt^ zV#$S-uWj=-*)0N-R_T-xEJUMxfX!D2*Wj4teG$u$=>OTrbE{8xOF3Xt-ua=YO&OVT zooY^$vWBx0&*$NAE{LQ@cBe?ZSd)50_^9gAskc8C8!bt7x$$yswO#e7a6n1j8u&v?FW^A_YuxNFsQE6jTukBs rNvc9*C%fm)-!AaTbXY07Px=;%HX@3+u)|*8!zm*>ER9n{7>c5Q+Ic3@ diff --git a/Package/Cactus_S4AP (package source)/220557DA!00000000!0F566BE2CD18DAFC.Polish .StringTable b/Package/Cactus_S4AP (package source)/220557DA!00000000!0F566BE2CD18DAFC.Polish .StringTable deleted file mode 100644 index 74712d49ee73c9c8d69de0c890299282755f6db8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 785 zcmZuvPe>L)9Q{>vDooP~FR=$ff(p{gQwIgf;FF@QgQps1=i42=*_mZ#_WO3hs}Thq zx@1L2c%=W?W};L5qeV&%9E%9t}AGfg8#iR4Sux1ek1^u7zfr=SzA5|wi7 z)C5LW%1l4B(#4VrgwDt) zNG-KKgYKIU*;Yss!GxdVm!9o;3x_O@MM%6HJu}+>xoe$v1PG<1*xkOIhd%xS(U=n;;_zNA@+vK6xn!MTgvkpfsC{0+R6{dt^ zV#$S-uWj=-*)0N-R_T-xEJUMxfX!D2*Wj4teG$u$=>OTrbE{8xOF3Xt-ua=YO&OVT zooY^$vWBx0&*$NAE{LQ@cBe?ZSd)50_^9gAskc8C8!bt7x$$yswO#e7a6n1j8u&v?FW^A_YuxNFsQE6jTukBs rNvc9*C%fm)-!AaTbXY07Px=;%HX@3+u)|*8!zm*>ER9n{7>c5Q+Ic3@ diff --git a/Package/Cactus_S4AP (package source)/220557DA!00000000!10566BE2CD18DAFC.Unknown.StringTable b/Package/Cactus_S4AP (package source)/220557DA!00000000!10566BE2CD18DAFC.Unknown.StringTable deleted file mode 100644 index 74712d49ee73c9c8d69de0c890299282755f6db8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 785 zcmZuvPe>L)9Q{>vDooP~FR=$ff(p{gQwIgf;FF@QgQps1=i42=*_mZ#_WO3hs}Thq zx@1L2c%=W?W};L5qeV&%9E%9t}AGfg8#iR4Sux1ek1^u7zfr=SzA5|wi7 z)C5LW%1l4B(#4VrgwDt) zNG-KKgYKIU*;Yss!GxdVm!9o;3x_O@MM%6HJu}+>xoe$v1PG<1*xkOIhd%xS(U=n;;_zNA@+vK6xn!MTgvkpfsC{0+R6{dt^ zV#$S-uWj=-*)0N-R_T-xEJUMxfX!D2*Wj4teG$u$=>OTrbE{8xOF3Xt-ua=YO&OVT zooY^$vWBx0&*$NAE{LQ@cBe?ZSd)50_^9gAskc8C8!bt7x$$yswO#e7a6n1j8u&v?FW^A_YuxNFsQE6jTukBs rNvc9*C%fm)-!AaTbXY07Px=;%HX@3+u)|*8!zm*>ER9n{7>c5Q+Ic3@ diff --git a/Package/Cactus_S4AP (package source)/220557DA!00000000!11566BE2CD18DAFC.Portuguese .StringTable b/Package/Cactus_S4AP (package source)/220557DA!00000000!11566BE2CD18DAFC.Portuguese .StringTable deleted file mode 100644 index 74712d49ee73c9c8d69de0c890299282755f6db8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 785 zcmZuvPe>L)9Q{>vDooP~FR=$ff(p{gQwIgf;FF@QgQps1=i42=*_mZ#_WO3hs}Thq zx@1L2c%=W?W};L5qeV&%9E%9t}AGfg8#iR4Sux1ek1^u7zfr=SzA5|wi7 z)C5LW%1l4B(#4VrgwDt) zNG-KKgYKIU*;Yss!GxdVm!9o;3x_O@MM%6HJu}+>xoe$v1PG<1*xkOIhd%xS(U=n;;_zNA@+vK6xn!MTgvkpfsC{0+R6{dt^ zV#$S-uWj=-*)0N-R_T-xEJUMxfX!D2*Wj4teG$u$=>OTrbE{8xOF3Xt-ua=YO&OVT zooY^$vWBx0&*$NAE{LQ@cBe?ZSd)50_^9gAskc8C8!bt7x$$yswO#e7a6n1j8u&v?FW^A_YuxNFsQE6jTukBs rNvc9*C%fm)-!AaTbXY07Px=;%HX@3+u)|*8!zm*>ER9n{7>c5Q+Ic3@ diff --git a/Package/Cactus_S4AP (package source)/220557DA!00000000!12566BE2CD18DAFC.Russian .StringTable b/Package/Cactus_S4AP (package source)/220557DA!00000000!12566BE2CD18DAFC.Russian .StringTable deleted file mode 100644 index 74712d49ee73c9c8d69de0c890299282755f6db8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 785 zcmZuvPe>L)9Q{>vDooP~FR=$ff(p{gQwIgf;FF@QgQps1=i42=*_mZ#_WO3hs}Thq zx@1L2c%=W?W};L5qeV&%9E%9t}AGfg8#iR4Sux1ek1^u7zfr=SzA5|wi7 z)C5LW%1l4B(#4VrgwDt) zNG-KKgYKIU*;Yss!GxdVm!9o;3x_O@MM%6HJu}+>xoe$v1PG<1*xkOIhd%xS(U=n;;_zNA@+vK6xn!MTgvkpfsC{0+R6{dt^ zV#$S-uWj=-*)0N-R_T-xEJUMxfX!D2*Wj4teG$u$=>OTrbE{8xOF3Xt-ua=YO&OVT zooY^$vWBx0&*$NAE{LQ@cBe?ZSd)50_^9gAskc8C8!bt7x$$yswO#e7a6n1j8u&v?FW^A_YuxNFsQE6jTukBs rNvc9*C%fm)-!AaTbXY07Px=;%HX@3+u)|*8!zm*>ER9n{7>c5Q+Ic3@ diff --git a/Package/Cactus_S4AP (package source)/220557DA!00000000!13566BE2CD18DAFC.Spanish .StringTable b/Package/Cactus_S4AP (package source)/220557DA!00000000!13566BE2CD18DAFC.Spanish .StringTable deleted file mode 100644 index 74712d49ee73c9c8d69de0c890299282755f6db8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 785 zcmZuvPe>L)9Q{>vDooP~FR=$ff(p{gQwIgf;FF@QgQps1=i42=*_mZ#_WO3hs}Thq zx@1L2c%=W?W};L5qeV&%9E%9t}AGfg8#iR4Sux1ek1^u7zfr=SzA5|wi7 z)C5LW%1l4B(#4VrgwDt) zNG-KKgYKIU*;Yss!GxdVm!9o;3x_O@MM%6HJu}+>xoe$v1PG<1*xkOIhd%xS(U=n;;_zNA@+vK6xn!MTgvkpfsC{0+R6{dt^ zV#$S-uWj=-*)0N-R_T-xEJUMxfX!D2*Wj4teG$u$=>OTrbE{8xOF3Xt-ua=YO&OVT zooY^$vWBx0&*$NAE{LQ@cBe?ZSd)50_^9gAskc8C8!bt7x$$yswO#e7a6n1j8u&v?FW^A_YuxNFsQE6jTukBs rNvc9*C%fm)-!AaTbXY07Px=;%HX@3+u)|*8!zm*>ER9n{7>c5Q+Ic3@ diff --git a/Package/Cactus_S4AP (package source)/220557DA!00000000!15566BE2CD18DAFC.Swedish .StringTable b/Package/Cactus_S4AP (package source)/220557DA!00000000!15566BE2CD18DAFC.Swedish .StringTable deleted file mode 100644 index 74712d49ee73c9c8d69de0c890299282755f6db8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 785 zcmZuvPe>L)9Q{>vDooP~FR=$ff(p{gQwIgf;FF@QgQps1=i42=*_mZ#_WO3hs}Thq zx@1L2c%=W?W};L5qeV&%9E%9t}AGfg8#iR4Sux1ek1^u7zfr=SzA5|wi7 z)C5LW%1l4B(#4VrgwDt) zNG-KKgYKIU*;Yss!GxdVm!9o;3x_O@MM%6HJu}+>xoe$v1PG<1*xkOIhd%xS(U=n;;_zNA@+vK6xn!MTgvkpfsC{0+R6{dt^ zV#$S-uWj=-*)0N-R_T-xEJUMxfX!D2*Wj4teG$u$=>OTrbE{8xOF3Xt-ua=YO&OVT zooY^$vWBx0&*$NAE{LQ@cBe?ZSd)50_^9gAskc8C8!bt7x$$yswO#e7a6n1j8u&v?FW^A_YuxNFsQE6jTukBs rNvc9*C%fm)-!AaTbXY07Px=;%HX@3+u)|*8!zm*>ER9n{7>c5Q+Ic3@ diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!0000000088B5FBB8.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!0000000088B5FBB8.Constructor.SimData.xml deleted file mode 100644 index 7cd75cd..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!0000000088B5FBB8.Constructor.SimData.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - FD04E3BE-00000000-8AF8B916CF64C646 - FD04E3BE-00000000-3BF33216A25546EA - 0x00000000 - 0x00000000 - 00B2D882-00000000-30F0846C783606F9 - 0 - 0 - 0x00000000 - 1 - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!0000000089032333.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!0000000089032333.Constructor.SimData.xml deleted file mode 100644 index 7cd75cd..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!0000000089032333.Constructor.SimData.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - FD04E3BE-00000000-8AF8B916CF64C646 - FD04E3BE-00000000-3BF33216A25546EA - 0x00000000 - 0x00000000 - 00B2D882-00000000-30F0846C783606F9 - 0 - 0 - 0x00000000 - 1 - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!000000008A606580.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!000000008A606580.Constructor.SimData.xml deleted file mode 100644 index 7cd75cd..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!000000008A606580.Constructor.SimData.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - FD04E3BE-00000000-8AF8B916CF64C646 - FD04E3BE-00000000-3BF33216A25546EA - 0x00000000 - 0x00000000 - 00B2D882-00000000-30F0846C783606F9 - 0 - 0 - 0x00000000 - 1 - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!000000008E00A8E2.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!000000008E00A8E2.Constructor.SimData.xml deleted file mode 100644 index 7cd75cd..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!000000008E00A8E2.Constructor.SimData.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - FD04E3BE-00000000-8AF8B916CF64C646 - FD04E3BE-00000000-3BF33216A25546EA - 0x00000000 - 0x00000000 - 00B2D882-00000000-30F0846C783606F9 - 0 - 0 - 0x00000000 - 1 - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000942950EC.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000942950EC.Constructor.SimData.xml deleted file mode 100644 index 7cd75cd..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000942950EC.Constructor.SimData.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - FD04E3BE-00000000-8AF8B916CF64C646 - FD04E3BE-00000000-3BF33216A25546EA - 0x00000000 - 0x00000000 - 00B2D882-00000000-30F0846C783606F9 - 0 - 0 - 0x00000000 - 1 - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000ACEC4762.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000ACEC4762.Constructor.SimData.xml deleted file mode 100644 index 7cd75cd..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000ACEC4762.Constructor.SimData.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - FD04E3BE-00000000-8AF8B916CF64C646 - FD04E3BE-00000000-3BF33216A25546EA - 0x00000000 - 0x00000000 - 00B2D882-00000000-30F0846C783606F9 - 0 - 0 - 0x00000000 - 1 - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000B0C1684A.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000B0C1684A.Constructor.SimData.xml deleted file mode 100644 index 7cd75cd..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000B0C1684A.Constructor.SimData.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - FD04E3BE-00000000-8AF8B916CF64C646 - FD04E3BE-00000000-3BF33216A25546EA - 0x00000000 - 0x00000000 - 00B2D882-00000000-30F0846C783606F9 - 0 - 0 - 0x00000000 - 1 - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000B4713A54.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000B4713A54.Constructor.SimData.xml deleted file mode 100644 index 7cd75cd..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000B4713A54.Constructor.SimData.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - FD04E3BE-00000000-8AF8B916CF64C646 - FD04E3BE-00000000-3BF33216A25546EA - 0x00000000 - 0x00000000 - 00B2D882-00000000-30F0846C783606F9 - 0 - 0 - 0x00000000 - 1 - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000B629BB49.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000B629BB49.Constructor.SimData.xml deleted file mode 100644 index 7cd75cd..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000B629BB49.Constructor.SimData.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - FD04E3BE-00000000-8AF8B916CF64C646 - FD04E3BE-00000000-3BF33216A25546EA - 0x00000000 - 0x00000000 - 00B2D882-00000000-30F0846C783606F9 - 0 - 0 - 0x00000000 - 1 - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000BB971053.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000BB971053.Constructor.SimData.xml deleted file mode 100644 index 7cd75cd..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000BB971053.Constructor.SimData.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - FD04E3BE-00000000-8AF8B916CF64C646 - FD04E3BE-00000000-3BF33216A25546EA - 0x00000000 - 0x00000000 - 00B2D882-00000000-30F0846C783606F9 - 0 - 0 - 0x00000000 - 1 - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000C8D1ECF5.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000C8D1ECF5.Constructor.SimData.xml deleted file mode 100644 index 7cd75cd..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000C8D1ECF5.Constructor.SimData.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - FD04E3BE-00000000-8AF8B916CF64C646 - FD04E3BE-00000000-3BF33216A25546EA - 0x00000000 - 0x00000000 - 00B2D882-00000000-30F0846C783606F9 - 0 - 0 - 0x00000000 - 1 - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000D037694E.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000D037694E.Constructor.SimData.xml deleted file mode 100644 index 7cd75cd..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000D037694E.Constructor.SimData.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - FD04E3BE-00000000-8AF8B916CF64C646 - FD04E3BE-00000000-3BF33216A25546EA - 0x00000000 - 0x00000000 - 00B2D882-00000000-30F0846C783606F9 - 0 - 0 - 0x00000000 - 1 - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000D51559C9.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000D51559C9.Constructor.SimData.xml deleted file mode 100644 index 7cd75cd..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000D51559C9.Constructor.SimData.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - FD04E3BE-00000000-8AF8B916CF64C646 - FD04E3BE-00000000-3BF33216A25546EA - 0x00000000 - 0x00000000 - 00B2D882-00000000-30F0846C783606F9 - 0 - 0 - 0x00000000 - 1 - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000D6BFC3D1.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000D6BFC3D1.Constructor.SimData.xml deleted file mode 100644 index 7cd75cd..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000D6BFC3D1.Constructor.SimData.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - FD04E3BE-00000000-8AF8B916CF64C646 - FD04E3BE-00000000-3BF33216A25546EA - 0x00000000 - 0x00000000 - 00B2D882-00000000-30F0846C783606F9 - 0 - 0 - 0x00000000 - 1 - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000D79B9065.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000D79B9065.Constructor.SimData.xml deleted file mode 100644 index 7cd75cd..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000D79B9065.Constructor.SimData.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - FD04E3BE-00000000-8AF8B916CF64C646 - FD04E3BE-00000000-3BF33216A25546EA - 0x00000000 - 0x00000000 - 00B2D882-00000000-30F0846C783606F9 - 0 - 0 - 0x00000000 - 1 - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000D888EB85.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000D888EB85.Constructor.SimData.xml deleted file mode 100644 index 7cd75cd..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000D888EB85.Constructor.SimData.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - FD04E3BE-00000000-8AF8B916CF64C646 - FD04E3BE-00000000-3BF33216A25546EA - 0x00000000 - 0x00000000 - 00B2D882-00000000-30F0846C783606F9 - 0 - 0 - 0x00000000 - 1 - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000DA4F627F.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000DA4F627F.Constructor.SimData.xml deleted file mode 100644 index 7cd75cd..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000DA4F627F.Constructor.SimData.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - FD04E3BE-00000000-8AF8B916CF64C646 - FD04E3BE-00000000-3BF33216A25546EA - 0x00000000 - 0x00000000 - 00B2D882-00000000-30F0846C783606F9 - 0 - 0 - 0x00000000 - 1 - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000DAF19D9B.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000DAF19D9B.Constructor.SimData.xml deleted file mode 100644 index 7cd75cd..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000DAF19D9B.Constructor.SimData.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - FD04E3BE-00000000-8AF8B916CF64C646 - FD04E3BE-00000000-3BF33216A25546EA - 0x00000000 - 0x00000000 - 00B2D882-00000000-30F0846C783606F9 - 0 - 0 - 0x00000000 - 1 - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000E330058C.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000E330058C.Constructor.SimData.xml deleted file mode 100644 index 7cd75cd..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000E330058C.Constructor.SimData.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - FD04E3BE-00000000-8AF8B916CF64C646 - FD04E3BE-00000000-3BF33216A25546EA - 0x00000000 - 0x00000000 - 00B2D882-00000000-30F0846C783606F9 - 0 - 0 - 0x00000000 - 1 - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000E9CA5D38.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000E9CA5D38.Constructor.SimData.xml deleted file mode 100644 index 7cd75cd..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000E9CA5D38.Constructor.SimData.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - FD04E3BE-00000000-8AF8B916CF64C646 - FD04E3BE-00000000-3BF33216A25546EA - 0x00000000 - 0x00000000 - 00B2D882-00000000-30F0846C783606F9 - 0 - 0 - 0x00000000 - 1 - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000EA1784B3.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000EA1784B3.Constructor.SimData.xml deleted file mode 100644 index 7cd75cd..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000EA1784B3.Constructor.SimData.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - FD04E3BE-00000000-8AF8B916CF64C646 - FD04E3BE-00000000-3BF33216A25546EA - 0x00000000 - 0x00000000 - 00B2D882-00000000-30F0846C783606F9 - 0 - 0 - 0x00000000 - 1 - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000F3563747.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000F3563747.Constructor.SimData.xml deleted file mode 100644 index 7cd75cd..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000F3563747.Constructor.SimData.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - FD04E3BE-00000000-8AF8B916CF64C646 - FD04E3BE-00000000-3BF33216A25546EA - 0x00000000 - 0x00000000 - 00B2D882-00000000-30F0846C783606F9 - 0 - 0 - 0x00000000 - 1 - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000F93B00FF.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000F93B00FF.Constructor.SimData.xml deleted file mode 100644 index 7cd75cd..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000F93B00FF.Constructor.SimData.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - FD04E3BE-00000000-8AF8B916CF64C646 - FD04E3BE-00000000-3BF33216A25546EA - 0x00000000 - 0x00000000 - 00B2D882-00000000-30F0846C783606F9 - 0 - 0 - 0x00000000 - 1 - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000FEB64AAE.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000FEB64AAE.Constructor.SimData.xml deleted file mode 100644 index 7cd75cd..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!00000000FEB64AAE.Constructor.SimData.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - FD04E3BE-00000000-8AF8B916CF64C646 - FD04E3BE-00000000-3BF33216A25546EA - 0x00000000 - 0x00000000 - 00B2D882-00000000-30F0846C783606F9 - 0 - 0 - 0x00000000 - 1 - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!83246516DB798A7C.Cactus_S4AP_LockDancing:Buff.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!83246516DB798A7C.Cactus_S4AP_LockDancing:Buff.SimData.xml deleted file mode 100644 index 0a9a146..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!0017E8F6!83246516DB798A7C.Cactus_S4AP_LockDancing:Buff.SimData.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - 00000000-00000000-0000000000000000 - 00000000-00000000-0000000000000000 - 0x00000000 - 0x00000000 - 00000000-00000000-0000000000000000 - 0 - 0 - 0x00000000 - 0x00000000 - 1 - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!000000008494610E.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!000000008494610E.Constructor.SimData.xml deleted file mode 100644 index 806fe0d..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!000000008494610E.Constructor.SimData.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - 4 - 8 - 16 - 32 - 64 - 0 - 0 - 0 - - - - 00000000-00000000-0000000000000000 - - 00000000-00000000-0000000000000000 - None - - 0x85F13D03 - - 00B2D882-00000000-30F0846C783606F9 - - 1 - 0 - 0 - - - 0x00000000 - 0x00000000 - 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!0000000085944434.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!0000000085944434.Constructor.SimData.xml deleted file mode 100644 index 831b410..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!0000000085944434.Constructor.SimData.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - 4 - 8 - 16 - 32 - 64 - 0 - 0 - 0 - - - - 00000000-00000000-0000000000000000 - - 00000000-00000000-0000000000000000 - None - - 0x8698D66E - - 00B2D882-00000000-30F0846C783606F9 - - 1 - 0 - 0 - - - 0x00000000 - 0x00000000 - 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC916.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC916.Constructor.SimData.xml deleted file mode 100644 index 1210ba2..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC916.Constructor.SimData.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - 4 - 8 - 16 - 32 - 64 - 0 - 0 - 0 - - - - 00000000-00000000-0000000000000000 - - 00000000-00000000-0000000000000000 - None - - 0xFDF5799A - - 00B2D882-00000000-30F0846C783606F9 - - 1 - 0 - 0 - - - 0x00000000 - 0x00000000 - 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC917.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC917.Constructor.SimData.xml deleted file mode 100644 index 212001e..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC917.Constructor.SimData.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - 4 - 8 - 16 - 32 - 64 - 0 - 0 - 0 - - - - 00000000-00000000-0000000000000000 - - 00000000-00000000-0000000000000000 - None - - 0xF2F9F5BD - - 00B2D882-00000000-30F0846C783606F9 - - 1 - 0 - 0 - - - 0x00000000 - 0x00000000 - 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC918.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC918.Constructor.SimData.xml deleted file mode 100644 index 409a218..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC918.Constructor.SimData.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - 4 - 8 - 16 - 32 - 64 - 0 - 0 - 0 - - - - 00000000-00000000-0000000000000000 - - 00000000-00000000-0000000000000000 - None - - 0xF8762C55 - - 00B2D882-00000000-30F0846C783606F9 - - 1 - 0 - 0 - - - 0x00000000 - 0x00000000 - 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC919.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC919.Constructor.SimData.xml deleted file mode 100644 index 0e976a3..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC919.Constructor.SimData.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - 4 - 8 - 16 - 32 - 64 - 0 - 0 - 0 - - - - 00000000-00000000-0000000000000000 - - 00000000-00000000-0000000000000000 - None - - 0x8836B113 - - 00B2D882-00000000-30F0846C783606F9 - - 1 - 0 - 0 - - - 0x00000000 - 0x00000000 - 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91A.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91A.Constructor.SimData.xml deleted file mode 100644 index 9f6fffd..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91A.Constructor.SimData.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - 4 - 8 - 16 - 32 - 64 - 0 - 0 - 0 - - - - 00000000-00000000-0000000000000000 - - 00000000-00000000-0000000000000000 - None - - 0x92619FF2 - - 00B2D882-00000000-30F0846C783606F9 - - 1 - 0 - 0 - - - 0x00000000 - 0x00000000 - 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91B.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91B.Constructor.SimData.xml deleted file mode 100644 index a839dfd..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91B.Constructor.SimData.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - 4 - 8 - 16 - 32 - 64 - 0 - 0 - 0 - - - - 00000000-00000000-0000000000000000 - - 00000000-00000000-0000000000000000 - None - - 0xDBE5EAB6 - - 00B2D882-00000000-30F0846C783606F9 - - 1 - 0 - 0 - - - 0x00000000 - 0x00000000 - 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91C.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91C.Constructor.SimData.xml deleted file mode 100644 index f4162db..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91C.Constructor.SimData.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - 4 - 8 - 16 - 32 - 64 - 0 - 0 - 0 - - - - 00000000-00000000-0000000000000000 - - 00000000-00000000-0000000000000000 - None - - 0xD8E6D160 - - 00B2D882-00000000-30F0846C783606F9 - - 1 - 0 - 0 - - - 0x00000000 - 0x00000000 - 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91D.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91D.Constructor.SimData.xml deleted file mode 100644 index 71f4e1e..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91D.Constructor.SimData.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - 4 - 8 - 16 - 32 - 64 - 0 - 0 - 0 - - - - 00000000-00000000-0000000000000000 - - 00000000-00000000-0000000000000000 - None - - 0xEA0CB8F8 - - 00B2D882-00000000-30F0846C783606F9 - - 1 - 0 - 0 - - - 0x00000000 - 0x00000000 - 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91E.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91E.Constructor.SimData.xml deleted file mode 100644 index 6ef1b7c..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91E.Constructor.SimData.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - 4 - 8 - 16 - 32 - 64 - 0 - 0 - 0 - - - - 00000000-00000000-0000000000000000 - - 00000000-00000000-0000000000000000 - None - - 0xB5B059A3 - - 00B2D882-00000000-30F0846C783606F9 - - 1 - 0 - 0 - - - 0x00000000 - 0x00000000 - 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91F.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91F.Constructor.SimData.xml deleted file mode 100644 index c0fd4be..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D04CC91F.Constructor.SimData.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - 4 - 8 - 16 - 32 - 64 - 0 - 0 - 0 - - - - 00000000-00000000-0000000000000000 - - 00000000-00000000-0000000000000000 - None - - 0x9874E78A - - 00B2D882-00000000-30F0846C783606F9 - - 1 - 0 - 0 - - - 0x00000000 - 0x00000000 - 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF0.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF0.Constructor.SimData.xml deleted file mode 100644 index 988a803..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF0.Constructor.SimData.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - 4 - 8 - 16 - 32 - 64 - 0 - 0 - 0 - - - - 00000000-00000000-0000000000000000 - - 00000000-00000000-0000000000000000 - None - - 0xC88E7C72 - - 00B2D882-00000000-30F0846C783606F9 - - 1 - 0 - 0 - - - 0x00000000 - 0x00000000 - 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF1.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF1.Constructor.SimData.xml deleted file mode 100644 index abe0a01..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF1.Constructor.SimData.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - 4 - 8 - 16 - 32 - 64 - 0 - 0 - 0 - - - - 00000000-00000000-0000000000000000 - - 00000000-00000000-0000000000000000 - None - - 0x97101441 - - 00B2D882-00000000-30F0846C783606F9 - - 1 - 0 - 0 - - - 0x00000000 - 0x00000000 - 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF2.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF2.Constructor.SimData.xml deleted file mode 100644 index e3215b6..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF2.Constructor.SimData.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - 4 - 8 - 16 - 32 - 64 - 0 - 0 - 0 - - - - 00000000-00000000-0000000000000000 - - 00000000-00000000-0000000000000000 - None - - 0xCDDB6620 - - 00B2D882-00000000-30F0846C783606F9 - - 1 - 0 - 0 - - - 0x00000000 - 0x00000000 - 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF3.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF3.Constructor.SimData.xml deleted file mode 100644 index 7a9f9ce..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF3.Constructor.SimData.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - 4 - 8 - 16 - 32 - 64 - 0 - 0 - 0 - - - - 00000000-00000000-0000000000000000 - - 00000000-00000000-0000000000000000 - None - - 0xC97977CA - - 00B2D882-00000000-30F0846C783606F9 - - 1 - 0 - 0 - - - 0x00000000 - 0x00000000 - 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF4.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF4.Constructor.SimData.xml deleted file mode 100644 index c46748e..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF4.Constructor.SimData.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - 4 - 8 - 16 - 32 - 64 - 0 - 0 - 0 - - - - 00000000-00000000-0000000000000000 - - 00000000-00000000-0000000000000000 - None - - 0xB2D63767 - - 00B2D882-00000000-30F0846C783606F9 - - 1 - 0 - 0 - - - 0x00000000 - 0x00000000 - 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF6.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF6.Constructor.SimData.xml deleted file mode 100644 index ab59efb..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D14CCAF6.Constructor.SimData.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - 4 - 8 - 16 - 32 - 64 - 0 - 0 - 0 - - - - 00000000-00000000-0000000000000000 - - 00000000-00000000-0000000000000000 - None - - 0xE8455F9F - - 00B2D882-00000000-30F0846C783606F9 - - 1 - 0 - 0 - - - 0x00000000 - 0x00000000 - 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D301A22C.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D301A22C.Constructor.SimData.xml deleted file mode 100644 index 1de34e9..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D301A22C.Constructor.SimData.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - 4 - 8 - 16 - 32 - 64 - 0 - 0 - 0 - - - - 00000000-00000000-0000000000000000 - - 00000000-00000000-0000000000000000 - None - - 0xBE01AC49 - - 00B2D882-00000000-30F0846C783606F9 - - 1 - 0 - 0 - - - 0x00000000 - 0x00000000 - 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B70.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B70.Constructor.SimData.xml deleted file mode 100644 index 3bc18ba..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B70.Constructor.SimData.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - 4 - 8 - 16 - 32 - 64 - 0 - 0 - 0 - - - - 00000000-00000000-0000000000000000 - - 00000000-00000000-0000000000000000 - None - - 0xA1E5B19B - - 00B2D882-00000000-30F0846C783606F9 - - 1 - 0 - 0 - - - 0x00000000 - 0x00000000 - 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B71.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B71.Constructor.SimData.xml deleted file mode 100644 index 9e2be1a..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B71.Constructor.SimData.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - 4 - 8 - 16 - 32 - 64 - 0 - 0 - 0 - - - - 00000000-00000000-0000000000000000 - - 00000000-00000000-0000000000000000 - None - - 0xC9249D53 - - 00B2D882-00000000-30F0846C783606F9 - - 1 - 0 - 0 - - - 0x00000000 - 0x00000000 - 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B72.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B72.Constructor.SimData.xml deleted file mode 100644 index a36a941..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B72.Constructor.SimData.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - 4 - 8 - 16 - 32 - 64 - 0 - 0 - 0 - - - - 00000000-00000000-0000000000000000 - - 00000000-00000000-0000000000000000 - None - - 0xE3298B37 - - 00B2D882-00000000-30F0846C783606F9 - - 1 - 0 - 0 - - - 0x00000000 - 0x00000000 - 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B73.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B73.Constructor.SimData.xml deleted file mode 100644 index 4ad65a9..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B73.Constructor.SimData.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - 4 - 8 - 16 - 32 - 64 - 0 - 0 - 0 - - - - 00000000-00000000-0000000000000000 - - 00000000-00000000-0000000000000000 - None - - 0xDD6F11B5 - - 00B2D882-00000000-30F0846C783606F9 - - 1 - 0 - 0 - - - 0x00000000 - 0x00000000 - 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B76.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B76.Constructor.SimData.xml deleted file mode 100644 index 8eb5e3a..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B76.Constructor.SimData.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - 4 - 8 - 16 - 32 - 64 - 0 - 0 - 0 - - - - 00000000-00000000-0000000000000000 - - 00000000-00000000-0000000000000000 - None - - 0xB9274531 - - 00B2D882-00000000-30F0846C783606F9 - - 1 - 0 - 0 - - - 0x00000000 - 0x00000000 - 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B77.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B77.Constructor.SimData.xml deleted file mode 100644 index 5453c65..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B77.Constructor.SimData.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - 4 - 8 - 16 - 32 - 64 - 0 - 0 - 0 - - - - 00000000-00000000-0000000000000000 - - 00000000-00000000-0000000000000000 - None - - 0xFBBCD468 - - 00B2D882-00000000-30F0846C783606F9 - - 1 - 0 - 0 - - - 0x00000000 - 0x00000000 - 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B7C.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B7C.Constructor.SimData.xml deleted file mode 100644 index 0dab6bb..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B7C.Constructor.SimData.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - 4 - 8 - 16 - 32 - 64 - 0 - 0 - 0 - - - - 00000000-00000000-0000000000000000 - - 00000000-00000000-0000000000000000 - None - - 0xDBD7E3BC - - 00B2D882-00000000-30F0846C783606F9 - - 1 - 0 - 0 - - - 0x00000000 - 0x00000000 - 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B7D.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B7D.Constructor.SimData.xml deleted file mode 100644 index 446f402..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!00000000D7924B7D.Constructor.SimData.xml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - 4 - 8 - 16 - 32 - 64 - 0 - 0 - 0 - - - - 00000000-00000000-0000000000000000 - - 00000000-00000000-0000000000000000 - None - - 0xDDFC2DE9 - - 00B2D882-00000000-30F0846C783606F9 - - 1 - 0 - 0 - - - 0x00000000 - 0x00000000 - 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!A951AD6CAA6F0CF6.Cactus_S4AP_Trait_LockDancing.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!A951AD6CAA6F0CF6.Cactus_S4AP_Trait_LockDancing.SimData.xml deleted file mode 100644 index d529a85..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!005FDD0C!A951AD6CAA6F0CF6.Cactus_S4AP_Trait_LockDancing.SimData.xml +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - 1 - 2 - 4 - 8 - 16 - 32 - 64 - - - - 0 - 00000000-00000000-0000000000000000 - None - 00000000-00000000-0000000000000000 - None - 0 - - - 0x00000000 - - - 00000000-00000000-0000000000000000 - - 0 - - - - 0x00000000 - 0x00000000 - 4 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/545AC67A!00E9D967!00000000A85DB38B.Constructor.SimData.xml b/Package/Cactus_S4AP (package source)/545AC67A!00E9D967!00000000A85DB38B.Constructor.SimData.xml deleted file mode 100644 index dd1b0f4..0000000 --- a/Package/Cactus_S4AP (package source)/545AC67A!00E9D967!00000000A85DB38B.Constructor.SimData.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - 0 - 0x85992464 - 0 - 00B2D882-00000000-F1C680E09B12C2B6 - 0 - 0 - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!0000000088B5FBB8.Cactus_S4AP_Trait21:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!0000000088B5FBB8.Cactus_S4AP_Trait21:Buff.BuffTuning.xml deleted file mode 100644 index 86ce2db..0000000 --- a/Package/Cactus_S4AP (package source)/6017E896!00000000!0000000088B5FBB8.Cactus_S4AP_Trait21:Buff.BuffTuning.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - 105774 - - INCREASE - 0 - - - - - - - - False - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!0000000089032333.Cactus_S4AP_Trait24:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!0000000089032333.Cactus_S4AP_Trait24:Buff.BuffTuning.xml deleted file mode 100644 index 122785c..0000000 --- a/Package/Cactus_S4AP (package source)/6017E896!00000000!0000000089032333.Cactus_S4AP_Trait24:Buff.BuffTuning.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - Skill_All - 4 - - - - - - - False - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!000000008A606580.Cactus_S4AP_Trait14:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!000000008A606580.Cactus_S4AP_Trait14:Buff.BuffTuning.xml deleted file mode 100644 index d243ad4..0000000 --- a/Package/Cactus_S4AP (package source)/6017E896!00000000!000000008A606580.Cactus_S4AP_Trait14:Buff.BuffTuning.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - 16707 - - INCREASE - 0 - - - - - - - - False - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!000000008E00A8E2.Cactus_S4AP_Trait5:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!000000008E00A8E2.Cactus_S4AP_Trait5:Buff.BuffTuning.xml deleted file mode 100644 index d846435..0000000 --- a/Package/Cactus_S4AP (package source)/6017E896!00000000!000000008E00A8E2.Cactus_S4AP_Trait5:Buff.BuffTuning.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - 16709 - - INCREASE - 0 - - - - - - - - False - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000942950EC.Cactus_S4AP_Trait3:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000942950EC.Cactus_S4AP_Trait3:Buff.BuffTuning.xml deleted file mode 100644 index 650e159..0000000 --- a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000942950EC.Cactus_S4AP_Trait3:Buff.BuffTuning.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - 16706 - - INCREASE - 0 - - - - - - - - False - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000ACEC4762.Cactus_S4AP_Trait23:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000ACEC4762.Cactus_S4AP_Trait23:Buff.BuffTuning.xml deleted file mode 100644 index 8c0c634..0000000 --- a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000ACEC4762.Cactus_S4AP_Trait23:Buff.BuffTuning.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - Skill_All - 3.5 - - - - - - - False - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000B0C1684A.Cactus_S4AP_Trait16:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000B0C1684A.Cactus_S4AP_Trait16:Buff.BuffTuning.xml deleted file mode 100644 index af45d16..0000000 --- a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000B0C1684A.Cactus_S4AP_Trait16:Buff.BuffTuning.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - 16708 - - INCREASE - 0 - - - - - - - - False - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000B4713A54.Cactus_S4AP_Trait10:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000B4713A54.Cactus_S4AP_Trait10:Buff.BuffTuning.xml deleted file mode 100644 index 44115f5..0000000 --- a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000B4713A54.Cactus_S4AP_Trait10:Buff.BuffTuning.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - 16659 - - INCREASE - 0 - - - - - - - - False - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000B629BB49.Cactus_S4AP_Trait4:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000B629BB49.Cactus_S4AP_Trait4:Buff.BuffTuning.xml deleted file mode 100644 index c815dec..0000000 --- a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000B629BB49.Cactus_S4AP_Trait4:Buff.BuffTuning.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - Skill_All - 2.5 - - - - - - - False - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000BB971053.Cactus_S4AP_Trait19:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000BB971053.Cactus_S4AP_Trait19:Buff.BuffTuning.xml deleted file mode 100644 index 821728d..0000000 --- a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000BB971053.Cactus_S4AP_Trait19:Buff.BuffTuning.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - 16712 - - INCREASE - 0 - - - - - - - - False - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000C8D1ECF5.Cactus_S4AP_Trait:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000C8D1ECF5.Cactus_S4AP_Trait:Buff.BuffTuning.xml deleted file mode 100644 index fb56119..0000000 --- a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000C8D1ECF5.Cactus_S4AP_Trait:Buff.BuffTuning.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - 16698 - - INCREASE - 0 - - - - - - - - False - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D037694E.Cactus_S4AP_Trait12:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D037694E.Cactus_S4AP_Trait12:Buff.BuffTuning.xml deleted file mode 100644 index a8e7ce2..0000000 --- a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D037694E.Cactus_S4AP_Trait12:Buff.BuffTuning.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - 16701 - - INCREASE - 0 - - - - - - - - False - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D51559C9.Cactus_S4AP_Trait22:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D51559C9.Cactus_S4AP_Trait22:Buff.BuffTuning.xml deleted file mode 100644 index c3d6ef8..0000000 --- a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D51559C9.Cactus_S4AP_Trait22:Buff.BuffTuning.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - Skill_All - 3 - - - - - - - False - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D6BFC3D1.Cactus_S4AP_LockProgramming:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D6BFC3D1.Cactus_S4AP_LockProgramming:Buff.BuffTuning.xml deleted file mode 100644 index e0a9538..0000000 --- a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D6BFC3D1.Cactus_S4AP_LockProgramming:Buff.BuffTuning.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - 16703 - - INCREASE - 0 - - - - - - - - False - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D79B9065.Cactus_S4AP_Trait8:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D79B9065.Cactus_S4AP_Trait8:Buff.BuffTuning.xml deleted file mode 100644 index 5b3024f..0000000 --- a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D79B9065.Cactus_S4AP_Trait8:Buff.BuffTuning.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - 16705 - - INCREASE - 0 - - - - - - - - False - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D888EB85.Cactus_S4AP_Trait13:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D888EB85.Cactus_S4AP_Trait13:Buff.BuffTuning.xml deleted file mode 100644 index a141395..0000000 --- a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000D888EB85.Cactus_S4AP_Trait13:Buff.BuffTuning.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - 16704 - - INCREASE - 0 - - - - - - - - False - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000DA4F627F.Cactus_S4AP_Trait6:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000DA4F627F.Cactus_S4AP_Trait6:Buff.BuffTuning.xml deleted file mode 100644 index 334f68c..0000000 --- a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000DA4F627F.Cactus_S4AP_Trait6:Buff.BuffTuning.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - 16713 - - INCREASE - 0 - - - - - - - - False - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000DAF19D9B.Cactus_S4AP_Trait11:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000DAF19D9B.Cactus_S4AP_Trait11:Buff.BuffTuning.xml deleted file mode 100644 index 8488d81..0000000 --- a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000DAF19D9B.Cactus_S4AP_Trait11:Buff.BuffTuning.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - 16700 - - INCREASE - 0 - - - - - - - - False - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000E330058C.Cactus_S4AP_Trait18:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000E330058C.Cactus_S4AP_Trait18:Buff.BuffTuning.xml deleted file mode 100644 index 21eae92..0000000 --- a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000E330058C.Cactus_S4AP_Trait18:Buff.BuffTuning.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - 16710 - - INCREASE - 0 - - - - - - - - False - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000E9CA5D38.Cactus_S4AP_Trait7:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000E9CA5D38.Cactus_S4AP_Trait7:Buff.BuffTuning.xml deleted file mode 100644 index f61e716..0000000 --- a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000E9CA5D38.Cactus_S4AP_Trait7:Buff.BuffTuning.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - 16699 - - INCREASE - 0 - - - - - - - - False - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000EA1784B3.Cactus_S4AP_Trait2:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000EA1784B3.Cactus_S4AP_Trait2:Buff.BuffTuning.xml deleted file mode 100644 index 2baf427..0000000 --- a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000EA1784B3.Cactus_S4AP_Trait2:Buff.BuffTuning.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - 16702 - - INCREASE - 0 - - - - - - - - False - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000F3563747.Cactus_S4AP_Trait15:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000F3563747.Cactus_S4AP_Trait15:Buff.BuffTuning.xml deleted file mode 100644 index a52f0b9..0000000 --- a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000F3563747.Cactus_S4AP_Trait15:Buff.BuffTuning.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - 16695 - - INCREASE - 0 - - - - - - - - False - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000F93B00FF.Cactus_S4AP_Trait20:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000F93B00FF.Cactus_S4AP_Trait20:Buff.BuffTuning.xml deleted file mode 100644 index f9dc0a1..0000000 --- a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000F93B00FF.Cactus_S4AP_Trait20:Buff.BuffTuning.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - 16714 - - INCREASE - 0 - - - - - - - - False - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000FEB64AAE.Cactus_S4AP_Trait9:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000FEB64AAE.Cactus_S4AP_Trait9:Buff.BuffTuning.xml deleted file mode 100644 index 621a979..0000000 --- a/Package/Cactus_S4AP (package source)/6017E896!00000000!00000000FEB64AAE.Cactus_S4AP_Trait9:Buff.BuffTuning.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - 39397 - - INCREASE - 0 - - - - - - - - False - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!83246516DB798A7C.Cactus_S4AP_LockDancing:Buff.BuffTuning.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!83246516DB798A7C.Cactus_S4AP_LockDancing:Buff.BuffTuning.xml deleted file mode 100644 index b48c088..0000000 --- a/Package/Cactus_S4AP (package source)/6017E896!00000000!83246516DB798A7C.Cactus_S4AP_LockDancing:Buff.BuffTuning.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - 128145 - - - - - - - False - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/6017E896!00000000!83246516DB798A7C.Cactus_S4AP_LockDancing:Buff.xml b/Package/Cactus_S4AP (package source)/6017E896!00000000!83246516DB798A7C.Cactus_S4AP_LockDancing:Buff.xml deleted file mode 100644 index 55856ee..0000000 --- a/Package/Cactus_S4AP (package source)/6017E896!00000000!83246516DB798A7C.Cactus_S4AP_LockDancing:Buff.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - 128145 - - - - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/7FB6AD8A!00000000!0000000000000000.S4SMergedPackageManifest b/Package/Cactus_S4AP (package source)/7FB6AD8A!00000000!0000000000000000.S4SMergedPackageManifest deleted file mode 100644 index 03302bc89f96a5102e39150bd5204434e2814ba9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2224 zcmZA2T}V@57{Kx4R|PIJLucP$MF_2$S&O=g0?8yb#VC+Db(mJ0&Y2ZPVhUy<5>|u+ z(M=W=ktKmaWTZI>vZ&M$!fs~mqNOdOtoBNOdV2=r^>@zs?>Xn}Fe8kAugLJ9vElc2 zM~Szl+MbubEvF&Osq?j0!i%x)WrJU>={wq+)Y?C0AJl!kZ-2gN%x=Uv+8g!#nEh5$ z`BSx@&l`I3=#BCPzqv@QSREhon~mgwtQTrK^Dv+H;K%)DwVxi-Px`Wk^d8e^*a{}~ z9@8%p^D+I`z|b?j$MkEiM!eGJWBRT}^GChM^hb7`d#m@De#45W(|V8TL*n`|eQ`$M zrru-vpy)CEz`n%SdXMQpiyqSla#Gv%9@E!~>&NtGW7dDrdrWT@-yf!Twsp+hU!EUK zUnk~c`rYNWndg%p(=QeCG5yY-)NcL!F@2?&kLmNbRNd2iOut;r$MhYSgQI$n>6eKf z(>Hx;9@cwIzeMzy{$z3XfAcZDM_fOqzn$6rOP`PFPlz7V=fz*_(R)mvB+ehx|2DRM z*LzI=MLhqQzTR2XqW747v6zqPTT3fuuAkr2DKQUo{N_U6ggy^5uUgzMOrLq+@g2R# z^b5uLV*2q;qgC%QeU+Gx>Cbc(cB;N~WFktfSnV$xnJ|3)u3oi$_1apKTKlJ`AL`Ei zw&#-WpQFjo#}5`5qkCgg)b_uQ6pj*(7LE~~B|KYrj&Q87NqDYsobWv1c;WfN3Bn76 z6S3bqn0+m!qOD>0uDU%&cW*++`})2hUKQR};&D2>ZjasNIPA1|Yh2~7GK=$QrQ74R sSZy0^Y1Z^jwzTN*fgzLo#-Ure*ZF6T`Eu)8j=f8At~|w$Ddyq$1KK>(ZU6uP diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!000000008494610E.Cactus_S4AP_ResyncLocations.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!000000008494610E.Cactus_S4AP_ResyncLocations.TraitTuning.xml deleted file mode 100644 index 5d608f1..0000000 --- a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!000000008494610E.Cactus_S4AP_ResyncLocations.TraitTuning.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - 0x85F13D03 - - ADULT - CHILD - ELDER - TEEN - YOUNGADULT - - 2f7d0004:00000000:30f0846c783606f9 - 0x85F13D03 - HIDDEN - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!0000000085944434.Cactus_S4AP_ShowYamlOptions.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!0000000085944434.Cactus_S4AP_ShowYamlOptions.TraitTuning.xml deleted file mode 100644 index f07f9a1..0000000 --- a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!0000000085944434.Cactus_S4AP_ShowYamlOptions.TraitTuning.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - 0x8698D66E - - ADULT - CHILD - ELDER - TEEN - YOUNGADULT - - 2f7d0004:00000000:30f0846c783606f9 - 0x8698D66E - HIDDEN - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC916.Cactus_S4AP_Trait19.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC916.Cactus_S4AP_Trait19.TraitTuning.xml deleted file mode 100644 index fb429e6..0000000 --- a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC916.Cactus_S4AP_Trait19.TraitTuning.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - 0xFDF5799A - - ADULT - CHILD - ELDER - TEEN - YOUNGADULT - - 2f7d0004:00000000:30f0846c783606f9 - 0xFDF5799A - HIDDEN - - - 3147239507 - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC917.Cactus_S4AP_Trait18.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC917.Cactus_S4AP_Trait18.TraitTuning.xml deleted file mode 100644 index 50554cb..0000000 --- a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC917.Cactus_S4AP_Trait18.TraitTuning.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - 0xF2F9F5BD - - ADULT - CHILD - ELDER - TEEN - YOUNGADULT - - 2f7d0004:00000000:30f0846c783606f9 - 0xF2F9F5BD - HIDDEN - - - 3811575180 - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC918.Cactus_S4AP_LockProgramming.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC918.Cactus_S4AP_LockProgramming.TraitTuning.xml deleted file mode 100644 index 1d5c1fa..0000000 --- a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC918.Cactus_S4AP_LockProgramming.TraitTuning.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - 0xF8762C55 - - ADULT - CHILD - ELDER - TEEN - YOUNGADULT - - 2f7d0004:00000000:30f0846c783606f9 - 0xF8762C55 - HIDDEN - - - 3602891729 - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC919.Cactus_S4AP_Trait16.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC919.Cactus_S4AP_Trait16.TraitTuning.xml deleted file mode 100644 index 4a637ce..0000000 --- a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC919.Cactus_S4AP_Trait16.TraitTuning.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - 0x8836B113 - - ADULT - CHILD - ELDER - TEEN - YOUNGADULT - - 2f7d0004:00000000:30f0846c783606f9 - 0x8836B113 - HIDDEN - - - 2965465162 - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91A.Cactus_S4AP_Trait15.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91A.Cactus_S4AP_Trait15.TraitTuning.xml deleted file mode 100644 index 6ab9445..0000000 --- a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91A.Cactus_S4AP_Trait15.TraitTuning.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - 0x92619FF2 - - ADULT - CHILD - ELDER - TEEN - YOUNGADULT - - 2f7d0004:00000000:30f0846c783606f9 - 0x92619FF2 - HIDDEN - - - 4082513735 - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91B.Cactus_S4AP_Trait14.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91B.Cactus_S4AP_Trait14.TraitTuning.xml deleted file mode 100644 index af4020a..0000000 --- a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91B.Cactus_S4AP_Trait14.TraitTuning.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - 0xDBE5EAB6 - - ADULT - CHILD - ELDER - TEEN - YOUNGADULT - - 2f7d0004:00000000:30f0846c783606f9 - 0xDBE5EAB6 - HIDDEN - - - 2321573248 - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91C.Cactus_S4AP_Trait13.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91C.Cactus_S4AP_Trait13.TraitTuning.xml deleted file mode 100644 index 6f8eae8..0000000 --- a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91C.Cactus_S4AP_Trait13.TraitTuning.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - 0xD8E6D160 - - ADULT - CHILD - ELDER - TEEN - YOUNGADULT - - 2f7d0004:00000000:30f0846c783606f9 - 0xD8E6D160 - HIDDEN - - - 3632851845 - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91D.Cactus_S4AP_Trait12.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91D.Cactus_S4AP_Trait12.TraitTuning.xml deleted file mode 100644 index 6943766..0000000 --- a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91D.Cactus_S4AP_Trait12.TraitTuning.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - 0xEA0CB8F8 - - ADULT - CHILD - ELDER - TEEN - YOUNGADULT - - 2f7d0004:00000000:30f0846c783606f9 - 0xEA0CB8F8 - HIDDEN - - - 3493292366 - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91E.Cactus_S4AP_Trait11.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91E.Cactus_S4AP_Trait11.TraitTuning.xml deleted file mode 100644 index fb8a9e3..0000000 --- a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91E.Cactus_S4AP_Trait11.TraitTuning.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - 0xB5B059A3 - - ADULT - CHILD - ELDER - TEEN - YOUNGADULT - - 2f7d0004:00000000:30f0846c783606f9 - 0xB5B059A3 - HIDDEN - - - 3673267611 - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91F.Cactus_S4AP_Trait10.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91F.Cactus_S4AP_Trait10.TraitTuning.xml deleted file mode 100644 index 6de6e05..0000000 --- a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D04CC91F.Cactus_S4AP_Trait10.TraitTuning.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - 0x9874E78A - - ADULT - CHILD - ELDER - TEEN - YOUNGADULT - - 2f7d0004:00000000:30f0846c783606f9 - 0x9874E78A - HIDDEN - - - 3027319380 - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF0.Cactus_S4AP_Trait22.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF0.Cactus_S4AP_Trait22.TraitTuning.xml deleted file mode 100644 index f6481eb..0000000 --- a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF0.Cactus_S4AP_Trait22.TraitTuning.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - 0xC88E7C72 - - ADULT - CHILD - ELDER - TEEN - YOUNGADULT - - 2f7d0004:00000000:30f0846c783606f9 - 0xC88E7C72 - HIDDEN - - - 3574946249 - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF1.Cactus_S4AP_Trait23.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF1.Cactus_S4AP_Trait23.TraitTuning.xml deleted file mode 100644 index 8480583..0000000 --- a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF1.Cactus_S4AP_Trait23.TraitTuning.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - 0x97101441 - - ADULT - CHILD - ELDER - TEEN - YOUNGADULT - - 2f7d0004:00000000:30f0846c783606f9 - 0x97101441 - HIDDEN - - - 2901165922 - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF2.Cactus_S4AP_Trait20.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF2.Cactus_S4AP_Trait20.TraitTuning.xml deleted file mode 100644 index 64cf832..0000000 --- a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF2.Cactus_S4AP_Trait20.TraitTuning.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - 0xCDDB6620 - - ADULT - CHILD - ELDER - TEEN - YOUNGADULT - - 2f7d0004:00000000:30f0846c783606f9 - 0xCDDB6620 - HIDDEN - - - 4181393663 - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF3.Cactus_S4AP_Trait21.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF3.Cactus_S4AP_Trait21.TraitTuning.xml deleted file mode 100644 index c5d7495..0000000 --- a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF3.Cactus_S4AP_Trait21.TraitTuning.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - 0xC97977CA - - ADULT - CHILD - ELDER - TEEN - YOUNGADULT - - 2f7d0004:00000000:30f0846c783606f9 - 0xC97977CA - HIDDEN - - - 2293627832 - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF4.Cactus_S4AP_Trait26.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF4.Cactus_S4AP_Trait26.TraitTuning.xml deleted file mode 100644 index cb29666..0000000 --- a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF4.Cactus_S4AP_Trait26.TraitTuning.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - 0xB2D63767 - - ADULT - CHILD - ELDER - TEEN - YOUNGADULT - - 2f7d0004:00000000:30f0846c783606f9 - 0xB2D63767 - HIDDEN - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF6.Cactus_S4AP_Trait24.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF6.Cactus_S4AP_Trait24.TraitTuning.xml deleted file mode 100644 index 207f0ff..0000000 --- a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D14CCAF6.Cactus_S4AP_Trait24.TraitTuning.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - 0xE8455F9F - - ADULT - CHILD - ELDER - TEEN - YOUNGADULT - - 2f7d0004:00000000:30f0846c783606f9 - 0xE8455F9F - HIDDEN - - - 2298684211 - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D301A22C.Cactus_S4AP_Trait.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D301A22C.Cactus_S4AP_Trait.TraitTuning.xml deleted file mode 100644 index 5532253..0000000 --- a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D301A22C.Cactus_S4AP_Trait.TraitTuning.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - 0xBE01AC49 - - ADULT - CHILD - ELDER - TEEN - YOUNGADULT - - 2f7d0004:00000000:30f0846c783606f9 - 0xBE01AC49 - HIDDEN - - - 3369200885 - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B70.Cactus_S4AP_Trait4.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B70.Cactus_S4AP_Trait4.TraitTuning.xml deleted file mode 100644 index 27fa318..0000000 --- a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B70.Cactus_S4AP_Trait4.TraitTuning.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - 0xA1E5B19B - - ADULT - CHILD - ELDER - TEEN - YOUNGADULT - - 2f7d0004:00000000:30f0846c783606f9 - 0xA1E5B19B - HIDDEN - - - 3056188233 - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B71.Cactus_S4AP_Trait5.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B71.Cactus_S4AP_Trait5.TraitTuning.xml deleted file mode 100644 index 04b200c..0000000 --- a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B71.Cactus_S4AP_Trait5.TraitTuning.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - 0xC9249D53 - - ADULT - CHILD - ELDER - TEEN - YOUNGADULT - - 2f7d0004:00000000:30f0846c783606f9 - 0xC9249D53 - HIDDEN - - - 2382407906 - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B72.Cactus_S4AP_Trait6.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B72.Cactus_S4AP_Trait6.TraitTuning.xml deleted file mode 100644 index 3614793..0000000 --- a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B72.Cactus_S4AP_Trait6.TraitTuning.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - 0xE3298B37 - - ADULT - CHILD - ELDER - TEEN - YOUNGADULT - - 2f7d0004:00000000:30f0846c783606f9 - 0xE3298B37 - HIDDEN - - - 3662635647 - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B73.Cactus_S4AP_Trait7.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B73.Cactus_S4AP_Trait7.TraitTuning.xml deleted file mode 100644 index 8ef8d41..0000000 --- a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B73.Cactus_S4AP_Trait7.TraitTuning.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - 0xDD6F11B5 - - ADULT - CHILD - ELDER - TEEN - YOUNGADULT - - 2f7d0004:00000000:30f0846c783606f9 - 0xDD6F11B5 - HIDDEN - - - 3922353464 - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B76.Cactus_S4AP_Trait2.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B76.Cactus_S4AP_Trait2.TraitTuning.xml deleted file mode 100644 index 9ceca76..0000000 --- a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B76.Cactus_S4AP_Trait2.TraitTuning.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - 0xB9274531 - - ADULT - CHILD - ELDER - TEEN - YOUNGADULT - - 2f7d0004:00000000:30f0846c783606f9 - 0xB9274531 - HIDDEN - - - 3927409843 - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B77.Cactus_S4AP_Trait3.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B77.Cactus_S4AP_Trait3.TraitTuning.xml deleted file mode 100644 index b5852b2..0000000 --- a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B77.Cactus_S4AP_Trait3.TraitTuning.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - 0xFBBCD468 - - ADULT - CHILD - ELDER - TEEN - YOUNGADULT - - 2f7d0004:00000000:30f0846c783606f9 - 0xFBBCD468 - HIDDEN - - - 2485735660 - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B7C.Cactus_S4AP_Trait8.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B7C.Cactus_S4AP_Trait8.TraitTuning.xml deleted file mode 100644 index b329259..0000000 --- a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B7C.Cactus_S4AP_Trait8.TraitTuning.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - 0xDBD7E3BC - - ADULT - CHILD - ELDER - TEEN - YOUNGADULT - - 2f7d0004:00000000:30f0846c783606f9 - 0xDBD7E3BC - HIDDEN - - - 3617296485 - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B7D.Cactus_S4AP_Trait9.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B7D.Cactus_S4AP_Trait9.TraitTuning.xml deleted file mode 100644 index a509c7e..0000000 --- a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!00000000D7924B7D.Cactus_S4AP_Trait9.TraitTuning.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - 0xDDFC2DE9 - - ADULT - CHILD - ELDER - TEEN - YOUNGADULT - - 2f7d0004:00000000:30f0846c783606f9 - 0xDDFC2DE9 - HIDDEN - - - 4273359534 - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!A951AD6CAA6F0CF6.Cactus_S4AP_Trait_LockDancing.TraitTuning.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!A951AD6CAA6F0CF6.Cactus_S4AP_Trait_LockDancing.TraitTuning.xml deleted file mode 100644 index 4eab292..0000000 --- a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!A951AD6CAA6F0CF6.Cactus_S4AP_Trait_LockDancing.TraitTuning.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - 0xB723A6E7 - - BABY - TODDLER - CHILD - TEEN - YOUNGADULT - ADULT - ELDER - - 0xB723A6E7 - HIDDEN - - - 9449789066976004732 - - - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!A951AD6CAA6F0CF6.Cactus_S4AP_Trait_LockDancing.xml b/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!A951AD6CAA6F0CF6.Cactus_S4AP_Trait_LockDancing.xml deleted file mode 100644 index f41773f..0000000 --- a/Package/Cactus_S4AP (package source)/CB5FDDC7!00000000!A951AD6CAA6F0CF6.Cactus_S4AP_Trait_LockDancing.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - BABY - TODDLER - CHILD - TEEN - YOUNGADULT - ADULT - ELDER - - - - 9449789066976004732 - - - HIDDEN - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/E882D22F!00000000!00000000A07795F4.Cactus_S4AP_ShowYamlOptionsInteraction.InteractionTuning.xml b/Package/Cactus_S4AP (package source)/E882D22F!00000000!00000000A07795F4.Cactus_S4AP_ShowYamlOptionsInteraction.InteractionTuning.xml deleted file mode 100644 index d60b2d1..0000000 --- a/Package/Cactus_S4AP (package source)/E882D22F!00000000!00000000A07795F4.Cactus_S4AP_ShowYamlOptionsInteraction.InteractionTuning.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - 2824713099 - - - - - - 3262040010 - - - - - - False - - - - - 2f7d0004:00000000:25eea5cdba6a6fd6 - - - - - INVALID - - - - - - - - Actor - - - - - - - - - Object - - - - - - - False - 0xFD327C75 - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/E882D22F!00000000!00000000C5690C31.Cactus_S4AP_SuperInteractionExperimental2.InteractionTuning.xml b/Package/Cactus_S4AP (package source)/E882D22F!00000000!00000000C5690C31.Cactus_S4AP_SuperInteractionExperimental2.InteractionTuning.xml deleted file mode 100644 index 4b2a853..0000000 --- a/Package/Cactus_S4AP (package source)/E882D22F!00000000!00000000C5690C31.Cactus_S4AP_SuperInteractionExperimental2.InteractionTuning.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - 2824713099 - - - - - - 3170762183 - - - - - - False - - - - - 2f7d0004:00000000:25eea5cdba6a6fd6 - - - - - INVALID - - - - - - - - Actor - - - - - - - - - Object - - - - - - - False - 0xA3CF48C3 - - \ No newline at end of file diff --git a/Package/Cactus_S4AP (package source)/E882D22F!00000000!00000000FE6A648E.Cactus_S4AP_ResyncLocationsInteraction.InteractionTuning.xml b/Package/Cactus_S4AP (package source)/E882D22F!00000000!00000000FE6A648E.Cactus_S4AP_ResyncLocationsInteraction.InteractionTuning.xml deleted file mode 100644 index e39b57f..0000000 --- a/Package/Cactus_S4AP (package source)/E882D22F!00000000!00000000FE6A648E.Cactus_S4AP_ResyncLocationsInteraction.InteractionTuning.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - 2824713099 - - - - - - 2572351313 - - - - - - False - - - - - 2f7d0004:00000000:25eea5cdba6a6fd6 - - - - - INVALID - - - - - - - - Actor - - - - - - - - - Object - - - - - - - False - 0x85F13D03 - - \ No newline at end of file From 6bdc1658adc093f858d6f030aabd170c857e8f5e Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 16 Dec 2025 09:25:17 -0700 Subject: [PATCH 107/134] add the package file repository as a submodule --- .gitmodules | 3 +++ Package/src | 1 + 2 files changed, 4 insertions(+) create mode 160000 Package/src diff --git a/.gitmodules b/.gitmodules index d280225..6362789 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "Libraries/core-library"] path = Libraries/core-library/lot51_core url = https://github.com/lot51/core-library.git +[submodule "Package/src"] + path = Package/src + url = https://github.com/Simsipelago/Sims4ArchipelagoPackage.git diff --git a/Package/src b/Package/src new file mode 160000 index 0000000..09f1907 --- /dev/null +++ b/Package/src @@ -0,0 +1 @@ +Subproject commit 09f1907e87d3c0d471e42084e4bbfaad5c44c6de From 1a6bf11d57e21dd3648434e9c2faa987bd64b15d Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 16 Dec 2025 09:36:17 -0700 Subject: [PATCH 108/134] Update package submodule to latest commit --- Package/src | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Package/src b/Package/src index 09f1907..ee855dd 160000 --- a/Package/src +++ b/Package/src @@ -1 +1 @@ -Subproject commit 09f1907e87d3c0d471e42084e4bbfaad5c44c6de +Subproject commit ee855dd9f129b61b2996effe0c026b1875b35e8e From 7d3fe55b7cd4bb79135ac5c63c80bdf790d69312 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 16 Dec 2025 09:48:00 -0700 Subject: [PATCH 109/134] edit the gitignore --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index af3bbb1..11d2587 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,7 @@ EA/* !EA/README.md # Libraries -Libraries/*/ +Libraries/S4CL/* # Additional non mod related items Scripts/rel From 6de07e67e9c6c2ab5b39d8db9b0ea449898f2207 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 16 Dec 2025 09:48:54 -0700 Subject: [PATCH 110/134] Add Core Library submodule correctly --- .gitmodules | 3 +++ Libraries/lot51_core | 1 + 2 files changed, 4 insertions(+) create mode 160000 Libraries/lot51_core diff --git a/.gitmodules b/.gitmodules index 6362789..4d5baae 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "Package/src"] path = Package/src url = https://github.com/Simsipelago/Sims4ArchipelagoPackage.git +[submodule "Libraries/lot51_core"] + path = Libraries/lot51_core + url = https://github.com/lot51/core-library.git diff --git a/Libraries/lot51_core b/Libraries/lot51_core new file mode 160000 index 0000000..b367e6e --- /dev/null +++ b/Libraries/lot51_core @@ -0,0 +1 @@ +Subproject commit b367e6ec577b5c942f1686fa55f81b5a1123ecbf From 2ad070dcd65d6d7a95e0b92d0a04b65ba310f74c Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 16 Dec 2025 09:58:40 -0700 Subject: [PATCH 111/134] fix type annotation --- Scripts/s4ap/events/skill_events.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Scripts/s4ap/events/skill_events.py b/Scripts/s4ap/events/skill_events.py index 93a1cf1..0a60347 100644 --- a/Scripts/s4ap/events/skill_events.py +++ b/Scripts/s4ap/events/skill_events.py @@ -1,3 +1,5 @@ +from typing import Optional + from sims.sim_info import SimInfo from sims4communitylib.events.event_handling.common_event import CommonEvent from statistics.skill import Skill @@ -26,7 +28,7 @@ def skill(self) -> Skill: return self._skill @property - def skill_id(self) -> int: + def skill_id(self) -> Optional[int]: """The decimal identifier of the Skill.""" from s4ap.utils.s4ap_skill_utils_class import S4APSkillUtils return S4APSkillUtils.get_skill_id(self.skill) From ad4ee845b87ef5f0f9bbd5b563734d06dcb990c1 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 16 Dec 2025 10:09:34 -0700 Subject: [PATCH 112/134] update the docstring --- Scripts/s4ap/events/skill_events.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/s4ap/events/skill_events.py b/Scripts/s4ap/events/skill_events.py index 0a60347..43fb35d 100644 --- a/Scripts/s4ap/events/skill_events.py +++ b/Scripts/s4ap/events/skill_events.py @@ -29,6 +29,6 @@ def skill(self) -> Skill: @property def skill_id(self) -> Optional[int]: - """The decimal identifier of the Skill.""" + """The decimal identifier of the Skill, or None if the Skill has no guid64 attribute.""" from s4ap.utils.s4ap_skill_utils_class import S4APSkillUtils return S4APSkillUtils.get_skill_id(self.skill) From 9c1622111b479e286046f8294b0b1a33ddf3717c Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 16 Dec 2025 10:12:14 -0700 Subject: [PATCH 113/134] update a thing --- Scripts/s4ap/utils/s4ap_save_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/s4ap/utils/s4ap_save_utils.py b/Scripts/s4ap/utils/s4ap_save_utils.py index 23209d6..2aaade5 100644 --- a/Scripts/s4ap/utils/s4ap_save_utils.py +++ b/Scripts/s4ap/utils/s4ap_save_utils.py @@ -11,7 +11,7 @@ def get_save_slot() -> Any: Retrieve the current save slot. :return: The current save slot. - :return: Any + :return: Union[int, None] """ persistence_service = services.get_persistence_service() if persistence_service is None: From b683ba67ce1db69d7b96e603671fd31551828f8d Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Tue, 16 Dec 2025 10:14:39 -0700 Subject: [PATCH 114/134] update the mod version --- Scripts/s4ap/modinfo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/s4ap/modinfo.py b/Scripts/s4ap/modinfo.py index b97c20f..ec8463b 100644 --- a/Scripts/s4ap/modinfo.py +++ b/Scripts/s4ap/modinfo.py @@ -14,7 +14,7 @@ def _name(self) -> str: @property def _version(self) -> str: # Mod version - return '0.3.0.beta2' + return '0.3.0.beta3' @property def _author(self) -> str: From 561489340f9f5d0fd34d303c3fa1be2d2d55aa90 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Mon, 5 Jan 2026 11:14:14 -0700 Subject: [PATCH 115/134] it's a list of strings now, not a set --- Scripts/s4ap/persistance/ap_session_data_store.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Scripts/s4ap/persistance/ap_session_data_store.py b/Scripts/s4ap/persistance/ap_session_data_store.py index 72e6cf5..1c1ffbf 100644 --- a/Scripts/s4ap/persistance/ap_session_data_store.py +++ b/Scripts/s4ap/persistance/ap_session_data_store.py @@ -1,4 +1,4 @@ -from typing import Any +from typing import Any, List import services from s4ap.jsonio.s4ap_json import print_json @@ -178,7 +178,7 @@ def save_item_info(self, items: str, item_ids: str, locations: str, senders: str self._set_value(S4APSettings.SENDERS, senders) S4APUtils.trigger_autosave() - def save_goal_and_career(self, goal: str, career: set): + def save_goal_and_career(self, goal: str, career: List[str]): self._set_value(S4APSettings.GOAL, goal) self._set_value(S4APSettings.CAREER, career) S4APUtils.trigger_autosave() @@ -201,7 +201,7 @@ def get_seed_name(self) -> str: def get_goal(self) -> str: return self._get_value(S4APSettings.GOAL) - def get_career(self) -> set: + def get_career(self) -> List[str]: return self._get_value(S4APSettings.CAREER) def get_slot(self) -> int: From d668c3804a4f4a14eb347a0165502b621c35a819 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Mon, 5 Jan 2026 11:15:14 -0700 Subject: [PATCH 116/134] update the comment with info --- Scripts/s4ap/persistance/ap_data_store.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/s4ap/persistance/ap_data_store.py b/Scripts/s4ap/persistance/ap_data_store.py index c417b68..2283306 100644 --- a/Scripts/s4ap/persistance/ap_data_store.py +++ b/Scripts/s4ap/persistance/ap_data_store.py @@ -48,6 +48,6 @@ def _default_data(self) -> Dict[str, Any]: S4APSettings.LOCATIONS: None, # this should be a List[str] (a list of strings) S4APSettings.SENDERS: None, # this should be a List[str] (a list of strings) S4APSettings.GOAL: None, # this should be a string - S4APSettings.CAREER: None, # currently this is a string, but in future versions, it will be a set coming from AP, which will probably deserialize as a list? i don't know exactly how JSON deserialization works with S4CL. + S4APSettings.CAREER: None, # currently this is a string, but in future versions, it will be a set coming from AP, which will probably deserialize as a list? i don't know exactly how JSON deserialization works with S4CL. from poking around, it'll be a list of strings, so it's been adjusted accordingly. S4APSettings.SLOT: 1, # this should be an integer, if it isn't, something has gone terribly wrong here }.copy() From 11641dd9cd6c5ee160f79686ee285051ab5e641d Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Mon, 5 Jan 2026 11:26:28 -0700 Subject: [PATCH 117/134] start fixing the multicareer stuff --- Scripts/s4ap/utils/s4ap_phone_utils.py | 28 ++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/Scripts/s4ap/utils/s4ap_phone_utils.py b/Scripts/s4ap/utils/s4ap_phone_utils.py index ccaf9da..f2c805f 100644 --- a/Scripts/s4ap/utils/s4ap_phone_utils.py +++ b/Scripts/s4ap/utils/s4ap_phone_utils.py @@ -163,10 +163,30 @@ def _show_aspiration_and_career(event_data: S4CLSimTraitAddedEvent): goal = data_store.get_goal() else: goal = 'Cant find the aspiration' - if data_store.get_career() is not None: - career = data_store.get_career() - else: - career = 'Cant find the career' + + career_data = data_store.get_career() + + options = [ + (1, LocalizationHelperTuning.get_raw_text(goal.replace("_", " ").title()), 1903793975082081275), + ] + + career_display = "Can't find the career" + row_id = 2 + + if career_data: + career_data = data_store.get_career() + if isinstance(career_data, list): + if len(career_data) == 1: + career_display = career_data[0] + else: + # Multiple careers → join them nicely + career_display = ', '.join( + c.replace("_", " ").title() + for c in career_data + ) + # Case: single string + elif isinstance(career_data, str): + career_display = career_data if data_store.get_items() is not None: item = 'Skill Gain Multiplier' if data_store.get_items().count(item) is not None: From b63b7d537c6de45255f03aeaf39676e10c34d683 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Mon, 5 Jan 2026 11:28:49 -0700 Subject: [PATCH 118/134] okay this should work now --- Scripts/s4ap/utils/s4ap_phone_utils.py | 39 +++++++++++++++----------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/Scripts/s4ap/utils/s4ap_phone_utils.py b/Scripts/s4ap/utils/s4ap_phone_utils.py index f2c805f..7b62b85 100644 --- a/Scripts/s4ap/utils/s4ap_phone_utils.py +++ b/Scripts/s4ap/utils/s4ap_phone_utils.py @@ -164,29 +164,36 @@ def _show_aspiration_and_career(event_data: S4CLSimTraitAddedEvent): else: goal = 'Cant find the aspiration' - career_data = data_store.get_career() - options = [ (1, LocalizationHelperTuning.get_raw_text(goal.replace("_", " ").title()), 1903793975082081275), ] - career_display = "Can't find the career" + career_data = data_store.get_career() row_id = 2 if career_data: career_data = data_store.get_career() if isinstance(career_data, list): if len(career_data) == 1: - career_display = career_data[0] - else: - # Multiple careers → join them nicely - career_display = ', '.join( - c.replace("_", " ").title() - for c in career_data + options.append( + (row_id, + LocalizationHelperTuning.get_raw_text(career_data[0].replace("_", " ").title()), + 12028399282094277793) ) - # Case: single string - elif isinstance(career_data, str): - career_display = career_data + else: + for career in career_data: + options.append( + (row_id, + LocalizationHelperTuning.get_raw_text(career.replace("_", " ").title()), + 12028399282094277793) + ) + row_id += 1 + else: + options.append( + (row_id, + LocalizationHelperTuning.get_raw_text("Can't find the career"), + 12028399282094277793) + ) if data_store.get_items() is not None: item = 'Skill Gain Multiplier' if data_store.get_items().count(item) is not None: @@ -206,11 +213,9 @@ def _show_aspiration_and_career(event_data: S4CLSimTraitAddedEvent): else: display = 'No Skill Multiplier' # Build rows as tuples: (id, name, icon) - options = [ - (1, LocalizationHelperTuning.get_raw_text(goal.replace("_", " ").title()), 1903793975082081275), - (2, LocalizationHelperTuning.get_raw_text(career.replace("_", " ").title()), 12028399282094277793), - (3, LocalizationHelperTuning.get_raw_text(display), 5906963266871873908) - ] + options.append( + (row_id + 1, LocalizationHelperTuning.get_raw_text(display), 5906963266871873908) + ) sim = event_data.sim_info.get_sim_instance() From 787652c92c525f1b8c048ebcb35363e4a2aeac26 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Mon, 5 Jan 2026 11:36:58 -0700 Subject: [PATCH 119/134] add some headers --- Scripts/s4ap/utils/s4ap_phone_utils.py | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/Scripts/s4ap/utils/s4ap_phone_utils.py b/Scripts/s4ap/utils/s4ap_phone_utils.py index 7b62b85..c73179e 100644 --- a/Scripts/s4ap/utils/s4ap_phone_utils.py +++ b/Scripts/s4ap/utils/s4ap_phone_utils.py @@ -168,9 +168,19 @@ def _show_aspiration_and_career(event_data: S4CLSimTraitAddedEvent): (1, LocalizationHelperTuning.get_raw_text(goal.replace("_", " ").title()), 1903793975082081275), ] - career_data = data_store.get_career() row_id = 2 + # ---------- Careers Header ---------- + options.append(( + row_id, + LocalizationHelperTuning.get_raw_text("──────── Careers ────────"), + 0 + )) + row_id += 1 + + # ---------- Careers ---------- + career_data = data_store.get_career() + if career_data: career_data = data_store.get_career() if isinstance(career_data, list): @@ -194,6 +204,15 @@ def _show_aspiration_and_career(event_data: S4CLSimTraitAddedEvent): LocalizationHelperTuning.get_raw_text("Can't find the career"), 12028399282094277793) ) + + # ---------- Skill Multiplier ---------- + options.append(( + row_id, + LocalizationHelperTuning.get_raw_text("──────── Skill Bonus ────────"), + 0 + )) + row_id += 1 + if data_store.get_items() is not None: item = 'Skill Gain Multiplier' if data_store.get_items().count(item) is not None: @@ -212,11 +231,13 @@ def _show_aspiration_and_career(event_data: S4CLSimTraitAddedEvent): display = 'No Skill Multiplier' else: display = 'No Skill Multiplier' - # Build rows as tuples: (id, name, icon) + options.append( (row_id + 1, LocalizationHelperTuning.get_raw_text(display), 5906963266871873908) ) + # ---------- Show Picker ---------- + sim = event_data.sim_info.get_sim_instance() picker = S4APDialog.ObjectPickerDialog( From 5f57f841b69fea1c9fa3207c6adcfed63f5f5109 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Mon, 5 Jan 2026 11:44:19 -0700 Subject: [PATCH 120/134] oops i forgot to increment (and also regrabbed something) --- Scripts/s4ap/utils/s4ap_phone_utils.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Scripts/s4ap/utils/s4ap_phone_utils.py b/Scripts/s4ap/utils/s4ap_phone_utils.py index c73179e..fed8acb 100644 --- a/Scripts/s4ap/utils/s4ap_phone_utils.py +++ b/Scripts/s4ap/utils/s4ap_phone_utils.py @@ -182,7 +182,6 @@ def _show_aspiration_and_career(event_data: S4CLSimTraitAddedEvent): career_data = data_store.get_career() if career_data: - career_data = data_store.get_career() if isinstance(career_data, list): if len(career_data) == 1: options.append( @@ -190,6 +189,7 @@ def _show_aspiration_and_career(event_data: S4CLSimTraitAddedEvent): LocalizationHelperTuning.get_raw_text(career_data[0].replace("_", " ").title()), 12028399282094277793) ) + row_id += 1 else: for career in career_data: options.append( @@ -204,6 +204,7 @@ def _show_aspiration_and_career(event_data: S4CLSimTraitAddedEvent): LocalizationHelperTuning.get_raw_text("Can't find the career"), 12028399282094277793) ) + row_id += 1 # ---------- Skill Multiplier ---------- options.append(( From 178be0fa640f10d48bcde3a6c23d341117ed1751 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Mon, 5 Jan 2026 14:37:57 -0700 Subject: [PATCH 121/134] oops that was indented to ofar --- Scripts/s4ap/utils/s4ap_phone_utils.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Scripts/s4ap/utils/s4ap_phone_utils.py b/Scripts/s4ap/utils/s4ap_phone_utils.py index fed8acb..85c1c1f 100644 --- a/Scripts/s4ap/utils/s4ap_phone_utils.py +++ b/Scripts/s4ap/utils/s4ap_phone_utils.py @@ -198,13 +198,13 @@ def _show_aspiration_and_career(event_data: S4CLSimTraitAddedEvent): 12028399282094277793) ) row_id += 1 - else: - options.append( - (row_id, - LocalizationHelperTuning.get_raw_text("Can't find the career"), - 12028399282094277793) - ) - row_id += 1 + else: + options.append( + (row_id, + LocalizationHelperTuning.get_raw_text("Can't find the career"), + 12028399282094277793) + ) + row_id += 1 # ---------- Skill Multiplier ---------- options.append(( From eb6dba2f1c83fbe22e27ffdbd92445224cee9140 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Mon, 5 Jan 2026 14:38:43 -0700 Subject: [PATCH 122/134] just use the row id --- Scripts/s4ap/utils/s4ap_phone_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/s4ap/utils/s4ap_phone_utils.py b/Scripts/s4ap/utils/s4ap_phone_utils.py index 85c1c1f..140e81e 100644 --- a/Scripts/s4ap/utils/s4ap_phone_utils.py +++ b/Scripts/s4ap/utils/s4ap_phone_utils.py @@ -234,7 +234,7 @@ def _show_aspiration_and_career(event_data: S4CLSimTraitAddedEvent): display = 'No Skill Multiplier' options.append( - (row_id + 1, LocalizationHelperTuning.get_raw_text(display), 5906963266871873908) + (row_id, LocalizationHelperTuning.get_raw_text(display), 5906963266871873908) ) # ---------- Show Picker ---------- From a74201ddc7f3406a5f8925aca54dee2a9dbbd929 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Mon, 5 Jan 2026 14:39:04 -0700 Subject: [PATCH 123/134] fix a typo --- Scripts/s4ap/utils/s4ap_phone_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/s4ap/utils/s4ap_phone_utils.py b/Scripts/s4ap/utils/s4ap_phone_utils.py index 140e81e..63206b8 100644 --- a/Scripts/s4ap/utils/s4ap_phone_utils.py +++ b/Scripts/s4ap/utils/s4ap_phone_utils.py @@ -162,7 +162,7 @@ def _show_aspiration_and_career(event_data: S4CLSimTraitAddedEvent): if data_store.get_goal() is not None: goal = data_store.get_goal() else: - goal = 'Cant find the aspiration' + goal = "Can't find the aspiration" options = [ (1, LocalizationHelperTuning.get_raw_text(goal.replace("_", " ").title()), 1903793975082081275), From 26939854b19af0628b3363362f0b9e7dc2c2b821 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Mon, 5 Jan 2026 14:47:23 -0700 Subject: [PATCH 124/134] skip checking for the one entry case (loop handles both) --- Scripts/s4ap/utils/s4ap_phone_utils.py | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/Scripts/s4ap/utils/s4ap_phone_utils.py b/Scripts/s4ap/utils/s4ap_phone_utils.py index 63206b8..b993f4b 100644 --- a/Scripts/s4ap/utils/s4ap_phone_utils.py +++ b/Scripts/s4ap/utils/s4ap_phone_utils.py @@ -183,22 +183,14 @@ def _show_aspiration_and_career(event_data: S4CLSimTraitAddedEvent): if career_data: if isinstance(career_data, list): - if len(career_data) == 1: + for career in career_data: # list with items in it options.append( (row_id, - LocalizationHelperTuning.get_raw_text(career_data[0].replace("_", " ").title()), + LocalizationHelperTuning.get_raw_text(career.replace("_", " ").title()), 12028399282094277793) ) row_id += 1 - else: - for career in career_data: - options.append( - (row_id, - LocalizationHelperTuning.get_raw_text(career.replace("_", " ").title()), - 12028399282094277793) - ) - row_id += 1 - else: + else: # none or empty list options.append( (row_id, LocalizationHelperTuning.get_raw_text("Can't find the career"), From 294b07e35153e20ca5a6965274ce781453702b5d Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Mon, 5 Jan 2026 15:28:38 -0700 Subject: [PATCH 125/134] update the package after renaming the traits --- Package/Cactus_S4AP.package | Bin 319615 -> 67571 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/Package/Cactus_S4AP.package b/Package/Cactus_S4AP.package index 8d98bf6b3f70b73dd27dfdeb10a35ed37e676928..c0f0bcd8ed3b3bb871a2540e9ce0de033f7e1bb6 100644 GIT binary patch delta 16093 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 KcaZ$~1pg0nvlAHr delta 271228 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⋙eFeiTj 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%0D~EjI?lf7#Rn$q7I;znVmnMG=?pwTe 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

      Pnm(jgzn}G6OGGyiSn>9YLLCAr;j$ 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

      k=q^eykDd22DBptW}sZ}`pk@!)-*<;b3Af7o{8 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 z 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�+L%q1bjgv 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 F!+(O-T_pej From ec5ce11c4d2e64992e44406c112c3b6030d00bbf Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Mon, 5 Jan 2026 16:40:47 -0700 Subject: [PATCH 126/134] update package submodule --- Package/src | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Package/src b/Package/src index ee855dd..db64602 160000 --- a/Package/src +++ b/Package/src @@ -1 +1 @@ -Subproject commit ee855dd9f129b61b2996effe0c026b1875b35e8e +Subproject commit db646022b858da91857043b837691951799ff7e5 From f8d5c00be19247b358f4aa715c4db7afa393a209 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Mon, 5 Jan 2026 16:45:22 -0700 Subject: [PATCH 127/134] make sure the rows are actually rows --- Scripts/s4ap/utils/s4ap_phone_utils.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Scripts/s4ap/utils/s4ap_phone_utils.py b/Scripts/s4ap/utils/s4ap_phone_utils.py index b993f4b..67b0743 100644 --- a/Scripts/s4ap/utils/s4ap_phone_utils.py +++ b/Scripts/s4ap/utils/s4ap_phone_utils.py @@ -165,13 +165,13 @@ def _show_aspiration_and_career(event_data: S4CLSimTraitAddedEvent): goal = "Can't find the aspiration" options = [ - (1, LocalizationHelperTuning.get_raw_text(goal.replace("_", " ").title()), 1903793975082081275), + S4APDialog.ObjectPickerDialog.create_picker_row(1, LocalizationHelperTuning.get_raw_text(goal.replace("_", " ").title()), 1903793975082081275), ] row_id = 2 # ---------- Careers Header ---------- - options.append(( + options.append(S4APDialog.ObjectPickerDialog.create_picker_row( row_id, LocalizationHelperTuning.get_raw_text("──────── Careers ────────"), 0 @@ -185,21 +185,21 @@ def _show_aspiration_and_career(event_data: S4CLSimTraitAddedEvent): if isinstance(career_data, list): for career in career_data: # list with items in it options.append( - (row_id, + S4APDialog.ObjectPickerDialog.create_picker_row(row_id, LocalizationHelperTuning.get_raw_text(career.replace("_", " ").title()), 12028399282094277793) ) row_id += 1 else: # none or empty list options.append( - (row_id, + S4APDialog.ObjectPickerDialog.create_picker_row(row_id, LocalizationHelperTuning.get_raw_text("Can't find the career"), 12028399282094277793) ) row_id += 1 # ---------- Skill Multiplier ---------- - options.append(( + options.append(S4APDialog.ObjectPickerDialog.create_picker_row( row_id, LocalizationHelperTuning.get_raw_text("──────── Skill Bonus ────────"), 0 @@ -226,7 +226,7 @@ def _show_aspiration_and_career(event_data: S4CLSimTraitAddedEvent): display = 'No Skill Multiplier' options.append( - (row_id, LocalizationHelperTuning.get_raw_text(display), 5906963266871873908) + S4APDialog.ObjectPickerDialog.create_picker_row(row_id, LocalizationHelperTuning.get_raw_text(display), 5906963266871873908) ) # ---------- Show Picker ---------- From cdd0c91c5feee74dfa25b93fa82b919895a057ee Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Mon, 5 Jan 2026 16:50:46 -0700 Subject: [PATCH 128/134] check none and also handle legacy strings --- .../s4ap/persistance/ap_session_data_store.py | 19 +++++++++++++++---- Scripts/s4ap/utils/s4ap_phone_utils.py | 14 +++++++++++--- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/Scripts/s4ap/persistance/ap_session_data_store.py b/Scripts/s4ap/persistance/ap_session_data_store.py index 1c1ffbf..43f80a4 100644 --- a/Scripts/s4ap/persistance/ap_session_data_store.py +++ b/Scripts/s4ap/persistance/ap_session_data_store.py @@ -97,8 +97,14 @@ def _ok_chosen(_: UiDialogOkCancel): on_ok=_ok_chosen, on_cancel=_cancel_chosen ) - dialog.show_dialog() - return True + + if dialog is not None: + dialog.show_dialog() + return True + else: + logger.warn("No active Sim to show dialog. Treating as cancel.") + return False + else: # Settings exist and match logger.debug("AP session data matched") return True @@ -133,8 +139,13 @@ def _cancel_chosen(_: UiDialogOkCancel): on_ok=_ok_chosen, on_cancel=_cancel_chosen ) - dialog.show_dialog() - return True + + if dialog is not None: + dialog.show_dialog() + return True + else: + logger.warn("No active Sim to show dialog. Treating as cancel.") + return False def check_index_value(self, index: str) -> bool: """Checks The Index from ReceivedItems to make sure it matches diff --git a/Scripts/s4ap/utils/s4ap_phone_utils.py b/Scripts/s4ap/utils/s4ap_phone_utils.py index 67b0743..61ec0cb 100644 --- a/Scripts/s4ap/utils/s4ap_phone_utils.py +++ b/Scripts/s4ap/utils/s4ap_phone_utils.py @@ -186,15 +186,23 @@ def _show_aspiration_and_career(event_data: S4CLSimTraitAddedEvent): for career in career_data: # list with items in it options.append( S4APDialog.ObjectPickerDialog.create_picker_row(row_id, - LocalizationHelperTuning.get_raw_text(career.replace("_", " ").title()), + LocalizationHelperTuning.get_raw_text(career.replace("_", " ").title()), 12028399282094277793) ) row_id += 1 + elif isinstance(career_data, str): + # Legacy support for string career data + options.append( + S4APDialog.ObjectPickerDialog.create_picker_row(row_id, + LocalizationHelperTuning.get_raw_text(career_data.replace("_", " ").title()), + 12028399282094277793) + ) + row_id += 1 else: # none or empty list options.append( S4APDialog.ObjectPickerDialog.create_picker_row(row_id, - LocalizationHelperTuning.get_raw_text("Can't find the career"), - 12028399282094277793) + LocalizationHelperTuning.get_raw_text("Can't find the career"), + 12028399282094277793) ) row_id += 1 From 3bfafb0b3752a2dc3190211fb2103e5bf133293b Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Mon, 5 Jan 2026 16:55:13 -0700 Subject: [PATCH 129/134] okay this is actually what we want --- Scripts/s4ap/utils/s4ap_phone_utils.py | 31 ++++++++++++++------------ 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/Scripts/s4ap/utils/s4ap_phone_utils.py b/Scripts/s4ap/utils/s4ap_phone_utils.py index 61ec0cb..4a337d5 100644 --- a/Scripts/s4ap/utils/s4ap_phone_utils.py +++ b/Scripts/s4ap/utils/s4ap_phone_utils.py @@ -185,32 +185,35 @@ def _show_aspiration_and_career(event_data: S4CLSimTraitAddedEvent): if isinstance(career_data, list): for career in career_data: # list with items in it options.append( - S4APDialog.ObjectPickerDialog.create_picker_row(row_id, - LocalizationHelperTuning.get_raw_text(career.replace("_", " ").title()), - 12028399282094277793) + ObjectPickerRow( + name=row_id, + option_id=LocalizationHelperTuning.get_raw_text(career.replace("_", " ").title()), + icon=12028399282094277793) ) row_id += 1 elif isinstance(career_data, str): # Legacy support for string career data options.append( - S4APDialog.ObjectPickerDialog.create_picker_row(row_id, - LocalizationHelperTuning.get_raw_text(career_data.replace("_", " ").title()), - 12028399282094277793) + ObjectPickerRow( + option_id=row_id, + name=LocalizationHelperTuning.get_raw_text(career_data.replace("_", " ").title()), + icon=12028399282094277793) ) row_id += 1 else: # none or empty list options.append( - S4APDialog.ObjectPickerDialog.create_picker_row(row_id, - LocalizationHelperTuning.get_raw_text("Can't find the career"), - 12028399282094277793) + ObjectPickerRow( + option_id=row_id, + name=LocalizationHelperTuning.get_raw_text("Can't find the career"), + icon=12028399282094277793) ) row_id += 1 # ---------- Skill Multiplier ---------- - options.append(S4APDialog.ObjectPickerDialog.create_picker_row( - row_id, - LocalizationHelperTuning.get_raw_text("──────── Skill Bonus ────────"), - 0 + options.append(ObjectPickerRow( + option_id=row_id, + name=LocalizationHelperTuning.get_raw_text("──────── Skill Bonus ────────"), + icon=0 )) row_id += 1 @@ -234,7 +237,7 @@ def _show_aspiration_and_career(event_data: S4CLSimTraitAddedEvent): display = 'No Skill Multiplier' options.append( - S4APDialog.ObjectPickerDialog.create_picker_row(row_id, LocalizationHelperTuning.get_raw_text(display), 5906963266871873908) + ObjectPickerRow(option_id=row_id, name=LocalizationHelperTuning.get_raw_text(display), icon=5906963266871873908) ) # ---------- Show Picker ---------- From fafb1fd9b0ed55819e959822aa99f96869cdae6b Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Mon, 5 Jan 2026 17:01:16 -0700 Subject: [PATCH 130/134] oops i swapped it --- Scripts/s4ap/utils/s4ap_phone_utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Scripts/s4ap/utils/s4ap_phone_utils.py b/Scripts/s4ap/utils/s4ap_phone_utils.py index 4a337d5..7614852 100644 --- a/Scripts/s4ap/utils/s4ap_phone_utils.py +++ b/Scripts/s4ap/utils/s4ap_phone_utils.py @@ -186,8 +186,8 @@ def _show_aspiration_and_career(event_data: S4CLSimTraitAddedEvent): for career in career_data: # list with items in it options.append( ObjectPickerRow( - name=row_id, - option_id=LocalizationHelperTuning.get_raw_text(career.replace("_", " ").title()), + option_id=row_id, + name=LocalizationHelperTuning.get_raw_text(career.replace("_", " ").title()), icon=12028399282094277793) ) row_id += 1 From 17e8898b36de0a16c13d62069a77b0dcf9ab8bb2 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Mon, 5 Jan 2026 17:02:21 -0700 Subject: [PATCH 131/134] oh god i didn't change that (thanks cr) --- Scripts/s4ap/persistance/ap_session_data_store.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/s4ap/persistance/ap_session_data_store.py b/Scripts/s4ap/persistance/ap_session_data_store.py index 43f80a4..f009b73 100644 --- a/Scripts/s4ap/persistance/ap_session_data_store.py +++ b/Scripts/s4ap/persistance/ap_session_data_store.py @@ -125,7 +125,7 @@ def _ok_chosen(_: UiDialogOkCancel): return True def _cancel_chosen(_: UiDialogOkCancel): - return True + return False # Prompt the user to either overwrite the previous session_data, or stop parsing the data packet and wait for the connection_status.json to update dialog = S4APUtils.show_ok_cancel_dialog( From e1d2236393a56dc370e0802fe73d18494cebe6d5 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Mon, 5 Jan 2026 17:16:44 -0700 Subject: [PATCH 132/134] hybridized async approach (thanks cr/gpt) --- .../s4ap/persistance/ap_session_data_store.py | 47 +++++++++++++++---- 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/Scripts/s4ap/persistance/ap_session_data_store.py b/Scripts/s4ap/persistance/ap_session_data_store.py index f009b73..97930f9 100644 --- a/Scripts/s4ap/persistance/ap_session_data_store.py +++ b/Scripts/s4ap/persistance/ap_session_data_store.py @@ -23,7 +23,7 @@ class S4APSessionStoreUtils: def __init__(self) -> None: self._data_manager = S4APDataManagerUtils() - def check_session_values(self, host_name: str, port: int, seed_name: str, player: str, slot: int) -> bool: + def check_session_values(self, host_name: str, port: int, seed_name: str, player: str, slot: int, on_complete: Callable[[bool], None] | None = None) -> bool: """ Check session store to make sure it's the same settings as before and send a warning otherwise :returns True, if stored settings exist and all values match the incoming parameters; False otherwise. """ @@ -44,6 +44,8 @@ def check_session_values(self, host_name: str, port: int, seed_name: str, player if isinstance(slot, list): logger.warn("The slot coming in from the connection_status.json is a list. This means your APWorld is out of date. Please update.") + if on_complete: + on_complete(False) return False if isinstance(stored_slot, list): @@ -54,6 +56,8 @@ def check_session_values(self, host_name: str, port: int, seed_name: str, player logger.info(f"Correct json file for this slot: s4ap_main_guid_{slot_id}.json") except Exception as ex: logger.error("Failed to retrieve save slot ID for this slot.", exception=ex) + if on_complete: + on_complete(False) return False if (str(stored_seed), str(stored_host_name), int(stored_port), str(stored_player), int(stored_slot)) != \ @@ -63,6 +67,9 @@ def check_session_values(self, host_name: str, port: int, seed_name: str, player def _cancel_chosen(_: UiDialogOkCancel): # If cancel is chosen, stop parsing data until connection_status.json changes + logger.info("User cancelled session dialog") + if on_complete: + on_complete(False) return False def _ok_chosen(_: UiDialogOkCancel): @@ -82,6 +89,8 @@ def _ok_chosen(_: UiDialogOkCancel): print_json(True, 'sync.json') print_json({}, 'locations_cached.json') CommonEventRegistry.get().dispatch(AllowReceiveItems(True)) + if on_complete: + on_complete(True) return True # if okay is chosen then save seed values and resync items # Prompt the user to either overwrite the previous session_data, or stop parsing the data packet and wait for the connection_status.json to update @@ -100,10 +109,22 @@ def _ok_chosen(_: UiDialogOkCancel): if dialog is not None: dialog.show_dialog() - return True + if on_complete: + logger.debug("Async dialog shown; awaiting user choice") + return False + else: + logger.error( + "check_session_values called synchronously with dialog! " + "This path is deprecated and unsafe." + ) + return True else: logger.warn("No active Sim to show dialog. Treating as cancel.") - return False + if on_complete: + on_complete(False) + return False + else: + return False else: # Settings exist and match logger.debug("AP session data matched") @@ -122,9 +143,14 @@ def _ok_chosen(_: UiDialogOkCancel): print_json({}, 'locations_cached.json') CommonEventRegistry.get().dispatch(AllowReceiveItems(True)) self.save_seed_values(host_name, port, seed_name, player, slot) - return True + # existing reset/save logic + if on_complete: + on_complete(True) def _cancel_chosen(_: UiDialogOkCancel): + logger.info("User cancelled session dialog") + if on_complete: + on_complete(False) return False # Prompt the user to either overwrite the previous session_data, or stop parsing the data packet and wait for the connection_status.json to update @@ -142,10 +168,15 @@ def _cancel_chosen(_: UiDialogOkCancel): if dialog is not None: dialog.show_dialog() - return True - else: - logger.warn("No active Sim to show dialog. Treating as cancel.") - return False + if on_complete: + logger.debug("Async dialog shown; awaiting user choice") + return False # prevent auto-continue + else: + logger.error( + "check_session_values called synchronously with dialog! " + "This path is deprecated and unsafe." + ) + return True # legacy behavior def check_index_value(self, index: str) -> bool: """Checks The Index from ReceivedItems to make sure it matches From 9510c1051bc00bdd432a2b7db5b08268ab279348 Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Mon, 5 Jan 2026 17:22:36 -0700 Subject: [PATCH 133/134] oops the syntax was wrong for 3.7 --- Scripts/s4ap/persistance/ap_session_data_store.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Scripts/s4ap/persistance/ap_session_data_store.py b/Scripts/s4ap/persistance/ap_session_data_store.py index 97930f9..d3f1fb6 100644 --- a/Scripts/s4ap/persistance/ap_session_data_store.py +++ b/Scripts/s4ap/persistance/ap_session_data_store.py @@ -1,4 +1,4 @@ -from typing import Any, List +from typing import Any, List, Callable, Optional import services from s4ap.jsonio.s4ap_json import print_json @@ -23,7 +23,7 @@ class S4APSessionStoreUtils: def __init__(self) -> None: self._data_manager = S4APDataManagerUtils() - def check_session_values(self, host_name: str, port: int, seed_name: str, player: str, slot: int, on_complete: Callable[[bool], None] | None = None) -> bool: + def check_session_values(self, host_name: str, port: int, seed_name: str, player: str, slot: int, on_complete: Optional[Callable[[bool], None]] = None) -> bool: """ Check session store to make sure it's the same settings as before and send a warning otherwise :returns True, if stored settings exist and all values match the incoming parameters; False otherwise. """ From 0277fc7086e51b4351f99261b4a34bbd8c1a29dc Mon Sep 17 00:00:00 2001 From: Benny Dreamly Date: Mon, 5 Jan 2026 17:24:22 -0700 Subject: [PATCH 134/134] fix the missing else clause --- Scripts/s4ap/persistance/ap_session_data_store.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Scripts/s4ap/persistance/ap_session_data_store.py b/Scripts/s4ap/persistance/ap_session_data_store.py index d3f1fb6..81d4612 100644 --- a/Scripts/s4ap/persistance/ap_session_data_store.py +++ b/Scripts/s4ap/persistance/ap_session_data_store.py @@ -177,6 +177,11 @@ def _cancel_chosen(_: UiDialogOkCancel): "This path is deprecated and unsafe." ) return True # legacy behavior + else: + logger.warn("No active Sim to show dialog. Treating as cancel.") + if on_complete: + on_complete(False) + return False def check_index_value(self, index: str) -> bool: """Checks The Index from ReceivedItems to make sure it matches

      Ve-g-p*_x?@r)D4b^mLR^KaSX zw4u;SF|7F)>~WeY@fG$sw;v8L~Y>=OZb)cI9tRZUUuBQ8fwli|{&qBbocjt>c-U9j2QB9j9DRO4syWRO_BadTl_)Vh|0wo2=l28f zpJ|VCDU|t7?Q#Cw?E`LjMz%7WZ2N$pi>CU2?F0UY*ay7J*+$AC^mOB8`S2C?0e`U4 z|1JA~$C-ZrihaOE)bT&iKHx{u!??>ou@9&ve}DUcOBIAKvky3j)T7u3JcpRt|43i# z1D47;;lFAh@XM#v48}e{=%GKb|GV}93$U8_*X#qPNX~z5AMoF3fA|=dm;Y;j==n!b+(=!tV>ugjU-;RQVmY)Edz@G7>uQTWmZOdM zjS}Ob$KZzKc&?;@5@MBeTg3)9Kb!c;8P@$g*ykf(Vm2emxAIYpY~&-ST4R)nj+on^ zz*D)(CD&vz))C7aZJ8MBJj$E=6UQ8w1G{yMc^)kJ6<-#;BDSVvc~a8(hsBQA67l63 z9;%l45+@vknRNfKVDAY34RSeUSrxVd201u{vl4N6j#aZF)7lu`~WqUwqdu+Hg^zhoE!(&HFF?bhgYDv-*yH2GUm>}Ix=vsbgLXp1iyCLFRYW5MpEgxx{wXdjZ8+Kk(ZFD_zft?kD;e?lPQ71LLM4v?&EW zDSb4q5@V-j8MO35S}N@sr7fG79=u*-sUbhP$<38Ua zN-gv$RxQMB_D1gDVtdk6xo3dlV zxFO`>HwT_V3*KOd*fCX6kUhj0jS`h@!AVHc2u5Z>tWt?TxNb5M-^;{+Z z%n>wLa#)5Dl4^a=v%gakGo{zbt4cCI)9f5krVu14GY=yrCXl>6l_~wyLc4gU8+POY z?7#LaQ>DqqvF!fL9|7DhD%mX?Ckue(Uihd*J%|yeIQg*g-#{J8+#}RL$HdYDOMBkD zwa18Uhc_ZN??lVhLSwCTtc*Ie(61C0x>Brhh_@}Ei533kt&$_EqqgdYvNdU=sOqch z?EwIm?!r}!uZdmMe~^|!O3K2=!trlW^xLC@X%7lfTr2fr+=GLD3)@1&HnzoB(ngsn zQL9qWCni2(dVZ7!6bccH=-)5Nezr^D(N#e3bu~Y^sK8@&~nCskT zjKC3+xjNaj`0(EXog5WgPYOmJqyQ61Yy2L}R1grKQ2dlh^aIQrU;|oc5MW&US7CnQ z02PuGqsAnS-b6kHryhW*a4c#yz47#G4oe5D)Kf+}3?lazNd}S9@l@_GPRx?tj)T(x zC$>3wk>H+Cyz$shpmV;BAxkrUT`udH1lqtn$2u_;be9{SmdP=m4+EV_F%9up20FLK z*B54yEI!f~XXunmMCExixdz z1=ryL*37w_nIjH)Lc8Uwuq6F;E_;(%+2@_YS7<@*hPI;&G22x;cVhf`$Z^LsZ}=D? z7Hb|D<6*4k<93D=^h#ds-d{kQUqWFR@ZDy7`VOV9r?gO0Wb~9r8LCJ<<~}VRty;`| zWXTe9pRds*+uW!8Z*mG^oBIT@XY%S_n8m6EeV87JIf=3jGrM>LshO_lVF_Xll4(!2 z{6vDxz?6g@PJilx3p25Jk{d-TMOlDA>mj$EMU+Be(s9Ia< z;WBKim5{@AD=c;hQ;)w2M?6_`74?X{KtKO& z*sfHxgl89=e>)B^Uh?X1Xb(()xHuSRS61YS+*IVN{Rk&9tskUc6d8NE*Rdl!Fye8D zEnCkX6kYPe^g+~pn` zJvlCaxx*?30#3+@CPBNMt7q?U>45^Deo(yHyhIEJ1j_Hbz$#Wu6&s|%+@Q-0JJ6@} zfzwR!n#m1ty-j!Z$=#>mHo0#%=S@#-2iHLxxnsi}w3fgqPh`Am#_;e(eF)vT(c=W4 z5{@8{TKgwbJ5zvKEI)e*AC}6JtRMcZ{f}1mY{{>LYW0`(*J|XdV;Ogg-MSIn`ie{E z-Uu%P3DBx7ehAGu)*hQ4;V3vBU&S3h6*peNzT$dqc`;BRFfOM!S1sIcbRRF=y3+*$ zV>OY9MXkMAo=1p)M8v#%30be`F^nf!q20Djud_|RsBg|EzA`*79VBQH&cM8psm*=S zd{1yYVJBL+0Ih}2hh>Hbxg(W$i12?@Q;Rv{#DdnXSykHeQx_Mx^p@b>;jS{AA0Kdo z>rx|1o3SLZ);E{FU6k{sT4Sb2X5onia?Rr@noWMAxQOn-+RKF*GV{mCGm`hwj|Zk% z_fb33_>yKk!ZJ)W7#nLx*%ciH$j=oJ;p&}OI^tbz3P7SOvHv=vzME85Wc+y6Qpx&& zHGjn`p{&$)|8Qf8D=_1mkXfBat8cCIYW28u^%$u{(HebhN6#rr^H~>R}C_C85+swRlnxlEU7i}L6>uSXL*o?fM zhb2nRjI5Y?PS4wAJ-g})q(VTnNvdgo-K&i{!1w*Q8r!38l`MXP&gpG#kyB_{>$U=s zUj((pfu&6}$Q3+roKJtWq=AofzlrbeXMf59T#L`OnG!ZA9}iOe&0G)6)!M!Dz^hwd z6PJSI;vAsedMjTh13@kdzJi$+wR^NCC$)#!ri6I;6*2oe+oA(Gu(l<~a>>K~mI&ZWCu~?pDcD8N$0%FO8ID4dw$Mr)!Pk ze+LxZ#>y1eNr3JrOByH->mSOGtP>v^h@ZN%R%wf4$3T5r=_(mehGqIH{?9sAk|D`9 z`2!JdFV?LQpB2$nKHc0AUKn7#K9DYNM zd0QWp8h0Ux(@;L#Y~6_`0_8Qi>!Gr)l;(PfTWA+9ZOWU*<7&@p)E&>zfDXB5Iwtac77A{^;`%QeI+`vb43k~@ zTx!%G3qqhL;Y=y4YJSNW?!*xvKt>VgsVKA*@6s<|5U1yyZ(f4RKLfv$Fm^%MLF!H4fxkHhF&zh6xQrfj*Hj|?WH5T~M-e)vzQh|K?p(}SXl znR$;%88y<^Ff;44E3$rUeQ9Mz!^4C}zE86&rP*=|wMnjb3rFzOcAh_>Kzraf{Kf}< zrD9DDYRXX$vr$Ga>czXLA}Z{Y}PlKBcBg*;1X#%o$ILZaS_DhsaB zlCG~- zNgdVtd*RD7-TL}!JZnW<4tLoa=X#rT7n~Ee*iht>L&5hB`Ag_;xvOl0D>B~E7_&2J zzif5(YQJm?t=B^L(KDNKIkYA7rO)$AuBYyDm)-}5;o>}I&qMUKkyA^qr*Dp_C4OjB z<&b?*7r1waZ!Vc^!&dPuWJ#XxfGP98$LOXvLT`{Yft8OD^r= z)n#ObciW41*=lG+x_>Ul5Tc{+CC2}p) zR35HGqdr^3pjPa6QL+Ghc^+|T&)*y>3Vt?xKT$6DJ z{($jgrnxl9>NhR(IPmXNKbSg=yH%RB=Qbfcou=@vi1E)%F}pG8+L9;urC6(q-X$@l zaa0Nfb+N>Fk{Pe?f!Mst_!>MxI%d#h#!NAiF~Qa8=H<-C@Ptelo72!DXQ91;Y$rST z<8izINU7WZ{BT}mD8wS(9L%4j{2gx(R6dJbEQt~y3T{YKW|quS1R-l$IRTQ-VA{{f zTDe5H{irS+Yrq+V7aKjwawECil`AaES~tsH>$FCbnZ2B-&_aCW z=3v;Anu_6PR6e1DF){~*(e}J;21plPP=+3j&wjq9^}LIGaJ~6HTQVgn@!cce@vbwq zWU~23+5E-*2Ur47r!b(q(54oW76hXXb1-jp+!weWI+J;UWAuSwSC;Qt!i7S^SPOB- zb0$JoJ^qjm7|k-<_0GoqUi}ak}5lQA+lH=`> z_za#rC_&#g_(8?T11E^gDHnA1r#S+-A|uFJyE2nCB4qv*~_$mz&ca)V)x5}Qo{Cul%T4)B$LebiRmEw)x7(@N?+qny(R-fpd779t) z$)vGSBH2#pG;;Xl)mI1YzWTrzeLR2@XyXO6cwE}z7jXb0v&xNI)U@4MMl@pvb@&No6v( zE$-ELhcH%)Jn;%LG(KH~RJ8}j2`wgR_wdmdGAfUr1pGMqjF&`wv=K)wR)b`aj38P$ zFeZcLKHp+E3s+ZH?581>GI#N;gy4xL+vLR+Tv!0tKZ6n0mR_zjwqv3N(q96mXrUbt zkG6C&Xzge?==4M;#QYy4f(T$Sc@gBKYv+sA9t#XZr8u538Y)msj6pJ&&~fHe`7tTIRVxr~ zuTJeW`>?Z2vJLaE=%5s%BVNUk{0$Is?q?pNV4}u$C?ip$SgFB3D#b_QeXyP27qVW- zQW9tWiKfrPAVcv;cz$VOh>=@N@zSVL)Gb5BQ_Ziz2W$7{f%`aF{FN^DWB6V|-VfB4UWBT)yWv2&7fT>N?uacp+zg>( zriqmj>o{yNSH+ElTR$b-+L|VNW$Fk|3`{cXqz2}j;(w;hHj4+I3wwnD#(9B<7#?In zvuT_tDY)9vTcHKxEe?d3rZxI!@HCl5VJHR8@O1EylMRuK)#}73R5qQ3idm}j>AOsc zawG7e^fY5C!<~dW0U*I%oQ{ecjliJFh7a+JdK&Ml2STp0`Yp^he=f~uR@dXU=(?iCJrdSqmI_&4l5Kp_t=5 zzb`QHVYBABLVrn8vl&1k^vWokNKl&6d@}%R0+nEtp;Dww)q=`3K!mJxGiaA#knh0MgIY&)hNe@ z9Gw%@fp#0$GN|A?4%E~TXcB@}=mIrcEe)?oUP~gXSNX&CHV#aCQ3Mnr+nxM??BC*l z$h5SbZs)znH`y$&l|QH^kJvGrZ^OfBM8DR_$d6%{rchyuJ6Y*P0y)Zs8ut&+OHjtQ z5X_U5F^Ulp%2;xf^zo3>f0r+{l4xGa$3zY}H>BnICWRMRE*DI!$?9*UJxiXVkku)*I?*Y!ogz#>#1LzCKFkt@ zr1hl>@w37Rk_)jp4Z>Gw&>AxUMJ*3JN(U0XuH~bmZ}H{{kBcYBTJQ}9ktw);HB(Uh ze37P*t?b(ry0r(2A(K=zw<#p&0kxvVs`sIm)~%W9tK8a>D59LWqTyBd9l7TixwObr z>n*@de{Yt!R~BK*^GI;paBt+~`@E4+_gM0mJ6wZ1mg>wGi%Hklm%ZWIX!@M(+P#9b z8hvB4D@?#7QKEAWkhyWIzTTbFPMrwspVRiEQDwGU-^I;z?=Zav$N zR<{N1b~j4)^ynq_{oBq7O8w9|0bQ$QOVaLfMsb>R$A@Y?mNMbVeM(pFY3Pi)aSwy9Zbf5`witkD%qA50my0n9G2yzS;kZA6S_zDIX%YPA9-p&q&KY5E5nioC zUtXm4%Y(SRd5q|rgDu4b$(#EL@ny8<);PMXKvkB1@^IFJujioS-h)KsznRtO3=s=Y zAui-wdvdJZVQgbK>-%IP!T*V5t485oiWfws_*k4Zg*4Rmm!LqNF0jJGey}?yEw+*0 zxA9xOd>a%PXDoyUvWoczbBB!YO7IxH!J|C!-C`bUInUt zTedzu*Z*{9rA14X!YH5)6*R;KND!y>w`KsBO6RT1NkggVMH9f0LfIN{{E*Z_P&ZHO z0rZjEGxQA}$9m7A1ET1{Nd%RXi9?yf`vDSNob109FF~#_uOou^o!L1H&jb}6a5+!y zlx#+BFf9y@n=0+}gc(5nWd0xQKihDTcgF!mltkR(X$Tu3(udM zyI=$dN=OPG{g6I$agjb3cm~x%vP>a>35Q@+otVuDn^7q2n6qwzvTaf;`{B!a=uR?- zT56Xe7FN;6?fIwhqpwrqtMQ7Ug@GHSPcLGyWS}iHB=MPIjThWe?5n-Kz*qZSP6JWu zZLD^FvOvQ}1P&2uYCi+xzFMPVO;yA{I?aX0rd-rjt_)vEwsE6Xj}~f?8Y1&xeXn~W zqkb$6bncp?bxO@t-J0ofzBCsnwe3aT;HsjFBcqXe%r{DT~uX{F&cYpfF@RM{|i&Rj4EdUvd8o#T<}vV7Czm z(puxgbg%Vu&U8M*i^*lgs=WdAo7#Md`4FFpseEvKPFhr3|2Y@c!{HYpig2 zl$sv5=uFansdO|mdNJO2m0Uibjlc} zMIW?kpQ>sfx1dw?(?2{o?!9hWpfzf0?&jsvo><{ow8T6_zpO$RBB`k!cKT20tSpj% z0CBR^v(6S!b|rr%66`7bmVXsH&6&Wo=_BQSN-6kv>96T;gl{cywI0giEGF#Db~|=P zu68)v>yJ?*r;bCN?F)O1HfgbVie06Jnt+SOlgMC2^`~Hw8)MyU$P|7p%Pi3>`lM#W z+Q2S}4&jSjTon9xcunNwMgD7-7fa!a4Q06ZuH+1Jh^)^otk12PoVc?-uXpJl*5^z6 z^j6o#?KRGIbKgXjhl;6M&)2Ho#&0U3xQmT;fpHcH@v*tF*?{uLCxBd(7N8V%>682B zMx$%&{`+dj7ld5}INc4LdokQv+Q~#dSabFfI*PLmAg($H#WzCU_G zOR&p9eA|7>OK_5&ta*-1KSc%8}z*Bp9 z0n*TqB${vonPp9Y$~E zE2;5LVy_+9CthMoN{LtIZt;}8!X62MX=#s5jKf-@KWyCUB4pWm1rq7f8@Z?#dD8;EZq76s^(l^)H=5+$_`W-5ooA)=jE=`V zr*?aCHbs9#O3)k}D5}^3&_vTnG6M=f((WxAwtvlcV0xEpQCC`8ej09TkzJ~_>Mq#vEzH$@Ztb~^ z9L#KtDoyWifT3_*jh#gq9eSTMcg_}i#!9KgXV1wld`)9`gKb4CwBXh~1^#MRhmfJ?8hoTwFfTmSVp>-VthPf{S!n=0Pr{3q(5_+R&6A z*x4^&qmmb=dsKWjmUKceGH(fAtcA|zMO!-56?V9+^%*j$453;1Ej>dI`Unrl9Sa*! ztg!Qcl3(H;7?n55JG4N}e25iRe<)J6e}-%$%f;|vUIn~Tiky^-j}Vj_k`BTL0+_eJuu*2?<2Uq@F%hGNmZYt@w5Y@9CA!Xs9{Q~YiBljkZuk#R4s z$zia&H{&>ugZ<(=Uj4W`P<`!|c1a-DVsF_dd>xC$RT!}Wec3vXbKji7Y`_M3JE=_O ztoSIYOx|9wBr7b}K4ed=@5Dfk9$w(Vap(onh?tZNy-&NKnUenflB1Aa8?Cp8PdNo#$w?s z%UCH}pcEWp855vR)fE+jGBy5OKYA(WJi@EL2GAM~C0#(_enmKIQvlnaa6o`V5#dt* zh3sqmff~#zPl#R&Tt~at(a~^sEX_X|WoUYh^V2)d)0Q3QBHE}ZU^W{a5GzFSs<*R) zmLT%%rZ>_S<$@R~J2Bo~J&+cCH@QA~JF5j{tjnJ`qMh9LWabn{hbQu5`l}9iy^hx# z=4TS%g<#kn+!{%#+-p_-T6B>Da*s8T_TSiuGv3KbYi^E>xCd4w&)N3#I`zDCvS%DC z3NzMMQZ)Mn&mvR(3NkIvRBtME?#IN3@$hl_jDFD?N;ip6`+9?sHGukd0nCSP4MI+eM1d$i|K$?v`p zB}}^(`Uweo>x-2Z=@aq-guoGXKVUq@5XId1J0@CXW$wyrhW))BB8m}Iil$8GE0PEW!Gun&n%HW zb-t{C!XGg&qz3ZSjp!Syy|V}Lv!bQOxqfa3Zx&a5E+Ox=2=L#>2gO?d!Pk`_D@Ty! z3lGINBvIOZI_76>fir8IZFfxf_HgBCJw<(b?$O&~tsk-(B<#cU2zxyjHpT)jK4|xJ zfU6pub>I6uFX$x@ETc(v}25-+ks`B=LUUrY%U0OeTU|@(Bfjt*Ro$mxfxUA=U zjlR}fcF=o5m%aznSQ$QsWV?5xQIoU&u=D+zvh_75Y*JY7GUawh9FYn7zH*yI*C*P~ z?eAH?@3Wt??dO&D^KAQhn*H3n)ylukeh#&t2j8{6ue6`n+0TRad|GKgf2W>t`6Zn7 zt@fO>ez{RL{7ZQm#Cec{Zvm}!y1C_fmBSmE{7Z#;C1IEWmmx!XK? z)`FQCB48I^r4(i<@-_UL`+#{5DPWpa_|I`*$6LQ=S-@;iXIP+0ElB8uPUSHJ1s_w+NZyGn1`xk_TA#hw-PhC?v%FhS|FFUg+7}s}Lmu|$Z%dyD^ZN~I#v!CE zxtM>8UL@Q29H-~e?bd$zj{-y05F9t?V+1GkTXO&bLfq<+_mDg^cek;MVpgHMq)_6Y zls3-0g2d0ES>x({iR9{Mk4&sw5AmZhHu6Ny{M|c%mhIrhT)cCY>Juupr4y>Tobip0 z32xQ`SFtBNqlhJ;b?ZQ1+rvHNS+YfkQao@H%If6lwPk;MEr% z=?YKl4IaEeTfCYhGO;ptHxi-2h;8MB#K^ni5SqV9*@mAJGhbv*enY(*>GL@H?$h^0 zACo*{6q6he$vn}@Toi>t5cmDCbhe#yij33AqadHiOY|wp_$xBH!qvMy5j2Oa=EP$= zx6S9=J7=_*!pHZc?Cv|WjSpySjq{7SyS!!Z$gwF$l@oeUglC``Z=*CzJD@&QNdiV) z&67&brxNP58u1IDm}QV#vi;$#o8}BmYZ#M;?`RUL!vSZte%~*D3JsjKix;g?G*o@bdYRgm-K|c!W4l zw681y1p@CG=Di@pohk)iaWRMDSvEXDySb zo?-41iBt&wataDju^_0IBE!uK4rL*|cC(9YaefPw9J@b_PqQheRFQFfy!bJ^(7Iyt zAytI+o&1|`v->aC6chb_lpplpNYZ03;F9>9PkIuce`CVN=|_*l6Puj`JmUy>FY_e{ zPdbr=cS8z1rwy-h7!9!JZ+`0h)q=NESj}O$hBbdn0Fa!&n4~a&6~39jt=9ZC&!?31 zpXEW#M{$CkXzyzlJ*D*jtbYCf8|lgR{*AOm|KsrVRCx1`fVYZ$QnLRu`@y>*0gqAd zm{6T&OyP?f%!{m-V#8&egTakx75^5;eGEk;A(YM=) z9twoy{wC4BpbU{r>AQI8-_WoH`c(LwOjh9pAEIMa@@k@dRlNMStd}CA;s`+BumJTk zf#QH31(50w?c`gMPkkLe1%0rkSFGv-kabj6)xW7?iUgs3L=7}E`W^Ob7XE=!Xo2Ve)ybs=g-}ws_{ks`Un~uNGP#> z3P~mCX){Vf^Jy4yKm1xt@99!EL6zL$@8zO7<18C;%MXt?L|+vO&~ELX6TpwM!JDAE zQTPgj=?jl-^S169fJ#IQ-AV;M-SFvqm5RbG-D%7AuHS_g94Hcr)V06U5#aC!IbJk6 zB32l`QFvDh9)3pG3BrXgXb!r9_9CMWibJ|`U=|LH3Kq$2u{mj8(Ui!$(@T-tB-pPv}u zzaoUvum8aPs{T{#sQp*yO!glEarT7&i@i6Gi@N&$$3amCHx{>nFu`?P1D6Ds929Io zKqN~bOK=4<14SKB6I_yULcuISEy2pb%0MfDEWupBCBa<4r9jQV6bg+0sn2?B3S_!=%=*bDi25cZVB3ikFQyN4$|A<<#=W9b@57sl>DR=qj*F&p`m29CWl4OI1FPB*X>R4Vt}i9GEBZ&@>~4u)e^fNdgGaQ7@gTWxve5tZ?aEh zCiQs4K4Ql1q3R6ReGIpB?7tP4*;kKTZNatzo#7&TLqeKYUP-O3dpuzeO8PL`#7cH3JJHKuG``+xDt}_c^tGA_}vBy{J zc*71CD|7=a{UT3Pv9$f0vY)*$M(X_xI%jXA9sBLwK=z5sw=CF;;66SpmP(gPYuLwI zb%lSo&?RknMVb&g<2?%i>1nYOZ|6fj2C-S#8h-sESe2#TitM9w#oad zZB{>K&&rz$l`c>NRo7FJJ=yy)5`h)_7>XzRVLva+>Q~rNqhUW}BetBaKVHUJrt;dx zFO$5bhrSNIDwoEZs|A+kmy|7SsD8uevAWKa>N&j&djV;Tldu&TC-6x zu`?SM6E*CH+~m$|+nKCky*;rr>*a|W*3B`USkQHO=G;+ zU#pmb>~FIeXZE)_yH~@0v%oW7ij{iB*EqPHuVFAdvFvBBTeH`#O|JtO9?*dIV|YKn ztr%_v{v#MZ!t`3YA-QrEyO0ksIxz<)+W_PAcB%lwbX!I{v7N22VWO?AuQ8^b+Sd?c ztM)bewR840_}MxKFiaD`FpaNqPCHj$!yH@J0Haqs_W*;JEqg<5zm`!i$f|C|xOKya zgiMv1_BEBw$`jJ?8a^bE0XD0G*c$JX6lbej@x<9?wHMRaXVYxi-F^0;qpoSQb~D-P zXMM<@-Jh@ijO_q;f5g}(a&`*~8VXJ1iindzs(xsjS1Msu#9k+r!?Phfh{Kk-ICM6_d2+v8l7z<3#sO4bC2+ zVr#C=%H>k)vyP3K#r`&ld7b@j8Z(CdwTfX+20d=Ze(8P1=U8Q3~*Qy+bAzchhSf`|*mEmZrV%DmEu<+3c9uj?IpVwrqAxZpUWFWLx&O z>GXEeCy8v`St?pa&ARGKc2+U%?|#N1){)YDo@VQ53}92?fR#s))U>8GbO7r>PiYaA zmJx451#8;oPn*`M;MuuQSrx|aA4uOSW10((+2rHP|0hb*>VvWo(5<7jQt(x%cv!s4kK87= zo{roM#-6mm((@N-1@%kn{{NwAe|fshv>wEk7FX%ZR#?-r*Ztu22=;n}>2-jy{h$Ct zdw6ZdUR%LyC-&OO^xEI!D*IF`OOW*y16#A^i5Vm{t*g|ugQR7~l`S)VgV-|T=PEVr zAgO6xoqdf<25Ec^OI%sgP8`IVcA~4a%nXv28CSN<9AeANRo1l92SOY6BWeF*D+e3D z?Y)iTwBBsQS+RY$VI%ZoANg+B2-$+oM({IxVZS2X@Y!r%nGLJ?XE&Z%%}20uq!G-1 ztIM=e{a=mXr=u{y*!ZZ$K`E{H$`Su`G@C|nS~Cj^oCb}LU@vI|d)ca`aqBFN+haHS z6_v2D`K)-rHa7N`ZEWl>+t}D&wz09lY-3}8VPo4TFAk=SZ8+Q5*bZ`-?LghxYj*F! z^m;IRJs4g)vDZ$f*E(bS;W|Tmc-@b^?kB(Ycx!>*vniob~FWW?P&)+t{XeVZ&&;JKNY|y0DEc#$DRjx=0(FJ3IDG?81(H6Wt|h zwy`~Ci^FQhtuwx(VxPZgv0$8^@pX2?V83OI$|q^|6MtjS6TjgdBB!tm6q^l&>}6Z_ zlD+b@E@n#MWD{QCttzxx)t0qC!+vHM+liUtV|dr1I*fg$h|P$z;nIrpc8&23b|UfB zvL6a;$4(@sMaMKZzGAn%pU#a3WNs8G=0;z3qZ$t+N7xZH>Ak0OXswy#d#ux++9{VaP`(N(y#lI}RO z`?;py>6Y&Cvd35rQS91cG1~(4Y>16vBTUN%*fci2!q~ZKK07u=xwDkCIzxn(ooRJ` zhCrR4@y$R#LvWy-m3Al71sc7&)FnkYH*9My z^Vo7`QFZVyQxmW%vhP~_)n~;~mX?;a1iPY^u4s*~v6cvAbM6Hx)#?}7$FLjPzghL$ z(jAJ$w%*1tEt_cU1Y^3+)JrFrZ%tWf@dWdjb%jL%D^O<~t@cgoSJRM(boSP=Bygxp zKjr6@G)X>u2P8S2mKUl0Y>~Ruut?RL7O8sEB2{l%r0PwJRK01Ds%MK7>jU}p%{qcr zr!_k)%cpD|yErl(oS!?1KRuzdg{_qOUkxt}n40$=SLF8pReLJ#Y1gCH5 ziI=Qu>CyLw_HAQ$i>*7xSgl8$G`vlhG(Fkg+i*$4+O*+%#*aPS+_3b+orCJj4a1wg zqu{gRH+BG*R_tjk(J=P^AXA_EvajGYy?@)mft3f>Q(kOZN!L^C^0$m#{+brAd^TX7 zo=G3D%ikv0qX9|n+2REokJO`cS<%>|ZCIuLFE;jZ4U3mfaSp|Ghi>f8E^5y%cF!(k zrj30LyPm=W?6VuYpR{=SNoUeI(wTIQw6S|h8@t!Di9&K*Yq(gWmf?2sH@h0`H+1~Rl4gh-6mURJ3eXp zLH6dxRht##*|+QKzVu>uJH{o=xz9f0e`{V%^)Lpq@nCv{wQ76i!za~u8Dd=eQ2I!J zXDPxsWZ6XNoHC8Qr|~kofzj08`kr*h!e-@T_913=qucg%X<_J494hUGY{0P_TZS>V zKGx;ZHA{6lb29p~ud=gQDg8_XYZzBXC#~<^M#mL@HTAQ;$o4VDmTj{3-)}0c$706j zXz`m^JJe=k1{cK=*<|7z5R`$YJWorqhq&ML)F#8B%h=0yMI!s%HQDB z-N)cK)AL`e?oVuNR;4mWcBkrymeO` zj?u^ZAL%xVpRxY{_EjD1CcW0v>;VV6k$}VkJcfZAM=S(}NE4<9^-gN$fb%u}iAEvuE73`N0 z8uDRDWU(()Vt1J}p2NMhHY@fs>-EhIcJ}eF>fxrhQ)PasydR$_k9{X#_55er-^)-| z{flX`$^M4A>N55|$TNIp)uT-}H;}Kax{SR6fc+=&2P(=ds(ypL>x6dp;o~*zErJF< z*8MNA4|q4|(s;-*ZI8%bQ2h$~#BW1b!voB^Vvgz)s^c^?S-BmV)E(WlUpK*bnomiZu8`_3oji<5WOhaHFo0XfHyUzG? zwj}UVBL+Q7B}szVL!vQOJ_h!Y9K$L}H)>sVmaB5vtLiq@(oh`v=NoJ$y{Gl4!py#8 z#>VgavW*9CyS0?pn9&zuo0`v#Ah1nEv0YW(p1x*ZXv@9_w1scd_q_@js~@|W&yFZ; zksGV6UdxRB#vBR9yxGCb*2kD;g4n~t?7K|IsC^6xlJ3vmU+^isY3*;BRm9ZlKo)JN zst#tiv315^b~!O$Tm3!z@?iGCkm^5~WV6?q^@wwIq;w`R6jyIxQhxX5aXEXt$@FA$ z=hs-vKU+9^``O1ZR&Dy3d$w?#dcYQrm-;K;>|yUOu}{YS^;Y%v7mMIsCzgciU;ICd zSZ+`MA^sHk|6l!Iv;ceVO7TzML2J@Asu&q}U98ZXfnL>IwmVqpP4?a(+1hLRm)=ne zuNoJ10()R5^YNJ?JLJc1Z<+pOg5I6z<3O*9nQ3~ZhkB%f%mrBvvYO}*KnEI&BH#%I z+}cuZpPVjn=wgy8wN{~11@o15O6ec!vSwkSanj;TlT7Zc)N_emMRW`fW_y_QuLNWr zNWF`U>$`&N2C_TI9w2*y>;+OI%dpAX7o+fh;C^Ip{#sFuvUZuLeoSx5aoZhBPYEiM=Aw zynjTH(yj_t>h7S|gvfZsTe8%?Ez77WvaAECvx>2h{@t;X+v5^Q92ePPvcJixkw5xr zN_#}4Qcowk{vD+~^IfH`ny=I?;*@$6(c_mW?b>*yUY4NLH7k^QyiuuJz(3m$8^_Te zC9qp0nU4<^*s}$8)mroXVFG)uz;3(FJb#41ULdfmlg;x-3G77zyK{pLeBub3eL}kP);dGJm+Y?R`MyxnUX57*9h#oZ_M*&LVk`= zFzRiIJ`{93$2zx_+gA%R3}gbx6ryK<4m1ttSPQ^&P?GDkOhNv-Z?#Bik`X(Vy28km z0)buqo%whiKgl-c$6plKcY(w_Fg_6Qlf)iR%6HFJ<`YbGDsP^}Etu z@K~wi_;?EfQ13)^AJ9ePCC657$3l>(mx2y7&yAN#^e5xR^@$ck8kH5quD9@P)DOWD zfn8&1K0aPxFB8~Zo0#WMCH7P+^ZqpgyRMn}_;i82PGHCJ@)|TS>b69816?$JYVGCm zW7$rYsM~>#{a6I|g>b!b0Xw~J4sLF~{+RDzlCKTXU-}>O&w)G&F&~hnAbI&$qCXk` zHG=$AEtT~vdr_&Ydnk3+o=Uxl=wZE-_8N^+SNBuu?w}VD9P5eFxxX?Fag=(2y+mM- zfPF8xgZXvb9qe%+v3!hI1HOr4uWK*!=M%f@0Q2?J4OH6eMk@7Wty0H)(wfGaQp9r+ zo-+bR%l-}Ll@a8;0(up+OLRv$?*x#@Qvy8L4n<>>d8oXVx-00p1P{|G{j$d?b>v5h z^;30fyuUPljmKksOGthHq4fpcaFAGEt-q4DE=blRUYBJNNX%0ouJlJ7W!csRrk5p9 z4&o>yBINkw*|Lm(SIJkmP^o7wQtHTqvMf$%k6)_P>)u!D&MTFA)M}-U?HM&vIexZ) zj^n3LE%#FnNNmq^!WWz*^B1j?r6yTfUfE`)j`c!`?dj|wmxnmYx^!iH*cY;1v0aum zU&&IRDNAjZEQ>$}?vVBDuVsn%Ew@2=J3wOnGGYE;`DMH0IMma3EA_zdl{)&NEXY;b zHF-)so#>i;rM+&R{JzRv$kWYHZl@rSSWYm+x$l+Zv7T$dZ#_t?r}`JA-!-u36Tf8e zQx(eo`h&{2OW=Qp#8rVG=0~OWkjz7I)Kdla8i8GR*gSu_z^*D%#@7%%s#s~)98v0F zM8|%-{({_p4?sFPDaU;xiNp3lSs}2yA64doaVV1ob{zk$AfQU%uYRm7FWGi97G;vj z?UcH0d!?==x}NCSM6V#ax`UDr+qr3Hxm_oKTn-YGL%(i-hl3nV{B*!y2GYHwTwW1K zO($7T1X%@Ar^;+e6oCP|r$DS`jeL&(o&TJ85s#3h0Y^Uc2 zwAUPtGx_oCt{i&=tcMv;E-$|3sLX$frNLFBo|t=j@QKhgM#**N-W{{zg7*k7!OlSl&rad8H7S1G3WRhb`~6-B2?4g|K%r zm!7{#%R|004xfv&+%Cv>&0sa2Vy6+#@HA37MXg)m+%yUO*)`k_4m?A#uPx?2K)~8{R%20#{SR#>DT8TZB5HVzAhZT zQo`pjGke*xlNUDh`)s9aNUwN#F=nK+e{uc8Jg6P#fA{Xn@qzjD;p7tz{$3z^-K=W6 zd%?rHUq7uZOZPAQlhzOW7xSR)iS3R3yNl$bgYi`gIPze9FyDckeC>M3^}7f0o90e> zH#jtR!s*0Ehlb9noJ8|QzF{1`aKdL9+3vT>2`yf6cP;zm(z2z`jc?=|%i+rbJ{+HC z)7R`B`p%;Tfw$vdoV)OR8O;yds}SO7dt!Ul!aT9;sqA00V|#Yz*gavt@e{kSKt6s|bV}Fd}^oJ+-cLy1mylP#uH6D^4{W;-drUy#ppH6T+v%X%(ItrML8Kvsct ze^JJRLFz%Kg3JY32C@bu)|<*qIInqt0rf{j$LAJxUF7m959;Xxd!4|J_kS&V%l%%V zk!1nM43IfQPXQhC!27>ZfV%)6z5iS1tgKJEi&8J>q118wxsFqwzef_?m*^2hUr2N# z(bI_jHPL@2dMVLw68#C$?fsPbI}_cF=);IUhUkGrpG@?*M2{!>TB2_z`d38%f#~~* zUP|-|qTeR^L!ztvmF?4x=v|5KO7sy#A4l|HqR%G!QlfuI^bDf!A^Jh0pCtO9M88h- ze~4}wplpxUL{}5N2hm-LK7#1uh#o@pnM9vQ^rb{!P4rZve@XNlqW?_vBSb$<^h-p) zPxL0^mF;Is^d3a_Ai6ivClLK@qQ67*#Y8s}eG}2Q6Fryc2Z&xy^vguQL-a>Pw+>Xc zPY0rRC;A|wk0yE`(Zh&7kLW9joA)Am+jhqD1jc7Vd;-S9^YLh>{4U^E2+}xl z+S1Zb!|wK+_0ff2=be-fH>?m|yd8Z+<&zyg62odwoFy zdU50*tGimaS+f7#=k9mV_*z#vMa=)AM|{!JjD)`u-WzHdw07!q_nT;ZC5i98Ypp(H z_a|v(OXj!quf3%f9F;)PxnZ2#mAJm?N>x-GMe)%jes0>| zV{U$b{{9!yR}L87?^P{|4=3^QZgX#B-&*z7napdO+a{Hr5XDa*@&3o$dTvNK_TP6S z_YWT$_PMVp-jl>v2JJ7K*0dyYP5O+n#^tTHh~nKyyz%_-HN3oQ9) zMbVm{ciX=&zgcRg{c}is-_l_(9h{@uW|#NrwxW@3eh}3^gTx;n`)6L6qhZ(Rk7Ing zZ5aAc6rV!k+s1dF`clgAt;X6ygkob?hKD=@){Fk>krnNr%)B8c2MDfui zzG-E2;pj7Ws$$ODdneiX<81?O|AmwI^*?RQn%-qb=j+R~#?pwL!u5XwiT}3m?7Alj z3m1Ou`Sp=aKQF|`$hhTulK7r$(&neS^s!xbqONE8TMokY%ZE&OlPc-Y5 zq1)&Bxv2eINc`Y8A9)q5YMa{sxG~#h%DT&0|02|Fq|7@4t7B7sZ#7_#H#KIDh!>!>SP}_bT4p*V9=PUr6G2-o5$Fp@VZ5 zuZsJbiAK6s3`reGMTU{Gf@o><*D?3HyCy;pi)eBdLZS}po;wxRn?vJ|&*Y9W& zKX35t4c8a2F%^LXh@;cu6ND}*RKgA{_pL(KRMyv zbd>AHHLC6Z^!Zs-z9)&FAMoCpWX5_?#&HQSFkMt~(>fwmI7;CrOmQ9f^-l%!u`v#H)&tk##W!dvf*at+rs+S_E*mTDP@DE_<9Z2_N&eh>+r)-8&Ua{B;N0pDQ^^Z zoBDdhlEncLzyFagiZ3Pc*5A&npQvAIsczvvxl8&|OHq6wi4XofWaQ6Z_n7kX!e2i+ zlcZQj@2)&~64!+*Q=NzH?d0it*}5}zMx2ud|vUe{rSr>04Go0moLE+l?; zd5+HU%Rig;^_^DItlzi7_1})f+YFp*2+}QGFzNleA8$XLvR+iaC5hkC%l_-DF3F>l zT1A{XpYzvCqWIc=%K1Mi>(GFUn@0Mi4Ds#%`0Cl?qWDS@|55s$T`S+4^yeo{&U|^j z!=&k=_)-$@*Jokdi|z6kMt4ogJh(UMx%b!T{#i)kKdCxUojB**n-}+dT(oJ1qj3J@ zkoYDE?^i$YUv}rsJ(s`N?9D6}<)1;~w+y!WZSjZUgAdJLn>uS;TjBbfLgIIPy`}rk zUHy(8|6=^Wo>TpW@d+e;r1iQ*fxk@H^G)XKXX>uH|0>Eqn#8aDy!Et47l-OL{Nxt> zQ|b1Roib8UcbAL_}~Bj-m!y? zL*Ee34i3E*z9QUz>_~j6>YzR>eDjmQ zT@bckZC~a5Z?drIkd}w7uNu!s-w(>1E;mTS(#$Saw=9cDr$R?-SG81l{NwD=I&S#DCy(^V-L) zowMg|s|+hzV`wjm&mi&N{Ijop`jtZB|BX#c*>)m! zT4Id8X!(tAI*H;FNPN-iTc7zvENXh*qfcM!(4XHC#YdC)m|e#<9Gj$CczU6#T})EX z-lF($62H+m;c?lMGk2z`Q>U$&HxoY=#yx*eAo2Rci4RogI`0U0v>~v0JBk9F7Voja#beH$FiW??U3U3eFxqm(+E4 zn+qN9#MyY~i{kA_d`+90^Q|@v*;o?s+jk`!6NLS5N#f7`GGx_PXTMrCZc>{9+YV7n zMdjD_QO^ICx3!B_9!_s*A2+jb%?DPWisCCt{LpTa$XR~wGmmQ;gD}37#E;7@ znR+0$ro`~OQ@eXP7S^Kj3rYO^S6|<~c*d+YZ?x~|v1xGbbI;$>`IkfDI~=@w{ji|e|JyUp9;FfJgk2q^uLd`i}Ft)@qOBM{pg2IEtW2sH)N*k zu8;eO;uA>x^2#?q{HN-#&wkt=c|U3FyPHMv(Ih@;!v!DzY_DC;B^x>>TzM-~6dz9F z%kmeV8Q#aPSDnZ1f*lk7$P>j+An}#yQ@-B0w&25n&)fGsv+2=6QM@OK&wu6e@c5tq z8}|2qpN!1;wU>`5-i^fj=bm!=c9F;5;d@Rz$WCG3Y6<^%>$eMu&v~g=$5UHldQNTf z>6y08i-r529f@y!XycC3+pqti@6_r-*oEJwiORPm@jE)@^i_}gd{LTxUd@GkpR1zy zT6k^>-~UUPm^5p9v(FuVx^m)I+gD$CK@?v};ul)p9;({8v9$ZBtNjmFUe6N6my-CA zPIIR=-*M+9yP4hcj(qjX8>09^62IW382h}*R$r9N+g}~GZ1!{Oho-0eyjK-S{9M$I z@$x#j4J7tAJ}-xPr1nxiFNQeE8i8G>F(02Uu-6IffxXT1XA0~Veay!P3+&kfyQ;5w z{xE?(S75j8XP!SoU@s8Z)&0%$M+xjj0=x47^Za^&y+mNwykwp~USKa1*j-)C^Ct@I z6#~1vn|c0ZfxSv#*A6t#pDM7|2<*B+=K0eF_Bw$*aIks)Oo82Ei23+nfjwJbSG{bW zKTKfH71(Wun&*!Y*b4-9wYz!#D1p65V0ZQ~QO9Xb!F!TKJ0(+Uj?mFB&f1}3MG>sa&ri2{3t z!0!I4dH!U9y-Hx$>df<}3hXrkyUxcvf4ab4C$I1 z{9c9M-1CyDoJr#KH{!#980A~=@I%QJ!Fzlq?OPYwq^ z!oe?b@OlnT^Tho7OjEWG;+_P@JVQA6JPy8wgKr}^mdnetl;dAbaLm(ky0Tt~J96-W z9Nd?K(>#$sj^n?c;8@=s1V^4i4t|b<-yt~i^YV0=(Rlj|BRKK|5ghZ3g*~U&Om|@L>e!<%xJC$3KDK zSZ*2z-^Ia?aByC`)pPvqBO7mrJ_N^ljV3teAHu=s5gd7Vd1erQ{>tcsq0@IPwo8IPy&3 z;Ilb6%@cVx5q~Uq7s1iLnBeGtiQwq}fP>r5QMLo}@bdKJ_=gf4%Z(;D@~vP z+ju+BJdtM@$3KYRn9pnuo5mANhR?!o$9(Q^aO>#C+rfq4$nU|yg9wi0^72gJ_;2FiIUKy0;FxD62d^hMFHgjK&uhGW zJUMs>!7-m`4!(wi^V%(+D z?k70%mveBMC-St6QMLo}xNz`c96X5N$UmFl$e%!P^ylT7L;R7an1f&9;PnK@a_tv1 z-VVJvIL#CD2_^o>Kab$(Z{XnD2#!4Y1V^4yf}=k#Ps@eM`l7!h!I9sMgZmO3d8QH^ zd15&@%@cWc5P!rA36A{b9Q+Q!k*DP%Wji2`3&GK!m*)hIeivNKyb`+8^O^( zkKpJ}^F+Lw<8Qe{SzqLLAUN_2Bslu}aB!Lr`p0qn*K_b41jl^#bMSJ4W4W~iM;>0D zE=wD4pJ5z4h~UUSn}a719P>=$;51L{Tvhk*n~e;Mt^EWwc{h2Y4;%d?QJsOK7|udJ`P^ zJqeEdp&UG#;K*a(;51M4&*%7`Bsk`Cje}b*Z@j(^1jlmS2#)-`Jj01U^28AwdDe6A zEDl~saO5xN;51Jxx8(|DJ0On>!O?#h2cN*fBMFZD2?R%eUYu366Qj z5**8=c_N<0@h{}y36AB`Jkfs*$3KIE=X3Cr9Q+!=vD_w!%K9SC%hQecW4(Mh z_*4!a$HCVV9P`;ha4eVRiTF9j{epLWji3=m4go>IPwQ^a9*AX9RE!O$9!@) z_z@0%iQt%LJ;9Nm=867&)+pNtaZiFHPY4H}$HCVS9Qn6#a9*CJ9RF&9W1f~qWxWu0 zJ-h{tjK*ApE1cMu$T3OV>Wf+Noz4$jNd<-^9?XBfeeKZxL%XCwz- zPH^PeL~!Jxd7}Rjof}{Tff}_9vN6L0U zoR_C3$3K+dSZ*}Ik$(-r(LaOW=$}t;^rv~E|25)|xa9_AeUZn3;OIY);OOr|aP*(b z!FhS6aQw3fj^!2-9LqgNaP+SwIQqBzxbb$Nc_Pm+j(-rrk$*M^Part*rx6@^c5!fC zo|VKO`RfUe{Pv$H+X3<31Vl!{{E^>>;K)CfgU1pac~S_DJUa-E{xna-&k=v*xx>M&QyXsw7lI?d2f>j)h=cR; zOyKx$;@~+PyqMsaXC=Wg&w36{^F;sNX^pp!CkGE9IOY>gaO7V@aP+77AfC_hKgq$b zaquRa8n2fl2Y2J(ygb8+Kjt6D!Pj%}9R$aA+t0zv36AB`Jdvm6W@S5|zY7N+#=(OK zj{LJZcmfCK<(WhLG0$QSeu;zE6CCrj-=b^>#CsDQ%cXfD9!mU?XCA@P-@w7Q5gd8) zId~}t=jCbnY2)>EBsk{j#=(6Fj(JYy;IRZpewrup>>&P#7ZMzK$~pKQf+J7M&l+zB z7Y@$La{|XdlHizU0teqjaLjWT2QMZ#^3yyKujlyNZ*9CC`Vbs>JPD3@hH~&|4$jLn zgZN{)`2@#uPZAvcs|k+&P0|~$uLHr6hvtbqz8wE>f}?*N!I3|O;OM`DgBNmeUY@nY zAIr7QXuKV|5*+#%SI|z>X z?C0R+9K4o;^YV20qVe__#=(OKj(N`J;0YW&jo{dBG*9F|!t>|g^#n&A`!ALCMZ7l$ z_vGNbJfn#}*2}=bw-Frk$>-pu9K4#~ST4;IamVeAx5Ge!qrVTqG0&+SJeGr}aByCp zg&hBL1jjsU366QT{HpQ#x^Qq04o>q#{z&4F`6Lh={Wo#&91dPgaO9`?AYRY$x6f?6 z9r|!^PYxc!!J|1iFV76(kNM{l9NXP9GsVDE%C>CS?_4P9lCOG4-P(ogGUk^%cXfDzKQr_yY1rO#T>kngFoQlc3(H% z4!k@)IsTy>Jeq?WICusJ&*R`UPi(hpj=$wMjn~(KgS&BXAA%>t_pT*|$=}D83g1%} z3w{a2zigfC7kF5fwnZTS1KD=6>GR;bAg++ar-END$TE<1Ak`0L9(RzzAoUvJ7M$NcCfg2N?`f4>A>GF32*Fbs*JGARc5eNIl3@khvhs zK-Pg&TZ}QapF7B4kb01*Aag;Mfvf|mwuE?)!65Y@Q$gl}ECX2wQr!gNK?Z}=gG>dP z3$hGk9Y}RkhzA)AQV%i}WG=`ukaZx{RuB&|7^EI#D#%=rWgzQ7s+&PP$Y79qkf|VZ zL6(861F3Ef@gRdi>OrQ0%mrBnvJRxW1;m342B`;`3NjaD8OS=2Y8AwT3A>GF32*Fbs*I(As%Ef$S9De!P&^4B7xnxmCV~ns0q>w>?H!b zrnPzgc!9l4V0Ud}oF%sA})-0#U{wvfwngE+Sn%J0v`{AO{= zOM$p(kh?2=5-cBqV<1|!&gc8R=1j+uq}D$$FXr%7P}oa7kPZK z96q-_a=T!Dn*R4^&I{aC_P_Rl_6^dgV%eGXp&;cJ@sBq)A=^_)@bCPwE^U$l+K zm&oBO1wQPrzUT5YzF3jyo&4tVpVdEXctZKGzbYY)*I#Qn<$319I03n3(ic<4tyt~v zeJ@(~tJjh;S|0ZQ1`b~e;me=>`-xdW^WCQo{Z7-{KjI{hZ!3qdlJKP+@7rp2*H+g* zZF6cxn@2A8JihH5KDRt&eWO2LF?NL0ruPQDUi@VI*?AjyeAyhn1j3gRdR4!p>Y#H} zxtEo-ZT9oO7X|Y@kHc3=_*SI8mo+_Pa>ma?hH5u{vb+~Bzr!3pmwaV?zrDO=S*_hg z{rd|#d^7P-&g(qBqa40y!WY-kuVUv6s~4i~y7ie^)h?CCcap z;g-EKRZ}^a$9IOqXZMq`zP6WZljmedwD&Q-->H>n%tIdEMGjv$;rr?3;ZqKHjawR5 z<{0Aio849(-%So*4&j^7RFxe&?<1RaBhK7yTe9aIkM9nL&vLJ_zICp>BXcv_Cv`pi z>c4xpUpvj?`(+hE>hggF)%tzK zj_1#C`@=d}-Vf=1R!jJtPnAXClO`AE@bYWV;q&}i*?vE6SkUZjOl!8e zoEexgZ}xXQzU~~p6vF5ITk4GezK!_l!j@4d9^Z6+?)OV^J?+Qgt0a7rr@V6J-+o^; z*Q(Q8zi;EyikIKZ96q;Sl=Yn#vG2{q^2TOO0D6o!_^&<(p89l%Bud zGSPiOj}Y+V_|!tZ!a&A@%mA4KvJhk`NGQev$7coLmIvhaqT{njkdLO1`SwT@*sBC~ zU0?J3nF712pZWN}xk|fcrBcWCLaAD9-d>ifv=@A;)NwqV2SU`Hh<<_SBS9DSf8jy7 zA4@@2f~*AzG|%_{p~m}PwUy+bq0|e$RO(nCET=9@X-6ET`fKxc_ixSH)!F9lb-T>l z%YHC#&&@S&PyNZfUH^-DdvKw7yZZt2_TYo&?fS#!?ZHRP+x17y+f$F5x99$5-mX4j z-tJy%-X46?yj_3Fygl`_d3&9}t}Zhl?_O@+9(>-s-Te>qc6FtBd);O8_Oh$y?YY(F z?Ws4++x552+k@|zx4YjrZ&%lux7XF1x2xd(%K%uA${v~buX}9XUgG41OPfjRoRzx1 zt5R1uGbOl(dAqyDyj|VbyuGf!d3%|wd3&9kd3*3c^LG7U^Y+vs=Iyyd&D+b|&D-mS znYXJ)n76yXV&1OyG;gmPW8Pji*1TP(Q`)OQ*Ns!+bX?)S><8S_t<*E4lzQp{rJlV=saNThI_8a1w^(TpPEhI*tChONhq4~LPKhTHJt|pguOqrX zMQK;9SL%sG$9x;)N5r4#$sa52Vfjiu>J-sky&I^d7pbF^di+GCo*kmpRpCm#XtoXq9H;QtUmdT|Ke|eQl{c z|4=psJNjD@f0vW8KT7o1|0kD^am@%%bE4x7M)YqYmgp^r zj`hI!CScb=JB2{KBZjMA|aki z>Q@ea)gV!)eg?3kj0K(gJpi0a>Sz7CJPxU(eh%PACHmFCxW)TH`fbYlL0OU<*CyuqlLht~fjzLPdH!sH-PX!{e3ZamBCxwQGtZwau-6Fefz8eHXAA7= z7RvZ+l~Si;%GTPvT~F-lma@O5l`LyO>RSU(8(9{COl~XdY8zQGtD`J)L26%sIFQLsvaaqd%XE;M7iB#g zqd~ zWLYpsmJwrRsr8j*(W4+!m)5qC-{-(}HY!NA*F?w?*X`slmFxD$MBhU6ZA9Nr^skA& zi|DyTFCcm`(SIZQDWYE>dL_}TiGG{tbwqEvUD+P3h~AFqjzsTH^u9!QBl>Wnk0p8l z(L;znjp&g?UqJNtiJnCCG@@@M`c9(nCi+iA-%s>nqMso81)^Ue`gNk;A$mR0n|-D1 z&(=h@C%PliU5MU?=&nQ`Npvrw`w=~a=+lTEN%XlyUqtk!L|;zyM53<)9iLmPI3%wd zcs-Bn2ij{6H*SxBbKZkL6IE|gAMv@zm3jRJ&Hd`ZqYdl)e3Sa_If~~7jK}=SA)fXh<NPPke9P`*eYE_KcD1MDb}P{>wpK(tavSRypkguL1BrKC^j)*S+G5q>Va9dd$6O*r@v#t(?K{Ho*$-DPbi5sY`0T$gH-GmJ8jtPk zajEg~h2uMxW5;+L-`;WG7B+0Lv{dZSR#-x^J?kF0e4pmL#fk4kW(w`0DQ#7TRs^I_``*rO(xmMDf-ne$$?itAQWA+%NLVowLa! zqgROHA6%5j56Y1%f7mJv*XJD)_Xtq z93;&@590SiymPNVeq7#WpUnxkJlYP*p$@qI*2 zi+TIb#y6YP%<1#ufX<&B6vanEJg%dyzS{P8*toXSd(~fgT=qdHVgH9f{A5_~tSw8U zUmG0tQXhwNDXFg)H@s=Vo4-B~zXakxbGcej{6ff#pm`(yyE!oEfGB?th{tt&`PhXW zIzLHuNT|Dhd+PPP&qVRPA$~8Ef9kvYrxpj!p1W|@$*phse7;W6()jqJg;5=zvt`_mnX10-B9j-xW8c> z%@6a({VSBjV}7xK)BOwWnEw_|JjPKw=7;>e{BZxRC;TdGU)VpZq5mF2JKgB^#j7vB z*R}QS!u?%4{&@cw?LQh{4)NHIMOIeRG*7r^ntVP!6k01PS z{n>ATcCTyu+J_tK zexKg|w{D{HV<8^rU;D?y>I=NC7Zv(^+HK3~(tb2P6Z-$bE%Wow;ihc&xUHNYI*3R6 zWPyDN$Bw+X@6q}D0IvJ@3gU5|@Zukmc-sDv(0*IMZ~VOEVO?+bYJJGA%l_^jzqX_8 zN8>}V{~-R`SDGy9)pcxy--CUVUtRwmK4!vQKYbwHsYY(+alN9Z*4i3oy%z5@bjD4e zI#Kx^r2m^tyq~;fN&UJ9RsFQzzqx!kjc@3GD37im*uQxF;8ELn|CdAm@a%Yfxr7s+ z2m2K_9^!a*?Dq>iept`A@o>Mx=}zPILw;^N>@Sl!@p%2XgxGQYMqb+f*gv?xS@a){px@h=vC|KX1Bjko3({FYPH zdgMJ(`Na_b5aJE>{}mnDcVvzA;kzFNzqfycC_WG3N5D7;UA|^~Vct8fwjDnFBp}&y zmMA_8;wMA=(rLRt@%SWa>sp(V9lMJz{3nV}Bk`5D$JXAnR&C$++n(d@lX9N>TqJEj z1BqXoy#BV^Yu-gAo$j4`bwYe^QTeeDzXkGd_t{T37f#L0^jr8@lWMnt-;3fSAs*+c zW%9MG7k+u+zt-<;o75&I{C!b;2#I&N?CrS!%TpIeZr^!!^VbphaS!hJ^&#;OS040O zva;Or?}OLIEEtd`JpXw>yc4Vwr?$+huo~NX_t2N#46l#qd|Q-%Z-}1^@fZ5X4GP~k zZ`=K55)IxFn?I5)-CaVIDEkGc?Tay z7l!3zcNgXV;G8`Fah-GNw*O|nRj)vo$g4j7o;`%uzttqZRc^A=lbQp!Uats#{qYwM z@Z*Tw{wpW(hWwKs+(;b0{QTXZl849K@G&}Wd@;mNhWcMC{`lrgb5HMIS<)`|#@54s z)B0P?mfv>|16cqv6W*6WfAu@EAL>*_3G77zyYn3L{Ca`CL}1svYn~tLi_bB}3;fFj zcGtP)%S#m4D+G4;_ssJr3+#2oo*t#-i;7n2HAL6UQ`+(SfnIwk&mT9C^FZQw35K|$ z`Eq>2_uhct4v=_$b6ub;2YFB?3hWgEyZb`({K*1)mB6lDWS&1&V6PF_b$avs=>mJ5 zz#bTDo+zA1ttE3+%36DESMT$j=$!_{g?V>QS~zy@u#|JEc9F=s3<_cp{JU z5RkqgvD~5#N}j|{N?oN^>h46>yr{HWxG42_qGuDmisoZd|7#>pb6oZd{!Nw@AhAAOo5=OH2Z{AbJ)z{E2XK2K=?PvVStjDv%NI+@t#)*`5fp3}hA9RgY!6=B_ODAWJ|x z-vbi`F-vyd;f%0Na~%DQ_KSr&lQHI;Q+ zEAR&y)=bu`KxQ|Wb$tt27O7;JY%NQ5OIfD30(%=-;&?q`C6CvWAaT5w*nq#S(!U=3 znlzK+(BIu&_EWtm%S;zpYI`Z;he6zE5}!-_27-My@zZEzzJ~RLyoeXronKPMC%Y;2 z+`&p+^|DfTCpxZsmm$wukoL{x_QCYRNF3rQa|L$ip~^h8L`NQ!sRDbAz^-#wmWRA3 z(*<@s_oIKEz~4PkSze7%si$sI>iSQWy7n`rUO;s1R$?c59nk~RmHt&kS7#{gfke+F zdKuAi+~l{A$4PIMEPX*Xv>SZy``ZA(F~g6mudYp5ScTrV=={$_y-T-T8AxkS6@`P6tf z^YOgrCnF%g5Xeh(fBYQDAM0NW^~L*T9^mKDQm!|?U-l&DWz8(x)dPpF-g{=w=0*6i zyoUP?Sl`|dNAtn*>Nw>YATAPQ#Hz4kzZQgKv~QbPpE1_qx%(G>Z2MnBUub)`c<&@pc^F5_({RcQX(PAi2$17fe3XH)L|wPMqPjl(Z}Ncph8t=r1=qWz8i^8n_f5BSmc^5EoS0RK54w^sV*PxYIA zV}o_LTkIFJI?{Zwex4k@a^S)Gb^kYV*PKtST;4z3=6>lP6>7?d^{a+BUj1UBe!Xqv zcEI{!{c#=g2ImPgwk`v>3e-2uF` z{fhy|c0@b2PcSE6YdbmL8xZewIlk4*qw{Tiu9yGom1=c^wh!`6;qZkJzS#JzAL34B zt~@hwU(4j^=0?hg?Tz_k9yI?MobrmHyl+4b?>KgR;U6=9T(vZEO7Fpko_oFw^PkJ% zbFi1&1Nq*5zkjE#E%&9?`K3PDxB4D_Jzc~8kNM*`!8ptx?Kpqt06*F>A3Z0ZEb#vj zQXaH0pVJux3%doJaa=g>~B|3fJ6_f0EqyN>Z5HLz#y=Aqqg z`O)%9zLn3F`b=3CfmCP7dKAi?vR(kX?G9Ow09gRi_G=jr1DOlb_8Z^>Sp+f=%Ex(B zytDChCEClueh2D_{ebq;Z{>LV_HsK=dmh9OlTdd?)kI9|e@7Avot6F{$m>(U8ox!uA+;`$Mmr)Y$Umw~S%39Kr5;tG)K!<1y2WLs9zk@>7iAIHBd#dp(2lZ5VAuR*J|6pF z01%>XOZ5Jri~7aRN$xKfkf^(X-jFwZzcu!YC)jDfBnt9(zG}XH@d7*67ay2Hoqms0 z-~YA#ouU39?LfML{PlmEuYZ}qj`hWN$5FTYU+eoK)EA^3NKt>gfgi1} zdzGL*#GZUZ>7RK|saMo1b)CgT>;jWiHBstCplhvUJaPIAli!4%ay@b1N^U0Gaet{h zrriH}AD8ti-2b}B@!=qm2d`t*a36~9-)I-zH?HE`r@(mLePhgjJmjl_`>4^7r=7E$ zH{Lf{7U+JZ+nYgiEhirf+cBgj2OE>t#|7eOeXzXOIprllTsX+V zdEqW{dwPNNAEjHn%%|D9`)8lD9sK)&P+tA8Jy2r(FdxLf2VS&e{pWJ>sRjR2Ag?5c z?{;??aI*aPmpb3*m9D&eQlS1Ahvi{DIbiqds+>2N&jL<93E)2+q`J?8D?9a_5B$5X z+l&pbu1XQ*!>j-Mobqa+oKqmzmd^ZLJ!oXJZPwj;e>uTv6fF<)U&Z0`?53PAZ_U2B z^M&$r>%2dAxD+)l`?=?;GhzHrfH>ZKN#>N7192%J&pU41@XDCw3!fZM+2;HANqkK4 zx%)CWUoZ~)59^o8DbJ<5Tt6$2gSK`GzjwE?^@E?hZk*BiKll3`MJjonEU+c(YzJA# z_wDBa-x`pZk1KqXHLQ#5ALb&<`0h$R>?f3E0=sJu^YMuSJMNSCK~>ZpAOY01pyRoz z3hJloA-AIjqz}jtqDO*`^}_RP5%9!J%!7I==o)x# zW~+}u?>-VBA`6XgVrarUVgp@>(N9b*BkRq+#sKaTnLWe+cuiu`ZwirF%Ef= z598uU9JYH3;55&Ow`5+7r{5Q+dt0`rgRB9GyaMnlL|5yWI4!cqCWr~>xb)6FyPjG#GReHf@uGoxWjzS@ms1* zK)n)h-Z-!We>x6y@5*^%9G*7@lq#>E9+fDspE7_i1tj)E#K%g$)HJ0Y0sVh{zr1hI zeu;p7sRdp-p3v?F>n^oxwmAbw5R6)dAv*jiT&k%S;>dxq71%b-mbrD z-X2_S-X7Sh;U`K>MMiW`>X-*goIj`+fxm6uG=vmV1-}RK=!pzh3HakXnlE47NnjtP zw3of6)RQMFbw#pF$z7tfN2MrrU7k|6_)V!7!MQAiGe2^PKP?~Q@%%;Sm->WUUM@%) zkGgG%GB3nYMhNT$0=v4@JU@<;Xebc%wnW!~j_Yont2|HCZnAU-83Hnr=&_(S06 z10Dm|>AI``AM;;G@*Vp>=Iby}&L8tdy*J>zd_BNU^R+$szqPl#3RzfSd%yZW=37ki zMZH{*Z#5_1OhLXHvai#9NCWHU;z4pdJ~t0e$?c(n&mqwG2#7D_#3O$=e81>9@WXXE z{y>=2@p7miLR=rSz)th8xT4HI z@h_#GOY|zDtFJ2kbwtPZ7(?od54NJ6p38argJGy#|1^-O$AZqSKiFygHMf-cN8MKH zxwT3?^{!IK{I#Thqd^z-XQaEbKB$KP&Z|!>*lB$V?lqnt-hjn?@rxEj`B{4?^F#fC zAU_9)qxoguZ#=(5(th|seo=mDP)-)+2@>0p*M51N{4)O^b?+VERJDbDX8?uw^J36eVB_=)GpJ1#AIZK-3JN z21U(aizxEm%UaLeZ!I}FzTfxP=N~@&_OsU7YwvS%a+1kpewF>e|g{8rM&Mti2Mkv{b1tEp``IDnP2Kg>{0g#*pC43@BC9}fA#a2$K-i? ztwElX>*Bs(E5~78|8Uu7V6@~MbM$%|M?ItG+a$;NZ=m=vYmT+V8og1@gX01%nE38s z`TUrPpWuDLFMfdWcm((2hVb~zoJz;1z-m2>xCd(=#RHhJt_*)JBEk7X*w@#Ol1cym zv2y*cagx#h!8|ee_da$q8<5m43ADS93`;Xit8T}u|3E=${ z_hmLaUTe9}&8*w>x`$o1GllCd6qF%h`>AFgK^_l5HhypqS! zhd%$-8mz~q`a?c6Hc|E;m?Rm`ClfxE&nIUw7x?iv+fDm9gB91M2-nM_?qsU(XDzVi zZlQ7Ct)wB=94q<_-p2ji&dNqXaW*XdRK4W*6v?rvlJnCgJMWYnx{-dq@&~W?fm&KW z`t)*qh&9HVW_3rXUYfPQYMnvjE>;gK>S~Rf_}05*-=1OAx23=AH^9enWj`9n^A_d{ zaNbz@?Uq4)x;?Ox&< zR^$Z~M-_YTm-D6+yQ0!ZU1(hSfd(1xn<+W=faH?m+=J2&KSW$&wa+4sv7(QR;-X^v z!?LbhaX@iYaZ2+Xs+W6$6xTiU6OPlkt&ub|m()Lxw8(0oPmDaR*=MAmT}m8(p47dJ z)cYF8y+vxzkVaW`U9fW%=kY-L1L8;t{{=k7hiA&pgd?QN<`$;Y+_8uVpd>6^Su97h?G-={n4=kUL$L~@u z2-feDJeg2c8f7%=N4diW`~HH|}d3JiY{aC_PUgE@0As=@7X-^pE##0*6cA z(Ot6t2+5WsB?p|6ai8>NPTnWEm<#;;x?}+DPZKNdlkoYn?3=VsJU_yZ@aNB3*U$A@ zxQ>nwu;2L{ny(ux>S4abQ1bgJAM4p~Ev?7O^RMRl>N!669`*a_&{@AcdeZc*2RW~K zZ$Q(+zkME0_oMqoKMh=Wjq1n4^Vjisi}KO$!3O=A5olOu5nSEyPDM5N9F}jWr0KNzR@j*?*Sg8js{8v-=zx_nb@WKTpP`&nNa?Nb2*F7JV|#eVOEd;s|r;3K@s} zOZaKrT1OgSwGJb8vgTMztg+$b*Nh8ciC!p44#zspUq} z5UVFhY#&3KWOa-qcC%)|H_^DCwZv+_nZ~oMxe3IUiKGtJ&?MsGWYYL8q-oZ~t;8AD z$Zf<4R@d#sUe+9|r=G^K?|;*&(swB?PLsZUy5!s)l5KY>zE`sEe#z0OZK9T>x)o#&vnXg>-!w!iwuags(feK7g?=xUS9NJfrJcIz!jVr&WFA-(`>wAN9Xg z`M7S{-lzHYymg8S#ee0^uyS;PX-LsxK`G{Lie67cOI1cCs>+5V#ug5^z zk0?J+ZC_S-N0(1-n)JkgxkEPAymp|``ucF5-cPKr2lqFT<8(h=4EkBd@sG0R9{ZxF zozF>D^y`^J%>CiM@}J7FZ*X6DL?hjl?n5 z)Li1we9{st=F{q3Kyi8;jQ1G=gK7UUj`O*i$MJY+_4)mRb%SIc-e(B&`0vWc`wUGy z9%n^;yw6an`bnCsBe;;(8GnW}vAF!YEy?n}&%{sgecK6qqJ#B)H(q5WP3qykJjUxz zvF2ERXYFti?Kij!GmZ=H%bh$vfK|VLTC-HHzmSp~T_)M~3UT2z(sY_M+eDgKL7I4- z6#Zo1kX(9Gvg2*Zo{Z%1O3Ai&C1>6vw!cprWA%L?<8sV)em%H__vKZ!fBuiS-X~m- zHM5R5yq+}2>inD-?{j&WBVTeHt1nON`HmF(Q}c`D;$M=j{Q2;Hm(Xz^#ESgFUOxPD zr~#=F4kqabyE|grlf!@#T zbSbUl5LV=P%ug!z43d8FQsU4Rq;P81E0A?4$kpjQ8gO)}L6vV||BpIqNpoTFzg> zyqdKmk5{r*u~xG-a~#$a;l98{#o@7XU4e0QeCzo99KdxSU|z@k9qTq$)X#A}-+0~+ zR^QFctf3Hbj5RWe7{|LE7sUO>Mt*(=AMhF7UlsWJJ$nf4_d-@YpX2^1%=d$Meu5t{ zx!=TmC#{$FbIW+1E|<}~xZml}>$XqseQo*XPp{jusLKbNp2NOiz5w^Tjq`Os@H=wd zQLMoP04{n#gT&*bS>oZRL!z5keRA?NA+ z!+d8O%-7*^I^LT(e@5nx2dmrV20qq*{mix}G~c4vkK=*$BM<9?zn0I3%eg*$^mBnh zKeIXh7S61Foz25q$?g!@w`Y<~`CUITt5B6_1kE0HJ?B7)e{jTM_S6TNcJ^%LHUY}UE z*ZcMz_x#=qb-$Po#|wFSzN-!98*nA7k)dz|I%%j-5LACF>$x`3-o-6Tj;uo z^VoNrf@bdQ#UHq|UZOu*Ewy+Cy^u zLdn*Fl4~>%mVR8Z<09$j6gw}Ge&ABc8O1T5^lOF?Cx((bE+lAL@@a^`W#r6(ji8zmB#uSl->x8!1zWZO!~j&~(nvyz=_B!@qgocdUD;Sxjy0Y2WpJ`UQk#d?tPT-ujr42FEuq zl*31XY1kG`O#ugd$;ugm*I6W{lZ%#UoA?Da7>am&pB5Ot z-y}cYBI{?jN=6;1{}<_(ev^zisJB$!N52kENUM1FALa9l%J=Yfxp(EHofT_G(RtKp za6Se2`h|XN+vR-4za%3L>fKS^_k2p%D}3(0X&>q<$bI2;34AE(zO?H)+Gj6okhOueQSlOH%mcMml#lLmJujddV(btJX#MVeua zRuZT7C#^Y%G;|1Q;80Sm3;P(sIIFD_^)qEO9jA$`c>Z)as7`@3QAM0#EwS3W(YTw{ zau{)tHOlHgoW{ef?(W2{BS@`BlIEPGp&q1;o}|fMq@|-tz12M4o78#|X{d%Y#+qR* zu%`Qv?>L1t&KfzDILDefjX2epG;um<%*|X&YCVHh-Irkh@dZ%fvpLQ~Y8gNpV)dOv z>^PS+#p*ea*m*vwhc(4&zktR=te6+~7X=;mr#ExR(yW@+#9LSp{&UB zUP|$JTxd-xzvPqg_clUj_~KB~*yW_oD@eUpk-Ge(Io6sw;xKE8H9m~S z?ZZh^tgaEn>8nYz*N_IUB`vV}MiNJ^V}CTM_Xg4ut35~@9YY!zOBx?X>K;$(x{1_w zGijF9J%QLCA}z4`ClXsHk$NYSI&UHMu*O-P{5ZPwtI0dJ6nr~#fuGN-#?bMtX2tPM z@cZl*{#*c_PqlCKeT;bD4d1s|r|QGU=PHbRujf3yznCv( zFkiEp@ABzybvg2Y@else`>h_&U%mw|d;T_Gi^+VC8q7Cv9PJzSdq?L}yMA`@#{5CW z&DZaC*yCIAxW#@2`250t>-E8J;(q3GedJ?*>UeyG^07Y)4En7YPyIG?-qZ6Aob}|$ zc_W^f_{UlC9kchrbsh7epK6Xb>t_(xM?TK4i+DX_l#hOs2K_GK_y>{q?%`*B{oLbM zO}MV@(l7cSlh*yB-YW+6DsH0nZ{qXw!r#U=2cJCYuHjXmT>Nyg7k*v4_547+Hx23y z2{&G_bjHflKUsc~KK`x8kMs0?V!!Y>Yveei{d`0D==Xhtek*R~ z^>f}en^wJa+F1{;8+hWn8&AIC*u_Tsxz3>8K(2@D&@B@>?9<^#%fs7yHg~GDwZBKN zAN_4IsMpB#+VT0)fBsFb*^y|cgZi!Az3(xhaYpriFsRqU^>F<;vhTOkpI<)hfu}#o zb!h(CQqc8qd@3f;KIz9Njt{PfwH&995Bw3z$NGOZ=(myMr?DRD+v~ecmz}=H{DXTP zz9qgfru#*`l0m%|u7l^3iGk9K zHbVL6cZWg0jT}FXwPj&bYNciJx>t{ywcEh`Q`hVBGtJNI`CIAv-g+A;))iMAxLx|5 zFmZylrk*&@8l1xMQ%R$&j%mb6R`+z`EUW(x;v%avLY(01|Hb^DV+M_9SmDpNj2~LJ z`o#7AyU6$6O&WyWLtJw&Y2ZHQD5<@HG{NehNt|bmJ-~4fl4e=s4-uzkk-8ryEwP4T z#ID(-N!Gv|;sR^@5n{X!9LBHzD)*rGBXGVr9+h!(CenGgWD+UjY>!b~oE3HZaeT9m zf1KjotiC7YJRK)f{VuGSr@(R9xQsuC<9evq35iA-H5^bo+mX=%eZwMSGAXnvppl@+T2R(8o0NN^DmNdJvpvc#RZ?0af3Ln zTE)4alW~(cZh+cP`(hb47yYTYqKaF^aYIyGCMoM}<+wT(7hfXdy52_nGE&8bmddz( z95+VAd7qbYqd0D&igUgo<7RSPy^6EEDC3rM+zb_$Q*j$Ou4PYoe3LIxJ>Sc+Zs*%+ z-5pqQ-g;9M=U7IH>oC3#!p-CU<+9#oT&GUet9gaug0GUg{zdBfx6Gf(d5tPR%W)-E z`)ia}!;0(2I?iiW`5BJ$y-s-r*7Pblf5$NGM;BJ?N9-Mnv%gCkd{5>L;`kvdFY-Rc z6+R%fW=ZXSbHx6&q?XUP&U(@)Yw2_1&#a5a$6`a z^aJM=N$oA9iLIozpIPyKE7xgI^)TNW9^b5d`!7@{_bX}oH&Vy%r1ov3p+87-f0D-k zV%2G^#5AeiGGw<(z=GH4y7J7f!)`ry6mNd|g)U_LFqCKf|cT$^` zG|HOjz~j9BZ>P}lY+=Rm40fcrIIC|Dnb&nH<@I1iUV-D>ds2LiwZK}#@4Mr98|wte zxG(qKl#lUZXUUc>lKqN{itSxxeD)B@?n5OzPaUyy>e;-$j?-wpYnjnkiSt5Ll<)3F z>N$+mdpK#JJ8AF;($JBlg`-GOFLI3Jyo)&An>2Ww^fM<&t~o`r|5VAAt0ZTJ6Z=QV z@#xi(L)St9-%#&# z>HB67mslhB65FFP&ia7lJah3OIUboMIqgyA)mTq&nSL@wgAP8^5!34<0{o8W- z%YMl7ek}X4e=51iZ2wY@NAkq~^m~aT%`zXayZzrx-nlODH0A=oF6|QG>mV!ow{Mj7 zVw)r5>>AN^j&yML4%DN0VYNOtn? z5skWw_H8!nYF5na+A8yW%vm)a`&GsvAL=hjKl`U-5BIZ>=g0L0{cTo#rMJs`%mcOW zkiOS)1+1Nl^Y=7$KI^~d(2uk5xd)^3dEwo(kIPuWE15C5K3~_eug_O|h3psk(2Vl^ zZOX@|O?-RX^7$bXKWpN<+Lf;#G4Tr~zI(Uw_2VXf$;9`yFJC`t;@fsFpC2&sGbX;v zD(lBONcQa~*>R?1oLA74iSIqDe1861=|?Y>oV-$U<~qsFpyWhYvOhwcx{K5oBaO_K zaaa%3H>bSsdPMmN$%Pjs2VWx2zbeO5D^J3v!rjmP;$v9xiCz! z?`p|~>m)nsB?q68ob7xSTHmP&hh$eb;#eO!UNcy7<{rtOM>=*e^-zCydUMkt;lZ-rQQu%qsfqwM4 z`E`7}J3K_|`SVk{ z{TCTVeuC9@jf_u?l7*vu0 znYhS`_gn5LOt$>@Kk(Dc1%BMmo=xjs$cp!0BIqBk7LB+IL2Ut!Q&G-4*P?CIvDh`jN>0=z4D>@ z$NDs#bX@0Q-*g{(?wNP%&&Akp@uS6^YP(gki#e*sMbdx3a~tJ_ZYOnyNyDtUdSc%c zj$BM$0#N5*3u>R%^)>w3v9#mIwZOnl!)SLm3uKWDo zUhOmdj=gj}tgi>>nXPXm$LaN5VbIS)j=zWXii@Y*c;zE|)XX|?w@JQ}xMKUB{zM6Zplqcm4c{B^}W_6p>-#zh*p*RoqdFb?$(k@M8>^PH3GEM)ET49(NRjQLO} zbD6B;94a}gxXA3eT*eicOIOHo%md9{S>8`vMLy2M;ud*b+4p;5Tvt}}`kGnw-*O+_bj;f3#?c7Q)h6W zkH<+R`;Dx~*Zvy@el?G8Qa;wx%V0fK&(e9)j`fZM+Wwr|diKk?#h*L(t?Lxh>q+^` zA4f+W`T1d_R`tAX87cDviV=_Jr5yYIQ8F)jo#cdK^xdkXWqj*6|HEhE<9ZO|cyL$6 zJ(-gx_3*y0^*P#qC##2bBnd_H9y#F{$(cf&*%BEA1=l2f7oA-B<)WhR`393F7vnJGlYG;Kep@3pPxzP zr*0@8@4d0SUoi0_L7DFzD>*zta?LHo*jKDSeJhXOCgb5lV`1rg>Lnu%8aMGHvt&N5 zg9W}0g7^GEKCkpx%Ey%z*WvKPvL5| zDZW(k5XH5Mt%uS8>UU7wQSly%_f))>;!cY9R_s*VLvc^VM=9>5_-Mt)C_YwkK=DY$ zqZD7Kc(mf{72lxvM#ak&H>l%(hvHQ#{$b_MP~50^o629P{QDK3rOuZ#)cJS;vwMkr zJOnpL#`!gp>v=XxKeb76^ef4h9guAihohuo4@ED^^aHFS8=W4eu~dgJY4a)Ps;TK)bSaw zc!FYjRL6}MBoo8tD0cUSCCT&1|1;=>dluDHA6BNQL0 z*sr)w@i4{16^~GSwc=|OU#mE%c!@gS7bzaE;$K$&bBb?K@hg@8zT#2p`S>x#gP)P- z&x=nDa8rJ3l%@D_!-5E6hEu@ImL?=ClxPIyj1b? zieFItqT-hnzpOZ=c$wnmieFLus^Whs{SfxKU2J3@#l)aQ2eFhyy9lX8x(I;yh-s_ioaI;jpBmh&5FNO{GH-0ioaL< zgW?|*7ZtZC-m3T~#Xl?lMe(nSe^Xpi{JY|9ivLiY-cz1GO^R12eqHe!ir-ZHmg2V+ zXB4kgyh`yqir-cIp5pfvf1o(4c(vj+ia%8Rk>ZaPf1>zP#W}@m6|YnLnd0?|KUe&P z;x85F6*nv1pm?L=O^Ux#{I%k56c-e4R{X8v?-XxQ{Jr8I6#uBWsJKP(R>j>m%g4)M ziVs)ZUGWi$k5ueb+(U6s#YZXbrTA#Y$0$Blu}g8a;@*mnQ+&MQ6BM7Q_$0+Oiu))& zS@9`~PgQ)H;=YPcSL{|?tGJ)y{>(Y`eoEo7Ve~?W|L^3VcLo2HKfipCxxhbHZphFp z@99-@1f+&-0|%tl-O%)2~Rz{D_A}(-h}eLFzkb z%uWk^f)Vd~o#K*jl6qH?2Hzo#eZZV0MV?mc>hiwtL+M98m7G#sQ0#1$@vaS$bw9qZ zrSIBG9QujW@hfTmPZ<~8PMrITG~8ymC|zhz9NR;VXZ9lwA3*9nh%|EuX{|s)I0RJ&9RnP zySz)|Jy^kgn6b3Xc)IiV@c2m9zx_P$blFcrG3r5WZW-@Vj5ui2#4jn|-Cx#69cbLd zx1J&My=O^A9ca?TcY9=hdVplqfjZ79??;qhI8VmsFOZD7Q1^x9{rDj1$1akLI?$4d zpS)D&Cx%Ey9jNuP@_tbHvCGTH7fpQc73K4jCcf>;^7+xLr0*Lp8S927O?=yk^7&!q z<9U9idY=DYJ;vXQy_`Y4 z0c&XesQ37t*K{sgE^z%ac;q#c9=msfQN8sB^=5ND?5FGZh6&4mdtyv&rynL=^X{R) z>HWlhE#y4CU+BNtV7?9?QvaJdKhl1~kn%eoxJ(I%!gm! zetrLWubuD>9=GTR^I<(k^KCJhufxZ*zAZdoa??u(?dOYqmK!kp{8f#^Q+hu1|D!>@ zAzTmV?}v@2M{KtjY~ZT;|os1N%9W^YrGLVA z?;zGge!hI$hqEIqFaN^1a^L6Dw-~L@YEW;6s<(0Sh|9gJZvMtH?~pM^y<5{>*TeaM zhBkMm_c*VpUY)1aR&Ia=SJoELa`)_aEx*zx3%%N9NT{G+xVx*r@rn?b#iTo2c$ zPunF9Jh@`Y4U4zE-hcSsXFp(c{3ddq(e(w7_hlT1_5E%A%16I;gMPcL<@IykRZW*U zuUbFjnqechpL|63j*UjwgF_AKja2ov?%fof(lp6^Q(@j2i>p7s$f({C2KAP4Jv<&J ze0AQ3KTn99zomVTM~+P_y549%S8|@w<6$j7-aD+L^&9PHFXdxDdl>XPlH<=~^^Kpo z>WqO$HGeU1$njIY9K6`*d^*~o-ZHL(^XZe={XeCqI-TtC*=+n}ET9N&x8^37E{0_`V9uifv3XSVOZ_yT==_4$cB^o#jUG?;H0 z&+{nj7q+J^Iq$@`e_!^(;=R_`27IsQL%ov?>UCJp=Q|(&(}q@GeBp^Tk;Y$}PW|c4 z{$J|z3HJwGP3|A?_`HnkV|~cS^=XpwalE?l_#EY9|4@IKfsgv@m5=@CYp@?(KIi@5 zysgjW1MiEbwJS%_QR+j^gEjC>wNTkkMhxPKZAZ(a{MCJH?{|^ zzqoeBg1YneeQx`WhaH1?prw(+cOKI07*f11i1Q{hiN5@|s$$7SIl?TJGj?)+DR-9v){+vRdw?aW89vwFHfl@41gO##&$vHLyRE6zkHOF!8MqP`;Bj z#p->K#$C%ugUq@<*!ocUKH?_6dzQ=(KhE<%L5lO{-L|*voDy7QF7WHniaed~m8@;K zK|BtPeqRXn_HIY@t$dxW;yQJ#cpaX*>DzIYZ6@Y^ee2hsJ5~O~pW6HT_ri?fJpH-^ z^X+Re-)hcV!rFW98|)vT8Xf z_`#=Se&}h*2|jO7*Zqw2LyGbHeWz@o{TskKi4}G5d$x1=dx+Yyf$^#Q`=olj@&kGw z2;&K!Keveb@;*mu^mCI~l6?PC8Hej36#2Mcfo7hkyqXtCu^z2a6Te{MyI(9{AIIet zo)}!I_$+3;Zy()A$0f;{Wo==t*hD_Kk{Rp6`}RSOuVP=nZyz`5-~EzYU-)HWe6P<^ zuG^F6+3+Rx)x_g9%y!l~R`i)lQ9WFreSDpEEvNAmYv>hX_p7AVf01Tbz5gb5yhiFw zlLnheLn}xzuhzWsOK;2g;Cqr??@JCV*7Xa@w|yk@Yt~Bke<3-tQF5{%+46(r{Lhl{ zIMIDMex*3iHqwT#>G;*XMUUT!%xyUl*Zb#plh0qDGUNHHiSt&gd^~^szx_RWqh^-alclMZ{|MhzoGTxbzHw^mX-$H>AU0nBah>R=cpRVd{QLdIYR)s-AFQu(vs^#= zsc0|ncW^uha{TeE-<&qJZ~s$zwT%Di>y3*G?@iU~!||x#}F5vve<9Qe#fBkrdkK;d=>mxtGkLNlbU!i>L59&7? z_^97*%dU^-fd=cX<@m!{k2}S3z}OMfHhy=@u!S$&;>+Q_3H@UK90v6oxDFoAi=WDV zcjp`HkMrO8ynog8S6r?459@E_yfp^bGpw(f_nPk7@YSo~PJw|JwQCw`bUq$uP_LQm;e5O= zIPtF9laBf6%L9&{_vKBVuZ;Gyh4b|JgyUCZFyFu*X#c8NFV0?f_XV47Uhu*f|L$iQ z{_!?_K4AZGe2|CZgZcUz%-6*8%x7JY|LW?47TmhlfBDs``!2k2ccc06ctD<>?+kikjrzv~gI%HVt-v=CWTVeXJb(=OC9)Hf${i2^*T(64q@d6+HUS#0E!S%;0AL|)p zu%0Cx{~+tU)2DppJa*`etKa(i{`m(jd{FPdo9{ORe7_lEF0i_P8@_W3Vys10Pl?A_ zi>#sFX}rjq`GYvH_lTW!g4>BRtXNOBgS>zJnYqCCbM-B>j}5GC`M}`(F!~-u)ZeqC zydP=gI?b$j|7HKn`kj=&X4+u)Gpl!BG`x6>;qm7@{d|P^Dh=ivxRoFOtS6^WdfgN5 z^M1#>PhDL9`(pkr%KzPu;e4r9d00REChliG$H7NGc7uMJIsOgSYrPY{eR$Zh$G4xc zWwrIS1ON7OSj!GNe%KeSJ`+D_;wSic_r>vL=3jrYz&~C2-I=WxI?r@pV7#7p{Y1yX z%Nk^DU~Obw!rH`&I(R*weci%!WC;74S&>-vJ!o zi}mm?YF?XC_w3`&M~3VX+u9DlZvMZYNAmvS`3lDu_jg4;PMOYhylVC(b?--tc%#2R z>E55?4j}b*Aq{pV#r|PkQFR_Xq0WQq675G7EB2+R>O~Hc^)rg|2TMP6gk*OQV#m>P zJghjt`-ktR)W_RdE%PIa?Y*U+RE+nl-{JLk_?_0@lNI}yK1J5ayCu78CFlD|&YUgT z?U5WhM>3APl^bxKCw=q<^`9^Ov|_xk?%qc0Lmsqvfy~D^G~<=Nd!XdPV9EZ=B}e#s z1$XCyVARj5`0y~9k2q*9e({D0B@=<_TwTE-X0OGaI&_oniG z(!_V%Ec4TfZ4;#*nJhVTtK|G`lB2gvE`}vz9Z+9=c|WWCXhg>2c;k8k{!jg#m&W8> zGTwWyOhmqPd-*Y-v7At6LTfU=1Io!!F>tVe>pecoiF3F3ncrVlI%}Nc0DUO`JCj;V#$`* zBxl~19C?p8!5VyD`q(#UPWkTDGCuMV*JH)?q0Zp?5d2u?W1d$1MEb7JBND6P^KoC>$nj0AxUYTk zw1+|)mW@bmAGr6{>n9&qgZ^+m%HbaTJ9+(BZ)IEBhmpJv z^y4ncJdDTHc+EB$SK#}&dam2RiuF5jeXXR|DR^D#<+w&x{W=iy7u9^;?Q;H%V&p+x zf5~`-?aJpEdDa?aJ53^BLa%(8sfi*J*S-qyMn}x%_mA`JB8^*KV>uv;7~#{nWF98<_R} zVZPq{!VbJ22ZGOK&b62QxObPFQmp5*TV=fVL&}dSj_)D!6P+Y`_Li*cCzbEA$@qlg z_&(B)93VMimz?b)IoVZm^gzk@dwjOz>G5*6mGl|b3LbAcj>el=*Rb~Fxbs*~Wu3!1 zl(h@%b*z(Fu|MG|*;lZ;0Amf~|H`_GpgxlnS!E7><#vg2aOg-aycE|Z+~OLp?# zgGB!Y#lGP(zN8rEZ}0>s;0~teaSWW^Kduj$`f2dKhbeR`d>Vrp$T-RN@sblaN%l^V9MwEg z`T>6b0{x|Lk$&Pf$@n~{+256`D|wmGkFbmmGUTGV-92H>ICY zj5uh`TQWYS*#5Tk{i`H9-;?Z798sK5j6R?>@5_1^ho+Qo&&qh558+ekxL5B-y19~c zEo&8zqpoX>tm9XVxQxL#e9WIejpnQ5K8AEAuIS6k`@$0oKT!mTu|&>C+G7h4k(T)#?SrsanpH^$6YsOoQKfdXL7#O82Tpq`5Zr! zbt!AN1E}st`;)F<9mKkkbvWx-)~T$WIlm3-Pdwh*Pmt#C&*K|;-q%@wVm*%i51El4 z&dc?bnk7d!N-io+ZIXWSE6D|Zzpu8I)<2LH&qH{BEPe5i<*5$972eTj=|;5U(|F z;sm_H!lsDp5H%|!Md>@ z301FjsH|VAk{mxwa_Df$@$Ql{M@aS`DcR|i9Oxk#{X#P)zO!ff{D_HPP`;;^tmivg za!RqC|9(9BjVUfE4jn7&IbD+DCrC~`OI&r|o-~tb zP10uGKRgbQUvsfsUtDqa66xnJm2A0Oa`Fnvjw>a*u96(_OSbaQuX=EUVEjD7GF-+7 zM@UBeP?e8g41?c`{lK*{KOc~c_--5@8zub!KR;LU-~IjD=Uv$6bc^*mnV(P`8!i2! zV$^|pub1%{hoXN658!_7`LpS~Xkl&RA=c+d(xkrahVt{rgVN8BksRgM+vr!Tdz_4q zD^BqDUn0+XlZ?+PPTVa0$OOs3kmR`Htm42eGCr%=a;x$cJ8zSIL~%lK&FwNiptz(s z6PEF@ddYz)l5u@&K9|mihHj*DnU}I^UcuvQSnFAFT%h);a=wgW%)jJ3nzxGU3}YV4 zs(A{J&tz>dm>>5K73Wj^YF6Aobo=4YRUKwdI_Qq`Zhm>@kEcb^Hy#&w{A}cTT3EYr z9mF9|&sVGFYkBoA_qGpSJlb7V_keBYlU2w=9p4CgebUJDRI(1_I+fUO<_&zj#xf6Q zMcu4=|J^!W9uIt83GrC(hg_$bbt^0SM11s4Sub&q%jL8flJ!oYuEAkoP4IU^d0+1w(lz$^FX8fNk4ahWW+%W8v;B3={l0mAB^L^X&{f| zzRAcRrSe@}%FmnVTHd!GRNnXSeP}_=i}zzXI%z#CE|%*`@b6`04A$jgzn1eqK33-2 z4=&%A{gCp0-o(egr+I#(eUG!hffdKaeQ5dllgckTWW29RGU`ID8|i%U_mKON?Do&{ zVk*yi_&>|bsyu)9f0k$MDf>(v@z3(yD$nNpXL%u&7wGZN@{%eq-SeO26;z(RSNXi) z(dGTjG39-StGpkoF7Ic1m-n5=m-oXbl=pKdmiJvX<^4#X@_zp0@_x;!<^AYs<^4k6 z^1j<$-jCIm_ly0?`<^q(`*{58=ZpB6<@4-kOFyRA;ZeR~+~+PonjX(9S-)k)^(mwB zFb>7_)o~2f(bres0NDrfpviN}`}T9CA0I&1OXLS%lAL{AaYk}Jr+A%Y)P>^t+@hYh zu!hQ$FSo@;qaB{*^r65+1MPan#AGIv7X2DCaHVye_Ow zJl?44xr)2)8;_geoQHi_!>so^s_GzrpG#>!v5s!c=(|;0WFN>M%<<@Zm_a_)pJsmy zYnR?Me=~D4_m6plYF><|4aVU+w#t4n4z>O){jg&DAJX^yDLJn=@R#%hJ0zDZ^nL>7 zFH}fQbda3yDA~J*+dTX{m?wtw&3aDdw`R5^~A-lHx>f>7&1PT)}$Wu6_KTeL(pc z#jTC-KYYi_dfK<1ApMZyf@155GCsxJauS_K`26R%p~TZz@%hjPn9)a6)wA;F3FdL! z^Q<^OoqYbd{Pg*X0-s;2Ij%{?TTYVwh7`vXqc5oMG?|||U9!(DIXzf%Vu<97V!WT+ z#Gj{J!rG{`;tJZ&ZmgYIk7Gr@3BR1LG+Z*yx7K*xKfE6WALm<$-|t3zPI1lEvVKsp z`x@yx>*)PU{C*UUE9zUXmGKyd;(E}L2Z8|^pBpLJJxVg_wCZT-dlk3F@jp_^FDQ0j zFYD=ioUip)((!Cy#Xclde(^?G&(5EZLfw$!l42i!o~t!paZGVeam`pcKk7hT3AR9JfhE9FE6S z&PSaUsvhDas*e5kUDri?I4pgvC(g&cmOuYDfIsKk#QRmPJ{MT5mvvAd_0n8#HJ?Yb zxn48ZTcXY{@09ZOqP+fU&fm=ST9~U?(MQst9`^SEj>mbhh8fol)Uiz6bzkuPCVtw) zcT6i^KWyUXO?>zC^7WI-&ntG^A@i|+hYhF45zdQ#%-9!bMCD@~T2y}UPB~vBBH24b zvimN{uDd1Y?vd=fSF-;;$>xzN<(!N`+CUvmFhoXPW!?IrMIR7K4eCzD;@qszz{jBn99+mM?#fitHulutHR-2Lq5C-;M}0lAy&>ZREs~2z zQabJ($m{7~@d;sd7Ht-_-`_d>_b)eQACCT|$q?q{_GU zmGu&eF)!46x{NO>MjX`Zmhl*eCQW=>ZTWosor5+bY5iMy{To;-`E!qz>{qc?7+F7tfG>OeEf4-S^`DgJyY;`QeVLKn+; z#6j_T4V+W)HJ8Zzm}2BXo&0*xdo~@vDpvTopFWxgN~&JsQaPVzsATku_hZ~wNWY{w zb*1z%|B*a@Uis(~8oNs72mO-cicufm2US$QmtVi4epaz_n5^#_E;*_=qZoCet`Rcd zcC}>ZHIhAw1BxSx6N)p63yQ7R%K4m%J&FU0BZ?D>Gl~m}tpPQ^Vvpj0;)vpe;*8>g zV(UmXzhaN#fZ~YagyM|ig5ty|Ie+W>N9WVywSl$b0^(}^d}1~8SpIxsH|BjgLeR{Ax2U$-;0 zn(HlL#q+UcoQ$`Pm+ZJnvTK6mU`R67Q^)f(u~uHc>-9J%%6#V}$+(}W=KNY#^j}c% zxW5QrE${cULx~-eW&OP7TcjVqRkG_g$=KhD!)Sf0RewblpSoS~l@s>Lky1%?1Gx7E7ziNK{m%f3{k31`0FF?^p$)vt7D*MYSMja@Q=MMf) z_cw<73tmY5xo;#zUr^KwJSgW6J}fz>7=y`)Hgoo zf$KxfQwH&aD1I)l7ySiQeDWEYkNxb(3Bg6u&%7ZywoH`C zZ1nSJ_(s3KX3xp>g%tC&tzum(<68~>2m0^G9A78n)9WQ?KbNfQ75Mrv_GWs#cVk6d zDlhZ#eTI3CYhcCC>yQU^eIfHP4)yTQYvby3+3=(PFh6gQpZikIpHu6>JW%%r8K2lF zIj0zT(3-DgJjS8%ucdD*NDgh5oKT!qjJid)iC3?k?G>IHlNURq=fNcZ`&;M_tTW6<_Qi^AjBx zwH8eLbfv6k>nvHZ&B(y5YTr%MjFB}Wxo&Xm6O9LbRj zBqtPS6eqnh-g&X)_%O-I5t7r_NREz@91lq@PLo{Ve%!ax<8TaXJ*(dD)Lk+^wM4S} zTgm<{l8cJ{-%B6&SFiK@_*_Yw+vIfueZ^Eh&cEPw{P^PMn@Y~FV#WOf;@zX=_1DjA z|3UVLd7<`H)#SX=J#mPTqzJC8}^*(&w z@#iwaVPd@R1;u*O+hsjx#b{VN)zMb6Wp~M?4wBQIBwP2DY};S5nCw3gQhrgfj`to= zzFu1SKK?#A+%M>Qc@?jHuU*a;RIKB3%J+7W`8qyn;yb#^{J3IWPoE$7{Eok#&WkWB z&I>5&;QQd_aU8~>)&pff7>9;UeAhuTKYNJeKzGHxBx4?E+QfGpT|Pf}tn`bDV=n1q zUTDe0*TBe5Jw9CoKJCd{i;|f=17j@m7!IpyH(B znoDJTX{cn(1I7EH*-`vBV>Nm|G;n$OdRY@6f6pa7o#xB4TJ9jOVy#wO%Z$FE_&nB9 z_UE$BWUXf%!`jSR$BO$%)T_Co{Q3gz#_tSm;{4usQs13fyRmL%zYTLg)>8$ zTv>j8&oudZ-|X)dV1G6^sLwU5D_EDXHnNVXqPPZT^ojk!{5yC6`%%lE16a!Io5?zt zbu8-?))lO4STT?PD!G22Uox(D-W%oh&d=yzJC71&$Gi3IuGKkxDSG&e%hqI z@heQuze*Fo%EYfW@oP=| zfhK;Pi9g1~uQ%}>4KOXwA;(8Z|$@tW4$+<@) z2OgCij!U-9mz-9Nd7+L4G9Kg5P(u1xPXk}iH}HD?cKy7Uu78!R@Y4%rz5Fwh9nVRQ zFP5BD99t@V$BU9Z{QOirmiocEpkWn{aVVb8dh!73ISf8;fcta!NnU@JwS~3fKHeYJ zDpt%3&71U>dRwm7$?J6o`Tbwzqb?NjUXBO*nLQaJ(iEmpe^CODWiZOp!^%GT` zWUg5y>!UAd)Wo;EBlCmrN=6-M*2H(cS3W;#;#=OA`QZ;Fm$H&=t0kjPXwbyR>sJ?_ ze*;;KUccs4y@dLCHm(ohgX#Qkb3Z8_|DH9n-{M-y{?8?29Z*-Z^h+Bg7dA@veI*%n zpm`G?k7s|B))8invo^7=R@}^td7$`x;v)N%ld10JNu-qxq!m1lJnz@LUPn@mk%lz>1l6AevNz!+pE?LJXl%G)?=_m8u=ScorJ>{nr>v-q6vYuCQ zSaDpju4g+>)+?Sb*?)m#ou5^{|3Vp$=a1l6`Tj8L$1Y_OF!j zfvY6zeEt5G{`r>eL3+N#`)W|s(fN%JP&|G<21OpU^?pTtUxA+AWio%-WPJ|*|F`vf zP3Di7)VK2Mg^s*o`hLzCs; zte7u4LdIhpiv7~RAK>5s_{T68P3mENM(g)pUA~{BiEqEAe16WvM}PSIBlr(qU-a7Y z^-CsxI#52}F|xcLHu2H#H0~GNP4N-Tc)u9OqoC@CM#+8>iapm!-#%J$K{0;*w3UBe zG)(Lx>3f2bONujNq#qe8*)vXZNpWJl^nEu;w%#l`r8qJ{`ks(v z+eFEcNs=v-C5LX2oL9_;xmEP@L+!rw{7}3=K2P9z0g3|dTjhKhhsI5O%WdWJ{U*M( zUgpQ9N)GV#F8vU#X9Fwx3rv^s7>AZjd_11;`%_^0X^X`I#`8<`4mqFgPRW=TitA}7 z9ti%!c%6^y7wX~p9o+i;n*4l-&v(Pe=exnX^8{e5AB^8G17rQ*JyialiuY2yw_@xs z>QySgv*LXe@2hw}#rrEhK(SqM7sXu_AE@{s#Rn@sMDd}Das9^n@qHg)d_M;m*K-hk3OwY5Kf-+05r)F;kg z{Jgw7XW5Sq?)+CpjN+mpdR>ZmCtnY$*{@}VA1ulFbBaZC{{hU8^D+0k%nxptTvV*< zdH<5}+Q;=|79UVB&VTU3%0He9B~9w%{k}NA51MAp<9$)yuLjm7tc|R?U)zrI>j|3p zSrb3N#}n_j;`I!UXWnw7XbJm+!F(I(V;t&fTi#E$EAQKPlYU4s=7EMg$ar^0$%uo- zP5j87GT*khVP{)4d{jiCT<8dJu1b0%5>s!I3p7#LRPueay*+p_* zvC;jIWe#0W9IUtxf?_|6^4*;0H_5kNNS_~{>Zkdpa(p%aJ_K}_!S81ve;nsO@PCnisL>w*SN{H%%ZI8svobqc9k@46kXzWnw zRr(GCzNWWaL5JN0#^FCced4K0m1a9_8Z$%Fpza@!q2(r+Z1px}dn; z+xR}d+avTif$uoFe16!($LAAqzmzwLcOO%JzJ!VII<|a1*6ZhWPEqTvsh0V1#n=~U zsJDzq{U)xvM%51;C*xy^JzeR33-#@XOU5`fd8G6sBk1of=+7A;-qS*pc_p5FA1t0F0>p9<1zw7(uCG0n;`CUWhda(a^Jp{(<74SH22#o%~ZXU?q zA?pWB?)PxL_D-dBgl5Qm%mdAu_^!Lk=SNNaqKWUlyL|nmiEq27e16cx&zktId&}34 zE8lycjK}eaPNU=DxL^8S#W*g|694_#C6Cd0Km2fc{-;dxalW|uy0(JrpuR0C`@uLg zXyT*3?Q!a>H!Je9Ci#g5IX~)+;W|@vy_qsTJ4bTz5y|KSYUAq#SS#jl=EwO8o*&l{ zyq|#2@8kN@%yI7Nbez4c$iqCi{%la!pBBzf-?8iKPt_B&ztya$n|@5LHyf91pC{R~ zKyq9$`h;4al<^+Lh=V4SA6Y2#3yQJdc|I>U@cK~C^0drv9p`@}lplSjd_3lJ$7w%@ zv7&C#BtNrA)wG%Zh$l{SPQVsm@3ExL<%GAN}C>JL1pE{Y2kT?2m=l+fD7S z<+*>B@8@+)!Mb?@|3A!+bKVM-pEk*lEtdUZJr#3l|2nhk^;YxvAXe-j&WCPQl%dZD z@BMT<{ZV;bQ6KxiNu3X4c%JM`nHNmT{!s^t^&~le4J-WYKg=(3UgvpyUUC7~lJfIg zmr5V~4CFe)R6Qr3-;F$9J^R>S(%e2VhZFPC30^5dMhf))KbQswi*CcbZ( z%*T8cPtkfivtmBIpO!}258GV1FNnu}exvrY8g&=QJnUy3`(s%3em3yx@svRIe%`aTfA)77{45myWV}M_ z(}(SPbN(E!Z$!M7vfsz-bR4gB&~I~(9S<&FU+`H%U)g5Yhs(jp=_`@$EFkOKHj{q- zQrkcKTM9pK34bzPDUX}_W;|inoAc**J%Zx_o`2WDZ{TS=9mlKhy(UhnK<+2{wfH~Zsw^##A+SySKkHoM+z&+%F> z;+2Z@Z7@W3x6Q?X7 z`{Uz<1-LL&t^vhqe{j)z0`~-zRju-d0lvhlBD_^zi&G~b@c0h$WUYEgd%Nuq& zj@MG?R{&+a)`8!>)zq8y3zpmU;c_r?{Zf#w7|43(g)c*t~c9ryvB=o^<}@S?Q|Tk z3g)>diK}%VH2mpK=vo&mGZf%Z{-(u zz1g1Qb%Kc3@$lRJrJauBH3$03fHGc-!M`Q+9il#54o0qDC(`Zyh}|DDR@m|2bd0^< zvi0omc=(wp{Kl$#}K@VCw61+Vy7t9Iul_ycWZ6>(6#N zj@N4F*8w>mT)tk9q5lI}@2s@z!{uP)^lqdJ0$E?Vne=Jz+Wy(!V)%JZ_>=MC^=rp3 zcD*@&j@Kz7UaR4^{dYSZ$E(*86OXPk7I+50`_H(>EjCLLln{n@OLy z%J$FxR>RLv!k>(n^Ovb_%HMXqIe(5d+bay&R*nb02(WIdN}D)`HV z-u1p+A1((Yr*B2Nw}7l~-c0%lAK3ocU#}-jefj~}pNv<_wx+&q+u8MIdyZG7h*u{3 zw)U{oalEENKL;q|bqo0Cgg)g%yFOeFMy_86(sg^%)RXlsn@j(Z?VtT+!cVdA$MKp9 zzN4q9Z^!O-y*Yo5mq)~F4yWJSPRH?D4E<7|jMr-L-JUY_WqroSc73=Uj9fn#(q#cz zzhE=zXMAG&XMc0x=W^kXk0<~7$K=5A?!V5j5wt%iOb zkmJMU?e(;Y+h8E;-Jja^<8m-^dNLvq^z%Qn z{joUZQwYL9+uWh;gM_W$&&6ZPsx8+4WrgG6VrtN6UuAObUy^k$hiAiuDuxWk! zX7rT@+UYA@w%pR!mM8SH>hD;L}Hj92(hR+D1MtF}Dhbz5E~!?n&CCzdUoZG=dENNC?VSVmzw(lvBNjcdYQNitWgQ^>^}zir%r6qC%kP?D*QW#a z9FKLV&*iU}`bhs7!e4uo@~;-^8d3k@@2K&)1$cM|z@#c7~!+!7!_UH8{t=y;I`~Auq zKfdz)^Ty{!ZT}YJ$Mx?-dAWX>@W*lE{Mo)k#4BO8sUNS82cukae`o)!A1dm%wwFB~ za()3>UXg!_h{gU;~$dBa=wErU5d!odL z?Gr?Q=|uf|Abn{3f}ci|^RR=*wcN4SxOYAuaQa=z z-%`c?opJY#<96Nk($mhVS^L^A-~GPP{K55U7wy+3;?pkLXX$48p96a?AID>zDBm96 zKKx+oRd?N=GPPgn=N;jXg>yU>q5e~mPWD$We}^a^k0XriFAx5h=XPQJS`mNFpXY;a zE27K?rq+3Zr$ke9&f-mbPjZ8uw9E99C4Tb~qVyldn9QT|pTw+p!y z@m_@ZE=F9VtuNYO&+(p$cILQqyyuDd^bq|cRir!Oo!)Jux3BxM&*z6uYyLZVA;+El z$@Ggc-yZ_39&~2o<4=9LIQ_=Qcmxxz0WUfEgoBKJJ zm-B0Z{URA()SvCSJP(4G<(Y@{xE;$`aFFQ_tp^&+=xZ>gpFy_cI7mEmo*5UKFEPmS za>&l5hED;`0J2@Hkk_((i|sD}c?qxsm~xr1s{yj#MUXcD^DZ}b^MLKZ-d7+!uodWB zX?Qnq9;$IWVCA?6E~IbW7>JD|fd@Bb|0cHWS_J1WHb|G(d-#qU?)^6Vzc zmmuU`Lf&1-dkA??A@3#R|I^>EJWINpZ|J-^?E_456i{e?Y$ zkAdw62>n1I4-#^+kdF{@ijY%ggjKp!-PCs$RmWDCgdZ9oG#>}gnYD+M+*5E zAs;K`3?XLCwd9;x8gq$zr2p$Mc<3V{8cOTbwc(Fncwol=>tN~Cqh}zS3y|jv+^vP)oZvsW_AtB(}e%& zLY^VynL;*4$zgw|3H@v#pDtvxItizj*E^eq{Tv~mCFHY(JXgr)2>DzgpC{ybLOx%} z7YO-6Azviqi-mlNkS`T-i;yo9^5sIlLdaJN`6?k_E#zy2JYUGy3i&!AUoYevgnXlr zZxZs&LS7)`TZFt&$hQjlHX+|G605qf|5HX=UV zguJbgw-a)AA#X3_9faIN$U6$Tr;v9N^3FouMaa7fc{d>^K;9g@zw!)ivKIIw@DE`3 zca1&)xIgeP;1J*l;IY8bz#`yyUak88Y`r8fv z4RsE2hUxzfweV1f<)N^2Li+Abvva2If6nYCgZO(f_*TK+0lrP}OTo{$!uInn_#S82 z{5Rk$XU?(m{S*9x{-;@dw{1|)Gi>`kz;8I+<_CdaEBIXSoq{h1-y!&^;8zL$Lh$W^ zUkHA=;2#0sCirFGmk53p_*TKM1;0q}zk^>O`0m|I+~x~D0ep+#`+}b*_<`V?1)m0f zhT!wT2LxXUzDDp(;41}x0r&}mzZtw+@DGE}6a35IGX(z$_%y+<2cIJNp4*yuCJDYT zc$eVQ!1ors8+?M`Yryvq{2cI(;I9Y2VYc1>?+4#0_!q&i75qEkI|SbeewE;RZD-=p zE_fIC<$^yNe4F6MfnOr{0QgqHUjTlQ;BN=NK=99kpD+0L!M6y0J@|Qo@7dkdw^{J} zgP$Sz0pJ6I9|^uj@W+F%6#OLc69hjUyj$=WfX@^B&EPWx{~-7@!M_APMey%}PZInZ z@Gims1irW6{{f#M_?@>maqc1b{lGhdPXfQ;G`s%~2j4099Pn!eUktuO@DstW68v=V z?SelK{BptH0Dg(!9|7Mg_!Zz63I0p)3k3fg`1ykGv4e?ci{M@0=LtR)e6!%Qz|Ro8 z8+<_Ur+}{!d@cA&!OsFeLGbgyy9IwW_&mYi20laZ4}wni-_!M_1MN$?+mcM1M$ z@Vy29EBFM#Z`%X?T<{6t9l;+2e#0!gpC^Ow6#Pi=YXx5bzC-XQf?p;08u0Ccp9X%p z;OByG6a3}imk53V_*TK+4}Ov0p8~%?@XNu^7yLWmTLixr{5-+`3qC{eJMC!Nt3#|; z_W|E5_yOPp3Dd20?2&9Q_%YyH1YZHZGs*T-2j1y#^Jjoh5d6j9FF$9RRi10WH$QK$ z&u?e{FWLOV;Cl=HdGKk1e+&Es!LJ5CL-3v8=L`N{@N1XZ<=LgDX_urIZN3lqfZz{j zd*SCu@bd+K9QZ||JSTu}6MPN$Re}$K?-cxO@I98>91lzYZTm5zv_>2?m z{yY|Zi{K}MUm*Bd;N6112zB&)WQS@SW${ z{558nXa<1m~56#N9icY^N_eD_^UJOhcgpZ&qN z2!1H|R>2p6cf@$^1D_`Nx!{)z{$}ubqMQ$cZ~l6g)qmQ+ccj|=9!IL~tk_~qBwep0{(gnb7130K!dXjB_2lL0+_HFFvD4So)_JZ%dn~7Vy;Pb$D3O)cn;b`0c0`Mt< zZwK!dypw?bEcg`gErNH0PnmCzKjq*P1Rnt3D*Vg`-!Awi;5!BX9{7~Q?fQNJz9V4s zo#0!i+q~1u)VD?O3E~7*;DR>w7))G5z zgTc4CZ9W5hK=>&F-+q8y-&4R>;(lTt6zjn|V&0zxzHPjn@44Vxud@5Yb>P=tZ}azq z?=9x3r@^NP{&nz+=GcDLf?su^&Hn*@hM2E++QY;-p_e^R?E}8~WV>DmF<)u(N#NT= ze1?H{L_g00pC-obao__YZeH*$qQ29>FA)4Z@UAI#9IgT1R%`Qjg0HNz`Degq_-+1e z@EwBxk^R@(_RgLr&TRpk@6G&Fn;*b@(B_WNQ|8~B77Hoppdr{KQ_-#*i}@3xnTPmftPe<1jP;0J@R5&h>_@Rc>TpJMO{ zqCZrF?-ct>5d0#M?^)m%h;?QQ__f#B`7Q*Xa+=LQ$@aqktKd6C`PYIE_-sEt_BL^w zaH`F_z&8v2Sn%@%Uk<)S@Uy@#5a$`r2A|-z$Ipwwy99p&`1VJec}UfG2l(ZJZ)HE1 z+Vy&d{fOg*SHK6vd5KlvJ1?;PdGLtxmB$9dV_Bl>%C;~DPo*V zXZ!Q)@{9uS^tSVLvwa_%_kwTU&*uH?XMdZY3EnOI%mbex>~93$A^7{jw~2h0fKS=i z&i4i8MZMa=cMAR!@EwBx7JP=_e+BOre7D}Fy($I28~A|W`+#p2e1Gr>qFzJ6y9A#F z-VuBW^Mmd9RDo|1`PPG9Ao$tfTLpgs_%^}M2j4FEJHS_p_0I#~oA zrwIOY@EKY5I?&nA#6Lmwa~F7*;4{Fd2)+`0hT!LbZ*R8Ce+77Fs?FaFzD*oY-Ov1Z z+x{8wDW}-{O7QcR*z?y{;F|@%f%(I1KRfSl;7>3VuC!7oOwfMa@nJnDV;?-;eo)b~#hPXS{3k z$AGU{W%C8#7kpszCxTz~kTi{(k+WcqWGk&u9pTO7rV)NS`XyTvryUp(jzVk1eKMZ`$Hg^9%5`6RP zw*6@E?Yr3aW#E_ZYV%cWznjfZ1-~l6=FepNUN(Oz``_K>ZwBAChs{3#e#xFT|1{h0 zW%IAH|GjPg1Mr>u*!3f1BSA{JaBfegOEigKT~z_@urz z?`HeQ?Dm=nJ|Or;@U4PB7ksDS=d=GMw*R}qHw*qL@a=+sgLyIUyaztzZrlGi;1>w~ zZ}18C*!Br76X#~Z9}K=z@Wa7Z-fR2G2j4FEa_|}V+4l9|TLpg>c-Q^5{Z-&w1b-KJ z=KSyA!MDTsV_kPs2 z9|3-b;KzbrCHN}vohxiV)4;dAZSxm_Zx_eo*MZNt$hN-=eDmctzXbg9IX3?)__WJx z{v+@Sm)QId;PbAqdFNmgx8+aTd>`-uaem-1@V#qo`=i0Hy4vQ)fOlVG^Cz)?aeiY8 z_-0Yx>EL_6Yx}tbeCLfee<%12f^P%w++^Fo559-se*&K%_?-?haqBJkL%_QPKN5V) zJLW!nUXP6h-}-3Pw?Hk+RYzD@AW%-?R?pAX&<*T3eo{Yu;Z zR`4C-{MfzB&#>?BS_b|*!G8jNt>D*#&k*bXf53m#YR7GtLruG^5_~`K3F10MD)=

      vJJ5#5yawmn#wX_N>--~bLW=QfpA1IkP-eBS4yF2h34^RivsB;R{T3eQ{!YWM zu?I-q(X+&ErmceAWIvZ-H)1nYz6BT+W_ak2K!~g9IL!NzQ9$-kYVu*;<<_n^15o0F z>^PAvT#9s@-7V*%%S#dVR(nD7y$7T`;JzR0EjFmXspMHXFmcug zC(W4`KE;f?elxweMGqSuaP}^>oYi_fqL(NH(ghY7zb#ay8Z>mcnNew=gLn^roK~A zkf9RCv6g?cu0rh^W%3v_ai<72&2-@u)Vl#PGy#^)%Yh$dk@8*_FDenM0wa%ddlDM> z8M9Zl<{xX+!_jh5Z1^5DN>_>3;x*-Ss$i>S}+j2!Www*vx zq?_B8yda_6`Zp2DW<0$62XCC&viZSq#Hq1-_Co$JZ%Wtk#X+W{j*t7vq8bRF<&~BP z_i6$2E%e%B`+uq1@qao8ezGupx4{2&3Gn-J;d}7bAVh2_MSTYS2MPRVZxi~P9?SIK z+2ciSebwWa*yBZReU%Td5~>-BoBFB)hfMuJaySzYZ^Wzg{nV@Wj!}GJ)a$o zo`}%nYL@dU64tkVW9Vtk!jnzUF`AyL11F0J>0?MQ|L0}Se>DDI{hBfUOT7s9;wJ+q zD*fxyBkQi%Bv-guYeFQik4H8*>DFi@#d+O|Hk3 zYj}nZV~1)FD27fNz~ZOvJ*s2TH@rTxpJn%->ACS=bGkoIr?om`za%&S2?=ZRGipUk zgn~cDPW2maa6FER*bIGo7;$l(hZp1`^_q;=63x|+OYb6_GcW_^49q%6a@9E49&Vkr zc?s)}=cq!s-1jWe+1qtO$F;qWMb}QkH-6sOsv{0l^U@HB0PX~Es~}?@HUa0`f0aJh zKqf5De2eSH2Cm^7W0qYvmvOE^yh0GDeWD2r-3YwwedKz1c@voAl#mYE5f9M@j2+nP z+(_eFU%xIRZsIee$~Q7?4EcU@Zc+06-NMr48~ALA@?E&HH2HRbIf%7f68YOlzV2N4 z8hz*3(f!(veA6@dWQgmu;1kZWr@ag#ts8Ho3jMY(b=Z-apDz9#W1mP;_*45JutLIJ zQ4C;PWe={}2a!mZ1`I&lcKizab`66rhWBeYU4F+}-la4R8ssu~#h<|pRbtTZT9$Pm zpgjEmGn4a+$HtzH*P4+{!*g&?Q4J6*!?@- zxI)!v|LIeDjte!qKr;e94QUPf$Gr;F0jYuq^DgtmMLaN`Kk510NJ zf8Td^--$<^QQU9Xsp5$*vQwG2G*wAjT9*jC=ImqSHQ#t{FI!+}#RaxGLKAshFu0v;H^OkHz`|J6}ULUGfv$%Hb5(Uh0u)ypfMaeU$U4U%L|XL zK`<%i1o7i+5O*jLOTMxB5z%wxVP#)VeT!Ym5pjGk7D(K|y=*oBBOITg@nBM(f#>9G zJU<09LhA347`Gbnc=%~eFC-LxApO~~2tbQ$oQc%Xw-B8uJM`wEkF?SyI<@q$LrYl5 z5l1Lmg7Q)>V52k7(G>OWUU>z16W#ZdYDR3y&39zcl^|Vjqf;undgOfQbX?BOsn%bW z=%<MG!-y?*lilz*4v z{8Wc{TEqn#aeQW`|M+0%ED+g#s^XX1#ZP@V8_!nzsTAzj`U?VdWe**{$fa+4`-7tV zRHzPgeZi(H{`3DnU0dy^?*E4Er+k`D6X!Vn8uu^Ran7&!1#!-*S>it?hF!BU4C=^A zmda2oo(^>Uc-%Tdd{iesx}py%c^H34zs>OuV~MGkT)d8>$8ZQvQAQa=JyA}q)%w1R z9zg!?T7T7q2>#yeN@Y7)u4~_?Z?%8dvcp{rG~HUcu&Fx#L>%0Brf|thQua- zVvcZ6q|$QkbDZ8-TV8=@WJwLL7qKdR4!pZ-aQv4`qB^nEPjN0fB!X4BR8 zvs}4tZ@RX6{P@@9_V{7^Dp#0!>G5LWp&TpBxdHf`7-*#5m`B&hv)SACl7fY#YL)i8 zYJd3ng$Ls3%?S%9g|AZ+7AdUxM*1`E?tr@&X8bY^znqo+C0vvKY}W-DdQIH!oK7D| zXDl%AS9oR7Z~-7D`0I*vZ&XLEV?-)D0q=Gmm>*6%?m#}9Ma zejj-ud7%uaxtQaQAE!F5Giw9b6Wlk>*07re_MaWFI{@2U8E`2C4fo!%yl~6hH~vH( zdT-p4Mp7OT=+8Q!?+fU8@HzzP2DdDoewA-<5}6r1XTy z76JNz186&dioO6rE~gx(KBj@*l?SL1G!qq$b*6#4RX;a&WZ*IncrE_7-I&IN2|tnnnpzWMI5GH7deNU z@f-SuUGMfV`o#qHi&O`U*aTXga~OGHZ>AMJ75lae!Iko5=CH8)N2VZ5Vc>mkD@R9;YD6l20GVl*MFq_|ejth7u%>pjCVauDrUklg{gb+yc8M8id`a_ibtkOuZD z?^a>mhDc7+=qHU2Ai57V-=*w|U56L-oE>jJPGW|m640ysyd&QBGjhv~w;SOZnbNW2 z?f!Ez;_W+Il>ebk@v{4ejyp$-w}%00ta!Tz&lHHar&gmYcfaVq@pE9Btfl-CV3W0U ziKfST;NnbqUDpbE`F>KYyb{bzGYghEKWSn{H&S)YAksT z;+X>SDm%%RgE)wrzYeP!fZfwQ(VcXNJ4x0Iv1lO7KW5~zrtGf!f%nG+;uOqps^B4* zaP3;_;T(V#ppLg@8I9WD)Qv)Rj)1O#J9FXa^D~Sea?ORwZnN1B zAD~gxPhYh6(gwPv{?vIKMRAlV%V8tpgj=|<0k_((yb7L*$%)2ZKU**jlvtQl_x zeCeaTv)lr(S^)B>Z{p5IDb;Pd4mX^9u88Y)Egs!LF$)jli7A~5vZ^S zxHEF~hxb*W-t%bnDw)8Mvh@M4 zv7f?q<<2*_UyrTT1e2~0+B!I=*l=i9yo&2j*Q1P0;b*)5ANtcAQ2cT9r#~U!&4;(7 z{&bD%Pk{@zbARfYPk_1oDJs8XRq|u%Ps5tgkE}m^2I|-z{pp`@DGCl}&(yKG9Q6*v zGGBfby$0?jK5((*Ht{ja6Q}FtZ7ZfiUf!h;wf+OJ@Jp-AuF5KjE;|W(COaQ46My2d z7JFa*AZ|#E-rL}1!Mjw@bFw|{iKV9proFjD7S{Wknw4D*(0vWkqehJT?4$csPS*J8 zM}Z=$rs1T6kN1VXWJAD90l1DGpwy zJ7`Dc;Mdf#xK~_*n+#di918nLr_Zf$-*hZ~C6&oWF>4&=jF_$bLQ>54X(h}--$;P4 z6qH-jd5yQNJRy{uD)(^>k2j3;^OZK_Q+)v@x_@xp4*!a1Q!9>ywqz?dp z)xT6EXW|-z%fzci;UCDw-&q*{-hzKECX&VS=lOCDf1$$g)qabMM~5%s%5#35f0df2 zXxzB&z-teXRJh%ry>LX8o z7V;l@`{4D*xPIQUXWh{GR~~b@Yo8CRq3_)D_Rjl;9p(B!6`!eSp$ya8&@i~A>}_9< zqu?z!4+_2e%zWbGJpZ}%yM^tA=Njqxo_pCdir3Vt%bfP&?&d&+_0+XmLB{Vm?Y>6F zX1-3FzlEyW(f{bE#H}hTAdK z`_GtfOj)-~lXEIfALTquhcW`f5ih0p%Xuzmq9wz>`!tc4p$D#Ro(19vRd7fK1sG)_ZD(Izhj+tY>F4L(xk< z$Z_PrgM5Vkt7u4eN(0f;z*jQqKRlxb)S7g@%KIrPr^jC>eHkzPN_qfLorlP?pb?@` zgFo}?ec$=UBf@sVlRlJe1|0PoYT?y42fW@2J?YsPc?~yf>j{MnePi3hX~z__hmf&{ z?{{b0LqYov{s%`n)(l;E0k(_%;9a{<6yj5lyZSv4Uvv5#^*+La{b8PpH)dl*K_@7l z-?NV{$S-9I^}zm@XY)G>{c3#r8F~n9sq^cXxu(92DrP(9`pzJvuu(ez<2S`sN^X5E zva4%)W=%w6PZb&mg0Bq8Nprysb!+~qb}rs}OPQ{}Sf@Lp4acnil(k(62&tAUXudN{ z{j~TdW>(F5WjCD|F1x+#6G!aGWtugcaM(1aRb|)#yr$<2l9Y@?CwO~l21&uWX4peK z`|UCyL~y$%J|53kGzkkE7iI>~VoKTCe>g z!>5m8Z|U))u{Ec^c(6^ANO<~ zBL|}gBafo^^L-8uEzFFBhlqq54frI#}iSr@ppUE2(zvg)~k&E&d zy_osia{NF?m{=qnrL5bJu$RlKanCwqPJuYxoZq!r_H#uCAreO!Bf#;S%J)d6{7UD^ zjnA0SmK!)ob+}J!Qq|2>Yx;#~{GmT0&mh&+3fSQRJZ{~$qjVnhpNg#KIgV>SMZc%n z0>*oJWTpD5%Cvsx(4#u{A9uC^MHDEgWR3@z|1q%_8VF|Ekxduk+nS**sztf=<>4|$ z|LF_l$mNJH3fSGNho)N()S;NDa`5rFKq^iD|LkHjM zs4YtRfuh1Oes^6xaY-*%+->a|R8u>2pjv?Pfhn8{K?R( zhur*&x}o7D=lBw zf%nxPyRpw#H}v`?Qyx0+oRw?x%J+o}a^$-T&0+qY_U$}#B^13W{ z_a^m?$Kq5ZmXH1W-Rlv75LEyBOd)6V>wlEF2+PgZ@o_OMSd@$0lpVMN^z!MQXS^2aXfNxTR zTtCzEx#m3hBrbwV%P9vlpA9}API9=&&IjIul`D+zK5aOj!th)^me+1LQOAhc?f=OsJf$cK5Qzm&hA`wO9% zBIqsFk5ISi>@hv2$B?S@m5(mkgUKVxdQ|)x`X4)AIURD0YH&`uupQ(E({yne%&PwT z`y>2~m+4QqnTilxb{=)!?J^G@yjICuwNmfj6#E@Dp7`cIWBB9Pwb~zFcaa@WoKt(! z#@Z9`NnYQ=WrMbNiv#1^WLW)Zy&^u08Vff4v^yIzj84g7Cy1N>(u7om47xEVw>n6?D zJAJdfKilV5{w>*|=r;Cm;=6D&20%#|sH{#b>pAvA@o)Nlw7GeLo%blHr?bEmU?;5w z^=g@GGa$M{y{@DtMf__OFV{A8>lUMng{2RHcS(e0?e>^e5hr_`(R zoaw}X#xKW0NzIz%%us(5iY`|2G(6b&5zn}KGR7Y)OL%nQyoAh5yHz1%>eH-9KBrT| z%Z}5LTSESGDYnkEmm>ye?U2`UUuox+C_CEG?)-qu#A#m8pI*3l9>^P>ECImbUFy03P-+U~+{2}7!*For9g)^cv88PJl1e*NE6dSQQ~KF#H@FUe0* zzsXQg@u0U{>3pcluW2}xEib2j<7noHFY;`R5dB7+`W+Raa;s*>fIQ1vxZv~znwP}M$oJXe&bGllZ&zQ&% z`$G;d-p$8jK7iRg;jYu2zGb1(2Y;haGZ+1Up4UVv$1c8iIqa&rDt7{h?J8VBH5)&f zd{_{w&~ObN`US#=J8?x2qpJc( z#_EERK=40-;2*Ks0$^kP09!ltF}#PdE{Fwjyc!xex9~-o!8dA#JRlv;A&LUuI7XQS z>d;KdLDagYGuxm*s$65o*T?T%a9sDB_~=^~XU9h#%{Sj`Qo#SJebu+(0s7#;O|aRF z{9F5M430b=81mq5TNzh^YgV%>=&|K9$cb`n!JzhsaPmy`sO3Lll516~l6#GC>G0dg zn3;E%-=`s}1HZ5)`Pcb2xa&9HANE0{)I5C-c`$vDV?Fueg??k_0Z$Zo82JDYDYE*D zBbv;AeMpMcrqNW-fqWmT-pH7?Z+2`V%c@gw^!HKrf4zN=smt&Gy5gHLjfqJ}r^DXW z_v+p-Mw2`R~>c-SHJN0pb(FfkS#K9GDgshA< zJ6Ib_9UWIFd2)3zJ5JR8L;2xHU>&gIMEqusH7M-*5WNvSP@f|Di*qJQ9@eMfod$Tk z=r>3|{l=9E>c{x28?3@2g6#WB9LyOX#~|5T5A#ZRnikL`iGioQXDUIzWP}Od^p!K!&#Ge3W8Kp=4u_!H1iLhR`ipEk6?-u8f}H;(#Td{9)+3}x zEcnr`wvKR8V*3>i#BX4?t~f8uWj6q+qfgS_hrdIk#eQ}knXBeTmK&RIwI6fZCFLzE z7OXA9;zS^bw_NZjM~5F;+$YYUDb9dn3GGw8M3oCY;gHR)>~Ew$Hmm-Khd5tzFS~|F zpc6+t6z}*h4zE0aCbk1#$?HVE9=jqbhYMih!Z#2 z?$(Q^tff;a`I#6EG(uzNPCxJzc}RF66b5kEj*{M4Ptnj^GnJg|2WF*YW!=XDjp|R? zctpQ|k*nByGbNXy*uJ!4b%3wQca0sNe7me*e9~#+lYgF<9iO-^Q~Jplm-08*lf;F~ z=1@Nne#ffpIfT3W6+Ecd2Zvh}y!8&bqb2PfaUSe_`mBlV`$?cTeU`g@cZPbH$5%n# zKI_zF<3zmt+;ucH=xWvQjO{qaiR9q_h&f}fC})+0^W?SLS7^GtdEm&nh4H2wEHR(m zxZ;D6)TN4k(#(tah4r2g{se|%6Xw5s z)$&K4s~b9}B_2HM#IM{6MswGD&O0?{y{F=K+C+i%p2v^;B(L{WFHrh+%2$sQ5@+V- z_m29|mTh*P{TpAF=r3tqUv2Vx@h>a*glTMwxaj{lL9_c8B3JgW)WHA3uoywUJF<&$ zKOD@gpB_Uw_Gx(dMK0RssrVm$&5pkxqlZaxZwcebnun7ht7fnh{_+tojBO}6g`sLI z{!+m+_mO|&td!#Z`FCYxfZ2vB>1y_5VPay$Eck8r8<;M@| zB0s!LuV>uF`UGPm=05rL04$}$a~pH+GrrweTONfN#m7j!L%H?VmR$s1|HZlfj4%i{ zi8l0m(R1G)>D12&QTRjr`ngnqY)Op+kLyv^`HO$5O7EtucG>yyQ`DGl1?;%)Z||o2 zkDSI~{8G(O^Mb2f;c;Jrxpg6Qd>ZEfF@^xw=__?nrd^DU@2bN1Iy3NHm=9k_<1==} zx^2dloM&nM_es3f18G61{jGiUg*>bMSoJE%+1PWiXfNb555&~#aO5{XQ{OxLl=|Lz zpN9>9LFNJS7Pp3h`rzEb`r!OXeQ$lGzdqP7jQm9ud5jpsoH&BY1oqV-xRl7c-`XR& z3;aRqLM4x04pO+NH=#?7x7Y(Pw+Z;w7&*P&(>^aSeSSszT#)MP_yP4QFM;w|haM~A z?SO_i!2yqUP><9M=sym8907O-fj{hxz(#~1_8A~gV?BEl#_nkw+81NfdHX_uuPTQm z1sa!nbsT`ykI+*s`++h3SD1EW4wq?1`;CHr#11~|O9$Yj zBy5oATHkEVI@FvM+R5i*%?0Fx_El(4`)|7TgOLIK+~X7;E+?KoGSWN0k$uqY5A8J1 zcjY{v3eW`7<2^{5-w4`L){1fV`$npDdj{OJEnZo6)h~9H!VNGx;JE`ta8f*L2TbF4 zfgSA$``NE9_yVj4hB634iO^_ZMKGG$Sk8dlwSK_*;BWSz(geWP+{1O8Jn$tYryCr4 zrzkM4G?{&x8#t~EguYK{)cQDg9>j-geu&_MpC5+tA;1q&d}!nckgN`uisOTaza;RX zf*+Fj;N^!DK2&l3zyk^&gshsZqoGqr9>}BVdn{K!sn#Eg9#zV~Z@Z|QaX?%sdV%80 z^j{-unxT$w2SmA)qo^3a%WLR&=%uLsIO9fp zidqHy)(o%o@8S7M9*@nykGPDTL(lg6rsOz>ctWgR>4zG_{7z|1R7Z_Lnd2+bf&J*f z)#$)J2J$=(=XGeX(VB*Wtx%J}m#sIL3FM2T8yYIw`GPJ;X1=F=3j4JeDv+}of(;ec z|GtE2jR>XD`uah}CS0yUaM8XAas(*>>-2r#7cedli(u`-H^76y(IL^H-Q5e3dl@-& z;Cv+)voD8o5&J+OG{~;!sGrL-&v19|C-rlomcnpct>BCPCUMmVBYypyu}23!m*>aC zH^0j1Z#?FCoz!qVpBkjeX8IfYC!`~T)9)$nxIP^#Sg0Rr{ z6ZV6Qw~NZQZU%tA`it#Fe0bb)A41#e#79?)#*@t#?91NoE$3p#8bzwgBgEMSjB5~& zK-U0|pj-n?Pq_xCD0GYs4nY59G?{waz8cnV8gNt5Inhld*gn@M4arCK$*OlflJt_HSoHdni zJ&C@6S5fr0-Zd)y0k{Zr(Y|;=Z#nB>82D%BTN6VbHLlKnDSkbS^z;9m{MAqJBkV9E ze^uQt9kD`mkT-uNdg!E^KyzM2@Ue)Str6JFJ0h^d{PHY)ICzq6%6wN#@N>26aP&xYciHJ`_lhl;(2%S|T=bV7 zGQ|O-qcp)=RM)Mxx<_y&p|XSRG%kl@|r^+6NaD?CrWVdFuh8rytpkA`RV!BHOy9@g@4 zE^7A?=&=Cq2Mb-ThU1hH9aPRbk6Cah=z8iTO^PyQy@K<&wRF6|ZQZ}0{k?+U ze~|V4CVbc9&uIGpEk!Z9{+$*z4NybQegM?;hqgUob(52qCh-}`W(*EACm2MzWIFlg zX?5PV+V+V>An7j8=`(xLEx-RS-CfWhJwH>U6a?h`7k7E{prq5W2_6%C3gxH{>~#-a z?}(#F4@mF<8_2*0@8EgPeu*r)djC^(8jIH_y&hvBtJS?$J5EKy!qW~5cMH2_$hXAM9Qu*G!GisEP^P6co?(J8iu zxDiX4u$#TPH6G3nF}a!sPxp#dG-%N&5peT= zqtdMxj<+s28EzkgKtONf&7;q!{$cAgHH_ZQkb?yZwN$55%|V=$(XDuHkdO z!^?(`At=Fytf|7DO<^~CPsn0{q$DD^T!H%q7bDZ(5QnS(to;6xexU>XoN$Hbu<#t} z$n!kMN5$)S_p&Rf0~`(SUY4}Ap>X%7asSZfuS&yH-cs?W>`uru3Mz@2>a%P4FlW2@EP+8adVIdtG`e;L-S%H-wa!lX^h*MMwR30)bR7g5#*6&F1?F(w3Y)Q=ZB5@dAbGOH}Nm^ z&EF8uN*=ojj>}FE`_rB`9mu6z575ZvAh_hPe2%fS0r_B5-e7rhzFPBo=1qIxB?oGb zF1Yc{9(TnH!XhQDiE+)TA3jI>NB{{fDQ{jA_xo|*p4ZT;!WCNkVLk}EYdTZuVJtbF zkA-W>sY*Y;9pqH?U|LQ|`J7iyKYe3+$;tEc(d85c5jk>t^F@)9?+Z#!`RaR_Qh=E>pWe7oj%46X|iE$PulG8qr=$!s6}U6u7q91I}+ zvax77e6XsmqT_+|jxnKQD(DC&b^ndlD>>-lMf!pCKRaG(I{@NM_CuHGeY?Sy;bi91 z$t10>mrI@^>7(q`ro!~ivvD(>|L)OvAY!?)^WVAaRad3otdPB4Rd%UPwg2$|vtE_Y zuMv@*A1DWhU?d*+6=+4CJGcQ=&r;>{Je(;eAWTt<-NdcMIGJ9LLp&yp7wv-=`+o~S zh=aXJYzronz|WrHUlQ^L&e%C8fD^Hf1t8^ryS1SiIL>(N7}}5oL(^v+(KcX5d$PLk ztWNO3D>>trGk3S?oR9^dbb1~VwP2iN;d-s)Ww5TyTdi_SrD}d}*C$Dk`mTrb0W(Gz zdJz$H#WAd>c4&LVN&9-6+B`i%z5bL`OZ^??XTyU{MHGD)E(ik^C_^O?( zYQ#P3BD`XBft~j;@_;TH%{)=gIT;MB=lbdSlG>KZqNGJts%GWP%GI1)sXE}@v3eO; zIYazdLi9)q`5}dW@nL+W{JT=s19MCaH)_f81}{SgNpBit2Z)7fim*4u#%uSBKbMCy zpLfOaeE5eRY?!%zP4@XqMa#>-TFYx0R%>+U5P2QH+b2O@&7;VxhpL9WD0N$2KfkY_ zygXo4$?Kd*w!8wT=i0BpRe8aMHJRBJ%;ENZIc>iUP+!LRGI5})849WTn}l`6Nvi$^ z^@^X*#6$gy)xhg@;kc+t3A{-H3!nUr7eg&xu=B$C$;L1QQ8+)@GO4)y9&&r5<|k?I zy6%1Z<|jSB9+m!nydTtDroW)y=Hw?oHu|HZ)1TP+6Hb5VH>1kG>XS}?otGUzO{FTO2kB@8S6~B78#r&tpNa!Run3aoB74@3T-_29(xD0Y9iU3UqYr9p z2yRIH>qSG(=M_1AbQl#_3OS!olk*0~3BH%^*QSZkQf-X~EqZkIL4?-tWdh^3=j{%? z+UsS%Q^Yg*jwD}iJA%-RL|^bZBEvSBsS#3HXHfPkDq}7T3z8G2)WBjMGN;&WPS=8# zHnyOVhm_h}Wcy96^s6r@VMxI@5{hanAg%-P^QkLBqU{Z+-FY&MRu$3zE7ttd*uC}>k)@NrO2tazKcWc z!f}|dHb7kRo#lD~rCl0Wb^xQ0C=ou{*86+q9AvgO4EJNkU5^NG&%cx)F=Xy?2{nx}1utd49*q?thFXpt& z<%s)N(f@Q^4NAfh=nt6-*m$~NO44~<>tmd!)CZrh4@Mh;Z`22$ph`lIv1jn@5Zc-r z#M)3o(=2m`9q%>!C7$Y0GdYJnw89=514lPBv8LI5<7IdN1^`twcwqzt084x(fN4Sp z^T565S9WZ^0d|BZ=HiKV{lptsMhgU=w!R9^7lbCgrM#?-2b0X|VX*_1k`C53%bfXW z@u}MUt05LEh*w~SCh3`;X%FMG<0J0I5+IzK==GxpKOG^cYY6Z|oHlM;V3RNfVy}{~$)?ku7nilogF0M3 zAb=rqP08JTlA~Q7`NWlcF#qLxfR@kCF&^0ya*@wv=;2Oryyg&tDqeyZRPhqTpz4|u z_y94`yX%EDh@lo@P%q~m*gz`Vt5~-5wAIp8=E}#v2Tutf*t%l!{-4(dZ1e=4qcQR< zC0<~~&R3rVw$8%c(xLV=KPun{#i79NhD}vz2d0{;U**`Z$wQR6mtPK3 zqRe}sCtK$G!Fyo>Qm`G~tGPk93v85j6F@}!U3y((Qk(KPHh(hynsu8+2+^-b4IzEo zyyNPo#oG3TV`#3&_*Rc33s!#`>!;T?xtGsE&JCm`JAtAO@7!ZSN&~tvM+FoO1~GI8 z>6F`>z&4W|?(XwM$dlg6!H=PnuiTt{oGQH#{MZgBOFer7b+f}b+$%0Zd)q)7*hd;* z261Kt65NrK)O8tL6ym&o+H>yZcVo^*K@L(NK~&)3%;vd%P#1tlX|zoiL7d(CcmO{&TCaj)Mehwul?Qg{m2yRcCLK7bngDaW?XREFA=5_GxBV7k z=~`bQYMP$iKOwl37ycL`!~fV35?ophMT5u&&@{i%cFI@ckZG{!2ihvI2sW{9jS4id z2=*FaJzNT{(d3{W5^)?9VaIVV*9VtZc7l!i;Ek0%^6z&lL-;r0HpGJIX70>u2~1n# zUVa~qFxb!n1-62IAe>nVm$*i@AM>~prYbR>#?a4s1Vo;}M_8@^9EQPw(%S&?CGG?? z(GJKL?SOo)be!fOUqyF#7c2>1r3vrUgewNVrx^Ic(h zrR`3~Mbn1e%XbnWSP`W!VB)fCy${LIgH+;Dil6tc3qB^{{D1UlH4CsuiASvWkh8-& zQ_G2&@e}hf^eo83aR2bay=k_?G;Ec3;Q}xB(;?cxhJUO(>Gq_Z7wKnvy|&x7OSp5U zB;oP$8}r&P?ge19fgU3Nvxl452Y82NzBK_*fIC|C6miek5&WXid^QTr7aa&%4o9X| zY>{i5$kyBSsu(l6)~oR%2DoC6<#rK6Z2IMZ*5H)^-xS9nLQ$PtCR(OvzxtF?s2OY2 zc>v4F94@0L_*ApLzIb2g2C?ysgW7uWbHdqB$1xRXX|3TQ^2-HE8V;IPm>_rHNqPwh za{ENmsRf~06>ob-|)x_#60y2IzpVdt;q~?1h$Cy4ujM*|q66 z!ZG_oX6Ewe1xjxM>d)d2r98?Z(N-ZSsde>O&%DL>auhz4U9s+nymUrO0e5JjfG)1U3u_t%;`4T;FuAs)dJaXscv^*e`7iCw+fg{@0L81z^yr=Bz zR4k=y|5mhKDxUcW^wRhA7<&1~_e<5w&mS*YFHNALRK3K7@@>@1U0aILOS<2?o-I)) z?c3b%<1mBb`uz*ZG5UR)kKvD=kA9#mj*mTx=Ogs{k6a(EKv^6gXJDFKf*&sbV~MgDM5CF>8MTIF1Ym<=Z%p zJokDr<4C4nI$!w+^imEaqw1ym=2G=C>o+CqCGv9VdI<>S+o+dQ|6Gh-(&J)FyhNRB z`}iIJ%HsO{!q-ab_wh|7^0GDkz6D4|wXef&D%HL=uP)iXykxb+e%~*YZ=-#^vZ*xt z8h*7zoou^(^#f&b_O%C?DPi8||8t4FY>j;lzcz+_t-rBU`|2Gm*}ghKMXB~x4)J8k zU6q{Y=7kIA@2-8NH2bQ0y+oaCyM2`dWfq?W^1~0lT#|kD{iQ@+w#L4yfMitv_2nB% zwXdTeD%rl`R9lJut3@c^M*nrtOQqRY&tFT_$+p{93s4qkUuXYm4Esut^Nop*oDUyR z7RSd8FBZ*5h4qp1kt&*xM_(wKkN8K=M+7K~)5p8dkHJS~T;H_0M4fDn--`cj48QfW z?o$2Mq6bR$TdP1tsea1~@np%p^l|ahSTTMpQ!mNCe*}8z0FqJ1lPSwf)ys?bm#i1x z|6}e;;Nz~U{ijgqP?i}KCF}!42tLrM`XGqtq_jANR>D#UlwuIAVG%-`&ZS(69$k7*KHlm-!LIDJTprlK=O6?((}c^P4Q-`@i@5eA>)! zx%ZxP?%D3S=iWG=dT(x zS%zm7{<`I<3HZyGlhDTh?|9@UjmL9O5|2ErJ<~zLJMsTes5|PfKQnvt@VT?DL!D2( zRh=a7nzK55$O^mg|{Vt zQ?@GfGm?Tx$K}hvNawWE% zLsm~6lK;Xu6a;xiX4!dU%|+P9W6gF7ht&8wsz@~E(fQ`hF1k=0!vkz}7xeD|}g#&`%FKDKX% zF24peI|U-^ zG!HzY{DF>`!>zSs`-x)5Kha0h3qVu#fh?BqLE=0Uv;KnYQI(%Fvc1AH%!TkSoJ@7^ zDgwvj_ER_({y`yK9Fy>pNpdlACwbwiNFP9bP zxjJZHy$c$$=XI7awgp1EQ+AiLG+I5Hv%KAb3G)QQlWdQ?ZgK~A-7x)^JeMKa`}t`b zreDXNN{+4f&IBjnjojjmcQWpEejPFOPJa^lvw&vg4Izk1$7Q-U*L8Gmr|GE=P_zB6 zw&()hvSO;fgs)=`6(VZ}k+(R%_e3RjA=B&4FzjVw$F1)PNDTq8Vy7v?RX>os7<5FP z_r{^7zjND84nFh^WMxH6>xJs+&RzoK!8y~q-T--ltOe>DD|h2m{*p)}WVue)zlNKE z;&SK;Ic8qEwOj1*AyMO_&Go;my2-UoA`qI0Ca~tmVcKy^|@h;GJ<6!9NV>AMx^O~9HQhTw@o#?O63xCwC5XDk&`c# z$;rY}IRR%DTZJ>Z85eZ8W=2s!|9r?Uk{6lU{&7+U{hX){A56%zT`xc@y@hVw0p04- z<)=cII7e)27sq9l0e;kojlz$5{(yRvWhddJrP12U+)_4lm36`ywO1{-Dc_gC-` zeA;y%(@2Z?x2QnibRf+isk~r0W?}!Tgps|o9#v{@c(c%0sl9eld$7CRGbX23#?gB@ z)MfSF?YI$Y^&ucrMejuk$+&v&olh7#<+q+3d;xl|RWI{sBz09LS>%Ek&_ucBf zDwSKk7uWSqS?|r-<6Y^!%vRO(gVB3KP`$J|IhUVS!}GHI6sm`}Dz0ifWEM6ACWs7$ zeNr4dO2%uE9t_YAzkQ%YKk(ZkoJ-V%e{?2Sz?p>S3Rd-gfNxV_4R=^?glg@B<8L)X zmzT)vXYc^>N&^zB@V8dhY7WdwRJa{VMfqD$D&_uGA7C^7mQg6&oXGfF7ktd{Ve@oF z-)-Pk@v?AAe!lT5o6t6C+_bmvS6&Z$Gq!I`mk(FiCF*ZkJqa7Q5Ga+{?^3kkU|7HY z+kij>EebTt1kL#M*?+l$hV!0E{rVXE`a18bS->&Xx#i^KtW*z}6-DCO|EjhVgfWYY z#KFHq)){#R!@_9&T%+50H*)8_>ihX4TTI075zX(RkfT2X?R@tb$V5AG(y+Djt-Ahq zXXiUGb5h05*X$8!=eLV1J71hu4X^(RJD+=}L^iZ_)6KXHTa#9-4_2 z&ce6@GE+OQJ?#K|Mm~eaLr;Ii$Y&;``M2tL=t{Ip*$i#r@I&BuC^hY@kask+6W2ji zt+%v496{CNp&HE22J=8@T?G$#+W`}fhl*ngfl9xiw7q}Bc<9*sm1EE{T?nEagSW*o zSdwbha7@{LU4(vch!I(H3Ecx(sI_Q^`Mt+rc(gHcd3-m`1dYf8sG!oPWOx+aszOqF z7T3@n^`1Y_^!xBTie44`X~)5f&=mWz1_gcH@cstv{&yIsC8>H{ zf93eIx}B%(nPelEnQ`^VW=$6z#Pt0U5B@ZiLKlFS0z5HcPKYUYu%*i z+f(W9!Grb3v!BEUqmCFXzf(+GMiO<^=oO*9#W6FUO}OLP(6F@wSjw%&v)-0XpKTJRUYus{99#!13g=`Z%dN!0!#f6`y< zmq!Q)-yuI;e=%QFba=1+VxO+3QZ9|W(BM&CYW5O&QSs7m8c9aN4i>`7gC!71i)m*ez$=^Dg5Qada?;5oX*ItsM9Cqoc?3tG@Ojqkmi8 z)O@J^IO85ew~a6eqGw#X9q!Vtn3_qtO%SKJ7h=eI>b4X5D|h4|aYrBzxi=I5Q}##x ziAb>{ppi8{CexMrBNu;7q_zcX4=Oa6vQ;AhN)gPApvDbn4AqTm13Jq>6bdn+XToRx?Q!@1SZcO9sGl{p2{PSJXBZs}z0`2#`^wW%g zcD>OSeOOmgg(k7>%V}cNs`u%A4gb^`IR8!dJNplf_XPEo+3x|-G-AK`v%3B6(Dhg9 ziHYs^BpR{yJ8JN#YQG2Gr{t0uN(@|lW+(j-w7PX7) zWwD;D3ZM18znstLBZAlJyr*M^&oZxRIMp8qPNS#(6K{y+$i9N5((mmMO4-l9QWs1T~K6IQR>rTHWqb@(K3 zT-$;#yk)--KQC3a-iiFY4y=l-=qcsr4OC#_eF9i;d=r~wd;f;<%~$U%W$!a_pXw`A zqa#NQzCU+aX{=HEb2(X9y%;7HyC5+bZ~Qr#u`u%!p%II}oxb%xzNh$eG1LB3$6KGn z?s6skCHAXV_)FWZ8bDXkBg$^Y!R!@wE9Tv}hmo7^zgMG+k(*y*I}OTBr;;0GxBiBQ z+(L!>uPoXD@X59otyCbgTNOM-v0sBF8p(V9j?%7q4EM^Og)|(K&@-_TJ+mwJzYDZy zJ8k9Ivtton7CCIhy89}$Dpcqh=om1^;yUl#-3`5(URCs($S)VaH^%&j@yDa#N!DlL z!g@S92vsc88>?#hv${R&|C@q$3jVX?RB${xiAJnFOXzkg;`mlit--dbEFUg047TR)_kZO6Yq{)l>Y4-t%gTwd;bRg`_@3IkbAgK#Z3DZ z{tidtzW!Z`L@cK}wf=45PBq8^nn3^7Tl{_f`?DI+zkM%j{HLmaU#2JAfaRh zBC5h$>nudhxFP24380kT3mdqqjvKy*0Sx6PkE-mr;kS5LsecPQPoRHK!)E$rQ+bU$ zv5bU7MAu13WQQNw?~+t68|H@lYw#T>Nj`=;F#h)xJs*IU<>mN=n8!k1mfGu6W)ncZ zq&Z{Y2b9K4)4pd5#fBM(kmKpHA#7MhBIf4xo=}S|=1$;tgKi=b&De8x3Jahlyk|bR z1z_JidL#e4j{o8Cl+B}8@W0FW-)cgPAKq6H`s3g8^|Zq>SB`&JPtB|cNAIG)H8AmaSK)i~mE_i;tZcDd(=+{>LYLmz)3|e9lOXgkcSCIQ zP9uQ=%iJhs#&90tAR(*vZLSHFuhyS!^Z9rNSQ`7x<k#$(y6!I~g^56OO(%92E~A$*jlnDf=$CHJf5Neqt~$ujx6_m>v(Hj4Hu?Zcga0KT5PZ5Y z+B5yKWN*W?(OWBDTrZF#+V}A26$a)yPD1#Ripc5{uv>)4KBxiBgFUJ95?rP1qwBDz zrRlntvG2;*zPT3_UQ>~q-2>!Cy84J|qrFBnDsy^rs&^sD0t$Th9&7k~?{ueYql=UmpXQ&_0r=lb5+)8}I^pvk3 ze4PfysgdX;^4m4X!d|VCg zUj@)a>0(LvO7-db0`hlUJ!x}{KUPgoB4duM%q^M8sv<>y74dU*2g2Z{ z=tWlFkHwV2{z(dx4pu@@OJX}y=EJjlcK-%spne{Vi+B6uR2A3{xb$OY|05HALAYo4 zA%2@2+aQ{D!-Ae+Z-ta89iT@UBQmh72>Z{l2N>dfoqr7G6D9xD8yyixZ~PfMREb_r znsR~qX7qu&@!x;HDpyc_bOUG6S=k-gw$FMGysDZ{god9V7j7`#-Bp_y{cZ*0UDaXg zE5oN6-~GBe-yH!MQ+2w&0Qn9Jc9KuO(DGe%``jcnFnovZ*7jNY&*eR9pX;T^w4qS? z{%<0)pa|5ib^PG;DKSMar*@EDR(!p4m9HHQ57)4i#ZnmLma*6fb}%&Oh}QgJ-2MUt zMH!H29rLfhYd*{UK3E?pyEghj#=I}nbJ~7Q%xCmJLrpS(^7-s}Y>27sYV)}DQ^8G* z&!VQje-oc&ey8YD8Gk|6rJP^RbsGz9?nre$%QB8(bVSVZ+40hefqXWohL94H7kxNG z#M3_<55JHcA{T948;FK~?uT~Z9hSgD)6g4R2U2+o!?asE-a?XPs`zNc{9PooOuH*`O%;6rpxF5-zu2x|aRe!Paq4WLnbhT!dBHuT#b7pfqc#Qy@PRth z2cIhB@aS1tMYRCyYIrCC54Gp6+~kW)R^ef2?Bl_GiPtCZd1(tAx*F+y9=N4Dah4#; z)_6O7*Tz3O@xt5hMnjiXxaDQ~ecmPab>h~9Hy$De-R20z6sbkf*70#)%cGz+puLQb z`uS);*iRp!IH-CD;Ss(XMy==@Fs=EKB^B^ZjKzf#H}hAXAC*x8Um@F>rx^LvppbQZ zSY%rc0R&qXg+04)66@SXotJPQTf=4WL#fcZ16V4n`8n)0ep==WqmA<1KiH=qUMKd! z&gsL1WE_-uM$w;Z`FOEj{ziT3JW#9&`K%lmL_LMWd_-5xlY@}D>)0-0KJ>Kk3ruCW zzgiUk-J02x`L8%Y_E>ya?raB9tZiO4X*$ z@#JslD>+ZP@|@ZCePyQbZnE+m&pvhjVZl51fo()}@MJ@EO}_r0o>R5{0aO1D@1g$V zs@I<}_1|{?yNCa^v#Y{CV(R}~Mg4WZE#(^o*%jaP&Q=4JbXA`AsGNC_Sh5Ykwr2Q>U@wpaO_h9ongD zWjk`B75$|4r_ik(x*i=4_4#n^5o28)Z%=Pq4?i6%=g8$NVAP(+b__JGac|~K&NI~O z@~)l|IRPIJDzx?jS~xd`=eR721n_bD)#msG*r(i63NK?{jQlZd$Rj1d&x(%QDLUrr z;zB#<>!Z2e?t>6K*}tEA_iK?cR(KtXSkse0W!~1;8U5I*+g+^@G4co-kuXZ~ehB3Z z(Q#qHOfC1KeyOA0&r#7xq~F(U&~rtqPS^xrtMOpqkZx}Sz~II9xRiu?QcMxfsA>o0 zV1f@jI@10DbYHalqcEjhKaCKB_wfCj5%r}KOL#M`+18xv-v6YcUpXEqAIf~>tdQu9 z{Y7txp6k%xyZw*EV`0%a+9S%U-=0l}-p7TEzV?;6j#fG-9#D_;7up>}JviaO>-+oL zV`2TB=~v>dzbk~$mG)e8_q^?~rJGIMf#vv*a>dK?!;DI~%7kaRa&>$i&f18>w%02e zTR03k8v#OD#P%R>D=2Rn3dV8d5?C-XdIKuk zlq1p)bn6#Cb`b!j4$6JpboS8^2rCYJS_bx8w7=Cwr6*xTR&N1G8QZr-w-e}Ztvwnt ze>`NLRb7O$n}nBm1WPtiPo8)HR0rkTA*(!R!<-Z)(+XKH17N9Y+{Lq4d*6uTDtQ`C z&olFT?w!|z1A`tM{c-kjh3`zw7)E|UYIL`(frbXdQH;=H%(jMBgU~+LfWraj@o>Ov zoeqku*+dHA$f6_H?sN%WZy#B81D@cMVFgbc&tQ`Cc<}dx+9m+PgPEGdQGC$b4KktQ zWJwLzROsXV4i1TlvsEh(xvD{zkzIc_w(o{%41PJRa{`%`jwjeRug<@6nU*YpZiqLb zig`Q?jVF*$tM5KKt%RTcbhR3%bUdc$>*67NB&=L{P8iPV`sjk5hZY=gFUfoH+4z5p zNbhVQhGs`PKSpLlRMsAowjz(Dg#tqI@Ni%lyY!Jahl^_le<>8uzD6QcgqVviS|i@o zg4NhQB1_*4G;00?S`w=j^%9s9)w0qA{Jk)6>p2>~a5-|?Wc2-0M){Gh1I=P+$TjnM z#`uCTe+*OKj{p@(sG%v46q_886H|a67|OqYMjRAA6j6V8RXlhDwt;o*EsFOP1uBoTc<)s73_tt$96=vuE^~@Nd3D zf?#A~6dleZ6`Y{^7J#qSP?OE@tGxW^om2bEc|CA=)%l{}e2$2K#L6YXNGM&!u?>;X z^sgi6=$@8C*gfzldR8R8#$G#m;i!)9n+`_mLGzWB{iNkOfgv04m$ir7wId1{wPU)U zIk>f9bb?_S`s)PZHYXUj6Ka21t&hI*r3&=gsET*DgB3x~Z$7f7KqS!rfGfdhCk{G` zCJ%irvZ@sRd)`G#@0vMkc_()6DFuF|xjiM~vbD z8ZE3l6qO)WMf#G7;TU#tW(`BkZ01Qy}=&&$XBU~yDW-|;O zkhj2KCNp3i)RG$V;(4Chpa8CgexOf?jZ=6CJOgJt@`yoGI*Zag5s7hxb-KKv3-z3ohkxEgQjo4kW2kxjdCJ;X3^UuW zVcaLF>!HqPU8X*vGgAFPXBlT6AT<7@(0B%VO9<>e-)tp2io)I!u&;P5XFx03{V2gT(zz0?@Fs^W4?1>kOe(N?U`Wbiyf0ddT)p|a%=5%3P zbW10cB>E_)Qg3{XrWWvHJ{F>a_2~0w9UBBT!KI6rB*jQ;h%XcQr6!V}u zBR=f@x4hrrJ1sM$Ou7}gkup;sZ_i#lQ;bN!cs^&wt2f?RJ|1q`RV`pQ^x^P_|B_wn zw}iS*wdnVHSS06O^IN>%g71Uy#_N!`Ew~Iw@V%*<&q)_v;FluLVf!HXrP%l>H%8dL z8-g)?nhxq~-#*Lu0CNc5=09)E`VCx8d{+2ySMs49W3OEXCAf^q0fo^$7z<6&O*CcM zh67hl{Nmg2kact)P8N6_rxg3T;wN}#b%nUyzrIYzp~$(SB-d8F=WKz~W)ZBu7wm?(who6J2rMmTZLH$iyoBnP9 z5o(NsbpVM_$O04!1UaGO)5;$$Gz@j30iam)=Ai*CA~mQfU9f1vUc_{}cp(?@C49=C z4SQ{0+{|Mm?G-Njp4dT5316Q4c%=4g7{60~&C4hIa2g>OaByXgdk+;Q^s=)>bJ4NX)-{0D`Hr}3>n)sKYv(Xn2 zQ)3^OKPq;sU*`-gG^1c2vgGQ{PVW8Am$yiq&9(zYAg424SDWL8}Jk0c`w*8C-!g9<-WQAzjQWa50w|ZSGRjxOy(HYU#iRT z=je|um2rjf=fsyo=k@;;mU!(E5H2;>?tKuwMANJG8K!)j`ivaA-GacR3T{jHP}n#~ z!|tNWIY)=A_uhWYj$G(`Q1ZpD8@Zux!wdRB_Lu##+rTm4FvkgHVgM(2j*meS>ZH-s zksKppOH&CXz!yVkwBr@}7Yk&jluVHaiL%~dj2UcL-3?-EK;*pYRJv5Z5ocZ;m+`l; z$Hx(r;%7w=XOxb8+mDAFnsP>d%$^09Qz3VWq(#9eXVglU(cdI3QZ>4Lx4g7#ABOf%BkpIP-P$6r2T;-wKlF-TAPUqL^)~6Td?Sx8Vf3n8>4xFV^UeNVBp@+Qkqh&;mwOVd?o;CQx0v)p`cX=dRv= zi)MIZ*fp}ut~>HBF9&ZgZ@`AdvB;`0>X_eq#GBX~b$aAd-X$;D+=qH1 ztG3~dm}D+Hz>YN9C^P;=e&Ik2vpZt3{gfL{x3uIxc*8qb1|v2lvib>Brz(1l>pc=M z=c9;RimGhnJE)(&`G_MIF4#7-8V`6mcmM~<4~LVmFpTcB@#8f4Z7?fcCM<*wAya+)a0r>jTXvC*A58y{`*@lD*~MiE6RY*^oTkPFORRtDl$&5& zuwia~BY;BVId6yGtB~Bgtmk|+PRV%>{La*4^rge+;{TuK^7)Z2Qjk;a|7$+)0~M>d z{V>GZ?f(Z9ftE7E?BW*~{iLYq>tWE7am>idpOUzsLFRb&6)VI)iQnbDn?P1wX%jy4 z#+F$>$LJkL4>TFQ{s_f$ASPg+sKzbzdn`So`KSU8jB{bfIX3cA-`U2F>kOQHnN(GK13%b?Lshx* z)71Qi=`X{7SnCBbn|OX=2`Vlo7MAe)**0FqF7fVJ8XT{(>h4L>t4xdG zmw=;8lB)#La@FJqcol&cL}G?F<58LOFu3vW;H}DkHhjQ4;%MZmz9OEz>k+B=njVhte3nWga{L2Rzp?kI-;XCmPb{Gi;|cN4s=%NrXZy*-6V6yJ`oP#b^Ic&5 zt(EmBs@K1l=$kE7{rx|lDt$IJRHIMG(C5t-OCP4)7+xg~27agkGq1n=!}Ge{nYp5# zT#(~r`n=vF;}n-XdH)4`32X2Mteda*nI4hu(^%kbxD)ea zsTUNJA&9{{IM&Z&j>kI(-X8g-n!VC`W9eDohQ8?}kY}8zjPDy-C&l+IZd^ry zq@0KJfJTsUEki@gC*b=QfT6q_gdo)HYx~YR&N!RI#$~_fcx1!eXyGK3>DfTn6{(Uc zE|%ZcM0ZoE{vZ1MKsn*I*3=Cs5JfBwV(Il?3MfcLr(&4+}`AHRB9x*T53cB=atLrxOHO_F){l z^Yx_>fIr+YlmNeaGuNTtx{9Z^>xXeZ{O7guFcw+4o^)laqRFh$7i@dyFp-do4S*D= z-Cjh+@H>=hL!n`aw8~4w%MrZH3DZQ`#+7J8!4cx^N_$&?yXq~ow>jQ^(cX^mcA>q^ z@b*Z1JHXpR>}?-!>u@WaS&S^(5v)67>9)z`4^*%wh_?joY75>W3T( zs}1^Dx8o)1&UxsnLI~y9{~QMv(zCZ0GavS1gP8rzStZ;l0PFv(ocr?m9rz$y`=wvR zhHMl2PhTM1ou`%f2W58Ttux=F9Vu885*7suKkP_7n!j64;el0{JL?VanXRlrsOm@e zyg9$;jfSD0(jwdh1wiA8%QRrDi0R+Td5@nSI-H zL*s4p^%=?DCW+MHAToIrkw+)dF@wyw4-{=9<+7Zh>MNx~!5dm+VWUTq&R9Bhj#EEr0@JSu3IpgZM>U!+&7US+ z9-qoZXj#tapGrOV&?l41k1<&Pf8dryy9>n$GL z1!s(t2V)JY%atM2OeyTJZE|m&`ljY$b$~?~A@H1m= z2V=JNHP8jSazI%~Z5TyO8S=+wv4|vZpi77uA@Se88ydMsDFMO}z3wlrW zI$n9oxOtxqsGl4)-g{YBsoM`KkG+(~ElA6}#3V3( zMD!MAo0qYtlC;J=vDLq8donqOZCd7Jxs^__74>m07!d_7s;8^d`kiexFU$jT=HB>5`zm2$p{tiBfS^mwIs zt*WnqNZ}%0LPy8HY>@E^5~1G*Z>x|FVfYA?k^d~KRN#6hS1pkM0b^XVo=m>^x*4L- zpCjwK>~QZX^b0$6yDmTTH$V<`gFIz%%*g7q5s*bc^tsG{{!Hk4g7_hj9?^5hr^h$n zJv}m?r@-%bV;xT%(3Fh<^R(@(TJLruZpSMn6<5dWANQm+|A1?!YBZ!kM4~YK{um zFRQVguTqv&e-}#mpI$H5=i;LNdav#Hx-z((#5I%D7xx1gqSbPKB|kilcZMIXuF4Nh zX5RBFEW; z-SCxML3;KOLpMf}3+dF^qGxqjNGaK|;mDn!nBVJ807ypNUt9y+$Q6qZOtwtFh}Yl{=8 zucNx%Aihch-qxdF`@k`oD^ig$Sl77Qg`pte*NNDYrk^eP9_+di( zm4hOrd<-;#=K}24ARfOr`}O@}7>w3ks^V0aSLch4J z2Q>Z4>{qj{hyBhg$bNlNg#7R^yq1}bLOOa*fCQNaQF%u);Sv8U$hG7$iHaE zb{8^~jCw6E`%%ZBek1*j{g(N{feRJS>pm-+FMM#pd&Ilo;LWyqxp=pr`I7m<|Mn~b zLE{jXPwM%?eZGPr`gyO|??aa}^7)5! zBjX2LuhY?^;33Ss4BxZAo7p@%&0GFw8*^{e-v{xnhF{|Dr=WuTx{Hmja``s0`U*6p z{q3->&yCyAMzH-B6xaL~Wkw)lFZ*MR+^m6Tp3rc&g8yCukITZp7CAK7-$^I^)OgEY znT7~cXr2C^HiVb`9_`in?V0?d$m(UK{&KS}AJp#}e_012dFZhf27ep#GX8Q**Arw9 zn^CM>&WLxbgLiI?!n<70mn1r!_p0qTQC54soJXhc2(E=g^OO zK~&?{wsW(MFi(nsZP+^jprktu*BNM1srcmJiLAU7EfS{Iua(Gzp=aUJU_N$-wFe7P z5$Dn4kFS&{Z*h{xhI_^xe*8H}1LmO7soR}^o{^PnHT?0f2g0A21pJ2){xtb9d1zK6 zF%X1AW_%=KL?YuL;djU6@&S{bld(s$(9C1#huOFU$?byUZRb|GRwOfX``rl+^IJcpH0AAlYe;u7xhwJR8&BPs$$E zbt(8u^H@vlQFf)GN02=#0)5SICH5$)fhV7?)8!|$M_0ct_NYaFA7qaP{r0Nbqqr^~ z)bADcXu#rMVUG%zD7=I0Q31uu<&5?y=HNY`%a3c1u3+Xz>D8&rO~ilPX{Fe*s)YY& zkCM841;03|GT0(51u*Hj;X4DB=?60_4L@{(btUe4^Zou})`JXoDteC7FEa0cBn*^Y zK>HDnzVZXWl9`*ud1e!w)oSuTk9ALG^1tm|JNX|2?&(I2NK&_3P7js4iv4f)u%a(0 zzc+jjh9Y6WcS$Py^>>YLAJ8kox8+ic?})*7)mKXKZPxg<=yt2&yK47Rd=n0wln--p z&RWZh^oz`s}QZ~P}tP3s0012*C|%!&0MwPOiVikuFr}t z(fNU|o>iV7*!{IqxuqtS`~ovi)`bV)F?(>`*$||X*gknK(|rw7+DxE2`3$GD=G104 zZjWqX{K(z&e)S`t0{(nbNSv#F6y=-VIknh&Rb`Yu0f(>P9dWcxsYwC^H7$?`jjT}c zQr->k;it?SQ&s?~9k0q-_d?4Wl?KE4rGj_hVT@7OZ4c4|x<8EkrgZ(xQ7G?U)^F&4 z0m%^SVgF)66^WgRW_W{U$BmC1W`UP{pjWX|d}-di86Udv`uRYd5>gR;y+D$=j8ROK zq%#`c!o{Wi=8i)~x@qUISfOWecyvG2?x6lYh;AkQt@jfz)?DW5%E;;)fP86w@Gd~g z=D!8uGmSMeev34jL|+ZFizyy8=->YD*RY)<()<#yxm z59oSadnNV2KgzRP;U}n0^-e!@GuDx5y1Qc&@=TE3AzUW@a1?>bm(Wu37MSeBfsM&q zU>RP9j$FeL!un8VJn8S!xpH2el73jaeO3JsGy37NCFS~|??Ody%7UR4;WYW1>E?6c z5I%hfSV68%{XKJl%H@ampo_}u*c-KhHu>1)&!TX@kQW`@$# z5ugH39?|Q@W4fJtQHmGoCiTlY5*)qJdpwrU@Td*!%!4Dxp5aEdNGY4wa}ST&cr1U> z54IC^*^}W$GT%-fTDah=fG6Ayc(8^5vcu&!VUPQfgYOLPe*d_$t>V9K1Jx2F59R)= zs7mF(a@{kY zYGkd-By3(SFz4byt#r95Ou>6>uGL#HRH~G2Cw_$nJ5;;WfkFN1HoH3&e7>gFG0RlG zdG9CxX_apb^`sN!*kS!45nI3HBayvU;YTPmE3+Qd_wNUZY{~m2m%I=vEV<;ZP&9H) z2Ir{Q`$XA&yzD+!cHhbS6G_IH*Dwntli5? z^%w87Tu9uf(yrgNO;x!)wo$~Q;C*n8&4(q?aG6#NUsTrnh3fU@7HNNB=nLigAbWwS z*>7ij_&0^C!hZ>Lhw$BrM;Q3Kr(FN_)$5;jp059m*{1$U>FaeV*Y=6NcJ#2!J1Fc+ z_4OF^wWHV5QFM<4NtNiz|E8RwV)g#HcScpZ#f`q+^YrrmF?xy`iI=Hgc1ScS8OZ$N z{s(G>VZm#`c5}wR;{MLu=UD~Zv2heOL>oP8NvhbUAU5Qp%Agoe4dOA?sPL$BPE2&iBZkB8S;lZnj0kgRGFKpp1{TVa(X~jxCukb?77WYH< z_uE@_72Z)}=dY%JvJ6Ls(9giBqC7*AXE$R<@6}^}fv0mwpr*NN*Kcxh-ROYnN@QqN8!|HXgcwozr`U`2_pI z5VtE=qG=u~+V$3!%l--%49hCt+9I;@D=ZA~I{-dESDSZ+z0>i1sz$?M`m2l%;0t}E zmF#*4Gp+W1mtBW8%pEBZO|$*obWj3Yj`Qr9l0F;(>XFs^0F1GH`oxAJ}iy>!YqgN`wwpo|2#+N)JV%8Wubaa&Lf8|||&1bNVMVG4<_W?`UAo;xJQfl9dz2GP}{luOTTfR%;Y9HW%mjCKJWkHHw3objoT51Gll~W+f=vx8s=o zRq#Y@$x^yrfGhB@BzwL0-A-#-IpUy{2wyW7ofqvkFQX4mavS(erJqo?uUuXb#2#EK za|?T@Fd(2dP#Hbm8BiHLV(?;L@}hk65*cvznIc@oz2ZBw&w7r9us2`fo5ESbt!AGo zC_h90`D6#5H9*ET(WajDJ z*0D-j4bO6-V>0-VIaq^A(V%QGaL=YXI(pCv4YH<75ijPAeobv%uJwS?tJcq?*!pmC zkI7<^qzKw;8KMVm)rC~%|3aM^i3yf3#!nfynvJ>kPkP7f-#f8PuH^AF+oo@WM*BrVoL++3^Tk{Bds}p zjK!As$JtMj7Y7CUig9*iHBA)atJU}ldPwC3ra(9l#}1M@$YjMPRBP5Q)m=|IykYW# zi(X^drcT7Oej*=RK{for(`IU}SdPMW9*~W|Sl@nKUj^bZK z*Yfe#9w3S{+39>&6{V7Cf&Y~1K-X&{IloVV=?`mksE_IDelUx;GG2^hPSn- z6ug-LfvlzQ&Yq?49!Aa%=UYYG!_`CCSF7uxepHTdi{lm+S3 z=9@+tg}v$6E0gn^xh0kGiym?8R(=<|KMK7EZ(x56WH5+{bp0NhpM#jCvjL9vOK`5% zBH1@F7uKNUnPynJPc4>As9Z`Db8~CB5;e%y7P%Bu82vb>2II`x8q6w{birs-e}HfF zmEwky^=$sUP@%6RzQFZUp<`97z?8Fm#4#f+bk~89vXqrGvIQ^jt%|4W{6ydOz=!F+ znL^?3BXktjOY6(jZ}w&0t|ZdzL@~5qT3!x=Jbi9$+Y{{bM%C2T9M%5FIe*jW`7(Hy z?n@an@d*6Rhi)l_^@FOC@^*cAFHylAn&$MC{%;L0+vPuJA0LUYmF#x`g;6uVw-rNa zp;2LUZz^y*Zen?($Bl;puBkWUgim2D^R%|Pw0M-Mk$RvY`K`Wttdb@5(hMxpP%Owj zbF_SMoer%dDv|whFf72!C9;khuiSB)@=yPShoDz3^j%SSFe*pKumw0an*|O%*gLBH zl+uS#U~J#@tPGdwci>^hw~;lSctI@0&)gEpnTM`l@%iKdS**|weeFczmdQx}s?m@d z0SjuqvOtAPQs|j*uL}MsbZSaqRB&qTbK+@1$Ky9wDaE{B(1Gi^Z_s#~&hgtE9(#B1 zYXVX>)@(*4Oa4nnfGCQ%I;g-7I)hm6ei7} zO|DOXxuP`6-l>lXTgKUx17o**-zVQYp%0h_<|M|vkPn(fb)s5_)6R`gk2aoJ8tVTZ zMR*Z)W@Pol!gzQbu92SLNxWfsv$q;aDH~J&bHz!9uS`2;y>~VHBgZpvdvD)V$*<gnMhl234MAb0mxb94gbf8af~soO9&R`_ocIHRM;7}q|Q z?43Q0vvBu#pGi&|PCiitbJanH;zGt*S!6mCPg8KrMw`6IM_?JyN5!I*gIMFe{Tu_f zIL}^xek$5s1HOc&A0T&xs8idKaDf4QvRvVzs^U0OdiH`&g%_Bx9<*N z>sbs%qQYw4jW1bcFL^U}?qC%BF(7SB3AQVjU2nuc0MWdI zHjj;^J2fpyzdl`Wklqw|(fjKNJqHLoIs9v$J^5ECxr2pMvy<>sIX%_6S2CQ?u_uls z#DVQIAO-ZN_^oC0cRQZ%%-{957Ki@5%UovIqNArFF@BOY66W{SE1QTzS*_!0NA$ z;cSqxv1n-dE>sLfwZUkqB7^$C)G&`K4}07A?wknqu{)b?nG*_ipQzwAdcx=-YEZ2w zl%Bhl$iQ&4-p(<;o_560%A^L4ZnCkJI6n18KPa)4xEWNwL|C&~p{|-`D&6`at7aFm z=QmRlIRA%JJtSqQ#=8ky%IWcMZeg&##P+1q+O9BhCWiSr`oy`%`g_waw71ePuuTb| zGPE~1hLkcs$&XHw{%qCd3|&ll&iCm!wu;*0K2&EYRDV_?xRKcTvELFj4KOo}*R4NzY=jGZn83+}}Id_5`LUMpl4IUHd(ev9J zJsQKVZ&TD`$GYWnUzl?FS#J5hsh8i;E#Ex#@*9`A_)oq36K?t3=~Kr4cDH=r)XQJ# zmT#VV`SacKv8k6o)-9jIenC^@pIL7CzNwer(JkLR_3|5+y8S=(@=v(sbJ!nfium8| zmhYQ-`77P>%~LObzFR&v_43EM<#VS^8UI;s`M#-_-_b4KJoWM$T|X=~_3}@+<#X6G zcB=jFmhYQ-`77P>%~LObzFR)#lxJLqHYA3Byu#`a?9n^Tk*?Kvg&LQ3k6q7V;V2$m>1WSC{qVD8 zJzB{YT|>9P4QLp;lFk687W6Twi2KN)K{@Zs>!)eK4D|)n`*pwG$Vz5lIZjt(&Fy^a zPWE6wFd|jVftuR4%hmmgzTF(2VYp%F34!JwLSrEKO4fSKb*Rt#_O|r);Fm|s;33^3 z3Isbp_yC*BCDIZXKz0lWDggMNAkR90XDL&I-kJX@36oGGP4YajEU*aR4|{H$SrND35)t!6u(L58vL#Qg{rSkKa1mUhklmO&yx5%sGl|I zXU+Iq)X!S=vkv^NA5`^q>t`wa?aPyXP2jlL&u@II#RqogbD>-2q{zK`pB@&n)3>wEG7?-Tl-e8Bspz9$dxzER(^ z|9Rh}@7edfZ`Swhciy+?d-gf+TlIa2c;mi9-`B|fskNO%KCW-Nd6U#PDc&^en{~YD z&^LX&N$Hz@>ac-UDp5TBfqp7;Tp5+JaBA)CoQ@vmha>Bt{;2xYOl?Z*+k1R%sLIT# z)d%`w-jFJh5lZa0UbHHaibgqUolr%gj=7ckX$+sh&h(3ZnnMT24=P92)ZxL@loM>l z074MjR`j>t%io*i$lG~6uMce$bMb;Q7Xt{(4`+l;S}y%*oGG-nV((Ok}@r|sY#-Moxl zu=J)w3G(*$uUEDRdLMc3$8&MUUeNpdL+^hSdjF95YmfiTeEOJc7afxXmn767-j;rt z+#AOHucaSonFmb^*g%;_;!422A2Sr~AK;vgg~#|kG=oSVIAduC{%>1)ApURXxlY9k zBC91giL)s1^Ux(ta;z%muk2k{@jUrLwof}-Z}gv;Xj+qwrg1*4 zX}01gfRnNNhGirfW z{j5(v>&M>#{cKP_%iwQ8KO51{viKXnP1PrA8*LQutW`e~)r@CU$piYCs9!vz+AZj3 zqGIuksx>YFygQT{#WSkU{(Dp#N>wV{=w29AsnnWLm6vPHcDYuS*VGap&eTIy8hg}M z3sw0mZGZj@(U{duU>&P$@Vwh_*M)+-Z9tsja5lr3? zF%eGQ5F=kejb^-=8i=qEIZ=+@;jddEWp}0rjxAgAg@)_6=)Te5lXD;)AqK48m{SV=;mo@;17)^uqUuaKjL^{`O+Kz|ZI5!bN zvv$5s#wQ%uk?>X4rEKTdU9v7^-DgVWgE4eo)Mum_^qIMJ((M>JIBf>;S9IX`!|()tN6+x&xS|&ynci!7rkNx5~(=R z^KN(5o_^NWO+oZd``1jp9|P{>GIk4i z*!d$hU+a$&Pn7|p%-4<>;KEm{d>rx=FVaT%t84uhj4Q}P{HLfV@X35^<$ByFALWsF zf$LlfW}VAN_Ag)W+4?D;KMf3QlXgb;i^XSN>Cr03?%^M;vK{a)nB!I0eKK3d6&QEN z+A;A%Pq1MqejnEQ-`i|e9%-2l9p|b%w#{o|d|!N|D!!pFBN9fx^V9p4h zHPe?vLtnrfGx|#QDaqF-&V=J&(#B;&n_fE_@O%_fxAHA5n5QPgRP5)?M zCZvGbgLFAIbCxt(e+^6#i#dlj^ zwTQS3|M5@oZkO*INS;Pf?R!!5i)Y))U>qA! zdpV95SRAX_7vtB-eoFPfadrNr_ve^dwm(Osrjnwp`rq^$`<$2Nv!&FecD)KFb(o9f zt``{xZn0Ng&!Vz)O1G#@U>wi9Ctri^w|Sh#J_+q?-fd*n)%Xywcr49|#^vuS` zw+{^!e(;6&`1WA|x!CoCJD=f+uTkZ1=e@^vRsJ^eqs!Vc`r0JRo%1mA*sz$OQGdrX z>x?ZWLm7MFs?7aJU!70yb}Mj?*w=70u|8z(W%mR*UUKd&1Fg7grV=byBPW=%GxQX z?{*I<`qq_wSMCo~_V;CXj{{HZvxKMB!1H{KfhY5kQoPIIx%fc^kMYTk7X|&uIL*>o zW%`k4>}5M%!H5g7n~k6{l!%#7&U!!Y0e_qzWWir~q4|bj25fY5najFrs^;yo(H}qKrfO42JGOuTM36RO&DoKCO$a>Xq zaiV>$BP;JFGVqZK&q3fT&tAa(x0=tJ@uBzVEA)it_+uWckIlL!yZ=zz`M|B&j9uvH*l30vcq{qzA zbZDWH4ldz=U!c1)EZvFiD7-gUm2Qp-`7!^`Ugz?L+^k0^>0zV{*0;rw2JzZ2Pn$8eiMHiI+d(n zrXQLfI8A~I1@GpA&9njZNa)?ybFy2{VBNchXGgc57G2NI0L{oW8NvDqm)w`at(_0M z1~)SI1uwJsJX!Q&O#MJ{rPR7(%!=U+b(fm|%0vFq}jbVJx5JB}Jx3~^dn`=rJpbM*v^sSo2Hq$y!0Wi9q{ zt-j~n=o*>{Cqx_HPtiBXPjvF%?D?<7mX};NJFnwJUq7m=OKarl@A1akIW9VZ{dSNbTF2ji`OrXYN=|;_y@qqd$cc?E^Kz&^M+5D-u$HMwMjjrIU zzbht48rdfdb3=Mw$XkE+CRe8i$usN162D~6I~W>z&-J?n25a9H|KBkY|Nlwze}m8e zv%Y%9DL*@N*Q@6ZUG`GV*_(d!WBRB8{Qr+i{zq-q`TzO<%lzN6@4KPzi9efwzQsRl z`X1}kclWQn{_w_=UTB*)bmcZpcSlZp^p}D3{qXA*^iBR{9Qt1WhyTm;jqWo={WAR5 z|7HEMG)H>2>|I^IWYHaFh(!I;JdS=D(E24BP@mB+jX;_DB~<_RSUy(DkJM{Mzx0tb z<@)7}w5u*s8C`zT`n=xzU#9mKer%$L%;a~yhSG`%x>Rra5ucLw#5 z-l>D%9$TlsQ?06Y4ZWizO*y?^|78iitHzi0`9HI<6TA1v71pm0>KC>xk*k3HCJbDL zD~w+o;Q!xdby8cI{~vGB^TT_F%l-3#Jyp#?c1h@<^JjLYVeNid#$NhNMA}g~A1->5 znYc)VT6BFC{fPY!8ioq!9a!L~_s^R(6%+dVAUd)RbFSYl=yUJdi!B|^C~5Nax#iZX z^hp@{yt8!$efF3FefmcO>C@=aN7oljpE$l0`uw)f&_{ni5q<6@eU@Xx0z(-6w?>zD z=_GXRojZ>Ie8G<`t%CjM>?_*7ZA81;e}4MDhyR+s=@Hns=O4K3z;92x{pmpacGN2s z_O0%3)Inu?R~!HNuBZPm+qcYaia&znI?#XafAxP^-(K~s=vxhU1s_7p2hkm_eG7F| z_n&i`w==scI=J;2eH#bL)VHx&(6{m+H)^=;Q3CHl6btUOztn4iD@g9-S# z|L>Zg`!L+QyYXQlJoM6ktoXr4PW7;(pg7kU-^TtsbE z`T6Ci{x9=$-7cyhP5t7>I*w+~c(IA%&kq~YnR`7l+DcSDwJ-t8hu7Dkz`rC_fGG1ub z?Ay2e7?LZ~FXXzoc9a13Yn(~>w3nqlahzp;PS}mp=6C#lshDpr0N;k80flPbJMHbTp2y3*e|)^& z{;`^W94`BAVt6jRWgK`q-yl3A2A;<@8+e+_+9{{=IT{{AH}VlL!>_xzD#5bQ*4G=o zV)!ONZ&FW1R^GzOpp#nPEOA~WbB2c=ApF;Lf1X2@Q-k)aH2b9PAsZ=fm>X4#dXaRb zwk(T!FW;~USxB;TOw9WboYLU=M=)t!2?%p3z1*9u{RU^ODR9?^!qoWhQXr!2+NAlf z@Yeqj|D6SA!t&qu;6zsCzy1;s{+IdhXTH0keIOWw_r!lOplA3mwmFFZ&igOh`NDrU zJu(IUYZmHN@L$~~Vav(#-+@l2Y0qdX2{I7n}Rc-pp4Z!65n#WWcbirGP-TTT^N~&dhWseMgM$Vjb zs>EM7jw&tmFC`;NIa4u9Ea`a6BbjnWKN!8tC4@)-l_iN$?EifR59C55327G)&|<2v zooe4L&);_c<1O1Crn<IUlliHD{sj)o5s|9+JG*vr`1G1y74b2kyyX{WFldl z;voNZID}@j0-H}?{RDS|^lrX{rji5_Srhb{X`sjaUB_d1I=bL{5TV+VG@n&VHe5Su>A>i9MKw7 z`7%(>@S@F*$yvSxTK)VYHxH&FA9_bUdX|rz)w}pgFPp|f0d%30+QZ(2e_NyBG;uFu zH_ZNVfYS~O4+NYxrzan0n}7^^HtRE;$-h|Wvfle+jb+>zaFwR;mvvXrSFelu61uwB zIR<`}fG#|ftN5NbIPE;>xhFijMlhXoVlfh zMD?S=cU*X)p|i{3c^f;qy72sX!(`zJTCe59liEh{3zdwK4Pwag6=4N_)_xyN{6?~% zKS>YUZI1h@2mQzyPx@>ytRKBBW2~Oy{GJWi#8=i>dU2f2sBxkCPRF$FWJuHSIiAa9 z#(D5tWc;u*(#u}{4Sms5Z85>a;AU4+SpSE1A*gVBT)ZvSmA5FFKzqg!@Yzvz#x4j?dx+Z&18|$9FS90vJdH1{;9?hpu z#~2$NqQkjC`C=o?Cp@%7C2g3SuipYRP~-IxorsogM9L^+r3M~S4seZlOHMO+V}ya1 zq08Np@6hvn!_ZXkd|kkSEg(*8tN>csFSqvS3c z56*#RP?2zEsPLe#nd%58&l+HJDFGH6OYo~QM9e#E=&yE8e+{X_XCjJo-VR)m0z9~gtYlAw1;XXbFj;<~n2gYaCXyyHi)Q(zaow$m{qOXy43 z>phFh2z~IWme2_cbSHjQzztTgaTkWMDndM&j0SHcD4WjEw`gdH4zM%~frj2ouUh&s z0AuJ!{lLqipZFbL0zfw5MuyqJ_M4miEQ(7XcT89G%M-wY_J+7DPe+2-iwCW-ZeAR% z5(=fqyQeEXvJ0LXmo z#0cioObq0=f3wsOmDy}mW>~|)ws}#$XX}mUJt+s zr2vL=9)*|NdfO1=t44$U?lX*|4bDXH3BA^p z!FLkiOAkzzUdFV^-{xsbZWzlf=R-XY!TkBi%4_if`YOL}o3lgdo1<{(of8(kThE_q zC{#xZeS3%$nuGYZuD=UUd0Bbr^0$Xj`=8a_|0T|VSU zZya3kZUI4j5;g1kScl;;R$Z=FWdHS!ncy3GtIww_Ip~0R-}p7=poAVQ%gd2Z>#wTy z{2dMF0IpJhHC-@lk{#PgRiOVj^rU>o(R}(f7!q&KR<)WG=arXz&)y~;I_|WzGCulp zukT+~#7Cpso{e~9LK)S(_vycycw}Q)I|eSJ_kNGa4$~m(%f6c!o>Rtyr%&K%Ht^i` z7X#18JHd1^@XXin43>R2F+2}lJ`R22+mSvg1J9lop2o6v%IWi~Zz}ps%HK|*6-i+6 z{q4f3D&A(8!|)fZEA}~pzx`51SYlH37b@!yEv{1k5ZBq^`Z}Cn)zU6kJ0_0$%#0-o zn=^h8`^NQ>h34%`^gm;_JL`QtjLcblz~}4mxf&|lgOS?z!k8nfVWeNzpb25i0Xluk zLeyJ+m4$Fp@P&4m5`6XeJP5wnWa0Y^wi?kY$jo1AbX@w${08Zl4@C@ohzYN-f%jz) zI9Cs{4(f@l4_}nQThg2Ki#zb$TS32z5SnPm*-$vistYGo90nMnZ%yA?I-~wRzkY`E zWwr7e3O}y!u_^*@${F9mtZ%R1Tq?H{%i|||#*xPiDAO>MG4lA07p;ESRN4;VC$Aa( za3GkNAP<&(H!(av>>dZ6#wg(loh5^ky!Xxv2A;;UcFN)T7FbsFr~b~!1utAe!*O!HFL^gz=lpOR z&Z*@XCvhRhkR0Qj&L7%(y-dZUqAdk~zY=8!TXlOb9+XAn_kIqI+4$+fB?w_~BW-p7 zD>F*L{A3E;o6bda1mKJC^|Z^zP>LF^z#l0T6`nzQa4&r5HY+i>LSjb_57hP`1@Dzx ztz~Du=}s*(T3k75l#6`A%ivQP$5?r(&nIPZjD+Hkg7^F%6@O^qK_fQ&+M^~0;z`?Xhe9H89WaSDXiRR+(2aowaGuaGV z)3{!9&mFKproXMeDBbViFqg;VEYf`I``FE3ErLtOFP~!|3aigsK&eptl=RF(OdRH^C7acv&5LwKhF zUZ=lgY#kJTQsaSd5LuVaHq6bYJ|Koq#~v2NB<|I-fP+h(&)2@RlpzW~ooRW?@PiAt zobQzH2E2B>Y6byVk&Rs`gd4;f9R!jPU`q#6A3zKx0G5ic!3mf<>kV(i=WKkQyugdP zhZown+tz*DkE1M#u{&}(O*?dj9Jr@CCZ{_*^9M^n4uS+8W8X~u&<7(jp1KKNl+kY_ z_d%C_a%LuJn8j>*4x6%(jw7Vwg_e#o*y_K1rX9N(yj?tmj=79_6L{q_bqBJFD;xB0I=qVG-^xv`AzGwDN8QK;Z81$d$hW&FM!Xkl<7T^xHT`6NqGPrhz948)u8wj@S! z&*!Y`5W_p~t8gW(el_$3|Jr!nlN3(;3sd*x2Y|G-gPhEwI^bfxbf3nZGcQvg zizmA>;mDmlmN1mq6&j|uW7-g7J8}m0;;^)C;J@D^M^$3aI?NZ% z%H$9G(KOiJ`|2WhZjB0yDXH*lI6iZut`o;X^58+v9wQQR-<|3_%zMl0CtO@R*?YWh z2h-h8phYyZVOC~d&(ryaKGl-SfJK()ruk>U0KO6f6z$l}R5l|7PQwJDC!3}T2EjSx zh-EuoY>0a*d3 z>?5n&IM&8~W~((5TKLqtqF@(PBc}~7n$f-cj%+wNc5kxhVN$o}wb5@m=TEasYIbY~bP(N|9A$s@{)3T&rDl#1~`pMQqi%u;_iFT<0B)nlN4-d8KsxVd^i- z+lZ{Z9*7Y4@LsC1(%g;6>KpLh(jb8w?|>i7L{r5rA}ha*TOe-duAT+7vKiBG4MVCh zfofK*j;Suab7~*tqnv0NZiXl%l6OKLe1Lp{QX0`Th&~K!d<-6>JAeCmAd!_{2Fs>% zASwy$opKw%bffp3_&l@@`MvymDHRj0{!!m9>PPaN`j)H@`<0;|)wL7u(j%xGq7SCz zqLvld2pqE~Dg`l1P?w~db$zCO3#Y%&ZVYn6*{B&HduU`I5(*VQgFy}Us}=5D@BQIa z6W5+XeWSO@tTM2#hq_ksHS)5;uUj*!g=fRuXeh=m7X>P@8Jt(2>eJtc%f2`HIy(~R zgen;IzP1=NMok04JhrCD>g`2+fDapWeKWLU>a<^Mm1>xZ!u8y9MPw;+R|Afk>g7Ti zl;d}4%a_gQDeubfLlx&dg>O0i!KTe-YWN{CUVpu?DEG$3-JoJvp5l(XVZ*S$^m$m4 zG4U>E-u;m8@|LX&ELcqJiSF!`sRYa*KqnOeD~As_&?PIhHtOu`li95ito)2+T(24yAThTq%!$n z`iT8@_ZV2aq7M2c&T|qYtG)}90$#`6{qcD{Z_VSPb}%fsmD}}=p95dg>WrZ*7REJKl24Nu|cgHA=iT|^hrr` zlkb>R9~0qG`lv~_PkNg^BYmlF#aDFfsEUgNt>^c&!U=r^?EnARyAtrYs_H+5LIV_L z*d#2{fksS0B}I{xbwV4M&_sf?8f^<PI+^DQ8!v}l;<((+t@x6PruQ%?^A`A(PuJNP zD#mZtHFsrLmu8nItR-0oJAfSeDMS1e9@L-I45`t1YKD}gM#)#)QWNSvug0XJ^OFBd zlpn*_)LTA)+Sh$8<_}*xQ+dzW&s;xGGvOSw?XQ?Jy`8LaXiMT5<^UY|4#~4!2}N%Y zYz}&J1Y6UKQS|8ZPg_=Z26hXB`+6nZ*lX>=kinYYqhb*yokOa^joYO;cioGTX5vXP-Dp8Oaqjk*tkhGds3^&8RfkOl^vNk`p^=i@!BVRr zC0T8el{bY31*Lrix>s;RS1!c6D&C>?8TEit>&oGTIpm0+F$~S$-OzK?fZco)>j_&6 zE`noX)S(3wS3>${bWA(|zC_vZ^776*3K{`;d1rY+Z8`d=u?q3R>hTBA*+~Du1U#Vh z=cacE*BQ^n$%&%XgCOY+gmbwl-QFMBESIfKHW$@vwD8@YH zM<+kCfI@hK336mTno6vE8i1^ock8VXp1`t_mN!l!l^Sqgwrm4jP@`mUg4yZrCnwG< z@0^QY$GyzI{!`tLP28=b?J0NL`I~TLQ(MU0iY-@$lU3@uRAgfjKu->Y^>?<4vLWR& zD%orayv^zBhe1d~*I&iyDo*!K&~Z!%rRH~G@+%Lg7?>qEN#<431W?iyVOVk4|3y&* z-mvIMkEr94lpjzY1FevsEq*yMPJpP|{s!-zd5`+UPUlRbJzE-uH!kwXPrbb`j`Vj! zbcCVzO<{cA>G&R2uaA$0dG~YPsqo+oiX+~RshjZy&BxG2&MkO3?kHCS7?sUy#GR{S zNWpFVB*MxojlX{vYDTyF`yj{vVq9YQgSu0Cpf&L(rt5sJ_5%q?2EX|*!jeg_ zAs-T9ruCbPbMTwROZMAdGF?99B|i)VC98CLl4DZom0wEssVXV(A)>|4yDjySee{w8 z6K^+8a5?>bI3N~}Q(QBi^Afg$Z2z_oev|x2*WVab$LRn!w_5wf@N^mS)cfEU139G# zF)E6Hq&$Wt@QV=^k+L|SlzuV1=y`=8F#@IQ=<&iSt}CeVBW{42hdVsCpq4hgDvd8( zW!)54``rKrd^i{^&V{WW?bN>T!W7z#(HCC&#Vw-S=)N%NHb40B!2i>!`1ex}WG&W5 ze_Q#!h@HUJaFfP+=vILf%atEhB3{!hHh!ahGrI!~gUrFFQnL>@rj(6cNbsSARjpQ$RGWbiJ z&sP4@ETqxtFL?%2{UzEJ)?4r|{H01WPjsH@bdGEf)f+xa`AH#qIs-1ilaVYXZi%NdVefp$$BUypC^o}LBi7dn?R9+lc-eX% z>P5w^(ir|Tc*QvF`D$4Y5iLe zW=~~*AKy88rR0Xk>}o3l%PcDPXMI-Dhk5Sg`GH{o0DP!=iUNE<-)2#ZyFHJ;Hf;`n z0ZHNJ!_|j3<--pAfGMk{&DMYMW1COC8nu3MD%wzsy&KSa`N&esvgN5J?*b%QJnOJT@7rGladAwOlu29pARe}plGs67jixuVjgN-02 zzA04fgKr{{uPA?ekYCA8Uosad`&ZrKOg0rkvSI9C+@$=&Ykl+Lgfl+-ir}1+wJ`iQ zfQ|*bUdPKJpx!OQ)EmK$b+n=^ z8U;w@{a8ZX5zSRp2dnye$>3FDo$Al4Wid=_;fqXsu^cHv7r-9J8YxWo?pg(J;6Nv z9=AE?#r~1?1h7LbVV>BHS4dBW1VrYPa8wAK2gM0A4bB==VlV5p(Kh?aP9o{)qkq4*8(v#k7zp{>LRamdfNtjw1CCeL>R0S%10lmG zWuqzKop5gtC?mJGz?#&?{2=0vfs3l2~azeT#xVkOp~}D+vhlc)5b>p=x+H1 z{>O*mVUNq*z8D`$0{eWMxNT%^k}2X2rig>|+?Ozw+)Ytk>hCHU#~UT@d{hDneigEf z{eUtZczwvq84Ox%>tF)ivSEh>+}_Lf8~#jq zdsPNIo=Jh4&#qVSZ*?-g`$Cv56;fY$gVc>IS)=5qeQ&^l%a$L6AVWTi-VoF$rj*Zw z8od%~^x8=%75S{p;NW=2&UuJ;82io+C)6>?#E}YlC33#(KT6ZO3UzR#yCMwv(Jz$fY(pFh36*<0zG4&9#nPHHQKFRFeZoBGCw zm=TJj9y((YVu4Zw02Q@mfmcde-h|HC2%Ym=JPmzQgilZ-RcX}7TWGGVX;UMF(7m`{ zeQ^C5AG#irj^<%vrULqEwjG3`SEZ`Zbw%Nfj)Qh{aC$lQ%Pc){MNKo3e({Tbk(?cw z+{ceuvKw=G4*k-!su9q}RZL%)oTt9E-oMVSEfAqSxQU;)gxOVz{9J6V8t>R4O2?M9 zY&xm#4)ANkn(@6S5vlA>>JgxUL)5!+oXu|_fCHR-k2m9x)2kXOryF-zaMo6o(=?zb zAnU1XG0*B*srWcg7b;M0G~X4c6VUR`nMZ2V<~_A@pWDIO1O8Gv(64fIfr>%MEaY}k z7-``MY7dbfo(=D)9#c5;ilHF}L~cKWIF%lfE4V`S@045VA9^BmY8HBep;ab5!SG5I zcYR)oZ>!e^b>H{6*=(Xg&gm#2RLI+uuY7YUi&TZy_j z0{GtgEMO1rezpoc4W3~sV4Gy#zZ$j*mZKgbTInFt81tJwu=9!4 z8#xhZ^!%pOPJc}B@5paTs_X$sVPB(GvXU>OF6U+Q3G-#Afkc_a(3BykonPcy8kH|A z5Xa9hw+#;LHS&6^p)|jXozeBSku<;4CYkf%WBPY!5V_2_Og(Pi-l~6{ju9Km2hHz2 zPbfQQ^rU$|&3xjr_aI-5`g!)pXOo|YUh|ne4+Kx;c?OC&3o5P^wAoM|Kj9|)0w_W^ zO45HShCAmvJteAc#uqH$7hMTcqCWJirbKaNupS?b2>fo?RCLk$f$%+EmGjD z<_$h6a%A*AL|!gOK34h1=fZJ?+Z*kvPW6w^#&5~>0R!HuTpXRhUzUY`{4A;$G8$&6 zyRGgYOPS>_U}qCuFL(Qx{o{sN+ra%|KDP>$Z7iZKTNcYJ@0vO8l#cPc!dcis3T8PU z5BIs!IuLGU_D}x}7Gdx?~HD`xY^q|ogGD$8xzM~%dcp1CAX(QkObj!Mw4<}wg353K8 zwTu@~93k}(HJRgu?{Ruu+2n4(&M>p*8@Y(leHW|w_)07>E1NP@#$~2mSHYo3WZ;Fj zk14ntJd=(w_=es@k6r$qQvfk~`8NZI4=H}go*vdSUKK$~>G|G|T7Il$sq~7@ z&4peUUx*whC?o0TPf2xeZ1{Cj<{0^~k`ie`n(vKCej2~J_ic0Nr@IjgPKmrZ#Y({|(CU8kXpdaIb0 zq6AXV$VgRJuVhhaZbDl%gSd_519RxQj;qqn6Iv_d8cUK>dqM&A4eBTy#y~D-UTW!V zvg=57TzN=Fhtt%($MaIZ_%}R0?5`94S=RZIwQnI`(xabeJVV$Fd?r8S%umGgJ>GND z=6fb@dA_7Dd-(5q4e-Z)s>Yie{NeQQw`@85)f%4c^F5V-C7$o`oSQb^6U;u}6HdtY zM3-jG56j*FK12HX-0)d+URr+GyE-NR_XY=okS?Zf#uvOJBg>foE6yJNTmA(2^Tq^! zG(G$er}9It@YnuC;XiwRs0J)?e(;{3mLEdd^FuU&A6yz9lNU&qcl+3vov?o*@Hu$@ zSmeuhL0W#8yyg7h*YIQkf72^~KYvW{yXL2bf5$~z%+HPY<;oAWz-62tiU1iuCFO%X z8nP_%!7dO%N@`^igL1w-A1ny{pIV2%o$gzA-I&ow;@siClsxN~nd3yBHCmUNXFUeL zrQ}(|m*wKcw^n75XT?dUnH|j!Ezi0ucr7uO*n&K3_#*1RF=wf=o91@rLRF?RFGGq_ z{pxY#C-X;1Oj?KzGPGZtkOHk`3N-ij1DV@zNNB%dZ0%3U)c)dvM)19(i#z0tvGuY7 z2~(NJ|1k1TY4&-@DvNteY8JQQ@?3=U^;yYTT!h-!!v#wek1=L(iy<1@CX0*uxsL~3 ztQFwKq-<{f6}gb496K!~WOF5fd#I=^oxoj`N}$DKN)rZawwyrOr3vSMD0z_F<;Ix{ z>4tWYiH`-j(B~ItII@K+vFgCi7VfvTvbT{7w-s4F)^g*AW0HN=aGy#CU4AFoLY>8Z zeQRZLegE5Zk=)@Qzlz+UM@MX&&ouG6Gk@s0gbci8`NKb;_>1|&?Qy}@jSIHp^M4bc zS;vE}mMr7J=(V}%=epDWH{!wQ!fhB2Vn?a`c=d{B#F!ApIjUwQhj=he`x#@xY}bF~MKdnil?+Er-9hJ=gi-Zs0OLUtA5y(##k8vY#(5(%h!j zylszX|2N~=?R4Kxcc}C2>jk-cKdNP8X1QgK>jg*63q6m@0a=fATWVhDIsAq?0n|%l z^B?!kK5PJt4{FW91u{#er>yP-rN%TxmG^Ds`&MtkN|5YA5&|wI`LC&!6RHG!F6!jQ z1bB5|n*)9zbfP^Qbt^xNWsC6Mj%@~b;;I+V&FDDmeJ%=6zmhc38v0Hy4ZL+U6OyhG z_sLkzwTPJ<*AJsUC2`)}-TpGBljUHIBJyF=%4$rCBtP@MOgWF?GzJeSy#=K!*)6d8 zFy`g2!=@Z+y;~*MyP@P=*1KV|3@+PCJqx4Sx>py8)YxkZc62Y^1v^ZsdX|Y;_ZNnW zisw>y=EnW_wh`Ylt!k$|v7Qk-4a;i4mN1?O$rD{Oci`GTO(E`;pqBvRah}hCWd_yO zq;x>E?wmakc5YOFkb0StT!FY9H6t8Q0w#vRUD;tGF@Xv=;zcz%gW^sHN?i`1aBC}5 z-y@*#i!qU=6}xCC1ndl=htLdJA#p^qvNcX&v%pmo_hhud?P9PYnOTb061%~D^Dq|m za^o2DqCQE6{NT1b<+{_T?o`tuf&Ug4a9`Jiq4JA(DN_Qw>O6lU^s+Y90D-fW)9~jF zC}8+d>NIkf*L>DeB$@~RcXQG1I~D2uY-*?-(<#n{caF(C*0gVt(#)>j??cMNRa&` zc?VUeH|zco77%Y+`!ywj)^$6ZU4jaq1Hb_C-v3pETYK= zJL{Kvx`?7J%U3`0?)Lg6wX^Q_JQXbG_B_=V=Bc*ld$-Hcb~%c0Kl&}o_imS??Q*nT zj<(Cu_Wd;j+s}!gBMX4H@2?4?$jFcM zd+Yh__T4{iS=|{pXUv0h#`1B_SRu|BD`M%g>}Jg)sfKv&S-9+fYTu#E^>1yp$l%M- zW%nEl+<7?$fHwSnXfyD(Jb4B301w6EnwLy*X^AqLFRPsxAbq~Rt%k7!x7WD8AduYz( zdB`}%hIfDwr!?|zfOnXRoy$|st|N!>++8#h@$Xy*SyR*14UecGfWaf`))RfU0%IG#0&)Q#%g+?D0v;#l?Bth%_L_yo|vriIk z2Y>nzL5sSuJ%?vAypNwF)>&HX@B9%fAN`$Ojq+!9HBOzY!Krf%I3X2)Vd_^ER~ zbLyO5oiM8oVaCyOatJd{t%D=TM*KXCjxAL}FIAyNs2d&FhxfIhw$b0T;otbq-TJ${ zL}w>!omKczVY58&v_J4fK_kGIa^gqimP5z!4N_5DTZW@P0`Od(F2@a2bb}Q`k`Yra=x+Z2 z&p4f!vOueZ7i9=D7+x^qY-GgQ!N?#;|6_@S7mZ7kOKfure74QHgd`2B&+SBYrkul5 zBMNl%b33^%p{!+DBi0f4h>~UDoh!x-%m|FX9p@#MwJhI3&K}|#0;qAGqjV)+sOUOP z4kkjWIijpn-H%P&t)lCjJCp;JC`PZ7uMRpGD}ln$Z1oqEHErm|&4RhOc@j4Z&*b6P z{N^;=$TuZrEh`!Yj%9BEfR_P|SAjDz0h}G#ygCob0n_W0!KT<7Xwuz$x*TE^`#V3h zpDZ6Xurqh_(dq*`bhj7E2LZ#~e4zTEe%S*btV_|mI@ioId^lc6uy?RWKWfBRIE%Xh zN32%CPQg|!ss+R2u+}Xxb}g$alR3Q*=NQ1o{S*DUn-`#{&)>9>ox7W#ct<`csCSkR zo7FFs>-o!O^~>#1Vn>Q=d72bV%DaAG5he!aq%44_U~O4od3j)&i$1aatEwC_g60CD^0O~5aVtCmJgbp z4j{-)8}8&U?IJvitKH4>pqm`+;OH2PasH~N?T zb!Y#$&Hk3_j&=v`kzNQ?(`+r{cZ;?BbF`2G?g?ZZWp?Fhf7tB4fSH z*28QaI;2?-lmApMbhvEOE^&V;wpno_Bh!v5 z^<=|TPc7%j5oPUO6@g+*H&xmTWRShp3uJO~w6dig#dVAKXU>g&Y0p7=oEj%lh0#KKzRx+ONWgWUprN`3(D8Htgu`I{aVhgO|Vx-CR9_4VA^1W+Ia!1k!c@TowS8 zkeXnm%ovyvb~WQ0BnOb&wt6Ml*u)gY0t7Idn4Vb3HXHfP*xEc_wW&hWA+)2Lb2mSu zKHP~v?)H9u$N|*d(Jc7LeZ#(ZF(L1P0nJ0gqXPN<*_B9oU~G$!j4AbxDe2L&%J0lH z*cq#`z%zERiIfCvbut4kmJni-N{PHErygulWcJDj9l2dBha*VJ$=&{lV-;%-$Z(~k zcL%EeAmRs`F9IKPDDl`s0s`DV(lY&ytq_N1(J9 zx;g}14R>sjcvGx^p*ICr4DMK}-tMtV-%fGIf-mRdj*UkHA5L7GYz}9S)gN<#O54I8 zV`>+ZEGaG+w!r!^c3V;hY=^A$E?DZsQbk}jyfVobpAMHt^2MhZuj~YqFaDCr7aswi zEXn^#>!RH!?$lXFA)!BlWM+4JQ$sBevkQBy<h})sMy^%UhNZ8k5rLxntV{ zIzRX^_LCn2TS5wyF5hvix;*bAKx<+k+*|u+QR7hIxkS{>|Cge|D__q=g_od#E#8kT z)$dK#-&JGP-_<|d7W$hL0E@ql%yOE{bA<%RqKX;JiYgvkF#9(Z%qs2sMVZjwq_pp0 z@u;FoaM_!p z(7PeBy1Z@S*rLPU+q2h#TOm695ah!+t1``;RL7EbUS(w}8H(S^g$z~UUA9%eTgSJ^ z360{2ACaULvQB<`5*UDWS4g#?xSNq|ht3u?`f6kTt0t4 zc{4-VSYQb0r97y3WK@{vTm;X&6d4uNrUz!{q5N~`{S_13ZFMgLF*ujcTu@AMdGuc_ zF7lN07hSr@Wi8ty&n4&g@h7+Wy{j~eMKue~C~H}nZ$xcc(mHgHzjJ0jmM3{-fk+g~ zZn(R(Kk&Lg@N7j_T|pG!M6I%=8;tnpqjj#{o*zU`QLer8U%%?l-Fz#)U^jz*5hSpA z4@MVbQy5wOVfKO7g?Q5XJ5)njJa(1>NiVm&F~N_tQr!#;qtFcFNr1gG+TDX-hdtk$CxeqER1L)zBelL)NUOiU#?s;m>c>t9jZxIsD@MN9uDLPD@v%vM-yof*IT90SJ zndsPSIzDbB{6!iC5ZNMJ!4N46tQHJjj!n9?0`;P8VlX{Dt0!IOver)oJ(qk&!G%q- z<#NCkmc>$kz}F6>xZ8X2MSA$o^a5Fhf~?BF+Q^#4z040Pz$@W~zfp}mQ`QA^f>sd# z9VV>~wP{7dTR!Ly1Gl}8TOyrGo$R*4NvCK?x=v;O(9r_}U4$A_s3H&|x*cdWB1{-yMW5Gu? z+B5hl&d`n%+&Dh+EC+ZRA1Cjc4jc7Z(k zG&~33H*5uMU)WjSh1yyp@9yTC&=Lk;q-EaSzJOmq(F{d|f$It&*4Gt8S@Ii0dB0Mb zRCsUG=|)n&K1M-8(i|#XE4`_Sg7m?ksPq~MMDHPqc%oc!EdIbyOBlK@HqPBTU4dk) z@khX)I}5vb&?n4^hk{J42OUU_lW#4$%SMqGtyyi-;|#Q``(q!x?EVtv_!ywTR(p?u zJ*B_MQXvNhZaR#V^heLrYIa&47$N?eyZu_2FuXc}phlJmXJ>eI^MpK(1Ln`DXRR)a z0AgRzVQ)LUiF&|>-^N$nV~{SFZyhl+XJ;{{lK{x@WDqM4KjpdpPHhKMuquyAZk3o> zpKfN)Kmw=gcF^JEu>=!r=YD zqwey~D?#N|dDgY?@{O^_-;jPEi6dL*;?@aIjQ0IgfG1Y;53=67XeY)IO$IDI8kR=g z4&UWv@YNSo+A&W%8P)nZ+8Lw6_&mq2_z~ri@0awygV(GNuHNW`m0+iXlkbBeijDa^ znT#;#e~F95At38_S4TR9$DOBcB2%Bc2K%Fvjq!U-{XV`x{&vkRSUa4s%Dm5Y&NZ|a zF~M5z!3y8(lNV?81n#cVkl4%5;gi4R?|J0`%O7|JciyR?$W=cB-@&u+w}srTd+-TR zH}pb1_yZoxn$pP7KQD2WPJODR_l)bWaXonmdi3{Ku6w>?|DUfotE~SgGmk!K|JUy! z!wvagJIR+47$U5!q{}{K4T+C+*|3x}+F3sur%~Q`m{)b(#9)Ym)BAs|SRMEnR z1Z^E}){sikovg=v5LT#pabR>U~H@MfGTA-OSJ=G+LHxIl(fzYSe@B$&+5H+ zp|C7~nZ1|b_fg3PR;+8Mfp9pW)t^@Q%}PE7Fit=CF-bleHNj|y^L2Zq5ii4+fF}=r zEwBx!Jl3OkY*3sQJ7_HQ{r=KX=-V6B^gSm|-@c>Xt$zNo-m0?xnLlja^G}~&e^FZc zUK~lGZ{GS5==;j^A7}b@AE@w~PL8$yi|dDs4BYV?gyKR24b zSpd3N?e!`8CO@g4?BxB%`$yr2fp;`NG{yO0zVGetzP;#g50v#UKJfMv&R_kJmjJ+v=vh(od5xe$9Ic%wdvOPg}+Z^#l`aI_<<5iocJ;5`4m`1b*b!-hDzG>L6pL5EUel9jh z)X0JimIV_-&z2W!9f*`FY@j zkC>kqi2ljfa69qHdmtt{MD$A@OYw8i)BRkDRQefwS7XS;ceG&B@PK|U9lm>rnq+*RiL7i~ zT?f1M`|0$m^r!W==+&A{DSDOhs~2$?11jpjsx)v5--&--jnP3}daQkK(NOp=+|z(A zI+=Zn-Wy&4yBZ8urTJap!Wl_?AiAf*Q#!exgtm%Lqj&|W7C<3sWx`+NfPblO z&q+tNP5s~U7DDb#J1#gJ|Bqj=mp`x?S&WnPh^7ZO49hoz=9{Vfre)I(`pF*i{r=|3 zp!sG3zR@(P9AP|yN3ExJxB+_VC#d0c(2}>rje(ticf~(mPXFd8`e4G4=MCt9cBg5( zfiNp2*&C}lc)rVjUdT8(8|dJ~9U4-4{#g6D;Mg4dsq`rNPQ(~EHgh@hZ;UV8&3EG$ z#~|J9H{uKBY_8XXto^$2INq0>(3X;#;l93 z26aro#vkZAXSMvyh?#tEu5`aUkk=Q~ye8dO{x{xzai;FyZm^jH^hG@}V(&$W!RzzN zJK=!90kzJCx1#fcPWm&1$8t5fAO{LhbHNoHZlUW^zKm3)OgQc5Kkq4QKIca6Ym)!G zSIasdtwB@%&g=92fy+H*oxg3s$BM2Q1xSRPnx}4#faiF9P5G2H{=oG$!c(lDLz?8J zsm~MTWr5Jt5XzAv7f#oRmpsaPf8d?608)W3^C2V+kWje~#Tb%MA!j;&m^eedS{7JU z*4d_D@&f}GdCI$f6T;9mayiJd&Mrdf?>r-~yz5+yY^wjfvLY#volz04{{u-?0^#}YliTrK-bPehn*d8xKPX}u)d|rsBq-2FHB|s*bK`BC4X!k_@ z%}_w(x2rTlKXoA;rKs8385yHq(t~qeEvq6-#vRP5CZDT8w^mWWdITQV-{A+h} zgW{iX?GAu9ut_bts8^GbYWm0BwjZ8J%v_(anwe|lk(W+Xcroo0zZ?(nYv-v~6Ti_~ zAVj5$aioGqt|m6;dw@SzWE^3b?Xlip1sg2w`*r&(*eEWxFZP5<+|CMc&TOnNkIxDI zl6{3E6h36ckfJYVS}Z=tmEVCrs21Mn4>{FBzV+4m4Z~BxRg-{mUOaPl4%i1y{suS23=Illp%hnJ4O6d(*BxycCx?7Krz z9*0?rjmCxUhT_DgB(Ab4uW)IO+Rvo|X+oLI9kOnLECf$s2e=&aRclY3tiulya5%Ms2j#KZ{r?{|-gK@NVKIQR-U#g?NfOb2VXfDV zeAiBh>)R3K`yDhz`EHotkZ&0KRQV1=4??~@ndJK-=vxh61K}$HeCg!9!Q|VXPlG3s zb>b!H0pn4^y7_5ow|qj;4oMZ_yhV^d4v=VrlzhgqwWcgvkvegSheXCW@Ov-o%VQV8lRlhVXqMR3hnM_R|nsxwQH_X?AmW2UrxR+`|TF-eI*zs&i7&YwDtIYa1_2*-UQ=~^!|j^0yi4` zkN<5M7%|>hG7-FH;*GAEn8Ze~vE!b0ywRn6`z!MOfo~z+c$A(z{Vs$9*XOC5BTn>p zUQy$pf~}MA$IQvTsDcfDU=8Ak|9&|hY4`&hB+?k7uVP0UyB)3~P`;lKY21CxHjgw; z>Z8y%l5fqG&TjsWicCl4nc|I6>2Qa#pRv3>GSVS{uy5;-;i{w4kReWk4;nWkGlJ>! zWEvc-$@d{gd*EAh8GQTCLt#g3xc;jGlbYr4e)T^BX5Y9bJCxD_PIXV0teV&itgz}K z{Gx|a+6@fBC9qwfkWETsi5%_^5@@b!ER10rH);ncI=r`OQsNl%!Qr3NUvoFNg1(Nx z#@${+f}_sJ3`hcP?rK)UmEN_Hy$UsrSi^83A8s3Vx4wrC2xGWvH>w|0E!owvP{X=9 zR_kE|MUpeunUXx~q#9HYwXB4z&uSu%b)kQp;cuTF2l|nVc;~$+dk2DM(YLRA+(r}V z;>46k(k+N1qnj08R;cF0-_-5F6`Ti`up*BzU`gM)I}?c(9duLGBL^6e5{js`@L?{6 zz@WoWQn?QLvE0RXu=VuuUyn>fhPXa%zczzDzNu)N)8L3lNCPd^>Ep=3OxnSbe_NWQ zM+Y{3SbFs7Lp5&G>(PiOca`$Nxruso5-K^hpWxBs*jjotv|;ReG=JYDJ$mE=T94L3 zx#X%xci^DaG=u2TXqI|(V4qy|=#pkQ=K3;>HhR56bF)q7DpWMfHcT>jkc`noA+x$xM z__D{}$(h^tn)ZL3(tgngia!}!=v1|IN&kmFZ`pa6wD-V2v!0&tUrdI{kN9tNdj6_0 z<9LeyW%^x#OIHF7sThk zm+JPC^|P+u{w&gysNrV)cD?wg)-xsJY-I$YHT{pyzwa!{INnAx-mkorjL&=xpR*tF zn|0pzIED)ewa(vm^dk$IOnn|SSETwt@m?a|`Dfr)2{6M)% zr*F_+P~xpOwEtFnuv50&ZQLvyxp_T3EX9G!s7Z?K=%4F2ahJ0RX@Y-a=Z&AGe`Atk zk_uyTOtNH5jun~Yn54^8%{!YiNoqXeV`3C@n^oX3P0rf#_^iRV=y!(8(o zrmZ_mi;)Q1S9wVbRJe|`aQ!|hB zPaANz@+bzhIOroyI_vXs9~!dQ8&*gLW)C3eGy#8sP2`@q%x2OxF=t?PyXjcxMltnZi)|00dCd^0F449*NwQ_K7e(Wbuu3G=m|~| z>~qab%=<50BN^Z#9n?vl{|APtK3C7b;&PVMkE;+3aC)XQ-sTX#vZG-y1A9Jj!0_Y- z-Hwq}gJE3ndHD$OmKp%)pl%yq7?O+eqS<@h)GLRSj0i$(x zaW3|(vM|4#@xE#~4 z6`r!LS!B91oD3oCwi-6*g9e+|T=`TglJmkEL~FLF2Mo4*T?RgoI*ys73siMRe*0d$ z2TxRn>)L}4Szf?^Yu6vmJvQa;;#m}ji2ZMq_(35C^MeDrs zNT|J&fTFW0#hqu-v(Fr}|tFs7-<`rVHpZh_TM->i)CS_fg9C#hf3{Y__wxE%T@ zUvj_4%{;PhHM6I93+lQ`Kc6g*G*W|~A)y@d;L&=TU5cLmslD#squWW5E5(-ydQg<0 z(SSQ%W%GQV>o9bPaxtLZ-F6MwVR&+HMBy)`UGSkFkCRG2q$8l88?S~f$!5}Rtsr^}GdLw#(BuIoc@B)rz6e*L@?zw$hAH7K}(Pe9>?UqC2+ooJaC-KqU{mu|-? zw`|9$9##FC6#lUA0ON%34nH_%Gu~b^ zr@of{mA-D&UDrz2^XN^w+p2{vmHx}u?>qeqc^~~p<)suqxc(lSXC&4ugX#(n{-46b zsg8O#wgY~#jg2rXxu}C-zJ%{GM|X;?=YLn7#Ai;UfPO6nSy}S`G#*FYwEj zuySCGf856Mz#5d^D(bctG@`eup>mw+)q%Tm93IRhLwVqif+hGHd3ZN9|3Z_lV@|Zk zI!MSKn&(|uN*j3>VOBRDa`OACvcN>fc%B|eYOFH8r&3OBCbe?cglcE*Ksa+OW`dI{#`|f3!k~$E*G8@J6@xocj|Ycm+kX| zml-DpC=*!29N;?UnJ|{DdFC3pIs26bo)X9S15ChC53VU4YCu=a%%-tZ!ZJrIsW92r zU@%X^0o2OHJcsD#jO*YIzf=o&TPQiN{D#uIQR~M0)y^BklXbIM|^x&%!17AyS}CK#m}xxZr{+yvHy=+ulaj)3XI2dG{_XxenA8s93y)HMZhCr zK|8nZvxSXw@z$SiquBd!t1jvrUJko>IAqSAh{ql?YA=kK)NDdMGiAc{oSZ~*K6x8e z4W%RPlg5aJKMzpjMyz94Dy`=So&H)9JS*e7Rv=yoD}FcniawLrXT>+}<~#8Pz^bu} zWLr2oC&J=|kdUk^;e}sY1jH2+^zKH0N73zJMNu!m3aN3=)djM$y8tFE=W@-QptFb(K9NaI(*ht*k`%hp9K2!H6pbd0`$g&+K z;ZvQmdJh|=U`r&R7jP@$43Ich->sZul7d+u+U@H$85$*n-LES=ay^srk#KAGkNk+# zw;l}CMT(0^H0E=ode4Cf?U(F>p_{GJ?HRsx_?cRdywdU}3X(UDtNRpAiv!X>rL_mQ zQ#lcKMtzImSab@%EyTA*W8~@f2_rAcorCTRQrFFHyfC9&AJQxdov8IS>~uqFz^{Bw z;X@kN?T@UFZqMBQIi~&hu}zF>zb5DQkImfv8>ap5+wD{T8{BgY+Ke*KCGkY_JYWm7 zj75)9ni@WUsEEDsePSL~>;%Wo%hnItZ>{^Ikz_v`Qpv-pPG80BN|DkN>2)DKZC1@V z+M%zMCf~Z-#fn@e-~cDPCh#3E*HRoVv#W^zd8Ll@Ms4g zg|9~*eo*^S8q7GHVEX}ij{Xbn-$?n#`lUc&HxjY-v|^^X(3%N+!|yWlChV7VqYdT- zxwrRW+Z!5ncmK52i>|`AIJ)CqYTWqDFZ-f~3g_jqwtki_kd-LfiT%>#H25?Ec|(eX|)pF8RJEcsNhz&qbU}zx+eb^Nn8P4?B>(A-;798}c?s$k_)n3Sl%3ljxHmBa z=|Fj+9|FELuG7K`NY3uimzA{i$R42lN?ankB5KW$a*1ZpC7MB(h~5cxOXUoZ-rmZM z4Bo9=6u3p$JraxQtyAjkS{6D+eXbg#LTfaf5MsILyh`5B_<3~e0Ic6QNtZxa;!d&N zU{E`6Gtxr}Aj9kT29P$ixQSMiV{wzPKUUnAn|!+svL7JOy30Jxiwdvl>@a;)hiY25 zADfSM6cev%PpPOi@!Ph$CX(i{F`=ZULASr{@zFRkKK8yXEj~hj%oQI?raAHPAJlL< zHIFw5A5J^~z4UX$Up*v&4WK{6$BMCM(j#K+j6G&ZvDAIQ#Ap72X!Az4myVA7-bu%O zg^u0mz@}r|LJJj(Y^eDzuhI40$@4PmyP(l`KYlD(->KHKY5&c+8QbqR?Vq>>?Kfv` zzsI!y+M~(v_r8#;|9wE_e!9W3AZXM&alY}tDTDO0%;oSOq;5sl@ztJSvKX}XvhM-* z!_jOg;q#9mrs7wY=!T463cj#o=4btC{Z5|W{b0VR654&UCWnRWEYI!>Yvz#l3_qLp zz{V~wz+q7B%(wmkIYVBfji;7!;5%`&@%%oJ(|C>;VK`Ae9F-SLH=gL0j>mJ-Xyf@W z)J6{UQR}PpGD~jpIk&(jkLx03i!zTV1oUR25A}z^0a?YtZ`@x%*0skP^mtS(R=+p% z#`-dR;N+_>N@rNKz6ZXI>Z}MVhHMt|e*p8VTu8HA!pXehc5JTg(Zf<^#r}UZc)tOD ziWT}4{zrgUgSaTa?+qn{OcV93jo)L@eciwMmc_s5^QMES=efB3NX8>S_eIfymIWDv zemS4F*?ZPTyQ$N zc*f>;GgkAQ`90mZ2s7-S=r8V>7cD$FMLsUK^%o72HTy;_A7;D`J~N@yLaD2YN{q;P z8Drcq4h)I`9p3LT+$y_%n-Ahzzj}TCTyb*`H|@F673%G$o{!^8j*J0 z*=ko4d?nZD{JF#IjP~7ixz0DA^*}OzHfT7^*lF!}Z}^LOK$|Z8-H;+pkEnHpUm01^ zyG6Pk!@ta5JKAwKH{%Q7(DvJfaczR@AdGko#fVEVpe$n;5_ZJb;VaNL6?KTeskO`I zw^)<@?Gm=s^JVveGotnl?1^yeKQTR9M2FjTO-UXKfR(k^K>rNy<({W~mNp~;d z9rVp0ynrwbV7CZhc*sORNX9%XfPFCzSTXuG@kID(1sC%|1~%LZKXTOv=%VTbP)`b_ zezCSy!5;lyDIdl~e&U!QmtL9A>70#>H;Ozu7wLVPumSdid;ktd;VF={N`e}A*80v& z8)H8Gdo6yq7A%r|ymIfSZYBm?#5He{$x?RJHDWumJ`M2B2E3>P#?~|}mU|LWxS2R(EnyJw3^FfV;SL)~P$Ve^crX)J(e}Q(^?W9)I!{5q z8u`gJrQy)2)M2R3;WD$5eqS}b%D}t`ro@m2mxNH*dg8hbQfE>8l%iKFP{qrEccv&= z1{DjHYV;y)>O~7|jVdi>9d_D=VTF(AfNn<%kfR;Y&&N_tSFyl_O|>*cUhB(%LcQOk z-^WUrWH^9B1xI7j`}CD#);rfa_fN_c|A6nrf02E$ef|W00QD1nUd@TB_jvx;q;=^I z&|Vj5ILX@@RC&eZA)dS&siywg{lM4#m8cuHF8N!+{@ot^emXdv`uYSSKEEsh&Y7Hd zU!(Bsgp+XeRbv3aN1pY{N_a~?J)Gdu49}Au5uic*p7TOwoj+3Rv!NFP7h!$2?6kyb zU2yLiC^6*C5m?PV6YH}v(~Cc<@YpQQ<|a?o8zumRm4#~R`eo-&_wA#VyUc38%(-j4 z;NGZSa4rX~0=X~2=1+Ygj7pmy4i*rq&7Wps^QUuS{?5Jq=gq<9Pj6xKr)MZ$<1qj7 zsM`E#EhGV(KjG`D8cjFjFm|t2_%rx7G-OTFN%#jo2}%9;xu6D+6pd5}l6IC^Vi6w3 zSMIh>{0@55==N3;MqK23wjH0BbhoZUCnTq5rZlw&H1EzLMqpp&@-IOpGBQel$8l@YXale3BYX~$?(}qa4sBNX%^}N8~DmBhF-JlIuT%Ri4 zgj(N@gZ9MhUjOiN?s60WdEZ(0JzZC`+VMU>a*V5vWjwLM^0Z@exBVOsOMPz<)Hk|P zwW_Pf9|cfR*P^P+4bUO~p68LVXu;C(Jc)`vBf653v=g?`b;; zB%|ixxS12`XX6f4%`@HgGl|wBuyCJ`>;se%2-H>g=yvol1P{V*=syGwOX~kK=wGF8 z3$6Wens~5Azi<2{;!*57MMm+2u1k8k&y{ZfQSNyqljv9#KLh)#q-js&5%AOke(r}E zUb}HPvRsYd3AcVO7Q%Dz?ohivk3)@Fr_QF4Yb1S#^m`;b-!*XWrawdOB@cH55EfbT z6=7<70M*6hNWF$Y3)+bac)EqW3?FIsRb`_2R_TDIo9WLyCwf;;0oI~BDS*UA1N+De zK38Eb@cK{RTJU}kd*cZ`MuOLi?hL%=%L~}YZkeJ>R``u=HF*DG_MICE-a!YvkH`x? z*FY!-c$ZdgE&Lvx4ZMx$&fs^vhBrSKc&pCXTJW}EcxTBAK3C0?Ip8<% zt6K}+Kf?JL72dD|-h1T*pKD2f9A5Ggb?Q0zXX2ISH^AA@4TDQ&3#>YXIup(Jn$yR})hW1RxqqvDQ% zC-nFn@bK0-uBm<$m3rN+Psk+tjDl!H^nu#N3ZAGc|CQNdJyb{9#5(lKgc%`gFMf7l zO)a)4&ZWuc7Nl#UL$qp^P%TCi#N$Ap9zThI%jUbz>BB7z|Jl>sx(L5G;r)$Jc}Ps; z2%TxWTVvYSMG*1!S+B_&&DmbictZU*43+9nCl^M)Mn0dHZ}lxqKp%gLK?JRPF5>`P zd8U1b+{F0_VXB1Oc8c&(0lpBxYZjd-$#cV^GRG$Rqv!GTd=ZyNck7qQO@OC(mdGTI z9>m%hBa(fx3?x{SMLSbCSfQZ&qTxM4`h=kzL94M;_CzW89)I2#-=xa9?JA z7ODxQX%$`@uF2>O{_m3CsPR$HY1S9|GmagGLuKo|i}5Q485x)ZB_BY3@KA)7eN!22 zibo_{ZAYwMT&VcTv@4C_KO^7q`1IJvsPDYGf2Z9Z29M}HxZTa~<7J8#_u_Up&r?u% zI=&86V;;)hD;VKo;1Yb4;IOQ#obl>R#H+kHVmFBcr$`*gr~?Z&R8Wf8^WnGS!Rl}R zgU+1c>iavT3siTTzZ_(tjH*kcNwRcbiGPs3_lUg!^)UdgdRk1RsO zbLE8kZ~2eA)?Hr%*z!Ao6^6;|qb{z6S^hxKecuGq=3b=69UQSAS@UKGu}S$nJ0*N4 zl}o4y(G!)6Dl+lG*6QS{RM*eq_QQ2Fj>k)(?Q)upL7ENgqVtissnm%Zmxjm4Ch5sT zO8|Iuh~tv^RdxPGPrCC4UR845`>4WSns!`+Kmg;aj+Gllk5xg$K@;j2uUS9Wpx<}W zQ^OIKi_opQ{n6f_mS>-BvIo9GG7z19{8^6Z+Yu_b5GCYgP8+-*O>(+U2p_34W#-pDVQ%jiX?N2BHq zt1$B?X?8PjNT)z%fnArXSqkdMybR+2IIetv(|^W|oQ8PK+HoiD>Es&vRr+!B`5J-` z`LP~cG2Rpz_9i{gc{9yl8R+r!v^d>U=uvcb0zD4C)zG6dsh?zeJkg@)QKX;CiXMg4 zqtT(D7MtDAk=Y<}VmfQ58e`ItQd5C<-%gCWj z14i_?<9jgFC(U1fPu!!d_%QSQwbwCjBO8XF#m=w6I!}O-G=F{3j*j{3+8%|k@fd?? zgX7`2_!%x9=9I46!+!#;>s$Ez!82Rl|IBX=TnInjHSwy zj-FJ0+?DP{evZ4xcP=OM>oB{FPXlV+Q1;57q35Aliol7(r_llu6hc*1lV7FqfIwEQ zgX*a{M`^;4xG`*1O=b7udwz1xP0mn@iDdU}EIv|*e+Nj{_CH^b2YpDKk<2gO062DZ zR+2ANlD_js)P(L_#=-=3duTRK0oS9&Zh=JxHze7Kb_rERp>rbBabgkUR zaLmd8M`)?S2btf*bd){gA3N-WyZuODtbE%0?!~v^3IDVY7M)f;?St#4iNUC@83V($ ztX$ehLqelUt5bEMX#{2gMJm^6OEILs&&pB&u6NcpG^!&Pg%e!jF*)C8o8mDyR+WXf}1cVB+nn`1omk>C$U}b~F`G1E2>8nj7a-;6gIezwO z`h%Yo_$t{lZzqYn1>cDPH@{dyaxO?>(vVNZKdG zYo0!^^{{{1kTYU)O&sTn-L2lwq_1*~*Ouz`2m{+pj@PQe;I=^ela!&vYm;qIRm9dY zO2l^TZnkX2JwBIro5S&|UDLr4yepMHBl>$fUW;CCj8!gHPPRoziP!Sc7Bg3&qHYb12@92Nq@YgGO>F64|GmeLC1IJg>!cnZ@*jn-%`SG?M z*EJK;;kSC5!|~3}>EIarQI7Jfre1pX*y{Ucecz<=w9EpGkj?HD2qvZCmsC zQ9GpLFRzBf8Lx1xBgbp`4e2#bExzBfcrCa@;bjZrHP_VyE>pbbNhETS?$0@X>b|t` zn(rDNubmagrNnFRS8R=V&6^0CuwnNP6g~)Fy7*O1udcVtQvUS#t_UfyhN3N0{~7*> ze_Sf@cm4ed&!C~Y-LMZu2WG%etlc;)D^w8cDz4|)c`**-W#(m4=ZnAd>3Ce2G+$h6 z=8OM%Rq}js)qKVuhHRu{-BKT2MzpRNP%Cq zo=y7;GPmDt+JCk_89&*#zgOn=L#F+2rL<4k=08IPgZG4Wj;Kk+oC)UMuoDpRyRJ-G z#TjaCifMzen!S9HoWd?=Z^caA2j`oT`IXNjyff?97M5bBux^&9{qS{^S)9&F?Gffz zk-|mzstYE8QHk18a>*|-Ift*XKe?WvlN?Qav$yKYl?F#Ip^|<%V2}P#wrS6?9zg0xP6sIVAqdAX;RQ^& zWq`H6u9vV&784u3F0`eGt39A7qC3mfR00ZYTdPT(kqk9ppsqL-~Dvz#_@PM&b!OWMNq+c1{W`GMi(jYwR^On; z5Ba0}7KInmgctj>>4SOxY5^ZhK-F^V(uVP>&ZS1bXZSf;KIEJmdw!m0q-gnA_ZcEH z=+*D1<2UZPXyfr+ejw8~C-a-T?HG_Ik>@^riq5AE1l71&@H($_c$EE>2lJW)kNF0V zg3!_MsCI;go~zdV7(B2af#2SrxNZu-k2Ml})S#gb4fV*=_W(1nwvOxbV0w|-?YwL} z7EcAlP~~HxXjl`;B=5=Ds4I!yoPl1b^I0k*sRtvxX5DcW3FUKz^z%;nPlE49gwG@J zu_kzqf(KWZGfhjA9`{&vAMl#xO#6&q)yQ}Pe1SELtBm=dX}_~uvdA1by`+*q5s~l%zRek z=>JRTU-ax-+!6?ktMhve`hBPT+3-NGERm7xV@bK9k-Me4+bV?HNdFPuU)LY+5e1}D zcbBK1KbgeCW%Em14rLu_gv23PlKEWKtM>_yC_O3d_AFL-NNJZPSgK-sPI2!_Sz0h8RQe3wB1gGewcwGDc*WOa)KTta%PAb-W3B8$G4*)`qP7d^Wnxwk z-R6bcIpM`QY_4?%dt0~T$@#$%+U<3=dnukaZ54MUxAhhNs;a7(@Ii;JNGHdMg)HwJ zoAO(Y`Rzsgru@>(aJXAP2Uc~$5?&mKC6ofoa{M~dxZJIOV!@OHXF*4Mo07L3~7 z;-vO`j`pfk+BS#UP~pTF=M&Ub$re>VzRP#;va zE4(Gct-zFZ5&#oxGJqDJ>`{Qz56TOC>%L8?N$B|nSatMS;%@%Ax;q6sqTtR60XFP6 z(0>aM%nuITIL7{4fvR1vI}#lhxtl+w20hK){zOuT4s`uj9@?DeZo5xCju#iHyJOt# zlX2&S)bZj<`AMQ$Y5~i8+%6;NEqCjzO^I@tht2J10H{8eKuv0Wg|o@5e{^U+dazC5 zp;fpi?ngWHVF>TXdcgDIOeF3(;cmMXK*E2_q~Ad)+kPEP`^B+p+Xdz_HS(tTwevGBigNS2W3m*DDag^CKPw^t9=S!;%UV;un_c3+A%AL zGlVoyh3H!1noQ#qk#gicYFjmbX}FEw=Ew^S$^IaJ#xDRn(tV2{SkeLroYgiVYFmyL z*^rmA#)K@<4oETzhSHgyM$b#3Ms-;|%?8tYqMRvO6gE7KFoKdEX`_|k4z z9AD5?jo?Y;>T=y}sYg7wO=uc=#;e~m@?_&V9tV7f`l?2Wla2#;s3OoVhbl@qjwb8B z%k{4VjS3FqZz}4=^ZwusTYnuOx~mfG%$%q?(hZ-?&cbJeC!AC06RZS{4m(U0Mp zdm%CqtjI0!LD-p6RZICb)DyP0KS);nAtGL39nxYugj!9-<_GiixHLPuXh3)mf1m4r z+|763LxNB>^4BE&DLh#99V$p{83rxoyOj_?OP2H#G;njodRdq?PV}pxbb@G1F4BjW zqpO9oA7QMQNnCA}?ekRPKCcQKGR6&PZzQ}mWq~)VDGlBRuUGuA74Q}$t~A~nzH8%+ zpb6gYN)ncmFMbGkGjc+^!^@`st^5Fr`oCv{O%{Qs+MW7xEFEWLXEFdV16)o0jRkw- z|I6!3BmlC1Y}r(GCDx&CI=#Md-CyPhP5*`uU`Leu*|Mo&!J~NY>IHW@wFCW?5#vR@ zK2l8mpoU!m%>)JaX5zUlI(}nPP3ap$Pa6(w#ZXi?WV+^q>^eAboua?7^MW+|XXXLH zcQwY{m{0NO9)NgIM3p6UfzbRkz~2T3gzR{TKF5&l)Q3g3%`C>+xS!vF0cD!lr~wpx z9-~{#cqrGrOdKyWa3(KX(!b}o!E9#9RP1`S5OqZSCe7arTsty8&@by)-Ocv`2!~L* z+dKFLkPz<**_X*K(}93>}?%Me1Nj z(koPteZjgk>e)VjX%u`Ove<#orHgXMXU8>LjL#?#7Pkq-OOo&zkuO9=R}51B3e0kf^eJ435mvqhd(h4aAkV(dY2aQf8&A&{bd9L0N-O0RsOS zcw}poyU1to>`uMfp0IAXO7Xdqj=VQ|e}AXzX6E9o)o`!rNX^gaf13Bjo_c?zXqU;J zijnt7{?x!>^f0$Jnw!R+nsJ)voq1o_+{|!sJ^Py7H=6w)n73vd$^7Tg|L*n&@IYD1 z=EK~r4-+*w*1fE0^FrWY;raO5TQ{k!>nuzpZ5qGuaFSD-3Pr4q;>D-?vT1WSTC11S zE>d4H(Kue$H8`xa0rgO9b4;1ulM;Krzv$>urJ_`iwvnUzAprnd)c)28c@;x9sn;0% zaay`zKU(EZ%}}_*C~Uh47D1{3K@lg=e+>`bth22f3!mNpnay&}Tb6v*ac5e1v-R6X z;F(Pm{vYLOJS!yDa1M zr?pQbe3PjWvyo$6y&ZILe#R>QtmxQSa6x7}#(BxIrj=p*(W=VbJ_*85wx+e95K-}x zJE*Z9DJW(x1K;`ZcL?8=b*bOW0<8sp{aYoUm-3lA3QG7L&UdZSzwun#N~nOct~(0O z(7)B_-)ix1_Cl_LQ)IUlaUkQ!}LeX$6q38;abeupYH{8v%dEB6kyc*A-a(cftEB>2ESV;N9zS z#-ziie!hV7I_Od^2Va{!+rqUR^GN=*7q2P}F;)2ZWM@{?BmM6DAc$wlS z=H-Y3Gfw&sf(JRz1XgS(>zq3`4+p#T^X6HDSIU*Arx?R&h`AYP0JRiLf8$;@oe}nh2;dv;6ISBI!Yx@5Po~1h2BxW}M??zm( z|4;Vg+w*peZ}3uukF3TQ&2D^y-d$Xcy4~!?S1S$2$G0kBe8ubH<1_6kE(c%geUTS9 z{Z!iH!JiOivZ)ITDeC9jG!XlEFJNT8!dwoyHY#M{bCkctdI)Ao&3P@*P*GbR%=_rt z6-3uh$`n4FA)L};wLf9+AC?Aw;h!?6;h&l?7=7km)Q4t`Il?}Nu3A|X8?~;UnQ#sY z!I~e8TpZ_f!?PSK^~_25hwkir)43dHcL+R2%d?bqvdVmRgDfg!u`^Gur3Av%&_=#; ziC9$R_<|?dRc>kgQOOIkOx^4+xO{2|btRFy?`Z8bZAIM^bg=CQ=wRP}vHq1_ z>_h0uh7$vj%fwaMUsmU@0M=OE&jD)-awEI0NBy^K{zc%-_-sC5zS7yPhU-ta#Nk?& z@Brc3!wJ{^fJ++zFJQ8+_%upNdNguL(pWz5W~i`1RK;wMo}W#I2mD}Mf`vch%aMi> zB3;#q3TZ8W+pBdy!GkPRam7dzp+}x|xs_+;`4o2I@c>cM@iRUuC2TS4%)QduQ#KjK zbA5Det(%?$%H_(6KN^X1)-XBvnPm+IJKv_xu`rVnl7=i*&_yfl6$+w(o68rPFe0IuINnSo{FA%GJOoH$S|mDxYxtT*t^*!uA7N@c}rnoybc?v52Loym?gyZ&h(TgU2oAxbJpf)3(dvFWHe7<{c-j2UmZW}Imfc;@qLnXkvg z_%PW&WE^Vv_%j472EcT=Yt;JAu6CwLczNSKPz$cBR31bUjPRNMF+uBr-fD$6=QxNj zC!0JZY%u^hmA^qgpMe8I;ch%=8oUFkL^2?8&Wm01GH|BPQ(tw;4u)Se92_g#APoGA z_tmueCpE{NcvUkUOo2*T!v z1S;GJpi~@Swm)Qu8b)_ftMp)7hB;X(eT&`-ou&H!6uvdN3fxMZqT^w^`$MFgB|x^y zkf~7}FFWLitwZ6uX#QsxeICt{qPFb+*fy`x^A~%)rEOtq{=#ci#kY=6&M&CevuXcV zZ)R-2$h5ylO8X^WFZo(;hYu*6T{3I-*S~gV z_mTIl_3{Qhao#d_8}~=$Zz4Q+zorZslg`gSvSA-r*VW_7K6t6T>t1=o-*st0b=k6i zom3h?)^f=I_`~0Q@vz8lU)Yn8)(3C* z8y%i>7jQdmh5M#A2zD z>%Z~i{FWz#7sl1^+qt-)&I`tRs&3cDCkn2|t*idzvVc|6OI(x(-t?0SFG1KomGUiU zQ-A;PzD4Wzaka#DuG_68HqPDlH@r4KC~y0lR#GJ9oOSlRlDQ@GO3o@ddxiEFBkS&g zn+$&U`=>2)-*gZo0cWWO=(-Pa! z-}(8UqjPs_7dl1nbsfO$L%?Op6TtGY|F;HzCBMZB!-C;i>}uLN_svo}nt;y02Epc# zla1S6?M2%zw|`I}xAjmobOQDPaMfKL`Tmjr873DGTYKWa-wq8!`&dPP7bd-4BS-J_Po1oCEz5pK3q33GH^FgG!3fYhWn<5tOq%Q zeOLaA7`V*c`a{9M&UN4Cuy3(A3-dVs;kX-+i(JsU5r`B(-EC*$hsf1zu5&Ih4lLh{ zAIabL^YwqQp2BxC0+3_V!ZCP2x4`j5j*%7&%{W!$pRx>Ov+luzGc>D6->iYxZ@z@z zEFPePvFn!qpS>%AkE^QslQy(dD9nHeBkMq;rYw>oN-B#pG=UeIkrXIK+G4O;;{wLE zp%GdLO=>ev0|OL|vKZGdZWuR+1j?kPG!%hp*#=M?L~$M!96({pmhb<+%bPb_GD*`G zkoWtwdGF1A_nv#sx#ymH?z!g#*Sp&1qr{BJm9G(#uJ)~XGJl0an9)1;KI@lm%-fuI z68mFC&q>1QE16dP#o#aQ|F;n=G5X&6^X*-ioO?XdjQWMfVFdlo4U58yKH@rDj#tWK zEsCKZlvjn050zAf=9E@_bdEE$xHR;csnwnBlUjcK<;OyP=STfhr};}mm-416^o`Qc zm-nvUo|6IRT4vM??39E)n`-(p95@Fp)Vg&g({C&Up-@eb;%P|q4Pbe%__j+ zKBM!-iSIkTqNh4I2p9m72XIu+7_2Ud;itVzu0Q?FY;Y`CN@HEEU$VpUxk?F(1O(q7 z`0H1zLe;_b0Hk`xW;+~!a?)?+4GpnfqF_b@Sg@MLuda2E%@3xV4qaLyks({J0w#{! zH~f`!>-Lt>$rIT3lEGP>H@@$>uXnu(7yy98g1_Vmye_?J);E5dr*(fxEOh?K0{mAgb%gWxHGqTEIAQ>;`%AWj_Aev;(PZb^37`AmVXssLBULj7t3bgSk&-9|uX`Y} z2bw>j_Xx-iZ0ToqXbk zeC@Jsr`6xpdq47@tp2jV{#N5__I!T-^Q-;At>9Qt%s*pmb;;)H&NUPFFrWFEXnZp| z4O~W5rw6Glm5T00QEuPVkN*8eRdB25`5B$1>YP#dDbr@cI0Um)d;-H#1aD$z}i4ufao$V9vx%`ImY9UspfGyDQ0k3`d z2hT}7pe6niDFu8GPZT?Zl0=Q5djgDA75{!1V6bh`JbrbfWj97O2GO2-9NJNehCz+V zGouebPK>knTL|Uke|-1JXTix+fH<-@$H;oXGO!+^7B!;d#5IukzSQy`9*$N3%U+;| z7#Ha4dSJSgjiHaHcdl`M;k;ko4PpXJ3dBLM!~s=DPXA980 zi$+o5j0o$CqRc)k{`2o4AqfQlfF3i34G1BP23%+ygK)x@1?{T<#1us)ygJ~l%X_|7 z9lQqs_+Nb#?N)N=7W!+@mC-7gJ*uQuk%w9 z7ieVV<>$N#&^(}^KloZzaFamEV}xo7+2VAt4pohW!+9f(!6q9KDKKrc_PAj961j zvPaP}dd%)l^gDx`ZvD=QbEXF8Ol4rC3?+0?*rpp)hWzfD;KSe+BlsYIo#S3o+UDQC zq%Ho*JAG8tI+uB-Zwzij)DL5N%s(?>bQ(U_%2T1Zw7uzct)vE16Dln;I_Ee8P=eb2 zmV%B_6RJ7{f2%%_LgMSrs=XaG(>J%pQ*9~d;sfz_#=ZXFy=?=|vqFdLIdkAs!9(_3 z`~vbPLqn>NN!7uB!3a=N zGw}CGH6?#GLePfKfk^}#N*jDe5RoX(gGFjq6mPMhJRK)%&clhMS#dlk@a)BNIqvC$ z2LH43D)FuY5G2;Wg7wMFXPR&E5By_N)%53$g&Pe(z2u^vQr9Z@!D4v=z4n*9L5vrT z)(yT_Hsbf+;`OTMUF|cV8~R7Dl+fu+?H# ze|=9_l&erT@^lA34S>&`2rQmEDP?q`J4EgDM~&$(8zo4~@hr@7IA*zWDHTyXVVM`2 zI?)JDonW*@oW{)L;(wd;b>e=q>(=-6Oz8Nu$JNdpj;`Czod`hAo%EJ@A|CyqUa-Uu zioF5g-Y}Oy5e>Z$&7<`>A`Ur~-Ja=etR$XY;{sZxeQ=-6QaMrnrN&f{V zG$Tk3KwXo?~0DWhs(3jCmru z#b0q*`@R^Y!MB)qX7k-CVVRWWJ+;!FB}+>?klmh^8|Uoj(ZY71^I!_6`RtpYhMs_Z z{h?`tvqxM1nT6|b()EAHs=sB_^*{GuLHNVE{(H{T@OxGLw7i4xs z$}S35sPFXHBVBnf^KU}X|Chib0joMcrsKJ!4B4LME&UzrS#5Ddkb@E9d|0tlefQCV zuH(7z94CaTILFDLG7MqVdUA3y|S1<}z>Jn8NI^(b*q8ND;BS zWQwCveQ)PaLBBLS4-lTl9C$Fr3V7&BEki0*Lagx!8c(_bTtq!W;35XdfK@()?}dB4 z2udQ3tKA4U?=Y|=F7gep!t_1zPX+lVuIYRE2eaubYc0m!z5c#}^*g?dKUdqr-m-`jZd;UEdLQQz0e@ z1NlhEzqSpf*o+>9d|J7wp!}%N4$x zN8wGW_HW@F-43`D5)!`J0;A82=Zdv9yO2tFMVn(9gOoNFZ*_{@N19vB8;fz2Z$T2 zVF8}rP3HEl2oBk+fLHr2cK&C*nON*$F<`JiH*YFDHsbJ)z;f3L-X_C>F-dr)-|_EXCfa?DUZ3oj zJ)V~8kL5bDiTz<;l0NhWXv2O#4*&&W13;L<20*|bF}tAG{LwE2J<*`JG(AQ1Wr_uQ z42giXh(3mU_L^{%7l6a2FAb7*ZqeO&lb{&6R()D1B4YiN_@wFwfyc#mc`Hb9Qnh>e zw~UjjJy)~?dan_x+TdYjU93zda{i8r!`G$i;aLOXUR5XJ|BCvgpT=S;Z^`&00{4?L z&l9>zgZ59@E`F!W%b^jXBXw!_)MG?VO{q6_&x*v^2hSS?Xeu+Pkk6$hlBLsBS<6*S?5<#_j z_~p>wXLj~_F}l%Cc;?9CL&RYoEYCkay5#Ge{^E5;f1^+4>+cF7(RQG}y{I-%e~$&5 zE85nMYiT*fi9>Z%fl6yIlG1bdK3oXm+g2!%4WiDRGXOJ6}T5jCT@1s3J zXOQPNpmRyREzX}3<(QC&gomlhiL)Kg;q-cmYt5yYh;TPy1>>rVc%)IVrxtBuh|@B1 z(9pExiG|0v540BZzc`M;X)a}+`)hPu)mi?RJarz%iQDJs8m8U~;5575H*U#rPtLcV z5PI=R^y91znvCNLV>-^#9N(W_Pn<+a9(f3gE~iqA%07SyxD)2d)1(I}P%JKs@7qMs z0_PA8mn+p={7HR0lRngI)wmxN@oc__5yaMXEFIj(djBdq241D}ZybH};4fWAW9BrP zl^A0a8ejcWC~XEkO1_tX6PTxFur?Z=sJ1}-E9dN_c{jWUNjIm0<8B3rmQVNyn=6-A%gV1YjQY)wFf)0LkzAJBzPS zzfTnBQij3hsu|(B`9P(g`fd2-E!kQSICKuIn}V^o?;$;twYtx_Jlu4G#7{nW34_vW z7GDZ@6EO+Eq<-JNLZ{KOjuYmg2uNdFvYP*Z9wG2$pO*+1#=3Qm;Q=AfVuHyjhA7jP zm%S#Vx-&n3$J`s^giDfe??*G?WL>;Ce_nxqmi~1eAHbRQf8+f5GHQ`V(uwGerFB)H zkm(1E;RaQ&9nQn?E8wiqa#I9ah$T4mmAFih=cSOOa@7I6P;SPoKCEj6FOgT-2?LAA z{$%DlIB|R~U$R|*?r41)a*!xC?>SnZ2k9H8dwbt9&As#BfUef?-4~ zQ%3=prwF+6jVJb5&4aF$ji5AWnlhfV>od*pcToCP5~a=Nzo>aX8((RAt*iY*s0wkN z_<>e!`Z07w%wooI@<2vMpQQ%gF5*1#T?O7XfVCO7iE*CzjI-;I~oC?vPQ=eGBEk+5@DcY3;U*lAVNI7;6?XU+J!KZ{pIuJ90bK@}RU_-#l z6B0FFT#j=Qo2uPje2K$>HCvvQYdQC}A1(?{QVnVTM?pv3^IvrcOX7z?P-WM4dL=+s zxlnZ_^nah+mz=QlW~#1i#q%$YJLXM7vL56;Xv3+@+m7L$N-Jx~t!LJUjgw{_=W1Vq zuCsL?D_{rHM)GTirsaV%*&&+ZdPUf`U0G|Z<{x4D%JZEgg73Jt>CgAONGl;iWKAYC zDFF?VBRvJAnJ-xSa!$Rr@3!5OAFm#X*XA40ZY~}&@abwl6ZUV7(9XF7Wo2^JBv5c%1jPo96J6Lyh4_Sn!W|fuxK_eDbjP1o0Iq z`0RAx;!BFS{vWu76+jyDUJh~w8g8E_BIIOT&S&x1OJ8-&c!kqXZSX~D-~uy=M0T)w zVZU^v+Y^^1H30pDdl5HvYGYhV4Wo>%CwD1C2wE(65b!04Z-M}*wz;%*| zF1ZAI8iJqcU#nP;)ujDvb$rcsyaWV^#+RjDl-^<&%ZRjoL|cG4_hF?U+3h^67x=T* zMa-{vAbXySlEd}BI&Od>9+F>P_R_j5fjw=ayzSA{P=B4$88Yo9Bj|OD4*={b_kS{U zI>b-yZ&0-nHeMFqki8Z7b(#w))x+V~C0fIl>ssQOETrT071e$?xBb?_?H?}Me+EJm z?H5&lGPnM4;rc%;>Ti?vw|Fzx)m%5Tk9r+>TF(0Y(jTSQ&F6CD>UA@@r1ihtS~v;v zs!c9450^IGusf?A;#=Smd;0!$6PAlFoaPtKz;tgn=qC;@2%lJ2=K9G#@xwHHS?l^a z*NA4|fBP3{IvSeRHR}2=EnNRKy8cK1tn2SvIz0an*BpOpdbZZfOE6%p4JA0}+ZOYo zS?Or8r;P;Vf=s&LdA^Es*+G><`KBcX?6=~Xsz zx>nC23}QpXiY;WsL)_4Za7`dy0rQbsw)taI8d{<|F2%qfz zSxQK|{I0IUMA8U-xdA$X4?2N?NGoq4{ME)KTkdgNRkUzBV{m69j%0BtL=FQUj?Qz>sa~z+c6)&3^}- zj=;>9Tx+O|W)f-HPsc={@GCn+plgaE(4z3$1OJ=T_@^KjS}ont|=ks*b4#)ppJTxine(|NB$MjTu>AOZ%`WjAsS4O}{LlW}+YOWlJVWwjTHBtX+RQgwA zVg2iRSkbcduXyQbhEelfPN{9y1d}z>V>Jvu)p<#d!o2KzW75SOU|uT5b<}ous>ZyN z^s(aUVcti6l!t1%!A?|#!;?lsis$YGDTK}+Dh=0MiRDd+!_|2^7Rh`7XS>!M3a-V& z(35z$x;2MNNM%YbdMwMD`nPtRQok!obyoJs-93KHfn0idoui@GC+>h}DJTQs;aYP5 zytPT0zmhU1iU<3GbJ_J{qDt?ZyNW7r%kk4YWi<5o`Rz7(9K}@EnjW*o!#L2x`M*sM zA5^*Gm-Yw!kyA@;S$z%mU#34^)3&|T)p;hY_nErU7^jwoH|#@$lMLFy4#ZBf$n4_r zfnbTSv1HEsCPOFMtd{1}{aEaK)nXr$fw=7J{Fnpu+QD`HFA?8_>-_iDPvg6OdJmuP z;gbUv_Ia_N^WMHkP};!%SNCV$+*>RflD&uL+DnG;TaLY?WB<|2#%q34guUcTgrU%c zu`}!?Vt?lM<7qF6xi8xJ`!iaz{N_too$1|~w)GQ)g`pO)JC(KMP+={>`Zv&dT1jAL z($#)H#Lw+)~4|JYCu~t|Ru$RLs4>?TL;aWKen;7Be8geyaGdOAno?&B821@S3pZjXA+%A?h zE58qqB0PvC&FcLo@nOJGM)fV?D94|H_@051L1BU^u_2+9`$y8&V#CDy0G{x>*g5My zm`cRH6-*^X?OS!`+D)7XjAl5Ug5!U}*mo$EvW(5eG45Mc>=@(j-hHdl;@`G!)y+u| z#*)~m@PFqomA}pI=BG^ByH;~=c1&yi4i}a69kZ1c#{^kcD)$FQ!}wJQ_Ynxb7?{3A zF6cUPZ5`hqQ~%@p*!!PvLC1~tLH^Ldm0rOu_TrGRi};556mpkxLeiTX)9X2F5R8fz zeLr*VBs(<6vlgX=x`3G_oB2O7R_3oPg7{1A#3vgxk`3}XSrli8%o+yu2ajeLoYJ$? z<Xgj~y}^{NMT0cNP8kk_Z{!jVIy9)ol-G~25=s)HG z5GVZ=Bl+z(_am3=nBUISmmniXbzXF3OF_TVxQuNJ`p z;NnK_HSH^%@AvoYWAE9=$QSR~$KdUXU6gmb|MGj|eSF9Ji2hmH-snA{NPA2s?0NjNv+a%AxcN95yZ3+9-q>=~Xol1M-yLsz zV|UpOF>Y~ImYwA%KMwXrR?VV(Atjp;C|ERsu_{eBzVO;-iu{ZV{X=ncY#NWyGuEFC*gZlfg+v)O0 zi=I)~d&g{VbnJfo8#6|O|G>5HD*V?UvHSV|_|f41{_wjB|GnPbhJRsi{3*mqf9pv0 z#+DBe%3W=5-0$-R?TtxoZ@l=G6PQ^4 zb%l(4YWcs1sv8j5pat;|nh*~Gu@Rc<5f1^5Y1Kx)cnCfn4*`J@5Dx(scYG2+Pz3mI zhl+{Vr!i4y7h$P>7@t{ zMfeZ8;X8=@Ql3D`Q-NSIu<8}pnrbqP^jmawUdV?LJFykL-QjZgCi9)5|#W}nA)GpdnQ zoB?mQ)5CtQQmC%mI-t7tD%CX|Ki3-fh;Pv~ljzwoy>;np;8|NhCQKIM8acl5*`Fz> zzd9DH_{z8ZHlP0b-hTN>KdHy$v+TXNPyb8tsj~Fnn(@_t{gef7bNzQ$! ze;>zr80f!P%?t!qMYR6Ao#%G6{yS19-sbu*?I{@-Zz-{SS}t$~8=dv*IC$!UKif7GVUGE*?^joErS zpZm8U1}gkob(G$^k;?CTZASUx`}b09!Twd~{(b7F+4zm#E8(XdGTZMKNAoN{OOa=( zH;}7?U4~vFesHhiJR^9Ie_h3OBCf34Jk^I}aeU*}Z;sJ#lISPGTDr}H^qZ)DNkt@ zn_m6qT>U1j-<+o3H0d`L`c0jFbC`Zpq2El^Z`}ILYp14$7KJMYC7m>naa}t!1d20= zduZNJXx!{N(WZPL8zN7?)v*;JT+bNc5w zE1Q2s|B|-;wW#{+c;;0dO^ z;4A)hXJbH^uO7JF{w-@L9$yn`3gW935@MOmi;Us=!4mh{z zIVm-y+pz3aGC6~@5mmDsqPF+^vzeL}5t=gRe?aEB%&8XzI|vT>Gc*giPt*sOZF-Zu z7Q1`2`1;=I1@RTWP>?riUUI+2SF5T&AKvVA5qRr4I|px+Hx7tC8K~Chs8sdY`^kIB zUk#sA{PoDpQOle4)dl|p#Jrz6~s?c*MHa!)c?7{^}Cm<@wM)TvEye#;rhM0{tI&IPu(TuA7u#tF`I&r zCo0~~(bR) zL^NT1noTS%OX-}83G<4tSjIY5-`@lsn1WZTGU9){7T3t~Zn3W*KUHXYJn-GI(|fc~3n(re196dv;#L&40v$1di224>X(smJ zR$i9gl+Mp|6vlv+^LYb?+a!*IRL5H8DUv~@UPBAawP!E+U6h<$u%uXTZK`%g&gW8z zNwY*c><*dMC6C=D4bR<%%+c;<-llNB#0c#Ryr?hP{ z>wju(cKyA7l=#y0*6rn8j}I;o>v4OUcIwC73LoVEMpYl@FkT!7Vm^cZkDMON_2xD| zy`e;#1$?SJc};)A@7O*QC1ZR>#rXUMAF!B+UjP`m;@Et$MHMjuFZ~j7W`!N9K9m+0 z+y5l~*+7g&-R z>X)s0eaL9LyBy6sDn5IWqrU;kwrKr0g4yd@QQG0jQy=@uPYj|6dDhIU5&g+Fck(v- zJMyh)S?L?O>(irV7UbKg=Bsb^zN*%zgpJq8<6&!M!Fns2l|J^7YqR-P)?Q5giwoE9 z*7ZMdO?Lgx+cN27!%u;H*?ZdB$;p?UY`BQ5B-=}v7pV4-FZAXxJ~bzQ+3g=s_k+3hto&u` zTGw)1wl-q8Q5pUEQ96m2jmH}cw^x9EXWH63$KD?96TP1!{eFOk(PYBByj9v2AZN1L z(ey)#ME|-Mr;74U^HDGL1RHqa=~L-p^0@wxuS04v3u9@S z)@mxz81trX7l|>EXcy{@`Nz;i#1mE>=u!3Sxx=D^&7S21>Y7wJt^ctc^#OFr5d)er zH@V?Si@c5f6YVk+MZ`6-JezPrns2l6+C}yFxS(_Fm@7?9`r`4m z^|*8&vhd|zruCm-Hol6le{tdZy}JGfI>uiAeue9=(Dh%OQ$JLmVYoC^BD%dg~TKRDB%Y5Xo#$2~Xte)g_qcx)&mWq*2 zuTc0E@w=CDw8X!Xv(JJ3A-i^QEMOFIaQzCzCRTJr%-=J8V_f3Jfu{A+N|-=KjW)XMFw{W zKFb~tM%!hR9ZO^Vb0Ejnk2VL?hJYJ))Jsa|q}GS`@tAuZ;@cdKAwGuVb~8bhOJ9g!j5} zfHyiic%4o8;dK`S@3rFqZz}+xd`{>3YaWgt`U=47Ee76i?-0DMl|ugk54V0j2j+#~ z$sax-#s^s}ue=s~30sgcGq!Xq{#!P+f8PhKPx{;Lv+iZS`F!KSho-an>;KSph3dcN zZT=mGzoovu1|ywgvT|`we`Z7GpO!V>=yA0SN&cSUQqwau4f6z6g8Hc-+$jf|FqkJ6 z-48x4XO{q77HEYOGxHD73tvVriiSTmO8EE5gt{2`BSpbqS1kNu{ulDFbx98Hhvk11 z&!#`+VM8(efBg>e|6&1e#nMs1+lb=%;B6`f-tmy%@zKHSY0eLCYccSShx`r$fKkZ9 z!2@eE zrxV2Hbd08U8y+jrP=7Lm%+`?ejnJ2!0un z-u*Z)JOo9sd43^^|ExB@eZsPfZ52Hp)-FbRcU+c--c2_aoA~+CI%= zx8I#zxc(+x|1C?$UjIu66@^#~Usy7B_>V7Kf3L3ps+{_@Jw(fH zB(4&dScC|JqFk@&^A9=Yw7uA-J$R1e42rVrT7cL0FW^BK$;F>5VoRU6+ zx@g5icG2W*aLo=?dqm(8++b6!3Vt^5;pPoiMAhZIiL-EG@N#al;VZsM@>Qyfdxm&r z+AVn%G-K?cHqf-a3&XWe%f-V`uh*avr2P^`(rCN8w|`-oSYYy7HLKL2W9I#5;B=V! ztsK8W4yS~BNN9l<9V$2PMhr*J55y-g-5yZl=)S_zXS~3KSM+`f<=V6`=S^N#`Lw^& z)%Z5$COYAI1$yiw7lj@K&%rcZ?LoU@QFtT$p$gaIYCne(6ma@W^iu9g@YH;Eq>mCW+|i;`&&qVvCluplSZ*5$R_=kNW>Um;S(l0h*9Zq^*G*PelSx|frNgV*(fuI( zS--s>cMJGit|SM@k&wcT+;9#)#jd;v9`Kl6d?-8Mb40Em5q>dm9SYc!3Bay#rGQSF zuOTEOYm?)?Mb$^xcxgD{H(n@VDyREHC=|X#d*Zx8T8~@e(VoEDzJSJ(PzB{h zC5IRAEWQ&vP5L|kI-&H1=5b>^Y1TS`A(YM(X!>bAxad*g<^Z$Ra06-(9-HwvcrB|2En2M_xG}{V`rT?= zig8nSoy5PrKLYPOhZB6f?P;9$+FrW&{rGiRFw zsbBN&2y*C%Z$VAaa%iwqNK7GzG#zw3h4iV$u;e#gUgIr`ZmyL-#xJ(P>RR2w7Z}^| z=xRNMa-@4Yq*er3B&1JjP`rRI5>5|)TPQUta}m?T+nlmqIkkAY=kv=_bx}I?SFEv3 z)7C0N_iJQ+SnMju4;7kT4>V@;L*>-W-ziUE-?Y<-qc_6FEC3IrYbaoI-FqTh)^=Z?Wp>QuS#15;p#us^9}j zt@ZgQ^c+mG#yU`|T(?1OZ5ve@jjR!hr<+Ou0j3Eod9?EW|h$5@hP+OiubGyqh@>>x=S= z7n-on5Io50^ZNJMlq7Zo`_zq{X}Yo=jz{(-uU-K6eYZu0q*?BLQ+W3h9*?TWP6yV< zamo5@Lu=U#je>XsdMve5Lafn`p=Cq=Rs@=~@xOw*cTFzbHhy%iyiqo)k>Xn2iWgK! z>`W>U)l0O?!JG)MktD!iRwPK6!96lbF#V+bb`agvGGPZ94*x_lnH%_zg=9bS;mxK` zE&d!q_jO7=Qmpob?kmo|e-wv0)*Z|4(dPnMgLyfEIm&U?s_NJLNq!OaVjun3rGs`o zfS3&%qk$(n3_M5M;due^2qiqpZ)MWW4$skf;E80FC+ZGo)%twS_wfMcs#j`S{_`iK zb8ojAZ+(1n|x4tbzVMzKau1Bu>}f! zFP|R@=>7%xPpCCE^*=%PqT21WTl+7w2c5TL5Vdt%27G!a0C=$_z=k zq#y&3KP=%I0l3u6mzGI_nG3xZjSRHY-9FJVXaUI1=%i9alVe3F-O}4zkstD((=6MB!N=H+@0+HrU9!=6+1cVRH z4m>MYsPKyqF5ujrH0$dv7NnR!D+vb*!u>=V@Pcz$E@6f%oQ`{(gwAHaqDd{Z0H^5! z6^QQ(uD}_p&oi$Ah0%njLQ`%J8&Ts zS$>$3H>G8Z`2qzWNBv&N3Z+4Kr?&l4EnRE;L1?Vbt#J{pe@Rcz_K zHA92jUU3~>1@~KpbgjR@;DSED$QKHrPjlU(KbXowI0$l2DfT&36}N~g7KLN&l718U z11>F3ZEWIN{RJB2xG)X{P$7`ixdaIM7Z%D78o@0!K^O|aeE;$yI`NE1AoxHngnwh= z${$Pt-f_wbanRb2;Vwbj-3cT3gn_`uJ|p-#M1aYfE!~?ph|3K4fq&2e1{)I2yY2Wz z;XV{3e5J}@Q?B6VJG;!Fo}~1bnBco-(J@A1YoCZO!5XpNZ$KJ{$g_C;$s z>_waCl{axc8J>d5YbItWCdY3UU$kvRZ(|^VB^B=^XC|cd1Fs4`?fJYsDry;~X@4OA zk(CM$3jY=!U^l8{+tR-j#$I8Zb**|51c$x2Lw#43=R2REgz!ss<2yHvy1!O_gLUdV zO>cX9E$Q#Tg3_NA-{m1_oO80#mb%onirZA|OaB0dAUdS%n(-@TzbMg$;iJVzk#(BB zBRUG!*?@NAXb{|!u}jblza60mgjKz2cv^gem_lHd6&Rn*Fe&0pj8rwt&Dl^jp=S^V zqDl=%q4(nv^CfNBlguCAfS5U0Cy)nO);90;3VyG^mw+{`o^Pt|ZS4|pqcL%O7=mF* z1q|es0LF(vM+T=tgtzZQry?*2528~T(ko&Z7U*Pv%2+RnbGF?6h&J92E`bEZ`tDpU z?u2ceqK?qkY$`1ieF`;H4X+=eC=PcOA=N(sb zH1JhjSu;IGaa~)o!I=5FtNkJ{85y@QND#=Wn&8Rec$Nl5iP=hkX#VIU+8EMGh)0Fj z*mvK`RrR2yVB!6-H~|aCTYd@ja-NXGObKZj zA>a-uT;RsGyAf#2fP#e6d71bKSn>zUC%8h(7_X|&;7L1aNUe9T0 zep%DDf!tTOaC}8qNO-5H0Y-l11Oyf>H;#tf-x4=EXCH^d_=g)u?`v%Nn=vzb#i2%U zz}WJ%vFct|=TZ2uztt@yc%AwF<6#O9Mz=jBWUhguO-#~(%_Nc0S8}HbNC_~;O3loH zrH^3TqySyKKTdPll^dzknSX+8Cwzv2Z_acHAmKZd@ag?H7^qL$6CijwX{e8{79Y2w zn8T^Rccs6l4vPkxtR>(Rm`#n)Dt^ET&geWx3`OJUgN&K?xjGThhvmbdm80W_q}2wo zRak+*08&zPc`-t$CiU>#e=m^dqjJFgm<&p3% zew4!3VlRmtM_dsfmRzY^F6lMrxXk_#HsfY7OkEHo2SUVg^U$?wHkc0clS6;^k*x1R zs|53e0xi&ZDvi(|Bo7FF=5(ls z!lW>Fn7~{!brEWvL+gP+EdX7sOZa}~6RxWlVK%Vj8W9yEqT(W_53z+13Xp4bewrRN zw%}%qfeZ{K_XS|_VV7IK4?F!I_XX{t@{t2VRe&P6iGK|!6H2ST2W1odo$Kx`z)g}r z)ZqqI1^_!i49@j|6BFh^%O_wTD0->F^De~Kim3`$=7XHX!FugygT?UDXAEsNfQc3( z_z)9Pw3xp_3676)4QDn#Xu67&AfW5@lCI57m~4;{q#AS$fUa{v*9Az0(F~GG+JdC> zNn11uQh>Hlut5o6^$F~kVdO)f4Pcuy_)s9Y8R36xg23Uc<{<(gN7pwB^Jo0Vix_~VL9W43J zQwSb#SQNrS@ZVke_^;^)HvS77q4;m`k^=oheV&{0@ZT>~B8@`dX}pY8-nMPPAq2|Y z;AR|`d!NzynUW0New0ea%!gc8558I)Z$}NNniQ>%XNuO|A7}A4SMQ^fs&gSZAVw%v z@4jRL7-=q~Pcvl83P_)7NS^?t&)h~aSpUE+Fix@|q0K-lwLmIWQW*KbffcosO0}Jz zLEfLG%rl%$3MoYL^4m7rwPF52r3oIiSrj(BPety z;l>aEYyUw|Bv&n|2FnX04eWSJgeGqpGJuR~pK(&P$F=HD|B-`R;2*EcH56V6MSd01 zX4N&X^HRb&5?`0&!M&EdJQDwh3m|DP40wQhC=Xn}uK?a>9gbzR(C}z#>ijMW`fukl zz9zV#rqfqK6WMobUVRPvp0R4HYto(0~cH zkZ_rczz-UZ+TfrD!@Lylt#+Yp>SluvZ3_uKB+?}D^w1AZM(r7R0)CJ|EflB&uF8Qc z;BAFR@+r)Sw66v?2p9$-V{4_Tf-DU_Y95>BPA}@Dl3L%xQ49SvxF7|S1nq(e^R9zn zBF*TWormwmhz@%deEU2NG~(hqiFCBH^k!+invFouT;MD@&e-xS)(VFkTb{9)o$M3i zQ+!{o7tr?aZ;_H@6FM8CjVZoc6F#&FeEK>%Wzbf}Vgu`th6?^e`v z1@UvNEVw$mNk%XhD+@3{1Dy;BC9n}l;h!6n#6-QIK~QnvYnTE-VnZzVpXmPq7tMmy zEUawzZ#+2J(H~LPaEwpm;sWy(z;i>N21)gL&nM=JX)l7QriI8$>m{*$np@YvH zfRk-fOucacmx|tiI_Z9QZ|(E}bb%1M!HAWVw4#BPC_OZ-_aX_`KL5z%H`I}=_&)*H zWSHT=YQpyt9jqoVbN|`3>ie&=3Nfx43)kal1cRY`^DodJpDJhPA0emEUW#Kz*c)dn zTo9qQ_FlzyvT85&)m%PQ^*Ca-_WD%0KV|VN*`n)b#1Wsj~QqGo>CNI|eq0!yuV}2?(}&_5wQt(xo^mF!zNQ z1a-N85b#3Acpz&ao2@;Ba&sFzdcZe?gEm>Y+J|iEtnL#=r!9C%B3W(?ND12dD}g{% zlxsHy0lfe#0x%%I0#SejFjv4{DmJhCNT4G#7IS7L#MS9)1C)5+WtT$_VfX`@z<_x@Vwg0LW*^Fdk+>QT|L%5*U6W4ysMIO`N@>(JHaRr5_F z-URrj32)|tp}t@QZ!GIZmHn)jMOuWR#t5!z0g!5$QQfMIG#$LD2M30E(}0^U-ZbK- zn>S6k>ETTaZhDc_whx>dVS-z5Zqx|1i^lMq;#^qzv7I68tXFO%TFk&7xfN?gMZ*Az zHTH4?S8RZwHVjE_fQTq%G4tXB_5QVe-v)gFUTxcl)CI5=1EsVk_$Wqzh+!bYL5QHSEC$CYRgItGoY8Ss0&pdA-=?1Iq0 z0E)-_{Q<1T=eX+MS0a8}9h<)B#X&`0}S@5yI zC`Up|ZRa^||0Y2fZh898{<0&m@LvC%K=ARJk{A7Rh{+y6#yq!3dV4Q)&KX#q+*sBt zUfwA2x8<4IV0&4Fukcf!_zCvD0M;`h`5Y+0(q>KBp!$kM0}Jot=Bt4(lX#o~mR~D2 zrV^`Gip^NV2(1zA7z?M!eOcEklU6bA>dL*@8)QjqZ`RfJS>RFa&$dm%8ddHq*5Iv; z2VAQI_^BWt#6Ud3&KZ30{V&+~V3ho~ZKaU!!}3p6StNz2jEhy++J#>x+!VN!O{g<1 z7$BXgpZutF02Bi4F7XFmMPs2R|?Q zGko%iq5_Ur!Jm5HqQuqyBm^x`s{NH*tDiuj0t^i14S;#)f_WFzfq}udw8b#%Gr9+v z%b`1OlC;!@=3;7{+fqAoy{r9MMW%?OXw08 z#A_d!K0>}4=%o4n{j7Dko6mdTS$)sQ?|I}>@QJp+;jF@IB}>n;vEj1YEf!RCb+~WM zWW5b$`9kM#^s-gwTKz@L202wWvPzp&+h9KOISbx`@{CN@2ULPCOsT_df7hyGP(RGm zu+Q}Tk@5{*%DvpTP)@0#Jl~6rMhYA;Zlno7(OT7`b75LZ_o%#&9EwmZPy&kS zQ83`tJ3q2F8=(TZxW6#cICfm9=b4WHsEm2WjX~$ZeCg#P7}EsinCfDNDLRJf1=B1@ z+kkIdIL~183gZx`8cZ*%NMTMjEg1JsBY20JjA=IDgwid3zL%1}6}Q6R2_wVr1yZp) z!-+sJNqX09*=M<5+kT#s2T^Jt>FJxR{!Z+TVKBtNot}Ddr(k&zF;!0EafCV?246Ot z1jS|@Xe9QGpntFn!USoau#Y^&*7I2{A9;e+hF5&q0m&=|%Y(v}F6h*x%5$_)j&i<* z__XP_)%1f}{4q2g^WDx-H){_lxKMKEy&qsm7w9-OIp~CzCdbuFnRI25ej9GpPAMzL zrR8>dttH}*gXY3@y4+j>XfQ6cUM715irCM|^-6faEI1)2t$SPuHym^I4_ERaO_<)8a8%=xbf`98TkS*HrLb&NdC*~XN_bdh_oDCZKHE!nZE$mSU zUxk&NI36jq+c+VsuvTZc?2(rLe0=j~Jn)QCbQMy8;1xTcT0(L*C4%E&s+Xh&Wh2WAQT94oreBn!6 z^33}nWqu-#ac3*OU_{Hb8G=#^Dz`qc&(V9%O~ub z4X^3((|V`okx`GI=sej@vEygk$JMyQ6ajD??P?&ks(Sd2JfQi_25&_0!8-g1!bYO& zC~jgH@`#vs4#+d_eV8G{u&1LJC?A{)1)68xGkhTvgpSecc)Phf8uZpY>_VAgf2!98m2YJz? zx%U+2jm>e;6#jfd?zNsT@i}>a6vw5<8#F)goI1Y=UDD4fmUFq_N}qWGh|6_erTSjW z2hyDX^m!-9DdsI%d@OJnZ@Npfk?^$U^`pym)zqk3d3O{a_LW=w!0xCH;BPLYacPZKSX{=_5w7?2A%WEUd|fXt6{AJ zBOV}1daRNegBo&ZgLwf8szL1mP&Ro;_y{ZU#A{ePo-rWk2gPJu?08L+cAq_KRQ>j? zAJ=}j?6Ld$oie2yJVV(}Th5c?i?pZg<3%2a{;KA~RoHZqcD)-h>4O97Ex)!_ya4w) z$$!1lnRO|h(!_@DQf}yCmBHmP#AX0&49_blrp`d;xj5J~6UyQuStDo8NO%JUEbK|N zOF^Orq7Yn|K`Fe_7Hb&YU|HBmsoH!n?Dmnl68@T*ggiYivF}rfepsMVA%{#ez`BP+ zejjH*Xik6BzKU$d#bEDEV1_nO8<<5`h=!A>$?M_T=$Q{M0{Cm-Zw*xbI`O=wtX@2? zEoOh0FXSgZ`f8^`F~854{t$O0u~9nxp#b)GSDg*UN2IAMJ`OhY zBsWsv!uJ(y2v-u?Gz}~hzA3k_Ej>+`QRLLl`!}i)>sNI6?4kaSubM zS`gOa9E*RGNMjY4xy5z$cKl9?2n#gxQwhW6c{E%;B5AR#S-6k3R1QG#vso%%lqGDIN&~Zmv{Z^bC(epNwP@Aw35`hX7*G^A&2=wx z%vc@YzYI>*<`CFEeC-f-qosV}Ur?nHzPH3G1&BCW@i-I)Fq5+t&1ALEB!!LByaQfW z)VqeSk1#|cn61UA8Oc=X^xT_as+3HiEH@a7(E8fTS_!l;Sf+4indZ23Oqq{v*XL=6 zhig&TU6-HVp<1`au_R4F*Sr<g0xO2e75WCC%pWJ>cH zW;CqGKoi_ZjQu!O939gp&C}kTOuykzN&H=V*JUJwrH2ANKD~CF2_|y%3FxS>8|Lc& zT7FQ&(}y3X@S$ay3Ef2On$ISSqp#pzd=E_1B*_T*u2mO8(hHNMBmMvdv^GhCsl*r$ zVpa|=s5hq{pKX`qrfi(ti{*SRmqWrzhXs$=({je|Q+7waM-(BWO2G%~W3g;Ze{D$= zml#~F#Onxn3f)oGjZ(EGn`&o1=4!9z42Ut8Hb9O5diYP|9k>*Z9&~6xf|t@@*S|6} zG(5bE!d7qI80l%peR|2!p{xCS9FJ{x z50ayz_iOXGG$uD_VR#moHSi<>79}SkJ_e4jz##ad5&C^u1eFoPoKb4=92I}{#+Wn^ zZ)=tIf#LC&WqRxb^{~{({73hj74_!2?HSv<=C|<-$b0Lc7Rb$Q>Lrb0I~pJLLA8J= zSfR9B?Uw;F84b>0N9-NbJqtcNc!BO>gtTq!H7DO-HACgrJTBdAJ^PkNU&ePaF89ct zX=lo7pu2-aNLUa`WXe_=)s9 zNYOFNJx=ROcWUxG!%w6;IL(iG{Zo_7ge%zt9Q9I%2&1L>v!6)(+<@1WX*pj3;W?t@)L=$8@3%)xxsWrwaq_3TD-F0&*LXD_((qZ|Maqi-&Za9 zea?G+B3>%pN$`TrPh>$uv3?>;WJ%lVYdri!9FHn?&hQgiHp|8blu#M#vIc9J(U!+g zsYpK&FGPA#%LsP|Kpcag$aTf}iFBVP`Sb1LCsK|{zBtTuKbF0~8qrT=1@`rXJREr+ z*#One=l`7{Z_U5pS$)qP!aRIYw4X?2ER*#%m=6E&``dPtPhLNfFsrmlwGHO4e8u^R z#DPk+D9iQ}i9JdArWa*4Kaua2Wv|D$ob3TpXi$sufqFh4pt#C~E+3M7=vKejy((HC z9|u2?8(=bi+xUspJwXoL0Y8!Zi}e$UovP=Vce;%gCV!Fm$r7$&_q&Vo7l})FJdg-j%!|`tuHd!f z1?VX3FB1NX#?5eh!dda4R>lxD8 zM&}*!7ioEl5(L{^*r(kk{vzeTw~*2W{Y5@w_ZM*kW47WMTg$><ai#R?Z>1OAX zg5#(6ubM|j?Jv?jb9CdUkiSTss)syAjZyQPjSn*YMI294+{AXazet@x&B*>D?Xcit zOvGWF9?oCnFV9Y<841NQoLJKSB6XD#pJVkGajNe%-AQx)%j+-FO&kijIh<_B@E7Sl zQNq`TI(cb%Fp|GWllsmM7r)QzFH-(D3D+?GBIT++_KjB>j!b`%)W;Qnq73CqHeZ2e zqw*Jt17#eqFcIhai(Fy%7cs1o8G{;fXoGp)`1p&oJR|TlUiLiS-*=x~i*za4Pp0Yb zB4i2fo80o@qo3xTX`*O< zk+H-TiBUd`pT9`_k=?h>8rAwT`qH@eJMr-D>v!sdl7EWv7b!lji0>6n%KroYBL7`# zjd1NR68TSIe~|+o(suLl@)xQ2FJ$d-{vvyoaieAw{vs`?G1p&Y{??u9FOp<8Y&)xR zlj$rGCAJlcdlCCg+TSJhYCiaH+#=z3Pm}!qp1;Vyym|aZjy<(lf00?Tq;2&z9{wT~ zDaFni{vu}_vD5uU>LAjKT1L400OA<@MT(3o(&Ux=`S$S_smCN=9A={1vlmz+`inG= z(qH7x`!nRN`71oTWSoZ`^%rS;EtB;&m{Ei`9BzMmM1PS8tF%eA4dx0FF|le`c?Lz) z?Z%e{{6!pZQNHO#nayA1OB1r!V>{?C();>2_=~));)=AsK@Qykf03f&iu4?!=b3l9 zzsTs~iuAszSe~XfJ^B0Zo{uAj)C@0ETcbq8ztnCmAJhh!G(9a~%x zk1DVC6^Hc`>Eh5Do1aMEK@zTU^%HRp33zsfpNK=jYsU-qEO>Wm{~5*&aINgZ3rM7R zpM(W5SBBdQ&hiu4XHe_AT_2G6(fg}^b@HA zzHN>l*i9Zbu1F;?W-FetrMx3?MPdg^y4m@J`;9igi?p9rtmNXcj-M9QPO;;ske^7o zss|tz=Om7}UZ~WSruPbnhYXG+urpp7p!Wo;4~vUe}~??YDPe_w_qFu84O( z$*<&T%4%NZ@m=pHl9&u6kJ?Y9abF4lJK9gA{^fU(pNJP45bXft=qFM>K~@(ki|hgP%yxK9Yam^Ap+0ej=AmAIVSTyRwAMQkm^1(lPa7X{X8Z z;%LwZ-Nz@cNDR$nwJ;Vx5f5gqq6~7*roAt=n<{svpGelc*fu-5(8Qa_=!}$j{;hoB(wcQwmc8V ztI-7KsB{aq@)^^6T@gW`v)}W52ha$IDN|GfB(mTtAU6OcU9D zBBNSI#X0`R&krQ_yWO{rDi}{?EdDX6{l^tAk>Bna;_w_qAL5`d8 z^^a-z0F{yd0sojs=2((U`^Ur&q>#;@cjuK~>-~c9@{g(WV2&BiKV}=uBct+<=|YXU z{xK&5@|~D>#|?(D?<7nAnBxTOtx$}H-KWmX8{|1SANv`sX%ReUSRV;7wk7-1l#NqtRGW}x)L8Dy%m^*$d z{bMRpT0Z9b$2cH=vi)OHugda8?eF(-XpPN3rc1R`?EZdHaa78W6!7c}|CsnIxp?8= zE$AN;ldz1=KjwuWYkjvxwa0Z9FTD?)-#;cH2r(M}7`Li_XZgoOrcrY2LjRa1;M?Z# zGLnBxJuqe~p0Sm_BmOac|H;&62SF^#JJHWCV#mIovG z$CT%Ri{IzTYNPJ|Co+#l7HXxkJ-uo zG4m#kj>QC1$On406tJMTV)eSjU3M z7~-gOCGzw8+r~e}2OXz4tVL!}QtUGSn9bMIKc@bl5`QE5$5b3Irk z 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�<3z})bo~I@o#bC22K0tApM%;EHgcKLh=8> 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